Как dplyr переименовать столбец, по индексу столбца?
Следующий код переименовывает первый столбец в наборе данных:
require(dplyr)
mtcars %>%
setNames(c("RenamedColumn", names(.)[2:length(names(.))]))
Желаемые результаты:
RenamedColumn cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
Можно ли достичь того же результата, используя rename
а индекс столбца?
Это:
mtcars %>%
rename(1 = "ChangedNameAgain")
не удастся:
Error in source("~/.active-rstudio-document", echo = TRUE) :
~/.active-rstudio-document:7:14: unexpected '='
6: mtcars %>%
7: rename(1 =
^
Точно так же пытаюсь использовать rename_
или же .[[1]]
как ссылка на столбец вернет ошибку.
4 ответа
По состоянию на dplyr
0.7.5
, rlang
0.2.1
, tidyselect
0.2.4
, это просто работает:
library(dplyr)
rename(mtcars, ChangedNameAgain = 1)
# ChangedNameAgain cyl disp hp drat wt qsec vs am gear carb
# Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
# Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
# Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
# Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
# Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
# ...
Оригинальный ответ и правки теперь устарели:
Логика rename()
является new_name = old_name
, так ChangedNameAgain = 1
будет иметь больше смысла, чем 1 = ChangedNameAgain
,
Я бы предложил:
mtcars %>% rename_(ChangedNameAgain = names(.)[1])
# ChangedNameAgain cyl disp hp drat wt qsec vs am gear carb
# Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
# Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
# Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
# Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
# Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
# Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
редактировать
Я еще не обернул голову вокруг нового dplyr
система программирования на основе rlang
, начиная с версий 0.6/0.7 dplyr
,
Подчеркнутая версия rename
используемый в моем первоначальном ответе, теперь устарел, и, согласно комментарию @jzadra, он не работал с синтаксически проблемными именами, такими как "foo bar"
,
Вот моя попытка с новым rlang
Нестандартная система оценки. Не стесняйтесь сказать мне, что я сделал неправильно, в комментариях:
df <- tibble("foo" = 1:2, "bar baz" = letters[1:2])
# # A tibble: 2 x 2
# foo `bar baz`
# <int> <chr>
# 1 1 a
# 2 2 b
Сначала я пытаюсь напрямую с rename()
но, к сожалению, у меня есть ошибка. Кажется, это FIXME
(или это FIXME не связано?) в исходном коде (я использую dplyr
0.7.4), чтобы он мог работать в будущем:
df %>% rename(qux = !! quo(names(.)[[2]]))
# Error: Expressions are currently not supported in `rename()`
(Редактировать: сейчас появляется сообщение об ошибке (dplyr 0.7.5) Error in UseMethod("rename_") : no applicable method for 'rename_' applied to an object of class "function"
)
(Обновление 2018-06-14: df %>% rename(qux = !! quo(names(.)[[2]]))
теперь, кажется, работает, все еще с dplyr 0.7.5, не уверен, что основной пакет изменился).
Вот обходной путь с select
это работает. Это не сохраняет порядок столбцов, как rename
хоть:
df %>% select(qux = !! quo(names(.)[[2]]), everything())
# # A tibble: 2 x 2
# qux foo
# <chr> <int>
# 1 a 1
# 2 b 2
И если мы хотим поместить это в функцию, мы должны были бы немного изменить это с :=
чтобы разрешить расстаться с цитатой на левой стороне. Если мы хотим быть устойчивыми к входным данным, таким как строки и имена переменных, мы должны использовать "темную магию" (или, как говорит виньетка) enquo()
а также quo_name()
(честно говоря, я не совсем понимаю, что он делает):
rename_col_by_position <- function(df, position, new_name) {
new_name <- enquo(new_name)
new_name <- quo_name(new_name)
select(df, !! new_name := !! quo(names(df)[[position]]), everything())
}
Это работает с новым именем в виде строки:
rename_col_by_position(df, 2, "qux")
# # A tibble: 2 x 2
# qux foo
# <chr> <int>
# 1 a 1
# 2 b 2
Это работает с новым именем в качестве фразы:
rename_col_by_position(df, 2, quo(qux))
# # A tibble: 2 x 2
# qux foo
# <chr> <int>
# 1 a 1
# 2 b 2
Это работает с новым именем как голое имя:
rename_col_by_position(df, 2, qux)
# # A tibble: 2 x 2
# qux foo
# <chr> <int>
# 1 a 1
# 2 b 2
И даже это работает:
rename_col_by_position(df, 2, `qux quux`)
# # A tibble: 2 x 2
# `qux quux` foo
# <chr> <int>
# 1 a 1
# 2 b 2
Вот пара альтернативных решений, которые, возможно, легче читать, потому что они не сосредоточены вокруг .
ссылка. select
понимает индексы столбцов, поэтому, если вы переименуете первый столбец, вы можете просто сделать
mtcars %>% select( RenamedColumn = 1, everything() )
Однако проблема с использованием select
является то, что он будет переупорядочивать столбцы, если вы переименовываете столбец в середине. Чтобы обойти эту проблему, вы должны предварительно выбрать столбцы слева от столбца, который вы переименовываете:
## This will rename the 7th column without changing column order
mtcars %>% select( 1:6, RenamedColumn = 7, everything() )
Другой вариант заключается в использовании нового rename_at
, которые также понимают индексы столбцов:
## This will also rename the 7th column without changing the order
## Credit for simplifying the second argument: Moody_Mudskipper
mtcars %>% rename_at( 7, ~"RenamedColumn" )
~
необходимо, потому что rename_at
является достаточно гибким и может принимать функции в качестве второго аргумента. Например, mtcars %>% rename_at( c(2,4), toupper )
сделает имена второго и четвертого столбцов заглавными.
dplyr
вытеснил
<tcode id="4347704"></tcode> с
<tcode id="4347705"></tcode>. Вы можете переименовать столбец по индексу следующим образом:
library(tidyverse)
mtcars %>%
rename_with(.cols = 1, ~"renamed_column")
#> renamed_column cyl disp hp drat wt qsec vs am gear
#> Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4
#> Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4
#> Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4
#> Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3
#> Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3
#> ...
Обязательно включите тильду () * перед именем нового столбца.
Также обратите внимание, что если вы введете
glue
пакет, вы можете изменить существующие имена столбцов следующим образом:
library(glue)
mtcars %>%
rename_with(.cols = 1, ~glue::glue("renamed_{.}"))
#> renamed_mpg cyl disp hp drat wt qsec vs am gear carb
#> Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
#> Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
#> Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
#> Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
#> Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
#> ...
Применение вышеуказанного подхода к нескольким столбцам - это просто вопрос передачи диапазона номеров индексов столбца с помощью двоеточия (
:
) или несколько индексов в векторе, используя
c()
; вот комбинация обоих:
mtcars %>%
rename_with(.cols = c(1:3, 5), ~glue::glue("renamed_{.}"))
#> renamed_mpg renamed_cyl renamed_disp hp renamed_drat wt
#> Mazda RX4 21.0 6 160.0 110 3.90 2.620
#> Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875
#> Datsun 710 22.8 4 108.0 93 3.85 2.320
#> Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215
#> Hornet Sportabout 18.7 8 360.0 175 3.15 3.440
#> ...
И имейте в виду, что, поскольку представляет собой текущее имя столбца, вы можете применить к нему функции модификации строки следующим образом:
mtcars %>%
rename_with(.cols = c(1:3),
~glue::glue("renamed_{str_replace(.,'mpg','miles_per_gallon')}"))
#> renamed_miles_per_gallon renamed_cyl renamed_disp hp
#> Mazda RX4 21.0 6 160.0 110
#> Mazda RX4 Wag 21.0 6 160.0 110
#> Datsun 710 22.8 4 108.0 93
#> Hornet 4 Drive 21.4 6 258.0 110
#> Hornet Sportabout 18.7 8 360.0 175
#> ...
* Вы можете узнать больше о
~
и
.
Сокращение функции NSE здесь .
По моему мнению rlang
как подсказывает @Aurele, здесь слишком много.
Решение 1. Используйте контекст трубы с фигурными скобками:
bcMatrix %>% {colnames(.)[1] = "foo"; .}
Решение 2: Или (ab) используйте тройник %>%
от magrittr
пакет (установлен в любом случае, если dplyr
используется) для выполнения переименования в качестве побочного эффекта:
bcMatrix %T>% {colnames(.)[1] = "foo"}
Решение 3: с помощью простой вспомогательной функции:
rename_by_pos = function(df, index, new_name){
colnames(df)[index] = new_name
df
}
iris %>% rename_by_pos(2,"foo")