///|
pub fn FeatureProfile::feature_index(self : FeatureProfile) -> Int {
self.source_column
}
///|
pub fn FeatureProfile::minimum(self : FeatureProfile) -> Double {
self.minimum_value
}
///|
pub fn FeatureProfile::maximum(self : FeatureProfile) -> Double {
self.maximum_value
}
///|
pub fn FeatureProfile::mean(self : FeatureProfile) -> Double {
self.arithmetic_mean
}
///|
pub fn FeatureProfile::variance(self : FeatureProfile) -> Double {
self.population_variance
}
///|
pub fn FeatureProfile::standard_deviation(self : FeatureProfile) -> Double {
self.population_standard_deviation
}
///|
pub fn FeatureProfile::is_constant(self : FeatureProfile) -> Bool {
self.constant_column
}
///|
pub fn ClassProfile::label(self : ClassProfile) -> Int {
self.class_label
}
///|
pub fn ClassProfile::count(self : ClassProfile) -> Int {
self.observation_count
}
///|
pub fn ClassProfile::proportion(self : ClassProfile) -> Double {
self.observation_proportion
}
///|
pub fn DatasetProfile::name(self : DatasetProfile) -> String {
self.source_name
}
///|
pub fn DatasetProfile::row_count(self : DatasetProfile) -> Int {
self.source_row_count
}
///|
pub fn DatasetProfile::feature_count(self : DatasetProfile) -> Int {
self.source_feature_count
}
///|
pub fn DatasetProfile::class_count(self : DatasetProfile) -> Int {
self.source_class_count
}
///|
pub fn DatasetProfile::features(self : DatasetProfile) -> Array[FeatureProfile] {
self.feature_profiles.copy()
}
///|
pub fn DatasetProfile::classes(self : DatasetProfile) -> Array[ClassProfile] {
self.class_profiles.copy()
}
///|
pub fn DatasetProfile::centroid(self : DatasetProfile) -> Array[Double] {
self.feature_centroid.copy()
}
///|
pub fn DatasetProfile::minimum_squared_norm(self : DatasetProfile) -> Double {
self.smallest_squared_row_norm
}
///|
pub fn DatasetProfile::maximum_squared_norm(self : DatasetProfile) -> Double {
self.largest_squared_row_norm
}
///|
pub fn DatasetProfile::mean_squared_norm(self : DatasetProfile) -> Double {
self.average_squared_row_norm
}
///|
fn summarize_feature(
rows : Array[Array[Double]],
column : Int,
) -> FeatureProfile {
let mut minimum = rows[0][column]
let mut maximum = rows[0][column]
let mut total = 0.0
for row in rows {
let value = row[column]
if value < minimum {
minimum = value
}
if value > maximum {
maximum = value
}
total = total + value
}
let mean = total / rows.length().to_double()
let mut squared_total = 0.0
for row in rows {
let difference = row[column] - mean
squared_total = squared_total + difference * difference
}
let variance = squared_total / rows.length().to_double()
{
source_column: column,
minimum_value: minimum,
maximum_value: maximum,
arithmetic_mean: mean,
population_variance: variance,
population_standard_deviation: variance.sqrt(),
constant_column: minimum == maximum,
}
}
///|
fn summarize_classes(data : Dataset) -> Array[ClassProfile] {
let profiles : Array[ClassProfile] = []
for label in data.classes() {
let count = data.class_count(label)
profiles.push({
class_label: label,
observation_count: count,
observation_proportion: count.to_double() / data.row_count().to_double(),
})
}
profiles
}
///|
/// Computes reproducible descriptive statistics from validated dense data.
pub fn dataset_profile(data : Dataset) -> DatasetProfile {
let rows = data.features()
let features : Array[FeatureProfile] = []
let centroid = Array::make(data.feature_count(), 0.0)
for column = 0; column < data.feature_count(); column = column + 1 {
let feature = summarize_feature(rows, column)
features.push(feature)
centroid[column] = feature.mean()
}
let mut minimum_norm = 0.0
let mut maximum_norm = 0.0
let mut norm_total = 0.0
for row_index, row in rows {
let mut squared_norm = 0.0
for value in row {
squared_norm = squared_norm + value * value
}
if row_index == 0 || squared_norm < minimum_norm {
minimum_norm = squared_norm
}
if row_index == 0 || squared_norm > maximum_norm {
maximum_norm = squared_norm
}
norm_total = norm_total + squared_norm
}
{
source_name: data.name(),
source_row_count: data.row_count(),
source_feature_count: data.feature_count(),
source_class_count: data.classes().length(),
feature_profiles: features,
class_profiles: summarize_classes(data),
feature_centroid: centroid,
smallest_squared_row_norm: minimum_norm,
largest_squared_row_norm: maximum_norm,
average_squared_row_norm: norm_total / data.row_count().to_double(),
}
}
///|
pub fn WeightProfile::count(self : WeightProfile) -> Int {
self.weight_count
}
///|
pub fn WeightProfile::minimum(self : WeightProfile) -> Double {
self.minimum_weight
}
///|
pub fn WeightProfile::maximum(self : WeightProfile) -> Double {
self.maximum_weight
}
///|
pub fn WeightProfile::total(self : WeightProfile) -> Double {
self.total_weight
}
///|
pub fn WeightProfile::mean(self : WeightProfile) -> Double {
self.average_weight
}
///|
pub fn WeightProfile::effective_sample_size(self : WeightProfile) -> Double {
self.effective_observation_count
}
///|
/// Computes Kish's effective sample size for finite positive weights.
pub fn weight_profile(
weights : Array[Double],
) -> Result[WeightProfile, SvmError] {
if weights.is_empty() {
return Err(EmptyMetricInput)
}
let mut minimum = weights[0]
let mut maximum = weights[0]
let mut total = 0.0
let mut squared_total = 0.0
for index, value in weights {
if !finite_double(value) || value <= 0.0 {
return Err(InvalidWeight(index, value))
}
if value < minimum {
minimum = value
}
if value > maximum {
maximum = value
}
total = total + value
squared_total = squared_total + value * value
}
Ok({
weight_count: weights.length(),
minimum_weight: minimum,
maximum_weight: maximum,
total_weight: total,
average_weight: total / weights.length().to_double(),
effective_observation_count: total * total / squared_total,
})
}