Python 如何使用NumPy中的列表列表对高级索引进行矢量化?
使用纯Python时,以下代码以45秒的速度运行Python 如何使用NumPy中的列表列表对高级索引进行矢量化?,python,numpy,pagerank,Python,Numpy,Pagerank,使用纯Python时,以下代码以45秒的速度运行 for iteration in range(maxiter): for node in range(n): for dest in adjacency_list[node]: rs[iteration + 1][dest] += beta * rs[iteration][node] / len(adjacency_list[node]) 但是,只需将rs初始化为numpy ndarray而不是p
for iteration in range(maxiter):
for node in range(n):
for dest in adjacency_list[node]:
rs[iteration + 1][dest] += beta * rs[iteration][node] / len(adjacency_list[node])
但是,只需将rs
初始化为numpy ndarray而不是python列表,代码就可以在145秒内运行。我真的不知道为什么numpy需要3倍于此数组索引的时间
我的想法是将尽可能多的东西矢量化,但只设法将beta/len(邻接列表[node])
的乘法矢量化。此代码在77s中运行
beta_over_out_degree = np.array([beta / len(al) for al in adjacency_list])
for iteration in range(1, maxiter + 1):
r_next = np.full(shape=n, fill_value=(1 - beta) / n)
f = beta_over_out_degree * r
for i in range(n):
r_next[adjacency_list[i]] += f[i]
r = np.copy(r_next)
rs[iteration] = np.copy(r)
问题在于,邻接列表
是一个列大小不同的列表列表,有100000行和1-15列。
使用邻接矩阵的更标准的方法,至少作为正常的ndarray,不是一个选项,因为对于n=100000,其(n,n)的形状太大,无法分配给内存
是否有任何方法可以使用其索引进行矢量化,以实现numpy高级索引(可能将其转换为numpy ndarray)
我也非常感谢任何其他的速度提示。
提前谢谢
编辑:多亏@stevemo,我利用csr\u矩阵
功能创建了邻接矩阵
,并将其用于迭代乘法。程序现在只运行2秒
for iteration in range(1, 101):
rs[iteration] += rs[iteration - 1] * adjacency_matrix
若我理解正确的话,这可以用一个线性公式来完成,使用邻接矩阵的矩阵幂 根据原始代码片段,您似乎有一些
n
节点网络,邻接信息存储为邻接
中的列表,每个节点都有一个值r
,这样它在迭代k+1
时的值是beta
乘以iterk
处每个相邻节点的r
之和。(您的循环以相反的方向构造,但内容相同。)
如果你不介意将你的邻接列表改革成一个更标准的列表,例如a_ij=1
如果ij
是邻居,否则为0,那么你可以用一个简单的矩阵积,r[k+1]=beta*(a@r[k])
完成内部两个循环
按照这个逻辑,r[k+2]=beta*(A@(beta*(A@r[k]))=(beta*A)**2@r[k]
或者一般来说
r[k] = (beta * A)**k @ r[0]
让我们在一个小型网络上尝试一下:
邻接矩阵
A=np.array([
[0, 1, 1, 0, 0],
[1, 0, 1, 0, 0],
[1, 1, 0, 1, 0],
[0, 0, 1, 0, 1],
[0, 0, 0, 1, 0]
])
#初始值
n=5
β=0.5
r0=np.ones(n)
maxiter=10
#经过一次迭代
打印(beta*(A@r0))
# [1. 1. 1.5 1. 0.5]
#经过10次迭代后
打印(np.linalg.matrix_power((β*A),maxiter)@r0)
# [2.88574219 2.88574219 3.4921875 1.99414062 0.89257812]
您可以共享阵列的尺寸吗?也许可以创建一个虚拟示例?您是需要所有迭代的值,还是只需要最后一个迭代的值?如果您指的是邻接列表的值,因为它在最内层循环中使用,我在所有迭代中都需要它们。当n=100000时,形状为:r->(1,n),rs(100,n),邻接列表->(n,介于1和15之间)为数组的单个元素编制索引的速度较慢。感谢您提供了非常详细和有用的答案。我是stackoverflow的noob,所以我忘记了另一个细节:邻接矩阵,至少作为一个正常的ndarray,不是一个选项,因为对于n=100000,它的(n,n)形状太大,无法分配给内存。Scipy应该对此没有问题,并且可以很好地使用NumPy。对于一个新用户来说,它们似乎有点吓人,但我向您保证,短时间的学习是值得的:)