2015-09-18 6 views
5

Я хотел бы использовать pandas и statsmodels, чтобы соответствовать линейной модели на подмножествах кадра данных и возвращать предсказанные значения. Тем не менее, мне трудно понять правильную идиому панд. Вот что я пытаюсь сделать:Может pandas groupby преобразовать DataFrame в серию?

import pandas as pd 
import statsmodels.formula.api as sm 
import seaborn as sns 

tips = sns.load_dataset("tips") 
def fit_predict(df): 
    m = sm.ols("tip ~ total_bill", df).fit() 
    return pd.Series(m.predict(df), index=df.index) 
tips["predicted_tip"] = tips.groupby("day").transform(fit_predict) 

В этой связи возникает следующее сообщение об ошибке:

--------------------------------------------------------------------------- 
ValueError        Traceback (most recent call last) 
<ipython-input-139-b3d2575e2def> in <module>() 
----> 1 tips["predicted_tip"] = tips.groupby("day").transform(fit_predict) 

/Users/mwaskom/anaconda/lib/python2.7/site-packages/pandas/core/groupby.pyc in transform(self, func, *args, **kwargs) 
    3033      return self._transform_general(func, *args, **kwargs) 
    3034   except: 
-> 3035    return self._transform_general(func, *args, **kwargs) 
    3036 
    3037   # a reduction transform 

/Users/mwaskom/anaconda/lib/python2.7/site-packages/pandas/core/groupby.pyc in _transform_general(self, func, *args, **kwargs) 
    2988      group.T.values[:] = res 
    2989     else: 
-> 2990      group.values[:] = res 
    2991 
    2992     applied.append(group) 

ValueError: could not broadcast input array from shape (62) into shape (62,6) 

Ошибка имеет смысл в том, что я думаю, .transform хочет отобразить DataFrame к DataFrame. Но есть ли способ сделать операцию groupby на DataFrame, передать каждый кусок в функцию, которая сводит ее к Серии (с тем же индексом), а затем объединить полученные Серии в нечто, что можно вставить в исходный фреймворк?

ответ

2

Верхняя часть здесь такая же, я просто использую набор данных для игрушек b/c. Я за брандмауэром.

tips = pd.DataFrame({ 'day':list('MMMFFF'), 'tip':range(6), 
         'total_bill':[10,40,20,80,50,40] }) 

def fit_predict(df): 
    m = sm.ols("tip ~ total_bill", df).fit() 
    return pd.Series(m.predict(df), index=df.index) 

Если вы измените «преобразование» на «применить», вы получите:

tips.groupby("day").apply(fit_predict) 

day 
F 3 2.923077 
    4 4.307692 
    5 4.769231 
M 0 0.714286 
    1 1.357143 
    2 0.928571 

Это не совсем то, что вы хотите, но если вы уронили уровень = 0, можно продолжить по желанию :

tips['predicted'] = tips.groupby("day").apply(fit_predict).reset_index(level=0,drop=True) 

    day tip total_bill predicted 
0 M 0   10 0.714286 
1 M 1   40 1.357143 
2 M 2   20 0.928571 
3 F 3   80 2.923077 
4 F 4   50 4.307692 
5 F 5   40 4.769231 
+1

Интересно, что это не работает с набором данных советов по морским судам из-за ошибки, включающей «день», являющийся категориальным объектом. Интересно, что это ошибка в пандах. – mwaskom

+0

Работает на панды мастера. Была ошибка с категориальными, у которых нет флага для объединений/concats. – TomAugspurger

+0

Прохладный. @TomAugspurger, вы бы сказали, что это самый идиоматический способ сделать это в Пандах? Я буду отмечать, если это так. – mwaskom

0

EDIT:

q.gps.apply(lambda df: df.join(q.fit_predict(df)))

мне пришлось модифицировать fit_predict функцию, чтобы назвать в Series.

def fit_predict(df): 
m = sm.ols("tip ~ total_bill", df).fit() 
s = pd.Series(m.predict(df), index=df.index) 
s.name = 'Prediction' #EDIT 
return s 
+0

Обратите внимание, что это не работает на примере, указанном в вопросе. – mwaskom

+0

Это не актуально, потому что '.describe' отображает' DataFrame' в 'DataFrame', а не' DataFrame' в 'Series'. – mwaskom

+0

Вы правы. Я изменил свой ответ, чтобы передать функцию DataFrame в DataFrame для преобразования. –

Смежные вопросы