Repository: scikit-learn/scikit-learn
File: sklearn/svm/tests/test_svm.py (Python)

Code before:

    assert_array_almost_equal(svm_cloned.dual_coef_, svm_builtin.dual_coef_)
    assert_array_almost_equal(svm_cloned.intercept_, svm_builtin.intercept_)
    assert_array_equal(svm_cloned.predict(iris.data), svm_builtin.predict(iris.data))

    assert_array_almost_equal(
        svm_cloned.predict_proba(iris.data),
        svm_builtin.predict_proba(iris.data),
        decimal=4,
    )
    assert_array_almost_equal(
        svm_cloned.decision_function(iris.data),
        svm_builtin.decision_function(iris.data),
    )


def test_svc_bad_kernel():
    svc = svm.SVC(kernel=lambda x, y: x)
    with pytest.raises(ValueError):
        svc.fit(X, Y)


# XXX: this test is thread-unsafe because it uses probability=True:
# https://github.com/scikit-learn/scikit-learn/issues/31885
@pytest.mark.thread_unsafe
@pytest.mark.filterwarnings("ignore::FutureWarning")
def test_libsvm_convergence_warnings(global_random_seed):
    a = svm.SVC(
        kernel=lambda x, y: np.dot(x, y.T),
        probability=True,
        random_state=global_random_seed,
        max_iter=2,
    )
    warning_msg = (
        r"Solver terminated early \(max_iter=2\).  Consider pre-processing "
        r"your data with StandardScaler or MinMaxScaler."
    )
    with pytest.warns(ConvergenceWarning, match=warning_msg):
        a.fit(np.array(X), Y)
    assert np.all(a.n_iter_ == 2)


def test_unfitted():
    X = "foo!"  # input validation not required when SVM not fitted

    clf = svm.SVC()
    with pytest.raises(Exception, match=r".*\bSVC\b.*\bnot\b.*\bfitted\b"):
        clf.predict(X)

    clf = svm.NuSVR()
    with pytest.raises(Exception, match=r".*\bNuSVR\b.*\bnot\b.*\bfitted\b"):

Review comment (suggestion):
I think we could change this test to remove `probability=True` along with all the test function annotations: it seems that the convergence problem tested in this test is unrelated to the choice of `probability=True`.

Code after:
    svc = svm.SVC(kernel=lambda x, y: x)
    with pytest.raises(ValueError):
        svc.fit(X, Y)


def test_libsvm_convergence_warnings(global_random_seed):
    a = svm.SVC(
        kernel=lambda x, y: np.dot(x, y.T),
        random_state=global_random_seed,
        max_iter=2,
    )
    warning_msg = (
        r"Solver terminated early \(max_iter=2\).  Consider pre-processing "
        r"your data with StandardScaler or MinMaxScaler."
    )
    with pytest.warns(ConvergenceWarning, match=warning_msg):
        a.fit(np.array(X), Y)
    assert np.all(a.n_iter_ == 2)


def test_unfitted():
    X = "foo!"  # input validation not required when SVM not fitted

    clf = svm.SVC()
    with pytest.raises(Exception, match=r".*\bSVC\b.*\bnot\b.*\bfitted\b"):
        clf.predict(X)

    clf = svm.NuSVR()
    with pytest.raises(Exception, match=r".*\bNuSVR\b.*\bnot\b.*\bfitted\b"):
        clf.predict(X)


def test_consistent_decision_function(global_random_seed):
    a = svm.SVC(max_iter=1, random_state=global_random_seed)
    proba_1 = a.fit(X, Y).decision_function(X)
    a = svm.SVC(max_iter=1, random_state=global_random_seed)
    proba_2 = a.fit(X, Y).decision_function(X)
    assert_array_almost_equal(proba_1, proba_2)


def test_linear_svm_convergence_warnings(global_random_seed):
    iris = get_iris_dataset(global_random_seed)

    # Test that warnings are raised if model does not converge

    lsvc = svm.LinearSVC(random_state=global_random_seed, max_iter=2)
    warning_msg = "Liblinear failed to converge, increase the number of iterations."
    with pytest.warns(ConvergenceWarning, match=warning_msg):
        lsvc.fit(X, Y)
    # Check that we have an n_iter_ attribute with int type as opposed to a
    # numpy array or an np.int32 so as to match the docstring.