我注意到索引多维数组比索引单维数组需要更多时间
a1 = np.arange(1000000)
a2 = np.arange(1000000).reshape(1000, 1000)
a3 = np.arange(1000000).reshape(100, 100, 100)
当我索引a1
%%timeit
a1[500000]
最慢的跑步比最快跑的时间长39.17倍。这可能意味着正在缓存中间结果。 10000000次循环,最佳3:每循环84.6 ns
%%timeit
a2[500, 0]
最慢的运行时间比最快的运行时间长31.85倍。这可能意味着正在缓存中间结果。 10000000次循环,最佳3:每循环102 ns
%%timeit
a3[50, 0, 0]
最慢的运行时间比最快的运行时间长46.72倍。这可能意味着正在缓存中间结果。 10000000次循环,最佳3:每循环119 ns
在什么时候我应该考虑一种索引或切片多维数组的替代方法?是什么情况使得值得努力和失去透明度?
答案 0 :(得分:5)
切片(n, m)
数组的另一种方法是展平数组并得出它的一维位置必须是什么。
考虑a = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
我们可以使用a[1, 2]
获取第2行第3列并获取5
或者,如果我们用1 * a.shape[1] + 2
展平a
,我们可以计算order='C'
是一维位置
因此我们可以使用a.ravel()[1 * a.shape[1] + 2]
效率这么高吗?不,为了从数组索引单个数字,它不值得麻烦。
如果我们想从数组中切出许多数字呢?我为2-D阵列设计了以下测试
2-D测试
from timeit import timeit
n, m = 10000, 10000
a = np.random.rand(n, m)
r = pd.DataFrame(index=np.power(10, np.arange(7)), columns=['Multi', 'Flat'])
for k in r.index:
b = np.random.randint(n, size=k)
c = np.random.randint(m, size=k)
kw = dict(setup='from __main__ import a, b, c', number=100)
r.loc[k, 'Multi'] = timeit('a[b, c]', **kw)
r.loc[k, 'Flat'] = timeit('a.ravel()[b * a.shape[1] + c]', **kw)
r.div(r.sum(1), 0).plot.bar()
看来,当切片超过100,000个数字时,最好平整阵列。
3-D
如何呢?
三维测试
from timeit import timeit
l, n, m = 1000, 1000, 1000
a = np.random.rand(l, n, m)
r = pd.DataFrame(index=np.power(10, np.arange(7)), columns=['Multi', 'Flat'])
for k in r.index:
b = np.random.randint(l, size=k)
c = np.random.randint(m, size=k)
d = np.random.randint(n, size=k)
kw = dict(setup='from __main__ import a, b, c, d', number=100)
r.loc[k, 'Multi'] = timeit('a[b, c, d]', **kw)
r.loc[k, 'Flat'] = timeit('a.ravel()[b * a.shape[1] * a.shape[2] + c * a.shape[1] + d]', **kw)
r.div(r.sum(1), 0).plot.bar()
类似的结果,可能更具戏剧性。
<强> 结论 强>
对于二维数组,如果需要从数组中提取超过100,000个元素,请考虑展平并导出展平位置。
对于3个或更多维度,似乎很清楚扁平化阵列几乎总是更好。
欢迎批评
我做错什么了吗?我没有想到明显的东西吗?