2015-07-03 58 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

很好的答案,謝謝。 –