Data Wrangler
Manipulate tabular data (CSV, Excel, JSON, Parquet, TSV) w/ pandas-powered scripts. Two scripts cover all operations: data_wrangler.py for data ops, excel_toolkit.py for Excel-specific features.
When to Use
- User asks to read, edit, filter, sort, or transform CSV/Excel/JSON/Parquet/TSV files
- User asks to merge/join datasets, deduplicate, fill missing values, or validate data
- User asks to create Excel workbooks w/ formatting, dropdowns, freeze panes, or multi-sheet
- User asks to pivot, unpivot, group-by, aggregate, sample, or split datasets
- User asks to add computed columns, rename columns, cast types, or apply formulas
- User asks to convert between data formats (CSV -> Excel, JSON -> Parquet, etc.)
- User asks to inspect/profile data structure, types, nulls, stats
Prerequisites
# Required
pip install pandas openpyxl
# Optional (per feature)
pip install pyarrow # Parquet support
pip install xlrd # Legacy .xls read
pip install pandasql # SQL queries on DataFrames
pip install fastparquet # Alternative Parquet engine
Quick Routing
| Task |
Script |
Command |
| Inspect/profile data |
data_wrangler.py |
inspect |
| Filter rows |
data_wrangler.py |
filter --where "expr" |
| Sort by columns |
data_wrangler.py |
sort --by Col --desc |
| Group & aggregate |
data_wrangler.py |
group --by Col --agg "Col:func" |
| Merge/join files |
data_wrangler.py |
merge f2 --on Key --how left |
| Pivot / unpivot |
data_wrangler.py |
pivot --index/--unpivot |
| Remove duplicates |
data_wrangler.py |
dedupe --subset "Col" |
| Fill missing values |
data_wrangler.py |
fill --column Col --strategy mean |
| Drop cols/rows |
data_wrangler.py |
drop --columns "A,B" |
| Rename columns |
data_wrangler.py |
rename --map "old:new" |
| Cast types |
data_wrangler.py |
cast --column Col --dtype datetime |
| Computed columns |
data_wrangler.py |
derive --formula "New = A + B" |
| Random sample |
data_wrangler.py |
sample --n 100 |
| Split by values |
data_wrangler.py |
split --by Region |
| Validate rules |
data_wrangler.py |
validate --rules rules.json |
| Apply formulas |
data_wrangler.py |
formula --expr "C=A+B" |
| Convert formats |
data_wrangler.py |
convert -o data.xlsx |
| SQL queries |
data_wrangler.py |
query --sql "SELECT..." |
| List Excel sheets |
excel_toolkit.py |
sheets |
| Extract sheet |
excel_toolkit.py |
extract --sheet Sales -o sales.csv |
| Combine -> xlsx |
excel_toolkit.py |
combine *.csv -o combined.xlsx |
| Format headers |
excel_toolkit.py |
format --header-style bold,blue --autowidth |
| Freeze panes |
excel_toolkit.py |
freeze --at B2 |
| Auto-filter |
excel_toolkit.py |
autofilter |
| Dropdown validation |
excel_toolkit.py |
validate --column Status --values "Open,Closed" |
| Protect sheet |
excel_toolkit.py |
protect --password secret |
| Create workbook |
excel_toolkit.py |
create --columns "Name,Age" -o template.xlsx |
Usage Patterns
Data Operations (data_wrangler.py)
All operations follow: python3 scripts/data_wrangler.py <op> <input> [options] [-o output]
# Inspect
python3 data_wrangler.py inspect sales.csv
python3 data_wrangler.py inspect data.xlsx --sheet "Q1 Sales" --nrows 1000
# Filter
python3 data_wrangler.py filter data.csv --where "Revenue > 10000" -o high_rev.csv
python3 data_wrangler.py filter data.csv --where 'Status == "active" and Age >= 25' -o active.csv
# Sort
python3 data_wrangler.py sort data.csv --by "Revenue,Name" --desc -o sorted.csv
# Group + Aggregate
python3 data_wrangler.py group data.csv --by Department --agg "Salary:mean,Salary:count,Revenue:sum" -o summary.csv
# Merge
python3 data_wrangler.py merge orders.csv customers.csv --on CustomerID --how left -o joined.csv
# Pivot
python3 data_wrangler.py pivot data.csv --index Name --columns Month --values Sales --aggfunc sum -o pivoted.csv
# Unpivot (melt)
python3 data_wrangler.py pivot wide.csv --index ID --unpivot --var-name Metric --value-name Value -o long.csv
# Deduplicate
python3 data_wrangler.py dedupe data.csv --subset "Email" --keep first -o clean.csv
# Fill nulls
python3 data_wrangler.py fill data.csv --column "Revenue,Profit" --strategy mean -o filled.csv
# Drop columns
python3 data_wrangler.py drop data.csv --columns "TempCol,Notes" -o trimmed.csv
python3 data_wrangler.py drop data.csv --null-threshold 0.5 -o cleaned.csv
# Rename
python3 data_wrangler.py rename data.csv --map "old_name:new_name,col2:Column2" -o renamed.csv
python3 data_wrangler.py rename data.csv --snake -o snake_case.csv
# Cast types
python3 data_wrangler.py cast data.csv --column Date --dtype datetime --date-format "%Y-%m-%d" -o typed.csv
# Computed columns
python3 data_wrangler.py derive data.csv --formula "Profit = Revenue - Cost" -o enriched.csv
# Sample
python3 data_wrangler.py sample large.csv --n 500 --seed 42 -o sample.csv
# Split by value
python3 data_wrangler.py split data.csv --by Region --output-dir ./by_region/
# Validate
python3 data_wrangler.py validate data.csv --rules validation_rules.json -o report.json
# Formula
python3 data_wrangler.py formula data.xlsx --expr "Total=Price*Quantity" -o calculated.xlsx
# Convert
python3 data_wrangler.py convert data.csv -o data.xlsx
python3 data_wrangler.py convert data.xlsx -o data.json
python3 data_wrangler.py convert data.json -o data.parquet
# SQL query
python3 data_wrangler.py query data.csv --sql "SELECT Name, AVG(Salary) FROM df WHERE Dept='Eng' GROUP BY Name"
Excel Operations (excel_toolkit.py)
All operations follow: python3 scripts/excel_toolkit.py <op> <input> [options] [-o output]
# List sheets
python3 excel_toolkit.py sheets workbook.xlsx
# Extract sheet
python3 excel_toolkit.py extract workbook.xlsx --sheet "Sales Q1" -o sales_q1.csv
# Combine multiple files into multi-sheet xlsx
python3 excel_toolkit.py combine sales.csv inventory.csv orders.csv -o report.xlsx
# Format
python3 excel_toolkit.py format data.xlsx --header-style bold,blue --autowidth --zebra -o styled.xlsx
# Freeze panes
python3 excel_toolkit.py freeze data.xlsx --at B2 -o frozen.xlsx
# Auto-filter
python3 excel_toolkit.py autofilter data.xlsx -o filtered.xlsx
# Dropdown validation
python3 excel_toolkit.py validate data.xlsx --column Status --values "Open,Closed,Pending" -o validated.xlsx
# Protect
python3 excel_toolkit.py protect data.xlsx --password mypass -o protected.xlsx
# Create template
python3 excel_toolkit.py create --columns "Name,Email,Department,Start Date,Salary" -o template.xlsx
Validation Rules Format
Create a JSON rules file for validate:
{
"rules": [
{"column": "Email", "type": "not_null"},
{"column": "Email", "type": "pattern", "regex": "^[^@]+@[^@]+\\.[^@]+$"},
{"column": "ID", "type": "unique"},
{"column": "Age", "type": "range", "min": 0, "max": 150},
{"column": "Status", "type": "enum", "values": ["active", "inactive", "pending"]}
]
}
Rule types: not_null, unique, range (min/max), pattern (regex), enum (allowed values).
Fill Strategies
| Strategy |
Behavior |
mean |
Fill w/ column mean (numeric) |
median |
Fill w/ column median (numeric) |
mode |
Fill w/ most frequent value |
zero |
Fill w/ 0 |
empty |
Fill w/ empty string |
ffill |
Forward fill (carry last value) |
bfill |
Backward fill |
drop |
Drop rows w/ nulls in column |
value:<v> |
Fill w/ specific value |
Supported Formats
| Format |
Read |
Write |
Dependency |
| CSV |
Y |
Y |
(builtin) |
| TSV |
Y |
Y |
(builtin) |
| XLSX |
Y |
Y |
openpyxl |
| XLS |
Y |
N |
xlrd |
| JSON |
Y |
Y |
(builtin) |
| JSONL |
Y |
Y |
(builtin) |
| Parquet |
Y |
Y |
pyarrow |
Integration w/ file-converter
Pipeline data between skills:
# 1. Convert YAML -> CSV (file-converter), then wrangle
python3 .claude/skills/file-converter/scripts/csv_json_yaml.py data.yaml data.csv
python3 .claude/skills/data-wrangler/scripts/data_wrangler.py filter data.csv --where "Status == 'active'" -o filtered.csv
# 2. Wrangle, then convert to PDF report
python3 data_wrangler.py group data.csv --by Dept --agg "Salary:mean,count" -o summary.csv
# (Use file-converter to render summary as markdown -> PDF)
# 3. Excel -> JSON -> YAML pipeline
python3 data_wrangler.py convert data.xlsx -o data.json
python3 .claude/skills/file-converter/scripts/csv_json_yaml.py data.json data.yaml
Pandas Query Syntax Reference
Filter expressions use pandas query syntax:
| Pattern |
Example |
| Comparison |
Age > 30, Revenue >= 10000 |
| Equality |
Status == "active", Region != "East" |
| String contains |
Name.str.contains("Smith") |
| Multiple conditions |
Age > 25 and Status == "active" |
| OR conditions |
Region == "East" or Region == "West" |
| IN list |
Status in ["active", "pending"] |
| NOT IN |
Status not in ["closed", "archived"] |
| Null check |
Revenue.notna(), Email.isna() |
| Between |
Age >= 18 and Age <= 65 |
Aggregation Functions
Available for group --agg and pivot --aggfunc:
sum, mean, median, min, max, count, std, var, first, last, nunique
Spec format: "Column:function" — multiple: "Salary:mean,Salary:count,Revenue:sum"
1---2name: data-wrangler3description: Production-grade tabular data manipulation using pandas & openpyxl. This skill should be used when editing, creating, filtering, sorting, merging, pivoting, deduplicating, validating, or transforming CSV, Excel (xlsx/xls), JSON, Parquet, or TSV files. Supports 18 operations via CLI scripts, advanced Excel formatting (multi-sheet, freeze, auto-filter, validation, styling), and file-converter integration for format pipelines.4---56# Data Wrangler78Manipulate tabular data (CSV, Excel, JSON, Parquet, TSV) w/ pandas-powered scripts. Two scripts cover all operations: `data_wrangler.py` for data ops, `excel_toolkit.py` for Excel-specific features.910## When to Use1112- User asks to read, edit, filter, sort, or transform CSV/Excel/JSON/Parquet/TSV files13- User asks to merge/join datasets, deduplicate, fill missing values, or validate data14- User asks to create Excel workbooks w/ formatting, dropdowns, freeze panes, or multi-sheet15- User asks to pivot, unpivot, group-by, aggregate, sample, or split datasets16- User asks to add computed columns, rename columns, cast types, or apply formulas17- User asks to convert between data formats (CSV -> Excel, JSON -> Parquet, etc.)18- User asks to inspect/profile data structure, types, nulls, stats1920## Prerequisites2122```bash23# Required24pip install pandas openpyxl2526# Optional (per feature)27pip install pyarrow # Parquet support28pip install xlrd # Legacy .xls read29pip install pandasql # SQL queries on DataFrames30pip install fastparquet # Alternative Parquet engine31```3233## Quick Routing3435| Task | Script | Command |36|------|--------|---------|37| Inspect/profile data | `data_wrangler.py` | `inspect` |38| Filter rows | `data_wrangler.py` | `filter --where "expr"` |39| Sort by columns | `data_wrangler.py` | `sort --by Col --desc` |40| Group & aggregate | `data_wrangler.py` | `group --by Col --agg "Col:func"` |41| Merge/join files | `data_wrangler.py` | `merge f2 --on Key --how left` |42| Pivot / unpivot | `data_wrangler.py` | `pivot --index/--unpivot` |43| Remove duplicates | `data_wrangler.py` | `dedupe --subset "Col"` |44| Fill missing values | `data_wrangler.py` | `fill --column Col --strategy mean` |45| Drop cols/rows | `data_wrangler.py` | `drop --columns "A,B"` |46| Rename columns | `data_wrangler.py` | `rename --map "old:new"` |47| Cast types | `data_wrangler.py` | `cast --column Col --dtype datetime` |48| Computed columns | `data_wrangler.py` | `derive --formula "New = A + B"` |49| Random sample | `data_wrangler.py` | `sample --n 100` |50| Split by values | `data_wrangler.py` | `split --by Region` |51| Validate rules | `data_wrangler.py` | `validate --rules rules.json` |52| Apply formulas | `data_wrangler.py` | `formula --expr "C=A+B"` |53| Convert formats | `data_wrangler.py` | `convert -o data.xlsx` |54| SQL queries | `data_wrangler.py` | `query --sql "SELECT..."` |55| List Excel sheets | `excel_toolkit.py` | `sheets` |56| Extract sheet | `excel_toolkit.py` | `extract --sheet Sales -o sales.csv` |57| Combine -> xlsx | `excel_toolkit.py` | `combine *.csv -o combined.xlsx` |58| Format headers | `excel_toolkit.py` | `format --header-style bold,blue --autowidth` |59| Freeze panes | `excel_toolkit.py` | `freeze --at B2` |60| Auto-filter | `excel_toolkit.py` | `autofilter` |61| Dropdown validation | `excel_toolkit.py` | `validate --column Status --values "Open,Closed"` |62| Protect sheet | `excel_toolkit.py` | `protect --password secret` |63| Create workbook | `excel_toolkit.py` | `create --columns "Name,Age" -o template.xlsx` |6465## Usage Patterns6667### Data Operations (`data_wrangler.py`)6869All operations follow: `python3 scripts/data_wrangler.py <op> <input> [options] [-o output]`7071```bash72# Inspect73python3 data_wrangler.py inspect sales.csv74python3 data_wrangler.py inspect data.xlsx --sheet "Q1 Sales" --nrows 10007576# Filter77python3 data_wrangler.py filter data.csv --where "Revenue > 10000" -o high_rev.csv78python3 data_wrangler.py filter data.csv --where 'Status == "active" and Age >= 25' -o active.csv7980# Sort81python3 data_wrangler.py sort data.csv --by "Revenue,Name" --desc -o sorted.csv8283# Group + Aggregate84python3 data_wrangler.py group data.csv --by Department --agg "Salary:mean,Salary:count,Revenue:sum" -o summary.csv8586# Merge87python3 data_wrangler.py merge orders.csv customers.csv --on CustomerID --how left -o joined.csv8889# Pivot90python3 data_wrangler.py pivot data.csv --index Name --columns Month --values Sales --aggfunc sum -o pivoted.csv9192# Unpivot (melt)93python3 data_wrangler.py pivot wide.csv --index ID --unpivot --var-name Metric --value-name Value -o long.csv9495# Deduplicate96python3 data_wrangler.py dedupe data.csv --subset "Email" --keep first -o clean.csv9798# Fill nulls99python3 data_wrangler.py fill data.csv --column "Revenue,Profit" --strategy mean -o filled.csv100101# Drop columns102python3 data_wrangler.py drop data.csv --columns "TempCol,Notes" -o trimmed.csv103python3 data_wrangler.py drop data.csv --null-threshold 0.5 -o cleaned.csv104105# Rename106python3 data_wrangler.py rename data.csv --map "old_name:new_name,col2:Column2" -o renamed.csv107python3 data_wrangler.py rename data.csv --snake -o snake_case.csv108109# Cast types110python3 data_wrangler.py cast data.csv --column Date --dtype datetime --date-format "%Y-%m-%d" -o typed.csv111112# Computed columns113python3 data_wrangler.py derive data.csv --formula "Profit = Revenue - Cost" -o enriched.csv114115# Sample116python3 data_wrangler.py sample large.csv --n 500 --seed 42 -o sample.csv117118# Split by value119python3 data_wrangler.py split data.csv --by Region --output-dir ./by_region/120121# Validate122python3 data_wrangler.py validate data.csv --rules validation_rules.json -o report.json123124# Formula125python3 data_wrangler.py formula data.xlsx --expr "Total=Price*Quantity" -o calculated.xlsx126127# Convert128python3 data_wrangler.py convert data.csv -o data.xlsx129python3 data_wrangler.py convert data.xlsx -o data.json130python3 data_wrangler.py convert data.json -o data.parquet131132# SQL query133python3 data_wrangler.py query data.csv --sql "SELECT Name, AVG(Salary) FROM df WHERE Dept='Eng' GROUP BY Name"134```135136### Excel Operations (`excel_toolkit.py`)137138All operations follow: `python3 scripts/excel_toolkit.py <op> <input> [options] [-o output]`139140```bash141# List sheets142python3 excel_toolkit.py sheets workbook.xlsx143144# Extract sheet145python3 excel_toolkit.py extract workbook.xlsx --sheet "Sales Q1" -o sales_q1.csv146147# Combine multiple files into multi-sheet xlsx148python3 excel_toolkit.py combine sales.csv inventory.csv orders.csv -o report.xlsx149150# Format151python3 excel_toolkit.py format data.xlsx --header-style bold,blue --autowidth --zebra -o styled.xlsx152153# Freeze panes154python3 excel_toolkit.py freeze data.xlsx --at B2 -o frozen.xlsx155156# Auto-filter157python3 excel_toolkit.py autofilter data.xlsx -o filtered.xlsx158159# Dropdown validation160python3 excel_toolkit.py validate data.xlsx --column Status --values "Open,Closed,Pending" -o validated.xlsx161162# Protect163python3 excel_toolkit.py protect data.xlsx --password mypass -o protected.xlsx164165# Create template166python3 excel_toolkit.py create --columns "Name,Email,Department,Start Date,Salary" -o template.xlsx167```168169## Validation Rules Format170171Create a JSON rules file for `validate`:172173```json174{175 "rules": [176 {"column": "Email", "type": "not_null"},177 {"column": "Email", "type": "pattern", "regex": "^[^@]+@[^@]+\\.[^@]+$"},178 {"column": "ID", "type": "unique"},179 {"column": "Age", "type": "range", "min": 0, "max": 150},180 {"column": "Status", "type": "enum", "values": ["active", "inactive", "pending"]}181 ]182}183```184185Rule types: `not_null`, `unique`, `range` (min/max), `pattern` (regex), `enum` (allowed values).186187## Fill Strategies188189| Strategy | Behavior |190|----------|----------|191| `mean` | Fill w/ column mean (numeric) |192| `median` | Fill w/ column median (numeric) |193| `mode` | Fill w/ most frequent value |194| `zero` | Fill w/ 0 |195| `empty` | Fill w/ empty string |196| `ffill` | Forward fill (carry last value) |197| `bfill` | Backward fill |198| `drop` | Drop rows w/ nulls in column |199| `value:<v>` | Fill w/ specific value |200201## Supported Formats202203| Format | Read | Write | Dependency |204|--------|------|-------|------------|205| CSV | Y | Y | (builtin) |206| TSV | Y | Y | (builtin) |207| XLSX | Y | Y | openpyxl |208| XLS | Y | N | xlrd |209| JSON | Y | Y | (builtin) |210| JSONL | Y | Y | (builtin) |211| Parquet | Y | Y | pyarrow |212213## Integration w/ file-converter214215Pipeline data between skills:216217```bash218# 1. Convert YAML -> CSV (file-converter), then wrangle219python3 .claude/skills/file-converter/scripts/csv_json_yaml.py data.yaml data.csv220python3 .claude/skills/data-wrangler/scripts/data_wrangler.py filter data.csv --where "Status == 'active'" -o filtered.csv221222# 2. Wrangle, then convert to PDF report223python3 data_wrangler.py group data.csv --by Dept --agg "Salary:mean,count" -o summary.csv224# (Use file-converter to render summary as markdown -> PDF)225226# 3. Excel -> JSON -> YAML pipeline227python3 data_wrangler.py convert data.xlsx -o data.json228python3 .claude/skills/file-converter/scripts/csv_json_yaml.py data.json data.yaml229```230231## Pandas Query Syntax Reference232233Filter expressions use pandas query syntax:234235| Pattern | Example |236|---------|---------|237| Comparison | `Age > 30`, `Revenue >= 10000` |238| Equality | `Status == "active"`, `Region != "East"` |239| String contains | `Name.str.contains("Smith")` |240| Multiple conditions | `Age > 25 and Status == "active"` |241| OR conditions | `Region == "East" or Region == "West"` |242| IN list | `Status in ["active", "pending"]` |243| NOT IN | `Status not in ["closed", "archived"]` |244| Null check | `Revenue.notna()`, `Email.isna()` |245| Between | `Age >= 18 and Age <= 65` |246247## Aggregation Functions248249Available for `group --agg` and `pivot --aggfunc`:250251`sum`, `mean`, `median`, `min`, `max`, `count`, `std`, `var`, `first`, `last`, `nunique`252253Spec format: `"Column:function"` — multiple: `"Salary:mean,Salary:count,Revenue:sum"`