///|
pub struct ReservoirSample {
capacity : Int
values : Array[Double]
mut seen : Int
rng : DeterministicRng
}
///|
pub fn ReservoirSample::new(
capacity : Int,
seed? : Int64 = 29L,
) -> ReservoirSample {
{
capacity: if capacity < 1 {
1
} else {
capacity
},
values: [],
seen: 0,
rng: DeterministicRng::new(seed~),
}
}
///|
pub fn ReservoirSample::push(self : ReservoirSample, value : Double) -> Unit {
if !is_finite(value) {
return
}
self.seen += 1
if self.values.length() < self.capacity {
self.values.push(value)
} else {
let index = (self.rng.next() % self.seen.to_int64()).to_int()
if index < self.capacity {
self.values[index] = value
}
}
}
///|
pub fn ReservoirSample::seen(self : ReservoirSample) -> Int {
self.seen
}
///|
pub fn ReservoirSample::values(self : ReservoirSample) -> Array[Double] {
sorted_copy(self.values)
}
///|
pub struct BootstrapEstimate {
mean : Double
lower : Double
upper : Double
standard_error : Double
replicates : Int
}
///|
pub fn bootstrap_mean(
values : Array[Double],
replicates? : Int = 100,
seed? : Int64 = 31L,
) -> BootstrapEstimate {
if values.length() == 0 {
return {
mean: 0.0,
lower: 0.0,
upper: 0.0,
standard_error: 0.0,
replicates: 0,
}
}
let rng = DeterministicRng::new(seed~)
let size = if replicates < 1 { 1 } else { replicates }
let estimates : Array[Double] = []
for _ in 0.. BootstrapEstimate {
if left.length() == 0 || right.length() == 0 {
return {
mean: 0.0,
lower: 0.0,
upper: 0.0,
standard_error: 0.0,
replicates: 0,
}
}
let rng = DeterministicRng::new(seed~)
let size = if replicates < 1 { 1 } else { replicates }
let scores : Array[Double] = []
for _ in 0.. (Array[Double], Array[Double]) {
let split = (values.length().to_double() * clamp_probability(train_fraction)).to_int()
let train : Array[Double] = []
let holdout : Array[Double] = []
for i, value in values {
if i < split {
train.push(value)
} else {
holdout.push(value)
}
}
(train, holdout)
}
///|
pub fn rolling_origins(
length : Int,
train_size : Int,
horizon : Int,
step? : Int = 1,
) -> Array[SegmentRange] {
let result : Array[SegmentRange] = []
let safe_step = if step < 1 { 1 } else { step }
let mut origin = if train_size < 1 { 1 } else { train_size }
while origin + horizon <= length {
result.push({ start: origin - train_size, end: origin + horizon })
origin += safe_step
}
result
}
///|
pub fn stratified_counts(values : Array[Double], bins : Int) -> Array[Int] {
let result = Array::make(if bins < 1 { 1 } else { bins }, 0)
if values.length() == 0 {
return result
}
let low = array_minimum(values)
let high = array_maximum(values)
let range = high - low
for value in values {
let index = if range <= 1.0e-12 {
0
} else {
((value - low) / range * result.length().to_double()).to_int()
}
let safe = if index >= result.length() {
result.length() - 1
} else if index < 0 {
0
} else {
index
}
result[safe] += 1
}
result
}