【问题标题】:Filter groups of df when each row of group fulfills the condition in at least N columns当组的每一行至少满足 N 列中的条件时过滤 df 组
【发布时间】:2017-11-23 11:40:41
【问题描述】:

我的 df 有个小问题。首先,我将向您展示一个示例,然后说明我想收到什么。

我的输入df:

C1  C2  C3  C4  C5  C6  C7  C8
A   I   I   D   X   I   I   I
A   I   I   I   X   D   I   I
A   I   I   I   X   I   I   I
A   I   D   I   X   NC  I   I
B   D   D   I   X   I   I   I
B   D   I   NC  X   I   I   D
C   NC  I   I   X   NC  D   I
C   I   I   I   X   I   I   I
C   I   I   I   X   I   I   D
D   NC  NC  I   X   D   D   D
D   I   I   I   X   D   D   I
D   D   D   I   X   I   I   NC
D   I   I   I   X   NC  I   I
E   NC  I   I   X   I   I   D
E   I   I   I   X   I   D   D

想要的结果:

C1  C2  C3  C4  C5  C6  C7  C8
A   I   I   D   X   I   I   I
A   I   I   I   X   D   I   I
A   I   I   I   X   I   I   I
A   I   D   I   X   NC  I   I

我希望只有组 (group by column 'C1')(所有行)在每行组中至少 2 次出现 'I'(让我们以 @987654325 @) 在组列中 C2, C3, C4 和 C6, C7, C8。

我决定使用filter()、all() 和rowSums()

 df_filtered <- df %>%
  group_by(C1) %>%
  filter(all(rowSums(df[,2:4] == 'I' & df[,6:8] == 'I') >= 2))

什么不起作用?它返回 0 行,不知道为什么......

【问题讨论】:

  • 为什么要排除C-rows 8 和 9,以及E-row 14?他们在组列C2, C3, C4 和C6, C7, C8 中也至少有2 个I。
  • 如果C2, C3, C4 或C6, C7, C8 列中有一个或更少的I,尽管在一行中,整个组都被丢弃。 C 组在第 7 行,C6, C7 列中有 NC 和 D。如果我们使用I 而不是NC 或D 或两者兼而有之,则整个组都应该通过过滤器。

标签: r dplyr apply


【解决方案1】:

解决方案

df %>%
    mutate(condition = rowSums(.[2:4] == 'I') >= 2 & rowSums(.[6:8] == 'I') >= 2) %>%
    group_by(C1) %>%
    filter(all(condition)) %>%
    select(-condition)

结果

# A tibble: 4 x 8
# Groups:   C1 [1]
      C1     C2     C3     C4     C5     C6     C7     C8
  <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr>
1      A      I      I      D      X      I      I      I
2      A      I      I      I      X      D      I      I
3      A      I      I      I      X      I      I      I
4      A      I      D      I      X     NC      I      I

说明

你使用的时候

filter(all(rowSums(df[,2:4] == 'I' & df[,6:8] == 'I') >= 2))

all() 比较是在df 的所有 行上进行的,而不仅仅是您组中的那些。此方法评估每一行的条件,然后仅在组上调用 all()。

【讨论】:

  • 是的,这就是我一直在寻找的答案,效果很好,非常感谢!
  • 很高兴它有帮助!
【解决方案2】:

您可以尝试使用unite(),然后通过正则表达式进行过滤。这是你的例子:

library(tidyverse)

# First loading your data 
data <-read.table(text = "C1  C2  C3  C4  C5  C6  C7  C8
A   I   I   D   X   I   I   I
A   I   I   I   X   D   I   I
A   I   I   I   X   I   I   I
A   I   D   I   X   NC  I   I
B   D   D   I   X   I   I   I
B   D   I   NC  X   I   I   D
C   NC  I   I   X   NC  D   I
C   I   I   I   X   I   I   I
C   I   I   I   X   I   I   D
D   NC  NC  I   X   D   D   D
D   I   I   I   X   D   D   I
D   D   D   I   X   I   I   NC
D   I   I   I   X   NC  I   I
E   NC  I   I   X   I   I   D
E   I   I   I   X   I   D   D", header = T)

# Then filtering rows
data %>% 
  # Creating a helper column
  unite(merged, C1:C8, sep = "", remove = F) %>%
  # Filtering by regexp
  filter(grepl("^A", merged), grepl("II", merged)) %>%
  # Deleting helper column
  select(-merged)

这是结果:

  C1 C2 C3 C4 C5 C6 C7 C8
1  A  I  I  D  X  I  I  I
2  A  I  I  I  X  D  I  I
3  A  I  I  I  X  I  I  I
4  A  I  D  I  X NC  I  I

玩得开心;)

【讨论】:

  • 这个解决方案的前提是 OP 已经知道只有组 A 会在结果中。它还假设每次在三个变量分组中都有两个I,其中至少有一个是连续的。例如,它不会捕获 merged 等于 AIDIXIDI 的行,即使这将匹配 OP 的条件。
猜你喜欢
  • 2022-12-21
  • 1970-01-01
  • 2021-11-04
  • 1970-01-01
  • 2019-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多