☰
Python电商数据分析系统:从订单CSV清洗到RFM分层与可视化
2026/9/27 23:03:36 网站建设 项目流程

简介:电商平台数据分析是Python课程设计中的高频选题。这套源码提供了完整可运行的实现方案,面向需要完成期末大作业或课程设计的高校学生,也适合Python数据分析入门者对照学习。系统围绕销售趋势、回购率、RFM用户分群、渠道来源等核心维度展开分析,各功能模块按独立Python文件组织,清晰展示数据清洗、统计分析到可视化的完整链路,用户可根据作业要求直接选取或组合模块。19张可视化图表以PNG形式随源码提供,配合说明文档便于理解分析逻辑;整个源码包共30个文件、约1.68MB,以zip压缩包形式分发,轻量易用。源码已本地验证可运行,评审得分98分,内容经助教老师审定,兼具完成度与可读性;目前已有197人学习下载,是课程设计参考的优质选择。

1. 电商大作业别再交“打印Excel”:这套 Python 分析系统能让你直接落地答辩

电商数据分析系统是 Python 大作业和课程设计里出现频率最高的选题,原因很简单:数据好找、逻辑直观、可视化效果好,老师一看就知道你做了事。但绝大多数人交上去的版本是 Jupyter Notebook 里堆了几十个单元格,图是 matplotlib 默认风格,也没做用户分群和 RFM 模型——这种作业能过,但拿不到高分。这套电商平台数据分析系统实现源码加文档说明,解决的就是“作业完整度”问题:它把数据预处理、订单分析、用户画像、商品销售排行、复购分析和可视化报告串成了一条完整链路,照着跑能出图,改参数能换数据集,答辩时每张图背后都有对应代码和结论。

适合的人群很明确:期末要交 Python 大作业的本科生、做课程设计的专科生、准备毕业设计但不想从零搭框架的人。你不用理解每个算法的数学推导,只要会跑 Python、能改文件路径,就能在一小时内复现整套分析流程。下面我会用拆过的类似项目的经验,把数据表结构、核心脚本逻辑、报表生成方式和最容易翻车的几个点都过一遍。

2. 先搞懂这套系统的数据链路:从 CSV 原始表到可视化看板

这套系统的核心不是某个高深算法,而是“数据怎么流动”。我拆解过的课程设计项目里,凡是代码能直接跑通、报告能自圆其说的,数据链路一定是清晰的。这套电商分析系统的链路分成四段:原始数据读取 → 数据清洗与特征工程 → 多维度统计分析 → 结果可视化与结论输出。

2.1 订单表结构:这五个字段是整个系统的地基

拿到源码后你先打开数据目录下的订单文件,常见命名是orders.csv或者sales_data.csv。不管文件名是什么,表里至少会包含下面这五个字段,这也是所有后续分析的依赖:

字段名类型作用
order_id字符串订单唯一标识,去重用
user_id字符串用户标识,做复购和用户分层
product_id字符串商品标识,做销量排行
order_amount浮点数订单金额,做销售额趋势
order_date日期下单时间,做时间序列分析

有些版本的源码会多出category(商品类目)、quantity(购买数量)、region(地区)字段,这属于加分项,后面做交叉分析会更好用。你在改数据的时候,先别急着动代码,用 Pandas 读一遍,确认这几列存在且类型正确。

import pandas as pd df = pd.read_csv('data/orders.csv', encoding='utf-8') print(df.dtypes) print(df.head())

这段代码的作用是加载数据并检查字段类型。常见问题是order_date被读成了字符串而不是datetime64类型,这会导致后面做月份聚合时排序错乱。如果发现类型不对,用pd.to_datetime()手动转换。我的习惯是读进来之后先写一行df['order_date'] = pd.to_datetime(df['order_date'])做强制转换,避免后续所有时间相关的操作踩坑。

2.2 预处理脚本:缺失值、重复订单和异常金额的清洗逻辑

数据清洗在课程设计里最容易草草了事,但恰恰是老师重点看的部分。这套源码里有一个data_clean.py或者preprocess.py模块,负责三件事:删除完全重复的订单记录、处理order_amount中的缺失值或负值、把日期格式统一。

