Ejecute una regresión OLS con Pandas Data Frame

111

Tengo un pandasmarco de datos y me gustaría poder predecir los valores de la columna A a partir de los valores de las columnas B y C. Aquí hay un ejemplo de juguete:

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

Idealmente, tendría algo como, ols(A ~ B + C, data = df)pero cuando miro los ejemplos de las bibliotecas de algoritmos scikit-learn, parece que alimenta los datos al modelo con una lista de filas en lugar de columnas. Esto me obligaría a reformatear los datos en listas dentro de listas, lo que parece frustrar el propósito de usar pandas en primer lugar. ¿Cuál es la forma más pitónica de ejecutar una regresión OLS (o cualquier algoritmo de aprendizaje automático en general) en datos en un marco de datos de pandas?

Miguel
fuente

Respuestas:

152

Creo que casi puedes hacer exactamente lo que pensaste que sería ideal, usando el paquete statsmodels , que era una de las pandas'dependencias opcionales antes pandas' de la versión 0.20.0 (se usó para algunas cosas 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
fuente
2
Tenga en cuenta que la palabra clave correcta es formula, formulasTypeError: from_formula() takes at least 3 arguments (2 given)
escribí
@DSM Muy nuevo en Python. Intenté ejecutar el mismo código y obtuve errores en ambos mensajes de impresión: print result.summary () ^ SyntaxError: sintaxis no válida >>> print result.parmas Archivo "<stdin>", línea 1 print result.parmas ^ SyntaxError: faltan paréntesis en llamar para 'imprimir' ... ¿Quizás cargué paquetes mal ?? Parece funcionar cuando no pongo "imprimir". Gracias.
a.powell
2
@ a.powell El código de OP es para Python 2. El único cambio que creo que debe hacer es poner paréntesis alrededor de los argumentos para imprimir: print(result.params)yprint(result.summary())
Paul Moore
Le agradecería si pudiera echar un vistazo a esto y gracias: stackoverflow.com/questions/44923808/…
Desta Haileselassie Hagos
intentar usar este formula()enfoque arroja el error de tipo TypeError: __init __ () falta 1 argumento posicional requerido: 'endog', así que supongo que está en desuso. también, olses ahoraOLS
3pitt
68

Nota: pandas.stats se ha eliminado con 0.20.0


Es posible hacer esto con 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---------------------------------

Tenga en cuenta que debe tener el statsmodelspaquete instalado, la función lo usa internamente pandas.stats.ols.

Roman Pekar
fuente
13
¡Tenga en cuenta que esto quedará obsoleto en la versión futura de pandas!
denfromufa
4
¿Por qué lo estás haciendo? ¡Espero vivamente que esta función sobreviva! ¡Es REALMENTE útil y rápido!
FaCoffee
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. Esto puede deberse a un problema con missing intercepts. El diseñador del Rpaquete equivalente se ajusta quitando el ajuste de la media: stats.stackexchange.com/a/36068/64552 . . Otras sugerencias: you can use sm.add_constant to add an intercept to the exog arrayy use un dict: reg = ols("y ~ x", data=dict(y=y,x=x)).fit()
javadba
2
Fue un día triste cuando quitaron el pandas.stats💔
3kstc
31

No sé si esto es nuevo en sklearno pandas, pero puedo pasar el marco de datos directamente sklearnsin convertir el marco de datos en una matriz numpy o cualquier otro tipo de datos.

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
fuente
2
Pequeña desviación del OP, pero encontré esta respuesta en particular muy útil, después de agregarla .values.reshape(-1, 1)a las columnas del marco de datos. Por ejemplo: x_data = df['x_data'].values.reshape(-1, 1)y pasando las matrices np x_data(y una creada de manera similar y_data) al .fit()método.
S3DEV
16

Esto me obligaría a reformatear los datos en listas dentro de listas, lo que parece frustrar el propósito de usar pandas en primer lugar.

No, no lo hace, simplemente conviértalo en una matriz NumPy:

>>> data = np.asarray(df)

Esto lleva un tiempo constante porque solo crea una vista de sus datos. Luego, aliméntelo a 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
fuente
3
Tenía que hacerlo np.matrix( np.asarray( df ) ), porque sklearn esperaba un vector vertical, mientras que las matrices numpy, una vez que las corta de una matriz, actúan como vecotrs horizontales, lo cual es genial la mayoría de las veces.
cjohnson318
Sin embargo, no hay una forma sencilla de hacer pruebas de los coeficientes con esta ruta
MichaelChirico
2
¿No hay alguna manera de alimentar directamente Scikit-Learn con Pandas DataFrame?
Femto Trader
para otros módulos de sklearn (árbol de decisiones, etc.), he usado valores df ['colname']., pero eso no funcionó para esto.
szeitlin
1
También puede utilizar el .valuesatributo. Es decir, reg.fit(df[['B', 'C']].values, df['A'].values).
3novak
6

Statsmodels puede crear un modelo OLS con referencias de columna directamente a un marco de datos de pandas.

Corto y dulce:

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


Detalles del código y resumen de regresión:

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

Salida:

                            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.
==============================================================================

Cómo obtener directamente R-cuadrado, coeficientes y valor 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
fuente