атрибут scipy.stats «энтропия» для непрерывных распределений не работает вручную

#python #entropy #information-theory #probability-distribution #scipy.stats

#python #энтропия #теория информации #распределение вероятности #scipy.stats

Вопрос:

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

Пытаясь выяснить, какую функцию .entropy атрибут вызывает в этих случаях, я обнаружил вызываемую функцию _entropy scipy.stats._distn_infrastructure.py , которая выполняет это с integrate.quad(pdf) помощью (числовое интегрирование).

Но когда я пытаюсь сравнить два подхода (атрибут .entropy и численное интегрирование с функцией _entropy ), функция выдает ошибку:

AttributeError: 'rv_frozen' object has no attribute '_pdf'

Почему атрибут распределения .entropy вычисляется нормально, но функция _entropy выдает ошибку?

 import numpy as np
from scipy import integrate 
from scipy.stats import norm, johnsonsu
from scipy.special import entr

def _entropy(self, *args): #from _distn_infrastructure.py
    def integ(x):
        val = self._pdf(x, *args)
        return entr(val)

    # upper limit is often inf, so suppress warnings when integrating
    # _a, _b = self._get_support(*args)
    _a, _b = -np.inf, np.inf   
    with np.errstate(over='ignore'):
        h = integrate.quad(integ, _a, _b)[0]

    if not np.isnan(h):
        return h
    else:
        # try with different limits if integration problems
        low, upp = self.ppf([1e-10, 1. - 1e-10], *args)
        if np.isinf(_b):
            upper = upp
        else:
            upper = _b
        if np.isinf(_a):
            lower = low
        else:
            lower = _a
    return integrate.quad(integ, lower, upper)[0]
 

Использование атрибута работает нормально:

 print(johnsonsu(a=2.55,b=2.55).entropy())
 

ВОЗВРАТ 0.9503703091220894

Но функция не:

 print(_entropy(johnsonsu(a=2.55,b=2.55)))
 

возвращает ошибку AttributeError: 'rv_frozen' object has no attribute '_pdf' , хотя johnsonsu имеет этот атрибут:

 def _pdf(self, x, a, b):
    # johnsonsu.pdf(x, a, b) = b / sqrt(x**2   1) *
    #                          phi(a   b * log(x   sqrt(x**2   1)))
    x2 = x*x
    trm = _norm_pdf(a   b * np.log(x   np.sqrt(x2 1)))
    return b*1.0/np.sqrt(x2 1.0)*trm
 

Какую функцию .entropy тогда вызывает атрибут в случае johnsonsu ?

Ответ №1:

Вы хотите либо johnsonsu(a=2.55,b=2.55).entropy() использовать замороженные дистрибутивы, либо johnsonsu.entropy(a=2.55,b=2.55) иным образом.

Почему часть вашего вопроса в основном заключается в том, что начальное подчеркивание в _entropy означает «детали реализации, не вызывайте напрямую». Более длинный ответ заключается в том, что замороженные дистрибутивы оборачивают экземпляр дистрибутива (self.dist) и делегируют ему вызовы _pdf, _pmf и т.д.

РЕДАКТИРОВАТЬ: выполнение johnsonsu(a=2.55,b=2.55) создает замороженный дистрибутив, rv_frozen. Не делайте этого, если вы не хотите повторно использовать экземпляр несколько раз: просто укажите параметры формы a, b в качестве аргументов функции энтропии.

Комментарии:

1. итак, как я могу заставить работать ручную _entropy функцию? и действительно ли это то, что .entropy вызывает атрибут? Я не знаю, использую ли я замороженные дистрибутивы, поскольку я не знаю, что это такое. Все, что я думал, что я делаю, это оцениваю johnsonsu . Два примера кода, которые вы написали, не помогают различать замороженные и незамороженные, поскольку они оба работают так же хорошо, как и друг с другом