Python中的页面排名
我是Python新手,我尝试根据Python中的以下等式计算页面排名向量: 其中,Pi(k)是第k次迭代后的页面排名向量,G是谷歌矩阵,H是超链接矩阵,a是悬挂节点向量,alpha=0.85,e是1的向量 使用G进行计算需要大量时间,而使用超链接矩阵H(稀疏矩阵)所需的时间应显著减少 这是我的密码:Python中的页面排名,python,algorithm,pagerank,Python,Algorithm,Pagerank,我是Python新手,我尝试根据Python中的以下等式计算页面排名向量: 其中,Pi(k)是第k次迭代后的页面排名向量,G是谷歌矩阵,H是超链接矩阵,a是悬挂节点向量,alpha=0.85,e是1的向量 使用G进行计算需要大量时间,而使用超链接矩阵H(稀疏矩阵)所需的时间应显著减少 这是我的密码: for i in range(1, k_steps+1): for j in range(0, len(dictionary_urls)): for k in range(0, len
for i in range(1, k_steps+1):
for j in range(0, len(dictionary_urls)):
for k in range(0, len(dictionary_urls)):
if matrix_H[k][j] != 0:
matrix_pi_k[i][j] += matrix_pi_k[i-1][k] * float(matrix_H[k][j])
alpha_pi_k_a += matrix_pi_k[i-1][k]*float(vector_a[k])
alpha_pi_k_a = alpha_pi_k_a * float(alpha)
alpha_pi_k_a = alpha_pi_k_a + float((1- alpha))
alpha_pi_k_a = alpha_pi_k_a / float(len(dictionary_urls))
matrix_pi_k[i][j] = matrix_pi_k[i][j] * float(alpha)
matrix_pi_k[i][j] = matrix_pi_k[i][j] + float(alpha_pi_k_a)
alpha_pi_k_a = 0
k_steps是所需的迭代次数
字典链接包含所有URL
代码执行后,矩阵πk应具有所有π向量
我计算了所有需要的变量。我使用H矩阵得到的运行时间几乎等于使用G矩阵得到的运行时间,尽管理论上应该有所不同
为什么??我应该改变什么来减少运行时间
谢谢。根据你的公式,矩阵H的计算看起来并不比矩阵G快 说明: 你可能想看一看 公式中最右边的部分(在
+
之后)只包含一个没有循环的简单计算,它的大O表示法就是O(1)
。这意味着,它不取决于您考虑的URL数量
而H和G的计算似乎至少是O(n^2)
(n
是URL的数量)
编辑:
在代码的深层嵌套部分,有两条指令,其中一条指令取决于matrix_H[k][j]
是否为0。尽管如此,如果它是0(如果H是稀疏矩阵,则大多数情况下都是这样),则将执行第二条指令。另外,你还是进入了循环
这仍然会使您的复杂性达到O(n^2),因此解析H并不比解析G快(很多)。问题在于,您使用相同的旧密集矩阵向量乘法算法将稀疏矩阵乘以密集向量。这样你就看不到任何加速了 假设有一个
nxn
矩阵A
(密集或稀疏)和一个n
-向量x
。要计算y=Ax,我们可以编写:
y = [0]*n
for i in range(n):
for j in range(n):
y[i] += A[i,j]*x[j]
无论矩阵A
是密集的还是稀疏的,这都有效。但是,假设A
是稀疏的。我们仍然循环遍历A
的所有列,以计算y
的单个条目,即使大多数条目都是零。所以外循环要经过n
迭代,内循环也要经过n
迭代
如果我们知道A
的哪些条目是非零的,我们可以做得更好。假设我们有一个列,列有行i
的所有非零条目,称之为nonzero[i]
。然后,我们可以用迭代替换该列表上的内部循环:
y = [0]*n
for i in range(n):
for j in nonzero[i]:
y[i] += A[i,j]*x[j]
因此,当我们的外循环进行n
迭代时,内循环只进行与非零项相同数量的迭代
这就是稀疏矩阵向量乘法带来的加速
使用numpy
!
但您还有另一个问题:您正试图使用纯Python进行矩阵乘法,这(由于类型检查、非连续数据结构等)速度很慢。解决方案是使用,它提供了快速算法和数据结构。然后您可以使用,因为它们为您实现了快速稀疏矩阵向量乘法
实验
我们可以通过一个快速的实验来展示这一切。首先,我们将生成一个10000 x 10000
密集矩阵a
:
>>> import numpy as np
>>> n = 10000
>>> A = np.random.sample((n,n))
然后我们将通过阈值化a
来生成稀疏矩阵B
B
与A
的大小相同,但只有10%的条目为非零:
>>> B = np.where(A < .1, A, 0).astype(float)
计算Ax
所需的时间与计算Bx
所需的时间相同,即使B
是“稀疏的”。当然,它不是真正稀疏的:它存储为一个密集的矩阵,有很多零条目。让我们将其稀疏化:
>>> sparse_B = scipy.sparse.csr_matrix(B)
>>> 100 loops, best of 3: 12 ms per loop
这是我们的加速!现在,为了好玩,如果我们将A
存储为稀疏矩阵,即使它非常密集,会怎么样
>>> sparse_A = scipy.sparse.csr_matrix(A)
>>> %timeit sparse_A.dot(x)
10 loops, best of 3: 112 ms per loop
哎哟!但这是意料之中的,因为将
A
存储为稀疏矩阵将在乘法过程中产生一些开销。根据我所读的内容,在稀疏矩阵上进行向量乘法所需的时间比在密集矩阵上进行乘法所需的时间要少得多。G是稠密矩阵,而H是稀疏矩阵。这应该会影响运行时间。@RomanYanovitski刚刚编辑了我的答案,以考虑您的评论,这正是我要问的:)。显然,我的代码效率不高,而且花费的时间比它应该花费的时间多得多。我不知道如何改进它,以减少它的运行时间。@RomanYanovitski好的,我是在回答你问题的“为什么”部分。现在关于“如何”,这是另一个故事:)让我看看我是否能得到一些有价值的东西。好吧,但问题是,即使我知道哪些条目是零,我也应该进行计算的第二部分,这会影响每次迭代。第二部分是指Pi向量与向量a的乘积,并将结果加到Pi向量上。因此,我不能跳过迭代,即使在使用zero@RomanYanovitski这很好,因为您不需要同时计算pi*H
和pi*a
。无论如何,你真的应该使用numpy
。
>>> sparse_A = scipy.sparse.csr_matrix(A)
>>> %timeit sparse_A.dot(x)
10 loops, best of 3: 112 ms per loop