通过名称重命名多列


81

有人应该已经问过这个问题,但是我找不到答案。说我有:

x = data.frame(q=1,w=2,e=3, ...and many many columns...)  

将我不一定知道位置的列的任意子集重命名为其他任意名称的最优雅方法是什么?

例如说,我要重命名"q""e""A""B",什么是最优雅的代码来做到这一点?

显然,我可以做一个循环:

oldnames = c("q","e")
newnames = c("A","B")
for(i in 1:2) names(x)[names(x) == oldnames[i]] = newnames[i]

但是我想知道是否有更好的方法?也许使用某些软件包?(plyr::rename等)

Answers:


102

setnamesdata.table包将在工作data.frame秒或data.table小号

library(data.table)
d <- data.frame(a=1:2,b=2:3,d=4:5)
setnames(d, old = c('a','d'), new = c('anew','dnew'))
d


 #   anew b dnew
 # 1    1 2    4
 # 2    2 3    5

请注意,更改是通过引用进行的,因此请勿复制(即使是data.frames!)


1
对于迟到的人-还可以查看下面的Joel答案,其中包括检查现有的列,以防万一您有可能没有全部显示的名称更改列表,例如old = c("a", "d", "e")
micstr

1
我想知道,如果您只想重命名一个子集/某些列而不是全部列,是否可以正常工作?因此,如果我有一个包含十列的数据框,并希望将_id_firstname重命名为firstname并将_id_lastname重命名为lastname,但其余8列保持不变,我可以这样做还是必须列出所有列?
Mus

@MusTheDataGuy您提供新名称和旧名称的子集,它将起作用。
mnel

@mnel我需要按照@Mus的要求更改子集的变量名称。但是,上面的代码不适用于数据的子集。@Gorka的答案可rename_at()用于更改子集的变量名。
Mehmet Yildirim

91

使用dplyr,您可以:

library(dplyr)

df = data.frame(q = 1, w = 2, e = 3)
    
df %>% rename(A = q, B = e)

#  A w B
#1 1 2 3

或者,如果您要使用向量,如@ Jelena-bioinf所建议:

library(dplyr)

df = data.frame(q = 1, w = 2, e = 3)

oldnames = c("q","e")
newnames = c("A","B")

df %>% rename_at(vars(oldnames), ~ newnames)

#  A w B
#1 1 2 3

LD尼古拉斯·梅LD Nicolas May)建议,给定的更改将rename_atrename_with

df %>% 
  rename_with(~ newnames[which(oldnames == .x)], .cols = oldnames)

#  A w B
#1 1 2 3

2
用户问old及传递和new姓名作为矢量的问题,我想
–JelenaČuklina,

4
谢谢@ Jelena-bioinf。我修改了答案,以包括您的建议。
Gorka

您能否解释〜(波浪号)的含义,以及“ .x”在rename_with示例中来自何处?
petzi

37

对于不太大的数据帧的另一种解决方案是(基于@thelatemail答案):

x <- data.frame(q=1,w=2,e=3)

> x
  q w e
1 1 2 3

colnames(x) <- c("A","w","B")

> x
  A w B
1 1 2 3

或者,您也可以使用:

names(x) <- c("C","w","D")

> x
  C w D
1 1 2 3

此外,您还可以重命名列名的子集:

names(x)[2:3] <- c("E","F")

> x
  C E F
1 1 2 3

23

这是我发现使用purrr::set_names()和一些stringr操作的组合重命名多个列的最有效方法。

library(tidyverse)

# Make a tibble with bad names
data <- tibble(
    `Bad NameS 1` = letters[1:10],
    `bAd NameS 2` = rnorm(10)
)

data 
# A tibble: 10 x 2
   `Bad NameS 1` `bAd NameS 2`
   <chr>                 <dbl>
 1 a                    -0.840
 2 b                    -1.56 
 3 c                    -0.625
 4 d                     0.506
 5 e                    -1.52 
 6 f                    -0.212
 7 g                    -1.50 
 8 h                    -1.53 
 9 i                     0.420
 10 j                     0.957

# Use purrr::set_names() with annonymous function of stringr operations
data %>%
    set_names(~ str_to_lower(.) %>%
                  str_replace_all(" ", "_") %>%
                  str_replace_all("bad", "good"))

# A tibble: 10 x 2
   good_names_1 good_names_2
   <chr>               <dbl>
 1 a                  -0.840
 2 b                  -1.56 
 3 c                  -0.625
 4 d                   0.506
 5 e                  -1.52 
 6 f                  -0.212
 7 g                  -1.50 
 8 h                  -1.53 
 9 i                   0.420
10 j                   0.957

6
这应该是答案,但是您是否还应该扩展管道中~and.参数的set_names()作用。
DaveRGP

在某些情况下,您需要明确输入purrr::set_names()
Levi Baguley

1
@DaveRGP使用purrr函数时,代字号~表示“对于每一列”。的.是dplyr语法LHS =管的左手侧,即参照该管道,在这种情况下,对象data
敏捷豆

11

因此,如果您不确定这些列是否存在并且只想重命名那些列,那么我最近自己遇到了这个问题:

existing <- match(oldNames,names(x))
names(x)[na.omit(existing)] <- newNames[which(!is.na(existing))]

6

建立在@ user3114046的答案上:

x <- data.frame(q=1,w=2,e=3)
x
#  q w e
#1 1 2 3

names(x)[match(oldnames,names(x))] <- newnames

