다른 값에 대한 확률이있는 파일이 있습니다.
1 0.1
2 0.05
3 0.05
4 0.2
5 0.4
6 0.2
이 분포를 사용하여 난수를 생성하고 싶습니다. 이를 처리하는 기존 모듈이 있습니까? 자체적으로 코딩하는 것은 매우 간단합니다 (누적 밀도 함수 작성, 임의의 값 [0,1] 생성 및 해당 값 선택). 이것은 일반적인 문제 여야하며 누군가가 함수 / 모듈을 생성 한 것 같습니다. 그것.
생일 목록 (표준 random
모듈의 배포를 따르지 않음)을 생성하고 싶기 때문에 이것이 필요합니다 .
답변
scipy.stats.rv_discrete
당신이 원하는 것일 수도 있습니다. values
매개 변수 를 통해 확률을 제공 할 수 있습니다 . 그런 다음 rvs()
분포 객체 의 방법 을 사용하여 난수를 생성 할 수 있습니다.
코멘트에 유진 Pakhomov에 의해 지적, 당신은 또한 전달할 수 p
에 키워드 매개 변수 numpy.random.choice()
, 예를
numpy.random.choice(numpy.arange(1, 7), p=[0.1, 0.05, 0.05, 0.2, 0.4, 0.2])
Python 3.6 이상을 사용 random.choices()
하는 경우 표준 라이브러리에서 사용할 수 있습니다 . Mark Dickinson 의 답변을 참조하십시오 .
답변
Python 3.6부터는 Python의 표준 라이브러리에 솔루션이 random.choices
있습니다.
사용법 예 : OP 질문에있는 것과 일치하는 모집단과 가중치를 설정해 보겠습니다.
>>> from random import choices
>>> population = [1, 2, 3, 4, 5, 6]
>>> weights = [0.1, 0.05, 0.05, 0.2, 0.4, 0.2]
이제 choices(population, weights)
단일 샘플을 생성합니다.
>>> choices(population, weights)
4
선택적 키워드 전용 인수를 k
사용하면 한 번에 둘 이상의 샘플을 요청할 수 있습니다. 이것은 random.choices
샘플을 생성하기 전에 호출 될 때마다 수행 해야하는 준비 작업이 있기 때문에 유용 합니다. 한 번에 많은 샘플을 생성하면 준비 작업을 한 번만 수행하면됩니다. 여기서 우리는 백만 개의 샘플을 생성하고 collections.Counter
우리가 얻는 분포가 우리가 준 가중치와 대략 일치하는지 확인하는 데 사용 합니다.
>>> million_samples = choices(population, weights, k=10**6)
>>> from collections import Counter
>>> Counter(million_samples)
Counter({5: 399616, 6: 200387, 4: 200117, 1: 99636, 3: 50219, 2: 50025})
답변
CDF를 사용하여 목록을 생성하면 이진 검색을 사용할 수 있다는 이점이 있습니다. 전처리를 위해 O (n) 시간과 공간이 필요하지만 O (k log n)에서 k 개의 숫자를 얻을 수 있습니다. 일반적인 파이썬리스트는 비효율적이기 때문에 array
모듈 을 사용할 수 있습니다 .
일정한 공간을 고집하면 다음을 수행 할 수 있습니다. O (n) 시간, O (1) 공간
def random_distr(l):
r = random.uniform(0, 1)
s = 0
for item, prob in l:
s += prob
if s >= r:
return item
return item # Might occur because of floating point inaccuracies
답변
아마 늦었을 수도 있습니다. 그러나 매개 변수를 numpy.random.choice()
전달하여을 사용할 수 있습니다 p
.
val = numpy.random.choice(numpy.arange(1, 7), p=[0.1, 0.05, 0.05, 0.2, 0.4, 0.2])
답변
(좋아요, 나는 당신이 수축 포장을 요구한다는 것을 알고 있지만, 아마도 자체 개발 솔루션은 당신의 취향에 충분히 간결하지 않았을 것입니다. 🙂
pdf = [(1, 0.1), (2, 0.05), (3, 0.05), (4, 0.2), (5, 0.4), (6, 0.2)]
cdf = [(i, sum(p for j,p in pdf if j < i)) for i,_ in pdf]
R = max(i for r in [random.random()] for i,c in cdf if c <= r)
나는이 표현의 결과를 눈으로 보아 이것이 효과가 있는지 의사에게 확인했다.
sorted(max(i for r in [random.random()] for i,c in cdf if c <= r)
for _ in range(1000))
답변
나는 커스텀 연속 분포에서 무작위 샘플 을 그리는 솔루션을 썼습니다 .
나는 당신과 비슷한 유스 케이스 (예 : 주어진 확률 분포로 임의의 날짜를 생성)에 이것을 필요로했습니다.
당신은 단지 기능 random_custDist
과 라인이 필요합니다 samples=random_custDist(x0,x1,custDist=custDist,size=1000)
. 나머지는 장식입니다 ^^.
import numpy as np
#funtion
def random_custDist(x0,x1,custDist,size=None, nControl=10**6):
#genearte a list of size random samples, obeying the distribution custDist
#suggests random samples between x0 and x1 and accepts the suggestion with probability custDist(x)
#custDist noes not need to be normalized. Add this condition to increase performance.
#Best performance for max_{x in [x0,x1]} custDist(x) = 1
samples=[]
nLoop=0
while len(samples)<size and nLoop<nControl:
x=np.random.uniform(low=x0,high=x1)
prop=custDist(x)
assert prop>=0 and prop<=1
if np.random.uniform(low=0,high=1) <=prop:
samples += [x]
nLoop+=1
return samples
#call
x0=2007
x1=2019
def custDist(x):
if x<2010:
return .3
else:
return (np.exp(x-2008)-1)/(np.exp(2019-2007)-1)
samples=random_custDist(x0,x1,custDist=custDist,size=1000)
print(samples)
#plot
import matplotlib.pyplot as plt
#hist
bins=np.linspace(x0,x1,int(x1-x0+1))
hist=np.histogram(samples, bins )[0]
hist=hist/np.sum(hist)
plt.bar( (bins[:-1]+bins[1:])/2, hist, width=.96, label='sample distribution')
#dist
grid=np.linspace(x0,x1,100)
discCustDist=np.array([custDist(x) for x in grid]) #distrete version
discCustDist*=1/(grid[1]-grid[0])/np.sum(discCustDist)
plt.plot(grid,discCustDist,label='custom distribustion (custDist)', color='C1', linewidth=4)
#decoration
plt.legend(loc=3,bbox_to_anchor=(1,0))
plt.show()
이 솔루션의 성능은 확실하지 않지만 가독성을 선호합니다.
답변
다음을 기준으로 항목 목록을 작성하십시오 weights
.
items = [1, 2, 3, 4, 5, 6]
probabilities= [0.1, 0.05, 0.05, 0.2, 0.4, 0.2]
# if the list of probs is normalized (sum(probs) == 1), omit this part
prob = sum(probabilities) # find sum of probs, to normalize them
c = (1.0)/prob # a multiplier to make a list of normalized probs
probabilities = map(lambda x: c*x, probabilities)
print probabilities
ml = max(probabilities, key=lambda x: len(str(x)) - str(x).find('.'))
ml = len(str(ml)) - str(ml).find('.') -1
amounts = [ int(x*(10**ml)) for x in probabilities]
itemsList = list()
for i in range(0, len(items)): # iterate through original items
itemsList += items[i:i+1]*amounts[i]
# choose from itemsList randomly
print itemsList
목표 목록을 더 작게 만들기 위해 최대 공약수로 양을 정규화하는 것이 최적화 일 수 있습니다.
또한 이것은 흥미로울 수 있습니다.