Skip to content
HotelMind AI

ML

Staffing Model

Source: hotelmind-ml/docs/models/staffing.md

Model Card: Staff Optimization

Purpose

Predict the required number of present staff for a department/branch/date (Reception, Kitchen, Housekeeping), to support shift-planning decisions.

⚠️ Trained entirely on synthetic data — see Known Assumptions below before using this model's output for any real decision.

Input Features

FEATURE_COLS (src/pipelines/staffing_pipeline.py):

FeatureSource
month, quarter, day_of_week, is_weekend, is_holidaysrc/features/calendar_features.py
scheduled_employeesdirect input (planned headcount)
present_employees_lag_7, present_employees_rolling_mean_7src/features/time_series_features.py, grouped by department_id
department_nameordinal-encoded categorical

Target Variable

present_employees (int) — synthetic headcount, see below.

Algorithm

Single shared GradientBoostingRegressor (StaffingRegressionModel, n_estimators=250, max_depth=4, learning_rate=0.05, random_state=42) across all 3 departments, with department_name as an encoded feature — one model rather than three, since departments share the same schema/grain (unlike Restaurant's per-meal split).

OR-Tools shift scheduler (src/models/staffing/or_tools_scheduler.py) remains an intentional NotImplementedError scaffold — this model predicts a headcount, not a shift assignment; converting the two is explicitly out of scope.

Training Dataset

data/features/staff_features.parquet — 4,815 rows (1,605 dates × 3 departments), generated by src/pipelines/synthetic_data.py::generate_staffing_daily from data/raw/staffing_daily_synthetic.csv. Chronological 80/20 train/test split.

Evaluation Metrics

ModelMAERMSEMAPE
Regression0.730.866.5%

Source: reports/latest_staffing.json. The low MAPE reflects the synthetic generator's low intrinsic noise (headcounts are small integers with limited variance), not real-world predictive strength.

Strengths

  • Single shared model across departments is simpler to maintain than per-department models, and the encoded department_name feature lets it still differentiate department-specific patterns.
  • Fast to train and predict (small feature set, small target range).

Limitations

  • No real staff-attendance data exists anywhere in this project. Every value this model was trained on is fabricated.
  • required_staff is a single point estimate — no confidence interval is produced (unlike Occupancy's Prophet model).
  • department is not validated against the known department list at the API layer — an unrecognized name silently encodes as -1 via OrdinalEncoder(handle_unknown="use_encoded_value") rather than raising a clear error (see docs/api/staff.md).

Known Assumptions

  • Synthetic generation formula: present_employees ≈ ratio[department] * occupied_rooms * day_of_week_multiplier + small integer noise, deterministic via np.random.default_rng(seed=42) (see reports/final_phase4/known_limitations.md items 1 and 10).
  • Department staffing ratios (DEPARTMENT_STAFF_RATIO in synthetic_data.py) are fixed constants, not derived from any real staffing policy.

Future Improvements

  • Replace the synthetic seed with real staff-attendance data if a workforce management data source is ever integrated.
  • Implement the OR-Tools scaffold to convert required_staff counts into actual shift assignments.
  • Add department-name validation at the API layer.