R语言缺失值插补之simputation包

2022-11-15 10:49:08 浏览数 (2)

R语言中有很多插补缺失值的R包,但是这些R包的使用语法都不一样,不利于学习和记忆。

simputation包旨在简化缺失值插补的流程,提供了统一的使用语法,提供多种常见的插补缺失值的方法,可以和管道符%>%连用,非常值得学习。

这个包和之前介绍的缺失值探索的R包naniar搭配使用效果非常棒,包的作者也经常互相cue,一个用于探索,一个用于插补,而且是tidy风格的,风格统一,非常推荐大家学习!

naniar介绍:R语言缺失值探索的强大R包:naniar

simputation这个包提供了很多了插补缺失值的方法,很多方法我也没有使用过,今天学习一下。目前支持以下插补方法:

  • 基于模型的方法
    • 线性回归
    • 稳健线性回归
    • 岭回归/弹性网络/lasso回归
    • CART模型(决策树)
    • 随机森林
  • 多元插补
    • 基于最大期望值的方法
    • missForest
  • Donor imputation (including various donor pool specifications)
    • K最近邻法
    • sequential hotdeck (LOCF, NOCB)
    • random hotdeck
    • Predictive mean matching
  • 其他
    • median imputation
    • Proxy imputation: 使用其他列的值或使用简单的转换得到的值.
    • Apply trained models for imputation purposes.

安装R包

代码语言:javascript复制
install.packages('simputation')

此包需要很多依赖包,默认不会安装依赖包,可以通过以下代码全部安装:

代码语言:javascript复制
install.packages('simputation', dependencies = T)

基本使用方法

代码语言:javascript复制
impute_<model>(data, formula, [model-specific options])

model是使用的方法,目前支持以下方法:

  • impute_rlm: robust linear model
  • impute_en: ridge/elasticnet/lasso
  • impute_cart: CART
  • impute_rf: random forest
  • impute_rhd: random hot deck
  • impute_shd: sequential hot deck
  • impute_knn: k nearest neighbours
  • impute_mf: missForest
  • impute_em: mv-normal
  • impute_const: 用一个固定值插补
  • impute_lm: linear regression
  • impute_pmm: Hot-deck imputation
  • impute_median: 均值插补
  • impute_proxy: 自定义公式插补,可以用均值等

data是需要插补的数据框,输出数据和输入数据结构一样,只不过缺失值被插补了。

formula指定需要插补的列。

[model-specific options]是根据所选模型不同有不同的参数。

示例

使用鸢尾花数据集,先把其中的一些值变为缺失值。

代码语言:javascript复制
dat <- iris
dat[1:3, 1] <- dat[3:7, 2] <- dat[8:10, 5] <- NA
head(dat, 10)
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1            NA         3.5          1.4         0.2  setosa
## 2            NA         3.0          1.4         0.2  setosa
## 3            NA          NA          1.3         0.2  setosa
## 4           4.6          NA          1.5         0.2  setosa
## 5           5.0          NA          1.4         0.2  setosa
## 6           5.4          NA          1.7         0.4  setosa
## 7           4.6          NA          1.4         0.3  setosa
## 8           5.0         3.4          1.5         0.2    <NA>
## 9           4.4         2.9          1.4         0.2    <NA>
## 10          4.9         3.1          1.5         0.1    <NA>

使用线性回归方法插补缺失值:

根据Sepal.WidthSpecies这两列,来预测Sepal.Length这一列的缺失值:

代码语言:javascript复制
library(simputation)
da1 <- impute_lm(dat, Sepal.Length ~ Sepal.Width   Species)
head(da1, 10)
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1      5.076579         3.5          1.4         0.2  setosa
## 2      4.675654         3.0          1.4         0.2  setosa
## 3            NA          NA          1.3         0.2  setosa
## 4      4.600000          NA          1.5         0.2  setosa
## 5      5.000000          NA          1.4         0.2  setosa
## 6      5.400000          NA          1.7         0.4  setosa
## 7      4.600000          NA          1.4         0.3  setosa
## 8      5.000000         3.4          1.5         0.2    <NA>
## 9      4.400000         2.9          1.4         0.2    <NA>
## 10     4.900000         3.1          1.5         0.1    <NA>

