Execute uma regressão OLS com o Pandas Data Frame

111

Tenho um pandasquadro de dados e gostaria de prever os valores da coluna A a partir dos valores das colunas B e C. Aqui está um exemplo de brinquedo:

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, eu teria algo como, ols(A ~ B + C, data = df)mas quando vejo os exemplos das bibliotecas de algoritmos scikit-learn, parece que ele alimenta os dados para o modelo com uma lista de linhas em vez de colunas. Isso exigiria que eu reformatasse os dados em listas dentro de listas, o que parece anular o propósito de usar os pandas em primeiro lugar. Qual é a maneira mais pítônica de executar uma regressão OLS (ou qualquer algoritmo de aprendizado de máquina de forma mais geral) em dados em um quadro de dados do pandas?

Michael
fonte

Respostas:

152

Acho que você quase pode fazer exatamente o que achou que seria o ideal, usando o pacote statsmodels que era uma das pandas'dependências opcionais antes pandas' da versão 0.20.0 (foi usado para algumas coisas no 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
fonte
2
Observe que a palavra-chave correta é formula, eu acidentalmente digitei formulase recebi um erro estranho:TypeError: from_formula() takes at least 3 arguments (2 given)
denfromufa
@DSM Muito novo em python. Tentei executar o mesmo código e obtiveram erros nas duas mensagens de impressão: print result.summary () ^ SyntaxError: sintaxe inválida >>> print result.parmas Arquivo "<stdin>", linha 1 print result.parmas ^ SyntaxError: Parênteses ausentes em ligue para 'imprimir' ... Talvez eu carreguei os pacotes errados ?? Parece funcionar quando não coloco "imprimir". Obrigado.
a.powell de
2
@ a.powell O código do OP é para Python 2. A única mudança que acho que você precisa fazer é colocar parênteses ao redor dos argumentos para imprimir: print(result.params)eprint(result.summary())
Paul Moore
Eu apreciaria se você pudesse dar uma olhada nisso e obrigado: stackoverflow.com/questions/44923808/…
Desta Haileselassie Hagos
tentar usar essa formula()abordagem gera o erro de tipo TypeError: __init __ () faltando 1 argumento posicional obrigatório: 'endog', então acho que está obsoleto. também, olsé agoraOLS
3pitt
68

Nota: pandas.stats foi removido com 0,20.0


É possível fazer isso com 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---------------------------------

Observe que você precisa ter o statsmodelspacote instalado, ele é usado internamente pela pandas.stats.olsfunção.

Roman Pekar
fonte
13
Observe que isso será descontinuado na versão futura do pandas!
denfromufa
4
Por que está fazendo isso? Espero vivamente que esta função sobreviva! É REALMENTE útil e rápido!
FaCoffee de
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. Isso pode ser devido a um problema com missing intercepts. O designer do Rpacote equivalente ajusta removendo o ajuste para a média: stats.stackexchange.com/a/36068/64552 . . Outras sugestões: you can use sm.add_constant to add an intercept to the exog arraye use um dict: reg = ols("y ~ x", data=dict(y=y,x=x)).fit()
javadba
2
Foi um dia triste quando eles removeram o pandas.stats💔
3kstc
31

Não sei se isso é novo em sklearnou pandas, mas sou capaz de passar o quadro de dados diretamente para, sklearnsem converter o quadro de dados em uma matriz numpy ou qualquer outro tipo de dados.

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
fonte
2
Pequeno desvio do OP - mas achei essa resposta específica muito útil, depois de anexar .values.reshape(-1, 1)às colunas do dataframe. Por exemplo: x_data = df['x_data'].values.reshape(-1, 1)e passando os arrays np x_data(e criados de forma semelhante y_data) para o .fit()método.
S3DEV
16

Isso exigiria que eu reformatasse os dados em listas dentro de listas, o que parece anular o propósito de usar os pandas em primeiro lugar.

Não, não precisa, basta converter em uma matriz NumPy:

>>> data = np.asarray(df)

Isso leva um tempo constante porque apenas cria uma visualização dos seus dados. Em seguida, alimente-o para o 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
fonte
3
Eu tive que fazer np.matrix( np.asarray( df ) ), porque sklearn esperava um vetor vertical, enquanto matrizes numpy, uma vez que você os corta de uma matriz, agem como vecotrs horizontais, o que é ótimo na maioria das vezes.
cjohnson318
nenhuma maneira simples de fazer testes dos coeficientes com esta rota, no entanto
MichaelChirico
2
Não há uma maneira de alimentar diretamente o Scikit-Learn com o Pandas DataFrame?
Femto Trader
para outros módulos sklearn (árvore de decisão, etc), usei df ['colname'] .valores, mas não funcionou para isso.
szeitlin
1
Você também pode usar o .valuesatributo. Ie reg.fit(df[['B', 'C']].values, df['A'].values),.
3novak
6

Statsmodels podem construir um modelo OLS com referências de coluna diretamente para um dataframe do pandas.

Curto e grosso:

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


Detalhes do código e resumo da regressão:

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

Resultado:

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

Como obter diretamente R ao quadrado, coeficientes e 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
fonte