ML model assessment covering classification metrics (precision, recall, F1, AUC-ROC), regression metrics (MAE, RMSE, R2), confusion matrix analysis, cross-validation strategies, bias detection, fairness metrics, and A/B testing for models. Use when the user asks about model evaluator, model evaluator best practices, or needs guidance on model evaluator implementation. Do NOT use when the user needs a different specialized skill or is asking about an unrelated technology domain.
Scanned 9/2/2026
Install to Claude Code
npx -y skills add FerroxLabs/wayland --skill model-evaluator --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Model Evaluator?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/ferroxlabs-model-evaluator)More formats (shields.io, HTML) on the badges page.
---
name: model-evaluator
description: |
ML model assessment covering classification metrics (precision, recall, F1, AUC-ROC), regression metrics (MAE, RMSE, R2), confusion matrix analysis, cross-validation strategies, bias detection, fairness metrics, and A/B testing for models.
Use when the user asks about model evaluator, model evaluator best practices, or needs guidance on model evaluator implementation.
Do NOT use when the user needs a different specialized skill or is asking about an unrelated technology domain.
license: Apache-2.0
metadata:
author: foundry-skills
version: "1.0.0"
tags: "ai-ml testing guide"
category: "ai-machine-learning"
subcategory: "ml-fundamentals"
depends: ""
disclaimer: "none"
difficulty: "intermediate"
---
# Model Evaluator
## Overview
Rigorous model assessment is essential to deploying trustworthy ML systems. This skill covers comprehensive metrics for classification and regression, strategies for cross-validation, statistical testing, bias and fairness auditing, and A/B testing frameworks for comparing models in production.
## Classification Metrics
### Core Metrics
```python
from sklearn.metrics import (
accuracy_score, precision_score, recall_score, f1_score,
roc_auc_score, average_precision_score, classification_report,
confusion_matrix,
)
import numpy as np
def classification_report_full(y_true, y_pred, y_prob=None) -> dict:
"""Comprehensive classification metrics."""
metrics = {
"accuracy": accuracy_score(y_true, y_pred),
"precision_macro": precision_score(y_true, y_pred, average="macro"),
"recall_macro": recall_score(y_true, y_pred, average="macro"),
"f1_macro": f1_score(y_true, y_pred, average="macro"),
# ... (condensed) ...
metrics["auc_roc_ovr"] = roc_auc_score(
y_true, y_prob, multi_class="ovr", average="macro"
)
return metrics
```
### Metric Selection Guide
| Metric | When to Use | Sensitive To |
|--------|-------------|-------------|
| Accuracy | Balanced classes only | Class imbalance |
| Precision | Cost of false positives is high | Threshold selection |
| Recall | Cost of false negatives is high | Threshold selection |
| F1 Score | Balance precision and recall | Threshold selection |
| AUC-ROC | Overall ranking ability | Not threshold-dependent |
| Average Precision | Imbalanced classes, ranking | Class distribution |
| Cohen's Kappa | Agreement beyond chance | None |
### Decision Framework
```
Is your dataset balanced (classes within 2x of each other)?
YES -> Accuracy is meaningful, but also report F1
NO -> DO NOT rely on accuracy. Use these instead:
- F1 (balanced view)
- Average Precision (best for heavy imbalance)
- AUC-ROC (threshold-independent ranking)
What is more costly?
False positives (spam filter, fraud alert):
-> Optimize for PRECISION
False negatives (cancer screening, security):
-> Optimize for RECALL
Both equally bad:
-> Optimize for F1 score
```
## Confusion Matrix Analysis
### Visualization and Interpretation
```python
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
def plot_confusion_matrix(
y_true, y_pred,
class_names: list[str] = None,
normalize: str = None,
figsize: tuple = (8, 6),
) -> plt.Figure:
"""Plot confusion matrix with detailed annotations."""
cm = confusion_matrix(y_true, y_pred, normalize=normalize)
fig, ax = plt.subplots(figsize=figsize)
# ... (condensed) ...
})
confused_with.sort(key=lambda x: x["count"], reverse=True)
analysis[cls]["most_confused_with"] = confused_with[:3]
return analysis
```
### ROC and Precision-Recall Curves
```python
from sklearn.metrics import roc_curve, precision_recall_curve, auc
def plot_roc_pr_curves(y_true, y_prob, figsize=(14, 5)):
"""Plot ROC and Precision-Recall curves side by side."""
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=figsize)
# ROC Curve
fpr, tpr, roc_thresholds = roc_curve(y_true, y_prob)
roc_auc = auc(fpr, tpr)
ax1.plot(fpr, tpr, label=f"AUC = {roc_auc:.3f}")
ax1.plot([0, 1], [0, 1], "k--", alpha=0.3)
ax1.set_xlabel("False Positive Rate")
ax1.set_ylabel("True Positive Rate")
ax1.set_title("ROC Curve")
# ... (condensed) ...
ax2.set_title("Precision-Recall Curve")
ax2.legend()
plt.tight_layout()
return fig
```
### Threshold Optimization
```python
from sklearn.metrics import balanced_accuracy_score
def find_optimal_threshold(
y_true, y_prob,
metric: str = "f1",
) -> tuple[float, float]:
"""Find the threshold that maximizes a given metric."""
thresholds = np.arange(0.1, 0.95, 0.01)
best_threshold = 0.5
best_score = 0
for threshold in thresholds:
y_pred = (y_prob >= threshold).astype(int)
# ... (condensed) ...
if score > best_score:
best_score = score
best_threshold = threshold
return best_threshold, best_score
```
## Regression Metrics
### Core Regression Metrics
```python
from sklearn.metrics import (
mean_absolute_error, mean_squared_error, r2_score,
mean_absolute_percentage_error, median_absolute_error,
)
def regression_report(y_true, y_pred) -> dict:
"""Comprehensive regression metrics."""
return {
"mae": mean_absolute_error(y_true, y_pred),
"rmse": np.sqrt(mean_squared_error(y_true, y_pred)),
"mse": mean_squared_error(y_true, y_pred),
"r2": r2_score(y_true, y_pred),
"mape": mean_absolute_percentage_error(y_true, y_pred),
"median_ae": median_absolute_error(y_true, y_pred),
"max_error": float(np.max(np.abs(y_true - y_pred))),
}
```
### Metric Interpretation
| Metric | Range | Interpretation |
|--------|-------|---------------|
| MAE | [0, inf) | Average absolute error in original units |
| RMSE | [0, inf) | Penalizes large errors more than MAE |
| R2 | (-inf, 1] | 1 = perfect; 0 = predicts mean; <0 = worse than mean |
| MAPE | [0, inf) | Percentage error (avoid when y has zeros) |
| Median AE | [0, inf) | Robust to outliers |
### Residual Analysis
```python
from scipy import stats as sp_stats
def plot_residual_analysis(y_true, y_pred, figsize=(14, 10)):
"""Comprehensive residual analysis plots."""
residuals = y_true - y_pred
fig, axes = plt.subplots(2, 2, figsize=figsize)
# Predicted vs Actual
axes[0, 0].scatter(y_pred, y_true, alpha=0.5, s=10)
min_val, max_val = min(y_true.min(), y_pred.min()), max(y_true.max(), y_pred.max())
axes[0, 0].plot([min_val, max_val], [min_val, max_val], "r--")
axes[0, 0].set_xlabel("Predicted")
axes[0, 0].set_ylabel("Actual")
# ... (condensed) ...
sp_stats.probplot(residuals, dist="norm", plot=axes[1, 1])
axes[1, 1].set_title("QQ Plot")
plt.tight_layout()
return fig
```
## Cross-Validation Strategies
### Choosing the Right Strategy
```python
from sklearn.model_selection import (
KFold, StratifiedKFold, TimeSeriesSplit,
GroupKFold, RepeatedStratifiedKFold,
cross_val_score,
)
def get_cv_strategy(
task_type: str,
data_type: str = "standard",
n_splits: int = 5,
groups=None,
):
"""Select appropriate cross-validation strategy."""
# ... (condensed) ...
if task_type == "classification":
return StratifiedKFold(n_splits=n_splits, shuffle=True, random_state=42)
return KFold(n_splits=n_splits, shuffle=True, random_state=42)
```
### Cross-Validation with Confidence Intervals
```python
def cv_with_confidence(model, X, y, cv=5, scoring="f1") -> dict:
"""Cross-validation with confidence interval."""
scores = cross_val_score(model, X, y, cv=cv, scoring=scoring)
mean = scores.mean()
std = scores.std()
n = len(scores)
se = std / np.sqrt(n)
# 95% confidence interval
ci_low = mean - 1.96 * se
ci_high = mean + 1.96 * se
return {
"mean": mean,
"std": std,
"scores": scores.tolist(),
"ci_95": (ci_low, ci_high),
"n_folds": n,
}
```
## Statistical Model Comparison
### Paired t-Test for Model Comparison
```python
from scipy import stats
def compare_models_statistical(
model_a_scores: list[float],
model_b_scores: list[float],
alpha: float = 0.05,
) -> dict:
"""Statistical comparison of two models using paired t-test."""
t_stat, p_value = stats.ttest_rel(model_a_scores, model_b_scores)
mean_diff = np.mean(model_a_scores) - np.mean(model_b_scores)
return {
"model_a_mean": np.mean(model_a_scores),
"model_b_mean": np.mean(model_b_scores),
"mean_difference": mean_diff,
"t_statistic": t_stat,
"p_value": p_value,
"significant": p_value < alpha,
"better_model": "A" if mean_diff > 0 else "B",
}
```
### McNemar's Test (for Classification)
```python
def mcnemar_test(y_true, y_pred_a, y_pred_b) -> dict:
"""McNemar's test: are two classifiers significantly different?"""
from statsmodels.stats.contingency_tables import mcnemar as mcnemar_fn
correct_a = (y_pred_a == y_true)
correct_b = (y_pred_b == y_true)
n01 = ((~correct_a) & correct_b).sum() # A wrong, B right
n10 = (correct_a & (~correct_b)).sum() # A right, B wrong
table = [[0, n01], [n10, 0]]
result = mcnemar_fn(table, exact=True)
return {
"a_right_b_wrong": int(n10),
"a_wrong_b_right": int(n01),
"p_value": result.pvalue,
"significant": result.pvalue < 0.05,
}
```
## Bias and Fairness Assessment
### Fairness Metrics
```python
def compute_fairness_metrics(
y_true: np.ndarray,
y_pred: np.ndarray,
sensitive_attr: np.ndarray,
privileged_value=1,
unprivileged_value=0,
) -> dict:
"""Compute fairness metrics across a sensitive attribute."""
priv_mask = sensitive_attr == privileged_value
unpriv_mask = sensitive_attr == unprivileged_value
# Demographic parity
rate_priv = y_pred[priv_mask].mean()
# ... (condensed) ...
"tpr_privileged": round(tpr_priv, 4),
"tpr_unprivileged": round(tpr_unpriv, 4),
"fpr_privileged": round(fpr_priv, 4),
"fpr_unprivileged": round(fpr_unpriv, 4),
}
```
### Fairness Metric Definitions
| Metric | Definition | Fair When |
|--------|-----------|-----------|
| Demographic Parity | Selection rate ratio across groups | Ratio between 0.8-1.25 |
| Equal Opportunity | True positive rate ratio | Ratio between 0.8-1.25 |
| Equalized Odds | TPR and FPR equal across groups | Both ratios near 1.0 |
| Predictive Parity | Positive predictive value equal | Ratio between 0.8-1.25 |
| Calibration | P(Y=1 given score=s) same across groups | Calibration curves overlap |
### Subgroup Analysis
```python
import pandas as pd
def subgroup_performance(
y_true, y_pred, y_prob,
group_column: np.ndarray,
group_names: dict,
) -> pd.DataFrame:
"""Compute performance metrics per subgroup."""
results = []
for group_val, group_name in group_names.items():
mask = group_column == group_val
if mask.sum() < 10:
continue
# ... (condensed) ...
metrics["auc_roc"] = float(roc_auc_score(y_true[mask], prob))
results.append(metrics)
return pd.DataFrame(results)
```
## A/B Testing for Models
### Online A/B Test Framework
```python
import hashlib
from dataclasses import dataclass, field
from scipy import stats
@dataclass
class ModelABTest:
"""A/B test framework for comparing models in production."""
name: str
model_a_name: str
model_b_name: str
traffic_split: float = 0.5
results_a: list = field(default_factory=list)
results_b: list = field(default_factory=list)
# ... (condensed) ...
"effect_size": "small" if abs(cohens_d) < 0.5 else "medium" if abs(cohens_d) < 0.8 else "large",
"recommendation": "B" if p_value < 0.05 and mean_b > mean_a else "A" if p_value < 0.05 else "continue_testing",
"samples_a": len(self.results_a),
"samples_b": len(self.results_b),
}
```
### Sample Size Planning
```python
from scipy.stats import norm
def required_sample_size(
baseline_metric: float,
minimum_detectable_effect: float,
alpha: float = 0.05,
power: float = 0.8,
metric_std: float = None,
) -> int:
"""Calculate required sample size per group for A/B test."""
if metric_std is None:
metric_std = np.sqrt(baseline_metric * (1 - baseline_metric))
z_alpha = norm.ppf(1 - alpha / 2)
z_beta = norm.ppf(power)
n = (2 * metric_std**2 * (z_alpha + z_beta)**2) / minimum_detectable_effect**2
return int(np.ceil(n))
```
## Comprehensive Scoring Report
```python
def generate_scoring_report(
model_name: str,
y_true, y_pred, y_prob=None,
sensitive_attrs: dict = None,
) -> dict:
"""Generate comprehensive scoring report."""
report = {
"model": model_name,
"dataset_size": len(y_true),
"class_distribution": {int(k): int(v) for k, v in zip(*np.unique(y_true, return_counts=True))},
}
report["metrics"] = classification_report_full(y_true, y_pred, y_prob)
# ... (condensed) ...
report["fairness"][attr_name] = compute_fairness_metrics(
y_true, y_pred, attr_values
)
return report
```
## Checklist
- [ ] Select metrics appropriate to the task and class distribution
- [ ] Report multiple metrics (never rely on accuracy alone)
- [ ] Analyze the confusion matrix for systematic error patterns
- [ ] Optimize the classification threshold if using probabilities
- [ ] Use proper cross-validation (stratified for classification, temporal for time series)
- [ ] Compute confidence intervals on performance estimates
- [ ] Perform statistical tests when comparing models
- [ ] Audit for bias across sensitive attributes (gender, race, age)
- [ ] Check fairness metrics (demographic parity, equal opportunity)
- [ ] Plan A/B tests with proper sample size calculations
- [ ] Document all metrics, thresholds, and decisions in a scoring report
## When to Use
**Use this skill when:**
- Designing or implementing model evaluator solutions
- Reviewing or improving existing model evaluator approaches
- Making architectural or implementation decisions about model evaluator
- Learning model evaluator patterns and best practices
- Troubleshooting model evaluator-related issues
**Do NOT use this skill when:**
- The question is about a fundamentally different technology domain
- A more specific sibling skill covers the exact topic needed
- The user needs a complete hands-on tutorial rather than expert guidance
## Output Format
```markdown
# Model Evaluator Analysis
## Context Assessment
[Situation summary and constraints]
## Recommended Approach
[Primary recommendation with rationale]
## Implementation Steps
1. [Step with specific details]
2. [Step with specific details]
3. [Step with specific details]
## Trade-offs and Considerations
- [Key trade-off 1]
- [Key trade-off 2]
## Next Steps
- [Immediate action item]
- [Follow-up action item]
```
## Example
**Input:** "Help me implement model evaluator for a medium-scale production application"
**Output:** A structured analysis covering current state assessment, recommended model evaluator approach with specific patterns, implementation roadmap with milestones, and risk mitigation strategies tailored to the application scale and constraints.
## Edge Cases
- **Legacy system integration:** When model evaluator must coexist with legacy approaches, provide a gradual migration path rather than a complete rewrite
- **Scale mismatch:** When the solution complexity exceeds the project scale, recommend a simpler approach and note when to revisit
- **Team skill gaps:** When the team lacks experience with the recommended approach, include learning resources and simpler alternatives
- **Conflicting requirements:** When constraints conflict (e.g., performance vs. maintainability), explicitly state the trade-off and recommend based on stated priorities
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!