【问题标题】:Separating column into single column and formating the entries将列分成单列并格式化条目
【发布时间】:2021-08-04 07:10:25
【问题描述】:

我有一个包含两列(idinfo)的巨大数据表,我想将 info 列分隔/拆分为单列并格式化它们。 这是一个示例,我的数据表的条目如下所示:

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]

最后我需要一个表,其中info 列分为六个单列(idtypepBupBozTBuzTBo 和 @987654332 @) 并将它们格式化如下:

#   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 列以及最终数据表的外观进行一点解释:

  • info 列中的所有逗号 , 必须替换为点 .(请参阅我的最终数据表)。
  • 第一个括号[] 的输入定义了我的新type 列,此外,如果info 列填充“S”或“KEINE”,这也必须是@ 的条目987654341@专栏。
  • 第二个括号[] 的输入定义了新列pBu(第一个元素)和pBo(最后一个元素)。
  • 第三个括号[] 的输入定义了新列zTBu(第一个元素)和zTBo(最后一个元素)。
  • 第四个括号[] 的输入定义了zV 列。
  • type 列有条目“S”或“KEINE”时,其余列必须用NAs 填充。

【问题讨论】:

    标签: r split datatable formatting


    【解决方案1】:
    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 
    

    %&gt;% as.data.table结尾,让你保持data.table形式

    【讨论】:

    • 感谢您的回答。你的代码对我有用,但它也会引发两个警告:1: Expected 4 pieces. Additional pieces discarded in 3 rows [1, 2, 5]. 2: Expected 4 pieces. Missing pieces filled with `NA` in 2 rows [3, 4].
    • 不用担心这个。这是正确的行为。首先:discarded 在最后一个] 之后抛出了一部分 - 在你的情况下,它只是什么都不丢弃,直到最后一个右括号之后什么都没有。第二:第3和第4行只有一个值(S,KEINE);函数需要 4 个值,所以它们是 filled by NAs
    • 好的!第二个警告没问题,因为我想要这些NAs。如果我想用0s 替换NAs 怎么办???
    • 在变异后添加%&gt;% replace_na(list(type = 0, `pBu - pBo` = 0, `zTBu - zTBo` = 0, zV = 0))separate%&gt;% replace_na(list(type = 0, pBu = 0, pBo = 0, zTBu = 0, zTBo = 0, zV = 0))
    • 谢谢你的回答:)
    【解决方案2】:

    您的代码可以结合内置函数gsub 和来自data.table 的函数tstrsplit。如果您想按照评论HERE 中的要求将缺失值设置为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)}]
    

    【讨论】:

    • 您的代码对我不起作用。在每一行中,|&gt; 带有红色下划线并引发错误...
    • 那是因为你的 R 没有更新。原生管道|&gt; 需要 R 版本 4.1.0,这是 R 的当前版本。此解决方案不适用于旧版本,除非您更新 R 或将解决方案调整为旧版本。有两种方法可以使其适应旧版本:1-将 |&gt; 替换为 %&gt;% 包中的 magrittr 或 2-查看更新的解决方案。查看以下内置变量的值以了解您正在使用的 R 版本:R.version.string。如果您选择更新您的 R,最好也更新 R Studio,以便它能够解决此更改
    • 让我知道您正在使用的 R 版本。另外,测试新代码并告诉我它是否有效
    • 您的更新对我来说很好。我的 R 版本是 3.6.3
    • 好吧,我的大数据表,你的版本不行。错误是:Error in `[.data.table`(dt.san2020, , `:=`((cols), { : Supplied 5 items to be assigned to 470 items of column 'type'. If you wish to 'recycle' the RHS please use rep() to make this intent clear to readers of your code.
    猜你喜欢
    • 2017-03-21
    • 1970-01-01
    • 1970-01-01
    • 2015-10-23
    • 1970-01-01
    • 1970-01-01
    • 2016-03-13
    • 1970-01-01
    • 2017-07-29
    相关资源
    最近更新 更多