R rename columns dynamically and ignore missing

Viewed 447

I have a dataset that I need to dynamically rename specific columns.

For example, I would normally rename the "mtcars" dataset the following way:

# THIS WORKS    
# Load data
data <- mtcars

# Gather data.frame with columns to rename, I am doing it this way because I generally have 
# a long list of "configurations" to plot that I go through in a for loop.  Might not be the most 
# efficient, but it generally works for me.
Columns_to_rename <- data.table(X = "mpg", Y = "gear", Color = "carb")

# Rename columns
plot_data <- data %>%
    dplyr::rename(X := !!Columns_to_rename$X[1],
                  Y := !!Columns_to_rename$Y[1],
                  Color := !!Columns_to_rename$Color[1]) %>%
    dplyr::select(X, Y, Color)

However, in my real dataset with the real Columns_to_rename, my dataset may not contain a header. I would just want to ignore that renaming.

Consider the case in the above example:

Columns_to_rename <- data.table(X = "mpg", Y = "gear", Color = "missing")

As far as I am aware, the dplyr package requires all columns to exist. Sticking with the tidyverse, I looked into using plyr package because I know this allows for missing column names. Unfortunately I could not figure out how to also call the columns dynamically. I have looked through previous StackOverflow questions and Answers, but haven't seen anyone needing to combine these two principles in their renaming.

Thanks!

1 Answers

An option would be to subset with %in%

library(dplyr)
nm1 <- unlist(Columns_to_rename)
nm2 <-  nm1[nm1 %in% names(data)]
data %>% 
      rename(!!! nm2) %>%
      select(names(nm2)) %>%
      head

-output

#                    X Y
#Mazda RX4         21.0 4
#Mazda RX4 Wag     21.0 4
#Datsun 710        22.8 4
#Hornet 4 Drive    21.4 3
#Hornet Sportabout 18.7 3
#Valiant           18.1 3

Or another option is rename_at or rename_with on the subset vector ('nm2')

data %>%
    rename_at(vars(all_of(nm2)), ~ names(nm2)) %>%
    select(names(nm2)) %>%
    head

NOTE: We could also wrap with any_of on 'nm1', but the issue is the names(nm1) will be having mismatch in length

data %>% 
      rename_at(vars(any_of(nm1)), ~ names(nm2))
Related