In [93]: a = np.random.randn(3218, 1415)
In [94]: rows = np.random.randint(a.shape[0], size=2000)
In [95]: cols = np.random.randint(a.shape[1], size=6)
In [96]: timeit a[rows][:, cols]
10 loops, best of 3: 186 ms per loop
In [97]: timeit (a.ravel()[(cols + (rows * a.shape[1]).reshape((-1,1))).ravel()]).reshape(rows.size, cols.size)
1000 loops, best of 3: 1.56 ms per loop
**初始答案:**以下是成绩单:
In [79]: a = np.random.randn(3218, 6)
In [80]: a.shape
Out[80]: (3218, 6)
In [81]: rows = np.random.randint(a.shape[0], size=2000)
In [82]: cols = np.array([1,3,4,5])
时间方法1:
In [83]: timeit a[rows][:, cols]
1000 loops, best of 3: 1.26 ms per loop
时间方法二:
In [84]: timeit (a.ravel()[(cols + (rows * a.shape[1]).reshape((-1,1))).ravel()]).reshape(rows.size, cols.size)
1000 loops, best of 3: 568 us per loop
检查结果是否实际相同:
In [85]: result1 = a[rows][:, cols]
In [86]: result2 = (a.ravel()[(cols + (rows * a.shape[1]).reshape((-1,1))).ravel()]).reshape(rows.size, cols.size)
In [87]: np.sum(result1 - result2)
Out[87]: 0.0
4条答案
按热度按时间ws51t4hk1#
让我试着总结Jaime和TheodrosZelleke的优秀答案,并加入一些评论。
1.高级(花哨)索引总是返回一个副本,而不是视图。
a[rows][:,cols]
意味着 * 两个 * 花哨的索引操作,因此创建并丢弃了一个中间副本a[rows]
。方便且可读,但不是非常有效。此外,要注意[:,cols]
通常从C-cont.源代码生成一个Fortran连续副本。a[rows.reshape(-1,1),cols]
是基于rows.reshape(-1,1)
和cols
是broadcast到预期结果的形状的事实的单个高级索引表达式。1.一个常见的经验是,扁平化数组中的索引可能比花哨的索引更高效,因此另一种方法是
或
1.效率将取决于内存访问模式以及起始数组是C连续的还是Fortran连续的,因此需要进行实验。
1.只有在真正需要的时候才使用花哨的索引:基本切片
a[rstart:rstop:rstep, cstart:cstop:cstep]
返回一个视图(虽然不连续),应该更快!s71maibg2#
令我惊讶的是,这种计算第一个线性1D索引的lenghty表达式比问题中提出的连续数组索引快50%:
UPDATE:OP更新了初始数组的形状描述,更新后的大小加速比超过99%:
**初始答案:**以下是成绩单:
时间方法1:
时间方法二:
检查结果是否实际相同:
yxyvkwin3#
如果你使用花哨的索引和广播来切片,你可以得到一些速度:
如果你从百分比的Angular 考虑,做一些事情快15%总是好的,但在我的系统中,对于你的数组大小,这将减少40 us的切片时间,很难相信240 us的操作会成为你的瓶颈。
hkmswyz64#
使用
np.ix_
,你可以用类似的速度来ravel/reshape,但代码更清晰: