r语言 - 使用带有 dplyr 的数据帧名称动态重命名



在此示例中,我使用的是iris数据集,我想将Petal.Length重命名为iris

library(dplyr)
some_fun <- function(x){
head(x) %>%
rename(!!quo_name(x) := "Petal.Length")
}
some_fun(iris)

但这会产生以下错误:

Error: `expr` must quote a symbol, scalar, or call

如果我使用enquo而不是quo_name,我有这个错误:

Error: The LHS of `:=` must be a string or a symbol

我想问题来自我打电话给some_fun(iris)而不是some_fun("iris"),但我必须打电话给some_fun(iris).

在使用some_fun(iris)时,我该怎么做?

编辑:我需要这个函数来使用purrr::map()运行列表。更新的示例:

library(dplyr)
library(purrr)
list_df <- list(mtcars2 = mtcars %>% mutate(Petal.Length = 1),
iris2 = iris)
some_fun <- function(x){
df_name <- deparse(substitute(x))
head(x) %>%
rename("{df_name}" := "Petal.Length")
}
test <- map(list_df, some_fun)
list2env(test, .GlobalEnv)
mtcars2
iris2

尝试使用deparse(substitute((( 获取数据集的名称,然后使用 dplyr 的新大括号进行非标准评估:

library(dplyr)
some_fun <- function(x){
df_name <- deparse(substitute(x)) #Comes out as string of df's name
head(x) %>%
rename("{df_name}" := "Petal.Length") #df_name is evaluated, THEN becomes the new variable name for Petal.Length
}
some_fun(iris)

基本上首先评估大括号中的所有内容。

编辑:这是基于OP更新的更新。只需事先提取名称,然后通过(略有更新的(函数传递它们。

library(dplyr)
library(purrr)
list_df <- list(mtcars2 = mtcars %>% mutate(Petal.Length = 1),
iris2 = iris)
df_names <- names(list_df)
some_fun <- function(x, x_name){
df_name <- x_name
head(x) %>%
rename("{df_name}" := "Petal.Length")
}
test <- map2(list_df, df_names, some_fun) 
list2env(test, .GlobalEnv)
mtcars2
#   mpg cyl disp  hp drat    wt  qsec vs am gear carb mtcars2
#1 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4       1
#2 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4       1
#3 22.8   4  108  93 3.85 2.320 18.61  1  1    4    1       1
#4 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1       1
#5 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2       1
#6 18.1   6  225 105 2.76 3.460 20.22  1  0    3    1       1
iris2
#  Sepal.Length Sepal.Width iris2 Petal.Width Species
#1          5.1         3.5   1.4         0.2  setosa
#2          4.9         3.0   1.4         0.2  setosa
#3          4.7         3.2   1.3         0.2  setosa
#4          4.6         3.1   1.5         0.2  setosa
#5          5.0         3.6   1.4         0.2  setosa
#6          5.4         3.9   1.7         0.4  setosa

根据您评论中添加的信息,以下是我认为可能对您有用的另外几种方法。

从命名列表开始:

library(purrr)
library(dplyr)
countries <- c("ABC", "DEF", "GHI", "JKL", "MNO")
df1 <- data.frame(country = countries, value = 1:5)
df2 <- data.frame(country = countries, value = 6:10)
df_list <- list(df1 = df1, df2 = df2)
df_list
#> $df1
#>   country value
#> 1     ABC     1
#> 2     DEF     2
#> 3     GHI     3
#> 4     JKL     4
#> 5     MNO     5
#> 
#> $df2
#>   country value
#> 1     ABC     6
#> 2     DEF     7
#> 3     GHI     8
#> 4     JKL     9
#> 5     MNO    10

我们可以使用 purrrimap来使用每个元素的名称来重命名该元素的"value"列:

df_list %>%
imap(~ .x %>% rename("{.y}" := value))
#> $df1
#>   country df1
#> 1     ABC   1
#> 2     DEF   2
#> 3     GHI   3
#> 4     JKL   4
#> 5     MNO   5
#> 
#> $df2
#>   country df2
#> 1     ABC   6
#> 2     DEF   7
#> 3     GHI   8
#> 4     JKL   9
#> 5     MNO  10

但是,还有另一种合并这些数据集的方法,如果所有"值"列都是相同的类型,则可能更可取。

在这种情况下,我们可以将 dplyr 的bind_rows.id参数一起使用,在合并的数据集中添加一个标识符列。这样,所有值都在同一列中,但我们仍然可以知道它们来自哪个来源。

df_list %>%
bind_rows(.id = "df")
#>     df country value
#> 1  df1     ABC     1
#> 2  df1     DEF     2
#> 3  df1     GHI     3
#> 4  df1     JKL     4
#> 5  df1     MNO     5
#> 6  df2     ABC     6
#> 7  df2     DEF     7
#> 8  df2     GHI     8
#> 9  df2     JKL     9
#> 10 df2     MNO    10

创建于 2020-07-01 由 reprex 软件包 (v0.3.0(

我认为您可以通过将bind_rows.id一起使用来跳过此操作,这会将 df 名称作为合并中的一列添加:

library(tidyverse)
df1 <- data.frame(a = c(1, 2),
b = c(1, 2))
df2 <- data.frame(a = c(1, 2),
b = c(1, 2))
df_list <- lst(df1, df2)
dplyr::bind_rows(df_list, .id = "df_name")
#   df_name a b
# 1     df1 1 1
# 2     df1 2 2
# 3     df2 1 1
# 4     df2 2 2

最新更新