【问题标题】:How can I sum collection.Counter objects in a Python Pandas Dataframe using the update() method?如何使用 update() 方法对 Python Pandas Dataframe 中的 collection.Counter 对象求和?
【发布时间】:2016-08-10 08:22:37
【问题描述】:

我正在处理不完全适合 pandas 数据框的半结构化数据,因此我有一些列包含长度差异很大的集合。计数器对象(即字典)。

我需要在另一列上应用 groupby 并且需要对这些计数器求和,但是不要删除零或忽略负值。这意味着我不能在这些列上使用 sum() 方法。

选择的方法是 update() 方法,但它不能像 sum() 方法那样简单地应用,因为它需要一个参数,该参数是另一个 Counter,但它位于另一行而不是另一列。

例子:

import pandas as pd
import collections as cc

A = [cc.Counter({'A': 1,'B':-1,'C': 1}),\
     cc.Counter({'A':-1,'B': 1,       'D': 0,'E': 1}),\
     cc.Counter({'A': 0,                     'E': 0,'F': 1}),\
     cc.Counter({       'B': 0,'C':-1,       'E':-1,'F':-1})]

B = ['N','N','N','N']

S1 = pd.Series(B,index=['W','X','Y','Z'],name='K',dtype=str)
S2 = pd.Series(A,index=['W','X','Y','Z'],name='L',dtype=dict)
F = pd.merge(S1.to_frame(),S2.to_frame(),left_index=True,right_index=True)
print F

这导致输出

   K                                        L
W  N             {u'A': 1, u'C': 1, u'B': -1}
X  N    {u'A': -1, u'B': 1, u'E': 1, u'D': 0}
Y  N              {u'A': 0, u'E': 0, u'F': 1}
Z  N  {u'C': -1, u'B': 0, u'E': -1, u'F': -1}

这样做:

G = F.groupby('K')
print G.sum()

导致这个输出:

    L
K    
N  {}

但我想要的是这样的:

Counter({'A': 0, 'C': 0, 'B': 0, 'E': 0, 'D': 0, 'F': 0})

可以通过如下的更新方法手动完成:

for i in range(1,4):
  A[0].update(A[i])
print A[0]

所以我要么需要一种技术来将 update() 应用于 groupby 对象,要么通过创建适当的函数,要么将分组的行更改为列(这似乎相当低效且耗时),或者我将拥有以忽略计数器中的零和负值的方式重组我的数据。

欢迎提出任何想法。

编辑: 在我的示例中,我仍然无法将建议的解决方案应用于分组 DataFrame:

G.apply(lambda x: pd.DataFrame(x).sum().to_dict())

给出结果:

K
N    {u'K': u'NNNN', u'L': {}}
dtype: object

问题是我不太明白 apply 在 groupby 对象上的工作原理。

就像我这样做的时候:

F.groupby('K').apply(lambda x: list(x))

结果是:

K
N    [K, L]
dtype: object

我不明白为什么以及如何。

编辑 2(解决方案):

在@piRSquared 的回答帮助我解决了问题后,我添加了完整的解决方案,不仅可以获取字典,还可以将字典重新放入 DataFrame:

pd.DataFrame.from_dict([to_dict_dropna(pd.concat([F.K, F.L.apply(pd.Series)], axis=1)\
.groupby('K').sum())]).T.reset_index()

to_dict_dropna() 函数取自“make pandas DataFrame to a dict and dropna”,如果求和字典中有没有值的键,则该函数是必需的。 我正在转置框架并重置索引,因为我需要将初始索引作为列。然后我将它与其他帧合并以获得我需要的最终格式。

PS:这种方法非常消耗内存,不应该用于更大的数据集。

【问题讨论】:

  • 'C' 的最终值不应该是-1 吗?以及'E''F'?

标签: python python-2.7 pandas dataframe counter


【解决方案1】:

考虑字典列表A

A = [{'A': 1,'B':-1,'C': 1},
     {'A':-1,'B': 1,       'D': 0,'E': 1},
     {'A': 0,                     'E': 0,'F': 1},
     {       'B': 0,'C':-1,       'E':-1,'F':-1}]


pd.DataFrame(A).stack().groupby(level=1).sum().to_dict()

{'A{'A': 0.0, 'B': 0.0, 'C': 0.0, 'D': 0.0, 'E': 0.0, 'F': 0.0}

我会保留原来的答案。但这是基于我的错误假设,即您想要最后一个值。当我意识到 sum 是您所需要的时,答案随之而来。

鉴于此,这是一个更好的解决方案

pd.DataFrame(A).sum().to_dict()

要将其直接应用于您定义的数据框F

pd.concat([F.K, F.L.apply(pd.Series)], axis=1).groupby('K').sum()

【讨论】:

  • 这需要每个 dict 的最后一个值并将它们放在一起,但我需要具有相同键的所有值的总和,无论它们是 0 还是负数。 1 + (-1) 应该产生 0,而不是 -1。但我会更仔细地研究 stack 方法,我以前没有意识到这一点。
  • @Khris 啊,现在我明白了。
  • 其实你已经非常接近答案了,我只需要一个调整:pd.DataFrame(A).stack().groupby(level=1).sum().to_dict() - 编辑: 而且你比我快一点,谢谢你这么容易解决。
  • @piRSquared - 非常好的最后一个解决方案;)
  • @piRSquared:我仍然无法将您的解决方案正确应用于整个 DataFrame,请参阅我的问题中的编辑。
猜你喜欢
  • 2020-10-18
  • 2017-06-11
  • 2019-01-20
  • 2021-11-01
  • 2014-08-21
  • 2018-01-23
  • 2013-02-27
  • 1970-01-01
  • 2022-06-11
相关资源
最近更新 更多