Cara mengurutkan dataframe berdasarkan beberapa kolom


1316

Saya ingin mengurutkan data.frame dengan beberapa kolom. Sebagai contoh, dengan data.frame di bawah ini saya ingin mengurutkan berdasarkan kolom z(turun) kemudian dengan kolom b(naik):

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

Jawaban:


1626

Anda dapat menggunakan order()fungsi secara langsung tanpa menggunakan alat tambahan - lihat jawaban yang lebih sederhana ini yang menggunakan trik langsung dari atas example(order)kode:

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

Edit beberapa 2+ tahun kemudian: Itu hanya ditanya bagaimana melakukan ini dengan indeks kolom. Jawabannya adalah dengan hanya mengoper kolom pengurutan yang diinginkan ke order()fungsi:

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> 

daripada menggunakan nama kolom (dan with()untuk akses langsung yang lebih mudah / lebih).


@Dirk Eddelbuettel apakah ada metode yang sama sederhana untuk matriks?
Jota

14
Seharusnya bekerja dengan cara yang sama, tetapi Anda tidak dapat menggunakannya with. Cobalah M <- matrix(c(1,2,2,2,3,6,4,5), 4, 2, byrow=FALSE, dimnames=list(NULL, c("a","b")))untuk membuat matriks M, kemudian gunakan M[order(M[,"a"],-M[,"b"]),]untuk memesannya di dua kolom.
Dirk Eddelbuettel

4
Cukup mudah :, dd[ order(-dd[,4], dd[,1]), ]tetapi tidak dapat digunakan withuntuk pengaturan ulang berbasis nama.
Dirk Eddelbuettel

18
Saya memiliki kesalahan "argumen tidak valid untuk operator unary" saat menjalankan contoh kedua.
Nailgun

21
Kesalahan "argumen tidak valid untuk operator unary" terjadi ketika Anda menggunakan minus dengan kolom karakter. Selesaikan dengan membungkus kolom xtfrm, misalnya dd[ order(-xtfrm(dd[,4]), dd[,1]), ].
Richie Cotton

477

Pilihan anda

  • order dari base
  • arrange dari dplyr
  • setorderdan setordervdaridata.table
  • arrange dari plyr
  • sort dari taRifx
  • orderBy dari doBy
  • sortData dari Deducer

Sebagian besar waktu Anda harus menggunakan dplyratau data.tablesolusi, kecuali tidak memiliki ketergantungan adalah penting, dalam hal ini digunakan base::order.


Saya baru-baru ini menambahkan sort.data.frame ke paket CRAN, menjadikannya kompatibel dengan kelas seperti yang dibahas di sini: Cara terbaik untuk membuat konsistensi generik / metode untuk sort.data.frame?

Oleh karena itu, mengingat data.frame dd, Anda dapat mengurutkan sebagai berikut:

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 )

Jika Anda adalah salah satu penulis asli dari fungsi ini, silakan hubungi saya. Diskusi mengenai domain publik ada di sini: http://chat.stackoverflow.com/transcript/message/1094290#1094290


Anda juga dapat menggunakan arrange()fungsi dari plyrseperti yang Hadley tunjukkan di utas di atas:

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

Benchmark: Perhatikan bahwa saya memuat setiap paket dalam sesi R baru karena ada banyak konflik. Khususnya memuat paket doBy yang menyebabkan sortpengembalian "Objek berikut ini disembunyikan dari 'x (posisi 17)': b, x, y, z", dan memuat paket Deducer menimpa sort.data.framedari Kevin Wright atau paket 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
)

Waktu rata-rata:

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

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

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

Waktu rata-rata: 1,567

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

Waktu rata-rata: 862

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

Waktu rata-rata: 1,694

Perhatikan bahwa doBy membutuhkan sedikit waktu untuk memuat paket.

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

Tidak dapat membuat Deducer memuat. Membutuhkan konsol JGR.

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

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

Tampaknya tidak kompatibel dengan microbenchmark karena melampirkan / melepaskan.


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

plot microbenchmark

(garis memanjang dari kuartil bawah ke kuartil atas, titik adalah median)


