이전 사건에 의해 편향된“무작위”생성기를 어떻게 만들 수 있습니까?


37

이전 이벤트에 의해 편향 된 기회 기반 시스템을 구현하려고합니다.

배경 : 몇 년 전, 나는 월드 오브 워크래프트가 업데이트 된 이벤트 체인에 대응할 새로운 기회 계산기를 구현했다고 발표 한 것을 기억합니다. (예 : 치명타 또는 연속으로 여러 번 피하기). 아이디어는 피격을 피할 경우 다음 피격을 피할 확률은 줄어들지 만 두 가지 방법으로 작동한다는 것입니다. 적중을 피하지 않으면 다음 적중을 피할 확률이 동일하게 증가합니다. 여기서 가장 중요한 요령은 여러 번의 시도에서 회피 확률이 여전히 스탯 시트에서 플레이어에게 주어진 백분율에 해당한다는 것입니다.

이런 종류의 시스템은 당시에 매우 흥미 로웠으며 지금은 그러한 해결책이 필요한 상황에 처해 있습니다.

내 문제는 다음과 같습니다.

  • 그러한 시스템을 구현하는 데 대한 온라인 리소스를 찾을 수있을 것이라고 생각하지만, 그 시스템을 찾는 데 관련된 관련 단어가 부족할 수 있습니다.
  • 또한 이항 적이 지 않은 시스템 (즉, 두 개의 결과)에 적합하지만 대신 4 개의 상호 배타적 인 이벤트가 포함 된 시스템에 적합하려면이 접근법이 필요합니다.

나의 현재 접근 방식은 추첨 티켓 시스템의 접근 방식과 유사합니다. 이벤트가 발생하면 다른 모든 이벤트에 유리하게 가중치를 변경합니다. 이것은 네 가지 사건이 똑같이 가능할 경우 효과적 일 수 있지만 제 경우에는 훨씬 더 널리 퍼져 야합니다. 그러나 일반적인 사건이 더 자주 발생함에 따라 다른 사건의 무게가 의도 한 것보다 훨씬 많이 이동하며 평균 티켓 수를 이벤트의 초기 값 주변에 유지하는 데 필요한 무게 변화의 숫자를 찾을 수없는 것 같습니다 주어진.

몇 가지 방향 포인터 또는 명확한 예가 많이 이해 될 것입니다.


4
뉘앙스가 있거나 정교한 답변을 원한다면 Mathematics.SE에 더 운이 좋을 것입니다. 수학자들은 확률에 대한 복잡한 질문에 편안하게 대답합니다. math.stackexchange.com
Kevin-Reinstate Monica


6
답변을 더 잘 이해할 수있는 수학 사이트의 대안은 Programmers.SE 입니다. 알고리즘 디자인은 특히 수학 에 대한 주제가 아니므로 유용한 입력을 얻으려면 초기 디자인을 만들어야 할 것입니다.
Lilienthal

1
나는 당신이 거기에 더 나은 대답을 얻을 수 있다고 Kevin과 Lilienthal에 동의하지만, mklingen의 대답을 읽으면서 여기에 설명 된 것이 Markov 체인으로 모델링 될 수 있으며 게임 개발자가 알 수있는 편리한 도구 일 수 있음을 깨달았습니다. 나중에 자세히 작성해 보도록하겠습니다.
nwellcome

1
여기에 대한 답변 중 일부에서 숫자를 실행하면서 여러 가지 다른 제약 조건이 있으며 모든 문제를 해결하는 솔루션이 필요한 것보다 더 복잡 할 수 있습니다. 사용 사례에 대한 자세한 내용은 최상의 옵션을 좁히는 데 도움이 될 수 있습니다. 예를 들어, 이벤트의 확률이 상당히 유사하거나 (예 : 각각 20 % 확률로 5 개의 diffetent 결과) 매우 다르거 나 (예 : 10 % miss 80 % hit 10 % critical)? 달리기 (예 : 연속 3 회 미스) 또는 덩어리 / 대기 (예 : 치명적을 받기 전에 8 회 시도 중 3 회 또는 20 회 시도)를 최소화 하시겠습니까?
DMGregory

답변:


19

기본적으로 요구하는 것은 다음 속성을 가진 이벤트를 생성하는 "반 미정"이벤트 생성기입니다.

  1. 각 이벤트가 발생하는 평균 속도는 미리 지정되어 있습니다.

  2. 동일한 이벤트는 무작위보다 두 번 연속으로 발생할 가능성이 적습니다.

  3. 사건은 완전히 예측할 수 없습니다.

이를 수행하는 한 가지 방법은 먼저 목표 1과 2를 만족시키는 비 랜덤 이벤트 생성기를 구현 한 다음 목표 3을 만족시키기 위해 임의성을 추가하는 것입니다.


비 랜덤 이벤트 생성기의 경우 간단한 디더링 알고리즘을 사용할 수 있습니다 . 구체적으로, p 1 , p 2 , ..., p n 은 사건 1 ~ n 의 상대적 우도이고 s = p 1 + p 2 + ... + p n 은 가중치의 합 이라고합시다 . 그런 다음 다음 알고리즘을 사용하여 비정규 최대 등분 산 이벤트 시퀀스를 생성 할 수 있습니다.

  1. 처음에 e 1 = e 2 = ... = e n = 0 이라고하자 .

  2. 이벤트를 생성하려면, 각 증가 전자 에 의해 P I , 출력 이벤트 k는 있는 전자 K (관계 당신이 원하는 방식을 깨는) 가장 큰 것입니다.

  3. e ks 만큼 줄이고 2 단계부터 반복하십시오.

예를 들어, p A = 5, p B = 4 및 p C = 1 인 세 개의 이벤트 A, B 및 C가 주어지면 이 알고리즘은 다음과 같은 출력 시퀀스와 같은 것을 생성합니다.

A B A B C A B A B A A B A B C A B A B A A B A B C A B A B A

이 30 개의 이벤트 시퀀스에 정확히 15 As, 12 B 및 3 C가 어떻게 포함되어 있는지 확인하십시오. 피할 수 없었던 행에서와 같이 두 번의 As가 몇 번 발생하는 것은 최적으로 분산 되지 는 않았지만 점점 가까워졌습니다.


이제이 순서에 임의성을 추가하기 위해 반드시 상호 배타적이지 않은 몇 가지 옵션이 있습니다.

  • 필립스의 조언을 따르고 적절한 규모의 숫자 N에 대해 N 개의 예정된 이벤트 의 "덱"을 유지할 수 있습니다. 이벤트를 생성해야 할 때마다 데크에서 임의의 이벤트를 선택한 다음 위의 디더링 알고리즘에 의해 다음 이벤트 출력으로 대체하십시오.

    이것을 N = 3 인 위의 예에 적용하면 다음과 같이 생성됩니다.

    A B A B C A B B A B A B C A A A A B B A B A C A B A B A B A

    반면 N = 10은 더 무작위로 보입니다.

    A A B A C A A B B B A A A A A A C B A B A A B A C A C B B B

    공통 이벤트 A와 B가 셔플 링으로 인해 더 많은 실행으로 끝나는 반면, 드문 C 이벤트는 여전히 상당히 잘 배치되어 있습니다.

  • 디더링 알고리즘에 임의성을 직접 주입 할 수 있습니다. 예를 들어, 2 단계에서 e ip i 씩 증가시키는 대신 p i × random (0, 2) 씩 증가시킬 수 있습니다 . 여기서 random ( a , b )는 ab 사이에 균일하게 분포 된 난수입니다 . 다음과 같은 결과가 출력됩니다.

    A B B C A B A A B A A B A B A A B A A A B C A B A B A C A B

    또는 e ip i + random (− c , c ) 씩 증가 시켜 ( c = 0.1 × s 인 경우 ) :

    B A A B C A B A B A B A B A C A B A B A B A A B C A B A B A

    또는 c = 0.5 × s의 경우 :

    B A B A B A C A B A B A A C B C A A B C B A B B A B A B C A

    가산 법이 곱셈 방식과 비교할 때 일반적인 사건 A 및 B보다 희귀 사건 C에 대해 훨씬 더 강력한 무작위 효과를 갖는 방법에 주목하십시오. 이것은 바람직하거나 바람직하지 않을 수 있습니다. 물론, e i평균 증분 이 p i 와 같은 특성을 유지하는 한 이러한 스킴의 일부 조합 또는 증분에 대한 다른 조정을 사용할 수도 있습니다 .

  • 또는 선택한 이벤트 k 를 임의의 이벤트 k 로 바꾸어 디더링 알고리즘 의 출력 을 교란시킬 수 있습니다 (원시 가중치 p i 에 따라 선택 ). 2 단계에서 출력 할 때 3 단계 에서 동일한 k 를 사용하는 한 디더링 프로세스는 여전히 임의의 변동을 균일하게하는 경향이 있습니다.

    예를 들어, 다음은 각 이벤트가 무작위로 선택 될 확률이 10 % 인 출력 예입니다.

    B A C A B A B A C B A A B B A B A B A B C B A B A B C A B A

    다음은 각 출력이 무작위 일 확률이 50 % 인 예입니다.

    C B A B A C A B B B A A B A A A A A B B A C C A B B A B B C

    위에서 설명한대로 순전히 무작위 및 디더링 된 이벤트의 혼합을 데크 / 믹싱 풀에 공급하거나 e i가 측정 한 k를 임의로 선택하여 디더링 알고리즘을 무작위 화하는 것을 고려할 수 있습니다 (음수 가중치를 0으로 처리).

추신. 다음은 비교를 위해 동일한 평균 속도를 가진 완전히 임의의 이벤트 시퀀스입니다.

A C A A C A B B A A A A B B C B A B B A B A B A A A A A A A
B C B A B C B A A B C A B A B C B A B A A A A B B B B B B B
C A A B A A B B C B B B A B A B A A B A A B A B A C A A B A

탄젠트 : 데크 기반 솔루션의 경우, 데크를 리필하기 전에 데크를 비울 수 있어야하는지 에 대한 의견일부 논의 되었으므로 가지 데크 충전 전략을 그래픽으로 비교하기로 결정했습니다.

음모
세미 랜덤 코인 플립을 생성하기위한 몇 가지 전략 도표 (평균 50:50의 머리 대 꼬리 비율). 가로 축은 플립 수이고, 세로 축은 (헤드-테일) / 2 = 헤드-플립 / 2로 측정 된 예상 비율과 누적 거리입니다.

