用戶流失預(yù)測案例分析

image.png

本文是對攜程用戶流失預(yù)測案例的一個總結(jié)囚玫,主要任務(wù)是對客戶流失率進行建模分析喧锦,并挖掘出影響用戶流失的關(guān)鍵因素。

目錄:
● 項目介紹
● 問題分析
● 數(shù)據(jù)探索
● 特征工程
● 建模分析
● 總結(jié)

一劫灶、項目介紹

攜程作為中國領(lǐng)先的綜合性旅行服務(wù)公司裸违,每天向超過2.5億會員提供全方位的旅行服務(wù)掖桦,在這海量的網(wǎng)站訪問量中本昏,我們可分析用戶的行為數(shù)據(jù)來挖掘潛在的信息資源。其中枪汪,客戶流失率是考量業(yè)務(wù)成績的一個非常關(guān)鍵的指標涌穆。數(shù)據(jù)是由攜程官方提供的經(jīng)過脫敏處理的一周用戶訪問數(shù)據(jù),不包含用戶ID等信息雀久,目的是為了深入了解用戶畫像及行為偏好宿稀,找到最優(yōu)算法,挖掘出影響用戶流失的關(guān)鍵因素赖捌。

二矮烹、 問題分析

這個項目要解決的問題是關(guān)于用戶流失的竭恬,在官方提供的字段和解釋中,有一個label字段预烙,這個是目標變量,也就是我們需要進行預(yù)測的值沙兰。label=1代表客戶流失斋射,label=0代表客戶未流失化借,很顯然這是個分類的預(yù)測問題倒信。

對于本項目而言乘综,最終的評價標準是要求在精確度達到97%的情況下套硼,最大化召回率卡辰。從業(yè)務(wù)角度這個評價標準很好理解,平臺一定不允許有客戶流失的情況發(fā)生邪意,但是挽回可能流失的客戶需要成本九妈,所以要求召回率盡可能高。

如無特別說明雾鬼,一般用的是PR曲線和ROC曲線萌朱。ROC曲線有一個突出優(yōu)勢,就是不受樣本不均衡的影響策菜。

三晶疼、 數(shù)據(jù)探索

1、數(shù)據(jù)總體情況

官方共提供2個數(shù)據(jù)集,分別為訓(xùn)練集userlostprob_train.txt和測試集userlostprob_test.txt摔桦。訓(xùn)練集為2016.05.15-2016.05.21期間一周的訪問數(shù)據(jù),測試集為2016.05.22-2016.05.28期間一周的訪問數(shù)據(jù)。本文采用測試集數(shù)據(jù)宁玫,為保護客戶隱私,不提供uid等信息笤成。數(shù)據(jù)經(jīng)過了脫敏,和實際商品的訂單量蒋情、瀏覽量、轉(zhuǎn)化率等有一些差距耸携,但是不會影響這個問題的可解性棵癣。

數(shù)據(jù)共有51個字段,除了目標變量label夺衍,還有50個特征狈谊。


image.png

拿到一份數(shù)據(jù),首先要做的是基于業(yè)務(wù)情況沟沙,理解每個字段背后的含義河劝。在特征變量超過10個的情況,一般要先對其進行分類矛紫。通過觀察和業(yè)務(wù)情況赎瞎,我將該數(shù)據(jù)大概分成三類:客戶行為指標、訂單指標和酒店指標如下圖颊咬。當然我也參考了網(wǎng)絡(luò)上一些大神的分類务甥,可能還是存在一些偏差。訂單相關(guān)的指標:如入住日期喳篇、訂單數(shù)敞临、取消率等;客戶行為相關(guān)的指標:如星級偏好麸澜、用戶偏好價格等哟绊;酒店相關(guān)的指標,如酒店評分均值痰憎、酒店評分人數(shù)票髓、平均價格等。


攜程案例思維導(dǎo)圖.jpg

從字段的描述信息來看铣耘,可以得到以下異常信息:
某些特征列存在不同程度的缺失洽沟;
有的特征列存在極值的情況,后面在進行缺失值填充的時候需要注意分布形態(tài)蜗细,另外對極值也需要處理一下裆操,減小異常點對預(yù)測的影響;
類似'delta_price'等代表價格的特征存在負值炉媒,這屬于異常情況踪区,后面需要對負值進行處理。


image.png
na_rate = (len(df)-df.count())/len(df)  # 缺失率計算
a = na_rate.sort_values(ascending=False)
a1 = pd.DataFrame(a)
plt.style.use('bmh')
plt.figure(figsize = (10,12))
plt.barh(range(df.shape[1]),a1[0])
plt.xlabel('na_rate')
plt.xlim([0,1])
plt.yticks(range(df.shape[1]),a1.index.values.tolist())
for x,y in enumerate(a1[0]):
    plt.text(y,x,'%.3f'%y, va='bottom')
image.png

2吊骤、各特征的分布
查看所有數(shù)值型特征的分布情況缎岗,一方面有利于特征工程中根據(jù)數(shù)據(jù)分布合理選用處理方法,包括異常值白粉、缺失值處理传泊,連續(xù)特征離散化處理鼠渺;另一方面有助于深入了解用戶行為。

for i in range(4,50):
    plt.hist(df[df.columns[i]].dropna().get_values())
    plt.xlabel(df.columns[i])
    plt.show()

忽略兩端極值的影響眷细,可以把businessrate_pre拦盹、businessrate_pre2、cancelrate_pre這3個特征近似看作正態(tài)分布溪椎,使用平均值填充缺失值普舆。
諸如starprefer、consuming_capacity校读、price_sensitive這些特征奔害,近似看作偏態(tài)分布,可以使用中位數(shù)填充缺失值地熄。

四华临、 特征工程

數(shù)據(jù)和特征決定了機器學(xué)習(xí)效果的上限,而模型和算法只是逼近這個上限端考。特征工程是建模前的關(guān)鍵步驟雅潭,特征處理得好,可以提升模型的性能却特。

整個特征工程的任務(wù)主要包括:格式轉(zhuǎn)換扶供、缺失值處理、衍生特征裂明、聚類特征椿浓、獨熱編碼、標準化等闽晦。

1扳碍、時間特征處理

(1)格式轉(zhuǎn)換

時間特征不存在缺失值,可以先處理仙蛉。訪問日期d和入住日期arrival是字符串格式笋敞,需要進行格式轉(zhuǎn)換。這里使用pandas中常用的時間函數(shù)to_datetime()荠瘪,將字符串格式轉(zhuǎn)換為日期格式夯巷。

df['d'] = pd.to_datetime(df['d'], format = '%Y-%m-%d')
df['arrival'] = pd.to_datetime(df['arrival'], format='%Y-%m-%d')

(2)衍生特征

衍生特征是根據(jù)現(xiàn)有特征衍生出來的一些特征,比如訪問日期和實際入住日期之間的差值哀墓,入住日期是周幾趁餐,入住日期否為周末。在機器學(xué)習(xí)中篮绰,是否為周末這個特征往往是非常重要的后雷。

# 查看用戶周幾入住
df['week2day'] = df['arrival'].map(lambda x: x.weekday())
# 查看用戶入住日期與訪問(預(yù)訂)日期的差值
df['booking_gap'] = (df['arrival'] -df['d']).map(lambda x: x.days).astype(int)
# 查看用戶入住的日期是否為周末
def is_weekend(a):
    if int(a) in [0,1,2,3,4]:
        return 0 # 0代表是工作日
    else:
        return 1 # 1代表是周末
df['is_weekend'] = df['week2day'].apply(is_weekend)

使用完這兩個時間特征之后,和sampleid一起刪除,這些特征對預(yù)測用戶流失沒有實質(zhì)的幫助喷面。

df.drop(['d','arrival','sampleid'],axis=1,inplace=True)  # 刪除特征

2星瘾、異常值處理

用戶偏好價格delta_price1走孽、delta_price2惧辈,以及當前酒店可訂最低價lowestprice存在大量的負值,理論上酒店的價格不可能為負磕瓷。同時數(shù)據(jù)分布比較集中盒齿,因此采取中位數(shù)填充。而客戶價值customer_value_profit困食、ctrip_profits也不應(yīng)該為負值边翁,這里將其填充為0。deltaprice_pre2_t1是酒店價格與對手價差均值硕盹,可以為負值符匾,無需處理。

# 查看最小值為負值的特征
df_min=df.min().iloc[4:]
df_min[df_min<0]
image.png
neg1=['delta_price1','delta_price2','lowestprice']
neg2=['customer_value_profit','ctrip_profits']
for col in neg1:
    df.loc[df[col]<0,col]=df[col].median()  # 填充中位數(shù)
