Author: Elena Albu
Date: 2025-05-24

# Using the missForestPredict package

#### Elena Albu

#### 2025-05-24

# Introduction

## What is this document?

The goal of this document is to highlight the functionality implemented in the package `missForestPredict` and to provide guidance for the usage of this package.

## Package information

The package `missForestPredict` implements the missing data imputation algorithm used in the R package `missForest` (Stekhoven and Bühlmann 2012) with adaptations for prediction settings. The function `missForest` is used to impute a (training) dataset with missing values and to learn imputations models that can be later used for imputing new observations. The function `missForestPredict` is used to impute one or multiple new observations (test set) using the models learned on the training data. The word “Predict” in the function name should not misguide the user. The function does not perform prediction of an outcome and is agnostic on whether the outcome variable for a prediction model is part of the training data or not; it will treat all columns of the provided data as variables to be imputed.

## Package functionality

Fast implementation

The imputation algorithm is based on random forests (Breiman 2001) as implemented in the `ranger` R package (Wright and Ziegler 2017). Ranger provides a fast implementation of random forests suitable for large datasets as well as high dimensional data.

Saved models and initialization

The missing values in each column are initialized with the mean/mode (or median/mode) of that variable derived on complete cases or a custom imputation scheme. Each variable is then imputed using the iterative algorithm of missForest (Stekhoven and Bühlmann 2012) until a stopping criterion is met. The algorithm supports all variable types (continuous and categorical with two or more levels) and uses a common stopping criterion for all variables. The initialization used for the training data and the random forest models for each iteration are saved and can be later used to impute new observations. Imputation initialization and models are by default “learned” also for variables with no missing values in the original (training) data. This allows for unfortunate situations in which new observations have different missing patterns than the one encountered in the training data (for example, because of accidental registration errors or because of unfortunate train / test split in which all missing values of a variable with low missingness fall in the test set).

Imputation of new observations

The models are applied iteratively to “predict” the missing values of each variable for the new observation, using the same number of iterations as used in the training data.

Convergence criteria

At each iteration the out-of-bag (OOB) error is calculated for each variable separately. To obtain a global error the OOB errors for all variables a weighted average is used, that can be controlled by the `var_weights` parameter. By default the weights are set to the proportion of missing values of each variable.

The normalized mean squared error is used for both continuous and categorical variables. For continuous variables, it is equivalent to \(1 - R^2\). For categorical variables, it is equivalent to \(1 - BSS\) (Brier Skill Score) (Brier et al. 1950).

More information on convergence criteria and error monitoring is provided in a separate vignette.

Support for dataframe and tibble

Both dataframe (`data.frame` class) and tibble (`tbl_df` class) are supported as input for the package functions. Currently matrix input is not supported.

## How to install

    install.packages("missForestPredict")

# How to use the package

## Data used for demonstration

Iris data The iris dataset in R base contains 4 continuous variables and one categorical variable with three categories for N = 150 flowers (Anderson 1935).

Diamonds data The diamonds dataset from `ggplot2` R package contains seven continuous variables and three categorical variables for N = 53940 diamonds (Wickham 2016).

## Imputation of training and test set

After installing the package you can load it in your R sessions with:

    library(missForestPredict)

We will load the iris dataset and split it in a training set (100 observations) and a test set (50 observations).

    data(iris)

    N <- nrow(iris)
    n_test <- floor(N/3)

    set.seed(2022)
    id_test <- sample(1:N, n_test)

    iris_train <- iris[-id_test,]
    iris_test <- iris[id_test,]

We produce 10% random missing values on each column in both the training and the test set.

    set.seed(2022)
    iris_train_miss <- produce_NA(iris_train, proportion = 0.1)
    iris_test_miss <- produce_NA(iris_test, proportion = 0.1)

    head(iris_train_miss)
    #>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
    #> 2           4.9          NA          1.4         0.2    <NA>
    #> 4           4.6         3.1          1.5         0.2  setosa
    #> 5           5.0         3.6          1.4          NA    <NA>
    #> 8           5.0         3.4          1.5         0.2  setosa
    #> 9           4.4         2.9          1.4         0.2  setosa
    #> 10           NA         3.1          1.5         0.1  setosa
    head(iris_test_miss)
    #>     Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
    #> 55           6.5         2.8          4.6         1.5 versicolor
    #> 75           6.4         2.9           NA         1.3 versicolor
    #> 6            5.4         3.9          1.7         0.4     setosa
    #> 123          7.7         2.8          6.7         2.0  virginica
    #> 14           4.3          NA          1.1          NA     setosa
    #> 7            4.6         3.4          1.4         0.3       <NA>

We will impute the training set and learn the random forest imputation models at the same time using the function `missForest`. To later use the models learned on a training set for imputation of new observations, `save_models` needs to be set to `TRUE`.

By default feedback on the number of iterations and the error monitoring is provided. You can set `verbose = FALSE` to silence this output. More information on error monitoring is provided in a separate vignette.

Please note that in all following examples we set the `ranger` parameter `num.threads` to 2. If you are running the code on a machine with more cores and you are willing to use them for running the code, you can remove this parameter completely.

    set.seed(2022)
    iris_train_imp_object <- missForestPredict::missForest(iris_train_miss,
                                                           save_models = TRUE,
                                                           num.threads = 2)
    #> Imputation sequence (missing proportion):  Sepal.Length (0.1) Sepal.Width (0.1) Petal.Length (0.1) Petal.Width (0.1) Species (0.1)
    #>   missForest iteration 1 in progress...done!
    #>     OOB errors MSE:            0.1805847667, 0.1135372435, 0.1997070656, 0.047025497, 0.029239605
    #>     OOB errors NMSE:           0.262503766, 0.6142107892, 0.0669550744, 0.0791675034, 0.1317734423
    #>     diff. convergence measure: 0.7690778849
    #>     time:                      0.285 seconds
    #>
    #>   missForest iteration 2 in progress...done!
    #>     OOB errors MSE:            0.1460403012, 0.1070329333, 0.0857073641, 0.0419331912, 0.0298745317
    #>     OOB errors NMSE:           0.2122888312, 0.5790239428, 0.0287348017, 0.0705945981, 0.1346348516
    #>     diff. convergence measure: 0.02586671
    #>     time:                      0.281 seconds
    #>
    #>   missForest iteration 3 in progress...done!
    #>     OOB errors MSE:            0.1395804541, 0.104410824, 0.0879523224, 0.0428531843, 0.0299527533
    #>     OOB errors NMSE:           0.2028985918, 0.564838925, 0.0294874609, 0.0721434079, 0.134987371
    #>     diff. convergence measure: 0.0041842538
    #>     time:                      0.273 seconds
    #>
    #>   missForest iteration 4 in progress...done!
    #>     OOB errors MSE:            0.1366279674, 0.1038477271, 0.0880044275, 0.0421867272, 0.0298089327
    #>     OOB errors NMSE:           0.1986067631, 0.5617926987, 0.02950493, 0.0710214262, 0.1343392181
    #>     diff. convergence measure: 0.0018181441
    #>     time:                      0.288 seconds
    #>
    #>   missForest iteration 5 in progress...done!
    #>     OOB errors MSE:            0.1407598198, 0.1017087681, 0.0848800684, 0.041837028, 0.0291735319
    #>     OOB errors NMSE:           0.2046129553, 0.5502214144, 0.0284574373, 0.070432707, 0.1314756722
    #>     diff. convergence measure: 0.00201297
    #>     time:                      0.288 seconds
    #>
    #>   missForest iteration 6 in progress...done!
    #>     OOB errors MSE:            0.139002653, 0.1038229081, 0.087047712, 0.0434566684, 0.0306075067
    #>     OOB errors NMSE:           0.2020586818, 0.5616584332, 0.0291841754, 0.0731593744, 0.1379381327
    #>     diff. convergence measure: -0.0037597223
    #>     time:                      0.281 seconds

