Data analytics case studyIndependent portfolio projectFictional data
Pricing/Demo
by Alfonso Cifuentes
Turning a complex publishing catalogue into defensible pricing insights.
This project grew out of a technical assessment I completed during a recruitment process for a data analyst role at an international educational publisher. The task was to structure a product catalogue, compare genuinely equivalent items, and explain which price differences deserved further investigation. I rebuilt the case with entirely fictional titles, series and prices so the approach could be shared publicly.
362 simulated products. 12 fictional series. One question: are the prices different, or are the products different?
An independent reconstruction using fictional data. No employer catalogue or commercial prices are included, and this is not paid or client work.
01 · The brief
Why a publisher can’t just sort its price list and read off the anomalies.
A price list is less straightforward than it looks.
An educational book price list hides a lot. One course can come as a student book, a workbook, an answer-key edition, a digital licence or a bundle, in several levels and editions. Two titles may look similar and still be different products.
Before looking for price anomalies, I needed to recover each product’s identity and define what a fair comparison actually meant. Averaging across all of it gives a confident wrong answer: the mean of this fictional catalogue is €44.04, a figure that describes no product at all.
Student book
The core coursebook for one level.
Workbook
Practice book, sold with or without an answer key.
Pack
A student book bundled with extras, such as digital access.
Digital access
An online version or practice licence; its duration is often not stated.
Edition
A revision of the same title; different editions are different products.
Level
CEFR (Starter to C1) for teens and adults, grades 1–6 for primary.
Fig. 1 Every product, one dot, grouped by type. Fictional EUR list prices: the types barely overlap, so a pooled average means little.
Price range by product type
Type
Count
Min
Median
Max
See type_stats in public/data/analysis.json
02 · The raw material
Every name and price below was invented by a seeded generator. Same seed, same file, byte for byte.
Five columns in. Nineteen out.
The raw file has 362 rows across 12 invented series, with two level systems. Each row carries only five fields: series, segment, sub-segment, title and price.
Enrichment adds fourteen attributes the comparison needs. Some can be read from the title; others, like edition and access duration, never appear there and have to come from metadata. That difference matters later.
Series
Segment
Sub-Segment
Title
Price_EUR
Edition
Level
Level_System
Product_Type
Product_Role
Book_Part
Pack_Type
Answer_Support
Digital_Main_Book_Access
Digital_Practice_Book_Access
Audio_Access
App_Access
Additional_Resources
Access_Duration
Amber Path
Compass Junction
Driftwood Dialogues
Fable Road
Glasshouse English
Kindred Horizons
Little Lanterns
Mosaic English
Northstar Language Lab
Orion Exam Prep
Silverline Skills
Wildflower Words
03 · My approach
Four steps, in this order. Skipping the first is how analysis quietly destroys evidence.
Hold the product still. Then look at the price.
Keep the source.
The raw file is never edited. Every correction lives in a separate reporting view that can be switched off, so any number can be traced back to the record it came from.
Recover the structure.
A rule-based parser reads titles only. It matched the reference labels on level, pack, answer key, book part, audio and digital access for all 362 rows, and abstained on product type twice (“TB”, “Gleebook”) rather than guess. The rules were written for this synthetic catalogue’s own title patterns, so that score checks the rules; it says nothing about accuracy on real data.
Not recoverable from titles: edition · access duration · extra resources · segment
Compare like with like.
Group products that are the same in every respect except the level, then ask whether the price changes with the level. The formal definition is below.
Separate fact from guess.
A price difference is a question for the commercial team, not a verdict. Each exception is classified as a data issue, a plausible pricing decision or an open question, and left in the data so the reader can disagree.
The analytical question
Comparable group: products sharing series, type, role, book part, pack, answer key, both digital rights, extra resources and edition, present at two or more levels. Uniform price: every product in the group has the same list price.
68 groups in total · 60 span two or more levels and can be tested · 8 exist at a single level and are set aside.
The interesting errors don’t show where a record belongs. They show where it landed.
Six exceptions. Two weren’t about price at all.
60comparable groups
54hold one price at every level
6change price with the level
4cheaper Starter level: a plausible pricing choice, unconfirmed
2a record from another series filed in the group: a data issue
Proof · Glasshouse English · Premium Pack with Digital · as recordedSeries field / Title / Price
Glasshouse EnglishGlasshouse English A2 Premium Pack with Digital€86.49
Glasshouse EnglishGlasshouse English B1 Premium Pack with Digital€86.49
Glasshouse EnglishMosaic English B1 Premium Pack with Digital€69.49
Glasshouse EnglishGlasshouse English B2 Premium Pack with Digital€86.49
?Observation, row 20: level B1 appears twice in this group, and one B1 title says Mosaic English. Interpretation: what looks like a €17 price cut is another series’ product filed under the wrong name. Action: keep the source; re-file it in the reporting view. Row 155 is the same pattern (a Glasshouse English study pack filed as Kindred Horizons).
As recorded
54/60
90.0% of comparable groups hold one price
re-file 2 records by title prefix, reporting view only
Reporting view
56/60
93.3% · same 60 groups, source file untouched
The denominator was recomputed after re-filing, not assumed: both views yield 68 groups and 60 comparable ones, because each misfiled record fills an empty slot in its real series. The classification was corrected for analysis; no price was changed.
05 · Explorer
Each row is one configuration; read across the levels. A highlighted price differs from the row’s reference price, its most common price, and shows the difference.
€69.49 differs from the row’s reference price
−€17.00 difference from the reference price
M series field contradicts the title (data issue)
E edition label spelled two ways
O price above the IQR fence, type unresolved
G “ebook” inside a word (parser trap)
T segment hierarchy mismatch
Read the catalogue yourself.
Pick a series. The grid shows every fictional product in it, priced by level; nothing is aggregated. Switch to the reporting view to see the two misfiled records move to their own series.
Scroll sideways for every level →
06 · Evidence
Each comparison holds series and level fixed and checks edition labels. Strict and indicative matches are reported separately.
Three comparisons, with their caveats.
Split volumes
Part A + Part B costs about 14% more than the complete book.
Strict (same series, level and edition label): 10 of 12 levels. Little Lanterns €62.00 vs €54.49 (+13.8%); Wildflower Words +13.9%. Indicative:2 Little Lanterns levels where parts and volume carry different edition labels show the same gap.
Entry level
Starter is cheaper in two series, and only there.
Mosaic English and Silverline Skills price Starter student books −€8.00 and workbooks −€4.00 below their other levels (−14.0% to −19.5%). Observation: a consistent pattern. Interpretation: an entry-level policy is plausible. List prices alone can’t confirm intent.
Answer keys
With key or without, the price is the same.
24 of 24 workbook pairs, matched on series, level and edition, share one price. Parity only means something because the match is strict.
07 · Quality register
Stet: let it stand. Query: ask the owner. Normalise: alias in reporting only. Investigate: a pattern without a known cause.
Ten things that look like facts.
Each issue was planted in the generator on purpose, then found, measured and logged. None was silently fixed.
Series field contradicts the title2 rowsQuery
Rows 20 and 155 carry another series’ name. They create two of the six price “exceptions”. The source keeps the recorded value; the reporting view re-files them by title prefix.
Two spellings of one edition3 + 3 rowsNormalise
“Second Edition” and “2nd Edition” appear on six Little Lanterns rows. Alias them for reporting. Because edition is part of the comparison key, these rows sit outside every cross-level group. They are six of the 8 single-level groups; the other two are the TB pack and the Gleebook resource, each the only product of its kind.
“Gleebook” is not an eBook1 rowStet
A printed resource whose name contains the letters “ebook”. A substring rule grants it digital access; a word-boundary rule doesn’t. The record is correct, so it stands. The parser was the problem.
One pack, two names6 vs 24 rowsQuery
Mosaic English calls its study pack “+ Online Access”; every other series says “with Digital”. Probably the same thing, but merging them is a business decision, not a parsing one.
Primary book filed as Secondary1 rowQuery
Row 61, Fable Road Level 1 Pupil Book: segment Primary, sub-segment Secondary. Every other Fable Road row says Primary. A hierarchy error that would skew any segment report.
The unresolved “TB” code€108.49Investigate
The only price above the upper IQR fence (about €100). “TB” could mean teacher’s book or something else entirely, so its category stays unresolved; it is not re-classified from its price. Flag it; don’t delete it to tidy a chart.
Access duration, mostly not stated6 of 72Stet
Six digital workbooks state 18 months; sixty-six say nothing. Blank means not stated, not unlimited. Treating the gap as “no limit” would invent a product feature.
Part A + B premium10 strict + 2 indicativeInvestigate
Buying both halves costs about 14% more than the complete volume at every level of both split series. Ten levels are strict matches; at two Little Lanterns levels the parts and the volume carry different edition labels, so those two are indicative only. Possibly intended; worth confirming before anyone calls it an error.
Starter priced below other levels4 groupsInvestigate
Two series, student book and workbook only. Consistent enough to look deliberate. The data shows the pattern; the reason has to come from a person.
Answer-key parity24 of 24 pairsStet
With-key and without-key workbooks always share a price when matched on series, level and edition. A clean result, logged because a looser match would have hidden it.
08 · Limits
Said plainly, so nobody has to infer it.
What a list price can’t tell you.
Not in the data
Sales
Costs
Margins
Discounts
Demand
So there is no recommended price here, no claim about profitability and no estimate of financial impact. The €44.04 mean describes this synthetic catalogue only, not any market. The parser’s perfect score is a check of rules written for synthetic titles, not a production benchmark. And replacing names and prices is not, on its own, a legal opinion on confidentiality. What the analysis can do is hand a commercial team four precise questions:
Is the Starter discount in Mosaic English and Silverline Skills deliberate?
Who owns series metadata, and how did rows 20 and 155 get filed under the wrong name?
Is the premium of about 14% for buying a book in two parts intended?
What is “TB”, and does €108.49 belong in the same catalogue?
09 · Videos and files
Everything the page says can be checked in these files. Rerun the generator and you get the same bytes.
Watch it, then check my work.
The full case, from the brief to the limits. Narrated with a synthetic voice (ElevenLabs).
A standalone one-minute story for phones, captions burned in.
The most striking number is not always the real problem. Two “price exceptions” here were filing errors; correcting the classification, not the prices, changed the reading from 54 to 56 uniform groups out of 60.
What the case shows for an analytics role: structuring messy catalogue data, defining a fair comparison before measuring, keeping lineage from source to report, separating observation from interpretation, and delivering it as reproducible Python, a live-formula Excel workbook and a clear story.
Made by Alfonso Cifuentes: Python for generation and analysis, Excel for live-formula verification, HTML, CSS and JavaScript for this page, Remotion and ElevenLabs for the videos.