Repository: scikit-learn/scikit-learn
File: sklearn/tree/tests/test_tree.py (Python)

Code before:

def test_only_constant_features():
    random_state = check_random_state(0)
    X = np.zeros((10, 20))
    y = random_state.randint(0, 2, (10,))
    for name, TreeEstimator in ALL_TREES.items():
        est = TreeEstimator(random_state=0)
        est.fit(X, y)
        assert est.tree_.max_depth == 0


def test_almost_constant_feature():
    # Non regression test for
    # https://github.com/scikit-learn/scikit-learn/pull/32259
    # Make sure that almost constant features are discarded.
    random_state = check_random_state(0)
    X = random_state.rand(10, 2)
    X[:, 0] *= 1e-7  # almost constant feature
    y = random_state.randint(0, 2, (10,))
    for _, TreeEstimator in ALL_TREES.items():
        est = TreeEstimator(random_state=0)
        est.fit(X, y)
        # the almost constant feature should not be used
        assert est.feature_importances_[0] == 0
        # other feature should be used
        assert est.feature_importances_[1] > 0


def test_behaviour_constant_feature_after_splits():
    X = np.transpose(
        np.vstack(([[0, 0, 0, 0, 0, 1, 2, 4, 5, 6, 7]], np.zeros((4, 11))))
    )
    y = [0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3]
    for name, TreeEstimator in ALL_TREES.items():
        # do not check extra random trees
        if "ExtraTree" not in name:
            est = TreeEstimator(random_state=0, max_features=1)
            est.fit(X, y)
            assert est.tree_.max_depth == 2
            assert est.tree_.node_count == 5


def test_with_only_one_non_constant_features():
    X = np.hstack([np.array([[1.0], [1.0], [0.0], [0.0]]), np.zeros((4, 1000))])

    y = np.array([0.0, 1.0, 0.0, 1.0])
    for name, TreeEstimator in CLF_TREES.items():
        est = TreeEstimator(random_state=0, max_features=1)
        est.fit(X, y)
        assert est.tree_.max_depth == 1
        assert_array_equal(est.predict_proba(X), np.full((4, 2), 0.5))

Review comment (suggestion):
@sercant for some reason, I can not push to your PR branch (maybe you have unticked the box "allow edits by maintainers"?), so doing this as a suggestion instead that you will need to accept. Those are the changes to the test I had in mind (parametrize + comment to explain where `1e-7` comes from):

```suggestion
@pytest.mark.parametrize("tree_cls", ALL_TREES.values())
def test_almost_constant_feature(tree_cls):
    # Non regression test for
    # https://github.com/scikit-learn/scikit-learn/pull/32259
    # Make sure that almost constant features are discarded.
    random_state = check_random_state(0)
    X = random_state.rand(10, 2)
    # FEATURE_TRESHOLD=1e-7 is defined in sklearn/tree/_partitioner.pyx but not
    # accessible from Python
    feature_threshold = 1e-7
    X[:, 0] *= feature_threshold  # almost constant feature
    y = random_state.randint(0, 2, (10,))

    est = tree_cls(random_state=0)
    est.fit(X, y)
    # the almost constant feature should not be used
    assert est.feature_importances_[0] == 0
    # other feature should be used
    assert est.feature_importances_[1] > 0
```

Code after:

def test_only_constant_features():
    random_state = check_random_state(0)
    X = np.zeros((10, 20))
    y = random_state.randint(0, 2, (10,))
    for name, TreeEstimator in ALL_TREES.items():
        est = TreeEstimator(random_state=0)
        est.fit(X, y)
        assert est.tree_.max_depth == 0


@pytest.mark.parametrize("tree_cls", ALL_TREES.values())
def test_almost_constant_feature(tree_cls):
    # Non regression test for
    # https://github.com/scikit-learn/scikit-learn/pull/32259
    # Make sure that almost constant features are discarded.
    random_state = check_random_state(0)
    X = random_state.rand(10, 2)
    # FEATURE_TRESHOLD=1e-7 is defined in sklearn/tree/_partitioner.pxd but not
    # accessible from Python
    feature_threshold = 1e-7
    X[:, 0] *= feature_threshold  # almost constant feature
    y = random_state.randint(0, 2, (10,))

    est = tree_cls(random_state=0)
    est.fit(X, y)
    # the almost constant feature should not be used
    assert est.feature_importances_[0] == 0
    # other feature should be used
    assert est.feature_importances_[1] > 0


def test_behaviour_constant_feature_after_splits():
    X = np.transpose(
        np.vstack(([[0, 0, 0, 0, 0, 1, 2, 4, 5, 6, 7]], np.zeros((4, 11))))
    )
    y = [0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3]
    for name, TreeEstimator in ALL_TREES.items():
        # do not check extra random trees
        if "ExtraTree" not in name:
            est = TreeEstimator(random_state=0, max_features=1)
            est.fit(X, y)
            assert est.tree_.max_depth == 2
            assert est.tree_.node_count == 5


def test_with_only_one_non_constant_features():
    X = np.hstack([np.array([[1.0], [1.0], [0.0], [0.0]]), np.zeros((4, 1000))])

    y = np.array([0.0, 1.0, 0.0, 1.0])
    for name, TreeEstimator in CLF_TREES.items():