我对一些解决方案进行了基准测试,以替换每列的缺失值。
set.seed(11)
df <- data.frame(replicate(3, sample(c(1:5, -99), 6, rep = TRUE)))
names(df) <- letters[1:3]
fix_na <- function(x) {
x[x == -99] <- NA
}
microbenchmark(
for(i in seq_along(df)) df[, i] <- fix_na(df[, i]),
for(i in seq_along(df)) df[[i]] <- fix_na(df[[i]]),
df[] <- lapply(df, fix_na)
)
Unit: microseconds
expr min lq mean median uq max neval
for (i in seq_along(df)) df[, i] <- fix_na(df[, i]) 179.167 191.9060 206.1650 204.2335 211.630 364.497 100
for (i in seq_along(df)) df[[i]] <- fix_na(df[[i]]) 83.420 92.8715 104.5787 98.0080 109.309 204.645 100
df[] <- lapply(df, fix_na) 105.199 113.4175 128.0265 117.9385 126.979 305.734 100
为什么[[]]运算符将数据帧的子集比[,]运算符快2倍?
修改
我从docendo discimus中包含了两个推荐的调用,并增加了数据量。
set.seed(11)
df1 <- data.frame(replicate(2000, sample(c(1:5, -99), 500, rep = TRUE)))
df2 <- df1
df3 <- df1
df4 <- df1
df5 <- df1
结果改变是,但我的问题仍然存在:[[]]的执行速度比[,]
快Unit: milliseconds
expr min lq mean median uq
for (i in seq_along(df1)) df1[, i] <- fix_na(df1[, i]) 301.06608 356.48011 377.31592 372.05625 392.73450 472.3330
for (i in seq_along(df2)) df2[[i]] <- fix_na(df2[[i]]) 238.72005 287.55364 301.35651 298.05950 314.04369 386.4288
df3[] <- lapply(df3, fix_na) 170.53264 189.83858 198.32358 193.43300 202.43855 284.1164
df4[df4 == -99] <- NA 75.05571 77.64787 85.59757 80.72697 85.16831 363.2223
is.na(df5) <- df5 == -99 74.44877 77.81799 84.22055 80.06496 83.01401 347.5798
答案 0 :(得分:0)
更快的方法是使用set
data.table
library(data.table)
setDT(df)
for(j in seq_along(df)){
set(df, i = which(df[[j]]== -99), j=j, value = NA)
}
关于OP关于使用[
和[[
进行基准测试的问题,[[
会在没有.data.frame
开销的情况下提取该列。但是,我会在更大的数据集上进行基准测试,以发现任何差异。另外,当我们在相同数据上分配NA时,当我们再次执行操作时,它不会做任何更改。
set.seed(11)
df1 <- data.frame(replicate(2000, sample(c(1:5, -99), 500, rep = TRUE)))
df2 <- copy(df1)
df3 <- copy(df1)
df4 <- copy(df1)
df5 <- copy(df1)
df6 <- copy(df1)
f1 <- function() for (i in seq_along(df1)) df1[, i] <- fix_na(df1[, i])
f2 <- function() for (i in seq_along(df2)) df2[[i]] <- fix_na(df1[[i]])
f3 <- function() df3[] <- lapply(df3, fix_na)
f4 <- function() df4[df4 == -99] <- NA
f5 <- function() is.na(df5) <- df5 == -99
f6 <- function() {
setDT(df6)
for(j in seq_along(df)){
set(df, i = which(df[[j]]== -99), j=j, value = NA)
}
}
t(sapply(paste0("f", 1:6), function(f) system.time(get(f)())))[,1:3]
# user.self sys.self elapsed
#f1 0.29 0 0.30
#f2 0.22 0 0.22
#f3 0.11 0 0.11
#f4 0.31 0 0.31
#f5 0.31 0 0.32
#f6 0.00 0 0.00
在这里,我使用system.time
作为OP的帖子中的函数已经在第一次运行中替换了NA的值,所以没有必要一次又一次地运行它。
答案 1 :(得分:-1)
在Arun建议的网站上找到一个非常类似的问题的答案:adv-r.had.co.nz/Performance.html
在从数据框中提取单个值部分,它说:
Blockquote以下微基准测试显示了七种从内置mtcars数据集访问单个值(右下角的数字)的方法。性能的变化令人吃惊:最慢的方法比最快的方法长30倍。 没有必要在性能上有这么大的差异。只是没有人有时间来修复它。
在不同的选择方法中,两个运算符[[和[与我观察到的结果相同)。 [[优于[