Vreau să am un fel de date.cadru cu mai multe coloane. De exemplu, cu datele.cadru de mai jos aș dori să sortați după coloana " z "(descrescătoare), atunci de coloana " b " (crescator):
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
Puteți utiliza [pentru()
](http://stat.ethz.ch/R-manual/R-devel/library/base/html/order.html funcția) direct, fără a recurge la add-on tools -- vezi acest simplu răspuns, care folosește un truc de sus de exemplu(comanda) codul:
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
Editare de 2+ de ani mai târziu: A fost întrebat cum de a face acest lucru prin coloana index. Răspunsul este de a trece pur și simplu de sortare dorit coloana(s) la comanda()
funcția:
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>
mai degrabă decât folosind numele coloanei (și cu()
pentru a fi mai ușor/mai mult acces direct).
aranja
de dplyr`setorder " și " setorderv
de date.masa`aranja
de plyr`fel
de taRifx`doBy
sortData "de la" Deducer
Cele mai multe din timp, ar trebui să utilizați dplyr " sau " date.tabelul soluții, dacă nu au nici-dependențe este important, în cazul în care utilizarea de bază::comanda
.
Recent am adăugat un fel.date.cadru pentru un CRAN pachet, ceea ce face clasa compatibil cum s-a discutat aici: https://stackoverflow.com/questions/6836963/best-way-to-create-generic-method-consistency-for-sort-data-frame
Prin urmare, având în vedere datele.cadru dd, puteți sorta după cum urmează:
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 )
Dacă sunteți unul dintre primii autori de această funcție, vă rugăm să contactați-mă. Dezbaterea publică domaininess este aici: http://chat.stackoverflow.com/transcript/message/1094290#1094290
Puteți folosi, de asemenea, aranja()
funcția de plyr` ca Hadley a subliniat în firul de mai sus:
library(plyr)
arrange(dd,desc(z),b)
Obiective de referință: să Rețineți că am încărcat fiecare ambalaj într-un nou R sesiune de acolo au fost o mulțime de conflicte. În special încărcarea doBy pachet cauze fel
de a reveni "următorul obiect(e) sunt mascate de 'x (poziția 17)': b, x, y, z", și de încărcare de Deducer pachet suprascrie `un fel.date.cadru de Kevin Wright sau taRifx pachet.
#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
)
Intervalul Median de timp:
dd[cu(dd, pentru(-z, b)), ]
778
dd[pentru(-dd$z, zz$b),]
788
library(taRifx)
microbenchmark(sort(dd, f= ~-z+b ),times=1000)
Timpul Median: 1,567
library(plyr)
microbenchmark(arrange(dd,desc(z),b),times=1000)
Timpul Median: 862
library(doBy)
microbenchmark(orderBy(~-z+b, data=dd),times=1000)
Timpul Median: 1,694
Rețineți că doBy nevoie de un pic de timp pentru a încărca pachetul.
library(Deducer)
microbenchmark(sortData(dd,c("z","b"),increasing= c(FALSE,TRUE)),times=1000)
N't face Deducer sarcină. Are nevoie de JGR consola.
esort <- function(x, sortvar, ...) {
attach(x)
x <- x[with(x,order(sortvar,...)),]
return(x)
detach(x)
}
microbenchmark(esort(dd, -z, b),times=1000)
Nu't par a fi compatibile cu microbenchmark ca urmare a atașa/detașa.
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))
(linii prelungi de la quartila inferioară a quartila superioară, dot este mediana)
Având în vedere aceste rezultate și o greutate de simplitate vs viteza, am'd trebuie să dau din cap a a aranja
în `plyr pachetului. Acesta are o sintaxă simplă și totuși este aproape la fel de rapidă ca bază R comenzile lor complicate mașinațiunile. De obicei genial Hadley Wickham muncă. Singura mea nemulțumire este că se rupe standard R nomenclatura în cazul în care sortarea obiectelor chemat de genu `(obiect), dar am înțeles de ce Hadley a făcut-o așa din cauza problemelor discutate în întrebare legate de mai sus.
Dirk's răspunsul este mare. Acesta subliniază, de asemenea, o diferență cheie în sintaxa folosit pentru indexarea datelor.cadru și de date.masa:
## 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)]
Diferența între cele două apeluri este mic, dar poate avea consecințe importante. Mai ales dacă ai scrie codul de producție și/sau sunt în cauză cu corectitudinea în cercetare, l's cel mai bun pentru a evita repetarea inutilă a nume de variabile. date.masa
te ajută să faci acest lucru.
Aici's un exemplu de cum repetarea unor nume de variabile-ar face probleme:
Las's schimba contextul de Dirk's a răspunde, și spun acest lucru este parte a unui proiect mai mare în cazul în care există o mulțime de nume de obiecte și acestea sunt de lungă și semnificativă; în loc de dd
- l's a numit quarterlyreport
. Devine :
quarterlyreport[with(quarterlyreport,order(-z,b)),]
Ok, bine. Nimic în neregulă cu asta. Următoarea seful tau iti cere sa includ ultimul trimestru's raport în raport. Du-te prin cod, adăugând un obiect `lastquarterlyreport în diverse locuri și într-un fel (cum naiba?) ajungi cu asta :
quarterlyreport[with(lastquarterlyreport,order(-z,b)),]
Asta e't ceea ce ai vrut dar ai n't la fața locului pentru că ai făcut-o rapid și it's, situat pe o pagină de cod similar. Codul nu't cădea peste (fără avertisment și fără eroare) deoarece R crede că este ceea ce ai vrut să spui. Te'd sper oricine citește raportul pete, dar poate ei nu't. Dacă lucrați cu limbaje de programare o mulțime, atunci această situație poate fi toate familiare. A fost o "typo" te'll spune. Am'll fix "typo" te'll-i spui șefului tău.
În de date.tabelul
ne-am're preocupat de mici detalii, cum ar fi acest lucru. Așa că ne-am'am facut ceva simplu, pentru a evita tastarea nume de variabile de două ori. Ceva foarte simplu. " eu " este evaluată în cadrul dd
deja, în mod automat. Nu't nevoie cu()
la toate.
În loc de
dd[with(dd, order(-z, b)), ]
l's doar
dd[order(-z, b)]
Și în loc de
quarterlyreport[with(lastquarterlyreport,order(-z,b)),]
l's doar
quarterlyreport[order(-z,b)]
L's o diferență foarte mică, dar ar putea salva gâtul într-o zi. Atunci când o greutate de până la răspunsuri diferite la această întrebare, ia în considerare de numărare repetari de nume de variabile, ca unul din criterii în luarea deciziei. Unele răspunsuri au destul de multe se repetă, altele nu au niciuna.
Există o mulțime de raspunsuri excelente aici, dar dplyr oferă doar sintaxa că pot aminti rapid și ușor (și deci, acum folosesc foarte des):
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)
Pentru OP's problema:
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 pachetului de date.tabelul oferă atât rapid și memorie eficientă ordonarea date.tabele cu o simplă sintaxă (din care o parte Matt a subliniat destul de bine în răspunsul său). Acolo a fost destul de o mulțime de îmbunătățiri și, de asemenea, o nouă funcție setorder()
de atunci. Din v1.9.5+,
setorder ()`, de asemenea, funcționează cu date.rame.
În primul rând, ne-am'll de a crea un set de date suficient de mare și de referință diferite metode menționate de alte răspunsuri și apoi lista de caracteristici de date.tabelul.
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)
Timpii sunt raportate de funcționare a sistemului.timp (...) pe aceste funcții se arată mai jos. Timpii sunt tabelate mai jos (în ordinea de mai încet la rapid).
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
# ------------------------------------------------------------
date.masa's
DT[pentru(...)]sintaxa fost **~10x** mai repede decât cel mai rapid de alte metode (
dplyr), în timp ce consuma aceeasi cantitate de memorie ca
dplyr`.
date.masa's
setorder()s **~14x** mai repede decât cel mai rapid de alte metode (
dplyr), în timp ce lua **doar 0, 4 GB de memorie suplimentar**.
dat` este acum în ordinea în care avem nevoie (cum este actualizat de referință).
Viteză:
date.tabelul's de comanda este extrem de rapid pentru a pune în aplicare radix comanda.
Sintaxa DT[pentru(...)]
este optimizat pe plan intern pentru a utiliza date.tabelul's comanda rapid la fel de bine. Puteți să vă păstrați folosind familiar de bază R, dar sintaxa accelera procesul (și de a folosi mai puțină memorie).
Memorie:
DF <- DF[pentru(...)]
Problema este că acest lucru necesită cel puțin de două ori (2x) pe de memorie a obiectului original. Pentru a fi eficient memoria, date.tabelul*, prin urmare, oferă, de asemenea, o funcție setorder()
.
setorder()
reordona date.tabele de referinta
(în loc de), fără a face copii suplimentare. Folosește memorie suplimentară egală cu dimensiunea de o coloană.
Alte caracteristici:
integer
, logic
, numeric
, caracter
și chiar bit64::integer64
tipuri.Rețineți că
factor
,Data
,POSIXct
etc.. clase sunt toate "întreg" /numeric
tipuri de dedesubt cu atribute suplimentare și, prin urmare, sunt suportate la fel de bine.
-xtfrm(.)
. Cu toate acestea, în date.tabelul, putem face, de exemplu, dat[pentru(-x)] " sau " setorder(dat, -x)
.
Cu asta (foarte util) funcția de Kevin Wright, postate în secțiunea sfaturi de R wiki, acest lucru este ușor de realizat.
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
Să presupunem că aveți o date.cadru
" a "și vrei să-l rezolve, folosind coloană numită" x " ordine descrescătoare. Suna la sortat de date.cadru`newdata
newdata <- A[order(-A$x),]
Dacă doriți ordine crescătoare, apoi înlocuiți - `"-" cu nimic. Poti avea ceva de genul
newdata <- A[order(-A$x, A$y, -A$z),]
în cazul în care " x " și " z " sunt niște coloane de date.cadru`O
. Acest lucru înseamnă un fel de date.cadru` " A "prin" x "descendentă," y "ascendentă și" z " descendent.
Am aflat despre "ordine" cu următorul exemplu, care apoi m-a derutat pentru o lungă perioadă de timp:
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
Singurul motiv pentru care acest exemplu funcționează este că "ordinul" este sortarea prin vectorul de Vârstă, nu de coloană numită "Vârsta" în `cadru de date de date.
Pentru a vedea acest lucru crea un identice cadru de date folosind citesti.tabel cu ușor diferite nume de coloană și fără a face uz de oricare dintre cele de mai sus vectori:
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)
Linia de mai sus structura pentru "ordine" nu mai funcționează pentru că nu există nici un vector numit "vârsta":
databyage = my.data[order(age),]
Următoarea linie funcționează pentru că "ordinul" felul in coloana "vârstă" în meu.date
.
databyage = my.data[order(my.data$age),]
Am crezut că acest lucru a fost în valoare de a posta având în vedere cât de confuz am fost prin acest exemplu pentru atât de mult timp. Dacă acest post nu este considerat adecvat pentru firul nu se poate elimina.
EDIT: May 13, 2014
Mai jos este un generalizate mod de sortare-un cadru de date de pe fiecare coloană fără a specifica numele coloanelor. Codul de mai jos arată modul de sortare de la stânga la dreapta sau de la dreapta la stânga. Aceasta funcționează dacă fiecare coloana este numerică. Nu am incercat cu un caracter coloană de adăugat.
Am gasit o fac.sun
cod de o lună sau două în urmă, într-o postare mai veche de pe un alt site, dar numai după detaliate și dificil de căutare. Eu nu sunt sigur că aș putea să mute acest post acum. Prezent fir este primul lovit pentru a comanda o data.cadruîn "R". Deci, m-am gândit mea versiune extinsă a face.sun
cod ar putea fi utile.
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
Ca răspuns la un comentariu adăugat în programul operațional pentru modul de sortare programatic:
Folosind dplyr " și " date.masa
library(dplyr)
library(data.table)
Doar folosi arrange_`, care este Standard versiune de Evaluare pentru "aranjează".
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)
mai multe informatii aici: https://cran.r-project.org/web/packages/dplyr/vignettes/nse.html
Este mai bine să utilizați formula as surprinde, de asemenea, mediu pentru a evalua o expresie în
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
Pentru motive de exhaustivitate: puteți folosi, de asemenea, sortByCol()
funcția de `BBmisc pachetului:
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
Comparație de performanță:
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
Doar ca mecanic card selectoare de mult timp în urmă, primul fel de puțin semnificative cheie, apoi următorul cele mai semnificative, etc. Nici o bibliotecă nu este necesar, funcționează cu orice număr de chei și orice combinație de crescător și descrescător chei.
dd <- dd[order(dd$b, decreasing = FALSE),]
Acum am're gata pentru a face cele mai importante. La fel este stabilă, și orice legături în cele mai importante au fost deja rezolvate.
dd <- dd[order(dd$z, decreasing = TRUE),]
Acest lucru nu poate fi cel mai rapid, dar este, cu siguranță, simplu și de încredere
Doar pentru motive de exhaustivitate, deoarece nu de mult a fost spus despre sortare de coloană de numere, Acesta poate fi cu siguranță a susținut că nu este de multe ori de dorit (pentru că ordinea coloanelor-ar putea schimba, deschizând calea pentru erori), dar în anumite situații (când, de exemplu, ai nevoie de un loc de muncă rapid de făcut și nu există nici un astfel de risc de coloane modificarea ordinelor), ar putea fi cel mai bun lucru de făcut, mai ales atunci când se ocupă cu un număr mare de coloane.
În acest caz, face.apel()` vine la salvare:
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
## (...)
Am fost luptă cu soluțiile de mai sus, atunci când am vrut să automatizeze mea proces de comanda pentru n coloane, ale căror nume de coloană ar putea fi diferită de fiecare dată. Am găsit o super utile funcție de psihiatrie a pachetului pentru a face acest lucru într-un mod simplu:
dfOrder(myDf, columnIndices)
unde columnIndices` sunt indici de una sau mai multe coloane, în ordinea în care doriți să le sortați. Mai multe informații aici: