Skip to contents

Builds a personalization / teleport vector for igraph::page_rank(personalized = ) from a per-URL external-authority prior (e.g. Ahrefs referring domains), aligned to the final graph vertex set. This is the core of TIPR ("topic/true internal PageRank"), where the random surfer's teleport mass is distributed in proportion to external authority instead of uniformly.

The prior URLs are expected to already share the vertex namespace (i.e. canonicalized with the same rurl settings and folded through the same redirect map as the edges). [pagerank()] performs that canonicalization and redirect-fold before calling this function; call it directly only when your prior URLs already match vertex_names.

Usage

align_prior_to_vertices(
  vertex_names,
  prior_df,
  prior_url_col = "url",
  prior_weight_col = "weight",
  transform = c("none", "log", "percentile", "minmax", "zipf", "rank_linear"),
  alpha = 0,
  exclude_nodes = character(0),
  verbose = TRUE
)

Arguments

vertex_names

Character vector of the graph's vertex names, in graph order (typically igraph::V(graph)$name).

prior_df

A data frame with one row per URL carrying a raw authority weight (e.g. referring-domain counts). Multiple rows for the same URL are summed (raw counts are additive — summing happens before any transform).

prior_url_col

Name of the URL column in prior_df. Default "url".

prior_weight_col

Name of the numeric weight column in prior_df. Default "weight". Contract: this must be an additive raw count. URLs that coalesce (duplicate rows here, redirect variants folded upstream by [pagerank()]) are combined by summation, which is only meaningful for counts — quantities that genuinely add when two URLs merge. This makes the prior source-agnostic: referring domains (the default metric), links-to-target, or dofollow-only referring domains from Ahrefs are interchangeable swaps, as are equivalent counts from other sources (SEMrush, GA4 entrances, …). Do not pass a calculated authority score (Ahrefs UR / DR, or any 0–100 rating): scores do not sum across redirect variants (the correct fold would be max), and a per-URL score such as UR is itself a PageRank-flavored metric, so using it as the teleport prior for PageRank is circular.

transform

Character, how to shape the raw authority before it becomes teleport mass. Passed to [transform_weights()]; one of "none" (default, faithful linear share), "log", "percentile", "minmax", "zipf", "rank_linear". The transform is applied only to vertices that actually carry authority; vertices with no prior contribute zero to the authority component.

alpha

Numeric in [0, 1], the mixture weight between a uniform teleport and the authority-weighted teleport: p = alpha * uniform + (1 - alpha) * authority_share. alpha = 0 (default) is pure authority teleport (pages with no external authority get no teleport mass, though they still receive rank via inlinks); alpha = 1 reproduces standard uniform PageRank. alpha is a smoothing knob, not a dead-node mechanism — isolate/self-loop handling owns dead nodes.

exclude_nodes

Character vector of vertex names that must receive zero teleport in both components (e.g. the synthetic "__pr_nofollow_sink__"). Real pages — including robots-blocked or 404 self-loop nodes — should not be excluded.

verbose

Logical, whether to emit coverage diagnostics via message() (vertices receiving authority, unmatched prior URLs and their dropped weight, and the realized uniform mass fraction). Default TRUE.

Value

A numeric vector the same length as vertex_names, in the same order, summing to 1 (suitable for igraph::page_rank(personalized = )). Excluded vertices get exactly 0. If the prior matches no vertex and alpha = 0, the function falls back to a uniform vector over the non-excluded vertices and warns.

Details

Alignment proceeds as: sum raw weights per URL -> match onto vertex_names (unmatched vertices get raw 0) -> apply transform to the vertices that carry authority -> normalize to an authority share -> mix with a uniform-over-real-vertices vector via alpha -> normalize to sum 1. Because igraph re-normalizes the personalization vector internally, only the relative weights matter; normalization here is for interpretability and to make alpha and exclude_nodes behave predictably.

See also

[pagerank()], [transform_weights()]

Examples

v <- c("https://x/a", "https://x/b", "https://x/c", "__pr_nofollow_sink__")
prior <- data.frame(
  url = c("https://x/a", "https://x/b"),
  weight = c(900, 100)
)
# Pure linear authority share; sink excluded
align_prior_to_vertices(v, prior,
  exclude_nodes = "__pr_nofollow_sink__",
  verbose = FALSE
)
#> [1] 0.9 0.1 0.0 0.0
# Compress the dynamic range
align_prior_to_vertices(v, prior,
  transform = "log",
  exclude_nodes = "__pr_nofollow_sink__", verbose = FALSE
)
#> [1] 0.5958252 0.4041748 0.0000000 0.0000000
# Authority-tilted uniform (every real page keeps a baseline)
align_prior_to_vertices(v, prior,
  alpha = 0.15,
  exclude_nodes = "__pr_nofollow_sink__", verbose = FALSE
)
#> [1] 0.815 0.135 0.050 0.000