| Type: | Package |
| Title: | Transforming Data Between Statistical Classifications |
| Version: | 0.2.0 |
| Description: | Provides support for transformations of numeric aggregates between statistical classifications (e.g. occupation or industry categorisations) using the 'Crossmaps' framework. Implements classes for representing transformations between a source and target classification as graph structures, and methods for validating and applying crossmaps to transform data collected under the source classification into data indexed using the target classification codes. Documentation about the 'Crossmaps' framework is provided in the included vignettes and in Huang (2024, <doi:10.48550/arXiv.2406.14163>). |
| License: | MIT + file LICENSE |
| Encoding: | UTF-8 |
| Language: | en-GB |
| Maintainer: | Cynthia A. Huang <cynthiahqy@gmail.com> |
| URL: | https://github.com/cynthiahqy/xmap, https://cynthiahqy.github.io/xmap/ |
| BugReports: | https://github.com/cynthiahqy/xmap/issues |
| LazyData: | true |
| Depends: | R (≥ 4.1) |
| Imports: | cli (≥ 3.4.0), dplyr (≥ 1.1.0), methods, pillar (≥ 1.6.0), rlang (≥ 1.0.0), tibble, tidyr, tidyselect, vctrs (≥ 0.6.0) |
| Suggests: | forcats, ggalluvial, ggforce, ggplot2, ggrepel, glue, knitr, purrr, RColorBrewer, rmarkdown, scales, stringr, testthat (≥ 3.0.0) |
| Config/testthat/edition: | 3 |
| VignetteBuilder: | knitr |
| Config/roxygen2/version: | 8.1.0 |
| NeedsCompilation: | no |
| Packaged: | 2026-08-23 14:33:17 UTC; cynthiah |
| Author: | Cynthia A. Huang |
| Repository: | CRAN |
| Date/Publication: | 2026-08-23 15:50:02 UTC |
xmap: Transforming Data Between Statistical Classifications
Description
Provides support for transformations of numeric aggregates between statistical classifications (e.g. occupation or industry categorisations) using the 'Crossmaps' framework. Implements classes for representing transformations between a source and target classification as graph structures, and methods for validating and applying crossmaps to transform data collected under the source classification into data indexed using the target classification codes. Documentation about the 'Crossmaps' framework is provided in the included vignettes and in Huang (2024, doi:10.48550/arXiv.2406.14163).
Author(s)
Maintainer: Cynthia A. Huang cynthiahqy@gmail.com (ORCID)
Authors:
Cynthia A. Huang cynthiahqy@gmail.com (ORCID)
Laura Puzzello [funder]
See Also
Useful links:
Report bugs at https://github.com/cynthiahqy/xmap/issues
Apply Crossmap Transformation to Conformable Data
Description
This function applies crossmap transformation to a dataset, transforming data based on specified mapping rules.
Usage
apply_xmap(.data, .xmap, values_from, keys_from = names(.xmap$.from), ...)
diagnose_apply_xmap(
.data,
.xmap,
values_from,
keys_from = names(.xmap$.from),
...
)
Arguments
.data |
The dataset to transform. |
.xmap |
An |
values_from |
A |
keys_from |
A |
... |
(reserved) |
Details
diagnose_apply_xmap() checks whether .data is conformable with
.xmap – the same two conditions apply_xmap() checks – and returns
detail on any offending rows, to help resolve the specific issue rather
than just knowing something's wrong. The returned xmap_diagnosis's
details has one entry per condition (NULL where that check passed):
-
not_covered: rows of.datawhosekeys_fromkey has no matching link in.xmap$.from -
missing_values: rows of.datawith a missing value in one or morevalues_fromcolumns
Value
A tibble with transformed data.
diagnose_apply_xmap() returns an xmap_diagnosis object: a
list with valid (a scalar logical) and details (a named list of
tibbles of offending rows, one per check, NULL where that check
passed). Printing the result shows a readable pass/fail report; see
new_xmap_diagnosis().
Functions
-
diagnose_apply_xmap(): Returns anxmap_diagnosisobject diagnosing why.datafailsapply_xmap()'s conformability checks.
Examples
abc_xmap <- demo$abc_links |>
as_xmap_tbl(from = "lower", to = "upper", weight_by = "share")
abc_data <- tibble::tibble(
lower = unique(demo$abc_links$lower),
count = runif(length(unique(demo$abc_links$lower)), min = 100, max = 500)
)
apply_xmap(
.data = abc_data,
.xmap = abc_xmap,
values_from = count
)
Coerce links into a crossmap tibble
Description
Converts an object of links into an xmap_tbl. Methods exist for
data.frame and matrix — see their respective sections below for how
from/to/weight_by are interpreted by each. Aborts with a message
pointing at the offending condition if the links aren't a valid crossmap
— the same conditions validate_as_xmap() checks, though currently
implemented independently rather than by calling it (except for the
matrix method, which does call validate_as_xmap() directly).
Usage
as_xmap_tbl(x, ...)
## S3 method for class 'data.frame'
as_xmap_tbl(x, from, to, weight_by, ..., tol = .Machine$double.eps^0.5)
## S3 method for class 'matrix'
as_xmap_tbl(
x,
...,
from = NULL,
to = NULL,
weight_by = NULL,
tol = .Machine$double.eps^0.5
)
diagnose_as_xmap_tbl(
x,
from,
to,
weight_by,
...,
tol = .Machine$double.eps^0.5
)
Arguments
x |
An object with links to coerce. Methods exist for |
... |
(reserved) Additional arguments passed to methods. |
from |
Identifies the 'from' nodes. For the |
to |
Identifies the 'to' nodes. For the |
weight_by |
Identifies the weight of the links. For the
|
tol |
Tolerance of comparison. |
Details
diagnose_as_xmap_tbl() checks whether x's links form a valid
crossmap — the same conditions validate_as_xmap() checks, though
currently implemented independently rather than by calling it — and
returns detail on any offending rows, to help resolve the specific
issue rather than just knowing something's wrong. The returned
xmap_diagnosis's details has one entry per condition ('NULL' where
that check passed):
-
bad_dups: rows sharing a.from-.topair with another row -
miss_from,miss_to,miss_weight_by: rows with a missing.from,.to, or.weight_byvalue, respectively -
nonpositive_weights: rows whose.weight_byis zero or negative -
bad_froms: for each.fromwhose outgoing weights don't sum to (near enough) one, that.fromand its actual weight sum
Value
Returns an xmap tibble object.
diagnose_as_xmap_tbl() returns an xmap_diagnosis object: a
list with valid (a scalar logical) and details (a named list of
tibbles of offending rows, one per check, NULL where that check
passed). Printing the result shows a readable pass/fail report; see
new_xmap_diagnosis().
Data frame method
as_xmap_tbl.data.frame() takes a data.frame-like object and converts
it into an xmap_tbl based on specified columns for from, to, and
weight_by.
Matrix method
as_xmap_tbl.matrix() takes an adjacency matrix (rows = .from,
columns = .to, cells = .weight_by, per validate_as_xmap()'s
.matrix method) and reshapes it into an xmap_tbl, dropping
zero-weight cells (non-links). It checks matrix validity with
validate_as_xmap() before reshaping — checking only after would let
an all-zero row (a .from with no outgoing links) disappear silently,
since dropping its only cells removes the row from the reshaped table
before anything could flag it.
from/to/weight_by here are optional strings naming the resulting
columns, since a matrix (unlike a data frame) has no columns to select
from — identity comes from dimnames() instead. They default to
names(dimnames(x)) when set, falling back to "rowname"/"colname"/
"cell" (named after where each value is actually pulled from) when
x has no named dimnames.
Examples
demo$abc_links |>
as_xmap_tbl(from = lower, to = upper, weight_by = share)
abc_matrix <- demo$abc_links |>
tidyr::pivot_wider(names_from = upper, values_from = share, values_fill = 0) |>
tibble::column_to_rownames("lower") |>
as.matrix()
as_xmap_tbl(abc_matrix)
Check whether matched keys/values are conformable with an xmap_tbl's
.from set (internal)
Description
The single source of truth for the two data-conformability conditions
apply_xmap() requires before transforming, shared by apply_xmap()'s
abort gate, diagnose_apply_xmap()'s flags, and validate_apply_xmap(),
so the three don't independently re-implement (and risk drifting on) the
same checks.
Usage
check_conformable_xmap_data(key, value, from)
Arguments
key |
A vector of matched keys from |
value |
A data frame of matched value column(s) from |
from |
|
Value
A list of two logicals: covered (every key has a matching
from) and no_missing_values (no value column has a missing value).
Check whether already-split .from/.to/.weight_by columns form a
valid crossmap (internal)
Description
The single source of truth for the three link-validity conditions,
shared by validate_as_xmap.data.frame() and xmap_tbl()'s construction
gate, so the two don't independently re-implement (and risk drifting on)
the same checks.
Usage
check_valid_xmap_df(tbl_x, tol)
Arguments
tbl_x |
A tibble/data frame with |
tol |
Deliberately has no default here, unlike the exported
entry points that call this – forces every caller to explicitly
forward its own user-facing |
Value
A single logical.
Compose Two Crossmaps Through a Shared Intermediate Classification
Description
Given xmap1 (S -> M) and xmap2 (M -> T) sharing intermediate
key set M, chains them into a single crossmap S -> T without
materialising M-level values. Composed weights sum, over every
shared m, the product of xmap1's weight onto m and xmap2's
weight from m:
w(s, t) = \sum_{m \in M} w_1(s, m) \, w_2(m, t)
Usage
compose_xmap(xmap1, xmap2, ..., tol = .Machine$double.eps^0.5)
Arguments
xmap1 |
An |
xmap2 |
An |
... |
(reserved) |
tol |
Tolerance of comparison. |
Details
Re-checks that both inputs are actually valid crossmaps, not just correctly classed, and aborts otherwise.
Only takes two crossmaps at a time. Matrix multiplication is
associative, so chain longer sequences with Reduce() instead of a
dedicated variadic interface – see the example below. Grouped
composition (e.g. one xmap1 per group, composed against a shared
xmap2) is likewise left to the caller via dplyr::group_map().
Known limitation: composing two individually-tol-valid crossmaps
can produce a composed crossmap that fails that same tol. Composed
weights are sums of products of the input weights, which amplifies
floating-point drift relative to either input alone – and compounds
further across a Reduce()-chained sequence. Widening tol on the
compose_xmap() call (or on the final Reduce() step) works around
this in practice, but the underlying cause is .weight_by being plain
double rather than a representation with an exact sum-to-1 guarantee
(see #27).
Value
An xmap_tbl, S -> T.
Examples
abc_xmap <- demo$abc_links |>
as_xmap_tbl(from = lower, to = upper, weight_by = share)
top_xmap <- tibble::tibble(
upper = c("AA", "BB", "CC", "DD", "EE"),
top = c("AAA", "AAA", "BBB", "BBB", "BBB"),
weight = 1
) |>
as_xmap_tbl(from = upper, to = top, weight_by = weight)
compose_xmap(abc_xmap, top_xmap)
# chaining more than two crossmaps: reduce pairwise composition over a
# list, e.g. lower -> upper -> top -> region
region_xmap <- tibble::tibble(
top = c("AAA", "BBB"),
region = c("north", "south"),
weight = 1
) |>
as_xmap_tbl(from = top, to = region, weight_by = weight)
Reduce(compose_xmap, list(abc_xmap, top_xmap, region_xmap))
Demo objects for the xmap package
Description
A collection of demo inputs for experimenting with functions
in the xmap package.
_pairs objects are tibbles with just source-target pairs (no weights)
_links objects are tibbles with weighted source-target links.
Usage
demo
Format
demo
A list with:
- ctr_iso3c_pairs
named vector with 249 elements. Names are ISO-3 country codes, values are ISO English country names. Retrieved from
countrycodepackage: https://github.com/vincentarelbundock/countrycode- anzsco22_isco8_crosswalk
tibble with 10 rows and 5 columns. Subset of crosswalk between ANZSCO22 and ISCO8 Occupation Code Standards published by The AUstralian Bureau of Statistics
- anzsco22_stats
tibble with 10 rows and 2 columns. Stylised Occupation Counts
- simple_links
tibble with 10 rows and 3 columns. specifying links
xcode->alphacodebyweight- abc_links
tibble with 6 rows and 3 columns, specifying links
lower->upperbyshare- aus_state_pairs
named list with 1 element named "AUS" containing codes for the Australian states
- aus_state_pop_df
tibble containing 2022 population figures for Australia by state. Retrieved from: https://www.abs.gov.au/statistics/people/population/national-state-and-territory-population/jun-2022
Examples
demo$abc_links
UNIDO INDSTAT4 industrial statistics (masked), with country lookup
Description
A subset of UNIDO's INDSTAT4 industrial-statistics database, with the
reported output value masked to a constant, bundled together with a
small country-code lookup table since the two are relationally paired
(indstat$masked_sample$country joins onto
indstat$country_lookup$code). Used in
vignette("extract-validate-existing") (Case 2) to
demonstrate grouped crossmap validation across country/year. Some
isic industry codes are reported only in combination (isiccomb),
with a single value covering several isic codes at once – the
vignette splits these back out.
Usage
indstat
Format
indstat
A list with:
- masked_sample
tibble with 17,365 rows and 11 columns:
- ctable
table code;
14(the only value in this subset) denotes the OUTPUT dimension of INDSTAT4- country
three-digit UN M49 country code (joins onto
country_lookup$code); 133 distinct countries in the full INDSTAT4 Rev.3 dataset, 8 in this subset- year
observation year (1990-2013)
- isic
3- or 4-digit ISIC Rev.3 industry code; every 4-digit code nests inside the 3-digit code given by its first three digits
- isiccomb
ISIC code as originally reported – either the same as
isic, or a combined code (containing a letter, e.g."151A") covering severalisiccodes at once- value
reported output value in USD, masked to
1000in this dataset (real values are not shipped);NAforisiccodes with no directly reported value (i.e. covered only by another row'sisiccomb)- utable
output valuation methodology, consistent within a country/year but variable across countries:
11= basic prices,12= factor prices,13= producers' prices,14= valuation not defined- source
reporting-status flag (
0-3) – exact code meanings are undocumented upstream, not just unconfirmed here (see reference below)- unit
value unit; always
"$"(USD) in INDSTAT4, no national-currency variants- country_iso3c
ISO-3c country code, joined from
country_lookup- country_name
country name, joined from
country_lookup
- country_lookup
tibble with 8 rows and 4 columns, a small lookup table of the 8 countries included in
masked_sample, used to join ISO-3c codes and country names onto it:- code
three-digit UN M49 country code, joins onto
masked_sample$country- name
country name
- iso3c
ISO-3c country code
- income_group
World Bank income group classification, 2006 vintage:
"H"= high income,"UM"= upper-middle income,"LM"= lower-middle income,"L"= low income. All four groups are represented in this subset
- isic_rev3_lookup
tibble with 529 rows and 4 columns, the full ISIC Rev. 3 classification hierarchy, giving a label for every
isic/isiccombcode number used inmasked_sample:- code
ISIC Rev. 3 code: a single letter for
"section"(17 rows), otherwise 2/3/4 digits for"division"/"group"/"class"- level
one of
"section","division","group","class", determined by the length ofcode- label
English description of the code
- parent_code
code of the immediate numeric parent – a
"class"code's first three digits (its"group"), or a"group"code's first two digits (its"division").NAfor"section"and"division", since sections cover ranges of divisions rather than sharing a numeric prefix with them
Details
The 8 reporters are five large economies (BRA, CHN, DEU, JPN, USA)
plus three chosen for structurally distinct splitting behaviour once
the split is re-aggregated to 3-digit ISIC: Colombia (splits are
entirely reconvergent – imputed at 4 digits, exact at 3), Romania
(the deepest sustained convergence in the source extract) and Yemen
(~95% of isic values sit in splits that cross a 3-digit boundary).
Source
masked_sample: downloaded and parsed from the UNIDO
INDSTAT4 website (Rev.3, 2019 vintage). See
https://cynthiahqy.github.io/indstat-TPP/001-clean_INDSTAT.html
for the cleaning pipeline this subset was derived from.
country_lookup: read by data-raw/indstat.R from
data-raw/indstat-country-lookup.csv, exported alongside
masked_sample by the same upstream script. income_group is the
2006 column of the World Bank's historical income classification
workbook ("Country Analytical History" sheet of OGHIST.xlsx);
current download at
https://datahelpdesk.worldbank.org/knowledgebase/articles/906519-world-bank-country-and-lending-groups
isic_rev3_lookup: UN Statistics Division classifications registry,
ISIC Rev. 3 English structure file, downloaded from
https://unstats.un.org/unsd/classifications/Econ/Download/In%20Text/ISIC_Rev_3_english_structure.Txt
into data-raw/isic_rev3_structure.txt. See #34.
Construct an xmap_diagnosis object
Description
xmap_diagnosis is the shared return contract for diagnose_as_xmap_*()
functions across crossmap representations (data frame, matrix, graph,
...): a single object shape regardless of whether the diagnosis passed
or failed, so callers can inspect $valid programmatically, or print
the object for a human-readable report of what needs fixing.
Usage
new_xmap_diagnosis(
valid,
details,
labels,
class = character(),
msg_valid,
msg_invalid
)
Arguments
valid |
A single logical: did every check pass? |
details |
A named list of tibbles (or |
labels |
A named list, one entry per check (same names as
|
class |
Additional subclass(es) to prepend, e.g. |
msg_valid, msg_invalid |
The headline |
Details
The set of checks, their labels, and what counts as an "offending
location" (rows, matrix cells, graph edges, ...) is specific to each
representation. Callers of new_xmap_diagnosis() supply labels for
their own checks, and are responsible for normalizing each check's
offending locations into a tibble before passing them in details —
print.xmap_diagnosis() stays representation-agnostic by only ever
printing tibbles.
Value
An xmap_diagnosis object.
Timor-Leste census occupation codes
Description
A ~1% sample of individual-level records from the Timor-Leste
Population and Housing Census 2015, prepared for the
occupation-categorisation analysis in Mata Dalan Institute (2020) –
see @source below. Used in
vignette("extract-validate-existing") (Case 1) to
demonstrate recovering an implicit occupation-recoding script as an
explicit crossmap.
Usage
timor_occupn
Format
A tibble with 11,775 rows and 5 columns:
- houseid
household identifier (5,508 distinct households)
- pno
person number within the household
- p3p3_sex
sex of the individual:
"1. Male"or"2. Female"- p3p4_age
age in years (0-98)
- occupn
original occupation code (161 distinct non-missing values, ranging 110-9999).
NAwhere no occupation code was recorded – these rows skew toward younger ages (median 12 vs. 39.5 for rows with a code) but the two groups overlap, so age alone doesn't fully explain which rows are missing
Source
Individual-level extract of the Timor-Leste Population and Housing Census 2015 microdata, prepared for the occupation-category analysis (Figures 1-2) in: Mata Dalan Institute (2020), "The Informal Sector in Timor-Leste in the Midst of COVID-19", August 2020, with support from Oxfam and Professor Brett Inder (Monash University). https://oi-files-cng-v2-prod.s3.eu-west-2.amazonaws.com/asia.oxfam.org/s3fs-public/file_attachments/MDI_COVID-19_Informal%20sector%20Research_Aug%2020_Final_English.pdf
timor_occupn is a ~1% sample of the full 1,179,654-row individual-level
census extract, grouped by occupn and sampled with dplyr – so the set
of occupation codes present is closer to fully represented than a plain
random sample of individuals would give. See data-raw/occupation.R.
Cheaply check whether .data is conformable with an xmap_tbl
Description
validate_apply_xmap() checks the same two conditions apply_xmap()
requires before transforming .data – every keys_from key has a
matching .xmap$.from link, and no values_from column has a missing
value – and returns a single logical, without building the
offending-rows/columns detail objects that diagnose_apply_xmap() does.
It's the primitive to reach for when you only need a pass/fail answer –
e.g. checking many .data/.xmap group pairs with dplyr::mutate() or
purrr::map2_lgl() before applying any of them. Reach for
diagnose_apply_xmap() once validate_apply_xmap() says something
failed and you need to know why; apply_xmap() checks the same
conditions at transform time and aborts with a message pointing at the
offending condition.
Usage
validate_apply_xmap(
.data,
.xmap,
values_from,
keys_from = names(.xmap$.from),
...
)
Arguments
.data |
The dataset to transform. |
.xmap |
An |
values_from |
A |
keys_from |
A |
... |
(reserved) |
Value
A single logical.
Examples
abc_xmap <- demo$abc_links |>
as_xmap_tbl(from = "lower", to = "upper", weight_by = "share")
abc_data <- tibble::tibble(
lower = unique(demo$abc_links$lower),
count = runif(length(unique(demo$abc_links$lower)), min = 100, max = 500)
)
validate_apply_xmap(abc_data, abc_xmap, values_from = count)
Cheaply check whether links form a valid crossmap
Description
A valid crossmap's links must satisfy four conditions:
Usage
validate_as_xmap(x, ..., tol = .Machine$double.eps^0.5)
## S3 method for class 'data.frame'
validate_as_xmap(x, from, to, weight_by, ..., tol = .Machine$double.eps^0.5)
## S3 method for class 'matrix'
validate_as_xmap(x, ..., tol = .Machine$double.eps^0.5)
Arguments
x |
An object with links to validate. Methods exist for |
... |
Passed to methods. |
tol |
Tolerance of comparison. |
from |
The column in |
to |
The column in |
weight_by |
The column in |
Details
every link has a non-missing
.from,.to, and.weight_byno two links share the same
.from-.topair (data-frame representations only — see the.matrixmethod for why this doesn't carry over to a matrix representation)every
.weight_byis strictly positive — a weight of zero or less means the pair isn't a valid link at all, not a degenerate onefor each
.from, the.weight_byvalues of its outgoing links sum to (approximately) one — this is what guarantees the total mass before and after a transformation stays the same
validate_as_xmap() checks these conditions and returns a single
logical, without building the offending-rows detail objects that
diagnose_as_xmap_tbl() does. It's the primitive to reach for when you
only need a pass/fail answer — e.g. inside dplyr::filter() or
dplyr::group_map() over many groups. Reach for diagnose_as_xmap_tbl()
once validate_as_xmap() says something failed and you need to know
why; xmap_tbl()/as_xmap_tbl() check the same conditions at
construction time and abort with a message pointing at the offending
condition.
Value
A single logical.
Conditions for matrices
A matrix represents .from/.to identity through dimnames() (rows =
.from, columns = .to) rather than per-link values, so the three
conditions above translate differently:
non-missing
.from/.tobecomes "rownames()/colnames()are non-NULL, with no repeated names"; non-missing.weight_bybecomes "noNAcells"the no-duplicate-pairs check does not carry over as-is: a single cell can't encode a duplicate pair (each is already a unique row x column intersection). What can still happen — and is checked above as a
.from/.to-identity condition, not a pairs condition — is repeateddimnames(): base R places no uniqueness constraint on them, e.g.matrix(1:4, 2, 2, dimnames = list(c("a", "a"), c("x", "y")))is a valid matrix with a repeated row name. A repeated row name would mean the same.fromkey has more than one, independently-checked set of outgoing weights; a repeated column name would mean weights for the same.tokey are split across columns, invisible torowSums(). Both are rejected by the row/column name uniqueness checkweights summing to one becomes a row-sum check; a row summing to exactly zero (a
.fromwith no outgoing links) fails here too, since 0 is never near enough to 1
Examples
demo$abc_links |>
validate_as_xmap(from = lower, to = upper, weight_by = share)
abc_matrix <- demo$abc_links |>
tidyr::pivot_wider(names_from = upper, values_from = share, values_fill = 0) |>
tibble::column_to_rownames("lower") |>
as.matrix()
validate_as_xmap(abc_matrix)
Boolean flags for properties of candidate and validated xmap links (internal)
Description
vhas_*() functions check properties of xmap links and/or candidate links.
They are the shared primitives behind the three link-validity conditions
checked independently by xmap_tbl(), diagnose_as_xmap_tbl(), and
validate_as_xmap()'s data.frame method — every non-matrix check of
"is x a valid crossmap" should route through these rather than
reimplementing the underlying logic.
Usage
vhas_no_missing(x)
vhas_no_dup_pairs(v_from, v_to)
vhas_positive_weights(v_weights)
vhas_valid_weights(v_from, v_weights, tol)
Arguments
x |
a vector, or a single-column data frame (as used to store
|
v_from, v_to, v_weights |
equal length vectors containing the source-target node pairs |
tol |
numeric >= 0. Ignore differences smaller than |
Value
TRUE or FALSE
Functions
-
vhas_no_missing(): Returns TRUE ifxhas no missing values -
vhas_no_dup_pairs(): Returns TRUE if xmap does not have duplicate pairs of source-target nodes (irrespective of weights) -
vhas_positive_weights(): Returns TRUE if every weight is strictly positive. A crossmap link's weight must lie in(0, 1]– a weight of exactly zero (or a negative weight) means the pair isn't a valid link at all, rather than a degenerate one, so it's checked separately fromvhas_valid_weights()'s per-.fromsum-to-one condition. A missing weight also fails this check (rather than propagatingNA) –vhas_no_missing()is where a missing-weight condition should be diagnosed on its own terms. -
vhas_valid_weights(): Returns TRUE if all weights for a givenfromlabel sum to (approximately) one. Afromlabel with no outgoing weights, or whose outgoing weights sum to zero, fails this check — a valid crossmap has no dangling.fromnodes. A missing weight also fails this check (rather than propagatingNA) —vhas_no_missing()is where a missing-weight condition should be diagnosed on its own terms.
Internal rlang methods
Description
Internal rlang methods
Internal vctrs methods
Description
Internal vctrs methods