此处Sepal.Length的第3个值还是NA,这是因为Sepal.Width这一列的第3个值是NA导致的,线性回归不能插补这样的缺失值。

可以通过中位数进行插补:

代码语言:javascript复制
da2 <- impute_median(da1, Sepal.Length ~ Species) # Species用来分组,相当于根据Species这一列分组求中位数然后分别插补
head(da2, 10)
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1      5.076579         3.5          1.4         0.2  setosa
## 2      4.675654         3.0          1.4         0.2  setosa
## 3      5.000000          NA          1.3         0.2  setosa
## 4      4.600000          NA          1.5         0.2  setosa
## 5      5.000000          NA          1.4         0.2  setosa
## 6      5.400000          NA          1.7         0.4  setosa
## 7      4.600000          NA          1.4         0.3  setosa
## 8      5.000000         3.4          1.5         0.2    <NA>
## 9      4.400000         2.9          1.4         0.2    <NA>
## 10     4.900000         3.1          1.5         0.1    <NA>

使用决策树方法来插补Species这一列:

代码语言:javascript复制
da3 <- impute_cart(da2, Species ~ .)
head(da3,10)
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1      5.076579         3.5          1.4         0.2  setosa
## 2      4.675654         3.0          1.4         0.2  setosa
## 3      5.000000          NA          1.3         0.2  setosa
## 4      4.600000          NA          1.5         0.2  setosa
## 5      5.000000          NA          1.4         0.2  setosa
## 6      5.400000          NA          1.7         0.4  setosa
## 7      4.600000          NA          1.4         0.3  setosa
## 8      5.000000         3.4          1.5         0.2  setosa
## 9      4.400000         2.9          1.4         0.2  setosa
## 10     4.900000         3.1          1.5         0.1  setosa

使用管道符连接多种插补方法

使用%>%管道符连接一系列操作:

代码语言:javascript复制
library(magrittr)
da4 <- dat %>% 
  impute_lm(Sepal.Length ~ Sepal.Width   Species) %>%
  impute_median(Sepal.Length ~ Species) %>%
  impute_cart(Species ~ .)
head(da4,10)
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1      5.076579         3.5          1.4         0.2  setosa
## 2      4.675654         3.0          1.4         0.2  setosa
## 3      5.000000          NA          1.3         0.2  setosa
## 4      4.600000          NA          1.5         0.2  setosa
## 5      5.000000          NA          1.4         0.2  setosa
## 6      5.400000          NA          1.7         0.4  setosa
## 7      4.600000          NA          1.4         0.3  setosa
## 8      5.000000         3.4          1.5         0.2  setosa
## 9      4.400000         2.9          1.4         0.2  setosa
## 10     4.900000         3.1          1.5         0.1  setosa

使用一个固定值进行插补

原数据这样:

代码语言:javascript复制
head(dat, 10)
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1            NA         3.5          1.4         0.2  setosa
## 2            NA         3.0          1.4         0.2  setosa
## 3            NA          NA          1.3         0.2  setosa
## 4           4.6          NA          1.5         0.2  setosa
## 5           5.0          NA          1.4         0.2  setosa
## 6           5.4          NA          1.7         0.4  setosa
## 7           4.6          NA          1.4         0.3  setosa
## 8           5.0         3.4          1.5         0.2    <NA>
## 9           4.4         2.9          1.4         0.2    <NA>
## 10          4.9         3.1          1.5         0.1    <NA>

使用7插补:

代码语言:javascript复制
da4 <- impute_const(dat, Sepal.Length ~ 7)
head(da4,10)
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1           7.0         3.5          1.4         0.2  setosa
## 2           7.0         3.0          1.4         0.2  setosa
## 3           7.0          NA          1.3         0.2  setosa
## 4           4.6          NA          1.5         0.2  setosa
## 5           5.0          NA          1.4         0.2  setosa
## 6           5.4          NA          1.7         0.4  setosa
## 7           4.6          NA          1.4         0.3  setosa
## 8           5.0         3.4          1.5         0.2    <NA>
## 9           4.4         2.9          1.4         0.2    <NA>
## 10          4.9         3.1          1.5         0.1    <NA>

