新闻详情

新闻详情

首页 / 资讯中心 / 详情

Python学生校园消费行为分析:从数据清洗到聚类结果集

发布时间:2026/9/15 4:47:35来源:尧图网络
Python学生校园消费行为分析:从数据清洗到聚类结果集
简介一套基于Python的学生校园消费行为分析完整方案面向数据分析初学者、高校相关课程设计及“智慧校园”应用研究者。围绕校园一卡通消费记录涵盖数据清洗、特征工程、食堂消费时段与占比分析、性别差异对比等任务可复现类似“暖心饭卡”项目的贫困生消费画像思路。压缩包共22个文件以ipynb分析代码、py脚本为主辅以结果图表jpg、说明文档docx/md及原始数据包zip整体约19.08MB。代码按任务拆分便于按步骤学习与二次扩展。已有143人学习浏览。通过源码数据结果集的组合读者可快速跑通完整分析流程掌握pandas可视化、餐饮消费规律挖掘等实用技能并直接参考报告撰写范式。1. 学生校园消费行为分析从一卡通流水到可复现的结果集一份校园一卡通流水少则几万条、多则上百万条直接扔进Excel只能看到一堆数字看不出规律。学生校园消费行为分析要解决的核心问题是从这些流水里提取可解释结论谁在正常三餐、谁长期不吃早餐、谁消费频次异常、哪些学生需要重点关注。常规落地路径是——用Python读取原始消费数据清洗掉充值、退款和重复流水按时间、餐次、商户三个维度构造特征再用聚类和异常检测生成消费画像最后导出结构化的结果集。这套分析源码加结果集的组合本身就是可复用的数据产物换一批流水文件改改路径和阈值就能重跑。整个过程不依赖大数据组件pandas 和 scikit-learn 足够覆盖百万行以内的校园场景。2. 消费行为分析的数据建模流水字段、脏数据与特征工程分析开始之前先把数据模型定清楚。一卡通系统导出的文件通常是一行一条流水字段各校略有差异但必含学生标识、交易时间、金额、商户编号。这个阶段的目标不是写算法而是把原始流水变成每行一个学生的特征宽表后面聚类和异常检测都在这张表上做。2.1 一卡通流水的最小字段集与消费口径建表之前先确认拿到的最小字段集少了任何一项后面的特征都算不出来。字段示例值作用student_id20230012学生唯一标识用于分组和后续关联学籍tx_time2024-11-05 12:03:44交易时间必须解析成 datetime 类型amount8.50交易金额消费为正数merchant_idC01商户编号对应食堂窗口、超市、开水房balance42.10交易后余额用于一致性校验tx_time 不转成 datetime后面按小时划分餐次、按天聚合都会出错这是新手最容易忽略的一步。balance 字段的价值在一段话里就能说清同一张卡相邻两笔消费之间余额应当等于上一笔余额减去当前金额误差不超过一分钱。对不上的行要么是系统补录导致顺序错乱要么是换卡后旧卡数据混入需要标记出来单独核查。分析口径上只保留消费类型。充值、退款、补助发放、挂失补卡都属于总流水直接进入特征计算会把日均消费拉高聚类结果完全失真。有的系统没有交易类型字段就用金额正负和商户编号过滤正数且金额落在食堂合理区间内的才算消费行。2.2 时间、餐次、结构三个维度的特征设计特征设计围绕三个维度展开每个维度回答一类业务问题组合起来才能完整描述一个学生的消费画像。维度代表特征计算口径时间规律首笔时间、末笔时间、首笔时间标准差每天首末笔消费时刻跨天求均值与标准差餐次窗口早餐次数、午餐次数、晚餐次数、夜宵次数按小时区间打标后统计再按在校天数均值化消费结构日均金额、单笔均值、商户数、充值笔数金额和商户编号的聚合必要时关联学籍表时间维度反映作息规律性标准差小说明每天吃饭时辰固定餐次窗口反映三餐覆盖度连续多天只有午晚两餐可能是生活习惯也可能与预算约束有关消费结构反映消费水平和选择面单笔均值低但商户数多通常是有意识控制开销。三个维度合成一张宽表每行一个学生这就是后续聚类和异常检测的输入。选择特征时要注意边界充值金额不要进特征它是补给行为不是消费行为商户编号只保留聚合后的商户数不要把每个窗口的商户ID铺开成一堆哑变量那会让特征维度膨胀到几百列聚类距离被稀疏维度带偏。2.3 Python数据清洗与特征聚合的落地代码import pandas as pd df pd.read_csv(consume_raw.csv, parse_dates[tx_time]) df df[df[tx_type] consume] df df.drop_duplicates(subset[student_id, tx_time, amount]) df df[(df[amount] 0) (df[amount] 200)] df df[df[tx_time].dt.hour.between(6, 23)]第一行把交易时间解析成 datetime第二行过滤交易类型只留下消费流水第三行按学生、时间、金额三列去重三列完全一样视为同一条流水被记录了两次第四行剔除金额异常行上限 200 元按普通食堂消费习惯设定如果学校有超市档口或水果店上调到 500 更合理第五行去掉凌晨 0 点到 6 点的零星流水这类记录在校园场景里数量极少却会干扰餐次窗口统计。提示amount 下限用大于 0 而不是大于等于 0防止把退款记录漏进来。上限阈值要结合商户清单复核一刀切 200 会把水果店的大额订单误删。df[biz_date] (df[tx_time] - pd.Timedelta(hours6)).dt.date df[hour] df[tx_time].dt.hour df[meal] pd.cut(df[hour], bins[5, 9, 13, 17, 20, 24], labels[breakfast, lunch, dinner, night, other]) feature df.groupby(student_id).agg( total_spend(amount, sum), tx_count(amount, count), avg_spend(amount, mean), merchant_nunique(merchant_id, nunique), active_days(biz_date, nunique), ) feature[avg_daily] feature[total_spend] / feature[active_days]biz_date 把时间后移 6 小时再取日期凌晨消费归属到前一天后面聚类就不会出现某学生夜间吃了顿夜宵、导致早餐覆盖天数异常的假象。pd.cut 的边界按校园作息设定5 到 9 点是早餐9 到 13 点是午餐13 到 17 点是下午加餐17 到 20 点是晚餐20 点后是夜宵。午餐区间拉到 9 点起算是为了覆盖上午没课、十一点半才去吃午饭的那批学生。聚合时 active_days 用的是实际出现消费的天数而不是日历天数。寒暑假、实习周学生在校天数不同直接除以总天数会把离校学生误判成低消费群体。avg_daily 才是口径统一的日均消费后面异常检测和高低消费分组都以它为准。3. 用Python跑通消费行为分析主流程聚类、异常检测与结果集输出特征宽表就绪后进入主流程。环境用 Python 3.8 以上装 pandas、scikit-learn、matplotlib 三件套就够不需要引入大数据组件。百万行以内的消费数据单机内存能轻松装下KMeans 跑完全量只需秒级真要到了千万行才需要考虑按时间切片或者换分布式框架。3.1 KMeans聚类参数怎么定n_clusters、n_init与标准化from sklearn.preprocessing import StandardScaler from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score nums feature.select_dtypes(number).drop(columns[cluster]) X StandardScaler().fit_transform(nums) for k in range(2, 8): km KMeans(n_clustersk, n_init10, random_state42) labels km.fit_predict(X) print(k, round(silhouette_score(X, labels), 4))标准化这一步直接决定聚类结果质量。日均金额是几十的量级早餐覆盖率是 0 到 1 的小数商户数是个位数量纲差几十倍不缩放的话 KMeans 的欧氏距离完全被金额主导其他维度等于没参与。n_init10 表示每个 k 值用 10 组不同的初始中心各跑一遍取目标函数最小的一次防止随机初始化把结果带进局部最优。random_state42 固定随机种子保证同一份数据两次运行得到完全一致的标签结果要写进报告或交给别的部门复核时这一点是硬要求。轮廓系数取 0 到 1校园消费场景 0.2 到 0.4 属正常。消费行为本身就是连续渐变不存在天然清晰的群体边界硬要追求 0.6 以上通常说明特征维度太少或样本群体极度割裂反而要回去检查清洗逻辑。选 k 时除了看分数还要看每个簇的人数占比出现一个簇占 80% 以上的情况说明 k 取小了或者特征区分度不够要降维到两个主成分画散点图看重叠程度。3.2 异常消费检测单维用IQR组合特征用DBSCANq1 feature[avg_daily].quantile(0.25) q3 feature[avg_daily].quantile(0.75) upper q3 1.5 * (q3 - q1) amount_outliers feature[feature[avg_daily] upper] print(amount_outliers[[avg_daily, tx_count]].head())单维金额异常用 IQR 最直接超过上界的学生要么消费习惯特殊要么流水中混入了代刷场景。校园里一个学生帮室友带饭、一周刷掉上千块的情况并不罕见单看金额只能筛出候选名单不能直接定性。要判断是不是真的偏离群体还需要把日均金额、餐次覆盖、商户数组合起来看这时用 DBSCAN。DBSCAN 的两个参数要按样本量调几万学生时 eps 从 0.5 试到 1.5min_samples 取 10 左右。先看聚类结果里簇的数量如果只有一个大簇加一堆散点说明 eps 太小放宽再跑如果散点占了三分之一说明 eps 太大正常学生都被划成离群点。DBSCAN 不需要预设簇数正好适合在 KMeans 之外做一个交叉验证两种算法都标出来的离群学生优先级最高。3.3 结果集的字段设计与Excel兼容输出result feature.copy() result[cluster] labels result[is_amount_outlier] result.index.isin(amount_outliers.index) result.to_csv(result_set.csv, encodingutf-8-sig, indexTrue)结果集要让人能复核不能只给一个 cluster 编号。cluster 后面要跟每个特征的取值is_amount_outlier 单独成列这样业务方拿到表能直接看到第 3 号聚类的人日均 12 元、早餐覆盖率 40%这种可解释信息。to_csv 的 encoding 用 utf-8-sig 而不是 utf-8Excel 直接打开才不会乱码打开后如果复制粘贴提示与数据验证限制不匹配通常是目标表设置了数据验证规则跟导出格式无关换一列粘贴即可。提示常见做法是同时输出三个文件——result_set.csv 给学生管理部门feature.csv 留作二次建模cluster_summary.csv 给管理层看群体画像。三个文件的字段口径要保持一致避免各算各的。4. 消费数据不一致与结果解读三个最容易翻车的地方脚本能跑通只是开始结果能不能用取决于数据一致性处理和业务解读。这三个问题几乎在每个校园数据集里都会出现提前处理能省下大量返工时间。4.1 数据不一致重复流水与余额连续性校验数据不一致最常见的形态是同一笔消费被记了两次。来源有三个换卡后旧卡流水补录、夜间增量同步任务重跑、人工补录没做幂等。直接按 student_id 去重会把真正的大额消费误删正确做法是先按学生交易时间金额找完全重复的行再对剩余流水做余额连续性校验。df df.sort_values([student_id, tx_time]) df[prev_balance] df.groupby(student_id)[balance].shift(1) df[expected_balance] df[prev_balance] - df[amount] df[balance_diff] (df[expected_balance] - df[balance]).abs() bad_rows df[df[prev_balance].notna() (df[balance_diff] 0.01)]按学生分组排序后shift(1) 取上一笔余额期望余额是上笔余额减当前金额。balance_diff 超过 0.01 元说明中间缺了一笔流水或余额字段没更新。这批行建议标记而不是删除删掉会进一步破坏余额链条后面财务对账时也更难定位。处理完的流水再进特征工程日均金额才有底气。4.2 餐次窗口边界凌晨消费归属与教学周口径餐次划分直接用交易小时判断有个死角凌晨 0 点到 1 点的消费日期上属于新的一天行为上却是前一天晚上的延续。归到当天的早餐明显错误当作 other 丢弃又会丢夜宵行为。常见做法是把时间整体后移 6 小时再取日期和小时凌晨消费自然并入前一个自然日。shifted df[tx_time] - pd.Timedelta(hours6) df[biz_date] shifted.dt.date df[biz_hour] shifted.dt.hour参数说明偏移 6 小时是把凌晨 0 点到 6 点并入前一日零售和餐饮行业处理跨天营业的通用口径。另外寒暑假、考试周、实习周的消费结构差异极大。特征重算前先按 biz_date 排除假期或者单独出一版只含教学周的结果集否则长假拉低的均值会掩盖正常学期的消费水平聚类分组也会偏向假期维度。4.3 聚类编号不能当标签cluster画像与层次聚类复核KMeans 给出的 cluster 编号是算法对特征空间的划分不是业务标签。编号 0 的学生可能消费中等换个数据集编号 0 又成了最低群体。解读前必须输出每个簇的特征均值表把cluster 0翻译成日均消费低、餐次覆盖少这种业务可读的描述。cluster人数日均金额早餐覆盖率商户数业务解读012409.842%3.2规律性偏弱的低消费群体1273018.688%5.1三餐规律的主流群体218042.376%8.9高消费且选择面广的少数群体如果 KMeans 每个 k 的轮廓系数都不理想或者某个簇人数超过七成失去区分度可以换层次聚类复核。scipy 的 linkage 函数能输出树状图直接看分割层数不需要预设 k。但层次聚类的复杂度是样本数的平方学生量超过两万时内存和耗时都会明显上升。常见做法是先 KMeans 粗分到 20 个簇再对这 20 个中心点做层次聚类既保留树状图的可解释性又不爆内存。5. 把消费分析结果集做成可增量更新的数据快照每周有新流水进来结果集还要可追溯这里有一个实用的增量做法。全量重跑在几十万行时还能接受但特征工程一旦引入滚动窗口重算时间会非线性上涨。常见做法是增量清洗 窗口重算 快照存储三步。import json from pathlib import Path state json.loads(Path(state.json).read_text()) last_ts pd.Timestamp(state[last_ts]) new_rows pd.read_csv(consume_daily.csv, parse_dates[tx_time]) new_rows new_rows[new_rows[tx_time] last_ts] if not new_rows.empty: clean_new clean_flow(new_rows) full pd.concat([snapshot, clean_new]).drop_duplicates( subset[student_id, tx_time, amount]) feature build_features(full) result run_clustering(feature) result.to_csv(fresult_set_{full[biz_date].max()}.csv, encodingutf-8-sig) state[last_ts] str(new_rows[tx_time].max()) Path(state.json).write_text(json.dumps(state))state.json 记录上次导入数据的最大时间戳作为增量边界。合并到快照后仍要 drop_duplicates因为增量文件边界处可能与上一批重叠。特征必须基于合并后的全量快照重算不能只算新增行餐次覆盖天数和跨天归属都依赖历史窗口。验证技巧每两周跑一次全量重算对比增量版的 cluster 标签一致率低于 95% 就去查 state.json 的时间戳是否被手工改过。结果集文件名带日期后缀保留上一版回溯问题时直接对比两个 CSV 的行数、总金额和每个簇的人数这三个指标能快速定位是数据缺失还是特征口径变了。增量产生的中间文件按日期归入当日目录配合每日数据备份结果集整体就是一份可回滚的分析资产。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Java Swing图书管理系统实战:MySQL连接、中文支持与JTable刷新 2026/9/15 5:35:39

