Where we start
Elasticity is the percentage change in units for a one percent change in price. On a log-log plot it is the slope of a straight line, which is why the whole of this track fits lines through logs. The trouble is never the fitting. It is what you fit on: an order, an item, a product, a month, a product-month, all products at once. Each choice gives a different slope from the same rows, and deep-dive session 2 shows the differences are not small: the same rows give -0.1 one way and -1.8 another. Tonight builds the rows properly so that argument can be had on solid ground.
★ What you walk out with tonight. A product-month panel built from raw order items with every decision written as a comment, the eligibility rule that separates a product you can read from one you cannot, a log-log fit you can explain in one sentence, and the reason you will never again quote one product's slope as its elasticity.
One row is one unit at one price
5 min liveOlist ships three tables that matter tonight: order items (112,650 rows, one per unit sold, with the price the seller listed and the freight the buyer paid), orders (99,441, with a status and a purchase timestamp), and products (32,951, with a category). Before any of it becomes a panel, three decisions have to be made and written down, and each one changes which rows survive.
LiveWhich rows count, and what "price" is3 min▶
Which rows. Delivered orders only, purchased before 1 September 2018. The second half of that rule comes from the marketplace itself: the export's last timestamp is 17 October 2018 but only 20 orders are dated September or October and none was delivered, so the file effectively stops at the end of August. The retention and RFM courses hit the same ragged edge and chose the same date; reusing it means the customer table there and the panel here describe the same months.
What price. An Olist item row carries two money columns: price, which the seller listed, and freight_value, which depends on how far the buyer lives. The seller's decision is the first one. The buyer's cost is the sum. For an elasticity of the seller's price, use price; the freight-inclusive version is run as a check in session 2 and moves the answer by about 0.1, which is inside the range the honest sentence already carries.
What grain. One row per product per calendar month: units sold, and the mean item price that month. Monthly is the finest grain at which most of the 203 products have more than one sale in a row, and it is the grain at which a seller actually changes a price. Weekly would give more rows and more zeros; quarterly would hide most of the price moves.
Self-studyWhy the row is an item and not an order, and where the 2,453 went2 min▶
An order can hold several items, each with its own product and price, so "units of product X" is a count of item rows, not order rows. Grouping by order would count a basket with three of the same product as one unit and merge two different products into one price. The item table is the one where a unit and a price sit on the same row, which is the only shape a demand curve can be read from.
The 2,453 items dropped by decision 1 are undelivered, cancelled or unavailable orders, plus the twenty stragglers after the snapshot. They are not errors; they are sales that did not complete, and a demand curve is about sales that did. Keep the count in a comment. If it ever changes on a re-run, the export changed and every number downstream is due a re-check.
Two analysts, two elasticities, one shop. One uses the price the customer paid, freight included; the other uses the list price. On a marketplace where freight is 20 percent of a cheap item's cost and 3 percent of a dear one's, the first analyst's "price" moves whenever the buyer mix shifts toward distant cities, which has nothing to do with the seller. Both get a slope. Only one of them is measuring a decision the seller can make.
The panel, and who gets to be in it
5 min liveA product with one price has no elasticity to read; a product that sold six units has a price and not a response. So the panel carries a rule at the door: at least 30 delivered items, at least six months with a sale, at least three distinct prices. Of 32,216 products with a sale, 203 pass. They carry 14.9 percent of every item the marketplace sold.
LiveThe three sieves, and what each is for3 min▶
Thirty items is a data floor: below it a month with two units and a month with three units differ by 50 percent for no reason a price could explain. 376 products pass. Three distinct prices is an economics floor: a slope needs the price to have been in more than one place, and two prices give a line through two points that is fitted to nothing. 226 of the 376 pass. Six months with a sale is an identification floor: one price change in a two-month product cannot separate "the price did it" from "the month did it". 203 pass all three.
The thresholds are choices and the page says so. Lower them and more products enter with noisier rows; raise them and the panel shrinks toward the handful of bestsellers. The right move is to write the three numbers as constants at the top of the script and re-run the whole ladder under two other settings before quoting anything, which session 10's bench does with two of them as switches.
The 203 are not a random sample of the marketplace. They are the products that sold a lot and repriced, which is the population any pricing decision is about anyway; the honest sentence says "for the products that can be read", not "for the marketplace".
Self-studyMean price in a month, and why not the median or the mode2 min▶
A product's price can change mid-month, and the month's row then carries a mean of two prices weighted by how many units sold at each. That mean is the price the average unit that month was sold at, which is the quantity a revenue calculation needs. The mode would hide the change; the median would jump. In the headline product, January 2018's mean of 69.98 is 121 units, all but a few at 69.90 and a handful at 75 before the cut took effect. The rest of the year's rows are single prices.
For the same reason, "units" is a count of item rows and not of orders. A basket of three is three units at one price, and it belongs in the month's total three times.
A line through the logs, and the slope that is too good
5 min liveTake the log of units and the log of price and fit a straight line. The slope is the elasticity: a slope of -2 says a one percent price rise loses two percent of units. Do it for each of the 203 products on its own months and you get 203 slopes, and they are a lesson in why one product is the wrong unit: the median is -2.03, 70 percent are negative, and a third are past 5 in absolute value, which no demand curve for a bath towel or a phone case has ever produced.
LiveWhy -10.17 is not an elasticity, and what it is instead3 min▶
Read the thirteen rows again. Five months at R$ 75 selling 5 to 45. A cut to R$ 69.90 and five months selling 43 to 121. Then R$ 89.90 and R$ 103, selling 2, 2 and 3. A line through that has to pass near the bottom-right dots, and it comes out at -10, which would mean a 10 percent rise loses 62 percent of units. Nobody's bath mat behaves like that.
What the last three months look like is a product going out of stock or being delisted, with a price raised on the way out, or a seller clearing the last units at a higher price with no promotion behind it. In either case the units did not fall because the price rose; both moved because the product was ending. The rows cannot distinguish demand from supply here, and a slope fitted to them is a description of the product's life, not of its buyers.
This is the general lesson and it is why the track fits the panel and not the product: one product's thirteen months carry every accident of its life, and a slope has no way of knowing which dots are accidents. Two hundred products' months average the accidents out, and what is left is the part they share.
Self-studyLogs, and why the slope is a percentage change2 min▶
Elasticity is a ratio of percentage changes, and the derivative of log x is one over x, so a small change in log x is a percentage change in x. A straight line in logs, log units = a + b log price, therefore says: a one percent change in price goes with a b percent change in units, at every price. That is the constant-elasticity demand curve, and b is the elasticity.
Two consequences worth holding. First, the fit is only as good as the assumption that the elasticity is the same at R$ 70 and R$ 100, which the bench's session tests by fitting on subsets. Second, zeros cannot be logged: a month with no sales is not in the panel at all, which is one reason the eligibility rule asks for six months with a sale rather than six months.
Items to a fitted slope, on 110,197 real rows
★ 22 min · everyone buildsSeven steps in pandas and numpy on the public Olist CSVs. Every number printed below is what the code produces; if yours differs, the difference is one of the three decisions and you should be able to name which. Get the CSVs from Kaggle (a free account, or kagglehub.dataset_download("olistbr/brazilian-ecommerce") fetches them with no login).
Load three tables. Items carry the price, orders carry the status and the timestamp, products carry the category. The translation file turns Portuguese category names into English.
Decision 1: which rows. Delivered, purchased before the snapshot. The snapshot is a literal with its reason beside it, never a computed maximum.
Decision 2 and the joins. The price is the seller's price; freight stays in a column of its own for the session 2 check. The month comes from the purchase timestamp.
Decision 3: the grain. One row per product per month. Units is a count of item rows; price is the mean item price that month.
The three sieves. Written as constants so that changing one is an edit, not an archaeology. Print the count each sieve leaves; the three numbers are the first thing to say about the panel.
Fit one line per product. The slope of log units on log price is the elasticity. Skip a product whose price never varied within the panel (there are none among the 203, but the guard costs nothing).
Read the one that sold most. Thirteen rows, a cut, a rise, a collapse, and a slope of -10.17. Look at the rows before believing the slope; that is the whole habit.
Keep the three sieves as constants and the counts as comments. When a colleague gets 190 products instead of 203, the diff between your script and theirs is the answer, and it takes a minute. Without the constants and the comments it takes an afternoon and ends in an argument about whose panel is "right".
Before deep-dive session 2
30 min- Run the seven steps on Olist, or on your own item-level sales table. Write the three decisions as comments at the top before any code below them.
- Change one sieve (30 items to 20, or 6 months to 4) and re-run. Write down the new product count and the new median slope. That pair of numbers is the cost of the threshold.
- Find your own headline product, the one with the most rows, and read its rows before its slope. Write one sentence on whether its slope is about buyers or about its life.
- Bring the panel. Session 2 fits it five ways and the five answers span a factor of sixteen.
Three questions
Clear all three and deep-dive session 1 gets stamped in your passport.
1 · Why is the panel built on item rows with the seller's listed price, and not on the price the buyer paid including freight?
Freight stays in its own column, and the freight-inclusive fit is run as a check in session 2, where it moves the within-product answer by about 0.1. The decision is about what question is being asked, not about the size of the number.
2 · The eligibility rule leaves 203 of 32,216 products. What is each of the three sieves for?
The thresholds are choices, written as constants, and the honest sentence says "for the products that can be read", not "for the marketplace". The 203 carry 14.9 percent of all items sold.
3 · The best-selling eligible product's own slope is -10.17. What is the honest reading?
A third of the 203 per-product slopes are past 5 in absolute value, which no demand curve for these goods produces. The panel of 2,216 rows, fitted as one line with 203 intercepts, is the unit that averages the accidents out; that is session 2.
What this session teaches, and where it came from
Every fact on this page, and its verification tier, is recorded in the course's source map.
Deep-dive session 1 cheat sheet · pin this
You have 2,216 rows and a reason not to trust any one product's slope. Deep-dive session 2 fits those rows five ways: across products, where the slope is +0.008 and cheap products are simply not popular products; pooled, where it is -0.108; within product, where it is -1.788; with month effects, -1.854; and against a placebo where prices are shuffled inside each product and the slope falls to zero. Same rows, a factor of sixteen, and the whole difference is whether a product was compared with itself.