by 나다경
데이터를 기반으로 패턴을 학습하고 결과를 예측하는 알고리즘 기법을 통칭함
머신러닝 알고리즘은 데이터를 기반으로 통계적인 신뢰도를 강화하고 예측 오류를 최소화하기 위한 다양한 수학적 기법을 적용해 데이터 내의 패턴을 스스로 인지하고 신뢰도 있는 예측 결과를 도출해 냄
데이터 분석 영역은 재빠르게 머신러닝 기반의 예측 분석으로 재편되고 있음
ex. 데이터마이닝, 영상 인식, 음성 인식, 자연어 처리 등
학습 순서
이 코스는 매우 기본적인 Python, Pandas를 다루는 과정부터 Probability, Distributions(Frequentist Statistics), Regression, Logistic Regression와 같은 통계적인 개념, Machine Learning, Ensembles, Bayes, Text and Clustering, Deep Networks까지 전반적인 내용을 다루고 있음
통계학 베이스가 있기 때문에 Week5의 Regression부터 수강함
Week5 Regression, Logistic Regression: in sklearn and statsmodels ~ Week11 Text and Clustering까지
학습 소요 시간 하루에 강의 1개씩, 약 1달
학습 방법
영상 + 자막 -> git에 있는 학습 자료바탕 + 필기
학습 소감
수학적 개념을 깊게 다루지 않고 기본적인 머신러닝 개념 위주로 다뤄서 내용은 이해하기에 어렵지 않았음. 처음 입문하기에는 나쁘지 않은 강의라고 볼 수 있음.
장점
질 높은 하버드 강의를 무료로 들을 수 있음
머신러닝을 체계적으로 공부할 수 있음. 몰아서 들으니깐 계절학기 느낌으로다가 수강 가능
단점
개인적으로는 Andrew Ng의 Machine Learning 코스를 더 추천함. 유명한 강의 + 연습문제 + 수료증 지급 3가지 이유로 추천함!
학습 소요 시간
하루에 강의 약 3개씩 or 소단원 1개씩, 약 1달 반
학습 방법
인프런 파이썬 머신러닝 완벽 가이드 강의 + 책
개념은 책을 통해 학습, 소스코드 위주의 학습
학습 소감
CS109에서 배운 기본적인 개념 덕분에 이론적인 부분은 복습하는 개념으로 공부함
다만, CS109에서는 다양한 분류나 회귀 방법을 사용하지 않았고, 코드 설명도 부족했는데 이번 강의와 책은 기본적인 부분을 쉽고 자세하게 알려줌
이제 머신러닝에 대한 공부는 어느 정도 해봤으니 실제 대회에 참가해서 직접 데이터 전처리, 모델 학습, 하이퍼파라미터 튜닝 등을 해보자!
데이콘 베이직 Basic 심장 질환 예측 경진대회로 선정함
기본적인 EDA나 모델 성능을 향상 시킬 수 있는 코드들이 잘 공유되어 있고, 비교적 데이터셋이 학습하기에 적절하다고 생각했기 때문
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')
%matplotlib inline
df = pd.read_csv('train.csv')
df.shape #(151,15)
df.describe()
plt.style.use('ggplot')
# 히스토그램
plt.figure(figsize=(25,20))
plt.suptitle('Data Histogram', fontsize=40)
# id는 제외하고 시각화
cols = df.columns[1:]
for i in range(len(cols)):
plt.subplot(5, 3, i+1)
plt.title(cols[i], fontsize=20)
if len(df[cols[i]].unique()) > 20:
plt.hist(df[cols[i]], bins=20, color='b', alpha=0.7)
else :
temp = df[cols[i]].value_counts()
plt.bar(temp.keys(), temp.values, width=0.5, alpha=0.7)
plt.xticks(temp.keys())
plt.tight_layout(rect=[0,0.03,1,0.95])
plt.show()
![data histogram](/ML-2021-final/data histogram.png)
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('ggplot')
# Boxplot 을 사용해서 데이터의 분포를 살펴보자.
plt.figure(figsize=(20,15))
plt.suptitle('Boxplots', fontsize=40)
# id 제외하고 시각화
cols = df.columns[1:-1]
for i in range(len(cols)):
plt.subplot(6,3,i+1)
plt.title(cols[i])
plt.boxplot(df[cols[i]])
plt.show()
plt.figure(figsize=(20,10))
heat_table = df.drop(['id'], axis=1).corr()
heatmap_ax = sns.heatmap(heat_table, annot=True, cmap='coolwarm')
heatmap_ax.set_xticklabels(heatmap_ax.get_xticklabels(), fontsize=15, rotation=45)
heatmap_ax.set_yticklabels(heatmap_ax.get_yticklabels(), fontsize=15)
plt.title('correlation between features', fontsize=40)
plt.show()
age
sns.kdeplot(df.loc[df['target'] == 1, 'age'], color='red')
sns.kdeplot(df.loc[df['target'] == 0, 'age'], color = 'green')
sex
plt.plot(figsize=(18,8))
sns.countplot('sex', hue='target', data=df)
plt.show()
cp
plt.plot(figsize=(18,8))
sns.countplot('cp', hue='target', data=df)
plt.show()
trestbps
sns.kdeplot(df.loc[df['target'] == 1, 'trestbps'], color='red')
sns.kdeplot(df.loc[df['target'] == 0, 'trestbps'], color = 'green')
심장 질환 유무에 상관없이 비슷함
chol
sns.kdeplot(df.loc[df['target'] == 1, 'chol'], color='red')
sns.kdeplot(df.loc[df['target'] == 0, 'chol'], color = 'green')
심장 질환 유무에 상관없이 비슷함
fbs
plt.plot(figsize=(18,8))
sns.countplot('fbs', hue='target', data=df)
plt.show()
restecg
plt.plot(figsize=(18,8))
sns.countplot('restecg', hue='target', data=df)
plt.show()
thalach
sns.kdeplot(df.loc[df['target'] == 1, 'thalach'], color='red')
sns.kdeplot(df.loc[df['target'] == 0, 'thalach'], color = 'green')
exang
plt.plot(figsize=(18,8))
sns.countplot('exang', hue='target', data=df)
plt.show()
oldpeak
sns.kdeplot(df.loc[df['target'] == 1, 'oldpeak'], color='red')
sns.kdeplot(df.loc[df['target'] == 0, 'oldpeak'], color = 'green')
slope
plt.plot(figsize=(18,8))
sns.countplot('slope', hue='target', data=df)
plt.show()
ca
plt.plot(figsize=(18,8))
sns.countplot('ca', hue='target', data=df)
plt.show()
thal
plt.plot(figsize=(18,8))
sns.countplot('thal', hue='target', data=df)
plt.show()
df.isnull().sum() # 모두 0임
thal
df['thal_nan'] = df['thal'].replace(0,np.nan)
df['ca_nan'] = df['ca'].replace(4,np.nan)
df['thal_nan'].isnull().sum() # 1
df['ca_nan'].isnull().sum() # 0
# 결측치 비율 -> 매우 작으므로 drop
df['thal_nan'].isnull().mean() # 0.006622516556291391
index1 = df[df['thal'] == 0].index
print(index1) # Int64Index([129], dtype='int64')
df.drop(index1, inplace=True)
trestbps
sns.distplot(df['trestbps'])
sns.distplot(np.log1p(df['trestbps']))
chol
sns.distplot(df['chol'])
sns.distplot(np.log1p(df['chol']))
df['trestbps'] = np.log1p(df['trestbps'])
df['chol'] = np.log1p(df['chol'])
oldpeak
plt.figure(figsize=(15,2))
sns.boxplot(df['oldpeak'])
trestbps
plt.figure(figsize=(15,2))
sns.boxplot(df['trestbps'])
chol
plt.figure(figsize=(15,2))
sns.boxplot(df['chol'])
thalach
plt.figure(figsize=(15,2))
sns.boxplot(df['thalach'])
features = ['oldpeak','trestbps','chol','thalach']
for feature in features:
print(feature)
IQR3 = df[feature].quantile(0.75)
IQR1 = df[feature].quantile(0.25)
IQR = IQR3 - IQR1
OUT_down= IQR1 - (1.5*IQR)
OUT_up = IQR3 + (1.5*IQR)
index1 = df[df[feature] > OUT_up].index
print(index1)
index2 = df[df[feature] < OUT_down].index
print(index2)
df.drop(index1, inplace=True)
df.drop(index2, inplace=True)
from sklearn.preprocessing import StandardScaler
transform_data = df.drop(columns=['id', 'age', 'sex', 'cp', 'trestbps', 'chol', 'fbs', 'restecg', 'exang', 'oldpeak', 'slope', 'ca','thal', 'target'])
scaler = StandardScaler()
std_transfrom_data = scaler.fit_transform(transform_data)
df[transform_data.columns] = std_transfrom_data
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import f1_score
from sklearn.metrics import plot_confusion_matrix
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score, confusion_matrix, roc_auc_score
X = df.iloc[:, 1:-1] # id,target 제거
y = df.iloc[:,-1] # target만 선택
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42)
lr_clf = LogisticRegression(random_state=156)
lr_clf.fit(X_train,y_train)
pred = lr_clf.predict(X_test)
print('Accuacy Score: ', accuracy_score(y_test, pred)) # 0.9285714285714286
print('ROC AUC Score: ', roc_auc_score(y_test, pred)) # 0.9166666666666667
print(f'f1_score : {f1_score(y_test, pred)}') # 0.9411764705882353
from sklearn.model_selection import GridSearchCV
params = {'penalty' : ['l2', 'l1'],
'C' : [0.01, 0.1, 1, 5, 10]}
lr_grid_clf = GridSearchCV(lr_clf, param_grid=params, scoring='accuracy', cv=5)
lr_grid_clf.fit(X_train, y_train)
print('최적 하이퍼 파라미터:{0}, 최적 평균 정확도: 1:.3f}'.format(lr_grid_clf.best_params_, lr_grid_clf.best_score_))
# 최적 하이퍼 파라미터:{'C': 5, 'penalty': 'l2'}, 최적 평균 정확도:0.821
pred = lr_grid_clf.predict(X_test)
print('Accuacy Score: ', lr_grid_clf.best_score_) # 0.8209486166007907
print('ROC AUC Score: ', roc_auc_score(y_test, pred)) # 0.9166666666666667
print(f'f1_score : {f1_score(y_test, pred)}') # 0.9411764705882353
from sklearn.tree import DecisionTreeClassifier
model = DecisionTreeClassifier(max_depth=5, random_state=42)
dt_clf = DecisionTreeClassifier(random_state=42)
param_grid = {'max_depth' : range(3,12),
'max_features' : [0.3, 0.5, 0.7, 0.9, 1]}
grid_dt_clf = GridSearchCV(dt_clf, param_grid=param_grid, n_jobs=-1, cv=5, verbose=2)
grid_dt_clf.fit(X_train, y_train)
print(grid_dt_clf.best_params_) # {'max_depth': 6, 'max_features': 0.7}
print(grid_dt_clf.best_score_) # 0.8109890109890111
pred = grid_dt_clf.predict(X_test)
print('Accuacy Score: ', grid_dt_clf.best_score_) # 0.8109890109890111
print('ROC AUC Score: ', roc_auc_score(y_test, pred)) # 0.8125
print(f'f1_score : {f1_score(y_test, pred)}') # 0.8484848484848485
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from xgboost import XGBClassifier
from lightgbm import LGBMClassifier
estimators = [DecisionTreeClassifier(random_state=42),
RandomForestClassifier(random_state=42),
GradientBoostingClassifier(random_state=42),
XGBClassifier(random_state=42),
LGBMClassifier(random_state=42)]
estimators
results = []
for estimator in estimators:
result = []
result.append(estimator.__class__.__name__)
results.append(result)
results
from sklearn.model_selection import RandomizedSearchCV
max_depth = np.random.randint(2,20,10)
param_distributions = {'max_depth':max_depth}
results = []
for estimator in estimators:
result = []
if estimator.__class__.__name__ != 'DecisionTreeClassifier':
param_distributions['n_estimators'] = np.random.randint(100,200,10)
clf = RandomizedSearchCV(estimator,
param_distributions,
n_iter=100,
scoring='accuracy',
n_jobs=-1,
cv=5,
verbose=2)
clf.fit(X_train, y_train)
result.append(estimator.__class__.__name__)
result.append(clf.best_params_)
result.append(clf.best_score_)
result.append(clf.score(X_test, y_test))
result.append(clf.cv_results_)
results.append(result)
df = pd.DataFrame(results,columns=['estimator','best_params','train_score','test_score','cv_result'])
test_set = pd.read_csv('test.csv')
test_set.head()
test_set['trestbps'] = np.log1p(test_set['trestbps'])
test_set['chol'] = np.log1p(test_set['chol'])
transform_data = test_set.drop(columns=['id', 'age', 'sex', 'cp', 'trestbps', 'chol', 'fbs', 'restecg', 'exang', 'oldpeak', 'slope', 'ca','thal'])
scaler = StandardScaler()
std_transfrom_data = scaler.fit_transform(transform_data)
test_set[transform_data.columns] = std_transfrom_data
test_X = test_set.iloc[:,1:] # id 제외 후 모든 데이터 사용
# 가장 f1 score값이 높았던 lr_grid_clf 사용
best_estimator = lr_grid_clf.best_estimator_
preds = best_estimator.predict(test_X)
submission = pd.read_csv('sample_submission.csv')
submission['target'] = preds
submission.to_csv('final.csv', index=False)
아무리 좋은 강의와 책을 독학하더라도 실제로 대회에 나가서 데이터를 가지고 머신러닝을 돌려보지 않으면 절대 실력이 늘지 않음
머신러닝 기법과 하이퍼파라미터 튜닝도 중요하지만 feture engineering이 훨씬 성능 향상에 크게 기여함을 알게 됨
이번 프로젝트는 단순히 로지스틱 회귀, Tree기반, xgb, lgbm 등을 사용했지만 다음 번에는 앙상블에 도전해 볼 계획임
비록 f1 score를 90점 대로 높이지 못했지만 앞으로 계속해서 공모전에 참가할 예정