如何在满足特定条件时删除一组值?

时间:2015-02-13 02:17:05

标签: r plyr dplyr

原则上数据如下所示:

obs gr  x1  x2  gender
1   1   0   4   M
2   1   4   13  M
3   1   13  15  M
4   1   15  15  M
5   2   0   1   F
6   2   1   15  F
7   2   15  19  F
8   2   19  30  F
9   2   30  31  F
10  3   0   2   F
11  3   2   4   F
12  3   4   7   F
13  4   0   1   M
14  4   1   14  M
15  4   14  22  M
16  4   22  31  M
17  4   31  31  M
18  4   31  60  M
19  4   60  60  M

我想使数据看起来像这样:在每个组(“gr”)中,如果x1和x2的值在任何行中相等,则该组中的所有值都将被删除。所以新数据应如下所示:

obs gr  x1  x2  gender
1   1   0   1   F
2   1   1   15  F
3   1   15  19  F
4   1   19  30  F
5   1   30  31  F
6   2   0   2   F
7   2   2   4   F
8   2   4   7   F

“gr”栏中的数字也应该重新排列。也就是说,2中的gr变为13中的gr变为2

感谢。

2 个答案:

答案 0 :(得分:2)

这是一种方法。我相信会有更好的方法。首先,我按gr对数据进行了分组。其次,我检查了x1x2中是否有任何行具有相同的值。如果有这样的行,我请R指定1,否则0。最后,我使用filter来完成子集。之后,我按照您的要求做了一些改变gr的工作。

group_by(mydf, gr) %>%
mutate(check = ifelse(any(x1 == x2) == TRUE, 1, 0)) %>%
filter(check == 0) %>%
ungroup %>%
mutate(gr = cumsum(c(TRUE, diff(gr) != 0))) %>%
select(-check)

#  obs gr x1 x2 gender
#1   5  1  0  1      F
#2   6  1  1 15      F
#3   7  1 15 19      F
#4   8  1 19 30      F
#5   9  1 30 31      F
#6  10  2  0  2      F
#7  11  2  2  4      F
#8  12  2  4  7      F

更新

感谢akrun的善意建议,我学会了一种处理这种情况的简洁方法。

group_by(mydf, gr) %>%
filter(!any(x1 == x2)) %>%
ungroup %>%
mutate(obs = 1:n(),
       gr = as.numeric(factor(gr)))

#  obs gr x1 x2 gender
#1   1  1  0  1      F
#2   2  1  1 15      F
#3   3  1 15 19      F
#4   4  1 19 30      F
#5   5  1 30 31      F
#6   6  2  0  2      F
#7   7  2  2  4      F
#8   8  2  4  7      F

DATA

mydf <- structure(list(obs = 1:19, gr = c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 
2L, 2L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 4L, 4L), x1 = c(0L, 4L, 
13L, 15L, 0L, 1L, 15L, 19L, 30L, 0L, 2L, 4L, 0L, 1L, 14L, 22L, 
31L, 31L, 60L), x2 = c(4L, 13L, 15L, 15L, 1L, 15L, 19L, 30L, 
31L, 2L, 4L, 7L, 1L, 14L, 22L, 31L, 31L, 60L, 60L), gender = structure(c(2L, 
2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L), .Label = c("F", "M"), class = "factor")), .Names = c("obs", 
"gr", "x1", "x2", "gender"), class = "data.frame", row.names = c(NA, 
-19L))

答案 1 :(得分:2)

以下是使用data.table的选项。

library(data.table)# data.table_1.9.5
setDT(mydf)[,.SD[!any(x1==x2)] , gr][, 
            c('gr', 'obs') := list(rleid(gr), 1:.N)][]
#    gr obs x1 x2 gender
#1:  1   1  0  1      F
#2:  1   2  1 15      F
#3:  1   3 15 19      F
#4:  1   4 19 30      F
#5:  1   5 30 31      F
#6:  2   6  0  2      F
#7:  2   7  2  4      F
#8:  2   8  4  7      F

注意:.SD可以替换为.I以获取行索引,然后将其用于子集化。

或使用base R

transform(mydf[with(mydf, !ave(x1==x2, gr, FUN=any)),], 
          obs=seq_along(obs), gr=as.numeric(factor(gr)))