4. 数据加载:使用 pandas 读取 CSV / Excel 格式的保单与理赔数据

数据加载是赔付率监控与尖峰识别的基础环节。在实际生产环境中,保单数据与理赔数据通常以 CSV 或 Excel 格式存储在数据仓库或本地文件系统中。本节将演示如何使用 pandas 库高效、稳定地加载这两种格式的数据,并处理常见的加载异常。

4.1 数据源结构概览

在开始编码之前,需要明确两个核心数据集的字段结构。下表列出了典型的保单主表与理赔明细表的关键字段:

数据集 字段名 类型 说明
保单主表 policy_id 字符串 保单唯一标识
underwrite_date 日期 承保日期
premium 浮点数 保费金额
product_line 字符串 产品线(如车险、健康险)
理赔明细表 claim_id 字符串 理赔案件唯一标识
policy_id 字符串 关联保单号
claim_date 日期 出险日期
claim_amount 浮点数 赔付金额

4.2 使用 pandas 读取 CSV 文件

CSV 是精算分析中最常见的文本格式。使用 pd.read_csv() 时,需要关注编码、分隔符、日期解析和数据类型优化。以下代码演示了标准加载流程:

import pandas as pd

# 读取保单数据
df_policy = pd.read_csv(
    'policy_data.csv',
    encoding='utf-8',
    sep=',',
    parse_dates=['underwrite_date'],
    dtype={
        'policy_id': 'string',
        'premium': 'float64',
        'product_line': 'category'
    }
)

# 读取理赔数据
df_claim = pd.read_csv(
    'claim_data.csv',
    encoding='utf-8',
    sep=',',
    parse_dates=['claim_date'],
    dtype={
        'claim_id': 'string',
        'policy_id': 'string',
        'claim_amount': 'float64'
    }
)

print(f"保单数据加载完成:{df_policy.shape[0]} 条记录")
print(f"理赔数据加载完成:{df_claim.shape[0]} 条记录")
精算实践提示: 对于百万级以上的保单数据,建议在 read_csv 中指定 dtype 字典,避免 pandas 自动推断类型带来的内存膨胀。将 product_line 设为 category 类型可显著降低内存占用。

4.3 使用 pandas 读取 Excel 文件

Excel 文件在业务部门中广泛使用,但加载时需注意多工作表、合并单元格和空行问题。推荐使用 pd.read_excel() 配合 sheet_name 参数:

# 读取 Excel 中的指定工作表
df_policy_excel = pd.read_excel(
    'policy_data.xlsx',
    sheet_name='保单信息',
    header=0,
    usecols='A:F',
    dtype={
        'policy_id': 'string',
        'premium': 'float64'
    }
)

# 读取理赔工作表,跳过前 2 行说明行
df_claim_excel = pd.read_excel(
    'claim_data.xlsx',
    sheet_name='理赔明细',
    skiprows=2,
    parse_dates=['claim_date']
)

print(f"Excel 保单数据加载完成:{df_policy_excel.shape[0]} 条记录")
print(f"Excel 理赔数据加载完成:{df_claim_excel.shape[0]} 条记录")
常见陷阱: Excel 文件中可能存在合并单元格,读取后会产生 NaN 值。建议在加载后使用 df.fillna(method='ffill') 进行前向填充,或要求业务方在导出前取消合并。

4.4 数据加载后的快速验证

加载完成后,必须执行一组快速验证,确保数据完整性。以下为推荐的验证清单:

  • 记录数核对: 使用 df.shape 确认行数与源文件一致。
  • 缺失值检查: 使用 df.isnull().sum() 定位关键字段的缺失情况。
  • 日期范围确认: 使用 df['claim_date'].min() 和 .max() 检查时间跨度是否合理。
  • 唯一性校验: 使用 df['policy_id'].nunique() 检查保单主键是否重复。
# 快速验证示例
print("缺失值统计:")
print(df_policy.isnull().sum())

print("\n理赔日期范围:")
print(f"最早:{df_claim['claim_date'].min()}")
print(f"最晚:{df_claim['claim_date'].max()}")

print("\n保单唯一性:")
print(f"唯一保单数:{df_policy['policy_id'].nunique()}")
print(f"总记录数:{df_policy.shape[0]}")

4.5 数据加载流程架构

下图展示了从原始文件到内存 DataFrame 的完整加载流程,包含异常处理与验证环节:

数据加载流程架构图 原始文件 CSV / Excel pandas 读取引擎 read_csv / read_excel 参数配置 dtype | parse_dates | encoding | skiprows usecols | sheet_name DataFrame 内存数据表 快速验证 shape | isnull | nunique 异常捕获:try-except 编码错误自动回退

4.6 常见加载异常与处理策略

在实际项目中,数据加载阶段常遇到以下三类异常。建议在代码中统一捕获并记录日志:

异常类型 典型原因 处理策略
UnicodeDecodeError 文件编码非 UTF-8(如 GBK) 使用 encoding='gbk' 或 encoding='ISO-8859-1' 回退
ParserError CSV 中存在不规则引号或分隔符 设置 quoting=csv.QUOTE_NONE 或 error_bad_lines=False
ValueError 日期列包含无法解析的格式 使用 errors='coerce' 将无效日期转为 NaT
import logging

logging.basicConfig(level=logging.INFO)

def safe_read_csv(filepath, **kwargs):
    """带异常处理的 CSV 加载函数"""
    try:
        df = pd.read_csv(filepath, **kwargs)
        logging.info(f"成功加载 {filepath},共 {df.shape[0]} 行")
        return df
    except UnicodeDecodeError:
        logging.warning(f"UTF-8 解码失败,尝试 GBK 编码: {filepath}")
        kwargs['encoding'] = 'gbk'
        return pd.read_csv(filepath, **kwargs)
    except Exception as e:
        logging.error(f"加载失败: {filepath},错误: {str(e)}")
        raise
最佳实践: 在精算生产环境中,建议将数据加载封装为独立的函数模块,统一管理编码、日志和异常回退策略。这能大幅减少因数据源格式变化导致的管道中断。