news 2026/9/4 9:49:12

SciPy 稀疏矩阵完全指南:从原理到实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SciPy 稀疏矩阵完全指南:从原理到实战

1. 引言

在科学计算和机器学习领域,我们经常需要处理大规模矩阵数据。然而,许多实际场景中的矩阵都包含大量零元素,例如推荐系统中的用户-物品评分矩阵、自然语言处理中的词频矩阵、图结构中的邻接矩阵等。如果使用普通的稠密矩阵存储这些数据,不仅会浪费大量内存,还会导致计算效率低下。

SciPy 提供了丰富的稀疏矩阵支持,能够高效地存储和操作这类数据。本文将系统介绍 SciPy 稀疏矩阵的核心概念、常见存储格式、创建方法、常用操作以及实战案例,帮助读者全面掌握这一重要工具。

2. 什么是稀疏矩阵

稀疏矩阵是指大部分元素为零的矩阵。与之相对,稠密矩阵是指大部分元素非零的矩阵。稀疏矩阵的"稀疏度"通常用非零元素占比来衡量,例如一个 10000×10000 的矩阵如果只有 10000 个非零元素,那么它的非零元素占比仅为 0.01%。

对于这样的矩阵,如果使用普通二维数组存储,需要 10000×10000×8 字节(假设 float64)约 800MB 内存;而使用稀疏矩阵存储,只需要存储非零元素的位置和值,内存占用可以降低几个数量级。

import numpy as np from scipy.sparse import csr_matrix 创建一个稠密矩阵 dense = np.array([ [0, 0, 3, 0], [4, 0, 0, 0], [0, 0, 0, 5], [0, 2, 0, 0] ]) 转换为稀疏矩阵 sparse = csr_matrix(dense) print("稠密矩阵内存占用:", dense.nbytes, "字节") print("稀疏矩阵内存占用:", sparse.data.nbytes + sparse.indices.nbytes + sparse.indptr.nbytes, "字节") print("非零元素:", sparse.nnz)

3. 常见的稀疏矩阵格式

SciPy 提供了多种稀疏矩阵格式,每种格式在存储效率和操作性能上各有优劣。下面介绍最常用的几种。

3.1 CSR 格式(Compressed Sparse Row)

CSR 格式按行压缩存储非零元素,是 SciPy 中最常用的格式之一。它使用三个数组表示矩阵:data 存储非零元素的值,indices 存储每个非零元素对应的列索引,indptr 存储每行第一个非零元素在 data 中的位置偏移。

from scipy.sparse import csr_matrix 创建 CSR 矩阵 row = np.array([0, 0, 1, 2, 2, 2]) col = np.array([0, 2, 2, 0, 1, 2]) data = np.array([1, 2, 3, 4, 5, 6]) csr = csr_matrix((data, (row, col)), shape=(3, 3)) print("CSR 矩阵:") print(csr.toarray()) print("data:", csr.data) print("indices:", csr.indices) print("indptr:", csr.indptr)

3.2 CSC 格式(Compressed Sparse Column)

CSC 格式与 CSR 格式类似,但按列压缩存储。它适合按列访问和列切片操作的场景,在矩阵乘法中也有广泛应用。

from scipy.sparse import csc_matrix 创建 CSC 矩阵 csc = csc_matrix((data, (row, col)), shape=(3, 3)) print("CSC 矩阵:") print(csc.toarray()) print("data:", csc.data) print("indices:", csc.indices) print("indptr:", csc.indptr)

3.3 COO 格式(Coordinate Format)

COO 格式是最直观的稀疏矩阵表示方式,它直接记录每个非零元素的行索引、列索引和值。这种格式非常适合从外部数据构建稀疏矩阵,但进行算术运算时效率较低。

from scipy.sparse import coo_matrix 创建 COO 矩阵 coo = coo_matrix((data, (row, col)), shape=(3, 3)) print("COO 矩阵:") print(coo.toarray()) print("row:", coo.row) print("col:", coo.col) print("data:", coo.data)

3.4 其他格式

除了上述三种格式,SciPy 还提供了 DOK(Dictionary of Keys)、LIL(List of Lists)、BSR(Block Sparse Row)等格式。DOK 和 LIL 适合动态构建矩阵,BSR 适合存储分块稀疏矩阵。

