Reputation: 133
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
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 ) )
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
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
Reputation: 151
dplyr::recode
would also work:
colnames(x) <- dplyr::recode(
colnames(x),
!!!setNames(as.character(idkey$new), idkey$original)
)
Upvotes: 10
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
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