一、博客摘要

本文基于真实电商订单数据集 order2021kmeans.xlsx,使用 Pandas、Matplotlib、Pyecharts、Scikit-learn 实现数据清洗、多维度营收可视化、月度退款分析、LRFM 用户特征构建、K-Means 聚类用户分群、交互式图表画像 全套实战。适合 Python 数据分析初学者、电商运营、机器学习入门学习者,所有代码可直接复制运行,同时标注踩坑点与业务解读,落地性极强。

技术栈:Python、Pandas(数据处理)、Matplotlib(静态可视化)、Pyecharts(交互式图表)、K-Means(无监督聚类) 实现功能:缺失值 / 异常值清洗、渠道 / 月度 / 时段收益分析、月度退款趋势、LRFM 特征工程、手肘法选 K 值、用户聚类分群、饼图 / 雷达图用户画像可视化

二、环境准备与依赖安装

2.1 导入基础库 & 全局配置

解决 Matplotlib 中文乱码、忽略运行警告,是数据分析项目通用前置配置。

python

运行

# 导入数据分析、可视化基础库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
# 导入pyecharts所有图表及配置项
from pyecharts.charts import * 
from pyecharts import options as opts
# 忽略代码运行警告
import warnings
warnings.filterwarnings('ignore')  

# 全局设置:Matplotlib中文显示 + 负号正常展示
mpl.rcParams['font.sans-serif']=['SimHei'] 
mpl.rcParams['axes.unicode_minus']=False

2.2 安装第三方依赖

若未安装pyecharts等库,在 Jupyter Notebook/CMD 终端执行以下命令:

bash

运行

pip install pyecharts pandas numpy matplotlib scikit-learn openpyxl

提示:openpyxl 用于读取 Excel 文件,缺少会导致pd.read_excel报错;安装完成后重启 Jupyter 内核生效。

三、数据加载与探索性分析

3.1 读取数据 & 查看基础信息

数据集包含 10 万 + 电商订单数据,涵盖订单、用户、渠道、时间、金额、退款等核心字段。

python

运行

# 读取Excel订单数据(文件需和代码放在同一目录)
df = pd.read_excel('order2021kmeans.xlsx')
# 查看前5行数据
df.head()

# 查看数据结构、字段类型、非空数量
df.info()

# 数值型字段描述性统计(均值、最值、分位数)
df.describe()

# 统计重复行数量
print("数据重复行数:", df.duplicated().sum())

# 统计全表缺失值
print("原始数据各字段缺失值统计:")
print(df.isnull().sum())

字段说明

  1. 基础标识:订单顺序编号、订单号、用户名、商品编号
  2. 金额指标:订单金额、付款金额(核心营收字段)
  3. 渠道平台:渠道编号、平台类型(微信公众号 / APP)
  4. 时间字段:下单时间、付款时间(datetime 时间格式)
  5. 订单状态:是否退款(区分有效订单与退款订单)

3.2 数据清洗(处理异常值 + 缺失值)

原始数据存在付款金额负数(退款异常)、渠道编号缺失问题,必须清洗后再分析。

python

运行

# 1. 处理付款金额负数异常值:取绝对值
df['付款金额'] = df['付款金额'].abs()

# 2. 删除含缺失值的行(渠道编号缺失无法做渠道分析)
df.dropna(inplace=True)

# 清洗后再次校验缺失值
print("清洗后缺失值统计:")
print(df.isnull().sum())

四、多维度营收可视化分析

4.1 按渠道划分收益(柱状图 + 玫瑰饼图)

统计各渠道总营收,分析核心盈利渠道,结合静态柱状图 + 交互式玫瑰图双重展示。

4.1.1 渠道收益柱状图

python

运行

# 按渠道分组,汇总付款金额并降序排序
channel_revenue = df.groupby('渠道编号')['付款金额'].sum().sort_values(ascending=False).reset_index()

