按条件筛选分组因子 - dplyr

5

假设我有以下这样一个数据框:

   day value group type id
1    1   0.1     A    X  1
2    1   0.4     A    Y  1
3    2   0.2     A    X  3
4    2   0.5     A    Y  3
5    3   0.3     A    X  5
6    3   0.2     A    Y  6
7    1   0.1     B    X  3
8    1   0.3     B    Y  3
9    2   0.1     B    X 11
10   2   0.4     B    Y 10
11   3   0.2     B    X 12
12   3   0.3     B    Y 12
13   1   0.1     C    X 12
14   1   0.3     C    Y 12
15   2   0.3     C    X  5
16   2   0.2     C    Y  5
17   3   0.2     C    X  3
18   3   0.2     C    Y  2

数据:

library(dplyr)
df1 <- data.frame(
day = rep(1:3,6),
value = c(0.1,0.2,0.3,0.4,0.5,0.2,0.1,0.1,0.2,0.3,0.4,0.3, 0.1,0.3,0.2,0.3,0.2,0.2),
group = rep(LETTERS[1:3], each=6)
) %>% 
  arrange(group,day) %>% 
  mutate(type=rep(LETTERS[24:25],9),
         id = c(1,1,3,3,5,6,3,3,11,10,12,12,12,12,5,5,3,2))  

df1

我希望能够基于条件过滤对该数据框进行筛选。我想要按照(day, group)分组,如果每个分组中的所有id都相等,则 过滤掉所有类型为Y的行,但保留类型为X的行。

我可以通过运行循环或通过数据框子集的几个步骤来完成此操作,但我想知道是否有一个一/两行代码的或方法?

这将是期望的输出:
   day value group type id
1    1   0.1     A    X  1
3    2   0.2     A    X  3
5    3   0.3     A    X  5
6    3   0.2     A    Y  6
7    1   0.1     B    X  3
9    2   0.1     B    X 11
10   2   0.4     B    Y 10
11   3   0.2     B    X 12
13   1   0.1     C    X 12
15   2   0.3     C    X  5
17   3   0.2     C    X  3
18   3   0.2     C    Y  2
4个回答

3

和 P Lapointe 类似,我也遇到了以下问题。一开始我想使用 all() 来检查所有 id 值是否相同,但尝试失败了。因此,我选择使用 diff()。使用 mutate() 函数,我检查了每个组的所有 id 值是否相同。然后,我选择了没有 check == TRUE and type == "Y" 组合的行。最后,我删除了 check 列。

group_by(df1, day, group) %>%
mutate(check = any(diff(id) == 0)) %>%
filter(!(check == TRUE & type == "Y")) %>%
select(-check)

#     day value  group  type    id
#   (int) (dbl) (fctr) (chr) (dbl)
#1      1   0.1      A     X     1
#2      2   0.2      A     X     3
#3      3   0.3      A     X     5
#4      3   0.2      A     Y     6
#5      1   0.1      B     X     3
#6      2   0.1      B     X    11
#7      2   0.4      B     Y    10
#8      3   0.2      B     X    12
#9      1   0.1      C     X    12
#10     2   0.3      C     X     5
#11     3   0.2      C     X     3
#12     3   0.2      C     Y     2

编辑

在与akrun进行沟通后,我对上述代码进行了修改。以下是新的代码。

group_by(df1, day, group) %>%
mutate(check = n_distinct(id) == 1) %>%
filter(!(check == TRUE & type == "Y")) %>%
select(-check)

3

以下是使用 data.table 的一行代码。

我们将 'data.frame' 转换为 'data.table' (setDT(df1)),按照 'day', 'group' 分组,if 'id' 的唯一元素的长度为 1,则获取 Data.table 的子集 (.SD) 行,其中 'type' 为 'X',否则获取 .SD

