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

2024-04-16 23:32:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用的是pandas数据帧,其中一列包含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

但是,如果我有一个使用数值而不是数组数据的列,它可以正常工作。我可以解决这个问题,但这很混乱,我想知道这是不是个错误,或者我做错了什么。我觉得这里使用数组可能有点边缘化,确实不确定它们是否受支持。思想?

谢谢


Tags: 数据importnumpypandasdfas错误np
2条回答

一种可能更笨拙的方法是遍历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,因为它希望智能地重塑数组的形状,正如您在这个错误发生的_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被显式设置为尝试智能地将具有相同索引的数据帧放回一起,并且一切都很好地对齐。因为在这样的数据帧中很少有嵌套数组,所以它会检查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上迭代。

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

这么说,这看起来像一个bug,引发异常纯粹是因为结果是一个数组:

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]

注意:他们肯定在里面是有原因的。。。

相关问题 更多 >