使用其数据框名称重命名列表中的数据框列

Rename column of dataframes inside a list with its dataframe name

我有多个 dataframes/tibbles 结构完全相同,但内容不同。他们的名字是我区分他们的唯一方式。 objective 是将它们全部合并到一个数据框中,带有一个因子列。原始数据帧每个 hour/measurement 一列,所以首先我想收集所有内容。

假设 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)
})

现在我卡住了。我需要使用该 df 的名称重命名 mtlist_tidy 内每个 dfs 中的 "temp_name" 列,即 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 的解决方案,但我对这个包还不是很熟悉。

这个可以吗?

lapply(mtlist_tidy, function(i) {
  names(i)["temp_name"] <- names(mtlist)[i] } )

几个想法:

首先,要解决当前问题,您可以使用 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。在这个例子中需要做更多的工作,因为一些识别变量,如 hpdisp 在多行中具有相同的值。

mtlist %>%
    map_df(~.x %>% gather("exp", "temp_name", 5:11), .id = "name" ) %>%
    group_by(name) %>%
    mutate( rows = 1:n() ) %>%
    spread(name, temp_name)

您可能想要添加一些 NSE 魔法:

library(rlang)
mtlist_tidy %>% map2(., names(.), ~rename(.x, UQ(sym(.y)) := temp_name))

我写了一个函数来重命名特定的列

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))