ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SciPy 稀疏矩阵:原理、类型与实战代码详解

SciPy 稀疏矩阵:原理、类型与实战代码详解 摘要本文深入探讨 SciPy 中稀疏矩阵的核心概念、存储格式与高效运算方法。通过丰富的 Python 代码实例详细解析 CSR、CSC、COO 等主流稀疏格式的创建、转换与操作并展示其在机器学习、图计算等领域的典型应用场景帮助读者掌握处理大规模稀疏数据的关键技能。1. 稀疏矩阵简介在科学计算和数据分析中我们经常遇到元素大部分为零的矩阵这类矩阵被称为稀疏矩阵。与存储所有元素的稠密矩阵相比稀疏矩阵仅存储非零元素及其位置能极大节省内存并提升计算效率。SciPy 的scipy.sparse模块提供了多种稀疏矩阵格式和高效算法是处理稀疏数据的标准工具。2. 核心稀疏矩阵格式SciPy 支持多种稀疏存储格式各有其适用场景。2.1 COO (Coordinate Format)COO 格式通过三个数组存储行索引、列索引和值。它易于构建但不支持高效算术运算。import numpy as np from scipy.sparse import coo_matrix 创建 COO 格式稀疏矩阵 data np.array([1, 2, 3, 4]) # 非零元素值 row np.array([0, 1, 2, 3]) # 行索引 col np.array([0, 1, 2, 3]) # 列索引 shape (4, 4) # 矩阵形状 coo coo_matrix((data, (row, col)), shapeshape) print(COO 矩阵:) print(coo.toarray()) # 转换为稠密矩阵显示 print(f非零元素数量: {coo.nnz}) print(f内存占用: {coo.data.nbytes coo.row.nbytes coo.col.nbytes} 字节)2.2 CSR (Compressed Sparse Row)CSR 格式通过三个数组存储值、列索引和行偏移指针。它支持高效的矩阵运算和行切片。from scipy.sparse import csr_matrix 从稠密矩阵创建 CSR dense_matrix np.array([ [1, 0, 0, 2], [0, 0, 3, 0], [0, 4, 0, 0], [5, 0, 0, 6] ]) csr csr_matrix(dense_matrix) print(\nCSR 矩阵:) print(csr.toarray()) print(fCSR 内部数组:) print(f data: {csr.data}) # 非零值 print(f indices: {csr.indices}) # 列索引 print(f indptr: {csr.indptr}) # 行偏移指针 CSR 高效行切片 print(\n第二行 (CSR 行切片):) print(csr[1].toarray())2.3 CSC (Compressed Sparse Column)CSC 格式是 CSR 的列压缩版本支持高效的列切片和列操作。from scipy.sparse import csc_matrix 创建 CSC 矩阵 csc csc_matrix(dense_matrix) print(\nCSC 矩阵:) print(csc.toarray()) print(fCSC 内部数组:) print(f data: {csc.data}) print(f indices: {csc.indices}) # 行索引 print(f indptr: {csc.indptr}) # 列偏移指针 CSC 高效列切片 print(\n第三列 (CSC 列切片):) print(csc[:, 2].toarray())2.4 格式对比与转换# 格式转换示例 print(格式转换:) csr_from_coo coo.tocsr() # COO → CSR csc_from_csr csr.tocsc() # CSR → CSC coo_from_csc csc.tocoo() # CSC → COO print(fCOO → CSR 成功: {type(csr_from_coo).name}) print(fCSR → CSC 成功: {type(csc_from_csr).name}) 格式特性对比 formats [COO, CSR, CSC] matrices [coo, csr, csc] print(\n格式特性对比:) for fmt, mat in zip(formats, matrices): print(f{fmt}:) print(f 支持高效行切片: {hasattr(mat, getitem)}) print(f 支持矩阵乘法: {hasattr(mat, dot)}) print(f 内存占用: {mat.data.nbytes mat.indices.nbytes getattr(mat, indptr, np.array([])).nbytes} 字节)3. 稀疏矩阵创建方法3.1 从稠密矩阵创建# 方法1: 直接传入稠密矩阵 dense np.eye(5) # 5x5 单位矩阵 sparse_from_dense csr_matrix(dense) 方法2: 指定非零位置 rows [0, 1, 2, 3, 4] cols [0, 1, 2, 3, 4] values [1, 1, 1, 1, 1] sparse_from_lists csr_matrix((values, (rows, cols)), shape(5, 5)) print(从稠密矩阵创建的稀疏矩阵:) print(sparse_from_dense.toarray()) print(\n从列表创建的稀疏矩阵:) print(sparse_from_lists.toarray())3.2 特殊稀疏矩阵from scipy.sparse import eye, diags, random 单位矩阵 identity eye(5, formatcsr) print(5x5 稀疏单位矩阵:) print(identity.toarray()) 对角矩阵 diagonal diags([1, 2, 3], offsets[-1, 0, 1], shape(5, 5), formatcsc) print(\n5x5 稀疏对角矩阵:) print(diagonal.toarray()) 随机稀疏矩阵 random_sparse random(5, 5, density0.3, formatcsr, random_state42) print(\n随机稀疏矩阵 (密度 0.3):) print(random_sparse.toarray()) print(f非零元素比例: {random_sparse.nnz / 25:.2%})3.3 从文件加载from scipy import io import tempfile import os 创建临时矩阵并保存 temp_matrix csr_matrix(np.array([[1, 0, 3], [0, 4, 0], [5, 0, 6]])) 保存为 Matrix Market 格式 with tempfile.NamedTemporaryFile(suffix.mtx, deleteFalse) as tmp: io.mmwrite(tmp.name, temp_matrix) # 从文件加载 loaded_matrix io.mmread(tmp.name) os.unlink(tmp.name) # 删除临时文件 print(从文件加载的矩阵:) print(loaded_matrix.toarray()) print(f格式: {type(loaded_matrix).name})4. 稀疏矩阵运算4.1 基本算术运算# 创建两个稀疏矩阵 A csr_matrix(np.array([[1, 0, 2], [0, 3, 0], [4, 0, 5]])) B csr_matrix(np.array([[0, 1, 0], [2, 0, 3], [0, 4, 0]])) print(矩阵 A:) print(A.toarray()) print(\n矩阵 B:) print(B.toarray()) 加法 C A B print(\nA B:) print(C.toarray()) 逐元素乘法 D A.multiply(B) # 或 A * B (逐元素) print(\nA ⊙ B (逐元素乘法):) print(D.toarray()) 标量乘法 E A * 2.5 print(\nA × 2.5:) print(E.toarray())4.2 矩阵乘法# 矩阵乘法 (真正的矩阵乘法) F A.dot(B) # 或 A B print(矩阵乘法 A B:) print(F.toarray()) 与稠密矩阵相乘 dense_vector np.array([1, 2, 3]) result A.dot(dense_vector) print(\n稀疏矩阵 × 稠密向量:) print(result) 大规模稀疏矩阵乘法性能演示 import time large_A random(1000, 1000, density0.01, formatcsr) large_B random(1000, 1000, density0.01, formatcsr) start time.time() large_C large_A.dot(large_B) sparse_time time.time() - start 对比稠密矩阵 dense_A large_A.toarray() dense_B large_B.toarray() start time.time() dense_C dense_A.dot(dense_B) dense_time time.time() - start print(f\n大规模矩阵乘法性能对比:) print(f稀疏矩阵乘法: {sparse_time:.4f} 秒) print(f稠密矩阵乘法: {dense_time:.4f} 秒) print(f加速比: {dense_time/sparse_time:.1f} 倍)4.3 矩阵函数与分解from scipy.sparse.linalg import inv, norm, eigs 矩阵求逆 (仅限小规模) small_sparse csr_matrix(np.array([[2, 1], [1, 2]])) try: inverse inv(small_sparse) print(矩阵求逆:) print(inverse.toarray()) except Exception as e: print(f求逆失败: {e}) 矩阵范数 print(f\n矩阵 A 的 Frobenius 范数: {norm(A, fro):.4f}) print(f矩阵 A 的无穷范数: {norm(A, np.inf):.4f}) 特征值计算 (仅计算前k个) print(\n计算前2个特征值:) try: eigenvalues, eigenvectors eigs(A, k2) print(f特征值: {eigenvalues}) except Exception as e: print(f特征值计算失败: {e})5. 实战应用案例5.1 文本分类中的词袋模型from sklearn.feature_extraction.text import CountVectorizer 示例文档 documents [ 机器学习是人工智能的核心, 深度学习是机器学习的分支, 自然语言处理使用深度学习技术, 人工智能包含机器学习和深度学习 ] 创建词袋模型 vectorizer CountVectorizer() X vectorizer.fit_transform(documents) print(文档-词项矩阵 (稀疏):) print(f形状: {X.shape}) print(f非零元素: {X.nnz}) print(f稀疏度: {X.nnz / (X.shape[0] * X.shape[1]):.2%}) 转换为 SciPy 稀疏矩阵 sparse_X X # sklearn 返回的就是 CSR 格式 print(f\n矩阵格式: {type(sparse_X).name}) 查看前几个文档的向量表示 print(\n前3个文档的向量表示:) for i in range(3): print(f文档{i1}: {sparse_X[i].toarray()})5.2 图邻接矩阵import networkx as nx 创建图 G nx.Graph() G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 0), (0, 2)]) 获取邻接矩阵 (稀疏格式) adj_matrix nx.adjacency_matrix(G) print(图邻接矩阵:) print(adj_matrix.toarray()) print(f\n图信息:) print(f节点数: {G.number_of_nodes()}) print(f边数: {G.number_of_edges()}) print(f邻接矩阵格式: {type(adj_matrix).name}) 计算图的拉普拉斯矩阵 laplacian nx.laplacian_matrix(G) print(\n拉普拉斯矩阵:) print(laplacian.toarray())5.3 推荐系统中的用户-物品矩阵# 模拟用户-物品评分矩阵 n_users 1000 n_items 500 density 0.01 # 1% 的评分密度 生成随机稀疏评分矩阵 np.random.seed(42) ratings random(n_users, n_items, densitydensity, formatcsr, data_rvslambda n: np.random.randint(1, 6, n)) print(推荐系统评分矩阵:) print(f用户数: {n_users}) print(f物品数: {n_items}) print(f评分总数: {ratings.nnz}) print(f评分密度: {ratings.nnz / (n_users * n_items):.2%}) 计算用户相似度 (余弦相似度) from sklearn.metrics.pairwise import cosine_similarity 取前100个用户计算相似度 small_ratings ratings[:100] user_similarity cosine_similarity(small_ratings) print(f\n前100个用户的相似度矩阵形状: {user_similarity.shape})6. 性能优化技巧6.1 格式选择指南import pandas as pd 创建性能对比数据 operations [构建, 行切片, 列切片, 矩阵乘法, 转置] formats [COO, CSR, CSC] performance_data { COO: [快, 慢, 慢, 慢, 快], CSR: [中, 快, 慢, 快, 中], CSC: [中, 慢, 快, 快, 中] } df pd.DataFrame(performance_data, indexoperations) print(稀疏矩阵格式性能对比:) print(df.to_string()) print(\n\n格式选择建议:) print(1. 构建阶段 → COO 格式最快) print(2. 行操作多 → 选择 CSR 格式) print(3. 列操作多 → 选择 CSC 格式) print(4. 算术运算 → CSR/CSC 格式) print(5. 频繁转换 → 考虑内存开销)6.2 内存使用优化# 比较不同数据类型的内存占用 dtypes [np.int8, np.int16, np.int32, np.int64, np.float32, np.float64] results [] for dtype in dtypes: # 创建相同稀疏模式的矩阵 data np.ones(1000, dtypedtype) rows np.random.randint(0, 100, 1000) cols np.random.randint(0, 100, 1000) mat csr_matrix((data, (rows, cols)), shape(100, 100)) memory mat.data.nbytes mat.indices.nbytes mat.indptr.nbytes results.append((dtype.__name__, memory)) print(不同数据类型的内存占用 (1000个非零元素):) for dtype_name, memory in results: print(f{dtype_name:10} → {memory:6} 字节)6.3 避免常见性能陷阱# 陷阱1: 频繁的格式转换 print(陷阱1: 避免在循环中频繁转换格式) print(正确做法: 一次性转换到目标格式后操作) 陷阱2: 对不适合的格式进行切片 csr_matrix_example random(100, 100, density0.1, formatcsr) print(f\n陷阱2: CSR 格式的列切片效率低) print(fCSR 列切片时间: , end) import time start time.time() _ csr_matrix_example[:, 50] # 列切片 print(f{time.time() - start:.6f} 秒) csc_matrix_example csr_matrix_example.tocsc() print(fCSC 列切片时间: , end) start time.time() _ csc_matrix_example[:, 50] # 列切片 print(
返回列表