Cách sắp xếp một khung dữ liệu theo nhiều cột


1316

Tôi muốn sắp xếp một data.frame theo nhiều cột. Ví dụ: với data.frame bên dưới, tôi muốn sắp xếp theo cột z(giảm dần) sau đó theo cột b(tăng dần):

dd <- data.frame(b = factor(c("Hi", "Med", "Hi", "Low"), 
      levels = c("Low", "Med", "Hi"), ordered = TRUE),
      x = c("A", "D", "A", "C"), y = c(8, 3, 9, 9),
      z = c(1, 1, 1, 2))
dd
    b x y z
1  Hi A 8 1
2 Med D 3 1
3  Hi A 9 1
4 Low C 9 2

Câu trả lời:


1626

Bạn có thể sử dụng order()chức năng trực tiếp mà không cần dùng đến các công cụ bổ trợ - hãy xem câu trả lời đơn giản hơn này sử dụng một mẹo ngay từ đầu example(order)mã:

R> dd[with(dd, order(-z, b)), ]
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1

Chỉnh sửa khoảng hơn 2 năm sau: Người ta chỉ hỏi làm thế nào để làm điều này theo chỉ số cột. Câu trả lời là chỉ cần chuyển (các) cột sắp xếp mong muốn cho order()hàm:

R> dd[order(-dd[,4], dd[,1]), ]
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1
R> 

thay vì sử dụng tên của cột (và with()để truy cập trực tiếp / dễ dàng hơn).


@Dirk Eddelbuettel có một phương pháp đơn giản tương tự cho ma trận không?
Jota

14
Nên hoạt động theo cùng một cách, nhưng bạn không thể sử dụng with. Cố gắng M <- matrix(c(1,2,2,2,3,6,4,5), 4, 2, byrow=FALSE, dimnames=list(NULL, c("a","b")))tạo một ma trận M, sau đó sử dụng M[order(M[,"a"],-M[,"b"]),]để đặt nó trên hai cột.
Dirk Eddelbuettel

4
Đủ dễ dàng : dd[ order(-dd[,4], dd[,1]), ], nhưng không thể sử dụng withcho tập hợp con dựa trên tên.
Dirk Eddelbuettel

18
Tôi có lỗi "đối số không hợp lệ đối với toán tử đơn nguyên" trong khi chạy ví dụ thứ hai.
Súng bắn đinh

21
Lỗi "đối số không hợp lệ đối với toán tử đơn nguyên" xảy ra khi bạn sử dụng dấu trừ với cột ký tự. Giải quyết nó bằng cách bọc cột trong xtfrm, ví dụ dd[ order(-xtfrm(dd[,4]), dd[,1]), ].
Richie Cotton

477

Lựa chọn của bạn

  • order từ base
  • arrange từ dplyr
  • setordersetordervtừdata.table
  • arrange từ plyr
  • sort từ taRifx
  • orderBy từ doBy
  • sortData từ Deducer

Hầu hết thời gian bạn nên sử dụng dplyrhoặc data.tablegiải pháp, trừ khi không có phụ thuộc là quan trọng, trong trường hợp sử dụng base::order.


Gần đây tôi đã thêm sort.data.frame vào gói CRAN, làm cho lớp này tương thích như được thảo luận ở đây: Cách tốt nhất để tạo tính nhất quán chung / phương thức cho sort.data.frame?

Do đó, với dd data.frame, bạn có thể sắp xếp như sau:

dd <- data.frame(b = factor(c("Hi", "Med", "Hi", "Low"), 
      levels = c("Low", "Med", "Hi"), ordered = TRUE),
      x = c("A", "D", "A", "C"), y = c(8, 3, 9, 9),
      z = c(1, 1, 1, 2))
library(taRifx)
sort(dd, f= ~ -z + b )

Nếu bạn là một trong những tác giả gốc của chức năng này, xin vui lòng liên hệ với tôi. Thảo luận về phạm vi công cộng có tại đây: http://chat.stackoverflow.com/transcript/message/1094290#1094290


Bạn cũng có thể sử dụng arrange()hàm từ plyrnhư Hadley đã chỉ ra trong chuỗi trên:

library(plyr)
arrange(dd,desc(z),b)

