Pertanyaan Bagaimana mengurutkan dataframe dengan banyak kolom?


Saya ingin mengurutkan data.frame dengan beberapa kolom. Misalnya, dengan data.frame di bawah ini saya ingin mengurutkan berdasarkan kolom z (descending) kemudian berdasarkan 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

1126
2017-08-18 21:33


asal


Jawaban:


Anda dapat menggunakan order() berfungsi secara langsung tanpa menggunakan alat tambahan - lihat jawaban 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 2+ tahun kemudian:  Itu hanya diminta bagaimana melakukannya dengan indeks kolom. Jawabannya adalah dengan hanya melewatkan kolom pengurutan yang diinginkan ke kolom 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 cepat).


1416
2017-08-18 21:51



Pilihan Anda

  • order dari base
  • arrange dari dplyr
  • setorder dan setorderv dari data.table
  • arrange dari plyr
  • sort dari taRifx
  • orderBy dari doBy
  • sortData dari Deducer

Sering kali Anda harus menggunakan dplyr atau data.table solusi, kecuali tidak memiliki ketergantungan adalah penting, dalam hal ini digunakan base::order.


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

Oleh karena itu, dengan diberikan 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 tentang domain publik ada di sini: http://chat.stackoverflow.com/transcript/message/1094290#1094290


Anda juga bisa menggunakan arrange() fungsi dari plyr seperti yang ditunjukkan Hadley dalam utas di atas:

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

Benchmarks: Perhatikan bahwa saya memuat setiap paket dalam sesi R baru karena ada banyak konflik. Secara khusus memuat penyebab paket doBy sort untuk mengembalikan "Objek berikut (s) yang bertopeng dari 'x (posisi 17)': b, x, y, z", dan memuat paket Deduser menimpa sort.data.frame dari 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
)

Median kali:

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 Median: 1,567

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

Waktu Median: 862

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

Waktu Median: 1,694

Perhatikan bahwa doBy membutuhkan waktu yang cukup lama untuk memuat paket.

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

Tidak dapat membuat pemuatan Deducer. 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 attach / detach.


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

microbenchmark plot

(Garis meluas dari kuartil bawah ke kuartil atas, titik adalah median)


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


382
2017-07-29 10:48



Jawabannya sangat bagus. Ini juga menyoroti perbedaan utama dalam sintaks yang digunakan untuk pengindeksan data.frames dan 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 khawatir dengan kebenaran dalam riset Anda, sebaiknya hindari pengulangan nama variabel yang tidak perlu. data.tablemembantu Anda melakukan ini.

Berikut ini contoh bagaimana pengulangan nama variabel dapat membawa Anda ke dalam masalah:

Mari kita mengubah konteks dari jawaban Dirk, dan katakan ini adalah bagian dari proyek yang lebih besar di mana ada banyak nama objek dan itu panjang dan bermakna; dari pada dd ini disebut 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 pergi melalui kode Anda, menambahkan objek lastquarterlyreport di berbagai tempat dan entah bagaimana (bagaimana caranya?) Anda berakhir dengan ini:

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

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

Di data.table kami khawatir tentang detail kecil seperti ini. Jadi kami telah melakukan sesuatu yang sederhana untuk menghindari pengetikan nama variabel dua kali. Sesuatu yang sangat sederhana. i dievaluasi dalam bingkai dd sudah, secara otomatis. Anda tidak perlu with() 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 lehermu suatu hari nanti. Ketika 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 memilikinya.


128
2018-05-25 16:25



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

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

105
2018-02-18 21:29



Paket R data.table menyediakan keduanya cepat dan hemat memori pemesanan data.tabel dengan sintaks langsung (bagian yang telah disorot Matt dengan baik dalam jawabannya). Sudah ada banyak perbaikan dan juga fungsi baru setorder() Dari dulu. Dari v1.9.5+, setorder() juga bekerja dengan data.frames.

Pertama, kita akan membuat dataset yang cukup besar dan patokan metode yang berbeda yang disebutkan dari jawaban lain dan kemudian daftar fitur tabel data.

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)

Tolok ukur:

Waktu yang dilaporkan mulai berjalan system.time(...) pada fungsi-fungsi ini ditunjukkan di bawah ini. Pengaturan waktu ditabulasikan 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 itu ~ 10x lebih cepat daripada metode tercepat lainnya (dplyr), sambil mengonsumsi jumlah memori yang sama dengan dplyr.

  • data.table's setorder() adalah ~ 14x lebih cepat daripada metode tercepat lainnya (dplyr), saat mengambil memori tambahan hanya 0,4GB. dat sekarang dalam urutan yang kami butuhkan (seperti yang diperbarui oleh referensi).

fitur data.table:

Kecepatan:

  • tabel dataPemesanan sangat cepat karena mengimplementasikannya memesan radix.

  • Sintaksnya DT[order(...)] dioptimalkan secara internal untuk digunakan tabel datacepat memesan juga. Anda dapat tetap menggunakan sintak dasar R yang sudah dikenal tetapi mempercepat proses (dan menggunakan lebih sedikit memori).

Ingatan:

  • Seringkali, kami tidak membutuhkan yang asli data.frame atau tabel data setelah penataan kembali. 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. Menjadi hemat memori, tabel data oleh karena itu juga menyediakan fungsi setorder().

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

Fitur lainnya:

  1. Mendukung integer, logical, numeric, character dan bahkan bit64::integer64 jenis.

    Perhatikan itu factor, Date, POSIXct dll .. semua kelas integer/numeric jenis di bawahnya dengan atribut tambahan dan oleh karena itu didukung juga.

  2. Di pangkalan R, kita tidak bisa menggunakannya - pada vektor karakter untuk mengurutkan berdasarkan kolom tersebut dalam urutan menurun. Sebaliknya kita harus menggunakannya -xtfrm(.).

    Namun, di tabel data, kita bisa lakukan, misalnya, dat[order(-x)] atau setorder(dat, -x).


69
2018-03-29 15:52



Dengan fungsi ini (sangat membantu) oleh Kevin Wright, diposting di bagian tips dari wiki R, ini mudah dicapai.

sort(dd,by = ~ -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

57
2017-08-18 21:37



atau Anda dapat menggunakan paket doBy

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

33
2018-01-19 20:44



Misalkan Anda memiliki data.frame  A dan Anda ingin mengurutkannya menggunakan kolom yang disebut x urutan menurun. Panggil yang diurutkan data.frame  newdata

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

Jika Anda menginginkan urutan naik maka ganti "-" tanpa apa-apa. Anda dapat memiliki sesuatu seperti

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

dimana x dan z beberapa kolom di data.frame  A. Ini berarti menyortir data.frame  A oleh x turun, y naik dan z turun.


31
2018-01-25 13:10



Atau, gunakan Paket Deduser

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

24
2017-08-20 19:43



jika SQL datang secara alami kepada Anda, sqldf menangani ORDER BY sebagai Codd dimaksudkan.


24
2018-03-08 23:30