# 绘制柱状图
plt.figure(figsize=(10,8))
plt.bar(channel_revenue['渠道编号'], channel_revenue['付款金额'])
plt.xticks(rotation=45)  # X轴标签旋转,防止文字重叠
plt.title('按渠道划分的收益')
plt.xlabel('渠道编号')
plt.ylabel('收益')
plt.tight_layout()  # 自动适配布局,避免标签截断
plt.show()
4.1.2 渠道收益交互式玫瑰饼图

使用 Pyecharts 绘制南丁格尔玫瑰图,鼠标悬浮可查看具体数值。

python

运行

# 适配pyecharts数据格式:二维列表
data = [list(z) for z in zip(channel_revenue['渠道编号'], channel_revenue['付款金额'])]

# 绘制环形玫瑰饼图
pie = (
    Pie()
    .add('渠道收益', data, rosetype='radius', radius=["20%","60%"])
    .set_global_opts(title_opts=opts.TitleOpts(title='按渠道划分的收益'))
)
# Jupyter中渲染图表
pie.render_notebook()

4.2 按月份划分整体收益

付款时间提取月份,分析全年 1-12 月营收趋势。

python

运行

# 从时间字段提取月份(1-12)
df['月份'] = df['付款时间'].dt.month

# 按月份分组统计总收益
month_revenue = df.groupby('月份')['付款金额'].sum().reset_index()

# 绘制月度收益柱状图
plt.figure(figsize=(10,8))
plt.bar(month_revenue['月份'], month_revenue['付款金额'])
plt.xticks(range(1,13))  # 强制展示1-12所有月份
plt.title('按月份划分的收益')
plt.xlabel('月份')
plt.ylabel('收益')
plt.tight_layout()
plt.show()

4.3 每日小时级收益分析(时段消费规律)

筛选非退款有效订单,拆分 24 小时时段,分析用户下单高峰。

python

运行

# 筛选非退款订单(有效成交订单)
data = df.loc[df['是否退款'] == '否']

# 提取时间衍生字段:小时、日期、英文星期
data['付款小时'] = data['付款时间'].dt.hour
data['付款天数'] = data['付款时间'].dt.day
data['付款天数名称'] = data['付款时间'].dt.day_name()

# 按【星期+小时】分组,统计时段收益
hourly_sales = data.groupby(['付款天数名称','付款小时'])['付款金额'].sum().reset_index()
# 重命名字段
hourly_sales = hourly_sales.rename(columns={'付款金额': 'TotalValue'})

# 按24小时为一组拆分数据(一天24个时段)
split_dfs = []
num_groups = len(hourly_sales) // 24
for i in range(num_groups):
    start_index = i * 24
    end_index = start_index + 24
    split_df = hourly_sales.iloc[start_index:end_index]
    split_dfs.append(split_df)

# 查看第一天24小时数据
print("第一天24小时收益数据:")
print(split_dfs[0])

# 绘制多日小时收益折线图
name = hourly_sales['付款天数名称'].unique()
line = (
    Line(init_opts=opts.InitOpts(width="1000px", height="600px"))
    .add_xaxis(split_dfs[0]['付款小时'].astype(str).tolist())
    .set_global_opts(
        title_opts={"text":"每日每小时收益总额"},
        legend_opts=opts.LegendOpts(orient='vertical', pos_top='5%', pos_right='5%')
    )
)

# 循环添加每日折线
for i in range(num_groups):
    line.add_yaxis(name[i], split_dfs[i]['TotalValue'].tolist(), label_opts=opts.LabelOpts(is_show=False))

line.render_notebook()

4.4 月度退款金额趋势分析

单独提取退款订单,统计每月退款总额,监控售后风险。

python

运行

# 复用已提取的月份字段,筛选退款订单
data_refund = df.loc[df['是否退款'] == '是']

# 按月份汇总退款金额
refund = data_refund.groupby('月份')['付款金额'].sum()

# 绘制退款趋势折线图
refund.plot(kind='line',title='每个月份退款金额')
plt.show()

五、LRFM 用户特征工程(用户分群核心)

