同步更新在今日頭條 (機(jī)器學(xué)習(xí)and數(shù)據(jù)科學(xué)): 案例實(shí)戰(zhàn):客戶價(jià)值預(yù)測(cè)模型
同步更新在個(gè)人網(wǎng)站:http://www.wangpengcufe.com/machinelearning/pythonml-pythonml7/
原理: 利用多元線性回歸模型根據(jù)多個(gè)因素預(yù)測(cè)客戶價(jià)值,當(dāng)模型搭建完成后,就可以對(duì)不同價(jià)值的客戶采用不同的業(yè)務(wù)策略。
源碼和數(shù)據(jù)下載鏈接見文章末尾鏈接。
目錄:
- 1、案例背景
- 2、案例主要應(yīng)用技術(shù)
- 3、案例數(shù)據(jù)
- 4、案例過(guò)程
- 4.1、導(dǎo)庫(kù)
- 4.2、數(shù)據(jù)讀取
- 4.3、數(shù)據(jù)探索
- 4.4、數(shù)據(jù)預(yù)處理
- 4.4.1、重復(fù)值處理
- 4.4.2、異常值處理
- 4.4.3、缺失值處理
- 4.5、特征工程
- 4.5.1、特征相關(guān)性分析
- 4.5.2、目標(biāo)相關(guān)性分析
- 4.5.3、特征構(gòu)造
- 4.6、模型搭建
- 4.6.1、構(gòu)建特征值和目標(biāo)值
- 4.6.2、劃分訓(xùn)練和測(cè)試集
- 4.6.3、模型搭建
- 4.7、線性回歸方程構(gòu)造
- 4.8、模型評(píng)估
- 4.9、評(píng)估結(jié)果解讀
- 5、案例數(shù)據(jù)結(jié)論
一、案例背景:
客戶價(jià)值預(yù)測(cè)就是指客戶未來(lái)一段時(shí)間能帶來(lái)多少利潤(rùn),其利潤(rùn)的來(lái)源可能來(lái)自于信用卡的年費(fèi)、取現(xiàn)手續(xù)費(fèi)、分期手續(xù)費(fèi)、境外交易手續(xù)費(fèi)用等。而分析出客戶的價(jià)值后,在進(jìn)行營(yíng)銷、電話接聽、催收、產(chǎn)品咨詢等各項(xiàng)服務(wù)時(shí),就可以針對(duì)高價(jià)值的客戶進(jìn)行區(qū)別于普通客戶的服務(wù),有助于進(jìn)一步挖掘這些高價(jià)值客戶的價(jià)值,并提高這些高價(jià)值客戶的忠誠(chéng)度。
二、案例主要應(yīng)用技術(shù)
本案例用到的主要技術(shù)包括:
- 數(shù)據(jù)建模: 線性回歸模型LinearRegression
- 模型評(píng)估:statsmodels
- 模型可視化:matplotlib 、seaborn 畫圖
- 主要用到的庫(kù)包括:pandas 和 Sklearn
本案例使用的開發(fā)工具是 jupyter notebook,故很多地方直接寫對(duì)象,就能輸出結(jié)果,不需要寫print(),如果是在其他的編輯器,在輸出時(shí),需要加上print()。
三、案例數(shù)據(jù)
以下是數(shù)據(jù)概覽:
特征變量數(shù):5
數(shù)據(jù)記錄數(shù):128
是否有NA值:有
是否有異常值:有
以下是本數(shù)據(jù)集的5個(gè)特征變量,包括:
load_amount : 歷史貸款金額,整數(shù)型變量。
loan_time :貸款次數(shù),整數(shù)型變量。
edu:學(xué)歷,分類型變量, 值域[高中, 本科,研究生]。
salary:薪水,整數(shù)型變量。
sex:性別,值域?yàn)槟谢蚺?br>
目標(biāo)變量value :客戶價(jià)值打分,整數(shù)型變量。
四、案例過(guò)程
4.1、導(dǎo)庫(kù)
import pandas as pd # pandas庫(kù)
from sklearn.preprocessing import LabelEncoder # 編號(hào)處理
from sklearn.model_selection import train_test_split # 劃分訓(xùn)練集和測(cè)試集
from sklearn.linear_model import LinearRegression # LinearRegression 線性回歸模型
import statsmodels.api as sm # 模型評(píng)估
import matplotlib.pyplot as plt # 畫圖
import seaborn as sns # 畫圖
plt.rcParams["font.sans-serif"]='SimHei' # 中文亂碼
plt.rcParams['axes.unicode_minus']=False # 負(fù)號(hào)無(wú)法正常顯示
%config InlineBackend.figure_format='svg' # 像素清晰
pandas:常用的數(shù)據(jù)讀取、 展示、處理和數(shù)據(jù)保存庫(kù)。
LabelEncoder :sklearn庫(kù)中數(shù)據(jù)預(yù)處理的preprocessing 包下的整數(shù)編碼類,用來(lái)將非數(shù)值對(duì)象轉(zhuǎn)換為數(shù)值類型。
train_test_split :sklearn庫(kù)中用來(lái)劃分訓(xùn)練集和測(cè)試集的類。
LinearRegression:sklearn庫(kù)中l(wèi)inear_model 包下面的線性回歸類,用來(lái)建立線性回歸模型。
statsmodels.api :引入線性回歸模型評(píng)估相關(guān)庫(kù)。
matplotlib.pyplot :引入matplotlib庫(kù)進(jìn)行模型可視化畫圖。
seaborn :引入seaborn 庫(kù)進(jìn)行可視化畫圖。
除了上述庫(kù)以外,還需要關(guān)于使用pandas讀Excel需要的附屬庫(kù)。如果之前沒有安裝過(guò)這個(gè)庫(kù), 需要在系統(tǒng)終端命令行窗口使用pip install xlrd 完成安裝。這個(gè)庫(kù)無(wú)需導(dǎo)入,在Pandas讀取Excel時(shí)會(huì)自動(dòng)調(diào)用。
用pip install xlwt
4.2、數(shù)據(jù)讀取
df = pd.read_excel('Customer_value.xlsx')
4.3、數(shù)據(jù)探索
數(shù)據(jù)形狀:
df.shape
打印輸出:(128, 6)
shape方法用來(lái)查看當(dāng)前數(shù)據(jù)的形狀,返回一個(gè)二維的數(shù)據(jù)元祖,逗號(hào)前面的數(shù)值表示128行,逗號(hào)后面的數(shù)值表示6列。
數(shù)據(jù)類型:
df.info()
返回結(jié)果如下:

