从下“索引阵列”的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