Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAINT: Protect against future pandas changes #7844

Merged
merged 1 commit into from Nov 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 20 additions & 0 deletions statsmodels/compat/pandas.py
@@ -1,4 +1,5 @@
from distutils.version import LooseVersion
from typing import Optional

import numpy as np
import pandas as pd
Expand Down Expand Up @@ -26,6 +27,9 @@
"make_dataframe",
"to_numpy",
"pandas_lt_1_0_0",
"get_cached_func",
"get_cached_doc",
"call_cached_func",
]

version = LooseVersion(pd.__version__)
Expand Down Expand Up @@ -181,3 +185,19 @@ def to_numpy(po: pd.DataFrame) -> np.ndarray:
return po.to_numpy()
except AttributeError:
return po.values


def get_cached_func(cached_prop):
try:
return cached_prop.fget
except AttributeError:
return cached_prop.func


def call_cached_func(cached_prop, *args, **kwargs):
f = get_cached_func(cached_prop)
return f(*args, **kwargs)


def get_cached_doc(cached_prop) -> Optional[str]:
return get_cached_func(cached_prop).__doc__
78 changes: 46 additions & 32 deletions statsmodels/regression/rolling.py
Expand Up @@ -8,7 +8,13 @@
License: 3-clause BSD
"""
from statsmodels.compat.numpy import lstsq
from statsmodels.compat.pandas import Appender, Substitution, cache_readonly
from statsmodels.compat.pandas import (
Appender,
Substitution,
cache_readonly,
call_cached_func,
get_cached_doc,
)

from collections import namedtuple

Expand Down Expand Up @@ -474,6 +480,7 @@ class RollingRegressionResults(object):
cov_type : str
Name of covariance estimator
"""

_data_in_cache = tuple()

