從下「索引陣列」的numpy
文檔:
NumPy的陣列可以與其它陣列(或任何其他序列 - 像對象,可以被轉換成一個陣列,如列表進行索引,以元組的 異常;請參閱本文末尾的原因)。 索引數組的使用範圍從簡單明瞭的案例到 複雜而難以理解的案例。 對於索引數組的所有情況,返回 是原始數據的副本,而不是針對 切片獲得的視圖。
換句話說,你的假設,你的行B[:,:] = A[idx,:]
(後修正一行@MSeifert指出)僅誘導從A
元素B
的複製是不正確的。相反,numpy
首先從索引A
創建一個新陣列,然後將其元素複製到B
中。
爲什麼內存使用量變化如此之大超出了我的想象。然而,看看你的原始數組形狀s=(300000,3000)
,如果我沒有計算錯誤的話,對於64位數字來說,這大概爲6.7GB。因此創建額外的數組,額外的內存使用似乎似乎合理。
編輯:
反應到OP的評論,我做了關於不同的方式的A
洗牌後的行分配給B
表現了一些測試。首先,在這裏一個小測試B=A[idx,:]
確實創建一個新的ndarray
的A
不僅僅是一個觀點:
>>> import numpy as np
>>> a = np.arange(9).reshape(3,3)
>>> a
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
>>> b = a[[2,0,1],:]
>>> b
array([[6, 7, 8],
[0, 1, 2],
[3, 4, 5]])
>>> b[0]=-5
>>> b
array([[-5, -5, -5],
[ 0, 1, 2],
[ 3, 4, 5]])
>>> a
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
因此,我們確實到b
分配新值葉a
不變。然後我就重新洗牌的A
行的最快的方法,讓他們幾個計時測試到B
:
import numpy as np
import timeit
import numba as nb
s=(300000, 3000)
A = np.arange(s[0]*s[1]).reshape(s)
idx = np.arange(s[0])
#directly keep the indexed array
def test1(x,idx):
return x[idx,:]
#the method of the OP
def test2(x, y, idx):
y[:,:]=x[idx,:]
return y
#using a simple for loop, e.g. if only part of the rows should be assigned
def test3(x,y,idx):
for i in range(len(idx)):
y[i,:] = x[idx[i],:]
return y
#like test3, but numba-compiled
@nb.jit(nopython=True)
def test4(x,y,idx):
for i in range(len(idx)):
y[i,:] = x[idx[i],:]
return y
B = np.zeros(s)
res = timeit.Timer(
'test1(A,idx)',
setup = 'from __main__ import test1, A, idx'
).repeat(7,1)
print('test 1:', np.min(res), np.max(res), np.mean(res))
B = np.zeros(s)
res = timeit.Timer(
'test2(A,B,idx)',
setup = 'from __main__ import test2, A, B, idx'
).repeat(7,1)
print('test 2:', np.min(res), np.max(res), np.mean(res))
B = np.zeros(s)
res = timeit.Timer(
'test3(A,B,idx)',
setup = 'from __main__ import test3, A, B, idx'
).repeat(7,1)
print('test 3:', np.min(res), np.max(res), np.mean(res))
B = np.zeros(s)
res = timeit.Timer(
'test4(A,B,idx)',
setup = 'from __main__ import test4, A, B, idx'
).repeat(7,1)
print('test 4:', np.min(res), np.max(res), np.mean(res))
結果(最小值,最大值,平均值)的7個運行是:
test 1: 19.880664938 21.354912988 20.2604536371
test 2: 73.419507756 139.534279557 122.949712777
test 3: 40.030043285 78.001182537 64.7852914216
test 4: 40.001512514 73.397133578 62.0058947516
最後,一個簡單的for
-loop不會執行得太差,特別是如果您只想分配部分行而不是整個數組。令人驚訝的是numba
似乎沒有提升性能。
你知道'np.random.shuffle'返回'None',所以你只需用'A [None,:]'索引? – MSeifert
@MSeifert甚至將有問題的行更正爲'np.random.shuffle(idx)'產生所描述的行爲。對於Mac而言,最後一行將峯值內存使用量從約24 MB增加到約3.5 GB(使用'resource.getrusage'測試它)。 –
是的,但討論一些可能無法做到的事情是沒有用的。 – MSeifert