info方法用來(lái)查看數(shù)據(jù)的類型和缺失情況:
- 從整體看,數(shù)據(jù)總共有128條,范圍是[0,127], 總共有6列。從具體字段看,value(客戶價(jià)值)是整數(shù)型,共128條未缺失,缺失值為0。loan_amount(貸款金額)是整數(shù)型,共128條未缺失,缺失值為0。loan_time(貸款次數(shù))是整數(shù)型,共128條未缺失,缺失值為0。edu(教育程度)是object對(duì)象,需要處理成數(shù)值,共128條未缺失,缺失值為0。salary (薪水) 是整數(shù)型,共126條未缺失,缺失值為2。sex(性別) 是object對(duì)象,需要處理成數(shù)值,共128條未缺失,缺失值為0。
- 統(tǒng)計(jì)的結(jié)果:總共的類型有 整數(shù)型字段4個(gè),object對(duì)象2個(gè)。
- 內(nèi)存使用情況:6.1kb的內(nèi)存
查看前幾行:
df.head()

head方法用來(lái)顯示指定數(shù)據(jù)(N)的前N數(shù)據(jù),不指定N的話,默認(rèn)顯示前5條。
數(shù)據(jù)概覽:
df.describe()

describe方法用來(lái)顯示數(shù)據(jù)中所有為數(shù)值類型的數(shù)據(jù)記錄數(shù)、均值、標(biāo)準(zhǔn)差、最小值、 25%、 50%、75%分位數(shù)數(shù)據(jù),最大值。
4.4、數(shù)據(jù)預(yù)處理
經(jīng)過(guò)數(shù)據(jù)的探索,我們知道了數(shù)據(jù)中有缺失值,有非數(shù)值對(duì)象。這樣就需要做2個(gè)數(shù)據(jù)預(yù)處理的工作,處理缺失值,和將非數(shù)值對(duì)象轉(zhuǎn)換為數(shù)值對(duì)象。在此之前,我們先看看有無(wú)重復(fù)值。
4.4.1、重復(fù)值處理
重復(fù)數(shù)據(jù)查詢:
df[df.duplicated()]
輸出結(jié)果:

