Sweep PageRank across a range of damping factors
Source:R/damping_sensitivity.R
damping_sensitivity.RdRuns [pagerank()] at each damping factor \(\alpha\) in `alphas` and returns a tidy data frame of per-URL scores alongside the convergence metadata for each solve. This makes the sensitivity of the ranking to \(\alpha\) directly inspectable on *your* graph, rather than relying on the field default of `0.85` (see the "Damping factor" section of [pagerank()] for why that default is only an empirical convention).
Usage
damping_sensitivity(edge_list_df, alphas = c(0.75, 0.8, 0.85, 0.9, 0.95), ...)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.
- ...
Additional arguments forwarded to [pagerank()] (e.g. `redirects_df`, `weight_col`, `algo`, `eps`, `niter`, `prior_df`). Passing `damping` here is an error, since `alphas` is what drives the damping factor.
Value
A tidy data frame with one row per (URL, \(\alpha\)) pair, sorted by `alpha` ascending then `score` descending, with columns:
- `url`
Node / page identifier.
- `alpha`
The damping factor used for this solve.
- `score`
The page's PageRank score at this `alpha`.
- `iters`
Iterations the solver used (ARPACK only; `NA` under PRPACK).
- `iters_estimate`
Power-iteration iteration-count estimate at the convergence tolerance (solver-independent).
- `residual`
Post-hoc L1 residual \(\|G x - x\|_1\) of the solve.
- `converged`
Whether the residual met the tolerance.
A `"convergence"` attribute is attached: a compact one-row-per-`alpha` data frame (`alpha`, `algo`, `iters`, `iters_estimate`, `residual`, `tol`, `converged`, `n_nodes`) summarizing each solve.
Details
The helper is the empirical companion to the closed-form \(\alpha\)-derivative analysis of Boldi, Santini & Vigna (PageRank as a Function of the Damping Factor, WWW 2005): instead of differentiating the PageRank vector with respect to \(\alpha\) analytically, it samples the vector at a grid of \(\alpha\) values so you can see how much each page's score (and the overall ranking) actually moves. Pair it with [compare_pagerank()] to quantify the rank churn between any two \(\alpha\) values.
Each row also carries the convergence metadata for that \(\alpha\)'s solve. The empirical `iters` count is only reported by the ARPACK solver; under the default PRPACK direct solver it is `NA` (PRPACK exposes no iteration count). To populate it, forward `algo = "arpack"` (or an `eps` / `niter` control) through `...`. The solver-independent `iters_estimate` column is always populated: it is the power-iteration rule of thumb \(\lceil \log_{10}(\tau) / \log_{10}(\alpha) \rceil\) (Langville & Meyer, 2004) at the convergence tolerance \(\tau\), and shows how the required iteration count climbs as \(\alpha\) approaches 1 regardless of solver.
See also
[pagerank()] (the "Damping factor" section), [pagerank_convergence], [compare_pagerank()], [pagerank_grid()]
Examples
edges <- data.frame(
from = c("A", "B", "C", "A", "D"),
to = c("B", "C", "A", "C", "A")
)
sens <- damping_sensitivity(edges, clean_edge_urls = FALSE)
print(sens)
#> 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
#> 7 B 0.80 0.2028302 NA 31 5.551115e-17 TRUE
#> 8 D 0.80 0.0500000 NA 31 5.551115e-17 TRUE
#> 9 A 0.85 0.3869418 NA 43 1.110223e-16 TRUE
#> 10 C 0.85 0.3736080 NA 43 1.110223e-16 TRUE
#> 11 B 0.85 0.2019503 NA 43 1.110223e-16 TRUE
#> 12 D 0.85 0.0375000 NA 43 1.110223e-16 TRUE
#> 13 A 0.90 0.3915401 NA 66 8.673617e-17 TRUE
#> 14 C 0.90 0.3822668 NA 66 8.673617e-17 TRUE
#> 15 B 0.90 0.2011931 NA 66 8.673617e-17 TRUE
#> 16 D 0.90 0.0250000 NA 66 8.673617e-17 TRUE
#> 17 A 0.95 0.3958876 NA 135 1.405126e-16 TRUE
#> 18 C 0.95 0.3910659 NA 135 1.405126e-16 TRUE
#> 19 B 0.95 0.2005466 NA 135 1.405126e-16 TRUE
#> 20 D 0.95 0.0125000 NA 135 1.405126e-16 TRUE
attr(sens, "convergence")
#> alpha algo iters iters_estimate residual tol converged n_nodes
#> 1 0.75 prpack NA 25 0.000000e+00 0.001 TRUE 4
#> 2 0.80 prpack NA 31 5.551115e-17 0.001 TRUE 4
#> 3 0.85 prpack NA 43 1.110223e-16 0.001 TRUE 4
#> 4 0.90 prpack NA 66 8.673617e-17 0.001 TRUE 4
#> 5 0.95 prpack NA 135 1.405126e-16 0.001 TRUE 4
# Populate the empirical iteration count by using the ARPACK solver.
sens_ar <- suppressMessages(
damping_sensitivity(edges, algo = "arpack", clean_edge_urls = FALSE)
)
attr(sens_ar, "convergence")
#> alpha algo iters iters_estimate residual tol converged n_nodes
#> 1 0.75 arpack 13 25 2.012279e-16 0.001 TRUE 4
#> 2 0.80 arpack 13 31 7.147061e-16 0.001 TRUE 4
#> 3 0.85 arpack 14 43 2.567391e-16 0.001 TRUE 4
#> 4 0.90 arpack 14 66 2.220446e-16 0.001 TRUE 4
#> 5 0.95 arpack 14 135 1.821460e-16 0.001 TRUE 4