PageRank
1. Introdução
O dataset roadNet-CA representa a malha viária da Califórnia, onde:
- Nós = interseções
- Arestas = segmentos viários direcionados
2. Carregamento do Grafo
Número de nós: 1965206
Número de arestas: 5533214
É direcionado? True
3. Implementação do PageRank Manual
A fórmula utilizada:
def pagerank_custom(G, d=0.85, tol=1e-4, max_iter=100):
nodes = list(G.nodes())
N = len(nodes)
idx = {n: i for i, n in enumerate(nodes)}
pr = np.full(N, 1 / N)
out_deg = np.array([G.out_degree(n) for n in nodes])
predecessors = {i: [idx[p] for p in G.predecessors(nodes[i])]
for i in range(N)}
base = (1 - d) / N
for _ in range(max_iter):
pr_new = np.full(N, base)
dangling_sum = pr[out_deg == 0].sum()
pr_new += d * dangling_sum / N
for i in range(N):
s = 0
for j in predecessors[i]:
if out_deg[j] > 0:
s += pr[j] / out_deg[j]
pr_new[i] += d * s
if np.max(np.abs(pr_new - pr)) < tol:
break
pr = pr_new
return {nodes[i]: float(pr[i]) for i in range(N)}
4. Execução do PageRank com d = 0.85
========== RESULTADOS ==========
Soma dos PR: 1.000000
PR mínimo: 1.303935e-07
PR máximo: 2.455213e-06
Top-10 nós por PageRank:
-
nó=225438 | PR=2.455213e-06
-
nó=287362 | PR=2.383126e-06
-
nó=241926 | PR=2.166864e-06
-
nó=748883 | PR=2.022689e-06
-
nó=1682326 | PR=2.022689e-06
-
nó=241299 | PR=1.950601e-06
-
nó=264566 | PR=1.950601e-06
-
nó=403664 | PR=1.950601e-06
-
nó=673507 | PR=1.950601e-06
-
nó=1258079 | PR=1.950601e-06
import numpy as np
import networkx as nx
def pagerank_custom(G, d=0.85, tol=1e-4, max_iter=100):
nodes = list(G.nodes())
N = len(nodes)
idx = {n: i for i, n in enumerate(nodes)}
pr = np.full(N, 1.0 / N)
out_deg = np.array([G.out_degree(n) for n in nodes])
predecessors = {i: [idx[p] for p in G.predecessors(nodes[i])] for i in range(N)}
base = (1 - d) / N
for _ in range(max_iter):
pr_new = np.full(N, base)
dangling_sum = pr[out_deg == 0].sum()
pr_new += d * dangling_sum / N
for i in range(N):
s = 0.0
for j in predecessors[i]:
if out_deg[j] > 0:
s += pr[j] / out_deg[j]
pr_new[i] += d * s
if np.max(np.abs(pr_new - pr)) < tol:
pr = pr_new
break
pr = pr_new
pr_dict = {nodes[i]: float(pr[i]) for i in range(N)}
return pr_dict
path = "./docs/pageRank/roadNet-CA.txt"
G = nx.read_edgelist(
path,
comments="#",
nodetype=int,
create_using=nx.DiGraph()
)
pr_dict = pagerank_custom(G, d=0.85)
pr_values = np.fromiter(pr_dict.values(), dtype=np.float64)
print("\n========== RESULTADOS ==========")
print(f"\nSoma dos PR: {pr_values.sum():.6f}")
print(f"\nPR mínimo: {pr_values.min():.6e}")
print(f"\nPR máximo: {pr_values.max():.6e}")
print("\nTop-10 nós por PageRank:")
top10 = sorted(pr_dict.items(), key=lambda x: x[1], reverse=True)[:10]
for i, (node, score) in enumerate(top10, 1):
print(f"\n{i:2d}. nó={node} | PR={score:.6e}")
5. Comparação com NetworkX
========== RESULTADOS (NetworkX) ==========
Soma dos PR: 1.000000
PR mínimo: 1.303935e-07
PR máximo: 2.455213e-06
Top-10 nós por PageRank:
-
nó=225438 | PR=2.455213e-06
-
nó=287362 | PR=2.383126e-06
-
nó=241926 | PR=2.166864e-06
-
nó=748883 | PR=2.022689e-06
-
nó=1682326 | PR=2.022689e-06
-
nó=241299 | PR=1.950601e-06
-
nó=264566 | PR=1.950601e-06
-
nó=403664 | PR=1.950601e-06
-
nó=673507 | PR=1.950601e-06
-
nó=1258079 | PR=1.950601e-06
import numpy as np
import networkx as nx
path = "./docs/pageRank/roadNet-CA.txt"
# Carregar grafo
G = nx.read_edgelist(
path,
comments="#",
nodetype=int,
create_using=nx.DiGraph()
)
# PageRank com networkx
pr_dict = nx.pagerank(G, alpha=0.85)
pr_values = np.fromiter(pr_dict.values(), dtype=float)
print("\n========== RESULTADOS (NetworkX) ==========")
print(f"\nSoma dos PR: {pr_values.sum():.6f}")
print(f"\nPR mínimo: {pr_values.min():.6e}")
print(f"\nPR máximo: {pr_values.max():.6e}")
print("\nTop-10 nós por PageRank:")
top10 = sorted(pr_dict.items(), key=lambda x: x[1], reverse=True)[:10]
for i, (node, score) in enumerate(top10, 1):
print(f"\n{i:2d}. nó={node} | PR={score:.6e}")
A comparação entre os resultados obtidos pela implementação manual do algoritmo PageRank e aqueles gerados pela função pagerank do NetworkX demonstra que não houve diferenças significativas entre as duas abordagens. Tanto a soma total dos valores de PageRank quanto os valores mínimo e máximo coincidem exatamente nas duas execuções, indicando que o cálculo converge para a mesma distribuição de importância dos nós. Além disso, o Top-10 nós mais bem ranqueados é idêntico em ambas as metodologias, com os mesmos valores numéricos de PageRank e na mesma ordem, o que confirma a correta implementação da fórmula iterativa utilizada. Esses resultados validam plenamente a implementação manual, mostrando que ela está alinhada com o comportamento esperado de uma biblioteca consolidada como o NetworkX.
6. Top-10 Nós Mais Importantes
7. Variação do Fator de Amortecimento
==================== RESULTADOS PARA d = 0.5 ====================
Soma dos PR: 1.000000
PR mínimo: 2.862295e-07
PR máximo: 1.653771e-06
Top-10 nós por PageRank:
-
nó=225438 | PR=1.653771e-06
-
nó=287362 | PR=1.611366e-06
-
nó=241926 | PR=1.484153e-06
-
nó=748883 | PR=1.399344e-06
-
nó=1682326 | PR=1.399344e-06
-
nó=241299 | PR=1.356940e-06
-
nó=264566 | PR=1.356940e-06
-
nó=403664 | PR=1.356940e-06
-
nó=673507 | PR=1.356940e-06
-
nó=1258079 | PR=1.356940e-06
==================== RESULTADOS PARA d = 0.85 ====================
Soma dos PR: 1.000000
PR mínimo: 1.303935e-07
PR máximo: 2.455213e-06
Top-10 nós por PageRank:
-
nó=225438 | PR=2.455213e-06
-
nó=287362 | PR=2.383126e-06
-
nó=241926 | PR=2.166864e-06
-
nó=748883 | PR=2.022689e-06
-
nó=1682326 | PR=2.022689e-06
-
nó=241299 | PR=1.950601e-06
-
nó=264566 | PR=1.950601e-06
-
nó=403664 | PR=1.950601e-06
-
nó=673507 | PR=1.950601e-06
-
nó=1258079 | PR=1.950601e-06
==================== RESULTADOS PARA d = 0.99 ====================
Soma dos PR: 1.000000
PR mínimo: 6.805902e-08
PR máximo: 2.775790e-06
Top-10 nós por PageRank:
-
nó=225438 | PR=2.775790e-06
-
nó=287362 | PR=2.691830e-06
-
nó=241926 | PR=2.439948e-06
-
nó=748883 | PR=2.272026e-06
-
nó=1682326 | PR=2.272026e-06
-
nó=241299 | PR=2.188066e-06
-
nó=264566 | PR=2.188066e-06
-
nó=403664 | PR=2.188066e-06
-
nó=673507 | PR=2.188066e-06
-
nó=1258079 | PR=2.188066e-06
import numpy as np
import networkx as nx
def pagerank_custom(G, d=0.85, tol=1e-4, max_iter=100):
# lista de nós e mapeamentos
nodes = list(G.nodes())
N = len(nodes)
if N == 0:
return {}
idx = {n: i for i, n in enumerate(nodes)}
# vetor inicial uniforme
pr = np.full(N, 1.0 / N, dtype=float)
# grau de saída de cada nó
out_deg = np.array([G.out_degree(n) for n in nodes], dtype=float)
# predecessores por índice (nós que apontam para i)
predecessors = {
i: [idx[p] for p in G.predecessors(nodes[i])]
for i in range(N)
}
base = (1.0 - d) / N
# iterações
for _ in range(max_iter):
pr_new = np.full(N, base, dtype=float)
# contribuição de nós dangling (sem saída)
dangling_sum = pr[out_deg == 0].sum()
pr_new += d * dangling_sum / N
# contribuição dos predecessores
for i in range(N):
s = 0.0
for j in predecessors[i]:
if out_deg[j] > 0:
s += pr[j] / out_deg[j]
pr_new[i] += d * s
# critério de parada
if np.max(np.abs(pr_new - pr)) < tol:
pr = pr_new
break
pr = pr_new
# converte para dict {nó: score}
pr_dict = {nodes[i]: float(pr[i]) for i in range(N)}
return pr_dict
# ----------------------------------------------------------------------
# Script principal: roda para d = 0.5, 0.85, 0.99 e printa resultados
# ----------------------------------------------------------------------
# Caminho do arquivo roadNet-CA (ajuste se necessário)
path = "./docs/pageRank/roadNet-CA.txt"
# Carrega o grafo como DiGraph
G = nx.read_edgelist(
path,
comments="#",
nodetype=int,
create_using=nx.DiGraph()
)
# Valores de d a serem testados
d_values = [0.5, 0.85, 0.99]
for d in d_values:
pr_dict = pagerank_custom(G, d=d, tol=1e-4, max_iter=100)
pr_values = np.fromiter(pr_dict.values(), dtype=float)
print(f"\n==================== RESULTADOS PARA d = {d} ====================")
print(f"\nSoma dos PR: {pr_values.sum():.6f}")
print(f"\nPR mínimo: {pr_values.min():.6e}")
print(f"\nPR máximo: {pr_values.max():.6e}")
# Top-10 nós
top10 = sorted(pr_dict.items(), key=lambda x: x[1], reverse=True)[:10]
print("\nTop-10 nós por PageRank:")
for i, (node, score) in enumerate(top10, 1):
print(f"\n{i:2d}. nó={node} | PR={score:.6e}")
A análise das três variações do fator de amortecimento (d = 0.5, 0.85 e 0.99) mostra que, embora os valores de PageRank sofram pequenas alterações numéricas conforme o peso dado ao “teleporte” aumenta ou diminui, o ranking dos nós permanece essencialmente estável. Em todas as configurações, o nó 225438 ocupa a primeira posição, seguido pelos nós 287362, 241926, 748883 e 1682326, indicando que esses vértices são estruturalmente centrais na malha viária independentemente do comportamento do caminhante aleatório. Observa-se que, para valores menores de d (como 0.5), o PageRank tende a se distribuir de forma mais uniforme, reduzindo a diferença entre os nós de maior e menor importância. Já para valores mais altos (como 0.99), a influência da topologia se intensifica, ampliando levemente as diferenças entre os nós de maior conectividade. Apesar disso, o conjunto de nós mais influentes não se altera, o que demonstra que a rede possui uma estrutura robusta de hubs e que o PageRank é bastante estável em relação à escolha do fator de amortecimento neste grafo.
8. Análise Final
Em síntese, os experimentos realizados demonstram que a implementação manual do PageRank é plenamente consistente com a solução consolidada do NetworkX, validando a corretude do algoritmo desenvolvido. Além disso, a análise das diferentes configurações do fator de amortecimento evidencia que, embora os valores absolutos de PageRank variem conforme a probabilidade de teleporte, o conjunto de nós mais influentes permanece estável em todas as execuções, revelando a presença de estruturas centrais bem definidas na malha viária do roadNet-CA. Isso reforça a robustez do PageRank como métrica de importância em redes reais e mostra que a conectividade intrínseca do grafo exerce maior impacto no ranking do que ajustes finos no parâmetro d. Dessa forma, os resultados obtidos fornecem uma caracterização consistente dos principais hubs da rede e confirmam a confiabilidade tanto da abordagem manual quanto das ferramentas de análise oferecidas por bibliotecas especializadas.
