简体   繁体   English

Numpy数组一次修改多个元素

[英]Numpy array modifying multiple elements at once

I have three numpy arrays: 我有三个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])

What I need to do is to change in one shot the elements of the row array that are present in a with the correspondent b elements. 我需要做的是一次性改变a对应的b元素中存在的行数组的元素。

ie: 即:

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

Doing this in a naive way would be: 以天真的方式这样做将是:

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

I would like a solution like; 我想要一个解决方案;

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

But that doesn't work... 但这不起作用......

Thanks in advance! 提前致谢!

If you don't have guarantees on the sorting of your arrays, you could have a reasonably efficient implementation using np.searchsorted : 如果您对阵列的排序没有保证,那么使用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

The only thing that this can't handle is repeated entries in array , but other than that it works like a charm: 唯一不能处理的是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])

Please note @Jaime's answer is better - this was marked as correct despite it relying on the ordering of the elements. 请注意@ Jaime的答案更好 - 尽管它依赖于元素的排序,但它被标记为正确。 Here is a working version that does not modify row in-place but otherwise will work in the general case. 这是一个工作版本,不会就地修改row ,但在一般情况下也可以。 At the end of this post is my original answer. 在这篇文章的最后是我的原始答案。

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)

results: 结果:

>>> 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]

ORIGINAL INCORRECT ANSWER 原始的不正确的答案

One way to do this is with the in1d function, which will generate a boolean array that you can use to index row as shown below. 一种方法是使用in1d函数,它将生成一个布尔数组,您可以使用它来索引row ,如下所示。

Note that you may have problems with this (and other methods) if the elements of row are not unique or if you have repeated elements in a 请注意,如果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])

You can normally use whatever index/boolean array you originally used to extract a for this purpose too. 您通常可以使用最初用于提取a任何索引/布尔数组来实现此目的。

Another possibility: 另一种可能性

>>> 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])

The way this works is: 这种方式的工作原理是:

>>> 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)

And this boolean mask corresponds to the entries you want to replace. 此布尔掩码对应于要替换的条目。

The time and space complexity of this solution are pretty bad: Θ( nm ) to replace m entries in an array of size n due to the large boolean mask. 此解决方案的时间和空间复杂性非常糟糕:由于布尔掩码较大,Θ( nm )将替换大小为n的数组中的m个条目。 I don't recommend it over in1d for your specific use case, but it shows a detour that is useful in related cases. 对于您的特定用例,我不建议使用in1d ,但是它显示了在相关情况下有用的绕道。

An interesting alternative solution is to use numpy.put as documented here . 一个有趣的替代解决方案是使用numpy.put作为记录在这里 In this case it is also important to think carefully about what will happen if there are duplicates in row . 在这种情况下,仔细考虑如果row有重复项将会发生什么也很重要。 By default, put will cycle through the elements in b if there are more than two matches in this case. 默认情况下,如果在这种情况下有两个以上的匹配项,则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

Edit: additional example to deal with index-based assignment query in comments: 编辑:在注释中处理基于索引的赋值查询的附加示例:

>>> 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])

You can now use array.put 您现在可以使用array.put

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM