pyinference.inference package

Submodules

pyinference.inference.factor module

class pyinference.inference.factor.Factor(name='', cond=None, cons=None)[source]

Bases: object

Фактор логического вывода.

Фактор связывает несколько переменных в совместное распределение вероятности.

Фактор это некая функция, которая ставит в соответствие каждому возможному набору значений некого множества переменных действительное число (значение фактора). Набор соответствующих значений A некоторого множества переменных V называется назначением (assignment), если: - мощность множества A равна мощности множества V; - каждый элемент множества A является элементом множества значений соответствующего элемента множества V

Пример: допустим, M – бинарная переменная M=(“монета”, {“орел”, “решка”}), а V – набор переменных V={M}3={M, M, M}, тогда А={“орел”, “орел”, “решка”} – корректное назначение, а А1={“решка”, “решка”} – некорректное назначение, так как не указано значение третьей переменной. А2={“решка”, “решка”, “ребро”} – также не является корректным назначением, так как третий элемент («ребро») отсутствует в области определения третьей переменной M. Однако, назначение А2 является корректным для множества V’={M, M, M’}, где M’=(“другая монета”, {“орел”, “решка”, “ребро”}), так как теперь третья переменная во множестве V’ уже другая и она содержит значение «ребро» в своей области определения. По тем же причинам, назначение А2 является корректным для набора V’’={M’, M’, M’}.

Таким образом, фактор определяется упорядоченной тройкой F=(N, V, X), где N – имя фактора, V – область определения фактора (набор переменных, на которых определен фактор), X – множество значений фактора соответствующей мощности.

Фактор определен на некотором упорядоченном множестве переменных, называемом областью определения (scope) фактора. Область определения обозначается так: F(A,B,C) или так: scope(F)={A,B,C}, где F – фактор, A, B и C – переменные, входящие в фактор. Заметим, что определение фактора не накладывает никаких ограничений ни на отдельные значения, ни на сумму этих значений, несмотря на то, что теория вероятности предусматривает такие ограничения. Фактор – это базовый строительный блок в вероятностных графических моделях. и представление вероятностей – всего лишь одно из возможных применений факторов. Например, определим фактор на одной переменной M, следующим образом:

coin_var = Variable(name="coin", terms=["орел", "решка"])
coin_factor = Factor(name="coin", cons=[coin_var])
import numpy as np
coin_factor.cpd = np.array([0.5, 0.5])

Note

Заметим, что по умолчанию, распределение фактора (атрибут cpd) принимает значения, соответствующие равномерному распределению. Так что последние две строчки в данном примере можно было бы опустить.

Факторы удобны для использования в вероятностных графических моделях тем, что на них определены некоторые операции, часто выполняемые в процессе логического вывода, в довольно общей форме, что позволяет использовать их как элементарные объекты для построения логических сетей.

Также, факторы могут представлять условные вероятности. Рассмотрим пример из медицинской диагностики. Определим бинарную переменную с=(«болезнь», {«нет», «есть»}) и бинарную переменную t=(«тест», {«положительный», «отрицательный»}). Переменная с показывает, есть ли у пациента определенное заболевание. а переменная t – результат диагностического теста. Допустим, что априорная вероятность данного заболевания равна 1%. Сконструируем фактор С=(«P(c)», {c}, {0.99, 0.01}). Очевидно, что вероятность получения определенного результата теста зависит от того, есть ли данное заболевание у пациента, или нет, то есть мы предполагаем известной вероятность P(t|c). Допустим, что вероятность получения положительного результата теста равна 90%. Соответственно, вероятность ложноотрицательного результата равна 0,1. Вероятность получить отрицательный результат при отсутствии заболевания равна 0,8, а вероятность ложноположительного результата – 0,2. Создадим фактор, представляющий данную условную вероятность:

c = Variable(name='C', terms=['no', 'yes'])
t = Variable(name='T', terms=['pos', 'neg'])
C = Factor(name='C', cons=[c])
C.cpd = np.array([0.99, 0.01])
T = Factor(name='T|C', cons=[t], cond=[c])
T.cpd = np.array([[0.2, 0.8], [0.9, 0.1]])

Синтаксис:

