Repository: scikit-learn/scikit-learn
File: sklearn/linear_model/tests/test_sgd.py (Python)

Code before:
    for nu in [0.1, 0.5, 0.9]:
        # no need for large max_iter
        model = SGDOneClassSVM(
            nu=nu, max_iter=100, tol=1e-3, learning_rate="constant", eta0=1e-3
        )
        model.fit(iris.data)
        # 6 is the minimal number of iterations that should be surpassed, after which
        # the optimization can stop
        assert model.n_iter_ > 6


@pytest.mark.parametrize("eta0, max_iter", [(1e-3, 10000), (3e-4, 20000)])
def test_sgd_oneclass_vs_linear_oneclass(eta0, max_iter):
    # Test convergence vs. liblinear `OneClassSVM` with kernel="linear"
    for nu in [0.1, 0.5, 0.9]:
        # allow enough iterations, small dataset
        model = SGDOneClassSVM(
            nu=nu, max_iter=max_iter, tol=None, learning_rate="constant", eta0=eta0
        )
        model_ref = OneClassSVM(kernel="linear", nu=nu, tol=1e-6)  # reference model
        model.fit(iris.data)
        model_ref.fit(iris.data)

        preds = model.predict(iris.data)
        dec_fn = model.decision_function(iris.data)

        preds_ref = model_ref.predict(iris.data)
        dec_fn_ref = model_ref.decision_function(iris.data)

        dec_fn_corr = np.corrcoef(dec_fn, dec_fn_ref)[0, 1]
        preds_corr = np.corrcoef(preds, preds_ref)[0, 1]
        # check weights and intercept concatenated together for correlation
        coef_corr = np.corrcoef(
            np.concatenate([model.coef_, -model.offset_]),
            np.concatenate([model_ref.coef_.flatten(), model_ref.intercept_]),
        )[0, 1]
        # share of predicted 1's
        share_ones = (preds == 1).sum() / len(preds)

        assert dec_fn_corr > 0.99
        assert preds_corr > 0.95
        assert coef_corr > 0.99
        assert_allclose(1 - share_ones, nu, atol=1e-2)


@pytest.mark.parametrize("nu", [0.1, 0.9])
def test_sgd_oneclass_vs_linear_oneclass_offsets_match(nu):
    """Test that the `offset_` of `SGDOneClassSVM` is close to the `offset_`
    of `OneClassSVM` with `kernel="linear"`, given enough iterations and a
    suitable value for the `eta0` parameter, while also ensuring that the
    dataset is scaled.

Review comment (suggestion):
I removed `0.5` from this list because it seems with higher nu values `OneClassSVM` takes a bit longer to `fit`. This test currently takes about 3s.

Code after:
        model.fit(iris.data)
        model_ref.fit(iris.data)

        preds = model.predict(iris.data)
        dec_fn = model.decision_function(iris.data)

        preds_ref = model_ref.predict(iris.data)
        dec_fn_ref = model_ref.decision_function(iris.data)

        dec_fn_corr = np.corrcoef(dec_fn, dec_fn_ref)[0, 1]
        preds_corr = np.corrcoef(preds, preds_ref)[0, 1]
        # check weights and intercept concatenated together for correlation
        coef_corr = np.corrcoef(
            np.concatenate([model.coef_, -model.offset_]),
            np.concatenate([model_ref.coef_.flatten(), model_ref.intercept_]),
        )[0, 1]
        # share of predicted 1's
        share_ones = (preds == 1).sum() / len(preds)

        assert dec_fn_corr > 0.99
        assert preds_corr > 0.95
        assert coef_corr > 0.99
        assert_allclose(1 - share_ones, nu, atol=1e-2)


@pytest.mark.parametrize("nu", [0.1, 0.9])
def test_sgd_oneclass_vs_linear_oneclass_offsets_match(nu):
    """Test that the `offset_` of `SGDOneClassSVM` is close to the `offset_`
    of `OneClassSVM` with `kernel="linear"`, given enough iterations and a
    suitable value for the `eta0` parameter, while also ensuring that the
    dataset is scaled.
    """
    X = iris.data
    X_scaled = StandardScaler().fit_transform(X)
    model = SGDOneClassSVM(
        nu=nu,
        max_iter=40000,
        tol=None,
        learning_rate="optimal",
        eta0=1e-6,
        random_state=42,
    )
    model_ref = OneClassSVM(kernel="linear", nu=nu, tol=5e-6)
    model.fit(X_scaled)
    model_ref.fit(X_scaled)
    assert_allclose(model.offset_, model_ref.offset_, atol=1.3e-6)


def test_l1_ratio():
    # Test if l1 ratio extremes match L1 and L2 penalty settings.
    X, y = datasets.make_classification(