在此示例中,我使用的是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