#r #dplyr
#r #dplyr
Вопрос:
При попытке переименовать некоторые столбцы фрейма данных с помощью dplyr rename_if
и списков старых и новых шаблонов некоторые имена столбцов в конечном итоге переключаются в выходных данных.
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
Мы видим, что столбцы wt
и Carburator
были переключены.
Как переименовать столбцы, используя rename_if
, когда списки имен ссылок расположены не в том же порядке, что и столбцы фрейма данных?
РЕДАКТИРОВАТЬ Использование rename_at(lst$Old, ~lst$New)
не работает, когда списки ссылок содержат имена, отсутствующие в конкретных столбцах фрейма данных.
Например, с:
lst <- list(Old=c("mpg", "cyl", "disp", "carb", "wt", "gear", "xtra"), New=c("Miles per Gallon", "Cylinder", "Displacement", "Carburator", "Weight", "Gear", "ExtraCol"))
(см. Имена xtra
и ExtraCol
)
Ответ №1:
Вместо rename_if
этого попробуйте rename_at
использовать, поскольку у вас есть имена столбцов, которые вы хотите заменить.
library(dplyr)
head(mtcars) %>% rename_at(lst$Old, ~lst$New)
Однако _at
/ _if
/ _all
варианты были заменены, поэтому попробуйте с 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
В базе R мы можем сделать это с помощью match
:
names(mtcars)[match(lst$Old, names(mtcars))] <- lst$New
В случае, если есть значения, lst
которых нет в именах, мы можем сначала отфильтровать их, а затем использовать описанный выше метод.
inds <- lst$Old %in% names(mtcars)
lst <- lapply(lst, `[`, inds)
Комментарии:
1. Спасибо, это отлично работает, когда списки содержат только имена, присутствующие в столбце фрейма данных. Что делать, если списки также включают имена, отсутствующие в конкретном фрейме данных (см. Мое редактирование)?
2. @u31889 Мы можем отфильтровать
lst
, чтобы сохранить только те значения, которые присутствуют в именах. Проблема при использованииrename_if
заключается в том, что вы можете выбирать столбцы, но при переименовании вы точно не знаете, какой из них переименовать, поэтому нам нужно сначала их отфильтровать. Смотрите обновленный ответ.
Ответ №2:
Замена which()
на match()
сохраняет индексы в порядке появления и решает проблему
mtcars %>% rename_if(names(.) %in% lst$Old, function(x){lst$New[match(x, lst$Old)]})