复制另一列的值进行插补:

代码语言:javascript复制
da4 <- impute_proxy(dat, Sepal.Length ~ Sepal.Width)
head(da4,10)
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1           3.5         3.5          1.4         0.2  setosa
## 2           3.0         3.0          1.4         0.2  setosa
## 3            NA          NA          1.3         0.2  setosa
## 4           4.6          NA          1.5         0.2  setosa
## 5           5.0          NA          1.4         0.2  setosa
## 6           5.4          NA          1.7         0.4  setosa
## 7           4.6          NA          1.4         0.3  setosa
## 8           5.0         3.4          1.5         0.2    <NA>
## 9           4.4         2.9          1.4         0.2    <NA>
## 10          4.9         3.1          1.5         0.1    <NA>

对多列使用同一种插补方法

根据Petal.LengthSpecies这两列使用rlm方法插补Sepal.LengthSepal.Width:

代码语言:javascript复制
da5 <- impute_rlm(dat, Sepal.Length   Sepal.Width ~ Petal.Length   Species)
head(da5)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1     4.945416    3.500000          1.4         0.2  setosa
## 2     4.945416    3.000000          1.4         0.2  setosa
## 3     4.854056    3.378979          1.3         0.2  setosa
## 4     4.600000    3.440107          1.5         0.2  setosa
## 5     5.000000    3.409543          1.4         0.2  setosa
## 6     5.400000    3.501236          1.7         0.4  setosa

同样也支持tidyverse中的.-,以下代码使用均值加残差插补除了Species的所有列:

代码语言:javascript复制
da6 <- impute_lm(dat, . - Species ~ 0   Species, add_residual = "normal") # Species用来分组
head(da6)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1     4.292233    3.500000          1.4         0.2  setosa
## 2     4.132790    3.000000          1.4         0.2  setosa
## 3     4.443134    3.643322          1.3         0.2  setosa
## 4     4.600000    3.518055          1.5         0.2  setosa
## 5     5.000000    3.355422          1.4         0.2  setosa
## 6     5.400000    3.094199          1.7         0.4  setosa

分组插补

可以在公式中使用|指定组。

代码语言:javascript复制
# 新建一个含缺失值的数据框
dat <- iris
dat[1:3,1] <- dat[3:7,2] <- NA

# 根据Species分组,然后再插补
da8 <- impute_lm(dat, Sepal.Length ~ Petal.Width | Species)
head(da8)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1     4.968092         3.5          1.4         0.2  setosa
## 2     4.968092         3.0          1.4         0.2  setosa
## 3     4.968092          NA          1.3         0.2  setosa
## 4     4.600000          NA          1.5         0.2  setosa
## 5     5.000000          NA          1.4         0.2  setosa
## 6     5.400000          NA          1.7         0.4  setosa

如果指定了一个或多个分组变量(通过用 分隔多个变量来指定多个),函数内部会进行以下操作:

  1. 根据分组变量的值将数据划分为子集
  2. 估计每个数据子集的模型并进行插补
  3. 组合插补的子集

也可以和dplyr包的group_by连用:

代码语言:javascript复制
library(magrittr)
library(dplyr)
## 
## 载入程辑包:'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union

dat <- iris
dat[1:3,1] <- dat[3:7,2] <- NA

dat %>% group_by(Species) %>% 
  impute_lm(Sepal.Length ~ Petal.Width)
