简体   繁体   中英

Switched columns with dplyr rename_if

Trying to rename some data frame columns using dplyr rename_if and lists of old and new patterns, some column names end up switched in the output.

head(mtcars)
                   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

lst <- list(Old=c("mpg", "cyl", "disp", "carb", "wt", "gear"), New=c("Miles per Gallon", "Cylinder", "Displacement", "Carburator", "Weight", "Gear"))

mtcars %>% 
rename_if(names(.) %in% lst$Old,
          function(x){
             lst$New[which(lst$Old %in% x)]}) %>% 
head()
                  Miles per Gallon Cylinder Displacement  hp drat Carburator
Mazda RX4                     21.0        6          160 110 3.90      2.620
Mazda RX4 Wag                 21.0        6          160 110 3.90      2.875
Datsun 710                    22.8        4          108  93 3.85      2.320
Hornet 4 Drive                21.4        6          258 110 3.08      3.215
Hornet Sportabout             18.7        8          360 175 3.15      3.440
Valiant                       18.1        6          225 105 2.76      3.460
                   qsec vs am Weight Gear
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

We can see that the wt and Carburator columns have been switched.

How to rename columns using rename_if when the reference name lists are not in the same order as the data frame columns?

EDIT The use of rename_at(lst$Old, ~lst$New) does not work when the reference lists contain names not present in the particular data frame columns.

For example with:

lst <- list(Old=c("mpg", "cyl", "disp", "carb", "wt", "gear", "xtra"), New=c("Miles per Gallon", "Cylinder", "Displacement", "Carburator", "Weight", "Gear", "ExtraCol"))

(see the xtra and ExtraCol names)

Instead of rename_if , try with rename_at since you have names of columns that you want to replace.

library(dplyr)
head(mtcars) %>% rename_at(lst$Old, ~lst$New)

However, _at / _if / _all variants have been superseded so try with rename_with .

head(mtcars) %>% rename_with(~lst$New, lst$Old)

#                  Miles per Gallon Cylinder Displacement  hp drat Weight  qsec vs am Gear Carburator
#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

In base R, we can do this using match :

names(mtcars)[match(lst$Old, names(mtcars))] <- lst$New

In case, there are values in lst which are not present in names we can first filter them and then use the above method.

inds <- lst$Old %in% names(mtcars)
lst <- lapply(lst, `[`, inds)

Replacing which() by match() keeps indexes by order of occurrence and solves the problem

mtcars %>% rename_if(names(.) %in% lst$Old, function(x){lst$New[match(x, lst$Old)]})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM