Thomas Haley
ConchaML
Published in
5 min readJul 27, 2020

--

I love to work in coffee shops. I love the coffee, the noise, the music…being together, yet alone. My favorite is La Monarca in South Pasadena.

Concha and Latte Hearts

Over the years, as I’ve eaten my concha, I’ve wondered, “How do they decide how many to make?” Lattes are easy, cafes just make those to order, but baked goods need to be made ahead of time, so someone has to estimate how much to make based on past demand. Saturdays are busier than Mondays, and cool, misty days seem busier than hot ones — but how much busier, exactly? I started to see the question everywhere:

How does Von’s know how many chickens to roast?

How does Top Pot Doughnuts know how many apple fritters to make?

How does Starbucks know how many chipotle chicken wraps to prepare?

Make too many and you lose money on wasted products, make too little and you miss out on sales. Demand is complex — the conditional probability density function isn’t necessarily normal, and the optimal production amount isn’t necessarily centered on the mean, it depends on the gross margin of the product. It’s a fascinating problem.

I built Concha to estimate optimal production. Concha is free and open source, and the code can be run on any computer (Windows, Mac, or Linux). This is the link to the Concha code on Github, along with installation instructions. I hope cafes, restaurants, and grocery can use it to increase profits.

How Concha Works

Almost every cafe, panaderia, restaurant has a “point of sale” (POS), one of those tablets with a credit card reader that asks if you want an email with your receipt. These keep track of every sale. Concha takes these transaction records as inputs to train a machine learning model for each product based on the day of the week and the weather. (The POS doesn’t record the weather, but Concha will ping the NOAA API and add it to the sales history.) Then Concha predicts optimal production amounts for the next week using models built using Google’s TensorFlow/Keras code libraries.

Simulation: Fancy Cupcake Shop

Let’s simulate six months of sales transactions, then look at the impact of using Concha’s model trained to maximize profits.

# Set up a planner with simulated products.
cupcake = Planner(
planner_name="fancy_cupcake_1",
batch_size=1,
batch_cost=3.0, # Each cupcake costs $3 to produce
unit_sale_price=4.75, #...and sells for $4.75
demand_estimation_quantiles=24
)
cupcake.simulate_history(
num_days=180,
stockout_prob=0.5,
demand_mean=20,
demand_std=2,
num_products=10
)

In this simulation, cupcakes cost $3 to make and sell for $4.75. We create 180 days of history, and assume that the supply ran out on about half the days (stockout_prob = 0.5). We assume there are 10 kinds of cupcakes and demand is nominally 20 per day per product. Demand is randomly drawn from a skew normal distribution that depends on the day of the week and the weather. To make it interesting, each product has a “type” chosen randomly, One type has demand increase non-linearly with temperature, for another it decreases, and for the last it peaks at 70 and decreases on either end.

Let’s compare two approaches to estimating production based on past sales: Maximizing for profit (“ProfitMaximizer” model), and using a weekday and weekend average for future weekends and weekdays. (“MeanWeekPart” model).

cupcake.grid_search(param_grid={"model": ["MeanWeekPart", "ProfitMaximizer"]})
Grid Search Comparing Models Results

Concha analyzes performance of different prediction models by splitting up the sales history into chunks, using 4/5 of the chunks to train the prediction model, and then evaluating the efficacy of the predictions on the last chunk (5-fold cross-validation). We see the profit maximizing machine learning model increases profits by ~ 9%. And increases the waste by ~1.5 %. That seems counterintuitive, but the ProfitMaximizer model is trying to optimally capture potential sales, weighed against potential waste, and sometimes it’s worth it to risk making too much. Let’s take a closer look at the average daily profits from each cross-validation fold:

cupcake.plot_profits()
Avg Daily Profits per CV Fold

Here’s the average wastes histogram:

cupcake.plot_wastes()
Avg Daily Waste per CV Fold

Let’s do a paired t-test to see if the difference in profits and wastes is significant.

cupcake.compare_grid_results()
Paired t-test of CV Folds

The difference in average profit, and the difference in average waste are significant. The _bounds fields show the 95% confidence bounds for the mean of the difference between the two populations.

Simulation: Panaderia

panaderia = Planner(
planner_name="panaderia_1",
batch_size=10, # Items are always made in trays of 10
batch_cost=3.0,
unit_sale_price=1.0
)
panaderia.simulate_history(
num_days=180,
stockout_prob=0.5,
demand_mean=150,
demand_std=15,
num_products=10
)

In this simulation, we have conchas that sell for $1, made in batches of 10, and each batch costs $3 to produce. The profit per unit is lower, but sales volumes are higher. Let’s compare models again:

panaderia.grid_search(param_grid={"model": ["MeanWeekPart", "ProfitMaximizer"]})
Panaderia Grid Search Results

Here are the profit histograms:

Panaderia Avg Daily Profits per CV Fold

Impact

This data is simulated, the actual impact of using Concha vs. using historical averages on profits is impossible to predict (but it is possible to measure.) If actual impact was half what we saw in these simulations, it would mean additional hundreds of dollars per month for a cafe/panaderia/grocery.

If you are trying out Concha, I’d love to hear about your experience!

--

--

Thomas Haley
ConchaML
Editor for

I’m always looking for useful insights from data. Right now, that means predicting optimal concha/bagel/salad production.