機器學習 (十三) 電商O2O優惠券使用預測-1

描述

       發放優惠券是各大公司一種重要的營銷手段,如電商平臺、打車平臺、線下門店等等,幾乎所有涉及到客戶消費的行業都有優惠券的發放,那麼如何精準定位發送優惠券,保證發送的優惠券是真正想使用優惠券的人呢,或者我能預測出來每個客戶是不是用優惠券,這樣一是可以計算營銷成本,二是可以留住用戶提升品牌競爭力,對企業營銷有着重要意義。

思路流程

       我們說這篇將介紹下如何通過機器學習方法來分析預測,在給客戶發券後在指定時間內用戶是否使用該券,
我們擁有某電商用戶2017年6月份的優惠券發放和使用記錄,利用這些數據來預測7月份用戶使用的概率。

  • 理解數據

       感覺理解數據非常重要,在這個場景中顯然用戶何時領取的優惠券、何時使用的是兩個比較重要特徵,這兩個特徵需要我們理解了數據,才能轉化爲數字的方式表達出來,對數據理解的越深刻,以後我們可以挖掘的特徵越多,我們的模型當然訓練出來就越好,如下圖:
這裏寫圖片描述
       我統一將NaN值替換爲-10了,方便處理,上面即通過優惠券接受日期判斷用戶是否收到優惠券,再通過是否購買上面商品來判斷用戶是否真正使用了券,這些信息提取出來可以當做標籤,他們都是我們從數據中提取出來的信息,可見有價值的信息很多。

  • 數據清洗

       已經存在的數據需要清洗加工爲統一的數據樣式,可以讓算法直接處理的數據格式,如在處理折扣率、滿X減Y這種優惠時,將它們處理爲統一值:
這裏寫圖片描述
這裏寫圖片描述
上面處理是將滿X減Y轉爲了折扣率一樣的格式,方便後面進行模型訓練。

  • 特徵提取

在原始數據中優惠券發放都是按着日曆來的,想一想可否將這個日期轉化爲週期,也是可以的,比如:
這裏寫圖片描述
這裏寫圖片描述
這些特徵都是我們自己來從數據中提取,提取特徵需要充分理解原始數據才能提取出來有價值的特徵。

  • 開始訓練
           在第一次訓練時先只結合了用戶的兩個分析特徵,滿減折扣率特徵,我們拆分爲了0-1之間的折扣率discount_rate,並且把滿X(discount_man)減Y(discount_jian),以及折扣類型(discount_type)等列,其次是接收優惠券的日期轉爲了日期類型,並將日期枚舉值轉爲了one-hot類型字段方便分析,這兩字段也算是我們進行了擴展分析。
    所有訓練屬性如下:
    這裏寫圖片描述

模型分析

       在這部分涉及到sklearn中工具類,有必要了解下原理,方便我們今後使用SGDClassifier、Pipeline、GridSearchCV。
模型選擇:
       在確定並清洗完訓練特徵後,下一步即選擇啥模型進行數據訓練,這裏我們目標是分類,那麼KNN、貝葉斯、SVM、LR等分類器是否都可以用呢,都是可以的,sklearn支持常用的分類器實現,可以直接用很方便,避免了重複造輪子,不過我們一定要理解它們的實現原理,這樣才能再上面不斷優化,創造新的學習器。
       說得更專業一點,模型不管多複雜最終出來的是一個函數,根據函數的定義函數的重點是映射關係,如A到B可以通過各種函數來映射,則我們的模型即從輸入到輸出的一種映射關係,也可以這麼理解在數學領域映射叫函數,在機器學習領域叫模型,在李航老師的書中稱這個映射集合爲假設空間(Hypothesis space),其實是爲了方便理解那麼多情況而創造出來了一個名詞而已。

       有很多種、確定了哪類模型後還需要調節各種參數不同參數還對應不同模型,首先我們來用LR分類器梯度上升求解。

參數調優:
       sklearn同時頁爲我們提供了調試參數的方法grid_search,可以輸入參數列表和模型、評分函數,它會選擇出來得分最優的參數,如果不適用這個調參我們自己一個參數一個參數實驗也可以求出最優參數。
官網文檔說明:http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html#sklearn.model_selection.GridSearchCV

       SGDClassifier類主要採用梯度下降的方法實現了LR和SVM,也就是我們如果要使用邏輯迴歸和SVM進行預測分類時,該類時一個很好的選擇,官網文檔如下:
http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.SGDClassifier.html

這裏寫圖片描述

       Pipeline機制在機器學習中也比較常見,就如管道含義一樣,他可以讓我們把好幾步流程串聯起來一起執行,使得代碼簡介,類似於java中的鏈式編程寫法,像是一種編程技巧,經常放在管道中的步驟是標準化、降維、學習器三種類型的步驟,在管道中他們會依次執行,每兩個銜接地方有抓換適配器,如下圖:
這裏寫圖片描述

代碼如下:


