서울시 월별 기상정보로 서울시 식중독 발생 환자 수를 예측하는 프로그램 Seoul FP-Weather 개발 프로젝트 진행과정 정리 및 회고. (3) 대시보드 및 웹페이지 구현, 배포 과정

(2023 수정사항)

서울시 월간 기상정보를 기반으로 서울시 월간 식중독 발생 환자 수를 예측하는 AI 머신 러닝 프로그램
Tech Stack

자유주제로 데이터 파이프라인 구축 및 API 서비스 개발Pull & Store)Machine Learning & Frond-end)대시보드 개발 및 배포서론식중독프로그램소개데이터베이스파이프라인DB구축모델링데이터 불러오기회귀 모델객체 부호화배포평년값 예측대시보드웹 배포결론활용방안한계점핵심, 느낀점
머신러닝에도 이용했던 서울 월별 기상요인 및 식중독 환자 수 데이터는 식중독 환자 발생 트렌드를 확인하기위한 대시보드를 제작하는데 이용하였음.
서울 월별,계절별 기후평년값 데이터는 pickle 라이브러리를 통해 불러온 모델을 통해 예측을 실시한 후에 예측에 대한 대시보드를 제작하는데 이용하였음.
Bootstrap template을 기반으로 HTML5, CSS3를 통해 웹페이지를 구현하였고, 모바일 버젼에서도 편하게 볼 수 있게끔 웹페이지를 최적화하는 작업도 수행하였음.

import numpy as np
import pandas as pd
import pickle
import os
import sys
import psycopg2
from dotenv import load_dotenv
#dotenv 로딩
load_dotenv(verbose=True)
'''
True
'''
#env 파일로부터 변수 추출
HOST = os.getenv('postgre_host')
PASSWORD = os.getenv('postgre_password')
DATABASE = 'postgredb'
USERNAME = 'kjcheong'
PORT = 5432
#연결
try:
conn = psycopg2.connect(
host=HOST,
port=PORT,
database=DATABASE,
user=USERNAME,
password = PASSWORD)
cur = conn.cursor()
print('connection success to DB')
except:
print('connection failure to DB')
sys.exit()
'''
connection success to DB
'''
#DB를 dataframe으로 저장
import pandas.io.sql as psql
month_avg = psql.read_sql("SELECT * FROM w_avg_month", conn)
month_avg

season_avg = psql.read_sql("SELECT * FROM w_avg_season", conn)
season_avg

#연결 종료
conn.close()
#예측에 쓰일 변수만 남기기
month_var = month_avg.iloc[:,2:]
display(month_var)
season_var = season_avg.iloc[:,1:]
display(season_var)

#모델 복호화
model = pickle.load(open("model.pkl", "rb"))
#예측
predict_month = model.predict(month_var).round(0)
predict_season = model.predict(season_var).round(0)
print(predict_month)
print(predict_season)
'''
[ 94. 34. 16. 14. 142. 222. 162. 171. 124. 80. 68. 149.]
[ 72. 188. 54. 52.]
'''
#기존 dataframe에 column 추가
month_pred = month_avg.copy()
season_pred = season_avg.copy()
month_pred['predict_patient'] = predict_month.astype(int)
season_pred['predict_patient'] = predict_season.astype(int)
display(month_pred)
display(season_pred)

#csv file로 저장
month_pred.to_csv('csv/pred-month.csv', index=False)
season_pred.to_csv('csv/pred-season.csv', index=False)






