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

avatar
Christopher DuBois
18 августа 2009 в 21:33
1271243
19
1406

Я хочу отсортировать 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
Источник

Ответы (19)

avatar
Dirk Eddelbuettel
18 августа 2009 в 21:51
1718

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

Jota
27 марта 2012 в 03:17
0

@Dirk Eddelbuettel есть ли такой же простой метод для матриц?

Dirk Eddelbuettel
27 марта 2012 в 12:41
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"]),], чтобы упорядочить ее по двум столбцам.

hertzsprung
21 октября 2012 в 14:30
0

Как я могу адаптировать это к порядку по индексу столбца, а не по имени столбца?

Dirk Eddelbuettel
21 октября 2012 в 14:34
5

Достаточно просто: dd[ order(-dd[,4], dd[,1]), ], но нельзя использовать with для подмножества на основе имени.

Nailgun
22 января 2013 в 23:01
19

У меня возникла ошибка «недопустимый аргумент унарного оператора» при выполнении второго примера.

René Nyffenegger
30 июля 2014 в 12:13
0

Зачем нужен этот пустой параметр (, ])?

Dirk Eddelbuettel
30 июля 2014 в 12:39
0

Потому что вы хотите выбрать все столбцы двумерной структуры данных R.

HattrickNZ
30 июля 2014 в 22:11
0

почему dd[ order(-dd[,4],, ] недействителен или 'dd [order (-dd [, 4],]' в основном, почему требуется dd[,1]? недостаточно ли -dd[,4], если вы просто хотите отсортировать по 1 столбцу?

Richie Cotton
24 марта 2015 в 11:40
25

Ошибка «недопустимый аргумент унарного оператора» возникает при использовании минуса в символьном столбце. Решите ее, заключив столбец в xtfrm, например dd[ order(-xtfrm(dd[,4]), dd[,1]), ].

avatar
Dominic Comtois
11 апреля 2019 в 03:58
9

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

В этом случае на помощь приходит 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
##    (...)
avatar
Kaden Killpack
29 октября 2018 в 16:56
20

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

dd1 <- dd %>%
    arrange(z) %>%
    arrange(desc(x))
avatar
AHegde
24 октября 2018 в 22:32
5

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

dfOrder(myDf, columnIndices)

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

функция dfOrder из пакета Psy

avatar
Stéphane Laurent
1 мая 2018 в 10:18
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
avatar
info_seekeR
5 февраля 2016 в 21:11
22

В ответ на комментарий, добавленный в OP о программной сортировке:

Использование 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

Лучше использовать формулу, так как она также захватывает среду для оценки выражения в

таблица данных

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
avatar
Lars Kotthoff
7 августа 2015 в 04:03
7

Для полноты: вы также можете использовать функцию 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
MichaelChirico
30 марта 2016 в 14:58
4

странно добавлять сравнение производительности, когда ваш метод самый медленный ... в любом случае сомнительная ценность использования теста на 4-х строчном data.frame

avatar
Arun
29 марта 2015 в 15:52
90

Пакет R data.table предоставляет как fast , так и эффективную память упорядочивание data.tables с простым синтаксисом (часть которого выделена довольно красиво в его ответе). С тех пор было внесено много улучшений, а также появилась новая функция 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.table DT[order(...)] синтаксис был ~ 10x быстрее, чем самый быстрый из других методов (dplyr), при этом потреблял тот же объем памяти, что и dplyr.

    >
  • data.table setorder() был на ~ 14x быстрее, чем самый быстрый из других методов (dplyr), при этом занимал всего 0,455 ГБ дополнительной памяти <20049869 dat теперь находится в том порядке, который нам требуется (поскольку он обновляется по ссылке).

функции data.table:

Скорость :

  • data.table упорядочивает очень быстро, потому что он реализует radix ordering.

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

Память :

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

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

    Проблема в том, что для этого требуется как минимум вдвое (2x) объем памяти исходного объекта. Чтобы быть эффективной памятью , data.table , следовательно, также предоставляет функцию setorder().

    setorder() переупорядочивает таблицы данных 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).