Điểm chuẩn: Lưu ý rằng tôi đã tải từng gói trong phiên R mới vì có rất nhiều xung đột. Cụ thể là tải gói doBy gây ra sorttrả về "Các đối tượng sau được che dấu từ 'x (vị trí 17)': b, x, y, z" và tải gói Deducer ghi đè sort.data.frametừ Kevin Wright hoặc gói taRifx.

#Load each time
dd <- data.frame(b = factor(c("Hi", "Med", "Hi", "Low"), 
      levels = c("Low", "Med", "Hi"), ordered = TRUE),
      x = c("A", "D", "A", "C"), y = c(8, 3, 9, 9),
      z = c(1, 1, 1, 2))
library(microbenchmark)

# Reload R between benchmarks
microbenchmark(dd[with(dd, order(-z, b)), ] ,
    dd[order(-dd$z, dd$b),],
    times=1000
)

Thời gian trung bình:

dd[with(dd, order(-z, b)), ] 778

dd[order(-dd$z, dd$b),] 788

library(taRifx)
microbenchmark(sort(dd, f= ~-z+b ),times=1000)

Thời gian trung bình: 1.567

library(plyr)
microbenchmark(arrange(dd,desc(z),b),times=1000)

Thời gian trung bình: 862

library(doBy)
microbenchmark(orderBy(~-z+b, data=dd),times=1000)

Thời gian trung bình: 1.694

Lưu ý rằng doBy mất một chút thời gian để tải gói.

library(Deducer)
microbenchmark(sortData(dd,c("z","b"),increasing= c(FALSE,TRUE)),times=1000)

Không thể tải Deducer. Cần giao diện điều khiển JGR.

esort <- function(x, sortvar, ...) {
attach(x)
x <- x[with(x,order(sortvar,...)),]
return(x)
detach(x)
}

microbenchmark(esort(dd, -z, b),times=1000)

Không có vẻ tương thích với microbenchmark do đính kèm / tách.


m <- microbenchmark(
  arrange(dd,desc(z),b),
  sort(dd, f= ~-z+b ),
  dd[with(dd, order(-z, b)), ] ,
  dd[order(-dd$z, dd$b),],
  times=1000
  )

uq <- function(x) { fivenum(x)[4]}  
lq <- function(x) { fivenum(x)[2]}

y_min <- 0 # min(by(m$time,m$expr,lq))
y_max <- max(by(m$time,m$expr,uq)) * 1.05

p <- ggplot(m,aes(x=expr,y=time)) + coord_cartesian(ylim = c( y_min , y_max )) 
p + stat_summary(fun.y=median,fun.ymin = lq, fun.ymax = uq, aes(fill=expr))

cốt truyện microbenchmark

(các dòng kéo dài từ phân vị thấp hơn đến phân vị trên, dấu chấm là trung vị)


Với những kết quả và nặng tốc độ so với sự đơn giản, tôi muốn phải từ bỏ cái gật đầu để arrangetrong plyrgói . Nó có một cú pháp đơn giản và gần như nhanh như các lệnh R cơ sở với các âm mưu phức tạp của chúng. Điển hình là công việc tuyệt vời của Hadley Wickham. Điều duy nhất của tôi với nó là nó phá vỡ danh pháp R tiêu chuẩn nơi các đối tượng sắp xếp được gọi theo sort(object), nhưng tôi hiểu tại sao Hadley lại làm như vậy do các vấn đề được thảo luận trong câu hỏi liên kết ở trên.


3
Hàm microbenchmark của ggplot2 ở trên hiện có sẵn dưới dạng taRifx::autoplot.microbenchmark.
Ari B. Friedman

@ AriB.Friedman Các khoảng trục y / tỷ lệ là gì?
nè 101

@ naught101 Trục y bắt đầu từ 0. Tỷ lệ nên là micro giây.
Ari B. Friedman

2
@AME xem cách bsắp xếp trong mẫu. Mặc định được sắp xếp theo tăng dần, vì vậy bạn không bao bọc nó desc. Tăng dần trong cả hai : arrange(dd,z,b). Giảm dần trong cả hai : arrange(dd,desc(z),desc(b)).
Ari B. Friedman

