2015-09-18 19 views
5

Chciałbym użyć pand i modeli statycznych, aby dopasować model liniowy do podzbiorów ramki danych i zwrócić przewidywane wartości. Mam jednak problem ze znalezieniem odpowiedniego idiomu pandy. Oto, co usiłuję zrobić:Czy grupy pandy mogą przekształcić DataFrame w serię?

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) 

Pojawia się następujący błąd:

--------------------------------------------------------------------------- 
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) 

Błąd sens, że myślę .transform chce zmapować DataFrame do DataFrame. Ale czy istnieje sposób na wykonanie operacji groupby w DataFrame, przekazanie każdej porcji do funkcji, która redukuje ją do Serii (z tym samym indeksem), a następnie połączenie uzyskanych Serii w coś, co można wstawić do oryginalnej ramki danych?

Odpowiedz

2

Górna część tutaj jest taka sama, używam tylko zestawu danych zabawki b/c Jestem za zaporą.

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) 

Jeśli zmienisz „przekształcić” do „zastosowania”, dostaniesz:

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 

to nie całkiem to, czego chcesz, ale jeśli spadnie poziom = 0, można postępować zgodnie z zapotrzebowaniem :

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

Ciekawe, to nie działa z zestawem danych porad Seaborn ze względu na błąd polegający na tym, że 'dzień' jest obiektem kategorycznym. Zastanawiam się, czy to błąd w pandach. – mwaskom

+0

Działa na mistrza pandy. Wystąpił błąd w Categoricals nie posiadający flagi dla join/concats. – TomAugspurger

+0

Cool. @TomAugspurger, czy uważasz, że jest to najbardziej idiotyczny sposób na zrobienie tego w Pandach? Zaznaczę poprawne, jeśli tak. – mwaskom

0

EDIT:

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

musiałem zmodyfikować funkcję fit_predict do nazwania 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

Należy jednak zauważyć, że nie działa na przykład podany w pytaniu. – mwaskom

+0

Nie ma to znaczenia, ponieważ '.describe' zamienia' DataFrame' na 'DataFrame', a nie' DataFrame' na 'Series'. – mwaskom

+0

Masz rację. Zmodyfikowałem swoją odpowiedź, aby przekazać funkcję DataFrame do DataFrame na 'transform'. –