from scipy.sparse import dok_matrix, lil_matrix DOK 格式:适合增量构建 dok = dok_matrix((3, 3), dtype=np.float32) dok[0, 1] = 2.5 dok[2, 0] = 3.5 print("DOK 矩阵:") print(dok.toarray()) LIL 格式:适合逐行修改 lil = lil_matrix((3, 3)) lil[0, 0] = 1 lil[1, 2] = 4 print("LIL 矩阵:") print(lil.toarray())

4. 稀疏矩阵的创建方法

除了从稠密矩阵转换,SciPy 还提供了多种直接创建稀疏矩阵的方法。

4.1 从数据数组创建

from scipy.sparse import csr_matrix 方式一:从 (data, (row, col)) 创建 data = np.array([1, 2, 3, 4]) row = np.array([0, 1, 2, 3]) col = np.array([0, 1, 2, 3]) matrix = csr_matrix((data, (row, col)), shape=(4, 4)) print("对角矩阵:") print(matrix.toarray())

4.2 创建特殊矩阵

from scipy.sparse import identity, diags, random 单位矩阵 eye = identity(5, format='csr') print("单位矩阵:") print(eye.toarray()) 对角矩阵 d = diags([1, 2, 3, 4], offsets=[0], shape=(4, 4)) print("对角矩阵:") print(d.toarray()) 随机稀疏矩阵 r = random(5, 5, density=0.2, format='csr') print("随机稀疏矩阵(密度 0.2):") print(r.toarray())

4.3 从文件加载

from scipy.io import mmread, savemat from scipy.sparse import csr_matrix 保存为 Matrix Market 格式 matrix = csr_matrix(np.random.rand(5, 5) < 0.2, dtype=np.float64) 实际保存时使用: from scipy.io import mmwrite mmwrite('matrix.mtx', matrix) 读取 Matrix Market 格式 loaded = mmread('matrix.mtx') print(loaded.toarray())

5. 稀疏矩阵的常用操作

5.1 矩阵转换与格式互转

from scipy.sparse import csr_matrix, csc_matrix, coo_matrix 创建 CSR 矩阵 csr = csr_matrix([[1, 0, 0], [0, 2, 0], [0, 0, 3]]) 格式互转 csc = csr.tocsc() coo = csr.tocoo() dense = csr.toarray() print("CSR 转 CSC 成功:", isinstance(csc, csc_matrix)) print("CSR 转 COO 成功:", isinstance(coo, coo_matrix)) print("CSR 转稠密矩阵:") print(dense)

5.2 矩阵运算

from scipy.sparse import csr_matrix A = csr_matrix([[1, 0, 2], [0, 3, 0], [4, 0, 5]]) B = csr_matrix([[1, 1, 0], [0, 1, 1], [1, 0, 1]]) 加法 C = A + B print("A + B:") print(C.toarray()) 乘法(矩阵乘法) D = A @ B print("A @ B:") print(D.toarray()) 逐元素乘法 E = A.multiply(B) print("A.multiply(B):") print(E.toarray()) 转置 F = A.T print("A 的转置:") print(F.toarray())

5.3 切片与索引

from scipy.sparse import csr_matrix matrix = csr_matrix([ [1, 0, 0, 2], [0, 3, 0, 0], [4, 0, 5, 0], [0, 0, 0, 6] ]) 获取单个元素 print("matrix[1, 1]:", matrix[1, 1]) 获取一行 row = matrix[1] print("第 2 行:", row.toarray()) 切片 sub = matrix[0:2, 0:2] print("左上角 2×2 子矩阵:") print(sub.toarray()) 修改元素 matrix[0, 0] = 10 print("修改后:") print(matrix.toarray())

5.4 统计与聚合

from scipy.sparse import csr_matrix matrix = csr_matrix([ [1, 0, 2], [0, 3, 0], [4, 0, 5] ]) 非零元素个数 print("非零元素个数:", matrix.nnz) 每行非零元素个数 print("每行非零元素个数:", matrix.getnnz(axis=1)) 每列非零元素个数 print("每列非零元素个数:", matrix.getnnz(axis=0)) 求和 print("所有元素之和:", matrix.sum()) print("每行之和:", matrix.sum(axis=1)) print("每列之和:", matrix.sum(axis=0))

