Đổi tên nhiều cột theo tên


81

Lẽ ra ai đó đã hỏi điều này rồi, nhưng tôi không thể tìm ra câu trả lời. Giả sử tôi có:

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

Cách thanh lịch nhất để đổi tên một tập hợp con tùy ý của các cột, có vị trí mà tôi không nhất thiết phải biết, thành một số tên tùy ý khác là gì?

Ví dụ: Giả sử tôi muốn đổi tên "q""e"thành "A""B", mã thanh lịch nhất để thực hiện việc này là gì?

Rõ ràng, tôi có thể thực hiện một vòng lặp:

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

Nhưng không biết có cách nào tốt hơn không? Có thể sử dụng một số gói? ( plyr::renamevv)

Câu trả lời:


102

setnamestừ data.tablegói sẽ hoạt động trên data.frames hoặc data.tables

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

Lưu ý rằng các thay đổi được thực hiện bằng cách tham chiếu, vì vậy không sao chép (ngay cả đối với data.frames!)


1
Đối với cuối lượt ở đây - Ngoài ra hãy xem tại câu trả lời của Joel dưới đây mà bìa kiểm tra đối với các cột hiện có trong trường hợp bạn có một danh sách thay đổi tên có thể không phải tất cả có mặt ví dụold = c("a", "d", "e")
micstr

1
Tôi tự hỏi, điều này có hoạt động không nếu bạn chỉ muốn đổi tên một tập hợp con / một số cột thay vì tất cả chúng? Vì vậy, nếu tôi có một khung dữ liệu gồm mười cột và muốn đổi tên _id_firstname thành tên đầu tiên và _id_lastname thành họ nhưng để nguyên tám cột còn lại, tôi có thể làm điều này hay tôi phải liệt kê tất cả các cột?
Mus

@MusTheDataGuy bạn cung cấp tập hợp con các tên mới và cũ và nó sẽ hoạt động.
mnel

@mnel Tôi cần thay đổi tên biến của một tập hợp con như @Mus đã yêu cầu. Tuy nhiên, đoạn mã trên không hoạt động đối với một tập hợp con dữ liệu. Câu trả lời của @ Gorka có rename_at()tác dụng thay đổi tên biến của một tập hợp con.
Mehmet Yildirim

91

Với dplyr bạn sẽ làm được:

library(dplyr)

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

#  A w B
#1 1 2 3

Hoặc nếu bạn muốn sử dụng vectơ, theo đề xuất của @ 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 Nicolas May đề xuất một thay đổi được đưa ra rename_atđang được thay thế bằng rename_with:

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

#  A w B
#1 1 2 3

2
người dùng được hỏi về đi qua oldnewtên như vectơ, tôi nghĩ
JelenaČuklina

4
Cảm ơn @ Jelena-bioinf. Tôi đã sửa đổi câu trả lời để bao gồm đề xuất của bạn.
Gorka

Bạn có thể vui lòng giải thích ý nghĩa của dấu ~ (dấu ngã) và ".x" đến từ đâu trong ví dụ rename_with?
petzi

37

Một giải pháp khác cho các khung dữ liệu không quá lớn là (xây dựng trên câu trả lời @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

Ngoài ra, bạn cũng có thể sử dụng:

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

> x
  C w D
1 1 2 3

Hơn nữa, bạn cũng có thể đổi tên một tập hợp con của các tên cột:

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

> x
  C E F
1 1 2 3

23

Đây là cách hiệu quả nhất mà tôi đã tìm thấy để đổi tên nhiều cột bằng cách sử dụng kết hợp purrr::set_names()và một vài stringrthao tác.

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
Đây nên là câu trả lời, nhưng bạn cũng có thể nên mở rộng về những gì các ~.đối số trong set_names()ống dẫn.
DaveRGP

Trong một số trường hợp, bạn cần phải nhập rõ ràng purrr::set_names().
Levi Baguley

1
@DaveRGP khi sử dụng các purrrhàm, dấu ngã ~có nghĩa là "cho mỗi cột". Các .là dplyr cú pháp cho LHS = phía bên tay trái của đường ống, tức là tham chiếu đến các đối tượng được cấp nước tập trung, trong trường hợp này data.
Agile Bean

11

Vì vậy, gần đây tôi đã tự mình gặp phải vấn đề này, nếu bạn không chắc liệu các cột có tồn tại hay không và chỉ muốn đổi tên những cột đó:

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

6

Dựa trên câu trả lời của @ 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

Điều này sẽ không phụ thuộc vào thứ tự cụ thể của các cột trong xtập dữ liệu.


1
Tôi đã bỏ phiếu tán câu trả lời của bạn, nhưng tôi vẫn tự hỏi, nếu có một cách thậm chí thanh lịch hơn để làm điều này, đặc biệt là phương pháp mà đổi tên theo tên, thay vì bởi vị trí
qoheleth

@qoheleth - nó đang được đổi tên theo tên! Không có đầu vào ở đây là một vectơ vị trí để xử matchlý điều đó. Điều tốt nhất bạn sẽ làm có lẽ là setnamescâu trả lời của @ mnel .
thelatemail

1
nó vẫn là một loại đổi tên theo vị trí bởi vì, như bạn đã nói, mặc dù tôi không phải chỉ định rõ ràng một vectơ vị trí, matchnó vẫn là một lệnh hướng theo vị trí. Theo tinh thần này, tôi cũng cho rằng vị trí câu trả lời của @ user3114046 cũng dựa trên (thậm chí nghĩ rằng %in%lệnh xử lý (hoặc cố gắng) mọi thứ). Tất nhiên, tôi cho rằng bạn có thể tranh luận rằng tất cả các lệnh đều được định hướng theo vị trí khi chúng ta đi sâu vào cơ chế cấp thấp .... nhưng đó không phải là ý của tôi ... câu trả lời data.table rất tuyệt vì không có nhiều lệnh gọi namecác lệnh.
qoheleth

4

Điều này sẽ thay đổi tất cả các lần xuất hiện của các chữ cái đó trong tất cả các tên:

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

2
Tôi không nghĩ rằng điều này là đặc biệt thanh lịch khi bạn vượt qua một vài trường hợp đổi tên.
thelatemail

Tôi không đủ giỏi để đưa ra gsubfncâu trả lời. Có lẽ G.Grothendieck sẽ ghé qua. Anh ta là regex-meister.
IRTFM

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

2
Không hoàn toàn, bởi vì như tôi đã nói, tôi không nhất thiết phải biết vị trí của các cột, giải pháp của bạn chỉ hoạt động nếu oldnamesđược sắp xếp để oldnames[i]xảy ra trước oldnames[j]cho i <j.
qoheleth

2

Bạn có thể đặt tên, lưu nó dưới dạng danh sách và sau đó thực hiện đổi tên hàng loạt trên chuỗi. Một ví dụ điển hình về điều này là khi bạn đang thực hiện quá trình chuyển đổi từ dài sang rộng trên tập dữ liệu:

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

Sidenote, nếu bạn muốn nối một chuỗi với tất cả các tên cột, bạn có thể sử dụng mã đơn giản này.

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

2

Nếu bảng chứa hai cột có cùng tên thì mã sẽ như thế này,

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

2

Bạn có thể sử dụng một vector được đặt tên.

Với cơ sở R (có thể hơi khó hiểu):

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

Hoặc một dplyrtùy chọn với !!!:

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

Các công trình sau vì 'lớn-bang' điều hành !!!đang buộc đánh giá của một danh sách hay một vector.

?`!!`

!!! force-splice một danh sách các đối tượng. Các phần tử của danh sách được nối với nhau, có nghĩa là mỗi phần tử trở thành một đối số duy nhất.


không hiểu cách này hoạt động - !!!oldnamestrả về c("A", "B")nhưng logic nào biến điều này thành c("A", "w", "B")??
Agile Bean

@AgileBean Tôi không biết bạn tìm thấy điều đó ở đâu !!! tên cũ sẽ trả về một vectơ. Nó được sử dụng để buộc đánh giá không chuẩn đối với nhiều đối số trong dplyr. xem ?`!!` 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)). Tôi nghĩ tôi sẽ thêm lời giải thích này vào câu trả lời. Chúc mừng vì đã đưa nó lên
Tjebo

1

Rất nhiều loại câu trả lời, vì vậy tôi chỉ viết hàm để bạn có thể sao chép / dán.

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"))dường như không còn hoạt động trong đổi tên dplyr?
sindri_baldur

0

Nếu một hàng dữ liệu chứa các tên bạn muốn thay đổi tất cả các cột thành bạn có thể làm

names(data) <- data[row,]

Đã cho datalà khung dữ liệu của bạn và rowlà số hàng chứa các giá trị mới.

Sau đó, bạn có thể xóa hàng chứa các tên có

data <- data[-row,]

0

Đây là chức năng mà bạn cần: Sau đó, chỉ cần chuyển x trong đổi tên (X) và nó sẽ đổi tên tất cả các giá trị xuất hiện và nếu không có trong đó thì nó sẽ không bị lỗi

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
này có vẻ là giống như câu trả lời của JoelKuiper , nhưng sau đó định hình như chức năng .....
Jaap
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.