[英]NumPy: 2D array from a list of arrays and scalars
我需要从一维数组和标量列表中创建一个2D numpy数组,以便复制标量以匹配1D数组的长度。
期望行为的示例
>>> x = np.ones(5)
>>> something([x, 0, x])
array([[ 1., 1., 1., 1., 1.],
[ 0., 0., 0., 0., 0.],
[ 1., 1., 1., 1., 1.]])
我知道列表中的矢量元素总是具有相同的长度(形状),因此我可以通过执行以下操作“手动”执行此操作:
def something(lst):
for e in lst:
if isinstance(e, np.ndarray):
l = len(e)
break
tmp = []
for e in lst:
if isinstance(e, np.ndarray):
tmp.append(e)
l = len(e)
else:
tmp.append(np.empty(l))
tmp[-1][:] = e
return np.array(tmp)
我要问的是,是否有一些现成的解决方案隐藏在numpy中,或者如果没有,是否有比上面更好的(例如更一般,更可靠,更快)的解决方案。
In [179]: np.column_stack(np.broadcast(x, 0, x))
Out[179]:
array([[ 1., 1., 1., 1., 1.],
[ 0., 0., 0., 0., 0.],
[ 1., 1., 1., 1., 1.]])
要么
In [187]: np.row_stack(np.broadcast_arrays(x, 0, x))
Out[187]:
array([[ 1., 1., 1., 1., 1.],
[ 0., 0., 0., 0., 0.],
[ 1., 1., 1., 1., 1.]])
使用np.broadcast
比np.broadcast_arrays
更快:
In [195]: %timeit np.column_stack(np.broadcast(*[x, 0, x]*10))
10000 loops, best of 3: 46.4 µs per loop
In [196]: %timeit np.row_stack(np.broadcast_arrays(*[x, 0, x]*10))
1000 loops, best of 3: 380 µs per loop
但比你的something
功能慢:
In [201]: %timeit something([x, 0, x]*10)
10000 loops, best of 3: 37.3 µs per loop
请注意, np.broadcast
最多可以传递32个数组:
In [199]: np.column_stack(np.broadcast(*[x, 0, x]*100))
ValueError: Need at least two and fewer than (32) array objects.
而np.broadcast_arrays
是无限的:
In [198]: np.row_stack(np.broadcast_arrays(*[x, 0, x]*100))
Out[198]:
array([[ 1., 1., 1., 1., 1.],
[ 0., 0., 0., 0., 0.],
[ 1., 1., 1., 1., 1.],
...,
[ 1., 1., 1., 1., 1.],
[ 0., 0., 0., 0., 0.],
[ 1., 1., 1., 1., 1.]])
使用np.broadcast
或np.broadcast_arrays
比something
更通用。 它将适用于不同(但可播放)形状的数组,例如:
In [209]: np.column_stack(np.broadcast(*[np.atleast_2d(x), 0, x]))
Out[209]:
array([[ 1., 1., 1., 1., 1.],
[ 0., 0., 0., 0., 0.],
[ 1., 1., 1., 1., 1.]])
而something([np.atleast_2d(x), 0, x])
返回:
In [211]: something([np.atleast_2d(x), 0, x])
Out[211]:
array([array([[ 1., 1., 1., 1., 1.]]), array([ 0.]),
array([ 1., 1., 1., 1., 1.])], dtype=object)
一个较短的方式,但我怀疑是否更快:
l = len(max(lst, key=lambda e: len(e) if isinstance(e, np.ndarray) else 0))
new_lst = np.array([(x if isinstance(x, np.ndarray) else np.ones(l) * x) for x in lst])
编辑:使用np.fromiter
更快地完成:
l = len(max(lst, key=lambda e: len(e) if isinstance(e, np.ndarray) else 0))
new_lst = np.fromiter(((x if isinstance(x, np.ndarray) else np.ones(l) * x) for x in lst))
并使用while循环来更快地完成它,但代码有点长:
i = 0
while not isinstance(lst[i], np.ndarray):
i += 1
l = len(lst[i])
new_lst = np.fromiter(((x if isinstance(x, np.ndarray) else np.ones(l) * x) for x in lst))
对于25行,列表理解版本的something
在broadcase
和broadcast_arrays
之间的速度:
In [48]: ll=[x,0,x,x,0]*5
In [49]: np.vstack([y if isinstance(y,np.ndarray) else np.zeros(5) for y in ll]).shape
Out[49]: (25, 5)
In [50]: timeit np.vstack([y if isinstance(y,np.ndarray) else np.zeros(5) for y in ll]).shape
1000 loops, best of 3: 219 us per loop
In [51]: timeit np.vstack(np.broadcast_arrays(*ll))
1000 loops, best of 3: 790 us per loop
In [52]: timeit np.column_stack(np.broadcast(*ll)).shape
10000 loops, best of 3: 126 us per loop
使用np.array
而不是vstack
它会变得更好:
In [54]: timeit np.array([y if isinstance(y,np.ndarray) else np.zeros(5) for y in ll]).shape
10000 loops, best of 3: 54.2 us per loop
对于2d x
, if
理解的vstack
可能是唯一正确的:
In [66]: x=np.arange(10).reshape(2,5)
In [67]: ll=[x,0,x,x,0]
In [68]: np.vstack([y if isinstance(y,np.ndarray) else np.zeros(5) for y in ll])
Out[68]:
array([[ 0., 1., 2., 3., 4.],
[ 5., 6., 7., 8., 9.],
[ 0., 0., 0., 0., 0.],
[ 0., 1., 2., 3., 4.],
[ 5., 6., 7., 8., 9.],
[ 0., 1., 2., 3., 4.],
[ 5., 6., 7., 8., 9.],
[ 0., 0., 0., 0., 0.]])
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.