Создадим два фактора, представляющих распределение двух переменных: P(A) и P(B|A). Первая переменная имеет безусловное распределение, значение второй зависит от значения первой.

Подготовка переменных (могут быть как дискретные, так и со связанным классификатором):

>>> from pyinference.fuzzy import set as fuzzy_set
>>> a = Variable(name='A', terms=['low', 'high'])
>>> fs = fuzzy_set.Partition(peaks=[0.0, 0.5, 1.0])
>>> b = Variable(name='B', terms=fs)

Создание факторов:

>>> A = Factor(name='A', cons=[a])
>>> B = Factor(name='B|A', cons=[b], cond=[a])
Поля класса:

name (str): имя фактора

cond (list): список условных переменных

cons (list): список подусловных переменных

vars (list): список всех переменных фактора (объединение предыдущих двух)

shape (tuple): кортеж мощностей всех переменных фактора (сохраняя порядок атрибута vars).
Соответствует форме массива cpd.

cpd (numpy.array): массив, хранящий распределение условной вероятности фактора.

Именованные параметры:

name (str): имя фактора

cons (list): массив подусловных переменных

cond (list): массив условных переменных

Исключения:
AttributeError: ошибка возникает, если массив подусловных переменных (cons) пуст
divide(other)[source]

Реализует деление факторов.

Деление факторов позволяет получить условное распределение из безусловного:

F(A,B) / F(B) = F(A|B)

Может вызываться как метод (p = f1.divide(f2)) или как оператор “/” (p = f1 / f2).

Синтаксис:
>>> import numpy as np
>>> c = Variable(name='C', terms=['no', 'yes'])
>>> t = Variable(name='T', terms=['pos', 'neg'])
>>> C = Factor(name='C', cons=[c])
>>> C.cpd = np.array([0.99, 0.01])
>>> T = Factor(name='T|C', cons=[t], cond=[c])
>>> T.cpd = np.array([[0.2, 0.8], [0.9, 0.1]])
>>> p = (C * T) / C
>>> "%0.3f" % p.cpd[0,0]
'0.200'
>>> len(p.vars)
2
Параметры:
other (Factor): фактор-делитель.
Возвращает:
Фактор-частное двух исходных
Исключения:
NotImplementedError: ошибка возникает, когда:
  • делитель имеет условные переменные;
  • некоторые подусловные переменные делителя отсутствуют среди подусловных переменных делимого

TypeError: ошибка возникает, когда второй операнд имеет неподдерживаемый тип.

marginal(var)[source]

Выполняет маргинализацию переменной из фактора.

Маргинализация позволяет исключить переменную из области определения фактора, просуммировав соответствующие значения назначений маргинализируемого фактора. Маргинализация является основой алгоритма variable elimination:

  • F(A,B,C) - B = F(A,C)
  • F(A,C|B) - B = F(A,C)
  • F(A,B|C) - B = F(A|C)

Может вызываться как метод (m = f1.marginal(var)) или как оператор “-” (m = f1 - var).

Синтаксис:
>>> import numpy as np
>>> c = Variable(name='C', terms=['no', 'yes'])
>>> t = Variable(name='T', terms=['pos', 'neg'])
>>> C = Factor(name='C', cons=[c])
>>> C.cpd = np.array([0.99, 0.01])
>>> T = Factor(name='T|C', cons=[t], cond=[c])
>>> T.cpd = np.array([[0.2, 0.8], [0.9, 0.1]])
>>> m = T - c
>>> m.cpd
array([ 1.1,  0.9])
>>> len(m.vars)
1
Параметры:
var (Variable or list): маргинализуемая (исключаемая) переменная.
Также в данный метод может передаваться список исключаемых переменных.
Возвращает:
Маргинализированный фактор
Исключения:
TypeError: ошибка возникает, когда второй операнд имеет неподдерживаемый тип.
product(other)[source]

Реализует произведение факторов.

Произведение факторов объединяет области определения двух факторов. Значением для каждого назначения является произведение соответствующих назначений множителей:

  • F(A) * F(B) = F(A,B)
  • F(A,|B) * F(B) = F(A,B)
  • F(A,B|C) * F(D|C) = F(A,B,D|C)
  • F(A,B|C) * F(D,C) = F(A,B,C,D)
  • None * F(A) = F(A)

