第3章:Pandas基础与债券数据读取

说实话,刚入行做债券量化那会儿,我最头疼的就是数据读取。交易所的数据格式五花八门,有的用CSV,有的用Excel,还有的直接从Wind导出来带一堆乱码。后来我慢慢摸索出一套套路,今天就跟大家聊聊Pandas处理债券数据的基本功。

3.1 Series与DataFrame:债券数据的两种容器

Pandas里最核心的两个东西,就是Series和DataFrame。你可以把Series想象成一列数据,比如某只债券的每日收盘价序列。DataFrame呢,就是一张完整的表格,行是日期,列是各种字段——开盘价、收盘价、成交量等等。

我刚开始用的时候,老是把它们搞混。后来我记住一句话:Series是一维的,DataFrame是二维的。就这么简单。

核心区别:

  • Series:带标签的一维数组,适合存储单个时间序列(如某只债券的日收益率)
  • DataFrame:带标签的二维表格,适合存储多只债券或多维度的数据

举个例子,假设我们有一只国债“21国债10”,它的每日收盘价可以存成Series:

import pandas as pd

# 创建一个Series,存储债券收盘价
closing_prices = pd.Series(
    [100.25, 100.30, 100.18, 100.42, 100.35],
    index=['2024-01-02', '2024-01-03', '2024-01-04', '2024-01-05', '2024-01-08'],
    name='21国债10收盘价'
)

print(closing_prices)

输出结果是这样的:

2024-01-02    100.25
2024-01-03    100.30
2024-01-04    100.18
2024-01-05    100.42
2024-01-08    100.35
Name: 21国债10收盘价, dtype: float64

你看,左边是索引(日期),右边是数值(价格),这就是Series的典型结构。我在做回测的时候,经常用Series来存策略的每日净值,方便后面计算收益率和最大回撤。

那DataFrame呢?它更像一张Excel表格。比如我们想存多只债券的行情:

# 创建一个DataFrame,存储多只债券行情
bond_data = pd.DataFrame({
    '日期': ['2024-01-02', '2024-01-03', '2024-01-04'],
    '21国债10': [100.25, 100.30, 100.18],
    '21国债15': [101.10, 101.05, 101.20],
    '22国债01': [99.80, 99.75, 99.90]
})

print(bond_data)
          日期  21国债10  21国债15  22国债01
0  2024-01-02   100.25   101.10    99.80
1  2024-01-03   100.30   101.05    99.75
2  2024-01-04   100.18   101.20    99.90

嗯,这里要注意一点:DataFrame的每一列其实都是一个Series。所以当你取bond_data['21国债10']时,得到的就是一个Series。这个关系搞清楚了,后面操作起来就顺手多了。

3.2 从CSV读取债券行情数据

实际工作中,债券数据最常见的来源就是CSV文件。交易所每天收盘后会生成一个CSV,里面包含了当天所有债券的行情。我一般用pd.read_csv()来读,但有几个参数必须设对。

先看一个典型的债券行情CSV长什么样:

日期,债券代码,债券简称,收盘价,涨跌幅,成交量
2024-01-02,019640.SH,21国债10,100.25,0.05,50000
2024-01-02,019658.SH,21国债15,101.10,-0.02,32000
2024-01-02,019694.SH,22国债01,99.80,0.10,45000

读取的代码很简单:

import pandas as pd

# 读取CSV文件
df = pd.read_csv('bond_daily_20240102.csv', encoding='utf-8')

print(df.head())

但是!我曾经踩过一个坑——日期列默认会被读成字符串。如果你后面要做时间序列分析,必须把它转成datetime类型:

# 正确做法:指定日期列并解析
df = pd.read_csv(
    'bond_daily_20240102.csv',
    encoding='utf-8',
    parse_dates=['日期'],  # 自动解析日期列
    index_col='日期'       # 把日期列设为索引
)

print(df.info())

避坑指南:我曾经因为没设parse_dates,导致后面画图时日期轴全乱了。还有一次,CSV文件里混了中文逗号(全角),read_csv直接报错。所以建议读取时加上encoding='utf-8-sig',能兼容大部分情况。

3.3 从Excel读取债券数据

有些机构喜欢用Excel存数据,特别是做信用债分析的时候,Excel里经常有多个sheet,每个sheet对应不同评级或不同期限的债券。

