stats API
Luna-Flow/mare_mark/stats は計時値の配列を、記述統計の要約、対応のある比較、シード付きのブートストラップ区間、外れ値をフィルタリングしたビューに変換します。すべての関数は純粋で、引数を読み、結果を割り当て、イベントストリームには一切触れません。各推定量の背後にある数学は stats の設計で導出しています。
ソース: src/stats/stats.mbt。
import {
"Luna-Flow/mare_mark/model",
"Luna-Flow/mare_mark/stats",
}
記述統計の要約
SummaryStats
SummaryStats は 1 つの標本の記述統計を保持します。
pub struct SummaryStats {
count : Int
min : Double
max : Double
mean : Double
median : Double
mad : Double
q1 : Double
q3 : Double
iqr : Double
std_dev : Double
}
順序統計量 を持つ標本 について、各フィールドは次のとおりです:
| フィールド | 定義 |
|---|---|
count | |
min, max | , |
mean | |
median | |
q1, q3 | , |
iqr | |
mad | の中央値。正規一致化係数 は掛けません |
std_dev | 母標準偏差 |
は線形補間した標本分位点(Hyndman–Fan のタイプ 7)です。 として、
フィールドはパッケージ外からは読み取り専用で、値は summarize によって生成されます。
summarize
summarize は値の配列に対する SummaryStats を計算します。
pub fn summarize(Array[Double]) -> SummaryStats
入力はソートの前にコピーされるため、呼び出し側の配列の順序は保たれます。空の配列では count == 0 となり、他のフィールドはすべて 0.0 になります。他のフィールドを読む前に count を確認してください。有限でない値は拒否されません。NaN があると平均と標準偏差は NaN になり、ソートにおけるその位置は未規定になります。コスト: 2 回のソートに の時間、 の追加領域。
test "summarize a sample" {
let summary = @stats.summarize([4.0, 1.0, 3.0, 2.0, 100.0])
inspect(summary.count, content="5")
inspect(summary.median, content="3")
inspect(summary.q1, content="2")
inspect(summary.q3, content="4")
inspect(summary.mad, content="1")
inspect(summary.mean, content="22")
}
平均は 1 つの遅い値に引っ張られて 22 になりますが、中央値、四分位数、MAD はそうなりません。以下の比較が中央値に基づいて構築されているのはそのためです。
対応のある比較
Decision
Decision は対応のある比較の判定です。
pub enum Decision {
Faster
Slower
Equivalent
Invalid
Unknown
}
| コンストラクタ | 意味 |
|---|---|
Faster | 中央値の相対差が 以下 |
Slower | 中央値の相対差が 以上 |
Equivalent | 中央値の相対差が と の間に厳密に収まる |
Invalid | 2 つの配列の長さが異なる |
Unknown | ペアが 1 つもない |
ここで は practical_delta_pct として渡される実用的な閾値です。Decision はパッケージ外からは読み取り専用です。パターンマッチはできますが、構築はできません。
Interval
Interval は、属するフェーズのラベルが付いた上下限の組です。
pub struct Interval {
low : Double
high : Double
mode : @model.IntervalMode
}
compare_paired はこれをペアごとの差の四分位範囲で埋めます。bootstrap_interval と compare_paired_with_bootstrap はパーセンタイル・ブートストラップ区間で埋めます。mode は呼び出し側からコピーされるラベルで、計算には影響しません。
Comparison
Comparison は候補をベースラインと比較した結果です。
pub struct Comparison {
baseline_id : String
candidate_id : String
relative_delta_pct : Double
speedup : Double
interval : Interval
decision : Decision
valid_samples : Int
}
| フィールド | 意味 |
|---|---|
relative_delta_pct | 。 のときは 0.0 |
speedup | 。 のときは 1.0 |
interval | ペアごとの差に対する上下限。単位は入力と同じです(例えば µs) |
decision | 上で説明した Decision |
valid_samples | ペアの数 |
はベースラインの配列、 は候補の配列、 はペアごとの差です。speedup が 1.0 を上回るのは、候補の方が速いことを意味します。
paired_deltas
paired_deltas は、同じインデックスにある候補の値から各ベースラインの値を引きます。
pub fn paired_deltas(Array[Double], Array[Double]) -> Array[Double]
第 1 引数がベースライン、第 2 引数が候補です。結果は 個の要素を持ちます。長い方の配列の余った値は無視されるため、長さの不一致をエラーとしたい場合は自分で長さを確認してください。
compare_paired
compare_paired は、揃えられた 2 つの計時値の配列を実用的な閾値を用いて比較します。
pub fn compare_paired(String, String, Array[Double], Array[Double], Double, @model.IntervalMode) -> Comparison
引数: ベースライン ID、候補 ID、ベースラインの値、候補の値、パーセント単位の実用的な閾値 、区間のラベル。両方の配列のインデックス は、同じデータセット、反復、ブロックを表していなければなりません。判断には点推定値 だけを使います。区間は差の四分位範囲 で、記述的なものであり信頼区間ではありません。
test "paired comparison" {
let baseline = [100.0, 102.0, 98.0, 101.0, 99.0, 103.0, 97.0, 100.0]
let candidate = [90.0, 93.0, 88.0, 92.0, 91.0, 94.0, 87.0, 90.0]
let comparison = @stats.compare_paired(
"baseline",
"candidate",
baseline,
candidate,
2.0,
@model.confirmatory_interval(),
)
inspect(comparison.relative_delta_pct, content="-9.5")
inspect(comparison.speedup, content="1.1049723756906078")
inspect(comparison.interval.low, content="-10")
inspect(comparison.interval.high, content="-9")
inspect(@stats.is_faster(comparison), content="true")
}
is_faster
is_faster は比較の判断が Faster かどうかを報告します。
pub fn is_faster(Comparison) -> Bool
これはダッシュボードやゲートのための簡便な関数です。その横に Comparison 全体を記録してください。false は Slower、Equivalent、Invalid、Unknown をすべて区別なく含みます。
ブートストラップ区間
BootstrapError
BootstrapError はブートストラップ区間を計算できなかった理由を説明します。
pub(all) enum BootstrapError {
EmptySamples
MismatchedPairs(Int, Int)
InvalidResamples(Int)
InvalidConfidence(Double)
NonFiniteSample(Int)
}
| コンストラクタ | 発生条件 |
|---|---|
EmptySamples | 再標本化するものがない |
MismatchedPairs(baseline, candidate) | ペアの配列の長さが異なる |
InvalidResamples(count) | 再標本化の回数が正でない |
InvalidConfidence(pct) | 信頼水準が 0 と 100 の間に厳密に収まる有限の数でない |
NonFiniteSample(index) | index の値が NaN または無限大 |
bootstrap_interval
bootstrap_interval は、標本の中央値に対するシード付きのパーセンタイル・ブートストラップ区間を計算します。
pub fn bootstrap_interval(Array[Double], UInt64, Int, Double, @model.IntervalMode) -> Result[Interval, BootstrapError]
引数: 値、シード、再標本化の回数 、パーセント単位の信頼水準 、区間のラベル。この関数はサイズ の再標本を復元抽出で 個引き、それぞれの中央値を取り、それらの中央値のタイプ 7 分位点を と で返します。ここで です。検査は空の入力、再標本化の回数、信頼水準、有限性の順に行われ、最初の失敗が返されます。
結果は引数だけの関数です。同じ値、シード、、 からはどのターゲットでも同じ上下限が得られます。上下限は常に low high を満たします。シード 0 は固定の非ゼロ定数に置き換えられます。コスト: の時間と の領域。
test "bootstrap interval of a median" {
let deltas = [-10.0, -9.0, -10.0, -9.0, -8.0, -9.0, -10.0, -10.0]
let interval = @stats.bootstrap_interval(
deltas,
42UL,
1000,
95.0,
@model.confirmatory_interval(),
).unwrap()
inspect(interval.low, content="-10")
inspect(interval.high, content="-9")
let error = @stats.bootstrap_interval(
deltas,
42UL,
1000,
100.0,
@model.confirmatory_interval(),
)
inspect(error is Err(@stats.BootstrapError::InvalidConfidence(_)), content="true")
}
compare_paired_with_bootstrap
compare_paired_with_bootstrap は、compare_paired の四分位区間を、ペアごとの差の中央値に対するブートストラップ区間に置き換えたものです。
pub fn compare_paired_with_bootstrap(String, String, Array[Double], Array[Double], Double, @model.IntervalMode, UInt64, Int, Double) -> Result[Comparison, BootstrapError]
最初の 6 つの引数は compare_paired と同じで、最後の 3 つはシード、再標本化の回数、パーセント単位の信頼水準です。compare_paired と異なり、長さの不一致はエラー(MismatchedPairs)になり、空の配列もエラー(EmptySamples)になります。relative_delta_pct、speedup、decision、valid_samples は compare_paired と同じで、変わるのは interval だけです。区間は入力の単位ですが、判断はパーセント単位です。
test "paired comparison with a bootstrap interval" {
let baseline = [100.0, 102.0, 98.0, 101.0, 99.0, 103.0, 97.0, 100.0]
let candidate = [90.0, 93.0, 88.0, 92.0, 91.0, 94.0, 87.0, 90.0]
let comparison = @stats.compare_paired_with_bootstrap(
"baseline",
"candidate",
baseline,
candidate,
2.0,
@model.confirmatory_interval(),
7UL,
2000,
95.0,
).unwrap()
inspect(comparison.decision is Faster, content="true")
inspect(comparison.interval.low, content="-10")
inspect(comparison.interval.high, content="-9")
}
外れ値のビュー
filter_outliers
filter_outliers は、外れ値ポリシーが残す値を元の順序で返します。
pub fn filter_outliers(Array[Double], @model.OutlierPolicy) -> Array[Double]
| ポリシー | 残る値 |
|---|---|
ReportOnly | すべての値(コピー) |
TukeyFence | |
MADTrim |
入力の配列は決して変更されません。値の半数を超えるものが等しい場合、MAD は 0 となり、MADTrim は中央値と等しい値だけを残します。結果は派生したビューとして使い、生の観測は保持してください。
test "outlier views" {
let values = [10.0, 11.0, 10.0, 12.0, 11.0, 48.0]
debug_inspect(
@stats.filter_outliers(values, @model.OutlierPolicy::TukeyFence),
content="[10, 11, 10, 12, 11]",
)
inspect(values.length(), content="6")
}