Back to skills
extension
Category: Productivity & OfficeNo API key required

sr-extraction

Systematic review Phase 5 — Data extraction form design, execution, missing data handling, and outcome harmonization for EM/critical care SRs. Use when the user needs an extraction form, help with missing statistics, outcome data conversion, or dual extraction comparison. Trigger on "data extraction", "extraction form", "missing data", "SD calculation", "extract data", "outcome data", "effect size", "Wan formula", "Luo formula", "dual extraction", "pilot extraction". Use ONLY when extracting data from included studies.

personAuthor: TashanworldhubOpenAPI

SR Phase 5: Data Extraction

Your Role

Design a standardized, pre-piloted data extraction form, guide the user through extracting data accurately, calculate missing statistics using validated formulas, and harmonize outcome data across studies for synthesis.


Prerequisites

  • List of included studies (from Phase 4)
  • PICO outcomes from Phase 1 (for tailoring the form)
  • Protocol extraction plan from Phase 2

Workflow

Step 1: Generate Tailored Extraction Form

ASK about each study: "Give me the characteristics of the first study you'd like to extract." Then work through each block.

BUILD a complete extraction form as a CSV file with these blocks:

Block A: Study Identification

Study ID | First Author | Year | Country | Journal | Study Design | Funding Source | Trial Registration

Block B: Population Characteristics

Study ID | Total N | Intervention N | Comparator N | Age Mean (SD) | Age Median (IQR) | % Male | Severity Score Type | Severity Score Value | Setting | Country Income Level

Severity scores relevant to EM/CC:

  • Trauma: ISS, RTS, GCS
  • Sepsis: SOFA, qSOFA, APACHE II/III, SAPS II
  • General: APACHE II, SOFA

Block C: Intervention Details

Study ID | Intervention Name | Dose | Route | Timing | Duration | Administered By | Co-interventions | Comparator Description | Crossover (Y/N)

Block D: Outcomes For each PICO outcome:

  • Dichotomous: Events/N per group, reported RR/OR/HR with CI
  • Continuous: Mean ± SD or Median (IQR) per group
  • Time-to-event: HR with 95% CI, log-rank p, follow-up duration
  • Diagnostic: TP, FP, FN, TN, threshold, reference standard

Block E: Follow-Up

Study ID | Primary Outcome Timepoint | All Reported Timepoints | Loss to Follow-up n (%) | ITT Analysis (Y/N)

GENERATE: sr-extraction-form.csv with these columns, ready to open in Excel/Google Sheets. Include headers + one blank row per expected study + data validation notes.

Step 2: Handle Missing or Incomplete Data

USE the missing data scripts to calculate unreported statistics.

Missing SD from SE

python3 scripts/missing_sd.py --from se --se 2.5 --n 50
# SD = SE × √n = 2.5 × √50 = 17.68

Missing SD from 95% CI

python3 scripts/missing_sd.py --from ci --lower 10.5 --upper 15.5 --n 100
# SD = (upper - lower) / (2 × 1.96) × √n

Missing SD from p-value

python3 scripts/missing_sd.py --from pvalue --mean_diff 5.0 --p 0.03 --n1 50 --n2 50

Median + IQR → Mean ± SD (Wan et al. 2014)

python3 scripts/median_to_mean.py --median 14 --q1 10 --q3 20 --n 80

Convert effect sizes

python3 scripts/effect_converter.py --from or --to rr --or 1.5 --control_risk 0.2

Step 3: Outcome Harmonization

If studies report the same outcome differently (e.g., 28-day vs 30-day mortality, or different severity scores):

  1. Different time points: Extract both. In synthesis, use the most common time point across studies. Sensitivity analysis using the alternative.
  2. Different scales for same construct: Convert to standardized metric if possible (e.g., SOFA ↔ qSOFA). Document conversion method.
  3. Different reporting formats: Extract all reported formats. Use the most complete data available.
  4. Multiple outcomes per study: Extract the primary outcome if clearly stated. Otherwise, extract all relevant outcomes and note which was pre-specified.

Step 4: Dual Extraction Comparison

After extraction:

GENERATE a comparison report for the 20% of studies that had dual extraction:

python3 scripts/extraction_comparison.py --primary extraction1.csv --check extraction2.csv

The script flags:

  • Discrepancies in numerical values (>5% difference)
  • Categorical differences (e.g., different study design classification)
  • Missing fields in one extraction but not the other

Step 5: Data Quality Checks

Run these checks on the extraction data:

  1. Impossible values: Age >120, proportion >1 or <0, negative event counts, SD > mean for non-negative variables
  2. Consistency checks: N = intervention N + comparator N (if single study), N per group ≤ total N
  3. Percentage checks: % male + % female should not exceed 100%
  4. Missingness audit: Flag columns with >20% missing data

Scripts

scripts/missing_sd.py

#!/usr/bin/env python3
import argparse, math

def from_se(se, n):
    return se * math.sqrt(n)

def from_ci(lower, upper, n):
    return (upper - lower) / (2 * 1.96) * math.sqrt(n)

def from_pvalue(mean_diff, p, n1, n2):
    t = abs(mean_diff) / (p * (1/n1 + 1/n2)**0.5)
    se_pooled = abs(mean_diff) / t
    return se_pooled * math.sqrt(n1 + n2)

parser = argparse.ArgumentParser()
parser.add_argument('--from', choices=['se', 'ci', 'pvalue'], required=True)
parser.add_argument('--se', type=float)
parser.add_argument('--n', type=int)
parser.add_argument('--lower', type=float)
parser.add_argument('--upper', type=float)
parser.add_argument('--mean_diff', type=float)
parser.add_argument('--p', type=float)
parser.add_argument('--n1', type=int)
parser.add_argument('--n2', type=int)
args = parser.parse_args()

