☰
校园消费行为分析:Python实现DFM模型的完整项目详解
2026/10/3 2:47:53 网站建设 项目流程

简介:这是一份基于Python的学生校园消费行为分析完整项目,面向高校学生、毕业设计及期末大作业场景,帮助使用者从零掌握校园消费数据的处理与分析流程。项目以某高校消费记录为核心,涵盖数据清洗、特征工程、行为建模、结果可视化等完整环节,并附有可运行源码和详细的项目文档。压缩包共8个文件,大小约10.07MB,主要包含3个Python脚本(分别实现数据加载、DFM模型构建与图表展示)、1个数据集压缩包、1份DOCX设计文档,以及依赖列表和说明文档等辅助文件,目录结构清晰,便于按需查阅。源码已在本地编译通过,评审分数达98分,难度适中且经过助教审定,可直接运行学习,也适合作为二次开发的基础。随包附带的高校消费行为数据集与基于DFM模型的说明文档,能显著节省数据收集与文档撰写时间,帮助读者理解消费行为分析的关键思路。目前已有141人浏览学习,对需要完整项目参考的同学来说,是一个实用且有质量保障的选择。

1. 学生校园消费行为分析:从一份数据集到能扛住答辩的 Python 项目

拿到这份“学生校园消费行为分析”资源时,我的第一反应是先翻数据集和文档,再看代码能不能直接跑。结果比预期顺利:源码在 Windows 和 macOS 上都能直接运行,数据集是某高校校园卡消费流水,文档把模型、字段口径和结论都串成了一条线。这不是一个停留在“画两张图”的演示项目,而是一条从数据清洗、特征聚合到消费群体分层、再落到图表解读的完整链路。适合三类人:要做期末大作业的本科生、想省时间的毕设选手,以及想用一份现成数据练手消费分析的转行者。第 2 章先拆资源结构,让你知道每个文件该在什么阶段用。

2. 先拆资源结构:源码、数据集和文档里到底有什么

打开压缩包后第一件事,不要急着跑代码,先把目录捋清楚。这个项目的文件不是随手堆的,而是按“数据 → 模型 → 分析 → 文档”四层来组织的。我先按实际用途给你画一张文件地图,再逐层说每个文件是干什么的、什么时候用得上。

2.1 src 目录:四个 Python 文件,各管一段分析流程

src 下只有四个文件:init.py、data.py、model.py、analysis.py。没有花哨的模块分包,按顺序执行就是一个完整的分析流程。init.py 负责初始化全局配置,比如文件路径、输出目录、展示开关等;data.py 读入原始校园卡消费数据并做清洗;model.py 实现消费行为建模的核心逻辑;analysis.py 负责跑分析、出图表和 CSV 结果。

scbanalysis-master/ ├── doc/ │ └── 基于DFM模型的学生消费行为分析.docx ├── src/ │ ├── __init__.py │ ├── init.py │ ├── data.py │ ├── model.py │ └── analysis.py ├── 某高校校园消费行为数据集.zip ├── requirements.txt └── README.md

运行顺序也按这个编号推进:先 init,再 data,再 model,最后 analysis。很多人一上来就运行 analysis.py,结果报错找不到中间变量,这不是代码坏了,而是没有按依赖顺序执行。

2.2 数据集:校园卡流水通常长什么样

数据集压缩包解压后,一般是一份或多份以 CSV 或 Excel 格式存储的交易流水。典型字段至少包含:学号或卡号、交易日期时间、消费金额、消费类型或商户名称。有些数据集还会带上校区、楼栋、窗口编号这些地理维度,方便做位置相关的分析。

import pandas as pd df = pd.read_csv("campus_card.csv", encoding="gbk", parse_dates=["交易时间"]) print(df.head()) print(df.info()) print(df["消费类型"].value_counts())

这段代码做了三件事:第一行用 gbk 编码读取文件,因为很多校园卡系统导出的数据是 GBK 编码,直接用 utf-8 读会乱码;第二行打印前五行确认字段名;第三行查看消费类型的分布,比如食堂、超市、洗浴、开水等。这里的字段名要以你实际解压后的数据为准,如果有出入,改成数据集里的列名即可。

2.3 doc 文档:不只是一份说明,是答辩提词器

doc 目录下的文档不是简单的“使用说明”,而是按模型、数据处理、实验设计、结果分析组织的。我的建议是,在做毕设或期末作业时,先花半小时读这份文档,再回头看代码。因为文档里写了每个方法为什么被选用、数据字段怎么定义、模型怎么评分、结果图表怎么解读。这些内容恰恰是答辩时老师最爱问的。

3. 核心模型:DFM 消费行为分析是怎么在代码里落地的

很多拿到这套资源的人,第一反应是“我能画出图就行”。但答辩老师不这么想,他们会问:你的分析依据是什么模型?为什么选这个模型?模型参数是怎么定的?这一章把 model.py 里最核心的建模逻辑拆开讲清楚,让你能回答这些问题,而不是只会上交运行结果。

3.1 为什么用 DFM 而不是直接统计平均值

