सदिश या स्तंभ में दूसरा (तीसरा…) उच्चतम / निम्नतम मान ज्ञात करने का सबसे तेज़ तरीका


161

आर अधिकतम और न्यूनतम प्रदान करता है, लेकिन मुझे पूरे वेक्टर को छांटने के अलावा और फिर इस वेक्टर से एक मान x चुनने के अलावा आदेश में एक और मूल्य खोजने के लिए वास्तव में तेज़ तरीका नहीं दिखता है।

उदाहरण के लिए दूसरा उच्चतम मूल्य प्राप्त करने का एक तेज़ तरीका है?


CRAN पर पैकेज किट में एक topnफंक्शन होता है sort, जो की तुलना में तेज होता है , orderऔर nth। दस्तावेज को देखें।
सुरेश_पाल

जवाबों:


195

के partialतर्क का उपयोग करें sort()। दूसरे उच्चतम मूल्य के लिए:

n <- length(x)
sort(x,partial=n-1)[n-1]

4
sort(x, TRUE)[2]@ अबरार के उत्तर में वर्णित के रूप में इस पद्धति का क्या फायदा है, प्रश्न में बाधा को संतुष्ट नहीं करने के अलावा?
ह्यूग

5
मैंने इस पद्धति का उपयोग किया, लेकिन निम्न त्रुटि प्राप्त करें: Error in sort.int(x, na.last = na.last, decreasing = decreasing, ...) : index 4705 outside bounds कोई भी विचार क्या समस्या हो सकती है? कुछ विवरण: मेरा x NAडेटा में कुछ s के साथ लंबाई 4706 का एक संख्यात्मक वेक्टर है । मैंने @RobHyndman के समान सटीक कोड का उपयोग करके वेक्टर में दूसरा उच्चतम मूल्य प्राप्त करने का प्रयास किया।
sriramn

आप अवरोही क्रमबद्ध क्यों नहीं करते और केवल दो मानों में से दूसरा लेते हैं? क्या यह तेज नहीं होगा?
15:17 बजे jwg

3
अवरोही तर्क आंशिक छँटाई के साथ संगत नहीं है।
रोब हंडमैन

7
हालांकि decreasingतर्क आंशिक छँटाई के साथ संगत नहीं है, आप हमेशा से रह सकते हैं -sort(-x, partial=n-1)[n-1]; यह तार्किक रूप से एक ही चीज है और इससे काफी कम समय लगता है sort(x, decreasing=TRUE)[n-1]
r2evans

52

केवल रिकॉर्ड के लिए थोड़ा धीमा विकल्प:

x <- c(12.45,34,4,0,-234,45.6,4)
max( x[x!=max(x)] )
min( x[x!=min(x)] )

यह आश्चर्य की बात होगी अगर यह पूरे वेक्टर को क्रमबद्ध करने और n-1 वां मान लेने की तुलना में कोई तेज़ था!
jwg

@jwg यह O (n) है, इसलिए इसे बड़े डेटासेट पर सॉर्ट करने से अधिक तेज़ होना चाहिए।
म्यूजियमफुल

अन्य स्वीकृत उत्तर की तुलना में NA के साथ बेहतर काम करता है - बस 'मिनट' फ़ंक्शन के तर्क के रूप में 'na.rm = TRUE' का उपयोग करें।
यार डॉन

2
ऐसा लगता है कि आप एक छोटे से संशोधन के साथ कुछ काफी गति सुधार कर सकते हैं:max(x[-which.max(x)])
sindri_baldur

31

मैंने रोब के उत्तर को थोड़ा और सामान्य फ़ंक्शन में लपेट दिया, जिसका उपयोग 2, 3, 4 वां (आदि) अधिकतम खोजने के लिए किया जा सकता है:

maxN <- function(x, N=2){
  len <- length(x)
  if(N>len){
    warning('N greater than length(x).  Setting N=length(x)')
    N <- length(x)
  }
  sort(x,partial=len-N+1)[len-N+1]
}

maxN(1:10)

1
ठंडा। यह उपयोग विशेष रूप से उपयोगी है maxN(1:10, 1:3)(मैंने डिफ़ॉल्ट एन को 1 पर सेट किया होगा)
पैट्रिकटी

23

RIFT में एक फ़ंक्शन है जिसे nth_element कहा जाता है, जो वास्तव में आपके द्वारा पूछा गया है और ऊपर चर्चा की गई सभी कार्यान्वयनों की तुलना में तेज़ है

