📄 예제에 사용한 파일
1. credit 데이터셋 알아보기
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
credit_df = pd.read_csv('/content/drive/MyDrive/KDT/Python/4.머신러닝 딥러닝/credit.csv')
credit_df
✅ 컬럼 수를 최대 30개로 보기
pd.set_option('display.max_columns', 30)
credit_df
✅ credit_df 정보 보기
credit_df.info()
✅ 개인정보와 같이 모델학습에 필요없는 피쳐를 삭제
credit_df.drop(['ID','Customer_ID','Name','SSN'], axis=1, inplace=True)
✅ Credit_Score 열의 데이터 종류와 데이터 개수 알아보기
credit_df['Credit_Score'].value_counts()
✅ Object형 데이터 라벨인코딩 하기
credit_df['Credit_Score'] = credit_df['Credit_Score'].replace({'Poor':0, 'Standard':1,'Good':2})
credit_df['Credit_Score']
✅ 수치형 데이터 정보 보기
✅ 리볼빙을 사용하는지에 대한 여부에 대한 신용점수를 시각화 하여 보기
sns.barplot(x='Payment_of_Min_Amount', y = 'Credit_Score', data=credit_df)
✅ 직업별 신용점수를 시각화 하여 알아보기
plt.figure(figsize=(20,5))
sns.barplot(x='Occupation',y='Credit_Score', data=credit_df)
✅ 각 피쳐별로 상관관계를 알아보기 위해 히트맵으로 보기
plt.figure(figsize=(12,12))
sns.heatmap(credit_df.corr(), cmap='coolwarm', vmin=-1, vmax=1, annot=True)
1. Delay_from_due_date와 Credit_Score은 반비례 관계(연체일이 많을수록 신용도가 낮음)
2. Monthly_Balance와 Credit_Score는 비례 관계(월별 잔고가 높으면 신용도가 높음)
3. Credit_Utilization_Ratio와 Credit_Score는 약간의 비례관계(신용카드 사용률(한도내)이 높으면 신용도가 높음)
✅ credit_df의 정보 보기
credit_df.info()
✅ credit_df 컬럼 중 dtype이 object인 컬럼을 보기
for i in credit_df.columns:
if credit_df[i].dtypes == 'O':
print(i)
>>> Age
Occupation
Annual_Income
Num_of_Loan
Type_of_Loan
Num_of_Delayed_Payment
Outstanding_Debt
Credit_History_Age
Payment_of_Min_Amount
Amount_invested_monthly
Payment_Behaviour
✅ 데이터에서 '_'와같은 이상한 문자 없애기
for i in ['Age', 'Annual_Income', 'Num_of_Loan', 'Num_of_Delayed_Payment', 'Outstanding_Debt', 'Amount_invested_monthly']:
credit_df[i] = pd.to_numeric(credit_df[i].str.replace('_',''))
✅ Credit_History_Age의 데이터를 개월수로 변경(예: 22 Years and 1 Months -> 22*12 + 1)
# Months를 먼저 없앰
credit_df['Credit_History_Age'] = credit_df['Credit_History_Age'].str.replace(' Months','')
credit_df['Credit_History_Age']
# Years and 를 기준으로 split 후 expnad=True 옵션을 줘서 0열(Years)과 1열(Months)로 만듦
# pd.to_numeric()으로 숫자 변환 후 Years * 12 + Months
credit_df['Credit_History_Age'] = pd.to_numeric(credit_df['Credit_History_Age'].str.split(' Years and ', expand=True)[0]) * 12 + pd.to_numeric(credit_df['Credit_History_Age'].str.split(' Years and ', expand=True)[1])
credit_df.head()
credit_df.describe()
✅ Age가 0보다 작은 데이터 보기
credit_df[credit_df['Age'] < 0]
✅ Age가 0보다 큰 사람들만 저장하기
credit_df = credit_df[credit_df['Age'] >= 0]
✅ Age를 내림차순으로 정렬하고 30개 데이터 보기
credit_df['Age'].sort_values(ascending=True).tail(30)
✅ 나이를 boxplot으로 알아보기
sns.boxplot(y=credit_df['Age'])
✅ 나이가100살 이상인 사람들의 데이터를 Age순으로 정렬
credit_df[credit_df['Age']>100].sort_values('Age')
✅ 나이가 120 미만인 사람들만 저장
credit_df = credit_df[credit_df['Age']<120]
✅ 수치형 데이터 보기
credit_df.describe()
✅ 은행 계좌가 20개 이상인 사람들의 비율 알아보기
len(credit_df[credit_df['Num_Bank_Accounts'] > 20]) / len(credit_df)
>>> 0.013029853207982847
# 은행계좌가 30개 이상인 사람들의 비율 - 20개와 차이 없음
len(credit_df[credit_df['Num_Bank_Accounts'] > 30]) / len(credit_df)
>>> 0.013029853207982847
# 은행계좌가 10개 이상인 사람들의 비율 - 20, 30개와 차이 없음
len(credit_df[credit_df['Num_Bank_Accounts'] > 10]) / len(credit_df)
>>> 0.013029853207982847
➡ 은행계좌가 10개 이상인 사람들의 데이터를 이상치로 판단
✅ 은행계좌가 10개 이하인 사람들만 저장하기
credit_df = credit_df[credit_df['Num_Bank_Accounts'] <=10]
credit_df.describe()
✅ 신용카드가 20개 이상인 사람들의 비율
len(credit_df[credit_df['Num_Credit_Card'] > 20]) / len(credit_df)
>>> 0.021975267379679145
# 신용카드가 10개 이상인 사람들의 비율
len(credit_df[credit_df['Num_Credit_Card'] > 10]) / len(credit_df)
>>> 0.022142379679144383
# 신용카드가 30개 이상인 사람들의 비율
len(credit_df[credit_df['Num_Credit_Card'] > 30]) / len(credit_df)
>>> 0.021724598930481284
➡ 신용카드가 10개 이상인 사람들의 데이터를 이상치로 판단
✅ 신용카드의 개수가 10개 이하인 사람들의 데이터만 저장하기
credit_df = credit_df[credit_df['Num_Credit_Card'] <=10]
credit_df.describe()
✅ 미국의 이자율이 40%인 것을 고려하여 이자율이 40보다 작은 데이터들만 저장
credit_df = credit_df[credit_df['Interest_Rate'] <=40]
✅ 대출 건수가 10개 이상인 사람들의 비율
len(credit_df[credit_df['Num_of_Loan'] > 10]) / len(credit_df)
>>> 0.005310350831374598 # 약 5%
✅ 대출받은 건수가 10개 이하이면서 0개 이상인 데이터들만 저장
credit_df = credit_df[(credit_df['Num_of_Loan'] <=10) & (credit_df['Num_of_Loan'] >= 0)]
✅ Delay_from_due_date가 0보다 큰 데이터들만 저장
credit_df = credit_df[credit_df['Delay_from_due_date'] >=0]
✅ Num_of_Delayed_Payment의 이상치를 정제
len(credit_df[credit_df['Num_of_Delayed_Payment'] > 10]) / len(credit_df)
>>> 0.6184971098265896
# 20개 이상인 데이터
len(credit_df[credit_df['Num_of_Delayed_Payment'] > 20]) / len(credit_df)
>>> 0.1169832094687586
# 30개 이상인 데이터
len(credit_df[credit_df['Num_of_Delayed_Payment'] > 30]) / len(credit_df)
>>> 0.007340122947059363
# 40개 이상인 데이터
len(credit_df[credit_df['Num_of_Delayed_Payment'] > 40]) / len(credit_df)
>>> 0.007340122947059363
# Num_of_Delayed_Payment가 0보다 크거나 같고 30개 이하인 데이터들만 저장
credit_df = credit_df[(credit_df['Num_of_Delayed_Payment'] <=30) & (credit_df['Num_of_Delayed_Payment'] >= 0)]
# Num_Credit_Inquiries가 NaN이면 0으로 바꿔줌
credit_df['Num_Credit_Inquiries'] = credit_df['Num_Credit_Inquiries'].fillna(0)
✅ NaN값 알아보기
credit_df.isna().sum()
💡 Credit_History_Age, Amount_invested_monthly, Monthly_Balance 의 데이터가 NaN인 경우 어떤걸로 채울까??
sns.displot(credit_df['Credit_History_Age'])
sns.displot(credit_df['Amount_invested_monthly'])
sns.displot(credit_df['Monthly_Balance'])
💡 NaN데이터를 중앙값으로 채우는 것이 낫다는 판단!
credit_df = credit_df.fillna(credit_df.median())
✅ 다시 NaN 데이터 알아보기
credit_df.isna().sum()
✅ Type_of_Loan에 대해 원 핫 인코딩 하기
# 1. 해당 열에 NaN값을 'No Loan'으로 대체
credit_df['Type_of_Loan'] = credit_df['Type_of_Loan'].fillna('No Loan')
# 2. 데이터의 'and'글자를 없앰
credit_df['Type_of_Loan'] = credit_df['Type_of_Loan'].str.replace('and ','')
# 3. ', '를 기준으로 데이터를 나누고 set을 이용하여 중복값을 제거함
type_list =set(credit_df['Type_of_Loan'].str.split(', ').sum())
type_list
# 4. type_list의 개수만큼 돌면서 각 i값에 해당하는 새로운 파생변수를 만듦 -> x값이 Type_of_Loan열에 있으면 1, 없으면 0으로 채워짐
for i in type_list:
credit_df[i] = credit_df['Type_of_Loan'].apply(lambda x: 1 if i in x else 0)
# 5. Type_of_Loan 열을 지움
credit_df.drop('Type_of_Loan', axis=1, inplace=True)
✅ credit_df 정보 보기
credit_df.info()
✅ Occupation열의 데이터 확인해보기
credit_df['Occupation'].value_counts()
# 'Unknown'으로 대체하기
credit_df['Occupation'] = credit_df['Occupation'].replace('_______','Unknown')
credit_df['Occupation'].value_counts()
✅ 'Payment_of_Amount'열 데이터 알아보기
credit_df['Payment_of_Min_Amount'].value_counts()
✅ 'Payment_Behavior' 열 데이터 알아보기
credit_df['Payment_Behaviour'].value_counts()
# 'Unknown'으로 대체하기
credit_df['Payment_Behaviour'] = credit_df['Payment_Behaviour'].replace('!@9#%8','Unknown')
credit_df['Payment_Behaviour'].value_counts()
✅ object형 데이터 원 핫 인코딩 하기
credit_df = pd.get_dummies(credit_df, columns=['Occupation','Payment_Behaviour','Payment_of_Min_Amount'])
✅ train 데이터와 test 데이터 나누기
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(credit_df.drop('Credit_Score', axis=1), credit_df['Credit_Score'], test_size=0.2, random_state=10)
2. LightGBM(LGBM)
- Tree 기반 학습 알고리즘인 gradient boosting 방식의 프레임워크
- Decision Tree, Random Forest는 균형 트리 분할(level wise, 데이터를 중요하다고 생각되는 피쳐를 통해 *균등하게* 나누기 때문에 속도가 조금 느림)방식이라면, LGBM은 리프 중심 트리 분할(leaf wise)
- GBM(Gradient Boosting Machine): 모델1을 통해 y를 예측하고, 모델2에 데이터를 넣어 다시 y를 예측, 모델3에 넣어 y를 예측 ...하는 방식을 사용
- 학습하는데 걸리는 시간이 적음(빠른 속도)
- 메모리 사용량이 상대적으로 적은편
- 적은 데이터셋을 사용할 경우 과대적합의 가능성이 매우 큼(피쳐를 무작위로 선택하여 나누기 때문에 과적합될 가능성이 큼)
- 사이킷런에서 제공하지 않고 따로 존재
- 예측과 회귀 둘 다 사용 가능
📍 일반적으로 데이터가 10000개 이상은 사용해야 함!
from lightgbm import LGBMClassifier
# 모델 객체 생성
base_model = LGBMClassifier(random_state=10)
# 학습
base_model.fit(X_train, y_train)
# 예측
pred1 = base_model.predict(X_test)
✅ 학습에 대한 평가
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report, roc_auc_score
# accuracy_score
accuracy_score(y_test, pred1)
>>> 0.7351324337831084
# confusion matrix
confusion_matrix(y_test, pred1) # 데이터가 한쪽으로 치우쳐져 있지 않음
>>> array([[407, 148, 27],
[145, 896, 91],
[ 3, 116, 168]])
print(classification_report(y_test, pred1))
✅ 예측 클래스 알아보기
credit_df['Credit_Score'].value_counts() # 3개 중 한개를 선택하게 됨
>>>
1 5581
0 2918
2 1503
Name: Credit_Score, dtype: int64
✅ 클래스별 예측 확률 구하기
proba1 = base_model.predict_proba(X_test)
proba1
6.98737764e-02,8.38143193e-01, 9.19830307e-02 # 2번째를 채택
>>> (0.0698737764, 0.838143193, 0.0919830307)
✅ roc_auc_score 확인하기(multi_class='ovr': 분류하는 클래스가 3개이기 때문에 OvR 방식을 채택)
roc_auc_score(y_test, proba1, multi_class='ovr')
>>> 0.8972566425279517
3. RandomizedSearchCV
- 분류기를 결정하고 해당 분류기의 최적의 하이퍼 파라미터를 찾기 위한 방법
- 튜닝하고싶은 파라미터를 지정하여 파라미터 값의 범위를 정하고, n_iter값을 설정하여 해당 수 만큼 Random하게 조합하여 반복 적용
# n_estimators: 반복 수행하는 트리의 수를 몇개로 잡을 것인지(기본값: 100), 값을 크게 지정하면 학습시간도 오래걸리며 과적합의 가능성이 커짐
# max_depth: 트리의 최대 깊이(기본값: -1, 최대깊이를 지정하지 않고 할 수 있는데 까지 깊이를 내려가게 함)
# num_leaves: 결정 트리에 있는 최대 리프 노드(말단 노드)의 개수, 작은 데이터셋의 경우 값을 작게 설정하는 것이 좋음
# learning_rate: 학습률(기본값: 0.1), 모델이 각 훈련 단계에서 이전 단계의 오차를 얼마나 반영하여 업데이트할지를 결정, 학습 속도를 조절하는 역할
# 높은 학습 속도는 모델이 빠르게 훈련 데이터에 적응할 수 있도록 하지만, 너무 높으면 수렴하지 못하고 오버슈팅(overshooting) 문제가 발생
# 반대로, 낮은 학습 속도는 수렴하는 데 더 많은 시간이 걸리지만, 더 정확한 모델을 얻을 수 있음
params = {
'n_estimators': [100, 300, 500, 1000],
'max_depth': [-1, 30, 50, 100],
'num_leaves': [5, 10, 20, 50],
'learning_rate': [0.01, 0.05, 0.1, 0.5]
}
# 모델 객체 생성
lgbm = LGBMClassifier(random_state=10)
from sklearn.model_selection import RandomizedSearchCV
# n_iter=30: 위 params 객체에서 조합을 30개를 만듦
rand_lgbm = RandomizedSearchCV(lgbm, params, n_iter=30, random_state=10)
# 학습
rand_lgbm.fit(X_train, y_train)
# cv_results_: 결과에 대한 리포트
rand_lgbm.cv_results_
# best_params_: 최적의 조합을 알려줌
rand_lgbm.best_params_
>>> {'num_leaves': 20, 'n_estimators': 300, 'max_depth': 50, 'learning_rate': 0.01}
# 최적의 하이퍼 파라미터 조합으로 모델 학습
lgbm = LGBMClassifier(random_state=10,num_leaves=20, n_estimators=300, max_depth=50, learning_rate=0.01)
lgbm.fit(X_train, y_train)
# 클래스별 예측 확률
proba2 = lgbm.predict_proba(X_test)
proba2
✅ roc_auc_score 알아보기
roc_auc_score(y_test, proba2, multi_class='ovr')
>>> 0.9024448184054178
# 하이퍼 파라미터 튜닝 전: 0.8972566425279517
# 하이퍼 파라미터 튜닝 후: 0.9024448184054178(성능 향상!😊)
0.9024448184054178 - 0.8972566425279517
>>> 0.005188175877466117
'Python > ML&DL' 카테고리의 다른 글
[파이썬, Python] 평가지표 - MSE, MAE, RMSE (0) | 2023.06.23 |
---|---|
[파이썬, Python] 머신러닝 - 7️⃣ KMeans (0) | 2023.06.19 |
[파이썬, Python] 머신러닝 - 5️⃣ 랜덤 포레스트(Random Forest) (0) | 2023.06.18 |
[파이썬, Python] 머신러닝 - 4️⃣ 서포트 벡터 머신(Support Vector Machine) (0) | 2023.06.18 |
[파이썬, Python] 머신러닝 - 3️⃣ 로지스틱 회귀(Logistic Regression) (0) | 2023.06.15 |