Непрерывная взаимная информация в Python

[Frontmatter] (пропустите это, если хотите просто задать вопрос):

В настоящее время я ищу возможности использования совместной информации Шеннон-Уивер и нормализованная избыточность для измерения степени маскировки информации между пакетами дискретных и непрерывных значений функций, организованных по функциям. Используя этот метод, моя цель - создать алгоритм, очень похожий на ID3, но вместо использования энтропия Шеннона, алгоритм будет стремиться (как ограничение цикла) максимизировать или минимизировать общую информацию между одной функцией и набор функций, основанный на полном пространстве входных функций, добавление новых функций к последней коллекции, если (и только если) они увеличивают или уменьшают взаимную информацию, соответственно. Это, по сути, перемещает алгоритм принятия решений ID3 в парное пространство, объединяя к нему ансамблевой подход со всеми ожидаемыми временными и пространственными сложностями обоих методов.

[/ Frontmatter]


К вопросу: я пытаюсь получить непрерывный интегратор, работающий на Python, используя SciPy. Поскольку я работаю со сравнениями дискретных и непрерывных переменных, моя текущая стратегия для каждого сравнения пар функция-функция выглядит следующим образом:

  • Дискретный признак по сравнению с дискретным признаком: используйте дискретную форму взаимной информации. Это приводит к двойному суммированию вероятностей, с которым мой код справляется без проблем.

  • Во всех остальных случаях (дискретное или непрерывное, обратное и непрерывное против непрерывного): используйте непрерывную форму, используя гауссову оценку. для сглаживания функций плотности вероятности.

Я могу выполнить какую-то дискретизацию для последних случаев, но поскольку мои наборы входных данных не являются по своей природе линейными, это потенциально излишне сложно.


Вот основной код:

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

Обратите внимание, что перерасчет ровно одной точки делается намеренно, чтобы предотвратить сингулярность в gaussian_kde класс. Когда размеры x и y взаимно приближаются к бесконечности, этот эффект становится незначительным.


Моя текущая загвоздка заключается в попытке заставить множественную интеграцию работать против Оценка плотности ядра по Гауссу в SciPy. Я пытался использовать SciPy dblquad для выполнения интеграции, но в последнем случае я получаю поразительное количество следующих сообщений.

Когда я устанавливаю numpy.seterr ( all='ignore' ):

Предупреждение: обнаружена ошибка округления, которая препятствует достижению запрошенного допуска. Ошибка может быть недооценена.

И когда я установил 'call' с помощью обработчика ошибок:

Ошибка с плавающей запятой (потеря значимости), с флагом 4

Ошибка с плавающей точкой (недопустимое значение), с флагом 8

Довольно легко понять, что происходит, правда? Ну, почти: IEEE 754-2008 и SciPy говорят мне только, что здесь происходит, а не почему < / em> или как обойти это.


Результат: 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)

Однако остается вопрос об исправлении округления, как и запрос на более надежную реализацию. Любая помощь в любой области будет принята с благодарностью.


person MrGomez    schedule 02.12.2011    source источник
comment
Удивительно, но в python еще нет постоянной реализации взаимной информации. Вы продвинулись дальше этого? Кроме того, почему ваш gfun = 0, а не -INF в вызове dblquad?   -  person naught101    schedule 18.10.2013
comment
К сожалению, я отказался от этого запроса с момента его написания и подозреваю, что мой пример кода можно улучшить. Насколько я помню (как это было два года назад), я искал взаимную информацию о компании. абсолютное значение, поэтому (-INF, 0) не имеет смысла. Но, если я ошибаюсь, оригинальные статьи Шеннона и Уивера, которые я пытался связать, должны прояснить это. :)   -  person MrGomez    schedule 19.10.2013
comment
Похоже, что в Minepy реализована непрерывная взаимная информация: minepy.sourceforge.net/docs /1.0.0/python.html   -  person naught101    schedule 26.10.2013
comment
Думаю, всегда возникает вопрос, лучше ли гауссовский KDE, чем простая гистограмма в этой ситуации. Я действительно не могу понять, почему это было бы иначе, и это решило бы ошибки округления ...   -  person naught101    schedule 12.12.2013
comment
Является ли Minepy в настоящее время лучшим ответом на такую ​​задачу?   -  person pir    schedule 24.09.2015


Ответы (1)


Прежде чем пробовать более радикальные решения, такие как переосмысление проблемы или использование других инструментов интеграции, посмотрите, поможет ли это. Замените INF=float('INF') на INF=1E12 или другое большое число - это может исключить NaN результаты, созданные простыми арифметическими операциями с входными переменными.

Никаких обещаний по этому поводу, но иногда полезно попробовать быстрое исправление, прежде чем приступать к серьезному алгоритмическому переписыванию или замене альтернативных инструментов.

person Raymond Hettinger    schedule 02.12.2011
comment
Хорошее предложение, хоть и то, что я пробовал. Придя к своей текущей реализации, я также попробовал использовать нетрансфинитные границы, чтобы увидеть, есть ли другой путь кода в QUADPACK (en.wikipedia.org/wiki/QUADPACK), с которым взаимодействует SciPy. Нет такой удачи. - Однако я изменил определение моей константы, чтобы посмотреть, будет ли это работать, и я все еще получаю nan в моем наборе результатов. Это означает, что значения NaN могут распространяться по областям с нулевой вероятностью, что меня беспокоит. * тесты * - person MrGomez; 03.12.2011
comment
Ага; По крайней мере, я исправил распространение nan. Исходный вопрос обновлен. - person MrGomez; 03.12.2011
comment
Оставить его непринятым было намеренно, потому что он отвечает на одну оговорку, но не на весь вопрос (я надеялся на дополнительные ответы). Таким образом, я постараюсь восполнить недостающие детали. - Обходной путь действительно заключается в использовании более правильных интеграторов. Если они недоступны, большую часть проблемы можно решить, играя с абсолютными и относительными значениями эпсилон. И вот загвоздка: dblquad от SciPy имел ошибку, когда эти значения сбрасывались на пол для внутренней интеграции. Таким образом, их команда была уведомлена вместе с патчем. - Отметить как принято сейчас. - person MrGomez; 14.12.2011