汇总分组 pandas 数据帧和 return NaN 中的行
Summing rows in grouped pandas dataframe and return NaN
例子
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)
问题
当分组数据帧包含 np.NaN
的值时,我希望分组总和为 NaN
,正如 pd.Series.sum
and also pd.DataFrame.sum
的 skipna=False
标志所给出的那样,但是,这
In [235]: df.v.sum(skipna=False)
Out[235]: nan
但是,此行为并未反映在 pandas.DataFrame.groupby
对象中
In [237]: df.groupby('l')['v'].sum()['right']
Out[237]: 2.0
并且不能通过直接应用np.sum
方法来强制
In [238]: df.groupby('l')['v'].apply(np.sum)['right']
Out[238]: 2.0
解决方法
我可以通过
解决这个问题
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
)
但这很难看。有没有更好的方法?
这是你想要的吗?
In [24]: df.groupby('l')['v'].agg(lambda x: np.nan if x.isnull().any() else x.sum())
Out[24]:
l
left -3.0
right NaN
Name: v, dtype: float64
或
In [22]: df.groupby('l')['v'].agg(lambda x: x.sum() if x.notnull().all() else np.nan)
Out[22]:
l
left -3.0
right NaN
Name: v, dtype: float64
我认为这是 pandas 所固有的。解决方法可以是:
df.groupby('l')['v'].apply(array).apply(sum)
模仿 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.
调用好的函数。
我不确定这属于丑陋程度的哪个范围,但它有效:
>>> series_sum = pd.core.series.Series.sum
>>> df.groupby('l')['v'].agg(series_sum, skipna=False)
l
left -3
right NaN
Name: v, dtype: float64
刚挖出你取df.v.sum
时用的sum
方法,支持skipna
选项:
>>> help(df.v.sum)
Help on method sum in module pandas.core.generic:
sum(axis=None, skipna=None, level=None, numeric_only=None, **kwargs) method
of pandas.core.series.Series instance
df.groupby(xxx).yyy.apply(lambda x: x.sum(skipna=False))
例子
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)
问题
当分组数据帧包含 np.NaN
的值时,我希望分组总和为 NaN
,正如 pd.Series.sum
and also pd.DataFrame.sum
的 skipna=False
标志所给出的那样,但是,这
In [235]: df.v.sum(skipna=False)
Out[235]: nan
但是,此行为并未反映在 pandas.DataFrame.groupby
对象中
In [237]: df.groupby('l')['v'].sum()['right']
Out[237]: 2.0
并且不能通过直接应用np.sum
方法来强制
In [238]: df.groupby('l')['v'].apply(np.sum)['right']
Out[238]: 2.0
解决方法
我可以通过
解决这个问题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
)
但这很难看。有没有更好的方法?
这是你想要的吗?
In [24]: df.groupby('l')['v'].agg(lambda x: np.nan if x.isnull().any() else x.sum())
Out[24]:
l
left -3.0
right NaN
Name: v, dtype: float64
或
In [22]: df.groupby('l')['v'].agg(lambda x: x.sum() if x.notnull().all() else np.nan)
Out[22]:
l
left -3.0
right NaN
Name: v, dtype: float64
我认为这是 pandas 所固有的。解决方法可以是:
df.groupby('l')['v'].apply(array).apply(sum)
模仿 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.
调用好的函数。
我不确定这属于丑陋程度的哪个范围,但它有效:
>>> series_sum = pd.core.series.Series.sum
>>> df.groupby('l')['v'].agg(series_sum, skipna=False)
l
left -3
right NaN
Name: v, dtype: float64
刚挖出你取df.v.sum
时用的sum
方法,支持skipna
选项:
>>> help(df.v.sum)
Help on method sum in module pandas.core.generic:
sum(axis=None, skipna=None, level=None, numeric_only=None, **kwargs) method
of pandas.core.series.Series instance
df.groupby(xxx).yyy.apply(lambda x: x.sum(skipna=False))