2
Theo ?arrange: "# LƯU Ý: các hàm plyr KHÔNG giữ nguyên hàng.names". Điều này làm cho arrange()chức năng tuyệt vời dưới mức tối ưu nếu một người muốn giữ row.names.
Landroni

149

Câu trả lời của Dirk rất hay. Nó cũng nêu bật một sự khác biệt chính trong cú pháp được sử dụng để lập chỉ mục data.frames và data.tables:

## The data.frame way
dd[with(dd, order(-z, b)), ]

## The data.table way: (7 fewer characters, but that's not the important bit)
dd[order(-z, b)]

Sự khác biệt giữa hai cuộc gọi là nhỏ, nhưng nó có thể có những hậu quả quan trọng. Đặc biệt nếu bạn viết mã sản xuất và / hoặc quan tâm đến tính chính xác trong nghiên cứu của mình, tốt nhất là tránh sự lặp lại không cần thiết của các tên biến.data.table giúp bạn làm điều này.

Đây là một ví dụ về cách lặp lại tên biến có thể khiến bạn gặp rắc rối:

Hãy thay đổi bối cảnh từ câu trả lời của Dirk và nói rằng đây là một phần của dự án lớn hơn, nơi có rất nhiều tên đối tượng và chúng dài và có ý nghĩa; thay vì ddnó được gọi là quarterlyreport. No trở nên :

quarterlyreport[with(quarterlyreport,order(-z,b)),]

Được rồi Không có gì sai với điều đó. Tiếp theo, sếp của bạn yêu cầu bạn đưa báo cáo của quý trước vào báo cáo. Bạn đi qua mã của mình, thêm một đối tượng lastquarterlyreportở nhiều nơi khác nhau và bằng cách nào đó (làm thế nào trên trái đất?) Bạn kết thúc với điều này:

quarterlyreport[with(lastquarterlyreport,order(-z,b)),]

Đó không phải là ý bạn nhưng bạn đã không phát hiện ra vì bạn đã làm nhanh và nó nằm trên một trang có mã tương tự. Mã không bị đổ (không có cảnh báo và không có lỗi) vì R nghĩ rằng đó là ý bạn. Bạn sẽ hy vọng bất cứ ai đọc báo cáo của bạn phát hiện ra nó, nhưng có lẽ họ không biết. Nếu bạn làm việc với các ngôn ngữ lập trình rất nhiều thì tình huống này có thể là tất cả để làm quen. Đó là một "lỗi đánh máy" bạn sẽ nói. Tôi sẽ sửa "lỗi đánh máy" bạn sẽ nói với sếp của bạn.

Trong data.tablechúng ta đang lo ngại về chi tiết nhỏ như thế này. Vì vậy, chúng tôi đã làm một cái gì đó đơn giản để tránh gõ tên biến hai lần. Một cái gì đó rất đơn giản. iđược đánh giá trong khung ddđã, tự động. Bạn không cần with()gì cả.

Thay vì

dd[with(dd, order(-z, b)), ]

nó chỉ

dd[order(-z, b)]

Và thay vì

quarterlyreport[with(lastquarterlyreport,order(-z,b)),]

nó chỉ

quarterlyreport[order(-z,b)]

Đó là một sự khác biệt rất nhỏ, nhưng nó có thể chỉ cứu cổ bạn một ngày nào đó. Khi cân nhắc các câu trả lời khác nhau cho câu hỏi này, hãy xem xét việc lặp lại các tên biến là một trong những tiêu chí của bạn khi quyết định. Một số câu trả lời có khá nhiều lần lặp lại, số khác không có.


9
+1 Đây là một điểm tuyệt vời và nhận được một chi tiết về cú pháp của R thường làm tôi khó chịu. Đôi khi tôi subset()chỉ sử dụng để tránh phải liên tục nhắc đến cùng một đối tượng trong một cuộc gọi.
Josh O'Brien

2
@ naught101 Liệu data.table FAQ 1.9 có trả lời không?
Matt Dowle

5
Tôi đoán bạn có thể thêm setorderchức năng mới ở đây, vì chủ đề này là nơi chúng tôi gửi tất cả các bản sao orderloại.
David Arenburg

125

