当前位置: 首页 > news >正文

超市销售数据Python实战包:透视分析+自动HTML报表生成(含清洗、多维统计与可视化)

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

简介:直接跑通超市销售分析全流程的轻量级Python工具包,用真实订单CSV文件(order.csv、order-14.1.csv、order-14.3.csv)做基础数据源。两个Jupyter Notebook分工明确:第一个负责数据清洗、缺失值处理、字段标准化,并支持按地区、商品品类、销售日期、门店等多维度生成动态透视表,快速算出销售额、订单数、平均客单价等核心指标;第二个专注自动化报表输出,一键运行即可生成带交互式图表(柱状图、折线图、热力图)的HTML报告,已预渲染好2、超市销售数据自动化报表.html,双击浏览器直接打开查看。全部代码控制在200行内,变量命名清晰,关键步骤附中文注释,新手照着说明.txt和使用说明(含常用包及安装方法).zip就能装好环境、跑通结果。不需要额外配置或网络请求,离线可用。适合学生交课程作业、投简历时展示数据分析能力,也适合作为小型商超日常销售复盘的轻量化模板。

1. 这不是“又一个Python练习题”,而是一份能直接放进简历的作品集底稿

你有没有遇到过这样的情况:学完Pandas的groupbypivot_table,却在课程设计里卡在“怎么把结果变成老板能看懂的一页报告”上?或者投数据分析岗时,作品集里全是Kaggle搬运来的Titanic预测,面试官扫一眼就划走——不是代码不行,是缺一个“真实业务场景闭环”的证据。这个超市销售数据Python实战包,就是为解决这个问题而生的。它不讲抽象理论,不堆炫酷算法,而是从三份真实的订单CSV文件(order.csvorder-14.1.csvorder-14.3.csv)出发,用不到200行干净、可读、带完整中文注释的Python代码,跑通一条完整的分析链路:原始数据 → 清洗标准化 → 多维透视统计 → 自动化HTML报表生成 → 浏览器一键查看。关键词里的“超市销售分析”不是泛泛而谈,它对应着真实业务中每天要问的问题:哪个区域卖得最好?生鲜品类是不是拖了后腿?周五下午三点是不是客流高峰?而“Python透视表”在这里不是语法练习,而是你用pd.pivot_table(index=['地区', '门店'], values='销售额', aggfunc='sum')这一行就能拉出区域-门店交叉业绩热力图的实操能力;“HTML报表生成”也不是调个plotly.offline.plot()就完事,而是把柱状图、折线趋势、订单量分布热力图全部嵌入一个自包含的HTML文件,双击打开即见效果,连服务器都不用起。我带过十几届数据分析方向的学生,发现他们最大的断层不在代码能力,而在“分析结果如何被业务方真正接收”。这份资源包刻意绕开了Flask/Django这类需要部署的框架,也避开了Power BI/Tableau这类需额外授权的工具,只用pandas+plotly+Jinja2三个核心库,把整个流程压缩进两个Jupyter Notebook里——第一个专注“算得准”,第二个专注“看得懂”。它适合谁?如果你正在赶电商类课程作业,它能让你交出一份比同学多出“动态筛选下拉框”和“自动更新时间戳”的报告;如果你在准备求职作品集,它能成为你GitHub主页上那个被星标最多的项目,因为HR点开2、超市销售数据自动化报表.html,3秒内就能看到你处理的是真实数据、产出的是真实价值;如果你是小型商超的店长或区域督导,它甚至可以直接作为每周销售复盘模板,改个路径、换份新CSV,5分钟生成带图表的周报PDF(只需加一行pdfkit.from_file())。这不是玩具项目,它的数据结构来自某连锁生鲜超市2023年Q3脱敏订单样本,字段包括订单ID下单时间收货地区门店编码商品大类商品小类数量单价实付金额优惠类型等共17列,覆盖了从下单到履约的全链路关键节点。所有代码离线可用,不依赖任何外部API或云服务,安装说明打包在zip里,连conda环境配置命令都给你写好了。接下来,我会带你一层层拆解这个包为什么能“开箱即用”,它在哪些细节上做了普通人想不到但业务方真正在意的设计,以及——更重要的是——当你想把它改成自己行业的分析模板时,该动哪几行、不动哪几行。

2. 内容整体设计与思路拆解:为什么是“两个Notebook”而不是“一个大脚本”?

2.1 分工逻辑:清洗分析与报表呈现必须物理隔离

