3. Predictive Modeling

 

참고하고 있는 이 옹골찬 케글은 학습 모델을 무려 7가지나 사용해준다. 킹갓이 아닐 수 없다. 나같은 초짜에게는 다양한 예시가 제일 이해도를 높여준다. 하지만 지금까지 머신러닝 Workflow만 설명한 것 치고는 꽤나 어려운 주제라고 할 수 있겠다. 따라서 앞으로 여기서 사용한 학습 모델을 설명하는 글을 작성할 때마다 링크를 걸어 두겠다. 일단 지금은 이런 것들이 있다, 이렇게 학습시킨다 정도로 알고 넘어가자.

 

from sklearn.model_selection import train_test_split #training and testing data split
from sklearn import metrics #accuracy measure

train,test=train_test_split(train_data,test_size=0.3,random_state=0,stratify=train_data['Survived'])
train_X=train[train.columns[1:]]
train_Y=train[train.columns[:1]]
test_X=test[test.columns[1:]]
test_Y=test[test.columns[:1]]
X=train_data[train_data.columns[1:]]
Y=train_data['Survived']

 

1)Logistic Regression

from sklearn.linear_model import LogisticRegression

model = LogisticRegression()
model.fit(train_X,train_Y)
prediction3=model.predict(test_X)
print('The accuracy of the Logistic Regression is',metrics.accuracy_score(prediction3,test_Y))
The accuracy of the Logistic Regression is 0.8134328358208955

 

 

2)Support Vector Machines(Linear and radial)

  • Linear Support Vector Machine (linear-SVM)
from sklearn import svm

model=svm.SVC(kernel='linear',C=0.1,gamma=0.1)
model.fit(train_X,train_Y)
prediction1=model.predict(test_X)
print('Accuracy for linear SVM is',metrics.accuracy_score(prediction1,test_Y))
Accuracy for linear SVM is 0.8171641791044776

 

  • Radial Support Vector Machine (rbf-SVM)
model=svm.SVC(kernel='rbf',C=1,gamma=0.1)
model.fit(train_X,train_Y)
prediction2=model.predict(test_X)
print('Accuracy for rbf SVM is ',metrics.accuracy_score(prediction2,test_Y))
Accuracy for rbf SVM is  0.8022388059701493

 

 

3)Random Forest

from sklearn.ensemble import RandomForestClassifier

model=RandomForestClassifier(n_estimators=100)
model.fit(train_X,train_Y)
prediction7=model.predict(test_X)
print('The accuracy of the Random Forests is',metrics.accuracy_score(prediction7,test_Y))
The accuracy of the Random Forests is 0.7873134328358209

 

 

4)K-Nearest Neighbours (KNN)

from sklearn.neighbors import KNeighborsClassifier

model=KNeighborsClassifier() 
model.fit(train_X,train_Y)
prediction5=model.predict(test_X)
print('The accuracy of the KNN is',metrics.accuracy_score(prediction5,test_Y))
The accuracy of the KNN is 0.7873134328358209

 

n_neighbours 속성의 값을 변경하면 KNN 모델의 정확도도 바뀐다.

a_index=list(range(1,11))
a=pd.Series()

x=[0,1,2,3,4,5,6,7,8,9,10]

for i in list(range(1,11)):
    model=KNeighborsClassifier(n_neighbors=i) 
    model.fit(train_X,train_Y)
    prediction=model.predict(test_X)
    a=a.append(pd.Series(metrics.accuracy_score(prediction,test_Y)))
    
plt.plot(a_index, a)
plt.xticks(x)
fig=plt.gcf()
fig.set_size_inches(12,6)
plt.show()

print('Accuracies for different values of n are:',a.values)
print("Max Accuracy ",a.values.max())

주어진 N의 범위 안에서의 정확도 그래프

Accuracies for different values of n are: [0.75746269 0.76119403 0.79477612 0.76492537 0.78731343 0.77985075
 0.76865672 0.7761194  0.75       0.76119403]
Max Accuracy  0.7947761194029851

 

 

5)Naive Bayes

from sklearn.naive_bayes import GaussianNB

model=GaussianNB()
model.fit(train_X,train_Y)
prediction6=model.predict(test_X)
print('The accuracy of the NaiveBayes is',metrics.accuracy_score(prediction6,test_Y))
The accuracy of the NaiveBayes is 0.8171641791044776

 

 

6)Decision Tree

from sklearn.tree import DecisionTreeClassifier

model=DecisionTreeClassifier()
model.fit(train_X,train_Y)
prediction4=model.predict(test_X)
print('The accuracy of the Decision Tree is',metrics.accuracy_score(prediction4,test_Y))
The accuracy of the Decision Tree is 0.7947761194029851

 

 

앞서했던 전처리와 EDA에 비해 함수가 매우 간략한 것을 알 수 있다. 사실 인공지능을 하다 보면 알고리즘을 돌려 정확도를 내는 것은 정말 쉽다. 단순히 함수만 사용하면 되니까 말이다. 하지만 이 함수들의 내용을 잘 알아야 함수를 설정할 때 사용자가 지정해야하는 파라미터들을 잘 설정할 수 있고 원하는 결과가 나오지 않았을 때 대체할만한 알고리즘을 선택할 수 있다. 하지만 일단 여기까지하자. 정확도가 높진 못하지만, 어쨌든 우리는 진짜 머신러닝을 해봤기 때문이다. 앞으로 더 공부하면서 차차 정확도를 높여가보고 여기에 쓰인 알고리즘은 어떤 원리로 동작되는지 알아가보자.

 

 

 

2. Feature Engineering and Data Cleaning

 

데이터를 대충 확인했으니 해야 할 일은 무엇인가? 바로 전처리이다! 사실 앞선 내용에서는 전처리가 EDA 보다 먼저라고 했지만 사실 EDA와 전처리는 같이 왔다갔다 하며 하기 때문에 이 문제에서는 우선적으로 EDA로 데이터를 확인했다. EDA로 데이터의 특성을 얼추 파악했으니 이제 전처리를 해야한다. 무엇을 전처리해야할까?

 

전처리할 것을 파악하기 위해 null값의 개수를 확인해보겠다.

 

train_data.isnull().sum()
PassengerId      0
Survived         0
Pclass           0
Name             0
Sex              0
Age            177
SibSp            0
Parch            0
Ticket           0
Fare             0
Cabin          687
Embarked         2
dtype: int64

 

Age와 Cabin은 앞선 EDA에서 누락된 데이터가 꽤나 있음을 알았는데 Embarked도 2개의 누락된 데이터가 있었다. 앞서 말했지만 Cabin은 누락된 데이터가 너무 많으므로 과감히 지운다. 그럼 Age와 Embarked의 누락된 데이터를 채워보자. 어떻게 채워야 누락된 데이터를 잘 채웠다고 소문이날까?

 

Age를 채우는 방법은 다양할 것이다. 누락된 데이터에 전체 나이의 평균치를 넣을 수도 있고 EDA를 통해 알게 된 데이터의 특징에 따라 채울 수도 있다. 필자는 참고한 케글의 방식을 따르겠다. 참고한 케글은 사람의 이름을 기준으로 Age를 나누었다. 탑승자 이름의 중간에 다양한 title이 존재하는데 이 title을 한 번 확인해보자.

 

train_data['Initial']= train_data.Name.str.extract('([A-Za-z]+)\.')

test_data['Initial']= test_data.Name.str.extract('([A-Za-z]+)\.')

# A-Z 또는 a-z 사이에 있고 .(점)이 오는 문자열을 찾는다. 중간에 위치한 title 찾는 코드
# 성별로 분류하여 Initial을 확인

pd.crosstab(train_data.Initial,train_data.Sex).T.style.background_gradient(cmap='summer_r')

성별을 기준으로 Initial을 확인한다.

 

여성은 Miss와 Mrs를 제일 많이 쓰고, 남성은 Mr와 Master를 많이 사용한다. 그럼 우리는 이제 누락된 데이터 중에서 Miss와 Mrs, Mr와 Master를 title로 갖는 값에 어떤 값을 채워야할까? 채워야 하는 값을 생각하기에 앞서, Miss, Mrs, Mr, Master와 같이 유의미하게 많은 데이터가 아닌 것들을 유의미한 데이터에 병합시킨다. 여기서 Mlle과 Mme는 Miss의 오타로 추정되기 때문에 Miss로 들어간다.

 

# 라벨(title)을 유의미한 데이터로 대체한다.

train_data['Initial'].replace(['Mlle','Mme','Ms','Dr','Major','Lady','Countess','Jonkheer','Col','Rev','Capt','Sir','Don'],['Miss','Miss','Miss','Mr','Mr','Mrs','Mrs','Other','Other','Other','Mr','Mr','Mr'],inplace=True)
test_data['Initial'].replace(['Mlle','Mme','Ms','Dr','Major','Lady','Countess','Jonkheer','Col','Rev','Capt','Sir','Don'],['Miss','Miss','Miss','Mr','Mr','Mrs','Mrs','Other','Other','Other','Mr','Mr','Mr'],inplace=True)

# 라벨에 따라 평균 값을 나타낸다.

train_data.groupby('Initial')['Age'].mean()
Initial
Master     4.574167
Miss      21.860000
Mr        32.739609
Mrs       35.981818
Other     45.888889
Name: Age, dtype: float64

 

그럼 이런 결과가 나타난다. Master는 답지 않게 어린 아이들을 뜻하는 것같고 Miss는 약 22세, Mr는 약 33세, Mrs는 약 36세, 기타의 title들은 약 46세의 평균값을 가진다. 이 평균값들을 누락된 데이터에 title을 기준으로 집어넣는다.

 

train_data.loc[(train_data.Age.isnull())&(train_data.Initial=='Mr'),'Age']=33
train_data.loc[(train_data.Age.isnull())&(train_data.Initial=='Mrs'),'Age']=36
train_data.loc[(train_data.Age.isnull())&(train_data.Initial=='Master'),'Age']=5
train_data.loc[(train_data.Age.isnull())&(train_data.Initial=='Miss'),'Age']=22
train_data.loc[(train_data.Age.isnull())&(train_data.Initial=='Other'),'Age']=46

test_data.loc[(test_data.Age.isnull())&(test_data.Initial=='Mr'),'Age'] = 33
test_data.loc[(test_data.Age.isnull())&(test_data.Initial=='Mrs'),'Age'] = 36
test_data.loc[(test_data.Age.isnull())&(test_data.Initial=='Master'),'Age'] = 5
test_data.loc[(test_data.Age.isnull())&(test_data.Initial=='Miss'),'Age'] = 22
test_data.loc[(test_data.Age.isnull())&(test_data.Initial=='Other'),'Age'] = 46


# 쉽게 하는 방법
title = train_data.Name.str.split('.').str.get(0).str.split(',').str.get(1)
train_data['title'] = title

a = train_data.groupby(train_data.title).Age.mean().round().reset_index()

pd.merge(train_data,a,on='title')

 

이제 train_data와 test_data에 누락된 값이 있는지, 평균값들이 잘 채워져 있는지 확인해본다.

 

train_data.Age.isnull().any()
test_data.Age.isnull().any()
False

 

Embarked 값은 train_data에서만 누락되어있고 누락된 데이터가 단지 2개 뿐이니, 가장 많이 탑승한 탑승구인 S를 채워넣겠다.

 

train_data['Embarked'].fillna('S',inplace=True)
train_data.Embarked.isnull().any()

 

 


 

1) Age_band

 

Age 데이터는 연속성을 띈다. 그냥 사용해도 되겠으나 우리는 다양한 방법을 공부하고 있기 때문에 이것을 그룹화시키려고 한다. 

 

# Age를 그룹화하기

train_data['Age_band']=0
train_data.loc[train_data['Age']<=16,'Age_band']=0
train_data.loc[(train_data['Age']>16)&(train_data['Age']<=32),'Age_band']=1
train_data.loc[(train_data['Age']>32)&(train_data['Age']<=48),'Age_band']=2
train_data.loc[(train_data['Age']>48)&(train_data['Age']<=64),'Age_band']=3
train_data.loc[train_data['Age']>64,'Age_band']=4
train_data.head()

train_data.head()를 통해 Age_band를 확인할 수 있다.

 

train_data['Age_band'].value_counts().to_frame().style.background_gradient(cmap='summer')

 

 

sns.factorplot('Age_band','Survived',data=train_data,col='Pclass')
plt.show()

Pclass 별 Age_band의 생존률

 

연속적인 Age 데이터를 Age_band로 그룹화하고 그것에 대해 EDA를 해보았다. 역시나 어떤 클래스던지간에 나이가 어린 사람일수록 생존률이 높음을 확인할 수 있다.

 

 

2) Family_Size and Alone

 

Family_size 와 Alone으로 분류한다. 이것은 Parch와 SibSp의 압축이다. 생존율이 승객의 가족 규모와 연관이 있는지를 판단하기 위해 분류한다.

 

# train_data를 Family_Size와 Alone으로 분류

#family size
train_data['Family_Size']=0
train_data['Family_Size']=train_data['Parch']+train_data['SibSp']

#Alone
train_data['Alone']=0
train_data.loc[train_data.Family_Size==0,'Alone']=1

sns.factorplot('Family_Size','Survived',data=train_data)
plt.show()

혼자라고 생존률이 높은것은 아니다.

 

2~4인 가족의 생존률이 다른 가족 수보다 더 높음을 알 수 있다.

 


 

얼추 데이터를 그룹화했으니 이제 데이터들이 얼마나 서로 유의미하게 연관되어있는지를 확인해볼 차례이다.

앞선 내용에서 생존과 굉장히 밀접한 관련이 있던 3가지 부분 또한 위와 같이 숫자로 그룹화하겠다.

 

train_data['Sex'].replace(['male','female'],[0,1],inplace=True)
train_data['Embarked'].replace(['S','C','Q'],[0,1,2],inplace=True)
train_data['Initial'].replace(['Mr','Mrs','Miss','Master','Other'],[0,1,2,3,4],inplace=True)

 

그 후 무의미하다고 여겨지는 데이터들을 Drop한다.

 

train_data.drop(['Name','Age','Ticket','Cabin','PassengerId','SibSp','Parch'],axis=1,inplace=True)
sns.heatmap(train_data.corr(),annot=True,cmap='RdYlGn',linewidths=0.2,annot_kws={'size':20})
fig=plt.gcf()
fig.set_size_inches(18,15)
plt.xticks(fontsize=14)
plt.yticks(fontsize=14)
plt.show()

상관관계를 나타내는 표가 만들어진다.

 

위의 이미지는 상관관계를 나타내주는 것이다. 색이 진할수록 관련도가 높은것이다. 이 표를 보면 생존률은 PClass, Sex, Fare, Initial과 많이 연관되어 있음을 알 수 있다. 상관관계 또한 EDA중의 하나이다. 개발자는 상관관계 표를 통해 유의미하게 연관되어 있는 데이터를 찾을 수 있다. 지금도 PClass, Sex, Initial에 대한 것은 이전 EDA를 통해 알았지만 Fare는 처음 알지 않았는가!

 

또 길어졌으니 학습하는 방법은 다음에 설명하겠다.

 

 

 

 

킹갓 케글을 아는가? 사실 필자도 최근에 알았다. (왜냐면 인공지능을 최근에 시작했음) 인공지능을 하면서 단언코 최고의 커뮤니티는 케글이 아닐까 한다. 다양한 대회들이 열리는 것은 물론이고 세계 각국의 인공지능 능력자들이 서로의 코드를 공유하기 때문에 개인적으로 깃허브보다 낫다고 생각한다. 그리고 Notebook을 사용해서 코드를 진행하면 흐름을 잘 이해할 수 있어서 처음 인공지능을 하는 사람들에게는 적격인 사이트라고 생각한다.

 

https://www.kaggle.com/c/titanic

 

Titanic: Machine Learning from Disaster

Start here! Predict survival on the Titanic and get familiar with ML basics

www.kaggle.com

 

앞서 2. 머신러닝 진행과정 에서 말했다시피 이론만 하고 넘어가면 제대로 모른다. 그러니 위의 Titanic 대회에 참가해 머신러닝의 진행과정을 실전을 통해 이해해보자!

 

참고로 케글 사용법과 타이타닉에 대해 잘 설명해주는 유튜브 동영상은 여기 를 누르면 되고, 필자가 참고한 케글은 여기 를 누르면 된다.

 

 

1.  EDA (탐색적 자료 분석)

 

import numpy as np 
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import missingno as msno
plt.style.use('fivethirtyeight')
import warnings
warnings.filterwarnings('ignore')
%matplotlib inline

# 데이터를 불러오고 보여준다.
data=pd.read_csv('../input/titanic-machine-learning-from-disaster/train.csv')

# 참고로 data.head()는 앞의 5개만을 보여준다.
data.head() 
 
 

데이터를 확인하면 이렇게 나온다.

 

Survived 0은 사망, 1은 생존을 의미
Pclass 선실 클래스
SibSp 탑승한 형제자매, 배우자의 수
Parch 탑승한 부모, 자식의 수
Ticket 티켓 번호
Fare 운임
Cabin 객실번호
Embarked 탑승장소(C: Cherbourg, Q: Queenstown, S: Southampton)

 

위의 라벨들이 의미하는 것을 표로 나타냈다. 당장 저 데이터만 봐도 NaN 값을 볼 수 있는데 그러면 얼마나 많은 데이터들이 누락되어있을까?

 

# train_data의 누락된 자료 비율 파악

for col in train_data.columns :
    msg = '항목 {:>10}\t 비어있는 자료의 비율 : {:.2f}%'.format(col, 100 * (train_data[col].isnull().sum() / train_data[col].shape[0]))
    print(msg)
항목 PassengerId	 비어있는 자료의 비율 : 0.00%
항목   Survived	 비어있는 자료의 비율 : 0.00%
항목     Pclass	 비어있는 자료의 비율 : 0.00%
항목       Name	 비어있는 자료의 비율 : 0.00%
항목        Sex	 비어있는 자료의 비율 : 0.00%
항목        Age	 비어있는 자료의 비율 : 19.87%
항목      SibSp	 비어있는 자료의 비율 : 0.00%
항목      Parch	 비어있는 자료의 비율 : 0.00%
항목     Ticket	 비어있는 자료의 비율 : 0.00%
항목       Fare	 비어있는 자료의 비율 : 0.00%
항목      Cabin	 비어있는 자료의 비율 : 77.10%
항목   Embarked	 비어있는 자료의 비율 : 0.22%

 

# test_data의 누락된 자료 비율 파악

for col in test_data.columns :
    msg = '항목 {:>10}\t 비어있는 자료의 비율 : {:.2f}%'.format(col, 100 * (test_data[col].isnull().sum() / test_data[col].shape[0]))
    print(msg)
항목 PassengerId	 비어있는 자료의 비율 : 0.00%
항목     Pclass	 비어있는 자료의 비율 : 0.00%
항목       Name	 비어있는 자료의 비율 : 0.00%
항목        Sex	 비어있는 자료의 비율 : 0.00%
항목        Age	 비어있는 자료의 비율 : 20.57%
항목      SibSp	 비어있는 자료의 비율 : 0.00%
항목      Parch	 비어있는 자료의 비율 : 0.00%
항목     Ticket	 비어있는 자료의 비율 : 0.00%
항목       Fare	 비어있는 자료의 비율 : 0.24%
항목      Cabin	 비어있는 자료의 비율 : 78.23%
항목   Embarked	 비어있는 자료의 비율 : 0.00%

 

