2015-07-03 57 views
3

我最近在使用结构化numpy数组时看到了一种现象,这种现象没有任何意义。我希望有人能帮助我理解正在发生的事情。我提供了一个最小的工作示例来说明问题。问题是这样的:为什么对布尔索引结构化数组的赋值依赖于索引排序?

当索引用布尔面具结构化numpy的数组,这个工程:

arr['fieldName'][boolMask] += val 

但以下不会:

arr[boolMask]['fieldName'] += val 

这里是一个最小的工作示例:

import numpy as np 

myDtype = np.dtype([('t','<f8'),('p','<f8',(3,)),('v','<f4',(3,))]) 

nominalArray = np.zeros((10,),dtype=myDtype) 
nominalArray['t'] = np.arange(10.) 
# In real life, the other fields would also be populated 
print "original times: {0}".format(nominalArray['t']) 

# Add 10 to all times greater than 5 
timeGreaterThan5 = nominalArray['t'] > 5 
nominalArray['t'][timeGreaterThan5] += 10. 
print "times after first operation: {0}".format(nominalArray['t']) 

# Return those times to their original values 
nominalArray[timeGreaterThan5]['t'] -= 10. 
print "times after second operation: {0}".format(nominalArray['t']) 

运行此产生以下输出:

original times: [ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.] 
times after first operation: [ 0. 1. 2. 3. 4. 5. 16. 17. 18. 19.] 
times after second operation: [ 0. 1. 2. 3. 4. 5. 16. 17. 18. 19.] 

我们在此清楚地看到第二个操作没有效果。如果有人可以解释为什么会发生这种情况,将不胜感激。

+0

它不会是'nominalArray [“t”] [timeGreaterThan5] - = 10' –

+0

@PadraicCunningham这将解决问题。我只是想知道为什么这是解决方案。这里的排序有什么特别之处? – tintedFrantic

+3

我现在得到你,他们都返回不同的对象,一个是视图,另一个不是,我想像高级与普通索引,'nominalArray [timeGreaterThan5]'返回'[(16.0,[0.0,0.0,0.0],[ 0.0,0.0,0.0])...'所以从'nominalArray [timeGreaterThan5]'返回的片不是查看对象 –

回答

3

这确实是一个复制v视图的问题。但我会更详细地介绍。

视图与副本之间的关键区别在于索引模式是否正常。常规的可以用数组shapestridesdtype表示。一般来说,布尔型索引(和相关的索引列表)不能用这些术语表示,所以numpy必须返回一个副本。

我喜欢看arr.__array_interface__属性。它显示形状,步幅和指向数据缓冲区的指针。如果指针与原始指针相同,则它是view

随着arr[idx] += 1,索引实际上是一个setitem方法,选择哪些数据缓冲项目加入修改。视图与复制之间的区别不适用。

但与arr[idx1][idx2] += 1,第一个索引是getitem方法。为此,观看和复制之间的区别。第二次索引修改第一次产生的数组。如果是视图,则修改会影响原始数据;如果一个副本,没有永久发生。副本可能会被修改,但它会在垃圾收集器中消失。

2d阵列,你可以结合这两个索引步骤,arr[idx1, idx2] += 1;实际上这是首选的语法。

对于结构化数组,字段索引与列索引类似,但不完全相同。首先,它不能与元素索引结合使用。

一个简单的结构化阵列:

In [234]: arr=np.ones((5,),dtype='i,f,i,f') 
In [235]: arr.__array_interface__ 
{'strides': None, 
'shape': (5,), 
'data': (152524816, False), 
'descr': [('f0', '<i4'), ('f1', '<f4'), ('f2', '<i4'), ('f3', '<f4')], 
'typestr': '|V16', 
'version': 3} 

选择一个场产生一个视图 - 相同的数据指针

In [236]: arr['f0'].__array_interface__['data'] 
Out[236]: (152524816, False) 

与布尔选择元素产生一个拷贝(差异指针)

In [242]: idx = np.array([1,0,0,1,1],bool) 
In [243]: arr[idx].__array_interface__['data'] 
Out[243]: (152629520, False) 

所以arr['f0'][idx] += 1修改中的选定项字段。

arr[idx]['f0'] += 1修改副本的f0字段,对arr没有影响。

arr[idx]['f0'] + 1arr['f0'][idx] + 1显示相同的内容,但他们不试图执行任何就地更改。

您可以从结构化数组中选择多个字段,即arr[['f0','f2']]。但这是一个副本。 (并且我收到一条警告,建议我做一个明确的副本)。

+0

很好的答案,谢谢。 –