The imputed training set can be found by extracting `ximp` dataframe from the object.

    iris_train_imp <- iris_train_imp_object$ximp

    head(iris_train_imp)
    #>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
    #> 2      4.900000    3.304453          1.4    0.200000  setosa
    #> 4      4.600000    3.100000          1.5    0.200000  setosa
    #> 5      5.000000    3.600000          1.4    0.255089  setosa
    #> 8      5.000000    3.400000          1.5    0.200000  setosa
    #> 9      4.400000    2.900000          1.4    0.200000  setosa
    #> 10     4.770257    3.100000          1.5    0.100000  setosa

We will further impute the test set using the learned imputation models. The function `missForestPredict` will:

- initialize the missing values in each variable with the initialization “learned” from the training set (mean/mode)

- imperatively predict the missing values of each variable using the learned random forest models for each iteration

    iris_test_imp <- missForestPredict::missForestPredict(iris_train_imp_object,
                                                          newdata = iris_test_miss)

    head(iris_test_imp)
    #>     Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
    #> 55           6.5    2.800000     4.600000   1.5000000 versicolor
    #> 75           6.4    2.900000     4.434043   1.3000000 versicolor
    #> 6            5.4    3.900000     1.700000   0.4000000     setosa
    #> 123          7.7    2.800000     6.700000   2.0000000  virginica
    #> 14           4.3    3.144955     1.100000   0.2080633     setosa
    #> 7            4.6    3.400000     1.400000   0.3000000     setosa

## Imputation of a single new observation

`missForestPredict` can impute a new observation with missing values. The new observation has to be provided as a dataframe with one row and with named columns (the column names have to correspond to the column names of the training set).

    single_observation <- iris_test_miss[1,]
    single_observation[1,2] <- NA

    print(single_observation)
    #>    Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
    #> 55          6.5          NA          4.6         1.5 versicolor

    single_observation_imp <- missForestPredict::missForestPredict(iris_train_imp_object,
                                                                   newdata = single_observation)

    print(single_observation_imp)
    #>    Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
    #> 55          6.5    3.010257          4.6         1.5 versicolor

`missForestPredict` package can impute observations with new missingness patterns not present in the training data as well as variables with no missingness (complete) in training data. The initialization and the random forest imputation models are “learned” for all variables in the dataset, regardless of the amount of missingness.

## Predict without storing the imputed matrix

The function `missForest` returns both the imputed training dataframe as well as the imputation models.

    str(iris_train_imp_object, max.level = 1)
    #> List of 11
    #>  $ ximp                     :'data.frame':   100 obs. of  5 variables:
    #>  $ init                     :List of 5
    #>  $ initialization           : chr "mean/mode"
    #>  $ impute_sequence          : chr [1:5] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width" ...
    #>  $ maxiter                  : num 10
    #>  $ save_models              : logi TRUE
    #>  $ models                   :List of 6
    #>  $ return_integer_as_integer: logi FALSE
    #>  $ integer_columns          : chr(0)
    #>  $ predictor_matrix         : num [1:5, 1:5] 0 1 1 1 1 1 0 1 1 1 ...
    #>   ..- attr(*, "dimnames")=List of 2
    #>  $ OOB_err                  :'data.frame':   55 obs. of  7 variables:
    #>  - attr(*, "class")= chr "missForest"

The imputed training data is though not necessary for imputing the test set. To avoid storing further these data in the object, `ximp` can be set to NULL.

    iris_train_imp <- iris_train_imp_object$ximp
    iris_train_imp_object$ximp <- NULL

    iris_test_imp <- missForestPredict::missForestPredict(iris_train_imp_object,
                                                          newdata = iris_test_miss)

    head(iris_test_imp)
    #>     Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
    #> 55           6.5    2.800000     4.600000   1.5000000 versicolor
    #> 75           6.4    2.900000     4.434043   1.3000000 versicolor
    #> 6            5.4    3.900000     1.700000   0.4000000     setosa
    #> 123          7.7    2.800000     6.700000   2.0000000  virginica
    #> 14           4.3    3.144955     1.100000   0.2080633     setosa
    #> 7            4.6    3.400000     1.400000   0.3000000     setosa

In `ximp` is set to NULL by mistake, and the training set imputation is lost, it can be recovered without rerunning the algorithm. Imputing the training set with the function `missForestPredict` will give the same results as the initial results of `missForest` function because the same models are applied to the variables in the same order and for the same number of iterations.

    set.seed(2022)
    iris_train_imp_object <- missForestPredict::missForest(iris_train_miss,
                                                           save_models = TRUE,
                                                           num.threads = 2)
    #> Imputation sequence (missing proportion):  Sepal.Length (0.1) Sepal.Width (0.1) Petal.Length (0.1) Petal.Width (0.1) Species (0.1)
    #>   missForest iteration 1 in progress...done!
    #>     OOB errors MSE:            0.1805847667, 0.1135372435, 0.1997070656, 0.047025497, 0.029239605
    #>     OOB errors NMSE:           0.262503766, 0.6142107892, 0.0669550744, 0.0791675034, 0.1317734423
    #>     diff. convergence measure: 0.7690778849
    #>     time:                      0.301 seconds
    #>
    #>   missForest iteration 2 in progress...done!
    #>     OOB errors MSE:            0.1460403012, 0.1070329333, 0.0857073641, 0.0419331912, 0.0298745317
    #>     OOB errors NMSE:           0.2122888312, 0.5790239428, 0.0287348017, 0.0705945981, 0.1346348516
    #>     diff. convergence measure: 0.02586671
    #>     time:                      0.288 seconds
    #>
    #>   missForest iteration 3 in progress...done!
    #>     OOB errors MSE:            0.1395804541, 0.104410824, 0.0879523224, 0.0428531843, 0.0299527533
    #>     OOB errors NMSE:           0.2028985918, 0.564838925, 0.0294874609, 0.0721434079, 0.134987371
    #>     diff. convergence measure: 0.0041842538
    #>     time:                      0.283 seconds
    #>
    #>   missForest iteration 4 in progress...done!
    #>     OOB errors MSE:            0.1366279674, 0.1038477271, 0.0880044275, 0.0421867272, 0.0298089327
    #>     OOB errors NMSE:           0.1986067631, 0.5617926987, 0.02950493, 0.0710214262, 0.1343392181
    #>     diff. convergence measure: 0.0018181441
    #>     time:                      0.305 seconds
    #>
    #>   missForest iteration 5 in progress...done!
    #>     OOB errors MSE:            0.1407598198, 0.1017087681, 0.0848800684, 0.041837028, 0.0291735319
    #>     OOB errors NMSE:           0.2046129553, 0.5502214144, 0.0284574373, 0.070432707, 0.1314756722
    #>     diff. convergence measure: 0.00201297
    #>     time:                      0.302 seconds
    #>
    #>   missForest iteration 6 in progress...done!
    #>     OOB errors MSE:            0.139002653, 0.1038229081, 0.087047712, 0.0434566684, 0.0306075067
    #>     OOB errors NMSE:           0.2020586818, 0.5616584332, 0.0291841754, 0.0731593744, 0.1379381327
    #>     diff. convergence measure: -0.0037597223
    #>     time:                      0.294 seconds

    # store imputed dataframe
    iris_train_imp <- iris_train_imp_object$ximp
    iris_train_imp_object$ximp <- NULL

    # re-impute the same dataframe using missForestPredict
    iris_train_imp_2 <-  missForestPredict::missForestPredict(iris_train_imp_object,
                                                          newdata = iris_train_miss)

    identical(iris_train_imp, iris_train_imp_2)
    #> [1] TRUE

## Impute larger datasets by adapting `num.trees`

Although `missForestPredict` benefits of the improved computation time of `ranger` package, larger dataset can still prove time consuming to impute.

We will load the diamonds dataset, which contains more than 50000 observations and produce 30% missing values on each variable.

    library(ggplot2)

    data(diamonds)

    # split train / test
    N <- nrow(diamonds)
    n_test <- floor(N/3)

    set.seed(2022)
    id_test <- sample(1:N, n_test)

    diamonds_train <- diamonds[-id_test,]
    diamonds_test <- diamonds[id_test,]

    diamonds_train_miss <- produce_NA(diamonds_train, proportion = 0.1)
    diamonds_test_miss <- produce_NA(diamonds_test, proportion = 0.1)

    head(diamonds_train_miss)
    #> # A tibble: 6 × 10
    #>   carat cut       color clarity depth table price     x     y     z
    #>   <dbl> <ord>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
    #> 1  0.23 Ideal     <NA>  SI2      61.5    55   326  3.95  3.98  2.43
    #> 2  0.21 Premium   E     <NA>     59.8    61   326  3.89  3.84  2.31
    #> 3  0.23 Good      E     VS1      56.9    65   327  4.05  4.07  2.31
    #> 4  0.29 Premium   I     <NA>     62.4    58   334  4.2   4.23  2.63
    #> 5  0.24 Very Good J     VVS2     62.8    57   336  3.94  3.96  2.48
    #> 6  0.24 Very Good I     VVS1     NA      57   336  3.95  3.98  2.47
    head(diamonds_test_miss)
    #> # A tibble: 6 × 10
    #>   carat cut     color clarity depth table price     x     y     z
    #>   <dbl> <ord>   <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
    #> 1  0.33 Ideal   <NA>  <NA>     61.9  57    1312  4.43  4.46  2.75
    #> 2  0.3  Ideal   H     SI1      62.6  53.1   475 NA     4.3   2.69
    #> 3  0.4  Ideal   I     VVS2     62    56    1240  4.74  4.77  2.95
    #> 4  0.73 Ideal   F     SI1      61.7  55    3249  5.79  5.82  3.58
    #> 5  0.3  Premium E     SI2      NA    58     540  4.31  4.28  2.66
    #> 6  1.01 Fair    F     VS2      64.8  NA    4791  6.3   6.25  4.07

The function `missForest` supports additional parameters to be passed to the `ranger` function. By default, the default values of `ranger` are used (e.g. the number of trees in the forest is 500). This can be overridden by passing `num.trees = 100`. Using less trees will prove to be computationally more efficient.

    set.seed(2022)
    diamonds_train_imp_object <- missForestPredict::missForest(diamonds_train_miss,
                                                               save_models = TRUE,
                                                               num.trees = 100,
                                                               num.threads = 2)
    #> Imputation sequence (missing proportion):  carat (0.1) cut (0.1) color (0.1) clarity (0.1) depth (0.1) table (0.1) price (0.1) x (0.1) y (0.1) z (0.1)
    #>   missForest iteration 1 in progress...done!
    #>     OOB errors MSE:            0.0007338342, 0.0756201708, 0.0983353857, 0.0682046934, 0.3742855572, 2.3480994763, 353521.1326901, 0.0059528819, 0.0243759479, 0.0074019455
    #>     OOB errors NMSE:           0.0032808592, 0.5280526776, 0.8201770738, 0.6632169458, 0.1820594083, 0.4736191439, 0.0221086495, 0.0047223274, 0.0193938761, 0.0153499845
    #>     diff. convergence measure: 0.7268019054
    #>     time:                      107.678 seconds
    #>
    #>   missForest iteration 2 in progress...done!
    #>     OOB errors MSE:            0.0003549404, 0.0635885383, 0.0885320477, 0.060165493, 0.1830502699, 2.2666920511, 320190.366257525, 0.0053688166, 0.0239160654, 0.0074422459
    #>     OOB errors NMSE:           0.0015868838, 0.4440362611, 0.7384112581, 0.5850444083, 0.0890390323, 0.4571990069, 0.0200241964, 0.0042589977, 0.0190279865, 0.0154335586
    #>     diff. convergence measure: 0.0357919356
    #>     time:                      109.748 seconds
    #>
    #>   missForest iteration 3 in progress...done!
    #>     OOB errors MSE:            0.0003637618, 0.0630538867, 0.0880169629, 0.0599197869, 0.1801280271, 2.2724371023, 321883.152457855, 0.005585046, 0.0239479753, 0.0072607665
    #>     OOB errors NMSE:           0.0016263227, 0.44030281, 0.734115136, 0.5826551818, 0.0876175995, 0.458357802, 0.0201300606, 0.004430529, 0.0190533746, 0.0150572107
    #>     diff. convergence measure: 0.0010715563
    #>     time:                      117.637 seconds
    #>
    #>   missForest iteration 4 in progress...done!
    #>     OOB errors MSE:            0.0003708465, 0.0630076346, 0.0879840478, 0.0599656933, 0.1884792854, 2.2704007194, 313360.68667099, 0.0048603539, 0.0235264121, 0.0072311817
    #>     OOB errors NMSE:           0.0016579972, 0.4399798336, 0.7338406042, 0.5831015722, 0.0916798058, 0.4579470571, 0.0195970791, 0.0038556422, 0.0187179724, 0.0149958585
    #>     diff. convergence measure: -0.0002027395
    #>     time:                      115.166 seconds

    # impute test set
    diamonds_train_imp_object$ximp <- NULL
    diamonds_test_imp <- missForestPredict::missForestPredict(diamonds_train_imp_object,
                                                              newdata = diamonds_test_miss)

    head(diamonds_test_imp)
    #> # A tibble: 6 × 10
    #>   carat cut     color clarity depth table price     x     y     z
    #>   <dbl> <ord>   <ord> <ord>   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
    #> 1  0.33 Ideal   E     IF       61.9  57    1312  4.43  4.46  2.75
    #> 2  0.3  Ideal   H     SI1      62.6  53.1   475  4.29  4.3   2.69
    #> 3  0.4  Ideal   I     VVS2     62    56    1240  4.74  4.77  2.95
    #> 4  0.73 Ideal   F     SI1      61.7  55    3249  5.79  5.82  3.58
    #> 5  0.3  Premium E     SI2      62.0  58     540  4.31  4.28  2.66
    #> 6  1.01 Fair    F     VS2      64.8  56.8  4791  6.3   6.25  4.07