很多新手会本能地把所有代码塞进一个.ipynb文件:前面读数据、清洗、做透视,后面画图、导出HTML,最后保存。这在技术上完全可行,但实际交付时会暴露出三个致命问题:一是调试成本高,每次改图表样式都要重跑一遍耗时的数据清洗;二是协作困难,业务同事想只看报表,却不得不面对满屏的fillna()astype()代码;三是复用性差,你想把这套逻辑迁移到服装销售分析上,结果发现清洗规则(比如地区字段的标准化映射表)和报表模板(比如是否需要展示退货率)耦合在一起,改一处崩三处。这个资源包采用“两个Notebook”的硬性分割,本质上是在模拟真实数据分析团队的工作流:数据工程师负责第一份Notebook(1、超市销售数据分析.ipynb),确保输入数据干净、口径统一、指标定义无歧义;数据分析师/可视化工程师负责第二份Notebook(2、超市销售数据自动化报表.ipynb),基于前者输出的标准化DataFrame,专注信息传达效率。这种分离不是为了炫技,而是有明确的技术收益。比如,在第一个Notebook里,我们对下单时间字段做了三重解析:先用pd.to_datetime()转为datetime类型,再提取年-月(用于月度趋势)、星期几(用于周维度分析)、小时(用于时段分析)三个衍生列;同时对收货地区字段执行了城市-省份映射(如“杭州市西湖区”→“浙江省”),并统一了门店编码的前缀(所有门店编码补零至6位,如M001M00001),这些操作一旦完成,第二个Notebook就完全不用关心原始数据的脏乱,直接拿df_clean这个DataFrame开干。这种设计让每个Notebook的职责单一到极致:第一个Notebook的最终输出只有两个对象——清洗后的主表df_clean和一个多维透视结果字典pivot_dict(键为维度名,值为对应透视表);第二个Notebook的输入也只有这两个对象。你可以把它理解成工厂流水线:上游车间(Notebook1)只管把原材料(原始CSV)加工成标准件(df_clean),下游车间(Notebook2)只管把这些标准件组装成最终产品(HTML报告)。这种解耦带来的直接好处是,当你要适配新业务时,90%的修改工作只发生在Notebook1里——比如服装行业需要增加“尺码”、“季节”维度,你只需在清洗阶段新增字段解析逻辑,Notebook2的报表模板几乎不用动。

2.2 技术选型:为什么放弃Matplotlib/Seaborn,坚持用Plotly+Jinja2?

市面上绝大多数Python数据分析教程教画图,首选都是Matplotlib或Seaborn。它们稳定、文档全、社区大,但有一个被严重低估的短板:静态输出。plt.savefig('sales.png')生成的图片是位图,放大就模糊;嵌入HTML时只能作为<img>标签,无法交互,不能点击筛选、不能悬停看数值、不能缩放。而这个资源包的核心价值之一,是生成“能直接给老板演示”的报表。老板不会关心你的plt.rcParams['font.sans-serif']设没设对,但他一定会指着屏幕问:“这个华东区的峰值,能不能让我看看是哪几家门店贡献的?”——这时候,静态图就彻底失效了。我们选择Plotly,正是因为它原生支持交互式图表,并且能无缝导出为自包含的HTML片段(fig.to_html(full_html=False, include_plotlyjs='cdn'))。更关键的是,Plotly的图表对象本身就是一个JSON结构,可以被Jinja2模板引擎直接消费。你看2、超市销售数据自动化报表.ipynb里的核心逻辑:它不是用fig.show()弹窗,也不是fig.write_html()硬编码路径,而是把每个图表对象(fig_region,fig_category,fig_time)存进一个字典,然后传给Jinja2模板。模板里这样写:{{ fig_region | safe }},Jinja2就把Plotly生成的JavaScript代码原样注入HTML。这种组合拳解决了三个层次的问题:底层是Plotly提供交互能力,中层是Jinja2提供HTML结构控制权(你能自由决定标题位置、图表排列顺序、是否加公司Logo),顶层是open()函数直接调用系统默认浏览器打开——整个过程没有中间服务器,没有网络请求,纯本地执行。有人会问:为什么不直接用Plotly自带的plotly.io.write_html()?答案是灵活性不足。那个方法生成的HTML是“黑盒”,你无法在图表上方加一段业务解读文字,无法在底部插入免责声明,也无法把多个图表按网格布局(比如左上柱状图、右上折线图、下方热力图)。而Jinja2模板给了你完全的HTML掌控力,模板文件report_template.html里,你甚至能看到这样的结构:

<div class="chart-container"> <h3>📊 按地区销售额分布(TOP5)</h3> <p class="subtitle">数据截止至 {{ report_date }},共 {{ total_orders }} 笔订单</p> {{ fig_region | safe }} </div>

这里的{{ report_date }}{{ total_orders }}是Notebook2里计算出的变量,和图表一样被注入。这种“代码逻辑+模板结构”的分离,才是工业级报表生成的正确姿势。至于为什么不用Dash?因为Dash需要启动一个Web服务进程,而这个包的设计哲学是“离线、轻量、零配置”。学生交作业时,不可能要求老师装Node.js再跑dash app;小店长复盘时,也不会为了看个周报去开终端敲python app.py。Plotly+Jinja2的组合,完美契合了“双击HTML即见效果”的终极目标。

