23

I'm trying to add a common prefix to each of the variable names in a data.frame. For example, using the mtcars data, I could add the prefix "cars." using the following code:

> data(mtcars)
> names(mtcars)
 [1] "mpg"  "cyl"  "disp" "hp"   "drat" "wt"   "qsec" "vs"  
 [9] "am"   "gear" "carb"
> names(mtcars) <- paste0("cars.", names(mtcars))
> names(mtcars)
 [1] "cars.mpg"  "cars.cyl"  "cars.disp" "cars.hp"  
 [5] "cars.drat" "cars.wt"   "cars.qsec" "cars.vs"  
 [9] "cars.am"   "cars.gear" "cars.carb"

However, I would like to do this as part of a piped operation (i.e., a series of functions strung together using %>%), using some of the dplyr syntax. It seems like some combination of rename and everything() should do the trick, but I don't know how to make it work. Does anyone have any ideas?

Jake Fisher
  • 3,220
  • 3
  • 26
  • 39

5 Answers5

34

Indeed, you can use rename_ (NSE rename itself doesn’t work):

data %>% rename_(.dots = setNames(names(.), paste0('cars.', names(.))))

… but honestly, why? Just assigning names directly is shorter and more readable:

data %>% setNames(paste0('cars.', names(.)))
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • Thanks! The actual use case is a little complicated -- in short, I'm doing a series of merges of one dataset to itself, and I don't want variables from the left hand side of the merge to get confused with variables of the same name from the right hand side of the merge. `merge` deals with this by assigning a suffix ".x" and ".y" to refer to the left- and right- hand sides of the merge, respectively, but I wanted the variables to have more descriptive names. I was also hoping to avoid saving an intermediate dataset with the new names, hence my effort to do this with a `dplyr` command. – Jake Fisher Nov 16 '15 at 18:05
  • 2
    `setNames(cars, paste0("cars.", names(cars))` was effective, though. Thanks again. – Jake Fisher Nov 16 '15 at 18:10
  • @Jake Well my second code example *doesn’t* use an intermediate data set. But yes, might as well use `setNames` instead of ` ``names<-`` `. – Konrad Rudolph Nov 16 '15 at 18:48
  • 1
    I propose to use `data.table::setnames()` instead of `setNames()` from `stats` . This has the advantage of throwing an error if the lengths of the old and new name vectors do not match which is a little saver. – der_grund Jul 06 '17 at 07:58
  • @der_grund It would be a bit overkill to load `data.table` just for that, if (like me) you’re not otherwise using the package. One more reason to write smaller packages with self-contained functionality instead of the conventional, bloated R packages. – Konrad Rudolph Jul 06 '17 at 08:39
  • @KonradRudolph I would not load the whole package, but simply call the function with `data.table::`. From my understanding, this does not load the whole package. Is that correct? – der_grund Jul 06 '17 at 13:08
  • @der_grund No, that still loads the whole package (it just doesn’t attach it). But even if it didn’t it would nevertheless include all of ‹data.table› as a logical *dependency* of your code. And while I’m generally not against dependencies, having such a huge dependency for a single function would strike most people (outside of R) as unreasonable. – Konrad Rudolph Jul 06 '17 at 13:25
  • @KonradRudolph Thanks for the explanation. I will take that into account next time. – der_grund Jul 06 '17 at 14:35
17

The latest solution (2020) seems to use rename_with, which is available in dplyr 1.0.0 and higher:

mtcars %>% rename_with(.fn = ~ paste0("Myprefix_", .x, "_Mypostfix")) -> mtcars.custom

Use the .cols = argument to specify a subset of variables, it defaults to everything().

slhck
  • 36,575
  • 28
  • 148
  • 201
jiggunjer
  • 1,905
  • 1
  • 19
  • 18
  • Which package is that from? Please add a documentation link. – slhck Oct 27 '20 at 19:57
  • 1
    @slhck the package name is in the question title... – jiggunjer Oct 28 '20 at 15:07
  • It's not like suggestions for functions from other packages aren't common around here. In particular, if you do a web search for "rename_with r", you get various references for a function from `tidytable` before any results for `dplyr` appear. In my case I had a pre-1.0 version so it wasn't available. – slhck Oct 28 '20 at 18:42
11

For future readers, dplyr now can do this with the select_if, select_at, and select_all functions:

dplyr::select_all(mtcars, .funs = funs(paste0("cars.", .)))
Jake Fisher
  • 3,220
  • 3
  • 26
  • 39
  • with dplyr version 0.7.4 it says "Error in paste0("cars.", .) : object '.' not found" – Make42 Jan 08 '19 at 13:05
  • Using cars, this works. However, on my data, it throws a different error using dplyr 0.7.6 (loaded via tidyverse 1.2.1): "Error: `nm` must be `NULL` or a character vector the same length as `x`. I'm confused by this. – aae Mar 07 '19 at 15:44
11

Another dplyr solution:

I find it easiest with the dplyr rename_all, rename_at, rename_if which from v.1.0.4. have been superseded by rename_with...

Try this for renaming all column names:

mtcars %>% rename_all(function(x){paste0("cars.", x)}) # older dplyr versions
mtcars %>% rename_with(.cols = everything(), function(x){paste0("cars.", x)}) # v.1.0.4.

Try this for renaming "some" column names:

