/006957

프로그래머를 위한 확률과 통계

Primary LanguageRubyBSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

= <프로그래머를 위한 확률통계>(길벗, 2019) 각 장 말미의 컬럼용 스크립트에 사용하는 루비 코드입니다.
원서의 지원 페이지는 다음과 같습니다.
http://ssl.ohmsha.co.jp/cgi-bin/menu.cgi?ISBN=978-4-274-06775-4

== ■ 준비

* Linux, Mac 의 경우: 준비 불필요. 안되면 아래와 같이 한다.
* 기타 UNIX 계열의 경우:
  * Ruby가 만약 들어 있지 않다면 설치한다.
  * /usr/bin/ruby 가 만약 없다면, (root 권한으로) 아래와 같이 실행한다.
    예를 들어 ruby 가 /usr/local/bin/ 에 설치되어 있다면,
      ln -s /usr/local/bin/ruby /usr/bin/
* Windows의 경우:
  * Ruby를 설치한다.
  * 비공식 지원 페이지도 참고한다.
    http://wiki.fdiary.net/lacs/?PSCS.Windows

Ruby 설치에 대해서는 http://www.ruby-lang.org/ko/를 참고한다.
버전 1.8.7에서 동작을 확인했다.

== ■ 사용 방법

시뮬레이션을 실행하려면:
각 서브디렉토리에서 "make" 또는 "make long"

매개변수를 바꾸려면:
"make"나 "make long"을 실행하면 표시되는 명령어를 직접 입력하여 마음대로 수정한다.

각 스크립트의 도움말을 보려면:
"ruby histogram.rb -h"과 같이 -h 옵션을 붙여서 실행한다.

== ■ 각 서브디렉토리의 설명

==== ◆ accident

(1)
사고는 계속 일어난다고 합니다.
  이는 사고가 한 번 일어나면 그 후 당분간은 사고
  확률이 높아짐을 의미하는 걸까요?……[가]

간단한 컴퓨터 시뮬레이션으로 검증해 봅시다.
"make"를 실행하면 나오는 계열 중 o가 사고 발생을 나타냅니다.
결과를 보면 o의 배치는 균일하지 않고
묘하게 가까운 덩어리와 묘하게 긴 공백 기간이 눈에 띕니다.

계열 아래에 표시되는 것은 "o끼리의 간격"
(이전 사고로부터 며칠 후에 다음 사고가 일어났는지)의 히스토그램입니다.
이것을 보더라도 짧은 간격으로 o가 나오는 일이
확실히 많다는 것을 알 수 있습니다……[나]

그러나 사실은 이 계열은 확률 0.1로 o를 쓰고
확률 0.9로 .를 쓰는 처리를 단순히 되풀이한 것입니다.
각 문자가 o가 될지 .이 될지는 완전 독립으로 확률도 일정합니다.
그래서 [나]가 반드시 [가]을 의미하는 것은 아닙니다.

"make long"으로는, 더 긴 계열로 시뮬레이션을 한 결과가 표시됩니다.

(2)
"o끼리의 간격"의 기댓값에 대해, 다음과 같은 두개의 서로 다른 가설을 생각할 수 있습니다.
어느쪽을 지지하세요? 지지하지 않는 가설의 어디가 오류라고 지적할 수 있습니까?

[가설 A]
t 문자째가 o 였다고 하자. 다음에 o 가 나오는 것이 k 문자뒤가 되는 확률은,
". 가 (k-1) 번 나오고 그 다음에 o 가 나온다"는 확률이므로
  (0.9 의 (k-1) 제곱) × 0.1
이다. 이 분포의 기댓값을 계산하면, 답은 10. (계산과정은 생략)

[가설 B]
t 문자째와 (t+1) 문자째와의 갈림길에 서서 생각해보자.
"다음에 o 가 나오는 것은 어떤 문자 다음인가"의 기댓값은, 가설 A 처럼 10 으로 구해진다.
한편, "직전에 o 가 나왔다는 것은 어떤 문자 앞인가"의 기댓값도, 역시 같은 이치로 10이 된다.
그러므로, o 에서부터 o 까지의 간격의 기댓값은 10 + 10 - 1 = 19 이다.
(이 실험에서는 "oo"을 간격 1, "o.o"을 간격 2, "o..o"을 간격 3이라고 세므로,
위의 식에는 "- 1"이 붙고 있습니다)

※ 아래 자료를 참고해 주시길 바랍니다.
  David MacKay: Information Theory, Inference and Learning Algorithms,
  Cambridge University Press, 2003.

==== ◆ cake

(1)
둥근 케이크를 형제가 나눕니다.
형은 케이크의 12시 위치에 포크를 꽂고 이렇게 말했습니다.
"중심에서 전혀 엉뚱한 방향으로 케이크를 두 번 잘라 둘로 나눌게.
포크가 있는 쪽이 내 것, 없는 쪽이 네 것이야."
이는 공평할까요?

"make"로, 시뮬레이션의 결과가 나옵니다.
최초에 표시되는 숫자의 나열은, 각 시뮬레이션으로 동생이 받은 몫(케이크 전체를 $1$로 할 때의 비율)의
히스토그램을 나타냅니다.
그 아래에는, 받은 몫의 비율의 히스토그램이 표시됩니다.

"make long"으로는, 시행 회수를 늘린 결과가 나옵니다.

※ 아래의 자료를 참고하길 바랍니다.
  "황금의 훌라후프"
  http://blog.beetama.com/blog-entry-557.html

(2)
긴 롤 케이크로 이치로, 지로, 사부로, 시로, 고로, 5명이 나눕니다.
아무렇게나(전에 어디를 잘랐는지도 보지 않고) 칼로 4번만 썰어
롤 케이크를 토막내어 왼쪽부터 순서대로
이치로, 지로,……, 고로가 받기로 했습니다.
이는 공평할까요?

"make roll"을 실행하면, 시뮬레이션 결과가 나옵니다.
위에 표시되는 것은 이치로 몫의 히스토그랯,
아래에 표시되는 것은 사부로 몫의 히스토그램입니다.

"make rlong"을 실행하면, 시행회수를 늘린 결과가 표시됩니다.
어떻게든 공평한것 같습니다만, 공평한 이유를 수식 없이 설명할 수 있습니까?

==== ◆ monty

유명한 몬티 홀 문제입니다.
어떤 문제인지는 web에서 검색하면 금방 찾습니다.
(예를 들어 아래 자료)
  http://wiki.fdiary.net/lacs/?Pr.Def.2

"make" 실행하면 나오는 것은, 최초의 선택을 유지하는 경우의 승률과,
문을 다시 선택하는 경우의 승률입니다.
이 결과를 보면, 다시 선택하는 쪽이 확실히 승률이 높아지고 있습니다.

==== ◆ nearest

한 변의 길이가 1인 d 차원 입방체를 무대로 하여,
그 안에 100 개의 점을 독립적인 균등 분포로 무작위로 둡니다.
최초에 둔 점 X(1) 으로부터, 나머지 점 X(2), ..., X(100) 까지의 
최단 거리 R = min ||X(j) - X(1)|| (j = 2, ..., 100) 은
얼마나 될까요?

"make run1"하면 d = 1 차원(즉 선분)의 경우가,
"make run2"하면 d = 2 차원(즉 정사각형)의 경우가,
"make run3"하면 d = 3 차원(즉 정육면체)의 경우가, 각각 시뮬레이션됩니다.
표시되는 것은, 같은 실험을 몇번을 반복했을 때 R의 히스토그램입니다.

더욱이, "make run"으로 d = 20 차원의 경우가 시뮬레이션됩니다.
이미지로부터도 꽤 큰 값이라고 느껴지지 않으세요?
(표시되는 것이 최단거리라는 것을 잊지 않도록).

"make long"으로 하면, 시행회수가 늘어난 결과를 볼 수 있습니다.

차원이 늘어남에 따라 점이 드문드문 해진다는 지금의 결과는
차원의 저주라고 불리는 현상의 예시입니다.
고차원적 데이터 분석·예측, 패턴 인식 등에서는
차원의 저주가 성가신 문제가 됩니다.

==== ◆ pattern

(1)
0001110101...처럼
랜덤으로(확률 반반으로 매번 독립에) $0$ 또는 $1$을 이어 써 가면
지정한 패턴이 나올 때까지의 길이를 셀 수 있습니다.
예를 들어 지정 패턴이 $1101$이면
수열의 끝이 "... 1101"로 된 시점에서
중단하고 거기까지의 길이입니다.
패턴에 따라 이 길이의 기댓값은 바뀌게 될까요?

"make"로는, 지정 패턴이 $01$인 경우와 $11$인 경우를 시뮬레이션합니다.
"make long"는, 더욱 시행 회수를 늘린 시뮬레이션을 하며,
"그 패턴이 나올때까지 걸리는 길이"의 히스토그램을 표시합니다.
패턴 11이 출현하기까지 오래 걸리기 쉬운데, 그 이유를 설명할 수 있습니까?

(2)
또한, "make count"으로는, 지정된 패턴이, 일정한 길이까지는
몇번 나왔지를 셉니다.
"make clong"는, 출현 회수의 히스토그램을 표시합니다.
이 출현 회수의 평균은, 패턴 01 에서도 패턴 11 에서도 거의 같습니다.
위의 결과와 일견 모순되는 것 같은데요. 어떻게 설명하겠습니까?

※ 아래의 자료를 참고해 주세요.
  ・G. 브람, 기타: 확률론에 오신 것을 환영합니다, 슈프링거 페어락 도쿄, 2005.
    제 14 장 "패턴"
  ・"코인으로 논다"
    http://blog.beetama.com/blog-entry-618.html

