这个目录是可复制到生产环境的独立项目。它从数据库读取江湾化学楼和四个校区的日用电数据,训练模型并保存参数;后续推理直接加载已保存参数,把预测结果写回对应的固定结果表。
scripts/train.py:训练入口,生成artifacts/model.joblib、artifacts/preprocess.joblib、artifacts/metrics.json和测试集预测结果。scripts/predict.py:推理入口,加载训练参数,对未来日期滚动预测。scripts/run_pipeline.py:生产调度入口,按“训练 -> 推理”的顺序运行化学楼、四校区或全部模型。scripts/verify_db_write.py:受控写库验收入口,显式确认后执行 1 天推理写库并回查目标表。scripts/deploy_acceptance.py:客户现场部署验收入口,自动训练、推理、写库回查,并与报告指标做容差比较。src/database.py:数据库查询、结果表创建、upsert。src/cleaning.py:零值、异常值清洗和同星期均值填充。src/features.py:时间、滞后、温度、校历特征计算;训练和推理时优先实时同步外部特征。src/external_features.py:Open-Meteo 天气 API 拉取和本地温度缓存更新。src/modeling.py:LASSO、RandomForest、GradientBoosting、MLP 和 Ensemble。data/:离线温度和校历特征源。docs/chemical_building_model.md:模型搭建和当前效果说明。
必须从 submission 目录运行命令,或使用 scripts/*.py 入口运行。模型文件中的 pickle/joblib 对象引用了 src.* 模块;如果在仓库根目录直接裸 joblib.load("submission/artifacts/model.joblib"),可能因找不到 src 包而失败。
- 安装 Python 3.9 或更高版本。
- 进入
submission目录并安装依赖:
cd submission
pip install -r requirements.txt- 配置数据库连接:
cp .env.example .env然后编辑 .env 中的 FD_DB_PASSWORD 等变量。也可以直接在生产环境设置同名环境变量。
- 训练一次模型:
python scripts/train.py训练会读取 phase_ll.ec_building_energy_copy1,按 name=江湾化学楼、campus_name=江湾校区、time_type=日 过滤数据,并把测试集预测写入 phase_ll.elecforcast_chemi。
训练期间外部特征会自动同步:
- 校历:优先查询
teach_etl.t_szls_zhjx_xnxqxx_xjwxt,并更新data/academic_calendar.csv缓存;查库失败时回退本地 CSV。 - 温度:优先调用 Open-Meteo API,并更新
data/temperature_yangpu.csv缓存;API 失败时回退本地 CSV。
- 后续推理:
python scripts/predict.py --horizon 30推理会加载 artifacts/model.joblib,从数据库读取最新历史数据,逐日滚动预测未来 30 天,并 upsert 到同一张结果表。
推理也会在开始时一次性同步当前历史日期到预测 horizon 末尾的温度和校历特征,然后逐日滚动生成预测。
- 生产调度入口:训练完成后立即调用推理,并写入数据库。
python scripts/run_pipeline.py --target all --horizon 30只运行化学楼:
python scripts/run_pipeline.py --target chemi --horizon 30只运行四校区:
python scripts/run_pipeline.py --target campus --campus all --horizon 30本地验证不写库:
python scripts/run_pipeline.py --target all --horizon 3 --no-db-write受控写库验收使用已有模型参数,只做 1 天推理写库并回查表中是否出现对应日期:
python scripts/verify_db_write.py --target all --horizon 1 --confirm-write该命令必须带 --confirm-write,否则会拒绝写库。
可单独刷新外部特征缓存:
python scripts/update_external_features.py --start-date 2023-01-01 --end-date 2026-06-30项目会自动创建以下结构的结果表:
CREATE TABLE IF NOT EXISTS phase_ll.elecforcast_chemi (
id SERIAL PRIMARY KEY,
statis_date DATE NOT NULL,
model_name VARCHAR(50) NOT NULL,
actual_value DOUBLE PRECISION,
predicted DOUBLE PRECISION,
rmse DOUBLE PRECISION,
mae DOUBLE PRECISION,
r2_score DOUBLE PRECISION,
mape DOUBLE PRECISION,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(statis_date, model_name)
);结果表不是每次训练新建一张。程序使用固定表名,先执行 CREATE TABLE IF NOT EXISTS,再按 (statis_date, model_name) 做 upsert。重新训练后,相同日期和相同模型名的行会被更新;新增日期或新增模型名会追加新行。
训练阶段会写入各模型测试集预测和评估指标。推理阶段只写入已保存的最佳模型预测,未来日期通常没有 actual_value,因此该字段为空。
- 第一次部署推荐先运行
python scripts/run_pipeline.py --target all --horizon 30,完成训练、推理和写库。 - 后续可以定期运行
python scripts/run_pipeline.py --target all --horizon 30更新预测表单。 - 如果新真实数据持续进入源表,下一次推理会自动使用最新历史用电值生成滞后特征。
data/academic_calendar.csv和data/temperature_yangpu.csv现在是缓存和失败回退文件,不再是唯一特征来源。--no-db-write可用于本地调试,只生成文件不写数据库。
生产上可以定时执行:
cd D:\2026\xxb\submission
python scripts/run_pipeline.py --target all --horizon 30这个命令会依次处理:
- 重新训练江湾化学楼模型,并更新化学楼结果表。
- 重新训练四校区模型,并更新四校区结果表。
- 加载刚训练好的模型,生成未来 30 天预测。
- 写入对应 DB 表。
结果表不会每次新建,而是更新固定表:
| 预测对象 | 结果表 |
|---|---|
| 化学楼 | phase_ll.elecforcast_chemi |
| 邯郸校区 | phase_ll.elecforcast_handan |
| 江湾校区 | phase_ll.elecforcast_jiangwan |
| 枫林校区 | phase_ll.elecforcast_fenglin |
| 张江校区 | phase_ll.elecforcast_zhangjiang |
相同 (statis_date, model_name) 会覆盖更新,新日期会追加。
推荐把“推理更新”和“重新训练”分两层理解:
- 推理更新:每周或每月跑一次。如果业务表单只看未来一个月预测,建议每月初跑一次
--horizon 30。 - 重新训练:建议每月一次,至少每季度一次。
更具体地说:
- 初期上线前 3-6 个月建议每月重训一次。学校用电受季节、寒暑假、开学和节假日影响明显,月度重训更稳。
- 模型稳定后可以改成每季度重训一次。
- 遇到暑假、寒假、开学、校区设备改造、源数据口径变化等特殊情况,应临时重训。
如果只想每隔一个月或一个季度更新表单,建议先用月度:
python scripts/run_pipeline.py --target all --horizon 30如果季度更新:
python scripts/run_pipeline.py --target all --horizon 90但 90 天滚动预测误差更容易累积,所以更推荐每月跑 30 天。
把整个 submission 文件夹复制到客户机器后,按以下步骤执行。
- 进入项目目录:
cd D:\2026\xxb\submission如果客户机器路径不同,进入复制后的 submission 目录即可。
- 准备 Python 环境并安装依赖:
python --version
pip install -r requirements.txt生产环境也可以使用锁定版本:
pip install -r requirements-lock.txt- 配置数据库连接:
copy .env.example .env编辑 .env,确认以下变量为客户数据库连接信息:
FD_DB_HOST=...
FD_DB_PORT=...
FD_DB_NAME=...
FD_DB_USER=...
FD_DB_PASSWORD=...
如果客户数据库、用户名和密码与开发环境一致,可以沿用同一套值,但仍建议现场先确认网络和权限。
- 执行自动部署验收脚本:
python scripts/deploy_acceptance.py默认验收口径:
- 固定训练截止日:
2026-05-13,用于复现docs/中记录的模型指标。 - 预测日期:
2026-06-01到2026-06-30,两端都包含,因此自动使用horizon=30。 - 自动训练江湾化学楼和四校区模型。
- 自动推理并写入 5 张固定结果表。
- 自动回查 5 张结果表中对应日期范围是否有预测数据。
- 自动比较关键模型指标,默认允许
0.02的绝对误差。
验收结果会打印到屏幕,并保存到:
artifacts/deployment_acceptance_report.json
- 如果只想先干跑,不写数据库:
python scripts/deploy_acceptance.py --no-db-write干跑成功只说明数据库可连接、训练和推理流程可执行、报告指标可复现。因为没有写库,db_prediction_rows 会为空;最终交付验收仍需不带 --no-db-write 再运行一次,确认 5 张结果表中确实产生预测行。
- 如果现场希望用客户库最新数据重训,而不是复现报告固定指标:
python scripts/run_pipeline.py --target all --horizon 30 --start-date 2026-06-01注意:使用最新数据重训时,模型指标可能与 docs/ 中报告的固定训练结果自然不同;这不一定是错误,需要以现场生成的 artifacts/metrics.json 和 artifacts/campus_models/metrics.json 为准。
- 验收应重点确认:
scripts/deploy_acceptance.py退出码为 0。artifacts/deployment_acceptance_report.json中ok为true。- 化学楼结果表
phase_ll.elecforcast_chemi有2026-06-01到2026-06-30的预测行。 - 四校区结果表
phase_ll.elecforcast_handan、phase_ll.elecforcast_jiangwan、phase_ll.elecforcast_fenglin、phase_ll.elecforcast_zhangjiang有同一日期范围的预测行。 - 四校区写入 DB 的
predicted是校区日用电量,不是差分;残差只是内部训练方式,输出前已还原为用电量。
本项目会在训练和推理时自动使用外部特征:
- 温度特征:优先调用 Open-Meteo API 获取杨浦区逐日最高温、最低温和平均温,并更新
data/temperature_yangpu.csv缓存。 - 校历特征:优先从数据库表
teach_etl.t_szls_zhjx_xnxqxx_xjwxt查询寒暑假信息,并更新data/academic_calendar.csv缓存。 - 如果 API 或校历表不可用,程序会回退到本地 CSV;如果未来日期没有完整温度记录,会使用训练期特征默认值补齐,保证训练、推理和写库流程不中断。
Open-Meteo 免费 forecast 接口通常只能提供约 16 天真实预报。执行 2026-06-01 到 2026-06-30 这类 30 天预测时,超过天气 API 预报窗口的日期可能无法获取真实未来天气。此时脚本会打印类似提示:
[temperature] API refresh failed, using local CSV fallback: 400 Client Error ...
这不是模型错误,也不会阻断验收。含义是天气 API 没有返回完整未来区间,程序已自动改用本地缓存或默认温度特征。
如果客户要求未来 30 天每天都必须使用真实天气预报,需要提供支持 30 天以上预报的商业天气 API,例如 AccuWeather Enterprise,并在后续版本中接入对应 API key。否则当前默认策略是:可获取的天气用 API 更新,超出预报窗口的日期用缓存/默认值兜底。
部署验收还会检查源数据表的最新日期。如果输出中出现:
latest source date is 2026-05-13; forecasting from 2026-06-01 will bridge a gap
说明源表最新真实用电数据早于预测开始日前一天。例如从 2026-06-01 开始预测,理想情况下源表至少应有 2026-05-31 的真实用电记录。源表缺口不会导致程序失败,但会让模型用更早的历史数据向前滚动预测,预测质量会下降。正式生产前建议客户补齐源表数据,或把预测开始日期设为源表最新日期的下一天。
构建镜像:
docker build -t electricity-forecast:latest .运行一次完整训练和 30 天推理:
docker run --rm --env-file .env electricity-forecast:latest覆盖默认命令,例如只跑四校区:
docker run --rm --env-file .env electricity-forecast:latest \
python scripts/run_pipeline.py --target campus --campus all --horizon 30依赖锁定文件为 requirements-lock.txt。普通开发可用 requirements.txt,生产构建建议使用锁定版本。
本项目现在同时包含江湾化学楼模型和四个校区模型。四校区模型位于独立入口中,复用同一套数据库、温度、校历和 upsert 工具函数。
训练四校区:
python scripts/train_campuses.py --campus all只训练单个校区:
python scripts/train_campuses.py --campus 邯郸校区本地测试不写数据库:
python scripts/train_campuses.py --campus all --end-date 2026-05-13 --no-db-write四校区推理:
python scripts/predict_campuses.py --campus all --horizon 30模型产物保存到 artifacts/campus_models/。每个校区有独立子目录,包含 model.joblib、metrics.json、prediction_results.csv 和 latest_forecast.json。
四校区输出表:
| 校区 | 输出表 |
|---|---|
| 邯郸校区 | phase_ll.elecforcast_handan |
| 江湾校区 | phase_ll.elecforcast_jiangwan |
| 枫林校区 | phase_ll.elecforcast_fenglin |
| 张江校区 | phase_ll.elecforcast_zhangjiang |
四校区模型最终预测目标是校区日用电量,不是差分。残差只是内部训练方式:固定测试集评估时模型学习 当日用电 - lag1。面向客户月度一次性生成 30 天预测时,推理阶段会把残差模型输出作为稳定锚点,再融合历史同月同日、同星期和近期水平,生成更有月度动态的日用电量曲线。这和江湾化学楼直接预测建筑日用电量的目标不同。
详细迁移和测试记录见 docs/campus_model_report.md。
本项目还包含用于 AI coding 学习与团队复用的教学资源,帮助同事在现有基础上进行二次开发。
skills/project_rebuild_prompt_notebook.ipynb 是一个教学示例,演示如何用 prompt 生成类似本项目的骨架代码。只读导出数据库源表为本地 CSV,调用 DeepSeek 生成项目文件,适合给非开发人员展示 AI coding 效果。
skills/electricity-forecast-builder/ 是一套可复用的 AI agent 技能,用于在 Cursor 等工具中快速构建楼宇/校区用电预测项目。它沉淀了"数据画像 → 文献依据 → baseline 建模 → 误差诊断 → 清洗/特征/目标迭代 → 多模型择优 → 封装验收"的完整工作流。
详细使用说明见 skills/notebook_and_skill_usage_guide.md。
Linux cron 每天 02:30 训练并预测:
30 2 * * * cd /opt/electricity-forecast/submission && python scripts/run_pipeline.py --target all --horizon 30 >> logs/pipeline.log 2>&1Windows 任务计划可把程序设为 python,参数设为:
scripts/run_pipeline.py --target all --horizon 30
起始目录设为生产机上的 submission 目录。