3. 财务报表数据结构化
财务报表是财务建模与现金流预测的基石。原始财报数据通常以非结构化文本、PDF 或 CSV 形式存在,必须经过结构化处理才能用于后续的参数调优与穿透查询。本节将系统讲解如何将资产负债表、利润表、现金流量表转换为标准的 Pandas DataFrame,并完成数据清洗、缺失值处理与日期索引设置。
3.1 三大报表的 DataFrame 表示
每张报表都有其独特的行结构(科目)与列结构(期间)。我们采用“宽表”与“长表”两种范式来存储:
| 报表类型 | 宽表结构(列 = 期间) | 长表结构(列 = 科目 + 期间) | 适用场景 |
|---|---|---|---|
| 资产负债表 | 科目名称, 2023Q1, 2023Q2, … | 科目名称, 报告期, 金额 | 宽表适合横向对比;长表适合透视与合并 |
| 利润表 | 科目名称, 2023-01, 2023-02, … | 科目名称, 报告期, 金额 | 宽表适合趋势分析;长表适合 SQL 查询 |
| 现金流量表 | 科目名称, 2023Q1, 2023Q2, … | 科目名称, 报告期, 金额 | 宽表适合直接观察;长表适合参数调优 |
以下代码演示如何将原始 CSV 数据加载为宽表 DataFrame,并转换为长表:
import pandas as pd
# 加载资产负债表(宽表)
bs_wide = pd.read_csv('balance_sheet.csv', index_col='科目')
print(bs_wide.head())
# 转换为长表(melt)
bs_long = bs_wide.reset_index().melt(
id_vars=['科目'],
var_name='报告期',
value_name='金额'
)
bs_long['报告期'] = pd.to_datetime(bs_long['报告期'])
print(bs_long.head())
实践建议: 建议将三大报表统一存储为长表格式,并在“报表类型”列中标记来源(BS / IS / CF),便于后续合并查询。
3.2 数据清洗与缺失值处理
原始财报数据常见问题包括:科目名称不一致、金额单位不统一、缺失值、重复行、非数值字符等。清洗流程应遵循以下步骤:
- 科目名称标准化:去除空格、统一简称(如“货币资金”与“现金”合并)。
- 金额单位统一:将“万元”、“亿元”转换为元,或统一为千元。
- 缺失值处理:区分“数据未披露”与“科目不存在”,前者用 NaN 标记,后者直接删除。
- 数据类型转换:确保金额列为 float,日期列为 datetime。
- 重复行去重:按科目+报告期去重,保留最后一条记录。
典型清洗代码示例:
# 清洗函数
def clean_financial_data(df):
# 1. 科目名称标准化
df['科目'] = df['科目'].str.strip().str.replace(' ', '')
# 2. 金额单位转换(假设原始单位为万元)
df['金额'] = df['金额'] * 10000
# 3. 缺失值处理
df['金额'] = pd.to_numeric(df['金额'], errors='coerce')
# 4. 去重
df = df.drop_duplicates(subset=['科目', '报告期'], keep='last')
return df
bs_clean = clean_financial_data(bs_long)
print(bs_clean.isnull().sum())
注意: 对于现金流量表中的“期初现金余额”与“期末现金余额”,缺失值不能直接填充为 0,应使用前向填充或根据勾稽关系推算。
3.3 日期索引设置
日期索引是时间序列分析的基础。设置日期索引后,可以方便地进行重采样、滚动计算与对齐操作。推荐将“报告期”列转换为 DatetimeIndex,并按升序排序。
日期索引设置步骤:
- 将字符串日期转换为
pd.DatetimeIndex。 - 处理不规则日期(如“2023-12-31”与“2023/12/31”统一格式)。
- 设置索引并排序。
- 检查索引是否唯一且无缺失。
# 设置日期索引
bs_clean['报告期'] = pd.to_datetime(bs_clean['报告期'], format='mixed')
bs_clean = bs_clean.set_index('报告期').sort_index()
# 检查索引
print(bs_clean.index.is_monotonic_increasing)
print(bs_clean.index.unique().shape)
关键点: 日期索引设置后,可以使用
.loc['2023'] 快速切片年度数据,或使用 .resample('Q') 进行季度汇总。
3.4 三大报表结构化流程总览
以下 SVG 图展示了从原始数据到结构化 DataFrame 的完整流程:
3.5 三大报表合并与穿透查询准备
结构化完成后,将三大报表合并为一个统一的长表,便于后续的穿透查询与参数调优:
# 合并三大报表
bs_clean['报表类型'] = 'BS'
is_clean['报表类型'] = 'IS'
cf_clean['报表类型'] = 'CF'
all_financials = pd.concat([bs_clean, is_clean, cf_clean], axis=0)
all_financials = all_financials.sort_index()
# 保存为 Parquet 格式(高效存储)
all_financials.to_parquet('financial_statements.parquet')
print(all_financials.head())
效率提示: 使用 Parquet 格式存储结构化后的财报数据,相比 CSV 可节省约 70% 磁盘空间,且读取速度提升 5-10 倍。
至此,三大报表已从原始数据转换为带有日期索引的干净 DataFrame,为后续的现金流预测模型参数调优与穿透查询奠定了坚实的数据基础。