運用RFM模型分析用戶價值度

背景概念概

用戶數據化運營是互聯網運營工作必備工作之一,且產品的生存必須有用戶。而會員價價值度是用來評估用戶的價值情況,是區分會員價值的重要性模型和參考依據,也是衡量不同營銷效果的關鍵指標之一,我們可以通過復購率、消費頻率、最近一次購買時間、最近一次購買金額等方面分析會員價值度。

常用的價值度模型是RFM。RFM模型是根據會員最近一次購買時間R(Rencency)、購買頻率F(Frequency)、購買金額M(Monetary)計算得出RFM分,通過這三個維度來評估客戶的用戶活躍價值。RFM模型基於一個固定時間點來做模型分析,分析的時間節點不同,所得到的結果也是不同的。

RFM模型分析步驟

1 、 設定分析數據的截止時間節點(如2018-4-1),用來做基於該時間節點的數據選取和計算。

2 、 在用戶資料庫中,以步驟1設定的時間節點為界限向前推一固定周期(如一周年、一個月等),選擇截取每個會員的會員ID、訂單時間、訂單金額的原始數據集。

3 、根據獲取到的原始數據集,分別計算

最近一次購買時間R(Rencency):各個會員最近的訂單時間與截止時間節點的距離;

購買頻率F(Frequency):以會員ID為區分,分別統計各會員ID的訂單數量;

購買金額M(Monetary):將用戶多個訂單的訂單金額求和。

4、 對R、F、M值進行分區。對於F和M變數來講,值越大代表購買頻率越高、訂單金額越 高;但對R來講值越小代表離截止時間節點越近,因此值越好。對R、F、M分別使用五分位(也可以分成其他分位,如三分位)法做數據分區,需要注意的是,對於R來講需要倒過來劃分,離截止時間越近的值劃分越大。

5、 將三個值組合或相加得到總的RFM得分。這裡有兩種得分方式,一種是直接將三個值拼接到一起,例如RFM得分為213、131、122;一種是直接將三個值相加求得一個新的匯總值,例如RFM得分為7、6、9。在得到不同會員的RFM的之後,根據步驟5產生的兩種結果有不用的應用思路:

應用思路

1:基於三個維度值做用戶群體劃分和解讀,對用戶的價值度做分析。例如得分為213的會員往往購買頻率較低,針對購買頻率低的客戶定期發送促銷活動郵件;針對得分為131的會員雖然購買頻率高但是訂單金額低等,這些客戶往往具有較高的購買粘性,可以考慮通過關聯或搭配銷售的方式提升訂單金額。

2:基於RFM的匯總得分評估所有會員的價值度價值,並可以做價值度排名;同時,該得分還可以作為輸入維度跟其他維度一起作為其他數據分析和挖掘模型的輸入變數,為分析建模提供基礎。

案例詳解

一、導入模塊庫

import numpy as np # 導入numpy庫import pandas as pd # 導入pandas庫import mysql.connector # 導入mysql連接庫import time # 導入時間庫

MYSQL Connector Python 資料庫連接工具官方安裝包dev.mysql.com

上面是mysql.connector庫的官方連接安裝包,可以對應自己的操作環境安裝適應的包。

二、讀取原始數據

dtypes = {SALEDATE: object, SALEID: object, AMOUNTINFO: np.float32} # 設置每列數據類型raw_data = pd.read_csv(sales1.csv, dtype=dtypes, index_col=USERID) # 讀取數據文件

提前用字典定義dtypes,便於對原始數據讀取時對數據框數據類型的自定義,如未定義則為系統默認類型。本次將SALEDATE(銷售時間)和SALEID(訂單ID)設置為字元串對象,對

AMOUNTINFO(訂單金額)設為浮點型。

該數據已直接存放在python分析系統目錄下,使用pd.read_csv 讀取數據文件,該數據已直接存放在python分析系統目錄下不需要設置路徑,可直接讀取。默認的csv是以逗號為分隔,因此無需制定分隔符。按上述字典設置參數dtype,同時以用戶ID為索引列。

三、對數據查看

print (raw_data.head(10)) # 列印原始數據前10條

通過head方法輸出前10條數據。

print (raw_data.describe()) # 列印原始數據基本描述性信息

通過數據框的describe方法輸出描述性統計信息。

