mlpack

Imputation

mlpack provides functionality for replacing missing values in a dataset either with imputed values, user-specified values, or removing points from a dataset that have missing values.

Imputing or removing missing values is an important part of the data science pipeline, as mlpack’s machine learning techniques do not support learning on data that contain missing values.

🔗 Imputer

The Imputer class offers a simple interface to impute missing values into a single dimension of a data matrix.

🔗 Constructor

🔗 Impute()

Once an Imputer object is constructed, the Impute() function can be used to replace missing values.

Notes:

🔗 Imputation strategies

mlpack provides four imputation strategies that can be used with Imputer. It is also possible to write a fully custom imputation strategy.

🔗 MeanImputation

🔗 MedianImputation

🔗 ListwiseDeletion

🔗 CustomImputation<>

🔗 Custom imputation strategies

Implementing a fully custom imputation strategy requires a class with only one method, matching the following API:

class FullyCustomImputation
{
 public:
  // This function should replace values in `data` in row `dimension` that have
  // value `missingValue` with whatever the custom imputation strategy value
  // should be.
  //
  // If `columnMajor` is `false`, then values should be replaced in the column
  // `dimension` instead.
  //
  // Remember when checking for missing values that NaN != NaN---use
  // `std::isnan()` instead to check if `missingValue` is NaN, and to check if
  // values in `data` are NaN.
  //
  // `data` will be an Armadillo matrix type or equivalent type matching the
  // Armadillo API.
  template<typename MatType>
  void Impute(MatType& data,
              const typename MatType::elem_type missingValue,
              const size_t dimension,
              const bool columnMajor = true);
};

🔗 Simple examples

Replace all NaNs in dimension 2 of a random matrix with the mean in that dimension.

// Create a random matrix with integer values that are either 0, 1, or NaN.
arma::mat data = arma::randi<arma::mat>(10, 20, arma::distr_param(0, 2));
// Replace the value 2 with NaN.
data.replace(2, std::nan(""));

mlpack::Imputer<mlpack::MeanImputation> imputer;

std::cout << "Dimension 2 before imputation:" << std::endl;
std::cout << data.row(2);

imputer.Impute(data, std::nan(""), 2);

std::cout << "Dimension 2 after imputation:" << std::endl;
std::cout << data.row(2);

Replace the value 0.0 in dimension 3 of a random matrix with the median in that dimension.

// Create a random matrix with NaNs and random values in [0.5, 1].
arma::mat data(10, 20, arma::fill::randu);
// Replace anything below 0.5 with NaN.
data.transform([](double val) { return (val <= 0.5) ? std::nan("") : val; });

mlpack::Imputer<mlpack::MedianImputation> imputer;

std::cout << "Dimension 3 before imputation:" << std::endl;
std::cout << data.row(3);

imputer.Impute(data, std::nan(""), 3);

std::cout << "Dimension 3 after imputation:" << std::endl;
std::cout << data.row(3);

Remove any columns where dimension 4 contains a NaN value from a random matrix.

// Create a random matrix with values in [0, 1].  In dimension 4, any value less
// than 0.3 will be turned into a NaN.
arma::mat data(10, 1000, arma::fill::randu);
data.row(4).transform(
    [](double val) { return (val < 0.3) ? std::nan("") : val; });

mlpack::Imputer<mlpack::ListwiseDeletion> imputer;

std::cout << "Dataset contains " << data.n_cols << " points before removing "
    << "points that have NaN in dimension 4." << std::endl;

imputer.Impute(data, std::nan(""), 4);

std::cout << "Dataset contains " << data.n_cols << " points after removing "
    << "points that have NaN in dimension 4." << std::endl;

Replace the value 0.0 in dimension 0 of a random matrix with the value 2.5. Use a 32-bit floating point matrix as the data type.

// Create random matrix with values in [0, 5].
arma::fmat data = arma::randi<arma::fmat>(5, 20, arma::distr_param(0, 5));

mlpack::CustomImputation<> c(2.5); // Replace values with 2.5.
mlpack::Imputer<mlpack::CustomImputation<>> imputer(c);

std::cout << "Dimension 0 before imputation:" << std::endl;
std::cout << data.row(0);

imputer.Impute(data, 0.0, 0);

std::cout << "Dimension 0 after imputation:" << std::endl;
std::cout << data.row(0);