Pandas Groupby Agg 函数不减少

Posted

技术标签:

【中文标题】Pandas Groupby Agg 函数不减少【英文标题】:Pandas Groupby Agg Function Does Not Reduce 【发布时间】:2015-02-10 21:23:45 【问题描述】:

我正在使用我在工作中使用了很长时间的聚合函数。这个想法是,如果传递给函数的系列长度为 1(即该组只有一个观察值),则返回该观察值。如果传递的 Series 的长度大于 1,则观察结果以列表形式返回。

这对某些人来说可能看起来很奇怪,但这不是 X、Y 问题,我有充分的理由想要做与这个问题无关的事情。

这是我一直在使用的功能:

def MakeList(x):
    """ This function is used to aggregate data that needs to be kept distinc within multi day 
        observations for later use and transformation. It makes a list of the data and if the list is of length 1
        then there is only one line/day observation in that group so the single element of the list is returned. 
        If the list is longer than one then there are multiple line/day observations and the list itself is 
        returned."""
    L = x.tolist()
    if len(L) > 1:
        return L
    else:
        return L[0]

现在由于某种原因,使用我正在处理的当前数据集,我得到一个 ValueError ,指出该函数没有减少。这是一些测试数据和我正在使用的剩余步骤:

import pandas as pd
DF = pd.DataFrame('date': ['2013-04-02',
                            '2013-04-02',
                            '2013-04-02',
                            '2013-04-02',
                            '2013-04-02',
                            '2013-04-02',
                            '2013-04-02',
                            '2013-04-02',
                            '2013-04-02',
                            '2013-04-02'],
                    'line_code':   ['401101',
                                    '401101',
                                    '401102',
                                    '401103',
                                    '401104',
                                    '401105',
                                    '401105',
                                    '401106',
                                    '401106',
                                    '401107'],
                    's.m.v.': [ 7.760,
                                25.564,
                                25.564,
                                9.550,
                                4.870,
                                7.760,
                                25.564,
                                5.282,
                                25.564,
                                5.282])
DFGrouped = DF.groupby(['date', 'line_code'], as_index = False)
DF_Agg = DFGrouped.agg('s.m.v.' : MakeList)

在尝试调试时,我将一个 print 语句设置为 print Lprint x.index 和 输出如下:

[7.7599999999999998, 25.564]
Int64Index([0, 1], dtype='int64')
[7.7599999999999998, 25.564]
Int64Index([0, 1], dtype='int64')

由于某种原因,agg 似乎将系列两次传递给函数。据我所知,这根本不正常,估计是我的功能没有减少的原因。

例如,如果我写一个这样的函数:

def test_func(x):
    print x.index
    return x.iloc[0]

这运行没有问题,打印语句是:

DF_Agg = DFGrouped.agg('s.m.v.' : test_func)

Int64Index([0, 1], dtype='int64')
Int64Index([2], dtype='int64')
Int64Index([3], dtype='int64')
Int64Index([4], dtype='int64')
Int64Index([5, 6], dtype='int64')
Int64Index([7, 8], dtype='int64')
Int64Index([9], dtype='int64')

这表明每个组只作为一个系列传递给函数一次。

谁能帮我理解为什么会失败?我已经在我使用的许多数据集中成功地使用了这个函数......

谢谢

【问题讨论】:

如果你的函数有时返回一个列表,有时返回一个值,pandas 可能会感到困惑,因为这两种情况会使用不同的 dtype。最好不要那样做。两次调用行为可能与here 为apply 描述的问题有关:它在第一组上调用该函数两次,以检查该函数是否改变了现有数据。 嗯....我应该尝试设置为 object dtype。 最奇怪的是,我一直在重用这段代码,没有任何问题。我知道 apply 和 transform 传递不同的数据包,因此很难从打印语句中确定发生了什么,但是 agh 相当简单。你能重现错误吗? 我可以重现错误,但我无法重现它工作的非错误。您的 test_func 确实减少了,因为它只返回一个值。您是否有一个聚合函数返回列表的工作示例?这对你有用吗? 一个有趣的解决方案是返回tuple(L)而不是L 【参考方案1】:

我无法真正解释为什么,但根据我的经验,listpandas.DataFrame 中并没有那么好用。

我通常改用tuple。 这将起作用:

def MakeList(x):
    T = tuple(x)
    if len(T) > 1:
        return T
    else:
        return T[0]

DF_Agg = DFGrouped.agg('s.m.v.' : MakeList)

     date line_code           s.m.v.
0  2013-04-02    401101   (7.76, 25.564)
1  2013-04-02    401102           25.564
2  2013-04-02    401103             9.55
3  2013-04-02    401104             4.87
4  2013-04-02    401105   (7.76, 25.564)
5  2013-04-02    401106  (5.282, 25.564)
6  2013-04-02    401107            5.282

【讨论】:

这与 tuple 类型是不可变的,因此是可散列的,而 list 不是。 可能!但是从“不聚合”的角度来看,这些概念是相同的,因此无法猜测某些内容不起作用,因为您使用的是列表而不是元组。不错的收获!【参考方案2】:

这是 DataFrame 中的错误功能。如果聚合器返回第一组的列表,它将因您提到的错误而失败;如果它为第一组返回一个非列表(非系列),它将正常工作。损坏的代码在 groupby.py 中:

def _aggregate_series_pure_python(self, obj, func):

    group_index, _, ngroups = self.group_info

    counts = np.zeros(ngroups, dtype=int)
    result = None

    splitter = get_splitter(obj, group_index, ngroups, axis=self.axis)

    for label, group in splitter:
        res = func(group)
        if result is None:
            if (isinstance(res, (Series, Index, np.ndarray)) or
                    isinstance(res, list)):
                raise ValueError('Function does not reduce')
            result = np.empty(ngroups, dtype='O')

        counts[label] = group.shape[0]
        result[label] = res

请注意if result is Noneisinstance(res, list。 您的选择是:

    伪造 groupby().agg(),所以它看不到第一组的列表,或者

    自己进行聚合,使用类似上面的代码但没有错误的测试。

【讨论】:

如另一个答案tuple 中所解释的那样可以正常工作。准确地说,上述函数不检查对象是否为tuple。错误或功能 - 您决定!

以上是关于Pandas Groupby Agg 函数不减少的主要内容,如果未能解决你的问题,请参考以下文章

pandas使用groupby函数进行分组聚合并使用agg函数将每个分组特定变量对应的多个内容组合到一起输出(merging content within a specific column of g

python处理数据的风骚操作[pandas 之 groupby&agg]

pandas使用groupby函数基于指定分组变量对dataframe数据进行分组使用agg函数计算每个分组不同数值变量的聚合统计值agg参数为字典指定不同变量的聚合计算统计量的形式

Pandas groupby agg - 如何获得计数?

python使用pandas中的groupby函数和agg函数计算每个分组数据的两个分位数(例如百分之10分位数和百分之90分位数)

pandas使用groupby函数按照多个分组变量进行分组聚合统计使用agg函数计算分组的多个统计指标(grouping by multiple columns in dataframe)