我有两个数据表。
第一个数据表有很多行,包含一个主名称(name1),相关名称(names2到names5)和一个数字列功能。相关名称有限(例如此处为5),每个名称 i 在相同的有限集中取值(例如,在字符串组W = {num1,num2,num3}中,大小为3这里)。
这是df
的头部的一个例子 name1 name2 name3 name4 name5 feat
1: num1 num2 num3 num3 num1 0.88010416
2: num2 num1 num2 num1 num1 1.37001035
3: num2 num1 num1 num1 num1 -1.68732684
4: num2 num2 num3 num1 num1 -0.62743621
5: num3 num2 num1 num1 num1 0.01831663
第二个数据表是"链接"具有数字特征feat_A和feat_B的W元素之间的表格。以下是此类df_alt
的头部示例 name feat_A feat_B
1: num1 -0.03763026 0.011395161
2: num2 0.72397606 0.009859946
3: num3 -0.49673886 0.678271423
将df与df_alt合并的最有效方法是什么? 我想为每个列名 i 合并df和df_alt,即获取(注意行不按顺序排列):
name1 name2 name3 name4 name5 feat feat_A1 feat_A2
1: num2 num1 num1 num1 num1 -1.68732684 0.72397606 -0.03763026
2: num3 num2 num1 num1 num1 0.01831663 -0.49673886 0.72397606
3: num2 num1 num2 num1 num1 1.37001035 0.72397606 -0.03763026
4: num2 num2 num3 num1 num1 -0.62743621 0.72397606 0.72397606
5: num1 num2 num3 num3 num1 0.88010416 -0.03763026 0.72397606
feat_A3 feat_A4 feat_A5 feat_B1 feat_B2 feat_B3
1: -0.03763026 -0.03763026 -0.03763026 0.009859946 0.011395161 0.011395161
2: -0.03763026 -0.03763026 -0.03763026 0.678271423 0.009859946 0.011395161
3: 0.72397606 -0.03763026 -0.03763026 0.009859946 0.011395161 0.009859946
4: -0.49673886 -0.03763026 -0.03763026 0.009859946 0.009859946 0.678271423
5: -0.49673886 -0.49673886 -0.03763026 0.011395161 0.009859946 0.678271423
feat_B4 feat_B5
1: 0.01139516 0.01139516
2: 0.01139516 0.01139516
3: 0.01139516 0.01139516
4: 0.01139516 0.01139516
5: 0.67827142 0.01139516
我需要多次执行此合并(df固定和df_alt变化),因此成本效率很重要......
我目前最好的方法是进行包含合并的循环,但我想避免这种循环
for(i in 1:5) {
df_alt_i = df_alt
names(df_alt_i) = paste0(names(df_alt), i)
df = merge(df, df_alt_i, by=paste0("name", i), all.x = TRUE)
}
df = df[, c(paste0("name", 1:5), "feat",
paste0("feat_A", 1:5), paste0("feat_B", 1:m)), with = FALSE]
有没有聪明的方法来完成这项任务?
我尝试使用dplyr的left_join(在另一篇文章中看到),但它比当前方法慢得多。我也考虑过Reduce(在另一篇文章中),但我不知道如何有效地使用它,因为在循环中使用相同的df_alt。我想过将名称特征转换为矩阵,然后用df_alt中的相关元素替换每个元素,但没有取得多大成功。
这里有完全可复制的代码:
library(data.table)
m = 5
nrow = 5
set.seed(1234)
sample_name = function(nrow) {
sample(c("num1", "num2", "num3"), nrow, replace = TRUE)
}
df = data.table(name1 = sample_name(nrow),
name2 = sample_name(nrow),
name3 = sample_name(nrow),
name4 = sample_name(nrow),
name5 = sample_name(nrow),
feat = rnorm(nrow))
df_alt = data.table(name = c("num1", "num2", "num3"),
feat_A = rnorm(3),
feat_B = rnorm(3))
## Merge approach
for(i in 1:m) {
df_alt_i = df_alt
names(df_alt_i) = paste0(names(df_alt), i)
df = merge(df, df_alt_i, by=paste0("name", i), all.x = TRUE)
}
df = df[, c(paste0("name", 1:m), "feat",
paste0("feat_A", 1:m), paste0("feat_B", 1:m)),
with = FALSE]
## Left join approach (slow)
library(dplyr)
left_join(df, df_alt, by=c("name1" = "name")) %>%
left_join(., df_alt, by=c("name2" = "name")) %>%
left_join(., df_alt, by=c("name3" = "name")) %>%
left_join(., df_alt, by=c("name4" = "name")) %>%
left_join(., df_alt, by=c("name5" = "name"))