【问题标题】:Manipulating variables to produce a new dataset in R操作变量以在 R 中生成新数据集
【发布时间】:2018-05-23 06:01:43
【问题描述】:

我是一个相对较新的 R 用户。我非常感谢您对我的数据集的任何帮助。

我有一个包含 2400 万行的数据集。数据集中有 3 个变量:患者姓名、药房名称和就诊时从药房取药的数量。

有些患者不止一次出现在数据集中(即他们在不同时间点从不同药房取药)。

数据框如下所示:

df <- data.frame(name = c("Tom", "Rob", "Tom", "Tom",  "Amy"), 
                 pharmacy = c("A", "B", "B", "B", "C"), 
                 meds = c(3, 2, 5, 8, 2))

我想根据这些数据生成一个新数据集,其中每个患者都有一个药房。该药房必须是患者服用最多药物的药房。

例如:对于汤姆来说,他最常去的药房是药房 B,因为他从那里买了 13 种药物(5+8 种药物)。我要生成的数据集:

data.frame(name = c("Tom", "Rob",  "Amy"), 
           pharmacy = c("B", "B", "C"), 
           meds = c(13, 2, 2))

有人可以帮我写一个代码来做到这一点吗? 我尝试了 R 中的各种功能,例如dplyrtidyraggregate(),但均未成功。任何帮助将不胜感激。

非常感谢

亚历克斯

【问题讨论】:

    标签: r dplyr tidyr


    【解决方案1】:

    您的问题不可重现。但这里有一个解决方案:

    # create reproducible example of data 
    dataset1 <- data.frame( 
    name = c("Tom", "Rob", "Tom", "Tom", "Amy"), 
    pharmacy = c("pharmacy_A", "pharmacy_B", "pharmacy_B", "pharmacy_B", "pharmacy_C"),  
    meds_count = c(3, 2, 5, 8, 2))
    
    library(dplyr) #load dplyr
    
    dataset2 <- dataset1 %>% group_by(name, pharmacy) %>% # group by your grouping variables
                       summarise(meds_count = sum(meds_count)) %>% # sum no. of meds by your grouping variables
                       top_n(1, meds_count) %>% # filter for only the top 1 count
                       ungroup()
    

    结果数据框:

    > dataset2
    # A tibble: 3 x 3
      name  pharmacy   meds_count
      <fct> <fct>           <dbl>
    1 Amy   pharmacy_C       2.00
    2 Rob   pharmacy_B       2.00
    3 Tom   pharmacy_B      13.0 
    

    【讨论】:

    • 非常感谢您的回复和帮助。这行得通!我真的很感激
    • 很高兴听到这个消息。考虑接受答案。请注意,您的答案已经包含在您的问题中,您只需将其翻译为dplyr 动词:将我的数据按每个患者的一家药房分组;通过汇总药物数量来按组汇总数据;从结果数据中,只为每个患者/药房组选择前一个结果。
    【解决方案2】:

    如果我理解正确,我想你正在寻找这样的东西。

    require(tidyverse)
    #Sample data. I copied yours. 
    df <- data.frame(name = c("Tom", "Rob", "Tom", "Tom",  "Amy"), 
                     pharmacy = c("A", "B", "B", "B", "C"), 
                     meds = c(3, 2, 5, 8, 2))
    

    编辑。我更改了 group_by()、summarise() 并添加了过滤器。

    df %>% 
      group_by(name, pharmacy) %>%
      summarise(SumMeds = sum(meds, na.rm = TRUE)) %>% 
      filter(SumMeds == max(SumMeds))
    

    结果:

      name  pharmacy SumMeds
      <fct> <fct>      <dbl>
    1 Amy   C             2.
    2 Rob   B             2.
    3 Tom   B            13.
    

    【讨论】:

    • 结果与OP请求不一样
    • Tom - B - 8 + 5 = 13。需要按名称和药房分组
    【解决方案3】:

    生成数据集:

    patient = c("Tom","Rob","Tom","Tom","Amy")
    pharmacy = c("A","B","B","B","C")
    meds = c(3,2,5,8,2)
    df = data.frame(patient,pharmacy,meds)
    

    df 是你的数据框

    library(dplyr)
    
    df = df %>% group_by(patient,pharmacy) %>% 
    summarize(meds =sum(meds)) %>% 
    group_by(patient) %>% 
    filter(meds == max(meds))
    
    • 按照患者和药房分组 df
    • 通过服用药物的总和计算每个患者从不同药店购买的药物总数。
    • 然后按患者分组
    • 最终筛选出最大值。

    打印数据框

    print(df)

    【讨论】:

      【解决方案4】:

      您可以在基础 R 中使用 aggregate 两次,然后是 merge
      在我看来,必须使用两次aggregate 有点复杂。也许dplyr 解决方案运行得更快,尤其是对于包含 2400 万行的数据集。

      agg <- aggregate(meds ~ name + pharmacy, df, FUN = function(x) sum(x))
      agg2 <- aggregate(meds ~ name, agg, function(x) x[which.max(x)])
      merge(agg, agg2)[c(1, 3, 2)]
      #  name pharmacy meds
      #1  Amy        C    2
      #2  Rob        B    2
      #3  Tom        B   13
      

      数据。
      这是编辑后问题中的数据集。

      df <- data.frame(name = c("Tom", "Rob", "Tom", "Tom",  "Amy"), 
                       pharmacy = c("A", "B", "B", "B", "C"), 
                       meds = c(3, 2, 5, 8, 2), stringsAsFactors = FALSE)
      

      【讨论】:

      • 你可以使用"\\D"作为你的正则表达式。
      • 结果与OP请求不一样
      • @AndreElrico 谢谢。已更正。
      【解决方案5】:

      假设以下数据集:

      df <- tribble(
        ~patient, ~pharmacy, ~medication,  
        "Tom", "Pharmacy A", "3 meds",
        "Rob", "Pharmacy B", "2 meds",
        "Tom", "Pharmacy B", "5 meds",
        "Tom", "Pharmacy B", "8 meds",
        "Amy", "Pharmacy C", "2 meds"
      )
      

      一个 tidyverse 友好的选项可能是:

      df %>% 
        mutate(med_n = as.numeric(str_extract(medication, "[0-9]"))) %>%  # 1
        group_by(patient, pharmacy) %>%  # 2
        mutate(med_sum = sum(med_n)) %>%  # 3
        group_by(patient) %>%  # 4
        filter(med_sum == max(med_sum)) %>%  # 5
        select(patient, pharmacy, med_sum) %>%  # 6
        distinct() # 7
      
      1. 创建一个数字变量,因为您不能添加字符串
      2. 在所有患者/药房夫妇中
      3. 查找药物总数
      4. 然后在所有患者中
      5. 只保留患者/药品总数最高的药房
      6. 丢弃无用的变量
      7. 丢弃重复的行(每个患者/药房夫妇多行)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-01-06
        • 2011-03-23
        • 2015-10-05
        • 1970-01-01
        • 2015-03-19
        • 2017-11-21
        • 1970-01-01
        • 2018-08-12
        相关资源
        最近更新 更多