इसके अलावा ऊपर चर्चा की गई पद्धतियाँ आंशिक प्रकार पर आधारित हैं, k सबसे छोटे मूल्यों को खोजने का समर्थन नहीं करते हैं

Rfast::nth(x, 5, descending = T)

X का 5 वाँ सबसे बड़ा तत्व लौटाएगा, जबकि

Rfast::nth(x, 5, descending = F)

X का 5 वां सबसे छोटा तत्व लौटाएगा

सबसे लोकप्रिय उत्तरों के खिलाफ नीचे बेंचमार्क।

10 हजार की संख्या के लिए:

N = 10000
x = rnorm(N)

maxN <- function(x, N=2){
    len <- length(x)
    if(N>len){
        warning('N greater than length(x).  Setting N=length(x)')
        N <- length(x)
    }
    sort(x,partial=len-N+1)[len-N+1]
}

microbenchmark::microbenchmark(
    Rfast = Rfast::nth(x,5,descending = T),
    maxn = maxN(x,5),
    order = x[order(x, decreasing = T)[5]]
)

Unit: microseconds
  expr      min       lq      mean   median        uq       max neval
 Rfast  160.364  179.607  202.8024  194.575  210.1830   351.517   100
  maxN  396.419  423.360  559.2707  446.452  487.0775  4949.452   100
 order 1288.466 1343.417 1746.7627 1433.221 1500.7865 13768.148   100

1 मिलियन संख्याओं के लिए:

N = 1e6 #evaluates to 1 million
x = rnorm(N)

microbenchmark::microbenchmark(
    Rfast = Rfast::nth(x,5,descending = T),
    maxN = maxN(x,5),
    order = x[order(x, decreasing = T)[5]]
)

Unit: milliseconds
  expr      min        lq      mean   median        uq       max neval
 Rfast  89.7722  93.63674  114.9893 104.6325  120.5767  204.8839   100
  maxN 150.2822 207.03922  235.3037 241.7604  259.7476  336.7051   100
 order 930.8924 968.54785 1005.5487 991.7995 1031.0290 1164.9129   100

8
अच्छा! आम तौर पर जब मैं एक अपेक्षाकृत कम प्रतिनिधि उपयोगकर्ता को एक लोकप्रिय पुराने प्रश्न का उत्तर जोड़ता हूं, तो यह बहुत कम गुणवत्ता वाला होता है। दूसरी ओर, यह एक उत्कृष्ट जोड़ है। मैंने कुछ पठनीयता संपादन किया, लेकिन यह बहुत अच्छा लग रहा है!
ग्रेगर थॉमस

3
यह उल्लेख करता है कि Rfast::nthकई तत्वों (जैसे 8 वें और 9 वें सबसे बड़े तत्व) के साथ-साथ उन तत्वों के सूचक भी लौट सकते हैं।
जशा

3
RIFT समाधान के बारे में मुझे जो पसंद है वह यह है कि पैकेज में प्रत्येक पंक्ति या स्तंभ के लिए ऐसा करने के लिए आसानी से कार्यान्वित समाधान है।
जय

16

यहाँ एक वेक्टर में एन सबसे छोटे / सबसे बड़े मूल्यों के उदाहरणों को खोजने का एक आसान तरीका है (उदाहरण के लिए N = 3):

N <- 3

एन सबसे छोटा:

ndx <- order(x)[1:N]

एन सबसे बड़ा:

ndx <- order(x, decreasing = T)[1:N]

तो आप निम्न मान निकाल सकते हैं:

x[ndx]

यह L लॉग L समय में चलता है, जहाँ L, x की लंबाई है। मुझे लगता है कि उपयोगकर्ता एक विधि के लिए उम्मीद कर रहा था जो लॉग एल समय में चलती है।
तीरंदाजी 22

यह दूसरा सबसे तेज़ तरीका हो सकता है अगर तरीकों को समय से आदेश दिया गया और सबसे तेज़ एन निकाला गया। मुझे यह भी पसंद है क्योंकि स्वीकृत समाधान की तुलना में यह बहुत स्पष्ट कोड है।
पीट

1
सैद्धांतिक सर्वश्रेष्ठ और स्वीकृत विधि (उम्मीद है) O (L) समय में चलती है, O (लॉग L) नहीं। यह O (L लॉग L) में चलता है।
Valentas

6

Nth उच्चतम मूल्य के लिए,

