计算 df 的平均值,但如果 => 1 个值与此平均值相差 >20%,则平均值设置为 NaN

Calculate mean of df, BUT if =>1 of the values differs >20% from this mean, the mean is set to NaN

我想计算数据框 a、b、c、d 列的平均值,但是如果每个数据框行中的四个值之一与这个平均值(四个值中的)相差超过 20%,则平均值必须设置为 NaN。

计算 4 列的平均值很容易,但我坚持定义条件 'if mean*0.8 <= data row <= mean*1,2 then mean == NaN.

在示例中,ID:5 和 ID:87 中的一个或多个值不在区间内,因此均值设置为 NaN。 (计算平均值和将 20% 条件应用于计算平均值时,初始数据框中的 NaN 值将被忽略)

所以我试图只计算没有 'outliers' 的数据行的平均值。

初始df:

 ID   a    b    c   d
  2  31   32   31  31
  5  33   52  159   2
  7  51  NaN   52  51 
 87  30   52  421   2
 90  10   11   10  11
102  41   42  NaN  42

期望的 df:

 ID   a    b    c   d    mean
  2  31   32   31  31   31.25
  5  33   52  159   2     NaN
  7  51  NaN   52  51   51.33
 87  30   52  421   2     NaN
 90  10   11   10  11   10.50
102  41   42  NaN  42   41.67

代码:

import pandas as pd

import numpy as np



df = pd.DataFrame({"ID": [2,5,7,87,90,102],
    
                    "a": [31,33,51,30,10,41],
     
                    "b": [32,52,np.nan,52,11,42],
      
                    "c": [31,159,52,421,10,np.nan],
  
                    "d": [31,2,51,2,11,42]})


print(df)



a = df.loc[:, ['a','b','c','d']]


df['mean'] = (a.iloc[:,0:]).mean(1)


print(df)


b = df.mean.values[:,None]*0.8 < a.values[:,:] < df.mean.values[:,None]*1.2
print(b)
...


试试这个:

# extract related information
s = df.iloc[:,1:]

# calculate mean
mean = s.mean(1)

# where condition is violated    
mask = s.lt(mean*.8, axis=0) | s.gt(mean*1.2, axis=0)

# mask where mask is True on any row
df['mean'] = mean.mask(mask.any(1))

输出:

    ID   a     b      c   d       mean
0    2  31  32.0   31.0  31  31.250000
1    5  33  52.0  159.0   2        NaN
2    7  51   NaN   52.0  51  51.333333
3   87  30  52.0  421.0   2        NaN
4   90  10  11.0   10.0  11  10.500000
5  102  41  42.0    NaN  42  41.666667