【问题标题】:Boolean indexing assignment of a numpy array to a numpy arraynumpy 数组到 numpy 数组的布尔索引分配
【发布时间】:2017-09-24 12:03:16
【问题描述】:

我看到一些我不理解的布尔索引行为,我希望在这里找到一些说明。

首先,这是我正在寻求的行为......

>>>
>>> a = np.zeros(10, dtype=np.ndarray)
>>> a
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=object)
>>> b = np.arange(10).reshape(2,5)
>>> b
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])
>>> a[5] = b
>>> a
array([0, 0, 0, 0, 0, array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]]), 0,
       0, 0, 0], dtype=object)
>>>

选择 ndarray 的 ndarray 的原因是因为我将追加存储在超级数组中的数组,它们的长度都不同。我为超级数组选择了类型 ndarray 而不是 list,这样我就可以访问所有 numpys 智能索引功能。

无论如何,如果我创建一个布尔索引器并使用它在位置 1 分配 b+5,它会做一些我没想到的事情

>>> indexer = np.zeros(10,dtype='bool')
>>> indexer
array([False, False, False, False, False, False, False, False, False, False], dtype=bool)
>>> indexer[1] = True
>>> indexer
array([False,  True, False, False, False, False, False, False, False, False], dtype=bool)
>>> a[indexer] = b+5
>>> a
array([0, 5, 0, 0, 0, array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]]), 0,
       0, 0, 0], dtype=object)
>>>

谁能帮我理解发生了什么?我希望结果是

>>> a[1] = b+5
>>> a
array([0, array([[ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]]), 0, 0,
       0, array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]]), 0, 0, 0, 0], dtype=object)
>>>

最终的目标是在B中存储大量的“b”数组,并将它们分配给这样的a

>>> a[indexer] = B[indexer]

编辑:

根据下面的讨论找到了可能的解决方法。如果需要,我可以将数据包装在一个类中

>>>
>>> class myclass:
...     def __init__(self):
...             self.data = np.random.rand(1)
...
>>>
>>> b = myclass()
>>> b
<__main__.myclass object at 0x000002871A4AD198> 
>>> b.data
array([ 0.40185378])
>>>
>>> a[indexer] = b
>>> a
array([None, <__main__.myclass object at 0x000002871A4AD198>, None, None,
       None, None, None, None, None, None], dtype=object)
>>> a[1].data
array([ 0.40185378])

编辑: 这实际上失败了。索引时我无法为数据字段分配任何内容

