///|
pub fn sum_finite(values : ArrayView[Double]) -> Double {
let mut total = 0.0
for value in values {
if is_finite(value) {
total += value
}
}
total
}
///|
pub fn count_finite(values : ArrayView[Double]) -> Int {
let mut count = 0
for value in values {
if is_finite(value) {
count += 1
}
}
count
}
///|
pub fn minimum_finite(values : ArrayView[Double]) -> Double {
let mut found = false
let mut result = 0.0
for value in values {
if is_finite(value) && (!found || value < result) {
result = value
found = true
}
}
result
}
///|
pub fn maximum_finite(values : ArrayView[Double]) -> Double {
let mut found = false
let mut result = 0.0
for value in values {
if is_finite(value) && (!found || value > result) {
result = value
found = true
}
}
result
}
///|
pub fn centered_values(
values : ArrayView[Double],
center : Double,
) -> Array[Double] {
let output : Array[Double] = []
for value in values {
if is_finite(value) {
output.push(value - center)
}
}
output
}
///|
pub fn mean_absolute_deviation(
values : ArrayView[Double],
center? : Double,
) -> Double {
let chosen = match center {
Some(value) => value
None => median(values)
}
let mut total = 0.0
let mut count = 0
for value in values {
if is_finite(value) {
total += (value - chosen).abs()
count += 1
}
}
if count == 0 {
0.0
} else {
total / Double::from_int(count)
}
}
///|
pub fn median_absolute_deviation(values : ArrayView[Double]) -> Double {
let center = median(values)
let deviations : Array[Double] = []
for value in values {
if is_finite(value) {
deviations.push((value - center).abs())
}
}
median(deviations)
}
///|
pub fn robust_z_score(value : Double, values : ArrayView[Double]) -> Double {
let center = median(values)
let scale = median_absolute_deviation(values) * 1.4826
z_score(value, center, scale)
}
///|
pub fn outlier_report(
values : ArrayView[Double],
threshold? : Double = 3.5,
) -> OutlierReport {
let center = median(values)
let scale = median_absolute_deviation(values) * 1.4826
let indices : Array[Int] = []
if scale > 0.0 {
for i in 0.. threshold {
indices.push(i)
}
}
}
{ indices, center, scale }
}
///|
pub fn covariance_summary(
x : ArrayView[Double],
y : ArrayView[Double],
) -> CovarianceSummary {
let n = Int::min(x.length(), y.length())
let mut count = 0
let mut sx = 0.0
let mut sy = 0.0
for i in 0.. Regression {
let n = Int::min(x.length(), y.length())
let mut count = 0
let mut sx = 0.0
let mut sy = 0.0
for i in 0.. Double {
model.intercept + model.slope * x
}
///|
pub fn regression_residuals(
model : Regression,
x : ArrayView[Double],
y : ArrayView[Double],
) -> Array[Double] {
let output : Array[Double] = []
let n = Int::min(x.length(), y.length())
for i in 0.. Array[HistogramBin] {
let output : Array[HistogramBin] = []
if bins <= 0 {
output
} else {
let s = summary(values)
let selected = match range {
Some(value) => value
None => make_range(minimum=s.minimum, maximum=s.maximum)
}
let width = (selected.maximum - selected.minimum) / Double::from_int(bins)
for i in 0.. 0.0 {
for value in values {
if is_finite(value) && range_contains(selected, value) {
let index = Int::min(
bins - 1,
((value - selected.minimum) / width).floor().to_int(),
)
output[index] = { ..output[index], count: output[index].count + 1 }
}
}
}
output
}
}
///|
pub fn empirical_cdf(values : ArrayView[Double], query : Double) -> Double {
let mut count = 0
let mut total = 0
for value in values {
if is_finite(value) {
total += 1
if value <= query {
count += 1
}
}
}
if total == 0 {
0.0
} else {
Double::from_int(count) / Double::from_int(total)
}
}
///|
pub fn rank_values(values : ArrayView[Double]) -> Array[Double] {
let output : Array[Double] = []
for value in values {
let mut lower = 0
let mut equal = 0
if is_finite(value) {
for other in values {
if is_finite(other) {
if other < value {
lower += 1
}
if other == value {
equal += 1
}
}
}
output.push(Double::from_int(lower) + Double::from_int(equal + 1) / 2.0)
} else {
output.push(0.0)
}
}
output
}
///|
pub fn winsorize(
values : ArrayView[Double],
lower_fraction : Double,
upper_fraction : Double,
) -> Array[Double] {
let low = percentile(values, lower_fraction)
let high = percentile(values, upper_fraction)
let output : Array[Double] = []
for value in values {
if is_finite(value) {
output.push(value.clamp(min=low, max=high))
} else {
output.push(value)
}
}
output
}
///|
pub fn trim_values(
values : ArrayView[Double],
fraction : Double,
) -> Array[Double] {
let low = percentile(values, fraction)
let high = percentile(values, 1.0 - fraction)
let output : Array[Double] = []
for value in values {
if is_finite(value) && value >= low && value <= high {
output.push(value)
}
}
output
}
///|
pub fn weighted_variance(
values : ArrayView[Double],
weights : ArrayView[Double],
) -> Double {
let mean = weighted_mean(values, weights)
let mut total = 0.0
let mut weight_total = 0.0
let n = Int::min(values.length(), weights.length())
for i in 0.. 0.0 {
let d = values[i] - mean
total += weights[i] * d * d
weight_total += weights[i]
}
}
if weight_total == 0.0 {
0.0
} else {
total / weight_total
}
}
///|
pub fn normalize_min_max(
values : ArrayView[Double],
lower : Double,
upper : Double,
) -> Array[Double] {
let s = summary(values)
let output : Array[Double] = []
if s.maximum == s.minimum {
for value in values {
if is_finite(value) {
output.push((lower + upper) / 2.0)
} else {
output.push(value)
}
}
} else {
for value in values {
if is_finite(value) {
output.push(
lower +
(value - s.minimum) * (upper - lower) / (s.maximum - s.minimum),
)
} else {
output.push(value)
}
}
}
output
}