23

另一个熊猫问题。

阅读 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 的两个切片(吸烟者和非吸烟者)进行排序而不改变它们各自的尺寸. 谁能解释它为什么失败?

4

1 回答 1

62

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

所以假设tips.groupby('smoker').transform(func)。将有两个组,分别称为 group1 和 group2。转换不调用func(group1)and func(group2)。相反,它调用func(group1['total_bill']), thenfunc(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. 如果您有一个包含年龄和体重列的 DataFrame,则针对这两个变量的总体平均值进行 z 标准化是没有意义的。取一堆数字的整体平均值甚至没有任何意义,其中一些是年龄,其中一些是权重。您必须根据平均年龄对年龄和相对于平均体重的体重进行 z 标准化,这意味着您要为每列单独转换。

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

于 2012-12-13T07:19:15.917 回答