【问题标题】:pandas' transform doesn't work sorting groupby outputpandas 的转换不起作用对 groupby 输出进行排序
【发布时间】:2012-12-01 00:37:15
【问题描述】:

另一个熊猫问题。

阅读 Wes Mckinney 关于数据分析和 Pandas 的优秀书籍,我遇到了以下我认为应该可行的事情:

假设我有一些关于提示的信息。

In [119]:

tips.head()
Out[119]:
total_bill  tip      sex     smoker    day   time    size  tip_pct
0    16.99   1.01    Female  False   Sun     Dinner  2   0.059447
1    10.34   1.66    Male    False   Sun     Dinner  3   0.160542
2    21.01   3.50    Male    False   Sun     Dinner  3   0.166587
3    23.68   3.31    Male    False   Sun     Dinner  2   0.139780
4    24.59   3.61    Female  False   Sun     Dinner  4   0.146808

我想知道与总账单相关的五个最大提示,即分别针对吸烟者和非吸烟者的tip_pct。所以这行得通:

def top(df, n=5, column='tip_pct'): 
    return df.sort_index(by=column)[-n:]

In [101]:

tips.groupby('smoker').apply(top)
Out[101]:
           total_bill   tip sex smoker  day time    size    tip_pct
smoker                                  
False   88   24.71   5.85    Male    False   Thur    Lunch   2   0.236746
185  20.69   5.00    Male    False   Sun     Dinner  5   0.241663
51   10.29   2.60    Female  False   Sun     Dinner  2   0.252672
149  7.51    2.00    Male    False   Thur    Lunch   2   0.266312
232  11.61   3.39    Male    False   Sat     Dinner  2   0.291990

True    109  14.31   4.00    Female  True    Sat     Dinner  2   0.279525
183  23.17   6.50    Male    True    Sun     Dinner  4   0.280535
67   3.07    1.00    Female  True    Sat     Dinner  1   0.325733
178  9.60    4.00    Female  True    Sun     Dinner  2   0.416667
172  7.25    5.15    Male    True    Sun     Dinner  2   0.710345

很好,但后来我想使用 pandas 的变换来做同样的事情:

def top_all(df):
    return df.sort_index(by='tip_pct')

tips.groupby('smoker').transform(top_all)

但是我得到了这个:

TypeError: Transform function invalid for data types

为什么?我知道转换需要返回一个与它作为输入接受的相同尺寸的数组,所以我认为我会遵守该要求,只需对原始 DataFrame 的两个切片(吸烟者和非吸烟者)进行排序而不改变它们各自的尺寸.谁能解释它为什么失败?

【问题讨论】:

    标签: python aggregate pandas


    【解决方案1】:

    transform 没有很好的文档记录,但它的工作方式似乎是转换函数传递的不是整个组作为数据帧,而是单个组的单个列。我不认为它真的适用于您正在尝试做的事情,您使用apply 的解决方案很好。

    所以假设tips.groupby('smoker').transform(func)。将有两个组,分别称为 group1 和 group2。转换不会调用func(group1)func(group2)。相反,它调用func(group1['total_bill']),然后是func(group1['tip']),等等,然后是func(group2['total_bill'])func(group2['tip'])。这是一个例子:

    >>> print d
       A  B  C
    0 -2  5  4
    1  1 -1  2
    2  0  2  1
    3 -3  1  2
    4  5  0  2
    >>> def foo(df):
    ...     print ">>>"
    ...     print df
    ...     print "<<<"
    ...     return df
    >>> print d.groupby('C').transform(foo)
    >>>
    2    0
    Name: A
    <<<
    >>>
    2    2
    Name: B
    <<<
    >>>
    1    1
    3   -3
    4    5
    Name: A
    <<<
    >>>
    1   -1
    3    1
    4    0
    Name: B
    # etc.
    

    你可以看到foo首先被调用,只有原始数据框的C=1组的A列,然后是该组的B列,然后是C=2组的A列,等等.

    如果您考虑一下转换的用途,这是有道理的。它用于在组上应用变换函数。但一般来说,这些函数在应用于整个组时没有意义,仅应用于给定列。例如,pandas 文档中的示例是关于使用 transform 进行 z 标准化的。如果您有一个包含年龄和体重列的 DataFrame,则针对这两个变量的总体平均值进行 z 标准化是没有意义的。取一堆数字的整体平均值甚至没有任何意义,其中一些是年龄,其中一些是权重。您必须根据平均年龄对年龄和相对于平均体重的体重进行 z 标准化,这意味着您要对每一列分别进行转换。

    所以基本上,你不需要在这里使用转换。 apply 是这里的合适函数,因为apply 确实将每个组作为单个 DataFrame 进行操作,而 transform 对每个组的每一列进行操作。

    【讨论】:

    • 优秀的答案。非常感谢!
    • 为什么transform的文档记录这么差?它让我疯狂。我不认为你有它完全正确(虽然我不知道它实际上是如何工作的),因为当你在你的函数中放置打印语句时,很明显转换实际上是将列作为序列和数据帧传递。它真的很奇怪,我想确切地了解幕后发生的事情,但找不到有关实际上如何实现转换的信息。
    猜你喜欢
    • 1970-01-01
    • 2021-07-02
    • 1970-01-01
    • 2021-08-27
    • 2017-06-13
    • 2022-12-11
    • 2016-11-04
    • 2020-02-22
    • 2019-06-27
    相关资源
    最近更新 更多