for col in neg2:
    df.loc[df[col]<0,col]=0  # 填充0

3瘩例、缺失值處理

缺失值全部為數(shù)值型數(shù)據(jù)啊胶,結(jié)合各個特征的數(shù)據(jù)分布情況,這里用了平均值和中位數(shù)填充兩種方式垛贤。對于近似正態(tài)分布的數(shù)據(jù)焰坪,采用平均值填充,而近似偏態(tài)分布的數(shù)據(jù)聘惦,以及其他數(shù)值型數(shù)據(jù)某饰,全部采用中位數(shù)填充。缺失率在80%以上的善绎,如historyvisit_7ordernum黔漂,已經(jīng)沒有太多分析價值,直接去掉禀酱。

df=df.drop('historyvisit_7ordernum',axis=1)  # 刪除特征
fillwithmean=['businessrate_pre','businessrate_pre2','cancelrate_pre']
for col in df.columns:
    if col in fillwithmean:
        fillvalue = df[col].mean()
        df[col] = df[col].fillna(fillvalue)  # 填充平均值
    else:
        fillvalue = df[col].median()
        df[col] = df[col].fillna(fillvalue)  # 填充中位數(shù)

4瘟仿、聚類特征

在實際行為中用戶ID對我們的分析流失起到重要的作用,但是由于數(shù)據(jù)敏感性問題比勉,樣本數(shù)據(jù)中并沒有給出劳较,但是我們可以通過將一些特征信息進行聚類,對這些樣本進行用戶分組浩聋,同理也可對酒店分組观蜗。把這兩類主體進行一個聚類,并把類的標簽作為一個新的特征衣洁。這里使用KMeans的方法做聚類處理墓捻,分別將用戶和酒店分成3個類別。

# 標準化
from sklearn.preprocessing import StandardScaler #標準化
ss = StandardScaler()
# 用戶聚類
from sklearn.cluster import KMeans
user_group = df[['historyvisit_totalordernum','ordercanncelednum','ordercanceledprecent','historyvisit_visit_detailpagenum','historyvisit_avghotelnum','lowestprice_pre']]
for i in range(len(user_group.columns)):
   user_group[user_group.columns[i]] = ss.fit_transform(user_group[user_group.columns[i]].values.reshape(-1,1))  # reshape(-1,1)將array轉(zhuǎn)換為一列
# 酒店聚類
hotel_group = df[['commentnums','novoters','cancelrate','hoteluv','hotelcr','lowestprice']]
for i in range(len(hotel_group.columns)):
   hotel_group[hotel_group.columns[i]] = ss.fit_transform(hotel_group[hotel_group.columns[i]].values.reshape(-1,1))
df['user_type'] = KMeans(n_clusters=3, init='k-means++').fit_predict(user_group)  # KMeans方法,分3類
df['hotel_type'] = KMeans(n_clusters=3, init='k-means++').fit_predict(hotel_group)  # KMeans方法砖第,分3類

5撤卢、連續(xù)特征離散化

在這個案例中,將某些數(shù)值型特征轉(zhuǎn)換成類別呈現(xiàn)更有意義梧兼,比如用戶決策習(xí)慣放吩、星級偏好、平均價格羽杰、消費能力指數(shù)等渡紫,同一類別表現(xiàn)出相似的屬性。同時可以使得算法減少噪聲的干擾考赛。而且在機器學(xué)習(xí)中惕澎,一般很少直接將連續(xù)值作為邏輯回歸模型的特征輸入。特征離散化以后颜骤,可以簡化邏輯回歸模型唧喉,降低了模型過擬合的風(fēng)險。后面會用到邏輯回歸模型忍抽,所以在這里還是先做離散化處理八孝。

根據(jù)業(yè)務(wù)經(jīng)驗選擇合適的連續(xù)型特征,在一定的數(shù)值范圍內(nèi)劃分分區(qū)梯找。

def deal_decisionhabit_user(x):
    if x<10:
        return 0
    elif x<30:
        return 1
    else:
        return 2
def deal_starprefer(x):
    if x<50:
        return 0
    elif x<80:
        return 1
    else:
        return 2
def deal_avgprice(x):
    if  x<400:
        return 0
    elif x<1000:
        return 1
    else:
        return 2
def deal_consuming_capacity(x):
    if  x<40:
        return 0
    elif x<80:
        return 1
    else:
        return 2