Có rất nhiều câu trả lời xuất sắc ở đây, nhưng dplyr đưa ra cú pháp duy nhất mà tôi có thể nhanh chóng và dễ nhớ (và vì vậy bây giờ sử dụng rất thường xuyên):

library(dplyr)
# sort mtcars by mpg, ascending... use desc(mpg) for descending
arrange(mtcars, mpg)
# sort mtcars first by mpg, then by cyl, then by wt)
arrange(mtcars , mpg, cyl, wt)

Đối với vấn đề của OP:

arrange(dd, desc(z),  b)

    b x y z
1 Low C 9 2
2 Med D 3 1
3  Hi A 8 1
4  Hi A 9 1

2
Câu trả lời được chấp nhận không hoạt động khi các cột của tôi là hoặc loại yếu tố (hoặc đại loại như thế) và tôi muốn sắp xếp theo kiểu giảm dần cho cột yếu tố này theo sau là cột số nguyên theo kiểu tăng dần. Nhưng điều này chỉ hoạt động tốt! Cảm ơn bạn!
Saheel Godhane

10
Tại sao chỉ"? Tôi thấy data.table dd[order(-z, b)]khá dễ sử dụng và ghi nhớ.
Matt Dowle

2
Đồng ý, không có nhiều giữa hai phương pháp đó, và data.tablecũng đóng góp rất lớn Rvào nhiều cách khác. Tôi cho rằng đối với tôi, có thể có một bộ dấu ngoặc (hoặc một loại dấu ngoặc ít hơn) trong trường hợp này làm giảm tải nhận thức xuống một lượng chỉ có thể nhận thấy được.
Ben

7
Đối với tôi nó đi xuống thực tế arrange()là hoàn toàn khai báo, dd[order(-z, b)]là không.
Mullefa

83

Các gói phần mềm R data.tablecung cấp cả hai nhanh chóngbộ nhớ hiệu quả Trật tự của data.tables với một cú pháp đơn giản (một phần trong số đó Matt đã nêu bật khá độc đáo trong câu trả lời của ông ). Đã có khá nhiều cải tiến và cũng là một chức năng mới setorder()kể từ đó. Từ v1.9.5+, setorder()cũng hoạt động với data.frames .

Đầu tiên, chúng tôi sẽ tạo một bộ dữ liệu đủ lớn và đánh giá các phương pháp khác nhau được đề cập từ các câu trả lời khác và sau đó liệt kê các tính năng của data.table .

Dữ liệu:

require(plyr)
require(doBy)
require(data.table)
require(dplyr)
require(taRifx)

set.seed(45L)
dat = data.frame(b = as.factor(sample(c("Hi", "Med", "Low"), 1e8, TRUE)),
                 x = sample(c("A", "D", "C"), 1e8, TRUE),
                 y = sample(100, 1e8, TRUE),
                 z = sample(5, 1e8, TRUE), 
                 stringsAsFactors = FALSE)

Điểm chuẩn:

Thời gian báo cáo là từ chạy system.time(...)trên các chức năng được hiển thị dưới đây. Thời gian được lập bảng dưới đây (theo thứ tự từ chậm nhất đến nhanh nhất).

orderBy( ~ -z + b, data = dat)     ## doBy
plyr::arrange(dat, desc(z), b)     ## plyr
arrange(dat, desc(z), b)           ## dplyr
sort(dat, f = ~ -z + b)            ## taRifx
dat[with(dat, order(-z, b)), ]     ## base R

# convert to data.table, by reference
setDT(dat)

dat[order(-z, b)]                  ## data.table, base R like syntax
setorder(dat, -z, b)               ## data.table, using setorder()
                                   ## setorder() now also works with data.frames 