在本案例中,發現數據的極值相差非常大,並且標準差也很大,說明數據波動非常明顯。另外,最大值和最小值似乎有些奇怪:最大值竟然有超過 30000 元、最小值卻只有 0.5 元,這兩種狀態都非常異常。對這些情況需要與業務部門溝通,對於低於10元的訂單是否是因為優惠券訂單而生成,因此對這些數據去除。

na_column = raw_data.isnull().any(axis=0) # 查看每一列是否具有缺失值print (na_column) # 查看具有缺失值的列

缺失值對後續分析會產生影響,因此檢查數據中是否有缺失值。

na_lines = raw_data.isnull().any(axis=1) # 查看每一行是否具有缺失值print (Total number of NA lines is: {0}.format(na_lines.sum())) # 查看具有缺失值的行總記錄

通過raw_data.isnull().any(axis=0)來判斷所有列是否含有缺失信息,其中的 isnull 用來查看是否有缺失值,any 用來判斷數據記錄中的任何一個位置出現缺失值都會計算在內,參數 axis=0 以列查看。

print (raw_data[na_lines]) # 只查看具有缺失值的行信息

通過放回統計查看,缺失值的行數只有10條,佔總體比例非常小,因此可以直接刪除。

四、對數據預處理

異常值處理

sales_data = raw_data.dropna() # 丟棄帶有缺失值的行記錄sales_data = sales_data[sales_data[AMOUNTINFO] > 10] # 丟棄訂單金額<=10的記錄sales_data[SALEDATE] = pd.to_datetime(sales_data[SALEDATE], format=%Y-%m-%d) # 將字元串轉換為日期格式

日期轉換的目的是實現時間間隔的計算,算出 R最近時間距離天數。

通過dropna方法刪除缺失值。

print (sales_data.dtypes)

分別計算 R、F、M 三個原始變數的數值

recency_value = sales_data[SALEDATE].groupby(sales_data.index).max() # 計算原始最近一次訂單時間frequency_value = sales_data[SALEDATE].groupby(sales_data.index).count() # 計算原始訂單頻率monetary_value = sales_data[AMOUNTINFO].groupby(sales_data.index).sum() # 計算原始訂單總金額

通過數據框的 groupby 方法計算各值,以原始數據框索引為主鍵分別對求訂單時間最大值,訂單計數統計,對訂單額求和。

五、計算RFM得分

deadline_date = pd.datetime(2017, 1, 1) # 指定一個時間節點,用於計算其他時間與該時間的距離

r_distance = (deadline_date - recency_value).dt.days # 計算R間隔r_score = pd.cut(r_distance, 5, labels=[5, 4, 3, 2, 1]) # 計算R得分f_score = pd.cut(frequency_value, 5, labels=[1, 2, 3, 4, 5]) # 計算F得分m_score = pd.cut(monetary_value, 5, labels=[1, 2, 3, 4, 5]) # 計算M得分

pd.datetime方法指定時間節點,dt.days方法獲取時間間隔天數。通過pd.cut 方法對三個變數值使用分位數做區間劃分,默認設置為 5 份,同時通過 labels 標籤指定區間標誌。要注意的是R區分值,數值越大指離指定時間越遠,因此其區間劃分後的值應該越小。

rfm_list = [r_score, f_score, m_score] # 將r、f、m三個維度組成列表rfm_column = [r_score, f_score, m_score] # 設置r、f、m三個維度列名rfm_pd = pd.DataFrame(np.array(rfm_list).transpose(), dtype=np.int32,columns=rfm_column,index=frequency_value.index) # 建立r、f、m數據框

建立 R、F、M 三個維度的值列表和名稱列表,用於生成數據框時指定數據和標籤。用pd.DataFrame 建立數據框。np.array 將 R、F、M 生成的值列錶轉換為矩陣。此時的矩陣形狀是(3,51778),不符合我們需要的三列的需求,因此使用 transpose 方法對矩陣做轉置處理。R、F、M 三個 Series 的索引都相同,可隨便指定一列為索引列。

print (rfm_pd.head())

rfm_pd[rfm_score] = rfm_pd[r_score] * 0.7 + rfm_pd[f_score] * 0.2 + rfm_pd[m_score] * 0.1

根據業務情況來設定個權重值,如更注重用戶的活躍度,次關注訪問頻率,最後為訂單金額。

