Repository: statsmodels/statsmodels

Issue:
Tests missing for functions if pandas is used
see for example #715 

I didn't see any test cases for regression plots that use pandas.
I think it might be similarly bad in many other areas.



Discussion:

Resolving patch:
diff --git a/statsmodels/graphics/regressionplots.py b/statsmodels/graphics/regressionplots.py
--- a/statsmodels/graphics/regressionplots.py
+++ b/statsmodels/graphics/regressionplots.py
@@ -17,6 +17,7 @@
 from statsmodels.sandbox.regression.predstd import wls_prediction_std
 from statsmodels.graphics import utils
 from statsmodels.nonparametric.smoothers_lowess import lowess
+from statsmodels.tools.tools import maybe_unwrap_results
 
 
 __all__ = ['plot_fit', 'plot_regress_exog', 'plot_partregress', 'plot_ccpr',
@@ -24,6 +25,7 @@
            'add_lowess', 'abline_plot', 'influence_plot',
            'plot_leverage_resid2']
 
+
 #TODO: consider moving to influence module
 def _high_leverage(results):
     #TODO: replace 1 with k_constant
@@ -86,6 +88,7 @@ def plot_fit(results, exog_idx, y_true=None, ax=None, **kwargs):
     fig, ax = utils.create_mpl_ax(ax)
 
     exog_name, exog_idx = utils.maybe_name_or_idx(exog_idx, results.model)
+    results = maybe_unwrap_results(results)
 
     #maybe add option for wendog, wexog
     y = results.model.endog
@@ -99,10 +102,11 @@ def plot_fit(results, exog_idx, y_true=None, ax=None, **kwargs):
         ax.plot(x1, y_true[x1_argsort], 'b-', label='True values')
     title = 'Fitted values versus %s' % exog_name
 
-    prstd, iv_l, iv_u = wls_prediction_std(results._results)
+    prstd, iv_l, iv_u = wls_prediction_std(results)
     ax.plot(x1, results.fittedvalues[x1_argsort], 'D', color='r',
             label='fitted', **kwargs)
-    ax.vlines(x1, iv_l[x1_argsort], iv_u[x1_argsort], linewidth=1, color='k', alpha=.7)
+    ax.vlines(x1, iv_l[x1_argsort], iv_u[x1_argsort], linewidth=1, color='k',
+            alpha=.7)
     #ax.fill_between(x1, iv_l[x1_argsort], iv_u[x1_argsort], alpha=0.1,
     #                    color='k')
     ax.set_title(title)
@@ -138,11 +142,12 @@ def plot_regress_exog(results, exog_idx, fig=None):
     fig = utils.create_mpl_fig(fig)
 
     exog_name, exog_idx = utils.maybe_name_or_idx(exog_idx, results.model)
+    results = maybe_unwrap_results(results)
 
     #maybe add option for wendog, wexog
     y_name = results.model.endog_names
     x1 = results.model.exog[:,exog_idx]
-    prstd, iv_l, iv_u = wls_prediction_std(results._results)
+    prstd, iv_l, iv_u = wls_prediction_std(results)
 
     ax = fig.add_subplot(2,2,1)
     ax.plot(x1, results.model.endog, 'o', color='b', alpha=0.9, label=y_name)
@@ -477,10 +482,11 @@ def plot_ccpr(results, exog_idx, ax=None):
     fig, ax = utils.create_mpl_ax(ax)
 
     exog_name, exog_idx = utils.maybe_name_or_idx(exog_idx, results.model)
+    results = maybe_unwrap_results(results)
 
     x1 = results.model.exog[:, exog_idx]
     #namestr = ' for %s' % self.name if self.name else ''
-    x1beta = x1*results._results.params[exog_idx]
+    x1beta = x1*results.params[exog_idx]
     ax.plot(x1, x1beta + results.resid, 'o')
     from statsmodels.tools.tools import add_constant
     mod = OLS(x1beta, add_constant(x1)).fit()
