Repository: statsmodels/statsmodels

Issue:
A small bug in GenericLikelihoodModelResults.bootstrap()
I guess line 1917 of statsmodels / base / model.py 
`rvsind = np.random.randint(self.nobs - 1, size=self.nobs)`
should be 
`rvsind = np.random.randint(self.nobs, size=self.nobs)`.

Otherwise the last observation would never be sampled.



Discussion:
Thanks for catching this. clearly a bug

( the bootstrap is experimental, because we need to add a more general method for it, that allows a choice of bootstrap type.)

`statsmodels` is a very usefully package, filling the gap between python and statistics beyond high school. (rpy2 and R might be a bit too esoteric to average user like me...) I hope it will become more full-fledged.

I used `GenericLikelihoodModel` to fit psychometric function (essentially a modified logistic regression with lower and upper asymptotes other than 0 and 1), and implemented parametric and non-parametric bootstrap methods accordingly. But I found it not easy for me to make the code more generic in order to be useful to others.

BTW, shall I close this issue for now?

@herrlich10  No, don't close this issue, I still need to fix this.

About your application: If you are willing to publish it, it would still make a good example, either to be converted to a notebook documentation example, https://github.com/statsmodels/statsmodels/wiki/Examples , or as an example that can eventually be converted to a supported model class. 
To the latter: I think it would be useful to get a collection of common non-linear models, and logistic regression, without the 0, 1 probability assumption as in discrete Logit, would be a good candidate. IIRC there are at least a few stackoverflow examples for this.


Resolving patch:
diff --git a/statsmodels/base/model.py b/statsmodels/base/model.py
--- a/statsmodels/base/model.py
+++ b/statsmodels/base/model.py
@@ -1700,7 +1700,7 @@ def bootstrap(self, nrep=100, method='nm', disp=0, store=1):
         print(self.model.__class__)
         hascloneattr = True if hasattr(self, 'cloneattr') else False
         for i in range(nrep):
-            rvsind = np.random.randint(self.nobs - 1, size=self.nobs)
+            rvsind = np.random.randint(self.nobs, size=self.nobs)
             #this needs to set startparam and get other defining attributes
             #need a clone method on model
             fitmod = self.model.__class__(self.endog[rvsind],
diff --git a/statsmodels/tsa/stattools.py b/statsmodels/tsa/stattools.py
--- a/statsmodels/tsa/stattools.py
+++ b/statsmodels/tsa/stattools.py
@@ -582,9 +582,10 @@ def pacf(x, nlags=40, method='ywunbiased', alpha=None):
     else:
         raise ValueError('method not available')
     if alpha is not None:
-        varacf = 1. / len(x)
+        varacf = 1. / len(x) # for all lags >=1
         interval = stats.norm.ppf(1. - alpha / 2.) * np.sqrt(varacf)
         confint = np.array(lzip(ret - interval, ret + interval))
+        confint[0] = ret[0]  # fix confidence interval for lag 0 to varpacf=0
         return ret, confint
     else:
         return ret


Test patch:
diff --git a/statsmodels/base/tests/test_data.py b/statsmodels/base/tests/test_data.py
--- a/statsmodels/base/tests/test_data.py
+++ b/statsmodels/base/tests/test_data.py
@@ -726,8 +726,9 @@ def test_hasconst(self):
                 assert_equal(mod.data.const_idx, result[1])
 
             # extra check after fit, some models raise on singular
+            fit_kwds = getattr(self, 'fit_kwds', {})
             try:
-                res = mod.fit()
+                res = mod.fit(**fit_kwds)
                 assert_equal(res.model.k_constant, result[0])
                 assert_equal(res.model.data.k_constant, result[0])
             except:
@@ -795,6 +796,7 @@ def __init__(self):
         from statsmodels.discrete.discrete_model import Logit
         self.mod = Logit
         self.y = self.y_bin
+        self.fit_kwds = {'disp': False}
 
 
 if __name__ == "__main__":
diff --git a/statsmodels/base/tests/test_optimize.py b/statsmodels/base/tests/test_optimize.py
--- a/statsmodels/base/tests/test_optimize.py
+++ b/statsmodels/base/tests/test_optimize.py
@@ -17,10 +17,10 @@ def dummy_func(x):
     return x**2
 
 def dummy_score(x):
-    return 2*x
+    return 2.*x
 
 def dummy_hess(x):
-    return [[2]]
+    return [[2.]]
 
 def test_full_output_false():
     # just a smoke test
diff --git a/statsmodels/tsa/tests/test_stattools.py b/statsmodels/tsa/tests/test_stattools.py
--- a/statsmodels/tsa/tests/test_stattools.py
+++ b/statsmodels/tsa/tests/test_stattools.py
@@ -179,6 +179,10 @@ def test_ols(self):
         # from edited Stata ado file
         res = [[-.1375625, .1375625]] * 40
         assert_almost_equal(centered[1:41], res, DECIMAL_6)
+        # check lag 0
+        assert_equal(centered[0], [0., 0.])
+        assert_equal(confint[0], [1, 1])
+        assert_equal(pacfols[0], 1)
 
 
     def test_yw(self):