Может вызываться как метод (p = f1.product(f2)) или как оператор “*” (p = f1 * f2).

Note

Также первым операндом произведения может выступать None (None * f1). Тогда метод вернет второй операнд. Это сделано для удобства множественного произведения.

Синтаксис:
>>> import numpy as np
>>> c = Variable(name='C', terms=['no', 'yes'])
>>> t = Variable(name='T', terms=['pos', 'neg'])
>>> C = Factor(name='C', cons=[c])
>>> C.cpd = np.array([0.99, 0.01])
>>> T = Factor(name='T|C', cons=[t], cond=[c])
>>> T.cpd = np.array([[0.2, 0.8], [0.9, 0.1]])
>>> p = T * C
>>> "%0.3f" % p.cpd[0,0]
'0.198'
>>> len(p.vars)
2
Параметры:
other (Factor): фактор-множитель.
Возвращает:
Фактор-произведение двух исходных
Исключения:

AttributeError: ошибка возникает, когда исключаемая переменная не входит в исходный фактор.

TypeError: ошибка возникает, когда второй операнд имеет неподдерживаемый тип.

pyinference.inference.net module

class pyinference.inference.net.Net(name='', nodes=None)[source]

Bases: object

Данный класс реализует смешанную сеть вывода.

Основным назначением данного класса является выполнение запросов к сети. Сеть формируется как набор факторов, характеризующих совместное распределение значений некоторого набора переменных.

Сети Байса традиционно представляются в виде графа, в котором вершины представляют переменные, входящие в сеть, а ребра – причинно-следственные связи, причем ребро направлено от причины к следствию. Это очень наглядное представление является одним из главных достоинств вероятностных графических моделей и позволяет отобразить условную вероятность в виде взаимосвязей переменных и факторов, а также зачастую построить граф по экспертным или эмпирическим данным для моделирования распределения вероятностей. В графе наглядно видна иерархичность условной вероятности. Если некая переменная X зависит от переменной Y, то переменная Y будет среди родителей переменной X на графе.

Запрос к байесовской сети выглядит следующим образом: каково распределение полной вероятности набора переменных Q, при условии, что набор переменных E принимает назначение q? Множество переменных Q называется запросом (query) или целевыми переменными и может состоять из одной и более переменных. Множество условий E называется наблюдения (evidence) или наблюдаемыми переменными и, в общем случае, может быть пустым. Множества Q и E не должны пересекаться. Множество переменных, входящих в байесовскую сеть, но не входящих во множества Q и E называется скрытые (hidden) переменные. Семантика этих множеств довольно очевидна. Запрос – это целевые переменные, которые нас интересуют, исходя из контекста конкретной задачи. Наблюдение – это те переменные, значения которых мы можем измерить или предсказать. Скрытые переменные не являются ни тем, ни другим, но могут оказывать неявное влияние на запрос и/или на наблюдения. В таких обозначениях использование сети Байеса для логического вывода сводится к вычислению вероятности P(Q|E).

Достоинством сетей Байеса является универсальность. Единожды сконструированная, сеть может использоваться для вычисления любых корректных запросов на области ее определения, то есть не нужно изменять конструкцию сети, чтобы выполнять запросы определенного вида. Запрос является корректным, если выполняются два условия: - все переменные входящие в множества наблюдений и запросов входят в область определения сети; - множества Q и E не пересекаются.

Итак, каждый запрос разбивает множество переменных области определения сети на три непересекающихся множества: Q, E и H. Значение любого запроса к Байсовской сети на этих множествах может быть вычислен только из фактора, представляющего распределение полной вероятности P(Q,E,H).

Синтаксис:
>>> import numpy as np
>>> from pyinference.inference.variable import Variable
>>> from pyinference.inference.factor import Factor
>>> c = Variable(name='C', terms=['no', 'yes'])
>>> t = Variable(name='T', terms=['pos', 'neg'])
>>> c_node = Factor(name='C', cons=[c])
>>> c_node.cpd = np.array([0.99, 0.01])
>>> t_node = Factor(name='T|C', cons=[t], cond=[c])
>>> t_node.cpd = np.array([[0.2, 0.8], [0.9, 0.1]])
>>> bn = Net(name='Cancer', nodes=[c_node, t_node])
Поля класса:

