본문 바로가기
수학의 재미/확률분포

술먹고 걷기(Random Walk) #1: 길따라 걷기

by hustler78 2022. 6. 25.
728x90
반응형

 

 

 

 

 

지난 글에서 마팅게일을 다루면서, random walk라는 프로세스가 마팅게일이 된다는 이야기를 했었죠.

 

2022.06.23 - [수학의 재미/확률분포] - 조건부 기댓값과 마팅게일(martingale) #1

 

조건부 기댓값과 마팅게일(martingale) #1

이번 글은 2022.06.22 - [수학의 재미/확률분포] - 확률공간과 조건부기댓값 확률공간과 조건부기댓값 금융공학은 미래를 예측하고, 모델링하는 이론이 자주 등장하기 때문에 확률 공간(ptobability spa

sine-qua-none.tistory.com

위의 글에서는 일차원 random walk를 다뤘습니다. 복습해보면, $X_1, X_2,\cdots,$를 평균이 0인 i.i.d. 확률분포라 하고

$$ S_n = \sum_{i=1}^n X_i $$

라 하면 $S_n$이 바로 random walk 이고 마팅게일이 된다고 했습니다. 

실제 random walk는 어떤 모습을 보일까요? 음주 운전 의심으로 직선 보행 테스트를 받는 사람을 생각해봅시다.

 

똑바로 걸을 수 있다규~

1차원에서 걷는 걸음걸이를 생각해 볼까요? 걸음이라는 확률변수를 $X$로 두고, 

  • 앞으로 한발짝 걷는 것을 : +1
  • 뒤로 한발짝 걷는 것을 : -1

이라 합시다. 앞으로 한 발짝, 뒤로 한 발짝 걷는 확률을 $\frac12$로 똑같다 하고요.

 

$X$ +1 -1
확률 $\frac12$ $\frac12$

그리고 $X_1, X_2, \cdots, $를 모두 $X$와 i.i.d인 확률변수라 합시다. 해석하자면 $X_n$은 $n$번째 걸음이 앞으로냐, 뒤로냐를 결정하는 확률변수인 거죠. 그럼 시작점을 기점으로 $n$번 걸음 후 최종 도착지는

$$ S_n := \sum_{i=1}^n X_i$$

입니다.


술 취한 사람이 1,000 걷는 행보와, 1,000보 걷는 행위를 500회 시켰을 때 어디 어디 도착해 있는지를 한번 볼까요?

def random_walk_1d():
    nSimulation = 500
    nSteps = 1000

    x_finish =[]

    for _ in range(nSimulation):
        x = []
        x0= 0
        x.append(x0)
        a= x0
        for _ in range(nSteps):
            rd = np.random.randint(0, 2)
            if rd==0:
                a += 1
            else:
                a -= 1
            x.append(a)
        x_finish.append(x[-1])

    plt.subplot(221)
    y0= np.zeros(len(x))
    plt.plot(x, y0, marker='o', color = 'c')
    plt.scatter(x[0],y0[0],color='b', s= 100, marker='s')
    plt.text(x[0],y0[0],'start')
    plt.scatter(x[-1], y0[-1], color='r', s=100, marker='s')
    plt.text(x[-1], y0[-1], 'finish')
    plt.title('one random walk({} steps)'.format(nSteps))

    plt.subplot(222)
    yt = [i * 0.5 for i in range(len(x))]
    plt.plot(x, yt, marker='o', color='c')
    plt.scatter(x[0], yt[0], color='b', s=100, marker='s')
    plt.text(x[0], yt[0], 'start')
    plt.scatter(x[-1], yt[-1], color='r', s=100, marker='s')
    plt.text(x[-1], yt[-1], 'finish')
    plt.ylabel('time')
    plt.title('one random walk({} steps with time)'.format(nSteps))

    plt.subplot(223)
    plt.scatter(x_finish, np.zeros(len(x_finish)))
    plt.title('{} simulation of final place of random walk'.format(nSimulation))

    plt.subplot(224)
    mean = np.mean(x_finish)
    plt.hist(x_finish, bins=50)
    plt.vlines(mean, ymin=0, ymax=40, colors='r')
    plt.text(mean,40,'average:{:.2f}'.format(mean))
    plt.title('histogram of final place')

    plt.show()

if __name__ == '__main__':
    random_walk_1d()

 

code 분석은 다음과 같습니다.

 

    nSimulation = 500
    nSteps = 1000

    x_finish =[]

nSteps : 한 번의 random walk 당 술취한 사람이 걷는 걸음수는 1000 걸음입니다.

nSimulation: 1,000 걸음 걷는 random walk 시뮬레이션을 500 회 할 예정입니다.

x_finish : 한번의 random walk 당 종착지를 저장할 list입니다.

 

 

    for _ in range(nSimulation):
        x = []
        x0= 0
        x.append(x0)
        a= x0
        for _ in range(nSteps):
            rd = np.random.randint(0, 2)
            if rd==0:
                a += 1
            else:
                a -= 1
            x.append(a)
        x_finish.append(x[-1])

nSimulation 번 loop를 돌립니다.

x : 한 번의 random walk의 행보를 저장한 list입니다.

x0 : 시작 좌표로서 x의 가장 첫 데이터는 x0입니다.

 

 

        for _ in range(nSteps):
            rd = np.random.randint(0, 2)
            if rd==0:
                a += 1
            else:
                a -= 1
            x.append(a)

for 문 속의 for문입니다. 

np.random.randit(0,2)를 하여 0 이상 2 미만의 정수 난수, 즉 0 또는 1의 난수를 발생합니다.

만일  그 난수가 0 이면 a를 하나 증가 (앞걸음) , 난수가 1이면 a를 하나 감소 (뒷걸음) 시켜 

x 안에 a를 원소로 저장합니다. 

이 것을 nSteps 만큼 loop를 돌립니다.

 

 

        x_finish.append(x[-1])

for 문 속의 for문이 다 돌면 하나의 random walk x가 생기게 되고 x의 마지막 원소인 x[-1]을 x_finish라는 list에 저장시킵니다. 그러면 x_finish 에는 random walk들이 각각 어디서 끝났는지 종착지가 모여 있게 되겠죠.

 

 

    plt.subplot(221)
    y0= np.zeros(len(x))
    plt.plot(x, y0, marker='o', color = 'c')
    plt.scatter(x[0],y0[0],color='b', s= 100, marker='s')
    plt.text(x[0],y0[0],'start')
    plt.scatter(x[-1], y0[-1], color='r', s=100, marker='s')
    plt.text(x[-1], y0[-1], 'finish')
    plt.title('one random walk({} steps)'.format(nSteps))

- subplot을 2*2로 세팅해서 1번째 영역에 그립니다.

- plotting을 위해 y0을 x와 size가 같고 모든 원소가 0이게끔 설정합니다.

- x는 500회 시뮬레이션에서 가장 마지막 시뮬레이션인 500번째에서 탄생한 random walk입니다.

- x[0], y[0] 는 해당 random walk의 시작점을 의미합니다. 시작점을 찍고, 'start'라고 씁니다.

- x[-1], y[-1]은 해당 random walk의 종착점을 의미합니다. 'finish'라고 씁니다

 

 

    plt.subplot(222)
    yt = [i * 0.5 for i in range(len(x))]
    plt.plot(x, yt, marker='o', color='c')
    plt.scatter(x[0], yt[0], color='b', s=100, marker='s')
    plt.text(x[0], yt[0], 'start')
    plt.scatter(x[-1], yt[-1], color='r', s=100, marker='s')
    plt.text(x[-1], yt[-1], 'finish')
    plt.ylabel('time')
    plt.title('one random walk({} steps with time)'.format(nSteps))

- subplot 2*2 영역의 2번째에 그리는 차트입니다.

- 첫 번째 그림과 다른점이 yt를 0.5씩 증가하도록 yt list를 만듭니다. 이유는, 첫번째 그림을 그려보았더니, 1차원으로 움직여서 술 취한 사람 행보가 왔다 갔다 하는 것이 보이지 않아,  어떻게 움직이는지 보기 위해 시간축을 하나 두어 안 겹치도록 그려 본 것입니다. 한 걸음에 0.5초씩 걸린다고 가정했습니다.

 

 

    plt.subplot(223)
    plt.scatter(x_finish, np.zeros(len(x_finish)))
    plt.title('{} simulation of final place of random walk'.format(nSimulation))

- subplot 2*2 영역의 3번째에 그립니다.

- x_finish 즉, random walk 들의 종착지들만 모아서 plotting 한 것입니다. y좌표는 모두 0으로 주었습니다.

- y좌표를 위해 x_finish와 길이가 똑같은 0 벡터를 만들었습니다 : np.zeros(len(x_finish))

 

 

    plt.subplot(224)
    mean = np.mean(x_finish)
    plt.hist(x_finish, bins=50)
    plt.vlines(mean, ymin=0, ymax=40, colors='r')
    plt.text(mean,40,'average:{:.2f}'.format(mean))
    plt.title('histogram of final place')

- 마지막 영역엔 histogram을 그립니다.

- x_finish 즉, 종착역들을 모아 그걸로 hitogram을 그리고 평균을 구해 차트에 표시해봅니다.

 

 

결과는 다음과 같습니다.

 

4가지 그림

위의 두 그림은 똑같은 그림인데, 시간축을 고려해서 random walk가 안 겹치도록 그린 그림입니다. 겁나게 싸돌아 댕겼네요~ 0에서 시작해서 왔다 갔다 장난 아닙니다.

 

아래의 두 그림은 술 취한 500명을 풀어놓아 천 걸음 걷게 해서 어디 도달한 건지를 찍어본 것입니다. 제일 멀리 간 이들은 100 걸음 이상씩도 가 있네요. 하지만 오른쪽 아래 그림을 보면 보통 자기 시작점에서 맴돌고 있는 걸 볼 수 있습니다. 그도 그럴것이 한 걸음을 나타낸 $X$라는 확률변수의 기댓값이 0이기 때문이죠.

히스토그램에서 볼수 있듯이 평균은 거의 0 근처에 있습니다. 아마 시뮬레이션 횟수를 크게 하면 훨씬 더 0에 가깝겠죠.

 


 

coding을 하다 보니 헷갈릴 만한 것이 있어 정리합니다. code 중에

            rd = np.random.randint(0, 2)

부분이 있었죠?

numpy 모듈 안의 random 모듈안의 randint는 (0,2) 인자를 받으면 0 이상 2 미만이라는 얘깁니다. 반면에

random 모듈 안에 randint 도 있습니다. random.randint(0,2)는 0 이상 2 이하입니다. 난수 발생할 때 주의해야겠습니다.

자세한 것을  여기에 기록해두겠습니다.

 

 

다음 글에서는 술취한 사람의 좀 더 멋있고 광폭적인 행보인 2차원 평면에서 쏘다니는 모습을 그려보도록 하겠습니다.

728x90
반응형

댓글