
Data Analyst
- 1.1k installs
- 432 repo stars
- Updated November 11, 2025
- ailabs-393/ai-labs-claude-skills
data-analyst is an agent skill that analyzes datasets with SQL or Python summaries, charts, and insight bullets for stakeholders.
About
The data-analyst skill helps agents explore datasets, write SQL or Python aggregations, and produce stakeholder-friendly insight summaries. It checks column types, missing values, and outliers before reporting metrics, trends, and segment breakdowns. Agents recommend visualizations when helpful, cite query definitions, and separate observations from hypotheses. Output formats include markdown tables, bullet insights, and suggested follow-up analyses. Use when users upload CSVs, database tables, or experiment logs needing exploratory analysis rather than production pipeline engineering.
- Exploratory analysis with SQL or Python aggregations.
- Checks data quality, missing values, and outliers first.
- Produces stakeholder insight bullets and markdown tables.
- Separates observations from hypotheses in summaries.
- Suggests follow-up analyses and simple visualizations.
Data Analyst by the numbers
- 1,102 all-time installs (skills.sh)
- +10 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #281 of 2,065 Data Science & ML skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 3, 2026 (Skillselion catalog sync)
data-analyst capabilities & compatibility
- Capabilities
- data quality checks · sql and python aggregations · stakeholder insight summaries · segment and trend breakdowns · follow up analysis recommendations
- Use cases
- data analysis · research
What data-analyst says it does
data-analyst
npx skills add https://github.com/ailabs-393/ai-labs-claude-skills --skill data-analystAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.1k |
|---|---|
| repo stars | ★ 432 |
| Security audit | 3 / 3 scanners passed |
| Last updated | November 11, 2025 |
| Repository | ailabs-393/ai-labs-claude-skills ↗ |
What trends, segments, and data quality issues exist in this dataset for stakeholders?
Analyze datasets with SQL or Python summaries, charts, and insight bullets for stakeholder reports.
Who is it for?
Agents exploring CSVs, tables, or logs for ad hoc analysis and reporting.
Skip if: Skip for production ETL pipeline engineering without an exploratory question.
When should I use this skill?
User asks for dataset analysis, SQL summaries, or insight bullets from experiment or business data.
What you get
Exploratory analysis with queries, tables, insight bullets, and recommended follow-up analyses.
- Imputation strategy recommendations
- Cleaned analysis-ready dataset
By the numbers
- Published at version 1.0.0 as @ai-labs-claude-skills/data-analyst
Files
Data Analyst
Overview
This skill provides comprehensive capabilities for data analysis workflows on CSV datasets. It automatically analyzes missing value patterns, intelligently imputes missing data using appropriate statistical methods, and creates interactive Plotly Dash dashboards for visualizing trends and patterns. The skill combines automated missing value handling with rich interactive visualizations to support end-to-end exploratory data analysis.
Core Capabilities
The data-analyst skill provides three main capabilities that can be used independently or as a complete workflow:
1. Missing Value Analysis
Automatically detect and analyze missing values in datasets, identifying patterns and suggesting optimal imputation strategies.
2. Intelligent Imputation
Apply sophisticated imputation methods tailored to each column's data type and distribution characteristics.
3. Interactive Dashboard Creation
Generate comprehensive Plotly Dash dashboards with multiple visualization types for trend analysis and exploration.
Complete Workflow
When a user requests complete data analysis with missing value handling and visualization, follow this workflow:
Step 1: Analyze Missing Values
Run the missing value analysis script to understand the data quality:
python3 scripts/analyze_missing_values.py <input_file.csv> <output_analysis.json>What this does:
- Detects missing values in each column
- Identifies data types (numeric, categorical, temporal, etc.)
- Calculates missing value statistics
- Suggests appropriate imputation strategies per column
- Generates detailed JSON report and console output
Review the output to understand:
- Which columns have missing data
- The percentage of missing values
- The recommended imputation method for each column
- Why each method was recommended
Step 2: Impute Missing Values
Apply automatic imputation based on the analysis:
python3 scripts/impute_missing_values.py <input_file.csv> <analysis.json> <output_imputed.csv>What this does:
- Loads the analysis results (or performs analysis if not provided)
- Applies the optimal imputation method to each column:
- Mean: For normally distributed numeric data
- Median: For skewed numeric data
- Mode: For categorical variables
- KNN: For multivariate numeric data with correlations
- Forward fill: For time series data
- Constant: For high-cardinality text fields
- Handles edge cases (drops rows/columns when appropriate)
- Generates imputation report with before/after statistics
- Saves cleaned dataset
The script automatically:
- Drops columns with >70% missing values
- Drops rows where critical ID columns are missing
- Performs batch KNN imputation for correlated variables
- Creates detailed imputation log
Step 3: Create Interactive Dashboard
Generate an interactive Plotly Dash dashboard:
python3 scripts/create_dashboard.py <imputed_file.csv> <output_dir> <port>Example:
python3 scripts/create_dashboard.py data_imputed.csv ./visualizations 8050What this does:
- Automatically detects column types (numeric, categorical, temporal)
- Creates comprehensive visualizations:
- Summary statistics table: Descriptive stats for all numeric columns
- Time series plots: Trend analysis if date/time columns exist
- Distribution plots: Histograms for understanding data distributions
- Correlation heatmap: Relationships between numeric variables
- Categorical analysis: Bar charts for categorical variables
- Scatter plot matrix: Pairwise relationships between variables
- Launches interactive Dash web server
- Optionally saves static HTML visualizations
Access the dashboard at http://127.0.0.1:8050 (or specified port)
Individual Use Cases
Use Case A: Quick Missing Value Assessment
When the user wants to understand data quality without imputation:
python3 scripts/analyze_missing_values.py data.csvReview the console output to understand missing value patterns and get recommendations.
Use Case B: Imputation Only
When the user has a dataset with missing values and wants cleaned data:
python3 scripts/impute_missing_values.py data.csvThis performs analysis and imputation in one step, producing data_imputed.csv.
Use Case C: Visualization Only
When the user has a clean dataset and wants interactive visualizations:
python3 scripts/create_dashboard.py clean_data.csv ./visualizations 8050This creates a full dashboard without any preprocessing.
Use Case D: Custom Imputation Strategy
When the user wants to review and adjust imputation strategies:
1. Run analysis first:
python3 scripts/analyze_missing_values.py data.csv analysis.json2. Review analysis.json and discuss strategies with the user
3. If needed, modify the imputation logic or parameters in the script
4. Run imputation:
python3 scripts/impute_missing_values.py data.csv analysis.json data_imputed.csvUnderstanding Imputation Methods
The skill uses intelligent imputation strategies based on data characteristics. Key methods include:
- Mean/Median: For numeric data (mean for normal distributions, median for skewed)
- Mode: For categorical variables (most frequent value)
- KNN (K-Nearest Neighbors): For multivariate numeric data where variables are correlated
- Forward Fill: For time series data (carry last observation forward)
- Interpolation: For smooth temporal trends
- Constant Value: For high-cardinality text fields (e.g., "Unknown")
- Drop: For columns with >70% missing or rows with missing IDs
For detailed information about when each method is appropriate, refer to references/imputation_methods.md.
Dashboard Features
The interactive dashboard includes:
Summary Statistics
- Count, mean, std, min, max, quartiles for all numeric columns
- Missing value counts and percentages
- Sortable table format
Time Series Analysis
- Line plots with markers for temporal trends
- Multiple series support (up to 4 primary metrics)
- Hover details with exact values
- Unified hover mode for easy comparison
Distribution Analysis
- Histograms for all numeric variables
- 30-bin default for granular distribution view
- Multi-panel layout for easy comparison
Correlation Analysis
- Heatmap showing correlation coefficients
- Color-coded from -1 (negative) to +1 (positive)
- Annotated with exact correlation values
- Useful for identifying relationships
Categorical Analysis
- Bar charts for categorical variables
- Top 10 categories shown (for high-cardinality variables)
- Frequency counts displayed
Scatter Plot Matrix
- Pairwise scatter plots for numeric variables
- Limited to 5 variables for readability
- Lower triangle shown (avoiding redundancy)
Setup and Dependencies
Before using the skill, ensure dependencies are installed:
pip install -r requirements.txtRequired packages:
pandas- Data manipulation and analysisnumpy- Numerical computingscikit-learn- KNN imputationplotly- Interactive visualizationsdash- Web dashboard frameworkdash-bootstrap-components- Dashboard styling
Best Practices
For Analysis:
1. Always run analysis before imputation to understand data quality 2. Review suggested imputation methods - they're recommendations, not mandates 3. Pay attention to missing value percentages (>40% requires careful consideration) 4. Check data types match expectations (e.g., numeric IDs detected as numeric)
For Imputation:
1. Save the original dataset before imputation 2. Review the imputation report to ensure methods make sense 3. Check imputed values are within reasonable ranges 4. Consider creating missing indicators for important variables 5. Document which imputation methods were used for reproducibility
For Dashboards:
1. Use imputed/cleaned data for most accurate visualizations 2. Save static HTML plots if sharing with non-technical stakeholders 3. Use different ports if running multiple dashboards simultaneously 4. For large datasets (>100k rows), consider sampling for faster rendering
Handling Edge Cases
High Missing Rates (>50%)
The scripts automatically flag columns with >50% missing values. Options:
- Drop the column if not critical
- Create a missing indicator variable
- Investigate why data is missing (may be informative)
Mixed Data Types
If a column contains mixed types (e.g., numbers and text):
- The script detects the primary type
- Consider cleaning the column before analysis
- Use constant imputation for mixed-type text columns
Small Datasets
For datasets with <50 rows:
- Simple imputation (mean/median/mode) is more stable
- Avoid KNN (requires sufficient neighbors)
- Consider dropping rows instead of imputing
Time Series Gaps
For time series with irregular timestamps:
- Use forward fill for short gaps
- Use interpolation for longer gaps with smooth trends
- Consider the sampling frequency when choosing methods
Troubleshooting
Script fails with "module not found"
Install dependencies: pip install -r requirements.txt
Dashboard won't start (port in use)
Specify a different port: python3 scripts/create_dashboard.py data.csv ./viz 8051
KNN imputation is slow
KNN is computationally intensive for large datasets. For >50k rows, consider:
- Using simpler methods (mean/median)
- Sampling the data first
- Using fewer columns in KNN
Imputed values seem incorrect
- Review the analysis report - check detected data types
- Verify the column is being detected correctly (numeric vs categorical)
- Consider manual adjustment or different imputation method
- Check for outliers that may affect mean/median calculations
Resources
scripts/
analyze_missing_values.py- Comprehensive missing value analysis with automatic strategy recommendationimpute_missing_values.py- Intelligent imputation using multiple methods tailored to data characteristicscreate_dashboard.py- Interactive Plotly Dash dashboard generator with multiple visualization types
references/
imputation_methods.md- Detailed guide to missing value imputation strategies, decision frameworks, and best practices
Other Files
requirements.txt- Python dependencies for the skill
export default async function data_analyst(input) {
console.log("🧠 Running skill: data-analyst");
// TODO: implement actual logic for this skill
return {
message: "Skill 'data-analyst' executed successfully!",
input
};
}
{
"name": "@ai-labs-claude-skills/data-analyst",
"version": "1.0.0",
"description": "Claude AI skill: data-analyst",
"main": "index.js",
"files": [
"."
],
"license": "MIT",
"author": "AI Labs"
}Missing Value Imputation Methods Reference
This document provides detailed information about various imputation strategies and when to use them.
Overview
Missing data is a common challenge in data analysis. The choice of imputation method significantly impacts analysis quality and should be based on:
- The type of data (numeric, categorical, temporal)
- The pattern of missingness (random, systematic)
- The percentage of missing values
- The relationship between variables
Imputation Methods
1. Mean Imputation
Description: Replace missing values with the arithmetic mean of non-missing values.
Best for:
- Normally distributed numeric data
- Low to moderate missing rates (<20%)
- Variables without strong relationships to others
Advantages:
- Simple and fast
- Maintains sample size
- Preserves mean of the distribution
Disadvantages:
- Reduces variance
- Distorts correlations
- Not suitable for skewed distributions
Example use case: Imputing missing temperature readings, height measurements, or test scores.
---
2. Median Imputation
Description: Replace missing values with the median of non-missing values.
Best for:
- Skewed numeric distributions
- Data with outliers
- Ordinal data
Advantages:
- Robust to outliers
- Works well with skewed data
- Simple to implement
Disadvantages:
- Reduces variance
- May not preserve relationships between variables
Example use case: Imputing income data, house prices, or any right-skewed distribution.
---
3. Mode Imputation
Description: Replace missing values with the most frequent value (mode).
Best for:
- Categorical variables
- Binary variables
- Low-cardinality discrete variables
Advantages:
- Appropriate for categorical data
- Maintains most common pattern
- Simple interpretation
Disadvantages:
- May introduce bias if mode is not truly representative
- Reduces variability
Example use case: Imputing product categories, gender, yes/no responses.
---
4. Constant Value Imputation
Description: Replace missing values with a predefined constant (e.g., "Unknown", 0, -999).
Best for:
- High-cardinality categorical variables
- When missingness itself is informative
- Text fields
Advantages:
- Makes missingness explicit
- Useful for categorical analysis
- Simple to implement
Disadvantages:
- May create artificial category
- Not suitable for numeric analysis without transformation
Example use case: Imputing missing comments, optional survey fields, or product descriptions.
---
5. Forward Fill (LOCF - Last Observation Carried Forward)
Description: Replace missing values with the last observed value in sequence.
Best for:
- Time series data
- Sequential measurements
- Slowly changing variables
Advantages:
- Preserves temporal patterns
- Logical for continuous processes
- Maintains smooth transitions
Disadvantages:
- Assumes stability over time
- Can propagate measurement errors
- Not suitable for volatile data
Example use case: Imputing stock prices, sensor readings, or patient vital signs.
---
6. Backward Fill (NOCB - Next Observation Carried Backward)
Description: Replace missing values with the next observed value in sequence.
Best for:
- Time series with forward-looking data
- When future values are more relevant
Advantages:
- Useful for certain temporal patterns
- Complements forward fill
Disadvantages:
- Less intuitive than forward fill
- May not reflect actual process
Example use case: Backfilling start dates, retroactive categorizations.
---
7. Interpolation
Description: Estimate missing values based on surrounding values using mathematical functions.
Types:
- Linear interpolation: Straight line between points
- Polynomial interpolation: Curved line fitting
- Spline interpolation: Smooth piecewise curves
Best for:
- Time series with smooth trends
- Numeric sequences
- Data with clear patterns
Advantages:
- More sophisticated than forward/backward fill
- Preserves trends
- Can capture non-linear patterns
Disadvantages:
- Requires ordered data
- Can be unstable at boundaries
- May not work for irregular patterns
Example use case: Filling gaps in temperature time series, smoothing measurement data.
---
8. KNN (K-Nearest Neighbors) Imputation
Description: Impute missing values using weighted average of K most similar observations.
Best for:
- Multivariate numeric data
- When variables are correlated
- Complex missing patterns
Advantages:
- Considers relationships between variables
- More accurate than univariate methods
- Preserves correlation structure
Disadvantages:
- Computationally expensive
- Requires choosing K parameter
- Sensitive to feature scaling
Parameters:
n_neighbors: Number of neighbors (typically 3-10)weights: 'uniform' or 'distance'
Example use case: Imputing medical measurements, sensor arrays, multivariate financial data.
---
9. Multiple Imputation by Chained Equations (MICE)
Description: Iterative imputation using regression models for each variable.
Best for:
- Complex datasets
- Multiple variables with missing values
- When uncertainty estimation is important
Advantages:
- Produces multiple complete datasets
- Accounts for uncertainty
- Flexible with different variable types
Disadvantages:
- Computationally intensive
- Complex to implement
- Requires statistical expertise
Example use case: Academic research, medical studies, survey data analysis.
---
10. Dropping Rows/Columns
Description: Remove observations or variables with missing values.
Best for:
- Small amounts of missing data (<5%)
- Missing completely at random (MCAR)
- When imputation may introduce bias
Dropping Rows when:
- Critical variables are missing (e.g., ID, key outcome)
- Missing rate per row is very high
- Dataset is large enough to afford loss
Dropping Columns when:
- Missing rate >50-70%
- Variable is not critical to analysis
- Imputation would be unreliable
Advantages:
- No imputation bias
- Simple and transparent
- Preserves observed data integrity
Disadvantages:
- Reduces sample size
- May introduce selection bias
- Loses information
---
Decision Framework
Step 1: Assess Missing Data Pattern
- MCAR (Missing Completely At Random): Any method works
- MAR (Missing At Random): Use model-based methods (KNN, MICE)
- MNAR (Missing Not At Random): Consider missingness mechanism, possibly drop or flag
Step 2: Check Missing Percentage
- <5%: Dropping rows may be acceptable
- 5-20%: Simple imputation (mean/median/mode)
- 20-40%: Advanced methods (KNN, MICE)
- >40%: Consider dropping column or creating missing indicator
Step 3: Consider Variable Type
- Numeric continuous: Mean, median, KNN, interpolation
- Numeric discrete: Mode, KNN
- Categorical: Mode, constant
- Temporal: Forward fill, interpolation
- Text: Constant value
Step 4: Evaluate Relationships
- Independent variables: Univariate methods (mean, median, mode)
- Correlated variables: Multivariate methods (KNN, MICE)
Best Practices
1. Analyze before imputing: Always understand your missing data pattern first 2. Document decisions: Keep track of which methods were used and why 3. Create indicators: Consider adding binary columns indicating which values were imputed 4. Validate results: Check if imputed values are reasonable 5. Sensitivity analysis: Test how different imputation methods affect your conclusions 6. Preserve original data: Always keep a copy of the original dataset
Common Pitfalls
1. Over-imputation: Imputing too much can create artificial patterns 2. Wrong method choice: Using mean for skewed data or mode for continuous data 3. Ignoring relationships: Not considering correlations between variables 4. Imputing non-random missingness: This can introduce serious bias 5. Not validating: Failing to check if imputed values make sense
References and Further Reading
- Rubin, D. B. (1987). Multiple Imputation for Nonresponse in Surveys
- van Buuren, S. (2018). Flexible Imputation of Missing Data
- Little, R. J., & Rubin, D. B. (2019). Statistical Analysis with Missing Data
pandas>=2.0.0
numpy>=1.24.0
scikit-learn>=1.3.0
plotly>=5.18.0
dash>=2.14.0
dash-bootstrap-components>=1.5.0
#!/usr/bin/env python3
"""
Analyze missing values in a dataset and suggest appropriate imputation strategies.
"""
import pandas as pd
import numpy as np
import json
import sys
from pathlib import Path
def detect_column_type(series):
"""Detect the semantic type of a column for better imputation."""
# Remove missing values for analysis
clean_series = series.dropna()
if len(clean_series) == 0:
return 'unknown'
# Check if numeric
if pd.api.types.is_numeric_dtype(series):
# Check if it's likely categorical (few unique values)
unique_ratio = len(clean_series.unique()) / len(clean_series)
if unique_ratio < 0.05 and len(clean_series.unique()) < 20:
return 'categorical_numeric'
# Check if it's an ID column (monotonic or very high cardinality)
if clean_series.is_monotonic_increasing or unique_ratio > 0.95:
return 'id'
# Check distribution characteristics
skewness = clean_series.skew()
if abs(skewness) < 0.5:
return 'numeric_normal'
else:
return 'numeric_skewed'
# Check if datetime
elif pd.api.types.is_datetime64_any_dtype(series):
return 'datetime'
# Check if categorical/object
elif pd.api.types.is_object_dtype(series) or pd.api.types.is_categorical_dtype(series):
unique_ratio = len(clean_series.unique()) / len(clean_series)
if unique_ratio > 0.9:
return 'text_unique'
elif unique_ratio < 0.1:
return 'categorical_low_cardinality'
else:
return 'categorical_medium_cardinality'
return 'unknown'
def suggest_imputation_strategy(series, col_type):
"""Suggest the best imputation strategy based on column type and data characteristics."""
missing_pct = (series.isna().sum() / len(series)) * 100
strategies = {
'method': None,
'reasoning': '',
'alternative': None
}
# High missing rate - consider dropping or special handling
if missing_pct > 50:
strategies['method'] = 'drop_or_flag'
strategies['reasoning'] = f'{missing_pct:.1f}% missing - consider dropping column or creating missing indicator'
return strategies
# Strategy based on column type
if col_type == 'numeric_normal':
strategies['method'] = 'mean'
strategies['reasoning'] = 'Normally distributed numeric data - mean imputation appropriate'
strategies['alternative'] = 'median'
elif col_type == 'numeric_skewed':
strategies['method'] = 'median'
strategies['reasoning'] = 'Skewed numeric data - median more robust than mean'
strategies['alternative'] = 'knn'
elif col_type == 'categorical_numeric':
strategies['method'] = 'mode'
strategies['reasoning'] = 'Numeric data with categorical nature - mode imputation'
strategies['alternative'] = 'most_frequent'
elif col_type in ['categorical_low_cardinality', 'categorical_medium_cardinality']:
strategies['method'] = 'mode'
strategies['reasoning'] = 'Categorical data - mode (most frequent) imputation'
strategies['alternative'] = 'constant:Unknown'
elif col_type == 'text_unique':
strategies['method'] = 'constant'
strategies['reasoning'] = 'High cardinality text - impute with constant value'
strategies['alternative'] = 'drop_rows'
elif col_type == 'datetime':
strategies['method'] = 'forward_fill'
strategies['reasoning'] = 'DateTime data - forward fill (carry last observation forward)'
strategies['alternative'] = 'interpolate'
elif col_type == 'id':
strategies['method'] = 'drop_rows'
strategies['reasoning'] = 'ID column - cannot impute, drop rows with missing IDs'
strategies['alternative'] = 'generate_sequence'
else:
strategies['method'] = 'knn'
strategies['reasoning'] = 'Unknown type - use KNN imputation based on similar rows'
strategies['alternative'] = 'drop_rows'
return strategies
def analyze_missing_values(filepath, output_json=None):
"""
Analyze missing values in a CSV file and generate a comprehensive report.
Args:
filepath: Path to the CSV file
output_json: Optional path to save analysis results as JSON
Returns:
Dictionary containing analysis results
"""
# Load data
df = pd.read_csv(filepath)
# Calculate overall statistics
total_rows = len(df)
total_cells = df.size
missing_cells = df.isna().sum().sum()
missing_pct = (missing_cells / total_cells) * 100
# Analyze each column
column_analysis = {}
for col in df.columns:
missing_count = df[col].isna().sum()
missing_pct_col = (missing_count / total_rows) * 100
if missing_count > 0:
col_type = detect_column_type(df[col])
strategy = suggest_imputation_strategy(df[col], col_type)
# Calculate statistics for non-missing values
clean_data = df[col].dropna()
stats = {}
if pd.api.types.is_numeric_dtype(df[col]):
stats = {
'mean': float(clean_data.mean()),
'median': float(clean_data.median()),
'std': float(clean_data.std()),
'min': float(clean_data.min()),
'max': float(clean_data.max())
}
elif pd.api.types.is_object_dtype(df[col]) or pd.api.types.is_categorical_dtype(df[col]):
value_counts = clean_data.value_counts().head(5)
stats = {
'unique_values': int(clean_data.nunique()),
'most_common': value_counts.to_dict()
}
column_analysis[col] = {
'missing_count': int(missing_count),
'missing_percentage': float(missing_pct_col),
'data_type': str(df[col].dtype),
'detected_type': col_type,
'total_values': int(total_rows),
'non_missing_values': int(total_rows - missing_count),
'statistics': stats,
'imputation_strategy': strategy
}
# Build complete report
report = {
'file': str(filepath),
'total_rows': int(total_rows),
'total_columns': int(len(df.columns)),
'total_cells': int(total_cells),
'missing_cells': int(missing_cells),
'missing_percentage': float(missing_pct),
'columns_with_missing': len(column_analysis),
'column_analysis': column_analysis
}
# Save to JSON if requested
if output_json:
with open(output_json, 'w') as f:
json.dump(report, f, indent=2)
print(f"Analysis saved to: {output_json}")
return report
def print_report(report):
"""Print a formatted report to console."""
print("\n" + "="*80)
print("MISSING VALUES ANALYSIS REPORT")
print("="*80)
print(f"\nFile: {report['file']}")
print(f"Dimensions: {report['total_rows']} rows × {report['total_columns']} columns")
print(f"\nOverall Missing Data:")
print(f" - Missing cells: {report['missing_cells']:,} / {report['total_cells']:,}")
print(f" - Missing percentage: {report['missing_percentage']:.2f}%")
print(f" - Columns with missing values: {report['columns_with_missing']}")
if report['columns_with_missing'] > 0:
print("\n" + "-"*80)
print("COLUMN-BY-COLUMN ANALYSIS")
print("-"*80)
for col, analysis in report['column_analysis'].items():
print(f"\n📊 Column: {col}")
print(f" Type: {analysis['data_type']} (detected as: {analysis['detected_type']})")
print(f" Missing: {analysis['missing_count']:,} / {analysis['total_values']:,} ({analysis['missing_percentage']:.2f}%)")
# Print statistics
if analysis['statistics']:
print(f" Statistics:")
for key, value in analysis['statistics'].items():
if isinstance(value, float):
print(f" - {key}: {value:.4f}")
elif isinstance(value, dict) and key == 'most_common':
print(f" - {key}:")
for val, count in value.items():
print(f" • {val}: {count}")
else:
print(f" - {key}: {value}")
# Print imputation strategy
strategy = analysis['imputation_strategy']
print(f" ✅ Recommended: {strategy['method']}")
print(f" Reason: {strategy['reasoning']}")
if strategy['alternative']:
print(f" Alternative: {strategy['alternative']}")
else:
print("\n✅ No missing values found in the dataset!")
print("\n" + "="*80 + "\n")
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python analyze_missing_values.py <csv_file> [output_json]")
sys.exit(1)
filepath = sys.argv[1]
output_json = sys.argv[2] if len(sys.argv) > 2 else None
if not Path(filepath).exists():
print(f"Error: File not found: {filepath}")
sys.exit(1)
report = analyze_missing_values(filepath, output_json)
print_report(report)
#!/usr/bin/env python3
"""
Create an interactive Plotly Dash dashboard for data visualization and trend analysis.
"""
import pandas as pd
import numpy as np
import sys
import json
from pathlib import Path
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import dash
from dash import dcc, html, Input, Output, callback
import dash_bootstrap_components as dbc
def detect_time_column(df):
"""Detect potential time/date columns in the dataframe."""
time_cols = []
for col in df.columns:
# Check if column is datetime type
if pd.api.types.is_datetime64_any_dtype(df[col]):
time_cols.append(col)
# Try to parse as datetime
elif pd.api.types.is_object_dtype(df[col]):
try:
pd.to_datetime(df[col])
time_cols.append(col)
except:
pass
return time_cols
def detect_numeric_columns(df):
"""Get all numeric columns suitable for visualization."""
return [col for col in df.columns if pd.api.types.is_numeric_dtype(df[col])]
def detect_categorical_columns(df, max_categories=20):
"""Get categorical columns with reasonable cardinality."""
cat_cols = []
for col in df.columns:
if pd.api.types.is_object_dtype(df[col]) or pd.api.types.is_categorical_dtype(df[col]):
if df[col].nunique() <= max_categories:
cat_cols.append(col)
return cat_cols
def create_time_series_plot(df, time_col, numeric_cols):
"""Create time series visualization for trend analysis."""
# Convert time column to datetime
df[time_col] = pd.to_datetime(df[time_col])
df = df.sort_values(time_col)
# Create subplot for each numeric column
n_cols = len(numeric_cols)
fig = make_subplots(
rows=min(n_cols, 4),
cols=1,
subplot_titles=[f"{col} Over Time" for col in numeric_cols[:4]],
vertical_spacing=0.1
)
for idx, col in enumerate(numeric_cols[:4]): # Limit to 4 for readability
row = idx + 1
fig.add_trace(
go.Scatter(
x=df[time_col],
y=df[col],
mode='lines+markers',
name=col,
line=dict(width=2),
marker=dict(size=4)
),
row=row,
col=1
)
fig.update_layout(
height=300 * min(n_cols, 4),
showlegend=True,
title_text="Time Series Trends",
hovermode='x unified'
)
fig.update_xaxes(title_text="Date", row=min(n_cols, 4), col=1)
return fig
def create_distribution_plots(df, numeric_cols):
"""Create distribution plots (histograms and box plots)."""
n_cols = len(numeric_cols)
cols_per_row = 2
n_rows = (n_cols + cols_per_row - 1) // cols_per_row
fig = make_subplots(
rows=n_rows,
cols=cols_per_row,
subplot_titles=[col for col in numeric_cols],
vertical_spacing=0.1,
horizontal_spacing=0.1
)
for idx, col in enumerate(numeric_cols):
row = (idx // cols_per_row) + 1
col_pos = (idx % cols_per_row) + 1
fig.add_trace(
go.Histogram(
x=df[col],
name=col,
nbinsx=30,
marker_color='lightblue',
opacity=0.7
),
row=row,
col=col_pos
)
fig.update_layout(
height=300 * n_rows,
showlegend=False,
title_text="Distribution Analysis"
)
return fig
def create_correlation_heatmap(df, numeric_cols):
"""Create correlation heatmap for numeric columns."""
if len(numeric_cols) < 2:
return None
corr_matrix = df[numeric_cols].corr()
fig = go.Figure(data=go.Heatmap(
z=corr_matrix.values,
x=corr_matrix.columns,
y=corr_matrix.columns,
colorscale='RdBu',
zmid=0,
text=corr_matrix.values.round(2),
texttemplate='%{text}',
textfont={"size": 10},
colorbar=dict(title="Correlation")
))
fig.update_layout(
title="Correlation Heatmap",
height=max(400, len(numeric_cols) * 40),
xaxis={'side': 'bottom'}
)
return fig
def create_categorical_analysis(df, cat_cols, numeric_col=None):
"""Create categorical analysis plots."""
if not cat_cols:
return None
n_cols = len(cat_cols)
fig = make_subplots(
rows=n_cols,
cols=1,
subplot_titles=[f"Distribution of {col}" for col in cat_cols],
vertical_spacing=0.1
)
for idx, col in enumerate(cat_cols):
row = idx + 1
value_counts = df[col].value_counts().head(10) # Top 10 categories
fig.add_trace(
go.Bar(
x=value_counts.index,
y=value_counts.values,
name=col,
marker_color='steelblue'
),
row=row,
col=1
)
fig.update_layout(
height=300 * n_cols,
showlegend=False,
title_text="Categorical Variable Analysis"
)
return fig
def create_scatter_matrix(df, numeric_cols):
"""Create scatter plot matrix for relationships between variables."""
if len(numeric_cols) < 2:
return None
# Limit to 5 columns for readability
cols_to_plot = numeric_cols[:5]
fig = px.scatter_matrix(
df,
dimensions=cols_to_plot,
title="Scatter Plot Matrix - Variable Relationships"
)
fig.update_traces(diagonal_visible=False, showupperhalf=False)
fig.update_layout(height=800)
return fig
def create_summary_statistics_table(df):
"""Create a summary statistics table."""
numeric_cols = detect_numeric_columns(df)
if not numeric_cols:
return None
stats_df = df[numeric_cols].describe().round(2).T
stats_df['missing'] = df[numeric_cols].isna().sum()
stats_df['missing_pct'] = (stats_df['missing'] / len(df) * 100).round(2)
fig = go.Figure(data=[go.Table(
header=dict(
values=['Variable'] + list(stats_df.columns),
fill_color='paleturquoise',
align='left',
font=dict(size=12, color='black')
),
cells=dict(
values=[stats_df.index] + [stats_df[col] for col in stats_df.columns],
fill_color='lavender',
align='left',
font=dict(size=11)
)
)])
fig.update_layout(
title="Summary Statistics",
height=min(600, 50 + len(numeric_cols) * 30)
)
return fig
def build_dashboard(filepath, output_dir=None, port=8050):
"""
Build and launch an interactive Plotly Dash dashboard.
Args:
filepath: Path to the CSV file
output_dir: Directory to save dashboard files (optional)
port: Port to run the dashboard server (default: 8050)
"""
# Load data
df = pd.read_csv(filepath)
# Detect column types
numeric_cols = detect_numeric_columns(df)
cat_cols = detect_categorical_columns(df)
time_cols = detect_time_column(df)
print(f"\nDataset loaded: {len(df)} rows, {len(df.columns)} columns")
print(f"Numeric columns: {len(numeric_cols)}")
print(f"Categorical columns: {len(cat_cols)}")
print(f"Time columns: {len(time_cols)}")
# Create visualizations
plots = {}
# Summary statistics
plots['summary'] = create_summary_statistics_table(df)
# Time series (if time column exists)
if time_cols and numeric_cols:
plots['timeseries'] = create_time_series_plot(df, time_cols[0], numeric_cols)
# Distribution plots
if numeric_cols:
plots['distributions'] = create_distribution_plots(df, numeric_cols[:6])
# Correlation heatmap
if len(numeric_cols) >= 2:
plots['correlation'] = create_correlation_heatmap(df, numeric_cols)
# Categorical analysis
if cat_cols:
plots['categorical'] = create_categorical_analysis(df, cat_cols[:5])
# Scatter matrix
if len(numeric_cols) >= 2:
plots['scatter_matrix'] = create_scatter_matrix(df, numeric_cols)
# Initialize Dash app
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
# Create layout
app.layout = dbc.Container([
dbc.Row([
dbc.Col([
html.H1("Data Analysis Dashboard", className="text-center mb-4"),
html.Hr()
])
]),
# Dataset info
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardBody([
html.H4("Dataset Overview", className="card-title"),
html.P(f"File: {Path(filepath).name}"),
html.P(f"Rows: {len(df):,} | Columns: {len(df.columns)}"),
html.P(f"Numeric: {len(numeric_cols)} | Categorical: {len(cat_cols)} | Time: {len(time_cols)}")
])
], className="mb-4")
])
]),
# Summary statistics
dbc.Row([
dbc.Col([
dcc.Graph(figure=plots['summary']) if plots.get('summary') else html.Div()
])
], className="mb-4"),
# Time series
dbc.Row([
dbc.Col([
dcc.Graph(figure=plots['timeseries']) if plots.get('timeseries') else html.Div()
])
], className="mb-4") if plots.get('timeseries') else html.Div(),
# Distributions
dbc.Row([
dbc.Col([
dcc.Graph(figure=plots['distributions']) if plots.get('distributions') else html.Div()
])
], className="mb-4"),
# Correlation heatmap
dbc.Row([
dbc.Col([
dcc.Graph(figure=plots['correlation']) if plots.get('correlation') else html.Div()
])
], className="mb-4") if plots.get('correlation') else html.Div(),
# Categorical analysis
dbc.Row([
dbc.Col([
dcc.Graph(figure=plots['categorical']) if plots.get('categorical') else html.Div()
])
], className="mb-4") if plots.get('categorical') else html.Div(),
# Scatter matrix
dbc.Row([
dbc.Col([
dcc.Graph(figure=plots['scatter_matrix']) if plots.get('scatter_matrix') else html.Div()
])
], className="mb-4") if plots.get('scatter_matrix') else html.Div(),
# Footer
dbc.Row([
dbc.Col([
html.Hr(),
html.P("Interactive Data Analysis Dashboard | Generated with Plotly Dash",
className="text-center text-muted")
])
])
], fluid=True)
# Save standalone HTML if output_dir specified
if output_dir:
output_dir = Path(output_dir)
output_dir.mkdir(parents=True, exist_ok=True)
# Save individual plots as HTML
for plot_name, fig in plots.items():
if fig:
html_file = output_dir / f"{plot_name}.html"
fig.write_html(html_file)
print(f"Saved: {html_file}")
print(f"\nStatic visualizations saved to: {output_dir}")
# Run server
print(f"\n{'='*80}")
print(f"Starting dashboard server...")
print(f"Access the dashboard at: http://127.0.0.1:{port}")
print(f"Press Ctrl+C to stop the server")
print(f"{'='*80}\n")
app.run_server(debug=False, port=port)
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python create_dashboard.py <csv_file> [output_dir] [port]")
print("\nExample:")
print(" python create_dashboard.py data.csv")
print(" python create_dashboard.py data.csv ./visualizations 8050")
sys.exit(1)
filepath = sys.argv[1]
output_dir = sys.argv[2] if len(sys.argv) > 2 else None
port = int(sys.argv[3]) if len(sys.argv) > 3 else 8050
if not Path(filepath).exists():
print(f"Error: File not found: {filepath}")
sys.exit(1)
build_dashboard(filepath, output_dir, port)
#!/usr/bin/env python3
"""
Automatically impute missing values in a dataset based on analysis.
"""
import pandas as pd
import numpy as np
import json
import sys
from pathlib import Path
from sklearn.impute import KNNImputer
from sklearn.preprocessing import LabelEncoder
def impute_column(df, col, method, params=None):
"""
Impute missing values in a specific column using the specified method.
Args:
df: DataFrame
col: Column name
method: Imputation method
params: Additional parameters for the method
Returns:
Series with imputed values
"""
series = df[col].copy()
params = params or {}
if method == 'mean':
return series.fillna(series.mean())
elif method == 'median':
return series.fillna(series.median())
elif method == 'mode':
mode_value = series.mode()
if len(mode_value) > 0:
return series.fillna(mode_value[0])
return series
elif method == 'most_frequent':
# Same as mode but explicitly for categorical
most_frequent = series.value_counts().idxmax() if len(series.value_counts()) > 0 else None
return series.fillna(most_frequent)
elif method == 'constant':
fill_value = params.get('fill_value', 'Unknown')
return series.fillna(fill_value)
elif method == 'forward_fill':
return series.fillna(method='ffill')
elif method == 'backward_fill':
return series.fillna(method='bfill')
elif method == 'interpolate':
if pd.api.types.is_numeric_dtype(series):
return series.interpolate(method='linear')
else:
return series.fillna(method='ffill') # Fallback for non-numeric
elif method == 'knn':
# KNN imputation requires numeric data
# For mixed datasets, we'll use KNN on numeric columns only
return series # Will be handled by batch KNN imputation
elif method == 'drop_rows':
# Mark for row deletion (handled at DataFrame level)
return series
elif method == 'drop_or_flag':
# For columns with too many missing values
# Option to create a missing indicator instead of dropping
if params.get('create_indicator', False):
return series
return series
else:
print(f"Warning: Unknown imputation method '{method}' for column '{col}'. Skipping.")
return series
def batch_knn_imputation(df, columns_for_knn, n_neighbors=5):
"""
Perform KNN imputation on multiple numeric columns simultaneously.
Args:
df: DataFrame
columns_for_knn: List of columns to impute using KNN
n_neighbors: Number of neighbors for KNN
Returns:
DataFrame with KNN-imputed values
"""
if not columns_for_knn:
return df
# Select only numeric columns for KNN
numeric_cols = [col for col in columns_for_knn if pd.api.types.is_numeric_dtype(df[col])]
if not numeric_cols:
return df
# Perform KNN imputation
imputer = KNNImputer(n_neighbors=n_neighbors)
df[numeric_cols] = imputer.fit_transform(df[numeric_cols])
return df
def impute_missing_values(filepath, analysis_json=None, output_file=None, create_missing_indicators=False):
"""
Automatically impute missing values based on analysis results.
Args:
filepath: Path to the CSV file
analysis_json: Path to analysis JSON (optional, will analyze if not provided)
output_file: Path to save imputed data (optional)
create_missing_indicators: Whether to create binary columns indicating missingness
Returns:
DataFrame with imputed values and imputation report
"""
# Load data
df = pd.read_csv(filepath)
original_rows = len(df)
# Load or generate analysis
if analysis_json and Path(analysis_json).exists():
with open(analysis_json, 'r') as f:
analysis = json.load(f)
else:
# Import and run analysis
from analyze_missing_values import analyze_missing_values
analysis = analyze_missing_values(filepath)
# Track imputation actions
imputation_log = {}
columns_to_drop = []
rows_to_drop_mask = pd.Series([False] * len(df))
knn_columns = []
# Create missing indicators if requested
if create_missing_indicators:
for col in analysis['column_analysis'].keys():
indicator_col = f'{col}_was_missing'
df[indicator_col] = df[col].isna().astype(int)
# Process each column with missing values
for col, col_analysis in analysis['column_analysis'].items():
strategy = col_analysis['imputation_strategy']
method = strategy['method']
imputation_log[col] = {
'method': method,
'missing_before': col_analysis['missing_count'],
'reasoning': strategy['reasoning']
}
if method == 'drop_or_flag':
if col_analysis['missing_percentage'] > 70:
columns_to_drop.append(col)
imputation_log[col]['action'] = f"Dropped column ({col_analysis['missing_percentage']:.1f}% missing)"
else:
# Keep column, user can decide
imputation_log[col]['action'] = f"Flagged for review ({col_analysis['missing_percentage']:.1f}% missing)"
elif method == 'drop_rows':
rows_to_drop_mask |= df[col].isna()
imputation_log[col]['action'] = "Marked rows for deletion"
elif method == 'knn':
knn_columns.append(col)
imputation_log[col]['action'] = "Queued for KNN imputation"
elif method.startswith('constant:'):
# Extract the constant value
fill_value = method.split(':', 1)[1]
df[col] = impute_column(df, col, 'constant', {'fill_value': fill_value})
imputation_log[col]['action'] = f"Filled with constant: {fill_value}"
imputation_log[col]['missing_after'] = df[col].isna().sum()
else:
# Standard imputation methods
df[col] = impute_column(df, col, method)
imputation_log[col]['action'] = f"Imputed using {method}"
imputation_log[col]['missing_after'] = df[col].isna().sum()
# Perform batch KNN imputation
if knn_columns:
print(f"Performing KNN imputation on {len(knn_columns)} columns...")
df = batch_knn_imputation(df, knn_columns)
for col in knn_columns:
imputation_log[col]['action'] = "Imputed using KNN"
imputation_log[col]['missing_after'] = df[col].isna().sum()
# Drop columns marked for deletion
if columns_to_drop:
df = df.drop(columns=columns_to_drop)
print(f"Dropped {len(columns_to_drop)} columns with excessive missing values")
# Drop rows marked for deletion
if rows_to_drop_mask.any():
rows_to_drop = rows_to_drop_mask.sum()
df = df[~rows_to_drop_mask].reset_index(drop=True)
print(f"Dropped {rows_to_drop} rows with missing critical values")
# Generate report
report = {
'input_file': str(filepath),
'original_rows': original_rows,
'final_rows': len(df),
'rows_dropped': original_rows - len(df),
'columns_dropped': len(columns_to_drop),
'columns_imputed': len([c for c in imputation_log if 'missing_after' in imputation_log[c]]),
'imputation_log': imputation_log
}
# Save imputed data
if output_file:
df.to_csv(output_file, index=False)
print(f"\nImputed data saved to: {output_file}")
report['output_file'] = str(output_file)
return df, report
def print_imputation_report(report):
"""Print a formatted imputation report."""
print("\n" + "="*80)
print("IMPUTATION REPORT")
print("="*80)
print(f"\nInput file: {report['input_file']}")
if 'output_file' in report:
print(f"Output file: {report['output_file']}")
print(f"\nData dimensions:")
print(f" - Original rows: {report['original_rows']:,}")
print(f" - Final rows: {report['final_rows']:,}")
if report['rows_dropped'] > 0:
print(f" - Rows dropped: {report['rows_dropped']:,}")
print(f"\nImputation summary:")
print(f" - Columns imputed: {report['columns_imputed']}")
if report['columns_dropped'] > 0:
print(f" - Columns dropped: {report['columns_dropped']}")
print("\n" + "-"*80)
print("COLUMN-BY-COLUMN IMPUTATION LOG")
print("-"*80)
for col, log in report['imputation_log'].items():
print(f"\n📊 Column: {col}")
print(f" Method: {log['method']}")
print(f" Missing before: {log['missing_before']}")
if 'missing_after' in log:
print(f" Missing after: {log['missing_after']}")
print(f" Action: {log['action']}")
print(f" Reasoning: {log['reasoning']}")
print("\n" + "="*80 + "\n")
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python impute_missing_values.py <csv_file> [analysis_json] [output_file]")
print("\nExample:")
print(" python impute_missing_values.py data.csv")
print(" python impute_missing_values.py data.csv analysis.json data_imputed.csv")
sys.exit(1)
filepath = sys.argv[1]
analysis_json = sys.argv[2] if len(sys.argv) > 2 else None
output_file = sys.argv[3] if len(sys.argv) > 3 else filepath.replace('.csv', '_imputed.csv')
if not Path(filepath).exists():
print(f"Error: File not found: {filepath}")
sys.exit(1)
print("Starting automatic imputation...")
df_imputed, report = impute_missing_values(
filepath,
analysis_json=analysis_json,
output_file=output_file,
create_missing_indicators=False
)
print_imputation_report(report)
# Save report as JSON
report_json = output_file.replace('.csv', '_report.json')
with open(report_json, 'w') as f:
json.dump(report, f, indent=2)
print(f"Detailed report saved to: {report_json}")
Related skills
FAQ
What tools does data-analyst use?
SQL or Python aggregations with quality checks before summarizing metrics and trends.
How are insights presented?
Markdown tables and bullet insights separating observations from hypotheses.
Does it build production pipelines?
No. It focuses on exploratory analysis rather than ETL pipeline engineering.
Is Data Analyst safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.