taxodist represents each taxon as an ordered lineage
from the root of The Taxonomicon classification to the queried node. The
resulting distance is a property of that classification hierarchy. It is
not an estimate of divergence time, genetic distance, or phylogenetic
branch length.
Let \(L_A\) and \(L_B\) be two ordered lineages. Let \(h(A,B)\) be the length of their continuous common prefix, equivalent to the depth of their most recent common ancestor (MRCA). The distance is
\[ d(A,B) = \begin{cases} 0, & L_A = L_B, \\ 1/h(A,B), & L_A \ne L_B. \end{cases} \]
If two lineages have no shared root, the package returns an infinite distance. Names repeated after the first divergence are not considered evidence of shared ancestry.
Zero is reserved for the same hierarchy node. Consequently, an
ancestor and one of its descendants have positive distance even though
they are connected by ancestry. Membership and distance answer different
questions: is_member() and taxo_path() should
be used for containment and ancestry queries.
For lineages belonging to one connected hierarchy, the distance is non-negative, symmetric, and satisfies identity of indiscernibles. It also satisfies the strong triangle inequality
\[ d(A,C) \leq \max\{d(A,B), d(B,C)\}. \]
The common prefix of \(A\) and \(C\) must be at least as long as the shorter of the common prefixes of \((A,B)\) and \((B,C)\). Therefore,
\[ h(A,C) \geq \min\{h(A,B),h(B,C)\}. \]
Taking reciprocals gives the strong triangle inequality.
The property can also be checked on the offline reference matrix distributed with the package.
m <- as.matrix(taxobase$statistical_matrix)
tolerance <- sqrt(.Machine$double.eps)
ultrametric_ok <- function(index) {
i <- index[1]
j <- index[2]
k <- index[3]
d_ij <- m[i, j]
d_ik <- m[i, k]
d_jk <- m[j, k]
d_ij <= max(d_ik, d_jk) + tolerance &&
d_ik <= max(d_ij, d_jk) + tolerance &&
d_jk <= max(d_ij, d_ik) + tolerance
}
all(combn(seq_len(nrow(m)), 3, FUN = ultrametric_ok))
#> [1] TRUEThe reciprocal distance weights shallow divergences heavily: two taxa whose MRCA is at depth 2 are at distance 0.5, while MRCAs at depths 40 and 41 give 0.025 and 0.024. It is also sensitive to the uneven resolution of the classification: in The Taxonomicon, vertebrate lineages are typically several times deeper than bacterial ones, so equal values do not correspond to equivalent taxonomic levels in different groups.
The metric argument offers three alternatives. With
\(d_A\) and \(d_B\) the depths of the two lineages:
| Metric | Definition | Properties |
|---|---|---|
"reciprocal" |
\(1/h\) | ultrametric |
"path" |
\(d_A + d_B - 2h\) | tree metric (number of edges) |
"wu_palmer" |
\(1 - 2h/(d_A + d_B)\) | in \([0, 1)\); normalized by depth |
"ranked" |
half the path through standard ranks only | Clarke and Warwick step weights |
The "ranked" metric reduces each lineage to its root,
the nodes of the Linnaean ranks kingdom, phylum, class, order, family,
genus, and species, and the queried taxon. Unranked clades, which make
up most of the nodes of richly resolved groups, are ignored. For two
species, the distance is the number of rank levels up to their shared
rank: 1 in the same genus, 2 in the same family, and so on. Rank levels
can be changed with the taxodist.rank_levels option. Note
that The Taxonomicon follows current phylogenetic classifications, so
that, for example, birds are the subclass Aves of the class
Reptilia.
lineages <- list(
Panthera = c("Biota", "Animalia", "Chordata", "Mammalia", "Carnivora",
"Felidae", "Panthera"),
Felis = c("Biota", "Animalia", "Chordata", "Mammalia", "Carnivora",
"Felidae", "Felis"),
Canis = c("Biota", "Animalia", "Chordata", "Mammalia", "Carnivora",
"Canidae", "Canis"),
Homo = c("Biota", "Animalia", "Chordata", "Mammalia", "Primates",
"Hominidae", "Homo"),
Musca = c("Biota", "Animalia", "Arthropoda", "Insecta", "Diptera",
"Muscidae", "Musca")
)
standard <- c(NA, "Kingdom", "Phylum", "Class", "Order", "Family", "Genus")
example <- taxo_from_lineages(
lineages,
ranks = rep(list(standard), length(lineages)) |> setNames(names(lineages))
)
for (metric in c("reciprocal", "path", "wu_palmer", "ranked")) {
cat("\n", metric, "\n")
print(round(distance_matrix(example, metric = metric, progress = FALSE), 3))
}
#>
#> reciprocal
#> Panthera Felis Canis Homo
#> Felis 0.167
#> Canis 0.200 0.200
#> Homo 0.250 0.250 0.250
#> Musca 0.500 0.500 0.500 0.500
#>
#> path
#> Panthera Felis Canis Homo
#> Felis 2
#> Canis 4 4
#> Homo 6 6 6
#> Musca 10 10 10 10
#>
#> wu_palmer
#> Panthera Felis Canis Homo
#> Felis 0.143
#> Canis 0.286 0.286
#> Homo 0.429 0.429 0.429
#> Musca 0.714 0.714 0.714 0.714
#>
#> ranked
#> Panthera Felis Canis Homo
#> Felis 1
#> Canis 2 2
#> Homo 3 3 3
#> Musca 5 5 5 5Rankings of pairs are the same under all four metrics within a single, evenly resolved lineage set such as this one; they differ when lineages of very different depths are compared.
taxo_distinctness() computes the indices of Warwick and
Clarke: taxonomic diversity \(\Delta\),
taxonomic distinctness \(\Delta^*\),
average taxonomic distinctness \(\Delta^+\), and its variation \(\Lambda^+\). With the "ranked"
metric they reproduce the classical definitions based on Linnaean ranks,
and they agree with vegan::taxondive(); with the other
metrics they use the full resolution of the classification.
d <- distance_matrix(example, metric = "ranked", progress = FALSE)
communities <- rbind(
site_1 = c(Panthera = 4, Felis = 2, Canis = 1, Homo = 0, Musca = 0),
site_2 = c(Panthera = 1, Felis = 0, Canis = 1, Homo = 2, Musca = 5)
)
taxo_distinctness(communities, d)
#>
#> ── Taxonomic distinctness ──
#>
#> Metric: ranked
#> sample S Delta Delta_star Delta_plus Lambda_plus SDelta_plus
#> site_1 3 0.952381 1.428571 1.666667 0.2222222 5.00000
#> site_2 4 3.166667 4.560000 3.833333 1.4722222 15.33333\(\Delta^+\) does not depend on sample size in expectation, so a sample can be compared with random samples of the same number of taxa drawn from a master list:
set.seed(1)
taxo_distinctness_test(c("Panthera", "Felis", "Canis"), d, n_iter = 499)
#>
#> ── Taxonomic distinctness test ──
#>
#> 3 taxa vs 499 random samples from a pool of 5 (metric: ranked)
#> statistic observed expected lower upper p_lower p_upper
#> Delta_plus 1.6667 3.400 1.6667 4.333 0.096 1
#> Lambda_plus 0.2222 1.195 0.2222 3.556 0.276 1The numerical value depends on the number and arrangement of nodes returned by The Taxonomicon. Taxonomic revisions, alternative classifications, and differences in lineage resolution can change both MRCA depth and distance.
Comparisons should therefore use lineages obtained from the same source and, where possible, the same package and data-retrieval version.
Some names correspond to more than one valid biological entry. A numeric Taxonomicon identifier can be supplied when a specific taxonomic concept is required.
Missing lineages produce missing pairwise values. Lineages without a common root produce infinite values. These cases should be resolved before applying methods that require a complete finite matrix, including clustering and ordination.
Smaller values indicate a deeper shared node in the source classification. They should not be interpreted as:
Hierarchical clustering of these distances produces a taxonomic similarity dendrogram, not an independently inferred phylogenetic tree.
Analyses using taxodist should report:
Formatted citations for the package and The Taxonomicon are available
through citation("taxodist").