【问题标题】:Conditional average with numpynumpy的条件平均
【发布时间】:2017-08-30 20:04:03
【问题描述】:

给定一个 2x3 数组,我想计算 axis=0 的平均值,但只考虑大于 0 的值。

所以给定数组

[ [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?谢谢!

【问题讨论】:

  • 0, 0, 0 filtered for &gt; 0 gives 0, 0, 0... 不,它没有。您能否更准确地描述您希望如何处理没有发现积极因素的情况?结果应该总是0吗?结果应该是所有元素的平均值吗?是否应该估算其他值?
  • 加权平均值计算为平均数和权重的乘积之和除以权重之和。由于第二列的权重加起来为 0(三个都是 False),因此无法进行除法。
  • 对发布的解决方案有何反馈?

标签: python arrays numpy average


【解决方案1】:

您可以获得大于零的掩码,并使用它沿第一个轴进行元素乘法和减和。最后,除以沿第一个轴的被屏蔽元素的数量以获得平均值。

因此,一种解决方案是 -

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]

【讨论】:

  • 当然,在没有正元素的情况下,你仍然除以零,所以如果发生这种情况,你会得到一个 NaN 平均值。试图取无数字平均值的潜在概念问题仍然存在。
猜你喜欢
  • 1970-01-01
  • 2012-02-29
  • 2015-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多