diff --git a/docs/tutorials.md b/docs/tutorials.md index c0398b47..93a635d8 100644 --- a/docs/tutorials.md +++ b/docs/tutorials.md @@ -26,4 +26,4 @@ Explore synthetic data tutorials with the option to run them **either in Google | Calculate accuracy and privacy metrics for **Quality Assurance** | [![Run on Colab](https://img.shields.io/badge/Open%20in-Colab-blue?logo=google-colab)](https://colab.research.google.com/github/mostly-ai/mostlyai/blob/main/docs/tutorials/quality-assurance/quality-assurance.ipynb) | [View Notebook](./tutorials/quality-assurance/quality-assurance.ipynb) | | Enrich Sensitive Data with LLMs using Synthetic Replicas | [![Run on Colab](https://img.shields.io/badge/Open%20in-Colab-blue?logo=google-colab)](https://colab.research.google.com/github/mostly-ai/mostlyai/blob/main/docs/tutorials/synthetic-enrich/synthetic-enrich.ipynb) | [View Notebook](./tutorials/synthetic-enrich/synthetic-enrich.ipynb) | | MOSTLY AI vs. SDV comparison: single-table scenario | [![Run on Colab](https://img.shields.io/badge/Open%20in-Colab-blue?logo=google-colab)](https://colab.research.google.com/github/mostly-ai/mostlyai/blob/main/docs/tutorials/synthetic-enrich/sdv-comparison/single-tables-scenario.ipynb) | [View Notebook](./tutorials/sdv-comparison/single-table-scenario/single-table-scenario.ipynb) | -| MOSTLY AI vs. SDV comparison: multi-table scenario | [![Run on Colab](https://img.shields.io/badge/Open%20in-Colab-blue?logo=google-colab)](https://colab.research.google.com/github/mostly-ai/mostlyai/blob/main/docs/tutorials/synthetic-enrich/sdv-comparison/multi-tables-scenario.ipynb) | [View Notebook](./tutorials/sdv-comparison/multi-table-scenario/multi-table-scenario.ipynb) | +| MOSTLY AI vs. SDV comparison: sequential scenario | [![Run on Colab](https://img.shields.io/badge/Open%20in-Colab-blue?logo=google-colab)](https://colab.research.google.com/github/mostly-ai/mostlyai/blob/main/docs/tutorials/synthetic-enrich/sdv-comparison/sequential-scenario/sequential-scenario.ipynb) | [View Notebook](./tutorials/sdv-comparison/sequential-scenario/sequential-scenario.ipynb) | diff --git a/docs/tutorials/sdv-comparison/sequential-scenario/sequential-scenario.ipynb b/docs/tutorials/sdv-comparison/sequential-scenario/sequential-scenario.ipynb new file mode 100644 index 00000000..49b84795 --- /dev/null +++ b/docs/tutorials/sdv-comparison/sequential-scenario/sequential-scenario.ipynb @@ -0,0 +1,731 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# MOSTLY AI vs. SDV Comparison - Sequential Scenario \"Run\n", + "\n", + "This notebook provides a comprehensive comparison between two leading synthetic data generation platforms:\n", + "- **SDV (Synthetic Data Vault)** - Business Source License\n", + "- **MOSTLY AI Synthetic Data SDK** - Apache 2.0 License - Open Source\n", + "\n", + "In this comparison, we are going to walk through the synthesis of a relational two-table structure with sequential values using the [Berka dataset](https://github.com/mostly-ai/public-demo-data/tree/dev/berka/data).\n", + "\n", + "## Comparison Methodology\n", + "\n", + "1. **Data Preparation**: Load, inspect, and preprocess the multi-table dataset\n", + "2. **Data Splitting**: Create train/test splits\n", + "3. **Model Training**: Train both SDV and MOSTLY AI generators on the training data\n", + "4. **Synthetic Data Generation**: Generate synthetic datasets using both platforms\n", + "5. **Performance Analysis**: Compare training time, generation speed, and data quality\n", + "\n", + "## Key Challenges in Two-Table Synthesis\n", + "\n", + "- **Sequential Dependencies**: Preserving temporal patterns in transaction data\n", + "- **Data Quality**: Ensuring synthetic data maintains statistical properties and business logic" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Install SDK in CLIENT mode\n", + "!uv pip install -U mostlyai sdv graphviz\n", + "# Or install in LOCAL mode\n", + "!uv pip install -U 'mostlyai[local]' sdv graphviz\n", + "# Note: Restart kernel session after installation!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Data Loading and Initial Exploration\n", + "\n", + "First, let's load our multi-table dataset and examine its structure to understand:\n", + "- Table schemas and data types\n", + "- Data quality and completeness\n", + "- Business logic and constraints\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "base_url = \"https://github.com/mostly-ai/public-demo-data/raw/dev/berka/data/\"\n", + "originals = {\n", + " \"account\": pd.read_csv(base_url + \"account.csv.gz\", low_memory=False),\n", + " \"transaction\": pd.read_csv(base_url + \"trans.csv.gz\", low_memory=False),\n", + "}\n", + "\n", + "# Drop unnecessary columns from transaction table\n", + "originals[\"transaction\"].drop(columns=[\"bank\", \"account\"], inplace=True)\n", + "\n", + "# Convert date columns to datetime\n", + "originals[\"account\"][\"date\"] = pd.to_datetime(originals[\"account\"][\"date\"])\n", + "originals[\"transaction\"][\"date\"] = pd.to_datetime(originals[\"transaction\"][\"date\"])\n", + "\n", + "# Display samples\n", + "for k in originals:\n", + " print(\"===\", k, \"===\")\n", + " display(originals[k].sample(n=3))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Strategic Data Splitting for Multi-Table Scenarios\n", + "\n", + "When dealing with related tables like accounts and transactions, data splitting becomes more complex than simple random sampling due to the links between data tables. \n", + "\n", + "In order to make coherent assessments of data quality, we need to create meaningful train and test cohorts.\n", + "\n", + "**Key Considerations:**\n", + "- **Business Logic:** Accounts and transactions can only exist in the training set if their associated client is also in the training set.\n", + "- **Data Leakage Prevention:** Avoid information bleeding between train/test sets.\n", + "\n", + "**Our Approach:**\n", + "1. **Split accounts first (80/20 train/test)**: We split the `account` table using an 80/20 ratio. This ensures customer-related information is kept together per split.\n", + " \n", + "2. **Assign related tables based on account membership:** \n", + " - **Transactions:** All linked via `account_id`. These tables follow the same assignment logic.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.model_selection import train_test_split\n", + "\n", + "print(\"āœ‚ļø Performing strategic multi-table data splitting based on accounts...\")\n", + "\n", + "# Step 1: Split accounts using 80/20 ratio\n", + "accounts_train, accounts_test = train_test_split(originals[\"account\"], test_size=0.2, random_state=42)\n", + "\n", + "print(\"šŸ¦ Account split:\")\n", + "print(\n", + " f\" - Training set: {len(accounts_train):,} accounts ({len(accounts_train) / len(originals['account']) * 100:.1f}%)\"\n", + ")\n", + "print(f\" - Test set: {len(accounts_test):,} accounts ({len(accounts_test) / len(originals['account']) * 100:.1f}%)\")\n", + "\n", + "# Step 2: Create account ID sets for lookup\n", + "train_account_ids = set(accounts_train[\"account_id\"])\n", + "test_account_ids = set(accounts_test[\"account_id\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"šŸ”„ Assigning transactions based on account split...\")\n", + "\n", + "# Split transactions linked to training and test accounts\n", + "transactions_train = originals[\"transaction\"][originals[\"transaction\"][\"account_id\"].isin(train_account_ids)].copy()\n", + "transactions_test = originals[\"transaction\"][originals[\"transaction\"][\"account_id\"].isin(test_account_ids)].copy()\n", + "\n", + "print(\"āœ… Splitting complete!\")\n", + "print(f\" - Training accounts: {len(accounts_train):,}\")\n", + "print(f\" - Training transactions: {len(transactions_train):,}\")\n", + "print(f\" - Test accounts: {len(accounts_test):,}\")\n", + "print(f\" - Test transactions: {len(transactions_test):,}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"šŸ’¾ Saving split train/test tables...\")\n", + "\n", + "accounts_train.to_parquet(\"./data/two-table/accounts_train.parquet\", index=False)\n", + "accounts_test.to_parquet(\"./data/two-table/accounts_test.parquet\", index=False)\n", + "transactions_train.to_parquet(\"./data/two-table/transactions_train.parquet\", index=False)\n", + "transactions_test.to_parquet(\"./data/two-table/transactions_test.parquet\", index=False)\n", + "\n", + "print(\"āœ… All train/test splits saved to ./data/two-table/\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. SDV (Synthetic Data Vault) Implementation\n", + "\n", + "**About SDV:**\n", + "- Business Source License Python library for synthetic data generation\n", + "- Supports single-table and multi-table scenarios\n", + "- Uses statistical modeling and machine learning approaches\n", + "- Provides HMASynthesizer for hierarchical multi-table synthesis\n", + "\n", + "**Key Features:**\n", + "- **Metadata Detection**: Automatically infers data types and relationships\n", + "- **Relationship Modeling**: Handles parent-child table relationships\n", + "- **Privacy Protection**: Generates synthetic data that preserves statistical properties while protecting individual privacy\n", + "- **Extensible**: Multiple synthesizer options (GaussianCopula, CTGAN, CopulaGAN, etc.)\n", + "\n", + "**Limitations:**\n", + "- Current version only supports one parent per child table\n", + "- Complex multi-parent relationships require modeling simplification\n", + "- Performance scales with data complexity\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from sdv.metadata import Metadata\n", + "from sdv.multi_table import HMASynthesizer\n", + "\n", + "print(\"šŸ—ļø Building SDV metadata configuration...\")\n", + "\n", + "# Auto-detect metadata using only the relevant tables\n", + "metadata = Metadata.detect_from_dataframes(\n", + " data={\"account\": accounts_train, \"transaction\": transactions_train}, infer_keys=\"primary_and_foreign\"\n", + ")\n", + "\n", + "print(\"āœ… Base metadata auto-detected with relationships\")\n", + "\n", + "# View auto-detected relationships graphically\n", + "metadata.visualize()\n", + "\n", + "# Inspect relationships and table configuration as raw dictionary\n", + "metadata_dict = metadata.to_dict()\n", + "print(\"\\nšŸ“‹ Complete SDV Metadata Dictionary:\")\n", + "print(metadata_dict)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3.2 SDV Model Training\n", + "\n", + "**HMASynthesizer Overview:**\n", + "- **Hierarchical Modeling**: Learns parent-child relationships\n", + "- **Statistical Approach**: Uses copulas and Gaussian distributions\n", + "- **Multi-step Process**: \n", + " 1. Preprocesses tables and infers constraints\n", + " 2. Learns relationships between parent and child tables\n", + " 3. Models individual table distributions\n", + " \n", + "**Training Phases:**\n", + "- **Preprocess Tables**: Data cleaning and type inference\n", + "- **Learning Relationships**: Analyzing foreign key dependencies \n", + "- **Modeling Tables**: Learning statistical distributions for synthesis\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "\n", + "print(\"šŸš€ Starting SDV training process...\")\n", + "print(\"This will involve multiple phases - preprocessing, relationship learning, and table modeling\")\n", + "\n", + "start_time = time.time()\n", + "\n", + "# Initialize the HMASynthesizer with our configured metadata\n", + "print(\"šŸ”§ Initializing HMASynthesizer...\")\n", + "synthesizer = HMASynthesizer(metadata)\n", + "\n", + "# Fit the synthesizer on training data\n", + "# This process will:\n", + "# 1. Preprocess all tables (clean data, infer constraints)\n", + "# 2. Learn multi-table relationships\n", + "# 3. Model the statistical distributions of each table\n", + "print(\"šŸ“Š Training synthesizer on multi-table data...\")\n", + "synthesizer.fit({\"account\": accounts_train, \"transaction\": transactions_train})\n", + "\n", + "end_time = time.time()\n", + "elapsed_minutes = (end_time - start_time) / 60\n", + "\n", + "print(\"āœ… SDV training completed successfully!\")\n", + "print(f\"ā±ļø Total training time: {elapsed_minutes:.2f} minutes\")\n", + "\n", + "# Report table sizes for clarity\n", + "print(\"šŸ“ˆ Training data breakdown:\")\n", + "print(f\" - Accounts: {len(accounts_train):,}\")\n", + "print(f\" - Transactions: {len(transactions_train):,}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3.3 SDV Synthetic Data Generation\n", + "\n", + "**Generation Process:**\n", + "- **Scale Parameter**: Controls the number of synthetic records (1.25 = same size as training data)\n", + "- **Hierarchical Generation**: First generates parent records (accounts), then child records (transactions)\n", + "- **Relationship Preservation**: Ensures all synthetic transfers reference valid synthetic customers\n", + "- **Statistical Sampling**: Uses learned distributions to create realistic synthetic data\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"šŸŽ² Starting SDV synthetic data generation...\")\n", + "print(\"Generating synthetic data using learned statistical distributions...\")\n", + "\n", + "start_time = time.time()\n", + "\n", + "# Generate synthetic data with the same number of records as training data\n", + "print(\"āš™ļø Generating 1.25x the training data size...\")\n", + "sdv_synthetic_data = synthesizer.sample(scale=1.25)\n", + "\n", + "end_time = time.time()\n", + "elapsed_minutes = (end_time - start_time) / 60\n", + "\n", + "print(\"āœ… SDV generation completed successfully!\")\n", + "print(f\"ā±ļø Generation time: {elapsed_minutes:.2f} minutes\")\n", + "\n", + "# Calculate synthetic record counts\n", + "synthetic_account_count = len(sdv_synthetic_data[\"account\"])\n", + "synthetic_transaction_count = len(sdv_synthetic_data[\"transaction\"])\n", + "\n", + "total_synthetic_records = synthetic_account_count + synthetic_transaction_count\n", + "generation_rate = total_synthetic_records / (end_time - start_time)\n", + "\n", + "print(f\"šŸš€ Generation rate: {generation_rate:,.0f} records/second\")\n", + "print(\"šŸ“Š Synthetic data breakdown:\")\n", + "print(f\" - Accounts: {synthetic_account_count:,}\")\n", + "print(f\" - Transactions: {synthetic_transaction_count:,}\")\n", + "\n", + "# Preview of generated synthetic data\n", + "sdv_synthetic_data[\"account\"].head()\n", + "sdv_synthetic_data[\"transaction\"].head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Save SDV synthetic data for comparison\n", + "output_folder = \"./data/two-table/\"\n", + "\n", + "synthetic_files = {\n", + " \"account\": f\"{output_folder}sdv_account.parquet\",\n", + " \"transaction\": f\"{output_folder}sdv_transaction.parquet\",\n", + "}\n", + "\n", + "for table_name, file_path in synthetic_files.items():\n", + " sdv_synthetic_data[table_name].to_parquet(file_path, index=False)\n", + " print(f\"šŸ’¾ Saved {table_name} synthetic data to: {file_path}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. MOSTLY AI Implementation\n", + "\n", + "**About MOSTLY AI Synthetic Data SDK:**\n", + "- Open-source (Apache 2) synthetic data SDK with advanced AI capabilities\n", + "- Also cloud-based service with enterprise-grade security and compliance\n", + "- Supports complex multi-table scenarios with multiple foreign keys\n", + "- Uses deep learning and autoregressive-based models\n", + "\n", + "**Getting Started:**\n", + "- **API Access**: Requires valid API credentials for cloud platform access\n", + "- **API Key Generation**: Get your free API key at: https://app.mostly.ai/settings/api-keys\n", + "\n", + "**Key Advantages:**\n", + "- **Advanced AI Models**: Utilizes state-of-the-art generative AI including language models\n", + "- **Mixed Data Types**: Excels at both tabular and text data synthesis\n", + "- **Enterprise Features**: Privacy guarantees, compliance reporting, and scalability\n", + "\n", + "**Architecture:**\n", + "- **Tabular Models**: For structured data (demographics, financials)\n", + "- **Language Models**: For text fields (names, addresses, emails) using LLMs like Llama-3.2\n", + "- **Sequential Models**: For time-series and ordered data patterns" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from mostlyai.sdk import MostlyAI\n", + "\n", + "print(\"šŸ”§ Initializing MOSTLY AI Synthetic Data SDK...\")\n", + "\n", + "# Initialize MOSTLY AI Synthetic Data SDK\n", + "mostly = MostlyAI(local=True)\n", + "\n", + "\n", + "print(\"āœ… MOSTLY AI Synthetic Data SDK initialized successfully\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4.1 MOSTLY AI Configuration Summary\n", + "\n", + "**Berka Two-Table Setup Highlights:**\n", + "\n", + "- **Accounts Table**\n", + " - Primary Key: `account_id`\n", + " - Referenced by transactions table as foreign key\n", + "\n", + "- **Transactions Table**\n", + " - Foreign Key: `account_id` (context)\n", + " - Context-aware modeling for financial records\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"āš™ļø Configuring streamlined MOSTLY AI generator...\")\n", + "print(\"Setting up minimal two-table configuration for account and transaction data...\")\n", + "\n", + "# Configure the generator for the reduced two-table setup\n", + "config = {\n", + " \"name\": \"Berka Accounts & Transactions Generator\",\n", + " \"tables\": [\n", + " {\n", + " \"name\": \"account\",\n", + " \"data\": accounts_train,\n", + " \"primary_key\": \"account_id\",\n", + " \"tabular_model_configuration\": {\"enable_model_report\": False},\n", + " },\n", + " {\n", + " \"name\": \"transaction\",\n", + " \"data\": transactions_train,\n", + " \"primary_key\": \"trans_id\",\n", + " \"foreign_keys\": [{\"column\": \"account_id\", \"referenced_table\": \"account\", \"is_context\": True}],\n", + " \"tabular_model_configuration\": {\"enable_model_report\": False},\n", + " },\n", + " ],\n", + "}\n", + "\n", + "print(\"āœ… MOSTLY AI generator configuration ready.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4.2 MOSTLY AI Training Process\n", + "\n", + "**Training Process:**\n", + "1. **Upload Data**: Send training data securely to MOSTLY AI cloud\n", + "2. **Model Configuration**: Apply the complex multi-table configuration\n", + "3. **AI Training**: Use advanced generative models including LLMs\n", + "4. **Quality Validation**: Automatic quality checks during training\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"šŸš€ Starting MOSTLY AI training...\")\n", + "print(\"šŸ“¤ Uploading training data to secure MOSTLY AI cloud platform...\")\n", + "\n", + "start_time = time.time()\n", + "\n", + "# Train the MOSTLY AI generator with our advanced configuration\n", + "# This will:\n", + "# 1. Upload training data securely to the cloud\n", + "# 2. Configure both tabular and language models\n", + "# 3. Train AI models for each table and their relationships\n", + "# 4. Wait for training completion with progress monitoring\n", + "g = mostly.train(config=config, start=True, wait=True)\n", + "\n", + "end_time = time.time()\n", + "elapsed_minutes = (end_time - start_time) / 60\n", + "\n", + "print(\"āœ… MOSTLY AI training completed successfully!\")\n", + "print(f\"ā±ļø Total training time: {elapsed_minutes:.2f} minutes\")\n", + "print(\"🧠 Advanced AI models trained for multi-table synthesis\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"šŸŽ² Starting MOSTLY AI synthetic data generation...\")\n", + "print(\"šŸŒ©ļø Using cloud-based AI models for high-quality multi-table synthesis...\")\n", + "\n", + "start_time = time.time()\n", + "\n", + "# Generate synthetic data using the trained MOSTLY AI generator\n", + "# Key advantages over SDV:\n", + "# - Handles foreign keys properly\n", + "# - Maintains statistical relationships across tables\n", + "\n", + "print(f\"šŸ“Š Generating {len(accounts_train):,} synthetic account records...\")\n", + "\n", + "sd = mostly.generate(g, size=len(accounts_train))\n", + "mostlyai_synthetic_data = sd.data()\n", + "\n", + "end_time = time.time()\n", + "elapsed_minutes = (end_time - start_time) / 60\n", + "\n", + "# Calculate generation statistics\n", + "total_records = sum(len(mostlyai_synthetic_data[table]) for table in mostlyai_synthetic_data.keys())\n", + "generation_rate = total_records / (end_time - start_time)\n", + "\n", + "print(\"āœ… MOSTLY AI generation completed successfully!\")\n", + "print(f\"ā±ļø Generation time: {elapsed_minutes:.2f} minutes\")\n", + "print(f\"šŸš€ Generation rate: {generation_rate:,.0f} records/second\")\n", + "\n", + "print(\"šŸ“Š Synthetic data breakdown:\")\n", + "for table_name in mostlyai_synthetic_data:\n", + " print(f\" - {table_name.capitalize()}: {len(mostlyai_synthetic_data[table_name]):,} rows\")\n", + "\n", + "# Preview\n", + "mostlyai_synthetic_data[\"account\"].head()\n", + "mostlyai_synthetic_data[\"transaction\"].head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Save MOSTLY AI synthetic data for comparison\n", + "output_folder = \"./data/two-table/\"\n", + "\n", + "mostlyai_files = {\n", + " \"account\": f\"{output_folder}mostlyai_account.parquet\",\n", + " \"transaction\": f\"{output_folder}mostlyai_transaction.parquet\",\n", + "}\n", + "\n", + "for table_name, file_path in mostlyai_files.items():\n", + " mostlyai_synthetic_data[table_name].to_parquet(file_path, index=False)\n", + " print(f\"šŸ’¾ Saved {table_name} synthetic data to: {file_path}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Synthetic Data Quality Assessment\n", + "\n", + "After generating synthetic data using both SDV and MOSTLY AI, it's crucial to comprehensively evaluate the quality, privacy, and integrity of the generated datasets. This section provides a multi-faceted quality assessment framework that ensures our synthetic data meets production standards.\n", + "\n", + "## 5.1 Statistical Quality Assessment with MOSTLY AI QA Library\n", + "\n", + "The MOSTLY AI QA library provides enterprise-grade quality assessment capabilities that evaluate synthetic data across multiple dimensions. This assessment generates comprehensive HTML reports and quantitative metrics that help understand:\n", + "\n", + "- **Accuracy Scores**: Overall statistical fidelity of synthetic data\n", + "- **Distance to Closest Record (DCR)**: Privacy risk measurement \n", + "- **Univariate & Bivariate Distributions**: Preservation of individual column and column-pair statistics\n", + "- **Correlation Analysis**: Maintenance of relationships between variables\n", + "- **Similarity Metrics**: Overall resemblance to training data while avoiding overfitting" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Import and initialize the quality assessment framework\n", + "from mostlyai import qa\n", + "\n", + "# Initialize logging to see detailed evaluation progress\n", + "qa.init_logging()\n", + "print(\"šŸ” Quality assessment framework initialized\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Load the split files from the disk\n", + "transactions_train = pd.read_parquet(\"./data/two-table/transactions_train.parquet\")\n", + "transactions_test = pd.read_parquet(\"./data/two-table/transactions_test.parquet\")\n", + "accounts_train = pd.read_parquet(\"./data/two-table/accounts_train.parquet\")\n", + "accounts_test = pd.read_parquet(\"./data/two-table/accounts_test.parquet\")\n", + "\n", + "print(\"šŸ“‚ Training and test datasets loaded successfully\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"šŸ“Š Evaluating SDV Transaction synthetic data quality...\")\n", + "\n", + "# Load the SDV synthetic dataset\n", + "sdv_transaction = pd.read_parquet(\"./data/two-table/sdv_transaction.parquet\")\n", + "\n", + "# Define ID columns to exclude from QA analysis (but keep account_id for context linkage)\n", + "id_columns_to_exclude = [\"trans_id\"]\n", + "\n", + "\n", + "def remove_id_columns(df, columns_to_remove):\n", + " return df.drop(columns=[col for col in columns_to_remove if col in df.columns])\n", + "\n", + "\n", + "# Prepare data for QA\n", + "sdv_transaction_qa = remove_id_columns(sdv_transaction, id_columns_to_exclude)\n", + "transactions_train_qa = remove_id_columns(transactions_train, id_columns_to_exclude)\n", + "transactions_test_qa = remove_id_columns(transactions_test, id_columns_to_exclude)\n", + "\n", + "report_path, metrics = qa.report(\n", + " syn_tgt_data=sdv_transaction_qa,\n", + " trn_tgt_data=transactions_train_qa,\n", + " hol_tgt_data=transactions_test_qa,\n", + " syn_ctx_data=pd.read_parquet(\"./data/two-table/sdv_account.parquet\"),\n", + " trn_ctx_data=accounts_train,\n", + " hol_ctx_data=accounts_test,\n", + " ctx_primary_key=\"account_id\",\n", + " tgt_context_key=\"account_id\",\n", + " max_sample_size_embeddings=10_000,\n", + " report_path=\"sdv_transaction_qa_report.html\",\n", + ")\n", + "\n", + "print(f\"šŸ“‹ SDV Transaction Quality Report saved to: {report_path}\")\n", + "print(\"\\nšŸ“ˆ SDV Transaction Quality Metrics:\")\n", + "print(metrics.model_dump_json(indent=4))\n", + "\n", + "# Print summary scores\n", + "sdv_transaction_accuracy = metrics.accuracy.overall\n", + "sdv_transaction_dcr_share = metrics.distances.dcr_share\n", + "print(\"\\nšŸŽÆ SDV Transaction Summary:\")\n", + "print(f\" Overall Accuracy: {sdv_transaction_accuracy:.3f}\")\n", + "print(f\" DCR Share: {sdv_transaction_dcr_share:.3f}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"šŸ“Š Evaluating MOSTLY AI Transactions synthetic data quality...\")\n", + "\n", + "# Load the MOSTLY AI synthetic dataset\n", + "mostlyai_transaction = pd.read_parquet(\"./data/two-table/mostlyai_transaction.parquet\")\n", + "\n", + "# Define ID columns to exclude from QA analysis (keep account_id)\n", + "id_columns_to_exclude = [\"trans_id\"]\n", + "\n", + "\n", + "def remove_id_columns(df, columns_to_remove):\n", + " return df.drop(columns=[col for col in columns_to_remove if col in df.columns])\n", + "\n", + "\n", + "# Prepare transaction data\n", + "mostlyai_transaction_qa = remove_id_columns(mostlyai_transaction, id_columns_to_exclude)\n", + "transactions_train_qa = remove_id_columns(transactions_train, id_columns_to_exclude)\n", + "transactions_test_qa = remove_id_columns(transactions_test, id_columns_to_exclude)\n", + "\n", + "report_path, metrics = qa.report(\n", + " syn_tgt_data=mostlyai_transaction_qa,\n", + " trn_tgt_data=transactions_train_qa,\n", + " hol_tgt_data=transactions_test_qa,\n", + " syn_ctx_data=pd.read_parquet(\"./data/two-table/mostlyai_account.parquet\"),\n", + " trn_ctx_data=accounts_train,\n", + " hol_ctx_data=accounts_test,\n", + " ctx_primary_key=\"account_id\",\n", + " tgt_context_key=\"account_id\",\n", + " max_sample_size_embeddings=10_000,\n", + " report_path=\"mostlyai_transaction_qa_report.html\",\n", + ")\n", + "\n", + "print(f\"šŸ“‹ MOSTLY AI Transaction Quality Report saved to: {report_path}\")\n", + "print(\"\\nšŸ“ˆ MOSTLY AI Transaction Quality Metrics:\")\n", + "print(metrics.model_dump_json(indent=4))\n", + "\n", + "# Print summary scores\n", + "mostlyai_transaction_accuracy = metrics.accuracy.overall\n", + "mostlyai_transaction_dcr_share = metrics.distances.dcr_share\n", + "print(\"\\nšŸŽÆ MOSTLY AI Transaction Summary:\")\n", + "print(f\" Overall Accuracy: {mostlyai_transaction_accuracy:.3f}\")\n", + "print(f\" DCR Share: {mostlyai_transaction_dcr_share:.3f}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Add a final comparison section\n", + "print(\"\\n\" + \"=\" * 60)\n", + "print(\"šŸ† FINAL COMPARISON\")\n", + "print(\"=\" * 60)\n", + "print(f\"SDV Transaction - Accuracy: {sdv_transaction_accuracy:.3f}, DCR Share: {sdv_transaction_dcr_share:.3f}\")\n", + "print(\n", + " f\"MOSTLY AI Transaction- Accuracy: {mostlyai_transaction_accuracy:.3f}, DCR Share: {mostlyai_transaction_dcr_share:.3f}\"\n", + ")\n", + "\n", + "print(\"\\nšŸ” METRIC INTERPRETATION:\")\n", + "print(\"• Higher accuracy = better statistical fidelity\")\n", + "print(\"• DCR Share ~0.5 = optimal privacy-utility balance\")\n", + "\n", + "print(\"\\nšŸ“Š ANALYSIS:\")\n", + "print(\"• MOSTLY AI consistently shows higher accuracy than SDV\")\n", + "print(\"• Both frameworks maintain reasonable DCR Share values around 0.5\")\n", + "print(\"• MOSTLY AI handles multi-table relationships and foreign keys with greater precision\")\n", + "\n", + "print(\"\\nāš ļø RECOMMENDATION:\")\n", + "print(\"• Review detailed HTML reports for nuanced privacy insights\")\n", + "print(\"• Pay attention to discriminator AUC and feature-wise similarity scores\")\n", + "print(\"• Align final choice with your privacy-utility balance requirements\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.18" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/tutorials/sdv-comparison/single-table-scenario/single-table-scenario.ipynb b/docs/tutorials/sdv-comparison/single-table-scenario/single-table-scenario.ipynb index 21fb8a0d..732ab16e 100644 --- a/docs/tutorials/sdv-comparison/single-table-scenario/single-table-scenario.ipynb +++ b/docs/tutorials/sdv-comparison/single-table-scenario/single-table-scenario.ipynb @@ -14,7 +14,7 @@ "id": "WJZteD10A1eR" }, "source": [ - "# MOSTLY AI vs. SDV Comparison - Single Table Scenario\n", + "# MOSTLY AI vs. SDV Comparison - Single Table Scenario \"Run\n", "\n", "## Framework Comparison\n", "This notebook compares two synthetic data generation libraries on a large-scale dataset:\n",