必须产生汇总价值。我发誓我是

时间:2016-10-03 21:16:29

标签: python pandas

考虑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

解决
当我将applynp.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'])

enter image description here

但这并不适用于较长的变换列表。

2 个答案:

答案 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]])