Julien Navarre
30 июня 2015 в 14:32
0

Спасибо за очень поучительный ответ о data.table. Хотя я не понимаю, что такое «пиковая память» и как вы ее рассчитали. Не могли бы вы объяснить? Спасибо !

Arun
30 июня 2015 в 14:55
0

Я использовал Инструменты -> выделения и сообщил размер «Все кучи и выделенная виртуальная машина».

MichaelChirico
30 марта 2016 в 15:03
2

@Arun ссылка Инструменты в вашем комментарии мертва. Хотите опубликовать обновление?

n1k31t4
17 июля 2017 в 09:25
0

@MichaelChirico Вот ссылка на информацию об инструментах Apple: developer.apple.com/library/content/documentation/…

avatar
Rick
15 января 2015 в 04:28
7

Так же, как в давние времена механические сортировщики карт, сначала сортируются по наименее значимому ключу, затем по следующему наиболее значимому и т. Д. Библиотека не требуется, работает с любым количеством клавиш и любой комбинацией клавиш по возрастанию и убыванию.

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

Теперь мы готовы перейти к наиболее значимому ключу. Сортировка стабильна, и все связи в наиболее значимом ключе уже устранены.

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

Это может быть не самый быстрый, но, безусловно, простой и надежный

avatar
Ben
18 февраля 2014 в 21:29
137

Здесь много отличных ответов, но 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)

Для проблемы OP:

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
Saheel Godhane
22 февраля 2014 в 18:36
3

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

Matt Dowle
19 марта 2014 в 11:11
10

Почему «только»? Я считаю, что dd[order(-z, b)] data.table довольно прост в использовании и запоминании.

Ben
19 марта 2014 в 17:13
2

Согласны, между этими двумя методами не так много, и data.table также является огромным вкладом в R во многих других отношениях. Я полагаю, что для меня, возможно, наличие на один набор скобок меньше (или на один тип скобок меньше) в этом случае снижает когнитивную нагрузку на едва заметную величину.

Mullefa
29 мая 2015 в 13:12
7

Для меня это сводится к тому, что arrange() полностью декларативен, а dd[order(-z, b)] - нет.

avatar
Mark Miller
2 сентября 2013 в 19:28
21

Я узнал о 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),]

Я подумал, что это стоит опубликовать, учитывая, как долго меня смущал этот пример. Если этот пост не подходит для обсуждения, я могу его удалить.

РЕДАКТИРОВАТЬ: 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
Frank
2 сентября 2013 в 19:34
4

Этот синтаксис работает, если вы храните свои данные в data.table вместо data.frame: require(data.table); my.dt <- data.table(my.data); my.dt[order(age)] Это работает, потому что имена столбцов доступны внутри скобок [].

A5C1D2H2I1M1N2O1R2T1
14 февраля 2014 в 11:16
0

Я не думаю, что здесь необходимо отрицательное голосование, но я также не думаю, что это сильно влияет на вопрос , особенно с учетом существующего набора ответов, некоторые из которых уже отражают требование с помощью data.frame s использовать with или $.

AdamO
25 мая 2016 в 04:28
1

Голосование за do.call упрощает сортировку многоколоночного фрейма данных. Просто do.call(sort, mydf.obj) и получится красивая каскадная сортировка.

avatar
Matt Dowle
25 мая 2012 в 16:25
161

Ответ Дирка великолепен. Он также подчеркивает ключевое различие в синтаксисе, используемом для индексации data.frame s и data.table s:

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

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

Josh O'Brien
25 мая 2012 в 20:45
11

+1 Это отличный момент, и он раскрывает детали синтаксиса R, которые меня часто раздражали. Иногда я использую subset(), чтобы избежать многократных ссылок на один и тот же объект в рамках одного вызова.

Matt Dowle
26 ноября 2012 в 08:04
2

@ naught101 Отвечает ли на этот вопрос FAQ 1.9 по data.table?

David Arenburg
8 января 2015 в 19:18
7

Я думаю, вы могли бы добавить сюда новую функцию setorder, так как в этой ветке мы отправляем все дубликаты типа order.

avatar
Ari B. Friedman
29 июля 2011 в 10:48
524

Ваш выбор

  • 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?

Следовательно, учитывая dd 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 )

Если вы один из первых авторов этой функции, свяжитесь со мной. Обсуждение общественного достояния находится здесь: https://chat.coderhelper.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 из Кевина. Wright или пакет 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)

Среднее время: 1,567

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)

Не удалось загрузить 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))

microbenchmark plot

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


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

Ari B. Friedman
1 июня 2012 в 01:23
3

Вышеупомянутая функция микробенчмарка ggplot2 теперь доступна как taRifx::autoplot.microbenchmark.

naught101
30 июля 2012 в 05:04
0

@ AriB.Friedman Какие интервалы по оси Y / какой масштаб?

Ari B. Friedman
30 июля 2012 в 10:43
0

@ naught101 Ось y начинается с 0. Масштаб должен составлять микросекунды.

AME
12 октября 2013 в 06:37
0

@ AriB.Friedman, используя слово «аранжировать», как нам сортировать по возрастанию? Я никогда не видел, чтобы примеры отсортировывались по возрастанию. Я попробовал «asc» вместо «desc», но это не сработало. Благодарность

Ari B. Friedman
12 октября 2013 в 10:16
2

@AME посмотрите, как b сортируется в примере. По умолчанию используется сортировка по возрастанию, поэтому вы просто не помещаете его в desc. По возрастанию в обоих: arrange(dd,z,b). По убыванию в обоих: arrange(dd,desc(z),desc(b)).

landroni
10 марта 2014 в 16:31
2

Согласно ?arrange: «# ПРИМЕЧАНИЕ: функции plyr НЕ сохраняют имена строк». Это делает превосходную функцию arrange() субоптимальной, если кто-то хочет сохранить row.names.

Ari B. Friedman
2 июля 2015 в 11:00
0

Некоторые из них, которые используют order, могут быть немного быстрее, если вы вместо этого используете sort.list(x, method=“radix”).

Sebastian
9 января 2021 в 09:11
0

Быстрая и независимая от класса версия, которая имеет скорость data.table, но возвращает копию кадра данных, предоставляется функциями collapse roworder и roworderv. Его следует добавить к основным параметрам, поскольку он обеспечивает существенно более быструю альтернативу dplyr::arrange, но возвращает копию данных, в отличие от data.table::setorder, который изменяет данные на месте и может быть нежелательным. подробнее см. здесь.

avatar
Andrew
26 мая 2011 в 15:08
20

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

dd <- dd[with(dd, order(-z, b)), ] 
avatar
Khayelihle
25 января 2011 в 13:10
43

Предположим, у вас есть 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 по убыванию.

avatar
malecki
8 марта 2010 в 23:30
37

если SQL вам понятен, пакет sqldf обрабатывает ORDER BY так, как задумал Кодд.

Brandon Bertelsen
29 июля 2010 в 05:31
7

MJM, спасибо, что указали на этот пакет. Он невероятно гибкий, и поскольку половина моей работы уже сделана путем извлечения данных из баз данных sql, это проще, чем изучать большую часть менее чем интуитивного синтаксиса R.

avatar
George Dontas
19 января 2010 в 20:44
42

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

library(doBy)
dd <- orderBy(~-z+b, data=dd)
Daman deep
1 июля 2021 в 16:41
0

какова польза от ~ in orderBy (~ -z + b?

avatar
Ian Fellows
20 августа 2009 в 19:43
34

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

library(Deducer)
dd<- sortData(dd,c("z","b"),increasing= c(FALSE,TRUE))
avatar
Christopher DuBois
18 августа 2009 в 21:37
79

С этой (очень полезной) функцией Кевина Райта, опубликованной в разделе советов вики 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
Ari B. Friedman
12 июля 2012 в 14:07
2

См. Мой ответ по тестированию алгоритма, используемого в этой функции.