Cara mengurutkan dataframe oleh beberapa kolom(s)

Saya ingin mengurutkan data.bingkai dengan beberapa kolom. Misalnya, dengan data.frame di bawah ini saya ingin mengurutkan berdasarkan kolom z (turun) maka pada kolom b (ascending):

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
Mengomentari pertanyaan (1)
Larutan

Anda dapat menggunakan order() fungsi langsung tanpa menggunakan add-on tools -- lihat ini jawaban sederhana yang menggunakan trik yang tepat dari atas `contoh(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

Mengedit beberapa 2+ tahun kemudian: Itu hanya bertanya bagaimana untuk melakukan hal ini dengan indeks kolom. Jawabannya adalah untuk hanya lulus pengurutan yang diinginkan kolom(s) untuk urutan () 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 dengan() untuk lebih mudah/lebih akses langsung).

Komentar (10)

Pilihan anda

  • order dari base
  • mengatur dari dplyr
  • setorder dan setorderv dari data.meja
  • mengatur dari plyr
  • semacam dari taRifx
  • orderBy dari doBy
  • sortData dari Deducer

Sebagian besar waktu anda harus menggunakan dplyr atau data.tabel solusi, kecuali setelah tidak ada dependensi adalah penting, dalam hal ini menggunakan dasar::order.


Saya baru-baru ini ditambahkan semacam.data.bingkai untuk CRAN paket, sehingga kelas yang kompatibel seperti yang dibahas di sini: https://stackoverflow.com/questions/6836963/best-way-to-create-generic-method-consistency-for-sort-data-frame

Oleh karena itu, mengingat data.bingkai dd, anda bisa urutkan sebagai berikut:


dd 
Komentar (8)

Dirk's jawaban yang lebih besar. Ia juga menyoroti perbedaan penting dalam sintaks yang digunakan untuk mengindeks data.frame dan data.tabel:

## 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 dua panggilan kecil, tetapi hal ini dapat memiliki konsekuensi penting. Terutama jika anda menulis kode produksi dan/atau yang berkaitan dengan kebenaran dalam penelitian anda,'s terbaik untuk menghindari pengulangan yang tidak perlu dari nama variabel. data.meja membantu anda melakukan hal ini.

Berikut ini's contoh bagaimana pengulangan nama-nama variabel bisa mendapatkan anda ke dalam kesulitan:

Let's mengubah konteks dari Dirk's jawaban, dan mengatakan ini adalah bagian dari proyek yang lebih besar di mana ada banyak nama objek dan mereka yang panjang dan bermakna; bukan dd it's disebut quarterlyreport. Menjadi :

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

Ok, baik-baik saja. Ada yang salah dengan itu. Berikutnya bos anda meminta anda untuk memasukkan kuartal terakhir's laporan dalam laporan. Anda pergi melalui kode anda, menambahkan objek lastquarterlyreport di berbagai tempat dan entah bagaimana caranya (bagaimana caranya?) anda berakhir dengan ini :

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

Yang isn't apa yang anda maksud tapi kau tidak't-spot itu karena anda melakukannya dengan cepat dan it's terletak pada sebuah halaman kode yang sama. Kode doesn't jatuh di atas (tidak ada peringatan dan tidak ada kesalahan) karena R berpikir itu adalah apa yang anda maksudkan. Anda'd berharap siapa pun yang membaca laporan anda bintik-bintik ini, tapi mungkin mereka don't. Jika anda bekerja dengan bahasa pemrograman yang banyak maka keadaan ini mungkin semua akrab. Itu adalah "typo" anda'll mengatakan. I'll memperbaiki "typo" anda'll mengatakan kepada atasan anda.

Di data.tabel kita're khawatir tentang rincian kecil seperti ini. Jadi kita've melakukan sesuatu yang sederhana untuk menghindari mengetik nama variabel dua kali. Sesuatu yang sangat sederhana. aku ini dievaluasi dalam kerangka dd sudah, secara otomatis. Anda don't perlu dengan() pada semua.

Bukan

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

it's hanya

dd[order(-z, b)]

Dan bukan

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

it's hanya

quarterlyreport[order(-z,b)]

It's perbedaan yang sangat kecil, tapi itu mungkin akan menyelamatkan leher anda satu hari. Ketika menimbang jawaban yang berbeda untuk pertanyaan ini, pertimbangkan untuk menghitung pengulangan nama-nama variabel sebagai salah satu kriteria anda dalam memutuskan. Beberapa jawaban memiliki beberapa mengulangi, yang lain tidak.

Komentar (4)

Ada banyak jawaban yang sangat baik di sini, tapi dplyr memberikan hanya sintaks yang saya dapat dengan cepat dan mudah diingat (dan sekarang digunakan 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 OP's masalah:

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
Komentar (4)

R paket data.tabelmenyediakan baik *cepat* dan *memori yang efisien* pemesanan *data.tabel* dengan lugas sintaks (bagian yang Matt telah disorot cukup baik [dalam jawabannya](https://stackoverflow.com/a/10758086/559784)). Di sana telah cukup banyak perbaikan dan juga fungsi barusetorder()sejak saat itu. Dariv1.9.5+,setorder()` juga bekerja dengan data.frame.

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

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:

