1. 程式人生 > >機器學習 (十六)電商O2O優惠券使用預測-2

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

介紹

       這篇文章是想繼續總結一遍優惠券預測,寫寫感受並進行一個記錄總結,零零散散以作為記錄整理之用。

本篇是選了三點本人覺得專案中重要的寫了一下,其它內容暫時略過

  • 第一部分:資料清洗資料分析程式碼基本功
  • 第二部分:特徵理解和選擇
  • 第三部分:模型選擇和調休

資料分析利器-python

       在用python進行資料分析時候,確實發現其有很多方便之處,其強大的函式處理功能,正看在《利用python進行資料分析》這本書發現還是不錯的,簡單內容如下:

在這裡插入圖片描述

在這裡插入圖片描述
筆記:

  • copy
    用在了提取特徵地方,複製一份資料單獨處理,不影響以前的,預設深複製
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'],
        'year': [2000, 2001, 2002, 2001, 2002, 2003],
        'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
frame = pd.DataFrame(data)
print(frame)
# 深複製 修改不影響原物件
data_deep_copy = frame.copy()

data_deep_copy.iloc[1] = 2018
print(data_deep_copy)
print(frame)

# 淺複製  修改影響原物件
data_shallow_copy = frame.copy(deep = False)
data_shallow_copy.iloc[1] = 2019
print(data_shallow_copy)
print(frame)

-梳理
分組
在提取使用者特徵時,根據User_id進行分組,得到分組物件,然後可以再分組物件上進行各種統計操作。

# 使用者 User 特徵
u = fdf[['User_id']].copy().drop_duplicates()

# u_coupon_count : num of coupon received by user
u1 = fdf[fdf['Date_received'] != -10][['User_id']].copy()
# 每個使用者領取優惠券的數量
u8 = utmp.groupby(['User_id'], as_index = False).median()
u8.rename(columns = {'distance':'u_median_distance'}, inplace = True)
u8.head(2)

  • fillna()
    處理缺失的資料,可以填充為自定義數字等,下面是再計算商戶特徵將特徵忘訓練集合並時,有的資料會為NaN值,將其填為中位數、平均數、最大、最小等,除了一般用法filla還有很多使用者用,可以參入函式來處理。
    df.fillna(method=‘ffill’)
    表示用前一個不為零的資料填充該列,又如df.fillna(method=‘ffill’, limit=2) 是過濾掉NAN值,且只填充前兩個。
merchant_feature = pd.merge(merchant_feature, m7, on = 'Merchant_id', how = 'left')
merchant_feature = merchant_feature.fillna(0)
  • drop_duplicates
    屬於過濾資料 移除重複項,比如在優惠券求每個使用者買個的商戶數量時進行了去重操作,預設會根據所有列相同去重,如果想要根據某列去重就需要傳入列名或列名陣列,另外其實每個方法基本都支援傳入inplace=True,表示改變原始資料的值,如果只想顯示哪行重複還可以使用duplicates會返回True 或False .
    # u_merchant_count : num of merchant user bought from
    u4 = df[df['Date'] != -10][['User_id', 'Merchant_id']].copy()
    u4.drop_duplicates(inplace = True)
    u4 = u4.groupby(['User_id'], as_index = False).count()
    u4.rename(columns = {'Merchant_id':'u_merchant_count'}, inplace = True)
  • get_dummies()
    該方法是處理離散變數的常用方法,因離散變數每行之間的大小比較關係不太大,重要的是哪個樣本取了哪個值,因為等於某個變為取值時我就讓其為1,沒有取值的列讓其為0,變為了啞變數、或指標變數,如典型的星期。下面即將週一到週日變為了one-hot encode展示。
# change weekday to one-hot encoding 
weekdaycols = ['weekday_' + str(i) for i in range(1,8)]
print(weekdaycols)
 
tmpdf = pd.get_dummies(dfoff['weekday'].replace('-10.0', np.nan))
tmpdf.columns = weekdaycols
dfoff[weekdaycols] = tmpdf
  • value_counts()
    這個方法求的是某個值出現的次數,常用來分析標籤類的個數,也可以把統計結果做成各種圖方便檢視,既然是統計每個值出現的個數,那需要先確定有哪些值可以使用unique()方法,返回一個去重後的陣列,在展示資料的時候遇到一個問題就是我根據條件過濾標籤後,進行統計,統計完的結果我往往不知道哪個值在上還是在下,不利於我展示圖形。
    解決方法是可以對value_counts()後的結果進行排序,具體實現看下面程式碼。
print(dfoff['label'].value_counts())
print('已有columns:',dfoff.columns.tolist())
dfoff.head(2)

obj = pd.Series(['c', 'a', 'd', 'a', 'a', 'b', 'b', 'c', 'c'])

# 對原列物件去重,得到唯一值列表,未排序
uniques = obj.unique()
print(uniques)

# 對唯一值列表排序
uniques.sort()
print(uniques)

# 排序方法一:返回的value_counts是一個Series物件 它包括索引和值,可以直接對索引排序
print(obj.value_counts().sort_index())

