• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

adaptive-machine-learning / CapyMOA / 24161643270

08 Apr 2026 10:19PM UTC coverage: 74.52% (-0.2%) from 74.706%
24161643270

Pull #340

github

web-flow
Merge d52d63a47 into f7f8dd433
Pull Request #340: feat: add feature importance classifier

119 of 182 new or added lines in 4 files covered. (65.38%)

6797 of 9121 relevant lines covered (74.52%)

0.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

14.29
/src/capymoa/feature_selection/visualization.py
1
from __future__ import annotations
1✔
2

3
from typing import Sequence
1✔
4

5
import matplotlib.pyplot as plt
1✔
6
import pandas as pd
1✔
7

8

9
def _normalize_feature_names(
1✔
10
    feature_names: Sequence[str] | str | None, n_features: int
11
) -> list[str]:
NEW
12
    if feature_names is None:
×
NEW
13
        return [f"f{i}" for i in range(n_features)]
×
NEW
14
    if isinstance(feature_names, str):
×
NEW
15
        names = [feature_names]
×
16
    else:
NEW
17
        names = [str(name) for name in feature_names]
×
18

NEW
19
    if len(names) != n_features:
×
NEW
20
        raise ValueError(
×
21
            f"feature_names length ({len(names)}) does not match importances length ({n_features})."
22
        )
NEW
23
    return names
×
24

25

26
def plot_feature_importance(
1✔
27
    importances: Sequence[float],
28
    feature_names: Sequence[str] | str | None = None,
29
    *,
30
    top_k: int | None = None,
31
    ax=None,
32
    title: str = "Feature importances",
33
):
34
    """Plot feature importances as a bar chart."""
NEW
35
    values = list(importances)
×
NEW
36
    names = _normalize_feature_names(feature_names, len(values))
×
37

NEW
38
    series = pd.Series(values, index=names, name="importance").sort_values(
×
39
        ascending=False
40
    )
NEW
41
    if top_k is not None:
×
NEW
42
        if top_k <= 0:
×
NEW
43
            raise ValueError("top_k must be greater than zero.")
×
NEW
44
        series = series.head(top_k)
×
45

NEW
46
    if ax is None:
×
NEW
47
        _, ax = plt.subplots(figsize=(10, 4))
×
48

NEW
49
    series.plot(kind="bar", ax=ax)
×
NEW
50
    ax.set_title(title)
×
NEW
51
    ax.set_xlabel("Feature")
×
NEW
52
    ax.set_ylabel("Importance")
×
NEW
53
    ax.figure.tight_layout()
×
NEW
54
    return ax
×
55

56

57
def plot_windowed_feature_importance(
1✔
58
    windowed_importances: list[dict],
59
    feature_names: Sequence[str] | str | None = None,
60
    *,
61
    top_k: int | None = None,
62
    ax=None,
63
    title: str = "Windowed feature importances",
64
):
65
    """Plot windowed feature importances over time."""
NEW
66
    if len(windowed_importances) == 0:
×
NEW
67
        raise ValueError("windowed_importances is empty.")
×
NEW
68
    if top_k is not None and top_k <= 0:
×
NEW
69
        raise ValueError("top_k must be greater than zero.")
×
70

NEW
71
    n_features = len(windowed_importances[0]["importances"])
×
NEW
72
    names = _normalize_feature_names(feature_names, n_features)
×
73

NEW
74
    window_df = pd.DataFrame(
×
75
        [entry["importances"] for entry in windowed_importances],
76
        columns=names,
77
    )
NEW
78
    window_df["instances_seen"] = [
×
79
        entry["instances_seen"] for entry in windowed_importances
80
    ]
81

NEW
82
    if top_k is None:
×
NEW
83
        top_features = names
×
84
    else:
NEW
85
        top_features = (
×
86
            window_df[names]
87
            .mean()
88
            .sort_values(ascending=False)
89
            .head(top_k)
90
            .index.tolist()
91
        )
92

NEW
93
    if ax is None:
×
NEW
94
        _, ax = plt.subplots(figsize=(10, 4))
×
95

NEW
96
    window_df.plot(x="instances_seen", y=top_features, ax=ax)
×
NEW
97
    ax.set_title(title)
×
NEW
98
    ax.set_xlabel("Instances seen")
×
NEW
99
    ax.set_ylabel("Importance")
×
NEW
100
    ax.figure.tight_layout()
×
NEW
101
    return ax
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc