Я хочу отсортировать 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
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"]),]
для упорядочения по двум столбцам.dd[ order(-dd[,4], dd[,1]), ]
но не может использоватьсяwith
для подмножеств на основе имен.xtfrm
, напримерdd[ order(-xtfrm(dd[,4]), dd[,1]), ]
.Ваш выбор
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?
Поэтому, учитывая data.frame dd, вы можете сортировать следующим образом:
Если вы являетесь одним из авторов этой функции, свяжитесь со мной. Дискуссия в отношении общедоступности является здесь: http://chat.stackoverflow.com/transcript/message/1094290#1094290
Вы также можете использовать
arrange()
функцию,plyr
указанную Хэдли в приведенной выше теме:Тесты: обратите внимание, что я загрузил каждый пакет в новом сеансе R, поскольку было много конфликтов. В частности, загрузка пакета doBy приводит
sort
к возврату «Следующие объекты маскируются из« x (позиция 17) »: b, x, y, z», а загрузка пакета Deducer перезаписываетсяsort.data.frame
из пакета Кевина Райта или пакета taRifx.Среднее время:
dd[with(dd, order(-z, b)), ]
+778dd[order(-dd$z, dd$b),]
+788Среднее время: 1,567
Среднее время: 862
Среднее время: 1694
Обратите внимание, что doBy требует много времени для загрузки пакета.
Не удалось заставить дедуцера загрузиться. Требуется консоль JGR.
Кажется, не совместим с микробенчмарком из-за прикрепления / отсоединения.
(линии простираются от нижнего квартиля до верхнего квартиля, точка - медиана)
Учитывая эти результаты и простоту взвешивания в зависимости от скорости, я должен был бы дать согласие
arrange
наplyr
пакет . Он имеет простой синтаксис и, тем не менее, почти такой же быстрый, как команды base R, с их запутанными махинациями. Типично блестящая работа Хэдли Уикхем. Моя единственная неприятность в том, что она нарушает стандартную номенклатуру R, в которой вызывается сортировка объектовsort(object)
, но я понимаю, почему Хэдли так поступила из-за проблем, обсуждаемых в вопросе, связанном выше.источник
taRifx::autoplot.microbenchmark
.b
отсортировано в образце. По умолчанию используется сортировка по возрастанию, поэтому вы просто не включаете ееdesc
. По возрастанию в обоихarrange(dd,z,b)
. По убыванию в обоихarrange(dd,desc(z),desc(b))
.?arrange
: «# ПРИМЕЧАНИЕ: функции plyr НЕ сохраняют row.names». Это делает превосходнуюarrange()
функцию неоптимальной, если кто-то хочет ее сохранитьrow.names
.Ответ Дирка великолепен. Это также подчеркивает ключевое различие в синтаксисе, используемом для индексации
data.frame
s иdata.table
s:Разница между двумя вызовами невелика, но она может иметь важные последствия. Особенно, если вы пишете производственный код и / или обеспокоены правильностью своих исследований, лучше избегать ненужного повторения имен переменных.
data.table
поможет вам сделать это.Вот пример того, как повторение имен переменных может привести к неприятностям:
Давайте изменим контекст из ответа Дирка и скажем, что это часть более крупного проекта, в котором много имен объектов, и они длинные и значимые; вместо того, чтобы
dd
это называетсяquarterlyreport
. Это становится :Хорошо. В этом нет ничего плохого. Затем ваш начальник просит вас включить отчет за последний квартал в отчет. Вы просматриваете свой код, добавляете объект
lastquarterlyreport
в различные места и каким-то образом (как на земле?) Вы в конечном итоге получаете следующее:Это не то, что вы имели в виду, но вы не заметили это, потому что вы сделали это быстро, и он расположен на странице с похожим кодом. Код не падает (без предупреждения и без ошибок), потому что R думает, что это то, что вы имели в виду. Вы бы надеялись, что тот, кто прочитает ваш отчет, заметит его, но, возможно, нет. Если вы много работаете с языками программирования, то эта ситуация может быть всем знакома. Это была опечатка, которую вы скажете. Я исправлю "опечатку", которую вы скажете своему боссу.
В
data.table
нас беспокоят мелкие детали, подобные этому. Итак, мы сделали что-то простое, чтобы не вводить имена переменных дважды. Нечто очень простое.i
оценивается в рамкахdd
уже, автоматически. Вам не нужноwith()
вообще.Вместо
это просто
И вместо
это просто
Это очень маленькая разница, но она может спасти вашу шею однажды. При взвешивании различных ответов на этот вопрос рассмотрите возможность считать повторения имен переменных одним из ваших критериев при принятии решения. Некоторые ответы имеют много повторений, другие нет.
источник
subset()
только для того, чтобы не повторять ссылки на один и тот же объект в течение одного вызова.setorder
функцию здесь, так как в этом потоке мы отправляем всеorder
типы dupes.Здесь есть много отличных ответов, но dplyr дает единственный синтаксис, который я могу быстро и легко запомнить (и теперь использую очень часто):
Для проблемы ОП:
источник
dd[order(-z, b)]
довольно прост в использовании и запоминается.data.table
это огромный вкладR
. Я полагаю, что для меня это может быть то, что в этом случае наличие одного меньшего набора скобок (или одного меньшего типа скобок) уменьшает когнитивную нагрузку лишь на едва заметную величину.arrange()
полностью декларативно,dd[order(-z, b)]
нет.Пакет R
data.table
обеспечивает быстрое и эффективное использование памяти в data.tables с простым синтаксисом (часть которого Мэтт очень хорошо подчеркнул в своем ответе ). С тех пор было довольно много улучшений и новой функцииsetorder()
. Сv1.9.5+
,setorder()
также работает с data.frames .Сначала мы создадим достаточно большой набор данных и проведем сравнение различных методов, упомянутых в других ответах, а затем перечислим функции data.table .
Данные:
тесты:
Сообщается, что время выполнения
system.time(...)
этих функций показано ниже. Время приведено в таблице ниже (в порядке от самого медленного до самого быстрого).data.table
«sDT[order(...)]
синтаксис был ~ 10 раз быстрее , чем самый быстрый из других методов (dplyr
), потребляя при этом один и тот же объем памяти , какdplyr
.data.table
Этоsetorder()
было в ~ 14 раз быстрее, чем самый быстрый из других методов (dplyr
), при этом потребовалось всего 0,4 ГБ дополнительной памяти .dat
теперь в том порядке, в котором мы нуждаемся (так как он обновляется по ссылке).Возможности data.table:
Скорость:
Порядок в data.table очень быстрый, потому что он реализует радикальное упорядочение .
Синтаксис
DT[order(...)]
внутренне оптимизирован для использования быстрого порядка в data.table . Вы можете продолжать использовать знакомый синтаксис base R, но ускорить процесс (и использовать меньше памяти).Память:
В большинстве случаев нам не требуется оригинальный data.frame или data.table после переупорядочения. То есть мы обычно присваиваем результат тому же объекту, например:
Проблема в том, что для этого требуется как минимум вдвое (в 2 раза) объем памяти исходного объекта. Для того, чтобы эффективно использовать память , data.table также предоставляет функцию
setorder()
.setorder()
переупорядочивает data.tablesby reference
( на месте ), не делая дополнительных копий. Используется только дополнительная память, равная размеру одного столбца.Другие особенности:
Он поддерживает
integer
,logical
,numeric
,character
и дажеbit64::integer64
тип.В базе R мы не можем использовать
-
вектор символов для сортировки по этому столбцу в порядке убывания. Вместо этого мы должны использовать-xtfrm(.)
.Однако в data.table мы можем просто сделать, например,
dat[order(-x)]
илиsetorder(dat, -x)
.источник
С помощью этой (очень полезной) функции Кевина Райта , опубликованной в разделе советов R-wiki, это легко достигается.
источник
или вы можете использовать пакет doBy
источник
Предположим, у вас есть
data.frame
A
и вы хотите отсортировать его, используя столбец, называемый поx
убыванию. Позвоните отсортированоdata.frame
newdata
Если вы хотите восходящий порядок, то замените его
"-"
ничем. Вы можете иметь что-то вродегде
x
иz
некоторые столбцы вdata.frame
A
. Это означает сортировкуdata.frame
A
поx
убыванию,y
возрастанию иz
убыванию.источник
если SQL вам подходит,
sqldf
пакет обрабатывает так,ORDER BY
как задумал Codd.источник
Как вариант, используя пакет Deducer
источник
В ответ на комментарий, добавленный в OP для того, как сортировать программно:
Использование
dplyr
иdata.table
dplyr
Просто используйте
arrange_
, которая является стандартной оценочной версией дляarrange
.больше информации здесь: https://cran.r-project.org/web/packages/dplyr/vignettes/nse.html
Лучше использовать формулу, поскольку она также захватывает среду для оценки выражения в
Таблица данных
источник
Я узнал о
order
следующем примере, который долго меня смущал:Единственная причина, по которой работает этот пример, заключается в том, что
order
сортировка выполняетсяvector Age
по столбцу, указанномуAge
вdata frame data
.Чтобы увидеть это, создайте идентичный фрейм данных, используя
read.table
несколько разные имена столбцов и не используя ни один из перечисленных выше векторов:Вышеуказанная структура линии
order
больше не работает, потому что нет вектора с именемage
:Следующая строка работает, потому что
order
сортирует по столбцуage
вmy.data
.Я думал, что это стоит опубликовать, учитывая, насколько я был смущен этим примером так долго. Если это сообщение не считается подходящим для темы, я могу удалить его.
РЕДАКТИРОВАТЬ: 13 мая 2014 г.
Ниже приведен обобщенный способ сортировки фрейма данных по каждому столбцу без указания имен столбцов. Код ниже показывает, как сортировать слева направо или справа налево. Это работает, если каждый столбец числовой. Я не пробовал с добавлением столбца символов.
Я нашел
do.call
код месяц или два назад в старом посте на другом сайте, но только после тщательного и сложного поиска. Я не уверен, что мог бы переместить этот пост сейчас. Настоящий поток является первым хитом для заказаdata.frame
вR
. Итак, я подумал, что моя расширенная версия этого исходногоdo.call
кода может быть полезна.источник
require(data.table); my.dt <- data.table(my.data); my.dt[order(age)]
работает, потому что имена столбцов доступны в скобках [].data.frame
с либо использованияwith
или$
.do.call
этого делает короткую работу по сортировке многоколоночного фрейма данных. Простоdo.call(sort, mydf.obj)
и красивый каскадный вид будет иметься.Ответ Дирка хорош, но если вам нужно, чтобы сортировка сохранялась, вы захотите применить сортировку обратно к имени этого фрейма данных. Используя пример кода:
источник
Аранжировка () в dplyer - мой любимый вариант. Используйте оператора трубы и переходите от наименее важного к наиболее важному аспекту
источник
Просто для полноты, поскольку о сортировке по номерам столбцов сказано немногое ... Можно, конечно, утверждать, что это часто нежелательно (поскольку порядок столбцов может измениться, что ведет к ошибкам), но в некоторых конкретных ситуациях (например, когда вам нужно выполнить быструю работу и нет риска изменить порядок столбцов), это может быть наиболее разумно, особенно при работе с большим количеством столбцов.
В таком случае
do.call()
на помощь приходит:источник
Ради полноты: вы также можете использовать
sortByCol()
функцию изBBmisc
пакета:Сравнение производительности:
источник
data.frame
Точно так же, как механические сортировщики карт давным-давно, сначала сортируют по наименее значимому ключу, затем по следующему наиболее значимому и т. Д. Библиотека не требуется, работает с любым количеством клавиш и любой комбинацией восходящих и нисходящих клавиш.
Теперь мы готовы сделать самый важный ключ. Сортировка стабильна, и любые связи в наиболее значимом ключе уже разрешены.
Это может быть не самым быстрым, но это, безусловно, просто и надежно
источник
Еще одна альтернатива, используя
rgr
пакет:источник
Я боролся с вышеуказанными решениями, когда хотел автоматизировать процесс заказа для n столбцов, имена столбцов которых могли каждый раз отличаться. Я нашел супер полезную функцию из
psych
пакета, чтобы сделать это простым способом:где
columnIndices
указатели одного или нескольких столбцов, в том порядке, в котором вы хотите их отсортировать. Больше информации здесь:Функция dfOrder из пакета 'psych'
источник