本案例由開發者:天津師範大學協同育人項目–翟羽佳提供
最新案例動態,請查閲 《【案例共創】基於華為開發者空間,實現RFM分析與CLTV預測的電商客户細分與營銷策略優化》。小夥伴快來領取華為開發者空間進行實操吧!
一、概述
1. 案例介紹
隨着電子商務行業的競爭加劇,企業需要更加精細化的客户管理策略來提升客户忠誠度和營銷效率。根據最新的市場調研,電商行業平均客户流失率高達35%,而營銷活動的平均投資回報率(ROI)僅為 1:4,遠低於行業標杆水平(數據來源:2024 年電商行業報告)。
在此背景下,客户關係管理(CRM)和客户生命週期價值(CLTV)分析成為提升企業競爭力的關鍵。通過客户細分和精準營銷,企業可以有效提升客户價值,優化資源配置,實現可持續增長。數據科學價值通過RFM模型和CLTV預測的結合,項目實現:
1.算法創新:使用 BG-NBD 模型預測客户的未來購買行為,Gamma-Gamma 模型預測客户的平均交易價值,結合RFM分羣實現精準客户細分;
2.業務落地:識別高價值“忠誠客户羣體” (佔比 “10%”,CLTV 值超均值 3 倍);定位“高潛流失羣”體 (購買頻次下降且消費金額減少),設計專屬挽回策略;
3.財務收益:預計首年推動營銷成本下降 15%,高價值客户 LTV 提升25%。
2. 適用對象
- 企業
- 個人開發者
- 高校學生
3. 案例時間
本案例總時長預計90分鐘。
4. 案例流程
説明:
- 配置AI Notebook和運行環境環境;
- 從OBS下載文件;
- 編輯並運行代碼;
5. 資源總覽
本案例預計花費0元。
|
資源名稱 |
規格 |
單價(元) |
時長(分鐘) |
|
開發者空間AI Notebook |
NPU basic | 1 \* NPU 910B | 8v CPU | 24GB | euler2.9-py310-torch2.1.0-cann8.0-openmind0.9.1-notebook
|
0
|
90
|
二、開發者空間AI Notebook和運行環境配置
1. 開發者空間AI Notebook配置
本案例中,使用開發者空間AI Notebook進行代碼編寫、功能實現,華為開發者空間Notebook是一款面向開發者的一站式雲端開發工具,主要用於AI開發、數據分析、模型訓練等場景。
開發者直接進入到開發者空間工作台。
進入到開發者空間工作台後,找打AI Notebook,點擊立即前往。
進入到AI Notebook頁面後,選擇NPU環境點擊立即啓動。
稍等片刻後點擊查看Notebook,前往Notebook主頁面。
至此,成功打開Notebook。
2. 運行環境配置
打開Notebook後,點擊筆記下的python 3,創建代碼編寫文件。
3. 安裝依賴庫
通過如下指令,安裝python第三方依賴庫。
pip install numpy
pip install pandas
pip install matplotlib
pip install scikit-learn
pip install seaborn
pip install pygments
pip install lifetimes
pip install openpyxl
pip install squarify
pip install sqlalchemy
注:若安裝失敗或安裝過程較慢,可以更換國內鏡像源。
pip install numpy pandas matplotlib scikit-learn seaborn pygments lifetimes openpyxl squarify sqlalchemy -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn
系統會自動安裝相關的包和工具,當安裝完成後,系統會返回所有已成功安裝的庫,如下圖所示:
安裝成功後對腳本進行運行可得到關於 Python 數據處理全流程開發,並具備將本地模型遷移至華為雲實現工業級部署的能力。
注:在安裝三方庫的末尾,日誌顯示Note: you may need to restart the kernel to use updated packages.,這裏系統提示我們需要手動重啓內核來更新環境,點擊Notebook頂部菜單欄內核\>重啓內核。
三、代碼實現與運行驗證
1. 獲取原始數據
為了方便項目運行,已提前將文件上傳OBS,之後通過分享鏈接在Notebook中可直接下載使用。文件壓縮包中包含後續所有的文件:
OBS鏈接地址:https://case-aac4.obs.cn-north-4.myhuaweicloud.com/online_retail_II
下載命令行:
!wget https://case-aac4.obs.cn-north-4.myhuaweicloud.com/online_retail_II
2. 功能分析
數據清洗:處理缺失值、異常值、退貨訂單。
RFM分析:通過Recency、Frequency、Monetary對客户分層。
CLTV預測:結合概率模型預測客户長期價值,支持業務決策。
可視化:貫穿始終,輔助理解數據分佈和結果。
3. 代碼實現
3.1 數據導入與初始化
# 導入所需的庫
from sqlalchemy import create_engine # 用於創建數據庫連接
import datetime as dt # 用於處理日期和時間
import pandas as pd # 用於數據處理和分析
import seaborn as sns # 用於數據可視化
import matplotlib.pyplot as plt # 用於繪圖
from lifetimes import BetaGeoFitter # 用於BG/NBD模型的擬合
from lifetimes import GammaGammaFitter # 用於Gamma-Gamma模型的擬合
from lifetimes.plotting import plot_period_transactions # 用於繪製週期交易圖
from sklearn.preprocessing import MinMaxScaler # 用於數據歸一化
import squarify # 用於繪製樹狀圖(treemap)
import warnings # 用於處理警告信息
warnings.filterwarnings("ignore") # 忽略警告信息
# 遍歷指定目錄下的文件
import os
for dirname, _, filenames in os.walk('/kaggle/input'):
for filename in filenames:
print(os.path.join(dirname, filename))
# 使用 Pandas 的 read_excel 函數讀取 Excel 文件中的數據
df_2010_2011 = pd.read_excel(r"online_retail_II", sheet_name="Year 2010-2011")
# 創建一個 DataFrame 的副本,命名為 df保留原始數據 df_2010_2011
df = df_2010_2011.copy()
# 使用 DataFrame 的 head() 方法查看數據的前 5 行
df.head()
3.2 數據預處理
# 使用 Pandas 的字符串操作方法 str.contains() 檢查 "Invoice" 列中的值是否包含 "C"
df = df[~df["Invoice"].str.contains("C", na=False)]
# 刪除 DataFrame 中包含缺失值的所有行
df.dropna(inplace=True)
# 定義異常值處理函數
def outlier_thresholds(dataframe, variable):
quartile1 = dataframe[variable].quantile(0.01)
quartile3 = dataframe[variable].quantile(0.99)
interquantile_range = quartile3 - quartile1
up_limit = quartile3 + 1.5 * interquantile_range
low_limit = quartile1 - 1.5 * interquantile_range
return low_limit, up_limit
def replace_with_thresholds(dataframe, variable):
low_limit, up_limit = outlier_thresholds(dataframe, variable)
dataframe.loc[(dataframe[variable] < low_limit), variable] = low_limit
dataframe.loc[(dataframe[variable] > up_limit), variable] = up_limit
# 處理異常值
replace_with_thresholds(df, "Quantity")
replace_with_thresholds(df, "Price")
3.3 數據概覽函數
# 定義函數 check_df,用於快速檢查 DataFrame 的基本信息
def check_df(dataframe):
print("################ Shape ####################")
print(dataframe.shape)
print("############### Columns ###################")
print(dataframe.columns)
print("############### Types #####################")
print(dataframe.dtypes)
print("############### Head ######################")
print(dataframe.head())
print("############### Tail ######################")
print(dataframe.tail())
print("############### Describe ###################")
print(dataframe.describe().T)
# 調用 check_df 函數
check_df(df)
3.4 類別型變量分析
# 獲取類別型變量
cat_cols = [col for col in df.columns if df[col].dtypes == "O"]
cat_but_car = [col for col in df.columns if df[col].nunique() > 100 and df[col].dtypes == "O"]
cat_cols = [col for col in cat_cols if col not in cat_but_car]
# 定義類別型變量分析函數
def cat_summary(dataframe, col_name, plot=False):
print(pd.DataFrame({col_name: dataframe[col_name].value_counts(),
"Ratio": 100 * dataframe[col_name].value_counts() / len(dataframe)}))
print("##########################################")
if plot:
fig_dims = (15, 5)
fig, ax = plt.subplots(figsize=fig_dims)
sns.countplot(x=dataframe[col_name], data=dataframe)
plt.xticks(rotation=45, ha='right')
plt.savefig("Country")
plt.close()
# 分析國家分佈
cat_summary(df, "Country", plot=True)
3.5 數值型變量分析
# 獲取數值型變量
num_cols = [col for col in df.columns if df[col].dtypes != 'O' and col not in ["Customer ID"]]
# 定義數值型變量分析函數
def num_summary(dataframe, numerical_col, plot=False):
if dataframe[numerical_col].dtype in ['int64', 'float64']:
quantiles = [0.05, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 0.95, 0.99]
print(dataframe[numerical_col].describe(quantiles).T)
if plot:
dataframe[numerical_col].hist(bins=20)
plt.xlabel(numerical_col)
plt.title(numerical_col)
plt.savefig(f"{numerical_col}_histogram.png")
plt.close()
# 分析數值型變量
for col in num_cols:
num_summary(df, col, plot=True)
3.6 商品銷售分析
# 分析商品銷售情況
df["StockCode"].nunique()
df_product = df.groupby("Description").agg({"Quantity": "count"}).reset_index()
top_pr = df_product.sort_values(by="Quantity", ascending=False).head(10)
sns.barplot(x="Description", y="Quantity", data=top_pr)
plt.xticks(rotation=90)
plt.savefig("Description")
plt.close()
3.7 RFM分析
# 計算總銷售額
df["TotalPrice"] = df["Price"] * df["Quantity"]
# 計算RFM指標
df["InvoiceDate"] = pd.to_datetime(df["InvoiceDate"])
today_date = dt.datetime(2011, 12, 11)
rfm = df.groupby("Customer ID").agg({
"InvoiceDate": lambda InvoiceDate: (today_date - InvoiceDate.max()).days,
"Invoice": lambda Invoice: Invoice.nunique(),
"TotalPrice": lambda TotalPrice: TotalPrice.sum()
})
rfm.columns = ["recency", "frequency", "monetary"]
rfm = rfm[rfm["monetary"] > 0]
# 計算RFM分數
rfm["recency_score"] = pd.qcut(rfm['recency'], 5, labels=[5, 4, 3, 2, 1])
rfm["frequency_score"] = pd.qcut(rfm["frequency"].rank(method="first"), 5, labels=[1, 2, 3, 4, 5])
rfm["monetary_score"] = pd.qcut(rfm["monetary"], 5, labels=[1, 2, 3, 4, 5])
rfm["RFM_SCORE"] = (rfm["recency_score"].astype(str) + rfm["frequency_score"].astype(str))
# 客户分段
seg_map = {
r'[1-2][1-2]': 'hibernating',
r'[1-2][3-4]': 'at_Risk',
r'[1-2]5': 'cant_loose',
r'3[1-2]': 'about_to_sleep',
r'33': 'need_attention',
r'[3-4][4-5]': 'loyal_customers',
r'41': 'promising',
r'51': 'new_customers',
r'[4-5][2-3]': 'potential_loyalists',
r'5[4-5]': 'champions'
}
rfm['segment'] = rfm['RFM_SCORE'].replace(seg_map, regex=True)
# 分段分析
rfm[["segment", "recency", "frequency", "monetary"]].groupby("segment").agg(["mean", "count"])
# 可視化
sgm = rfm["segment"].value_counts()
plt.figure(figsize=(10, 7))
sns.barplot(x=sgm.index, y=sgm.values)
plt.xticks(rotation=45)
plt.title('Customer Segments2', color='blue', fontsize=15)
plt.savefig("Customer Segments2")
plt.close()
# 樹狀圖
df_treemap = rfm.groupby('segment').agg('count').reset_index()
fig, ax = plt.subplots(1, figsize=(10, 10))
squarify.plot(sizes=df_treemap['RFM_SCORE'],
label=df_treemap['segment'],
alpha=0.8,
color=['tab:red', 'tab:purple', 'tab:brown', 'tab:pink', 'tab:gray'])
plt.axis('off')
plt.savefig("2")
plt.close()
3.8 CLTV預測
# 準備CLTV數據
cltv_df = df.groupby('Customer ID').agg({
'InvoiceDate': [lambda date: (date.max() - date.min()).days,
lambda date: (today_date - date.min()).days],
'Invoice': lambda num: num.nunique(),
'TotalPrice': lambda TotalPrice: TotalPrice.sum()
})
cltv_df.columns = ['recency', 'T', 'frequency', 'monetary']
cltv_df["monetary"] = cltv_df["monetary"] / cltv_df["frequency"]
cltv_df = cltv_df[(cltv_df['frequency'] > 1) & (cltv_df['monetary'] > 0)]
cltv_df["recency"] = cltv_df["recency"] / 7
cltv_df["T"] = cltv_df["T"] / 7
# BG/NBD模型
bgf = BetaGeoFitter(penalizer_coef=0.001)
bgf.fit(cltv_df['frequency'], cltv_df['recency'], cltv_df['T'])
cltv_df["expected_purc_1_week"] = bgf.predict(1, cltv_df['frequency'], cltv_df['recency'], cltv_df['T'])
cltv_df["expected_purc_1_month"] = bgf.predict(4, cltv_df['frequency'], cltv_df['recency'], cltv_df['T'])
# Gamma-Gamma模型
ggf = GammaGammaFitter(penalizer_coef=0.01)
ggf.fit(cltv_df['frequency'], cltv_df['monetary'])
cltv_df["expected_average_profit"] = ggf.conditional_expected_average_profit(cltv_df['frequency'], cltv_df['monetary'])
# 計算CLTV
cltv = ggf.customer_lifetime_value(
bgf, cltv_df['frequency'], cltv_df['recency'], cltv_df['T'], cltv_df['monetary'],
time=6, freq="W", discount_rate=0.01
)
cltv_final = cltv_df.merge(cltv.reset_index(), on="Customer ID", how="left")
# 歸一化和分段
cltv_final["scaled_clv"] = MinMaxScaler().fit_transform(cltv_final[["clv"]])
cltv_final["segment"] = pd.qcut(cltv_final["scaled_clv"], 4, labels=["D", "C", "B", "A"])
4 運行程序代碼
代碼編輯完成後,點擊運行按鈕,等待程序運行(過程約5分鐘)。
程序運行結束後,輸出分析結果:
################ Shape ####################
(397925, 8)
############### Columns ###################
Index(['Invoice', 'StockCode', 'Description', 'Quantity', 'InvoiceDate',
'Price', 'Customer ID', 'Country'],
dtype='object')
############### Types #####################
Invoice object
StockCode object
Description object
Quantity float64
InvoiceDate datetime64[ns]
Price float64
Customer ID float64
Country object
dtype: object
############### Head ######################
Invoice StockCode Description Quantity \
0 536365 85123A WHITE HANGING HEART T-LIGHT HOLDER 6.0
1 536365 71053 WHITE METAL LANTER 6.0
2 536365 84406B CREAM CUPID HEARTS COAT HANGER 8.0
3 536365 84029G KNITTED UNION FLAG HOT WATER BOTTLE 6.0
4 536365 84029E RED WOOLLY HOTTIE WHITE HEART. 6.0
InvoiceDate Price Customer ID Country
0 2010-12-01 08:26:00 2.55 17850.0 United Kingdom
1 2010-12-01 08:26:00 3.39 17850.0 United Kingdom
2 2010-12-01 08:26:00 2.75 17850.0 United Kingdom
3 2010-12-01 08:26:00 3.39 17850.0 United Kingdom
4 2010-12-01 08:26:00 3.39 17850.0 United Kingdom
############### Tail ######################
Invoice StockCode Description Quantity \
541905 581587 22899 CHILDREN'S APRON DOLLY GIRL 6.0
541906 581587 23254 CHILDRENS CUTLERY DOLLY GIRL 4.0
541907 581587 23255 CHILDRENS CUTLERY CIRCUS PARADE 4.0
541908 581587 22138 BAKING SET 9 PIECE RETROSPOT 3.0
541909 581587 POST POSTAGE 1.0
InvoiceDate Price Customer ID Country
541905 2011-12-09 12:50:00 2.10 12680.0 France
541906 2011-12-09 12:50:00 4.15 12680.0 France
541907 2011-12-09 12:50:00 4.15 12680.0 France
541908 2011-12-09 12:50:00 4.95 12680.0 France
541909 2011-12-09 12:50:00 18.00 12680.0 France
############### Describe ###################
count mean min \
Quantity 397925.0 11.833709 1.0
InvoiceDate 397925 2011-07-10 23:44:09.817126400 2010-12-01 08:26:00
Price 397925.0 2.893201 0.0
Customer ID 397925.0 15294.308601 12346.0
25% 50% 75% \
Quantity 2.0 6.0 12.0
InvoiceDate 2011-04-07 11:12:00 2011-07-31 14:39:00 2011-10-20 14:33:00
Price 1.25 1.95 3.75
Customer ID 13969.0 15159.0 16795.0
max std
Quantity 298.5 25.534486
InvoiceDate 2011-12-09 12:50:00 NaN
Price 37.06 3.227143
Customer ID 18287.0 1713.172738
Country Ratio
Country
United Kingdom 354345 89.048187
Germany 9042 2.272287
France 8343 2.096626
EIRE 7238 1.818936
Spain 2485 0.624490
Netherlands 2363 0.593830
Belgium 2031 0.510398
Switzerland 1842 0.462901
Portugal 1462 0.367406
Australia 1185 0.297795
Norway 1072 0.269397
Italy 758 0.190488
Channel Islands 748 0.187975
Finland 685 0.172143
Cyprus 614 0.154300
Sweden 451 0.113338
Austria 398 0.100019
Denmark 380 0.095495
Poland 330 0.082930
Japan 321 0.080668
Israel 248 0.062323
Unspecified 244 0.061318
Singapore 222 0.055789
Iceland 182 0.045737
USA 179 0.044983
Canada 151 0.037947
Greece 145 0.036439
Malta 112 0.028146
United Arab Emirates 68 0.017089
European Community 60 0.015078
RSA 58 0.014576
Lebanon 45 0.011309
Lithuania 35 0.008796
Brazil 32 0.008042
Czech Republic 25 0.006283
Bahrain 17 0.004272
Saudi Arabia 9 0.002262
##########################################
count 397925.000000
mean 11.833709
std 25.534486
min 1.000000
5% 1.000000
10% 1.000000
20% 2.000000
30% 2.000000
40% 4.000000
50% 6.000000
60% 8.000000
70% 12.000000
80% 12.000000
90% 24.000000
95% 36.000000
99% 120.000000
max 298.500000
Name: Quantity, dtype: float64
count 397925.000000
mean 2.893201
std 3.227143
min 0.000000
5% 0.420000
10% 0.550000
20% 0.850000
30% 1.250000
40% 1.650000
50% 1.950000
60% 2.100000
70% 2.950000
80% 4.150000
90% 6.350000
95% 8.500000
99% 14.950000
max 37.060000
Name: Price, dtype: float64
相應的生成的圖片以及統計圖以圖片的形式保存在左側文件中,可以手動點擊進行查看:
至此,基於華為開發者空間,實現RFM分析與CLTV預測的電商客户細分與營銷策略優化案例結束。
四、釋放資源
在運行完成後,點擊關閉實例按鈕,停止資源倒計時: