주제
3차 프로젝트 3일차
신용등급의 지표 알아보기
- 일반적으로 상환이력 정보, 부채 수준, 신용거래기간, 신용형태 정보를 종합하여 산출
- 상환이력 : 빚을 기간 안에 갚았는지, 과거 채무상환을 미룬 적이 있는지 등의 연체 정보
- 부채 수준 : 대출의 규모 및 신용카드 이용금액 등의 현재의 채무보유 수준
- 신용 거래 기간 : 신용카드 및 대출 등의 거래기간
- 신용형태 정보 : 고금리 대출 이용 여부, 대출 거래기관 수 등
- 대출 심사 : 신용등급과 개인의 소득 및 재산, 재직 상태 등을 합산
피쳐 선정
- 데이터에서 사용할 수 있는 부분 :
- 연간 소득, 근로기간, 주택소유상태, 부채대비소득비율, 총계좌수, 최근2년간연체횟수, 총연체금액, 연체계좌수, 총상환원금, 총상환이자
- 연체금액과 연체계좌수는 상관계수는 0.01로 둘 다 사용 가능해보임
- 새로운 피쳐 생성 :
- 총상환원금비율 = 총상환원금 / 대출금액
- 총상환이자비율 = 총상환이자 / 대출금액
- 처음에는 관련 피쳐를 모두 넣어보고 특성 중요도를 확인하여 중요도가 적은 것부터 소거하며 반복적으로 학습-평가 진행 예정
오늘 한 일
1. EDA 및 데이터 전처리
- 범주형 데이터 시각화 후 주택소유상태가 ANY인 데이터가 1개 존재하는 것을 발견
- 확인 후 1개뿐이니 최빈값인 MORTGAGE로 대체하여도 무리가 아니라고 판단
# 1개밖에 없으니 최빈값(MORTGAGE)으로 채우기로 결정
train.loc[train['주택소유상태'] == 'ANY', '주택소유상태'] = 'MORTGAGE'
train[train['주택소유상태'] == 'ANY'].value_counts().sum()
test.loc[test['주택소유상태'] == 'ANY', '주택소유상태'] = 'MORTGAGE'
test[test['주택소유상태'] == 'ANY'].value_counts().sum()
- 근로기간이 Unknown인 데이터는 총 5671개
- 근로기간의 최빈값은 10+ years인데 최빈값이면서 최대 범주이기 때문에 최빈값 대신 0으로 대체
# unknown은 0으로 처리
train['근로기간'] = train['근로기간'].replace('Unknown', '0')
test['근로기간'] = test['근로기간'].replace('Unknown', '0')
- 총상환원금과 총상환이자가 모두 0인 데이터 확인 결과 총 5407개가 존재
- 전체 데이터의 약 5.6% → 적은 수가 아님
- 결측치인지 아닌지 근거를 찾기 위해 모두 0인 데이터와 0이 아닌 데이터들의 대출등급 비율을 비교함
- 비교 결과 등급의 비율이 매우 흡사함
- 따라서 오로지 두 개의 컬럼만 0으로 존재하는 걸수도 있다는 생각을 했고, 결측치라고 판단
- 편향 문제가 발생할 수 있으니 일단 해당 데이터를 유지하여 진행해보고 나중에 0인 데이터를 전부 제거한 데이터로도 진행해볼 예정


2. 피쳐 엔지니어링
- 총상환원금비율과 총상환이자비율 피쳐 생성
3. 스케일링과 인코딩
- 연간소득은 단위가 너무 크기 때문에 로그 변환을 결정
- 총상환원금, 총상환이자는 크게 왜도되어 있기 때문에 마찬가지로 로그 변환 결정
- 0인 데이터가 존재하기 때문에 log1p()함수를 사용
# 로그 변환 (왜도가 있는 연간소득, 총상환원금, 총상환이자에 대한 처리)
train['연간소득_log'] = np.log1p(train['연간소득'])
train['총상환원금_log'] = np.log1p(train['총상환원금'])
train['총상환이자_log'] = np.log1p(train['총상환이자'])
test['연간소득_log'] = np.log1p(test['연간소득'])
test['총상환원금_log'] = np.log1p(test['총상환원금'])
test['총상환이자_log'] = np.log1p(test['총상환이자'])
- 데이터가 이상치가 많고, 정규분포를 따르는 특성이 없기 때문에 RobustScaler 사용 결정
# 스케일링
# 이상치가 많고 정규분포를 따르는 특성이 없기 때문에 RobustScaler 선택
from sklearn.preprocessing import RobustScaler
scaler = RobustScaler()
train[numeric_cols] = scaler.fit_transform(train[numeric_cols])
test[numeric_cols] = scaler.transform(test_pre[numeric_cols])
- 레이블 인코딩은 대출등급을 제외한 모든 범주형 데이터에 적용
# 레이블 인코딩
from sklearn.preprocessing import LabelEncoder
object = train.select_dtypes(include = 'object').columns
le = LabelEncoder()
for i in object:
if i != '대출등급':
train[i] = le.fit_transform(train[i])
test[i] = le.transform(test[i])
3. 모델 훈련
- RandomForestClassifier를 사용하여 훈련
- 첫번째 시도는 우선 새로운 피쳐 없이 주어진 피쳐만 사용해볼 예정
# 기본 모델 학습
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_validate
from sklearn.model_selection import StratifiedKFold
rf = RandomForestClassifier(n_estimators=100, random_state=42)
scores = cross_validate(rf, X, y, cv=StratifiedKFold())
print(np.mean(scores['test_score']))

- 특성 중요도 확인
# 특성 중요도 확인
rf.fit(X, y)
for feat, importance in zip(X.columns, rf.feature_importances_):
print(f'{feat} : {importance}')

- 중요도가 낮은 총연체금액, 연체계좌수, 주택소유상태, 최근_2년간_연체_횟수
- 중요도가 높은 순은 대출금액 - 부채_대비_소득_비율, 연간소득_log 순
- 중요도가 낮은 피쳐 삭제 후 다시 예측 -> 1% 정도 상승함
# 피쳐 제거 후 시도 -> 약간 상승
scores = cross_validate(rf, X, y, cv=StratifiedKFold())
print(np.mean(scores['test_score']))

'Data Science > TIL (Today I Learned)' 카테고리의 다른 글
| 프로그래머스 데이터분석 데브코스 1기 - 60일차 (2) | 2024.02.16 |
|---|---|
| 프로그래머스 데이터분석 데브코스 1기 - 59일차 (1) | 2024.02.15 |
| 프로그래머스 데이터분석 데브코스 1기 - 57일차 (1) | 2024.02.13 |
| 프로그래머스 데이터분석 데브코스 1기 - 56일차 (1) | 2024.02.12 |
| 프로그래머스 데이터분석 데브코스 1기 - 55일차 (0) | 2024.02.09 |