천지 경쟁 O2O 쿠폰 예측 + XGboost 사용 방법, AUC 0.5379
2월부터 천지 경기 코드를 봤는데 지금까지 거의 두 달 동안 기본적인 입문이라고 할 수 있습니다. 어떤 경기 절차인지 알고 혼자서 이리저리 굴러다녔습니다. 중간 과정은 매우 힘들었습니다. 여러 번 버그카드 때문에 며칠 동안 해결해 준 사람이 없어서 효율이 낮았습니다.
자, 본론으로 돌아가서 최근에 한 O2O 경연을 나눠보도록 하겠습니다.
천지 신인전에 등록한 후에 기술권에 가서 공부를 했습니다. 100줄 코드가 천지 O2O 쿠폰에 입문하여 신인전의 베이스라인을 사용하는 것을 보고 디버깅 코드를 가져왔습니다. 결과는 순조롭게 진행되었고 코드도 비교적 간단했습니다.특징 공정 처리를 거의 하지 않고 SGDClassifier 알고리즘을 사용했다. 마지막으로 AUC는 0.5287이고 랭킹은 412/13500으로 1위의 0.81과 차이가 매우 크다.
그래서 이를 바탕으로 코드 수정을 다시 하고 일부 특징을 추출하여 XGboost 알고리즘 모델을 이용하여 결과를 제출했다. 마지막으로 AUC는 0.5379로 60여 명, 350/13500에 랭크되었다.다음은 이번 코드를 공유하고 상세하게 해독하겠습니다.
import os, sys, pickle
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import seaborn as sns
from datetime import date
from sklearn.model_selection import KFold, train_test_split, StratifiedKFold, cross_val_score, GridSearchCV
from sklearn.pipeline import Pipeline
from sklearn.linear_model import SGDClassifier, LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import log_loss, roc_auc_score, auc, roc_curve
from sklearn.preprocessing import MinMaxScaler
import xgboost as xgb
#import xgboost as xgb
#import lightgbm as lgb
display for this notebook
%matplotlib inline %config InlineBackend.figure_format = ‘retina’
1: 데이터 세트 가져오기 대략적인 데이터 세트 보기dfoff = pd.read_csv("..\input\ccf_offline_stage1_train.csv",keep_default_na = False)
dftest = pd.read_csv("..\input\ccf_offline_stage1_test_revised.csv",keep_default_na = False)
dfon = pd.read_csv("..\input\ccf_online_stage1_train.csv",keep_default_na = False)
dfoff.head(5) # 5
dftest.head(5) # 5
이를 통해 알 수 있듯이 훈련 집합은 테스트 집합보다 한 열의Date가 많다. 우리가 해야 할 일은 훈련 훈련 집합의 데이터를 통해 마지막으로 테스트 집합을 통해 사용자가 소비할지 안 할지 예측하는 것이다.
본 대회 문제는 사용자가 2016년 1월 1일부터 2016년 6월 30일 사이에 실제 온·오프라인 소비 행위를 제공하고, 사용자가 2016년 7월 쿠폰을 수령한 후 15일 이내의 사용 상황을 예측한다.
데이터 세트 세척 방법 1: 부족한 값이 있는지 확인dfoff.isnull().sum().sort_values(ascending=False).head(10) #
Date 0 Date_received 0 Distance 0 Discount_rate 0 Coupon_id 0 Merchant_id 0 User_id 0 dtype: int64 dfoff.info() #
RangeIndex: 1754884 entries, 0 to 1754883 Data columns (total 7 columns): User_id int64 Merchant_id int64 Coupon_id object Discount_rate object Distance object Date_received object Date object dtypes: int64(2), object(5) memory usage: 93.7+ MB dfoff["Date_received"].unique() # Data_receive
dfoff["Date"].unique()
print(" , :" ,dfoff[(dfoff["Date_received"] != "null") & (dfoff["Date"] != "null")].shape[0])
print(' , :%d' % dfoff[(dfoff['Date_received'] != 'null') & (dfoff['Date'] == 'null')].shape[0])
print(' , :%d' % dfoff[(dfoff['Date_received'] == 'null') & (dfoff['Date'] != 'null')].shape[0])
print(' , :%d' % dfoff[(dfoff['Date_received'] == 'null') & (dfoff['Date'] == 'null')].shape[0])
쿠폰 있음, 구매 상품: 75382 쿠폰 있음, 미구매 상품: 977900 쿠폰 없음, 구매 상품: 701602 쿠폰 없음, 미구매 상품: 0#
print('1. User_id in training set but not in test set', set(dftest['User_id']) - set(dfoff['User_id']))
#
print('2. Merchant_id in training set but not in test set', set(dftest['Merchant_id']) - set(dfoff['Merchant_id']))
dfoff = pd.read_csv("..\input\ccf_offline_stage1_train.csv",keep_default_na = False)
dftest = pd.read_csv("..\input\ccf_offline_stage1_test_revised.csv",keep_default_na = False)
dfon = pd.read_csv("..\input\ccf_online_stage1_train.csv",keep_default_na = False)
dfoff.head(5) # 5
dftest.head(5) # 5
dfoff.isnull().sum().sort_values(ascending=False).head(10) #
dfoff.info() #
dfoff["Date_received"].unique() # Data_receive
dfoff["Date"].unique()
print(" , :" ,dfoff[(dfoff["Date_received"] != "null") & (dfoff["Date"] != "null")].shape[0])
print(' , :%d' % dfoff[(dfoff['Date_received'] != 'null') & (dfoff['Date'] == 'null')].shape[0])
print(' , :%d' % dfoff[(dfoff['Date_received'] == 'null') & (dfoff['Date'] != 'null')].shape[0])
print(' , :%d' % dfoff[(dfoff['Date_received'] == 'null') & (dfoff['Date'] == 'null')].shape[0])
#
print('1. User_id in training set but not in test set', set(dftest['User_id']) - set(dfoff['User_id']))
#
print('2. Merchant_id in training set but not in test set', set(dftest['Merchant_id']) - set(dfoff['Merchant_id']))
2: 세척 데이터 집합과 추출 특징 지식점 1: unique 함수는 몇 가지 유형을 볼 수 있습니까
지식점2: 데이터가 한 줄에 집중된 특징을 추출하려면 dfoff['중간 저장 제목']+.함수라는 형식.예: 아래
특징1: 할인율
우리는 첫 번째 특징이 바로 할인율이라고 생각했다. 할인 강도가 클수록 사용자가 쿠폰을 사용할 확률이 높다. 먼저 유니크 함수로 몇 가지 할인 유형이 있는지 살펴보자.
print('Discount_rate :',dfoff['Discount_rate'].unique())
Discount_rate 유형:[‘null’ ‘150:20’ ‘20:1’ ‘200:20’ ‘30:5’ ‘50:10’ ‘10:5’ ‘100:10’ ‘200:30’ ‘20:5’ ‘30:10’ ‘50:5’ ‘150:10’ ‘100:30’ ‘200:50’ ‘100:50’ ‘300:30’ ‘50:20’ ‘0.9’ ‘10:1’ ‘30:1’ ‘0.95’ ‘100:5’ ‘5:1’ ‘100:20’ ‘0.8’ ‘50:1’ ‘200:10’ ‘300:20’ ‘100:1’ ‘150:30’ ‘300:50’ ‘20:10’ ‘08.85'0.6','150:50','0.75','0.5','200:5','0.7','30:20','300:10','0.2','50:30','200:100','150:5'] 인쇄 결과에 따르면 할인 유형은 모두 3종이다.
첫 번째는 nan, 세일 없음
두 번째는 150:20으로 150원 차면 20원 감소.
세 번째는 0.95 할인. 0.95 할인.
따라서 다음과 같은 네 가지 특성을 추출할 수 있는 함수를 구축했습니다.
할인 유형: getDiscountType()
할인율:convertRate
가득 참: getDiscountMan
감량: getDiscountJian
# convert Discount_rate and Distance
def getDiscountType(row): # row
if row == 'null':
return 'null' #
elif ':' in row:
return 1 #
else:
return 0 #
def convertRate(row):
"""Convert discount to rate"""
if row == 'null': #
return 1.0
elif ':' in row:
rows = row.split(':')
return 1.0 - float(rows[1])/float(rows[0]) # ,
else:
return float(row) #
def getDiscountMan(row):
if ':' in row:
rows = row.split(':')
return int(rows[0]) # , row[0]
else:
return 0 # 0
def getDiscountJian(row):
if ':' in row:
rows = row.split(':')
return int(rows[1]) # , row[1]
else:
return 0 # 0
def processData(df): # processData,
# convert discunt_rate
df['discount_rate'] = df['Discount_rate'].apply(convertRate)# , Discount_rate
df['discount_man'] = df['Discount_rate'].apply(getDiscountMan)
df['discount_jian'] = df['Discount_rate'].apply(getDiscountJian)
df['discount_type'] = df['Discount_rate'].apply(getDiscountType)
print(df['discount_rate'].unique()) # discount_rate
# convert distance
df['distance'] = df['Distance'].replace('null', -1).astype(int)
return df
dfoff = processData(dfoff) # , processData ,
dftest = processData(dftest) # ,dftest
[1. 0.86666667 0.95 0.9 0.83333333 0.8 0.5 0.85 0.75 0.66666667 0.93333333 0.7 0.6 0.96666667 0.98 0.99 0.975 0.33333333 0.2 0.4 ] [0.83333333 0.9 0.96666667 0.8 0.95 0.75 0.98 0.5 0.86666667 0.6 0.66666667 0.7 0.85 0.33333333 0.94 0.93333333 0.975 0.99 ]
# , 4 "Date discount_rate","discount_man","discount_jian","discount_type"
dfoff.head(2)
#print('Distance :', dfoff['Distance'].unique())
데이터 세트 클리닝 2: 데이터 세트의 유형 변환 처리 "Distance"거리 열
#df['distance'] = df['Distance'].replace('null', -1).astype(int) # distance null -1,
#print(df['distance'].unique()) # distance
dftest.head(2) # ,
date_received = dfoff['Date_received'].unique() # data_received
date_received = sorted(date_received[date_received != 'null'])
date_buy = dfoff['Date'].unique()
date_buy = sorted(date_buy[date_buy != 'null'])
date_buy = sorted(dfoff[dfoff['Date'] != 'null']['Date'])
print(' ',date_received[0],' ', date_received[-1])
print(' ', date_buy[0], ' ', date_buy[-1])
쿠폰 수령일 20160101~20160615 소비일 20160101~20160630
특징2: 요일 특징을 추출하고 소비 시간은 요일과 관련이 있을 가능성이 더 높다.
def getWeekday(row): # getWeekday ,row
if row == 'null': # ,
return row
else:
return date(int(row[0:4]), int(row[4:6]), int(row[6:8])).weekday() + 1
# Date_received , , getWeekday , weekday
dfoff['weekday'] = dfoff['Date_received'].astype(str).apply(getWeekday)
dftest['weekday'] = dftest['Date_received'].astype(str).apply(getWeekday)
# weekday_type : 1, 0
dfoff['weekday_type'] = dfoff['weekday'].apply(lambda x : 1 if x in [6,7] else 0 )
dftest['weekday_type'] = dftest['weekday'].apply(lambda x : 1 if x in [6,7] else 0 )
dfoff.head()
데이터 집합 처리 방식 3: 원-hot 독열 인코딩 진행
# change weekday to one-hot encoding
weekdaycols = ['weekday_' + str(i) for i in range(1,8)]
print(weekdaycols) # weekdaycols
tmpdf = pd.get_dummies(dfoff['weekday'].replace('null', np.nan)) # one_hot
tmpdf.columns = weekdaycols #
dfoff[weekdaycols] = tmpdf
tmpdf = pd.get_dummies(dftest['weekday'].replace('null', np.nan)) # one_hot
tmpdf.columns = weekdaycols
dftest[weekdaycols] = tmpdf
dfoff.head()
[‘weekday_1’, ‘weekday_2’, ‘weekday_3’, ‘weekday_4’, ‘weekday_5’, ‘weekday_6’, ‘weekday_7’]
자, 상기 간단한 특징 추출을 통해 우리는 모두 14개의 유용한 특징을 얻었습니다:discountrate
discount_type
discount_man
discount_jian
distanceweek
distance
dayweekday_type
weekday_1
weekday_2
weekday_3
weekday_4
weekday_5
weekday_6
weekday_7
마크업 레이블 레이블
특징이 생긴 후에 우리는 훈련 견본에 대해 label 표시를 해야 한다. 즉, 어떤 것이 정견본(y=1)이고 어떤 것이 마이너스 견본(y=0)인지 확인해야 한다.우리가 예측해야 할 것은 사용자가 쿠폰을 받은 후 15 이내의 소비 상황이다.그래서 총 세 가지 상황이 있다.
1.Date_received == ‘null’:
쿠폰을 받지 못했다는 뜻이니 고려할 필요가 없다. y=-1
2.(Date_received != ‘null’) & (Date != ‘null’) & (Date - Date_received <= 15):
쿠폰을 수령하고 15일 이내에 사용한다는 뜻, 즉 정견본, y=1
3.(Date_received != ‘null’) & ((Date == ‘null’) | (Date - Date_received > 15)):
쿠폰 수령이 15일 이내에 사용되지 않음, 즉 마이너스 샘플, y=0
자, 규칙을 알게 되면 탭 비고 함수를 정의할 수 있습니다.
플러스 마이너스 샘플
def label(row): # label,row
if row['Date_received'] == 'null':
return -1 #Date_received , ,
if row['Date'] != 'null':
td = pd.to_datetime(row['Date'], format='%Y%m%d') - pd.to_datetime(row['Date_received'], format='%Y%m%d')
if td <= pd.Timedelta(15, 'D'): # 15 ,
return 1
return 0 # 15 ,
dfoff['label'] = dfoff.apply(label, axis = 1)
dfoff["label"].unique() #unique
array([-1, 0, 1], dtype=int64)
value_counts 함수는 각 유형의 개수를 통계하는 것이다
우리는 이 함수를 사용하여 훈련집에 표시를 해서 양과 음의 견본이 도대체 얼마나 많은지 볼 수 있다.
print(dfoff['label'].value_counts()) #
0 988887 -1 701602 1 64395 Name: label, dtype: int64
분명히 정본은 모두 64395건, 음본은 모두 988887건이다.분명히 플러스와 마이너스 견본의 수량 차이가 매우 크다.모델 성능 평가 기준으로 AUC를 사용하는 이유이기도 합니다.
dfoff.columns.tolist () 함수는 헤더를 보는 데 사용됩니다
print(' columns:',dfoff.columns.tolist()) #
이미 있는 columns:[‘User_id’, ‘Merchant_id’, ‘Coupon_id’, ‘Discount_rate’, ‘Distance’, ‘Date_received’, ‘Date’, ‘discount_rate’, ‘discount_man’, ‘discount_jian’, ‘discount_type’, ‘distance’, ‘weekday’, ‘weekday_type’, ‘weekday_1’, ‘weekday_2’, ‘weekday_3’, ‘weekday_4’, ‘weekday_5’, ‘weekday_6’, ‘weekday_7’, ‘label’]
dfoff.head(2)
셋째, 모형을 세우는 것은 다음으로 가장 주요한 기계 학습 모형을 세우는 것이다.먼저 우리가 선택한 특징은 위에서 추출한 14가지 특징이다. 모델의 성능을 검증하기 위해 검증집을 구분하여 모델 검증을 해야 한다. 구분 방식은 수령 날짜, 즉 훈련집: 20160101-20160515, 검증집: 20160516-20160615이다.우리는 XGboost 알고리즘을 채택했다
xgboost 1.훈련집과 검증집을 구분하여 얻은 결과에 주의하라predprob는 확률값이다.
마지막으로 검증 세트에 대해 AUC를 계산할 수 있습니다.sklearn 라이브러리에서 자체 계산한 AUC 함수를 직접 호출하면 됩니다.
# data split
df = dfoff[dfoff['label'] != -1].copy() # df
train = df[(df['Date_received'] < '20160516')].copy() #df 20160516
valid = df[(df['Date_received'] >= '20160516') & (df['Date_received'] <= '20160615')].copy() #df 20160516
print(train['label'].value_counts()) #
print(valid['label'].value_counts()) #
0 759172 1 41524 Name: label, dtype: int64 0 229715 1 22871 Name: label, dtype: int64
#train.head(5)
#valid.head(5)
y = train.label
#drop
# ,
X = train.drop(["User_id","Merchant_id","Coupon_id","Discount_rate","Distance","Date","Date_received","label"],axis=1)
val_y = valid.label
# ,
val_X = valid.drop(["User_id","Merchant_id","Coupon_id","Discount_rate","Distance","Date","Date_received","label"],axis=1)
# ,
tests = dftest.drop(["User_id","Merchant_id","Coupon_id","Discount_rate","Distance","Date_received"],axis=1)
val_X["weekday"].unique(),val_X["discount_type"].unique()
# , weekday discount_type object ,
(array([6, 1, 4, 3, 2, 7, 5], dtype=object), array([1, 0], dtype=object))
#astype
# weekday , int
X["weekday"] = X["weekday"].astype(int)
X["discount_type"] =X["discount_type"].astype(int)
val_X["weekday"]=val_X["weekday"].astype(int)
val_X["discount_type"]=val_X["discount_type"].astype(int)
tests["weekday"].unique()
array([2, 3, 5, 6, 7, 1, 4], dtype=int64)
val_X[“weekday”].unique () # 보기
array([6, 1, 4, 3, 2, 7, 5], dtype=int64)
#xgb
xgb_val = xgb.DMatrix(val_X,label=val_y) # xgb
xgb_train = xgb.DMatrix(X, label=y) # label xgb
xgb_test = xgb.DMatrix(tests) # xgb
xgb_val_X = xgb.DMatrix(val_X) # xgb
C:\ProgramData\Anaconda3\lib\site-packages\xgboost\core.py:587: FutureWarning: Series.base is deprecated and will be removed in a future version if getattr(data, ‘base’, None) is not None and C:\ProgramData\Anaconda3\lib\site-packages\xgboost\core.py:588: FutureWarning: Series.base is deprecated and will be removed in a future version data.base is not None and isinstance(data, np.ndarray)\
# (auc)
def myauc(test):
testgroup = test.groupby(["Coupon_id"])
aucs = []
for i in testgroup:
tmpdf = i[1]
if len(tmpdf['label'].unique()) != 2:
continue
fpr, tpr, thresholds = roc_curve(tmpdf['label'], tmpdf['pred'], pos_label=1)
aucs.append(auc(fpr, tpr))
return np.average(aucs)
XGboost 알고리즘 프레임워크
params = {'booster': 'gbtree',
#'objective': 'rank:pairwise',
'eval_metric': 'auc',
'gamma': 0.1,
'min_child_weight': 1.1,
'max_depth': 5,
'lambda': 10,
'subsample': 0.7,
'colsample_bytree': 0.7,
'colsample_bylevel': 0.7,
'eta': 0.01,
'tree_method': 'exact',
'seed': 0,
'nthread': 12
}
watchlist = [(xgb_train, 'train')]
model = xgb.train(params, xgb_train, num_boost_round=1000, evals=watchlist,early_stopping_rounds=100)
model.save_model('C:/Users/Administrator/o2o.code/notebook/xgbmodel')
model = xgb.Booster(params)
model.load_model('C:/Users/Administrator/o2o.code/notebook/xgbmodel')
val_X.head()
valid.head()
model = xgb.Booster()
model.load_model('C:/Users/Administrator/o2o.code/notebook/xgbmodel') #
temp = valid[["Coupon_id", "label"]].copy() # "Coupon_id", "label"
temp['pred'] = model.predict(xgb_val) #
temp.pred = MinMaxScaler(copy=True, feature_range=(0, 1)).fit_transform(temp['pred'].values.reshape(-1, 1))
print(myauc(temp)) # AUC
temp.head()
0.5518357641394374
tests.head()
val_X.head()
#predeict,
y_test = dftest[['User_id','Coupon_id',"Date_received"]].copy()
y_test['label'] = model.predict(xgb_test) #
#
y_test.to_csv("C:/Users/Administrator/o2o.code/notebook/second.csv", index=None, header=None)
y_test.head()
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.