name (str): имя сети;

nodes(list): список факторов, составляющих сеть.

Именованные параметры:

name (str): имя сети;

nodes (list): список факторов, составляющих сеть.

Передача конструктору списока bn = Node(name='sample net', nodes=a_list) эквивалентна использованию метода add_node():

bn = Net(name='sample net')
for node in a_list:
    bn.add_node(node)

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

add_node(factor)[source]

Метод добавляет фактор к сети.

В процессе добавления фактора к сети производится проверка корректности. Он заключается в том, что мы не можем добаить к сети фактор, если его родителя в сети нет. Например, у нас есть два фактора: F(C) и G(T|C). Так как второй фактор (G) представляет условную вероятность, его родителем должен быть фактор, определяющий распределение вероятности переменной C, то есть, фактор F. Таким образом, если мы сначала попытаемся добавить к сети фактор G, то получим ошибку, так как его родителя в сети нет. Однако, если сперва добавить фактор F, а уже затем фактор G, то проблем не возникнет. Такая проверка гарантирует корректность графа, представляющего данную сеть.

Синтаксис:
>>> import numpy as np
>>> from pyinference.inference.variable import Variable
>>> from pyinference.inference.factor import Factor
>>> c = Variable(name='C', terms=['no', 'yes'])
>>> t = Variable(name='T', terms=['pos', 'neg'])
>>> c_node = Factor(name='C', cons=[c])
>>> c_node.cpd = np.array([0.99, 0.01])
>>> t_node = Factor(name='T|C', cons=[t], cond=[c])
>>> t_node.cpd = np.array([[0.2, 0.8], [0.9, 0.1]])
>>> bn = Net(name='Cancer')
>>> bn.add_node(c_node)
>>> bn.add_node(t_node)
Параметры:
factor (Factor): добавляемый фактор
Исключения:
AttributeError: ошибка возникает, если при добавлении фактора провалилась проверка корректности.
joint()[source]

Рассчитывает распределение совместной вероятности всех переменных сети.

Синтаксис:
>>> import numpy as np
>>> from pyinference.inference.variable import Variable
>>> from pyinference.inference.factor import Factor
>>> c = Variable(name='C', terms=['no', 'yes'])
>>> t = Variable(name='T', terms=['pos', 'neg'])
>>> c_node = Factor(name='C', cons=[c])
>>> c_node.cpd = np.array([0.99, 0.01])
>>> t_node = Factor(name='T|C', cons=[t], cond=[c])
>>> t_node.cpd = np.array([[0.2, 0.8], [0.9, 0.1]])
>>> bn = Net(name='Cancer', nodes=[c_node, t_node])
>>> j = bn.joint()
>>> j.shape
(2, 2)
>>> len(j.vars)
2
>>> "%0.3f" % j.cpd[0,0]
'0.198'
>>> "%0.3f" % j.cpd[1,1]
'0.001'
Возвращает:
Фактор (Factor), представляющий рапределение полной вероятности всех переменных сети.
query(query=None, evidence=None)[source]

Выполняет запрос к сети вывода.

Синтаксис:
>>> import numpy as np
>>> from pyinference.inference.variable import Variable
>>> from pyinference.inference.factor import Factor
>>> c = Variable(name='C', terms=['no', 'yes'])
>>> t = Variable(name='T', terms=['pos', 'neg'])
>>> c_node = Factor(name='C', cons=[c])
>>> c_node.cpd = np.array([0.99, 0.01])
>>> t_node = Factor(name='T|C', cons=[t], cond=[c])
>>> t_node.cpd = np.array([[0.2, 0.8], [0.9, 0.1]])
>>> bn = Net(name='Cancer', nodes=[c_node, t_node])
>>> q = bn.query(query=[c], evidence=[t])
>>> len(q.vars)
2
>>> q.cond[0].name
'T'
>>> q.cons[0].name
'C'
>>> "%0.3f" % q.cpd[0,0]
'0.957'
>>> "%0.3f" % q.cpd[1,1]
'0.001'
Именованные параметры:

query (list): список переменных (Variable) запроса;

