def test_posterior_computation(mocker, classes, prior, cfm, first_class_posterior):
    def mock_confusion_matrix(y, y_pred):
        return np.array(cfm)

    mocker.patch("sklego.meta.subjective_classifier.confusion_matrix", side_effect=mock_confusion_matrix)
    mock_estimator = mocker.Mock(RandomForestClassifier())
    mock_estimator.classes_ = np.array(classes)
    subjective_model = SubjectiveClassifier(mock_estimator, dict(zip(classes, prior)))
    subjective_model.fit(np.zeros((10, 10)), np.array([classes[0]] * 10))
    assert (
        pytest.approx(subjective_model.posterior_matrix_[0, 0], 0.001)
        == first_class_posterior
    )
    assert np.isclose(subjective_model.posterior_matrix_.sum(axis=0), 1).all()
def test_fit_y_data_inconsistent_with_prior_failure_conditions(prior, y):
    with pytest.raises(ValueError) as exc:
        SubjectiveClassifier(RandomForestClassifier(),
                             prior).fit(np.zeros((len(y), 2)), np.array(y))

    assert str(
        exc.value).startswith('Training data is inconsistent with prior')
def test_params_failure_conditions(inner_estimator, prior, evidence,
                                   expected_error_msg):
    with pytest.raises(ValueError) as exc:
        SubjectiveClassifier(inner_estimator, prior,
                             evidence).fit(np.zeros((2, 2)), np.zeros(2))

    assert str(exc.value).startswith(expected_error_msg)
def test_weighted_proba(weights, y_hats, expected_probas):
    assert np.isclose(
        SubjectiveClassifier._weighted_proba(np.array(weights),
                                             np.array(y_hats)),
        np.array(expected_probas),
        atol=1e-02,
    ).all()
def test_to_discrete():
    assert np.isclose(
        SubjectiveClassifier._to_discrete(
            np.array([[1, 0], [0.8, 0.2], [0.5, 0.5], [0.2, 0.8]])
        ),
        np.array([[1, 0], [1, 0], [1, 0], [0, 1]]),
    ).all()
def test_predict_proba(mocker, evidence_type, expected_probas):
    def mock_confusion_matrix(y, y_pred):
        return np.array([[80, 20], [10, 90]])

    mocker.patch("sklego.meta.subjective_classifier.confusion_matrix", side_effect=mock_confusion_matrix)
    mock_inner_estimator = mocker.Mock(RandomForestClassifier)
    mock_inner_estimator.predict_proba.return_value = np.array(
        [[0.8, 0.2], [1, 0], [0.5, 0.5], [0.2, 0.8]]
    )
    mock_inner_estimator.classes_ = np.array([0, 1])
    subjective_model = SubjectiveClassifier(
        mock_inner_estimator, {0: 0.8, 1: 0.2}, evidence=evidence_type
    )
    subjective_model.fit(np.zeros((10, 10)), np.zeros(10))
    posterior_probabilities = subjective_model.predict_proba(np.zeros((4, 2)))
    assert posterior_probabilities.shape == (4, 2)
    assert np.isclose(
        posterior_probabilities, np.array(expected_probas), atol=0.01
    ).all()
def test_estimator_checks_classification(test_fn):
    if test_fn.__name__ == 'check_classifiers_classes':
        prior = {
            'one': 0.1,
            'two': 0.1,
            'three': 0.1,
            -1: 0.1,
            1: 0.6
        }  # nonsensical prior to make sklearn check pass
    else:
        prior = {0: 0.7, 1: 0.2, 2: 0.1}

    # Some of the sklearn checkers generate random y data with 3 classes, so prior needs to have these classes
    estimator = SubjectiveClassifier(LogisticRegression(), prior)
    test_fn(SubjectiveClassifier.__name__, estimator)