具有NaN(缺失)值的pandas GroupBy列

66bbxpm5  于 2023-11-15  发布在  其他
关注(0)|答案(7)|浏览(128)

我有一个DataFrame,在我希望groupby的列中有许多缺失值:

import pandas as pd
import numpy as np
df = pd.DataFrame({'a': ['1', '2', '3'], 'b': ['4', np.NaN, '6']})

In [4]: df.groupby('b').groups
Out[4]: {'4': [0], '6': [2]}

字符串
看到Pandas已经删除了目标值为NaN的行。我想包含这些行!
有什么建议吗?

9w11ddsr

9w11ddsr1#

pandas >= 1.1

从pandas 1.1开始,你可以更好地控制这种行为,现在在grouper中允许使用**dropna=False**的NA值:

pd.__version__
# '1.1.0.dev0+2004.g8d10bfb6f'

# Example from the docs
df

   a    b  c
0  1  2.0  3
1  1  NaN  4
2  2  1.0  3
3  1  2.0  2

# without NA (the default)
df.groupby('b').sum()

     a  c
b        
1.0  2  3
2.0  2  5

个字符

mwecs4sa

mwecs4sa2#

这在文档的缺失数据部分中提到:
GroupBy中的NA组被自动排除。
一种解决方法是在执行groupby之前使用占位符(例如-1):

In [11]: df.fillna(-1)
Out[11]: 
   a   b
0  1   4
1  2  -1
2  3   6

In [12]: df.fillna(-1).groupby('b').sum()
Out[12]: 
    a
b    
-1  2
4   1
6   3

字符串

  • 也就是说,这感觉相当糟糕的黑客.也许应该有一个选项,包括NaN在groupby(见this github issue-使用相同的占位符黑客)。
  • 但是,如another answer中所述,“从pandas 1.1开始,您可以更好地控制此行为,现在允许在grouper中使用dropna=False*”
hgncfbus

hgncfbus3#

这是一个古老的主题,如果有人仍然对此感到困惑,另一个解决方法是在分组之前将via .astype(str)转换为字符串。

df = pd.DataFrame({'a': ['1', '2', '3'], 'b': ['4', np.NaN, '6']})
df['b'] = df['b'].astype(str)
df.groupby(['b']).sum()

个字符

gupuwyp2

gupuwyp24#

我不能给M. Kiewisch添加评论,因为我没有足够的声誉点(只有41点,但需要超过50点才能评论)。
无论如何,只是想指出,M. Kiewisch解决方案并不像现在这样工作,可能需要更多的调整。

>>> df = pd.DataFrame({'a': [1, 2, 3, 5], 'b': [4, np.NaN, 6, 4]})
>>> df
   a    b
0  1  4.0
1  2  NaN
2  3  6.0
3  5  4.0
>>> df.groupby(['b']).sum()
     a
b
4.0  6
6.0  3
>>> df.astype(str).groupby(['b']).sum()
      a
b
4.0  15
6.0   3
nan   2

字符串
这表明,对于组B=4.0,对应的值是15而不是6。这里只是将1和5作为字符串连接起来,而不是将其作为数字相加。

0ejtzxu1

0ejtzxu15#

到目前为止提供的所有答案都会导致潜在的危险行为,因为您很可能选择了一个实际上是数据集一部分的虚拟值。当您创建具有许多属性的组时,这种可能性越来越大。简单地说,这种方法并不总是很好地泛化。
一个不那么麻烦的解决方案是使用pd.drop_duplicates()来创建一个唯一的值组合索引,每个值组合都有自己的ID,然后根据该ID进行分组。它更详细,但确实完成了工作:

def safe_groupby(df, group_cols, agg_dict):
    # set name of group col to unique value
    group_id = 'group_id'
    while group_id in df.columns:
        group_id += 'x'
    # get final order of columns
    agg_col_order = (group_cols + list(agg_dict.keys()))
    # create unique index of grouped values
    group_idx = df[group_cols].drop_duplicates()
    group_idx[group_id] = np.arange(group_idx.shape[0])
    # merge unique index on dataframe
    df = df.merge(group_idx, on=group_cols)
    # group dataframe on group id and aggregate values
    df_agg = df.groupby(group_id, as_index=True)\
               .agg(agg_dict)
    # merge grouped value index to results of aggregation
    df_agg = group_idx.set_index(group_id).join(df_agg)
    # rename index
    df_agg.index.name = None
    # return reordered columns
    return df_agg[agg_col_order]

字符串
请注意,您现在可以简单地执行以下操作:

data_block = [np.tile([None, 'A'], 3),
              np.repeat(['B', 'C'], 3),
              [1] * (2 * 3)]

col_names = ['col_a', 'col_b', 'value']

test_df = pd.DataFrame(data_block, index=col_names).T

grouped_df = safe_groupby(test_df, ['col_a', 'col_b'],
                          OrderedDict([('value', 'sum')]))


这将返回成功的结果,而不必担心错误的真实的数据被误认为虚拟值。

vs91vp4v

vs91vp4v6#

Andy Hayden的解决方案的一个小问题-它不工作(不再?)因为np.nan == np.nan产生False,所以replace函数实际上没有做任何事情。
对我起作用的是:

df['b'] = df['b'].apply(lambda x: x if not np.isnan(x) else -1)

字符串
(At至少这是Pandas 0.19.2的行为。抱歉添加它作为不同的答案,我没有足够的声誉来评论。)

pbpqsu0x

pbpqsu0x7#

我已经回答了这个问题,但由于某种原因,答案被转换为评论。然而,这是最有效的解决方案:
不能在组中包含(和传播)NaN是相当令人恼火的。引用R是没有说服力的,因为这种行为与许多其他事情不一致。无论如何,虚拟黑客也很糟糕。然而,如果有NaN,组的大小(包括NaN)和计数(忽略NaN)会有所不同。

dfgrouped = df.groupby(['b']).a.agg(['sum','size','count'])

dfgrouped['sum'][dfgrouped['size']!=dfgrouped['count']] = None

字符串
当这些值不同时,您可以将该组的聚合函数结果的值设置回None。

相关问题