数据挖掘中的抽样算法

来源:互联网 发布:qq好友不显示网络状态 编辑:程序博客网 时间:2024/05/16 07:05
在数据挖掘中,经常会用到抽样,比如欠(过)采样等,总的说来有两种,一种是已知样本总量n,从中随机抽m个样本;另一种是未知样本总量,从中抽取m个样本,这种情况一般是流数据,或者是很大量的数据。
 
问题描述就是从n个数中随机选出m个有序数字,不允许重复选择。这里n>m。下面的算法来自《编程珠玑》,或者《计算机程序设计艺术》
1.当n已知
依次考虑整数0,1,2。。。n-1,通过适当的随机测试来对每个整数进行选择,这样输出就是有序的了。
一般来说从r个剩余整数中选出s个,我们可以以概率s/r来选择下一个数。
select = m
remaining = n
for i = [0, n)
     if (bigrand() % remaining ) < select
            print i
            select--
     remaining--
C++代码如下:
void genknuth(int m, int n)
{
      for (int i = 0; i < n; i++)
            if ((bigrand() % (n-i)) < m) {
                 cout << i << endl;
                 m--;
            }
}
证明略去。
解释如下:
cpu在一次循环的每一步都是一次实验,那么cpu在做N多次循环后,这个循环里的每一步就都构成了一个有N个样本的样本空间,在每个样本空间里,我们定义好问题要求的事件后,就可以计算该事件的发生概率了;

所以,我们可以总结出抽样算法的设计规律:就是已知概率(随机),通过算法设计实验,生成样本空间,定义问题要求事件,让事件发生的概率为已知概率,然后进一步按照该概率来完成抽样。

2.当n未知
解决方法是叫Reservoir Sampling (蓄水池抽样)

用一个数据结构R记录现在已选择的行号。
初始为前m行都选了。
然后对第x行(x > m),以
m/x的概率选中这一行
,然后用x随机替换掉当前R中的某一个值,ie,每一行都有1/m的概率被替换。
这样遍历到文件末尾,最后R中的m个就是随机选择出的m个。
无需知道文件总行数,因为每次选择概率是动态的
可以证明这m个是随机的
 
伪码如下:

                    Init : a reservoir with the size: k

                     for   i= k+1toN

                              M=random(1, i);

                              if( M < k)

                                     SWAPthe Mth valueandith value

                       end for

证明如下:

http://wansishuang.iteye.com/blog/443902  

每次都是以 k/i 的概率来选择
例: k=1000的话, 从1001开始作选择,1001被选中的概率是1000/1001,1002被选中的概率是1000/1002,与我们直觉是相符的。

接下来证明:
     假设当前是i+1, 按照我们的规定,i+1这个元素被选中的概率是k/i+1,也即第 i+1 这个元素在蓄水池中出现的概率是k/i+1
     此时考虑前i个元素,如果前i个元素出现在蓄水池中的概率都是k/i+1的话,说明我们的算法是没有问题的。
   
对这个问题可以用归纳法来证明:k < i <=N
   1.当i=k+1的时候,蓄水池的容量为k,第k+1个元素被选择的概率明显为k/(k+1), 此时前k个元素出现在蓄水池的概率为 k/(k+1), 很明显结论成立。
   2.假设当 j=i 的时候结论成立,此时以 k/i 的概率来选择第i个元素,前i-1个元素出现在蓄水池的概率都为k/i。 
      证明当j=i+1的情况:
      即需要证明当以 k/i+1 的概率来选择第i+1个元素的时候,此时任一前i个元素出现在蓄水池的概率都为k/(i+1).
前i个元素出现在蓄水池的概率有2部分组成, ①在第i+1次选择前得出现在蓄水池中,②得保证第i+1次选择的时候不被替换掉
       ①.由2知道在第i+1次选择前,任一前i个元素出现在蓄水池的概率都为k/i
       ②.考虑被替换的概率:  
首先要被替换得第 i+1 个元素被选中(不然不用替换了)概率为 k/i+1,其次是因为随机替换的池子中k个元素中任意一个,所以不幸被替换的概率是 1/k,故
       前i个元素中任一被替换的概率 = k/(i+1) * 1/k = 1/i+1
       则没有被替换的概率为:   1 - 1/(i+1) = i/i+1
综合① ②,通过乘法规则
得到前i个元素出现在蓄水池的概率为 k/i * i/(i+1) = k/i+1
  故证明成立

当m=1时,就是编程zuji后面的作业题目,算法就是总是选择第一行,然后以1/2的概率选择第二行,1/3的概率选择第3行。。。。。
1/n的概率选择第n行。

其实是上面讨论的第二种情况的特例。
 
 解释如下:
这里的事件与第一种抽样正好相反,第一种抽样是前i次试验构成一种事件,这里是从i到最后的试验构成一种事件,因此最后第n个单独构成一个事件,显然这个元素在实验结束后发生的概率是k/n;其他第i个被抽中的概率对应的事件是第i个抽中,而后续的元素都不被抽中,该事件发生的概率依然为k/n。因此,按照程序构成的事件发生试验,最后抽出的k个元素,每一个被抽中的概率都是k/n,也就是随机抽样了。
 

 

原创粉丝点击