728x90

어제 언급한 택시수요예측 딥러닝 문제점은 각 지역마다 카운트가 다른 점이었습니다

예를 들어 강남은 1시에 100건의 콜 데이터가 있지만 다른 지역은 누락된 곳이 있었죠 

 

만일 각 지역이 같은 크기?를 갖고 있었다면 timestep를 결정하기 쉬웠을 거라 생각합니다 

그러면 특정 시간을 예측하기 위해서 몇 시간 전 데이터를 일괄적으로 timestep으로 지정하면 간단할 거라 생각합니다

 

아무튼 각 지역마다 정보 카운트가 달랐기 때문에

가장 먼저 각 시간대별 몇 개의 데이터가 존재하는지를 확인해야 했습니다

그래서 아래 결과를 확인할 수 있었죠

년원일은 해당 시간대의 마지막 데이터의 년원일입니다 예를 들어 00:00:00의 시간을 가진 데이터는 2015-05-29일 마지막 데이터 라는 얘기가 됩니다 예상했던 대로 각 시간대 마다 개수가 다르더라구요 

참고로 00:00은 정시부터 30분, 30:00은 30분부터 정시입니다. 예를들어 00:00 > 1시~30분이고 30:00 > 1시 30분~2시입니다. 

해결된 것은 각 시간대 별로 데이터를 구분할 수 있다는 것이고, 문제가 된 것은 구분된 데이터를 이젠 숫자가 아니라 실제 데이터를 어떻게 가져올 것이냐 라는 것에서 막혔습니다 

  try:
    if pca_ohe_df.iloc[idx]['minute2'] == pca_ohe_df.iloc[idx+1]['minute2'] and pca_ohe_df.iloc[idx]['Hour'] == pca_ohe_df.iloc[idx+1]['Hour']:
      data.append(np.array(pca_ohe_df.iloc[idx]))  #np.array() : 이걸 하지 않으면 각 행 마다 컬럼이 따라 들어온다
      num+=1
    else:
      print('{0}의 총 갯수는 {1}입니다'.format(pca_ohe_df.iloc[idx]['minute'], num))
      input_data.append(np.array((data)))
      data=[] #data 리스트 초기화
      num=0  #카운트 초기화

여러 방법을 해보다가 위 코드가 지금 현재 상태입니다 아직 해결이 안 된 상태죠

이 코드를 실행하면 

input_data는 아래와 같이 나옵니다

450개가 넘은 변수가 하나로 뭉쳐지게 됩니다

지금은 정확히 기억이 안 나지만 다른 방법으로 할 때는 변수도 잘 나왔지만

원본 데이터와 같은 데이터가 되더라고요 

 

제 의도는 각 시간대별 리스트로 묶여서 3D 텐서 형식으로 만드는 게 목적이었습니다

따라서 원본 데이터와 같아지면 시간대별 구분점이 없기 때문에 사용을 못하게 됩니다 ㅠ 

 

오늘은 이 문제만 가지고 씨름을 해야 했고 아직 해결을 못한 상태라서 

일정에 차질이 빚어질 거라 확신합니다 ㅎㅎㅎㅎ 

 

만일 이문제가 해결이 된다면 다음 문제는 

데이터를 분리할 때 과연 잘 작동을 하느냐입니다 

이틀 전에 일괄적으로 timestep을 정하고 분리를 시도했는데 오류가 났었습니다 

주피터에서는 데이터 크기가 큰 것 때문에 오류가 난 걸로 보이는데 코랩은 오류 메시지가 뜨질 않고

런타임이 초기화가 됩니다

 

스태킹도 지금 12시간째 학습 중입니다.. 나중에 정 안되면 데이터를 절반 줄이거나 

원핫인코딩을 줄이거나 해야 할 것 같습니다..

컴퓨터대신 내가 계산하고 싶게 만드는 사진^^

사실 lightGBM을 돌렸을 때 성능이 꽤 괜찮게 나왔기 때문에 

 

웬만하면 삭제 없이 모두 가져가고 싶은 게 목표인데 말이죵.. 

산넘ㅇ ㅓ 산입니다 :) 

감사합니다

728x90
728x90

코랩에서 택시수요예측 스태킹을 어젯밤부터 아침까지 실행하다가 

사용 용량 초과로 인해 초기화가 돼... 됐습니다..

 

그래서 주피터 노트북으로 실행했지만 6시간 이상이 걸리더라고요

제 노트북이 몇 년 된지라 계속하면 망가질까 걱정되다가 결국 중단했습니다 ㅠㅠ 

 

게다가 딥러닝도 막혔습니다 LSTM 하기 위해서 데이터 셋을 만들던 중에 

크기가 2 테라가 넘어서 뺀찌를 먹더군요 처음 알았습니다 딥러닝 이외에 다른 제한이 있다는 걸요 

2015년도 5월 데이터만 가져왔는데 이렇게 크기가 커진 거라면 아마 원핫인코딩을 많이 늘려서 그런 것 같습니다

피처가 450개인데 여기서 몇 개를 삭제해야 할 것 같아요 

 

게다가.. 지역별 개수가 다 다른 것 같더라고요 

예를 들어 강남역 오후 8시 택시 정보는 있는데 신도림역 오후 8시 택시 정보가 없는 것처럼요 

 

