如何读取边列表以创建一个scipy稀疏矩阵

6

我有一个大文件,每一行都有一对8个字符的字符串。类似这样:

ab1234gh iu9240gh

每一行都有一个字符串,文件实际上代表了一个图形,每个字符串是一个节点id。我想读入该文件并直接制作成scipy稀疏邻接矩阵。然后,我将使用Python中提供的众多工具之一在该矩阵上运行PCA。

有没有简单的方法可以做到这一点,或者我需要先在内存中创建一个图形,然后将其转换为稀疏矩阵?由于文件很大,我希望尽可能避免中间步骤。

最终我将把稀疏邻接矩阵馈送到http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.TruncatedSVD.html#sklearn.decomposition.TruncatedSVD

1个回答

5
我认为这是sklearn中的常规任务,因此该软件包中必须有一些工具可以完成此操作,或者在其他SO问题中有答案。我们需要添加正确的标记。
但是仅从我对numpysparse的了解来看,我会做以下事情:
创建一个样本2D数组- N行,2列,其中包含字符值:
In [638]: A=np.array([('a','b'),('b','d'),('a','d'),('b','c'),('d','e')])
In [639]: A
Out[639]: 
array([['a', 'b'],
       ['b', 'd'],
       ['a', 'd'],
       ['b', 'c'],
       ['d', 'e']], 
      dtype='<U1')

使用np.unique来识别唯一的字符串,并作为奖励提供从这些字符串到原始数组的映射。这是该任务的核心。
In [640]: k1,k2,k3=np.unique(A,return_inverse=True,return_index=True)
In [641]: k1
Out[641]: 
array(['a', 'b', 'c', 'd', 'e'], 
      dtype='<U1')
In [642]: k2
Out[642]: array([0, 1, 7, 3, 9], dtype=int32)
In [643]: k3
Out[643]: array([0, 1, 1, 3, 0, 3, 1, 2, 3, 4], dtype=int32)

我可以重塑那个 inverse 数组,以确定每个 A 中的条目所在的行和列。
In [644]: rows,cols=k3.reshape(A.shape).T
In [645]: rows
Out[645]: array([0, 1, 0, 1, 3], dtype=int32)
In [646]: cols
Out[646]: array([1, 3, 3, 2, 4], dtype=int32)

使用这些工具,构建一个每个“交叉点”处都有1的稀疏矩阵是轻而易举的。
In [648]: M=sparse.coo_matrix((np.ones(rows.shape,int),(rows,cols)))
In [649]: M
Out[649]: 
<4x5 sparse matrix of type '<class 'numpy.int32'>'
    with 5 stored elements in COOrdinate format>
In [650]: M.A
Out[650]: 
array([[0, 1, 0, 1, 0],
       [0, 0, 1, 1, 0],
       [0, 0, 0, 0, 0],
       [0, 0, 0, 0, 1]])

第一行,a 在第二列和第四列有值,分别是 bd,以此类推。

============================

原始内容:

In [648]: M=sparse.coo_matrix((np.ones(k1.shape,int),(rows,cols)))

这是错的。 data 数组应该与 rowscols 的形状匹配。这里没有引发错误,因为 k1 恰好具有相同的大小。但是,如果混合不同的唯一值,则可能会引发错误。
====================
这种方法假设整个数据库 A 可以加载到内存中。 unique 可能需要类似的内存使用。最初,coo 矩阵可能不会增加内存使用量,因为它将使用提供作为参数的数组。但是,任何计算和/或转换为 csr 或其他格式都将进行进一步的复制。
我可以想象通过分块加载数据库并使用某些其他结构来获取唯一值和映射来解决内存问题。您甚至可以从块构造一个 coo 矩阵。但迟早你会遇到内存问题。scikit 代码将创建该稀疏矩阵的一个或多个副本。

谢谢。是否可以在不必先读取整个矩阵的情况下逐块进行操作? - Simd
根据您的需求,您可以使用类似于此答案的方法逐块读取文件,然后找到应该填充的行和列。 - Mahdi
我已经在https://dev59.com/l1kT5IYBdhLWcg3wX-dp发布了关于我的问题的后续内容。 - Simd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接