使用sapply进行中位数插补

3

我希望能够替换数据框中列中的缺失值。我已经编写了以下代码:

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)
      }

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


我认为在这里使用for循环是个好主意——因为其中一些列保持不变。顺便说一下,在第一个if中使用is.numeric而不是复杂条件。 - gagolews
2个回答

5
您可以使用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})

如果你想要的是高性能的话,我相信会有人提供数据表格解决方案(不幸的是我不熟悉那个包所以不能自己做)。


4
这实际上是一个微妙的问题,值得讨论(依我之见)。您有一个数据框,并希望仅为数值列填充中位数,结果当然是一个数据框。 apply(...)函数将首先强制转换其参数为矩阵。由于矩阵中的所有元素在定义上必须是相同的数据类型,如果原始数据框中有任何字符或因子列,则在传递给apply(...)时整个矩阵都将被强制转换为字符。请保留HTML标记。
# 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$xdf$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

我认为这是值得商榷的,是否比使用循环更好...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接