제가 처음에는 zip_code별 그룹바이 하니까 383개 zip_code가 나왔었습니다 

아~ 그럼 여기에 30분 단위로 쪼개니까 일괄적으로 계산하면 맞아떨어지겠구나 생각했었더랬죠 

 

But

역시 호락호락하지 않았습니다.. 스태킹도 안되고 딥러닝도 막히니까 두통이 느껴지는 것 같기도 하고 ㅎㅎ

오늘은 좀 일찍 마무리하고 쉬다가 낼 일어나서 다시 해봐야 할 것 같아요

 

 

 

728x90
728x90

예정대로 PCA진행화 스태킹까지 끝마쳤습니다

XGBoost로 gridSearch를 실행하니까 역시 오래 걸리더라구요

 

처음부터 LIghtGBM을 했다면 더 빨리 진도를 나갈수 있었을 건데 말이죠

오늘은 막히는 오류가 있거나 하진 않았습니다! 

 

그래서 내일은 LSTM이나 GRU같은 시계열 데이터 예측 딥러닝 모델을 사용해 볼까 해요

어떤 식으로 해야 할지는 내일 자세히 알아 볼려고합니다

 

여러곳을 찾아보니까 택시수요예측를 LSTM,GRU로 한 블로그를 못봐서 좀 희소성? 이 있지 않을까 생각합니다

카카오브레인팀은 30분씩 쪼개서 4시간씩 묶어 예측을 한것같더라구요 (제가 이해 하기로는)

 

이외에도 다른 정보를 구글링하고 참고해서 또 열심히 해보겠습니다

감사합니다:) 

728x90
728x90

택시 수요예측 프로젝트 전처리 부분을 진행했습니다 

날씨를 bad, normal로 변수를 추가하고 원핫인코딩을 zip_code와 함께 진행했습니다

그런데 여기 난관이 columns= 이부분 이였습니다

실습 때는 zip_code 하나라서 쉬었지만 변수 하나가 추가되니까 막히더라고요

 

pd.concat 파라미터 구글링을 해봤지만 원하는 결과를 찾지 못해서 꽤 헤매었습니다 

구글링을 멈추고 내가 원하는 형태는 뭘까 생각해 보며 이것저것 시도해 보다가 np.concatenate를 사용하니까

되더라고요 뿌~듯하고 문제 하나를 넘겼다는 생각에 숨통이 틔였습니다

#원핫인코딩
from sklearn.preprocessing import OneHotEncoder

#객체 생성
ohe= OneHotEncoder()
ohe.fit(base_df[['zip_code','wheather']])
ohe_output= ohe.transform(base_df[['zip_code','wheather']]).toarray()
ohe_df=pd.concat([base_df, pd.DataFrame(ohe_output, columns=np.concatenate([ohe.categories_[0],ohe.categories_[1]], axis=0))],axis=1)
ohe_df

 

 

이렇게 문제 하나를 통과하니까 또 다른 문제가 뙇!!!

 

iplot 사용제한이 있을 줄은 몰랐는데..  정말 생각지 못한 곳에서 문제가 생기는 게 프로그래밍의 매력이 아닐까...라는 새.. 생각.. 이.. 듭니ㄷ ㅏ  . .   으흠 

 

iplot이 깔끔하고 고급져 보여서 좋아했는데 말이죠 ㅠ 급한 대로 해당 사이트 들어가서 application을 제출하라고 하더라고요 그래서 일단은 보냈는데 결과가 어떻게 나올지는 지켜봐야 할 것 같아요

 

그리고 지금은 XGBoot를 gridSearch로 진행 중인데 지금 1시간째 돌아가고 있네요 

연산량이 많진 않은 것 같은데 말이죠.. 지금은 중단하고 내일 다시 조정해서 돌려봐야 할 것 같아요 

 

내일은 스태킹을 해보고 연관 있는 변수끼리 PCA를 통해서 차원 축소한 성능을 비교해볼 생각이긴 합니다

계획만 그렇게 잡고 있고 또 내일이 가면 어떻게 바뀔지는 내일 공부 기록에 남겨 놓겠습니다:)

 

728x90
728x90

참고서적-파이썬 머신러닝 가이드

저번 블로그의 XGBoost, LightGBM 실습에 이어서 신용카드 사기 검출 실습을 하면서 공부를 해봤습니다~!

 

1. Import

import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
os.chdir('./Data/creditcard')
credit_df=pd.read_csv('creditcard.csv')

#의미없는 Time 변수 제거
del credit_df['Time']

 

2. 데이터 분리

#데이터프레임 복사후 데이터 가공처리
def get_train_test_split(df=None):
    #인자로 입력된 DataFrame의 사전 데이터 가공(Time 변수 삭제)이 완료된 복사 DataFrame 반환
    df_copy=credit_df
    
    #DataFrame의 맨 마지막 칼럼이 레이블, 나머지는 피처들
    x_features=df_copy.iloc[:,:-1]
    y_target=df_copy.iloc[:,-1]
    
    #데이터 분리, stratify 기반으로 분리-train,test 비율 동일하게
    from sklearn.model_selection import train_test_split
    x_train,x_test,y_train,y_test= train_test_split(x_features,y_target, test_size=0.3, random_state=0,stratify=y_target)
    
    #데이터 반환 
    return x_train,x_test,y_train,y_test
    
