top of page

소스 코드 제출

공개·회원 71명

20250809

import numpy as np

import pandas as pd

import datetime

import math

import random

import matplotlib.pyplot as plt

import matplotlib.dates as mdates

from scipy.integrate import odeint

from geopy.geocoders import Nominatim

import folium

from folium.plugins import HeatMapWithTime

import os

import webbrowser

import time


# 폰트 설정 (한글, 마이너스 부호)

plt.rcParams['font.family'] = 'Malgun Gothic'

plt.rcParams['axes.unicode_minus'] = False




def plot_real_data_graph(df_covid):

df_covid = pd.read_csv('./코로나_확진자_수_통계.csv', encoding='utf-8')

df_covid.columns = df_covid.columns.str.strip()

df = df_covid

x = df['연도'].astype(str).to_numpy()

y = df['확진자'].to_numpy()

plt.figure(figsize=(10, 5))

plt.plot(x, y, marker='o', linestyle='-', color = 'red', label = '코로나 확진률(누적)')

plt.xlabel('연도')

plt.ylabel('확진자')

plt.title('현실 데이터 코로나 확진자 수')

plt.legend()

plt.grid()

plt.show()



# SIRV 모델

def sirv_model_unique(y, t, N, beta_func, gamma, reinfection_rate, vaccination_schedule):

U, S, I, R, C = y

beta = beta_func(t)


vac_effect = sum(rate for start_day, rate in vaccination_schedule if t >= start_day)

new_infections = beta * S * I / N

first_infections = new_infections * (U / S if S > 0 else 0)


dUdt = -first_infections

dSdt = -new_infections + reinfection_rate * R - vac_effect * S

dIdt = new_infections - gamma * I

dRdt = gamma * I - reinfection_rate * R + vac_effect * S

dCdt = first_infections


return dUdt, dSdt, dIdt, dRdt, dCdt



# R0 시간별 변동

def beta_time_dependent(t):

gamma = 1/14

if t <= 365:

R0 = 2.5

elif t <= 600:

R0 = 1.2

elif t <= 800:

R0 = 4.0

elif t <= 1000:

R0 = 1.5

elif t <= 1200:

R0 = 5.0

else:

R0 = 1.0

return R0 * gamma



# 시뮬레이션

def run_sirv_simulation():

N = 50_000_000

I0, R0, C0 = 10, 0, 10

S0 = N - I0 - R0

U0 = N - I0

gamma = 1/14

reinfection_rate = 1/180

vaccination_schedule = [(500, 0.002), (900, 0.003)]


start_date = pd.to_datetime('2020-01-01')

end_date = pd.to_datetime('2024-06-30')

total_days = (end_date - start_date).days

t = np.linspace(0, total_days, total_days + 1)

y0 = U0, S0, I0, R0, C0


ret = odeint(sirv_model_unique, y0, t,

args=(N, beta_time_dependent, gamma, reinfection_rate, vaccination_schedule))


U, S, I, R, C = ret.T

dates = start_date + pd.to_timedelta(t, unit='D')


return dates, U, S, I, R, C, C, N



# 🔵 감염 그래프 출력

def plot_sirv_graph(dates, U, S, I, R, C, N):

U_pct = (U / N) * 100

R_pct = (R / N) * 100

I_pct = (I / N) * 100

C_pct = (C / N) * 100


plt.figure(figsize=(14, 7))

plt.plot(np.array(dates), np.array(I_pct), 'r', linewidth=2, label='현재 감염자 (I%)')

plt.plot(np.array(dates), np.array(R_pct), 'g', linewidth=2, label='회복자 (R%)')

plt.plot(np.array(dates), np.array(C_pct), 'm--', linewidth=2, label='감염 경험자 (C%)')

plt.plot(np.array(dates), np.array(U_pct), 'c--', linewidth=2, label='아직 안 걸린 사람 (U%)')


plt.xlabel('날짜')

plt.ylabel('인구 대비 비율 (%)')

plt.title('현실 반영 코로나 SIRV 시뮬레이션 결과')

plt.legend()

plt.grid()

plt.gca().xaxis.set_major_locator(mdates.MonthLocator(bymonth=[1, 6]))

plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))

plt.xticks(rotation=45)

plt.tight_layout()

plt.show()



def plot_sirv_graph_overlay(dates, U, S, I, R, C, N, df_covid):

U_pct = (U / N) * 100

R_pct = (R / N) * 100

I_pct = (I / N) * 100

C_pct = (C / N) * 100


covid_dates = pd.to_datetime(df_covid['연도'].astype(str) + '-01-01')

covid_confirmed = df_covid['확진자'].to_numpy()

plt.figure(figsize=(14, 7))



ax1 = plt.gca()

ax1.plot(np.array(dates), np.array(I_pct), 'r', linewidth=2, label='시뮬레이션 현재 감염자 (I%)')


ax2 = ax1.twinx()

ax2.plot(np.array(covid_dates), np.array(covid_confirmed), 'b--o', label='현실 누적 확진자')


ax1.set_xlabel('날짜 / 연도')

ax1.set_ylabel('인구 대비 감염자 비율 (%)')

ax2.set_ylabel('확진자 수')


ax1.xaxis.set_major_locator(mdates.YearLocator())

ax1.xaxis.set_major_formatter(mdates.DateFormatter('%Y'))

plt.setp(ax1.get_xticklabels(), rotation=45, ha='right')


ax1.legend(loc='upper left')

ax2.legend(loc='upper right')


plt.title('시뮬레이션 감염자와 현실 누적 확진자 비교')

plt.grid(True)

plt.tight_layout()

plt.show()



# 🗺️ 지도 확산 시각화

def create_heatmap_simulation(dates, I_vals, C_vals, country_name="South Korea"):

geolocator = Nominatim(user_agent="covid_sim")

location = geolocator.geocode(country_name)

if location is None:

raise ValueError(f"{country_name} 좌표를 찾을 수 없습니다.")

center_lat, center_lon = location.latitude, location.longitude


step = 7

heat_data = []

time_index = []


for idx in range(0, len(dates), step):

current_I = I_vals[idx]

current_C = C_vals[idx]

date = dates[idx]


num_points = max(int(current_I / 20000), 5)

spread_radius = max(10, math.sqrt(current_C) / 50)


points = [

random_point_in_circle(center_lat, center_lon, spread_radius)

for _ in range(num_points)

]


heat_data.append(points)

time_index.append(date.strftime("%Y-%m-%d"))


m = folium.Map(location=[center_lat, center_lon], zoom_start=5, tiles='cartodbpositron')


HeatMapWithTime(

data=heat_data,

index=time_index,

auto_play=True,

max_opacity=0.8,

radius=10,

gradient={0.2: 'blue', 0.4: 'lime', 0.6: 'orange', 0.8: 'red'}

).add_to(m)


output_file = "covid_heatmap_simulation.html"

m.save(output_file)

file_path = os.path.abspath(output_file)

print(f"Heatmap 시뮬레이션 저장 완료: {file_path}")

webbrowser.open(f"file://{file_path}")



# 🔁 원형 반경 내 랜덤 포인트

def random_point_in_circle(lat_center, lon_center, radius_km):

r = radius_km * math.sqrt(random.random())

theta = random.uniform(0, 2 * math.pi)

delta_lat = r * math.cos(theta) / 111

delta_lon = r * math.sin(theta) / (111 * math.cos(math.radians(lat_center)))

lat = lat_center + delta_lat

lon = lon_center + delta_lon

return [lat, lon]



# ▶️ 메인 실행

if __name__ == "__main__":

df_covid = pd.read_csv('./코로나_확진자_수_통계.csv', encoding='utf-8')

df_covid.columns = df_covid.columns.str.strip()

dates, U, S, I, R, C, _, N = run_sirv_simulation()

create_heatmap_simulation(dates, I, C, country_name="South Korea")

time.sleep(5)

plot_sirv_graph(dates, U, S, I, R, C, N)

plot_real_data_graph(df_covid)

plot_sirv_graph_overlay(dates, U, S, I, R, C, N, df_covid)

1회 조회
주소 : 경기도 용인시 광교중앙로 302 블루 스퀘어 602호
연락처 : 031) 216 - 1546 ,     031) 215 - 1546
사업자등록번호 : 465-92-00916
​학원 등록 제 4603호
bottom of page