尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

用Python自动生成预测分析表:Excel模板到zip打包实践

发布时间:2026/9/28 16:38:46

资讯中心
01
ARTICLE

用Python自动生成预测分析表:Excel模板到zip打包实践

用Python自动生成预测分析表:Excel模板到zip打包实践
简介针对编译原理课程中LL(1)预测分析表自动生成这一经典实验这份代码资源提供了一套完整可运行的C语言方案主要面向正在学习语法分析、需要动手验证FIRST集与FOLLOW集计算过程的本科生与自学者。程序支持输入文法并输出对应的预测分析表重点演示了集合迭代求解逻辑、表数据的组织方式等核心难点可帮助读者绕过手工推导易错的环节快速获得正确结果。压缩包共十二个文件包括一个C源文件、十一个文本文件文本中既有测试文法输入也有运行后的结果输出以及简要说明整体仅约十五千字节轻量且便于对比学习。目前已有九百六十七人学习下载使用者可结合代码与测试样例对照参考教材梳理预测分析表的构造流程也很适合在此基础上做扩展、修改或排错。1. 实现预测分析表的自动生成别再做每周一次的手工报表很多团队的预测分析表还停在「人肉流水线」周一早上从数据库拉数粘到 Excel 里套一个固定模板再用散点图趋势线或者简单的 Excel 函数估下个月数字最后压缩成 zip 发给业务群。整个过程两三个小时一半时间花在打开多个窗口来回复制粘贴。这个标题所指向的就是把这套手工流水线压成一条命令Python 读取历史数据按配置好的模型算出预测值写入提前做好的报表模板最后用 zipfile 打包成带日期的交付文件。做完之后每周只要双击一下或交给调度器预测分析表就能在几分钟内自动生成并归档。适合的人群很明确天天和销售、库存、流量数据打交道的报表工程师、数据运营和刚转数据分析的开发者。做这件事不需要大数据平台一台能跑 Python 的办公电脑就够。判断自己是否需要它可以看两个信号一是预测表的格式永远不变只是数字在变二是你经常因为忘记更新某个 sheet 或漏改单元格被问「这版是不是最新的」。下面我按自己落地这类任务的完整路径来讲从模型选型讲到 zip 打包最后给你几个调参和排毒的经验。2. 预测分析表自动生成的架构拆解数据源、预测模型与报表模板怎么选2.1 先定预测粒度日、周、月报决定模型复杂度常见错误是上来就套一个「先进模型」。预测分析表的粒度决定了数据量和波动形态也就决定了用什么模型。月度预测 48 个月的数据一共只有 48 个点用 Prophet 或 ARIMA 反而容易过度拟合日度预测有上千个点才有必要考虑季节性和趋势项。做架构决策我一般先问四件事预测输出是几个数字还是一张趋势表。我见过不少需求是「只要下个月的总量和环比」那就不需要做序列模型直接算增长率的加权平均都够用。数据有没有明显周期性。日度数据通常有周内周期周度数据可能有月度波动月度数据要看有没有年度同比。历史数据多长。少于 12 个月的历史不要碰季节分解连移动平均都可能算出让人笑话的结果。预测表是给人看还是给系统用。给人看要附置信区间或者至少说明上下浮动给系统用输出 JSON 对接接口会更省事Excel 只是留痕。这几件事定下来模型的复杂度基本就锁死了。我自己的经验内部运营周报用简单指数平滑加环比说明季度经营预测才上线性回归或者带季节项的策略。最开始不要追求模型的「聪明」先把流程跑起来预测表自动生成比预测精度提升一个百分点重要得多。2.2 模型选型线性回归、指数平滑还是 Prophet按数据量和数据形态选预测分析表里最终要落一个可解释的数字所以模型选型必须考虑「能解释」而不是「能算」。给业务方讲「这是 ARIMA(2,1,3) 的结果」远不如讲「这是过去三个月平均趋势加季节修正」来得有效。我的常规选择如下数据特征推荐模型输出解释实现成本数据平稳或近似线性样本 30 100 个线性回归趋势外推公式明确可解释性强Python sklearn 或直接用 numpy.polyfit有随机波动但无强季节月度数据指数平滑Holt / Holt-Winters参数少给出平滑系数即可讲清statsmodels 的 ETS日度数据、有周/月季节样本 300Prophet 或 SARIMA能拆出趋势、周季节、年度季节Prophet 安装较简单SARIMA 调参繁琐只需下一个点不想维护模型移动平均或加权平均谁都看得懂三行代码这里提醒一个新手友好的点先不要直接调 sktime 或 Prophet 的超参。预测分析表自动生成的核心矛盾是把报表稳定地发出去而不是把模型指标刷到 99。先用 sklearn 的 LinearRegression 或 statsmodels 的 SimpleExpSmoothing 跑通整条链路再回头换模型这样排障范围小很多。2.3 报表模板先行Excel 模板的单元格占位与动态写入预测表的最终样式如果每次都用代码从零画你会被边框、列宽、合并单元格折磨疯。我的做法是先在 Excel 里手工做好一个「模板文件」里面把表头、公式、样式全部定好只留下需要填数据的单元格留空或写上特殊占位符。模板放哪些内容第一行标题写明「XX 区域销售预测分析表」年份用占位符{year}。第二行是日期与生成时间生成时间用{gen_time}因为每次生成都要变。数据区预留三列预测值、置信下限、置信上限用浅色背景填充。最后一列留一个「说明」自动写入模型名称和样本量比如线性回归样本数 36方便业务方看的时候不必追问。附一个「历史数据」sheet把原始数据原样放过去这样万一预测和实际差得远别人可以自己在表格里查原因。用 openpyxl 加载模板、写入数值、保存为新文件再打包 zip。掌握这个顺序之后你会发现 Excel 的格式问题彻底和你无关了代码只负责计算和填值。3. 用 Python 把预测分析表自动生成跑通pandas、openpyxl 与 zipfile 的最小命令3.1 环境准备与流程主骨架假设你已经有一份历史数据放在data/sales.csv字段包含date和sales。自动生成预测分析表的整体流程分四步读数据 → 训练模型并预测 → 写入 Excel 模板 → 压缩为 zip。先建一个项目目录forecast_table/ ├── config.yaml # 参数配置路径、模型、预测天数 ├── template.xlsx # 手工做好的报表模板 ├── data/ # 原始数据目录 ├── output/ # 生成结果目录 └── auto_forecast.py # 主脚本当然也可以不用 yaml直接用 Python 里的字典但项目一旦要交接配置文件比改代码更安全。主骨架先写成这样import pandas as pd from statsmodels.tsa.holtwinters import ExponentialSmoothing from datetime import datetime, timedelta from openpyxl import load_workbook from openpyxl.utils.dataframe import dataframe_to_rows import zipfile import os def forecast_series(df, periods30): # 用指数平滑建模这里假设数据无强季节性先用加法趋势 model ExponentialSmoothing( df[sales], trendadd, seasonalNone, initialization_methodestimated ) fit model.fit() return fit.forecast(periods) def main(): df pd.read_csv(data/sales.csv, parse_dates[date]) df df.sort_values(date) forecast_values forecast_series(df, periods30) # 后续步骤写模板、打包 print(forecast_values.head()) if __name__ __main__: main()这段代码先把数据读进来并排序然后调用forecast_series做预测。ExponentialSmoothing是 statsmodels 里的经典指数平滑实现trendadd表示趋势项是加法方式适合销售数据这样绝对值波动不太大的场景initialization_methodestimated让模型自动估计初始状态避免你手填一个离谱的初值导致前几个预测点偏差很大。跑通这一段后再往下接「写表」和「打包」就顺理成章了。3.2 数据读取与预测计算参数怎么设才不翻车预测计算是整条链路里最容易「看似正常其实结果有问题」的地方。常见坑包括日期索引没有排序、缺失值直接让模型报错、以及预测天数远远超出历史长度导致置信区间爆宽。写代码时需要把边界条件亮出来def prepare_data(df, date_coldate, value_colsales): df df.copy() df[date_col] pd.to_datetime(df[date_col]) df df.sort_values(date_col) # 重采样到日缺失值填 0 或前向填充这里以日度销售为例 df df.resample(D, ondate_col).agg({value_col: sum}).reset_index() # 直接丢弃开头可能的空值行太多空值时建议告警 df df.dropna(subset[value_col]) return df注意resample(D)会把原始数据按天汇总如果有多个数据点落在同一天会求和。这一步对预测日程很重要如果你是周报应该改成W-MON否则模型看到的序列刻度是乱的。实际生产里我遇到过填了缺失值结果模型把 0 当成真实低值、预测出一串负数的翻车场景所以这里要先看数据形态再决定填充策略而不是一概fillna(0)。预测长度periods我通常设为「报表周期 × 2」比如预测未来 30 天就留 60 天的余量不我这里说的是模型预测的periods直接等于你要展示的天数即可多预测没有任何收益。真正要注意的是模型训练时如果数据全部用完就没有留出验证集我一般会留最后 7 天作为回测先算一遍预测误差再全量训练出正式数字。代码逻辑说明prepare_data内部不修改原始 DataFrame返回的是副本这能避免后续多次运行时被之前步骤污染。dropna是把数据开头可能的空行去干净因为指数平滑对前端的空值很敏感。3.3 写入 Excel 模板并生成预测分析表模板里我已经预留了从 B5 开始的预测值区域第一列填日期后面三列分别填预测值、下限、上限。用 openpyxl 写入时注意两点先load_workbook不要新建 workbook写入后必须save成新文件不要覆盖模板。def fill_template(template_path, output_path, forecast_df): wb load_workbook(template_path) ws wb[预测] # 假设模板里有一个名为“预测”的sheet # 从模板中约定的起始行写入 start_row 5 for i, row in enumerate(forecast_df.itertuples(indexFalse)): # row 是 (date, forecast, lower, upper) ws.cell(rowstart_row i, column2, valuerow[0]) # 预测值 ws.cell(rowstart_row i, column3, valuerow[1]) # 下限 ws.cell(rowstart_row i, column4, valuerow[2]) # 上限 # 写入生成时间到固定单元格 ws[B2] datetime.now().strftime(%Y-%m-%d %H:%M) wb.save(output_path) return output_path这里用ws.cell(row, column, value)而不是ws[B5]这种坐标硬编码是为了循环方便。itertuples 返回的元组顺序要和 forecast_df 的列顺序一致所以在前面构造 forecast_df 时我会显式给 date、forecast、lower、upper 四列排序。模板里的固定单元格B2写入生成时间B3可以再用一行写模型名称。参数说明start_row5是我模板里数据起始行如果你的模板表头占了三行就改成 4 或 6。建议把start_row也提到 config.yaml因为领导随时可能要你在表头加一行「比率】那样模板改一格代码不用动。3.4 用 zipfile 打包交付别踩文件句柄的坑生成的output/销售预测_2024-03-15.xlsx不是最终交付物。为了保留原始数据、模板和预测结果通常要打成一个 zip。zipfile 是标准库但很容易犯「文件没关闭就压缩」的错或者踩 zip 内文件名带路径导致解压出现一堆嵌套目录的坑。def build_zip(zip_name, file_list): # 用 with 确保列表里的文件写入后自动关闭 with zipfile.ZipFile(zip_name, w, zipfile.ZIP_DEFLATED) as zf: for file in file_list: if os.path.isfile(file): # arcname 只取文件名避免压缩时带上 output 目录层级 zf.write(file, arcnameos.path.basename(file)) return zip_name代码逻辑说明ZIP_DEFLATED是压缩算法对 Excel 文件能有一定压缩效果虽然表格本身已经不小但多个 csv 和 xlsx 打在一起能减少邮件附件体积。arcnameos.path.basename(file)是防坑关键如果不指定arcnamezip 内会出现output/2024-...xlsx接收方解压时会多套一层目录业务方马上会觉得你交付不专业。执行完脚本后输出目录里会有一个类似预测分析表_20240315.zip的文件里面至少包含预测表、历史数据 csv。这个 zip 就是自动生成闭环的最终产物。4. 自动生成落地定时调度、参数配置与 zip 包命名规范4.1 用配置文件管住关键参数预测分析表最大的维护成本不是代码而是参数。业务方某天说「以后周五下午三点要看到周报」你不能改代码只能改配置。我的做法是引入config.yaml读完再进主程序data: input_path: data/sales.csv date_col: date value_col: sales history_weeks: 12 model: type: exponential_smoothing trend: add seasonal_period: 7 report: template_path: template.xlsx output_prefix: 销售预测分析表 start_row: 5 zip: enabled: true keep_latest: 10在 Python 里用yaml.safe_load读取然后传给各个函数。这样做的另一个好处是换数据源时你只需要改input_path不用动任何一行模型代码。注意config.yaml里的history_weeks可以控制训练窗口我通常只拿最近 12 周做训练不是全部都喂给模型因为更远的历史对短期预测往往是噪声。4.2 在 Windows 和 Linux 上做定时任务这一节是很多人把脚本写好之后卡住的点。用 Python 脚本已经跑出功能但如何定时执行、如何保证执行环境正确往往比写脚本本身更闹心。这里分平台说明最常见的做法。在 Windows 上我一般用「任务计划程序」建一个基本任务触发器选每周一 08:00操作选「启动程序」程序填python.exe的绝对路径参数填脚本路径。注意工作目录容易踩坑脚本里的data/sales.csv是相对路径如果任务计划里的「起始于」没填项目目录Python 会找不到文件。最好的办法是在脚本开头把所有相对路径基于os.path.dirname(__file__)拼接这样无论在哪里执行都不会出错。在 Linux 上用 crontab0 8 * * 1 cd /opt/forecast /usr/local/bin/python auto_forecast.py logs/forecast.log 21这条命令每周一 08:00 执行先进入项目目录再调用绝对路径的 Python 解释器避免系统自带 python 版本不对的问题。日志重定向很重要因为自动生成过程中任何报错都要有迹可循否则周三发现没生成就晚了。crontab 里环境变量是精简的所以 Python 如果是虚拟环境一定要用虚拟环境里的解释器全路径。我自己的教训是第一次跑 crontab 前先手动执行一次然后连续观察两天确认 zip 文件时间戳每天都能更新。定时任务失败的最大原因不是脚本逻辑而是环境变量和路径。4.3 zip 包命名规范与保留最近几份的清理策略自动生成的 zip 文件如果不控制命名和保留数量过三个月会铺满整个磁盘。我建议的命名格式是{output_prefix}_{date}.zip例如销售预测分析表_20240315.zip日期统一用年月日。这样按文件名排序就是时间排序。清理策略用保守的「保留最近 N 份」def clean_old_output(output_dir, prefix, keep10): files [f for f in os.listdir(output_dir) if f.startswith(prefix) and f.endswith(.zip)] if len(files) keep: files.sort() # 按日期排序因为文件名里是日期 for f in files[:-keep]: os.remove(os.path.join(output_dir, f))注意files.sort()对销售预测分析表_20240315.zip这种命名生效因为中文前缀相同剩余部分就是可排序日期。如果你的业务要求保留月度归档就把keep调成 36 而不是 10。这是拿空间换安全比较省心。5. 预测分析表自动生成的避坑指南常见问题与排查5.1 模板里写好的公式打开生成文件后变成 0 或丢失现象我用 openpyxl 加载 template.xlsx 并保存结果模板里的 SUM、AVERAGE 公式全部没了或者生成的文件打开是所有公式单元格显示 0。原因openpyxl 默认加载 workbooks 时公式单元格存的是公式字符串但如果保存时不保留公式或者 Excel 没有重算用户打开后可能看不到结果甚至某些版本会直接把公式丢掉。解决我的对策是尽可能把计算逻辑放 Python 里不要放 Excel 模板里。比如预测值合计这一项在写模板时先算好再作为常量写入。如果必须要保留 Excel 公式可以用 openpyxl 的write_onlyFalse加载并保留公式单元格或者干脆把模板改成「数据 公式」混合生成后让 Excel 打开触发重算。更稳妥的做法用 LibreOffice 无头模式打开并转换不过这个方案引入额外依赖除非业务方硬性要求否则我不用。5.2 生成的 Excel 里中文乱码或字体变形现象在模板里输入中文没问题但 Python 写入数据后打开乱码或者某些字显示成方框。原因模板文件本身的编码没问题大多是中文字体在深色背景或默认字体设置下被降级另一个可能是原始 csv 编码是 GBK被 pandas 按 UTF-8 读成乱码。解决读 CSV 时显式指定编码pd.read_csv(data/sales.csv, encodinggbk)或encodingutf-8-sig。Excel 字体问题可以直接在代码里统一设置from openpyxl.styles import Font ws[B2].font Font(name微软雅黑, size10)尽量在制作模板时就用系统默认字体不要在代码里频繁改字因为每次生成都会重新覆盖样式。5.3 zip 包损坏或者提示「文件被占用」现象脚本执行成功但生成的 zip 解压时提示文件损坏有时报PermissionError说文件正被另一个进程使用。原因最常见的是把文件写入 zip 时还留着 Excel 的打开句柄尤其在 Windows 上用 pandas 打开过但没有关闭 ExcelWriter 会造成文件锁。或者zipfile.ZipFile在循环里没有用 with文件没有正常 flush 完毕。解决严格用with open(...)和with zipfile.ZipFile(...)嵌套并且生成 zip 前确认所有 Excel 文件已关闭。如果是在 Windows 上后台跑排查是否有 Excel 进程残留。我这里有过一次血泪在脚本里调用了df.to_excel()忘了有 Excel 占用后面 zip 了半截文件出来解压直接报错。从那以后我统一用 openpyxl 写完再压缩。5.4 预测结果全是一样的值或一直下降现象预测结果变成一条水平线或者直接下降到底一看就是错的。原因指数平滑模型参数没配好尤其trendadd却把季节性设成None模型只学了整体衰减趋势另一个原因是历史数据里存在大量 0 值或缺失模型被带偏。解决先画出历史数据折线图肉眼确认趋势。用statsmodels的plot也可以但更省事是打印最近 10 个值和预测前 10 个值对比。如果确实有趋势把trend改成mul乘法趋势试试并且把seasonal_period设为 7 或 12 看看是否引入周期。每次调参只改一个参数不要同时改两个否则你永远不知道是哪个救了你。5.5 定时任务跑了但文件没有更新现象Windows 任务计划程序里显示上次运行成功但 output 目录里没有新文件。原因多半是工作目录问题脚本用了相对路径读data/sales.csv但计划程序的工作目录不是项目目录导致找不到文件但 Python 没有报错不找不到文件肯定会报错但如果脚本一开始就os.chdir(objdir)失败被 try 吞掉就会静默退出。解决在脚本第一行就固定项目根目录比如ROOT_DIR os.path.dirname(os.path.abspath(__file__))然后把所有路径基于 ROOT_DIR 拼接。定时任务里的「起始于」填这个绝对路径。加日志输出每次执行往logs/写一行包含时间戳的日志并print(os.getcwd())这样失败时能立刻定位。6. 把预测分析表做得更可靠结果校验、异常告警与增量预测的技巧自动化生成只是起点真正让人愿意用这套方案的是预测结果的可靠性。我通常会在生成 zip 前加两个校验步骤。第一个是回测校验从训练数据末尾切出 7 天作为测试集用同样的模型参数预测这 7 天计算平均绝对百分比误差MAPE。如果 MAPE 大于 30%我不会直接发出去而是在「说明」列写上一句「本周预测波动较大仅供参考」。这比代码自动发出去再被业务质问要从容得多。def calc_mape(actual, forecast): actual np.asarray(actual, dtypefloat) forecast np.asarray(forecast, dtypefloat) mask actual ! 0 return np.mean(np.abs(actual[mask] - forecast[mask]) / np.abs(actual[mask])) * 100第二个是极值检查生成预测序列后判断预测值是否落在历史值的最小值和最大值的合理外扩区间内。比如历史最低是 100结果预测出一个 50除非有明确业务原因否则代码里就检查出来并告警。我的教训是有一年双十一前用简单线性回归外推没检查极值预测值冲到历史两倍业务方看到直接撤回后来我就在脚本里加了上下限约束超限时自动改为用过去三年同期的均值至少数字不会离谱。增量预测方面我不建议每次全量训练。如果销售数据每天追加可以每周做一次全量重训其余每日只滚动预测未来 7 天。滚动方式很简单把历史数据窗口每次后移一天重新训练并取第一天的预测值。这样做产出的预测表既有连续性又能跟随最近变化。存档时zip 里的历史数据 sheet 保留最近 90 天即可避免文件体积膨胀。这些技巧让「自动生成」不只是代替复制粘贴而成为一个稳定的小型数据产品。我做这类任务到现在最重要的习惯是每版生成的 zip 都保留最近至少两份防止新模型跑出坏结果时没有后悔药可吃。希望这套路径能帮到你少走我当年那些坑。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。