如何对这个替换操作进行矢量化?

时间:2013-12-10 23:41:56

标签: r for-loop vectorization apply

我有一个数据集,需要根据另一个数据集的值进行上限/修剪等。两个数据集都具有相同的结构(列名等)。

将存储在其他数据集中的转换应用于当前数据集的快速方法是什么?

示例数据:

#generate sample data & set some values to NA
#this is the dataset that has variables that need to be trimmed
x1 <- data.frame(a=rep(11:20), b=rep(41:50))
x1[2,1] <- NA
x1

#a vector containing values to trim to (in this case, say 75th percentile)
y1 <- apply(x1, 2, function(x) quantile(x, 0.75, na.rm=T))
y1

#I am doing this inside a loop
for (i in 1:ncol(x1)){
  x1[is.na(x1[[i]]),] <- y1[i]       #if missing, set to some value

  x1[x1[[i]] > y1[i], i] <- y1[i]    #if larger than 75th pctl, set to some value
}

x1

我很确定有一种更快的矢量化方式来做到这一点。我非常感谢任何投入。

2 个答案:

答案 0 :(得分:1)

一个选项:将您的逻辑编写为一个带矢量和值的函数:

myfun <- function(x, y) {
    x[is.na(x)] <- y
    x[x > y] <- y
    return (x)
}

然后使用mapplyx1视为列的列表(它的类别):

mapply(myfun, x1, y1)

你可以通过包裹它来强制它回到data.frame

data.frame(mapply(myfun, x1, y1))

如果您愿意,还可以添加SIMPLIFY=FALSE


根据评论,Map是一个更好的选择,因为它避免了一些打字,可能还有一些开销:

as.data.frame(Map(myfun, x1, y1))

答案 1 :(得分:1)

这是使用data.table包的另一个选项。 data.table速度非常快,语法强大,但缺点是需要学习新的语法。

library(data.table)

x1 <- data.frame(a=rep(11:20), b=rep(41:50))
x1[2,1] <- NA

# Convert data.frame to data.table.
DT <- data.table(x1)

# Put your desired operations into a function, for clarity/tidiness.
update_vals <- function(x, prob=0.75) {
    xcut <- quantile(x, probs=prob, na.rm=TRUE)
    x[is.na(x) | x > xcut] <- xcut
    return(x)
}

# Use lapply and data.table syntax to 'loop' over columns.
DT2 = DT[, lapply(.SD, update_vals)]
DT2
#      a     b
#  1: 11 41.00
#  2: 18 42.00
#  3: 13 43.00
#  4: 14 44.00
#  5: 15 45.00
#  6: 16 46.00
#  7: 17 47.00
#  8: 18 47.75
#  9: 18 47.75
# 10: 18 47.75