Alternatively, the `maxiter` parameter can be set to a lower number (the default is 10) or other `ranger` parameters can be adapted. Note that not all parameters to ranger function are supported. Parameters that should be adapted in function of the imputed variable (outcome for the ranger function) are not supported. Generic parameters that can be applied to all variables are supported (like: `num.trees, mtry, min.node.size, max.depth, replace,` …), as well as `class.weights` for factor variables.

## Custom initialization

The parameter `initialization` supports three values: `mean/mode`, `median/mode` and `custom`. The default is mean/mode, which will initialize each variable with the mean (for continuous variables) or mode (for categorical variables) calculated based on the complete observations on that variable.

When `custom` is used, a complete dataframe is expected in `x_init`. For example, the imputations of another imputation method can be used as initialization. When `custom` is used in `missForest` function, an initialization dataframe has to be passed to the `missForestPredict` function later on too.

We will exemplify this with an initialization using linear models on the `iris` dataset. Let’s assume that variables `Sepal.Width` and `Species` are known to be never missing. We will regress the other variables on these two variables and save the linear models to be applied on the test set afterwards.

    data(iris)

    # split train / test
    N <- nrow(iris)
    n_test <- floor(N/3)

    set.seed(2022)
    id_test <- sample(1:N, n_test)

    iris_train <- iris[-id_test,]
    iris_test <- iris[id_test,]

    # produce missing values
    set.seed(2022)
    iris_train_miss <- produce_NA(iris_train, proportion = c(0.2, 0, 0.2, 0.2, 0))
    iris_test_miss <- produce_NA(iris_test, proportion = c(0.2, 0, 0.2, 0.2, 0))

    # build linear models for Sepal.Length, Petal.Width, Petal.Length using complete cases for each variable
    fit_1 <- lm(Sepal.Length ~ ., data = iris_train_miss[!is.na(iris_train_miss$Sepal.Length),
                                                         c("Sepal.Length", "Sepal.Width", "Species")])
    fit_2 <- lm(Petal.Width ~ ., data = iris_train_miss[!is.na(iris_train_miss$Petal.Width),
                                                        c("Petal.Width", "Sepal.Width", "Species")])
    fit_3 <- lm(Petal.Length ~ ., data = iris_train_miss[!is.na(iris_train_miss$Petal.Length),
                                                         c("Petal.Length", "Sepal.Width", "Species")])

    # impute training with predictions of linear model
    iris_train_init <- iris_train_miss
    iris_train_init$Sepal.Length[is.na(iris_train_init$Sepal.Length)] <-
      predict(fit_1, iris_train_init[is.na(iris_train_init$Sepal.Length), c("Sepal.Width", "Species")])
    iris_train_init$Petal.Width[is.na(iris_train_init$Petal.Width)] <-
      predict(fit_2, iris_train_init[is.na(iris_train_init$Petal.Width), c("Sepal.Width", "Species")])
    iris_train_init$Petal.Length[is.na(iris_train_init$Petal.Length)] <-
      predict(fit_3, iris_train_init[is.na(iris_train_init$Petal.Length), c("Sepal.Width", "Species")])

    # impute the training set using this initialization
    set.seed(2022)
    iris_train_imp_obj <- missForest(iris_train_miss,
                                     save_models = TRUE,
                                     initialization = "custom",
                                     x_init = iris_train_init,
                                     num.threads = 2)
    #> Imputation sequence (missing proportion):  Sepal.Width (0) Species (0) Sepal.Length (0.2) Petal.Length (0.2) Petal.Width (0.2)
    #>   missForest iteration 1 in progress...done!
    #>     OOB errors MSE:            0.0730876748, 0.0237252013, 0.1649041486, 0.1319607463, 0.0370457597
    #>     OOB errors NMSE:           0.4076187636, 0.1068061283, 0.2572005749, 0.0437137048, 0.064322709
    #>     diff. convergence measure: 0.8782543371
    #>     time:                      0.3 seconds
    #>
    #>   missForest iteration 2 in progress...done!
    #>     OOB errors MSE:            0.0930420062, 0.0268716766, 0.1460845335, 0.0890187057, 0.0354149427
    #>     OOB errors NMSE:           0.5189064727, 0.120970933, 0.2278476698, 0.0294885982, 0.0614911145
    #>     diff. convergence measure: 0.0154698687
    #>     time:                      0.289 seconds
    #>
    #>   missForest iteration 3 in progress...done!
    #>     OOB errors MSE:            0.0939954728, 0.0281705232, 0.1438479738, 0.0933701042, 0.0355682791
    #>     OOB errors NMSE:           0.5242240706, 0.1268180815, 0.2243593133, 0.0309300552, 0.0617573531
    #>     diff. convergence measure: 0.0005935536
    #>     time:                      0.289 seconds
    #>
    #>   missForest iteration 4 in progress...done!
    #>     OOB errors MSE:            0.091653229, 0.0265741491, 0.1455890675, 0.0908685708, 0.0352721908
    #>     OOB errors NMSE:           0.5111610949, 0.1196315236, 0.2270748928, 0.0301013899, 0.0612432538
    #>     diff. convergence measure: -0.000457605
    #>     time:                      0.281 seconds

    # build test set initialization using the linear models learned on training
    iris_test_init <- iris_test_miss
    iris_test_init$Sepal.Length[is.na(iris_test_init$Sepal.Length)] <-
      predict(fit_1, iris_test_init[is.na(iris_test_init$Sepal.Length), c("Sepal.Width", "Species")])
    iris_test_init$Petal.Width[is.na(iris_test_init$Petal.Width)] <-
      predict(fit_2, iris_test_init[is.na(iris_test_init$Petal.Width), c("Sepal.Width", "Species")])
    iris_test_init$Petal.Length[is.na(iris_test_init$Petal.Length)] <-
      predict(fit_3, iris_test_init[is.na(iris_test_init$Petal.Length), c("Sepal.Width", "Species")])

    # impute test set
    iris_test_imp <- missForestPredict(iris_train_imp_obj, newdata = iris_test_miss,
                                       x_init = iris_test_init)

    evaluate_imputation_error(iris_test_imp, iris_test_miss, iris_test)
    #>       variable        MSE       NMSE MER macro_F1 F1_score
    #> 1 Petal.Length 0.04259210 0.01659605  NA       NA       NA
    #> 2  Petal.Width 0.03852413 0.12053859  NA       NA       NA
    #> 3 Sepal.Length 0.07919212 0.16553537  NA       NA       NA
    #> 4  Sepal.Width 0.00000000 0.00000000  NA       NA       NA
    #> 5      Species         NA         NA   0        0        0
    evaluate_imputation_error(iris_test_init, iris_test_miss, iris_test)
    #>       variable        MSE       NMSE MER macro_F1 F1_score
    #> 1 Petal.Length 0.07731568 0.03012612  NA       NA       NA
    #> 2  Petal.Width 0.03350469 0.10483320  NA       NA       NA
    #> 3 Sepal.Length 0.10322009 0.21576106  NA       NA       NA
    #> 4  Sepal.Width 0.00000000 0.00000000  NA       NA       NA
    #> 5      Species         NA         NA   0        0        0

