r语言 - 如何将数据帧变量名称移动到第一行并将新变量名称添加到列表中的多个数据帧?


library(purrr)
library(tibble)
library(dplyr)

数据帧的起始列表

lst <- list(df1 = data.frame(X.1 = as.character(1:2),
heading = letters[1:2]),
df2 =  data.frame(X.32 = as.character(3:4),
another.topic = paste("Line ", 1:2)))
lst
#> $df1
#>   X.1 heading
#> 1   1       a
#> 2   2       b
#> 
#> $df2
#>   X.32 another.topic
#> 1    3       Line  1
#> 2    4       Line  2

预期的"组合"数据帧,具有新的一致变量名称,以及每个构成数据帧的第一行中的旧变量名称。

#>    id   h1            h2
#> 1 df1  X.1       heading
#> 2 df1    1             a
#> 3 df1    2             b
#> 4 df2 X.32 another.topic
#> 5 df2    3       Line  1
#> 6 df2    4       Line  2

add_row需要"名称-值对,传递给 tibble((。只能为 .data 中已存在的列定义值,未设置的列将获得 NA 值。

这就是我认为我所取得的成就:

df_nms <- 
map(lst, names) %>% 
map(set_names)
#> $df1
#>       X.1   heading 
#>     "X.1" "heading" 
#> 
#> $df2
#>            X.32   another.topic 
#>          "X.32" "another.topic"

但是我不能把最后一点绑起来,使用咕噜咕噜函数将名称添加到每个数据帧的头部。我已经尝试了许多map2变体,pmap目前我能得到的最接近的变体(如果我add_row视为公式,则以~为前缀并删除.y我得到一个新的第一行填充了 NA(。我想我错过了如何将名称-值对传递给 add_row 函数。

map2(lst, df_nms, add_row(.x, .y, .before = 1)) %>% 
map(set_names, c("h1", "h2")) %>% 
map_dfr(bind_rows, .id = "id")
#> Error in add_row(.x, .y, .before = 1): object '.x' not found

解决最后一步的指针将不胜感激。

不太确定如何通过purrr映射函数执行此操作,但这里有一个替代方案,

library(dplyr)
bind_rows(lapply(lst, function(i){d1 <- as.data.frame(matrix(names(i), ncol = ncol(i))); 
rbind(d1, setNames(i, names(d1)))}), .id = 'id')
#   id   V1            V2
#1 df1  X.1       heading
#2 df1    1             a
#3 df1    2             b
#4 df2 X.32 another.topic
#5 df2    3       Line  1
#6 df2    4       Line  2

这是一种使用map的方法,rbindlist来自data.table和一些基本的 R 函数:

library(purrr)
library(dplyr)
library(data.table)
map(lst, ~ as.data.frame(unname(rbind(colnames(.x),as.matrix(.x))))) %>%
rbindlist(idcol = "id")
#    id   V1            V2
#1: df1  X.1       heading
#2: df1    1             a
#3: df1    2             b
#4: df2 X.32 another.topic
#5: df2    3       Line  1
#6: df2    4       Line  2

或者,如果我们使用colnames<-,我们可以使用map_df

map_df(lst, ~ as.data.frame(rbind(colnames(.x),as.matrix(.x))) %>%
`colnames<-`(.,paste0("h",seq(1,dim(.)[2]))), .id = "id")
#   id   h1            h2
#1 df1  X.1       heading
#2 df1    1             a
#3 df1    2             b
#4 df2 X.32 another.topic
#5 df2    3       Line  1
#6 df2    4       Line  2

这里的关键是:

  1. 使用as.matrix来摆脱因素/字符不兼容。
  2. 删除带有unname的名称或使用colnames<-设置它们
  3. 使用idcols =.id =功能将列表的名称作为列获取。

我稍微更改了您的示例数据,在lst中创建 data.frame 时将stringsAsFactors设置为FALSE

这是使用的解决方案data.table::rbindlist().

#sample data
lst <- list(df1 = data.frame(X.1 = as.character(1:2),
heading = letters[1:2], 
stringsAsFactors = FALSE),   # !! <--
df2 =  data.frame(X.32 = as.character(3:4),
another.topic = paste("Line ", 1:2),
stringsAsFactors = FALSE)   # !! <--
)
DT <- data.table::rbindlist( lapply( lst, function(x) rbind( names(x), x ) ), 
use.names = FALSE, idcol = "id" )
setnames(DT, names( lst[[1]] ), c("h1", "h2") ) 
#     id   h1            h2
# 1: df1  X.1       heading
# 2: df1    1             a
# 3: df1    2             b
# 4: df2 X.32 another.topic
# 5: df2    3       Line  1
# 6: df2    4       Line  2

最新更新