Làm thế nào để sắp xếp lại các cột trong khung dữ liệu?


311

Làm thế nào một người sẽ thay đổi đầu vào này (với trình tự: thời gian, vào, ra, các tệp):

Time   In    Out  Files
1      2     3    4
2      3     4    5

Để đầu ra này (với trình tự: time, out, in, files)?

Time   Out   In  Files
1      3     2    4
2      4     3    5

Đây là dữ liệu R giả:

table <- data.frame(Time=c(1,2), In=c(2,3), Out=c(3,4), Files=c(4,5))
table
##  Time In Out Files
##1    1  2   3     4
##2    2  3   4     5

4
help(Extract)còn được gọi là?'['
Joris Meys

3
Ngoài gợi ý của @ Joris, hãy thử đọc phần 2.7 và phần 5 của hướng dẫn "Giới thiệu về R": cran.r-project.org/doc/manuals/R-intro.html
Gavin Simpson

3
Một vấn đề bổ sung: tất cả các câu trả lời yêu cầu danh sách đầy đủ các cột, nếu không, chúng sẽ dẫn đến việc đặt lại. Điều gì sẽ xảy ra nếu chúng ta chỉ muốn liệt kê một vài cột được sắp xếp làm cột đầu tiên, nhưng cũng giữ lại tất cả các cột khác?
000andy8484

Câu trả lời:


341

Khung dữ liệu của bạn có bốn cột như vậy df[,c(1,2,3,4)]. Lưu ý dấu phẩy đầu tiên có nghĩa là giữ tất cả các hàng và 1,2,3,4 đề cập đến các cột.

Để thay đổi thứ tự như trong câu hỏi trên, hãy làm df2[,c(1,3,2,4)]

Nếu bạn muốn xuất tệp này dưới dạng csv, hãy làm write.csv(df2, file="somedf.csv")


35
Điều này là ổn khi bạn có số lượng cột hạn chế, nhưng nếu bạn có ví dụ 50 cột thì sẽ mất quá nhiều thời gian để nhập tất cả các số hoặc tên cột. Điều gì sẽ là một giải pháp nhanh hơn?
Herman Toothrot

54
@ user4050: trong trường hợp đó, bạn có thể sử dụng cú pháp ":", ví dụ df [, c (1,3,2,4,5: 50)].
dalloliogm

1
để đặt các cột trong idcols khi bắt đầu: idcols <- c ("name", "id2", "start", "thời gian"); cols <- c (idcols, name (cts) [- which (name (cts)% in% idcols)]); df <- df [cols]
kasterma

13
@ user4050: bạn cũng có thể sử dụng df[,c(1,3,2,4:ncol(df))]khi bạn không biết có bao nhiêu cột.
arekolek 15/03/2016

1
Bạn cũng có thể sử dụng dput (colnames (df)), nó in tên cột theo định dạng ký tự R. Sau đó bạn có thể sắp xếp lại tên.
Chris

168
# reorder by column name
data <- data[c("A", "B", "C")]

#reorder by column index
data <- data[c(1,3,2)]

1
Câu hỏi khi mới bắt đầu, bạn có thể kết hợp đặt hàng theo chỉ mục và theo tên? Ví dụ data <- data[c(1,3,"Var1", 2)]?
Bram Vanroy

6
@BramVanroy không, c(1,3,"Var1", 2)sẽ được đọc c("1","3","Var1", "2")vì các vectơ có thể chứa dữ liệu chỉ có một loại, vì vậy các loại được quảng bá thành loại chung nhất hiện tại. Bởi vì không có cột nào có tên nhân vật "1", "3", v.v. bạn sẽ nhận được "cột không xác định". list(1,3,"Var1", 2)giữ các giá trị mà không cần quảng cáo kiểu, nhưng bạn không thể sử dụng một listtrong bối cảnh trên.
Terry Brown

1
Tại sao các tập hợp con mtcars[c(1,3,2)]làm việc? Tôi đã mong đợi một lỗi liên quan đến kích thước không chính xác hoặc tương tự ... Không phải vậy mtcars[,c(1,3,2)]sao?
Landroni

data.frames là danh sách dưới mui xe với các cột là các mục thứ tự đầu tiên
petermeissner

106

Bạn cũng có thể sử dụng chức năng tập hợp con:

data <- subset(data, select=c(3,2,1))

Bạn nên sử dụng toán tử [] như trong các câu trả lời khác, nhưng có thể hữu ích khi biết rằng bạn có thể thực hiện một tập hợp con và một cột sắp xếp lại hoạt động trong một lệnh.

Cập nhật:

Bạn cũng có thể sử dụng chức năng chọn từ gói dplyr:

data = data %>% select(Time, out, In, Files)