sort(x, TRUE)[n]

8
ओपी ने पहले ही अपने पोस्ट में कहा था कि यह एक ऐसा समाधान था जिसका वह उपयोग नहीं करना चाहता था: "पूरे वेक्टर को छाँटने के अलावा और इस वेक्टर से मान x लेने के अलावा"।
पॉल हैमस्ट्रा

3

मैंने पाया कि पहले अधिकतम तत्व को हटा देना और फिर तुलनात्मक गति में एक और अधिकतम रन बनाना:

system.time({a=runif(1000000);m=max(a);i=which.max(a);b=a[-i];max(b)})
   user  system elapsed 
  0.092   0.000   0.659 

system.time({a=runif(1000000);n=length(a);sort(a,partial=n-1)[n-1]})
   user  system elapsed 
  0.096   0.000   0.653 

2

यहाँ मैंने पाया सबसे सरल तरीका है,

num <- c(5665,1615,5154,65564,69895646)

num <- sort(num, decreasing = F)

tail(num, 1)                           # Highest number
head(tail(num, 2),1)                   # Second Highest number
head(tail(num, 3),1)                   # Third Highest number
head(tail(num, n),1)                   # Generl equation for finding nth Highest number

1

जब मैं हाल ही में एक दिए गए वेक्टर में शीर्ष एन अधिकतम / मिनट संख्या के आर फ़ंक्शन रिटर्निंग इंडेक्स की तलाश कर रहा था, तो मुझे आश्चर्य हुआ कि ऐसा कोई फ़ंक्शन नहीं है।

और यह बहुत कुछ समान है।

बेस :: ऑर्डर फंक्शन का उपयोग करके ब्रूट फोर्स सॉल्यूशन सबसे आसान लगता है।

topMaxUsingFullSort <- function(x, N) {
  sort(x, decreasing = TRUE)[1:min(N, length(x))]
}

लेकिन यह इस मामले में सबसे तेजी से एक अपने नहीं है एन मूल्य के वेक्टर लंबाई की तुलना में अपेक्षाकृत छोटा है एक्स

दूसरी तरफ यदि N वास्तव में छोटा है, तो आप आधार का उपयोग कर सकते हैं :: जोकि क्रमिक रूप से कार्य करता है और प्रत्येक पुनरावृत्ति में आप पाया गया मूल्य-byf बदल सकते हैं

# the input vector 'x' must not contain -Inf value 
topMaxUsingWhichMax <- function(x, N) {
  vals <- c()
  for(i in 1:min(N, length(x))) {
    idx      <- which.max(x)
    vals     <- c(vals, x[idx]) # copy-on-modify (this is not an issue because idxs is relative small vector)
    x[idx]   <- -Inf            # copy-on-modify (this is the issue because data vector could be huge)
  }
  vals
}

मेरा मानना ​​है कि आप समस्या को देखते हैं - आर की कॉपी-ऑन-संशोधित प्रकृति। इसलिए यह बहुत बहुत छोटे एन (1,2,3) के लिए बेहतर प्रदर्शन करेगा, लेकिन यह बड़े एन मूल्यों के लिए तेजी से धीमा हो जाएगा। और आप वेक्टर एक्स एन बार में सभी तत्वों पर ध्यान केंद्रित कर रहे हैं ।

मुझे लगता है कि स्वच्छ आर में सबसे अच्छा समाधान आंशिक आधार :: सॉर्ट का उपयोग करना है ।

topMaxUsingPartialSort <- function(x, N) {
  N <- min(N, length(x))
  x[x >= -sort(-x, partial=N)[N]][1:N]
}

तब आप ऊपर दिए गए फ़ंक्शन के परिणाम से अंतिम ( N th) आइटम का चयन कर सकते हैं ।

नोट: उपर्युक्त कार्य केवल उदाहरण हैं - यदि आप उनका उपयोग करना चाहते हैं, तो आपको / इनपुट जानकारी की जांच करनी होगी (जैसे। N> लंबाई (x) )।

मैंने http://palusga.cz/?p=18 पर कुछ इसी तरह के (एक वेक्टर के शीर्ष एन अधिकतम / मिनट मूल्यों के अनुक्रमित प्राप्त करें) के बारे में एक छोटा सा लेख लिखा था - आप यहां समान कार्यों के कुछ बेंचमार्क पा सकते हैं जिन्हें मैंने ऊपर परिभाषित किया था।



