ai-market-mechanism/processing/validate_data.py
agent-runner ef901e2eb9 v4.0: 地市间对比分析 + 实施路线图 + 风险缓解矩阵
- 新增 3.7 地市间对比分析(表 6,8 地市分三梯队,含梯度分析与跨地市验证)
- 新增 5.4 实施路线图与风险缓解(表 7 三阶段路线图 + 表 8 六类风险矩阵)
- 更新 notebooks/pilot_analysis.md(新增第 9-10 节)
- 新增 plots/city_comparison.png + city_comparison.csv + roadmap_data.csv
- 更新 processing/validate_data.py(校验扩展至 46 项,全部通过)
2026-08-21 10:47:22 +00:00

222 lines
6.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""数据一致性校验脚本。
校验 notebooks/pilot_analysis.md 中的关键数据与 plots/*.csv 数据文件一致,
并验证论文 reports/paper_draft.md 中引用的核心数值与数据源吻合。
用法:
python3 processing/validate_data.py
"""
import csv
import os
import re
import sys
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
PLOTS = os.path.join(ROOT, "plots")
NOTEBOOK = os.path.join(ROOT, "notebooks", "pilot_analysis.md")
PAPER = os.path.join(ROOT, "reports", "paper_draft.md")
errors = []
checks = 0
def ok(msg):
global checks
checks += 1
print(f" PASS: {msg}")
def fail(msg):
global errors
errors.append(msg)
print(f" FAIL: {msg}")
def load_csv(name):
path = os.path.join(PLOTS, name)
with open(path, encoding="utf-8") as f:
return list(csv.DictReader(f))
def check_run_data():
print("[1] 校验运行数据 CSV")
rows = load_csv("pilot_run_data.csv")
cities = [r["city"] for r in rows]
if len(cities) == 8:
ok(f"地市数 = 8: {', '.join(cities)}")
else:
fail(f"地市数 = {len(cities)}, 期望 8")
producing = [r for r in rows if r["stage"] == "实际产出"]
if len(producing) == 2:
ok(f"实际产出地市 = 2: {', '.join(r['city'] for r in producing)}")
else:
fail(f"实际产出地市 = {len(producing)}, 期望 2")
huizhou = next(r for r in rows if r["city"] == "惠州")
if int(huizhou["alert_count"]) == 19800:
ok("惠州预警数据 = 19,800")
else:
fail(f"惠州预警数据 = {huizhou['alert_count']}, 期望 19800")
foshan = next(r for r in rows if r["city"] == "佛山")
if int(foshan["alert_count"]) == 3923:
ok("佛山预警数据 = 3,923")
else:
fail(f"佛山预警数据 = {foshan['alert_count']}, 期望 3923")
def check_vendor_effort():
print("[2] 校验供应商人天投入 CSV")
rows = load_csv("vendor_effort.csv")
total = sum(int(r["person_days"]) for r in rows)
if total == 100:
ok(f"人天合计 = {total}")
else:
fail(f"人天合计 = {total}, 期望 100")
expected = {
"需求沟通与前期对接": 15,
"现场培训与推广": 20,
"技术接入与配置": 18,
"问题响应与日常运营": 20,
"个性化适配与优化": 12,
"差旅在途": 10,
"文档编写": 5,
}
for row in rows:
cat = row["category"]
days = int(row["person_days"])
if cat in expected and days == expected[cat]:
ok(f"{cat} = {days} 人天")
else:
fail(f"{cat} = {days}, 期望 {expected.get(cat, '?')}")
def check_access_cost():
print("[3] 校验接入耗时 CSV")
rows = load_csv("access_cost.csv")
steps = {r["step"]: r for r in rows}
ideal_sum = sum(int(steps[s]["ideal_days"]) for s in
["账号开通", "权限配置", "组织数据匹配", "应用入口配置", "网络策略审批"])
if ideal_sum == 10:
ok(f"理想端到端 = {ideal_sum} 工作日")
else:
fail(f"理想端到端 = {ideal_sum}, 期望 10")
actual_sum = sum(int(steps[s]["actual_days"]) for s in
["账号开通", "权限配置", "组织数据匹配", "应用入口配置", "网络策略审批"])
if actual_sum == 18:
ok(f"各环节实际合计 = {actual_sum} 工作日(端到端实际约 20含排队余量")
else:
fail(f"各环节实际合计 = {actual_sum}, 期望 18")
def check_paper_numbers():
print("[4] 校验论文核心数值")
with open(PAPER, encoding="utf-8") as f:
text = f.read()
patterns = [
(r"144[,]?853", "累计命中异常数据 144,853"),
(r"476\s*次", "累计预警推送 476 次"),
(r"10\s*条.*规则", "监测规则 10 条"),
(r"19[,]?800", "惠州预警 19,800"),
(r"3[,]?923", "佛山预警 3,923"),
(r"8\s*个", "推广地市 8 个"),
(r"7\s*场.*培训", "推广培训 7 场"),
(r"100\s*人天", "供应商投入 100 人天"),
(r"\s*4\s*周", "端到端实际约 4 周"),
(r"\s*30\s*%", "标准化降本约 30%"),
(r"表 6", "表 6 地市间对比"),
(r"表 7", "表 7 实施路线图"),
(r"表 8", "表 8 风险缓解矩阵"),
(r"5\.0\s*倍", "惠州/佛山产出量差 5.0 倍"),
(r"三阶段", "三阶段路线图"),
(r"阶段门", "阶段门审核"),
]
for pat, desc in patterns:
if re.search(pat, text):
ok(f"论文含 {desc}")
else:
fail(f"论文未找到 {desc}")
def check_plots_exist():
print("[5] 校验图表文件存在")
for name in ["pilot_run_data.png", "vendor_effort.png", "access_cost.png",
"city_comparison.png", "city_comparison.csv", "roadmap_data.csv"]:
path = os.path.join(PLOTS, name)
if os.path.isfile(path) and os.path.getsize(path) > 0:
ok(f"{name} 存在 ({os.path.getsize(path)} bytes)")
else:
fail(f"{name} 缺失或为空")
def check_v4_content():
print("[6] 校验 v4.0 新增内容")
with open(PAPER, encoding="utf-8") as f:
text = f.read()
checks_v4 = [
(r"3\.7\s*地市间对比", "3.7 地市间对比分析"),
(r"5\.4\s*实施路线图", "5.4 实施路线图与风险缓解"),
(r"稳定运行梯队", "稳定运行梯队"),
(r"实际产出梯队", "实际产出梯队"),
(r"推广接入梯队", "推广接入梯队"),
(r"标准化筑基", "第一阶段:标准化筑基"),
(r"评价闭环", "第二阶段:评价闭环"),
(r"扩围深化", "第三阶段:扩围深化"),
]
for pat, desc in checks_v4:
if re.search(pat, text):
ok(f"论文含 {desc}")
else:
fail(f"论文未找到 {desc}")
nb_path = os.path.join(ROOT, "notebooks", "pilot_analysis.md")
with open(nb_path, encoding="utf-8") as f:
nb = f.read()
for section in ["## 9. 地市间对比分析", "## 10. 实施路线图与风险缓解"]:
if section in nb:
ok(f"notebooks 含 {section}")
else:
fail(f"notebooks 缺少 {section}")
def main():
print("=" * 60)
print("数据一致性校验 — AI时代市场化运作机制研究")
print("=" * 60)
print()
check_run_data()
print()
check_vendor_effort()
print()
check_access_cost()
print()
check_paper_numbers()
print()
check_plots_exist()
print()
check_v4_content()
print()
print("=" * 60)
if errors:
print(f"校验完成:{checks} 通过,{len(errors)} 失败")
for e in errors:
print(f" - {e}")
sys.exit(1)
else:
print(f"校验完成:全部 {checks} 项通过0 失败")
sys.exit(0)
if __name__ == "__main__":
main()