[Project] Seoul FP-Weather - (1) Introduction & Database

Kyung Jae, Cheong·2022년 11월 7일
0

개인프로젝트

목록 보기
5/17

서울시 월별 기상정보로 서울시 식중독 발생 환자 수를 예측하는 프로그램 Seoul FP-Weather 개발 프로젝트 진행과정 정리 및 회고. (1) 서론과 데이터베이스 구축 과정

Seoul FP-Weather

  • App link = Seoul-FP-Weather (Koyeb 배포)
    • 예측 모델 정상 작동 확인 완료
    • Heroku를 통해 배포하였으나 2022년 11월 28일부터 Heroku 무료 요금제는 더 이상 제공되지 않으므로 Koyep을 통해 재배포 실시

(2023 수정사항)

  • 기존의 프로그램의 경우 Heroku를 통해서 배포를 진행했었으나, heroku 정책상 2022년 11월 28일부터 Heroku 무료 요금제는 더 이상 제공되지 않기 때문에 Application Error가 발생함.
  • 이에 Heroku와 동일하게 Gihub Repository 연동 방식이 가능한 Koyeb을 통해 재배포를 진행하였음.
    • 재배포한 웹사이트에서 예측 모델이 정상적으로 구동됨을 확인 완료함.
    • 대체 링크를 추가하여 수정사항을 반영하였음.

서울시 월별 날씨기반
식중독 환자수 예측
Seoul Food-Posisoning
Prediction by Weather

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

  • Tech Stack

00. 프로젝트 개요

필수 포함 요소

  • 자유주제데이터 파이프라인 구축API 서비스 개발
  • 데이터베이스 구축 (Pull & Store)
  • API 서비스 개발 (Machine Learning & Frond-end)
  • 데이터 분석용 대시보드 개발 및 배포

프로젝트 목차

  • Introduction 서론
    • Food-Poisoning 식중독
    • Seoul FP-Weather 프로그램소개
  • Database 데이터베이스
    • Data Pipeline 파이프라인
    • Database DB구축
  • Modeling 모델링
    • Data Import 데이터 불러오기
    • Regression Modeling 회귀 모델
    • Object Encoding 객체 부호화
  • Deployment 배포
    • Prediction 평년값 예측
    • Dashboard 대시보드
    • Web Deployment 웹 배포
  • Conclusion 결론
    • Applications 활용방안
    • Limitations 한계점
    • Takeaway 핵심, 느낀점

01. Introduction 서론

1-1. Food-Poisoning 식중독

  • 식중독(Food Poisoning) : 식품 또는 물의 섭취에 의해 발생된 감염성, 독소형 질환
    • 세균성 식중독이 가장 흔한 형태
  • 식중독과 날씨
    • 식중독을 일으키는 식중독균은 35~36도 부근에서 가장 빠르게 증식함
    • 고온 다습한 여름철에 위험도가 가장 높음
  • 식중독지수 : 정부기관에서 발표하는 식중독 위험도를 나타내는 지표이며, 온도 및 습도를 고려한 식품의 부패 가능도를 의미함
    • 식중독은 날씨와 연관이 깊음

1-2. Seoul FP-Weather 프로그램 소개

  • 본 프로젝트는 코드스테이츠 AI 부트캠프 Section3 Data Engineering 개인프로젝트로써 협업없이 혼자서 진행한 프로젝트임.
  • 식중독은 날씨와 연관이 깊기 때문에 이러한 날씨 정보를 통해 식중독 환자 수를 인공지능으로 예측해볼 수 있지 않을까? 라는 질문에서 프로젝트를 기획하고 구현하고 배포하게 되었음.
  • 날씨는 지역의 영향이 커서 전국을 대상으로 하지않고 대한민국에서 가장 인구가 밀집되어 있는 서울특별시의 기상정보 및 식중독 데이터를 수집하고 진행하였음.

02. Database 데이터베이스

2-1. Data Pipeline 파이프라인

프로젝트 진행 프로세스

  • 데이터 가져오기 (Data Pull)
  • 데이터 저장하기 (Data Store)
  • 머신러닝 API 및 대시보드 개발
  • Front-end 구현 및 배포

2-2. Database DB구축

