一种有效的分位数算法/数据结构,允许样本随着时间的推移而更新?
Posted
技术标签:
【中文标题】一种有效的分位数算法/数据结构,允许样本随着时间的推移而更新?【英文标题】:A efficient quantiles algorithm/data structure that allows samples to be updated as they increment over time? 【发布时间】:2020-10-12 23:53:54 【问题描述】:我正在寻找一种有效的分位数算法,该算法允许样本值随着时间的变化而“更新”或替换。
假设我有项目 1-n
的值。我想把这些放到一个分位数算法中,可以有效地存储它们。但是,在将来的某个时候,item-i
的值会增加。我想删除 item-i
的原始值并将其替换为更新后的值。具体用例适用于样本值随时间递增的流系统。
我见过的最接近这种情况的是t-Digest data structure。它有效地存储样本值。它唯一缺少的是删除和替换样本值的能力。
我还查看了Apache Quantiles Datasketch - 它遇到了同样的问题 - 无法移除和替换样本。
编辑:多考虑这一点,不一定需要删除旧值并插入增量值。如果存在只能更新值的约束,则可能有一种方法可以更轻松地重新计算内部状态。
【问题讨论】:
【参考方案1】:我们可以保留一个从变量名到值的 Map 和一个 SortedMap(搜索树),其键由值和名称组成(例如 value + "_" + name,或具有这两个字段的 Comparable 对象),所以排序后的键也是排序后的值,但我们也可以有唯一的键,以便能够删除旧值 + 变量名并引入新值 + 变量名。这是 HBase 中使用的一种技术,与持久化 TreeMap(自平衡二叉搜索树)没有太大区别。
那么计算分位数或百分位数就是扫描结构的问题。
当更新率较高而分位数查询率较低时,这是有效的。
当请求分位数的频率不是那么低时,我没有任何好主意,也许还有一组堆结构,这种结构也以某种方式索引以提高删除效率,例如https://***.com/questions/8705099/how-to-delete-in-a-heap-data-structure#:~:text=4%20Answers&text=Actually%2C%20you%20can%20remove%20an,parent%20of%20the%20old%20item.
【讨论】:
【参考方案2】:如果更新时间 O(log n)
和分位数计算时间 O(log n)
对您来说是可以接受的,那么其中一种解决方案是实现任何类型的自平衡二叉树(Splay tree、AVL-tree、Red-Black tree)而保持HashMap<Key, Node>
与树结构并行(或者如果您知道您的键是数字0
到n-1
,那么您可以将数组用于相同目的)。您还需要为每个给定节点保留子树中的节点计数(这对于所有提到的自平衡树都是可能的 - 这是对节点进行更新的所有方法的一个小补充,例如旋转,等等)。
使用键 K 更新值的伪代码,新值 V 将是:
Node node = find_node_in_hash_map_by_key(K); # O(1)
delete_node_keeping_subtree_counts_valid(node); # O(log n)
add_new_node_keeping_subtree_counts_valid(K, V); # O(log n)
在O(log n)
中也可以获取分位数 q,因为每个节点中都有可用的子树大小,因为它几乎可以让您在O(log n)
时间内按大小访问第 i 个元素。该操作的伪代码如下所示:
# i-th element requested
node = root
while true:
left = node.left_subtree
left_count = 0
if left is not None:
left_count = left.nodes_count
if i < left_count:
node = left # select i-th element in the left subtree
elif i == left_count:
return node.value # we have exactly i elements in left subtree, so i-th value is in the current node
else:
i -= left_count + 1 # select element i - left_count - 1 from the right subtree
node = node.right
我不知道这种数据结构有一个好的开源 JAVA 解决方案,但是编写自己的 AVL 树并不是那么困难(并且 Splay 树应该是最简单的,只是它们最坏的情况复杂性不是O(log n)
,但平均来说应该不错)。
【讨论】:
以上是关于一种有效的分位数算法/数据结构,允许样本随着时间的推移而更新?的主要内容,如果未能解决你的问题,请参考以下文章
python 绘制以检查任何样本的分布的分位数:qqplot
数据挖掘&机器学习招聘网站的职位招聘数据的分位数图分位数-分位数图以及散点图使用线性回归算法拟合散点图处理详解