Skip to contents

Generates a synthetic version of a data.frame, with similar characteristics to the original. See Details for the algorithm used.

Usage

synthetic(
  data,
  model_expression = ranger(x = x, y = y),
  predict_expression = predict(model, data = xsynth)$predictions,
  missingness_expression = NULL,
  verbose = TRUE
)

Arguments

data

A data.frame of which to make a synthetic version.

model_expression

An R-expression to estimate a model. Defaults to ranger(x = x, y = y), which uses the fast implementation of random forests in ranger. The expression is evaluated in an environment containing objects x and y, where x is a data.frame with the predictor variables, and y is a vector of outcome values (see Details).

predict_expression

An R-expression to generate predicted values based on the model estimated by model_expression. Defaults to predict(model, data = xsynth)$predictions. This expression must return a vector of predicted values. The expression is evaluated in an environment containing objects model and xsynth, where model is the model estimated by model_expression, and xsynth is the data.frame of synthetic data used to predict the next column (see Details).

missingness_expression

Optional. An R-expression to impute missing values. Defaults to NULL, which means listwise deletion is used. The expression is evaluated in an environment containing the object data, as specified in the call to synthetic. It must return a data.frame with the same dimensions and column names as the original data. For example, use missingness_expression = missRanger::missRanger(data = data) for a fast implementation of the excellent 'missForest' single imputation technique.

verbose

Logical, Default: TRUE. Whether to show a progress bar while running the algorithm and provide informative messages.

Value

A data.frame with synthetic data, based on data.

Details

Based on the work by Nowok, Raab, and Dibben (2016), this function uses a simple algorithm to generate a synthetic dataset with similar characteristics to the original. The algorithm is as follows:

  1. Let x be the original data.frame, with columns 1:j

  2. Let xsynth be a synthetic data.frame, with columns 1:j

  3. Column 1 of xsynth is a bootstrapped version of column 1 of x

  4. Using model_expression, a predictive model is built for column c, for c along 2:j, with c predicted from columns 1:(c-1) of the original data.

  5. Using predict_expression, columns 1:(c-1) of the synthetic data are used to predict synthetic values for column c.

Variables are thus imputed in order of occurrence in the data.frame. To impute in a different order, reorder the data.

Note that, for data synthesis to work properly, it is essential that the class of variables is defined correctly. The default algorithm ranger supports numeric, integer, and factor types. Other types of variables should be converted to one of these types, or users can use a custom model_expression and predict_expressio when calling synthetic.

Note that for data synthesis to work properly, it is essential that the class of variables is defined correctly. The default algorithm ranger supports numeric, integer, factor, and logical data. Other types of variables should be converted to one of these types.

Users can provide use a custom model_expression and predict_expression to use a different algorithm when calling synthetic.

As demonstrated in the example, users could call lm as a model_expression to use linear regression, which preserves linear marginal relationships but can give rise to values out of range of the original data. Or users could call sample as a predict_expression to bootstrap each variable, a very quick solution that maintains univariate distributions but loses all marginal relationships. These examples are not exhaustive, and users can even create custom functions.

References

Nowok, B., Raab, G.M and Dibben, C. (2016). synthpop: Bespoke creation of synthetic data in R. Journal of Statistical Software, 74(11), 1-26. doi:10.18637/jss.v074.i11 .

Examples

if (FALSE) {
# Example using the iris dataset and default ranger algorithm
iris_syn <- synthetic(iris)

# Example using lm as prediction algorithm (only works for numeric variables)
# note that, within the model_expression, a new data.frame is created because
# lm() requires a separate data argument:
dat <- iris[, 1:4]
synthetic(dat,
          model_expression = lm(.outcome ~ .,
                                data = data.frame(.outcome = y,
                                xsynth)),
          predict_expression = predict(model, newdata = xsynth))
}
# Example using bootstrapping:
synthetic(iris,
          model_expression = NULL,
          predict_expression = sample(y, size = length(y), replace = TRUE))
#> 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |==============                                                        |  20%
  |                                                                            
  |============================                                          |  40%
  |                                                                            
  |==========================================                            |  60%
  |                                                                            
  |========================================================              |  80%
  |                                                                            
  |======================================================================| 100%
