第三章 Python环境搭建:NumPy基础、Pandas基础、Matplotlib基础、SciPy优化器介绍

说实话,做量化金融这些年,我见过太多人一上来就搞复杂的数学模型,结果连数据都读不进去。嗯,这就像盖房子不打地基。今天咱们就把这四块基石——NumPy、Pandas、Matplotlib、SciPy——彻底搞明白。

核心逻辑:这四兄弟各司其职——NumPy管数值计算,Pandas管数据处理,Matplotlib管可视化,SciPy管优化求解。少了谁都不行。

均值方差优化 Python 技术栈 NumPy 数组运算 矩阵操作 统计函数 Pandas DataFrame 时间序列 数据清洗 Matplotlib 折线图 散点图 子图布局 SciPy 优化器 约束条件 目标函数 数据加载 → 数据清洗 → 计算协方差 → 优化求解 → 可视化结果 ← 数据流方向

3.1 NumPy基础——量化计算的发动机

NumPy,说白了就是Python里的数学引擎。我刚开始做量化时,用纯Python列表算收益率,跑一次要等半天。后来换成NumPy数组,速度直接起飞。

为什么这么快?因为NumPy底层是C语言写的,而且用了向量化操作。你想想看,同样的循环,Python是一步一步走,NumPy是一整片一起算。

核心数据结构:ndarray

import numpy as np

# 创建数组
prices = np.array([100.5, 101.2, 102.8, 103.1])
print(prices.shape)  # (4,)

# 二维数组——模拟多只股票
portfolio = np.array([
    [100.5, 50.2],
    [101.2, 51.0],
    [102.8, 50.8]
])
print(portfolio.shape)  # (3, 2)

我的小技巧:创建数组时尽量指定dtype,比如 np.array([...], dtype=np.float64)。我曾经因为默认整数类型导致收益率计算全错,排查了一下午。

常用统计函数

returns = np.array([0.01, -0.02, 0.015, 0.005])

mean_return = np.mean(returns)      # 平均收益率
std_return = np.std(returns)        # 标准差(风险)
cov_matrix = np.cov(returns)        # 协方差矩阵

print(f"平均收益: {mean_return:.4f}")
print(f"风险: {std_return:.4f}")

这里有个坑——np.cov()默认是按行计算协方差的。如果数据是每列一只股票,记得用rowvar=False。我当年第一次算投资组合方差时,结果怎么都对不上,就是这个参数搞的鬼。

3.2 Pandas基础——数据处理的瑞士军刀

Pandas,说白了就是Excel的超级升级版。我个人习惯把所有行情数据都装进DataFrame里,操作起来特别顺手。

DataFrame入门

import pandas as pd

# 创建DataFrame
data = {
    '日期': ['2024-01-01', '2024-01-02', '2024-01-03'],
    '茅台': [1680.0, 1695.0, 1702.0],
    '五粮液': [135.0, 134.5, 136.2]
}
df = pd.DataFrame(data)
print(df.head())

时间序列处理

# 把日期列转成时间索引
df['日期'] = pd.to_datetime(df['日期'])
df.set_index('日期', inplace=True)

# 计算日收益率
returns = df.pct_change().dropna()
print(returns)

注意pct_change()计算的是百分比变化,不是对数收益率。做均值方差优化时,我建议用对数收益率,因为它在时间上可加性更好。但这里先用简单收益率,方便理解。

数据清洗实战

# 处理缺失值——真实数据里常有停牌
df.fillna(method='ffill', inplace=True)  # 用前一个交易日填充

# 筛选数据
df_filtered = df[df.index >= '2024-01-01']

# 滚动计算
df['20日均线'] = df['茅台'].rolling(window=20).mean()

我曾经处理过一份包含3000只股票的数据,里面有大量缺失值和异常值。用Pandas的链式操作,几行代码就搞定了。要是用Excel,估计得加班到天亮。

3.3 Matplotlib基础——让数据说话

