【问题标题】:Median imputation using sapply使用 sapply 进行中值插补
【发布时间】:2014-06-08 04:09:52
【问题描述】:

我想替换数据框列中的缺失值。我写了以下代码

MedianImpute <- function(data=data)
     {
      for(i in 1:ncol(data))
        {        
        if(class(data[,i]) %in% c("numeric","integer"))
          {
          if(sum(is.na(data[,i])))
            {
            data[is.na(data[,i]),i] <- 
                          median(data[,i],na.rm = TRUE)
            }
          }
        }
      return(data)
      }

这将返回数据框,其中 NA 被列中位数替换。 我不想使用 for 循环,如何使用 R 中的任何应用函数获得相同的结果?

【问题讨论】:

  • 我认为 for 循环在这里是一个好主意 - 这是因为某些列保持不变。顺便说一句,在第一个 if 中使用 is.numeric 而不是第一个 if 中的复杂条件。

标签: r for-loop apply missing-data


【解决方案1】:

这实际上是一个微妙的问题,因此值得进行一些讨论(IMO)。您有一个data frame,并且只想估算数字列的中位数,结果当然是一个数据框。

apply(...) 函数将首先将其参数强制转换为矩阵。由于定义矩阵中的所有元素必须是相同的数据类型,如果原始 df 中有任何字符或因子列,则整个矩阵在传递给 @987654323 时将被强制转换为 char @。

# 1st column of df is a factor
df <- data.frame(a=letters[1:5],x=sample(1:5,5),y=runif(5))
df[3,]$x <- NA
df[5,]$y <- NA
df
#   a  x         y
# 1 a  5 0.5235779
# 2 b  3 0.2142011
# 3 c NA 0.8886608
# 4 d  4 0.4952574
# 5 e  1        NA

apply(df,2,function(x) {
  if(is.numeric(x)) ifelse(is.na(x),median(x,na.rm=T),x) else x})
#      a   x    y          
# [1,] "a" " 5" "0.5235779"
# [2,] "b" " 3" "0.2142011"
# [3,] "c" NA   "0.8886608"
# [4,] "d" " 4" "0.4952574"
# [5,] "e" " 1" NA         

sapply(df,FUN=f) 会将df 的列单独传递给函数f(...),但是,结果将是矩阵。因此,例如,df 中的任何因子都将被强制转换为整数。

sapply(df,function(x) {
  if(is.numeric(x)) ifelse(is.na(x),median(x,na.rm=T),x) else x})
#      a   x         y
# [1,] 1 5.0 0.5235779
# [2,] 2 3.0 0.2142011
# [3,] 3 3.5 0.8886608
# [4,] 4 4.0 0.4952574
# [5,] 5 1.0 0.5094176

所以在这里,df$x 和 df$y 是正确的,但看看 df$a 发生了什么:通过返回因子水平将因子强制转换为数字 - 不是你想要的!

lapply(df,FUN=F) 将返回一个列表,然后可以将其转换为数据框。这种方法会给你想要的结果:

data.frame(lapply(df,function(x) {
    if(is.numeric(x)) ifelse(is.na(x),median(x,na.rm=T),x) else x}))
#   a   x         y
# 1 a 1.0 0.3093707
# 2 b 3.0 0.3486391
# 3 c 3.5 0.8292446
# 4 d 5.0 0.7882574
# 5 e 4.0 0.5684483

我认为这是否比使用循环更好......

【讨论】:

    【解决方案2】:

    您可以使用apply 将函数应用于所有列

    dat<-data.frame(c1=c(1,2,3,NA),c2=c(10, NA, 20, 30))
    apply(dat, 2, function(x) ifelse(is.na(x), median(x, na.rm=T), x))
    

    稍微快一点

    imputeMedianv3<-function(x) apply(x, 2, function(x){x[is.na(x)]<-median(x, na.rm=T); x})
    

    我敢肯定,如果您要的是性能,有人会提供数据表解决方案(不幸的是我不熟悉那个包,所以不能自己做)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-05
      • 2020-04-04
      • 1970-01-01
      • 1970-01-01
      • 2016-11-19
      • 1970-01-01
      相关资源
      最近更新 更多