क्रमपरिवर्तन दोहराए बिना आर में कैसे फिर से भरना है?


13

आर में, यदि मैं सेट करता हूं (), और फिर किसी सूची को यादृच्छिक बनाने के लिए नमूना फ़ंक्शन का उपयोग करता हूं, तो क्या मैं गारंटी दे सकता हूं कि मैं एक ही क्रमपरिवर्तन उत्पन्न नहीं करूंगा?

अर्थात...

set.seed(25)
limit <- 3
myindex <- seq(0,limit)
for (x in seq(1,factorial(limit))) {
    permutations <- sample(myindex)
    print(permutations)
}

यह पैदा करता है

[1] 1 2 0 3
[1] 0 2 1 3
[1] 0 3 2 1
[1] 3 1 2 0
[1] 2 3 0 1
[1] 0 1 3 2

क्या छपे हुए सभी क्रमांकन अनूठे क्रमपरिवर्तन होंगे? या क्या इस पर अमल करने के तरीके के आधार पर कुछ संभावना है, कि मुझे कुछ दोहराए जा सकते हैं?

मैं दोहराए बिना गारंटी के ऐसा करने में सक्षम होना चाहता हूं। मुझे यह कैसे करना है?

(मैं भी अनुमति () की तरह एक फ़ंक्शन का उपयोग करने से बचना चाहता हूं, जिसमें सभी क्रमपरिवर्तन उत्पन्न करने के लिए एक बहुत ही यंत्रवत विधि है --- यह यादृच्छिक नहीं दिखता है।)

इसके अलावा, सिडेनोट --- ऐसा लगता है कि यह समस्या ओ ((एन!)!) है, अगर मैं गलत नहीं हूँ।


डिफ़ॉल्ट रूप से, 'नमूना' का तर्क 'प्रतिस्थापित' FALSE पर सेट है।
ओकराम

धन्यवाद ओकराम, लेकिन यह एक विशेष नमूने के भीतर काम कर रहा है। इसलिए यह सुनिश्चित करता है कि 0,1,2, और 3 एक ड्रॉ के भीतर दोहराए नहीं जाएंगे (इसलिए, मैं 0,1,2,2 ड्रा नहीं कर सकता), लेकिन मुझे नहीं पता कि यह गारंटी देता है कि दूसरा नमूना मैं 0123 के उसी क्रम को फिर से नहीं खींच सकता। यही मैं कार्यान्वयन-वार सोच रहा हूं, चाहे बीज को सेट करने से उस पुनरावृत्ति पर कोई प्रभाव पड़े।
मैट्रिचॉप्स

हाँ, यह है कि मैं क्या अंत में जवाब ;-) पढ़कर समझा जाता है
ocram

1
यदि limit12 से अधिक हो जाता है, तो R के लिए स्थान आवंटित करने का प्रयास करने पर आप RAM से बाहर निकल जाएंगे seq(1,factorial(limit))। (! 12 2 जीबी है, तो 13 के बारे में की आवश्यकता है 25 जीबी, 14 जीबी 350 के बारे में, आदि के बारे में की आवश्यकता होगी!)
whuber

2
1: n के सभी क्रमपरिवर्तन के यादृच्छिक क्रम उत्पन्न करने के लिए एक तेज, कॉम्पैक्ट और सुरुचिपूर्ण समाधान है , बशर्ते आप आराम से n स्टोर कर सकते हैं! 0: (n!) श्रेणी में पूर्णांक। यह संख्याओं के भाज्य आधार निरूपण के साथ क्रमपरिवर्तन का प्रत्यावर्तन सारणी निरूपण करता है।
whuber

जवाबों:


9

प्रश्न की कई मान्य व्याख्याएँ हैं। टिप्पणी - विशेष रूप से 15 या अधिक तत्वों के क्रमांकन का संकेत देने वाले एक की आवश्यकता है (15! = 1307674368000 बड़ा हो रहा है) - सुझाव दें कि जो चाहता था वह अपेक्षाकृत छोटा यादृच्छिक नमूना है, प्रतिस्थापन के बिना, सभी n! = n * (n-1) (n-2) ... * 2 * 1 1: n के क्रमपरिवर्तन। यदि यह सच है, तो कुछ हद तक कुशल समाधान मौजूद हैं।

निम्न फ़ंक्शन, rpermदो तर्कों n(नमूने mके क्रमपरिवर्तन का आकार ) और (आकार n के क्रमपरिवर्तन की संख्या ) को स्वीकार करता है । यदि m निकट या n से अधिक है, तो फ़ंक्शन को लंबा समय लगेगा और कई NA मान लौटाएंगे: यह उपयोग के लिए अभिप्रेत है जब n अपेक्षाकृत बड़ा हो (कहते हैं, 8 या अधिक) और m n से बहुत छोटा है! यह अब तक पाए गए क्रमपरिवर्तन के एक स्ट्रिंग प्रतिनिधित्व को कैशिंग करके काम करता है और तब तक नए क्रमपरिवर्तन (यादृच्छिक रूप से) उत्पन्न करता है जब तक कि एक नया नहीं मिलता है। यह R की साहचर्य सूची-अनुक्रमण क्षमता का शोषण करता है जो पहले से पाए गए क्रमपरिवर्तन की सूची को जल्दी से खोज लेता है।