def clean_orders(df): # 去除完全重复的记录(基于所有列判断) df = df.drop_duplicates() # 删除订单金额为空的行 df = df.dropna(subset=['order_amount']) # 过滤异常金额:金额小于等于0视为无效订单 df = df[df['order_amount'] > 0] # 重置索引,避免清洗后索引断裂 df = df.reset_index(drop=True) return df

这里有几个值得注意的设计点。drop_duplicates()默认基于所有列判断,如果同一个订单号由于系统 bug 产生了多条记录且金额相同,会被剔除;但如果金额有细微差别就删不掉,更严格的写法是subset=['order_id']按订单号去重,实际操作中建议改成后者。dropna(subset=['order_amount'])只针对金额列做空值检测,不影响其他字段缺失的行,这样避免把整行有用的信息都丢掉。过滤负值属于业务逻辑层防御,电商场景里退款会产生负金额记录,如果要做销售净额分析,这部分数据可以保留但单独标记,具体取舍取决于作业要求。

2.3 分析库选型:为什么用 Pandas 而不是 SQL 或纯 Python

很多大作业选手纠结要不要用 SQL 做查询,这套系统给了明确答案:不需要。课程设计场景下数据量级撑死几万行,Pandas 的 DataFrame 操作完全够用,而且输出直接对接可视化库,省去数据库连接这一步。纯 Python 写统计逻辑更不可取,循环遍历几万行数据太慢,而且代码量翻倍。Pandas 的groupby()、merge()、pivot_table()三个函数能覆盖电商分析百分之八十的需求。

# 按月统计销售额趋势 monthly_sales = df.groupby(df['order_date'].dt.to_period('M'))['order_amount'].sum() # 用户复购统计 user_order_count = df.groupby('user_id')['order_id'].count() # 商品销量排行 product_sales = df.groupby('product_id')['order_amount'].sum().sort_values(ascending=False)

这三行代码分别对应三个核心分析维度:时间趋势、用户行为、商品表现。dt.to_period('M')是把日期截断到月份,比手动提取year和month再拼接要简洁得多。sort_values(ascending=False)拿到的是降序排列的结果,直接取前十条就是销售排行榜。如果你拿到手的源码里没有写这三段逻辑,那说明分析部分不完整,建议你按照这个思路自己补上,这也是答辩时能讲清楚的关键。

3. 核心分析模块拆解:RFM 用户分层和商品销售排行实战

数据分析系统能不能拿高分,取决于有没有“洞察”,不只是画几张图。这套源码里的两个亮点模块是 RFM 用户价值分层和商品销售排行,它们用的是电商行业里通行的方法论,能直接产出一段有说服力的结论。

3.1 RFM 模型在 Pandas 里的标准实现:四分位打分的完整代码

RFM 是 Recency(最近一次消费间隔)、Frequency(消费频率)、Monetary(消费金额)三个维度的缩写。思路不复杂:每个用户算三个指标,然后按分位数分成高组和低组,最终组合出 8 类用户。最不值钱的是一般挽留用户,最值钱的是重要价值用户。

import pandas as pd import datetime # 计算每个用户的 RFM 指标 snapshot_date = df['order_date'].max() + datetime.timedelta(days=1) rfm = df.groupby('user_id').agg({ 'order_date': lambda x: (snapshot_date - x.max()).days, # R 'order_id': 'count', # F 'order_amount': 'sum' # M }).rename(columns={ 'order_date': 'recency', 'order_id': 'frequency', 'order_amount': 'monetary' }) # 四分位打分,数值越大表现越好 rfm['r_score'] = pd.qcut(rfm['recency'], 4, labels=[4, 3, 2, 1]) rfm['f_score'] = pd.qcut(rfm['frequency'].rank(method='first'), 4, labels=[1, 2, 3, 4]) rfm['m_score'] = pd.qcut(rfm['monetary'].rank(method='first'), 4, labels=[1, 2, 3, 4])

qcut是这个方案里的核心函数。它在做等频分箱,每个分箱里的用户数量大致一致。注意一个坑:frequency和monetary如果有大量相同的值,qcut会报错,所以先用rank(method='first')给数据加一个稳定排名垫底,确保每个值都唯一。recency的得分方向是反的,间隔天数越少得分越高,所以 labels 是 4、3、2、1 倒着排的。snapshot_date取数据最大日期加一天,这样不会出现 0 天间隔,避免边界判断模糊。

3.2 用户分层结果解读:怎样从 8 类用户里找到最重要的 20%

