在 R 的 for 循环中使用 dplyr::rename 函数

问题描述 投票:0回答:3

我试图了解

dplyr::rename
函数如何在 R 中的 for 循环中工作。原则上,我想重命名来自另一个列表的多个数据帧的列名称。

这是一个失败的示例,我想使用来自

new.names
数据集的名称重命名每个数据集的第一列。

library(tidyverse)

iris1 <- iris
iris2 <- iris
iris3 <- iris

files <- list(iris1,iris2,iris3)

new.names <- c("change1","change2","change")

如果我尝试这个 for 循环,它会失败:

test <- list()
for(i in 1:length(files)){
  test[[i]] <- files[[i]] |> 
    dplyr::rename(new.names[i]=1)
}
test

为什么会这样?

r dplyr tidyverse
3个回答
2
投票

如果你想使用循环,你需要在左侧的名称上使用

!! sym()
以及海象运算符
:=

library(tidyverse)

iris1 <- iris
iris2 <- iris
iris3 <- iris

files <- list(iris1,iris2,iris3)

new.names <- c("change1","change2","change")

test <- list()

test <- list()
for(i in 1:length(files)){
  test[[i]] <- files[[i]] |> 
    dplyr::rename(!! sym(new.names[i]) := 1)
}
test |>
  map(head) # for printing
#> [[1]]
#>   change1 Sepal.Width Petal.Length 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
#> 
#> [[2]]
#>   change2 Sepal.Width Petal.Length 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
#> 
#> [[3]]
#>   change Sepal.Width Petal.Length 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

我们也可以在没有

for
循环的情况下做到这一点,然后我们需要
new.names
列表作为列表的列表,然后我们可以使用
purrr::map2()
:

library(tidyverse)

iris1 <- iris
iris2 <- iris
iris3 <- iris

files <- list(iris1,iris2,iris3)

new.names <- list(
  list(change1 = 1),
  list(change2 = 1),
  list(change = 1))

map2(files,
     new.names,
     ~ dplyr::rename(.x, !!! .y) %>% 
       head() # for printing
     )

#> [[1]]
#>   change1 Sepal.Width Petal.Length 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
#> 
#> [[2]]
#>   change2 Sepal.Width Petal.Length 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
#> 
#> [[3]]
#>   change Sepal.Width Petal.Length 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

创建于 2022 年 10 月 22 日,使用 reprex v2.0.2

为什么这有效?

在 dplyr 中,我们可以将调用构造为列表,然后使用

!!!
评估(或拼接)它们。这就是我们在这里所做的。

new.names
包含列表的列表。每个子列表都以新列名称作为名称,以旧列的位置作为值。

因此对于一个文件我们可以这样做:

dplyr::rename(files[[1]], !!! new.names[[1]]) |> head()

如果

new.names
只是一个简单的列表(没有子列表),那么这些值将没有名称,我们将无法构造调用。

最后,我们还可以使用

map2()
而不用列表列表构造调用,而是使用字符串:

new.names <- c("change1", "change2", "change")

map2(files,
     new.names,
     ~ dplyr::rename(.x, !! sym(.y) := 1) %>% 
       head() # for printing
     )

其逻辑与

for
循环中的逻辑相同:我们使用
sym()
将字符串转换为名称,使用
!!
对其求值,并使用海象运算符
:=
代替
=


1
投票

这是使用函数的不同方法

setNames()

test <- list()
for(i in 1:length(files)){
  test[[i]] <- files[[i]] %>%  
    setNames(c(new.names[i], names(files[[i]])[-1]))
}

> test %>% lapply(head)
#[[1]]
#  change1 Sepal.Width Petal.Length 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
#
#[[2]]
#  change2 Sepal.Width Petal.Length 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
#
#[[3]]
#  change Sepal.Width Petal.Length 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

1
投票

您还可以使用

dplyr::rename_with
以便将重命名部分作为函数动态传递,如下所示:

test <- list()
for(i in 1:length(files)){
  test[[i]] <- files[[i]] %>%
    dplyr::rename_with(function(x) { x <- new.names[i]; return(x) }, c(1) )

}
test

请阅读

renames_with
文档,了解指定函数和整洁选择的参数。

如果你不关心

dplyr::rename
,你能做的最简单的事情就是:

test <- list()
for(i in 1:length(files)){
  
  test[i] <- files[i]
  
  names(test[[i]])[1] <- new.names[i]
}
test
© www.soinside.com 2019 - 2024. All rights reserved.