플롯의 빨간색과 초록색 선은 비교를위한 두 가지 비 데크 기반 알고리즘을 보여줍니다.

  • 레드 라인, 결정 론적 디더링 : 짝수 번째 결과는 항상 선두이고 홀수 번째 결과는 항상 꼬리입니다.
  • 녹색 라인, 독립적 인 랜덤 플립 : 각 결과는 무작위로 독립적으로 선택되며, 50 % 확률로 머리와 50 % 확률로 꼬리가 있습니다.

다른 세 줄 (파란색, 자주색, 청록색)은 각각 40 개의 카드로 구성된 데크 기반 전략의 결과를 보여줍니다. 각각 40 개의 카드로 구성된 데크는 처음에 20 개의 "헤드"카드와 20 개의 "테일"카드로 채워져 있습니다.

  • 파란색 선, 비우면 채움 : 덱이 비워 질 때까지 카드가 무작위로 뽑힌 다음 20 개의 "헤드"카드와 20 개의 "꼬리"카드로 덱이 리필됩니다.
  • 자주색 선, 반쯤 비면 채움 : 덱에 20 장의 카드가 남을 때까지 카드가 무작위로 뽑 힙니다. 갑판은 10 개의 "헤드"카드와 10 개의 "꼬리"카드로 채워집니다.
  • 청록색 선, 연속 채우기 : 카드가 무작위로 그려집니다. 짝수 번 추첨은 즉시 "헤드"카드로 교체되고 홀수 번 추첨은 "꼬리"카드로 교체됩니다.

물론, 위의 도표는 무작위 프로세스의 단일 구현 일 뿐이지 만 합리적으로 대표적입니다. 특히, 모든 데크 기반 프로세스는 편향이 제한적이며 빨간색 (결정 론적) 선에 거의 근접한 반면 순수한 임의의 녹색 선은 결국 방황합니다.

(실제로, 0에서 멀어지는 파란색, 보라색 및 녹청 선의 편차는 데크 크기에 의해 엄격하게 제한됩니다. 파란색 선은 0에서 10 단계 이상 멀어 질 수 없으며, 보라색 선은 0에서 15 단계 만 벗어날 수 있습니다) 청록색 선은 0에서 최대 20 단계 떨어져 표류 할 수 있습니다. 물론 실제로 실제로 한계에 도달하는 선은 너무 멀어 질 수 있습니다. 너무 멀리 걸어 다니면 0에 가까워지는 경향이 있기 때문입니다. 떨어져서.)

한눈에, 서로 다른 데크 기반 전략 간에는 분명한 차이가 없지만 (평균적으로 파란색 선은 빨간색 선에 다소 가깝게 유지되고 청록색 선은 다소 더 멀리 떨어져 있음), 파란색 선에 대한 면밀한 검사 뚜렷한 결정 론적 패턴을 보여줍니다 : 40 회 추첨 할 때마다 (점선 회색 세로선으로 표시), 파란색 선은 0에서 빨간색 선과 정확히 일치합니다. 자주색과 청록색 선은 엄격하게 제한되지 않으며 어느 시점에서나 0에서 멀어 질 수 있습니다.

모든 데크 기반 전략에서, 그 변형을 유지하는 중요한 특징은 카드가 데크에서 무작위로 추출되는 동안 데크가 결정적 으로 리필 된다는 사실입니다. 덱을 채우는 데 사용 된 카드가 무작위로 선택 되었다면, 모든 덱 기반 전략은 순수한 무작위 선택 (녹색 선)과 구분할 수 없게됩니다.


매우 정교한 답변. 디더링 알고리즘에 임의의 요소를 추가하는 것은 간단합니다. :)
Sonaten

당신의 대답을 따르기로 결정했습니다. :) 그러나 메소드 개요를 추가하는 것이 좋습니다. 귀하의 답변에 따라 제가하려고하는 것은 "Red"와 "Purple"솔루션을 모두 시도하는 것입니다.
Sonaten

53

주사위를 굴리지 말고 카드를 처리하십시오.

RNG의 가능한 모든 결과를 가져 와서 목록에 넣고 무작위로 섞은 다음 무작위로 결과를 반환하십시오. 목록의 끝에 있으면 반복하십시오.

결과는 여전히 균등하게 분배되지만 목록의 마지막 항목이 다음 중 첫 번째 항목이 아닌 한 개별 결과는 반복되지 않습니다.

이것이 당신의 취향에 대해 너무 예측하기 쉬운 경우, n가능한 결과 수의 몇 배인 목록을 사용하고 n셔플 링하기 전에 가능한 모든 결과를 그 시간에 넣을 수 있습니다 . 또는 완전히 반복되기 전에 목록을 다시 섞을 수 있습니다.


1
조회 "셔플 백"(이 사이트에서도)
jhocking

3
이것은 얼마나 많은 테트리스 게임이 플레이어가 키 조각으로 너무 오랫동안 굶어 죽지 않도록 하는가입니다. 설정된 간격 동안 발생을 제어하려면 새 카드를 삽입하기 전에 Philipp이 제안한대로 가방 / 갑판을 비우는 것이 중요합니다. 이동하면서 카드를 다시 삽입하거나 가중치를 다시 조정하면 계산이 어렵고 잘못되기 쉬운 방식으로 확률 분포를 왜곡 할 수 있습니다.
DMGregory

