目录
- 引言:为什么 NumPy 在 AI 中如此重要?
- NumPy 数组 (ndarray)
- 2.1 创建数组
- 从列表或元组创建
- 使用
arange
、linspace
、logspace
- 使用
zeros
、ones
、empty
、full
- 使用
eye
、diag
- 从文件读取 (loadtxt, genfromtxt)
- 2.2 数组属性
ndim
(维度)shape
(形状)size
(元素个数)dtype
(数据类型)itemsize
(每个元素的字节大小)nbytes
(总字节大小)- 2.3 数据类型
- 整数 (int8, int16, int32, int64)
- 无符号整数 (uint8, uint16, uint32, uint64)
- 浮点数 (float16, float32, float64)
- 复数 (complex64, complex128)
- 布尔值 (bool)
- 对象 (object)
- 字符串 (string_, unicode_)
- 2.4 数组操作
- 索引 (indexing)
- 切片 (slicing)
- 变形 (reshaping)
- 拼接 (concatenation, stacking)
- 拆分 (splitting)
- 转置 (transposing)
- 广播 (broadcasting)
- NumPy 通用函数 (ufunc)
- 3.1 数学运算 (+, -, *, /, **, %, abs, sqrt, exp, log, sin, cos, tan, …)
- 3.2 比较运算 (==, !=, >, <, >=, <=)
- 3.3 逻辑运算 (np.logical_and, np.logical_or, np.logical_not)
- 3.4 位运算 (&, |, ^, ~)
- NumPy 线性代数 (linalg)
- 4.1 矩阵乘法 (dot, matmul)
- 4.2 矩阵转置 (transpose)
- 4.3 矩阵求逆 (inv)
- 4.4 矩阵行列式 (det)
- 4.5 矩阵的秩 (matrix_rank)
- 4.6 求解线性方程组 (solve)
- 4.7 特征值和特征向量 (eig)
- 4.8 奇异值分解 (svd)
- 4.9 最小二乘法 (lstsq)
- NumPy 随机数 (random)
- 5.1 随机数种子 (seed)
- 5.2 简单随机数 (rand, randn, randint)
- 5.3 各种分布的随机数 (uniform, normal, binomial, poisson, exponential, …)
- 5.4 随机排列 (shuffle, permutation)
- NumPy 实用技巧
- 6.1 条件筛选 (boolean indexing)
- 6.2 数组排序 (sort)
- 6.3 数组去重 (unique)
- 6.4 查找最大/最小值 (max, min, argmax, argmin)
- 6.5 数组求和、平均值、标准差 (sum, mean, std)
- 6.6 数组累积和 (cumsum)
- 6.7 数组舍入 (round, floor, ceil)
- 6.8 将 NumPy 数组保存到文件 (save, savez, savetxt)
- NumPy 在 AI 中的应用
- 总结与下一步
- 挑战任务
今天,我想和大家聊聊一个看似基础,却又至关重要的工具——NumPy。如果你正在AI的道路上探索,或者已经身处其中,那么NumPy绝对是你不可或缺的伙伴。
1. 引言:为什么 NumPy 在 AI 中如此重要?
想象一下,AI模型就像精密的机器,而数据就是驱动它的燃料。在AI的世界里,数据往往以多维数组的形式存在。无论是图像、文本、音频,还是复杂的表格数据,最终都会被转化成计算机能够理解和处理的数字阵列。
NumPy,正是为高效处理这些多维数组而生的Python库。它就像AI世界的地基,为各种高级的AI框架(如TensorFlow、PyTorch、Scikit-learn)提供了坚实的数据运算基础。
为什么NumPy如此重要?原因很简单:高效、简洁、方便、且无处不在。
- 高效性:NumPy底层使用C语言编写,对数组运算进行了极致优化,速度远超Python原生列表。这对于动辄处理海量数据的AI应用至关重要。
- 简洁性:NumPy提供了丰富的函数库,几行代码就能完成复杂的矩阵运算、统计分析等任务,让你的代码更易读、易维护。
- 方便性:NumPy的广播机制、切片索引等特性,使得数组操作如同行云流水般顺畅,极大地提升了开发效率。
- 广泛应用:毫不夸张地说,只要你接触AI,就绕不开NumPy。它是数据科学、机器学习、深度学习生态系统中不可或缺的核心组件。
如果你想在AI领域更进一步,那么深入理解NumPy,绝对是你的必修课。
2. NumPy 数组 (ndarray)
NumPy的核心是ndarray(N-dimensional array),即N维数组对象。它可以存储同类型的数据,并支持快速的数学运算。
2.1 创建数组
NumPy 提供了多种便捷的方法来创建数组:
从列表或元组创建
这是最直接的方式:
import numpy as np
# 从列表创建
a = np.array([1, 2, 3])
print(a) # 输出: [1 2 3]
# 从嵌套列表创建二维数组
b = np.array([[1, 2], [3, 4]])
print(b)
# 输出:
# [[1 2]
# [3 4]]
# 从元组创建
c = np.array((1, 2, 3))
print(c) # 输出: [1 2 3]
使用 arange
、linspace
、logspace
这些函数可以快速生成有规律的数组:
# arange: 类似于 Python 的 range,但返回数组
c = np.arange(10) # 生成 0 到 9 的整数数组
print(c) # 输出: [0 1 2 3 4 5 6 7 8 9]
d = np.arange(0, 10, 2) # 生成 0 到 10 (不包含) 步长为 2 的数组
print(d) # 输出: [0 2 4 6 8]
# linspace: 生成指定范围内,指定数量的等差数列
e = np.linspace(0, 1, 11) # 生成 0 到 1 之间,包含 11 个元素的等差数组
print(e) # 输出: [0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]
# logspace: 生成指定范围内,指定数量的等比数列 (对数刻度)
f = np.logspace(0, 2, 5) # 生成 10^0 到 10^2 之间,包含 5 个元素的等比数组
print(f) # 输出: [ 1. 3.16227766 10. 31.6227766 100. ]
使用 zeros
、ones
、empty
、full
这些函数可以创建特定形状和初始值的数组:
# zeros: 创建指定形状的全 0 数组
g = np.zeros((2, 3)) # 2 行 3 列的全 0 数组
print(g)
# 输出:
# [[0. 0. 0.]
# [0. 0. 0.]]
# ones: 创建指定形状的全 1 数组
h = np.ones((3, 2)) # 3 行 2 列的全 1 数组
print(h)
# 输出:
# [[1. 1.]
# [1. 1.]
# [1. 1.]]
# empty: 创建指定形状的未初始化数组 (速度快,但值不确定)
i = np.empty((2, 2)) # 2 行 2 列的未初始化数组
print(i)
# 输出 (值不确定,每次运行可能不同):
# [[6.23042e-307 1.60222e-322]
# [0.00000e+000 0.00000e+000]]
# full: 创建指定形状,并用指定值填充的数组
j = np.full((3, 3), 7) # 3 行 3 列,所有元素为 7 的数组
print(j)
# 输出:
# [[7 7 7]
# [7 7 7]
# [7 7 7]]
使用 eye
、diag
用于创建特殊矩阵:
# eye: 创建单位矩阵 (对角线为 1,其余为 0)
k = np.eye(3) # 3x3 单位矩阵
print(k)
# 输出:
# [[1. 0. 0.]
# [0. 1. 0.]
# [0. 0. 1.]]
# diag: 创建对角矩阵,或提取对角线元素
l = np.diag([1, 2, 3]) # 以 [1, 2, 3] 为对角线元素的对角矩阵
print(l)
# 输出:
# [[1 0 0]
# [0 2 0]
# [0 0 3]]
从文件读取 (loadtxt
, genfromtxt
)
在实际AI项目中,数据通常存储在文件中。NumPy 提供了方便的函数来读取文件中的数据并创建数组:
# 假设有一个名为 'data.txt' 的文本文件,内容如下 (逗号分隔):
# 1,2,3
# 4,5,6
# 使用 loadtxt 读取文本文件 (适用于数据类型一致的文件)
# data = np.loadtxt('data.txt', delimiter=',')
# print(data)
# 输出:
# [[1. 2. 3.]
# [4. 5. 6.]]
# genfromtxt 更通用,可以处理缺失值等更复杂的情况
# data_gen = np.genfromtxt('data.txt', delimiter=',')
# print(data_gen)
# 输出:
# [[1. 2. 3.]
# [4. 5. 6.]]
# 注意:请先自行创建 'data.txt' 文件进行测试
2.2 数组属性
理解数组的属性对于操作和管理数据至关重要:
a = np.array([[1, 2, 3], [4, 5, 6]])
print("维度 (ndim):", a.ndim) # 输出: 维度 (ndim): 2 (二维数组)
print("形状 (shape):", a.shape) # 输出: 形状 (shape): (2, 3) (2 行 3 列)
print("元素个数 (size):", a.size) # 输出: 元素个数 (size): 6 (总共 6 个元素)
print("数据类型 (dtype):", a.dtype) # 输出: 数据类型 (dtype): int64 (整数类型,根据系统可能不同)
print("每个元素的字节大小 (itemsize):", a.itemsize) # 输出: 每个元素的字节大小 (itemsize): 8 (int64 占 8 字节)
print("总字节大小 (nbytes):", a.nbytes) # 输出: 总字节大小 (nbytes): 48 (6 个元素 * 每个元素 8 字节)
2.3 数据类型
NumPy 提供了丰富的数据类型,可以灵活地存储各种数据:
- 整数:
int8
,int16
,int32
,int64
(不同位数的整数) - 无符号整数:
uint8
,uint16
,uint32
,uint64
(非负整数) - 浮点数:
float16
,float32
,float64
(单精度、双精度浮点数) - 复数:
complex64
,complex128
(复数) - 布尔值:
bool
(True 或 False) - 对象:
object
(可以存储任意 Python 对象,效率较低) - 字符串:
string_
,unicode_
(固定长度字符串)
你可以在创建数组时使用 dtype
参数显式指定数据类型:
a = np.array([1, 2, 3], dtype=np.float32) # 创建 float32 类型的数组
print(a.dtype) # 输出: float32
选择合适的数据类型可以有效节省内存空间,并提升运算效率。
2.4 数组操作
NumPy 提供了强大的数组操作功能,让数据处理更加高效便捷。
索引 (indexing)
访问数组中的单个元素:
a = np.array([[1, 2, 3], [4, 5, 6]])
print(a[0, 0]) # 输出: 1 (第一行第一列,索引从 0 开始)
print(a[1, 2]) # 输出: 6 (第二行第三列)
切片 (slicing)
访问数组的子区域:
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(a[0, :]) # 输出: [1 2 3] (第一行,":" 表示所有列)
print(a[:, 1]) # 输出: [2 5 8] (第二列,":" 表示所有行)
print(a[0:2, 1:3]) # 输出: [[2 3] [5 6]] (第 1-2 行,第 2-3 列)
变形 (reshaping)
改变数组的形状,但不改变元素数量:
a = np.arange(6) # 创建 [0 1 2 3 4 5]
print(a) # 输出: [0 1 2 3 4 5]
b = a.reshape(2, 3) # 变形为 2 行 3 列的矩阵
print(b)
# 输出:
# [[0 1 2]
# [3 4 5]]
c = b.ravel() # 将多维数组展开为一维数组
print(c) # 输出: [0 1 2 3 4 5]
拼接 (concatenation, stacking)
将多个数组合并成一个数组:
a = np.array([[1, 2, 3], [4, 5, 6]])
b = np.array([[7, 8, 9], [10, 11, 12]])
# concatenate: 沿指定轴拼接数组
c = np.concatenate((a, b), axis=0) # 沿行 (axis=0) 拼接
print(c)
# 输出:
# [[ 1 2 3]
# [ 4 5 6]
# [ 7 8 9]
# [10 11 12]]
d = np.concatenate((a, b), axis=1) # 沿列 (axis=1) 拼接
print(d)
# 输出:
# [[ 1 2 3 7 8 9]
# [ 4 5 6 10 11 12]]
# hstack (horizontal stack): 水平拼接 (相当于 axis=1 的 concatenate)
e = np.hstack((a, b))
print(e)
# 输出 (与 d 相同):
# [[ 1 2 3 7 8 9]
# [ 4 5 6 10 11 12]]
# vstack (vertical stack): 垂直拼接 (相当于 axis=0 的 concatenate)
f = np.vstack((a,b))
print(f)
# 输出 (与 c 相同):
# [[ 1 2 3]
# [ 4 5 6]
# [ 7 8 9]
# [10 11 12]]
拆分 (splitting)
将一个数组拆分成多个子数组:
a = np.arange(9).reshape(3, 3) # 创建 3x3 数组
print(a)
# 输出:
# [[0 1 2]
# [3 4 5]
# [6 7 8]]
# split: 沿指定轴拆分数组
g = np.split(a, 3, axis=0) # 沿行 (axis=0) 拆分成 3 份
print(g)
# 输出 (列表,每个元素都是一个子数组):
# [array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])]
h = np.split(a, 3, axis=1) # 沿列 (axis=1) 拆分成 3 份
print(h)
# 输出 (列表,每个元素都是一个子数组):
# [array([[0], [3], [6]]), array([[1], [4], [7]]), array([[2], [5], [8]])]
转置 (transposing)
交换数组的维度,对于二维数组来说就是行列互换:
a = np.array([[1, 2, 3], [4, 5, 6]])
print(a)
# 输出:
# [[1 2 3]
# [4 5 6]]
print(a.T) # 转置
# 输出:
# [[1 4]
# [2 5]
# [3 6]]
广播 (broadcasting)
NumPy 最强大的特性之一,允许不同形状的数组进行运算。NumPy 会自动扩展维度较小的数组,使其与维度较大的数组兼容,再进行逐元素运算。
x = np.array([[1, 2, 3], [4, 5, 6]]) # 2x3 数组
y = np.array([1, 0, 1]) # 1x3 数组 (或 shape 为 (3,) 的一维数组)
print(y.shape) # 输出:(3,)
print(x + y) # 广播机制:y 会自动扩展为 [[1, 0, 1], [1, 0, 1]],再与 x 相加
# 输出:
# [[2 2 4]
# [5 5 7]]
系统架构图:NumPy 在 AI 生态中的位置
图示:NumPy 作为 AI 生态系统的基础,为数据处理、分析以及深度学习框架提供核心支持。数据首先进入 NumPy 进行高效处理,之后才能被其他库和框架有效地利用。
3. NumPy 通用函数 (ufunc)
NumPy 提供了大量的通用函数 (ufunc),可以对数组进行逐元素操作,极大地提升了运算效率。
3.1 数学运算
NumPy 提供了丰富的数学运算 ufunc,涵盖了基础的算术运算到复杂的数学函数:
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print("加法 (+):", a + b) # 输出: 加法 (+): [5 7 9]
print("减法 (-):", a - b) # 输出: 减法 (-): [-3 -3 -3]
print("乘法 (*):", a * b) # 输出: 乘法 (*): [ 4 10 18]
print("除法 (/):", a / b) # 输出: 除法 (/): [0.25 0.4 0.5 ]
print("幂运算 (**):", a ** b) # 输出: 幂运算 (**): [ 1 32 729]
print("取模 (%):", a % b) # 输出: 取模 (%): [1 2 3]
print("绝对值 (abs):", np.abs([-1, -2, 3])) # 输出: 绝对值 (abs): [1 2 3]
print("平方根 (sqrt):", np.sqrt(a)) # 输出: 平方根 (sqrt): [1. 1.41421356 1.73205081]
print("指数 (exp):", np.exp(a)) # 输出: 指数 (exp): [ 2.71828183 7.3890561 20.08553692]
print("对数 (log):", np.log(a)) # 输出: 对数 (log): [0. 0.69314718 1.09861229]
print("正弦 (sin):", np.sin(a)) # 输出: 正弦 (sin): [0.84147098 0.90929743 0.14112001]
print("余弦 (cos):", np.cos(a)) # 输出: 余弦 (cos): [ 0.54030231 -0.41614684 -0.9899925 ]
print("正切 (tan):", np.tan(a)) # 输出: 正切 (tan): [ 1.55740772 -2.18503986 -0.14254654]
3.2 比较运算
比较运算 ufunc 返回布尔值数组,用于条件判断和数据筛选:
a = np.array([1, 2, 3])
b = np.array([3, 2, 1])
print("等于 (==):", a == b) # 输出: 等于 (==): [False True False]
print("不等于 (!=):", a != b) # 输出: 不等于 (!=): [ True False True]
print("大于 (>):", a > b) # 输出: 大于 (>): [False False True]
print("小于 (<):", a < b) # 输出: 小于 (<): [ True False False]
print("大于等于 (>=):", a >= b) # 输出: 大于等于 (>=): [False True True]
print("小于等于 (<=):", a <= b) # 输出: 小于等于 (<=): [ True True False]
3.3 逻辑运算
逻辑运算 ufunc 用于进行布尔数组的逻辑操作:
a = np.array([True, True, False, False])
b = np.array([True, False, True, False])
print("逻辑与 (logical_and):", np.logical_and(a, b)) # 输出: 逻辑与 (logical_and): [ True False False False]
print("逻辑或 (logical_or):", np.logical_or(a, b)) # 输出: 逻辑或 (logical_or): [ True True True False]
print("逻辑非 (logical_not):", np.logical_not(a)) # 输出: 逻辑非 (logical_not): [False False True True]
3.4 位运算
位运算 ufunc 直接操作整数的二进制位:
a = np.array([1, 2, 3], dtype=np.uint8) # 二进制: 00000001, 00000010, 00000011
b = np.array([3, 2, 1], dtype=np.uint8) # 二进制: 00000011, 00000010, 00000001
print("按位与 (&):", a & b) # 输出: 按位与 (&): [1 2 1] (二进制: 00000001, 00000010, 00000001)
print("按位或 (|):", a | b) # 输出: 按位或 (|): [3 2 3] (二进制: 00000011, 00000010, 00000011)
print("按位异或 (^):", a ^ b) # 输出: 按位异或 (^): [2 0 2] (二进制: 00000010, 00000000, 00000010)
print("按位取反 (~):", ~a) # 输出: 按位取反 (~): [254 253 252] (二进制: 11111110, 11111101, 11111100 - 注意 uint8 的溢出)
4. NumPy 线性代数 (linalg)
numpy.linalg
模块提供了强大的线性代数运算功能,这在机器学习和深度学习中应用极其广泛。
4.1 矩阵乘法
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print("矩阵乘法 (dot):")
print(np.dot(A, B))
# 输出:
# [[19 22]
# [43 50]]
print("矩阵乘法 (@ 运算符):")
print(A @ B) # 另一种更简洁的写法
# 输出 (与 dot 相同):
# [[19 22]
# [43 50]]
4.2 矩阵转置
A = np.array([[1, 2], [3, 4]])
print("矩阵转置 (A.T):")
print(A.T)
# 输出:
# [[1 3]
# [2 4]]
print("矩阵转置 (transpose):")
print(np.transpose(A))
# 输出 (与 A.T 相同):
# [[1 3]
# [2 4]]
4.3 矩阵求逆
A = np.array([[1, 2], [3, 4]])
A_inv = np.linalg.inv(A) # 计算矩阵 A 的逆矩阵
print("矩阵求逆 (inv):")
print(A_inv)
# 输出:
# [[-2. 1. ]
# [ 1.5 -0.5]]
print("验证逆矩阵 (A @ A_inv):")
print(A @ A_inv) # 矩阵 A 乘以其逆矩阵,应该接近单位矩阵
# 输出 (接近单位矩阵):
# [[1.0000000e+00 0.0000000e+00]
# [8.8817842e-16 1.0000000e+00]]
4.4 矩阵行列式
A = np.array([[1, 2], [3, 4]])
det_A = np.linalg.det(A) # 计算矩阵 A 的行列式
print("矩阵行列式 (det):", det_A) # 输出: 矩阵行列式 (det): -2.0
4.5 矩阵的秩
A = np.array([[1, 2], [3, 4]])
rank_A = np.linalg.matrix_rank(A) # 计算矩阵 A 的秩
print("矩阵的秩 (matrix_rank):", rank_A) # 输出: 矩阵的秩 (matrix_rank): 2
4.6 求解线性方程组
# 求解线性方程组 Ax = b
# 例如: x + 2y = 5, 3x + 4y = 11
A = np.array([[1, 2], [3, 4]]) # 系数矩阵 A
b = np.array([5, 11]) # 常数向量 b
x = np.linalg.solve(A, b) # 求解 Ax = b
print("求解线性方程组 (solve):", x) # 输出: 求解线性方程组 (solve): [1. 2.] (即 x=1, y=2)
4.7 特征值和特征向量
A = np.array([[1, 2], [2, 1]])
eigenvalues, eigenvectors = np.linalg.eig(A) # 计算矩阵 A 的特征值和特征向量
print("特征值 (eig values):", eigenvalues) # 输出: 特征值 (eig values): [ 3. -1.]
print("特征向量 (eig vectors):\n", eigenvectors)
# 输出:
# 特征向量 (eig vectors):
# [[ 0.70710678 -0.70710678]
# [ 0.70710678 0.70710678]]
4.8 奇异值分解 (SVD)
A = np.array([[1, 2, 3], [4, 5, 6]])
U, S, V = np.linalg.svd(A) # 对矩阵 A 进行奇异值分解
print("U (SVD U):\n", U)
print("S (SVD Singular Values):", S) # 奇异值 (对角线元素)
print("V (SVD V):\n", V)
4.9 最小二乘法
# 求解 Ax = b 的最小二乘解 (当 A 不是方阵或方程组无解时)
# 例如:拟合直线 y = mx + c,已知若干个 (x, y) 数据点
A = np.array([[1, 1], [1, 2], [1, 3]]) # 设计矩阵 A (假设 y = c + mx)
b = np.array([2, 3, 5]) # 观测值向量 b (y 值)
x, residuals, rank, s = np.linalg.lstsq(A, b, rcond=None) # 求解最小二乘解
print("最小二乘解 (lstsq):", x) # 输出: 最小二乘解 (lstsq): [0.5 1.5] (即 c=0.5, m=1.5)
print("残差平方和 (residuals):", residuals) # 输出: 残差平方和 (residuals): [0.5]
5. NumPy 随机数 (random)
numpy.random
模块提供了强大的随机数生成功能,用于模拟数据、初始化模型参数、以及各种随机算法。
5.1 随机数种子
np.random.seed(42) # 设置随机数种子,保证每次运行程序生成的随机数序列相同,便于结果复现
5.2 简单随机数
print("0-1 均匀分布随机数 (rand):\n", np.random.rand(2, 3)) # 生成 2x3 数组,元素为 [0, 1) 之间的均匀分布随机数
# 输出 (每次运行可能不同,但种子固定后会相同):
# [[0.37454012 0.95071431 0.73199394]
# [0.59865848 0.15601864 0.15599452]]
print("标准正态分布随机数 (randn):\n", np.random.randn(2, 3)) # 生成 2x3 数组,元素为标准正态分布 (均值为 0,标准差为 1) 随机数
# 输出 (每次运行可能不同,但种子固定后会相同):
# [[ 0.70807258 -0.12289023 0.2088636 ]
# [-1.95967015 -0.43333143 1.21791614]]
print("指定范围整数随机数 (randint):\n", np.random.randint(1, 10, (2, 3))) # 生成 2x3 数组,元素为 [1, 10) 之间的随机整数
# 输出 (每次运行可能不同,但种子固定后会相同):
# [[4 4 8]
# [5 7 3]]
5.3 各种分布的随机数
NumPy 提供了各种常见概率分布的随机数生成函数:
print("均匀分布 (uniform):\n", np.random.uniform(1, 10, (2, 3))) # 生成 2x3 数组,元素为 [1, 10) 之间的均匀分布随机数
print("正态分布 (normal):\n", np.random.normal(0, 1, (2, 3))) # 生成 2x3 数组,元素为正态分布随机数 (均值为 0,标准差为 1)
print("二项分布 (binomial):\n", np.random.binomial(10, 0.5, (2, 3))) # 生成 2x3 数组,元素为二项分布随机数 (n=10, p=0.5)
print("泊松分布 (poisson):\n", np.random.poisson(5, (2, 3))) # 生成 2x3 数组,元素为泊松分布随机数 (lambda=5)
print("指数分布 (exponential):\n", np.random.exponential(2, (2, 3))) # 生成 2x3 数组,元素为指数分布随机数 (scale=2,即均值为 2)
# ... 还有更多分布,例如 gamma, beta, chi2 等
5.4 随机排列
a = np.arange(10) # 创建 [0 1 2 3 4 5 6 7 8 9]
print("原始数组:", a) # 输出: 原始数组: [0 1 2 3 4 5 6 7 8 9]
np.random.shuffle(a) # 就地打乱数组 a 的顺序 (改变原数组)
print("shuffle 打乱后:", a)
# 输出 (每次运行可能不同,但种子固定后会相同):
# shuffle 打乱后: [9 1 6 7 3 0 8 4 2 5]
b = np.arange(10) # 重新创建 [0 1 2 3 4 5 6 7 8 9]
c = np.random.permutation(b) # 返回打乱后的新数组,不改变原数组 b
print("permutation 打乱后:", c)
# 输出 (每次运行可能不同,但种子固定后会相同):
# permutation 打乱后: [1 7 4 6 9 2 8 0 3 5]
print("原始数组 b (未改变):", b) # 输出: 原始数组 b (未改变): [0 1 2 3 4 5 6 7 8 9]
流程图:NumPy 数组创建流程
流程图:展示了 NumPy 数组创建的主要流程,根据不同的数据来源和需求,选择不同的 NumPy 函数来创建 ndarray 对象。
6. NumPy 实用技巧
掌握一些 NumPy 的实用技巧,可以让你在数据处理中更加得心应手。
6.1 条件筛选 (boolean indexing)
使用布尔数组作为索引,可以高效地筛选数组中满足特定条件的元素:
a = np.array([1, 2, 3, 4, 5])
print("大于 2 的元素:", a[a > 2]) # 输出: 大于 2 的元素: [3 4 5]
print("大于 1 且小于 5 的元素:", a[(a > 1) & (a < 5)]) # 输出: 大于 1 且小于 5 的元素: [2 3 4]
6.2 数组排序
a = np.array([3, 1, 4, 2, 5])
print("排序后的数组 (sort):", np.sort(a)) # 输出: 排序后的数组 (sort): [1 2 3 4 5] (返回排序后的副本,原数组不变)
print("原始数组 a (未改变):", a) # 输出: 原始数组 a (未改变): [3 1 4 2 5]
a.sort() # 就地排序,直接修改原数组 a
print("就地排序后的数组 (a.sort()):", a) # 输出: 就地排序后的数组 (a.sort()): [1 2 3 4 5]
6.3 数组去重
a = np.array([1, 2, 2, 3, 3, 3, 4, 4, 4, 4])
print("去重后的数组 (unique):", np.unique(a)) # 输出: 去重后的数组 (unique): [1 2 3 4]
6.4 查找最大/最小值
a = np.array([3, 1, 4, 2, 5])
print("最大值 (max):", np.max(a)) # 输出: 最大值 (max): 5
print("最小值 (min):", np.min(a)) # 输出: 最小值 (min): 1
print("最大值索引 (argmax):", np.argmax(a)) # 输出: 最大值索引 (argmax): 4 (最大值 5 的索引)
print("最小值索引 (argmin):", np.argmin(a)) # 输出: 最小值索引 (argmin): 1 (最小值 1 的索引)
6.5 数组求和、平均值、标准差
a = np.array([1, 2, 3, 4, 5])
print("求和 (sum):", np.sum(a)) # 输出: 求和 (sum): 15
print("平均值 (mean):", np.mean(a)) # 输出: 平均值 (mean): 3.0
print("标准差 (std):", np.std(a)) # 输出: 标准差 (std): 1.4142135623730951
6.6 数组累积和
a = np.array([1, 2, 3, 4, 5])
print("累积和 (cumsum):", np.cumsum(a)) # 输出: 累积和 (cumsum): [ 1 3 6 10 15]
# 累积和的计算过程: [1, 1+2, 1+2+3, 1+2+3+4, 1+2+3+4+5]
6.7 数组舍入
a = np.array([1.2, 2.5, 3.7])
print("四舍五入 (round):", np.round(a)) # 输出: 四舍五入 (round): [1. 2. 4.]
print("向下取整 (floor):", np.floor(a)) # 输出: 向下取整 (floor): [1. 2. 3.]
print("向上取整 (ceil):", np.ceil(a)) # 输出: 向上取整 (ceil): [2. 3. 4.]
6.8 将 NumPy 数组保存到文件
a = np.array([[1, 2, 3], [4, 5, 6]])
np.save("my_array.npy", a) # 保存为 .npy 文件 (NumPy 专用的二进制格式,高效)
print("数组已保存到 my_array.npy")
b = np.load("my_array.npy") # 加载 .npy 文件
print("从 my_array.npy 加载的数组:\n", b)
# 输出:
# 从 my_array.npy 加载的数组:
# [[1 2 3]
# [4 5 6]]
np.savetxt("my_array.txt", a, delimiter=",") # 保存为文本文件 (例如 CSV 格式,通用性好)
print("数组已保存到 my_array.txt")
c = np.loadtxt("my_array.txt", delimiter=",") # 加载文本文件
print("从 my_array.txt 加载的数组:\n", c)
# 输出:
# 从 my_array.txt 加载的数组:
# [[1. 2. 3.]
# [4. 5. 6.]]
# np.savez("my_arrays.npz", array_a=a, array_b=b) # 保存多个数组到一个 .npz 文件中 (压缩格式)
# arrays = np.load("my_arrays.npz") # 加载 .npz 文件
# print(arrays['array_a']) # 访问保存的数组
7. NumPy 在 AI 中的应用
NumPy 在 AI 的各个环节都扮演着重要的角色:
- 数据预处理:数据清洗、缺失值处理、数据转换(例如归一化、标准化)、特征缩放等,都离不开 NumPy 的高效数组运算。
- 特征工程:从原始数据中提取、构造有意义的特征,例如图像像素特征、文本词向量特征、音频频谱特征等,NumPy 提供了强大的数组操作和数学运算支持。
- 模型构建:无论是传统的机器学习模型(如线性回归、逻辑回归、支持向量机),还是现代的深度学习模型(神经网络),其底层运算都基于 NumPy 数组。模型参数、权重、偏置项等都以 NumPy 数组的形式存储和计算。
- 图像处理:图像本质上是像素矩阵,NumPy 可以方便地进行图像的读取、显示、裁剪、缩放、旋转、滤波、特征提取等操作。很多图像处理库(如 OpenCV, Pillow)都与 NumPy 紧密结合。
- 自然语言处理 (NLP):文本数据可以转换为词袋模型、TF-IDF 向量、词嵌入向量(如 Word2Vec, GloVe, FastText),这些向量表示都以 NumPy 数组的形式存储。NumPy 也用于文本数据的预处理、特征提取、模型构建等环节。
- 音频处理:音频信号可以表示为波形数据(一维数组)或频谱图数据(二维数组),NumPy 可以用于音频数据的读取、分析、特征提取(如 MFCCs, Mel 频谱)、音频合成等操作。
NumPy 在 AI 应用流程中的角色
图示:NumPy 在 AI 应用流程中的核心地位。数据预处理、特征工程阶段,NumPy 用于高效的数据操作和特征提取。模型训练阶段,各种 AI 框架(Scikit-learn, TensorFlow, PyTorch)都依赖 NumPy 数组作为数据输入和模型参数的载体。
8. 总结与下一步
NumPy 是 AI 世界的基石,掌握 NumPy 的核心概念和常用功能,是成为一名合格的 AI 从业者的必要条件。本文深入浅出地介绍了 NumPy 的方方面面,从数组创建、属性、操作,到通用函数、线性代数、随机数生成,再到实用技巧和在 AI 中的应用,希望能够帮助你系统地学习 NumPy。
下一步,建议你:
- 实践练习:动手敲代码,完成文中的代码示例,并尝试解决文末的挑战任务。
- 查阅文档:深入阅读 NumPy 官方文档,了解更多高级功能和细节。
- 结合应用:尝试将 NumPy 应用到实际的 AI 项目中,例如数据分析、图像处理、简单的机器学习模型等。
- 学习相关库:继续学习基于 NumPy 的其他库,例如 Pandas (数据分析)、Matplotlib (数据可视化)、Scikit-learn (机器学习)、TensorFlow/PyTorch (深度学习),构建更完整的 AI 技术栈。
9. 挑战任务
- 复习:回顾本文所有概念和代码示例,确保理解 NumPy 的核心知识点。
- 练习:完成以下 NumPy 操作:
- 创建一个 3x4 的全 0 数组。
- 创建一个 5x5 的单位矩阵。
- 创建一个从 10 到 100 (不包括 100) 的等差数列,步长为 5。
- 创建一个 2x3x4 的三维数组,元素为随机整数 (范围自定)。
- 给定数组
a = np.array([1, 2, 3, 4, 5, 6])
,将其变形为 2x3 的矩阵。 - 给定数组
a = np.array([1, 2, 3])
和b = np.array([4, 5, 6])
,计算它们的点积 (矩阵乘法)。 - 给定矩阵
A = np.array([[1, 2], [3, 4]])
,计算它的逆矩阵。 - 给定矩阵
A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
,计算它的特征值和特征向量。 - 生成 100 个服从标准正态分布的随机数,并计算它们的平均值和标准差。
- 生成 10 个服从二项分布 (n=10, p=0.5) 的随机数。
- 给定数组
a = np.array([5, 2, 8, 1, 9, 4])
,对其进行升序和降序排序。 - 给定数组
a = np.array([1, 2, 2, 3, 3, 3, 4, 4, 4, 4])
,找出其中的唯一值,并统计每个唯一值出现的次数。 - 给定数组
a = np.array([1, 2, 3, 4, 5])
,找出大于 2 且小于 5 的元素,并将它们替换为 0。 - 将一个 NumPy 数组保存到文件 (文本和二进制两种格式),然后从文件中加载。
- 探索:尝试使用 NumPy 实现一个简单的线性回归模型,例如使用最小二乘法拟合一组数据点。
- 阅读:深入阅读 NumPy 官方文档,特别是关于广播机制、ufunc 高级用法、以及性能优化的部分。
希望这篇博客能成为你 NumPy 学习的良好起点。AI 的世界广阔而精彩,NumPy 将是你手中最可靠的工具之一。让我们一起在 AI 的道路上不断前行!