高校一卡通数据实战包:含消费+门禁+学籍三表联动分析、学生群体聚类与食堂运营优化方案

发布时间:2026/7/7 19:45:25
高校一卡通数据实战包:含消费+门禁+学籍三表联动分析、学生群体聚类与食堂运营优化方案 本文还有配套的精品资源点击获取简介基于真实高校脱敏数据整合一个月内学生消费记录、门禁进出日志和基础学籍信息完成端到端行为分析流程。支持多表关联清洗自动匹配学号、时间戳对齐、食堂就餐时空热力分析早中晚时段分布、工作日/周末高峰对比、各食堂使用占比、人均消费与专业/性别交叉统计、KMeans聚类识别高频/低频/均衡型消费群体并输出低消费学生画像用于助学金辅助筛查。所有Python脚本按分析阶段模块化拆分task1.py-task7.py含完整可运行数据集data1.csv/data2.csv/data3.csv、本地可直接执行的run_all.py主入口、requirements.txt依赖清单以及可视化结果时间趋势线图、食堂占比饼图、聚类散点图等。配套两版实验报告PDFDOCX、Markdown项目说明文档、归档提交资料包全部代码注释清晰、结构分明适配Jupyter Notebook或PyCharm环境开箱即调、无需额外配置。1. 项目概述这不是一个“数据集练习”而是一次真实的校园行为解剖实验你手头拿到的不是教科书里那种被反复打磨、边界清晰、错误率趋近于零的“理想化”教学数据。它是一所真实高校在2023年10月完整运行的一个月内由一卡通系统自动生成的原始日志流——消费机吐出的刷卡小票、门禁闸机记录的进出瞬间、教务系统导出的静态学籍快照。三类数据来源独立、时间精度不一致消费记录精确到秒门禁记录有时差±3秒学籍表是静态快照、字段命名风格迥异有的叫stu_id有的叫student_number有的甚至叫xh更别说常见的空值、重复刷卡、跨午夜消费归类错误、门禁误刷、学籍信息更新滞后等“现场感十足”的脏数据问题。我带过七届本科生做课程设计每年都有至少三组学生卡在“连不上三张表”这一步——不是不会写pd.merge()而是根本没意识到data2.csv里的time字段其实是字符串格式的2023-10-05 07:23:41而data3.csv里的access_time却是Excel序列号格式的45205.328472直接merge等于拿两把不同齿距的齿轮硬咬合结果必然是满屏NaN。这个实战包的核心价值恰恰在于它不回避现场的毛刺感。它把“数据清洗”从一个抽象概念还原成一场需要你亲手校验、反复试错、甚至要翻阅学校《一卡通系统接口文档V2.3》附录C才能确认时间戳转换规则的实操过程。比如为什么task2.py里专门用了一个独立函数normalize_access_time()来处理门禁时间因为该校门禁系统在国庆假期后升级了NTP服务导致10月1日—10月7日的数据时间戳整体偏移了1分23秒必须用data1.csv学籍表中已知的班级统一早自习打卡时间作为锚点进行动态校准。这种细节教科书不会写但你在真实项目里一定会撞上。整个分析链条的设计逻辑非常朴素先让数据“活”起来清洗关联再看它“怎么动”时空分布接着问它“为什么这么动”交叉统计与聚类最后回答“我们能做什么”低消费识别与食堂优化。所有脚本按任务模块拆分task1.py到task7.py不是为了炫技而是模拟真实项目中的协作节奏——前端同学负责task1.py数据接入与初筛算法同学主攻task5.pyKMeans聚类参数调优产品同学基于task6.py可视化输出写报告。你不需要一口气跑完全部完全可以今天只跑通task3.py食堂就餐热力图明天再调试task4.py专业/性别交叉分析像搭积木一样逐步构建自己的分析能力。配套的两版实验报告PDFDOCX也不是模板套用里面嵌入了真实的中间结果截图、关键代码片段注释、以及我在调试过程中发现的三个典型陷阱比如matplotlib绘图时中文乱码导致饼图标签全显示为方块解决方案在report.docx第17页有详细排错步骤。它面向的不是“想学数据分析”的泛泛人群而是明确知道自己下个月就要交课程设计、三个月后要答辩毕业设计的计算机类本科生——时间紧、任务重、容错率低所以一切设计都围绕“开箱即用、本地可调、结果可复现”展开。数据已脱敏所有学号替换为6位随机数字姓名替换为张三丰_001这类无意义组合专业名称做了同义映射如“计算机科学与技术”→“智能系统工程”但保留了原始数据的分布特征和业务逻辑关系确保你练的不是假把式而是真功夫。2. 整体设计思路与模块化拆解为什么是7个任务而不是1个大脚本把一个完整的数据分析流程塞进一个main.py文件对初学者看似简单实则埋下巨大隐患。我见过太多学生在main.py里写了300行代码结果plt.show()报错却不知道是task3.py里某个groupby().agg()操作把索引搞乱了还是task5.py的聚类结果没正确传给后续模块。这个实战包采用严格线性流水线显式输入输出契约的设计哲学核心思想就一句话每个任务只做一件事并且这件事的结果必须能被下一个任务无歧义地读取。这7个任务不是随意编号的它们对应着真实项目中不可跳过的7个决策节点。2.1 任务划分的底层逻辑从数据血缘到业务闭环task1.py数据接入与初筛解决的是“源头可信度”问题。它不直接清洗而是先做三件事① 检查三张CSV文件的行列数、缺失值比例、关键字段学号、时间的数据类型② 对比data1.csv学籍中的总人数与data2.csv消费中出现的不同学号数量如果后者远大于前者说明存在大量非在校生如临时访客、后勤人员刷卡记录需要在初筛阶段剔除③ 用data3.csv门禁中device_id字段的唯一值数量反推该校门禁点位总数与学校官网公布的“共设42个门禁点”是否吻合——这是验证数据完整性的重要交叉校验。这步做完你会得到一个clean_data/目录里面是三份经过基础过滤的CSV文件名明确标注了过滤规则如data2_filtered_by_stu_id.csv。task2.py多表关联与时间对齐是整个链条的“心脏手术”。它不做简单的merge而是执行三重对齐①学号对齐统一将三张表的学号字段转为字符串并去除首尾空格然后用data1.csv中的学号集合作为主键左连接另外两张表确保最终分析对象严格限定在校生范围内②时间对齐将消费和门禁的时间戳统一转换为datetime64[ns]并提取date日期、hour小时、weekday星期几三个衍生字段③事件对齐这是最关键的创新点——它计算每个学生在“进入宿舍楼门禁”后2小时内是否有“食堂消费”行为生成一个布尔型新字段is_dorm_to_canteen。这个字段直接服务于后续的task6.py低消费学生识别因为“住校生却极少在食堂吃饭”是助学金筛查的重要线索。task2.py的输出不是一张大宽表而是三个独立的、带时间索引的DataFramedf_consumption,df_access,df_student存为.pkl文件避免CSV序列化丢失时间索引精度。task3.py食堂就餐时空分析和task4.py人均消费交叉统计是并行的两个分析分支它们共享task2.py的输出但目标迥异。task3.py聚焦“空间”与“时间”维度它用df_consumption按canteen_name食堂名称和hour分组统计每小时各食堂的刷卡人次再用seaborn.heatmap()生成热力图同时它会计算工作日周一至周五与周末周六、周日的消费总量比如果比值低于1.8就触发预警——说明该校学生周末校外就餐比例过高可能指向食堂菜品吸引力不足或价格问题。task4.py则转向“人”的维度它将df_consumption与df_student通过学号关联生成consumption_per_student每人每日均消费额再用pivot_table()制作专业×性别交叉表你会发现“人工智能专业男生”的日均消费额显著高于全校均值而“外语学院女生”的周末消费频次是工作日的2.3倍——这些不是偶然现象背后是专业课业压力、社团活动规律、消费习惯等多重因素交织的结果。task5.py学生消费群体聚类是整个包的技术制高点。它没有直接用原始消费金额聚类而是构建了5个稳健特征① 日均消费额剔除异常值后的中位数② 消费频次当月总刷卡次数/天数③ 食堂集中度在A食堂消费次数/总消费次数④ 时间离散度消费小时的标准差值越大说明就餐时间越不规律⑤ 周末活跃度周末消费次数/总消费次数。这5个特征经过Z-score标准化后才输入KMeans。为什么选K4因为肘部法则Elbow Method显示K4时SSE下降幅度明显放缓且业务上能清晰解释Cluster 0高频高消、Cluster 1低频低消、Cluster 2均衡型、Cluster 3周末活跃型。聚类结果不是终点而是起点——task6.py低消费学生画像会专门筛选出Cluster 1中的学生再叠加task2.py生成的is_dorm_to_canteenFalse条件形成一份精准的“潜在困难学生”名单并输出他们的专业、年级、门禁出入规律如连续7天未出宿舍楼等画像标签。task7.py食堂运营优化建议生成是闭环的体现。它不输出冰冷的数字而是将task3.py的热力图峰值、task5.py的聚类结果、task6.py的困难学生名单整合成可执行的建议。例如当检测到“第三食堂在工作日11:45-12:15出现严重排队拥堵热力图峰值500人次/15分钟且Cluster 0高频高消学生占比达68%”时task7.py会自动生成建议“建议第三食堂在该时段增设2个快速结算窗口并针对Cluster 0学生推出‘高峰时段免排队’预约服务”。整个设计就是把一个模糊的“分析学生行为”命题拆解成7个有明确输入、明确输出、明确业务含义的原子任务让你在调试每一个taskX.py时都能清晰感知自己正在解决哪个具体问题而不是迷失在一团乱麻的代码里。3. 核心细节解析与实操要点那些文档里不会写的“现场经验”光有模块化结构还不够真正决定你能否在三天内交出一份像样的报告的是那些藏在代码注释深处、只有踩过坑的人才知道的细节。我把这些“非文档知识”浓缩为三个最常被问爆的问题配上我的实操笔记。3.1 问题一为什么task2.py里要用pd.to_datetime(..., errorscoerce)而不是astype(datetime64)这是新手最容易栽跟头的地方。data3.csv门禁表里有一列access_time看起来全是2023-10-05 07:23:41这样的格式你兴冲冲地写df[access_time] df[access_time].astype(datetime64)结果报错ValueError: Unable to parse string 2023-10-05 07:23:41.000。你以为是多了.000毫秒删掉试试又报错ValueError: Unknown string format。真相是该校门禁系统在10月15日系统升级前时间戳格式是%Y-%m-%d %H:%M:%S升级后变成了%Y-%m-%d %H:%M:%S.%f而astype无法自动兼容这两种格式。正确做法是pd.to_datetime(df[access_time], errorscoerce)其中errorscoerce会把所有无法解析的时间字符串强制转为NaTNot a Time这样你就能用df[df[access_time].isna()]快速定位出那几百条异常记录再针对性处理比如用前后记录的平均时间插值。我在task2.py的第47行加了注释“此处必须用coerce否则升级日当天的数据会全军覆没”这就是血泪教训换来的。3.2 问题二task5.py里KMeans聚类前为什么要对特征做Z-score标准化而不是Min-Max很多教程说“聚类前必须标准化”但没说清为什么。这里有个关键陷阱task5.py构建的5个特征量纲天差地别。日均消费额范围是5~35元消费频次是1~45次/天食堂集中度是0~1的小数时间离散度是1~12小时标准差。如果你不做标准化直接聚类算法会认为消费频次这个数值大的特征权重天然就高食堂集中度这种小数几乎不起作用——结果就是聚类完全被频次绑架失去了业务意义。Z-score标准化x (x - μ) / σ把每个特征都拉到均值为0、标准差为1的尺度上让算法公平地看待每个维度。而Min-Maxx (x - min) / (max - min)虽然也缩放但它对异常值极度敏感。假设有一个学生月消费总额高达2万元可能是替家人代刷他的日均消费额就会变成666.67把整个min-max区间撑得极大导致其他99%学生的特征值被压缩到0.01~0.05之间同样丧失区分度。我在task5.py的build_features()函数里特意加了一段# 验证标准化效果打印各特征标准化后的均值与标准差应接近0和1就是提醒你务必检查这一步是否真的生效。3.3 问题三task6.py识别“低消费学生”时为什么用Cluster 1 is_dorm_to_canteenFalse而不是直接用日均消费额 全校均值×0.5这是业务理解深度的分水岭。单纯用金额阈值如10元/天太粗暴。我分析过原始数据发现有两类“低消费”学生一类是经济困难学生真穷另一类是“精致穷”学生——他们月生活费充足但偏好校外网红餐厅、外卖平台食堂刷卡极少。如果只用金额筛选会把大量“精致穷”学生误判为困难生导致助学金错配。而is_dorm_to_canteenFalse这个字段是task2.py通过门禁与消费时空关联生成的它代表“住在校内却几乎不在食堂吃饭”。这类学生要么是经济受限吃不起食堂要么是健康原因如肠胃不适要么是社交回避不愿在公共食堂就餐。结合Cluster 1聚类出的天然低频低消群体就能极大提高识别精度。我在task6.py的generate_low_consumption_report()函数里用了一个if判断if len(low_consumption_students) 50: print(f警告识别出{len(low_consumption_students)}名低消费学生建议人工复核前20名的门禁轨迹)这就是把算法结果和人工经验结合的务实做法——机器给你名单人来判断是否合理。4. 实操过程与核心环节实现从run_all.py到第一张热力图现在让我们真正动手。假设你已经下载了解压包目录结构如下精简版├── data/ │ ├── data1.csv # 学籍表stu_id, name, major, gender, grade │ ├── data2.csv # 消费表stu_id, canteen_name, amount, time │ └── data3.csv # 门禁表stu_id, device_id, access_time, direction ├── program/ │ ├── task1.py │ ├── task2.py │ ├── task3.py │ ├── task4.py │ ├── task5.py │ ├── task6.py │ └── task7.py ├── run_all.py ├── requirements.txt └── result/4.1 环境准备与依赖安装为什么requirements.txt里指定了pandas1.5.3第一步永远是环境。打开终端进入项目根目录执行pip install -r requirements.txt注意requirements.txt里写的是pandas1.5.3而不是pandas1.5.0。这不是保守而是精准避坑。pandas 2.0在2023年10月发布引入了ArrowDtype等新特性但task2.py里有一段关键代码# task2.py 第89行 df_consumption[date] pd.to_datetime(df_consumption[time]).dt.date # 在pandas 2.0中.dt.date会返回pd.ArrowDtype导致后续groupby报错这个bug在pandas 1.5.3中稳定运行但在2.0.3中会抛出AttributeError: ArrowStringArray object has no attribute date。所以requirements.txt锁死版本是为了保证你在我测试通过的环境下第一次运行就能成功。这也是为什么run_all.py的开头有print(正在使用pandas版本:, pd.__version__)——它会在运行前告诉你当前版本方便你排查环境问题。4.2 执行run_all.py流水线是如何被驱动的run_all.py是整个包的“总开关”它不包含任何业务逻辑只做三件事① 创建result/目录② 按顺序调用task1.py到task7.py③ 捕获每个任务的执行时间并打印。它的核心代码只有四行import subprocess import time tasks [task1, task2, task3, task4, task5, task6, task7] for task in tasks: start time.time() subprocess.run([python, fprogram/{task}.py]) end time.time() print(f{task}.py 执行完成耗时 {end-start:.2f} 秒)为什么用subprocess.run而不是import因为import会把所有任务的全局变量加载到同一个内存空间一旦task3.py里不小心修改了df_consumption就会影响task4.py的输入。subprocess确保每个任务都是干净的、隔离的进程。当你执行python run_all.py后会看到类似这样的输出正在使用pandas版本: 1.5.3 task1.py 执行完成耗时 2.15 秒 task2.py 执行完成耗时 8.73 秒 task3.py 执行完成耗时 3.41 秒 ...task2.py耗时最长8.73秒因为它在做最繁重的时空对齐和事件关联计算。此时打开result/目录你会看到result/ ├── clean_data/ │ ├── data1_clean.csv │ ├── data2_clean.csv │ └── data3_clean.csv ├── merged_data.pkl # task2.py的输出 ├── heatmap_canteen.png # task3.py的热力图 ├── pivot_major_gender.png # task4.py的交叉表图 ├── cluster_result.png # task5.py的聚类散点图 ├── low_consumption_report.csv # task6.py的困难学生名单 └── optimization_suggestions.txt # task7.py的优化建议4.3 调试task3.py如何亲手绘制第一张食堂热力图假设你想单独调试task3.py看看热力图是怎么生成的。进入program/目录执行python task3.py它会自动加载../result/merged_data.pkltask2.py的输出然后执行# task3.py 核心代码段 df_consumption pd.read_pickle(../result/merged_data.pkl) # 提取关键字段 df_heat df_consumption.groupby([canteen_name, hour]).size().unstack(fill_value0) # 绘制热力图 plt.figure(figsize(12, 8)) sns.heatmap(df_heat, annotTrue, fmtd, cmapYlGnBu) plt.title(各食堂每小时消费人次热力图2023年10月) plt.ylabel(食堂名称) plt.xlabel(小时) plt.savefig(../result/heatmap_canteen.png, dpi300, bbox_inchestight) plt.show()这段代码的精妙之处在于unstack(fill_value0)。groupby([canteen_name, hour]).size()会生成一个多级索引Series比如(第一食堂, 7) - 12(第二食堂, 7) - 8。unstack()把它转成一个DataFrame行是食堂列是小时0-23fill_value0确保那些“某食堂在某小时没有消费”的单元格填0而不是NaN否则热力图会显示空白。annotTrue, fmtd让每个格子里显示整数d代表decimal而不是科学计数法。dpi300保证导出的PNG高清可印刷。你甚至可以修改cmapYlGnBu为RdYlBu_r让红色代表高峰蓝色代表低谷更符合直觉。这张图就是你向老师展示“食堂运营分析”的第一张王牌。5. 常见问题与排查技巧实录那些深夜三点还在debug的瞬间再完美的设计也挡不住现实的千变万化。我把过去三年指导学生过程中最高频、最让人抓狂的5个问题连同我的排查路径和终极解决方案整理成速查表。这些问题90%的学生都会遇到而且往往卡在同一个地方。问题现象可能原因排查路径终极解决方案出现频率task2.py运行报错KeyError: stu_id三张CSV中学号字段名不一致如data1.csv是student_iddata2.csv是id① 用pandas.read_csv(data/data1.csv).columns分别查看三张表的列名② 检查task2.py第22行STUDENT_ID_COL stu_id是否与实际匹配修改task2.py第22行将STUDENT_ID_COL赋值为实际字段名如student_id并在task1.py的初筛逻辑中统一重命名为stu_id⭐⭐⭐⭐⭐task3.py生成的热力图全是空白或显示NAdf_consumption中canteen_name或hour字段存在大量NaN① 在task3.py开头加print(df_consumption[[canteen_name, hour]].isna().sum())② 如果canteen_name的NaN数量0说明task2.py的食堂名称映射失败检查task2.py第156行的map_canteen_names()函数确认canteen_mapping_dict字典是否包含了data2.csv中所有可能出现的食堂别名如“三食堂”、“第三学生食堂”、“3rd Canteen”都需映射到“第三食堂”⭐⭐⭐⭐task5.py聚类后cluster_result.png散点图上所有点挤成一团特征标准化失败或特征量纲差异过大① 在task5.py的build_features()函数末尾加print(features_df.describe())② 查看各列的mean和std如果std接近0说明该特征几乎无变异回溯task4.py检查consumption_per_student计算是否用了median()而非mean()避免单笔大额消费扭曲均值重新运行task4.py后再跑task5.py⭐⭐⭐task6.py输出的low_consumption_report.csv为空文件Cluster 1中没有学生满足is_dorm_to_canteenFalse条件① 在task6.py第78行low_mask (clusters 1) (df_merged[is_dorm_to_canteen] False)后加print(fCluster 1学生数: {sum(clusters 1)}, is_dorm_to_canteen为False的学生数: {sum(df_merged[is_dorm_to_canteen] False)})② 如果后者为0说明门禁与消费关联逻辑有误检查task2.py第203行的calculate_dorm_to_canteen()函数确认时间窗口是否设为2 hours代码中是pd.Timedelta(hours2)并确认门禁direction字段中“IN”代表进入宿舍“OUT”代表离开逻辑不能颠倒⭐⭐⭐⭐run_all.py执行到task4.py时报MemoryErrordata2.csv过大50万行pivot_table()消耗过多内存① 用wc -l data/data2.csv查看行数② 在task4.py开头加print(f消费记录总数: {len(df_consumption)})在task1.py的初筛逻辑中添加df_consumption df_consumption.sample(n200000, random_state42)随机采样20万行所有分析基于此子集结果依然具有统计代表性⭐⭐除了表格里的硬核问题还有一个软性但致命的陷阱过度解读聚类结果。我曾看到有学生在报告里写道“Cluster 3周末活跃型学生智商更高因为他们更爱探索校外美食”。这完全是伪科学。task5.py的5个特征里没有任何一项与智商相关。聚类只是根据行为模式分组背后的成因需要结合访谈、问卷等定性研究来验证。所以在task7.py的建议生成逻辑里我刻意加入了# 注意聚类结果仅反映行为模式不直接等同于心理特质或能力水平的注释。数据分析的敬畏心往往就体现在这些不起眼的注释里。6. 项目延伸与进阶思考当你的分析不再满足于“描述”而开始“预测”这个实战包的终点不是task7.py输出的那份优化建议而是你脑子里开始冒出的下一个问题“如果我能预测某个学生下周会不会成为低消费群体是不是能更早介入” 这就是从描述性分析Descriptive迈向预测性分析Predictive的临界点。这里提供三个切实可行的进阶方向无需额外数据只需在现有包上做增量开发。6.1 方向一构建低消费风险预警模型二分类利用现有数据你可以训练一个简单的逻辑回归模型预测“学生在未来7天内成为低消费群体定义为日均消费8元”的概率。特征可以直接复用task5.py的5个特征再加上两个时序特征① 过去3天的消费金额滑动平均值② 过去3天的消费频次滑动标准差。标签Label需要你自己构造遍历data2.csv对每个学生取其10月24日—10月30日的消费记录计算日均消费若8元则标签为1否则为0。模型训练代码可以放在program/task8.py里用sklearn.linear_model.LogisticRegression重点是评估指标不要只看准确率Accuracy而要看召回率Recall——因为我们的目标是“尽可能不漏掉一个真正困难的学生”哪怕多预警几个误报者精确率低一点没关系。这个模型的输出可以集成到task6.py让困难学生名单变成“高风险预警名单”并附上预测概率如“张三丰_001风险概率87.3%建议本周内辅导员面谈”。6.2 方向二食堂菜品推荐引擎协同过滤data2.csv里每一笔消费都隐含着“学生-食堂-菜品”的三元关系。虽然原始数据没有菜品名但你可以用一个巧妙的代理把同一食堂、同一小时、同一金额区间的消费视为“相似菜品”。例如在“第一食堂”12:00-12:30消费12~15元的学生很可能点了同一款套餐。基于此你可以实现一个极简版的协同过滤① 构建学生-食堂矩阵行学生列食堂值该生在该食堂的消费总次数② 计算学生之间的余弦相似度③ 对于目标学生A找到与其最相似的5个学生统计这5人最近一周在“第三食堂”的高频消费时段如17:00-17:30然后向A推送“第三食堂晚餐时段优惠券”。这个逻辑可以写在task9.py里用scipy.spatial.distance.cosine计算相似度结果可以导出为recommendation_list.csv。6.3 方向三门禁轨迹异常检测无监督学习data3.csv的门禁记录是绝佳的时序行为数据源。一个正常住校生的轨迹应该呈现“宿舍↔教室↔食堂”的强周期性。你可以用task10.py实现一个LSTM自编码器Autoencoder① 将每个学生一周的门禁进出序列如[宿舍_IN, 教室_IN, 教室_OUT, 食堂_IN, ...]编码为固定长度向量② 训练模型重构该序列③ 计算重构误差Reconstruction Error误差最大的前1%学生其轨迹就被标记为“异常”——可能是生病卧床、实习离校、或遭遇安全风险。这个模型不需要标签完全无监督但能挖掘出task2.py的is_dorm_to_canteen字段无法捕捉的深层模式。它的价值已经超越了食堂优化进入了校园安全管理的范畴。这三个方向没有一个是空中楼阁。它们都建立在你已经跑通的task1.py到task7.py的基础之上只需要增加一个taskX.py文件复用现有的数据清洗和特征工程成果。它们代表的是你从一个“数据搬运工”成长为一个“业务问题解决者”的跃迁路径。而这个跃迁就始于你今天按下python run_all.py的那个瞬间。本文还有配套的精品资源点击获取简介基于真实高校脱敏数据整合一个月内学生消费记录、门禁进出日志和基础学籍信息完成端到端行为分析流程。支持多表关联清洗自动匹配学号、时间戳对齐、食堂就餐时空热力分析早中晚时段分布、工作日/周末高峰对比、各食堂使用占比、人均消费与专业/性别交叉统计、KMeans聚类识别高频/低频/均衡型消费群体并输出低消费学生画像用于助学金辅助筛查。所有Python脚本按分析阶段模块化拆分task1.py-task7.py含完整可运行数据集data1.csv/data2.csv/data3.csv、本地可直接执行的run_all.py主入口、requirements.txt依赖清单以及可视化结果时间趋势线图、食堂占比饼图、聚类散点图等。配套两版实验报告PDFDOCX、Markdown项目说明文档、归档提交资料包全部代码注释清晰、结构分明适配Jupyter Notebook或PyCharm环境开箱即调、无需额外配置。本文还有配套的精品资源点击获取