|
12 | 12 | assert_array_equal,
|
13 | 13 | )
|
14 | 14 | from scipy import sparse
|
15 |
| -from scipy.linalg import svd |
| 15 | +from scipy.linalg import LinAlgWarning, svd |
16 | 16 |
|
17 | 17 | from sklearn import config_context
|
18 | 18 | from sklearn._loss import HalfMultinomialLoss
|
@@ -2374,3 +2374,45 @@ def test_multi_class_deprecated():
|
2374 | 2374 | lrCV = LogisticRegressionCV(multi_class="multinomial")
|
2375 | 2375 | with pytest.warns(FutureWarning, match=msg):
|
2376 | 2376 | lrCV.fit(X, y)
|
| 2377 | + |
| 2378 | + |
| 2379 | +def test_newton_cholesky_fallback_to_lbfgs(global_random_seed): |
| 2380 | + # Wide data matrix should lead to a rank-deficient Hessian matrix |
| 2381 | + # hence make the Newton-Cholesky solver raise a warning and fallback to |
| 2382 | + # lbfgs. |
| 2383 | + X, y = make_classification( |
| 2384 | + n_samples=10, n_features=20, random_state=global_random_seed |
| 2385 | + ) |
| 2386 | + C = 1e30 # very high C to nearly disable regularization |
| 2387 | + |
| 2388 | + # Check that LBFGS can converge without any warning on this problem. |
| 2389 | + lr_lbfgs = LogisticRegression(solver="lbfgs", C=C) |
| 2390 | + with warnings.catch_warnings(): |
| 2391 | + warnings.simplefilter("error") |
| 2392 | + lr_lbfgs.fit(X, y) |
| 2393 | + n_iter_lbfgs = lr_lbfgs.n_iter_[0] |
| 2394 | + |
| 2395 | + assert n_iter_lbfgs >= 1 |
| 2396 | + |
| 2397 | + # Check that the Newton-Cholesky solver raises a warning and falls back to |
| 2398 | + # LBFGS. This should converge with the same number of iterations as the |
| 2399 | + # above call of lbfgs since the Newton-Cholesky triggers the fallback |
| 2400 | + # before completing the first iteration, for the problem setting at hand. |
| 2401 | + lr_nc = LogisticRegression(solver="newton-cholesky", C=C) |
| 2402 | + with ignore_warnings(category=LinAlgWarning): |
| 2403 | + lr_nc.fit(X, y) |
| 2404 | + n_iter_nc = lr_nc.n_iter_[0] |
| 2405 | + |
| 2406 | + assert n_iter_nc == n_iter_lbfgs |
| 2407 | + |
| 2408 | + # Trying to fit the same model again with a small iteration budget should |
| 2409 | + # therefore raise a ConvergenceWarning: |
| 2410 | + lr_nc_limited = LogisticRegression( |
| 2411 | + solver="newton-cholesky", C=C, max_iter=n_iter_lbfgs - 1 |
| 2412 | + ) |
| 2413 | + with ignore_warnings(category=LinAlgWarning): |
| 2414 | + with pytest.warns(ConvergenceWarning, match="lbfgs failed to converge"): |
| 2415 | + lr_nc_limited.fit(X, y) |
| 2416 | + n_iter_nc_limited = lr_nc_limited.n_iter_[0] |
| 2417 | + |
| 2418 | + assert n_iter_nc_limited == lr_nc_limited.max_iter - 1 |
0 commit comments