
简介基于python的图书馆借阅数据分析设计与实现是一份面向数据分析初学者、图书馆专业学生和信息化从业者的实战资源可用于课程设计、毕业设计或数据分析项目练手。它围绕2014至2017年图书借还记录、读者信息、图书目录等数据通过主题词提取、帕累托分析、热门书分析、排名变化四个Python脚本并配以图书分类法简表、停用词表等文本资源完整演示了从数据清洗到分析结果展示的流程。压缩包共16个文件包含7个xlsx数据文件、4个py脚本、3个txt说明文档、1个readme和1张说明图整体仅46.45MB目录结构清晰readme可帮助快速了解各文件用途。该资料已有2275人学习适合想用真实业务数据提升Python数据分析与挖掘能力的读者代码与文档配合到位便于理解每一步分析思路直接运行即可复现结果。1. 基于 Python 的图书馆借阅数据分析源码包拆解与实战复现路径图书馆借阅数据本质上是长期积累的用户行为数据它包含读者信息、借还记录、图书目录三张核心表。基于 Python 做借阅数据分析不是跑一两个统计函数出几张图就完事而是要把“谁在借什么书、借阅量如何变化、热门书排名怎么迁移、主题词分布反映什么学科热点”这套完整链路跑通。这份资源包正好覆盖了借书名 TOP20 排名变化、帕累托分析、热门书分析和主题词提取四个模块适合正在做图书相关毕设、需要完成部门借阅报告的数据从业者。它解决的不是“会不会 pandas”的问题而是“拿到真实图书馆数据后按什么顺序清洗、分组、透视、出结论”的问题。下面我按实际拆解的顺序把每个脚本的设计意图和落地参数逐一讲透。2. 借阅数据结构和预处理四张 Excel 表先要解决三个脏数据问题整个分析链路的前提是数据能对齐。包里给了 2014 到 2017 四年的“图书借还”表外加读者信息、图书目录、中图法简表和停用词表。很多人上来直接 pd.read_excel 然后就开始 groupby结果透视出来的数字对不上——这不是运气问题是没做前置校验。2.1 四张表的关系主键、外键和粒度先明确表之间的关系图书目录表以“图书ID”为主键读者信息表以“读者证号”为主键借还表是明细流水每一行是一次借阅行为包含图书ID、读者证号、借书日期、续借次数等字段。粒度上借还表是“一本书被借一次”一行不是按天汇总也不是按读者汇总。读进来之后第一件事是统一字段类型。import pandas as pd # 读取四张核心表 borrow_2014 pd.read_excel(图书借还2014.xlsx) borrow_2015 pd.read_excel(图书借还2015.xlsx) borrow_2016 pd.read_excel(图书借还2016.xlsx) borrow_2017 pd.read_excel(图书借还2017.xlsx) reader_df pd.read_excel(读者信息.xlsx) book_df pd.read_excel(图书目录.xlsx) # 合并四年借阅数据加一个年份字段方便后续按年对比 borrow_2014[年份] 2014 borrow_2015[年份] 2015 borrow_2016[年份] 2016 borrow_2017[年份] 2017 borrow_df pd.concat( [borrow_2014, borrow_2015, borrow_2016, borrow_2017], ignore_indexTrue ) print(borrow_df.shape) print(borrow_df.dtypes)逻辑说明concat 纵向堆叠四张表之前先手动加“年份”列否则合并后无法区分一条记录来自哪一年。ignore_indexTrue 是让合并后的行索引重新从 0 编号避免出现重复索引导致后续 groupby 结果诡异。参数说明read_excel 在读真实图书馆导出的表时经常遇到表头不在第一行的情况。如果发现列名变成了“Unnamed: 0”用header1或skiprows指定真正的表头行比事后改名省事。2.2 脏数据问题一读者证号数字和字符串混存图书馆业务系统导出的读者证号有的表里是纯数字有的表里是文本还有的带着前导零。如果不统一两个表 merge 的时候同一读者会被拆成两条记录。# 统一读者证号为字符串并去掉两端空白 for col in [读者证号, 证号]: if col in borrow_df.columns: borrow_df[col] borrow_df[col].astype(str).str.strip() if col in reader_df.columns: reader_df[col] reader_df[col].astype(str).str.strip() # 校验看看证号是否有空值 print(borrow_df[读者证号].isna().sum()) print(reader_df[证号].isna().sum())逻辑说明astype(str) 会把数字 1001 转成字符串 1001但如果是浮点数 1001.0 会转成 1001.0所以更稳妥的做法是先去掉 .0 后缀。strip() 是去掉业务系统里常见的不可见空格。参数说明如果你发现证号字段变成 1001 和 1001.0 两种形态用str.replace(r\.0$, , regexTrue)清洗。这一步不做后面所有 merge 都会少数据。2.3 脏数据问题二书名字段里的版本、册次、标点噪声同一本书在借还记录里可能写成《三体》、《三体全集》、《三体 1》等。做热门书排名时这些会被当成三本书分别统计热榜就被稀释了。import re def clean_title(title): 清理书名中的版本、册次和标点噪声 if not isinstance(title, str): return title # 去掉括号内容如全集、(上中下册) title re.sub(r[(][^)]*[)], , title) # 去掉“第X册/部/卷”这类册次描述 title re.sub(r第[0-9一二三四五六七八九十][册部卷], , title) # 去掉书名号 title title.replace(《, ).replace(》, ) return title.strip() borrow_df[题名_清洗] borrow_df[题名].apply(clean_title)逻辑说明清洗规则要克制。去掉括号内容能合并“全集/套装”噪声但有些书名本身带括号且是正式书名的一部分比如《经济季刊》这一条规则会误伤。取舍上热门书分析用清洗后的字段单本明细展示用原始字段。参数说明正则[(][^)]*[)]匹配中文和英文括号内的内容。如果你的数据里有英文括号嵌套先跑一轮看清洗前后的唯一值数量变化确认没有大面积误伤再定稿。2.4 脏数据问题三借书日期跨年错乱和空值借还表里偶发“还书日期早于借书日期”这种物理不可能的数据以及部分日期缺失。处理策略不是删除而是打标记。# 统一日期列 borrow_df[借书日期] pd.to_datetime(borrow_df[借书日期], errorscoerce) borrow_df[还书日期] pd.to_datetime(borrow_df[还书日期], errorscoerce) # 标记异常还书日期比借书日期更早 mask borrow_df[还书日期] borrow_df[借书日期] print(f异常借还记录数{mask.sum()}) # 过滤掉借书日期为空的记录保留还书日期异常但借书日期正常的记录 borrow_df borrow_df[borrow_df[借书日期].notna()].copy()逻辑说明errorscoerce 会把无法解析的日期变成 NaT然后过滤掉借书日期的空值。还书日期异常记录建议单独存一份不直接删除——有些系统在续借时会把还书日期重写看起来像负借阅时长。参数说明dateutil 解析中式日期 2015/1/2 和 2015-01-02 都能处理但如果遇到纯数字格式 20150102pd.to_datetime 需要加format%Y%m%d指定。3. 热门书分析和帕累托图从借阅明细到采购决策的落地路径预处理做完进入第一个核心分析模块。资源包里“热门书分析.py”和“生成帕累托.py”两个脚本解决的是同一个问题的两个侧面热门书告诉你是哪几本在撑场面帕累托告诉你这种“撑场面”到底有多集中。3.1 热门书 TOP20聚合键怎么选、并列排名怎么处理热门书分析的第一步是按图书聚合借阅次数。这里有个细节按“图书ID”聚合还是按“题名”聚合我的建议是优先用“图书ID”聚合因为同一本书在书目表里 ID 唯一题名可能有细微差异。# 热门书 TOP20按图书ID聚合附加题名信息 book_hot ( borrow_df .groupby([图书ID]) .agg( 借阅次数(图书ID, count), 题名(题名_清洗, first) ) .reset_index() .sort_values(借阅次数, ascendingFalse) ) book_hot_top20 book_hot.head(20).copy() book_hot_top20[排名] range(1, 21) print(book_hot_top20[[排名, 题名, 借阅次数]])逻辑说明groupby(图书ID) 后 agg 里同时传两个 aggfunccount 统计借阅次数first 取该 ID 下第一条题名作为代表。sorted 后 head(20) 截取前 20。参数说明如果你希望并列排名比如两本书并列第五用rank(methodmin)生成排名列而不是 range(1, 21)。业务上并列排名更常见因为真实借阅数据里次数相同的概率不低。3.2 帕累托分析头部 20% 图书到底扛了多少借阅量帕累托图的核心是算累计占比。这里的关键不是图而是“前多少本书贡献了 80% 的借阅量”。# 帕累托分析排序后的累计贡献 book_hot[累计借阅次数] book_hot[借阅次数].cumsum() book_hot[累计占比] book_hot[累计借阅次数] / book_hot[借阅次数].sum() * 100 # 找达到 80% 的临界位置 reach_80 book_hot[book_hot[累计占比] 80] print(f达到80%累计借阅量需要 {reach_80.index[0] 1} 本书) print(f图书总数: {len(book_hot)}) print(f头部{reach_80.index[0] 1}本的借阅量占比: f{book_hot[累计占比].iloc[reach_80.index[0]]:.2f}%)逻辑说明cumsum 依次累加累计占比第一次突破 80 的行索引加一就是“覆盖八成借阅量所需的最少图书数”。index[0] 取的是第一个满足条件的索引位置。参数说明一本图书馆藏几万册时这个数字通常在几百到一千之间。如果前 50 本就贡献了 80% 借阅量说明馆藏极度头部集中——采购复本量需要加大冷门书要考虑剔旧。3.3 帕累托图的 Matplotlib 绘制参数脚本最终要出图。帕累托图是柱状图加折线图的组合柱状图是每本书的借阅次数折线图是累计占比。import matplotlib.pyplot as plt # 只画前 50 本后面的长尾太长没有可视化意义 plot_data book_hot.head(50) fig, ax1 plt.subplots(figsize(12, 6)) ax1.bar(plot_data[题名][:20], plot_data[借阅次数][:20], color#4C72B0) ax1.set_xlabel(图书) ax1.set_ylabel(借阅次数) ax1.set_xticklabels(plot_data[题名][:20], rotation45, haright) # 次坐标轴画累计占比折线 ax2 ax1.twinx() ax2.plot(plot_data[累计占比][:20], color#C44E52, markero) ax2.set_ylabel(累计占比 (%)) ax2.set_ylim(0, 100) plt.title(图书馆借阅帕累托分析前20本) plt.tight_layout() plt.savefig(pareto_top20.png, dpi150)逻辑说明twinx() 创建共享 x 轴的第二个 y 轴让柱状图和折线图量纲不同也能叠在一起。取前 20 本书画柱状图是因为前 20 的借阅次数差异大画前 50 会让小数值被压成一条线。参数说明dpi150 是输出分辨率用在报告里够清晰用在投影屏幕上建议提到 200。color 参数可以换成图书馆统一的 VI 色避免默认红蓝配色和学校报告模板冲突。4. 借阅排名变化分析跨年度对比与消减趋势的量化算法只看单年热榜容易判断失误——某本书去年排第一今年可能掉出前十。尤其高校图书馆每年采购经费、专业设置都在变书的热度迁移能反映学科建设方向的调整。资源包里的“排名变化”脚本就是做跨 2014 到 2017 四年的借阅榜对比量化哪本书上升了、哪本掉队了。4.1 多年度对比的透视表设计:排名矩阵核心思路是把四年排名压成一张宽表每一行是一本书每一列是一个年份单元格的值是这本书当年的热榜排名。这样横向看一本书的迁移轨迹纵向看某年的热榜构成。# 先按年分组计算借阅次数和当年的内部排名 borrow_df[年度排名] ( borrow_df .groupby(年份)[图书ID] .transform(count) ) # 按年度排序并生成排名 book_rank ( borrow_df .groupby([年份, 图书ID, 题名_清洗]) .agg(借阅次数(图书ID, count)) .reset_index() ) book_rank[当年排名] ( book_rank .groupby(年份)[借阅次数] .rank(methoddense, ascendingFalse) ) # 透视成宽表 rank_pivot book_rank.pivot_table( index题名_清洗, columns年份, values当年排名, aggfuncmin ) print(rank_pivot.head(20))逻辑说明rank 部分放在了 groupby 之后而不是 transform因为需要先聚合出每本书在每年的总借阅次数再算排名。pivot_table 的 aggfuncmin 处理同一本书在同一年出现多行的情况。参数说明rank 的 methoddense 表示并列名次不占位两本书并列第一时下一本还是第二而不是第三。如果你要严格排名用 methodmin 或 first。4.2 消减趋势判定连续两年在榜但名次下滑的书排名变化不只是看差值还要识别“持续在榜但逐步下滑”的书——这种比某一年的暴跌更值得关注。# 筛选连续四年都在 TOP20 榜单的书 mask_2014 rank_pivot[2014] 20 mask_2015 rank_pivot[2015] 20 mask_2016 rank_pivot[2016] 20 mask_2017 rank_pivot[2017] 20 continuous rank_pivot[mask_2014 mask_2015 mask_2016 mask_2017] # 计算四年排名斜率用线性拟合的系数近似 from scipy.stats import linregress def trend_slope(row): years [2014, 2015, 2016, 2017] ranks row.values # 排除 NaN 后做最小二乘拟合 valid [(y, r) for y, r in zip(years, ranks) if not pd.isna(r)] if len(valid) 2: return 0 slope, _, _, _, _ linregress([y for y, _ in valid], [r for _, r in valid]) return slope return 0等一下上面 return 0 的缩进写错了改一下。def trend_slope(row): years [2014, 2015, 2016, 2017] ranks row.values # 排除 NaN 后做最小二乘拟合 valid [(y, r) for y, r in zip(years, ranks) if not pd.isna(r)] if len(valid) 2: return 0 slope, _, _, _, _ linregress([y for y, _ in valid], [r for _, r in valid]) return slope continuous[排名斜率] continuous.apply(trend_slope, axis1) # 斜率为正代表排名数值变大即排名下滑 print(continuous[continuous[排名斜率] 1].sort_values(排名斜率, ascendingFalse).head(10))逻辑说明linregress 用最小二乘拟合“年份-排名”的线性关系斜率大于 1 意味着排名每年大约下滑 1 名以上。排名数值是离散整数线性拟合会损失一些精度但用于排序筛选足够。参数说明scipy.stats.linregress 返回五个值取第一个即斜率。如果没装 scipy可以用 numpy 的 polyfit 替换效果一致。4.3 排名变化的热图和标注把变化趋势可视化趋势表是给分析人员看的热图是给决策者看的。热图的 y 轴是书名x 轴是年份颜色越深代表排名越靠前。import seaborn as sns # 取四年都上榜的排名数据画热图 plot_rank continuous[[排名斜率]].merge( rank_pivot, left_indexTrue, right_indexTrue ).head(15) plt.figure(figsize(10, 8)) sns.heatmap( plot_rank[[2014, 2015, 2016, 2017]], annotTrue, fmtg, cmapYlOrRd, cbar_kws{label: 排名}, linewidths0.5 ) plt.title(2014-2017 连续上榜图书排名变化热图) plt.tight_layout() plt.savefig(rank_heatmap.png, dpi150)逻辑说明annotTrue 在每个方格中写入排名数值fmtg 去除小数位。颜色深和浅的跳变点在视觉上非常直观——要么是断崖式下滑要么是新书强势冲榜。参数说明cmap 选 YlOrRd 是黄红渐变排名 1 对应黄色。如果想让第一名最显眼用cmaprocket_r深色代表第一。5. 主题词提取与文本挖掘从书名到学科热点的分析闭环借阅次数只能告诉你哪本书火没法告诉你哪类知识火。图书馆报告常用的做法是提取书名主题词再映射到中图法分类号量化“计算机类借阅上涨 X%”、“文学类占比下降 Y%”。资源包里的“提取主题词.py”处理的就是这个环节。5.1 主题词提取jieba 分词与停用词过滤的参数设置主题词提取不是简单的分词要去掉停用词、只保留有区分度的实词。包里的 stopwords.txt 是领域定制停用词表比通用表多了“上册”“下册”“大全”“指南”这类图书馆场景词。import jieba from collections import Counter # 加载停用词表 with open(stopwords.txt, encodingutf-8) as f: stopwords set(line.strip() for line in f if line.strip()) def extract_top_keywords(title_series, top_n30): 从书名Series提取主题词并统计频次 word_counter Counter() for title in title_series: if not isinstance(title, str): continue # 精确模式分词 words jieba.lcut(title) for w in words: w w.strip() # 过滤停用词、单字、纯数字 if ( w and w not in stopwords and len(w) 1 and not w.isdigit() ): word_counter[w] 1 return word_counter.most_common(top_n) title_keywords extract_top_keywords(borrow_df[题名_清洗], top_n30) for word, count in title_keywords[:20]: print(word, count)逻辑说明jieba.lcut 返回分词后的列表len(w) 1 过滤掉“学”“书”这类单字not w.isdigit() 过滤掉书名里的年份和卷号数字。词频统计放在最后一个循环里避免中途重复遍历。参数说明jieba 默认词库里“Python”可能被切成“Python”也可以切成“Py”“thon”——如果切分结果不理想手动 add_word 加固领域词。5.2 中图法分类映射从 22 个大类到热门主题词画像中文图书分类法把馆藏拆成 22 个大类A 马克思主义、B 哲学、C 社会科学总论……T 工业技术书的“中图分类号”在图书目录表里。把借阅流水的图书ID join 上分类号就能按类目聚合。# 借阅流水关联中图分类号 borrow_with_cat borrow_df.merge( book_df[[图书ID, 中图分类号]], on图书ID, howleft ) # 取分类号的首字母作为一级类目 borrow_with_cat[一级类目] borrow_with_cat[中图分类号].str[0] # 按年份类目统计借阅量 cat_yearly ( borrow_with_cat .groupby([年份, 一级类目]) .agg(借阅次数(图书ID, count)) .reset_index() ) # 透视成宽表方便比较各年占比 cat_pivot cat_yearly.pivot_table( index年份, columns一级类目, values借阅次数, aggfuncsum ).fillna(0) # 计算各类目年度占比 cat_ratio cat_pivot.div(cat_pivot.sum(axis1), axis0) * 100 print(cat_ratio.round(2))逻辑说明merge 时 howleft 保借阅流水全部记录没有匹配到分类号的书会留空。str[0] 取分类号首位字母如果你想精确到二级类目用 str[:3]。参数说明有的图书馆编目时分类号带辅助符号比如“TP312.5”str[0] 取的是 T空分类号的书算入“未知类目”——建议单独统计占比不要直接填充为某个字母否则会污染类目聚合结果。5.3 学科热点的年度趋势主题词与头部类目的交叉验证把主题词频和中图法类目趋势交叉起来看能有“软件工程主题词频上涨T 类借阅增长 15%”这种交叉验证结论。写代码时注意主题词从书名提取类目从分类号聚合两者是互补视角。# 按年度提取 TOP10 主题词观察主题词迁移 for year in [2014, 2015, 2016, 2017]: year_data borrow_df[borrow_df[年份] year] year_top extract_top_keywords(year_data[题名_清洗], top_n10) words [w for w, c in year_top[:5]] print(f{year}: {, .join(words)}) # 输出2014和2017的热词对比通常是年度报告的核心数据逻辑说明主题词的年度对比建议输出到 CSV 而不是直接打印——后续可以做词频涨幅排序找出“新晋热词”和“退热词”。所谓新晋热词是指上一年的 TOP20 里没有、今年冲进 TOP10 的词。参数说明top_n 参数控制每年前 N 个词。如果图书馆馆藏偏向理工类建议把停用词表里加上“研究、分析、方法、基于、实现”这些论文常用噪声词。6. 借阅分析报告的避坑与常见问题排查从数据清洗到主题词提取每个环节都有几个高频雷区。这里按“现象-原因-解决方案”记录实际拆解中踩过的坑。6.1 重复借阅记录导致借阅次数虚高现象同一本书同一个读者在同一分钟借了两次热门书排名里这本书虚高一位。原因系统在读者续借时生成了一条新记录而不是在原记录上更新续借次数或者读者还书后立刻再借同一本书时间差只有几秒。解决按“图书ID 读者证号 借书日期”三个字段去重。注意不要去掉“一小时内同一读者重借同一本书”这种数据可能是真实的有针对性借阅。6.2 年份字段混入日期格式导致 concat 后年份列变成 datetime现象合并四年数据后年份列出现 2015-01-01 而不是 2015。原因某一张表的 Excel 单元格格式被设成了日期导致 pandas 读出的是 datetime 而不是 int。解决读入后统一处理年份列如果是 datetime用 dt.year 提取年份如果是 int保持原样。# 年份列兜底如果是 datetime 类型提取年份 def coerce_year(series): if pd.api.types.is_datetime64_any_dtype(series): return series.dt.year return series for year_df in [borrow_2014, borrow_2015, borrow_2016, borrow_2017]: year_df[年份] coerce_year(year_df[年份])6.3 中图分类号缺失导致类目分析出现巨大“未知类”现象类目分析里“未知”占比达到 30%无法解释其他类目的趋势。原因图书目录表和借还表关联时部分索书号为空或者分类号字段存在中文描述和字母代码混用。解决对空值单独标记不参与热词类目分析分类号别直接用 str[0]先 strip 再加非法字符校验取值必须是 A-Z 开头。6.4 笛卡尔积爆炸merge 时忘了去掉重复的图书ID现象借阅数据从几万行变成几百万行groupby 结果明显错误。原因图书目录表里同一本书出现多行不同副本、不同馆藏地点直接 merge 时每一行都匹配上了。解决先 drop_duplicates 再 merge。book_df_dedup book_df.drop_duplicates(subset[图书ID]) borrow_with_cat borrow_df.merge( book_df_dedup[[图书ID, 中图分类号]], on图书ID, howleft )7. 资源包复现的扩展用法把静态分析变成动态模板分析做完代码是死的数据是新的。这份资源包的价值在于换成新数据也能跑通。最后给出三个扩展用法帮你把一次性分析变成可持续的月度报告模板。7.1 参数化年度对比函数化重构分析脚本把四年对比写成函数传任意年份列表就能跑不用每次改代码。def yearly_borrow_report(borrow_full, years): 生成指定年份集合的借阅对比报表核心字段 summary_rows [] for y in years: y_data borrow_full[borrow_full[年份] y] top_book ( y_data.groupby(题名_清洗)[图书ID] .count() .sort_values(ascendingFalse) .head(1) ) summary_rows.append({ 年份: y, 总借阅次数: len(y_data), 活跃读者数: y_data[读者证号].nunique(), 榜首图书: top_book.index[0], 榜首借阅次数: int(top_book.iloc[0]), }) return pd.DataFrame(summary_rows) # 示例调用 report yearly_borrow_report(borrow_df, [2014, 2015, 2016, 2017]) print(report)逻辑说明nunique 是去重计数和 count 的区别是关键——总借阅次数可以重复活跃读者数不能重复。7.2 排行榜断崖检测用排名变化斜率自动标注异常书把第四章的斜率逻辑换成分类判断自动输出预警列表。def flag_rank_anomalies(rank_matrix, drop_threshold5): 标记排名大幅下滑的书 drop_threshold: 连续两年排名下滑超过该值则预警 flags [] for book in rank_matrix.index: ranks rank_matrix.loc[book].dropna() if len(ranks) 3: diff ranks.diff().dropna() if (diff drop_threshold).any(): flags.append({ 书名: book, 最大单年下滑: int(diff.max()), 最近排名: int(ranks.iloc[-1]), }) return pd.DataFrame(flags) # 输出下滑预警列表 anomaly_df flag_rank_anomalies(rank_pivot) print(anomaly_df.sort_values(最大单年下滑, ascendingFalse).head())逻辑说明diff() 计算行内相邻年份的排名差值为正代表排名数字变大即下滑。超过阈值的年份被标记为异常。7.3 生成一页纸摘要把多维指标压进一个 Excel最终交付不是一堆图而是一个单一入口的报表文件。把总览、TOP10、类目趋势、排名变化放进不同 sheet打开第一个 sheet 就能看到核心结论。# 写出多 sheet 报表 with pd.ExcelWriter(某高校图书馆借阅分析月报.xlsx, engineopenpyxl) as writer: report.to_excel(writer, sheet_name总览, indexFalse) book_hot_top20.to_excel(writer, sheet_name热门书TOP20, indexFalse) cat_ratio.round(2).to_excel(writer, sheet_name类目占比) rank_pivot.head(30).to_excel(writer, sheet_name排名变化)逻辑说明ExcelWriter 是写多 sheet 的标准姿势。注意第一个 sheet 必须是总览而不是数据明细——决策者打开文件看到的第一个东西决定ta对这个报告的整体印象。参数说明engineopenpyxl 是 xlsx 格式最稳定的选择如果遇到数字被存成文本补一步sheet.to_excel(..., float_format%.2f)统一数字格式。作为拆过多个图书数据项目的人最大的体会是这类分析没有“一次跑通”的运气只有“反复验证”的习惯。每次拿到新的月度数据我都强制自己先跑一遍去重率、空值率、同比波动三个 sanity check再谈分析和图表——这个习惯帮我躲过了好几次排名虚高和类目缺失的坑。这份资源包的脚本拿过去可以直接改路径运行但真正值钱的是里面清洗逻辑和分类映射的取舍。希望帮到你。本文还有配套的精品资源点击获取