带有NaN(缺失)值的groupby列

我有一个DataFrame的列中有许多缺less的值,我希望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目标值的行。 (我想包括这些行!)

因为我需要很多这样的操作(许多cols缺less值),并且使用比中位数(通常是随机森林)更复杂的函数,所以我想避免编写太复杂的代码段。

有什么build议么? 我应该为此写一个函数还是有一个简单的解决scheme?

这在文档的缺失数据部分中提到 :

GroupBy中的NA组被自动排除。 例如,此行为与R一致。

一种解决方法是在执行groupby之前使用占位符(例如-1):

 In [11]: df.fillna(-1) Out[11]: ab 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(见这个github问题 – 它使用相同的占位符黑客)。

由于我没有足够的声望点(只有41个,但需要超过50个评论),所以我无法给M. Kiewisch添加评论。

无论如何,只是想指出,M. Kiewisch解决scheme不工作,可能需要更多的调整。 考虑一下例子

 >>> df = pd.DataFrame({'a': [1, 2, 3, 5], 'b': [4, np.NaN, 6, 4]}) >>> df ab 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连接起来而不是将它们作为数字加在一起。

古代的话题,如果有人仍然绊倒了这一点 – 另一个解决方法是在分组之前通过.astype(str)转换为string。 这将保存NaN的。

 in: 

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

 out: a b 4 1 6 3 nan 2 

对安迪·海登的解决scheme的一个小点 – 它不工作(不再?),因为np.nan == np.nan产生False ,所以replace函数实际上并没有做任何事情。

这对我有效:

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

(至less这是Pandas 0.19.2的行为,很抱歉把它作为一个不同的答案join,我没有足够的评价。)

虽然默认情况下在组合中没有skipnafunction,但是有一个简单而干净的方法来做到这一点:

 def custom_mean(df): return df.mean(skipna=False) group.agg({"your_col_name_to_be_aggregated":custom_mean}) 

而已!

请注意,我没有对此进行基准testing,但我预计它比以前的答案中讨论的要快。

在文档中find答案

我已经回答了这个问题,但是有些理由把答案转换成了评论。 不过,这是最有效的解决scheme:

NaN在群体中不能包含(并传播)是相当严重的。 引用R并不令人信服,因为这种行为与许多其他事情不一致。 无论如何,虚拟黑客也是相当糟糕的。 但是,如果有NaN,则组的大小(包括NaNs)和计数(忽略NaNs)将会有所不同。

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

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