22021110
23일차
오늘 포스팅할 내용은 DecisionTree, 결정트리이다.
불러온 데이터는 kaggle의 Salary Prediction Classification (급여 예측 분류) 이다.
간단한 데이터세트 정보이다.
DecisionTree, 결정트리?
💡사전적 의미
의사 결정 규칙과 그 결과들을 트리 구조로 도식화한 의사 결정 지원 도구의 일종.
쉽게 풀이하자면,
분류해서 정리되는 과정이다.
이사를 예로 들면 좋을것 같은데
이사는 보통 현재 집의 물건들을 모두 패키징해서
새로운 집에 다시 정리하는 과정인데
이 과정이 사실 결정트리와 같다고 생각한다.
기존 집의 모든 나의 물건들을
새로운 집에 정리할 때 가장 먼저 하는 분류는 무었인가?
바로 위치이다.
거실이야? 안방이야? 주방이야? 화장실이야? 방1이야? 방2야?
거실이면 여기, 안방이면 저기, ....
안방에서도 옷이면 여기.
가전제품이면 여기.
책이면 여기.
이렇게 특정 기준(질문)에 따라 데이터가 구분되고 다음 행동을 하는 모델을
DecisionTree, 결정트리라고 한다.
따라서 맨 위(Root Node)에서부터 맨 아래(Terminal Node,Leaf Node)까지 도달하는 과정이
나무를 뒤집어 놓은 모양과 닮았다 하여 트리라는 단어가 붙는다.
💡
노드(Node) : 결정 트리에서 질문이나 정답을 담은 네모 상자
Root Node : 처음 분류 기준 (즉, 첫 질문)
Terminal Node or Leaf Node : 마지막 노드
이제 데이터를 불러오자.
.info()로 데이터 타입을 확인해 보니
결측치가 존재하며, 데이터 타입도 object(범주형 변수)와 int(연속형 변수)가 섞여 있는것을 확인했다.
.describe()로 확인해보니
연속형 변수는 위의 주석과 같은 컬럼들이 있었고
.describe(include=['O'])로 확인해서
범주형 변수 또한 주석과 같은 컬럼들이 존재한다는것을 인지했다.
그럼 이제 범주형 변수부터 전처리 해보자.
우리가 분류하고자 하는 기준 'class'컬럼은
현재 <=50K, >50K로 데이터가 저장되어있기에
<=50K는 0으로
>50K는 1로 변환하여 저장하자.
위와 같이 .map({'<=50K': 0, '>50K': 1})를 사용해
바꿔 주었다.
새로운 리스트 obj_list를 만들고
반복문과 리스트 컴프리핸션을 통해 남은 object타입의 컬럼명을 뽑는 코드이다.
이제 만든 obj_list에 들어있는 컬럼명들을
순서대로 컬럼명과 해당 컬럼의 nunique()를 출력하는 반복문이다.
위의 출력을 보고 우리는 결정을 해야한다.
연속형 변수라면 values의 평균이나 최빈값을 넣어줄 수 있지만
범주형 변수이기 때문에 힘들고
drop을 하는 방법도 있고
전부다 .get_dummies로 처리할 수 있다.
하지만 결정을 하는데 모든 colume의 기준들이 필요하지 않기 때문에
시간상 values의 nunique의 개수가 10개 이상인 column들만 전처리 하기로 결정했다.
그래서 위와 같은 반복문을 짜서
nunique의 개수가 10개 이상인 column들만 출력했다.
'education'컬럼에 .value_counts() 하니위에서 보았던 16개의 종류가 나왔다.
이를 어찌 처리해야하나 고민하다가'education-num' 컬럼과 매칭이 되지 않을까란 생각이 들었다.
그래서 잠시 'education-num' 컬럼을 불러와서 출력해보고
위와 같이
반복문을 통해 두개의 컬럼들 모두 16개의 values를 가지고 있기에
range(1,17)을 잡고
f스트링 뒤의 코드를 해석하자면
df[df['education-num'] == n]['education'].unique()
# 잘라서 보면 이해 하기 쉽다.
❗ n =1 이 들어왔을 때
➡️ 'education-num'컬럼의 value가 1인 전체 df 데이터 출력
2. print( df[df['education-num'] == 1]['education'] )
➡️ 'education-num'컬럼의 value가 1인 'education' 컬럼의 value 출력
3. print( df[df['education-num'] == 1]['education'].unique() )
➡️ 'education-num'컬럼의 value가 1인 'education' 컬럼의 value 의 종류 출력
결론 n=1~16일때 'education-num'컬럼의 value가 1~16인 'education' 컬럼의 value 의 종류 출력
각각의 'education-num'의 value들은 'education'을 하나 씩 배정 받았다 확인.
이제 'education-num' 과 'education'의 관계를 알았으니
'education'컬럼은 삭제(.drop())해 주자.
'occupation' 컬럼의 경우
직업이라는 특성이 있고 이미 잘 묶여 있어서 패스했다.
'native-country' 컬럼의 경우
미국이 가장 많았다.
여기서도 여러 선택지가 있었지만
나라별 연봉 평균 으로 바꾸기로 했다.
.groupby를 통해
나라별 연봉 평균을 구하고
.sort_values(ascending=False)를 넣어
순위 확인을 위해 정리했다.
그럼 이제 이 데이터를 원래 df에 합쳐보자.
country_group 변수에위에서 구한 데이터를 저장하고
이 데이터의 인덱스를 확인했더니 원본 df의 인덱스와 다르다.
.reset_index()를 해서 다시 저장해준다.
❗원본 데이터의 index를 함부로 손대면 안되는 이유, index 통일의 중요성
.merge를 통해 원본 df와 country_group을 합쳐준다.
country_group
뭐와 합칠거야? = country_group
on = 'native-country'
기준이 뭐야? = 컬럼 'native-country'
❗ on이 안들어가면 on=none이므로 두 데이터의 공통 열이름(id)을 기준으로 inner(교집합) 조인하게 된다.
how='left'
어떻게 합칠건데? = country_gorup의 고유값을 기준으로
그럼 이제 'country_class_mean' 컬럼도 없애주자
위의 class_x와 class_y는
merge당시 각 데이터 프레임의 class컬럼이 이름은 같지만
value들은 달라서 구분해서 합쳐진건데
이 또한 컬럼명을 바꿔서 구분을 해주도록 하자.
이제 범주형 데이터의 결.측.치를 처리해보자.
현재 'workclass' , 'occupation', 'native-country' 에 결측치가 존재하는것을 확인 할 수 있다.
평균이 가장 적었던 'native-country' 컬럼에는
임의의 값 99를 넣어 결측치 처리를 해주었다.
'workclass'컬럼의 경우 values의 평균을 구해 가장 높은
Private로 결측치를 채워줬다.
'occupation' 컬럼의 경우
정말 손댈 이유가 전 혀 없기에
결측치를 Unknown으로 채워 줬다.
마지막으로 결측치 확인을 다시하고
범주형 데이터의 전처리가 모두 끝이 났다는것을 확인했다.
이제 정리한 범주형 데이터들을
get_dummies를 활용해 연속형 데이터로 바꿔준다.
훈련셋과 시험셋을 분리해주고
사이키런.tree 라이브러리에서 결정트리(DecisionTreeClassifier)모델을 임포트 해주고
훈련시키고 예측하고 정확도 확인까지 한 과정이다.
결정트리 알고리즘은
나무를 뒤집어 놓은 모양으로 뻗어나가는데,
위의 출력과 같이 train score가 학습이 너무 잘돼test score보다 정확도가 높은것을 알 수 있다.이를 과최적화(오버피팅)라고 한다.
이러한 과최적화(오버피팅)을 방지하기 위해 우리는
깊이(depth)를 튜닝해서 최적의 깊이를 구해야 한다.
위의 데이터는 깊이가 2일때
가장 train score와 test score가 정확도의 차이가 나지 않기에
가장 적합하다고 할 수 있다.
좀 더 육안으로 이해하기 쉽게
시각화해보자.
앞서 말해왔던
결정트리 모델을 시각화한 결과이다.
나무를 뒤집어 놓은 모양으로 생긴것을 확인할 수 있으며
깊이를 3으로 하면
시작부터 각각 총 3번의 갈림길(Node)에서 선택을 했다는 것을 알 수 있다.
💡 gini? 불순도(Impurity) - 지니계수(Gini Index)?
쉽게 설명하면 불순도를 측정해서 값으로 보여주는것이다.
즉, 이 데이터를 어떤 기준으로 분류했을때 동일한 객체들로만 잘 모아줄까를 고려해서나눠야 하는데
gini계수는 현재 node에 불순도를 측정해서 얼마나 잘 걸러졌는지 수치로 표현한 것이다.
= 현재 노드에 있는 데이터들이 동일한 객체 비율 대비 동일하지 않고 따로 노는 객체 비율
따라서 가지가 쳐질수록 gini계수가 0으로 가까워 진다면
그 클래스에 속한 불순도가 낮으므로 좋다는 뜻이다.
'Hello MLop > ML' 카테고리의 다른 글
MLop_ML_XGBoost_커플 성사 여부 예측 (0) | 2022.11.17 |
---|---|
MLop_ML_RandomForest_중고차 가격 예측 (0) | 2022.11.15 |
MLop_ML_NaiveBayes_SMS 스팸 수집 (0) | 2022.11.12 |
MLop_ML_KNN_WineData (0) | 2022.11.10 |
MLop_ML_로지스틱회귀_타이타닉 생존자 예측 (0) | 2022.11.09 |