我承认问题的标题有点神秘,但请耐心等待。我有两个数据表,一个小,一个非常大,包含无用的信息。
第一个数据集(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)]
答案 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 = "")