The ALLELEMATCH Package for R: Supplementary Documentation with Tutorials

P. Galpern, M. Manseau, P. Hettinga, K. Smith, and P. Wilson

2026-06-28

1 Introduction

This R vignette can also be found as a PDF document supplement to the publication describing the allelematch package. Here, we describe the operation of the package in more detail and illustrate its use in a tutorial format.

The allelematch package was developed to identify unique genotype profiles in situations where there are likely to be multiple samples of each individual present. Such conditions arise in wildlife conservation genetics where non-invasive sampling of feather, hair, and fecal material can produce large datasets containing an unknown number of animals.

Finding unique individuals appears on the surface to be a trivial exercise; a matter of sorting genotypes into identical groups. When there is unlikely to be error in profiling and missing data is absent, identity analysis is straightforward and software for this purpose has long been available (Kalinowski et al., 2007; Peakall & Smouse, 2006; Wilberg & Dreher, 2004). The task becomes much more complicated if data sets contain missing information at some loci, or are subject to even a modest amount of genotyping error. In these cases samples from the same individual may differ because of allele dropouts or false alleles, or they may be identical except for some missing information. These issues make it ambiguous which samples belong to which individual, or how many individuals are present.

This is the niche for allelematch: applications of genotype profiling where identity must be established in suboptimal circumstances. In conservation genetics these conditions are common. Collecting high quality samples can often be challenging, and as data sets grow larger in size, quality control may be uneven. allelematch may also be useful in laboratory quality control, i.e., to visually highlight genotyping errors in data sets where the same individual is profiled multiple times for confirmation.

2 Approach

allelematch operates by comparing rows of a multilocus genotype matrix, where rows are samples, and columns for each locus give the names of the alleles that are present. For diploid codominant data, there are typically two columns for each locus. It finds the similarities between the samples using a metric which is a form of the Hamming distance (Hamming, 1950) modified to account for missing data. It then uses hierarchical clustering and a dynamic method for identifying clusters on a dendrogram. This step is done using the Dynamic Tree Cut package for R (Langfelder et al., 2008) which defines groups of similar samples at a specified threshold of dissimilarity.

2.1 Algorithm

Specifically, amUnique(), the workhorse function of the package, performs the following operations:

  1. Determine a similarity score for each pair of samples. Let \(A\) be a matrix \([a_{ij}]_{m \times n}\) with elements that are allele names or missing data, where \(m\) is the number of samples, and \(n\) is the total number of columns containing the allele calls. Find the similarity score,

    \[s_{p,q} = \frac{N_{\text{match}_{p,q}}}{n} + \frac{N_{\text{missing}_{p,q}}}{2n}, \forall p,q \in \{1, 2, \dots, m\} \quad (1)\]

    where \(N_{\text{match}_{p,q}}\) is the number of elements (alleles or missing data) that match in rows \(a_{p,*}\) and \(a_{q,*}\), and \(N_{\text{missing}_{p,q}}\) is the number of elements that are missing in either row \(a_{p,*}\) or row \(a_{q,*}\). A score of \(s_{p,q} = 1\) means that the elements of both rows are identical. Scores less than one have been penalized \(\frac{1}{n}\) for each mismatching element, and penalized a smaller amount, \(\frac{1}{2n}\), where an element is missing in one row but not missing in the other row.

  2. Produce a symmetric dissimilarity matrix from the similarity scores, \(s_{p,q}\).

