Synthetic Data Generation
Problem
Testing and development require realistic data, but production data has privacy concerns and edge cases are rare. Need deterministic, comprehensive test data that covers all user archetypes and scenarios.
Solution
Persona-based synthetic data generation with behavioral modeling:
Persona Taxonomy (25 Archetypes)
# personas/taxonomy.yml
personas:
# Financial States
- id: wealthy_stable
financial:
income_range: [150000, 500000]
savings_rate: [0.2, 0.4]
risk_tolerance: high
- id: struggling_student
financial:
income_range: [0, 25000]
savings_rate: [-0.1, 0.05]
risk_tolerance: low
- id: retired_fixed_income
financial:
income_range: [30000, 60000]
savings_rate: [-0.05, 0.1]
risk_tolerance: very_low
# Behavioral Traits
- id: early_adopter
behavior:
tech_savvy: high
feature_exploration: aggressive
feedback_tendency: high
- id: power_user
behavior:
session_frequency: daily
feature_depth: expert
edge_case_likelihood: highGeneration Pipeline
# generators/user_generator.py
from dataclasses import dataclass
from typing import List
import random
@dataclass
class UserProfile:
id: str
persona_id: str
financial_state: dict
behavior_traits: dict
activity_history: List[dict]
def generate_user(persona: dict, seed: int = None) -> UserProfile:
"""Generate user matching persona archetype."""
if seed:
random.seed(seed)
return UserProfile(
id=f"user_{random.randint(1000, 9999)}",
persona_id=persona['id'],
financial_state=sample_financial_state(persona['financial']),
behavior_traits=sample_behavior(persona['behavior']),
activity_history=generate_activity_sequence(persona)
)
def sample_financial_state(config: dict) -> dict:
"""Sample within configured ranges."""
return {
'income': random.uniform(*config['income_range']),
'savings_rate': random.uniform(*config['savings_rate']),
'risk_tolerance': config['risk_tolerance']
}Monte Carlo Stress Testing
# testing/stress_test.py
def monte_carlo_scenario(persona_distribution: dict, iterations: int = 10000):
"""Run Monte Carlo simulation across user personas."""
results = []
for _ in range(iterations):
# Sample persona based on distribution
persona = weighted_sample(persona_distribution)
user = generate_user(persona)
# Run scenario
outcome = simulate_user_journey(user)
results.append({
'persona': persona['id'],
'outcome': outcome,
'deviation_score': calculate_deviation(outcome, expected)
})
return analyze_results(results)Deviation Scoring
Track how far synthetic behavior deviates from expected:
def calculate_deviation(actual: dict, expected: dict) -> float:
"""Calculate normalized deviation score."""
deviations = []
for key in expected:
if key in actual:
deviation = abs(actual[key] - expected[key]) / expected[key]
deviations.append(deviation)
return sum(deviations) / len(deviations)Usage
Generating Test Dataset
# Generate 1000 users across all personas
python -m generators.batch \
--personas personas/taxonomy.yml \
--count 1000 \
--output test_data/users.json \
--seed 42 # ReproducibleDogfooding Test Data
Use generated data in development:
# Load synthetic users for testing
users = load_synthetic_users('test_data/users.json')
# Filter by persona for targeted testing
power_users = [u for u in users if u.persona_id == 'power_user']
edge_case_users = [u for u in users if u.behavior_traits['edge_case_likelihood'] == 'high']Trade-offs
When to Use
- Privacy-sensitive domains
- Comprehensive edge case coverage
- Reproducible test scenarios
- Load testing with realistic distributions
When NOT to Use
- Small, simple tests
- When real anonymized data is available
- Quick prototyping
Source
Extracted from Aura data generation research for financial application testing.
Related
- TDD Workflow - Testing methodology
- Optimal Small AI - Training data generation
- Procedural Generation - Code generation