我有两个不同大小的1-dim数组X和Y.我正在尝试构建由X和Y上的条件产生的2-dim数组。例如:
X=np.array([0.3, 2.1, 4.3])
Y=np.array([1.5, 3.5])
mask = X>Y[:,np.newaxis]
现在我想执行类似X[mask]=X[mask]+1
的内容,因此对于上面的例子,它会导致:
newX = np.array([0.3, 3.1, 5.3],[0.3, 2.1, 5.3]])
我设法通过这样做得到了这个结果:
newX = np.append(X, X).reshape(2,3)
newX[mask]=newX[mask]+1
但是这个硬编码了Y数组的长度(示例中为2),并且包含一个带有np.append的副本,如果X ad Y实际上是大数组(并且它可能也很丑),这个代价很高。有没有正确的方法来做到这一点?
答案 0 :(得分:1)
在这种特殊情况下,您希望在mask
为True的地方添加1,
也许最简单的方法是利用广播和dtype
促销 - 也就是说,在数字语境中将布尔值视为整数。
In [49]: X + mask
Out[49]:
array([[ 0.3, 3.1, 5.3],
[ 0.3, 2.1, 5.3]])
如果可能,请使用广播代替X
的明确平铺副本。
但是,如果您需要newX
,则可以使用
In [54]: np.tile(X, (Y.size,1))
Out[54]:
array([[ 0.3, 2.1, 4.3],
[ 0.3, 2.1, 4.3]])
np.tile
避免了np.outer
所做的乘法,因此为此目的更快。
例如,使用此设置:
import numpy as np
import timeit
import collections
import matplotlib.pyplot as plt
timing = collections.defaultdict(list)
Ns = np.linspace(10, 10000, 5).astype(int)
Ms = np.linspace(10, 10000, 5).astype(int)
for N, M in zip(Ns, Ms):
X = np.random.random(N)
Y = np.random.random(M)
timing['tile'].append(timeit.timeit(
'np.tile(X, (Y.size,1))',
'from __main__ import np, X, Y',
number=10))
timing['outer'].append(timeit.timeit(
'np.outer(np.ones_like(Y),X)',
'from __main__ import np, X, Y',
number=10))
plt.plot(Ns*Ms, timing['tile'], label='tile')
plt.plot(Ns*Ms, timing['outer'], label='outer')
plt.legend(loc='best')
plt.show()
随着数组的大小变大,tile
和outer
之间的差异
应该相对于总时间减少,因为所需的时间
在RAM / swap中分配/管理大型数据压倒了相对较小的数据
计算成本。