按组合并 Pandas 数据框后,对行求和并返回 NaN。

13

例子

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.sumpd.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
)

但这很丑陋。有更好的方法吗?
4个回答

7

我认为这是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.

调用好的函数。


2
值得注意的是,对于多列(即DataFrame),该方法更改为.apply(pd.DataFrame.sum, skipna=False) - Alexander McFarlane
针对重新采样,这个方法可行:df['my_column'].resample('1h').apply(pd.Series.sum, skipna=False)。 - Adam R. Jensen

4

我不确定这个在丑陋程度上属于什么级别,但它可以工作:

>>> 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

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

0
df.groupby(xxx).yyy.apply(lambda x: x.sum(skipna=False))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接