rfm_pd_1 = rfm_pd.copy()rfm_pd_1[r_score] = rfm_pd_1[r_score].astype(str)rfm_pd_1[f_score] = rfm_pd_1[f_score].astype(str)rfm_pd_1[m_score] = rfm_pd_1[m_score].astype(str)rfm_pd[rfm_comb]=rfm_pd_1[r_score].str.cat(rfm_pd_1[f_score]).str.cat(rfm_pd_1[m_score])

依照方法二中,將R、F、M 三個值組合,組成一個三位數,通過字元串組合。通過pandas 的字元串處理庫 str 中的 cat 方法做字元串合併,該方法可以將右側的數據合併到左側

六、輸出保存結果

print (rfm_pd.head()) # 列印數據前5項結果

print (rfm_pd.describe())

將RFM得分文件保存到本地,便於業務做進一步分析應用。

rfm_pd.to_csv(sales_rfm_score1.csv)

可以將 RFM 得分寫入數據框,方便為其他模型做輸入維度,這裡使用MySQL 官方連接程序實現。

table_name = sales_rfm_score1 # 要寫庫的表名

通過 table_name=sales_rfm_score定義要寫入的表的名稱,該變數會在後續表識別和寫入時用到。config 定義了一個用於寫入資料庫的詳細配置信息定義。

config = {host: 127.0.0.1, # 默認127.0.0.1 user: root, # 用戶名 password: 123456, # 密碼 port: 3306, # 埠,默認為3306 database: python_data, # 資料庫名稱 charset: gb2312 # 字元編碼 }

con = mysql.connector.connect(**config) # 建立mysql連接cursor = con.cursor() # 獲得游標

在將數據寫入資料庫之前,需要先判斷資料庫中是否存在要寫入的表。如果不存在需要新建數據表。

cursor.execute("show tables") #table_object = cursor.fetchall() # 通過fetchall方法獲得所有數據table_list = [] # 創建庫列表

for t in table_object: # 循環讀出所有庫 table_list.append(t[0]) # 每個每個庫追加到列表

if not table_name in table_list: # 如果目標表沒有創建 cursor.execute( CREATE TABLE %s ( user_id VARCHAR(20), r_score int(2), f_score int(2), m_score int(2), rfm_score DECIMAL(10,2), rfm_comb VARCHAR(10), insert_date VARCHAR(20) )ENGINE=InnoDB DEFAULT CHARSET=gb2312 % table_name) # 創建新表

user_id = rfm_pd.index # 索引列rfm_score = rfm_pd[rfm_score] # RFM加權得分列rfm_comb = rfm_pd[rfm_comb] # RFM組合得分列timestamp = time.strftime(%Y-%m-%d, time.localtime(time.time())) # 寫庫日期

print (Begin to insert data into table {0}....format(table_name)) # 輸出開始寫庫的提示信息for i in range(rfm_pd.shape[0]): # 設置循環次數並依次循環 insert_sql = "INSERT INTO `%s` VALUES (%s,%s,%s,%s,%s,%s,%s)" % (table_name, user_id[i], r_score.iloc[i], f_score.iloc[i], m_score.iloc[i], rfm_score.iloc[i],rfm_comb.iloc[i], timestamp) # 寫庫SQL依據 cursor.execute(insert_sql) # 執行SQL語句,execute函數裡面要用雙引號 con.commit() # 提交命令cursor.close() # 關閉游標con.close() # 關閉資料庫連接print (Finish inserting, total records is: %d % (i + 1)) # 列印寫庫結果

七、結論:

公司的會員中 99%以上的客戶消費狀態都不容樂觀,主要體現在消費頻率低 R、消費總金額低 M。——經過分析,這裡主要由於其中有一個用戶(ID 為 74270)消費金額非常高,導致做 5 分位時收到最大值的影響,區間向大值域區偏移。

公司中有一些典型客戶的整個貢獻特徵明顯,重點是 RFM 得分為 555 的用戶(ID 為 74270),該用戶不僅影響了訂單金額高,而且其頻率和購買新鮮度和消費頻率都非常高,應該引起會員管理部門的重點關注。

推薦閱讀:

初學R並實現探索性數據分析
大咖聊數據| 滴滴出行李觀:數據維度上的評估效果,最直接看LTV
R語言——回歸分析
淺談群組分析(Cohort Analysis)之於產品運營的價值
推薦書單:數據分析看懂財報是做到高層必備的能力

TAG:數據分析 | 用戶運營 |