从邻接表快速创建 Scipy 稀疏矩阵
Quickly creating Scipy sparse matrix from adjacency list
我正在尝试从邻接表创建一个 networkx 图。我目前正在执行以下操作,速度很慢。我查看了 scipy.sparse 矩阵选项,据我所知 none 与我正在使用的格式相同。 adj 中的每个项目都可以有不同的长度,这使情况变得复杂。
o3dmesh.adjacency list returns 一组列表。
集合 adjacency_list[i] 包含顶点 i 的相邻顶点的索引。没有行、列索引,只有绝对索引。
import open3d as o3d
import networkx as nx
import scipy
def adj_matrix(adj):
n = len(adj)
g= scipy.sparse.dok_matrix((n,n), int)
for num, i in enumerate(adj):
g[num, list(i)] = 1
return g
o3dmesh = mesh = o3d.io.read_triangle_mesh(path)
adj = o3dmesh.adjacency_list
adj = adj_matrix(adj)
graph = nx.from_scipy_sparse_matrix(adj)
我不熟悉 networkx
或您的 adj 列表。但是从代码中我猜它是 (0,n) 范围内的整数列表或数组。
下面是从此类数组构造矩阵的最常用方法:
In [28]: from scipy import sparse
In [29]: adj = np.random.randint(0,10,size=10)
In [30]: adj
Out[30]: array([4, 7, 9, 7, 2, 1, 3, 3, 4, 8])
In [31]: data = np.ones_like(adj)
In [32]: rows = np.arange(10)
In [33]: col = adj
In [34]: M = sparse.coo_matrix((data,(rows, col)), shape=(10,10))
In [35]: M
Out[35]:
<10x10 sparse matrix of type '<class 'numpy.int64'>'
with 10 stored elements in COOrdinate format>
In [36]: M.A
Out[36]:
array([[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0]])
为了使用你的函数,我已经把它变成了一个二维数组:
In [39]: M1 = adj_matrix(adj[:,None])
In [40]: M1
Out[40]:
<10x10 sparse matrix of type '<class 'numpy.float64'>'
with 10 stored elements in Dictionary Of Keys format>
In [41]: M1.A
Out[41]:
array([[0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],
[0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],
[0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],
[0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 1., 0.]])
如果 adj
是列表的列表(或对象数组),coo
构造会稍微复杂一些。详细信息将取决于您最初 adj
的样子。目标是在矩阵的每个非零元素的 3 个 coo
输入数组中的每一个中都有一个条目。
集合列表
好的,让我们创建一个集合列表:
def foo():
n = np.random.randint(0,10)
return np.random.randint(0,10,(n,))
In [34]: alist = [set(foo()) for _ in range(10)]
In [35]: alist
Out[35]:
[{0, 1, 3, 6, 9},
{1, 9},
{0, 2, 5},
{0, 1, 2, 5, 8},
{1, 4, 5, 8},
{1, 4, 5, 6, 7, 8, 9},
{0, 3, 4, 7, 8, 9},
{0, 1, 4, 7},
{0, 4, 7, 8},
{1, 5, 7, 8, 9}]
你应该已经提供了这样的测试用例或功能。我确实要求 [mcve].
你的函数:
def adj_matrix(adj):
n = len(adj)
g= sparse.dok_matrix((n,n), int)
for num, i in enumerate(adj):
g[num, list(i)] = 1
return g
对我以前的代码进行改编以处理新的 adj 输入:
def my_adj(adj):
n = len(adj)
row, col, data = [],[],[]
for num, i in enumerate(adj):
c = list(i)
m = len(c)
col.append(c)
data.append([1]*m)
row.append([num]*m)
data = np.hstack(data)
row = np.hstack(row)
col = np.hstack(col)
return sparse.coo_matrix((data, (row, col)), shape=(n,n))
比较结果:
In [36]: adj_matrix(alist)
Out[36]:
<10x10 sparse matrix of type '<class 'numpy.float64'>'
with 45 stored elements in Dictionary Of Keys format>
In [37]: _.A
Out[37]:
array([[1., 1., 0., 1., 0., 0., 1., 0., 0., 1.],
[0., 1., 0., 0., 0., 0., 0., 0., 0., 1.],
[1., 0., 1., 0., 0., 1., 0., 0., 0., 0.],
[1., 1., 1., 0., 0., 1., 0., 0., 1., 0.],
[0., 1., 0., 0., 1., 1., 0., 0., 1., 0.],
[0., 1., 0., 0., 1., 1., 1., 1., 1., 1.],
[1., 0., 0., 1., 1., 0., 0., 1., 1., 1.],
[1., 1., 0., 0., 1., 0., 0., 1., 0., 0.],
[1., 0., 0., 0., 1., 0., 0., 1., 1., 0.],
[0., 1., 0., 0., 0., 1., 0., 1., 1., 1.]])
In [38]: my_adj(alist)
Out[38]:
<10x10 sparse matrix of type '<class 'numpy.int64'>'
with 45 stored elements in COOrdinate format>
In [39]: _.A
Out[39]:
array([[1, 1, 0, 1, 0, 0, 1, 0, 0, 1],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 1, 0, 0, 1, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 1, 0, 0, 1, 0],
[0, 1, 0, 0, 1, 1, 0, 0, 1, 0],
[0, 1, 0, 0, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 1, 1, 0, 0, 1, 1, 1],
[1, 1, 0, 0, 1, 0, 0, 1, 0, 0],
[1, 0, 0, 0, 1, 0, 0, 1, 1, 0],
[0, 1, 0, 0, 0, 1, 0, 1, 1, 1]])
时间:
In [44]: timeit adj_matrix(alist).tocoo()
2.09 ms ± 76.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [45]: timeit my_adj(alist)
259 µs ± 203 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
我正在尝试从邻接表创建一个 networkx 图。我目前正在执行以下操作,速度很慢。我查看了 scipy.sparse 矩阵选项,据我所知 none 与我正在使用的格式相同。 adj 中的每个项目都可以有不同的长度,这使情况变得复杂。
o3dmesh.adjacency list returns 一组列表。 集合 adjacency_list[i] 包含顶点 i 的相邻顶点的索引。没有行、列索引,只有绝对索引。
import open3d as o3d
import networkx as nx
import scipy
def adj_matrix(adj):
n = len(adj)
g= scipy.sparse.dok_matrix((n,n), int)
for num, i in enumerate(adj):
g[num, list(i)] = 1
return g
o3dmesh = mesh = o3d.io.read_triangle_mesh(path)
adj = o3dmesh.adjacency_list
adj = adj_matrix(adj)
graph = nx.from_scipy_sparse_matrix(adj)
我不熟悉 networkx
或您的 adj 列表。但是从代码中我猜它是 (0,n) 范围内的整数列表或数组。
下面是从此类数组构造矩阵的最常用方法:
In [28]: from scipy import sparse
In [29]: adj = np.random.randint(0,10,size=10)
In [30]: adj
Out[30]: array([4, 7, 9, 7, 2, 1, 3, 3, 4, 8])
In [31]: data = np.ones_like(adj)
In [32]: rows = np.arange(10)
In [33]: col = adj
In [34]: M = sparse.coo_matrix((data,(rows, col)), shape=(10,10))
In [35]: M
Out[35]:
<10x10 sparse matrix of type '<class 'numpy.int64'>'
with 10 stored elements in COOrdinate format>
In [36]: M.A
Out[36]:
array([[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0]])
为了使用你的函数,我已经把它变成了一个二维数组:
In [39]: M1 = adj_matrix(adj[:,None])
In [40]: M1
Out[40]:
<10x10 sparse matrix of type '<class 'numpy.float64'>'
with 10 stored elements in Dictionary Of Keys format>
In [41]: M1.A
Out[41]:
array([[0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],
[0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],
[0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],
[0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 1., 0.]])
如果 adj
是列表的列表(或对象数组),coo
构造会稍微复杂一些。详细信息将取决于您最初 adj
的样子。目标是在矩阵的每个非零元素的 3 个 coo
输入数组中的每一个中都有一个条目。
集合列表
好的,让我们创建一个集合列表:
def foo():
n = np.random.randint(0,10)
return np.random.randint(0,10,(n,))
In [34]: alist = [set(foo()) for _ in range(10)]
In [35]: alist
Out[35]:
[{0, 1, 3, 6, 9},
{1, 9},
{0, 2, 5},
{0, 1, 2, 5, 8},
{1, 4, 5, 8},
{1, 4, 5, 6, 7, 8, 9},
{0, 3, 4, 7, 8, 9},
{0, 1, 4, 7},
{0, 4, 7, 8},
{1, 5, 7, 8, 9}]
你应该已经提供了这样的测试用例或功能。我确实要求 [mcve].
你的函数:
def adj_matrix(adj):
n = len(adj)
g= sparse.dok_matrix((n,n), int)
for num, i in enumerate(adj):
g[num, list(i)] = 1
return g
对我以前的代码进行改编以处理新的 adj 输入:
def my_adj(adj):
n = len(adj)
row, col, data = [],[],[]
for num, i in enumerate(adj):
c = list(i)
m = len(c)
col.append(c)
data.append([1]*m)
row.append([num]*m)
data = np.hstack(data)
row = np.hstack(row)
col = np.hstack(col)
return sparse.coo_matrix((data, (row, col)), shape=(n,n))
比较结果:
In [36]: adj_matrix(alist)
Out[36]:
<10x10 sparse matrix of type '<class 'numpy.float64'>'
with 45 stored elements in Dictionary Of Keys format>
In [37]: _.A
Out[37]:
array([[1., 1., 0., 1., 0., 0., 1., 0., 0., 1.],
[0., 1., 0., 0., 0., 0., 0., 0., 0., 1.],
[1., 0., 1., 0., 0., 1., 0., 0., 0., 0.],
[1., 1., 1., 0., 0., 1., 0., 0., 1., 0.],
[0., 1., 0., 0., 1., 1., 0., 0., 1., 0.],
[0., 1., 0., 0., 1., 1., 1., 1., 1., 1.],
[1., 0., 0., 1., 1., 0., 0., 1., 1., 1.],
[1., 1., 0., 0., 1., 0., 0., 1., 0., 0.],
[1., 0., 0., 0., 1., 0., 0., 1., 1., 0.],
[0., 1., 0., 0., 0., 1., 0., 1., 1., 1.]])
In [38]: my_adj(alist)
Out[38]:
<10x10 sparse matrix of type '<class 'numpy.int64'>'
with 45 stored elements in COOrdinate format>
In [39]: _.A
Out[39]:
array([[1, 1, 0, 1, 0, 0, 1, 0, 0, 1],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 1, 0, 0, 1, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 1, 0, 0, 1, 0],
[0, 1, 0, 0, 1, 1, 0, 0, 1, 0],
[0, 1, 0, 0, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 1, 1, 0, 0, 1, 1, 1],
[1, 1, 0, 0, 1, 0, 0, 1, 0, 0],
[1, 0, 0, 0, 1, 0, 0, 1, 1, 0],
[0, 1, 0, 0, 0, 1, 0, 1, 1, 1]])
时间:
In [44]: timeit adj_matrix(alist).tocoo()
2.09 ms ± 76.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [45]: timeit my_adj(alist)
259 µs ± 203 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)