2
@DMGregory : 사실, 덱을 비우기 전에 새 카드를 섞어 쓰는 것이 좋습니다 (실제로 결과를보다 자연스럽고 예측하기 어렵게 만드는 것이 좋습니다). 중요한 것은 단행 새로운 카드의 (평균) 비율 있는지 확인하는 것입니다 갑판 당신이 그릴 원하는 원하는 부분에 해당 밖으로 그것을합니다.
Ilmari Karonen

4
일 마리 카로 넨 (Illmari Karonen) : 품목을 교체 할 때 동일한 결과의 실행을 제한하거나 특정 결과 사이의 긴 간격으로 셔플 백의 이점을 잃을 수 있습니다. 대체율이 목표 확률 분포와 같으면 각 결과를 무작위로 독립적으로 생성하는 것과 같은 위치에있을 가능성이 있습니다. 목표 확률 분포와 같지 않으면 효과적인 확률을 예측하고 그에 따라 균형을 잡기가 어려운 방식으로 왜곡 할 수 있습니다. asker는 정확하게이 문제로 어려움을 겪고 있다고 설명합니다.
DMGregory

2
@DMGregory와 동의 함. 새 카드를 섞으면 바로 시스템 자체가 무효화됩니다. 카드 처리 시스템은 원하는 결과에 구체적이고 완벽하게 적합합니다. 당신이 여왕을 제거 할 때 예를 들어, 갑판에서 (예를 들어 기존의 카드를 사용하는), 여왕 그리기의 확률은 감소하고, 카드 그리기의 확률 다른 퀸 증가보다 더합니다. 당신이 원한다면 그것은 자체 조정 시스템입니다.
Volte

17

Markov Random Graph을 사용해 볼 수 있습니다. 그래프에서 노드가 될 수있는 각 이벤트를 고려하십시오. 각 이벤트에서 발생했을 수있는 다른 이벤트에 대한 링크를 작성하십시오. 이러한 각 링크에는 전환 확률 이라는 가중치가 적용됩니다 . 그런 다음 전이 모델에 따라 임의의 그래프 걷기를 수행합니다.

예를 들어, 공격 결과 (치명타, 회피 등)를 나타내는 그래프를 가질 수 있습니다. 플레이어의 통계에 따라 무작위로 선택된 노드로 시작 노드를 초기화하십시오 ( "주사위 굴림"). 그런 다음 다음 공격에서 전환 모델에 따라 다음에 어떤 일이 발생할지 결정하십시오.

전환 가중치를 적용하는 방법을 결정하기 위해주의를 기울여야합니다. 우선, 노드에서 나오는 모든 전환은 확률 1을 더해야합니다. 할 수있는 한 가지 간단한 방법은 모든 노드에서 다른 모든 노드로 전환하는 것입니다. 가중치는 해당 이벤트가 발생할 확률과 같습니다. 현재 이벤트가 다시 발생할 수없는 경우 priori

예를 들어, 세 가지 이벤트가있는 경우 :

  Critical, P = 0.1
  Hit,      P = 0.3
  Miss,     P = 0.6

확률 질량을 다른 이벤트에 균일하게 재분배하여 치명타가 다시 발생하지 않도록 전이 모델을 설정할 수 있습니다.

  Critical -> Critical,   P = 0.0
  Critical -> Hit,        P = 0.35
  Critical -> Miss,       P = 0.65

편집 : 아래 의견에서 알 수 있듯이이 모델은 원하는 동작을 수행하기에 충분히 복잡하지 않습니다. 대신 여러 개의 추가 상태를 추가해야 할 수도 있습니다!


1
제안하는 가중치 가중치 체계는 각 주에서 원하는 확률을 유지하지 않습니다. 이 수치로 실증 테스트를 수행하면 입력 값에서 벗어나 시간의 약 41 %, 임계 값이 약 25 %의 누락이 발생합니다. 확률에 비례하여 나머지 상태로 전환하면 (예 : 미스가 치명타를받을 확률이 25 %이고 적중 할 확률이 75 %입니다) 44 %의 미스율과 17 %의 치명타로 약간 더 좋아집니다. 입력에서 원하는 확률을 반영하지 않습니다.
DMGregory

