///|
pub fn median(values : Array[Double]) -> Double {
quantile(values, 0.5)
}
///|
pub fn median_absolute_deviation(values : Array[Double]) -> Double {
let center = median(values)
let deviations = Array::new(capacity=values.length())
for value in values {
deviations.push((value - center).abs())
}
median(deviations)
}
///|
pub fn trimmed_mean(values : Array[Double], trim_fraction : Double) -> Double {
if values.length() == 0 {
return 0.0
}
let sorted = values.copy()
for i in 1.. 0 && sorted[j - 1] > key {
sorted[j] = sorted[j - 1]
j -= 1
}
sorted[j] = key
}
let fraction = clamp(trim_fraction, 0.0, 0.49)
let cut = (sorted.length().to_double() * fraction).to_int()
let remaining = Array::new()
for i in cut..<(sorted.length() - cut) {
remaining.push(sorted[i])
}
mean(remaining)
}
///|
pub fn winsorized_mean(
values : Array[Double],
trim_fraction : Double,
) -> Double {
mean(winsorize(values, trim_fraction, 1.0 - clamp(trim_fraction, 0.0, 0.49)))
}
///|
pub fn weighted_quantile(
values : Array[Double],
weights : Array[Double],
probability : Double,
) -> Double {
if values.length() == 0 || values.length() != weights.length() {
return 0.0
}
let order = Array::new(capacity=values.length())
for i in 0.. 0 && values[order[j - 1]] > values[key] {
order[j] = order[j - 1]
j -= 1
}
order[j] = key
}
let target = clamp(probability, 0.0, 1.0) * sum(weights)
let mut cumulative = 0.0
for index in order {
cumulative += weights[index]
if cumulative >= target {
return values[index]
}
}
values[order[order.length() - 1]]
}
///|
pub fn empirical_cdf(
values : Array[Double],
points : Array[Double],
) -> Array[Double] {
let result = Array::new(capacity=points.length())
for point in points {
let mut count = 0
for value in values {
if value <= point {
count += 1
}
}
result.push(
if values.length() == 0 {
0.0
} else {
count.to_double() / values.length().to_double()
},
)
}
result
}
///|
pub fn standardized_mean_difference_from_groups(
treated : Array[Double],
control : Array[Double],
) -> Double {
let pooled = (variance(treated) + variance(control)) / 2.0
if pooled <= 0.0 {
0.0
} else {
(mean(treated) - mean(control)) / pooled.sqrt()
}
}
///|
pub fn robust_z_scores(values : Array[Double]) -> Array[Double] {
let center = median(values)
let scale = median_absolute_deviation(values) * 1.4826
let result = Array::new(capacity=values.length())
for value in values {
result.push(if scale == 0.0 { 0.0 } else { (value - center) / scale })
}
result
}
///|
pub fn outlier_indices(
values : Array[Double],
threshold : Double,
) -> Array[Int] {
let z = robust_z_scores(values)
let result = Array::new()
for i in 0.. threshold {
result.push(i)
}
}
result
}