data-analysis
Skill1 starsChanged 7 months agoMITView on GitHub
Data analysis workflows with pandas, Polars, and DuckDB for exploration, cleaning, and transformation. Use when: performing exploratory data analysis, cleaning messy datasets, computing aggregations and statistics, writing Jupyter/Marimo notebook workflows, choosing between pandas and Polars, querying Parquet files with DuckDB, building reproducible analysis notebooks, auditing existing analysis code for performance or correctness, or designing post-pipeline transform steps.
76 other projects use a version of this.
Adopted by
Most recently taken up by
- pedrohcgs/claude-code-my-workflowtheir own version, first seen Nov 8, 2026
- zakirkun/slayerclawtheir own version, first seen Nov 8, 2026
- notegpt-official/notegpt-skillstheir own version, first seen Nov 6, 2026
- CatCatUncle/openworkbuddytheir own version, first seen Nov 5, 2026
- flonat/flonat-researchtheir own version, first seen Nov 3, 2026
- AgnesAI-Labs/agnet-skills-cntheir own version, first seen Nov 1, 2026
Used with
Projects with it also use algorithm-design, review-r and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
lingzhi227Skillalgorithm-design
Design algorithms with LaTeX pseudocode and UML diagrams. Generate algorithmic environments, Mermaid class/sequence diagrams, and ensure consistency between pseudocode and implementation. Use when formalizing methods for a paper.
Also in 5 projects that use this
luischanciSkillreview-r
Run the R code review protocol on R scripts. Checks code quality, reproducibility, domain correctness, and professional standards. Produces a report without editing files.
Also in 4 projects that use this
zephyrwang6Skilldeepl
Übersetzt Texte, Dokumente und XLIFF-Dateien via DeepL API. Verwende für Übersetzungen mit /deepl translate, /deepl file oder /deepl xliff.
Also in 4 projects that use this
zephyrwang6Skillimagemagick-conversion
Convert and manipulate images with ImageMagick. Covers format conversion, resizing, batch processing, quality adjustment, and image transformations. Use when user mentions image conversion, resizing images, ImageMagick, magick command, batch image processing, or thumbnail generation.
Also in 4 projects that use this
lingzhi227Skilllatex-formatting
Handle LaTeX formatting, templates, and styling for academic papers. Set up conference templates (ICML, ICLR, NeurIPS, AAAI, ACL), fix formatting issues, manage packages, and ensure venue-specific compliance. Use when the user needs to set up a paper template, fix LaTeX formatting, or prepare for submission.
Also in 4 projects that use this
stophobiaSkillsurprise-me
Create a delightful, unexpected "wow" experience for the user by dynamically discovering and creatively combining other enabled skills. Triggers when the user says "surprise me" or any request expressing a desire for an unexpected creative showcase. Also triggers when the user is bored, wants inspiration, or asks for "something interesting".
Also in 4 projects that use this
- +3 more from zephyrwang6
- +2 more from lingzhi227
Other versions76 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 76
- bytedance/deer-flow★ 85ksame name
- pedrohcgs/claude-code-my-workflow★ 1.7ksame name
- fastclaw-ai/fastclaw★ 1.4ksame name
- stophobia/deerflow2.0-enhanced★ 821same name
- EvovexAI/EvoFlow★ 612same name
- claude-office-skills/skills★ 433same name
- CatCatUncle/openworkbuddy★ 398same name
- lingzhi227/agent-research-skills★ 350same name
- zephyrwang6/myskill★ 339same name
- duyet/clickhouse-monitoring★ 303same name
66 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository42 other files it gives its agents.
- accessibility-testingSkill
- alternatives-analysisSkill
- anomaly-detectionSkill
- api-designSkill
- async-messagingSkill
- caching-strategiesSkill
- chartsSkill
- cicdSkill
- code-reviewSkill
- commsSkill
- critical-feedbackSkill
- databaseSkill
- data-migrationsSkill
- data-visualizationSkill
- dependency-managementSkill
- dockerSkill
- error-handlingSkill
- feature-flagsSkill
- git-workflowSkill
- goalsSkill
- ide-setupSkill
- large-changeSkill
- logging-metricsSkill
- markdown-docsSkill
- mcp-serverSkill
- meeting-agendasSkill
- okrsSkill
- presentationsSkill
- product-managementSkill
- prompt-writingSkill
- pythonSkill
- reclassificationSkill
- release-managementSkill
- retrospectivesSkill
- roadmap-planningSkill
- securitySkill
- stakeholder-commsSkill
- statisticsSkill
- status-updatesSkill
- testingSkill
- ticket-writingSkill
- typescriptSkill
The file
We split this skill into the rules it gives an agent
6 rules. 0 are common, 4 are distinctive, and 2 are very specific to this project.
0
Common
Most of the 53 edited versions we read keep these.
4
Distinctive
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 43
Use pandas: when a downstream library requires it (sklearn, certain plotting libraries) or for quick one-off exploration.
- Distinctive: line 44
Use DuckDB SQL: when the question is naturally expressed in SQL (aggregations, joins, window functions) and data lives in Parquet files.
- Distinctive: line 51
Follow this sequence when encountering a new dataset:
- Distinctive: line 272
Every analysis notebook should follow this structure:
- Very specific: line 327
Use
scan_parquet(lazy): instead of read_parquet (eager) for datasets larger than available RAM. - Very specific: line 330
Stream large results: Use collect(streaming=True) for datasets that don't fit in memory even after filtering.
“Common” is measured: kept by at least 6 in 10 of the 53 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Data Analysis Standards
When to Use
- Exploring a new dataset (shape, distributions, quality)
- Cleaning and transforming data after pipeline ingestion
- Computing aggregations, groupings, and statistical summaries
- Writing Jupyter or Marimo notebooks for analysis
- Querying Parquet or CSV files with DuckDB SQL
- Choosing between pandas, Polars, and DuckDB for a task
- Building reproducible analysis workflows
- Auditing existing notebooks or analysis scripts for correctness, performance, or readability
Tool Selection
| Tool | Best For | Install |
| Polars | Large datasets, performance-critical transforms, lazy evaluation, type safety | uv add polars |
| pandas | Quick exploration, broad ecosystem compatibility, small-to-medium data | uv add pandas |
| DuckDB | SQL-based analytics on Parquet/CSV without loading into memory | uv add duckdb |
Decision Guide
- Default to Polars for any repeatable analysis or transform — faster, stricter types, lower memory.
- Use pandas when a downstream library requires it (sklearn, certain plotting libraries) or for quick one-off exploration.
- Use DuckDB SQL when the question is naturally expressed in SQL (aggregations, joins, window functions) and data lives in Parquet files.
- Combine freely: Polars and DuckDB share Apache Arrow as the memory format — zero-copy conversion between them.
Exploratory Data Analysis (EDA) Workflow
Follow this sequence when encountering a new dataset:
1. Shape and Schema
import polars as pl
df = pl.read_parquet("data/raw/users.parquet")
print(f"Rows: {df.height:,}, Columns: {df.width}")
print(df.schema)
print(df.head(5))2. Null and Completeness Audit
null_report = df.select(
pl.all().null_count().name.suffix("_nulls"),
).unpivot().sort("value", descending=True)
print(null_report)
# Percentage complete
completeness = df.select(
(1 - pl.all().null_count() / df.height).name.suffix("_complete"),
).unpivot().sort("value")
print(completeness)3. Descriptive Statistics
# Numeric columns
print(df.select(pl.col(pl.NUMERIC_DTYPES)).describe())
# Categorical value counts
for col in df.select(pl.col(pl.String)).columns:
print(f"\n{col}:")
print(df.group_by(col).len().sort("len", descending=True).head(10))4. Distributions and Outliers
# Quick histogram via DuckDB for large data
import duckdb
duckdb.sql("""
SELECT histogram(amount, 20) AS amount_hist
FROM 'data/raw/orders.parquet'
""").show()
# Outlier detection with IQR
q1, q3 = df.select(
pl.col("amount").quantile(0.25).alias("q1"),
pl.col("amount").quantile(0.75).alias("q3"),
).row(0)
iqr = q3 - q1
outliers = df.filter(
(pl.col("amount") < q1 - 1.5 * iqr) | (pl.col("amount") > q3 + 1.5 * iqr)
)
print(f"Outliers: {outliers.height} rows ({outliers.height / df.height:.1%})")5. Temporal Patterns
daily = (
df.with_columns(pl.col("created_at").cast(pl.Date).alias("date"))
.group_by("date")
.agg(pl.len().alias("count"))
.sort("date")
)
print(daily)Data Cleaning Patterns
Standard Cleaning Pipeline
def clean_users(df: pl.DataFrame) -> pl.DataFrame:
"""Clean raw user data."""
return (
df
# Drop exact duplicates
.unique()
# Normalize text columns
.with_columns(
pl.col("email").str.to_lowercase().str.strip_chars(),
pl.col("name").str.strip_chars(),
)
# Filter invalid rows
.filter(pl.col("email").str.contains(r"^[^@]+@[^@]+\.[^@]+$"))
# Cast types
.with_columns(
pl.col("created_at").str.to_datetime("%Y-%m-%dT%H:%M:%SZ"),
)
# Drop columns not needed downstream
.drop("raw_html", "debug_info")
)Handling Missing Data
| Strategy | When |
| Drop rows | Missing data is rare (<5%) and random |
| Fill with default | Business logic defines a sensible default (e.g., 0 for missing counts) |
| Forward/backward fill | Time-series data with sparse readings |
| Flag as missing | Downstream analysis needs to distinguish "0" from "unknown" |
# Fill with default
df = df.with_columns(pl.col("country").fill_null("Unknown"))
# Forward fill time-series
df = df.sort("timestamp").with_columns(pl.col("temperature").forward_fill())
# Flag missing
df = df.with_columns(pl.col("amount").is_null().alias("amount_missing"))Aggregation Patterns
Group-By Aggregations
summary = (
df.group_by("category")
.agg(
pl.len().alias("count"),
pl.col("amount").sum().alias("total"),
pl.col("amount").mean().alias("avg"),
pl.col("amount").median().alias("median"),
pl.col("amount").std().alias("std"),
pl.col("amount").quantile(0.95).alias("p95"),
)
.sort("total", descending=True)
)Window Functions
df = df.with_columns(
# Running total per user
pl.col("amount")
.cum_sum()
.over("user_id")
.alias("running_total"),
# Rank within category
pl.col("amount")
.rank(method="dense", descending=True)
.over("category")
.alias("rank_in_category"),
)Time-Series Resampling
monthly = (
df.sort("date")
.group_by_dynamic("date", every="1mo")
.agg(
pl.col("amount").sum().alias("monthly_total"),
pl.col("user_id").n_unique().alias("unique_users"),
)
)DuckDB SQL for Analysis
Query Parquet files directly without loading into Python memory:
import duckdb
# Aggregate across partitioned Parquet files
result = duckdb.sql("""
SELECT
date_trunc('month', created_at) AS month,
country,
count(*) AS orders,
sum(amount) AS revenue,
avg(amount) AS avg_order_value
FROM 'data/raw/orders/**/*.parquet'
GROUP BY 1, 2
ORDER BY 1, 4 DESC
""")
# Convert to Polars for further manipulation
df = result.pl()DuckDB + Polars Integration
import duckdb
import polars as pl
# Register Polars DataFrame as a DuckDB table
df = pl.read_parquet("data/cleaned/users.parquet")
duckdb.sql("SELECT * FROM df WHERE country = 'US' LIMIT 10").show()DuckDB automatically detects Polars and pandas DataFrames by variable name — no explicit registration needed.
Notebook Best Practices
Structure
Every analysis notebook should follow this structure:
- Title and objective — Markdown cell stating what question the notebook answers.
- Imports and config — Single cell with all imports; set display options.
- Data loading — Load from Parquet (pipeline output), not raw APIs.
- Exploration — EDA steps (shape, nulls, distributions).
- Analysis — The actual computation answering the objective.
- Visualization — Charts supporting the conclusions (see data-visualization skill).
- Conclusions — Markdown cell summarizing findings.
Config Cell Template
import polars as pl
import duckdb
from pathlib import Path
# Display settings
pl.Config.set_tbl_rows(20)
pl.Config.set_fmt_str_lengths(80)
DATA_DIR = Path("data")Rules
- Never call APIs from notebooks — load from pipeline outputs (Parquet files). Pipelines are the ingestion layer; notebooks are the analysis layer.
- Use relative paths from the project root, not absolute paths.
- Each notebook answers one question — don't create monolithic analysis notebooks.
- Clear outputs before committing — notebooks with output diffs are unreadable in git.
- Name notebooks descriptively:
01_user_churn_analysis.ipynb, notUntitled3.ipynb. - Pin the Python kernel to the project's
uvenvironment.
Performance Tips
Polars Lazy Evaluation
For large datasets, use lazy evaluation to let Polars optimize the query plan:
result = (
pl.scan_parquet("data/raw/events/*.parquet") # lazy — no data loaded yet
.filter(pl.col("event_type") == "purchase")
.group_by("user_id")
.agg(pl.col("amount").sum().alias("total_spent"))
.sort("total_spent", descending=True)
.head(100)
.collect() # executes the optimized plan
)Memory Management
- Use
scan_parquet(lazy) instead ofread_parquet(eager) for datasets larger than available RAM. - Select only needed columns:
pl.scan_parquet(...).select(["id", "amount"])avoids loading unused columns. - Filter early: Push filters before aggregations to reduce data volume.
- Stream large results: Use
collect(streaming=True)for datasets that don't fit in memory even after filtering.
Cross-References
- Data pipelines: See the data-pipelines skill for dlt-based ingestion that produces the Parquet files analyzed here.
- Data visualization: See the data-visualization skill for plotting analysis results in notebooks.
- Charts (web): See the charts skill for React/Recharts visualization when building web dashboards from analysis outputs.
- Python conventions: See the python skill for type hints, project setup, and Ruff configuration.
- Database queries: See the database skill when analysis requires querying PostgreSQL or DynamoDB directly.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