離散化之后的特征唆阿,以及酒店和用戶這兩個聚類特征,均為數(shù)值型锈锤,都需要轉(zhuǎn)換為字符串型驯鳖,以便接下來進行獨熱編碼。

df['decisionhabit_user'] = df['decisionhabit_user'].map(lambda x:str(deal_decisionhabit_user(int(x))))
df["starprefer"] = df["starprefer"].map(lambda x:str(deal_starprefer(int(x))))
df["consuming_capacity"] = df["consuming_capacity"].map(lambda x: str(deal_consuming_capacity(int(x))))
df['avgprice'] = df['avgprice'].map(lambda x: str(deal_avgprice(int(x))))
df[["user_type","hotel_type"]]=df[["user_type","hotel_type"]].applymap(str)

6久免、分類變量one-hot-encode

對分類變量進行獨熱編碼浅辙,可以解決分類器不好處理屬性數(shù)據(jù)的問題,編碼后的特征都可以看做是連續(xù)的特征阎姥,并且在一定程度上也起到了擴充特征的作用记舆。這里使用get_dummies方法實現(xiàn)one-hot-encode。

df=pd.get_dummies(df)

7呼巴、用戶分組特征

由于數(shù)據(jù)集沒有提供用戶uid泽腮,需要根據(jù)已有特征對用戶進行分組,生成用戶標簽usertag衣赶。這里采取了一種近似的方法诊赊,如果用戶的某些行為特征相同,則認為是同一個用戶的行為府瞄。后面需要根據(jù)用戶標簽分割數(shù)據(jù)集碧磅,同一個用戶的信息不能同時出現(xiàn)在訓(xùn)練集和測試集中,否則模型會過擬合。

這里用于判斷是否為同一用戶行為的特征有:用戶一年內(nèi)取消訂單數(shù)鲸郊、近3個月用戶歷史日均訪問酒店數(shù)丰榴、用戶年訂單數(shù)、客戶價值_近1年秆撮、客戶價值四濒、用戶轉(zhuǎn)化率、年訪問次數(shù)像吻,并且使用hash函數(shù)處理字符串峻黍。

df['usertag']= df.ordercanncelednum.map(str) \
+ df.historyvisit_avghotelnum.map(str) \
+ df.ordernum_oneyear.map(str) \
+ df.customer_value_profit.map(str) \
+ df.ctrip_profits.map(str) \
+ df.cr.map(str) \
+ df.visitnum_oneyear.map(str)
df.usertag = df.usertag.map(lambda x: hash(x))  # 生成哈希值

8复隆、標準化

對于一些基于距離的模型拨匆,需要標準化處理,比如回歸分析挽拂、神經(jīng)網(wǎng)絡(luò)惭每、SVM。

而對于與距離計算無關(guān)的樹模型亏栈,不需要標準化處理台腥,比如決策樹、隨機森林等绒北,因為樹中節(jié)點的選擇只關(guān)注當前特征在哪里切分對分類更好黎侈,即只在意特征內(nèi)部的相對大小,而與特征間的相對大小無關(guān)闷游。

這里還是標準化處理下峻汉,后面會用到不同的模型做對比。注意只用對部分數(shù)值型特征進行標準化脐往,label列(0/1)休吠、新生成的獨熱編碼(0/1)、用戶標簽usertag無需參與標準化业簿。所以先對數(shù)據(jù)進行拆分瘤礁,處理之后再使用concat合并。

df1=df
df2=pd.DataFrame(df1['label'])  # label
df3=df1.iloc[:,1:-24]  # 需要標準化的特征
df4=df1.iloc[:,-24:] # 獨熱編碼和用戶標簽
columns=df3.columns.tolist()  # 提取df3的列名梅尤,存放在列表中
# 對拆分后的df3進行標準化
scaler = StandardScaler()
scaler.fit(df3)
df3=scaler.transform(df3)
df3=pd.DataFrame(df3,columns=columns)  # 標準化處理后的數(shù)據(jù)是array柜思,轉(zhuǎn)換為DataFrame
df_concat1=pd.concat([df2,df3],axis=1) # 與df2合并  
df_concat2=pd.concat([df_concat1,df4],axis=1)   # 與df4合并  
df_new=df_concat2  # 生成新的DataFrame

8、分割數(shù)據(jù)集

