r रशस स्तंभ(ओं) द्वारा डेटाफ्रेम को कैसे क्रमबद्ध करें?




विजय स्तम्भ एंड कीर्ति स्तम्भ (12)

मैं एकाधिक कॉलम द्वारा डेटा.फ्रेम को सॉर्ट करना चाहता हूं। उदाहरण के लिए, नीचे डेटा.फ्रेम के साथ मैं कॉलम 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

आर पैकेज data.table एक सीधा सिंटैक्स के साथ डेटा . tables के तेज़ और मेमोरी कुशल ऑर्डरिंग दोनों प्रदान करता है (जिसमें से एक हिस्सा मैट ने अपने जवाब में काफी अच्छी तरह से हाइलाइट किया है)। तब से काफी सुधार हुए हैं और एक नया फ़ंक्शन setorder() भी है। v1.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)

मानक:

रिपोर्ट किए गए समय नीचे दिखाए गए इन कार्यों पर चल रहे 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 . data.table DT[order(...)] वाक्यविन्यास अन्य तरीकों ( dplyr ) के सबसे तेज़ से ~ 10x तेज था, जबकि dplyr के समान स्मृति की मात्रा का उपभोग करते dplyr

  • data.table . data.table का setorder() अन्य तरीकों ( dplyr ) की तुलना में ~ 14x तेज था, जबकि केवल 0.4 जीबी अतिरिक्त मेमोरी ले रहा था। dat अब हमें आवश्यक क्रम में है (क्योंकि इसे संदर्भ द्वारा अपडेट किया गया है)।

डेटाटेबल विशेषताएं:

गति:

  • डेटाटेबल का ऑर्डरिंग बेहद तेज़ है क्योंकि यह रेडिक्स ऑर्डरिंग लागू करता है।

  • सिंटैक्स DT[order(...)] डेटाटेबल के तेज़ ऑर्डरिंग का उपयोग करने के लिए आंतरिक रूप से अनुकूलित किया गया है। आप परिचित बेस आर सिंटैक्स का उपयोग जारी रख सकते हैं लेकिन प्रक्रिया को तेज कर सकते हैं (और कम मेमोरी का उपयोग करें)।

याद:

  • अधिकांश बार, हमें रीडरिंग के बाद मूल डेटा.फ्रेम या डेटाटेबल की आवश्यकता नहीं होती है। यही है, हम आमतौर पर परिणाम को उसी ऑब्जेक्ट पर असाइन करते हैं, उदाहरण के लिए:

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

    मुद्दा यह है कि मूल वस्तु की स्मृति को कम से कम दो बार (2x) की आवश्यकता होती है। स्मृति कुशल होने के लिए , डेटा.table इसलिए फ़ंक्शन setorder() भी प्रदान करता है।

    setorder() किसी भी अतिरिक्त प्रतियों के बिना by reference ( जगह में ) by reference data.tables by reference । यह केवल एक कॉलम के आकार के बराबर अतिरिक्त मेमोरी का उपयोग करता है।

अन्य सुविधाओं:

  1. यह integer , logical , numeric , character और यहां तक ​​कि bit64::integer64 प्रकार का समर्थन करता है।

    ध्यान दें कि factor , Date , POSIXct आदि .. कक्षाएं अतिरिक्त गुणों के साथ सभी integer / numeric प्रकार हैं और इसलिए भी समर्थित हैं।

  2. बेस आर में, हम उस कॉलम द्वारा घटते क्रम में सॉर्ट करने के लिए एक वर्ण वेक्टर पर उपयोग नहीं कर सकते हैं। इसके बजाय हमें -xtfrm(.) का उपयोग -xtfrm(.)

    हालांकि, डेटाटेबल में , हम बस कर सकते हैं, उदाहरण के लिए, dat[order(-x)] setorder(dat, -x) dat[order(-x)] या setorder(dat, -x)


मान लें कि आपके पास data.frame है। data.frame A और आप x अवरोही क्रम नामक कॉलम का उपयोग करके इसे सॉर्ट करना चाहते हैं। सॉर्ट data.frame गए data.frame कॉल करें। data.frame newdata

newdata <- A[order(-A$x),]

यदि आप आरोही क्रम चाहते हैं तो कुछ भी के साथ "-" को प्रतिस्थापित करें। आप कुछ ऐसा कर सकते हैं

newdata <- A[order(-A$x, A$y, -A$z),]

जहां x और z data.frame में कुछ कॉलम हैं। data.frame A । इसका मतलब है x अवरोही, z आरोही और z अवरोही द्वारा data.frame A


वैकल्पिक रूप से, पैकेज डेड्यूसर का उपयोग कर

library(Deducer)
dd<- sortData(dd,c("z","b"),increasing= c(FALSE,TRUE))


मैंने निम्नलिखित उदाहरण के साथ 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 द्वारा सॉर्ट कर रहा है, न कि data frame data में Age नामक कॉलम द्वारा।

