Read/Write NumPy 结构化数组非常慢,线性大小慢
Read/Write NumPy Structured Array very slow, linear in size slow
令我惊讶的是,我发现读取和写入 NumPy 结构化数组似乎与数组的大小成线性关系。
因为这看起来很不对,我想知道,如果我在这里做错了什么或者是否有错误。
这是一些示例代码:
def test():
A = np.zeros(1, dtype=[('a', np.int16), ('b', np.int16, (1,100))])
B = np.zeros(1, dtype=[('a', np.int16), ('b', np.int16, (1,10000))])
C = [{'a':0, 'b':[0 for i in xrange(100)]}]
D = [{'a':0, 'b':[0 for i in xrange(10000)]}]
for i in range(100):
A[0]['a'] = 1
B[0]['a'] = 1
B['a'][0] = 1
x = A[0]['a']
x = B[0]['a']
C[0]['a'] = 1
D[0]['a'] = 1
行分析给出以下结果:
Total time: 5.28901 s, Timer unit: 1e-06 s
Function: test at line 454
Line # Hits Time Per Hit % Time Line Contents
==============================================================
454 @profile
455 def test():
456
457 1 10 10.0 0.0 A = np.zeros(1, dtype=[('a', np.int16), ('b', np.int16, (1,100))])
458 1 13 13.0 0.0 B = np.zeros(1, dtype=[('a', np.int16), ('b', np.int16, (1,10000))])
459
460 101 39 0.4 0.0 C = [{'a':0, 'b':[0 for i in xrange(100)]}]
461 10001 3496 0.3 0.1 D = [{'a':0, 'b':[0 for i in xrange(10000)]}]
462
463 101 54 0.5 0.0 for i in range(100):
464 100 20739 207.4 0.4 A[0]['a'] = 1
465 100 1741699 17417.0 32.9 B[0]['a'] = 1
466
467 100 1742374 17423.7 32.9 B['a'][0] = 1
468 100 20750 207.5 0.4 x = A[0]['a']
469 100 1759634 17596.3 33.3 x = B[0]['a']
470
471 100 123 1.2 0.0 C[0]['a'] = 1
472 100 76 0.8 0.0 D[0]['a'] = 1
如您所见,我什至没有访问更大的数组(尽管 10.000 的大小实际上非常小..)。顺便说一句: shape=(10000,1) 而不是 (1,10000).
的行为相同
有什么想法吗?
将结构化数组解释为字典列表,并与内置函数进行比较,预期的计算成本与大小无关(参见 C 和 D)
NumPy 版本。 1.10.1.
在 ipython
中使用 timeit
我得到的 A
和 B
的时间基本相同
In [30]: timeit A[0]['a']=1
1000000 loops, best of 3: 1.9 µs per loop
In [31]: timeit B[0]['a']=1
1000000 loops, best of 3: 1.87 µs per loop
In [32]: timeit B['a'][0]=1
1000000 loops, best of 3: 554 ns per loop
In [33]: timeit x=A[0]['a']
1000000 loops, best of 3: 1.74 µs per loop
In [34]: timeit x=B[0]['a']
1000000 loops, best of 3: 1.73 µs per loop
即使我用 100 条记录创建 B
,时间也不会改变
In [39]: timeit B['a']=1 # set 100 values at once
1000000 loops, best of 3: 1.08 µs per loop
In [40]: timeit B['a'][10]=1
1000000 loops, best of 3: 540 ns per loop
In [41]: B.shape # 2Mb size
Out[41]: (100,)
即使 'b' 字段设置 10000 个值也不昂贵
In [46]: B['b'].shape
Out[46]: (100, 1, 10000)
In [47]: B['b'][:,:,:100]=1
In [48]: timeit B['b'][:,:,:100]=1
100000 loops, best of 3: 10.7 µs per loop
In [49]: B['b'].sum()
Out[49]: 10000
In [50]: np.__version__
Out[50]: '1.11.0'
这是在 NumPy 1.10.1 上使用结构化数组的 known issue。问题日志中的对话似乎表明它已在所有更新的 NumPy 版本上修复,包括 1.10.2 和 1.11.0。
更新 NumPy 应该可以解决问题。
令我惊讶的是,我发现读取和写入 NumPy 结构化数组似乎与数组的大小成线性关系。
因为这看起来很不对,我想知道,如果我在这里做错了什么或者是否有错误。
这是一些示例代码:
def test():
A = np.zeros(1, dtype=[('a', np.int16), ('b', np.int16, (1,100))])
B = np.zeros(1, dtype=[('a', np.int16), ('b', np.int16, (1,10000))])
C = [{'a':0, 'b':[0 for i in xrange(100)]}]
D = [{'a':0, 'b':[0 for i in xrange(10000)]}]
for i in range(100):
A[0]['a'] = 1
B[0]['a'] = 1
B['a'][0] = 1
x = A[0]['a']
x = B[0]['a']
C[0]['a'] = 1
D[0]['a'] = 1
行分析给出以下结果:
Total time: 5.28901 s, Timer unit: 1e-06 s
Function: test at line 454
Line # Hits Time Per Hit % Time Line Contents
==============================================================
454 @profile
455 def test():
456
457 1 10 10.0 0.0 A = np.zeros(1, dtype=[('a', np.int16), ('b', np.int16, (1,100))])
458 1 13 13.0 0.0 B = np.zeros(1, dtype=[('a', np.int16), ('b', np.int16, (1,10000))])
459
460 101 39 0.4 0.0 C = [{'a':0, 'b':[0 for i in xrange(100)]}]
461 10001 3496 0.3 0.1 D = [{'a':0, 'b':[0 for i in xrange(10000)]}]
462
463 101 54 0.5 0.0 for i in range(100):
464 100 20739 207.4 0.4 A[0]['a'] = 1
465 100 1741699 17417.0 32.9 B[0]['a'] = 1
466
467 100 1742374 17423.7 32.9 B['a'][0] = 1
468 100 20750 207.5 0.4 x = A[0]['a']
469 100 1759634 17596.3 33.3 x = B[0]['a']
470
471 100 123 1.2 0.0 C[0]['a'] = 1
472 100 76 0.8 0.0 D[0]['a'] = 1
如您所见,我什至没有访问更大的数组(尽管 10.000 的大小实际上非常小..)。顺便说一句: shape=(10000,1) 而不是 (1,10000).
的行为相同有什么想法吗?
将结构化数组解释为字典列表,并与内置函数进行比较,预期的计算成本与大小无关(参见 C 和 D)
NumPy 版本。 1.10.1.
在 ipython
中使用 timeit
我得到的 A
和 B
In [30]: timeit A[0]['a']=1
1000000 loops, best of 3: 1.9 µs per loop
In [31]: timeit B[0]['a']=1
1000000 loops, best of 3: 1.87 µs per loop
In [32]: timeit B['a'][0]=1
1000000 loops, best of 3: 554 ns per loop
In [33]: timeit x=A[0]['a']
1000000 loops, best of 3: 1.74 µs per loop
In [34]: timeit x=B[0]['a']
1000000 loops, best of 3: 1.73 µs per loop
即使我用 100 条记录创建 B
,时间也不会改变
In [39]: timeit B['a']=1 # set 100 values at once
1000000 loops, best of 3: 1.08 µs per loop
In [40]: timeit B['a'][10]=1
1000000 loops, best of 3: 540 ns per loop
In [41]: B.shape # 2Mb size
Out[41]: (100,)
即使 'b' 字段设置 10000 个值也不昂贵
In [46]: B['b'].shape
Out[46]: (100, 1, 10000)
In [47]: B['b'][:,:,:100]=1
In [48]: timeit B['b'][:,:,:100]=1
100000 loops, best of 3: 10.7 µs per loop
In [49]: B['b'].sum()
Out[49]: 10000
In [50]: np.__version__
Out[50]: '1.11.0'
这是在 NumPy 1.10.1 上使用结构化数组的 known issue。问题日志中的对话似乎表明它已在所有更新的 NumPy 版本上修复,包括 1.10.2 和 1.11.0。
更新 NumPy 应该可以解决问题。