이 페이지의 목차
시뮬레이션 구현하기 ② 확산
코드 예제: Python · 예상 50분
학습 목표
- 시간에 따라 변하는 현상의 시뮬레이션을 구현하고 개선할 수 있다.
관련 성취기준
- [12소생04-04]
소프트웨어를 적극적으로 활용하여 시뮬레이션 모델을 구현한다.
생각 열기 — 퍼지는 것은 어떻게 퍼질까
반에 감기 걸린 친구가 한 명 있다. 처음에는 몇 명 안 되던 환자가 어느 날 갑자기 많아지고, 또 어느새 줄어든다.
S · I · R — 세 무리로 나누기
- S
아직 안 걸린 사람
Susceptible. 옮을 수 있는 사람. 처음에는 거의 모두가 여기에 있다.
- I
앓는 중인 사람
Infected. 다른 사람에게 옮길 수 있다.
- R
나은 사람
Recovered. 이 모델에서는 다시 걸리지 않는다고 정했다. 백신을 맞은 사람도 처음부터 여기에 둔다.
규칙은 둘이다. ① S 가 I 를 만나면 어떤 확률로 I 가 된다. ② I 는 시간이 지나면 R 이 된다. 처음에 천천히 느는 까닭은 I 가 적어서 만남이 적기 때문이고, 결국 줄어드는 까닭은 옮을 수 있는 S 가 줄어들기 때문이다.
두 가지 모델로 시뮬레이션하기
아래 시뮬레이터에는 같은 현상을 담은 모델이 둘 있다. ① 점으로 보기는 사람 200명이 하나하나 돌아다니는 확률 모델이고, ② 식으로 보기는 세 무리의 «수»만 셈하는 결정론 모델이다.
아직 안 걸림 S 앓는 중 I 나음 R
변수 · 입력
변수를 바꾼 뒤에는 [새로 섞기] 를 눌러야 반영된다.
규칙 (하루마다)
새로 걸리는 사람 = β × S × I ÷ N · 새로 낫는 사람 = γ × I
변수를 바꾸며 실험하기
약 20분① 점으로 보기에서
- 변수를 그대로 두고 끝까지 한 번에를 세 번 눌러 보자(누르기 전에 새로 섞기). 「한 번이라도 걸린 사람」이 매번 같은가?
- 거리 두기를 60%로 올리고 새로 섞기 → ▶ 시작. 지난 실험의 점선과 견주어 앓는 사람의 정점이 어떻게 바뀌는가?
- 거리 두기를 0으로 돌리고 백신을 50%로 올려 보자.
② 식으로 보기에서
- β 를 0.3에서 0.15로 낮춰 보자. 앓는 사람이 가장 많은 날과 그 수가 어떻게 바뀌는가?
- β ÷ γ 가 1보다 작아지게 만들어 보자. 무슨 일이 생기는가?
| ① 점으로 (행위자 모델) | ② 식으로 (SIR 방정식) | |
|---|---|---|
| 사람을 | 한 명 한 명 따로 | 세 무리의 수로만 |
| 우연 | 있다 — 돌릴 때마다 다르다 | 없다 — 언제나 같은 곡선 |
| 잘하는 것 | 사람마다 다른 행동(멈춰 있는 사람)을 넣기 쉽다 | 빠르고, 원리를 식으로 설명하기 쉽다 |
| 아쉬운 것 | 사람이 많으면 계산이 오래 걸린다 | 모두가 고르게 섞인다고 가정한다 |
곡선 평탄화
거리 두기나 손 씻기로 β 를 낮추면 걸리는 사람이 줄 뿐 아니라, 한꺼번에 앓는 사람의 정점이 낮아지고 늦춰진다. 병원의 병상은 한정되어 있으므로 정점이 낮아지는 것만으로도 큰 차이가 난다. 이를 «곡선을 평탄하게 만든다»고 한다.
먼저 식으로 보기의 계산을 파이썬으로 옮겨 보자. 규칙 두 줄이 그대로 코드 두 줄이 된다.
N, I, R = 10000, 10, 0
S = N - I - R
beta, gamma = 0.3, 0.1 # 하루에 옮기는 정도, 하루에 낫는 비율
앓는사람 = [I]
for 날 in range(1, 161):
새감염 = beta * S * I / N
새회복 = gamma * I
S, I, R = S - 새감염, I + 새감염 - 새회복, R + 새회복
앓는사람.append(I)
정점 = max(앓는사람)
print('앓는 사람이 가장 많은 날:', 앓는사람.index(정점), '일째')
print('그날 앓는 사람:', round(정점), '명')
print('160일 뒤 한 번도 안 걸린 사람:', round(S), '명')앓는 사람이 가장 많은 날: 41 일째 그날 앓는 사람: 3127 명 160일 뒤 한 번도 안 걸린 사람: 533 명
S, I, R = … 처럼 세 값을 한 줄에서 함께 바꾸는 것이 중요하다. 따로 세 줄로 쓰면 S 를 먼저 바꾼 뒤 그 새 S 로 I 를 계산하게 되어 결과가 달라진다. 이 계산은 시뮬레이터의 「식으로 보기」와 같은 식이며, 교과서를 만들 때 두 결과가 같은지 컴퓨터로 대조했다.
이제 β 를 반으로 줄였을 때와 견주어 그래프로 그린다.
import matplotlib.pyplot as plt
def 확산(beta, gamma=0.1, N=10000, I=10, 일수=160):
S, R = N - I, 0
앓는사람 = [I]
for _ in range(일수):
새감염 = beta * S * I / N
새회복 = gamma * I
S, I, R = S - 새감염, I + 새감염 - 새회복, R + 새회복
앓는사람.append(I)
return 앓는사람
plt.figure(figsize=(7, 3.5))
plt.plot(확산(0.3), label='β = 0.3 (평소)')
plt.plot(확산(0.15), label='β = 0.15 (거리 두기)')
plt.title('앓는 사람 수의 변화 — 곡선 평탄화')
plt.xlabel('날')
plt.ylabel('앓는 사람 수')
plt.legend()
plt.show()
for b in [0.3, 0.15]:
곡선 = 확산(b)
print(f'β={b}: 정점 {곡선.index(max(곡선))}일째, {round(max(곡선))}명')β=0.3: 정점 41일째, 3127명 β=0.15: 정점 116일째, 646명