x
#  A w B
#1 1 2 3

这将不依赖于x数据集中列的特定顺序。


1
我支持您的回答,但我仍然想知道是否还有一种更优雅的方法,尤其是按名称而不是按位置重命名的方法
qoheleth 2014年

@qoheleth-它正在重命名!此处没有输入是位置向量,因此match需要注意。您要做的最好的事情可能是@mnel的setnames答案。
thelatemail 2014年

1
它仍然按位置重命名,因为,正如您所说,即使我不必显式指定位置矢量,match它仍然是面向位置的命令。本着这种精神,我也认为@ user3114046的答案位置也是基于的(甚至认为该%in%命令会注意(或尝试)处理问题)。当然,我想当我们深入到低级机制时,您可以争辩说所有命令都是面向位置的....但这不是我的意思... data.table的答案很好,因为没有多次调用name命令。
qoheleth 2014年

4

这将更改所有名称中所有这些字母的出现:

 names(x) <- gsub("q", "A", gsub("e", "B", names(x) ) )

2
一旦您经过几个重命名实例,我认为这并不是特别优雅。
thelatemail 2014年

我还不够好,无法给出gsubfn答案。也许G.Grothendieck会来的。他是正则表达式存储器。
IRTFM

4
names(x)[names(x) %in% c("q","e")]<-c("A","B")

2
不完全是,因为正如我所说,我不一定知道列的位置,所以您的解决方案仅在oldnames排序后才有效,这样才oldnames[i]发生在oldnames[j]i <j之前。
qoheleth 2014年

2

您可以获取名称集,将其保存为列表,然后对字符串进行批量重命名。一个很好的例子是对数据集进行从长到宽的过渡时:

names(labWide)
      Lab1    Lab10    Lab11    Lab12    Lab13    Lab14    Lab15    Lab16
1 35.75366 22.79493 30.32075 34.25637 30.66477 32.04059 24.46663 22.53063

nameVec <- names(labWide)
nameVec <- gsub("Lab","LabLat",nameVec)

names(labWide) <- nameVec
"LabLat1"  "LabLat10" "LabLat11" "LabLat12" "LabLat13" "LabLat14""LabLat15"    "LabLat16" " 

2

旁注,如果要将一个字符串连接到所有列名,则只需使用此简单代码即可。

colnames(df) <- paste("renamed_",colnames(df),sep="")

2

如果表格中包含两列具有相同名称的列,则代码如下所示:

rename(df,newname=oldname.x,newname=oldname.y)

2

您可以使用命名向量。

使用基数R(可能有些笨拙):

x = data.frame(q = 1, w = 2, e = 3) 

rename_vec <- c(q = "A", e = "B")

names(x) <- ifelse(is.na(rename_vec[names(x)]), names(x), rename_vec[names(x)])

x
#>   A w B
#> 1 1 2 3

dplyr选择!!!

library(dplyr)

rename_vec <- c(A = "q", B = "e") # the names are just the other way round than in the base R way!

x %>% rename(!!!rename_vec)
#>   A w B
#> 1 1 2 3

后者之所以起作用,是因为“大爆炸”运算符!!!强制评估列表或向量。

?`!!`

!!! 强制拼接对象列表。列表中的元素被拼接到位,这意味着它们每个都成为一个单独的参数。


不知道它是如何工作的-!!!oldnames返回,c("A", "B")但是哪个逻辑将其转换为c("A", "w", "B")??
敏捷豆

@AgileBean我不知道您在哪里发现!!! oldnames将返回一个向量。它用于强制对dplyr中的多个参数进行非标准评估。见?`!!` Use `!!!` to add multiple arguments to a function. Its argument should evaluate to a list or vector: args <- list(1:3, na.rm = TRUE) ; quo(mean(!!!args))。我想我会将此解释添加到答案中。为它
加油打气

1

有很多的答案,所以我只是编写了该函数,以便您可以复制/粘贴。

rename <- function(x, old_names, new_names) {
    stopifnot(length(old_names) == length(new_names))
    # pull out the names that are actually in x
    old_nms <- old_names[old_names %in% names(x)]
    new_nms <- new_names[old_names %in% names(x)]

    # call out the column names that don't exist
    not_nms <- setdiff(old_names, old_nms)
    if(length(not_nms) > 0) {
        msg <- paste(paste(not_nms, collapse = ", "), 
            "are not columns in the dataframe, so won't be renamed.")
        warning(msg)
    }

    # rename
    names(x)[names(x) %in% old_nms] <- new_nms
    x
}

 x = data.frame(q = 1, w = 2, e = 3)
 rename(x, c("q", "e"), c("Q", "E"))

   Q w E
 1 1 2 3

rename(x, c("q", "e"), c("Q", "E"))似乎不再可以在dplyr重命名中工作?
sindri_baldur

0

如果数据的一行包含要更改的名称,则可以将所有列更改为

names(data) <- data[row,]

给定data是您的数据框,row是包含新值的行号。

然后,您可以删除包含名称的行

data <- data[-row,]

0

这是您需要的功能:然后将x传递给rename(X),它将重命名出现的所有值,如果不在其中,则不会出错

rename <-function(x){
  oldNames = c("a","b","c")
  newNames = c("d","e","f")
  existing <- match(oldNames,names(x))
  names(x)[na.omit(existing)] <- newNames[which(!is.na(existing))]
  return(x)
}

1
这似乎与JoelKuiper的答案相同,但随后被重新构造为函数..
Jaap
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.