Как 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 ответа

Решение

По состоянию на dplyr0.7.5, rlang0.2.1, tidyselect0.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")
Другие вопросы по тегам