读取Excel用pd.read_excel()

# 读取Excel文件
df_excel = pd.read_excel(
    'bond_credit_data.xlsx',
    sheet_name='AAA级',  # 指定sheet
    header=0             # 第一行作为列名
)

print(df_excel.shape)  # 看看有多少行多少列

如果Excel里有多个sheet,可以用sheet_name=None一次性读进来,返回一个字典:

# 读取所有sheet
all_sheets = pd.read_excel('bond_credit_data.xlsx', sheet_name=None)

# 遍历每个sheet
for sheet_name, df_sheet in all_sheets.items():
    print(f"Sheet: {sheet_name}, 行数: {len(df_sheet)}")

我个人习惯用openpyxl引擎来处理Excel,因为它的兼容性最好。如果遇到.xls格式的老文件,记得装xlrd库。

3.4 数据预览与基本信息查看

数据读进来之后,第一件事不是急着分析,而是先看看数据长什么样。我一般会做这几步检查:

3.4.1 快速预览:head()和tail()

# 查看前5行
print(df.head())

# 查看后3行
print(df.tail(3))

head()默认显示前5行,tail()默认显示后5行。你可以传参数指定行数。这个操作能帮你快速判断数据是否正常加载。

3.4.2 基本信息:info()

# 查看数据框基本信息
df.info()

输出类似这样:

<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 1000 entries, 2024-01-02 to 2024-12-31
Data columns (total 5 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   债券代码  1000 non-null   object 
 1   债券简称  1000 non-null   object 
 2   收盘价   998 non-null    float64
 3   涨跌幅   1000 non-null   float64
 4   成交量   1000 non-null   int64  
dtypes: float64(2), int64(1), object(2)
memory usage: 46.9 KB

这里有几个关键信息:

  • 行数和列数:1000行,5列
  • 非空值数量:收盘价只有998个非空,说明有2个缺失值
  • 数据类型:object一般是字符串,float64是浮点数,int64是整数

小技巧:如果发现某列应该是数值型但显示为object,多半是数据里混了字符(比如“--”表示缺失)。可以用pd.to_numeric()强制转换,错误值设为NaN。

3.4.3 统计描述:describe()

# 查看数值列的统计信息
print(df.describe())

输出:

           收盘价        涨跌幅         成交量
count  998.000000  1000.000000  1.000000e+03
mean   100.150000     0.001200  4.200000e+04
std      1.250000     0.015000  1.500000e+04
min     97.500000    -0.050000  1.000000e+04
25%     99.200000    -0.008000  3.000000e+04
50%    100.100000     0.001000  4.000000e+04
75%    101.000000     0.010000  5.200000e+04
max    103.500000     0.060000  8.000000e+04

这个表能告诉你数据的分布情况。比如收盘价最低97.5,最高103.5,均值100.15。如果发现最大值异常高,那就要警惕是不是数据录入错误。

3.4.4 缺失值检查:isnull()

# 检查每列的缺失值数量
print(df.isnull().sum())

# 缺失值占比
print(df.isnull().mean() * 100)

我记得有一次做国债期货分析,发现某天的数据全是NaN。后来查出来是交易所那天休市,但数据文件还是生成了。所以检查缺失值是个好习惯,能避免后面计算时出现莫名其妙的错误。

3.5 本章知识体系

下面这张图总结了本章的核心内容,你可以把它当作一个快速索引:

第3章:Pandas基础与债券数据读取 数据结构 Series(一维) DataFrame(二维) 数据读取 read_csv() read_excel() 数据预览 head() / tail() info() / describe() 关键参数与注意事项 parse_dates:解析日期列 index_col:设置索引列 encoding:处理中文编码 sheet_name:指定Excel工作表 isnull():检查缺失值 dtype:检查数据类型 核心流程 读取数据 → 预览结构 → 检查缺失 → 确认类型 → 开始分析

嗯,到这里Pandas的基础操作就讲完了。说白了就是三板斧:读进来、看一眼、查问题。后面几章我们会在这个基础上做更复杂的操作,比如数据清洗、合并、分组聚合等等。但今天这些基本功,是后面所有操作的地基。

我个人建议你找个真实的债券CSV文件练练手。没有的话,可以用pd.DataFrame()自己造点数据。多试几次,手感就来了。


公众号:蓝海资料掘金营,微信deep3321