3. 财务凭证序时账数据加载与科目编码规范化

财务凭证序时账数据加载与科目编码规范化 学习卡片

任务说明

本案例读取财务序时账 CSV,检查“科目编码”列的长度分布与层级结构,并为缺失上级编码的记录补全上级科目编码。科目编码按层级分段:一级 4 位,其后每级 2 位(如 1122、112201、11220101)。补全规则:若某记录的科目编码长度大于 4 位,则其上级科目编码为去掉最后 2 位后的前缀;若长度为 4 位,则无上级科目编码。

环境与依赖

Python 3.8+,依赖 pandas。安装:pip install pandas。输入文件 journal.csv 需包含列:凭证号, 科目编码, 科目名称, 借方, 贷方。

核心实现

import pandas as pd

def load_journal(path):
    df = pd.read_csv(path, dtype={"科目编码": str})
    df["科目编码"] = df["科目编码"].str.strip()
    return df

def check_levels(df):
    # 长度分布
    dist = df["科目编码"].str.len().value_counts().sort_index()
    # 层级:4位为1级,之后每2位加1级
    def level(code):
        n = len(code)
        if n < 4 or (n - 4) % 2 != 0:
            return None
        return 1 + (n - 4) // 2
    df["层级"] = df["科目编码"].map(level)
    return dist, df

def fill_parent(df):
    def parent(code):
        return code[:-2] if len(code) > 4 else None
    df["上级科目编码"] = df["科目编码"].map(parent)
    return df

if __name__ == "__main__":
    df = load_journal("journal.csv")
    dist, df = check_levels(df)
    print("科目编码长度分布:")
    print(dist)
    invalid = df[df["层级"].isna()]
    if not invalid.empty:
        print("存在非法编码:")
        print(invalid[["凭证号", "科目编码"]])
    df = fill_parent(df)
    print(df[["凭证号", "科目编码", "层级", "上级科目编码"]])
    df.to_csv("journal_filled.csv", index=False, encoding="utf-8-sig")

运行与验证

将上述代码保存为 normalize.py,与 journal.csv 同目录,执行 python normalize.py。验证要点:

  • 长度分布只应出现 4、6、8 等偶数且 ≥4 的值;若出现其他长度,脚本会打印非法编码记录。
  • 输出中每条长度 >4 的记录,其“上级科目编码”应等于自身编码去掉末 2 位;长度 =4 的记录该列为空。
  • 生成 journal_filled.csv,用 Excel 打开确认新增“层级”“上级科目编码”两列且内容与规则一致。

处理流程

读取 journal.csv 检查长度/层级 标记非法编码 补全上级科目编码 code[:-2] 输出 CSV