我有多个数据帧/元素具有相同的确切结构,但内容不同。他们的名字是我能区分他们的唯一方式。目标是将它们全部合并到一个数据框中,并使用因子列。原始数据帧每小时/测量有一列,所以首先我要收集所有内容。
想象一下mtcars df的第5到11列是我的小时列。
mt1 <- mtcars
mt2 <- mtcars
mt3 <- mtcars
mt4 <- mtcars
mtlist <- list(m1 = mt1,
m2 = mt2,
m3 = mt3,
m4 = mt4)
require(tidyverse)
mtlist_tidy <- lapply(mtlist, function(x){
df <- x %>%
gather(exp, temp_name, 5:11)
return(df)
})
现在我被卡住了。我需要在mtlist_tidy中的每个dfs中重命名“temp_name”列,其名称为df,即m1,m2等:
> head(mtlist_tidy$m1)
mpg cyl disp hp exp temp_name
1 21.0 6 160 110 drat 3.90
2 21.0 6 160 110 drat 3.90
3 22.8 4 108 93 drat 3.85
4 21.4 6 258 110 drat 3.08
5 18.7 8 360 175 drat 3.15
6 18.1 6 225 105 drat 2.76
应该成为
> head(mtlist_tidy$m1)
mpg cyl disp hp exp m1
1 21.0 6 160 110 drat 3.90
2 21.0 6 160 110 drat 3.90
3 22.8 4 108 93 drat 3.85
4 21.4 6 258 110 drat 3.08
5 18.7 8 360 175 drat 3.15
6 18.1 6 225 105 drat 2.76
然后purrr::reduce(mtlist_tidy, full_join)
会工作,完成我的任务。
我想必须只使用purrr
和跳过lapply的解决方案,但我对这个包不熟悉。
答案 0 :(得分:5)
一些想法:
首先,要解决当前问题,您可以使用map2
同时遍历列表和列表名称。然后,您可以通过gather_
使用列表名称命名新列(用于标准评估)。
map2(mtlist, names(mtlist), ~gather_(.x, "exp", .y, names(.x)[5:11]) )
请注意, purrr 的下一个版本将imap
作为循环列表和列表名称的快捷方式。此外,下一版 tidyr 将使用tidyeval
,gather_
将被弃用。
其次,您可以使用map_df
代替lapply
来保持长格式。 map_df
在底层使用bind_rows
,您可以通过.id
参数为每个列表添加分组变量。
mtlist %>%
map_df(~.x %>% gather("exp", "temp_name", 5:11), .id = "name" )
要从此处以宽格式放置数据集,您可以使用spread
。在此示例中需要更多工作,因为某些标识变量(如hp
和disp
在多行中具有相同的值。
mtlist %>%
map_df(~.x %>% gather("exp", "temp_name", 5:11), .id = "name" ) %>%
group_by(name) %>%
mutate( rows = 1:n() ) %>%
spread(name, temp_name)
答案 1 :(得分:2)
你可能想要添加一些NSE魔法:
library(rlang)
mtlist_tidy %>% map2(., names(.), ~rename(.x, UQ(sym(.y)) := temp_name))
答案 2 :(得分:0)
这样做吗?
lapply(mtlist_tidy, function(i) {
names(i)["temp_name"] <- names(mtlist)[i] } )
答案 3 :(得分:0)
我编写了一个函数来重命名特定列
rename_fn <- function(df, col_ind, new_names) {
names(df)[col_ind] <- new_names
return(df)
}
然后简单地使用来自 purrr 的 map2
mtlist_tidy<-mtlist_tidy %>% map2(.,names(mtlist_tidy),
~rename_fn(.x,col_ind = 6,new_names = .y))