c++ - 如何计算信息增益的值以减少浮点逼近误差?

标签 c++ math floating-point floating-accuracy numerical-methods

我有一个数据集,其中包含一些属于由 12 表示的两个类标签的特征。处理该数据集是为了构建决策树:在构建树的过程中,我需要计算信息增益以找到数据集的最佳划分。

N1 个特征与标签 1 关联,N2 个特征与标签 2 关联,那么可以使用以下公式计算:

Entropy = - (N1/N)*log2(N1/N) - (N2/N)*log2(N2/N) ,其中N = N1 + N2

我需要计算三个熵值才能获得信息增益:

  • entropyBefore ,即当前数据集划分前的熵;
  • entropyLeft ,即划分后左分割的熵;
  • entropyRight ,即划分后右分割的熵。

因此,信息增益等于 entropyBefore - (S1/N)*entropyLeft - (S2/N)*entropyRight ,其中 S1 是属于分割 1 的类 1 的特征数量,S2 是类 < 的特征数量em>2属于分割2。

如何计算信息增益的值以减少浮点逼近误差?当我在信息增益必须为零的情况下应用上述公式时,计算值却等于一个非常小的负值。

更新(示例代码)

double N = static_cast<double>(this->rows());   // rows count of the dataset

double entropyBefore = this->entropy();   // current entropy (before performing the split)

bool firstCheck = true;
double bestSplitIg;

for each possible split
{
    // ...

    pair<Dataset,Dataset> splitPair = split(...,...);
    double S1 = splitPair.first.rows();
    double S2 = splitPair.second.rows();

    double entropyLeft = splitPair.first.entropy();
    double entropyRight = splitPair.second.entropy();

    double splitIg = entropyBefore - (S1/N*entropyLeft + S2/N*entropyRight);
    if (firstCheck || splitIg > bestSplitIg)
    {
        bestSplitIg = splitIg;
        // ...

        firstCheck = false;
    }
}

最佳答案

如果您只是使用熵来确定哪个替代方案更好,因此您只需要比较两个熵的结果,而不需要它们的实际值,那么您可以消除一些计算。

你有这个函数:Entropy(N1, N2, N) -> - N1/N*log2(N1/N) - N2/N*log2(N2/N)。

假设 N 在问题持续时间内是一个常数,让我们将表达式乘以 N:

  • N1*log2(N1/N)-N2*log2(N2/N)

接下来,将“/N”从对数中分离出来:

  • N1*(log2(N1)-log2(N)) - N2*(log2(N2)-log2(N))

并展开:

  • N1*log2(N1) - N2*log2(N2) - (N1+N2)*log2(N)

并简化:

  • N1*log2(N1) - N2*log2(N2) - N*log2(N)

显然 N*log2(N) 是一个常数,不会影响一个熵是否大于另一个熵,因此我们可以丢弃它。

此外,乘以 ln(2),这也不会改变一个熵是否大于另一个熵。这具有将 log2 函数更改为 ln 函数的效果,并且数学库可以稍微更准确地计算 ln(它是“自然”对数是有原因的):

E(N1, N2, N) -> - N1*ln(N1) - N2*ln(N2)

该函数的运算次数较少,因此它的计算可能比 Entropy 函数更准确,并且它具有以下属性:(精确计算时)E(N1, N2, N) < E(M1, M2, N) iff熵(N1, N2, N) < 熵(M1, M2, N)。

关于c++ - 如何计算信息增益的值以减少浮点逼近误差?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14947132/

相关文章:

c++ - 使用 ofstream 将多个变量类型写入文本文件

c++ - 是否有可用于防止转义字符被识别的标准库函数?

c++ - 如何在gdb的调用命令中使用C++默认参数

c - SSE 将寄存器设置为 0.0's and 1.0' s 的最佳方法?

c++ - NAN比分Arduino Uno

c# - 找到一个值正下方的 float

c - scanf 成功但存储的值不适合某些大的 float

python - 如何让我的 Python 扩展接受额外的参数?

c++ - 在 Eclipse CDT 中重构 C++

c++ - 求圆内坐标的角度