写点什么

基于华为开发者空间,实现 RFM 分析与 CLTV 预测的电商客户细分与营销策略优化

  • 2025-10-27
    中国香港
  • 本文字数:8648 字

    阅读完需:约 28 分钟

基于华为开发者空间,实现RFM分析与CLTV预测的电商客户细分与营销策略优化

本案例由开发者:天津师范大学协同育人项目–翟羽佳提供

最新案例动态,请查阅 《【案例共创】基于华为开发者空间,实现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. 案例流程


说明:


  1. 配置 AI Notebook 和运行环境环境;

  2. 从 OBS 下载文件;

  3. 编辑并运行代码;

5. 资源总览

本案例预计花费 0 元。


二、开发者空间 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 osfor 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_2011df = 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"] / 7cltv_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'])
# 计算CLTVcltv = 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                objectStockCode              objectDescription            objectQuantity              float64InvoiceDate    datetime64[ns]Price                 float64Customer ID           float64Country                objectdtype: object############### Head ######################  Invoice StockCode                          Description  Quantity  \0  536365    85123A   WHITE HANGING HEART T-LIGHT HOLDER       6.0   1  536365     71053                  WHITE METAL LANTERN       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 RatioCountry United Kingdom 354345 89.048187Germany 9042 2.272287France 8343 2.096626EIRE 7238 1.818936Spain 2485 0.624490Netherlands 2363 0.593830Belgium 2031 0.510398Switzerland 1842 0.462901Portugal 1462 0.367406Australia 1185 0.297795Norway 1072 0.269397Italy 758 0.190488Channel Islands 748 0.187975Finland 685 0.172143Cyprus 614 0.154300Sweden 451 0.113338Austria 398 0.100019Denmark 380 0.095495Poland 330 0.082930Japan 321 0.080668Israel 248 0.062323Unspecified 244 0.061318Singapore 222 0.055789Iceland 182 0.045737USA 179 0.044983Canada 151 0.037947Greece 145 0.036439Malta 112 0.028146United Arab Emirates 68 0.017089European Community 60 0.015078RSA 58 0.014576Lebanon 45 0.011309Lithuania 35 0.008796Brazil 32 0.008042Czech Republic 25 0.006283Bahrain 17 0.004272Saudi Arabia 9 0.002262##########################################count 397925.000000mean 11.833709std 25.534486min 1.0000005% 1.00000010% 1.00000020% 2.00000030% 2.00000040% 4.00000050% 6.00000060% 8.00000070% 12.00000080% 12.00000090% 24.00000095% 36.00000099% 120.000000max 298.500000Name: Quantity, dtype: float64count 397925.000000mean 2.893201std 3.227143min 0.0000005% 0.42000010% 0.55000020% 0.85000030% 1.25000040% 1.65000050% 1.95000060% 2.10000070% 2.95000080% 4.15000090% 6.35000095% 8.50000099% 14.950000max 37.060000Name: Price, dtype: float64
复制代码


相应的生成的图片以及统计图以图片的形式保存在左侧文件中,可以手动点击进行查看:








至此,基于华为开发者空间,实现 RFM 分析与 CLTV 预测的电商客户细分与营销策略优化案例结束。

四、释放资源

在运行完成后,点击关闭实例按钮,停止资源倒计时:



用户头像

提供全面深入的云计算技术干货 2020-07-14 加入

生于云,长于云,让开发者成为决定性力量

评论

发布
暂无评论
基于华为开发者空间,实现RFM分析与CLTV预测的电商客户细分与营销策略优化_RFM模型_华为云开发者联盟_InfoQ写作社区