knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) library(pagerankr)
PageRank is a lens, not the deliverable. The same crawl answers different questions depending on how you prepare the graph first: what does the site look like exactly as crawled? What does it look like once its own canonical and nofollow declarations are honored? Which pages feed authority outward rather than collect it? What survives once site chrome stops voting?
pagerank() can express all of those, but only through a long argument list.
A preset is a small named bundle of those arguments describing one
recurring view, so a view becomes a one-liner:
edges <- data.frame( from = c("A", "A", "B", "C"), to = c("B", "C", "A", "A") ) pagerank(edges, preset = "raw")
Presets are opt-in. pagerank() with no preset behaves exactly as it always
has — nothing here changes a default.
pr_preset("raw")
A preset is a plain named list, so you can always print one to see exactly what it does. Nothing is hidden: the table below is the whole registry.
| Preset | Expands to | The view |
|---|---|---|
| "raw" | self_loops = "keep", drop_isolates_flag = FALSE, nofollow_action = "keep", out_of_scope_fold = "keep" | The graph exactly as crawled. Nothing is applied; rel=nofollow votes like any other link. The faithful baseline. |
| "declared" | self_loops = "drop", drop_isolates_flag = TRUE, nofollow_action = "evaporate", robots_blocked_action = "show", out_of_scope_fold = "relabel" | The graph after honoring what the site declares — nofollow, canonicals, redirects, robots. A pure pin of today's defaults. |
| "reversed" | reverse = TRUE | Every edge flipped: a page scores highly when it points at well-connected pages. The feeder view. |
| "content" | placement_weights = c(content = 1, nav = 0.1, header = 0.1, footer = 0.1, aside = 0.1) | Links in the main content keep their full vote; links in site chrome are discounted to a tenth. |
"raw" — the faithful baselineThe naive view, and deliberately the one the package makes easiest to state.
Every other view is a claim about what should count; "raw" is the claim-free
comparison point. Reach for it when you want to see how much of a ranking your
own preparation choices produced.
"declared" — a pin, not a change"declared" sets every value to what pagerank() already defaults to. Running
with it produces byte-identical scores to running without it:
identical( pagerank(edges, preset = "declared")$pagerank, pagerank(edges)$pagerank )
That is the point. Its value is provenance: a run made with
preset = "declared" is a recorded, auditable statement that the declared view
was intended, and it stays pinned to the bundle as documented even if a future
package default moves.
Note the boundary: a preset sets policy, never data. "declared" turns on
honoring canonicals and redirects, but the canonical and redirect tables
themselves (canonicals_df, redirects_df, indexability_df) are still yours
to supply.
"reversed" — the feeder viewpagerank(edges, preset = "reversed")
topic_feeder_pagerank() already reverses the graph itself, so
preset = "reversed" is a harmless no-op there rather than an error.
"content" — stop letting the navigation rank the siteSite chrome — navigation, header, footer, sidebar — is typically the large majority of a crawl's edges. Left unweighted it does not merely influence the ranking, it manufactures it: every page links to the same handful of chrome targets, so those targets win by sheer repetition regardless of editorial intent.
"content" discounts them. It needs one thing from you: placement_col, the
name of a column saying which page region each link was found in. That is data,
so the preset cannot supply it.
placed <- data.frame( from = c("A", "A", "B", "C"), to = c("B", "C", "A", "A"), region = c("content", "footer", "content", "content") ) pagerank(placed, preset = "content", placement_col = "region")
B and C are each linked once from A. Unweighted they tie; weighted, the
footer link is worth a tenth of the in-content one and C falls behind.
The accepted region terms are content, nav, header, footer and aside.
pagerank_screaming_frog() derives them for you from the crawl, so there
preset = "content" works with no extra argument.
Two properties worth stating explicitly:
placement_weights keep
weight 1, which is what makes a partial recipe like c(nav = 0.1) mean
"discount nav, leave everything else alone". A preset is a complete recipe,
so it names every term — otherwise footer and aside would quietly outweigh
nav tenfold.A preset bundles policy — the graph-hygiene and weighting knobs above. It
never touches data: the redirects_df, canonicals_df, indexability_df
and status_df tables you supply (or leave NULL). Those tables decide a
second, orthogonal thing — how much of the crawl is folded away before
scoring — and that is its own view model, layered on top of whichever preset you
pick. Three layers, from the crawl as collected to the crawl fully interpreted:
(a) Raw — every crawled URL is its own node. Nothing is folded: a
redirecting URL keeps the PageRank it receives instead of passing it on, a
canonicalized page stays separate from its canonical, and a 404 scores like any
live page. You get this by not supplying the fold tables — they all default
NULL, so the raw layer is the absence of data. This is exactly why the
"raw" preset alone cannot guarantee it: a preset sets policy, and no policy can
un-supply a redirects_df you passed. On the bare pagerank() path the raw
layer is the default (you supply no tables), and preset = "raw" additionally
relaxes the hygiene policy so nothing at all is applied. On the Screaming Frog
path, where the wrapper builds those tables from the bundle for you,
preset = "raw" is special-cased to switch the folding back off — so it delivers
the raw layer there too.
(b) Real — redirects and canonicals are followed; dead pages collect but
cannot pass. Supply the fold tables and the graph reflects the live, canonical
corpus a search engine would score: redirect and canonical sources fold into
their terminal target (an alias, not a separate page), and the "collects
PageRank but cannot pass it" class — noindex, robots-blocked, and 4xx/5xx
response-dead pages — routes its throughput to a shared waste sink instead of
recirculating it (see ?pagerank and vignette("pagerankr-usage") for why the
sink is the only faithful choice for a dead page). This is the view most
internal-link audits want; pagerank_screaming_frog() assembles it from the
crawl by default.
(c) Annotated — the page_state indicator. Layer (b) hands a folded score
to a page that may be a black hole: a 404 can amass PageRank from every page
still linking to it, then evaporate it to the sink. That score is real mass but
not earned authority, and nothing else on the row distinguishes it from a strong
live page. So whenever indexability_df or status_df is supplied, the result
gains a page_state column tagging each row live, noindex, robots_blocked,
or response_dead (the highest-precedence signal wins). The annotation is the
package's answer to "why is this dead URL ranking?" — and the reason such rows
can be kept in the output instead of silently dropped.
Layers and presets compose freely: a layer is which data you fold, a preset is which policy you bundle, and you choose them independently.
A preset never silently overrides something you typed.
# The raw bundle says nofollow_action = "keep"; the explicit argument wins. attr( pagerank(edges, preset = "raw", nofollow_action = "drop"), "transition_audit" )$config$nofollow_action
This holds through every wrapper that forwards ... to pagerank() —
trustrank(), topic_sensitive_pagerank(), topic_feeder_pagerank() and
pagerank_screaming_frog() — with one boundary: arguments a wrapper sets
itself are wrapper-owned, and a preset cannot change those.
Presets are not composable with each other; preset takes a single bundle.
They do not need to be: "content" sets only placement weights and leaves
every hygiene knob at its default, and the defaults are the "declared"
view.
Because a preset is an ordinary list, you can splice it, print it, or use it as a starting point:
# Splice a bundle into a call do.call(pagerank, c(list(edges), pr_preset("raw"))) # Start from a preset and adjust my_view <- pr_preset("raw") my_view$drop_isolates_flag <- TRUE pagerank(edges, preset = my_view)
Hand-rolled bundles are validated against pagerank()'s formals, so a
misspelled argument fails loudly instead of sliding through ....
The audit attached to every result records which named view produced it:
attr(pagerank(edges, preset = "raw"), "transition_audit")$config$preset
It records the preset name for a registered preset (whether passed by name or
as a pr_preset() result), "custom" for a hand-rolled bundle, and NULL
when no preset was used. Two runs that expand to the same configuration are
therefore still distinguishable by the intent behind them — which, for a pure
pin like "declared", is the only durable record that intent existed.
?pr_preset for the reference documentation.vignette("pagerankr-usage") for the underlying arguments each preset sets.Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.