2. 申请评分卡数据字典构建

任务说明

本案例基于一份原始字段说明(字段名、中文含义、原始类型、取值/备注),生成标准化数据字典:统一字段类型(数值型/类别型/文本型/日期型)、规范字段命名、补充取值说明,并输出为 CSV 与 Markdown 两种可直接交付的形式。输入数据在本案例中直接内置,无需外部文件即可运行。

实现代码

import csv
import re
from pathlib import Path

# 原始字段说明:字段名, 中文含义, 原始类型, 取值/备注
RAW_FIELDS = [
    ("cust_id",      "客户编号",   "string",  "唯一标识,如 C000123"),
    ("apply_date",   "申请日期",   "string",  "格式 YYYY-MM-DD"),
    ("age",          "年龄",       "int",     "18-70"),
    ("gender",       "性别",       "string",  "M=男, F=女"),
    ("marital",      "婚姻状况",   "string",  "S=未婚, M=已婚, D=离异"),
    ("education",    "学历",       "string",  "1=高中及以下,2=大专,3=本科,4=硕士及以上"),
    ("monthly_inc",  "月收入(元)", "float",   ">=0"),
    ("loan_amt",     "申请金额(元)","float",  ">0"),
    ("loan_term",    "贷款期限(月)","int",    "6/12/24/36"),
    ("has_house",    "是否有房",   "string",  "Y/N"),
    ("overdue_cnt",  "近2年逾期次数","int",   ">=0"),
    ("apply_result", "审批结果",   "string",  "1=通过, 0=拒绝"),
]

# 原始类型 -> 标准类型
TYPE_MAP = {
    "int": "数值型", "float": "数值型",
    "string": "文本型", "date": "日期型",
}

# 字段名 -> 标准类型覆盖(string 但语义为类别/日期)
SEMANTIC_OVERRIDE = {
    "cust_id": "文本型",
    "apply_date": "日期型",
    "gender": "类别型",
    "marital": "类别型",
    "education": "类别型",
    "has_house": "类别型",
    "apply_result": "类别型",
}

def normalize_name(name: str) -> str:
    """字段名统一为小写下划线风格。"""
    return re.sub(r"[^a-z0-9]+", "_", name.strip().lower()).strip("_")

def build_dictionary(raw_fields):
    rows = []
    for name, meaning, raw_type, note in raw_fields:
        std_name = normalize_name(name)
        std_type = SEMANTIC_OVERRIDE.get(std_name, TYPE_MAP.get(raw_type, "文本型"))
        rows.append({
            "字段名": std_name,
            "中文含义": meaning,
            "字段类型": std_type,
            "取值说明": note,
        })
    return rows

def write_csv(rows, path: Path):
    with path.open("w", newline="", encoding="utf-8-sig") as f:
        writer = csv.DictWriter(f, fieldnames=["字段名", "中文含义", "字段类型", "取值说明"])
        writer.writeheader()
        writer.writerows(rows)

def write_markdown(rows, path: Path):
    header = "| 字段名 | 中文含义 | 字段类型 | 取值说明 |\n|---|---|---|---|\n"
    body = "".join(
        f"| {r['字段名']} | {r['中文含义']} | {r['字段类型']} | {r['取值说明']} |\n"
        for r in rows
    )
    path.write_text(header + body, encoding="utf-8")

if __name__ == "__main__":
    out_dir = Path("output")
    out_dir.mkdir(exist_ok=True)

    dict_rows = build_dictionary(RAW_FIELDS)
    write_csv(dict_rows, out_dir / "data_dictionary.csv")
    write_markdown(dict_rows, out_dir / "data_dictionary.md")

    # 控制台打印,便于快速核对
    for r in dict_rows:
        print(f"{r['字段名']:<14}{r['字段类型']:<6}{r['中文含义']}")
    print(f"\n共 {len(dict_rows)} 个字段,已输出到 {out_dir}/")

运行方式

python build_dict.py

脚本会在当前目录创建 output/,生成 data_dictionary.csv 与 data_dictionary.md。

验证方法与通过条件

  • 控制台按“字段名 / 字段类型 / 中文含义”逐行打印 12 个字段,字段名均为小写下划线风格。
  • output/data_dictionary.csv 表头为 字段名,中文含义,字段类型,取值说明,共 12 行数据。
  • 类型判定符合语义:age/loan_amt/overdue_cnt 等为“数值型”,gender/marital/education/has_house/apply_result 为“类别型”,apply_date 为“日期型”,cust_id 为“文本型”。
  • Markdown 文件可直接粘贴到文档中渲染为表格,列与 CSV 一致。

常见问题

  • 若原始字段说明来自 Excel,可先用 pandas.read_excel 读入并转成 RAW_FIELDS 同样的四元组列表,其余逻辑不变。
  • 新增字段时只需在 RAW_FIELDS 追加一行;若其 string 类型实际为类别或日期,在 SEMANTIC_OVERRIDE 中登记即可。