news 2026/9/23 4:54:36

Python校园消费行为分析实战:从数据清洗到聚类建模全链路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python校园消费行为分析实战:从数据清洗到聚类建模全链路

简介:这是一份面向数据分析初学者与高校学生的Python实战项目资源,围绕校园消费行为分析展开,可用于课程设计、技能练习或研究参考。压缩包共20个文件,约20.37MB,包含4个py源码脚本、4个csv数据文件、9张png与3张jpg结果图,分别对应分析代码、原始消费数据与可视化输出,结构清晰便于按任务模块对照学习。项目覆盖数据采集、清洗处理、分析与可视化、消费行为模型构建及结果展示等完整流程,读者可借助源码与数据复现聚类分析、关联规则和预测模型等典型方法,理解从原始数据到结论报告的落地路径。目前已有794人学习下载,适合希望掌握Python数据处理与分析技术、积累消费行为建模经验的人群参考使用。

1. 从一份校园消费数据包说起:Python 分析链路到底能跑出什么

很多做校园信息化或者零售运营的朋友,手里其实不缺数据,缺的是一条能跑通、能复现、能拿给别人看的分析链路。这份「基于 Python 的学生校园消费行为分析」资源包,恰好就是一条完整链路的实物切片:data目录下放着data1.csvdata2.csv两份原始消费流水,code目录里是task1_X1.pytask3_X4.py这一组任务脚本,result目录则沉淀了task1_X.csvtask1_1_X.csv两个中间结果表和十来张task2_X*.pngtask3_X*.png可视化图。它解决的不是「教你怎么装 Python」这种入门问题,而是把采集、清洗、聚合、可视化、建模这条链路上每一步的输入输出都摆出来,让你能对着结果反推代码逻辑。适合谁?适合已经会写基础 Python、想拿一份真实校园消费数据练手的数据分析初学者,也适合需要给学校后勤或校园商家做消费洞察报告、但不想从零造轮子的从业者。下面我按「资源是什么 → 怎么跑 → 坑在哪 → 怎么进阶」的顺序拆一遍。

2. 拆包与数据摸底:两份 CSV 和一组任务脚本怎么对上

2.1 目录结构与文件职责

拿到压缩包先别急着跑代码,先把目录摊开看一遍。这份资源的文件组织是典型的「数据 / 代码 / 结果」三分法,职责边界很清楚:

目录文件作用
datadata1.csvdata2.csv原始消费流水,两份文件大概率是不同维度或不同时间段的记录
codetask1_X1.pytask1_X2.pytask2_X1.pytask3_X1.py按任务编号组织的分析脚本,task1 偏清洗、task2 偏统计可视化、task3 偏建模
resulttask1_X.csvtask1_1_X.csv清洗或聚合后的中间结果表,可直接用 Excel 打开核对
resulttask2_X1.png~task2_X5.pngtask3_X1.png~task3_X4.png各任务输出的图表,是验证代码是否跑对的直接依据

demo.jpg在根目录和子目录都出现,通常是运行效果截图或流程图,用来对照「跑完应该长什么样」。这里有个细节值得注意:脚本命名里的X1X2X4不是随便编的,它对应的是同一任务下的不同子问题或不同数据集分支,比如task3_X1.pytask3_X2.py可能分别对data1data2做聚类。跑之前先确认每个脚本读的是哪份 CSV,否则很容易出现「代码没报错但结果对不上」的玄学问题。

2.2 用 pandas 做第一轮数据摸底

在跑任何分析脚本之前,我习惯先用一段独立的摸底代码把两份 CSV 的字段、类型、缺失情况看清楚。这一步能帮你判断后面脚本里的列名引用是否和实际数据一致:

import pandas as pd # 分别读取两份原始数据,注意编码,校园系统导出的 CSV 常见 gbk 或 utf-8-sig for name in ["data1.csv", "data2.csv"]: df = pd.read_csv(f"data/{name}", encoding="utf-8-sig") print(f"===== {name} =====") print("形状:", df.shape) print("字段:", list(df.columns)) print("前 3 行:\n", df.head(3)) print("缺失值:\n", df.isnull().sum()) print("类型:\n", df.dtypes)

