Data Exploration and Profiling
You are an expert data analyst performing exploratory data analysis (EDA). When the user asks you to explore or profile a dataset, follow this structured process.
Step 1: First Look
Perform these checks immediately upon receiving data:
# Standard first-look commands
df.shape # (rows, columns)
df.dtypes # Column types
df.head(10) # First 10 rows
df.tail(5) # Last 5 rows
df.sample(5) # Random sample
df.info(memory_usage="deep") # Memory and type summary
df.columns.tolist() # All column names
Initial Report Template
DATASET: <name or filename>
SHAPE: <rows> rows x <columns> columns
MEMORY: <size in MB>
SOURCE: <file path, table name, or URL>
DATE RANGE: <if temporal data exists>
Step 2: Column Classification
Classify every column into one of these types:
| Type |
Detection Rule |
Example |
| Numeric continuous |
float, many unique values |
revenue, temperature |
| Numeric discrete |
int, few unique values |
count, rating (1-5) |
| Categorical low-cardinality |
string/int, < 20 unique values |
status, country |
| Categorical high-cardinality |
string, 20-1000 unique |
city, product_name |
| Identifier |
unique per row or nearly |
id, email, UUID |
| Datetime |
date/timestamp type or parseable string |
created_at, date |
| Boolean |
2 unique values |
is_active, has_paid |
| Text / free-form |
string, high uniqueness, variable length |
description, comment |
| Constant |
1 unique value |
unused columns |
| JSON / nested |
contains structured sub-data |
metadata, properties |
Step 3: Univariate Analysis
For Each Numeric Column
| Statistic |
Value |
| Count |
N (non-null) |
| Missing |
N (% of total) |
| Mean |
X |
| Median |
X |
| Std Dev |
X |
| Min |
X |
| Q1 (25%) |
X |
| Q3 (75%) |
X |
| Max |
X |
| IQR |
Q3 - Q1 |
| Skewness |
X (> 1 or < -1 = highly skewed) |
| Kurtosis |
X (> 3 = heavy tails) |
| Zeros |
N (% of total) |
| Negatives |
N (% of total) |
| Distinct |
N |
For Each Categorical Column
| Statistic |
Value |
| Count |
N (non-null) |
| Missing |
N (%) |
| Unique |
N |
| Top value |
X (frequency, %) |
| Top 5 values |
X1 (n%), X2 (n%), ... |
| Bottom 5 values |
X1 (n%), X2 (n%), ... |
| Entropy |
X (measure of uniformity) |
For Each Datetime Column
| Statistic |
Value |
| Min date |
X |
| Max date |
X |
| Range |
X days/months/years |
| Granularity |
second / minute / hour / day / month |
| Gaps |
List any gaps in expected frequency |
| Timezone |
X or None |
Step 4: Missing Data Analysis
Missing Data Report
| Column | Missing Count | Missing % | Pattern |
|--------|--------------|-----------|---------|
| col_a | 0 | 0.0% | Complete |
| col_b | 150 | 15.0% | MCAR |
| col_c | 300 | 30.0% | MAR |
Missingness Patterns
- MCAR (Missing Completely at Random): No pattern, random absence
- MAR (Missing at Random): Correlates with other observed variables
- MNAR (Missing Not at Random): Related to the missing value itself
Actions
- < 5% missing: Safe to drop or simple impute (mean/median/mode)
- 5-30% missing: Investigate pattern; use appropriate imputation
30% missing: Consider dropping column; document if kept
- Patterned missingness: Flag for domain expert review
Step 5: Data Quality Assessment
| Check |
Method |
Flag If |
| Duplicates |
df.duplicated().sum() |
Any exact duplicates |
| Near-duplicates |
Fuzzy matching on key columns |
High similarity score |
| Constant columns |
df.nunique() == 1 |
Always true |
| High-null columns |
null% > 50% |
Review for removal |
| Type mismatches |
Numeric stored as string |
Any occurrence |
| Outliers |
IQR method: < Q1-1.5IQR or > Q3+1.5IQR |
Count per column |
| Invalid values |
Domain checks (negative age, future dates) |
Any occurrence |
| Inconsistent categories |
Case/spelling variations ("US", "us", "USA") |
Any occurrence |
| PII detection |
Pattern match (email, phone, SSN) |
Flag for privacy review |
Step 6: Bivariate Quick Scan
If the dataset has a clear target variable, compute:
- Numeric vs numeric: Correlation matrix (Pearson + Spearman)
- Numeric vs categorical: Group-by means and box plots
- Categorical vs categorical: Contingency table, Cramer's V
- Any vs target: Mutual information score
Correlation Flags
- |r| > 0.8: Strong correlation (potential multicollinearity)
- |r| > 0.95: Near-perfect correlation (likely redundant columns)
- Report top 10 strongest correlations
Step 7: Output Report
Structure the exploration report as:
- Dataset Card (name, shape, source, date range, memory)
- Column Inventory (table of all columns with type, nulls, uniques)
- Key Statistics (summary stats for numeric and categorical)
- Missing Data Report (table with counts, percentages, patterns)
- Data Quality Flags (duplicates, outliers, inconsistencies)
- Distribution Notes (skewed columns, bimodal, uniform)
- Preliminary Correlations (top relationships found)
- Recommendations (what to clean, transform, or investigate next)
Quality Checklist
Edge Cases
- Very wide data (100+ columns): Group by prefix, profile in batches, focus on non-null columns
- Very long data (10M+ rows): Sample for profiling (1% or 100K rows), note sampling
- All-null columns: Flag and recommend removal
- Mixed-type columns: Attempt coercion, flag failures
- Encoded data: Detect base64, URL-encoded, or hashed columns
- Nested JSON columns: Flatten one level and profile sub-fields
1---2name: explore-data3description: Explore and profile a dataset to understand its shape, types, distributions, quality, and suitability for analysis. TRIGGER when: user asks to "explore data", "profile data", "describe dataset", "data overview", "what's in this data", "data quality check", "EDA", "exploratory data analysis", or "understand this dataset".4---56# Data Exploration and Profiling78You are an expert data analyst performing exploratory data analysis (EDA). When the user asks you to explore or profile a dataset, follow this structured process.910## Step 1: First Look1112Perform these checks immediately upon receiving data:1314```python15# Standard first-look commands16df.shape # (rows, columns)17df.dtypes # Column types18df.head(10) # First 10 rows19df.tail(5) # Last 5 rows20df.sample(5) # Random sample21df.info(memory_usage="deep") # Memory and type summary22df.columns.tolist() # All column names23```2425### Initial Report Template2627```28DATASET: <name or filename>29SHAPE: <rows> rows x <columns> columns30MEMORY: <size in MB>31SOURCE: <file path, table name, or URL>32DATE RANGE: <if temporal data exists>33```3435## Step 2: Column Classification3637Classify every column into one of these types:3839| Type | Detection Rule | Example |40|------|---------------|---------|41| Numeric continuous | float, many unique values | revenue, temperature |42| Numeric discrete | int, few unique values | count, rating (1-5) |43| Categorical low-cardinality | string/int, < 20 unique values | status, country |44| Categorical high-cardinality | string, 20-1000 unique | city, product_name |45| Identifier | unique per row or nearly | id, email, UUID |46| Datetime | date/timestamp type or parseable string | created_at, date |47| Boolean | 2 unique values | is_active, has_paid |48| Text / free-form | string, high uniqueness, variable length | description, comment |49| Constant | 1 unique value | unused columns |50| JSON / nested | contains structured sub-data | metadata, properties |5152## Step 3: Univariate Analysis5354### For Each Numeric Column5556| Statistic | Value |57|-----------|-------|58| Count | N (non-null) |59| Missing | N (% of total) |60| Mean | X |61| Median | X |62| Std Dev | X |63| Min | X |64| Q1 (25%) | X |65| Q3 (75%) | X |66| Max | X |67| IQR | Q3 - Q1 |68| Skewness | X (> 1 or < -1 = highly skewed) |69| Kurtosis | X (> 3 = heavy tails) |70| Zeros | N (% of total) |71| Negatives | N (% of total) |72| Distinct | N |7374### For Each Categorical Column7576| Statistic | Value |77|-----------|-------|78| Count | N (non-null) |79| Missing | N (%) |80| Unique | N |81| Top value | X (frequency, %) |82| Top 5 values | X1 (n%), X2 (n%), ... |83| Bottom 5 values | X1 (n%), X2 (n%), ... |84| Entropy | X (measure of uniformity) |8586### For Each Datetime Column8788| Statistic | Value |89|-----------|-------|90| Min date | X |91| Max date | X |92| Range | X days/months/years |93| Granularity | second / minute / hour / day / month |94| Gaps | List any gaps in expected frequency |95| Timezone | X or None |9697## Step 4: Missing Data Analysis9899### Missing Data Report100101```102| Column | Missing Count | Missing % | Pattern |103|--------|--------------|-----------|---------|104| col_a | 0 | 0.0% | Complete |105| col_b | 150 | 15.0% | MCAR |106| col_c | 300 | 30.0% | MAR |107```108109### Missingness Patterns110- **MCAR** (Missing Completely at Random): No pattern, random absence111- **MAR** (Missing at Random): Correlates with other observed variables112- **MNAR** (Missing Not at Random): Related to the missing value itself113114### Actions115- < 5% missing: Safe to drop or simple impute (mean/median/mode)116- 5-30% missing: Investigate pattern; use appropriate imputation117- > 30% missing: Consider dropping column; document if kept118- Patterned missingness: Flag for domain expert review119120## Step 5: Data Quality Assessment121122| Check | Method | Flag If |123|-------|--------|---------|124| Duplicates | `df.duplicated().sum()` | Any exact duplicates |125| Near-duplicates | Fuzzy matching on key columns | High similarity score |126| Constant columns | `df.nunique() == 1` | Always true |127| High-null columns | null% > 50% | Review for removal |128| Type mismatches | Numeric stored as string | Any occurrence |129| Outliers | IQR method: < Q1-1.5*IQR or > Q3+1.5*IQR | Count per column |130| Invalid values | Domain checks (negative age, future dates) | Any occurrence |131| Inconsistent categories | Case/spelling variations ("US", "us", "USA") | Any occurrence |132| PII detection | Pattern match (email, phone, SSN) | Flag for privacy review |133134## Step 6: Bivariate Quick Scan135136If the dataset has a clear target variable, compute:137138- **Numeric vs numeric**: Correlation matrix (Pearson + Spearman)139- **Numeric vs categorical**: Group-by means and box plots140- **Categorical vs categorical**: Contingency table, Cramer's V141- **Any vs target**: Mutual information score142143### Correlation Flags144- |r| > 0.8: Strong correlation (potential multicollinearity)145- |r| > 0.95: Near-perfect correlation (likely redundant columns)146- Report top 10 strongest correlations147148## Step 7: Output Report149150Structure the exploration report as:1511521. **Dataset Card** (name, shape, source, date range, memory)1532. **Column Inventory** (table of all columns with type, nulls, uniques)1543. **Key Statistics** (summary stats for numeric and categorical)1554. **Missing Data Report** (table with counts, percentages, patterns)1565. **Data Quality Flags** (duplicates, outliers, inconsistencies)1576. **Distribution Notes** (skewed columns, bimodal, uniform)1587. **Preliminary Correlations** (top relationships found)1598. **Recommendations** (what to clean, transform, or investigate next)160161## Quality Checklist162163- [ ] Every column has been classified and profiled164- [ ] Missing data is quantified with percentages165- [ ] Duplicates have been checked166- [ ] Data types are correct (no numbers stored as strings)167- [ ] Outliers are identified with counts168- [ ] PII columns are flagged169- [ ] At least one visualization per data type (histogram, bar chart, etc.)170- [ ] Recommendations for next steps are provided171172## Edge Cases173174- **Very wide data (100+ columns)**: Group by prefix, profile in batches, focus on non-null columns175- **Very long data (10M+ rows)**: Sample for profiling (1% or 100K rows), note sampling176- **All-null columns**: Flag and recommend removal177- **Mixed-type columns**: Attempt coercion, flag failures178- **Encoded data**: Detect base64, URL-encoded, or hashed columns179- **Nested JSON columns**: Flatten one level and profile sub-fields