基于传统 RFM 模型扩展为LRFM,从 4 个维度量化用户消费行为,为聚类模型提供特征:

  • L:用户最大消费时间 - 最小消费时间(用户消费周期)
  • R:最近一次消费距离数据集最晚时间的天数(用户活跃度)
  • F:用户订单总数量(消费频次)
  • M:用户累计消费总金额(用户价值)

python

运行

# 1. 计算L指标:用户两次消费的时间间隔(天数)
L = (data.groupby('用户名')['付款时间'].max() - data.groupby('用户名')['付款时间'].min()).dt.days.reset_index()

# 2. 计算R指标:最近消费距离数据集最大日期的天数
data['付款时间'] = pd.to_datetime(data['付款时间'])
max_date = max(data['付款时间'])
data['diff'] = max_date - data['付款时间']
data['diff'] = data['diff'].dt.days
R = data.groupby('用户名')['diff'].min().reset_index()

# 3. 计算F指标:用户订单总数
F = data.groupby('用户名')['订单号'].count().reset_index()

# 4. 计算M指标:用户累计消费金额
M = data.groupby('用户名')['付款金额'].sum().reset_index()

# 多表合并,生成LRFM完整数据集
LRFMdata = L.merge(R).merge(F).merge(M)
# 规范列名
LRFMdata.columns = ['用户名','L','R','F','M']
# 查看特征数据
LRFMdata.head()

六、数据标准化(K-Means 前置必备)

K-Means 基于欧式距离计算,不同特征数值量级差距过大会导致模型偏倚,使用 MinMaxScaler 将数据缩放到 [0,1] 区间。

python

运行

# 备份原始数据,防止数据污染
model_data = LRFMdata.copy()

# 提取L/R/F/M 4个特征列(剔除用户名字符串列)
scale_matrix = model_data.iloc[:, 1:5]

# 导入归一化工具
from sklearn.preprocessing import MinMaxScaler
model_scaler = MinMaxScaler()
# 执行归一化转换
data_scaled = model_scaler.fit_transform(scale_matrix)

# 输出保留3位小数的归一化结果
print("归一化后特征数据:")
print(data_scaled.round(3))

七、手肘法确定 K-Means 最优聚类数

通过手肘法计算不同 K 值对应的 SSE(簇内误差平方和),曲线拐点即为最优聚类数量。

python

运行

from sklearn.cluster import KMeans

# 存储不同K值的SSE
SSE = []
# 遍历K=1~9,训练模型
for i in range(1,10):
    kmeans = KMeans(n_clusters = i, random_state = 10)
    kmeans.fit(data_scaled)
    SSE.append(kmeans.inertia_)

# 绘制手肘图
plt.figure(figsize=(8,6))
plt.plot(range(1,10), SSE, marker = 'o', color='red')
plt.title('手肘法确定最优K值')
plt.xlabel('聚类数量 K')
plt.ylabel('SSE(簇内误差平方和)')
plt.grid(True)
plt.show()

业务解读:本案例曲线拐点为 K=3,最终将用户分为 3 个群体。

八、K-Means 模型训练 & 标签合并

根据最优 K 值训练聚类模型,将聚类标签合并回原始 LRFM 数据集。

python

运行

# 设置聚类数量为3
n_clusters = 3
# 初始化并训练模型,同时预测聚类标签
model_kmeans = KMeans(n_clusters=n_clusters, random_state=10)
cluster_labels_k = model_kmeans.fit_predict(data_scaled)

# 将聚类标签绑定到原始数据
LRFMdata['Cluster_Id'] = cluster_labels_k
merge_data = LRFMdata.copy()

九、聚类结果统计与可视化(用户画像)

9.1 各用户群体指标统计

计算每个聚类的 L/R/F/M 均值、群体人数,初步分析群体特征。

python

运行

# 筛选分析字段
merged_lrfm = merge_data[['M','F','R','L','Cluster_Id']]

# 按聚类分组,计算各指标均值
mean_lrfm = merged_lrfm.groupby('Cluster_Id').mean().reset_index()
# 统计每个群体的用户数量
mean_lrfm['count'] = merged_lrfm['Cluster_Id'].value_counts().values

