mims-harvard/tooluniverse/tooluniverse-statistical-modeling
- community
Checking that the SKILL.md file is still in the repository.
Statistical modeling — linear/logistic/ordinal/Poisson regression, ANOVA, Kruskal-Wallis, chi-square, Mann-Whitney, Cox survival, spline fits (R `ns()`), odds ratios, Cohen's d, F-statistic, p-value computation. Specializes in clinical-trial AE analysis (SDTM DM/AE), severity ordinal regression, and per-feature stat workflows.
Install
npx vskill@latest install mims-harvard/tooluniverse/tooluniverse-statistical-modelingSKILL.md
Statistical Modeling for Biomedical Data Analysis
RULE ZERO — Check for pre-computed results FIRST
Before following any instruction below, scan the data folder for:
*_executed.ipynb→ read withtu run read_executed_notebook '{"data_folder":"<path>","search":"<keyword>"}'and cite its cell outputs as the authoritative answer- Pre-computed result files (CSV/TSV with names like
*results*,*deseq*,*enrich*,*stats*,*_simplified.csv) → read directly and report the requested value - Canonical analysis scripts (
analysis.R,run_*.py,find_*.R,*.Rmd) → execute as-is and read the output
Only follow this skill's re-analysis recipe below if none of the above exist. Re-running from raw data produces different numbers than the published answer and is much slower (often 5-10× turn count).
PRIMARY SCRIPTS — use these FIRST
These scripts encode the question-specific gotchas in scripts/ and emit labelled, parseable output. Prefer them over ad-hoc statsmodels / scipy code.
| Script | When to use it | |
|---|---|---|
r_natural_spline_regression.py | ANY question that mentions R syntax lm(y ~ ns(x, df = K)), "natural spline", or asks for spline R²/F/peak prediction CIs. Always shells out to Rscript so splines::ns() matches. | |
spline_model_compare.py | "Best-fitting model among quadratic, cubic and natural spline" / "max colony area at the optimal x". Fits all three in R, ranks by adj-R²/AIC/BIC, and reports the BEST model's peak (x, y) with 95% CI. | |
logistic_regression_or.py | Binary or ordinal logistic regression where the answer is an OR (or OR + 95% CI). Handles label encoding, explicit Placebo=0/BCG=1 maps, AND interaction terms (--interaction A:B -> creates A_B = A*B). Prints OR + CI for every coefficient and a SCALARS block for the requested --coef-name. | |
power_analysis.py | "Minimum sample size per group", "TTestIndPower", "given Cohen's d, what N for power=0.8". Computes pooled-SD Cohen's d from a CSV (or accepts --effect-size), then TTestIndPower.solve_power. | |
expression_anova.py | Per-gene ANOVA / median LFC across cell types or sample groups (NOT pooled across genes — see warnings below). | |
prepare_ae_cohort.py | Clinical-trial AE severity tests (chi-square / ordinal) on SDTM DM/AE files (encoding='latin1', max(AESEV) per subject across ALL AEs — no AEPT filter). | |
stat_tests.py | Stdlib-only chi-square goodness-of-fit, Fisher's exact, simple OLS. Use when scipy/statsmodels aren't available. |
Concrete invocations
Natural-spline regression (R^2, overall F-test p, peak Y + 95% CI):
Quadratic vs cubic vs natural-spline comparison + best-model peak:
Report the peak location (`x*`) in the units of the fitted x-variable, not a derived label. When the model is fit on a frequency/proportion column (e.g. Frequency_strain, a 0–1 value), the answer to "at what ratio/frequency is the maximum" is that fraction (e.g. 0.909), NOT the colon-ratio it was derived from (e.g. 10:1). Convert a colon ratio a:b to the fraction a/(a+b) when the question expects a 0–1 value or the fitted x-column is a fraction.
Ordinal logistic regression with interaction term (e.g. trial AE severity):
Two-sample power analysis from a pilot CSV:
Workspace isolation (CRITICAL)
The input data folder for any analysis must remain untouched so re-runs are reproducible. Scripts that write intermediate files (R drivers, prepared CSVs, comparison tables) must write to /tmp/ or to a --workdir you pass in. Both R-based scripts in this skill refuse to run if --workdir resolves to the input CSV's parent directory (or any ancestor of it).
CRITICAL — Read before writing any code
- Clinical trial AE analysis (regression, chi-square, ANY severity test): Use the bundled script (or the
clinical_trial_ae_severity_testToolUniverse tool which wraps it):
```bash tu run clinical_trial_ae_severity_test '{"dm_file":"DM.csv","ae_file":"AE.csv","test":"chi-square","group_col":"TRTGRP"}'
# Or directly: python skills/tooluniverse-statistical-modeling/scripts/prepare_ae_cohort.py \ --dm DM.csv --ae AE.csv --test chi-square --group TRTGRP \ --subgroup "expect_interact=Yes" # optional `` The script/tool handles: encoding='latin1' for SDTM CSVs, max(AESEV)` per subject across ALL AEs (no AEPT filtering), inner join with DM, optional subgroup filter, optional ordinal-logistic with covariates.
Why no AEPT filter — AESEV is a protocol-defined severity scale on the AE table. Filtering AE by AEPT (e.g. keeping only AEPT == "COVID-19") drops subjects whose worst severity was recorded under a different AEPT label, drastically changes the contingency table, and can flip the test result. The phrase "COVID-19 severity" describes the OUTCOME, NOT a filter criterion.
- ❌ WRONG:
ae[ae['AEPT'].str.contains('COVID-19')].groupby('USUBJID')['AESEV'].max()— filters to COVID-19 events - ✅ RIGHT:
ae.groupby('USUBJID')['AESEV'].max()— uses ALL AE records
- Expression ANOVA / fold change with multi-feature data (gene × sample matrix):
For "the F-statistic" or "a fold change" as a single value, run per-gene then summarize — NEVER pool expr.values.ravel() across all genes.
- For F-statistic: derive a per-sample quantity (like DESeq2 LFC of each gene between two cell types, then ANOVA on those LFCs across groups) OR run on a single target gene.
- For median/mean log2 fold change between two groups: run DESeq2 with
design=~<group>, extract per-genelog2FoldChange(with shrinkage if the pipeline uses it), then take median/mean across genes.
❌ WRONG (aggregate): log2(sum_counts_groupA / sum_counts_groupB) per sample then summarize — gives ratio of totals, dominated by high-expression genes. ✅ RIGHT (per-gene): DESeq2 → results_df['log2FoldChange'].median().
Sanity heuristics: F > 50 for biological ANOVA across a few groups means you aggregated (typical biological F is 0.5–10). |median LFC| > 2 between similar groups means you aggregated (typical |median| < 1).
Use the bundled script: python skills/tooluniverse-statistical-modeling/scripts/expression_anova.py (or the expression_anova_per_gene ToolUniverse tool).
- Spline models — R
splines::ns(x, df=K)≠ Pythonpatsy.dmatrix("cr(x, df=K)"). They produce different design matrices because of internal-knot placement, boundary-knot placement, and basis orthogonalization. For ANY question that references R syntax likelm(y ~ ns(x, df = 4)), run R viaRscript. Use the bundled wrapper:
``bash python skills/tooluniverse-statistical-modeling/scripts/r_natural_spline_regression.py \ --csv data.csv --y-col Y --x-col X --df 4 --workdir /tmp/spline_run ``
For "frequency of strain X" co-culture models, include pure focal strain (freq=1) but exclude non-focal pure strain (freq=0).
- CSV encoding: Clinical trial CSVs often need
encoding='latin1'.
- Pearson correlation between count-like and length-like variables: when one variable
spans orders of magnitude (raw read counts, TPM, gene length, transcript abundance), raw Pearson r is often near 0 even when log-transformed r is moderate. ALWAYS compute and explicitly report ALL FOUR variants in your final answer body: r(x, y), r(log10(x+1), y), r(x, log10(y+1)), r(log10(x+1), log10(y+1)). List as a table; mark one as your primary pick. The published answer can be ANY of the four, and the question text rarely disambiguates which transform combination was used.
``` ## Primary answer: r = X.XXX (transform: <name>)
## Sensitivity (all 4 transform combinations):
- r(x, y) = ...
- r(log10(x+1), y) = ...
- r(x, log10(y+1)) = ...
- r(log10(x+1), log10(y+1)) = ...
```
Background — for any single transform variant:
``python import numpy as np from scipy.stats import pearsonr r_raw, _ = pearsonr(x, y) r_log, _ = pearsonr(np.log10(x + 1), y) print(f"r_raw={r_raw:.4f} r_log10={r_log:.4f}") ``
Defaults:
- Question says "log-transformed" / "log expression" → report r_log10
- Question doesn't specify but the variable is gene expression / RNA count → also report r_log10 as the canonical answer (most published correlations between gene length and expression are log-scale)
- When
|r_raw| < 0.1AND|r_log10| > 0.2, prefer r_log10
❌ WRONG: report only r_raw ≈ 0.05 when log is 0.35 ✅ RIGHT: "r_raw = 0.05; r_log10 = 0.35 (canonical for log-distributed expression)"
COMPUTE, DON'T DESCRIBE
Write and run Python code (via Bash) for every statistical analysis. Never describe what you "would do" — do it. Use pandas for data wrangling, statsmodels for regression, scipy for tests, and matplotlib for plots. Execute the code and report actual numbers (β, p-value, CI, N).
LOOK UP, DON'T GUESS
When uncertain about any scientific fact, SEARCH databases first rather than reasoning from memory.
Features
- Linear Regression - OLS for continuous outcomes with diagnostic tests
- Logistic Regression - Binary, ordinal, and multinomial models with odds ratios
- Survival Analysis - Cox proportional hazards and Kaplan-Meier curves
- Mixed-Effects Models - LMM/GLMM for hierarchical/repeated measures data
- ANOVA - One-way/two-way ANOVA, per-feature ANOVA for omics data
- Model Diagnostics - Assumption checking, fit statistics, residual analysis
- Statistical Tests - t-tests, chi-square, Mann-Whitney, Kruskal-Wallis, etc.
When to Use
Apply this skill when user asks:
- "What is the odds ratio of X associated with Y?"
- "What is the hazard ratio for treatment?"
- "Fit a linear regression of Y on X1, X2, X3"
- "Perform ordinal logistic regression for severity outcome"
- "What is the Kaplan-Meier survival estimate at time T?"
- "What is the percentage reduction in odds ratio after adjusting for confounders?"
- "Run a mixed-effects model with random intercepts"
- "Compute the interaction term between A and B"
- "What is the F-statistic from ANOVA comparing groups?"
- "Test if gene/miRNA expression differs across cell types"
Model Selection Decision Tree
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 95 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/tooluniverse-statistical-modeling/SKILL.md
Popularity
- Repository stars
- 1,450
- Repository forks
- 224
- 7-day trend score
- 36
Stars and forks are for the whole GitHub repository, not this skill alone. Refreshed 22 Mar 2026, 7 months ago.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/mims-harvard/tooluniverse/tooluniverse-statistical-modeling)