3. 银行交易流水清洗与标准化
任务说明
不同银行导出的流水格式不一致:日期有 2024/03/05、20240305、05-03-2024 等写法;金额有的用借贷标志列区分方向,有的直接带正负号;摘要里混有空格、全角符号和多余备注。本案例把三家银行的原始流水统一成一张标准化明细表,字段为:交易日期、交易金额(收入为正、支出为负)、摘要、银行。
处理流程
完整代码
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。