Python中的连续互信息

18

[Frontmatter] (如果您只想要问题,可以跳过这部分):

我目前正在研究使用Shannon-Weaver Mutual Informationnormalized redundancy来衡量离散和连续特征值之间的信息屏蔽程度,这些特征值按特征组织。使用这种方法,我的目标是构建一个非常类似于ID3的算法,但该算法不会使用Shannon entropy,而是寻求(作为循环约束条件)最大化或最小化单个特征和基于完整输入特征空间的特征集合之间的共享信息,仅在它们相应地增加或减少互信息的情况下,将新特征添加到后者集合中。实际上,这将ID3的决策算法移动到对偶空间,并用预期的时间和空间复杂性将集成方法与其固定在一起。

[/Frontmatter]


问题是:我正在尝试使用SciPy在Python中实现一个连续的积分器。由于我正在比较离散和连续变量,因此我的当前策略是针对每个特征-特征对进行以下操作:

  • 离散特征与离散特征:使用互信息的离散形式。这导致了概率的双重求和,我的代码可以轻松处理。

  • 所有其他情况(离散与连续、反之亦然以及连续与连续):使用连续形式,使用高斯估计器平滑概率密度函数

我可以对后一种情况进行某种形式的离散化,但由于我的输入数据集本质上不是线性的,这可能会使问题过于复杂。


这是关键代码:

import math
import numpy
import scipy
from scipy.stats import gaussian_kde
from scipy.integrate import dblquad

# Constants
MIN_DOUBLE = 4.9406564584124654e-324 
                    # The minimum size of a Float64; used here to prevent the
                    #  logarithmic function from hitting its undefined region
                    #  at its asymptote of 0.
INF = float('inf')  # The floating-point representation for "infinity"

# x and y are previously defined as collections of 
# floating point values with the same length

# Kernel estimation
gkde_x = gaussian_kde(x)
gkde_y = gaussian_kde(y)

if len(binned_x) != len(binned_y) and len(binned_x) != len(x):
    x.append(x[0])
    y.append(y[0])

gkde_xy = gaussian_kde([x,y])
mutual_info = lambda a,b: gkde_xy([a,b]) * \
           math.log((gkde_xy([a,b]) / (gkde_x(a) * gkde_y(b))) + MIN_DOUBLE)

# Compute MI(X,Y)
(minfo_xy, err_xy) = \
    dblquad(mutual_info, -INF, INF, lambda a: 0, lambda a: INF)

print 'minfo_xy = ', minfo_xy

请注意,故意多计算一个点是为了防止 SciPy 的 gaussian_kde 类出现奇异性。随着 x 和 y 的大小相互趋近于无穷大,这种影响变得可以忽略不计。


我的当前难点是尝试在SciPy中使用高斯核密度估计进行多重积分,我一直在尝试使用SciPy的dblquad执行积分,但在后一种情况下,我收到了以下惊人的消息。
当我设置numpy.seterr(all='ignore')时:
警告:检测到舍入误差的发生,这会阻止实现所请求的容限。错误可能被低估。
而当我使用错误处理程序将其设置为'call'时:

Floating point error (underflow), with flag 4

Floating point error (invalid value), with flag 8

很容易想象出正在发生什么,对吧?嗯,几乎是的:IEEE 754-2008和SciPy只告诉我这里正在发生什么,而不是为什么如何解决它


结论是:通常情况下,minfo_xy会解析为nan;在执行Float64数学运算时,采样不足以防止信息丢失或无效。
使用SciPy时,是否有一般性的解决方法?
更好的是:如果Python中有一个稳健的、罐装的连续互信息实现,它具有一个接口,可以接受两个浮点值集合或一组合并的对,请提供链接,如果您知道存在这样的实现,它将解决这个完整的问题。
提前致谢。

编辑:这解决了上面例子中的nan传播问题:

mutual_info = lambda a,b: gkde_xy([a,b]) * \
    math.log((gkde_xy([a,b]) / ((gkde_x(a) * gkde_y(b)) + MIN_DOUBLE)) \
        + MIN_DOUBLE)

然而,舍入校正的问题仍然存在,对于更强大的实现也有要求。在这两个方面提供任何帮助将不胜感激。


令人惊讶的是,Python中尚未有连续互信息的实现。你有进一步了解吗?此外,在dblquad调用中,为什么gfun = 0而不是-INF? - naught101
1
很遗憾,自从我最初写下这篇文章以来,我已经放弃了这个调查,并且我怀疑我的代码示例可以改进。如果我没记错的话(因为已经过去两年了),我当时是在寻求关于绝对值的互信息,所以(-INF, 0)没有意义。但是,如果我错了,我尝试链接的原始Shannon和Weaver论文应该能够澄清这一点。 :) - MrGomez
1
Minepy似乎有一个连续互信息的实现:http://minepy.sourceforge.net/docs/1.0.0/python.html - naught101
1
我想,总有一个问题,高斯核密度估计是否比简单的直方图在这种情况下更好。我真的想不出为什么会有很大的区别,而且这可以解决舍入误差的问题... - naught101
目前来看,Minepy是这样的任务的最佳选择吗? - pir
1个回答

4

在尝试更彻底的解决方案,如重新定义问题或使用不同的集成工具之前,请先查看此方法是否有帮助。将 INF=float('INF') 替换为 INF=1E12 或其他大数值,可以消除由输入变量的简单算术操作创建的 NaN 结果。

无法保证一定有效,但有时在进行重大算法重写或替代备用工具之前,尝试快速修复可能是有益的。


好的建议,尽管我已经尝试过。在我的当前实现中,我还尝试了非无限边界,以查看QUADPACK(https://en.wikipedia.org/wiki/QUADPACK)中是否有不同的代码路径可用,这与SciPy接口。没有这样的运气。--然而,我已经修改了我的常数定义,以查看是否有效,并且我仍然在我的结果集中收到`nan`。这意味着NaN值可能正在传播零概率区域,这让我感到担忧。 \ 测试\ - MrGomez
是的,我已经修复了“nan”传播问题。原始问题已经更新。 - MrGomez
2
留下未被接受是故意的,因为它回答了一个警告,但并没有回答整个问题(我希望得到更多答案)。因此,我将寻求填补缺失的细节。 - 解决方法确实是使用更正确的积分器。如果这些积分器不可用,通过调整绝对和相对 epsilon 值可以解决很多问题。问题在于:SciPy 中的 dblquad 存在一个 bug,内部积分的这些值会被丢弃。因此,他们已经通知了他们的团队,并提供了一个修补程序。 - 现在将其标记为已接受。 - MrGomez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接