一文學會機器學習預測流程(電信客戶流失率問題)

來源:互聯網
上載者:User

標籤:nta   需要   表格   obs   turn   邏輯   als   自己   []   

摘要: 本文介紹了如何把機器學習演算法應用到具體問題中。 以電信電訊廠商客戶流失率問題為例,從問題的提出, 資料的分析, 演算法的評估, 到最終的結果展示, ,一步步介紹機器學習基本流程。 使用者資料來源於互連網。

1 定義問題

客戶流失率問題是電信電訊廠商面臨得一項重要課題,也是一個較為流行的案例。根據測算,招攬新的客戶比保留住既有客戶的花費大得多(通常5-20倍的差距)。因此,如何保留住現在的客戶對電訊廠商而言是一項非常有意義的事情。 本文希望通過一個公開資料的客戶流失率問題分析,能夠帶著大家理解如何應用機器學習預測演算法到實際應用中。

當然, 實際的情境比本文例子複雜的多,如果想具體應用到項目, 還需要針對不同的情境和資料進行具體的分析。

從機器學習的分類來講, 這是一個監督問題中的分類問題。 具體來說, 是一個二分類問題。 所有的資料中包括一些特徵, 最後就是它的分類:流失或者在網。接下來我們就開始具體的處理。

2 分析資料

首先我們來匯入資料, 然後查看資料的基本情況。

2.1 資料匯入

通過pandas來匯入csv, 然後我們來查看一下資料的基本情況

from __future__ import divisionimport pandas as pdimport numpy as npds = pd.read_csv(‘./churn.csv‘)col_names = ds.columns.tolist()print "Column names:"print col_namesprint(ds.shape)

輸出:

Column names:[‘State‘, ‘Account Length‘, ‘Area Code‘, ‘Phone‘, "Int‘l Plan", ‘VMail Plan‘, ‘VMail Message‘, ‘Day Mins‘, ‘Day Calls‘, ‘Day Charge‘, ‘Eve Mins‘, ‘Eve Calls‘, ‘Eve Charge‘, ‘Night Mins‘, ‘Night Calls‘, ‘Night Charge‘, ‘Intl Mins‘, ‘Intl Calls‘, ‘Intl Charge‘, ‘CustServ Calls‘, ‘Churn?‘](3333, 21)

可以看到, 整個資料集有3333條資料, 20個維度, 最後一項是分類。

2.2 基本資料以及類型

我們可以列印一些資料, 對資料和取值有一個基本的理解。

peek = data.head(5)print(peek)

輸出:

   State  Account Length  Area Code     Phone Int‘l Plan VMail Plan  0     KS             128        415  382-4657         no        yes   1     OH             107        415  371-7191         no        yes   2     NJ             137        415  358-1921         no         no   3     OH              84        408  375-9999        yes         no   4     OK              75        415  330-6626        yes         no       Eve Charge  Night Mins  Night Calls  Night Charge  Intl Mins  Intl Calls  0        16.78       244.7           91         11.01       10.0           3   1        16.62       254.4          103         11.45       13.7           3   2        10.30       162.6          104          7.32       12.2           5   3         5.26       196.9           89          8.86        6.6           7   4        12.61       186.9          121          8.41       10.1           3       Intl Charge  CustServ Calls  Churn?  0          2.70               1  False.  1          3.70               1  False.  2          3.29               0  False.  3          1.78               2  False.  4          2.73               3  False.  

我們可以看到, 資料集有20項特徵,分別是州名, 賬戶長度, 區號, 電話號碼, 國際計劃,語音郵箱, 白天通話分鐘數, 白天電話個數, 白天收費, 晚間通話分鐘數,晚間電話個數, 晚間收費, 夜間通話分鐘數,夜間電話個數, 夜間收費, 國際分鐘數, 國際電話個數, 國際收費, 客服電話數,流失與否.

  • 可以看到這裡面有個人資訊,應該可以看到有些資訊與流失與否關係不大。 州名, 區號可以指明客戶的位置, 和流失有關係麼, 不知道, 具體位置如果不分類, 應該完全沒有關係。 而州名, 也許某個州有了某個強勁的競爭者? 這也是瞎猜, 暫時意義不大, 刪除。
  • 帳號長度, 電話號碼, 不需要
  • 國際計劃, 語音郵箱。 可能有關係, 先留著吧。
  • 分別統計了白天, 晚間, 夜間的通話分鐘, 電話個數, 收費情況。 這是重要訊息保留
  • 客服電話, 客戶打電話投訴多那流失率可能會大。 這個是重要訊息保留。
  • 流失與否。 這是分類結果。