x_train,x_test,y_train,y_test=get_train_test_split(credit_df)

Time 변수를 제거 후에 feature와 label을 분리하는데 분리 시 샘플링 방식은 나뉟stratify로 해줍니다.

stratify 값을 y_target으로 지정해주면 각각의 class 비율(ratio)을 train / validation에 유지해 줍니다. (한 쪽에 쏠려서 분배되는 것을 방지합니다) 

 

# 레이블 값이 비율을 백분율로 환산하여 서로 비슷하게 분활됐는지 확인
print('학습 데이터 레이블 값 비율')
print(y_train.value_counts()/y_train.shape[0]*100)
print('테스트 데이터 레이블 값 비율')
print(y_test.value_counts()/y_test.shape[0]*100)

학습 데이터 레이블 값 비율
0    99.827451
1     0.172549
Name: Class, dtype: float64
테스트 데이터 레이블 값 비율
0    99.826785
1     0.173215
Name: Class, dtype: float64

 

3. 로지스틱 회귀 VS LightGBM 성능 비교

def get_clf_eval(y_test,pred,pred_proba):
    from sklearn.metrics import f1_score, accuracy_score,precision_score,recall_score,confusion_matrix, roc_auc_score
    confusion = confusion_matrix(y_test, pred)
    accuracy= accuracy_score(y_test, pred)
    precision=precision_score(y_test, pred)
    recall= recall_score(y_test, pred)
    #F1스코어 추가
    f1 =f1_score(y_test,pred)
    print('오차 행렬')
    print(confusion)
    #ROC-AUC 
    roc_auc=roc_auc_score(y_test,pred_proba)
    print('정확도 {0:.4f}, 정밀도 {1:.4f}, 재현율 {2:.4f}, F1:{3:.4f}, AUC:{4:.4f}'.format(accuracy,precision,recall,f1,roc_auc))

성능 평가에 사용되는 함수를 먼저 만들어줍니다.

 

1. 정밀도 = TP/(FP+TP) - 예측을 기준으로 

FP+TP : 예측을 positive로 한 전체 데이터의 수 

TP: 예측과 실제 값이 positive로 맞춘 데이터의 수

-예측을 positive로 한 것들 중에 예측과 실제의 값이 positive로 일치한 데이터의 비율을 말합니다

-일반 메일을 스팸메일이라고 잘못 분류하는 경우에는 재현율 보다 정밀도를 우선 시 합니다.

2. 재현율= TP/(FN+TP) - 실제 값을 기준으로 

FN+TP : 실제 값이 positive인 데이터의 수

- 실제 값이 positive인 것들 중에  예측과 실제의 값이 positive로 일치한 데이터의 비율을 말합니다

  민감도 또는 TPR(true positive Rate) 이라고도 불립니다

- 특히 재현율은 암 판단 모델을 평가할 때입니다. 실제로 양성인 환자를 음성으로 잘못 판단 내리면

  치명적이기 때문에 재현율 평가가 중요합니다

 

위 내용을 정리를 하다 보니까 추가적인 설명이 필요할 것 같아서 제 생각을 적어봤습니다

-정밀도와 재현율의 차이는  분모가 FT 냐 FN 이냐의 차이입니다. 

정밀도의 FT은 False인 값을 True로 예측을 한 것이고

재현율 FN은 False을 올바르게 Negative로 예측했느냐 차이인 것 같습니다

 

위 예시처럼 재현율의 암 판단은 양성을 양성이라고 제대로 판단해야 하기 때문에 FN이 중요하고

정밀도는 실제로 양성이 아닌, 메일로 따지면 스팸메일이 아닌 정상메일의 데이터 예측을 positive 양성으로

예측해서 스팸메일로 분류하는 경우입니다. 

 

3. AUC= ROC 곡선 면적 밑의 면적

AUC 스코어는 이진 분류의 예측 성능 지표입니다.  

간단히 적어보면, ROC 곡선은 FPR (x축)의 변함에 따라 TRP(y축)의 곡선 형태를 보여줍니다.

FPR(False positive Rate) = FP / (FP+TN) = 1-TNR = 1- 특이성

TRP(True positive Rate) = TP / (FN+TP) = 재현율이며 민감 도라고 불리기도 합니다.

TNR(True Negative Rate) = TRP에 대응하는 지표로 특이성이라 실제 값이 음성(Negative)을 정확히 예측해야

수준을 나타냅니다 (코로나 음성인 사람은 음성으로 정확히 예측해야 한다)

반대로, 코로나 양성인 사람을 양성으로 정확히 예측해야 하는 건 당연히 TRP, 재현율 일 겁니다 

 

그러면 FPR은 1-특이성이므로 음성인 사람을 양성이라고 예측한 값일 겁니다

ROC는 이 FRP을 0~1까지 변경하면서 TRP의 변화 값을 구하여 곡선으로 나타냅니다.

 

 

로지스틱 회귀

from sklearn.linear_model import LogisticRegression

lr_clf= LogisticRegression()
lr_clf.fit(x_train,y_train)
lr_pred=lr_clf.predict(x_test)
lr_pred_proba=lr_clf.predict_proba(x_test)[:,1]

get_clf_eval(y_test,pred,lr_pred_proba)

오차 행렬
[[85281    14]
 [   57    91]]
