Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dplyr 'rename' standard evaluation function not working as expected?

Tags:

r

dplyr

UPDATE: From comment below on this post, this is now working as expected, without the issues I laid out here.

Below is a toy example of using rename_ from dplyr. I was expecting to be able to change the column name back to it's original name using the second example below, but I'm guessing that function argument evaluation rules are somehow preventing it from working the way I think. There is an easy workaround using the original plyr package rename function (as well as using the base package names function), but I have a feeling I'm missing a dplyr solution to this.

I have a workaround as shown below, but I'd welcome both a dplyr solution to the second example working as I expect, or an explanation of why I shouldn't expect it to work the way I want it to.

Thank you, Matt

EDIT: I added an example below using rename_ to make this work, but is complicated. I assume if the bug that Hadley refers to below gets fixed, this will work as he shows below. But until then, my awkward way does, but it is probably better to use the standard plyr method. Also added base R technique at end for example completeness.

library(plyr)
library(dplyr)

# dataframe to operate on
dat <- data_frame(a=1, b=1)

# identifier with string of column name in dat
x <- "a"


# Renaming using standard evaluation this way works
dat %>%
    rename_("new" = x)
# Source: local data frame [1 x 2]
# 
#   new b
# 1   1 1


# But changing it back does not
# I expect "a" to be the name, not the identifier x
dat %>%
    rename_("new" = x) %>%
    rename_(x = "new")
# Source: local data frame [1 x 2]
# 
#   x b
# 1 1 1


# This works, but seems really awkward...
dat %>%
    rename_("newname" = x) %>%
    do(do.call(rename_, setNames(list(., "newname"), c(".data", x))))

# Source: local data frame [1 x 2]
# 
#   a b
# 1 1 1


# This works fine
dat %>%
    rename_("new" = x) %>%
    plyr::rename(c("new" = x))
# Source: local data frame [1 x 2]
# 
#   a b
# 1 1 1


# Base R way
datrn <- dat %>%
    rename_("newname" = x)
names(datrn)[names(datrn) == "newname"] = x
datrn
# Source: local data frame [1 x 2]
# 
#   a b
# 1 1 1
like image 557
mpettis Avatar asked Oct 28 '14 22:10

mpettis


1 Answers

There are a few thing that make this painful:

  1. c(x = "new") is the same as c("x" = "new"), and not the opposite of c(new = x).

  2. You can construct the vector you want with setNames(x, "new"), but...

  3. I forgot to add the .dots argument to rename_ (bug report at https://github.com/hadley/dplyr/issues/708) so you can't do:

    rename_(dat, .dots = setNames(x, "new"))
    

    Instead you need to use do.call:

    do.call(rename_, c(list(quote(dat)), list(setNames(x, "new"))))
    
like image 70
hadley Avatar answered Oct 06 '22 16:10

hadley