# R-session memory usage (BEFORE) = ~2GB (size of 'dat')
# ------------------------------------------------------------
# Package      function    Time (s)  Peak memory   Memory used
# ------------------------------------------------------------
# doBy          orderBy      409.7        6.7 GB        4.7 GB
# taRifx           sort      400.8        6.7 GB        4.7 GB
# plyr          arrange      318.8        5.6 GB        3.6 GB 
# base R          order      299.0        5.6 GB        3.6 GB
# dplyr         arrange       62.7        4.2 GB        2.2 GB
# ------------------------------------------------------------
# data.table      order        6.2        4.2 GB        2.2 GB
# data.table   setorder        4.5        2.4 GB        0.4 GB
# ------------------------------------------------------------
  • data.table's DT[order(...)]cú pháp là ~ 10x nhanh hơn so với nhanh nhất của các phương pháp khác ( dplyr), trong khi tiêu thụ cùng một lượng bộ nhớ như dplyr.

  • data.table's setorder()~ 14x nhanh hơn so với nhanh nhất của các phương pháp khác ( dplyr), trong khi chụp chỉ 0.4GB thêm bộ nhớ . datbây giờ theo thứ tự chúng tôi yêu cầu (vì nó được cập nhật bằng cách tham khảo).

tính năng data.table:

Tốc độ:

  • Thứ tự của data.table cực kỳ nhanh vì nó thực hiện thứ tự cơ số .

  • Cú pháp DT[order(...)]được tối ưu hóa nội bộ để sử dụng thứ tự nhanh chóng của data.table . Bạn có thể tiếp tục sử dụng cú pháp cơ sở R quen thuộc nhưng tăng tốc quá trình (và sử dụng ít bộ nhớ hơn).

Ký ức:

  • Hầu hết thời gian, chúng tôi không yêu cầu data.frame hoặc data.table gốc sau khi sắp xếp lại. Đó là, chúng ta thường gán kết quả trở lại cho cùng một đối tượng, ví dụ:

    DF <- DF[order(...)]

    Vấn đề là điều này đòi hỏi ít nhất hai lần (2 lần) bộ nhớ của đối tượng ban đầu. Để có hiệu quả bộ nhớ , data.table do đó cũng cung cấp một hàmsetorder() .

    setorder()sắp xếp lại data.tables by reference ( tại chỗ ) mà không tạo thêm bất kỳ bản sao nào. Nó chỉ sử dụng thêm bộ nhớ bằng kích thước của một cột.

Các tính năng khác:

  1. Nó hỗ trợ integer, logical, numeric, charactervà thậm chí bit64::integer64các loại.

    Lưu ý rằng factor, Date, POSIXctvv .. các lớp học đều integer/ numericloại bên dưới với các thuộc tính bổ sung và do đó được hỗ trợ là tốt.

  2. Trong cơ sở R, chúng ta không thể sử dụng -trên một vectơ ký tự để sắp xếp theo cột đó theo thứ tự giảm dần. Thay vào đó chúng ta phải sử dụng -xtfrm(.).

    Tuy nhiên, trong data.table , chúng ta chỉ có thể làm, ví dụ, dat[order(-x)]hoặc setorder(dat, -x).


Cảm ơn câu trả lời rất hướng dẫn này về data.table. Mặc dù vậy, tôi không hiểu "bộ nhớ tối đa" là gì và cách bạn tính toán nó. Bạn có thể giải thích? Cảm ơn bạn !
Julien Navarre

Tôi đã sử dụng Dụng cụ -> phân bổ và báo cáo kích thước "Tất cả đống phân bổ và VM phân bổ".
Arun

2
@Asl liên kết dụng cụ trong bình luận của bạn đã chết. Muốn đăng cập nhật?
MichaelChirico 30/03/2016

@MichaelChirico Đây là đường dẫn đến thông tin về Dụng cụ do Apple sản xuất: developer.apple.com/l
Library / content / document / trộm


39

hoặc bạn có thể sử dụng gói doBy

library(doBy)
dd <- orderBy(~-z+b, data=dd)

39

Giả sử bạn có một data.frame Avà bạn muốn sắp xếp nó bằng cột được gọi là xthứ tự giảm dần. Gọi sắp xếpdata.frame newdata

newdata <- A[order(-A$x),]

Nếu bạn muốn thứ tự tăng dần thì thay thế "-"bằng không có gì. Bạn có thể có một cái gì đó như

newdata <- A[order(-A$x, A$y, -A$z),]

ở đâu xzmột số cột trong data.frame A. Điều này có nghĩa là sắp xếp data.frame Atheo xgiảm dần, ytăng dần và zgiảm dần.


32

nếu SQL tự nhiên đến với bạn, sqldfgói xử lý ORDER BYnhư Codd dự định.


