将字符串解析为嵌套的data.table

时间:2018-11-13 03:55:18

标签: r data.table

我在一个表中有数据,其中每行一个单元格是一个多行字符串,其格式有点像文档的格式,在其末尾有引用。例如,这些字符串之一如下:

item A...1
item B...2
item C...3
item D...2
1=foo
2=bar
3=baz

我最终的目标是将foo / bar / baz提取到列中并计算匹配项。因此,对于以上内容,我最后要包含以下一行:

foo | bar | baz
----+-----+----
1   | 2   | 1

我试图从提取“引用”映射开始,作为一个嵌套的data.table,如下所示:

code | reason
-----+-------
1    | foo
2    | bar
3    | baz

这是我尝试使用data.tablestringr进行的操作。

encounter_alerts[, whys := lapply(
  str_extract_all(text, regex('^[0-9].*$', multiline = TRUE)),
  FUN = function (s) { fread(text = s, sep = '=', header = FALSE, col.names = c('code', 'reason')) }
)]

我对尝试执行此操作时收到的错误消息感到非常困惑:

Error in fread(text = s, sep = "=", header = FALSE, col.names = c("code",  :
  file not found: 1=foo

我明确地使用text而不是file,所以我不确定它是如何尝试将文本行解释为文件名!

当我用一行进行测试时,它似乎工作正常:

> fread(text = str_extract_all(encounter_alerts[989]$text, regex('^[0-9].*$', multiline = TRUE))[[1]], sep = '=', header = FALSE, col.names = c('code', 'reason'))
   code reason
1:    1    foo
2:    2    bar

我在做什么错?有更好的方法吗?

谢谢!

4 个答案:

答案 0 :(得分:2)

注意:阅读评论后进行了编辑

根据您的评论,我试图重现我所理解的数据。

:help :filter

代码:

:let

结果

:redir @a
:let
:redir END
:vnew
@ap
:v/qf/d

答案 1 :(得分:0)

使用stringr和dplyr可以轻松完成

library(stringr)
library(dplyr)
v <- as.data.frame(c(  "item A...1",
         "item B...2",
        "item C...3",
         "item D...2"))
colnames(v)<- "items"

matching <- c( "1",
               "2",
               "3")
Mapping <- read.table(text="code     reason
1    foo
                      2  bar
                      3  baz
                      ", header = T)

## Answer 
df1<- v %>%
  mutate(code = str_extract(v$items, str_c(matching, collapse = "|")))
str(df1)
str(Mapping)
df1$code <- as.numeric(df1$code )

df1 <- left_join(df1,Mapping)

请看看

答案 2 :(得分:0)

也许有更好的方法来执行此操作,但是这里的解决方案不需要任何其他库(除stringer外,您已经在使用)。

sample_str <- 'item A...1
item B...2
item C...3
item D...2
1=foo
2=bar
3=baz'

lines <- stringr::str_split(sample_str, '\n', simplify = T)

extracted_strs <- lines[stringr::str_detect(lines, '^\\d=\\w+$')]

dfs_list <- lapply(extracted_strs, function(x) {
  str_parts <- stringr::str_split(x, '=', simplify = T)
  df_args = list()
  df_args[[str_parts[2]]] = as.integer(str_parts[1])
  df_args[['stringsAsFactors']] = F

  do.call(data.frame, df_args)
})


df <- do.call(cbind, dfs)

答案 3 :(得分:0)

非常感谢@prosoitos提供帮助。这是我最终使用的最终代码,高度基于公认的答案-它混合了不同的程序包等,我希望最终清除它们,但最后期限会出现...

get_code_reason_mapping <- function(alert_text) {
  alert_text %>%
    str_extract_all(regex('^[0-9]=(.*)$', multiline = T)) %>%
    unlist() %>%
    str_split_fixed("=", 2) %>%
    as.data.table() %>%
    setnames(c('code', 'reason'))
}

encounter_alerts$code_reason_mapping <- map(encounter_alerts$alert_text, get_code_reason_mapping)

get_why_codes <- function(alert_text) {
  alert_text %>%
    str_extract_all(regex('[/n][0-9e][0-9>][0-9]$', multiline = TRUE)) %>%
    unlist() %>%
    str_sub(-1) %>%
    as.data.table() %>%
    setnames(c('code'))
}

encounter_alerts$why_codes <- map(encounter_alerts$alert_text, get_why_codes)

get_code_counts <- function(df1, df2) {
  left_join(df1, df2) %>%
    count(reason) %>%
    spread(reason, n)
}

code_counts <- map2_df(encounter_alerts$code_reason_mapping, encounter_alerts$why_codes, get_code_counts)

code_counts[is.na(code_counts)] <- 0

code_counts