Python中的页面排名

时间:2014-12-22 17:39:33

标签: python algorithm pagerank

我是Python新手,我正在尝试根据Python中的这个等式计算网页排名向量: enter image description here

其中 Pi(k)是k-Th迭代后的Page-rank向量, G 是Google矩阵, 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(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是所需的迭代次数。

dictionary_links包含所有网址。

执行代码后,matrix_pi_k应该包含所有Pi向量

我计算了所需的所有变量。我使用 H 矩阵运行时间几乎等于使用​​ G 矩阵的运行时间,但理论上它应该是不同的。

为什么呢?我应该改变什么来减少运行时间?

谢谢。

2 个答案:

答案 0 :(得分:5)

问题在于,您使用相同的密集矩阵向量乘法算法将稀疏矩阵乘以密集向量。你不会以这种方式看到任何加速。

假设您有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进行矩阵乘法,这(由于类型检查,非连续数据结构等)是。解决方案是使用numpy,它提供快速算法和数据结构。然后你可以使用scipy's sparse matrices,因为它们会为你实现快速稀疏矩阵向量乘法。

实验

我们可以通过快速实验展示所有这些。首先,我们将生成10,000 x 10,000密集矩阵A

>>> import numpy as np
>>> n = 10000
>>> A = np.random.sample((n,n))

然后我们通过阈值B制作稀疏矩阵ABA的大小相同,但只有10%的条目非零:

>>> B = np.where(A < .1, A, 0).astype(float)

现在我们制作一个密集的向量,将AB乘以:

>>> x = np.random.sample(n)
>>> %timeit A.dot(x)
10 loops, best of 3: 46.7 ms per loop
>>> %timeit B.dot(x)
10 loops, best of 3: 43.7 ms per loop

计算Ax与计算Bx所花费的时间相同,即使B是&#34;稀疏&#34;。当然,它并非真正稀疏:它被存储为具有大量零条目的密集矩阵。让我们稀疏:

>>> 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存储为稀疏矩阵会在乘法过程中产生一些开销。

答案 1 :(得分:0)

根据您的公式,矩阵H的计算看起来不比矩阵G快。

<强>解释

您可能需要查看introduction to Big O notation

公式中最右边的部分(在+之后)只包含一个没有循环的简单计算,其Big O表示法只是O(1)。这意味着,它不依赖于您考虑的网址数量。

而H和G的计算似乎至少为O(n^2)n是网址数。)

修改

在代码的深层嵌套部分中,您有两条指令,其中一条指令取决于matrix_H[k][j]是否为0。但是,如果它是0,如果H是稀疏矩阵,则大多数情况下将是这种情况,但是将执行第二条指令。另外,无论如何都要进入循环。

这仍然给你一个O(n^2)的复杂性,因此解析H并不比解析G快得多。