Download src/train.py from aigovdev/governance-risk-classifier: direct link, hf CLI and curl.
- Browser
- Download file 4.71 kB
-
https://huggingface.co/aigovdev/governance-risk-classifier/resolve/main/src/train.py
- Command line
-
hf download hf://aigovdev/governance-risk-classifier/src/train.py
-
curl -L -o train.py https://huggingface.co/aigovdev/governance-risk-classifier/resolve/main/src/train.py
4.71 kB
| import json | |
| from pathlib import Path | |
| import joblib | |
| import pandas as pd | |
| import sklearn | |
| from datasets import load_dataset | |
| from sklearn.compose import ColumnTransformer | |
| from sklearn.linear_model import LogisticRegression | |
| from sklearn.metrics import ( | |
| accuracy_score, | |
| classification_report, | |
| confusion_matrix, | |
| ) | |
| from sklearn.model_selection import StratifiedKFold, cross_val_predict | |
| from sklearn.pipeline import Pipeline | |
| from sklearn.preprocessing import OneHotEncoder | |
| DATASET_ID = "aigovdev/ai-governance-scenarios" | |
| MODEL_PATH = Path("artifacts/model.joblib") | |
| METRICS_PATH = Path("artifacts/metrics.json") | |
| FEATURES = [ | |
| "sector", | |
| "impact", | |
| "decision_autonomy", | |
| "human_oversight", | |
| "monitoring", | |
| "traceability", | |
| "technical_documentation", | |
| ] | |
| def map_risk(label: str) -> str: | |
| if label in {"low", "limited"}: | |
| return "lower" | |
| if label == "high": | |
| return "high" | |
| if label == "unacceptable": | |
| return "unacceptable" | |
| raise ValueError(f"Unexpected governance_risk label: {label}") | |
| def build_pipeline() -> Pipeline: | |
| preprocessor = ColumnTransformer( | |
| transformers=[ | |
| ( | |
| "categorical", | |
| OneHotEncoder( | |
| handle_unknown="ignore", | |
| ), | |
| FEATURES, | |
| ) | |
| ], | |
| remainder="drop", | |
| ) | |
| classifier = LogisticRegression( | |
| max_iter=2000, | |
| class_weight="balanced", | |
| random_state=42, | |
| ) | |
| return Pipeline( | |
| [ | |
| ("preprocessor", preprocessor), | |
| ("classifier", classifier), | |
| ] | |
| ) | |
| def main(): | |
| MODEL_PATH.parent.mkdir(parents=True, exist_ok=True) | |
| dataset = load_dataset( | |
| DATASET_ID, | |
| split="train", | |
| ) | |
| df = dataset.to_pandas() | |
| df["risk_tier"] = df["governance_risk"].map(map_risk) | |
| X = df[FEATURES].copy() | |
| y = df["risk_tier"].copy() | |
| print("Dataset:", DATASET_ID) | |
| print("Examples:", len(df)) | |
| print() | |
| print("Target distribution:") | |
| print(y.value_counts().sort_index()) | |
| print() | |
| cv = StratifiedKFold( | |
| n_splits=3, | |
| shuffle=True, | |
| random_state=42, | |
| ) | |
| pipeline = build_pipeline() | |
| predictions = cross_val_predict( | |
| pipeline, | |
| X, | |
| y, | |
| cv=cv, | |
| ) | |
| labels = [ | |
| "lower", | |
| "high", | |
| "unacceptable", | |
| ] | |
| accuracy = accuracy_score( | |
| y, | |
| predictions, | |
| ) | |
| report = classification_report( | |
| y, | |
| predictions, | |
| labels=labels, | |
| output_dict=True, | |
| zero_division=0, | |
| ) | |
| matrix = confusion_matrix( | |
| y, | |
| predictions, | |
| labels=labels, | |
| ) | |
| print("Stratified 3-Fold Cross-Validation") | |
| print("=" * 42) | |
| print( | |
| classification_report( | |
| y, | |
| predictions, | |
| labels=labels, | |
| digits=3, | |
| zero_division=0, | |
| ) | |
| ) | |
| print("Confusion matrix") | |
| print("Labels:", labels) | |
| print(matrix) | |
| print() | |
| pipeline.fit( | |
| X, | |
| y, | |
| ) | |
| joblib.dump( | |
| pipeline, | |
| MODEL_PATH, | |
| ) | |
| metrics = { | |
| "dataset": DATASET_ID, | |
| "examples": int(len(df)), | |
| "target_distribution": { | |
| key: int(value) | |
| for key, value in y.value_counts().to_dict().items() | |
| }, | |
| "evaluation": { | |
| "method": "stratified_3_fold_cross_validation", | |
| "accuracy": float(accuracy), | |
| "macro_precision": float( | |
| report["macro avg"]["precision"] | |
| ), | |
| "macro_recall": float( | |
| report["macro avg"]["recall"] | |
| ), | |
| "macro_f1": float( | |
| report["macro avg"]["f1-score"] | |
| ), | |
| "confusion_matrix_labels": labels, | |
| "confusion_matrix": matrix.tolist(), | |
| }, | |
| "features": FEATURES, | |
| "risk_mapping": { | |
| "low": "lower", | |
| "limited": "lower", | |
| "high": "high", | |
| "unacceptable": "unacceptable", | |
| }, | |
| "runtime": { | |
| "scikit_learn": sklearn.__version__, | |
| }, | |
| "limitations": [ | |
| "Dataset contains only 12 synthetic scenarios.", | |
| "Evaluation is illustrative and not a production benchmark.", | |
| "Risk tiers are engineering labels, not legal classifications.", | |
| ], | |
| } | |
| METRICS_PATH.write_text( | |
| json.dumps( | |
| metrics, | |
| indent=2, | |
| ), | |
| encoding="utf-8", | |
| ) | |
| print("Saved model:", MODEL_PATH.resolve()) | |
| print("Saved metrics:", METRICS_PATH.resolve()) | |
| if __name__ == "__main__": | |
| main() | |