2.3 架构精简:200行代码如何承载全流程?关键在“不做通用,只做够用”

看到“200行代码”这个数字,很多人第一反应是“怎么可能?”——毕竟光是读取三个CSV文件、合并、去重、处理缺失值,没个五六十行打不住。这里的关键在于:它不做通用数据处理框架,只做超市销售这一垂直场景的精准打击。举个最典型的例子:缺失值处理。通用方案会写一堆if df[col].dtype == 'object': df[col].fillna('Unknown') else: df[col].fillna(df[col].median()),但在这个包里,我们直接根据业务常识硬编码:
-收货地区缺失 → 填充为"未知地区"(因为地区是强业务字段,缺失意味着数据采集失败,不能随便用众数填充)
-商品大类缺失 → 填充为"其他"(分类体系里确实存在“其他”兜底类目)
-实付金额缺失 → 删除整行(金额为null的订单无分析价值)

这种“不优雅但高效”的写法,省去了类型判断、策略分发的几十行代码。再比如时间维度处理,通用方案会写一个函数支持任意时间粒度(年/季度/月/周/日/时),但这里只实现三个业务刚需粒度:年-月(用于月度同比)、星期几(用于工作日/周末对比)、小时(用于时段分析),每种都用一行dt属性搞定:df['下单时间'].dt.to_period('M')df['下单时间'].dt.dayofweekdf['下单时间'].dt.hour。透视分析部分更是如此。它不提供pivot_table()的所有参数选项,而是封装了几个预设函数:
-get_region_pivot():固定index='地区',values='实付金额',aggfunc='sum'
-get_category_trend():固定index='年-月',columns='商品大类',values='订单数',aggfunc='count'

这些函数内部其实就一行pd.pivot_table()调用,但通过封装,把复杂的参数组合变成了业务友好的接口。用户不需要记住margins=True怎么用,只需要调用get_region_pivot(df_clean),就能拿到地区销售额汇总表。这种“牺牲通用性,换取可读性和可维护性”的设计,正是它能在200行内完成全流程的根本原因。它不是Python教学代码,而是业务解决方案代码——就像一把瑞士军刀,每一把刃都针对一个具体任务打磨,而不是追求能切开所有东西。

3. 核心细节解析与实操要点:清洗、透视、报表生成的“魔鬼在细节”

3.1 数据清洗:三份CSV文件的合并逻辑与字段标准化陷阱

资源包提供的三份CSV文件(order.csvorder-14.1.csvorder-14.3.csv)并非简单的时间分片,而是来自不同数据源的异构快照。order.csv是主订单表,包含完整字段;order-14.1.csvorder-14.3.csv则是补充表,字段更少,但包含了主表缺失的优惠类型配送状态。很多新手第一步就读取合并,结果得到一个充满NaN的混乱DataFrame。这里的第一个关键细节是:合并必须按业务主键,而非盲目pd.concat()我们定义业务主键为订单ID,但检查发现order-14.1.csv里的订单ID格式是ORD20230701001,而主表是20230701001,少了前缀。因此,清洗的第一步不是处理缺失值,而是统一主键格式:

# 在 1、超市销售数据分析.ipynb 中 def unify_order_id(df): """统一订单ID格式:去除前缀ORD,补零至12位""" df['订单ID'] = df['订单ID'].astype(str).str.replace('ORD', '').str.zfill(12) return df df_main = unify_order_id(pd.read_csv('order.csv')) df_supp1 = unify_order_id(pd.read_csv('order-14.1.csv')) df_supp2 = unify_order_id(pd.read_csv('order-14.3.csv'))

这个zfill(12)看似简单,却解决了后续所有关联的基础。第二个陷阱是字段类型错乱。order-14.3.csv里的实付金额列,由于导出时Excel自动格式化,部分数值被存成了字符串"¥128.00"。如果直接pd.to_numeric(),会报错。我们的处理是先用正则清洗:df['实付金额'] = df['实付金额'].str.replace(r'[¥,]', '', regex=True),再转换。第三个也是最容易被忽视的细节:时间字段的时区与精度。下单时间order.csv里是2023-07-01 14:30:22,但在order-14.1.csv里是2023/07/01 14:30,缺少秒级精度。pd.to_datetime()默认会把缺失的秒填为00,这没问题;但更要命的是,order-14.3.csv里的时间是2023-07-01T14:30:22+08:00,带时区信息。如果不处理,合并后dt.hour会因时区转换出错。解决方案是强制转为本地时区并去掉时区信息:pd.to_datetime(df['下单时间']).dt.tz_localize(None)。这些细节,文档里不会写,但实操中踩一次坑就要浪费半小时。所以我们在Notebook的清洗部分,每个关键步骤都加了# 【实操心得】注释,比如:

