【问题标题】:Add missing rows to data.table according to multiple keyed columns根据多键列向data.table添加缺失的行
【发布时间】:2015-02-06 22:29:06
【问题描述】:

我有一个 data.table 对象,其中包含多个指定唯一案例的列。在下面的小示例中,变量“name”、“job”和“sex”指定了唯一 ID。我想添加缺失的行,以便每个案例对于另一个变量“from”的每个可能实例都有一行(类似于expand.grid)。

library(data.table)
set.seed(1)
mydata <- data.table(name = c("john","john","john","john","mary","chris","chris","chris"),
                 job = c("teacher","teacher","teacher","teacher","police","lawyer","lawyer","doctor"),
                 sex = c("male","male","male","male","female","female","male","male"),
                 from = c("NYT","USAT","BG","TIME","USAT","BG","NYT","NYT"),
                 score = rnorm(8))

setkeyv(mydata, cols=c("name","job","sex"))

mydata[CJ(unique(name, job, sex), unique(from))]

这是当前的 data.table 对象:

> mydata
    name     job    sex from      score
1:  john teacher   male  NYT -0.6264538
2:  john teacher   male USAT  0.1836433
3:  john teacher   male   BG -0.8356286
4:  john teacher   male TIME  1.5952808
5:  mary  police female USAT  0.3295078
6: chris  lawyer female   BG -0.8204684
7: chris  lawyer   male  NYT  0.4874291
8: chris  doctor   male  NYT  0.7383247

这是我想要的结果:

> mydata
     name     job    sex from      score
1:   john teacher   male  NYT -0.6264538
2:   john teacher   male USAT  0.1836433
3:   john teacher   male   BG -0.8356286
4:   john teacher   male TIME  1.5952808
5:   mary  police female  NYT  NA
6:   mary  police female USAT  0.3295078
7:   mary  police female   BG  NA
8:   mary  police female TIME  NA
9:  chris  lawyer female  NYT -NA
10: chris  lawyer female USAT -NA
11: chris  lawyer female   BG -0.8204684
12: chris  lawyer female TIME -NA
13: chris  lawyer   male  NYT  0.4874291
14: chris  lawyer   male USAT  NA
15: chris  lawyer   male   BG  NA
16: chris  lawyer   male TIME  NA
17: chris  doctor   male  NYT  0.7383247
18: chris  doctor   male USAT  NA
19: chris  doctor   male   BG  NA
20: chris  doctor   male TIME  NA

这是我尝试过的:

setkeyv(mydata, cols=c("name","job","sex"))
mydata[CJ(unique(name, job, sex), unique(from))]

但我收到以下错误,添加 fromLast=TRUE(或 FALSE)并没有给我正确的解决方案:

Error in unique.default(name, job, sex) : 
  'fromLast' must be TRUE or FALSE

以下是我遇到的相关答案(但似乎都没有处理多个键控列): add missing rows to a data table

Efficiently inserting default missing rows in a data.table

Fastest way to add rows for missing values in a data.frame?