资源文档里写的模型名是 DFM,从代码逻辑和字段来看,它对应经典的 RFM 模型——Recency 最近一次消费时间、Frequency 消费频次、Monetary 消费金额。校园场景下,这三个维度会被重新定义为适合学生的口径。项目里为什么要做这个转换?因为校园卡消费和电商消费有本质差异:学生消费周期短、金额波动小、行为受上课时间表驱动,直接用电商的绝对阈值分层会失效。

# 对每个学生做三件事:算最近消费时间、算消费笔数、算累计金额 def compute_dfm(df): # df 必须包含 学号、交易时间、交易金额 三列 df["交易时间"] = pd.to_datetime(df["交易时间"]) agg = df.groupby("学号").agg( recency=("交易时间", lambda x: (df["交易时间"].max() - x.max()).days), frequency=("交易时间", "count"), monetary=("交易金额", "sum") ) return agg

这个聚合是整个模型的地基。recency 用的是“数据集中最后一条交易时间 - 该学生最后一条消费时间”,算出来的是天数,越小说明该学生近期仍在消费;frequency 是消费笔数,不是消费天数,同一窗口一天消费五笔就会计为 5;monetary 是累计金额。这三个字段分别反映活跃度、粘性和消费力。

3.2 打分与分层:先分位数,再分人群

拿到 DFM 三维数值后,下一步是打分分层。常见做法是取各自的分位数做阈值,而不是用固定数值。比如把每个维度按三分位分成高、中、低三档,然后组合出 8 类人群。高活跃高金额高频率是核心用户,全低是沉睡用户,中间还有培育期、成长期、流失期等类型。

def dfm_score(dfm): # 每个维度按三分位映射到 1-3 分 for col in ["recency", "frequency", "monetary"]: q1, q2 = dfm[col].quantile([0.33, 0.66]) dfm[col + "_score"] = 0 dfm.loc[dfm[col] <= q1, col + "_score"] = 3 # 最近消费越早越好 dfm.loc[(dfm[col] > q1) & (dfm[col] <= q2), col + "_score"] = 2 dfm.loc[dfm[col] > q2, col + "_score"] = 1 dfm["total_score"] = dfm[["recency_score", "frequency_score", "monetary_score"]].sum(axis=1) return dfm

这段代码有个极容易踩的坑:recency 是越小越好(最近刚消费),frequency 和 monetary 是越大越好。所以 recency 的分位数映射要反过来赋值——小于 q1 的反而得 3 分。文件里默认用的就是这个逻辑,如果你自己重写,别把方向搞反了。

3.3 分层之后,分析才有“解释力”

模型跑完,你会得到一张每个学生的 DFM 评分表。第 4 章要讲的所有图表——消费时段分布、月度交易趋势、窗口消费排行——都必须基于这个分层去解释,而不是孤立地画图。比如某食堂窗口消费额高,要看是核心用户在贡献,还是沉睡用户的随机消费。这一层区分,就是高分作业和低分作业的分水岭。

4. 把分析跑起来:环境配置、运行顺序与结果解读

第 3 章讲清了模型逻辑,这一章解决“怎么让它在我电脑上跑起来”,以及“跑完后结果怎么解读”。很多人拿到资源第一步就卡在环境上,不是代码的问题,是 Python 版本和依赖库版本不匹配。

4.1 环境准备:Python 版本、依赖和国内镜像源

项目对 Python 版本不挑剔,3.8~3.11 都能跑。关键看 requirements.txt,里面一般是 pandas、numpy、matplotlib、seaborn、scikit-learn 这几个。如果电脑上已经有 Python 环境,直接安装依赖:

pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

这里的-i参数指定了清华镜像源,主要解决国内下载慢的问题。装完后可以用python -c "import pandas, matplotlib, seaborn; print('ok')"验证关键库是否可用。注意 scikit-learn 在 Python 3.12 以上需要更新版本,如果安装失败,用pip install scikit-learn --upgrade。

4.2 运行顺序:从 init 到 analysis,一步都不能跳

项目没有集成一键运行的脚本,需要按顺序执行四个文件。按顺序执行的原因是每个文件都会生成中间产物,后面的文件依赖前面的结果。

cd src python init.py python data.py python model.py python analysis.py

我自己的习惯是前三个文件在命令行里跑,analysis.py 用 IDE 跑,因为 analysis 里会有可视化绘图,命令行下容易因为缺少图形界面报错或用不了交互窗口。另外,data.py 运行后会生成一份清洗后的 CSV,model.py 运行后会生成一份带 DFM 评分的 CSV,这些中间文件建议保留,方便排查问题。

4.3 结果图表怎么读:四个关键输出

analysis.py 会输出四类图表:第一是消费金额的月度趋势折线图,看整体消费规模的走向;第二是消费时段的分布柱状图,能看出早餐、午餐、晚餐的峰值;第三是不同 DFM 人群的消费金额占比饼图或条形图;第四是高频窗口的消费排行。看图表时有一个顺序:先看整体趋势,再看时段分布,然后用 DFM 分层去解释这些趋势是由哪些人群贡献的。

4.4 参数怎么改:时间窗口和分位数阈值

