TaxResolveR provides a reproducible workflow for preparing, resolving, assessing, reviewing, summarising, and documenting scientific names used in ecological and biodiversity datasets.
The package separates three related tasks: preparing scientific names for taxonomic resolution, obtaining matches from an external taxonomic source, and evaluating whether those matches should be accepted directly or reviewed manually.
This distinction is important because successful taxonomic resolution does not necessarily imply an exact species-level match.
For this introduction, consider a small vector containing valid species names, a genus placeholder, an empty value, and a missing value.
TaxResolveR provides several functions for inspecting and preparing scientific names before external taxonomic resolution.
clean_scientific_names() performs basic cleaning while
preserving missing and empty values.
parse_scientific_names() separates recognised components
of scientific names and identifies the detected rank or placeholder
structure.
parse_scientific_names(scientific_names)
#> original_name genus specific_epithet infraspecific_rank
#> 1 Homo sapiens Homo sapiens <NA>
#> 2 Parastacus brasiliensis Parastacus brasiliensis <NA>
#> 3 Chilina sp. Chilina <NA> <NA>
#> 4 <NA> <NA> <NA>
#> 5 <NA> <NA> <NA> <NA>
#> infraspecific_epithet rank_detected
#> 1 <NA> species
#> 2 <NA> species
#> 3 <NA> genus_placeholder
#> 4 <NA> <NA>
#> 5 <NA> <NA>classify_scientific_names() combines parsing information
with a structural classification of each input record.
classify_scientific_names(scientific_names)
#> original_name clean_name genus
#> 1 Homo sapiens Homo sapiens Homo
#> 2 Parastacus brasiliensis Parastacus brasiliensis Parastacus
#> 3 Chilina sp. Chilina sp. Chilina
#> 4 <NA>
#> 5 <NA> <NA> <NA>
#> specific_epithet infraspecific_rank infraspecific_epithet rank_detected
#> 1 sapiens <NA> <NA> species
#> 2 brasiliensis <NA> <NA> species
#> 3 <NA> <NA> <NA> genus_placeholder
#> 4 <NA> <NA> <NA> <NA>
#> 5 <NA> <NA> <NA> <NA>
#> canonical_name parse_success name_status
#> 1 Homo sapiens TRUE valid_structure
#> 2 Parastacus brasiliensis TRUE valid_structure
#> 3 Chilina sp. TRUE placeholder
#> 4 <NA> FALSE empty
#> 5 <NA> FALSE missingFor example, a conventional binomial can be classified as
valid_structure, whereas Chilina sp. is
recognised as a placeholder. Empty and missing inputs
remain explicitly distinguishable.
validate_species_names() provides simple structural
indicators that are useful when screening input data.
validate_species_names(scientific_names)
#> original_name missing_name empty_name multiple_spaces binomial
#> 1 Homo sapiens FALSE FALSE FALSE TRUE
#> 2 Parastacus brasiliensis FALSE FALSE FALSE TRUE
#> 3 Chilina sp. FALSE FALSE FALSE FALSE
#> 4 FALSE TRUE FALSE FALSE
#> 5 <NA> TRUE FALSE FALSE FALSEStructural validation should not be interpreted as taxonomic resolution. For example, a genus placeholder is not a binomial species name but can still contain enough information to support a genus-level query.
standardize_scientific_names() combines cleaned and
parsed information into a standardised representation.
standardize_scientific_names(scientific_names)
#> original_name clean_name genus
#> 1 Homo sapiens Homo sapiens Homo
#> 2 Parastacus brasiliensis Parastacus brasiliensis Parastacus
#> 3 Chilina sp. Chilina sp. Chilina
#> 4 <NA>
#> 5 <NA> <NA> <NA>
#> specific_epithet infraspecific_rank infraspecific_epithet rank_detected
#> 1 sapiens <NA> <NA> species
#> 2 brasiliensis <NA> <NA> species
#> 3 <NA> <NA> <NA> genus_placeholder
#> 4 <NA> <NA> <NA> <NA>
#> 5 <NA> <NA> <NA> <NA>
#> canonical_name parse_success
#> 1 Homo sapiens TRUE
#> 2 Parastacus brasiliensis TRUE
#> 3 Chilina sp. TRUE
#> 4 <NA> FALSE
#> 5 <NA> FALSEprepare_taxonomic_queries() determines which records
contain sufficient information for taxonomic resolution and constructs
the corresponding query names.
prepare_taxonomic_queries(scientific_names)
#> original_name clean_name genus
#> 1 Homo sapiens Homo sapiens Homo
#> 2 Parastacus brasiliensis Parastacus brasiliensis Parastacus
#> 3 Chilina sp. Chilina sp. Chilina
#> 4 <NA>
#> 5 <NA> <NA> <NA>
#> specific_epithet infraspecific_rank infraspecific_epithet rank_detected
#> 1 sapiens <NA> <NA> species
#> 2 brasiliensis <NA> <NA> species
#> 3 <NA> <NA> <NA> genus_placeholder
#> 4 <NA> <NA> <NA> <NA>
#> 5 <NA> <NA> <NA> <NA>
#> canonical_name parse_success name_status query_name
#> 1 Homo sapiens TRUE valid_structure Homo sapiens
#> 2 Parastacus brasiliensis TRUE valid_structure Parastacus brasiliensis
#> 3 Chilina sp. TRUE placeholder Chilina
#> 4 <NA> FALSE empty <NA>
#> 5 <NA> FALSE missing <NA>
#> query_ready
#> 1 TRUE
#> 2 TRUE
#> 3 TRUE
#> 4 FALSE
#> 5 FALSEA placeholder such as Chilina sp. is therefore converted
to the genus query Chilina, whereas empty and missing
records are marked as not ready for querying.
resolve_taxonomy() sends prepared names to an external
taxonomic source. GBIF is currently the implemented source.
A typical call is:
Because external taxonomic services require network access and can change over time, live GBIF queries are not evaluated while this vignette is built. This keeps package documentation reproducible and prevents temporary network or service problems from causing vignette-build failures.
taxresolve()For most users, taxresolve() is the main entry point. It
combines taxonomic resolution, match assessment, and review
flagging.
For example:
results <- taxresolve(
c(
"Homo sapiens",
"Homo sapens",
"Chilina sp.",
"Parastacus brasiliensis"
),
source = "gbif"
)The returned data frame contains the taxonomic information supplied by the resolution stage together with fields describing resolution status, match quality, acceptance status, and whether manual review is recommended.
The remainder of this vignette uses a fixed example representing a taxonomic-resolution result. This allows the assessment, review, summary, and reporting stages to be demonstrated without requiring network access.
The example includes an exact species match, a non-exact match, an exact genus-level match, another exact species match, two non-queryable records, and one unresolved query.
resolved_example <- data.frame(
source = rep("gbif", 7),
query_name = c(
"Homo sapiens",
"Homo sapens",
"Chilina",
"Parastacus brasiliensis",
NA_character_,
NA_character_,
"Xyzabc nonexistenttaxon"
),
matched_name = c(
"Homo sapiens",
"Homo sapiens",
"Chilina",
"Parastacus brasiliensis",
NA_character_, NA_character_, NA_character_
),
accepted_name = c(
"Homo sapiens",
"Homo sapiens",
"Chilina",
"Parastacus brasiliensis",
NA_character_, NA_character_, NA_character_
),
taxonomic_status = c(
"ACCEPTED", "ACCEPTED", "ACCEPTED", "ACCEPTED",
NA_character_, NA_character_, NA_character_
),
rank = c(
"SPECIES", "SPECIES", "GENUS", "SPECIES",
NA_character_, NA_character_, NA_character_
),
kingdom = rep(NA_character_, 7),
phylum = rep(NA_character_, 7),
class = rep(NA_character_, 7),
order = rep(NA_character_, 7),
family = rep(NA_character_, 7),
genus = rep(NA_character_, 7),
taxon_id = c(
2436436, 2436436, 3243720, 2224027,
NA_real_, NA_real_, NA_real_
),
match_type = c(
"EXACT", "VARIANT", "EXACT", "EXACT",
NA_character_, NA_character_, NA_character_
),
match_confidence = c(
99, 95, 94, 99, NA_real_, NA_real_, NA_real_
),
resolution_success = c(
TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE
),
stringsAsFactors = FALSE
)
resolved_example[c(
"query_name",
"matched_name",
"rank",
"match_type",
"match_confidence",
"resolution_success"
)]
#> query_name matched_name rank match_type
#> 1 Homo sapiens Homo sapiens SPECIES EXACT
#> 2 Homo sapens Homo sapiens SPECIES VARIANT
#> 3 Chilina Chilina GENUS EXACT
#> 4 Parastacus brasiliensis Parastacus brasiliensis SPECIES EXACT
#> 5 <NA> <NA> <NA> <NA>
#> 6 <NA> <NA> <NA> <NA>
#> 7 Xyzabc nonexistenttaxon <NA> <NA> <NA>
#> match_confidence resolution_success
#> 1 99 TRUE
#> 2 95 TRUE
#> 3 94 TRUE
#> 4 99 TRUE
#> 5 NA FALSE
#> 6 NA FALSE
#> 7 NA FALSEassess_taxonomic_match() interprets the resolution
output and adds three fields: resolution_status,
match_quality, and accepted_status.
assessed_example <- assess_taxonomic_match(resolved_example)
assessed_example[c(
"query_name",
"resolution_status",
"match_quality",
"accepted_status"
)]
#> query_name resolution_status match_quality accepted_status
#> 1 Homo sapiens resolved high accepted
#> 2 Homo sapens resolved moderate accepted
#> 3 Chilina resolved high accepted
#> 4 Parastacus brasiliensis resolved high accepted
#> 5 <NA> not_queryable <NA> <NA>
#> 6 <NA> not_queryable <NA> <NA>
#> 7 Xyzabc nonexistenttaxon unresolved unresolved unresolvedA high-quality match should not automatically be interpreted as a
species-level identification. In this example, Chilina is
an exact genus-level match and is therefore distinct from an exact
species-level match.
flag_taxonomic_review() adds
review_required and review_reason.
reviewed_example <- flag_taxonomic_review(assessed_example)
reviewed_example[c(
"query_name",
"resolution_status",
"match_quality",
"review_required",
"review_reason"
)]
#> query_name resolution_status match_quality review_required
#> 1 Homo sapiens resolved high FALSE
#> 2 Homo sapens resolved moderate TRUE
#> 3 Chilina resolved high FALSE
#> 4 Parastacus brasiliensis resolved high FALSE
#> 5 <NA> not_queryable <NA> TRUE
#> 6 <NA> not_queryable <NA> TRUE
#> 7 Xyzabc nonexistenttaxon unresolved unresolved TRUE
#> review_reason
#> 1 <NA>
#> 2 non_exact_match
#> 3 <NA>
#> 4 <NA>
#> 5 not_queryable
#> 6 not_queryable
#> 7 unresolvedThis separates successful resolution from records that still warrant attention. Non-exact matches, unresolved queries, and non-queryable inputs can therefore be documented explicitly rather than silently discarded.
summarize_taxonomic_resolution() returns a compact
one-row summary of the main resolution, match-quality, acceptance, and
review counts.
taxonomic_resolution_report() produces a structured
report containing the total summary together with category counts and
proportions.
report_example <- taxonomic_resolution_report(reviewed_example)
report_example$total_summary
#> total_names resolved unresolved not_queryable high_quality moderate_quality
#> 1 7 4 1 2 3 1
#> low_quality accepted not_accepted review_required
#> 1 0 4 0 4
report_example$resolution_status
#> category n proportion
#> 1 resolved 4 0.5714286
#> 2 unresolved 1 0.1428571
#> 3 not_queryable 2 0.2857143
report_example$match_quality
#> category n proportion
#> 1 high 3 0.4285714
#> 2 moderate 1 0.1428571
#> 3 low 0 0.0000000
#> 4 unresolved 1 0.1428571
#> 5 not_queryable 0 0.0000000
report_example$review_reasons
#> category n proportion
#> 1 non_exact_match 1 0.1428571
#> 2 low_information_match 0 0.0000000
#> 3 not_accepted 0 0.0000000
#> 4 uncertain_taxonomic_status 0 0.0000000
#> 5 unresolved 1 0.1428571
#> 6 not_queryable 2 0.2857143
#> 7 insufficient_information 0 0.0000000The proportions in the detailed tables use the total number of input records as their denominator.
export_taxonomic_results() can write the complete
reviewed data and associated summary tables to CSV files.
A typical export is:
The function creates five files: taxonomic_results.csv,
taxonomic_summary.csv, resolution_status.csv,
match_quality.csv, and review_reasons.csv.
Existing managed output files are not overwritten unless
overwrite = TRUE is requested.
The export example is not evaluated while building this vignette because documentation should not create persistent user-facing output directories as a side effect.
TaxResolveR is designed to retain problematic records rather than silently remove them. Missing and empty inputs can remain in the workflow as non-queryable records, while syntactically queryable names that cannot be resolved can be retained as unresolved records.
Duplicate names can also be retained in the returned data so that row-level correspondence with the original input is preserved.
This behaviour supports data auditing because unresolved or incomplete taxonomic information remains visible in downstream summaries and review flags.
For routine use, a practical workflow is to:
taxresolve() using the intended taxonomic
source;review_required is
TRUE;Because external taxonomies can change, the taxonomic source and date of resolution should be retained as part of a reproducible biodiversity workflow.