将由两个不同的定界符分隔的字符串中的值列表转换为单独的行

dww*_*dww 5 string r data.table

我有一个看起来像这样的data.table(dt)

#    id               value
# 1:  1      {1:3.2,2:14.2}
# 2:  2      {1:14.0,2:3.0}
# 3:  3 {1:3.4,2:3.9,3:0.1}
# 4:  4             {1:2.1}
Run Code Online (Sandbox Code Playgroud)

该value列包含值列表,其中每个值由其在列表中的位置(1,2,3 ...)开头,后跟a :,然后是值本身。列表值用逗号分隔,整个列表用大括号括起来{...}。

我想将其转换为长格式(dt.all),例如

#    id N value
# 1:  1 1   3.2
# 2:  1 2  14.2
# 3:  2 1  14.0
# 4:  2 2   3.0
# 5:  3 1   3.4
# 6:  3 2   3.9
# 7:  3 3   0.1
# 8:  4 1   2.1
Run Code Online (Sandbox Code Playgroud)

各种失败的尝试包括:

stingr::str_extract(string = dt$value, pattern = "(?<=:).*(?=,)")
gsub(".*: *(.*?) *,.*", "\\1", dt$value)
gsubfn:strapplyc(dt$value, ":(.*?),", simplify = c)
Run Code Online (Sandbox Code Playgroud)

关于如何做到这一点的任何建议? data.table首选解决方案,但如果失败,将接受tidyverse或其他方法。

数据:

dt = structure(list(id = 1:4, value = c("{1:3.2,2:14.2}", "{1:14.0,2:3.0}", 
  "{1:3.4,2:3.9,3:0.1}", "{1:2.1}")), row.names = c(NA, -4L), class = c("data.table", 
    "data.frame"))

dt.all = structure(list(id = c(1L, 1L, 2L, 2L, 3L, 3L, 3L, 4L), N = c(1L, 
  2L, 1L, 2L, 1L, 2L, 3L, 1L), value = c(3.2, 14.2, 14, 3, 3.4, 
    3.9, 0.1, 2.1)), row.names = c(NA, -8L), class = c("data.table", 
      "data.frame"))
Run Code Online (Sandbox Code Playgroud)

Ron*_*hah 5

使用tidyverse函数的一种方法是{}从字符串中删除引号(),用于str_extract_all获取冒号(:)之前和之后的数字以及unnest这些值。

library(dplyr)

dt %>%
  mutate(value = gsub("\\{|\\}", "", value), 
         N = stringr::str_extract_all(value, "\\d+(?=:)"), 
         value = stringr::str_extract_all(value, "(?<=:)\\d+\\.\\d+")) %>%
  tidyr::unnest(N, value)

#  id N value
#1  1 1   3.2
#2  1 2  14.2
#3  2 1  14.0
#4  2 2   3.0
#5  3 1   3.4
#6  3 2   3.9
#7  3 3   0.1
#8  4 1   2.1
Run Code Online (Sandbox Code Playgroud)


dww*_*dww 5

我发现,如果我gsub习惯将项目编号括在引号中,那么可以使用将其解析为json表达式library(jsonlite)。

dt[, .(value = {v1 <- unlist(fromJSON(gsub("([0-9]+):", '"\\1":', value)))}, 
       N = names(v1)),by=id]

#    id value N
# 1:  1   3.2 1
# 2:  1  14.2 2
# 3:  2  14.0 1
# 4:  2   3.0 2
# 5:  3   3.4 1
# 6:  3   3.9 2
# 7:  3   0.1 3
# 8:  4   2.1 1
Run Code Online (Sandbox Code Playgroud)