Funny item co-occurrences in 3 million Instacart orders
The strangest things people buy at the grocery store
The other day I was idly wondering what are the strangest combinations of items people buy at grocery stores. The kind of shopping cart that makes the cashier snicker and later tell his friends, "Dude, can you believe this guy came in and only bought condoms and apples?"
So I fired up Claude and started looking for any receipt data I could find.
Grocery stores keep this kind of data very close to the chest. There are consumer apps that collect receipt data (like ReceiptHog and Fetch) but they presumably just sell it to hedge funds or something. Years ago, however, Instacart open-sourced data from 3 million orders as part of a machine learning competition to optimize their recommendation algorithm. The data is still available on Kaggle and it's very rich. What we want is the exact opposite of a recommendation algorithm but this data should work fine.

The Instacart data set includes the following:
- 3,214,874 orders
- ~10 products per order on average
- 49,688 unique products
- 134 unique "aisles" (product categories)
So all we have to do is look at every cart and see which combinations of items are least likely to appear, right? Let's try that. For the sake of testing a few groupings, I included pairs, triples, and quads.
Product co-occurrence count: pairs
| count | product 1 | product 2 |
|---|---|---|
| 1 | Banana | Extra Fancy Unsalted Mixed Nuts |
| 1 | Organic Hass Avocado | Baby Cucumbers |
| 1 | Organic Hass Avocado | Trail Mix |
| 1 | Bag of Organic Bananas | Bananas |
| 1 | Limes | Trail Mix |
| 1 | Organic Garnet Sweet Potato (Yam) | Clementines |
| 1 | Organic Avocado | Zero Calorie Cola |
| 1 | Organic Fuji Apple | Baby Cucumbers |
Note: maximum pair co-occurrence count is 62,341.
Product co-occurrence count: triples
| count | product 1 | product 2 | product 3 |
|---|---|---|---|
| 1 | Banana | Bag of Organic Bananas | Soda |
| 1 | Banana | Bag of Organic Bananas | Clementines |
| 1 | Banana | Bag of Organic Bananas | Sparkling Mineral Water |
| 1 | Banana | Bag of Organic Bananas | Flat Parsley, Bunch |
| 1 | Banana | Bag of Organic Bananas | Sparkling Water |
| 1 | Banana | Bag of Organic Bananas | Fresh CA Grown Eggs |
| 1 | Banana | Bag of Organic Bananas | Red Seedless Grapes |
Note: maximum triple co-occurrence count is 15,066.
Product co-occurrence count: quads
| count | product 1 | product 2 | product 3 | product 4 |
|---|---|---|---|---|
| 1 | Banana | Bag of Organic Bananas | Organic Baby Spinach | Half & Half |
| 1 | Banana | Bag of Organic Bananas | Organic Whole Milk | Organic Zucchini |
| 1 | Banana | Bag of Organic Bananas | Organic Avocado | Organic Half & Half |
| 1 | Banana | Bag of Organic Bananas | Strawberries | Organic Lemon |
| 1 | Banana | Bag of Organic Bananas | Organic Hass Avocado | Spring Water |
| 1 | Banana | Bag of Organic Bananas | Organic Yellow Onion | Organic Fuji Apple |
Note: maximum quad co-occurrence count is 3,828.
Hmm. These aren't very interesting. Maybe that's because there are a ton of combinations that only occur once, and we're only looking at the top 5-10, so we need a better way to sort them.
There are roughly 1.2 billion possible unique pairs of products (unordered pairs from a set of 50,000). About 97% of them never occur in our data, and of the ones that do, around 22 million pairs occur exactly once. When almost every pair is tied at zero or one, "least common" becomes meaningless.
So how should we sort? Claude had a good idea to rank each combination by "lift": how frequently it actually appears divided by how frequently we'd expect it to appear. If you have two very common items like apples and oranges, you'd expect them to co-occur a lot. If they don't, that's notable, and the pair should rank higher. Now let's try that.
Product co-occurrence by lift: pairs
| lift | product 1 | product 2 |
|---|---|---|
| 0.0007 | Banana | Extra Fancy Unsalted Mixed Nuts |
| 0.0010 | Organic Hass Avocado | Baby Cucumbers |
| 0.0012 | Organic Hass Avocado | Trail Mix |
| 0.0017 | Bag of Organic Bananas | Bananas |
| 0.0019 | Limes | Trail Mix |
| 0.0020 | Organic Garnet Sweet Potato (Yam) | Clementines |
| 0.0021 | Organic Avocado | Zero Calorie Cola |
| 0.0025 | Organic Fuji Apple | Baby Cucumbers |
Product co-occurrence by lift: triples
| lift | product 1 | product 2 | product 3 |
|---|---|---|---|
| 0.0016 | Banana | Bag of Organic Bananas | Soda |
| 0.0019 | Banana | Bag of Organic Bananas | Clementines |
| 0.0032 | Banana | Bag of Organic Bananas | Sparkling Mineral Water |
| 0.0043 | Banana | Bag of Organic Bananas | Flat Parsley, Bunch |
| 0.0047 | Banana | Bag of Organic Bananas | Sparkling Water |
| 0.0056 | Banana | Bag of Organic Bananas | Fresh CA Grown Eggs |
Product co-occurrence by lift: quads
| lift | product 1 | product 2 | product 3 | product 4 |
|---|---|---|---|---|
| 0.0111 | Banana | Bag of Organic Bananas | Organic Baby Spinach | Half & Half |
| 0.0128 | Banana | Bag of Organic Bananas | Organic Whole Milk | Organic Zucchini |
| 0.0137 | Banana | Bag of Organic Bananas | Organic Avocado | Organic Half & Half |
| 0.0148 | Banana | Bag of Organic Bananas | Strawberries | Organic Lemon |
| 0.0155 | Banana | Bag of Organic Bananas | Organic Hass Avocado | Spring Water |
I think I see a pattern... Of course it's unlikely that someone would buy both organic and non-organic bananas which points to the bigger issue that 50,000 products is too granular. Every product has a dozen+ variants. There are 28 different condom products and 110 different apple products in the produce department alone, so our silly "condoms + apples" example will struggle to rise above the noise.
We have 49,688 products (too narrow) sorted into 134 aisles (too broad). We need something in between. Time to build a classifier! But how?
Enter GPC
It turns out nearly 100% of grocery retailers use a product classification system called GS1 Global Product Classification (GPC). GPC is an ontology of everything you might find at a big-box or a grocer. It divides the universe of products into segments (camping, footwear, lighting, tools, food…), which contain families (bread, beverages, fruits, meat, vegetables…), which contain classes (beans, melons, peppers, fungi…), which contain bricks (chanterelles, enokitake, truffles, morels…).