【问题讨论】:

    标签: r merge data.table cross-join


    【解决方案1】:

    一种可能性是将pastenamejobsex 放在一起,获取unique 值,然后使用uniquefrom 值执行CJ .之后,使用library(splitstackshape) 中的cSplitpasted 列拆分回三列,将这些列重命名为setnames,并在设置key 后将join 重命名为mydata

    library(splitstackshape)
    library(data.table)
    mydata1 <- setnames(cSplit(mydata[,CJ(unique(paste(name, job, sex)), 
                from=unique(from))], 'V1', ' '), 2:4, c('name', 'job', 'sex'))[,
                         c(2:4,1)]
    setkeyv(mydata, cols=colnames(mydata)[1:4])
    mydata[mydata1]
    #      name     job    sex from      score
    #1: chris  doctor   male   BG         NA
    #2: chris  doctor   male  NYT  0.7383247
    #3: chris  doctor   male TIME         NA
    #4: chris  doctor   male USAT         NA
    #5: chris  lawyer female   BG -0.8204684
    #6: chris  lawyer female  NYT         NA
    #7: chris  lawyer female TIME         NA
    #8: chris  lawyer female USAT         NA
    #9: chris  lawyer   male   BG         NA
    #10: chris  lawyer   male  NYT  0.4874291
    #11: chris  lawyer   male TIME         NA
    #12: chris  lawyer   male USAT         NA
    #13:  john teacher   male   BG -0.8356286
    #14:  john teacher   male  NYT -0.6264538
    #15:  john teacher   male TIME  1.5952808
    #16:  john teacher   male USAT  0.1836433
    #17:  mary  police female   BG         NA
    #18:  mary  police female  NYT         NA
    #19:  mary  police female TIME         NA
    #20:  mary  police female USAT  0.3295078
    

    【讨论】:

    • 相当激烈。列选择是 2:4 吗?
    • @jazzurro 是的,使用setnames重命名这些列
    • 知道了。非常感谢。 :)
    【解决方案2】:

    这里有几种可能性 - https://github.com/Rdatatable/data.table/pull/814

    CJ.dt = function(...) {
      rows = do.call(CJ, lapply(list(...), function(x) if(is.data.frame(x)) seq_len(nrow(x)) else seq_along(x)));
      do.call(data.table, Map(function(x, y) x[y], list(...), rows))
    }
    
    setkey(mydata, name, job, sex, from)
    
    mydata[CJ.dt(unique(data.table(name, job, sex)), unique(from))]
    #     name     job    sex from      score
    # 1: chris  doctor   male  NYT  0.7383247
    # 2: chris  doctor   male   BG         NA
    # 3: chris  doctor   male TIME         NA
    # 4: chris  doctor   male USAT         NA
    # 5: chris  lawyer female  NYT         NA
    # 6: chris  lawyer female   BG -0.8204684
    # 7: chris  lawyer female TIME         NA
    # 8: chris  lawyer female USAT         NA
    # 9: chris  lawyer   male  NYT  0.4874291
    #10: chris  lawyer   male   BG         NA
    #11: chris  lawyer   male TIME         NA
    #12: chris  lawyer   male USAT         NA
    #13:  john teacher   male  NYT -0.6264538
    #14:  john teacher   male   BG -0.8356286
    #15:  john teacher   male TIME  1.5952808
    #16:  john teacher   male USAT  0.1836433
    #17:  mary  police female  NYT         NA
    #18:  mary  police female   BG         NA
    #19:  mary  police female TIME         NA
    #20:  mary  police female USAT  0.3295078
    

    【讨论】:

      【解决方案3】:

      开发版 tidyr 现在有一种优雅的方式来执行此操作,因为 expand() 函数现在支持嵌套和交叉:

      library(dplyr)
      
      mydata <- data_frame(
        name = c("john","john","john","john","mary","chris","chris","chris"),
        job = c("teacher","teacher","teacher","teacher","police","lawyer","lawyer","doctor"),
        sex = c("male","male","male","male","female","female","male","male"),
        from = c("NYT","USAT","BG","TIME","USAT","BG","NYT","NYT"),
        score = rnorm(8)
      )
      
      mydata %>% 
        expand(c(name, job, sex), from) %>% 
        left_join(mydata)
      
      #> Joining by: c("name", "job", "sex", "from")
      #> Source: local data frame [20 x 5]
      #> 
      #>     name     job    sex from      score
      #> 1  chris  doctor   male   BG         NA
      #> 2  chris  doctor   male  NYT  0.5448206
      #> 3  chris  doctor   male TIME         NA
      #> 4  chris  doctor   male USAT         NA
      #> 5  chris  lawyer female   BG  1.2015173
      #> 6  chris  lawyer female  NYT         NA
      #> 7  chris  lawyer female TIME         NA
      #> 8  chris  lawyer female USAT         NA
      #> 9  chris  lawyer   male   BG         NA
      #> 10 chris  lawyer   male  NYT -1.0930237
      #> 11 chris  lawyer   male TIME         NA
      #> 12 chris  lawyer   male USAT         NA
      #> 13  john teacher   male   BG  1.1345461
      #> 14  john teacher   male  NYT  1.3032946
      #> 15  john teacher   male TIME  2.4901830
      #> 16  john teacher   male USAT -1.6449096
      #> 17  mary  police female   BG         NA
      #> 18  mary  police female  NYT         NA
      #> 19  mary  police female TIME         NA
      #> 20  mary  police female USAT -0.2443080
      

      【讨论】:

        猜你喜欢
        • 2018-06-19
        • 2017-11-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-29
        • 1970-01-01
        • 1970-01-01
        • 2020-06-22
        相关资源
        最近更新 更多