NumPy入门:数组创建、数组运算、矩阵操作、随机数生成

做量化交易,说白了就是跟数据打交道。K线数据、因子数据、回测数据……每天面对的都是成千上万的数字。Python自带的列表处理这些数据?嗯,慢得让人抓狂。这时候NumPy就派上用场了。

我个人习惯把NumPy叫做「量化交易的基石」。没有它,后面学Pandas、回测框架都会很吃力。今天我们就把它啃下来。

一、NumPy数组的创建

先说说最基础的东西——怎么创建一个数组。别小看这一步,我在项目中遇到过不少新手因为数组类型搞错,导致后面计算全崩了。

1. 从列表创建

最简单的方式,直接把Python列表传进去:

import numpy as np

# 一维数组
arr1 = np.array([1, 2, 3, 4, 5])
print(arr1)  # [1 2 3 4 5]

# 二维数组(矩阵)
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print(arr2)
# [[1 2 3]
#  [4 5 6]]
小提示:创建数组时最好指定dtype,比如 np.array([1,2,3], dtype=np.float64)。我曾经因为默认整数类型导致除法结果被截断,查了半天bug。

2. 常用创建函数

实际工作中,我们很少手动敲数据。更多是用这些函数:

函数 说明 示例
np.zeros() 创建全0数组 np.zeros((3,4))
np.ones() 创建全1数组 np.ones((2,3))
np.arange() 类似range,返回数组 np.arange(0, 10, 2)
np.linspace() 等间隔取数 np.linspace(0, 1, 5)
np.eye() 单位矩阵 np.eye(3)
# 实战中常用的写法
zeros_arr = np.zeros((10000, 5))  # 1万行5列,初始化因子矩阵
arange_arr = np.arange(100)       # 0到99,做索引用
linspace_arr = np.linspace(0, 1, 50)  # 0到1之间均匀取50个点

二、数组运算

NumPy最爽的地方就是向量化运算。不用写循环,一个符号搞定所有元素。

1. 基本算术运算

数组之间可以直接加减乘除,对应位置元素各自计算:

a = np.array([10, 20, 30, 40])
b = np.array([1, 2, 3, 4])

print(a + b)  # [11 22 33 44]
print(a - b)  # [9 18 27 36]
print(a * b)  # [10 40 90 160]
print(a / b)  # [10. 10. 10. 10.]
重点:向量化运算比Python循环快几十倍。我回测时处理百万级数据,用循环要等几分钟,换成向量化运算秒出结果。

2. 广播机制

不同形状的数组也能运算?没错,这就是广播。说白了,NumPy会自动把小的数组「扩展」成大的形状。

# 标量广播
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr + 100)
# [[101 102 103]
#  [104 105 106]]

# 一维数组广播到二维
row = np.array([10, 20, 30])
print(arr + row)
# [[11 22 33]
#  [14 25 36]]
注意:广播不是万能的。形状不匹配时会报错。比如(3,4)的数组和(3,5)的数组没法广播。我曾经在这上面栽过跟头,写代码前最好先检查一下shape。

3. 统计运算

量化分析离不开统计指标。NumPy提供了全套工具:

data = np.array([1.2, 2.5, 3.8, 4.1, 5.6])

print(np.mean(data))    # 均值:3.44
print(np.std(data))     # 标准差:1.58
print(np.max(data))     # 最大值:5.6
print(np.min(data))     # 最小值:1.2
print(np.percentile(data, 25))  # 25分位数:2.5

三、矩阵操作

量化交易里,矩阵操作太常见了。协方差矩阵、相关系数矩阵、投资组合优化……都离不开它。

1. 矩阵乘法

注意区分 *@

A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

# 对应元素相乘(Hadamard积)
print(A * B)
# [[ 5 12]
#  [21 32]]

# 真正的矩阵乘法
print(A @ B)
# [[19 22]
#  [43 50]]

2. 转置与重塑

这两个操作我几乎每天都要用:

arr = np.array([[1, 2, 3], [4, 5, 6]])

# 转置
print(arr.T)
# [[1 4]
#  [2 5]
#  [3 6]]

# 重塑形状
print(arr.reshape(3, 2))
# [[1 2]
#  [3 4]
#  [5 6]]

# 展平成一维
print(arr.flatten())
# [1 2 3 4 5 6]

3. 矩阵求逆与行列式

做线性回归或优化问题时,经常需要求逆矩阵:

from numpy.linalg import inv, det

M = np.array([[1, 2], [3, 4]])

M_inv = inv(M)  # 求逆
print(M_inv)
# [[-2.   1. ]
#  [ 1.5 -0.5]]

M_det = det(M)  # 行列式
print(M_det)    # -2.0
避坑指南:我曾经在计算投资组合权重时,忘了检查矩阵是否可逆。结果程序跑着跑着就报LinAlgError。现在我的习惯是:求逆之前先算行列式,如果接近0就改用伪逆 np.linalg.pinv()

四、随机数生成

随机数在量化里用途很广:蒙特卡洛模拟、随机游走、回测中的随机抽样……

1. 基本随机数

# 设置种子,保证结果可复现
np.random.seed(42)

# 均匀分布 [0,1)
rand_arr = np.random.rand(3, 4)
print(rand_arr)

# 正态分布
norm_arr = np.random.randn(1000)  # 均值0,标准差1

# 指定范围整数
int_arr = np.random.randint(0, 100, size=10)  # 0到99的10个整数

2. 高级随机分布

做风险分析时,我经常用到这些:

# 二项分布(模拟涨跌次数)
binom_arr = np.random.binomial(n=100, p=0.5, size=10)

# 泊松分布(模拟交易次数)
poisson_arr = np.random.poisson(lam=5, size=20)

# 随机抽样
population = np.array(['A', 'B', 'C', 'D', 'E'])
sample = np.random.choice(population, size=3, replace=False)

3. 随机打乱

做交叉验证或数据洗牌时很有用:

data = np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
np.random.shuffle(data)  # 原地打乱行顺序
print(data)
# 每次运行结果不同

五、知识体系总览

下面这张图是我自己总结的NumPy核心脉络,建议保存下来对照学习:

NumPy核心知识 数组创建 • np.array() • np.zeros() / ones() • np.arange() • np.linspace() • np.eye() 数组运算 • 向量化运算 • 广播机制 • 统计函数 • 聚合操作 矩阵操作 • 矩阵乘法 @ • 转置 .T • 重塑 reshape • 求逆 inv() • 行列式 det() 随机数生成 • 均匀/正态分布 • 二项/泊松分布 • 随机抽样 • 打乱 shuffle 量化交易数据处理的核心工具

嗯,到这里NumPy的核心内容就差不多了。你想想看,数组创建、运算、矩阵操作、随机数,这四个模块基本覆盖了量化交易中90%的数据处理场景。我个人建议你把这些代码都敲一遍,光看是记不住的。

下次遇到数据处理的活儿,先想想能不能用NumPy的向量化操作代替循环。养成这个习惯,你的代码会又快又优雅。


专注资料整理