Suppose I have the following list of dataframes:
lst <- list(
a=data.frame(key=c(1,2,3), val=c(10,20,30)),
b=data.frame(key=c(1,2,3), val=c(100,200,300)),
c=data.frame(key=c(1,2,3), val=c(1000,2000,3000)),
d=data.frame(key=c(1,2), val=c(10000,20000)))
How do I create a data.frame as follows? (or similar):
key val.a val.b val.c val.d
1 1 10 100 1000 10000
2 2 20 200 2000 20000
3 3 30 300 3000 NA
I tried to do it this way (but FAILED):
Browse[2]> Reduce(function(x,y) merge(x, y, by = 'key', all.x = T), lst)
key val.x val.y val.x val.y
1 1 10 100 1000 10000
2 2 20 200 2000 20000
3 3 30 300 3000 NA
Warning message:
In merge.data.frame(x, y, by = "key", all.x = T) :
column names ‘val.x’, ‘val.y’ are duplicated in the result
NOTE: I would prefer a base-R solution but am interested in other ways of doing this
We can use inner_join with reduce after renaming the second column with the corresponding list name
library(purrr)
library(dplyr)
library(stringr)
imap(lst, ~ { nm <- .y
.x %>%
rename_at(vars(val), ~ str_c(., ".", nm))}) %>%
reduce(full_join, by = 'key')
# key val.a val.b val.c val.d
#1 1 10 100 1000 10000
#2 2 20 200 2000 20000
#3 3 30 300 3000 30000
Or in base R, we use Map to do the renaming of the column, then as in the OP's post, do the merge within Reduce
Reduce(function(...) merge(..., by = 'key', all = TRUE),
Map(function(x, y) setNames(x, c('key',
paste0(names(x)[-1], ".", y))), lst, names(lst)))
# key val.a val.b val.c val.d
#1 1 10 100 1000 10000
#2 2 20 200 2000 20000
#3 3 30 300 3000 30000
If you are not too fussed about the column names etc looking exactly they way you have it, you can use the following:
df_merged = do.call(cbind,lst) %>%
select(key = a.key, 2,4,6,8)
with output:
key a.val b.val c.val d.val
1 1 10 100 1000 10000
2 2 20 200 2000 20000
3 3 30 300 3000 30000
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With