C++ 增量熵计算
设C++ 增量熵计算,c++,algorithm,decision-tree,entropy,C++,Algorithm,Decision Tree,Entropy,设std::vector counts为正整数向量,设N:=counts[0]+…+counts[counts.length()-1]为向量分量之和。设置pi:=counts[i]/N,我使用经典公式H=p0*log2(p0)+…+pn*log2(pn)计算熵 计数向量在变化——计数在增加——每变化200次,我就重新计算熵。在快速的google和stackoverflow搜索之后,我找不到任何增量熵计算的方法。所以问题是:对于熵计算,是否有一种增量方法 编辑:这个问题的动机是使用这些公式来估计类
std::vector counts
为正整数向量,设N:=counts[0]+…+counts[counts.length()-1]
为向量分量之和。设置pi:=counts[i]/N
,我使用经典公式H=p0*log2(p0)+…+pn*log2(pn)
计算熵
计数
向量在变化——计数在增加——每变化200次,我就重新计算熵。在快速的google和stackoverflow搜索之后,我找不到任何增量熵计算的方法。所以问题是:对于熵计算,是否有一种增量方法
编辑:这个问题的动机是使用这些公式来估计类学习者的增量信息增益
已解决:请参阅。您可以通过重新计算计数并使用一些简单的数学恒等式来简化熵公式来重新计算熵
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
,以及另一个称为batch
的新200个观察值的向量,您可以在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);
});
}
void update_H(双精度&H,标准::向量与计数,整数与否,标准::向量常量与批处理)
{
N+=batch.size();
自动F=-1/(N*log2(N));
用于(自动b:批处理)
++计数[b];
H=F*std::累加(count.begin(),count.end(),0.0,[](int elem){
返回元素*log2(元素);
});
}
这里我假设您已经将您的观察编码为int
。如果您有某种符号,则需要一个符号表std::map
,并在更新计数之前在批处理中查找每个符号
这似乎是为一般更新编写代码的最快方法。如果您知道在每一批中只有很少的计数会发生变化,那么您可以像@migdal那样跟踪变化的计数,减去它们对熵的旧贡献,再加上新贡献 我推导了熵和基尼指数的更新公式和算法,并做了说明。(注释的工作版本可用。)另请参见答案
为了方便起见,我加入了简单的Python代码,演示了派生公式:
您可能想尝试前往,以获得对您的问题的更详细的数学处理。Shaktal,我将问题发布在mathoverflow上,他们在那里指出了以下文章:
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)