将列分成单列并格式化条目

Separating column into single column and formating the entries

我有一个包含两列(idinfo)的庞大数据 table,我想将 separate/split 列 info 分成单列并格式化它们。 这是一个示例,我的数据 table 的条目如下所示:

id <- c(8750, 3048, 3593, 8475, 9921)
info <- c("[J/B][10,00/10,00][1,500/1,500][1,00]", "[J*/POP][0,00/0,00/0,00/0,00][2,210/2,210/2,210/2,210][1,50]", "S", "KEINE",
          "[Q*/B][5,00/5,00][1,500/1,500][0,70]")
dt.test <- data.table(id, info)
dt.test
#   id                                                         info
# 8750                        [J/B][10,00/10,00][1,500/1,500][1,00]
# 3048 [J*/POP][0,00/0,00/0,00/0,00][2,210/2,210/2,210/2,210][1,50]
# 3593                                                            S
# 8475                                                        KEINE
# 9921                         [Q*/B][5,00/5,00][1,500/1,500][0,70]

最后我需要一个 table,其中 info 列被分成六个单独的列(idtypepBupBozTBuzTBozV) 并将它们格式化如下:

#   id   type pBu pBo zTBu zTBo  zV
# 8750    J/B  10  10 1.50 1.50 1.0
# 3048 J*/POP   0   0 2.21 2.21 1.5
# 3593      S  NA  NA   NA   NA  NA
# 8475  KEINE  NA  NA   NA   NA  NA
# 9921   Q*/B   5   5 1.50 1.50 0.7

只是对开头的 info 专栏和结尾数据 table 的一些解释:

  1. separate 括号
  2. 取第一部分和最后一部分(mutateword
  3. ,. (map_df)
  4. 清理左括号(第二个map_df
  5. select保持正确的顺序 列
library(tidyr)
library(stringr)
library(purrr)
dt.test %>% 
  separate(info, into = c('type', 'pBu - pBo', 'zTBu - zTBo',  'zV'), 
           sep = "\]|\/ " , 
           remove = T) %>% 
  mutate('pBu' = word(`pBu - pBo`,1, sep = "\/"),
         'pBo' = word(`pBu - pBo`,-1, sep = "\/"),
         'pBu - pBo' = NULL,
         
         'zTBu' = word(`zTBu - zTBo`,1, sep = "\/"),
         'zTBo' = word(`zTBu - zTBo`,-1, sep = "\/"),
         'zTBu - zTBo' = NULL) %>% 
  map_df(~ gsub(",", ".", .x)) %>%
  map_df(~ gsub("\[", "", .x)) %>% 
  select(id ,  type, pBu, pBo, zTBu, zTBo,  zV) ## %>% as.data.table


output
# A tibble: 5 x 7
  id    type   pBu   pBo   zTBu  zTBo  zV   
  <chr> <chr>  <chr> <chr> <chr> <chr> <chr>
1 8750  J/B    10.00 10.00 1.500 1.500 1.00 
2 3048  J*/POP 0.00  0.00  2.210 2.210 1.50 
3 3593  S      NA    NA    NA    NA    NA   
4 8475  KEINE  NA    NA    NA    NA    NA   
5 9921  Q*/B   5.00  5.00  1.500 1.500 0.70 

%>% as.data.table最后,允许你保持data.table形式

您的代码可以组合内置函数 gsubdata.table 中的函数 tstrsplit。如果您想按照评论 中的要求将缺失值设置为 0,您只需将函数 tstrsplit 中的参数 fill 设置为 0。假设您保留了 data.table 很大,请注意这个答案比@dy_by 提出的答案要快得多(在我的机器上大约快 23 倍)。

此解决方案需要 R 版本 4.1.0

cols <- c("type", "pBu", "pBo", "zTBu", "zTBo", "zV")

dt.test[, (cols) := gsub(",", ".", info, fixed=TRUE) |>
                    gsub(pattern="^\[|\]$", replacement="") |> 
                    gsub(pattern="/[0-9./]+/", replacement="/") |> 
                    tstrsplit("\]\[|/(?=\d)", perl=TRUE, type.convert=TRUE)]


dt.test[, !"info"]
#       id   type   pBu   pBo  zTBu  zTBo    zV
# 1:  8750    J/B    10    10  1.50  1.50   1.0
# 2:  3048 J*/POP     0     0  2.21  2.21   1.5
# 3:  3593      S    NA    NA    NA    NA    NA
# 4:  8475  KEINE    NA    NA    NA    NA    NA
# 5:  9921   Q*/B     5     5  1.50  1.50   0.7

更新

这是要纳入评论的更新。它旨在用于早于 4.1.0

的 R 版本
dt.test[, (cols) := {x <- gsub(",", ".", info, fixed=TRUE)
                     x <- gsub("^\[|\]$", "", x)
                     x <- gsub("/[0-9./]+/", "/", x)
                     tstrsplit(x, "\]\[|/(?=\d)", perl=TRUE, type.convert=TRUE)}]