데이터 수집

  • 데이터는 Open API를 통해 수집하기도 했고, excel 및 csv 파일 다운로드하여 가공해 사용하기도 하였음.
  • 다운로드 받은 데이터의 가공은 Jupyter Notebook을 통해 진행하였고, pandas 라이브러리를 통해 가공하고 csv파일로 저장하였음.
  • 가공과정 소스코드 : seoul-weather.ipynb (클릭)

  • 월별 식중독 환자수 데이터
    • 식품의약품안전처 공공데이터에서 API key를 신청하고 받아서 사용했으며, 추가요청인자로 서울시 월별 식중독 발생 데이터를 JSON형태로 받아와 이용하였음.
    • 데이터 범위 : 2002년 3월 ~ 2022년 9월
  • 월별 기후 평년값 (1991~2020)
    • 기상청 기상자료개발포털에서 월별 기후 평년값 엑셀 데이터를 다운로드하고 기상청에서 정의하는 8개의 주요요소를 추려내 가공하였음.
    • 주요요소 : 평균기온, 최고기온, 최저기온, 강수량, 평균풍속, 상대습도, 일조시간, 해면기압
  • 서울시 기상개황 통계자료
    • 서울시 열린데이터 광장 데이터 중 서울시 월별 기상개황 통계에서 식중독 환자수 데이터의 범위에 해당하는 기간과 기상청 주요요소 8개를 선택하여 csv형태로 다운로드하고 가공하여 사용하였음.
    • 데이터 범위 : 2002년 1월 ~ 2021년 12월
    • 주요요소 : 평균기온, 최고기온, 최저기온, 강수량, 평균풍속, 상대습도, 일조시간, 해면기압

클라우드 데이터베이스 구축

  • 데이터를 저장하기에 앞서 AWS(아마존 웹 서비스)의 클라우드 데이터베이스 서비스 중에서 Amazon RDS를 통해 서버를 구축하였음.
    • 서버를 지속적으로 유지할 것은 아니라서 free-tier를 이용하였음.
  • 데이터는 관계형데이터베이스(RDB)로 구축하였음.
  • 데이터베이스에 데이터를 저장하고 불러오는 과정은 SQL 시스템 중에서 PostgreSQL을 이용하였음.

데이터베이스에 데이터 저장 (python, PostgreSQL)

  • 호스트 주소, 비밀번호, API key는 보안상의 이유로 dotenv와 .env파일을 이용해 숨김처리하였음.
# library import
import os
import sys
import csv
import json
import psycopg2
import requests
from dotenv import load_dotenv

#PostgreSQL & API 정보를 변수로 저장
load_dotenv(verbose=True)

HOST = os.getenv('postgre_host')
PASSWORD = os.getenv('postgre_password')

DATABASE = 'postgredb'
USERNAME = 'kjcheong'
PORT = 5432

KEY = os.getenv('fp_api_key')
REGION = "서울"
API_URL = f'http://openapi.foodsafetykorea.go.kr/api/{KEY}/I2848/json/1/999/OCCRNC_AREA={REGION}'

