我有一个 data.frame A 和一个 data.frame B ,其中包含 A 的子集
如何创建一个 data.frame C,它是 data.frame A 并且排除了 data.frame B?谢谢你的帮助。
我有一个 data.frame A 和一个 data.frame B ,其中包含 A 的子集
如何创建一个 data.frame C,它是 data.frame A 并且排除了 data.frame B?谢谢你的帮助。
获取 A 中不在 B 中的行
C = A[! data.frame(t(A)) %in% data.frame(t(B)), ]
如果这个 B 数据集确实是第一个数据集的嵌套版本,则必须首先创建创建该数据集的索引。恕我直言,我们不应该讨论数据集之间的差异,而是否定最初创建 B 数据集的原始索引。这是我的意思的一个例子:
A <- mtcars
B <- mtcars[mtcars$cyl==6, ]
C <- mtcars[mtcars$cyl!=6, ]
如果 B 确实是 A 的子集,您可以检查:
if(!identical(A[rownames(B), , drop = FALSE], B)) stop("B is not a subset of A!")
然后您可以按行名过滤:
C <- A[!rownames(A) %in% rownames(B), , drop = FALSE]
或者
C <- A[setdiff(rownames(A), rownames(B)), , drop = FALSE]
A <- data.frame(x = 1:10, y = 1:10)
#Random subset of A in B
B <- A[sample(nrow(A),3),]
#get A that is not in B
C <- A[-as.integer(rownames(B)),]
相对于 mplourde 的答案的性能测试:
library(rbenchmark)
f1 <- function() A[- as.integer(rownames(B)),]
f2 <- function() A[! data.frame(t(A)) %in% data.frame(t(B)), ]
benchmark(f1(), f2(), replications = 10000,
columns = c("test", "elapsed", "relative"),
order = "elapsed"
)
test elapsed relative
1 f1() 1.531 1.0000
2 f2() 8.846 5.7779
查看行名的速度大约快 6 倍。两次转置调用会在计算上变得昂贵。
这是两种data.table
节省内存和时间的解决方案
render_markdown(strict = T)
library(data.table)
# some biggish data
set.seed(1234)
ADT <- data.table(x = seq.int(1e+07), y = seq.int(1e+07))
.rows <- sample(nrow(ADT), 30000)
# Random subset of A in B
BDT <- ADT[.rows, ]
# set keys for fast merge
setkey(ADT, x)
setkey(BDT, x)
## how CDT <- ADT[-ADT[BDT,which=T]] the data as `data.frames for fastest
## alternative
A <- copy(ADT)
setattr(A, "class", "data.frame")
B <- copy(BDT)
setattr(B, "class", "data.frame")
f2 <- function() noBDT <- ADT[-ADT[BDT, which = T]]
f3 <- function() noBDT2 <- ADT[-BDT[, x]]
f1 <- function() noB <- A[-as.integer(rownames(B)), ]
library(rbenchmark)
benchmark(base = f1(),DT = f2(), DT2 = f3(), replications = 3)
## test replications elapsed relative user.self sys.self
## 2 DT 3 0.92 1.108 0.77 0.15
## 1 base 3 3.72 4.482 3.19 0.52
## 3 DT2 3 0.83 1.000 0.72 0.11
这不是最快的,并且可能非常慢,但它是 mplourde 的替代方案,它考虑了行数据,并且应该适用于 flodel 批评的混合数据。它依赖于 qdap 包中的 paste2 功能,该功能尚不存在,因为我计划在下个月或 2 个月内发布它:
粘贴2功能:
paste2 <- function(multi.columns, sep=".", handle.na=TRUE, trim=TRUE){
if (trim) multi.columns <- lapply(multi.columns, function(x) {
gsub("^\\s+|\\s+$", "", x)
}
)
if (!is.data.frame(multi.columns) & is.list(multi.columns)) {
multi.columns <- do.call('cbind', multi.columns)
}
m <- if(handle.na){
apply(multi.columns, 1, function(x){if(any(is.na(x))){
NA
} else {
paste(x, collapse = sep)
}
}
)
} else {
apply(multi.columns, 1, paste, collapse = sep)
}
names(m) <- NULL
return(m)
}
# Flodel的混合数据集:
A <- data.frame(x = 1:4, y = as.character(1:4)); B <- A[1:2, ]
# 我的方法:
A[!paste2(A)%in%paste2(B), ]