Statistical Imputation for Missing Values in Machine Learning

Datasets may have missing values, and this can cause problems for many machine learning algorithms.

As such, it is good practice to identify and replace missing values for each column in your input data prior to modeling your prediction task. This is called missing data imputation, or imputing for short.

A popular approach for data imputation is to calculate a statistical value for each column (such as a mean) and replace all missing values for that column with the statistic. It is a popular approach because the statistic is easy to calculate using the training dataset and because it often results in good performance.

In this tutorial, you will discover how to use statistical imputation strategies for missing data in machine learning.

After completing this tutorial, you will know:

  • Missing values must be marked with NaN values and can be replaced with statistical measures to calculate the column of values.
  • How to load a CSV value with missing values and mark the missing values with NaN values and report the number and percentage of missing values for each column.
  • How to impute missing values with statistics as a data preparation method when evaluating models and when fitting a final model to make predictions on new data.

Kick-start your project with my new book Data Preparation for Machine Learning, including step-by-step tutorials and the Python source code files for all examples.

Let’s get started.

  • Updated Jun/2020: Changed the column used for prediction in examples.
Statistical Imputation for Missing Values in Machine Learning

Statistical Imputation for Missing Values in Machine Learning
Photo by Bernal Saborio, some rights reserved.

Tutorial Overview

This tutorial is divided into three parts; they are:

  1. Statistical Imputation
  2. Horse Colic Dataset
  3. Statistical Imputation With SimpleImputer
    1. SimpleImputer Data Transform
    2. SimpleImputer and Model Evaluation
    3. Comparing Different Imputed Statistics
    4. SimpleImputer Transform When Making a Prediction

Statistical Imputation

A dataset may have missing values.

These are rows of data where one or more values or columns in that row are not present. The values may be missing completely or they may be marked with a special character or value, such as a question mark “?”.

These values can be expressed in many ways. I’ve seen them show up as nothing at all […], an empty string […], the explicit string NULL or undefined or N/A or NaN, and the number 0, among others. No matter how they appear in your dataset, knowing what to expect and checking to make sure the data matches that expectation will reduce problems as you start to use the data.

— Page 10, Bad Data Handbook, 2012.

Values could be missing for many reasons, often specific to the problem domain, and might include reasons such as corrupt measurements or data unavailability.

They may occur for a number of reasons, such as malfunctioning measurement equipment, changes in experimental design during data collection, and collation of several similar but not identical datasets.

— Page 63, Data Mining: Practical Machine Learning Tools and Techniques, 2016.

Most machine learning algorithms require numeric input values, and a value to be present for each row and column in a dataset. As such, missing values can cause problems for machine learning algorithms.

As such, it is common to identify missing values in a dataset and replace them with a numeric value. This is called data imputing, or missing data imputation.

A simple and popular approach to data imputation involves using statistical methods to estimate a value for a column from those values that are present, then replace all missing values in the column with the calculated statistic.

It is simple because statistics are fast to calculate and it is popular because it often proves very effective.

Common statistics calculated include:

  • The column mean value.
  • The column median value.
  • The column mode value.
  • A constant value.

Now that we are familiar with statistical methods for missing value imputation, let’s take a look at a dataset with missing values.

Want to Get Started With Data Preparation?

Take my free 7-day email crash course now (with sample code).

Click to sign-up and also get a free PDF Ebook version of the course.

Horse Colic Dataset

The horse colic dataset describes medical characteristics of horses with colic and whether they lived or died.

There are 300 rows and 26 input variables with one output variable. It is a binary classification prediction task that involves predicting 1 if the horse lived and 2 if the horse died.

There are many fields we could select to predict in this dataset. In this case, we will predict whether the problem was surgical or not (column index 23), making it a binary classification problem.

The dataset has numerous missing values for many of the columns where each missing value is marked with a question mark character (“?”).

Below provides an example of rows from the dataset with marked missing values.

You can learn more about the dataset here:

