한국형 우울증 딥러닝 예측 모델 및 진단 프로그램 "Kor-DEEPression" 개발 과정 정리 및 회고.
(2) Preprocess & Database (전처리 & 데이터베이스 구축)
(Part2) Database 데이터베이스
데이터 전처리
클라우드 DB 구축
SQL쿼리
# 라이브러리 import
import pandas as pd
# 라이브러리 및 함수 Import
import pandas as pd
from custom_modules.preprocess import *
# column 리스트 정의(기본변수, 건강설문, 생활습관, 만성질환, 우울증변수)
col_demo = ['year', 'age', 'HE_BMI', 'sex', 'edu', 'genertn', 'marri_2', 'EC1_1']
col_health = ['D_1_1', 'LQ4_00', 'D_2_1', 'BO1_1', 'BO2_1']
col_life = ['BD1_11', 'BD2_1', 'sm_presnt', 'BP1']
col_disease = ['HE_HP', 'HE_DM', 'HE_HCHOL', 'HE_HTG']
col_disease_20 = ['HE_HP', 'HE_DM_HbA1c', 'HE_HCHOL', 'HE_HTG']
col_dpr = ['DF2_pr', 'mh_PHQ_S']
# 데이터 불러오기 기능(2014, 2016, 2018)
def data_load(filedir):
'''
data_load
데이터 불러오기 기능(2014, 2016, 2018)
---
입력 변수 정보
filedir : (str)불러올 파일의 디렉토리
---
출력 : DataFrame
'''
# csv file 불러오기(여러 type이 섞여있는 column도 있으므로 low_memory=False로 설정)
df0 = pd.read_csv(filedir, low_memory=False)
# 분석에 이용할 column list를 정의(리스트 합 연산)
col_list = ['id']+col_demo+col_health+col_disease+col_life+col_dpr
# column list에 해당하는 column을 추출
df1 = df0[col_list]
# column을 추출한 DataFrame 출력
return df1
# 데이터 불러오기 기능(2020)
def data_load_20(filedir):
'''
data_load
데이터 불러오기 기능(2020)
---
입력 변수 정보
filedir : (str)불러올 파일의 디렉토리
---
출력 : DataFrame
'''
# csv file 불러오기(여러 type이 섞여있는 column도 있으므로 low_memory=False로 설정)
df0 = pd.read_csv(filedir, low_memory=False)
# 분석에 이용할 column list를 정의(리스트 합 연산)
col_list = ['ID']+col_demo+col_health+col_disease_20+col_life+col_dpr
# column list에 해당하는 column을 추출 및 column 이름을 통일시키기
df1 = df0[col_list].rename(columns={'ID':'id','HE_DM_HbA1c':'HE_DM'})
# column을 추출한 DataFrame 출력
return df1
# 데이터 불러오기 기능
df14 = data_load('./1_DataBase/downloads/raw_data/HN14_ALL.csv')
df16 = data_load('./1_DataBase/downloads/raw_data/HN16_ALL.csv')
df18 = data_load('./1_DataBase/downloads/raw_data/HN18_ALL.csv')
df20 = data_load_20('./1_DataBase/downloads/raw_data/HN20_ALL.csv')
print('\nData Loading : Success')
print(df14.shape, df16.shape, df18.shape, df20.shape)
'''
Data Loading : Success
(7550, 24) (8150, 24) (7992, 24) (7359, 24)
'''
# 데이터 병합 기능(concatenate)
def concat_df(df_list):
'''
concat_df
데이터 병합 기능 (row 방향)
---
입력 변수 정보
df_list : (list)병합할 DataFrame의 List
---
출력 : DataFrame
'''
# concat(default는 row 방향, index 초기화를 위해 ignore_index=True로 설정)
df = pd.concat(df_list, ignore_index=True)
# 병합한 DataFrame 출력
return df
# 데이터 병합 기능
df_list = [df14, df16, df18, df20]
df = concat_df(df_list)
print('\nData Merge : Success')
print(df.shape)
'''
Data Merge : Success
(31051, 24)
'''
# 결측치 제거 기능 : 결측치는 ' '(공백)으로 채워져 있음
def drop_nan_df(df):
'''
drop_nan_df
결측치 제거 기능 (결측치는 ' '(공백)으로 채워져 있음)
---
입력 변수 정보
df : (DataFrame)결측치 제거할 DataFrame
---
출력 : 결측치 제거 후 DataFrame
'''
# 공백(' ')을 None값으로 변환하는 함수 정의
def fill_nan(value):
if value == ' ':
value = None
return value
# 원본 데이터 변환 방지를 위해 copy 실시
df1 = df.copy()
# applymap으로 모든 데이터 값에 변환 함수를 적용
df1 = df1.applymap(fill_nan)
# 결측치가 하나라도 존재(any)하면 row(axis=0)를 제거
df1 = df1.dropna(axis=0, how='any')
# 결측치 제거한 DataFrame 출력
return df1
# 결측치 제거 기능 1
df_drop = drop_nan_df(df)
print('\nDroped NaN values : Success')
# print(df_drop.info())
'''
Droped NaN values : Success
'''
# dtype변환을 간단하게 처리하기 위해 임시 저장 후 다시 불러오기
df_drop.to_csv('./1_DataBase/downloads/temp_data/HN_drop_14_20.csv', index=False)
df_temp = pd.read_csv('./1_DataBase/downloads/temp_data/HN_drop_14_20.csv')
# csv editor를 통해 직접 확인하였으며, 제거는 query함수로 실시함
def drop_9s_df(df):
'''
drop_9s_df
설문변수 무응답 데이터(결측치) 제거 기능 (9 또는 99)
---
입력 변수 정보
df : (DataFrame)결측치 제거할 DataFrame
---
출력 : 결측치 제거 후 DataFrame
'''
# marri_2(결혼상태), D_1_1(주관적건강인지)
df1 = df.query('marri_2!=99 and marri_2!=8 and marri_2!=9 and D_1_1!=9')
# BO1_1(연간체중변화), BD1_11(연간음주빈도), BD2_1(1회음주량), BP1(스트레스인지정도)
df2 = df1.query('BO1_1!=9 and BD1_11!=9 and BD2_1!=9 and BP1!=9')
# index reset
df2 = df2.reset_index(drop=True)
# 결측치 제거한 DataFrame 출력
return df2
# 결측치 제거 기능 2
df_drop2 = drop_9s_df(df_temp)
print('\nDropped 9 or 99 values : Success')
# print(f"{df_drop2.tail()}\n{df_drop2.shape}")
print(df_drop2.shape)
'''
Dropped 9 or 99 values : Success
(16570, 24)
'''
# Target으로 쓸 Column을 추가하는 기능
def get_targets(df):
'''
get_targets
Target으로 쓸 Column을 추가하는 기능
---
입력 변수 정보
df : (DataFrame) DataFrame
---
출력 : target column을 추가한 DataFrame
'''
# 빈 리스트 생성
depression = []
MDD = []
# 우울증 관련 변수만 추출하기
df_targets = df[col_dpr] # ['DF2_pr', 'mh_PHQ_S']
# DataFrame의 row 한줄씩 반복 수행
for i in range(len(df_targets)):
# 우울증을 현재 가지고 있다고 응답 or PHQ-9점수가 5점 이상인 경우
if df_targets.loc[i, 'DF2_pr'] == 1\
or df_targets.loc[i, 'mh_PHQ_S'] > 4:
# Depression = 1
depression.append(1)
# PHQ-9점수가 10점 이상인 경우 : 주요우울장애(MDD)로 구분
if df_targets.loc[i, 'mh_PHQ_S'] > 9:
MDD.append(1)
else:
MDD.append(0)
# 우울증 의사진단 받지 않거나(8) 현재 우울증이 없으며(0), PHQ-9점수도 4점 이하
else:
# Depression & MDD = 0
depression.append(0)
MDD.append(0)
# Target Column 추가
df['Depression'] = depression
df['MDD'] = MDD
# target column을 추가한 DataFrame 출력
return df
# Feature 1차 가공(재분류)
def get_features(df):
'''
get_features
가공한 Feature의 Column을 추가하는 기능
---
입력 변수 정보
df : (DataFrame) DataFrame
---
출력 : 가공한 Feature column을 추가한 DataFrame
'''
# 빈 리스트 생성
household = []
marital = []
limit = []
modality = []
w_change = []
HE_HBP = []
HE_DB = []
HE_DYSL = []
drink_freq = []
drink_amount = []
# DataFrame의 row 한줄씩 반복 수행
for i in range(len(df)):
# 가구 세대 구성 (1~7) --> household (0~3)
# 1인 가구 (1)
if df.loc[i, 'genertn'] == 1:
household.append(0)
# 1세대 가구 (2,3)
elif df.loc[i, 'genertn'] in [2,3]:
household.append(1)
# 2세대 가구 (4,5,6)
elif df.loc[i, 'genertn'] in [4,5,6]:
household.append(2)
# 3세대 이상 가구 (7)
elif df.loc[i, 'genertn'] == 7:
household.append(3)
# 결혼 상태(1~4,88) --> marital(1~3)
# 기혼 및 유배우자 (1,2)
if df.loc[i, 'marri_2'] in [1,2]:
marital.append(1)
# 사별 혹은 이혼 (3,4)
elif df.loc[i, 'marri_2'] in [3,4]:
marital.append(2)
# 미혼(88)
elif df.loc[i, 'marri_2'] == 88:
marital.append(3)
# 질환 및 사고에 의한 활동 제한 여부
# 아니오(2) --> 0
if df.loc[i, 'LQ4_00'] == 2:
limit.append(0)
# 예(1) --> 1
elif df.loc[i, 'LQ4_00'] == 1:
limit.append(1)
# 2주간 이환(질환) 여부
# 아니오(2) --> 0
if df.loc[i, 'D_2_1'] == 2:
modality.append(0)
# 예(1) --> 1
elif df.loc[i, 'D_2_1'] == 1:
modality.append(1)
# 1년간 체중 조절 노력 없이 체중이 3kg이상 변화한 경우
# 체중변화없음(1) --> 0
if df.loc[i, 'BO1_1'] == 1:
w_change.append(0)
# 체중감소(2)or체중증가(3) & 체중 조절 노력함(1,2,3) --> 0
elif df.loc[i, 'BO1_1'] in [2,3]\
and df.loc[i, 'BO2_1'] in [1,2,3]:
w_change.append(0)
# 체중감소(2)or체중증가(3) & 체중 조절 노력 안함(4) --> 1
elif df.loc[i, 'BO1_1'] in [2,3]\
and df.loc[i, 'BO2_1'] == 4:
w_change.append(1)
# 고혈압 유병 여부
# 고혈압(3) --> 1
if df.loc[i, 'HE_HP'] == 3:
HE_HBP.append(1)
# 정상(1), 전단계(2) --> 0
elif df.loc[i, 'HE_HP'] in [1,2]:
HE_HBP.append(0)
# 당뇨병 유병 여부
# 당뇨병(3) --> 1
if df.loc[i, 'HE_DM'] == 3:
HE_DB.append(1)
# 정상(1), 공복혈당장애(2) --> 0
elif df.loc[i, 'HE_DM'] in [1,2]:
HE_DB.append(0)
# 이상지질혈증(고지혈증) 유병 여부
# 고콜레스테롤혈증(1) or 고중성지방혈증(1) --> 1
if df.loc[i, 'HE_HCHOL'] == 1\
or df.loc[i, 'HE_HTG'] == 1:
HE_DYSL.append(1)
# 모두 정상(0) --> 0
elif df.loc[i, 'HE_HCHOL'] == 0\
and df.loc[i, 'HE_HTG'] == 0:
HE_DYSL.append(0)
# 1년간 음주 빈도 (1~6, 8) --> (0~6)
# 평생마셔본적없음(8) --> 0
if df.loc[i, 'BD1_11'] == 8:
drink_freq.append(0)
# 나머지 변수(1~6) 그대로 사용
elif df.loc[i, 'BD1_11'] in [1,2,3,4,5,6]:
drink_freq.append(df.loc[i, 'BD1_11'])
# 1회 음주량 (1~5, 8) --> (0~5)
# 1년간 안마심(8) or 평생 안마심(8) --> 0
if df.loc[i, 'BD2_1'] == 8:
drink_amount.append(0)
# 나머지 변수(1~5) 그대로 사용
elif df.loc[i, 'BD2_1'] in [1,2,3,4,5]:
drink_amount.append(df.loc[i, 'BD2_1'])
# 가공한 Feature의 Column을 추가
df['household'] = household
df['marital'] = marital
df['limit'] = limit
df['modality'] = modality
df['w_change'] = w_change
df['HE_HBP'] = HE_HBP
df['HE_DB'] = HE_DB
df['HE_DYSL'] = HE_DYSL
df['dr_freq'] = drink_freq
df['dr_amount'] = drink_amount
# 가공한 Feature column을 추가한 DataFrame 출력
return df
# Target Column 및 가공한 Feature Column들을 추가하는 기능
df_add_targets = get_targets(df_drop2)
df_add_features = get_features(df_add_targets)
print('\nAdd Features & Add Targets : Success')
'''
Add Features & Add Targets : Success
'''
# 가공한 DataFrame을 RDB형태에 맞도록 재조합하는 기능
def devide_for_RDB(df):
'''
devide_for_RDB
가공한 DataFrame을 RDB형태에 맞도록 재조합하는 기능
---
입력 변수 정보
df : (DataFrame) 분리 할 DataFrame의 List
---
출력 : tuple of DataFrame
'''
# 변수 리스트 정의
col_year = ['id', 'year']
col_feature = ['id', 'age', 'HE_BMI', 'sex', 'edu',
'household', 'marital', 'EC1_1',
'D_1_1', 'limit', 'modality', 'w_change',
'HE_HBP', 'HE_DB', 'HE_DYSL',
'dr_freq', 'dr_amount', 'sm_presnt', 'BP1']
col_target = ['id', 'Depression', 'MDD']
# column 추출
df_year = df[col_year]
df_feature = df[col_feature]
df_target = df[col_target]
# 분리한 DataFrame들을 Tuple로 출력
return df_year, df_feature, df_target
# 가공한 DataFrame을 RDB형태에 맞도록 분리하는 기능
df_year, df_feature, df_target = devide_for_RDB(df_add_features)
print('\nData division completed')
print('Shapes : df_year, df_feature, df_target')
print(df_year.shape, df_feature.shape, df_target.shape)
'''
Data division completed
Shapes : df_year, df_feature, df_target
(16570, 2) (16570, 19) (16570, 3)
'''
# 최종 DataFrame들을 csv로 Export
df_year.to_csv('./1_DataBase/downloads/HN_year.csv', index=False)
df_feature.to_csv('./1_DataBase/downloads/HN_feature.csv', index=False)
df_target.to_csv('./1_DataBase/downloads/HN_target.csv', index=False)
print('\nData Saved at "Kor-DEEPression/1_DataBase/downloads/"\n')
'''
Data Saved at "Kor-DEEPression/1_DataBase/downloads/"
'''
ElephantSQL
을 이용하여 데이터베이스를 생성하고 구축하였음# 라이브러리 import
import csv
import json
# 라이브러리 및 함수 Import
import os
import sys
import psycopg2
from dotenv import load_dotenv
from custom_modules.postgresql_upload import *
보안 유지를 위해 호스트, DB이름, user이름, 비밀번호는 .env
파일에 담고 python-dotenv
라이브러리를 통해 불러온 뒤에 정보들을 전역변수(global var)로 저장하여 진행하였음
1-2_PostgreSQL-RDB.py
# .env파일에 저장된 정보들을 불러옴
load_dotenv(verbose=True)
# HOST, PORT, DATABASE, USERNAME, PASSWORD를 전역변수로 저장
HOST = os.getenv('postgre_host')
PORT = 5432
DATABASE = os.getenv('postgre_database')
USERNAME = os.getenv('postgre_user')
PASSWORD = os.getenv('postgre_password')
# 파일이 실행되면 자동으로 동작하는 main 함수
def main():
~~코드 내용~~
# 파일이 실행되면 자동으로 main 함수를 동작하도록 함
if __name__ == '__main__':
main()
# postgreSQL 연결
try:
conn = psycopg2.connect(
host=HOST,
port=PORT,
database=DATABASE,
user=USERNAME,
password=PASSWORD)
# 커서 지정
cur = conn.cursor()
print('\nconnection success to DB')
# 예외처리 : 연결 실패할 경우 시스템을 중단
except:
print('\nconnection error to DB')
sys.exit()
'''
connection success to DB
'''
테이블 리스트 초기화 및 생성을 효율적으로 진행하기 위해 table 리스트를 정의함 (순서가 중요하기 때문에 리스트로써 정의함)
1-2_PostgreSQL-RDB.py
# 테이블 리스트 정의 (id_year-->targets-->범주형변수들-->features)
table_list = ['id_year',
'targets',
'sex',
'education',
'household',
'marital',
'economy',
'subj_health',
'drk_freq',
'drk_amount',
'smoke',
'stress',
'features']
수정사항을 원활하게 반영하기 위해 DB CRUD 중에서 Update 대신 Delete 후 Create하도록 프로그래밍을 설계하였으므로 테이블 초기화 함수 부터 정의, 순서는 위에서 정의한 리스트의 역순으로 진행되어야 오류 없이 초기화가 가능함
custom_modules/postgresql_upload.py
# 테이블 초기화 기능(features-->범주형변수들-->targets-->id_year)
# 외래키를 가진 테이블(자식)부터 제거해야하므로 순서가 중요함
def table_initialization(cursor, table_list):
'''
table_initialization
테이블 초기화 기능
---
입력 변수 정보
cursor : (object) psycopg2.connect.cursor()
table_list : (list) 테이블 이름 리스트
---
출력 : None
'''
# 입력 받은 table list의 역순으로 반복을 진행함
for table_name in reversed(table_list):
# 테이블 이름과 동일한 테이블이 존재하면 삭제하는 명령어 실행
cursor.execute(f"""DROP TABLE IF EXISTS {table_name};""")
# 테이블 초기화 (features-->범주형변수들-->targets-->id_year)
table_initialization(cursor=cur, table_list=table_list)
print('\ntable initialization complete')
'''
table initialization complete
'''
# 테이블 생성 기능(id_year-->targets-->범주형변수들-->features)
# 외래키를 가지지 않는 테이블(부모)부터 생성해야하므로 순서가 중요함
def table_creation(cursor, table_list):
'''
table_creation
테이블 생성 기능
---
입력 변수 정보
cursor : (object) psycopg2.connect.cursor()
table_list : (list) 테이블 이름 리스트
---
출력 : None
'''
# id_year 테이블 생성 (부모 테이블)
cursor.execute(f"""CREATE TABLE IF NOT EXISTS {table_list[0]} (
id VARCHAR NOT NULL,
year INTEGER,
CONSTRAINT {table_list[0]}_pk PRIMARY KEY (id)
);""")
# targets 테이블 생성 (id_year의 자식 테이블)
cursor.execute(f"""CREATE TABLE IF NOT EXISTS {table_list[1]} (
id VARCHAR NOT NULL,
depression INTEGER,
mdd INTEGER,
CONSTRAINT {table_list[1]}_pk PRIMARY KEY (id),
CONSTRAINT {table_list[1]}_fk FOREIGN KEY (id) REFERENCES {table_list[0]} (id)
);""")
# 범주형 변수들(총 10개)의 테이블들을 생성 (부모 테이블)
for feature_name in table_list[2:-1]:
cursor.execute(f"""CREATE TABLE IF NOT EXISTS {feature_name} (
id_{feature_name} INTEGER,
{feature_name} VARCHAR,
CONSTRAINT {feature_name}_pk PRIMARY KEY (id_{feature_name})
);""")
# features 테이블 생성 (id_year와 범주형 테이블들의 자식 테이블)
cursor.execute(f"""CREATE TABLE IF NOT EXISTS {table_list[-1]} (
id VARCHAR NOT NULL,
age INTEGER,
bmi FLOAT,
{table_list[2]} INTEGER,
{table_list[3]} INTEGER,
{table_list[4]} INTEGER,
{table_list[5]} INTEGER,
{table_list[6]} INTEGER,
{table_list[7]} INTEGER,
limitation INTEGER,
modality INTEGER,
w_change INTEGER,
high_bp INTEGER,
diabetes INTEGER,
dyslipidemia INTEGER,
{table_list[-5]} INTEGER,
{table_list[-4]} INTEGER,
{table_list[-3]} INTEGER,
{table_list[-2]} INTEGER,
CONSTRAINT {table_list[-1]}_pk PRIMARY KEY (id),
CONSTRAINT {table_list[-1]}_fk FOREIGN KEY (id) REFERENCES {table_list[0]} (id),
CONSTRAINT {table_list[-1]}_fk_{table_list[2]} FOREIGN KEY ({table_list[2]}) REFERENCES {table_list[2]} (id_{table_list[2]}),
CONSTRAINT {table_list[-1]}_fk_{table_list[3]} FOREIGN KEY ({table_list[3]}) REFERENCES {table_list[3]} (id_{table_list[3]}),
CONSTRAINT {table_list[-1]}_fk_{table_list[4]} FOREIGN KEY ({table_list[4]}) REFERENCES {table_list[4]} (id_{table_list[4]}),
CONSTRAINT {table_list[-1]}_fk_{table_list[5]} FOREIGN KEY ({table_list[5]}) REFERENCES {table_list[5]} (id_{table_list[5]}),
CONSTRAINT {table_list[-1]}_fk_{table_list[6]} FOREIGN KEY ({table_list[6]}) REFERENCES {table_list[6]} (id_{table_list[6]}),
CONSTRAINT {table_list[-1]}_fk_{table_list[7]} FOREIGN KEY ({table_list[7]}) REFERENCES {table_list[7]} (id_{table_list[7]}),
CONSTRAINT {table_list[-1]}_fk_{table_list[-5]} FOREIGN KEY ({table_list[-5]}) REFERENCES {table_list[-5]} (id_{table_list[-5]}),
CONSTRAINT {table_list[-1]}_fk_{table_list[-4]} FOREIGN KEY ({table_list[-4]}) REFERENCES {table_list[-4]} (id_{table_list[-4]}),
CONSTRAINT {table_list[-1]}_fk_{table_list[-3]} FOREIGN KEY ({table_list[-3]}) REFERENCES {table_list[-3]} (id_{table_list[-3]}),
CONSTRAINT {table_list[-1]}_fk_{table_list[-2]} FOREIGN KEY ({table_list[-2]}) REFERENCES {table_list[-2]} (id_{table_list[-2]})
);""")
# 테이블 생성 (id_year-->targets-->범주형변수들-->features)
table_creation(cursor=cur, table_list=table_list)
print('\ntable created complete')
'''
table created complete
'''
# csv data를 RDB에 입력하는 기능
# csv에서 한줄씩 넣는 executemany 방식은 시간이 상당히 오래 걸림
# cursor의 copy_from 메소드로 csv전체를 복사하여 RDB에 붙여 넣으면 훨씬 간단하고 빠르게 수행할 수 있음!
def insertion_csv(cursor, table_name, path):
'''
insertion_csv
csv data를 RDB에 입력하는 기능
---
입력 변수 정보
cursor : (object) psycopg2.connect.cursor()
table_name : (str) 테이블 이름
path : csv file 디렉토리
---
출력 : None
'''
# 연산 실시후 파일이 닫히도록 with문을 활용한다
with open(path, 'r') as cf:
# csv 모듈의 reader를 통해 csv 파일을 읽기
csv_reader = csv.reader(cf)
# 첫 행에는 변수 이름이 저장되어 있으므로 next로 넘어가기
next(csv_reader)
# copy_from으로 csv데이터를 통째로 입력하기
cursor.copy_from(cf, table_name, sep=',')
# json data를 RDB에 입력하는 기능
# 데이터 수가 많지 않기 때문에 executemany 방식으로 데이터를 입력
def insertion_json(cursor, table_list, path):
'''
insertion_json
json data를 RDB에 입력하는 기능
---
입력 변수 정보
cursor : (object) psycopg2.connect.cursor()
table_list : (list) 테이블 이름 리스트
path : json file 디렉토리
---
출력 : None
'''
# 연산 실시후 파일이 닫히도록 with문을 활용한다
with open(path, 'r', encoding='utf-8') as jf:
json_reader = json.load(jf)
# 전달받은 table list의 요소를 순서대로 반복하여 json 데이터를 입력
for table_name in table_list:
cursor.executemany(f"""INSERT INTO {table_name} (id_{table_name}, {table_name}) VALUES (%s, %s);""",
[list(dict.values()) for dict in json_reader[table_name]])
{
"sex":
[
{
"sex" : 1,
"name" : "Male"
},
{
"sex" : 2,
"name" : "Female"
}
]
}
# 데이터 삽입 (id_year-->targets-->범주형변수들-->features)
insertion_csv(cur, table_list[0], path='./1_DataBase/downloads/HN_year.csv')
insertion_csv(cur, table_list[1], path='./1_DataBase/downloads/HN_target.csv')
insertion_json(cur, table_list[2:-1], path='./1_DataBase/json_variable.json')
insertion_csv(cur, table_list[-1], path='./1_DataBase/downloads/HN_feature.csv')
print('\ndata insert complete')
'''
data insert complete
'''
# 변경사항을 저장(commit)
conn.commit()
# postgreSQL 연결 종료
conn.close()
print('\nSuccessfully Disconnected to DB\n')
'''
Successfully Disconnected to DB
'''
DBeaver
프로그램을 통해 확인함# 라이브러리 import
import pandas as pd
# 라이브러리 및 함수 Import
import os
import sys
import psycopg2
from dotenv import load_dotenv
from custom_modules.postgresql_down import *
# SQL Qurey문을 통해 csv 데이터를 생성하는 기능
# mode를 지정하여 목적에 맞게 쿼리를 실시함
def get_csv_file(cursor, mode, target, savepath):
'''
get_csv_file
SQL Qurey문을 통해 csv 데이터를 생성하는 기능
---
입력 변수 정보
cursor : (object) psycopg2.connect.cursor()
mode : (str) 'EDA' or 'Model'
target : (str) 'depression', 'MDD'
savepath : (str) 저장 파일 경로
---
출력 : None
'''
# mode가 'EDA' 인 경우(EDA용 데이터 쿼리)
if mode == 'EDA':
# target이 'depression' 인 경우
if target == 'depression':
sql_query = """
SELECT f.id , y."year" , f.age , f.bmi , f1.sex , f2.education , f3.household , f4.marital , f5.economy ,
f6.subj_health , f.limitation , f.modality , f.w_change , f.high_bp , f.diabetes , f.dyslipidemia ,
f7.drk_freq , f8.drk_amount , f9.smoke , f10.stress , t.depression
FROM features AS f
JOIN targets AS t ON f.id = t.id
JOIN id_year AS y ON f.id = y.id
JOIN sex AS f1 ON f.sex = f1.id_sex
JOIN education AS f2 ON f.education = f2.id_education
JOIN household AS f3 ON f.household = f3.id_household
JOIN marital AS f4 ON f.marital = f4.id_marital
JOIN economy AS f5 ON f.economy = f5.id_economy
JOIN subj_health AS f6 ON f.subj_health = f6.id_subj_health
JOIN drk_freq AS f7 ON f.drk_freq = f7.id_drk_freq
JOIN drk_amount AS f8 ON f.drk_amount = f8.id_drk_amount
JOIN smoke AS f9 ON f.smoke = f9.id_smoke
JOIN stress AS f10 ON f.stress = f10.id_stress
"""
# target이 'MDD' 인 경우
elif target == 'MDD':
sql_query = """
SELECT f.id , y."year" , f.age , f.bmi , f1.sex , f2.education , f3.household , f4.marital , f5.economy ,
f6.subj_health , f.limitation , f.modality , f.w_change , f.high_bp , f.diabetes , f.dyslipidemia ,
f7.drk_freq , f8.drk_amount , f9.smoke , f10.stress , t.mdd
FROM features AS f
JOIN targets AS t ON f.id = t.id
JOIN id_year AS y ON f.id = y.id
JOIN sex AS f1 ON f.sex = f1.id_sex
JOIN education AS f2 ON f.education = f2.id_education
JOIN household AS f3 ON f.household = f3.id_household
JOIN marital AS f4 ON f.marital = f4.id_marital
JOIN economy AS f5 ON f.economy = f5.id_economy
JOIN subj_health AS f6 ON f.subj_health = f6.id_subj_health
JOIN drk_freq AS f7 ON f.drk_freq = f7.id_drk_freq
JOIN drk_amount AS f8 ON f.drk_amount = f8.id_drk_amount
JOIN smoke AS f9 ON f.smoke = f9.id_smoke
JOIN stress AS f10 ON f.stress = f10.id_stress
WHERE t.depression = 1
"""
# 예외처리 : Exception 문을 출력하도록 설정하고 함수를 종료 시킴
else:
raise Exception("\nERROR : 'target' must be 'depression' or 'MDD'")
# mode가 'Model'인 경우(Modeling용 데이터 쿼리)
elif mode == 'Model':
# target이 'depression' 인 경우
if target == 'depression':
sql_query = """
SELECT f.* , t.depression
FROM features AS f
JOIN targets AS t ON f.id = t.id
"""
# target이 'MDD' 인 경우
elif target == 'MDD':
sql_query = """
SELECT f.* , t.mdd
FROM features AS f
JOIN targets AS t ON f.id = t.id
WHERE t.depression = 1
"""
# 예외처리 : Exception 문을 출력하도록 설정하고 함수를 종료 시킴
else:
raise Exception("\nERROR : 'target' must be 'depression' or 'MDD'")
# 예외처리 : Exception 문을 출력하도록 설정하고 함수를 종료 시킴
else:
raise Exception("\nERROR : 'mode' must be 'EDA' or 'Model'")
# csv 생성 SQL 쿼리문
sql_csv = f"""COPY ({sql_query}) TO STDOUT WITH CSV DELIMITER ',';"""
with open(savepath, 'w', encoding='utf-8') as cf:
cursor.copy_expert(sql_csv, cf)
# 동작 여부를 확인하기 위한 print문
print(f"{mode}_{target}_temp.csv file created Successfully")
# Query & Get csv(temp) : SQL Qurey문을 통해 csv 데이터를 생성하는 기능
# EDA모드에서는 범주형 변수의 테이블을 모두 JOIN하여 모두 문자열로 불러옴
get_csv_file(cur, mode='EDA', target='depression', savepath="./2_Modeling/downloads/temp_data/EDA_depr_temp.csv")
get_csv_file(cur, mode='EDA', target='MDD', savepath="./2_Modeling/downloads/temp_data/EDA_mdd_temp.csv")
# Model모드에서는 모두 수치형으로 데이터를 불러옴
get_csv_file(cur, mode='Model', target='depression', savepath="./2_Modeling/downloads/temp_data/Model_depr_temp.csv")
get_csv_file(cur, mode='Model', target='MDD', savepath="./2_Modeling/downloads/temp_data/Model_mdd_temp.csv")
'''
EDA_depression_temp.csv file created Successfully
EDA_MDD_temp.csv file created Successfully
Model_depression_temp.csv file created Successfully
Model_MDD_temp.csv file created Successfully
'''
SQL 쿼리를 통해 얻은 데이터에는 column 이름에 대한 정보가 포함되어 있지 않기 때문에, 이를 pandas를 통해 추가함
custom_modules/postgresql_down.py
# DataFrame을 통해 column 이름을 추가하는 함수
# mode를 지정하여 목적에 맞게 기능을 수행함
def load_df_with_columns(mode, target, filepath):
'''
load_df_with_columns
column 이름을 추가하는 함수
---
입력 변수 정보
mode : (str) 'EDA' or 'Model'
target : (str) 'depression', 'MDD'
filepath : (str) 파일 경로
---
출력 : DataFrame
'''
# 공통적으로 담고 있는 Feature의 리스트를 정의함
col_feat = ['age', 'BMI', 'sex', 'education', 'household', 'marital', 'economy',
'subj_health', 'limitation', 'modality', 'w_change', 'high_bp',
'diabetes', 'dyslipidemia', 'drk_freq', 'drk_amount', 'smoke', 'stress']
# 지정한 mode와 target에 따라 column 이름 리스트를 결정함
if mode == 'EDA':
if target == 'depression':
col_list = ['id', 'year'] + col_feat + ['depression']
elif target == 'MDD':
col_list = ['id', 'year'] + col_feat + ['MDD']
else: # 예외처리 : Exception 문을 출력하도록 설정하고 함수를 종료 시킴
raise Exception("\nERROR : 'target' must be 'depression' or 'MDD'")
elif mode == 'Model':
if target == 'depression':
col_list = ['id'] + col_feat + ['depression']
elif target == 'MDD':
col_list = ['id'] + col_feat + ['MDD']
else: # 예외처리 : Exception 문을 출력하도록 설정하고 함수를 종료 시킴
raise Exception("\nERROR : 'target' must be 'depression' or 'MDD'")
else: # 예외처리 : Exception 문을 출력하도록 설정하고 함수를 종료 시킴
raise Exception("\nERROR : 'mode' must be 'EDA' or 'Model'")
# 위에서 결정한 col_list에 따라서 column의 이름을 붙여주면서 DataFrame을 불러옴
df = pd.read_csv(filepath, names=col_list)
# 동작여부 테스트용 코드
print(f"{mode}_{target} : {df.shape}")
# 출력 : DataFrame
return df
# Data loading : column 이름을 추가하기 위해 저장한 임시 데이터를 다시 불러옴
df_eda_depr = load_df_with_columns(mode='EDA', target='depression', filepath="./2_Modeling/downloads/temp_data/EDA_depr_temp.csv")
df_eda_mdd = load_df_with_columns(mode='EDA', target='MDD', filepath="./2_Modeling/downloads/temp_data/EDA_mdd_temp.csv")
df_depr = load_df_with_columns(mode='Model', target='depression', filepath="./2_Modeling/downloads/temp_data/Model_depr_temp.csv")
df_mdd = load_df_with_columns(mode='Model', target='MDD', filepath="./2_Modeling/downloads/temp_data/Model_mdd_temp.csv")
print('Data loading : Success\n')
'''
EDA_depression : (16570, 21)
EDA_MDD : (3359, 21)
Model_depression : (16570, 20)
Model_MDD : (3359, 20)
Data loading : Success
'''
# column 이름을 추가한 DataFrame을 csv로 저장하는 기능
# mode를 지정하여 목적에 맞게 기능을 수행함(EDA 모드에서는 이진변수를 문자열로 수정)
def df_to_csv(df, mode, target, savepath):
'''
df_to_csv
DataFrame을 csv로 저장하는 기능
---
입력 변수 정보
df : (DataFrame) 저장할 DataFrame
mode : (str) 'EDA' or 'Model'
target : (str) 'depression', 'MDD'
savepath : (str) 저장 파일 경로
---
출력 : None
'''
# mode가 'EDA'인 경우 : 이진변수를 문자열(Yes,No)로 수정
if mode == 'EDA':
df1 = df.replace({0:'No', 1:'Yes'})
# mode가 'Model' 인 경우 : 'id' column을 제외
elif mode == 'Model':
df1 = df.iloc[:,1:]
# 예외처리 : Exception 문을 출력하도록 설정하고 함수를 종료 시킴
else:
raise Exception("\nERROR : 'mode' must be 'EDA' or 'Model'")
# 지정한 경로에 DataFrame을 csv로 Export
df1.to_csv(savepath, index=False)
# 동작 여부를 확인하기 위한 테스트용 코드
print(f"csv file for {mode}_{target} exported Successfully")
# Data to csv(final) : column 이름을 추가한 최종 데이터들을 Export함
# EDA 모드에서는 이진변수를 문자열(Yes,No)로 수정
df_to_csv(df_eda_depr, mode='EDA', target='depression', savepath='./2_Modeling/downloads/EDA_depr.csv')
df_to_csv(df_eda_mdd, mode='EDA', target='MDD', savepath='./2_Modeling/downloads/EDA_mdd.csv')
# Model 모드에서는 'id' column을 제외
df_to_csv(df_depr, mode='Model', target='depression', savepath='./2_Modeling/downloads/Model_depr.csv')
df_to_csv(df_mdd, mode='Model', target='MDD', savepath='./2_Modeling/downloads/Model_mdd.csv')
print('Data to csv file : Success\n')
'''
csv file for EDA_depression exported Successfully
csv file for EDA_MDD exported Successfully
csv file for Model_depression exported Successfully
csv file for Model_MDD exported Successfully
Data to csv file : Success
'''
# SQL Qurey문 정의 (변수는 EDA에서 정한 변수로 추출)
sql_query = """
SELECT f.id, y."year", f.age,
f.sex, f1.sex,
f.household, f2.household,
f.marital, f3.marital,
f.subj_health, f4.subj_health,
f.stress, f5.stress,
t.depression, t.mdd
FROM features AS f
JOIN targets AS t ON f.id = t.id
JOIN id_year AS y ON f.id = y.id
JOIN sex AS f1 ON f.sex = f1.id_sex
JOIN household AS f2 ON f.household = f2.id_household
JOIN marital AS f3 ON f.marital = f3.id_marital
JOIN subj_health AS f4 ON f.subj_health = f4.id_subj_health
JOIN stress AS f5 ON f.stress = f5.id_stress
"""
# Column 이름이 없는 상태로 저장되므로 다시 불러와서 Column 이름을 추가
column_list = ['id', 'year', 'age', 'sex', '성별', 'household', '세대유형',
'marital', '혼인상태', 'subj_health', '주관적건강인지도',
'stress', '스트레스인지도', 'Depression', 'MDD']
df_temp = pd.read_csv(save_path_temp, names=column_list)
# Age column 범주화
Ages = []
for index, value in enumerate(df_temp.age):
if value < 30:
Ages.append('20s')
elif value < 40:
Ages.append('30s')
elif value < 50:
Ages.append('40s')
elif value < 60:
Ages.append('50s')
elif value < 70:
Ages.append('60s')
elif value < 80:
Ages.append('70s')
else: Ages.append('over 80s')
df_fix = df_temp.copy()
df_fix['나이대'] = Ages
# Depression 과 MDD를 종합한 Column을 새로 생성
Depr_MDD_Code = []
Depr_MDD_label = []
for index in range(df_fix.shape[0]):
if df_fix.loc[index, 'Depression'] == 0:
Depr_MDD_Code.append(0)
Depr_MDD_label.append('정상')
elif df_fix.loc[index, 'MDD'] == 0:
Depr_MDD_Code.append(1)
Depr_MDD_label.append('경도우울증')
elif df_fix.loc[index, 'MDD'] == 1:
Depr_MDD_Code.append(2)
Depr_MDD_label.append('주요우울장애')
df_add_target = df_fix.copy()
df_add_target['Depr_MDD'] = Depr_MDD_Code
df_add_target['우울증분류'] = Depr_MDD_label
# 열 순서 바꾸기
sort_columns = ['id', 'year', 'age', '나이대', 'sex', '성별', 'household', '세대유형',
'marital', '혼인상태', 'subj_health', '주관적건강인지도', 'stress', '스트레스인지도',
'Depression', 'MDD', 'Depr_MDD', '우울증분류']
df_sorted = df_add_target[sort_columns]
# CSV file로 Export
df_sorted.to_csv(save_path_final, index=False)
print("Column Addition & Saving csv : Success\n")
'''
Column Addition & Saving csv : Success
'''
다음 과정에서는 시각화 분석 및 대시보드 제작에 관련된 내용을 다루도록 하겠음.