# 누락된 데이터를 시각화 해보자

msno.matrix(df=train_data.iloc[:,:], figsize=(8,8), color=(0.7,0.4,0.2))

train_data의 데이터 시각화 / 디스크 정리 보는 기분

 

 

Cabin과 Age 데이터가 꽤 많이 누락되어있고 Cabin 데이터는 사실상 없다고 보는게 맞겠다. 하지만 데이터가 많이 없다고 무의미한 데이터일까? 대답은 그건 아무도 모른다이다. Cabin같은 경우는 누락된 데이터가 너무 많아 평균값으로 채울 수도 없으니 지우는게 맞다고 본다. 하지만 Age같이 애매하게 누락된 데이터들은 최대한 살려야한다. 사실 이게 또 좋다고 볼 수도 없다. 하지만 데이터가 많을수록 더 정확한 모델이 만들어지기 때문에 최대한 많은 데이터가 필요하므로 사람들은 열심히 열심히 누락된 데이터를 매꾸는 전처리 과정을 거치게 된다. 일단 계속해서 EDA를 하자.

 

f,ax=plt.subplots(1,2,figsize=(18,8))
train_data['Survived'].value_counts().plot.pie(explode=[0,0.1],autopct='%1.1f%%',ax=ax[0],shadow=True)
ax[0].set_title('Survived')
ax[0].set_ylabel('')
sns.countplot('Survived',data=train_data,ax=ax[1])
ax[1].set_title('Survived')
plt.show()

위의 코드로 코딩을 하면 이와 같은 그림이 나온다.

 

앞서 표에서 말했다시피 0은 사망을 뜻한다. 많은 사람들이 죽었음을 알 수 있는 대목이다. 그러면 여기서 궁금해지는 것이 있다. 어떤 사람들이 살아남았을까? 우리는 이것을 확인하기위해 EDA를 사용한다. 그리고 이것을 확인하는 것은 예측을 더 쉽게할 수 있다.

 

# 성별에 따른 사망자와 생존자

f,ax=plt.subplots(1,2,figsize=(18,8))
train_data[['Sex','Survived']].groupby(['Sex']).mean().plot.bar(ax=ax[0])
ax[0].set_title('Survived vs Sex')
sns.countplot('Sex',hue='Survived',data=train_data,ax=ax[1])
ax[1].set_title('Sex:Survived vs Dead')
plt.show()

여자가 압도적으로 생존률이 높았다.

남자가 약 600명, 여자가 약 300명으로 남자 승객이 여성에 비해 압도적으로 높았음에도 불구하고 여성의 생존률이 남성의 생존률보다 더 높은 것을 확인할 수 있다. (사스가 Lady first의 나라) 이런 시각적인 데이터를 보면 타이타닉에 탔던 사람들은 약자를 우선으로 여겼을 확률이 매우 높다. 이런 직관을 판단하기 위해 EDA과정이 필요하다. 그렇다면 약자인 노인과 영아의 생존률은 얼마인지 확인해보자.

 

# 나이에 따른 사망자와 생존자

f,ax=plt.subplots(1,2,figsize=(20,10))
train_data[data['Survived']==0].Age.plot.hist(ax=ax[0],bins=20,edgecolor='black',color='red')
ax[0].set_title('Survived= 0')
x1=list(range(0,85,5))
ax[0].set_xticks(x1)
train_data[train_data['Survived']==1].Age.plot.hist(ax=ax[1],color='green',bins=20,edgecolor='black')
ax[1].set_title('Survived= 1')
x2=list(range(0,85,5))
ax[1].set_xticks(x2)
plt.show()

15세 미만의 아이들의 생존자는 대체로 사망자보다 많다.

 

fig, ax = plt.subplots(1,1, figsize=(9,5))
sns.kdeplot(train_data[train_data['Survived'] == 1]['Age'], ax=ax)
sns.kdeplot(train_data[train_data['Survived'] == 0]['Age'], ax=ax)
plt.legend(['Survived','Dead'])
plt.xlabel('Age')
plt.ylabel('Survived')
plt.show()

위의 막대그래프를 더 직관적으로 나타냈다.

 

위의 그래프들을 보면 죽은 사람과 산 사람이 비슷비슷한 20~60대와는 달리 확실히 15세 미만의 아이들이 생존률이 더 높음을 알 수 있다. (직관이 먹혔다!) 그렇다면 클래스에 따라서는 생존률이 어떻게 나타날까? 대부분 사람들의 직관으로 부자들이 많이 생존했을 것이라고 예측할 수 있다. 과연 그럴까?

 

# 클래스에 따른 사망자와 생존자

pd.crosstab(train_data.Pclass,data.Survived,margins=True).style.background_gradient(cmap='summer_r')

클래스에 따른 생존자와 사망자 수

 

