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