본문 바로가기
카테고리 없음

[p5.js / The nature of code] 0. Randomness(무작위성) - 0.5 A Custom Distribution of Random Numbers(임의 숫자 사용자 정의 정의 분포)

by the_cat_Soy 2024. 4. 23.
 

Examples

 

natureofcode.com

 

Custom Distribution of Random Numbers(임의 숫자 사용자 정의 정의 분포)

 

 주변을 무작위로 돌아다니는 것은 음식을 찾는 합리적인 전략처럼 보입니다. 어차피 음식이 어디에 있는지 알 수 없으니까 찾을 때까지 무작위로 돌아다닐 수밖에 없겠죠. 그러나 문제가 있습니다. 워커 객체를 관찰하면 알겠지만, 랜덤 워커는 이전에 방문한 위치로 많이 되돌아가는 현상이 있습니다. 이를 과잉 샘플링이라고 합니다. 이렇게 되면 음식을 찾는 데 실패하거나 적어도 비효율적일 수 있습니다.

 

 이런 문제를 피하는 한 가지 전략은 때때로 매우 큰 걸음을 내딛는 것입니다. 이렇게 하면 워커가 특정 위치 주변을 무작위로 찾아다니면서 주기적으로 멀리 뛰어가서 과잉 샘플링의 양을 줄일 수 있습니다. 이를 레비 비행이라고 하는 랜덤 워크의 변형이며, 사용자 정의 확률 집합이 필요합니다. 레비 비행의 정확한 구현은 아니지만, 확률 분포를 다음과 같이 명시할 수 있습니다: 걸음이 길면 길수록 선택될 확률이 낮아지고, 걸음이 짧으면 선택될 확률이 높아집니다.

 

 이전에 언급한 것처럼 값이 채워진 배열을 사용하여 사용자 정의 확률 분포를 생성하거나 random()의 결과를 테스트하여 만들 수 있습니다. 레비 비행을 구현하는 한 가지 방법은 1%의 확률로 큰 걸음을 내딛도록 지정하는 것입니다:

let r = random(1);
if (r < 0.01) {
  xstep = random(-100, 100);
  ystep = random(-100, 100); // A 1% chance of taking a large step

} else {
  xstep = random(-1, 1);
  ystep = random(-1, 1);
}

 

Figure 0.3 : "y = x"의 그래프에서 y는 값 x가 선택될 확률입니다.

 

 하지만 이 방법은 확률을 고정된 옵션으로 줄입니다: 99%의 경우 작은 걸음을 내딛고, 1%의 경우 큰 걸음을 내딛습니다. 그러나 대신 숫자가 높을수록 더 자주 선택되도록 하는 더 일반적인 규칙을 만들고 싶다면 어떨까요? 예를 들어, 0.8791은 0.8532보다 선택될 확률이 더 높아질 수 있습니다. 비록 그 차이가 매우 작더라도요. 다시 말해, x가 무작위 숫자인 경우, 선택될 확률을 y축과 함수 y = x로 매핑할 수 있습니다(Figure 0.3 참조).

 

0.3에 있는 그래프에 따라 무작위 숫자의 분포를 생성할 수 있다면, 공식으로 정의할 수 있는 다른 어떤 곡선도 따르는 무작위 분포를 생성할 수 있어야 합니다.

 

 사용자 정의 분포의 한 해결책은 하나 대신 두 개의 무작위 숫자를 선택하는 것입니다. 첫 번째 무작위 숫자는 단순히 무작위 숫자입니다. 그러나 두 번째 숫자는 자격 부여 무작위 값이라고 부를 것입니다. 이 값은 프로그램이 해당 첫 번째 숫자를 사용할지 아니면 버리고 다른 값을 선택할지 결정하는 데 사용됩니다. 자격 부여가 쉬운 숫자는 더 자주 선택되고, 거의 자격 부여되지 않는 숫자는 드물게 선택됩니다. 여기에는 다음 단계가 있습니다(지금은 0부터 1까지의 무작위 값만 고려합니다):

 

  1.  랜덤 숫자를 선택합니다: r1.
  2.  r1이 자격 부여해야 하는 확률 p를 계산합니다. 다음을 시도해 봅시다: p = r1.
  3. 다른 무작위 숫자를 선택합니다: r2.
  4. 만약 r2가 p보다 작다면, 당신은 숫자를 찾았습니다: r1!
  5. 만약 r2가 p보다 작지 않다면, 다시 1단계로 돌아가서 처음부터 다시 시작합니다.

 

 여기서 무작위 값이 자격 부여될 확률은 무작위 숫자 자체와 같습니다. 이는 도표 0.3에서 보았던 것과 같습니다. 예를 들어, r1이 0.1이라면, r1이 자격 부여될 확률은 10%가 됩니다. r1이 0.83인 경우에는 83%의 자격 부여 확률을 갖게 됩니다. 숫자가 높을수록 사용될 확률이 높아집니다.

 

 이 과정은 수락-거부 알고리즘이라고 불리며, 몬테 카를로 메소드의 일종입니다(몬테 카를로 카지노에서 명명되었습니다). 다음 예제는 수락-거부 알고리즘을 구현하는 함수를 보여줍니다. 이 함수는 0부터 1까지의 무작위 값을 반환합니다.

 
 

Example 0.5: An Accept-Reject Distribution(수락 거부 분포)

function acceptreject() {
  while (true) {
	//이 과정을 "영원히" 반복하여 자격 부여되는 무작위 값을 찾을 때까지 계속합니다.

    let r1 = random(1);
	//무작위 값을 선택합니다.

    let probability = r1;
	//확률을 할당합니다.

    let r2 = random(1);
	//두 번째 무작위 값을 선택합니다.

    if (r2 < probability) {
      return r1;
  	//자격 부여되었습니까? 그렇다면, 작업을 완료했습니다!
   
    }
	
  }
}
 

https://editor.p5js.org/natureofcode/sketches/3t5iHwA7Q

 수락-거부 알고리즘은 무작위 숫자의 사용자 정의 분포를 생성하는 데에는 작동하지만, 이 기술은 특히 자격 부여 확률이 매우 낮을 때 많은 양의 연산이 낭비될 수 있어 효율적이지 않습니다. 특히 자격 부여 확률이 매우 낮을 때 많은 양의 무작위 값이 거부될 때, 상당한 양의 계산이 낭비될 수 있습니다. 9장에서 유전 알고리즘을 다룰 때, 다른, 더 최적화된 방법을 사용할 것입니다.

 

 

Exercise 0.6

임의 워커의 걸음 크기를 변화시키기 위해 사용자 정의 확률 분포를 사용하세요. 걸음 크기는 자격 부여된 무작위 값의 범위를 조절하여 결정될 수 있습니다. 확률을 이차 함수에 매핑하여 값을 선택하는 확률을 값의 제곱과 동일하게 만들 수 있습니까?

let step = 10; //무작위 걸음 크기의 균일한 분포. 이것을 변경하세요!
let stepx = random(-step, step); 
let stepy = random(-step, step);
this.x += stepx;
this.y += stepy;

 

(1장에서는 보다 효율적으로 걸음 크기를 변화시키는 벡터를 사용하는 방법을 보여 드리겠습니다.)