(14주차) 12월9일
징검다리3 문제풀이 (풀이2,3)
-
(1/5) 징검다리 문제 III 두번째 풀이 (1)
-
(2/5) 징검다리 문제 III 두번째 풀이 (2)
-
(3/5) 징검다리 문제 III 세번째 풀이 (1)
-
(4/5) 징검다리 문제 III 세번째 풀이 (2)
-
(5/5) 징검다리 문제 III 세번째 풀이 (3)
강화유리와 유리를 구분할 수 있는 유리 장인이 있다.
이 유리장인은 80퍼센트의 확률로 강화유리를 고른다.
총 10명의 참가자가 있고 이 참가자들은 (유리,강화유리)의 조합으로 이루어진 징검다리를 5번연속으로 건너야 한다.
아래의 경우에 참가자들은 평균적으로 몇명이 살아남겠는가?
(1) 일반인1 - 일반인2 - .... - 일반인9 - 유리장인 || (강화유리, 유리)
(2) 유리장인 - 일반인1 - 일반인2 - ... - 일반인9 || (강화유리, 유리)
1000번 시뮬레이션을 하여 결과를 추정하라.
(단, 일반인은 50%의 확률로 강화유리를 고를수 있다고 하자)
[예시] (1)의 시뮬레이션 결과가 아래와 같다고 하자.
- 첫번째 징검다리: 유리장인이 강화유리 선택
- 두번째 징검다리: 유리장인이 강화유리 선택
- 세번째 징검다리: 유리장인이 일반유리 선택 $\to$ 유리장인 탈락 & 일반인9는 당연히 강화유리를 선택
- 네번째 징검다리: 일반인9가 일반유리 선택 $\to$ 일반인9 탈락 & 일반인8은 당연히 강화유리 선택
- 다섯번째 징검다리: 일반인8이 강화유리 선택
이 경우는 일반인8,일반인7, $\dots$, 일반인1이 살아남으므로 8명이 살아남는다.
[예시] (2)의 시뮬레이션 결과가 아래와 같다고 하자.
- 첫번째 징검다리: 일반인9 일반유리 선택 $\to$ 일반인9 탈락 & 일반인8은 강화유리 선택
- 두번째 징검다리: 일반인8 일반유리 선택 $\to$ 일반인8 탈락 & 일반인7은 강화유리 선택
- 세번째 징검다리: 일반인7 일반유리 선택 $\to$ 일반인7 탈락 & 일반인6은 강화유리 선택
- 네번째 징검다리: 일반인6 일반유리 선택 $\to$ 일반인6 탈락 & 일반인5는 강화유리 선택
- 다섯번째 징검다리: 일반인5 일반유리 선택 $\to$ 일반인5 탈락 & 일반인4는 강화유리 선택
이 경우는 일반인4,일반인3,일반인2,일반인1,유리장인 이 살아남는다. (따라서 5명)
-
즉 살아남을수 있는 최대인원수는 10명이며 최소인원수는 5명이다.
-
유리장인이 100%의 확률로 강화유리를 구분한다면 (1)의 경우 항상 10명이 살아남는다. (즉 평균도 10명)
-
아래와 같은 수식을 세울 수 있다.
총 살아남은 사람의 수 = 5 + 장인의 성공횟수 + (5-장인의성공횟수-1)의 기회중에서 일반인의 성공횟수
- 단 (5-장인의성공횟수-1)=<0 이면 마지막항은 0으로 계산한다.
-
장인의 성공횟수를 $x$, 일반인의 성공횟수를 $y$라고 하자. 그러면 구하는것은 $5+x+y$이다.
-
장인의 성공횟수
library(tidyverse)
x_ = rbinom(5,size=1,0.8)
x_
cumprod(x_)
x=sum(cumprod(x_))
print(x)
-
일반인의 성공횟수
xx_ = 5-x-1
print(xx_)
y = rbinom(1, size=xx_, 0.5)
y
-
살아남은 사람수는?
print(5+x+y)
-
정리하면
rslt <- c()
for (i in 1:10000){
x=sum(cumprod(rbinom(5,size=1,0.8)))
xx_=5-x-1
if (xx_>0) y = rbinom(1, size=xx_, 0.5) else y=0
rslt[i]=5+x+y
}
mean(rslt)
ARR = c('N1','N2','N3','N4','N5','N6','N7','N8','N9','A')
ARR
SURV = 10
PLAYER = ARR[SURV]
PLAYER
STAGE = 0
-
첫시도
toss = function(p) rbinom(n=1,size=1,prob=p) %>% as.logical
PROB = 0.8
TOSSRSLT = toss(PROB)
if (TOSSRSLT==TRUE){
SURV = SURV
STAGE = STAGE + 1
PLAYER = ARR[SURV]
}else{
SURV = SURV - 1
STAGE = STAGE + 1
PLAYER = ARR[SURV]
}
print(TOSSRSLT)
print(SURV)
print(STAGE)
print(PLAYER)
-
코드를 간단히 수정하자.
PROB = 0.8
TOSSRSLT = toss(PROB)
if (TOSSRSLT==FALSE) SURV = SURV - 1
STAGE = STAGE + 1
PLAYER = ARR[SURV]
print(TOSSRSLT)
print(SURV)
print(STAGE)
print(PLAYER)
-
다시 처음부터 보고싶다면?
SURV = 10
STAGE = 0
PLAYER = ARR[SURV]
PROB = 0.8
TOSSRSLT = toss(PROB)
if (TOSSRSLT==FALSE) SURV = SURV - 1
STAGE = STAGE + 1
PLAYER = ARR[SURV]
print(TOSSRSLT)
print(SURV)
print(STAGE)
print(PLAYER)
-
reset을 하는 함수를 만들자.
reset = function(){
SURV = 10
STAGE = 0
PLAYER = ARR[SURV]
}
- 제대로 동작하지 않음 $\to$
=
를<<-
로 수정해보자.
reset = function(){
SURV <<- 10
STAGE <<- 0
PLAYER <<- ARR[SURV]
}
reset()
print(TOSSRSLT)
print(SURV)
print(STAGE)
print(PLAYER)
-
출력함수의 기능을 묶어보자. $\to$ 출력(display)와 저장기능을 통합하여 record 함수 만듬
record = function() list(TOSSRSLT=TOSSRSLT, SURV=SURV, STAGE=STAGE, PLAYER=PLAYER)
record()$SURV %>% print
-
reset + record 를 사용하고 결과를 살펴보면
reset()
record()
- TOSSRSLT의 의미가 헷갈릴수 있으니 약간 수정하자.
record = function() list(PRE_TOSSRSLT=TOSSRSLT, SURV=SURV, STAGE=STAGE, PLAYER=PLAYER)
reset = function(){
TOSSRSLT <<- NA
SURV <<- 10
STAGE <<- 0
PLAYER <<- ARR[SURV]
}
reset()
record()
-
지금까지 코드의 중간정리
ARR = c('N1','N2','N3','N4','N5','N6','N7','N8','N9','A')
SURV = 10
PLAYER = ARR[SURV]
STAGE = 0
PROB = 0.8
TOSSRSLT = NA
### 변수들의 모음
toss = function(p) rbinom(n=1,size=1,prob=p) %>% as.logical
reset = function(){
TOSSRSLT <<- NA
SURV <<- 10
STAGE <<- 0
PLAYER <<- ARR[SURV]
}
record = function(){
list(PRE_TOSSRSLT=TOSSRSLT, SURV=SURV, STAGE=STAGE, PLAYER=PLAYER)
}
### 함수들의 모음
PROB = 0.8
TOSSRSLT = toss(PROB)
if (TOSSRSLT==FALSE) SURV = SURV - 1
STAGE = STAGE + 1
PLAYER = ARR[SURV]
### body
-
PROB 가 항상 0.8인것은 아니며 사실 PLAYER=='A' 일 경우에만 0.8 이고 그외의 경우는 0.5 이다.
ARR = c('N1','N2','N3','N4','N5','N6','N7','N8','N9','A')
SURV = 10
PLAYER = ARR[SURV]
STAGE = 0
PROB = 0.8
TOSSRSLT = NA
### 변수들의 모음
toss = function(p) rbinom(n=1,size=1,prob=p) %>% as.logical
reset = function(){
TOSSRSLT <<- NA
SURV <<- 10
STAGE <<- 0
PLAYER <<- ARR[SURV]
}
record = function(){
list(PRE_TOSSRSLT=TOSSRSLT, SURV=SURV, STAGE=STAGE, PLAYER=PLAYER)
}
### 함수들의 모음
PROB = 0.5+ (PLAYER=='A')*0.3 #### 이부분을 수정했음
TOSSRSLT = toss(PROB)
if (TOSSRSLT==FALSE) SURV = SURV - 1
STAGE = STAGE + 1
PLAYER = ARR[SURV]
### body
-
Test 해보자.
reset()
record()
PROB = 0.5+ (PLAYER=='A')*0.3 #### 이부분을 수정했음
TOSSRSLT = toss(PROB)
if (TOSSRSLT==FALSE) SURV = SURV - 1
STAGE = STAGE + 1
PLAYER = ARR[SURV]
record()
-
스테이지를 진행하는 부분을 묶어서 함수로 처리하자.
ARR = c('N1','N2','N3','N4','N5','N6','N7','N8','N9','A')
SURV = 10
PLAYER = ARR[SURV]
STAGE = 0
PROB = 0.8
TOSSRSLT = NA
### 변수들의 모음
toss = function(p) rbinom(n=1,size=1,prob=p) %>% as.logical
reset = function(){
TOSSRSLT <<- NA
SURV <<- 10
STAGE <<- 0
PLAYER <<- ARR[SURV]
}
record = function(){
list(PRE_TOSSRSLT=TOSSRSLT, SURV=SURV, STAGE=STAGE, PLAYER=PLAYER)
}
go = function(){
PROB <<- 0.5+ (PLAYER=='A')*0.3
TOSSRSLT <<- toss(PROB)
if (TOSSRSLT==FALSE) SURV <<- SURV - 1
STAGE <<- STAGE + 1
PLAYER <<- ARR[SURV]
}
### 함수들의 모음
### body
-
test
reset()
record()
go()
record()
-
어차피 5번 시행을 하므로 go이외에 gogo함수를 따로 만들자.
ARR = c('N1','N2','N3','N4','N5','N6','N7','N8','N9','A')
SURV = 10
PLAYER = ARR[SURV]
STAGE = 0
PROB = 0.8
TOSSRSLT = NA
### 변수들의 모음
toss = function(p) rbinom(n=1,size=1,prob=p) %>% as.logical
reset = function(){
TOSSRSLT <<- NA
SURV <<- 10
STAGE <<- 0
PLAYER <<- ARR[SURV]
}
record = function(){
list(PRE_TOSSRSLT=TOSSRSLT, SURV=SURV, STAGE=STAGE, PLAYER=PLAYER)
}
go = function(){
PROB <<- 0.5+ (PLAYER=='A')*0.3
TOSSRSLT <<- toss(PROB)
if (TOSSRSLT==FALSE) SURV <<- SURV - 1
STAGE <<- STAGE + 1
PLAYER <<- ARR[SURV]
}
gogo = function() for(i in 1:5) go()
### 함수들의 모음
-
test
reset()
record()
gogo()
record()
-
히스토리를 볼 수 있는 gogo함수를 만들어보자.
gogo_history = function(){
rslt_ = as_tibble(record()) ## go를 시작하기전의 결과가 티블로 만들어짐
for(i in 1:5){
go()
rslt_ = rbind(rslt_, as_tibble(record()))
}
print(rslt_)
}
reset()
record()
gogo_history()
-
이제 simulate_once 라는 함수를 만들어서 시뮬레이션 결과를 저장하자.
simulate_once = function(){
reset()
gogo()
return(record()$SURV )
}
simulate_once() %>% print
-
따라서 답은
simrslt = c()
for (i in 1:100000) simrslt[i] = simulate_once()
mean(simrslt) %>% print
-
코드를 최종적으로 정리하면
ARR = c('N1','N2','N3','N4','N5','N6','N7','N8','N9','A')
SURV = 10
PLAYER = ARR[SURV]
STAGE = 0
PROB = 0.8
TOSSRSLT = NA
### 변수들의 모음
toss = function(p) rbinom(n=1,size=1,prob=p) %>% as.logical
reset = function(){
TOSSRSLT <<- NA
SURV <<- 10
STAGE <<- 0
PLAYER <<- ARR[SURV]
}
record = function(){
list(PRE_TOSSRSLT=TOSSRSLT, SURV=SURV, STAGE=STAGE, PLAYER=PLAYER)
}
go = function(){
PROB <<- 0.5+ (PLAYER=='A')*0.3
TOSSRSLT <<- toss(PROB)
if (TOSSRSLT==FALSE) SURV <<- SURV - 1
STAGE <<- STAGE + 1
PLAYER <<- ARR[SURV]
}
gogo = function() for(i in 1:5) go()
gogo_history = function(){
rslt_ = as_tibble(record()) ## go를 시작하기전의 결과가 티블로 만들어짐
for(i in 1:5){
go()
rslt_ = rbind(rslt_, as_tibble(record()))
}
print(rslt_)
}
simulate_once = function(){
reset()
gogo()
return(record()$SURV )
}
### 함수들의 모음
simrslt = c()
for (i in 1:100000) simrslt[i] = simulate_once()
mean(simrslt)
### body
-
장점: 함수의 입력/출력을 상당부분 생략가능, 함수의 출력을 어딘가에 저장하는 번거로운 과정도 스킵가능, 구현이 쉬움
-
단점: 지정한 변수들과 함수의 목록을 한번에 파악하기 힘듬. 하나의 노트북에서 다른 풀이도 함께하다보면 변수이름들이 매우 헷갈릴수 있음.
-
단점을 극복하기 위한 대안 (1) 하나의 노트북을 사용한다. (2) 변수나 함수들을 모두 초기화한다. (커널초기화) (3) 이 모든것을 하나의 함수로 묶는다.
-
(2) 변수나 함수들을 모두 초기화하는 방법
ls() ## 현재 R에 저장된 변수목록을 출력
rm(list=ls()) # 현재 R환경에 있는 함수+변수를 삭제
ls() ## 현재 R에 저장된 변수목록을 출력
- 이제 R에는 더이상 함수나 변수가 없다.
-
(3) 이 모든것을 하나의 함수로 묶는방법
rm(list=ls())
ls()
- 일단 R환경은 깨끗한 상태임
SIMULATE = function(){
### 변수들의 모음
ARR = c('N1','N2','N3','N4','N5','N6','N7','N8','N9','A')
SURV = 10
PLAYER = ARR[SURV]
STAGE = 0
PROB = 0.8
TOSSRSLT = NA
### Subfunction들의 모음
toss = function(p) rbinom(n=1,size=1,prob=p) %>% as.logical
reset = function(){
TOSSRSLT <<- NA
SURV <<- 10
STAGE <<- 0
PLAYER <<- ARR[SURV]
}
record = function(){
list(PRE_TOSSRSLT=TOSSRSLT, SURV=SURV, STAGE=STAGE, PLAYER=PLAYER)
}
go = function(){
PROB <<- 0.5+ (PLAYER=='A')*0.3
TOSSRSLT <<- toss(PROB)
if (TOSSRSLT==FALSE) SURV <<- SURV - 1
STAGE <<- STAGE + 1
PLAYER <<- ARR[SURV]
}
gogo = function() for(i in 1:5) go()
gogo_history = function(){
rslt_ = as_tibble(record()) ## go를 시작하기전의 결과가 티블로 만들어짐
for(i in 1:5){
go()
rslt_ = rbind(rslt_, as_tibble(record()))
}
print(rslt_)
}
simulate_once = function(){
reset()
gogo()
return(record()$SURV )
}
### BODY
simrslt = c()
for (i in 1:100000) simrslt[i] = simulate_once()
mean(simrslt)
}
ls()
- 현재는 SIMULATE 하나만 저장되어있음
SIMULATE()
ls()
- 실행한이후에도 SIMULATE 하나만 저장되어 있음