# 【实操心得】订单ID格式不一致是跨表合并最大雷区!务必先统一再merge。 # 若跳过此步直接pd.concat(),会导致重复订单、关联失败、透视结果翻倍。 df_merged = pd.merge(df_main, df_supp1, on='订单ID', how='left') df_clean = pd.merge(df_merged, df_supp2, on='订单ID', how='left')

3.2 多维透视分析:从“能算”到“算得准”的四个业务维度设计

透视分析不是pd.pivot_table()一贴了事,核心在于维度设计必须匹配业务决策链条。这个包预设了四个黄金维度,每个都经过真实业务验证:

  1. 地区维度(省-市两级穿透)
    不是简单按收货地区原始值透视,而是先构建地理层级映射表。我们内置了一个region_mapping.csv(虽未在目录树列出,但代码里有硬编码字典),把"杭州市西湖区"映射到"浙江省-杭州市""深圳市南山区"映射到"广东省-深圳市"。透视时用index='省级地区'columns='市级地区',生成一个省为行、市为列的矩阵,方便区域经理一眼看出“浙江省内,杭州和宁波谁更强”。

  2. 品类维度(大类-小类双层钻取)
    商品大类如生鲜粮油日化,小类如生鲜-蔬菜生鲜-水果。透视时用pd.crosstab()生成交叉频次表,再结合销售额加权,得到各小类占大类销售额比重。这个比重比绝对值更有决策意义——比如生鲜大类总销售额下降5%,但生鲜-水果小类占比从30%升到45%,说明问题出在蔬菜供应链,而非整体需求萎缩。

  3. 时间维度(三周期嵌套:年-月 / 星期几 / 小时)
    这是区别于普通分析的关键。我们不只做月度汇总,而是把下单时间解析为三个独立列:年-月2023-07)、星期几0=周一)、小时14)。然后分别做透视:年-月看趋势,星期几看周末效应(验证“周末订单量是平日1.8倍”的假设),小时看高峰时段(实测发现11:00-13:0017:00-19:00是双高峰)。更妙的是,这三个维度可以组合,比如pivot_table(index='星期几', columns='小时', values='订单数', aggfunc='sum'),直接生成一张7×24的热力图,清晰显示“周三下午15点”是全年最低谷,“周六晚上18点”是全年最高峰。

  4. 门店维度(单店效能与区域协同)
    门店编码M00001M00012共12家。透视时不仅算单店销售额,还计算单店日均订单量(用订单数 / 销售天数)、客单价实付金额 / 订单数)、连带率商品数量 / 订单数)。这些指标合成一个门店健康度评分(日均订单量排名 * 0.4 + 客单价排名 * 0.3 + 连带率排名 * 0.3),分数越高门店运营越健康。这个评分被直接用在HTML报表的“门店TOP5”榜单里,让管理者无需看原始数据,一眼锁定标杆和洼地。

提示:所有透视表都设置了margins=True,自动添加All行和All列,方便快速看总量。但要注意,All行的客单价不是所有订单的平均值,而是总销售额 / 总订单数,这才是业务上正确的“平均客单价”。

3.3 HTML报表生成:交互图表背后的“三明治”结构设计

2、超市销售数据自动化报表.ipynb生成的HTML报告,表面看是几张漂亮图表,底层却是精心设计的“三明治”结构:底层是Plotly生成的JavaScript图表代码,中层是Jinja2模板定义的HTML骨架与业务文案,顶层是Notebook注入的动态变量。理解这个结构,是你能自主修改报表的关键。

首先,Plotly图表的创建严格遵循“一个图表,一个函数”原则。比如地区销售额柱状图:

def create_region_bar(df_pivot): """创建地区销售额柱状图""" fig = px.bar( df_pivot.reset_index(), x='地区', y='实付金额', title='📈 各地区销售额分布(TOP5)', labels={'实付金额': '销售额(元)', '地区': '地区'}, color='实付金额', color_continuous_scale='Blues' ) fig.update_layout(height=400, margin=dict(l=20, r=20, t=60, b=20)) return fig

注意title里用了📈符号——这不是装饰,而是为了让非技术人员一眼识别图表类型。所有图表函数返回的都是plotly.graph_objects.Figure对象,这是Jinja2能消费的唯一格式。

其次,Jinja2模板report_template.html的结构是模块化的。它被分成五个<section>区块,每个区块对应一个分析维度,且预留了“业务解读”插槽:

<section id="region-analysis"> <h2>📍 地区销售分析</h2> <!-- 【业务解读】华东区贡献了总销售额的62%,其中浙江、江苏两省占华东区的78% --> <div class="chart-container"> {{ fig_region | safe }} </div> </section>

这里的<!-- 【业务解读】... -->是硬编码的提示,告诉使用者:这里应该填写你自己的业务洞察,而不是让模型生成。模板里没有AI味的“综上所述”,只有具体的、可验证的陈述。

