Initial commit

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
lofyer
2026-07-13 15:38:41 +08:00
co-authored by factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
commit 71db82393a
180 changed files with 170640 additions and 0 deletions
+210
View File
@@ -0,0 +1,210 @@
#!/usr/bin/env python3
"""
覆盖率审计脚本
检查:
1. 二期ETL输出的字段名称,赋分引擎实际用到了多少
2. 赋分引擎里按关键词匹配的字段,在二期数据中能否命中
3. 每个维度的赋分数据源覆盖情况
"""
import sys
import re
import inspect
from pathlib import Path
from collections import defaultdict
import pandas as pd
import numpy as np
sys.path.insert(0, str(Path(__file__).parent))
sys.path.insert(0, str(Path(__file__).parent.parent.parent / "backend"))
from data_engine_era2 import DataEngineEra2
from app.engines.scoring_engine import ScoringEngine
from config_era2 import DIMENSION_FRAMEWORK, SUBJECTS
def section(title):
print(f"\n{'=' * 80}")
print(f" {title}")
print(f"{'=' * 80}")
def main():
# ===== 加载二期全量数据(不分区,看全貌) =====
section("1. 加载二期全量数据")
engine = DataEngineEra2(district_filter=None)
engine.load_all()
print(f" 学校数: {len(engine.schools)}")
# 获取全量字段名称
course_df = engine._course_impl
subject_df = engine._subject_impl
basic_df = engine._basic_info
course_fields = sorted(course_df["字段名称"].dropna().unique())
subject_fields = sorted(subject_df["字段名称"].dropna().unique())
basic_fields = sorted(basic_df["字段名称"].dropna().unique())
print(f" 课程实施表字段名称数: {len(course_fields)}")
print(f" 学科课程表字段名称数: {len(subject_fields)}")
print(f" 基础信息表字段名称数: {len(basic_fields)}")
# ===== 2. 提取赋分引擎中所有用到的字段名称和关键词 =====
section("2. 赋分引擎字段引用分析")
# 从 ScoringEngine 源码中提取所有字符串常量(字段名称/关键词)
src = inspect.getsource(ScoringEngine)
# 提取所有中文字符串(字段名称)
# 匹配双引号和单引号中的中文字符串
field_refs = set()
keyword_refs = set()
# 精确字段引用:df["字段名称"] == "xxx" 或 字段名称 == field
exact_patterns = re.findall(r'["\']([^"\']*[\u4e00-\u9fff][^"\']*)["\']', src)
for p in exact_patterns:
# 跳过注释性文字
if len(p) > 30 or '' in p or '' in p or '赋分' in p:
continue
field_refs.add(p)
# 关键词引用:str.contains("xxx")
contains_patterns = re.findall(r'\.str\.contains\(["\']([^"\']+)["\']', src)
for p in contains_patterns:
# 这些是用 | 分隔的关键词
for kw in p.split('|'):
keyword_refs.add(kw.strip())
# 其他关键词引用(in循环中的列表)
keyword_lists = re.findall(r'for (?:keyword|field|hw_type|resource) in \[([^\]]+)\]', src)
for kl in keyword_lists:
items = re.findall(r'["\']([^"\']+)["\']', kl)
for item in items:
if any('\u4e00' <= c <= '\u9fff' for c in item):
field_refs.add(item)
print(f"\n 赋分引擎中精确引用的字段名称: {len(field_refs)}")
print(f" 赋分引擎中关键词引用: {len(keyword_refs)}")
# ===== 3. 逐一检查精确字段在二期数据中的命中情况 =====
section("3. 精确字段匹配检查")
all_data_fields = set(course_fields) | set(subject_fields) | set(basic_fields)
matched = []
missing = []
for f in sorted(field_refs):
if f in all_data_fields:
matched.append(f)
else:
missing.append(f)
print(f"\n ✅ 命中: {len(matched)}/{len(field_refs)}")
print(f" ❌ 未命中: {len(missing)}/{len(field_refs)}")
if missing:
print(f"\n 未命中的字段(赋分引擎引用但二期数据中不存在):")
for f in missing:
# 尝试模糊匹配
fuzzy = [df for df in all_data_fields if f.replace('_', '') in df.replace('_', '') or df.replace('_', '') in f.replace('_', '')]
if fuzzy:
print(f"{f}")
print(f" → 可能对应: {fuzzy[:3]}")
else:
print(f"{f} (无近似匹配)")
# ===== 4. 关键词匹配检查 =====
section("4. 关键词匹配检查")
for kw in sorted(keyword_refs):
course_hits = course_df[course_df["字段名称"].str.contains(kw, na=False)]["字段名称"].unique()
subject_hits = subject_df[subject_df["字段名称"].str.contains(kw, na=False)]["字段名称"].unique()
total = len(course_hits) + len(subject_hits)
status = "" if total > 0 else ""
print(f" {status} '{kw}': 课程表{len(course_hits)}个, 学科表{len(subject_hits)}")
if total == 0:
# 看看有没有相近的
all_names = list(course_fields) + list(subject_fields)
similar = [n for n in all_names if kw[:2] in n][:3]
if similar:
print(f" → 近似: {similar}")
# ===== 5. 按维度逐一检查赋分数据覆盖 =====
section("5. 按维度检查赋分数据覆盖(抽样一所学校)")
# 取一所数据较完整的学校
test_school = engine.schools[0]
print(f" 测试学校: {test_school}")
scoring = ScoringEngine(engine)
scores = scoring._score_school(test_school)
print(f"\n {'维度':<20} {'赋分项数':>8} {'均值':>8} {'是否有效':>8}")
print(f" {'' * 50}")
for dim, vals in scores.items():
n = len(vals)
avg = np.mean(vals) if vals else 0
# 判断是否有效:是否全是默认值
is_default = (n <= 1 and abs(avg - 1.0) < 0.01) or (n <= 1 and abs(avg - 1.5) < 0.01) or (n <= 1 and abs(avg - 2.0) < 0.01) or (n <= 1 and abs(avg - 0.5) < 0.01)
status = "⚠️ 默认值" if is_default else ""
print(f" {dim:<20} {n:>8} {avg:>8.2f} {status:>8}")
# ===== 6. 多校抽样统计 =====
section("6. 多校统计:各维度赋分项数分布")
# 取前20所学校统计
sample_schools = engine.schools[:20]
dim_stats = defaultdict(list)
for school in sample_schools:
s = scoring._score_school(school)
for dim, vals in s.items():
dim_stats[dim].append(len(vals))
print(f"\n 抽样学校数: {len(sample_schools)}")
print(f"\n {'维度':<20} {'最小':>6} {'最大':>6} {'均值':>6} {'全为1':>8}")
print(f" {'' * 50}")
for dim in DIMENSION_FRAMEWORK:
for sub in DIMENSION_FRAMEWORK[dim]["sub_dimensions"]:
vals = dim_stats.get(sub, [0])
min_v = min(vals)
max_v = max(vals)
avg_v = np.mean(vals)
all_one = sum(1 for v in vals if v <= 1)
warn = "⚠️" if all_one > len(vals) * 0.5 else ""
print(f" {sub:<20} {min_v:>6} {max_v:>6} {avg_v:>6.1f} {all_one:>4}/{len(vals)} {warn}")
# ===== 7. 二期新增但赋分引擎未使用的字段 =====
section("7. 二期数据中存在但赋分引擎未引用的高频字段(Top 30)")
# 统计二期中每个字段名称出现的学校数
course_field_school_count = course_df.groupby("字段名称")["学校名称"].nunique().sort_values(ascending=False)
subject_field_school_count = subject_df.groupby("字段名称")["学校名称"].nunique().sort_values(ascending=False)
# 过滤掉已被赋分引擎引用的
unused_course = course_field_school_count[~course_field_school_count.index.isin(field_refs)]
unused_subject = subject_field_school_count[~subject_field_school_count.index.isin(field_refs)]
# 进一步过滤:去掉被关键词匹配可能命中的
def is_keyword_matched(field_name):
for kw in keyword_refs:
if kw in str(field_name):
return True
return False
unused_course_strict = unused_course[~unused_course.index.map(is_keyword_matched)]
unused_subject_strict = unused_subject[~unused_subject.index.map(is_keyword_matched)]
print(f"\n [课程实施表] 未被引用的字段 (按学校覆盖率排序, Top 20):")
for field, cnt in unused_course_strict.head(20).items():
print(f" {field}: {cnt}所学校有数据")
print(f"\n [学科课程表] 未被引用的字段 (Top 20):")
for field, cnt in unused_subject_strict.head(20).items():
print(f" {field}: {cnt}所学校有数据")
print(f"\n✅ 覆盖率审计完成!")
if __name__ == "__main__":
main()