rperm <- function(m, size=2) { # Obtain m unique permutations of 1:size

    # Function to obtain a new permutation.
    newperm <- function() {
        count <- 0                # Protects against infinite loops
        repeat {
            # Generate a permutation and check against previous ones.
            p <- sample(1:size)
            hash.p <- paste(p, collapse="")
            if (is.null(cache[[hash.p]])) break

            # Prepare to try again.
            count <- count+1
            if (count > 1000) {   # 1000 is arbitrary; adjust to taste
                p <- NA           # NA indicates a new permutation wasn't found
                hash.p <- ""
                break
            }
        }
        cache[[hash.p]] <<- TRUE  # Update the list of permutations found
        p                         # Return this (new) permutation
    }

    # Obtain m unique permutations.
    cache <- list()
    replicate(m, newperm())  
} # Returns a `size` by `m` matrix; each column is a permutation of 1:size.

कॉलम वैक्टर के replicateरूप में क्रमपरिवर्तन को वापस करने की प्रकृति है ; उदाहरण के लिए , निम्नलिखित मूल प्रश्न में एक उदाहरण प्रस्तुत करता है, ट्रांसपोज़्ड :

> set.seed(17)
> rperm(6, size=4)
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1    2    4    4    3    4
[2,]    3    4    1    3    1    2
[3,]    4    1    3    2    2    3
[4,]    2    3    2    1    4    1

टाइमिंग छोटे से मध्यम मूल्यों के लिए उत्कृष्ट हैं, लगभग 10,000 तक, लेकिन बड़ी समस्याओं के लिए नीचा दिखाते हैं। उदाहरण के लिए, n = 1000 तत्वों (10 मिलियन मानों का एक मैट्रिक्स) के m = 10,000 क्रमोन्नति का एक नमूना 10 सेकंड में प्राप्त किया गया था; n = 20 तत्वों के m = 20,000 क्रमोन्नति का एक नमूना 11 सेकंड के लिए आवश्यक था, भले ही आउटपुट (400,000 प्रविष्टियों का एक मैट्रिक्स) बहुत छोटा था; और n = 20 तत्वों के m = 100,000 क्रमांकन का नमूना नमूना 260 सेकंड के बाद निरस्त कर दिया गया (मेरे पास पूरा होने की प्रतीक्षा करने का धैर्य नहीं था)। यह स्केलिंग समस्या R के साहचर्य संबोधन में स्केलिंग अक्षमताओं से संबंधित प्रतीत होती है। 1000 या तो के समूहों में नमूने उत्पन्न करके, उसके चारों ओर काम कर सकता है, फिर उन नमूनों को एक बड़े नमूने में जोड़कर और डुप्लिकेट को हटा सकता है।

संपादित करें

हम कैश को दो कैश के पदानुक्रम में तोड़कर रैखिक असममित प्रदर्शन के पास प्राप्त कर सकते हैं , ताकि आर को एक बड़ी सूची के माध्यम से कभी भी खोज न करना पड़े। वैचारिक रूप से (हालांकि इसे लागू नहीं किया गया है), क्रमचय के पहले तत्वों द्वारा अनुक्रमित एक सरणी बनाएं । इस सरणी में प्रविष्टियाँ उन सभी तत्वों को साझा करने वाले सभी क्रमपरिवर्तन की सूची हैं। यह जांचने के लिए कि क्या एक क्रमचय देखा गया है, कैश में अपनी प्रविष्टि को खोजने के लिए उसके पहले तत्वों का उपयोग करें और फिर उस प्रविष्टि के भीतर उस क्रमचय की खोज करें। हम सभी सूचियों के अपेक्षित आकार को संतुलित करने के लिए को चुन सकते हैं । वास्तविक कार्यान्वयन का उपयोग नहीं करता हैk k k kkkkkk-फोल्ड सरणी, जो पर्याप्त सामान्यता में प्रोग्राम करना मुश्किल होगा, लेकिन इसके बजाय एक अन्य सूची का उपयोग करता है।

यहां कुछ समय के लिए क्रमपरिवर्तन आकारों और अनुरोधित अलग-अलग परमिटों की संख्या के लिए कुछ बीता हुआ समय है:

 Number Size=10 Size=15 Size=1000 size=10000 size=100000
     10    0.00    0.00      0.02       0.08        1.03
    100    0.01    0.01      0.07       0.64        8.36
   1000    0.08    0.09      0.68       6.38
  10000    0.83    0.87      7.04      65.74
 100000   11.77   10.51     69.33