然後我們可以看一下資料的類型, 如下:

ds.info()

輸出:

RangeIndex: 3333 entries, 0 to 3332Data columns (total 21 columns):State             3333 non-null objectAccount Length    3333 non-null int64Area Code         3333 non-null int64Phone             3333 non-null objectInt‘l Plan        3333 non-null objectVMail Plan        3333 non-null objectVMail Message     3333 non-null int64Day Mins          3333 non-null float64Day Calls         3333 non-null int64Day Charge        3333 non-null float64Eve Mins          3333 non-null float64Eve Calls         3333 non-null int64Eve Charge        3333 non-null float64Night Mins        3333 non-null float64Night Calls       3333 non-null int64Night Charge      3333 non-null float64Intl Mins         3333 non-null float64Intl Calls        3333 non-null int64Intl Charge       3333 non-null float64CustServ Calls    3333 non-null int64Churn?            3333 non-null objectdtypes: float64(8), int64(8), object(5)memory usage: 546.9+ KB

看見, 有int, float, object。 對於不是資料型的資料, 後面除非決策樹等演算法, 否則應該會轉化成資料行。
所以我們把churn? 結果轉化, 以及"Int‘l Plan","VMail Plan", 這兩個參數只有yes, no 兩種, 所以也進行轉化成01值。

2.3 描述性統計

describe() 可以返回具體的結果, 對於每一列。

數量
平均值
標準差
25% 分位
50% 分位元
75% 分位元
最大值 很多時候你可以得到NA的數量和比例。

       Account Length    Area Code  VMail Message     Day Mins    Day Calls  count     3333.000000  3333.000000    3333.000000  3333.000000  3333.000000   mean       101.064806   437.182418       8.099010   179.775098   100.435644   std         39.822106    42.371290      13.688365    54.467389    20.069084   min          1.000000   408.000000       0.000000     0.000000     0.000000   25%         74.000000   408.000000       0.000000   143.700000    87.000000   50%        101.000000   415.000000       0.000000   179.400000   101.000000   75%        127.000000   510.000000      20.000000   216.400000   114.000000   max        243.000000   510.000000      51.000000   350.800000   165.000000           Day Charge     Eve Mins    Eve Calls   Eve Charge   Night Mins  count  3333.000000  3333.000000  3333.000000  3333.000000  3333.000000   mean     30.562307   200.980348   100.114311    17.083540   200.872037   std       9.259435    50.713844    19.922625     4.310668    50.573847   min       0.000000     0.000000     0.000000     0.000000    23.200000   25%      24.430000   166.600000    87.000000    14.160000   167.000000   50%      30.500000   201.400000   100.000000    17.120000   201.200000   75%      36.790000   235.300000   114.000000    20.000000   235.300000   max      59.640000   363.700000   170.000000    30.910000   395.000000          Night Calls  Night Charge    Intl Mins   Intl Calls  Intl Charge  count  3333.000000   3333.000000  3333.000000  3333.000000  3333.000000   mean    100.107711      9.039325    10.237294     4.479448     2.764581   std      19.568609      2.275873     2.791840     2.461214     0.753773   min      33.000000      1.040000     0.000000     0.000000     0.000000   25%      87.000000      7.520000     8.500000     3.000000     2.300000   50%     100.000000      9.050000    10.300000     4.000000     2.780000   75%     113.000000     10.590000    12.100000     6.000000     3.270000   max     175.000000     17.770000    20.000000    20.000000     5.400000          CustServ Calls  count     3333.000000  mean         1.562856  std          1.315491  min          0.000000  25%          1.000000  50%          1.000000  75%          2.000000  max          9.000000  