# 输出统计结果
print("各用户群体特征均值 & 人数统计:")
print(mean_lrfm)

9.2 聚类人数占比环形饼图

可视化 3 类用户的人数分布占比。

python

运行

# 构造饼图数据
data_lrfm = [list(z) for z in zip(mean_lrfm['Cluster_Id'], mean_lrfm['count'])]

# 绘制环形饼图
pie_lrfm = (
    Pie()
    .add('每种分类人数占比', data_lrfm, radius=["35%","50%"])
    .set_global_opts(title_opts=opts.TitleOpts(title="每种分类人数占比"))
)
pie_lrfm.render_notebook()

9.3 用户分群特征雷达图(核心画像)

使用雷达图直观对比 3 类用户在 L、R、F、M 四个维度的差异,完成最终用户分层。

python

运行

from pyecharts import options as opts
from pyecharts.charts import Radar

# 1. 定义雷达图维度
dims = ['M', 'F', 'R', 'L']

# 2. 自动计算维度最大值,设置雷达图边界
indicators = []
for dim in dims:
    max_val = mean_lrfm[dim].max() * 1.1  # 放大1.1倍,避免图形顶格
    indicators.append(opts.RadarIndicatorItem(name=dim, max_=max_val))

# 3. 提取3个聚类的特征数据
cluster_0_data = mean_lrfm[mean_lrfm['Cluster_Id'] == 0][dims].values[0].tolist()
cluster_1_data = mean_lrfm[mean_lrfm['Cluster_Id'] == 1][dims].values[0].tolist()
cluster_2_data = mean_lrfm[mean_lrfm['Cluster_Id'] == 2][dims].values[0].tolist()

# 4. 绘制多组雷达图
c = (
    Radar(init_opts=opts.InitOpts(width="800px", height="600px"))
    .add_schema(schema=indicators)
    # 第一类用户
    .add(
        "Cluster 0",
        [cluster_0_data],
        color="#FF0000",
        linestyle_opts=opts.LineStyleOpts(color="#FF0000"),
    )
    # 第二类用户
    .add(
        "Cluster 1",
        [cluster_1_data],
        color="#0000FF",
        linestyle_opts=opts.LineStyleOpts(color="#0000FF"),
    )
    # 第三类用户
    .add(
        "Cluster 2",
        [cluster_2_data],
        color="#008000",
        linestyle_opts=opts.LineStyleOpts(color="#008000"),
    )
    # 隐藏数据标签、配置标题与图例
    .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    .set_global_opts(
        title_opts=opts.TitleOpts(title="用户分群特征雷达图"),
        legend_opts=opts.LegendOpts(pos_top="10%"),
    )
)
c.render_notebook()

十、完整整合代码(一键复制运行)

将所有代码按执行顺序整合,直接复制到 Jupyter Notebook 即可运行(确保order2021kmeans.xlsx与代码同目录)。

python

运行

# ===================== 电商订单数据分析+LRFM+K-Means聚类 完整代码 =====================
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from pyecharts.charts import * 
from pyecharts import options as opts
import warnings
warnings.filterwarnings('ignore')  

# 解决Matplotlib中文乱码
mpl.rcParams['font.sans-serif']=['SimHei'] 
mpl.rcParams['axes.unicode_minus']=False

# 1. 数据加载与探索
df = pd.read_excel('order2021kmeans.xlsx')
df.head()
df.info()
df.describe()
print("重复行数:", df.duplicated().sum())
print("原始缺失值:")
print(df.isnull().sum())

# 2. 数据清洗
df['付款金额'] = df['付款金额'].abs()
df.dropna(inplace=True)
print("清洗后缺失值:")
print(df.isnull().sum())

# 3. 渠道收益分析 柱状图
channel_revenue = df.groupby('渠道编号')['付款金额'].sum().sort_values(ascending=False).reset_index()
plt.figure(figsize=(10,8))
plt.bar(channel_revenue['渠道编号'], channel_revenue['付款金额'])
plt.xticks(rotation=45)
plt.title('按渠道划分的收益')
plt.xlabel('渠道编号')
plt.ylabel('收益')
plt.tight_layout()
plt.show()

