开发者

random.sample() returning the same random sequence every time?

I'm using python's random.sample(population, k) function to generate a set of random values from a list to create new permutations of that list. The issue is that each time it runs through a loop, it's generating the exact same random sequence. Why is this? I even used random.seed(i) so that the i variable (changing each time through the loop) would seed it a different value each time. Still the same sequence. What gives!@

Here is how I'm using it:

def initialBuild(self):
    alphabet = self.alphabet
    for i in range (self.length):
        value = random.sample(alphabet, 1)
        alphabet.remove(value[0])
        self.finalWord.append(value[0])
    print "Final word = ", self.finalWord

which is just being called from the init method of an Individual class. The init method is being called like so...

def buildPopulation(self, alphabet):
    #Initialize empty individuals
    for i in range(POPULATION_SIZE):
        self.population.append(Individual(alphabet))

and the init method looks like this...

def __init__(self, alphabet = []):
    self.length = len(alphabet)
    self.alphabet = alphabet
    self.initialBuild()

At the end, I'm printing a final word. Here is the output of running this method twice:

Final Word = [[1150, 1160], [720, 635], [95, 260], [595, 360], [770, 610], [830, 610], [25, 185], [520, 585], [605, 625], [410, 250], [555, 815], [880, 660], [300, 465], [1220, 580], [1215, 245], [1250, 400], [565, 575], [1605, 620], [845, 680], [1170, 65], [795, 645], [525, 1000], [760, 650], [580, 1175], [420, 555], [25, 230], [345, 750], [700, 500], [725, 370], [1530, 5], [1740, 245], [875, 920], [415, 635], [1340, 725], [975, 580], [575, 665], [1465, 200], [830, 485], [660, 180], [475, 960], [685, 595], [145, 665], [510, 875], [845, 655], [650, 1130], [945, 685], [480开发者_如何学Python, 415], [700, 580], [560, 365], [685, 610], [835, 625], [1320, 315]]

Final Word = [[1150, 1160], [720, 635], [95, 260], [595, 360], [770, 610], [830, 610], [25, 185], [520, 585], [605, 625], [410, 250], [555, 815], [880, 660], [300, 465], [1220, 580], [1215, 245], [1250, 400], [565, 575], [1605, 620], [845, 680], [1170, 65], [795, 645], [525, 1000], [760, 650], [580, 1175], [420, 555], [25, 230], [345, 750], [700, 500], [725, 370], [1530, 5], [1740, 245], [875, 920], [415, 635], [1340, 725], [975, 580], [575, 665], [1465, 200], [830, 485], [660, 180], [475, 960], [685, 595], [145, 665], [510, 875], [845, 655], [650, 1130], [945, 685], [480, 415], [700, 580], [560, 365], [685, 610], [835, 625], [1320, 315]]

Notice that these two are absolutely identical..

Edit: Since I'm having a hard time picking out code that I think will be useful, yet short enough to go into this post, I've posted a bunch of it on pastebin. http://pastebin.com/f5f068391 This is hopefully a better alternative.. Thanks again


I'm not sure what you mean by "generating the exact same random sequence". Since you only give us a snippet that can't be run on its own, it's quite possible that there are bugs in other parts of your code that you choose not to show us -- I've tried adding the absolutely minimal amount of code needed to make your snippet run, i.e.:

import random

import string
def self(): pass
self.alphabet = list(string.lowercase)
self.finalWord = []
self.length = 4

for x in range(5):
  alphabet = self.alphabet
  for i in range (self.length):
      value = random.sample(alphabet, 1)
      alphabet.remove(value[0])
      self.finalWord.append(value[0])
  print "Final word = ", self.finalWord

and here's what I see when I run this self-sufficient script a few times:

$ python sa.py 
Final word =  ['y', 'm', 'u', 'z']
Final word =  ['y', 'm', 'u', 'z', 'h', 'b', 'c', 's']
Final word =  ['y', 'm', 'u', 'z', 'h', 'b', 'c', 's', 'x', 'l', 'r', 'n']
Final word =  ['y', 'm', 'u', 'z', 'h', 'b', 'c', 's', 'x', 'l', 'r', 'n', 'q', 'a', 'k', 'e']
Final word =  ['y', 'm', 'u', 'z', 'h', 'b', 'c', 's', 'x', 'l', 'r', 'n', 'q', 'a', 'k', 'e', 'p', 'd', 'j', 'w']
$ python sa.py 
Final word =  ['k', 'v', 'o', 'd']
Final word =  ['k', 'v', 'o', 'd', 'q', 'p', 'w', 'l']
Final word =  ['k', 'v', 'o', 'd', 'q', 'p', 'w', 'l', 'n', 'u', 'g', 't']
Final word =  ['k', 'v', 'o', 'd', 'q', 'p', 'w', 'l', 'n', 'u', 'g', 't', 'i', 'r', 'e', 'f']
Final word =  ['k', 'v', 'o', 'd', 'q', 'p', 'w', 'l', 'n', 'u', 'g', 't', 'i', 'r', 'e', 'f', 's', 'c', 'j', 'z']
$ python sa.py 
Final word =  ['o', 'a', 'g', 't']
Final word =  ['o', 'a', 'g', 't', 'k', 'j', 'y', 'w']
Final word =  ['o', 'a', 'g', 't', 'k', 'j', 'y', 'w', 'z', 'l', 'i', 's']
Final word =  ['o', 'a', 'g', 't', 'k', 'j', 'y', 'w', 'z', 'l', 'i', 's', 'u', 'p', 'f', 'm']
Final word =  ['o', 'a', 'g', 't', 'k', 'j', 'y', 'w', 'z', 'l', 'i', 's', 'u', 'p', 'f', 'm', 'h', 'e', 'q', 'v']

