File: recursive_ls.py

package info (click to toggle)
statsmodels 0.14.6%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 49,956 kB
  • sloc: python: 254,365; f90: 612; sh: 560; javascript: 337; asm: 156; makefile: 145; ansic: 32; xml: 9
file content (182 lines) | stat: -rw-r--r-- 6,287 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/usr/bin/env python
# coding: utf-8

# DO NOT EDIT
# Autogenerated from the notebook recursive_ls.ipynb.
# Edit the notebook and then sync the output with this file.
#
# flake8: noqa
# DO NOT EDIT

# # Recursive least squares
#
# Recursive least squares is an expanding window version of ordinary least
# squares. In addition to availability of regression coefficients computed
# recursively, the recursively computed residuals the construction of
# statistics to investigate parameter instability.
#
# The `RecursiveLS` class allows computation of recursive residuals and
# computes CUSUM and CUSUM of squares statistics. Plotting these statistics
# along with reference lines denoting statistically significant deviations
# from the null hypothesis of stable parameters allows an easy visual
# indication of parameter stability.
#
# Finally, the `RecursiveLS` model allows imposing linear restrictions on
# the parameter vectors, and can be constructed using the formula interface.

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import statsmodels.api as sm
from pandas_datareader.data import DataReader

np.set_printoptions(suppress=True)

# ## Example 1: Copper
#
# We first consider parameter stability in the copper dataset (description
# below).

print(sm.datasets.copper.DESCRLONG)

dta = sm.datasets.copper.load_pandas().data
dta.index = pd.date_range("1951-01-01", "1975-01-01", freq="YS")
endog = dta["WORLDCONSUMPTION"]

# To the regressors in the dataset, we add a column of ones for an
# intercept
exog = sm.add_constant(
    dta[["COPPERPRICE", "INCOMEINDEX", "ALUMPRICE", "INVENTORYINDEX"]])

# First, construct and fit the model, and print a summary. Although the
# `RLS` model computes the regression parameters recursively, so there are
# as many estimates as there are datapoints, the summary table only presents
# the regression parameters estimated on the entire sample; except for small
# effects from initialization of the recursions, these estimates are
# equivalent to OLS estimates.

mod = sm.RecursiveLS(endog, exog)
res = mod.fit()

print(res.summary())

# The recursive coefficients are available in the `recursive_coefficients`
# attribute. Alternatively, plots can generated using the
# `plot_recursive_coefficient` method.

print(res.recursive_coefficients.filtered[0])
res.plot_recursive_coefficient(range(mod.k_exog), alpha=None, figsize=(10, 6))

# The CUSUM statistic is available in the `cusum` attribute, but usually
# it is more convenient to visually check for parameter stability using the
# `plot_cusum` method. In the plot below, the CUSUM statistic does not move
# outside of the 5% significance bands, so we fail to reject the null
# hypothesis of stable parameters at the 5% level.

print(res.cusum)
fig = res.plot_cusum()

# Another related statistic is the CUSUM of squares. It is available in
# the `cusum_squares` attribute, but it is similarly more convenient to
# check it visually, using the `plot_cusum_squares` method. In the plot
# below, the CUSUM of squares statistic does not move outside of the 5%
# significance bands, so we fail to reject the null hypothesis of stable
# parameters at the 5% level.

res.plot_cusum_squares()

# ## Example 2: Quantity theory of money
#
# The quantity theory of money suggests that "a given change in the rate
# of change in the quantity of money induces ... an equal change in the rate
# of price inflation" (Lucas, 1980). Following Lucas, we examine the
# relationship between double-sided exponentially weighted moving averages
# of money growth and CPI inflation. Although Lucas found the relationship
# between these variables to be stable, more recently it appears that the
# relationship is unstable; see e.g. Sargent and Surico (2010).

start = "1959-12-01"
end = "2015-01-01"
m2 = DataReader("M2SL", "fred", start=start, end=end)
cpi = DataReader("CPIAUCSL", "fred", start=start, end=end)


def ewma(series, beta, n_window):
    nobs = len(series)
    scalar = (1 - beta) / (1 + beta)
    ma = []
    k = np.arange(n_window, 0, -1)
    weights = np.r_[beta**k, 1, beta**k[::-1]]
    for t in range(n_window, nobs - n_window):
        window = series.iloc[t - n_window:t + n_window + 1].values
        ma.append(scalar * np.sum(weights * window))
    return pd.Series(ma,
                     name=series.name,
                     index=series.iloc[n_window:-n_window].index)


m2_ewma = ewma(
    np.log(m2["M2SL"].resample("QS").mean()).diff().iloc[1:], 0.95, 10 * 4)
cpi_ewma = ewma(
    np.log(cpi["CPIAUCSL"].resample("QS").mean()).diff().iloc[1:], 0.95,
    10 * 4)

# After constructing the moving averages using the $\beta = 0.95$ filter
# of Lucas (with a window of 10 years on either side), we plot each of the
# series below. Although they appear to move together prior for part of the
# sample, after 1990 they appear to diverge.

fig, ax = plt.subplots(figsize=(13, 3))

ax.plot(m2_ewma, label="M2 Growth (EWMA)")
ax.plot(cpi_ewma, label="CPI Inflation (EWMA)")
ax.legend()

endog = cpi_ewma
exog = sm.add_constant(m2_ewma)
exog.columns = ["const", "M2"]

mod = sm.RecursiveLS(endog, exog)
res = mod.fit()

print(res.summary())

res.plot_recursive_coefficient(1, alpha=None)

# The CUSUM plot now shows substantial deviation at the 5% level,
# suggesting a rejection of the null hypothesis of parameter stability.

res.plot_cusum()

# Similarly, the CUSUM of squares shows substantial deviation at the 5%
# level, also suggesting a rejection of the null hypothesis of parameter
# stability.

res.plot_cusum_squares()

# ## Example 3: Linear restrictions and formulas

# ## Linear restrictions
#
# It is not hard to implement linear restrictions, using the `constraints`
# parameter in constructing the model.

endog = dta["WORLDCONSUMPTION"]
exog = sm.add_constant(
    dta[["COPPERPRICE", "INCOMEINDEX", "ALUMPRICE", "INVENTORYINDEX"]])

mod = sm.RecursiveLS(endog, exog, constraints="COPPERPRICE = ALUMPRICE")
res = mod.fit()
print(res.summary())

# ## Formula
#
# One could fit the same model using the class method `from_formula`.

mod = sm.RecursiveLS.from_formula(
    "WORLDCONSUMPTION ~ COPPERPRICE + INCOMEINDEX + ALUMPRICE + INVENTORYINDEX",
    dta,
    constraints="COPPERPRICE = ALUMPRICE",
)
res = mod.fit()
print(res.summary())