2.인공지능 치매예측 부분엔 전체적인 코드를 작성했습니다.
해당 페이지부턴 자세한 접근방법과 코드설명을 첨부하겠습니다.
#1. 데이터프레임 만들기
from scipy.signal import butter,filtfilt
import csv, os ; from glob import glob
import matplotlib.pyplot as plt
import numpy as np ; import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from tqdm.notebook import tqdm ; import seaborn as sns
from skimage.restoration import denoise_wavelet
from sklearn.model_selection import train_test_split
from sklearn.metrics import f1_score
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler, \
QuantileTransformer, PowerTransformer, Normalizer
import warnings
warnings.filterwarnings('ignore')
plt.rcParams["font.family"] = 'NanumGothic'
plt.rcParams['axes.unicode_minus'] = False
train_test_set = sorted(glob('GNB/100_new/*.csv'))
validation_set = sorted(glob('GNB/35_new/*.csv'))
df_98_ = pd.DataFrame()
category = 0
for i, file in enumerate(train_test_set) :
user_df = pd.read_csv(file)
user_df = user_df[user_df.columns[:22]][:]
lst_730 = user_df.columns[1:8].tolist()
lst_850 = user_df.columns[8:15].tolist()
lst_back = user_df.columns[15:22].tolist()
for idx in range(7) :
# user_df[lst_730[idx]] = user_df[lst_730[idx]] - np.mean(user_df[lst_730[idx]]) # DC OFFSET 제거
# user_df[lst_850[idx]] = user_df[lst_850[idx]] - np.mean(user_df[lst_850[idx]]) # DC OFFSET 제거
# 98명 데이터에 730,850 각각 +1300, 35명 데이터 각각 200씩 더해주면 정확도 올라감
user_df[lst_730[idx]] = user_df[lst_730[idx]] # + user_df[lst_back[idx]] #+ 300
user_df[lst_850[idx]] = user_df[lst_850[idx]] # + user_df[lst_back[idx]] #+ 300
user_df = user_df[user_df.columns[:15]][:]
uid = int(file.split('/')[-1].split('\\')[1].split(".")[0])
user_df.insert(0,'uid', uid)
if i < 55:
category = 'CN'
elif 55<=i<85:
category = 'MCI'
elif 85<=i<99:
category = "AD"
user_df['Category'] = category
df_98_ = pd.concat([df_98_,user_df])
uid_lst = list(set(df_98_.uid.unique().tolist()))
df_98 = pd.DataFrame()
for uid in uid_lst :
df = df_98_[df_98_.uid==uid]
df_98 = pd.concat([df_98,df])
df_98 = df_98.reset_index(drop = True)
del df_98_
print("\n데이터 바로 확인 특정 유저 특정 채널 불러오기")
uids = 15
plt.title("98 Raw Data - User name : {} - 730nm,850nm - 4Channel".format(uids),fontsize=20)
df_98[df_98.uid==uids].A_730_3.plot(figsize=(12,5))
df_98[df_98.uid==uids].A_850_3.plot(figsize=(12,5))
주어진 데이터는 여러개의 csv 파일이 존재합니다. 해당 파일을 한개로 묶어 데이터프레임을 만들어주는 과정입니다. 데이터 프레임을 만들고 plot 해주면 해당 이미지를 얻을 수 있습니다.
#2. 이상치 확인하기
df_98[df_98.columns[2:]].boxplot(figsize=(15,7))
컬럼별 이상치값을 파악했습니다. 생각보다 이상치가 많이 분포되어있다는 점을 확인했습니다.
박스 위 아래 검은점은 사분위수의 통계적 관점에서의 이상치입니다.
sns.boxplot(data=df_98, y='A_730_0', x='Category')
sns.boxplot(data=df_98, y='A_730_1', x='Category')
sns.boxplot(data=df_98, y='A_730_2', x='Category')
sns.boxplot(data=df_98, y='A_730_3', x='Category')
sns.boxplot(data=df_98, y='A_730_4', x='Category')
sns.boxplot(data=df_98, y='A_730_5', x='Category')
sns.boxplot(data=df_98, y='A_730_6', x='Category')
카테고리별로 이상치값을 뽑아봤습니다.
이상하죠? 건강할수록(CN : 정상, MCI : 경도인지장애, AD : 알츠하이머) 이상치가 많다...?
def outlier_iqr(data, column):
# lower, upper 글로벌 변수 선언하기
global lower, upper
# 4분위수 기준 지정하기
q25, q75 = np.quantile(data[column], 0.25), np.quantile(data[column], 0.75)
# IQR 계산하기
iqr = q75 - q25
# outlier cutoff 계산하기
cut_off = iqr * 1.5
# lower와 upper bound 값 구하기
lower, upper = q25 - cut_off, q75 + cut_off
print('IQR은',iqr, '이다.')
print('lower bound 값은', lower, '이다.')
print('upper bound 값은', upper, '이다.')
# 1사 분위와 4사 분위에 속해있는 데이터 각각 저장하기
data1 = data[data[column] > upper]
data2 = data[data[column] < lower]
# 이상치 총 개수 구하기
print('총 이상치 건수는', data1.shape[0] + data2.shape[0], '이다.')
return data1,data2
사분위수를 통한 이상치를 추출하고 시각화하기 위해서 사용한 코드입니다. 이 코드는 [python] 탭에도 저장되어있는 코드로 자주 사용하는 코드입니다.
columns = 'A_850_2' # 채널(컬럼)
outlier_1, outlier_2 = outlier_iqr(df_98,columns) # 98명의 유저들의 특정 컬럼(채널)의 전체 데이터 분포를 활용한 이상치 탐지
plt.figure(figsize=(10,5))
sns.distplot(df_98[columns], kde=False)
# 이상치 영역 박스 그리기
plt.axvspan(xmin=lower, xmax=df_98[columns].min(), alpha=0.2, color='red')
plt.axvspan(xmin=upper, xmax=df_98[columns].max(), alpha=0.2, color='red')
columns = 'A_850_1'
outlier_1, outlier_2 = outlier_iqr(df_98,columns)
len(outlier_1), len(outlier_2)
print("\n 이상치가 존재하는 유저 목록 : {}".format(outlier_1.uid.unique().tolist()))
print("\n 80번 유저의 이상치 구간 (실선 제외) , 이상치 건수 : {}".format(len(outlier_1[outlier_1.uid==80])),
"(주황색)")
df_98[df_98.uid==80].A_850_1.plot()
outlier_1[outlier_1.uid==80].A_850_1.plot()
이상치가 존재하는 유저의 목록을 뽑아봐도
if i < 55:
category = 'CN'
elif 55<=i<85:
category = 'MCI'
elif 85<=i<99:
category = "AD"
대부분 CN과 MCI 에 분포되어있음이 확인됩니다.
<결론>
1. IQR 로 구한 통계학적 이상치값이 없어져야할 값이 아닌 단순히 신호값이 높은것들의 값이였고, CN, MCI, AD 를 구별짓는 한개의 척도로 받아들어야 하구나! 를 예상 할 수 있습니다.
2. 그렇다면 이 아날로그 신호를 디지털로 해석되면 어떨까?
- 높은신호값은 디지털관점으로 모두 1로 보고 낮은 신호값을 0으로 본다면? CN(정상)에 가까운 사람일수록 1인 신호가 많고 AD(알츠하이머)에 가까운 사람일수록 0인 신호가 많겠구나! 를 예상할 수 있습니다.