Skip to content

Commit

Permalink
Merge b70da1b into 1bc6576
Browse files Browse the repository at this point in the history
  • Loading branch information
jseabold committed Oct 25, 2013
2 parents 1bc6576 + b70da1b commit b89f890
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 3 deletions.
9 changes: 8 additions & 1 deletion statsmodels/base/data.py
Expand Up @@ -234,7 +234,14 @@ def _get_names(self, arr):
def _get_yarr(self, endog):
if data_util._is_structured_ndarray(endog):
endog = data_util.struct_to_ndarray(endog)
return np.asarray(endog).squeeze()
endog = np.asarray(endog)
if len(endog) == 1: # never squeeze to a scalar
if endog.ndim == 1:
return endog
elif endog.ndim > 1:
return np.asarray([endog.squeeze()])

return endog.squeeze()

def _get_xarr(self, exog):
if data_util._is_structured_ndarray(exog):
Expand Down
6 changes: 5 additions & 1 deletion statsmodels/regression/linear_model.py
Expand Up @@ -412,7 +412,11 @@ def __init__(self, endog, exog, weights=1., missing='none', hasconst=None):
weights = np.array(weights)
if weights.shape == ():
weights = np.repeat(weights, len(endog))
weights = weights.squeeze()
# handle case that endog might be of len == 1
if len(weights) == 1:
weights = np.array([weights.squeeze()])
else:
weights = weights.squeeze()
super(WLS, self).__init__(endog, exog, missing=missing,
weights=weights, hasconst=hasconst)
nobs = self.exog.shape[0]
Expand Down
17 changes: 16 additions & 1 deletion statsmodels/tsa/arima_model.py
Expand Up @@ -349,6 +349,10 @@ def _make_arma_exog(endog, exog, trend):
k_trend = 0
return k_trend, exog

def _check_estimable(nobs, n_params):
if nobs <= n_params:
raise ValueError("Insufficient degrees of freedom to estimate")

class ARMA(tsbase.TimeSeriesModel):

__doc__ = tsbase._tsa_doc % {"model" : _arma_model,
Expand All @@ -364,6 +368,7 @@ def __init__(self, endog, order=None, exog=None, dates=None, freq=None,
warnings.warn("In the next release order will not be optional "
"in the model constructor.", FutureWarning)
else:
_check_estimable(len(self.endog), sum(order))
self.k_ar = k_ar = order[0]
self.k_ma = k_ma = order[1]
self.k_lags = k_lags = max(k_ar,k_ma+1)
Expand Down Expand Up @@ -412,7 +417,12 @@ def _fit_start_params_hr(self, order):
endog -= np.dot(exog, ols_params).squeeze()
if q != 0:
if p != 0:
armod = AR(endog).fit(ic='bic', trend='nc')
# make sure we don't run into small data problems in AR fit
nobs = len(endog)
maxlag = int(round(12*(nobs/100.)**(1/4.)))
if maxlag >= nobs:
maxlag = nobs - 1
armod = AR(endog).fit(ic='bic', trend='nc', maxlag=maxlag)
arcoefs_tmp = armod.params
p_tmp = armod.k_ar
# it's possible in small samples that optimal lag-order
Expand Down Expand Up @@ -794,6 +804,7 @@ def fit(self, order=None, start_params=None, trend='c', method = "css-mle",
"This will overwrite any order given in the model "
"constructor.", FutureWarning)

_check_estimable(len(self.endog), sum(order))
# get model order and constants
self.k_ar = k_ar = int(order[0])
self.k_ma = k_ma = int(order[1])
Expand All @@ -820,6 +831,8 @@ def fit(self, order=None, start_params=None, trend='c', method = "css-mle",
# (re)set trend and handle exogenous variables
# always pass original exog
k_trend, exog = _make_arma_exog(endog, self.exog, trend)
# check again now that we know the trend
_check_estimable(len(endog), k_ar + k_ma + k_exog + k_trend)

self.k_trend = k_trend
self.exog = exog # overwrites original exog from __init__
Expand Down Expand Up @@ -899,6 +912,8 @@ def __init__(self, endog, order, exog=None, dates=None, freq=None,
super(ARIMA, self).__init__(endog, (p,q), exog, dates, freq, missing)
self.k_diff = d
self.endog = np.diff(self.endog, n=d)
#NOTE: will check in ARMA but check again since differenced now
_check_estimable(len(self.endog), p+q)
if exog is not None:
self.exog = self.exog[d:]
self.data.ynames = 'D.' + self.endog_names
Expand Down
18 changes: 18 additions & 0 deletions statsmodels/tsa/tests/test_arima.py
Expand Up @@ -1873,6 +1873,24 @@ def test_arima_1123():
assert_almost_equal(fc[1], 0.968759, 6)
assert_almost_equal(fc[2][0], [0.582485, 4.379952], 6)

def test_small_data():
# 1146
y = [-1214.360173, -1848.209905, -2100.918158, -3647.483678, -4711.186773]

# refuse to estimate these
assert_raises(ValueError, ARIMA, y, (2, 0, 3))
assert_raises(ValueError, ARIMA, y, (1, 1, 3))
mod = ARIMA(y, (1, 0, 3))
assert_raises(ValueError, mod.fit, trend="c")

# try to estimate these...leave it up to the user to check for garbage
# and be clear, these are garbage parameters.
# X-12 arima will estimate, gretl refuses to estimate likely a problem
# in start params regression.
res = mod.fit(trend="nc", disp=0, start_params=[.1,.1,.1,.1])
mod = ARIMA(y, (1, 0, 2))
res = mod.fit(disp=0, start_params=[.1, .1, .1, .1])


if __name__ == "__main__":
import nose
Expand Down

0 comments on commit b89f890

Please sign in to comment.