0 Làm thế nào để bạn tạo một đối tượng mới và sắp xếp nó theo năm, tên và sự kiện? [bản sao]

câu hỏi được tạo ra tại Wed, May 8, 2019 12:00 AM

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
    
1217
  1. Đối với gấu trúc, có thể tìm thấy giải pháp tại đây .
    2019-01-29 23: 27: 57Z
    19 Câu trả lời                              19                         

    Bạn có thể sử dụng order() hoạt độ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 mã example(order):

    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ỉ mục 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 hàm order():

    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).

        
    1523
    2018-09-21 13: 42: 37Z
    1. @ Dirk Eddelbuettel có một phương pháp đơn giản tương tự cho ma trận không?
      2012-03-27 03: 17: 34Z
    2. Nên hoạt động theo cùng một cách, nhưng bạn không thể sử dụng with. Hãy thử M <- matrix(c(1,2,2,2,3,6,4,5), 4, 2, byrow=FALSE, dimnames=list(NULL, c("a","b"))) để tạo ma trận M, sau đó sử dụng 0600350991111010 >
      2012-03-27 12: 41: 29Z
    3. Đủ dễ dàng: M[order(M[,"a"],-M[,"b"]),], nhưng không thể sử dụng dd[ order(-dd[,4], dd[,1]), ] để đặt tên dựa trên tên.
      2012-10-21 14: 34: 07Z
    4. 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.
      2013-01-22 23: 01: 47Z
    5. 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 gói cột trong with, ví dụ xtfrm.
      2015-03-24 11: 40: 45Z

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

    • dd[ order(-xtfrm(dd[,4]), dd[,1]), ] từ order
    • base từ arrange
    • dplyrsetorder từ setorderv
    • data.table từ arrange
    • plyr từ sort
    • taRifx từ orderBy
    • doBy từ sortData

    Hầu hết thời gian bạn nên sử dụng các giải pháp Deducer hoặc dplyr, trừ khi không có phụ thuộc là quan trọng, trong trường hợp đó sử dụng data.table.

    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 pháp để sắp xếp .data.frame?

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

    base::order

    Nếu bạn là một trong những tác giả gốc của chức năng này, 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 chức năng

    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 )
    
    từ arrange() như Hadley đã chỉ ra trong chuỗi trên: plyr

    Đ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 khiến

    library(plyr)
    arrange(dd,desc(z),b)
    
    trả 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 đè lên sort từ Kevin Wright gói. sort.data.frame

    Thời gian trung bình:

    #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
    )
    
    778

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

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

    Thời gian trung bình: 1,567

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

    Thời gian trung bình: 862

    library(plyr)
    microbenchmark(arrange(dd,desc(z),b),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(doBy)
    microbenchmark(orderBy(~-z+b, data=dd),times=1000)
    

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

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

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

    esort <- function(x, sortvar, ...) {
    attach(x)
    x <- x[with(x,order(sortvar,...)),]
    return(x)
    detach(x)
    }
    
    microbenchmark(esort(dd, -z, b),times=1000)
    

     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ị cao hơn, dấu chấm là trung vị)

    Với những kết quả này và cân nhắc sự đơn giản so với tốc độ, tôi phải gật đầu với

    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))
    
    trong gói arrange . 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 bởi plyr, 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 được liên kết ở trên.

        
    425
    2019-04-12 17: 55: 12Z
    1. + 1 về tính kỹ lưỡng, mặc dù tôi thừa nhận rằng tôi thấy đầu ra sort(object) khá khó đọc ...
      2011-07-31 15: 55: 31Z
    2. Chức năng microbenchmark của ggplot2 ở trên hiện có sẵn là microbenchmark.
      2012-06-01 01: 23: 01Z
    3. @ AriB.Friedman Khoảng thời gian trục y /tỷ lệ là gì?
      2012-07-30 05: 04: 19Z
    4. @ AME xem cách taRifx::autoplot.microbenchmark được sắ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ó trong b. Tăng dần trong cả hai: desc. Giảm dần trong cả hai: arrange(dd,z,b).
      2013-10-12 10: 16: 56Z
    5. Theo arrange(dd,desc(z),desc(b)): "# LƯU Ý: các hàm plyr KHÔNG bảo toàn hàng.names". Điều này làm cho hàm ?arrange tuyệt vời trở nên tối ưu nếu người ta muốn giữ arrange().
      2014 /03-10 16: 31: 33Z

    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 row.namess và data.frames:

    data.table

    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 lặp lại không cần thiết các tên biến.

    ## 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)]
    
     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ì data.table, nó được gọi là dd. Nó trở thành:

    quarterlyreport

    Ok, tốt thô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

    quarterlyreport[with(quarterlyreport,order(-z,b)),]
    
    ở 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: lastquarterlyreport

    Đó không phải là ý của 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" mà bạn sẽ nói với sếp của bạn.

    Trong

    quarterlyreport[with(lastquarterlyreport,order(-z,b)),]
    
    chúng tôi quan tâm đến những 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. data.table được đánh giá trong khung i rồi, tự động. Bạn không cần dd.

    Thay vì

    with()

    chỉ là

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

    Và thay vì

    dd[order(-z, b)]
    

    chỉ là

    quarterlyreport[with(lastquarterlyreport,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, một số khác không có.

        
    135
    2012-05-25 21: 42: 51Z
    1. + 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 sử dụng
      quarterlyreport[order(-z,b)]
      
      chỉ để 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.
      2012-05-25 20: 45: 05Z
    2. Mọi ý tưởng tại sao chúng hoạt động theo những cách khác nhau?
      2012-11-26 07: 21: 21Z
    3. @ naught101 Liệu data.table FAQ 1.9 có trả lời không?
      2012-11-26 08: 04: 59Z
    4. Tôi đoán bạn có thể thêm chức năng subset() mới ở đây, vì chủ đề này là nơi chúng tôi gửi tất cả các bản sao loại setorder.
      2015-01-08 19: 18: 19Z

    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):

    order

    Đối với sự cố của OP:

    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)
    
        
    113
    2014 /02-18 21: 29: 25Z
    1. 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 cột số nguyên trong thời trang tăng dần. Nhưng điều này chỉ hoạt động tốt! Cảm ơn bạn!
      2014 /02-22 18: 36: 52Z
    2. Tại sao "chỉ"? Tôi thấy
      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
      
      của data.table khá dễ sử dụng và dễ nhớ.
      2014-03-19 11: 11: 38Z
    3. Đồng ý, không có nhiều giữa hai phương thức đó và dd[order(-z, b)] cũng đóng góp rất lớn cho data.table theo 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.
      2014-03-19 17: 13: 59Z
    4. Đối với tôi, thực tế là R hoàn toàn không phải là khai báo, arrange() thì không.
      2015-05-29 13: 12: 07Z

    Gói R dd[order(-z, b)] cung cấp cả nhanh hiệu quả bộ nhớ sắp xếp thứ tự data.tables với cú pháp đơn giản (một phần trong đó Matt có đã nhấn mạnh khá độc đáo trong câu trả lời của mình ). Đã có khá nhiều cải tiến và cũng là một chức năng mới data.table kể từ đó. Từ setorder(), v1.9.5+ cũng hoạt động với data.frames .

    Trước tiên, chúng tôi sẽ tạo một bộ dữ liệu đủ lớn và điểm chuẩn các phương thức 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:

    setorder()

    Điểm chuẩn:

    Thời gian được báo cáo là từ việc chạy

    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)
    
    trên các chức năng được hiển thị bên dưới. Thời gian được lập bảng dưới đây (theo thứ tự từ chậm nhất đến nhanh nhất). system.time(...)
      Cú pháp
    • 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
      # ------------------------------------------------------------
      
      của data.table ~ 10x nhanh hơn so với các phương thức nhanh nhất (DT[order(...)]), trong khi tiêu thụ cùng một lượng bộ nhớ là 0600350991111010
    • dplyr dplyr ~ 14x nhanh hơn các phương pháp nhanh nhất (data.table), trong khi chỉ cần chỉ thêm 0,4 GB bộ nhớ . setorder() hiện theo thứ tự chúng tôi yêu cầu (vì nó được cập nhật theo tham chiếu).

    tính năng data.table:

    Tốc độ:

      Việc đặt hàng của
    • data.table cực kỳ nhanh chóng vì nó thực hiện đặt hàng cơ số .

    • Cú pháp dplyr được tối ưu hóa nội bộ để sử dụng thứ tự nhanh 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).

    Bộ nhớ:

    • Hầu hết thời gian, chúng tôi không yêu cầu data.frame hoặc data.table ban đầu 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ụ:

      dat

      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. Để trở thành bộ nhớ hiệu quả , data.table do đó cũng cung cấp chức năng DT[order(...)].

      DF <- DF[order(...)]
      
      sắp xếp lại data.tables setorder() ( 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ợ setorder(), by reference, integer, logical và thậm chí numeric.

        

      Lưu ý rằng character, bit64::integer64, factor vv .. các lớp đều là các loại Date/POSIXct bên dưới các thuộc tính bổ sung và do đó cũng được hỗ trợ.

    2. Trong cơ sở R, chúng tôi không thể sử dụng integer 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 tôi phải sử dụng numeric.

      Tuy nhiên, trong data.table , chúng tôi chỉ có thể làm, ví dụ: - hoặc -xtfrm(.).

    75
    2017-05-23 10: 31: 37Z
    1. Cảm ơn câu trả lời rất có căn cứ 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!
      2015-06-30 14: 32: 54Z
    2. Tôi đã sử dụng
nguồn đặt đây