打分完成后需要计算综合分并归类,通常加权方式是三个维度同权重相加。高价值用户是三个维度都高于均值的组合,比如重要价值用户(R 高 F 高 M 高),重要发展用户(R 高 F 低 M 高)。在答辩里,你只需要强调一个数字:前 20% 的用户贡献了多少销售额。

# 计算综合分 rfm['total_score'] = rfm['r_score'].astype(int) + rfm['f_score'].astype(int) + rfm['m_score'].astype(int) # 定义用户标签 def rfm_label(row): if row['total_score'] >= 9: return '重要价值用户' elif row['total_score'] >= 6: return '重要发展用户' elif row['total_score'] >= 4: return '一般保持用户' else: return '一般挽留用户' rfm['user_label'] = rfm.apply(rfm_label, axis=1) # 统计各类用户占比和贡献 label_stats = rfm.groupby('user_label').agg( user_count=('user_id', 'count'), total_amount=('monetary', 'sum') ) label_stats['amount_ratio'] = label_stats['total_amount'] / label_stats['total_amount'].sum() * 100

这段的核心决策在于total_score的阈值划分。阈值没有行业统一标准,完全依赖四分位计算的分值分布,你可以在答辩时说明这是相对分层而非绝对分层。apply配合自定义函数能处理多条件判断,比np.where嵌套可读性高很多。最后算出的amount_ratio就是那个“20% 用户贡献 70% 销售额”的核心证据,建议你在文档里把这句话写进分析结论。

3.3 商品维度分析:Top N 排行和类目占比的组合拳

只有销售金额排行还不够,还需要加一个类目占比分析,让结论更立体。源码里的analyze_products.py或者类似脚本会完成这两步,输出结果直接用于绘图。

# Top 10 畅销商品 top10 = df.groupby('product_id')['order_amount'].sum().nlargest(10).reset_index() top10.columns = ['product_id', 'sales_amount'] # 类目销售占比(如果数据包含category字段) if 'category' in df.columns: category_summary = df.groupby('category')['order_amount'].sum().sort_values(ascending=False) category_ratio = category_summary / category_summary.sum() * 100

nlargest(10)比sort_values().head(10)更直接,性能也更好。类目占比如果原始数据没有category字段,这段代码会自动跳过,算是一个兼容性设计。我建议你在文档里给category_ratio画一个饼图,它能直接回答“这个平台靠什么类目赚钱”的问题,老师看到这句话就知道你的分析是有业务逻辑的。

4. 可视化与报告输出:用 Pyecharts 生成交互式 HTML 还是用 Matplotlib 静态图

分析做完了,最后一步是出图。这时候课设选手最常见的纠结是选 Pyecharts 还是 Matplotlib。建议你在动手前先把定位想清楚:如果答辩现场是投屏展示,Pyecharts 的交互式图表能让你手动悬停看数值,观感好;如果最终提交物是 Word 文档和 PDF 报告,Matplotlib 的静态图更稳,不依赖 HTML 环境。

4.1 一组图表对应一组业务结论:六个必出的分析图

这套源码里至少包含六种图表,对应六段分析结论。我在拆类似项目的时候习惯做一张对照表,答辩时照着讲非常顺:

图表分析结论核心代码函数
月度销售额折线图销售额波动趋势与峰值节点plt.plot()
类目占比饼图核心收入来源结构plt.pie()
用户 RFM 分层柱状图各价值层级用户数量分布plt.bar()
商品销量 Top10 条形图畅销商品集中度plt.barh()
复购用户占比环形图用户粘性与忠诚度评估plt.pie()+wedgeprops
时间段下单量柱状图用户活跃时段分布plt.bar()

我一般会在写绘图代码前把结论先写出来,再反向选图。比如“哪个时段用户最爱下单”这件事,条形图比饼图传递信息更准,人眼对长度比对角度敏感。这套源码的默认设置里时间维度是按月分析的,如果你拿到的是日度数据,改成按小时分析会有意外发现,电商平台凌晨下单占比高是常态,写进结论里会显得你做过额外探索。

4.2 Matplotlib 中文字体显示乱码:一个必须提前处理的坑

用 Matplotlib 在 Windows 上画图,最恼人的问题就是中文显示成方块。源码文档里通常会提示你加字体设置,但很多人没注意就跳过了。上来直接画的后果就是图里全是小方块,答辩时无比尴尬。解决办法是显式指定中文字体,同时把负号的显示设置也一起修掉。