【问题讨论】:

  • 它没有:(它失败了......但感谢您提供的信息!我会在未来这样做

标签: numpy multidimensional-array indexing boolean


【解决方案1】:
In [203]: a = np.empty(5, object)
In [204]: a
Out[204]: array([None, None, None, None, None], dtype=object)
In [205]: a[3]=np.arange(3)
In [206]: a
Out[206]: array([None, None, None, array([0, 1, 2]), None], dtype=object)

如此简单的索引与这个对象数组一起工作。

布尔索引适用于阅读:

In [207]: a[np.array([0,0,0,1,0], dtype=bool)]
Out[207]: array([array([0, 1, 2])], dtype=object)
In [208]: a[np.array([0,0,1,0,0], dtype=bool)]

但是写的时候有问题:

Out[208]: array([None], dtype=object)
In [209]: a[np.array([0,0,1,0,0], dtype=bool)]=np.arange(2)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-209-c1ef5580972c> in <module>()
----> 1 a[np.array([0,0,1,0,0], dtype=bool)]=np.arange(2)

ValueError: NumPy boolean array indexing assignment cannot assign 2 
input values to the 1 output values where the mask is true

np.where(&lt;boolean&gt;)[2]也给出问题:

In [221]: a[[2]]=np.arange(3)
/usr/local/bin/ipython3:1: DeprecationWarning: assignment will raise an 
error in the future, most likely because your index result shape does 
not match the value array shape. You can use `arr.flat[index] = values`    
to keep the old behaviour.

因此,无论出于何种原因,对对象 dtype 数组的索引赋值都不能像常规数组那样工作。

即使是推荐的flat 也不起作用

In [226]: a.flat[[2]]=np.arange(3)
In [227]: a
Out[227]: array([None, None, 0, array([0, 1, 2]), None], dtype=object)

我可以分配一个非列表/数组对象

In [228]: a[[2]]=None
In [229]: a
Out[229]: array([None, None, None, array([0, 1, 2]), None], dtype=object)
In [230]: a[[2]]={3:4}
In [231]: a
Out[231]: array([None, None, {3: 4}, array([0, 1, 2]), None], dtype=object)
In [232]: idx=np.array([0,0,1,0,0],bool)
In [233]: a[idx]=set([1,2,3])
In [234]: a
Out[234]: array([None, None, {1, 2, 3}, array([0, 1, 2]), None], dtype=object)

object dtype 数组位于numpy 数组功能的边缘。


看看我们用getitem 得到了什么。使用标量索引,我们可以得到该槽中存储的对象(在我的最新案例中,是set)。但是使用[[2]] 或布尔值,我们得到另一个对象数组。

In [235]: a[2]
Out[235]: {1, 2, 3}
In [236]: a[[2]]
Out[236]: array([{1, 2, 3}], dtype=object)
In [237]: a[idx]
Out[237]: array([{1, 2, 3}], dtype=object)
In [238]: a[idx].shape
Out[238]: (1,)

我怀疑当a[idx] 在 LHS 上时,它会先尝试将 RHS 转换为对象数组:

Out[241]: array([0, 1, 2], dtype=object)
In [242]: _.shape
Out[242]: (3,)
In [243]: np.array(set([1,2,3]), object)
Out[243]: array({1, 2, 3}, dtype=object)
In [244]: _.shape
Out[244]: ()

set 的情况下,结果数组只有一个元素,可以放在 (1,) 槽中。但是当 RHS 是一个列表或数组时,结果是一个 n 元素数组,例如(3,),它不适合 (1,) 槽。

解决方案(某种)

如果您想通过某种形式的高级索引(布尔值或列表)将列表/数组分配给对象数组中的插槽,请首先将该项目放入正确大小的对象数组中:

In [255]: b=np.empty(1,object)
In [256]: b[0]=np.arange(3)
In [257]: b
Out[257]: array([array([0, 1, 2])], dtype=object)
In [258]: b.shape
Out[258]: (1,)
In [259]: a[idx]=b
In [260]: a
Out[260]: array([None, None, array([0, 1, 2]), array([0, 1, 2]), None], dtype=object)

或者使用稍微大一点的数组:

In [264]: a = np.zeros(10, dtype=object)
In [265]: b = np.arange(10).reshape(2,5)
In [266]: a[5] = b
In [267]: c = np.zeros(1, dtype=object)  # intermediate object wrapper
In [268]: c[0] = b+5
In [269]: idx = np.zeros(10,bool)
In [270]: idx[1]=True
In [271]: a[idx] = c
In [272]: a
Out[272]: 
array([0, array([[ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]]), 0, 0,
       0, array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]]), 0, 0, 0, 0], dtype=object)

如果 idx 有 n 个 True 项,则 c 必须具有将广播到 (n,) 的形状

【讨论】:

  • 当我确保 RHS dtype 与 LHS(即 object dtype)匹配时,它看起来不那么错误。然后它只是可广播形状的标准业务。又回到了那个老问题——如何明确地将列表或数组转换为已知形状的对象数组。
  • 是否也可以分配和附加此索引?如果我们有正确的 C 形状并在其中包含值,那么 a[idx].append(C[idx]) 是否有意义?
  • a[idx] 是一个对象数组,而不是一个列表。它没有附加方法。 a[2] 可以是一个列表,因此是可附加的。您可以在c 中放置一个大列表或数组,然后分配它。
猜你喜欢
  • 2021-01-06
  • 2020-03-25
  • 1970-01-01
  • 2017-08-06
  • 2015-05-19
  • 2018-07-06
  • 2018-12-13
  • 2012-04-10
  • 1970-01-01
相关资源
最近更新 更多