% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/markExcluded.R
\name{markExcluded}
\alias{markExcluded}
\title{Mark "exclude" (non-distinct / non-unique / ambiguous) taxa}
\usage{
markExcluded(
  df_samptax,
  SampID = "SAMPLEID",
  TaxaID = "TAXAID",
  TaxaCount = "N_TAXA",
  Exclude = "EXCLUDE",
  TaxaLevels,
  Exceptions = NA,
  verbose = FALSE
)
}
\arguments{
\item{df_samptax}{Input data frame.}

\item{SampID}{Column name in df_samptax for sample identifier.
Default = "SAMPLEID".}

\item{TaxaID}{Column name in df_samptax for organism identifier.
Default = "TAXAID".}

\item{TaxaCount}{Column name in df_samptax for organism count.
Default = "N_TAXA".}

\item{Exclude}{Column name for Exclude Taxa results in returned data frame.
Default = "Exclude".}

\item{TaxaLevels}{Column names in df_samptax that for phylogenetic names to
be evaluated.
Need to be in order from coarse to fine (i.e., Phylum to Species).}

\item{Exceptions}{NA or two column data frame of synonyms or other
exceptions.  Default = NA
Column 1 is the name used in the TaxaID column of df_samptax.
Column 2 is the name used in the TaxaLevels columns of df_samptax.}

\item{verbose}{Boolean value for if status messages are output to the
console.
Default = FALSE}
}
\value{
Returns a data frame of df_samptax with an additional column,
Exclude.
}
\description{
Takes as an input data frame with Sample ID, Taxa ID, and
phlogenetic name fields and returns a similar dataframe with a column for
"exclude" taxa (TRUE or FALSE).

Exclude taxa are refered to by multiple names; ambiguous, non-distinct, and
non-unique. The "exclude" name was chosen so as to be consistent with
"non-target" taxa. That is, taxa marked as "TRUE" are treated as
undesireables.  Exclude taxa are those that are present in a sample when
taxa of the same group are present in the same sample are identified finer
level.  That is, the parent is marked as exclude when child taxa are
present in the same sample.
}
\details{
The exclude taxa are referenced in the metric values function.
These taxa are removed from the taxa richness metrics.  This is because these
are coarser level taxa when fine level taxa are present in the same sample.

Exceptions is a 2 column data frame of synonyms or other exceptions.
Column 1 is the name used in the TaxaID column the input data frame
(df_samptax). Column 2 is the name used in the TaxaLevels columns of the
input data frame (df_samptax).  The phylogenetic columns (TaxaLevels) will be
modified from Column 2 of the Exceptions data frame to match Column 1 of the
Exceptions data frame.  This ensures that the algorithm for markExcluded
works properly. The changes will not be stored and the original names
provided in the input data frame (df_samptax) will be returned in the final
result.  The function example below includes a practical case.

Taxa Levels are phylogenetic names that are to be checked.  They should be
listed in order from course (kingdom) to fine (species).  Names not appearing
in the data will be skipped.

The spelling of names must be consistent (including case) for this function
to produce the intended output.
}
\examples{

# Packages
library(readxl)
library(dplyr)
library(lazyeval)
library(knitr)

# Data
df_samps_bugs <- read_excel(system.file("./extdata/Data_Benthos.xlsx",
                                        package="BioMonTools"),
                            guess_max=10^6)

# Variables
SampID     <- "SampleID"
TaxaID     <- "TaxaID"
TaxaCount  <- "N_Taxa"
Exclude    <- "Exclude_New"
TaxaLevels <- c("Kingdom",
                "Phylum",
                "SubPhylum",
                "Class",
                "SubClass",
                "Order",
                "SubOrder",
                "SuperFamily",
                "Family",
                "SubFamily",
                "Tribe",
                "Genus",
                "SubGenus",
                "Species",
                "Variety")
# Taxa that should be treated as equivalent
Exceptions <- data.frame("TaxaID" = "Sphaeriidae",
                         "PhyloID" = "Pisidiidae")

# EXAMPLE 1
df_tst <- markExcluded(df_samps_bugs,
                       SampID = "SampleID",
                       TaxaID = "TaxaID",
                       TaxaCount = "N_Taxa",
                       Exclude = "Exclude_New",
                       TaxaLevels = TaxaLevels,
                       Exceptions = Exceptions)

# Compare
df_compare <- dplyr::summarise(dplyr::group_by(df_tst, SampleID),
                               Exclude_Import = sum(Exclude),
                               Exclude_R = sum(Exclude_New))
df_compare$Diff <- df_compare$Exclude_Import - df_compare$Exclude_R
#
tbl_diff <- table(df_compare$Diff)
kable(tbl_diff)
# sort
df_compare <- df_compare \%>\% arrange(desc(Diff))

# Number with issues
sum(abs(df_compare$Diff))
# total samples
nrow(df_compare)

# confusion matrix
tbl_results <- table(df_tst$Exclude, df_tst$Exclude_New, useNA = "ifany")
#
# Show differences
kable(tbl_results)
knitr::kable(df_compare[1:10, ])
knitr::kable(df_compare[672:678, ])
# samples with differences
samp_diff <- as.data.frame(df_compare[df_compare[,"Diff"] != 0, "SampleID"])
# results for only those with differences
df_tst_diff <- df_tst[df_tst[,"SampleID"] \%in\% samp_diff$SampleID, ]
# add diff field
df_tst_diff$Exclude_Diff <- df_tst_diff$Exclude - df_tst_diff$Exclude_New

# Classification Performance Metrics
class_TP <- tbl_results[2,2] # True Positive
class_FN <- tbl_results[2,1] # False Negative
class_FP <- tbl_results[1,2] # False Positive
class_TN <- tbl_results[1,1] # True Negative
class_n <- sum(tbl_results)  # total
#
# sensitivity (recall); TP / (TP+FN); measure model to ID true positives
class_sens <- class_TP / (class_TP + class_FN)
# precision; TP / (TP+FP); accuracy of model positives
class_prec <- class_TP / (class_TP + class_FP)
# specifity; TN / (TN + FP); measure model to ID true negatives
class_spec <- class_TN  / (class_TN + class_FP)
# overall accuracy; (TP + TN) / all cases; accuracy of all classifications
class_acc <- (class_TP + class_TN) / class_n
# F1; 2 * (class_prec*class_sens) / (class_prec+class_sens)
## balance of precision and recall
class_F1 <- 2 * (class_prec * class_sens) / (class_prec + class_sens)
#
results_names <- c("Sensitivity (Recall)",
                   "Precision",
                   "Specificity",
                   "Overall Accuracy",
                   "F1")
results_values <- c(class_sens,
                    class_prec,
                    class_spec,
                    class_acc,
                    class_F1)
#
tbl_class <- data.frame(results_names, results_values)
names(tbl_class) <- c("Performance Metrics", "Percent")
tbl_class$Percent <- round(tbl_class$Percent * 100, 2)
kable(tbl_class)

#~~~~~~~~~~~~~~~~~~~~~~~~~~

# EXAMPLE 2
## No Exceptions

df_tst2 <- markExcluded(df_samps_bugs,
                        SampID = "SampleID",
                        TaxaID = "TaxaID",
                        TaxaCount = "N_Taxa",
                        Exclude = "Exclude_New",
                        TaxaLevels = TaxaLevels,
                        Exceptions = NA)

# Compare
df_compare2 <- dplyr::summarise(dplyr::group_by(df_tst2, SampleID),
                                Exclude_Import = sum(Exclude),
                                Exclude_R = sum(Exclude_New))
df_compare2$Diff <- df_compare2$Exclude_Import - df_compare2$Exclude_R
#
tbl_diff2 <- table(df_compare2$Diff)
kable(tbl_diff2)
# sort
df_compare2 <- df_compare2 \%>\% arrange(desc(Diff))

# Number with issues
sum(abs(df_compare2$Diff))
# total samples
nrow(df_compare2)

# confusion matrix
tbl_results2 <- table(df_tst2$Exclude, df_tst2$Exclude_New, useNA = "ifany")
#
# Show differences
kable(tbl_results2)
knitr::kable(df_compare2[1:10, ])
knitr::kable(tail(df_compare2))
# samples with differences
(samp_diff2 <- as.data.frame(df_compare2[df_compare2[, "Diff"] != 0,
                                         "SampleID"]))
# results for only those with differences
df_tst_diff2 <- filter(df_tst2, SampleID \%in\% samp_diff2$SampleID)
# add diff field
df_tst_diff2$Exclude_Diff <- df_tst_diff2$Exclude - df_tst_diff2$Exclude_New

# Classification Performance Metrics
class_TP2 <- tbl_results2[2,2] # True Positive
class_FN2 <- tbl_results2[2,1] # False Negative
class_FP2 <- tbl_results2[1,2] # False Positive
class_TN2 <- tbl_results2[1,1] # True Negative
class_n2 <- sum(tbl_results2)  # total
#
# sensitivity (recall); TP / (TP+FN); measure model to ID true positives
class_sens2 <- class_TP2 / (class_TP2 + class_FN2)
# precision; TP / (TP+FP); accuracy of model positives
class_prec2 <- class_TP2 / (class_TP2 + class_FP2)
# specifity; TN / (TN + FP); measure model to ID true negatives
class_spec2 <- class_TN2 / (class_TN2 + class_FP2)
# overall accuracy; (TP + TN) / all cases; accuracy of all classifications
class_acc2 <- (class_TP2 + class_TN2) / class_n2
# F1; 2 * (class_prec*class_sens) / (class_prec+class_sens)
## balance of precision and recall
class_F12 <- 2 * (class_prec2 * class_sens2) / (class_prec2 + class_sens2)
#
results_names2 <- c("Sensitivity (Recall)",
                    "Precision",
                    "Specificity",
                    "Overall Accuracy",
                    "F1")
results_values2 <- c(class_sens2,
                     class_prec2,
                     class_spec2,
                     class_acc2,
                     class_F12)
#
tbl_class2 <- data.frame(results_names2, results_values2)
names(tbl_class2) <- c("Performance Metrics", "Percent")
tbl_class2$Percent <- round(tbl_class2$Percent * 100, 2)
kable(tbl_class2)
}