import matplotlib.pyplot as plt # 指定中文字体,Windows 常见为 SimHei,macOS 为 Arial Unicode MS plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False

axes.unicode_minus这个参数是用来修复坐标轴负号显示成方块的问题的,很多人漏了这一步。如果你用的是 Jupyter,还可以用%matplotlib inline让图直接嵌入页面。如果你把系统换成了 macOS,字体名需要改成Arial Unicode MS,否则同样乱码。这一步做完再跑绘图脚本,中文就正常了,属于“一劳永逸”的操作。

4.3 将图表和结论拼接成报告:文档结构决定答辩观感

好的课程设计文档需要遵循一个逻辑顺序:背景与目标 → 数据说明与预处理 → 分析方法 → 可视化结果 → 结论建议。这套源码配套的文档说明里已经给出了一个可复用的框架,你需要做的是把生成的图片插入对应位置,并给每一张图配一段两三行的解读。

文档中的分析结论不要只写“月销售额为 100 万元”,要写“月销售额呈现 3 月峰值、11 月低谷的规律,推测受大促活动和季节性影响”。前者是数据陈述,后者是商业洞察。答辩时老师不关心你的代码有多复杂,他关心的是你能不能用数据解释业务现象。文档里如果有“建议”部分,尽量提两三条可执行的动作,比如“针对重要价值用户发放专属优惠券”,这就比空泛的“提高用户活跃度”有说服力。

5. 避坑实战记录:数据缺失、编码报错与可视化翻车的典型修复过程

课程设计跑代码不会一帆风顺。这类电商数据分析项目的高频问题集中在数据读取、类型转换、绘图显示三个环节。我把拆项目过程中遇到的最常见的问题和修复方法整理成几条,每个都是现象、原因、解决三步对应,可以直接对照手头的报错信息操作。

5.1 文件读取直接报 FileNotFoundError

现象:运行pd.read_csv()时报错,提示文件路径不存在,但文件明明就在项目目录里。
原因:终端的工作目录和项目根目录不一致。很多人用 VSCode 打开单个 py 文件运行,但终端当前目录还在用户主目录下,相对路径自然找不到文件。
解决:使用绝对路径读取,或者把工作目录切换到项目根目录,代码如下:

import os os.chdir(os.path.dirname(os.path.abspath(__file__)))

os.chdir把工作目录切到当前脚本所在目录,之后所有相对路径都基于项目根目录生效。这是最省事的方法,比每次手动拼绝对路径可靠得多。

5.2 CSV 文件编码导致中文乱码

现象:数据读进来了,但中文列名或者中文字段显示成乱码。
原因:CSV 文件保存时可能是 GBK 编码,而 Pandas 默认用 UTF-8 读取。
解决:显式指定编码读取。UTF-8 读不了就改用 GBK,同时可以加参数engine='python'兜底。

df = pd.read_csv('data/orders.csv', encoding='gbk', engine='python')

如果你的数据文件是别人给的,多半是 GBK。如果文件是 Mac 或者 Linux 上传的,多半是 UTF-8。我习惯的做法是先写一个探测代码,用chardet判断真实编码,但课程设计没有那么多时间,直接encoding='utf-8'试跑,报错就换gbk,两分钟能解决。

5.3 qcut 报 BinsError: Bin edges must be unique

现象:运行 RFM 打分代码时报ValueError: Bin edges must be unique。
原因:frequency和monetary字段中大量用户的值相同,等频分箱时边界无法划分,比如一百个用户里六十个都只买了一单。
解决:先对列做rank(method='first')再传入qcut,或者改用自定义阈值分箱。

rfm['f_score'] = pd.qcut(rfm['frequency'].rank(method='first'), 4, labels=[1, 2, 3, 4])

rank(method='first')给相同值分配不同的排名序号,保证每个值唯一,分箱边界就不会重复。这个坑极其隐蔽,报错信息也不是很直观,但修复成本很低,代码无非多写一层函数调用。

5.4 Matplotlib 绘制的图在上交的文档里丢失

现象:本地 Jupyter 里图正常显示,但把 Notebook 导出成 Word 或 PDF 后图片无法显示。
原因:Notebook 内嵌图是 base64 编码存在 ipynb 文件里,导出时依赖解释器重新执行,部分导出器直接丢弃图片。
解决:把每张图显式保存成 PNG 再插入文档,保存时设置dpi让图片更清晰。

