2016-08-25 127 views
7

這給了我很多麻煩,而且我對numpy數組與pandas系列的不兼容性感到困惑。當我使用一系列創建布爾數組時,例如用布爾數組掩蓋一系列

x = np.array([1,2,3,4,5,6,7]) 
y = pd.Series([1,2,3,4,5,6,7]) 
delta = np.percentile(x, 50) 
deltamask = x- y > delta 

delta掩碼創建布爾熊貓系列。

但是,如果你這樣做

x[deltamask] 
y[deltamask] 

您發現該陣列完全忽略面膜。沒有錯誤發生,但最終會得到兩個不同長度的對象。這意味着,像

x[deltamask]*y[deltamask] 

導致錯誤的操作:

print type(x-y) 
print type(x[deltamask]), len(x[deltamask]) 
print type(y[deltamask]), len(y[deltamask]) 

更令人費解的,我注意到,運營商<被區別對待。例如

print type(2*x < x*y) 
print type(2 < x*y) 

將分別給你一個pd.series和np.array。

此外,

5 < x - y 

產生一系列,如此看來,該系列優先,而一系列掩模的布爾元素傳遞到numpy的陣列時,並導致一個切片被提升到整數陣列。

這是什麼原因?

+2

'pandas'數據結構建立在'numpy'數組之上。 ''系列'確實有點***'numpy'陣列,它們不是'numpy'陣列。另外,你的意思是:_系列完全忽略了面具。 'deltamask'全部是'False',所以'Series'不應該返回任何值。 – Abdou

+0

對不起,我的意思是相反的。系列不尊重陣列蒙版,陣列不尊重系列蒙版。 – michel

+0

我認爲'系列'尊重'numpy陣列'口罩;再檢查一遍。但是numpy數組似乎沒有采用'Series'掩碼(實際上這很有趣)。但是'x [deltamask.values]'確實有效。 – Abdou

回答

3

花式索引

作爲numpy的目前維持在numpy的花哨索引的工作原理如下:

  1. 如果括號內的東西是一個tuple(是否有明確的括號或沒有)時,元組的元素是x不同維度的索引。例如,在這種情況下,x[(True, True)]x[True, True]都將增加IndexError: too many indices for array,因爲x是1D。但是,在發生異常之前,還會發出警告:VisibleDeprecationWarning: using a boolean instead of an integer will result in an error in the future

  2. 如果括號之間的事情是恰好一個ndarray,而不是一個子類或其它陣列狀,並有一個布爾類型,它將被作爲掩模施加。這就是爲什麼x[deltamask.values]給出了預期結果(空數組因爲deltamask是所有False

  3. 如果括號內的事情是任何陣列狀,無論是像Series或只是一個list,還是其他什麼東西的子類,它被轉換到np.intp數組(如果可能的話)並用作整數索引,所以x[deltamask] yeilds東西相當於x[[False] * 7]或者只是x[[0] * 7]在這種情況下,len(deltamask)==7x[0]==1所以結果是[1, 1, 1, 1, 1, 1, 1]

這種行爲是違反直覺的,它生成的FutureWarning: in the future, boolean array-likes will be handled as a boolean array index表示修復正在進行中。我會更新這個答案,因爲我發現/對numpy進行了任何更改。

這個信息可以在塞巴斯蒂安伯格對我對Numpy討論here的最初查詢的迴應中找到。

關係運算符

現在讓我們來解決您在比較是如何工作的問題的第二部分。關係運算符(<,>,<=,>=)通過調用被比較對象之一的相應方法來工作。對於<這是__lt__。然而,Python實際上並沒有爲表達式x < y調用x.__lt__(y),而是檢查被比較對象的類型。如果y是實現比較的x的子類型,則不管您如何編寫原始比較,Python都傾向於調用y.__gt__(x)。如果yx的子類,則x.__lt__(y)將被調用的唯一方式是如果y.__gt__(x)返回NotImplemented以指示在該方向上不支持該比較。

當你做5 < x - y時會發生類似的事情。雖然ndarray不是int的子類,但比較int.__lt__(ndarray)返回NotImplemented,因此Python實際上最終調用(x - y).__gt__(5),這當然是定義的,並且工作得很好。

Python docs可以找到更簡潔的解釋。