2.4 圖形化理解你的資料

之前的一些資訊, 只是一些很初步的理解, 但是對於機器學習演算法來講是不夠的。 下面我們從幾個維度去進一步理解你的資料。工具可以用數字表格, 也可以用圖形(matplotlib) 這裡畫圖較多。

  • 特徵自己的資訊
  • 特徵和分類之間的關係
  • 特徵和特徵之間的關係
    -- 這裡鑒於時間的關係, 有些關係並沒有直接應用於演算法本身, 但是在進一步的演算法提升中是很有意義的, 這裡更多的是一種展示。
2.4.1 特徵本身的資訊

我們先來看一下流失比例, 以及關於打客戶電話的個數分布

import matplotlib.pyplot as plt%matplotlib inlinefig = plt.figure()fig.set(alpha=0.2)  # 設定圖表顏色alpha參數plt.subplot2grid((2,3),(0,0))             # 在一張大圖裡分列幾個小圖ds[‘Churn?‘].value_counts().plot(kind=‘bar‘)# plots a bar graph of those who surived vs those who did not. plt.title(u"stat for churn") # puts a title on our graphplt.ylabel(u"number")  plt.subplot2grid((2,3),(0,2))            ds[‘CustServ Calls‘].value_counts().plot(kind=‘bar‘)# plots a bar graph of those who surived vs those who did not. plt.title(u"stat for cusServCalls") # puts a title on our graphplt.ylabel(u"number")  plt.show()

很容易理解。

然後呢, 我們的資料的特點是對白天, 晚上, 夜間,國際都有分鐘數, 電話數, 收費三種維度。 那麼我們拿白天的來舉例。

import matplotlib.pyplot as plt%matplotlib inlinefig = plt.figure()fig.set(alpha=0.2)  # 設定圖表顏色alpha參數plt.subplot2grid((2,5),(0,0))             # 在一張大圖裡分列幾個小圖ds[‘Day Mins‘].plot(kind=‘kde‘)    # plots a kernel desnsity estimate of customer plt.xlabel(u"Mins")# plots an axis lableplt.ylabel(u"density") plt.title(u"dis for day mins")plt.subplot2grid((2,5),(0,2))            ds[‘Day Calls‘].plot(kind=‘kde‘)    # plots a kernel desnsity estimate of customer plt.xlabel(u"call")# plots an axis lableplt.ylabel(u"density") plt.title(u"dis for day calls")plt.subplot2grid((2,5),(0,4))           ds[‘Day Charge‘].plot(kind=‘kde‘)   # plots a kernel desnsity estimate of customer plt.xlabel(u"Charge")# plots an axis lableplt.ylabel(u"density") plt.title(u"dis for day charge")plt.show()

可以看到分布基本上都是高斯分布, 這也符合我們的預期, 而高斯分布對於我們後續的一些演算法處理是個好訊息。

2.4.2 特徵和分類的關聯

我們來看一下一些特徵和分類之間的關聯。 比如下面int plan

import matplotlib.pyplot as pltfig = plt.figure()fig.set(alpha=0.2)  # 設定圖表顏色alpha參數int_yes = ds[‘Churn?‘][ds[‘Int\‘l Plan‘] == ‘yes‘].value_counts()int_no = ds[‘Churn?‘][ds[‘Int\‘l Plan‘] == ‘no‘].value_counts()df_int=pd.DataFrame({u‘int plan‘:int_yes, u‘no int plan‘:int_no})df_int.plot(kind=‘bar‘, stacked=True)plt.title(u"statistic between int plan and churn")plt.xlabel(u"int or not") plt.ylabel(u"number")plt.show()

我們可以看到, 有國際電話的流失率較高。 猜測也許他們有更多的選擇, 或者對服務有更多的要求。 需要特別對待。 也許你需要電話多收集一下意見了。