plt.savefig('output/monthly_sales.png', dpi=150, bbox_inches='tight')

bbox_inches='tight'会让保存的图片自动裁剪空白边缘,答辩页面看起来更紧凑。我一般把图片统一保存到output目录,文件名和图表英文名对应,插入文档时直接引用,不会出幺蛾子。

5.5 Pyecharts 生成了 HTML 但浏览器打开是空白页

现象:Pyecharts 生成的.html文件双击打开,页面空白,控制台报错找不到echarts.min.js。
原因:Pyecharts 默认从 CDN 引用了 ECharts 的 JS 文件,而当前电脑没有外网访问能力。
解决:使用本地资源模式,在初始化图表时指定renderer和Environment配置,或者直接把源码里的 JS 文件下载到本地项目目录并引入。

from pyecharts.globals import CurrentConfig, OnlineHost CurrentConfig.ONLINE_HOST = './js/'

把echarts.min.js放在项目js目录下即可。这条相当重要,答辩教室的网络环境基本不可控,提前改成本地引用是最稳妥的。

6. 把静态分析升级成动态看板:基于 Pyecharts 的简单交互探索

前面第五步做的 Matplotlib 静态图够交作业,但如果你想在答辩时有一个能现场演示的操作环节,建议花半小时把核心图表换成 Pyecharts 的交互版本。这里有一个很实用的技巧:把 Pyecharts 渲染的 HTML 文件嵌入一个简易的本地展示页面,双击就能打开,不依赖 Jupyter。

Pyecharts 的调用方式和 Matplotlib 不太一样,它是链式调用,先创建图表对象,再通过add()方法添加数据,最后用render()输出 HTML。下面的代码生成一个按月销售的交互式折线图,鼠标悬停能看到每个月的具体金额:

from pyecharts.charts import Line from pyecharts import options as opts monthly_data = df.groupby(df['order_date'].dt.to_period('M'))['order_amount'].sum() months = [str(m) for m in monthly_data.index] amounts = [round(v, 2) for v in monthly_data.values] line = ( Line() .add_xaxis(months) .add_yaxis( '月销售额', amounts, is_smooth=True, label_opts=opts.LabelOpts(is_show=False) ) .set_global_opts( title_opts=opts.TitleOpts(title='月度销售额趋势'), tooltip_opts=opts.TooltipOpts(trigger='axis') ) ) line.render('output/monthly_sales_chart.html')

is_smooth=True是让曲线变得圆滑,去掉锯齿感的参数,这在展示趋势时观感更好。label_opts=opts.LabelOpts(is_show=False)是关闭数据标签,防止点太多的时候数字挤成一团。tooltip_opts=opts.TooltipOpts(trigger='axis')设置悬浮提示,鼠标在图表上移动时,同一横坐标的所有系列值都会显示,这是交互体验的重要一环。

如果你想把多个图放在同一个页面展示,可以使用Grid组件并行布局,或者用Tab组件做成多标签切换,这样相当于做了一个迷你版的分析看板。这套源码里如果已经包含了dashboard.py这类脚本,说明作者已经帮你想好了展示方式,你只需要替换数据文件路径后运行即可。如果源码里没有,按上面这段代码思路补一个,效果会立刻超出预期。

代码跑通之后,建议你验证两个核心结论的输出路径:一是确认output目录下生成了预期数量的图片和 HTML 文件,二是打开控制台确认没有报错和警告。如果出现 DataFrame 的SettingWithCopyWarning,这说明你在切片后做了修改操作,虽然不影响结果,但答辩时被问到会露怯。提前复制一份df.copy()再处理,能彻底消除这类警告。

我在最近一次帮学生调试这个项目的过程中,就遇到过把客户数据 CSV 从 Excel 另存后,日期格式变成了2024/1/5而代码默认写的是2024-01-05,结果所有月份聚合全乱了。从那以后,我每次拿到新数据都会先执行一次字段类型探查,确认order_date的格式和值域范围,再决定要不要加解析参数parse_dates。这个大检查流程节省的调试时间远超多写的十行代码。希望这些拆解和踩坑记录能帮你在两周内把这份资源吃透,交出一份站得住脚的课设作业。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询