nanmean с весами для расчета средневзвешенного значения в pandas .agg - PullRequest
0 голосов
/ 18 июня 2020

Я использую лямбда-функцию в агрегации pandas для вычисления средневзвешенного значения. Моя проблема в том, что если одно из значений - nan, весь результат - nan этой группы. Как я могу этого избежать?

df = pd.DataFrame(np.random.randn(5, 3), index=['a', 'c', 'e', 'f', 'h'],columns = ['one', 'two', 'three'])
df['four'] = 'bar'
df['five'] = df['one'] > 0
df = df.reindex(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
df.loc['b','four'] ='foo'
df.loc['c','four'] ='foo'


        one       two     three four   five found
a  1.046540 -0.304646 -0.982008  bar   True   NaN
b       NaN       NaN       NaN  foo    NaN   foo
c -1.086525  1.086501  0.403910  foo  False   NaN
d       NaN       NaN       NaN  NaN    NaN   NaN
e  0.569420  0.105422  0.192559  bar   True   NaN
f  0.384400 -0.558321  0.324624  bar   True   NaN
g       NaN       NaN       NaN  NaN    NaN   NaN
h  0.656231 -2.185062  0.180535  bar   True   NaN


df.groupby('four').agg(sum=('two','sum'), weighted_avg=('one', lambda x: np.average(x, weights=df.loc[x.index, 'two'])))

           sum  weighted_avg
four                        
bar  -2.942608      0.648173
foo   1.086501           NaN

желаемый результат:

           sum  weighted_avg
four                        
bar  -2.942608      0.648173
foo   1.086501     -1.086525 

В отличие от этого вопроса , проблема не в том, что фактическое значение столбца делает не отображается, это проблема nanmean, у которого нет опции взвешивания.

Другой числовой пример:

     x      y
0   NaN   18.0
1   NaN   21.0
2   NaN   38.0
3  56.0  150.0
4  65.0  154.0

Здесь мы бы хотели просто вернуть средневзвешенное значение двух последних строк и проигнорировать остальные строки, содержащие nan.

Ответы [ 2 ]

2 голосов
/ 18 июня 2020

Для меня реализована работа это решение:

def f(x):
    indices = ~np.isnan(x)
    return np.average(x[indices], weights=df.loc[x.index[indices], 'two'])

df = df.groupby('four').agg(sum=('two','sum'), weighted_avg=('one', f))

print (df)
           sum  weighted_avg
four                        
bar  -2.942607      0.648173
foo   1.086501     -1.086525

EDIT:

def f(x):
    indices = ~np.isnan(x)
    if indices.all():
        return np.average(x[indices], weights=df.loc[x.index[indices], 'two'])
    else:
        return np.nan
0 голосов
/ 19 июня 2020

Это кажется более надежным:

def f(x):
    indices = (~np.isnan(x)) & (~np.isnan(df[weight_column]))[x.index]
    try:
        return np.average(x[indices], weights=df.loc[x.index[indices], weight_column])
    except ZeroDivisionError:
        return np.nan

df = df.groupby('four').agg(sum=('two','sum'), weighted_avg=('one', f))
...