Mengingat hasil ini dan menimbang kesederhanaan vs kecepatan, saya harus memberi anggukan arrangepada plyrpaket . Ia memiliki sintaksis yang sederhana namun hampir sama cepatnya dengan perintah R dasar dengan intrik yang berbelit-belit. Pekerjaan Hadley Wickham yang biasanya brilian. Satu-satunya keluhan saya dengan itu adalah bahwa itu melanggar nomenklatur R standar di mana objek penyortiran dipanggil sort(object), tapi saya mengerti mengapa Hadley melakukannya seperti itu karena masalah yang dibahas dalam pertanyaan yang terkait di atas.


3
Fungsi microbenchmark ggplot2 di atas sekarang tersedia sebagai taRifx::autoplot.microbenchmark.
Ari B. Friedman

@ AriB.Friedman Berapa interval sumbu y / apa skalanya?
naught101

@ naught101 Sumbu y dimulai pada 0. Skala harus mikrodetik.
Ari B. Friedman

2
@AME lihat bagaimana bdiurutkan dalam sampel. Defaultnya adalah mengurutkan dengan menaik, jadi Anda tidak perlu membungkusnya desc. Naik di kedua: arrange(dd,z,b). Turun di kedua: arrange(dd,desc(z),desc(b)).
Ari B. Friedman

2
Per ?arrange: "# CATATAN: fungsi plyr JANGAN pertahankan row.names". Ini membuat arrange()fungsi yang sangat baik menjadi suboptimal jika seseorang ingin mempertahankannya row.names.
landroni

149

Jawaban Dirk sangat bagus. Itu juga menyoroti perbedaan utama dalam sintaks yang digunakan untuk pengindeksan data.framedan 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)]

Perbedaan antara kedua panggilan itu kecil, tetapi dapat memiliki konsekuensi penting. Terutama jika Anda menulis kode produksi dan / atau berkaitan dengan kebenaran dalam penelitian Anda, yang terbaik adalah menghindari pengulangan nama variabel yang tidak perlu.data.table membantu kamu melakukan ini.

Berikut adalah contoh bagaimana pengulangan nama variabel dapat membuat Anda mendapat masalah:

Mari kita ubah konteks dari jawaban Dirk, dan katakan ini adalah bagian dari proyek yang lebih besar di mana ada banyak nama objek dan mereka panjang dan bermakna; bukannya dddisebut quarterlyreport. Menjadi :

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

Baiklah. Tidak ada yang salah dengan itu. Selanjutnya bos Anda meminta Anda untuk memasukkan laporan kuartal terakhir dalam laporan. Anda membaca kode Anda, menambahkan objek lastquarterlyreportdi berbagai tempat dan entah bagaimana (bagaimana?) Anda berakhir dengan ini:

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

Bukan itu yang Anda maksudkan tetapi Anda tidak menemukannya karena Anda melakukannya dengan cepat dan terletak pada halaman kode yang sama. Kode tidak jatuh (tidak ada peringatan dan tidak ada kesalahan) karena R menganggap itu yang Anda maksud. Anda akan berharap siapa pun yang membaca laporan Anda menemukannya, tetapi mungkin tidak. Jika Anda banyak bekerja dengan bahasa pemrograman maka situasi ini mungkin akrab. Itu adalah "kesalahan ketik" yang akan Anda katakan. Saya akan memperbaiki "kesalahan ketik" yang akan Anda katakan kepada bos Anda.

Dalam data.tablekami khawatir tentang detail kecil seperti ini. Jadi kami telah melakukan sesuatu yang sederhana untuk menghindari mengetik nama variabel dua kali. Sesuatu yang sangat sederhana. idievaluasi dalam bingkai ddsudah, secara otomatis. Kamu tidak perluwith() sama sekali.

Dari pada

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

hanya saja

dd[order(-z, b)]

Dan bukannya

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

hanya saja

quarterlyreport[order(-z,b)]