7
MJM, cảm ơn bạn đã chỉ ra gói này. Nó cực kỳ linh hoạt và bởi vì một nửa công việc của tôi đã được thực hiện bằng cách lấy từ cơ sở dữ liệu sql, điều đó dễ hơn là học nhiều cú pháp trực quan của R.
Brandon Bertelsen

31

Ngoài ra, sử dụng gói Deducer

library(Deducer)
dd<- sortData(dd,c("z","b"),increasing= c(FALSE,TRUE))

19

Đáp lại bình luận được thêm vào trong OP về cách sắp xếp theo chương trình:

Sử dụng dplyrdata.table

library(dplyr)
library(data.table)

dplyr

Chỉ cần sử dụng arrange_, đó là phiên bản Đánh giá Tiêu chuẩn cho arrange.

df1 <- tbl_df(iris)
#using strings or formula
arrange_(df1, c('Petal.Length', 'Petal.Width'))
arrange_(df1, ~Petal.Length, ~Petal.Width)
    Source: local data frame [150 x 5]

   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
          (dbl)       (dbl)        (dbl)       (dbl)  (fctr)
1           4.6         3.6          1.0         0.2  setosa
2           4.3         3.0          1.1         0.1  setosa
3           5.8         4.0          1.2         0.2  setosa
4           5.0         3.2          1.2         0.2  setosa
5           4.7         3.2          1.3         0.2  setosa
6           5.4         3.9          1.3         0.4  setosa
7           5.5         3.5          1.3         0.2  setosa
8           4.4         3.0          1.3         0.2  setosa
9           5.0         3.5          1.3         0.3  setosa
10          4.5         2.3          1.3         0.3  setosa
..          ...         ...          ...         ...     ...


#Or using a variable
sortBy <- c('Petal.Length', 'Petal.Width')
arrange_(df1, .dots = sortBy)
    Source: local data frame [150 x 5]

   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
          (dbl)       (dbl)        (dbl)       (dbl)  (fctr)
1           4.6         3.6          1.0         0.2  setosa
2           4.3         3.0          1.1         0.1  setosa
3           5.8         4.0          1.2         0.2  setosa
4           5.0         3.2          1.2         0.2  setosa
5           4.7         3.2          1.3         0.2  setosa
6           5.5         3.5          1.3         0.2  setosa
7           4.4         3.0          1.3         0.2  setosa
8           4.4         3.2          1.3         0.2  setosa
9           5.0         3.5          1.3         0.3  setosa
10          4.5         2.3          1.3         0.3  setosa
..          ...         ...          ...         ...     ...

#Doing the same operation except sorting Petal.Length in descending order
sortByDesc <- c('desc(Petal.Length)', 'Petal.Width')
arrange_(df1, .dots = sortByDesc)

thêm thông tin ở đây: https://cran.r-project.org/web/packages/dplyr/vignettes/nse.html

Tốt hơn là sử dụng công thức vì nó cũng nắm bắt môi trường để đánh giá một biểu thức trong

bảng dữ liệu

dt1 <- data.table(iris) #not really required, as you can work directly on your data.frame
sortBy <- c('Petal.Length', 'Petal.Width')
sortType <- c(-1, 1)
setorderv(dt1, sortBy, sortType)
dt1
     Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
  1:          7.7         2.6          6.9         2.3 virginica
  2:          7.7         2.8          6.7         2.0 virginica
  3:          7.7         3.8          6.7         2.2 virginica
  4:          7.6         3.0          6.6         2.1 virginica
  5:          7.9         3.8          6.4         2.0 virginica
 ---                                                            
146:          5.4         3.9          1.3         0.4    setosa
147:          5.8         4.0          1.2         0.2    setosa
148:          5.0         3.2          1.2         0.2    setosa
149:          4.3         3.0          1.1         0.1    setosa
150:          4.6         3.6          1.0         0.2    setosa

18

Tôi đã học được ordervới ví dụ sau đây khiến tôi bối rối trong một thời gian dài:

set.seed(1234)

ID        = 1:10
Age       = round(rnorm(10, 50, 1))
diag      = c("Depression", "Bipolar")
Diagnosis = sample(diag, 10, replace=TRUE)

data = data.frame(ID, Age, Diagnosis)