def check_model(data, predictors):
    
    classifier = lambda: SGDClassifier(
        loss='log', //對數損失函數 邏輯迴歸
        penalty='elasticnet', //l1 l2結合
        fit_intercept=True, //截距
        max_iter=100, //迭代次數
        shuffle=True, //打散樣本
        n_jobs=1,
        class_weight=None)//樣本權重一樣
 
    model = Pipeline(steps=[
        ('ss', StandardScaler()),
        ('en', classifier())
    ])
 
    parameters = {
        'en__alpha': [ 0.001, 0.01, 0.1],
        'en__l1_ratio': [ 0.001, 0.01, 0.1]
    }
 
    folder = StratifiedKFold(n_splits=3, shuffle=True)
    
    grid_search = GridSearchCV(
        model, //分類器
        parameters, //參數列表
        cv=folder, //交叉驗證folder數量
        n_jobs=-1, //並行數
        verbose=1)//日誌長度,不輸出訓練過程
    //運行搜索
    grid_search = grid_search.fit(data[predictors], 
                                  data['label'])
    
    return grid_search

model = check_model(train, predictors)
    print(model.best_score_)//運行過程中觀察到的最好評分
    print(model.best_params_)//取得最佳結果的參數組合
# valid predict
y_valid_pred = model.predict_proba(valid[predictors])
valid1 = valid.copy()
valid1['pred_prob'] = y_valid_pred[:, 1]
valid1.head(2)

# avgAUC calculation
vg = valid1.groupby(['Coupon_id'])
aucs = []
for i in vg:
    tmpdf = i[1] 
    if len(tmpdf['label'].unique()) != 2:
        continue
    fpr, tpr, thresholds = roc_curve(tmpdf['label'], tmpdf['pred_prob'], pos_label=1)
    aucs.append(auc(fpr, tpr))
print(np.average(aucs))

# test prediction for submission
y_test_pred = model.predict_proba(dftest[predictors])
dftest1 = dftest[['User_id','Coupon_id','Date_received']].copy()
dftest1['label'] = y_test_pred[:,1]
dftest1.to_csv('submit1.csv', index=False, header=False)
dftest1.head()

ROC曲線表示的是模型靈敏度,橫座標爲FPR ,縱座標爲TPR 即縱座標表示真正預測爲正樣本的個數除以正樣本個數的比值,橫座標爲預測爲正的負樣本個數除以負樣本個數,我們想要的結果是TPR越高越好,但有時FPR也會升高。
第一個參數爲標籤、第二個爲預測概率值,第三個爲指定哪類爲正類,它的原理也很簡單是根據不同的閾值來計算不同的點,然後在連接起來即形成曲線。

from sklearn.metrics import auc
# import  matplotlib as plt
plt.rcParams['axes.unicode_minus'] = False  
roc_auc = auc(fpr_total, tpr_total)  
plt.title('Receiver Operating Characteristic')  
plt.plot(fpr_total, tpr_total, 'b', label='AUC = %0.2f' % roc_auc)  
plt.legend(loc='lower right')  
plt.plot([0, 1], [0, 1], 'r--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.0])
plt.ylabel('Recall')
plt.xlabel('Fall-out')
plt.show()
如下圖我畫出來的ROC曲線

這裏寫圖片描述
       ROC曲線評價統計量計算。ROC曲線下的面積值在1.0和0.5之間。在AUC>0.5的情況下,AUC越接近於1,說明診斷效果越好。AUC在 0.5~0.7時有較低準確性,AUC在0.7~0.9時有一定準確性,AUC在0.9以上時有較高準確性。AUC=0.5時,說明診斷方法完全不起作用,無診斷價值。AUC<0.5不符合真實情況,在實際中極少出現。根據經驗我們的AUC值爲0.62說明模型預測準確率較低,因此還需要繼續優化,下篇我們繼續優化模型。

問題思考

-除了AUC曲線還有啥有效的方法來分析模型效果?
-我們計算出來AUC值爲0.62,那麼如何優化模型?提取更有效的特徵還是模型上下功夫?
-AUC值是每一個樣本點的還是整個數據集的?

題外思考

耶魯大學的精神
       耶魯大學是美國一所老牌有名的大學,很多國內外爭先恐後的進入,它也是唯一一所靠文科出名的大學,可見它將文學思想發揚光大,想一下世界各個大學辦學各有各自的特色,將每一種特色做到極致就會脫穎而出成爲有名的大學,麻省理工等大學是在於理科研究和教學等方面非常優秀,其實大部分學校都注重理科教學質量,很少有大學拿文科來當做自己的強項,因爲啥呢?是不是感覺文科是很虛的科目、是容易出來被罵專業軟文的學科,然而耶魯卻把文科的思想做的了極致,在創造新思想新文化、培養人作爲未來領袖方面做到了極致。
       舉個簡單的例子如果某個學生家鄉遇到困難,那麼它是鼓勵學習爲之多做出一些力量,不是盡些綿薄之力而是盡全力,要有一種爲家鄉、爲祖國奉獻的責任感,將故鄉、社會、國家的責任當做自己的事情來做的責任感,與不在其位不謀其政思想正好相背離,有時感覺這種思想有點消極影響,它這所學校在於培養學生的責任感。
當然,我們偉大的祖國也不乏這種責任感,很久以前的唐朝就有詩人李賀 提筆 ,如下:
李 賀
男兒何不帶吳鉤,
收取關山五十州?
請君暫上凌煙閣,
若個書生萬戶侯?
       李賀作爲一個文弱書生,想拿起寶劍去收復五十州失地,這首詩被流傳千古是因爲有社會責任感在裏面,有文化精髓在傳承,這些都是前任留下的寶貴財富,需要我們去靜靜品味。

參考文章

Pipeline機制
https://blog.csdn.net/lanchunhui/article/details/50521648
https://www.jianshu.com/p/9c2c8c8ef42d

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章