Some bricks go even deeper into subtypes or attributes, e.g. Morels can have a growing method of CONVENTIONAL or ORGANIC, but for our purposes we can stop at the brick level. There are 5,318 bricks in the full GPC system. Many segments (plumbing, live animals, industrial systems, etc.) aren't sold at grocery stores, so we can drop them. That leaves 9 grocery-relevant segments with 1,697 total bricks, and our products only populate about 1,000 of them. This feels like the right level of granularity and yields a 50x reduction in complexity!
Time to fire up the ol' classifier. Since we're squeezing ~50,000 products into ~1,000 bricks, I used a standard two-stage approach:
- Shortlist the brick options for each product. First, get embeddings for every product and every brick. I did this locally using
qwen3-embedding:8b. Then, for each product, find its 10 nearest bricks by cosine similarity. - Choose the best brick. Use an LLM to select the best-fit brick for each product from the 10 options. This cost me ~$5 and took a few minutes, running 60 requests in parallel using
gpt-4.1-mini. The full product-to-brick mapping is here in case it's useful to anyone else.
Now let's run our co-occurrence algorithm again and see if using bricks rather than products yields better results.
Brick co-occurrence by lift: pairs
| lift | brick 1 | brick 2 |
|---|---|---|
| 0.004 | Wine – Still | Grains/Cereal – Not Ready to Eat (Frozen) |
| 0.007 | Spirits | Grains/Cereal – Not Ready to Eat (Frozen) |
| 0.012 | Beer | Baby Leaves |
| 0.013 | Spirits | Dates |
| 0.019 | Wine – Still | Stem Vegetables (Fresh Cut) |
| 0.020 | Spirits | Fish – Unprepared/Unprocessed |
| 0.022 | Beer | Fish – Unprepared/Unprocessed (Shelf Stable) |
Brick co-occurrence by lift: triples
| lift | brick 1 | brick 2 | brick 3 |
|---|---|---|---|
| 0.014 | Cheese | Wine – Still | Frozen Grains/Cereal |
| 0.019 | Milk | Savoury Grain Meals (Shelf Stable) | Spirits |
| 0.019 | Cucumbers | Baby/Infant Specialised Foods | Spirits |
| 0.020 | Kale | Clementines | Wine – Still |
| 0.021 | Broccoli | Baby/Infant Specialised Foods | Spirits |
Brick co-occurrence by lift: quads
| lift | brick 1 | brick 2 | brick 3 | brick 4 |
|---|---|---|---|---|
| 0.027 | Banana | Strawberries | Garlic | Spirits |
| 0.028 | Milk Substitutes | Strawberries | Carrots | Spirits |
| 0.032 | Banana | Milk Substitutes | Baby Food | Spirits |
| 0.035 | Banana | Milk | Wine – Still | Savoury Grain Meals |
Far less repetition! But there's still something missing. Just because these are the rarest combinations doesn't make them interesting. For some reason people don't buy wine and frozen rice together, or beer and fish. So what? How do we make these combos spicier? Funnier?
We need a humor index for products.
What's funny?
Claude dutifully scored all ~1,000 grocery bricks with a 0–1 humor score, based roughly on how taboo they are or how likely they'd be to come up in a stand-up comedy routine. The general ranges:
| score | # of bricks | examples |
|---|---|---|
| 0.0 – 0.1 | 726 | Milk, Armenian Cucumber, Herbs, Prepared Fish |
| 0.1 – 0.3 | 271 | Confectionery, Cooking Wines, Breath Fresheners, Ear Care |
| 0.3 – 0.5 | 50 | Energy Drinks, Toilet Paper, Denture Care, Diet Aids |
| 0.5 – 0.7 | 12 | Wart/Corn Treatments, Foot Care, Medical Lubricants, Appetite Control |
| 0.7 – 1.0 | 15 | Condoms, Intimate Lubricants, Contraception, Enemas/Douches |
(Humor scores for all bricks are here)
Now we can multiply each combo's aggregate humor into the ranking alongside its rarity, and we should get much better results. Let's try that.
Funniest rare combos: pairs
| brick 1 | brick 2 |
|---|---|
| Garlic | Diarrhoea Remedies |
| Kale | Enemas/Douches |
| Garlic | Enemas/Douches |
| Flat Parsley | Condoms |
| Baby Food | Enemas/Douches |
| Coriander | Enemas/Douches |
| Baby Food | Condoms |
| Baby Food | Adult Diapers |
Funniest rare combos: triples
| brick 1 | brick 2 | brick 3 |
|---|---|---|
| Cheese | Almond Milk | Intimate Lubricants |
| Milk | Almond Milk | Intimate Lubricants |
| Apples | Avocados | Intimate Lubricants |
| Onions | Raspberries | Antacids/Flatulence Remedies |
| Apples | Tinned Vegetables | Condoms |
| Milk | Almond Milk | Enemas/Douches |
Funniest rare combos: quads
| brick 1 | brick 2 | brick 3 | brick 4 |
|---|---|---|---|
| Milk | Almond Milk | Tomatoes | Antacids/Flatulence Remedies |
| Apples | Avocados | Ice Cream | Antacids/Flatulence Remedies |
| Cheese | Milk | Apples | Condoms |
| Bananas | Apples | Kale | Antacids/Flatulence Remedies |
| Bananas | Yogurt | Milk | Enemas/Douches |
Much better! Some of these even made me laugh out loud. Kale and an enema? Parsley and condoms? Adult diapers and baby food? There's gotta be a joke in there somewhere.
That said, in a large enough shopping cart, funny combos become more likely just by chance. If you're ordering all your groceries for the week you're going to pick up everything, from the boring to the spicier. So what happens if we look only at small carts, where the entire order is just 2 or 3 items?
Funniest small carts: 2 items
| item 1 | item 2 |
|---|---|
| Vitamin D Milk | Ultra Thin Condoms |
| Cola | Ultra Thin Condoms |
| Bag of Organic Bananas | Anti-Diarrheal |
| Italian Bread | Ultra Thin Condoms |
| Oreo Chocolate Sandwich Cookies | Personal Lubricant |
| Bag of Organic Bananas | Incontinence Underwear |
Funniest small carts: 3 items
| item 1 | item 2 | item 3 |
|---|---|---|
| String Cheese | Potato Chips | Omeprazole Acid Reducer |
| Black Cherry Yogurt | Hass Avocado | Omeprazole Acid Reducer |
| String Cheese | Black Cherry Yogurt | Personal Lubricant |
| String Cheese | Italian Bread | Personal Lubricant |
| Vitamin D Milk | Italian Bread | Anti-Diarrheal |
| Bag of Organic Bananas | Cola | Personal Lubricant |
Small orders are less common but we still got some fun ones. Oreos and lube? Sounds like a good time!
