11import numpy as np
22import pytest
3+ from numpy .testing import assert_allclose
4+ from scipy .sparse import issparse
35
46from sklearn .base import ClassifierMixin
57from sklearn .datasets import load_iris
68from 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
711from sklearn .utils import check_random_state
812from sklearn .utils ._testing import (
913 assert_almost_equal ,
10- assert_array_almost_equal ,
1114 assert_array_equal ,
1215)
1316from 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():
123132def 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):
251260def 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
265274def test_regressor_undefined_methods ():
0 commit comments