再來看一下

#查看客戶服務電話和結果的關聯fig = plt.figure()fig.set(alpha=0.2)  # 設定圖表顏色alpha參數cus_0 = ds[‘CustServ Calls‘][ds[‘Churn?‘] == ‘False.‘].value_counts()cus_1 = ds[‘CustServ Calls‘][ds[‘Churn?‘] == ‘True.‘].value_counts()df=pd.DataFrame({u‘churn‘:cus_1, u‘retain‘:cus_0})df.plot(kind=‘bar‘, stacked=True)plt.title(u"Static between customer service call and churn")plt.xlabel(u"Call service") plt.ylabel(u"Num") plt.show()

基本上可以看出, 打客戶電話的多少和最終的分類是強相關的, 打電話3次以上的流失率比例急速升高。 這是一個非常關鍵的指標。

3 準備資料

好的, 我們已經看了很多,對資料有了一定的理解。 下面我們開始具體對資料進行操作。

3.1 去除無關列

首先, 根據對問題的分析, 我們做第一件事情, 去除三列無關列。 州名, 電話, 區號。

  • 我們和下一步一起做
3.2 轉化成數實值型別

對於有些特徵, 本身不是數實值型別的, 這些資料是不能被演算法直接使用的, 所以我們來處理一下

# Isolate target datads_result = ds[‘Churn?‘]Y = np.where(ds_result == ‘True.‘,1,0)dummies_int = pd.get_dummies(ds[‘Int\‘l Plan‘], prefix=‘_int\‘l Plan‘)dummies_voice = pd.get_dummies(ds[‘VMail Plan‘], prefix=‘VMail‘)ds_tmp=pd.concat([ds, dummies_int, dummies_voice], axis=1)# We don‘t need these columnsto_drop = [‘State‘,‘Area Code‘,‘Phone‘,‘Churn?‘, ‘Int\‘l Plan‘, ‘VMail Plan‘]df = ds_tmp.drop(to_drop,axis=1)print "after convert "print df.head(5)

輸出:

after convert 01   Account Length  VMail Message  Day Mins  Day Calls  Day Charge  Eve Mins  0             128             25     265.1        110       45.07     197.4   1             107             26     161.6        123       27.47     195.5   2             137              0     243.4        114       41.38     121.2   3              84              0     299.4         71       50.90      61.9   4              75              0     166.7        113       28.34     148.3      Eve Calls  Eve Charge  Night Mins  Night Calls  Night Charge  Intl Mins  0         99       16.78       244.7           91         11.01       10.0   1        103       16.62       254.4          103         11.45       13.7   2        110       10.30       162.6          104          7.32       12.2   3         88        5.26       196.9           89          8.86        6.6   4        122       12.61       186.9          121          8.41       10.1      Intl Calls  Intl Charge  CustServ Calls  _int‘l Plan_no  _int‘l Plan_yes  0           3         2.70               1               1                0   1           3         3.70               1               1                0   2           5         3.29               0               1                0   3           7         1.78               2               0                1   4           3         2.73               3               0                1      VMail_no  VMail_yes  0         0          1  1         0          1  2         1          0  3         1          0  4         1          0 

我們可以看到結果, 所有的資料都是數值型的, 而且除去了對我們沒有意義的列。

3.3 scale 資料範圍

我們需要做一些scale的工作。 就是有些屬性的scale 太大了。

  • 對於羅吉斯迴歸和梯度下降來說, 個屬性的scale 差距太大, 會對收斂速度有很大的影響。
  • 我們這裡對所有的都做, 其實可以對一些突出的特徵做這種處理。
#scaleX = df.as_matrix().astype(np.float)# This is importantfrom sklearn.preprocessing import StandardScalerscaler = StandardScaler()X = scaler.fit_transform(X)print "Feature space holds %d observations and %d features" % X.shapeprint "Unique target labels:", np.unique(y)

輸出:

Feature space holds 3333 observations and 19 featuresUnique target labels: [0 1]

