bhffs
bhffs

Reputation: 133

Selectively Rename R Data Frame Column Names Using a Key, Value Pair Dictionary

I know there's an easy way to do this but I can't remember how I did it and can't find my notes. Basically I have a data frame with a bunch of column names. I also have a key,value pair data frame that has some new column names that need to replace the existing ones. I want to rename all of the columns that have a pair (and none that don't). So for example we can use mtcars:

x<-mtcars
idkey <- data.frame("original" =  c("cyl","hp"), "new" = c("cylinder", "horsepower"))
> head(x)
                   mpg cyl disp  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

> idkey
  original        new
1      cyl   cylinder
2       hp horsepower

I just want to replace the column names in x that exist in idkey. So after the replacement names(x) will go from this

> names(x)
 [1] "mpg"  "cyl"  "disp" "hp"   "drat" "wt"   "qsec" "vs"   "am"   "gear" "carb"

to this:

> names(x)
 [1] "mpg"  "cylinder"  "disp" "horsepower"   "drat" "wt"   "qsec" "vs"   "am"   "gear" "carb"

Note I would need this to only rename the columns which exist in the key, so some columns may not get renamed and they wouldn't be in any particular order.

Upvotes: 7

Views: 4548

Answers (5)

DiegoJArg
DiegoJArg

Reputation: 183

You can make a dictionary-like or lookup-table as a named-vector with old-new paired names and rename the dataframe only if is on the dict, so that it won't fail if you attempt to re-run the chunk. This "coalesces" the names.

rename_lookup <- c(
  "to"            = "from" ,
  "cylinder"        = "cyl",
  "horsepower"      = "hp"
  )
mtcars %>% rename( any_of( rename_lookup ) )
Additionally

You can easily get the vector with
names(mtcars) %>% dput

And the paste it like this, to quickly edit in order.

mtcars <- c("mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am", "gear", "carb")

mtcars <- c("mpg", "cylinder", "disp", "horsepower", "drat", "wt", "qsec", "vs", "am", "gear", "carb")

An step further, you can quickly build a dictionary like this

names(mtcars) %>% 
   dput %>% 
   capture.output %>%  
   str_replace_all(", ", ",\n ") %>% 
   writeLines

which returns:

c("mpg",
 "cyl",
 "disp",
 "hp",
 "drat",
 "wt",
 "qsec",
 "vs",
 "am",
"gear",
 "carb")

And then you can rename in a more readable layout, to finally use it again as before.

rename_lookup <- 
c("MPG"       = "mpg",   # And add your column notes here
  "CYLINDER"  = "cyl",   # And add your column notes here
  "DISP"      = "disp",
  "HORSEPOWER"= "hp",
  "..." = "drat",
  "..." = "wt"  ,
  "..." = "qsec",
  "..." = "vs"  ,
  "..." = "am"  ,
  "..." = "gear",
  "..." = "carb")

mtcars %>% rename( any_of( rename_lookup ) )

But, be careful, if you want direct assignment with rename_lookup, then you need to use its names. And only if the rename_lookup contains exactly the same columns count and meaning.

names(mtcars) <- names(rename_lookup)

Upvotes: 2

csgroen
csgroen

Reputation: 2541

A dplyr>=1.0.0 solution using rename_with:

library(tidyverse)
idkey2 <- idkey %>% pull(new, original)
x %>%
    rename_with(~ idkey2[.], !! names(idkey2)) %>%
    head()
#>                    mpg cylinder disp horsepower drat    wt  qsec vs am gear
#> Mazda RX4         21.0        6  160        110 3.90 2.620 16.46  0  1    4
#> Mazda RX4 Wag     21.0        6  160        110 3.90 2.875 17.02  0  1    4
#> Datsun 710        22.8        4  108         93 3.85 2.320 18.61  1  1    4
#> Hornet 4 Drive    21.4        6  258        110 3.08 3.215 19.44  1  0    3
#> Hornet Sportabout 18.7        8  360        175 3.15 3.440 17.02  0  0    3
#> Valiant           18.1        6  225        105 2.76 3.460 20.22  1  0    3
#>                   carb
#> Mazda RX4            4
#> Mazda RX4 Wag        4
#> Datsun 710           1
#> Hornet 4 Drive       1
#> Hornet Sportabout    2
#> Valiant              1

Upvotes: 0

Baurice
Baurice

Reputation: 151

dplyr::recode would also work:

colnames(x) <- dplyr::recode(
  colnames(x), 
  !!!setNames(as.character(idkey$new), idkey$original)
)

Upvotes: 10

Ronak Shah
Ronak Shah

Reputation: 388962

We can use match in base R

names(x)[match(idkey$original, names(x))] <- idkey$new
head(x)

#                   mpg cylinder disp horsepower 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

data

x<-mtcars
idkey <- data.frame("original" =  c("cyl","hp"), 
                    "new" = c("cylinder", "horsepower"), stringsAsFactors = FALSE)

Upvotes: 4

akrun
akrun

Reputation: 887078

In this case, rename_at would be useful. Specify the variables to be renamed inside the vars from the 'original' column of 'idkey' (the columns are factor - so convert to character class with as.character - because the data.frame default option is stringsAsFactors = TRUE)

library(dplyr)
x %>%
    rename_at(vars(as.character(idkey$original)), ~ as.character(idkey$new)) %>%
    head(2)
#             mpg cylinder disp horsepower drat    wt  qsec vs am gear carb
#Mazda RX4      21        6  160        110  3.9 2.620 16.46  0  1    4    4
#Mazda RX4 Wag  21        6  160        110  3.9 2.875 17.02  0  1    4    4

Upvotes: 5

Related Questions