Back to home
Case study · Bachelor's thesis

Making data quality measurable

My bachelor's thesis “Key Figures for Measuring Data Quality” (grade 1.3), worked through again: with more than a million real, uncleaned retail records from a public dataset.

1.07Minvoice lines analyzed
8attributes profiled
23 %lines without a customer
97 %“complete” with equal weights

The idea of the thesis

Decisions are made based on data, but bad data often only shows up at the very end: in the data warehouse, when a KPI doesn't add up. My thesis looked at how to make data quality measurable beforehand.

The approach: pick quality criteria from the literature, turn them into percentages through metrics, and get the facts straight from the database through data profiling. In the thesis I applied this to the customer master data of an industrial company. Here I show the same approach on public data.

How to recognize data quality

Credibility

CorrectnessConsistencyReliability

Usefulness

CompletenessAccuracyTimelinessNon-redundancyRelevance

Interpretability

UniformityUnambiguityUnderstandability

Key integrity

Key uniquenessReferential integrity

Taxonomy after Hinrichs (2002). Data quality is always multidimensional and depends on the purpose the data is used for.

Data profiling in four steps

1

Integration

Copy the data from the source system into a separate area so the analysis doesn't load the system and the state is frozen.

2

Analysis

Examine attributes, tuples and relations with standard methods: data type, value range, patterns, domains, NULL values, keys, relationships.

3

Presentation

Prepare the findings so the business side understands them, and calculate key figures from them.

4

Assessment

Clarify with the business side what really is an error and fix the causes. Then the cycle starts again.

The metric: completeness on three levels

Following Hinrichs, completeness is built bottom up. A value counts as missing if it is NULL or something that means the same in business terms, such as “UNDEFINED”, “?” or a 0 used as a placeholder.

(1) Attribute valueQ(w) = 0 if w ≙ NULL, else 1
(2) Tuple (record)Q(t) =Σ Q(t.Ai) · giΣ gi
(3) Relation (table)Q(T) =Σ Q(ti)|T|

g is an attribute's weight between 0 and 1, depending on how important it is for the use case.

Applied to a public dataset

Online Retail II contains every invoice line of a UK online retailer over two years, uncleaned and with all the quirks of real systems. It's the same kind of data as in my thesis: customer and sales data. The analysis follows the approach from chapter 4 step by step.

1,067,371 lines53,628 invoices5,942 customers5,305 products43 countries2009-12 – 2011-12

The data, up close

16 real rows from the dataset, picked so that every finding shows up at least once. Choose a check or click a highlighted cell to see what's behind it.

Case
Invoice
Invoice number
StockCode
Product code
Description
Product description
Quantity
Quantity
InvoiceDate
Invoice date
Price
Unit price
Customer ID
Customer number
Country
Country
Unremarkable4894348504815CM CHRISTMAS GLASS BALL 20 LIGHTS1209-12-01 07:456.9513085United Kingdom
CancellationC48944922087PAPER BUNTING WHITE LACE-1209-12-01 10:332.9516321Australia
No customer number48952585226CBLUE PULL BACK RACING CAR109-12-01 11:490.55NULLUnited Kingdom
Country “EIRE”48952035751CPURPLE CURRENT CANDLE RING1209-12-01 11:410.7514911EIRE
Unknown country49486084832ZINC WILLIE WINKIE CANDLE STICK510-01-19 11:010.8512470Unspecified
Postage as product489439POSTPOSTAGE309-12-01 09:2818.0012682France
Note instead of name48946371477short-24009-12-01 10:520.00NULLUnited Kingdom
“?” as name49502721314?1,14610-01-20 13:480.00NULLUnited Kingdom
Ghost row48952121646NULL-5009-12-01 11:440.00NULLUnited Kingdom
Write-offA506401BAdjust bad debt110-04-29 13:36-53,594.36NULLUnited Kingdom
Duplicate48951721912VINTAGE SNAKES & LADDERS109-12-01 11:343.7516329United Kingdom
Duplicate48951721912VINTAGE SNAKES & LADDERS109-12-01 11:343.7516329United Kingdom
Same code, other name49536215058ABLUE WHITE SPOTS GARDEN PARASOL210-01-24 12:127.9515727United Kingdom
Same code, other name53820015058ABLUE POLKADOT GARDEN PARASOL110-12-10 11:117.9517912United Kingdom
Same customer, other country49736322055MINI CAKE STAND HANGING STRAWBERY810-02-09 09:411.6512370Austria
Same customer, other country53882685123AWHITE HANGING HEART T-LIGHT HOLDER6410-12-14 12:582.5512370Cyprus

