[PYTHON - 머신러닝_LightGBM]★geopy.distance이용한 거리계산★groupby★agg활용한 통계계산★time 라이브러리★민감도, ROC곡선★
1. LightGBM
==> XGBoost 이후 나온 최신 부스팅 모델. ==> 리프 중심 트리 분할 방식 사용
장점 :
㉠ XGBoost보다 빠르고 높은 정확도를 보여준다.
㉡ 예측에 영향을 미친 변수의 중요도를 확인할 수 있다.
㉢ 변수 종류가 많고 데이터가 클 수록 상대적으로 뛰어난 성능을 보여준다.
단점 :
㉠ 복잡한 모델인 만큼 ,해석에 어려움이 있다.
㉡ 하이퍼파라미터 튜닝이 까다롭다.
유용한 곳:
1> 종속변수가 연속형 데이터인 경우든 범주형 데이터인 경우든 모두 사용 가능
2> 이미지나 자연어가 아닌 표로 정리된 데이터라면 거의 모든 상황에서 활용 가능 ==> XGBoost 와 비슷
2. 데이터 전처리
1> 불필요한 변수들 제외
==> 이상거래(fraud)를 예측 ==> 합리적이지 않다. ==> 이름 관련 변수를 제외가능
2> to_datetime 활용하여 datetime으로 변환
data['trans_date_trans_time'] = pd.to_datetime(data['trans_date_trans_time']) # 날짜 형식으로 변환
data['trans_date_trans_time']
3> 피처엔지니어링
==> 이상거래 감지의 기본적인 아이디어는 해당 고객의 기존 거래 패턴에서 벗어나는 경우를 감지하는 것이다.
ex) 서울에서 카드를 사용하던 사람이 런던에서 고액의 물건을 구매, 주류매장을 이용한 적이 없는데 주류매장에서 고액의 결제
==>Z-점수(Z-score)를 활용하여 패턴 확인
https://knowallworld.tistory.com/220
모집단의 z-점수
표본의 z-점수
https://knowallworld.tistory.com/253
data.groupby('cc_num').count()
==> groupby를 활용하면 count , mean 등 산술연산을 진행해야 한다.
amt_info = data.groupby('cc_num').agg(['mean' , 'std'])['amt'].reset_index() #cc_num별 amt 평균과 표준편차 계산
amt_info.head()
==> groupby 활용하여 평균과 표준편차 계산
==> data의 cc_num을 그룹화하고, 평균과 표준편차를 구한다. 그중 amt열만 조사한다.
data = data.merge(amt_info , on = 'cc_num' , how = 'left') # 데이터 합치기
data
data[['amt' , 'mean' , 'std' , 'amt_z_score']].head()
==> 위도 경도 한 변수로 합치기
data['merch_coord'] = pd.Series(zip(data['merch_lat'] , data['merch_long'])) # 위도, 경도 한 변수로 합치기
data['cust_coord'] = pd.Series(zip(data['lat'] , data['long'])) # 위도, 경도 한 변수로 합치기
data
==> zip() 함수를 통하여 괄호로 묶인 위도 경도 값 얻어냈다.
import geopy.distance
data['distance'] = data.apply(lambda x : geopy.distance.distance(x['merch_coord'] , x['cust_coord']).km , axis =1 ) # 거리계산
import time
start_time = time.time()
data['distance'] = data.apply(lambda x : geopy.distance.distance(x['merch_coord'] , x['cust_coord']).km , axis =1 ) # 거리계산
end_time = time.time()
print(end_time - start_time)
==> time 라이브러리를 활용하여 코드 실행 전과 후의 소요시간 파악 가능하다.
distance_info = data.groupby('cc_num').agg(['mean' , 'std'])['distance'].reset_index() # cc_num 별, 거리 정보 계산
data = data.merge(distance_info , on = 'cc_num' , how = 'left') # 데이터 합치기
data['distance_z_score'] = (data['distance'] - data['mean']) / data['std'] # z-score 계산
data.drop(['mean' , 'std'] , axis =1 , inplace = True) # 변수 제거
data.head()
data['age'] = 2021 - pd.to_datetime(data['dob']).dt.year # dt.year 활요한 나이 계산
data
==> dt.year 활용 나이 계산
data = pd.get_dummies(data, columns = ['category' , 'gender'] , drop_first= True)
data
3. 모델링 및 평가하기
==> 신용카드의 이상거래를 감지하여 지금까지 발생한 거래 데이터를 기반으로 모델을 학습 ==> 모델을 이용하여 앞으로 일어나는 거래에 대한 이상 여부 예측
train = data[data.index < '2020-07-01'] # 훈련셋 설정
test = data[data.index >= '2020-07-01'] # 시험셋 설정
len(test) / len(data) # 시험셋 비율 확인 ==> 0.284
==> 시험셋 : 0.2 , 훈련셋 : 0.8 ==> 학습시키는데 적당하다.
X_train = train.drop('is_fraud' , axis =1)
X_test = test.drop('is_fraud' , axis = 1)
y_train = train['is_fraud']
y_test = test['is_fraud']
import lightgbm as lgb
model_1 = lgb.LGBMClassifier(random_state= 100) # 모델 객체 생성
model_1.fit(X_train , y_train)
pred_1 = model_1.predict(X_test) # 예측
==> lightgbm 라이브러리 활용하여 모델 객체 , 학습 및 예측
from sklearn.metrics import accuracy_score , confusion_matrix , classification_report , roc_auc_score
# 정확도 점수 , 혼동 행렬 , 분류 리포트 , ROC AUC 점수
accuracy_score(y_test , pred_1) # 정확도 확인
==> 0.99647 ==> 정확도가 약 99.7% ==> but. is_fraud가 0 인경우가 99%이기 때문에 정확도의 의미는 중요치 않다.
print(confusion_matrix(y_test , pred_1)) # 혼동 행렬
실제값 \ 예측값 | 0 | 1 |
0 | 522933 | 716 |
1 | 821 | 1191 |
참양성 ==> 1191
거짓양성(1종 오류) ==> 716
거짓음성(2종 오류) ==> 821
print(classification_report(y_test , pred_1)) # 분류 리포트 확인
정밀도 : 0.62
재현율 : 0.59 ==> 실제 이상거래를 얼마나 예측했는지(실제론 정상거래여도 이상거래가 되었는지 여부 예측)를 의미하는 재현율이 이상거래 탐지엔 중요
f1-score : 0.61
정밀도(precision)은 1로 예측한 경우 중, 얼마만큼이 실제로 1인지를 나타낸다.
==> 양성을 양성으로 판단 / (양성을 양성으로 판단 + 1종오류) ==> 1 종오류가 중요하면 정밀도에 주목
재현율(recall)은 실제로 1 중에, 얼마만큼을 1로 예측했는지를 나타낸다.
==> 양성을 양성으로 판단/ (양성을 양성으로판단 + 2종오류) ==> 2 종오류가 중요하면 재현도에 주목
F1-점수(F1-score)은 정밀도와 재현율의 조화평균을 의미한다.
==> 2 * (정밀도 * 재현율) / (정밀도 + 재현율) ==> 1 종오류, 2종오류 중요한 오류가 없다면 F1-SCORE 활용
1> 예측모델의 민감도
pred_1 = model_1.predict(X_test) # 예측
pred_1
==> array([0,0,0,0,.....] ) ==> 0.5기준
proba_1 = model_1.predict_proba(X_test) # 예측
proba_1
==> 소수점값 출력으로 모델의 예측값에 대한 민감도를 높였다.
==> 이중 우리가 알고 싶은 값은 1일 가능성 예측 ==> 1 열에만 주목 한다.
proba_1 = proba_1[: ,1] # 1 에 대한 예측 결과 출력
proba_1
proba_int1 = (proba_1 > 0.2).astype('int') # 0.2 기준으로 분류
proba_int2 = (proba_1 > 0.8).astype('int') # 0.8 기준으로 분류
print(confusion_matrix(y_test , proba_int1))
[[522105 1544]
[ 598 1414]]
참양성 ==> 1191 ==> 1414 ==> 증가
거짓양성(1종 오류) ==> 716 ==> 1544 ==> 증가
거짓음성(2종 오류) ==> 821 ==> 598 ==> 감소
print(classification_report(y_test , proba_int1))
정밀도 : 0.62==>0.48 ==> 감소
재현율 : 0.59==>0.70 ==> 증가
f1-score : 0.61==>0.57
print(confusion_matrix(y_test , proba_int2))
[[523183 466]
[ 958 1054]]
참양성 ==> 1191 ==> 1054 ==> 감소
거짓양성(1종 오류) ==> 716 ==> 466 ==> 감소
거짓음성(2종 오류) ==> 821 ==> 958 ==> 증가
==> 정상거래를 이상거래로 의심하는 경우는 줄었으나, 이상거래를 놓치는 경우가 많아졌다.
print(classification_report(y_test , proba_int2))
정밀도 : 0.62==>0.69==> 증가
재현율 : 0.59==>0.52 ==> 감소
f1-score : 0.61==>0.60 ==> 감소
2> 예측모델의 민감도
==> 기준점에 따라 재현율이 달라질 수 있어, 최적의 기준점은 모델에 따라 달라진다.
EX) 모델 A에서는 0.4에서 높은 재현율과 적절한 정밀도 얻을 수 있다 ==> 모델 B에서는 0.3이 최적의 기준점이 된다.
==> AUC 활용하여 모호한 모델의 평가 가능
4. AUC(Area Under the ROC Curve)
ROC 곡선 :
민감도(TPR) = TP(참양성) / (TP(참 양성) + FN(거짓 음성) ) = 재현율
==> 실제 1인 것중 얼마만큼 제대로 1로 예측되었는지 ==> 1에 가까울 수록 좋다.
특이도(FPR) = FP(거짓양성) / (FP(거짓 양성) + TN(참 음성) )
==> 실제 0 인 것중 얼마만큼이 1로 잘못 예측되었는지 ==> 0에 가까울 수록 좋다.
ROC 곡선은 ==> X축 FPR , Y축 TPR
AUC (Area Under the ROC Curve) ==> ROC 곡선의 아래쪽에 해당하는 면적
roc_auc_score(y_test , proba_1) # 정확도 확인
==> 0.9366009333487075 ==> AUC 또한 정확도와 마찬가지로 종속변수가 한쪽으로 편향될 때 자연스럽게 높게 나오는 경향이 있어 반드시 매우 좋다고 해석 할 수 는 없다.
출처 : 데싸노트의 실전에서 통하는 머신러닝
(Golden Rabbit , 저자 : 권시현)
※혼자 공부용
'머신러닝 > LightGBM' 카테고리의 다른 글
[LightGBM활용_Kaggle-타이타닉-04] 모델 돌려보기(단독_ Descision Tree) (0) | 2023.05.23 |
---|---|
[LightGBM활용_Kaggle-타이타닉-03] 피처별 전처리하기★pd.cut (0) | 2023.05.20 |
[LightGBM활용_Kaggle-타이타닉-02] 피처별 전처리하기 (1) | 2023.05.20 |
[LightGBM활용_Kaggle-타이타닉-01] EDA 및 전처리하기 (0) | 2023.05.20 |
[PYTHON - 머신러닝_LightGBM-02]랜덤 그리드 서치★L1정규화★L2정규화★LGBMClassifer()와 train()의 차이 (0) | 2023.01.27 |