Как отсортировать фрейм данных по нескольким столбцам (столбцам)

Я хочу отсортировать 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
Комментарии к вопросу (1)
Решение

Вы можете использовать функцию 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() для более простого/прямого доступа).

Комментарии (10)

Ваш выбор

  • приказ от базы
  • договориться с dplyr
  • setorder и setorderv с данных.стол
  • договориться с plyr
  • вроде от taRifx
  • заказпо от тело
  • sortData от Deducer

Большую часть времени вы должны использовать dplyr или данных.таблица решений, если у вас нет зависимостей имеет большое значение, в этом случае основание использовать::заказ.


Недавно я добавил.данных.рамка для клюквенно пакет, что делает его совместимым класса, как описано здесь: https://stackoverflow.com/questions/6836963/best-way-to-create-generic-method-consistency-for-sort-data-frame

Поэтому, учитывая данные.рама ДД, можно сортировать следующим образом:


dd 
Комментарии (8)

Кортик'ы ответ велик. В нем также подчеркивается ключевая разница в синтаксис, используемый для индексирования данных`.рама и данных.таблицы:

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

Разница между двумя вызовами небольшой, но это может иметь важные последствия. Особенно если вы пишете код и/или связаны с правильностью в своих исследованиях, он'ы лучше, чтобы избежать ненужных повторение имен переменных. данные.стол` поможет вам сделать это.

Здесь'ы пример того, как повторение имен переменных может получить вас в беде:

Позвольте's поменять контекст от Dirk'ы ответ, и сказать, что это часть более крупного проекта, где есть много имен объектов и они длинные и содержательные; вместо " ч " это's посетило quarterlyreport. Она становится :

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

Ок, хорошо. Ничего плохого в этом нет. Следующий ваш босс просит вас включить в последнем квартале'ы в отчете. Вы идете через ваш код, добавление объекта `lastquarterlyreport в разных местах и как-то (как?) вы в конечном итоге с этим :

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

Что это'т то, что вы имели в виду но вы не'т это место потому что вы сделали это быстро, и это'ы, расположенный на странице подобный код. Код не'т упасть (без предупреждения и без ошибок), потому что Р думает, что именно это вы имели в виду. Вы'd надеюсь, что тот, кто читает ваш доклад замечает его, но, возможно, они не'т. Если вы работаете с языками программирования очень много, то эта ситуация может быть всем знакомы. Это было на "опечатка" Вы'Лл сказать. Я'МР исправить на "опечатка" Вы'будете говорить с вашим боссом.

В данных.Таблица мы'вновь обеспокоены крошечный такой детали. Так что мы'ве сделали что-то простое, чтобы не вводить дважды имена переменных. Что-то очень простое. " я "оценивается в рамках" ДД " уже автоматически. Вы Don'т необходимость `С () на всех.

Вместо

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

это's просто

dd[order(-z, b)]

И вместо того, чтобы

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

это's просто

quarterlyreport[order(-z,b)]

Это's очень маленькая разница, но это может быть просто спасти вашу шею один день. При взвешивании разных ответов на этот вопрос, считают подсчет повторений имен переменных в качестве одного из критериев при принятии решения. Некоторые ответы достаточно нескольких повторов, другие нет.

Комментарии (4)

Есть много хороших ответов здесь, но 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
Комментарии (4)

Данные пакет R.таблица обеспечивает как быстро и эффективная память заказ данных.столы простой синтаксис (часть из которых Мэтт подчеркнуто достаточно хорошо в ответ). Там было довольно много улучшений, а также новые функции setorder()с тех пор. От В1.9.5+, `setorder () также работает с данных.кадров.

Во-первых, мы'Лл создать набор данных достаточно большой и сопоставлять различные методы, упомянутые из других ответов, а затем перечислите особенности сведения.стол.

Данные###:

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)

Показателей:

Время в заявление от работающей системы`.время (...) на эти функции показаны ниже. Тайминги приведены в таблице ниже (при заказе от минимальных до максимальных).

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
# ------------------------------------------------------------
  • данных.стол&#39;ыДТ[порядок(...)]синтаксис был **~10х** быстрее, чем самый быстрый из других методов (dplyr), при этом потребляя такое же количество памяти какdplyr`.

  • данных.стол&#39;ыsetorder()был **~14х** быстрее, чем самый быстрый из других методов (dplyr), а с **всего 0,4 ГБ дополнительной памяти**.дат` теперь в порядке, мы требуем (как он обновляется по ссылке).