돌려 보고 → 견주고 → 고치기
시뮬레이션은 한 번 만들고 끝나지 않는다. 결과를 현실(또는 상식)과 견주고, 어긋나면 모델을 고친다.
- 1모델을 만들어 돌려 본다
- 2결과를 실제 기록이나 상식과 견준다
- 3어긋나는 곳을 찾아 까닭을 짐작한다 (덜어 낸 요소? 잘못 정한 숫자?)
- 4규칙이나 변수를 고친다
- 5다시 돌려 보고 나아졌는지 확인한다
예를 들어 이 모델은 나은 사람이 다시 걸리지 않는다고 정했다. 다시 걸리는 병이라면 「R 이 시간이 지나면 S 로 돌아간다」는 규칙을 더해야 한다. 고치고 다시 견주는 것을 되풀이하며 모델이 쓸모 있어진다.
나만의 시뮬레이션
약 50분4차시에 쓴 시뮬레이션 설계서로 나만의 시뮬레이션을 만든다. 이 단원의 파이썬 예제 가운데 가장 비슷한 것을 고치기 해서 시작하면 좋다 — 줄 서기는 5차시, 우연과 되풀이는 6차시, 시간에 따라 퍼지는 것은 이 차시 예제.
- 줄 서기형
5차시 급식 줄 코드에서
횡단보도 신호, 매점 계산대, 놀이 기구 대기 줄 …
- 되풀이형
6차시 생일·주사위 코드에서
뽑기 확률, 계주 순서, 시험 찍기 점수 …
- 퍼짐형
7차시 SIR 코드에서
소문, 유행어, 숲불, 새 앱의 사용자 수 …
나만의 시뮬레이션 — 만들고 고친 기록
- 물음을 적었다
- 코드나 막힌 곳을 적었다
- 고친 과정을 적었다
- 변수를 바꾼 실험을 했다
- 모델의 한계를 함께 적었다
글자 규칙으로 살펴보는 점검표다. 다 켜졌다고 좋은 답이 되는 것은 아니다 — 마지막 판단은 내가 한다.
적은 내용은 이 브라우저에만 저장된다. 다른 컴퓨터로 옮기거나 제출하려면 내려받는다.
확인 문제
개념 확인 문제
보기를 누르면 바로 채점된다. 틀려도 해설을 읽으면 된다.
SIR 모델에서 아무도 약을 먹지 않았는데도 앓는 사람(I)이 결국 줄어드는 까닭은?12소생04-04
β 를 0.3에서 0.15로 낮추었을 때의 변화로 알맞은 것은?12소생04-04
‘점으로 보기’(행위자 모델)와 ‘식으로 보기’(SIR 방정식)의 차이로 알맞은 것은?12소생04-04
시뮬레이션 결과가 실제 기록과 크게 어긋났을 때 가장 알맞은 다음 행동은?12소생04-04
교과서에서 찾기
이 차시에 대응하는 교과서 위치가 아직 정리되지 않았다. [확인필요]