Java Swing图书管理系统实战:MySQL连接、中文支持与JTable刷新

简介:这是一套基于Java Swing与MySQL开发的GUI图书管理系统完整工程,面向高校计算机专业学生课程设计与Java GUI开发初学者,解决双角色(学生/管理员)场景下的图书借阅、入库、读者管理等核心业务需求。资源包共184个文…

阅读更多 →
AutoHedge:量化交易自动对冲系统设计与实践 2026/9/15 5:35:39

AutoHedge:量化交易自动对冲系统设计与实践

做量化的朋友应该都有过这种经历:策略逻辑没毛病,回测曲线也漂亮,但一上实盘,账户回撤总是比预期大一号。仓位暴露、行情跳空、多账户敞口不一致,随便哪一个都能把辛辛苦苦积累的利润一口吃掉。所以我始终觉得&#xf…

阅读更多 →
iOS第一行代码:从Xcode启动到真机调试的完整链路 2026/9/15 5:35:38

iOS第一行代码:从Xcode启动到真机调试的完整链路

1. 这不是“Hello World”,而是iOS开发者的成人礼 “iOS开发新手的第一行代码”——这七个字背后,藏着一群刚合上《Swift编程入门》、手指悬在Xcode编辑器上方、连模拟器启动键都犹豫三秒的人。我带过37个零基础转岗的前端、设计、测试同事做iOS开发&am…

阅读更多 →
从dragonballsuper_082-1到规范漫画库:命名整理实战指南 2026/9/15 5:35:38

从dragonballsuper_082-1到规范漫画库:命名整理实战指南

我试过在NAS上折腾一套漫画管理库,最终发现真正卡住我的不是存储空间,而是那一堆乱七八糟的文件命名和重复的章节目录。所以当我在整理《龙珠超》这套漫画时,拿到“dragonballsuper_082-1”这样的文件,第一反应是:这个…

阅读更多 →
C#酒店管理系统实战:ADO.NET+事务+房态同步 2026/9/15 5:35:38

C#酒店管理系统实战:ADO.NET+事务+房态同步

简介:这是一套面向C#初学者与毕业设计学生的酒店管理信息系统实战源码,聚焦Windows桌面端开发与SQL Server数据库应用,解决中小型酒店日常运营中的客房调度、预订登记、入住退房及账务统计等核心业务需求。资源共91个文件,包含31个…

阅读更多 →
数据库实时同步与异步同步:机制、原理与工程实践 2026/9/15 5:32:38

数据库实时同步与异步同步:机制、原理与工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