The errors (MSE, NMSE) for `Sepal.Length` and `Petal.Length` decreased compared to the initialization imputation. The missclasification error (MER) for `Species` is 0 (if a variable does not have missing values, the error returned will be 0).

Also keep in mind that `x_init` should be complete dataframe, if used. For example, if you would wish to impute only one variable using a different method as initialization, you cannot rely on the `missForest` function to do mean/mode initialization for the other variables. You would have to do it yourself before providing `x_init`.

## Using `predictor_matrix`

By default, missForest will create models for all variables in a dataframe and will use all other variables in the imputation of each variable. Controlling which variables to impute and which predictors to use for the imputation of each variable can be done using the parameter `predictor_matrix`. We illustrate three different cases:

- variables not imputed and not used as predictor

- variables not imputed but used as predictor

- variables imputed but not used as predictor

### Variables not imputed and not used as predictor

We consider the case when a date variable is kept in the dataframe for further reference. Such variable does not need imputation, nor can be used as predictor.

    data(iris)

    iris$Date_collected <- seq(Sys.Date() - nrow(iris) + 1, Sys.Date(), by="days")

    # split train / test
    N <- nrow(iris)
    n_test <- floor(N/3)

    set.seed(2022)
    id_test <- sample(1:N, n_test)

    iris_train <- iris[-id_test,]
    iris_test <- iris[id_test,]

    iris_train_miss <- produce_NA(iris_train, proportion = c(0.1,0.1,0.1,0.1,0.1,0))
    iris_test_miss <- produce_NA(iris_test, proportion = c(0.1,0.1,0.1,0.1,0.1,0))

    head(iris_train_miss)
    #>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species Date_collected
    #> 2           4.9         3.0          1.4         0.2  setosa     2024-12-27
    #> 4           4.6         3.1          1.5         0.2  setosa     2024-12-29
    #> 5           5.0         3.6          1.4         0.2  setosa     2024-12-30
    #> 8           5.0         3.4          1.5         0.2  setosa     2025-01-02
    #> 9            NA         2.9          1.4         0.2  setosa     2025-01-03
    #> 10          4.9          NA          1.5         0.1  setosa     2025-01-04

We will create a predictor matrix so that the `Date_collected` variable is not included in imputation and not included as predictor. We will initialize the predictor matrix using the function `create_predictor_matrix`. This is the default predictor matrix in which all variables are included for imputation and all other variables are used as predictors. The diagonal is 0 as one variable will not be used as predictor for its own imputation model.

    predictor_matrix <- create_predictor_matrix(iris_train_miss)

    print(predictor_matrix)
    #>                Sepal.Length Sepal.Width Petal.Length Petal.Width Species
    #> Sepal.Length              0           1            1           1       1
    #> Sepal.Width               1           0            1           1       1
    #> Petal.Length              1           1            0           1       1
    #> Petal.Width               1           1            1           0       1
    #> Species                   1           1            1           1       0
    #> Date_collected            1           1            1           1       1
    #>                Date_collected
    #> Sepal.Length                1
    #> Sepal.Width                 1
    #> Petal.Length                1
    #> Petal.Width                 1
    #> Species                     1
    #> Date_collected              0

The rows control the variables to be imputed and the columns control the variables as predictors. We will set all zeros for `Date_collected` both row-wise and column-wise.

    predictor_matrix["Date_collected",] <- 0
    predictor_matrix[,"Date_collected"] <- 0

    print(predictor_matrix)
    #>                Sepal.Length Sepal.Width Petal.Length Petal.Width Species
    #> Sepal.Length              0           1            1           1       1
    #> Sepal.Width               1           0            1           1       1
    #> Petal.Length              1           1            0           1       1
    #> Petal.Width               1           1            1           0       1
    #> Species                   1           1            1           1       0
    #> Date_collected            0           0            0           0       0
    #>                Date_collected
    #> Sepal.Length                0
    #> Sepal.Width                 0
    #> Petal.Length                0
    #> Petal.Width                 0
    #> Species                     0
    #> Date_collected              0

