Як сортувати кадр даних за кількома стовпцями


1316

Я хочу сортувати data.frame за кількома стовпцями. Наприклад, за допомогою data.frame нижче я хотів би сортувати за стовпцем z(низхідний), а потім за стовпцем b(за зростанням):

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

Відповіді:


1625

Ви можете використовувати order()функцію безпосередньо, не вдаючись до додаткових інструментів - дивіться цю простішу відповідь, яка використовує хитрість праворуч у верхній частині 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

Відредагуйте через 2+ років: Просто запитали, як це зробити за індексом стовпців. Відповідь полягає у тому, щоб просто передати потрібну стовпчики сортування у 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> 

замість використання назви стовпця (та with()для більш легкого / прямого доступу).


@Dirk Eddelbuettel чи існує такий же простий метод для матриць?
Джота

14
Потрібно працювати так само, але ви не можете використовувати with. Спробуйте M <- matrix(c(1,2,2,2,3,6,4,5), 4, 2, byrow=FALSE, dimnames=list(NULL, c("a","b")))створити матрицю M, а потім використовуйте M[order(M[,"a"],-M[,"b"]),]для впорядкування її у двох стовпцях.
Дірк Еддельбуеттель

4
Досить просто:, dd[ order(-dd[,4], dd[,1]), ]але не може використовуватись withдля підмножини на основі імен.
Дірк Еддельбюттель

18
У мене є помилка "недійсний аргумент для унарного оператора" під час запуску другого прикладу.
Nailgun

21
Помилка "недійсний аргумент для унарного оператора" виникає, коли ви використовуєте мінус зі стовпцем символів. Вирішити його обгортання колонки в xtfrm, наприклад dd[ order(-xtfrm(dd[,4]), dd[,1]), ].
Річі Коттон

477

Ваш вибір

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

Більшу частину часу ви повинні використовувати рішення dplyrабо data.tableрішення, якщо тільки не має залежностей, важливо, і в цьому випадку використовувати base::order.


Нещодавно я додав sort.data.frame до пакету CRAN, роблячи клас сумісним, як обговорювалося тут: Найкращий спосіб створити загальну / послідовну методику для sort.data.frame?

Тому, враховуючи дані.frame dd, ви можете сортувати наступне:

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 )

Якщо ви один з оригінальних авторів цієї функції, будь ласка, зв'яжіться зі мною. Дискусія щодо публічної доступності тут: http://chat.stackoverflow.com/transcript/message/1094290#1094290


Ви також можете використовувати arrange()функцію, plyrяк Хадлі вказав у вищенаведеній темі:

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

Орієнтири: Зауважте, що я завантажував кожен пакет у новому сеансі R, оскільки було багато конфліктів. Зокрема, завантаження пакета doBy призводить sortдо повернення "Наступні об'єкти маскуються з 'x (позиція 17)': b, x, y, z", а завантаження пакета Deducer перезаписується sort.data.frameз Кевіна Райт або пакета 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
)

Середній час:

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

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

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

Середній час: 1567

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

Середній час: 862

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

Середній час: 1694

Зауважте, що doBy потребує небагато часу, щоб завантажити пакет.

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

Не вдалося завантажити вивідник. Потрібна консоль JGR.

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

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

Не здається сумісним з мікробензиновим позначкою через прикріплення / від'єднання.


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

сюжет мікробензика

(лінії простягаються від нижнього кварталу до верхнього кватиля, точка - медіана)


Враховуючи ці результати та зважуючи простоту та швидкість, я повинен би дати кивок arrangeу plyrпакеті . Він має простий синтаксис і все ж майже такий же швидкий, як і базові команди R зі своїми звивистими махінаціями. Типово геніальна робота Хедлі Вікхема. Моя єдина боротьба з цим полягає в тому, що він порушує стандартну номенклатуру R, де подзвонюють об'єкти сортування sort(object), але я розумію, чому Хедлі зробив це таким чином через проблеми, обговорені у вищезазначеному питанні.


3
Функція мікроблоку ggplot2, наведена вище, тепер доступна як taRifx::autoplot.microbenchmark.
Арі Б. Фрідман

@ AriB.Friedman Які інтервали осі y / яка шкала?
naught101

@ naught101 Вісь y починається з 0. Масштаб повинен становити мікросекунди.
Арі Б. Фрідман

