对分组的pandas数据帧中的行求和并返回NaN

Ale*_*ane 7 python numpy nan dataframe pandas

import pandas as pd
import numpy as np
d = {'l':  ['left', 'right', 'left', 'right', 'left', 'right'],
     'r': ['right', 'left', 'right', 'left', 'right', 'left'],
     'v': [-1, 1, -1, 1, -1, np.nan]}
df = pd.DataFrame(d)
Run Code Online (Sandbox Code Playgroud)

问题

当分组的数据帧包含值np.NaNI时,希望分组的总和NaN是由skipna=False标志给出的,但是pd.Series.sum也是pd.DataFrame.sum如此

In [235]: df.v.sum(skipna=False)
Out[235]: nan
Run Code Online (Sandbox Code Playgroud)

但是,此行为未反映在pandas.DataFrame.groupby对象中

In [237]: df.groupby('l')['v'].sum()['right']
Out[237]: 2.0
Run Code Online (Sandbox Code Playgroud)

并且不能通过np.sum直接应用该方法强制使用

In [238]: df.groupby('l')['v'].apply(np.sum)['right']
Out[238]: 2.0
Run Code Online (Sandbox Code Playgroud)

解决方法

我可以通过这样做来解决这个问题

check_cols = ['v']
df['flag'] = df[check_cols].isnull().any(axis=1)
df.groupby('l')['v', 'flag'].apply(np.sum).apply(
    lambda x: x if not x.flag else np.nan,
    axis=1
)
Run Code Online (Sandbox Code Playgroud)

但这很难看.有更好的方法吗?

B. *_* M. 7

我认为这是熊猫与生俱来的。解决方法可以是:

df.groupby('l')['v'].apply(array).apply(sum)
Run Code Online (Sandbox Code Playgroud)

模仿 numpy 的方式,

或者

df.groupby('l')['v'].apply(pd.Series.sum,skipna=False) # for series, or
df.groupby('l')['v'].apply(pd.DataFrame.sum,skipna=False) # for dataframes.
Run Code Online (Sandbox Code Playgroud)

调用好的函数。

  • 值得补充的是,对于多列(即 DataFrame),该方法更改为“.apply(pd.DataFrame.sum,skipna=False)” (2认同)