Nothing
# Author: Robert J. Hijmans
# Date : December 2009
# Version 0.1
# Licence GPL v3
RMSE <- function(obs, prd, na.rm=FALSE) {
sqrt(mean((obs - prd)^2, na.rm=na.rm))
}
RMSE_null <- function(obs, prd, na.rm=FALSE) {
r <- RMSE(obs, prd, na.rm=na.rm)
null <- RMSE(obs, mean(obs))
(null - r) / null
}
.auctest <- function(p, a) {
w <- stats::wilcox.test(p, a)
pauc <- w$p.value
auc <- as.vector(w$statistic) / (length(a) * length(p))
cbind(auc, pauc)
}
setClass("paModelEvaluation",
representation (
presence = "vector",
absence = "vector",
confusion = "matrix",
stats = "data.frame",
tr_stats = "data.frame",
thresholds = "data.frame"
)
)
pa_evaluate <- function(p, a, model=NULL, x=NULL, tr, ...) {
if (!is.null(model)) {
if (is.null(x)) {
p <- predict(model, p, ...)
a <- predict(model, a, ...)
} else {
p <- terra::extract(x, p)
p <- predict(model, p, ...)
a <- terra::extract(x, a)
a <- predict(model, a, ...)
}
}
p <- as.numeric(stats::na.omit(p))
a <- as.numeric(stats::na.omit(a))
np <- length(p)
na <- length(a)
if (na == 0 | np == 0) {
stop("cannot evaluate a model without absence and presence data that are not NA")
}
if (missing(tr)) {
if (length(p) > 1000) {
tr <- as.vector(stats::quantile(p, 0:1000/1000))
} else {
tr <- p
}
if (length(a) > 1000) {
tr <- c(tr, as.vector(stats::quantile(a, 0:1000/1000)))
} else {
tr <- c(tr, a)
}
tr <- sort(unique( round(tr, 8)))
tr <- c( tr - 0.0001, tr[length(tr)] + c(0, 0.0001))
} else {
tr <- sort(as.vector(tr))
}
N <- na + np
xc <- methods::new("paModelEvaluation")
xc@presence = p
xc@absence = a
R <- sum(rank(c(p, a))[1:np]) - (np*(np+1)/2)
auc <- R / (as.numeric(na) * as.numeric(np))
cr <- try( stats::cor.test(c(p,a), c(rep(1, length(p)), rep(0, length(a))) ), silent=TRUE )
corc <- pcor <- NA
if (!inherits(cr, "try-error")) {
corc <- cr$estimate
pcor <- cr$p.value
}
res <- matrix(ncol=4, nrow=length(tr))
colnames(res) <- c("tp", "fp", "fn", "tn")
for (i in 1:length(tr)) {
res[i,1] <- length(p[p>=tr[i]]) # a true positives
res[i,2] <- length(a[a>=tr[i]]) # b false positives
res[i,3] <- length(p[p<tr[i]]) # c false negatives
res[i,4] <- length(a[a<tr[i]]) # d true negatives
}
xc@confusion = res
a = res[,1]
b = res[,2]
c = res[,3]
d = res[,4]
# after Fielding and Bell
np <- as.integer(np)
na <- as.integer(na)
prevalence = (a[1] + c[1]) / N
# overall diagnostic power
ODP = (b[1] + d[1]) / N
xc@stats <- data.frame(np, na, prevalence, auc, cor=corc, pcor, ODP)
rownames(xc@stats) <- NULL
# correct classification rate
CCR = (a + d) / N
# sensitivity, or true positive rate
TPR = a / (a + c)
# specificity, or true negative rate
TNR = d / (b + d)
# False positive rate
FPR = b / (b + d)
# False negative rate
FNR = c/(a + c)
PPP = a/(a + b)
NPP = d/(c + d)
# misclassification rate
MCR = (b + c)/N
# odds ratio
OR = (a*d)/(c*b)
prA = (a+d)/N
prY = (a+b)/N * (a+c)/N
prN = (c+d)/N * (b+d)/N
prE = prY + prN
kappa = (prA - prE) / (1-prE)
xc@tr_stats <- data.frame(treshold=tr, kappa, CCR, TPR, TNR, FPR, FNR, PPP, NPP, MCR, OR)
max_kappa <- tr[which.max(kappa)]
# maximum sum of the sensitivity (true positive rate) and specificity (true negative rate)
max_spec_sens <- tr[which.max(TPR + TNR)]
# no omission
no_omission <- tr[max(which(res[, "fn"] == 0))]
# Suggestions by Diego Nieto-Lugilde
# equal prevalence
equal_prevalence = tr[which.min(abs(tr - prevalence))]
# equal sensitivity and specificity
equal_sens_spec <- tr[which.min(abs(TPR - TNR))]
xc@thresholds <- data.frame(max_kappa, max_spec_sens, no_omission, equal_prevalence, equal_sens_spec)
return(xc)
}
setMethod ("show" , "paModelEvaluation",
function(object) {
cat("@stats\n")
print(round(object@stats, 3))
cat("\n")
cat("@thresholds\n")
print(round(object@thresholds, 3))
cat("\n")
cat("@tr_stats\n")
x <- rbind(head(object@tr_stats, 4), tail(object@tr_stats, 3))
x <- round(x, 2)
x[4, ] <- "..."
print(x)
}
)
setMethod ("show" , "paModelEvaluation",
function(object) {
cat("@stats\n")
print(round(object@stats, 3))
cat("\n")
cat("@thresholds\n")
print(round(object@thresholds, 3))
cat("\n")
cat("@tr_stats\n")
x <- rbind(head(object@tr_stats, 4), tail(object@tr_stats, 3))
x <- round(x, 2)
x[4, ] <- "..."
print(x)
}
)
setMethod("plot", signature(x="paModelEvaluation"),
function(x, y="ROC", col="red", ...) {
if (y == "boxplot") {
prediction <- c(x@presence, x@absence)
group <- c(rep("presence", length(x@presence)), rep("absence", length(x@absence)) )
boxplot(prediction~group, data=data.frame(prediction, group), ...)
} else if (y == "ROC") {
txt = paste("AUC=", round(x@stats$auc,3))
plot(x@tr_stats$FPR, x@tr_stats$TPR, xlim=c(0,1), ylim=c(0,1), xlab="False postive rate", ylab="True positive rate", col=col, main=txt, ...)
lines(x@tr_stats$FPR, x@tr_stats$TPR, col=col)
lines(rbind(c(0,0), c(1,1)), lwd=2, col="grey")
} else if (y == "density") {
pr <- density(x@presence)
ab <- density(x@absence, bw=pr$bw )
yl = c(min(ab$y, pr$y), max(ab$y, pr$y))
xl = c(min(x@tr_stats$treshold), max(x@tr_stats$treshold))
plot(ab, main="", ylab=paste("Density. Bandwidth=",round(pr$bw,5),paste=""), xlab="predicted value", xlim=xl, ylim=yl, lwd=2, lty=2, col="blue", ...)
lines(pr, col="red", lwd=2)
} else if (y %in% colnames(x@tr_stats)) {
dat <- x@tr_stats[, y]
#mx = x@tr_stats$treshold[which.max(dat)]
#mn = x@tr_stats$treshold[which.min(dat)]
plot(x@tr_stats$treshold, dat, xlab="threshold", ylab=y, ...)
lines(x@tr_stats$treshold, dat, col=col)
} else {
stop("invalid option")
}
}
)
if (!isGeneric("threshold")) {
setGeneric("threshold", function(x, ...)
standardGeneric("threshold"))
}
setMethod('threshold', signature(x='paModelEvaluation'),
function(x) {
x@thresholds
}
)
cm_evaluate <- function(cmat, stat="overall") {
stopifnot(stat %in% c("kappa", "overall", "class"))
n <- sum(cmat)
d <- diag(cmat)
if (stat == "kappa") {
# observed (true) cases per class
p <- rowSums(cmat) / n
# predicted cases per class
q <- colSums(cmat) / n
expAccuracy <- sum(p*q)
OA <- sum(d) / n
kappa <- (OA - expAccuracy) / (1 - expAccuracy)
return(kappa)
} else if (stat == "overall") {
OA <- sum(d) / n
return(OA)
} else if (stat == "class") {
rw <- d / rowSums(cmat)
cw <- d / colSums(cmat)
x <- rbind(rw, cw)
rownames(x) <- c("row-wise", "col-wise")
return(x)
}
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.