Exécuter une régression OLS avec Pandas Data Frame

111

J'ai un pandasbloc de données et j'aimerais pouvoir prédire les valeurs de la colonne A à partir des valeurs des colonnes B et C.Voici un exemple de jouet:

import pandas as pd
df = pd.DataFrame({"A": [10,20,30,40,50], 
                   "B": [20, 30, 10, 40, 50], 
                   "C": [32, 234, 23, 23, 42523]})

Idéalement, j'aurais quelque chose comme ols(A ~ B + C, data = df)mais quand je regarde les exemples des bibliothèques d'algorithmes, scikit-learnil semble que cela alimente les données du modèle avec une liste de lignes au lieu de colonnes. Cela m'obligerait à reformater les données en listes à l'intérieur de listes, ce qui semble aller à l'encontre de l'objectif d'utiliser des pandas en premier lieu. Quelle est la manière la plus pythonique d'exécuter une régression OLS (ou un algorithme d'apprentissage automatique plus généralement) sur des données dans une trame de données pandas?

Michael
la source

Réponses:

152

Je pense que vous pouvez presque faire exactement ce que vous pensiez être l'idéal, en utilisant le package statsmodels qui était l'une des pandas`` dépendances optionnelles avant pandas'' la version 0.20.0 (il a été utilisé pour plusieurs choses dans pandas.stats.)

>>> import pandas as pd
>>> import statsmodels.formula.api as sm
>>> df = pd.DataFrame({"A": [10,20,30,40,50], "B": [20, 30, 10, 40, 50], "C": [32, 234, 23, 23, 42523]})
>>> result = sm.ols(formula="A ~ B + C", data=df).fit()
>>> print(result.params)
Intercept    14.952480
B             0.401182
C             0.000352
dtype: float64
>>> print(result.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                      A   R-squared:                       0.579
Model:                            OLS   Adj. R-squared:                  0.158
Method:                 Least Squares   F-statistic:                     1.375
Date:                Thu, 14 Nov 2013   Prob (F-statistic):              0.421
Time:                        20:04:30   Log-Likelihood:                -18.178
No. Observations:                   5   AIC:                             42.36
Df Residuals:                       2   BIC:                             41.19
Df Model:                           2                                         
==============================================================================
                 coef    std err          t      P>|t|      [95.0% Conf. Int.]
------------------------------------------------------------------------------
Intercept     14.9525     17.764      0.842      0.489       -61.481    91.386
B              0.4012      0.650      0.617      0.600        -2.394     3.197
C              0.0004      0.001      0.650      0.583        -0.002     0.003
==============================================================================
Omnibus:                          nan   Durbin-Watson:                   1.061
Prob(Omnibus):                    nan   Jarque-Bera (JB):                0.498
Skew:                          -0.123   Prob(JB):                        0.780
Kurtosis:                       1.474   Cond. No.                     5.21e+04
==============================================================================

Warnings:
[1] The condition number is large, 5.21e+04. This might indicate that there are
strong multicollinearity or other numerical problems.
DSM
la source
2
Notez que le mot clé correct est formula, j'ai tapé accidentellement à la formulasplace et j'ai eu une erreur étrange:TypeError: from_formula() takes at least 3 arguments (2 given)
denfromufa
@DSM Très nouveau en python. J'ai essayé d'exécuter le même code et j'ai obtenu des erreurs sur les deux messages d'impression: print result.summary () ^ SyntaxError: syntaxe invalide >>> print result.parmas File "<stdin>", ligne 1 print result.parmas ^ SyntaxError: parenthèses manquantes dans appel à 'imprimer' ... Peut-être ai-je mal chargé les paquets ?? Cela semble fonctionner quand je ne mets pas "print". Merci.
a.powell
2
@ a.powell Le code de l'OP est pour Python 2. Le seul changement que je pense que vous devez faire est de mettre des parenthèses autour des arguments pour imprimer: print(result.params)etprint(result.summary())
Paul Moore
J'apprécierais si vous pouviez jeter un oeil à ceci et merci: stackoverflow.com/questions/44923808/…
Desta Haileselassie Hagos
essayer d'utiliser cette formula()approche lève l'erreur de type TypeError: __init __ () manque 1 argument de position requis: 'endog', donc je suppose qu'il est obsolète. aussi, olsest maintenantOLS
3pitt
68

Remarque: pandas.stats a été supprimé avec 0.20.0


Il est possible de faire cela avec pandas.stats.ols:

>>> from pandas.stats.api import ols
>>> df = pd.DataFrame({"A": [10,20,30,40,50], "B": [20, 30, 10, 40, 50], "C": [32, 234, 23, 23, 42523]})
>>> res = ols(y=df['A'], x=df[['B','C']])
>>> res
-------------------------Summary of Regression Analysis-------------------------

Formula: Y ~ <B> + <C> + <intercept>

Number of Observations:         5
Number of Degrees of Freedom:   3

R-squared:         0.5789
Adj R-squared:     0.1577

Rmse:             14.5108

F-stat (2, 2):     1.3746, p-value:     0.4211

Degrees of Freedom: model 2, resid 2

-----------------------Summary of Estimated Coefficients------------------------
      Variable       Coef    Std Err     t-stat    p-value    CI 2.5%   CI 97.5%
--------------------------------------------------------------------------------
             B     0.4012     0.6497       0.62     0.5999    -0.8723     1.6746
             C     0.0004     0.0005       0.65     0.5826    -0.0007     0.0014
     intercept    14.9525    17.7643       0.84     0.4886   -19.8655    49.7705
---------------------------------End of Summary---------------------------------

Notez que vous devez avoir le statsmodelspackage installé, il est utilisé en interne par la pandas.stats.olsfonction.

Roman Pekar
la source
13
Notez que cela va être obsolète dans la future version de pandas!
denfromufa
4
Pourquoi le faites-vous? J'espère vivement que cette fonction survivra! C'est VRAIMENT utile et rapide!
FaCoffee du
2
The pandas.stats.ols module is deprecated and will be removed in a future version. We refer to external packages like statsmodels, see some examples here: http://www.statsmodels.org/stable/regression.html
javadba
2
@DestaHaileselassieHagos. Cela peut être dû à un problème avec missing intercepts. Le concepteur du Rpackage équivalent s'ajuste en supprimant l'ajustement de la moyenne: stats.stackexchange.com/a/36068/64552 . . Autres suggestions: you can use sm.add_constant to add an intercept to the exog arrayet utilisez un dict: reg = ols("y ~ x", data=dict(y=y,x=x)).fit()
javadba
2
C'était un triste jour quand ils ont retiré le pandas.stats💔
3kstc
31

Je ne sais pas si c'est nouveau dans sklearnou pandas, mais je suis capable de transmettre directement la trame de données sklearnsans convertir la trame de données en un tableau numpy ou tout autre type de données.

from sklearn import linear_model

reg = linear_model.LinearRegression()
reg.fit(df[['B', 'C']], df['A'])

>>> reg.coef_
array([  4.01182386e-01,   3.51587361e-04])
3novak
la source
2
Petit détournement du PO - mais j'ai trouvé cette réponse particulière très utile, après avoir .values.reshape(-1, 1)ajouté aux colonnes du dataframe. Par exemple: x_data = df['x_data'].values.reshape(-1, 1)et en passant les tableaux np x_data(et un tableau créé de manière similaire y_data) dans la .fit()méthode.
S3DEV
16

Cela m'obligerait à reformater les données en listes à l'intérieur de listes, ce qui semble aller à l'encontre de l'objectif d'utiliser des pandas en premier lieu.

Non, il suffit de convertir en un tableau NumPy:

>>> data = np.asarray(df)

Cela prend un temps constant car cela crée simplement une vue sur vos données. Puis alimentez-le pour scikit-learn:

>>> from sklearn.linear_model import LinearRegression
>>> lr = LinearRegression()
>>> X, y = data[:, 1:], data[:, 0]
>>> lr.fit(X, y)
LinearRegression(copy_X=True, fit_intercept=True, normalize=False)
>>> lr.coef_
array([  4.01182386e-01,   3.51587361e-04])
>>> lr.intercept_
14.952479503953672
Fred Foo
la source
3
Je devais le faire np.matrix( np.asarray( df ) ), car sklearn s'attendait à un vecteur vertical, alors que les tableaux numpy, une fois que vous les coupez d'un tableau, agissent comme des vecotrs horizontaux, ce qui est excellent la plupart du temps.
cjohnson318
pas de moyen simple de faire des tests des coefficients avec cet itinéraire, cependant
MichaelChirico
2
N'existe-t-il pas un moyen d'alimenter directement Scikit-Learn avec Pandas DataFrame?
Femto Trader
pour les autres modules sklearn (arbre de décision, etc.), j'ai utilisé df ['colname']. values, mais cela n'a pas fonctionné pour cela.
szeitlin
1
Vous pouvez également utiliser l' .valuesattribut. -À- dire, reg.fit(df[['B', 'C']].values, df['A'].values).
3novak
6

Statsmodels peut construire un modèle OLS avec des références de colonne directement à un dataframe pandas.

Court et doux:

model = sm.OLS(df[y], df[x]).fit()


Détails du code et résumé de la régression:

# imports
import pandas as pd
import statsmodels.api as sm
import numpy as np

# data
np.random.seed(123)
df = pd.DataFrame(np.random.randint(0,100,size=(100, 3)), columns=list('ABC'))

# assign dependent and independent / explanatory variables
variables = list(df.columns)
y = 'A'
x = [var for var in variables if var not in y ]

# Ordinary least squares regression
model_Simple = sm.OLS(df[y], df[x]).fit()

# Add a constant term like so:
model = sm.OLS(df[y], sm.add_constant(df[x])).fit()

model.summary()

Production:

                            OLS Regression Results                            
==============================================================================
Dep. Variable:                      A   R-squared:                       0.019
Model:                            OLS   Adj. R-squared:                 -0.001
Method:                 Least Squares   F-statistic:                    0.9409
Date:                Thu, 14 Feb 2019   Prob (F-statistic):              0.394
Time:                        08:35:04   Log-Likelihood:                -484.49
No. Observations:                 100   AIC:                             975.0
Df Residuals:                      97   BIC:                             982.8
Df Model:                           2                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const         43.4801      8.809      4.936      0.000      25.996      60.964
B              0.1241      0.105      1.188      0.238      -0.083       0.332
C             -0.0752      0.110     -0.681      0.497      -0.294       0.144
==============================================================================
Omnibus:                       50.990   Durbin-Watson:                   2.013
Prob(Omnibus):                  0.000   Jarque-Bera (JB):                6.905
Skew:                           0.032   Prob(JB):                       0.0317
Kurtosis:                       1.714   Cond. No.                         231.
==============================================================================

Comment obtenir directement le R au carré, les coefficients et la valeur p:

# commands:
model.params
model.pvalues
model.rsquared

# demo:
In[1]: 
model.params
Out[1]:
const    43.480106
B         0.124130
C        -0.075156
dtype: float64

In[2]: 
model.pvalues
Out[2]: 
const    0.000003
B        0.237924
C        0.497400
dtype: float64

Out[3]:
model.rsquared
Out[2]:
0.0190
vestland
la source