numpy masking array X基于具有不同大小的数组Y的条件

时间:2017-02-06 10:03:48

标签: python arrays numpy-broadcasting

我有两个不同大小的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实际上是大数组(并且它可能也很丑),这个代价很高。有没有正确的方法来做到这一点?

1 个答案:

答案 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()

enter image description here

随着数组的大小变大,tileouter之间的差异 应该相对于总时间减少,因为所需的时间 在RAM / swap中分配/管理大型数据压倒了相对较小的数据 计算成本。