## # A tibble: 150 x 5
## # Groups:   Species [3]
##    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
##  *        <dbl>       <dbl>        <dbl>       <dbl> <fct>  
##  1         4.96         3.5          1.4         0.2 setosa 
##  2         4.96         3            1.4         0.2 setosa 
##  3         4.96        NA            1.3         0.2 setosa 
##  4         4.6         NA            1.5         0.2 setosa 
##  5         5           NA            1.4         0.2 setosa 
##  6         5.4         NA            1.7         0.4 setosa 
##  7         4.6         NA            1.4         0.3 setosa 
##  8         5            3.4          1.5         0.2 setosa 
##  9         4.4          2.9          1.4         0.2 setosa 
## 10         4.9          3.1          1.5         0.1 setosa 
## # ... with 140 more rows

使用impute_proxy指定自己的插补方法

impute_proxy允许自定义formula

自定义一个robust ratio imputation方法进行插补:

代码语言:javascript复制
dat <- iris
dat[1:3,1] <- dat[3:7,2] <- NA

dat <- impute_proxy(dat, Sepal.Length ~ median(Sepal.Length,na.rm=TRUE)/median(Sepal.Width, na.rm=TRUE) * Sepal.Width | Species)
head(dat)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1     5.147059         3.5          1.4         0.2  setosa
## 2     4.411765         3.0          1.4         0.2  setosa
## 3           NA          NA          1.3         0.2  setosa
## 4     4.600000          NA          1.5         0.2  setosa
## 5     5.000000          NA          1.4         0.2  setosa
## 6     5.400000          NA          1.7         0.4  setosa

自定义使用均值进行插补:

代码语言:javascript复制
dat <- iris
dat[1:3,1] <- dat[3:7,2] <- NA

dat <- impute_proxy(dat, Sepal.Length ~ mean(Sepal.Length,na.rm=TRUE))
head(dat)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1     5.862585         3.5          1.4         0.2  setosa
## 2     5.862585         3.0          1.4         0.2  setosa
## 3     5.862585          NA          1.3         0.2  setosa
## 4     4.600000          NA          1.5         0.2  setosa
## 5     5.000000          NA          1.4         0.2  setosa
## 6     5.400000          NA          1.7         0.4  setosa

自定义使用均值进行插补(先根据Species分组再计算均值):

代码语言:javascript复制
dat <- iris
dat[1:3,1] <- dat[3:7,2] <- NA

dat <- impute_proxy(dat, Sepal.Length ~ mean(Sepal.Length,na.rm=TRUE) | Species)
head(dat)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1     5.012766         3.5          1.4         0.2  setosa
## 2     5.012766         3.0          1.4         0.2  setosa
## 3     5.012766          NA          1.3         0.2  setosa
## 4     4.600000          NA          1.5         0.2  setosa
## 5     5.000000          NA          1.4         0.2  setosa
## 6     5.400000          NA          1.7         0.4  setosa

使用在其他数据集中训练过的模型插补数据

在其他数据集训练模型

代码语言:javascript复制
m <- lm(Sepal.Length ~ Sepal.Width   Species, data = iris)

新建一个要插补的数据集

代码语言:javascript复制
dat <- iris
dat[1:3,1] <- dat[3:7,2] <- NA
head(dat)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1           NA         3.5          1.4         0.2  setosa
## 2           NA         3.0          1.4         0.2  setosa
## 3           NA          NA          1.3         0.2  setosa
## 4          4.6          NA          1.5         0.2  setosa
## 5          5.0          NA          1.4         0.2  setosa
## 6          5.4          NA          1.7         0.4  setosa

使用训练过的模型进行插补

代码语言:javascript复制
dat <- impute(dat, Sepal.Length ~ m)
head(dat)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1     5.063856         3.5          1.4         0.2  setosa
## 2     4.662076         3.0          1.4         0.2  setosa
## 3           NA          NA          1.3         0.2  setosa
## 4     4.600000          NA          1.5         0.2  setosa
## 5     5.000000          NA          1.4         0.2  setosa
## 6     5.400000          NA          1.7         0.4  setosa

以上就是今天的主要内容,关于缺失值的探索和处理还有很多其他优秀的R包,将在以后继续为大家介绍其他工具。但是风格最统一、搭配最好的就是这两个包了!

0 人点赞