简介面向Python课程设计与期末大作业的电商平台数据分析系统完整资源适合需要可直接运行项目作为参考的高校学生。资源围绕电商业务数据设计实现了用户行为分析、RFM用户分层、回购率统计、销售趋势分析、渠道来源拆解等常见模块覆盖数据分析课程中的典型实验场景同时附带脏数据处理方式说明和README文档便于理解数据清洗、特征计算与可视化输出的完整流程。压缩包共30个文件以7个Python源码脚本为主体实现数据清洗、特征分析与图表绘制辅以19张结果展示图与3个缓存文件整体仅1.68MB轻量易部署源码经本地编译通过评审分98分助教审定难度适中可直接用于期末大作业、课程设计或毕业设计参考。目前已有197人学习浏览作为高分项目范例能帮助读者快速搭建电商数据分析框架并借鉴实现思路。1. 为什么电商数据分析是大作业里的“安全牌”这个题到底在考你什么Python 大作业电商平台数据分析系统实现源码文档说明高分项目这类题目几乎每个开 Python 课的学校都会出现一版。它不是让你做一个能下单的商城也不是让你训练一个预测模型而是要把一整条数据处理链路走通从拿到或构造订单数据到清洗、聚合、算指标再到画图、写结论、打包成一份能答辩的文档。评分老师看的就是“你是不是真的会分析而不是会抄代码”。这个方向适合两类人一类是课程要求必须做“信息系统类”大作业想找一个数据量可控、工作量肉眼可见的题目另一类是求职作品集里缺一个数据展示项目想用半天到两天时间补上一个完整案例。它不依赖 GPU、不依赖真实业务接口一台普通笔记本就能跑完。前面把技术栈和目录结构定好后面就是照方抓药的事。2. 技术选型与工程结构先摆平“用什么”和“怎么放”再谈写代码2.1 技术栈决策纯 Python 脚本还是带 Web 壳先回答一个最常见的问题这个系统到底要不要做成网页很多高分模板会给你一个 Flask 页面打开能看到图表和数据表格但这不代表你必须这么做。我见过两种做法各有各的道理方案组成适合情况答辩风险纯脚本版pandas 清洗 matplotlib 出图 控制台输出结论课程只要求“分析报告 图表”功能偏少容易被问“系统在哪里”带 Web 壳版脚本版基础 Flask 渲染页面 ECharts 图表课程要求“系统”或展示给非技术 audience工作量多一天但效果显著我的建议是如果老师明确说了“系统”两个字就做带 Web 壳的版本。这里的“系统”在答辩语境下就等于“有界面、能交互”。但如果时间只够一天脚本版也能过只要文档里写清楚“数据入库—清洗—分析—可视化”四层结构把脚本输出截图放进文档观感并不差。下文默认按脚本版为主、最后补 Web 壳的方案讲这样两头都能落。技术栈选型上没有悬念pandas 做数据清洗和聚合matplotlib 做静态图表Flask 只用来把结果展示成网页。不用 Django因为只暴露几个路由Django 的 admin、ORM、迁移机制在这里全是负资产。数据库用 SQLite 还是直接 CSV如果你没学过 SQL直接用 CSV pandas.read_csv 就行减少一个变量如果你会用 pandas 的 merge、groupby数据量在几万行以内时 CSV 完全不输数据库。2.2 目录设计与文档联动源码和文档说明怎么配套很多人的项目只有一个 main.py跑完输出几张 png这在小作业里可以但在“系统 文档说明”的评分结构下很吃亏。我一般会把工程拆成这样你直接照着建ecommerce_analysis/ ├── data/ │ ├── raw_orders.csv # 原始订单数据不手动改 │ └── clean_orders.csv # 清洗后数据分析只用这份 ├── scripts/ │ ├── generate_data.py # 造数脚本保证可复现 │ ├── clean_data.py # 清洗脚本 │ ├── analysis.py # 核心指标计算 │ └── visualize.py # 生成图表 ├── output/ │ ├── daily_sales.png │ ├── top10_products.png │ ├── rfm_heatmap.png │ └── metrics_summary.json # 指标汇总Web 版直接用 ├── web_app/ │ └── app.py # Flask 入口可选 ├── docs/ │ └── 说明文档.md └── requirements.txt每个文件只干一件事是这套结构能避免答辩翻车的核心。比如 generate_data.py 只负责产出 raw_orders.csvclean_data.py 只读 raw绝不回头改源文件analysis.py 输出 JSON 而不是直接 print 一眼就过。这样文档里写“各模块职责”时你就有话可说而不是笼统的一句“主程序完成所有功能”。requirements.txt 也必须有这是文档能复现的前提pandas2.1.4 matplotlib3.8.2 flask3.0.0 openpyxl3.1.22.3 环境准备与本机跑通最小命令别用系统全局 Python大作业最大的隐性扣分项就是“换个环境跑不起来”。用虚拟环境隔离也能在文档里写上“virtualenv 创建独立运行环境”这一句加分话。cd ecommerce_analysis python -m venv venv # Windows: venv\Scripts\activate # macOS / Linux: source venv/bin/activate pip install -r requirements.txt说明python -m venv venv 创建虚拟环境到 venv 目录激活后 pip 装的包只对当前项目生效。装依赖用 -r 从 requirements.txt 读取避免手工逐个装漏掉。如果你用的是 PyCharm创建项目时可以直接选 Virtualenv效果一样。到这一步环境能跑通后面的流程就都是确定性的了。3. 数据准备与清洗没有干净数据后面全是废图3.1 造一份可复现的模拟订单数据随机种子决定你报告里的“真实性”电商平台的真实订单数据拿不到也绝不能拿爬虫去搞。最常见、最可靠的做法是自己造一份带业务含义的模拟数据。造数不是随便 random要让分布大致合理晚上和周末订单多、爆品销量高但单价低、数码类客单价明显高于零食类。这样你分析出来的结论才像话。import random import pandas as pd from datetime import datetime, timedelta random.seed(42) # 商品池不同品类给不同价格区间 products [ {name: 无线鼠标, category: 数码配件, min_price: 49, max_price: 89}, {name: 机械键盘, category: 数码配件, min_price: 199, max_price: 499}, {name: 手机支架, category: 数码配件, min_price: 9, max_price: 29}, {name: 保温杯, category: 家居日用, min_price: 39, max_price: 129}, {name: 收纳箱, category: 家居日用, min_price: 25, max_price: 79}, {name: 零食礼包, category: 食品, min_price: 29, max_price: 99}, ] # 时间范围近 90 天 start_date datetime(2024, 1, 1) end_date datetime(2024, 3, 31) rows [] for order_id in range(1, 3001): # 周末和晚上下单概率更高 day_offset random.randint(0, (end_date - start_date).days) order_time start_date timedelta(daysday_offset, hoursrandom.randint(10, 22), minutesrandom.randint(0, 59)) if order_time.weekday() 5: weight 2 # 周末订单翻倍 else: weight 1 if 19 order_time.hour 22: weight 1 # 晚间再加权 for _ in range(random.randint(1, 3)): # 一单可能含多件商品 product random.choice(products) qty random.randint(1, 3) if weight 1 else random.randint(1, 2) price round(random.uniform(product[min_price], product[max_price]), 2) rows.append({ order_id: order_id, user_id: random.randint(1000, 1500), product_name: product[name], category: product[category], quantity: qty, price: price, amount: round(price * qty, 2), order_time: order_time.strftime(%Y-%m-%d %H:%M:%S), }) df pd.DataFrame(rows) df.to_csv(data/raw_orders.csv, indexFalse, encodingutf-8-sig) print(f生成 {len(df)} 条订单明细)逻辑说明random.seed(42) 固定随机种子保证每次运行生成完全相同的数据。你文档里写的所有数值都来自这份确定性的数据否则两次运行结果不同答辩时老师让你重跑一遍就对不上。weight 变量模拟业务权重周末权重为 2、晚间额外加 1但注意它只影响购买件数概率不是直接给金额乘系数——这只是为了让数据分布更像真实订单不必做成精确的概率模型。参数说明订单数 3000用户数 5011000-1500时间范围 90 天。这三个参数决定你后续图表的密度3000 条明细画日趋势足够饱满501 个用户做分层也够。如果你的报告需要月度对比就把日期范围改成 6 个月并把订单数加到 6000 以上。生成 CSV 时用 encodingutf-8-sig这是给 Excel 用的编码Excel 直接打开不会乱码——很多教程只写 utf-8Windows 上 Excel 打开就是一堆乱码这一步值得记住。3.2 清洗三步去重、补空、拒掉异常订单造出来的数据也要走一遍真实清洗流程这是文档里“数据预处理”章节的素材。清洗本身不在于数据有多脏而在于你展示了“我知道这些坑存在并做了处理”。import pandas as pd df pd.read_csv(data/raw_orders.csv) # 1. 去重同一订单号加同一商品名才算重复 df.drop_duplicates(subset[order_id, product_name], inplaceTrue) # 2. 缺失值金额为空或用户为空的行直接剔除 df.dropna(subset[amount, user_id], inplaceTrue) # 3. 异常值数量0、金额0、单价9999 都视为脏数据 df df[(df[quantity] 0) (df[amount] 0) (df[price] 9999)] # 4. 时间转 datetime方便后续按天/月聚合 df[order_time] pd.to_datetime(df[order_time]) df[order_date] df[order_time].dt.date df.to_csv(data/clean_orders.csv, indexFalse, encodingutf-8-sig) print(f清洗前 {len(df)} 行清洗后保留 {len(df)} 行)逻辑说明drop_duplicates 的 subset 参数限定判断重复的列不要全列去重——同一个订单含两条不同商品是正常业务全列去重会误删。dropna 只针对关键字段因为商品名缺失可能不影响金额汇总而 user_id 缺失会导致后续 RFM 分析无法做用户分组。异常值过滤用布尔条件组合这里不用 replace直接剔除是更干净的做法。参数说明price 9999 是防呆阈值你可以按业务调整为 100000关键是它必须比商品池里的最高单价大一个量级。清洗完的行数建议和原始行数对比在文档里写“共剔除 N 行无效数据”这就是数据质量的量化证明。上面这段代码只是标准流程如果你自己模拟数据时没生成缺失值可以在 generate_data.py 里留 5% 的空金额字段——故意制造脏数据再清洗报告反而更有说服力。3.3 Excel 落盘与对账拿 Excel 透视表当裁判清洗后的数据除了存 CSV我会再导出一份 Excel目的是给文档附件用也方便老师自己打开筛选。这不是冗余而是让审核者能亲手核对你算的每个数。import pandas as pd df pd.read_csv(data/clean_orders.csv) # 按天汇总销售额写入 Excel 的 sheet1 daily df.groupby(order_date)[amount].sum().reset_index() monthly df.groupby(df[order_time].dt.month)[amount].sum().reset_index() with pd.ExcelWriter(output/agg_tables.xlsx, engineopenpyxl) as writer: daily.to_excel(writer, sheet_name日销售额, indexFalse) monthly.to_excel(writer, sheet_name月销售额, indexFalse)代码说明groupby 聚合后要 reset_index如果不重置order_date 会变成索引列to_excel 写出来会带一层奇怪的行名。pd.ExcelWriter 配合 with 语句能确保文件写完后关闭句柄不然在 Windows 上文件可能被占用第二次运行报 PermissionError。参数说明engineopenpyxl 是写 xlsx 必需的后端xls 老格式是 xlwt别混用。这个 Excel 文件生成后你可以在 Excel 里插入透视表拉一个“日销售额”和程序算出来的数对一遍——对上了说明 groupby 逻辑没问题对不上优先检查 order_date 是否真的转了 datetime 类型。这一步对账花五分钟能避免“图表数据和描述文字对不上”这种最尴尬的答辩事故。4. 分析指标与可视化从平均值到 RFM 的完整链路4.1 时间趋势分析先 resample 再画线别直接 plot 原始数据做完清洗第一个必做的分析是时间趋势。我见过很多人把 3000 行订单直接按天 groupby 后画线画出来锯齿状极其难看。正确做法是按天聚合后再做时间序列重采样把“天数”这个单位统一。import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(data/clean_orders.csv) df[order_time] pd.to_datetime(df[order_time]) df.set_index(order_time, inplaceTrue) # 按天求和再取 7 日均线平滑 daily df[amount].resample(D).sum() weekly daily.rolling(window7, min_periods1).mean() plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei] plt.rcParams[axes.unicode_minus] False fig, ax plt.subplots(figsize(12, 5)) ax.plot(daily.index, daily.values, label日销售额, color#888, linewidth0.8) ax.plot(weekly.index, weekly.values, label7日均线, color#E63946, linewidth2) ax.set_title(近90天销售额趋势) ax.legend() plt.tight_layout() plt.savefig(output/daily_sales.png, dpi150)逻辑说明resample(D) 是把索引为时间的数据重采样到天和单纯的 groupby 日期不同它会把没有订单的日期也补成 0画出来是一条连续的时间轴不会有断点。rolling(window7) 取 7 天滑动平均把周内波动抹平趋势线才看得出整体方向——这是报告里“销售额整体呈上升趋势”这句话的唯一依据。参数说明figsize(12, 5) 长宽比适合在文档里插入不会过高占版dpi150 是打印清晰度的底线低于 100 放到答辩 PPT 里会明显发虚。字体设置里 SimHei 是黑体Microsoft YaHei 是微软雅黑前者在 Linux 上通常没有所以列两个备选系统按顺序找。4.2 Top10 商品与二八法则用条形图把差异拉出来趋势图证明“总量”接下来必须展示“结构”。Top10 商品贡献了多少销售额在电商报告里几乎必提。这一步能引出二八法则的分析结论让你的报告从“罗列图表”升级到“有观点”。import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(data/clean_orders.csv) top10 (df.groupby(product_name)[amount] .sum() .sort_values(ascendingFalse) .head(10)) total_sales df[amount].sum() top10_share top10.sum() / total_sales * 100 fig, ax plt.subplots(figsize(10, 6)) ax.barh(top10.index[::-1], top10.values[::-1], color#2A9D8F) ax.set_xlabel(销售额元) ax.set_title(fTop10 商品销售额贡献占比 {top10_share:.1f}%) plt.tight_layout() plt.savefig(output/top10_products.png, dpi150) print(top10)逻辑说明sort_values(ascendingFalse) 按销售额降序排head(10) 截前 10。barh 是横向条形图类别名称长时横向更易读。这里用 top10.index[::-1] 反转顺序让最大值在顶部如果不反转matplotlib 默认从底部往上排最大项反而不在最显眼的位置。参数说明top10_share 是 Top10 销售额占总销售额的百分比这个数通常是报告里最有冲击力的一个数字。例如算出来可能是 45% 左右你就可以在文档里写“Top10 商品贡献了约 45% 的营收头部商品集中度明显”——有数据有判断这就是高分项目和普通作业的差别。4.3 RFM 用户分层找出“高价值沉默用户”用户分层是电商数据分析系统的标配内容也是拉开档次的模块。RFM 三个字母分别代表最近一次消费时间、消费频率、消费金额。实现不复杂但必须讲清理由你为什么要分层因为运营资源有限得优先服务值得服务的用户。import pandas as pd df pd.read_csv(data/clean_orders.csv) ref_date df[order_time].max() pd.Timedelta(days1) # 按用户聚合 RFM 三指标 rfm df.groupby(user_id).agg( recency(order_time, lambda x: (ref_date - x.max()).days), frequency(order_id, count), monetary(amount, sum) ) # 四分位数分档数值高于中位数的记为 1否则 0 def score(series): return (series series.median()).astype(int) rfm[R], rfm[F], rfm[M] score(rfm[recency]), score(rfm[frequency]), score(rfm[monetary]) # 分层规则8 类用户合并成 4 类主型 def rfm_label(row): if row[R] 1 and row[F] 1 and row[M] 1: return 重要价值用户 if row[M] 1: return 高消费潜力用户 if row[R] 1: return 活跃普通用户 return 沉默风险用户 rfm[label] rfm.apply(rfm_label, axis1) rfm.to_csv(output/rfm_result.csv, encodingutf-8-sig) # 看一眼分层结果 print(rfm[label].value_counts())逻辑说明recency 用 ref_date 减去每个用户最近一次下单日期得到“距今多少天没消费”frequency 用 order_id 出现次数统计注意 agg 里第一个元组 (order_time, lambda ...) 表示对 order_time 列应用 lambda(order_id, count) 表示对 order_id 计数——字段映射别写反。四分位数分档是 RFM 最常见实现数值大于全体中位数为 1否则为 0。阈值用中位数而不是平均值因为消费金额分布通常右偏平均值会被大额用户拉高中位数更稳。参数说明ref_date 取数据最大时间 1 天确保“最近消费”是相对完整日期区间计算的。分层规则这里只写了 4 类完整 RFM 是 2³8 类但我建议报告里合并成 4 类因为 8 类会分散用户数答辩时解释成本高。你可以把 rfm_result.csv 导入 Excel 筛选某个县体用户 ID并去明细表里验证这个用户的真实消费记录——能验证说明分层不是黑匣子。4.4 热力图与图表保存可视化配置统一入口图表风格统一是“高分项目”的外观底线。如果每张图颜色、字体、尺寸都不一样老师扫一眼就觉得是拼凑的。我会把可视化配置抽到一个公共函数然后热力图用 seaborn 风格画出来展示 RFM 分布。import pandas as pd import matplotlib.pyplot as plt # 统一图表风格 plt.rcParams[figure.figsize] (10, 6) plt.rcParams[axes.grid] True plt.rcParams[grid.linestyle] -- plt.rcParams[grid.alpha] 0.4 plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei] plt.rcParams[axes.unicode_minus] False rfm pd.read_csv(output/rfm_result.csv) # 画 R、F、M 三个分档的平均值雷达式对比 summary rfm.groupby(label)[[recency, frequency, monetary]].mean() # 对数值归一化到 0-1避免金额数值过大压扁其他轴 summary_norm (summary - summary.min()) / (summary.max() - summary.min()) fig, ax plt.subplots(figsize(8, 6)) im ax.imshow(summary_norm.T, cmapYlOrRd, aspectauto) ax.set_xticks(range(len(summary_norm.index))) ax.set_xticklabels(summary_norm.index, rotation30) ax.set_yticks(range(3)) ax.set_yticklabels([最近消费, 消费频率, 消费金额]) plt.colorbar(im, axax, label归一化均值) plt.tight_layout() plt.savefig(output/rfm_heatmap.png, dpi150)逻辑说明imshow 把数值矩阵渲染为热力图cmapYlOrRd 从黄到红渐变数值越大颜色越深。summary_norm.T 做转置让每一列是一个用户类型、每一行是一个指标这样竖向看某个用户类型的三项指标强弱更直观。归一化到 0-1 是必要的否则 monetary 均值几千recency 均值几十两者没法在同一张图上比较颜色深浅。参数说明aspectauto 让单元格自动铺满画布不加这个参数热力图会被拉成正方形导致变形。rotation30 让用户类型的标签斜着排避免文字相互遮挡。这一张热力图配合上一节的柱状图、趋势图整套图表组合已经覆盖“时间、结构、人群”三个维度文档里每个分析结论都能落到图上。5. 避坑会毁掉分数的 5 个常见问题5.1 中文乱码与方块字编码问题现场现象matplotlib 画出的图里所有中文标题变成方框CSV 用 Excel 打开后中文全是乱码或者读 CSV 直接报 UnicodeDecodeError。原因三个环节各有差异。matplotlib 默认字体不支持中文pandas to_csv 默认 utf-8而 Excel 默认 GBK 打开pandas read_csv 默认按系统编码读取Windows 下可能是 GBK。解决matplotlib 在 pyplot 画图前设置 plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei] 和 plt.rcParams[axes.unicode_minus] FalseCSV 写入统一 encodingutf-8-sig读取时如果报错显式指定 pd.read_csv(path, encodingutf-8)还是报错就试试 encodinggbk。这个坑最值得提前规避因为乱码图一旦生成只能重跑没有后悔药。5.2 日期轴变成密集黑线没做重采样现象画日销售额趋势时横轴密密麻麻挤成一团线条杂乱看不出规律。原因直接把每行的订单时间作为横轴绘图没有先 resample 到天导致同一日期出现多条记录或者日期格式不统一。另一个原因是日期索引没有排序matplotlib 按出现顺序画线线就来回折。解决先 df[order_time] pd.to_datetime(...)然后 set_index(order_time)再 resample(D).sum()。resample 会自动按时间排序并补齐空日期。如果只想显示 1 月到 3 月可以先用 df.loc[2024-01-01:2024-03-31] 切片再聚合。5.3 图糊了或被截断dpi 和 tight_layout 同时生效现象保存的 png 放到文档里模糊或图例、标题被截掉一半。原因dpi 低于 100图在文档里被拉伸后像素不够figsize 设置过大、内容超出画布边界。解决保存时统一 dpi150画布 figsize 控制在 (10, 6) 到 (12, 6) 之间。打印前调 plt.tight_layout()它会自动收缩留白避免标题被子图遮挡。生成后先本地打开看一眼别直接插进文档——图被截断这一项几乎每个班都有几个人中招。5.4 造数“太假”分布不合理被老师当场问住现象答辩时老师说“你这数据怎么每天销售额都一样高”或者“凌晨 3 点还在疯狂下单”原因random.randint 均匀生成时间没有模拟真实人群作息商品价格区间太窄导致销量和金额高度线性相关。解决generate_data.py 里对时间加权——晚上和周末提高下单概率工作日上午 10 点到下午 4 点保持常规凌晨直接降低到接近零。价格区间要拉开差距数码配件定价几十到几百食品就几块到几十。还可以再往数据里加 3% 的退款记录amount 为负清洗时剔除这样报告里就能写“剔除了 N 条退款异常数据”真实性明显提升。5.5 文档和代码对不上换个电脑跑不出来现象代码在你自己电脑上运行正常拷到老师机器上 ImportError 或者路径报错。原因依赖没锁版本用绝对路径读文件中文文件名在 macOS 和 Windows 编码不一致。解决所有文件路径用相对路径比如 data/clean_orders.csv不要写 C:/Users/xxx/Project/...。requirements.txt 锁住 pandas、matplotlib、flask 的版本号。跑之前确认当前工作目录在项目根目录而不是在子目录里执行脚本。最后用 Python 的 ifname main: 包住所有执行代码防止被 import 时意外跑一遍。这三件事做齐换环境基本不会再翻车。6. 进阶技巧把静态图升级成数据看板再用一张表自证没算错如果还想往上够一够可以把 matplotlib 的 png 换成网页看板工作量不大但观感提升明显。Flask 里写一个路由读取 analysis.py 输出的 metrics_summary.json把日销售额、Top10、RFM 分布渲染成 ECharts 图表。关键在于Flask 只做数据中转不做计算所有指标都在 analysis.py 里算好网页端只是换一种形式展示。我一般会在 app.py 里写一个 /dashboard 路由返回一个模板页页面上的图表数据全部来自 JSON 文件——这样你可以在答辩现场刷新页面给老师看比翻 png 图片有说服力得多。计算正确性上最后务必跑一次对账脚本把 analysis.py 算出的月度总销售额和 agg_tables.xlsx 里 Excel 透视表的数核对。对不上优先查 groupby 是否漏了过滤条件对得上文档里可以加一句“输出结果已与 Excel 透视表交叉验证”。这套流程做完你会发现自己对数据链路的理解比照着教程敲二十遍都有用。我当年做类似项目时就是在 RFM 分层上吃了亏——阈值用平均值而不是中位数导致所有用户都被归到“沉默风险”答辩时被问得说不出话后来习惯所有分箱先画分布图再定阈值这个习惯一直留到现在。希望帮到你。本文还有配套的精品资源点击获取