迭代两个 data.tables' 行的更优雅的方法
A more elegant way to iterate over two data.tables' rows
我开始越来越频繁地使用 R,来自 C/C++。出于这个原因,在使用 R 的数据结构时,我经常发现自己在思考 à la C++。
这里我有两个 data.tables 必须遍历并用 table A 中第 2 列的值更新 table A 中第 1 列和第 2 列的值=44=]B,根据第1栏tableBw.r.t。 table A.
中的第 1 列和第 2 列
对于这种令人困惑的描述,我们深表歉意。我努力让它变得更好
我有两个数据tables(行数不同,因为它们实际上可能不同):
TabA
Col1 Col2
1: TP53 CD68
2: TP53 MPDU1
3: TP53 PHF2
4: TP53 KIAA0753
5: CD68 ZBTB4
6: CD68 CHD3
7: MPDU1 ZBTB4
8: MPDU1 CHD3
9: MPDU1 SLC2A4
10: MPDU1 YBX2
11: MPDU1 AURKB
12: MPDU1 TMEM132B
13: PHF2 C9orf129
14: PHF2 CDH23
15: PHF2 PTPDC1
和 TabB:
Col3 Col4
1: ADAM32 0
2: ADARB2 1
3: AGBL2 2
4: ALOX12 3
5: ANKRD46 4
6: APOL1 5
7: APOOL 6
8: ASPA 7
9: AUH 8
10: AURKB 9
11: AUTS2 10
12: BAAT 11
所以基本上,我想比较 TabA 中的 Col1 和 Col2 与 TabB 中的 Col3:如果它们相等,则将字符串替换为 TabB 的 Col4 中的数字。
我的方法,绝对是 C 风格:
for(i in 1:nrow(TabA)) {
for(j in 1:nrow(TabB)) {
if(TabA$Col1[i] == TabB$Col3[j]) {
TabA$Col1[i] <- TabB$Col4[j]
}
if(TabA$Col2[i] == TabB$Col3[j]) {
TabA$Col2[i] <- TabB$Col4[j]
}
}
}
这按预期工作,但我很确定有一种更优雅(也更有效)的方法可以利用 data.table 的功能来做到这一点。
有人有什么建议吗?
谢谢
因为我没有你的数据,所以我做了一个小例子,但我认为这就是你要找的东西:
x<- c("a","b","c","d")
y<-c("a","d","e","f")
z<-c("z1","z2","z3","z4")
x[x %in% y]<-z[x %in% y]
如果您正在使用 data.table
您的原始问题(在对问题进行大量编辑之前)可以这样完成:
TabA <- data.table(Col1 = sample(LETTERS, 15), Col3 = rnorm(15))
TabB <- data.table(Col2 = sample(LETTERS, 15), Col4 = rnorm(15))
setkey(TabA, Col1)
setkey(TabB, Col2)
TabA
# shows TabA before changing it
TabA[TabB, Col3 := Col4]
我仍然觉得 data.table
的语法有点奇怪,因为当函数不修改其参数时,它与 R 中的标准行为不同。另一方面,它使代码简洁、内存高效和快速。
重写问题的解决方案
请注意,您的示例数据没有帮助 - TabB$Col3
中没有 TabA$Col1
的匹配项。无论如何,这可以通过几种方式解决。
使用 data.table
:=
运算符:
TabA[Col1 %in% TabB$Col3, Col1 := with(TabB, as.character(Col4[na.omit(match(Col1, Col3))]))]
TabA[Col2 %in% TabB$Col3, Col2 := with(TabB, as.character(Col4[na.omit(match(Col2, Col3))]))]
使用基本 R 语法(也适用于 data.frame
):
TabA$Col1[TabA$Col1 %in% TabB$Col3] <- TabB$Col4[match(TabA$Col1[TabA$Col1 %in% TabB$Col3], TabB$Col3)]
TabA$Col2[TabA$Col2 %in% TabB$Col3] <- TabB$Col4[match(TabA$Col2[TabA$Col2 %in% TabB$Col3], TabB$Col3)]
使用 setkey 并加入:
TabA[, Index := 1:nrow(TabA)]
setkey(TabA, Col1)
TabA[TabB, nomatch = 0, Col1 := as.character(Col4)]
setkey(TabA, Col2)
TabA[TabB, nomatch = 0, Col2 := as.character(Col4)]
setkey(TabA, Index)
TabA[, Index := NULL]
所有这些都假定 Col1 和 Col2 中的某些项目不会匹配。如果这不是真的,则可以优化代码。这也是Col4不得不强制角色化的原因。
这是一个仅使用基数的建议 R
。
the_equals <- TabA$Col1[which(TabA$Col1 %in% TabB$Col3)]
nequals <- length(the_equals)
if(nequals>0) {
idx1 <- lapply(1:nequals, function(x) which(TabA$Col1==the_equals[x]))
idx2 <- lapply(1:nequals, function(x) which(TabB$Col3==the_equals[x]))
Col2_new <- sapply(1:nequals, function(x) TabB$Col4[idx2[[x]][1]])
for(i in 1:nequals) TabA$Col2[idx1[[i]]] <- Col2_new[i]
}
希望对您有所帮助。
当我想遍历datatabe
的每一行时,我通常使用by=1:nrow(DT)
library(data.table)
TabA <- data.table(Col1=c('A', 'B', 'C', 'D'), Col2=c('B', 'A', 'D', 'C'))
TabB <- data.table(Col3=c('A', 'B', 'C'), Col4=c(1, 2, 3))
TabA[, .(Col1=as.character(ifelse(nrow(TabB[Col3==Col1]) > 0, TabB[Col3==Col1]$Col4, Col1)),
Col2=as.character(ifelse(nrow(TabB[Col3==Col2]) > 0, TabB[Col3==Col2]$Col4, Col2))
),
by=1:nrow(TabA)][, .(Col1, Col2)]
或
TabA[, `:=`(Col1=as.character(ifelse(nrow(TabB[Col3==Col1]) > 0, TabB[Col3==Col1]$Col4, Col1)),
Col2=as.character(ifelse(nrow(TabB[Col3==Col2]) > 0, TabB[Col3==Col2]$Col4, Col2))
),
by=1:nrow(TabA)]
我开始越来越频繁地使用 R,来自 C/C++。出于这个原因,在使用 R 的数据结构时,我经常发现自己在思考 à la C++。
这里我有两个 data.tables 必须遍历并用 table A 中第 2 列的值更新 table A 中第 1 列和第 2 列的值=44=]B,根据第1栏tableBw.r.t。 table A.
对于这种令人困惑的描述,我们深表歉意。我努力让它变得更好
我有两个数据tables(行数不同,因为它们实际上可能不同):
TabA
Col1 Col2
1: TP53 CD68
2: TP53 MPDU1
3: TP53 PHF2
4: TP53 KIAA0753
5: CD68 ZBTB4
6: CD68 CHD3
7: MPDU1 ZBTB4
8: MPDU1 CHD3
9: MPDU1 SLC2A4
10: MPDU1 YBX2
11: MPDU1 AURKB
12: MPDU1 TMEM132B
13: PHF2 C9orf129
14: PHF2 CDH23
15: PHF2 PTPDC1
和 TabB:
Col3 Col4
1: ADAM32 0
2: ADARB2 1
3: AGBL2 2
4: ALOX12 3
5: ANKRD46 4
6: APOL1 5
7: APOOL 6
8: ASPA 7
9: AUH 8
10: AURKB 9
11: AUTS2 10
12: BAAT 11
所以基本上,我想比较 TabA 中的 Col1 和 Col2 与 TabB 中的 Col3:如果它们相等,则将字符串替换为 TabB 的 Col4 中的数字。
我的方法,绝对是 C 风格:
for(i in 1:nrow(TabA)) {
for(j in 1:nrow(TabB)) {
if(TabA$Col1[i] == TabB$Col3[j]) {
TabA$Col1[i] <- TabB$Col4[j]
}
if(TabA$Col2[i] == TabB$Col3[j]) {
TabA$Col2[i] <- TabB$Col4[j]
}
}
}
这按预期工作,但我很确定有一种更优雅(也更有效)的方法可以利用 data.table 的功能来做到这一点。 有人有什么建议吗?
谢谢
因为我没有你的数据,所以我做了一个小例子,但我认为这就是你要找的东西:
x<- c("a","b","c","d")
y<-c("a","d","e","f")
z<-c("z1","z2","z3","z4")
x[x %in% y]<-z[x %in% y]
如果您正在使用 data.table
您的原始问题(在对问题进行大量编辑之前)可以这样完成:
TabA <- data.table(Col1 = sample(LETTERS, 15), Col3 = rnorm(15))
TabB <- data.table(Col2 = sample(LETTERS, 15), Col4 = rnorm(15))
setkey(TabA, Col1)
setkey(TabB, Col2)
TabA
# shows TabA before changing it
TabA[TabB, Col3 := Col4]
我仍然觉得 data.table
的语法有点奇怪,因为当函数不修改其参数时,它与 R 中的标准行为不同。另一方面,它使代码简洁、内存高效和快速。
重写问题的解决方案
请注意,您的示例数据没有帮助 - TabB$Col3
中没有 TabA$Col1
的匹配项。无论如何,这可以通过几种方式解决。
使用 data.table
:=
运算符:
TabA[Col1 %in% TabB$Col3, Col1 := with(TabB, as.character(Col4[na.omit(match(Col1, Col3))]))]
TabA[Col2 %in% TabB$Col3, Col2 := with(TabB, as.character(Col4[na.omit(match(Col2, Col3))]))]
使用基本 R 语法(也适用于 data.frame
):
TabA$Col1[TabA$Col1 %in% TabB$Col3] <- TabB$Col4[match(TabA$Col1[TabA$Col1 %in% TabB$Col3], TabB$Col3)]
TabA$Col2[TabA$Col2 %in% TabB$Col3] <- TabB$Col4[match(TabA$Col2[TabA$Col2 %in% TabB$Col3], TabB$Col3)]
使用 setkey 并加入:
TabA[, Index := 1:nrow(TabA)]
setkey(TabA, Col1)
TabA[TabB, nomatch = 0, Col1 := as.character(Col4)]
setkey(TabA, Col2)
TabA[TabB, nomatch = 0, Col2 := as.character(Col4)]
setkey(TabA, Index)
TabA[, Index := NULL]
所有这些都假定 Col1 和 Col2 中的某些项目不会匹配。如果这不是真的,则可以优化代码。这也是Col4不得不强制角色化的原因。
这是一个仅使用基数的建议 R
。
the_equals <- TabA$Col1[which(TabA$Col1 %in% TabB$Col3)]
nequals <- length(the_equals)
if(nequals>0) {
idx1 <- lapply(1:nequals, function(x) which(TabA$Col1==the_equals[x]))
idx2 <- lapply(1:nequals, function(x) which(TabB$Col3==the_equals[x]))
Col2_new <- sapply(1:nequals, function(x) TabB$Col4[idx2[[x]][1]])
for(i in 1:nequals) TabA$Col2[idx1[[i]]] <- Col2_new[i]
}
希望对您有所帮助。
当我想遍历datatabe
by=1:nrow(DT)
library(data.table)
TabA <- data.table(Col1=c('A', 'B', 'C', 'D'), Col2=c('B', 'A', 'D', 'C'))
TabB <- data.table(Col3=c('A', 'B', 'C'), Col4=c(1, 2, 3))
TabA[, .(Col1=as.character(ifelse(nrow(TabB[Col3==Col1]) > 0, TabB[Col3==Col1]$Col4, Col1)),
Col2=as.character(ifelse(nrow(TabB[Col3==Col2]) > 0, TabB[Col3==Col2]$Col4, Col2))
),
by=1:nrow(TabA)][, .(Col1, Col2)]
或
TabA[, `:=`(Col1=as.character(ifelse(nrow(TabB[Col3==Col1]) > 0, TabB[Col3==Col1]$Col4, Col1)),
Col2=as.character(ifelse(nrow(TabB[Col3==Col2]) > 0, TabB[Col3==Col2]$Col4, Col2))
),
by=1:nrow(TabA)]