Skip to content
AI.info

ML data engineering

Feature Transformations and Stateful Pipelines

Engineer reusable transformations, fitted statistics, target-derived features, tests, and parity across environments.

By the end you can

Steps

Promote a feature from experiment to shared pipeline

Promoting a feature should settle what it means, not merely copy code into a repository. Specify the semantics first: entity, cutoff, source, formula, units, null behavior, and intended consumers. Then classify the state. Fitted parameters, historical windows, external versions, and learned dependencies each impose a different obligation on training and on serving. Implement the logic once. Where two implementations are unavoidable, establish golden tests across runtimes. Add value and invariant tests covering normal, missing, boundary, late, duplicate, and adversarial cases. Then version the feature and watch it: usage, distributions, freshness, online parity, and deprecation status. A feature that nobody observes is a feature nobody can retire.

FigureProcess · 5 steps
  1. 1. Specify semantics

    Name entity, cutoff, source, formula, units, null behavior, and intended consumers.

  2. 2. Classify state

    Identify fitted parameters, historical windows, external versions, and learned dependencies.

  3. 3. Implement once or compare implementations

    Share execution code or establish golden tests across runtimes.

  4. 4. Add value and invariant tests

    Cover normal, missing, boundary, late, duplicate, and adversarial cases.

  5. 5. Version and observe

    Track usage, distributions, freshness, online parity, and deprecation status.

A production feature needs a specification, executable implementation, fitted artifacts, tests, lineage, and an owner.

Analogy

A feature pipeline is a recipe with calibrated measures

One recipe travels between several kitchens. Ingredients are the sources, preparation steps are transformations, and calibrated measures are fitted parameters. A shared recipe is not enough if one kitchen uses a different oven, substitutes ingredients, or measures after cooking. Tests and reference outputs verify that the result is comparable.

Then the analogy breaks, and the break is the point. Measures in a recipe mean the same thing in every kitchen. Fitted feature state does not. It carries the training population inside it. A vocabulary or a quantile boundary is not a universal ingredient; it is an artifact fitted under one dataset version.

Reusable feature logic must carry its fitted state, data boundary, and reference outputs with it.

Test feature meaning, not only code execution

Unit tests verify formulas on small fixtures. Property tests check invariants, such as counts never being negative or recency increasing for a fixed event as the cutoff moves forward.

Golden-record tests compare expected outputs for realistic timelines. Offline–online comparison replays serving requests and measures exact or tolerance-based equality.

Distribution tests can detect broad regressions. They should not replace value-level evidence. Two wrong implementations can produce similar histograms.

Finally, check slice by slice whether each feature is useful and steady. A feature that helps globally but fails for cold-start entities or one region may need fallback logic or narrower use.

The strongest form of the parity test is a logging rule. Google’s Rules of Machine Learning states it as Rule #29: “save the set of features used at serving time, and then pipe those features to a log to use them at training time”. A small fraction of examples will do. The guide reports that the YouTube home page switched to logging features at serving time, with “significant quality improvements”. Skew stops being an argument and becomes a measurement.

Feature QA spans formula correctness, temporal behavior, runtime parity, statistical stability, and consumer value.

Example

Transformation skew can survive identical column names

Offline and online values may differ because logic, state, source, or timing diverges. Two of those divergences have standards and papers behind them. Both are worth reading before you write a window or a tokenizer.

The clock first. A stream carries two times, not one. Google’s Dataflow Model paper separated them in 2015: event time, “the time at which the event itself actually occurred”, and processing time, “the time at which an event is observed at any given point during processing within the pipeline”. The gap between the two is not a bug waiting to be fixed. Akidau and colleagues write: “During processing, the realities of the systems in use (communication delays, scheduling algorithms, time spent processing, pipeline serialization, etc.) result in an inherent and dynamically changing amount of skew between the two domains.” Their figure for it is titled “Time Domain Skew”. The watermark that bounds the skew is only a heuristic: “for most real-world distributed data sets, the system lacks sufficient knowledge to establish a 100% correct watermark”.

Apache Flink 1.20 defines the same two clocks independently. “Event time is the time that each individual event occurred on its producing device”. “Processing time refers to the system time of the machine that is executing the respective operation”. And “A Watermark(t) declares that event time has reached time t in that stream”. A window that does not say which clock it counts on has not been specified.

Then the text. “Normalize the same way” is not an instruction until it names a form. Unicode Standard Annex #15 defines four. NFD is canonical decomposition. NFC is canonical decomposition followed by canonical composition. NFKD and NFKC are the compatibility versions of each. The payoff is in the annex’s summary: “When implementations keep strings in a normalized form, they can be assured that equivalent strings have a unique binary representation.” And: “Two equivalent strings will have precisely the same normalized form.” The same visible text held in two different forms is two different code point sequences. Two different code point sequences are two different vocabulary lookups.