We will pass this matrix to the missForest function.

    set.seed(2022)
    iris_train_imp_object <- missForestPredict::missForest(iris_train_miss, save_models = TRUE,
                                                           predictor_matrix = predictor_matrix,
                                                           verbose = TRUE,
                                                           num.threads = 2)
    #> Variables skipped from imputation (missing proportion):  Date_collected (0)
    #> Imputation sequence (missing proportion):  Sepal.Length (0.1) Sepal.Width (0.1) Petal.Length (0.1) Petal.Width (0.1) Species (0.1)
    #>   missForest iteration 1 in progress...done!
    #>     OOB errors MSE:            0.1321317066, 0.10523858, 0.1718372789, 0.0474722515, 0.0286067706
    #>     OOB errors NMSE:           0.1908654972, 0.595706727, 0.0549534971, 0.0784297212, 0.1287781633
    #>     diff. convergence measure: 0.7902532788
    #>     time:                      0.296 seconds
    #>
    #>   missForest iteration 2 in progress...done!
    #>     OOB errors MSE:            0.1344608872, 0.1006473046, 0.0753625539, 0.0412766428, 0.0308036236
    #>     OOB errors NMSE:           0.1942300205, 0.5697176493, 0.0241009164, 0.0681938498, 0.1386676645
    #>     diff. convergence measure: 0.0107647011
    #>     time:                      0.315 seconds
    #>
    #>   missForest iteration 3 in progress...done!
    #>     OOB errors MSE:            0.1323754935, 0.09950605, 0.0745920893, 0.0402520421, 0.031050421
    #>     OOB errors NMSE:           0.1912176496, 0.5632575368, 0.0238545221, 0.0665010894, 0.1397786644
    #>     diff. convergence measure: 0.0020601276
    #>     time:                      0.438 seconds
    #>
    #>   missForest iteration 4 in progress...done!
    #>     OOB errors MSE:            0.1304893236, 0.0966658656, 0.0714839491, 0.0419741648, 0.0324202227
    #>     OOB errors NMSE:           0.1884930594, 0.5471805721, 0.02286054, 0.0693462378, 0.1459450558
    #>     diff. convergence measure: 0.0021567994
    #>     time:                      0.298 seconds
    #>
    #>   missForest iteration 5 in progress...done!
    #>     OOB errors MSE:            0.1266613438, 0.0962102903, 0.0721258547, 0.0425182377, 0.030750851
    #>     OOB errors NMSE:           0.1829635065, 0.544601772, 0.0230658212, 0.0702451101, 0.1384301001
    #>     diff. convergence measure: 0.0029038311
    #>     time:                      0.306 seconds
    #>
    #>   missForest iteration 6 in progress...done!
    #>     OOB errors MSE:            0.1319315666, 0.0989414657, 0.0712392766, 0.0435415902, 0.0304066648
    #>     OOB errors NMSE:           0.1905763931, 0.5600616876, 0.0227822938, 0.0719358083, 0.1368806881
    #>     diff. convergence measure: -0.0045861122
    #>     time:                      0.29 seconds

    iris_train_imp <- iris_train_imp_object$ximp

    head(iris_train_imp)
    #>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species Date_collected
    #> 2      4.900000    3.000000          1.4         0.2  setosa     2024-12-27
    #> 4      4.600000    3.100000          1.5         0.2  setosa     2024-12-29
    #> 5      5.000000    3.600000          1.4         0.2  setosa     2024-12-30
    #> 8      5.000000    3.400000          1.5         0.2  setosa     2025-01-02
    #> 9      4.691372    2.900000          1.4         0.2  setosa     2025-01-03
    #> 10     4.900000    3.105951          1.5         0.1  setosa     2025-01-04

    iris_test_imp <- missForestPredict::missForestPredict(iris_train_imp_object,
                                                          newdata = iris_test_miss)

    head(iris_test_imp)
    #>     Sepal.Length Sepal.Width Petal.Length Petal.Width    Species Date_collected
    #> 55      6.500000    2.800000     4.708793         1.5 versicolor     2025-02-18
    #> 75      5.855067    2.900000     4.300000         1.3 versicolor     2025-03-10
    #> 6       5.400000    3.599435     1.700000         0.4     setosa     2024-12-31
    #> 123     7.700000    3.328557     6.700000         2.0  virginica     2025-04-27
    #> 14      4.300000    3.000000     1.349165         0.1     setosa     2025-01-08
    #> 7       4.600000    3.400000     1.400000         0.3     setosa     2025-01-01

### Variables not imputed but used as predictor

We consider the case when we do not want to impute the variable `Sepal.Length` (for example, we do not plan to use it further in a prediction model), but we want to use it as predictor for the imputation of other variables.

    data(iris)

    # split train / test
    N <- nrow(iris)
    n_test <- floor(N/3)

    set.seed(2022)
    id_test <- sample(1:N, n_test)

    iris_train <- iris[-id_test,]
    iris_test <- iris[id_test,]

    iris_train_miss <- produce_NA(iris_train, proportion = 0.1)
    iris_test_miss <- produce_NA(iris_test, proportion = 0.1)

    head(iris_train_miss)
    #>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
    #> 2           4.9         3.0          1.4         0.2  setosa
    #> 4           4.6         3.1          1.5         0.2  setosa
    #> 5           5.0         3.6          1.4         0.2  setosa
    #> 8           5.0         3.4          1.5         0.2  setosa
    #> 9            NA         2.9          1.4         0.2  setosa
    #> 10          4.9          NA          1.5         0.1  setosa

We create the predictor matrix and set zeros row-wise. The row represents the variable to be imputed, the columns represent the predictors used in imputation. Setting zero row-wise means: do not use any of the predictors in imputing `Sepal.Length`. This situation is interpreted as: do not build imputation models for `Sepal.Length`.

    predictor_matrix <- create_predictor_matrix(iris_train_miss)
    predictor_matrix["Sepal.Length",] <- 0

    print(predictor_matrix)
    #>              Sepal.Length Sepal.Width Petal.Length Petal.Width Species
    #> Sepal.Length            0           0            0           0       0
    #> Sepal.Width             1           0            1           1       1
    #> Petal.Length            1           1            0           1       1
    #> Petal.Width             1           1            1           0       1
    #> Species                 1           1            1           1       0

    set.seed(2022)
    iris_train_imp_object <- missForestPredict::missForest(iris_train_miss, save_models = TRUE,
                                                           predictor_matrix = predictor_matrix,
                                                           verbose = TRUE,
                                                           num.threads = 2)
    #> Variables skipped from imputation (missing proportion):  Sepal.Length (0.1)
    #> Imputation sequence (missing proportion):  Sepal.Width (0.1) Petal.Length (0.1) Petal.Width (0.1) Species (0.1)
    #>   missForest iteration 1 in progress...done!
    #>     OOB errors MSE:            0.114959549, 0.1852976307, 0.0482054866, 0.0293069052
    #>     OOB errors NMSE:           0.6507326176, 0.0592581126, 0.0796411116, 0.1319299364
    #>     diff. convergence measure: 0.7696095555
    #>     time:                      0.23 seconds
    #>
    #>   missForest iteration 2 in progress...done!
    #>     OOB errors MSE:            0.1023949589, 0.072581124, 0.0421905216, 0.0294071898
    #>     OOB errors NMSE:           0.5796103087, 0.0232114162, 0.0697036847, 0.1323813845
    #>     diff. convergence measure: 0.029163746
    #>     time:                      0.238 seconds
    #>
    #>   missForest iteration 3 in progress...done!
    #>     OOB errors MSE:            0.1028834653, 0.0743708699, 0.0415134264, 0.0286170581
    #>     OOB errors NMSE:           0.5823755163, 0.0237837762, 0.0685850441, 0.1288244744
    #>     diff. convergence measure: 0.0003344958
    #>     time:                      0.235 seconds
    #>
    #>   missForest iteration 4 in progress...done!
    #>     OOB errors MSE:            0.1040739851, 0.0726249659, 0.0413376979, 0.0297091523
    #>     OOB errors NMSE:           0.5891144961, 0.0232254368, 0.0682947199, 0.1337407189
    #>     diff. convergence measure: -0.0027016402
    #>     time:                      0.228 seconds

    iris_train_imp <- iris_train_imp_object$ximp

    iris_test_imp <- missForestPredict::missForestPredict(iris_train_imp_object,
                                                          newdata = iris_test_miss)

    head(iris_test_imp)
    #>     Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
    #> 55      6.500000    2.800000     4.699944         1.5 versicolor
    #> 75      5.848889    2.900000     4.300000         1.3 versicolor
    #> 6       5.400000    3.606202     1.700000         0.4     setosa
    #> 123     7.700000    3.366053     6.700000         2.0  virginica
    #> 14      4.300000    3.000000     1.356646         0.1     setosa
    #> 7       4.600000    3.400000     1.400000         0.3     setosa