==== ◆ portfolio

확률 0.7로 "가"가 나오고, 확률 0.3로 "나"가 나온다는 추첨이 있습니다.
가, 나 어느 쪽에 걸어도 당첨되면 판돈이 2배가 됩니다.
그러므로 아에 거는 것이 분명 유리합니다.

당신은 매일 이 제비뽑기에 전 재산을 겁니다.
구체적으로는 전 재산 중 비중 p를 가에, 나머지를 나에 겁니다.
p는 미리 정합니다.
이를 계속 반복한다면 p를 어떤 값으로 하는 것이 좋을까요?

하루 이익의 기댓값을 생각하면 $p = 1$(전 재산을 가로)이 분명히 최적입니다.
그러나 그런 도박을 되풀이하면 언젠가는 빗나가
전 재산을 잃어 버리겠죠.

"make"으로 표시되는 것은 p = 0.99의 경우와 p = 0.7의 경우
시뮬레이션 결과입니다.
"이런 내기를 100일간 진행, 재산이 몇 배가 되었는가"라는
실험을 100번 되풀이해서, 그 히스토그램을 표시합니다.
다만 그대로라면 자릿수가 너무 커져서 몇 배가 됐는지를 상용 로그로
취했습니다.

"-1<="은 0.1배 이상 1배 미만, "0<="은 1배 이상 10배 미만,
"1<="은 10배 이상 100배 미만, "2<="은 100배 이상 1000배 미만,
라는 식입니다.

이 결과를 보면 가장 득이 되는 제비에만 집중하지 않고,
그 반대 경우에도 적당히 투자를 분산하는 게 낫습니다.

==== ◆ sugoroku

주사위 놀이 게임에서 여러분은 플레이어가 아니라 총괄하는 사람입니다.
무한히 긴 오솔길의 주사위 놀이로 여러분은 어딘가 좋아하는 칸에
미리 함정을 걸어 둡니다.
플레이어가 함정에서 멈추면 여러분의 승리이고,
모든 함정을 넘어간다면 여러분의 패배입니다.

우선 함정이 하나의 경우는 어디에 가는 것이 좋을까요?
"make"하면, 함정 장소를 바꿔 봐서, 승률이 어떻게 되는지를 표시합니다.
(O 이 여러분의 승리, X 가 여러분의 패배).
"make long"하면, 더 시행 회수를 늘린 시뮬레이션을 합니다.
표시되는 명령어를 직접 쳐서 "t=" 부분을 바꾸면,
원하는 곳에 함정을 걸어서, 여러 장소를 시험할 수 있습니다.

또한, 함정이 두개라면 어떨까요?
"make two"로 두개의 경우가 시뮬레이션 가능합니다.
"make tlong"하면, 더욱 시행 회수가 늘어난 시뮬레이션을 합니다.
어디에 어느 정도 떨어져서 두는 것이 좋을지는, 이렇게 여러가지 시험해보세요.

더욱이, 3개나 4개라면?

※ 아래 자료를 참고해주세요.
  "xe-kdoo(2007-03-23) 주사위 게임에서 가장 멈추기 쉬운 말은?"
  http://yowaken.dip.jp/tdiary/20070323.html

==== ◆ tomoe

원형 전투를 시뮬레이션합니다.
원형 전투는 A, B, C, 세 명이 있을 때 다음 방식으로 우승자를 결정합니다.
* 먼저 A와 B가 싸운다 → A가 이겼다
* 승자 A가 대기하던 C와 싸운다 → C가 이겼다
* 승자 C가 대기하던 B와 싸운다 → B가 이겼다
* 승자 B가 대기하던 A와 싸운다 → A가 이겼다
* 승자 A가 대기하던 C과 싸운다 → A가 이겼다 …… 연승했기 때문에 A가 우승
이런 식으로 ""진 사람을 교체"해서 뱅글뱅글 계속 싸워서, 누군가가 연승한다면 그 사람이 우승이 됩니다.

원형 전투는 순서에 따른 유불리(有不利)가 있음이 알려져 있습니다.
"make"로 최초에 표시되는 것은,
"누구와 누가 싸워도 승패 확률은 반반"이라는 설정에서의 각자의 승률입니다.
다음으로 표시되는 것은 다음과 같은 설정(C가 이길 확률이 더 큰)에서의 결과입니다.
* A가 B를 이길 확률은 50%
* B가 C를 이길 확률은 45%
* C가 A에 이길 확률은 55%
그 아래는 C가 이길 확률을 더 크게 만들고 있습니다.
C가 이길 확률이 현저히 높은 설정에서도 우승률은 좀처럼 오르지 않네요.

"make long"하면, 더 시행 회수를 늘린 결과가 표시됩니다.

== ■ 힌트

Hint.txt 에 힌트 한마디를 써두었습니다. 스스로 생각해내고 싶은 분은 읽지 말아 주세요.

=end