用于机器学习的稀疏矩阵

2025年6月19日 | 阅读 12 分钟

稀疏矩阵在机器学习中发挥着不可或缺的作用,尤其是在处理具有许多零值的高维数据时。这可以减少计算量和内存使用量,最小化内存占用,并提高处理大型数据集的速度。本文旨在全面介绍稀疏矩阵:它们是什么,在机器学习中的用途,以及对可扩展高效建模的贡献。

稀疏矩阵是一种矩阵,其中大部分元素是零;而稠密矩阵则包含大部分非零元素。稀疏矩阵的实际应用通常出现在自然语言处理(NLP)、计算机视觉和推荐系统中,这些领域包含大量数据,其中包含大量零。稀疏矩阵在内存方面更轻量,因为它只存储非零元素的位置和值,从而优化了内存和功耗。

稀疏矩阵机器学习中至关重要,因为它们具有内存和计算效率,尤其是在处理具有许多零的大型数据集时。通过仅存储非零值,它们可以显著减少内存使用并加快计算速度,因为算法可以跳过零。这使得矩阵乘法等运算更快。稀疏矩阵还优化了存储,能够更好地管理NLP和大数据等领域中常见的海量数据集。

处理稀疏矩阵

使用 Python 的 scipy.sparse 模块有多种处理稀疏矩阵的方法。以下是一些广泛使用的稀疏矩阵格式:

  • Compressed Sparse Row (CSR):这是最常用的格式之一。压缩稀疏行(CSR)格式以一种天然支持高效行切片和快速矩阵向量乘法的方式组织数据。因此,它适用于频繁的基于行的操作和大规模计算。
  • Compressed Sparse Column (CSC):CSC 格式针对列切片进行了优化,并支持高效的矩阵分解。因此,当频繁访问列或转换矩阵时,它非常适用。
  • Dictionary of Keys (DOK):对于动态构建和灵活的元素修改,字典键(DOK)格式非常有用。将矩阵表示为行和列坐标的字典意味着可以直接添加或修改值。这使得 DOK 成为增量构建稀疏矩阵的便捷选择,尽管一旦矩阵完成,可能需要将其转换为其他格式以获得最佳操作。
  • Coordinate List (COO):坐标列表(COO)格式在初始化稀疏矩阵时方便且流行。COO 格式存储每个元素及其行和列索引,因此从原始坐标数据构建稀疏矩阵非常容易。COO 格式的矩阵通常会转换为 CSR 或 CSC 以进行后续操作,因为它不提供优化的操作。

稀疏矩阵在机器学习中的应用

稀疏矩阵在机器学习领域的不同领域得到了广泛应用,包括但不限于以下方面:

  • 自然语言处理 (NLP):在 NLP 中,数据通常是文本文档,以极高维空间的向量形式表示,每个维度对应词汇表中的不同元素。例如,词袋模型或 TF-IDF 表示中的大部分条目都是零,因为文档只包含整体词汇表的一小部分。稀疏矩阵通过仅存储非零计数来支持高效处理这些大型特征空间。
  • 推荐系统:最频繁的用户-项目交互将保留在稀疏矩阵中,因为用户几乎不可能与所有项目进行交互,因此大部分条目将为零。这些稀疏矩阵有助于高效地维护此数据结构,从而以最小的存储要求进行推荐。
  • 图像处理:图像数据也可以表示为矩阵,其中像素值构成条目。在某些图像(如二值图像或阈值图像)中,大部分像素条目为零。因此,稀疏矩阵可用于以节省内存并加速处理的方式存储图像数据,例如,在将模式识别或压缩算法应用于图像时。
  • 图数据表示:在机器学习中,图通常表示为邻接矩阵。那些稀疏的图(即,大多数节点只有少量连接)通常最好使用稀疏矩阵表示,这样无需存储不必要的零,从而实现图算法的可扩展性。

机器学习中稀疏矩阵的挑战

在使用稀疏矩阵时,需要考虑各种挑战和注意事项。

  • 有限的操作:稀疏矩阵可能使某些矩阵操作比预期的效率低下或更加复杂。并非所有算法都支持稀疏数据,通常需要特殊技术或库。例如,特定的分解和一些转换可能不像处理普通全尺寸稀疏矩阵那样容易执行。
  • 模型兼容性:并非所有机器学习模型都能够处理稀疏矩阵。虽然线性模型在数据非常稀疏时不会损失太多性能,但更复杂的模型(如神经网络)可能会出现问题,除非它们是专门为稀疏输入设计的。基于所有元素交互的模型在稀疏数据上表现可能较差。
  • 转换开销:即使是稀疏和稠密格式之间,或不同稀疏格式之间的简单转换,也会产生计算开销。每种格式(如 CSR 或 CSC)都针对特定任务进行了优化,格式之间的转换通常会影响管道的速度和效率。
  • 数据操作的复杂性:稀疏矩阵可能会增加简单数据操作的复杂性,而这些操作在索引或切片时非常常见。由于数据和索引是分开存储的,因此与稠密矩阵相比,访问或修改值可能更加复杂,使得数据操作更具挑战性。
  • 某些模型的信息精度损失:如果零条目对特定任务有信息量,那么稀疏矩阵中可能会丢失重要信息。虽然稀疏格式对大多数任务都非常高效,但如果零值有意义,它们的缺失可能会严重降低模型性能。

现在,我们将通过稀疏矩阵来演示内存使用量的减少。

稀疏矩阵的内存使用量减少

