【问题标题】:How to delete a group of values when a certain certain condition is met?当满足某个特定条件时如何删除一组值?
【发布时间】:2015-02-13 02:17:05
【问题描述】:

最初的数据是这样的:

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”列中的数字也应该重新排列。也就是说,在这种情况下,gr 中的 2 变为 1gr 中的 3 变为 2

谢谢。

【问题讨论】:

  • 看到你的预期结果,我很困惑。例如,obs 4 在 x1 和 x2 中有 15 个。如果我没记错的话,你不想要组 gr1 中的任何数据。是对的吗?另一件事是预期结果似乎与原始数据不匹配。我错过了什么吗?
  • 嗨,爵士乐。预期结果不包含原始数据中第 1 组和第 4 组的任何值,因为在任一组中,至少有一行具有相同的 x1 和 x2 值。虽然两个数据集不匹配(组号也变了),但预期的结果正是我想要的。

标签: r plyr dplyr


【解决方案1】:

这是一种方法。我相信会有更好的方法。首先,我将数据按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

数据

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))

【讨论】:

  • 嗨,爵士乐:您的代码有效。太棒了。我真的很感谢你的帮助。实际上,在我问这个问题之前,我尝试了 "subset"、"with"、"%in%" 等,但它们对我的效果并不好。我需要花更多时间学习包 "dplyr"。再次感谢。
  • @Jason 欢迎您。我很高兴该代码对您有用。 :)
  • @akrun 是的,在看到您的回答后,我现在正在考虑这个问题。我仍然无法以有效的方式使用filter。非常感谢您的建议。我会修改我的答案。
  • @akrun 是的,我看到了与ifelse 相关的帖子。我尽量避免ifelse。在这种情况下,您的方式是简洁的方式。我以为会有更好的方法,但我在解决问题时想不出像你这样的想法。
  • @jazzurro 你的代码已经很好了,只是需要一些修改。
【解决方案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)))

【讨论】:

  • 非常感谢阿克伦。
  • @Jason 没问题。很高兴为您提供帮助。
猜你喜欢
  • 2020-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-19
  • 1970-01-01
相关资源
最近更新 更多