Tip: the finding cards further down highlight the matching cells too.

Attribute level

Tuple level

Relation level

Completeness per attribute

At attribute level, almost everything looks very good. With one exception, and that's exactly the one that matters for customer analyses.

Invoice number
100.00 %
Product code
100.00 %
Product description
99.51 %
Quantity
100.00 %
Invoice date
100.00 %
Unit price
99.42 %
Customer number
77.23 %
Country
99.93 %

Try it yourself: weighting can hide gaps

This was the key insight of my thesis. Depending on how the attributes are weighted, the same data produces a very different key figure. Move the sliders or pick a use case.

99.5 %
Completeness with your weights
97.0 %
Completeness with equal weights
77.2 %
Weakest attribute: Customer number

A key figure above 95 % even though almost every fourth line has no customer: that's the effect the thesis warns about. Always look at attribute level too.

How the metric calculates

The same rows, now rated: 1 = present, 0 = missing (placeholders included). On the right is each row's completeness Q(t) with the weights from above. Click a row to see the calculation.

Case
Invoice
Invoice number
StockCode
Product code
Description
Product description
Quantity
Quantity
InvoiceDate
Invoice date
Price
Unit price
Customer ID
Customer number
Country
Country
Q(t)
Unremarkable111111111.00
Cancellation111111111.00
No customer number111111010.98
Country “EIRE”111111111.00
Unknown country111111100.95
Postage as product111111111.00
Note instead of name110110010.75
“?” as name110110010.75
Ghost row110110010.75
Write-off111111010.98
Duplicate111111111.00
Duplicate111111111.00
Same code, other name111111111.00
Same code, other name111111111.00
Same customer, other country111111111.00
Same customer, other country111111111.00
Q(T) of this sample = Σ Q(t) / 160.95
Calculation for „Note instead of name“
Q(t) = (1·1.0 + 1·1.0 + 0·0.3 + 1·1.0 + 1·1.0 + 0·1.0 + 0·0.1 + 1·0.3) / 5.7 = 0.75

Each 0 or 1 is multiplied by its attribute's weight (same order as the table), and the sum is divided by the sum of the weights.

The sample is deliberately full of problem cases. The big figures above apply to the whole dataset.

What I take away

  • Data quality can't be defined in general, only for a purpose. For a sales analysis this data is good, for a customer analysis it isn't.
  • A single key figure isn't enough. Only several criteria and several levels together give an honest picture.
  • Data profiling doesn't just find errors, it also hints at their cause, for example the ghost rows or the cancellations hidden in the key.

What I'd add today

  • Automate the checks as rules so they run on every data import, as I do today in my migration projects.
  • Measure further criteria such as consistency and timeliness, not just completeness.
  • Let machine learning find unusual patterns instead of knowing every rule in advance. That's a topic of my master's.

Sources & notes

Dataset: Chen, D. (2019). Online Retail II [Dataset]. UCI Machine Learning Repository. https://doi.org/10.24432/C5CG6D (CC BY 4.0).

Bachelor's thesis: Ackermann, P. (2021). Kennzahlen zur Messung der Datenqualität (Key Figures for Measuring Data Quality). Europäische Fachhochschule (now CBS International Business School). Grade 1.3.

The original thesis contains confidential company data and is therefore not public. All figures on this page come from the public dataset.