도찐개찐

[머신러닝] 10. 엔트로피 본문

PYTHON/데이터분석

[머신러닝] 10. 엔트로피

도개진 2023. 1. 3. 10:29

엔트로피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)
728x90
Comments