1000000  195.5   125.5

(आकार = 10 से आकार = 15 तक स्पष्ट रूप से विषम गति इसलिए है क्योंकि कैश का पहला स्तर आकार = 15 के लिए बड़ा है, दूसरे स्तर की सूचियों में प्रविष्टियों की औसत संख्या को कम करता है, जिससे आर की साहचर्य खोज को गति मिलती है। रैम में लागत, निष्पादन को ऊपरी स्तर के कैश आकार को बढ़ाकर तेजी से बनाया जा सकता है। बस k.head1 से बढ़ रहा है (जो ऊपरी स्तर के आकार को 10 से गुणा करता है) rperm(100000, size=10)उदाहरण के लिए 11.77 सेकंड से 8.72 सेकंड तक फैला है, जो ऊपरी स्तर का बना रहा है। कैश 10 गुना बड़ा है, फिर भी कोई सराहनीय लाभ नहीं हुआ, 8.51 सेकंड में देखा।)

10 तत्वों के 1,000,000 अद्वितीय क्रमपरिवर्तन के मामले को छोड़कर (सभी 10 का पर्याप्त हिस्सा! = 3.63 मिलियन ऐसे क्रमपरिवर्तन के बारे में), व्यावहारिक रूप से कभी टकराव का पता नहीं चला। इस असाधारण मामले में, 169,301 टकराव हुए, लेकिन पूरी तरह से असफलताएं (एक मिलियन अद्वितीय क्रमपरिवर्तन वास्तव में प्राप्त हुए थे)।