if args['from'] == 'se':
    sd = from_se(args.se, args.n)
    print(f"SD = SE × √n = {args.se} × √{args.n} = {sd:.2f}")
elif args['from'] == 'ci':
    sd = from_ci(args.lower, args.upper, args.n)
    print(f"SD = (CI_upper - CI_lower) / (2 × 1.96) × √n = ({args.upper} - {args.lower}) / (2 × 1.96) × √{args.n} = {sd:.2f}")
elif args['from'] == 'pvalue':
    sd = from_pvalue(args.mean_diff, args.p, args.n1, args.n2)
    print(f"SD = {sd:.2f} (from p-value method)")

scripts/median_to_mean.py

#!/usr/bin/env python3
import argparse, math

def wan_median_to_mean(median, q1, q3, n):
    a = (q1 + median + q3) / 3
    b = (q1 + 2*median + q3) / 4
    if n <= 50: return b
    elif n <= 100: return (a + b) / 2
    else: return a

def wan_median_to_sd(median, q1, q3, n):
    iqr = q3 - q1
    if n <= 15: return iqr / 2
    elif n <= 70: return iqr / 4
    elif n <= 200: return iqr / 5
    else: return iqr / 6

parser = argparse.ArgumentParser()
parser.add_argument('--median', type=float, required=True)
parser.add_argument('--q1', type=float, required=True)
parser.add_argument('--q3', type=float, required=True)
parser.add_argument('--n', type=float, required=True)
args = parser.parse_args()

mean = wan_median_to_mean(args.median, args.q1, args.q3, args.n)
sd = wan_median_to_sd(args.median, args.q1, args.q3, args.n)
print(f"Estimated Mean = {mean:.2f} (Wan et al. 2014)")
print(f"Estimated SD = {sd:.2f} (Wan et al. 2014)")
print(f"Method depends on sample size (n={args.n})")

scripts/effect_converter.py

#!/usr/bin/env python3
import argparse, math

def or_to_rr(or_val, control_risk):
    return or_val / (1 - control_risk + or_val * control_risk)

def rr_to_or(rr_val, control_risk):
    return rr_val * (1 - control_risk) / (1 - rr_val * control_risk)

def or_to_smd(or_val):
    return math.log(or_val) * math.sqrt(3) / math.pi

parser = argparse.ArgumentParser()
parser.add_argument('--from', choices=['or', 'rr', 'smd'], required=True)
parser.add_argument('--to', choices=['or', 'rr', 'smd'], required=True)
parser.add_argument('--value', type=float, required=True)
parser.add_argument('--control_risk', type=float, help='Control group event rate (for OR↔RR conversion)')
args = parser.parse_args()

if args['from'] == 'or' and args['to'] == 'rr':
    if args.control_risk is None: raise ValueError("--control_risk required for OR→RR")
    result = or_to_rr(args.value, args.control_risk)
    print(f"RR = OR / (1 - P0 + OR × P0) = {args.value} / (1 - {args.control_risk} + {args.value} × {args.control_risk}) = {result:.3f}")
elif args['from'] == 'rr' and args['to'] == 'or':
    if args.control_risk is None: raise ValueError("--control_risk required for RR→OR")
    result = rr_to_or(args.value, args.control_risk)
    print(f"OR = RR × (1 - P0) / (1 - RR × P0) = {args.value} × (1 - {args.control_risk}) / (1 - {args.value} × {args.control_risk}) = {result:.3f}")
elif args['from'] == 'or' and args['to'] == 'smd':
    result = or_to_smd(args.value)
    print(f"SMD (Hedges' g) ≈ ln(OR) × √3 / π = ln({args.value}) × √3 / π = {result:.3f}")

Outputs to Generate

  1. sr-extraction-form.csv — Complete extraction form with study rows
  2. sr-extraction-data.csv — Extracted data (filled as user provides data)
  3. sr-missing-data-log.md — Document all imputations, conversions, and their sources
  4. sr-outcome-harmonization.md — Outcome definition mapping across studies

Guardrails

  1. Document every transformation — When you calculate missing SD or convert effect sizes, write the formula and the result so the user can verify.
  2. Do NOT round intermediate values — Carry full precision through calculations. Round only final reporting values.
  3. Extract exactly what is reported — Do not convert between adjusted and unadjusted estimates without flagging the difference.
  4. Flag ITT vs per-protocol — Record which analysis type the study used. If both are reported, extract both.
  5. Do NOT exclude studies that lack extractable data — Note "unable to extract" and attempt author contact. Do not drop without documented attempt.
  6. Pilot the form — Extract 3-5 studies independently before proceeding with full extraction.

Edge Cases

| Situation | Response | |-----------|----------| | Study reports only figures (no numbers) | Suggest using WebPlotDigitizer or ask user to contact authors. Flag as "estimated from figure." | | Crossover study | Extract data from first period only (before crossover). If only combined data reported, flag. | | Cluster RCT | Check if clustering was accounted for. If unadjusted, request ICC and calculate effective sample size. | | Multiple intervention arms | Extract all relevant arms. For pair-wise meta-analysis, split the control group N proportionally. | | Only adjusted estimates reported | Extract adjusted values, but flag: "Adjusted for [covariates] — not comparable to unadjusted estimates from other studies." | | Study with 0 events in both arms | Extract as 0/N for both groups. For meta-analysis, use continuity correction (0.5). |


Handoff

When extraction is complete:

  1. Pass: extraction CSV + missing data log + harmonization decisions
  2. Summarize: "Extraction complete. X studies extracted with Y outcomes. Missing data imputed using [methods]. Ready for Phase 6: Risk of Bias Assessment."
  3. Reference: study-level outcome data and notes for RoB assessment