我承认问题的标题有点神秘,但请耐心等待.我有两个数据表,一个小,一个非常大,包含无用的信息.
第一个数据集(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
Run Code Online (Sandbox Code Playgroud)
所以它只包含数字,其中一些可以在第二个数据表中找到.第二个数据表(dt2)包含许多字段,但我需要的是ID.
ID
1: 49693
2: 49693
3: 49693
4: 49693
5: 49693
6: 2674708
7: 2679818
8: 2680618
9: 49693
10: 2695042
Run Code Online (Sandbox Code Playgroud)
我想要做的是在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
Run Code Online (Sandbox Code Playgroud)
在CG_OK中有一个1,因为对于CG 49693,我们可以在dt2中找到具有相同ID的6行.
我可以实现结果的方法:子集dt2只包含可以在CG,MG1和MG2中找到的值,然后计算每个值的行,然后以某种方式合并.
我的问题是,是否有更好的(或代码方面更短)方式?有点像(我不知道):
dt1[, CG_OK := ifelse(nrow(dt2[ID == CG]) > 5, 1, 0)]
Run Code Online (Sandbox Code Playgroud)
附:
dt1[, paste0(names(dt1),'_OK') := lapply(.SD, function(x) as.integer(x %in% unique(dt2$ID))), .SDcols = 1:3][]
Run Code Online (Sandbox Code Playgroud)
你得到:
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
Run Code Online (Sandbox Code Playgroud)
如果不需要转换为整数:
dt1[, paste0(names(dt1),'_OK') := lapply(.SD, `%in%`, unique(dt2$ID)), .SDcols = 1:3]
Run Code Online (Sandbox Code Playgroud)
或者更具可读性:
cols <- names(dt1)
dt1[, paste0(cols,'_OK') := lapply(.SD, `%in%`, unique(dt2$ID)), .SDcols = cols]
Run Code Online (Sandbox Code Playgroud)
因为要检查所有列,所以不一定需要指定.SDcols参数.所以,最短的版本是:
dt1[, paste0(cols,'_OK') := lapply(.SD, `%in%`, unique(dt2$ID))]
Run Code Online (Sandbox Code Playgroud)