该数据集对于可用的 16 GB 内存来说太大了。具体来说,训练输入由 105,942 列和 228,942 行组成,总计 97 GB。另一方面,训练目标占 105,942 列和 23,418 行,约为 10 GB。测试输入则占 55,935 列和 228,942 行,总计 13 GB。由于数据量巨大,无法一次性全部加载到内存中。然而,数据本身包含大量零,因此具有高度稀疏性。

我们无法加载整个数据集。因此,为了研究数据集的稀疏性,我们只取前 5000 行,以便在内存限制内进行分析。

 

输出

Sparse Matrices for Machine Learning

现在,我们将计算每列中的非零值数量。

输出

Sparse Matrices for Machine Learning

可以通过计算非零值占总值的比例来确定 DataFrame 的整体稀疏性。

输出

 
0.021427460230101947   

由于非零值的数量仅占加载数据集总量的 2%,因此我们可以轻松地说该数据集非常稀疏。因此,数据集的其余部分也应如此;如果我们使用不同的数据结构,就可以消除这种内存浪费。

输出

 
63   

内存优化

Multiome 中的数据本质上是稀疏的,而稀疏矩阵是处理内存使用效率最高的方式,可以让我们以更少的内存开销加载数据。更具体地说,CSR 矩阵通过三个一维数组在内存使用方面是最佳的,同时还具有与矩阵稀疏性相关的某些特殊结构。数据数组仅包含非零元素,并以最紧凑的形式存储,直接对应于数据的实际值。索引数组的形状与数据数组相同;它包含每个非零值的列索引。然后,ptr_ind 数组通过标记数据数组和索引数组中每个行的边界,方便地访问行。从给定的数据数组中获取行 `i` 的所有条目就像在数据数组中切片索引 `ptr_ind[i]` 到 `ptr_ind[i+1]` 之间一样。索引数组也是如此。由于这是一个内存密集型数据集 Train-Multi-Inputs,我们可以通过分块数据按顺序构建这三个数组,从而在内存限制内管理大型数据集。

为了进一步优化性能,我们还在 Cython 代码中计算了 ptr_ind 数组,这可以将处理时间减少几个数量级,因为它使得行索引的压缩最优化,从而有效将时间缩短一半。

输出

Sparse Matrices for Machine Learning

我们可以向数组添加最后一个元素,它表示索引或数据数组的长度,因为 ptr_ind 数组的形状是 (行数),而不是 (行数 + 1)。

输出

Sparse Matrices for Machine Learning

其他 Multiome 文件(如 target_trains 和 test_inputs)也可以以更少的内存使用量保存。许多最先进的模型都可以使用稀疏矩阵作为训练数据,这加速了计算,并避免了繁琐且缓慢的迭代器。

现在,我们也可以使用稀疏矩阵对稀疏矩阵相关数据进行 EDA。

使用稀疏矩阵进行 EDA

稀疏矩阵在这方面非常有用,尤其是在处理 Multiome 数据时,因为 Multiome 数据集中 98% 的单元格包含零。将数据编码为稀疏矩阵可以节省大量内存。稀疏表示可以更有效地利用内存;内存需求低于 8GB,而不是稠密格式所需的约 90GB;这使得可以将完整的训练数据加载到内存中。现在,让我们通过 AmbrosM 来实际操作,我们将介绍一种处理 Multiome 数据的更优方法,并为 Kaggle 竞争者提供稀疏与稠密数据表示的直观比较。与 AmbrosM 的笔记本相比,关键区别在于数据以稀疏 CSR 格式呈现,并且 PCA 或 TruncatedSVD 应用于整个训练集,而不是仅限于 6000 行 x 4000 列的选定子集。

保留了 16 个组件,而不是 AmbrosM 笔记本中的 4 个,并且 Ridge 回归应用于 50,000 行,而不是 6,000 行。尽管此笔记本处理的数据量更大,但仅需约 10 分钟即可完成,而 AmbrosM 的方法需要一个小时。竞赛数据已预先编码为稀疏矩阵,可直接用于 Multiome 预测,而 CITEseq 预测则来自 VuongLam 的公开笔记本,目前该笔记本仍保持最高评分。

以下函数计算 true_y 和 pred_y 之间每行的皮尔逊相关系数,然后对所有这些相关系数取平均值。

首先,我们加载 Multiome 的所有训练输入数据。这应该不到一分钟。

输出

Sparse Matrices for Machine Learning

PCA

我们无法直接将 PCA 应用于稀疏矩阵,因为 PCA 首先需要“中心化”数据,这会破坏稀疏性。我们改用 TruncatedSVD,它基本上是“无中心化的 PCA”。我们可能需要对其进行一些更好的归一化,但出于简化的目的,我们将省略它。

输出

Sparse Matrices for Machine Learning

然而,Sklearn 的 Ridge 回归不接受稀疏矩阵作为目标值,尽管它们可以作为输入。因此,目标值需要转换为稠密格式。稀疏输入数据和稠密目标数据都可以存储在内存中,但这会导致 Ridge 回归过程内存不足。因此,从现在开始,我们将使用训练数据的一个子集(50,000 行)。

输出

Sparse Matrices for Machine Learning

输出

 
124  

Sklearn 抱怨说数组比矩阵更好。遗憾的是,Kaggle 上可用的旧版 Scipy 版本不支持稀疏数组,只支持稀疏矩阵。因此,警告将被抑制。

输出

Sparse Matrices for Machine Learning

输出

Sparse Matrices for Machine Learning