Models are not built for the variable `Sepal.Length`. Nevertheless this variable is initialized (with mean imputation), as it is used in other imputation models. As this variable is not imputed iteratively, its mean imputation might not be optimal for it being used as predictor. We recommend using this case only for complete variables in the training data and no expected missing values in future data.

    names(iris_train_imp_object$models[[1]])
    #> [1] "Sepal.Width"  "Petal.Length" "Petal.Width"  "Species"
    names(iris_train_imp_object$init)
    #> [1] "Sepal.Width"  "Petal.Length" "Petal.Width"  "Species"      "Sepal.Length"

### Variables imputed but not used as predictor

A third case is that when we want to impute a variable (based on all other variables), but we don’t want to use it as predictor for specific variables. For example we do not want to use the `Species` variable in the imputation of `Petal.Length` and `Petal.Width`.

    data(iris)

    # split train / test
    N <- nrow(iris)
    n_test <- floor(N/3)

    set.seed(2022)
    id_test <- sample(1:N, n_test)

    iris_train <- iris[-id_test,]
    iris_test <- iris[id_test,]

    iris_train_miss <- produce_NA(iris_train, proportion = 0.1)
    iris_test_miss <- produce_NA(iris_test, proportion = 0.1)

    head(iris_train_miss)
    #>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
    #> 2           4.9         3.0          1.4         0.2  setosa
    #> 4           4.6         3.1          1.5         0.2  setosa
    #> 5           5.0         3.6          1.4         0.2  setosa
    #> 8           5.0         3.4          1.5         0.2  setosa
    #> 9            NA         2.9          1.4         0.2  setosa
    #> 10          4.9          NA          1.5         0.1  setosa

    predictor_matrix <- create_predictor_matrix(iris_train_miss)
    predictor_matrix["Petal.Length","Species"] <- 0
    predictor_matrix["Petal.Width","Species"] <- 0

    print(predictor_matrix)
    #>              Sepal.Length Sepal.Width Petal.Length Petal.Width Species
    #> Sepal.Length            0           1            1           1       1
    #> Sepal.Width             1           0            1           1       1
    #> Petal.Length            1           1            0           1       0
    #> Petal.Width             1           1            1           0       0
    #> Species                 1           1            1           1       0

    set.seed(2022)
    iris_train_imp_object <- missForestPredict::missForest(iris_train_miss, save_models = TRUE,
                                                           predictor_matrix = predictor_matrix,
                                                           verbose = TRUE,
                                                           num.threads = 2)
    #> Imputation sequence (missing proportion):  Sepal.Length (0.1) Sepal.Width (0.1) Petal.Length (0.1) Petal.Width (0.1) Species (0.1)
    #>   missForest iteration 1 in progress...done!
    #>     OOB errors MSE:            0.1321317066, 0.10523858, 0.1995931534, 0.0633470777, 0.0325202974
    #>     OOB errors NMSE:           0.1908654972, 0.595706727, 0.0638298154, 0.104656794, 0.146395559
    #>     diff. convergence measure: 0.7797091215
    #>     time:                      0.26 seconds
    #>
    #>   missForest iteration 2 in progress...done!
    #>     OOB errors MSE:            0.1324720772, 0.0977323242, 0.1640616699, 0.0614127228, 0.0320254308
    #>     OOB errors NMSE:           0.1913571656, 0.5532172989, 0.0524668603, 0.1014610131, 0.1441678341
    #>     diff. convergence measure: 0.0117568441
    #>     time:                      0.266 seconds
    #>
    #>   missForest iteration 3 in progress...done!
    #>     OOB errors MSE:            0.1310844049, 0.0968943299, 0.1567967823, 0.0596113528, 0.0312776987
    #>     OOB errors NMSE:           0.18935266, 0.5484738023, 0.050143552, 0.0984849388, 0.1408017932
    #>     diff. convergence measure: 0.0030826851
    #>     time:                      0.256 seconds
    #>
    #>   missForest iteration 4 in progress...done!
    #>     OOB errors MSE:            0.1299819533, 0.0957681029, 0.1560184703, 0.0619265087, 0.0330657856
    #>     OOB errors NMSE:           0.1877601583, 0.5420987544, 0.0498946481, 0.1023098476, 0.1488511655
    #>     diff. convergence measure: -0.0007315655
    #>     time:                      0.257 seconds

    iris_train_imp <- iris_train_imp_object$ximp

    iris_test_imp <- missForestPredict::missForestPredict(iris_train_imp_object,
                                                          newdata = iris_test_miss)

    head(iris_test_imp)
    #>     Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
    #> 55       6.50000    2.800000     4.800350         1.5 versicolor
    #> 75       5.83872    2.900000     4.300000         1.3 versicolor
    #> 6        5.40000    3.598210     1.700000         0.4     setosa
    #> 123      7.70000    3.347473     6.700000         2.0  virginica
    #> 14       4.30000    3.000000     1.384145         0.1     setosa
    #> 7        4.60000    3.400000     1.400000         0.3     setosa

A predictor matrix can be checked using the function `check_predictor_matrix`. In case the predictor matrix is not valid, an error will be returned. For valid predictor matrices, human readable message about the imputation scheme will be printed.

    check_predictor_matrix(predictor_matrix, iris_train)
    #> GREAT! All checks passed succesfully.
    #> Variable Sepal.Length will be imputed using all other variables.
    #> Variable Sepal.Width will be imputed using all other variables.
    #> Variable Petal.Length will be imputed using Sepal.Length, Sepal.Width, Petal.Width.
    #> Variable Petal.Width will be imputed using Sepal.Length, Sepal.Width, Petal.Length.
    #> Variable Species will be imputed using all other variables.