# 渠道收益 玫瑰饼图
data = [list(z) for z in zip(channel_revenue['渠道编号'], channel_revenue['付款金额'])]
pie = (Pie().add('渠道收益', data, rosetype='radius', radius=["20%","60%"]).set_global_opts(title_opts=opts.TitleOpts(title='按渠道划分的收益')))
pie.render_notebook()

# 4. 月度整体收益分析
df['月份'] = df['付款时间'].dt.month
month_revenue = df.groupby('月份')['付款金额'].sum().reset_index()
plt.figure(figsize=(10,8))
plt.bar(month_revenue['月份'], month_revenue['付款金额'])
plt.xticks(range(1,13))
plt.title('按月份划分的收益')
plt.xlabel('月份')
plt.ylabel('收益')
plt.tight_layout()
plt.show()

# 5. 小时级收益分析
data = df.loc[df['是否退款'] == '否']
data['付款小时'] = data['付款时间'].dt.hour
data['付款天数'] = data['付款时间'].dt.day
data['付款天数名称'] = data['付款时间'].dt.day_name()
hourly_sales = data.groupby(['付款天数名称','付款小时'])['付款金额'].sum().reset_index()
hourly_sales = hourly_sales.rename(columns={'付款金额': 'TotalValue'})

split_dfs = []
num_groups = len(hourly_sales) // 24
for i in range(num_groups):
    start_index = i * 24
    end_index = start_index + 24
    split_df = hourly_sales.iloc[start_index:end_index]
    split_dfs.append(split_df)
print(split_dfs[0])

name = hourly_sales['付款天数名称'].unique()
line = (Line(init_opts=opts.InitOpts(width="1000px", height="600px")).add_xaxis(split_dfs[0]['付款小时'].astype(str).tolist()).set_global_opts(title_opts={"text":"每日每小时收益总额"},legend_opts=opts.LegendOpts(orient='vertical', pos_top='5%', pos_right='5%')))
for i in range(num_groups):
    line.add_yaxis(name[i], split_dfs[i]['TotalValue'].tolist(), label_opts=opts.LabelOpts(is_show=False))
line.render_notebook()

# 6. 月度退款分析
data_refund = df.loc[df['是否退款'] == '是']
refund = data_refund.groupby('月份')['付款金额'].sum()
refund.plot(kind='line',title='每个月份退款金额')
plt.show()

# 7. 构建LRFM特征
L = (data.groupby('用户名')['付款时间'].max() - data.groupby('用户名')['付款时间'].min()).dt.days.reset_index()
data['付款时间'] = pd.to_datetime(data['付款时间'])
max_date = max(data['付款时间'])
data['diff'] = max_date - data['付款时间']
data['diff'] = data['diff'].dt.days
R = data.groupby('用户名')['diff'].min().reset_index()
F = data.groupby('用户名')['订单号'].count().reset_index()
M = data.groupby('用户名')['付款金额'].sum().reset_index()

LRFMdata = L.merge(R).merge(F).merge(M)
LRFMdata.columns = ['用户名','L','R','F','M']
LRFMdata.head()

# 8. 数据标准化
model_data = LRFMdata.copy()
scale_matrix = model_data.iloc[:, 1:5]
from sklearn.preprocessing import MinMaxScaler
model_scaler = MinMaxScaler()
data_scaled = model_scaler.fit_transform(scale_matrix)
print(data_scaled.round(3))

# 9. 手肘法选最优K值
from sklearn.cluster import KMeans
SSE = []
for i in range(1,10):
    kmeans = KMeans(n_clusters = i, random_state = 10)
    kmeans.fit(data_scaled)
    SSE.append(kmeans.inertia_)
plt.figure(figsize=(8,6))
plt.plot(range(1,10), SSE, marker = 'o', color='red')
plt.title('手肘法确定最优K值')
plt.xlabel('聚类数量 K')
plt.ylabel('SSE(簇内误差平方和)')
plt.grid(True)
plt.show()