最后,Notebook2的注入逻辑是原子化的。它不把整个df_clean传进去,而是只传计算好的变量:

# 报表元数据 report_data = { 'report_date': datetime.now().strftime('%Y年%m月%d日'), 'total_orders': len(df_clean), 'total_sales': f"¥{df_clean['实付金额'].sum():,.0f}", 'top_region': df_pivot_region.index[0], # TOP1地区 'top_category': df_pivot_category.index[0], # TOP1品类 # 图表对象 'fig_region': fig_region.to_html(full_html=False, include_plotlyjs='cdn'), 'fig_category': fig_category.to_html(full_html=False, include_plotlyjs='cdn'), # ... 其他图表 }

然后用template.render(**report_data)一次性注入。这种设计保证了模板的纯净性——它只负责“怎么展示”,不负责“展示什么内容”,内容由Notebook严格计算后喂给它。当你想增加“退货率分析”时,只需在Notebook2里计算return_rate = df_clean['退货标记'].sum() / len(df_clean),在模板里加一行退货率:{{ return_rate|round(4)*100 }}%,再加一个图表函数,三步完成,绝不污染现有逻辑。

4. 实操过程与核心环节实现:从零开始跑通全流程的逐行指南

4.1 环境搭建:为什么推荐conda而非pip?一个被忽略的依赖地狱

虽然说明文档里写了pip install -r requirements.txt,但实操中我强烈建议你用conda创建独立环境。原因只有一个:Plotly的渲染后端依赖kaleido,而kaleido在Windows上用pip安装常因Visual Studio编译器缺失失败。conda能直接安装预编译的二进制包,一步到位。以下是我在Windows 11、macOS Sonoma、Ubuntu 22.04上都验证过的命令:

# 创建名为supermarket的环境,指定Python 3.9(兼容性最好) conda create -n supermarket python=3.9 # 激活环境 conda activate supermarket # 用conda安装核心科学计算库(更快、更稳) conda install pandas numpy jupyter plotly # 用pip安装Jinja2和pdfkit(conda仓库版本旧) pip install Jinja2 pdfkit # 【关键】安装wkhtmltopdf(pdfkit依赖的底层引擎) # Windows:下载exe安装包 https://wkhtmltopdf.org/downloads.html,勾选“Add to PATH” # macOS:brew install wkhtmltopdf # Ubuntu:sudo apt-get install wkhtmltopdf

注意:requirements.txt里写的plotly==5.18.0是有意为之。新版Plotly(6.x)移除了to_html()include_plotlyjs='cdn'选项,改为强制内联JS,导致HTML文件体积暴涨至5MB+,加载极慢。5.18.0是最后一个支持CDN模式的稳定版,我们锁死它,就是为了保证生成的HTML文件小于800KB,双击秒开。

环境激活后,验证是否成功:

# 在终端运行 jupyter notebook

然后在浏览器打开http://localhost:8888,新建一个Notebook,输入:

import pandas as pd import plotly.express as px print("✅ 环境验证通过")

如果没报错,恭喜,你已越过最大的门槛。很多同学卡在这一步,反复重装,其实是没意识到conda和pip的分工:conda管底层依赖(C++库、编译器),pip管纯Python包。混用会导致冲突。

4.2 运行第一个Notebook:数据清洗的“七步通关”详解

打开1、超市销售数据分析.ipynb,按Shift+Enter逐单元格运行。以下是每个关键步骤的深度解析,不只是“做什么”,更是“为什么这么做”:

Step 1:读取与初步探查
代码:df_main = pd.read_csv('order.csv', encoding='utf-8')
【为什么】指定encoding='utf-8'而非默认'gbk',因为order-14.3.csv是UTF-8编码,混合读取会报UnicodeDecodeError。探查时重点看df_main.info()non-null count,确认收货地区有12%缺失,优惠类型有35%缺失——这决定了后续清洗策略。

Step 2:主键统一与合并
代码:df_merged = pd.merge(df_main, df_supp1, on='订单ID', how='left')
【为什么】用how='left',确保主表所有订单都在,补充表缺失的字段为NaN,而不是丢弃订单。合并后立刻检查df_merged['订单ID'].duplicated().sum(),应为0,否则说明主键不唯一,需排查数据源。

Step 3:时间字段解析
代码:df['年-月'] = df['下单时间'].dt.to_period('M')
【为什么】to_period('M')生成的是Period类型,不是字符串。它的好处是:排序时2023-06永远在2023-07之前,不会出现字符串排序的2023-12023-10之前的错误;且能直接用于时间序列分析,比如df.groupby('年-月')['实付金额'].sum().plot()

Step 4:地区标准化
代码:df['省级地区'] = df['收货地区'].map(region_map).fillna('未知省份')
【为什么】map()apply(lambda x: ...)快5倍以上,且fillna()放在最后,确保所有映射失败的都归为一类,避免分散的“未知”污染分析。

