Pandas data cleaning
The largest community-driven library of Agent Skills (SKILL.md + scripts/references/examples) for Claude, Codex, Gemini CLI, Cursor and friends.
npx -y skills add JayRHa/AgentSkills --skill pandas-data-cleaningAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Cleans messy tabular datasets in pandas end-to-end — fixing dtypes, parsing dates and numbers, standardizing text, handling missing values, removing duplicates, detecting and treating outliers, and reshaping wide/long into tidy data. Use this skill when the user asks to "clean this CSV/Excel/dataframe", "fix data types", "handle missing values / NaNs", "remove duplicates", "deal with outliers", "standardize column names or categories", "parse dates", "melt/pivot/reshape", or to build a reproducible cleaning pipeline before analysis or modeling.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
7.9 KB, as published. Nobody here has run it
pandas Data Cleaning
Overview
Keywords: pandas, data cleaning, dtypes, missing values, NaN, imputation, duplicates, outliers, IQR, z-score, tidy data, melt, pivot, normalize, standardize, parse dates, categorical, data quality, ETL preprocessing.
This skill turns a messy DataFrame into a tidy, correctly-typed, analysis-ready dataset using a repeatable, auditable workflow. The core principle: profile first, decide explicitly, transform with logging, validate after. Never mutate data silently — every fill, drop, or cast should be a deliberate, documented choice you can defend.
Treat cleaning as a pipeline that produces (1) the cleaned DataFrame and (2) a record of decisions. Prefer chained, non-mutating transforms (df.assign(...), .pipe(...)) over scattered in-place edits so the pipeline is reproducible top-to-bottom.
Workflow
-
Profile the raw data. Before changing anything, understand it. Run
scripts/profile_data.py <path>(or replicate inline) to get shape, dtypes, per-column null counts/percentages, unique counts, sample values, and candidate problems (mixed types, high-cardinality strings, numeric-looking objects, constant columns). Seereferences/cleaning-checklist.md. -
Fix structure. Standardize column names (snake_case, strip whitespace, dedupe). Set/verify the index. Drop fully-empty rows/columns and constant columns that carry no signal. Confirm one observation per row, one variable per column (tidy form). If not tidy, defer reshape to step 8.
-
Coerce dtypes. Convert numeric-looking strings (
"1,234","$5.00","12%") to numbers, parse dates with explicit formats, cast low-cardinality strings tocategory, and use nullable dtypes (Int64,boolean,string) where missing values must coexist with non-float types. Seereferences/dtype-conversion.md. -
Standardize text & categories. Trim whitespace, normalize case, collapse synonyms ("USA"/"U.S.A."/"United States"), fix encoding artifacts, and map free-text categories to a controlled vocabulary.
-
Handle missing values. First distinguish disguised missing (
"NA","-","unknown",-999, empty string) from real values and convert them toNaN/pd.NA. Then choose a strategy per column — drop, constant fill, statistical impute (mean/median/mode), forward/backfill for time series, or model-based — and document why. Use the decision framework below. -
Remove duplicates. Detect exact duplicates and key-based duplicates (
subset=[...]). Decide keep policy (first/last/aggregate). Watch for near-duplicates from inconsistent text (handle those in step 4 first). -
Detect & treat outliers. Use IQR fences or z-scores to flag, then decide: keep (legitimate extreme), cap/winsorize, transform (log), or remove (data error). Never delete outliers reflexively. See
references/outliers-and-reshaping.md. -
Reshape to tidy. Use
meltto go wide→long,pivot/pivot_tablefor long→wide, andstr.split/explodeto split packed columns. Confirm the result satisfies the three tidy rules. -
Validate. Re-profile. Assert invariants: expected row count range, no unexpected nulls in required columns, dtypes correct, key uniqueness, value ranges/domains. Fail loudly if violated. See the validation section in
references/cleaning-checklist.md. -
Persist the recipe. Capture the ordered transforms in a single function/notebook cell so the same raw input always yields the same clean output. Use
templates/cleaning_report.mdto summarize what was done and why.
Missing-Value Decision Framework
| Situation | Recommended strategy |
|---|---|
| Column >50–60% missing, not critical | Drop the column |
| A few rows missing in a required key/target | Drop those rows |
| Numeric, missing-at-random, skewed | Impute median |
| Numeric, roughly symmetric | Impute mean (or median for robustness) |
| Categorical | Impute mode, or add explicit "Missing" category |
| Time series / ordered | ffill/bfill, or interpolate (.interpolate()) |
| Missingness is itself informative | Keep NaN + add boolean was_missing flag |
| Need non-float ints with NaN | Cast to nullable Int64, don't fill |
Rule of thumb: imputing changes the distribution. For modeling, prefer adding a missingness indicator alongside the imputed value so the model can learn from "was missing."
Outlier Decision Framework
- Flag, don't auto-delete. Compute IQR fences (
Q1 - 1.5*IQR,Q3 + 1.5*IQR) or |z| > 3. - Investigate. Is it a data-entry error (age = 999), a unit mistake (cm vs m), or a real rare event?
- Treat by cause: error → fix or remove; legitimate extreme but distorting → winsorize/cap at the fence or log-transform; legitimate and meaningful → keep.
- Use robust methods (IQR, median) over mean/std on skewed data, since mean/std are themselves dragged by outliers.
Worked Example (condensed)
Given a column price of strings like "$1,299.00", "N/A", "":
df["price"] = (
df["price"]
.replace({"N/A": pd.NA, "": pd.NA})
.str.replace(r"[$,]", "", regex=True)
.pipe(pd.to_numeric, errors="coerce") # bad parses -> NaN
)
df["price"] = df["price"].fillna(df["price"].median()) # documented: skewed
See examples/clean_messy_sales.md for a full raw→clean walkthrough with a 12-column messy sales file, and run scripts/clean_pipeline.py --help for a configurable end-to-end cleaner.
Best Practices
- Profile before and after. You cannot clean what you have not measured, and you cannot trust a clean you did not verify.
- Prefer non-mutating chains. Build the cleaned frame with
.assign/.pipeso the whole recipe is one readable, rerunnable block. Avoid sprinklinginplace=True. - Coerce with
errors="coerce", then inspect the new NaNs — they reveal unparseable values you'd otherwise miss. - Use explicit date formats (
pd.to_datetime(s, format="%Y-%m-%d")) to avoid silent misparsing of ambiguous01/02/03. - Use nullable dtypes (
Int64,boolean,string) instead of forcing floats just to hold NaN. - Document every destructive choice (drop/fill/cap) in the cleaning report so reviewers can challenge it.
- Validate with assertions at the end; treat a cleaning script that produces silently-wrong data as a bug.
- Keep the raw file immutable. Always read raw, write cleaned to a new path.
Common Pitfalls
- Disguised missing values (
"unknown",-999,"-", whitespace) left as real data, poisoning means and joins. Always normalize these to NaN first. inplace=Truechaining bugs and accidentalSettingWithCopyWarningfrom chained indexing — use.locand reassignment.- Auto-deleting outliers before checking whether they're legitimate, throwing away the most interesting rows.
- Mean-imputing skewed columns, dragging the central tendency and shrinking variance.
float64columns full of1.0/2.0because NaN forced float — cast toInt64after cleaning.- Ambiguous date parsing (
dayfirstvs default) silently swapping day/month. - Dropping duplicates before standardizing text, so
"Acme "and"acme"survive as distinct. - Pivot collisions — using
pivotwhen index/column pairs aren't unique; usepivot_tablewith an explicitaggfunc. - No post-clean validation, shipping a dataset whose row count or domain quietly broke.
Gives 0 of the 12 instructions most data analysis skills give
Counted across 286 of the 286 authors here whose files we hold, read 2026-08-06
- use excel formulas instead of hardcoded calculated valuesin 35 of 286, across 7 files
- match existing template conventions when modifying filesin 35 of 286, across 7 files
- document sources for all hardcoded valuesin 35 of 286, across 7 files
- write minimal concise python codein 35 of 286, across 7 files
- place all assumptions in separate assumption cellsin 32 of 286, across 5 files
- apply industry-standard color coding to financial modelsin 31 of 286, across 5 files
- format years as text stringsin 30 of 286, across 3 files
- recalculate formulas using recalc.py after modificationsin 30 of 286, across 3 files
- format negative numbers using parenthesesin 30 of 286, across 3 files
- fix all identified formula errors before finishingin 27 of 286, across 1 file
- use colorblind-safe palettesin 19 of 286, across 12 files
- Name tests after the prevented bugin 13 of 286, across 8 files
Said here and by no other author read
- profile the raw data first
- fix structure and standardize column names
- coerce dtypes explicitly
- standardize text and categories
- distinguish disguised missing values from real values
- document every destructive cleaning choice
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once.