在numpy中交换多值的子集

时间:2012-08-22 15:08:01

标签: numpy swap numpy-broadcasting

给出一个起始numpy数组,如下所示:

B = np.array( [1, 1, 1, 0, 2, 2, 1, 3, 3, 0, 4, 4, 4, 4] )

当存在重复时,将一组值换成另一组值的最有效方法是什么?例如,让

s1 = [1,2,4]
s2 = [4,1,2]

低效的交换方法将遍历s1s2,如下所示:

B2 = B.copy()
for x,y in zip(s1,s2):
    B2[B==x] = y

作为输出

B2 -> [4, 4, 4, 0, 1, 1, 4, 3, 3, 0, 2, 2, 2, 2]

有没有办法在没有zip循环的情况下就地执行此操作?

2 个答案:

答案 0 :(得分:2)

>>> B = np.array( [1, 1, 1, 0, 2, 2, 1, 3, 3, 0, 4, 4, 4, 4] )
>>> s1 = [1,2,4]
>>> s2 = [4,1,2]
>>> B2 = B.copy()
>>> c, d = np.where(B == np.array(s1)[:,np.newaxis])
>>> B2[d] = np.repeat(s2,np.bincount(c))
>>> B2
array([4, 4, 4, 0, 1, 1, 4, 3, 3, 0, 2, 2, 2, 2])

答案 1 :(得分:1)

如果你只有0到n之间的整数(如果不是没有问题可以推广到任何整数范围,除非它非常稀疏),最有效的方法是使用take / fancy索引:

swap = np.arange(B.max() + 1) # all values in B
swap[s1] = s2 # replace the values you want to be replaced

B2 = swap.take(B) # or swap[B]

对于这里给出的小B来说,这几乎快两倍,但是如果B值越大,它的速度越快,重复B到大约100000的长度就会得到8倍。这也避免了每个s1元素的==操作,因此当s1 / s2变大时,它会扩展得更好。

编辑:你也可以使用np.put(也在另一个答案中)来获得swap[s1] = s2的某些加速。对于这些1D问题,take / put只是更快。