11

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

例如

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

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

谢谢

4

3 回答 3

15

一种可能更笨重的方法是遍历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")

这与 pandas 在后台所做的非常相似 [groupby,然后进行一些聚合,然后重新合并],因此您并没有真正失去太多。


深入内部

这里的问题是,pandas 正在明确检查输出不是an,ndarray因为它想要智能地重塑您的数组,正如您在此代码段中看到_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

我的猜测是,这是因为groupby明确设置为尝试智能地将具有相同索引的 DataFrame 重新组合在一起,并且所有内容都很好地对齐。由于在 DataFrame 中很少有嵌套数组,因此它会检查 ndarrays 以确保您实际使用的是聚合函数。在我的直觉中,这感觉像是一份工作Panel,但我不确定如何完美地改造它。顺便说一句,您可以通过将输出转换为列表来回避这个问题,如下所示:

DF.groupby("category").agg({"arraydata": lambda x: list(x.sum())})

Pandas 没有抱怨,因为现在你有了一个 Python 对象数组。[但这实际上只是在类型检查中作弊]。如果你想转换回数组,只需应用np.array它。

result = DF.groupby("category").agg({"arraydata": lambda x: list(x.sum())})
result["arraydata"] = result["arraydata"].apply(np.array)

你想如何解决这个问题实际上取决于你为什么有列,ndarray以及你是否想同时聚合其他任何东西。GroupBy也就是说,你总是可以像我上面展示的那样迭代。

于 2013-06-07T03:04:02.903 回答
2

如果您不这样做(例如,按照您的建议,使用数字数据),Pandas 的工作效率会更高。另一种选择是对这种多维数据使用Panel对象。

话虽如此,这看起来像一个错误,引发 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]

笔记:几乎可以肯定他们在那里是有原因的……

于 2013-06-07T03:02:15.020 回答
0

由于 sum 函数仅遍历行,或者 sum 函数仅计算沿第一个轴的总和。您可以定义一个聚合函数:

def mySum(dataframe):

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

然后将此函数传递给agg()

DF.groupby('category').agg(mySum)
于 2020-08-12T10:43:28.270 回答