\[D_{m,m} = 1 - \begin{bmatrix} 1 & s_{1,2} & \dots & s_{1,m} \\ s_{2,1} & 1 & \dots & s_{2,m} \\ \vdots & \vdots & \ddots & \vdots \\ s_{m,1} & s_{m,2} & \dots & 1 \end{bmatrix}\]

  1. Perform agglomerative hierarchical clustering on the dissimilarity matrix, \(D\), using the complete linkage method.

  2. Use a hybrid dynamic tree cutting method (Langfelder et al., 2008) to identify clusters, where a cut height parameter \(\hat{d}\) gives the maximum dissimilarity between any two samples in a cluster. This parameter is related to the similarity score as \(\hat{d} = 1 - \hat{s}\).

  3. Find the consensus sample for each cluster, if a cluster contains more than one sample at this \(\hat{d}\). allelematch provides two supported options1 for declaring consensus samples:

    1. The consensus is the sample that is most similar to other samples in the cluster (calculated using Equation 1).

    2. The consensus is the sample with the least amount of missing data.

  4. Declare as singletons samples which are the only member of their cluster.

  5. Produce a new matrix \(A' = [a'_{ij}]_{m' \times n}\) consisting of the consensus samples if they exist, and the singleton samples.

  6. IF \(A'\) contains only singletons continue to step 9. ELSE let \(A = A'\) and return to step 1.

  7. Declare as unique all rows of the matrix \(A'\).

  8. Compare unique matrix \(A'\) to all original samples. For each row \(a'_{q,*}\) of the unique matrix \(A'\), find all rows \(a_{p,*}\) of the original matrix \(A\) that have a similarity score \(s_{p,q} \ge \hat{s}\). For example,

\[s_{p,q} = \frac{N_{\text{match}_{p,q}}}{n} + \frac{N_{\text{missing}_{p,q}}}{2n}, \forall p \in \{1, 2, \dots, m\}, q \in \{1, 2, \dots, m'\} \quad (2)\]

  1. Declare as matches rows \(a'_{q,*}\) that have a score \(s_{p,q} \ge \hat{s}\) for exactly one row \(a_{p,*}\).

  2. Declare as multiple matches rows \(a'_{q,*}\) that have a score \(s_{p,q} \ge \hat{s}\) for two or more rows \(a_{p,*}\).

  3. Declare as unclassified rows \(a'_{q,*}\) that do not have a score \(s_{p,q} \ge \hat{s}\).

2.2 Notes

3 Tutorial

The tutorial is organized around example data sets. Five examples review the use of allelematch for identifying samples representing unique individuals in datasets where these individuals may be sampled multiple times.

The tutorials provide sample code, and the graphical output from R has been inserted as figures. However, the most important output from allelematch is in the form of HTML documents. These illustrate in colour how samples match and mismatch. Note that within one example multiple HTML files may be generated and these are numbered sequentially (e.g. example1_1.html, example1_2.html, etc.).

It is also possible to reproduce these examples directly in R. All example data sets are provided with the package and the tutorials demonstrate how to access this data.

3.1 Quantifying Missing Data

In datasets where missing indices are prevalent or individual loci suffer from a high drop-out rate, allelematch calculations may approach mathematical stability limits. The first suggested step in the workflow is to pre-screen your dataset for missing allele calls.

Use amPreCheck() to generate a comprehensive summary of missing data across loci and samples, alongside the minimum number of shared loci discovered between any pair of individuals. If a dataset features samples that share zero overlapping loci, amPreCheck() will issue a critical warning to help you identify these constraints before they trigger runtime errors during clustering.

Users are strongly encouraged to enforce quality control filtering before executing full allelematch optimization routines. For example, a reliable threshold for stable clustering is ensuring that at least 75% of the total locus panel is called for every individual sample. While lower thresholds can sometimes be tolerated, severe data sparsity may introduce instability or bias into downstream genetic analyses. We will demonstrate the utility of this function in each of the three examples below.

3.2 Identifying unique individuals

Example 1: High quality data set

The data in this example are simulated2 to represent a high quality data set that might result from a laboratory protocol where samples were run multiple times to confirm their identity. It has no genotyping error, a near-zero missing data load, and approximately 60% of the individuals have been artificially resampled more than once.

In typical usage data would be imported into R in the most convenient manner. This may be the read.csv() function for example. In this and the following examples we load the data supplied with the package using the data() function.

library(allelematch)

data(amExample1)

Next, we create an amDataset object to prepare the data for use with other allelematch functions. The sample number serves as the index, missing data is coded as “-99”, and we explicitly exclude the knownIndividual column. We then pre-screen the data using amPreCheck().

example1 <- amDataset(
  amExample1, 
  indexColumn = "sampleId",
  ignoreColumn = "knownIndividual", 
  missingCode = "-99"
)

amPreCheck(example1)

The report for this dataset indicates high data quality: no single locus exceeds 5% missing data, the average individual missing data load is only 0.5%, and the individual with the highest missing data load is at 10%. Furthermore, every pair of samples shares at least 9 out of 10 loci. Given these metrics, the function provides a safe verdict, indicating the dataset is well-suited for clustering.

The next step is to determine the optimal dissimilarity criterion for identifying unique individuals. This criterion is best understood in terms of the number of allele mismatches allowed (alleleMismatch parameter; or \(\hat{m}\) (see Section 2.2 Notes). This routine evaluates the number of unique individuals identified across a range of parameter values to suggest an optimal threshold.

amUniqueProfile(example1, doPlot = TRUE)

The output profile (Figure 1) shows that an optimum for this data is allowing 2 alleles to mismatch (alleleMismatch = 2). Note how multipleMatch, the number of samples that match more than one unique individual, is zero at the optimum. This tells us that every sample has been declared as a unique individual or as a match to a unique individual.

Figure 1: High quality dataset.
Figure 1: High quality dataset.

This is described as a ZeroSecondMinimum profile, indicating that multipleMatch reaches zero at a parameter setting other than alleleMismatch = 0. Simulations indicate that with this profile morphology the software can independently determine the alleleMismatch parameter required to identify the correct number of unique genotypes (\(\pm 3\%\)).3

The final step is to use the alleleMismatch criterion to identify which samples are unique and which samples are matches.

uniqueExample1 <- amUnique(example1, alleleMismatch = 2)

This should be reviewed carefully before proceeding. The results can be viewed in an HTML format as follows.

## Save to disk
summary(uniqueExample1, html = "example1_1.html")

## View in default browser
summary(uniqueExample1, html = TRUE)

In this example, 12 unique genotypes were identified among 20 samples. The alleleMismatch parameter we set at an earlier step allows up to two alleles to be different for samples to be declared identical. Examining the HTML output, there are no cases where mismatches occurred. The mismatching alleles would be highlighted in red. There is one case with missing data at one locus (unique genotype 12), and pink highlighting is used to indicate missing data. Recall how a missing allele in one genotype but not the other penalizes the score by \(\frac{1}{2n}\) (by Equation 1). For this reason sample 19 (also unique genotype 12) matches itself with a score of 1, but matches sample 20 with a score of 0.95.

The same results can also be saved in a CSV spreadsheet format. This format lacks some of the supplementary information as well as the colour formatting that can be helpful for reviewing the results.

summary(uniqueExample1, csv = "example1_1.csv")

An analysis-ready dataset can also be prepared from the CSV output. We encourage caution with this step. Typically the output of the analysis must be reviewed in detail before an analysis-ready data set can be used uncritically. For example, checking that \(P_{\text{sib}}\) probabilities are all below a threshold value is a minimum requirement as allelematch does not use this as a criterion.

summary(uniqueExample1, csv = "example1_2.csv", uniqueOnly = TRUE)

When the multiple sampling was simulated in this data set, we kept track of which individual each sample came from in the knownIndividual column. For typical non-invasive sampling applications, however, such information would not be known. We will repeat the analysis using this column as the meta-data to demonstrate that allelematch performed correctly.

example1chk <- amDataset(
  amExample1, 
  indexColumn = "sampleId",
  metaDataColumn = "knownIndividual", 
  missingCode = "-99"
)

uniqueExample1chk <- amUnique(example1chk, alleleMismatch = 2)

summary(uniqueExample1chk, html = "example1_2.html")

Notice how the individual identifier (a three-letter code) is consistent between the genotype declared unique and the genotypes that match it. Also note how each unique identifier appears only once in the list of unique genotypes, indicating that the analysis has not overestimated the number of individuals.

Example 2: Good quality data set

The data in this example have also been simulated4, this time to reflect the qualities of a good quality data set, where genotyping error and missing data exist, but these can be confidently handled by allelematch without manual intervention. At each locus, a random 4% of heterozygotes lost their second allele to simulate an allele dropout, and a random 4% of samples at each locus had alleles set to missing.

Load the data and create an amDataset object. The knownIndividual column is again kept as meta-data for instructional purposes. Then, we pre-screen the data using the amPreCheck() function.

data(amExample2)

example2 <- amDataset(
  amExample2, 
  indexColumn = "sampleId",
  metaDataColumn = "knownIndividual", 
  missingCode = "-99"
)

amPreCheck(example2)

The report for this dataset indicates good data quality: no single locus exceeds 4.7% missing data, the average individual missing data load is 4.6%, but the individual with the highest missing data load is at 20%. Furthermore, every pair of samples shares at least 6 out of 10 loci. Given these metrics, the function provides a safe verdict, indicating the dataset is well-suited for clustering.

Find the optimal alleleMismatch parameter for this data set.

amUniqueProfile(example2, doPlot = TRUE)

The output profile (Figure 2) demonstrates a ZeroSecondMinimum profile suggesting that the identified alleleMismatch parameter can be applied with confidence.

Figure 2: Good quality dataset.
Figure 2: Good quality dataset.

Conduct the unique analysis with the recommended alleleMismatch setting, and review the HTML output.

uniqueExample2 <- amUnique(example2, alleleMismatch = 3)

summary(uniqueExample2, html = "example2_1.html")

allelematch identified 100 unique genotypes from these 148 samples, and did so with no errors (as illustrated by the knownIndividual identifier). There are a number of examples of allelematch correctly matching samples despite allele mismatches (the mismatching alleles are highlighted in red).

\(P_{\text{sib}}\) is not given in these mismatching cases by default because partial matching samples are not “identical”. However, if we treat mismatching alleles as if they were missing, \(P_{\text{sib}}\) can be calculated for the non-missing loci as follows:

uniqueExample2 <- amUnique(example2, alleleMismatch = 3, doPsib = "all")

summary(uniqueExample2, html = "example2_2.html")

It is important to stress again that allelematch does not identify unique genotypes using the \(P_{\text{sib}}\) criterion, but rather presents this value to allow the user to assess the probability that:

Matching samples represent siblings of unique genotypes rather than duplicate samples of the same individual.

Unique genotypes represent siblings of other unique genotypes.

Example 3: Marginal quality data set

The data in this example have been simulated5 to represent a data set of marginal quality where the use of allelematch combined with careful manual review of the results is required to achieve a confident assessment of the unique genotypes. At each locus, a random 4% of heterozygotes lost their second allele to simulate an allele dropout, and a random 10% of samples at each locus had alleles set to missing.

Load the data and create an amDataset object. Once again, we retain the knownIndividual for instructional purposes. Then, we pre-screen the data using the amPreCheck() function.

data(amExample3)

example3 <- amDataset(
  amExample3, 
  indexColumn = "sampleId",
  metaDataColumn = "knownIndividual", 
  missingCode = "-99"
)

amPreCheck(example3)

The report for this dataset indicates marginal data quality: no single locus exceeds 9.7% missing data, the average individual missing data load is 9.7%, but the individual with the highest missing data load is at 50%. Here, at least one pair of sample shares only 2 out of 10 loci. Still, given these metrics, the function provides a safe verdict, indicating the dataset is well-suited for clustering.

Find the optimal alleleMismatch parameter for this data set.

amUniqueProfile(example3, doPlot = TRUE)

The output profile (Figure 3) demonstrates a NonZeroSecondMinimum profile, which is the first sign that we are dealing with a marginal data set. When this sort of profile is produced, amUniqueProfile() can be somewhat error-prone in finding the optimal value for the alleleMismatch parameter, and our first concern is making sure that it chose the best value.

Figure 3: Marginal quality dataset.
Figure 3: Marginal quality dataset.

We are looking for the second minimum in the multipleMatch variable (the first minimum being at alleleMismatch = 0), and the function appears to have identified this correctly at alleleMismatch = 6.

Conduct the unique analysis with the recommended alleleMismatch setting, and review the HTML output.

uniqueExample3 <- amUnique(example3, alleleMismatch = 6)

summary(uniqueExample3, html = "example3_1.html")

Two new issues appear in this example that did not exist for the previous two data sets. The header of the HTML output informs us that there are 2 unclassified samples and 4 multipleMatch samples. We will consider these in turn.

Unclassified samples are those which just exceed the criterion of similarity to be declared a match, but as an artifact of the dynamic tree cutting algorithm are not sufficiently different to be declared unique (i.e., to form their own clusters). Often this is because of missing data rather than mismatching data. If the analysis protocol does not permit their exclusion, the most robust approach is to reprofile these samples at their missing loci. However, this may not always be possible. Here we demonstrate an approach to simplify the manual classification of these samples.

The task is to determine whether these unclassified samples should be declared a unique genotype or as a match to an existing unique genotype. We use a function which conducts a pairwise analysis, comparing all the rows in the dataset of the first argument with all rows in the dataset of the second argument and returning those that exceed a similarity score (i.e., by Equation 2). In this case, the first dataset consists of the two unclassified samples from the previous step, and the second consists of all the samples declared as unique in the previous step. These datasets can be accessed from the uniqueExample3 object produced by amUnique().

unclassifiedExample3 <- amPairwise(
  uniqueExample3$unclassified,
  uniqueExample3$unique, 
  alleleMismatch = 7
)

Note how we used the next highest criterion, alleleMismatch = 7, because we want to see if these samples are only slightly more different than existing unique genotypes. We can then examine this in HTML format.

summary(unclassifiedExample3, html = "example3_2.html")

Using this output, we must now make a judgement call about what types of evidence are sufficient for declaring differences among individuals. Here, the rows with yellow highlighting are the unclassified samples and the rows without highlighting are unique genotypes.

For the first unclassified sample, it is mostly missing data and one mismatch that is driving the borderline status. If the five missing loci were reprofiled, it is likely that these two rows would match at a much lower criterion, and therefore sample 208 should be declared a match of sample 204. Thanks to the knownIndividual information retained from when the data were simulated, we can confirm this supposition. Indeed, the two samples did come from the same individual, ACN.

The second unclassified sample achieves its borderline status with four missing loci, but it also differs from its closest unique genotype because of three mismatching alleles. In this case, it is more likely that sample 251 is a unique genotype. Again, this conclusion is supported by the knownIndividual column with samples representing individuals ADA and ABN.

MultipleMatch samples are those that match more than one unique genotype. These occur when samples do not all sort into clearly defined groups representing unique genotypes. As the profiling shows, the numbers of these uncertain samples varies with the alleleMismatch criterion.

If we set the criterion too low, unique genotypes will not be sufficiently different and samples will appear to match multiple unique individuals. If we set a high criterion, it might not matter as long as unique genotypes are well-differentiated (e.g., Example 1; alleleMismatch = 3 to alleleMismatch = 7).

However, in cases where there is low allelic diversity and heterozygosity in the dataset, there could be insufficient information to distinguish unique genotypes when the criterion is set too high, and once again unique genotypes may be improperly determined, resulting in samples that will match multiple unique genotypes.

We could examine the earlier output from the unique analysis to resolve these samples (the questionable genotypes are flagged CHECK UNIQUE and the samples that cause this are flagged MULTIPLE MATCH). However, it is simpler to again use a pairwise approach to bring together just the relevant samples. Here we compare the four multipleMatch samples against the unique genotypes. The criterion is not changed this time from the original unique analysis.

multipleMatchExample3 <- amPairwise(
  uniqueExample3$multipleMatch,
  uniqueExample3$unique, 
  alleleMismatch = 6
)

summary(multipleMatchExample3, html = "example3_3.html")

Examining the HTML output, sample 112 (yellow highlighting) matches two unique genotypes (unhighlighted). Sample 110 is very likely the same unique genotype as 112 because it differs mostly because of missing data, while sample 260 differs by both four mismatching alleles and missing data. In this case, sample 112 can be declared a match of sample 110 and a false match of sample 260. Using the same argumentation, sample 162 is likely a match of 161, and sample 218 a match of 213. This has resolved three of the four multipleMatch cases.

Sample 183 differs from two unique genotypes (samples 182 and 181) chiefly because of missing data. In this case, we should consider two unique genotype rows to be the same as the multipleMatch sample; we could think of sample 183 as an intermediate or “missing link” between two incorrectly designated unique genotypes. As a result, we must remove one of the unique genotypes. Because it has the least amount of missing data, let’s declare sample 181 the unique genotype, and sample 183 and 182 matches of this unique genotype.

Once again, we turn to the knownIndividual column for confirmation that we made the correct decisions for this simulated data. Indeed, the correct decision was to reduce the total number of unique genotypes by one (individual ACF appears in two unique genotypes).

Reviewing the unclassified samples added sample 251 to the unique genotype list, and reviewing the multipleMatch samples removed sample 183 from the unique genotype list. Finally, we produce a CSV file of the original unique analysis and use spreadsheet software to make the necessary changes in classification.

summary(uniqueExample3, csv = "example3_1.csv")

Example 4: Low quality data set

For this example, we have simulated6 a low quality data set where uncertainty created by genotyping error and missing data, combined with a lack of information in the form of allelic diversity across loci, will result in a low confidence assessment of the unique genotypes. At each locus, a random 6% of heterozygotes lost their second allele to simulate an allele dropout, and a random 20% of samples at each locus had alleles set to missing.

Load the data and create an amDataset object. Again, we retain the knownIndividual for instructional reasons. Then, we pre-screen the data using the amPreCheck() function.

data(amExample4)

example4 <- amDataset(
  amExample4, 
  indexColumn = "sampleId",
  metaDataColumn = "knownIndividual", 
  missingCode = "-99"
)

amPreCheck(example4)

The report for this dataset indicates low data quality: no single locus exceeds 19.9% missing data, the average individual missing data load is 19.9%, but the individual with the highest missing data load is at 70%. Here, at least one pair of samples is not called at any of the same loci. Given these metrics, the function provides a critical warning, indicating the dataset may not provide stable clusters, and suggests close inspection of the output, and consideration of pre-filtration of the data to remove individuals or loci with high missing data rates.

Find the optimal alleleMismatch parameter for this data set.

amUniqueProfile(example4, doPlot = TRUE)

The output profile (Figure 4) demonstrates a NoSecondMinimum profile, which is a sign that allelematch cannot make a confident assessment of the unique genotypes within the range of the alleleMismatch criterion examined (by default this is 0% to 40% of allele columns mismatching). We can also, therefore, disregard the optimal alleleMismatch criterion.

Figure 4: Low quality dataset.
Figure 4: Low quality dataset.

For illustration, let’s see what would happen if we used this criterion uncritically and proceeded with the analysis.

uniqueExample4 <- amUnique(example4, alleleMismatch = 1)

summary(uniqueExample4, html = "example4_1.html")

Thanks to the knownIndividual column, we find in the output that at this low criterion all samples are declared unique incorrectly.

We know from our simulation that there should be exactly 100 unique genotypes in this data set. In practice, of course, this would seldom be known. But it may be possible to have a ballpark estimate for the number of unique genotypes. Let’s set our ballpark estimate at 100, and look at Figure 4 to find what setting of alleleMismatch we would need to return approximately 100 samples. This appears to be alleleMismatch = 6.

uniqueExample4ballpark <- amUnique(example4, alleleMismatch = 6)

summary(uniqueExample4ballpark, html = "example4_2.html")

There are 99 individuals in this output, but from the knownIndividual column we can see that there are a number of individuals that have been declared unique genotypes more than once, and others that should have been declared unique have been overlooked. Given uncertainty and the absence of information in the data set, allelematch is unable to identify the unique genotypes with confidence. Arguably, a human tasked with the same job would face the same challenge.

In some analysis protocols, however, a high confidence assessment of all the unique genotypes may not be required. For example, a subsample of the unique genotypes in a population may be needed for a multi-population analysis. One approach is simply to remove samples with more than a threshold amount of missing data in the hope that this reduces ambiguity in the data set. Another approach is to set a high alleleMismatch criterion. For example:

uniqueExample4high <- amUnique(example4, alleleMismatch = 8)

summary(uniqueExample4high, html = "example4_3.html")

Looking at the knownIndividual column for the unique genotypes in the output, we can see we have produced a set of truly unique genotypes using this very high alleleMismatch criterion, although these will be biased towards individuals who are unrelated.

Example 5: Wildlife data set

In this final example, we use real data from the non-invasive sampling of a wildlife population. The data have been anonymized by changing sampling details. A single column giving the sex is also available, and we show how this can be used as an extra locus. Missing data is also more common at some loci than at others, with a total load of about 10%.

First, load the data, then create the amDataset object, using the samplingData column as meta-data. Note that we have previously concatenated several sampling data columns into one because allelematch is limited to only one meta-data column and we require this information for downstream analyses. (Concatenation of the raw data set could be done using the paste() function, for example.)

Also note how the index column, sampleId can contain any valid ASCII character, and is not limited to numerals. Allele columns are also not limited to numerals, as is the case with the sex column.

Next, we pre-screen the data using the amPreCheck() function.

data(amExample5)

# Inspect the unique levels of metadata and identifiers
head(levels(amExample5$samplingData))
head(levels(amExample5$sampleId))
head(levels(amExample5$sex))

example5 <- amDataset(
  amExample5, 
  indexColumn = "sampleId",
  metaDataColumn = "samplingData", 
  missingCode = "-99"
)

amPreCheck(example5)

The report for this dataset indicates marginal data quality: no single locus exceeds 72.8% missing data, the average individual missing data load is 9.5%, but the individual with the highest missing data load is at 23.8%. Here, at every pair of samples is called at least 8 out of the 11 loci (10 diploid, and 1 sex column). Given these metrics, the function provides a cautionary warning, indicating the missing data load is heavy, that high parameter settings may produce unstable clusters, and consideration of pre-filtration of the data to remove individuals or loci with high missing data rates.

allelematch operates largely without reference to loci, instead working by matching elements of corresponding row vectors. Locus information is only required for the sibling \(P_{\text{sib}}\) calculation. In previous examples, we have not specified which allele columns were associated with each locus because there were an even number of columns. allelematch correctly assumed that it was reading codominant diploid data, and therefore that columns were paired for each locus.

In this data set, we have one unpaired column, sex, and ten additional loci in paired columns.

names(amExample5)

We can create a mapping vector to specify how the allele columns map onto loci. This vector should be the same length as the number of allele columns, and each element should give an arbitrary name or number for the locus it represents.

example5map <- c(
  "sex", "LOC1", "LOC1", "LOC2", "LOC2", "LOC3", "LOC3", 
  "LOC4", "LOC4", "LOC5", "LOC5", "LOC6", "LOC6", "LOC7", 
  "LOC7", "LOC8", "LOC8", "LOC9", "LOC9", "LOC10", "LOC10"
)

An equivalent and much more compact way of doing this is as follows:

example5map <- c(1, rep(2:11, each = 2))

Next, we find the optimal alleleMismatch parameter for this data set. We specify the locus mapping using the multilocusMap parameter.

amUniqueProfile(example5, multilocusMap = example5map, doPlot = TRUE)

The output profile (Figure 5) demonstrates a NonZeroSecondMinimum profile. We note that the optimal criterion has been correctly determined from the profile at alleleMismatch = 3 because this value is the second minimum.

Figure 5: Wildlife dataset.
Figure 5: Wildlife dataset.

The profile morphology, low allelic diversity, and high missing data load suggest immediately that we are dealing with a data set of marginal quality and should be prepared to take extra steps to classify some unclassified samples, and review the classifications of unique genotypes that have multipleMatch samples.

Now, we run the unique analysis using the recommended alleleMismatch setting and produce HTML output.

uniqueExample5 <- amUnique(
  example5, 
  multilocusMap = example5map, 
  alleleMismatch = 3
)

summary(uniqueExample5, html = "example5_1.html")

Looking at the output, we find three unclassified samples and 11 multipleMatch samples. We can review the unclassified samples by using the next highest alleleMismatch setting. Using this output, we can decide whether to classify these as unique genotypes or matches to existing unique genotypes.

unclassifiedExample5 <- amPairwise(
  uniqueExample5$unclassified,
  uniqueExample5$unique, 
  alleleMismatch = 4
)

summary(unclassifiedExample5, html = "example5_2.html")

Next, we can review the multipleMatch samples at the original alleleMismatch setting. This output can help us determine if the CHECK UNIQUE samples should remain as unique genotypes, or be reclassified as matches to a unique genotype.

multipleMatchExample5 <- amPairwise(
  uniqueExample5$multipleMatch,
  uniqueExample5$unique, 
  alleleMismatch = 3
)

summary(multipleMatchExample5, html = "example5_3.html")

Finally, if we prefer to use our favourite spreadsheet software rather than R, we can create a CSV version of the original unique analysis, and use this to manually reclassify samples as required as well as prepare the data set for subsequent analyses.

summary(uniqueExample5, csv = "example5_1.csv")

References

Hamming RW (1950) Error detecting and error correcting codes. Bell System Technical Journal, 29, 147-160.

Kalinowski ST, Taper ML, Marshall TC (2007) Revising how the computer program CERVUS accommodates genotyping error increases success in paternity assignment. Molecular Ecology, 16, 1099-1106.

Langfelder P, Zhang B, Horvath S (2008) Defining clusters from a hierarchical cluster tree: the Dynamic Tree Cut package for R. Bioinformatics, 24, 719.

Peakall R, Smouse PE (2006) GENALEX 6: genetic analysis in Excel. Population genetic software for teaching and research. Molecular Ecology Notes, 6, 288-295.

Wilberg MJ, Dreher BP (2004) GENECAP: a program for analysis of multilocus genotype data for non-invasive sampling and capture-recapture population estimation. Molecular Ecology Notes, 4, 783-785.

Woods JG, Paetkau D, Lewis D, et al. (1999) Genetic tagging of free-ranging black and brown bears. Wildlife Society Bulletin, 27, 616-627.


  1. Options to interpolate missing data when identifying the consensus are currently experimental.↩︎

  2. Please see the publication associated with this package for details on how data were simulated.↩︎

  3. Please see the publication associated with this package for more information on how this was verified.↩︎

  4. Please see the publication associated with this package for details on how data were simulated.↩︎

  5. Please see the publication associated with this package for details on how data were simulated.↩︎

  6. Please see the publication associated with this package for details on how data were simulated.↩︎