4、必备Python库(一):NumPy基础:数组创建、索引与切片、数学运算、随机数生成

各位同学,欢迎来到第四讲。今天咱们聊聊 NumPy。

说实话,在量化交易这个行当里,NumPy 就是你的左膀右臂。我做了这么多年策略开发,几乎每天都要跟它打交道。你想想看,处理行情数据、计算收益率、做回测,哪一步离得开数组运算?

这一讲,我带你快速掌握 NumPy 最核心的四个技能:数组创建、索引与切片、数学运算、随机数生成。别怕,都是干货,上手很快。

NumPy 基础 数组创建 np.array() np.zeros() / np.ones() np.arange() / np.linspace() 索引与切片 一维/多维索引 布尔索引 花式索引 数学运算 逐元素运算 广播机制 统计函数 随机数生成 np.random.randn() np.random.randint()

4.1 数组创建:从零开始造数据

先说说怎么创建数组。我个人习惯,写策略前第一件事就是先把数据装进 NumPy 数组里。

最基础的方法:

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]])
print(arr2)
# [[1 2]
#  [3 4]]

嗯,这里要注意:传入的数据类型要一致。如果混了字符串和数字,NumPy 会全部转成字符串。我在项目中遇到过这种情况,回测时算收益率突然报错,查了半天才发现是数据类型搞混了。

快速生成特殊数组:

# 全零数组
zeros = np.zeros((3, 4))  # 3行4列,全是0

# 全一数组
ones = np.ones((2, 3))    # 2行3列,全是1

# 单位矩阵
eye = np.eye(4)            # 4x4 单位矩阵

# 等差数列
arange_arr = np.arange(0, 10, 2)  # [0 2 4 6 8]

# 等间隔数列
linspace_arr = np.linspace(0, 1, 5)  # [0.   0.25 0.5  0.75 1.  ]
小技巧: 做回测时,我经常用 np.zeros() 来预分配持仓数组,这样比动态追加快得多。你想想看,几百万条数据,用 Python 列表一个个 append,那速度简直没法看。

4.2 索引与切片:精准定位你的数据

说白了,索引就是找数据的位置。NumPy 的索引比 Python 列表强大得多。

一维数组索引:

arr = np.array([10, 20, 30, 40, 50])
print(arr[0])    # 10
print(arr[-1])   # 50
print(arr[1:4])  # [20 30 40]

二维数组索引:

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

print(matrix[0, 1])    # 2(第0行第1列)
print(matrix[1, :])    # [4 5 6](第1行所有列)
print(matrix[:, 2])    # [3 6 9](所有行第2列)
重点: 切片操作返回的是视图,不是副本。修改切片会影响原数组。如果你想要副本,用 .copy() 方法。

我曾经在写策略时踩过这个坑:对切片做了修改,结果原数据也跟着变了,回测结果完全对不上。后来养成了习惯,需要独立数据时一定加 .copy()

布尔索引: 这个在量化里太常用了。

prices = np.array([100, 102, 98, 105, 97])
# 找出所有大于100的价格
high_prices = prices[prices > 100]
print(high_prices)  # [102 105]

你想想看,筛选涨停股、过滤异常数据,布尔索引一行代码搞定。

4.3 数学运算:让数组自己算

NumPy 最爽的地方就是向量化运算。不用写循环,数组自己就能算。

逐元素运算:

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

print(a + b)   # [5 7 9]
print(a * b)   # [4 10 18]
print(a ** 2)  # [1 4 9]
print(np.sqrt(a))  # [1.   1.41 1.73]

广播机制: 说白了,就是形状不同的数组也能做运算。

# 标量广播
arr = np.array([1, 2, 3])
print(arr + 10)  # [11 12 13]

# 一维与二维广播
matrix = np.array([[1, 2, 3],
                   [4, 5, 6]])
row = np.array([10, 20, 30])
print(matrix + row)
# [[11 22 33]
#  [14 25 36]]
注意: 广播不是万能的。形状不匹配时会报错。比如 (3,4) 的数组和 (3,) 的数组做运算,就会出问题。遇到这种情况,先用 .reshape() 调整形状。

统计函数: 做量化必备。

data = np.array([100, 102, 98, 105, 97])

print(np.mean(data))    # 100.4
print(np.std(data))     # 3.2
print(np.max(data))     # 105
print(np.min(data))     # 97
print(np.sum(data))     # 502

计算收益率、波动率,这些函数直接拿来用就行。

4.4 随机数生成:模拟与回测的基石

随机数在量化里用处太大了。蒙特卡洛模拟、随机策略测试、数据增强,都离不开它。

常用随机函数:

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

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

# 标准正态分布
randn_arr = np.random.randn(1000)

# 整数随机
randint_arr = np.random.randint(0, 100, size=10)

# 从数组中随机选择
choices = np.random.choice([1, 2, 3, 4, 5], size=3, replace=False)
经验之谈: 每次做回测前,我都会设置 np.random.seed()。这样别人复现我的结果时,随机数序列完全一致,不会出现「你的结果和我的不一样」这种尴尬情况。

举个例子,用随机数模拟股价走势:

# 模拟100天的收益率(正态分布)
returns = np.random.randn(100) * 0.01  # 日波动率1%
# 计算累计价格
price = 100 * np.cumprod(1 + returns)
print(price[:5])  # 前5天的价格

嗯,这个例子虽然简单,但蒙特卡洛模拟的核心思想就在里面了。

4.5 实战小练习:计算移动平均线

光说不练假把式。咱们用 NumPy 实现一个简单的 5 日移动平均线。

prices = np.array([100, 102, 101, 105, 103, 107, 106])

# 方法1:手动计算
ma5_manual = np.array([
    np.mean(prices[i:i+5]) for i in range(len(prices)-4)
])
print(ma5_manual)  # [102.2 103.6 104.4]

# 方法2:用卷积(更高效)
ma5_conv = np.convolve(prices, np.ones(5)/5, mode='valid')
print(ma5_conv)    # [102.2 103.6 104.4]

你看,用 np.convolve 一行代码就搞定了。我在实盘策略里就是这么写的,速度比循环快几十倍。


好了,这一讲的内容就到这里。NumPy 的基础操作你基本都掌握了。记住:数组创建是起点,索引切片是工具,数学运算是核心,随机数是武器。把这四个点练熟,后面的 Pandas 和回测框架学起来会轻松很多。

有什么问题,欢迎随时交流。咱们下节课见。

专注资料整理