機器學習:用RFM給電商使用者做價值分組畫像

語言: CN / TW / HK

持續創作,加速成長!這是我參與「掘金日新計劃 · 10 月更文挑戰」的第3天,點選檢視活動詳情

前言

前篇文章《機器學習:從資料中找到使用者的RFM值》跟著課程進行了定義問題、資料收集和預處理得到了RFM值,但是並不能直觀的看出使用者的 “價值”分佈 情況,下面可以先通過分佈直方圖來大致的分佈情況。

大致看看RFM分佈情況

R值分佈

df_user['R值'].plot(kind='hist',bins=25,title='新進度分佈直方圖') #R值直方圖

image.png

F值分佈

df_user.query('F值 < 800')['F值'].plot(kind='hist',bins=50,title='消費頻率分佈直方圖') #F值直方圖

之所以篩選了 'F值 < 800' 是因為後面的值佔比過於小,可以通過df_user.describe()#df_user的統計資訊,預設只對數值類資料進行統計 檢視

image.png

M值分佈

df_user.query('M值 < 20000')['M值'].plot(kind='hist',bins=50,title='消費金額分佈直方圖') #M值直方圖

image.png

第一感受是越靠近前面的值人數越多,但是並不能將使用者劃分為像“高”、“中”、“低”價值。

那麼我們有沒有辦法將使用者劃分為呢?當然可以最簡單的方法是去試比如將R值0-50分為一組,50-150分為一組,150以上分為一組,看使用者是不是在次分組下聚集,如果不聚集就繼續嘗試,很顯然這種方法不夠高效,那麼就需要藉助演算法了。

使用聚類演算法貼標籤

給使用者分組畫像屬於無監督學習,因為源資料中沒有欄位指明使用者的價值是“高”還是“低”。在無監督學習中,聚類和降維是最常見的演算法,這裡要使用的就是聚類了。

聚類演算法

聚類演算法可以讓機器把資料集中的樣本按照特徵的性質分組,不過它只幫助我們把特徵彼此鄰近的使用者聚成一組(這裡的組稱為聚類的蔟)。而這裡說的“特徵彼此鄰近”,指的這些使用者的資料特徵在座標系中有更短的向量空間距離。也就是說,聚類演算法是把空間位置相近的特徵資料歸為同一組。

image.png

分為組之後就可以人為貼標籤了,比如這裡的“價值高低”。這樣就可以實現監督學習向監督學習的轉換。

K-Means演算法

課程中作者沒有說為啥選擇K-Means,這個展示擱置。

演算法中的K代表聚類的簇(也就是組)的個數,指定K的數值後,K-Means演算法會在資料中隨機挑選出K個數據點,作為簇的質心(centroid),這些質心就是未來每個簇的中心點,演算法會根據其他資料點和它的距離來進行聚類。

如果質心離在資料簇中不夠中心就會進行移動,直到質心的移動變化很小了,或者說固定不變了,那麼K-Means演算法就可以停止了。

下面是選取質心並移動的過程:

image.png

那麼K值怎麼確定呢?

手肘法選取K值

“手肘法”(elbow method)可以幫我們決定,在某一批資料點中,資料分為多少組比較合適。

手肘法是通過聚類演算法的損失值曲線來直觀確定簇的數量。損失值曲線,就是以影象的方法繪出,取每一個K值時,各個資料點距離質心的平均距離。

image.png

定義手肘點的函式: from sklearn.cluster import KMeans #匯入KMwans模組 def show_elbow(df): # 定義手肘函式 distance_list = [] # 聚質心的距離(損失) K = range(1,9) #K值範圍 for k in K: kmeans = KMeans(n_clusters=k,max_iter=100) # 建立KMeans模型 kmeans = kmeans.fit(df) # 擬合模型 distance_list.append(kmeans.inertia_) # 建立每個K值的損失 plt.plot(K,distance_list,'bx-') # 繪畫 plt.xlabel('k') # X軸 plt.ylabel('距離均方誤差') # Y軸 plt.title('k值手肘圖') # 標題

R值聚類K值手肘圖: show_elbow(df_user[['R值']]) # 顯示R值聚類K值手肘圖

image.png

F值聚類K值手肘圖: show_elbow(df_user[['F值']]) # 顯示F值聚類K值手肘圖

image.png

M值聚類K值手肘圖: show_elbow(df_user[['M值']]) # 顯示M值聚類K值手肘圖

image.png

選取肘部位置,選擇3作為R值簇的個數,選擇4作為F值簇的個數(筆者覺得5才是,先按課程的來),選擇4作為M值簇的個數(筆者覺得3才是,先按課程的來)。

