我有以下结构的列表,myList <- replicate(5, data.frame(id = 1:10, mean = runif(10)), simplify =F)
我想通过合并来减少它
myList %>% reduce(function(x, y) merge(x, y, by = 'id'))
但是,这会导致以下列名:
id mean.x mean.y mean.x mean.y mean
虽然我想要类似的东西
id mean1 mean2 mean3 mean4 mean5
其中数字基于
myList
的顺序。显然我可以迭代
1:length(myList)
,但我发现这个解决方案不优雅。其他选项是在减少函数中引入检查,但这会导致对列表中的每个元素进行新的线性时间搜索,所以我认为它不是很有效。有没有另一种方法来实现这一目标?
最佳答案
新答案:
使用 rbindlist
包中的 dcast
和 data.table
:
library(data.table)
mydata <- rbindlist(myList, idcol = 'df')
dcast(mydata, id ~ paste0('mean',df), value.var = 'mean')
或者使用 tidyverse 包:
library(dplyr)
library(tidyr)
myList %>%
bind_rows(., .id = 'df') %>%
spread(df, mean) %>%
rename_at(-1, funs(paste0('mean',.)))
两者都给出(显示
data.table
-output):当
id
中的一个或多个数据帧中有 duplicates in myList
时,您必须将 dcast
-step 调整为 dcast(mydata, id + rowid(id,df) ~ paste0('mean',df), value.var = 'mean')
以获得正确的结果。检查以下示例以查看结果:myList <- replicate(5, data.frame(id = sample(1:10, 10, TRUE), mean = runif(10)), simplify = FALSE)
mydata <- rbindlist(myList, idcol = 'df')
dcast(mydata, id + rowid(id,df) ~ paste0('mean',df), value.var = 'mean')
当
id
中没有重复项时,这也适用。tidyverse
-code 然后必须适应:myList %>%
bind_rows(., .id = 'df') %>%
group_by(df, id) %>%
mutate(ri = row_number()) %>%
ungroup() %>%
spread(df, mean) %>%
rename_at(3:7, funs(paste0('mean',.)))
旧答案(仍然有效):
一个可能的解决方案:
# option 1
myList <- mapply(function(x,y) {names(x)[2] = paste0('mean',y); x}, myList, 1:length(myList), SIMPLIFY = FALSE)
Reduce(function(x, y) merge(x, y, by = 'id'), myList)
# option 2 (quite similar to @zx8754's solution)
mydata <- Reduce(function(x, y) merge(x, y, by = 'id'), myList)
setNames(mydata, c('id', paste0('mean', seq_along(myList))))
这使: