items = ['TV', '냉장고', '전자레인지', '컴퓨터', '선풍기', '선풍기', '믹서', '믹서']
#1. LabelEncoder
from sklearn.preprocessing import LabelEncoder
label_encoder = LabelEncoder()
label_encoder.fit_transform(items)
#2. OneHotEncoder
from sklearn.preprocessing import OneHotEncoder
import numpy as np
items = np.array(items).reshape(-1,1)
onehot_encoder = OneHotEncoder()
onehot_encoder.fit_transform(items)
onehot_labels = onehot_encoder.fit_transform(items)
onehot_labels.toarray()
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris
iris_data = load_iris()
dt_clf = DecisionTreeClassifier(random_state=42)
data = iris_data.data ## X
label = iris_data.target ## y
scores = cross_val_score(dt_clf, data, label, scoring = 'accuracy', cv=5)
scores
from sklearn.datasets import load_iris
import pandas as pd
iris = load_iris()
iris = iris['data']
iris_df = pd.DataFrame(iris)
iris_df
#pandas의 apply를 사용하여 정규화
#방법1
iris_df.apply(lambda x: (x-x.min()) / (x.max() - x.min()))
#방법2
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
iris_scalred = scaler.fit_transform(iris_df)
iris_scalred_df = pd.DataFrame(iris_scalred)
iris_scalred_df
from sklearn.datasets import load_wine
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score
wine = load_wine()
features = X = wine.data
labels = y = wine.target
dt_clf = DecisionTreeClassifier()
#4개의 구간으로 나누기
cross_val_score(dt_clf, features, labels, cv = 4)
cross_val_score(dt_clf, features, labels, scoring = 'accuracy', cv = 4)
#'labels'의 데이터별 개수 확인
labels
pd.Series(labels).value_counts()
from collections import Counter
Counter(labels) #딕셔너리 형태로 출력
np.bincount(labels)
titanic cvs 파일 : http://naver.me/5Zv8m3dH
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
import os
os.getcwd()
titanic = pd.read_csv('./titanic_train.csv') #'./' : 현재 위치
titanic[:5]
사이킷런 머신러닝 알고리즘은 Null값을 허용하지 않으므로 Null값을 먼저 처리해주어야 한다 -> fillna()
titanic.info()
titanic.isna().sum()
#Age의 결측치를 평균으로 변경
m = titanic['Age'].mean().round(0)
titanic['Age'] = titanic['Age'].fillna(m)
titanic['Age']
#결측치를 'N' 으로 변경
titanic['Cabin'] = titanic['Cabin'].fillna('N')
titanic['Embarked'] = titanic['Embarked'].fillna('N')
titanic.info()
#Cabin 칼럼의 선실 등급을 나타내는 첫 글자만 따기
titanic['Cabin'] = titanic['Cabin'].str[:1]
#성별, 생존여부 별로 생존여부의 빈도수
titanic.groupby(['Sex', 'Survived'])[['Survived']].agg('count')
#성별 생존율
titanic['Sex'].value_counts()
sns.barplot(data = titanic, x = 'Sex', y = 'Survived')
#좌석별 생존율
sns.barplot(data = titanic, x = 'Pclass', y = 'Survived', hue = 'Sex')
#연령별 생존율
#Age에 따라 값을 구분
#0~5세: Baby, 6~12세: Child, 13~18세: Teenager, 19~25세: Student,
#26~35세: Young Adult, 36~60세: Adult, 61세 이상: Elderly, -1이하: Unknown
binss = [0, 5, 12, 18, 25, 35, 60, 100]
labelss = ['Baby', 'Child', 'Teenager', 'Student', 'Young Adult', 'Adult', 'Elderly']
pd.cut(titanic['Age'], bins = binss, labels = labelss, right = True)
titanic['Age_category'] = pd.cut(titanic['Age'], bins = binss, labels = labelss, right = True)
sns.barplot(data = titanic, x = 'Age_category', y = 'Survived', hue = 'Sex', order = labelss)
titanic.drop('Age_category', axis = 1, inplace = True)
#'Cabin'를 LabelEncoding
titanic['Cabin'].value_counts()
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
encoder.fit_transform(titanic['Cabin'])
titanic['Cabin'] = encoder.fit_transform(titanic['Cabin']).tolist()
titanic[:5]
titanic['Sex'] = encoder.fit_transform(titanic['Sex']).tolist()
titanic['Embarked'] = encoder.fit_transform(titanic['Embarked']).tolist()
titanic[:5]
from sklearn.preprocessing import LabelEncoder
def encode_features(df):
features = ['Cabin', 'Sex', 'Embarked']
for feature in features:
encoder = LabelEncoder()
df[feature] = encoder.fit_transform(df[feature])
return df
encode_features(titanic)
titanic = encode_features(titanic)
titanic[:5]
#분석에 불필요한 'PassengerId', 'Name', 'Ticket' 칼럼 삭제
titanic.drop(['PassengerId', 'Name', 'Ticket'], axis = 1, inplace = True)
titanic[:5]
#학습 데이터 세트(피처와 레이블) 생성
features = X = titanic.iloc[:, 1:]
#labels = y = titanic.Survived #Series 형태, 다른표현 : titanic.iloc[:, :1]
labels = y = titanic.iloc[:, :1]
#테스트 데이터 세트 추출 (크기 : 20%)
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size = 0.2, random_state = 11)
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
dt_clf = DecisionTreeClassifier()
rf_clf = RandomForestClassifier()
lr_clf = LogisticRegression()
#DecisionTreeClassifier 의 학습/예측 평가
dt_clf.fit(X_train, y_train)
dt_pred = dt_clf.predict(X_test)
print("정확도: ", accuracy_score(y_test, dt_pred).round(4))
#RandomForestClassifier 의 학습/예측 평가
rf_clf.fit(X_train, y_train)
rf_pred = rf_clf.predict(X_test)
print("정확도: ", accuracy_score(y_test, rf_pred).round(4))
#LogisticRegression 의 학습/예측 평가
lr_clf.fit(X_train, y_train)
lr_pred = lr_clf.predict(X_test)
print("정확도: ", accuracy_score(y_test, lr_pred).round(4))
#features - 인덱스가 1,3,5번
features.iloc[[1,3,5], :]
test_index
features.iloc[test_index, :]
features.take(test_index)
#KFold 교차 검증
from sklearn.model_selection import KFold
dt_clf = DecisionTreeClassifier()
kfold = KFold(n_splits = 5)
scores = []
count = 0
#KFold 교차 검증 수행
for train_index, test_index in kfold.split(titanic):
#titanic 데이터에서 교차 검증별로 학습과 검증 데이터를 가리키는 index 생성
X_trian, X_test = features.values[train_index], features.values[test_index]
y_trian, y_test = labels.values[train_index], labels.values[test_index]
#X_trian, X_test = features.take(train_index), features.take(test_index)
#y_trian, y_test = labels.take(train_index), labels.take(test_index)
dt_clf.fit(X_train, y_train)
pred = dt_clf.predict(X_test)
acc = accuracy_score(y_test, pred)
scores.append(acc)
count += 1
print(f"{count}번째 개별 정확도: ", acc)
print(scores)
print("평균 정확도: ", np.mean(scores).round(4))
from sklearn.model_selection import cross_val_score
scores = cross_val_score(dt_clf, features, labels, cv = 5)
scores
print("평균 정확도: ", np.mean(scores).round(4))
파라미터 : max_depth, min_samples_split, min_samples_leaf / cv = 5
from sklearn.model_selection import GridSearchCV
dt_clf = DecisionTreeClassifier()
parameters = {'max_depth' : [2,3,5,10], 'min_samples_split' : [2,3,5], 'min_samples_leaf' : [1,5,8]}
grid_dclf = GridSearchCV(dt_clf, param_grid = parameters, scoring = 'accuracy', cv = 5)
grid_dclf.fit(X_train, y_train)
print("최적 하이퍼 파라미터: ", grid_dclf.best_params_)
print("최고 정확도: ", grid_dclf.best_score_.round(4))
best_dclf = grid_dclf.best_estimator_
#최적 하이퍼 파라미터로 학습된 Estimator로 예측 및 평가
dpred = best_dclf.predict(X_test)
accuracy = accuracy_score(y_test, dpred)
accuracy
참고 ppt : http://naver.me/5G5skN0k
참고 코드 : http://naver.me/G5QBlDkv
머신 러닝 모델은 여러가지 방법으로 예측 성능을 평가할 수 있으며,
'성능 평가 지표' 는 일반적으로 모델이 '분류'인지 '회귀'인지에 따라 여러 종류로 나뉜다
분류의 성능 평가 지표
정확도(Accuracy), 오차행렬(Confusion Matrix), 정밀도(Precision), 재현율(Recall), F1 스코어, ROC AUC
분류는 긍정/부정과 같은 2개의 결과값만을 가지는 '이진 분류' 와 여러 개의 결정 클래스 값을 가지는 '멀티 분류' 로 나뉠 수 있다
정확도는 실제 데이터에서 예측 데이터가 얼마나 같은지, 즉 예측값과 실제값이 얼마나 동일한지에 대한 비율을 말한다
직관적으로 모델 예측 성능을 나타낼 수 있는 지표이지만, 이진 분류의 경우 데이터의 구성에 따라 머신러닝 모델의 성능을 왜곡할 수 있으며 따라서 정확도 수치 하나만 가지고 성능을 평가하지 않는다
단순한 알고리즘으로 예측하더라도 데이터의 구성에 따라 정확도 결과가 높은 수치로 나올 수 있기 때문에 정확도를 평가 지표로 사용할 때는 매우 신중해야 한다
특히 불균형한 레이블 값 분포에서 머신러닝 모델의 성능을 판단할 경우, 정확도가 평가 지표로 사용되어서는 안되며, 이러한 한계점을 극복하기 위해 여러가지 분류 지표와 함께 적용하여 머신러닝 모델 성능을 평가해야 한다

