An XGBoost regressor that forecasts a Gojek/GOTO driver's daily earnings in IDR from their own
recent earnings history, calendar context, and a self-reported wellness score.
It is the earnings half of the Fairleap forecasting pair. Its output is also the first input feature
of fairleap-v1-laborsupply-xgboost-2k,
which forecasts hours worked.
📊 Model Details
Architecture
xgboost.sklearn.XGBRegressor, booster=gbtree
Objective
reg:squarederror
Boosting rounds
750
Max depth
3
Learning rate
0.3
Random state
42
Input features
20 (ordered — see below)
Output
1 continuous value: predicted daily earnings, IDR
Total tree nodes
10,598 (4,924 splits + 5,674 leaves) — the "11k" in the name
Mean nodes per tree
14.1 of a possible 15
Artifact
app/earnings_model.pkl, 840 KB, joblib
Version
v1
License
MIT
🎯 Intended Use
Giving an individual driver a short-horizon (roughly one to fourteen day) indication of expected
daily income, so that budgeting and savings advice downstream has a number to work from. The model
is trained per-driver-history: it reads only that driver's own past daily totals.
Out-of-Scope Use
Any real financial decision. The model is trained entirely on synthetic data (see below) and
its R² of 0.397 means it explains under 40% of the variance even on that synthetic test split.
Determining pay, eligibility, credit, or employment. Do not use these forecasts as an input to
anything that decides what a person receives or is entitled to.
Fleet-level or market-level forecasting. There is no cross-driver, geographic, or seasonal
signal in the feature set beyond day-of-week.
Horizons beyond ~14 days. Lag features degrade to constants past the supplied history window.
🔢 Feature Schema
Feature order is load-bearing. This is a plain XGBRegressor with no column-name validation at
predict time — passing the right columns in the wrong order produces plausible numbers, not an error.
#
Feature
Type
Description
0
day_of_week
int 0–6
Monday = 0
1
is_weekend
int 0/1
1 when day_of_week >= 5
2
wellness_score
int
Self-reported wellness, constant across the forecast window
3
rolling_mean_7
float
Mean of the last 7 historical daily earnings
4
rolling_std_7
float
Population std of the last 7 historical daily earnings
5
rolling_mean_14
float
Mean of the last 14 historical daily earnings
6–19
lag_1 … lag_14
float
Daily earnings 1–14 days before the target day
Rolling statistics are computed once from the tail of the supplied history and are therefore
constant across every day in a forecast window — they are not updated recursively as the forecast
walks forward. Lags fall back to NaN when they reach before the start of the supplied history;
XGBoost handles NaN natively via its default split direction.
🚀 How to Use
Directly
python
1import joblib
2import pandas as pd
34model = joblib.load("app/earnings_model.pkl")56FEATURES =["day_of_week","is_weekend","wellness_score",7"rolling_mean_7","rolling_std_7","rolling_mean_14"]+ \
8[f"lag_{i}"for i inrange(1,15)]910X = pd.DataFrame([{...}], columns=FEATURES)# order matters11earnings =abs(model.predict(X)[0])
As a service
sh
1pip install -r requirements.txt
2python wsgi.py # dev, port 5000
3gunicorn --bind 0.0.0.0:5000 wsgi:app # production
4docker compose up # container
GET / returns a healthcheck and the route table.
POST /predict/earnings — feature construction from raw daily logs is handled for you by
app/regressor_utils.py:
Fully synthetic ride-event records generated by data_gen.py, one row per completed ride:
Column
Description
driver_id
Synthetic driver identifier
timestamp
Ride timestamp, unique and strictly increasing per driver
day_of_week
0–6, Monday = 0
hour_of_day
0–23
location_cluster
Indonesian city label
hours_worked
Hours attributed to the ride
rides_completed
Rides in the record
earnings
Earnings in IDR — the target
wellness_score
Self-reported driver wellness
preferred_location
Driver's stated preferred city
avg_ride_duration_minutes
Mean ride duration
🔬 Training Procedure
Lags 1–14 and 7/14-day rolling statistics are derived from the earnings column, rows with
resulting NaNs are dropped, and the frame is split 80/20 with train_test_split.
Synthetic data only. No claim this model makes about driver income reflects real Gojek/GOTO
earnings. It was never validated against real driver data.
Weak absolute accuracy. R² = 0.397 on synthetic test data. A mean absolute error of ~52,900 IDR
is large relative to the daily earnings being predicted.
Train/serve skew. Lags and rolling windows are built at training time over per-ride event
rows — the dataset carries hour_of_day and multiple rows per driver per day. At serving time
regressor_utils.py builds one row per day with lags over daily totals. lag_1 means "the
previous ride" during training and "yesterday" during inference. This is a known defect, not a
design choice.
Static rolling features. Rolling statistics do not advance across the forecast window, so every
day in a multi-day forecast sees the same rolling_mean_7 / rolling_std_7 / rolling_mean_14.
wellness_score is self-reported and held constant across the window, so any bias in how
drivers rate themselves is carried straight into the forecast.
No geographic or seasonal signal.location_cluster and preferred_location are in the
dataset but not in the feature set. Holidays, weather, promotions and surge are absent entirely.
No uncertainty estimate. A single point prediction is returned with no interval, which
overstates confidence for a model at this accuracy.
🛠️ Tech Stacks
xgboost: An optimized gradient boosting library designed to be highly efficient, flexible, and portable for supervised learning problems.
scikit-learn: A robust machine learning library that provides simple and efficient tools for data mining and data analysis.
pandas: A powerful data manipulation and analysis library offering labeled data structures and operations for manipulating numerical tables and time series.
numpy: A foundational library for numerical computing in Python, supporting large, multi-dimensional arrays and matrices.
joblib: A library for lightweight pipelining and efficient serialization of Python objects, often used for persisting machine learning models.
flask: A lightweight and flexible WSGI web application framework designed to get applications up and running quickly.
gunicorn: A Python WSGI HTTP server for UNIX that's commonly used to serve Flask or Django web applications in production.
⚙️ Installation
sh
1git clone https://github.com/Fairleap-AI/fairleap-v1-earnings-xgboost-11k
2cd fairleap-v1-earnings-xgboost-11k
3docker compose up