# 10. K-Means模型训练
n_clusters = 3
model_kmeans = KMeans(n_clusters=n_clusters, random_state=10)
cluster_labels_k = model_kmeans.fit_predict(data_scaled)
LRFMdata['Cluster_Id'] = cluster_labels_k
merge_data = LRFMdata.copy()

# 11. 聚类统计分析
merged_lrfm = merge_data[['M','F','R','L','Cluster_Id']]
mean_lrfm = merged_lrfm.groupby('Cluster_Id').mean().reset_index()
mean_lrfm['count'] = merged_lrfm['Cluster_Id'].value_counts().values
print(mean_lrfm)

# 12. 聚类人数占比饼图
data_lrfm = [list(z) for z in zip(mean_lrfm['Cluster_Id'], mean_lrfm['count'])]
pie_lrfm = (Pie().add('每种分类人数占比', data_lrfm, radius=["35%","50%"]).set_global_opts(title_opts=opts.TitleOpts(title="每种分类人数占比")))
pie_lrfm.render_notebook()

# 13. 用户分群雷达图
dims = ['M', 'F', 'R', 'L']
indicators = []
for dim in dims:
    max_val = mean_lrfm[dim].max() * 1.1
    indicators.append(opts.RadarIndicatorItem(name=dim, max_=max_val))

cluster_0_data = mean_lrfm[mean_lrfm['Cluster_Id'] == 0][dims].values[0].tolist()
cluster_1_data = mean_lrfm[mean_lrfm['Cluster_Id'] == 1][dims].values[0].tolist()
cluster_2_data = mean_lrfm[mean_lrfm['Cluster_Id'] == 2][dims].values[0].tolist()

c = (
    Radar(init_opts=opts.InitOpts(width="800px", height="600px"))
    .add_schema(schema=indicators)
    .add("Cluster 0",[cluster_0_data],color="#FF0000",linestyle_opts=opts.LineStyleOpts(color="#FF0000"))
    .add("Cluster 1",[cluster_1_data],color="#0000FF",linestyle_opts=opts.LineStyleOpts(color="#0000FF"))
    .add("Cluster 2",[cluster_2_data],color="#008000",linestyle_opts=opts.LineStyleOpts(color="#008000"))
    .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    .set_global_opts(title_opts=opts.TitleOpts(title="用户分群特征雷达图"),legend_opts=opts.LegendOpts(pos_top="10%"))
)
c.render_notebook()

十一、项目总结 & 踩坑避坑指南

11.1 业务总结

  1. 数据层:完成 10 万 + 订单数据清洗,解决缺失值、负数异常值,保障数据质量;
  2. 可视化层:从渠道、月份、小时、退款 4 个维度完成营收分析,定位核心渠道、消费高峰、售后风险月份;
  3. 特征层:基于业务构建 LRFM 四维用户特征,量化用户消费行为;
  4. 模型层:使用手肘法确定最优聚类数,通过 K-Means 实现用户自动分群;
  5. 运营落地:结合统计表、饼图、雷达图完成用户画像,可针对不同群体制定差异化营销方案(高价值用户维系、沉睡用户召回、普通用户转化)。

11.2 高频踩坑点(新手必看)

  1. 中文乱码:Matplotlib 必须配置SimHei黑体,否则中文显示为方框;
  2. 时间字段报错:时间列必须为datetime格式,才能使用.dt提取月份、小时;
  3. K-Means 报错 / 结果异常必须做数据标准化,金额等大数值字段会主导聚类结果;
  4. Pyecharts 渲染问题:Jupyter 使用render_notebook(),普通.py文件使用render("xxx.html")
  5. 变量未定义:重启 Jupyter 内核后,需从上到下依次运行代码,避免变量丢失。

十二、CSDN 发布补充(标签 + 分类)

  • 博客标题:Python 电商订单数据分析实战 | 数据清洗 + 可视化 + LRFM+K-Means 用户分群(完整代码)
  • 标签:Python 数据分析、KMeans 聚类、RFM 模型、电商分析、Pandas、Pyecharts
  • 文章分类:Python、数据分析、机器学习实战

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