What you will be able to do
- Explain why filling in missing values with a column statistic usually keeps more information than dropping rows
- Compare mean, median and mode imputation, including which column types each one can handle
- Show from real numbers how one extreme value moves the mean but leaves the median almost unchanged
- Apply each strategy with scikit-learn SimpleImputer, PySpark na.fill with sf.median / sf.mode, and the Databricks AutoML imputers parameter
Key concept
Univariate (column-statistic) imputation — Each missing value is replaced with one number or category worked out from the values that are present in the same column: its mean, its median or its most frequent value. The choice of statistic decides which value goes in, and so how much the filled column still looks like the original data.
1.Drop or fill: why imputation exists
Real datasets have gaps, and most estimators can't work with them. You have two broad options. You can remove the rows (or columns) that have gaps, or you can fill each gap with a value inferred from the data you do have. The Databricks EDA tutorial lists both options in its data-cleaning step: handling missing values 'might involve replacing them with a specific value or removing the affected rows.' Before comparing mean, median and mode, it helps to see what dropping costs.
from pyspark.sql import Row
df = spark.createDataFrame([
Row(age=10, height=80.0, name="Alice"),
Row(age=5, height=None, name="Bob"),
Row(age=None, height=None, name="Tom"),
])
df.na.drop().show()
+---+------+-----+
|age|height| name|
+---+------+-----+
| 10| 80.0|Alice|
+---+------+-----+The scikit-learn guide makes the same point. Dropping incomplete rows 'comes at the price of losing data which may be valuable (even though incomplete)'. Its recommended alternative is to impute: work out the missing values from the known part of the data. The simplest way is univariate. For each column, compute one statistic from that column's present values and write it into every gap. scikit-learn's SimpleImputer offers three such statistics (mean, median and most frequent) plus a fixed constant. The rest of this lesson is about choosing among them.
Checkpoint 1 of 8· Check yourself
According to the scikit-learn guide, what is the main drawback of discarding rows or columns that contain missing values?
Discarding rows throws away the values that were present in them. Imputation avoids that by inferring the missing values from the known part of the data.
“this comes at the price of losing data which may be valuable (even though incomplete)”Source: scikit-learn.org
2.Mean vs median: what one extreme value does
Mean and median imputation both fill a numeric column with one central value, but they measure 'central' differently. The mean adds up all the present values and divides by how many there are. The median is the middle value once the values are sorted. In Databricks you can compute the median directly with the PySpark function sf.median, which 'Returns the median of the values in a group.' Here it is applied to earnings per course:
from pyspark.sql import functions as sf
df = spark.createDataFrame([
("Java", 2012, 20000), ("dotNET", 2012, 5000),
("Java", 2012, 22000), ("dotNET", 2012, 10000),
("dotNET", 2013, 48000), ("Java", 2013, 30000)],
schema=("course", "year", "earnings"))
df.groupby("course").agg(sf.median("earnings")).show()
+------+----------------+
|course|median(earnings)|
+------+----------------+
| Java| 22000.0|
|dotNET| 10000.0|
+------+----------------+(5000 + 10000 + 48000) / 3 = 21000. Mean imputation would fill in 21000, more than twice the median of 10000 and higher than two of the three real values. The single 48000 pulled the mean up, while the median is still the middle value. Java's values are closer together (20000, 22000, 30000), so its mean of 24000 is only a little above its median of 22000.
That reveal is the core of the mean-versus-median comparison. The mean uses the size of every value, so one large value moves it. The median depends only on which value is in the middle, so an extreme value at one end barely moves it. When a numeric column's values are bunched together, the two statistics come out close and either one is a reasonable fill. When a few values sit far out on one side, they can be well apart, and the median gives a fill value much nearer to most of the real data. One caveat: the documentation provided for this lesson has no written rule such as 'use the median for skewed data.' That guideline comes from the exam guide's framing. The arithmetic above shows why it holds.
The statistic is learned once and then reused. In scikit-learn, SimpleImputer computes each column's statistic when you call fit, then writes it into the gaps of whatever data you pass to transform. Fit on a first column of 1, NaN and 7 with strategy='mean', and the learned mean is 4. Every later NaN in that column becomes 4, even in rows that weren't present during fit.
Checkpoint 2 of 8· Check yourself
SimpleImputer(strategy='mean') is fit on a first column containing 1, NaN and 7. You then transform a new row whose first value is NaN. What value goes in?
SimpleImputer fills each column with a statistic computed from that column's present values at fit time: (1 + 7) / 2 = 4. The source's own example prints 4 for exactly this case.
“using the statistics (mean, median or most frequent) of each column in which the missing values are located”Source: scikit-learn.org
Checkpoint 3 of 8· Exam question
A retention analytics table includes `days_since_last_login`, a right-skewed numeric column where most customers log in within a week but a small group of dormant accounts push values into the thousands. About 6% of rows are missing this value, and the team wants to fill the gaps without letting the dormant-account outliers distort the typical customer's imputed value. Which imputation strategy best fits this column?
Correct answer: B — Impute the missing values with the column median, because the middle ranked login gap reflects a typical customer without being pulled toward the dormant-account extremes.
- A. The mean is pulled toward the extreme dormant-account values in a right-skewed distribution, so it overstates the typical customer's login gap rather than representing it accurately.
- B. The median is the correct choice here because it is robust to the extreme values from dormant accounts and represents the typical customer's login gap without distortion.
- C. The mode is intended for categorical or discrete data with a clearly repeated value; a continuous, mostly-unique login-gap column rarely has a meaningful most-frequent value to impute with.
- D. Dropping 6% of rows discards usable records and does not answer the question of which of the three imputation strategies fits a skewed numeric column.
3.Mode: the strategy that works on categories
Mean and median both need numbers you can add or sort. A column of country codes, product types or colours has neither, so the only statistic left is the most frequent value, the mode. This is the main contrast in the objective. Mean and median are choices for numeric columns. Mode is the statistic that also works on categorical ones. scikit-learn's SimpleImputer 'supports categorical data represented as string values or pandas categoricals when using the 'most_frequent' or 'constant' strategy'. Mean and median aren't on that list. Note the name: scikit-learn calls the mode strategy most_frequent, not 'mode'.
Checkpoint 4 of 8· Fill the gap
This DataFrame holds string categories with some NaNs. Which strategy value fills each gap with the column's most common category?
>>> imp = SimpleImputer(strategy=" ? ")
>>> print(imp.fit_transform(df))SimpleImputer's mode strategy is named most_frequent, and string or categorical data is only supported with most_frequent or constant. In the source example, column one's NaN becomes 'a' and column two's becomes 'y'.
Source: scikit-learn.orgOn the Databricks side, the mode is available as the PySpark function sf.mode and as the SQL mode aggregate. The SQL reference says it 'Returns the most frequent, not NULL, value of expr in a group'. The argument can be 'An expression of any type that can be compared', including strings. The 'not NULL' part matters for imputation. In the query below, NULL is the most common entry (three of seven), but mode ignores it and returns the most common real value. If a group contains only nulls, mode returns NULL, so there is nothing to fill with.
> SELECT mode(col) FROM VALUES (NULL), (1), (NULL), (2), (NULL), (3), (3) AS tab(col);
3Ties are a risk mean and median don't have. If two categories are equally common, the imputed value can differ from one run to the next, and so can a model trained on the result. Both the PySpark and SQL forms take a deterministic flag. In PySpark, deterministic: 'If there are multiple equally-frequent results then return the lowest (defaults to false).' Here it breaks a three-way tie by returning -10. The SQL reference adds one caveat: even with deterministic set to true, results can vary for some string collations, such as UTF8_LCASE.
from pyspark.sql import functions as sf
df = spark.createDataFrame([(-10,), (0,), (10,)], ["col"])
df.select(sf.mode("col", True)).show()Checkpoint 5 of 8· Exam question
An order table has a `shipping_method` column with categorical values such as "Standard", "Express", and "Overnight". About 8% of rows are missing this value before the team one-hot encodes the feature for a classification model. Which imputation approach is most appropriate for this nominal categorical column?
Correct answer: A — Impute the missing shipping method with the mode, because replacing gaps with the category customers choose most often keeps the feature a valid, existing label.
- A. The mode is correct for a nominal categorical column because it fills gaps with an actual, already-observed category rather than a value with no meaning for labels.
- B. A mean requires arithmetic on the values, and shipping method categories have no inherent numeric order, so averaging category codes produces a meaningless result.
- C. A median requires the values to be ordered, and shipping method labels are nominal with no natural ranking, so a middle value is not well defined.
- D. Introducing a new placeholder category is a different technique from imputing with mean, median, or mode, and it changes the feature's cardinality rather than reusing an observed category.
4.Applying a strategy: na.fill, constants and AutoML imputers
| Strategy | SimpleImputer strategy | Spark function to compute it | String / categorical columns? | Behaviour to watch |
|---|---|---|---|---|
| Mean | 'mean' | (average of the column) | Not supported | Every value counts towards it, so one extreme value moves it (dotNET: 21000 vs median 10000) |
| Median | 'median' | sf.median | Not supported | The middle value; an extreme value at one end barely moves it |
| Mode | 'most_frequent' | sf.mode | Supported | Ties are non-deterministic unless deterministic is set |
| Constant | 'constant' | (a literal passed to fillna) | Supported | Fills a fixed value of your choice, not one computed from the data |
In PySpark, DataFrame.fillna and DataFrameNaFunctions.fill (df.na.fill) are aliases. Both take a literal replacement value: 'The replacement value must be an int, float, boolean, or string.' So a median or mode fill in Spark takes two steps. First compute the statistic with sf.median or sf.mode, then pass the result to na.fill. To give different columns different strategies (say a median for a numeric column and a mode for a string column), pass a dict: 'If the value is a dict, then subset is ignored and value must be a mapping from column name (string) to replacement value.'
df = spark.createDataFrame([
(10, 80.5, "Alice"),
(5, None, "Bob"),
(None, None, "Tom")],
schema=["age", "height", "name"])
df.na.fill({'age': 50, 'name': 'unknown'}).show()
+---+------+-------+
|age|height| name|
+---+------+-------+
| 10| 80.5| Alice|
| 5| NULL| Bob|
| 50| NULL|unknown|
+---+------+-------+A single scalar is easier to write but less careful. In the fillna reference, df.na.fill(50) fills age and height but leaves the string name and boolean bool columns NULL, because 'Columns specified in subset that do not have matching data types are ignored.' A constant fill like this, or the EDA tutorial's df.fillna(0), is a different kind of choice from mean, median or mode. The tutorial describes it as 'A common way to treat NaN or Null values is to replace them with 0 for easier mathematical processing', but the 0 doesn't come from the column's own values.
Checkpoint 6 of 8· Check yourself
A DataFrame has columns age (int), height (float), name (string) and bool (boolean). After df.na.fill(50), name and bool still contain NULLs. Why?
The integer 50 matches only the numeric columns. Spark silently skips the others, so you need a per-column dict (or a separate string or boolean fill) to fill them.
“Columns specified in subset that do not have matching data types are ignored.”Source: docs.databricks.com
Databricks AutoML exposes the same three choices as a training option. The imputers parameter of databricks.automl.classify and regress maps column names to a strategy, and as a string 'the value must be one of “mean”, “median”, or “most_frequent”.' For a fixed value, use a dictionary with strategy constant and a fill_value. If you leave a column out, 'AutoML selects a default strategy based on column type and content', the same type-driven choice this lesson has been making by hand. Specifying a non-default method has a side effect: AutoML then skips semantic type detection.
Checkpoint 7 of 8· Match them up
Match each AutoML imputers setting for a column to what happens
Tap a term, then the definition that fits it.
AutoML accepts mean, median or most_frequent as strings, takes a constant via a dictionary, and chooses its own default for any column you don't configure.
“If no imputation strategy is provided for a column, AutoML selects a default strategy based on column type and content.”Source: docs.databricks.com
Checkpoint 8 of 8· Exam question
A quality-control dataset tracks `part_weight_grams` for a manufactured component. Histograms show the distribution is approximately symmetric and bell-shaped, with no extreme outliers, and 3% of measurements are missing due to a sensor glitch. Which imputation strategy is the most defensible default for this column?
Correct answer: A — Impute the missing weights with the column mean, because a roughly symmetric distribution with no outliers lets the average represent the typical part weight accurately.
- A. The mean is appropriate here because a symmetric, outlier-free distribution means the average and the typical value coincide, so mean imputation does not introduce the bias it would on skewed data.
- B. The median is a safer default only when skew or outliers are present; on a symmetric outlier-free distribution it offers no advantage over the mean and is not the best-fit choice.
- C. The mode fits categorical or discrete data with a clearly repeated value, not a continuous physical measurement where most recorded weights are distinct.
- D. A fixed specification value ignores the actual observed distribution of part weights and is not one of the three statistics the scenario is asking to compare.
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.Dropping rows with missing values is the safe, lossless default; na.drop() only removes rows that are mostly empty.Why is that wrong?
By default, na.drop() removes every row that has any null or NaN. That also throws away the real values in those rows, which is the cost imputation avoids.
Covered in Drop or fill: why imputation exists
2.Mean or median imputation can be applied to a string or categorical column, and scikit-learn's mode strategy is called 'mode'.Why is that wrong?
SimpleImputer supports string and categorical data only with most_frequent (the mode) or constant. The strategy name is most_frequent.
Covered in Mode: the strategy that works on categories
3.Mode imputation always gives the same fill value for the same data.Why is that wrong?
When two values are equally frequent, Databricks mode returns either one unless deterministic is set to true. Even then, some string collations can still vary.
Covered in Mode: the strategy that works on categories
4.df.na.fill(value) with one scalar fills every column of the DataFrame.Why is that wrong?
Columns whose type doesn't match the replacement value are silently skipped. To fill numeric and string columns with different statistics, pass a dict of column name to value.
Covered in Applying a strategy: na.fill, constants and AutoML imputers
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.
“Handling missing values, which might involve replacing them with a specific value or removing the affected rows.”
↩︎ Drop or fill: why imputation exists“A common way to treat NaN or Null values is to replace them with 0 for easier mathematical processing.”
↩︎ Applying a strategy: na.fill, constants and AutoML imputers - 2.
“Returns a new DataFrame omitting rows with null or NaN values.”
↩︎ Drop or fill: why imputation exists“Returns a new DataFrame omitting rows with null or NaN values.”
↩︎ Exam trap 1 - 3.https://scikit-learn.org/stable/modules/impute.htmlSecondary source
“this comes at the price of losing data which may be valuable (even though incomplete)”
↩︎ Drop or fill: why imputation exists“using the statistics (mean, median or most frequent) of each column in which the missing values are located”
↩︎ Mean vs median: what one extreme value does“supports categorical data represented as string values or pandas categoricals when using the 'most_frequent' or 'constant' strategy”
↩︎ Mode: the strategy that works on categories“imputes values in the i-th feature dimension using only non-missing values in that feature dimension”
↩︎ Key concept“supports categorical data represented as string values or pandas categoricals when using the 'most_frequent' or 'constant' strategy”
↩︎ Exam trap 2 - 4.
“Returns the median of the values in a group.”
↩︎ Mean vs median: what one extreme value does - 5.
“Returns the most frequent, not NULL, value of expr in a group.”
↩︎ Mode: the strategy that works on categories“An expression of any type that can be compared.”
↩︎ Mode: the strategy that works on categories“The result is non-deterministic if there is a tie for the most frequent value.”
↩︎ Exam trap 3“The function returns either 1 or 2, but not 3”
↩︎ Prediction - 6.
“If there are multiple equally-frequent results then return the lowest (defaults to false).”
↩︎ Mode: the strategy that works on categories - 7.
“If the value is a dict, then subset is ignored and value must be a mapping from column name (string) to replacement value.”
↩︎ Applying a strategy: na.fill, constants and AutoML imputers“The replacement value must be an int, float, boolean, or string.”
↩︎ Applying a strategy: na.fill, constants and AutoML imputers“DataFrame.fillna and DataFrameNaFunctions.fill are aliases of each other.”
↩︎ Applying a strategy: na.fill, constants and AutoML imputers“Columns specified in subset that do not have matching data types are ignored.”
↩︎ Exam trap 4“Columns specified in subset that do not have matching data types are ignored.”
↩︎ Checkpoint - 8.
“If specified as a string, the value must be one of “mean”, “median”, or “most_frequent”.”
↩︎ Applying a strategy: na.fill, constants and AutoML imputers“If you specify a non-default imputation method, AutoML does not perform semantic type detection.”
↩︎ Applying a strategy: na.fill, constants and AutoML imputers“If no imputation strategy is provided for a column, AutoML selects a default strategy based on column type and content.”
↩︎ Checkpoint