《NumPy 实战进阶》
在数据科学、机器学习、人工智能等领域,我们经常需要处理海量的数值数据。Python 虽然是一门优秀的语言,但其内置的列表(List)在处理大规模数值计算时效率低下。这时,NumPy(Numerical Python) 就成为了不可或缺的核心库。它提供了高性能的多维数组对象以及大量用于操作这些数组的工具,其底层由 C 语言编写,使得数据处理速度远超原生 Python,是几乎所有 Python 数据科学生态系统(如 Pandas, Scikit-learn, TensorFlow)的基础。
为什么选择 NumPy?
高性能:底层 C 实现,向量化操作避免了低效的 Python 循环。
多维数组:强大的 ndarray对象可以高效地表示和操作向量、矩阵和高维张量。
丰富的功能:集成了数学函数、线性代数、随机数生成、傅里叶变换等功能。
内存效率:同质数据类型使得数组在内存中连续存储,占用空间小且访问速度快。
核心概念:ndarray(N-dimensional Array)
NumPy 的核心是 ndarray对象,即多维数组。理解它的属性是掌握 NumPy 的第一步。
创建数组
import numpy as np
# 从 Python 列表创建
list_1d = [1, 2, 3, 4, 5]
arr_1d = np.array(list_1d)
list_2d = [[1, 2, 3], [4, 5, 6]]
arr_2d = np.array(list_2d)
# 创建特殊数组
zeros = np.zeros((2, 3)) # 全 0 数组
ones = np.ones((3, 2)) # 全 1 数组
full = np.full((2, 2), 7) # 全为指定值的数组
eye = np.eye(3) # 单位矩阵
# 创建有规律序列的数组
range_arr = np.arange(0, 10, 2) # [0, 2, 4, 6, 8],类似 range,但返回数组
linspace_arr = np.linspace(0, 1, 5) # [0., 0.25, 0.5, 0.75, 1.],均分区间
数组的属性
arr = np.array([[1, 2, 3], [4, 5, 6]])
print("数组形状 (Shape):", arr.shape) # (2, 3) -> 2行3列
print("数组维度 (NDim):", arr.ndim) # 2 -> 二维数组
print("数组大小 (Size):", arr.size) # 6 -> 总共有6个元素
print("数组数据类型 (DType):", arr.dtype) # int64 (或 int32) -> 元素类型
print("每个元素字节大小:", arr.itemsize) # 8 (对于int64)
补充概念:数据类型 (dtype)
NumPy 要求数组内所有元素必须是同一类型。常见类型有:
int8, int16, int32, int64: 不同位数的有符号整数。
uint8, … : 无符号整数。
float16, float32, float64(float): 不同精度的浮点数。float64是默认类型。
bool: 布尔值 True/False。
数组的形状操作:升维、降维与重塑
升维与降维
# 升维 (Reshape)
v = np.arange(8) # [0, 1, 2, 3, 4, 5, 6, 7]
r_2d = v.reshape(2, 4) # 变为 2x4 的二维数组
r_3d = v.reshape(2, 2, 2) # 变为 2x2x2 的三维数组
# 使用 -1 让 NumPy 自动计算维度
r_auto_col = v.reshape(4, -1) # 4行,列数自动计算为2 -> 4x2
r_auto_row = v.reshape(-1, 2) # 列数为2,行数自动计算为4 -> 4x2
# 降维 (Flatten/Ravel)
arr_3d = np.arange(8).reshape(2, 2, 2)
# flatten(): 总是返回原数组的**副本**,修改副本不影响原数组。
flat_flatten = arr_3d.flatten()
# ravel(): 尽可能返回原数组的**视图**,修改视图会影响原数组(更节省内存)。
flat_ravel = arr_3d.ravel()
# 直接修改 shape 属性 (原地操作)
arr_3d.shape = (4, 2)
关键区别:flatten()vs ravel()
flatten():深度拷贝,安全但耗内存。
ravel():浅拷贝(视图),高效但需小心副作用。
调整大小:resize()
resize()会直接修改原数组,而 reshape()返回一个新数组。
v = np.arange(4)
v.resize((2, 3)) # 报错!总元素数不匹配 (4 != 2 * 3)
v.resize((2, 2)) # 成功,v 被修改为 2x2 数组
# 或者使用 np.resize(v, new_shape),它会自动循环填充或截断数据
数组的索引与切片
NumPy 的索引和切片语法与 Python 列表类似,但功能更强大,尤其对于多维数组。
一维数组
arr = np.arange(1, 10)
print(arr[2]) # 选取第3个元素 -> 3
print(arr[[1, 3, 5]])# 花式索引,选取第2,4,6个元素 -> [2, 4, 6]
print(arr[1:5]) # 切片 [2, 3, 4, 5]
多维数组 (以二维为例)
索引格式:arr[行索引, 列索引]
arr_2d = np.arange(1, 13).reshape(3, 4)
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
print(arr_2d[1, 2]) # 第2行第3列的元素 -> 7
print(arr_2d[2, :]) # 第3行的所有列 -> [9, 10, 11, 12]
print(arr_2d[:, 1]) # 第2列的所有行 -> [2, 6, 10]
print(arr_2d[0:2, 1:3]) # 第1-2行,第2-3列 -> [[2 3] [6 7]]
print(arr_2d[[0, 2], :]) # 第1和第3行 -> [[1 2 3 4] [9 10 11 12]]
三维及更高维的索引以此类推,遵循 [dim0_index, dim1_index, dim2_index, …]的规则。
数组的运算
这是 NumPy 展现其强大能力的地方——向量化操作。无需编写循环即可对整个数组进行计算,简洁且高效。
算术运算 (元素级)
形状相同的数组进行算术运算,是对应位置的元素进行操作。
a = np.array([[1, 2], [3, 4]])
b = np.array([[2, 2], [2, 2]])
print(a + b) # [[3 4] [5 6]]
print(a - b) # [[-1 0] [1 2]]
print(a * b) # [[2 4] [6 8]] (这是点乘/哈达玛积,不是矩阵乘法!)
print(a / b) # [[0.5 1. ] [1.5 2. ]]
print(a ** 2) # [[1 4] [9 16]] (平方)
矩阵运算 (线性代数)
使用 np.dot()或 @运算符进行真正的矩阵乘法。
a = np.array([[1, 2], [3, 4]])
b = np.array([[2, 0], [1, 2]])
# 矩阵乘法 (点积)
dot_product = a.dot(b)
matmul_product = a @ b
# 结果: [[4 4] [10 8]]
# 规则: (a的第i行) · (b的第j列) = 结果[i, j]
# 矩阵求逆
a_inv = np.linalg.inv(a)
print(a @ a_inv) # 近似等于单位矩阵 [[1. 0.] [0. 1.]]
数组的统计与聚合函数
NumPy 提供了大量的函数来对数组进行分析。
arr = np.random.randn(3, 4) # 生成一个 3x4 的正态分布随机数组
print("总和:", arr.sum())
print("平均值:", arr.mean())
print("标准差:", arr.std())
print("方差:", arr.var())
print("最大值:", arr.max())
print("最小值:", arr.min())
# 沿着特定轴 (axis) 计算
# axis=0: 沿列方向(跨行)计算,结果维度减少一维(行)
# axis=1: 沿行方向(跨列)计算,结果维度减少一维(列)
print("每列的和:", arr.sum(axis=0)) # 得到一个长度为4的数组
print("每行的和:", arr.sum(axis=1)) # 得到一个长度为3的数组
数组合并与分割
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])
# 合并
# 水平合并 (沿列,增加列数)
h_stack = np.hstack((a, b.T)) # b需要转置才能拼接
h_concat = np.concatenate((a, b.T), axis=1)
# 垂直合并 (沿行,增加行数)
v_stack = np.vstack((a, b))
v_concat = np.concatenate((a, b), axis=0)
# 分割
arr = np.arange(16).reshape(4, 4)
# 水平平均分割为2份
h_split = np.hsplit(arr, 2) # 等价于 np.split(arr, 2, axis=1)
# 垂直平均分割为2份
v_split = np.vsplit(arr, 2) # 等价于 np.split(arr, 2, axis=0)
# 非均匀分割 (使用 array_split)
uneven_h_split = np.array_split(arr, [1, 3], axis=1) # 在第1和第3列后切
随机数生成
np.random模块功能强大,是模拟和机器学习的基石。
# 设置随机种子以保证结果可复现
np.random.seed(42)
# randint: [low, high) 区间的整数
rand_int = np.random.randint(0, 10, size=(2, 3))
# rand: [0, 1) 区间的均匀分布浮点数
rand_uniform = np.random.rand(2, 3)
# normal: 正态分布 N(mean, std^2)
rand_normal = np.random.normal(loc=0, scale=1, size=(2, 3))
# 常用分布:binomial, poisson, chisquare 等
文件的输入输出
NumPy 可以方便地读写文本文件和二进制文件。
# 从文本文件加载 (如 CSV)
# data = np.loadtxt('data.csv', delimiter=',', skiprows=1) # 跳过标题行
# 保存为文本文件
arr = np.array([[1, 2, 3], [4, 5, 6]])
np.savetxt('my_array.txt', arr, fmt='%d', delimiter=',') # fmt指定格式
# 更高效的二进制格式 (推荐用于大型数组)
# np.save('my_array.npy', arr)
# loaded_arr = np.load('my_array.npy')
NumPy 是开启 Python 数据科学大门的钥匙。本文梳理了其核心概念,从创建数组、理解属性,到形状操作、索引切片、向量化运算、统计聚合、合并分割以及随机数生成和文件 I/O。熟练掌握这些基础知识,将为进一步学习 Pandas、Matplotlib、Scikit-learn 等高级库打下坚实的基础。建议读者务必亲自运行文中的每一个示例,通过实践来加深理解。
更多推荐

所有评论(0)