Exercises: ML Engineering and Feature Stores
Solutions and grading notes are in the instructor companion. Exercises marked ๐งช use
code/pit_join.py. None of these requires you to train a model โ that is the point of the chapter.
Warm-Up
Exercise 32.1 โ Whose problem is it?
Difficulty: โ โโ ยท Time: 15 minutes
For each symptom, say whether it is yours, shared, or not yours โ and name the first diagnostic you would run:
- The model scores 0.83 offline and 0.59 in production, from day one.
- The model scored 0.72 at launch and 0.61 six months later.
- The model has never exceeded 0.55 in any configuration.
- The model scored 0.72 for eight months and 0.58 last Tuesday.
- The model's predictions are well-calibrated but the business impact is negligible.
Then: ยง32.2 gives a four-line lookup for this. Write it from memory before checking.
Exercise 32.2 โ Three parts of a feature
Difficulty: โ โโ ยท Time: 15 minutes
ยง32.3: a feature is a value about an entity, at a moment.
For each, name the entity, the value, and the as-of โ and say which is missing or ambiguous:
customer.lifetime_ordersin a nightly-refreshed table.product.categoryin a Type 2 dimension.session.pages_viewed, computed at session end.customer.churn_probability, written by a model that runs weekly.(customer, product).times_purchased.
Which of the five has a version as well as a timestamp, and why?
Exercise 32.3 โ Read the leak
Difficulty: โ โโ ยท Time: 20 minutes ยท ๐งช
python code/pit_join.py --leak
- The naive join scores 0.830 and the as-of join 0.591. Explain the mechanism in two sentences, using the fact that churners stop ordering.
- 97.1% of rows differ between the two joins. Why is that number so high, and what would make it lower?
- The chapter says the failure mode of leakage is "good news." What does that imply about which defects get investigated?
- Which of Chapter 23's twenty-two assertions would catch this? Be honest.
Core
Exercise 32.4 โ Write an as-of join
Difficulty: โ โ โ ยท Time: 45 minutes
Without looking at pit_join.py:
- Write an as-of join in SQL for your warehouse. Handle: the inclusive boundary, entities with no feature row, and multiple feature rows on the same timestamp.
- Write the same thing in Python, as a sort-merge.
- State the invariant your implementation must satisfy, in one sentence.
- Write the test that asserts it over a whole dataset, not over three examples.
- Now read
pit_join.py's version and diff it against yours. What did you miss?
Exercise 32.5 โ Null is not zero
Difficulty: โ โ โ ยท Time: 30 minutes ยท ๐งช
ยง32.5's ๐ callout: 130 of 20,000 rows have no observation.
- For each feature, say what
NULLmeans and what0means, and whether they differ:orders_to_dateยทdays_since_last_orderยทrefund_count_90dยทavg_basket_centsยทis_email_subscriber - Two of the five are cases where
0is the correct fill. Which, and why? - In
pit_join.py, changerow["value"] = Nonetorow["value"] = 0. Re-run--self-check. Which assertions fail, and which do not? What does the set of passing assertions tell you about testing this decision? - Design the assertion you would add to Chapter 23's register to catch a silent
COALESCE(x, 0)on a feature column.
Exercise 32.6 โ Measure feature age
Difficulty: โ โ โ ยท Time: 40 minutes ยท ๐งช
python code/pit_join.py --asof
- The fixture's ages are p50 11 days, p90 34, p99 55, max 61. Where does that distribution come from? Trace it back to the fixture's generation.
- For a real feature you have access to, compute the age distribution at training time. If you have no such feature, compute it for a warehouse table you refresh on a schedule.
- ยง32.6 says the fix is sometimes to make serving staler. Construct the case where that is right, and the case where it is clearly wrong.
- Build the four-column table from ยง32.6's ๐ callout for three features you own.
Exercise 32.7 โ The row-level diff
Difficulty: โ โ โ ยท Time: 45 minutes ยท ๐งช
python code/pit_join.py --skew
- Case Study 2's distribution comparison found means of 34.2 and 34.6 and passed. Reproduce that: compute the mean of both paths in the fixture and confirm they look equivalent.
- Now compute the row-level disagreement rate. State in one sentence why the first check cannot find what the second finds.
- Break the segmentation: report the disagreement rate by a segment other than recency. Does the concentration still show up?
- Add a fourth bug to
serving_days_since_last_orderโ your choice โ and predict its disagreement rate and segment before running it.
Exercise 32.8 โ Do you need a feature store?
Difficulty: โ โ โ ยท Time: 30 minutes
ยง32.9's threshold: online inference and the same feature computed twice and more than one consumer.
Apply it to five scenarios:
- One model, batch scoring nightly, one team.
- One model, online scoring at checkout, one team.
- Four models, all batch, sharing eight features across three teams.
- Two models, one batch and one online, sharing four features.
- Twelve models, all online, one team, no shared features.
For each: buy, build the missing piece, or use a table โ and name the missing piece where relevant.
Exercise 32.9 โ Labels
Difficulty: โ โ โ ยท Time: 40 minutes
ยง32.11's four properties: definition, two timestamps, delay, source.
For a prediction problem you know (or Kestrel's churn model):
- Write the label definition precisely enough that two people would compute it identically.
- Name both timestamps. How far apart are they?
- What is the labeling delay, and what does it do to your newest training data?
- Is the label produced by a human, a rule, or a model? If a model, describe the feedback loop.
- ยง30.8's problem applies here. Grep for your label's name. How many definitions?
Exercise 32.10 โ The monitoring set
Difficulty: โ โ โ ยท Time: 40 minutes
ยง32.12 lists four things to monitor and excludes model accuracy.
- Implement the first โ feature distributions in training versus serving โ for three features. Report mean, p50, p99, and null rate in both.
- Why is accuracy excluded, and when does it become available for a 90-day churn label?
- Design the alert thresholds for all four. Which one should page (Chapter 26), and which should not?
- ยง32.12 claims the prediction distribution is a leading indicator. Construct the scenario where it moves and nothing is wrong.
Advanced
Exercise 32.11 โ Extend the lab
Difficulty: โ โ โ ยท Time: 90 minutes ยท ๐งช
Add three to pit_join.py, with self-checks:
- A second leaking feature with a different mechanism โ one that leaks through an aggregate window rather than a current value.
- A
--splitmode implementing the time-split evaluation from Case Study 1, reporting both CV and time-split AUC. - Feature age reported per segment, so a segment with systematically staler features is visible.
- A materialization simulator: apply changed-only writes and count them (ยง32.8's 71ร).
- An l-o-o entity check: assert that an entity's feature value never depends on another entity's future โ a leak class the current fixture cannot express.
- A
--skew --segment-byflag taking any grouping expression.
Then: report how many self-checks you added, and name the one that would have caught a bug you did not deliberately inject.
Exercise 32.12 โ Find the leak in a real pipeline
Difficulty: โ โ โ ยท Time: 60 minutes
Take a training query from your own work, or write one for Kestrel's churn model.
- List every feature and its as-of semantics. Any feature you cannot answer for is a suspect.
- For each, ask: could this value have changed between the prediction moment and now, in a way correlated with the outcome? That question is the leak detector.
- Run the time-split check. Report both numbers.
- If the gap is small, construct a leak and confirm your check detects it. A diagnostic you have never seen fire is not yet a diagnostic.
Exercise 32.13 โ Design the shared implementation
Difficulty: โ โ โ ยท Time: 90 minutes
Case Study 2's fix separated computation from retrieval.
- Take a feature currently computed in SQL. Refactor it into a function that takes data and returns a value, plus two thin retrieval layers.
- What does the SQL path cost in runtime? Measure it, or estimate and say how.
- Where does your design break? Case Study 2 names one: a feature needing data the serving path cannot cheaply fetch. Construct yours.
- Implement the daily skew check, reported by segment.
- Write the case for deleting your skew check in a year, and the rebuttal.
Exercise 32.14 โ The backfill that invalidated a model
Difficulty: โ โ โ ยท Time: 60 minutes
ยง32.10's ๐ callout: a correct backfill silently invalidated a model for five weeks.
- Design the control. A backfill to a feature table must enumerate its consumers before running. Where does the consumer list come from?
- Content-address a training set. What exactly do you hash, and what breaks if you hash the query instead of the data?
- The corrected feature ran 3% lower and the model over-predicted churn. Which of ยง32.12's four monitors would have caught it, and how fast?
- ยง32.10 says a materially changed definition is a new feature with a new name. Argue against this, then argue for it, then say which you would enforce.
Exercise 32.15 โ Hold the boundary
Difficulty: โ โ โ ยท Time: 45 minutes
ยง32.13: "the model isn't good enough" is not a data engineering ticket.
- Write the four questions you can answer in a week โ leaking, skewed, stale, mislabelled โ as a concrete checklist with the command or query for each.
- Run all four against a model you have access to. Report the four answers.
- Draft the message you send when all four come back clean. It must be useful, not defensive.
- Construct the case where a data engineer should take on model quality, and say what changes.
Project Milestone
Exercise 32.16 โ Feature infrastructure for Kestrel
Difficulty: โ โ โ ยท Time: 3โ4 hours ยท ๐งช
Build the ML surface from ยง32.12's ๐งฑ callout on your own platform.
- Build one point-in-time-correct feature table as a Chapter 20 incremental model with
valid_from/valid_to. - Write one as-of join, with the invariant test over all rows.
- Compute feature age for that feature, and state what serving age it would need.
- Generate labels for a prediction problem, with both timestamps and a documented delay.
- Run the time-split evaluation against a random split. Report both. If they agree, construct a leak and confirm the check catches it.
- Implement the skew check for one feature computed two ways โ even if you have to write the second way to have something to compare.
- Publish the three daily numbers: skew rate, feature age ratio, null rate delta.
- Apply ยง32.9's threshold to your platform and write the one-paragraph answer.
Deliverable: the feature model, the as-of join and its test, both evaluation numbers, the three published metrics, and the feature-store decision with its reasoning.
Step 5 is the one that matters. A team that has never seen its leak detector fire does not have a leak detector.