정확도 0.9992, 정밀도 0.8667, 재현율 0.6149, F1:0.7194, AUC:0.9564

 

로지스틱 실행결과 재현율이 0.61로 다른 평가지표에 비해 낮아 보입니다.  이번엔 LightGBM 모델 결과를 보기 앞서서

get_model_train_eval 함수를 만들어서 학습 및 평가를 간단히 하겠습니다

 

# 함수로 만들기
def get_model_train_eval(model, ftr_train=None,ftr_test=None, tar_train=None,tar_test=None):
    model.fit(x_train,y_train)
    pred=model.predict(x_test)
    pred_proba=model.predict_proba(x_test)[:,1]
    get_clf_eval(tar_test,pred,pred_proba)

LightGBM

 

from lightgbm import LGBMClassifier

lgbm_clf = LGBMClassifier(n_estimators=1000, num_leaves=64, n_jobs=-1, boost_from_average=False)
get_model_train_eval(lgbm_clf,  ftr_train=x_train,ftr_test=y_train, tar_train=x_test,tar_test=y_test)

오차 행렬
[[85290     5]
 [   36   112]]
정확도 0.9995, 정밀도 0.9573, 재현율 0.7568, F1:0.8453, AUC:0.9790

로지스틱 모델보다 전반적인 성능이 개선되었습니다.

amount 변수의 분포를 확인 후, 값이 한쪽으로 치우쳐 있다면 scaling을 진행하여 다시 예측해보겠습니다

 

데이터 분포도 변환 후 모델 학습/예측/평가

import seaborn as sns
plt.figure(figsize=(8,4))
plt.xticks(range(0,30000,1000), rotation=60)
#히시토그램 시각화
sns.distplot(credit_df['Amount'])

# 1000불 이하가 대부분이고, 2700불은 드물지만 존재함, 이를 stardardScaler로 표준 정규 분포 형태로 변환 후 예측성능 비교실시

전처리 작업으로 scaling 하는 함수를 만듭니다

def get_preprocessed_df(df=None):
    from sklearn.preprocessing import StandardScaler
    df_copy=credit_df
    scaler=StandardScaler()
    amount_n= scaler.fit_transform(df_copy['Amount'].values.reshape(-1,1))
    
    #변환된 amount를 Amount_scaled로 이름 변경 후, DataFrame 맨 앞 컬럼으로 입력
    df_copy.insert(0, "Amount_scaled",amount_n)
    
    #기존 Time, amount 제거
    df_copy.drop(["Amount"], axis=1, inplace=True)
    return df_copy

scaling은 평균 0, 분산 1을 만드는 StandardScaler를 사용합니다.

스케일링 후 로지스틱, LightGBM을 다시 실행해 봅니다

 

#amount를 정규 분포 형태로 변환 후 로지스틱 회귀 및 LightGBM 수행
x_train,x_test,y_train,y_test = get_train_test_split(df_copy)

print("### 로지스틱 회귀 예측 성능 ###")
lr_clf= LogisticRegression()
get_model_train_eval(lr_clf, ftr_train=x_train,ftr_test=x_test, tar_train=y_train,tar_test=y_test)

print("### lightGBM 예측 성능 ###")
lightgbm_clf=LGBMClassifier(n_estimators=1000, num_leaves=64, n_jobs=-1,boost_from_average=False)
get_model_train_eval(lightgbm_clf, ftr_train=x_train,ftr_test=x_test, tar_train=y_train,tar_test=y_test)

### 로지스틱 회귀 예측 성능 ###
오차 행렬
[[85282    13]
 [   56    92]]
정확도 0.9992, 정밀도 0.8762, 재현율 0.6216, F1:0.7273, AUC:0.9647

### lightGBM 예측 성능 ###
오차 행렬
[[85290     5]
 [   36   112]]
정확도 0.9995, 정밀도 0.9573, 재현율 0.7568, F1:0.8453, AUC:0.981

 

