Устаревшая опция rolling window В OLS от Pandas до Statsmodels
как следует из названия, где опция функции rolling в команде ols в Pandas перенесена в в statsmodels? Я не могу его найти. Панды говорят мне, что doom в работах:
FutureWarning: 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://statsmodels.sourceforge.net/stable/regression.html
model = pd.ols(y=series_1, x=mmmm, window=50)
в самом деле, если вы делаете что-то вроде:
import statsmodels.api as sm
model = sm.OLS(series_1, mmmm, window=50).fit()
print(model.summary())
вы получаете результаты (окно не ухудшает работу кода), но вы получаете только параметры регрессии, запущенной на весь период, а не ряд параметров для каждого из скользящего периода, который должен быть должен работать дальше.
3 ответов
Я создал ols
модуль, предназначенный для имитации устаревших панд MovingOLS
; это здесь.
она имеет три основных класса:
-
OLS
: статическая (одно окно) обычная регрессия наименьших квадратов. Выходные данные-массивы NumPy -
RollingOLS
: rolling (multi-window) обычная регрессия наименьших квадратов. Выход выше-размерность массивов numpy. -
PandasRollingOLS
: обертывания результатыRollingOLS
в панд Серия & Таблиц Данных. Предназначен для имитации внешнего вида устаревшего модуля pandas.
обратите внимание, что модуль является частью пакета (который я в настоящее время загружаю в PyPi), и для этого требуется один импорт между пакетами.
первые два класса выше полностью реализованы в NumPy и в первую очередь используют матричную алгебру. RollingOLS
пользуется широкой вещания. Атрибуты в значительной степени имитируют OLS statsmodels RegressionResultsWrapper
.
пример:
# Pull some data from fred.stlouisfed.org
from pandas_datareader.data import DataReader
syms = {'TWEXBMTH' : 'usd',
'T10Y2YM' : 'term_spread',
'PCOPPUSDM' : 'copper'
}
data = (DataReader(syms.keys(), 'fred', start='2000-01-01')
.pct_change()
.dropna())
data = data.rename(columns=syms)
print(data.head())
# usd term_spread copper
# DATE
# 2000-02-01 0.01260 -1.40909 -0.01997
# 2000-03-01 -0.00012 2.00000 -0.03720
# 2000-04-01 0.00564 0.51852 -0.03328
# 2000-05-01 0.02204 -0.09756 0.06135
# 2000-06-01 -0.01012 0.02703 -0.01850
# Rolling regressions
from pyfinance.ols import PandasRollingOLS
y = data.usd
x = data.drop('usd', axis=1)
window = 12 # months
model = PandasRollingOLS(y=y, x=x, window=window)
print(model.beta.head()) # Coefficients excluding the intercept
# term_spread copper
# DATE
# 2001-01-01 0.00010 0.05568
# 2001-02-01 0.00047 0.06271
# 2001-03-01 0.00147 0.03576
# 2001-04-01 0.00161 0.02956
# 2001-05-01 0.00158 -0.04497
print(model.fstat.head())
# DATE
# 2001-01-01 0.28121
# 2001-02-01 0.42602
# 2001-03-01 0.38802
# 2001-04-01 0.39230
# 2001-05-01 0.41706
# Freq: MS, Name: fstat, dtype: float64
print(model.rsq.head()) # R-squared
# DATE
# 2001-01-01 0.05882
# 2001-02-01 0.08648
# 2001-03-01 0.07938
# 2001-04-01 0.08019
# 2001-05-01 0.08482
# Freq: MS, Name: rsq, dtype: float64
Роллинг бета с sklearn
import pandas as pd
from sklearn import linear_model
def rolling_beta(X, y, idx, window=255):
assert len(X)==len(y)
out_dates = []
out_beta = []
model_ols = linear_model.LinearRegression()
for iStart in range(0, len(X)-window):
iEnd = iStart+window
model_ols.fit(X[iStart:iEnd], y[iStart:iEnd])
#store output
out_dates.append(idx[iEnd])
out_beta.append(model_ols.coef_[0][0])
return pd.DataFrame({'beta':out_beta}, index=out_dates)
df_beta = rolling_beta(df_rtn_stocks['NDX'].values.reshape(-1, 1), df_rtn_stocks['CRM'].values.reshape(-1, 1), df_rtn_stocks.index.values, 255)
добавление для полноты скорости numpy
- единственное решение, которое ограничивает вычисления только коэффициентами регрессии и окончательной оценкой
функция регрессии качения Numpy
import numpy as np
def rolling_regression(y, x, window=60):
"""
y and x must be pandas.Series
"""
# === Clean-up ============================================================
x = x.dropna()
y = y.dropna()
# === Trim acc to shortest ================================================
if x.index.size > y.index.size:
x = x[y.index]
else:
y = y[x.index]
# === Verify enough space =================================================
if x.index.size < window:
return None
else:
# === Add a constant if needed ========================================
X = x.to_frame()
X['c'] = 1
# === Loop... this can be improved ====================================
estimate_data = []
for i in range(window, x.index.size+1):
X_slice = X.values[i-window:i,:] # always index in np as opposed to pandas, much faster
y_slice = y.values[i-window:i]
coeff = np.dot(np.dot(np.linalg.inv(np.dot(X_slice.T, X_slice)), X_slice.T), y_slice)
estimate_data.append(coeff[0] * x.values[window-1] + coeff[1])
# === Assemble ========================================================
estimate = pandas.Series(data=estimate_data, index=x.index[window-1:])
return estimate
Примечания
в некоторых конкретных случаях применения, которые требуют только окончательной оценки регрессии, x.rolling(window=60).apply(my_ols)
Кажется несколько медленным
напомним, что коэффициенты регрессии могут быть рассчитывается как матричное произведение, как вы можете прочитать на страница наименьших квадратов Википедии. Этот подход через numpy
матричное умножение может несколько ускорить процесс против использования ols в statsmodels
. Этот продукт выражается в строке, начинающейся как coeff = ...