def __init__(
Expand Down Expand Up @@ -515,32 +522,33 @@ def _wrap(self, val):
return DataFrame(val, columns=col_names, index=mi)

@cache_readonly
@Appender(RegressionResults.aic.func.__doc__)
@Appender(get_cached_doc(RegressionResults.aic))
def aic(self):
return self._wrap(RegressionResults.aic.func(self))
return self._wrap(call_cached_func(RegressionResults.aic, self))

@cache_readonly
@Appender(RegressionResults.bic.func.__doc__)
@Appender(get_cached_doc(RegressionResults.bic))
def bic(self):
with np.errstate(divide="ignore"):
return self._wrap(RegressionResults.bic.func(self))
return self._wrap(call_cached_func(RegressionResults.bic, self))

def info_criteria(self, crit, dk_params=0):
return self._wrap(RegressionResults.info_criteria(
self, crit, dk_params=dk_params))
return self._wrap(
RegressionResults.info_criteria(self, crit, dk_params=dk_params)
)

@cache_readonly
def params(self):
"""Estimated model parameters"""
return self._wrap(self._params)

@cache_readonly
@Appender(RegressionResults.ssr.func.__doc__)
@Appender(get_cached_doc(RegressionResults.ssr))
def ssr(self):
return self._wrap(self._ssr)

@cache_readonly
@Appender(RegressionResults.llf.func.__doc__)
@Appender(get_cached_doc(RegressionResults.llf))
def llf(self):
return self._wrap(self._llf)

Expand All @@ -555,27 +563,29 @@ def k_constant(self):
return self._k_constant

@cache_readonly
@Appender(RegressionResults.centered_tss.func.__doc__)
@Appender(get_cached_doc(RegressionResults.centered_tss))
def centered_tss(self):
return self._centered_tss

@cache_readonly
@Appender(RegressionResults.uncentered_tss.func.__doc__)
@Appender(get_cached_doc(RegressionResults.uncentered_tss))
def uncentered_tss(self):
return self._uncentered_tss

@cache_readonly
@Appender(RegressionResults.rsquared.func.__doc__)
@Appender(get_cached_doc(RegressionResults.rsquared))
def rsquared(self):
return self._wrap(RegressionResults.rsquared.func(self))
return self._wrap(call_cached_func(RegressionResults.rsquared, self))

@cache_readonly
@Appender(RegressionResults.rsquared_adj.func.__doc__)
@Appender(get_cached_doc(RegressionResults.rsquared_adj))
def rsquared_adj(self):
return self._wrap(RegressionResults.rsquared_adj.func(self))
return self._wrap(
call_cached_func(RegressionResults.rsquared_adj, self)
)

@cache_readonly
@Appender(RegressionResults.nobs.func.__doc__)
@Appender(get_cached_doc(RegressionResults.nobs))
def nobs(self):
return self._wrap(self._nobs)

Expand All @@ -590,24 +600,24 @@ def use_t(self):
return self._use_t

@cache_readonly
@Appender(RegressionResults.ess.func.__doc__)
@Appender(get_cached_doc(RegressionResults.ess))
def ess(self):
return self._wrap(RegressionResults.ess.func(self))
return self._wrap(call_cached_func(RegressionResults.ess, self))

@cache_readonly
@Appender(RegressionResults.mse_model.func.__doc__)
@Appender(get_cached_doc(RegressionResults.mse_model))
def mse_model(self):
return self._wrap(RegressionResults.mse_model.func(self))
return self._wrap(call_cached_func(RegressionResults.mse_model, self))

@cache_readonly
@Appender(RegressionResults.mse_resid.func.__doc__)
@Appender(get_cached_doc(RegressionResults.mse_resid))
def mse_resid(self):
return self._wrap(RegressionResults.mse_resid.func(self))
return self._wrap(call_cached_func(RegressionResults.mse_resid, self))

@cache_readonly
@Appender(RegressionResults.mse_total.func.__doc__)
@Appender(get_cached_doc(RegressionResults.mse_total))
def mse_total(self):
return self._wrap(RegressionResults.mse_total.func(self))
return self._wrap(call_cached_func(RegressionResults.mse_total, self))

@cache_readonly
def _cov_params(self):
Expand All @@ -629,17 +639,19 @@ def cov_params(self):
the returned covariance is a DataFrame with a MultiIndex with
key (observation, variable), so that the covariance for
observation with index i is cov.loc[i].
"""
"""
return self._wrap(self._cov_params)

@cache_readonly
@Appender(RegressionResults.f_pvalue.func.__doc__)
@Appender(get_cached_doc(RegressionResults.f_pvalue))
def f_pvalue(self):
with np.errstate(invalid="ignore"):
return self._wrap(RegressionResults.f_pvalue.func(self))
return self._wrap(
call_cached_func(RegressionResults.f_pvalue, self)
)

@cache_readonly
@Appender(RegressionResults.fvalue.func.__doc__)
@Appender(get_cached_doc(RegressionResults.fvalue))
def fvalue(self):
if self._cov_type == "nonrobust":
return self.mse_model / self.mse_resid
Expand All @@ -665,19 +677,21 @@ def fvalue(self):
return stat

@cache_readonly
@Appender(RegressionResults.bse.func.__doc__)
@Appender(get_cached_doc(RegressionResults.bse))
def bse(self):
with np.errstate(invalid="ignore"):
return self._wrap(np.sqrt(np.diagonal(self._cov_params, 0, 2)))

@cache_readonly
@Appender(LikelihoodModelResults.tvalues.func.__doc__)
@Appender(get_cached_doc(LikelihoodModelResults.tvalues))
def tvalues(self):
with np.errstate(invalid="ignore"):
return self._wrap(LikelihoodModelResults.tvalues.func(self))
return self._wrap(
call_cached_func(LikelihoodModelResults.tvalues, self)
)

@cache_readonly
@Appender(LikelihoodModelResults.pvalues.func.__doc__)
@Appender(get_cached_doc(LikelihoodModelResults.pvalues))
def pvalues(self):
if self.use_t:
df_resid = getattr(self, "df_resid_inference", self.df_resid)
Expand Down
13 changes: 9 additions & 4 deletions statsmodels/tsa/ar_model.py
@@ -1,7 +1,12 @@
# -*- coding: utf-8 -*-
from __future__ import annotations

from statsmodels.compat.pandas import Appender, Substitution, to_numpy
from statsmodels.compat.pandas import (
Appender,
Substitution,
call_cached_func,
to_numpy,
)

from collections.abc import Iterable
import datetime as dt
Expand Down Expand Up @@ -1774,9 +1779,9 @@ def compute_ics(res):
nobs=nobs, df_model=df_model, sigma2=sigma2, llf=llf
)

aic = AutoRegResults.aic.func(res)
bic = AutoRegResults.bic.func(res)
hqic = AutoRegResults.hqic.func(res)
aic = call_cached_func(AutoRegResults.aic, res)
bic = call_cached_func(AutoRegResults.bic, res)
hqic = call_cached_func(AutoRegResults.hqic, res)

return aic, bic, hqic

Expand Down
8 changes: 4 additions & 4 deletions statsmodels/tsa/ardl/model.py
@@ -1,6 +1,6 @@
from __future__ import annotations

from statsmodels.compat.pandas import Appender, Substitution
from statsmodels.compat.pandas import Appender, Substitution, call_cached_func
from statsmodels.compat.python import Literal

from collections import defaultdict
Expand Down Expand Up @@ -1450,9 +1450,9 @@ def compute_ics(y, x, df):
nobs=nobs, df_model=df + x.shape[1], sigma2=sigma2, llf=llf
)

aic = ARDLResults.aic.func(res)
bic = ARDLResults.bic.func(res)
hqic = ARDLResults.hqic.func(res)
aic = call_cached_func(ARDLResults.aic, res)
bic = call_cached_func(ARDLResults.bic, res)
hqic = call_cached_func(ARDLResults.hqic, res)

return aic, bic, hqic

Expand Down