All skills
Skillintermediate

Data Analysis Script with Ralph

This example demonstrates using Ralph Orchestrator to create a data analysis script with pandas, visualization, and reporting.

Claude Code Knowledge Pack7/10/2026

Overview

Data Analysis Script with Ralph

This example demonstrates using Ralph Orchestrator to create a data analysis script with pandas, visualization, and reporting.

Task Description

Create a Python data analysis script that:

  • Loads and cleans CSV data
  • Performs statistical analysis
  • Creates visualizations
  • Generates HTML report

PROMPT.md File

# Task: Build Sales Data Analysis Script

Create a Python script to analyze sales data with the following requirements:

## Data Processing

1. Load sales data from CSV file
2. Clean and validate data:
   - Handle missing values
   - Convert data types
   - Remove duplicates
   - Validate date ranges

## Analysis Requirements

1. **Sales Metrics**
   - Total revenue by month
   - Average order value
   - Top 10 products by revenue
   - Sales growth rate

2. **Customer Analysis**
   - Customer segmentation (RFM analysis)
   - Customer lifetime value
   - Repeat purchase rate
   - Geographic distribution

3. **Product Analysis**
   - Best/worst performing products
   - Product category performance
   - Seasonal trends
   - Inventory turnover

## Visualizations

Create the following charts:
1. Monthly revenue trend (line chart)
2. Product category breakdown (pie chart)
3. Customer distribution map (geographic)
4. Sales heatmap by day/hour
5. Top products bar chart

## Output

Generate an HTML report with:
- Executive summary
- Key metrics dashboard
- Interactive charts (using plotly)
- Data tables
- Insights and recommendations

## File Structure

sales-analysis/ ├── analyze.py # Main analysis script ├── data_loader.py # Data loading and cleaning ├── analysis.py # Analysis functions ├── visualizations.py # Chart generation ├── report_generator.py # HTML report creation ├── requirements.txt # Dependencies ├── config.yaml # Configuration ├── templates/ # HTML templates │ └── report.html ├── data/ # Data directory │ └── sales.csv # Sample data └── output/ # Output directory └── report.html # Generated report


## Sample Data Structure

CSV columns:
- order_id, customer_id, product_id, product_name, category
- quantity, unit_price, total_price, discount
- order_date, ship_date, region, payment_method

Running Ralph

ralph init
cp data-analysis-prompt.md PROMPT.md
ralph run --agent claude --max-iterations 35

Expected Output

analyze.py (Main Script)

#!/usr/bin/env python3
"""
Sales Data Analysis Script
Analyzes sales data and generates comprehensive HTML report
"""

from datetime import datetime

from pathlib import Path

from data_loader import DataLoader
from analysis import SalesAnalyzer, CustomerAnalyzer, ProductAnalyzer
from visualizations import ChartGenerator
from report_generator import ReportGenerator

# Setup logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

def load_config(config_path='config.yaml'):
    """Load configuration from YAML file"""
    with open(config_path, 'r') as f:
        return yaml.safe_load(f)

def main():
    """Main analysis pipeline"""
    logger.info("Starting sales data analysis...")
    
    # Load configuration
    config = load_config()
    
    # Step 1: Load and clean data
    logger.info("Loading data...")
    loader = DataLoader(config['data']['input_file'])
    df = loader.load_and_clean()
    logger.info(f"Loaded {len(df)} records")
    
    # Step 2: Perform analysis
    logger.info("Performing analysis...")
    
    # Sales analysis
    sales_analyzer = SalesAnalyzer(df)
    sales_metrics = {
        'total_revenue': sales_analyzer.calculate_total_revenue(),
        'monthly_revenue': sales_analyzer.get_monthly_revenue(),
        'avg_order_value': sales_analyzer.calculate_avg_order_value(),
        'growth_rate': sales_analyzer.calculate_growth_rate(),
        'top_products': sales_analyzer.get_top_products(10)
    }
    
    # Customer analysis
    customer_analyzer = CustomerAnalyzer(df)
    customer_metrics = {
        'total_customers': customer_analyzer.count_unique_customers(),
        'repeat_rate': customer_analyzer.calculate_repeat_rate(),
        'rfm_segments': customer_analyzer.perform_rfm_analysis(),
        'lifetime_value': customer_analyzer.calculate_clv(),
        'geographic_dist': customer_analyzer.get_geographic_distribution()
    }
    
    # Product analysis
    product_analyzer = ProductAnalyzer(df)
    product_metrics = {
        'category_performance': product_analyzer.analyze_categories(),
        'seasonal_trends': product_analyzer.find_seasonal_trends(),
        'inventory_turnover': product_analyzer.calculate_turnover(),
        'product_ranking': product_analyzer.rank_products()
    }
    
    # Step 3: Generate visualizations
    logger.info("Creating visualizations...")
    chart_gen = ChartGenerator(df)
    
    charts = {
        'revenue_trend': chart_gen.create_revenue_trend(
            sales_metrics['monthly_revenue']
        ),
        'category_pie': chart_gen.create_category_pie(
            product_metrics['category_performance']
        ),
        'customer_map': chart_gen.create_customer_map(
            customer_metrics['geographic_dist']
        ),
        'sales_heatmap': chart_gen.create_sales_heatmap(),
        'top_products_bar': chart_gen.create_top_products_bar(
            sales_metrics['top_products']
        )
    }
    
    # Step 4: Generate report
    logger.info("Generating HTML report...")
    report_gen = ReportGenerator()
    
    report_data = {
        'generated_at': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        'record_count': len(df),
        'date_range': f"{df['order_date'].min()} to {df['order_date'].max()}",
        'sales_metrics': sales_metrics,
        'customer_metrics': customer_metrics,
        'product_metrics': product_metrics,
        'charts': charts,
        'insights': generate_insights(sales_metrics, customer_metrics, product_metrics)
    }
    
    output_path = Path(config['output']['report_path'])
    output_path.parent.mkdir(parents=True, exist_ok=True)
    
    report_gen.generate(report_data, output_path)
    
    logger.info(f"Report generated: {output_path}")
    logger.info("Analysis complete!")
    
    return output_path