0
topn = function(vector, n){
  maxs=c()
  ind=c()
  for (i in 1:n){
    biggest=match(max(vector), vector)
    ind[i]=biggest
    maxs[i]=max(vector)
    vector=vector[-biggest]
  }
  mat=cbind(maxs, ind)
  return(mat)
}

यह फ़ंक्शन शीर्ष n मान और उनके सूचक के साथ एक मैट्रिक्स लौटाएगा। आशा है कि यह वीडीवी-चाउ की मदद करता है


0

यह इनपुट न्यूमेरिक वेक्टर x में N'th सबसे छोटा या सबसे बड़ा मान का सूचकांक मिलेगा। नीचे सेट करें = यदि आप ऊपर से N'th चाहते हैं, तो नीचे या NAL से N'th चाहते हैं, तो तर्कों में TRUE करें। N = 1 और निचला = TRUE किसके समतुल्य है .min, N = 1 और निचला = FALSE जो.m.max के बराबर है।

FindIndicesBottomTopN <- function(x=c(4,-2,5,-77,99),N=1,bottom=FALSE)
{

  k1 <- rank(x)
  if(bottom==TRUE){
    Nindex <- which(k1==N)
    Nindex <- Nindex[1]
  }

  if(bottom==FALSE){
    Nindex <- which(k1==(length(x)+1-N))
    Nindex <- Nindex[1]
  }

  return(Nindex)
}

0

dplyr में फ़ंक्शन nth है, जहां पहला तर्क वेक्टर है और दूसरा वह स्थान है जो आप चाहते हैं। यह तत्वों को दोहराने के लिए भी जाता है। उदाहरण के लिए:

x = c(1,2, 8, 16, 17, 20, 1, 20)

दूसरा सबसे बड़ा मूल्य ढूँढना:

 nth(unique(x),length(unique(x))-1)

[1] 17

2
क्या यह व्रत है ...?
बेन बोल्कर

2
आंतरिक रूप से यह उपयोग करता है x[[order(order_by)[[n]]]]- इसलिए इसे पूरे वेक्टर को छांटने की आवश्यकता होती है। तो यह स्वीकार किए जाते हैं उत्तर के रूप में उपवास नहीं किया जाएगा।
बेन बोलकर

5
लेकिन यह sort आंशिक = तर्क (जो सब कुछ बदलता है) के साथ उपयोग करता है
बेन बोल्कर

@BenBolker जो पाओलो या रोब के जवाब का अर्थ है सुधार करने के लिए इस्तेमाल किया जा सकता है dplyr::nth()? bench::mark(max(x[-which.max(x)]), x[[order(-x)[[2]]]] ), nth()लगभग 10 गुना धीमा लगता है, जहां length(x)3 मिलियन है।
sindri_baldur

-1

आप के साथ अगले उच्च मूल्य की पहचान कर सकते हैं cummax()। यदि आप उदाहरण के लिए प्रत्येक नए उच्च मान का स्थान चाहते हैं, तो आप cummax()मानों के अपने वेक्टर diff()को उन स्थानों की पहचान करने के लिए फ़ंक्शन में पास कर सकते हैं , जहां cummax()मूल्य बदल गया है। हम सदिश है

v <- c(4,6,3,2,-5,6,8,12,16)
cummax(v) will give us the vector
4  6  6  6  6  6  8 12 16

अब, यदि आप एक परिवर्तन का स्थान ढूंढना चाहते हैं, तो cummax()मेरे पास कई विकल्प हैं, जिनका मैं उपयोग करता हूं sign(diff(cummax(v)))। आपको खोए हुए पहले तत्व के कारण समायोजित करना होगा diff()। वेक्टर के लिए पूरा कोड vहोगा:

which(sign(diff(cummax(v)))==1)+1

मुझे लगता है कि आप प्रश्न को गलत समझते हैं। दूसरा उच्चतम मूल्य, लक्ष्य को ढूंढना है। यह आपको v से 12 तक पहुंचने में कैसे मदद करता है ... और तीसरे उच्चतम से 8 तक?
फ्रैंक

-1

आप sortइस तरह से कीवर्ड का उपयोग कर सकते हैं :

sort(unique(c))[1:N]

उदाहरण:

c <- c(4,2,44,2,1,45,34,2,4,22,244)
sort(unique(c), decreasing = TRUE)[1:5]

पहले 5 अधिकतम नंबर देंगे।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.