Ini perbedaan yang sangat kecil, tetapi mungkin hanya menyelamatkan leher Anda suatu hari. Saat menimbang jawaban yang berbeda untuk pertanyaan ini, pertimbangkan untuk menghitung pengulangan nama variabel sebagai salah satu kriteria Anda dalam memutuskan. Beberapa jawaban memiliki beberapa pengulangan, yang lain tidak.


9
+1 Ini adalah poin yang bagus, dan mendapatkan detail sintaks R yang sering membuat saya jengkel. Saya terkadang menggunakan subset()hanya untuk menghindari berulang kali merujuk ke objek yang sama dalam satu panggilan.
Josh O'Brien

2
@ naught101 Apakah data.tabel FAQ 1.9 menjawab itu?
Matt Dowle

5
Saya kira Anda dapat menambahkan setorderfungsi baru juga di sini, karena utas ini adalah tempat kami mengirim semua ordertipe dupes.
David Arenburg

125

Ada banyak jawaban bagus di sini, tetapi dplyr memberikan satu-satunya sintaks yang dapat saya ingat dengan cepat dan mudah (dan sekarang gunakan sangat sering):

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)

Untuk masalah 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
Jawaban yang diterima tidak berfungsi ketika kolom saya adalah tipe atau faktor (atau sesuatu seperti itu) dan saya ingin menyortir secara turun-temurun untuk kolom faktor ini diikuti oleh kolom integer dalam mode naik. Tapi ini bekerja dengan baik! Terima kasih!
Saheel Godhane

10
Kenapa "hanya"? Saya menemukan data.tabel ini dd[order(-z, b)]cukup mudah digunakan dan diingat.
Matt Dowle

2
Setuju, tidak ada banyak di antara kedua metode itu, dan data.tablemerupakan kontribusi besar Rdalam banyak hal juga. Saya kira bagi saya, mungkin bahwa memiliki satu set kurung kurang (atau satu jenis kurung kurang) dalam hal ini mengurangi beban kognitif dengan jumlah yang nyaris tak terlihat.
Ben

7
Bagi saya itu datang ke fakta yang arrange()sepenuhnya deklaratif, dd[order(-z, b)]bukan.
Mullefa

83

Paket R data.tablemenyediakan baik cepat dan memori efisien pemesanan data.tables dengan sintaks yang mudah (bagian yang Matt telah menyoroti cukup baik dalam jawabannya ). Telah ada cukup banyak peningkatan dan juga fungsi baru setorder()sejak saat itu. Dari v1.9.5+, setorder()juga berfungsi dengan data.frame .

Pertama, kita akan membuat dataset yang cukup besar dan membandingkan metode-metode berbeda yang disebutkan dari jawaban lain dan kemudian mencantumkan fitur-fitur data.table .

Data:

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)

Tolak ukur:

Pengaturan waktu yang dilaporkan berasal dari menjalankan system.time(...)fungsi-fungsi ini yang ditunjukkan di bawah ini. Pengaturan waktu ditabulasi di bawah ini (dalam urutan paling lambat hingga tercepat).

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(...)]sintaks adalah ~ 10x lebih cepat dari yang tercepat dari metode lain ( dplyr), sedangkan mengkonsumsi jumlah yang sama memori sebagai dplyr.

  • data.table's setorder()adalah ~ 14x lebih cepat dari yang tercepat dari metode lain ( dplyr), saat mengambil hanya 0.4GB memori tambahan . datsekarang dalam urutan yang kami butuhkan (karena diperbarui dengan referensi).

fitur data.table:

Kecepatan:

  • pemesanan data.table sangat cepat karena mengimplementasikan pemesanan radix .

  • Sintaks DT[order(...)]dioptimalkan secara internal untuk menggunakan data.table juga memesan cepat. Anda dapat tetap menggunakan sintaks dasar R yang familier tetapi mempercepat prosesnya (dan menggunakan lebih sedikit memori).

Penyimpanan:

  • Sebagian besar waktu, kami tidak memerlukan kerangka data.atau atau data.tabel setelah pemesanan ulang. Artinya, kami biasanya menetapkan hasilnya kembali ke objek yang sama, misalnya:

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

    Masalahnya adalah ini membutuhkan setidaknya dua kali (2x) memori objek asli. Agar memori efisien , data.table juga menyediakan fungsi setorder().

    setorder()menata ulang data.tables by reference ( di tempat ), tanpa membuat salinan tambahan. Ini hanya menggunakan memori ekstra sama dengan ukuran satu kolom.