No need to download the dataset as we will download it automatically in the worked examples.

Marking missing values with a NaN (not a number) value in a loaded dataset using Python is a best practice.

We can load the dataset using the read_csv() Pandas function and specify the “na_values” to load values of ‘?‘ as missing, marked with a NaN value.

Once loaded, we can review the loaded data to confirm that “?” values are marked as NaN.

We can then enumerate each column and report the number of rows with missing values for the column.

Tying this together, the complete example of loading and summarizing the dataset is listed below.

Running the example first loads the dataset and summarizes the first five rows.

We can see that the missing values that were marked with a “?” character have been replaced with NaN values.

Next, we can see the list of all columns in the dataset and the number and percentage of missing values.

We can see that some columns (e.g. column indexes 1 and 2) have no missing values and other columns (e.g. column indexes 15 and 21) have many or even a majority of missing values.

Now that we are familiar with the horse colic dataset that has missing values, let’s look at how we can use statistical imputation.

Statistical Imputation With SimpleImputer

The scikit-learn machine learning library provides the SimpleImputer class that supports statistical imputation.

In this section, we will explore how to effectively use the SimpleImputer class.

SimpleImputer Data Transform

The SimpleImputer is a data transform that is first configured based on the type of statistic to calculate for each column, e.g. mean.

Then the imputer is fit on a dataset to calculate the statistic for each column.

The fit imputer is then applied to a dataset to create a copy of the dataset with all missing values for each column replaced with a statistic value.

We can demonstrate its usage on the horse colic dataset and confirm it works by summarizing the total number of missing values in the dataset before and after the transform.

The complete example is listed below.

Running the example first loads the dataset and reports the total number of missing values in the dataset as 1,605.

The transform is configured, fit, and performed and the resulting new dataset has no missing values, confirming it was performed as we expected.

Each missing value was replaced with the mean value of its column.

SimpleImputer and Model Evaluation

It is a good practice to evaluate machine learning models on a dataset using k-fold cross-validation.

To correctly apply statistical missing data imputation and avoid data leakage, it is required that the statistics calculated for each column are calculated on the training dataset only, then applied to the train and test sets for each fold in the dataset.

If we are using resampling to select tuning parameter values or to estimate performance, the imputation should be incorporated within the resampling.

— Page 42, Applied Predictive Modeling, 2013.

This can be achieved by creating a modeling pipeline where the first step is the statistical imputation, then the second step is the model. This can be achieved using the Pipeline class.

For example, the Pipeline below uses a SimpleImputer with a ‘mean‘ strategy, followed by a random forest model.

We can evaluate the mean-imputed dataset and random forest modeling pipeline for the horse colic dataset with repeated 10-fold cross-validation.

The complete example is listed below.

Running the example correctly applies data imputation to each fold of the cross-validation procedure.

Note: Your results may vary given the stochastic nature of the algorithm or evaluation procedure, or differences in numerical precision. Consider running the example a few times and compare the average outcome.

The pipeline is evaluated using three repeats of 10-fold cross-validation and reports the mean classification accuracy on the dataset as about 86.3 percent, which is a good score.

Comparing Different Imputed Statistics

How do we know that using a ‘mean‘ statistical strategy is good or best for this dataset?

The answer is that we don’t and that it was chosen arbitrarily.

We can design an experiment to test each statistical strategy and discover what works best for this dataset, comparing the mean, median, mode (most frequent), and constant (0) strategies. The mean accuracy of each approach can then be compared.

The complete example is listed below.

Running the example evaluates each statistical imputation strategy on the horse colic dataset using repeated cross-validation.

Note: Your results may vary given the stochastic nature of the algorithm or evaluation procedure, or differences in numerical precision. Consider running the example a few times and compare the average outcome.

The mean accuracy of each strategy is reported along the way. The results suggest that using a constant value, e.g. 0, results in the best performance of about 88.1 percent, which is an outstanding result.

