基于第一列的值而不合并计算第二数据表中的行

时间:2016-11-25 17:36:02

标签: r data.table

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

第一个数据集(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)]

3 个答案:

答案 0 :(得分:7)

使用:

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))]

答案 1 :(得分: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

答案 2 :(得分:1)

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

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 = "")