Rename columns in a dataframe by list of correspondence

Viewed 293

I try to rename columns of a dataframe, via a correspondence table, a two-columns dataframe (name before and name after).

In my situation, the to-rename dataframe may have columns not referenced in my correspondence table (it's not a problem, they won't be renamed), and, at the opposite, the correspondence table may contain names not included in my dataframe. This list may be used for other dataframes.

And, at least, the order of the names may not be the same in the 2 dataframes, it would be too easy.

I have a solution with a loop, but try to find another solution, with no loop.

Any idea ? Thanks in advance.

Here is my code


df_to_rename <- data.frame(annee = 2010:2012,
                            code_commune = 67000:67002,
                            duree_occup_ou_vacance_tranche = 1:3,
                            nb_total_logements = 100:102,
                            secret_not_in_list  = 1:3)

liste_noms_col <- data.frame(noms_origine = c("mode_occ",
                                              "code_commune",
                                              "annee",
                                              "duree_occup_ou_vacance_tranche",
                                              "nb_total_logements"),
                             noms_nouveaux = c("mode d\'occupation - not included",
                                               "code INSEE commune",
                                               "Année",
                                               "durée d\'occupation (ou vacance)",
                                               "Nombre de logements"))


##### Rename by loop

l_noms <- df_to_rename %>% names()

# (i_nom  <-  l_noms[1])
for(i_nom in l_noms) {
  nom_a_changer <-
    liste_noms_col[liste_noms_col$noms_origine == i_nom, "noms_nouveaux"]
  # message(i_nom," -> ",nom_a_changer)
  
  if(length(nom_a_changer)>0) {
    df_to_rename <- df_to_rename %>%
      rename({{nom_a_changer}} := {{i_nom}})
    message(i_nom," -> ",nom_a_changer)
  }
}
df_to_rename %>% names()
2 Answers

Turn liste_noms_col into a list with deframe, filter names of interest, and rename():

library(dplyr)

liste_noms_col <- deframe(liste_noms_col[, 2:1])
liste_noms_col <- liste_noms_col[liste_noms_col %in% names(df_to_rename)]

rename(df_to_rename, !!! liste_noms_col)

Auditing the triple-bang (!!!) "unquote-splice" replacement:

expr(
  rename(df_to_rename, !!! liste_noms_col)
)

#> rename(df_to_rename, `code INSEE commune` = "code_commune", 
#>     Année = "annee", `durée d'occupation (ou vacance)` = "duree_occup_ou_vacance_tranche", 
#>     `Nombre de logements` = "nb_total_logements")

Use match and get the new column names of dataframe which is present in liste_noms_col. For the column names which are not present in liste_noms_col, keep the original columns as it is.

cols <- liste_noms_col$noms_nouveaux[match(names(df_to_rename), liste_noms_col$noms_origine)]
cols[is.na(cols)] <- names(df_to_rename)[is.na(cols)]
names(df_to_rename) <- cols
df_to_rename

#  Année code INSEE commune durée d'occupation (ou vacance) Nombre de logements secret_not_in_list
#1  2010              67000                               1                 100                  1
#2  2011              67001                               2                 101                  2
#3  2012              67002                               3                 102                  3

Using dplyr :

library(dplyr)

df_to_rename %>%
  rename_with(~coalesce(liste_noms_col$noms_nouveaux[match(., liste_noms_col$noms_origine)], .))
Related