Запустите регрессию OLS с фреймом данных Pandas

У меня есть pandas фрейм данных, и я хотел бы предсказать значения столбца A по значениям в столбцах B и C. Вот игрушечный пример:

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

В идеале у меня было бы что-то вроде ols(A ~ B + C, data = df), но когда я смотрю примеры из библиотек алгоритмов, таких как scikit-learn, кажется, что данные загружаются в модель со списком строк вместо столбцов. Это потребовало бы от меня переформатирования данных в списки внутри списков, что, похоже, в первую очередь противоречит цели использования панд. Каков наиболее питонический способ запустить регрессию OLS (или любой алгоритм машинного обучения в целом) для данных в кадре данных pandas?


person Michael    schedule 15.11.2013    source источник


Ответы (6)


Я думаю, что вы можете делать именно то, что считали идеальным, используя пакет statsmodels, который был одним из pandas ' необязательные зависимости до pandas 'версии 0.20.0 (она использовалась для некоторых вещей в 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.
person DSM    schedule 15.11.2013
comment
Обратите внимание, что правильное ключевое слово - formula, вместо этого я случайно набрал formulas и получил странную ошибку: TypeError: from_formula() takes at least 3 arguments (2 given) - person denfromufa; 14.11.2016
comment
@DSM Очень новичок в Python. Пытался запустить тот же код и получил ошибки в обоих сообщениях печати: print result.summary () ^ SyntaxError: недопустимый синтаксис ››› print result.parmas File ‹stdin›, строка 1 print result.parmas ^ SyntaxError: Отсутствуют круглые скобки при вызове 'print' ... Может я неправильно загрузил пакеты ?? Кажется, работает, когда я не помещаю печать. Спасибо. - person a.powell; 01.04.2017
comment
@ a.powell Код OP предназначен для Python 2. Единственное изменение, которое, я думаю, вам нужно сделать, - это заключить в круглые скобки аргументы для печати: print(result.params) и print(result.summary()) - person Paul Moore; 07.04.2017
comment
Я был бы признателен, если бы вы могли взглянуть на это и поблагодарить вас: stackoverflow.com/questions/44923808/ - person Desta Haileselassie Hagos; 05.07.2017
comment
попытка использовать этот подход formula() вызывает ошибку типа TypeError: __init __ () отсутствует 1 обязательный позиционный аргумент: 'endog', поэтому я предполагаю, что он устарел. Кроме того, ols теперь OLS - person 3pitt; 18.05.2018
comment
Как отмечают другие, sm.ols устарел в пользу sm.OLS. Поведение по умолчанию также отличается. Чтобы запустить регрессию по формуле, как это сделано здесь, вам нужно сделать: result = sm.OLS.from_formula(formula="A ~ B + C", data=df).fit() - person Lucas H; 25.02.2019
comment
Насколько я могу судить, по состоянию на март 2019 года это единственный рабочий пример выполнения регрессии из DataFrame pandas во всем Интернете. - person Bill; 16.03.2019

Примечание. pandas.stats был удален в версии 0.20.0


Это можно сделать с помощью 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---------------------------------

Обратите внимание, что у вас должен быть установлен statsmodels пакет, он используется внутри функции pandas.stats.ols.

person Roman Pekar    schedule 15.11.2013
comment
Обратите внимание, что в будущей версии pandas это будет устаревшим! - person denfromufa; 04.04.2016
comment
Зачем это нужно? Я очень надеюсь, что эта функция сохранится! Это ДЕЙСТВИТЕЛЬНО полезно и быстро! - person FaCoffee; 22.11.2016
comment
@DestaHaileselassieHagos. Это может быть связано с проблемой missing intercepts. Разработчик эквивалентного пакета R выполняет корректировку, удаляя корректировку для среднего: stats.stackexchange.com/a/36068/64552 < / а>. . Другие предложения: you can use sm.add_constant to add an intercept to the exog array и используйте dict: reg = ols("y ~ x", data=dict(y=y,x=x)).fit() - person WestCoastProjects; 05.07.2017
comment
Это был печальный день, когда убрали pandas.stats ???? - person 3kstc; 28.02.2018
comment
@RomanPekar: ... Извините, но позволяют ли стандарты сделать комментарий об удалении в верхней части ответа крупнее и смелее? :) Или переместив его ниже серой линии. Мои глаза не отрывались от части Это возможно ... - person CPBL; 14.05.2018
comment
есть странный элемент данных для C 42523. Это выброс. Вероятно, его следует удалить или вменять в среднее значение за вычетом 425323 - person Golden Lion; 12.02.2021