이진 분류의 예측 오류가 얼마인지와 더불어 어떠한 유형의 예측 오류가 발생하고 있는지를 함께 나타내는 지표이다
※ 정밀도(Precision)
= True Positive / predicted positive
= TP / (TP + FP)
= a / (a+b)
예측이 positive 한 것의 개수 중 (a+b)
실제로 positive 한 것의 개수 (a)
질병이 있다고 예측한 것 중 실제 질병이 있는 경우
※ 재현율(Recall)
= True Positive / actually positive
= TP / (TP + FN)
= a / (a+c)
= True Positive Rate = 민감도(Sensitivity)
실제로 positive 한 것의 개수 중 (a+c)
positive로 예측한 것의 개수 (a)
실제 질병이 있는 경우, 실시한 검사에서 질병이 '있다'고 판정할 수 있는 능력
※ 특이도(Specificity)
= True Negative / actually negative
= TN / (FP + TN) = d / (b+d)
= True Negative Rate
실제로 negative 한 것의 개수 중 (b+d)
negative로 예측한 것의 개수 (d)
실제 질병이 없는 경우, 실시한 검사에서 질병이 없다고 판정할 수 있는 능력
※ FPR(False Positive Rate)
= 1 - Specificity
= FP / (FP + TN)
= b / (b+d)
오분류율 = (b+c) / (a+b+c+d)
정분류율(정확도) = 1 - 오분류율 = (a+d) / (a+b+c+d)
(정확도는 오차행렬에서 True에 해당하는 값인 TN과 TP에 좌우된다)
정확도는 분류 모델의 성능을 측정할 수 있는 '한 가지 요소' 일 뿐이다
불균형한 데이터 세트에서 정확도 만으로는 모델 신뢰도가 떨어질 수 있으며,
정확도보다 더 선호되는 평가 지표인 정밀도(Precision)와 재현율(Recall)이 있다
정밀도와 재현율은 Positive 데이터 세트의 예측 성능에 좀 더 초점을 맞춘 평가 지표 이다
※ 정밀도(Precision) = TP / (TP + FP)
예측을 Positive로 한 대상 중에 예측과 실제 값이 Positive로 일치한 데이터의 비율
질병이 있다고 예측한 것 중 실제 질병이 있는 경우
※ 재현율(Recall) = TP / (TP + FN)
실제 값이 Positive인 대상 중에 예측과 실제 값이 Positive로 일치한 데이터의 비율
실제 질병이 있는 경우, 실시한 검사에서 질병이 '있다'고 판정할 수 있는 능력
정밀도와 재현율 지표는 이진 분류 모델의 업무 특성에 따라서 둘 중 하나의 지표가 더 중요하게 간주될 수도 있다
재현율이 더 중요한 지표가 되는 경우 -> 실제 Positive(양성)인 데이터를 Negative로 잘못 판단하면 안되는 경우 (ex. 암 판단 모델, 보험사기 및 금융사기 적발 모델 등)
정밀도가 더 중요한 지표가 되는 경우 -> 실제 Negative(음성)인 데이터를 Positive로 잘못 판단하면 안되는 경우 (ex. 스팸 메일 여부 판단 등)
정밀도 또는 재현율이 특별히 강조되어야 하는 경우, 분류의 결정 임계값(Threshold) 을 조정해 정밀도 또는 재현율의 수치를 높일 수 있다
하지만 정밀도와 재현율은 상호 보완적인 평가 지표이므로, 어느 한쪽을 강제로 높이면 다른 하나는 떨어지기 쉽다
일반적으로 이진 분류에서는 임계값을 0.5 (50%) 로 정하고, 이 기준값보다 확률이 크면 positive, 작으면 negative로 결정한다
분류 결정 임계값은 positive 예측값을 결정하는 확률의 기준이 된다
임계값을 0.4로 낮추면, positive일 확률을 0.5가 아닌 0.4부터 예측을 한다
즉, 임계값이 낮아질수록 positive로 예측할 확률이 높아져 재현율이 증가한다
재현율이 높아질수록, 정밀도는 낮아진다
반대로 임계값이 증가할수록 재현율 값은 낮아지고 정밀도는 높아진다
※ 정밀도가 100% 가 되는 방법 -> FP = 0
※ 재현율이 100% 가 되는 방법 -> FN = 0
재현율과 정밀도 모두 동일하게 TP를 높이는 데 초점을 맞추지만,
재현율은 FN를 낮추는 데, 정밀도는 FP를 낮추는 데 초점을 맞춘다
(재현율의 FN과, 정밀도의 FP가 '0'에 가까워 질수록 100%에 가까워지기 때문)
사이킷런은 개별 데이터별로 예측 확률을 반환하는 메서드인 predict_proba() 를 제공한다
predict_proba() 메서드는 피처 레코드의 개별 클래스 예측 확률을 반환한다
predict() 메서드와 유사하지만 반환 결과가 예측 값이 아닌 '예측 확률 결과' 이다
predict_proba() 를 수행해 반환되는 ndarray 는 첫번째 칼럼이 클래스 값 0에 대한 예측 확률, 두번째 칼럼이 클래스 값 1에 대한 예측 확률이다
정밀도와 재현율을 결합한 지표
F1 스코어는 정밀도와 재현율이 어느 한쪽으로 치우치지 않는 수치를 나타낼 때 상대적으로 높은 값을 가진다
F1
= 2 / (1/recall + 1/precision)
= 2 {(precision recall) / (precision + recall)}
ROC 곡선은 FPR(False Positive Rate)이 변할 때 TPR(True Positive Rate)이 어떻게 변하는지를 나타내는 곡선이다 (x = FPR, y = TPR)
※ TPR
= 재현율 또는 민감도
= TP / (TP + FN)
=실제값 Positive가 정확히 예측되어야 하는 수준을 나타냄
= 질병이 있는 사람은 질병이 있으므로 양성 판정
※ TNR
= 특이성
= TN / (TN + FP)
= 실제값 Negative가 정확히 예측되어야 하는 수준을 나타냄
= 질병이 없는 건강한 사람은 질병이 없으므로 음성 판정
※ FPR
= FP / (FP + TN)
= 1 - TNR
= 1 - 특이성
FPR 값을 0으로 만들려면 :
임계값 = 1 로 지정 -> 아예 positive로 예측하지 X -> FP값 = 0 -> 자연스럽게 FPR = 0
FPR 값을 1으로 만들려면 :
임계값 = 0 로 지정 -> 다 positive로 예측 -> TN값 = 0 -> FPR = 1
임계값을 1부터 0까지 변화시키면서 FPR 을 구하고, 이 FPR 값의 변화에 따른 TPR 값을 구하는 것이 ROC 곡선이다
ROC 곡선 자체는 FPR과 TPR의 변화 값을 보는 데에 이용하며, 분류의 성능 지표로 사용되는 것은 ROC 곡선 면적에 기반한 AUC 값으로 결정한다
AUC 값은 ROC 곡선 밑의 면적을 구한 것으로서, 일반적으로 '1'에 가까울 수록 좋은 수치이다
AUC 값이 커지려면 FPR이 작은 상태에서 얼마나 큰 TPR을 얻을 수 있느냐가 관건이다
가운데 직선(AUC = 0.5) 에서 멀어지고, 왼쪽 상단 모서리 쪽으로 가파르게 곡선이 이동할수록 '직사각형에 가까운 곡선' 이 되어 면적이 1에 가까워지는 좋은 ROC AUC 성능 수치를 얻게 된다
y_test
pred
accuracy_score(y_test, pred)
from sklearn.metrics import confusion_matrix, accuracy_score, precision_score, recall_score, f1_score
#오차 행렬 -> 첨부된 이미지와 다르게 TP와 TN의 위치가 뒤바뀌어 나타난다
confusion_matrix(y_test, pred)
#정분류율
(97 + 47) / (97 + 47 + 18 + 16)
#정밀도
Precision = 47 / (47 + 18)
Precision
precision_score(y_test, pred)
#재현율
recall = 47 / (47 + 16)
recall
recall_score(y_test, pred)
def get_clf_eval(y_test, pred):
confusion = confusion_matrix(y_test, pred)
precision = precision_score(y_test, pred)
recall = recall_score(y_test, pred)
f1 = f1_score(y_test, pred)
print(confusion)
print()
print(f" 정확도: {precision:.4f} \n 재현율: {recall:.4f} \n f1_스코어: {f1:.4f}")
get_clf_eval(y_test, pred)