본문 바로가기

TIL

[240216] 구매자 예측 모델링(실패한 코드)

* 자료 출처: Kaggle - Google Analytics Customer Revenue Prediction

 

1. 문제 배경

- GA 로그데이터를 활용해 구매자 예측 모델링 시도 

- 매출액 칼럼에서 NaN은 미구매로 간주하고 0, 매출액이 있는 값은 1로 대치 

- 데이터 분리, 인코딩 및 스케일링 작업 진행 

- 프로젝트 시간이 부족하여 추가 전처리 및 x변수 조정 작업하지 못하고 실패로 마무리 

 

2. 모델링

- 데이터 분리

from sklearn.model_selection import train_test_split

# 데이터를 train, test로 분리
X = df.drop(columns = ['Revenue_yn'])
y = df[['Revenue_yn']]

# 학습과 평가를 위해 데이터 셋 분리
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify = y, random_state= 42)

#분리된 데이터 차원 확인
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)

 

- 인코딩 및 스케일링

# 라벨 인코더(범주형): channelGrouping, device.deviceCategory, geoNetwork.country
# 스케일링 (수치형): totals.pageviews, totals.visits, totals.hits (기타 - 평균 세션 시간, 재방문 수 등)

from sklearn.preprocessing import LabelEncoder, StandardScaler

en_lb = LabelEncoder()
# 0: (Other) 1: Affiliates 2: Direct 3: Display 4: Organic Search 5: Paid Search, 6: Referral, 7: Social
df['channel_en'] = en_lb.fit_transform(df[['channelGrouping']])
# 0: desktop 1: mobile 2: tablet
df['deviceCategory_en'] = en_lb.fit_transform(df[['device.deviceCategory']])
# 0: (not set) 1: Africa 2: Americas 3: Asia 4: Europe 5: Oceania
df['continent_en'] = en_lb.fit_transform(df[['geoNetwork.continent']])

sc_sd = StandardScaler()
df['pageviews_sc'] = sc_sd.fit_transform(df[['totals.pageviews']])
df['visits_sc'] = sc_sd.fit_transform(df[['totals.visits']])
df['hits_sc'] = sc_sd.fit_transform(df[['totals.hits']])

df.describe(include='all')

 

- 모델링 학습 및 평가 

def get_score(train:pd.DataFrame,  test:pd.DataFrame, x_var_list:list):
    """ train과 test 데이터와 X변수 컬럼을 받아 평가지표를 내는 함수입니다.

    Args:
        train (pd.DataFrame): train 데이터프레임
        test (pd.DataFrame): test 데이터프레임
        x_var_list (list): 모델링에 사용할 변수 리스트
    """
    #외부 전달인자를 내부변수에 할당
    X_train = train 
    X_test = test

    #일부 컬럼만 가져오기
    X_train = X_train[x_var_list]
    X_test = X_test[x_var_list]
    
    #모듈불러오기
    from sklearn.linear_model import LogisticRegression
    from sklearn.tree import DecisionTreeClassifier
    from sklearn.ensemble import RandomForestClassifier
    from xgboost import XGBRFClassifier
    from sklearn.metrics import accuracy_score, f1_score
        
    #모델 가져오기
    model_log = LogisticRegression()
    model_dt = DecisionTreeClassifier(random_state=42)
    model_rf = RandomForestClassifier(random_state=42)
    model_xgb = XGBRFClassifier(random_state=42)

    #모델 학습하기
    model_log.fit(X_train, y_train)
    model_dt.fit(X_train, y_train)
    model_rf.fit(X_train, y_train)
    model_xgb.fit(X_train, y_train)
    
    # 학습하여 결과 저장
    y_pred_log_train = model_log.predict(X_train)
    y_pred_log_test = model_log.predict(X_test)

    y_pred_dt_train = model_dt.predict(X_train)
    y_pred_dt_test = model_dt.predict(X_test)

    y_pred_rf_train = model_rf.predict(X_train)
    y_pred_rf_test = model_rf.predict(X_test)

    y_pred_xgb_train = model_xgb.predict(X_train)
    y_pred_xgb_test = model_xgb.predict(X_test)

    #평가표 생성
    result = pd.DataFrame({'acc' : [accuracy_score(y_train, y_pred_log_train), accuracy_score(y_train, y_pred_dt_train), accuracy_score(y_train, y_pred_rf_train), accuracy_score(y_train, y_pred_xgb_train), 
                                    accuracy_score(y_test, y_pred_log_test),accuracy_score(y_test, y_pred_dt_test),accuracy_score(y_test, y_pred_rf_test),accuracy_score(y_test, y_pred_xgb_test)],
                            'f1_score' : [f1_score(y_train, y_pred_log_train),f1_score(y_train, y_pred_dt_train),f1_score(y_train, y_pred_rf_train),f1_score(y_train, y_pred_xgb_train), 
                                          f1_score(y_test, y_pred_log_test), f1_score(y_test, y_pred_dt_test), f1_score(y_test, y_pred_rf_test), f1_score(y_test, y_pred_xgb_test)]},
                            index=pd.MultiIndex.from_tuples([('train', 'logistic'),('train', 'dt'), ('train', 'rf'), ('train', 'XGB'),
                                                             ('test', 'logistic'),('test', 'dt'), ('test', 'rf'), ('test', 'XGB')]))
    

    display(result.round(2))

# duration 변수만 사용하여 결과내기
get_score(X_train, X_test, ['channel_en','deviceCategory_en','campaign_yn','newVisits_yn'])

 

> 결론: F1 스코어 0점으로 예측 모델링 실패 

 

 

3. 추후 과제 

- SMOTE 기법 활용한 오버샘플링 적용 

구매 비중이 전체의 1.3 %로 데이터 불균형이 심해 제대로된 학습이 어려웠을 것으로 추측

└ 정확도는 97%인데 반해 f1 스코어가 0점이라는 것에서도 데이터 불균형 문제가 여실히 드러남 

- 전체 평균 세션수가 1인 데이터는 제외해보는 등 모델링에 활용할 표본 범위를 조정하는 것도 방법이 될 듯