我有数据帧的可变长度列表。我想使用指定的列名称或索引将每个列表中的dfs合并为单个df,该列名称或索引因df而异。这是一个3 dfs的例子
my.list <- list(
data.frame(a = 1:10, b = letters[1:10], c = 101:110),
data.frame(d = 6:15, e = letters[1:10], f = 1:10),
data.frame(l = 2:11, m = letters[11:20], o = 1:10))
我希望通过ids
中提到的每个df的特定列进行合并ids <- c('a', 'f', 'l')
获得类似
的内容id b c d e m o
1 a 101 6 a NA NA
2 b 102 7 b k 1
3 c 103 8 c l 2
4 d 104 9 d m 3
5 e 105 10 e n 4
6 f 106 11 f o 5
7 g 107 12 g p 6
8 h 108 13 h q 7
9 i 109 14 i r 8
10 j 110 15 j s 9
11 NA NA NA NA t 10
我尝试使用merge
和/或Reduce
执行此操作,但未能传递ID
答案 0 :(得分:6)
我们可以通过更改与&#39; ids&#39;对应的列名来更改所有names
元素的唯一list
。与&#39; id&#39;然后使用Reduce
merge
lst <- Map(function(x, y) {names(x)[match(y, names(x))] <- 'id'; x}, my.list, ids)
Reduce(function(...) merge(..., by = 'id', all = TRUE), lst)
# id b c d e m o
#1 1 a 101 6 a <NA> NA
#2 2 b 102 7 b k 1
#3 3 c 103 8 c l 2
#4 4 d 104 9 d m 3
#5 5 e 105 10 e n 4
#6 6 f 106 11 f o 5
#7 7 g 107 12 g p 6
#8 8 h 108 13 h q 7
#9 9 i 109 14 i r 8
#10 10 j 110 15 j s 9
#11 11 <NA> NA NA <NA> t 10
答案 1 :(得分:6)
这是一个data.table
答案,与@ akrun的回答类似。
但是,我们将其设置为键,而不是重命名列。然后我们可以通过键合并而不是按名称合并。这会保留列名。
library(data.table)
funky <- function(x) {
setDT(my.list[[x]])
setkeyv(my.list[[x]], ids[x])
return(NULL)
}
所以这个函数将传递一个索引x
。首先,它会将data.frame
的{{1}}位置xth
设置为my.list
。然后,它将根据data.table
中相同位置指定的列名称设置此新data.table
的键。最后,由于这一切都已完成,因此请返回ids
以防止无用的打印输出。
现在将该函数应用于列表中的所有对象。
NULL
解压缩a <- lapply(seq_along(ids), funky)
Reduce(function(x, y) merge(x,
y,
by.x = key(x),
by.y = key(y),
all = TRUE),
my.list)
,我们可以使用Reduce
和key(x)
指定要合并的列。这是允许我们避免修改列名称的步骤。
key(y)
答案 2 :(得分:5)
一个想法可能是将感兴趣的列转换为rownames,然后合并到rownames,即
l1 <- Map(function(x, y) {rownames(x) <- x[[y]]; x}, my.list, ids)
Reduce(function(x, y)merge(x, y, all = TRUE), lapply(l1, function(x)
data.frame(x, id = rownames(x))))
# id a b c d e f l m o
#1 1 1 a 101 6 a 1 NA <NA> NA
#2 10 10 j 110 15 j 10 10 s 9
#3 2 2 b 102 7 b 2 2 k 1
#4 3 3 c 103 8 c 3 3 l 2
#5 4 4 d 104 9 d 4 4 m 3
#6 5 5 e 105 10 e 5 5 n 4
#7 6 6 f 106 11 f 6 6 o 5
#8 7 7 g 107 12 g 7 7 p 6
#9 8 8 h 108 13 h 8 8 q 7
#10 9 9 i 109 14 i 9 9 r 8
#11 11 NA <NA> NA NA <NA> NA 11 t 10
答案 3 :(得分:3)
@Frank做了一个评论,让我想到一个简单,直接的循环:
# initialise result
result <- my.list[[1L]]
# add/merge remaining data.frames from list using the given column in ids to merge on
for (i in tail(seq_along(my.list), -1L)) {
result <- merge(result, my.list[[i]], by.x = ids[1L], by.y = ids[i], all = TRUE)
}
result
a b c d e m o 1 1 a 101 6 a <NA> NA 2 2 b 102 7 b k 1 3 3 c 103 8 c l 2 4 4 d 104 9 d m 3 5 5 e 105 10 e n 4 6 6 f 106 11 f o 5 7 7 g 107 12 g p 6 8 8 h 108 13 h q 7 9 9 i 109 14 i r 8 10 10 j 110 15 j s 9 11 11 <NA> NA NA <NA> t 10
在合并之前,此方法不需要重命名列表中的任何data.frames的单个列。但是,为了与OP的预期结果保持一致,之后可以重命名id
列:
tmp <- colnames(result)
colnames(result) <- replace(tmp, tmp == ids[1L], "id")
result
id b c d e m o 1 1 a 101 6 a <NA> NA 2 2 b 102 7 b k 1 3 3 c 103 8 c l 2 4 4 d 104 9 d m 3 5 5 e 105 10 e n 4 6 6 f 106 11 f o 5 7 7 g 107 12 g p 6 8 8 h 108 13 h q 7 9 9 i 109 14 i r 8 10 10 j 110 15 j s 9 11 11 <NA> NA NA <NA> t 10
注意OP多次指出ids
向量包含要为每个 data.frames合并的列的名称:
I want to merge by a specific column of each df mentioned in ids,和 Essentially I know the by variables (ids) but they differ among the dfs
因此,我担心使用match()
的答案可能是错误的。
答案 4 :(得分:-2)
合并我可以建议你使用sqldf包中的sqldf命令,你可以这样做:
A = data.frame(a = 1:10, b = letters[1:10], c = 101:110)
B = data.frame(d = 6:15, e = letters[1:10], f = 1:10)
C = data.frame(l = 2:11, m = letters[11:20], o = 1:10)
joined_df <- sqldf('select A.*,B.*,C.* from A left join B on A.a=B.f left join C on A.a=C.l')