Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Data science across machine learning, statistical modeling, and experimentation. Use when selecting ML algorithms, engineering features, designing A/B tests, evaluating model performance, or building predictive pipelines.
.claude/skills/borghei-data-scientist/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 181% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 116% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 148% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 63% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 284% | 0% |
The agent operates as a senior data scientist, selecting algorithms, engineering features, designing experiments, evaluating models, and translating predictions into business impact.
Before modeling, confirm these inputs. If any is unknown or vague, ASK — do not assume:
Stop rule: ask only the 2-3 that most change the output. If the user says "just draft it," proceed and list your assumptions at the top of the artifact.
| Scenario | Recommended | When to upgrade | |----------|------------|-----------------| | Need interpretability | Logistic / Linear Regression | Always start here for stakeholder-facing models | | Small data (< 10K rows) | Random Forest | Move to XGBoost if accuracy insufficient | | Medium data, high accuracy needed | XGBoost / LightGBM | Default workhorse for tabular data | | Large data, complex patterns | Neural Network | Only when tree methods plateau | | Unsupervised grouping | K-Means / DBSCAN | Use silhouette score to validate k |
Numerical transforms:
pythonimport numpy as np, pandas as pd def engineer_numerical(df: pd.DataFrame, col: str) -> pd.DataFrame: return pd.DataFrame({ f'{col}_log': np.log1p(df[col]), f'{col}_sqrt': np.sqrt(df[col].clip(lower=0)), f'{col}_squared': df[col] ** 2, f'{col}_binned': pd.cut(df[col], bins=5, labels=False), })
Time-based features with cyclical encoding:
pythondef engineer_time(df: pd.DataFrame, col: str) -> pd.DataFrame: dt = pd.to_datetime(df[col]) return pd.DataFrame({ f'{col}_hour': dt.dt.hour, f'{col}_dayofweek': dt.dt.dayofweek, f'{col}_month': dt.dt.month, f'{col}_is_weekend': dt.dt.dayofweek.isin([5, 6]).astype(int), f'{col}_hour_sin': np.sin(2 * np.pi * dt.dt.hour / 24), f'{col}_hour_cos': np.cos(2 * np.pi * dt.dt.hour / 24), })
Feature selection (importance-based):
pythonfrom sklearn.ensemble import RandomForestClassifier def select_top_features(X, y, n=20): rf = RandomForestClassifier(n_estimators=100, random_state=42) rf.fit(X, y) importance = pd.Series(rf.feature_importances_, index=X.columns) return importance.nlargest(n).index.tolist()
Classification:
pythonfrom sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score def evaluate_classifier(y_true, y_pred, y_proba=None) -> dict: m = { "accuracy": accuracy_score(y_true, y_pred), "precision": precision_score(y_true, y_pred), "recall": recall_score(y_true, y_pred), "f1": f1_score(y_true, y_pred), } if y_proba is not None: m["auc_roc"] = roc_auc_score(y_true, y_proba) return m
Regression:
pythonfrom sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score import numpy as np def evaluate_regressor(y_true, y_pred) -> dict: return { "mae": mean_absolute_error(y_true, y_pred), "rmse": np.sqrt(mean_squared_error(y_true, y_pred)), "r2": r2_score(y_true, y_pred), }
Sample size calculation:
pythonfrom scipy import stats import numpy as np def required_sample_size(baseline_rate: float, mde: float, alpha: float = 0.05, power: float = 0.8) -> int: """Return required N per variant. mde is relative (e.g., 0.10 = 10% lift).""" effect = baseline_rate * mde z_a = stats.norm.ppf(1 - alpha / 2) z_b = stats.norm.ppf(power) p = baseline_rate return int(np.ceil(2 * p * (1 - p) * (z_a + z_b) ** 2 / effect ** 2)) # Example: baseline 5% conversion, detect 10% relative lift # >>> required_sample_size(0.05, 0.10) -> ~62,214 per variant
Result analysis:
pythondef analyze_ab(control: np.ndarray, treatment: np.ndarray, alpha: float = 0.05) -> dict: """Analyze A/B test with proportions z-test.""" n_c, n_t = len(control), len(treatment) p_c, p_t = control.mean(), treatment.mean() p_pool = (control.sum() + treatment.sum()) / (n_c + n_t) se = np.sqrt(p_pool * (1 - p_pool) * (1/n_c + 1/n_t)) z = (p_t - p_c) / se p_val = 2 * (1 - stats.norm.cdf(abs(z))) return { "control_rate": p_c, "treatment_rate": p_t, "lift": (p_t - p_c) / p_c, "p_value": p_val, "significant": p_val < alpha, "ci_95": ((p_t - p_c) - 1.96 * se, (p_t - p_c) + 1.96 * se), }
markdown# Data Science Project: [Name] ## Business Objective -- What problem are we solving? ## Success Metrics -- Primary: [metric]; Secondary: [metric] ## Data -- Sources, size (rows/features), time period ## Methodology -- Numbered steps ## Results | Metric | Baseline | Model | Improvement | |--------|----------|-------|-------------| ## Business Impact -- [Quantified impact] ## Recommendations -- [Next actions] ## Limitations -- [Known caveats]
references/ml_algorithms.md -- Algorithm deep divesreferences/feature_engineering.md -- Feature engineering patternsreferences/experimentation.md -- A/B testing guidereferences/statistics.md -- Statistical methodsbashpython scripts/experiment_tracker.py log --name "xgb_v2" --params '{"lr":0.1,"depth":6}' --metrics '{"f1":0.87,"auc":0.92}' python scripts/experiment_tracker.py list --sort-by f1 --top 5 python scripts/experiment_tracker.py compare --ids 1 3 5 --json python scripts/hypothesis_tester.py ttest --file data.csv --col-a group_a --col-b group_b python scripts/hypothesis_tester.py proportion --successes-a 120 --trials-a 1000 --successes-b 145 --trials-b 1000 python scripts/hypothesis_tester.py chi-square --file contingency.csv --json python scripts/feature_selector.py --file dataset.csv --target churn --top 10 python scripts/feature_selector.py --file dataset.csv --target revenue --method correlation --json
| Tool | Purpose | Key Flags | |------|---------|-----------| | experiment_tracker.py | Log, list, and compare experiments with parameters, metrics, and tags in a local JSON file | log --name --params --metrics --tags, list --sort-by --top, compare --ids, --json | | hypothesis_tester.py | Run statistical tests: Welch's t-test, paired t-test, proportion z-test, chi-square independence | ttest --file --col-a --col-b [--paired], proportion --successes-a --trials-a ..., chi-square --file, --json | | feature_selector.py | Rank features by composite score (variance, correlation, mutual information, null rate) for a target column | --file <csv>, --target <col>, --top <n>, --method all/correlation/mutual_info, --json |
| Problem | Likely Cause | Resolution | |---------|-------------|------------| | Model overfits (large train-test gap in metrics) | Too many features, insufficient regularization, or data leakage | Reduce feature count with feature_selector.py, add regularization, and audit feature engineering for temporal leakage | | A/B test shows significant result but tiny effect size | Large sample size makes small differences statistically significant | Always report effect size (Cohen's d) alongside p-value; use practical significance thresholds | | hypothesis_tester.py p-value differs from scipy | The tool uses normal/t-distribution approximations (standard library only) | For publication-grade analysis, validate with scipy.stats; the tool is designed for fast directional estimates | | Feature importance scores are near-zero for all features | Target variable has extremely low variance or the feature set lacks predictive signal | Check target distribution; consider feature engineering or collecting additional data sources | | experiment_tracker.py shows experiment IDs out of order | Experiments were logged non-sequentially or the log file was manually edited | IDs are auto-incremented; use --sort-by on a metric for meaningful ordering | | Chi-square test fails with "table must be at least 2x2" | CSV contingency table has fewer than 2 rows or 2 columns of numeric data | Ensure the CSV has a header row and at least 2x2 numeric cells; verify the format matches expectations | | Class imbalance causes misleading accuracy | Accuracy inflated by majority class predictions | Use F1, precision-recall, or AUC-ROC instead; apply SMOTE or class weights during training |
feature_selector.py output is saved with the experiment record.experiment_tracker.py including parameters, metrics, and a descriptive name.In scope: Machine learning algorithm selection, feature engineering, model training and evaluation, A/B test design and analysis, statistical hypothesis testing, experiment tracking, and communicating results to stakeholders.
Out of scope: Model deployment to production (see ml-ops-engineer), data pipeline infrastructure, dashboard development, and real-time serving architecture.
Limitations: The Python tools use only the Python standard library. hypothesis_tester.py uses normal and t-distribution approximations that are accurate for moderate sample sizes but should be validated with scipy for edge cases (very small n, extreme skew). feature_selector.py computes approximate mutual information using binned discretization -- for high-precision feature selection, use sklearn's mutual_info_classif or permutation importance. All tools process local files and do not integrate with MLflow, W&B, or other tracking platforms.
data-analytics/ml-ops-engineer): Trained models are handed off for production deployment, monitoring, and registry management.data-analytics/data-analyst): Complex analytical questions requiring predictive modeling are escalated from the analyst to the data scientist.data-analytics/analytics-engineer): Feature engineering pipelines may depend on mart models as upstream data sources.product-team/): Experiment results inform product decisions; A/B test designs are co-created with product managers.engineering/senior-ml-engineer): Algorithm implementation details and model architecture decisions bridge data science and ML engineering.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 25,487 | 19,435 | -24% | 1 | 1 | 0% | 4,405 | 6,921 | +57% | 0 | 0 | — |
case-02 | fail→pass | 16,367 | 25,450 | +55% | 1 | 1 | 0% | 2,845 | 7,983 | +181% | 0 | 0 | — |
case-03 | fail→pass | 16,239 | 15,249 | -6% | 1 | 1 | 0% | 2,941 | 6,362 | +116% | 0 | 0 | — |
case-04 | pass→pass | 15,446 | 12,964 | -16% | 1 | 1 | 0% | 2,406 | 5,594 | +133% | 0 | 0 | — |
case-05 | fail→fail | 11,121 | 10,466 | -6% | 1 | 1 | 0% | 1,800 | 5,100 | +183% | 0 | 0 | — |
case-06 | pass→pass | 11,994 | 10,555 | -12% | 1 | 1 | 0% | 2,175 | 5,250 | +141% | 0 | 0 | — |
case-07 | pass→fail | 14,207 | 14,516 | +2% | 1 | 1 | 0% | 3,127 | 6,363 | +103% | 0 | 0 | — |
case-08 | fail→pass | 9,532 | 3,230 | -66% | 1 | 1 | 0% | 1,625 | 4,025 | +148% | 0 | 0 | — |
case-09 | fail→pass | 14,618 | 3,345 | -77% | 1 | 1 | 0% | 2,479 | 4,053 | +63% | 0 | 0 | — |
case-10 | fail→pass | 6,081 | 3,308 | -46% | 1 | 1 | 0% | 1,045 | 4,018 | +284% | 0 | 0 | — |
case-11 | fail→pass | 6,170 | 2,925 | -53% | 1 | 1 | 0% | 1,035 | 3,934 | +280% | 0 | 0 | — |
case-12 | fail→pass | 15,128 | 13,499 | -11% | 1 | 1 | 0% | 2,489 | 5,732 | +130% | 0 | 0 | — |
case-13 | fail→pass | 27,601 | 10,076 | -63% | 1 | 1 | 0% | 1,371 | 5,146 | +275% | 0 | 0 | — |
case-14 | pass→pass | 12,497 | 12,586 | +1% | 1 | 1 | 0% | 2,045 | 5,426 | +165% | 0 | 0 | — |
case-15 | pass→pass | 14,272 | 17,039 | +19% | 1 | 1 | 0% | 2,201 | 6,515 | +196% | 0 | 0 | — |
case-16 | pass→pass | 13,765 | 13,279 | -4% | 1 | 1 | 0% | 2,294 | 5,834 | +154% | 0 | 0 | — |
case-17 | pass→pass | 12,091 | 10,047 | -17% | 1 | 1 | 0% | 1,930 | 5,084 | +163% | 0 | 0 | — |
case-18 | pass→fail | 17,363 | 17,579 | +1% | 1 | 1 | 0% | 2,702 | 6,304 | +133% | 0 | 0 | — |
case-19 | fail→pass | 14,853 | 13,310 | -10% | 1 | 1 | 0% | 2,509 | 5,582 | +122% | 0 | 0 | — |
case-20 | fail→fail | 16,421 | 18,073 | +10% | 1 | 1 | 0% | 3,284 | 6,947 | +112% | 0 | 0 | — |
case-21 | fail→pass | 14,242 | 13,157 | -8% | 1 | 1 | 0% | 2,425 | 5,622 | +132% | 0 | 0 | — |
case-22 | fail→fail | 23,005 | 20,853 | -9% | 1 | 1 | 0% | 4,515 | 7,402 | +64% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +36 percentage points is the difference between those two pass rates over the 21 comparable cases. 2 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.