22.10.25.
오랜만에 velog 작성! 공부하기가 싫다. 피곤하다! 그래도 해야지! 밀린 velog는 언젠가...!
그동안 미드프로젝트를 진행했고, 미드프로젝트를 마무리 한 후 이제 머신러닝 수업에 들어갔다.
미드프로젝트 끝낼 때, 와 드디어 끝이구나 했는데, 끝은 무슨 이제 시작이었다! 다시 시작해보자. 파이팅!
어제 사실 머신러닝 첫 수업을 했었다. 내용은 머신러닝을 위해 사용하는 다양한 프레임워크에 대한 소개!
그리고 앞으로의 학습 방향! 등 이었다. 오늘부터 본격적으로 머신러닝 수업을 시작했다.
범주형 | 수치형 | |
---|---|---|
지도학습 | 분류 | 회귀 |
비지도학습 | 군집화 | 차원축소 |
머신러닝의 다양한 분야 중 특히 scikit-learn 의 개발자는 classification과 regression을 머신러닝의 주요 분야로 생각한다고 하여, 사이킷런에는 분류와 회귀가 잘 되어 있다고 한다.
머신러닝에는 다양한 알고리즘을 적용할 수 있다.
지도학습 알고리즘으로는 선형회귀, 정규화, 로지스틱 회귀, 서포트 벡터 머신, 나이브 베이즈 분류, 랜덤 포레스트, 신경망, k-최근접 이웃 알고리즘 등이 있다.
해당 알고리즘들은 분류 또는 회귀, 혹은 둘 모두에 적용할 수 있다.
특히, 로지스틱 회귀의 경우 회귀가 아닌 분류에 사용하는 알고리즘을 기억하자.
비지도학습 알고리즘으로는 주성분 분석, 잠재 의미 분석, 음수 미포함 행렬 분해, k-평균 알고리즘, 가우시안 혼합 모델 등이 있다고 한다... 아직 뭔지 하나도 모르겠지만, 차차 공부해나가자!
데이터 전처리
데이터 전처리는 필수적이다. 여태까지 배운바와 같이 EDA를 하며 전처리를 진행하기도 하고, 특히 머신러닝을 위해서는 Normalization, Scaling, Imputation(결측치 채우기), Encoding 등의 전처리를 진행하면 좋다. outlier도 판단하여 사용할지 말지 경정해야한다.
사이킷런의 알고리즘들은 결측치가 있다면 오류를 반환하기 때문에 imputation은 필수라고 한다.
머신러닝의 과정(지도학습)
오늘 수업 중 가장 중요했던 내용! 머신러닝, 그 중에서도 지도학습의 과정을 기억하자.
일단 끝! 데이터를 나누고, 학습시키고, 평가하면 된다.
이를 위해 코드에서 등장할 다양한 용어들을 살펴보자.
그럼 이제 지도학습의 알고리즘 중 하나인 Decision Tree 알고리즘을 알아보자.
위키백과 - 결정트리
각 노드가 질문의 형태를 이루고 있고, 그 질문의 답변에 따라서 데이터가 나누어지면 그게 바로 decision tree model 이다. 맨 처음의 노드가 root node, 중간은 intermediate node, 마지막은 terminal node 또는 leaf node라고 한단다. 결정 트리 내의 모든 노드에는 입력속성(클래스)가 일대일로 대응되며 각 노드에는 속성이 가질 수 있는 값이 표시, leaf node에는 클래스 또는 클래스의 확률 분포가 표시된다. 결정트리의 학습은 주어진 데이터를 적절한 분할 기준에 따라 부분집합들로 나누어 가는 과정을 통해 이루어진다.
결정 트리 분석법은 분류 트리, 회귀 트리로 나눌 수 있는데, 분류 트리의 경우 목표 변수가 유한한 값을 가지며, 회귀 트리의 경우 무한한 값을 가진다. 이렇듯 분류 및 회귀 트리를 일컬어 CART라고 한다.
당뇨를 예측하는 분석 모델 만들기.
DecisionTreeClassifier 이용, pima-indians-diabetes-database 이용.
https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_diabetes.html
데이터 EDA
EDA부터 진행하여 데이터를 파악한다! describe 해보고 특이한 점 찾아보고, hist를 통해 수치형 변수의 전체 분포도 파악해본다.
특이한 점이 있으면 시각화를 해 어떤 양상을 띄고 있는지 파악도 해본다.
Feature Engineering
feature를 적당히 조작하여 머신러닝에 더 적합한 형태로 만들 수 있다.
예를 들면, EDA 결과 임신 횟수라는 feature가 6을 넘어간다면, 당뇨일 가능성이 아주 커진다는 것을 발견하였고, 이에 수치형 변수인 임신횟수를, 6을 넘는지 안넘는지에 대한 범주형 변수 형태로 Encoding 해볼 수 있다.
df['Pregnancies_high'] = df['Pregnancies'] > 6
이와 같은 feature engineering은 꼭 해야하는 것도, 성능의 향상을 보장하는 것도 아니다. 단지 이런 방향의 조작도 가능하다는 것을 생각하고 있으면 된다.
결측치를 다루는 것 역시 feature engineering에 해당한다고 볼 수 있다. 예를 들면 이 데이터 중 Insulin feature는 결측치 값들을 모두 0으로 포함하고 있었다. 이는 데이터의 해석에 큰 영향을 끼치기에, 결측치를 다른 값으로 채워주도록 하였다.(당뇨병인지, 아닌지로 구분한 각 그룹의 인슐린 평균값)
Insulin_mean = df.groupby('Outcome')['Insulin_nan'].mean()
df['Insulin_fill'] = df['Insulin_nan']
df.loc[(df['Insulin_nan'].isnull()) & (df['Outcome']==0), 'Insulin_fill'] = Insulin_mean[0]
df.loc[(df['Insulin_nan'].isnull()) & (df['Outcome']==1), 'Insulin_fill'] = Insulin_mean[1]
음 여기서 엄청 오래걸렸다! 이런 코드로 진행해보려 했는데, 어디가 틀린건지 한참 찾았다...
df.loc[df['Outcome']== 0, 'Insulin_fill3'] = df['Insulin_nan'].fillna(Insulin_mean[0])
df['Insulin_fill3'] = df['Insulin_fill3'].fillna(Insulin_mean[1])
한참 걸려서야 찾았다..... outcome이 0인 애들만 골라내어 fiilna를 해준 값을 컬럼 전체에 할당하면, fillna 함수를 적용한 결과물에는 outcome == 1인 행들이 존재하지가 않기 때문에, outcome이 1인 행들은 NaN이 된다. 따라서 이런 코드로 쓰려면 아래와 같이 작성해야 했다.
df['Insulin_fill3'] = df['Insulin_nan']
df.loc[df['Outcome']== 0, 'Insulin_fill3'] = df.loc[df['Outcome']== 0, 'Insulin_fill3'].fillna(Insulin_mean[0])
df['Insulin_fill3'] = df['Insulin_fill3'].fillna(Insulin_mean[1])
split_count = int(df.shape[0] * 0.8)
train = df[:split_count]
test = df[split_count:]
8 : 2의 비율로 train set과 test set을 나누었다.
feature_names = df.columns.tolist()
feature_names.remove('Outcome')
label_name = "Outcome"
X_train = train[feature_names]
X_test = test[feature_names]
y_train = train[label_name]
y_test = test[label_name]
앞에서 언급했듯이, feature_names와 label name 을 이용해 데이터셋을 잘 나눈다.
from sklearn.tree import DecisionTreeClassifier()
model = DecisionTreeClassifier(random_state = 42)
model을 선언할때, 다양한 인자들(hyper parameter라고 한다. 여기서는 criterion, max_depth, max_features, min_samples_split 등)을 설정해줄 수 있다. 이는 모델의 성능에 큰 영향을 끼친다.
예를 들어, max_depth가 너무 적다면 underfitting(과소적합)이, 너무 크다면 overfittin(과대적합)이 발생할 수 있다.
model.fit(X_train, y_train)
y_predict = model.predict(X_test)
(y_predict == y_test).mean()
두번째는, 미리 구현된 알고리즘을 사용하는 방법이다.
from sklearn.metrics import accuracy_score
accuracy_score(y_test, y_predict)
세번째는, model의 score를 사용하는 방법이다.
model.score(X_test, y_test)
이렇게 세 가지 방법으로 모델을 평가할 수 있다!
from sklearn.tree import plot_tree
plt.figure(figsize = (20,20))
ptree = plot_tree(model, max_depth = 6, feature_names = feature_names, filled = True, fontsize = 10)
plt.show()
결과물
model.feature_importances_
sns.barplot(x = model. feature_importances_, y = model.feature_names_in_)