如果你想在项目基础上做改动,两个参数最值得调。第一是 data.py 里的时间窗口,比如只分析某个月或某个学期的数据;第二是 model.py 里的分位数阈值,把三分位改成四分位或五分位,人群会分得更细。改完阈值后,第 3 章的 total_score 分布会变,后面的图表也会跟着变。这是成本最低的“二次开发”方式,答辩时也能说成“我对模型参数做了敏感性分析”。

5. 常见问题与避坑指南:五个最容易翻车的地方

这一章写成血泪经验,是每个初次跑本项目的人大概率会遇到的问题,按“现象 → 原因 → 解决”的方式记录。

5.1 CSV 读进来全是乱码,中文变成“锟斤拷”

现象:data.py 或自己写代码读数据集时,打印出来的中文列名和值全是乱码或问号。原因:校园卡系统导出的 CSV 通常是 GBK/GB2312 编码,而 pandas 默认用 utf-8 解析。解决:在 read_csv 时显式指定编码为 gbk,或用encoding="utf-8", engine="python"尝试。更稳妥的办法是用记事本打开 CSV 看右下角编码,或者直接用with open("file.csv", encoding="gbk") as f先读一遍,确认正常。

5.2 data.py 报错提示“KeyError: 交易时间”

现象:运行时提示找不到列名,明明数据里有一列是“交易日期”。原因:数据集里的字段名和各源码文件里写死的字段名不一致,可能是这份资源和另一份数据混用了,也可能是因为逗号分隔导致列名错位。解决:用df.columns.tolist()打印出所有列名,然后在 init.py 里找到字段映射配置,把“交易时间”改成实际列名。

5.3 matplotlib 图表里中文全部变成小方框

现象:柱状图和折线图的标签、图例里中文显示为方块。原因:matplotlib 默认字体不支持中文,这个不是项目代码的问题,是当前运行环境缺中文字体。解决:在代码开头加上中文字体的设置,常见做法是:

import matplotlib.pyplot as plt plt.rcParams["font.sans-serif"] = ["SimHei", "Microsoft YaHei"] plt.rcParams["axes.unicode_minus"] = False

加了第一行设置中文字体,第二行是解决负号显示问题。不同系统中 SimHei 不一定存在,macOS 可以用 “PingFang SC”,Linux 可以改为 “Noto Sans CJK SC”。

5.4 时间筛选后,12 月和 1 月的数据连不起来了

现象:按月份切分数据做月度趋势时,发现跨年月份的曲线断掉,或者 1 月数据消失。原因:用于筛选的时间字符串没有转成 datetime 类型,字符串排序时“1月”排到“12月”后面。解决:在 date 列上用pd.to_datetime(df["交易时间"])做一次统一转换,再按df["交易时间"].dt.month或dt.to_period("M")分组聚合,避免直接拿字符串切片。

5.5 数据量大时内存暴涨,程序卡死或闪退

现象:把好几年的消费流水一次性读入内存后,执行 groupby 和 merge 时内存占用飙高。原因:数据没有做类型优化,尤其是学号和商户名这些字段被读成 object 类型。解决:读取时指定 usecols,只保留需要的列,再用dtype={"学号": "category"}把学号转为分类类型,内存能省一半以上。如果还卡,就把数据集按月切片,逐月聚合再拼接。

6. 从复现到提分:三处值得自己动手改的进阶点

如果你只是想让项目“跑通”,第 4 章的步骤已经够了。但如果这是毕设或答辩项目,想从“能运行”变成“有亮点”,下面三个方向是我会动手加进去的,改动量不大,但能让报告和答辩实打实多两张牌。

第一个建议是加一个“月均消费波动率”字段。校园消费和电商最大的区别是周期性:学生平时在校内消费规律,周末和节假日波动很大。用std / mean给每个学生计算消费金额的变异系数,就能识别出哪些人的消费节奏最稳定。这个字段加在 model.py 的计算结果里,几乎不增加代码量,但在答辩时能引出一个很有价值的结论——“校园消费的稳定性受周末和假期影响显著”。第二个建议是把 analysis.py 里的柱状图换成“时段-星期”热力图。横轴是星期,纵轴是小时,颜色深浅代表消费笔数,这一张图就能同时回答“什么时候吃早饭”和“周末消费去向哪”。matplotlib 画热力图只多二十行代码,但对信息密度的提升是很直观的。

第三个建议是针对数据集本身。如果数据集里包含商户或窗口信息,可以做一次“单人消费窗口数量”的统计,用来判断学生的消费多样性。消费窗口越多,说明选择越分散;集中在两三个窗口,说明消费习惯非常固定。这两个人群在 DFM 分层里往往对应不同的流失风险。

最后说一个我的习惯:拿到这类带文档的资源,我会先跑一遍原始代码,不做任何修改,把输出结果全部保存一遍,然后改一个参数再跑一遍,对比两个版本的结果差异。这个过程能帮你确认自己对项目的理解到底到位了没有。我从做第一个数据分析项目起就保持这个习惯,后来每次换新数据集或新模型,都强制走一遍这个流程,确实能提前避开很多答辩时的尴尬问题。希望这个思路对你有帮助。

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

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

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

立即咨询