Skip to content

Commit

Permalink
BUG: Remove change of global pickle method
Browse files Browse the repository at this point in the history
Refactor PCA and Kernel methods to avoid instance methods
Remove buggy pickling method change in functional graphics

closes statsmodels#4772
  • Loading branch information
bashtage committed Sep 11, 2018
1 parent 4b57473 commit 064c5c3
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 35 deletions.
22 changes: 2 additions & 20 deletions statsmodels/graphics/functional.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
"""Module for functional boxplots."""
from statsmodels.compat.python import range, zip
from statsmodels.compat.scipy import factorial

from statsmodels.multivariate.pca import PCA
from statsmodels.nonparametric.kernel_density import KDEMultivariate
from statsmodels.compat.python import range, zip
from statsmodels.graphics.utils import _import_mpl
from collections import OrderedDict
from itertools import combinations
import numpy as np
from statsmodels.compat.scipy import factorial
try:
from scipy.optimize import differential_evolution, brute, fmin
have_de_optim = True
Expand All @@ -16,31 +16,13 @@
have_de_optim = False
from multiprocessing import Pool
import itertools
try:
import copyreg
except ImportError:
import copy_reg as copyreg
import types

from . import utils


__all__ = ['hdrboxplot', 'fboxplot', 'rainbowplot', 'banddepth']


def _pickle_method(m):
"""Handle pickling issues with class instance."""
if m.im_self is None:
return getattr, (m.im_class, m.im_func.func_name)
else:
return getattr, (m.im_self, m.im_func.func_name)


copyreg.pickle(types.MethodType, _pickle_method)


class HdrResults(object):

"""Wrap results and pretty print them."""

def __init__(self, kwds):
Expand Down
24 changes: 16 additions & 8 deletions statsmodels/multivariate/pca.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,14 +229,9 @@ def __init__(self, data, ncomp=None, standardize=True, demean=True,
self._ncomp = min_dim

self._method = method
if self._method == 'eig':
self._compute_eig = self._compute_using_eig
elif self._method == 'svd':
self._compute_eig = self._compute_using_svd
elif self._method == 'nipals':
self._compute_eig = self._compute_using_nipals
else:
raise ValueError('method is not known.')
# Workaround to avoid instance methods in __dict__
if self._method not in ('eig', 'svd', 'nipals'):
raise ValueError('method {0} is not known.'.format(method))

self.rows = np.arange(self._nobs)
self.cols = np.arange(self._nvar)
Expand Down Expand Up @@ -409,6 +404,19 @@ def _prepare_data(self):
data = adj_data
return data / np.sqrt(self.weights)

def _compute_eig(self):
"""
Wrapper for actual eigenvalue method
This is a workaround to avoid instance methods in __dict__
"""
if self._method == 'eig':
return self._compute_using_eig()
elif self._method == 'svd':
return self._compute_using_svd()
else: # self._method == 'nipals'
return self._compute_using_nipals()

def _compute_using_svd(self):
"""SVD method to compute eigenvalues and eigenvecs"""
x = self.transformed_data
Expand Down
11 changes: 7 additions & 4 deletions statsmodels/nonparametric/_kernel_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,6 @@ def _compute_bw(self, bw):
-----
The default values for bw is 'normal_reference'.
"""

self.bw_func = dict(normal_reference=self._normal_reference,
cv_ml=self._cv_ml, cv_ls=self._cv_ls)
if bw is None:
bw = 'normal_reference'

Expand All @@ -131,7 +128,13 @@ def _compute_bw(self, bw):
else:
# The user specified a bandwidth selection method
self._bw_method = bw
bwfunc = self.bw_func[bw]
# Workaround to avoid instance methods in __dict__
if bw == 'normal_reference':
bwfunc = self._normal_reference
elif bw == 'cv_ml':
bwfunc = self._cv_ml
else: # bw == 'cv_ls'
bwfunc = self._cv_ls
res = bwfunc()

return res
Expand Down
8 changes: 5 additions & 3 deletions statsmodels/nonparametric/kernel_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ def __init__(self, endog, exog, var_type, reg_type='ll', bw='cv_ls',
self.exog = _adjust_shape(exog, self.k_vars)
self.data = np.column_stack((self.endog, self.exog))
self.nobs = np.shape(self.exog)[0]
self.bw_func = dict(cv_ls=self.cv_loo, aic=self.aic_hurvich)
self.est = dict(lc=self._est_loc_constant, ll=self._est_loc_linear)
defaults = EstimatorSettings() if defaults is None else defaults
self._set_defaults(defaults)
Expand All @@ -116,7 +115,11 @@ def _compute_reg_bw(self, bw):
else:
# The user specified a bandwidth selection method e.g. 'cv_ls'
self._bw_method = bw
res = self.bw_func[bw]
# Workaround to avoid instance methods in __dict__
if bw == 'cv_ls':
res = self.cv_loo
else: # bw == 'aic'
res = self.aic_hurvich
X = np.std(self.exog, axis=0)
h0 = 1.06 * X * \
self.nobs ** (- 1. / (4 + np.size(self.exog, axis=1)))
Expand Down Expand Up @@ -494,7 +497,6 @@ def __init__(self, endog, exog, var_type, reg_type, bw='cv_ls',
self.exog = _adjust_shape(exog, self.k_vars)
self.data = np.column_stack((self.endog, self.exog))
self.nobs = np.shape(self.exog)[0]
self.bw_func = dict(cv_ls=self.cv_loo, aic=self.aic_hurvich)
self.est = dict(lc=self._est_loc_constant, ll=self._est_loc_linear)
defaults = EstimatorSettings() if defaults is None else defaults
self._set_defaults(defaults)
Expand Down

0 comments on commit 064c5c3

Please sign in to comment.