考虑pd.Series
s
a = np.arange(4)
mux = pd.MultiIndex.from_product([list('ab'), list('xy')])
s = pd.Series([a] * 4, mux)
print(s)
a x [0, 1, 2, 3]
y [0, 1, 2, 3]
b x [0, 1, 2, 3]
y [0, 1, 2, 3]
dtype: object
问题
s
的每个元素都是numpy.array
。当我尝试在组内求和时,我得到一个错误,因为groupby函数期望结果是标量...(我猜)
s.groupby(level=0).sum()
Exception Traceback (most recent call last) <ipython-input-627-c5b3bf6890ea> in <module>() ----> 1 s.groupby(level=0).sum() C:\Anaconda2\lib\site-packages\pandas\core\groupby.pyc in f(self) 101 raise SpecificationError(str(e)) 102 except Exception: --> 103 result = self.aggregate(lambda x: npfunc(x, axis=self.axis)) 104 if _convert: 105 result = result._convert(datetime=True) C:\Anaconda2\lib\site-packages\pandas\core\groupby.pyc in aggregate(self, func_or_funcs, *args, **kwargs) 2584 return self._python_agg_general(func_or_funcs, *args, **kwargs) 2585 except Exception: -> 2586 result = self._aggregate_named(func_or_funcs, *args, **kwargs) 2587 2588 index = Index(sorted(result), name=self.grouper.names[0]) C:\Anaconda2\lib\site-packages\pandas\core\groupby.pyc in _aggregate_named(self, func, *args, **kwargs) 2704 output = func(group, *args, **kwargs) 2705 if isinstance(output, (Series, Index, np.ndarray)): -> 2706 raise Exception('Must produce aggregated value') 2707 result[name] = self._try_cast(output, group) 2708 Exception: Must produce aggregated value
解决
当我将apply
与np.sum
一起使用时,它可以正常使用。
s.groupby(level=0).apply(np.sum)
a [0, 2, 4, 6]
b [0, 2, 4, 6]
dtype: object
问题
是否有一种优雅的方式来处理这个问题?
真正的问题
我实际上想以这种方式使用agg
s.groupby(level=0).agg(['sum', 'prod'])
但它以同样的方式失败 获得这个的唯一方法是
pd.concat([g.apply(np.sum), g.apply(np.prod)],
axis=1, keys=['sum', 'prod'])
但这并不适用于较长的变换列表。
答案 0 :(得分:2)
from this well explained answer你可以将你的ndarray转换为list,因为pandas似乎正在检查输出是否是一个ndarray,这就是你得到这个错误的原因:
s.groupby(level=0).agg({"sum": lambda x: list(x.sum()), "prod":lambda x: list(x.prod())})
出[249]:
sum prod
a [0, 2, 4, 6] [0, 1, 4, 9]
b [0, 2, 4, 6] [0, 1, 4, 9]
答案 1 :(得分:0)
Pandas不能将数组作为值。对于DataFrame
使用s
而不是Series
是更好的做法。这将为您提供预期的行为,并且比使用lambda /列表快得多。
您可以轻松地将其转换为DataFrame
:
s = s.apply(pd.Series)
那时,在任何级别上进行汇总都非常容易。
s.groupby(level=0).agg(['sum', 'prod'])
0 1 2 3
sum prod sum prod sum prod sum prod
a 0 0 2 1 4 4 6 9
b 0 0 2 1 4 4 6 9
您可以在这里停下来,但是我认为这不是您理想中想要的格式。重新堆叠聚合非常容易。
test = s.groupby(level=0).agg(['sum', 'prod'])
test = test.stack(level=0).unstack()
test
prod sum
0 1 2 3 0 1 2 3
a 0 1 4 9 0 2 4 6
b 0 1 4 9 0 2 4 6
此时,您可以按期望的方式调用每个乘积和求和。
test['prod']
0 1 2 3
a 0 1 4 9
b 0 1 4 9
或者如果您希望将其作为数组返回:
test['prod'].values
array([[0, 1, 4, 9],
[0, 1, 4, 9]])