这段代码的逻辑很直接:循环读两份文件,先看形状判断数据量级,再看字段名确认后面脚本引用的列是否存在,最后看缺失值和类型。参数上唯一需要留意的是encoding,如果报UnicodeDecodeError,把utf-8-sig换成gbk再试,这是国内校园系统导出 CSV 最常见的两种编码。跑完这一步你会得到两份数据的字段清单,拿它去对照task1_X1.py里的列名,能提前发现「脚本里写的是amount但数据里叫money」这类低级但致命的错位。

2.3 任务脚本的执行顺序

这份资源的脚本是按 task 编号递进的,不要跳着跑。合理的执行顺序是:先跑task1_X1.pytask1_X2.py完成清洗,产出result/task1_X.csvtask1_1_X.csv;再跑task2_X1.pytask2_X5.py做统计和可视化,产出那批task2_*.png;最后跑task3_X1.pytask3_X4.py做建模,产出task3_*.png。每个脚本跑完,先去result目录确认对应的输出文件是否生成、时间戳是否更新,再跑下一个。这种「跑一个验一个」的节奏,比一口气全跑完再排查要省事得多。

3. 清洗与聚合:task1 脚本里的字段处理和中间结果核对

3.1 消费流水的典型清洗动作

校园消费数据常见的脏法就那么几种:金额字段带货币符号、时间字段格式不统一、有退款导致的负数、有重复刷卡记录。task1_X1.pytask1_X2.py干的就是把这些收拾干净。我一般会在读懂原脚本后,按下面这个模式补一段可复用的清洗逻辑,方便你对照理解每一步在干什么:

import pandas as pd df = pd.read_csv("data/data1.csv", encoding="utf-8-sig") # 1. 金额列去掉可能的货币符号并转 float df["amount"] = df["amount"].astype(str).str.replace("¥", "", regex=False) df["amount"] = pd.to_numeric(df["amount"], errors="coerce") # 2. 时间列统一转 datetime,无法解析的置为 NaT df["trade_time"] = pd.to_datetime(df["trade_time"], errors="coerce") # 3. 剔除金额为空或为负的异常记录(退款单独处理) df = df[df["amount"].notna() & (df["amount"] > 0)] # 4. 按「学号 + 时间 + 金额」去重,防止重复刷卡 df = df.drop_duplicates(subset=["stu_id", "trade_time", "amount"]) # 5. 导出中间结果,供 task2 使用 df.to_csv("result/task1_X.csv", index=False, encoding="utf-8-sig") print("清洗后行数:", len(df))

逻辑说明:第 1 步处理金额字段的类型污染,errors="coerce"保证无法转换的值变成NaN而不是直接抛异常;第 2 步统一时间格式,这是后面做「按小时/按天聚合」的前提;第 3 步把退款和异常金额剔掉,注意如果你的分析目标包含退款行为,这一步要改成单独标记而不是删除;第 4 步的去重键是经验值,校园一卡通重复刷卡的判定通常就是这三要素相同。参数上,encoding和前面摸底保持一致,导出时用utf-8-sig是为了 Excel 打开不乱码。

3.2 中间结果表的核对方法

result/task1_X.csvtask1_1_X.csv是清洗后的产物,也是 task2 的输入。核对这两个文件,重点看三件事:行数是否比原始数据少(少了说明清洗生效)、字段是否比原始数据多(多了说明做了衍生,比如拆出了「小时」「星期几」)、金额列的分布是否合理(有没有离谱的极大值)。我一般会写一段快速核对代码:

import pandas as pd raw = pd.read_csv("data/data1.csv", encoding="utf-8-sig") clean = pd.read_csv("result/task1_X.csv", encoding="utf-8-sig") print("原始行数:", len(raw), "清洗后行数:", len(clean)) print("清洗后字段:", list(clean.columns)) print("金额描述统计:\n", clean["amount"].describe())