스케일링 전후 차이가 미비했습니다(교재와는 다른 결과를 보였습니다.

amount를 log을 취해서 정규분포와 근사하게 만든 후 다시 모델을 실행해 보겠습니다.

 

로지스틱 & LightGBM(amount log 변환 件)

def get_preprocessed_df(df=None):
    df_copy=df.copy()
    
    #넘파이의 log1p()를 이용해 amount를 로그 변환
    amount_n= np.log1p(df_copy['Amount'])
    df_copy.insert(0, "Amount_Scaled", amount_n)
    df_copy.drop(["Amount"], axis=1, inplace=True)
    return df_copy

df_copy=get_preprocessed_df(credit_df)

#amount를 정규 분포 형태로 변환 후 로지스틱 회귀 및 LightGBM 수행
x_train,x_test,y_train,y_test = get_train_test_split(df_copy)

print("### 로지스틱 회귀 예측 성능 ###")
lr_clf= LogisticRegression()
get_model_train_eval(lr_clf, ftr_train=x_train,ftr_test=x_test, tar_train=y_train,tar_test=y_test)

print("### lightGBM 예측 성능 ###")
lightgbm_clf=LGBMClassifier(n_estimators=1000, num_leaves=64, n_jobs=-1,boost_from_average=False)
get_model_train_eval(lightgbm_clf, ftr_train=x_train,ftr_test=x_test, tar_train=y_train,tar_test=y_test)

### 로지스틱 회귀 예측 성능 ###
오차 행렬
[[85282    13]
 [   56    92]]
정확도 0.9992, 정밀도 0.8762, 재현율 0.6216, F1:0.7273, AUC:0.9647

### lightGBM 예측 성능 ###
오차 행렬
[[85290     5]
 [   36   112]]
정확도 0.9995, 정밀도 0.9573, 재현율 0.7568, F1:0.8453, AUC:0.9812

amount의 log변환도 같은 위 결과와 같은 성능을 보였습니다.

개선이 미비한 원인 중 이상치의 존재일 가능성이 있으므로 이를 제거 후 성능 비교를 다시 해봅니다.

 

이상치 제거 후 성능 비교

-IQR로 이상치를 파악하기 전에 먼저 corr()를 이용해서 레이블의 중요 피처를 구별하여 해당되는 것들만 제거합니다.

# 상관도
import seaborn as sns

try:
    del credit_df['Amount_scaled']
except:
    pass
plt.figure(figsize=(16,16))
corr=credit_df.corr()
sns.heatmap(corr, cmap="RdBu")

레이블인 class와 상관관계가 높은 것은 v14,17인데, 이 중에서 v14 만 이상치 제거 실시합니다

 

import numpy as np

#이상치 인덱스를 반환하는 함수 생성
def get_outlier(df=None, column=None, weight=1.5):
    #fraud에 해당하는 column 데이터만 추출, 1/4 분위와 3/4 분위 지점을 np.percentile로 구함
    fraud = df[df['Class']==1][column]
    quantile_25 = np.percentile(fraud.values, 25)
    quantile_75 = np.percentile(fraud.values, 75)
    
    #IQR을 구하고. IQR에 1.5를 곱해 최댓값과 최솟값 지점 구함
    iqr= quantile_75-quantile_25
    iqr_weight=iqr*weight
    lowest_val=quantile_25-iqr_weight
    highest_val=quantile_75+iqr_weight
    
    #최대값보다 크거나, 최솟값보다 작은 값을 이상치 데이터로 설정하고 DataFram3 index 반환
    outlier_index = fraud[(fraud< lowest_val) | (fraud> highest_val)].index
    return outlier_index

 get_outlier 함수를 통해 V14칼럼의 이상치를 제거해줍니다

outlier_index=get_outlier(df=credit_df, column='V14', weight=1.5)
print('이상치 데이터 인덱스:', outlier_index)

이상치 데이터 인덱스: Int64Index([8296, 8615, 9035, 9252], dtype='int64')
def get_preprocessed_df(df=None):
    df_copy=df.copy()
    
    #넘파이의 log1p()를 이용해 amount를 로그 변환
    amount_n= np.log1p(df_copy['Amount'])
    df_copy.insert(0, "Amount_Scaled", amount_n)
    try:
        df_copy.drop(["Time","Amount"], axis=1, inplace=True)
    except:
        df_copy.drop(["Amount"], axis=1, inplace=True)  
    
    #이상치 제거하는 로직 추가
    outlier_index=get_outlier(df=df, column='V14', weight=1.5)
    df_copy.drop(outlier_index, axis=0, inplace=True)
    return df_copy

 

이상치를 제거한 로지스틱 VS LightGBM 성능 비교 

#amount를 정규 분포 형태로 변환 후 로지스틱 회귀 및 LightGBM 수행
df_copy=get_preprocessed_df(credit_df)
x_train,x_test,y_train,y_test = get_train_test_split(df_copy)

print("### 로지스틱 회귀 예측 성능 ###")
lr_clf= LogisticRegression()
get_model_train_eval(lr_clf, ftr_train=x_train,ftr_test=x_test, tar_train=y_train,tar_test=y_test)
print('\n')

print("### lightGBM 예측 성능 ###")
lightgbm_clf=LGBMClassifier(n_estimators=1000, num_leaves=64, n_jobs=-1,boost_from_average=False)
get_model_train_eval(lightgbm_clf, ftr_train=x_train,ftr_test=x_test, tar_train=y_train,tar_test=y_test)

### 로지스틱 회귀 예측 성능 ###
오차 행렬
[[85281    14]
 [   57    91]]
정확도 0.9992, 정밀도 0.8667, 재현율 0.6149, F1:0.7194, AUC:0.9564

### lightGBM 예측 성능 ###
오차 행렬
[[85290     5]
 [   36   112]]
정확도 0.9995, 정밀도 0.9573, 재현율 0.7568, F1:0.8453, AUC:0.9790

이상치 제거 후 성능 비교를 해본 결과 눈에 띄는 개선 점은 없었습니다.

이번엔 smote(오버 샘플링)을 적용하여 모델 성능 비교를 해보겠습니다.

 

from imblearn.over_sampling import SMOTE

#smote는 train 데이터에만 적용한다
smote= SMOTE(random_state=0)
x_train_over,y_train_over= smote.fit_sample(x_train,y_train)
print("SMOTE 적용 전 학습용 피처/레이블 데이터 세트:", x_train.shape, y_train.shape)
print("SMOTE 적용 후 학습용 피처/레이블 데이터 세트:", x_train_over.shape, y_train_over.shape)
print("SMOTE 적용 후 레이블 값 분포: \n", pd.Series(y_train_over).value_counts())

SMOTE 적용 전 학습용 피처/레이블 데이터 세트: (199364, 29) (199364,)
SMOTE 적용 후 학습용 피처/레이블 데이터 세트: (398040, 29) (398040,)
SMOTE 적용 후 레이블 값 분포: 
 1    199020
0    199020
Name: Class, dtype: int64

smote는 학습 데이터 세트에만 적용시켜야 합니다. smote을 적용하여 199364건->398040건으로 2배 가까이 증가했습니다. 이 데이터를 기반으로 모델을 실행하겠습니다.

 

#로지스틱
lr_clf=LogisticRegression()
get_model_train_eval(lr_clf, ftr_train=x_train_over,ftr_test=x_test, tar_train=y_train_over,tar_test=y_test)

오차 행렬
[[85281    14]
 [   57    91]]
정확도 0.9992, 정밀도 0.8667, 재현율 0.6149, F1:0.7194, AUC:0.9564
#LightGBM
lgbm_clf =LGBMClassifier(n_estimators=1000, num_leaves=64, n_jobs=-1, boost_from_average=False)
get_model_train_eval(lgbm_clf, ftr_train=x_train_over,ftr_test=x_test, tar_train=y_train_over,tar_test=y_test)

오차 행렬
[[85290     5]
 [   36   112]]
정확도 0.9995, 정밀도 0.9573, 재현율 0.7568, F1:0.8453, AUC:0.9790

smote 적용 후, 성능 결과를 보면 이전과 동일하거나 미비한 변화를 보입니다

서적에는 모델마다 변화량이 조금씩 달랐는데 제가 실습하는 동안의 성능 비교는 비슷하거나 변화가 없었습니다.

728x90
728x90

RNN을 적용해서 택시 수요예측을 진행하고 싶어서 계속 공부를 했습니다

케라스 창시자에게 배우는 딥러닝 책을 보면서 기온예측 실습이 있길래 쭉 훑어 봤는데

 

음.. 이해가 가질 않았습니다  

10분마다 나오는 센서 데이터를 가지고 기온을 예측해야 하는 내용인데 

 

책에서는 10일전 데이터로 돌아가는 lookback,  1시간마다 데이터 포인트 하나를 샘플링, 24시간이 지난 데이터가 타킷이 되는 delay 같은 개념이 나오는데 

 

아직 제 수준으로는 저자가 어떤 의도로 이렇게 했는데 이해가 가질 않더라구요.. 

그러다 보니 뒤에 내용도 당연히 모르겠고, 집중력이 흩어졌습니다 ;; 

 

사실 이책을 보기 전 부터 평소와 다르게 계속 졸아 버려서 집중력이 좋진 않았습니다 

공부를 분명 했는데 뭘 했는지 모른걸 보면 하는 둥 마는 둥 시간만 축 낸것같네요  내시간 돌리도 ㅠ

 

내일부터는 본격적으로 적용을 해야 할텐데 

아직 갈피를 못잡고 있어서 숨이 턱턱 막히네요 ㅎㅎ 

 

힘들수록 보람은 커지는 법이니까 

오늘 제대로 자고 내일은 집중력 있게 

해보겠습니다 !

728x90
728x90

택시 수요예측에 적용할 모델을 정하기 위해서 저번 주에 이어서 앙상블 기법을 공부했습니다 

Smote와 LightGBM을 기반한 신용카드 사기 검출 실습을 진행했죠

 

조금 많은 페이지였는데 중간마다 생각 좀 해야 할 부분들이 있어서 예상보다 진도를 많이 못 나간 것 같아요 

중요한 건 진도보다는 이해가 중요하니까 이번만큼은 시간에 쫓기지 않고 임하려고 합니다 

 

지금은 방법만을 배우고 있는 것 같아서 미완성이라는 느낌을 받습니다 

내가 쓰고있는 알고리즘이 수학적으로 어떻게 연결이 되고 작동이 되는지를 알아야 비로소 속이 좀 풀릴 것 같아요 지금은 많은 기법들을 실습하고 이해하는데만 꽤 많은 시간이 걸릴 것 같더라고요 정말 많~~ 은 기법들이 있어서 깜짝 놀랐습니다 잠시 딴 얘기로 넘어갔네요;  다시 본론으로 와서

 

실습을 끝난 후에는 카카오브레인의 TGnet을 다시 봤습니다 초보 지식으로는 이해하는데 무리가 있었고 적용하기에도 힘들 것 같더군요 

 

하지만 좀 깜짝놀랄만한 걸 알게 되었습니다 시간 안내 임베딩이라는 건데 

정말 사람처럼 시간적인 개념을 학습 시켜서 방대한 시퀀스 데이터가 필요 없게끔 만드는 기술인 것 같아요 

이런 개념이 딥러닝과 가깝다고 기재한 카카오브레인팀이 대단해 보였습니다 

 

덕분에 저도 딥러닝에 대해서 좀더 다른 시각을 바라볼 수 있는 눈이 생긴 것 같아서 기뻤습니다 

제 프로젝트에 이런 아이디어를 적용 할순 없는지 , 그리고 새로운 아이디어는 있는지 탐색을 하고 싶은 욕구가 오릅니다! 

 

스태킹 기법은 말로만 들었지 실제로 실습해본 건 오늘이 처음이었습니다

예측한 데이터를 기반으로 다시 예측하는 과정이 흥미로웠습니다:) 그런데 서적에서는 실제 현실에서는 잘 사용되지 않는다는 말에 좀 아쉬웠습니다 ㅠ 예측을 다시 예측한다는 개념이 현실에서는 잘 맞아떨어지지 않은가 봅니다 

 

