Skip to content
Back to skills

External Model Validation

ASecurity

Use when validating an existing prognostic risk signature on an external bulk expression cohort with survival outcomes, producing risk scores, Kaplan-Meier curves, risk distribution plots, heatmap, and time-dependent ROC curves. NOT for: model training, feature selection, nomogram construction, calibration analysis, or single-cell data.

  • 1,793 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added June 6, 2026
datagobashexpresstesting

Works with

  • cli

Security analysis

A100/100

Pro scans all 17 files and shows the line behind each finding

Scanned June 6, 2026

npx -y skills add aipoch/medical-research-skills --skill external-model-validation --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of External Model Validation?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for External Model Validation
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/aipoch-external-model-validation/badge)](https://www.skillsdirectory.com/skills/aipoch-external-model-validation)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: external-model-validation
description: "Use when validating an existing prognostic risk signature on an external bulk expression cohort with survival outcomes, producing risk scores, Kaplan-Meier curves, risk distribution plots, heatmap, and time-dependent ROC curves. NOT for: model training, feature selection, nomogram construction, calibration analysis, or single-cell data."
license: MIT
skill-author: AIPOCH
---

# External Model Validation

## Input Validation

This skill accepts: an existing prognostic gene signature (model coefficient file with `Gene` and `Coef` columns), a bulk expression matrix in CSV format (genes as rows, samples as columns), and a clinical file with `OS` and `OS.time` survival columns.

If the user's request does not involve validating a pre-existing prognostic model on an external cohort — for example, asking to train a new model, perform feature selection, build a nomogram, run calibration curves, analyze single-cell data, or process data without survival endpoints — do not proceed with the workflow. Instead respond:

> "external-model-validation is designed to validate an existing prognostic risk signature on an external bulk expression cohort with survival outcomes. Your request appears to be outside this scope. Please provide a fixed model coefficient file plus expression and clinical data with OS/OS.time columns, or use a more appropriate tool for model training, nomogram construction, or single-cell analysis."

## When to Read External Files

| Situation | File to Read | Purpose |
|-----------|--------------|---------|
| **Need to run the analysis** | `scripts/main.R` | Execute: `Rscript scripts/main.R --exp_file ... --cli_file ... --model_file ...` |
| **Need workflow order or output generation steps** | `scripts/run_analysis.R` | Review the 4-step orchestration of loading, scoring, plotting, and metadata export |
| **Need risk score or sample matching logic** | `scripts/functions.R` | Inspect core data preparation and validation logic |
| **Need output writing or metadata export details** | `scripts/io.R` | Inspect output directory creation and file-writing helpers |
| **Need plotting implementation details** | `scripts/plotting.R` | Inspect Kaplan-Meier, risk, heatmap, and ROC plot generation |
| **Need input validation, logging, timeout, or dependency logic** | `scripts/utils.R` | Review validation helpers, `SKILL_*` error handling, logging, and runtime safeguards |
| **Need statistical assumptions or method details** | `references/algorithm.md` | Risk score formula, group cutoff, survival analysis, ROC, and heatmap assumptions |
| **Need troubleshooting help** | `references/troubleshooting.md` | Common failures, warnings, and concrete fixes |
| **Need CLI usage examples** | `references/cli-guide.md` | Parameter explanations, examples, and command patterns |
| **Need expected outputs or benchmark run** | `references/baseline-run.md` | Real-data baseline command, runtime, memory checkpoints, and output inventory |
| **Need test inputs** | `tests/data/` | Example expression, clinical, and model files for validation |
| **Need to refresh the retained example output** | `tests/refresh_example_output.R` | Rebuild `tests/output/` with `--overwrite` using the bundled test data |

---

## Usage

```bash
Rscript scripts/main.R \
  --exp_file ./expression.csv \
  --cli_file ./clinical.csv \
  --model_file ./model.csv \
  --output_dir ./output/ \
  --time_unit month \
  --seed 42
```

---

## Arguments

| Short | Long | Type | Default | Description |
|-------|------|------|---------|-------------|
| `-e` | `--exp_file` | character | **required** | Expression matrix CSV with genes as rows and samples as columns |
| `-c` | `--cli_file` | character | **required** | Clinical CSV with sample IDs as row names and `OS`, `OS.time` columns |
| `-m` | `--model_file` | character | **required** | Model coefficient CSV with `Gene` and `Coef` columns |
| `-o` | `--output_dir` | character | `./output/` | Output directory |
|  | `--overwrite` | flag | `FALSE` | Allow writing into a non-empty output directory |
| `-u` | `--time_unit` | character | `month` | Survival time unit in input clinical file: `day`, `month`, `year` |
|  | `--col_high` | character | `#E64B35` | Color for high-risk samples |
|  | `--col_low` | character | `#4DBBD5` | Color for low-risk samples |
|  | `--roc_cols` | character | `#E64B35,#00A087,#3C5488` | Comma-separated colors for ROC curves |
|  | `--roc_times` | character | `1,3,5` | Comma-separated ROC time points **always in years**, regardless of `--time_unit`. When follow-up is in days or months, still provide `--roc_times` in years (e.g., `1,3,5` for 1, 3, and 5 years). |
|  | `--roc_pos` | character | `bottomright` | ROC legend position |
|  | `--km_breaks` | integer | `0` | Kaplan-Meier x-axis break in years; `0` selects automatically |
| `-s` | `--seed` | integer | `42` | Random seed for reproducibility |
|  | `--timeout_seconds` | integer | `3600` | Elapsed timeout limit in seconds |

---

## When to Use

- You already have a fixed prognostic gene signature and coefficients.
- You need to test that model on an independent cohort with bulk expression and survival data.
- You want standard outputs for external validation: risk table, Kaplan-Meier curve, risk score plot, survival status plot, expression heatmap, and time-dependent ROC.

## When Not to Use

- Do not use this skill to train or re-fit a prognostic model.
- Do not use it for nomogram construction, calibration curves, DCA, or diagnostic classification.
- Do not use it for single-cell expression matrices or cohorts without survival endpoints.
- Do not use identifiable patient data without de-identification and local compliance approval.
- Do not use for cohorts with very few events (fewer than 5 events may produce unreliable Kaplan-Meier and ROC results).

## Research Use Notice

- This skill is for research and validation workflows only.
- It does not provide diagnosis, treatment recommendations, or clinical decision support.
- Use de-identified data and follow IRB, ethics, and data-use requirements before running on human cohorts.

---

## Input Format

### Expression Matrix (`exp_file`)

CSV with genes as rows and samples as columns. The first column must contain gene identifiers.

```csv
"","Sample_1","Sample_2","Sample_3"
"TSPAN6",3.87,4.54,8.12
"TNMD",9.98,5.86,5.38
"DPM1",7.95,6.11,5.41
```

### Clinical File (`cli_file`)

CSV with sample IDs as row names and at least `OS` and `OS.time` columns.

```csv
,Age,OS,OS.time
Sample_1,59,0,133.5
Sample_2,60,0,49.13
Sample_3,59,1,22.40
```

- `OS` must use `0/1` encoding.
- `OS.time` must be positive and interpretable under `--time_unit`.

### Model Coefficient File (`model_file`)

CSV with two required columns: `Gene` and `Coef`.

```csv
Gene,Coef
TSPAN6,-0.25
TNMD,0.15
DPM1,0.32
```

---

## Output Files

| File | Description |
|------|-------------|
| `data/risk_data.rds` | Serialized analysis dataset containing survival data, model gene expression, risk scores, and risk groups |
| `table/out_varifyRisk.txt` | Tab-delimited risk table for all matched samples |
| `plot/out_varifySurv.pdf` | Kaplan-Meier survival curve with risk table |
| `plot/out_varify.riskScore.pdf` | Ordered risk score plot |
| `plot/out_varify.survStat.pdf` | Survival status plot |
| `plot/out_varify.heatmap.pdf` | Heatmap of model genes across ordered samples |
| `plot/out_varify.ROC.pdf` | Time-dependent ROC curve PDF |
| `analysis.log` | Runtime log including memory checkpoints and processing steps |
| `run_parameters.tsv` | Exact parameter values used for the run |
| `session_info.txt` | R version, platform, and package session information |

---

## Workflow

### Step 1: Validate Inputs
- Check required files and CSV extensions.
- Validate color strings, timeout, seed, KM break setting, and time unit choice.
- Parse `--roc_times` and `--roc_cols`.

### Step 2: Build Matched Validation Dataset
- Read expression, clinical, and model files.
- Match samples shared by expression columns and clinical row names.
- Check all model genes exist in the expression matrix.
- Remove incomplete cases before downstream analysis.

### Step 3: Calculate Risk Scores and Groups
- Compute risk scores with the supplied linear predictor.
- Convert follow-up time into years.
- Split patients into `low` and `high` groups using the median risk score.

### Step 4: Generate Validation Outputs
- Save the full risk table and RDS object.
- Produce Kaplan-Meier, risk score, survival status, heatmap, and time-dependent ROC plots.
- Save session metadata and exact run parameters.

---

## Methods

### Risk Score Formula

For sample `i`, the skill computes:

```text
riskScore_i = sum(expression_ig * coefficient_g)
```

using all genes listed in `model_file`.

### Risk Stratification

- Samples are ordered by `riskScore`.
- The median risk score is used as the cutoff.
- Samples with scores above the median are labeled `high`; the others are labeled `low`.

### Survival Analysis

- Kaplan-Meier curves are fit with `survival::survfit`.
- Group difference is shown with the default log-rank p-value in `survminer::ggsurvplot`.

### Time-Dependent ROC

- ROC analysis is performed with `timeROC::timeROC` using follow-up time in years.
- All `--roc_times` values must be smaller than the maximum observed follow-up time.
- `--roc_times` is always interpreted in years, regardless of `--time_unit`.

---

## Examples

### Basic Usage

```bash
Rscript scripts/main.R \
  -e tests/data/BRCA_data.csv \
  -c tests/data/BRCA_clinic.csv \
  -m tests/data/BRCA_coef.csv \
  -o ./output/
```

### Input Follow-up Recorded in Days

```bash
Rscript scripts/main.R \
  -e expression.csv \
  -c clinical.csv \
  -m model.csv \
  -o ./output \
  -u day \
  --roc_times 1,2,3
```

Note: `--roc_times 1,2,3` means 1, 2, and 3 years — even though `--time_unit day` was supplied. The skill converts `OS.time` from days to years internally before ROC computation.

### Custom Plot Colors and ROC Settings

```bash
Rscript scripts/main.R \
  -e expression.csv \
  -c clinical.csv \
  -m model.csv \
  -o ./output \
  --col_high '#B2182B' \
  --col_low '#2166AC' \
  --roc_cols '#B2182B,#4D9221,#2166AC' \
  --roc_pos topleft \
  --km_breaks 2
```

---

## Error Handling

### Common Errors

| Error | Cause | Solution |
|-------|-------|----------|
| `SKILL_FILE_NOT_FOUND` | Input path is missing or wrong | Check file path and permissions |
| `SKILL_MISSING_COLUMNS` | Clinical or model file lacks required columns | Ensure `OS`, `OS.time`, `Gene`, and `Coef` exist |
| `SKILL_SAMPLE_MISMATCH` | No overlapping samples between expression and clinical data | Align sample IDs exactly |
| `SKILL_EMPTY_DATA` | An input file is empty after loading | Verify the CSV contains at least one row and one column of usable data |
| `SKILL_INVALID_DATA` | Duplicate genes, empty data, non-numeric coefficients, or invalid survival values. For duplicate genes: deduplicate with `dplyr::distinct()` or keep the row with highest mean expression (e.g., `mat[order(-rowMeans(mat[,-1])),] %>% distinct(Gene, .keep_all=TRUE)`) | Clean input tables and verify formats |
| `SKILL_ANALYSIS_ERROR` | Risk groups collapse or event count is too low | Use a valid signature and cohort with enough events (minimum ~5) |
| `SKILL_INVALID_PARAMETER` | Bad `--time_unit`, invalid color, or impossible ROC time point | Correct the parameter value |
| `SKILL_DEPENDENCY_MISSING` | Required R package is not installed | Install the missing package |
| `SKILL_PKG_VERSION` | Installed package version is below the required minimum | Upgrade the package to the required version |

**IF error persists**, READ: `references/troubleshooting.md`

---

## Testing

### Test with Included Data

```bash
# Check CLI
Rscript scripts/main.R --help

# Run with bundled test data in a fresh output directory
Rscript scripts/main.R \
  -e tests/data/BRCA_data.csv \
  -c tests/data/BRCA_clinic.csv \
  -m tests/data/BRCA_coef.csv \
  -o ./output/
```

### Validation Commands

```bash
# Run R tests
Rscript tests/testthat.R

# Refresh the retained example output bundle
Rscript tests/refresh_example_output.R

# Inspect the generated risk table
wc -l tests/output/table/out_varifyRisk.txt

# Review the retained example outputs
ls -la tests/output/
```

### Real-data Baseline

The repository stores a documented real-data baseline summary in `references/baseline-run.md`.

**IF you need exact benchmark outputs or runtime expectations**, READ: `references/baseline-run.md`

→ Directory structure and implementation details: [references/project-structure.md](references/project-structure.md)

Files in this skill

  • SKILL.md12.4 KB
  • eval_report_external-model-validation_result.json17.3 KB
  • references/algorithm.md3.7 KB
  • references/baseline-run.md2.5 KB
  • references/cli-guide.md2.8 KB
  • references/project-structure.md1.6 KB
  • references/troubleshooting.md5.2 KB
  • scripts/functions.R4.8 KB
  • scripts/io.R2.6 KB
  • scripts/main.R6.9 KB
  • scripts/plotting.R4.9 KB
  • scripts/run_analysis.R1.9 KB
  • scripts/utils.R4 KB
  • tests/data/BRCA_coef.csv47 B
  • tests/data/BRCA_data.csv59.6 KB
  • tests/refresh_example_output.R980 B
  • tests/testthat.R729 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…