第3章:Python数据处理基础——pandas核心数据结构与数据清洗实战
各位同学,欢迎来到量化策略自动化全链路实战的第三站。今天我们要聊的,是每个量化工程师都绕不开的吃饭家伙——pandas。说实话,我入行头两年,80%的调试时间都花在数据清洗上。你想想看,策略写得再漂亮,数据一塌糊涂,回测结果就是垃圾进垃圾出。所以这一章,咱们把pandas的底子打扎实。
3.1 核心数据结构:Series与DataFrame
pandas就两个核心数据结构:Series和DataFrame。Series说白了就是一维带标签的数组,DataFrame就是二维表格。我个人习惯把DataFrame想象成Excel里的sheet,Series就是其中一列。
3.1.1 Series:一维数据容器
创建Series很简单,传个列表或字典就行。我在项目中经常用它来存单只股票的收盘价序列。
import pandas as pd
import numpy as np
# 从列表创建
s = pd.Series([100, 102, 101, 105], index=['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04'])
print(s)
# 从字典创建
price_dict = {'2024-01-01': 100, '2024-01-02': 102, '2024-01-03': 101}
s2 = pd.Series(price_dict)
嗯,这里要注意:索引(index)是Series的灵魂。没有索引,数据就是一堆散沙。我见过新手直接把数据塞进去,结果索引自动生成0,1,2...后面做时间序列分析时全乱套了。
3.1.2 DataFrame:二维表格
DataFrame才是我们真正天天打交道的。创建方式很多,最常用的是从字典或CSV读入。
# 从字典创建DataFrame
data = {
'股票代码': ['000001', '000002', '600519'],
'收盘价': [10.5, 20.3, 1500.0],
'成交量': [1000000, 500000, 200000]
}
df = pd.DataFrame(data)
print(df)
# 查看基本信息
print(df.info()) # 数据类型、非空计数
print(df.describe()) # 统计摘要
记得有一次,我接手一个老项目,DataFrame里混着字符串和数字,一算均值直接报错。从那以后,我每次拿到数据第一件事就是跑df.info(),看看各列类型对不对。
核心操作速查:
df.head(n):看前n行,默认5行df.tail(n):看后n行df.columns:获取列名列表df.index:获取行索引df['列名']:选取单列,返回Seriesdf[['列1', '列2']]:选取多列,返回DataFrame
3.2 数据读取与写入:CSV/Excel/数据库
量化交易的数据源五花八门。我最常用的是CSV,因为轻量、通用。但遇到需要给老板汇报时,Excel更友好。数据库嘛,生产环境必备。
3.2.1 CSV文件操作
CSV是量化界的通用语言。我建议你养成一个好习惯:读入时指定parse_dates和index_col,省得后面再转换。
# 读取CSV
df = pd.read_csv('stock_data.csv',
parse_dates=['日期'],
index_col='日期',
encoding='utf-8')
# 写入CSV
df.to_csv('cleaned_data.csv', encoding='utf-8-sig', index=True)
避坑指南:我曾经因为没指定encoding='utf-8-sig',导出的CSV在Excel里中文全乱码。后来我统一用utf-8-sig,再没出过问题。
3.2.2 Excel文件操作
Excel支持多sheet,适合整理不同维度的数据。比如一个文件里,sheet1放日线数据,sheet2放财务指标。
# 读取Excel
df = pd.read_excel('fund_data.xlsx', sheet_name='日线数据')
# 写入Excel,多sheet
with pd.ExcelWriter('output.xlsx') as writer:
df_daily.to_excel(writer, sheet_name='日线数据', index=False)
df_fund.to_excel(writer, sheet_name='财务指标', index=False)
3.2.3 数据库读写
生产环境我一般用SQLite做本地缓存,用MySQL做团队共享。pandas的read_sql和to_sql简直是神器。
from sqlalchemy import create_engine
# 连接SQLite数据库
engine = create_engine('sqlite:///quant.db')
# 从数据库读取
df = pd.read_sql("SELECT * FROM daily_data WHERE date >= '2024-01-01'", engine)
# 写入数据库
df.to_sql('daily_data', engine, if_exists='replace', index=False)
注意:写入数据库时,if_exists参数有三个选项:fail(表存在就报错)、replace(替换)、append(追加)。我建议第一次用replace,后续增量更新用append。
3.3 数据清洗:缺失值、重复值、异常值
数据清洗占了我量化工作中至少40%的时间。你想想看,从交易所拿到的原始数据,经常有停牌日、除权除息、数据缺失等问题。不洗干净,策略回测就是自欺欺人。
3.3.1 缺失值处理
缺失值在pandas里显示为NaN。处理方式就三种:删除、填充、插值。我个人经验是:如果缺失比例小于5%,直接删除;如果大于5%,用前向填充或插值。
# 检查缺失值
print(df.isnull().sum())
# 删除缺失值
df_drop = df.dropna() # 删除任何包含NaN的行
df_drop_col = df.dropna(axis=1) # 删除任何包含NaN的列
# 填充缺失值
df_fill = df.fillna(method='ffill') # 前向填充
df_fill_mean = df.fillna(df.mean()) # 用均值填充
# 插值(适合时间序列)
df_interp = df.interpolate(method='linear')
我的经验:处理股票数据时,停牌日的缺失值用前向填充最合理。因为停牌期间价格不变,用前一天的价格是符合逻辑的。但如果是财务数据,用均值填充更稳妥。
3.3.2 重复值处理
重复数据通常来自数据源重复推送或合并时的错误。我曾经因为没去重,回测时同一笔交易算了两次收益,结果策略收益率虚高20%。
# 检查重复行
print(df.duplicated().sum())
# 查看重复的具体行
print(df[df.duplicated(keep=False)])
# 删除重复行
df_unique = df.drop_duplicates()
# 按指定列去重
df_unique_subset = df.drop_duplicates(subset=['股票代码', '日期'])
嗯,这里keep参数很关键:keep='first'保留第一个,keep='last'保留最后一个,keep=False全部删除。我一般用keep='first',因为最早的数据通常最可靠。
3.3.3 异常值处理
异常值是最头疼的。比如某只股票突然出现-999的收盘价,或者成交量突然放大100倍。这些不处理,策略会做出疯狂决策。
常用的方法有两种:3σ原则和IQR(四分位距)法。
# 3σ原则:超出均值±3倍标准差视为异常
def detect_outliers_zscore(df, column, threshold=3):
z_scores = np.abs((df[column] - df[column].mean()) / df[column].std())
return df[z_scores > threshold]
# IQR方法:超出Q1-1.5*IQR或Q3+1.5*IQR视为异常
def detect_outliers_iqr(df, column):
Q1 = df[column].quantile(0.25)
Q3 = df[column].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
return df[(df[column] < lower_bound) | (df[column] > upper_bound)]
# 处理异常值:替换为上下限
def cap_outliers(df, column):
Q1 = df[column].quantile(0.25)
Q3 = df[column].quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR
df[column] = df[column].clip(lower, upper)
return df
避坑指南:我曾经用3σ原则处理收益率数据,结果发现收益率分布是尖峰厚尾的,3σ把很多正常的极端行情都剔除了。后来我改用IQR方法,效果好了很多。记住:金融数据很少服从正态分布。
3.4 本章知识体系总览
下面这张图是我自己总结的pandas数据处理全流程。你照着这个顺序做,基本不会漏掉关键步骤。
好了,这一章的内容就到这里。pandas的数据处理能力远不止这些,但上面这些已经能覆盖量化交易中90%的场景。你把这些练熟了,后面写策略回测、因子分析都会顺手很多。
公众号:蓝海数据掘金营,微信deep3321