random.sample () возвращать одну и ту же случайную последовательность каждый раз? - PullRequest
8 голосов
/ 30 января 2010

Я использую функцию Python random.sample (population, k) для генерации набора случайных значений из списка для создания новых перестановок этого списка. Проблема в том, что каждый раз, когда он проходит через цикл, он генерирует точно такую ​​же случайную последовательность. Почему это? Я даже использовал random.seed (i), чтобы переменная i (изменяющаяся каждый раз в цикле) каждый раз получала новое значение. Все та же последовательность. Что дает! @

Вот как я это использую:

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

, который вызывается только из метода init индивидуального класса. Метод init вызывается так ...

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

и метод init выглядит следующим образом ...

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

В конце я печатаю последнее слово. Вот результат запуска этого метода дважды:

Последнее слово = [[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]]

Последнее слово = [[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]]

Обратите внимание, что эти два абсолютно идентичны ..

Редактировать: Так как мне трудно выбрать код, который, я думаю, будет полезен, но достаточно короток, чтобы перейти к этому сообщению, я опубликовал его на pastebin. http://pastebin.com/f5f068391 Это, надеюсь, лучшая альтернатива .. Еще раз спасибо

Ответы [ 4 ]

14 голосов
/ 30 января 2010

Я не уверен, что вы подразумеваете под "генерацией точно такой же случайной последовательности". Поскольку вы даете нам только фрагмент кода, который не может быть запущен сам по себе, вполне возможно, что в других частях вашего кода есть ошибки, которые вы решили не показывать нам - я попытался добавить абсолютно минимальный объем кода необходим для запуска вашего фрагмента, то есть:

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

и вот что я вижу, когда запускаю этот самодостаточный скрипт несколько раз:

$ 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']

Как вы видите, это что-то , но"точно такая же случайная последовательность" - он меняет каждый прогон, как и ожидалось.

Я полагаю, что я неправильно прочитал ваши мысли, пытаясь сделать ваш код исполняемым, и вы подразумеваете, что он будет использоваться совсем иначе, чем мой крошечный скрипт, но тогда чтение мыслей - ненадежное искусство (которое почему было бы намного лучше, если бы вы опубликовали отдельный, выполнимый пример, сделанный настолько малым, насколько это возможно, при воспроизведении вашей проблемы, вместо того, чтобы заставлять нас пытаться читать ваши мысли! -) .

Почему бы вам не настроить только что опубликованный автономный скрипт на минимально необходимую сумму, чтобы приблизить его к предполагаемому использованию и воспроизвести проблему, которую вы наблюдаете? Тогда Нам будет намного проще и продуктивнее обнаружить любую проблему, которая может возникнуть в вашем коде, и предложить лучший способ ее исправить!

Редактировать : код OP, вставленный в pastebin, имеет две ошибки, которые абсолютно не связаны с random и объединяются, чтобы создать наблюдаемое поведение OP. Вот соответствующая часть кода, отредактированная:

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

Хорошо, здесь есть еще одна ошибка (использование старых, устаревших классов в новом коде вместо блестящих новых стилевых классов, которые всегда должны использоваться), но это не то, что кусает OP (пока), поэтому мы просто упомянем об этом мимоходом; -).

Ошибка 1: поскольку ни __init__, ни какой-либо другой метод никогда не выполняют присваивание self.chromosome = ..., все упоминания self.chromosome в коде фактически относятся к единственному списку Phenotype.chromosome, в котором все экземпляры Phenotype классная доля. Так что неизбежно все такие экземпляры будут всегда иметь абсолютно одинаковые, идентичные chromosome, несмотря ни на что. Исправление: добавьте self.chromosome = [] в __init__ (лучше также удалить переменные уровня класса, потому что они не приносят никакой пользы и только запутывают проблему).

Ошибка 2: посмотрите на следующие строки кода еще раз, чтобы определить его:

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

Понял? self.alleles и локальное имя alleleSet являются ссылками на точно один и тот же набор alleles (или список, фактически), который был передан - так что remove вызывает i изменяя коллекцию, которая была передана. Таким образом, эта коллекция остается пустой после создания самого первого фенотипа (именно поэтому, несмотря на ошибку 1, хромосома не продолжает расти: потому что коллекция аллелей остается пустой навсегда).

Исправлено: сделать копию, например. alleleSet = list(self.alleles), чтобы не повредить оригинальную коллекцию.

Лучшее исправление: то, что вы делаете, это чрезвычайно запутанный способ написания гораздо более простого кода, такого как:

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

Т.е. просто получите случайную перестановку. Создание произвольной перестановки путем создания N отдельных выборок и удаления каждой выборки из коллекции по мере ее создания - это действительно обходной, медленный и сложный способ решения чрезвычайно простой проблемы! -)

6 голосов
/ 30 января 2010

Не меняйте семена для каждого образца. Это ломает генератор случайных чисел и абсолютно гарантирует, что он не случайный.

Установите семя ровно один раз. И никогда больше не меняйте это значение во время работы приложения.

Генератор случайных чисел запускается с известного постоянного числа. Каждый раз, когда вы бежите, вы должны получить одну и ту же последовательность. Установка без начального числа дает предсказуемую последовательность. Установка любого константы (например, i в примере) дает предсказуемую последовательность.

Если вам нужна непредсказуемая последовательность, вам нужно непредсказуемое начальное число. Используйте время дня или несколько байтов, считанных из / dev / random, в качестве начальных значений. Один раз.

Считайте это упрощением.

word = random.sample( alphabet, length )

Похоже, у меня разные последовательности.

>>> 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']
1 голос
/ 16 июня 2017

Мне было интересно то же самое, потом я понял, что это потому, что Python блокирует случайное значение, пока вы снова не запустите код случайного числа. Другими словами, функция случайных чисел должна находиться внутри цикла while, а не над ним. Выполнение последнего заставляет одно и то же установленное случайное число повторяться снова и снова, как только начинается цикл.

Вот простой пример, который запускает 20 испытаний случайного целого числа от 1 до 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
1 голос
/ 18 марта 2017
value = random.sample(alphabet, 1) 

Исходя из того, что я собрал методом проб и ошибок, он выполняет итерацию случайного значения из вашего населения и присваивает ему значение После этого «value» всегда будет первым случайным значением val. Он снова не повторяется случайным образом, он просто придерживается значения val, которое было присвоено значению.

Вместо:

self.finalWord.append(value[0])

Попробуйте это:

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

Я не проверял это, поэтому я не уверен на 100%, что это будет работать. Но независимо от того, если я не ошибаюсь, это должно выяснить вашу проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...