From 95aa2952e1544a5a2e0f14d366bae1bfd8e9195a Mon Sep 17 00:00:00 2001
From: Naoya Kanai <naopon@gmail.com>
Date: Sat, 10 Jun 2017 06:01:02 -0700
Subject: [PATCH] Add logsumexp and comb to utils.fixes (#9046)

---
 sklearn/decomposition/online_lda.py         |  2 +-
 sklearn/ensemble/gradient_boosting.py       |  3 +--
 sklearn/ensemble/tests/test_forest.py       |  2 +-
 sklearn/linear_model/logistic.py            |  2 +-
 sklearn/linear_model/tests/test_sag.py      |  2 +-
 sklearn/metrics/cluster/supervised.py       |  2 +-
 sklearn/mixture/base.py                     |  2 +-
 sklearn/mixture/dpgmm.py                    |  2 +-
 sklearn/mixture/gmm.py                      |  2 +-
 sklearn/model_selection/_split.py           |  3 +--
 sklearn/model_selection/tests/test_split.py |  3 ++-
 sklearn/naive_bayes.py                      |  2 +-
 sklearn/utils/extmath.py                    |  2 +-
 sklearn/utils/fixes.py                      | 13 +++++++++----
 sklearn/utils/tests/test_random.py          |  4 ++--
 15 files changed, 25 insertions(+), 21 deletions(-)

diff --git a/sklearn/decomposition/online_lda.py b/sklearn/decomposition/online_lda.py
index 68900a3ea0..7cfcb0ae43 100644
--- a/sklearn/decomposition/online_lda.py
+++ b/sklearn/decomposition/online_lda.py
@@ -13,13 +13,13 @@ Link: http://matthewdhoffman.com/code/onlineldavb.tar
 
 import numpy as np
 import scipy.sparse as sp
-from scipy.misc import logsumexp
 from scipy.special import gammaln
 import warnings
 
 from ..base import BaseEstimator, TransformerMixin
 from ..utils import (check_random_state, check_array,
                      gen_batches, gen_even_slices, _get_n_jobs)
+from ..utils.fixes import logsumexp
 from ..utils.validation import check_non_negative
 from ..externals.joblib import Parallel, delayed
 from ..externals.six.moves import xrange
diff --git a/sklearn/ensemble/gradient_boosting.py b/sklearn/ensemble/gradient_boosting.py
index 779cf2d3b5..baa0d7b0ae 100644
--- a/sklearn/ensemble/gradient_boosting.py
+++ b/sklearn/ensemble/gradient_boosting.py
@@ -27,7 +27,6 @@ from abc import ABCMeta
 from abc import abstractmethod
 
 from .base import BaseEnsemble
-from ..base import BaseEstimator
 from ..base import ClassifierMixin
 from ..base import RegressorMixin
 from ..externals import six
@@ -40,7 +39,6 @@ import numbers
 import numpy as np
 
 from scipy import stats
-from scipy.misc import logsumexp
 from scipy.sparse import csc_matrix
 from scipy.sparse import csr_matrix
 from scipy.sparse import issparse
@@ -57,6 +55,7 @@ from ..utils import check_X_y
 from ..utils import column_or_1d
 from ..utils import check_consistent_length
 from ..utils import deprecated
+from ..utils.fixes import logsumexp
 from ..utils.stats import _weighted_percentile
 from ..utils.validation import check_is_fitted
 from ..utils.multiclass import check_classification_targets
diff --git a/sklearn/ensemble/tests/test_forest.py b/sklearn/ensemble/tests/test_forest.py
index b964ed768d..8f09d26df0 100644
--- a/sklearn/ensemble/tests/test_forest.py
+++ b/sklearn/ensemble/tests/test_forest.py
@@ -14,7 +14,6 @@ from itertools import combinations
 from itertools import product
 
 import numpy as np
-from scipy.misc import comb
 from scipy.sparse import csr_matrix
 from scipy.sparse import csc_matrix
 from scipy.sparse import coo_matrix
@@ -42,6 +41,7 @@ from sklearn.ensemble import RandomTreesEmbedding
 from sklearn.model_selection import GridSearchCV
 from sklearn.svm import LinearSVC
 from sklearn.utils.validation import check_random_state
+from sklearn.utils.fixes import comb
 
 from sklearn.tree.tree import SPARSE_SPLITTERS
 
diff --git a/sklearn/linear_model/logistic.py b/sklearn/linear_model/logistic.py
index c12b494380..281a460615 100644
--- a/sklearn/linear_model/logistic.py
+++ b/sklearn/linear_model/logistic.py
@@ -15,7 +15,6 @@ import warnings
 
 import numpy as np
 from scipy import optimize, sparse
-from scipy.misc import logsumexp
 from scipy.special import expit
 
 from .base import LinearClassifierMixin, SparseCoefMixin, BaseEstimator
@@ -27,6 +26,7 @@ from ..utils import check_random_state
 from ..utils.extmath import (log_logistic, safe_sparse_dot, softmax,
                              squared_norm)
 from ..utils.extmath import row_norms
+from ..utils.fixes import logsumexp
 from ..utils.optimize import newton_cg
 from ..utils.validation import check_X_y
 from ..exceptions import NotFittedError
diff --git a/sklearn/linear_model/tests/test_sag.py b/sklearn/linear_model/tests/test_sag.py
index 3d1df5116b..02a557d56e 100644
--- a/sklearn/linear_model/tests/test_sag.py
+++ b/sklearn/linear_model/tests/test_sag.py
@@ -6,7 +6,6 @@
 import math
 import numpy as np
 import scipy.sparse as sp
-from scipy.misc import logsumexp
 
 from sklearn.linear_model.sag import get_auto_step_size
 from sklearn.linear_model.sag_fast import _multinomial_grad_loss_all_samples
@@ -14,6 +13,7 @@ from sklearn.linear_model import LogisticRegression, Ridge
 from sklearn.linear_model.base import make_dataset
 from sklearn.linear_model.logistic import _multinomial_loss_grad
 
+from sklearn.utils.fixes import logsumexp
 from sklearn.utils.extmath import row_norms
 from sklearn.utils.testing import assert_almost_equal
 from sklearn.utils.testing import assert_array_almost_equal
diff --git a/sklearn/metrics/cluster/supervised.py b/sklearn/metrics/cluster/supervised.py
index 9115b93abe..f1f033bf6f 100644
--- a/sklearn/metrics/cluster/supervised.py
+++ b/sklearn/metrics/cluster/supervised.py
@@ -18,11 +18,11 @@ from __future__ import division
 from math import log
 
 import numpy as np
-from scipy.misc import comb
 from scipy import sparse as sp
 
 from .expected_mutual_info_fast import expected_mutual_information
 from ...utils.validation import check_array
+from ...utils.fixes import comb
 
 
 def comb2(n):
diff --git a/sklearn/mixture/base.py b/sklearn/mixture/base.py
index 3c8c701e62..478131a945 100644
--- a/sklearn/mixture/base.py
+++ b/sklearn/mixture/base.py
@@ -11,7 +11,6 @@ from abc import ABCMeta, abstractmethod
 from time import time
 
 import numpy as np
-from scipy.misc import logsumexp
 
 from .. import cluster
 from ..base import BaseEstimator
@@ -19,6 +18,7 @@ from ..base import DensityMixin
 from ..externals import six
 from ..exceptions import ConvergenceWarning
 from ..utils import check_array, check_random_state
+from ..utils.fixes import logsumexp
 
 
 def _check_shape(param, param_shape, name):
diff --git a/sklearn/mixture/dpgmm.py b/sklearn/mixture/dpgmm.py
index 8e2137b44f..3d1858c513 100644
--- a/sklearn/mixture/dpgmm.py
+++ b/sklearn/mixture/dpgmm.py
@@ -21,11 +21,11 @@ import numpy as np
 from scipy.special import digamma as _digamma, gammaln as _gammaln
 from scipy import linalg
 from scipy.linalg import pinvh
-from scipy.misc import logsumexp
 from scipy.spatial.distance import cdist
 
 from ..externals.six.moves import xrange
 from ..utils import check_random_state, check_array, deprecated
+from ..utils.fixes import logsumexp
 from ..utils.extmath import squared_norm, stable_cumsum
 from ..utils.validation import check_is_fitted
 from .. import cluster
diff --git a/sklearn/mixture/gmm.py b/sklearn/mixture/gmm.py
index 3fd659ece8..79ff8d169d 100644
--- a/sklearn/mixture/gmm.py
+++ b/sklearn/mixture/gmm.py
@@ -19,10 +19,10 @@ from time import time
 
 import numpy as np
 from scipy import linalg
-from scipy.misc import logsumexp
 
 from ..base import BaseEstimator
 from ..utils import check_random_state, check_array, deprecated
+from ..utils.fixes import logsumexp
 from ..utils.validation import check_is_fitted
 from .. import cluster
 
diff --git a/sklearn/model_selection/_split.py b/sklearn/model_selection/_split.py
index 7d9c8f9aad..d4cd2537e5 100644
--- a/sklearn/model_selection/_split.py
+++ b/sklearn/model_selection/_split.py
@@ -22,14 +22,13 @@ from abc import ABCMeta, abstractmethod
 
 import numpy as np
 
-from scipy.misc import comb
 from ..utils import indexable, check_random_state, safe_indexing
 from ..utils.validation import _num_samples, column_or_1d
 from ..utils.validation import check_array
 from ..utils.multiclass import type_of_target
 from ..externals.six import with_metaclass
 from ..externals.six.moves import zip
-from ..utils.fixes import signature
+from ..utils.fixes import signature, comb
 from ..base import _pprint
 
 __all__ = ['BaseCrossValidator',
diff --git a/sklearn/model_selection/tests/test_split.py b/sklearn/model_selection/tests/test_split.py
index ad77ecd7b8..93f0dff189 100644
--- a/sklearn/model_selection/tests/test_split.py
+++ b/sklearn/model_selection/tests/test_split.py
@@ -5,7 +5,6 @@ import warnings
 import numpy as np
 from scipy.sparse import coo_matrix, csc_matrix, csr_matrix
 from scipy import stats
-from scipy.misc import comb
 from itertools import combinations
 from itertools import combinations_with_replacement
 
@@ -57,6 +56,8 @@ from sklearn.datasets import make_classification
 from sklearn.externals import six
 from sklearn.externals.six.moves import zip
 
+from sklearn.utils.fixes import comb
+
 from sklearn.svm import SVC
 
 X = np.ones(10)
diff --git a/sklearn/naive_bayes.py b/sklearn/naive_bayes.py
index 5c81dc7041..fbff00fb67 100644
--- a/sklearn/naive_bayes.py
+++ b/sklearn/naive_bayes.py
@@ -19,7 +19,6 @@ are supervised learning methods based on applying Bayes' theorem with strong
 from abc import ABCMeta, abstractmethod
 
 import numpy as np
-from scipy.misc import logsumexp
 from scipy.sparse import issparse
 
 from .base import BaseEstimator, ClassifierMixin
@@ -28,6 +27,7 @@ from .preprocessing import LabelBinarizer
 from .preprocessing import label_binarize
 from .utils import check_X_y, check_array, check_consistent_length
 from .utils.extmath import safe_sparse_dot
+from .utils.fixes import logsumexp
 from .utils.multiclass import _check_partial_fit_first_call
 from .utils.validation import check_is_fitted
 from .externals import six
diff --git a/sklearn/utils/extmath.py b/sklearn/utils/extmath.py
index 0e0a211882..687ddd4e4a 100644
--- a/sklearn/utils/extmath.py
+++ b/sklearn/utils/extmath.py
@@ -17,10 +17,10 @@ import warnings
 import numpy as np
 from scipy import linalg
 from scipy.sparse import issparse, csr_matrix
-from scipy.misc import logsumexp as scipy_logsumexp
 
 from . import check_random_state, deprecated
 from .fixes import np_version
+from .fixes import logsumexp as scipy_logsumexp
 from ._logistic_sigmoid import _log_logistic_sigmoid
 from ..externals.six.moves import xrange
 from .sparsefuncs_fast import csr_row_norms
diff --git a/sklearn/utils/fixes.py b/sklearn/utils/fixes.py
index bfa5c917b0..0e96057f92 100644
--- a/sklearn/utils/fixes.py
+++ b/sklearn/utils/fixes.py
@@ -11,8 +11,6 @@ at which the fixe is no longer needed.
 # License: BSD 3 clause
 
 import warnings
-import sys
-import functools
 import os
 import errno
 
@@ -36,6 +34,7 @@ def _parse_version(version_string):
             version.append(x)
     return tuple(version)
 
+
 euler_gamma = getattr(np, 'euler_gamma',
                       0.577215664901532860606512090082402431)
 
@@ -142,11 +141,17 @@ if sp_version < (0, 15):
     # Backport fix for scikit-learn/scikit-learn#2986 / scipy/scipy#4142
     from ._scipy_sparse_lsqr_backport import lsqr as sparse_lsqr
 else:
-    from scipy.sparse.linalg import lsqr as sparse_lsqr
+    from scipy.sparse.linalg import lsqr as sparse_lsqr  # noqa
+
+
+try:  # SciPy >= 0.19
+    from scipy.special import comb, logsumexp
+except ImportError:
+    from scipy.misc import comb, logsumexp  # noqa
 
 
 def parallel_helper(obj, methodname, *args, **kwargs):
-    """Helper to workaround Python 2 limitations of pickling instance methods"""
+    """Workaround for Python 2 limitations of pickling instance methods"""
     return getattr(obj, methodname)(*args, **kwargs)
 
 
diff --git a/sklearn/utils/tests/test_random.py b/sklearn/utils/tests/test_random.py
index 199c2310fb..159635c569 100644
--- a/sklearn/utils/tests/test_random.py
+++ b/sklearn/utils/tests/test_random.py
@@ -2,10 +2,10 @@ from __future__ import division
 
 import numpy as np
 import scipy.sparse as sp
-from scipy.misc import comb as combinations
 from numpy.testing import assert_array_almost_equal
 from sklearn.utils.random import sample_without_replacement
 from sklearn.utils.random import random_choice_csc
+from sklearn.utils.fixes import comb
 
 from sklearn.utils.testing import (
     assert_raises,
@@ -88,7 +88,7 @@ def check_sample_int_distribution(sample_without_replacement):
         # Counting the number of combinations is not as good as counting the
         # the number of permutations. However, it works with sampling algorithm
         # that does not provide a random permutation of the subset of integer.
-        n_expected = combinations(n_population, n_samples, exact=True)
+        n_expected = comb(n_population, n_samples, exact=True)
 
         output = {}
         for i in range(n_trials):
-- 
GitLab