엔트로피entropy
물리 열역학의 관점에서의 정의
물질의 열적 상태를 나타내는 물리량의 하나
보통 무질서도라고 함
엔트로피가 높으면 무질서도 증가
통계적 관점에서의 정의
정보이득information gain의 혼잡도
엔트로피가 높으면 정보이해가 어려워 짐
학습데이터는 기본적으로 혼잡한 상태 임
따라서, 어떤 조건으로 분류해야만 전체 혼잡도가 개선되는지 계산
정리한 결과에 대해 다시 계산해서 처리를 반복 적용함
즉, 정보의 불확실성을 수치로 나타낸 것을 의미
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
from sklearn.metrics import recall_score
from sklearn.metrics import precision_score
from sklearn.metrics import roc_curve
from sklearn.metrics import roc_auc_score
import pydotplus
from sklearn import tree
엔트로피의 식
$ entropy = -\sum p_k \log_2 p_k $
복수의 현상(1~n)이 존재할때 그 혼잡도를 나타내는 엔트로피의 식
-p(현상1) * log(p(현상1)) + -p(현상2) * log(p(현상2)) + ... ... -p(현상n) * log(p(현상n))
참고) 엔트로피는 일반적으로 2를 밑으로 하는 로그로 계산함
# x를 기준으로 y를 나누는 가장 좋은 방법은?
# x = [1,2,3,4,5,6,7,8]
# y = [0,0,0,1,1,1,1,1]
# 방법1) x : 3.5 (최적의 조건)
# 방법2) x : 4.5 (오분류의 가능성 존재)
# ex) 확률 0.1의 현상이 10개 일어난 경우 엔트로피는?
# -p(현상1) * log(p(현상1))
import math
# -0.1 * math.log2(0.1) # 0.332
-0.1 * math.log2(0.1) * 10 # 3.321
3.3219280948873626
# ex) 확률 0.25의 현상이 4개 일어난 경우 엔트로피는?
-0.25 * math.log2(0.25) * 4
2.0
10마리의 동물이 개인지 고양이인지 분류
# big follow walking class
# yes yes yes dog
# yes yes no cat
# no yes yes dog
# yes yes yes dog
# no no yes cat
# yes no yes dog
# yes no yes cat
# no no no cat
# yes yes yes dog
# no yes no dog
1) target에 대한 entropy 계산
10마리 중 개는 6, 고양이는 4
개로 분류 될 확률 : 6 / 10
고양이로 분류 될 확률 : 4 / 10
-0.6 * math.log(0.6) - 0.4 * math.log2(0.4)
per = 6/10
per2 = 4/10
-per * math.log2(per) - per2 * math.log2(per2)
0.9709505944546686
1a) 덩치를 기준으로 분류시 엔트로피 계산
덩치 큰 여부로 분류 (6) - 개:고양이 4:2
덩치가 큰 경우 개로 분류 : 4/6 = 0.667
덩치가 큰 경우 고양이로 분류 : 2/6 = 0.333
-0.667 * math.log2(0.667)-0.333 * math.log2(0.333)
0.9179621399872384
1b) 덩치를 기준으로 분류시 엔트로피 계산
덩치 작은 여부로 분류 (6) - 개:고양이 2:2
덩치가 작은 경우 개로 분류 : 2/4 = 0.5
덩치가 작은 경우 고양이로 분류 : 2/4 = 0.5 -p(0.5) * log(p(0.5) * 2)
-0.5 * math.log2(0.5) * 2
1.0
1c) 덩치를 기준으로 분류시 최종 엔트로피 계산
덩치로 분류했을때의 엔트로피는
개로 분류될 확률 x 덩치로 분류될 확률과
고양이로 분류될 확률 x 덩치로 분류될 확률을
더해준 결과값이 됨
0.6 * 0.917 + 0.4 * 1.0
0.9502
2a) 따름을 기준으로 분류시 엔트로피 계산
따름으로 분류했을때의 엔트로피 (6) - 개:고양이 5:1
따를 경우 개로분류 : 5/6
따를 경우 고양이로 분류 : 1/6
-(5/6) * math.log2(5/6) -(1/6) * math.log2(1/6)
0.6500224216483541
2b) 따름을 기준으로 분류시 엔트로피 계산
안따름으로 분류했을때의 엔트로피 (4) - 개:고양이 1:3
안따를 경우 개로분류 : 1/4
안따를 경우 고양이로 분류 : 3/4
-(1/4) * math.log2(1/4) -(3/4) * math.log2(3/4)
0.8112781244591328
2c) 따름을 기준으로 분류시 최종 엔트로피 계산
0.6 * 0.650 + 0.4 * 0.811
0.7144
3a) 산책을 기준으로 분류시 엔트로피 계산
-(5/7) * math.log2(5/7) -(2/7) * math.log2(2/7)
0.863120568566631
3b) 산책을 기준으로 분류시 엔트로피 계산
-(1/3) * math.log2(1/3) -(2/3) * math.log2(2/3)
0.9182958340544896
3c) 산책을 기준으로 분류시 최종 엔트로피 계산
0.6 * 0.863 + 0.4 * 0.918
0.885
4) 중간 결론
덩치, 따름, 산책 여부에 따라 정보의 불확실 수치들을 비교
덩치 : 0.970 -> 0.9502
따름 : 0.970 -> 0.7144(!!!)
산책 여부 : 0.970 -> 0.8845
개/고양이 의사결정나무로 분류
catdog = pd.read_csv('../data/catdog.csv')
catdog
big
follow
walking
class
0
yes
yes
yes
dog
1
yes
yes
no
cat
2
no
yes
yes
dog
3
yes
yes
yes
dog
4
no
no
yes
cat
5
yes
no
yes
dog
6
yes
no
yes
cat
7
no
no
no
cat
8
yes
yes
yes
dog
9
no
yes
no
dog
# from sklearn.preprocessing import LabelEncoder
# encoder = LabelEncoder()
# catdog.big = encoder.fit_transform(catdog.big)
# catdog.follow = encoder.fit_transform(catdog.follow)
# catdog.walking = encoder.fit_transform(catdog.walking)
# catdog['class'] = encoder.fit_transform(catdog['class'])
# data = catdog.iloc[:, :3]
for c in catdog.columns:
catdog[c] = encoder.fit_transform(catdog[c])
# 범주형 변수를 레이블 인코딩 하기 2
# pd.Categorical(변수), 변수.cat.codes
for c in catdog.columns:
catdog[c] = pd.Categorical(catdog[c])
catdog[c] = catdog[c].cat.codes
catdog.head()
big
follow
walking
class
0
1
1
1
1
1
1
1
0
0
2
0
1
1
1
3
1
1
1
1
4
0
0
1
0
data = catdog.iloc[:, :3]
data
target = catdog['class']
X_train, X_test, y_train, y_test = train_test_split(data, target, train_size = 0.7,
stratify=target)
dtclf = DecisionTreeClassifier(criterion='entropy', max_depth=5) # 기본값은 gini 계수 > entropy 로 변환
dtclf.fit(X_train, y_train)
dtclf.score(X_train, y_train)
0.8571428571428571
pred = dtclf.predict(X_test)
accuracy_score(y_test, pred)
1.0
dot_data = tree.export_graphviz(dtclf, out_file=None,
feature_names=data.columns,
class_names=['cat', 'dog']
)
graph = pydotplus.graph_from_dot_data(dot_data)
graph.write_png('../img/catdog.png')
True
import matplotlib.image as pltimg
img = pltimg.imread('../img/catdog.png')
plt.figure(figsize=(12,8))
plt.imshow(img)
plt.axis('off')
plt.show()
scipy 패키지의 entropy 계산 함수
entropy(이벤트수, ...], base=로그밑수)
from scipy.stats import entropy
entropy([6,4], base=2)
0.9709505944546688
# 덩치로 분류 했을때 확률
# 덩치 클때
# 덩치 작을때
entropy([4,2], base=2), entropy([2,2], base=2)
(0.9182958340544894, 1.0)