Fitur lainnya:

  1. Mendukung integer, logical, numeric, characterdan bahkan bit64::integer64jenis.

    Perhatikan bahwa factor, Date, POSIXctdll .. kelas semua integer/ numericjenis di bawahnya dengan atribut tambahan dan karena itu didukung juga.

  2. Di basis R, kita tidak bisa menggunakan -vektor karakter untuk mengurutkan berdasarkan kolom itu dalam urutan menurun. Sebaliknya kita harus menggunakan -xtfrm(.).

    Namun, dalam data.table , kita bisa melakukannya, misalnya, dat[order(-x)]atau setorder(dat, -x).


Terima kasih atas jawaban yang sangat instruktif tentang data ini. Padahal, saya tidak mengerti apa itu "memori puncak" dan bagaimana Anda menghitungnya. Bisakah Anda jelaskan? Terima kasih !
Julien Navarre

Saya menggunakan Instrumen -> alokasi dan melaporkan ukuran "Semua tumpukan dan alokasi VM".
Arun

2
@Arun tautan Instrumen di komentar Anda sudah mati. Ingin memposting pembaruan?
MichaelChirico

@MichaelChirico Ini adalah tautan ke informasi tentang Instrumen yang dibuat oleh Apple: developer.apple.com/library/content/documentation/…
n1k31t4


39

atau Anda bisa menggunakan paket doBy

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

39

Misalkan Anda memiliki data.frame Adan ingin mengurutkannya menggunakan kolom yang disebut xurutan menurun. Panggil yang disortirdata.frame newdata

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

Jika Anda ingin pesanan naik maka ganti "-"dengan yang tidak ada. Anda dapat memiliki sesuatu seperti

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

di mana xdan zbeberapa kolom di data.frame A. Ini berarti mengurutkan data.frame Adengan xmenurun, ynaik dan zturun.


32

jika SQL datang secara alami kepada Anda, sqldfpaket menangani ORDER BYseperti yang dimaksudkan Codd.


7
MJM, terima kasih telah menunjukkan paket ini. Ini sangat fleksibel dan karena setengah dari pekerjaan saya sudah dilakukan dengan menarik dari database sql itu lebih mudah daripada belajar banyak dari R kurang dari sintaks intuitif.
Brandon Bertelsen

31

Atau, menggunakan paket Deducer

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

19

Menanggapi komentar yang ditambahkan dalam OP untuk cara menyortir secara terprogram:

Menggunakan dplyrdandata.table

library(dplyr)
library(data.table)

dplyr

Cukup gunakan arrange_, yang merupakan versi Evaluasi Standar untuk 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)

info lebih lanjut di sini: https://cran.r-project.org/web/packages/dplyr/vignettes/nse.html

Lebih baik menggunakan rumus karena juga menangkap lingkungan untuk mengevaluasi ekspresi

tabel data

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

Saya belajar orderdengan contoh berikut yang kemudian membingungkan saya untuk waktu yang lama:

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

Satu-satunya alasan contoh ini berfungsi adalah karena orderdisortir oleh vector Age, bukan oleh kolom yang disebutkan Agedalam data frame data.

Untuk melihat ini, buat bingkai data yang identik menggunakan read.tabledengan nama kolom yang sedikit berbeda dan tanpa menggunakan salah satu dari vektor di atas:

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)

Struktur garis di atas ordertidak lagi berfungsi karena tidak ada vektor bernama age:

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

Baris berikut berfungsi karena ordermengurutkan pada kolom agedi my.data.

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

Saya pikir ini layak diposkan mengingat betapa bingungnya saya dengan contoh ini sejak lama. Jika posting ini dianggap tidak sesuai untuk utas, saya dapat menghapusnya.

EDIT: 13 Mei 2014

