3. 银行交易流水清洗与标准化

银行交易流水清洗与标准化 学习卡片

任务说明

不同银行导出的流水格式不一致:日期有 2024/03/05、20240305、05-03-2024 等写法;金额有的用借贷标志列区分方向,有的直接带正负号;摘要里混有空格、全角符号和多余备注。本案例把三家银行的原始流水统一成一张标准化明细表,字段为:交易日期、交易金额(收入为正、支出为负)、摘要、银行。

处理流程

银行A流水 日期/金额/摘要 银行B流水 借贷标志列 银行C流水 带符号金额 清洗与标准化 日期→ISO 金额→带符号 摘要→去噪 标准化明细表 日期/金额 摘要/银行

完整代码

import pandas as pd
import re

# 1. 三家银行原始流水(模拟导出结构差异)
bank_a = pd.DataFrame({
    "交易日期": ["2024/03/05", "2024/03/06", "2024/03/07"],
    "交易金额": ["1,200.00", "-350.50", "8000"],
    "摘要": ["  货款收入 ", "支付 供应商 款项", "退款(部分)"],
})
bank_b = pd.DataFrame({
    "日期": ["20240305", "20240306", "20240307"],
    "金额": [1200.00, 350.50, 8000.00],
    "借贷标志": ["贷", "借", "贷"],
    "备注": ["货款收入", "支付供应商款项", "退款(部分)"],
})
bank_c = pd.DataFrame({
    "交易时间": ["05-03-2024", "06-03-2024", "07-03-2024"],
    "发生额": ["+1200.00", "-350.50", "+8000.00"],
    "摘要说明": ["货款收入", "支付供应商款项", "退款(部分)"],
})

def clean_summary(text):
    """去空格、全角括号转半角、去掉尾部备注"""
    s = str(text).strip()
    s = s.replace("(", "(").replace(")", ")")
    s = re.sub(r"\s+", "", s)
    return s

def parse_date(val):
    """统一为 YYYY-MM-DD"""
    s = str(val).strip()
    for fmt in ("%Y/%m/%d", "%Y%m%d", "%d-%m-%Y"):
        try:
            return pd.to_datetime(s, format=fmt).strftime("%Y-%m-%d")
        except ValueError:
            continue
    raise ValueError(f"无法识别日期格式: {val}")

def parse_amount(val):
    """去掉千分位逗号,转为 float"""
    return float(str(val).replace(",", "").strip())

def normalize(df, date_col, amount_col, summary_col, bank, sign_col=None):
    out = pd.DataFrame()
    out["交易日期"] = df[date_col].map(parse_date)
    amt = df[amount_col].map(parse_amount)
    if sign_col is not None:
        # 借贷标志:借为支出(负),贷为收入(正)
        sign = df[sign_col].map({"借": -1, "贷": 1})
        amt = amt * sign
    out["交易金额"] = amt
    out["摘要"] = df[summary_col].map(clean_summary)
    out["银行"] = bank
    return out

result = pd.concat([
    normalize(bank_a, "交易日期", "交易金额", "摘要", "银行A"),
    normalize(bank_b, "日期", "金额", "备注", "银行B", sign_col="借贷标志"),
    normalize(bank_c, "交易时间", "发生额", "摘要说明", "银行C"),
], ignore_index=True)

result = result.sort_values(["交易日期", "银行"]).reset_index(drop=True)
print(result.to_string(index=False))

运行与验证

依赖:pip install pandas。直接运行脚本即可。

通过条件:输出 9 行、4 列;交易日期 全部为 YYYY-MM-DD;银行B的“借”记录金额为负、“贷”为正;摘要无空格且括号为半角。按代码逻辑,首行应为 2024-03-05 / 1200.0 / 货款收入 / 银行A,银行B同日“借”记录为 -350.5。