Case study 1 of 6
eBay iPhone price engine
What a used iPhone sells for, learned from 30,000+ real eBay sold prices.
- stack
- Python
- LightGBM
- ONNX
- FastAPI
- Go
- Docker
- Kubernetes
- AWS
C$61.61
test MAE (10-13% of median, per family)
per-family MAE C$23-114
0.94
R² over the whole price range; read MAE per family
worst family (Ridge) at 0.885
81.5%
80% band coverage, held out
bands from out-of-fold residuals
Price a phone with the exported model
The repo's exported LightGBM pipelines, run by ONNX Runtime in this browser; nothing leaves the page. Before the first prediction the widget replays 50 recorded parity vectors and stops if any output drifts more than 0.5% from the Python pipeline's.
Sold prices as labels, with an 80% band
Asking prices for used phones are unusable as labels: identical configs list anywhere from C$139 to C$1,420, and most listings never sell. Sold prices are market-clearing prices, so the scraper collects only completed sales from eBay.ca (31,875 raw listings, 26,027 after cleaning; every filter step logged as a funnel).
A point estimate alone overstates what any model knows about a marketplace. Each prediction carries an 80% band built from P10/P90 quantiles of out-of-fold residuals in log space, stored as two offsets in the model metadata; no second model. Held-out coverage lands at 81.5% against the 80% target.
Per family, MAE is 8 to 27% of the median, tightest where prices are highest. The X-generation families (median C$118-136, MAE C$21-32) are grouped in the repo's table and left off this chart.
The 56-fit sweep
Seven model families by four sampling strategies, per target, on one GPU. Pick a target and a cell; the winner is outlined. No sampling strategy beat unresampled training for price, and every tree ensemble beat the PyTorch MLP.
Serving: FastAPI and a Go port
Serving runs twice. A FastAPI service is the simple path; a 250-line Go microservice runs the same models through ONNX Runtime for small, fast-scaling pods on Kubernetes. The Go server rebuilds the sklearn feature vector from constants exported off the fitted pipelines, replays recorded parity vectors at startup, and exits if predictions drift more than 0.5% from the Python pipeline's recorded outputs.
The demo at the top of this page is a third consumer of the same exported contract, held to the same parity rule. The depreciation scope on the home page is a fourth; every point on it came out of this model.