❤️ 배운 것
2023-10-13 Decision Tree Algorithm with IGR
빈 데이터 채우기
h1_slope 노드는 flat, moderate, steep 3가지로 구분이 되어야 하는데
다른 종류는 모두 인스턴스 데이터가 있지만,
moderate에 해당하는 인스턴스 데이터가 없음
이 경우에는 기존 상위 노드에 chapparal이 2개, conifer가 1개가 있으니까
가장 많은 데이터인 chapparal을 선택하여 채움
(moderate가 나왔을 때도 분류를 해야하기 때문에)
-> 일단 다수데이터로 분류되도록 하는 것임
Information Gain Ratio
information gain을 기준으로 분기용 피처를 선정할 경우
최적화가 아닌데, 잘게 쪼개어져서 I.G가 높게 나오는 경우를 선택하는 한계점이 있음
Information Gain Ratio = IG / IV
IV란 target 대신 feature 기준으로 entropy를 구한 값
ex)
with whom으로 자르면
t1~ t8 : 1개
t9 : 2개
def get_iv():
probs = [1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 2/10]
probs = np.array(probs)
entropy = -np.sum(probs * np.log2(probs))
print(entropy)
# 3.4541209043760985
어떤 metric을 사용하는 지에 따라 decision tree 모양도 달라지고,
예측값도 달라진다.
metric은 Information Gain, Information Gain Ratio 등..
Gini index
$$
Gini(t, D) = 1 - \sum_{l=levels(t)}P(t=l)^2
$$
IGR 기준 decision Tree
def entropy(p: list):
tot = sum(p)
p = np.array(p).astype(dtype='float64')
p /= tot
entropy = -np.sum(p * np.log2(p))
return entropy
def information_gain(parent, child):
parent_entropy = entropy(parent)
l_parent = float(sum(parent))
partition_entropy = []
for ele in child:
l_child = float(sum(ele))
part_ent = entropy(ele)
curr_ent = l_child / l_parent * part_ent
partition_entropy.append(curr_ent)
final_entropy = sum(partition_entropy)
ig = parent_entropy - final_entropy
return ig
def get_igr(parent, child):
ig = information_gain(parent=parent, child=child)
child_all = [sum(x) for x in child]
iv = entropy(child_all)
igr = ig / iv
return igr
def get_igr_idx(X, y, col_names):
ig_list = list()
h_list = list()
parent_uniques, parent_cnts = np.unique(y, return_counts=True)
for i in range(X.shape[1]):
curr = X[:, i]
uq = np.unique(curr)
children = list()
for ele in uq:
ele_idx = (curr == ele)
curr_y = y[ele_idx]
uniq, cnts = np.unique(curr_y, return_counts=True)
# child = [[6], [1, 3]]
children.append(cnts)
e = information_gain(parent=parent_cnts, child=children)
ig_list.append(e)
# get iv by features
for i in range(X.shape[1]):
curr = X[:, i]
uniques, cnts = np.unique(curr, return_counts=True)
curr_entropy = entropy(cnts)
h_list.append(curr_entropy)
gr_list = np.array(ig_list) / np.array(h_list)
print("col: ", col_names)
print("gr: ", gr_list)
max_idx = np.argmax(gr_list)
return max_idx
def decision_tree_by_igr(data, col_names):
X = data[:, 1:-1]
y = data[:, -1]
col_names = col_names[1:-1]
# root node separation
max_idx = get_igr_idx(X, y, col_names)
print(f"h1 node: idx {max_idx} {col_names[max_idx]}")
# flat-fin, moderate-fin, steep-3types
print("=" * 30)
# data filtration by slope - steep
to_remain = (X[:, max_idx] == 'steep')
X1 = X[to_remain]
X1 = np.delete(X1, max_idx, axis=1)
y1 = y[to_remain]
col_names.pop(max_idx)
# h1 separation
max_idx = get_igr_idx(X1, y1, col_names)
print(f"h2 node: idx {max_idx} {col_names[max_idx]}")
# low-filled with chapparal, medium-2types, high-fin, highest-fin
print("=" * 30)
# data filtration by elevation - medium
to_remain = (X1[:, max_idx] == 'medium')
X2 = X1[to_remain]
X2 = np.delete(X2, max_idx, axis=1)
y2 = y1[to_remain]
col_names.pop(max_idx)
# h2 separation
max_idx = get_igr_idx(X2, y2, col_names)
print(f"h3 node: idx {max_idx} {col_names[max_idx]}")
def main_routine():
df = pd.read_csv('../data/vegetation.csv')
col_names = df.columns.to_list()
data = df.to_numpy()
decision_tree_by_igr(data, col_names)
if __name__ == '__main__':
main_routine()
코드 기전
main_routine(): 메인 루틴, csv 데이터를 읽어서 decision tree를 계산하는 코드 실행
decision_tree_by_igr(data, col_names): information gain ratio를 기준으로 의사결정나무를 계산하는 기능
루트 노드 계산 -> h1노드 계산 -> h2노드 계산
get_igr_idx(X, y, col_names): 피처데이터 X와 타겟 y으로 information gain ratio를 계산, igr 최댓값의 index를 리턴
ig list와 h list를 구하여 나눔
information_gain(parent, child): parent와 child로 information gain을 구하는 기능
entropy(p: list): 단일 entropy를 구하는 기능
ID STREAM SLOPE ELEVATION VEGETATION
0 1 False steep high chapparal
1 2 True moderate low riparian
2 3 True steep medium riparian
3 4 False steep medium chapparal
4 5 False flat high conifer
5 6 True steep highest conifer
6 7 True steep high chapparal
col: ['STREAM', 'SLOPE', 'ELEVATION']
gr: [0.31054583 0.50260164 0.47622714]
h1 node: idx 1 SLOPE
==============================
col: ['STREAM', 'ELEVATION']
gr: [0.43253807 0.63797403]
h2 node: idx 1 ELEVATION
==============================
col: ['STREAM']
gr: [1.]
h3 node: idx 0 STREAM
Process finished with exit code 0
DATASET
ID | STREAM | SLOPE | ELEVATION | VEGETATION |
1 | FALSE | steep | high | chapparal |
2 | TRUE | moderate | low | riparian |
3 | TRUE | steep | medium | riparian |
4 | FALSE | steep | medium | chapparal |
5 | FALSE | flat | high | conifer |
6 | TRUE | steep | highest | conifer |
7 | TRUE | steep | high | chapparal |
IGR Metric Decision Tree
💛 배운점/느낀점
- 여러 계산이 섞인 IGR을 수학적으로 이해하고, 코드로 구현해내는 과정이 시간이 많이 소요되었지만 의미있는 훈련이었다.
- 스크립트식으로 코드를 작성하지 않고, 시간 안에 최대한 가능한 만큼 함수화하여 코드를 작성해보면서 머신러닝적 사고방식 및 코딩을 연습하는 계기가 되었다.
- 엑셀 피벗테이블로 데이터를 filtration하여 직접 diagram까지 그려보니 데이터 분기를 확실하게 확인할 수 있었다.
'Education > 새싹 TIL' 카테고리의 다른 글
새싹 AI데이터엔지니어 핀테커스 7주차 (화) - Bayes Theorem 개념 (0) | 2023.10.17 |
---|---|
새싹 AI데이터엔지니어 핀테커스 7주차 (월) - Decision Tree with Continuous Values (1) | 2023.10.17 |
새싹 AI데이터엔지니어 핀테커스 6주차 (목) - Kmeans, Decision Tree 해부 (진짜열심히했음) (0) | 2023.10.12 |
새싹 AI데이터엔지니어 핀테커스 6주차 (수) - KNN(full code) (1) | 2023.10.11 |
새싹 AI데이터엔지니어 핀테커스 6주차 (화) - KNN (1) | 2023.10.10 |