Applying a form does not settle it either. The W3C warns, in its string-matching character model, that “Many users are surprised to find that two identical-looking strings—including those that have had a specific Unicode normalization form applied—might not in fact use the same underlying Unicode code points.” Its recommendation is still explicit: “Content authors SHOULD use Unicode Normalization Form C (NFC) wherever possible for content.” Choose a form, record it with the vocabulary, apply it on both sides.

  • Scaler drift: training fits a mean on last year, while serving recomputes a rolling mean every hour.
  • Vocabulary mismatch: the offline tokenizer applies one of the four forms defined in Unicode Standard Annex #15 — NFD, NFC, NFKD, NFKC — and the mobile client applies another, or none. Identical-looking strings then arrive as different code point sequences and miss the vocabulary.
  • Window mismatch: training counts events over seven calendar days of event time, while serving uses 168 processing-time hours — and the skew between those two domains is, in the Dataflow Model’s words, “inherent and dynamically changing”.
  • Default mismatch: missing category maps to “unknown” offline but to the most common class online.
  • Reference mismatch: historical training joins a corrected merchant table, while serving reads a stale cache.

Feature logic is production code with statistical state

A feature transformation can be simple arithmetic, a time-window aggregation, a category vocabulary, a scaler, a tokenizer, or a learned embedding. These operations define what evidence the model sees.

Some transformations are stateless. Converting meters to kilometers always applies the same rule. Others learn parameters from data: means, quantiles, category frequencies, vocabularies.

Stateful transformations must respect training boundaries and carry their fitted state into evaluation and serving. Recomputing them independently creates leakage or skew. The scikit-learn documentation gives the definition plainly: “Data leakage occurs when information that would not be available at prediction time is used when building the model.”

Fit a data-dependent step on the whole dataset before the evaluation split and you do not shade the estimate. You manufacture it. Ambroise and McLachlan measured that in PNAS in 2002, on microarray gene-expression data. With gene selection performed on the whole leukemia set before cross-validation, “the leave-one-out error CV1IE is zero for only three selected genes” — a perfect classifier from three genes. Move the selection outside the cross-validation and the error rises to about 5%, by external 10-fold CV and by the .632+ bootstrap. On the colon data the same contrast runs 6.5% internal against roughly 15% external. Same data, same genes. Only the position of the selection changed.

scikit-learn reproduces the effect from nothing at all. Its page on common pitfalls builds 200 samples, 10,000 randomly generated features, and randomly assigned binary targets. With SelectKBest(k=25) fitted before the split, accuracy_score comes out at 0.76. Fitted after the split, it comes out at 0.5, which is what a coin does. The scikit-learn developers state the conclusion: “Using all the data to perform feature selection results in an accuracy score much higher than chance, even though our targets are completely random.”

This is not a niche failure. Kapoor and Narayanan, surveying leakage across machine-learning-based science in Patterns, found “17 fields where leakage has been found, collectively affecting 294 papers”. Their taxonomy names both of the failures above. [L1.2] is pre-processing on training and test set: “Using the entire dataset for any pre-processing steps, such as imputation or over/under sampling, results in leakage.” [L1.3] is feature selection on training and test set.

A feature pipeline should expose dependencies, types, time semantics, fitted artifacts, defaults, and version. Reuse is valuable only while the reused definition still matches the decision context.

Google’s TFX team put a price on one such gap. Comparing serving logs against training data on the same day, Google Play found features that were always missing from the logs but always present in training. An online A/B experiment followed. Removing the skew “improved the app install rate on the main landing page of the app store by 2%”. Two percent of a store front, from a mismatch that every column name agreed about.

A feature is a versioned computation over defined evidence, not merely a column with a convenient name.

Visual

Transformations differ by state and time dependence

The category determines how a transformation must be trained, versioned, and served. Five categories cover most of what a pipeline contains.

A pure stateless transform applies fixed logic to each value or record, independently. A fitted transform learns parameters — mean, bins, vocabulary, encoder state — from training data, and therefore carries a dataset version inside it. A historical aggregation summarizes events in a bounded window before a prediction cutoff, which makes it hostage to the clock that window is counted on. An external enrichment adds reference data or model outputs, each with its own version and availability. A learned representation produces embeddings or latent features through a separately trained model, and inherits every boundary that model was trained under.

Only the first is free. The other four each drag something along behind them.

FigureHierarchy · 5 levels
  • Pure stateless transform

    Applies fixed logic independently to each value or record.

    • Fitted transform

      Learns parameters such as mean, bins, vocabulary, or encoder state from training data.

      • Historical aggregation

        Summarizes events within a bounded window before a prediction cutoff.

        • External enrichment

          Adds reference data or model outputs with their own versions and availability.

          • Learned representation

            Produces embeddings or latent features through a separately trained model.

Every nontrivial feature should declare which state and time boundary determine its value.

Comparison

Notebook code, shared libraries, and declarative feature definitions

The best choice makes critical semantics reviewable and executable across environments.