그리고 문뜩 생각이 드는 게, 

예측을 100%로 끌어올리는 미지의 숫자가 있진 않을까 라는.. 

 

몇십 년 후 사람을 뛰어넘는 인공지능이 나왔을 때 

그 인공지능은 그 숫자를 찾아 내진 않을까 상상해봤습니다 

 

회귀에서 잡음은 어쩔 수 없는 현상이라고 배웠는데 이 잡음을 찾아내야 한다면 뭘 고려해야 할까 

평소에도 상상을 많이 하는 편이라서 공부하다가 나도 모르게 그쪽으로 빠집니다

 

아인슈타인? 잘 생각이 안 나지만 어느 수학자가 말하길 모든 현상은 수학적으로 표현 가능하다고 합니다

그러면 주식 예측이나 잡음처럼 예측하기 어려운 분야에 딱 들어맞는, 사회적 현상을 모두 고려한 최적의 숫자를 찾아낸다면 인공지능 개발자가 더이상 필요 없게 되진 않을까 합니다

 

공부 기록을 해야 하는데 적다 보면 맨날 생각의 흐름대로 흘러 가네요  

다음번엔 좀 더 공부 기록 다운 기록을 적어보도록 노력해 보겠습니다

 

오늘 실습한 내용은 매일 포스팅 작업 중입니다 ~ 이번주 안으로 완성해서 이 블로그 글에 url 남기겠습니다