Seoul-FP-Weather
├── app.py
├── data
│ └── model.pkl
├── templates
│ ├── index.html
│ ├── 404.html
│ ├── 404-1.html
│ └── 404-2.html
├── static
│ ├── css
│ ├── img
│ ├── js
│ └── favicon.ico
├── Procfile
└── requirements.txt
#라이브러리 import
from flask import Flask, render_template, request
import numpy as np
import pickle
#플라스크 클래스명 지정 및 모델 불러오기
app = Flask(__name__)
model = pickle.load(open("./data/model.pkl", "rb"))
#에러 페이지 데코레이터
@app.errorhandler(404)
def page_not_found(error):
return render_template('404.html'), 404
#웹 페이지 rendering
@app.route('/', methods=['GET', 'POST'])
def index():
#웹페이지 (GET)
if request.method == 'GET':
return render_template('index.html'), 200
#입력 변수를 서버에 보내 예측 실행 (POST)
if request.method == 'POST':
try:
var1 = float(request.form['avgTa'])
var2 = float(request.form['maxTa'])
var3 = float(request.form['minTa'])
var4 = float(request.form['sumRn'])
var5 = float(request.form['avgWs'])
var6 = float(request.form['avgRhm'])
var7 = float(request.form['sumSsHr'])
var8 = float(request.form['avgPs'])
array = np.array([[var1, var2, var3, var4, var5, var6, var7, var8]])
pred = int(model.predict(array).round(0))
if pred < 0 :
return render_template('404-1.html') #에러페이지(예상범위를 벗어남)
else :
return render_template('index.html',pred=pred)
except:
return render_template('404-2.html') #에러페이지(숫자만 입력하시오)
#앱 실행코드 (디버깅 모드)
if __name__ == "__main__":
app.run(debug=True)
...
<div class="cover-req" style="background-color: #444;">
<br>
<h1 class="cover-heading">
<p>기상 정보를 입력해주세요<br>(숫자만 입력해주세요)</p>
</h1>
<div class="content-grid">
<div class="heading-grid">
<div class="grid-contents">
<div class="work-request--info">
<form action="/#predict-req" method="post">
<div class="info-name" style="width: 150px; margin-bottom: 20px;">
<label for="formGroupExampleInput">월 평균 기온 (℃)</label>
<input type="text" name="avgTa" required>
</div>
<div class="info-name" style="width: 150px; margin-bottom: 20px;">
<label for="formGroupExampleInput">월 최고 기온 (℃)</label>
<input type="text" name="maxTa" required>
</div>
<div class="info-name" style="width: 150px; margin-bottom: 20px;">
<label for="formGroupExampleInput">월 최저 기온 (℃)</label>
<input type="text" name="minTa" required>
</div>
<div class="info-name" style="width: 150px; margin-bottom: 20px;">
<label for="formGroupExampleInput">월 합 강수량 (mm)</label>
<input type="text" name="sumRn" required>
</div>
<div class="info-name" style="width: 150px; margin-bottom: 20px;">
<label for="formGroupExampleInput">월 평균 풍속 (m/s)</label>
<input type="text" name="avgWs" required>
</div>
<div class="info-name" style="width: 150px; margin-bottom: 20px;">
<label for="formGroupExampleInput">월 평균 상대습도 (%)</label>
<input type="text" name="avgRhm" required>
</div>
<div class="info-name" style="width: 150px; margin-bottom: 20px;">
<label for="formGroupExampleInput">월 합 일조시간 (hr)</label>
<input type="text" name="sumSsHr" required>
</div>
<div class="info-name" style="width: 150px; margin-bottom: 20px;">
<label for="formGroupExampleInput">월 평균 해면기압 (hpa)</label>
<input type="text" name="avgPs" required>
</div>
<button type="submit" class="btn btn-lg btn-default">
<img src="../static/img/icon.png" alt="FP-Weather"> Predict !
</button>
</form>
</div>
</div>
<div class="grid-contents">
<div class="predict-result">
{% if pred %}
<br><br>
<img src="../static/img/icon-96.png">
<h2>서울시<br></h2>
<h3>월별 식중독<br><br>환자 수<br><br>예측 결과<br></h3>
<h2>{{ pred }} 명</h2>
<br>
<img src="../static/img/icon-96.png">
<br>
{% endif %}
</div>
</div>
</div>
</div>
</div>
...
입력

출력

성공적으로 작동!
Github Repository 생성
Heroku 회원가입 후 로그인 (Authenticator라는 휴대폰 어플을 통해 인증 후 로그인하였음)

앱 생성

깃허브 연결
web: gunicorn app:app
#python=3.8
#pip freeze > requirements.txt
certifi==2022.9.24
charset-normalizer==2.1.1
click==8.1.3
colorama==0.4.6
contourpy==1.0.6
cycler==0.11.0
Flask==2.2.2
fonttools==4.38.0
gunicorn==20.1.0
idna==3.4
importlib-metadata==5.0.0
itsdangerous==2.1.2
Jinja2==3.1.2
joblib==1.2.0
kiwisolver==1.4.4
lightgbm==3.3.3
MarkupSafe==2.1.1
matplotlib==3.6.0
numpy==1.23.4
packaging==21.3
pandas==1.5.1
Pillow==9.3.0
psycopg2-binary==2.9.5
pyparsing==3.0.9
python-dateutil==2.8.2
python-dotenv==0.21.0
pytz==2022.5
requests==2.28.1
scikit-learn==1.1.3
scipy==1.9.3
seaborn==0.12.1
six==1.16.0
threadpoolctl==3.1.0
urllib3==1.26.12
Werkzeug==2.2.2
wincertstore==0.2
zipp==3.10.0



기상요인을 통해 식중독 발생 환자 수를 예측하는 프로그램을 구현하고 배포하는 것이 프로젝트의 핵심. -> 성공적인 구현 및 배포 완료.Data 수집, Cloud DB 구축, 머신러닝 API 서비스 개발, 대시보드 제작, 웹페이지 구현, 모바일 최적화 작업 등...!