2
@AME подивіться, як bсортується у вибірці. За замовчуванням впорядковується за зростанням, так що ви просто не загортаєте його desc. Висхідний в обох: arrange(dd,z,b). Спустившись в обох: arrange(dd,desc(z),desc(b)).
Арі Б. Фрідман

2
Відповідно до ?arrange: "# ПРИМІТКА: функції plyr НЕ зберігають імен рядків". Це робить відмінну arrange()функцію неоптимальною, якщо хочеться зберегти row.names.
landroni

148

Відповідь Дірка чудова. Він також підкреслює ключову різницю в синтаксисі, який використовується для індексації data.frames і 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)]

Різниця між двома дзвінками невелика, але це може мати важливі наслідки. Особливо, якщо ви пишете виробничий код та / або переймаєтесь правильністю у своєму дослідженні, краще уникати непотрібного повторення назв змінних. data.table допомагає вам це зробити.

Ось приклад того, як повторення імен змінних може привести вас до проблеми:

Давайте змінимо контекст з відповіді Дірка і скажемо, що це частина більшого проекту, де існує багато назв об’єктів, і вони довгі та значущі; замість того, ddщо називається quarterlyreport. Це стає :

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

Добре, гаразд. Нічого поганого в цьому немає. Далі ваш начальник просить вас включити до звіту останній квартал. Ви переглядаєте свій код, додаючи об'єкт lastquarterlyreportу різних місцях і якось (як на землі?) Закінчуєте це:

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

Це не те, що ви мали на увазі, але ви цього не помітили, оскільки ви зробили це швидко, і він розташований на сторінці подібного коду. Код не перепадає (без попередження та помилки), оскільки R вважає, що це ви мали на увазі. Ви сподіваєтесь, що хто прочитає ваш звіт, це помітить, але, можливо, вони цього не роблять. Якщо ви багато працюєте з мовами програмування, то ця ситуація може бути всім знайома. Скажете, це був «друкарський помилок». Я виправлю «друкарську помилку», яку ви скажете своєму начальнику.

В data.tableми стурбовані дрібних деталях , як це. Тому ми зробили щось просте, щоб уникнути набору змінних імен двічі. Щось дуже просте. iоцінюється в рамках ddвже, автоматично. Вам зовсім не потрібно with().

Замість

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

це просто

dd[order(-z, b)]

І замість цього

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

це просто

quarterlyreport[order(-z,b)]

Це дуже мала різниця, але це може просто врятувати шию одного дня. Зважуючи різні відповіді на це питання, розгляньте підрахунок повторів імен змінних як один із ваших критеріїв при прийнятті рішення. Деякі відповіді мають досить багато повторів, інші - жодного.


9
+1 Це чудовий момент, і він описується в деталях синтаксису R, який часто мене дратував. Я інколи використовую subset()просто, щоб уникнути повторного звернення до одного і того ж об'єкта в межах одного дзвінка.
Джош О'Браєн

2
@ naught101 Чи відповідає відповідь data.table FAQ 1.9?
Метт Даул

5
Я думаю, ви можете також додати нову setorderфункцію сюди, оскільки ця нитка - це те, куди ми надсилаємо всі orderтипи дупів.
Девід Аренбург

125

Тут дуже багато відмінних відповідей, але dplyr дає єдиний синтаксис, який я швидко і легко запам'ятовую (і тому зараз користуюся дуже часто):

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)

Для проблеми ОП:

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
Прийнята відповідь не працює, коли мої стовпці є чи фактором типу (або чимось подібним), і я хочу сортувати у низхідному порядку для цього стовпчика-фактора, а потім цілого стовпця у порядку зростання. Але це працює просто чудово! Дякую!
Saheel Godhane

10
Чому "тільки"? Я вважаю, що data.table dd[order(-z, b)]досить простий у використанні та запам'ятовується.
Метт Даул

2
Домовились, між цими двома методами не так вже й багато, і data.tableце також є величезним внеском Rу багато інших способів. Я гадаю, для мене може бути те, що наявність одного меншого набору дужок (або одного меншого типу дужок) у цьому випадку зменшує когнітивне навантаження на ледь помітну кількість.
Бен

7
Для мене це зводиться до того, що arrange()це абсолютно декларативно, dd[order(-z, b)]ні.
Маллефа

83

Пакет R data.tableзабезпечує як швидке, так і ефективне впорядкування впорядкування таблиць даних із прямим синтаксисом (частину якого Метт досить добре виділив у своїй відповіді ). Відтоді було вдосконалено багато, а також нова функція setorder(). З v1.9.5+, setorder()також працює з data.frames .