library(data.table)#v1.9.6+
setDT(df1)[, if(uniqueN(id)==1) .SD[type=='X'] else .SD, .(day, group)]
#    day group value type id
# 1:   1     A   0.1    X  1
# 2:   2     A   0.2    X  3
# 3:   3     A   0.3    X  5
# 4:   3     A   0.2    Y  6
# 5:   1     B   0.1    X  3
# 6:   2     B   0.1    X 11
# 7:   2     B   0.4    Y 10
# 8:   3     B   0.2    X 12
# 9:   1     C   0.1    X 12
#10:   2     C   0.3    X  5
#11:   3     C   0.2    X  3
#12:   3     C   0.2    Y  2

如果“类型”已按示例数据排序
unique(setDT(df1), by = c('day', 'group', 'id'))

如果没有订购,
unique(setDT(df1)[order(group,day, id, type)],by = c('day', 'group' , 'id'))

数据

df1 <- structure(list(day = c(1L, 1L, 2L, 2L, 3L, 3L, 1L, 1L, 
2L, 2L, 
3L, 3L, 1L, 1L, 2L, 2L, 3L, 3L), value = c(0.1, 0.4, 0.2, 0.5, 
0.3, 0.2, 0.1, 0.3, 0.1, 0.4, 0.2, 0.3, 0.1, 0.3, 0.3, 0.2, 0.2, 
0.2), group = c("A", "A", "A", "A", "A", "A", "B", "B", "B", 
"B", "B", "B", "C", "C", "C", "C", "C", "C"), type = c("X", "Y", 
"X", "Y", "X", "Y", "X", "Y", "X", "Y", "X", "Y", "X", "Y", "X", 
"Y", "X", "Y"), id = c(1L, 1L, 3L, 3L, 5L, 6L, 3L, 3L, 11L, 10L, 
12L, 12L, 12L, 12L, 5L, 5L, 3L, 2L)), .Names = c("day", "value", 
"group", "type", "id"), class = "data.frame", 
row.names = c(NA, -18L))

@jazzurro 谢谢,这个功能已经在一段时间前引入了。 - akrun
我觉得直到现在我才意识到自己有些落后于学习新功能。今天我会查看DT起重机手册。 - jazzurro
@jazzurro 在 dplyr 中的等效函数是 n_distinct - akrun
1
啊,我明白了。知道了。谢谢! - jazzurro

1

试试这个:

 df1 %>% group_by(day,group) %>% distinct(id)

您的原始数据已经有序,因此没有问题,否则请尝试。
df1 %>% group_by(day, group) %>%
    arrange(group, day, type) %>% distinct(id) %>%
    ungroup %>%‌ ​arrange(group, day, type, id)

这是否依赖于“type”变量按X-Y顺序排列?还是基于因子水平进行操作? - jalapic
是的,它确实需要。因此首先要调用arrange(day, group, type)函数。 - bramtayl
你的原始数据已经有序,所以没问题,否则请尝试:df1%>%group_by(day,group)%>%arrange(group,day,type)%>%distinct(id)%>%ungroup%>%arrange(group,day,type,id) - Shenglin Chen

1
这是我的解决方案,使用了 dplyr
df1%>%
group_by(day,group)%>%
mutate(len=length(unique(id))==1)%>%
filter(ifelse(len==TRUE,type=="X",type %in% c("X","Y")))

Source: local data frame [12 x 6]
Groups: day, group

   day value group type id   len
1    1   0.1     A    X  1  TRUE
2    2   0.2     A    X  3  TRUE
3    3   0.3     A    X  5 FALSE
4    3   0.2     A    Y  6 FALSE
5    1   0.1     B    X  3  TRUE
6    2   0.1     B    X 11 FALSE
7    2   0.4     B    Y 10 FALSE
8    3   0.2     B    X 12  TRUE
9    1   0.1     C    X 12  TRUE
10   2   0.3     C    X  5  TRUE
11   3   0.2     C    X  3 FALSE
12   3   0.2     C    Y  2 FALSE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接