панды' преобразование не работает сортировка выходных данных метода groupBy


[5] Еще один вопрос панды.

Читая превосходную книгу Уэса Маккинни об анализе данных и пандах, я столкнулся со следующей вещью, которая, как мне казалось, должна была сработать:]}

Предположим, у меня есть некоторая информация о советах.

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

Достаточно хорошо, но тогда я хотел использовать преобразование панды, чтобы сделать то же самое, как это:

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

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

Но вместо этого я получаю следующее:

TypeError: Transform function invalid for data types

Почему? Я знаю, что преобразование требует возврата массива тех же измерений, которые оно принимает в качестве входных данных, поэтому я думал, что буду соответствовать этому требованию, просто сортируя оба среза (курильщиков и некурящих) исходного фрейма данных без изменения их соответствующих размеров. Может ли кто-нибудь объяснить, почему это не удалось?

1 15

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['total_bill']). Вот пример:

>>> 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 сначала вызывается только столбцом A группы C=1 исходного фрейма данных, затем столбцом B этой группы, затем столбцом A группы C=2 и т. д.

Это имеет смысл, если вы подумаете о том, для чего предназначена трансформация. Он предназначен для применения функций преобразования к группам. Но в целом, эти функции не будут иметь смысла, когда применяются ко всей группе, только к данному столбцу. Например, пример в в pandas docs речь идет о Z-стандартизации с использованием transform. Если у вас есть фрейм данных со столбцами для возраста и веса, не имеет смысла Z-стандартизировать по отношению к общему среднему значению обеих этих переменных. Это даже ничего не значит, если взять общее среднее из множества чисел, некоторые из которых являются возрастами, а некоторые-весами. Вы должны Z-стандартизировать возраст по отношению к среднему возрасту и вес по отношению к среднему весу, что означает, что вы хотите преобразовать отдельно для каждой колонки. Таким образом, в принципе, вам не нужно использовать преобразование здесь. apply является здесь подходящей функцией, потому что apply действительно оперирует с каждой группой как единым фреймом данных, в то время как transform оперирует с каждым столбцом каждой группы.