Report how stable a PageRank ranking is across damping factors
Source:R/pagerank_stability.R
pagerank_stability.RdSweeps [pagerank()] over a grid of damping factors with [damping_sensitivity()] and compares each \(\alpha\)'s ranking against a reference \(\alpha\) with [compare_pagerank()], returning a one-row-per- \(\alpha\) stability summary. It answers the open question flagged in the "Damping factor" section of [pagerank()]: on *your* graph, how much does the ranking actually move as \(\alpha\) varies?
Usage
pagerank_stability(
edge_list_df,
alphas = c(0.75, 0.8, 0.85, 0.9, 0.95),
reference = 0.85,
top_k = 10,
...
)Arguments
- edge_list_df
A data frame representing the edge list, passed to every [pagerank()] call. (Named for consistency with the rest of the package; it is an edge list, not a constructed graph object.)
- alphas
Numeric vector of damping factors to sweep, each strictly between 0 and 1. Default `c(0.75, 0.80, 0.85, 0.90, 0.95)`. Duplicate values are dropped.
- reference
The baseline damping factor every other \(\alpha\) is compared against. A single number strictly between 0 and 1, default `0.85`. Included in the sweep automatically if not already in `alphas`.
- top_k
Size of the top-scoring set used for the `top_k_overlap` churn metric. Positive integer, default `10`.
- ...
Additional arguments forwarded to [damping_sensitivity()] and on to [pagerank()] (e.g. `redirects_df`, `weight_col`, `algo`, `prior_df`). Passing `damping` is an error, since `alphas` drives the damping factor.
Value
A data frame with one row per swept \(\alpha\) (ascending), with columns:
- `alpha`
The damping factor.
- `spearman_rho`
Spearman rank correlation of this \(\alpha\)'s ranking against the reference, on their common nodes (`NA` if fewer than 3 common nodes).
- `mean_abs_delta`
Mean absolute score difference vs the reference on common nodes.
- `top_k_overlap`
Fraction in `[0, 1]` of the reference's top-`k` pages that are also in this \(\alpha\)'s top-`k` (1 = identical top set). The effective `k` shrinks to the node count on small graphs.
- `nodes_gained`, `nodes_lost`
Nodes present at this \(\alpha\) but not the reference, and vice versa. Normally 0: varying \(\alpha\) changes scores, not the node set.
- `algo`, `iters`, `iters_estimate`, `residual`, `tol`, `converged`, `n_nodes`
The per-\(\alpha\) convergence metadata carried over from [damping_sensitivity()].
The full per-(URL, \(\alpha\)) sensitivity frame from [damping_sensitivity()] is attached as the `"sensitivity"` attribute, and the `reference` and `top_k` used are attached as same-named attributes.
Details
A Spearman rank correlation near 1 across the whole grid means the choice of damping factor is immaterial for this graph — the conventional `0.85` is as good as any nearby value. A low correlation, or a top-\(k\) overlap well below 1, flags a graph whose ranking is genuinely \(\alpha\)-sensitive and worth investigating before trusting any single solve.
This is a thin orchestration layer: it performs no PageRank math of its own, delegating the solves to [damping_sensitivity()] and the rank-comparison statistics to [compare_pagerank()]. The `reference` factor is always included in the sweep (even if absent from `alphas`) so it can serve as the comparison baseline; its own row is a sanity anchor (`spearman_rho = 1`, `mean_abs_delta = 0`, `top_k_overlap = 1`).
Examples
edges <- data.frame(
from = c("A", "B", "C", "A", "D"),
to = c("B", "C", "A", "C", "A")
)
stab <- pagerank_stability(edges, clean_edge_urls = FALSE)
print(stab)
#> alpha spearman_rho mean_abs_delta top_k_overlap nodes_gained nodes_lost
#> 1 0.75 1 0.013447950 1 0 0
#> 2 0.80 1 0.006689967 1 0 0
#> 3 0.85 1 0.000000000 1 0 0
#> 4 0.90 1 0.006628598 1 0 0
#> 5 0.95 1 0.013201832 1 0 0
#> algo iters iters_estimate residual tol converged n_nodes
#> 1 prpack NA 25 0.000000e+00 0.001 TRUE 4
#> 2 prpack NA 31 5.551115e-17 0.001 TRUE 4
#> 3 prpack NA 43 1.110223e-16 0.001 TRUE 4
#> 4 prpack NA 66 8.673617e-17 0.001 TRUE 4
#> 5 prpack NA 135 1.405126e-16 0.001 TRUE 4
# Drill into the per-(url, alpha) scores behind the summary.
head(attr(stab, "sensitivity"))
#> url alpha score iters iters_estimate residual converged
#> 1 A 0.75 0.3769231 NA 25 0.000000e+00 TRUE
#> 2 C 0.75 0.3567308 NA 25 0.000000e+00 TRUE
#> 3 B 0.75 0.2038462 NA 25 0.000000e+00 TRUE
#> 4 D 0.75 0.0625000 NA 25 0.000000e+00 TRUE
#> 5 A 0.80 0.3820755 NA 31 5.551115e-17 TRUE
#> 6 C 0.80 0.3650943 NA 31 5.551115e-17 TRUE