Skip to content
HotelMind AI

ML

Synthetic Data

Training-data provenance per model.

Source: hotelmind-ml/docs/datasets/synthetic_data.md

Synthetic Data

Two of this project's five ML domains — Restaurant and Staffing — have no real underlying data anywhere in this repository or its inputs. This document explains why, and exactly how the synthetic substitute was built.

Why synthetic data was necessary

  • The canonical booking dataset (hotel_bookings.csv) contains only reservation-level fields — no F&B transactions, no staff attendance records.
  • The Phase 3 warehouse's fact_restaurant_sale and fact_staff_attendance tables were never populated — no source data exists to populate them from (see docs/datasets/warehouse.md).
  • The task required Restaurant and Staffing models to be actually trained, with real (non-placeholder) evaluation metrics — which is impossible without some training data. The alternative (leaving these two domains as untrained scaffolds) was explicitly rejected in favor of generating clearly-labeled synthetic data, following the same pattern as two pre-existing synthetic seeds in this project (room_type_dim.csv, events_holiday_calendar.csv).

Design principle: driven by real signal, not pure noise

Both generators (src/pipelines/synthetic_data.py) are seeded from the real, derived daily occupancy (occupied_rooms, itself computed from actual fact_booking check-in/check-out ranges — not synthetic). This means synthetic Restaurant/Staffing values still correlate sensibly with real booking activity (busier days → more meals served, more staff present), rather than being pure random numbers disconnected from any signal.

Synthetic restaurant data

data/raw/restaurant_daily_synthetic.csv, generated by generate_restaurant_daily():

revenue[meal] = base_rate[meal] * occupied_rooms * day_of_week_multiplier * (1 + noise)
items_sold = total_revenue / avg_item_value
  • base_rate: breakfast $8/room, lunch $6/room, dinner $12/room (fixed constants, not measured)
  • day_of_week_multiplier: 1.15× on weekends, 1.0× on weekdays
  • noise: N(0, 0.05) per meal per day, seeded (np.random.default_rng(42))
  • avg_item_value: fixed constant (mean of per-meal item values, $9.5/$14/$22)

Synthetic staffing data

data/raw/staffing_daily_synthetic.csv, generated by generate_staffing_daily():

present_employees[dept] ≈ ceil(ratio[dept] * occupied_rooms * day_of_week_multiplier) + noise
  • ratio: Reception 0.03, Kitchen 0.05, Housekeeping 0.08 (fixed constants, not derived from any real staffing policy)
  • noise: integer {-1, 0, +1}, seeded

Determinism

Both generators use np.random.default_rng(seed=42) — identical input (the derived daily occupancy DataFrame) always produces byte-identical synthetic output. Regenerating the seed files is a reproducible no-op, not a source of drift. Verified in tests/test_synthetic_data.py.

Known limitations

  • Every Restaurant/Staffing prediction is illustrative, not a real business forecast. Do not present these models' output to stakeholders as measuring real demand or real staffing needs.
  • Evaluation metrics for these two domains measure how well each model fits the synthetic generator's own signal-plus-noise, not real-world accuracy.
  • If real F&B or staff-attendance data ever becomes available, only load_data() in RestaurantPipeline/StaffingPipeline needs to change — the model classes, feature engineering, and API layer are data-source agnostic.

See reports/final_phase4/known_limitations.md (items 1, 9, 10) and reports/model_discovery/feature_quality.md §1 for further detail.