如何通过列索引dplyr重命名列?

时间:2017-03-13 17:20:50

标签: r dataframe dplyr rename nse

以下代码重命名数据集中的第一列:

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 个答案:

答案 0 :(得分:26)

{ test: /\.(jpe?g|png|gif|svg)$/i, loader: 'file?name=img/[name].[ext]' },... dplyr0.7.5 rlang0.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_nameChangedNameAgain = 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 版本0.6 / 0.7以来,我还没有围绕基于dplyr的新rlang编程系统。

我的初始答案中使用的dplyr的下划线后缀版本现已弃用,并且根据@ jzadra的评论,它对于{{1}等语法上有问题的名称无效}。

以下是我对基于rename的新非标准评估系统的尝试。在评论中,请不要犹豫告诉我我做错了什么:

"foo bar"

首先我直接尝试rlang但不幸的是我遇到了错误。源代码中似乎是FIXME(或者这个FIXME无关吗?)(我使用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 0.7.4),所以它可以在以后使用:

rename()

(编辑:现在的错误消息(dplyr 0.7.5)读取dplyr

(更新2018-06-14: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"的解决方法。它不像df %>% rename(qux = !! quo(names(.)[[2]]))那样保留列顺序:

select

如果我们想把它放在一个函数中,我们必须用rename稍微修改它以允许在左侧进行取消引用。如果我们想要对字符串和裸变量名等输入很健壮,我们必须使用&#34;黑魔法&#34; (或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

答案 1 :(得分:6)

这里有几个替代解决方案可以说更容易阅读,因为它们并不关注.引用。 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 )将使第二列和第四列的名称为大写。

答案 2 :(得分:4)

dplyr 已用 rename_at() 取代 rename_with()。您可以像这样按索引重命名列:

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 函数简写 here 的更多信息。

答案 3 :(得分:1)

@Aurele建议的Imho rlang在这里太多了。

解决方案1:使用大括号管道上下文:

bcMatrix %>% {colnames(.)[1] = "foo"; .}

解决方案2:或者(ab)使用来自%>%包的tee操作符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")