데이터셋의 목적
✅ 수백/수천개의 피처 다루는 방법
=> describe(기술통계), nunique(유일 값 빈도수), skew(왜도), kurt(첨도), mean(평균), deviation(편차)
✅ 피처가 너무 많을 때 => describe(기술통계)
어느 한쪽에 너무 치우쳐진 값이나 대부분 같은 값으로 되어있는 데이터 찾기
✅ 계산량을 줄이기 위해 의미없는 데이터를 제거
✅ Tree 계열 알고리즘 중에 사이킷런 외에 라이브러리의 알고리즘 익혀보는 목적
✅ 모델 평가 방법 ( Validation)
Hold-out-Validation | Cross-Validation |
데이터 개수 충분 but 크기 작으면 부정확 |
모델의 일반화 성능 파악할 때 |
대용량 데이터셋, 빠르게 (모델) 성능 평가, 비용 ▼ | 작은 데이터셋, 정확하게 (모델) 성능 평가, 비용 ▲ |
(CV에 비해) 신뢰도 ▼ | 신뢰도 ▲ |
✅ XGBoost
✅ LightGBM
✅ CatBoost
데이터 미리보기 & 전처리
👨💼 Benz-manufacturing 데이터 미리보기
📝 데이터가 익명화
1) 변수가 많다
2) 0으로 된 희소값이 많아 밀도가 낮은 값이 보입니다
3) 이미 인코딩이 되어있는 값?
4) 앞쪽은 문자열 데이터, 뒷쪽은 숫자
📝 Test 데이터와 Train 데이터 1:1
=> 행 개수 동일
=> Index 겹치지 않는지 확인하는 방법 2가지
1) pd.concat
#1 train데이터셋과 test 데이터셋 각각 to_frame()으로 데이터프레임 형태로 생성
#2 두 데이터셋 concat(ignore_index=True 하여 인덱스 재생성)
#3 ID 컬럼에 대해 유일 값 빈도수 확인
pd.concat([train.index.to_frame(), test.index.to_frame()], ignore_index=True).ID.nunique()
2) len(set())
#1 train 데이터셋과 test 데이터셋에 set 취해주기(중복값이 있다면 없어짐)
#2 집합된 데이터셋의 차집합 구하기 (겹치는 게 없다면 길이 그대로)
#3 len 확인
len(train.index), len(test.index)
4209 4209
len(set(train.index) - set(test.index))
4209
len(set(test.index) - set(train.index))
4209
📝 Train데이터셋의 유일값 빈도수(nunique)의 기술통계(describe)
📝 Test데이터셋의 유일값 빈도수(nunique)의 기술통계(describe)
📌 max 값이 차이나는 이유
=> test 데이터셋에는 정답 값( y 컬럼 ) 이 제외되었기 때문
=> train 데이터셋의 max : 2545 => y컬럼에 겹치는 값 굉장히 적음. 유니크한 값 2545 개
📝 Train데이터셋(y컬럼 제외)의 유일값 빈도수(nunique)의 기술통계(describe)
=> 수치데이터, 범주데이터 구분 없이 그냥 유일값만!
=> 75% 이상의 값이 대부분 Binary값인 걸 확인
=> min = 1이 있는 것으로 보아 단일 값으로 이루어져 있는 컬럼(변수) 존재
=> max = 47 인것으로 보아 유일값의 개수가 가장 많은 컬럼(변수) 은 47개 유일값 존재
📝 범주형 데이터 확인
# 범주형 데이터 기술통계 확인
#1 train.select_dtypes(include='O').describe()
#2 train.describe(include='O')
=> 범주형 데이터 기술통계를 확인해 피쳐별 특징 확인
→ X4 컬럼의 경우, 유일값이 4개이고, 4209개의 값 중에서 freq이 4205이다. (4개 빼고 다 같은 값)
✅ X4는 대부분의 값이 d로 되어 있음
✅ b, c 값은 각각 1개씩 있는데 개수가 적어 제대로 학습되지 않을수도 있음
✅ 사용할것인지 말것인지는 도메인 지식 활용해야하는데 여기서는 도메인 정보 익명화
📝 수치형 데이터 확인
# 수치형 데이터 기술통계 확인
#1 train.describe(include='number')
#2 train.select_dtypes(include='number').describe()
=> 수치형 데이터의 기술통계를 구하고, 그 기술통계의 기술통계를 통해 경향성을 파악하였습니다.
→ min이 0이고 max가 1
→ 이미 스케일링이 되어있다
✅ 전체 행렬의 행<==>열 전환을 통해 각 변수의 기술통계 볼 수 있음
✅ 어떤 기술통계는 눈에 보이지만 368개의 통계 모두 꼼꼼히 보기 시간 부족 or 리소스 부족
✅ 수백/ 수천개의 변수에 대해 기술통계 구했다면 기술통계 한 번 더 구해볼 수 있음
💡 기술통계의 기술통계 ( 더블 디스크라이빙 )
train.drop(columns="y").describe().T.describe()
✅ 행의 mean 0.157672 => 수치 데이터 기술통계에 대한 전반적 평균
✅ 행의 min => 모든 변수에 대한 기술통계의 min 값 전부 0
✅ 행의 max =>모든 변수에 대한 기술통계의 max 값의 1사분위수 이상의 값(25%이상)이 전부 1
✅ min, max 둘다 0이라면 같은 값 들어있는 변수도 있을 것임
💡수치데이터의 유일값 개수의 기술통계
📝 왜도(skew)와 첨도(kurt)
# 수치변수에 대한 왜도 & 첨도
train.drop(columns="y").select_dtypes(exclude="O").agg(["skew", "kurt"]).T.describe()
=> 위 기술통계에서 nunique 값 1 or 2 인것 확인 ( =컬럼마다 유일값이 1개에서 2개)
=> 위 수치데이터 기술통계에서 값 0 or 1 ( =컬럼의 값 대부분 0 or 1 )
=> 값 한쪽으로 치우쳐져 있는지 확인하기 위해
=> 비대칭도가 큰 ( skew > 50 ) 컬럼에 대해 히스토그램 그리기
plt.figure(figsize=(16,20))
train_skew = abs(train.drop(columns="y").select_dtypes(exclude="O").skew())
train[train_skew[train_skew > 50].index].hist();
값이 0쪽으로 치우쳐져 있음
📝 데이터 전처리
1) 2진 변수중 대부분 같은 값으로 구성되어 있는 컬럼 구하기
bi_unique_col = train[train_skew[train_skew > 50].index].nunique().index
2) 모두 같은 값으로 구성되어 있는 컬럼 구하기
# 이런 방법이 아직도 익숙치가 않다...
uniq_one = train.nunique() == 1
uniq_one_cols = uniq_one[uniq_one].index
uniq_one_cols
display(train[uniq_one_cols].head(2))
3) 구한 컬럼들 합치기
# list(set()) 을 해주는 이유는 중복이 없기는 하지만 혹시라도 중복이 있을 때 제거
remove_col = list(set(uniq_one_cols.tolist() + bi_unique_col.tolist()))
remove_col[:5]
4) 합친 컬럼들 제거하기
# 모두 같은 값으로 되어 있는 변수 제거하기
train_remove_col = train.drop(columns=remove_col).copy()
test_remove_col = test.drop(columns=remove_col).copy()
📝 category type
문자열처럼 보이고 작동하지만 내부적으로는 정수의 배열로 표현됩니다.
=> 이를 통해 데이터를 사용자 지정 순서로 정렬하고 데이터를 보다 효율적으로 저장
=> lightGBM, CatBoost 에서는 범주형 피처를 인코딩 없이 사용할 수 있음
-> object type 변수들을 category type으로 바꿔주기
1) 범주형 변수 찾기
cat_col = train_remove_col.select_dtypes(include='O').columns.to_list()
2) 범주형 -> 카테고리형
# LightGBM, CatBoost 에서는 범주형 피처를 인코딩 없이 사용할 수 있습니다.
# 따로 범주형 피처를 지정해서 사용할 수 있습니다.
train_remove_col[cat_col] = train_remove_col[cat_col].astype('category')
test_remove_col[cat_col] = test_remove_col[cat_col].astype('category')
📌 Tip !
1) %ls
=> 현재 작업중인 파일의 디렉토리 목록 나열
2) !unzip
=> 현재 디렉토리 내에 위치한 zip 파일을 압축해제
👨💼 질문
1) - 질문
범주형을 인코딩해서 분류.
=> 수치형인 'y' 컬럼을 예측
XGBOOST 모델 중에서
Classfier가 아닌 Regressor를 사용하는 것?
1) - 답변
수치 데이터를 예측하는 것이기 때문에 회귀를 사용
+ 캐글에 있는 평가 지표를 보면 R Square Score => 해당 문제가 회귀 문제인것을 도출
2) - 질문
정규분포 형태가 왜 머신러닝의 학습에 도움이 되는지?
2) - 답변
어느 한쪽 값으로 치우쳐져 있다면 모델이 특징을 학습하기 어려움.
고루 분포가 되어 있다면 학습하기가 좀 더 나음
=> 우리도 분석 데이터가 너무 한쪽에 몰려있음 / 너무 뾰족하면 대부분 비슷해 보임. 특징을 찾기 어렵다
+ 챗 GPT 답변 📊
XGBoost
✅XGBoost
- 순차적으로 트리 생성 , 내부적으로는 병렬처리 -> 속도가 빠르다
- Bagging 모델에 비해 Overfitting 가능성.
✅XGBoost의 장점
- GBM 대비 빠른 수행시간
- 병렬 처리로 학습, 분류 속도가 빠름
- 과적합 규제(Regularization)
- 표준 GBM 경우 과적합 규제기능이 없으나, XGBoost는 자체에 과적합 규제 기능으로 강한 내구성을 가진다.
- Early Stopping(조기 종료) 기능
- 다양한 옵션을 제공하며 Customizing이 용이하다.
✅ Bagging => 병렬트리를 여러 개 생성, 오버피팅에 좀 덜 취약합니다. => 랜덤포레스트, ExtraTree
✅ Boosting => 순차적으로 트리를 생성, 오버피팅에 좀 더 취약하며, 개별 트리의 성능이 중요할 때 사용합니다. => GBM, XGBoost, LightGBM, CatBoost 등
LightGBM
✅ LightGBM 이란?
- XGBoost에 비해 훈련 시간이 짧고 성능도 좋아 부스팅 알고리즘에서 주목을 받고 있다.
- GradientBoosting을 발전시킨 것이 XGBoost, 여기서 속도를 더 높인 것이 LightGBM이다.
- 트리 기준 분할이 아닌 리프 기준 (leaf wise tree) 분할 방식을 사용한다.
- 학습에 소요되는 시간이 짧고 메모리 사용량도 절약할 수 있어 대용량 데이터 처리가 가능하다.
- 적은 데이터셋에서 과적합 발생 우려가 있다.
✅ LightGBM 핵심 알고리즘
✨ GOSS : Gradient based One Side Sampling
- 기울기 기반 단측 표본 추출법
-> 행을 줄임
-> “모델의 학습에 많은 도움이 되는 샘플” 모두 학습에 사용하고, "학습에 별 도움이 안 되는 샘플”은 일부만 학습에 사용.
-> 오답 위주로 샘플 구성 . 트리 시각화 하면 한쪽방향으로 만들어짐
✨ EFB : Exclusive Feature Bundling
- 변수 개수를 줄여 차원을 효과적으로 감소
-> 열을 줄임
-> 트리의 가지를 뻗어나가면서 사용되는 feature의 가짓수를 줄여 트리가 overfitting되는 것을 방지한다.
-> 인코딩이 되어있는 데이터는 밀도가 낮습니다. 그래서 낮은 밀도의 데이터끼리 합칠 수 있는 것은 합칩니다. 예를 들어 바이너리 값인 연장자 여부를 주니어, 시니어 각각 인코딩했다면 불필요한 인코딩이 됩니다. 서로 배타적인 특징을 갖습니다. 이런 피처를 합쳐서 사용하는 것이 EFB 기법입니다. 알고리즘 내부에서 서로 배타적인 특징을 갖는 피처를 찾아 합칩니다.
=> 행(틀린 문제 위주로 샘플링)과 열을 줄여서 학습시간을 더 빠르게