【问题标题】:data.table equivalent of tidyr::complete()data.table 相当于 tidyr::complete()
【发布时间】:2017-09-14 23:04:03
【问题描述】:

tidyr::complete() 将行添加到 data.frame 以获取数据中缺失的列值的组合。示例:

library(dplyr)
library(tidyr)

df <- data.frame(person = c(1,2,2),
                 observation_id = c(1,1,2),
                 value = c(1,1,1))
df %>%
  tidyr::complete(person,
                  observation_id,
                  fill = list(value=0))

产量

# A tibble: 4 × 3
  person observation_id value
   <dbl>          <dbl> <dbl>
1      1              1     1
2      1              2     0
3      2              1     1
4      2              2     1

person == 1observation_id == 2 组合中 df 中缺少的 value 已填充值为 0。

data.table 中的这个等价物是什么?

【问题讨论】:

    标签: r data.table tidyr tidyverse


    【解决方案1】:

    我认为 data.table 的理念需要的任务专用函数比您在 tidyverse 中找到的要少,因此需要一些额外的编码,例如:

    res = setDT(df)[
      CJ(person = person, observation_id = observation_id, unique=TRUE), 
      on=.(person, observation_id)
    ]
    

    在此之后,您仍然需要手动处理缺失级别的值填充。我们可以使用setnafill 来有效地处理这个问题并在data.table 的最新版本中引用:

    setnafill(res, fill = 0, cols = 'value')
    

    请参阅@Jealie's answer,了解可以避开此问题的功能。


    当然,这里的列名必须输入三次,这很疯狂。但另一方面,可以编写一个包装器:

    completeDT <- function(DT, cols, defs = NULL){
      mDT = do.call(CJ, c(DT[, ..cols], list(unique=TRUE)))
      res = DT[mDT, on=names(mDT)]
      if (length(defs)) 
        res[, names(defs) := Map(replace, .SD, lapply(.SD, is.na), defs), .SDcols=names(defs)]
      res[]
    } 
    
    completeDT(setDT(df), cols = c("person", "observation_id"), defs = c(value = 0))
    
       person observation_id value
    1:      1              1     1
    2:      1              2     0
    3:      2              1     1
    4:      2              2     1
    

    作为避免在第一步输入三次名称的快速方法,这是@thelatemail 的想法:

    vars <- c("person","observation_id")
    df[do.call(CJ, c(mget(vars), unique=TRUE)), on=vars]
    
    # or with magrittr...
    c("person","observation_id") %>% df[do.call(CJ, c(mget(.), unique=TRUE)), on=.]
    

    更新:感谢@MichaelChirico 和@MattDowle for the improvement,现在您无需在 CJ 中输入两次姓名。

    【讨论】:

      【解决方案2】:

      那里可能有更好的答案,但这有效:

      dt[CJ(person=unique(dt$person), 
            observation_id=unique(dt$observation_id)),
         on=c('person','observation_id')]
      

      这给出了:

         person observation_id value
      1:      1              1     1
      2:      2              1     1
      3:      1              2    NA
      4:      2              2     1
      

      现在,如果您希望能够填写任何值(而不是 NA),我建议您等待 corresponding feature 完成或贡献:)

      【讨论】:

        【解决方案3】:

        值得注意的是,上面的completeDT 函数没有tidyr::complete 的许多功能。特别是,空因子水平被删除 - 不像tidyr::complete 保留它们。如果您确实想保留空因子,可以按如下方式编辑该函数。下面的make_vals 函数可以更复杂地处理其他变量类,例如。整数的完整序列。

        
        library(magrittr)
        library(data.table)
        
        
        dat <- data.frame(
          person = c(1,2,2),
          observation_id = factor(c(1,1,2), 1:3),
          value = c(1,1,1))
        
        dat %>%
          tidyr::complete(
            person, observation_id, fill = list(value=0))
        #> # A tibble: 6 x 3
        #>   person observation_id value
        #>    <dbl> <fct>          <dbl>
        #> 1      1 1                  1
        #> 2      1 2                  0
        #> 3      1 3                  0
        #> 4      2 1                  1
        #> 5      2 2                  1
        #> 6      2 3                  0
        
        completeDT <- function(DT, cols, defs = NULL){
          
          make_vals <- function(col) {
            if(is.factor(col)) factor(levels(col))
            else unique(col)
          }
          
          mDT = do.call(CJ, c(lapply(DT[, ..cols], make_vals), list(unique=TRUE)))
          res = DT[mDT, on=names(mDT)]
          if (length(defs)) 
            res[, names(defs) := Map(replace, .SD, lapply(.SD, is.na), defs), .SDcols=names(defs)]
          res[]
        } 
        
        completeDT(DT = setDT(dat), cols = c("person", "observation_id"), defs = c(value = 0))
        #>    person observation_id value
        #> 1:      1              1     1
        #> 2:      1              2     0
        #> 3:      1              3     0
        #> 4:      2              1     1
        #> 5:      2              2     1
        #> 6:      2              3     0
        

        reprex package (v0.3.0) 于 2021 年 3 月 8 日创建

        【讨论】:

          猜你喜欢
          • 2018-04-16
          • 1970-01-01
          • 2019-07-01
          • 2016-01-03
          • 2017-11-01
          • 2021-10-22
          • 2022-01-06
          • 2021-07-26
          相关资源
          最近更新 更多