我希望能够探索并可能改进@akrun上述优秀答案中使用的数据。以下是他在示例中使用的数据:
library(data.table)
set.seed(24)
DT <- data.table(v1= c(NA, 1:4), v2 = c(NA, LETTERS[1:4]), v3=c(rnorm(4), NA))
DT
以下是他建议使用的两种方法:
fun1 <- function(x){
for(j in seq_along(x)){
set(x, i = which(is.na(x[[j]]) & is.numeric(x[[j]])), j = j, value = 0)
}
}
fun2 <- function(x){
ind <- which(sapply(x, is.numeric))
for(j in ind){
set(x, i = which(is.na(x[[j]])), j = j, value = 0)
}
}
我认为上述第一种方法非常聪明,因为它利用了NAs的类型信息。
首先,尽管在i
参数中不可用.SD
,但可以使用get()
提取列名,因此我认为可以以这种方式进行子赋值data.table
:
fun3 <- function(x){
nms <- names(x)[sapply(x, is.numeric)]
for(j in nms){
x[is.na(get(j)), (j):=0]
}
}
通常情况下,需要依赖.SD
和.SDcols
仅在数字列上工作。
fun4 <- function(x){
nms <- names(x)[sapply(x, is.numeric)]
x[, (nms):=lapply(.SD, function(i) replace(i, is.na(i), 0)), .SDcols=nms]
}
但是我突然想到:“嘿,谁说我们不能使用基础的R语言进行这种操作呢?”下面是一个简单的lapply()
函数和条件语句,包装在setDT()
函数中。
fun5 <- function(x){
setDT(
lapply(x, function(i){
if(is.numeric(i))
i[is.na(i)]<-0
i
})
)
}
最后,我们可以使用条件的相同思路来限制应用
set()
的列。
fun6 <- function(x){
for(j in seq_along(x)){
if (is.numeric(x[[j]]) )
set(x, i = which(is.na(x[[j]])), j = j, value = 0)
}
}
这是基准测试结果:
microbenchmark::microbenchmark(
for.set.2cond = fun1(copy(DT)),
for.set.ind = fun2(copy(DT)),
for.get = fun3(copy(DT)),
for.SDcol = fun4(copy(DT)),
for.list = fun5(copy(DT)),
for.set.if =fun6(copy(DT))
)
DT[...] <- y
。建议阅读vignettes https://github.com/Rdatatable/data.table/wiki/Getting-started,这是一种比“为每个步骤寻找解决方案”更高效的学习方式。下面的答案甚至不需要你发现的with=FALSE技巧。 - FrankDT[...] <- y
这样使用,其中...
是你想到的任何内容。赋值应该使用:=
或set
而不是<-
。箭头方式实际上在特殊情况下确实可以工作,也就是说表格被修改了,但它不是按引用方式工作的(据我所知),因此不是惯用方法。要使用 data.table,您需要学习一些它们的惯用法。如果您还不知道我所说的:=
是什么意思,那么查看vignettes是一个很好的理由。 - Franknumeric_cols <- which(sapply(DT,is.numeric))
,相比于在顶端一次性计算,效率更高。b) 然后只需引用DT[, numeric_cols]
。c) 是的,在j表达式中放置函数调用很棘手,而且经常会触发语法错误。 - smci