使用稀疏矩阵时如何保留额外的列信息?

How to preserve extra column information when using sparse matrices?

我正在尝试了解如何在使用稀疏矩阵时保留额外信息。我正在编写一些代码,将 pandas 数据帧转换为网络。数据框有一个包含节点的列、一个包含边的列和一些属性列。

>>> df.head()

  authors  papers     attr1             attr2
0       g  [4, 8]  yikpmrbf  FCCLYDWSFJVORGXL
1       h     [7]  zxdkzyam  DHJZADCAPRQYAXGR
2       c     [4]  lnynqqhf  PACVSZULQSKXBURW
3       k  [5, 3]  vjzgyebn  QMLHUIDWXGNPVQTH
4       r     [7]  etjghgcp  CSYIMFXKOYFWWUTH

到目前为止,我一直在使用以下代码制作 networkx 图,其中 authors 是具有边的节点,如果它们在 papers 中共享一个值。

from itertools import chain
import numpy as np
from scipy import sparse
import networkx as nx

node='authors'
link='papers'

indptr = np.fromiter(chain((0,), map(len, df[link])),
                     int, len(df[link])+1).cumsum()
unq, idx = np.unique(np.concatenate(df[link]), return_inverse=True)
node_link_matrix = sparse.csr_matrix(
    (np.ones(idx.size, int), idx, indptr),
    (len(df[link]),
     len(unq))
)
node_node_matrix = (node_link_matrix@node_link_matrix.T).tocoo()
G = nx.convert_matrix.from_scipy_sparse_matrix(node_node_matrix)

这会计算数据中每个节点-节点对的边权重。 node_link_matrix 的行数与数据框中的行数一样多,列数与独特的边缘值(在本例中为独特的论文)一样多。因此,这些值表示 "how many of x paper are present in x row"。 node_node_matrix 是正方形,rows/columns 与数据框中的行数一样多。它是 node_link_matrixnode_link_matrix 转置后的点积。这些值是边的权重,这个矩阵可以很容易地用networkx变成一个图。

>>> node_link_matrix
<74x10 sparse matrix of type '<class 'numpy.int64'>'
    with 140 stored elements in Compressed Sparse Row format>

>>> node_node_matrix
<74x74 sparse matrix of type '<class 'numpy.int64'>'
    with 1786 stored elements in COOrdinate format>

我正在尝试的是将有关 attr1 列的信息放入其中。我首先尝试将 "ones" 替换为实际的属性字符串,因此之前的代码变为:

from itertools import chain
import numpy as np
from scipy import sparse
import networkx as nx

node='authors'
link='papers'

indptr = np.fromiter(chain((0,), map(len, df[link])),
                     int, len(df[link])+1).cumsum()
unq, idx = np.unique(np.concatenate(df[link]), return_inverse=True)
node_link_matrix = sparse.csr_matrix(
    (np.repeat(df.attr1.values, np.diff(indptr)), idx, indptr),  # <-- Changed this part
    (len(df[link]),
     len(unq))
)

这不起作用,因为稀疏矩阵不能很好地处理字符串。我试图通过用将每次出现映射到正确属性的字典替换实际值来克服这个问题

from itertools import chain
import numpy as np
from scipy import sparse
import networkx as nx

node='authors'
link='papers'

indptr = np.fromiter(chain((0,), map(len, df[link])),
                     int, len(df[link])+1).cumsum()
unq, idx = np.unique(np.concatenate(df[link]), return_inverse=True)
node_link_matrix = sparse.csr_matrix(
    (range(idx.size), idx, indptr),  # <-- Values are now IDs
    (len(df[link]),
     len(unq))
)

edge_attr_dict = dict(zip(range(idx.size), np.repeat(df.attr1.values, np.diff(indptr))))

然后,这给了我一个 node_link_matrix 映射节点值到边缘值及其对应的 attr1 值。问题是,由于现在的值是符号数字,而不仅仅是 1 和 0,因此获取节点-节点关系的点积函数不再起作用。所以我需要的是一种方法来保留稀疏矩阵中的节点属性信息,但仍然能够按原样使用点积函数。我一直在考虑这是否可以通过 "pushing" 属性进入三维,使用 3d 张量而不是稀疏矩阵来完成,但我对此没有太多经验。

这是一种相当快速的方法,可以将您的 table 重新处理为 Node 1 -Node 2 - Edge attributes

edges = []

for p, group in df.explode("papers").groupby("papers"):

    # Add a new author2 edge column and explode it
    authors = group["authors"].tolist()
    group = group.copy() # This explicit copy suppresses an implicit-copy warning
    group["author2"] = [authors for _ in range(group.shape[0])]
    group = group.explode("author2")

    # Get rid of self-interaction rows
    edges.append(group.loc[group["authors"] != group["author2"], :])

edges = pd.concat(edges)
edges.reset_index(drop=True, inplace=True)

这在内存方面比 COO 矩阵更大,但只要您的数据不是非常大,拥有数据帧的灵活性是值得的。