【问题标题】:R:stringr - How to locate a position of a word in a string separated by semicolons?R:stringr - 如何在分号分隔的字符串中定位单词的位置?
【发布时间】:2021-12-03 23:06:05
【问题描述】:

我正在寻找以下问题的 R 解决方案:

我有一个格式如下所示的疾病注册表:

Patient Diagnosis Date of diagnosis 1 ... Date of diagnosis 47 ... Dates of diagnosis n
ID0001 C18.9 - Malignant neoplasm of colon [first disease mentioned]; Disease 2; ...; Disease n 2020-01-21 ... ... ... ...
.... ... ... ... ... ... ...
ID18000 [...]; C18.9 - Malignant neoplasm of colon [mentioned as 47th diagnosis out of 95]; [...] ... ... 2005-03-04 ... ...
ID18001 C18.9 - Malignant neoplasm of colon [the last of n mentioned] ... ... ... ... 2011-02-11

每一行(患者)都有一列,其中以分号分隔的疾病名称和每个诊断的连续列格式。

我想从这个数据集中派生一个用于特定诊断的二进制变量和带有日期的附加列(例如“结肠癌”)。为此,现在必须在 Diagnosis 列中确定疾病的位置(因为这将反映 Date 列的编号)。 如图所示,提到疾病的地方可能会有所不同,因此带有日期的列会因患者而异

我最初的想法是用分号将诊断列分开,但考虑到数据集的大小,它不是最佳的。

我想知道 stringr 包中是否有任何功能可以解决这个问题而无需进行列拆分?

感谢您的帮助!

【问题讨论】:

  • 为此我喜欢tidyr::separate_rows。例如df %>% separate_rows(Diagnosis, sep = ";"
  • 如果您的问题中有更具代表性的数据会有所帮助。我相信那里的某个地方存在专有数据,这不是我们需要的……看起来很像您的数据但没有我们无法拥有的真实数据的东西。例如,Diagnosis 可能只是 "Disease 1; Disease 2; Disease 3",而您有三个适用于它们的 Date_of_diagnosis 列。拥有至少那么多(最好是几行可能有不同数量的疾病)将非常有帮助。但我们只能猜测/假设。谢谢。
  • 至于你喜欢不把它拆分出来......这当然是可行的,但是重复提取一两个东西在很大程度上效率低下。我建议您应该考虑将您的数据架构从当前的可变宽度(具有嵌入性)重塑为单个长格式框架(它没有嵌入分号分隔的字符串中)。从长远来看,它使许多事情变得容易得多。
  • 亲爱的@r2evans 我已经修改了如上所示的示例。可能难以捕捉的重要细节是字符串中的特定诊断位置不是固定的,因为它是以随机顺序输入的。因此,患者之间的列数也会有所不同。

标签: r string dplyr stringr


【解决方案1】:

希望我理解正确,但这是我使用 dplyr 的解决方案

df <- data.frame(Patient =c("ID0001","ID0002","ID0003"),Diagnosis=c("Disease1; Disease2; Disease3"),Date_of_diagnosis1=as.Date("2020-01-21"),Date_of_diagnosis2 = as.Date("2020-01-23"),Date_of_diagnosis3=as.Date("2015-12-01"))
df %>% 
  mutate(Diagnosis = strsplit(Diagnosis, ";")) %>% 
  unnest(Diagnosis)

输出

Patient Diagnosis   Date_of_diagnosis1 Date_of_diagnosis2 Date_of_diagnosi~
  <chr>   <chr>       <date>             <date>             <date>           
1 ID0001  "Disease1"  2020-01-21         2020-01-23         2015-12-01       
2 ID0001  " Disease2" 2020-01-21         2020-01-23         2015-12-01       
3 ID0001  " Disease3" 2020-01-21         2020-01-23         2015-12-01       
4 ID0002  "Disease1"  2020-01-21         2020-01-23         2015-12-01       
5 ID0002  " Disease2" 2020-01-21         2020-01-23         2015-12-01       
6 ID0002  " Disease3" 2020-01-21         2020-01-23         2015-12-01       
7 ID0003  "Disease1"  2020-01-21         2020-01-23         2015-12-01       
8 ID0003  " Disease2" 2020-01-21         2020-01-23         2015-12-01       
9 ID0003  " Disease3" 2020-01-21         2020-01-23         2015-12-01    

【讨论】:

    【解决方案2】:

    我建议您应该将数据从这种嵌入式和宽格式转换为更简单的一次诊断/每行日期 long 格式。

    你的样本数据不多,所以这里是一些假数据,我希望它有点代表性:

    dat <- data.frame(
      Patient = c("ID0001","ID18000","ID18001"),
      Diagnosis = c("Disease1;Disease2;Disease3", "Disease2;Disease17", "Disease1;Disease4;Disease5"),
      Date_of_diagnoses1 = c("2018-01-21", "2018-01-22", "2019-01-23"),
      Date_of_diagnoses2 = c("2019-02-21", "2019-02-22", "2019-02-23"),
      Date_of_diagnoses3 = c("2020-03-21", NA, "2020-03-23")
    )
    dat
    #   Patient                  Diagnosis Date_of_diagnoses1 Date_of_diagnoses2 Date_of_diagnoses3
    # 1  ID0001 Disease1;Disease2;Disease3         2018-01-21         2019-02-21         2020-03-21
    # 2 ID18000         Disease2;Disease17         2018-01-22         2019-02-22               <NA>
    # 3 ID18001 Disease1;Disease4;Disease5         2019-01-23         2019-02-23         2020-03-23
    

    使用 tidyverse:

    library(dplyr)
    library(stringr)
    library(purrr)   # pmap_chr
    
    dat %>%
      tidyr::pivot_longer(-c(Patient, Diagnosis), names_to = "Sequence", values_to = "Date") %>%
      filter(!is.na(Date)) %>%
      mutate(
        Date = as.Date(Date),
        Sequence = as.integer(str_extract(Sequence, "[0-9]+$")),
        Diagnosis = purrr::pmap_chr(list(strsplit(Diagnosis, ";", fixed = TRUE), Sequence), `[[`)
      )
    # # A tibble: 8 x 4
    #   Patient Diagnosis Sequence Date      
    #   <chr>   <chr>        <int> <date>    
    # 1 ID0001  Disease1         1 2018-01-21
    # 2 ID0001  Disease2         2 2019-02-21
    # 3 ID0001  Disease3         3 2020-03-21
    # 4 ID18000 Disease2         1 2018-01-22
    # 5 ID18000 Disease17        2 2019-02-22
    # 6 ID18001 Disease1         1 2019-01-23
    # 7 ID18001 Disease4         2 2019-02-23
    # 8 ID18001 Disease5         3 2020-03-23
    

    关于数据的假设:

    • Date_of_diagnoses# 字段的数量始终是正确的,即,Date* 列的数量始终与 ; 中以; 分隔的诊断一样多;
    • 每个Date末尾的数字计数正确,可以用作Diagnosis上的索引;这不是一个严格的要求(解决起来并不难),但我发现使用它很方便,并且更能保证我们始终使用正确的 Date 和正确的 Diagnosis
    • Diagnosis 格式完美,没有嵌入的分号会影响提取

    一般而言,虽然这确实会延长您的数据(可能显着延长,具体取决于每位患者的诊断数量),但它也提供了更清晰的数据视图(在我看来):能够更多地提取单个疾病很容易。

    【讨论】:

      猜你喜欢
      • 2012-11-01
      • 2011-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-10
      • 2017-07-22
      • 2021-12-17
      相关资源
      最近更新 更多