Data quality in depth: holes, duplicates, outliers, identifiers, leaks
Everything the Quality tab tells you, what it cannot tell you, and the ten points of accuracy that were hiding in 240 duplicate rows
Objectives
By the end of this session you will be able to:
- Read a missing-value pattern and turn it into a hypothesis about the data collection
- Measure what duplicate rows do to a score, instead of assuming
- Compare the two outlier methods and choose one on purpose
- Recognise an identifier column and know why the studio drops some columns by itself
- Name the five leak codes rakoon-ds raises, and find one it does not raise
- Seal a test set before you have the chance to peek
Prerequisites
- A rakoon-ds account on https://rakoon-ds.apps.way-up.io (free, browser only, nothing to install), and the group join code your instructor gives you
- A recent Chrome, Edge or Firefox. Computation runs either in your own tab (browser engine) or on the server; the header pill tells you which
- The mission for this session, assigned to your group. Open a project, then the Mission button in the workshop header: the panel opens next to Report. Click Check after each step
- Practical works 1 and 2 finished
- Transformation, chart and algorithm names come from the rakoon-ds registry and are served in French even when the interface is in English. Every step below gives you the French label you will click and, in
code font, the registry key the mission checks against.
Data
Three built-in datasets, each chosen for one defect. Nothing to download.
| Dataset | Rows x cols | The defect it carries |
|---|---|---|
titanic | 1 309 x 11 | 20 % of ages missing, 77 % of cabins missing, and the two go missing together |
wine_quality | 1 599 x 12 | 240 exact duplicate rows and a target imbalanced 68 to 1 |
bike_sharing | 731 x 15 | two columns whose sum is exactly the target |
If your instructor gives you the SNCF lost-property pack (objets-trouves-restitution-2019 to -2022, 258 902 rows), run the same six steps on it: the return date is the leak, and the studio flags it as leak_association at 1.00 with an accuracy of 0.999, against 0.70 for the honest model.
Timing
The steps below add up to the announced duration. If you fall behind, Step 1 to Step 3 are the ones that must be finished.
| # | What you do | Time |
|---|---|---|
| Step 1 | Missing values, and the pattern block nobody reads | 12 min |
| Step 2 | Duplicates: measure them, do not assume | 15 min |
| Step 3 | Outliers: two methods, two viewpoints | 12 min |
| Step 4 | Identifiers, and what the studio drops behind your back | 10 min |
| Step 5 | Leaks: the five it catches, and the one it misses | 16 min |
| Step 6 | Seal, and write the data section | 10 min |
| Total | 75 min | |
Instructions
Step 1: Missing values, and the pattern block nobody reads12 min
- New project
PW6 Quality. Add the built-in Titanic (passagers). - Explore → Quality, target
survivant. - In the Missing values card, read the per-column bars, then scroll to Most frequent patterns.
Reference figures: age 263 missing (20.1 %), cabine 1 014 (77.5 %), canot 823 (62.9 %). And the patterns:
| Columns empty together | Rows | Share |
|---|---|---|
cabine + canot | 538 | 41.1 % |
cabine alone | 235 | 18.0 % |
age + cabine + canot | 182 | 13.9 % |
canot alone | 90 | 6.9 % |
Answer in writing, in two sentences: what kind of passenger is described by the first pattern, and what does that imply about imputing age with the overall mean?
The card of this dataset says it: age is missing more often in third class. Dropping incomplete rows therefore deletes third class preferentially, and imputing with the mean makes every third-class passenger look like an average passenger. Neither is neutral. "Missing" is data.
Step 2: Duplicates: measure them, do not assume15 min
- Add the built-in Qualité du vin rouge (
wine_quality). - Quality tab, target
qualite. The Duplicates card reports 240 extra rows (15.0 %), 220 groups, 1 359 distinct rows, and lists the row numbers of each group. - Train a Forêt aléatoire (
rf_clf) onqualitewith every column. Note the accuracy. - Apply Supprimer les doublons (
drop_duplicates) (family Lignes, no column selected = all columns). You get 1 359 rows. - Train the same forest on the deduplicated dataset. Note the accuracy again.
| Dataset | Rows | Accuracy | F1 |
|---|---|---|---|
wine_quality as delivered | 1 599 | 0.6725 | 0.6506 |
after drop_duplicates | 1 359 | 0.5706 | 0.5504 |
Ten points of accuracy. They were not skill, they were the same wine sitting on both sides of the train / test split: the model recognised rows it had already been shown. This is the cheapest and most common way to lie to yourself with a score.
Also read the Class balance card here: 681 wines rated 5, 10 wines rated 3, a majority-to-minority ratio of 68.1, and three classes flagged rare (4 with 53 rows, 8 with 18, 3 with 10). What does global accuracy tell you about a class that holds 0.6 % of the data?
Step 3: Outliers: two methods, two viewpoints12 min
Still on wine_quality, Outliers card. Each numeric column gets two counts side by side: outside the Tukey (IQR) bounds, and |z| > 3. Plus the bounds, the quartiles, and up to five example values with their row number.
| Column | Outside IQR bounds |
|---|---|
sucre_residuel | 155 |
chlorures | 112 |
sulfates | 59 |
so2_total | 55 |
acidite_fixe | 49 |
- Pick
sucre_residuel. Click through to two of the example rows in Overview. Are they errors, or are they sweet wines? - Decide, and act: keep them, cap them with Filtrer des lignes (
filter_rows), or bin them with Discrétiser (bins) (bin_numeric) so the extreme values fall into one bucket. - Write down the decision and the reason. "I removed the outliers" is not a reason.
The interquartile method assumes nothing about the shape of the distribution; the z-score assumes it is roughly normal. On a skewed column they disagree, and the disagreement is the information. The report looks at one column at a time: a point that is only strange through the combination of its values is not seen at all.
Step 4: Identifiers, and what the studio drops behind your back10 min
A column with almost as many distinct values as rows cannot generalise. rakoon-ds does two things about it, and you need to know both.
- On
titanic, Quality tab:nomis listed under the points to watch, 1 307 distinct values out of 1 309, ratio 0.998. - Train any classification model on
titanicand open its results. Look for the list of variables actually used. - You will find that
nomandcabinewere disabled automatically and that the studio says so.
That is a real difference with Orange, where a one-hot encoding of 1 307 names explodes in your face. Here the columns are excluded and the list is shown. Your job is no longer to survive the explosion, it is to read the list and check that nothing useful was dropped.
One subtlety worth remembering: a continuous column whose values are all distinct is not treated as an identifier. Three random coordinates are not three row numbers. Only text, categorical and integer columns can be flagged.
Step 5: Leaks: the five it catches, and the one it misses16 min
rakoon-ds checks for leaks before training and shows a banner above the metrics. Five codes:
| Code | Severity | What it means |
|---|---|---|
leak_duplicate | high | the column is the target: same values, or a bijective recoding of it |
leak_association | high | mixed association with the target at 0.98 or more |
leak_name | to fix | the column name contains the target name (prix_final_estime when predicting prix) |
id_feature | to fix | a near-unique feature column |
constant_target | high | the target is constant, or 99 % one class |
Now the counter-example. Add the built-in Vélos en libre-service (par jour) (bike_sharing). Its card says that occasionnels plus abonnes equals total, exactly.
- Train a Forêt aléatoire (
rf_reg) ontotalwith every column. - Reference result: R² = 0.9974, RMSE 99.8, and no warning at all.
The detector looks at one column against the target. Neither occasionnels nor abonnes alone reaches the 0.98 threshold, so nothing fires, and the model is still doing an addition rather than a prediction. A leak that is spread across two columns is invisible to the tool. That is what the model card, and you, are for.
- Retrain without
occasionnelsandabonnes. Reference: R² 0.8889 with the calendar and weather columns, against R² -0.0245 for the Modèle de référence (médiane) (dummy_reg). - Write both numbers down. One of them is a fact about the world; the other is a fact about your spreadsheet.
Step 6: Seal, and write the data section10 min
- On any of the three datasets: apply Découper (proportions) (
split) with0.8, 0.2to get two disjoint parts. - Click the 20 % node and press Sceller. Try to open Explore on it: preview, profile, quality, charts and download all answer with a padlock and one sentence.
- Train a model on the 80 % part, choosing the sealed node as Jeu de test. It works: the sealed dataset is still a perfectly valid test set.
Write as you go, not at the end. In the Report panel every section has its guiding questions in grey; anything you type is saved after 0.7 s. Write the Données section: for each of the three datasets, the defect, the number, and what you did about it. Fifteen lines.
If a browser-side training uses a sealed test set, the computation falls back to the server, because downloading the sealed file is exactly what sealing forbids. Same result, different machine, and the header pill says so.
What you should have
- A missing-value pattern read and interpreted, not just observed
- The duplicate experiment run: two numbers, ten points apart
- An outlier decision taken and justified on one column
- The list of automatically disabled columns, found and read
- The bike leak reproduced: R² 0.9974 with no warning
- One sealed dataset used as a test set
- The
dep-6mission at 6 / 6
Deliverables
- Mission:
dep-6validated - Report: Données and Exploration sections, with the before / after duplicate table
- One paragraph: name a leak that rakoon-ds would not catch on a dataset from your own field, and say how you would catch it
Bonus
- On
breast_cancer, the thirty variables are highly redundant (radius, perimeter and area describe the same size). Look at what that does to the permutation importance chart: importance shared between twins looks like importance that does not exist. - Build a CSV where one column is the target recoded 0 / 1, import it, train, and see
leak_duplicatefire. - Rename a column to
total_estimeonbike_sharingand train ontotal:leak_nameshould fire on the name alone.
Resources
- Session 6 slides (the lecture this practical work follows)
- Course page: both programmes, all fifteen sessions
- rakoon-ds studio
missions/dep-6.json