728x90
728x90

Voting classifier

import pandas as pd
from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import seaborn as sns
import matplotlib.pyplot as plt

#데이터 불러오기
cancer = load_breast_cancer()

data_df= pd.DataFrame(cancer.data, columns=cancer.feature_names)
data_df.head()

* voting의 인자는 estimators, voting 
* estimators : 개별 분류기를 튜플로 담아 넣는다 
* voting : hard or soft  (defalt hard)

# 개별 분류기 객체 생성
lr_clf= LogisticRegression()
knn_clf=KNeighborsClassifier(n_neighbors=8)

#개별 모델을 앙상블 모델로 구현
#soft : 각 분류기에서 출력된 레이블의 확률을 평균 낸것들 가장 높은걸 최종결과값으로 선정
vo_clf =VotingClassifier(estimators=[("LR",lr_clf), ('KNN', knn_clf)], voting='soft')

x_train,x_test,y_train,y_test = train_test_split(cancer.data, cancer.target, test_size=0.2, random_state=156)

#votinclassifier 학습/예측/평가
vo_clf.fit(x_train, y_train)
pred=vo_clf.predict(x_test)
print('voting 분류기 정확도: {0:.4f}'.format(accuracy_score(y_test,pred)))

#개별 모델의 학습/예측/평가
classifiers= [lr_clf, knn_clf]
for classifier in classifiers:
  classifier.fit(x_train,y_train)
  pred=classifier.predict(x_test)
  class_name= classifier.__class__.__name__
  print('{0} 정확도: {1:.4f}'.format(class_name, accuracy_score(y_test,pred)))


랜덤포레스트

* 중첩되는 데이터 세트를 생성 (부트스트래핑)
* 부트스트랩: 통계학에서는 데이터 세트를 임의로 만들어서 개별 평균의 분포도를 측정하는 목적을 위한 샘플링 방식을 지칭
from sklearn.ensemble import RandomForestClassifier 

#데이터 분리
x_train,x_test,y_train,y_test = train_test_split(cancer.data, cancer.target, test_size=0.2, random_state=156)

#랜덤 포레스트 학습 및 별도의 테스트 세트로 예측 성능 평가
rf_clf=RandomForestClassifier(random_state=0)
rf_clf.fit(x_train,y_train)
pred=rf_clf.predict(x_test)
accuracy = accuracy_score(y_test,pred)
print('랜덤 포레스트 정확도:{0:.4f}'.format(accuracy))

랜덤포레스트(하이퍼 파라미터 및 튜닝)

from sklearn.model_selection import GridSearchCV

params={
    'n_estimators': [100],
    'max_depth':[6,8,10,12],
    'min_samples_leaf':[8,12,18],
    'min_samples_split':[8,16,20]
}
rf_clf = RandomForestClassifier(random_state=0, n_jobs=-1)
grid_cv= GridSearchCV(rf_clf, param_grid=params, cv=2, n_jobs=-1)
grid_cv.fit(x_train,y_train)

print('최적 하이퍼 파라미터: \n', grid_cv.best_params_)
print('최고 예측 정확도: {0:.4f}'.format(grid_cv.best_score_))


최적 하이퍼 파라미터: 
 {'max_depth': 6, 'min_samples_leaf': 8, 'min_samples_split': 8, 'n_estimators': 100}
최고 예측 정확도: 0.9451
new_rf_clf= RandomForestClassifier(random_state=0 , n_estimators=300, max_depth=6, min_samples_split=8, min_samples_leaf=8)
new_rf_clf.fit(x_train,y_train)
pred=new_rf_clf.predict(x_test)
accuracy=accuracy_score(y_test, pred)
print("램던 포레트스 정확도:{0:.4f}".format(accuracy))

