Я хочу отсортировать 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
Вы можете использовать функцию 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()
для более простого/прямого доступа).
приказ
от базы
договориться
с 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 <- 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 )
Если вы являетесь одним из авторов этой функции, пожалуйста, свяжитесь со мной. Дискуссия по вопросу публичных domaininess-это здесь: http://chat.stackoverflow.com/transcript/message/1094290#1094290
Вы также можете использовать упорядочить()
функции plyr
как Хэдли указывал выше резьбы:
library(plyr)
arrange(dd,desc(z),b)
Ориентиры: обратите внимание, что я загрузил каждого пакета в новый сеанс Р, так как было много конфликтов. В частности, погрузка доби пакет вызывает "сортировка", чтобы вернуться "В следующих объекта(ов) скрыты от 'х (позиция 17)': б, х, у, Z", и нагрузка на Deducer пакет перезаписывает сортировки.данных.рамка с Кевин Райт или пакет 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
)
Медиана времени:
ДД[с(ДД, порядок(-з, б)), ]
778
ДД[порядка (ДД$з, ДД долларов США),]
788
library(taRifx)
microbenchmark(sort(dd, f= ~-z+b ),times=1000)
Медиана времени: 1,567
library(plyr)
microbenchmark(arrange(dd,desc(z),b),times=1000)
Медиана времени: 862
library(doBy)
microbenchmark(orderBy(~-z+b, data=dd),times=1000)
Медиана времени: 1,694
Обратите внимание, что доби занимает довольно много времени, чтобы загрузить пакет.
library(Deducer)
microbenchmark(sortData(dd,c("z","b"),increasing= c(FALSE,TRUE)),times=1000)
Не мог'т принять нагрузку Deducer. Нужна консоль руководство 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))
(линии простираются от Нижний квартиль верхний квартиль, точка медиана)
Учитывая эти результаты и взвешивания простота и скорость, я'd должны дать добро на упорядочить
в plyr пакет. Он имеет простой синтаксис и еще почти так же быстро, как база команды R с их запутанные махинации. Как правило, блестящая работа Хэдли Уикхэм. Моя единственная претензия к нему заключается в том, что он нарушает стандартный номенклатуре R, где объекты сортировки вам называют `рода(объект), но я понимаю, почему Хэдли сделал это таким образом, благодаря обсудили вопрос связан вышеперечисленные вопросы.
Кортик'ы ответ велик. В нем также подчеркивается ключевая разница в синтаксис, используемый для индексирования данных`.рама и данных.таблицы:
## 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 очень маленькая разница, но это может быть просто спасти вашу шею один день. При взвешивании разных ответов на этот вопрос, считают подсчет повторений имен переменных в качестве одного из критериев при принятии решения. Некоторые ответы достаточно нескольких повторов, другие нет.
Есть много хороших ответов здесь, но 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
Данные пакет 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
# ------------------------------------------------------------
данных.стол'ы
ДТ[порядок(...)]синтаксис был **~10х** быстрее, чем самый быстрый из других методов (
dplyr), при этом потребляя такое же количество памяти как
dplyr`.
данных.стол'ы
setorder()был **~14х** быстрее, чем самый быстрый из других методов (
dplyr), а с **всего 0,4 ГБ дополнительной памяти**.
дат` теперь в порядке, мы требуем (как он обновляется по ссылке).
данные###.особенности таблицы:
Скорость:
данные.таблица'сек заказ очень быстро, потому что он реализует заказ радикса.
ДТ синтаксис [порядок(...)]
оптимизирован внутренне в использовании сведения.таблица'ы быстрый заказ, а также. Вы можете продолжать использовать привычные базовый синтаксис R, но ускорить процесс (и использовать меньше памяти).
Память:
ДФ <- ДФ[порядок(...)]
Вопрос в том, что для этого требуется как минимум в два раза (2х) память исходного объекта. Чтобы быть эффективной памяти, данных.таблица* поэтому также предоставляет функции setorder()`.
setorder()
переупорядочивает сведения.таблицы ссылка
(в), без внесения каких-либо дополнительных копий. Он использует только дополнительную память, равную размеру одного столбца.
Другие особенности:
целое
, логическое
, цифровой
, символ
и даже bit64::типы integer64
.обратите внимание, что
фактор
,дата
,POSIXct
и т. д.. классцелое число
/числовой
типа под дополнительными атрибутами и, таким образом, поддерживает также.
-
на векторный характер для сортировки по этому столбцу в порядке убывания. Вместо этого мы должны использовать -xtfrm(.)
. Однако, в данных.таблица мы можем просто сделать, например, дат[порядок(-х)]
или setorder(дат, -х)
.
С помощью этой (очень полезной) функции Кевина Райта, опубликованной в разделе советов в 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
или вы можете использовать пакет доби
library(doBy)
dd <- orderBy(~-z+b, data=dd)
Предположим, у вас есть данные.рамка
A
и вы хотите отсортировать их, используя столбец под названием " Х " в порядке убывания. Вызов данных, отсортированных.рамка
newdata
newdata <- A[order(-A$x),]
Если вы хотите возрастанию, затем заменить в "-" у
разбитого корыта. Вы можете иметь что-то вроде
newdata <- A[order(-A$x, A$y, -A$z),]
где X
и Z
несколько столбцов данных.рамка`а
. Это означает, что данные сортировка.рамка`a
по по убыванию х
, у
восходящие и Z
по убыванию.
если SQL естественно для вас, - sqldf пакет ручки порядок
как Кодди предназначены.
В качестве альтернативы, используя пакет Deducer
library(Deducer)
dd<- sortData(dd,c("z","b"),increasing= c(FALSE,TRUE))
Я узнал о "заказе" со следующим примером, который потом смутило меня в течение длительного времени:
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 <- 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)
Вышеуказанные структуры линии на "порядок" больше не работает, потому что нет вектора назвали "возраст":
databyage = my.data[order(age),]
Следующая строка работает, потому что "порядок" сортировка по столбцу "возраст" в моем.данных`.
databyage = my.data[order(my.data$age),]
Я думал, что это стоило проводки учитывая, как запутался я на этом примере так долго. Если этот пост не считаются подходящими для резьбы я могу удалить его.
Редактировать: 13 мая 2014 года,
Ниже приведен обобщенный способ сортировки блоков данных каждого столбца без указания имен столбцов. В приведенном ниже коде показано, как сортировать слева направо или справа налево. Это работает, если каждый столбец является числовым. Я не пробовал с колонкой персонаж добавил.
Я нашел делать.называете код месяц или два назад в старый пост на другом сайте, но только после длительных и трудных поисков. Я не уверен, я мог теперь перевести этот пост. Настоящий поток-это первый хит для заказа данных.рамка
в р
. Так, я думал, что моя Расширенная версия, что первоначально делать.код вызова может быть полезна.
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
В ответ на замечание, добавил в ОП для сортировки программно:
С помощью dplyrи
данных.стол`
library(dplyr)
library(data.table)
dplyr #
Просто используйте 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
Лучше использовать формулу, так как он также отражает окружающую среду, чтобы оценить выражение в
данные#.таблица
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
Упорядочить() в dplyer-мой любимый вариант. Использовать оператор трубы и перейти от наименее важных к наиболее важным аспектом
dd1 <- dd %>%
arrange(z) %>%
arrange(desc(x))
Для полноты картины: вы также можете использовать функцию 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
Просто как механические сортировщики карту давно, сначала вроде как наименее важные, затем следующий наиболее значимый и т. д. Не требуется библиотека, работает с любым количеством ключей и любое сочетание восходящих и нисходящих ключей.
dd <- dd[order(dd$b, decreasing = FALSE),]
Теперь мы'вновь готовы сделать самые важные. Сорт стабильный, и никаких связей в наиболее значимых ключ уже решены.
dd <- dd[order(dd$z, decreasing = TRUE),]
Это может быть не самый быстрый, но это, конечно, простой и надежный
Просто для полноты картины, поскольку не так много было сказано о сортировке по столбцу цифр... это можно с уверенностью утверждать, что это часто не желательно (потому что порядок столбцов может меняться, прокладывая путь к ошибкам), но в некоторых конкретных ситуациях (когда, например, вам нужно быстро и нет такого риска столбцов, изменение ордеров), это может быть наиболее разумная вещь, чтобы сделать, особенно когда имеешь дело с большим количеством столбцов.
В этом случае делать.звоните()` приходит на помощь:
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
## (...)
Другая альтернатива, с помощью РГР пакет:
> 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
Я боролся с одним из описанных выше способов, когда я хотел автоматизировать процесс заказа для n столбцов, столбец, чьи имена могут быть разными каждый раз. Я нашла супер полезная функция из психушки
пакет для этого простым способом:
dfOrder(myDf, columnIndices)
где columnIndices являются показатели одного или нескольких столбцов, в том порядке, в котором вы хотите отсортировать их. Более подробная информация здесь: