我的数据集类似于下面的数据集:
d <- data.frame(A=c(11,11,11,11,21,21,111,111,111,44,44,44),
B=c(0,1,0,0,0,0,1,0,0,0,0,0),
C=c(3,2,1,3,4,2,1,2,3,12,22,31))
d
A B C
1 11 0 3
2 11 1 2
3 11 0 1
4 11 0 3
5 21 0 4
6 21 0 2
7 111 1 1
8 111 0 2
9 111 0 3
10 44 0 12
11 44 0 22
12 44 0 31
我想删除唯一A中每行B = 0的行。例如,当A = 11时,有B = 1(第2行),所以没关系。相比之下,对于A = 21,所有B都等于零,所以我想删除A = 21的所有行。对于A = 44,所有B都是零,所以我想删除A = 44的所有行。
最后,我需要获取此数据框:
new_d
A B C
1 11 0 3
2 11 1 2
3 11 0 1
4 11 0 3
5 111 1 12
6 111 0 22
7 111 0 31
P.S。不关心C列,我添加它只是为了表明数据集中有超过2列。
答案 0 :(得分:2)
您可以使用ave
和逻辑子集,如下所示:
d[!!ave(d$B, d$A, FUN=function(i) !all(i == 0)),]
A B C
1 11 0 3
2 11 1 2
3 11 0 1
4 11 0 3
7 111 1 1
8 111 0 2
9 111 0 3
这里,当向量包含非零元素时,!all(i == 0)
返回TRUE。 ave
对每个组执行此检查,并返回与初始向量大小相同的向量,!!
将其转换为逻辑向量。此转换是必要的,因为ave
将返回与初始向量相同类型的向量。比!!
更明确的是as.logical
。
d[as.logical(ave(d$B, d$A, FUN=function(i) !all(i == 0))),]
答案 1 :(得分:2)
或使用简单的dplyr
操作:(顺便说一句,我相信您的预期输出已关闭)
require(dpylr)
d %>% group_by(A) %>% filter(sum(B) >= 1)
答案 2 :(得分:2)
base R
解决方案如何:
d[d$A %in% d$A[d$B!=0], ]
它也很快:
library(microbenchmark)
library(dplyr)
set.seed(33) ## making a larger example
A <- do.call(c, lapply(sample(10000, 2000), function(x) rep(x, sample(100, 1))))
B <- sample(c(0,1), length(A), replace = TRUE, prob = c(18/19, 1/19))
C <- sample(10^5, length(A), replace = TRUE)
df <- data.frame(A, B, C)
superBase <- function(d) {d[d$A %in% d$A[d$B!=0], ]}
aveStat <- function(d) {d[!!ave(d$B, d$A, FUN=function(i) !all(i == 0)),]}
dplyrSol <- function(d) {d %>% group_by(A) %>% filter(sum(B) >= 1)}
microbenchmark(superBase(df), aveStat(df), dplyrSol(df))
Unit: milliseconds
expr min lq mean median uq max neval cld
superBase(df) 21.44030 23.81434 30.00466 26.67157 27.32492 167.1614 100 a
aveStat(df) 34.23338 39.03278 49.12483 40.29534 42.96865 204.0808 100 b
dplyrSol(df) 63.52571 65.32626 71.64950 67.20563 69.43784 215.5980 100 c
给出相同的结果:
identical(superBase(df), aveStat(df))
[1] TRUE