Fra*_*ank 16 r data.table
我有一个data.table,列有一个NAs.我想删除该列占用特定值的行(恰好是这样"").但是,我的第一次尝试也导致我丢失了NAs 行:
> a = c(1,"",NA)
> x <- data.table(a);x
a
1: 1
2:
3: NA
> y <- x[a!=""];y
a
1: 1
Run Code Online (Sandbox Code Playgroud)
看了之后?`!=`,我找到了一个有效的衬垫,但这很痛苦:
> z <- x[!sapply(a,function(x)identical(x,""))]; z
a
1: 1
2: NA
Run Code Online (Sandbox Code Playgroud)
我想知道是否有更好的方法来做到这一点?此外,我认为没有好的方法来扩展它以排除多个非NA值.这是一个糟糕的方式:
> drop_these <- function(these,where){
+ argh <- !sapply(where,
+ function(x)unlist(lapply(as.list(these),function(this)identical(x,this)))
+ )
+ if (is.matrix(argh)){argh <- apply(argh,2,all)}
+ return(argh)
+ }
> x[drop_these("",a)]
a
1: 1
2: NA
> x[drop_these(c(1,""),a)]
a
1: NA
Run Code Online (Sandbox Code Playgroud)
我查看?J并尝试使用data.frame,这似乎有所不同,NA在子集化时保留s:
> w <- data.frame(a,stringsAsFactors=F); w
a
1 1
2
3 <NA>
> d <- w[a!="",,drop=F]; d
a
1 1
NA <NA>
Run Code Online (Sandbox Code Playgroud)
Aru*_*run 17
你应该用%in%.它会返回一个逻辑向量.
a %in% ""
# [1] FALSE TRUE FALSE
x[!a %in% ""]
# a
# 1: 1
# 2: NA
Run Code Online (Sandbox Code Playgroud)
data.table:(反对data.frame)
如果你查看函数下data.table文件的源代码,就会有一组参数检查.其中之一是:data.table.R"[.data.table"if-statementsi
if (!missing(i)) {
# Part (1)
isub = substitute(i)
# Part (2)
if (is.call(isub) && isub[[1L]] == as.name("!")) {
notjoin = TRUE
if (!missingnomatch) stop("not-join '!' prefix is present on i but nomatch is provided. Please remove nomatch.");
nomatch = 0L
isub = isub[[2L]]
}
.....
# "isub" is being evaluated using "eval" to result in a logical vector
# Part 3
if (is.logical(i)) {
# see DT[NA] thread re recycling of NA logical
if (identical(i,NA)) i = NA_integer_
# avoids DT[!is.na(ColA) & !is.na(ColB) & ColA==ColB], just DT[ColA==ColB]
else i[is.na(i)] = FALSE
}
....
}
Run Code Online (Sandbox Code Playgroud)
为了解释这种差异,我在这里贴了重要的代码.我还将它们标记为3部分.
dt[a != ""]不能按预期工作(由OP)?首先,part 1评估一个类的对象call.if语句的第二部分part 2返回FALSE.在此之后,call"评估"给予c(TRUE, FALSE, NA).然后part 3执行.因此,NA被替换为FALSE(逻辑循环的最后一行).
x[!(a== "")]按预期工作(由OP)?part 1返回调用一次.但是,part 2评估为TRUE因此设置:
1) `notjoin = TRUE`
2) isub <- isub[[2L]] # which is equal to (a == "") without the ! (exclamation)
Run Code Online (Sandbox Code Playgroud)
这就是魔术发生的地方.这个否定现在已被删除.请记住,这仍然是课堂调用的对象.因此,这将eval再次评估(使用)到逻辑.所以,(a=="")评估为c(FALSE, TRUE, NA).
现在,这是检查is.logical在part 3.所以,在这里,NA被替换为FALSE.因此它变得,c(FALSE, TRUE, FALSE).在某些时候,which(c(F,T,F))执行a,这里得到2.因为notjoin = TRUE(from part 2)seq_len(nrow(x))[-2]= c(1,3)被返回.所以,x[!(a=="")]基本上返回x[c(1,3)]哪个是期望的结果.这是相关的代码段:
if (notjoin) {
if (bywithoutby || !is.integer(irows) || is.na(nomatch)) stop("Internal error: notjoin but bywithoutby or !integer or nomatch==NA")
irows = irows[irows!=0L]
# WHERE MAGIC HAPPENS (returns c(1,3))
i = irows = if (length(irows)) seq_len(nrow(x))[-irows] else NULL # NULL meaning all rows i.e. seq_len(nrow(x))
# Doing this once here, helps speed later when repeatedly subsetting each column. R's [irows] would do this for each
# column when irows contains negatives.
}
Run Code Online (Sandbox Code Playgroud)
鉴于这种情况,我觉得有一些不一致的语法..如果我设法让时间来制定的问题,那么我会尽快写一个帖子.
马太福音的背景回答:
!=考虑一下这个问题所强调的on行为NA并不是有意的。初衷确实是想和[.data.framewrt不一样,相信大家都对此感到满意。例如,常见问题解答 2.17 有:==NA
DT[ColA==ColB]比DF[!is.na(ColA) & !is.na(ColB) & ColA==ColB,]
这种便利是通过以下方式实现的:
DT[c(TRUE,NA,FALSE)]NA将as视为FALSE,但DF[c(TRUE,NA,FALSE)]返回NA每个的行NA
动机不仅是方便,而且是速度,因为每个 、 、!和is.na本身就是向量扫描,并且每个结果都有相关的内存分配(在介绍小插图中进行了解释)&。==因此,虽然x[is.na(a) | a!=""]这是一个可行的解决方案,但它正是我试图避免在 data.table 中需要的逻辑类型。x[!a %in% ""]稍微好一些;即 2 次扫描 (%in%和!) 而不是 3 次 ( is.na,|和!=)。但确实 x[a != ""]应该NA在一次扫描中完成弗兰克所期望的(包括 )。
提交的新功能请求链接回此问题:
感谢弗兰克、埃迪和阿伦。如果我没有正确理解,请随时纠正,否则最终会做出改变。需要以考虑复合表达式的方式完成;例如,DT[colA=="foo" & colB!="bar"]应排除带有NAin 的行colA,但包括其中colAis non- NAbut colBis 的行NA。同样,DT[colA!=colB]应包括 colA 或 colB 所在的行NA,但不能同时包含两者。也许DT[colA==colB]应该包括同时存在colA和 的行(我相信目前还没有)。colBNA