做量化,光有数字不行,得画出来看。Matplotlib就是干这个的。我习惯用它画收益率曲线、有效前沿、还有风险收益散点图。

基础绘图

import matplotlib.pyplot as plt

# 设置中文字体——这个坑我踩过
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 画收益率曲线
plt.figure(figsize=(10, 6))
plt.plot(df.index, df['茅台'], label='茅台', linewidth=2)
plt.plot(df.index, df['五粮液'], label='五粮液', linewidth=2)
plt.title('股票价格走势')
plt.xlabel('日期')
plt.ylabel('价格')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

避坑指南:在Jupyter Notebook里,记得加%matplotlib inline。我曾经在服务器上跑脚本,忘了加这句,结果图全没了,白跑了一整夜。

子图布局——多维度展示

fig, axes = plt.subplots(2, 2, figsize=(12, 8))

# 左上:价格走势
axes[0, 0].plot(df.index, df['茅台'])
axes[0, 0].set_title('价格走势')

# 右上:收益率分布
axes[0, 1].hist(returns['茅台'], bins=20, alpha=0.7)
axes[0, 1].set_title('收益率分布')

# 左下:滚动波动率
axes[1, 0].plot(returns['茅台'].rolling(20).std())
axes[1, 0].set_title('20日滚动波动率')

# 右下:散点图
axes[1, 1].scatter(returns['茅台'], returns['五粮液'], alpha=0.5)
axes[1, 1].set_title('收益率相关性')

plt.tight_layout()
plt.show()

3.4 SciPy优化器介绍——求解最优权重

终于到了最核心的部分。均值方差优化的本质,就是求解一个带约束的优化问题。SciPy的minimize函数就是干这个的。

优化器核心参数

参数 说明 常用值
fun 目标函数(要最小化的东西) 自定义函数
x0 初始猜测值 均匀权重
method 优化算法 'SLSQP', 'trust-constr'
bounds 变量取值范围 (0, 1) 不允许做空
constraints 约束条件 权重之和=1

实战:最小化方差组合

from scipy.optimize import minimize
import numpy as np

# 假设我们有3只股票
returns = np.array([0.12, 0.08, 0.15])  # 年化收益率
cov_matrix = np.array([
    [0.1, 0.02, 0.04],
    [0.02, 0.08, 0.01],
    [0.04, 0.01, 0.12]
])

# 目标函数:组合方差
def portfolio_variance(weights):
    return weights.T @ cov_matrix @ weights

# 约束条件:权重之和为1
constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})

# 变量范围:不允许做空
bounds = tuple((0, 1) for _ in range(3))

# 初始猜测:均匀分配
initial_weights = [1/3, 1/3, 1/3]

# 求解
result = minimize(portfolio_variance, 
                  initial_weights,
                  method='SLSQP',
                  bounds=bounds,
                  constraints=constraints)

print(f"最优权重: {result.x}")
print(f"最小方差: {result.fun:.4f}")

重要提醒:SLSQP方法对初始值敏感。我遇到过多次因为初始值选得不好,结果收敛到局部最优的情况。建议多试几个初始点,或者用basinhopping全局优化器。

优化器选择建议

  • SLSQP:最常用,支持等式和不等式约束。适合中小规模问题。
  • trust-constr:更稳健,适合约束复杂的场景。但速度稍慢。
  • differential_evolution:全局优化,不怕局部最优。但计算量大。

我个人习惯先用SLSQP快速跑一遍,如果结果看起来不对劲,再换trust-constr验证。你想想看,优化器就像工具箱里的扳手,不同场景得用不同的工具。

本章核心要点

  • NumPy的向量化操作是量化计算的基础
  • Pandas的DataFrame让数据处理变得优雅
  • Matplotlib的可视化能帮你快速发现问题
  • SciPy的minimize是求解最优权重的核心工具

好了,这四样工具都备齐了。下一章咱们就要真刀真枪地干——用这些工具实现完整的均值方差优化流程。到时候你会发现,原来那些复杂的数学公式,用代码实现起来其实挺简单的。

专注资料整理