At the end of the run, a box and whisker plot is created for each set of results, allowing the distribution of results to be compared.

We can clearly see that the distribution of accuracy scores for the constant strategy is better than the other strategies.

Box and Whisker Plot of Statistical Imputation Strategies Applied to the Horse Colic Dataset

Box and Whisker Plot of Statistical Imputation Strategies Applied to the Horse Colic Dataset

SimpleImputer Transform When Making a Prediction

We may wish to create a final modeling pipeline with the constant imputation strategy and random forest algorithm, then make a prediction for new data.

This can be achieved by defining the pipeline and fitting it on all available data, then calling the predict() function passing new data in as an argument.

Importantly, the row of new data must mark any missing values using the NaN value.

The complete example is listed below.

Running the example fits the modeling pipeline on all available data.

A new row of data is defined with missing values marked with NaNs and a classification prediction is made.

Further Reading

This section provides more resources on the topic if you are looking to go deeper.

Related Tutorials

Books

APIs

Dataset

Summary

In this tutorial, you discovered how to use statistical imputation strategies for missing data in machine learning.

Specifically, you learned:

  • Missing values must be marked with NaN values and can be replaced with statistical measures to calculate the column of values.
  • How to load a CSV value with missing values and mark the missing values with NaN values and report the number and percentage of missing values for each column.
  • How to impute missing values with statistics as a data preparation method when evaluating models and when fitting a final model to make predictions on new data.

Do you have any questions?
Ask your questions in the comments below and I will do my best to answer.

Get a Handle on Modern Data Preparation!

Data Preparation for Machine Learning

Prepare Your Machine Learning Data in Minutes

...with just a few lines of python code

Discover how in my new Ebook:
Data Preparation for Machine Learning

It provides self-study tutorials with full working code on:
Feature Selection, RFE, Data Cleaning, Data Transforms, Scaling, Dimensionality Reduction, and much more...

Bring Modern Data Preparation Techniques to
Your Machine Learning Projects


See What's Inside