建立和訓練模型

建立模型

from sklearn.cluster import KMeans #匯入KMeans模組 kmeans_R = KMeans(n_clusters=3) #設定K=3 kmeans_F = KMeans(n_clusters=4) #設定K=4 kmeans_M = KMeans(n_clusters=4) #設定K=4

訓練模型

kmeans_R.fit(df_user[['R值']]) #擬合模型 kmeans_F.fit(df_user[['F值']]) #擬合模型 kmeans_M.fit(df_user[['M值']]) #擬合模型

使用模型進行聚類,並給使用者分組

給R、F、M值聚類

df_user['R值層級']=kmeans_R.predict(df_user[['R值']]) #通過聚類模型求出R值的層級 df_user.head()#顯示頭幾行資料

image.png

df_user.groupby('R值層級')['R值'].describe() # R值層級分組統計資訊

image.png

0表示距離上次消費以來從231到372天,1表示0-94天,2表示95-225天。可以看出不能直接使用體現價值的高低,需要人為排序。

為聚類的層級做排序

```

定義一個order_cluster函式為聚類排序

def order_cluster(cluster_name, target_name,df,ascending=False): new_cluster_name = 'new_' + cluster_name #新的聚類名稱 df_new = df.groupby(cluster_name)[target_name].mean().reset_index() #按聚類結果分組,建立df_new物件 df_new = df_new.sort_values(by=target_name,ascending=ascending).reset_index(drop=True) #排序 df_new['index'] = df_new.index #建立索引欄位 df_new = pd.merge(df,df_new[[cluster_name,'index']], on=cluster_name) #基於聚類名稱把df_new還原為df物件,並新增索引欄位 df_new = df_new.drop([cluster_name],axis=1) #刪除聚類名稱 df_new = df_new.rename(columns={"index":cluster_name}) #將索引欄位重新命名為聚類名稱欄位 return df_new #返回排序後的df_new物件 ```

  • 排序後的R值聚類 df_user=order_cluster('R值層級','R值',df_user,False) df_user.groupby('R值層級')['R值'].describe()

image.png

  • 排序後的F值聚類 df_user['F值層級']=kmeans_F.predict(df_user[['F值']]) # 通過聚類模型求出F值的層級 df_user=order_cluster('F值層級','F值',df_user,True) # 呼叫蔟排序函式 df_user.groupby('F值層級')['F值'].describe()

image.png - 排序後的M值聚類 df_user['M值層級'] = kmeans_M.predict(df_user[['M值']]) #通過聚類模型求出M值的層級 df_user = order_cluster('M值層級', 'M值',df_user,True) #呼叫簇排序函式 df_user.groupby('M值層級')['M值'].describe() #M值層級分組統計資訊 df_user = df_user.sort_values(by='使用者碼',ascending=True).reset_index(drop=True) #根據使用者碼排序 df_user.head() #顯示頭幾行資料

image.png

為使用者整體分組畫像

這裡可以把R、F、M三個層級的值相加,得到總體價值。 df_user['總分']=df_user['R值層級']+df_user['F值層級']+df_user['M值層級'] # 求出每個使用者RFM總分 總價值,最大值為8,所以範圍是0-8,可以根據以下規則給使用者分層: - 0-2 分,低價值使用者 - 3-4 分,中價值使用者 - 5-8 分,高價值使用者

```

在df_user物件中新增總體價值這個欄位

df_user.loc[(df_user['總分']<=2) & (df_user['總分']>=0), '總體價值'] = '低價值' df_user.loc[(df_user['總分']<=4) & (df_user['總分']>=3), '總體價值'] = '中價值' df_user.loc[(df_user['總分']<=8) & (df_user['總分']>=5), '總體價值'] = '高價值' df_user #顯示df_user ```

image.png

現在有了“標籤”可以看看R、F、M和標籤的相關性: ```

顯示高、中、低價值組分佈散點圖(F值與M值)

plt.scatter(df_user.query("總體價值 == '高價值'")['F值'],df_user.query("總體價值 == '高價值'")['M值'],c='g',marker='*') plt.scatter(df_user.query("總體價值 == '中價值'")['F值'], df_user.query("總體價值 == '中價值'")['M值'],marker=8) plt.scatter(df_user.query("總體價值 == '低價值'")['F值'], df_user.query("總體價值 == '低價值'")['M值'],c='r') ```

image.png

來源

06 | 聚類分析:如何用RFM給電商使用者做價值分組畫像?