Skip to content

Faker Synthesizer from a YAML configuration

This section demonstrates driving the FakerSynthesizer from a single declarative YAML file carrying the columns, the structural scaffold, the numerical distributions and the conditional generation rules — with only the reference data and calculated features (Python callables) supplied in code.

Configuration file

# FakerSynthesizer configuration: columns + structure + statistical behavior in
# one declarative file. Loaded with `load_faker_config` (see
# faker_synthesizer_from_yaml.py). Reserved keys: scaffold, distributions,
# conditions — everything else under `columns` is the per-column metadata
# configuration. Calculated features are Python callables and are passed in code.

columns:
  quantity:
    datatype: numerical
    vartype: float
    min: 1.0
    max: 5000.0
  n_transactions:
    datatype: numerical
    vartype: int
    min: 1
    max: 500
  segment:
    datatype: categorical
    vartype: string
    categories:
      retail: 80
      fleet: 20
  payment_type:
    datatype: categorical
    vartype: string
    categories:
      card: 70
      cash: 25
      app: 5

# WHICH rows exist: one row per product per day of March 2026, with
# category-aware density — fuel books every day, shop items have quiet days.
# `products` is provided at fit() time through `reference_data`.
scaffold:
  dimensions:
    - column: product_id
      from_table: products
      from_column: product_id
    - column: booking_date
      date_range: {start: "2026-03-01", end: "2026-03-31", freq: D}
  density:
    by: {table: products, column: category}
    rates: {fuel: 1.0, beverages: 0.85, snacks: 0.7, car_wash: 0.5}
    multipliers:
      - {when: weekend, factor: 1.25, except: [fuel]}

# statistical shape of numerical columns (default would be uniform in domain)
distributions:
  n_transactions: {distribution: poisson, lam: 60}

# per-segment behavior: fleet customers buy in bulk and pay by card/app
conditions:
  - column: quantity
    rules:
      - when: {segment: fleet}
        distribution: {distribution: lognormal, mean: 7.2, sigma: 0.4}
    default:
      distribution: {distribution: lognormal, mean: 4.6, sigma: 0.6}
  - column: payment_type
    rules:
      - when: {segment: fleet}
        values: {card: 0.85, app: 0.15}
    # retail rows fall back to the column's declared category distribution

Example Code

"""
Example: FakerSynthesizer driven by a single YAML configuration file.

The YAML (faker_config.yaml) declares the columns, the structural scaffold
(product x day grid with category-aware density), the numerical distributions,
and the conditional generation rules. This script only supplies what cannot
live in YAML: the reference DataFrame backing the scaffold's `from_table`
dimension, and the calculated features (Python callables).

Generated table: daily fuel-station bookings for March 2026 —
  - every product x active-day combination exists exactly once (scaffold)
  - fleet bookings are bulk-sized and card/app-paid (conditions)
  - n_transactions follows a Poisson shape (distributions)
  - avg_ticket is computed exactly, never sampled (calculated features)
Fully deterministic under `random_state`; zero LLM calls.
"""
from pathlib import Path

import pandas as pd

from ydata.metadata import Metadata
from ydata.metadata.builder import MetadataConfigurationBuilder
from ydata.synthesizers import FakerSynthesizer
from ydata.synthesizers.faker.config import load_faker_config

# reference table backing the scaffold's `from_table` dimension (in practice:
# read from your product master)
products = pd.DataFrame(
    {
        "product_id": ["P-001", "P-002", "P-003", "P-004", "P-005"],
        "name": ["Diesel", "Unleaded 95", "Craft Beer 6-pack", "Trail Mix", "Deluxe Car Wash"],
        "category": ["fuel", "fuel", "beverages", "snacks", "car_wash"],
    }
)

# one file: columns + scaffold + distributions + conditions
config = load_faker_config(Path(__file__).parent / "faker_config.yaml")

metadata = Metadata(configuration_builder=MetadataConfigurationBuilder(config.columns))

synth = FakerSynthesizer(locale="en")
synth.fit(
    metadata,
    scaffold=config.scaffold,
    reference_data={"products": products},
    distributions=config.distributions,
    conditions=config.conditions,
    calculated_features=[
        {
            "calculated_features": "avg_ticket",
            "function": lambda quantity, n_transactions: (quantity / n_transactions).round(2),
            "calculated_from": ["quantity", "n_transactions"],
        },
    ],
)

# the scaffold defines the row count; random_state makes the run reproducible
data = synth.sample(random_state=42)

df = data.to_pandas()
print(df.head(10))
print(f"\n{len(df)} bookings | {df['product_id'].nunique()} products | "
      f"{df['booking_date'].nunique()} days")
print("\nMean quantity per segment (fleet buys in bulk):")
print(df.groupby('segment')['quantity'].mean().round(1))
print("\nPayment mix for fleet bookings (card/app only):")
print(df.loc[df['segment'] == 'fleet', 'payment_type'].value_counts(normalize=True).round(2))

# the calculated identity holds exactly on every row
assert (df["avg_ticket"] == (df["quantity"] / df["n_transactions"]).round(2)).all()