### Impact of `proportion_usable_cases` on the predictor matrix

The default predictor matrix can be altered by the setting of `proportion_usable_cases`.

missForest initializes each variable and then builds models for each variable using the observed values of that variable as outcome of a random forest model. It then imputes the missing part of the variable using the learned models. Situations when a variable is mostly or completely missing for the observed part of another variable are suboptimal for learning the models, as the models will mostly rely on the initialization rather than on true values. Situations when a variable is missing for the missing part of another variable are suboptimal for the imputation (prediction) part as the predictions will rely on the initialization rather than on true values. By default `proportion_usable_cases` will filter the variables (as predictors) if they are completely missing for the observed or missing part of another variable.

As an example, we will make `Sepal.Length` and `Sepal.Width` in `iris` missing together and `Petal.Length` missing for the observed part of these variables. Checking the predictor matrix post imputation will reveal that these variables will not be used as predictor for each other because of the “sub-optimal” missingness pattern.

    data(iris)

    iris_mis <- iris
    iris_mis[1:50, "Sepal.Length"] <- NA
    iris_mis[1:50, "Sepal.Width"] <- NA
    iris_mis[51:150, "Petal.Length"] <- NA

    set.seed(2022)
    iris_train_imp_object <- missForestPredict::missForest(iris_mis, save_models = TRUE,
                                                           verbose = TRUE,
                                                           num.threads = 2)
    #> Imputation sequence (missing proportion):  Petal.Width (0) Species (0) Sepal.Length (0.333333333333333) Sepal.Width (0.333333333333333) Petal.Length (0.666666666666667)
    #>   missForest iteration 1 in progress...done!
    #>     OOB errors MSE:            0.0303866744, 0.0291728981, 0.3136621699, 0.07915427, 0.0292968842
    #>     OOB errors NMSE:           0.0526510879, 0.1312780414, 0.7211354019, 0.7221050762, 0.9912330568
    #>     diff. convergence measure: 0.1435733521
    #>     time:                      0.214 seconds
    #>
    #>   missForest iteration 2 in progress...done!
    #>     OOB errors MSE:            0.0308247402, 0.0304129278, 0.3141739419, 0.0789656118, 0.0294529379
    #>     OOB errors NMSE:           0.0534101258, 0.1368581751, 0.7223120083, 0.7203839936, 0.9965129902
    #>     diff. convergence measure: -0.0025038477
    #>     time:                      0.212 seconds

    print(iris_train_imp_object$predictor_matrix)
    #>              Sepal.Length Sepal.Width Petal.Length Petal.Width Species
    #> Sepal.Length            0           0            0           1       1
    #> Sepal.Width             0           0            0           1       1
    #> Petal.Length            0           0            0           1       1
    #> Petal.Width             1           1            1           0       1
    #> Species                 1           1            1           1       0

    check_predictor_matrix(iris_train_imp_object$predictor_matrix, iris_mis, verbose = TRUE)
    #> GREAT! All checks passed succesfully.
    #> Variable Sepal.Length will be imputed using Petal.Width, Species.
    #> Variable Sepal.Width will be imputed using Petal.Width, Species.
    #> Variable Petal.Length will be imputed using Petal.Width, Species.
    #> Variable Petal.Width will be imputed using all other variables.
    #> Variable Species will be imputed using all other variables.

# Final words

The package `missForestPredict` is based on the `missForest` package (Stekhoven and Bühlmann 2012) with additional functionality for convergence criteria, initialization, predictor specification and imputation of new observations.

Other imputation packages based on random forests are available in the R ecosystem, using iterative algorithms, like `missRanger` (Mayer and Mayer 2019), `mice` (Van Buuren, Oudshoorn, and Jong 2007), `CALIBERrfimpute` (Shah et al. 2021), `miceRanger` (Wilson 2020). These provide various extended functionality, but they do not support the imputation of new observations, with the exception of `miceRanger` (Wilson 2020) which, to our knowledge, is the only iterative algorithm that can impute new observations. Non-iterative algorithms are also available: the function `rfImpute` in the `randomForest` (Liaw and Wiener 2002) package requires presence of the outcome at imputation time, which makes it inadequate for prediction settings (where imputation for a single new observation for which the outcome is not yet know may be of interest); `caret` (Kuhn et al. 2008) implements bagged trees without iterations and will impute new observations for most missingness patterns; `imputeMissings` implements random forests non-iteratively but the initialization is not learned on the training set and will require a test set for initialization.

The R package `missForestPredict` uses an iterative algorithm and can impute a single new observation in (applied) prediction settings, even when the new observation exhibits a missingness pattern not encountered in the training set. It is therefore suitable for (applied) prediction settings.

# References

Anderson, Edgar. 1935. “The Irises of the Gaspe Peninsula.” Bull. Am. Iris Soc. 59: 2–5.
Breiman, L. 2001. “Random forests.” Machine Learning 45 (1): 5–32.
Brier, Glenn W et al. 1950. “Verification of Forecasts Expressed in Terms of Probability.” Monthly Weather Review 78 (1): 1–3.
Kuhn, Max et al. 2008. “Caret Package.” Journal of Statistical Software 28 (5): 1–26.
Liaw, Andy, and Matthew Wiener. 2002. “Classification and Regression by randomForest.” R News 2 (3): 18–22. https://CRAN.R-project.org/doc/Rnews/.
Mayer, Michael, and Maintainer Michael Mayer. 2019. “Package ‘missRanger’.” R Package.
Shah, Anoop, Jonathan Bartlett, Harry Hemingway, Owen Nicholas, Aroon Hingorani, Maintainer Anoop Shah, and TRUE BuildVignettes. 2021. “Package ‘CALIBERrfimpute’.”
Stekhoven, Daniel J, and Peter Bühlmann. 2012. “MissForest—Non-Parametric Missing Value Imputation for Mixed-Type Data.” Bioinformatics 28 (1): 112–18.
Van Buuren, Stef, CGM Oudshoorn, and Maintainer Roel de Jong. 2007. “The MICE Package.” URL Https://Www. Rdocumentation. Org/Packages/Mice/Versions/2.25.
Wickham, Hadley. 2016. Ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. https://ggplot2.tidyverse.org.
Wilson, S. 2020. “miceRanger: Multiple Imputation by Chained Equations with Random Forests. R Package Version 1.3. 5.”
Wright, Marvin N., and Andreas Ziegler. 2017. “Ranger: A Fast Implementation of Random Forests for High Dimensional Data in c++ and r.” Journal of Statistical Software 77 (1): 1–17. https://doi.org/10.18637/jss.v077.i01.