램던 포레트스 정확도:0.9474

feature importance

ttr_importances_values= new_rf_clf.feature_importances_
feature_importances = pd.Series(ttr_importances_values, index= cancer.feature_names)
tfr_top20=feature_importances.sort_values(ascending=False)[:20]

plt.figure(figsize=(16,10))
plt.title('Feature importtances Top 20')
sns.barplot(x=tfr_top20, y=tfr_top20.index)
plt.show()


GBM(Gradiant boosting machine)

* 여러 개의 약한 학습기를 순차적으로 학습-예측 후 잘못 예측한 데이터에 가중치를 부여함으로써 오류개선
* 가중치 업데이트 방식은 경사 하강법이며 오류 값은 true-pred 값
* 오류값을 최소화하는 방향으로 도달
* 과적합에도 뛰어난 예측 성능 발휘, 수행시간의 증가

from sklearn.ensemble import GradientBoostingClassifier
import time

#데이터 불러오기
x_train,x_test,y_train,y_test = train_test_split(cancer.data, cancer.target, test_size=0.2, random_state=156)

#GBM 수행시간 측정을 위한 시작 시간 설정
start_time =time.time()

gb_clf=GradientBoostingClassifier(random_state=0)
gb_clf.fit(x_train,y_train)
pred=gb_clf.predict(x_test)
accuracy = accuracy_score(y_test, pred)

print('GBM 정확도: {0:.4f}'.format(accuracy))
print('GBM 수행시간: {0:.1f}초'.format(time.time()-start_time))


GBM 정확도: 0.9561
GBM 수행시간: 0.4초

GBM 하이퍼 파라미터 및 튜닝

params={
    'n_estimators':[100,200,300,400,500],
    'learning_rate':[0.05,0.1]
}
grid_cv= GridSearchCV(gb_clf, param_grid=params, cv=2, verbose=1)
grid_cv.fit(x_train,y_train)
pred=grid_cv.predict(x_test)

print('최적의 하이퍼 파라미터:\n', grid_cv.best_params_)
print('최고 예측 정확도:{0:.4f}'.format(grid_cv.best_score_))


최적의 하이퍼 파라미터:
 {'learning_rate': 0.1, 'n_estimators': 100}
최고 예측 정확도:0.9385
#GridSearchCV를 이용해 최적으로 학습된 estimator
gb_pred=grid_cv.best_estimator_.predict(x_test)
gb_accuracy = accuracy_score(y_test,gb_pred)
print("GBM 정확도:{0:.4f}".format(gb_accuracy))

GBM 정확도:0.9561

XGBoost

from xgboost import XGBClassifier

xgb_wrapper= XGBClassifier(n_estimators=400, learning_rate=0.1, max_depth=3)
                                  #early_stopping_rounds: 조기종료까지 최소반복횟수  
evals =[(x_test, y_test)]
xgb_wrapper.fit(x_train, y_train, early_stopping_rounds=100, eval_metric='logloss', eval_set=evals, verbose=True)
w_pred=xgb_wrapper.predict(x_test)
w_pred_proba= xgb_wrapper.predict_proba(x_test)[:,1]
def get_clf_eval(y_test,pred):
  from sklearn.metrics import f1_score, accuracy_score,precision_score,recall_score,confusion_matrix
  confusion = confusion_matrix(y_test, pred)
  accuracy= accuracy_score(y_test, pred)
  precision=precision_score(y_test, pred)
  recall= recall_score(y_test, pred)
  #F1스코어 추가
  f1 =f1_score(y_test,pred)
  print('오차 행렬')
  print(confusion)
  #f1 score print 추가
  print('정확도 {0:.4f}, 정밀도 {1:.4f}, 재현율 {2:.4f}, F1:{3:.4f}'.format(accuracy,precision,recall,f1))
 
get_clf_eval(y_test,pred)

오차 행렬
[[35  2]
 [ 3 74]]
정확도 0.9561, 정밀도 0.9737, 재현율 0.9610, F1:0.9673

feature importance

from xgboost import plot_importance
fig,ax = plt.subplots(figsize=(10,12))
plot_importance(xgb_wrapper, ax=ax)


LightGBM

* 균형트리를 추구하지 않고 최대 손실값을 가지는 리프 노드를 계속 분할하는 방식

from lightgbm import LGBMClassifier

lgbm_wrapper = LGBMClassifier(n_estimators=400)

#w조기 중단 설정
evals=[(x_test,y_test)]
lgbm_wrapper.fit(x_train,y_train,early_stopping_rounds=100, eval_metric='logloss', eval_set=evals, verbose=True)
preds= lgbm_wrapper.predict(x_test)
pred_proba= lgbm_wrapper.predict(x_test)

get_clf_eval(y_test,preds)

오차 행렬
[[33  4]
 [ 2 75]]
정확도 0.9474, 정밀도 0.9494, 재현율 0.9740, F1:0.9615

feature importance

#중요도 시각화
from lightgbm import plot_importance
# %matplotlib inline

fig,ax=plt.subplots(figsize=(10,12))
plot_importance(lgbm_wrapper,ax=ax)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90

+ Recent posts