ध्यान दें कि बड़े क्रमचय आकार (20 या अधिक से अधिक) के साथ, एक नमूने में भी दो समान क्रमपरिवर्तन प्राप्त करने की संभावना है, जितना कि 1,000,000,000 बड़े पैमाने पर छोटा है। इस प्रकार, यह समाधान उन स्थितियों में मुख्य रूप से लागू होता है जहां (ए) ( और बीच (बी) के अनूठे क्रमपरिवर्तन की बड़ी संख्या उत्पन्न होती है, लेकिन फिर भी, (सी) सभी तुलना में काफी कम हैक्रमपरिवर्तन की आवश्यकता है।n = 15 n !n=5n=15n!

वर्किंग कोड इस प्रकार है।

rperm <- function(m, size=2) { # Obtain m unique permutations of 1:size
    max.failures <- 10

    # Function to index into the upper-level cache.
    prefix <- function(p, k) {    # p is a permutation, k is the prefix size
        sum((p[1:k] - 1) * (size ^ ((1:k)-1))) + 1
    } # Returns a value from 1 through size^k

    # Function to obtain a new permutation.
    newperm <- function() {
        # References cache, k.head, and failures in parent context.
        # Modifies cache and failures.        

        count <- 0                # Protects against infinite loops
        repeat {
            # Generate a permutation and check against previous ones.
            p <- sample(1:size)
            k <- prefix(p, k.head)
            ip <- cache[[k]]
            hash.p <- paste(tail(p,-k.head), collapse="")
            if (is.null(ip[[hash.p]])) break

            # Prepare to try again.
            n.failures <<- n.failures + 1
            count <- count+1
            if (count > max.failures) {  
                p <- NA           # NA indicates a new permutation wasn't found
                hash.p <- ""
                break
            }
        }
        if (count <= max.failures) {
            ip[[hash.p]] <- TRUE      # Update the list of permutations found
            cache[[k]] <<- ip
        }
        p                         # Return this (new) permutation
    }

    # Initialize the cache.
    k.head <- min(size-1, max(1, floor(log(m / log(m)) / log(size))))
    cache <- as.list(1:(size^k.head))
    for (i in 1:(size^k.head)) cache[[i]] <- list()

    # Count failures (for benchmarking and error checking).
    n.failures <- 0

    # Obtain (up to) m unique permutations.
    s <- replicate(m, newperm())
    s[is.na(s)] <- NULL
    list(failures=n.failures, sample=matrix(unlist(s), ncol=size))
} # Returns an m by size matrix; each row is a permutation of 1:size.

यह करीब है, लेकिन मुझे लगता है कि मुझे कुछ त्रुटियां मिलती हैं, जैसे 1, 2, और 4, लेकिन मुझे लगता है कि मैं देख रहा हूं कि आपका क्या मतलब है और इसके साथ काम करने में सक्षम होना चाहिए। धन्यवाद! > rperm(6,3) $failures [1] 9 $sample [,1] [,2] [,3] [1,] 3 1 3 [2,] 2 2 1 [3,] 1 3 2 [4,] 1 2 2 [5,] 3 3 1 [6,] 2 1 3
1

4

uniqueसही तरीके से प्रयोग करना चाहिए:

set.seed(2)
limit <- 3
myindex <- seq(0,limit)

endDim<-factorial(limit)
permutations<-sample(myindex)

while(is.null(dim(unique(permutations))) || dim(unique(permutations))[1]!=endDim) {
    permutations <- rbind(permutations,sample(myindex))
}
# Resulting permutations:
unique(permutations)

# Compare to
set.seed(2)
permutations<-sample(myindex)
for(i in 1:endDim)
{
permutations<-rbind(permutations,sample(myindex))
}
permutations
# which contains the same permutation twice

कोड को ठीक से नहीं समझाने के लिए क्षमा करें। मैं अब थोड़ी हड़बड़ी में हूं, लेकिन बाद में आपके किसी भी सवाल का जवाब देने में मुझे खुशी है। इसके अलावा, मुझे उपरोक्त कोड की गति के बारे में कोई पता नहीं है ...
MånsT

1
मैंने क्रियाशील किया कि आपने मुझे इस तरह क्या दिया: `मायपरम <- फ़ंक्शन (सीमा) {myindex <- seq (0, सीमा) endDim <-factorial (सीमा) क्रमपरिवर्तन <-sample (myindex) जबकि (is.null (अद्वितीय) (क्रमपरिवर्तन))) || मंद (अद्वितीय (क्रमपरिवर्तन)) [1]! = अंतडिम) {क्रमपरिवर्तन <- rbind (क्रमपरिवर्तन, नमूना (myindex))} लौटाना (अद्वितीय (क्रमपरिवर्तन))} '' यह काम करता है, लेकिन जब मैं कर सकते हैं सीमा = 6, सीमा = 7 मेरे कंप्यूटर को ज़्यादा गरम करता है। = पीआई को लगता है कि अभी भी
इसको कम

@Mittenchops, आप यह क्यों कहते हैं कि हमें क्रमपरिवर्तन दोहराए बिना R में पुन: उपयोग के लिए अद्वितीय का उपयोग करने की आवश्यकता है? धन्यवाद।
फ्रैंक

2

मैं आपके पहले प्रश्न को थोड़ा सा बढ़ाता हूं, और यह सुझाव देता हूं कि यदि आपके अपेक्षाकृत छोटे वैक्टर के साथ काम कर रहे हैं, तो आप बस उपयोग करने वाले सभी क्रमों को उत्पन्न कर सकते हैं permnऔर उन्हें बेतरतीब ढंग से उपयोग करने वालों को ऑर्डर कर सकते हैं sample:

x <- combinat:::permn(1:3)
> x[sample(factorial(3),factorial(3),replace = FALSE)]
[[1]]
[1] 1 2 3

[[2]]
[1] 3 2 1

[[3]]
[1] 3 1 2

[[4]]
[1] 2 1 3

[[5]]
[1] 2 3 1

[[6]]
[1] 1 3 2

मुझे यह बहुत पसंद है, और मुझे यकीन है कि यह सही सोच है। लेकिन मेरी समस्या ने मुझे 10 तक जाने वाले एक अनुक्रम का उपयोग किया है। Permn () factorial (7) और factorial (8) के बीच काफी धीमा था, इसलिए मुझे लगता है कि 9 और 10 निषेधात्मक रूप से विशाल होने जा रहे हैं।
Mittenchops

@Mittenchops सच है, लेकिन यह अभी भी संभव है कि आपको वास्तव में केवल एक बार, सही गणना करने की आवश्यकता है? उन्हें एक फ़ाइल में सहेजें, और तब उन्हें लोड करें जब आपको उनकी आवश्यकता हो और पूर्व-निर्धारित सूची से "नमूना"। तो आप धीमी गणना permn(10)या जो कुछ भी एक बार कर सकते हैं।
जोरान

ठीक है, लेकिन अगर मैं सभी क्रमचय कहीं रख रहा हूं, तो यह भी फैक्टरियल (15) के आसपास टूट जाता है --- बस स्टोर करने के लिए बहुत ज्यादा जगह। इसलिए मैं सोच रहा हूं कि क्या बीज की स्थापना मुझे सामूहिक रूप से नमूना क्रमांकन की अनुमति देगी --- और यदि नहीं, तो ऐसा करने के लिए एक एल्गोरिथ्म है।
Mittenchops

@ मेन्टूपॉप्स एक बीज को स्थापित करने से प्रदर्शन प्रभावित नहीं होगा, यह सिर्फ उसी शुरुआत की गारंटी देता है जब आप PRNG को कॉल करते हैं।
रोमन लुसट्रिक

1
@Mitten इसके लिए सहायता देखें set.seed: यह वर्णन करता है कि RNG की स्थिति को कैसे बचाया जाए और बाद में इसे पुनर्स्थापित किया जाए।
whuber
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.