34

dplyr's rename functions require the new column name to be passed in as unquoted variable names. However I have a function where the column name is constructed by pasting a string onto an argument passed in and so is a character string.

For example say I had this function

myFunc <- function(df, col){
  new <- paste0(col, '_1')
  out <- dplyr::rename(df, new = old)
  return(out)
}

If I run this

df <- data.frame(a = 1:3, old = 4:6)
myFunc(df, 'x')

I get

  a new
1 1   4
2 2   5
3 3   6

Whereas I want the 'new' column to be the name of the string I constructed ('x_1'), i.e.

  a x_1
1 1   4
2 2   5
3 3   6

Is there anyway of doing this?

Filburt
  • 17,626
  • 12
  • 64
  • 115
user1165199
  • 6,351
  • 13
  • 44
  • 60
  • 4
    From the [announcement of `dplyr 0.3`](http://blog.rstudio.org/2014/10/13/dplyr-0-3-2/): "You can now program with `dplyr` – every function that uses non-standard evaluation (NSE) also has a standard evaluation (SE) twin that ends in `_` [...] The SE version of each function has similar arguments, but they must be explicitly “quoted”." Thus, check if `rename_` might be useful here. – Henrik Oct 20 '14 at 16:40
  • Thanks, that is useful to know but it doesn't actually change anything in this case. It would work if the column I was passing in was the old column name, but changing the above function to use rename_ (and putting old in quotes) still returns the same – user1165199 Oct 20 '14 at 16:56
  • 2
    @user1165199 I would do `colnames(df)[colnames(df) %in% "old"] <- paste0("x","_")` (in a function if that is necessary) as it is able to replace a vector of names easily. – akrun Oct 20 '14 at 18:18
  • Thanks akrun, that is what I have done in the end. Was just hoping there was a neater way of doing it using an existing function. – user1165199 Oct 21 '14 at 09:23
  • I want to send a concatenated list to all the column names. `df` <%>` `new <- c("a.new", "b.new")` %>% `names(.) <- rename_(new)` – mtelesha Nov 10 '15 at 15:28

2 Answers2

24

I think this is what you were looking for. It is the use of rename_ as @Henrik suggested, but the argument has an, lets say, interesting, name:

> myFunc <- function(df, col){
+   new <- paste0(col, '_1')
+   out <- dplyr::rename_(df, .dots=setNames(list(col), new))
+   return(out)
+ }
> myFunc(data.frame(x=c(1,2,3)), "x")
  x_1
1   1
2   2
3   3
>

Note the use of setNames to use the value of new as name in the list.

kasterma
  • 4,259
  • 1
  • 20
  • 27
  • 5
    I'm not sure what the `list(col)` is trying to do. If you simply do `.dots=setNames(col, new)`, your example still works. And if you have multiple columns you are renaming, `list()` will cause problems because `length(list(col)) != length(new)` – gregmacfarlane Aug 25 '16 at 14:40
  • 1
    This is now deprecated. How can this be achieved using the current "tidy evaluation"? – Karthik Thrikkadeeri Jan 06 '22 at 09:42
1

Recent updates to tidyr and dplyr allow you to use the rename_with function.

Say you have a data frame:

library(tidyverse)

df <- tibble(V0 = runif(10), V1 = runif(10), V2 = runif(10), key=letters[1:10])

And you want to change all of the "V" columns. Usually, my reference for columns like this comes from a json file, which in R is a labeled list. e.g.,

colmapping <- c("newcol1", "newcol2", "newcol3")
names(colmapping) <- paste0("V",0:2)

You can then use the following to change the names of df to the strings in the colmapping list:

df <- rename_with(.data = df, .cols = starts_with("V"), .fn = function(x){colmapping[x]})
Brian Goodwin
  • 391
  • 3
  • 14