The following code renames first column in the data set:
require(dplyr)
mtcars %>%
setNames(c("RenamedColumn", names(.)[2:length(names(.))]))
Desired results:
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
Would it be possible to arrive at the same result using rename
and column index?
This:
mtcars %>%
rename(1 = "ChangedNameAgain")
will fail:
Error in source("~/.active-rstudio-document", echo = TRUE) :
~/.active-rstudio-document:7:14: unexpected '='
6: mtcars %>%
7: rename(1 =
^
Similarly trying to use rename_
or .[[1]]
as column reference will return an error.
As of dplyr
0.7.5
, rlang
0.2.1
, tidyselect
0.2.4
, this simply works:
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
# ...
Original answer and edits now obsolete:
The logic of rename()
is new_name = old_name
, so ChangedNameAgain = 1
would make more sense than 1 = ChangedNameAgain
.
I would suggest:
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
Edit
I have yet to wrap my head around the new dplyr
programming system based on rlang
, since versions 0.6/0.7 of dplyr
.
The underscore-suffixed version of rename
used in my initial answer is now deprecated, and per @jzadra's comment, it didn't work anyway with syntactically problematic names like "foo bar"
.
Here is my attempt with the new rlang
-based Non Standard Evaluation system. Do not hesitate to tell me what I've done wrong, in the comments:
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
First I try directly with rename()
but unfortunately I've got an error. It seems to be a FIXME
(or is this FIXME unrelated?) in the source code (I'm using dplyr
0.7.4), so it could work in the future:
df %>% rename(qux = !! quo(names(.)[[2]]))
# Error: Expressions are currently not supported in `rename()`
(Edit: the error message now (dplyr 0.7.5) reads Error in UseMethod("rename_") : no applicable method for 'rename_' applied to an object of class "function"
)
(Update 2018-06-14: df %>% rename(qux = !! quo(names(.)[[2]]))
now seems to work, still with dplyr 0.7.5, not sure if an underlying package changed).
Here is a workaround with select
that works. It doesn't preserve column order like rename
though:
df %>% select(qux = !! quo(names(.)[[2]]), everything())
# # A tibble: 2 x 2
# qux foo
# <chr> <int>
# 1 a 1
# 2 b 2
And if we want to put it in a function, we'd have to slightly modify it with :=
to allow unquoting on the left hand side. If we want to be robust to inputs like strings and bare variable names, we have to use the "dark magic" (or so says the vignette) of enquo()
and quo_name()
(honestly I don't fully understand what it does):
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())
}
This works with new name as a string:
rename_col_by_position(df, 2, "qux")
# # A tibble: 2 x 2
# qux foo
# <chr> <int>
# 1 a 1
# 2 b 2
This works with new name as a quosure:
rename_col_by_position(df, 2, quo(qux))
# # A tibble: 2 x 2
# qux foo
# <chr> <int>
# 1 a 1
# 2 b 2
This works with new name as a bare name:
rename_col_by_position(df, 2, qux)
# # A tibble: 2 x 2
# qux foo
# <chr> <int>
# 1 a 1
# 2 b 2
And even this works:
rename_col_by_position(df, 2, `qux quux`)
# # A tibble: 2 x 2
# `qux quux` foo
# <chr> <int>
# 1 a 1
# 2 b 2