| name | data-analysis |
| description | Analyze data files and produce summary statistics with real commands |
Data Analysis
When to Use
Use this skill when tasked with analyzing data files (CSV, JSON, JSONL, TSV, logs) to extract insights, compute statistics, or identify patterns.
Procedure
1. Inspect the Data
DATA_FILE="${1:-/home/shared/data.csv}"
echo "=== File Info ==="
file "$DATA_FILE"
ls -lh "$DATA_FILE"
echo ""
echo "=== First 10 lines ==="
head -10 "$DATA_FILE"
echo ""
echo "=== Line count ==="
wc -l "$DATA_FILE"
For CSV files:
echo "=== Column count ==="
head -1 "$DATA_FILE" | awk -F',' '{print NF, "columns"}'
echo ""
echo "=== Headers ==="
head -1 "$DATA_FILE" | tr ',' '\n' | nl
echo ""
echo "=== Sample rows ==="
head -5 "$DATA_FILE" | column -t -s','
For JSON files:
echo "=== Structure ==="
jq 'if type == "array" then length, (.[0] | keys) else keys end' "$DATA_FILE"
echo ""
echo "=== Record count ==="
jq 'if type == "array" then length else 1 end' "$DATA_FILE"
echo ""
echo "=== First record ==="
jq 'if type == "array" then .[0] else . end' "$DATA_FILE"
For JSONL files:
echo "=== Record count ==="
wc -l "$DATA_FILE"
echo ""
echo "=== Fields ==="
head -1 "$DATA_FILE" | jq 'keys'
echo ""
echo "=== First 3 records ==="
head -3 "$DATA_FILE" | jq .
2. Validate Data Quality
echo "=== Data Quality Checks ==="
echo "--- Empty fields per column ---"
awk -F',' '
NR==1 { for(i=1;i<=NF;i++) header[i]=$i; next }
{
for(i=1;i<=NF;i++) {
if($i == "" || $i == "null" || $i == "NULL") empty[i]++
}
total++
}
END {
for(i=1;i<=length(header);i++)
if(empty[i]>0) printf "%s: %d empty (%.1f%%)\n", header[i], empty[i], empty[i]*100/total
}' "$DATA_FILE"
echo ""
echo "--- Duplicate rows ---"
sort "$DATA_FILE" | uniq -d | wc -l | xargs -I{} echo "{} duplicate rows"
echo ""
echo "--- Duplicate keys (first column) ---"
awk -F',' 'NR>1{print $1}' "$DATA_FILE" | sort | uniq -d | head -5
For JSON:
echo "--- Null fields ---"
jq '[.[] | to_entries[] | select(.value == null) | .key] | group_by(.) | map({key: .[0], count: length})' "$DATA_FILE" 2>/dev/null
echo "--- Empty strings ---"
jq '[.[] | to_entries[] | select(.value == "") | .key] | group_by(.) | map({key: .[0], count: length})' "$DATA_FILE" 2>/dev/null
3. Compute Summary Statistics
Numeric columns (CSV with awk):
COL=3
HEADER=$(head -1 "$DATA_FILE" | cut -d',' -f$COL)
echo "=== Statistics for column $COL ($HEADER) ==="
awk -F',' -v col=$COL '
NR > 1 && $col != "" {
n++
sum += $col
if(n==1 || $col < min) min = $col
if(n==1 || $col > max) max = $col
vals[n] = $col
}
END {
if(n==0) { print "No numeric values"; exit }
mean = sum/n
# Sort for median
for(i=1;i<=n;i++) sorted[i] = vals[i]
for(i=1;i<=n;i++) for(j=i+1;j<=n;j++) if(sorted[i]>sorted[j]) { t=sorted[i]; sorted[i]=sorted[j]; sorted[j]=t }
median = (n%2==1) ? sorted[int(n/2)+1] : (sorted[n/2]+sorted[n/2+1])/2
printf " Count: %d\n Sum: %.2f\n Mean: %.2f\n Median: %.2f\n Min: %.2f\n Max: %.2f\n", n, sum, mean, median, min, max
}' "$DATA_FILE"
Categorical columns (CSV):
COL=2
HEADER=$(head -1 "$DATA_FILE" | cut -d',' -f$COL)
echo "=== Value counts for column $COL ($HEADER) ==="
awk -F',' -v col=$COL 'NR>1{print $col}' "$DATA_FILE" \
| sort | uniq -c | sort -rn | head -20
JSON statistics:
FIELD="amount"
echo "=== Statistics for field: $FIELD ==="
jq --arg f "$FIELD" '
[.[] | .[$f] | select(. != null and type == "number")] |
{
count: length,
sum: add,
mean: (add / length),
min: min,
max: max,
sorted: sort | {
median: (if length % 2 == 1 then .[length/2 | floor] else (.[length/2 - 1] + .[length/2]) / 2 end)
}
} | {count, sum, mean, min, max, median: .sorted.median}
' "$DATA_FILE"
4. Complex Analysis with Python
For analysis beyond what awk/jq can do:
python3 <<'PYEOF'
import csv
import json
import sys
from collections import Counter
from statistics import mean, median, stdev
with open("/home/shared/data.csv") as f:
reader = csv.DictReader(f)
rows = list(reader)
print(f"Records: {len(rows)}")
print(f"Fields: {list(rows[0].keys())}")
field = "amount"
values = [float(r[field]) for r in rows if r[field]]
print(f"\n{field}:")
print(f" Count: {len(values)}")
print(f" Mean: {mean(values):.2f}")
print(f" Median: {median(values):.2f}")
print(f" Stdev: {stdev(values):.2f}")
print(f" Min: {min(values):.2f}")
print(f" Max: {max(values):.2f}")
field = "status"
counts = Counter(r[field] for r in rows)
print(f"\n{field} distribution:")
for val, count in counts.most_common(10):
pct = count / len(rows) * 100
print(f" {val}: {count} ({pct:.1f}%)")
PYEOF
5. Write the Report
REPORT_FILE="/home/shared/analysis-$(date +%Y%m%d)-$(basename "$DATA_FILE" | sed 's/\..*//')\.md"
cat > "$REPORT_FILE" <<'EOF'
**Date:** YYYY-MM-DD
**Data Source:** [file path]
**Analyst:** [agent name]
| Metric | Value |
|--------|-------|
| Records | N |
| Fields | N |
| File Size | N KB |
| Empty Values | N (N%) |
| Duplicates | N |
1. [Most significant finding]
2. [Second finding]
3. [Third finding]
| Field | Count | Mean | Median | Min | Max | Stdev |
|-------|-------|------|--------|-----|-----|-------|
| ... | ... | ... | ... | ... | ... | ... |
[Top values for categorical fields]
- [Issue 1]
- [Issue 2]
[Commands and tools used for analysis]
EOF
bash /home/shared/scripts/artifact.sh register \
--name "analysis-$(basename "$DATA_FILE" | sed 's/\..*//')" \
--type "report" \
--path "$REPORT_FILE" \
--description "Data analysis of $DATA_FILE"
Quality Checklist