NumPy入门:数组创建与向量化运算

张开发
2026/4/12 10:04:33 15 分钟阅读

分享文章

NumPy入门:数组创建与向量化运算
目录一、 NumPy是什么为什么学它1.1 一个直观的对比1.2 NumPy的核心优势二、 数组创建六脉神剑2.1 从列表、元组创建2.2 用内置函数创建特殊数组2.3 创建等差、等比序列2.4 创建随机数组2.5 创建全为某个常数的数组2.6 从磁盘文件读取三、 向量化运算告别循环3.1 什么是向量化运算3.2 基本算术运算逐元素3.3 比较运算与布尔数组3.4 通用函数Universal Functions3.5 聚合函数沿着轴计算四、 广播机制不同形状数组如何运算4.1 广播的规则4.2 广播实例4.3 广播的限制4.4 手动广播np.newaxis 增加维度五、 高级索引与花式索引5.1 整数数组索引5.2 布尔索引5.3 花式索引组合六、 综合案例股票收益率计算七、 常见陷阱7.1 复制 vs 视图7.2 避免不必要的拷贝7.3 数据类型导致的内存爆炸7.4 使用 np.dot 或 做矩阵乘法一、 NumPy是什么为什么学它1.1 一个直观的对比假设你要计算 [1, 2, 3, ..., 1000000] 每个数的平方再用Python原生列表和NumPy数组分别实现python import numpy as np import time # Python列表循环 data_list list(range(1_000_000)) start time.time() result_list [x**2 for x in data_list] print(f列表循环耗时: {time.time()-start:.4f}秒) # NumPy数组向量化 data_np np.arange(1_000_000) start time.time() result_np data_np ** 2 print(fNumPy向量化耗时: {time.time()-start:.4f}秒) # 输出 列表循环耗时: 0.0892秒 NumPy向量化耗时: 0.0031秒NumPy快了近30倍而且代码更简洁。1.2 NumPy的核心优势特性Python列表NumPy数组存储方式存储对象指针内存不连续存储同类型数值内存连续运算效率逐元素循环Python层开销大C语言实现无Python循环开销维度支持嵌套列表操作繁琐原生支持多维数组轴操作灵活数学函数需要自己写循环直接np.sin, np.exp等总结只要涉及大规模数值计算优先用NumPy。二、 数组创建六脉神剑2.1 从列表、元组创建python import numpy as np # 一维数组 a np.array([1, 2, 3, 4]) print(a) # [1 2 3 4] print(type(a)) # class numpy.ndarray # 二维数组 b np.array([[1, 2], [3, 4], [5, 6]]) print(b) # [[1 2] # [3 4] # [5 6]] print(b.shape) # (3, 2) —— 3行2列 # 指定数据类型 c np.array([1, 2, 3], dtypenp.float32) print(c.dtype) # float32注意尽量保证数组中元素类型一致否则NumPy会统一向上转换int→float。2.2 用内置函数创建特殊数组python # 全零数组 zeros np.zeros((2, 3)) print(zeros) # [[0. 0. 0.] # [0. 0. 0.]] # 全一数组 ones np.ones((3, 2), dtypenp.int64) print(ones) # [[1 1] # [1 1] # [1 1]] # 单位矩阵对角为1 eye np.eye(3) print(eye) # [[1. 0. 0.] # [0. 1. 0.] # [0. 0. 1.]] # 未初始化的数组内容随机速度最快 empty np.empty((2, 2)) print(empty) # 可能是任意值使用时需谨慎2.3 创建等差、等比序列python # arange类似range但返回数组 arr1 np.arange(0, 10, 2) # start, stop, step print(arr1) # [0 2 4 6 8] # linspace等间距取N个点包含终点 arr2 np.linspace(0, 10, 5) # 0到10均匀取5个数 print(arr2) # [ 0. 2.5 5. 7.5 10. ] # logspace对数等间距10的幂次 arr3 np.logspace(0, 2, 5) # 10^0 到 10^2取5个 print(arr3) # [ 1. 3.16 10. 31.62 100. ]2.4 创建随机数组python # 设置随机种子保证结果可复现 np.random.seed(42) # 均匀分布 [0,1) rand_uniform np.random.rand(2, 3) # 2x3 print(rand_uniform) # 标准正态分布 N(0,1) rand_normal np.random.randn(3, 3) print(rand_normal) # 随机整数 [low, high) rand_int np.random.randint(1, 100, size(2, 4)) print(rand_int) # 随机打乱一维数组 arr np.array([1,2,3,4,5]) np.random.shuffle(arr) print(arr)2.5 创建全为某个常数的数组python # 方式1full const np.full((3, 4), 7) print(const) # 3x4全为7 # 方式2ones 乘法不推荐但可以 const2 np.ones((2,2)) * 3.142.6 从磁盘文件读取python # 从CSV或其他文本文件读取简单场景 # 实际大数据集推荐用pandas但NumPy也能做 data np.genfromtxt(data.csv, delimiter,, skip_header1) print(data.shape)创建方法速查表函数说明示例np.array(list)从列表创建np.array([1,2,3])np.zeros(shape)全0np.zeros((2,3))np.ones(shape)全1np.ones((2,3))np.eye(N)单位矩阵np.eye(3)np.arange(start,stop,step)等差数列np.arange(0,10,2)np.linspace(start,stop,num)等间距np.linspace(0,1,5)np.random.rand(d0,d1)[0,1)均匀np.random.rand(2,3)np.random.randn(d0,d1)标准正态np.random.randn(2,3)三、 向量化运算告别循环3.1 什么是向量化运算向量化指的是对整个数组执行批量操作而不需要显式编写循环。NumPy在底层用C语言循环避免了Python的逐元素开销。对比示例python # 传统循环方式 a [1, 2, 3, 4] b [5, 6, 7, 8] c [] for i in range(len(a)): c.append(a[i] b[i]) print(c) # [6, 8, 10, 12] # NumPy向量化方式 a_np np.array([1, 2, 3, 4]) b_np np.array([5, 6, 7, 8]) c_np a_np b_np print(c_np) # [6 8 10 12]3.2 基本算术运算逐元素python x np.array([1, 2, 3]) y np.array([4, 5, 6]) print(加法:, x y) # [5 7 9] print(减法:, x - y) # [-3 -3 -3] print(乘法:, x * y) # [4 10 18] print(除法:, x / y) # [0.25 0.4 0.5] print(幂运算:, x ** y) # [1 32 729] print(取余:, x % y) # [1 2 3] # 标量运算会自动广播 print(x 10) # [11 12 13] print(x * 2) # [2 4 6]3.3 比较运算与布尔数组python scores np.array([85, 92, 78, 90, 88]) # 逐元素比较 print(scores 85) # [False True False True True] # 布尔索引超实用 high_scores scores[scores 85] print(high_scores) # [92 90 88] # 条件组合 (与), | (或), ~ (非) middle scores[(scores 80) (scores 90)] print(middle) # [85 90 88]3.4 通用函数Universal FunctionsNumPy提供了大量数学函数可以直接作用于数组python arr np.array([0, np.pi/2, np.pi]) # 三角函数 print(np.sin(arr)) # [0. 1. 0.] print(np.cos(arr)) # [ 1. 0. -1.] # 指数与对数 print(np.exp(arr)) # e^x print(np.log(arr1)) # ln(x1) # 取整 arr2 np.array([1.2, 2.7, -1.5]) print(np.floor(arr2)) # [ 1. 2. -2.] print(np.ceil(arr2)) # [ 2. 3. -1.] print(np.round(arr2)) # [ 1. 3. -2.] # 绝对值、平方根 print(np.abs(arr2)) print(np.sqrt(np.array([4,9,16]))) # [2. 3. 4.]3.5 聚合函数沿着轴计算python matrix np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) print(总和:, np.sum(matrix)) # 45 print(均值:, np.mean(matrix)) # 5.0 print(最大值:, np.max(matrix)) # 9 print(最小值:, np.min(matrix)) # 1 print(标准差:, np.std(matrix)) # 2.58 print(方差:, np.var(matrix)) # 6.67 # 沿着轴axis计算 # axis0 表示列方向跨行axis1 表示行方向跨列 print(按列求和:, np.sum(matrix, axis0)) # [12 15 18] print(按行求和:, np.sum(matrix, axis1)) # [6 15 24] # 累积和 print(np.cumsum(matrix)) # [1 3 6 10 15 21 28 36 45]轴的理解axis0是垂直方向从上到下axis1是水平方向从左到右。四、 广播机制不同形状数组如何运算4.1 广播的规则当两个数组形状不同时NumPy会尝试广播使它们形状兼容。规则如下1. 从尾部维度开始比较从后往前。2. 如果两个维度相等或其中一个为1或其中一个缺失则兼容。3. 否则报错 ValueError: operands could not be broadcast together。通俗理解小数组会被拉伸到大数组的形状然后逐元素运算。4.2 广播实例python # 例1二维数组 一维数组 A np.array([[1,2,3], [4,5,6]]) B np.array([10,20,30]) print(A B) # [[11 22 33] # [14 25 36]] # 广播过程B被拉伸成 [[10,20,30], [10,20,30]] # 例2二维数组 列向量 C np.array([[1], [2]]) # 形状 (2,1) D np.array([10,20,30]) # 形状 (3,) print(C D) # 形状 (2,3) # [[11 21 31] # [12 22 32]]4.3 广播的限制python # 不兼容的例子 A np.ones((3, 4)) B np.ones((4, 3)) # print(A B) # 报错维度 (3,4) 和 (4,3) 尾部不兼容 # 但以下可以 C np.ones((3, 4, 5)) D np.ones((4, 5)) print((C D).shape) # (3,4,5) 兼容4.4 手动广播np.newaxis 增加维度python x np.array([1,2,3]) # 形状 (3,) y np.array([4,5,6]) # 形状 (3,) # 想计算外积x_i * y_j得到3x3矩阵 # 方法增加维度 x_col x[:, np.newaxis] # 变成 (3,1) y_row y[np.newaxis, :] # 变成 (1,3) outer x_col * y_row print(outer) # [[ 4 5 6] # [ 8 10 12] # [12 15 18]]五、 高级索引与花式索引5.1 整数数组索引python arr np.array([10, 20, 30, 40, 50]) indices [0, 2, 4] print(arr[indices]) # [10 30 50] # 二维示例 matrix np.arange(12).reshape(3, 4) print(matrix) # [[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]] rows [0, 1, 2] cols [3, 1, 2] print(matrix[rows, cols]) # [3, 5, 10] - (0,3), (1,1), (2,2)5.2 布尔索引python data np.random.randn(5) print(data) mask data 0 print(data[mask]) # 只取正数 # 修改满足条件的元素 data[data 0] 0 # 将所有负数置0 print(data)5.3 花式索引组合python arr np.arange(10) # 取不连续的位置 print(arr[[1,3,5,7]]) # [1 3 5 7] # 二维花式索引 matrix np.arange(20).reshape(4,5) print(matrix[[0,2,3], [1,3,4]]) # 取(0,1),(2,3),(3,4)六、 综合案例股票收益率计算让我们用NumPy实战一个金融场景计算股票的日收益率、波动率和夏普比率。python import numpy as np # 模拟某股票20个交易日的收盘价假设数据 np.random.seed(42) prices 100 np.cumsum(np.random.randn(20) * 2) # 随机游走 print(股价:, prices[:5], ...) # 1. 计算每日收益率 (当天收盘/前天收盘 - 1) # 方法向量化避免循环 returns (prices[1:] - prices[:-1]) / prices[:-1] print(日收益率:, returns[:5]) # 2. 计算年化收益率假设252个交易日 annual_return np.mean(returns) * 252 print(f年化收益率: {annual_return*100:.2f}%) # 3. 计算年化波动率风险 annual_volatility np.std(returns) * np.sqrt(252) print(f年化波动率: {annual_volatility*100:.2f}%) # 4. 夏普比率假设无风险利率3% risk_free_rate 0.03 sharpe_ratio (annual_return - risk_free_rate) / annual_volatility print(f夏普比率: {sharpe_ratio:.2f}) # 5. 最大回撤最高点到最低点的最大跌幅 cumulative np.maximum.accumulate(prices) # 历史最高 drawdown (prices - cumulative) / cumulative max_drawdown np.min(drawdown) print(f最大回撤: {max_drawdown*100:.2f}%) # 输出示例 股价: [100. 101.8656 103.39359 104.20067 106.50789] ... 年化收益率: 15.32% 年化波动率: 22.18% 夏普比率: 0.56 最大回撤: -8.74%七、 常见陷阱7.1 复制 vs 视图python arr np.arange(10) # 切片返回的是视图共享内存 slice_view arr[2:5] slice_view[0] 100 print(arr) # [0 1 100 3 4 5 6 7 8 9] 原数组被修改 # 要复制独立数据用 .copy() slice_copy arr[2:5].copy() slice_copy[0] 999 print(arr) # 原数组不变7.2 避免不必要的拷贝python # 坏做法重复创建临时数组 for i in range(1000): result arr i # 每次循环创建新数组 # 好做法原地修改如果允许 arr 1000 # 直接修改原数组无额外内存7.3 数据类型导致的内存爆炸python # 默认float64如果数据范围小用float32或int8 arr np.ones(1000000, dtypenp.int8) # 1MB arr2 np.ones(1000000, dtypenp.float64) # 8MB7.4 使用 np.dot 或 做矩阵乘法python A np.random.rand(100, 200) B np.random.rand(200, 50) # 矩阵乘法不是逐元素乘 C np.dot(A, B) # 或者 A B print(C.shape) # (100, 50)如果这篇文章对你有帮助欢迎点赞、收藏、关注哦

更多文章