Developing an AI-based demand forecasting system for restaurants
Restaurant inventory and staff management directly depend on forecasting guest traffic and orders. Excess inventory → write-offs and losses. Staff shortages → long waits → negative reviews. The ML system predicts cover count and order composition with 85-90% accuracy on most days.
Forecasting tasks
Cover count forecast: How many guests will visit the restaurant in each time slot (breakfast/lunch/dinner, or every 30 minutes).
Revenue per cover: The average bill depends on: day of the week, season, special menus, and audience composition.
Dish demand forecast: What dishes and in what quantities will be ordered? The basis for mise en place is the preparation of ingredients.
Staffing requirement: Cover count → the number of waiters, cooks, and hostesses per slot.
Factors Determining Demand
| Factor | Influence | How to take into account |
|---|---|---|
| Day of the week | Fri-Sat 2-3× higher than Wed | Dummy variables |
| Holidays | +30-80% on non-working days | Holiday calendar |
| Weather | Rain: -15-25% for veranda | NWP API |
| Special Menus | Fish Friday +20% | Promo Flags |
| Events | Concert Nearby +40% | Event API |
| Season | Summer: veranda +50%, winter -20% | Month/season |
| Reviews | Viral TikTok → abnormal peak | NLP monitoring |
Forecasting model
features = {
# Лаги
'covers_lag_7d_same_slot': covers_7d_ago_same_time,
'covers_lag_14d_same_slot': covers_14d_ago_same_time,
# Время
'day_of_week': dow,
'time_slot': slot_30min,
'month': month,
'is_holiday': holiday_flag,
'days_since_holiday': days_to_nearest_holiday,
# Резервации (forward-looking)
'reservations_for_slot': reservations_made_for_this_slot,
'reservations_trend': reservations_vs_7d_ago,
'walk_in_forecast': estimated_walk_in, # covers - reservations
# Внешние
'temperature': temperature,
'rain_probability': precipitation_probability,
'nearby_events_score': event_impact_score,
# Меню
'special_menu_flag': has_special_menu,
'promotional_campaign': active_promo
}
model = lgb.LGBMRegressor(n_estimators=300, learning_rate=0.05)
Dish Forecast
Hierarchy: Cover Forecast → Category Mix → Dish Demand
Category Mix:
# Исторически: в обед заказывают 60% основных блюд, 20% закусок, 20% десертов
# В ужин: 50%/25%/25%
# В праздник: +10% к десертам, +5% к алкогольным напиткам
def dish_category_mix(meal_type, day_type):
base_mix = historical_category_mix[(meal_type, day_type)]
return apply_seasonal_adjustment(base_mix, current_season)
Top-N dishes forecast: For each popular dish (top 40, >80% of revenue):
- Share in its category: XGBoost
- Features: day of the week, season, menu item, price
Long-tail dishes: we do not forecast individually - group forecast by category.
Waste Reduction
Excess supplies → food waste. The ML system minimizes:
Safe Order Quantity:
SOQ = quantile(forecast_distribution, p=90) # не медиана, а 90-й процентиль
# Лучше слегка переготовить (можно использовать завтра)
# чем 86'd dish (завершилось блюдо в меню)
Shelf life management:
- Ingredients with a short shelf life → in daily specials, promotions
- Pre-emptive 86: with a low forecast and small quantity → remove from the menu in advance
Food waste tracker: IoT scales for garbage → feedback: if we constantly throw away a specific ingredient → reduce the order.
Staffing Optimization
def staff_needed(covers_forecast, slot_minutes=30):
"""
Covers → официанты через labor productivity norm
"""
tables_needed = covers_forecast / avg_covers_per_table
servers_needed = ceil(tables_needed / covers_per_server)
# Кухня: covers × avg_dish_per_cover / production_capacity_per_cook
kitchen_needed = ceil(covers_forecast * avg_dishes / cook_hourly_capacity)
return {
'servers': servers_needed,
'kitchen': kitchen_needed,
'host': 1 if covers_forecast > 20 else 0
}
Integration with the scheduling system: R&D Rotamaster, BambooHR, or Jowi — APIs for creating shifts based on the staffing forecast.
POS integration
- iiko, r_keeper, Tillypad: Russian POS — API or SQL for historical data and requests
- Square, Toast, Lightspeed: Western POS — REST API
- Reservation systems: Restaurant capabilities of Yandex/2gis, OpenTable, Resy — API for reservations
Pipeline:
- Daily 07:00: Import yesterday's data from POS
- Recalculation of the forecast for 14 days ahead
- Chef's notice: mise en place plan for tomorrow
- Manager's notice: 3-day staffing plan
Metrics:
- Cover count MAPE: < 10% для следующего дня
- Dish demand MAPE: < 15% для топ-10 блюд
- Food waste reduction: 15-30%
- Labor cost savings: 5-10% through schedule optimization
Deadlines: Basic cover forecast + staffing – 4-5 weeks. A full-fledged system with dish-level forecasting, waste tracker, and POS integration – 3-4 months.