def generate_insights(sales, customers, products):
    """Generate insights from analysis results"""
    insights = []
    
    # Revenue insights
    if sales['growth_rate'] > 0:
        insights.append(f"Revenue is growing at {sales['growth_rate']:.1f}% monthly")
    else:
        insights.append(f"Revenue declined by {abs(sales['growth_rate']):.1f}% monthly")
    
    # Customer insights
    repeat_rate = customers['repeat_rate']
    if repeat_rate > 0.3:
        insights.append(f"Strong customer loyalty with {repeat_rate:.1%} repeat rate")
    else:
        insights.append(f"Opportunity to improve retention (current: {repeat_rate:.1%})")
    
    # Product insights
    top_category = products['category_performance'].iloc[0]
    insights.append(f"{top_category['category']} is the top performing category")
    
    return insights

if __name__ == '__main__':
    try:
        report_path = main()
        print(f"\
✅ Analysis complete! Report saved to: {report_path}")
    except Exception as e:
        logger.error(f"Analysis failed: {e}")
        raise

data_loader.py


from datetime import datetime

logger = logging.getLogger(__name__)

class DataLoader:
    """Handle data loading and cleaning"""
    
    def __init__(self, filepath):
        self.filepath = filepath
    
    def load_and_clean(self):
        """Load CSV and perform cleaning"""
        # Load data
        df = pd.read_csv(self.filepath)
        logger.info(f"Loaded {len(df)} raw records")
        
        # Clean data
        df = self.remove_duplicates(df)
        df = self.handle_missing_values(df)
        df = self.convert_data_types(df)
        df = self.validate_data(df)
        
        logger.info(f"Cleaned data: {len(df)} records")
        return df
    
    def remove_duplicates(self, df):
        """Remove duplicate records"""
        before = len(df)
        df = df.drop_duplicates(subset=['order_id'])
        after = len(df)
        
        if before > after:
            logger.info(f"Removed {before - after} duplicate records")
        
        return df
    
    def handle_missing_values(self, df):
        """Handle missing values appropriately"""
        # Fill numeric columns with 0
        numeric_cols = df.select_dtypes(include=[np.number]).columns
        df[numeric_cols] = df[numeric_cols].fillna(0)
        
        # Fill categorical columns with 'Unknown'
        categorical_cols = df.select_dtypes(include=['object']).columns
        df[categorical_cols] = df[categorical_cols].fillna('Unknown')
        
        return df
    
    def convert_data_types(self, df):
        """Convert columns to appropriate data types"""
        # Convert dates
        date_columns = ['order_date', 'ship_date']
        for col in date_columns:
            if col in df.columns:
                df[col] = pd.to_datetime(df[col], errors='coerce')
        
        # Convert numeric columns
        numeric_columns = ['quantity', 'unit_price', 'total_price', 'discount']
        for col in numeric_columns:
            if col in df.columns:
                df[col] = pd.to_numeric(df[col], errors='coerce')
        
        # Convert IDs to string
        id_columns = ['order_id', 'customer_id', 'product_id']
        for col in id_columns:
            if col in df.columns:
                df[col] = df[col].astype(str)
        
        return df
    
    def validate_data(self, df):
        """Validate data integrity"""
        # Remove rows with invalid dates
        if 'order_date' in df.columns:
            df = df[df['order_date'].notna()]
        
        # Remove rows with negative prices
        if 'total_price' in df.columns:
            df = df[df['total_price'] >= 0]
        
        # Remove rows with invalid quantities
        if 'quantity' in df.columns:
            df = df[df['quantity'] > 0]
        
        return df
    
    def generate_sample_data(self, num_records=1000):
        """Generate sample sales data for testing"""
        np.random.seed(42)
        
        # Generate dates
        dates = pd.date_range(
            start='2023-01-01',
            end='2023-12-31',
            periods=num_records
        )
        
        # Categories and products
        categories = ['Electronics', 'Clothing', 'Books', 'Home', 'Sports']
        products = {
            'Electronics': ['Laptop', 'Phone', 'Tablet', 'Headphones'],
            'Clothing': ['Shirt', 'Pants', 'Jacket', 'Shoes'],
            'Books': ['Fiction', 'Non-fiction', 'TextBook', 'Magazine'],
            'Home': ['Furniture', 'Decor', 'Kitchen', 'Bedding'],
            'Sports': ['Equipment', 'Apparel', 'Footwear', 'Accessories']
        }
        
        # Generate records
        records = []
        for i in range(num_records):
            category = np.random.choice(categories)
            product = np.random.choice(products[category])
            quantity = np.random.randint(1, 10)
            unit_price = np.random.uniform(10, 500)
            discount = np.random.uniform(0, 0.3)
            
            records.append({
                'order_id': f'ORD{i:05d}',
                'customer_id': f'CUST{np.random.randint(1, 200):04d}',
                'product_id': f'PROD{np.random.randint(1, 50):03d}',
                'product_name': product,
                'category': category,
                'quantity': quantity,
                'unit_price': unit_price,
                'total_price': quantity * unit_price * (1 - discount),
                'discount': discount,
                'order_date': dates[i],
                'ship_date': dates[i] + pd.Timedelta(days=np.random.randint(1, 7)),
                'region': np.random.choice(['North', 'South', 'East', 'West']),
                'payment_method': np.random.choice(['Credit Card', 'PayPal', 'Cash'])
            })
        
        return pd.DataFrame(records)

