Мне удалось использовать класс pandas 'MovingOLS
(источник здесь) в устаревшем модуле stats/ols
. К сожалению, он был полностью испорчен pandas 0.20.
Вопрос о том, как эффективно запускать регрессию OLS регенерации, задавался несколько раз (здесь), но сформулирован немного широко и оставлен без отличный ответ, на мой взгляд.
Вот мои вопросы:
-
Как лучше всего имитировать базовую структуру pandas '
MovingOLS
? Самой привлекательной особенностью этого класса была возможность просмотра нескольких методов/атрибутов в виде отдельных временных рядов - т.е. коэффициенты, r-квадрат, t-статистика и т.д., не требуя повторной регрессии. Например, вы можете создать что-то вродеmodel = pd.MovingOLS(y, x)
, а затем вызвать.t_stat
,.rmse
,.std_err
и тому подобное. В приведенном ниже примере, наоборот, я не вижу возможности заставить вас вычислять каждую статистику отдельно. Есть ли метод, который не предусматривает создание скользящих/катящихся "блоков" (шагов) и выполнение регрессий/использование линейной алгебры для получения параметров модели для каждого? -
В более широком смысле, что происходит под капотом в pandas, что делает
rolling.apply
неспособным выполнять более сложные функции? * Когда вы создаете объект.rolling
, в условиях неспециалиста, что происходит внутри - Это принципиально отличается от цикла по каждому окну и создания более массивного массива, как я делаю ниже?
* А именно, func
передано .apply
:
Необходимо создать одно значение из входных данных ndarray * args и ** kwargs передаются функции
Здесь, где я сейчас нахожусь с некоторыми образцами данных, регрессирует процентные изменения в торговом взвешенном долларе по спредам по процентной ставке и цене на медь. (Это не имеет смысла, просто выбрал их случайным образом.) Я взял это из реализации на основе классов и попытался разбить его на более простой script.
from datetime import date
from pandas_datareader.data import DataReader
import statsmodels.formula.api as smf
syms = {'TWEXBMTH' : 'usd',
'T10Y2YM' : 'term_spread',
'PCOPPUSDM' : 'copper'
}
start = date(2000, 1, 1)
data = (DataReader(syms.keys(), 'fred', start)
.pct_change()
.dropna())
data = data.rename(columns = syms)
data = data.assign(intercept = 1.) # required by statsmodels OLS
def sliding_windows(x, window):
"""Create rolling/sliding windows of length ~window~.
Given an array of shape (y, z), it will return "blocks" of shape
(x - window + 1, window, z)."""
return np.array([x[i:i + window] for i
in range(0, x.shape[0] - window + 1)])
data.head(3)
Out[33]:
usd term_spread copper intercept
DATE
2000-02-01 0.012573 -1.409091 -0.019972 1.0
2000-03-01 -0.000079 2.000000 -0.037202 1.0
2000-04-01 0.005642 0.518519 -0.033275 1.0
window = 36
wins = sliding_windows(data.values, window=window)
y, x = wins[:, :, 0], wins[:, :, 1:]
coefs = []
for endog, exog in zip(y, x):
model = smf.OLS(endog, exog).fit()
# The full set of model attributes gets lost with each loop
coefs.append(model.params)
df = pd.DataFrame(coefs, columns=data.iloc[:, 1:].columns,
index=data.index[window - 1:])
df.head(3) # rolling 36m coefficients
Out[70]:
term_spread copper intercept
DATE
2003-01-01 -0.000122 -0.018426 0.001937
2003-02-01 0.000391 -0.015740 0.001597
2003-03-01 0.000655 -0.016811 0.001546