8000 [MRG] Fix MultinomialNB and BernoulliNB alpha=0 bug by yl565 · Pull Request #7477 · scikit-learn/scikit-learn · GitHub
[go: up one dir, main page]

Skip to content

[MRG] Fix MultinomialNB and BernoulliNB alpha=0 bug #7477

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

8000 Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions sklearn/naive_bayes.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# (parts based on earlier work by Mathieu Blondel)
#
# License: BSD 3 clause
import warnings

from abc import ABCMeta, abstractmethod

Expand Down Expand Up @@ -603,6 +604,9 @@ def _get_intercept(self):
intercept_ = property(_get_intercept)


_ALPHA_MIN = 1e-10


class MultinomialNB(BaseDiscreteNB):
"""
Naive Bayes classifier for multinomial models
Expand Down Expand Up @@ -680,10 +684,21 @@ class MultinomialNB(BaseDiscreteNB):
"""

def __init__(self, alpha=1.0, fit_prior=True, class_prior=None):
self.alpha = alpha
self._alpha = alpha
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this violates scikit-learn API. Please check the setting of alpha in fit. Also, only clip it when it is used, and don't change the value of self.alpha.

self.fit_prior = fit_prior
self.class_prior = class_prior

@property
def alpha(self):
if self._alpha < 0:
raise ValueError('Smoothing parameter alpha = %e. '
'alpha must be >= 0!' % self._alpha)
if self._alpha < _ALPHA_MIN:
warnings.warn('alpha too small will result in numeric errors, '
'setting alpha = %e' % _ALPHA_MIN)
return _ALPHA_MIN
return self._alpha

def _count(self, X, Y):
"""Count and smooth feature occurrences."""
if np.any((X.data if issparse(X) else X) < 0):
Expand Down Expand Up @@ -781,11 +796,22 @@ class BernoulliNB(BaseDiscreteNB):

def __init__(self, alpha=1.0, binarize=.0, fit_prior=True,
class_prior=None):
self.alpha = alpha
self._alpha = alpha
self.binarize = binarize
self.fit_prior = fit_prior
self.class_prior = class_prior

@property
def alpha(self):
if self._alpha < 0:
raise ValueError('Smoothing parameter alpha = %e. '
'alpha must be >= 0!' % self._alpha)
if self._alpha < _ALPHA_MIN:
warnings.warn('alpha too small will result in numeric errors, '
'setting alpha = %e' % _ALPHA_MIN)
return _ALPHA_MIN
return self._alpha

def _count(self, X, Y):
"""Count and smooth feature occurrences."""
if self.binarize is not None:
Expand Down
29 changes: 28 additions & 1 deletion sklearn/tests/test_naive_bayes.py
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ def test_feature_log_prob_bnb():
denom = np.tile(np.log(clf.class_count_ + 2.0), (X.shape[1], 1)).T

# Check manual estimate matches
assert_array_equal(clf.feature_log_prob_, (num - denom))
assert_array_almost_equal(clf.feature_log_prob_, (num - denom))


def test_bnb():
Expand Down Expand Up @@ -536,3 +536,30 @@ def test_naive_bayes_scale_invariance():
for f in [1E-10, 1, 1E10]]
assert_array_equal(labels[0], labels[1])
assert_array_equal(labels[1], labels[2])


def test_alpha_zero():
# Setting alpha=0 should not output nan results when p(x_i|y_j)=0 is a case
X = np.array([[1, 0], [1, 1]])
y = np.array([0, 1])
nb = BernoulliNB(alpha=0.)
nb.fit(X, y)
prob = np.array([[1, 0], [0, 1]])
assert_array_almost_equal(nb.predict_proba(X), prob)

nb = MultinomialNB(alpha=0.)
nb.fit(X, y)
prob = np.array([[2./3, 1./3], [0, 1]])
assert_array_almost_equal(nb.predict_proba(X), prob)

# Test sparse X
X = scipy.sparse.csr_matrix(X)
nb = BernoulliNB(alpha=0.)
nb.fit(X, y)
prob = np.array([[1, 0], [0, 1]])
assert_array_almost_equal(nb.predict_proba(X), prob)

nb = MultinomialNB(alpha=0.)
nb.fit(X, y)
prob = np.array([[2./3, 1./3], [0, 1]])
assert_array_almost_equal(nb.predict_proba(X), prob)
0