databyAge = data[order(Age),]
databyAge

Lý do duy nhất ví dụ này hoạt động là vì ordersắp xếp theo vector Age, chứ không phải theo cột có tên Agetrong data frame data.

Để thấy điều này, hãy tạo một khung dữ liệu giống hệt nhau bằng read.tablecác tên cột hơi khác nhau và không sử dụng bất kỳ vectơ nào ở trên:

my.data <- read.table(text = '

  id age  diagnosis
   1  49 Depression
   2  50 Depression
   3  51 Depression
   4  48 Depression
   5  50 Depression
   6  51    Bipolar
   7  49    Bipolar
   8  49    Bipolar
   9  49    Bipolar
  10  49 Depression

', header = TRUE)

Cấu trúc dòng trên orderkhông còn hoạt động vì không có vector có tên age:

databyage = my.data[order(age),]

Dòng sau hoạt động vì ordersắp xếp trên cột agetrong my.data.

databyage = my.data[order(my.data$age),]

Tôi nghĩ rằng đây là giá trị đăng bài cho rằng tôi đã bối rối như thế nào bởi ví dụ này quá lâu. Nếu bài viết này không được coi là phù hợp với chủ đề tôi có thể loại bỏ nó.

EDIT: ngày 13 tháng 5 năm 2014

Dưới đây là cách tổng quát để sắp xếp khung dữ liệu theo từng cột mà không chỉ định tên cột. Mã dưới đây cho thấy cách sắp xếp từ trái sang phải hoặc phải sang trái. Điều này hoạt động nếu mỗi cột là số. Tôi đã không thử với một cột nhân vật được thêm vào.

Tôi đã tìm thấy do.callmã một hoặc hai tháng trước trong một bài viết cũ trên một trang web khác, nhưng chỉ sau khi tìm kiếm rộng rãi và khó khăn. Tôi không chắc chắn tôi có thể di dời bài viết đó bây giờ. Chủ đề hiện tại là lần đầu tiên để đặt hàng data.frametrong R. Vì vậy, tôi nghĩ rằng phiên bản mở rộng của do.callmã gốc đó có thể hữu ích.

set.seed(1234)

v1  <- c(0,0,0,0, 0,0,0,0, 1,1,1,1, 1,1,1,1)
v2  <- c(0,0,0,0, 1,1,1,1, 0,0,0,0, 1,1,1,1)
v3  <- c(0,0,1,1, 0,0,1,1, 0,0,1,1, 0,0,1,1)
v4  <- c(0,1,0,1, 0,1,0,1, 0,1,0,1, 0,1,0,1)

df.1 <- data.frame(v1, v2, v3, v4) 
df.1

rdf.1 <- df.1[sample(nrow(df.1), nrow(df.1), replace = FALSE),]
rdf.1

order.rdf.1 <- rdf.1[do.call(order, as.list(rdf.1)),]
order.rdf.1

order.rdf.2 <- rdf.1[do.call(order, rev(as.list(rdf.1))),]
order.rdf.2

rdf.3 <- data.frame(rdf.1$v2, rdf.1$v4, rdf.1$v3, rdf.1$v1) 
rdf.3

order.rdf.3 <- rdf.1[do.call(order, as.list(rdf.3)),]
order.rdf.3

4
Cú pháp đó hoạt động nếu bạn lưu trữ dữ liệu của mình trong data.table, thay vì data.frame: require(data.table); my.dt <- data.table(my.data); my.dt[order(age)]Điều này hoạt động vì tên cột được cung cấp bên trong dấu ngoặc [].
Frank

Tôi không nghĩ rằng downvote là cần thiết ở đây, nhưng tôi cũng không nghĩ rằng điều này bổ sung nhiều vào câu hỏi , đặc biệt là xem xét các câu trả lời hiện có, một số trong đó đã nắm bắt được yêu cầu với data.frames để sử dụng withhoặc $.
A5C1D2H2I1M1N2O1R2T1

1
upvote cho do.callđiều này làm cho công việc ngắn của việc sắp xếp một khung dữ liệu nhiều màu. Đơn giản do.call(sort, mydf.obj)và một loại thác đẹp sẽ có.
AdamO

17

Câu trả lời của Dirk là tốt nhưng nếu bạn cần sắp xếp để tiếp tục, bạn sẽ muốn áp dụng sắp xếp lại vào tên của khung dữ liệu đó. Sử dụng mã ví dụ:

dd <- dd[with(dd, order(-z, b)), ] 

13

Sắp xếp () trong dplyer là tùy chọn yêu thích của tôi. Sử dụng toán tử đường ống và đi từ khía cạnh quan trọng nhất đến quan trọng nhất

dd1 <- dd %>%
    arrange(z) %>%
    arrange(desc(x))

7

Chỉ vì mục đích đầy đủ, vì không có nhiều thông tin về việc sắp xếp theo số cột ... Chắc chắn có thể lập luận rằng điều đó thường không được mong muốn (vì thứ tự của các cột có thể thay đổi, mở đường cho lỗi), nhưng trong một số tình huống cụ thể (ví dụ khi bạn cần một công việc nhanh chóng được thực hiện và không có nguy cơ cột thay đổi đơn hàng như vậy), đó có thể là điều hợp lý nhất để làm, đặc biệt là khi xử lý số lượng lớn cột.

Trong trường hợp đó, do.call()đến để giải cứu:

ind <- do.call(what = "order", args = iris[,c(5,1,2,3)])
iris[ind, ]

##        Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
##    14           4.3         3.0          1.1         0.1     setosa
##    9            4.4         2.9          1.4         0.2     setosa
##    39           4.4         3.0          1.3         0.2     setosa
##    43           4.4         3.2          1.3         0.2     setosa
##    42           4.5         2.3          1.3         0.3     setosa
##    4            4.6         3.1          1.5         0.2     setosa
##    48           4.6         3.2          1.4         0.2     setosa
##    7            4.6         3.4          1.4         0.3     setosa
##    (...)

6

Để hoàn thiện: bạn cũng có thể sử dụng sortByCol()chức năng từ BBmiscgói:

library(BBmisc)
sortByCol(dd, c("z", "b"), asc = c(FALSE, TRUE))
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1

So sánh hiệu suất:

library(microbenchmark)
microbenchmark(sortByCol(dd, c("z", "b"), asc = c(FALSE, TRUE)), times = 100000)
median 202.878

library(plyr)
microbenchmark(arrange(dd,desc(z),b),times=100000)
median 148.758

microbenchmark(dd[with(dd, order(-z, b)), ], times = 100000)
median 115.872

4
Thật lạ khi thêm một so sánh hiệu suất khi phương pháp của bạn chậm nhất ... dù sao cũng nghi ngờ giá trị của việc sử dụng điểm chuẩn trên 4 hàngdata.frame
MichaelChirico 30/03/2016

5

Giống như các bộ sắp xếp thẻ cơ học từ lâu, đầu tiên sắp xếp theo khóa quan trọng nhất, sau đó là quan trọng nhất tiếp theo, v.v. Không cần thư viện, hoạt động với bất kỳ số lượng khóa và bất kỳ tổ hợp phím tăng dần và giảm dần nào.

 dd <- dd[order(dd$b, decreasing = FALSE),]

Bây giờ chúng tôi đã sẵn sàng để làm chìa khóa quan trọng nhất. Loại này ổn định và bất kỳ mối quan hệ nào trong khóa quan trọng nhất đã được giải quyết.

dd <- dd[order(dd$z, decreasing = TRUE),]

Đây có thể không phải là nhanh nhất, nhưng nó chắc chắn là đơn giản và đáng tin cậy


4

Một cách khác, sử dụng rgrgói:

> library(rgr)
> gx.sort.df(dd, ~ -z+b)
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1

4

Tôi đã vật lộn với các giải pháp trên khi tôi muốn tự động hóa quy trình đặt hàng của mình cho n cột, có tên cột có thể khác nhau mỗi lần. Tôi tìm thấy một chức năng siêu hữu ích từ psychgói để thực hiện việc này một cách đơn giản:

dfOrder(myDf, columnIndices)

Ở đâu columnIndices các chỉ mục của một hoặc nhiều cột, theo thứ tự mà bạn muốn sắp xếp chúng. Thêm thông tin ở đây:

Hàm dfOrder từ gói 'psych'

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.