如果清洗后行数只少了个位数,说明数据本身比较干净;如果少了一半以上,就要回头检查去重键是不是设得太宽,把正常记录也误删了。金额的describe()里重点看max,如果出现几万甚至几十万的单笔消费,基本可以判定是异常值,需要在清洗阶段加一个分位数截断。

3.3 衍生字段的构造

消费行为分析里,光有原始时间和金额是不够的,task2 的很多图表依赖衍生字段。常见的衍生包括:从trade_time拆出hour(几点消费)、weekday(周几消费)、is_weekend(是否周末),以及按金额分档的amount_level(低/中/高消费)。这些字段一般在 task1 阶段就构造好,写进中间结果表,task2 直接拿来用。构造时注意hour要用dt.hourweekdaydt.dayofweek(周一是 0),别用dt.weekday搞混。这一步没有太多坑,但字段名要和 task2 脚本里的引用严格一致,否则又是一轮「跑得通但图是空的」。

4. 可视化与建模:task2、task3 脚本的图表逻辑和模型选择

4.1 task2 的五张图分别在回答什么问题

task2_X1.pngtask2_X5.png这五张图,基本覆盖了消费行为分析的标准问题集:消费金额分布、消费时间分布、不同人群消费对比、消费频次统计、消费趋势变化。对应的脚本task2_X1.pytask2_X5.py通常用 matplotlib 或 seaborn 出图。我拿「按小时统计消费笔数」这个最常见的图举例,说明脚本里的逻辑:

import pandas as pd import matplotlib.pyplot as plt df = pd.read_csv("result/task1_X.csv", encoding="utf-8-sig") df["trade_time"] = pd.to_datetime(df["trade_time"]) df["hour"] = df["trade_time"].dt.hour hourly = df.groupby("hour")["amount"].agg(["count", "sum"]).reset_index() plt.figure(figsize=(10, 5)) plt.bar(hourly["hour"], hourly["count"], color="#4C72B0") plt.xlabel("小时") plt.ylabel("消费笔数") plt.title("校园消费时段分布") plt.xticks(range(0, 24)) plt.tight_layout() plt.savefig("result/task2_X1.png", dpi=150)

逻辑说明:先按小时分组,同时统计笔数和金额,agg(["count", "sum"])一次拿到两个指标;画图时用柱状图看分布形态,xticks固定 0 到 23 保证横轴完整。参数上dpi=150是出图清晰度和文件大小的平衡点,tight_layout防止标签被裁。跑完对照result/task2_X1.png,如果横轴只有部分小时、或者柱子高度明显异常,回去检查hour字段是否构造正确、有没有把NaT混进去。

4.2 task3 的建模脚本在做什么

task3_X1.pytask3_X4.py对应的是消费行为建模,从摘要描述看,涉及聚类分析、关联规则和预测模型。聚类(比如 KMeans 对学生按消费金额和频次分群)是最常见的入口,关联规则(比如「买了 A 的人也会买 B」)适合食堂窗口或超市商品分析,预测模型(比如预测下月消费额)则依赖时间序列或回归。以聚类为例,脚本的核心逻辑通常是:选特征 → 标准化 → 定 K 值 → 聚类 → 可视化。这里有个选型理由要讲清楚:消费金额和消费频次量纲差很多,不标准化直接聚类,结果会被金额主导,频次几乎不起作用。所以StandardScaler这一步不能省。

import pandas as pd from sklearn.preprocessing import StandardScaler from sklearn.cluster import KMeans df = pd.read_csv("result/task1_X.csv", encoding="utf-8-sig") # 按学生聚合出消费总额和消费笔数两个特征 stu = df.groupby("stu_id")["amount"].agg(["sum", "count"]).reset_index() stu.columns = ["stu_id", "total_amount", "trade_count"] # 标准化,消除量纲差异 X = StandardScaler().fit_transform(stu[["total_amount", "trade_count"]]) # 聚成 3 类,随机种子固定保证可复现 km = KMeans(n_clusters=3, random_state=42, n_init=10) stu["cluster"] = km.fit_predict(X) stu.to_csv("result/task3_X1.csv", index=False, encoding="utf-8-sig") print(stu.groupby("cluster")[["total_amount", "trade_count"]].mean())

