Pandas:当列包含numpy数组时聚合

时间:2013-06-07 02:25:03

标签: python numpy pandas aggregation

我正在使用pandas DataFrame,其中一列包含numpy数组。当试图通过聚合对该列求和时,我得到一个错误,指出“必须产生聚合值”。

e.g。

import pandas as pd
import numpy as np

DF = pd.DataFrame([[1,np.array([10,20,30])],
               [1,np.array([40,50,60])], 
               [2,np.array([20,30,40])],], columns=['category','arraydata'])

这就像我期望的那样:

DF.groupby('category').agg(sum)

输出:

             arraydata
category 1   [50 70 90]
         2   [20 30 40]

但是,由于我的真实数据框有多个数字列,因此不选择arraydata作为聚合的默认列,我必须手动选择它。这是我尝试过的一种方法:

g=DF.groupby('category')
g.agg({'arraydata':sum})

这是另一个:

g=DF.groupby('category')
g['arraydata'].agg(sum)

两者都给出相同的输出:

Exception: must produce aggregated value

但是,如果我有一个使用数字而不是数组数据的列,它可以正常工作。我可以解决这个问题,但这很令人困惑,我想知道这是一个错误,还是我做错了什么。我觉得这里使用数组可能有点边缘,但确实不确定它们是否得到支持。想法?

由于

3 个答案:

答案 0 :(得分:10)

一种,也许更笨重的方法是迭代GroupBy对象(它生成(grouping_value, df_subgroup)元组。例如,为了达到你想要的目标,你可以这样做:

grouped = DF.groupby("category")
aggregate = list((k, v["arraydata"].sum()) for k, v in grouped)
new_df = pd.DataFrame(aggregate, columns=["category", "arraydata"]).set_index("category")

这与大熊猫无论如何都在做什么非常类似[groupby,然后做一些聚合,然后合并回来],所以你并没有真正失去太多。


潜入内部

这里的问题是pandas明确检查输出不是ndarray,因为它想要智能地重塑你的数组,正如你在{{1}的片段中看到的那样发生错误的地方。

_aggregate_named

我的猜测是,这是因为def _aggregate_named(self, func, *args, **kwargs): result = {} for name, group in self: group.name = name output = func(group, *args, **kwargs) if isinstance(output, np.ndarray): raise Exception('Must produce aggregated value') result[name] = self._try_cast(output, group) return result 被明确设置为尝试智能地将具有相同索引的DataFrame重新组合在一起并且所有内容都很好地对齐。由于很少在这样的DataFrame中嵌套数组,因此它会检查ndarrays以确保您实际使用的是聚合函数。在我的直觉中,这感觉就像是groupby的工作,但我不确定如何完美地改造它。顺便说一句,您可以通过将输出转换为列表来回避此问题,如下所示:

Panel

Pandas不抱怨,因为现在你有一个Python对象数组。 [但这实际上只是在类型检查中作弊]。如果您想转换回数组,只需将DF.groupby("category").agg({"arraydata": lambda x: list(x.sum())}) 应用于它。

np.array

您希望如何解决此问题,实际上取决于为什么您有result = DF.groupby("category").agg({"arraydata": lambda x: list(x.sum())}) result["arraydata"] = result["arraydata"].apply(np.array) 列以及是否要同时聚合其他任何内容。也就是说,您可以像上面显示的那样迭代ndarray

答案 1 :(得分:2)

如果这样做(例如使用数字数据,如你所建议的话),Pandas的工作效率会更高。另一种方法是使用Panel对象来处理这种多维数据。

说这看起来像一个bug,Exception正在被提升纯粹是因为结果是一个数组:

Exception: Must produce aggregated value

In [11]: %debug
> /Users/234BroadWalk/pandas/pandas/core/groupby.py(1511)_aggregate_named()
   1510             if isinstance(output, np.ndarray):
-> 1511                 raise Exception('Must produce aggregated value')
   1512             result[name] = self._try_cast(output, group)

ipdb> output
array([50, 70, 90])

如果您不顾后果地从源代码中删除这两行,它会按预期工作:

In [99]: g.agg(sum)
Out[99]:
             arraydata
category
1         [50, 70, 90]
2         [20, 30, 40]

注意:他们几乎可以肯定在那里......

答案 2 :(得分:0)

由于sum函数仅对行进行迭代,或者sum函数仅沿第一个轴计算和。 您可以定义一个聚合函数:

def mySum(dataframe):

    return np.sum(np.sum(dataframe))

然后将此函数传递到agg()中:

DF.groupby('category').agg(mySum)