Numpy数组一次修改多个元素

时间:2013-12-18 11:06:56

标签: python numpy indexing

我有三个numpy数组:

row = np.array([1,2,3,4,5])

# a is a subset of row:

a = np.array([1, 5])

# b is an array that I use to change some elements in the first row array:

b = np.array([10, 550])

我需要做的是将一次性更改为a对应的b元素中存在的行数组元素。

即:

>> modified_row
array([10, 2, 3, 4, 500])

以天真的方式这样做:

for i in range(len(a)):
    row[np.where(row==a[i])]= b[i]

我想要一个类似的解决方案;

row[np.where(row==a)] = b

但这不起作用......

提前致谢!

5 个答案:

答案 0 :(得分:5)

如果您对阵列的排序没有保证,那么使用np.searchsorted可以实现合理有效的实施:

def find_and_replace(array, find, replace):
    sort_idx = np.argsort(array)
    where_ = np.take(sort_idx, 
                     np.searchsorted(array, find, sorter=sort_idx))
    if not np.all(array[where_] == find):
        raise ValueError('All items in find must be in array')
    row[where_] = b

唯一不能处理的是array中的重复输入,但除此之外它就像魅力一样:

>>> row = np.array([5,4,3,2,1])
>>> a = np.array([5, 1])
>>> b = np.array([10, 550])
>>> find_and_replace(row, a, b)
>>> row
array([ 10,   4,   3,   2, 550])

>>> row = np.array([5,4,3,2,1])
>>> a = np.array([1, 5])
>>> b = np.array([10, 550])
>>> find_and_replace(row, a, b)
>>> row
array([550,   4,   3,   2,  10])

>>> row = np.array([4, 5, 1, 3, 2])
>>> find_and_replace(row, a, b)
>>> row
array([  4, 550,  10,   3,   2])

答案 1 :(得分:4)

请注意@ Jaime的答案更好 - 尽管它依赖于元素的排序,但它被标记为正确。这是一个工作版本,它不会就地修改row,但在一般情况下会起作用。这篇文章的最后是我原来的答案。

import numpy as np

def replaced(row, a, b):
    row_order = row.argsort()
    a_order = a.argsort()

    sorted_row = row[row_order]
    sorted_a = a[a_order]
    sorted_b = b[a_order]

    sorted_row[np.in1d(sorted_row, sorted_a)] = sorted_b

    # return results in original order
    return sorted_row[row_order.argsort()]

a = np.array([1, 5])
b = np.array([10, 550])

row = np.array([1,2,3,4,5])
print replaced(row, a, b)

row = np.array([5,4,3,2,1])
print replaced(row, a, b)

row = np.array([4, 5, 1, 3, 2])
print replaced(row, a, b)

结果:

>>> row = np.array([1,2,3,4,5])
>>> print replaced(row, a, b)
[ 10   2   3   4 550]
>>> 
>>> row = np.array([5,4,3,2,1])
>>> print replaced(row, a, b)
[550   4   3   2  10]
>>> 
>>> row = np.array([4, 5, 1, 3, 2])
>>> print replaced(row, a, b)
[  4 550  10   3   2]

原始不正确的答案

执行此操作的一种方法是使用in1d函数,该函数将生成一个布尔数组,可用于索引row,如下所示。

请注意,如果row的元素不唯一,或者a

中有重复的元素,则可能会遇到此问题(和其他方法)的问题
>>> import numpy as np
>>> row = np.array([1,2,3,4,5])
>>> a = np.array([1, 5])
>>> b = np.array([10, 550])
>>> np.in1d(row, a)
array([ True, False, False, False,  True], dtype=bool)
>>> row[np.in1d(row, a)] = b
>>> row
array([ 10,   2,   3,   4, 550])

您通常也可以使用最初用于提取a的索引/布尔数组来实现此目的。

答案 2 :(得分:3)

另一种可能性:

>>> row = np.array([1,2,3,4,5])
>>> row[np.any(row.reshape(-1, 1) == a, axis=1)] = b
>>> row
array([ 10,   2,   3,   4, 550])

这种方式的工作原理是:

>>> row.reshape(-1, 1) == a
array([[ True, False],
       [False, False],
       [False, False],
       [False, False],
       [False,  True]], dtype=bool)
>>> np.any(row.reshape(-1, 1) == a, axis=1)
array([ True, False, False, False,  True], dtype=bool)

此布尔掩码对应于您要替换的条目。

此解决方案的时间和空间复杂性非常糟糕:Θ( nm )替换 n 大小的数组中的 m 条目由于大布尔掩码。对于您的特定用例,我不建议使用in1d,但它会显示在相关情况下有用的绕道。

答案 3 :(得分:2)

一个有趣的替代解决方案是使用numpy.put作为记录here。在这种情况下,仔细考虑如果row中存在重复会发生什么也很重要。默认情况下,如果在这种情况下有两个以上的匹配项,put将遍历b中的元素。

import numpy as np
row = np.array([1,2,3,4,5])
a = np.array([1, 5])
b = np.array([10, 550])
index_list = [np.where(row == element) for element in a]
np.put(row,index_list,b)
row
array([ 10,   2,   3,   4, 550]) #output

编辑:在评论中处理基于索引的作业查询的附加示例:

>>> import numpy as np
>>> target_array = np.arange(50)
>>> n = 2 
>>> index_array = np.arange(0,len(target_array),n)
>>> b = np.array([10, 550])
>>> np.put(target_array, index_array, b)
>>> target_array #note that np.put cycles through the substitutions in b
array([ 10,   1, 550,   3,  10,   5, 550,   7,  10,   9, 550,  11,  10,
        13, 550,  15,  10,  17, 550,  19,  10,  21, 550,  23,  10,  25,
       550,  27,  10,  29, 550,  31,  10,  33, 550,  35,  10,  37, 550,
        39,  10,  41, 550,  43,  10,  45, 550,  47,  10,  49])

答案 4 :(得分:0)

您现在可以使用array.put

>>> a = np.arange(5)
>>> np.put(a, [0, 2], [-44, -55])
>>> a
array([-44,   1, -55,   3,   4])