6. 实战案例:推荐系统中的用户-物品评分矩阵

下面通过一个完整的实战案例,演示如何使用 SciPy 稀疏矩阵处理推荐系统中的用户-物品评分数据。

6.1 构建评分矩阵

import numpy as np from scipy.sparse import csr_matrix, save_npz, load_npz 模拟用户-物品评分数据 用户 ID、物品 ID、评分 user_ids = np.array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4]) item_ids = np.array([0, 2, 1, 3, 0, 4, 2, 3, 1, 4]) ratings = np.array([5, 3, 4, 2, 5, 1, 3, 4, 2, 5]) num_users = 5 num_items = 5 构建稀疏评分矩阵 rating_matrix = csr_matrix((ratings, (user_ids, item_ids)), shape=(num_users, num_items)) print("评分矩阵:") print(rating_matrix.toarray()) print("非零评分数量:", rating_matrix.nnz)

6.2 计算用户相似度

from scipy.sparse import csr_matrix from sklearn.preprocessing import normalize 对评分矩阵按行归一化 normalized = normalize(rating_matrix, norm='l2', axis=1) 计算用户相似度矩阵(余弦相似度) user_similarity = normalized @ normalized.T print("用户相似度矩阵:") print(user_similarity.toarray())

6.3 基于物品的协同过滤推荐

from scipy.sparse import csr_matrix 计算物品相似度矩阵 item_similarity = normalized.T @ normalized print("物品相似度矩阵:") print(item_similarity.toarray()) 为某个用户生成推荐 def recommend(user_id, rating_matrix, item_similarity, top_k=3): # 获取用户已评分的物品 user_ratings = rating_matrix[user_id].toarray().flatten() rated_items = np.where(user_ratings > 0)[0] # 计算未评分物品的预测评分 scores = {} for item in range(rating_matrix.shape[1]): if item in rated_items: continue # 基于相似物品的加权评分 sim_items = item_similarity[item].toarray().flatten() sim_items[rated_items] = 0 # 只考虑已评分物品 if sim_items.sum() &gt; 0: scores[item] = (sim_items @ user_ratings) / sim_items.sum() 返回 Top-K 推荐 recommendations = sorted(scores.items(), key=lambda x: x[1], reverse=True)[:top_k] return recommendations 为用户 0 生成推荐 recs = recommend(0, rating_matrix, item_similarity) print("为用户 0 的推荐结果:") for item, score in recs: print(f" 物品 {item}: 预测评分 {score:.2f}")

6.4 保存与加载稀疏矩阵

from scipy.sparse import save_npz, load_npz 保存为 .npz 格式 save_npz('rating_matrix.npz', rating_matrix) print("评分矩阵已保存") 加载稀疏矩阵 loaded = load_npz('rating_matrix.npz') print("加载成功,形状:", loaded.shape) print("非零元素数量:", loaded.nnz)

7. 性能对比:稀疏矩阵 vs 稠密矩阵

为了直观展示稀疏矩阵的优势,下面进行一个简单的性能对比实验。

import numpy as np import time from scipy.sparse import csr_matrix, random 创建一个 10000×10000 的稀疏矩阵,密度 0.1% n = 10000 density = 0.001 生成稀疏矩阵 sparse_mat = random(n, n, density=density, format='csr') print(f"稀疏矩阵非零元素: {sparse_mat.nnz}") 内存对比 dense_memory = n * n * 8 # float64 sparse_memory = sparse_mat.data.nbytes + sparse_mat.indices.nbytes + sparse_mat.indptr.nbytes print(f"稠密矩阵内存: {dense_memory / 1024 / 1024:.1f} MB") print(f"稀疏矩阵内存: {sparse_memory / 1024 / 1024:.2f} MB") print(f"内存节省: {dense_memory / sparse_memory:.0f} 倍") 矩阵乘法性能对比 vector = np.random.rand(n) 稀疏矩阵乘法 start = time.time() result_sparse = sparse_mat @ vector time_sparse = time.time() - start 稠密矩阵乘法(仅对小规模演示) print(f"稀疏矩阵向量乘法耗时: {time_sparse * 1000:.2f} ms")