duplicated()函數(shù)可以查詢重復(fù)的內(nèi)容??梢钥吹降?2行記錄重復(fù)了,被代碼篩選了出來(lái)。
查看重復(fù)的數(shù)量:
df.duplicated().sum()
輸出結(jié)果為:1。說(shuō)明數(shù)據(jù)中只有一行數(shù)據(jù)重復(fù)了。
刪除重復(fù)數(shù)據(jù):
df = df.drop_duplicates()
需要注意的是,drop_duplicates()函數(shù)并不改變?cè)砀窠Y(jié)構(gòu),所以需要進(jìn)行重新賦值,或者在其中設(shè)置inplace參數(shù)為True。
再次查看數(shù)據(jù)類型:
df.info()

可以看到從整體看,數(shù)據(jù)的數(shù)量變成了127行了,比之前的128少了一行,說(shuō)明重復(fù)值刪除成功。
4.4.2、異常值處理
處理完了重復(fù)值,我們?cè)賮?lái)看看數(shù)據(jù)中有無(wú)異常值。
查看異常值,我們可以用箱體圖進(jìn)行觀察。查看整體的異常情況:
df.boxplot()
輸出結(jié)果:

可以看到value,loan_amount,loan_time,salary中分別有異常值。不過(guò),異常值是否都直接刪除,需要我們結(jié)合具體的業(yè)務(wù)來(lái)考慮。value(客戶價(jià)值)只超過(guò)最大值一點(diǎn),可以不刪除。loan_amount(貸款金額)也只比最大值大一點(diǎn),不是大的很過(guò)分,可以考慮不刪除,同理,薪水的異常值也可以認(rèn)為是可接受的范圍內(nèi)。由于load_time(貸款次數(shù))的數(shù)據(jù)量綱和其他的不一致,我們可以單獨(dú)查看:
df[['loan_time']].boxplot()
輸出結(jié)果:

我們可以看到,有一個(gè)貸款次數(shù),是要遠(yuǎn)遠(yuǎn)大于其他數(shù)據(jù)的,結(jié)合實(shí)際業(yè)務(wù)情況,我們可以認(rèn)為這個(gè)是異常值,(貸款這么多次,銀行的征信還能過(guò)得去嗎)。當(dāng)然最保險(xiǎn)的做法是和業(yè)務(wù)人員再進(jìn)行一次確認(rèn),然后進(jìn)行異常值刪除。這里,我們暫且認(rèn)為這個(gè)貸款次數(shù)30次的人就是異常值。
我們可以找到這條記錄:
df[df['loan_time']==30]
輸出結(jié)果:

刪除異常值:
df = df.drop(df[df['loan_time']==30].index)
查看結(jié)果:
df[df['loan_time']==30]
輸出結(jié)果:

可以看到數(shù)據(jù)中已經(jīng)查不到原來(lái)的這條異常記錄了。
4.4.3、缺失值處理
之所以把缺失值放在異常值處理之后,是因?yàn)?,缺失值通常用平均值,中位?shù)等方法填補(bǔ),如果數(shù)據(jù)中有異常值的話,求平均會(huì)影響到缺失值的數(shù)值。
剛才已經(jīng)通過(guò)數(shù)據(jù)探索,發(fā)現(xiàn)了salary(薪水)一列中有缺失值,那么我們可以用代碼將其篩選出來(lái):
df[df['salary'].isnull()]
輸出結(jié)果:

可以看到26行和60行的薪水一列是缺失的。
缺失值通常處理的方法是刪除,平均值填補(bǔ),中位數(shù)填補(bǔ)。根據(jù)實(shí)際情況,我們這里用平均值法填補(bǔ)。
df = df.fillna(df.mean())
再次確認(rèn)填補(bǔ)效果:
df.info()

可以看到,數(shù)據(jù)中已經(jīng)沒有缺失值了。至此,數(shù)據(jù)預(yù)處理的工作已經(jīng)做完,下面我們開始特征工程的工作。
4.5、特征工程
首先我們查看是否還具有多重共線性的數(shù)據(jù),我們查看特征之間的相關(guān)性。
4.5.1、相關(guān)性分析
首先獲取所有的特征變量:
feature = df.drop(['value'],axis=1)
feature.head()

然后我們查看特征之間的相關(guān)性,得到相關(guān)性矩陣:
corr = feature.corr()
corr

我們將特征矩陣進(jìn)行熱力圖可視化展示:
plt.figure(figsize=(10,6))
ax = sns.heatmap(corr, xticklabels=corr.columns, yticklabels=corr.columns,
linewidths=0.2, cmap="RdYlGn",annot=True)
plt.title("Correlation between variables")

從圖中,我們可以看出特征之間沒有很強(qiáng)的相關(guān)性,沒有需要處理的共線性的問(wèn)題。需要注意的是,特性矩陣只會(huì)分析數(shù)值類型的特征,不會(huì)分析非數(shù)值對(duì)象的特征。
4.5.2、目標(biāo)相關(guān)性分析
df_onehot = pd.get_dummies(df)
df_onehot.head()

plt.figure(figsize=(15,4))
df_onehot.corr()['value'].sort_values(ascending=False).plot(kind='bar')
plt.title('Correlation between value and variables ')

可以看到目標(biāo)對(duì)象value(客戶價(jià)值)跟貸款金額,薪水,貸款次數(shù)高度相關(guān),和性別無(wú)關(guān)。和學(xué)歷相關(guān),其中,和本科成正相關(guān),和高中成負(fù)相關(guān),跟研究生學(xué)歷關(guān)系不大,這可能是樣本中研究生比例小造成的。說(shuō)明學(xué)歷對(duì)客戶價(jià)值還是有一定影響的。
我們可以看一下樣本中學(xué)歷構(gòu)成情況:
df['edu'].value_counts()

研究生只有4例。
4.5.3、特征構(gòu)造
非數(shù)值型對(duì)象是不能直接進(jìn)行機(jī)器建模學(xué)習(xí)的,所以我們要處理非數(shù)值對(duì)象,將其轉(zhuǎn)換為數(shù)值對(duì)象。這里,我們要用到LabelEncoder函數(shù)。
le = LabelEncoder()
edu = le.fit_transform(df['edu'])
df['edu'] = edu
sex = le.fit_transform(df['sex'])
df['sex'] = sex
df.head()

通過(guò)LabelEncoder函數(shù),我們將原來(lái)的數(shù)值轉(zhuǎn)換成為了數(shù)值,這樣就為后面的機(jī)器學(xué)習(xí)建模做好了準(zhǔn)備。有的小伙伴會(huì)問(wèn):那原來(lái)edu(學(xué)歷)中的高中,本科,研究生怎么和數(shù)值1,2對(duì)應(yīng)呢?這是個(gè)好問(wèn)題啊,我們可以這樣來(lái)做。即通過(guò)LabelEncoder轉(zhuǎn)換前后的計(jì)數(shù)我們可以進(jìn)行比較,具體方法如下:
首先我們做一下轉(zhuǎn)換前的計(jì)數(shù):
df['edu'].value_counts()

df['sex'].value_counts()

然后我們做一下轉(zhuǎn)換之后的計(jì)數(shù):
df['edu'].value_counts()

df['sex'].value_counts()