f,ax=plt.subplots(1,2,figsize=(18,8))
train_data['Pclass'].value_counts().plot.bar(color=['#CD7F32','#FFDF00','#D3D3D3'],ax=ax[0])
ax[0].set_title('Number Of Passengers By Pclass')
ax[0].set_ylabel('Count')
sns.countplot('Pclass',hue='Survived',data=train_data,ax=ax[1])
ax[1].set_title('Pclass:Survived vs Dead')
plt.show()

클래스에 따른 데이터를 시각화하였다.

 

3등급의 사람들이 제일 많았으나 3등급의 사망자가 제일 많았다. 1등급은 예상대로 생존자가 사망자보다 더 많았다. (직관이 먹혔다!2) 그렇다면 여기서 갑자기 궁금한 것이 있다. (사실 궁금하다기보다는 코드가 있으니 써먹으려고ㅋㅎ) 클래스 간 성별에 따른 생존률이 위에서 보여진것과 동일할까? 3등급의 사람들은 전체 성별 생존률과는 무관하게 남성이 여성보다 더 많이 살았을 수도 있지 않을까?

 

# 클래스 별 성별에 따른 사망자와 생존자

sns.factorplot('Pclass','Survived',hue='Sex',data=train_data)
plt.show()

응 아니야

 

이건 나의 직관이 틀렸다! 이렇게 이런 저런 직관과 데이터의 분류, 흐름 등을 파악하기 위해 EDA 과정은 반드시 필요하다. 개발자가 데이터를 잘 이해해야 좋은 알고리즘을 선택해 좋은 모델을 만들 수 있기 때문이다. 이렇게 사람의 직관으로 어느정도 추정할 수 있는 데이터와 달리, 전혀 감도 잡을 수 없는 데이터들은 어떻게 사용해야할까? 이 역시 EDA를 통해 데이터의 숨겨져 있는 특징들을 파악할 수 있다. 

 

# 탑승장소를 기반으로한 다양한 데이터 조합들

f,ax=plt.subplots(2,2,figsize=(20,15))
sns.countplot('Embarked',data=train_data,ax=ax[0,0])
ax[0,0].set_title('No. Of Passengers Boarded')
sns.countplot('Embarked',hue='Sex',data=train_data,ax=ax[0,1])
ax[0,1].set_title('Male-Female Split for Embarked')
sns.countplot('Embarked',hue='Survived',data=train_data,ax=ax[1,0])
ax[1,0].set_title('Embarked vs Survived')
sns.countplot('Embarked',hue='Pclass',data=train_data,ax=ax[1,1])
ax[1,1].set_title('Embarked vs Pclass')
plt.subplots_adjust(wspace=0.2,hspace=0.5)
plt.show()

 

sns.factorplot('Pclass','Survived',hue='Sex',col='Embarked',data=train_data)
plt.show()

역시 Lady Frist

 

전체적으로 봤을 때 S 에서 가장 많은 사람이 탑승했다. C와 Q 는 남녀의 비율이 비슷하고, S는 남자가 더 많으며 S의 경우 생존률 낮다.  Pclass와 함께 보면 C가 생존률 높은 이유와 S가 생존률이 낮은 이유가 클래스와 연관이 있음을 알 수 있다. 이렇게 EDA를 사용하면 자칫 보지 않았을 연관성에 대해서도 판단할 수 있게 된다.

 

너무 길어졌으니 전처리 과정은 다음에 설명하겠다.

 

 

 

머신러닝 Workflow

 

대부분의 머신러닝은 위와 같은 방식으로 진행된다.

 

1) Data Preprocessing (데이터 전처리)

 

수집한 데이터가 깨끗할거라는 기대는 버리는게 좋다. 애초에 데이터를 수집하는 것 부터가 일이다. 예를 들어 스타일링 변화의 실패를 줄이고자 다양한 헤어스타일을 가상으로 나의 얼굴에 대입해본다고 생각하자. 여기서의 헤어스타일은 굉장히 자연스럽게 연출되기를 기대한다. 그럼 이 모델을 만들기 위해서는 우선 데이터가 필요하다. 앞서 말했지만 다량의 데이터들이 수학적인 알고리즘을 통해 데이터들끼리 자체적인 로직을 만들기 때문에 우리는 다!량!의! 데이터들이 필요하다. 당장 구글에 머리스타일을 검색해 보자. 다양한 각도와 구도의 이미지들을 볼 수 있다. 우리의 똑똑하지만 멍청한 인공지능은 깨끗하게 가공된 데이터가 아니면 학습률/예측률이 난리가 난다. (사실 인공지능은 영화들이 만들어낸 허구다. 나도 당장 로봇이 말하는 그런 AI만 생각했지 현재까지의 인공지능은 그냥 인간이 거의 다함ㅠ 이렇게 전처리가 빡셀줄 몰랐지) 그래서 인간은 노동을 통해 다량의 데이터들을 깨끗하고 정제된 데이터로 만들어 학습에 사용해야한다. 따라서 데이터 전처리는 단순 노동과 노동과 노동의 연속이다. (전처리 방법도 다양하기 때문에 진짜 죽음 뿐)

 