A notebook transformation keeps feature logic beside one experiment. It is fast for exploration, difficult to test and reuse consistently, and it often hides fitted state and source assumptions. It is appropriate only before the feature becomes shared.

A shared code library has training and serving import the same implementation. It reduces duplicated logic and supports unit and property tests. It still needs data and time contracts, and it is most useful for complex language-specific transformations.

A declarative feature definition has a platform execute versioned feature metadata and transformations. It makes lineage and reuse easier to discover and can generate offline and online materializations. The cost is limited room for custom algorithms, and coupling to the platform. It earns its keep when many teams share common entities and windows.

That third column is not a category invented for a comparison table. Feast is a dated, documented instance of it. Tim Sell and Willem Pienaar announced it on the Google Cloud Blog on 19 January 2019: “Developed jointly by GO-JEK and Google Cloud, Feast aims to solve a set of common challenges facing machine learning engineering teams by becoming an open, extensible, unified platform for feature storage”. The consistency mechanism is the specific thing worth copying: “Feast provides consistency by managing and unifying the ingestion of data from batch and streaming sources, using Apache Beam, into both the feature warehouse and feature serving stores. Users can query features in the warehouse and the serving API using the same set of feature identifiers.” One ingestion, two materializations, one set of identifiers.

The project documentation describes Feast today as “an open-source feature store that helps teams operate production ML systems at scale by allowing them to define, manage, validate, and serve features for production AI/ML”. It also says what its point-in-time correct retrieval is for: “Avoid data leakage by generating point-in-time correct feature sets so data scientists can focus on feature engineering rather than debugging error-prone dataset joining logic.” A platform that generates the training join for you is a platform that can enforce the cutoff you would otherwise have to remember.

FigureComparison · 3 columns

Notebook transformation

Feature logic lives beside one experiment.

  • Fast for exploration
  • Difficult to test and reuse consistently
  • Often hides fitted state and source assumptions
  • Appropriate only before the feature becomes shared

Shared code library

Training and serving import the same implementation.

  • Reduces duplicated logic
  • Supports unit and property tests
  • Still needs data and time contracts
  • Useful for complex language-specific transformations

Declarative feature definition

A platform executes versioned feature metadata and transformations.

  • Makes lineage and reuse easier to discover
  • Can generate offline and online materializations
  • May limit custom algorithms or create platform coupling
  • Useful when many teams share common entities and windows

Key idea

Target-derived features require nested boundaries

Target encoding, frequency conditioned on labels, and supervised representation learning can leak outcomes if computed using the same row’s label. That failure has a name and a formal analysis behind it. The CatBoost paper, in 2018, opens its abstract by saying what ordered boosting and ordered target statistics were built for: “Both techniques were created to fight a prediction shift caused by a special kind of target leakage present in all currently existing implementations of gradient boosting algorithms.” Target statistics computed over the whole training set were not a stylistic preference to be corrected. They were the defect the algorithm was designed around.

Within training data, generate these values through out-of-fold or leave-one-out procedures appropriate to the method. Validation and test values must use mappings fitted only on training partitions. scikit-learn ships that protocol as the difference between two methods on one class. TargetEncoder.fit_transform “internally relies on a cross fitting scheme to prevent target information from leaking into the train-time representation”: “the training data is split into k folds (determined by the cv parameter) and each fold is encoded using the encodings learnt using the other k-1 folds”, with cv defaulting to 5. The plain fit method is the naive one, and the documentation says so rather than leaving it to be discovered: “The fit method does not use any cross fitting schemes and learns one encoding on the entire training set. It is discouraged to use this method because it can introduce data leakage as mentioned above.”

Time-dependent targets need temporal ordering as well. A category’s future outcome rate cannot be used for an earlier example, even when both rows sit in the training split. The INFORMS 2010 Data Mining Contest is the public demonstration of what happens when that boundary is left to the entrants. It ran on Kaggle, drew 894 registered participants from 27 countries and 147 submitted solutions, and asked for the direction of a stock price 60 minutes ahead. Kaufman and colleagues recount the outcome: “The surprising results were that about 30 participating groups achieved more than 0.9 AUC, with the best model surpassing 0.99 AUC.” KDnuggets reported the same at the time — “With almost 900 participants, the winning entry had AUC of 0.99”.

None of it was forecasting. The explanatory variables carried future information, reachable through a cointegrated second stock and a public Yahoo/Google Finance lookup. The organisers could not verify after the fact who had used it, so they published a second leaderboard beside the overall one: a “Not using future information ranking”. The remedy the same authors propose is structural rather than procedural — “learn-predict separation”. Kapoor and Narayanan file the failure as [L3.1] Temporal leakage: “When an ML model is used to make predictions about a future outcome of interest, the test set should not contain any data from a date before the training set.”

If a feature uses labels, its construction needs a stricter protocol than an ordinary input transformation — which is why fit and fit_transform are deliberately different methods.

Key takeaways