Я не знаю, является ли это новым в sklearn или pandas, но я могу передать фрейм данных непосредственно в sklearn без преобразования фрейма данных в массив numpy или любые другие типы данных.

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])
person 3novak    schedule 07.01.2017
comment
Небольшое отклонение от OP, но я нашел этот конкретный ответ очень полезным после добавления .values.reshape(-1, 1) в столбцы фрейма данных. Например: x_data = df['x_data'].values.reshape(-1, 1) и передача массивов x_data (и созданных аналогичным образом y_data) np в метод .fit(). - person S3DEV; 24.10.2017

Это потребовало бы от меня переформатирования данных в списки внутри списков, что, похоже, в первую очередь противоречит цели использования панд.

Нет, просто преобразуйте в массив NumPy:

>>> data = np.asarray(df)

Это занимает постоянное время, потому что это просто создает представление для ваших данных. Затем скормите его в 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
person Fred Foo    schedule 16.11.2013
comment
Мне пришлось сделать np.matrix( np.asarray( df ) ), потому что sklearn ожидал вертикальный вектор, тогда как массивы numpy, как только вы их вырезаете из массива, действуют как горизонтальные векторы, что в большинстве случаев отлично. - person cjohnson318; 09.01.2014
comment
нет простого способа сделать тесты коэффициентов с этим маршрутом, однако - person MichaelChirico; 26.11.2014
comment
Нет ли способа напрямую кормить Scikit-Learn с Pandas DataFrame? - person Femto Trader; 03.04.2015
comment
для других модулей sklearn (дерево решений и т. д.) я использовал значения df ['colname']., но это не сработало для этого. - person szeitlin; 30.04.2015
comment
Вы также можете использовать атрибут .values. То есть reg.fit(df[['B', 'C']].values, df['A'].values). - person 3novak; 07.01.2017

Statsmodels позволяет создавать модель OLS со ссылками на столбцы непосредственно на фрейм данных pandas.

Кратко и понятно:

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


Подробная информация о коде и сводка регрессии:

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

Вывод:

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

Как напрямую получить R-квадрат, коэффициенты и 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
person vestland    schedule 14.02.2019

B не является статистически значимым. Данные не позволяют делать выводы из них. C влияет на вероятность B

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

 avg_c=df['C'].mean()
 sumC=df['C'].apply(lambda x: x if x<avg_c else 0).sum()
 countC=df['C'].apply(lambda x: 1 if x<avg_c else None).count()
 avg_c2=sumC/countC
 df['C']=df['C'].apply(lambda x: avg_c2 if x >avg_c else x)
 
 print(df)

 model_ols = smf.ols("A ~ B+C",data=df).fit()

 print(model_ols.summary())

 df[['B','C']].plot()
 plt.show()


 df2=pd.DataFrame()
 df2['B']=np.linspace(10,50,10)
 df2['C']=30

 df3=pd.DataFrame()
 df3['B']=np.linspace(10,50,10)
 df3['C']=100

 predB=model_ols.predict(df2)
 predC=model_ols.predict(df3)
 plt.plot(df2['B'],predB,label='predict B C=30')
 plt.plot(df3['B'],predC,label='predict B C=100')
 plt.legend()
 plt.show()

 print("A change in the probability of C affects the probability of B")

 intercept=model_ols.params.loc['Intercept']
 B_slope=model_ols.params.loc['B']
 C_slope=model_ols.params.loc['C']
 #Intercept    11.874252
 #B             0.760859
 #C            -0.060257

 print("Intercept {}\n B slope{}\n C    slope{}\n".format(intercept,B_slope,C_slope))


 #lower_conf,upper_conf=np.exp(model_ols.conf_int())
 #print(lower_conf,upper_conf)
 #print((1-(lower_conf/upper_conf))*100)

 model_cov=model_ols.cov_params()
 std_errorB = np.sqrt(model_cov.loc['B', 'B'])
 std_errorC = np.sqrt(model_cov.loc['C', 'C'])
 print('SE: ', round(std_errorB, 4),round(std_errorC, 4))
 #check for statistically significant
 print("B z value {} C z value {}".format((B_slope/std_errorB),(C_slope/std_errorC)))
 print("B feature is more statistically significant than C")


 Output:

 A change in the probability of C affects the probability of B
 Intercept 11.874251554067563
 B slope0.7608594144571961
 C slope-0.060256845997223814

 Standard Error:  0.4519 0.0793
 B z value 1.683510336937001 C z value -0.7601036314930376
 B feature is more statistically significant than C

 z>2 is statistically significant     
person Golden Lion    schedule 12.02.2021