전처리를 하다보면 이런 상황 발생

 

 

2) EDA (Exploratory Data Analysis)  & Feature Engineering (탐색적 데이터분석)

 

EDA란 수집한 데이터를 다양한 각도에서 관찰하고 이해하는 과정이다. 한마디로 데이터를 알고리즘에 때려 박기 전에 그래프나 통계적인 방법으로 자료를 직관적으로 바라보며 특징을 찾고, 숨겨진 패턴을 발견하는 과정이다. 사실 필자는 이것의 중요성에 대해 잘 인식하지 못했다. 근데 이게 사실상 제일 중요하다. 전처리는 노동과 노동의 연속이라면 이 단계에서는 직관이 중시되기 때문이다. 생각보다 인공지능을 직접 하다보면 개발자의 직관이 많이 요구된다. 분명히 사용하는 알고리즘은 더럽게 복잡한 수학적 공식을 사용하지만 그건 컴퓨터의 영역이라면 개발자는 이 과정을 통해 데이터의 특징을 파악하여 발견한 특징들을 잘 활용하여 모델을 구성해야한다. 그래야 학습률이 좋다. 근데 이 과정도 전처리 못지 않게 노동과 노동과 노동의 연속이다. (사실 인공지능은 말만 번지르르하지 실제로 만들려면 그냥 단순 노동과 직관이 90%라고 해도 과언이 아니다.) 

 

 

3) Algorithm selection (알고리즘 선택)

 

WOW 드디어 알고리즘을 선택하는 단계이다! 여기가 이제 진짜 인공지능이라고 보면 되겠다만 문제는 여기도 노동과 노동의 연속이라는 것이다. (도망쳐) 앞으로 차차 다양한 알고리즘에 대해 글을 쓰겠지만 수학적인 내용은 굉장히 복잡하다. 필자는 전공에서 사용하는 수학 공식들부터도 어떻게 이런 수식들이 이런 결과를 도출할 수 있는가에 대한 경이로움을 느꼈는데 인공지능은 그거의 곱절로 놀랍고 놀랍다. (문제는 그만큼 복잡함) 내가 수학을 잘하고 좋아했더라면 알고리즘을 만드는 사람이 되지 않았을까 하는 헛된 꿈도 잠깐 꾸어봤지만, 나는 새로운 수식을 만들어낼 정도로 의지있고 똑똑한 사람이 아니기 때문에 (당장 남이 만든 공식 이해하기도 벅참) 있는 알고리즘이나 잘 활용하자는 생각이다. 문제는 다양한 알고리즘을 수학적으로 이해했다고 해도 적용과는 또 별개라는 것이다. 알고리즘들은 다양하고, 거기에 사용되는 속성들도 굉장히 다양하며 그것은 사람이 모두 설정한다. (인공지능 당신 하는게 도대체 뭔데) 그래서 앞과정을 다끝내도 여기와서도 멘탈이 터진다. 프로그래밍을 하려면 초월과 달관하는 자세는 필수라고 생각한다.

 

코딩이 오류가 나도, 기껏 오류 고쳐서 돌아가도 원하는 결과가 안나와도 나는 괜찮다.

 

 

4) Training / Evaluation / Parameter Tuning

 

이걸 한 번에 묶은 이유는 학습시키면 평가하고 평가가 원하는 결과가 안나오면 하이퍼 파라미터를 다시 조정하는 과정을 계속해서 반복해야 하기 때문이다. 이 과정은 그래도 앞의 과정들보단 낫다. 나는 기다리고 컴퓨터가 돌아가기 때문이다. 문제는 반복했는데도 일정수준 이상으로 높아지지 않으면 앞 과정들을 다시 반복해야한다는 것이다. 이런 결과가 생기면 또 멘탈이 터진다. 앞의 과정들을 잘 하면 이런 불상사는 없을 수 있겠으나 글쎄... 지금 당장 하고 있는 프로젝트도 이 과정에서 결과값이 안나오면 전처리를 다시 만지는걸 보아 불상사는 항상 생길 것 같다. (그것이 개발자의 인생이지 노답)

 

 

5) Deployment (배포)

 

이 과정까지 도달했다면 당신은 축배를 들어야한다. 당신은 진정한 인공지능을 만들어 냈다. 

 

 

 

 

 

당신은 이 글을 보면 아~ 인공지능은 대충 이런 구조로 되어있구나를 알 수 있게 될것이다.

문제는 코딩은 하나도 모르고 대충 느낌으로 알게 된다는 것이다! 나는 항상 이게 불만이었다. 모든 이론들은 이론상으로는 알겠다라고 느끼지만 실전에 들어가면 까막눈처럼 막막하기 때문이다. 따라서 다음에는 이 과정들을 함축적이면서도 자세하게 알려주는 문제에 대해 다루고자 한다. 커밍쑨!

 

인공지능(Artificial Intelligence)