在使用數(shù)據(jù)集訓(xùn)練模型之前巷燥,我們需要先將整個數(shù)據(jù)集分為訓(xùn)練集赡盘、驗證集、測試集矾湃。訓(xùn)練集是用來訓(xùn)練模型的亡脑,通過嘗試不同的方法和思路使用訓(xùn)練集來訓(xùn)練不同的模型,再通過驗證集使用交叉驗證來挑選最優(yōu)的模型,通過不斷的迭代來改善模型在驗證集上的性能霉咨,最后再通過測試集來評估模型的性能蛙紫。

由于官方提供的數(shù)據(jù)已經(jīng)劃分好訓(xùn)練集和測試集,我們現(xiàn)在需要在原始訓(xùn)練集中劃分出訓(xùn)練集和驗證集途戒,這里是70%劃分為訓(xùn)練集坑傅,30%劃分為驗證集。

那究竟依據(jù)什么特性進行劃分呢喷斋?劃分數(shù)據(jù)集需注意時間性唁毒、地域性、層次性(stratifiedKFold)星爪。前面已經(jīng)提到過浆西,在做本地數(shù)據(jù)集劃分的時候需要基于用戶進行劃分,也就是要保證劃分前后的數(shù)據(jù)是滿足獨立同分布的顽腾。另外近零,由于提供的是一周的數(shù)據(jù),時間序列特性不是很明顯抄肖,所以沒有按時間線對數(shù)據(jù)進行劃分久信。

splitnum=int(len(df_new.index)* 0.7)  # 分割點:70%
df_new=df_new.sort_values(by="usertag")  # 按照usertag排序
# 前70%行數(shù)據(jù)生成訓(xùn)練集
df_new.iloc[:splitnum,].to_csv(r'data/userlostprob_train.csv', sep='\t', index=False)
# 其余數(shù)據(jù)生成測試集
df_new.iloc[splitnum:, ].to_csv(r'data/userlostprob_test.csv', sep='\t', index=False)

五、建模分析

對于一個分類問題漓摩,一般經(jīng)常使用的模型有邏輯回歸裙士、隨機森林、xgboost管毙。在正常的情況下腿椎,xgboost會比隨機森林效果更好,但是如果數(shù)據(jù)的噪聲比較大的話锅风,也會出現(xiàn)隨機森林的效果更好的情況酥诽。為了比較不同模型在這個分類問題中的性能表現(xiàn),這里使用了三個模型分別訓(xùn)練和評估皱埠。

導(dǎo)入包肮帐,使用sklearn庫完成建模分析。

from sklearn.metrics import precision_recall_curve
from sklearn.metrics import accuracy_score
from sklearn import metrics
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import GridSearchCV
from sklearn.feature_selection import SelectFromModel

導(dǎo)入處理后的數(shù)據(jù)集边器,并刪除usertag標簽训枢。

train=r'data/userlostprob_train.csv'
test=r'data/userlostprob_test.csv'
trainData = pd.read_csv(train,sep="\t").drop(["usertag"],axis=1)
testData = pd.read_csv(test,sep="\t").drop(["usertag"],axis=1)

從訓(xùn)練集和測試集中分別提取特征和目標變量label,訓(xùn)練模型后忘巧,用測試集評估模型的性能恒界。

train_X = trainData.iloc[:,1:]  # 特征從第1列開始選
train_Y = trainData.iloc[:,0]  # 第0列是label
test_X = testData.iloc[:,1:]
test_Y = testData.iloc[:,0]

1、邏輯回歸模型

(1)導(dǎo)入模型

from sklearn import linear_model
from sklearn.linear_model import LogisticRegression

(2)模型性能評估

輸出準確率accuracy砚嘴、AUC面積以及精確度precision≥0.97條件下的最大召回率recall十酣。

lr = LogisticRegression()
lr.fit(train_X,train_Y)  # 訓(xùn)練模型
test_pred_lr = lr.predict_proba(test_X)[:,1]  # 預(yù)測為1的可能性
fpr_lr,tpr_lr,threshold = metrics.roc_curve(test_Y,test_pred_lr)
auc = metrics.auc(fpr_lr,tpr_lr)
score = metrics.accuracy_score(test_Y,lr.predict(test_X))  # 輸入真實值和預(yù)測值
print([score,auc])  # 準確率涩拙、AUC面積
precision_lr, recall_lr, thresholds = precision_recall_curve(test_Y, test_pred_lr)
pr_lr = pd.DataFrame({"precision": precision_lr, "recall": recall_lr})
prc_lr = pr_lr[pr_lr.precision >= 0.97].recall.max()
print(prc_lr)  # 精確度≥0.97條件下的最大召回率
image.png

邏輯回歸模型過于簡單,預(yù)測準確率比較低耸采,在precision≥0.97的情況下兴泥,最大recall僅為0.0001。

2虾宇、隨機森林模型

(1)導(dǎo)入分類器

from sklearn.ensemble import RandomForestClassifier

(2)模型性能評估

輸出準確率accuracy搓彻、AUC面積以及精確度precision≥0.97條件下的最大召回率recall。

rfc = RandomForestClassifier(n_estimators=200)
rfc.fit(train_X,train_Y)  # 訓(xùn)練模型
test_pred_rfc = rfc.predict_proba(test_X)[:,1]  # 預(yù)測為1的可能性
fpr_rfc,tpr_rfc,thre_rfchold = metrics.roc_curve(test_Y,test_pred_rfc)
auc = metrics.auc(fpr_rfc,tpr_rfc)
score = metrics.accuracy_score(test_Y,rfc.predict(test_X))  # 輸入真實值和預(yù)測值
print([score,auc])  # 準確率嘱朽、AUC面積
precision_rfc, recall_rfc, thresholds = precision_recall_curve(test_Y, test_pred_rfc)
pr_rfc = pd.DataFrame({"precision": precision_rfc, "recall": recall_rfc})
prc_rfc = pr_rfc[pr_rfc.precision >= 0.97].recall.max()
print(prc_rfc)  # 精確度≥0.97條件下的最大召回率

[0.90051888068642982, 0.95880960471941379]

0.636531495094

對于這個項目旭贬,隨機森林模型表現(xiàn)較好,迭代200次以后模型準確率0.900搪泳,在precision≥0.97的情況下稀轨,最大recall已經(jīng)可以達到0.636。

(3)特征重要性

使用feature_importance方法森书,可以得到特征的重要性排序靶端。當然谎势,還可以使用plot_importance方法凛膏,默認的importance_type=“weight”,將其設(shè)置為“gain”脏榆,可以得到和feature_importance方法相同的結(jié)果猖毫。

importance = rfc.feature_importances_
indices = np.argsort(importance)[::-1]  # np.argsort()返回數(shù)值升序排列的索引,[::-1]表示倒序
features = train_X.columns
for f in range(train_X.shape[1]):
    print("%2d) %3d %20s (%.4f)" %(f+1,indices[f],features[indices[f]], importance[indices[f]]))
# 作圖
plt.figure(figsize=(15,8))
plt.title('Feature importance')
plt.bar(range(train_X.shape[1]),importance[indices],color='blue')
plt.xticks(range(train_X.shape[1]),indices)
plt.xlim([-1,train_X.shape[1]])
plt.show()
1.jpg

在前15個特征中须喂,用戶相關(guān)的指標有:年訪問次數(shù)吁断、訪問時間點、一年內(nèi)距上次訪問時長坞生、用戶轉(zhuǎn)化率仔役、一年內(nèi)距離上次下單時長、提前預(yù)定時間是己、用戶價值又兵。酒店相關(guān)的指標有:24小時內(nèi)已訪問酒店商務(wù)屬性指數(shù)均值、24小時內(nèi)已訪問酒店可訂最低價均值卒废、24小時歷史瀏覽次數(shù)最多酒店歷史uv沛厨、24小時內(nèi)已訪問次數(shù)最多酒店可訂最低價、24小時歷史瀏覽酒店歷史uv均值摔认。城市相關(guān)的指標:昨日提交當前城市同入住日期的app訂單數(shù)逆皮、昨日訪問當前城市同入住日期的app uv數(shù)。


2.jpg

(4)篩選特征

根據(jù)特征重要性結(jié)果挑選特征参袱,重新進行模型訓(xùn)練和評估电谣。這里篩選的閾值設(shè)定為0.005秽梅。不過篩選特征后模型性能沒有得到明顯提升。

selection = SelectFromModel(rfc, threshold=0.005, prefit=True)
select_train_X = selection.transform(train_X)
select_test_X = selection.transform(test_X)

3剿牺、xgboost模型

(1)導(dǎo)入分類器

import xgboost as xgb
from xgboost.sklearn import XGBClassifier

(2)模型調(diào)參

使用GridSearchCV(網(wǎng)格搜索)的方法調(diào)節(jié)xgboost模型的參數(shù)风纠,主要的影響參數(shù)有樹的最大深度、最小葉子節(jié)點樣本權(quán)重和牢贸、懲罰項系數(shù)gamma竹观、使用數(shù)據(jù)占比、使用特征占比潜索。這里分步調(diào)節(jié)臭增,尋找最優(yōu)參數(shù)。

param_test1 = {
    'max_depth': range(3, 10, 2),
    'min_child_weight': range(1, 6, 2)}
param_test2 = {
    'gamma': [i / 10.0 for i in range(0, 5)]}
param_test3 = {
    'subsample': [i / 10.0 for i in range(6, 10)],
    'colsample_bytree': [i / 10.0 for i in range(6, 10)]}
gsearch = GridSearchCV(estimator=XGBClassifier(learning_rate =0.1, n_estimators=1000, max_depth=5,min_child_weight=1, gamma=0, subsample=0.8,  colsample_bytree=0.8, objective= 'binary:logistic', nthread=1, scale_pos_weight=1, seed=27),param_grid =param_test1,scoring='roc_auc',n_jobs=1,iid=False, cv=5)
gsearch.fit(train_X ,train_Y )
means = gsearch.cv_results_['mean_test_score']
params = gsearch.cv_results_['params']
print(means, params)
# 模型最好的分數(shù)竹习、模型最好的參數(shù)誊抛、模型最好的評估器
print(gsearch.best_score_ ,gsearch.best_params_,gsearch.best_estimator_)

(3)模型性能評估

使用上一步找到的最優(yōu)參數(shù)組合,代入模型進行訓(xùn)練和評估整陌。輸出準確率accuracy拗窃、AUC面積以及精確度precision≥0.97條件下的最大召回率recall。

model = XGBClassifier(base_score=0.5, booster='gbtree', colsample_bylevel=1,
                        colsample_bytree=0.8, gamma=0, learning_rate=0.1, max_delta_step=0,
                        max_depth=9, min_child_weight=1, missing=None, n_estimators=1000,
                        reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=27, silent=True,
                        subsample=0.9)
model.fit(train_X ,train_Y)  # 訓(xùn)練模型
test_pred_xgb = model.predict_proba(test_X)[:,1]  # 預(yù)測為1的可能性
fpr_xgb,tpr_xgb,threshold = metrics.roc_curve(test_Y,test_pred_xgb)
auc = metrics.auc(fpr_xgb,tpr_xgb)
score = metrics.accuracy_score(test_Y,model.predict(test_X))  # 輸入真實值和預(yù)測值
print([score,auc])  # 準確率泌辫、AUC面積
precision_xgb, recall_xgb, thresholds = precision_recall_curve(test_Y, test_pred_xgb)
pr_xgb = pd.DataFrame({"precision": precision_xgb, "recall": recall_xgb})
prc_xgb = pr_xgb[pr_xgb.precision >= 0.97].recall.max()
print(prc_xgb)  # 精確度≥0.97條件下的最大召回率

[0.9064082247903219, 0.95434695969275529]

0.587697393873

迭代1000次之后随夸,得到的模型準確率0.906阅悍,在precision≥0.97的情況下绷跑,最大recall可以達到0.587。

(4)特征重要性

從xgboost模型也可以得到影響用戶流失的特征盆犁,按照重要性排序殿遂,有24小時內(nèi)是否訪問訂單填寫頁诈铛、提前預(yù)訂時間、用戶轉(zhuǎn)化率墨礁、用戶決策幢竹、訪問時間點、用戶年訂單數(shù)恩静、當前酒店歷史cr焕毫、用戶類型、24小時內(nèi)已訪問酒店商務(wù)屬性指數(shù)均值等蜕企。

其中酒店相關(guān)的指標有:當前酒店歷史cr咬荷、24小時內(nèi)已訪問酒店商務(wù)屬性指數(shù)均值。用戶相關(guān)的指標有:24小時內(nèi)是否訪問訂單填寫頁轻掩、提前預(yù)訂時間幸乒、用戶轉(zhuǎn)化率、用戶決策唇牧、訪問時間點罕扎、用戶年訂單數(shù)聚唐、用戶類型。