इसे देखने के लिए थोड़ा अलग कॉलम नामों के साथ read.table का उपयोग 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 my.data में कॉलम age पर my.data

databyage = my.data[order(my.data$age),]

मैंने सोचा कि यह पोस्टिंग के लायक था यह देखते हुए कि मैं इतनी देर तक इस उदाहरण से कितना उलझन में था। यदि यह पोस्ट थ्रेड के लिए उपयुक्त समझा नहीं गया है तो मैं इसे हटा सकता हूं।

संपादित करें: 13 मई, 2014

कॉलम नाम निर्दिष्ट किए बिना प्रत्येक कॉलम द्वारा डेटा फ्रेम को सॉर्ट करने का एक सामान्य तरीका नीचे दिया गया है। नीचे दिया गया कोड दिखाता है कि बाएं से दाएं या दाएं से बाएं कैसे क्रमबद्ध करें। यह काम करता है अगर हर कॉलम संख्यात्मक है। मैंने जोड़े गए वर्ण स्तंभ के साथ प्रयास नहीं किया है।

मुझे एक महीने या दो बार एक अलग साइट पर एक पुरानी पोस्ट में do.call कोड मिला, लेकिन केवल व्यापक और कठिन खोज के बाद। मुझे यकीन नहीं है कि मैं अब उस पोस्ट को स्थानांतरित कर सकता हूं। R में data.frame ऑर्डर करने के लिए वर्तमान धागा पहला हिट है। इसलिए, मैंने सोचा कि उस मूल 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

यहां बहुत सारे उत्कृष्ट उत्तर दिए गए हैं, लेकिन 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

या आप पैकेज doBy का उपयोग कर सकते हैं

library(doBy)
dd <- orderBy(~-z+b, data=dd)

Dirk का जवाब बहुत अच्छा है। यह data.frame और data.table data.frame एस अनुक्रमणित करने के लिए प्रयुक्त वाक्यविन्यास में एक महत्वपूर्ण अंतर भी दर्शाता है:

## 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 । यह बनता है :

quarterlyreport[with(quarterlyreport,order(-z,b)),]

अच्छी बात है। कुछ गलत नहीं है उसके साथ। इसके बाद आपका मालिक आपको रिपोर्ट में पिछली तिमाही की रिपोर्ट शामिल करने के लिए कहता है। आप अपने कोड से lastquarterlyreport , विभिन्न स्थानों में किसी ऑब्जेक्ट को lastquarterlyreport जोड़ते हैं और किसी भी तरह (पृथ्वी पर कैसे?) आप इसके साथ समाप्त होते हैं:

quarterlyreport[with(lastquarterlyreport,order(-z,b)),]

यही वह नहीं है जिसका मतलब था लेकिन आपने इसे नहीं देखा क्योंकि आपने इसे तेज़ किया था और यह समान कोड के पृष्ठ पर घिरा हुआ है। कोड खत्म नहीं होता है (कोई चेतावनी नहीं और कोई त्रुटि नहीं) क्योंकि आर सोचता है कि इसका मतलब क्या है। आप उम्मीद करेंगे कि जो भी आपकी रिपोर्ट पढ़ता है उसे स्पॉट करता है, लेकिन शायद वे नहीं करते हैं। यदि आप प्रोग्रामिंग भाषाओं के साथ बहुत काम करते हैं तो यह परिस्थिति परिचित हो सकती है। यह एक "टाइपो" था जिसे आप कहेंगे। मैं "टाइपो" को ठीक कर दूंगा जो आप अपने मालिक से कहेंगे।

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

यह एक बहुत छोटा अंतर है, लेकिन यह सिर्फ एक दिन आपकी गर्दन को बचा सकता है। इस प्रश्न के विभिन्न उत्तरों का वजन करते समय, परिवर्तनीय नामों की पुनरावृत्ति को निर्णय लेने में अपने मानदंडों में से एक के रूप में गिनने पर विचार करें। कुछ उत्तरों में कुछ दोहराने हैं, दूसरों के पास कोई नहीं है।


पूर्णता के लिए: आप BBmisc पैकेज से sortByCol() फ़ंक्शन का भी उपयोग कर सकते हैं:

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

Dirk का जवाब अच्छा है, लेकिन अगर आपको जारी रखने के लिए इस तरह की ज़रूरत है तो आप उस डेटा फ्रेम के नाम पर वापस सॉर्ट करना चाहेंगे। उदाहरण कोड का उपयोग करना:

dd <- dd[with(dd, order(-z, b)), ] 

यदि एसक्यूएल आपके लिए स्वाभाविक रूप से आता है, तो एसकल्डएफ ऑर्डर को कोडड के रूप में संभालता है।


प्रोग्रामेटिक रूप से सॉर्ट करने के तरीके के लिए ओपी में एक टिप्पणी के जवाब में:

dplyr और data.table का उपयोग करना

library(dplyr)
library(data.table)

dplyr

बस arrange_ उपयोग 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




r-faq