Chcę posortować ramkę danych według wielu kolumn. Na przykład z data.frame poniżej chciałbym sortować według kolumny z
(malejąco), a następnie według kolumny b
(rosnąco):
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
. SpróbujM <- matrix(c(1,2,2,2,3,6,4,5), 4, 2, byrow=FALSE, dimnames=list(NULL, c("a","b")))
utworzyć macierzM
, a następnie użyj,M[order(M[,"a"],-M[,"b"]),]
aby zamówić ją w dwóch kolumnach.dd[ order(-dd[,4], dd[,1]), ]
ale nie można go używaćwith
do podzbiorów opartych na nazwach.xtfrm
, na przykład zawijając kolumnędd[ order(-xtfrm(dd[,4]), dd[,1]), ]
.Twoje wybory
order
odbase
arrange
oddplyr
setorder
isetorderv
oddata.table
arrange
odplyr
sort
odtaRifx
orderBy
oddoBy
sortData
odDeducer
Przez większość czasu powinieneś korzystać z rozwiązań
dplyr
lubdata.table
, chyba że ważne jest posiadanie niezależności, w takim przypadku użyjbase::order
.Niedawno dodałem sort.data.frame do pakietu CRAN, dzięki czemu jest on zgodny z klasą, jak omówiono tutaj: Najlepszy sposób tworzenia spójności ogólnej / metody dla sort.data.frame?
Dlatego biorąc pod uwagę data.frame dd, możesz sortować w następujący sposób:
Jeśli jesteś jednym z oryginalnych autorów tej funkcji, skontaktuj się ze mną. Dyskusja na temat domeny publicznej jest tutaj: http://chat.stackoverflow.com/transcript/message/1094290#1094290
Możesz także użyć
arrange()
funkcji z,plyr
jak wskazał Hadley w powyższym wątku:Benchmarki: Zauważ, że załadowałem każdy pakiet w nowej sesji R, ponieważ było wiele konfliktów. W szczególności ładowanie pakietu doBy powoduje
sort
zwrócenie „Następujące obiekty są maskowane z„ x (pozycja 17) ”: b, x, y, z”, a ładowanie pakietu Deducer zastępujesort.data.frame
Kevin Wright lub pakiet taRifx.Mediana razy:
dd[with(dd, order(-z, b)), ]
778dd[order(-dd$z, dd$b),]
788Mediana czasu: 1567
Mediana czasu: 862
Mediana czasu: 1,694
Pamiętaj, że doBy zajmuje dużo czasu, aby załadować pakiet.
Nie można zmusić Deducer do obciążenia. Potrzebuje konsoli JGR.
Wygląda na to, że nie jest kompatybilny z mikrodrukiem ze względu na dołączanie / odłączanie.
(linie rozciągają się od dolnego kwartylu do górnego kwartylu, kropka jest medianą)
Biorąc pod uwagę te wyniki i ważenie prostoty w porównaniu z szybkością, musiałbym skinąć głową
arrange
wplyr
pakiecie . Ma prostą składnię, a mimo to jest prawie tak szybki, jak komendy podstawowego R z ich skomplikowanymi machinacjami. Zazwyczaj genialna praca Hadleya Wickhama. Jedyną moją wadą jest to, że łamie standardową nomenklaturę R, w której wywoływane są obiekty sortującesort(object)
, ale rozumiem, dlaczego Hadley zrobił to w ten sposób z powodu problemów omówionych w pytaniu powiązanym powyżej.źródło
taRifx::autoplot.microbenchmark
.b
jest posortowany w próbce. Domyślnie sortuj według rosnącego, więc po prostu go nie zawijajdesc
. Rosnąco zarówno:arrange(dd,z,b)
. Malejąco zarówno:arrange(dd,desc(z),desc(b))
.?arrange
: „# UWAGA: funkcje plyr NIE zachowują nazw row.names”. To sprawia, że doskonałaarrange()
funkcja nie jest optymalna, jeśli chce się ją zachowaćrow.names
.Odpowiedź Dirka jest świetna. Podkreśla również kluczową różnicę w składni do indeksowania
data.frame
s idata.table
s:Różnica między tymi dwoma połączeniami jest niewielka, ale może mieć poważne konsekwencje. Zwłaszcza jeśli piszesz kod produkcyjny i / lub martwisz się o poprawność swoich badań, najlepiej unikać niepotrzebnego powtarzania nazw zmiennych.
data.table
pomaga ci to zrobić.Oto przykład, w jaki sposób powtarzanie nazw zmiennych może powodować kłopoty:
Zmieńmy kontekst z odpowiedzi Dirka i powiedzmy, że jest to część większego projektu, w którym istnieje wiele nazw obiektów, które są długie i znaczące; zamiast
dd
nazywa sięquarterlyreport
. Staje się :Ok dobrze. Nic w tym złego. Następnie szef prosi o uwzględnienie raportu z ostatniego kwartału. Przechodzisz przez swój kod, dodając obiekt
lastquarterlyreport
w różnych miejscach i jakoś (jak to możliwe, do licha):Nie to miałeś na myśli, ale nie zauważyłeś tego, ponieważ zrobiłeś to szybko i jest on umieszczony na stronie podobnego kodu. Kod się nie przewraca (bez ostrzeżenia i bez błędu), ponieważ R myśli, że to właśnie miałeś na myśli. Miałbyś nadzieję, że ktokolwiek przeczyta twój raport, zauważy to, ale może nie. Jeśli dużo pracujesz z językami programowania, ta sytuacja może być znana. To powiesz „literówka”. Naprawię literówkę, którą powiesz swojemu szefowi.
W
data.table
jesteśmy zaniepokojeni drobnych szczegółów, takich jak ten. Zrobiliśmy więc coś prostego, aby uniknąć dwukrotnego wpisywania nazw zmiennych. Coś bardzo prostego.i
jest oceniany w ramachdd
już, automatycznie. W ogóle nie potrzebujeszwith()
.Zamiast
to poprostu
I zamiast
to poprostu
To bardzo mała różnica, ale pewnego dnia może po prostu zaoszczędzić szyję. Analizując różne odpowiedzi na to pytanie, rozważ liczenie powtórzeń nazw zmiennych jako jedno z kryteriów przy podejmowaniu decyzji. Niektóre odpowiedzi mają kilka powtórzeń, inne nie.
źródło
subset()
tylko, aby uniknąć konieczności wielokrotnego odwoływania się do tego samego obiektu w ramach jednego połączenia.setorder
funkcję, ponieważ w tym wątku wysyłamy wszystkieorder
duplikaty typów.Istnieje tutaj wiele doskonałych odpowiedzi, ale dplyr podaje jedyną składnię, którą mogę szybko i łatwo zapamiętać (a więc teraz bardzo często używam):
W przypadku problemu PO:
źródło
dd[order(-z, b)]
dość łatwy w użyciu i pamiętam.data.table
jest to ogromny wkładR
w wiele innych sposobów. Przypuszczam, że dla mnie może być tak, że posiadanie jednego mniejszego zestawu nawiasów (lub jednego mniejszego rodzaju nawiasów) w tym przypadku zmniejsza obciążenie poznawcze o ledwo zauważalną ilość.arrange()
jest całkowicie deklaratywne,dd[order(-z, b)]
nie jest.Pakiet R
data.table
zapewnia szybkie i efektywne pod względem pamięci uporządkowanie tabel data.tab z prostą składnią (której część Matt dość ładnie podkreślił w swojej odpowiedzi ). Od tego czasu wprowadzono wiele ulepszeń, a także nowa funkcjasetorder()
. Odv1.9.5+
,setorder()
współpracuje również z data.frames .Najpierw utworzymy zestaw danych wystarczająco duży i porównamy różne metody wymienione w innych odpowiedziach, a następnie wymienimy funkcje data.table .
Dane:
Benchmarki:
Zgłoszone czasy pochodzą z działania
system.time(...)
tych funkcji pokazanych poniżej. Czasy są zestawione poniżej (w kolejności od najwolniejszej do najszybszej).data.table
jestDT[order(...)]
składnia było ~ 10x szybciej niż największe innych metod (dplyr
), zaś zużywa tyle samo jak pamięćdplyr
.data.table
„ssetorder()
było ~ 14x szybciej niż najszybszy z innymi metodami (dplyr
), a jednocześnie tylko 0.4GB dodatkowej pamięci .dat
jest teraz w wymaganej przez nas kolejności (ponieważ jest aktualizowany przez odniesienie).Funkcje data.table:
Prędkość:
Kolejność data.table jest niezwykle szybka, ponieważ implementuje porządkowanie w Radix .
Składnia
DT[order(...)]
jest zoptymalizowana wewnętrznie w celu wykorzystania również szybkiego zamawiania data.table . Możesz nadal używać znanej podstawowej składni R, ale przyspieszyć proces (i zużywać mniej pamięci).Pamięć:
W większości przypadków nie wymagamy oryginalnego data.frame lub data.table po zmianie kolejności. Oznacza to, że zwykle przypisujemy wynik z powrotem do tego samego obiektu, na przykład:
Problem polega na tym, że wymaga to przynajmniej dwukrotnie (2x) pamięci oryginalnego obiektu. Dlatego, aby zapewnić wydajność pamięci , data.table udostępnia również funkcję
setorder()
.setorder()
zmienia kolejność danych. tabeleby reference
( na miejscu ), bez wykonywania dodatkowych kopii. Wykorzystuje tylko dodatkową pamięć równą wielkości jednej kolumny.Inne funkcje:
Obsługuje
integer
,logical
,numeric
,character
a nawetbit64::integer64
rodzaje.W bazie R nie możemy używać
-
wektora znaków do sortowania według tej kolumny w malejącej kolejności. Zamiast tego musimy użyć-xtfrm(.)
.Jednak w data.table możemy po prostu zrobić, na przykład,
dat[order(-x)]
lubsetorder(dat, -x)
.źródło
Dzięki tej (bardzo pomocnej) funkcji Kevina Wrighta , opublikowanej w sekcji porad na wiki R, można to łatwo osiągnąć.
źródło
lub możesz użyć pakietu doBy
źródło
Załóżmy, że masz
data.frame
A
i chcesz je posortować za pomocą kolumny zwanejx
kolejnością malejącą. Zadzwoń do posortowanegodata.frame
newdata
Jeśli chcesz porządek rosnący, zastąp
"-"
go niczym. Możesz mieć coś takiegogdzie
x
iz
są niektóre kolumny wdata.frame
A
. Oznacza to sortowaniedata.frame
A
wedługx
malejącego,y
rosnącego iz
malejącego.źródło
jeśli SQL przychodzi ci naturalnie,
sqldf
pakiet obsługuje sięORDER BY
tak, jak zamierzał Codd.źródło
Alternatywnie, używając pakietu Deducer
źródło
W odpowiedzi na komentarz dodany w PO dotyczący programowego sortowania:
Korzystanie
dplyr
idata.table
dplyr
Wystarczy użyć
arrange_
, która jest wersją Standardową wersję testowąarrange
.więcej informacji tutaj: https://cran.r-project.org/web/packages/dplyr/vignettes/nse.html
Lepiej jest użyć formuły, ponieważ przechwytuje ona także środowisko do oceny wyrażenia
Tabela danych
źródło
Dowiedziałem się o tym
order
z poniższego przykładu, który przez długi czas mylił mnie:Jedynym powodem, dla którego ten przykład działa, jest
order
sortowanie wedługvector Age
, a nie według kolumny o nazwieAge
wdata frame data
.Aby to zobaczyć, utwórz identyczną ramkę danych, używając
read.table
nieco innych nazw kolumn i bez użycia żadnego z powyższych wektorów:Powyższa struktura linii
order
już nie działa, ponieważ nie ma wektora o nazwieage
:Poniższy wiersz działa, ponieważ
order
sortuje według kolumnyage
wmy.data
.Pomyślałem, że warto to opublikować, biorąc pod uwagę, jak długo byłem zdezorientowany tym przykładem. Jeśli ten post nie zostanie uznany za odpowiedni dla tego wątku, mogę go usunąć.
EDYCJA: 13 maja 2014 r
Poniżej znajduje się ogólny sposób sortowania ramki danych według każdej kolumny bez podawania nazw kolumn. Poniższy kod pokazuje, jak sortować od lewej do prawej lub od prawej do lewej. Działa to, jeśli każda kolumna jest liczbą. Nie próbowałem z dodaną kolumną znaków.
Znalazłem
do.call
kod miesiąc lub dwa lata temu w starym poście na innej stronie, ale dopiero po obszernym i trudnym wyszukiwaniu. Nie jestem pewien, czy mógłbym teraz przenieść ten post. Obecny wątek jest pierwszym hitem na zamówieniedata.frame
wR
. Pomyślałem więc, że moja rozszerzona wersja tego oryginalnegodo.call
kodu może się przydać.źródło
require(data.table); my.dt <- data.table(my.data); my.dt[order(age)]
Działa to, ponieważ nazwy kolumn są dostępne w nawiasach [].data.frame
albo do użyciawith
albo$
.do.call
to sprawia, że krótka praca nad sortowaniem wielokolumnowej ramki danych. Po prostudo.call(sort, mydf.obj)
będzie piękny rodzaj kaskady.Odpowiedź Dirka jest dobra, ale jeśli chcesz zachować sortowanie, powinieneś zastosować sortowanie z powrotem do nazwy tej ramki danych. Za pomocą przykładowego kodu:
źródło
Arrange () w dplyerze to moja ulubiona opcja. Użyj operatora potoku i przejdź od najmniej ważnego do najważniejszego aspektu
źródło
Ze względu na kompletność, ponieważ niewiele powiedziano o sortowaniu według numerów kolumn ... Z pewnością można argumentować, że często nie jest pożądane (ponieważ kolejność kolumn może się zmienić, torując drogę do błędów), ale w niektórych szczególnych sytuacjach (gdy na przykład potrzebujesz szybkiej pracy i nie ma takiego ryzyka zmiany kolejności kolumn), może to być najbardziej rozsądne, szczególnie w przypadku dużej liczby kolumn.
W takim przypadku
do.call()
przychodzi na ratunek:źródło
Dla kompletności: możesz również użyć
sortByCol()
funkcji zBBmisc
pakietu:Porównanie wydajności:
źródło
data.frame
Podobnie jak dawno temu mechaniczne sortowniki kart, najpierw sortuj według najmniej znaczącego klucza, a następnie następnego najbardziej znaczącego itd. Nie jest wymagana biblioteka, działa z dowolną liczbą kluczy i dowolną kombinacją kluczy rosnących i malejących.
Teraz jesteśmy gotowi zrobić najbardziej znaczący klucz. Sortowanie jest stabilne, a wszelkie powiązania w najbardziej znaczącym kluczu zostały już rozwiązane.
To może nie być najszybszy, ale z pewnością jest prosty i niezawodny
źródło
Inna alternatywa, przy użyciu
rgr
pakietu:źródło
Walczyłem z powyższymi rozwiązaniami, gdy chciałem zautomatyzować proces zamawiania dla n kolumn, których nazwy kolumn mogą być za każdym razem inne. Znalazłem bardzo przydatną funkcję z
psych
pakietu, aby to zrobić w prosty sposób:gdzie
columnIndices
są indeksy jednej lub więcej kolumn, w kolejności, w której chcesz je posortować. Więcej informacji tutaj:Funkcja dfOrder z pakietu „psych”
źródło