這樣,對(duì)應(yīng)關(guān)系就一目了然,不用我再說(shuō)了吧!
4.6、模型搭建
4.6.1、構(gòu)建特征值和目標(biāo)值
# 構(gòu)建特征值X 和目標(biāo)值 Y
X = df.drop('value',axis=1)
y = df['value']
x是包含了除value以外的所有列,y只是value這一列。
4.6.2、劃分訓(xùn)練和測(cè)試集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
test_size=0.2,表示用20%的數(shù)據(jù)測(cè)試,用80%的數(shù)據(jù)來(lái)訓(xùn)練。得到的結(jié)果為X的訓(xùn)練集X_train, X的測(cè)試集X_test, y的訓(xùn)練集 y_train, y的測(cè)試集 y_test。
4.6.3、模型搭建
regr = LinearRegression()
regr.fit(X, y)
y_pred = regr.predict(X_test)
4.7、線性回歸方程構(gòu)造
regr.coef_

print('各系數(shù)為:' + str(regr.coef_))
print('常數(shù)項(xiàng)系數(shù)k0為:' + str(regr.intercept_))

最后得到的線性方程為:y = 129 + 0.059x1 + 95x2 - 53x3 + 0.054x4 + 7.53*x5
4.8、模型評(píng)估
X2 = sm.add_constant(X)
est = sm.OLS(y, X2).fit()
est.summary()

x = len(y_pred)
plt.plot(range(x), y_pred, label='預(yù)測(cè)值')
plt.plot(range(x), y_test, label='真實(shí)值')
plt.title('真實(shí)值和預(yù)測(cè)值對(duì)比走勢(shì)圖')
plt.xticks([])
plt.legend()
plt.show()

regr.score(X_test, y_test)
輸出結(jié)果:準(zhǔn)確率為0.6470898016296844
4.9、評(píng)估結(jié)果解讀
1、coef列,就是常數(shù)項(xiàng)(const)和特征變量(loan_amount, load_time, edu, salary, sex)前的系數(shù),即截距b和斜率系數(shù),可以看到,這和之前求出的結(jié)果是一致的。
2、對(duì)模型評(píng)估而言,需要關(guān)心的幾個(gè)指標(biāo)有 R-squared、Adj.R-squared 和P值的信息。
2.1、這里的R-squared為0.548, Adj.R-squared為0.529,說(shuō)明模型的線性擬合程度還不是特別好,可能因?yàn)榘咐~數(shù)據(jù)量偏少,不過(guò)在此數(shù)據(jù)量條件下也算可以接受的結(jié)果。
2.2、對(duì)P值而言,大部分的P值都較小,的確與目標(biāo)變量(客戶價(jià)值)是顯著相關(guān)的,而sex這一特征的P值達(dá)到了0.819,說(shuō)明性別和目標(biāo)變量是沒有顯著相關(guān)性的,這個(gè)結(jié)論也符合經(jīng)驗(yàn)認(rèn)知。之后的建模中就可以舍去這一特征變量了。
五、案例數(shù)據(jù)結(jié)論
1、從特征的相關(guān)性來(lái)看,目標(biāo)對(duì)象value(客戶價(jià)值)跟貸款金額,薪水,貸款次是呈現(xiàn)高度相關(guān)的。這說(shuō)明用戶歷史貸款的記錄越多,客戶的給企業(yè)帶來(lái)了利潤(rùn),客戶的價(jià)值自然要高。
2、客戶價(jià)值和性別無(wú)關(guān)。
3、客戶價(jià)值和學(xué)歷相關(guān),其中,和本科成正相關(guān),和高中成負(fù)相關(guān),跟研究生學(xué)歷關(guān)系不大,可能學(xué)歷太低風(fēng)險(xiǎn)性會(huì)高一點(diǎn),客戶的價(jià)值相對(duì)低一點(diǎn)。案例中研究生學(xué)歷太少,導(dǎo)致結(jié)果是跟研究生學(xué)歷關(guān)系不大。
4、模型的整體準(zhǔn)確率只有0.65,R-squared為0.548, Adj.R-squared為0.529,說(shuō)明模型的擬合程度不是特別滿意,可能是案例的數(shù)量偏少。不過(guò)在此數(shù)據(jù)量條件下也算可以接受的結(jié)果。
源碼下載 :源碼下載地址
數(shù)據(jù)下載:客戶價(jià)值數(shù)據(jù)表 (訪問(wèn)密碼: 7287)