- SciPy 教程
- SciPy - 首页
- SciPy - 简介
- SciPy - 环境设置
- SciPy - 基本功能
- SciPy - 聚类
- SciPy - 常量
- SciPy - FFTpack
- SciPy - 积分
- SciPy - 插值
- SciPy - 输入和输出
- SciPy - 线性代数
- SciPy - Ndimage
- SciPy - 优化
- SciPy - 统计
- SciPy - CSGraph
- SciPy - 空间
- SciPy - ODR
- SciPy - 特殊函数包
- SciPy 有用资源
- SciPy - 参考
- SciPy - 快速指南
- SciPy - 有用资源
- SciPy - 讨论
SciPy - CSGraph
CSGraph 代表压缩稀疏图,专注于基于稀疏矩阵表示的快速图算法。
图表示
首先,让我们了解什么是稀疏图以及它如何帮助图表示。
什么是稀疏图?
图只是一组节点,节点之间有链接。图几乎可以表示任何东西——社交网络连接,其中每个节点都是一个人,并连接到熟人;图像,其中每个节点都是一个像素,并连接到相邻像素;高维分布中的点,其中每个节点都连接到其最近邻;以及你能想到的几乎任何其他东西。
表示图数据的一种非常有效的方法是使用稀疏矩阵:我们称之为 G。矩阵 G 的大小为 N x N,而 G[i, j] 给出节点“i”和节点“j”之间连接的值。稀疏图主要包含零——也就是说,大多数节点只有少量连接。事实证明,在大多数感兴趣的情况下,此属性都是正确的。
稀疏图子模块的创建是由 scikit-learn 中使用的几种算法驱动的,这些算法包括以下内容:
Isomap - 一种流形学习算法,需要在图中找到最短路径。
层次聚类 - 一种基于最小生成树的聚类算法。
谱分解 - 一种基于稀疏图拉普拉斯算子的投影算法。
作为一个具体的例子,假设我们想表示以下无向图:
此图有三个节点,其中节点 0 和 1 通过权重为 2 的边连接,节点 0 和 2 通过权重为 1 的边连接。我们可以构建密集、掩码和稀疏表示,如以下示例所示,记住无向图由对称矩阵表示。
G_dense = np.array([ [0, 2, 1], [2, 0, 0], [1, 0, 0] ]) G_masked = np.ma.masked_values(G_dense, 0) from scipy.sparse import csr_matrix G_sparse = csr_matrix(G_dense) print G_sparse.data
以上程序将生成以下输出。
array([2, 1, 2, 1])
这与之前的图相同,除了节点 0 和 2 通过权重为零的边连接。在这种情况下,上面的密集表示会导致歧义——如果零是有意义的值,如何表示非边。在这种情况下,必须使用掩码或稀疏表示来消除歧义。
让我们考虑以下示例。
from scipy.sparse.csgraph import csgraph_from_dense G2_data = np.array ([ [np.inf, 2, 0 ], [2, np.inf, np.inf], [0, np.inf, np.inf] ]) G2_sparse = csgraph_from_dense(G2_data, null_value=np.inf) print G2_sparse.data
以上程序将生成以下输出。
array([ 2., 0., 2., 0.])
使用稀疏图的单词阶梯
单词阶梯是由刘易斯·卡罗尔发明的一种游戏,其中单词通过每次更改一个字母来链接。例如:
APE → APT → AIT → BIT → BIG → BAG → MAG → MAN
在这里,我们已经用七步从“APE”到“MAN”,每次更改一个字母。问题是——我们能否使用相同的规则找到这些词之间更短的路径?这个问题自然地表示为一个稀疏图问题。节点将对应于单个单词,并且我们将创建连接那些最多相差一个字母的单词对之间的边。
获取单词列表
首先,当然,我们必须获得有效单词的列表。我正在运行 Mac,Mac 在以下代码块中给出的位置有一个词典。如果您使用的是不同的架构,则可能需要搜索一下才能找到您的系统词典。
wordlist = open('/usr/share/dict/words').read().split() print len(wordlist)
以上程序将生成以下输出。
235886
现在我们想查看长度为 3 的单词,因此让我们只选择那些正确长度的单词。我们还将消除以大写字母开头(专有名词)或包含非字母数字字符(如撇号和连字符)的单词。最后,我们将确保所有内容都小写,以便稍后进行比较。
word_list = [word for word in word_list if len(word) == 3] word_list = [word for word in word_list if word[0].islower()] word_list = [word for word in word_list if word.isalpha()] word_list = map(str.lower, word_list) print len(word_list)
以上程序将生成以下输出。
1135
现在,我们有了一个包含 1135 个有效三个字母单词的列表(确切数量可能会根据使用的特定列表而有所不同)。这些单词中的每一个都将成为我们图中的一个节点,我们将创建连接与每个单词对相关联的节点的边,这些单词对只相差一个字母。
import numpy as np word_list = np.asarray(word_list) word_list.dtype word_list.sort() word_bytes = np.ndarray((word_list.size, word_list.itemsize), dtype = 'int8', buffer = word_list.data) print word_bytes.shape
以上程序将生成以下输出。
(1135, 3)
我们将使用每个点之间的汉明距离来确定哪些单词对是连接的。汉明距离衡量两个向量之间不同条目的分数:任何两个汉明距离等于 1/N1/N 的单词,其中 NN 是单词中字母的数量,这些字母在单词阶梯中是连接的。
from scipy.spatial.distance import pdist, squareform from scipy.sparse import csr_matrix hamming_dist = pdist(word_bytes, metric = 'hamming') graph = csr_matrix(squareform(hamming_dist < 1.5 / word_list.itemsize))
在比较距离时,我们不使用相等性,因为这对于浮点值来说可能不稳定。只要单词列表中没有两个条目相同,不等式就会产生所需的结果。现在,我们的图设置好了,我们将使用最短路径搜索来查找图中任意两个单词之间的路径。
i1 = word_list.searchsorted('ape') i2 = word_list.searchsorted('man') print word_list[i1],word_list[i2]
以上程序将生成以下输出。
ape, man
我们需要检查这些是否匹配,因为如果这些单词不在列表中,输出将出现错误。现在,我们只需要找到图中这两个索引之间的最短路径即可。我们将使用迪杰斯特拉算法,因为它允许我们仅为一个节点查找路径。
from scipy.sparse.csgraph import dijkstra distances, predecessors = dijkstra(graph, indices = i1, return_predecessors = True) print distances[i2]
以上程序将生成以下输出。
5.0
因此,我们看到“ape”和“man”之间的最短路径仅包含五个步骤。我们可以使用算法返回的前驱来重建此路径。
path = [] i = i2 while i != i1: path.append(word_list[i]) i = predecessors[i] path.append(word_list[i1]) print path[::-1]i2]
以上程序将生成以下输出。
['ape', 'ope', 'opt', 'oat', 'mat', 'man']