布尔索引将numpy数组赋值给numpy数组

时间:2017-04-26 21:51:55

标签: numpy multidimensional-array indexing boolean

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

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

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

编辑: 这实际上失败了。索引

时,我无法为数据字段分配任何内容

1 个答案:

答案 0 :(得分: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(<boolean>)[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,)的形状