【问题标题】:Incremental entropy computation增量熵计算
【发布时间】:2013-06-10 21:04:00
【问题描述】:

std::vector<int> counts 为正整数向量,令N:=counts[0]+...+counts[counts.length()-1] 为向量分量之和。设置pi:=counts[i]/N,我使用经典公式H=p0*log2(p0)+...+pn*log2(pn)计算熵。

counts 向量正在变化 --- 计数增加 --- 每 200 次变化我重新计算熵。经过快速的 google 和 stackoverflow 搜索后,我找不到任何增量熵计算的方法。那么问题来了:是否有增量方法like the ones for variance 用于熵计算?

编辑:这个问题的动机是在VFDT-like 学习者中使用此类公式进行增量信息增益估计。

已解决:this mathoverflow post

【问题讨论】:

标签: c++ algorithm decision-tree entropy


【解决方案1】:

您可以通过重新计算计数并使用一些简单的数学恒等式来简化熵公式来重新计算熵

K = count.size();
N = count[0] + ... + count[K - 1];
H = count[0]/N * log2(count[0]/N) + ... + count[K - 1]/N * log2(count[K - 1]/N)
  = F * h
h = (count[0] * log2(count[0]) + ... + count[K - 1] * log2(count[K - 1]))
F = -1/(N * log2(N)) 

因为log2(a / b) == log2(a) - log2(b) 而成立

现在给定一个旧向量 count 迄今为止的观测值和另一个新的 200 个观测值向量 batch,您可以在 C++11 中执行此操作

void update_H(double& H, std::vector<int>& count, int& N, std::vector<int> const& batch)
{
    N += batch.size();
    auto F = -1/(N * log2(N));
    for (auto b: batch)
       ++count[b];
    H = F * std::accumulate(count.begin(), count.end(), 0.0, [](int elem) { 
        return elem * log2(elem);
    });
}

在这里,我假设您已将您的观察编码为int。如果您有某种符号,则需要一个符号表std::map&lt;Symbol, int&gt;,并在更新count 之前查找batch 中的每个符号。

这似乎是为一般更新编写一些代码的最快方法。如果您知道在每个批次中实际上只有很少的计数发生变化,您可以像 @migdal 那样做并跟踪变化的计数,减去它们对熵的旧贡献并添加新贡献。

【讨论】:

    【解决方案2】:

    我导出了熵和基尼指数的更新公式和算法,并做了笔记available on arXiv。 (该笔记的工作版本可用here。)另见this mathoverflow答案。

    为方便起见,我将包含简单的 Python 代码,以演示派生公式:

    from math import log
    from random import randint
    
    # maps x to -x*log2(x) for x>0, and to 0 otherwise 
    h = lambda p: -p*log(p, 2) if p > 0 else 0
    
    # update entropy if new example x comes in 
    def update(H, S, x):
        new_S = S+x
        return 1.0*H*S/new_S+h(1.0*x/new_S)+h(1.0*S/new_S)
    
    # entropy of union of two samples with entropies H1 and H2
    def update(H1, S1, H2, S2):
        S = S1+S2
        return 1.0*H1*S1/S+h(1.0*S1/S)+1.0*H2*S2/S+h(1.0*S2/S)
    
    # compute entropy(L) using only `update' function 
    def test(L):
        S = 0.0 # sum of the sample elements
        H = 0.0 # sample entropy 
        for x in L:
            H = update(H, S, x)
            S = S+x
        return H
    
    # compute entropy using the classic equation 
    def entropy(L):
        n = 1.0*sum(L)
        return sum([h(x/n) for x in L])
    
    # entry point 
    if __name__ == "__main__":
        L = [randint(1,100) for k in range(100)]
        M = [randint(100,1000) for k in range(100)]
    
        L_ent = entropy(L)
        L_sum = sum(L)
    
        M_ent = entropy(M)
        M_sum = sum(M)
    
        T = L+M
    
        print "Full = ", entropy(T)
        print "Update = ", update(L_ent, L_sum, M_ent, M_sum)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-31
      • 1970-01-01
      • 2014-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-05
      相关资源
      最近更新 更多