#파일 실행시 작동하는 함수안에 과정을 모두 포함
def main():
    # postgreSQL 연결
    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()
    
    # 테이블 초기화(파일 재실행시 오류 최소화)
    cur.execute("""DROP TABLE IF EXISTS fp_seoul;""")
    cur.execute("""DROP TABLE IF EXISTS weather;""")
    cur.execute("""DROP TABLE IF EXISTS w_avg_month;""")
    cur.execute("""DROP TABLE IF EXISTS w_avg_season;""")
    print('4 table dropped')
    
    # 테이블 생성 명령어
    sql_create_table_asv = """CREATE TABLE IF NOT EXISTS w_avg_season (
        season VARCHAR(8) NOT NULL,
        avgTa FLOAT,
        maxTa FLOAT,
        minTa FLOAT,
        sumRn FLOAT,
        avgWs FLOAT,
        avgRhm FLOAT,
        sumSsHr FLOAT,
        avgPs FLOAT,
        CONSTRAINT w_avg_season_PK PRIMARY KEY (season)
        );"""
    sql_create_table_ayv = """CREATE TABLE IF NOT EXISTS w_avg_month (
        month VARCHAR(2) NOT NULL,
        season VARCHAR(8) NOT NULL,
        avgTa FLOAT,
        maxTa FLOAT,
        minTa FLOAT,
        sumRn FLOAT,
        avgWs FLOAT,
        avgRhm FLOAT,
        sumSsHr FLOAT,
        avgPs FLOAT,
        CONSTRAINT w_avg_month_PK PRIMARY KEY (month),
        CONSTRAINT w_avg_month_FK FOREIGN KEY (season) REFERENCES w_avg_season (season)
        );"""
    sql_create_table_w = """CREATE TABLE IF NOT EXISTS weather (
        month_id DATE NOT NULL,
        year VARCHAR(4) NOT NULL,
        month VARCHAR(2) NOT NULL,
        avgTa FLOAT,
        maxTa FLOAT,
        minTa FLOAT,
        sumRn FLOAT,
        avgWs FLOAT,
        avgRhm FLOAT,
        sumSsHr FLOAT,
        avgPs FLOAT,
        CONSTRAINT weather_PK PRIMARY KEY (month_id),
        CONSTRAINT weather_FK FOREIGN KEY (month) REFERENCES w_avg_month (month)        
        );"""
    sql_create_table_fp = """CREATE TABLE IF NOT EXISTS fp_seoul (
        month_id DATE NOT NULL,
        patient_count INTEGER,
        CONSTRAINT fp_seoul_PK PRIMARY KEY (month_id),
        CONSTRAINT fp_seoul_FK FOREIGN KEY (month_id) REFERENCES weather (month_id)
        );"""
    
    #테이블 생성 실행
    cur.execute(sql_create_table_asv)
    cur.execute(sql_create_table_ayv)
    cur.execute(sql_create_table_w)
    cur.execute(sql_create_table_fp)
    
    print('4 table created')
    
    
    # csv file로부터 데이터 추출(서울시 월별 기상개황)
    with open('./data/csv/seoul-weather-month.csv','r') as cf:
        csv_reader = csv.reader(cf)
        next(csv_reader)
        data_w = list(csv_reader)
    
    # api data 수집
    req = requests.get(API_URL)
    raw_data = json.loads(req.text)    
    
    fp_raw = raw_data['I2848']['row']
    data_fp = []
    for row in fp_raw:
        if row["OCCRNC_YEAR"] == "2022":
            continue
        else:
            y_m = row["OCCRNC_YEAR"]+"-"+row["OCCRNC_MM"]
            p_c = row["PATNT_CNT"]
            data_fp.append([y_m,p_c])
    
    # 월별평년값 데이터 추출
    with open('./data/csv/seoul-average-month.csv','r') as cf:
        csv_reader = csv.reader(cf)
        next(csv_reader)
        data_ayv = list(csv_reader)
        
    # 계절평균값 데이터 추출
    with open('./data/csv/seoul-average-season.csv','r') as cf:
        csv_reader = csv.reader(cf)
        next(csv_reader)
        data_asv = list(csv_reader)
    
    #평년값 데이터 삽입 명령어
    sql_insert_asv = """INSERT INTO w_avg_season 
        (season, avgTa, maxTa, minTa, sumRn, avgWs, avgRhm, sumSsHr, avgPs)
        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s);"""
    sql_insert_ayv = """INSERT INTO w_avg_month 
        (month, season, avgTa, maxTa, minTa, sumRn, avgWs, avgRhm, sumSsHr, avgPs)
        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s);"""
    
    # 기상, 식중독 데이터 삽입 명령어
    sql_insert_w = """INSERT INTO weather 
        (month_id, year, month, avgTa, maxTa, minTa, sumRn, avgWs, avgRhm, sumSsHr, avgPs)
        VALUES (TO_DATE(%s,'YYYY.MM'), %s, %s, %s, %s, %s, %s, %s, %s, %s, %s);"""
    sql_insert_fp = """INSERT INTO fp_seoul(month_id, patient_count) VALUES (TO_DATE(%s,'YYYY.MM'), %s);"""
    
    # 데이터 삽입 실행
    cur.executemany(sql_insert_asv, data_asv)
    cur.executemany(sql_insert_ayv, data_ayv)
    cur.executemany(sql_insert_w, data_w)
    cur.executemany(sql_insert_fp, data_fp)
           
    conn.commit()
    conn.close()
    
    print('data inserted to DB')


#파일 실행시 함수 실행 명령
if __name__ == "__main__":
    main()
# $ python data/postgresql-1-rdb.py
'''
connection success to DB
4 table dropped
4 table created
data inserted to DB
'''
  • Data Schema 데이터 스키마

03~. 이후 모델링 과정은 다음 포스팅에서!

profile
Machine Learning Engineer ( AI Engineer )

0개의 댓글