Tôi không chắc về hiệu quả, nhưng nhờ cú pháp của dplyr, giải pháp này sẽ linh hoạt hơn, đặc biệt nếu bạn có nhiều cột. Ví dụ: phần sau đây sẽ sắp xếp lại các cột của bộ dữ liệu mtcars theo thứ tự ngược lại:

mtcars %>% select(carb:mpg)

Và sau đây sẽ chỉ sắp xếp lại một số cột và loại bỏ các cột khác:

mtcars %>% select(mpg:disp, hp, wt, gear:qsec, starts_with('carb'))

Đọc thêm về cú pháp chọn của dplyr .


5
Có một số lý do không sử dụng subset(), xem câu hỏi này .
MERose

2
Cảm ơn bạn. Trong mọi trường hợp bây giờ tôi sẽ sử dụng chức năng chọn từ gói dplyr, thay vì tập hợp con.
dalloliogm

87
Khi bạn muốn mang một vài cột sang bên trái và không bỏ các cột khác, tôi thấy everything()đặc biệt tuyệt vời; mtcars %>% select(wt, gear, everything())
chàng trai

2
Dưới đây là một cách khác để sử dụng hàm every () select_helper để sắp xếp lại các cột ở bên phải / kết thúc. stackoverflow.com/a/44353144/4663008 github.com/tidyverse/dplyr/issues/2838 Có vẻ như bạn sẽ cần sử dụng 2 select () để di chuyển một số cột sang đầu bên phải và các cột khác ở bên trái.
Arthur Yip

1
chức năng mới dplyr :: relocate chính xác cho việc này. xem câu trả lời của H 1 bên dưới
Arthur Yip

39

Như đã đề cập trong bình luận này , các đề xuất tiêu chuẩn cho việc sắp xếp lại các cột trong một data.framethường rất cồng kềnh và dễ bị lỗi, đặc biệt là nếu bạn có nhiều cột.

Hàm này cho phép sắp xếp lại các cột theo vị trí: chỉ định tên biến và vị trí mong muốn và không lo lắng về các cột khác.

##arrange df vars by position
##'vars' must be a named vector, e.g. c("var.name"=1)
arrange.vars <- function(data, vars){
    ##stop if not a data.frame (but should work for matrices as well)
    stopifnot(is.data.frame(data))

    ##sort out inputs
    data.nms <- names(data)
    var.nr <- length(data.nms)
    var.nms <- names(vars)
    var.pos <- vars
    ##sanity checks
    stopifnot( !any(duplicated(var.nms)), 
               !any(duplicated(var.pos)) )
    stopifnot( is.character(var.nms), 
               is.numeric(var.pos) )
    stopifnot( all(var.nms %in% data.nms) )
    stopifnot( all(var.pos > 0), 
               all(var.pos <= var.nr) )

    ##prepare output
    out.vec <- character(var.nr)
    out.vec[var.pos] <- var.nms
    out.vec[-var.pos] <- data.nms[ !(data.nms %in% var.nms) ]
    stopifnot( length(out.vec)==var.nr )

    ##re-arrange vars by position
    data <- data[ , out.vec]
    return(data)
}

Bây giờ yêu cầu của OP trở nên đơn giản như thế này:

table <- data.frame(Time=c(1,2), In=c(2,3), Out=c(3,4), Files=c(4,5))
table
##  Time In Out Files
##1    1  2   3     4
##2    2  3   4     5

arrange.vars(table, c("Out"=2))
##  Time Out In Files
##1    1   3  2     4
##2    2   4  3     5

Để trao đổi thêm TimeFilescác cột bạn có thể làm điều này:

arrange.vars(table, c("Out"=2, "Files"=1, "Time"=4))
##  Files Out In Time
##1     4   3  2    1
##2     5   4  3    2

Chức năng rất đẹp. Tôi đã thêm một phiên bản sửa đổi của chức năng này vào gói cá nhân của tôi .
Deleet

1
Điều này thực sự hữu ích - nó sẽ giúp tôi tiết kiệm rất nhiều thời gian khi tôi chỉ muốn di chuyển một cột từ cuối một khoảng cách thực sự rộng đến đầu
Mrmoleje

Wow, tôi thích điều này.
OfTheAzureSky

37

Một dplyrgiải pháp (một phần của bộ tidyversegói) là sử dụng select:

select(table, "Time", "Out", "In", "Files") 

# or

select(table, Time, Out, In, Files)

2
Lựa chọn tốt nhất cho tôi. Ngay cả khi tôi phải cài đặt nó, nó rõ ràng là khả năng rõ ràng nhất.
Garini

