我有两个不同大小的 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
和 Y
实际上是大型数组(而且它可能也很丑陋)。有正确的方法吗?
最佳答案
在这种特殊情况下,您希望在 mask
为 True 时加 1,
也许最简单的方法是利用广播和 dtype
提升——也就是说, bool 值在数字上下文中被视为整数。
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 中分配/管理大型数组/交换淹没了相对较小的数组
计算成本。
关于python - 根据不同大小的数组 Y 的条件屏蔽数组 X,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42065007/