如何通过列索引 dplyr 重命名列?
How to dplyr rename a column, by column index?
以下代码重命名数据集中的第一列:
require(dplyr)
mtcars %>%
setNames(c("RenamedColumn", names(.)[2:length(names(.))]))
想要的结果:
RenamedColumn cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
是否可以使用 rename
和列索引得到相同的结果?
这个:
mtcars %>%
rename(1 = "ChangedNameAgain")
将失败:
Error in source("~/.active-rstudio-document", echo = TRUE) :
~/.active-rstudio-document:7:14: unexpected '='
6: mtcars %>%
7: rename(1 =
^
同样,尝试使用 rename_
或 .[[1]]
作为列引用将 return 出错。
从 dplyr
0.7.5
、rlang
0.2.1
、tidyselect
0.2.4
开始,这很有效:
library(dplyr)
rename(mtcars, ChangedNameAgain = 1)
# ChangedNameAgain cyl disp hp drat wt qsec vs am gear carb
# Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
# Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
# Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
# Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
# Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
# ...
原始答案和编辑现已过时:
rename()
的逻辑是new_name = old_name
,所以ChangedNameAgain = 1
比1 = ChangedNameAgain
更有道理。
我建议:
mtcars %>% rename_(ChangedNameAgain = names(.)[1])
# ChangedNameAgain cyl disp hp drat wt qsec vs am gear carb
# Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
# Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
# Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
# Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
# Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
# Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
编辑
自从 dplyr
.
的 0.6/0.7 版本以来,我还没有完全了解基于 rlang
的新 dplyr
编程系统
我最初的回答中使用的 rename
的下划线后缀版本现已弃用,并且根据@jzadra 的评论,它无论如何都无法使用 "foo bar"
.[= 等语法上有问题的名称48=]
这是我对基于 rlang
的新非标准评估系统的尝试。不要犹豫,在评论中告诉我我做错了什么:
df <- tibble("foo" = 1:2, "bar baz" = letters[1:2])
# # A tibble: 2 x 2
# foo `bar baz`
# <int> <chr>
# 1 1 a
# 2 2 b
首先我直接用 rename()
尝试,但不幸的是我遇到了错误。源码里好像是FIXME
(或者这个FIXME不相关?)(我用的是dplyr
0.7.4),所以以后可以用:
df %>% rename(qux = !! quo(names(.)[[2]]))
# Error: Expressions are currently not supported in `rename()`
(编辑:现在的错误消息(dplyr 0.7.5)显示为Error in UseMethod("rename_") : no applicable method for 'rename_' applied to an object of class "function"
)
(更新 2018-06-14:df %>% rename(qux = !! quo(names(.)[[2]]))
现在似乎可以工作,仍然使用 dplyr 0.7.5,不确定底层包是否更改)。
这是 select
的解决方法。它不会像 rename
那样保留列顺序:
df %>% select(qux = !! quo(names(.)[[2]]), everything())
# # A tibble: 2 x 2
# qux foo
# <chr> <int>
# 1 a 1
# 2 b 2
如果我们想把它放在一个函数中,我们必须用 :=
稍微修改它以允许在左侧取消引用。如果我们想对像字符串和裸变量名这样的输入具有鲁棒性,我们必须使用 enquo()
和 quo_name()
的 "dark magic"(或者说 vignette)(老实说我不完全明白它的作用):
rename_col_by_position <- function(df, position, new_name) {
new_name <- enquo(new_name)
new_name <- quo_name(new_name)
select(df, !! new_name := !! quo(names(df)[[position]]), everything())
}
这适用于作为字符串的新名称:
rename_col_by_position(df, 2, "qux")
# # A tibble: 2 x 2
# qux foo
# <chr> <int>
# 1 a 1
# 2 b 2
这适用于新名称作为 quosure:
rename_col_by_position(df, 2, quo(qux))
# # A tibble: 2 x 2
# qux foo
# <chr> <int>
# 1 a 1
# 2 b 2
这适用于新名称作为裸名:
rename_col_by_position(df, 2, qux)
# # A tibble: 2 x 2
# qux foo
# <chr> <int>
# 1 a 1
# 2 b 2
即使这样也行得通:
rename_col_by_position(df, 2, `qux quux`)
# # A tibble: 2 x 2
# `qux quux` foo
# <chr> <int>
# 1 a 1
# 2 b 2
恕我直言 rlang
@Aurele 的建议在这里太多了。
解决方案 1:使用大括号管道管道上下文:
bcMatrix %>% {colnames(.)[1] = "foo"; .}
解决方案 2:或者(ab)使用 magrittr
包中的 tee 运算符 %>%
(如果使用 dplyr
则无论如何安装)执行重命名作为副作用:
bcMatrix %T>% {colnames(.)[1] = "foo"}
解决方案 3:使用简单的辅助函数:
rename_by_pos = function(df, index, new_name){
colnames(df)[index] = new_name
df
}
iris %>% rename_by_pos(2,"foo")
这里有几个可以说更容易阅读的备选解决方案,因为它们不围绕 .
参考。 select
了解列索引,因此如果您要重命名第一列,您可以简单地执行
mtcars %>% select( RenamedColumn = 1, everything() )
但是,使用 select
的问题在于,如果您在中间重命名列,它将对列重新排序。要解决此问题,您必须 pre-select 您要重命名的列左侧的列:
## This will rename the 7th column without changing column order
mtcars %>% select( 1:6, RenamedColumn = 7, everything() )
另一种选择是使用新的 rename_at
,它也理解列索引:
## This will also rename the 7th column without changing the order
## Credit for simplifying the second argument: Moody_Mudskipper
mtcars %>% rename_at( 7, ~"RenamedColumn" )
~
是必需的,因为 rename_at
非常灵活,可以接受函数作为它的第二个参数。例如,mtcars %>% rename_at( c(2,4), toupper )
将使第二和第四列的名称大写。
dplyr
已取代 rename_at()
with rename_with()
。您可以像这样按索引重命名列:
library(tidyverse)
mtcars %>%
rename_with(.cols = 1, ~"renamed_column")
#> renamed_column cyl disp hp drat wt qsec vs am gear
#> Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4
#> Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4
#> Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4
#> Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3
#> Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3
#> ...
确保在新列名称前包含波浪号 (~
)*。
另请注意,如果您引入glue
包,您可以像这样修改现有的列名:
library(glue)
mtcars %>%
rename_with(.cols = 1, ~glue::glue("renamed_{.}"))
#> renamed_mpg cyl disp hp drat wt qsec vs am gear carb
#> Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
#> Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
#> Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
#> Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
#> Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
#> ...
将上述方法应用于多列只是使用冒号(:
)传递列索引号范围或使用c()
在向量中传递多个索引的问题;这是两者的组合:
mtcars %>%
rename_with(.cols = c(1:3, 5), ~glue::glue("renamed_{.}"))
#> renamed_mpg renamed_cyl renamed_disp hp renamed_drat wt
#> Mazda RX4 21.0 6 160.0 110 3.90 2.620
#> Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875
#> Datsun 710 22.8 4 108.0 93 3.85 2.320
#> Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215
#> Hornet Sportabout 18.7 8 360.0 175 3.15 3.440
#> ...
请记住,由于 .
表示当前列名,您可以像这样对其应用字符串修改函数:
mtcars %>%
rename_with(.cols = c(1:3),
~glue::glue("renamed_{str_replace(.,'mpg','miles_per_gallon')}"))
#> renamed_miles_per_gallon renamed_cyl renamed_disp hp
#> Mazda RX4 21.0 6 160.0 110
#> Mazda RX4 Wag 21.0 6 160.0 110
#> Datsun 710 22.8 4 108.0 93
#> Hornet 4 Drive 21.4 6 258.0 110
#> Hornet Sportabout 18.7 8 360.0 175
#> ...
*您可以详细了解 ~
和 .
NSE 函数 shorthand .
以下代码重命名数据集中的第一列:
require(dplyr)
mtcars %>%
setNames(c("RenamedColumn", names(.)[2:length(names(.))]))
想要的结果:
RenamedColumn cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
是否可以使用 rename
和列索引得到相同的结果?
这个:
mtcars %>%
rename(1 = "ChangedNameAgain")
将失败:
Error in source("~/.active-rstudio-document", echo = TRUE) :
~/.active-rstudio-document:7:14: unexpected '='
6: mtcars %>%
7: rename(1 =
^
同样,尝试使用 rename_
或 .[[1]]
作为列引用将 return 出错。
从 dplyr
0.7.5
、rlang
0.2.1
、tidyselect
0.2.4
开始,这很有效:
library(dplyr)
rename(mtcars, ChangedNameAgain = 1)
# ChangedNameAgain cyl disp hp drat wt qsec vs am gear carb
# Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
# Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
# Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
# Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
# Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
# ...
原始答案和编辑现已过时:
rename()
的逻辑是new_name = old_name
,所以ChangedNameAgain = 1
比1 = ChangedNameAgain
更有道理。
我建议:
mtcars %>% rename_(ChangedNameAgain = names(.)[1])
# ChangedNameAgain cyl disp hp drat wt qsec vs am gear carb
# Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
# Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
# Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
# Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
# Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
# Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
编辑
自从 dplyr
.
rlang
的新 dplyr
编程系统
我最初的回答中使用的 rename
的下划线后缀版本现已弃用,并且根据@jzadra 的评论,它无论如何都无法使用 "foo bar"
.[= 等语法上有问题的名称48=]
这是我对基于 rlang
的新非标准评估系统的尝试。不要犹豫,在评论中告诉我我做错了什么:
df <- tibble("foo" = 1:2, "bar baz" = letters[1:2])
# # A tibble: 2 x 2
# foo `bar baz`
# <int> <chr>
# 1 1 a
# 2 2 b
首先我直接用 rename()
尝试,但不幸的是我遇到了错误。源码里好像是FIXME
(或者这个FIXME不相关?)(我用的是dplyr
0.7.4),所以以后可以用:
df %>% rename(qux = !! quo(names(.)[[2]]))
# Error: Expressions are currently not supported in `rename()`
(编辑:现在的错误消息(dplyr 0.7.5)显示为Error in UseMethod("rename_") : no applicable method for 'rename_' applied to an object of class "function"
)
(更新 2018-06-14:df %>% rename(qux = !! quo(names(.)[[2]]))
现在似乎可以工作,仍然使用 dplyr 0.7.5,不确定底层包是否更改)。
这是 select
的解决方法。它不会像 rename
那样保留列顺序:
df %>% select(qux = !! quo(names(.)[[2]]), everything())
# # A tibble: 2 x 2
# qux foo
# <chr> <int>
# 1 a 1
# 2 b 2
如果我们想把它放在一个函数中,我们必须用 :=
稍微修改它以允许在左侧取消引用。如果我们想对像字符串和裸变量名这样的输入具有鲁棒性,我们必须使用 enquo()
和 quo_name()
的 "dark magic"(或者说 vignette)(老实说我不完全明白它的作用):
rename_col_by_position <- function(df, position, new_name) {
new_name <- enquo(new_name)
new_name <- quo_name(new_name)
select(df, !! new_name := !! quo(names(df)[[position]]), everything())
}
这适用于作为字符串的新名称:
rename_col_by_position(df, 2, "qux")
# # A tibble: 2 x 2
# qux foo
# <chr> <int>
# 1 a 1
# 2 b 2
这适用于新名称作为 quosure:
rename_col_by_position(df, 2, quo(qux))
# # A tibble: 2 x 2
# qux foo
# <chr> <int>
# 1 a 1
# 2 b 2
这适用于新名称作为裸名:
rename_col_by_position(df, 2, qux)
# # A tibble: 2 x 2
# qux foo
# <chr> <int>
# 1 a 1
# 2 b 2
即使这样也行得通:
rename_col_by_position(df, 2, `qux quux`)
# # A tibble: 2 x 2
# `qux quux` foo
# <chr> <int>
# 1 a 1
# 2 b 2
恕我直言 rlang
@Aurele 的建议在这里太多了。
解决方案 1:使用大括号管道管道上下文:
bcMatrix %>% {colnames(.)[1] = "foo"; .}
解决方案 2:或者(ab)使用 magrittr
包中的 tee 运算符 %>%
(如果使用 dplyr
则无论如何安装)执行重命名作为副作用:
bcMatrix %T>% {colnames(.)[1] = "foo"}
解决方案 3:使用简单的辅助函数:
rename_by_pos = function(df, index, new_name){
colnames(df)[index] = new_name
df
}
iris %>% rename_by_pos(2,"foo")
这里有几个可以说更容易阅读的备选解决方案,因为它们不围绕 .
参考。 select
了解列索引,因此如果您要重命名第一列,您可以简单地执行
mtcars %>% select( RenamedColumn = 1, everything() )
但是,使用 select
的问题在于,如果您在中间重命名列,它将对列重新排序。要解决此问题,您必须 pre-select 您要重命名的列左侧的列:
## This will rename the 7th column without changing column order
mtcars %>% select( 1:6, RenamedColumn = 7, everything() )
另一种选择是使用新的 rename_at
,它也理解列索引:
## This will also rename the 7th column without changing the order
## Credit for simplifying the second argument: Moody_Mudskipper
mtcars %>% rename_at( 7, ~"RenamedColumn" )
~
是必需的,因为 rename_at
非常灵活,可以接受函数作为它的第二个参数。例如,mtcars %>% rename_at( c(2,4), toupper )
将使第二和第四列的名称大写。
dplyr
已取代 rename_at()
with rename_with()
。您可以像这样按索引重命名列:
library(tidyverse)
mtcars %>%
rename_with(.cols = 1, ~"renamed_column")
#> renamed_column cyl disp hp drat wt qsec vs am gear
#> Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4
#> Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4
#> Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4
#> Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3
#> Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3
#> ...
确保在新列名称前包含波浪号 (~
)*。
另请注意,如果您引入glue
包,您可以像这样修改现有的列名:
library(glue)
mtcars %>%
rename_with(.cols = 1, ~glue::glue("renamed_{.}"))
#> renamed_mpg cyl disp hp drat wt qsec vs am gear carb
#> Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
#> Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
#> Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
#> Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
#> Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
#> ...
将上述方法应用于多列只是使用冒号(:
)传递列索引号范围或使用c()
在向量中传递多个索引的问题;这是两者的组合:
mtcars %>%
rename_with(.cols = c(1:3, 5), ~glue::glue("renamed_{.}"))
#> renamed_mpg renamed_cyl renamed_disp hp renamed_drat wt
#> Mazda RX4 21.0 6 160.0 110 3.90 2.620
#> Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875
#> Datsun 710 22.8 4 108.0 93 3.85 2.320
#> Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215
#> Hornet Sportabout 18.7 8 360.0 175 3.15 3.440
#> ...
请记住,由于 .
表示当前列名,您可以像这样对其应用字符串修改函数:
mtcars %>%
rename_with(.cols = c(1:3),
~glue::glue("renamed_{str_replace(.,'mpg','miles_per_gallon')}"))
#> renamed_miles_per_gallon renamed_cyl renamed_disp hp
#> Mazda RX4 21.0 6 160.0 110
#> Mazda RX4 Wag 21.0 6 160.0 110
#> Datsun 710 22.8 4 108.0 93
#> Hornet 4 Drive 21.4 6 258.0 110
#> Hornet Sportabout 18.7 8 360.0 175
#> ...
*您可以详细了解 ~
和 .
NSE 函数 shorthand