使用隨機森林模型和xgboost模型得到的在top10特征差異較大腔召,重合的特征只有4個杆查,訪問時間點、提前預(yù)訂時間臀蛛、用戶轉(zhuǎn)化率亲桦、24小時內(nèi)已訪問酒店商務(wù)屬性指數(shù)均值。

3.jpg

4.jpg

接下來看下隨機森林和xgboost模型的ROC曲線和PR曲線浊仆,綜合比較模型性能客峭。
5.jpg

6.jpg

7.jpg

這兩個模型的ROC曲線和PR曲線差異不大,總體而言隨機森林模型比xgboost模型表現(xiàn)好抡柿。從評定標準來看舔琅,隨機森林的召回率比xgboost稍高一些。認為可能是因為數(shù)據(jù)缺失較多洲劣,造成了噪音比較大备蚓。

六、總結(jié)

1囱稽、特征工程

缺失值和異常值處理是關(guān)鍵郊尝,根據(jù)數(shù)據(jù)和模型選擇是否需要獨熱編碼和標準化,按照業(yè)務(wù)經(jīng)驗合理構(gòu)造衍生特征和聚類特征粗悯。篩選特征的方法有很多種虚循,比如方差、卡方值样傍、相關(guān)系數(shù)等,這里用了樹模型的特征重要性铺遂。特征工程決定了機器學(xué)習(xí)效果的上限衫哥,模型優(yōu)化只能無限接近這個上限。

2襟锐、模型對比結(jié)果

使用邏輯回歸撤逢、隨機森林和xgboost三種模型做對比分析,按照評定標準粮坞,在精確度≥0.97的條件下蚊荣,隨機森林模型的性能最優(yōu),召回率可以達到0.636莫杈。該模型可以直接上線用于用戶流失預(yù)測互例。

3、影響用戶流失的關(guān)鍵因素

從模型表現(xiàn)上看筝闹,隨機森林效果最優(yōu)媳叨。根據(jù)特征重要性排序腥光,提取影響用戶流失的最關(guān)鍵因素。其中用戶相關(guān)的指標有:年訪問次數(shù)糊秆、訪問時間點武福、一年內(nèi)距上次訪問時長、用戶轉(zhuǎn)化率痘番、一年內(nèi)距離上次下單時長捉片。酒店相關(guān)的指標有:24小時內(nèi)已訪問酒店商務(wù)屬性指數(shù)均值、24小時內(nèi)已訪問酒店可訂最低價均值汞舱、24小時歷史瀏覽次數(shù)最多酒店歷史uv界睁、24小時內(nèi)已訪問次數(shù)最多酒店可訂最低價、24小時歷史瀏覽酒店歷史uv均值兵拢。城市相關(guān)的指標:昨日提交當前城市同入住日期的app訂單數(shù)翻斟、昨日訪問當前城市同入住日期的app uv數(shù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末说铃,一起剝皮案震驚了整個濱河市访惜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌腻扇,老刑警劉巖债热,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異幼苛,居然都是意外死亡窒篱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門舶沿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來墙杯,“玉大人,你說我怎么就攤上這事括荡「吒洌” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵畸冲,是天一觀的道長嫉髓。 經(jīng)常有香客問我,道長邑闲,這世上最難降的妖魔是什么算行? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮苫耸,結(jié)果婚禮上州邢,老公的妹妹穿的比我還像新娘。我一直安慰自己鲸阔,他們只是感情好偷霉,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布迄委。 她就那樣靜靜地躺著,像睡著了一般类少。 火紅的嫁衣襯著肌膚如雪叙身。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天硫狞,我揣著相機與錄音信轿,去河邊找鬼。 笑死残吩,一個胖子當著我的面吹牛财忽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播泣侮,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼即彪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了活尊?” 一聲冷哼從身側(cè)響起隶校,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蛹锰,沒想到半個月后深胳,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡铜犬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年舞终,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片癣猾。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡敛劝,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出煎谍,到底是詐尸還是另有隱情攘蔽,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布呐粘,位于F島的核電站,受9級特大地震影響转捕,放射性物質(zhì)發(fā)生泄漏作岖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一五芝、第九天 我趴在偏房一處隱蔽的房頂上張望痘儡。 院中可真熱鬧,春花似錦枢步、人聲如沸沉删。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矾瑰。三九已至砖茸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間殴穴,已是汗流浹背凉夯。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留采幌,地道東北人劲够。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像休傍,于是被迫代替她去往敵國和親征绎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容