Skip to content

Commit 3d35e02

Browse files
authored
TST better PassiveAggressive test against simple implementation (#31857)
1 parent d578de5 commit 3d35e02

File tree

1 file changed

+22
-13
lines changed

1 file changed

+22
-13
lines changed

sklearn/linear_model/tests/test_passive_aggressive.py

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import numpy as np
22
import pytest
3+
from numpy.testing import assert_allclose
4+
from scipy.sparse import issparse
35

46
from sklearn.base import ClassifierMixin
57
from sklearn.datasets import load_iris
68
from sklearn.linear_model import PassiveAggressiveClassifier, PassiveAggressiveRegressor
9+
from sklearn.linear_model._base import SPARSE_INTERCEPT_DECAY
10+
from sklearn.linear_model._stochastic_gradient import DEFAULT_EPSILON
711
from sklearn.utils import check_random_state
812
from sklearn.utils._testing import (
913
assert_almost_equal,
10-
assert_array_almost_equal,
1114
assert_array_equal,
1215
)
1316
from sklearn.utils.fixes import CSR_CONTAINERS
@@ -24,7 +27,7 @@ class MyPassiveAggressive(ClassifierMixin):
2427
def __init__(
2528
self,
2629
C=1.0,
27-
epsilon=0.01,
30+
epsilon=DEFAULT_EPSILON,
2831
loss="hinge",
2932
fit_intercept=True,
3033
n_iter=1,
@@ -41,6 +44,12 @@ def fit(self, X, y):
4144
self.w = np.zeros(n_features, dtype=np.float64)
4245
self.b = 0.0
4346

47+
# Mimic SGD's behavior for intercept
48+
intercept_decay = 1.0
49+
if issparse(X):
50+
intercept_decay = SPARSE_INTERCEPT_DECAY
51+
X = X.toarray()
52+
4453
for t in range(self.n_iter):
4554
for i in range(n_samples):
4655
p = self.project(X[i])
@@ -63,7 +72,7 @@ def fit(self, X, y):
6372

6473
self.w += step * X[i]
6574
if self.fit_intercept:
66-
self.b += step
75+
self.b += intercept_decay * step
6776

6877
def project(self, X):
6978
return np.dot(X, self.w) + self.b
@@ -123,15 +132,15 @@ def test_classifier_refit():
123132
def test_classifier_correctness(loss, csr_container):
124133
y_bin = y.copy()
125134
y_bin[y != 1] = -1
135+
data = csr_container(X) if csr_container is not None else X
126136

127-
clf1 = MyPassiveAggressive(loss=loss, n_iter=2)
128-
clf1.fit(X, y_bin)
137+
clf1 = MyPassiveAggressive(loss=loss, n_iter=4)
138+
clf1.fit(data, y_bin)
129139

130-
data = csr_container(X) if csr_container is not None else X
131-
clf2 = PassiveAggressiveClassifier(loss=loss, max_iter=2, shuffle=False, tol=None)
140+
clf2 = PassiveAggressiveClassifier(loss=loss, max_iter=4, shuffle=False, tol=None)
132141
clf2.fit(data, y_bin)
133142

134-
assert_array_almost_equal(clf1.w, clf2.coef_.ravel(), decimal=2)
143+
assert_allclose(clf1.w, clf2.coef_.ravel())
135144

136145

137146
@pytest.mark.parametrize(
@@ -251,15 +260,15 @@ def test_regressor_partial_fit(csr_container, average):
251260
def test_regressor_correctness(loss, csr_container):
252261
y_bin = y.copy()
253262
y_bin[y != 1] = -1
263+
data = csr_container(X) if csr_container is not None else X
254264

255-
reg1 = MyPassiveAggressive(loss=loss, n_iter=2)
256-
reg1.fit(X, y_bin)
265+
reg1 = MyPassiveAggressive(loss=loss, n_iter=4)
266+
reg1.fit(data, y_bin)
257267

258-
data = csr_container(X) if csr_container is not None else X
259-
reg2 = PassiveAggressiveRegressor(tol=None, loss=loss, max_iter=2, shuffle=False)
268+
reg2 = PassiveAggressiveRegressor(loss=loss, max_iter=4, shuffle=False, tol=None)
260269
reg2.fit(data, y_bin)
261270

262-
assert_array_almost_equal(reg1.w, reg2.coef_.ravel(), decimal=2)
271+
assert_allclose(reg1.w, reg2.coef_.ravel())
263272

264273

265274
def test_regressor_undefined_methods():

0 commit comments

Comments
 (0)