8. 常见问题与注意事项

在使用 SciPy 稀疏矩阵时,有几个常见问题需要特别注意。

8.1 格式选择

不同格式适用于不同场景:CSR 适合行访问和矩阵乘法,CSC 适合列访问,COO 适合构建矩阵,DOK 和 LIL 适合动态修改。在实际应用中,应根据具体需求选择合适的格式。

8.2 避免隐式转换为稠密矩阵

对稀疏矩阵执行某些操作时,可能会隐式转换为稠密矩阵,导致内存爆炸。例如,对稀疏矩阵使用布尔索引时,应格外小心。

from scipy.sparse import csr_matrix matrix = csr_matrix([[1, 0], [0, 2]]) 避免这样做(可能触发稠密转换) result = matrix[matrix > 0] 推荐做法:使用稀疏矩阵的专用方法 nonzero_indices = matrix.nonzero() print("非零元素位置:", nonzero_indices)

8.3 稀疏矩阵与 NumPy 的互操作

稀疏矩阵与 NumPy 数组之间的转换需要注意数据类型和格式。使用toarray()方法可以转换为稠密数组,但应确保矩阵规模在可接受范围内。

from scipy.sparse import csr_matrix matrix = csr_matrix([[1, 0], [0, 2]]) 转换为 NumPy 数组 dense = matrix.toarray() print("NumPy 数组:") print(dense) 从 NumPy 数组创建 new_matrix = csr_matrix(dense) print("从 NumPy 数组创建成功")

9. 总结

本文系统介绍了 SciPy 稀疏矩阵的核心概念、常见格式、创建方法、常用操作和实战案例。稀疏矩阵是处理大规模稀疏数据的重要工具,在推荐系统、自然语言处理、图计算等领域有着广泛应用。

掌握稀疏矩阵的关键在于理解不同格式的特点和适用场景,并根据实际需求选择合适的格式。在实际项目中,建议先评估数据的稀疏程度和操作类型,再决定使用哪种稀疏矩阵格式,从而在内存效率和计算性能之间取得最佳平衡。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/3 6:59:21

胎化社会:数字时代的人的生存困境

摘要&#xff1a;算法、AI与商业平台正把现代人重新养进一座“人造子宫”&#xff0c;带来不可忽视的精神退行。本文围绕二次子宫发育、胎包文化、脐带平台与子宫人等概念&#xff0c;剖析现代人如何从脱胎换骨滑向脱胎换胎&#xff0c;并指出重新落地现实的路径。人类自有文明…

作者头像 李华
网站建设 2026/9/3 6:58:37

配电网可靠性评估:最小路法与蒙特卡洛法工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/3 6:58:37

SQLazy 是不是你的 dbt 工作流里缺的那一环

dbt虽好亦有盲区如果你在做 analytics engineering&#xff0c;dbt 大概率已经在工作流里了。把 ELT 中的 T 交给它&#xff0c;SQL 变成可测试、可文档化、可协作的代码&#xff0c;遇到个简单转换比如 JOIN、CASE、GROUP BY&#xff0c;应付起来得心应手。但当分析逻辑变得复…

作者头像 李华
网站建设 2026/9/3 6:56:51

工业视觉检测:从700张图片到YOLOv8数据集的完整构建与标注策略

简介&#xff1a;本资源是面向工业视觉检测场景的传送带皮带破损缺陷识别专用数据集&#xff0c;适用于YOLOv8等目标检测模型的训练与验证&#xff0c;特别适合智能制造、设备巡检及自动化质检领域的算法工程师与高校研究者开展缺陷检测实践。数据集包含700张真实场景采集的传送…

作者头像 李华
网站建设 2026/9/3 6:56:16

Python仿真轴承故障信号:从时域波形到频谱与包络谱分析实战

简介&#xff1a;本资源面向机械故障诊断、信号处理方向的本科生、研究生及工程技术人员&#xff0c;提供轴承典型故障&#xff08;如内圈、外圈、滚动体缺陷&#xff09;的仿真信号分析完整实践方案。资源包含时域波形图与频谱图的生成与可视化代码&#xff0c;辅以直观的操作…

作者头像 李华