
Data Analysis
- 1 installs
- 255 repo stars
- Updated February 27, 2026
- lingzhi227/claude-research-skills
This is a copy of data-analysis by lingzhi227 - installs and ranking accrue to the original listing.
Helps with ai & agent building tasks.
About
data-analysis is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- data-analysis
- AI & Agent Building
- AI-coding skill
Data Analysis by the numbers
- 1 all-time installs (skills.sh)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/lingzhi227/claude-research-skills --skill data-analysisAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 255 |
| Last updated | February 27, 2026 |
| Repository | lingzhi227/claude-research-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Data Analysis
Generate rigorous statistical analysis code with multi-round review.
Input
$0— Data source (CSV, JSON, pickle, or experiment logs)$1— Research goal or hypothesis to test
References
- 4-round code review prompts:
~/.claude/skills/data-analysis/references/review-prompts.md
Scripts
Statistical summary and comparison
python ~/.claude/skills/data-analysis/scripts/stat_summary.py --input results.csv --compare method --metric accuracy --output summary.json
python ~/.claude/skills/data-analysis/scripts/stat_summary.py --input results.csv --describeDetects data types, recommends tests, runs comparisons, outputs effect sizes and significance stars. Requires numpy, scipy.
Format p-values
python ~/.claude/skills/data-analysis/scripts/format_pvalue.py --values "0.001 0.05 0.23" --format stars
python ~/.claude/skills/data-analysis/scripts/format_pvalue.py --csv results.csv --column pvalue --format latexFormats p-values with stars, LaTeX notation, or plain text. Stdlib-only.
Workflow
Step 1: Generate Analysis Code
Structure the code with these sections: 1. # IMPORT — pandas, numpy, scipy, statsmodels, sklearn 2. # LOAD DATA — Load from original data files 3. # DATASET PREPARATIONS — Missing values, units, exclusion criteria 4. # DESCRIPTIVE STATISTICS — Summary tables if needed 5. # PREPROCESSING — Dummy variables, normalization 6. # ANALYSIS — Statistical tests per hypothesis 7. # SAVE ADDITIONAL RESULTS — Extra results to pickle
Step 2: 4-Round Code Review
1. Round 1 — Code Flaws: Mathematical/statistical errors, wrong calculations, trivial tests 2. Round 2 — Data Handling: Missing values, units, preprocessing, test choice 3. Round 3 — Per-Table: Sensible values, measures of uncertainty, missing data 4. Round 4 — Cross-Table: Completeness, consistency, missing variables
Step 3: Produce Results
- Every nominal value must have uncertainty (CI, STD, or p-value)
- Statistical tests must be appropriate for the data type
- Results must match actual data — never hallucinate
Allowed Packages
pandas, numpy, scipy, statsmodels, sklearn, pickle
Statistical Test Selection
| Data Type | Test |
|---|---|
| Two groups, normal | Independent t-test |
| Two groups, non-normal | Mann-Whitney U |
| Paired samples | Paired t-test / Wilcoxon |
| Multiple groups | ANOVA / Kruskal-Wallis |
| Categorical | Chi-square / Fisher's exact |
| Correlation | Pearson / Spearman |
| Regression | OLS / Logistic / Mixed effects |
Rules
- Always report p-values for statistical tests
- Account for relevant confounding variables
- Use inherent package functionality (e.g.,
formula = "y ~ a * b"for interactions) - Do not manually implement available statistical functions
- Access dataframes using string-based column names, not integer indices
Related Skills
- Upstream: experiment-code, experiment-design
- Downstream: table-generation, figure-generation, backward-traceability
- See also: math-reasoning
Data Analysis Review Prompts
Extracted from data-to-paper (hypothesis_testing/coding/analysis/coding.py) and AgentLaboratory.
4-Round Code Review System (data-to-paper)
Round 1: Fundamental Code Flaws
### CHECK FOR FUNDAMENTAL FLAWS:
Check for any fundamental mathematical or statistical flaws in the code.
### CHECK FOR WRONG CALCULATIONS:
Explicitly list all key calculations and assess them.
### CHECK FOR MATH TRIVIALITIES:
Check for any mathematically trivial assessments / statistical tests.
For example, testing whether a value is different from zero when it is
defined as a sum of positive values.
### OTHER ISSUES:
Any other issues you find in the code.Round 2: Data Handling Issues
### DATASET PREPARATIONS:
- Missing values: Are missing values handled correctly?
- Units: Are units consistent and correctly converted?
- Data restriction: Is data appropriately filtered/restricted?
### DESCRIPTIVE STATISTICS:
Check for issues in descriptive statistics calculations.
### PREPROCESSING:
Review data preprocessing steps:
- Normalization / standardization
- Feature encoding
- Train/test split methodology
### ANALYSIS:
Check data analysis issues:
- Correct statistical test selection
- Assumptions met (normality, independence, etc.)
- Multiple comparisons correction
### STATISTICAL TESTS:
Check choice and implementation of statistical tests:
- Is the test appropriate for the data type?
- Are assumptions validated?
- Are p-values correctly computed and interpreted?Round 3: Per-Table Individual Review
### SENSIBLE NUMERIC VALUES:
Check each numeric value in the table:
- Are values within expected ranges?
- Do percentages sum to 100% where expected?
- Are decimal places appropriate?
### MEASURES OF UNCERTAINTY:
Does the table report measures of uncertainty?
- p-values for statistical tests
- Confidence intervals for estimates
- Standard deviations for means
### MISSING DATA:
Are we missing key variables or important results?
### OTHER ISSUES:
Any other issues you find in the table.Note: This round runs individually for each output file (df_.pkl).*
Round 4: Cross-Table Completeness
### COMPLETENESS OF TABLES:
Does the code create all needed results for the hypothesis testing plan?
### CONSISTENCY ACROSS TABLES:
Are tables consistent in:
- Variable naming conventions
- Measures of uncertainty reported
- Decimal precision
- Statistical test choices
### MISSING DATA:
Are we missing key variables or measures of uncertainty
that should be reported for a complete analysis?Allowed Packages Whitelist (data-to-paper)
ALLOWED_PACKAGES = [
'pandas',
'numpy',
'scipy',
'statsmodels',
'sklearn',
'pingouin', # For ANOVA and post-hoc tests
'matplotlib', # For diagnostic plots only
]Statistical Test Selection Guide
Select the appropriate statistical test based on:
| Data Type | Groups | Test |
|-----------|--------|------|
| Continuous, normal, 2 groups | Independent | Independent t-test |
| Continuous, normal, 2 groups | Paired | Paired t-test |
| Continuous, non-normal, 2 groups | Independent | Mann-Whitney U |
| Continuous, normal, 3+ groups | Independent | One-way ANOVA |
| Continuous, non-normal, 3+ groups | Independent | Kruskal-Wallis |
| Categorical, 2 variables | Independent | Chi-square test |
| Continuous, 2 variables | Correlation | Pearson/Spearman |
| Binary outcome | Multiple predictors | Logistic regression |
Always check assumptions before applying parametric tests:
1. Normality (Shapiro-Wilk test)
2. Homogeneity of variance (Levene's test)
3. Independence of observationsResults Interpretation Dialogue (AgentLaboratory)
Postdoc guides PhD to extract insights:
1. "What are the key findings from the results?"
2. "Are there any surprising or unexpected results?"
3. "How do results compare to baselines?"
4. "What is the statistical significance of improvements?"
5. "Are there any failure cases or limitations?"
6. "What patterns do you observe across datasets?"#!/usr/bin/env python3
"""Format p-values for academic papers.
Formats p-values with proper precision, significance stars,
and LaTeX-compatible output.
Self-contained: uses only stdlib.
Extracted from data-to-paper's pvalue.py formatting utilities.
Usage:
python format_pvalue.py --values "0.001 0.05 0.23" --format stars
python format_pvalue.py --values "0.0001 0.03 0.5" --format latex
python format_pvalue.py --values "1e-8 0.01 0.1" --format text
python format_pvalue.py --csv results.csv --column pvalue --format stars
"""
import argparse
import csv
import json
import sys
P_VALUE_MIN = 1e-6
DEFAULT_LEVELS = (0.05, 0.01, 0.001)
def format_p_value(p: float, min_val: float = P_VALUE_MIN,
smaller_than: str = "<") -> str:
"""Format a p-value to a string with appropriate precision."""
if not isinstance(p, (int, float)):
return str(p)
if p < 0 or p > 1:
return f"invalid({p})"
if p >= min_val:
return f"{p:.3g}"
return f"{smaller_than}{min_val}"
def format_p_value_latex(p: float, min_val: float = P_VALUE_MIN) -> str:
"""Format a p-value for LaTeX output."""
if p >= min_val:
return f"${p:.3g}$"
return f"$<${min_val}"
def p_to_stars(p: float, levels: tuple = DEFAULT_LEVELS) -> str:
"""Convert p-value to significance stars.
Default levels: * p<0.05, ** p<0.01, *** p<0.001
"""
if p < levels[2]:
return "***"
if p < levels[1]:
return "**"
if p < levels[0]:
return "*"
return "ns"
def stars_legend(levels: tuple = DEFAULT_LEVELS) -> str:
"""Generate a legend string for significance stars."""
parts = [f"ns p >= {levels[0]}"]
symbols = ["*", "**", "***"]
for i, level in enumerate(levels):
parts.append(f"{symbols[i]} p < {level}")
return ", ".join(parts)
def format_comparison(name1: str, name2: str, p: float,
fmt: str = "text") -> str:
"""Format a comparison result with p-value."""
if fmt == "stars":
return f"{name1} vs {name2}: p={format_p_value(p)} {p_to_stars(p)}"
elif fmt == "latex":
star = p_to_stars(p)
pstr = format_p_value_latex(p)
return f"{name1} vs {name2}: {pstr} {star}"
else:
return f"{name1} vs {name2}: p={format_p_value(p)}"
def main():
parser = argparse.ArgumentParser(description="Format p-values for academic papers")
parser.add_argument("--values", help="Space-separated p-values")
parser.add_argument("--csv", help="CSV file with p-values")
parser.add_argument("--column", default="pvalue", help="Column name in CSV (default: pvalue)")
parser.add_argument("--format", choices=["text", "stars", "latex", "json"],
default="text", help="Output format (default: text)")
parser.add_argument("--levels", help="Significance levels (comma-separated, default: 0.05,0.01,0.001)")
parser.add_argument("--output", "-o", help="Output file")
args = parser.parse_args()
levels = DEFAULT_LEVELS
if args.levels:
levels = tuple(float(x) for x in args.levels.split(","))
p_values = []
if args.values:
for v in args.values.split():
try:
p_values.append(float(v))
except ValueError:
print(f"Warning: skipping invalid value '{v}'", file=sys.stderr)
elif args.csv:
with open(args.csv, encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
try:
p_values.append(float(row[args.column]))
except (ValueError, KeyError):
pass
else:
print("Error: specify --values or --csv", file=sys.stderr)
sys.exit(1)
if not p_values:
print("No valid p-values found.", file=sys.stderr)
sys.exit(1)
results = []
for p in p_values:
entry = {"p_value": p}
entry["formatted"] = format_p_value(p)
entry["stars"] = p_to_stars(p, levels)
entry["latex"] = format_p_value_latex(p)
results.append(entry)
output_lines = []
if args.format == "json":
output_lines.append(json.dumps(results, indent=2))
elif args.format == "stars":
for r in results:
output_lines.append(f"p={r['formatted']} {r['stars']}")
output_lines.append(f"\nLegend: {stars_legend(levels)}")
elif args.format == "latex":
for r in results:
output_lines.append(f"{r['latex']} {r['stars']}")
else:
for r in results:
output_lines.append(f"p = {r['formatted']}")
text = "\n".join(output_lines) + "\n"
if args.output:
with open(args.output, "w", encoding="utf-8") as f:
f.write(text)
print(f"Written to {args.output}", file=sys.stderr)
else:
sys.stdout.write(text)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""Statistical summary and comparison of experimental results.
Takes experiment results in CSV/JSON, detects data types, recommends
statistical tests, runs comparisons, and outputs formatted results.
Requires: numpy, scipy
Usage:
python stat_summary.py --input results.csv --compare method --metric accuracy --output summary.json
python stat_summary.py --input results.json --compare model --metric f1_score
python stat_summary.py --input results.csv --describe
"""
import argparse
import csv
import json
import math
import os
import sys
try:
import numpy as np
from scipy import stats
except ImportError:
print("Error: numpy and scipy required. Install: pip install numpy scipy", file=sys.stderr)
sys.exit(1)
def load_data(path: str) -> list[dict]:
"""Load data from CSV or JSON."""
ext = os.path.splitext(path)[1].lower()
if ext == ".csv":
with open(path, encoding="utf-8") as f:
reader = csv.DictReader(f)
return list(reader)
elif ext == ".json":
with open(path, encoding="utf-8") as f:
data = json.load(f)
if isinstance(data, list):
return data
raise ValueError("JSON must be a list of records")
else:
raise ValueError(f"Unsupported format: {ext}")
def detect_numeric_columns(data: list[dict]) -> list[str]:
"""Detect which columns contain numeric data."""
if not data:
return []
numeric = []
for key in data[0].keys():
try:
vals = [float(row[key]) for row in data if row.get(key, "") != ""]
if len(vals) > len(data) * 0.5:
numeric.append(key)
except (ValueError, TypeError):
pass
return numeric
def get_column_values(data: list[dict], col: str) -> list[float]:
"""Extract numeric values from a column."""
vals = []
for row in data:
try:
vals.append(float(row[col]))
except (ValueError, TypeError, KeyError):
pass
return vals
def describe_column(values: list[float]) -> dict:
"""Compute descriptive statistics for a numeric column."""
arr = np.array(values)
return {
"count": len(arr),
"mean": float(np.mean(arr)),
"std": float(np.std(arr, ddof=1)) if len(arr) > 1 else 0.0,
"min": float(np.min(arr)),
"q25": float(np.percentile(arr, 25)),
"median": float(np.median(arr)),
"q75": float(np.percentile(arr, 75)),
"max": float(np.max(arr)),
}
def recommend_test(groups: list[list[float]]) -> str:
"""Recommend a statistical test based on the data."""
n_groups = len(groups)
if n_groups < 2:
return "none"
# Check normality (Shapiro-Wilk for each group)
all_normal = True
for g in groups:
if len(g) < 3:
all_normal = False
break
if len(g) <= 5000:
_, p = stats.shapiro(g)
if p < 0.05:
all_normal = False
break
if n_groups == 2:
# Check if paired (same length)
if len(groups[0]) == len(groups[1]):
return "paired_ttest" if all_normal else "wilcoxon"
return "independent_ttest" if all_normal else "mann_whitney"
else:
return "anova" if all_normal else "kruskal_wallis"
def run_comparison(groups: dict[str, list[float]], test: str) -> dict:
"""Run a statistical comparison between groups."""
group_names = list(groups.keys())
group_values = list(groups.values())
result = {
"test": test,
"groups": {name: describe_column(vals) for name, vals in groups.items()},
}
if test == "independent_ttest" and len(group_values) == 2:
stat, p = stats.ttest_ind(group_values[0], group_values[1])
result["statistic"] = float(stat)
result["p_value"] = float(p)
elif test == "paired_ttest" and len(group_values) == 2:
stat, p = stats.ttest_rel(group_values[0], group_values[1])
result["statistic"] = float(stat)
result["p_value"] = float(p)
elif test == "mann_whitney" and len(group_values) == 2:
stat, p = stats.mannwhitneyu(group_values[0], group_values[1], alternative='two-sided')
result["statistic"] = float(stat)
result["p_value"] = float(p)
elif test == "wilcoxon" and len(group_values) == 2:
stat, p = stats.wilcoxon(group_values[0], group_values[1])
result["statistic"] = float(stat)
result["p_value"] = float(p)
elif test == "anova":
stat, p = stats.f_oneway(*group_values)
result["statistic"] = float(stat)
result["p_value"] = float(p)
elif test == "kruskal_wallis":
stat, p = stats.kruskal(*group_values)
result["statistic"] = float(stat)
result["p_value"] = float(p)
# Effect size (Cohen's d for two groups)
if len(group_values) == 2:
n1, n2 = len(group_values[0]), len(group_values[1])
m1, m2 = np.mean(group_values[0]), np.mean(group_values[1])
s1, s2 = np.std(group_values[0], ddof=1), np.std(group_values[1], ddof=1)
pooled_std = math.sqrt(((n1 - 1) * s1**2 + (n2 - 1) * s2**2) / (n1 + n2 - 2))
if pooled_std > 0:
result["cohens_d"] = float((m1 - m2) / pooled_std)
# Significance stars
if "p_value" in result:
p = result["p_value"]
if p < 0.001:
result["significance"] = "***"
elif p < 0.01:
result["significance"] = "**"
elif p < 0.05:
result["significance"] = "*"
else:
result["significance"] = "ns"
return result
def pairwise_comparisons(groups: dict[str, list[float]]) -> list[dict]:
"""Run pairwise comparisons between all groups."""
names = list(groups.keys())
results = []
for i in range(len(names)):
for j in range(i + 1, len(names)):
pair = {names[i]: groups[names[i]], names[j]: groups[names[j]]}
test = recommend_test(list(pair.values()))
comp = run_comparison(pair, test)
comp["pair"] = [names[i], names[j]]
results.append(comp)
return results
def main():
parser = argparse.ArgumentParser(description="Statistical summary of experimental results")
parser.add_argument("--input", required=True, help="Input file (.csv or .json)")
parser.add_argument("--compare", help="Column to group by for comparison")
parser.add_argument("--metric", help="Metric column to compare")
parser.add_argument("--describe", action="store_true", help="Show descriptive statistics only")
parser.add_argument("--pairwise", action="store_true", help="Run all pairwise comparisons")
parser.add_argument("--output", "-o", help="Output JSON file")
args = parser.parse_args()
data = load_data(args.input)
if not data:
print("No data loaded.", file=sys.stderr)
sys.exit(1)
numeric_cols = detect_numeric_columns(data)
if args.describe:
result = {"columns": {}}
for col in numeric_cols:
vals = get_column_values(data, col)
result["columns"][col] = describe_column(vals)
print(f"Descriptive statistics for {len(numeric_cols)} numeric columns:", file=sys.stderr)
elif args.compare and args.metric:
# Group by compare column
groups = {}
for row in data:
group = str(row.get(args.compare, "unknown"))
val = row.get(args.metric)
try:
val = float(val)
except (ValueError, TypeError):
continue
groups.setdefault(group, []).append(val)
if len(groups) < 2:
print(f"Need at least 2 groups, found {len(groups)}", file=sys.stderr)
sys.exit(1)
test = recommend_test(list(groups.values()))
print(f"Groups: {list(groups.keys())}", file=sys.stderr)
print(f"Recommended test: {test}", file=sys.stderr)
result = run_comparison(groups, test)
if args.pairwise and len(groups) > 2:
result["pairwise"] = pairwise_comparisons(groups)
else:
print("Error: specify --describe or both --compare and --metric", file=sys.stderr)
sys.exit(1)
output = json.dumps(result, indent=2, ensure_ascii=False)
if args.output:
with open(args.output, "w", encoding="utf-8") as f:
f.write(output)
print(f"Written to {args.output}", file=sys.stderr)
else:
print(output)
if __name__ == "__main__":
main()