R语言 从cvs文件中的自由文本列提取多个值

6ljaweal  于 2023-03-15  发布在  其他
关注(0)|答案(2)|浏览(135)

我有一个CVS文件,其中一列包含一系列医学测试,这些测试是自由文本格式的,带有日期、测试名称和结果,如下所示。我需要提取每个医学测试的值,并将它们转换为列。我想知道是否有一种方法可以做到这一点,而不必训练NLP模型来提取这些信息。
| 患者|结果|
| - ------|- ------|
| 1个|“2022年1月3日- HMG -斑块:65000 2022年1月3日- HMG -血红蛋白:7.8 2022年1月5日-尿素:50.0 2022年1月5日- HMG -斑块:八万”|
| 第二章|“2022年1月6日- ALT/白芍总苷:25.0 2022年6月1日- AST/总 MOXy :40.0 2022年6月3日-胆红素:0.8英寸|
| 三个|“2022年1月3日- HMG -红细胞压积:40 2022年1月3日- HMG -血红蛋白:10.2英寸|
CSV:

Patient;Results 
1;"01/03/2022 - HMG - Plaques: 65000 01/03/2022 - HMG - Haemoglobin: 7.8 01/05/2022 - Urea: 50.0 01/05/2022 - HMG - Plaques: 80000" 
2;"06/01/2022 - ALT/TGP: 25.0 06/01/2022 - AST/TGO: 40.0 06/03/2022 - Bilirrubin: 0.8" 
3;"01/03/2022 - HMG - Haematocrit: 40 01/03/2022 - HMG - Haemoglobin: 10.2"
31moq8wy

31moq8wy1#

假设DF的定义可重复,如结尾注解所示,在每个日期前插入一个新行,分成不同的行,将日期和检测项分开,然后将检测项和值分开。

library(dplyr)
library(tidyr)

DF %>%
  mutate(Results = gsub(" (../../....)", "\n\\1", Results)) %>%
  separate_rows(Results, sep = "\n") %>%
  separate(Results, c("Date", "Test"), sep = " - ", extra = "merge") %>%
  separate(Test, c("Test", "Value"), sep = ": ", convert = TRUE)

给出:

# A tibble: 9 × 4
  Patient Date       Test                Value
    <int> <chr>      <chr>               <dbl>
1       1 01/03/2022 HMG - Plaques     65000  
2       1 01/03/2022 HMG - Haemoglobin     7.8
3       1 01/05/2022 Urea                 50  
4       1 01/05/2022 HMG - Plaques     80000  
5       2 06/01/2022 ALT/TGP              25  
6       2 06/01/2022 AST/TGO              40  
7       2 06/03/2022 Bilirrubin            0.8
8       3 01/03/2022 HMG - Haematocrit    40  
9       3 01/03/2022 HMG - Haemoglobin    10.2

注解

Lines <- 'Patient;Results 
1;"01/03/2022 - HMG - Plaques: 65000 01/03/2022 - HMG - Haemoglobin: 7.8 01/05/2022 - Urea: 50.0 01/05/2022 - HMG - Plaques: 80000" 
2;"06/01/2022 - ALT/TGP: 25.0 06/01/2022 - AST/TGO: 40.0 06/03/2022 - Bilirrubin: 0.8" 
3;"01/03/2022 - HMG - Haematocrit: 40 01/03/2022 - HMG - Haemoglobin: 10.2"'
DF <- read.csv2(text = Lines)
lkaoscv7

lkaoscv72#

我会使用正则表达式(regex),如果你在R中使用stringr包,它非常适合,如果你想提取所有的日期,你可以这样做:

library(stringr)
library(magrittr) # for pipes

"01/03/2022 - HMG - Plaques: 65000 01/03/2022 - HMG - Haemoglobin: 7.8 01/05/2022 - Urea: 50.0 01/05/2022 - HMG - Plaques: 80000" %>%
str_extract_all("[0-9]{1,2}/[0-9]{1,2}/[0-9]{2,4}")

如果您想提取第一个和第二个日期之间的所有内容(不包括日期),您可以执行以下操作:

"01/03/2022 - HMG - Plaques: 65000 01/03/2022 - HMG - Haemoglobin: 7.8 01/05/2022 - Urea: 50.0 01/05/2022 - HMG - Plaques: 80000" %>%
  str_extract("(?<=[0-9]{1,2}/[0-9]{1,2}/[0-9]{2,4}).*?(?=[0-9]{1,2}/[0-9]{1,2}/[0-9]{2,4})")

要删除从第一个日期(含)到第二个日期(不含)的所有内容,您可以执行以下操作:

"01/03/2022 - HMG - Plaques: 65000 01/03/2022 - HMG - Haemoglobin: 7.8 01/05/2022 - Urea: 50.0 01/05/2022 - HMG - Plaques: 80000" %>%
  str_extract("[0-9]{1,2}/[0-9]{1,2}/[0-9]{2,4}.*?(?=[0-9]{1,2}/[0-9]{1,2}/[0-9]{2,4})")

您可以保存提取的文本,然后从更大的字符串中删除它,如下所示:

first_result <- "01/03/2022 - HMG - Plaques: 65000 01/03/2022 - HMG - Haemoglobin: 7.8 01/05/2022 - Urea: 50.0 01/05/2022 - HMG - Plaques: 80000" %>%
  str_extract("[0-9]{1,2}/[0-9]{1,2}/[0-9]{2,4}.*?(?=[0-9]{1,2}/[0-9]{1,2}/[0-9]{2,4})")

"01/03/2022 - HMG - Plaques: 65000 01/03/2022 - HMG - Haemoglobin: 7.8 01/05/2022 - Urea: 50.0 01/05/2022 - HMG - Plaques: 80000" %>%
  str_remove(first_result)

您可以执行一系列的提取操作,直到将所有结果分解为单个测试。完成这些操作后,还可以使用类似的正则表达式提取测试名称和值。例如:

first_date <- first_result %>% str_extract("[0-9]{1,2}/[0-9]{1,2}/[0-9]{2,4}")
first_test_name <- first_result %>% str_extract("(?<=-).*(?=:)")
first_result_value <- first_result %>% str_extract("(?<=:).*")

stringr包也适用于vector/datafame列,例如:

c("a2bc","dfr4","5qwer") %>% str_extract("[0-9]")

str_extract_all()返回一个列表,因此需要考虑这个问题。根据您的需要,有时最简单的方法是使用unlist()将提取值的列表转换为向量。
使用str_squish()可以删除多余白色。stringr包中有大量其他函数,根据您希望数据最终采用的格式,可以使用正则表达式完成其他任务。对于我使用稍微复杂一些的环视模式所做的事情,可能有更有效的方法。您还可以使用sub()gsub()执行类似于stringr包对base r执行的操作。
有一堆regex资源在线和堆栈溢出有一堆regex的问题和答案了!

相关问题