diff --git a/statsmodels/stats/outliers_influence.py b/statsmodels/stats/outliers_influence.py
--- a/statsmodels/stats/outliers_influence.py
+++ b/statsmodels/stats/outliers_influence.py
@@ -13,6 +13,7 @@
 from statsmodels.regression.linear_model import OLS
 from statsmodels.tools.decorators import cache_readonly
 from statsmodels.stats.multitest import multipletests
+from statsmodels.tools.tools import maybe_unwrap_results
 
 # outliers test convenience wrapper
 
@@ -57,7 +58,7 @@ def outlier_test(model_results, method='bonf', alpha=.05, labels=None,
     from scipy import stats # lazy import
     infl = getattr(model_results, 'get_influence', None)
     if infl is None:
-        results = getattr(model_results, '_results', model_results)
+        results = maybe_unwrap_results(model_results)
         raise AttributeError("model_results object %s does not have a "
                 "get_influence method." % results.__class__.__name__)
     resid = infl().resid_studentized_external
@@ -198,10 +199,7 @@ class OLSInfluence(object):
 
     def __init__(self, results):
         #check which model is allowed
-        try:
-            self.results = results._results # don't use wrapped results
-        except: # we got unwrapped results
-            self.results = results
+        self.results = maybe_unwrap_results(results)
         self.nobs, self.k_vars = results.model.exog.shape
         self.endog = results.model.endog
         self.exog = results.model.exog
diff --git a/statsmodels/tools/tools.py b/statsmodels/tools/tools.py
--- a/statsmodels/tools/tools.py
+++ b/statsmodels/tools/tools.py
@@ -523,3 +523,12 @@ def nan_dot(A, B):
     C[should_be_nan] = np.nan
 
     return C
+
+def maybe_unwrap_results(results):
+    """
+    Gets raw results back from wrapped results.
+
+    Can be used in plotting functions or other post-estimation type
+    routines.
+    """
+    return getattr(results, '_results', results)


Test patch:
diff --git a/statsmodels/graphics/tests/test_regressionplots.py b/statsmodels/graphics/tests/test_regressionplots.py
--- a/statsmodels/graphics/tests/test_regressionplots.py
+++ b/statsmodels/graphics/tests/test_regressionplots.py
@@ -9,6 +9,7 @@
 from statsmodels.graphics.regressionplots import (plot_fit, plot_ccpr,
                   plot_partregress, plot_regress_exog, abline_plot,
                   plot_partregress_grid, plot_ccpr_grid)
+from pandas import Series, DataFrame
 
 try:
     import matplotlib.pyplot as plt  #makes plt available for test functions
@@ -76,6 +77,21 @@ def test_plot_oth(self):
 
         plt.close('all')
 
+class TestPlotPandas(TestPlot):
+    def setup(self):
+        nsample = 100
+        sig = 0.5
+        x1 = np.linspace(0, 20, nsample)
+        x2 = 5 + 3* np.random.randn(nsample)
+        X = np.c_[x1, x2, np.sin(0.5*x1), (x2-5)**2, np.ones(nsample)]
+        beta = [0.5, 0.5, 1, -0.04, 5.]
+        y_true = np.dot(X, beta)
+        y = y_true + sig * np.random.normal(size=nsample)
+        exog0 = sm.add_constant(np.c_[x1, x2], prepend=False)
+        exog0 = DataFrame(exog0, columns=["const", "var1", "var2"])
+        y = Series(y, name="outcome")
+        res = sm.OLS(y, exog0).fit()
+        self.res = res
 
 class TestABLine(object):
 
@@ -116,3 +132,17 @@ def test_abline_ab_ax(self):
         ax.scatter(self.X[:,1], self.y)
         fig = abline_plot(intercept=intercept, slope=slope, ax=ax)
         plt.close(fig)
+
+class TestABLinePandas(TestABLine):
+    @classmethod
+    def setupClass(cls):
+        np.random.seed(12345)
+        X = sm.add_constant(np.random.normal(0, 20, size=30))
+        y = np.dot(X, [25, 3.5]) + np.random.normal(0, 30, size=30)
+        cls.X = X
+        cls.y = y
+        X = DataFrame(X, columns=["const", "someX"])
+        y = Series(y, name="outcome")
+        mod = sm.OLS(y,X).fit()
+        cls.mod = mod
+