43 Responses to Statistical Imputation for Missing Values in Machine Learning

  1. Avatar
    Kapila May 15, 2020 at 2:08 pm #

    Hi,
    Trying to get the the missing values that are marked with a “?” be replaced with NaN values but I get an error message;

    ……….
    …………….

    KeyError: “None of [Int64Index([0], dtype=’int64′)] are in the [columns]”

    Please help.

    Thanks

    • Avatar
      Jason Brownlee May 15, 2020 at 3:55 pm #

      Sorry to hear that, are you able to confirm that your libraries are up to date, that you copied the code exactly and that you used the same dataset?

      More suggestions here:
      https://machinelearningmastery.com/faq/single-faq/why-does-the-code-in-the-tutorial-not-work-for-me

    • Avatar
      Abdül MERAL May 17, 2020 at 5:20 am #

      for i in range(dataframe.shape[1]):
      # count number of rows with missing values
      n_miss = dataframe.isnull().sum()[i] # change this line
      perc = n_miss / dataframe.shape[0] * 100
      print(‘> %d, Missing: %d (%.1f%%)’ % (i, n_miss, perc))

      • Avatar
        Abdül MERAL May 17, 2020 at 5:21 am #

        change this line like that,
        n_miss = dataframe.isnull().sum()[i] # change this line

  2. Avatar
    Stan May 17, 2020 at 12:05 am #

    Hi Jason, great post! Could you please give some intuition why constant imputation gives better results than median/mean imputation? From my point of view it’s unintuitive that so simple technique brings better score than statistical method fitting each individual feature.

    • Avatar
      Jason Brownlee May 17, 2020 at 6:37 am #

      We are not good at answering “why” questions in applied machine learning, we don’t have good theories.

      I can say something general like it depends on the specifics of the dataset and chosen model. We could dig into the model and figure out why a const results in better performance than a mean for this dataset. It might be a piece of work though.

  3. Avatar
    Jurij May 17, 2020 at 1:29 am #

    Great post!

  4. Avatar
    Joshua Mwaro May 19, 2020 at 12:50 pm #

    Good work!.
    So insightful,

    • Avatar
      Jason Brownlee May 19, 2020 at 1:27 pm #

      Thanks!

      • Avatar
        Sampathkumar R May 31, 2020 at 4:51 am #

        SimpleImputer class use a single strategy (eg., Mean, median,etc). How do impute missing values in different column with different strategies for a single dataset.in reality, each column may need different strategies to impute missing values.

  5. Avatar
    Puneet Rajput May 31, 2020 at 11:47 pm #

    Hi Jason!

    Nice Article!

    But I have one query. You are trying filling in 4 statistics for missing values and then validating it based on their respective accuracy. Don’t you think you should focus on finding whether the feature values are normal or non-normal in nature and then impute mean, median respectively. You are focusing on the end result and not doing the right way ? Please correct me if I am wrong.

    • Avatar
      Jason Brownlee June 1, 2020 at 6:23 am #

      Thanks!

      Perhaps. Grid searching different imputation strategies may be faster than understanding the distribution of each variable.

  6. Avatar
    Gopi June 29, 2020 at 9:18 pm #

    Hi Jason,
    As usual, Another Great post 🙂
    Can you give me some details on Model-Based imputation as well, like imputation using KNN or any other machine learning model instead of statistical imputation?
    If you can add pro, cons on why model rather statistical or vice-versa that will be more helpful.
    Thank you,
    Gopi

  7. Avatar
    Priya July 30, 2020 at 4:59 pm #

    Hi Sir,
    How can I fill missing values in time series data by taking the average of respective month? Do you have any tutorial regarding this in python?

  8. Avatar
    slim sidhom October 22, 2020 at 3:30 am #

    I think the whole idea behind fitting then transforming is indeed to avoid data leakage but this is mainly in the case of K-fold cross-validation. let me explain myself.
    In K-fold CV, you are each time fitting or training your model on K-1 folds or subsets then using the one left out to do the validation i.e. measuring the performance of the training model on the validation data.. Then an average of MSEs or MAEs is measured to get the overall model performance.
    Now if you have NaN in your dataset and you do imputation the following will happen:
    1- You take K-1 folds to train the data
    2- You use the left-out fold or subset for validation, but you are considering the left out information in the imputation of the training sets. For example, if mean is used as a strategy for imputation, then you have considered information from the left out dataset to fit your train data. that is by definition data leakage.

    I think the same applies to Leave-one-out-cross-validation.

    Now the question is ( and that is puzzling me, to be honest ): what about the imputation of NaN in the left-out dataset or the validation dataset? if we use the fit imputation from the training data to fill in NaN for the validation dataset, we are also leaking the data. Since my model will perform better since data from training has leaked to validation.
    This gets even worse for the test data if we use the imputer’s fitted to the training data.

    This is indeed what the exercise in Kaggle suggests though, so what do I miss here?

    • Avatar
      slim sidhom October 22, 2020 at 4:07 am #

      You are mentioning in the blog that the sin of preprocessing is for instance doing it before splitting data for validation and testing. Why because we’ll do leakage into training data. But the same happens in the other way round, no?

      Suppose I had the NaN values, what would be a better choice for not overperforming my model during testing?
      Now the same question with train data fitted imputer and using test data to fill NaN ( say with mean)?

      • Avatar
        Jason Brownlee October 22, 2020 at 6:50 am #

        Sorry, I don’t follow this question, can you please rephrase or elaborate?

    • Avatar
      Jason Brownlee October 22, 2020 at 6:48 am #

      Regardless of the procedure used to evaluate a model (train/test/val, kfold, etc.) a data transform like imputation is fit on the training dataset and applied to all datasets, such as train, test, val, new dataset, etc.

      A competition is different as you have the universe of input data available and you can break this rule.

  9. Avatar
    slim sidhom October 22, 2020 at 8:00 am #

    My point is that data leakage happens when unseen data or test data leaks into the training data. That would make the model over-performing.

    Then why is this not an issue in the other direction? data leaking from training to test, val etc…
    I have not seen any explanation for that? Why is this a rule at all? for me using training data to fit the test data will also make the performance of the model look good on test data.
    And why would I need to fit test data with train data at all? isn’t better to fit it with its own data?

  10. Avatar
    slim sidhom October 22, 2020 at 7:05 pm #

    Yes absolutely but in our case, the test data is “known” 🙂

    I think the whole idea is that in real life when we’re using new data to predict then we should use the training data for fitting NaN or preprocessing for two main reasons:

    1- If we have 1 single observation then preprocessing with it is impracticable
    2- usually, new data is “smaller” than train data so the strategy is best estimated with train data be it mean, median etc…plus we’ll be unfair with the model if we fit the test data with itself as this will fill in biased values for the NaN.

    What cofounded me is that in competitions, we have a large chunk of the data already available at hands which should in practice well estimate the mean, median etc…

    Thanks anyway for your feedback 🙂

  11. Avatar
    slim sidhom October 24, 2020 at 12:57 am #

    Wow that’s insane indeed 🙂
    thanks for the information!

  12. Avatar
    kooshyar January 31, 2021 at 11:20 am #

    Dear Jason

    can you please explain more about your box plot?

    How did you find that the constant imputation strategy according to the whisker plot? what is the empty circle in the plot is it an outlier or something else?

    why you always use random-forest classifier for evaluating imputation? is there any point for this algorithm rather than others?

    thanks

  13. Avatar
    AGGELOS PAPOUTSIS April 11, 2021 at 10:55 pm #

    Hi,

    when is the best time to handle missing data if you have categorical features in the dataset,?

    Before converting categorical features to numerical or after?

    • Avatar
      Jason Brownlee April 12, 2021 at 5:08 am #

      It does not matter really, as long as you don’t allow data leakage. Perhaps after ordinal encoding.

  14. Avatar
    AGGELOS PAPOUTSIS April 12, 2021 at 6:04 am #

    hi, thanks for the reply

    Encoding must perform also to training data to avoid data leakage? or data leakage is relevant to the other data preparation techniques?

    • Avatar
      Jason Brownlee April 13, 2021 at 5:59 am #

      Any data preparation must be fit on the training dataset only, then applied to the train and test sets to avoid data leakage. Or you can use a pipeline that will do this automatically.

  15. Avatar
    Leily July 23, 2021 at 3:30 am #

    Hi,
    Thanks for great post.

    Imputation of missing values should be done after removing outlier or before outlier treatment?

    • Avatar
      Jason Brownlee July 23, 2021 at 6:02 am #

      Perhaps after. Experiment and discover what works well or best for your specific dataset and models.

  16. Avatar
    rirhandzu September 29, 2021 at 1:04 pm #

    HI

    Thanks for the information.

    however, when i try to implement this on my datasets, when i get to the validation it returns an error ‘ValueError: Input contains NaN, infinity or a value too large for dtype(‘float64′).’ i think X/Y still have NAN values

    • Adrian Tam
      Adrian Tam September 30, 2021 at 1:25 am #

      Maybe your Y has some zero so X/Y gets NaN? Try to do some preprocessing to replace those values before you use it.

  17. Avatar
    said koussi January 28, 2023 at 4:19 am #

    Great Post, Thank you Jason

    • Avatar
      James Carmichael January 28, 2023 at 8:44 am #

      You are very welcome! We greatly appreciate your support!

  18. Avatar
    said koussi January 29, 2023 at 3:33 am #

    Jason is erroneus data can categorize as missing values, and how we can handle with it , Thank you in advance

  19. Avatar
    itsme February 25, 2023 at 1:25 pm #

    Why do we need to make the missing values for the new data as NaN when the model was trained on the missing values being t a constant 0?

Leave a Reply