有没有办法对一个带有几个numpy数组的操作进行矢量化并将它们放入一个字典列表中?
这是一个简化的例子。真实场景可能涉及更多数组和更多字典键。
import numpy as np
x = np.arange(10)
y = np.arange(10, 20)
z = np.arange(100, 110)
print [dict(x=x[ii], y=y[ii], z=z[ii]) for ii in xrange(10)]
我可能会在xrange
电话中进行数千或数十万次迭代。创建x
,y
和z
的所有操作都是矢量化的(我的示例并不像上面那么简单)。因此,只有1个循环留下来摆脱,我预计会导致巨大的加速。
我尝试使用map
函数创建dict和各种其他解决方法。似乎Python for
循环是缓慢的部分(像往常一样)。由于预先存在的API要求,我有点坚持使用字典。但是,没有dicts和记录数组的解决方案或其他东西会很有趣,但最终我认为它不适用于现有的API。
答案 0 :(得分:3)
用你的小例子,我在获取比列表和词典理解的组合更快的速度方面遇到了麻烦
In [105]: timeit [{'x':i, 'y':j, 'z':k} for i,j,k in zip(x,y,z)]
100000 loops, best of 3: 15.5 µs per loop
In [106]: timeit [{'key':{'x':i, 'y':j, 'z':k}} for i,j,k in zip(x,y,z)]
10000 loops, best of 3: 37.3 µs per loop
在分区之前使用数组连接来连接数组的替代方法较慢。
In [108]: timeit [{'x':x_, 'y':y_, 'z':z_} for x_, y_, z_ in np.column_stack((x,y,z))]
....
10000 loops, best of 3: 58.2 µs per loop
=======================
结构化数组最简单recfunctions
:
In [109]: from numpy.lib import recfunctions
In [112]: M=recfunctions.merge_arrays((x,y,z))
In [113]: M.dtype.names=['x','y','z']
In [114]: M
Out[114]:
array([(0, 10, 100), (1, 11, 101), (2, 12, 102), (3, 13, 103),
(4, 14, 104), (5, 15, 105), (6, 16, 106), (7, 17, 107),
(8, 18, 108), (9, 19, 109)],
dtype=[('x', '<i4'), ('y', '<i4'), ('z', '<i4')])
In [115]: M['x']
Out[115]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
时间慢得多,但是如果你想一次访问所有x
值,那么比从所有词典中获取它们要好得多。
np.rec.fromarrays((x,y,z),names=['x','y','z'])
生成具有给定名称的重新排列。大约相同的速度。
我还可以构造一个正确的dtype和shape的空数组,并将数组复制到它。这可能与此merge
一样快,但描述起来更复杂。
我建议优化使用/访问的数据结构而不是构建速度。一般来说,你构造一次,并多次使用它。
============
In [125]: dt=np.dtype([('x',x.dtype),('y',y.dtype),('z',z.dtype)])
In [126]: xyz=np.zeros(x.shape,dtype=dt)
In [127]: xyz['x']=x; xyz['y']=y; xyz['z']=z
# or for n,d in zip(xyz.dtype.names, (x,y,z)): xyz[n] = d
In [128]: xyz
Out[128]:
array([(0, 10, 100), (1, 11, 101), (2, 12, 102), (3, 13, 103),
(4, 14, 104), (5, 15, 105), (6, 16, 106), (7, 17, 107),
(8, 18, 108), (9, 19, 109)],
dtype=[('x', '<i4'), ('y', '<i4'), ('z', '<i4')])
答案 1 :(得分:2)
这是一个(Num)?Pythonic方式:
In [18]: names = np.array(['x', 'y', 'z'])
In [38]: map(dict, np.dstack((np.repeat(names[None, :], 10, axis=0), np.column_stack((x, y, z)))))
Out[38]:
[{'x': '0', 'y': '10', 'z': '100'},
{'x': '1', 'y': '11', 'z': '101'},
{'x': '2', 'y': '12', 'z': '102'},
{'x': '3', 'y': '13', 'z': '103'},
{'x': '4', 'y': '14', 'z': '104'},
{'x': '5', 'y': '15', 'z': '105'},
{'x': '6', 'y': '16', 'z': '106'},
{'x': '7', 'y': '17', 'z': '107'},
{'x': '8', 'y': '18', 'z': '108'},
{'x': '9', 'y': '19', 'z': '109'}]
另请注意,如果您不需要同时使用所有词典,则只需创建一个生成器并按需访问每个项目。
(dict(x=x[ii], y=y[ii], z=z[ii]) for ii in xrange(10))
如果你想要一个嵌套字典,我建议列表理解:
In [88]: inner = np.dstack((np.repeat(names[None, :], 10, axis=0), np.column_stack((x, y))))
In [89]: [{'connection': d} for d in map(dict, inner)]
Out[89]:
[{'connection': {'x': '0', 'y': '10'}},
{'connection': {'x': '1', 'y': '11'}},
{'connection': {'x': '2', 'y': '12'}},
{'connection': {'x': '3', 'y': '13'}},
{'connection': {'x': '4', 'y': '14'}},
{'connection': {'x': '5', 'y': '15'}},
{'connection': {'x': '6', 'y': '16'}},
{'connection': {'x': '7', 'y': '17'}},
{'connection': {'x': '8', 'y': '18'}},
{'connection': {'x': '9', 'y': '19'}}]
答案 2 :(得分:1)
这是一种混合使用NumPy
和Pandas
的方法 -
# Stack into columns & create a pandas dataframe with appropriate col names
a = np.column_stack((x.ravel(),y.ravel(),z.ravel()))
df = pd.DataFrame(a,columns=[['x','y','z']])
# Convert to list of dicts
out = df.T.to_dict().values()
示例运行 -
In [52]: x
Out[52]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [53]: y
Out[53]: array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
In [54]: z
Out[54]: array([100, 101, 102, 103, 104, 105, 106, 107, 108, 109])
In [55]: out
Out[55]:
[{'x': 0, 'y': 10, 'z': 100},
{'x': 1, 'y': 11, 'z': 101},
{'x': 2, 'y': 12, 'z': 102},
{'x': 3, 'y': 13, 'z': 103},
{'x': 4, 'y': 14, 'z': 104},
{'x': 5, 'y': 15, 'z': 105},
{'x': 6, 'y': 16, 'z': 106},
{'x': 7, 'y': 17, 'z': 107},
{'x': 8, 'y': 18, 'z': 108},
{'x': 9, 'y': 19, 'z': 109}]