【问题标题】:insert empty rows to complete cases of a column插入空行以完成列的案例
【发布时间】:2015-11-06 22:35:45
【问题描述】:

假设我有一个 data.table

col1   col2    col3
 a     123      1
 a     433      2
 a     322      3       
 b     43       1  
 b     4333     2
 c     43       1

在上表中,col1 的每个类别应该有 3 行。但只有类别 a 有 3 行。因此,我想为 col1 的其他类别的缺失案例插入带有 NA 的空白行。输出看起来像

col1   col2    col3
 a     123      1
 a     433      2
 a     322      3       
 b     43       1  
 b     4333     2
 b     NA       3
 c     43       1
 c     NA       2
 c     NA       3

如何通过一次函数调用来实现它?

【问题讨论】:

  • DT[CJ(col1=col1, col3=col3, unique=TRUE), on=c("col1","col3")]。不得不重复这样的列名很烦人。在下一个版本中,可以使用DT[CJ(col1,col3,unique=TRUE), on=c("col1","col3")]。如果你加载 tidyr,setDT(complete(DT,col1,col3)) 是一个选项。它可能效率较低。
  • @Frank 这太棒了。如果我想在外部提供最大参数(在本例中为 3)怎么办?也就是说,我想说如果c 的行数小于 3,那么只插入剩余的行(在这种情况下为 2 行)。或者如果行数小于 2,那么只插入剩余的行(在这种情况下为 1)?我该怎么做?
  • 我不太明白这个问题。也许你应该把它作为一个新问题发布(因为你已经有两个答案了)..?
  • 这是我过去一两个月看到的至少 2-3 个问题的重复。

标签: r dataframe data.table


【解决方案1】:

data.table 我认为这个成语是与col1col3 的笛卡尔/叉积的合并

(在@Jealie 和@PLapointe 的回答中也是如此):

DT[CJ(col1 = col1, col3 = col3, unique=TRUE), on = c("col1", "col3")]

   col1 col2 col3
1:    a  123    1
2:    a  433    2
3:    a  322    3
4:    b   43    1
5:    b 4333    2
6:    b   NA    3
7:    c   43    1
8:    c   NA    2
9:    c   NA    3

CJ 构造笛卡尔积,A[B,on=cols] 与结果中B 的所有行合并。


tidyr 在 data.table 之外,另一个语法更好的替代方法是在 tidyr 中:

library(tidyr)
complete(DT, col1, col3)

不幸的是,这不会返回 data.table。你可以在结果上使用setDT 来解决这个问题。

【讨论】:

  • 我的任务需要我稍后删除这些插入的人工行。我该怎么做?
  • @user3664020 嗯,你可以做类似res = DT[, is_artificial := FALSE][CJ(col1 = col1, col3 = col3, unique=TRUE), on = c("col1", "col3")][is.na(is_artificial), is_artificial := TRUE] 的事情。然后您可以稍后过滤该列。
【解决方案2】:

或者您可以在dplyr 中使用full_join

table1 <-read.table(text="col1   col2    col3
 a     123      1
 a     433      2
 a     322      3
 b     43       1
 b     4333     2
 c     43       1", header=T,stringsAsFactors =F)

library(dplyr)
all1 <-expand.grid(letters[1:3],1:3, stringsAsFactors = F)
colnames(all1) <-c("col1","col3")
full_join(table1,all1,c("col1","col3"))

  col1 col2 col3
1    a  123    1
2    a  433    2
3    a  322    3
4    b   43    1
5    b 4333    2
6    c   43    1
7    c   NA    2
8    b   NA    3
9    c   NA    3

【讨论】:

    【解决方案3】:

    我会申请mergedata.tabledata.frame 都可用)。

    让我们从创建我们想要的模式开始:

    > pattern = data.frame(col1=rep(letters[1:3], each=3), col3=rep(1:3,3))
    > pattern
      col1 col3
    1    a    1
    2    a    2
    3    a    3
    4    b    1
    5    b    2
    6    b    3
    7    c    1
    8    c    2
    9    c    3
    

    然后将这个模式与真实数据合并:

    > merge(pattern, real_data, all.x=T, by=c('col1','col3'))
      col1 col3 col2
    1    a    1  123
    2    a    2  433
    3    a    3  322
    4    b    1   43
    5    b    2 4333
    6    b    3   NA
    7    c    1   43
    8    c    2   NA
    9    c    3   NA
    

    注意:real_data 是通过以下方式获得的:

    # data.table:
    real_data = structure(list(col1 = structure(c(1L, 1L, 1L, 2L, 2L, 3L), .Label = c("a", "b", "c"), class = "factor"), col2 = c(123L, 433L, 322L, 43L, 4333L, 43L), col3 = c(1L, 2L, 3L, 1L, 2L, 1L)), .Names = c("col1", "col2", "col3"), class = c("data.table","data.frame"), row.names = c(NA, -6L))
    # or data.frame:
    real_data = structure(list(col1 = structure(c(1L, 1L, 1L, 2L, 2L, 3L), .Label = c("a", "b", "c"), class = "factor"), col2 = c(123L, 433L, 322L, 43L, 4333L, 43L), col3 = c(1L, 2L, 3L, 1L, 2L, 1L)), .Names = c("col1", "col2", "col3"), class = "data.frame", row.names = c(NA, -6L))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-07
      • 2017-10-10
      • 1970-01-01
      • 2018-05-30
      • 1970-01-01
      • 2018-09-01
      • 2021-09-30
      • 2014-07-20
      相关资源
      最近更新 更多