hyperloglog计算uv原理

1、从伯努利试验说起

什么是伯努利试验?

在相同的条件下,相互独立的重复一种随机试验,这种试验只有两种可能的情况:发生或不发生。如果我们在这种条件下进行了n次试验,则称为n重伯努利试验。

在日常生活中,最常见的伯努利试验就是抛硬币,抛硬币之后只有两种结果:正面或负面。如果我们独立的进行n次伯努利抛硬币试验,每一次伯努利试验第一次出现正面朝上时抛硬币的次数为分别k1,k2,..kn

                                                记:k_max = max(k1,k2,...,kn)

那么根据极大似然估计方法(推理过程没有仔细研究,待我研究后再补充),可得出n和k_max之间的估算关系为:

                                                        n = 2 ^ k_max

借用网上的案例如下:

第一次试验:抛掷1次出现正面,此时k=1,n=1;
第二次实验:抛掷3次出现正面,此时k=3,n=2;
第三次实验:抛掷6次出现正面,此时k=6,n=3;
第n次试验:抛掷10次出现正面,此时k=10,n=n,通过估算关系计算,n=2^10
上述案例可以看出,假设n=3,此时通过估算关系n=2^kmax,2^6 ≠3,而且偏差很大。因此得出结论,这种估算方法误差很大。

2、估值优化

        为了解决上述估值偏差较大的问题,增大测试轮数来缩小误差,过程如下:

        我们进行m轮试验,每一轮进行n次独立的伯努利试验,这样每一轮都能得到一个k_max,分别记为:k_1_max,k_2_max,...,k_m_max,过程展示如下:

此时用每一轮k_i_max的平均数作为k_max的值,记为如下: 

 k\_max = \frac{k\_1\_max + k\_2\_max + ... + k\_m\_max}{m}

则:n = 2^{k\_max}

因为我们一共抛了m轮,则最终的估计公式如下:

Estimate = m * n = m * 2^{k\_max}

注:刚开始看这个估计公式的时候,没明白为什么要乘以一个m。现在理解一下:我们的k_max取所有轮的平均值作为估计,那么他对应的是一轮试验的预估结果:n = 2^k_max。但是我们实际上是一共抛了m轮,共m*n次,所以最后的预估值要乘以m。

这个预估方式叫做LogLog

3、Hyperloglog过程

        hyperloglog与loglog方式唯一的不同区别在于,loglog取用的是每一轮最大值的平均值,而hyperloglog取用的是每一轮最大值的调和平均数。取调和平均的原因是为了解决某一次异常数据带来的巨大扰动。有一个十分形象的例子来说明这个问题。

马云月工资一亿,我和九个小伙伴的工资分别是10000,11000,... , 19000。

使用平均数,我们的平均工资为 = 9104090

使用调和平均数,我们的平均工资 = 15303

显然用调和平均数更能准确说明我们的平均工资。

调和平均数据的计算公式如下:

H_{m} = \frac{m}{\sum_{i=1}^{m}\frac{1}{x_{i}}}

所以用hyperloglog预估的公式如下:

Estimate = m * 2^{H_{m}}

4、伯努利试验为什么可以对uv的估算?

       1、 在uv计算中如何模拟一次伯努利试验呢?

             对于我们的用户id,我们可以进行hash转换,因为用户id是随机的,hash转换的值也是随机的,然后我们计算hash值低位连续0的个数k,作为一次抛硬币伯努利试验第一次出现正面的次数的模拟,这也是一个随机数。综上,用这种方式来模拟一次伯努利试验。

        2、那么为什么这个过程可以模拟uv去重呢?

        假设我们有两组数据:

        第一组数据:{uid1,uid2,uid3,uid4,uid5,uid6}  没有重复uid数据

        第二组数据:{uid1,uid1,uid2,uid2,uid3,uid4,uid4,uid5,uid6} 有uid重复数据

        因为相同uid的hash值一样,这样低位连续0的个数也一样,假设uid1,uid2,uid3,uid4,uid5,uid6低位连续0的个数分别为k1,k2,k3,k4,k5,k6.

        那么对于第一组数据,k_max应该是

        kmax_1 = max(k1,k2,k3,k4,k5,k6)

        对于第二组数据,k_max应该是

        kmax_2 = max(k1,k1,k2,k2,k3,k4,k4,k5,k6)

        显然:kmax_1 = kmax_2

        那么这两组的预估值也应该是一样的。这就是使用伯努利试验可以进行uv预估的原因。

5、分桶及代码的实现

        分桶的原理就相当于进行m轮试验。

        这其中还有一些参数的调节,这里就不再赘述了,写这篇文章的目的是弄清楚hyperloglog的原理,对于看其他博客不理解的地方进行了进一步的思考和说明。如果想看分桶过程和代码实现,推荐以下博客:

HyperLogLog 使用及其算法原理详细讲解

猜你喜欢

转载自blog.csdn.net/chenzhiang1/article/details/126602472
Uv
今日推荐