Pandas 'преобразование не работает.

Другой вопрос pandas.

Чтение 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 без изменения их соответствующих размеров, Может ли кто-нибудь объяснить, почему это не удалось?

Ответ 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 посвящен z-стандартизации с использованием transform. Если у вас есть DataFrame с столбцами по возрасту и весу, было бы нецелесообразно z-стандартизировать по отношению к среднему значению обеих этих переменных. Это даже не означает ничего, чтобы принять общее значение совокупности чисел, некоторые из которых являются возрастом, а некоторые из них - весами. Вы должны z-стандартизировать возраст по отношению к среднему возрасту и весу по отношению к среднему весу, что означает, что вы хотите преобразовать отдельно для каждого столбца.

Итак, в принципе, здесь вам не нужно использовать преобразование. apply является подходящей функцией здесь, потому что apply действительно работает в каждой группе как единый DataFrame, а transform работает с каждым столбцом каждой группы.