данные###.особенности таблицы:

Скорость:

  • данные.таблица'сек заказ очень быстро, потому что он реализует заказ радикса.

  • ДТ синтаксис [порядок(...)] оптимизирован внутренне в использовании сведения.таблица'ы быстрый заказ, а также. Вы можете продолжать использовать привычные базовый синтаксис R, но ускорить процесс (и использовать меньше памяти).

Память:

  • В большинстве случаев, мы не'т требуют оригинал сведения.рама или данных.таблица после перенумерации. То есть, мы, как правило, присвоить результат обратно в один и тот же объект, например:

ДФ <- ДФ[порядок(...)]

Вопрос в том, что для этого требуется как минимум в два раза (2х) память исходного объекта. Чтобы быть эффективной памяти, данных.таблица* поэтому также предоставляет функции setorder()`.

setorder() переупорядочивает сведения.таблицы ссылка (в), без внесения каких-либо дополнительных копий. Он использует только дополнительную память, равную размеру одного столбца.

Другие особенности:

  1. Он поддерживает целое, логическое, цифровой, символ и даже bit64::типы integer64.

обратите внимание, что фактор, дата, POSIXct и т. д.. класс целое число/числовой типа под дополнительными атрибутами и, таким образом, поддерживает также.

  1. В базовом R, мы не можем использовать - на векторный характер для сортировки по этому столбцу в порядке убывания. Вместо этого мы должны использовать -xtfrm(.).

Однако, в данных.таблица мы можем просто сделать, например, дат[порядок(-х)] или setorder(дат, -х).

Комментарии (4)

С помощью этой (очень полезной) функции Кевина Райта, опубликованной в разделе советов в R wiki, этого легко добиться.

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
Комментарии (1)

или вы можете использовать пакет доби


library(doBy)
dd 
Комментарии (0)

Предположим, у вас есть данные.рамка A и вы хотите отсортировать их, используя столбец под названием " Х " в порядке убывания. Вызов данных, отсортированных.рамка newdata


newdata 
Комментарии (0)

если SQL естественно для вас, - sqldf пакет ручки порядок как Кодди предназначены.

Комментарии (1)

В качестве альтернативы, используя пакет Deducer


library(Deducer)
dd
Комментарии (0)

Я узнал о "заказе" со следующим примером, который потом смутило меня в течение длительного времени:

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

Единственная причина, этот пример работает, потому что "порядок" - это сортировка по `вектор возрасту, а не по графе "возраст" в данных кадра данных.

Чтобы увидеть это создание одинаковых фрейма данных, используя прочитанное.стол с немного разными названиями колонок и без использования любой из вышеперечисленных векторов:


my.data 
Комментарии (3)

Дирк'ы ответ хороший, но если вам нужен такой, чтобы сохраняться вы'll хочу применить все на имени фрейма данных. Используя пример кода:


dd 
Комментарии (0)

В ответ на замечание, добавил в ОП для сортировки программно:

С помощью dplyrиданных.стол`

library(dplyr)
library(data.table)

dplyr # Просто используйте arrange_, который в стандартной версии оценки для организовать.


df1 
Комментарии (0)

Упорядочить() в dplyer-мой любимый вариант. Использовать оператор трубы и перейти от наименее важных к наиболее важным аспектом

dd1 %
    arrange(z) %>%
    arrange(desc(x))
Комментарии (0)

Для полноты картины: вы также можете использовать функцию 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
Комментарии (1)

Просто как механические сортировщики карту давно, сначала вроде как наименее важные, затем следующий наиболее значимый и т. д. Не требуется библиотека, работает с любым количеством ключей и любое сочетание восходящих и нисходящих ключей.


 dd 
Комментарии (0)

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

В этом случае делать.звоните()` приходит на помощь:


ind 
Комментарии (0)

Другая альтернатива, с помощью РГР пакет:

> 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
Комментарии (0)

Я боролся с одним из описанных выше способов, когда я хотел автоматизировать процесс заказа для n столбцов, столбец, чьи имена могут быть разными каждый раз. Я нашла супер полезная функция из психушки пакет для этого простым способом:

dfOrder(myDf, columnIndices)

где columnIndices являются показатели одного или нескольких столбцов, в том порядке, в котором вы хотите отсортировать их. Более подробная информация здесь:

функция dfOrder от 'псих' пакет

Комментарии (0)