난수는 일반적으로 우리가 '균일 분포'라고 부르는 것을 따릅니다. 즉, 임의의 숫자가 선택될 확률이 동일합니다.
그러나 일부 숫자를 다른 숫자보다 더 자주 선택하려면 가중 난수 생성기와 같은 다른 전략이 필요합니다. .
몇 가지 실용적인 응용 프로그램은 다음과 같습니다.
- 비디오 게임의 전리품 테이블에서 적들이 다양한 드롭률로 다양한 아이템을 드롭할 수 있습니다.
- 더 많은 티켓을 소지한 사람이 더 많은 당첨 기회를 얻을 수 있는 복권
간단한 전략
추첨 예에 대해 생각해 보면 분명한 해결책을 생각해 낼 수 있습니다. 각 '티켓'에 대해 항목 사본이 하나씩 있는 배열을 생성하는 것입니다.
예를 들어 John이 4개의 복권 티켓을 구매하고 David가 1개만 구매하는 경우 John은 David보다 4배 더 많은 당첨 기회를 갖게 됩니다.
실제 구현은 다음과 같습니다. :
users = { john: 4, david: 1 } raffle = [] users.map do |name, tickets| tickets.times { raffle << name } end p raffle # [:john, :john, :john, :john, :david] p raffle.sample # :john
나는 그들이 구입한 모든 티켓에 대해 그 사람의 이름을 한 번씩 추가하고 그 목록에서 임의의 이름을 선택합니다. 목록에 더 많이 오르는 덕분에 그 이름이 선택될 확률이 높아집니다.
나는 이 접근 방식이 매우 간단하고 목록이 있으면 매우 빠르게 승자를 선택할 수 있기 때문에 이 방식을 좋아합니다.
가중치의 합
메모리를 더 효율적으로 사용할 수 있는 또 다른 방법이 있는데, 무작위 값을 선택하는 것이 더 느리다는 단점이 있습니다.
아이디어는 1과 모든 가중치의 합 사이에서 임의의 숫자를 선택한 다음 이 숫자보다 작거나 같은 가중치를 찾을 때까지 반복하는 것입니다.
코드는 다음과 같습니다. :
def random_weighted(weighted) max = sum_of_weights(weighted) target = rand(1..max) weighted.each do |item, weight| return item if target <= weight target -= weight end end def sum_of_weights(weighted) weighted.inject(0) { |sum, (item, weight)| sum + weight } end
이 코드는 키가 항목이고 값이 가중치인 해시를 사용합니다. 다음과 같이 이 메서드를 호출할 수 있습니다.
random_weighted(cats: 5, dogs: 1) # :cats
여러 번 실행한 후 결과 분포를 보면 예상대로 작동하는지 테스트할 수 있습니다.
예시입니다 :
counts = Hash.new(0) def pick_number random_weighted(cats: 2, dogs: 1) end 1000.times { counts[pick_number] += 1 } p counts
이것을 몇 번 실행하고 출력을 보고 비율이 올바른지 확인하십시오.
결론
더 정교한 알고리즘이 있지만 이 두 가지가 잘 작동합니다. 이 기사가 도움이 되었기를 바랍니다. 계속해서 더 많은 글을 쓸 수 있도록 친구들과 공유해 주세요!