나는 베이 즈 규칙을 잊었다 :( 나중에 다시 계산 될 것이다. 전이 모델이 CCHM 또는 CHHM 또는 가능성이 높은 MMHM과 같은 가능한 시퀀스를 제외하기 때문에 사전 확률 분포를 유지하는 것이 불가능할 수있다.
mklingen

"반복 없음"제약 조건은 극도로 높고 낮은 무게와 관련하여 여기에 손을 묶을 수 있습니다. 10 번의 시도 중 1 회를 중요하게하려면이 방법이 충족 할 수있는 유일한 방법은 5 번의 미스와 5 번의 히트를 교대로하는 것입니다. 연속적인 누락이없는 시퀀스는 여기에서 입력 요구 사항을 충족시킬 수 없습니다.
DMGregory

4
@ mklingen, 나는 DMGregory에 동의합니다. "엄격히 반복 없음"은 여기서 바람직하지 않습니다. 오히려 그들은 동일한 결과의 장쇄 확률이 균일 한 무작위 확률보다 적을 것을 원합니다. 당신은 외모가 좋아하는 (지향) 마르코프 체인이 할 수있는 . 이것은 여러 상태를 사용하여 "Hit 1"에서 "Hit 2"및 "Hit 2"에서 "Hit 3+"로의 전환 가능성이 낮아지고 "Hit 1"및 "Crit로 다시 전환되는 확률이 반복되는 이벤트를 나타냅니다. 1 "올라갑니다.
nwellcome

@nwellcome 그것은 좋은 생각입니다.
mklingen

3

C #에서 만든 구현은 다음과 같습니다.

  • 확률을 기반으로 이벤트 활성화
  • 반복되는 이벤트의 가능성을 줄이려면 해당 확률을 조정하십시오.
  • 원래 확률에서 너무 멀지 않은 곳

내가하고있는 일을 볼 수 있도록 몇 가지 의견을 추가했습니다.

    int percentageEvent1 = 15; //These are the starter values. So given a scenario, the
    int percentageEvent2 = 40; //player would have around a 15 percent chance of event
    int percentageEvent3 = 10; //one occuring, a 40 percent chance of event two occuring
    int percentageEvent4 = 35; //10 percent for event three, and 35 percent for event four.

    private void ResetValues()
    {
        percentageEvent1 = 15;
        percentageEvent2 = 40;
        percentageEvent3 = 10;
        percentageEvent4 = 35;
    }

    int resetCount = 0; //Reset the probabilities every so often so that they don't stray too far.

    int variability = 1; //This influences how much the chance of an event will increase or decrease
                           //based off of past events.

    Random RandomNumberGenerator = new Random();

    private void Activate() //When this is called, an "Event" will be activated based off of current probability.
    {
        int[] percent = new int[100];
        for (int i = 0; i < 100; i++) //Generate an array of 100 items, and select a random event from it.
        {
            if (i < percentageEvent1)
            {
                percent[i] = 1; //Event 1
            }
            else if (i < percentageEvent1 + percentageEvent2)
            {
                percent[i] = 2; //Event 2
            }
            else if (i < percentageEvent1 + percentageEvent2 + percentageEvent3)
            {
                percent[i] = 3; //Event 3
            }
            else
            {
                percent[i] = 4; //Event 4
            }
        }
        int SelectEvent = percent[RandomNumberGenerator.Next(0, 100)]; //Select a random event based on current probability.

        if (SelectEvent == 1)
        {
            if (!(percentageEvent1 - (3 * variability) < 1)) //Make sure that no matter what, probability for a certain event
            {                                                //does not go below one percent.
                percentageEvent1 -= 3 * variability;
                percentageEvent2 += variability;
                percentageEvent3 += variability;
                percentageEvent4 += variability;
            }
        }
        else if (SelectEvent == 2)
        {
            if (!(percentageEvent2 - (3 * variability) < 1))
            {
                percentageEvent2 -= 3 * variability;
                percentageEvent1 += variability;
                percentageEvent3 += variability;
                percentageEvent4 += variability;
            }
        }
        else if (SelectEvent == 3)
        {
            if (!(percentageEvent3 - (3 * variability) < 1))
            {
                percentageEvent3 -= 3 * variability;
                percentageEvent1 += variability;
                percentageEvent2 += variability;
                percentageEvent4 += variability;
            }
        }
        else
        {
            if (!(percentageEvent4 - (3 * variability) < 1))
            {
                percentageEvent4 -= 3 * variability;
                percentageEvent1 += variability;
                percentageEvent2 += variability;
                percentageEvent3 += variability;
            }
        }

        resetCount++;
        if (resetCount == 10)
        {
            resetCount = 0;
            ResetValues();
        }

        RunEvent(SelectEvent); //Run the event that was selected.
    }

이것이 도움이되기를 바랍니다. 코멘트 에서이 코드의 개선을 제안하십시오. 감사합니다!


1
이 가중치 체계는 사건을 평등하게 만드는 경향이 있습니다. 주기적으로 무게를 재설정하는 것은 실제로 얼마나 나쁜지를 제한하는 반창고이며, 10 롤 중 1 롤이 무게 재조정으로부터 전혀 이익을 얻지 못하게합니다. 또한 하나의 알고리즘 메모 : 무작위 선택을 수행하기 위해 100 개의 항목으로 구성된 테이블을 채워 많은 작업을 낭비하고 있습니다. 대신 임의의 롤을 생성 한 다음 4 개의 결과를 반복하여 확률을 합산 할 수 있습니다. 롤이 합계보다 작 으면 결과가 나타납니다. 테이블 채우기가 필요하지 않습니다.
DMGregory

3

mklingen의 답변 을 약간 일반화하겠습니다 . 기본적으로 Gambler 's Fallacy 를 구현하려고 하지만 여기에 더 일반적인 방법을 제공합니다.

n가능성 이 있는 이벤트가 있다고 가정하십시오 p_1, p_2, ..., p_n. 이벤트가 때 i일어난 그 확률 요인으로 재조정하여야한다 0≤a_i≤1/p_i(이 있어야합니다, 후자는 중요하다, 그렇지 않으면 당신은보다 확률보다 다른 이벤트로 끝날 부정적인 확률 , 기본적으로 평균 " 안티 불구하고,"- 이벤트. 또는 뭔가를) 일반적으로 a_i<1. 예를 들어 a_i=p_i,를 선택할 수 있습니다 . 즉, 두 번째 이벤트 발생 확률은 이벤트가 정확히 두 번 연속 발생하는 원래 확률입니다. 예를 들어 두 번째 코인 던지기는 1/2 대신 1/4의 확률을 갖습니다. 다른 한편으로, 당신은 또한 a_i>1"행운 / 불운의 획"을 촉발하는 것을 의미 할 수도 있습니다 .

다른 모든 사건들은 서로에 대해 똑같이 가능한 것으로 유지되어야한다. 즉, b_i모든 확률의 합이 1과 같도록 모두 같은 요인에 의해 재조정되어야한다.

1 = a_i*p_i + b_i*(1-p_i)  # Σ_{j≠i) p_j  = 1 - p_i
 b_i = (1 - a_i*p_i) / (1 - p_i).   (1)

지금까지는 간단합니다. 그러나 이제 두 가지 사건의 모든 가능한 순서를 고려하면 그로부터 추출 된 단일 사건 확률은 원래 확률이됩니다.

허락하다

        / p_i * b_i * p_j  (ji)
p_ij = <
        \ a_i * (p_i     (j=i)

이벤트 j이후에 발생할 수있는 이벤트의 가능성을 나타내며, 그렇지 않은 경우 (에 의해 암시 됨 )에 i유의하십시오 . 이것은 또한 베이 즈 정리 가 요구하는 것이며 이것은 또한 암시합니다p_ij≠p_jib_i=b_j (2)(1)a_j = 1 - a_i*p_i + (1-a_i)*p_i/p_j

Σ_j p_ij = p_i * b_i * (1 - p_i) + a_i * (p_i
         = b_i * p_i + (a_i - b_i) * (p_i
         = p_i  # using (1)

원하는대로. 이것이 a_i다른 하나를 수정 한다는 의미에 유의하십시오 .


이제이 절차를 여러 번 적용 할 때 어떻게되는지, 즉 3 개 이상의 이벤트 순서를 살펴 보겠습니다. 기본적으로 세 번째 이벤트의 조작 된 확률을 선택할 수있는 두 가지 옵션이 있습니다.

a) 두 번째 이벤트 만 발생한 것처럼 첫 번째 이벤트 및 리그를 잊어 버리십시오.

         / p_ij * a_j * p_j  (j=k)
p_ijk = <
         \ p_ij * b_j * p_l  (jk)

예를 들어 p_jik≠p_ikj대부분의 경우에 이는 베이를 위반한다는 점에 유의하십시오 .

b) 다음 번 에 이벤트 가 발생할 새로운 확률 을 얻는 새로운 확률로 확률 p_ij(고정 i)을 사용하십시오 . 수정 여부는 전적으로 귀하에게 달려 있지만 modified로 인해 새로운 내용 은 확실히 다릅니다 . 그런 다음 다시 동일한 확률 로 발생 하는 모든 순열을 요구함으로써 선택이 제한 될 수 있습니다. 보자 ...pi_jpi_jkkai_jbi_jpi_jai_jijk

         / p_ij * bi_j * pi_k  (jk)
p_ijk = <
         \ (p_ij * ai_j      (j=k)

         / b_i * bi_j * p_i * p_j * pi_k  (ijki)
         | b_i * ai_j * p_i * (p_j      (ij=k)
      = <  a_i * (p_i * bi_i * pi_k     (i=jk)
         | b_i * p_i * bi_j * p_k * pi_i  (i=kj)
         \ a_i * ai_i * (p_i * pi_i     (i=k=j)

및 이의 순환 순열은 각각의 경우에 동일해야한다.

나는 이것에 대한 나의 지속이 잠시 기다려야 할 것을 두려워한다 ...


이를 실험적으로 테스트하면 여전히 많은 실행에서 입력 확률에서 왜곡이 발생합니다. 예를 들어 mklingen의 답변에서 숫자를 사용하여 a_i / p_i = 0.5 인 경우 입력 미스율 60 %는 50.1 %의 관측 률이되고 10 %의 입력 임 계율은 13.8 %로 관찰됩니다. 결과 전이 행렬을 고출력으로 가져 와서이를 확인할 수 있습니다. a_i : p_i의 비율을 1에 더 가깝게 선택하면 왜곡이 줄어들지 만 런 감소 효과는 떨어집니다.
DMGregory

@DMGregory의 좋은 점 : 단순히 전이 행렬의 힘을 사용할 수 없습니다. 나중에 답변을 드리겠습니다.
Tobias Kienzler

@DMGregory 나는 전체 프로세스 (변형 b)를 설명하기 시작했지만 꽤 지루하고 현재 시간이 부족하다 : /
Tobias Kienzler

1

가장 좋은 옵션은 무작위 가중치 항목 선택을 사용하는 것입니다. 이 C 번호의 구현입니다 여기에 ,하지만 그들은 쉽게 찾을 또는 다른 언어로 만들 수 있습니다.

아이디어는 선택 될 때마다 옵션의 가중치를 줄이고 선택하지 않을 때마다 증가시키는 것입니다.

예를 들어, 선택 옵션 NumOptions-1의 무게를 줄이고 다른 모든 옵션의 무게를 1 씩 늘리면 (무게 <0 인 항목을 제거하고 0보다 높아질 때 읽어야 함) 모든 옵션은 대략 선택됩니다. 오랜 기간 동안 같은 횟수이지만 최근에 선택한 옵션은 선택 가능성이 훨씬 낮습니다.


다른 많은 답변에서 제안한 것처럼 무작위 순서를 사용하는 문제는 모든 옵션을 선택했지만 하나를 선택하면 다음에 어떤 옵션을 선택할지 100 % 확실하게 예측할 수 있다는 것입니다. 그다지 무작위는 아닙니다.


1

내 답변이 잘못되었습니다. 테스트에 결함이있었습니다.

이 디자인의 결함을 지적하는 토론과 의견을 위해이 답변을 여기에 남겨두고 있지만 실제 테스트는 잘못되었습니다.

당신이 찾고있는 것은 가중 가중치입니다. 네 가지 가능한 결과에 대한 가중치는 이전 결과에 의해 더 조정 (가중치)되어야하지만 전체적으로 적절한 가중치를 유지해야합니다.

이 작업을 수행하는 가장 쉬운 방법은 롤링 된 특정 값의 가중치를 줄이고 다른 가중치를 늘림으로써 각 롤의 모든 가중치변경하는 것입니다 .

예를 들어, Fumble, Miss, Hit 및 Crit의 4 가지 가중치가 있다고 가정합니다. 또한 원하는 전체 무게는 Fumble = 10 %, Miss = 50 %, Hit = 30 %, Crit = 10 %입니다.

RNG (난수 생성기)를 사용하여 1과 100 사이의 값을 생성 한 다음이 값이이 범위 내에있는 위치와 비교하는 경우 (1-10 Fumble, 11-60 miss, 61-90 hit, 91-100 crit ), 개별 롤을 생성 중입니다.

롤을 만들 때 롤된 값을 기준으로 해당 범위를 즉시 조정하는 경우 향후 롤에 가중치를 부여하지만 다른 가중치를 늘릴 때 와 동일한 총량 만큼 롤 가중치를 줄여야합니다 . 위의 예에서 롤 중량을 3 씩 줄이고 다른 중량을 각각 1 씩 증가시킵니다.

각 롤에 대해이 작업을 수행하면 줄무늬가 발생할 가능성이 있지만 각 롤에 대해 향후 롤이 현재 롤이 아닌 다른 롤일 가능성이 높아지기 때문에 줄이 크게 줄어 듭니다. 이 효과를 높이면 가중치를 더 크게 증가 / 감소시켜 (예를 들어 전류를 6 씩 줄이고 다른 것을 2 씩 증가시켜) 줄무늬의 가능성을 더욱 줄일 수 있습니다.

이 접근법을 검증하기 위해 빠른 앱을 실행했으며 이러한 가중치로 32000 회 반복하면 다음 그래프가 생성됩니다. 상단 그래프는 각 롤에서 4 개의 가중치 즉시 값을 표시하고 하단 그래프는 해당 지점까지 롤업 된 각 결과 유형의 합계 수를 표시합니다.

보시다시피, 가중치는 원하는 값 주위에서 약간 변동하지만 전체 가중치는 원하는 범위 내에서 유지되며, 다양한 시작 숫자가 확정 된 후 결과는 원하는 비율에 거의 완벽하게 맞습니다.

이 예제는 실제로 더 나은 RNG 중 하나가 아닌 .NET System.Random 클래스를 사용하여 생성되었으므로 더 나은 RNG를 사용하면 더 정확한 결과를 얻을 수 있습니다. 또한 32000이이 도구를 사용하여 그래프로 표시 할 수있는 최대 결과 였지만 테스트 도구는 동일한 전체 패턴으로 5 억 개 이상의 결과를 생성 할 수있었습니다.


이 방법은 가장 최근에 사용한 가중치가 아닌 원래 가중치를 기준으로 +1/3을 적용한 경우에만 작동합니다. (이와 같이 지속적으로 가중치를 균일하게 수정하면 등가로 향하게됩니다.) 이렇게하면 장기적으로 목표에 대한 확률이 유지되지만 실행을 줄이는 데는 거의 도움이되지 않습니다. 한 번 놓쳤다는 점을 감안할 때,이 체계에서 두 번 더 연속으로 놓칠 확률은 22 %이며 독립 추첨에서는 25 %입니다. 더 큰 효과 (예 : + 3 / -9)를 위해 가중치 이동을 늘리면 장기 확률이 바이어스됩니다.
DMGregory

실제로 위에 제시된 데이터는 롤을 처리 할 때마다 가장 최근의 무게에 + 1 / -3을 적용합니다. 따라서 초기 50 % 무게로 한 번 놓치면 다음 미스 무게는 47 %가되고, 다시 그리면 다음 무게는 44 %가됩니다. 달리기 횟수를 줄이지 만 (별도의 지표는 달리기 횟수를 24 % 줄인 것으로 확인 됨)이 계획은 여전히 ​​4 가지 가중치를 각각 0이 아닌 확률로 남겨 둘 가능성이 높기 때문에 여전히 불가피합니다 ( 예를 들어 연속으로 4 개의 크릿이 발생하면 치명적인 무게가 남을 수 있습니다.
David C Ellis

그것이 의도라면 구현에 버그가 있습니다. 그래프를 보아라.-그 무게 값은 7에서 11 사이에서만 튀어 나오며 그 밖의 값은 없다. 나는 당신이 묘사하는 지속적인 수정을 사용하여 시뮬레이션을 실행했으며 그래프는 크게 다릅니다. 각 주에서의 확률은 처음 백 번의 시험에서 각각 25 %로 수렴합니다.
DMGregory

Dangit, 당신이 지적한대로 실제로 버그가 발생했습니다. 글쎄,이 대답을 공격.
David C Ellis

@DavidCEllis 당신은 당신의 구현에 결함이 있거나 아이디어 자체가 있다고 말하고 있습니까? 내 냅킨 뒤 직관은 대략 당신이 묘사 한 모델에 도달했으며 (그리면 확률을 낮추고, 점차 모든 확률을 원래 값으로 점차 복원합니다) 여전히 이해가됩니다.
dimo414

0

본질적으로 필터를 수행 할 수 있습니다. 지난 n 개의 이벤트를 추적하십시오. 확률은 해당 이벤트에 적용된 일부 필터입니다. 0 번째 필터는 0 일 경우 기본 확률이며, 1이면 실패한 경우 회피했습니다. 기본이 25 %이고 필터가 각 반복의 절반 씩 감소한다고 가정 해 봅시다. 그러면 필터는 다음과 같습니다.

[.25 .125 .0625 .03125] 

원하는 경우 계속 진행하십시오. 이 체계의 전체 확률은 기본 확률 0.25보다 약간 높습니다. 사실, 같은 방식으로 주어진 확률은 (나는 x를 실제 확률이라고 부르고, p는 확률 입력이다) :

x=p+(1-x)*(p/2+p/4+p/8)

x를 풀면 답이 p(1+1/2+1/4+1/8)/(1+p(1/2+1/4+1/8)(또는 주어진 사례) 임을 알 수 x=0.38461538461있습니다. 그러나 당신이 정말로 원하는 것은 x가 주어지면 p를 찾는 것입니다. 그것은 더 어려운 문제로 판명되었습니다. 무한 필터를 가정하면 문제는 x+x*p=2*p또는 p=x/(2-x)입니다. 따라서 필터를 늘리면 평균 p와 같은 결과를 얻을 수 있지만 최근에 성공한 정도에 따라 다른 결과를 얻을 수 있습니다.

기본적으로 이전 값을 사용하여 이번 라운드의 수락 임계 값을 결정하고 임의의 값을 취합니다. 그런 다음 필터가 주어진 다음 임의의 값을 생성하십시오.


-1

직접 제안한 것처럼이 방법 중 하나는 가중 랜덤을 구현하는 것입니다. 아이디어는 가중치와 결과를 수정할 수있는 난수 (또는 결과) 생성기를 만드는 것입니다.

다음은 Java로 구현 한 것입니다.

import java.util.Map;
import java.util.Random;

/**
 * A psuedorandom weighted outcome generator
 * @param <E> object type to return
 */
public class WeightedRandom<E> {

    private Random random;
    private Map<E, Double> weights;

    public WeightedRandom(Map<E, Double> weights) {
        this.random = new Random();
        this.weights = weights;
    }

    /**
     * Returns a random outcome based on the weight of the outcomes
     * @return
     */
    public E nextOutcome() {
        double totalweight = 0;

        // determine the total weigth
        for (double w : weights.values()) totalweight += w;

        // determine a value between 0.0 and the total weight
        double remaining = random.nextDouble() * totalweight;

        for (E entry : weights.keySet()) {
            // subtract the weight of this entry
            remaining -= weights.get(entry);

            // if the remaining is smaller than 0, return this entry
            if (remaining <= 0) return entry;
        }

        return null;
    }

    /**
     * Returns the weight of an outcome
     * @param outcome the outcome to query
     * @return the weight of the outcome, if it exists
     */
    public double getWeight(E outcome) {
        return weights.get(outcome);
    }

    /**
     * Sets the weight of an outcome
     * @param outcome the outcome to change
     * @param weight the new weigth
     */
    public void setWeight(E outcome, double weight) {
        weights.put(outcome, weight);
    }
}

편집 가중치를 자동으로 조정하려는 경우, 예를 들어 결과가 B 일 때 A의 확률을 높이십시오.

  1. nextOutcome()메소드 의 동작을 변경하여 결과에 따라 가중치를 수정합니다.
  2. setWeight()결과에 따라 가중치를 수정하는 데 사용 합니다.

OP가 가중 무작위 결과를 생성하는 방법을 묻지 않고 가중치를 조정하여 동일한 결과가 여러 번 연속적으로 발생할 가능성을 줄이기 위해 질문을 잘못 읽은 것 같습니다.
Ilmari Karonen

나는이 시스템을 사용하여 어떻게 가능한지 설명하기 위해 내 대답 중 일부를 변경했습니다.
erikgaal
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.