Python:基于多个子集更改数组元素的值

时间:2018-01-31 20:34:49

标签: python arrays numpy

我正在尝试根据子集的子集修改数组的值,但我找不到这样做的方法。我认为这暴露了我对数组索引和子集的确切工作方式以及视图的缺乏了解,但我无法在任何地方找到解决方案,所以我希望有人可以帮助我。

示例问题:

import numpy as np

#generate some simple data
MyArray=np.arange(20).reshape(4,5)

>>>MyArray
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19]])

#subset 1
i=np.where(MyArray > 5)

#subset of that subset
j=np.where(MyArray[i] < 15)

>>>MyArray[i][j]
array([ 6,  7,  8,  9, 10, 11, 12, 13, 14])

太棒了,这就是我期望看到的!但是,如果我现在想要将这些值更改为其他值,我就不能:

>>>MyArray[i][j]=999
>>>MyArray[i][j]
array([ 6,  7,  8,  9, 10, 11, 12, 13, 14])

#hmmmm :(

一个有效的丑陋解决方案

我可以通过循环遍历j的元素来获得要改变的值,但这看起来非常笨拙&amp;难以理解:

#get number of elements in j
nj=np.size(j)

#loop over each element of j and modify the corresponding ith element 
of MyArray 
for j_it in range(0,nj):
    MyArray[i[0][j[0][j_it]]][i[1][j[0][j_it]]]=999

>>>MyArray
array([[  0,   1,   2,   3,   4],
       [  5, 999, 999, 999, 999],
       [999, 999, 999, 999, 999],
       [ 15,  16,  17,  18,  19]])

同样,我可以仅使用一个子集化级别来修改MyArray

ii=np.where((MyArray > 5) & (MyArray < 15))
MyArray[ii]=999
>>>MyArray
array([[  0,   1,   2,   3,   4],
       [  5, 999, 999, 999, 999],
       [999, 999, 999, 999, 999],
       [ 15,  16,  17,  18,  19]])

那么,第一个例子我哪里出错?

注意: - 我知道我的最后一个解决方案适用于这个问题,但我的实际问题必然涉及更多数据和第二级子集(可能还有第三个......)

在此先感谢,如果这很简单,我真的应该能够从文档中解决这个问题而道歉:我还没有能够:(

4 个答案:

答案 0 :(得分:2)

正如你所说,你的最后一个例子解决了你的问题。您缺少的问题是,调用MyArray[i]会创建一个新数组,然后您使用MyArray[i][j]再次编制索引。当您尝试分配此子集的结果时,您实际上并未分配到MyArray

要做到与第一个示例类似,您可能希望在一个操作中执行所有操作:

import numpy as np

#generate some simple data
MyArray=np.arange(20).reshape(4,5)

>>>MyArray
MyArray([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19]])

#subset 1
i=np.where(MyArray > 5)

#subset of that subset
j=np.where(MyArray[i] < 15)

# Mask array subset
MyArray[i[0][j[0]], i[1][j[0]]] = 999

>>>MyArray
MyArray([[  0,   1,   2,   3,   4],
   [  5, 999, 999, 999, 999],
   [999, 999, 999, 999, 999],
   [ 15,  16,  17,  18,  19]])

基本上,ij都是包含数组的元组,指示哪些索引在where语句中匹配。 i包含两个数组,每个数组对应MyArray中的每个维度。 j包含i中包含的数组的单个维度的一个数组。您希望在j[0]中获取两个数组的i元素。

希望这是有道理的。如果您有疑问,请告诉我。

答案 1 :(得分:1)

尝试创建布尔数组:

condition_1 = MyArray > 5
condition_2 = MyArray < 15

然后您可以使用按位&amp;

bools = condition1 & condition2

的值如下:

[[ False,  False,  False,  False,  False],
   [ True,  True,  True,  ...]...]

如果此类数组的长度与要更改数据的数组的长度相同,则可以在使用索引时使用它。但是,根据单元格是否满足您的条件,您可以使用True或False而不是索引。

MyArray[bools] = 999

答案 2 :(得分:1)

我认为@Vorticity的另一个答案显然是正确的,并且经过深思熟虑的解释,我觉得不同的代码片段更具可读性和可理解性。

来自https://docs.scipy.org/doc/numpy/reference/generated/numpy.where.html 我们可以告诉np在第一个arg到np.where得到评估之后我们的布尔值后要使用什么值。

>>>np.where((MyArray > 5) & (MyArray < 15), MyArray, 999)

array([[999, 999, 999, 999, 999],
   [999,   6,   7,   8,   9],
   [ 10,  11,  12,  13,  14],
   [999, 999, 999, 999, 999]])

话虽如此,&#34;未分配给MyArray问题的一个很好的例子如下:

>>> MyArray
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19]])
>>> MyArray = MyArray[i]
>>> MyArray
array([ 6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
>>> MyArray = MyArray[j]
>>> MyArray
array([ 6,  7,  8,  9, 10, 11, 12, 13, 14])

我认为让很多人(包括我自己)绊倒的主要原因是,只需拨打MyArray[i]而不将其分配给=的某些内容并不能使计算机保持在小于或大于比较的结果是。

答案 3 :(得分:1)

maskedarray看起来拥有正确的工具集

import numpy.ma as ma


MyArray=np.arange(20).reshape(4,5)

subma = ma.masked_inside(MyArray, 5, 15)  # lots of ma. logic, arithematic ops

subma.filled(999)

Out[44]: 
array([[  0,   1,   2,   3,   4],
       [999, 999, 999, 999, 999],
       [999, 999, 999, 999, 999],
       [999,  16,  17,  18,  19]])