如何使用 update() 方法对 Python Pandas Dataframe 中的 collection.Counter 个对象求和?

How can I sum collection.Counter objects in a Python Pandas Dataframe using the update() method?

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

我需要在另一列上应用 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 on 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:这种方法非常耗内存,不应该用于较大的数据集。

考虑字典列表 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()