# 排序方法二:新建一個Series物件,對vales 和 index 賦值,index 先排好序
uc2 = pd.Series(obj.value_counts().values, index=uniques)
print(uc2)
  • apply()
    它常用來處理一列或者整個表格一起處理資料,可以傳入函式,在資料清洗、轉換等非常有用,如將滿減券轉為折扣券過程中一個方法即可完成。
def convertRate(row):
    """Convert discount to rate"""
    if row == -10 :
        return 1.0
    elif ':' in row:
        rows = row.split(':')
        return 1.0 - float(rows[1])/float(rows[0])
    else:
        return float(row)
        
def processData(df):
    # convert discunt_rate
    df['discount_rate'] = df['Discount_rate'].apply(convertRate)
    print(df['discount_rate'].unique())
    return df
    

模型好壞主因-有效的特徵

使用者特徵提取

1.使用者線下消費優惠券的日期
2.使用者線下消費優惠券的距離
3.使用者線下消費優惠券折扣率
4.使用者接收到優惠券數量
5.使用者購買記錄的數量(包括使用和非使用優惠券)
u_buy_count : times of user buy offline (with or without coupon)
6.使用者購買記錄的數量(使用優惠券)
u_buy_with_coupon : times of user buy offline (with coupon)
7使用者購買記錄的商戶數量(包括使用和非使用優惠券)
#u_merchant_count : num of merchant user bought from
8.使用者購買記錄(使用優惠券)與商家的各種距離,一個使用者不止一次購買,不止在一個商家
#u_min_distance、u_max_distance、u_mean_distance、u_median_distance
u_use_coupon_rate
9.使用者使用優惠券概率=使用者使用優惠券買東西數量 / 使用者擁有優惠券數量
u_buy_with_coupon_rate
10.使用者使用優惠券購買概率 = 使用者使用優惠券買東西數量 / 使用者購買數量
#calculate rate

商戶特徵提取

#m_coupon_count : num of coupon from merchant
11.每個商戶發放的優惠券數量
m_sale_count : num of sale from merchant (with or without coupon)
12.每個商戶賣出記錄(包括使用和非使用優惠券)
m_sale_with_coupon : num of sale from merchant with coupon usage
13.每個商戶賣出記錄(包括使用)
#m_min_distance
14.每個商戶賣出記錄(使用優惠券)與商家各種距離,一個商家不止一次賣出記錄,不止賣給一個顧客
#m_coupon_use_rate
15.商家優惠券使用概率 = 商家賣出的數量(使用優惠券) / 商家發放的優惠券數量
16.商家賣出的裡面優惠券概率 = 商家賣出的數量(使用優惠券) / 商家賣出的數量

       專案90%以上的程式碼是在處理各種特徵、提取、轉換、清洗等工作,特徵工程可見很重要,找出來的特徵越好,那麼模型效果越好,可以說在做專案的時候要重視特徵提取這塊,全力瞭解需求、瞭解業務場景是做好一個模型的前提,切記。

專案模型

       如果只是使用機器學習的分類、迴歸等,那sk-learn庫完全可以夠用,裡面包含了常用演算法的實現,這些庫往往是一些技術領導者封裝出來,如谷歌、IBM等,我們可以研究他們的實現思路,優惠券中用到了邏輯迴歸

  • 線性模型 邏輯迴歸
    SGDClassifier 在第一篇已經提及,這裡略過。。
  • LGBMClassifier
    lgbm基於boost思想實現的一個模型融合方法,基於逐漸提升演算法常用的融合演算法有adaboost、gbmboost等,sk-learn已經提供了實現方法,另外還有兩種實現框架xgboost、lgbmboost,他們效能更好一些,後面講詳細介紹。

API文件地址
http://lightgbm.apachecn.org/cn/latest/Python-API.html#scikit-learn-api

model = lgb.LGBMClassifier(
                    learning_rate = 0.01,   #提升學習率
                    boosting_type = 'gbdt', #提升樹的型別
                    objective = 'binary',#目標二分類
                    metric = 'logloss',#early_stop 對數損失
                    max_depth = 5,#提升學習率
                    sub_feature = 0.7,#
                    num_leaves = 3,#樹的最大葉子數
                    colsample_bytree = 0.7,#訓練特徵取樣率 列
                    n_estimators = 5000,#擬合的樹的棵樹,相當於訓練輪數
                    early_stop = 50,#提前結束輪數
                    verbose = -1)
model.fit(trainSub[predictors], trainSub['label'])

隨筆思考

改變人生的不是道理,而是習慣

       開始做一個專案時感覺這麼多內容要分析,有時難免有些躊躇不前,思想決定行為,表現出來後果是做這件事難免拖拖拉拉,效率可見非常緩慢,終於有一天起了個大早靜下心來一口氣梳理完了,發現也沒有想的那麼難,最重要的是有信心去做,心無旁騖的做,效率會很高,很快就會做完。
       從一片文章上提到“改變人一生的不是道理,而是習慣“,感覺頗有道理,道理是用來聽得、記得,而習慣是行動,每個人的生活無時無刻在發生各種動作、行為也即為習慣,成功與平庸的人相比並不是懂得更多的道理,而是將一個個大道理轉化為了行為習慣。