mtcars %>% rename_at(vars(hp:wt) ,function(x){paste0("cars.", x)}) # older dplyr versions
mtcars %>% rename_with(.cols = hp:wt, function(x){paste0("cars.", x)}) # v.1.0.4.
T. BruceLee
  • 501
  • 4
  • 16
  • 1
    from dplyr `v1.0.4` documentation ("rename_if(), rename_at(), and rename_all() have been superseded by rename_with(). The matching select statements have been superseded by the combination of a select() + rename_with()." – Brian D Apr 09 '21 at 22:03
  • I think you have your arguments backward in your `rename_with()` example, or at least the first one: your `mtcars %>% rename_with(everything(), function(x){paste0("cars.", x)})` line threw an error for me, but `mtcars %>% rename_with(function(x){paste0("cars.", x)}, everything())` worked as intended/described. (Perhaps the function has changed?) – Aaron Montgomery Oct 12 '21 at 17:04
4

dplyr now expects lists and will throw a warning:

Warning message:
funs() is soft deprecated as of dplyr 0.8.0
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

you can solve this example as follows:


dplyr::select_all(mtcars, list(~ paste0("cars.", .)))
#>                     cars.mpg cars.cyl cars.disp cars.hp cars.drat cars.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
#> Valiant                 18.1        6     225.0     105      2.76   3.460
#> Duster 360              14.3        8     360.0     245      3.21   3.570
#> Merc 240D               24.4        4     146.7      62      3.69   3.190
#> Merc 230                22.8        4     140.8      95      3.92   3.150
#> Merc 280                19.2        6     167.6     123      3.92   3.440
#> Merc 280C               17.8        6     167.6     123      3.92   3.440
#> Merc 450SE              16.4        8     275.8     180      3.07   4.070
#> Merc 450SL              17.3        8     275.8     180      3.07   3.730
#> Merc 450SLC             15.2        8     275.8     180      3.07   3.780
#> Cadillac Fleetwood      10.4        8     472.0     205      2.93   5.250
#> Lincoln Continental     10.4        8     460.0     215      3.00   5.424
#> Chrysler Imperial       14.7        8     440.0     230      3.23   5.345
#> Fiat 128                32.4        4      78.7      66      4.08   2.200
#> Honda Civic             30.4        4      75.7      52      4.93   1.615
#> Toyota Corolla          33.9        4      71.1      65      4.22   1.835
#> Toyota Corona           21.5        4     120.1      97      3.70   2.465
#> Dodge Challenger        15.5        8     318.0     150      2.76   3.520
#> AMC Javelin             15.2        8     304.0     150      3.15   3.435
#> Camaro Z28              13.3        8     350.0     245      3.73   3.840
#> Pontiac Firebird        19.2        8     400.0     175      3.08   3.845
#> Fiat X1-9               27.3        4      79.0      66      4.08   1.935
#> Porsche 914-2           26.0        4     120.3      91      4.43   2.140
#> Lotus Europa            30.4        4      95.1     113      3.77   1.513
#> Ford Pantera L          15.8        8     351.0     264      4.22   3.170
#> Ferrari Dino            19.7        6     145.0     175      3.62   2.770
#> Maserati Bora           15.0        8     301.0     335      3.54   3.570
#> Volvo 142E              21.4        4     121.0     109      4.11   2.780
#>                     cars.qsec cars.vs cars.am cars.gear cars.carb
#> Mazda RX4               16.46       0       1         4         4
#> Mazda RX4 Wag           17.02       0       1         4         4
#> Datsun 710              18.61       1       1         4         1
#> Hornet 4 Drive          19.44       1       0         3         1
#> Hornet Sportabout       17.02       0       0         3         2
#> Valiant                 20.22       1       0         3         1
#> Duster 360              15.84       0       0         3         4
#> Merc 240D               20.00       1       0         4         2
#> Merc 230                22.90       1       0         4         2
#> Merc 280                18.30       1       0         4         4
#> Merc 280C               18.90       1       0         4         4
#> Merc 450SE              17.40       0       0         3         3
#> Merc 450SL              17.60       0       0         3         3
#> Merc 450SLC             18.00       0       0         3         3
#> Cadillac Fleetwood      17.98       0       0         3         4
#> Lincoln Continental     17.82       0       0         3         4
#> Chrysler Imperial       17.42       0       0         3         4
#> Fiat 128                19.47       1       1         4         1
#> Honda Civic             18.52       1       1         4         2
#> Toyota Corolla          19.90       1       1         4         1
#> Toyota Corona           20.01       1       0         3         1
#> Dodge Challenger        16.87       0       0         3         2
#> AMC Javelin             17.30       0       0         3         2
#> Camaro Z28              15.41       0       0         3         4
#> Pontiac Firebird        17.05       0       0         3         2
#> Fiat X1-9               18.90       1       1         4         1
#> Porsche 914-2           16.70       0       1         5         2
#> Lotus Europa            16.90       1       1         5         2
#> Ford Pantera L          14.50       0       1         5         4
#> Ferrari Dino            15.50       0       1         5         6
#> Maserati Bora           14.60       0       1         5         8
#> Volvo 142E              18.60       1       1         4         2

Created on 2019-07-31 by the reprex package (v0.3.0)

JD Long
  • 59,675
  • 58
  • 202
  • 294