2. 数据源获取与初步认识:使用Python读取催收系统导出的CSV/Excel文件
在催收异常复盘项目中,第一步是获取原始数据并建立对其结构、类型与质量的初步认知。催收系统通常支持导出为 CSV 或 Excel 格式,字段包含但不限于:手机号、触达时间、状态码、客户姓名、案件编号等。本节将演示如何使用 Python 的 pandas 库读取这些文件,并展示原始数据的全貌。
2.1 数据源文件结构预览
典型的催收触达记录导出文件包含以下核心字段,下表列出了常见字段及其业务含义:
| 字段名 | 数据类型 | 业务含义 | 示例值 |
|---|---|---|---|
case_id |
字符串 | 案件唯一编号 | CS20241001-001 |
customer_name |
字符串 | 客户姓名 | 张三 |
phone_number |
字符串 | 客户手机号 | 138****1234 |
contact_time |
日期时间 | 催收触达时间 | 2024-10-01 09:15:30 |
status_code |
整数 | 触达结果状态码 | 200 |
duration_sec |
整数 | 通话时长(秒) | 120 |
agent_id |
字符串 | 催收员编号 | AG-0451 |
2.2 使用Pandas读取CSV文件
Python 的 pandas 库提供了 read_csv() 函数,可以快速将 CSV 文件加载为 DataFrame。以下代码演示了基本读取操作,并展示前 5 行数据:
import pandas as pd
# 读取催收系统导出的CSV文件
file_path = "data/collection_contact_20241001.csv"
df = pd.read_csv(file_path, encoding='utf-8')
# 展示数据基本信息
print("数据形状(行数, 列数):", df.shape)
print("\n前5行数据预览:")
print(df.head())
# 查看各列数据类型
print("\n各列数据类型:")
print(df.dtypes)
输出示例:
数据形状(行数, 列数): (15000, 8)
前5行数据预览:
case_id customer_name phone_number contact_time status_code duration_sec agent_id
0 CS20241001-001 张三 13800138001 2024-10-01 09:15:30 200 120 AG-0451
1 CS20241001-002 李四 13900139002 2024-10-01 09:18:45 404 0 AG-0451
2 CS20241001-003 王五 13700137003 2024-10-01 09:22:10 500 0 AG-0452
3 CS20241001-004 赵六 13600136004 2024-10-01 09:30:00 200 85 AG-0453
4 CS20241001-005 孙七 13500135005 2024-10-01 09:35:20 200 200 AG-0451
各列数据类型:
case_id object
customer_name object
phone_number object
contact_time object
status_code int64
duration_sec int64
agent_id object
dtype: object
💡 提示: 注意
contact_time 列被识别为 object(字符串)类型,而非 datetime。在后续数据清洗中,需要将其转换为标准时间格式,以便进行时间维度的异常分析。
2.3 读取Excel文件的差异
如果催收系统导出的是 .xlsx 格式,需要使用 read_excel() 函数,并可能需要指定工作表名称:
# 读取Excel文件
df_excel = pd.read_excel("data/collection_contact_20241001.xlsx", sheet_name=0)
# 快速查看数据摘要
print("Excel数据摘要:")
print(df_excel.info())
两种读取方式返回的 DataFrame 结构一致,但 read_excel() 对日期格式的自动推断能力更强,部分情况下可直接识别为 datetime64 类型。
2.4 原始数据初步认识:字段质量扫描
在正式清洗前,需要对原始数据进行快速质量扫描,重点关注缺失值、重复记录和异常状态码。以下代码展示了基础扫描方法:
# 缺失值统计
print("各列缺失值数量:")
print(df.isnull().sum())
# 重复行检查
print("\n完全重复行数:", df.duplicated().sum())
# 状态码分布统计
print("\n状态码分布:")
print(df['status_code'].value_counts().sort_index())
输出示例:
各列缺失值数量:
case_id 0
customer_name 0
phone_number 0
contact_time 0
status_code 0
duration_sec 0
agent_id 0
dtype: int64
完全重复行数: 0
状态码分布:
200 12000
404 1500
500 1000
503 500
Name: status_code, dtype: int64
🔍 关键发现: 状态码
404(未接通)、500(系统错误)、503(服务不可用)合计占比约 20%,这些异常状态码是后续复盘分析的重点对象。同时,duration_sec 在状态码非 200 时均为 0,符合业务逻辑。
2.5 数据源结构总览图
下图展示了从催收系统导出原始数据到初步认识阶段的整体流程与字段结构:
2.6 常见问题与避坑指南
- 编码问题: 中文 CSV 文件常使用
utf-8或gbk编码。若读取出现乱码,尝试encoding='gbk'或encoding='utf-8-sig'。 - 日期列类型: 读取后务必检查日期列是否为
datetime64类型,否则后续时间计算会出错。可使用pd.to_datetime()强制转换。 - 手机号格式: 手机号在 CSV 中可能被 Excel 自动转换为科学计数法,建议导出时设置文本格式,或在读取时指定
dtype={'phone_number': str}。 - 大文件读取: 若文件行数超过 10 万行,可使用
chunksize参数分块读取,避免内存溢出。
⚠️ 注意: 不要直接修改原始导出文件。建议在读取后立即创建副本(
df_original = df.copy()),以便在清洗过程中随时回溯对比。