2017-08-30 179 views
-2

給定的2x3陣列,我要計算在axis=0的平均水平,但只考慮那些值大於0條件與平均numpy的

所以給出的陣列

[ [1,0], 
    [0,0], 
    [1,0] ] 

我想要的輸出要

# 1, 0, 1 filtered for > 0 gives 1, 1, average = (1+1)/2 = 1 
# 0, 0, 0 filtered for > 0 gives 0, 0, 0, average = 0  
[1 0] 

我當前的代碼是

import numpy as np 

frame = np.array([ [1,0], 
        [0,0], 
        [1,0] ]) 

weights=np.array(frame)>0 

print("weights:") 
print(weights) 

print("average without weights:") 
print((np.average(frame, axis=0))) 

print("average with weights:") 
print((np.average(frame, axis=0, weights=weights))) 

這給了我

weights: 
[[ True False] 
[False False] 
[ True False]] 
average without weights: 
[ 0.66666667 0.  ] 
average with weights: 
Traceback (most recent call last): 
File "C:\Users\myuser\project\test.py", line 123, in <module> 
print((np.average(frame, axis=0, weights=weights))) 
File "C:\Users\myuser\Miniconda3\envs\myenv\lib\site-packages\numpy\lib\function_base.py", line 1140, in average 
"Weights sum to zero, can't be normalized") 
ZeroDivisionError: Weights sum to zero, can't be normalized 

我不明白這個錯誤。我在做什麼錯了,我怎麼能得到沿axis=0沿大於零的所有值的平均值?謝謝!

+1

'0,0,0過濾爲> 0產生0,0,0' ......不,它不需要。你能否更準確地描述你如何處理沒有找到積極因素的情況?結果應該總是0嗎?結果應該是所有元素的平均值嗎?是否應該計算一些其他的價值? – user2357112

+0

加權平均值計算爲平均數和權重的乘積之和除以權重之和。由於第二列的權重加起來爲0(所有三個都是「假」),所以這種劃分是不可能的。 – DyZ

+0

和對發佈的解決方案的反饋? – Divakar

回答

0

您可以獲得大於零的掩碼,並使用它沿第一個軸執行元素複用和減法。最後,除以沿着第一軸的屏蔽元素的數量以獲得平均值。

因此,一個解決辦法是 -

mask = a > 0 # Input array : a 
out = np.einsum('i...,i...->...',a,mask)/mask.sum(0) 

採樣運行 -

In [52]: a 
Out[52]: 
array([[ 3, -3, 3], 
     [ 2, 2, 0], 
     [ 0, -3, 1], 
     [ 0, 1, 1]]) 

In [53]: mask = a > 0 

In [56]: np.einsum('i...,i...->...',a,mask) # summations of > 0s 
Out[56]: array([5, 3, 5]) 

In [57]: np.einsum('i...,i...->...',a,mask)/mask.sum(0) # avg values of >0s 
Out[57]: array([ 2.5  , 1.5  , 1.66666667]) 

要佔全部零列,看來我們期待0作爲結果。所以,我們可以用np.where做選擇,就像這樣 -

In [61]: a[:,-1] = 0 

In [62]: a 
Out[62]: 
array([[ 3, -3, 0], 
     [ 2, 2, 0], 
     [ 0, -3, 0], 
     [ 0, 1, 0]]) 

In [63]: mask = a > 0 

In [65]: np.where(mask.any(0), np.einsum('i...,i...->...',a,mask)/mask.sum(0), 0) 
__main__:1: RuntimeWarning: invalid value encountered in true_divide 
Out[65]: array([ 2.5, 1.5, 0. ]) 

只是忽略警告那裏。

如果你覺得偏執的警告,使用masking -

mask = a > 0 
vm = mask.any(0) # valid mask 
out = np.zeros(a.shape[1]) 
out[vm] = np.einsum('ij,ij->j',a[:,vm],mask[:,vm])/mask.sum(0)[vm] 
+0

當然,在沒有積極因素的情況下,你仍然被零分,所以如果發生這種情況,你會得到一個平均值。嘗試取平均數字的概念性問題仍然存在。 – user2357112

+0

@ user2357112好點!編輯涵蓋這種情況。 – Divakar