Python 如何使用NumPy中的列表列表对高级索引进行矢量化?

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

使用纯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而不是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
乘以iter
k
处每个相邻节点的
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。对于一个新用户来说,它们似乎有点吓人,但我向您保证,短时间的学习是值得的:)