///|
pub fn KernelDiagnostics::entry_count(self : KernelDiagnostics) -> Int {
self.matrix_entry_count
}
///|
pub fn KernelDiagnostics::minimum(self : KernelDiagnostics) -> Double {
self.smallest_entry
}
///|
pub fn KernelDiagnostics::maximum(self : KernelDiagnostics) -> Double {
self.largest_entry
}
///|
pub fn KernelDiagnostics::mean(self : KernelDiagnostics) -> Double {
self.average_entry
}
///|
pub fn KernelDiagnostics::diagonal_mean(self : KernelDiagnostics) -> Double {
self.average_diagonal
}
///|
pub fn KernelDiagnostics::maximum_symmetry_error(
self : KernelDiagnostics,
) -> Double {
self.largest_symmetry_error
}
///|
/// Computes finite summary statistics for the checked kernel matrix.
pub fn kernel_diagnostics(
data : Dataset,
kernel : Kernel,
) -> Result[KernelDiagnostics, SvmError] {
let matrix = match kernel_matrix(kernel, data) {
Err(error) => return Err(error)
Ok(value) => value
}
let count = matrix.length()
let mut minimum = matrix[0][0]
let mut maximum = matrix[0][0]
let mut total = 0.0
let mut diagonal_total = 0.0
let mut symmetry_error = 0.0
for row = 0; row < count; row = row + 1 {
diagonal_total = diagonal_total + matrix[row][row]
for column = 0; column < count; column = column + 1 {
let value = matrix[row][column]
if value < minimum {
minimum = value
}
if value > maximum {
maximum = value
}
total = total + value
let difference = value - matrix[column][row]
let error = if difference < 0.0 { -difference } else { difference }
if error > symmetry_error {
symmetry_error = error
}
}
}
Ok({
matrix_entry_count: count * count,
smallest_entry: minimum,
largest_entry: maximum,
average_entry: total / (count * count).to_double(),
average_diagonal: diagonal_total / count.to_double(),
largest_symmetry_error: symmetry_error,
})
}
///|
pub fn BinaryModelDiagnostics::support_vectors(
self : BinaryModelDiagnostics,
) -> Int {
self.retained_count
}
///|
pub fn BinaryModelDiagnostics::negative_support_vectors(
self : BinaryModelDiagnostics,
) -> Int {
self.lower_class_count
}
///|
pub fn BinaryModelDiagnostics::positive_support_vectors(
self : BinaryModelDiagnostics,
) -> Int {
self.upper_class_count
}
///|
pub fn BinaryModelDiagnostics::minimum_alpha(
self : BinaryModelDiagnostics,
) -> Double {
self.smallest_alpha
}
///|
pub fn BinaryModelDiagnostics::maximum_alpha(
self : BinaryModelDiagnostics,
) -> Double {
self.largest_alpha
}
///|
pub fn BinaryModelDiagnostics::mean_alpha(
self : BinaryModelDiagnostics,
) -> Double {
self.average_alpha
}
///|
/// Summarizes alpha magnitudes and original-class support counts.
pub fn binary_model_diagnostics(model : BinaryModel) -> BinaryModelDiagnostics {
let labels = model.support_labels()
let alphas = model.support_alphas()
let mut lower_count = 0
let mut upper_count = 0
let mut minimum = alphas[0]
let mut maximum = alphas[0]
let mut total = 0.0
for index, alpha in alphas {
if labels[index] == model.negative_class() {
lower_count = lower_count + 1
} else {
upper_count = upper_count + 1
}
if alpha < minimum {
minimum = alpha
}
if alpha > maximum {
maximum = alpha
}
total = total + alpha
}
{
retained_count: alphas.length(),
lower_class_count: lower_count,
upper_class_count: upper_count,
smallest_alpha: minimum,
largest_alpha: maximum,
average_alpha: total / alphas.length().to_double(),
}
}
///|
pub fn MarginDiagnostics::observation_count(self : MarginDiagnostics) -> Int {
self.fitted_observation_count
}
///|
pub fn MarginDiagnostics::misclassified_count(self : MarginDiagnostics) -> Int {
self.incorrect_count
}
///|
pub fn MarginDiagnostics::margin_violation_count(
self : MarginDiagnostics,
) -> Int {
self.violating_count
}
///|
pub fn MarginDiagnostics::minimum_margin(self : MarginDiagnostics) -> Double {
self.smallest_margin
}
///|
pub fn MarginDiagnostics::maximum_margin(self : MarginDiagnostics) -> Double {
self.largest_margin
}
///|
pub fn MarginDiagnostics::mean_margin(self : MarginDiagnostics) -> Double {
self.average_margin
}
///|
/// Computes y*f(x) for observations belonging to the model's two classes.
pub fn training_margin_diagnostics(
model : BinaryModel,
data : Dataset,
) -> Result[MarginDiagnostics, SvmError] {
if data.feature_count() != model.feature_count() {
return Err(
PredictionDimensionMismatch(model.feature_count(), data.feature_count()),
)
}
let rows = data.features()
let labels = data.labels()
let mut minimum = 0.0
let mut maximum = 0.0
let mut total = 0.0
let mut incorrect = 0
let mut violations = 0
for index, label in labels {
let sign = if label == model.negative_class() {
-1.0
} else if label == model.positive_class() {
1.0
} else {
return Err(UnknownClassLabel(label))
}
let decision = match model.decision_value(rows[index]) {
Err(error) => return Err(error)
Ok(value) => value
}
let margin = sign * decision
if index == 0 || margin < minimum {
minimum = margin
}
if index == 0 || margin > maximum {
maximum = margin
}
if margin <= 0.0 {
incorrect = incorrect + 1
}
if margin < 1.0 {
violations = violations + 1
}
total = total + margin
}
Ok({
fitted_observation_count: rows.length(),
incorrect_count: incorrect,
violating_count: violations,
smallest_margin: minimum,
largest_margin: maximum,
average_margin: total / rows.length().to_double(),
})
}
///|
pub fn MulticlassModelDiagnostics::class_count(
self : MulticlassModelDiagnostics,
) -> Int {
self.fitted_class_count
}
///|
pub fn MulticlassModelDiagnostics::support_counts(
self : MulticlassModelDiagnostics,
) -> Array[Int] {
self.retained_support_counts.copy()
}
///|
pub fn MulticlassModelDiagnostics::convergence_reports(
self : MulticlassModelDiagnostics,
) -> Array[ConvergenceReport] {
self.fitted_convergence_reports.copy()
}
///|
pub fn MulticlassModelDiagnostics::total_support_vectors(
self : MulticlassModelDiagnostics,
) -> Int {
self.retained_support_total
}
///|
pub fn MulticlassModelDiagnostics::all_converged(
self : MulticlassModelDiagnostics,
) -> Bool {
self.every_model_converged
}
///|
/// Aggregates support counts and convergence reports in sorted class order.
pub fn multiclass_model_diagnostics(
model : MulticlassModel,
) -> MulticlassModelDiagnostics {
let models = model.binary_models()
let counts : Array[Int] = []
let reports : Array[ConvergenceReport] = []
let mut total = 0
let mut converged = true
for binary in models {
let count = binary.support_vector_count()
let report = binary.convergence()
counts.push(count)
reports.push(report)
total = total + count
if !report.converged() {
converged = false
}
}
{
fitted_class_count: model.model_count(),
retained_support_counts: counts,
fitted_convergence_reports: reports,
retained_support_total: total,
every_model_converged: converged,
}
}