As you see, that's anything but "the exact same random sequence" -- it's changing each and every run, just as expected.

I imagine I've read your mind incorrectly when trying to make your code executable, and that you mean it to be used very differently than my tiny script uses it -- but then mind-reading is an unreliable art (which is why it would be so much better if you posted a self-contained, runnable example, made as tiny as it can be while still reproducing your problem, rather than forcing us to try and read your mind!-).

Why don't you tweak the stand-alone script I've just posted by the minimal needed amount to make it closer to your intended use, and to reproduce the problem you observe? Then it will be so much easier and more productive for us to spot any issue your code may have and suggest the best way to fix it!

Edit: the OP's code as pasted in pastebin has two bugs that have absolutely nothing to do with random and combine to produce the OP's observed behavior. Here's the relevant part of the code, redacted:

class Phenotype:
   ...
   chromosome = []

   def __init__(self, alleles = []):
    self.length = len(alleles)
    self.alleles = alleles
    self.initialBuild()

   def initialBuild(self):
    alleleSet = self.alleles
    for i in range (self.length):
        value = random.sample(alleleSet, 1)
        alleleSet.remove(value[0])
        self.chromosome.append(value[0])

OK, there's another bug here (using old, legacy classes in new code, instead of shiny new style classes which should always be used), but that's not what's biting the OP (yet), so we'll just mention it in passing;-).

Bug 1: since neither __init__ nor any other method ever do an assignment self.chromosome = ..., all the mentions of self.chromosome in the code actually refer to the one and only list Phenotype.chromosome which all instances of the Phenotype class share. So inevitably all such instances will always have exactly the same, identical chromosome, no matter what. Fix: add self.chromosome = [] in __init__ (better also to remove the class-level variables because they do no good whatsoever and only confuse the issue).

Bug 2: look at the following lines of code again to spot it:

    self.alleles = alleles
       ...
    alleleSet = self.alleles
       ...
        alleleSet.remove(value[0])

Got it? self.alleles and the local name alleleSet are all references to exactly the one and the same alleles set (or list, actually) that's passed in -- so the remove call i altering the collection that's passed in. So that collection's left empty after the very first Phenotype is instantiated (which is why despite Bug 1 the chromosome doesn't keep growing: because the alleles collection is left empty forevermore).

Fix: make a copy, e.g. alleleSet = list(self.alleles), to avoid damaging the original collection.

Better fix: what you're doing is an extremely convoluted way to spell much simpler code such as:

self.chromosome = list(self.alleles)
random.shuffle(self.chromosome)

i.e., just get a random permutation. Building a random permutation by doing N separate samples and removing each sample from the collection as it's generated is a really round-about, slow and complicated way to attack an extremely simple problem!-)


Do not change the seed for every sample. That breaks the random number generator and absolutely assures that it's not random.

Set the seed exactly once. And never change that value again while your application is running.

The Random Number generator starts with a known, constant seed. Each time you run, you should get the same sequence. Setting no seed gives a predictable sequence. Setting any constant seed (like i in the example) gives a predictable sequence.

If you want an unpredictable sequence, you need an unpredictable seed. Use the time-of-day, or some bytes read from /dev/random as seed values. Once.

Consider this as a simplification.

word = random.sample( alphabet, length )

It seems to produce different sequences for me.

>>> import string, random
>>> alphabet = string.ascii_lowercase
>>> random.sample( alphabet, 5 )
['x', 'p', 's', 'k', 'h']
>>> random.sample( alphabet, 5 )
['y', 'h', 'u', 'n', 'd']


value = random.sample(alphabet, 1) 

From what I've gathered by trial and error, this iterates a random val from your population, and assigns it to "value". After that, "value" will always be that first random val. It doesn't iterate randomly again, it just sticks with the val that was assigned to value.

Instead of:

self.finalWord.append(value[0])

Try this:

self.finalWord.append(random.sample(alphabet, 1)[0])

I haven't tested this, so I'm not 100% sure it will work. But regardless, if I'm not mistaken, it should elucidate your problem.


I was wondering the same thing, then I realized it's because Python locks the random value until you run the random number code again. In other words, the random number function needs to be IN the while-loop, and not above it. Doing the latter causes the same established random number to repeat again and again once the loop starts.

Here's a simple example that runs 20 Trials of a Random Integer between 1 and 10:

#CORRECT version:
x = 1
y = 1
while x<=20:
    number = random.randint(1,10)
    print("Trial", y, "is", number)
    x = x + 1
    y = y + 1

#INCORRECT version:

number = random.randint(1,10)
x = 1
y = 1
while x<=20:
    print("Trial", y, "is", number)
    x = x + 1
    y = y + 1
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