Di bawah ini adalah cara umum menyortir bingkai data dengan setiap kolom tanpa menentukan nama kolom. Kode di bawah ini menunjukkan cara menyortir dari kiri ke kanan atau dari kanan ke kiri. Ini berfungsi jika setiap kolom numerik. Saya belum mencoba dengan kolom karakter yang ditambahkan.

Saya menemukan do.callkode satu atau dua bulan yang lalu di sebuah posting lama di situs yang berbeda, tetapi hanya setelah pencarian yang luas dan sulit. Saya tidak yakin bisa memindahkan pos itu sekarang. Utas saat ini adalah hit pertama untuk memesan data.framein R. Jadi, saya pikir versi saya yang diperluas dari do.callkode asli itu mungkin berguna.

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
Sintaks itu berfungsi jika Anda menyimpan data Anda dalam data.table, bukan data.frame: require(data.table); my.dt <- data.table(my.data); my.dt[order(age)]Ini berfungsi karena nama kolom tersedia di dalam kurung [].
Frank

Saya tidak berpikir downvote diperlukan di sini, tetapi saya juga tidak berpikir ini menambah banyak pertanyaan di tangan, terutama mengingat set jawaban yang ada, beberapa di antaranya sudah menangkap persyaratan dengan data.framebaik untuk menggunakan withatau $.
A5C1D2H2I1M1N2O1R2T1

1
upvote untuk do.callini membuat pekerjaan singkat menyortir bingkai data multicolumn. Cukup do.call(sort, mydf.obj)dan semacam kaskade yang indah akan didapat.
AdamO

17

Jawaban Dirk bagus, tetapi jika Anda perlu pengurutan untuk bertahan, Anda ingin menerapkan pengurutan kembali ke nama bingkai data itu. Menggunakan kode contoh:

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

13

Atur () di dplyer adalah opsi favorit saya. Gunakan operator pipa dan beralih dari aspek yang paling tidak penting ke yang paling penting

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

7

Hanya demi kelengkapan, karena tidak banyak yang dikatakan tentang pengurutan berdasarkan nomor kolom ... Dapat dipastikan bahwa itu sering tidak diinginkan (karena urutan kolom bisa berubah, membuka jalan ke kesalahan), tetapi dalam beberapa situasi tertentu (ketika misalnya Anda perlu pekerjaan cepat dilakukan dan tidak ada risiko kolom mengubah pesanan), itu mungkin hal yang paling masuk akal untuk dilakukan, terutama ketika berhadapan dengan sejumlah besar kolom.

Dalam hal ini, do.call()datanglah untuk menyelamatkan:

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

Demi kelengkapan: Anda juga dapat menggunakan sortByCol()fungsi dari BBmiscpaket:

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

Perbandingan kinerja:

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
aneh untuk menambahkan perbandingan kinerja saat metode Anda paling lambat ... tetap meragukan nilai menggunakan tolok ukur pada 4-barisdata.frame
MichaelChirico

5

Seperti halnya penyortir kartu mekanis dahulu kala, pertama urutkan berdasarkan kunci yang paling tidak signifikan, lalu yang paling signifikan berikutnya, dll. Tidak diperlukan pustaka, bekerja dengan sejumlah kunci dan kombinasi tombol mana pun yang naik dan turun.

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

Sekarang kita siap melakukan kunci yang paling signifikan. Penyortiran stabil, dan ikatan apa pun dalam kunci paling signifikan telah dipecahkan.

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

Ini mungkin bukan yang tercepat, tetapi tentu saja sederhana dan dapat diandalkan


4

Alternatif lain, menggunakan rgrpaket:

> 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

Saya berjuang dengan solusi di atas ketika saya ingin mengotomatiskan proses pemesanan saya untuk n kolom, yang nama kolomnya bisa berbeda setiap kali. Saya menemukan fungsi super bermanfaat dari psychpaket untuk melakukan ini secara langsung:

dfOrder(myDf, columnIndices)

dimana columnIndices indeks dari satu atau lebih kolom, dalam urutan di mana Anda ingin mengurutkannya. Informasi lebih lanjut di sini:

dfOrder berfungsi dari paket 'psych'

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.