逻辑说明:先按学号聚合出两个核心特征,再标准化,再聚类。n_clusters=3是常见起点,实际 K 值要靠肘部法或轮廓系数确定,脚本里如果写死了 3,你可以改成循环试 2 到 6 看效果。random_state=42n_init=10是为了结果可复现,这两个参数不设的话每次跑出来的分群可能不一样,做报告时会很尴尬。跑完看每个簇的均值,如果某一簇的total_amounttrade_count都明显偏高,那就是「高消费高频」人群,对应的是校园里消费能力最强的那批学生。

4.3 结果集与图表的交叉验证

result目录里的 PNG 和 CSV 是互相印证的:CSV 是数值结果,PNG 是数值的视觉呈现。验证时不要只看图好不好看,要拿图去反推数值是否合理。比如聚类图里如果三个簇的点完全重叠,说明特征区分度不够或者没标准化;时间分布图里如果凌晨时段也有大量消费,要么数据有问题,要么就是把NaT错误地归到了 0 点。这种交叉验证的习惯,能帮你在写报告之前就把数据问题拦下来。

5. 避坑与排查:跑这份资源时最容易翻车的五个地方

5.1 编码不对导致读取直接报错

现象:pd.read_csvUnicodeDecodeError,脚本第一步就挂。原因:国内校园系统导出的 CSV 常用gbkgb2312,而脚本里可能写的是默认utf-8。解决:先试utf-8-sig,不行换gbk,再不行用chardet探测。我一般会在读取处加一个 try 链,把两种编码都兜住。

5.2 列名对不上导致 KeyError

现象:脚本跑到df["amount"]时报KeyError: 'amount'。原因:实际 CSV 的列名可能是中文「消费金额」或者英文money,和脚本里的引用不一致。解决:先跑第 2 章的摸底代码打印df.columns,拿实际列名去改脚本,或者统一在读取后做一次df.rename(columns={...})映射。这个坑血泪经验最多,因为报错信息只告诉你缺哪个键,不告诉你实际有哪些键。

5.3 时间字段解析失败被静默丢弃

现象:清洗后行数骤减,但没有任何报错。原因:pd.to_datetime(..., errors="coerce")会把解析失败的值变成NaT,如果后面又做了dropna,这些行就被无声无息地删了。解决:在to_datetime之后先统计NaT数量,如果占比超过 5%,说明时间格式比预想的复杂,需要先用字符串切片或正则把格式统一再转。别让coerce成为黑匣子。

5.4 聚类不标准化导致分群失真

现象:聚类结果里某一簇几乎包含所有样本,另外两簇只有零星几个点。原因:特征量纲差异大,金额的方差远大于频次,KMeans 的距离计算被金额主导。解决:聚类前必须StandardScaler,或者改用对量纲不敏感的方法。判断是否标准化到位,可以看标准化后各特征的均值是否接近 0、标准差是否接近 1。

5.5 图表中文显示成方块

现象:PNG 里中文标题和标签全是方框。原因:matplotlib 默认字体不含中文。解决:在绘图脚本开头设置plt.rcParams["font.sans-serif"] = ["SimHei"]plt.rcParams["axes.unicode_minus"] = False。如果系统没有 SimHei,换成Microsoft YaHeiWenQuanYi Micro Hei。这个坑不影响数值结果,但会让你的结果图没法直接放进报告,属于「不致命但很烦」的那类。

6. 进阶玩法:把这份资源改成可复用的分析模板

跑通原脚本只是第一步,真正让这份资源产生长期价值的方式,是把它改造成一个参数化的分析模板。我的做法是抽出一个config.py,把文件路径、编码、聚类 K 值、图表输出目录这些易变项集中管理,脚本里只引用配置,不再写死。这样换一份新的校园消费数据,只需要改配置里的路径和字段映射,整条链路就能复用。

具体来说,我会在config.py里定义:

# config.py DATA_DIR = "data" RESULT_DIR = "result" ENCODING = "utf-8-sig" COL_MAP = {"消费金额": "amount", "交易时间": "trade_time", "学号": "stu_id"} K_CLUSTERS = 3 RANDOM_STATE = 42

