Мне нужна функция Python, которая будет выводить случайную строку из 4 различных символов, когда заданы требуемые вероятности символов - PullRequest
2 голосов
/ 13 апреля 2009

Например, Функция может быть что-то вроде def RandABCD (n, .25, .34, .25, .25):

Где n - длина генерируемой строки, а следующие числа - желаемые вероятности A, B, C, D.

Я бы подумал, что это довольно просто, но у меня проблемы с созданием работающей программы. Любая помощь будет принята с благодарностью.

Ответы [ 6 ]

4 голосов
/ 13 апреля 2009

Вот код для выбора одного взвешенного значения. Вы должны быть в состоянии взять это отсюда. Для выполнения работы используются bisect и random .

from bisect import bisect
from random import random

def WeightedABCD(*weights):
  chars = 'ABCD'
  breakpoints = [sum(weights[:x+1]) for x in range(4)]
  return chars[bisect(breakpoints, random())]

Назовите это так: WeightedABCD(.25, .34, .25, .25).

РЕДАКТИРОВАТЬ: Вот версия, которая работает, даже если веса не складываются до 1,0:

from bisect import bisect_left
from random import uniform

def WeightedABCD(*weights):
  chars = 'ABCD'
  breakpoints = [sum(weights[:x+1]) for x in range(4)]
  return chars[bisect_left(breakpoints, uniform(0.0,breakpoints[-1]))]
2 голосов
/ 13 апреля 2009

Для четырех букв, вот что-то быстро с моей головы:

from random import random

def randABCD(n, pA, pB, pC, pD):
    # assumes pA + pB + pC + pD == 1
    cA = pA
    cB = cA + pB
    cC = cB + pC
    def choose():
        r = random()
        if r < cA:
           return 'A'
        elif r < cB:
           return 'B'
        elif r < cC:
           return 'C'
        else:
           return 'D'
    return ''.join([choose() for i in xrange(n)])

У меня нет сомнений, что это можно сделать намного чище / короче, сейчас я немного тороплюсь.

Причина, по которой я не был бы доволен Дэвидом в ответе Дакоты об использовании списка повторяющихся символов, заключается в том, что в зависимости от ваших вероятностей, возможно, не удастся создать список с дубликатами в нужных числах для имитации вероятностей, которые вы хочу. (Ну, я думаю, это всегда возможно, но вам может понадобиться огромный список - что, если ваши вероятности были 0,11235442079, 0,4072777384, 0,2297927874, 0,25057505341?)

РЕДАКТИРОВАТЬ : вот более понятная универсальная версия, которая работает с любым количеством букв с любыми весами:

from bisect import bisect
from random import uniform

def rand_string(n, content):
    ''' Creates a string of letters (or substrings) chosen independently
        with specified probabilities. content is a dictionary mapping
        a substring to its "weight" which is proportional to its probability,
        and n is the desired number of elements in the string.

        This does not assume the sum of the weights is 1.'''
    l, cdf = zip(*[(l, w) for l, w in content.iteritems()])
    cdf = list(cdf)
    for i in xrange(1, len(cdf)):
        cdf[i] += cdf[i - 1]
    return ''.join([l[bisect(cdf, uniform(0, cdf[-1]))] for i in xrange(n)])        
2 голосов
/ 13 апреля 2009

Случайный класс довольно мощный в Python. Вы можете создать список с нужными символами в соответствующих весах, а затем использовать random.choice для получения выбора.

Сначала убедитесь, что вы делаете случайный импорт.

Например, допустим, вы хотели получить действительно случайную строку из A, B, C или D. 1. Создайте список с персонажами li = ['A', 'B', 'C', 'D']

  1. Затем получите значения из него, используя random.choice. output = "" .join ([random.choice (li) для i в диапазоне (0, n)])

Вы можете легко сделать это функцией с n в качестве параметра.

В приведенном выше случае у вас есть равный шанс получить A, B, C или D.

Вы можете использовать повторяющиеся записи в списке для повышения вероятности символов. Так, например, допустим, что вы хотели 50% -ый шанс A и 25% -ый шанс B и C соответственно. У вас может быть такой массив:

li = ['A', 'A', 'B', 'C']

и т. Д.

Было бы нетрудно параметризовать символы, поступающие с желаемыми весами, моделировать, что я буду использовать словарь.

Characterbasis = {'A': 25, 'B': 25, 'C': 25, 'D': 25}

Сделайте, чтобы первый параметр, а второй был длиной строки, и используйте приведенный выше код для генерации вашей строки.

0 голосов
/ 14 апреля 2009

Спасибо всем за помощь, мне удалось кое-что выяснить, в основном с этой информацией. Для своей особой необходимости я сделал что-то вроде этого:

import random
#Create a function to randomize a given string
def makerandom(seq):
    return ''.join(random.sample(seq, len(seq)))
def randomDNA(n, probA=0.25, probC=0.25, probG=0.25, probT=0.25):
    notrandom=''
    A=int(n*probA)
    C=int(n*probC)
    T=int(n*probT)
    G=int(n*probG)

#The remainder part here is used to make sure all n are used, as one cannot
#have half an A for example.
    remainder=''
    for i in range(0, n-(A+G+C+T)):
        ramainder+=random.choice("ATGC")
    notrandom=notrandom+ 'A'*A+ 'C'*C+ 'G'*G+ 'T'*T + remainder
    return makerandom(notrandom)
0 голосов
/ 13 апреля 2009

Хм, что-то вроде:

import random
class RandomDistribution:
    def __init__(self, kv):
        self.entries = kv.keys()
        self.where = []
        cnt = 0
        for x in self.entries:
            self.where.append(cnt)
            cnt += kv[x]
        self.where.append(cnt)   

    def find(self, key):
        l, r = 0, len(self.where)-1
        while l+1 < r:
           m = (l+r)/2
           if self.where[m] <= key:
               l=m
           else:
               r=m
        return self.entries[l]

    def randomselect(self):
        return self.find(random.random()*self.where[-1])

rd = RandomDistribution( {"foo": 5.5, "bar": 3.14, "baz": 2.8 } )
for x in range(1000):
    print rd.randomselect()

должно пройти большую часть пути ...

0 голосов
/ 13 апреля 2009

Вот примерное представление о том, что может вам подойти

import random as r

def distributed_choice(probs):
    r= r.random()
    cum = 0.0

    for pair in probs:
        if (r < cum + pair[1]):
            return pair[0]          
        cum += pair[1]

Параметр probs принимает список пар вида (объект, вероятность). Предполагается, что сумма вероятностей равна 1 (в противном случае ее тривиально нормализовать).

Чтобы использовать его, просто выполните:

''.join([distributed_choice(probs)]*4)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...