Model Development · Topic 2 of 5

Estimators, Transformers and Training Pipelines

Databricks ML Associate: tell Spark ML estimators from transformers, know what fit and transform return, and chain the stages in a training pipeline.

  • 5 min
  • Includes a diagram
In a nutshell
  • Transformers have transform() and learn nothing; estimators have fit() and return a model.
  • A fitted model is a transformer, so it is applied with transform().
  • A Pipeline is an estimator; its fit() returns a PipelineModel.

What it is

Spark ML builds every workflow from two kinds of stage. A transformer turns one DataFrame into another with transform(). An estimator learns something from data with fit() and returns a model, which is itself a transformer.

A Pipeline chains these stages in order. It is an estimator too: calling fit() on it runs every stage on the training data and returns a PipelineModel you apply to new data with transform().

Training DataFramePipelineestimatorfitPipelineModeltransformertransform on test dataPredictions

How it works

Estimators versus transformers

TransformerEstimator
Main methodtransform(df)fit(df)
ReturnsA new DataFrame with added columnsA fitted model (a transformer)
Learns from dataNoYes
ExamplesVectorAssembler, fitted models such as LogisticRegressionModelStringIndexer, OneHotEncoder, Imputer, StandardScaler, LogisticRegression, RandomForestClassifier

The rule of thumb: if a stage must look at the data to know what to do (category list, mean, scale, weights), it is an estimator. VectorAssembler only packs columns into one vector, so it needs nothing from the data and is a transformer.

Estimatorfit() returnsWhat it learned
StringIndexerStringIndexerModelThe category to index mapping
ImputerImputerModelThe mean, median or mode per column
StandardScalerStandardScalerModelColumn standard deviations (and means if centering)
LogisticRegressionLogisticRegressionModelCoefficients and intercept
PipelinePipelineModelEvery fitted stage in order

Building a training pipeline

Training pipeline: the training part of randomSplit passes through a StringIndexer estimator, a VectorAssembler transformer and a RandomForestRegressor estimator; Pipeline.fit returns a PipelineModel that transforms the test data with the same fitted stages. A typical pipeline splits the data, fits preprocessing and the model on the training part only, and scores the test part with the same fitted stages.

from pyspark.ml import Pipeline
from pyspark.ml.feature import StringIndexer, VectorAssembler
from pyspark.ml.regression import RandomForestRegressor
train_df, test_df = df.randomSplit([0.8, 0.2], seed=42)
idx = StringIndexer(inputCol="city", outputCol="city_idx", handleInvalid="keep")
vec = VectorAssembler(inputCols=["city_idx", "rooms"], outputCol="features")
rf = RandomForestRegressor(featuresCol="features", labelCol="price")
model = Pipeline(stages=[idx, vec, rf]).fit(train_df)

Then model.transform(test_df) adds a prediction column. The StringIndexer inside the PipelineModel uses the mapping learned from training data, so test rows are encoded the same way.

handleInvalid="keep" gives unseen categories their own index. The default is "error", which fails on a city that was not in the training data; "skip" drops those rows.

Stage order and common preprocessing

OrderStageWhy
1ImputerFill numeric nulls (mean, median or mode)
2StringIndexerTurn string categories into indexes
3OneHotEncoderTurn indexes into vectors, for linear models
4VectorAssemblerPack all features into one vector column
5StandardScalerScale the vector, for linear models with regularization
6Estimator (the model)Learn from the features column

Tree models in Spark can use the StringIndexer output directly, because the indexer marks the column as categorical. The tree's maxBins (default 32) must then be at least the number of categories in any categorical feature, or training fails.

Why a pipeline matters

Fitting each stage by hand on the full dataset leaks test information into training, for example an imputer mean that includes test rows. A pipeline fitted on train_df learns every statistic from training data only.

The fitted PipelineModel is one object, so you can log it with mlflow.spark.log_model or save it with model.write().overwrite().save(path). Scoring later reuses exactly the same preprocessing, with no copy of the feature code to keep in step.

The same idea exists in scikit-learn: sklearn.pipeline.Pipeline with fit() and predict(), used for single node models.

How the exam asks about this

  • "Which stage returns a model when fit is called?" Any estimator, such as StringIndexer or LogisticRegression.
  • "What does Pipeline.fit(train_df) return?" A PipelineModel, which is a transformer.
  • "Scoring fails because the test data contains a new category." Set handleInvalid to keep or skip on the StringIndexer.

What to remember for the exam

  • Transformers have transform() and learn nothing; estimators have fit() and return a model.
  • A fitted model is a transformer, so it is applied with transform().
  • A Pipeline is an estimator; its fit() returns a PipelineModel.
  • VectorAssembler is a transformer; StringIndexer, OneHotEncoder, Imputer and StandardScaler are estimators.
  • Fit the pipeline on training data only, then transform the test data.
  • StringIndexer handleInvalid defaults to error; keep and skip are the alternatives.
Watch out

Do not call fit() on a PipelineModel or transform() on an unfitted Pipeline. The Pipeline is fitted once; the PipelineModel it returns is what scores data.

Common mistakes

Calling VectorAssembler an estimator. It only combines columns into a vector and learns nothing from the data. It is a transformer and has no fit() step.

Fitting preprocessing on the whole dataset. An imputer or scaler fitted before the split learns from test rows. Split first, then fit the pipeline on the training part.

Forgetting new categories at scoring time. A StringIndexer with the default handleInvalid raises an error on unseen labels. Choose keep or skip when production data may contain new values.

Check yourself

  • Is StringIndexer an estimator or a transformer?

    An estimator, because it must read the data to learn the category to index mapping; fit() returns a StringIndexerModel.

  • What does calling fit on a Pipeline return?

    A PipelineModel, a transformer that holds every fitted stage and scores new data with transform().

  • Why fit the pipeline on training data only?

    So statistics such as imputer means and category mappings come only from training rows, which avoids leaking test information into the model.

Topic 2 of 5 in Model Development

Test yourself on Model Development

The full Databricks Machine Learning Associate question bank has 600 questions, with timed practice exams and an explanation for every answer.

This study guide is independent and is not affiliated with, endorsed by, or sponsored by Databricks. Vendor names, certification names and exam codes are trademarks of their respective owners and are used for identification only.