其他的呢, 還可以考慮降維等各種方式。 但是再實際使用中, 我們往往首先做出一個模型, 得到一個參考結果, 然後逐步最佳化。 所以我們準備資料就到這裡。

4 評估演算法

我們會使用多個演算法來計算結果, 然後選擇較好的。 如下

# prepare modelsmodels = []models.append((‘LR‘, LogisticRegression()))models.append((‘LDA‘, LinearDiscriminantAnalysis()))models.append((‘KNN‘, KNeighborsClassifier()))models.append((‘CART‘, DecisionTreeClassifier()))models.append((‘NB‘, GaussianNB()))models.append((‘SVM‘, SVC()))# evaluate each model in turnresults = []names = []scoring = ‘accuracy‘for name, model in models:    kfold = KFold(n_splits=10, random_state=7)    cv_results = cross_val_score(model, X, Y, cv=kfold, scoring=scoring)    results.append(cv_results)    names.append(name)    msg = "%s: %f (%f)" % (name, cv_results.mean(), cv_results.std())    print(msg)# boxplot algorithm comparisonfig = pyplot.figure()fig.suptitle(‘Algorithm Comparison‘)ax = fig.add_subplot(111)pyplot.boxplot(results)ax.set_xticklabels(names)pyplot.show()
LR: 0.860769 (0.021660)LDA: 0.852972 (0.021163)KNN: 0.896184 (0.016646)CART: 0.920491 (0.012471)NB: 0.857179 (0.015487)SVM: 0.921091 (0.016828)

可以看到什麼呢, 看到SVM 和 CART 效果相對較好。

5 提升結果

提升的部分, 如何使用提升演算法。
比如隨機森林。 xgboost

from sklearn.ensemble import RandomForestClassifiernum_trees = 100max_features = 3kfold = KFold(n_splits=10, random_state=7)model = RandomForestClassifier(n_estimators=num_trees, max_features=max_features)results = cross_val_score(model, X, Y, cv=kfold)print(results.mean())# 0.954696013379
from sklearn.ensemble import GradientBoostingClassifierseed = 7num_trees = 100kfold = KFold(n_splits=10, random_state=seed)model = GradientBoostingClassifier(n_estimators=num_trees, random_state=seed)results = cross_val_score(model, X, Y, cv=kfold)print(results.mean())# 0.953197209185

可以看到, 這兩種演算法對單個演算法的提升還是很明顯的。 進一步的, 也可以繼續調整tree的數目, 但是效果應該差不多了。

6 展示結果

這裡展示了如何儲存這個演算法, 以及如何取出然後應用。

#storefrom sklearn.model_selection import train_test_splitfrom pickle import dumpfrom pickle import loadX_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.33, random_state=7)from sklearn.ensemble import GradientBoostingClassifierseed = 7num_trees = 100kfold = KFold(n_splits=10, random_state=seed)model = GradientBoostingClassifier(n_estimators=num_trees, random_state=seed)model.fit(X_train, Y_train)# save the model to diskfilename = ‘finalized_model.sav‘dump(model, open(filename, ‘wb‘))# some time later...# load the model from diskloaded_model = load(open(filename, ‘rb‘))result = loaded_model.score(X_test, Y_test)print(result)
7 後記

本文展示了通過使用者流失率問題, 如何把機器學習的預測過程應用到實際項目中。

  • 從業務的角度, 這個只是一個demo性質的應用, 實際情境可能複雜的多。
  • 從流程的角度, 通過對資料的分析可以進一步提升演算法的效能, 對於某些的特徵, 可以採取不同的處理方式。 比如缺失值的處理, 這裡很完整, 就省去了這個步驟。
  • 對於一些步驟, 這裡解釋並不是很詳細, 讀者可以參考部落格的 掌握python機器學習 系列

參考文章
1 http://blog.yhat.com/posts/predicting-customer-churn-with-sklearn.html
2 http://blog.csdn.net/han_xiaoyang/article/details/49797143 寒小陽的部落格。

一文學會機器學習預測流程(電信客戶流失率問題)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.