인공지능(Artificial Intelligence)이란 기계 혹은 시스템에 의해 만들어진 지능, 즉 인공적인 지능을 뜻한다.

앞으로 인공지능에 대해 더 탐구해보면 알겠지만 다양하고 복잡한 알고리즘들을 사용하는 것 치고는 뜻이 참 간단하고 추상적임을 알 수 있겠다. 필자도 처음에는 저런 추상적인 뜻만 보고 인공지능이란 참으로 흥미롭고 재미있는 학문이겠구나! 라고 생각했다.

(애초에 모든 분야가 호기심은 자극한다. 내 전공도 처음에는 오 재미있겠는데?로 시작해서 4년 내내 재미없음과 잘못되었음을 깨닫는 과정을 거쳤다. 깨달았을 때는 이미 늦음ㅠ)

잘못된 생각이었다고 생각하지만 어쩌겠는가. 이미 발을 들였으니 얻어가는 것이라도 있게 열심히 공부해 보자.

 

당장 구글에서 인공지능을 검색하면 위키백과의 인공지능을 볼 수 있다. 위키백과에서 옹골차게 인공지능의 흐름까지 알려주니 지하철이나 버스에서 왔다갔다할 때 가끔씩 읽어보는 것도 나쁘지 않다고 생각한다.

 

구글에 인공지능을 검색하면 이런 이미지가 나온다.

 

인공지능을 크게는 머신러닝과 딥러닝으로 구분할 수 있다. 그림에서 보다시피 머신러닝은 딥러닝을 포함한다. 

그럼 머신러닝과 딥러닝은 정확하게 뭘까?

 

 

머신러닝

여기 기똥찬 블로그를 찾았다. 여태까지 내가 배운 머신러닝을 기똥차게 압축한 블로그다. 블로그에 있는 글을 참고해서 정말 간단하게 머신러닝을 말하자면 문제를 해결하기 위한 맞춤 코드를 작성하지 않고 많은 양의 데이터를 일반 알고리즘에 공급하여 데이터를 기반으로 한 자체 로직이 만들어지는 것이 머신러닝이다. 

 

매번 뜬구름 잡는 소리로만 개념을 이해하다가 블로그 덕에 이런 사이트를 찾다니 참 행운이다. 여러분도 이 링크를 타고 들어가서 읽어보면 큰 도움이 될 것이다. 머신러닝의 전반적인 흐름과 개요를 완벽하게 잡았다랄까! 

 

 

딥러닝

여기 또다른 블로그의 링크를 걸어두었다. 여기도 딥러닝을 잘 설명해주고 있고 머신러닝과 딥러닝의 차이 등에 대해 잘 설명해주고 있다. 블로그에 들어가서 자세히 읽어보면 딥러닝을 이해하는데 큰 도움이 될 것이다. 또 내 블로그에서 간단히 딥러닝을 말해보겠다.

 

 

뉴런                                                                                                        다중 퍼셉트론

 

딥러닝은 인간의 뉴런에서 따온 학습 방법이다. 생명과학을 한 사람이라면 뉴런에 대해 알 것이다. 필자는 수능때 생물1을 봤기 때문에 뉴런과 유전에 대해 아주 빠삭했었는데 지금은 문과 친구들 부모님의 혈액형으로 친구의 혈액형을 때려맞추는 수준으로만 남아있다. 따라서 뉴런에 대해 자세히 설명해줄 여력이 없다. 궁금한 사람은 찾아보면 되겠으나, 최소한의 이해를 돕기 위한 야매 설명을 하자면 그냥 뉴런과 뉴런이 손에 손잡고 전기를 전달해서 반사작용이나 행동을 한다고 보면 되겠다. (생물하는 사람들이 보면 대노할 수준의 설명이 아닐까하는 마음ㅋㅎ) 이런 뉴런의 특징을 퍼셉트론이라는 것으로 구현해 낸다고 보면 된다. 퍼셉트론이 동작하는 방식은 다음과 같다. 각 노드의 가중치와 입력치를 곱한 것을 모두 합한 값이 활성함수에 의해 판단되는데, 그 값이 임계치(보통 0)보다 크면 뉴런이 활성화되고 결과값으로 1을 출력한다. 뉴런이 활성화되지 않으면 결과값으로 -1을 출력한다. 더 자세한 설명은 퍼셉트론을 다루는 파트에서 더 자세히 하겠다.

 

+) 몇줄 요약

머신러닝은 규칙을 사람이 만들지만, 딥러닝은 신경망이 주어진 데이터로부터 특징과 규칙을 직접 학습(end-to-end machine learning)한다. 따라서 머신러닝은 사람이 생각한 특징, 파생변수가 정확도 향상에 큰 역할을 하는 경우가 많고 딥러닝은 신경망의 학습능력에 따라 정확도가 달라진다. 인공지능은 이 모든 것을 포괄하면서 더 사람답게, 인간의 지적 능력을 거의 똑같이 구사하고자하는 것을 의미한다.

 

 

+ Recent posts