R dplyr基于组和列进行有条件聚合

时间:2019-07-29 16:07:30

标签: r dplyr

我有一个包含受试者ID的数据集,我在其中根据不同的标准(“指标”)每小时进行一次测量。这些指标中的每一个都符合或不符合法规遵从性(1表示是,0表示否)。我有两个目标:

任务

(1)确定“完全合规”,即受试者每小时的每个度量标准都为1。如果为零,则表示该对象不符合“完全合规性”。

(2)确定每个主题的依从百分比。即如果受试者的3/4小时全为1,则表示他们符合75%的要求。

我想使用dplyrfilter()的组合或一些我可能不熟悉的聚合函数来解决这个问题。

示例

这是一个示例数据集:

df <- data.frame(
  "Subject ID" = c("A", "A", "A", "A", "B", "B", "B", "B", "C", "C", "C", "C"),
  "Metric 1" = rep("value", 12),
  "Compliance 1" = rep(1, 12),
  "Metric 2" = rep("value", 12),
  "Compliance 2" = c(1,1,1,1,1,0,1,1,1,1,1,1),
  "Metric 3" = rep("value", 12),
  "Compliance 3" = c(1,1,1,1,0,1,1,1,1,1,1,1)
)

这就是我想使用dplyr来实现点(1)的目的:

df2 <- data.frame(
  "Subject ID" = c("A", "A", "A", "A", "C", "C", "C", "C"),
  "Metric 1" = rep("value", 8),
  "Compliance 1" = rep(1, 8),
  "Metric 2" = rep("value", 8),
  "Compliance 2" = rep(1, 8),
  "Metric 3" = rep("value", 8),
  "Compliance 3" = rep(1, 8)
)

对于(2),我想汇总数据以显示主题(A)符合100%,而(B)符合50%。

修改后的答案

感谢tmfmnk,我能够使用以下方法获得压缩百分比:

df %>%
  mutate(cond = rowMeans(select(., starts_with("Compliance"))) == 1) %>%
  group_by(Subject.ID) %>% 
  tally(cond) %>% 
  mutate(perc = n/4)

  Subject.ID     n  perc
  <fct>      <int> <dbl>
1 A              4   1  
2 B              2   0.5
3 C              4   1  

2 个答案:

答案 0 :(得分:2)

一种可能是:

df %>%
 mutate(cond = rowMeans(select(., starts_with("Compliance"))) == 1) %>%
 group_by(Subject.ID) %>%
 filter(all(cond)) %>%
 select(-cond)

      Subject.ID Metric.1 Compliance.1 Metric.2 Compliance.2 Metric.3 Compliance.3
    1          A    value            1    value            1    value            1
    2          A    value            1    value            1    value            1
    3          A    value            1    value            1    value            1
    4          A    value            1    value            1    value            1
    5          C    value            1    value            1    value            1
    6          C    value            1    value            1    value            1
    7          C    value            1    value            1    value            1
    8          C    value            1    value            1    value            1

如果需要百分比,则可以执行以下操作:

df %>%
 mutate(cond = rowMeans(select(., starts_with("Compliance")))) 

   Subject.ID Metric.1 Compliance.1 Metric.2 Compliance.2 Metric.3 Compliance.3      cond
1           A    value            1    value            1    value            1 1.0000000
2           A    value            1    value            1    value            1 1.0000000
3           A    value            1    value            1    value            1 1.0000000
4           A    value            1    value            1    value            1 1.0000000
5           B    value            1    value            1    value            0 0.6666667
6           B    value            1    value            0    value            1 0.6666667
7           B    value            1    value            1    value            1 1.0000000
8           B    value            1    value            1    value            1 1.0000000
9           C    value            1    value            1    value            1 1.0000000
10          C    value            1    value            1    value            1 1.0000000
11          C    value            1    value            1    value            1 1.0000000
12          C    value            1    value            1    value            1 1.0000000

要获得每组满足条件的案件的百分比(由@ rsh52提议):

df %>%
 mutate(cond = rowMeans(select(., starts_with("Compliance"))) == 1) %>%
 group_by(Subject.ID) %>% 
 tally(cond) %>% 
 mutate(perc = n/4)

  Subject.ID     n  perc
  <fct>      <int> <dbl>
1 A              4   1  
2 B              2   0.5
3 C              4   1  

答案 1 :(得分:1)

这个答案有点冗长,但是逻辑应该很容易遵循-将每个合规性列的1求和,计算合规性百分比,在3个合规性列中删除<100%遵从性的主题。然后从原始数据框中过滤掉那些主题。

compliant <- df %>% select(Subject.ID,matches('Compliance')) %>% 
  gather(k,v,-Subject.ID) %>% 
  group_by(Subject.ID,k) %>% 
  summarise(sum=sum(v),n=n()) %>% 
  group_by(Subject.ID,k) %>%
  mutate(perc=sum/sum(n)) %>% 
  group_by(Subject.ID) %>% summarise(c=sum(perc)) %>% 
  filter(c==3)

# A tibble: 2 x 2
  Subject.ID     c
  <fct>      <dbl>
1 A              3
2 C              3

df %>% filter(Subject.ID %in% compliant$Subject.ID)

  Subject.ID Metric.1 Compliance.1 Metric.2 Compliance.2 Metric.3 Compliance.3
1          A    value            1    value            1    value            1
2          A    value            1    value            1    value            1
3          A    value            1    value            1    value            1
4          A    value            1    value            1    value            1
5          C    value            1    value            1    value            1
6          C    value            1    value            1    value            1
7          C    value            1    value            1    value            1
8          C    value            1    value            1    value            1