Step 5:缺失值处理
代码:df['优惠类型'].fillna('无优惠', inplace=True)
【为什么】不填'Unknown'而填'无优惠',因为业务上“没填优惠”大概率就是“没用优惠”,填'无优惠'更符合业务直觉,报表里显示“无优惠占比85%”比“Unknown占比85%”更有意义。

Step 6:关键指标派生
代码:df['客单价'] = df['实付金额'] / df['订单数']
【为什么】这里订单数是每行一个订单,所以是df['实付金额'] / 1,但代码写成/ df['订单数']是为了未来扩展——如果数据源改为订单明细表(一行一商品),订单数列就代表该订单的商品数量,公式依然成立。

Step 7:透视表生成与保存
代码:pivot_region = get_region_pivot(df_clean)
【为什么】get_region_pivot()函数内部有pivot_region = pivot_region.sort_values('实付金额', ascending=False).head(5),强制取TOP5。这是业务硬需求:报表只展示最重要的5个地区,避免信息过载。生成的pivot_region会被pickle.dump()保存为pivot_cache.pkl,供第二个Notebook直接读取,避免重复计算。

运行完这七个步骤,你会在当前目录看到pivot_cache.pkldf_clean.pkl两个文件。这就是第一个Notebook的全部产出——干净的数据和预计算的透视表。此时,你可以关掉这个Notebook,完全不用管它,进入下一步。

4.3 运行第二个Notebook:HTML报表生成的“四步渲染”实录

打开2、超市销售数据自动化报表.ipynb,同样逐单元格运行。这是整个流程的高潮,也是最容易出错的环节:

Step 1:加载清洗结果
代码:df_clean = pd.read_pickle('df_clean.pkl')
【实操心得】如果报错FileNotFoundError,说明第一个Notebook没运行完,或者路径不对。别急着重跑,先检查当前工作目录:import os; print(os.getcwd()),确保它指向资源包根目录(即有order.csv的那个文件夹)。

Step 2:生成所有图表
代码:fig_region = create_region_bar(pivot_region)
【为什么】所有create_*函数都带title参数,且标题以emoji开头(📈📅📍)。这不是花哨,而是降低认知负荷——人在快速浏览HTML时,图标比文字更快被大脑识别。实测表明,带emoji的标题能让管理者停留时间提升40%。

Step 3:渲染HTML
代码:html_string = template.render(**report_data)
【关键检查点】运行这行后,立刻打印len(html_string),正常应在750000~850000之间(约750KB)。如果小于500KB,说明fig_*.to_html()没成功,可能是Plotly版本不对;如果大于2MB,说明include_plotlyjs='cdn'失效,JS被内联了。

Step 4:保存并打开
代码:with open('超市销售周报_自动生成.html', 'w', encoding='utf-8') as f: f.write(html_string)
【终极验证】运行完这行,不要在Notebook里点“显示”,而是去文件浏览器,找到刚生成的超市销售周报_自动生成.html双击用系统默认浏览器打开。如果看到标题、图表、数据全部正常,且鼠标悬停在柱子上能显示数值,点击图表能缩放,恭喜,你已100%跑通。

提示:生成的HTML文件是自包含的,所有Plotly JS都通过CDN加载(<script src="https://cdn.plot.ly/plotly-2.24.1.min.js"></script>),所以首次打开需要联网。但CDN是公共地址,国内访问极快,且JS文件只加载一次,后续打开秒开。如果真有离线需求,把include_plotlyjs='cdn'改成include_plotlyjs=True,JS会内联,文件变大但完全离线。

5. 常见问题与排查技巧实录:那些文档里不会写的“血泪经验”

5.1 文件路径错误:为什么总是报“FileNotFoundError”?

这是新手最高频的问题,占所有咨询的70%。根本原因不是代码错,而是对Jupyter工作目录的理解偏差。Jupyter Notebook的当前工作目录(os.getcwd()不是Notebook文件所在目录,而是你启动jupyter notebook命令时所在的目录。比如,你解压资源包到D:\projects\supermarket,然后在D:\目录下打开了cmd,输入jupyter notebook,那么所有Notebook的工作目录都是D:\,而不是D:\projects\supermarket

【排查三步法】
1. 在Notebook第一个单元格运行:

import os print("当前工作目录:", os.getcwd()) print("文件列表:", os.listdir('.'))
  1. 如果order.csv不在输出的文件列表里,说明路径错了。
  2. 解决方案有二:
    -推荐:在资源包根目录(有order.csv的文件夹)里,按住Shift右键,选择“在此处打开Powershell窗口”,再输入jupyter notebook
    -备选:在Notebook里手动切换:os.chdir(r'D:\projects\supermarket')(Windows)或os.chdir('/Users/xxx/projects/supermarket')(Mac/Linux)。

注意:os.chdir()只对当前Notebook生效,重启内核后需重设。所以最佳实践永远是“在哪启动,就在哪工作”。

5.2 图表不显示:Plotly的“CDN加载失败”真相

有时HTML文件双击打开,页面一片空白,F12看控制台报错:Failed to load resource: net::ERR_CONNECTION_REFUSED。这不是你的网络问题,而是Plotly的CDN地址被本地防火墙或安全软件拦截了。国内用户偶尔会遇到。

【速查与解决】
1. 打开生成的HTML文件,Ctrl+U查看源码,搜索plotly-,确认JS地址是https://cdn.plot.ly/plotly-2.24.1.min.js
2. 复制这个URL,粘贴到浏览器地址栏访问。如果打不开,说明CDN被拦。
3.终极解决方案:修改2、超市销售数据自动化报表.ipynb中所有to_html()调用,把include_plotlyjs='cdn'换成include_plotlyjs=True。虽然文件变大,但100%可靠。
4. 【隐藏技巧】如果只想临时测试,可以把CDN地址换成国内镜像:include_plotlyjs='https://cdnjs.cloudflare.com/ajax/libs/plotly.js/2.24.1/plotly.min.js'(cdnjs在国内访问稳定)。

5.3 透视结果异常:为什么“华东区”销售额是负数?

这通常发生在实付金额字段里混入了退款订单,而退款金额被记为负值(如-128.00)。业务上,销售额应为正向收入,退款应单独统计。但原始数据没区分。

【诊断命令】
在第一个Notebook里运行:

print("实付金额统计:") print(df_clean['实付金额'].describe()) print("\n负值订单详情:") print(df_clean[df_clean['实付金额'] < 0][['订单ID', '实付金额', '下单时间']].head())

【业务决策】
- 如果负值是少量退款,可在清洗阶段过滤:df_clean = df_clean[df_clean['实付金额'] >= 0]
- 如果负值是大量“逆向物流”订单,应新增交易类型字段(正向销售/逆向退款),并在透视时分开展示。
-绝不abs()函数强行转正,那会扭曲业务实质。

5.4 报表中文乱码:为什么标题显示“?????”

这是Windows系统的经典坑。Jinja2模板默认用utf-8编码保存HTML,但Windows记事本等老旧工具可能用gbk打开,显示乱码。但这不影响浏览器——现代浏览器(Chrome/Firefox/Edge)默认按utf-8解析HTML。

【验证方法】
1. 用VS Code打开生成的HTML文件,右下角看编码显示,应为UTF-8
2. 如果是GBK,点击右下角编码名,选择Reopen with EncodingUTF-8,再保存。
3.永久解决:在Notebook的保存代码里,强制指定编码:

with open('report.html', 'w', encoding='utf-8') as f: f.write(html_string)

5.5 扩展性问题:如何快速改成“服装销售分析”?

这是大家最关心的实战问题。改动仅需三处,全部在1、超市销售数据分析.ipynb里:

  1. 字段映射:把收货地区换成收货省份,把商品大类换成服装品类男装/女装/童装),把下单时间换成下单日期(去掉小时,因为服装下单无强时段性)。
  2. 清洗逻辑:删除小时解析,增加尺码字段标准化("M""Medium""L""Large")。
  3. 透视维度:把get_region_pivot()改成get_province_pivot(),把index'地区'换成'收货省份';新增get_size_pivot(),分析尺码客单价的关系。

最后分享一个小技巧:所有业务字段名(如'实付金额''订单ID')都定义在Notebook开头的CONFIG字典里。改一个地方,全局生效。这才是专业级代码的写法。

6. 这个项目教会我的:关于“数据分析作品集”的三个残酷真相

跑通这个超市销售分析包,只是第一步。真正让它成为你简历上闪光点的,是你如何用它讲好一个业务故事。在我辅导的上百份作品集中,我发现三个被普遍忽视的真相:

第一个真相:HR和业务面试官根本不看你的代码行数,他们只看你解决了什么问题。你在README里写“使用Pandas进行数据清洗”,不如直接写“发现原始数据中12%的订单缺失地区信息,通过关联物流单号补全,使区域分析覆盖率从88%提升至100%”。后者让一个技术动作瞬间有了业务重量。

第二个真相:最好的可视化不是最炫的,而是最不容误解的。这个包里所有的图表,都刻意避免3D效果、渐变色、复杂图例。柱状图用单色,折线图用粗线,热力图用蓝白渐变(色盲友好)。因为真正的业务场景里,老板不会给你30秒解释“这个颜色代表什么”,他要的是3秒内抓住重点。所以我在HTML报表的每个图表下方,都加了一行小字结论:“华东区销售额占比62%,较上月提升3个百分点”,把分析结果直接翻译成人话。

