Pandas - 列中 groupby 之后的 Concat 字符串,忽略 NaN,忽略重复项

Posted

技术标签:

【中文标题】Pandas - 列中 groupby 之后的 Concat 字符串,忽略 NaN,忽略重复项【英文标题】:Pandas - Concat strings after groupby in column, ignore NaN, ignore duplicates 【发布时间】:2017-01-11 00:40:39 【问题描述】:

根据查询,我的 DF 可以有一个带有字符串的列或一个带有 NaN 的列。

例如:

  ID     grams   Projects
0  891            4.0      NaN
1  725            9.0      NaN

  ID     grams   Projects
0  890            1.0      P1, P2
1  724            1.0      P1
2  880            1.0      P1, P2
3  943            1.0      P1
4  071            1.0      P1

我可以处理其中一个,但是当我尝试创建一个通用的函数时,我失败了。最后我需要忽略 NaN,因为我将此 DF 作为 JSON 响应发送,而 NaN 给了我无效的格式。

我现在的做法是:

#When Projects is a string
df['Projects'] = _df.groupby("ID")['External_Id'].apply(lambda x: ",".join(x))

#When Projects is NaN
df['Projects'] = _df.groupby("ID")['External_Id'].apply(lambda x: "")

我尝试使用fillna() 并检查 'x' 的 dtype,但它总是返回为 object,所以我无法检查它是否是 strNaN

此外,“项目”列的结果不应允许重复。某些按 ID 分组的行包含重要信息,这些信息将被汇总(“克”),但“External_Id”不应出现多次。 例如:

  ID       grams      External_Id
0  890        1.0      P1
1  890        1.0      P2
2  890        1.0      P2
3  724        1.0      P1
4  724        1.0      P1

结果应该是

  ID       grams      Projects
0  890        3.0      P1, P2
1  724        2.0      P1

不是

  ID       grams      Projects
0  890        1.0      P1, P2, P2
1  724        1.0      P1, P1

【问题讨论】:

如果我理解正确,您需要检测列是否有 NaN? 是的,你是对的。如果列有 NaN,我想返回一个空字符串 (""),因为它在 JSON 对象中无效。 “忽略重复项”是什么意思?它在标题中,但似乎从问题的正文中消失了。 你说得对,我忘了解释。我会添加到正文中。我基本上有一些具有相同 ID 和相同项目的行。行上的其他信息对于计数/分析很重要,但例如,项目在连接时应该只出现一次,而不是“P1,P1,P1 ...”。 所有的 NaN 是否都与同一个项目有关?如果你能举个输入数据的例子就好了 【参考方案1】:

假设你开始

In [37]: df = pd.DataFrame('a': [1, 1, 2, 2], 'b': [1, None, 2, 4], 'c': ['foo', 'sho', 'sha', 'bar'])

In [43]: df
Out[43]: 
   a    b    c
0  1  1.0  foo
1  1  NaN  foo
2  2  2.0  sha
3  2  4.0  bar

然后您可以将相同的函数应用于bc,同时处理 NaN 和重复项:

In [44]: df.b.groupby(df.a).apply(lambda x: '' if x.isnull().any() else ','.join(set(x.astype(str).values)))
Out[44]: 
a
1           
2    2.0,4.0
dtype: object

In [45]: df.c.groupby(df.a).apply(lambda x: '' if x.isnull().any() else ','.join(set(x.astype(str).values)))
Out[45]: 
a
1        foo
2    sha,bar
dtype: object

【讨论】:

这就像一个魅力。我尝试了这个.isnull(),但我不知道我可以使用这个.any() 也不是astype()(我正在使用.dtype 进行验证)......该设置很好地避免了重复。谢谢【参考方案2】:

我认为这应该会有所帮助:

import numpy
df_new = df.replace(numpy.nan,' ', regex=True)

编辑:

我认为这个solution 可以为你工作(就像@Ami 的答案的替代品。

【讨论】:

这很好用,但这就是我忽略重复项的意思。它现在返回一堆逗号。例如:" , , , , , , , , " 对不起,我想我不明白,你想输出什么? 抱歉,@vlad.rad,我编辑了我的问题。当没有项目时,我只想拥有“”,而不是“, , , , , , , ,” 或重复项目。我忘了在正文中添加。 我想我只需要在这个答案中使用 set() .apply(lambda x: ",".join(set(x))) 我找到了关于堆栈溢出的另一个讨论,我已将链接粘贴到我编辑的答案中。祝你好运!

以上是关于Pandas - 列中 groupby 之后的 Concat 字符串,忽略 NaN,忽略重复项的主要内容,如果未能解决你的问题,请参考以下文章

Pandas GroupBy 并选择特定列中具有最小值的行

如何使用 groupby 调整 pandas 中的小计列?

Python pandas - 在 groupby 之后过滤行

Pandas - 在groupby之后将列转换为新行

Pandas、groupby 和其他列中的计数数据

Python pandas:替换 groupby 对象中的选择值