evidence (list): список переменных (Variable) свидетельств.

Возвращает:
Фактор (Factor), представляющий рапределение условной вероятности, где условными переменными являются наблюдения (evidence), а подусловными - переменные запроса (query): F(Q|E).

pyinference.inference.variable module

class pyinference.inference.variable.Variable(name='', terms=None)[source]

Bases: object

Класс реализует переменную

Переменная представляет собой некий параметр, могущий иметь определенный набор значений. Набор значений переменной может задаваться двумя способами. Во-первых, можно задать списком. В таком случае, этот список следует передать как аргумент terms конструктора. Во-вторых, с переменной может быть ассоциирован нечеткий классификатор (см. pyinference.fuzzy.set.FuzzySet). Тогда передать конструктору следует его.

Переменная в байесовском моделировании – некая сущность, обладающая именем и областью определения. Обычно, рассматриваются переменные двух типов: дискретные и непрерывные. Дискретные переменные принимают значения из некоторого конечного множества X, а непрерывные – определены на некотором подмножестве множества действительных чисел. В общем случае, переменная определяется упорядоченной парой V=(N, X), где N – имя переменной, а X – множество возможных значений.

Примером случайной переменной может быть результат подбрасывания монеты в таком случае областью ее определения будет множество {“орел”, “решка”}. В общем случае, конкретные значения переменной не имеют синтаксического значения (имеют место только семантически, то есть по смыслу) и их обычно заменяют соответствующим по числу элементов подмножество множества натуральных числе. То есть в нашем примере, можно обозначить значение «решка» за 0, а «орел» - за 1, и тогда область определения переменной будет {0, 1}.

Построим данную переменную с использованием класса Variable:

coin = Variable(name="coin", terms=["орел", "решка"])

Частным и довольно распространенным случаем дискретной переменной является переменная, способная принимать только два значения. Такая переменная называется бинарной. В примере выше – результат подбрасывания монеты – бинарная переменная.

Наиболее важным производным свойством дискретной переменной является мощность переменной – количество значений, которые она может принимать. Мощность бинарной переменной равна двум.

Синтаксис:
>>> import pyinference.inference.variable
>>> a = Variable(name='a', terms=[0, 1])
>>> a.value = 'low'
>>> from pyinference.fuzzy import set as fuzzy_set
>>> fs = fuzzy_set.Partition(peaks=[0.0, 0.5, 1.0])
>>> b = Variable(name='B', terms=fs)
Поля класса:

card (int): мощность переменной (количество значений)

classifier(dict or pyinference.fuzzy.set.FuzzySet): связанный с переменной классификатор

name (str): имя переменной

terms (list): список значений переменной (терм-множество)

value (object): текущее значение переемнной

Именованные параметры:

name (str): имя переменной

terms (list or dict or pyinference.fuzzy.set.FuzzySet): набор значений переменной

Исключения:
TypeError: ошибка возникает, если агрумент terms имеет неподдерживаемый тип.
equals(value)[source]

Проверка переменной на равенство значению.

Данный метод принимает некое значение и вычисляет меру сходства его со значением атрибута value.

Синтаксис:
>>> import pyinference.inference.variable
>>> a = Variable(name='a', terms=[0, 1])
>>> a.value = 'low'
>>> '%.2f' % a.equals('low')
'1.00'
>>> '%.2f' % a.equals('high')
'0.00'
>>> from pyinference.fuzzy import set as fuzzy_set
>>> import pyinference.inference.variable
>>> fs = fuzzy_set.Partition(peaks=[0.0, 0.5, 1.0])
>>> b = Variable(name='B', terms=fs)
>>> b.value = 0.5
>>> '%.2f' % b.equals(0.5)
'1.00'
>>> b.value = '1'
>>> '%.2f' % b.equals(0.25)
'0.50'
Параметры:
value (object): Значение переменной. Может быть как элементом терм-множества занчений, явно перечисленного в атрибуте terms класса, так и элементом области определения связанного с этой переменной классификатора.
Возвращает:
Действительное число x, где -1.0 <= x <= 1.0, характеризующую меру сходства переданного и текущего значений переменной.
Исключения:
AttributeError: если текущее значение переменной не было задано до вызова данного метода.

Module contents