第三个真相:作品集的价值不在于你做了什么,而在于你思考过什么没做。这个包没有做机器学习预测,没有接实时API,没有建数据仓库。为什么?因为在超市销售这个场景里,80%的管理决策靠的是准确、及时、易懂的描述性分析。预测下周销量固然酷,但知道“上周水果品类退货率高达25%,主要集中在草莓单品”更能立刻止损。我在项目文档里专门加了一节《为什么不做预测模型?》,坦诚说明:当前数据粒度(只有订单汇总,无库存、天气、竞品数据)、业务成熟度(连基础复盘都没跑顺)、团队能力(店长只会看Excel)都不支持预测落地。这种清醒的克制,反而比强行堆砌技术更能体现专业素养。

所以,当你把这个包放进作品集时,请不要只放GitHub链接。在项目介绍里,用一句话说清:“这是一个为中小型商超设计的轻量化销售复盘工具,帮助店长在5分钟内生成带交互图表的HTML周报,聚焦解决‘哪个区域卖得最好’、‘什么品类在亏损’、‘什么时候该补货’这三个高频问题。” 然后,附上你生成的2、超市销售数据自动化报表.html的截图,重点圈出“门店健康度评分TOP3”和“小时销售热力图”这两个最具业务洞察力的部分。最后,加一句:“代码开源,欢迎PR——特别是你所在行业的字段映射表,我们一起把它做成零售业的通用分析模板。” 这样的作品集,才有温度,有观点,有延展性。它不再是一个冰冷的代码包,而是一个你与真实世界对话的入口。

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

简介:直接跑通超市销售分析全流程的轻量级Python工具包,用真实订单CSV文件(order.csv、order-14.1.csv、order-14.3.csv)做基础数据源。两个Jupyter Notebook分工明确:第一个负责数据清洗、缺失值处理、字段标准化,并支持按地区、商品品类、销售日期、门店等多维度生成动态透视表,快速算出销售额、订单数、平均客单价等核心指标;第二个专注自动化报表输出,一键运行即可生成带交互式图表(柱状图、折线图、热力图)的HTML报告,已预渲染好2、超市销售数据自动化报表.html,双击浏览器直接打开查看。全部代码控制在200行内,变量命名清晰,关键步骤附中文注释,新手照着说明.txt和使用说明(含常用包及安装方法).zip就能装好环境、跑通结果。不需要额外配置或网络请求,离线可用。适合学生交课程作业、投简历时展示数据分析能力,也适合作为小型商超日常销售复盘的轻量化模板。


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

http://www.jsqmd.com/news/1143217/

相关文章:

  • 系统分析师备考系列目录
  • Matlab水体识别工具包:9层CNN自动分割遥感图,输出二值掩膜(含标注数据+可运行工程)
  • Wireshark界面全解析:从新手到高效网络分析
  • curious
  • 深入剖析ComfyUI-Easy-Use transformer_options错误的终极指南
  • AI自主攻击勒索300万,真相让人后背发凉!普通人避坑3招自保
  • 2026-07-06 GitHub 热点项目精选
  • DDrawCompat终极指南:在Windows 10/11上完美运行经典老游戏的秘密武器
  • 手机号码定位系统:3分钟快速查询地理位置终极指南
  • 零配置浏览器自动化:Playwright CRX插件实现录制即代码
  • Wireshark与ngrok组合实战:构建远程调试与网络分析闭环
  • JUnit 5与TestNG深度对比:Java测试框架选型实战指南
  • 数据预处理避坑指南:5个常见错误与3个真实数据集上的性能影响分析
  • AI工具如何辅助评委精准筛选国自然资助项目
  • AI如何重塑API测试工作流:从Postman手动配置到智能生成的效率革命
  • Python爬虫实战:逆向瑞数6代动态Cookie生成机制
  • Electron 鸿蒙 PC 上点关闭就真退出了?我花了两天才把“最小化到托盘“做稳
  • 前端与后端性能优化实战:从代码分割到缓存策略的完整指南
  • 基于SSM的商铺租赁管理系统:技术栈、背景意义、核心代码与系统测试
  • 2026最新8款团队协作编程平台平替实测|知识库规范管理权威合集
  • 高精度ADC ADS127L11与PIC18F2550数据采集方案
  • 天翼云盘签到 - 青龙面板自动签到脚本
  • InvizCrypt:基于客户端加密的LaTeX安全协作方案解析
  • Playwright Stealth插件:绕过网站反爬虫检测的实战指南
  • 3分钟搞定:魔兽争霸III终极优化方案让你的经典游戏焕发新生
  • 终极英雄联盟辅助神器:Seraphine如何帮你轻松实现智能战绩查询与自动化操作
  • Java支付系统签名验证实战:从原理到可插拔框架设计
  • 我又发现了7个高质量App
  • 零样本平面图定位:基于几何基元的室内空间推理方法
  • Windows APK安装器完整教程:轻松在电脑上安装Android应用