#>     Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
#> 1            4.4         3.8          3.9         0.4     setosa
#> 2            6.1         2.7          5.0         0.2 versicolor
#> 3            5.4         2.9          1.6         1.8     setosa
#> 4            5.6         3.3          1.5         2.3 versicolor
#> 5            4.4         2.8          4.5         0.2     setosa
#> 6            5.9         3.2          1.4         1.3 versicolor
#> 7            4.9         3.0          1.4         1.3 versicolor
#> 8            6.5         3.1          3.6         1.9  virginica
#> 9            5.4         3.0          4.9         0.2 versicolor
#> 10           5.1         3.5          4.9         0.2     setosa
#> 11           5.6         2.7          1.5         2.2     setosa
#> 12           6.4         3.0          1.5         1.8 versicolor
#> 13           5.6         2.7          1.5         1.4 versicolor
#> 14           5.6         3.3          4.0         1.6 versicolor
#> 15           4.8         2.5          4.2         1.6  virginica
#> 16           5.0         3.1          4.2         1.3     setosa
#> 17           7.3         2.8          4.2         2.4  virginica
#> 18           5.8         3.0          1.3         2.1  virginica
#> 19           6.1         3.2          4.1         0.2 versicolor
#> 20           5.2         3.2          1.5         0.2     setosa
#> 21           4.6         2.8          1.7         0.3 versicolor
#> 22           6.4         3.4          4.5         2.1     setosa
#> 23           4.9         3.4          3.5         2.3  virginica
#> 24           7.2         3.1          5.1         2.5  virginica
#> 25           6.7         3.2          5.5         1.8     setosa
#> 26           7.6         3.1          1.7         0.4     setosa
#> 27           7.4         2.8          1.5         2.1     setosa
#> 28           4.9         3.3          1.3         1.7 versicolor
#> 29           5.6         2.2          4.5         1.9 versicolor
#> 30           6.3         4.1          1.9         1.0     setosa
#> 31           5.9         3.2          1.6         2.3 versicolor
#> 32           6.3         2.5          1.3         2.0 versicolor
#> 33           4.9         3.0          1.4         0.2  virginica
#> 34           6.1         2.6          4.9         1.4  virginica
#> 35           5.1         2.2          4.5         0.1  virginica
#> 36           4.8         3.2          5.1         1.0 versicolor
#> 37           5.0         3.1          5.7         1.5 versicolor
#> 38           4.5         3.6          3.0         1.8     setosa
#> 39           6.7         3.2          1.5         2.3  virginica
#> 40           5.8         3.0          4.9         1.1  virginica
#> 41           7.1         3.1          1.4         0.4     setosa
#> 42           5.0         2.7          1.9         1.3     setosa
#> 43           5.2         2.8          1.3         2.3  virginica
#> 44           4.3         3.0          3.3         0.1     setosa
#> 45           5.0         3.4          4.1         0.2     setosa
#> 46           5.8         2.7          4.4         0.3     setosa
#> 47           6.3         3.1          1.5         0.2  virginica
#> 48           5.4         3.5          5.8         2.4     setosa
#> 49           4.8         2.7          3.5         0.2     setosa
#> 50           5.7         3.4          1.4         0.3     setosa
#> 51           6.8         2.5          1.4         1.8 versicolor
#> 52           5.4         2.8          4.5         0.2 versicolor
#> 53           6.5         3.4          5.0         2.0 versicolor
#> 54           5.4         2.6          1.3         1.3  virginica
#> 55           5.0         3.9          5.0         1.5 versicolor
#> 56           4.6         2.8          4.6         2.0 versicolor
#> 57           5.5         3.4          5.6         1.3 versicolor
#> 58           6.3         3.4          1.4         1.0  virginica
#> 59           7.0         3.0          1.6         2.5 versicolor
#> 60           6.5         3.4          4.6         0.4     setosa
#> 61           6.7         3.2          3.3         1.3  virginica
#> 62           4.8         2.9          5.7         1.3  virginica
#> 63           6.9         2.9          1.6         0.2  virginica
#> 64           5.1         3.0          1.4         1.2 versicolor
#> 65           4.6         3.4          1.5         1.6  virginica
#> 66           5.0         3.8          5.0         1.8 versicolor
#> 67           5.5         2.9          1.2         1.3  virginica
#> 68           5.0         3.1          4.0         1.4  virginica
#> 69           6.3         3.4          1.5         1.2  virginica
#> 70           7.0         3.5          6.1         2.0     setosa
#> 71           6.1         2.9          4.6         1.8 versicolor
#> 72           6.7         3.0          1.9         2.0 versicolor
#> 73           4.8         3.2          1.4         1.0  virginica
#> 74           4.4         2.4          1.5         1.8     setosa
#> 75           4.7         3.2          5.6         1.7     setosa
#> 76           4.6         3.2          3.3         2.4 versicolor
#> 77           4.8         3.0          6.1         2.1  virginica
#> 78           4.4         3.0          1.4         2.1     setosa
#> 79           6.0         2.6          5.4         1.3     setosa
#> 80           4.5         3.4          1.5         1.9  virginica
#> 81           5.1         3.5          4.0         0.3 versicolor
#> 82           6.8         2.3          4.9         1.6 versicolor
#> 83           5.8         2.0          4.8         1.5  virginica
#> 84           5.0         2.8          5.1         2.5  virginica
#> 85           5.4         3.1          5.6         1.8     setosa
#> 86           4.9         2.8          6.1         1.0     setosa
#> 87           5.2         2.7          5.8         1.4  virginica
#> 88           6.1         3.4          1.6         1.4     setosa
#> 89           5.8         4.2          4.5         1.4     setosa
#> 90           6.9         3.2          4.4         1.6 versicolor
#> 91           6.7         3.2          1.4         1.4     setosa
#> 92           5.5         3.5          4.5         0.1  virginica
#> 93           7.3         3.1          6.0         1.1 versicolor
#> 94           7.9         3.5          3.0         0.2 versicolor
#> 95           5.8         2.7          6.4         1.9  virginica
#> 96           5.7         2.6          4.2         1.3 versicolor
#> 97           6.4         2.3          1.5         0.2     setosa
#> 98           6.7         3.1          4.8         2.4  virginica
#> 99           4.8         3.9          4.5         0.2 versicolor
#> 100          5.1         3.8          4.7         2.5 versicolor
#> 101          5.6         2.4          1.7         1.8 versicolor
#> 102          4.9         4.1          5.6         1.3     setosa
#> 103          6.3         3.9          1.0         1.4  virginica
#> 104          5.6         2.9          5.7         1.0     setosa
#> 105          5.2         3.3          1.4         1.3 versicolor
#> 106          5.3         3.1          5.7         0.2 versicolor
#> 107          6.0         4.4          1.3         0.2 versicolor
#> 108          4.6         2.7          4.7         1.9     setosa
#> 109          6.3         3.5          1.4         1.0 versicolor
#> 110          4.8         3.4          3.0         1.3 versicolor
#> 111          5.5         3.1          4.3         1.5  virginica
#> 112          5.1         3.3          1.1         2.2     setosa
#> 113          6.1         2.8          4.7         2.4  virginica
#> 114          6.1         2.7          5.2         2.5  virginica
#> 115          6.3         2.0          1.7         0.2     setosa
#> 116          4.8         2.8          4.8         2.0 versicolor
#> 117          4.7         3.0          4.7         1.3  virginica
#> 118          6.8         2.4          4.7         1.2 versicolor
#> 119          6.1         3.0          1.3         0.3  virginica
#> 120          6.9         3.0          1.5         1.3 versicolor
#> 121          6.7         4.2          1.4         1.5     setosa
#> 122          5.9         3.4          5.1         1.0 versicolor
#> 123          5.0         3.9          1.6         1.5 versicolor
#> 124          6.1         2.8          1.3         0.2  virginica
#> 125          6.3         2.0          4.0         1.3     setosa
#> 126          6.5         3.6          1.7         1.3     setosa
#> 127          7.2         3.2          3.7         1.4 versicolor
#> 128          6.3         2.5          1.6         0.2     setosa
#> 129          4.4         3.2          5.2         2.0     setosa
#> 130          5.2         3.2          4.5         1.5 versicolor
#> 131          5.7         3.4          4.7         0.2 versicolor
#> 132          6.7         3.0          5.6         2.3     setosa
#> 133          5.8         3.4          5.1         0.4  virginica
#> 134          4.9         2.9          3.9         0.2     setosa
#> 135          5.4         3.6          3.0         2.5 versicolor
#> 136          5.6         3.1          5.5         0.2     setosa
#> 137          5.2         3.3          3.6         1.4     setosa
#> 138          4.8         2.5          5.0         0.2 versicolor
#> 139          6.7         3.0          5.6         2.0     setosa
#> 140          6.4         3.1          4.9         1.9  virginica
#> 141          4.4         2.5          1.5         0.6  virginica
#> 142          6.4         3.1          4.6         0.1     setosa
#> 143          7.7         3.6          1.6         0.3     setosa
#> 144          6.5         3.0          1.7         1.9 versicolor
#> 145          5.2         2.7          1.4         1.9     setosa
#> 146          6.0         3.2          1.3         2.5  virginica
#> 147          6.0         2.8          1.4         0.2     setosa
#> 148          5.5         2.8          5.1         1.8     setosa
#> 149          4.5         3.2          5.1         2.0 versicolor
#> 150          5.0         2.9          1.5         1.9  virginica
if (FALSE) {
# Example with missing data, no imputation
iris_missings <- iris
for(i in 1:10){
  iris_missings[sample.int(nrow(iris_missings), 1, replace = TRUE),
                sample.int(ncol(iris_missings), 1, replace = TRUE)] <- NA
}
iris_miss_syn <- synthetic(iris_missings)

# Example with missing data, imputation by median/mode substitution
# First, define a simple function for median/mode substitution:
imp_fun <- function(x){
  if(is.data.frame(x)){
    return(data.frame(sapply(x, imp_fun)))
  } else {
    out <- x
    if(inherits(x, "numeric")){
      out[is.na(out)] <- median(x[!is.na(out)])
    } else {
      out[is.na(out)] <- names(sort(table(out), decreasing = TRUE))[1]
    }
    out
  }
}

# Then, call synthetic() with this function as missingness_expression:
iris_miss_syn <- synthetic(iris_missings,
                           missingness_expression = imp_fun(data))
}