作者:数据小c适合人群:零基础Python学习者、NLP/ML入门者
一、NumPy入门
1.1 NumPy是什么?
NumPy(Numerical Python)是Python科学计算的基础库,提供了:
NumPy vs Python列表:
# Python列表:每个元素是独立对象a = [1, 2, 3, 4]b = [x * 2for x in a] # 需要循环# NumPy:向量化操作import numpy as npa = np.array([1, 2, 3, 4])b = a * 2# 直接运算
1.2 安装与配置
# pip安装pip install numpy# conda安装(推荐)conda install numpy# 换源安装(国内加速)pip install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy
1.3 验证安装
import numpy as np# 查看版本print(np.__version__) # 1.24.0 或更高# 验证基本功能arr = np.array([1, 2, 3])print(arr) # [1 2 3]
二、数组创建
2.1 从Python列表/元组创建
import numpy as np# 一维数组arr1d = np.array([1, 2, 3, 4, 5])print("一维数组:", arr1d)# 输出: [1 2 3 4 5]# 二维数组arr2d = np.array([[1, 2, 3], [4, 5, 6]])print("二维数组:\n", arr2d)# 输出:# [[1 2 3]# [4 5 6]]# 指定数据类型arr_int = np.array([1, 2, 3], dtype=np.float32)print("float32数组:", arr_int) # [1. 2. 3.]# 从元组创建arr_tuple = np.array((1, 2, 3))print("从元组:", arr_tuple) # [1 2 3]
2.2 占位符创建函数
import numpy as np# 全0数组zeros_1d = np.zeros(5)print("全0一维:", zeros_1d)# 输出: [0. 0. 0. 0. 0.]zeros_2d = np.zeros((3, 4))print("全0二维:\n", zeros_2d)# 输出:# [[0. 0. 0. 0.]# [0. 0. 0. 0.]# [0. 0. 0. 0.]]# 全1数组ones_1d = np.ones(5)print("全1一维:", ones_1d)# 输出: [1. 1. 1. 1. 1.]ones_2d = np.ones((2, 3, 4)) # 2个3行4列的数组print("全1三维形状:", ones_2d.shape) # (2, 3, 4)# 未初始化数组(随机值,依赖内存状态)empty_arr = np.empty((2, 3))print("未初始化:\n", empty_arr)# 输出: 内存中的随机值# 填充指定值full_arr = np.full((2, 3), 7)print("填充7:\n", full_arr)# 输出:# [[7 7 7]# [7 7 7]]
2.3 数值范围创建
import numpy as np# arange:类似rangearr1 = np.arange(10)print("arange(10):", arr1)# 输出: [0 1 2 3 4 5 6 7 8 9]arr2 = np.arange(1, 10, 2) # 起始1,结束10,步长2print("arange(1,10,2):", arr2)# 输出: [1 3 5 7 9]arr3 = np.arange(10, 1, -2) # 倒序print("arange(10,1,-2):", arr3)# 输出: [10 8 6 4 2]# linspace:等间距数组arr4 = np.linspace(0, 1, 5) # 0到1之间等距取5个点print("linspace(0,1,5):", arr4)# 输出: [0. 0.25 0.5 0.75 1. ]
2.4 特殊矩阵
import numpy as np# 单位矩阵eye_3 = np.eye(3)print("3x3单位矩阵:\n", eye_3)# 输出:# [[1. 0. 0.]# [0. 1. 0.]# [0. 0. 1.]]identity_4 = np.identity(4)print("4x4单位矩阵:\n", identity_4)# 对角矩阵diag_arr = np.diag([1, 2, 3, 4])print("对角矩阵:\n", diag_arr)# 输出:# [[1 0 0 0]# [0 2 0 0]# [0 0 3 0]# [0 0 0 4]]# 获取对角元素arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])print("对角元素:", np.diag(arr))# 输出: [1 5 9]
2.5 随机数组创建
import numpy as np# [0, 1)均匀分布rand_arr = np.random.rand(3, 4)print("均匀分布[0,1):\n", rand_arr)# 输出: 3x4的随机数矩阵# 标准正态分布(均值0,标准差1)randn_arr = np.random.randn(3, 4)print("标准正态分布:\n", randn_arr)# 指定范围内的整数随机数组randint_arr = np.random.randint(0, 10, (3, 4)) # [0, 10)的整数print("随机整数[0,10):\n", randint_arr)# 输出: 3x4的整数矩阵,每个元素0-9# 指定均值和标准差的正态分布normal_arr = np.random.normal(100, 15, (3, 4)) # 均值100,标准差15print("正态分布(100,15):\n", normal_arr)# 从给定数组随机选择choices = np.random.choice([1, 2, 3, 4, 5], size=10)print("随机选择:", choices)# 输出: 长度为10的数组,元素来自[1,2,3,4,5]# 打乱顺序arr = np.array([1, 2, 3, 4, 5])np.random.shuffle(arr) # 原地打乱print("打乱后:", arr)# 设置随机种子(可重复)np.random.seed(42)arr1 = np.random.rand(5)np.random.seed(42)arr2 = np.random.rand(5)print("相同种子:", np.array_equal(arr1, arr2)) # True
2.6 其他创建方式
import numpy as np# fromfunction:通过函数生成defmy_func(i, j):return i + jarr = np.fromfunction(my_func, (3, 4), dtype=int)print("fromfunction:\n", arr)# 输出:# [[0 1 2 3]# [1 2 3 4]# [2 3 4 5]]# fromstring:从字符串arr = np.fromstring("1 2 3 4 5", dtype=int, sep=' ')print("fromstring:", arr)# 输出: [1 2 3 4 5]# 使用索引生成arr = np.diag(np.arange(3, 6)) # 对角线上是3,4,5print("索引对角:\n", arr)# 输出:# [[3 0 0]# [0 4 0]# [0 0 5]]
三、数组属性
3.1 核心属性
import numpy as nparr = np.array([[1, 2, 3], [4, 5, 6]])print("形状 (shape):", arr.shape) # (2, 3) - 2行3列print("维度数 (ndim):", arr.ndim) # 2print("元素总数 (size):", arr.size) # 6print("数据类型 (dtype):", arr.dtype) # int64print("单元素字节 (itemsize):", arr.itemsize) # 8print("总字节数 (nbytes):", arr.nbytes) # 48# strides:跨维度步长print("跨维度步长 (strides):", arr.strides)# 输出: (24, 8) - 行间跳24字节,列间跳8字节
3.2 数据类型
import numpy as np# 查看数据类型arr = np.array([1, 2, 3])print("默认整数类型:", arr.dtype) # int64 或 int32arr = np.array([1.0, 2.0, 3.0])print("默认浮点类型:", arr.dtype) # float64# 创建时指定类型arr_int8 = np.array([1, 2, 127], dtype=np.int8)print("int8:", arr_int8, arr_int8.dtype)arr_uint32 = np.array([1, 2, 3], dtype=np.uint32)print("uint32:", arr_uint32, arr_uint32.dtype)arr_float32 = np.array([1.0, 2.0, 3.0], dtype=np.float32)print("float32:", arr_float32, arr_float32.dtype)# 复数类型arr_complex = np.array([1+2j, 3+4j], dtype=complex)print("复数:", arr_complex)# 布尔类型arr_bool = np.array([True, False, True], dtype=bool)print("布尔:", arr_bool)# 字符串类型arr_str = np.array(['hello', 'world'], dtype='<U10') # Unicode,最大10字符print("字符串:", arr_str)
3.3 类型转换
import numpy as nparr = np.array([1.5, 2.7, 3.9])# 转换为整数(截断)arr_int = arr.astype(np.int32)print("转int32:", arr_int) # [1 2 3]# 转换为浮点arr_float = arr.astype(np.float32)print("转float32:", arr_float) # [1.5 2.7 3.9]# 字符串转数值arr_str = np.array(['1.5', '2.7', '3.9'])arr_num = arr_str.astype(float)print("字符串转float:", arr_num) # [1.5 2.7 3.9]# 数值转字符串arr = np.array([1, 2, 3])arr_str = arr.astype(str)print("转字符串:", arr_str) # ['1' '2' '3']
四、数组索引与切片
4.1 一维数组索引
import numpy as nparr = np.array([0, 1, 2, 3, 4, 5])print("完整数组:", arr) # [0 1 2 3 4 5]print("第一个元素:", arr[0]) # 0print("最后一个元素:", arr[-1]) # 5# 切片print("arr[1:4]:", arr[1:4]) # [1 2 3]print("arr[:3]:", arr[:3]) # [0 1 2]print("arr[3:]:", arr[3:]) # [3 4 5]print("arr[::2]:", arr[::2]) # [0 2 4] - 步长2print("arr[::-1]:", arr[::-1]) # [5 4 3 2 1 0] - 反转# 负索引切片print("arr[-3:-1]:", arr[-3:-1]) # [3 4]
4.2 多维数组索引
import numpy as nparr2d = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])print("原数组:\n", arr2d)# [[ 1 2 3 4]# [ 5 6 7 8]# [ 9 10 11 12]]# 获取元素print("arr2d[0, 0]:", arr2d[0, 0]) # 1 - 第一行第一列print("arr2d[2, 3]:", arr2d[2, 3]) # 12 - 第三行第四列print("arr2d[-1, -1]:", arr2d[-1, -1]) # 12 - 最后一行最后一列# 获取行print("第一行:", arr2d[0]) # [1 2 3 4]print("最后一行:", arr2d[-1]) # [ 9 10 11 12]# 获取列print("第一列:", arr2d[:, 0]) # [1 5 9]print("最后一列:", arr2d[:, -1]) # [ 4 8 12]# 切片组合print("前两行,前三列:\n", arr2d[:2, :3])# [[1 2 3]# [5 6 7]]print("后两行:\n", arr2d[-2:, :])# [[ 5 6 7 8]# [ 9 10 11 12]]print("奇数行:\n", arr2d[::2, :])# [[ 1 2 3 4]# [ 9 10 11 12]]
4.3 布尔索引
import numpy as nparr = np.array([1, 2, 3, 4, 5, 6])# 条件索引print("arr > 3:", arr[arr > 3]) # [4 5 6]print("arr % 2 == 0:", arr[arr % 2 == 0]) # [2 4 6]# 多条件mask = (arr > 2) & (arr < 6)print("2 < arr < 6:", arr[mask]) # [3 4 5]# 注意:条件需要括号,且用 & 而不是 and# 错误写法:arr > 2 and arr < 6# 否定print("不满足条件的:", arr[~(arr > 3)]) # [1 2 3]# 布尔数组运算bool_arr = np.array([True, False, True, False, True, False])print("True元素:", arr[bool_arr]) # [1 3 5]
4.4 高级索引
import numpy as nparr = np.arange(12).reshape(3, 4)print("原数组:\n", arr)# [[ 0 1 2 3]# [ 4 5 6 7]# [ 8 9 10 11]]# 整数数组索引indices = np.array([0, 2])print("取第0行和第2行:\n", arr[indices])# [[ 0 1 2 3]# [ 8 9 10 11]]# 二维索引(选择对角元素)row_idx = np.array([0, 1, 2])col_idx = np.array([0, 1, 2])print("对角元素:", arr[row_idx, col_idx]) # [0 5 10]# np.ix_ 组合索引print("使用ix_:\n", arr[np.ix_([0, 2], [0, 2])])# [[ 0 2]# [ 8 10]]# 使用整数列表print("arr[[0, 1], [0, 1]]:", arr[[0, 1], [0, 1]]) # [0 5]# 修改值arr[[0, 2], [0, 0]] = 100print("修改后:\n", arr)# [[100 1 2 3]# [ 4 5 6 7]# [100 9 10 11]]
五、数组形状操作
5.1 reshape
import numpy as nparr = np.arange(12)print("原数组:", arr) # [0 1 2 3 4 5 6 7 8 9 10 11]# 改为3行4列arr_3x4 = arr.reshape(3, 4)print("3x4:\n", arr_3x4)# [[ 0 1 2 3]# [ 4 5 6 7]# [ 8 9 10 11]]# 改为2行6列arr_2x6 = arr.reshape(2, 6)print("2x6:\n", arr_2x6)# 改为4行3列arr_4x3 = arr.reshape(4, 3)print("4x3:\n", arr_4x3)# 改为3维数组arr_3d = arr.reshape(2, 3, 2)print("3维形状:", arr_3d.shape) # (2, 3, 2)# -1自动计算arr_auto = arr.reshape(-1, 4) # 自动计算行数:12/4=3print("-1自动(3,4):\n", arr_auto)arr_auto2 = arr.reshape(3, -1) # 自动计算列数:12/3=4print("-1自动(3,4)2:\n", arr_auto2)
5.2 flatten vs ravel
import numpy as nparr = np.arange(12).reshape(3, 4)print("原数组:\n", arr)# flatten:返回副本flat_copy = arr.flatten()flat_copy[0] = 100print("flatten后修改副本第一个元素:", flat_copy[0]) # 100print("原数组未变:", arr[0, 0]) # 0# ravel:返回视图(尽量不复制)view = arr.ravel()view[0] = 100print("ravel后修改视图第一个元素:", view[0]) # 100print("原数组被修改:", arr[0, 0]) # 100# 性能对比import timebig_arr = np.arange(1000000).reshape(1000, 1000)start = time.time()_ = big_arr.flatten()print("flatten耗时:", time.time() - start)start = time.time()_ = big_arr.ravel()print("ravel耗时:", time.time() - start)# ravel通常更快
5.3 转置与轴操作
import numpy as nparr = np.arange(12).reshape(3, 4)print("原数组:\n", arr)# [[ 0 1 2 3]# [ 4 5 6 7]# [ 8 9 10 11]]# 转置 Tprint("转置T:\n", arr.T)# [[ 0 4 8]# [ 1 5 9]# [ 2 6 10]# [ 3 7 11]]# swapaxesprint("交换轴(1,0):\n", arr.swapaxes(1, 0))# 与T相同# moveaxis:移动轴位置arr_3d = np.arange(24).reshape(2, 3, 4) # (batch, row, col)print("3D形状:", arr_3d.shape) # (2, 3, 4)# 将最后一轴移到最前:(batch, row, col) -> (col, batch, row)arr_transposed = np.moveaxis(arr_3d, -1, 0)print("移动后形状:", arr_transposed.shape) # (4, 2, 3)
5.4 合并与分割
import numpy as npa = np.array([1, 2, 3])b = np.array([4, 5, 6])# concatenate:沿轴拼接print("concatenate:", np.concatenate([a, b])) # [1 2 3 4 5 6]# vstack:垂直堆叠(行方向)arr_v = np.vstack([a, b])print("vstack:\n", arr_v)# [[1 2 3]# [4 5 6]]# hstack:水平堆叠(列方向)arr_h = np.hstack([a, b])print("hstack:", arr_h) # [1 2 3 4 5 6]# column_stack:列堆叠a2 = np.array([[1, 2], [3, 4]])b2 = np.array([[5, 6], [7, 8]])print("column_stack:\n", np.column_stack([a2, b2]))# [[1 2 5 6]# [3 4 7 8]]# 分割arr = np.arange(12)print("原数组:", arr) # [ 0 1 2 3 4 5 6 7 8 9 10 11]# split按位置分割parts = np.split(arr, [3, 7])print("split([3,7]):", parts)# [array([0, 1, 2]), array([3, 4, 5, 6]), array([ 7, 8, 9, 10, 11])]# hsplit水平分割arr_2d = np.arange(12).reshape(3, 4)print("原2D:\n", arr_2d)left, right = np.hsplit(arr_2d, [2])print("hsplit [2]:\n", left, "\n", right)# vsplit垂直分割top, bottom = np.vsplit(arr_2d, [2])print("vsplit [2]:\n", top, "\n", bottom)
六、数组运算
6.1 基础数学运算
import numpy as nparr = np.array([1, 2, 3, 4, 5])print("原数组:", arr)print("+5:", arr + 5) # [ 6 7 8 9 10]print("-2:", arr - 2) # [-1 0 1 2 3]print("*3:", arr * 3) # [ 3 6 9 12 15]print("/2:", arr / 2) # [0.5 1. 1.5 2. 2.5]print("**2:", arr ** 2) # [ 1 4 9 16 25]print("//2:", arr // 2) # [0 1 1 2 2]print("%2:", arr % 2) # [1 0 1 0 1]# 2D数组arr2d = np.array([[1, 2], [3, 4]])print("\n2D数组:\n", arr2d)print("+10:\n", arr2d + 10)# [[11 12]# [13 14]]
6.2 元素级运算函数
import numpy as npa = np.array([1, 2, 3])b = np.array([4, 5, 6])print("a:", a, "b:", b)print("add:", np.add(a, b)) # [5 7 9]print("subtract:", np.subtract(b, a)) # [3 3 3]print("multiply:", np.multiply(a, b)) # [ 4 10 18]print("divide:", np.divide(a, b)) # [0.25 0.4 0.5]print("mod:", np.mod(b, a)) # [0 1 0]print("power:", np.power(a, 2)) # [1 4 9]print("sqrt:", np.sqrt(a)) # [1. 1.41421356 1.73205081]
6.3 聚合函数
import numpy as nparr = np.array([1, 2, 3, 4, 5])print("数组:", arr)print("sum:", arr.sum()) # 15print("mean:", arr.mean()) # 3.0print("std:", arr.std()) # 1.4142135623730951print("var:", arr.var()) # 2.0print("min:", arr.min()) # 1print("max:", arr.max()) # 5print("argmin:", arr.argmin()) # 0print("argmax:", arr.argmax()) # 4print("median:", np.median(arr)) # 3.0# 2D聚合arr2d = np.array([[1, 2, 3], [4, 5, 6]])print("\n2D数组:\n", arr2d)print("所有元素sum:", arr2d.sum()) # 21print("每列sum:", arr2d.sum(axis=0)) # [5 7 9]print("每行sum:", arr2d.sum(axis=1)) # [ 6 15]print("所有元素mean:", arr2d.mean()) # 3.5print("每列mean:", arr2d.mean(axis=0)) # [2.5 3.5 4.5]print("每行mean:", arr2d.mean(axis=1)) # [2. 5.]
6.4 三角函数
import numpy as nparr = np.array([0, np.pi/6, np.pi/4, np.pi/3, np.pi/2])print("角度数组:", arr)print("sin:", np.sin(arr)) # [0. 0.5 0.70710678 0.8660254 1. ]print("cos:", np.cos(arr)) # [1.00000000e+00 8.66025404e-01 7.07106781e-01 5.00000000e-01 6.123233995736766e-17]print("tan:", np.tan(arr)) # [0.00000000e+00 5.77350269e-01 1.00000000e+00 1.73205081e+00 1.63312394e+16]# 反三角函数arr = np.array([0, 0.5, 0.707, 0.866, 1])print("\n反三角:")print("arcsin:", np.arcsin(arr))print("arccos:", np.arccos(arr))print("arctan:", np.arctan(arr))
6.5 指数与对数
import numpy as nparr = np.array([1, 2, 3, 4, 5])print("数组:", arr)print("exp:", np.exp(arr)) # [ 2.71828183 7.3890561 20.08553692 54.59815003 148.4131591 ]print("exp2:", np.exp2(arr)) # [ 2. 4. 8. 16. 32.]print("log (ln):", np.log(arr)) # [0. 0.69314718 1.09861229 1.38629436 1.60943791]print("log2:", np.log2(arr)) # [0. 1. 1.5849625 2. 2.32192809]print("log10:", np.log10(arr)) # [0. 0.30103 0.47712125 0.60205999 0.69897 ]
6.6 统计函数
import numpy as nparr = np.array([1, 2, 3, 4, 5])print("数组:", arr)print("cumsum:", np.cumsum(arr)) # [ 1 3 6 10 15] - 累加和print("cumprod:", np.cumprod(arr)) # [ 1 2 6 24 120] - 累乘积print("diff:", np.diff(arr)) # [1 1 1 1] - 差分# 直方图data = np.array([1, 1, 2, 2, 3, 3, 3, 4, 5])hist, bins = np.histogram(data, bins=[1, 2, 3, 4, 5, 6])print("直方图计数:", hist) # [2 2 3 1 1]print("直方图边界:", bins) # [1 2 3 4 5 6]# 百分位数arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])print("25%分位:", np.percentile(arr, 25)) # 3.25print("50%分位:", np.percentile(arr, 50)) # 5.5print("75%分位:", np.percentile(arr, 75)) # 7.75
七、广播机制
7.1 什么是广播?
广播允许不同形状的数组进行运算,NumPy自动扩展小数组以匹配大数组。
import numpy as np# 最简单的广播:标量与数组arr = np.array([1, 2, 3])print("数组 + 标量:", arr + 5)# [6 7 8] - 标量5被广播为[5,5,5]
7.2 广播规则
从后向前比较维度:
import numpy as np# 案例1:形状相等,直接运算a = np.array([[1, 2, 3], [4, 5, 6]]) # (2,3)b = np.array([[1, 1, 1], [2, 2, 2]]) # (2,3)print("(2,3) + (2,3):\n", a + b)# 案例2:一个维度为1,自动扩展a = np.array([[1, 2, 3]]) # (1,3)b = np.array([[1, 2, 3], [4, 5, 6]]) # (2,3)print("(1,3) + (2,3):\n", a + b)# [[2 4 6]# [5 7 9]]# 案例3:行向量与矩阵a = np.arange(4).reshape(4, 1) # (4,1)b = np.arange(4) # (4,)print("(4,1) + (4,):\n", a + b)# [[0 1 2 3]# [1 2 3 4]# [2 3 4 5]# [3 4 5 6]]# 案例4:三维广播a = np.arange(24).reshape(2, 3, 4) # (2,3,4)b = np.arange(4).reshape(1, 1, 4) # (1,1,4)print("3D广播形状:", (a + b).shape) # (2,3,4)
7.3 无法广播的案例
import numpy as np# 形状不兼容a = np.array([[1, 2, 3]]) # (1,3)b = np.array([[1, 2], [3, 4]]) # (2,2)try: print(a + b)except ValueError as e: print("错误:", e)# ValueError: operands could not be broadcast together
7.4 实用场景
import numpy as np# 场景1:行归一化X = np.array([[1, 2, 3], [4, 5, 6]], dtype=float)X_normalized = X - X.mean(axis=1, keepdims=True)print("行归一化:\n", X_normalized)# [[-1. -0. 1.]# [-1. -0. 1.]]# 场景2:列归一化X_norm_col = X - X.mean(axis=0, keepdims=True)print("列归一化:\n", X_norm_col)# [[-1.5 -1.5 -1.5]# [ 1.5 1.5 1.5]]# 场景3:加偏置向量W = np.random.randn(10, 100) # 权重x = np.random.randn(100) # 输入b = np.zeros(10) # 偏置output = W @ x + b # b自动广播# 场景4:计算距离矩阵points = np.array([[0, 0], [1, 1], [2, 2]])dist = points[:, np.newaxis, :] - points[np.newaxis, :, :]print("距离矩阵形状:", dist.shape) # (3, 3, 2)
八、矩阵运算
8.1 矩阵乘法
import numpy as npA = np.array([[1, 2], [3, 4]])B = np.array([[5, 6], [7, 8]])print("A:\n", A)print("B:\n", B)# @运算符(Python 3.5+)print("A @ B:\n", A @ B)# [[19 22]# [43 50]]# np.dot函数print("np.dot(A, B):\n", np.dot(A, B))# 方法调用print("A.dot(B):\n", A.dot(B))
8.2 逐元素乘法 vs 矩阵乘法
import numpy as npA = np.array([[1, 2], [3, 4]])B = np.array([[5, 6], [7, 8]])print("逐元素乘法 A * B:\n", A * B)# [[ 5 12]# [21 32]]print("矩阵乘法 A @ B:\n", A @ B)# [[19 22]# [43 50]]
8.3 常用矩阵运算
import numpy as npA = np.array([[4, 2], [3, 1]])print("矩阵A:\n", A)# 行列式det = np.linalg.det(A)print("行列式:", det) # -2.0# 逆矩阵inv = np.linalg.inv(A)print("逆矩阵:\n", inv)# [[-0.5 1. ]# [ 1.5 -2. ]]# 验证 A @ A^{-1} = Iprint("A @ A^{-1}:\n", A @ inv)# 接近单位矩阵# 特征值分解eigenvalues, eigenvectors = np.linalg.eig(A)print("特征值:", eigenvalues)print("特征向量:\n", eigenvectors)# 奇异值分解B = np.array([[1, 2], [3, 4], [5, 6]])U, S, Vt = np.linalg.svd(B)print("SVD - U shape:", U.shape, "S shape:", S.shape, "Vt shape:", Vt.shape)# QR分解Q, R = np.linalg.qr(B)print("QR分解 - Q shape:", Q.shape, "R shape:", R.shape)# 范数vec = np.array([3, 4])print("L2范数:", np.linalg.norm(vec)) # 5.0# 解线性方程组 Ax = bA = np.array([[1, 1], [2, 1]])b = np.array([3, 5])x = np.linalg.solve(A, b)print("解x:", x) # [2. 1.]print("验证:", np.allclose(A @ x, b)) # True
8.4 向量运算
import numpy as npa = np.array([1, 2, 3])b = np.array([4, 5, 6])print("a:", a, "b:", b)# 点积dot = np.dot(a, b)print("点积 dot(a, b):", dot) # 1*4 + 2*5 + 3*6 = 32# 叉积(仅3D或2D)a_3d = np.array([1, 0, 0])b_3d = np.array([0, 1, 0])cross = np.cross(a_3d, b_3d)print("叉积 cross(a, b):", cross) # [0 0 1]# 外积outer = np.outer(a, b)print("外积 outer(a, b):\n", outer)# [[ 4 5 6]# [ 8 10 12]# [12 15 18]]# 内积inner = np.inner(a, b)print("内积 inner(a, b):", inner) # 32(同dot)
九、文件IO
9.1 保存与加载
import numpy as npimport os# 保存单个数组arr = np.array([1, 2, 3, 4, 5])np.save('arr.npy', arr)# 加载loaded = np.load('arr.npy')print("加载:", loaded) # [1 2 3 4 5]# 保存多个数组arr1 = np.array([1, 2, 3])arr2 = np.array([4, 5, 6])np.savez('arrays.npz', a=arr1, b=arr2)# 加载data = np.load('arrays.npz')print("a:", data['a']) # [1 2 3]print("b:", data['b']) # [4 5 6]# 清理os.remove('arr.npy')os.remove('arrays.npz')
9.2 文本文件
import numpy as npimport os# 保存为CSVarr = np.array([[1, 2, 3], [4, 5, 6]])np.savetxt('arr.csv', arr, delimiter=',')np.savetxt('arr.txt', arr, delimiter='\t')# 加载CSVloaded = np.loadtxt('arr.csv', delimiter=',')print("CSV加载:\n", loaded)# 指定数据类型loaded = np.loadtxt('arr.csv', delimiter=',', dtype=int)# 使用genfromtxt处理缺失值data_str = "1,2,3\n4,,6\n7,8,9"with open('missing.csv', 'w') as f: f.write(data_str)loaded = np.genfromtxt('missing.csv', delimiter=',')print("缺失值处理:", loaded)# [[ 1. 2. 3.]# [ 4. nan 6.]# [ 7. 8. 9.]]# 清理os.remove('arr.csv')os.remove('arr.txt')os.remove('missing.csv')
9.3 结构化数组
import numpy as np# 定义结构dtype = [('name', 'U10'), ('age', 'i4'), ('weight', 'f4')]people = np.zeros(3, dtype=dtype)# 赋值people['name'] = ['Alice', 'Bob', 'Charlie']people['age'] = [25, 30, 35]people['weight'] = [55.5, 80.0, 70.0]print("结构化数组:\n", people)print("Names:", people['name'])print("Ages:", people['age'])
十、常见报错与解决方案
10.1 安装类报错
# 报错1:No module named numpy# 解决:# pip install numpy# 或 conda install numpy# 或换源# pip install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy# 报错2:NumPy 2.x兼容问题# 解决:降级# pip install numpy<2# 或升级相关库# pip install --upgrade scikit-learn
10.2 数据类型报错
import numpy as np# 报错:TypeError: ufunc 'add' did not contain a loop...# 原因:对字符串数组进行数学运算arr_str = np.array(['1', '2', '3'], dtype=str)print("字符串数组:", arr_str)# 解决:转换为数值类型arr_float = arr_str.astype(float)result = arr_float + 1.0print("转换后加1:", result) # [2. 3. 4.]
10.3 形状相关报错
import numpy as np# 报错:ValueError: operands could not be broadcast together# 原因:形状不匹配且无法广播a = np.array([1, 2, 3]) # (3,)b = np.array([[1, 2], [3, 4]]) # (2,2)# 解决1:调整形状a_2d = a.reshape(1, 3) # (1,3)b_2d = b[:2, :3] # (2,3)print("调整后:", a_2d + b_2d)# 解决2:用 np.newaxisprint("newaxis:", a[np.newaxis, :] + b)print("newaxis:", a[:, np.newaxis] + b)
10.4 索引报错
import numpy as np# 报错:IndexError: index x is out of boundsarr = np.array([1, 2, 3])# arr[5] # 报错!# 解决:检查索引范围print("索引范围:", len(arr)) # 3print("有效索引: 0到", len(arr)-1) # 0到2# 报错:TypeError: only integer scalar arrays can be converted...# 原因:用数组而不是标量索引indices = np.array([0, 1])arr = np.array([[1, 2, 3], [4, 5, 6]])# 正确用法print("正确索引:", arr[indices, indices]) # [1 5]print("ix_用法:\n", arr[np.ix_(indices, indices)])
10.5 布尔索引报错
import numpy as np# 报错:IndexError: boolean index did not match...arr = np.array([[1, 2], [3, 4], [5, 6]])# 布尔数组长度必须与被索引维度匹配bool_idx_3 = np.array([True, False, True]) # 长度3,匹配第一维print("正确用法:", arr[bool_idx_3, :])# [[1 2]# [5 6]]# 错误:bool长度不匹配# bool_idx_2 = np.array([True, False]) # 长度2,不匹配3# arr[bool_idx_2, :] # 报错!
十一、性能优化技巧
11.1 向量化优先
import numpy as npimport timearr = np.random.rand(1000000)# ❌ 慢:Python循环start = time.time()result_loop = [np.sin(x) for x in arr]time_loop = time.time() - startprint(f"循环: {time_loop:.4f}秒")# ✅ 快:向量化start = time.time()result_vec = np.sin(arr)time_vec = time.time() - startprint(f"向量化: {time_vec:.4f}秒")print(f"加速比: {time_loop/time_vec:.1f}x")
11.2 避免不必要复制
import numpy as nparr = np.arange(1000000).reshape(1000, 1000)# ❌ 创建副本arr2 = arr + 0# 或 arr * 1# ✅ 原地操作arr += 0# ✅ fill方法arr.fill(0)# ✅ 视图而非副本view = arr.reshape(100, 100, 100) # 共享内存copy = view.copy() # 显式复制
11.3 内存连续性
import numpy as nparr = np.arange(12).reshape(3, 4)[:, :2]print("C连续:", arr.flags['C_CONTIGUOUS']) # False# 强制转为C连续arr_c = np.ascontiguousarray(arr)print("转C连续后:", arr_c.flags['C_CONTIGUOUS']) # True# 或Fortran连续arr_f = np.asfortranarray(arr)print("转F连续后:", arr_f.flags['F_CONTIGUOUS']) # True
11.4 数据类型选择
import numpy as npimport sys# float64 vs float32arr_f64 = np.random.rand(1000, 1000).astype(np.float64)arr_f32 = arr_f64.astype(np.float32)print("float64内存:", sys.getsizeof(arr_f64) / 1024 / 1024, "MB")print("float32内存:", sys.getsizeof(arr_f32) / 1024 / 1024, "MB")# float32约节省一半内存
11.5 使用原地函数
import numpy as nparr = np.arange(1000000).astype(float)# ❌ 非原地arr = arr + 5# ✅ 原地arr += 5# ✅ fill(最快)arr = np.empty(1000000)arr.fill(5) # 比 arr = np.full() 更快
11.6 聚合函数axis优化
import numpy as nparr = np.random.rand(1000, 1000)# 按行求和(axis=1)通常比按列快row_sums = arr.sum(axis=1)# 保持维度row_sums_kept = arr.sum(axis=1, keepdims=True) # shape (1000, 1)
11.7 性能测试
import numpy as npimport time# 方法1:手动计时A = np.random.rand(1000, 1000)B = np.random.rand(1000, 1000)start = time.time()C = A @ Bprint(f"矩阵乘法: {time.time()-start:.4f}秒")# 方法2:cProfile# import cProfile# cProfile.run('A @ B', sort='cumulative')# 方法3:ipython %timeit# %timeit A @ B
十二、高级用法
12.1 nditer迭代器
import numpy as nparr = np.arange(12).reshape(3, 4)print("原数组:\n", arr)print("迭代访问:")for x in np.nditer(arr): print(x, end=' ')# 0 1 2 3 4 5 6 7 8 9 10 11# 修改元素arr_copy = np.arange(12).reshape(3, 4)for x in np.nditer(arr_copy, op_flags=['readwrite']): x[...] = x ** 2print("\n平方后:\n", arr_copy)
12.2 where函数
import numpy as nparr = np.array([1, 2, 3, 4, 5])# 条件替换result = np.where(arr > 3, arr, 0)print("where(arr>3, arr, 0):", result) # [0 0 0 4 5]# 三目运算result = np.where(arr > 2, 'big', 'small')print("where三目:", result) # ['small' 'small' 'big' 'big' 'big']# 二维示例arr2d = np.array([[1, 2, 3], [4, 5, 6]])result = np.where(arr2d > 3, arr2d, -1)print("2D where:\n", result)# [[-1 -1 -1]# [ 4 5 6]]
12.3 clip截断
import numpy as nparr = np.array([1, 2, 10, 8, 3, 12, 0])# 限制在[2, 7]范围内clipped = np.clip(arr, 2, 7)print("clip(2,7):", clipped)# [ 2 2 7 7 3 7 2]
12.4 any与all
import numpy as nparr = np.array([True, False, True])print("any:", np.any(arr)) # True - 至少一个Trueprint("all:", np.all(arr)) # False - 不是全True# 用于条件判断arr = np.array([1, 2, 3, 4, 5])if np.any(arr > 10): print("有大于10的")if np.all(arr > 0): print("全为正")
12.5 排序
import numpy as nparr = np.array([3, 1, 4, 1, 5, 9, 2, 6])# 排序sorted_arr = np.sort(arr)print("排序:", sorted_arr) # [1 1 2 3 4 5 6 9]# 原地排序arr_copy = arr.copy()arr_copy.sort()print("原地排序:", arr_copy)# 返回排序索引indices = np.argsort(arr)print("排序索引:", indices) # [1 3 0 2 4 6 7 5]# 部分排序:第k小的元素在正确位置kth = np.partition(arr, 3)print("partition(3):", kth) # 前3小的元素无序排列# 2D数组排序arr2d = np.array([[3, 1, 2], [6, 5, 4], [9, 8, 7]])print("按行排序:\n", np.sort(arr2d, axis=1))print("按列排序:\n", np.sort(arr2d, axis=0))
12.6 搜索与唯一值
import numpy as nparr = np.array([1, 2, 3, 2, 1, 4, 2, 5])# 找值的位置print("2的位置:", np.where(arr == 2)) # (array([1, 3, 6]),)# 最大最小索引print("最大索引:", np.argmax(arr)) # 5print("最小索引:", np.argmin(arr)) # 0# 唯一值unique = np.unique(arr)print("唯一值:", unique) # [1 2 3 4 5]# 带计数唯一值unique, counts = np.unique(arr, return_counts=True)print("唯一值和计数:", dict(zip(unique, counts)))# {1: 2, 2: 3, 3: 1, 4: 1, 5: 1}# 判断元素是否在数组中arr1 = np.array([1, 2, 3, 4, 5])arr2 = np.array([2, 4, 6])mask = np.in1d(arr1, arr2)print("arr1中在arr2里的:", arr1[mask]) # [2 4]
十三、NumPy在NLP/ML中的典型应用
13.1 词向量表示
import numpy as np# 词表大小10000,嵌入维度300vocab_size, embedding_dim = 10000, 300# 随机初始化词向量embeddings = np.random.randn(vocab_size, embedding_dim) * 0.01print("词向量形状:", embeddings.shape) # (10000, 300)# 获取词向量word_id = 42word_embedding = embeddings[word_id]print("第42个词的向量形状:", word_embedding.shape) # (300,)
13.2 One-Hot编码
import numpy as npdefone_hot(index, vocab_size):"""将索引转换为one-hot向量""" vec = np.zeros(vocab_size) vec[index] = 1return vec# 示例vocab_size = 5print("索引2的one-hot:", one_hot(2, vocab_size)) # [0. 1. 0. 0. 0.]print("索引0的one-hot:", one_hot(0, vocab_size)) # [1. 0. 0. 0. 0.]# 批量one-hotbatch_indices = np.array([0, 2, 3])batch_size, vocab_size = len(batch_indices), 5one_hot_batch = np.eye(vocab_size)[batch_indices]print("批量one-hot:\n", one_hot_batch)
13.3 相似度计算
import numpy as npdefcosine_similarity(a, b):"""计算余弦相似度"""return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))# 示例词向量word_vecs = np.array([ [0.1, 0.2, 0.3], # 词0 [0.4, 0.5, 0.6], # 词1 [0.11, 0.21, 0.31] # 词2(接近词0)])print("词0和词1相似度:", cosine_similarity(word_vecs[0], word_vecs[1]))print("词0和词2相似度:", cosine_similarity(word_vecs[0], word_vecs[2]))# 词0和词2相似度更高# 批量计算:词与所有词的相似度query = word_vecs[0]similarities = np.dot(word_vecs, query) / (np.linalg.norm(word_vecs, axis=1) * np.linalg.norm(query))print("词0与所有词的相似度:", similarities)
13.4 Softmax实现
import numpy as npdefsoftmax(x):"""数值稳定的softmax""" exp_x = np.exp(x - np.max(x)) # 减去最大值避免溢出return exp_x / exp_x.sum()# 示例logits = np.array([3.0, 1.0, 0.2])print("Softmax:", softmax(logits))print("和为1:", softmax(logits).sum()) # 1.0# 批量softmaxlogits_batch = np.array([[3.0, 1.0, 0.2], [1.0, 2.0, 3.0]])exp_batch = np.exp(logits_batch - np.max(logits_batch, axis=1, keepdims=True))softmax_batch = exp_batch / exp_batch.sum(axis=1, keepdims=True)print("批量Softmax:\n", softmax_batch)
13.5 批处理
import numpy as np# 模拟batch_size=32, seq_len=100, embedding_dim=300batch_size, seq_len, embedding_dim = 32, 100, 300batch = np.random.randn(batch_size, seq_len, embedding_dim)print("批次形状:", batch.shape) # (32, 100, 300)# 取前10个词first_10 = batch[:, :10, :]print("前10词:", first_10.shape) # (32, 10, 300)# 取最后一个词(通常用于分类任务)last hidden = batch[:, -1, :]print("最后隐藏:", last_hidden.shape) # (32, 300)# 掩码:忽略paddingmask = np.array([1, 1, 1, 1, 1, 0, 0, 0, 0, 0]) # 前5个有效valid_outputs = batch[:, :5, :] # 只取有效位置print("有效输出:", valid_outputs.shape) # (32, 5, 300)
13.6 矩阵运算实现神经网络层
import numpy as np# 全连接层:y = Wx + bclassLinear:def__init__(self, input_dim, output_dim): self.W = np.random.randn(input_dim, output_dim) * 0.01 self.b = np.zeros(output_dim)defforward(self, x):return x @ self.W + self.b# 示例linear = Linear(input_dim=300, output_dim=100)x = np.random.randn(32, 10, 300) # batch=32, seq_len=10, embed=300y = linear.forward(x)print("全连接输出形状:", y.shape) # (32, 10, 100)
十四、总结速查表
14.1 创建函数速查
| |
|---|
np.array([1,2,3]) | |
np.zeros((2,3)) | |
np.ones((2,3)) | |
np.arange(10) | |
np.linspace(0,1,5) | |
np.eye(3) | |
np.random.rand(3,4) | |
np.random.randn(3,4) | |
np.random.randint(0,10,(3,4)) | |
14.2 属性速查
| |
|---|
arr.shape | |
arr.ndim | |
arr.dtype | |
arr.size | |
arr.itemsize | |
arr.strides | |
14.3 常用操作速查
| |
|---|
| arr.reshape(3,4) |
| arr.T |
| np.concatenate([a,b]) |
| arr.sum(axis=0) |
| arr.mean() |
| arr.max() |
| A @ B |
| np.dot(a,b) |
| np.save('arr.npy',arr) |
| np.load('arr.npy') |
14.4 常见错误对照
| | |
|---|
No module named numpy | | pip install numpy |
TypeError: ufunc... | | arr.astype(float) |
ValueError: shapes... | | |
IndexError: out of bounds | | |
ValueError: boolean dimension... | | |
十五、推荐资源
官方文档:
- NumPy参考:numpy.org/doc/stable/
书籍:
- 《Python for Data Analysis》(Wes McKinney)
在线课程:
作者:数据小c | 关注公众号,获取更多Python/NLP学习笔记