///|
pub fn class_weight(
label : Int,
value : Double,
) -> Result[ClassWeight, SvmError] {
if !finite_double(value) || value <= 0.0 {
return Err(InvalidClassWeight(label, value))
}
Ok({ weighted_label: label, weight_value: value })
}
///|
pub fn ClassWeight::label(self : ClassWeight) -> Int {
self.weighted_label
}
///|
pub fn ClassWeight::value(self : ClassWeight) -> Double {
self.weight_value
}
///|
fn class_multiplier(label : Int, weights : Array[ClassWeight]) -> Double {
for weight in weights {
if weight.weighted_label == label {
return weight.weight_value
}
}
1.0
}
///|
fn validate_class_weights(
classes : Array[Int],
weights : Array[ClassWeight],
) -> Result[Unit, SvmError] {
for position, weight in weights {
let mut known = false
for label in classes {
if label == weight.weighted_label {
known = true
}
}
if !known {
return Err(UnknownClassLabel(weight.weighted_label))
}
for previous = 0; previous < position; previous = previous + 1 {
if weights[previous].weighted_label == weight.weighted_label {
return Err(DuplicateClassWeight(weight.weighted_label))
}
}
}
Ok(())
}
///|
/// Fits binary C-SVC with positive sample and optional class multipliers.
pub fn train_binary_weighted(
data : Dataset,
sample_weights : Array[Double],
class_weights : Array[ClassWeight],
config : BinaryConfig,
) -> Result[BinaryModel, SvmError] {
if sample_weights.length() != data.row_count() {
return Err(WeightLengthMismatch(data.row_count(), sample_weights.length()))
}
for index, value in sample_weights {
if !finite_double(value) || value <= 0.0 {
return Err(InvalidWeight(index, value))
}
}
let classes = data.classes()
match validate_class_weights(classes, class_weights) {
Err(error) => return Err(error)
Ok(_) => ()
}
let labels = data.labels()
let bounds = Array::make(data.row_count(), 0.0)
for index, sample_weight in sample_weights {
let effective = config.c() *
sample_weight *
class_multiplier(labels[index], class_weights)
if !finite_double(effective) || effective <= 0.0 {
return Err(ZeroEffectiveWeight)
}
bounds[index] = effective
}
train_binary_bounds(data, config, bounds)
}