Instructions to use hoodsy/sn-triage with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Scikit-learn
How to use hoodsy/sn-triage with Scikit-learn:
from huggingface_hub import hf_hub_download import joblib model = joblib.load( hf_hub_download("hoodsy/sn-triage", "sklearn_model.joblib") ) # only load pickle files from sources you trust # read more about it here https://skops.readthedocs.io/en/stable/persistence.html - Notebooks
- Google Colab
- Kaggle
sn-triage
A daily fault-triage classifier for solar PV plants: given a 24-number shape summary of one plant-day (performance index vs baseline, clear-sky ratios, plateau/dead runs, temperature tracking, snow trail, seasonality), it labels the day as one of nine classes:
healthy, outage, weather, snow, snow_shedding,
cloud_intermittent, clipping, curtailment, thermal.
The model is a scikit-learn HistGradientBoostingClassifier distilled
from a rules-plus-referee pipeline over 32 public PVDAQ systems and one
SolarNetwork node. It was built to generalize to plants it has never
seen: every feature is a ratio or a fraction of plant capacity, and
missing values (no temperature sensor, short history, no weather feed)
are tolerated as NaN. It runs day-level, per site, on a single meter
stream β sub-metering is not required at inference time.
Usage
model.joblib is a self-describing bundle (a plain dict), pickled with
joblib under scikit-learn 1.9.0 / Python 3.11:
import joblib
bundle = joblib.load("model.joblib")
model = bundle["model"] # HistGradientBoostingClassifier
features = bundle["features"] # ordered list of 24 column names
classes = bundle["classes"] # the 9 labels
# bundle["trained_at"] = "2026-08-01T03:44:37+00:00"
# bundle["version"] = "20260801T034437Z"
X = day_frame[features] # one row per day; NaN allowed
labels = model.predict(X)
proba = model.predict_proba(X)
Feature definitions and the training data are in the companion dataset:
hoodsy/sn-triage-dataset.
The 24 features, in bundle order: pi_rel, csr, model_csr, chop,
plateau_run_h, peak_frac, expected_peak_frac, dead_run_h,
morning_ratio, midday_ratio, tmax_c, temp_corr, snow_3d,
snow_7d, snow_30d, pi_slope_14d, pi_drop_share, unit_count,
unit_dist, doy_sin, doy_cos, pi, coverage, rain_mm.
This is a joblib pickle β load it only from this repository or another source you trust.
Training
- 67,987 trainable site-days (nine classes;
data_gapandunclassifieddays excluded) across 33 sites, of which 6,141 are gold: days graded against per-inverter data by a fleet-relative referee. Sample weights = class balance Γ 5 for gold. - Labels come from an evidence-backed rule classifier, overruled by the referee where sub-metering proved it wrong. The published dataset holds 67,782 of these 67,987 trainable rows: the difference is exactly the 205 trainable days of the one non-PVDAQ training site (a SolarNetwork node excluded from the dataset for licensing reasons).
Evaluation
Faults are multi-day events; all protocols split by event or by site, never by row.
- Leave-one-site-out macro-F1 0.92 (headline): train on 32 sites, score the held-out site, rotate. All classes β₯ 0.86 except curtailment (0.69).
- Event-holdout macro-F1 0.959.
- On the 1,552 days where the referee overruled the rules, this model β never trained on the site being scored β sides with the referee 77% of the time and with the overruled rule label 0%.
- True held-out-site test: two Santa Ana, CA systems (PVDAQ 14695/14697) were onboarded after training and scored against the frozen model: 98.4% day-level agreement over 1,710 labeled days, 88.5% on the 208 referee-graded days, zero false alarms across 1,383 healthy days. Both sites were folded into training afterward, and this published model is the retrain; the numbers above describe its frozen predecessor on data that model had never seen.
Edge deployment
This exact bundle (20260801T034437Z) also runs at the edge as a
SolarQuant plugin (Ecosuite's spec: a container on the plant's
SolarNode ingests live datums, closes each local day, computes the same
24 features β Open-Meteo weather when available, clear-sky fallback β
and posts a daily fault-class datum). Replaying a 7-month window of the
SolarNetwork training node through the containerized plugin at
production streaming cadence reproduced the batch pipeline's final
labels on 92.4% of 211 days, including 88/88 outage days (a real
77-day outage) and 44/44 weather days. The residual is the plugin's
online trailing-median baseline vs the batch two-pass baseline on
marginal healthy/weather days, plus days the batch left unclassified
(a label this model deliberately does not have β it predicts over them).
Limitations
- Curtailment is the hard class (F1 0.69). Its residual confusion is asymmetric partial outage (one inverter of two down) vs curtailment β from a single meter stream both look like a bright, smooth, scaled-down day. Separating them reliably requires sub-metering.
- Trained on fixed-tilt systems only; tracker plants are out of scope.
- Day-level granularity: it labels days, not intervals, and won't catch sub-daily transients.
- Weather features assume Open-Meteo/ERA5-like inputs where used; they are NaN-tolerant but the model performs best with them present.
Attribution
Trained on data derived from NREL's PVDAQ public datasets (DOE Open Energy Data Initiative, CC BY 4.0):
Deline, C., Perry, K., Deceglie, M., Muller, M., Sekulic, W., & Jordan, D. (2021). Photovoltaic Data Acquisition (PVDAQ) Public Datasets [Data set]. Open Energy Data Initiative (OEDI). NREL. https://doi.org/10.25984/1846021
Weather data by Open-Meteo.com (CC BY 4.0); contains modified Copernicus Climate Change Service information (ERA5). One additional training site (a residential Auckland node) comes from the SolarNetwork public API.
- Downloads last month
- -
Dataset used to train hoodsy/sn-triage
Evaluation results
- leave-one-site-out macro-F1 on PVDAQ daily solar fault triage (leave-one-site-out)self-reported0.920