然后在每个 task 脚本开头from config import *,读取时统一走pd.read_csv(f"{DATA_DIR}/data1.csv", encoding=ENCODING).rename(columns=COL_MAP)。这样列名映射只维护一处,换数据时改COL_MAP就行,不用去每个脚本里搜替换。K 值和随机种子也集中管理,做对比实验时改一个地方就能重跑全链路。

再进一步,可以把 task1 到 task3 串成一个run_all.py,用subprocess或直接函数调用的方式按顺序执行,每步之间加一个输出文件存在性检查,任何一步失败就中止并打印是哪一步、缺哪个文件。这样你交付给别人的就不是一堆散脚本,而是一条能一键跑通、失败能定位的流水线。验证模板是否改造成功,标准很简单:拿一份字段名不同的新 CSV,只改config.py里的COL_MAP和路径,全链路能跑出结果图,就算成了。

从那以后我每次拿到这种「源码 + 数据 + 结果集」的资源包,都强制先跑一遍摸底、再核对中间结果、最后才动建模脚本,绝不跳步。这套顺序帮我省下了大量「跑得通但结果不对」的排查时间。希望帮到你。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 4:54:31

乐图地图包下载避坑指南与速查手册

乐图地图包下载避坑指南与速查手册 你是不是也遇到过这种情况?从网上随手复制一段地图包下载代码,或者照搬某个教程里的配置,结果一跑就报错,或者下载下来的东西根本用不了。这种“复制粘贴”式的开发,往往是新手入门最大的坑。别急,今天这篇《乐图地图包下载》避坑指南兼 速查手册…

作者头像 李华
网站建设 2026/9/23 4:54:19

一文搞懂htcu11:从语法到架构的底层逻辑拆解

一文搞懂htcu11:从语法到架构的底层逻辑拆解 很多刚入行的工程师,或者从其他语言转行过来的朋友,都有一个共同的困扰: 学会了语法却不知怎么搭项目 。你看着文档里的 htcu11…

作者头像 李华
网站建设 2026/9/23 4:54:00

地松鼠速查手册:5个必踩坑一次讲透

地松鼠速查手册:5个必踩坑一次讲透 官方文档翻了三遍还是记不住重点?别慌,这不是你的问题。地松鼠这类工具的底层逻辑确实绕,新手容易在配置和依赖上栽跟头。我整理了一份地松鼠速查手册,把大家最常问的几个坑直接摊开讲。 坑一:环境依赖冲突导致启动失败…

作者头像 李华
网站建设 2026/9/23 4:53:45

3个实战项目拆解奥特曼格斗进化重生底层逻辑

3个实战项目拆解奥特曼格斗进化重生底层逻辑 面试被问原理答不上来,往往不是背得不够多,而是没在 实战项目 里真刀真枪地调过包。最近复盘几个经典格斗游戏架构,发现很多开发者对状态机与帧同步的理解停留在表面。今天咱们不整虚的,直接拿 奥特曼格斗进化重生…

作者头像 李华
网站建设 2026/9/23 4:53:21

5分钟搞懂开关原理,搞定高频面试题

5分钟搞懂开关原理,搞定高频面试题 官方文档太长抓不住重点?别慌。很多后端工程师在准备 高频面试题 时,对“开关”(Feature Toggle/Flag)的理解还停留在“if-else”层面。其实,开关原理是系统架构中控制灰度发布、降级熔断的核心基石。今天咱们不背八股文,直接动手从零搭建一个生产级…

作者头像 李华
网站建设 2026/9/23 4:53:17

别只背 app制作教程,手写实现源码才懂底层逻辑

别只背 app制作教程,手写实现源码才懂底层逻辑 面试被问“App 启动流程”或“页面生命周期”,你卡壳了吗?很多人只会调 API,一旦深入原理就露馅。其实, 手写实现 核心模块,比死记硬背十遍 app制作教程 更有效。 入口定位:从 Manifest 到 Application 的真相…

作者头像 李华