How to Dplyr Rename a Column, by Column Index

How to dplyr rename a column, by column index?

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

Rename multiple columns with series index using dplyr in R

Or using rename_with

library(dplyr)
library(stringr)
test %>%
rename_with(~ str_c('t', 0:2), X0:X2)

Changing specific column names using pipe

With tidyverse, we can use rename_with

library(dplyr)
mtcars <- mtcars %>%
rename_with(~ c('a', 'b'), 2:3)

names(mtcars)
#[1] "mpg" "a" "b" "hp" "drat" "wt" "qsec" "vs" "am" "gear" "carb"

We could use replace with names<-

head(mtcars) %>% 
`names<-`(replace(names(.), 2:3, c('a', 'b')))

-output

#                   mpg a   b  hp drat    wt  qsec vs am gear carb
#Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
#Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
#Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
#Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
#Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
#Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1

How to rename selected columns using dplyr with new column names as strings

If you want to use dplyr's rename function, it would be best to create a named vector / list and call it using the .dots argument in the standard evaluation version:

cols <- c("Sepal.Length", "Petal.Length")
to_app <- ".xxx"
cols <- setNames(cols, paste0(cols, to_app))

df %>% rename_(.dots = cols)

## A tibble: 5 × 3
# Sepal.Length.xxx Sepal.Width Petal.Length.xxx
#* <dbl> <dbl> <dbl>
#1 5.1 3.5 1.4
#2 4.9 3.0 1.4
#3 4.7 3.2 1.3
#4 4.6 3.1 1.5
#5 5.0 3.6 1.4

Note however, that this approach is subject to change with the next version 0.6.0 of dplyr (see e.g. http://blog.rstudio.org/2017/04/13/dplyr-0-6-0-coming-soon/ and http://dplyr.tidyverse.org/articles/programming.html).

Renaming multiple columns with indices in R

These steps can help you:

colname <- names(df)

colname[2:6] <- paste(colname[2:6], "2014")
colname[7:18] <- paste(colname[7:18], "2015")
colname[19:30] <- paste(colname[19:30], "2016")

#Now set the column name in data frame
colnames(df) <- colname


# Column names after modification
#>names(df)
# [1] "x" "Aug. 2014" "Sept. 2014" "Oct. 2014" "Nov. 2014" #"Dec. 2014" "Jan. 2015" "Feb. 2015" "March 2015" "Apr. 2015"
#[11] "May 2015" "June 2015" "July 2015" "Aug. 2015" "Sept. 2015" #"Oct. 2015" "Nov. 2015" "Dec. 2015" "Jan. 2016" "Feb 2016"
#[21] "March 2016" "April 2016" "May 2016" "June 2016" "July 2016" "Aug #2016" "Sept 2016" "Oct 2016" "Nov 2016" "Dec 2016"
#[31] "Jan " "Feb " "Mar" "April " "May" #"June" "July " "Aug " "Sept " "Oct "
#[41] "Nov " "Dec" "Jan 4th"

How to rename columns by their number?

Full example to my comment:

dataset <- ...
new_names <- c("new_name_1", "new_name_2", ...)
dataset <- dataset %>% set_names(new_names)

If you only want to replace some older names, use something like this:

dataset <- ...
mtch <- c("old_name_2" = "new_name_2", ...)
new_names <- names(dataset)
new_names[names(mtch)] <- as.character(mtch)
dataset <- dataset %>% set_names(new_names)

Renaming multiple columns from vector in dplyr chain

An option with rename_at would be

df %>% 
rename_at(vars(starts_with('old_name')), ~ new_names)
# A tibble: 1 x 6
# RID Var1 Var2 new_name1 new_name2 new_name3
# <dbl> <chr> <chr> <dbl> <dbl> <dbl>
#1 1.00 A B 4.00 8.00 20.0

But, it is possible to make a function that works with rename_if by creating a logical index on the column names

df %>%
rename_if(grepl("^old_name", names(.)), ~ new_names)
# A tibble: 1 x 6
# RID Var1 Var2 new_name1 new_name2 new_name3
# <dbl> <chr> <chr> <dbl> <dbl> <dbl>
#1 1.00 A B 4.00 8.00 20.0

The rename_if in general is checking at the values of the columns instead of the column names i.e.

new_names2 <- c('var1', 'var2')
df %>%
rename_if(is.character, ~ new_names2)
# A tibble: 1 x 6
# RID var1 var2 old_name1 old_name2 old_name3
# <dbl> <chr> <chr> <dbl> <dbl> <dbl>
#1 1.00 A B 4.00 8.00 20.0

Rename all columns except id column by adding a prefix using dplyr

library(dplyr)

df %>%
dplyr::rename_with(~ paste0("source_", .), -id)

The third argument to rename_with is .cols, where you can use tidyselect syntax to select the columns. Here -id excludes this column.


Per the comments the . syntax is a cleaner/simpler style than an writing an anonymous function, but you could accomplish this equivalently as:

df %>% 
dplyr::rename_with(function(x) paste0("source_", x), -id)


Related Topics



Leave a reply



Submit