- 新增 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 项,全部通过)
222 lines
6.9 KiB
Python
222 lines
6.9 KiB
Python
#!/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()
|