我尝试按因子变量对data.frame进行分组,然后返回data.frame的行,这些行对应于在每个组中只出现一次的观察结果。例如,请考虑以下数据:
x = matrix(c(1,1,2,2,2,3,4,4,5,4), nrow = 5, ncol = 2, byrow = F)
x = data.frame(x)
x
# X1 X2
# 1 1 3
# 2 1 4
# 3 2 4
# 4 2 5
# 5 2 4
我想按照第1列中的值对数据进行分组,然后返回第2列中的值仅在组中出现一次的行。这里,函数将返回第一行,第二行和第四行。
期望的输出
# X1 X2
# 1 1 3
# 2 1 4
# 4 2 5
我希望将此应用于行数> 1毫米的数据集。
答案 0 :(得分:4)
在基数R中,您可以尝试ave
:
x[with(x, ave(X2, X1, X2, FUN = length)) == 1, ]
# X1 X2
# 1 1 3
# 2 1 4
# 4 2 5
由于ave
在有多个组和多个分组变量时扩展性非常差,您可能需要先创建一个新组:
x[with(x, ave(X2, sprintf("%s__%s", X1, X2), FUN = length)) == 1, ]
根据数据的性质,速度会有很大差异。
您也可以尝试:
library(dplyr)
x %>%
group_by(X1, X2) %>%
filter(n() == 1)
# Source: local data frame [3 x 2]
# Groups: X1, X2 [3]
#
# X1 X2
# (dbl) (dbl)
# 1 1 3
# 2 1 4
# 3 2 5
答案 1 :(得分:3)
我们可以使用data.table
。我们将'data.frame'转换为'data.table'(setDT(x)
,按第一列分组,即“X1”,if
,只有一个观察,返回行除了删除所有复制并仅返回唯一的行。
library(data.table)
setDT(x)[, if(.N==1) .SD else
.SD[!(duplicated(X2)|duplicated(X2, fromLast=TRUE))], X1]
# X1 X2
#1: 1 3
#2: 1 4
#3: 2 5
如果我们同时使用“X1”和“X2”作为分组变量
setDT(x)[x[, .I[.N==1], .(X1, X2)]$V1]
# X1 X2
#1: 1 3
#2: 1 4
#3: 2 5
注意:Data.table非常快且紧凑。
或者不使用任何分组选项,base R
我们可以
x[!(duplicated(x)|duplicated(x, fromLast=TRUE)),]
# X1 X2
#1 1 3
#2 1 4
#4 2 5
或tally
dplyr
library(dplyr)
x %>%
group_by_(.dots= names(x)) %>%
tally() %>%
filter(n==1) %>%
select(-n)
请注意,这应该比其他dplyr解决方案更快。
library(data.table)
library(dplyr)
示例数据
set.seed(24)
x1 <- data.frame(X1 = sample(1:5000, 1e6, replace=TRUE),
X2 = sample(1:10000, 1e6, replace=TRUE))
x2 <- copy(as.data.table(x1))
基地R接近
system.time(x1[with(x1, ave(X2, sprintf("%s__%s", X1, X2), FUN = length)) == 1, ])
# user system elapsed
# 20.245 0.002 20.280
system.time(x1[!(duplicated(x1)|duplicated(x1, fromLast=TRUE)), ])
# user system elapsed
# 1.994 0.000 1.998
dplyr接近
system.time(x1 %>% group_by(X1, X2) %>% filter(n() == 1))
# user system elapsed
# 33.400 0.006 33.467
system.time(x1 %>% group_by_(.dots= names(x2)) %>% tally() %>% filter(n==1) %>% select(-n))
# user system elapsed
# 2.331 0.000 2.333
data.table approach
system.time(x2[x2[, .I[.N==1], list(X1, X2)]$V1])
# user system elapsed
# 1.128 0.001 1.131
system.time(x2[, .N, by = list(X1, X2)][N == 1][, N := NULL][])
# user system elapsed
# 0.320 0.000 0.323
总结:“data.table”方法取得了成功,但如果由于某种原因无法使用该软件包,那么使用基础R中的duplicated
也会表现得非常好。
答案 2 :(得分:1)
使用base,类似
do.call(rbind, lapply(split(x, x$X1),
function(y){y[table(y$X2) == 1,]}))
# X1 X2
# 1.1 1 3
# 1.2 1 4
# 2 2 5
其中split
将x
拆分为按X1
级别划分的data.frames列表,然后将lapply
个子集划分为只有一次出现的行X2
的值,由table
制表。 do.call(rbind
然后将生成的data.frames重新组合回一个。