17 个不稳定版本 (6 个破坏性更新)
使用旧的 Rust 2015
0.7.1 | 2018年3月1日 |
---|---|
0.7.0 | 2017年12月11日 |
0.6.3 | 2017年12月6日 |
0.6.2 | 2017年11月20日 |
0.1.4 | 2016年7月1日 |
#164 in 算法
5,141 每月下载量
用于 13 个包 (9 个直接)
86KB
1.5K SLoC
quantiles
这个包旨在成为一组提供空间和计算保证的近似分位数算法的集合。最近的研究已经推动了近似技术,但没有一个是普遍适用的,并且有基本的权衡。
最初的工作是为了支持内部 Postmates 项目,但希望这个包可以普遍有用。
算法
CKMS - 在数据流上有效计算有偏分位数
这是 Cormode, Korn, Muthukrishnan, Srivastava 的论文 "在数据流上有效计算有偏分位数" 中提出的算法的实现。这里的雄心是近似数据流上的分位数,而不需要在内存中保留大量信息。这个实现遵循了 IEEE 版本 的论文。作者的自行出版版本是不正确的,如果使用该版本进行跟随,这个实现将 不会 有意义。只使用了 'full biased' 不变量。这个算法的 'targeted quantiles' 变体在本质上是有缺陷的,这是作者在 "在数据流上有偏分位数的时间和空间效率高的确定性算法" 中纠正的问题。
use quantiles::CKMS;
let mut ckms = CKMS::<u16>::new(0.001);
for i in 1..1001 {
ckms.insert(i as u16);
}
assert_eq!(ckms.query(0.0), Some((1, 1)));
assert_eq!(ckms.query(0.998), Some((998, 998)));
assert_eq!(ckms.query(0.999), Some((999, 999)));
assert_eq!(ckms.query(1.0), Some((1000, 1000)));
查询提供对真实分位数的近似,+/- εΦn。在上面的例子中,ε 设置为 0.001,n 是 1000。最小和最大分位数--0.0 和 1.0--已经是精确的。中间查询的误差为 +/- 0.998。(这碰巧是精确的分位数,但并不总是这样。)
对于一个误差ε,这种结构将需要T*(floor(1/(2*ε)) + O(1/ε log εn)) + f64 + usize + usize存储空间,其中T是专用类型。
在本地测试中,每点的插入时间约为4微秒,方差为7%。这意味着每秒可以插入250k个点。
Misra Gries - ε近似频率计数
Misra-Gries计算一个ε近似频率计数,用于N个元素的流。输出是k个最频繁的元素。
- 近似计数f'[e]小于元素e的真实频率f[e],但最多为εN,即(f[e] - εN) ≤ f'[e] ≤ f[e]
- 任何频率f[e] ≥ εN的元素e都会出现在结果集中
误差界限ε = 1/(k+1),其中k是算法中使用的计数器数量。当k = 1时,即单个计数器,该算法等同于Boyer-Moore多数算法。
如果您想检查至少出现εN次的元素,您将需要进行第二次遍历来计算结果集中值的精确频率,这可以在常数空间中完成。
use quantiles::misra_gries::*;
let k: usize = 3;
let numbers: Vec<u32> = vec![1,3,2,1,3,4,3,1,2,1];
let counts = misra_gries(numbers.iter(), k);
let bound = numbers.len() / (k+1);
let in_range = |f_expected: usize, f_approx: usize| {
f_approx <= f_expected &&
(bound >= f_expected || f_approx >= (f_expected - bound))
};
assert!(in_range(4usize, *counts.get(&1).unwrap()));
assert!(in_range(2usize, *counts.get(&2).unwrap()));
assert!(in_range(3usize, *counts.get(&3).unwrap()));
Greenwald Khanna - ε近似分位数
Greenwald Khanna计算ε近似分位数。如果所需的分位数是φ
,则ε近似分位数是介于⌊(φ-ε)N⌋
和⌊(φ+ε)N⌋
之间的任何元素
流摘要数据结构可以处理最多max[usize]个观察结果。
开始和结束分位数分别被限制在观察到的最小和最大元素。
此页解释了理论: http://www.mathcs.emory.edu/~cheung/Courses/584-StreamDB/Syllabus/08-Quantile/Greenwald.html
use quantiles::greenwald_khanna::*;
let epsilon = 0.01;
let mut stream = Stream::new(epsilon);
let n = 1001;
for i in 1..n {
stream.insert(i);
}
let in_range = |phi: f64, value: u32| {
let lower = ((phi - epsilon) * (n as f64)) as u32;
let upper = ((phi + epsilon) * (n as f64)) as u32;
(epsilon > phi || lower <= value) && value <= upper
};
assert!(in_range(0f64, *stream.quantile(0f64)));
assert!(in_range(0.1f64, *stream.quantile(0.1f64)));
assert!(in_range(0.2f64, *stream.quantile(0.2f64)));
assert!(in_range(0.3f64, *stream.quantile(0.3f64)));
assert!(in_range(0.4f64, *stream.quantile(0.4f64)));
assert!(in_range(1f64, *stream.quantile(1f64)));
升级
0.2 -> 0.3
本版本引入了两个新算法:“Greenwald Khanna”和“Misra Gries”。现有的CKMS已从根目录移动到自己的子模块。您需要更新您的导入,从
use quantiles::CMKS;
到
use quantiles::ckms::CKMS;
依赖关系
~170KB