visualizations.py


from plotly.subplots import make_subplots

class ChartGenerator:
    """Generate interactive charts using Plotly"""
    
    def __init__(self, df):
        self.df = df
    
    def create_revenue_trend(self, monthly_revenue):
        """Create monthly revenue trend line chart"""
        fig = go.Figure()
        
        fig.add_trace(go.Scatter(
            x=monthly_revenue.index,
            y=monthly_revenue.values,
            mode='lines+markers',
            name='Revenue',
            line=dict(color='#1f77b4', width=3),
            marker=dict(size=8)
        ))
        
        fig.update_layout(
            title='Monthly Revenue Trend',
            xaxis_title='Month',
            yaxis_title='Revenue ($)',
            hovermode='x unified',
            template='plotly_white'
        )
        
        return fig.to_html(include_plotlyjs='cdn')
    
    def create_category_pie(self, category_data):
        """Create category breakdown pie chart"""
        fig = px.pie(
            category_data,
            values='revenue',
            names='category',
            title='Revenue by Category',
            color_discrete_sequence=px.colors.qualitative.Set3
        )
        
        fig.update_traces(
            textposition='inside',
            textinfo='percent+label'
        )
        
        return fig.to_html(include_plotlyjs='cdn')
    
    def create_sales_heatmap(self):
        """Create sales heatmap by day and hour"""
        # Extract day and hour
        self.df['day_of_week'] = self.df['order_date'].dt.day_name()
        self.df['hour'] = self.df['order_date'].dt.hour
        
        # Aggregate sales
        heatmap_data = self.df.groupby(['day_of_week', 'hour'])[
            'total_price'
        ].sum().reset_index()
        
        # Pivot for heatmap
        pivot_table = heatmap_data.pivot(
            index='day_of_week',
            columns='hour',
            values='total_price'
        )
        
        # Reorder days
        days_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 
                     'Friday', 'Saturday', 'Sunday']
        pivot_table = pivot_table.reindex(days_order)
        
        fig = go.Figure(data=go.Heatmap(
            z=pivot_table.values,
            x=pivot_table.columns,
            y=pivot_table.index,
            colorscale='Viridis',
            text=pivot_table.values.round(0),
            texttemplate='%{text}'