3、Pandas数据处理基础:Series与DataFrame创建、数据读取与写入、缺失值处理、数据排序与排名、数据分组与聚合
做量化投资,说白了就是跟数据打交道。而Pandas,就是咱们手里最趁手的兵器。这一章,我带你把这把兵器磨快。
我个人习惯,拿到任何数据源,第一件事就是把它塞进Pandas里。为什么?因为只有结构化之后,你才能用代码去批量操作、去分析、去挖掘。咱们从最基础的两个数据结构开始。
3.1 Series与DataFrame:数据的骨架
Series就是一列数据,带个索引。DataFrame呢,就是多列Series拼起来的表格。你想想看,股票的历史日线数据,日期是索引,开盘价、收盘价、成交量……每一列都是一个Series,合起来就是DataFrame。
创建起来很简单:
import pandas as pd
import numpy as np
# 创建一个Series
s = pd.Series([100, 102, 101, 105], index=['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04'])
print(s)
# 创建一个DataFrame
data = {
'日期': ['2024-01-01', '2024-01-02', '2024-01-03'],
'收盘价': [100, 102, 101],
'成交量': [10000, 12000, 11000]
}
df = pd.DataFrame(data)
print(df)
嗯,这里要注意:索引不一定是整数。在量化场景里,我几乎总是把日期设为索引。这样后面做时间序列分析、滑动窗口计算,都方便得多。
3.2 数据读取与写入:从文件到内存
真实世界里,数据不会凭空出现。它们躺在CSV文件里、Excel表格里、数据库里。Pandas提供了统一的接口,让你一把拉进来。
# 读取CSV
df = pd.read_csv('stock_data.csv', parse_dates=['日期'], index_col='日期')
# 读取Excel
df = pd.read_excel('stock_data.xlsx', sheet_name='日线数据')
# 写入CSV
df.to_csv('processed_data.csv')
# 写入Excel
df.to_excel('processed_data.xlsx', sheet_name='清洗后')
我曾经踩过一个坑:读取CSV时,日期列被当成字符串读进来了。后来做日期运算,怎么都不对。所以我现在每次读CSV,都会加上 parse_dates=True 或者指定列名。这招帮我省了不少排查时间。
encoding='utf-8' 或 encoding='gbk'。
3.3 缺失值处理:数据清洗的第一关
真实数据,没有完美的。停牌、数据源中断、节假日……都会产生缺失值。你想想看,如果不对缺失值做处理,后面算均值、算收益率,结果全是错的。
Pandas里处理缺失值,核心就两招:
# 检查缺失值
print(df.isnull().sum())
# 方法一:删除含缺失值的行
df_clean = df.dropna()
# 方法二:填充缺失值
df_filled = df.fillna(method='ffill') # 用前一个值填充
df_filled = df.fillna(df.mean()) # 用均值填充
我个人习惯,对于时间序列数据,优先用前向填充(ffill)。因为股票数据,停牌一天,第二天复牌,用前一天的收盘价做填充,逻辑上说得通。但如果是财务数据,我建议用均值或中位数填充,或者干脆删除。
3.4 数据排序与排名:找到好股票的第一步
排序和排名,是量化选股的基础操作。你想找出市盈率最低的10只股票?想按ROE从高到低排序?都得靠它。
# 按收盘价排序
df_sorted = df.sort_values(by='收盘价', ascending=False)
# 按索引排序
df_sorted_index = df.sort_index()
# 排名:给每个值一个名次
df['排名'] = df['市盈率'].rank(ascending=True)
这里有个细节:rank() 方法默认遇到相同值会取平均排名。比如两个并列第一,排名都是1.5。如果你想要严格的名次,可以加参数 method='min' 或 method='dense'。
我记得有一次做因子测试,因为排名方法没选对,导致回测结果偏差很大。后来排查了半天,才发现是 rank() 的默认行为跟我预期的不一样。所以,用之前一定看清楚文档。
3.5 数据分组与聚合:从个股到组合
分组聚合,是量化分析里最强大的操作之一。你想按行业分组,算每个行业的平均市盈率?想按月份分组,算每个月的收益率?都靠它。
# 按行业分组,计算平均市盈率
grouped = df.groupby('行业')['市盈率'].mean()
# 多列聚合
result = df.groupby('行业').agg({
'市盈率': ['mean', 'std'],
'市值': 'sum'
})
# 遍历分组
for industry, group in df.groupby('行业'):
print(f"行业: {industry}, 股票数: {len(group)}")
你想想看,A股有几十个行业,每个行业里几十上百只股票。如果不分组,你怎么对比?怎么发现哪个行业被低估了?
.reset_index() 把分组键变回普通列。否则后面做合并、做可视化,索引层级会让你头疼。
知识体系总览
这一章的内容,说白了就是一条线:从创建数据,到读取数据,到清洗数据,再到排序排名和分组聚合。每一步都是下一步的基础。我画了一张图,帮你理清脉络:
这一章的内容,是后续所有量化策略的基石。你想想看,没有数据清洗,你拿什么算因子?没有分组聚合,你怎么做行业轮动?把这些基础打牢,后面写策略的时候,你会感谢现在的自己。