Timing yang dilaporkan adalah dari menjalankan sistem.waktu(...)` pada fungsi-fungsi ini ditunjukkan di bawah ini. Timing ditabulasikan berikut (dalam urutan dari yang paling lambat ke cepat).

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.tabel's DT[order(...)] sintaks adalah ~10x lebih cepat dari yang tercepat dari metode lain (dplyr), sementara mengkonsumsi jumlah yang sama dari memori sebagai dplyr.

  • data.tabel's setorder() adalah ~14x lebih cepat dari yang tercepat dari metode lain (dplyr), saat mengambil hanya 0.4 GB memori tambahan. dat sekarang di order, kami membutuhkan (seperti yang diperbarui oleh referensi).

data.tabel fitur:

Kecepatan:

  • data.tabel's memesan sangat cepat karena menerapkan radix memesan.

  • Sintaks DT[order(...)] dioptimalkan secara internal digunakan data.tabel's cepat memesan juga. Anda dapat tetap menggunakan akrab basis R sintaks tapi mempercepat proses (dan menggunakan memori kurang).

Memori:

  • Sebagian besar waktu, kita don't membutuhkan asli data.frame atau data.tabel setelah penataan kembali. Artinya, kita biasanya menetapkan hasilnya kembali terhadap obyek yang sama, misalnya:

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

Masalahnya adalah bahwa hal ini membutuhkan setidaknya dua kali (2x) memori dari objek asli. Untuk menjadi memori yang efisien, data.tabel oleh karena itu juga menyediakan fungsi setorder().

setorder() menata ulang data.tabel referensi (di tempat), tanpa membuat salinan tambahan. Hanya menggunakan memori tambahan sama dengan ukuran satu kolom.

Fitur lain:

  1. Mendukung integer, logis, numerik, karakter dan bahkan bit64::integer64 jenis.

Perhatikan bahwa faktor, Tanggal, POSIXct dll.. kelas semua integer/numerik jenis bawahnya dengan atribut tambahan dan karena itu didukung juga.

  1. Dalam basis R, kita tidak dapat menggunakan - pada karakter vektor untuk mengurutkan berdasarkan kolom dalam urutan penurunan. Sebaliknya kita harus menggunakan -xtfrm(.).

Namun, dalam data.tabel, kita hanya bisa melakukan, misalnya, dat[order(-x)] atau setorder(dat, -x).

Komentar (4)

Dengan ini (sangat membantu) fungsi oleh Kevin Wright, posted in tips bagian dari R wiki, hal 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
Komentar (1)

atau anda dapat menggunakan paket doBy


library(doBy)
dd 
Komentar (0)

Misalkan anda memiliki data.frame`A dan anda ingin mengatasinya dengan menggunakan kolom x urutan. Sebut diurutkan data.frame newdata


newdata 
Komentar (0)

jika SQL datang secara alami kepada anda, sqldf paket menangani ORDER BY as Codd yang dimaksudkan.

Komentar (1)

Atau, menggunakan paket Deducer


library(Deducer)
dd
Komentar (0)

Saya belajar tentang order dengan contoh berikut yang kemudian saya bingung 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 ini contoh karya adalah karena pesanan adalah menyortir oleh vektor Usia, bukan oleh kolom bernama Usia di data frame data.

Untuk melihat hal ini membuat data yang identik frame menggunakan baca.meja dengan sedikit berbeda, nama kolom dan tanpa menggunakan apapun di atas vektor-vektor:


my.data 
Komentar (3)

Dirk's jawaban yang lebih baik tetapi jika anda perlu untuk bertahan anda'll ingin menerapkan semacam kembali ke nama yang data frame. Menggunakan contoh kode:


dd 
Komentar (0)

Dalam menanggapi komentar ditambahkan dalam OP untuk cara semacam pemrograman:

Menggunakan dplyr dan data.meja

library(dplyr)
library(data.table)

dplyr

Hanya menggunakan arrange_, yang merupakan Standar Evaluasi yang versi untuk mengatur.


df1 
Komentar (0)

Mengatur() di dplyer adalah pilihan favorit saya. Menggunakan pipa operator dan pergi dari yang paling penting ke yang paling penting aspek

dd1 %
    arrange(z) %>%
    arrange(desc(x))
Komentar (0)

Demi kelengkapan: anda juga dapat menggunakan sortByCol() fungsi dari BBmisc paket:

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
Komentar (1)

Sama seperti kartu mekanik penyortir lama, pertama urutkan berdasarkan yang paling penting, kemudian yang berikutnya yang paling signifikan, dll. Ada perpustakaan yang diperlukan, bekerja dengan sejumlah tombol dan kombinasi dari naik dan turun tombol.


 dd 
Komentar (0)

Hanya demi kelengkapan, sejak tidak banyak yang telah dikatakan tentang pengurutan berdasarkan kolom nomor... Itu pasti dapat dikatakan bahwa hal ini sering tidak diinginkan (karena urutan kolom yang bisa berubah, paving jalan untuk kesalahan), tetapi dalam beberapa situasi tertentu (ketika misalnya anda membutuhkan pekerjaan cepat selesai dan tidak ada risiko dari kolom mengubah pesanan), mungkin menjadi hal yang paling masuk akal untuk dilakukan, terutama ketika berhadapan dengan besar kolom.

Dalam kasus itu, apakah.call() datang untuk menyelamatkan:


ind 
Komentar (0)

Alternatif lain, menggunakan rgr paket:

> 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
Komentar (0)

Saya berjuang dengan solusi di atas ketika saya ingin mengotomatisasi saya proses pemesanan untuk n kolom, dan kolom nama-nama bisa berbeda setiap kali. Saya menemukan sangat membantu fungsi dari psikologi paket untuk melakukan hal ini dengan cara yang sederhana:

dfOrder(myDf, columnIndices)

di mana columnIndices adalah indeks dari satu atau lebih kolom, dalam urutan yang anda inginkan untuk mengurutkan mereka. Informasi lebih lanjut di sini:

dfOrder fungsi dari 'psikologi' paket

Komentar (0)