Спочатку ми створимо набір даних досить великий і порівняємо різні методи, згадані з інших відповідей, а потім перерахуємо особливості data.table .

Дані:

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)

Орієнтири:

Повідомлення про синхронізацію починають працювати system.time(...)за цими функціями, показаними нижче. Часи часу відображаються в таблиці (у порядку найповільнішого та найшвидшого).

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.tableDT[order(...)]Синтаксис 's на 10 разів швидший, ніж найшвидший з інших методів ( dplyr), витрачаючи при цьому той же об'єм пам'яті, що і dplyr.

  • data.table's setorder()було на 14 разів швидше, ніж найшвидший з інших методів ( dplyr), забираючи лише 0,4 Гб додаткової пам'яті . datзараз в тому порядку, який ми вимагаємо (оскільки він оновлюється посиланням).

Особливості data.table:

Швидкість:

  • Замовлення data.table надзвичайно швидке, оскільки воно здійснює радіоупорядкування .

  • Синтаксис DT[order(...)]оптимізований для внутрішнього використання також для швидкого впорядкування data.table . Ви можете продовжувати використовувати звичний синтаксис базового R, але прискорити процес (і використовувати менше пам'яті).

Пам'ять:

  • У більшості випадків нам не потрібен оригінальний data.frame або data.table після переупорядкування. Тобто ми зазвичай присвоюємо результат тому ж об’єкту, наприклад:

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

    Проблема полягає в тому, що для цього потрібно принаймні двічі (2x) пам'ять оригінального об'єкта. Для ефективної пам’яті , таким чином , таблиця даних також забезпечує функцію setorder().

    setorder()впорядковує data.tables by reference ( в місці ), без внесення будь - яких додаткових копій. Він використовує лише додаткову пам'ять, рівну розміру одного стовпця.

Інші особливості:

  1. Він підтримує integer, logical, numeric, characterі навіть bit64::integer64тип.

    Зверніть увагу , що factor, Date, і POSIXctт.д .. класи все integer/ numericтипів під додатковими атрибутами , і тому також підтримуються.

  2. У базі R ми не можемо використовувати -для символьного вектора для сортування за цим стовпцем у порядку зменшення. Натомість ми повинні використовувати-xtfrm(.) .

    Однак у data.table ми можемо просто зробити, наприклад, dat[order(-x)]або setorder(dat, -x).


Дякую за цю дуже повчальну відповідь про data.table. Хоча я не розумію, що таке "пікова пам'ять" і як ви її обчислили. Не могли б ви пояснити, будь ласка? Дякую !
Жульєн Наварра

Я використав інструменти -> асигнування та повідомив про розмір "Всю купу та розподілення".
Арун

2
@Arun Інструменти у вашому коментарі мертві. Хочете опублікувати оновлення?
MichaelChirico

@MichaelChirico Ось посилання на інформацію про інструменти, зроблені Apple: developer.apple.com/library/content/documentation/…
n1k31t4

73

Завдяки цій (дуже корисній) функції Кевіна Райт , розміщеній у розділі порад вікі R, це легко досягти.

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

2
Дивіться мою відповідь щодо тестування алгоритму, який використовується в цій функції.
Арі Б. Фрідман


39

Припустимо, у вас є data.frame Aі ви хочете сортувати його за допомогою стовпця, який називається xнизхідним порядком. Дзвоніть відсортованомуdata.frame newdata

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

Якщо ви хочете висхідний порядок, тоді замініть "-"нічим. Ви можете мати щось подібне

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

де xі zдеякі колонки в data.frame A. Це означає сортувати data.frame Aза xнизхідним, yвисхідним та zнизхідним рівнем.


32

якщо SQL приходить вам природно, sqldfпакет обробляє так, ORDER BYяк Codd задумав.


7
MJM, дякую, що вказали на цей пакет. Це неймовірно гнучко, і тому, що половину моєї роботи вже зроблено, витягуючи з баз даних sql, це легше, ніж вивчити більшу частину R менше, ніж інтуїтивно зрозумілий синтаксис.
Брендон Бертелсен


19

У відповідь на коментар, доданий в ОП, як сортувати програмно:

Використання dplyrтаdata.table

library(dplyr)
library(data.table)

dplyr

Просто використовуйте arrange_, що є версією стандартної оцінки 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)

Більше інформації тут: https://cran.r-project.org/web/packages/dplyr/vignettes/nse.html

