如何用data.table重现无共同列数据集的base R合并行为?
如何用data.table实现无共同列数据集的笛卡尔积合并?
我需要合并两个无共同列的data.table,最终得到行数为N1*N2的结果(N1、N2分别是两个数据集的行数)。
在base R中可以直接通过merge()实现:
A <- data.frame(id = 1:6, value = 19:24) B <- data.frame(value2 = c(25, 25, 26, 26), value3 = 4:5) A #> id value #> 1 1 19 #> 2 2 20 #> 3 3 21 #> 4 4 22 #> 5 5 23 #> 6 6 24 B #> value2 value3 #> 1 25 4 #> 2 25 5 #> 3 26 4 #> 4 26 5 merge(A, B, all = TRUE) #> id value value2 value3 #> 1 1 19 25 4 #> 2 2 20 25 4 #> 3 3 21 25 4 #> 4 4 22 25 4 #> 5 5 23 25 4 #> 6 6 24 25 4 #> 7 1 19 25 5 #> 8 2 20 25 5 #> 9 3 21 25 5 #> 10 4 22 25 5 #> 11 5 23 25 5 #> 12 6 24 25 5 #> 13 1 19 26 4 #> 14 2 20 26 4 #> 15 3 21 26 4 #> 16 4 22 26 4 #> 17 5 23 26 4 #> 18 6 24 26 4 #> 19 1 19 26 5 #> 20 2 20 26 5 #> 21 3 21 26 5 #> 22 4 22 26 5 #> 23 5 23 26 5 #> 24 6 24 26 5
但改用data.table直接调用merge()会报错,因为data.table要求必须明确指定合并列:
library(data.table) A <- data.table(id = 1:6, value = 19:24) B <- data.table(value2 = c(25, 25, 26, 26), value3 = 4:5) merge(A, B, all = TRUE) #> Error in merge.data.table(A, B, all = TRUE): A non-empty vector of column names for `by` is required.
解决方案
可以通过以下几种方式用data.table实现相同的笛卡尔积合并效果:
方法1:添加临时共同列后使用merge()
给两个表添加一个完全相同的临时列,以此作为合并键,合并完成后再删除该临时列:
library(data.table) A <- data.table(id = 1:6, value = 19:24) B <- data.table(value2 = c(25, 25, 26, 26), value3 = 4:5) # 添加临时键列 A[, temp_key := 1] B[, temp_key := 1] # 执行合并并删除临时列 result <- merge(A, B, by = "temp_key", all = TRUE)[, temp_key := NULL] print(result)
方法2:利用索引生成笛卡尔积
通过生成两个表行索引的所有组合,再按索引提取对应行并拼接,这是更高效的方式:
library(data.table) A <- data.table(id = 1:6, value = 19:24) B <- data.table(value2 = c(25, 25, 26, 26), value3 = 4:5) # 生成所有行索引的笛卡尔积组合 idx <- CJ(i = seq_len(nrow(A)), j = seq_len(nrow(B)), sorted = FALSE) # 按索引提取行并拼接 result <- cbind(A[idx$i], B[idx$j]) print(result)
方法3:利用行复制拼接
通过重复行的方式直接生成笛卡尔积结构,再拼接第二个表的内容:
library(data.table) A <- data.table(id = 1:6, value = 19:24) B <- data.table(value2 = c(25, 25, 26, 26), value3 = 4:5) # 重复A的行,次数等于B的行数 result <- A[rep(seq_len(.N), nrow(B))] # 重复B的行,次数等于A的行数,添加到结果中 result[, c(names(B)) := B[rep(seq_len(.N), each = nrow(A))]] print(result)
内容的提问来源于stack exchange,提问作者bretauv
相关产品推荐
相关产品推荐

