# 机器学习中的稀疏矩阵的温和介绍

> 原文： [https://machinelearningmastery.com/sparse-matrices-for-machine-learning/](https://machinelearningmastery.com/sparse-matrices-for-machine-learning/)

主要包含零值的矩阵称为稀疏矩阵，与大多数值非零的矩阵不同，称为密集。

大型稀疏矩阵通常是常见的，尤其是在应用机器学习中，例如包含计数的数据，将类别映射到计数的数据编码，甚至在机器学习的整个子字段中，例如自然语言处理。

表示和使用稀疏矩阵就好像它们是密集的一样计算成本很高，并且通过使用专门处理矩阵稀疏性的表示和操作可以实现表现的大大改进。

在本教程中，您将发现稀疏矩阵，它们出现的问题以及如何直接在 Python 中使用它们。

完成本教程后，您将了解：

*   稀疏矩阵主要包含零值，与密集矩阵不同。
*   无数区域中您可能会遇到数据，数据准备和机器学习子字段中的稀疏矩阵。
*   有许多有效的方法来存储和使用稀疏矩阵，SciPy 提供了可以直接使用的实现。

让我们开始吧。

![A Gentle Introduction to Sparse Matrices for Machine Learning](img/f9be8453259dc1cacd2394113a4c6e5f.jpg)

机器学习稀疏矩阵的温和介绍
摄影： [CAJC：在落基山脉](https://www.flickr.com/photos/carolannie/26617750821/)，保留一些权利。

## 教程概述

本教程分为 5 个部分;他们是：

*   稀疏矩阵
*   稀疏性问题
*   机器学习中的稀疏矩阵
*   使用稀疏矩阵
*   Python 中的稀疏矩阵

## 稀疏矩阵

稀疏矩阵是主要由零值组成的矩阵。

稀疏矩阵不同于具有大多数非零值的矩阵，其被称为密集矩阵。

> 如果矩阵的许多系数为零，则矩阵是稀疏的。对稀疏性的兴趣之所以产生，是因为它的利用可以带来巨大的计算节省，并且因为在实践中出现的许多大矩阵问题都很少。

- 第 1 页，[稀疏矩阵的直接方法](http://amzn.to/2DcsQVU)，第二版，2017 年。

矩阵的稀疏度可以用分数量化，分数是矩阵中零值的数量除以矩阵中元素的总数。

```
sparsity = count zero elements / total elements
```

下面是一个小的 3 x 6 稀疏矩阵的示例。

```
     1, 0, 0, 1, 0, 0
A = (0, 0, 2, 0, 0, 1)
     0, 0, 0, 2, 0, 0
```

该示例具有矩阵中 18 个元素的 13 个零值，使该矩阵的稀疏度得分为 0.722 或约 72％。

## 稀疏性问题

稀疏矩阵可能导致空间和时间复杂性方面的问题。

### 空间复杂性

非常大的矩阵需要大量内存，而我们希望使用的一些非常大的矩阵是稀疏的。

> 在实践中，大多数大型矩阵都是稀疏的 - 几乎所有条目都是零。

- 第 465 页，[线性代数简介](http://amzn.to/2AZ7R8j)，第五版，2016 年。

非常大的矩阵的一个例子是一个链接矩阵，它显示从一个网站到另一个网站的链接。

较小的稀疏矩阵的示例可以是针对所有已知英语单词的一本书中的单词的单词或术语出现矩阵。

在这两种情况下，包含的矩阵都是稀疏的，其值比数据值多得多。将这些稀疏矩阵表示为密集矩阵的问题是需要存储器，并且必须为矩阵中的每个 32 位或甚至 64 位零值分配存储器。

这显然是浪费内存资源，因为这些零值不包含任何信息。

### 时间复杂性

假设一个非常大的稀疏矩阵可以适合内存，我们将希望对该矩阵执行操作。

简单地说，如果矩阵主要包含零值，即没有数据，则在该矩阵上执行操作可能花费很长时间，其中所执行的大部分计算将涉及将零值相加或相乘在一起。

> 在这些问题上使用线性代数的一般方法是浪费的，因为大多数用于求解方程组或反转矩阵的 O（N ^ 3）算术运算涉及零操作数。

- 第 75 页，[数字秘籍：科学计算的艺术](http://amzn.to/2CF5atj)，第三版，2007 年。

这是矩阵运算的时间复杂度增加的问题，其随着矩阵的大小而增加。

当我们考虑到即使是微不足道的机器学习方法可能需要对每行，每列甚至整个矩阵进行许多操作时，这个问题也变得复杂，导致执行时间大大延长。

## 机器学习中的稀疏矩阵

稀疏矩阵在应用机器学习中出现了很多变化。

在本节中，我们将介绍一些常见示例，以激励您了解稀疏性问题。

### 数据

稀疏矩阵出现在某些特定类型的数据中，最显着的是记录活动发生或计数的观察。

三个例子包括：

*   用户是否观看了电影目录中的电影。
*   用户是否在产品目录中购买了产品。
*   歌曲目录中歌曲的听众数量。

### 数据准备

稀疏矩阵出现在用于准备数据的编码方案中。

三个常见的例子包括：

*   单热编码，用于将分类数据表示为稀疏二进制向量。
*   计数编码，用于表示文档词汇表中单词的频率
*   TF-IDF 编码，用于表示词汇表中的归一化词频分数。

### 学习领域

机器学习中的一些研究领域必须开发专门的方法来直接解决稀疏性，因为输入数据几乎总是稀疏的。

Three examples include:

*   处理文本文档的自然语言处理。
*   用于在目录中处理产品使用的推荐系统。
*   处理包含大量黑色像素的图像时的计算机视觉。

> 如果语言模型中有 100,000 个单词，则特征向量的长度为 100,000，但对于短消息，几乎所有要素都将计为零。

- 第 22 页，[人工智能：一种现代方法](http://amzn.to/2C4LhMW)，第三版，2009 年。

## 使用稀疏矩阵

表示和使用稀疏矩阵的解决方案是使用备用数据结构来表示稀疏数据。

可以忽略零值，并且仅需要存储或操作稀疏矩阵中的数据或非零值。

有多种数据结构可用于有效地构造稀疏矩阵;下面列出了三个常见的例子。

*   **键字典**。使用字典，其中行和列索引映射到值。
*   **名单**。矩阵的每一行都存储为一个列表，每个子列表包含列索引和值。
*   **坐标列表**。每个元组都存储一个元组列表，其中包含行索引，列索引和值。

还有一些数据结构更适合执行有效的操作;下面列出了两个常用的例子。

*   **压缩稀疏行**。对于非零值，行的范围和列索引，使用三个一维数组表示稀疏矩阵。
*   **压缩稀疏列**。与压缩稀疏行方法相同，除了列索引被压缩并在行索引之前首先读取。

压缩稀疏行（简称 CSR）通常用于表示机器学习中的稀疏矩阵，因为它支持高效的访问和矩阵乘法。

## Python 中的稀疏矩阵

SciPy 提供了使用多个数据结构创建稀疏矩阵的工具，以及将密集矩阵转换为稀疏矩阵的工具。

在 NumPy 数组上运行的许多线性代数 NumPy 和 SciPy 函数可以透明地在 SciPy 稀疏数组上运行。此外，使用 NumPy 数据结构的机器学习库也可以在 SciPy 稀疏数组上透明地运行，例如用于一般机器学习的 scikit-learn 和用于深度学习的 Keras。

通过调用`csr_matrix()`函数，可以使用 CSR 表示将存储在 NumPy 数组中的密集矩阵转换为稀疏矩阵。

在下面的示例中，我们将 3 x 6 稀疏矩阵定义为密集数组，将其转换为 CSR 稀疏表示，然后通过调用`todense()`函数将其转换回密集数组。

```
# dense to sparse
from numpy import array
from scipy.sparse import csr_matrix
# create dense matrix
A = array([[1, 0, 0, 1, 0, 0], [0, 0, 2, 0, 0, 1], [0, 0, 0, 2, 0, 0]])
print(A)
# convert to sparse matrix (CSR method)
S = csr_matrix(A)
print(S)
# reconstruct dense matrix
B = S.todense()
print(B)
```

运行该示例首先打印定义的密集数组，然后是 CSR 表示，然后是重建的密集矩阵。

```
[[1 0 0 1 0 0]
 [0 0 2 0 0 1]
 [0 0 0 2 0 0]]

  (0, 0)	1
  (0, 3)	1
  (1, 2)	2
  (1, 5)	1
  (2, 3)	2

[[1 0 0 1 0 0]
 [0 0 2 0 0 1]
 [0 0 0 2 0 0]]
```

NumPy 不提供计算矩阵稀疏度的函数。

然而，我们可以通过首先找到矩阵的密度并从中减去矩阵来轻松地计算它。 NumPy 数组中的非零元素的数量可以由`count_nonzero()`函数给出，并且数组中元素的总数可以由数组的 size 属性给出。因此，可以将数组稀疏度计算为

```
sparsity = 1.0 - count_nonzero(A) / A.size
```

下面的示例演示了如何计算数组的稀疏性。

```
# calculate sparsity
from numpy import array
from numpy import count_nonzero
# create dense matrix
A = array([[1, 0, 0, 1, 0, 0], [0, 0, 2, 0, 0, 1], [0, 0, 0, 2, 0, 0]])
print(A)
# calculate sparsity
sparsity = 1.0 - count_nonzero(A) / A.size
print(sparsity)
```

首先运行该示例打印定义的稀疏矩阵，然后是矩阵的稀疏性。

```
[[1 0 0 1 0 0]
 [0 0 2 0 0 1]
 [0 0 0 2 0 0]]

0.7222222222222222
```

## 扩展

本节列出了一些扩展您可能希望探索的教程的想法。

*   开发自己的示例，将密集数组转换为稀疏数组并计算稀疏性。
*   为 SciPy 支持的每个稀疏矩阵表示方法开发一个示例。
*   选择一个稀疏表示方法并从零开始自己实现。

如果你探索任何这些扩展，我很想知道。

## 进一步阅读

如果您希望深入了解，本节将提供有关该主题的更多资源。

### 图书

*   [线性代数简介](http://amzn.to/2AZ7R8j)，第五版，2016 年。
*   2.7 节稀疏线性系统，[数值秘籍：科学计算的艺术](http://amzn.to/2CF5atj)，第三版，2007。
*   [人工智能：一种现代方法](http://amzn.to/2C4LhMW)，第三版，2009 年。
*   [稀疏矩阵的直接方法](http://amzn.to/2DcsQVU)，第二版，2017 年。

### API

*   [稀疏矩阵（scipy.sparse）API](https://docs.scipy.org/doc/scipy/reference/sparse.html)
*   [scipy.sparse.csr_matrix（）API](https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.csr_matrix.html)
*   [numpy.count_nonzero（）API](https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.count_nonzero.html)
*   [numpy.ndarray.size API](https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.ndarray.size.html)

### 用品

*   [维基百科上的稀疏矩阵](https://en.wikipedia.org/wiki/Sparse_matrix)

## 摘要

在本教程中，您发现了稀疏矩阵，它们出现的问题以及如何直接在 Python 中使用它们。

具体来说，你学到了：

*   稀疏矩阵主要包含零值，与密集矩阵不同。
*   无数区域中您可能会遇到数据，数据准备和机器学习子字段中的稀疏矩阵。
*   有许多有效的方法来存储和使用稀疏矩阵，SciPy 提供了可以直接使用的实现。

你有任何问题吗？
在下面的评论中提出您的问题，我会尽力回答。