【问题标题】:Summarizing a collection of data frames - improving upon a clumsy solution总结一组数据框——改进一个笨拙的解决方案
【发布时间】:2021-05-29 23:33:28
【问题描述】:

我有一组数据框,df_i,代表一组患者第 i 次到医院就诊。我想总结每个数据框以确定第 i 次访问的男性、女性和患者总数。虽然我可以解决这个问题,但我的解决方案很笨拙。有没有更简单的方法来获得我想要的最终数据框?示例如下:

df_1 <- data.frame(
  ID     = c(rep("A",4), rep("B",3), rep("C",2), "D"),
  Dates  = seq.Date(from = as.Date("2020-01-01"), to = as.Date("2020-01-10"), by = "day"),
  Sex    = c(rep("Male",4), rep("Male",3), rep("Female",2), "Female"),
  Weight = seq(100, 190, 10),
  Visit  = rep(1, 10)
)

df_2 <- data.frame(
  ID     = c(rep("A",4), rep("B",3), rep("C",2)),
  Dates  = seq.Date(from = as.Date("2020-02-01"), to = as.Date("2020-02-9"), by = "day"),
  Sex    = c(rep("Male",4), rep("Male",3), rep("Female",2)),
  Weight = seq(100, 180, 10),
  Visit  = rep(2, 5)
)

df_3 <- data.frame(
  ID     = c(rep("A",4), rep("B",3)),
  Dates  = seq.Date(from = as.Date("2020-03-01"), to = as.Date("2020-03-07"), by = "day"),
  Sex    = rep("Male",7),
  Weight = seq(140, 200, 10),
  Visit  = rep(3, 7)
)

我希望生成以下结果:

> df_sum
  Visit Patients Men Women
1     1        4   2     2
2     2        3   2     1
3     3        2   2     0

我可以用一种很笨拙的方式来做:首先创建一个临时数据框,总结df_1中的信息

df_tmp <- df_1 %>%
            group_by(ID) %>%
            filter(Dates == min(Dates)) %>%
            summarize(n = n(), Men = sum(Sex == "Male"), Women = sum(Sex == "Female"))
> df_tmp
# A tibble: 4 x 4
  ID        n   Men Women
  <chr> <int> <int> <int>
1 A         1     1     0
2 B         1     1     0
3 C         1     0     1
4 D         1     0     1

接下来,对df_tmp 中的每一列求和,以创建汇总列的第一行。

r1 <- c(sum(df_tmp$n), sum(df_tmp$Men), sum(df_tmp$Women))

重复第二个和第三个数据帧。最后 rbind 将这些行组合在一起以创建汇总数据框。虽然这可行,但它非常笨拙,并且不能概括为访问次数可变的情况。有人会为我的问题指出一个更优雅的解决方案吗?

在此先感谢

托马斯·飞利浦

【问题讨论】:

    标签: r dataframe summarize


    【解决方案1】:

    也可以用bind_rows做成一个tibble:

    library(tidyverse)
    bind_rows(df_1, df_2, df_3, .id = "day") %>%
      group_by(day, ID) %>%
      slice_min(Dates) %>%
      group_by(day) %>%
      summarize(n = n(), Men = sum(Sex == "Male"), Women = sum(Sex == "Female"))
    

    结果

    # A tibble: 3 x 4
      day       n   Men Women
    * <chr> <int> <int> <int>
    1 1         4     2     2
    2 2         3     2     1
    3 3         2     2     0
    

    【讨论】:

    • 这个简单干净。我想slice_min 也可以实现为filter(Dates == min(Dates)),我也只是选择不添加 id 列,而只是使用Visit 进行分组。谢谢。
    【解决方案2】:

    将数据放入列表并通过map 对其进行迭代,这样您就不必为每个数据帧重复代码。使用janitor::adorn_totals,您可以在输出中添加一个包含总计的新行并获取宽格式数据。

    library(tidyverse)
    
    list_df <- list(df_1, df_2, df_3)
    
    map_df(list_df, ~.x %>% 
                  group_by(ID) %>%
                  filter(Dates == min(Dates)) %>%
                  ungroup %>%
                  count(Sex) %>%
                  janitor::adorn_totals(name = 'Patients'), .id = 'Visit') %>%
      pivot_wider(names_from = Sex, values_from = n, values_fill = 0)
    
    #  Visit Female  Male Patients
    #  <chr>  <int> <int>    <int>
    #1 1          2     2        4
    #2 2          1     2        3
    #3 3          0     2        2
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多