dimhold.by
← Writing

Cheap food rose 33% in a year, until I read the same prices backwards

On Wednesday the UK statistics office published inflation for November. In its CPI tables food and non alcoholic drinks cost 16.4% more than a year ago. This year the argument about such numbers is mostly about cheap food. In January Jack Monroe wrote that a 500 g pack of the cheapest pasta went from 29p to 70p. Later that month the New Statesman took the raw prices that ONS publishes. It showed that the cheapest tenth of prices rose much faster than the median.

I knew the official number and never looked at how it is made. The idea was to build my own index from receipts. But one person’s receipts are 15 or 20 things from 1 or 2 shops. I did not know what an index from such a small basket can say at all. So first I wanted to see it on data where I can check the answer.

The receipts ONS publishes

Every month ONS puts online the prices its collectors write down in local shops. The dataset is called “item indices and price quotes”. One line is one price: the item, a shop code, a region, the price and a flag for a sale or a replacement product. For food and drinks it is about 42 thousand valid prices a month for about 175 items. An item is something like “large loaf white unsliced 800g” or “milk semi skimmed 2 pints”. The same dataset has the official index of every item and its weight in CPI for 2022.

This is the closest thing to receipts that is open. I took the files from November 2021 to November 2022, the last one came out together with the 16.4%. Then I wrote a short Python script with pandas.

Others have asked the same question. In October ONS itself published an experimental index of the cheapest product in each of 30 everyday items, scraped from supermarket websites. It got about 17% to September. I am not the first here. What I wanted to see is how much the answer depends on how you count.

First, can I get 16.4% back

I counted it 3 ways. The official item indices, combined with their CPI weights and chain linked through January the way ONS does it, give 16.0%. My own index from the raw prices gives 16.8%. There I compare one shelf a year apart, which means the same item in the same region and the same shop code. The naive version is what you do with a pile of receipts. Take the geometric mean of all prices of an item in November 2022 and divide it by the same for November 2021. No matching at all. It gives 16.6%.

The gap between 16.0% and 16.4% I could not close. One potato item worth 0.8 of 116 has no published index, but it can explain at most about 0.1 point. The rest sits inside the published subclass indices and I did not trace it.

The naive version came out closer than my matched one, which surprised me, but per item it is much worse than it looks. Of the 175 items, 170 have an official index in both years. For 90% of them the naive count misses the official item index somewhere between 6 points too low and 8 points too high. Over 170 items these errors mostly cancel, which I would not count on for a basket of 15.

0 0 10 10 20 20 30 30 40 40 50 50 official item index, % naive, all prices, % 15.5 16.0 16.5 17.0 naive 16.6% official items 16.0% published 16.4%
ONS price quotes and item indices, November 2021 and November 2022. Diagonal: naive equals official.

Cheap food

The New Statesman method on November prices is simple: take the 10th percentile and the median of each item in both years. The 10th percentile rose faster than the median in 98 of 170 items, slower in 68 and the same in 4. Weighted, cheap prices rose 20.4% against 16.3% for the median. The claim holds on these numbers too.

But the 10th percentile in 2021 and in 2022 are different shelves. I wanted the same shelf. I took the prices that were in the cheapest tenth of their item in November 2021 and looked at the same shelf a year later. By my first count they rose 32.9%. All the rest rose 13.6%. Cheap shelves rose faster in 125 of the 150 items that have enough matched shelves. I checked if it is sales, a cheap price that is just a promotion and comes back. It is not. 6.2% of these shelves were on sale against 5.5% of the others.

At this point I had the title of this post. Then I counted it the other way. Take the shelves that are cheapest in November 2022 and look how much they rose from a year before. If cheap shelves really climb faster, these should rise at least as much as everybody else. They rose 3.8%, against 16.3% for the rest.

The pairs mirror each other. That is what regression to the mean looks like. Suppose part of the price difference between shelves is noise. Then shelves picked as cheapest at the start seem to climb out later while the ones picked at the end look like they barely moved.

The noise was in the files, I just did not look at the flags. In a month about 1 in 10 food prices carries a mark that the product was replaced or its size changed. A shelf can also disappear for some months and come back. The same item and shop code a year apart is often not the same product. My first guess was the yearly sample change in February. It was wrong, because 99.9% of shelves carry their January price into February.

So I kept only unbroken shelves: a price in all 13 months and no mark of any kind except sales. That leaves 11,082 shelves in 142 items. The cheapest tenth of November 2021 rose 25.0%, the rest 15.7%. Backwards, the cheapest tenth of November 2022 rose 14.4%, the rest 16.6%. Most of the backwards gap is gone.

all matched shelves cheapest tenth picked in 32.9% cheapest 13.6% rest Nov 2021 3.8% cheapest 16.3% rest Nov 2022 unbroken shelves, no marks cheapest tenth picked in 25.0% cheapest 15.7% rest Nov 2021 14.4% cheapest 16.6% rest Nov 2022
Geometric mean of price change per shelf. A shelf is the same item, region and shop code. Right: 11,082 shelves in 142 items.

Some gap is still there. Forwards, the cheap tenth beat the rest by 9.4 points. Backwards it was 2.2 points behind. Real catch up makes cheap shelves gain in both directions, while noise helps them one way and hurts them the other. If the noise is the same both ways, (9.4 − 2.2) / 2 = 3.6 points is real catch up and (9.4 + 2.2) / 2 = 5.8 is noise. The same split on all matched shelves, with the 33%, gives 3.4 points of catch up and 15.9 of noise. Cheap shelves did rise faster, by about 3 or 4 points a year. Most of the gap between 33% and the rest came from shelves broken during the year: replaced, resized or missing for some months.

A basket of 15

Now the question I started with. I made baskets of 15 random items on unbroken shelves, all with equal weight. Each item is bought on 1 random shelf, so the shops are random too. 90% of such baskets landed between 9.1% and 26.4%. The official number is 16.4%.

If instead of 1 shelf I take the average change of each item, the same baskets of 15 land between 11.8% and 20.6%. With 2 other random seeds these bounds move by 0.1 or 0.2 points. The list of items gives about 9 points of spread and the shelf doubles it to about 17.

item average 90%: 11.8 … 20.6 1 random shelf per item 90%: 9.1 … 26.4 published 16.4% 0 5 10 15 20 25 30 35 40 basket price change, Nov 2021 → Nov 2022, %
Equal weights, unbroken shelves from figure 2. Brackets show where 90% of baskets land. 5 of 20,000 wide baskets fall outside the axis.

If somebody’s receipts say 25%, it is no proof that the official number is wrong. A small basket on random shelves gives that by chance.

What I did not check

  • Quantities. Real receipts have 3 packs of milk and 1 jar of coffee, my baskets have equal weights.
  • Size changes. Items are defined by a size range, like 750 to 800 g. ONS adjusts for size changes. I only dropped flagged replacements, I did not look how often a pack shrank inside the range.
  • The split into catch up and noise assumes the noise is the same in both directions. It is an assumption, I did not measure it. Unbroken shelves may also be a different kind of shelf, not just a cleaner one.
  • The rest of the gap between 16.0% and 16.4%.
  • Online shopping and discounters beyond what collectors visit. This is the UK and only food and drinks.
  • The basket size of 15 is my choice.