【问题标题】:Count rows in second data table based on column values of first without merging根据第一个的列值计算第二个数据表中的行而不合并
【发布时间】:2016-11-25 17:36:01
【问题描述】:

我承认问题的标题有点神秘,但请耐心等待。我有两张数据表,一张很小,一张很大,其中包含无用的信息。

第一个数据集(dt1)的格式如下:

      CG     MG1     MG2
1:   49693 914569 4417756
2:   50422  22514   31343
3:   90543  90544 4531361
4:  142864 143471  143806
5:  386093   2149 4149104
6: 2674708  23921   24327

所以它只包含数字,其中一些可以在第二个数据表中找到。第二个数据表 (dt2) 包含许多字段,但我需要的是 ID。

      ID
1:   49693
2:   49693
3:   49693
4:   49693
5:   49693
6: 2674708
7: 2679818
8: 2680618
9:   49693
10: 2695042

我要做的是在 dt1 中再添加 3 列,每列指定 dt2 中是否有超过 5 行 ID 分别等于 CG1、MG1、MG2。我的最终结果是这样的:

     CG     MG1     MG2    CG_OK MG1_OK MG2_OK
1:   49693 914569 4417756     1      0      0
2:   50422  22514   31343     0      0      0
3:   90543  90544 4531361     0      0      0
4:  142864 143471  143806     0      0      0
5:  386093   2149 4149104     0      0      0
6: 2674708  23921   24327     0      0      0

CG_OK 中有一个 1,因为对于 CG 49693,我们可以在 dt2 中找到 6 行具有相同 ID。

实现我的结果的方法:子集 dt2 仅包含可以在 CG、MG1 和 MG2 中找到的值,然后计算每个行的行数,然后以某种方式合并回来。

我的问题是,有没有更好的(或者在代码方面更短)的方法?类似的东西(我知道不工作):

dt1[, CG_OK := ifelse(nrow(dt2[ID == CG]) > 5, 1, 0)]

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    与:

    dt1[, paste0(names(dt1),'_OK') := lapply(.SD, function(x) as.integer(x %in% unique(dt2$ID))), .SDcols = 1:3][]
    

    你得到:

            CG    MG1     MG2 CG_OK MG1_OK MG2_OK
    1:   49693 914569 4417756     1      0      0
    2:   50422  22514   31343     0      0      0
    3:   90543  90544 4531361     0      0      0
    4:  142864 143471  143806     0      0      0
    5:  386093   2149 4149104     0      0      0
    6: 2674708  23921   24327     1      0      0
    

    如果不需要转换成整数:

    dt1[, paste0(names(dt1),'_OK') := lapply(.SD, `%in%`, unique(dt2$ID)), .SDcols = 1:3]
    

    或者更具可读性:

    cols <- names(dt1)
    dt1[, paste0(cols,'_OK') := lapply(.SD, `%in%`, unique(dt2$ID)), .SDcols = cols]
    

    因为要检查所有列,所以不一定需要指定.SDcols 参数。所以,最短的版本是:

    dt1[, paste0(cols,'_OK') := lapply(.SD, `%in%`, unique(dt2$ID))]
    

    【讨论】:

    • 非常感谢,非常好!
    • 或者,利用自动索引... v2s = unique(DT2$ID); for (v in names(DT)[1:3]){ newv = paste0(v, "_OK"); DT[, (newv) := 0L ]; DT[eval(substitute(v %in% v2s, list(v=as.symbol(v)))), (newv) := 1L, verbose = TRUE ] } 我猜。 (我不太擅长substitute,所以这可能是错误的。)
    【解决方案2】:

    这是对@Procrastinus 答案的修改,用于检查 df2 中是否有超过 5 个 ID:

    dt1[, paste0(names(dt1),"_OK") :=
          lapply(.SD, function(i) as.integer(i %in% dt2[, .N, by=ID][N > 5,]$ID))]
    
    dt1
            CG    MG1     MG2 CG_OK MG1_OK MG2_OK
    1:   49693 914569 4417756     1      0      0
    2:   50422  22514   31343     0      0      0
    3:   90543  90544 4531361     0      0      0
    4:  142864 143471  143806     0      0      0
    5:  386093   2149 4149104     0      0      0
    6: 2674708  23921   24327     0      0      0
    

    【讨论】:

    • 非常感谢! (实话实说,您的答案正是在回答我的问题,但是好的,两个答案的概念相同,而且你们都有很多代表,所以我选择了第一个!)
    • @User2321 没问题,他打败了我,并且有一些不错的改进,比如SDcols
    【解决方案3】:

    如果您喜欢更长的解决方案,可以将您的表与频率表合并:

    mrgDta <- sapply(dta1, function(x) {
        x <- merge(x = as.data.frame(x), as.data.frame(table(dta2)),
                   all.x = TRUE,
                   all.y = FALSE,
                   by.x = 1,
                   by.y = 1)[,2]
    })
    

    然后清理它:

    mrgDta[is.na(mrgDta)] <- 0
    mrgDta[mrgDta > 5] <- 1
    colnames(mrgDta) <- paste(names(dta1), "OK", sep = "_")
    

    结果:

        >> head(mrgDta)
         CG_OK MG1_OK MG2_OK
    [1,]     1      0      0
    [2,]     0      0      0
    [3,]     0      0      0
    [4,]     0      0      0
    [5,]     0      0      0
    [6,]     1      0      0
    

    旁注:

    merge 解决方案很灵活,例如,您可以更改计数以反映百分比:as.data.frame(prop.table(table(dta2)))


    数据

    # Copied from the original question, Mac OS
    dta1 <- read.delim(pipe("pbpaste"), sep = "")
    dta2 <- read.delim(pipe("pbpaste"), sep = "")
    

    【讨论】:

    • 感谢您的回答!我试图避免合并,但这也可以。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-08
    • 2013-12-06
    • 2010-10-23
    相关资源
    最近更新 更多