diff --git a/src/Knet.jl b/src/Knet.jl index 8e5115a3a..681c4d498 100644 --- a/src/Knet.jl +++ b/src/Knet.jl @@ -18,6 +18,7 @@ include("ops21/Ops21.jl") include("ops21_gpu/Ops21_gpu.jl") include("fileio_gpu/FileIO_gpu.jl") include("train20/Train20.jl") +include("metrics/Metrics.jl") # include("layers21/Layers21.jl") # See if we have a gpu at initialization: @@ -43,12 +44,15 @@ using Knet.KnetArrays #: KnetArray, gc, knetgc, ka, setseed, seed! using Knet.FileIO_gpu #: cpucopy, gpucopy using Knet.Ops20 #: RNN, accuracy, batchnorm, bce, bmm, bnmoments, bnparams, conv4, deconv4, dropout, elu, invx, logistic, logp, logsoftmax, logsumexp, mat, nll, pool, relu, rnnforw, rnninit, rnnparam, rnnparams, selu, sigm, softmax, unpool, zeroone using Knet.Train20 #: Adadelta, Adagrad, Adam, Momentum, Nesterov, Rmsprop, SGD, Sgd, adadelta, adadelta!, adagrad, adagrad!, adam, adam!, atype, bilinear, converge, converge!, gaussian, goldensection, hyperband, minibatch, momentum, momentum!, nesterov, nesterov!, optimizers, param, param0, progress, progress!, rmsprop, rmsprop!, sgd, sgd!, train!, training, update!, xavier, xavier_normal, xavier_uniform +using Knet.Metrics #: confusion_matrix, class_confusion, confusion_params, visualize, classification_report, condition_positive, condition_negative, predicted_positive, predicted_negative, correctly_classified, incorrectly_classified, sensitivity_score, specificity_score, precision_score, accuracy_score, balanced_accuracy_score, negative_predictive_value, false_negative_rate, false_positive_rate, false_discovery_rate, false_omission_rate, f1_score, prevalence_threshold, threat_score, fowlkes_mallows_index, informedness, matthews_correlation_coeff export @diff, Adadelta, Adagrad, Adam, AutoGrad, Knet, KnetArray, Momentum, Nesterov, Param, RNN, Rmsprop, SGD, Sgd, accuracy, adadelta, adadelta!, adagrad, adagrad!, adam, adam!, batchnorm, bce, bilinear, bmm, bnmoments, bnparams, cat1d, conv4, converge, converge!, cpucopy, deconv4, dropout, elu, gaussian, goldensection, gpu, gpucopy, grad, gradloss, hyperband, invx, ka, knetgc, logistic, logp, logsoftmax, logsumexp, mat, minibatch, momentum, momentum!, nesterov, nesterov!, nll, optimizers, param, param0, params, pool, progress, progress!, relu, rmsprop, rmsprop!, rnninit, rnnparam, rnnparams, selu, setseed, sgd, sgd!, sigm, softmax, train!, training, unpool, update!, value, xavier, xavier_normal, xavier_uniform, zeroone +#metrics +export confusion_matrix, class_confusion, visualize, classification_report, condition_positive, condition_negative, predicted_positive,predicted_negative, correctly_classified, incorrectly_classified, sensitivity_score, recall_score, specificity_score, precision_score, positive_predictive_value, accuracy_score, balanced_accuracy_score, negative_predictive_value, false_negative_rate, false_positive_rate, false_discovery_rate, false_omission_rate, f1_score, prevalence_threshold, threat_score, matthews_correlation_coeff, fowlkes_mallows_index, informedness, markedness, cohen_kappa_score, hamming_loss, jaccard_score, confusion_params + + # This is assumed by some old scripts: export rnnforw end # module - - diff --git a/src/metrics/Classification/Classification.jl b/src/metrics/Classification/Classification.jl new file mode 100644 index 000000000..9c3c3f26e --- /dev/null +++ b/src/metrics/Classification/Classification.jl @@ -0,0 +1,10 @@ +module Classification + +import Plots +import Statistics + +include("confusion_matrix.jl"); export confusion_params, confusion_matrix, class_confusion +include("metrics.jl"); export visualize +include("visualization.jl"); export classification_report, condition_positive, condition_negative, predicted_positive,predicted_negative, correctly_classified, incorrectly_classified, sensitivity_score, recall_score, specificity_score, precision_score, positive_predictive_value, accuracy_score, balanced_accuracy_score, negative_predictive_value, false_negative_rate, false_positive_rate, false_discovery_rate, false_omission_rate, f1_score, prevalence_threshold, threat_score, matthews_correlation_coeff, fowlkes_mallows_index, informedness, markedness, cohen_kappa_score, hamming_loss, jaccard_score, confusion_params + +end diff --git a/src/metrics/Classification/classification_metrics.jl b/src/metrics/Classification/classification_metrics.jl new file mode 100644 index 000000000..6f371c2a0 --- /dev/null +++ b/src/metrics/Classification/classification_metrics.jl @@ -0,0 +1,2109 @@ +export confusion_matrix, class_confusion, visualize, classification_report, condition_positive, condition_negative, predicted_positive,predicted_negative, correctly_classified, incorrectly_classified, sensitivity_score, recall_score, specificity_score, precision_score, positive_predictive_value, accuracy_score, balanced_accuracy_score, negative_predictive_value, false_negative_rate, false_positive_rate, false_discovery_rate, false_omission_rate, f1_score, prevalence_threshold, threat_score, matthews_correlation_coeff, fowlkes_mallows_index, informedness, markedness, cohen_kappa_score, hamming_loss, jaccard_score, confusion_params + +using Plots: heatmap +using Statistics: mean + +""" + confusion_params(matrix::Array{Number,2}) + +Return the true positives, true negatives, false positives, false negatives arrays +from the given n x n matrix. If the provided matrix is not n x n, an assertion +exception: "Given matrix is not n x n" will be raised. As a visualization for the inner +calculation of the function, [this page](https://devopedia.org/images/article/208/6541.1566280388.jpg) may be visited + +""" +function confusion_params(matrix::Array{Number,2}) + @assert size(matrix)[1] == size(matrix)[2] "Given matrix is not n x n " + tp = []; tn = []; fp = []; fn = [] + matrix_sum = sum(matrix) + @inbounds for i in 1:size(matrix)[1] + push!(tp, matrix[i,i]) + push!(fn, sum(matrix[i,:]) - tp[i] ) + push!(fp, sum(matrix[:,i]) -tp[i]) + push!(tn, (matrix_sum - tp[i] - fn[i] - fp[i])) + end + return tp, tn, fp, fn +end + +function check_index(x, none_accepted; class_name = nothing, ith_class = nothing) + if !none_accepted; @assert class_name != nothing || ith_class != nothing "No class name or class indexing value provided"; end + if none_accepted && class_name == nothing == ith_class + return -1 + elseif class_name != nothing + @assert class_name in x "There is no such class in the labels of the given confusion matrix" + index = findfirst(x -> x == class_name, x) + return index + else + @assert ith_class >= 0 && ith_class <= length(x) "ith_class value is not in range" + return ith_class + end +end + +function clear_output(x, zero_division) + if true in [isnan(i) || isinf(i) for i in x] + if zero_division == "warn" || zero_division == "0" + if zero_division == "warn"; @warn "Zero division, replacing NaN or Inf with 0"; end; + if length(x) > 1 + return replace(x, NaN => 0) + else + return 0 + end + else + if length(x) > 1 + return replace(x, NaN => 1) + else + return 1 + end + end + else return x + end +end + +""" +A struct for representing confusion matrix and related computations + +## Fields +**`true_positives`** : An array that contains the true positive values of each label. For binary case, +`true_positives` is a single value. For multiclass, ith element in the array corresponds to the +`true_positives` of the ith class in the labels list. + +**`true_negatives`** : An array that contains the true negative values of each label. For binary case, +`true_negatives` is a single value. For multiclass, ith element in the array corresponds to the +`true_negatives` of the ith class in the labels list. + +**`false_positives`** : An array that contains the false positive values of each label. For binary case, +`false_positives` is a single value. For multiclass, ith element in the array corresponds to the +`false_positives` of the ith class in the labels list. + +**false_negatives** : An array that contains the false negative values of each label. For binary case, +`false_negatives` is a single value. For multiclass, ith element in the array corresponds to the +`false_negatives` of the ith class in the labels list. + +**`matrix`** : an n x n matrix where n is the length of labels. It represents the actual confusion matrix +from which true positives, true negatives, false positives and false negatives are calculated. + +**`Labels`** : an array representing the labels which are used for printing and visualization purposes + +**`zero division`** : + \n\t"warn" => all NaN and Inf values are replaced with zeros and user is warned by @warn macro in the + \tprocess + + \t"0" => all NaN and Inf values are replaced with zeros but the user is not warned by @warn macro in the + \tprocess + + \t"1" => all NaN and Inf values are replaced with ones but the user is not warned by @warn macro in the + \tprocess + + +""" + +struct confusion_matrix + true_positives::Array{Int} + true_negatives::Array{Int} + false_positives::Array{Int} + false_negatives::Array{Int} + matrix::Array{Number,2} + Labels::Array{Union{Int,AbstractString}} + zero_division::String +end + +""" +## Constructors + +```confusion_matrix(expected::Array{T,1}, predicted::Array{T,1}; ) where T <: Union{Int, String}``` + +Return a confusion matrix object constructed by the expected and predicted arrays. Expected and predicted arrays +must be of size (n,1) or or vector type. Lengths of the expected and predicted arrays must be equal; thus, +there should be a prediction and a ground truth for each classification. + +## Keywords + + \n**`labels`** : vector-like of shape (n,1), default = nothing + \nList of labels to index the matrix. If nothing is given, those that appear at least once + in expected or predicted are used in sorted order. + + \n**`normalize`** : boolean, default = nothing + \nDetermines whether or not the confusion matrix (matrix field of the produced confusion matrix) will be normalized. + + \n**`sample_weight`** : Number, default = nothing + \nSample weights which will be filled in the matrix before confusion params function is called + + \n**`zero_division`** : "warn", "0", "1", default = "warn" + \n_See:_ confusion matrix fields + +## Example +\n +```julia-repl +julia> y_true = [1,1,1,2,3,3,1,2,1,1,2,1]; + +julia> y_pred = [1,3,2,1,2,3,1,1,2,3,2,1]; + +julia> x = confusion_matrix(y_true, y_pred) +\n┌ Warning: No labels provided, constructing a label set by union of the unique elements in Expected +and Predicted arrays\n + + 1 2 3 + _____________________ + 3 2 2 │1 + 2 1 0 │2 Predicted + 0 1 1 │3 + + +julia> y_true = ["emirhan", "knet", "metrics", "confusion", "knet", "confusion", "emirhan", "metrics", "confusion"]; + +julia> y_pred = ["knet", "knet", "confusion", "confusion", "knet", "emirhan", "emirhan", "knet", "confusion"]; + +julia> x = confusion_matrix(y_true, y_pred, labels = ["emirhan", "knet", "confusion", "metrics"]) + +Expected + +emirhan knet confusion metrics +____________________________________________________________ +1 1 0 0 │emirhan +0 2 0 0 │knet +1 0 2 0 │confusion Predicted +0 1 1 0 │metrics + +``` +## References + [1] [Wikipedia entry for the Confusion matrix] + (https://en.wikipedia.org/wiki/Confusion_matrix) + (Note: Wikipedia and other references may use a different + convention for axes) + +_See: confusion params function_ \n +_Source:_ [script](https://github.com/emirhan422/KnetMetrics/blob/main/src/metrics/classification_metrics.jl) + +""" +function confusion_matrix(expected::Array{T,1}, predicted::Array{T,1}; labels = nothing, normalize = false, sample_weight = 0, zero_division = "warn") where T <: Union{Int, String} + @assert length(expected) == length(predicted) "Sizes of the expected and predicted values do not match" + @assert eltype(expected) <: Union{Int, String} && eltype(predicted) <: Union{Int, String} "Expected and Predicted arrays must either be integers or strings" + @assert eltype(expected) == eltype(predicted) "Element types of Expected and Predicted arrays do not match" + if labels != nothing; @assert length(labels) != 0 "Labels array must contain at least one value"; end; + @assert zero_division in ["warn", "0", "1"] "Unknown zero division behaviour specification" + if labels == nothing + @warn "No labels provided, constructing a label set by union of the unique elements in Expected and Predicted arrays" + labels = union(unique(expected),unique(predicted)) + if eltype(labels) == Int + sort!(labels) + end + end + dictionary = Dict() + for i in 1:length(labels) + dictionary[labels[i]] = i + end + matrix = zeros(Number, length(labels), length(labels)) + if sample_weight != 0 + fill!(matrix, sample_weight) + end + @inbounds for i in 1:length(expected) + matrix[dictionary[expected[i]],dictionary[predicted[i]]] += 1 + end + tp, tn, fp, fn = confusion_params(matrix) + if 0 in tp + @warn "There are elements of value 0 in the true positives array. This may lead to false values for some functions" + end + if 0 in tn + @warn "There are elements of value 0 in the true negatives array. This may lead to false values for some functions" + end + if 0 in fp + @warn "There are elements of value 0 in the false positives array. This may lead to false values for some functions" + end + if 0 in fn + @warn "There are elements of value 0 in the false negatives array. This may lead to false values for some functions" + end + if normalize + matrix = [round(i, digits = 3) for i in LinearAlgebra.normalize(matrix)] + end + return confusion_matrix(tp,tn,fp,fn,matrix,labels, zero_division) +end + +""" +```class_confusion(c::confusion_matrix; class_name = nothing, ith_class = nothing)``` + +\nReturn a binary confusion matrix for the class denoted by `class_name` or `ith_class` arguments. + +## Keywords + +**`ith_class`** : Int, default = nothing +\n\tReturn the binary confusion matrix of the ith class in the Labels array. This will be ignored if class_name is not `nothing` +**`class_name`** : Int, String, default = nothing +\n\tReturn the binary confusion matrix of the class of given value if exists in the Labels array. + +## Example +\n +```julia-repl +julia> y_true = [1,1,1,2,3,3,1,2,1,1,2,1]; + +julia> y_pred = [1,3,2,1,2,3,1,1,2,3,2,1]; + +julia> x = confusion_matrix(y_true, y_pred) +\n┌ Warning: No labels provided, constructing a label set by union of the unique elements in Expected +and Predicted arrays + +julia> class_confusion(x, ith_class = 2) +2×2 Array{Int64,2}: + 1 3 + 2 6 + +julia> class_confusion(x, class_name = 2) +2×2 Array{Int64,2}: + 1 3 + 2 6 +``` +""" +function class_confusion(c::confusion_matrix; class_name = nothing, ith_class = nothing) + index = check_index(c.Labels, false ,class_name = class_name, ith_class = ith_class) + return [c.true_positives[index] c.false_positives[index]; c.false_negatives[index] c.true_negatives[index]] +end + +""" +```visualize(c::confusion_matrix)``` + +Visualize the matrix of the given confusion matrix object by heatmap function of the Plots library. +""" +function visualize(c::confusion_matrix) + converted_labels = [] + for i in c.Labels + push!(converted_labels, string(i)) + end + heatmap(converted_labels, converted_labels, c.matrix, c = :dense) +end + +function Base.show(io::IO, ::MIME"text/plain", c::confusion_matrix) + printer = Int(round(size(c.matrix)[1] / 2)) +1 + label_len = maximum([length(string(i)) for i in c.Labels])[1] + 6 + label_size = length(c.Labels) + println(io, lpad("Expected\n", printer* label_len )) + println(io, [lpad(i,label_len) for i in c.Labels]...) + println(io, repeat("_", length(c.Labels) * label_len)) + for i in 1:size(c.matrix)[1] + println(io, [lpad(string(i),label_len) for i in c.matrix[i,:]]..., " │", c.Labels[i], i == printer ? "\tPredicted" : " ") + end +end + +""" +```classification_report(c::confusion_matrix;)``` + +Return all the values listed below if `return_dict` is true. Else, write the values to the given IO element. + +Returned dictionary: +``` + "true-positives" => c.true_positives + "false-positives" => c.false_positives + "true-negatives" => c.true_negatives + "false-negatives" => c.false_negatives + "condition-positive" => condition_positive(c) + "condition-negative" => condition_negative(c) + "predicted-positive" => predicted_positive(c) + "predicted-negative" => predicted_negative(c) + "correctly-classified" => correctly_classified(c) + "incorrectly-classified" => incorrectly_classified(c) + "sensitivity" => sensitivity_score(c) + "specificity" => specificity_score(c) + "precision" => precision_score(c) + "accuracy-score" => accuracy_score(c) + "balanced Accuracy" => balanced_accuracy(c) + "positive-predictive-value" => positive_predictive_value(c) + "negative-predictive-value" => negative_predictive_value(c) + "false-negative-rate" => false_negative_rate(c) + "false-positive-rate" => false_positive_rate(c) + "false-discovery-rate" => false_discovery_rate(c) + "false-omission-rate" => false_omission_rate(c) + "f1-score" => f1_score(c) + "prevalence-threshold" => prevalence_threshold(c) + "threat-score" => threat_score(c) + "matthews-correlation-coefficient" => matthews_correlation_coeff(c) + "fowlkes-mallows-index" => fowlkes_mallows_index(c) + "informedness" => informedness(c) + "markedness" => markedness(c) + "jaccard-score-nonaverage" => jaccard_score(c, average = nothing) + "jaccard-score-microaverage" => jaccard_score(c, average = "micro") + "hamming-loss" => hamming_loss(c) + "cohen-kappa-score" => cohen_kappa_score(c) +``` + +For a sample output to the given IO element, see Example section. + +## Keywords + + \n**`io`** : ::IO, default = Base.stdout + \n\tIO element to write to + + \n**`return_dict`** : default = false + \n\tReturn a dictionary as specified below if true; print the values specified below if false + + \n**`target_names`** : vector-like, default = nothing + \n\tIf not nothing, replace the labels of the given confusion matrix object whilst printing + + \n**`digits`** : Int, default = 2 + \n\tDetermines how the rounding procedure will be digitized. If `return_dict` is true, this will be ignored and the values + will be placed into the dictionary with full precision + +## Example + +```julia-repl + +julia> y_true = [1,1,1,2,3,3,1,2,1,1,2,1]; + +julia> y_pred = [1,3,2,1,2,3,1,1,2,3,2,1]; + +julia> x = confusion_matrix(y_true, y_pred) +┌ Warning: No labels provided, constructing a label set by union of the unique elements in Expected and Predicted arrays +└ @ Path +julia> classification_report(x) +Summary: +confusion_matrix +True Positives: [3, 1, 1] +False Positives: [2, 3, 2] +True Negatives: [3, 6, 8] +False Negatives: [4, 2, 1] + +Labelwise Statistics + + 1 2 3 + Condition Positive: 7.0 3.0 2.0 + Condition Negative: 5.0 9.0 10.0 + Predicted Positive: 5.0 4.0 3.0 + Predicted Negative: 7.0 8.0 9.0 + Correctly Classified: 6.0 7.0 9.0 + Incorrectly Classified: 6.0 5.0 3.0 + Sensitivity: 0.43 0.33 0.5 + Specificity: 0.6 0.67 0.8 + Precision: 0.6 0.25 0.33 + Accuracy Score: 0.5 0.58 0.75 + Balanced Accuracy: 0.51 0.5 0.65 + Negative Predictive Value: 0.43 0.75 0.89 + False Negative Rate: 0.57 0.67 0.5 + False Positive Rate: 0.4 0.33 0.2 + False Discovery Rate: 0.4 0.33 0.2 + False Omission Rate: 0.57 0.25 0.11 + F1 Score: 0.5 0.29 0.4 + Jaccard Score: 0.33 0.17 0.25 +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Main Path + Prevalence Threshold:16.73 Inf 1.05 + Threat Score: 0.33 0.17 0.25 +Matthews Correlation Coefficient 0.03 0.0 0.26 + Fowlkes Mallows Index: 0.51 0.29 0.41 + Informedness: 0.03 0.0 0.3 + Markedness:-0.74-0.81 -0.7 + +General Statistics + + Accuracy Score: 0.1527777777777778 + Cohen Kappa Score: 0.07692307692307698 + Hamming Loss: 0.5833333333333334 + Jaccard Score: 0.2631578947368421 +``` +""" +function classification_report(c::confusion_matrix; io::IO = Base.stdout, return_dict = false, target_names = nothing, digits = 2) + if return_dict + result_dict = Dict() + result_dict["true-positives"] = c.true_positives + result_dict["false-positives"] = c.false_positives + result_dict["true-negatives"] = c.true_negatives + result_dict["false-negatives"] = c.false_negatives + result_dict["condition-positive"] = condition_positive(c) + result_dict["condition-negative"] = condition_negative(c) + result_dict["predicted-positive"] = predicted_positive(c) + result_dict["predicted-negative"] = predicted_negative(c) + result_dict["correctly-classified"] = correctly_classified(c) + result_dict["incorrectly-classified"] = incorrectly_classified(c) + result_dict["sensitivity"] = sensitivity_score(c) + result_dict["specificity"] = specificity_score(c) + result_dict["precision"] = precision_score(c) + result_dict["accuracy-score"] = accuracy_score(c) + result_dict["balanced Accuracy"] = balanced_accuracy(c) + result_dict["positive-predictive-value"] = positive_predictive_value(c) + result_dict["negative-predictive-value"] = negative_predictive_value(c) + result_dict["false-negative-rate"] = false_negative_rate(c) + result_dict["false-positive-rate"] = false_positive_rate(c) + result_dict["false-discovery-rate"] = false_discovery_rate(c) + result_dict["false-omission-rate"] = false_omission_rate(c ) + result_dict["f1-score"] = f1_score(c) + result_dict["prevalence-threshold"] = prevalence_threshold(c) + result_dict["threat-score"] = threat_score(c) + result_dict["matthews-correlation-coefficient"] = matthews_correlation_coeff(c) + result_dict["fowlkes-mallows-index"] = fowlkes_mallows_index(c) + result_dict["informedness"] = informedness(c) + result_dict["markedness"] = markedness(c) + result_dict["jaccard-score-nonaverage"] = jaccard_score(c, average = nothing) + result_dict["jaccard-score-microaverage"] = jaccard_score(c, average = "micro") + result_dict["hamming-loss"] = jaccard_score(c) + result_dict["cohen-kappa-score"] = cohen_kappa_score(c) + return result_dict + else + labels = target_names != nothing && length(target_names) == length(c.Labels) ? target_names : c.Labels + len = maximum([length(string(i)) for i in labels]) + label_size = length(c.Labels) + label_len = len + digits + 2 + println(io,"Summary:\n", summary(c)) + println(io,"True Positives: ", c.true_positives) + println(io,"False Positives: ", c.false_positives) + println(io,"True Negatives: ", c.true_negatives) + println(io,"False Negatives: ", c.false_negatives) + println(io,"\n",lpad("Labelwise Statistics", label_len * Int(round(size(c.matrix)[1] / 2)+1)), "\n") + println(io,lpad(" ", 30), [lpad(i, label_len) for i in labels]...) + println(io,lpad("Condition Positive:", 30), [lpad(round(i, digits = digits), label_len) for i in condition_positive(c)]...) + println(io,lpad("Condition Negative:", 30), [lpad(round(i, digits = digits), label_len) for i in condition_negative(c)]...) + println(io,lpad("Predicted Positive:", 30), [lpad(round(i, digits = digits), label_len) for i in predicted_positive(c)]...) + println(io,lpad("Predicted Negative:", 30), [lpad(round(i, digits = digits), label_len) for i in predicted_negative(c)]...) + println(io,lpad("Correctly Classified:", 30), [lpad(round(i, digits = digits), label_len) for i in correctly_classified(c)]...) + println(io,lpad("Incorrectly Classified:", 30), [lpad(round(i, digits = digits), label_len) for i in incorrectly_classified(c)]...) + println(io,lpad("Sensitivity:", 30), [lpad(round(i, digits = digits), label_len) for i in sensitivity_score(c)]...) + println(io,lpad("Specificity:", 30), [lpad(round(i, digits = digits), label_len) for i in specificity_score(c)]...) + println(io,lpad("Precision:", 30) , [lpad(round(i, digits = digits), label_len) for i in precision_score(c)]...) + println(io,lpad("Accuracy Score:", 30 ) , [lpad(round(accuracy_score(c, ith_class = i), digits = digits), label_len) for i in 1:label_size]...) + println(io,lpad("Balanced Accuracy:", 30), [lpad(round(i, digits = digits), label_len) for i in balanced_accuracy(c)]...) + println(io,lpad("Negative Predictive Value:", 30), [lpad(round(i, digits = digits), label_len) for i in negative_predictive_value(c)]...) + println(io,lpad("False Negative Rate:", 30), [lpad(round(i, digits = digits), label_len) for i in false_negative_rate(c)]...) + println(io,lpad("False Positive Rate:", 30), [lpad(round(i, digits = digits), label_len) for i in false_positive_rate(c)]...) + println(io,lpad("False Discovery Rate:", 30), [lpad(round(i, digits = digits), label_len) for i in false_discovery_rate(c)]...) + println(io,lpad("False Omission Rate:", 30), [lpad(round(i, digits = digits), label_len) for i in false_omission_rate(c)]...) + println(io,lpad("F1 Score:", 30), [lpad(round(i, digits = digits), label_len) for i in f1_score(c)]...) + println(io,lpad("Jaccard Score:", 30), [lpad(round(i, digits = digits), label_len) for i in jaccard_score(c, average = nothing)]...) + println(io,lpad("Prevalence Threshold:", 30), [lpad(round(i, digits = digits), label_len) for i in prevalence_threshold(c)]...) + println(io,lpad("Threat Score:", 30), [lpad(round(i, digits = digits), label_len) for i in threat_score(c)]...) + println(io,lpad("Matthews Correlation Coefficient", 30), [lpad(round(i, digits = digits), label_len) for i in matthews_correlation_coeff(c)]...) + println(io,lpad("Fowlkes Mallows Index:", 30), [lpad(round(i, digits = digits), label_len) for i in fowlkes_mallows_index(c)]...) + println(io,lpad("Informedness:", 30), [lpad(round(i, digits = digits), label_len) for i in informedness(c)]...) + println(io,lpad("Markedness:", 30), [lpad(round(i, digits = digits), label_len) for i in markedness(c)]...) + println(io,"\n",lpad("General Statistics", label_len * Int(round(size(c.matrix)[1] / 2)+1)), "\n") + println(io, lpad("Accuracy Score:\t",30), accuracy_score(c)) + println(io, lpad("Cohen Kappa Score:\t", 30), cohen_kappa_score(c)) + println(io, lpad("Hamming Loss:\t", 30), hamming_loss(c)) + println(io, lpad("Jaccard Score:\t", 30), jaccard_score(c, average = "micro")) + end +end + +""" +```condition_positive(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return condition positive values of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + Condition Positives: True Positives + False Negatives + +## Keyowrds + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return condition positive values for all the elements in the labels arrays + +## Example + +First example no indexing:\n\n + +```julia-repl +julia> y_true = ["sample", "knet", "metrics", "function", "knet", "knet","function"]; + +julia> y_pred = ["sample", "knet", "sample", "function", "knet", "knet","knet"]; + +julia> x = confusion_matrix(y_true, y_pred); + +julia> condition_positive(x) +4-element Array{Int64,1}: + 1 + 3 + 1 + 2 + +``` + +Second example value of a specific class:\n\n + +```julia-repl +julia> y_true = ["sample", "knet", "metrics", "function", "knet", "knet","function"]; + +julia> y_pred = ["sample", "knet", "sample", "function", "knet", "knet","knet"]; + +julia> x = confusion_matrix(y_true, y_pred); + +julia> condition_positive(x, class_name = "knet") +3 + +``` +_See also_ : `confusion_matrix`, `condition_negative`, `predicted_positive`, `predicted_negative` + +""" +function condition_positive(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.true_positives + c.false_negatives + return clear_output(x,c.zero_division) + else + x = c.true_positives[index] + c.false_negatives[index] + return clear_output(x,c.zero_division) + end +end + +""" +```condition_negative(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return condition negative values of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + Condition Negatives: True Negatives + False Positives + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return condition negative values for all the elements in the labels arrays + +## Example + +First example no indexing:\n\n + +```julia-repl +julia> y_pred = [1,2,3,1,4,2,1,2,3,4,1,2,3,4,1,2,2,2,3,1]; + +julia> y_true = [1,2,1,1,4,2,4,2,2,4,1,2,3,2,1,2,2,2,1,1]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [1,2,3,4]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> condition_negative(x) +4-element Array{Int64,1}: + 14 + 13 + 16 + 17 + +``` + +Second example value of a specific class:\n\n + +```julia-repl +julia> y_pred = [1,2,3,1,4,2,1,2,3,4,1,2,3,4,1,2,2,2,3,1]; + +julia> y_true = [1,2,1,1,4,2,4,2,2,4,1,2,3,2,1,2,2,2,1,1]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [1,2,3,4]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> condition_negative(x, class_name = 3) +16 + +``` + +_See also_ : `confusion_matrix`, `condition_positive`, `predicted_positive`, `predicted_negative` + +""" +function condition_negative(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.true_negatives + c.false_positives + return clear_output(x,c.zero_division) + else + x = c.true_negatives[index] + c.false_positives[index] + return clear_output(x,c.zero_division) + end +end + +""" +```predicted_positive(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return predicted positive values of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + Predicted Positives: True Positives + False Positives + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return predicted positive values for all the elements in the labels arrays + +## Example + +First example no indexing:\n\n + +```julia-repl +julia> y_pred = [2, 3, 4, 2, 5, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 3, 3, 4, 2]; + +julia> y_true = [2, 3, 2, 2, 5, 3, 5, 3, 3, 5, 2, 3, 4, 3, 2, 3, 3, 3, 2, 2]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [2,3,4,5]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> predicted_positive(x) +4-element Array{Int64,1}: + 7 + 9 + 1 + 3 + +``` + +Second example value of a specific class:\n\n + +```julia-repl +julia> y_pred = [2, 3, 4, 2, 5, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 3, 3, 4, 2]; + +julia> y_true = [2, 3, 2, 2, 5, 3, 5, 3, 3, 5, 2, 3, 4, 3, 2, 3, 3, 3, 2, 2]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [2,3,4,5]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> predicted_positive(x, class_name = 3) +9 +``` + +_See also_ : `confusion_matrix`, `condition_negative`, `predicted_positive`, `predicted_negative` + +""" +function predicted_positive(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.true_positives + c.false_positives + return clear_output(x,c.zero_division) + else + x = c.true_positives[index] + c.false_positives[index] + return clear_output(x,c.zero_division) + end +end + +""" +```predicted_negative(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return predicted negative values of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + Predicted Negatives: Negatives + False Negatives + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return predicted negative values for all the elements in the labels arrays + +## Example + +First example no indexing:\n\n + +```julia-repl +julia> y_pred = [2, 3, 4, 2, 5, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 3, 3, 4, 2]; + +julia> y_true = [2, 3, 2, 2, 5, 3, 5, 3, 3, 5, 2, 3, 4, 3, 2, 3, 3, 3, 2, 2]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [2,3,4,5]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> predicted_negative(x) +4-element Array{Int64,1}: + 13 + 11 + 19 + 17 + +``` + +Second example value of a specific class:\n\n + +```julia-repl +julia> y_pred = [2, 3, 4, 2, 5, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 3, 3, 4, 2]; + +julia> y_true = [2, 3, 2, 2, 5, 3, 5, 3, 3, 5, 2, 3, 4, 3, 2, 3, 3, 3, 2, 2]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [2,3,4,5]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> predicted_negative(x, class_name = 4) +19 + +``` +_See also_ : `confusion_matrix`, `condition_negative`, `predicted_positive`, `condition_positive` + +""" +function predicted_negative(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.true_negatives + c.false_negatives + return clear_output(x,c.zero_division) + else + x = c.true_negatives[index] + c.false_negatives[index] + return clear_output(x,c.zero_division) + end +end + +""" +```correctly_classified(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return number of correctly classified instances of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + Correctly Classified Values: True Positives + True Negatives + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return number of correctly classified instances for all the elements in the labels arrays + +## Example + +First example no indexing:\n\n + +```julia-repl +julia> y_pred = [2, 3, 4, 2, 5, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 3, 3, 4, 2]; + +julia> y_true = [2, 3, 2, 2, 5, 3, 5, 3, 3, 5, 2, 3, 4, 3, 2, 3, 3, 3, 2, 2]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [2,3,4,5]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> correctly_classified(x) +4-element Array{Int64,1}: + 17 + 18 + 17 + 18 + +``` + +Second example value of a specific class:\n\n + +```julia-repl +julia> y_pred = [2, 3, 4, 2, 5, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 3, 3, 4, 2]; + +julia> y_true = [2, 3, 2, 2, 5, 3, 5, 3, 3, 5, 2, 3, 4, 3, 2, 3, 3, 3, 2, 2]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [2,3,4,5]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> correctly_classified(x, ith_class = 1) +17 +``` + +_See also_ : `confusion_matrix`, `predicted_negative`, `predicted_positive`, `incorrectly_classified` + +""" +function correctly_classified(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.true_positives + c.true_negatives + return clear_output(x,c.zero_division) + else + x = c.true_positives[index] + c.true_negatives[index] + return clear_output(x,c.zero_division) + end +end + +""" +```incorrectly_classified(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return number of incorrectly classified instances of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + Inorrectly Classified: False Negatives + False Positives + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return number of incorrectly classified instances for all the elements in the labels arrays + +## Example + +First example no indexing:\n\n + +```julia-repl +julia> y_pred = [2, 3, 4, 2, 5, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 3, 3, 4, 2]; + +julia> y_true = [2, 3, 2, 2, 5, 3, 5, 3, 3, 5, 2, 3, 4, 3, 2, 3, 3, 3, 2, 2]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [2,3,4,5]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> incorrectly_classified(x) +4-element Array{Int64,1}: + 3 + 2 + 3 + 2 + +``` + +Second example value of a specific class:\n\n + +```julia-repl +julia> y_pred = [2, 3, 4, 2, 5, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 3, 3, 4, 2]; + +julia> y_true = [2, 3, 2, 2, 5, 3, 5, 3, 3, 5, 2, 3, 4, 3, 2, 3, 3, 3, 2, 2]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [2,3,4,5]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> incorrectly_classified(x, ith_class = 2) +2 + +``` + +_See also_ : `confusion_matrix`, `predicted_negative`, `predicted_positive`, `correctly_classified` + +""" +function incorrectly_classified(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.false_positives + c.false_negatives + return clear_output(x,c.zero_division) + else + x = c.false_positives[index] + c.false_negatives[index] + return clear_output(x,c.zero_division) + end +end + +""" +```sensitivity_score(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return sensitivity (recall) score of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + The sensitivity (recall) is the ratio ``tp / (tp + fn)`` where ``tp`` is the number of + true positives and ``fn`` the number of false negatives. The recall is + intuitively the ability of the classifier to find all the positive samples. + The best value is 1 and the worst value is 0. + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return sensitivity(recall) score for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> sensitivity_score(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +5-element Array{Float64,1}: + 0.2 + 0.5 + 1.0 + 0.0 + 0.0 + +julia> sensitivity_score(x, class_name = 1) +0.2 +``` + +_See also_ : `confusion_matrix` , `recall_score` , `balanced_accuracy_score`, `specificity_score` +""" +function sensitivity_score(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.true_positives ./ condition_positive(c) + return clear_output(x, c.zero_division) + else + x = c.true_positives[index] / condition_positive(c, ith_class = index) + return clear_output(x, c.zero_division) + end +end + +""" +```recall_score(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return recall(sensitivity) score of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + The recall (sensitivity) is the ratio ``tp / (tp + fn)`` where ``tp`` is the number of + true positives and ``fn`` the number of false negatives. The recall is + intuitively the ability of the classifier to find all the positive samples. + The best value is 1 and the worst value is 0. + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return recall (sensitivity) score for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> recall_score(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +5-element Array{Float64,1}: + 0.2 + 0.5 + 1.0 + 0.0 + 0.0 + +julia> recall_score(x, class_name = 1) +0.2 +``` + +_See also_ : `confusion_matrix` , `sensitivity_score` , `balanced_accuracy_score`, `specificity_score` + +""" +function recall_score(c::confusion_matrix; ith_class = nothing, class_name = nothing) + return sensitivity_score(c, ith_class = ith_class, class_name = class_name) +end + + +""" +```specificity_score(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return specificity score of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + The specificity is the ratio ``tn / (tn + fp)`` where ``tn`` is the number of + true negatives and ``fp`` the number of false positives. The specificity is + intuitively the ability of the classifier to find all the negative samples. + The best value is 1 and the worst value is 0. + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return specificity score for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> specificity(x) +5-element Array{Float64,1}: + 0.6 + 1.0 + 0.7777777777777778 + 0.7 + 1.0 + +julia> specificity(x,ith_class = 2) +1.0 +``` + +_See also_ : ```confusion_matrix```, ```sensitivity_score```, ```balanced_accuracy_score```,```recall_score``` + +""" +function specificity_score(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.true_negatives ./ condition_negative(c) + return clear_output(x, c.zero_division) + else + x = c.true_negatives[index] / condition_negative(c, ith_class = index) + return clear_output(x, c.zero_division) + end +end + + +""" +```precision_score(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return precision score of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + The precision is the ratio ``tp / (tp + fp)`` where ``tp`` is the number of + true positives and ``fp`` the number of false positives. The precision is + intuitively the ability of the classifier not to label as positive a sample + that is negative. + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return precision score for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> precision_score(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Main Path +5-element Array{Float64,1}: + 0.3333333333333333 + 1.0 + 0.3333333333333333 + 0.0 + 0.0 + +julia> precision_score(x, class_name = 3) +0.3333333333333333 + +``` + +_See also_ : ```confusion_matrix```, ```sensitivity_score```, ```balanced_accuracy_score```,```recall_score``` + +""" +function precision_score(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.true_positives ./ (c.true_positives + c.false_positives) + return clear_output(x, c.zero_division) + else + x = c.true_positives[index] / (c.true_positives[index] + c.false_positives[index]) + return clear_output(x,c.zero_division) + end +end + +""" +```positive_predictive_value(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return score of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + The positive predictive value is the ratio ``tp / (tp + fp)`` where ``tp`` is the number of + true positives and ``fp`` the number of false positives. The positive predictive value is + intuitively the ability of the classifier not to label as positive a sample + that is negative. + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return positive predictive value for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> positive_predictive_value(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Main Path +5-element Array{Float64,1}: + 0.3333333333333333 + 1.0 + 0.3333333333333333 + 0.0 + 0.0 + +julia> positive_predictive_value(x, ith_class = 3) +0.3333333333333333 + +``` + +_See also_ : ```negative_predictive_value```, ```confusion_matrix```, ```sensitivity_score```, ```balanced_accuracy_score```,```recall_score``` + +""" +function positive_predictive_value(c::confusion_matrix; ith_class = nothing, class_name = nothing) + return precision_score(c, class_name = class_name, ith_class = ith_class) +end + +""" +```accuracy_score(c::confusion_matrix; ith_class = nothing, class_name = nothing, normalize = true, sample_weight = nothing) ``` + +Return accuracy classification score. + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +**`normalize`** : bool, default= true + If ``False``, return the number of correctly classified samples. + Otherwise, return the fraction of correctly classified samples. + +**`sample_weight`** : array-like of shape (n_samples,), default=None + Sample weights. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return positive predictive value for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> accuracy_score(x) +0.36 + +julia> accuracy_score(x, normalize = false) +3.5999999999999996 + +``` + +_See also_ : ```jaccard_score``` ```confusion_matrix```, ```hamming_loss```, ```balanced_accuracy_score```,```recall_score``` + + +""" +function accuracy_score(c::confusion_matrix; ith_class = nothing, class_name = nothing, normalize = true, sample_weight = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + accuracy_array = [accuracy_score(c, ith_class = i) for i in 1:length(c.true_positives)] + if normalize + x = sample_weight == nothing ? (sum(accuracy_array) / sum(c.matrix)) : (sum(accuracy_array .* sample_weight) / sum(c.matrix)) + return clear_output(x,c.zero_division) + else + x = sample_weight == nothing ? sum(accuracy_array) : dot(accuracy_array, sample_weight) + return clear_output(x,c.zero_division) + end + else + if normalize + x = (c.true_positives[index] + c.true_negatives[index] ) / (condition_positive(c, ith_class = index) + condition_negative(c, ith_class = index)) + return clear_output(x, c.zero_division) + else + x = (c.true_positives[index]) + return clear_output(x, c.zero_division) + end + end +end + +""" +```balanced_accuracy_score(c::confusion_matrix; ith_class = nothing, class_name = nothing) ``` + +Return balanced accuracy classification score. + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return balanced accuracy score for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> balanced_accuracy_score(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +5-element Array{Float64,1}: + 0.4 + 0.75 + 0.8888888888888888 + 0.35 + 0.5 + +julia> balanced_accuracy_score(x, ith_class = 3) +0.8888888888888888 + +``` + +_See also_ : ```accuracy_score``` ```confusion_matrix```, ```hamming_loss```, ```balanced_accuracy_score```,```recall_score``` + +[1] Brodersen, K.H.; Ong, C.S.; Stephan, K.E.; Buhmann, J.M. (2010). + The balanced accuracy and its posterior distribution. + Proceedings of the 20th International Conference on Pattern + Recognition, 3121-24. +[2] John. D. Kelleher, Brian Mac Namee, Aoife D'Arcy, (2015). + `Fundamentals of Machine Learning for Predictive Data Analytics: + Algorithms, Worked Examples, and Case Studies + [link](https://mitpress.mit.edu/books/fundamentals-machine-learning-predictive-data-analytics) + +""" +function balanced_accuracy_score(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [(sensitivity_score(c, ith_class = i) + specificity_score(c, ith_class = i)) / 2 for i in 1:length(c.true_positives)] + return clear_output(x,c.zero_division) + else + x = (sensitivity_score(c,ith_class = index) + specificity_score(c, ith_class = index)) / 2 + return clear_output(x,c.zero_division) + end +end + +""" + +```negative_predictive_value(c::confusion_matrix; ith_class = nothing, class_name = nothing) ``` + +Return negative predictive value for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return negative predictive value for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> negative_predictive_value(x) +5-element Array{Float64,1}: + 0.42857142857142855 + 0.8888888888888888 + 1.0 + 1.0 + 0.8 + + julia> negative_predictive_value(x, class_name = 1) + 0.42857142857142855 +``` + +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```positive_predictive_value```, ```balanced_accuracy_score``` + +""" +function negative_predictive_value(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [c.true_negatives[i] / (c.true_negatives[i] + c.false_negatives[i]) for i in 1:length(c.true_positives)] + return clear_output(x,c.zero_division) + else + x = c.true_negatives[index] / (c.true_negatives[index] + c.false_negatives[index]) + return clear_output(x,c.zero_division) + end +end + +""" + +```false_negative_rate(c::confusion_matrix; ith_class = nothing, class_name = nothing) ``` + +Return false negative rate for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return false negative rate for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> false_negative_rate(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +5-element Array{Float64,1}: + 0.8 + 0.5 + 0.0 + 0.0 + 1.0 + + julia> false_negative_rate(x, ith_class = 3) + 0.0 + ``` + + _See Also_ : ```confusion_matrix```, ```false_positive_rate```, ```positive_predictive_value```, ```balanced_accuracy_score``` + +""" +function false_negative_rate(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [c.false_negatives[i] / condition_positive(c,ith_class = i) for i in 1:length(c.true_positives)] + return clear_output(x,c.zero_division) + else + x = c.false_negatives[index] / condition_positive(c,ith_class = index) + return clear_output(x,c.zero_division) + end +end + +""" + +```false_positive_rate(c::confusion_matrix; ith_class = nothing, class_name = nothing) ``` + +Return false positive rate for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return false positive rate for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> false_positive_rate(x) +5-element Array{Float64,1}: + 0.4 + 0.0 + 0.2222222222222222 + 0.3 + 0.0 + + julia> false_positive_rate(x, ith_class = 3) + 0.2222222222222222 + ``` + + _See Also_ : ```confusion_matrix```, ```false_negative_rate```, ```positive_predictive_value```, ```balanced_accuracy_score``` +""" +function false_positive_rate(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [c.false_positives[i] / condition_negative(c,ith_class = i) for i in 1:length(c.true_positives)] + return clear_output(x,c.zero_division) + else + x = c.false_positives[index] / condition_negative(c,ith_class = index) + return clear_output(x,c.zero_division) + end +end + +""" + +```false_discovery_rate(c::confusion_matrix; ith_class = nothing, class_name = nothing) ``` + +Return false discovery rate for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return false discovery rate for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> false_discovery_rate(x) +5-element Array{Float64,1}: + 0.4 + 0.0 + 0.2222222222222222 + 0.3 + 0.0 + +julia> false_discovery_rate(x, ith_class = 3) +0.2222222222222222 + +``` +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```positive_predictive_value```, ```false_omission_rate``` + +""" +function false_discovery_rate(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [c.false_positives[i] / ( c.false_positives[i] + c.true_negatives[i]) for i in 1:length(c.true_positives)] + return clear_output(x,c.zero_division) + else + x = c.false_positives[index] / ( c.false_positives[index] + c.true_negatives[index]) + return clear_output(x,c.zero_division) + end +end + +""" +```false_omission_rate(c::confusion_matrix; ith_class = nothing, class_name = nothing) ``` + +Return false omission rate for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return false omission rate for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> false_omission_rate(x) +5-element Array{Float64,1}: + 0.5714285714285714 + 0.11111111111111116 + 0.0 + 0.0 + 0.19999999999999996 + +julia> false_omission_rate(x, ith_class = 5) +0.19999999999999996 +``` + +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```positive_predictive_value```, ```false_discovery_rate``` +""" +function false_omission_rate(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [1 - negative_predictive_value(c,ith_class = i) for i in 1:length(c.true_positives)] + return clear_output(x,c.zero_division) + else + x = 1 - negative_predictive_value(c,ith_class = index) + return clear_output(x,c.zero_division) + end +end + +""" +```f1_score(c::confusion_matrix; ith_class = nothing, class_name = nothing) ``` + +Return f1 score for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return f1 score for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> f1_score(x) +5-element Array{Float64,1}: + 0.25 + 0.6666666666666666 + 0.5 + 0.0 + 0.0 + +julia> f1_score(x, class_name = 2) +0.6666666666666666 +``` + +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```recall_score```, ```false_omission_rate``` + +""" +function f1_score(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [(2* c.true_positives[i] ) / (2* c.true_positives[i] + c.false_positives[i] + c.false_negatives[i]) for i in 1:length(c.true_positives)] + return clear_output(x,c.zero_division) + else + x = (2* c.true_positives[index] ) / (2* c.true_positives[index] + c.false_positives[index] + c.false_negatives[index]) + return clear_output(x,c.zero_division) + end +end + +""" + +```prevalence_threshold(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return prevalence threshold for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return prevalence threshold for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> prevalence_threshold(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +5-element Array{Float64,1}: + -2.828427124746191 + 0.0 + 0.0 + -1.8257418583505536 + 0.0 + +julia> prevalence_threshold(x, ith_class = 1) +-2.828427124746191 +``` + +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```recall_score```, ```f1_score``` + +""" +function prevalence_threshold(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [(sqrt(abs(sensitivity_score(c,ith_class = i) * (-specificity_score(c,ith_class = i) +1) + specificity_score(c,ith_class = i) -1)) / (sensitivity_score(c,ith_class = i) + specificity_score(c,ith_class = i) -1)) for i in 1:length(c.true_positives)] + return clear_output(x,c.zero_division) + else + x = (sqrt(abs(sensitivity_score(c,ith_class = index) * (-specificity_score(c,ith_class = index) +1) + specificity_score(c,ith_class = index) -1)) / (sensitivity_score(c,ith_class = index) + specificity_score(c,ith_class = index) -1)) + return clear_output(x,c.zero_division) + end +end + +""" + +```threat_score(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return threat score for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return threat score for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> threat_score(x) +5-element Array{Float64,1}: + 0.14285714285714285 + 0.5 + 0.3333333333333333 + 0.0 + 0.0 + +julia> threat_score(x, ith_class = 3) +0.3333333333333333 + +``` +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```recall_score```, ```f1_score``` + +""" +function threat_score(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [c.true_positives[i] / (c.true_positives[i] + c.false_negatives[i] + c.false_positives[i]) for i in 1:length(c.true_positives)] + return clear_output(x,c.zero_division) + else + x = c.true_positives[index] / (c.true_positives[index] + c.false_negatives[index] + c.false_positives[index]) + return clear_output(x,c.zero_division) + end +end + +""" + +```matthews_correlation_coeff(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return Matthew's Correlation Coefficient for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return Matthew's Correlation Coefficient for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> matthews_correlation_coeff(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +5-element Array{Float64,1}: + -0.2182178902359924 + 0.6666666666666666 + 0.5091750772173156 + 0.0 + 0.0 + +julia> matthews_correlation_coeff(x, ith_class = 3) +0.5091750772173156 + +``` + +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```threat_score```, ```f1_score``` + +""" +function matthews_correlation_coeff(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [(c.true_positives[i] * c.true_negatives[i] - c.false_positives[i] * c.false_negatives[i]) / sqrt( abs((c.true_positives[i] + c.false_positives[i]) * (c.true_positives[i] + c.false_negatives[i]) * + (c.true_negatives[i] + c.false_positives[i]) * (c.true_negatives[i] + c.false_negatives[i]))) + for i in 1:length(c.true_positives)] + return clear_output(x,c.zero_division) + else + x = (c.true_positives[index] * c.true_negatives[index] - c.false_positives[index] * c.false_negatives[index]) / sqrt( (c.true_positives[index] + c.false_positives[index]) * (c.true_positives[index] + c.false_negatives[index]) * + (c.true_negatives[index] + c.false_positives[index]) * (c.true_negatives[index] + c.false_negatives[index])) + return clear_output(x,c.zero_division) + end +end + +""" + +```fowlkes_mallows_index(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return Fowlkes Mallows Index for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return Fowlkes Mallows Index for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> fowlkes_mallows_index(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Main Path +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Main Path +5-element Array{Float64,1}: + 0.2581988897471611 + 0.7071067811865476 + 0.5773502691896257 + 0.0 + 0.0 + +julia> fowlkes_mallows_index(x, ith_class = 2) +0.7071067811865476 + +``` + +_See Also_ : ```confusion_matrix```, ```matthews_correlation_coeff```, ```threat_score```, ```f1_score``` +""" +function fowlkes_mallows_index(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [sqrt(positive_predictive_value(c,ith_class = i) * sensitivity_score(c,ith_class = i)) for i in 1:length(c.true_positives)] + return clear_output(x,c.zero_division) + else + x = sqrt(positive_predictive_value(c,ith_class = index) * sensitivity_score(c,ith_class = index)) + return clear_output(x,c.zero_division) + end +end + +""" + +```informedness(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return informedness value for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return informedness value for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> informedness(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +5-element Array{Float64,1}: + -0.19999999999999996 + 0.5 + 0.7777777777777777 + -0.30000000000000004 + 0.0 + +julia> informedness(x,ith_class = 3) +0.7777777777777777 + +``` + +_See Also_ : ```confusion_matrix```, ```matthews_correlation_coeff```, ```markedness```, ```f1_score``` +""" +function informedness(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [ ( specificity_score(c,ith_class = i) + sensitivity_score(c,ith_class = i) -1) for i in 1:length(c.true_positives)] + return clear_output(x,c.zero_division) + else + x = specificity_score(c,ith_class = index) + sensitivity_score(c,ith_class = index) -1 + return clear_output(x,c.zero_division) + end +end + +""" + +```markedness(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return markedness value for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return markedness value for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> markedness(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +5-element Array{Float64,1}: + -0.8571428571428572 + -0.11111111111111116 + -0.6666666666666667 + -1.0 + -1.0 + +julia> markedness(x, ith_class = 1) +-0.19999999999999996 + +``` + +_See Also_ : ```confusion_matrix```, ```matthews_correlation_coeff```, ```informedness```, ```f1_score``` + +""" +function markedness(c::confusion_matrix; ith_class = nothing, class_name = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [( precision_score(c,ith_class = i) * negative_predictive_value(c,ith_class = i) -1) for i in 1:length(c.true_positives)] + return clear_output(x,c.zero_division) + else + x = specificity_score(c,ith_class = index) + sensitivity_score(c,ith_class = index) -1 + return clear_output(x,c.zero_division) + end +end + +""" +```cohen_kappa_score(c::confusion_matrix; weights = nothing) ``` + +Return Cohen's Kappa (a statistic that measures inter-annotator agreement) + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> cohen_kappa_score(x) +0.125 +``` + +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```jaccard_score```, ```f1_score``` + +""" +function cohen_kappa_score(c::confusion_matrix; weights = nothing) +#reference: scikitlearn.metrics.classification.cohen_kappa_score + @assert weights in [nothing, "quadratic", "linear"] "Unknown kappa weighting type" + w_mat = nothing + sum0 = sum(c.matrix, dims = 1) + sum1 = sum(c.matrix, dims = 2) + expected = (sum1 * sum0) ./ sum(sum0) + if weights == nothing + w_mat = ones(length(c.Labels),length(c.Labels)) + for i in 1:length(c.Labels) + w_mat[i,i] = 0 + end + else + w_mat = zeros(length(c.Labels),length(c.Labels)) + w_mat += [i for i in 1:length(c.Labels)] + if weights == "linear" + w_mat = abs(w_mat - transpose(w_mat)) + else + w_mat = (w_mat - transpose(w_mat)) ^2 + end + end + x = sum(w_mat .* c.matrix) / sum(w_mat .* expected) + return clear_output(1- x,c.zero_division) +end + +""" + +```hamming_loss(c::confusion_matrix) ``` + +Compute the average Hamming loss. + The Hamming loss is the fraction of labels that are incorrectly predicted. + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> hamming_loss(x) +0.7 +``` + +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```jaccard_score```, ```f1_score``` + +""" +function hamming_loss(c::confusion_matrix;) + x = zeros(sum(c.matrix)) + x[1] = sum(c.false_negatives) + return clear_output(mean(x), c.zero_division) +end + +""" + +```jaccard_score(c::confusion_matrix; average = "binary", sample_weight = nothing) ``` + +Compute Jaccard similarity coefficient score + The Jaccard index [1], or Jaccard similarity coefficient, defined as + the size of the intersection divided by the size of the union of two label + sets, is used to compare set of predicted labels for a sample to the + corresponding set of labels in ``y_true``. + +## Keywords + +average : string [None, 'binary' (default), 'micro', 'macro', 'samples, 'weighted'] + If ``None``, the scores for each class are returned. Otherwise, this + determines the type of averaging performed on the data: + ``binary``: + Only report results for the class specified by ``pos_label``. + ``micro``: + Calculate metrics globally by counting the total true positives, + false negatives and false positives. + ``macro``: + Calculate metrics for each label, and find their unweighted + mean. This does not take label imbalance into account. + ``weighted``: + Calculate metrics for each label, and find their average, weighted + by support (the number of true instances for each label). This + alters 'macro' to account for label imbalance. + ``samples``: + Calculate metrics for each instance, and find their average (only + meaningful for multilabel classification). +sample_weight : array-like of shape (n_samples,), default=None + Sample weights. + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> hamming_loss(x) +0.7 +``` + +## References + +[1] [Wikipedia entry for the Jaccard index](https://en.wikipedia.org/wiki/Jaccard_index) + + +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```hamming_loss```, ```f1_score``` + +""" +function jaccard_score(c::confusion_matrix; average = "binary", sample_weight = nothing) + @assert average in [nothing, "binary", "weighted", "samples", "micro", "macro"] "Unknown averaging type" + if sample_weight != nothing @assert length(sample_weight) == length(c.true_positives) "Dimensions of given sample weight does not match the confusion matrix"; end + numerator = c.true_positives + denominator = c.true_positives + c.false_negatives + c.false_positives + if average == nothing + x = numerator ./ denominator + return clear_output(x, c.zero_division) + elseif average == "micro" + numerator = sum(numerator) + denominator = sum(denominator) + x = numerator ./ denominator + return clear_output(x, c.zero_division) + elseif average == "macro" + numerator = c.true_positives + denominator = c.true_positives + c.false_negatives + c.false_positives + x = numerator ./ denominator + return clear_output(mean(x), c.zero_division) + elseif average == "weighted" || average == "samples" + weights = nothing + if average == "weighted" + weights = c.false_negatives + c.true_positives + elseif average == "samples" + weights = sample_weight + end + score = numerator ./ denominator + x = [weights[i] * score[i] for i in 1:length(c.Labels)] + x / length(c.Labels) + return clear_output(x, c.zero_division) + else + x = [(c.false_negatives[i] + c.true_positives[i])/length(c.Labels) for i in 1:length(c.Labels)] + return clear_output(x, c.zero_division) + end +end diff --git a/src/metrics/Classification/confusion_matrix.jl b/src/metrics/Classification/confusion_matrix.jl new file mode 100644 index 000000000..8f4b5bb7c --- /dev/null +++ b/src/metrics/Classification/confusion_matrix.jl @@ -0,0 +1,269 @@ +export confusion_params, confusion_matrix, class_confusion + +#Confusion matrix related classes + +using LinearAlgebra + +""" + confusion_params(matrix::Array{Number,2}) + +Return the true positives, true negatives, false positives, false negatives arrays +from the given n x n matrix. If the provided matrix is not n x n, an assertion +exception: "Given matrix is not n x n" will be raised. As a visualization for the inner +calculation of the function, [this page](https://devopedia.org/images/article/208/6541.1566280388.jpg) may be visited + +""" +function confusion_params(matrix::Array{Number,2}) + @assert size(matrix)[1] == size(matrix)[2] "Given matrix is not n x n " + tp = []; tn = []; fp = []; fn = [] + matrix_sum = sum(matrix) + @inbounds for i in 1:size(matrix)[1] + push!(tp, matrix[i,i]) + push!(fn, sum(matrix[i,:]) - tp[i] ) + push!(fp, sum(matrix[:,i]) -tp[i]) + push!(tn, (matrix_sum - tp[i] - fn[i] - fp[i])) + end + return tp, tn, fp, fn +end + +function check_index(x, none_accepted; class_name = nothing, ith_class = nothing) + if !none_accepted; @assert class_name != nothing || ith_class != nothing "No class name or class indexing value provided"; end + if none_accepted && class_name == nothing == ith_class + return -1 + elseif class_name != nothing + @assert class_name in x "There is no such class in the labels of the given confusion matrix" + index = findfirst(x -> x == class_name, x) + return index + else + @assert ith_class >= 0 && ith_class <= length(x) "ith_class value is not in range" + return ith_class + end +end + +function clear_output(x, zero_division) + if true in [isnan(i) for i in x] + if zero_division == "warn" || zero_division == "0" + if zero_division == "warn"; @warn "Zero division, replacing NaN with 0"; end; + if length(x) > 1 + return replace(x, NaN => 0) + else + return 0 + end + else + if length(x) > 1 + return replace(x, NaN => 1) + else + return 1 + end + end + else return x + end +end + +""" +A struct for representing confusion matrix and related computations + +## Fields +**`true_positives`** : An array that contains the true positive values of each label. For binary case, +`true_positives` is a single value. For multiclass, ith element in the array corresponds to the +`true_positives` of the ith class in the labels list. + +**`true_negatives`** : An array that contains the true negative values of each label. For binary case, +`true_negatives` is a single value. For multiclass, ith element in the array corresponds to the +`true_negatives` of the ith class in the labels list. + +**`false_positives`** : An array that contains the false positive values of each label. For binary case, +`false_positives` is a single value. For multiclass, ith element in the array corresponds to the +`false_positives` of the ith class in the labels list. + +**false_negatives** : An array that contains the false negative values of each label. For binary case, +`false_negatives` is a single value. For multiclass, ith element in the array corresponds to the +`false_negatives` of the ith class in the labels list. + +**`matrix`** : an n x n matrix where n is the length of labels. It represents the actual confusion matrix +from which true positives, true negatives, false positives and false negatives are calculated. + +**`Labels`** : an array representing the labels which are used for printing and visualization purposes + +**`zero division`** : + \n\t"warn" => all NaN and Inf values are replaced with zeros and user is warned by @warn macro in the + \tprocess + + \t"0" => all NaN and Inf values are replaced with zeros but the user is not warned by @warn macro in the + \tprocess + + \t"1" => all NaN and Inf values are replaced with ones but the user is not warned by @warn macro in the + \tprocess + + +""" + +struct confusion_matrix + true_positives::Array{Int} + true_negatives::Array{Int} + false_positives::Array{Int} + false_negatives::Array{Int} + matrix::Array{Number,2} + Labels::Array{Union{Int,AbstractString}} + zero_division::String +end + +""" +## Constructors + +```confusion_matrix(expected::Array{T,1}, predicted::Array{T,1}; ) where T <: Union{Int, String}``` + +Return a confusion matrix object constructed by the expected and predicted arrays. Expected and predicted arrays +must be of size (n,1) or or vector type. Lengths of the expected and predicted arrays must be equal; thus, +there should be a prediction and a ground truth for each classification. + +## Keywords + + \n**`labels`** : vector-like of shape (n,1), default = nothing + \nList of labels to index the matrix. If nothing is given, those that appear at least once + in expected or predicted are used in sorted order. + + \n**`normalize`** : boolean, default = nothing + \nDetermines whether or not the confusion matrix (matrix field of the produced confusion matrix) will be normalized. + + \n**`sample_weight`** : Number, default = nothing + \nSample weights which will be filled in the matrix before confusion params function is called + + \n**`zero_division`** : "warn", "0", "1", default = "warn" + \n_See:_ confusion matrix fields + +## Example +\n +```julia-repl +julia> y_true = [1,1,1,2,3,3,1,2,1,1,2,1]; + +julia> y_pred = [1,3,2,1,2,3,1,1,2,3,2,1]; + +julia> x = confusion_matrix(y_true, y_pred) +\n┌ Warning: No labels provided, constructing a label set by union of the unique elements in Expected +and Predicted arrays\n + + 1 2 3 + _____________________ + 3 2 2 │1 + 2 1 0 │2 Predicted + 0 1 1 │3 + + +julia> y_true = ["emirhan", "knet", "metrics", "confusion", "knet", "confusion", "emirhan", "metrics", "confusion"]; + +julia> y_pred = ["knet", "knet", "confusion", "confusion", "knet", "emirhan", "emirhan", "knet", "confusion"]; + +julia> x = confusion_matrix(y_true, y_pred, labels = ["emirhan", "knet", "confusion", "metrics"]) + +Expected + +emirhan knet confusion metrics +____________________________________________________________ +1 1 0 0 │emirhan +0 2 0 0 │knet +1 0 2 0 │confusion Predicted +0 1 1 0 │metrics + +``` +## References + [1] [Wikipedia entry for the Confusion matrix] + (https://en.wikipedia.org/wiki/Confusion_matrix) + (Note: Wikipedia and other references may use a different + convention for axes) + +_See: confusion params function_ \n +""" +function confusion_matrix(expected::Array{T,1}, predicted::Array{T,1}; labels = nothing, normalize = false, sample_weight = 0, zero_division = "warn") where T <: Union{Int, String} + @assert length(expected) == length(predicted) "Sizes of the expected and predicted values do not match" + @assert eltype(expected) <: Union{Int, String} && eltype(predicted) <: Union{Int, String} "Expected and Predicted arrays must either be integers or strings" + @assert eltype(expected) == eltype(predicted) "Element types of Expected and Predicted arrays do not match" + if labels != nothing; @assert length(labels) != 0 "Labels array must contain at least one value"; end; + @assert zero_division in ["warn", "0", "1"] "Unknown zero division behaviour specification" + if labels == nothing + @warn "No labels provided, constructing a label set by union of the unique elements in Expected and Predicted arrays" + labels = union(unique(expected),unique(predicted)) + if eltype(labels) == Int + sort!(labels) + end + end + dictionary = Dict() + for i in 1:length(labels) + dictionary[labels[i]] = i + end + matrix = zeros(Number, length(labels), length(labels)) + if sample_weight != 0 + fill!(matrix, sample_weight) + end + @inbounds for i in 1:length(expected) + matrix[dictionary[expected[i]],dictionary[predicted[i]]] += 1 + end + tp, tn, fp, fn = confusion_params(matrix) + if 0 in tp + @warn "There are elements of value 0 in the true positives array. This may lead to false values for some functions" + end + if 0 in tn + @warn "There are elements of value 0 in the true negatives array. This may lead to false values for some functions" + end + if 0 in fp + @warn "There are elements of value 0 in the false positives array. This may lead to false values for some functions" + end + if 0 in fn + @warn "There are elements of value 0 in the false negatives array. This may lead to false values for some functions" + end + if normalize + matrix = [round(i, digits = 3) for i in LinearAlgebra.normalize(matrix)] + end + return confusion_matrix(tp,tn,fp,fn,matrix,labels, zero_division) +end + +""" +```class_confusion(c::confusion_matrix; class_name = nothing, ith_class = nothing)``` + +\nReturn a binary confusion matrix for the class denoted by `class_name` or `ith_class` arguments. + +## Keywords + +**`ith_class`** : Int, default = nothing +\n\tReturn the binary confusion matrix of the ith class in the Labels array. This will be ignored if class_name is not `nothing` +**`class_name`** : Int, String, default = nothing +\n\tReturn the binary confusion matrix of the class of given value if exists in the Labels array. + +## Example +\n +```julia-repl +julia> y_true = [1,1,1,2,3,3,1,2,1,1,2,1]; + +julia> y_pred = [1,3,2,1,2,3,1,1,2,3,2,1]; + +julia> x = confusion_matrix(y_true, y_pred) +\n┌ Warning: No labels provided, constructing a label set by union of the unique elements in Expected +and Predicted arrays + +julia> class_confusion(x, ith_class = 2) +2×2 Array{Int64,2}: + 1 3 + 2 6 + +julia> class_confusion(x, class_name = 2) +2×2 Array{Int64,2}: + 1 3 + 2 6 +``` +""" +function class_confusion(c::confusion_matrix; class_name = nothing, ith_class = nothing) + index = check_index(c.Labels, false ,class_name = class_name, ith_class = ith_class) + return [c.true_positives[index] c.false_positives[index]; c.false_negatives[index] c.true_negatives[index]] +end + +function Base.show(io::IO, ::MIME"text/plain", c::confusion_matrix) + printer = Int(round(size(c.matrix)[1] / 2)) +1 + label_len = maximum([length(string(i)) for i in c.Labels])[1] + 6 + label_size = length(c.Labels) + println(io, lpad("Expected\n", printer* label_len )) + println(io, [lpad(i,label_len) for i in c.Labels]...) + println(io, repeat("_", length(c.Labels) * label_len)) + for i in 1:size(c.matrix)[1] + println(io, [lpad(string(i),label_len) for i in c.matrix[i,:]]..., " │", c.Labels[i], i == printer ? "\tPredicted" : " ") + end +end diff --git a/src/metrics/Classification/metrics.jl b/src/metrics/Classification/metrics.jl new file mode 100644 index 000000000..6275b09c1 --- /dev/null +++ b/src/metrics/Classification/metrics.jl @@ -0,0 +1,1962 @@ +export classification_report, condition_positive, condition_negative, predicted_positive,predicted_negative, correctly_classified, incorrectly_classified, sensitivity_score, recall_score, specificity_score, precision_score, positive_predictive_value, accuracy_score, balanced_accuracy_score, negative_predictive_value, false_negative_rate, false_positive_rate, false_discovery_rate, false_omission_rate, f1_score, prevalence_threshold, threat_score, matthews_correlation_coeff, fowlkes_mallows_index, informedness, markedness, cohen_kappa_score, hamming_loss, jaccard_score, confusion_params + +using Statistics: mean + +""" +```classification_report(c::confusion_matrix;)``` + +Return all the values listed below if `return_dict` is true. Else, write the values to the given IO element. + +Returned dictionary: +``` + "true-positives" => c.true_positives + "false-positives" => c.false_positives + "true-negatives" => c.true_negatives + "false-negatives" => c.false_negatives + "condition-positive" => condition_positive(c) + "condition-negative" => condition_negative(c) + "predicted-positive" => predicted_positive(c) + "predicted-negative" => predicted_negative(c) + "correctly-classified" => correctly_classified(c) + "incorrectly-classified" => incorrectly_classified(c) + "sensitivity" => sensitivity_score(c) + "specificity" => specificity_score(c) + "precision" => precision_score(c) + "accuracy-score" => accuracy_score(c) + "balanced Accuracy" => balanced_accuracy(c) + "positive-predictive-value" => positive_predictive_value(c) + "negative-predictive-value" => negative_predictive_value(c) + "false-negative-rate" => false_negative_rate(c) + "false-positive-rate" => false_positive_rate(c) + "false-discovery-rate" => false_discovery_rate(c) + "false-omission-rate" => false_omission_rate(c) + "f1-score" => f1_score(c) + "prevalence-threshold" => prevalence_threshold(c) + "threat-score" => threat_score(c) + "matthews-correlation-coefficient" => matthews_correlation_coeff(c) + "fowlkes-mallows-index" => fowlkes_mallows_index(c) + "informedness" => informedness(c) + "markedness" => markedness(c) + "jaccard-score-nonaverage" => jaccard_score(c, average = nothing) + "jaccard-score-microaverage" => jaccard_score(c, average = "micro") + "hamming-loss" => hamming_loss(c) + "cohen-kappa-score" => cohen_kappa_score(c) +``` + +For a sample output to the given IO element, see Example section. + +## Keywords + + \n**`io`** : ::IO, default = Base.stdout + \n\tIO element to write to + + \n**`return_dict`** : default = false + \n\tReturn a dictionary as specified below if true; print the values specified below if false + + \n**`target_names`** : vector-like, default = nothing + \n\tIf not nothing, replace the labels of the given confusion matrix object whilst printing + + \n**`digits`** : Int, default = 2 + \n\tDetermines how the rounding procedure will be digitized. If `return_dict` is true, this will be ignored and the values + will be placed into the dictionary with full precision + +## Example + +```julia-repl + +julia> y_true = [1,1,1,2,3,3,1,2,1,1,2,1]; + +julia> y_pred = [1,3,2,1,2,3,1,1,2,3,2,1]; + +julia> x = confusion_matrix(y_true, y_pred) +┌ Warning: No labels provided, constructing a label set by union of the unique elements in Expected and Predicted arrays +└ @ Path +julia> classification_report(x) +Summary: +confusion_matrix +True Positives: [3, 1, 1] +False Positives: [2, 3, 2] +True Negatives: [3, 6, 8] +False Negatives: [4, 2, 1] + +Labelwise Statistics + + 1 2 3 + Condition Positive: 7.0 3.0 2.0 + Condition Negative: 5.0 9.0 10.0 + Predicted Positive: 5.0 4.0 3.0 + Predicted Negative: 7.0 8.0 9.0 + Correctly Classified: 6.0 7.0 9.0 + Incorrectly Classified: 6.0 5.0 3.0 + Sensitivity: 0.43 0.33 0.5 + Specificity: 0.6 0.67 0.8 + Precision: 0.6 0.25 0.33 + Accuracy Score: 0.5 0.58 0.75 + Balanced Accuracy: 0.51 0.5 0.65 + Negative Predictive Value: 0.43 0.75 0.89 + False Negative Rate: 0.57 0.67 0.5 + False Positive Rate: 0.4 0.33 0.2 + False Discovery Rate: 0.4 0.33 0.2 + False Omission Rate: 0.57 0.25 0.11 + F1 Score: 0.5 0.29 0.4 + Jaccard Score: 0.33 0.17 0.25 +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Main Path + Prevalence Threshold:16.73 Inf 1.05 + Threat Score: 0.33 0.17 0.25 +Matthews Correlation Coefficient 0.03 0.0 0.26 + Fowlkes Mallows Index: 0.51 0.29 0.41 + Informedness: 0.03 0.0 0.3 + Markedness:-0.74-0.81 -0.7 + +General Statistics + + Accuracy Score: 0.1527777777777778 + Cohen Kappa Score: 0.07692307692307698 + Hamming Loss: 0.5833333333333334 + Jaccard Score: 0.2631578947368421 +``` +""" +function classification_report(c::confusion_matrix; io::IO = Base.stdout, return_dict = false, target_names = nothing, digits = 2) + if return_dict + result_dict = Dict() + result_dict["true-positives"] = c.true_positives + result_dict["false-positives"] = c.false_positives + result_dict["true-negatives"] = c.true_negatives + result_dict["false-negatives"] = c.false_negatives + result_dict["condition-positive"] = condition_positive(c) + result_dict["condition-negative"] = condition_negative(c) + result_dict["predicted-positive"] = predicted_positive(c) + result_dict["predicted-negative"] = predicted_negative(c) + result_dict["correctly-classified"] = correctly_classified(c) + result_dict["incorrectly-classified"] = incorrectly_classified(c) + result_dict["sensitivity"] = sensitivity_score(c) + result_dict["specificity"] = specificity_score(c) + result_dict["precision"] = precision_score(c) + result_dict["accuracy-score"] = accuracy_score(c) + result_dict["balanced Accuracy"] = balanced_accuracy_score(c) + result_dict["positive-predictive-value"] = positive_predictive_value(c) + result_dict["negative-predictive-value"] = negative_predictive_value(c) + result_dict["false-negative-rate"] = false_negative_rate(c) + result_dict["false-positive-rate"] = false_positive_rate(c) + result_dict["false-discovery-rate"] = false_discovery_rate(c) + result_dict["false-omission-rate"] = false_omission_rate(c ) + result_dict["f1-score"] = f1_score(c) + result_dict["prevalence-threshold"] = prevalence_threshold(c) + result_dict["threat-score"] = threat_score(c) + result_dict["matthews-correlation-coefficient"] = matthews_correlation_coeff(c) + result_dict["fowlkes-mallows-index"] = fowlkes_mallows_index(c) + result_dict["informedness"] = informedness(c) + result_dict["markedness"] = markedness(c) + result_dict["jaccard-score-nonaverage"] = jaccard_score(c, average = nothing) + result_dict["jaccard-score-microaverage"] = jaccard_score(c, average = "micro") + result_dict["hamming-loss"] = jaccard_score(c) + result_dict["cohen-kappa-score"] = cohen_kappa_score(c) + return result_dict + else + labels = target_names != nothing && length(target_names) == length(c.Labels) ? target_names : c.Labels + len = maximum([length(string(i)) for i in labels]) + label_size = length(c.Labels) + label_len = len + digits + 2 + println(io,"Summary:\n", summary(c)) + println(io,"True Positives: ", c.true_positives) + println(io,"False Positives: ", c.false_positives) + println(io,"True Negatives: ", c.true_negatives) + println(io,"False Negatives: ", c.false_negatives) + println(io,"\n",lpad("Labelwise Statistics", label_len * Int(round(size(c.matrix)[1] / 2)+1)), "\n") + println(io,lpad(" ", 30), [lpad(i, label_len) for i in labels]...) + println(io,lpad("Condition Positive:", 30), [lpad(round(i, digits = digits), label_len) for i in condition_positive(c)]...) + println(io,lpad("Condition Negative:", 30), [lpad(round(i, digits = digits), label_len) for i in condition_negative(c)]...) + println(io,lpad("Predicted Positive:", 30), [lpad(round(i, digits = digits), label_len) for i in predicted_positive(c)]...) + println(io,lpad("Predicted Negative:", 30), [lpad(round(i, digits = digits), label_len) for i in predicted_negative(c)]...) + println(io,lpad("Correctly Classified:", 30), [lpad(round(i, digits = digits), label_len) for i in correctly_classified(c)]...) + println(io,lpad("Incorrectly Classified:", 30), [lpad(round(i, digits = digits), label_len) for i in incorrectly_classified(c)]...) + println(io,lpad("Sensitivity:", 30), [lpad(round(i, digits = digits), label_len) for i in sensitivity_score(c)]...) + println(io,lpad("Specificity:", 30), [lpad(round(i, digits = digits), label_len) for i in specificity_score(c)]...) + println(io,lpad("Precision:", 30) , [lpad(round(i, digits = digits), label_len) for i in precision_score(c)]...) + println(io,lpad("Accuracy Score:", 30 ) , [lpad(round(accuracy_score(c, ith_class = i), digits = digits), label_len) for i in 1:label_size]...) + println(io,lpad("Balanced Accuracy:", 30), [lpad(round(i, digits = digits), label_len) for i in balanced_accuracy_score(c)]...) + println(io,lpad("Negative Predictive Value:", 30), [lpad(round(i, digits = digits), label_len) for i in negative_predictive_value(c)]...) + println(io,lpad("False Negative Rate:", 30), [lpad(round(i, digits = digits), label_len) for i in false_negative_rate(c)]...) + println(io,lpad("False Positive Rate:", 30), [lpad(round(i, digits = digits), label_len) for i in false_positive_rate(c)]...) + println(io,lpad("False Discovery Rate:", 30), [lpad(round(i, digits = digits), label_len) for i in false_discovery_rate(c)]...) + println(io,lpad("False Omission Rate:", 30), [lpad(round(i, digits = digits), label_len) for i in false_omission_rate(c)]...) + println(io,lpad("F1 Score:", 30), [lpad(round(i, digits = digits), label_len) for i in f1_score(c)]...) + println(io,lpad("Jaccard Score:", 30), [lpad(round(i, digits = digits), label_len) for i in jaccard_score(c, average = nothing)]...) + println(io,lpad("Prevalence Threshold:", 30), [lpad(round(i, digits = digits), label_len) for i in prevalence_threshold(c)]...) + println(io,lpad("Threat Score:", 30), [lpad(round(i, digits = digits), label_len) for i in threat_score(c)]...) + println(io,lpad("Matthews Correlation Coefficient", 30), [lpad(round(i, digits = digits), label_len) for i in matthews_correlation_coeff(c)]...) + println(io,lpad("Fowlkes Mallows Index:", 30), [lpad(round(i, digits = digits), label_len) for i in fowlkes_mallows_index(c)]...) + println(io,lpad("Informedness:", 30), [lpad(round(i, digits = digits), label_len) for i in informedness(c)]...) + println(io,lpad("Markedness:", 30), [lpad(round(i, digits = digits), label_len) for i in markedness(c)]...) + println(io,"\n",lpad("General Statistics", label_len * Int(round(size(c.matrix)[1] / 2)+1)), "\n") + println(io, lpad("Accuracy Score:\t",30), accuracy_score(c)) + println(io, lpad("Cohen Kappa Score:\t", 30), cohen_kappa_score(c)) + println(io, lpad("Hamming Loss:\t", 30), hamming_loss(c)) + println(io, lpad("Jaccard Score:\t", 30), jaccard_score(c, average = "micro")) + end +end + +classification_report(expected, predicted; io::IO = Base.stdout, return_dict = false, target_names = nothing, digits = 2) = +classification_report(confusion_matrix(expected, predicted); io = Base.stdout, return_dict = false, target_names = nothing, digits = 2) + +## + +# Confusion Matrix Evaluation Functions + +""" +```condition_positive(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return condition positive values of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + Condition Positives: True Positives + False Negatives + +## Keyowrds + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return condition positive values for all the elements in the labels arrays + +## Example + +First example no indexing:\n\n + +```julia-repl +julia> y_true = ["sample", "knet", "metrics", "function", "knet", "knet","function"]; + +julia> y_pred = ["sample", "knet", "sample", "function", "knet", "knet","knet"]; + +julia> x = confusion_matrix(y_true, y_pred); + +julia> condition_positive(x) +4-element Array{Int64,1}: + 1 + 3 + 1 + 2 + +``` + +Second example value of a specific class:\n\n + +```julia-repl +julia> y_true = ["sample", "knet", "metrics", "function", "knet", "knet","function"]; + +julia> y_pred = ["sample", "knet", "sample", "function", "knet", "knet","knet"]; + +julia> x = confusion_matrix(y_true, y_pred); + +julia> condition_positive(x, class_name = "knet") +3 + +``` +_See also_ : `confusion_matrix`, `condition_negative`, `predicted_positive`, `predicted_negative` + +""" +function condition_positive(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.true_positives + c.false_negatives + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = c.true_positives[index] + c.false_negatives[index] + return clear_output(x,c.zero_division) + end +end + +condition_positive(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +condition_positive(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" +```condition_negative(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return condition negative values of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + Condition Negatives: True Negatives + False Positives + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return condition negative values for all the elements in the labels arrays + +## Example + +First example no indexing:\n\n + +```julia-repl +julia> y_pred = [1,2,3,1,4,2,1,2,3,4,1,2,3,4,1,2,2,2,3,1]; + +julia> y_true = [1,2,1,1,4,2,4,2,2,4,1,2,3,2,1,2,2,2,1,1]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [1,2,3,4]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> condition_negative(x) +4-element Array{Int64,1}: + 14 + 13 + 16 + 17 + +``` + +Second example value of a specific class:\n\n + +```julia-repl +julia> y_pred = [1,2,3,1,4,2,1,2,3,4,1,2,3,4,1,2,2,2,3,1]; + +julia> y_true = [1,2,1,1,4,2,4,2,2,4,1,2,3,2,1,2,2,2,1,1]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [1,2,3,4]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> condition_negative(x, class_name = 3) +16 + +``` + +_See also_ : `confusion_matrix`, `condition_positive`, `predicted_positive`, `predicted_negative` + +""" +function condition_negative(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.true_negatives + c.false_positives + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = c.true_negatives[index] + c.false_positives[index] + return clear_output(x,c.zero_division) + end +end + +condition_negative(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +condition_negative(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + + +""" +```predicted_positive(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return predicted positive values of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + Predicted Positives: True Positives + False Positives + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return predicted positive values for all the elements in the labels arrays + +## Example + +First example no indexing:\n\n + +```julia-repl +julia> y_pred = [2, 3, 4, 2, 5, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 3, 3, 4, 2]; + +julia> y_true = [2, 3, 2, 2, 5, 3, 5, 3, 3, 5, 2, 3, 4, 3, 2, 3, 3, 3, 2, 2]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [2,3,4,5]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> predicted_positive(x) +4-element Array{Int64,1}: + 7 + 9 + 1 + 3 + +``` + +Second example value of a specific class:\n\n + +```julia-repl +julia> y_pred = [2, 3, 4, 2, 5, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 3, 3, 4, 2]; + +julia> y_true = [2, 3, 2, 2, 5, 3, 5, 3, 3, 5, 2, 3, 4, 3, 2, 3, 3, 3, 2, 2]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [2,3,4,5]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> predicted_positive(x, class_name = 3) +9 +``` + +_See also_ : `confusion_matrix`, `condition_negative`, `predicted_positive`, `predicted_negative` + +""" +function predicted_positive(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.true_positives + c.false_positives + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = c.true_positives[index] + c.false_positives[index] + return clear_output(x,c.zero_division) + end +end + +predicted_positive(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +predicted_positive(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" +```predicted_negative(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return predicted negative values of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + Predicted Negatives: Negatives + False Negatives + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return predicted negative values for all the elements in the labels arrays + +## Example + +First example no indexing:\n\n + +```julia-repl +julia> y_pred = [2, 3, 4, 2, 5, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 3, 3, 4, 2]; + +julia> y_true = [2, 3, 2, 2, 5, 3, 5, 3, 3, 5, 2, 3, 4, 3, 2, 3, 3, 3, 2, 2]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [2,3,4,5]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> predicted_negative(x) +4-element Array{Int64,1}: + 13 + 11 + 19 + 17 + +``` + +Second example value of a specific class:\n\n + +```julia-repl +julia> y_pred = [2, 3, 4, 2, 5, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 3, 3, 4, 2]; + +julia> y_true = [2, 3, 2, 2, 5, 3, 5, 3, 3, 5, 2, 3, 4, 3, 2, 3, 3, 3, 2, 2]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [2,3,4,5]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> predicted_negative(x, class_name = 4) +19 + +``` +_See also_ : `confusion_matrix`, `condition_negative`, `predicted_positive`, `condition_positive` + +""" +function predicted_negative(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.true_negatives + c.false_negatives + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = c.true_negatives[index] + c.false_negatives[index] + return clear_output(x,c.zero_division) + end +end + +predicted_negative(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +predicted_negative(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" +```correctly_classified(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return number of correctly classified instances of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + Correctly Classified Values: True Positives + True Negatives + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return number of correctly classified instances for all the elements in the labels arrays + +## Example + +First example no indexing:\n\n + +```julia-repl +julia> y_pred = [2, 3, 4, 2, 5, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 3, 3, 4, 2]; + +julia> y_true = [2, 3, 2, 2, 5, 3, 5, 3, 3, 5, 2, 3, 4, 3, 2, 3, 3, 3, 2, 2]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [2,3,4,5]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> correctly_classified(x) +4-element Array{Int64,1}: + 17 + 18 + 17 + 18 + +``` + +Second example value of a specific class:\n\n + +```julia-repl +julia> y_pred = [2, 3, 4, 2, 5, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 3, 3, 4, 2]; + +julia> y_true = [2, 3, 2, 2, 5, 3, 5, 3, 3, 5, 2, 3, 4, 3, 2, 3, 3, 3, 2, 2]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [2,3,4,5]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> correctly_classified(x, ith_class = 1) +17 +``` + +_See also_ : `confusion_matrix`, `predicted_negative`, `predicted_positive`, `incorrectly_classified` + +""" +function correctly_classified(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.true_positives + c.true_negatives + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = c.true_positives[index] + c.true_negatives[index] + return clear_output(x,c.zero_division) + end +end + +correctly_classified(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +correctly_classified(confusion_matrix(expected,predicted); ith_class = ith_class, class_name = class_name, average = average) + +""" +```incorrectly_classified(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return number of incorrectly classified instances of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + Inorrectly Classified: False Negatives + False Positives + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return number of incorrectly classified instances for all the elements in the labels arrays + +## Example + +First example no indexing:\n\n + +```julia-repl +julia> y_pred = [2, 3, 4, 2, 5, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 3, 3, 4, 2]; + +julia> y_true = [2, 3, 2, 2, 5, 3, 5, 3, 3, 5, 2, 3, 4, 3, 2, 3, 3, 3, 2, 2]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [2,3,4,5]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> incorrectly_classified(x) +4-element Array{Int64,1}: + 3 + 2 + 3 + 2 + +``` + +Second example value of a specific class:\n\n + +```julia-repl +julia> y_pred = [2, 3, 4, 2, 5, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 3, 3, 4, 2]; + +julia> y_true = [2, 3, 2, 2, 5, 3, 5, 3, 3, 5, 2, 3, 4, 3, 2, 3, 3, 3, 2, 2]; + +julia> x = confusion_matrix(y_pred, y_true, labels = [2,3,4,5]); +┌ Warning: There are elements of value 0 in the false positives array. This may lead to false values for some functions +└ @ Path +┌ Warning: There are elements of value 0 in the false negatives array. This may lead to false values for some functions +└ @ Path + +julia> incorrectly_classified(x, ith_class = 2) +2 + +``` + +_See also_ : `confusion_matrix`, `predicted_negative`, `predicted_positive`, `correctly_classified` + +""" +function incorrectly_classified(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.false_positives + c.false_negatives + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = c.false_positives[index] + c.false_negatives[index] + return clear_output(x,c.zero_division) + end +end + +incorrectly_classified(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +incorrectly_classified(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" +```sensitivity_score(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return sensitivity (recall) score of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + The sensitivity (recall) is the ratio ``tp / (tp + fn)`` where ``tp`` is the number of + true positives and ``fn`` the number of false negatives. The recall is + intuitively the ability of the classifier to find all the positive samples. + The best value is 1 and the worst value is 0. + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return sensitivity(recall) score for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> sensitivity_score(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +5-element Array{Float64,1}: + 0.2 + 0.5 + 1.0 + 0.0 + 0.0 + +julia> sensitivity_score(x, class_name = 1) +0.2 +``` + +_See also_ : `confusion_matrix` , `recall_score` , `balanced_accuracy_score`, `specificity_score` +""" +function sensitivity_score(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.true_positives ./ condition_positive(c) + x = clear_output(x, c.zero_division) + return average == "binary" ? x : mean(x) + else + x = c.true_positives[index] / condition_positive(c, ith_class = index) + return clear_output(x, c.zero_division) + end +end + +sensitivity_score(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +sensitivity_score(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" +```recall_score(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return recall(sensitivity) score of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + The recall (sensitivity) is the ratio ``tp / (tp + fn)`` where ``tp`` is the number of + true positives and ``fn`` the number of false negatives. The recall is + intuitively the ability of the classifier to find all the positive samples. + The best value is 1 and the worst value is 0. + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return recall (sensitivity) score for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> recall_score(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +5-element Array{Float64,1}: + 0.2 + 0.5 + 1.0 + 0.0 + 0.0 + +julia> recall_score(x, class_name = 1) +0.2 +``` + +_See also_ : `confusion_matrix` , `sensitivity_score` , `balanced_accuracy_score`, `specificity_score` + +""" +function recall_score(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + return sensitivity_score(c, ith_class = ith_class, class_name = class_name, average = average) +end + +recall_score(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +recall_score(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" +```specificity_score(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return specificity score of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + The specificity is the ratio ``tn / (tn + fp)`` where ``tn`` is the number of + true negatives and ``fp`` the number of false positives. The specificity is + intuitively the ability of the classifier to find all the negative samples. + The best value is 1 and the worst value is 0. + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return specificity score for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> specificity(x) +5-element Array{Float64,1}: + 0.6 + 1.0 + 0.7777777777777778 + 0.7 + 1.0 + +julia> specificity(x,ith_class = 2) +1.0 +``` + +_See also_ : ```confusion_matrix```, ```sensitivity_score```, ```balanced_accuracy_score```,```recall_score``` + +""" +function specificity_score(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.true_negatives ./ condition_negative(c) + x = clear_output(x, c.zero_division) + return average == "binary" ? x : mean(x) + else + x = c.true_negatives[index] / condition_negative(c, ith_class = index) + return clear_output(x, c.zero_division) + end +end + +specificity_score(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +specificity_score(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" +```precision_score(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return precision score of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + The precision is the ratio ``tp / (tp + fp)`` where ``tp`` is the number of + true positives and ``fp`` the number of false positives. The precision is + intuitively the ability of the classifier not to label as positive a sample + that is negative. + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return precision score for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> precision_score(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Main Path +5-element Array{Float64,1}: + 0.3333333333333333 + 1.0 + 0.3333333333333333 + 0.0 + 0.0 + +julia> precision_score(x, class_name = 3) +0.3333333333333333 + +``` + +_See also_ : ```confusion_matrix```, ```sensitivity_score```, ```balanced_accuracy_score```,```recall_score``` + +""" +function precision_score(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = c.true_positives ./ (c.true_positives + c.false_positives) + x = clear_output(x, c.zero_division) + return average == "binary" ? x : mean(x) + else + x = c.true_positives[index] / (c.true_positives[index] + c.false_positives[index]) + return clear_output(x,c.zero_division) + end +end + +precision_score(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +precision_score(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" +```positive_predictive_value(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return score of either the whole confusion matrix or the classes specified by `class_name` or `ith_class` +arguments. + + The positive predictive value is the ratio ``tp / (tp + fp)`` where ``tp`` is the number of + true positives and ``fp`` the number of false positives. The positive predictive value is + intuitively the ability of the classifier not to label as positive a sample + that is negative. + +## Keywords + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return positive predictive value for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> positive_predictive_value(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Main Path +5-element Array{Float64,1}: + 0.3333333333333333 + 1.0 + 0.3333333333333333 + 0.0 + 0.0 + +julia> positive_predictive_value(x, ith_class = 3) +0.3333333333333333 + +``` + +_See also_ : ```negative_predictive_value```, ```confusion_matrix```, ```sensitivity_score```, ```balanced_accuracy_score```,```recall_score``` + +""" +function positive_predictive_value(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + return precision_score(c, class_name = class_name, ith_class = ith_class, average = average) +end + +positive_predictive_value(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +positive_predictive_value(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" +```accuracy_score(c::confusion_matrix; ith_class = nothing, class_name = nothing, normalize = true, sample_weight = nothing) ``` + +Return accuracy classification score. + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +**`normalize`** : bool, default= true + If ``False``, return the number of correctly classified samples. + Otherwise, return the fraction of correctly classified samples. + +**`sample_weight`** : array-like of shape (n_samples,), default=None + Sample weights. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return positive predictive value for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> accuracy_score(x) +0.36 + +julia> accuracy_score(x, normalize = false) +3.5999999999999996 + +``` + +_See also_ : ```jaccard_score``` ```confusion_matrix```, ```hamming_loss```, ```balanced_accuracy_score```,```recall_score``` + + +""" +function accuracy_score(c::confusion_matrix; ith_class = nothing, class_name = nothing, normalize = true, sample_weight = nothing) + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + accuracy_array = [accuracy_score(c, ith_class = i) for i in 1:length(c.true_positives)] + if normalize + x = sample_weight == nothing ? (sum(accuracy_array) / sum(c.matrix)) : (sum(accuracy_array .* sample_weight) / sum(c.matrix)) + return clear_output(x,c.zero_division) + else + x = sample_weight == nothing ? sum(accuracy_array) : dot(accuracy_array, sample_weight) + return clear_output(x,c.zero_division) + end + else + if normalize + x = (c.true_positives[index] + c.true_negatives[index] ) / (condition_positive(c, ith_class = index) + condition_negative(c, ith_class = index)) + return clear_output(x, c.zero_division) + else + x = (c.true_positives[index]) + return clear_output(x, c.zero_division) + end + end +end + +accuracy_score(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, normalize = true, sample_weight = nothing) where T <: Union{Int, String} = +accuracy_score(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, normalize = true, sample_weight = nothing) + +""" +```balanced_accuracy_score(c::confusion_matrix; ith_class = nothing, class_name = nothing) ``` + +Return balanced accuracy classification score. + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return balanced accuracy score for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> balanced_accuracy_score(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +5-element Array{Float64,1}: + 0.4 + 0.75 + 0.8888888888888888 + 0.35 + 0.5 + +julia> balanced_accuracy_score(x, ith_class = 3) +0.8888888888888888 + +``` + +_See also_ : ```accuracy_score``` ```confusion_matrix```, ```hamming_loss```, ```balanced_accuracy_score```,```recall_score``` + +[1] Brodersen, K.H.; Ong, C.S.; Stephan, K.E.; Buhmann, J.M. (2010). + The balanced accuracy and its posterior distribution. + Proceedings of the 20th International Conference on Pattern + Recognition, 3121-24. +[2] John. D. Kelleher, Brian Mac Namee, Aoife D'Arcy, (2015). + `Fundamentals of Machine Learning for Predictive Data Analytics: + Algorithms, Worked Examples, and Case Studies + [link](https://mitpress.mit.edu/books/fundamentals-machine-learning-predictive-data-analytics) + +""" +function balanced_accuracy_score(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [(sensitivity_score(c, ith_class = i) + specificity_score(c, ith_class = i)) / 2 for i in 1:length(c.true_positives)] + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = (sensitivity_score(c,ith_class = index) + specificity_score(c, ith_class = index)) / 2 + return clear_output(x,c.zero_division) + end +end + +balanced_accuracy_score(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +balanced_accuracy_score(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" + +```negative_predictive_value(c::confusion_matrix; ith_class = nothing, class_name = nothing) ``` + +Return negative predictive value for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return negative predictive value for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> negative_predictive_value(x) +5-element Array{Float64,1}: + 0.42857142857142855 + 0.8888888888888888 + 1.0 + 1.0 + 0.8 + + julia> negative_predictive_value(x, class_name = 1) + 0.42857142857142855 +``` + +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```positive_predictive_value```, ```balanced_accuracy_score``` + +""" +function negative_predictive_value(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [c.true_negatives[i] / (c.true_negatives[i] + c.false_negatives[i]) for i in 1:length(c.true_positives)] + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = c.true_negatives[index] / (c.true_negatives[index] + c.false_negatives[index]) + return clear_output(x,c.zero_division) + end +end + +negative_predictive_value(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +negative_predictive_value(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" + +```false_negative_rate(c::confusion_matrix; ith_class = nothing, class_name = nothing) ``` + +Return false negative rate for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return false negative rate for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> false_negative_rate(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +5-element Array{Float64,1}: + 0.8 + 0.5 + 0.0 + 0.0 + 1.0 + + julia> false_negative_rate(x, ith_class = 3) + 0.0 + ``` + + _See Also_ : ```confusion_matrix```, ```false_positive_rate```, ```positive_predictive_value```, ```balanced_accuracy_score``` + +""" +function false_negative_rate(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [c.false_negatives[i] / condition_positive(c,ith_class = i) for i in 1:length(c.true_positives)] + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = c.false_negatives[index] / condition_positive(c,ith_class = index) + return clear_output(x,c.zero_division) + end +end + +false_negative_rate(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +false_negative_rate(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" + +```false_positive_rate(c::confusion_matrix; ith_class = nothing, class_name = nothing) ``` + +Return false positive rate for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return false positive rate for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> false_positive_rate(x) +5-element Array{Float64,1}: + 0.4 + 0.0 + 0.2222222222222222 + 0.3 + 0.0 + + julia> false_positive_rate(x, ith_class = 3) + 0.2222222222222222 + ``` + + _See Also_ : ```confusion_matrix```, ```false_negative_rate```, ```positive_predictive_value```, ```balanced_accuracy_score``` +""" +function false_positive_rate(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [c.false_positives[i] / condition_negative(c,ith_class = i) for i in 1:length(c.true_positives)] + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = c.false_positives[index] / condition_negative(c,ith_class = index) + return clear_output(x,c.zero_division) + end +end + +false_positive_rate(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +false_positive_rate(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" + +```false_discovery_rate(c::confusion_matrix; ith_class = nothing, class_name = nothing) ``` + +Return false discovery rate for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return false discovery rate for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> false_discovery_rate(x) +5-element Array{Float64,1}: + 0.4 + 0.0 + 0.2222222222222222 + 0.3 + 0.0 + +julia> false_discovery_rate(x, ith_class = 3) +0.2222222222222222 + +``` +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```positive_predictive_value```, ```false_omission_rate``` + +""" +function false_discovery_rate(c::confusion_matrix; ith_class = nothing, class_name = nothing, average= "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [c.false_positives[i] / ( c.false_positives[i] + c.true_negatives[i]) for i in 1:length(c.true_positives)] + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = c.false_positives[index] / ( c.false_positives[index] + c.true_negatives[index]) + return clear_output(x,c.zero_division) + end +end + +false_discovery_rate(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +false_discovery_rate(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" +```false_omission_rate(c::confusion_matrix; ith_class = nothing, class_name = nothing) ``` + +Return false omission rate for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return false omission rate for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> false_omission_rate(x) +5-element Array{Float64,1}: + 0.5714285714285714 + 0.11111111111111116 + 0.0 + 0.0 + 0.19999999999999996 + +julia> false_omission_rate(x, ith_class = 5) +0.19999999999999996 +``` + +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```positive_predictive_value```, ```false_discovery_rate``` +""" +function false_omission_rate(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [1 - negative_predictive_value(c,ith_class = i) for i in 1:length(c.true_positives)] + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = 1 - negative_predictive_value(c,ith_class = index) + return clear_output(x,c.zero_division) + end +end + +false_omission_rate(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +false_omission_rate(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" +```f1_score(c::confusion_matrix; ith_class = nothing, class_name = nothing) ``` + +Return f1 score for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return f1 score for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> f1_score(x) +5-element Array{Float64,1}: + 0.25 + 0.6666666666666666 + 0.5 + 0.0 + 0.0 + +julia> f1_score(x, class_name = 2) +0.6666666666666666 +``` + +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```recall_score```, ```false_omission_rate``` + +""" +function f1_score(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [(2* c.true_positives[i] ) / (2* c.true_positives[i] + c.false_positives[i] + c.false_negatives[i]) for i in 1:length(c.true_positives)] + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = (2* c.true_positives[index] ) / (2* c.true_positives[index] + c.false_positives[index] + c.false_negatives[index]) + return clear_output(x,c.zero_division) + end +end + +f1_score(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +f1_score(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" + +```prevalence_threshold(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return prevalence threshold for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return prevalence threshold for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> prevalence_threshold(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +5-element Array{Float64,1}: + -2.828427124746191 + 0.0 + 0.0 + -1.8257418583505536 + 0.0 + +julia> prevalence_threshold(x, ith_class = 1) +-2.828427124746191 +``` + +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```recall_score```, ```f1_score``` + +""" +function prevalence_threshold(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [(sqrt(abs(sensitivity_score(c,ith_class = i) * (-specificity_score(c,ith_class = i) +1) + specificity_score(c,ith_class = i) -1)) / (sensitivity_score(c,ith_class = i) + specificity_score(c,ith_class = i) -1)) for i in 1:length(c.true_positives)] + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = (sqrt(abs(sensitivity_score(c,ith_class = index) * (-specificity_score(c,ith_class = index) +1) + specificity_score(c,ith_class = index) -1)) / (sensitivity_score(c,ith_class = index) + specificity_score(c,ith_class = index) -1)) + return clear_output(x,c.zero_division) + end +end + +prevalence_threshold(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +prevalence_threshold(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" + +```threat_score(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return threat score for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return threat score for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> threat_score(x) +5-element Array{Float64,1}: + 0.14285714285714285 + 0.5 + 0.3333333333333333 + 0.0 + 0.0 + +julia> threat_score(x, ith_class = 3) +0.3333333333333333 + +``` +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```recall_score```, ```f1_score``` + +""" +function threat_score(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [c.true_positives[i] / (c.true_positives[i] + c.false_negatives[i] + c.false_positives[i]) for i in 1:length(c.true_positives)] + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = c.true_positives[index] / (c.true_positives[index] + c.false_negatives[index] + c.false_positives[index]) + return clear_output(x,c.zero_division) + end +end + +threat_score(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +threat_score(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" + +```matthews_correlation_coeff(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return Matthew's Correlation Coefficient for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return Matthew's Correlation Coefficient for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> matthews_correlation_coeff(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +5-element Array{Float64,1}: + -0.2182178902359924 + 0.6666666666666666 + 0.5091750772173156 + 0.0 + 0.0 + +julia> matthews_correlation_coeff(x, ith_class = 3) +0.5091750772173156 + +``` + +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```threat_score```, ```f1_score``` + +""" +function matthews_correlation_coeff(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [(c.true_positives[i] * c.true_negatives[i] - c.false_positives[i] * c.false_negatives[i]) / sqrt( abs((c.true_positives[i] + c.false_positives[i]) * (c.true_positives[i] + c.false_negatives[i]) * + (c.true_negatives[i] + c.false_positives[i]) * (c.true_negatives[i] + c.false_negatives[i]))) + for i in 1:length(c.true_positives)] + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = (c.true_positives[index] * c.true_negatives[index] - c.false_positives[index] * c.false_negatives[index]) / sqrt( (c.true_positives[index] + c.false_positives[index]) * (c.true_positives[index] + c.false_negatives[index]) * + (c.true_negatives[index] + c.false_positives[index]) * (c.true_negatives[index] + c.false_negatives[index])) + return clear_output(x,c.zero_division) + end +end + +matthews_correlation_coeff(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +matthews_correlation_coeff(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" + +```fowlkes_mallows_index(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return Fowlkes Mallows Index for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return Fowlkes Mallows Index for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> fowlkes_mallows_index(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Main Path +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Main Path +5-element Array{Float64,1}: + 0.2581988897471611 + 0.7071067811865476 + 0.5773502691896257 + 0.0 + 0.0 + +julia> fowlkes_mallows_index(x, ith_class = 2) +0.7071067811865476 + +``` + +_See Also_ : ```confusion_matrix```, ```matthews_correlation_coeff```, ```threat_score```, ```f1_score``` +""" +function fowlkes_mallows_index(c::confusion_matrix; ith_class = nothing, class_name = nothing, average ="binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [sqrt(positive_predictive_value(c,ith_class = i) * sensitivity_score(c,ith_class = i)) for i in 1:length(c.true_positives)] + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = sqrt(positive_predictive_value(c,ith_class = index) * sensitivity_score(c,ith_class = index)) + return clear_output(x,c.zero_division) + end +end + +fowlkes_mallows_index(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +fowlkes_mallows_index(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" + +```informedness(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return informedness value for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return informedness value for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> informedness(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +5-element Array{Float64,1}: + -0.19999999999999996 + 0.5 + 0.7777777777777777 + -0.30000000000000004 + 0.0 + +julia> informedness(x,ith_class = 3) +0.7777777777777777 + +``` + +_See Also_ : ```confusion_matrix```, ```matthews_correlation_coeff```, ```markedness```, ```f1_score``` +""" +function informedness(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [ ( specificity_score(c,ith_class = i) + sensitivity_score(c,ith_class = i) -1) for i in 1:length(c.true_positives)] + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = specificity_score(c,ith_class = index) + sensitivity_score(c,ith_class = index) -1 + return clear_output(x,c.zero_division) + end +end + +informedness(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +informedness(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" + +```markedness(c::confusion_matrix; ith_class = nothing, class_name = nothing)``` + +Return markedness value for the specified class(es). + +## Arguments + +**`ith_class`** : Int, default = nothing +Return the results for the ith class in the ith label of the label list of the given confusion matrix object. + +**`class_name`** : Int/String, default = nothing +Return the results for the class of the speicifed value in the ith label of the label list of the given confusion matrix object. + +If both `class_name` and `ith_class` arguments are equal to `nothing`, return markedness value for all the elements in the labels arrays + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> markedness(x) +┌ Warning: Zero division, replacing NaN or Inf with 0 +└ @ Path +5-element Array{Float64,1}: + -0.8571428571428572 + -0.11111111111111116 + -0.6666666666666667 + -1.0 + -1.0 + +julia> markedness(x, ith_class = 1) +-0.19999999999999996 + +``` + +_See Also_ : ```confusion_matrix```, ```matthews_correlation_coeff```, ```informedness```, ```f1_score``` + +""" +function markedness(c::confusion_matrix; ith_class = nothing, class_name = nothing, average = "binary") + @assert average in ["binary", "macro"] "Unknown averaging type" + index = check_index(c.Labels, true, ith_class = ith_class, class_name = class_name) + if index == -1 + x = [( precision_score(c,ith_class = i) * negative_predictive_value(c,ith_class = i) -1) for i in 1:length(c.true_positives)] + x = clear_output(x,c.zero_division) + return average == "binary" ? x : mean(x) + else + x = specificity_score(c,ith_class = index) + sensitivity_score(c,ith_class = index) -1 + return clear_output(x,c.zero_division) + end +end + +markedness(expected::Array{T,1}, predicted::Array{T,1}; ith_class = nothing, class_name = nothing, average = "binary") where T <: Union{Int, String} = +markedness(confusion_matrix(expected,predicted), ith_class = ith_class, class_name = class_name, average = average) + +""" +```cohen_kappa_score(c::confusion_matrix; weights = nothing) ``` + +Return Cohen's Kappa (a statistic that measures inter-annotator agreement) + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> cohen_kappa_score(x) +0.125 +``` + +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```jaccard_score```, ```f1_score``` + +""" +function cohen_kappa_score(c::confusion_matrix; weights = nothing) +#reference: scikitlearn.metrics.classification.cohen_kappa_score + @assert weights in [nothing, "quadratic", "linear"] "Unknown kappa weighting type" + w_mat = nothing + sum0 = sum(c.matrix, dims = 1) + sum1 = sum(c.matrix, dims = 2) + expected = (sum1 * sum0) ./ sum(sum0) + if weights == nothing + w_mat = ones(length(c.Labels),length(c.Labels)) + for i in 1:length(c.Labels) + w_mat[i,i] = 0 + end + else + w_mat = zeros(length(c.Labels),length(c.Labels)) + w_mat += [i for i in 1:length(c.Labels)] + if weights == "linear" + w_mat = abs(w_mat - transpose(w_mat)) + else + w_mat = (w_mat - transpose(w_mat)) ^2 + end + end + x = sum(w_mat .* c.matrix) / sum(w_mat .* expected) + return clear_output(1- x,c.zero_division) +end + +cohen_kappa_score(expected::Array{T,1}, predicted::Array{T,1}; weights = nothing) where T <: Union{Int, String} = +cohen_kappa_score(confusion_matrix(expected,predicted), weights = nothing) + +""" + +```hamming_loss(c::confusion_matrix) ``` + +Compute the average Hamming loss. + The Hamming loss is the fraction of labels that are incorrectly predicted. + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> hamming_loss(x) +0.7 +``` + +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```jaccard_score```, ```f1_score``` + +""" +function hamming_loss(c::confusion_matrix;) + x = zeros(sum(c.matrix)) + x[1] = sum(c.false_negatives) + return clear_output(mean(x), c.zero_division) +end + +hamming_loss(expected::Array{T,1}, predicted::Array{T,1};) where T <: Union{Int, String} = +hamming_loss(confusion_matrix(expected,predicted)) + +""" + +```jaccard_score(c::confusion_matrix; average = "binary", sample_weight = nothing) ``` + +Compute Jaccard similarity coefficient score + The Jaccard index [1], or Jaccard similarity coefficient, defined as + the size of the intersection divided by the size of the union of two label + sets, is used to compare set of predicted labels for a sample to the + corresponding set of labels in ``y_true``. + +## Keywords + +average : string [None, 'binary' (default), 'micro', 'macro', 'samples, 'weighted'] + If ``None``, the scores for each class are returned. Otherwise, this + determines the type of averaging performed on the data: + ``binary``: + Only report results for the class specified by ``pos_label``. + ``micro``: + Calculate metrics globally by counting the total true positives, + false negatives and false positives. + ``macro``: + Calculate metrics for each label, and find their unweighted + mean. This does not take label imbalance into account. + ``weighted``: + Calculate metrics for each label, and find their average, weighted + by support (the number of true instances for each label). This + alters 'macro' to account for label imbalance. + ``samples``: + Calculate metrics for each instance, and find their average (only + meaningful for multilabel classification). +sample_weight : array-like of shape (n_samples,), default=None + Sample weights. + +## Examples + +```julia-repl +julia> y_true = [3, 1, 1, 2, 1, 2, 1, 5, 1, 5]; + +julia> y_pred = [3, 1, 4, 1, 4, 2, 3, 4, 3, 1]; + +julia> x = confusion_matrix(y_true, y_pred, labels= [1,2,3,4,5]); + +julia> hamming_loss(x) +0.7 +``` + +## References + +[1] [Wikipedia entry for the Jaccard index](https://en.wikipedia.org/wiki/Jaccard_index) + + +_See Also_ : ```confusion_matrix```, ```accuracy_score```, ```hamming_loss```, ```f1_score``` + +""" +function jaccard_score(c::confusion_matrix; average = "binary", sample_weight = nothing) + @assert average in [nothing, "binary", "weighted", "samples", "micro", "macro"] "Unknown averaging type" + if sample_weight != nothing @assert length(sample_weight) == length(c.true_positives) "Dimensions of given sample weight does not match the confusion matrix"; end + numerator = c.true_positives + denominator = c.true_positives + c.false_negatives + c.false_positives + if average == nothing + x = numerator ./ denominator + return clear_output(x, c.zero_division) + elseif average == "micro" + numerator = sum(numerator) + denominator = sum(denominator) + x = numerator ./ denominator + return clear_output(x, c.zero_division) + elseif average == "macro" + numerator = c.true_positives + denominator = c.true_positives + c.false_negatives + c.false_positives + x = numerator ./ denominator + return clear_output(mean(x), c.zero_division) + elseif average == "weighted" || average == "samples" + weights = nothing + if average == "weighted" + weights = c.false_negatives + c.true_positives + elseif average == "samples" + weights = sample_weight + end + score = numerator ./ denominator + x = [weights[i] * score[i] for i in 1:length(c.Labels)] + x / length(c.Labels) + return clear_output(x, c.zero_division) + else + x = [(c.false_negatives[i] + c.true_positives[i])/length(c.Labels) for i in 1:length(c.Labels)] + return clear_output(x, c.zero_division) + end +end + +jaccard_score(expected::Array{T,1}, predicted::Array{T,1}; average = "binary", sample_weight = nothing) where T <: Union{Int, String} = +jaccard_score(confusion_matrix(expected,predicted), average = average, sample_weight = sample_weight) diff --git a/src/metrics/Classification/visualization.jl b/src/metrics/Classification/visualization.jl new file mode 100644 index 000000000..eec3fbeac --- /dev/null +++ b/src/metrics/Classification/visualization.jl @@ -0,0 +1,126 @@ +#Visualization Functions +export visualize + +using Plots + +gr() + +function _plot(c::confusion_matrix; func, type, title, labels = nothing) + x = nothing + if type == "condition-positive"; x = func(labels, condition_positive(c) , title = title, labels = permutedims(labels)) + elseif type == "condition-negative"; x = func(labels, condition_negative(c) , title = title, labels = permutedims(labels)) + elseif type == "predicted-positive"; x = func(labels, predicted_positive(c) , title = title, labels = permutedims(labels)) + elseif type == "predicted-negative"; x = func(labels, predicted_positive(c) , title = title, labels = permutedims(labels)) + elseif type == "correctly-classified"; x = func(labels, correctly_classified(c) , title = title, labels = permutedims(labels)) + elseif type == "incorrectly-classified"; x = func(labels, incorrectly_classified(c) , title = title, labels = permutedims(labels)) + elseif type == "sensitivity-score"; x = func(labels, sensitivity_score(c) , title = title, labels = permutedims(labels)) + elseif type == "recall-score"; x = func(labels, recall_score(c), title = title, labels = permutedims(labels)) + elseif type == "specificity-score";x = func(labels, specificity_score(c) ,title = title, labels = permutedims(labels)) + elseif type == "precision-score";x = func(labels, precision_score(c), title = title, labels = permutedims(labels)) + elseif type == "positive-predictive-value"; x = func(labels, positive_predictive_value(c) , title = title, labels = permutedims(labels)) + elseif type == "accuracy-score"; x = func(labels, accuracy_score(c), title = title, labels = permutedims(labels)) + elseif type == "balanced-accuracy-score"; x = func(labels, balanced_accuracy_score(c), title = title, labels = permutedims(labels)) + elseif type == "negative-predictive-value"; x = func(labels, negative_predictive_value(c), title = title, labels = permutedims(labels)) + elseif type == "false-negative-rate"; x = func(labels, false_negative_rate(c), title = title, labels = permutedims(labels)) + elseif type == "false-positive-rate"; x = func(labels, false_positive_rate(c), title = title, labels = permutedims(labels)) + elseif type == "false-discovery-rate"; x = func(labels, false_discovery_rate(c), title = title, labels = permutedims(labels)) + elseif type == "false-omission-rate"; x = func(labels, false_omission_rate(c), title = title, labels = permutedims(labels)) + elseif type == "f1-score"; x = func(labels, f1_score(c), title = title, labels = permutedims(labels)) + elseif type == "prevalence-threshold"; x = func(labels, prevalence_threshold(c), title = title, labels = permutedims(labels)) + elseif type == "threat-score"; x = func(labels, threat_score(c), title = title, labels = permutedims(labels)) + elseif type == "matthews-correlation-coeff"; x = func(labels, matthews_correlation_coeff(c), title = title, labels = permutedims(labels)) + elseif type == "fowlkes-mallows-index"; x = func(labels,fowlkes-mallows-index(c), title = title, labels = permutedims(labels)) + elseif type == "informedness"; x = func(labels, informedness(c), title = title, labels = permutedims(labels)) + elseif type == "markedness"; x = func(labels, markedness(c), title = title, labels = permutedims(labels)) + elseif type == "cohen-kappa-score"; x = func(labels, cohen_kappa_score(c), title = title, labels = permutedims(labels)) + elseif type == "hamming-loss"; x = func(labels, hamming_loss(c), title = title, labels = permutedims(labels)) + elseif type == "jaccard-score"; x = func(labels, jaccard_score(c), title = title, labels = permutedims(labels)) + end + return x +end + + +""" +```visualize(c::confusion_matrix, )``` + +Visualize the given properties of the confusion matrix as specified + +## Keywords +**`mode`** : String, Array of String; represents properties given below of the confusion matrix, can be either an array containing different properties +or a single string.\n + Supported Modes: \n + - `matrix`\n + - `condition-positive`\n + - `condition-negative`\n + - `predicted-positive\n + - `predicted-negative`\n + - `correctly-classified`\n + - `incorrectly-classified`\n + - `sensitivity-score`\n + - `recall-score`\n + - `specificity-score`\n + - `precision-score`\n + - `positive-predictive-value`\n + - `accuracy-score`\n + - `balanced-accuracy-score`\n + - `negative-predictive-value`\n + - `false-negative-rate`\n + - `false-positive-rate`\n + - `false-discovery-rate`\n + - `false-omission-rate`\n + - `f1-score`\n + - `prevalence-threshold`\n + - `threat-score`\n + - `matthews-correlation-coeff`\n + - `fowlkes-mallows-index`\n + - `informedness`\n + - `markedness`\n + - `cohen-kappa-score`\n + - `hamming-loss`\n + - `jaccard-score`\n + +**`seriestype`** : String, denotes which visualization function will be used; default: heatmap + Supported visualization functions: + - `heatmap` + - `bar` + - `histogram` + - `scatter` + - `line` + +**`title`** : String, denotes the title that will displayed above the drawn plot, default: nothing + +**`labels`** : Vector, denotes the labels that will be used for the plot. If equals to nothing, labels of the given confusion matrix will be used. + +""" +function visualize(c::confusion_matrix; mode = "matrix", seriestype::String = "heatmap", title= nothing, labels = nothing) + @assert seriestype in ["scatter", "heatmap", "line", "histogram", "bar"] "Unknown visualization format" + labels = labels != nothing ? labels : convert(Array{typeof(c.Labels[1])}, c.Labels) + if title == nothing; title = mode isa Array ? mode : String(Base.copymutable(mode)); end + title = title isa Array ? title : [title] + mode = mode isa Array ? mode : [mode] + plt = [] + for i in 1:length(mode) + @assert mode[i] in ["matrix", "condition-positive", "condition-negative", "predicted-positive","predicted-negative", "correctly-classified", "incorrectly-classified", "sensitivity-score", "recall-score", "specificity-score", "precision-score", "positive-predictive-value", "accuracy-score", "balanced-accuracy-score", "negative-predictive-value", "false-negative-rate", "false-positive-rate", "false-discovery-rate", + "false-omission-rate", "f1-score", "prevalence-threshold", "threat-score", "matthews-correlation-coeff", "fowlkes-mallows-index", + "informedness", "markedness", "cohen-kappa-score", "hamming-loss", "jaccard-score"] "Unknown visualization mode" + if mode[i] != "matrix"; @assert seriestype in ["scatter", "line", "histogram", "bar"] "The given mode does not support this visualization format"; end + x = nothing + if mode[i] == "matrix" + if seriestype == "histogram"; x = histogram(labels, c.matrix, labels = permutedims(labels), title = title[i]) + elseif seriestype == "scatter"; x = scatter(labels, c.matrix, labels = permutedims(labels), title = title[i]) + elseif seriestype == "line"; x = plot(labels, c.matrix, labels = permutedims(labels), title = title[i]) + elseif seriestype == "bar"; x = bar(labels, c.matrix, labels = permutedims(labels), title = title[i]) + elseif seriestype == "heatmap"; x = heatmap(labels, labels, c.matrix, labels = permutedims(labels), title = title[i]) + end + else + if seriestype == "histogram"; x = _plot(c; func = histogram, type = mode[i], title = title[i], labels = labels) + elseif seriestype == "scatter"; x = _plot(c; func = scatter, type = mode[i], title = title[i], labels = labels) + elseif seriestype == "line"; x = _plot(c; func = plot, type = mode[i], title = title[i], labels = labels) + elseif seriestype == "bar"; x = _plot(c; func = bar, type = mode[i], title = title[i], labels = labels) + elseif seriestype == "heatmap"; x = _plot(c; func = heatmap, type = mode[i], title = title[i], labels = labels) + end + end + push!(plt, x) + end + plot(plt..., layout = (length(plt), 1)) +end diff --git a/src/metrics/metrics.jl b/src/metrics/metrics.jl new file mode 100644 index 000000000..12d8ad142 --- /dev/null +++ b/src/metrics/metrics.jl @@ -0,0 +1,13 @@ +module Metrics + +import LinearAlgebra +import Plots +import Statistics: mean + +export confusion_matrix, class_confusion, visualize, classification_report, condition_positive, condition_negative, predicted_positive,predicted_negative, correctly_classified, incorrectly_classified, sensitivity_score, recall_score, specificity_score, precision_score, positive_predictive_value, accuracy_score, balanced_accuracy_score, negative_predictive_value, false_negative_rate, false_positive_rate, false_discovery_rate, false_omission_rate, f1_score, prevalence_threshold, threat_score, matthews_correlation_coeff, fowlkes_mallows_index, informedness, markedness, cohen_kappa_score, hamming_loss, jaccard_score, confusion_params + +include("classification/Classification.jl") + +using Metrics.Classification + +end diff --git a/test/classification-metrics.jl b/test/classification-metrics.jl new file mode 100644 index 000000000..f8bf34d3d --- /dev/null +++ b/test/classification-metrics.jl @@ -0,0 +1,128 @@ +using Test +using Knet.Metrics + +@testset "metrics" begin + random_true = rand(2:6,1000) + random_pred = rand(2:6,1000) + random_labels = [2,3,4,5,6] + random_confusion_matrix = confusion_matrix(random_true, random_pred, labels = random_labels) + + @testset "binary-confusion-matrix" begin + y_true = [1,1,2,2] + y_pred = [1,1,2,2] + x = confusion_matrix(y_true, y_pred) + @test x.matrix == [2 0; 0 2] + end + + y_true = [3, 2, 4, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5, 3, 4, 4, 2] + y_pred = [3, 2, 5, 3, 2, 4, 4, 3, 2, 3, 4, 2, 2, 3, 4, 2, 3, 3, 4, 4] + labels = [2, 3, 4, 5] + + x = confusion_matrix(y_true, y_pred, labels = labels) + + @testset "multiclass-confusion-matrix" begin + @test x.matrix == [4 0 1 0; 0 5 1 0; 0 1 4 1; 2 1 0 0] + end + + @testset "class-confusion" begin + @test class_confusion(x,ith_class =2) == [5 2; 1 12] + @test class_confusion(random_confusion_matrix,ith_class =2) == class_confusion(random_confusion_matrix, class_name = 3) + end + + @testset "condition-positive" begin + @test condition_positive(x) == [5, 6, 6, 3] + @test condition_positive(x, ith_class = 2) == 6 + @test condition_positive(random_confusion_matrix, class_name = 3) == condition_positive(random_confusion_matrix, ith_class = 2) + end + + @testset "condition-negative" begin + @test condition_negative(x) == [15, 14, 14, 17] + @test condition_negative(x,ith_class = 3) == 14 + @test condition_negative(random_confusion_matrix, class_name = 3) == condition_negative(random_confusion_matrix, ith_class = 2) + end + + @testset "sensitivity-recall-score" begin + @test isapprox(sensitivity_score(x), [0.8, 0.8333333333333334, 0.6666666666666666, 0.0]) + @test sensitivity_score(random_confusion_matrix) == recall_score(random_confusion_matrix) + end + + @testset "specificity-score" begin + @test isapprox(specificity_score(x),[0.8666666666666667, 0.8571428571428571, 0.8571428571428571, 0.9411764705882353]) + end + + @testset "precision-score" begin + @test isapprox(precision_score(x), [0.6666666666666666, 0.7142857142857143, 0.6666666666666666, 0.0]) + end + + @testset "accuracy-score" begin + @test isapprox(accuracy_score(x), 0.16499999999999998) + @test accuracy_score(x, normalize = false) == 3.3 + end + + @testset "balanced-accuracy-score" begin + @test isapprox(balanced_accuracy_score(x),[0.8333333333333334, 0.8452380952380952, 0.7619047619047619, 0.47058823529411764]) + end + + @testset "negative-predictive-value" begin + @test isapprox(negative_predictive_value(x), [0.9285714285714286, 0.9230769230769231, 0.8571428571428571, 0.8421052631578947]) + end + + @testset "false-positive-rate" begin + @test isapprox(false_positive_rate(x), [0.13333333333333333, 0.14285714285714285, 0.14285714285714285, 0.058823529411764705]) + end + + @testset "false-negative-rate" begin + @test isapprox(false_negative_rate(x), [0.2, 0.16666666666666666, 0.3333333333333333, 1.0]) + end + + @testset "false-discovery-rate" begin + @test isapprox(false_discovery_rate(x) , [0.13333333333333333, 0.14285714285714285, 0.14285714285714285, 0.058823529411764705]) + end + + @testset "false-omission-rate" begin + @test isapprox(false_omission_rate(x),[0.0714285714285714, 0.07692307692307687, 0.1428571428571429, 0.1578947368421053]) + end + + @testset "f1-score" begin + @test isapprox(f1_score(x),[0.7272727272727273, 0.7692307692307693, 0.6666666666666666, 0.0]) + end + + @testset "prevalence-threshold" begin + @test isapprox(prevalence_threshold(x),[0.24494897427831755, 0.22347381718647807, 0.4165977904505312, -4.12310562561766]) + end + + @testset "threat-score" begin + @test isapprox(threat_score(x),[0.5714285714285714, 0.625, 0.5, 0.0]) + end + + @testset "matthews-correlation-coefficient" begin + @test isapprox(matthews_correlation_coeff(x),[0.629940788348712, 0.6633880657639324, 0.5238095238095238, -0.09637388493048533]) + end + + @testset "fowlkes-mallows-index" begin + @test isapprox( fowlkes_mallows_index(x),[0.7302967433402214, 0.7715167498104596, 0.6666666666666666, 0.0]) + end + + @testset "informedness" begin + @test isapprox(informedness(x) ,[0.6666666666666667, 0.6904761904761905, 0.5238095238095237, -0.05882352941176472]) + end + + @testset "markedness" begin + @test isapprox(markedness(x), [-0.38095238095238093, -0.34065934065934056, -0.4285714285714286, -1.0]) + end + + @testset "hamming-loss" begin + @test hamming_loss(x) == 0.35 + end + + @testset "jaccard-score" begin + @test jaccard_score(x) == [1.25, 1.5, 1.5, 0.75] + @test isapprox(0.48148148148148145, jaccard_score(x, average = "micro")) + @test isapprox(0.42410714285714285, jaccard_score(x, average = "macro")) + end + + @testset "cohen-kappa-score" begin + @test isapprox(0.5155709342560555, cohen_kappa_score(x)) + end + +end diff --git a/test/classification-metrics0.jl b/test/classification-metrics0.jl new file mode 100644 index 000000000..2b1b9419f --- /dev/null +++ b/test/classification-metrics0.jl @@ -0,0 +1,128 @@ +using Test +using KnetMetrics + +@testset "classification-metrics" begin + random_true = rand(2:6,1000) + random_pred = rand(2:6,1000) + random_labels = [2,3,4,5,6] + random_confusion_matrix = confusion_matrix(random_true, random_pred, labels = random_labels) + + @testset "binary-confusion-matrix" begin + y_true = [1,1,2,2] + y_pred = [1,1,2,2] + x = confusion_matrix(y_true, y_pred) + @test x.matrix == [2 0; 0 2] + end + + y_true = [3, 2, 4, 3, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5, 3, 4, 4, 2] + y_pred = [3, 2, 5, 3, 2, 4, 4, 3, 2, 3, 4, 2, 2, 3, 4, 2, 3, 3, 4, 4] + labels = [2, 3, 4, 5] + + x = confusion_matrix(y_true, y_pred, labels = labels) + + @testset "multiclass-confusion-matrix" begin + @test x.matrix == [4 0 1 0; 0 5 1 0; 0 1 4 1; 2 1 0 0] + end + + @testset "class-confusion" begin + @test class_confusion(x,ith_class =2) == [5 2; 1 12] + @test class_confusion(random_confusion_matrix,ith_class =2) == class_confusion(random_confusion_matrix, class_name = 3) + end + + @testset "condition-positive" begin + @test condition_positive(x) == [5, 6, 6, 3] + @test condition_positive(x, ith_class = 2) == 6 + @test condition_positive(random_confusion_matrix, class_name = 3) == condition_positive(random_confusion_matrix, ith_class = 2) + end + + @testset "condition-negative" begin + @test condition_negative(x) == [15, 14, 14, 17] + @test condition_negative(x,ith_class = 3) == 14 + @test condition_negative(random_confusion_matrix, class_name = 3) == condition_negative(random_confusion_matrix, ith_class = 2) + end + + @testset "sensitivity-recall-score" begin + @test isapprox(sensitivity_score(x), [0.8, 0.8333333333333334, 0.6666666666666666, 0.0]) + @test sensitivity_score(random_confusion_matrix) == recall_score(random_confusion_matrix) + end + + @testset "specificity-score" begin + @test isapprox(specificity_score(x),[0.8666666666666667, 0.8571428571428571, 0.8571428571428571, 0.9411764705882353]) + end + + @testset "precision-score" begin + @test isapprox(precision_score(x), [0.6666666666666666, 0.7142857142857143, 0.6666666666666666, 0.0]) + end + + @testset "accuracy-score" begin + @test isapprox(accuracy_score(x), 0.16499999999999998) + @test accuracy_score(x, normalize = false) == 3.3 + end + + @testset "balanced-accuracy-score" begin + @test isapprox(balanced_accuracy_score(x),[0.8333333333333334, 0.8452380952380952, 0.7619047619047619, 0.47058823529411764]) + end + + @testset "negative-predictive-value" begin + @test isapprox(negative_predictive_value(x), [0.9285714285714286, 0.9230769230769231, 0.8571428571428571, 0.8421052631578947]) + end + + @testset "false-positive-rate" begin + @test isapprox(false_positive_rate(x), [0.13333333333333333, 0.14285714285714285, 0.14285714285714285, 0.058823529411764705]) + end + + @testset "false-negative-rate" begin + @test isapprox(false_negative_rate(x), [0.2, 0.16666666666666666, 0.3333333333333333, 1.0]) + end + + @testset "false-discovery-rate" begin + @test isapprox(false_discovery_rate(x) , [0.13333333333333333, 0.14285714285714285, 0.14285714285714285, 0.058823529411764705]) + end + + @testset "false-omission-rate" begin + @test isapprox(false_omission_rate(x),[0.0714285714285714, 0.07692307692307687, 0.1428571428571429, 0.1578947368421053]) + end + + @testset "f1-score" begin + @test isapprox(f1_score(x),[0.7272727272727273, 0.7692307692307693, 0.6666666666666666, 0.0]) + end + + @testset "prevalence-threshold" begin + @test isapprox(prevalence_threshold(x),[0.24494897427831755, 0.22347381718647807, 0.4165977904505312, -4.12310562561766]) + end + + @testset "threat-score" begin + @test isapprox(threat_score(x),[0.5714285714285714, 0.625, 0.5, 0.0]) + end + + @testset "matthews-correlation-coefficient" begin + @test isapprox(matthews_correlation_coeff(x),[0.629940788348712, 0.6633880657639324, 0.5238095238095238, -0.09637388493048533]) + end + + @testset "fowlkes-mallows-index" begin + @test isapprox( fowlkes_mallows_index(x),[0.7302967433402214, 0.7715167498104596, 0.6666666666666666, 0.0]) + end + + @testset "informedness" begin + @test isapprox(informedness(x) ,[0.6666666666666667, 0.6904761904761905, 0.5238095238095237, -0.05882352941176472]) + end + + @testset "markedness" begin + @test isapprox(markedness(x), [-0.38095238095238093, -0.34065934065934056, -0.4285714285714286, -1.0]) + end + + @testset "hamming-loss" begin + @test hamming_loss(x) == 0.35 + end + + @testset "jaccard-score" begin + @test jaccard_score(x) == [1.25, 1.5, 1.5, 0.75] + @test isapprox(0.48148148148148145, jaccard_score(x, average = "micro")) + @test isapprox(0.42410714285714285, jaccard_score(x, average = "macro")) + end + + @testset "cohen-kappa-score" begin + @test isapprox(0.5155709342560555, cohen_kappa_score(x)) + end + +end diff --git a/tutorial/New Tutorials/How to Train and Evalutate Models .ipynb b/tutorial/New Tutorials/How to Train and Evalutate Models .ipynb new file mode 100644 index 000000000..105a6c01b --- /dev/null +++ b/tutorial/New Tutorials/How to Train and Evalutate Models .ipynb @@ -0,0 +1,198 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Training and Evaluating Models\n", + "In this notebook, we will learn how to train a defined model and evalute its performance.\n", + "* Objectives: Learning built-in training (adam, ada), evaluating (accuracy) functions\n", + "* Prerequisites: Knet Neural Network Architecture and Layers notebook\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Importing Knet:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#using Pkg\n", + "#Pkg.add(\"Knet\")\n", + "using Knet\n", + "using MLDatasets\n", + "#You may see an error if your device does not support CUDA or your CUDA driver is not CUDA 10.1 or higher but you will be\n", + "#able to use all the functionalities, except GPU operations, in spite of this error" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's remember our layer and model definitions from the last tutorial:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "struct dense; w; b; f; end\n", + "(d::dense)(x) = d.f.(d.w * mat(x) .+ d.b)\n", + "dense(i::Int,o::Int,f=relu) = dense(param(o,i), param0(o), f);\n", + "\n", + "struct Conv; w; b; f; end\n", + "(c::Conv)(x) = c.f.(pool(conv4(c.w, x) .+ c.b))\n", + "Conv(w1,w2,cx,cy,f=relu) = Conv(param(w1,w2,cx,cy), param0(1,1,cy,1), f);\n", + "\n", + "struct Chain; layers; Chain(args...)= new(args);end\n", + "(c::Chain)(x) = (for l in c.layers; x = l(x); end; x)\n", + "(c::Chain)(x,y) = nll(c(x),y)\n", + "\n", + "LeNet = Chain(Conv(5,5,1,20), Conv(5,5,20,50), dense(800,500), dense(500,10,identity))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The data we need to train the model will be imported from an open source Julia library [MLDatasets](https://github.com/JuliaML/MLDatasets.jl). Details of importing data and using built-in Knet utilities for preprocessing will be explained in depth later." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Load MNIST data\n", + "xtrn,ytrn = MNIST.traindata(Float32); ytrn[ytrn.==0] .= 10\n", + "xtst,ytst = MNIST.testdata(Float32); ytst[ytst.==0] .= 10\n", + "dtrn = minibatch(xtrn, ytrn, 100; xsize=(size(xtrn,1),size(xtrn,2),1,:))\n", + "dtst = minibatch(xtst, ytst, 100; xsize=(size(xtst,1),size(xtst,2),1,:));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In Knet, we pass the model and data to optimizer functions instead of conventional \"model.train\" way.\n", + "Built-in optimization functions:\n", + "* adam\n", + "* adadelta\n", + "* momentum\n", + "* rmsprop\n", + "* adagrad\n", + "* nesterov\n", + "\n", + "An in-depth explanation of the optimization algorithms:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "@doc adam" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Training" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "adam(LeNet, ncycle(dtrn,10))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The ncycle function is built in [IterTools](https://juliacollections.github.io/IterTools.jl/latest/) library that takes the data as the first parameter and the number of epochs as the second parameter. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "@doc nycle" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When trained (it will take 30 seconds to 10 minutes depending on the CPU/GPU power), you will see that the function does not visualize the progress. For that, Knet has a function named progress!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "@doc progress!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "progress!(adam(LeNet, ncycle(dtrn,10)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Knet also has the function \"train!\" which is deprecated but still fully functional:\n", + "\n", + "function train!(model, data; loss=nll, optimizer=Adam(), callback=epochs(data,1), o...)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "progress!(train!(model, dtrn))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.5.2", + "language": "julia", + "name": "julia-1.5" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/tutorial/New Tutorials/KNET Neural Network Architecture and Layers.ipynb b/tutorial/New Tutorials/KNET Neural Network Architecture and Layers.ipynb new file mode 100644 index 000000000..b0dd19ed6 --- /dev/null +++ b/tutorial/New Tutorials/KNET Neural Network Architecture and Layers.ipynb @@ -0,0 +1,484 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Knet Neural Networks\n", + "***\n", + "In this an the following notebook, we will analyze the procedure of defining, training and evaluating neural networks. \n", + "* Objective: Learning construction a model like the LeNet given in [Quick Start](https://github.com/denizyuret/Knet.jl/blob/master/tutorial/15.quickstart.ipynb) with a thorough explanation of each part\n", + "* Prerequisites: [Julia arrays](https://docs.julialang.org/en/v1/manual/arrays)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In Knet, there are two ways to create a neural network, one being using the built-in Knet structs and the other being defining hand-written callable objects that accepts an array (matrix or vector) and outputs the result of the wanted logic in the right dimension. We will begin with custom layer." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Importing Knet if not already imported or using it" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "┌ Warning: This version of CUDA.jl only supports NVIDIA drivers for CUDA 10.1 or higher (yours is for CUDA 8.0.0)\n", + "└ @ CUDA C:\\Users\\PC\\.julia\\packages\\CUDA\\gKMm0\\src\\initialization.jl:111\n" + ] + }, + { + "ename": "LoadError", + "evalue": "InitError: Could not find a suitable CUDA installation\nduring initialization of module Knet", + "output_type": "error", + "traceback": [ + "InitError: Could not find a suitable CUDA installation\nduring initialization of module Knet", + "", + "Stacktrace:", + " [1] error(::String) at .\\error.jl:33", + " [2] __runtime_init__() at C:\\Users\\PC\\.julia\\packages\\CUDA\\gKMm0\\src\\initialization.jl:114", + " [3] macro expansion at C:\\Users\\PC\\.julia\\packages\\CUDA\\gKMm0\\src\\initialization.jl:32 [inlined]", + " [4] macro expansion at .\\lock.jl:183 [inlined]", + " [5] _functional(::Bool) at C:\\Users\\PC\\.julia\\packages\\CUDA\\gKMm0\\src\\initialization.jl:26", + " [6] functional(::Bool) at C:\\Users\\PC\\.julia\\packages\\CUDA\\gKMm0\\src\\initialization.jl:19", + " [7] functional at C:\\Users\\PC\\.julia\\packages\\CUDA\\gKMm0\\src\\initialization.jl:18 [inlined]", + " [8] __init__() at C:\\Users\\PC\\.julia\\packages\\Knet\\OYNCT\\src\\Knet.jl:26", + " [9] _include_from_serialized(::String, ::Array{Any,1}) at .\\loading.jl:697", + " [10] _require_search_from_serialized(::Base.PkgId, ::String) at .\\loading.jl:782", + " [11] _require(::Base.PkgId) at .\\loading.jl:1007", + " [12] require(::Base.PkgId) at .\\loading.jl:928", + " [13] require(::Module, ::Symbol) at .\\loading.jl:923", + " [14] include_string(::Function, ::Module, ::String, ::String) at .\\loading.jl:1091", + " [15] execute_code(::String, ::String) at C:\\Users\\PC\\.julia\\packages\\IJulia\\rWZ9e\\src\\execute_request.jl:27", + " [16] execute_request(::ZMQ.Socket, ::IJulia.Msg) at C:\\Users\\PC\\.julia\\packages\\IJulia\\rWZ9e\\src\\execute_request.jl:86", + " [17] #invokelatest#1 at .\\essentials.jl:710 [inlined]", + " [18] invokelatest at .\\essentials.jl:709 [inlined]", + " [19] eventloop(::ZMQ.Socket) at C:\\Users\\PC\\.julia\\packages\\IJulia\\rWZ9e\\src\\eventloop.jl:8", + " [20] (::IJulia.var\"#15#18\")() at .\\task.jl:356" + ] + } + ], + "source": [ + "#using Pkg\n", + "#Pkg.add(\"Knet\")\n", + "using Knet\n", + "#You may see an error if your device does not support CUDA or your CUDA driver is not CUDA 10.1 or higher but you will be\n", + "#able to use all the functionalities, except GPU operations, in spite of this error" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating Our First Custom Layer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A sample dense layer:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "struct dense; w; b; f; end" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Definition of a sample dense layer includes w (weights), b (bias), f(activation function). Bias and activation functions are not necessary but the field \"w\" is needed in all custom layers to be manipulated during training process." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "(d::dense)(x) = d.f.(d.w * mat(x) .+ d.b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We create a functor (a callable object/ function-like object) that multiplies the input with its weights, adds bias, applies the given activation function and returns the results" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "dense(i::Int,o::Int,f=relu) = dense(param(o,i), param0(o), f);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We declare a constructor that utilizes built-in \"param\" and \"param0\" functions that return KnetArrays, powerful built-in array that have all the operations a Julia array has but also designed with a focus on GPU opearations, in the appropriate sizes. Usage of Knet arrays are not mandatory however highly encouraged due to performance improvement. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In addition, the constructor has a keyword-parameter named \"f\", whose default value is relu. Relu is one of the many built-in activation functions Knet has. Here is a list of all the built-in Knet functions: elu, relu, selu, sigmoid, gelu.\n", + "For further reference:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "No documentation found.\n", + "\n", + "Binding \\texttt{relu} does not exist.\n", + "\n" + ], + "text/markdown": [ + "No documentation found.\n", + "\n", + "Binding `relu` does not exist.\n" + ], + "text/plain": [ + " No documentation found.\n", + "\n", + " Binding \u001b[36mrelu\u001b[39m does not exist." + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@doc relu" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "No documentation found.\n", + "\n", + "Binding \\texttt{elu} does not exist.\n", + "\n" + ], + "text/markdown": [ + "No documentation found.\n", + "\n", + "Binding `elu` does not exist.\n" + ], + "text/plain": [ + " No documentation found.\n", + "\n", + " Binding \u001b[36melu\u001b[39m does not exist." + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@doc elu" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That is how custom layers are defined in Knet" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is another example custom layer:." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "struct Conv; w; b; f; end\n", + "(c::Conv)(x) = c.f.(pool(conv4(c.w, x) .+ c.b))\n", + "Conv(w1,w2,cx,cy,f=relu) = Conv(param(w1,w2,cx,cy), param0(1,1,cy,1), f);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As mentioned before, a struct with the fields including the \"w\" field representing the weights has been declared. Then, a function-like object that takes an input (matrix, number or vector) and outputs the result of the appliance of the inner logic. This struct makes use of the param and param0 as well. Since this is a convolutional layer, the calculation has different steps. For further reference:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "No documentation found.\n", + "\n", + "Binding \\texttt{conv4} does not exist.\n", + "\n" + ], + "text/markdown": [ + "No documentation found.\n", + "\n", + "Binding `conv4` does not exist.\n" + ], + "text/plain": [ + " No documentation found.\n", + "\n", + " Binding \u001b[36mconv4\u001b[39m does not exist." + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + " @doc conv4" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "No documentation found.\n", + "\n", + "Binding \\texttt{pool} does not exist.\n", + "\n" + ], + "text/markdown": [ + "No documentation found.\n", + "\n", + "Binding `pool` does not exist.\n" + ], + "text/plain": [ + " No documentation found.\n", + "\n", + " Binding \u001b[36mpool\u001b[39m does not exist." + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@doc pool" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Using built-in Layers\n", + "**A NOTE FOR THE DEVELOPER TEAMTo include this part, the [layers script](https://github.com/denizyuret/Knet.jl/blob/master/src/layers21/Layers21.jl) must export the layers**
\n", + "Knet offers the following built-in layers with a remarkable option of customization:\n", + "* [Dense](https://github.com/denizyuret/Knet.jl/blob/master/src/layers21/dense.jl)\n", + "* [Embed](https://github.com/denizyuret/Knet.jl/blob/master/src/layers21/embed.jl)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Dense Layer \n", + "Built-in Dense Layer has the following constructors:\n", + "\n", + "* function Dense(weights, bias=nothing; f=nothing, dims=1, dropout=0)\n", + "* function Dense(wsize::Integer...; f=nothing, dims=1, dropout=0, atype=atype(), binit=zeros, init=𝑼(√(6/(densein(wsize,dims)+denseout(wsize,dims)))))\n", + "\n", + "Although how confusion the definitions may seem at the first glance, they are fairly easy to use. \n", + "\n", + "Keyword arguments:\n", + "* `f=nothing`: apply activation function to output if not nothing\n", + "* `dims=1`: number of input dimensions in the weight tensor\n", + "* `dropout=0`: apply dropout with this probability to input if non-zero\n", + "* `atype=Knet.atype()`: array and element type for parameter initialization\n", + "* `init=𝑼(√(6/(fanin+fanout)))`: initialization function for weights\n", + "* `binit=zeros`: initialization function for bias, if `nothing` do not use bias\n", + "\n", + "Example:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "ename": "LoadError", + "evalue": "UndefVarError: relu not defined", + "output_type": "error", + "traceback": [ + "UndefVarError: relu not defined", + "", + "Stacktrace:", + " [1] top-level scope at In[10]:1", + " [2] include_string(::Function, ::Module, ::String, ::String) at .\\loading.jl:1091", + " [3] execute_code(::String, ::String) at C:\\Users\\PC\\.julia\\packages\\IJulia\\rWZ9e\\src\\execute_request.jl:27", + " [4] execute_request(::ZMQ.Socket, ::IJulia.Msg) at C:\\Users\\PC\\.julia\\packages\\IJulia\\rWZ9e\\src\\execute_request.jl:86", + " [5] #invokelatest#1 at .\\essentials.jl:710 [inlined]", + " [6] invokelatest at .\\essentials.jl:709 [inlined]", + " [7] eventloop(::ZMQ.Socket) at C:\\Users\\PC\\.julia\\packages\\IJulia\\rWZ9e\\src\\eventloop.jl:8", + " [8] (::IJulia.var\"#15#18\")() at .\\task.jl:356" + ] + } + ], + "source": [ + "dense_layer = Dense(2, dim = 2, f = relu)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Chaining Layers\n", + "To chain layers, one must declare a callable object that can iterate over the layers and output the final value or return the result of the cost function when (x,y) provided. Currently, Knet does not have a built-in model that is capable of these operations. An example is placed below:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "struct Chain; layers; Chain(args...)= new(args);end" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A simple struct that has a field layers which will hold the given layers as a tuple. " + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "(c::Chain)(x) = (for l in c.layers; x = l(x); end; x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A callable object is created that takes an input and applies the logic given in the layers in the given order" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "(c::Chain)(x,y) = nll(c(x),y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A callable object that returns the cost of a(x) and y (true) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating the model" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "ename": "LoadError", + "evalue": "UndefVarError: relu not defined", + "output_type": "error", + "traceback": [ + "UndefVarError: relu not defined", + "", + "Stacktrace:", + " [1] Conv(::Int64, ::Int64, ::Int64, ::Int64) at .\\In[7]:3", + " [2] top-level scope at In[14]:1", + " [3] include_string(::Function, ::Module, ::String, ::String) at .\\loading.jl:1091", + " [4] execute_code(::String, ::String) at C:\\Users\\PC\\.julia\\packages\\IJulia\\rWZ9e\\src\\execute_request.jl:27", + " [5] execute_request(::ZMQ.Socket, ::IJulia.Msg) at C:\\Users\\PC\\.julia\\packages\\IJulia\\rWZ9e\\src\\execute_request.jl:86", + " [6] #invokelatest#1 at .\\essentials.jl:710 [inlined]", + " [7] invokelatest at .\\essentials.jl:709 [inlined]", + " [8] eventloop(::ZMQ.Socket) at C:\\Users\\PC\\.julia\\packages\\IJulia\\rWZ9e\\src\\eventloop.jl:8", + " [9] (::IJulia.var\"#15#18\")() at .\\task.jl:356" + ] + } + ], + "source": [ + "LeNet = Chain(Conv(5,5,1,20), Conv(5,5,20,50), dense(800,500), dense(500,10,identity))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.5.2", + "language": "julia", + "name": "julia-1.5" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/tutorial/New Tutorials/Knet General Overview.ipynb b/tutorial/New Tutorials/Knet General Overview.ipynb new file mode 100644 index 000000000..2b48a4f62 --- /dev/null +++ b/tutorial/New Tutorials/Knet General Overview.ipynb @@ -0,0 +1,93 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Introduction to Knet\n", + "***\n", + "In this notebook, we aim to welcome the new users with a gentle introduction" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## What is Knet?\n", + "[Knet](https://github.com/denizyuret/Knet.jl) (pronounced \"kay-net\") is the Koç University deep learning framework implemented in [Julia](https://docs.julialang.org/en/v1/) by [Deniz Yuret](http://www.denizyuret.com/) and collaborators. It supports GPU operation and automatic differentiation using dynamic computational graphs for models defined in plain Julia. For reference, you may visit the [documentation](https://denizyuret.github.io/Knet.jl/latest/) and read the [paper](https://docs.google.com/viewer?a=v&pid=sites&srcid=ZGVmYXVsdGRvbWFpbnxtbHN5c25pcHMyMDE2fGd4OjI2YjI4NTZlNzNmNjg0Zjk)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## How to include Knet?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "using Pkg\n", + "Pkg.add(\"Knet\")\n", + "#using Knet" + ] + }, + { + "attachments": { + "image.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Important Points to Consider\n", + "* Because of the Julia's [approach to object oriented programming](https://docs.julialang.org/en/v1/manual/types/#Composite-Types), Knet differs from other deep learning frameworks by being built upon the usage of [callable objects](https://docs.julialang.org/en/v1/manual/methods/#Function-like-objects) instead of Python or C++ style classes. \n", + "* Knet is based on computation graphs and utilizes [Julia AutoGrad Package](https://github.com/denizyuret/AutoGrad.jl). \n", + "* Knet supports GPU operations, namely Cuda archtitecture, resulting in a remarkable performance depicted below:\n", + "
\n", + "\n", + "![image.png](attachment:image.png)\n", + "[image source](https://docs.google.com/viewer?a=v&pid=sites&srcid=ZGVmYXVsdGRvbWFpbnxtbHN5c25pcHMyMDE2fGd4OjI2YjI4NTZlNzNmNjg0Zjk)" + ] + }, + { + "attachments": { + "Knet%20Diagram.png": { + "image/png": "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THvttZc699xzzdTSZPn+eGaq8zacWonQ2dmpRowYYaakkzyyETlBWU6snKBVq1apMWPGmCmlyXbstrIcuGrGtGLFipqKpxbP0UCP6fLLL1c33XST2meffcxUN5I3S8EwGNRaTJyjweE3v/mNfvA+/PDDzZRkEr+kgVzmSSwTJ05UxxxzjJlSG2rt2qu1eEQtxiTlw7333qvvqTQSv71vB2r5IJUIUtZRPgxstRaPICaf/HB42mmnqfPOO89MKU220R/PTFQiOCo3JioRiMkqNyZbifDCCy+YqQCq5Y033lDbbrttTVYivP766zo2AOV588031TbbbFOTlQjSZHn77bc3UwFUy3777TcoKhHccwEAAAAAgCGNSgQAAAAAAOCESgQAAAAAAOCESgQAAAAAAOCESgQAAAAAAOCESgQAAAAAAOCESgQAAAAAAOCESgQAAAAAAOCESgQAAAAAAOCkvru7W6WlXC4XO73SqaurSzU0NMTOK5V6enpip5dK1Yqp1uKpxXM00GOS7QDoX1nv94Fc5kkCUDmUDwAqKev93h/PTHUdHR05s7+JJMOwYcPMX+kkEEn19dkaOsjyb7zxhtp6663NlHSyHSmMJaAsqhXTm2++GYpHDvprr72m1q9frzZs2KD++c9/qn//+9/qrbfeUps2bVKbN2/2T0xdnd6WxNXY2Ki22GIL9ba3vU29/e1vV9tss416xzveobbbbju15ZZb6vVyjmo3pmuvvVbddttt6sUXXzRTAVSLlA3bbrutmj9/vjrkkEPM1NIGepnX1tamJk2apF5//XUdG4DyyHc8+U4m/0YfdthhZmppA718ePTRR9UJJ5yg1q1bp7bffnszFUC17Lvvvqq5uVl97WtfM1PS9cczU523gpKVCDK7s7NTjRgxwkxJJ3kkGCkgs+ycPDyvWrVKjRkzxkwpTbZjtyUP2q76MqY1a9boh72XX35ZLVu2TP35z3/WlQYrVqxQHR0dulCOI/siFQVyAdh/WOw2pXJBKhnk+ERJJcKoUaN02m233dTuu++u9thjD7XnnnuqvffeW6c4rvFE1cI5ihroMV1++eXqpptuUi+88IKZCqBabCXC4sWL1eGHH26mJqt2+VBOmSexTJw4kUoEoJdsJcK9996r76k0g6F8WLJkiS7rqEQA+sd+++2nTjvtNHXeeeeZKaVVs3wIPjO5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SXa/sm5Hks3rmuw2APQv1/tdyGe1yodyyjxJACqH8gFAJWW9b0Xc9KRUbvkQyqO3OkiNGjVKDwd49913q7///e9qv/32U2effbZau3atWQL9SUZbkHNywQUXqBkzZqinnnpKffKTnzRzAQAAAACDTU1UNx5xxBF6KEj5hfuOO+7QIzrIg+sbb7xhlkA1zZ8/Xx100EHqc5/7nD43L7/8MqNqAAAAAEANqKk2S1OnTtUPrJdccon66U9/qnbZZRf9C7gMIYi+N3fuXD1yxoknnqhbIDz77LPq6quv1i1GAAAAAACDX02++DR9+nS1fPlyXZkgIwDIaA5nnnmmWrp0qVkClfKvf/1LD7+57777qlNPPVXtv//+utPEm266SY/CAAAAAACoHTVZiSCkw4dvfvObatmyZepnP/uZ+sMf/qA7YfzEJz6h5s2bZ5ZCuWSozbPOOkuNHDlSXXjhhbpzy7/+9a/6lRKpSAAAAAAA1J6arUQI+vznP69+//vfq0WLFulRAaZMmaKb2EuLhccff9wshTTr1q1T1157rWpqalIf/vCH9TG94oor1OrVq/UIDDL8JgAAAACgdg2JSgRLOvmT1xteffVV9fWvf13df//96iMf+Yg64IAD9KsPf/rTn8ySsN588011yy23qBNOOEHtuOOO6txzz1V77bWXevDBB3UFzFe+8hW1xRZbmKUBAAAAALVsSFUiWKNHj9avOsgrDo8++qiaOHGifodfmuG///3vV+edd5566KGHzNJDj7wCct1116lPfepTapttttGjLMi4oPIaiLRG+O53v6sOPfRQszQAAAAAYKgYkpUIQTKagDTJl/f5H374YXX00Ueru+66Sx122GFqp512UieddJL6yU9+op5//nmTo/bIUJgSs7zeIZUoe+65p25xIBUI0nJDWiPcfvvt+lhIXxMAAAAAgKGJJ8KAgw8+WF1++eXqmWeeUX/5y1/UBRdcoDo7O9W3v/1tPfrA7rvvrh+kf/jDH6q2tja1adMmk3NweeGFF/RwjF/72td03wbbbrut7hjxkUceUccee6y677771Pr16/UyJ598snr7299ucgIAAAAAhrK6rq6unPn/WLlcTm3evFk1NjaaKekkj7de3QQ+yy/XkkceXuXdexeyHUnd3d1q+PDhZmq6cmKS1x7kFQfpTFBSR0eHni6/3Et673vfq4c0lMoG6TNgIFi7dq1uQfHcc8+pZ599Vg+9+NRTT6nXXntNHy+pQDjooIPUIYccotP2229vciYbyOdI8tTadSd55PWRm2++WVf+AKguaaklFa333nuvmjBhgpmarNrlQzll3uLFi9VRRx2lXn/9dR0bgPJIS01ptXnPPffofrfSDIbyYcmSJerII4/Ur6+6fC8EUFn77befHjb/O9/5jplSWjXLh+AzU533MFyyEkFIhmHDhpm/0smOScqyU0KWly9sW2+9tZmSTrbT09OjD0IWvY3pH//4h34ol4dzeUiXlgsyTchJlFcCZLSCd77znWq33XZTu+yyix4RQoZElAMvBXO5v/DLhSJf/qSAX7NmjVq5cqVasWKF7jBS9kH6NJDXM2S+eMc73qErNyS95z3v0X0/vO9979PzavkcuRroMcmIGLfddpt68cUXzVQA1WIrEebPn68rW10M9DJPWtJNmjSJSgSgl2wlgvwbLa/Buhjo5YP8aCadaVOJAPQPeV5rbm7WLcZd9cczU523gtSWCNKkf8SIEWZKOskjwUgBmWXnpGZ21apVasyYMWZKabIdu62stS99EZP8YyK//MvD3ssvv6wf5uX/ZQhEeciX+UFSCy0nYautttL7IqMcyDRZf11dnf5HRrYpr0289dZb6t///rf65z//qf71r3+ZNfhkn6SzyF133VW/crHHHnvo1hB77723ete73qWnRw3VcxRnoMckr9hIx59Zv+xLXrmOakmtxcQ5GhxkJBr59f7www83U5JJ/JIGcpknsUiHwtIarZbU2rVXa/GIWoxJygdpqST3VBqJ3963A7V8kJYIUtZRPgxstRaPICafPC+edtppuqN/F7KN/nhmohLBUbkxSeWBjUcuCmk5IK8ZyC9A0hxEpkmlwMaNG/U+SSsDSbIdueikVklik32VlgtS4SAtC+SBcocddtCdP0rLBs5R7cYklQgbNmzIVAhJBZRcV66tK2Q7IuuvI5JPjl/W2k/ZjpyjoRxTrcUjajmm448/vqYqEe68806uPc9AjanW4hG1HJP0K1VLlQh33HEH156nmjFl2c5giIfyoXcxybMelQhl7pgL2Y7d1kAtjIOVCGkGQzy1eI6IiZiCqhUT54iYgojJR0w+zhExBRGTr5ZjytJHBueImIL6Kyb3XAAAAAAAYEijEgEAAAAAADihEgEA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" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## A sample program flow\n", + "![Knet%20Diagram.png](attachment:Knet%20Diagram.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.5.2", + "language": "julia", + "name": "julia-1.5" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}