15
Tidyverse (dplyr trong thực tế) cũng có tùy chọn để chọn các nhóm cột, ví dụ để di chuyển biến Loài về phía trước : select(iris, Species, everything()). Cũng lưu ý rằng trích dẫn là không cần thiết.
Paul Rougieux

3
Điều quan trọng cần lưu ý là điều này sẽ bỏ tất cả các cột không được chỉ định rõ ràng trừ khi bạn đưa everything()vào như trong nhận xét của
PaulRougieux

dplyrCũng groupsẽ sắp xếp lại các biến, vì vậy hãy coi chừng khi sử dụng biến đó trong chuỗi.
David Tonhofer

26

Có thể đó là một sự trùng hợp ngẫu nhiên khi thứ tự cột bạn muốn có tên cột theo thứ tự bảng chữ cái giảm dần. Vì đó là trường hợp bạn có thể làm:

df<-df[,order(colnames(df),decreasing=TRUE)]

Đó là những gì tôi sử dụng khi tôi có các tệp lớn với nhiều cột.


!! WARNING !! data.tablebiến TARGETthành một vectơ int: TARGET <- TARGET[ , order(colnames(TARGET), decreasing=TRUE)] để sửa lỗi đó: TARGET <- as.data.frame(TARGET) TARGET <- TARGET[ , order(colnames(TARGET), decreasing=TRUE)]
Zachary Ryan Smith


12

Các ba hàng đầu đánh giá câu trả lời có một điểm yếu.

Nếu khung dữ liệu của bạn trông như thế này

df <- data.frame(Time=c(1,2), In=c(2,3), Out=c(3,4), Files=c(4,5))

> df
  Time In Out Files
1    1  2   3     4
2    2  3   4     5

Sau đó, nó là một giải pháp kém để sử dụng

> df2[,c(1,3,2,4)]

Nó thực hiện công việc, nhưng bạn vừa giới thiệu một sự phụ thuộc vào thứ tự của các cột trong đầu vào của bạn.

Phong cách lập trình dễ vỡ này là phải tránh.

Việc đặt tên rõ ràng của các cột là một giải pháp tốt hơn

data[,c("Time", "Out", "In", "Files")]

Ngoài ra, nếu bạn có ý định sử dụng lại mã của mình trong một cài đặt chung hơn, bạn có thể chỉ cần

out.column.name <- "Out"
in.column.name <- "In"
data[,c("Time", out.column.name, in.column.name, "Files")]

Điều này cũng khá hay vì nó hoàn toàn cách ly chữ. Ngược lại, nếu bạn sử dụng dplyr'sselect

data <- data %>% select(Time, out, In, Files)

sau đó bạn sẽ thiết lập những người sẽ đọc mã của bạn sau này, bao gồm cả bản thân bạn, cho một chút lừa dối. Các tên cột đang được sử dụng như chữ mà không xuất hiện trong mã như vậy.


3

dplyrphiên bản 1.0.0bao gồm relocate()chức năng dễ dàng sắp xếp lại các cột:

dat <- data.frame(Time=c(1,2), In=c(2,3), Out=c(3,4), Files=c(4,5))

library(dplyr) # from version 1.0.0 only

dat %>%
  relocate(Out, .before = In)

hoặc là

dat %>%
  relocate(Out, .after = Time)

2
data.table::setcolorder(table, c("Out", "in", "files"))

xin vui lòng cho biết thư viện bạn có chức năng setcolordertừ.
Triamus

1

Người duy nhất tôi thấy làm việc tốt là từ đây .

 shuffle_columns <- function (invec, movecommand) {
      movecommand <- lapply(strsplit(strsplit(movecommand, ";")[[1]],
                                 ",|\\s+"), function(x) x[x != ""])
  movelist <- lapply(movecommand, function(x) {
    Where <- x[which(x %in% c("before", "after", "first",
                              "last")):length(x)]
    ToMove <- setdiff(x, Where)
    list(ToMove, Where)
  })
  myVec <- invec
  for (i in seq_along(movelist)) {
    temp <- setdiff(myVec, movelist[[i]][[1]])
    A <- movelist[[i]][[2]][1]
    if (A %in% c("before", "after")) {
      ba <- movelist[[i]][[2]][2]
      if (A == "before") {
        after <- match(ba, temp) - 1
      }
      else if (A == "after") {
        after <- match(ba, temp)
      }
    }
    else if (A == "first") {
      after <- 0
    }
    else if (A == "last") {
      after <- length(myVec)
    }
    myVec <- append(temp, values = movelist[[i]][[1]], after = after)
  }
  myVec
}

Sử dụng như thế này:

new_df <- iris[shuffle_columns(names(iris), "Sepal.Width before Sepal.Length")]

Hoạt động như một lá bùa.

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.