Краще використовувати формулу, оскільки вона також захоплює середовище для оцінки виразу в

data.table

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

Я дізнався про orderнаступний приклад, який потім мене тривалий час бентежив:

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

Єдиною причиною цього прикладу є те, що orderце сортування за vector Ageстовпцем, названим Ageуdata frame data .

Для цього створіть ідентичний кадр даних, використовуючи read.tableтрохи інші назви стовпців і не використовуючи жодного з перерахованих вище векторів:

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)

Наведена вище структура рядка orderбільше не працює, тому що немає вектора з ім'ям age:

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

Наступний рядок працює, оскільки orderсортує в стовпці ageв my.data.

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

Я вважав, що це варто опублікувати, враховуючи, наскільки я так розгублений на цьому прикладі. Якщо ця публікація не вважається доцільною для теми, я можу її видалити.

EDIT: 13 травня 2014 року

Нижче наведено узагальнений спосіб сортування кадру даних за кожним стовпцем без зазначення назв стовпців. Код нижче показує, як сортувати зліва направо або справа наліво. Це працює, якщо кожен стовпець є числовим. Я не пробував із додаванням символьної колонки.

Я знайшов do.callкод місяць-два тому в старому дописі на іншому веб-сайті, але лише після широкого і важкого пошуку. Я не впевнений, що міг би перенести цю посаду зараз. Справжній потік є першим хітом для замовлення data.frameпо прибуттю R. Отже, я вважав, що моя розширена версія цього оригінального do.callкоду може бути корисною.

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
Цей синтаксис спрацьовує, якщо ви зберігаєте свої дані у таблиці даних замість data.frame: require(data.table); my.dt <- data.table(my.data); my.dt[order(age)]Це працює, оскільки назви стовпців доступні у дужках [].
Френк

Я не думаю, що голосування тут не потрібне, але я також не думаю, що це значно додає до питання , особливо з огляду на існуючий набір відповідей, деякі з яких вже охоплюють вимогу data.frames або використовувати withабо $.
A5C1D2H2I1M1N2O1R2T1

1
Оновлення для do.callцього робить короткою роботою сортування багатокольонового кадру даних. Просто do.call(sort, mydf.obj)і красивий сорт каскаду буде мати.
AdamO

17

Відповідь Дірка хороша, але якщо вам потрібно зберегти сортування, ви захочете застосувати сортування назад до імені цього кадру даних. Використовуючи приклад коду:

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

13

Упорядкувати () у dplyer - це мій улюблений варіант. Скористайтеся трубним оператором і перейдіть від найменш важливого до найважливішого аспекту

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

7

Просто задля повноти, оскільки про сортування за номерами стовпців не було сказано багато… Напевно можна стверджувати, що це часто небажано (адже порядок стовпців міг би змінитися, проклавши шлях до помилок), але у деяких конкретних ситуаціях (коли, наприклад, вам потрібно швидко виконати роботу, і немає такого ризику зміни стовпців замовлень), це може бути найрозумнішим, що потрібно зробити, особливо коли мова йде про велику кількість стовпців.

У цьому випадку do.call()на допомогу приходить:

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

Для повноти: ви також можете використовувати sortByCol()функцію з BBmiscпакета:

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

Порівняння продуктивності:

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
дивно додавати порівняння продуктивності, коли ваш метод найповільніший ... все одно сумнівне значення використання орієнтиру на 4-му рядуdata.frame
MichaelChirico

5

Як і механічні сортувальники карт давно, спочатку сортуйте за найменш значущим ключем, потім за наступним найбільш значущим тощо. Бібліотека не потрібна, працює з будь-якою кількістю клавіш та будь-якою комбінацією висхідних та низхідних ключів.

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

Тепер ми готові зробити найважливіший ключ. Сорт стабільний, і будь-які зв'язки в найбільш значущому ключі вже вирішені.

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

Це може бути не найшвидшим, але це, звичайно, просто і надійно


4

Ще одна альтернатива використання rgrпакету:

> 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

Я боровся з вищезазначеними рішеннями, коли хотів автоматизувати процес замовлення для n стовпців, назви стовпців яких могли бути різними щоразу. Я знайшов надзвичайно корисну функцію з psychпакету, щоб це зробити просто:

dfOrder(myDf, columnIndices)

де columnIndices знаходяться індекси однієї чи кількох стовпців у тому порядку, в якому ви хочете їх сортувати. Більше інформації тут:

dfOrder функція з пакету 'psych'

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.