在金融数据分析这条路上Pandas 几乎是绕不开的核心工具。无论是处理行情数据、计算技术指标还是构建回归模型、回测交易策略Pandas 都承担着数据清洗、转换、聚合和统计分析的基础工作。近期整理了一份港科大 Python 金融统计课程的学习笔记内容从 Pandas 基础操作一直延伸到回归策略实现本文把这条学习路径做一个系统梳理并给出可以直接运行的代码示例与实战项目适合正在学习 Python 数据分析、量化入门以及想系统掌握 Pandas 的读者。1. 为什么金融统计要从 Pandas 开始很多初学者在接触量化交易或金融数据分析时第一反应是去背各种策略公式或者直接跳到机器学习模型。但实际上金融数据分析的核心难点从来不是模型本身而是数据准备。真实场景中的金融数据通常存在以下问题数据来自多个源格式不统一。存在缺失值、重复值、异常值。时间序列需要对齐、重采样、频率转换。需要按股票、行业、日期等多个维度进行分组聚合。数据量较大需要高效的内存处理方式。Pandas 正是为了解决这些问题而设计的。它提供了两种核心数据结构Series 和 DataFrame分别对应一维和二维结构化数据。在金融统计课程中Pandas 被用于从数据读取、清洗、探索性统计到回归建模前的特征工程承担了数据流水线的主体工作。从港科大这门课程的内容设置来看它的学习路径非常清晰Python 基础语法 ↓ Pandas 数据处理 ↓ 金融数据获取与清洗 ↓ 描述性统计与可视化 ↓ 回归分析与统计检验 ↓ 交易策略构建与回测这条路径的优点在于每一步都在上一轮的基础上做叠加当走到回归策略时前面的数据处理能力已经足够支撑完整的分析闭环。对于自学的人而言这也是值得参考的路线。2. 环境准备与版本说明在开始之前先把运行环境准备好。本文的代码基于以下环境版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。项目推荐环境操作系统Windows 10/11、macOS、Linux 均可Python3.8 - 3.11Pandas1.5.x 或 2.0.xNumPy1.24.x 或更新版本statsmodels0.14.xmatplotlib3.7.xIDEPyCharm、VS Code、Jupyter Notebook 均可2.1 安装 Python如果机器上还没有 Python推荐直接从官网下载安装包。Windows 用户安装时务必勾选 “Add Python to PATH”否则后面在命令行中执行 python 命令会提示找不到。安装完成后打开终端或命令行输入以下命令验证python --version pip --version看到版本号输出说明安装成功。2.2 安装 Pandas 及相关库使用 pip 一次性安装本文所需的所有依赖pip install pandas numpy statsmodels matplotlib openpyxl如果只需要基础的数据处理功能pandas 和 numpy 就够用了。statsmodels 用于回归分析和统计检验matplotlib 用于绘图openpyxl 用于读写 Excel 文件。如果安装速度慢可以切换为国内镜像源pip install pandas numpy statsmodels matplotlib openpyxl -i https://pypi.tuna.tsinghua.edu.cn/simple2.3 验证安装在 Python 交互环境或 IDE 中执行import pandas as pd import numpy as np import statsmodels.api as sm print(pd.__version__) print(np.__version__)能正常输出版本号说明环境没有问题。需要特别提醒的是Python 3.12 及更高版本发布时部分第三方库可能还来不及同步适配如果安装 pandas 或 statsmodels 时报二进制依赖错误建议退回 Python 3.10 或 3.11 版本兼容性最稳定。3. Pandas 核心概念与高频操作这一节梳理金融统计中最常用的 Pandas 操作。这些操作会贯穿整个课程和后续的策略实现。3.1 Series 与 DataFrameSeries 是一维带标签数组可以理解为一个带索引的列表。DataFrame 是二维表格结构包含行索引和列名是金融数据处理中最常用的数据结构。创建一个示例 DataFrameimport pandas as pd data { stock: [000001, 000001, 600000, 600000], date: [2024-01-02, 2024-01-03, 2024-01-02, 2024-01-03], close: [10.5, 10.8, 7.2, 7.5], volume: [100000, 120000, 80000, 95000] } df pd.DataFrame(data) print(df)输出结果stock date close volume 0 000001 2024-01-02 10.5 100000 1 000001 2024-01-03 10.8 120000 2 600000 2024-01-02 7.2 80000 3 600000 2024-01-03 7.5 950003.2 数据类型转换金融数据中经常遇到类型问题价格被读成字符串、日期不是 datetime 类型、成交量包含千分位逗号等。最常见的需求是把字符串日期转成时间类型把数字字符串转成浮点数。df[date] pd.to_datetime(df[date]) df[close] df[close].astype(float) print(df.dtypes)输出stock object date datetime64[ns] close float64 volume int64 dtype: objectPandas 中有一个经典陷阱当 Series 中包含缺失值 NaN 时astype(float) 没问题但 astype(int) 会报错。此时需要先处理缺失值再转换类型。另一个常见需求是“指定两列的值均相同则只保留一条记录”这属于重复值处理使用 drop_duplicates 即可实现。df df.drop_duplicates(subset[stock, date])subset 参数指定判断重复的列只有当这些列的值都相同时才视为重复行。3.3 数据筛选与条件查询金融数据经常需要按日期范围、价格区间、股票代码进行筛选。按条件筛选# 只保留收盘价大于 8 元的记录 df_filtered df[df[close] 8] # 按日期范围筛选 df_range df[(df[date] 2024-01-02) (df[date] 2024-01-03)] # 使用 isin 筛选多个股票 df_stocks df[df[stock].isin([000001, 600000])]这里要注意一点Pandas 中表示“且”|表示“或”必须用括号把每个条件包起来。新手经常在这里写错比如写成df[df[close] 8 and df[volume] 90000]这会直接抛出 ValueError。3.4 分组聚合按股票分组计算均值、求和、标准差是金融统计的日常操作。grouped df.groupby(stock).agg( avg_close(close, mean), total_volume(volume, sum), std_close(close, std) ) print(grouped)输出avg_close total_volume std_close stock 000001 10.65 220000 0.212132 600000 7.35 175000 0.212132groupby 之后使用 agg 方法可以同时对不同列执行不同聚合函数并重命名结果列非常适合快速生成统计报表。3.5 缺失值处理金融数据中缺失值非常常见比如停牌日、未成交数据、指标计算出现 NaN 等。常用处理方式方法适用场景代码示例删除缺失行缺失比例很低df.dropna()向前填充时间序列用上一期值填充df.fillna(methodffill)向后填充时间序列用下一期值填充df.fillna(methodbfill)用均值填充数值型数据缺失比例不高df.fillna(df.mean())用中位数填充存在极端值或偏态分布df.fillna(df.median())时间序列数据中向前填充ffill是最常用的方式之一。例如计算收益率时遇到停牌日可以用前一个交易日的收盘价继续参与计算。4. 金融数据获取与预处理实战在进入回归和策略之前先做一个完整的金融数据预处理案例。这里使用在线 API 获取真实行情数据然后完成类型转换、排序、去重、缺失值处理、计算收益率等步骤。由于不同数据源的接口变动较频繁本文以 tushare 为例演示思路你需要注册账号并获取 token。也可以替换为其他你熟悉的数据源。4.1 安装数据源库pip install tushare4.2 获取股票行情数据import tushare as ts import pandas as pd # 设置 token需要提前在 tushare 官网注册 ts.set_token(你的token) pro ts.pro_api() # 获取平安银行 2024 年 1 月到 6 月的日线行情 df pro.daily( ts_code000001.SZ, start_date20240101, end_date20240630 ) # 按日期升序排列 df df.sort_values(trade_date).reset_index(dropTrue) print(df.head())输出示例ts_code trade_date open high low close pre_close change pct_chg vol amount 0 000001.SZ 20240102 9.50 9.65 9.40 9.58 9.50 0.08 0.84 500000 4.8e05 1 000001.SZ 20240103 9.60 9.70 9.50 9.55 9.58 -0.03 -0.31 480000 4.6e054.3 日期格式与索引设置将 trade_date 转成 datetime 类型并设置为 DataFrame 的索引。df[trade_date] pd.to_datetime(df[trade_date]) df df.set_index(trade_date).sort_index()4.4 计算日收益率日收益率有两种常见计算方式简单收益率和对数收益率。简单收益率直接用当日收盘价与前一日收盘价相除再减 1对数收益率使用自然对数差适合需要可加性的统计分析场景。df[simple_return] df[close].pct_change() df[log_return] np.log(df[close] / df[close].shift(1))pct_change 是 Pandas 内置函数本质是(当前值 - 上一值) / 上一值。shift(1) 表示把整个 Series 向下平移一个位置实现“取前一天收盘价”的效果。4.5 处理首日 NaN第一行因为前一天没有数据收益率必然是 NaN。对于回归分析或策略信号计算可以将其删除也可以填充为 0。df df.dropna(subset[simple_return, log_return])5. 从描述性统计到回归分析完成数据清洗后下一步是统计分析和建模。5.1 描述性统计使用 describe 方法快速查看核心统计量print(df[simple_return].describe())输出示例count 118.000000 mean 0.000214 std 0.013456 min -0.040123 25% -0.006540 50% 0.000312 75% 0.007823 max 0.037891 Name: simple_return, dtype: float645.2 滚动窗口与波动率估计金融统计中经常使用滚动窗口计算移动平均线和滚动波动率。滚动波动率通常是收益率的滚动标准差再乘以年化因子。# 20 日滚动均值 df[ma20] df[close].rolling(window20).mean() # 20 日滚动标准差用于衡量波动率 df[vol20] df[simple_return].rolling(window20).std() * np.sqrt(252)这里乘以np.sqrt(252)是因为 A 股一年大约有 252 个交易日日波动率乘以交易日数量的平方根即可近似转换为年化波动率。5.3 线性回归建模回归分析在金融统计中用途广泛估计股票的 Beta 系数、检验因子与收益率的关系、构建多因子模型等。以 CAPM 模型的简化形式为例用市场收益率解释个股收益率[ R_i \alpha \beta \times R_m \varepsilon ]先准备一组示例数据。这里用沪深 300 指数收益率代表市场收益率import statsmodels.api as sm # 构造示例数据个股收益率和市场收益率 # 实际项目中需要从数据源分别下载 import numpy as np np.random.seed(42) n 200 market_return np.random.normal(0.0002, 0.01, n) stock_return 0.0001 1.2 * market_return np.random.normal(0, 0.005, n) df_model pd.DataFrame({ stock_return: stock_return, market_return: market_return })添加常数项并拟合 OLS 回归X sm.add_constant(df_model[market_return]) y df_model[stock_return] model sm.OLS(y, X).fit() print(model.summary())statsmodels 会输出包含系数、标准误、t 值、P 值、R-squared 等内容的完整回归结果。其中coef列中的 market_return 系数就是 Beta 估计值const就是 Alpha 估计值。如果 P 值小于 0.05通常认为该系数在统计上显著。课程中对回归结果的解读顺序是先看 R-squared 了解模型的解释力度再看各系数的符号、大小和显著性最后结合业务含义判断是否符合金融逻辑。5.4 回归结果的业务解读举例说明假设输出 Beta 1.2P 值 0.01含义是市场收益率每变动 1%该股票的平均收益率大约同方向变动 1.2%。Beta 大于 1 说明该股票的波动幅度大于市场整体属于进攻型品种Beta 小于 1 则相对稳健。Alpha 0.0001 且 P 值不显著时说明在样本区间内没有证据表明该股票存在显著的超额收益。这一步是从“会跑代码”到“会做分析”的关键转折。很多初学者能输出回归结果表格但不知道如何解读拿到数据后一片空白。金融统计课程的价值正是在这里不仅教函数更教如何把统计量翻译成投资含义。6. 从回归结果到简单交易策略回归分析本身不会直接产生交易信号但可以用于构建因子再根据因子值与阈值生成买卖信号。下面构建一个完整的单因子策略示例。6.1 策略思路使用股票的动量因子作为选股依据。动量因子的计算方式是最近 N 日的累计收益率[ momentum \frac{P_t}{P_{t-N}} - 1 ]如果动量因子大于 0说明最近表现强势买入小于 0说明表现弱势卖出或空仓。这是一个简化的趋势跟踪策略示例。6.2 构造动量因子df[momentum_20] df[close] / df[close].shift(20) - 1 df df.dropna(subset[momentum_20])6.3 生成交易信号df[signal] 0 df.loc[df[momentum_20] 0, signal] 1 df.loc[df[momentum_20] 0, signal] -1这里 signal 的取值含义是1持有或买入。-1卖出或做空如果只想做单边做多可以把负值设为 0。0空仓。6.4 计算策略日收益率策略收益率的计算方式是信号乘以下一期的实际收益率这样做是为了避免前视偏差。前视偏差是回测中最常见的低级错误用当天的信号直接乘以当天的收益率相当于“偷看未来”。正确的写法df[strategy_return] df[signal].shift(1) * df[simple_return] df df.dropna(subset[strategy_return])shift(1) 的作用是把信号向后移动一天表示“昨天收盘计算的信号今天开盘或收盘执行”。6.5 累计收益对比计算策略累计净值和基准累计净值df[strategy_cum] (1 df[strategy_return]).cumprod() df[benchmark_cum] (1 df[simple_return]).cumprod() print(df[[strategy_cum, benchmark_cum]].tail())6.6 可视化对比使用 matplotlib 绘制策略累计净值与基准累计净值曲线import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False df[[strategy_cum, benchmark_cum]].plot(figsize(10, 6)) plt.title(动量策略 vs 基准累计净值) plt.xlabel(日期) plt.ylabel(累计净值) plt.legend([策略, 基准]) plt.grid(True) plt.show()这里之所以设置 SimHei 字体是因为 matplotlib 默认字体在中文环境下会显示方框需要显式指定中文字体。完整策略代码汇总如下方便直接复制运行import pandas as pd import numpy as np import matplotlib.pyplot as plt # 假设 df 已经是通过数据源获取并清洗后的日线数据 # 列close, simple_return # 1. 计算动量因子 df[momentum_20] df[close] / df[close].shift(20) - 1 # 2. 生成交易信号 df[signal] 0 df.loc[df[momentum_20] 0, signal] 1 df.loc[df[momentum_20] 0, signal] -1 # 3. 计算策略收益率避免前视偏差 df[strategy_return] df[signal].shift(1) * df[simple_return] # 4. 删除空值 df df.dropna(subset[momentum_20, strategy_return]) # 5. 计算累计净值 df[strategy_cum] (1 df[strategy_return]).cumprod() df[benchmark_cum] (1 df[simple_return]).cumprod() # 6. 输出策略表现指标 total_return df[strategy_cum].iloc[-1] - 1 annual_return df[strategy_cum].iloc[-1] ** (252 / len(df)) - 1 sharpe df[strategy_return].mean() / df[strategy_return].std() * np.sqrt(252) max_drawdown (df[strategy_cum] / df[strategy_cum].cummax() - 1).min() print(f累计收益: {total_return:.2%}) print(f年化收益: {annual_return:.2%}) print(f夏普比率: {sharpe:.2f}) print(f最大回撤: {max_drawdown:.2%})输出示例数据来源不同会有所差异累计收益: 12.35% 年化收益: 18.72% 夏普比率: 1.25 最大回撤: -8.47%6.7 策略代码存在的问题上面这个策略可以运行但只是最小示例离可实盘还有相当大的距离。主要问题包括没有考虑交易成本真实场景中买卖佣金、印花税、滑点会显著吞噬收益。信号更新频率低20 日动量每天都会变动容易造成频繁交易。没有设置止盈止损极端行情下回撤可能很大。没有进行样本外测试和参数敏感性分析20 日窗口是主观设定的。单标的策略随机性大结论难以推广到全市场。在课程后续进阶部分会逐步加入交易成本、多标的组合、参数优化和样本外验证。这些改进让策略从“课堂作业”逐步接近“可评估的量化模型”。7. 常见问题与排查思路7.1 Pandas 安装失败问题现象常见原因解决思路pip install pandas速度慢或超时网络原因使用国内镜像源安装时出现Microsoft Visual C报错Windows 缺少 C 运行库安装 Visual C Build ToolsPython 3.12 安装 pandas 失败版本过新部分依赖未适配使用 Python 3.10 或 3.11ModuleNotFoundError: No module named pandas未安装或 IDE 解释器不一致检查当前 Python 环境并执行 pip 安装7.2 日期类型相关报错问题现象常见原因解决思路TypeError: Cannot compare type Timestamp with type str日期列不是 datetime 类型先pd.to_datetime()再比较时间筛选结果为空日期字符串格式不匹配统一为YYYY-MM-DD格式KeyError: trade_date列名与代码不一致检查df.columns实际列名7.3 分组聚合常见错误问题现象常见原因解决思路TypeError: agg() missing 1 required positional argument: funcagg 未传聚合函数agg(mean)或agg({close: mean})分组后索引混乱groupby 默认将分组列设为索引使用as_indexFalse重置索引聚合结果出现 NaN原始数据包含缺失值先处理缺失值再聚合7.4 回归与统计模块相关报错问题现象常见原因解决思路ModuleNotFoundError: No module named statsmodels未安装pip install statsmodelsValueError: endog and exog matrices are different sizesy 和 X 长度不一致检查是否存在 NaN 行未删除Perfect separation detected数据存在完全线性可分检查特征是否存在重复或共线性8. 最佳实践与工程建议最后补充一些工程层面的建议这些内容在课程视频中未必会详细讲但在实际项目和面试中经常被问到。8.1 数据清洗优先于建模建模之前先把数据质量做扎实。课程中至少 60% 的时间花在 Pandas 数据处理上原因是真实数据远比喻气中的干净数据复杂。一个建议在任何回归或策略之前先跑一遍 describe、info、isnull().sum()对数据形成整体认知。8.2 避免前视偏差回测中最致命的错误是前视偏差。所有信号必须基于当时已经存在的信息不能使用未来数据。标准做法是用shift(1)把信号滞后一天再与收益率相乘。8.3 分离数据探索与策略回测建议用 Jupyter Notebook 做数据探索和可视化用 Python 脚本或类封装策略回测逻辑。Notebook 方便交互但难以进行版本管理和自动化测试项目落地时把核心代码抽取为独立的 .py 文件。8.4 交易成本不可忽略任何策略回测都应加入交易成本模型。A 股市场中单边交易成本通常在万分之几到千分之一之间加上冲击成本高频交易的损耗相当可观。课程作业中的策略如果不计成本真实运行时结果可能截然不同。8.5 使用 assert 做数据验证数据管道中多用 assert 检查数据质量例如assert df[close].isnull().sum() 0, close 列存在缺失值 assert (df[close] 0).all(), close 列存在非正值 assert df.index.is_monotonic_increasing, 索引不是单调递增这些断言可以在数据出问题时快速暴露错误避免带着脏数据一路跑到策略结果才发现异常。8.6 代码规范与可维护性金融分析代码同样需要结构化。建议至少拆分为project/ ├── data/ │ └── load_data.py ├── indicators/ │ └── momentum.py ├── strategy/ │ └── backtest.py ├── analysis/ │ └── regression.py └── main.py每个模块只做一件事函数命名使用动词开头例如load_stock_data()、calculate_momentum()、generate_signal()、run_backtest()。8.7 版本锁定与复现数据分析项目应该记录依赖版本。使用 requirements.txt 锁定环境pip freeze requirements.txt这样换一台机器、隔一段时间再来运行也能复现结果不会因为 Pandas 或 NumPy 升级导致结果变化。9. 继续进阶的方向如果已经能独立完成从数据获取、处理、统计到简单策略回测的整个流程接下来可以沿着以下方向继续深入多因子模型把动量、价值、波动率等多个因子组合起来使用多元回归确定因子权重。时间序列建模从线性回归转向 ARIMA、GARCH 等金融时间序列模型关注收益率波动聚集性。组合优化基于均值-方差模型或风险平价模型做资产配置。事件研究与绩效归因分析特定事件对股价的影响拆解策略收益来源。回测框架工程化把回测逻辑封装成框架支持参数扫描、多标的并发、交易成本模型等。课程学习的意义不只是掌握函数而是建立一套从问题到数据的分析思维方式。拿到任何金融数据都知道应该如何清洗、如何探索、如何建模、如何验证这种能力比记住某个 API 重要得多。如果这篇文章对你有帮助欢迎收藏备用后续会继续整理金融统计与量化策略相关的实战内容。