2016-02-18 6 views
10

Я следовал за бумагой here и кодом here (он реализован с использованием симметричной kld и модели отступания, предложенной в статье в 1-й ссылке) для вычисления KLD между двумя текстовые наборы данных. Я изменил для цикла, в конце концов, чтобы вернуть распределение вероятностей двух наборов данных, чтобы проверить, если оба сумму до 1:Вычисление симметричных расхождений Kullback-Leibler между двумя документами

import re, math, collections 

def tokenize(_str): 
    stopwords = ['and', 'for', 'if', 'the', 'then', 'be', 'is', \ 
       'are', 'will', 'in', 'it', 'to', 'that'] 
    tokens = collections.defaultdict(lambda: 0.) 
    for m in re.finditer(r"(\w+)", _str, re.UNICODE): 
     m = m.group(1).lower() 
     if len(m) < 2: continue 
     if m in stopwords: continue 
     tokens[m] += 1 

    return tokens 
#end of tokenize 

def kldiv(_s, _t): 
    if (len(_s) == 0): 
     return 1e33 

    if (len(_t) == 0): 
     return 1e33 

    ssum = 0. + sum(_s.values()) 
    slen = len(_s) 

    tsum = 0. + sum(_t.values()) 
    tlen = len(_t) 

    vocabdiff = set(_s.keys()).difference(set(_t.keys())) 
    lenvocabdiff = len(vocabdiff) 

    """ epsilon """ 
    epsilon = min(min(_s.values())/ssum, min(_t.values())/tsum) * 0.001 

    """ gamma """ 
    gamma = 1 - lenvocabdiff * epsilon 

    """ Check if distribution probabilities sum to 1""" 
    sc = sum([v/ssum for v in _s.itervalues()]) 
    st = sum([v/tsum for v in _t.itervalues()]) 

    ps=[] 
    pt = [] 
    for t, v in _s.iteritems(): 
     pts = v/ssum 
     ptt = epsilon 
     if t in _t: 
      ptt = gamma * (_t[t]/tsum) 
     ps.append(pts) 
     pt.append(ptt) 
    return ps, pt 

Я протестирована с

d1 = """Many research publications want you to use BibTeX, which better organizes the whole process. Suppose for concreteness your source file is x.tex. Basically, you create a file x.bib containing the bibliography, and run bibtex on that file.""" d2 = """In this case you must supply both a \left and a \right because the delimiter height are made to match whatever is contained between the two commands. But, the \left doesn't have to be an actual 'left delimiter', that is you can use '\left)' if there were some reason to do it."""

sum(ps) = 1 но sum(pt) это путь меньше, чем 1, когда:

This should be the case.

ли Ther e что-то неправильное в коде или еще? Благодаря!

Update:

Для того, чтобы как пт и пс сумму до 1, я должен был изменить код на:

vocab = Counter(_s)+Counter(_t) 
    ps=[] 
    pt = [] 
    for t, v in vocab.iteritems(): 
     if t in _s: 
      pts = gamma * (_s[t]/ssum) 
     else: 
      pts = epsilon 

     if t in _t: 
      ptt = gamma * (_t[t]/tsum) 
     else: 
      ptt = epsilon 

     ps.append(pts) 
     pt.append(ptt) 

    return ps, pt 
+0

Не связанный с вашим вопросом, в тестовых строках (d1 и d2), вы должны использовать две последовательные обратные косые черты. Символ обратной косой черты используется для экранирования в python. Пример: 'x =" \\ left "вместо" x = "\ left". –

ответ

2

Обе суммы (PS) и суммы (PT) являются суммарная вероятность масса _s и _t над суппами ort из s (под «поддержкой s» я имею в виду все слова, которые появляются в _s, независимо от слов, которые появляются в _t). Это означает, что

  1. sum (ps) == 1, так как for-loop суммирует все слова в _s.
  2. sum (pt) < = 1, где равенство будет выполняться, если носитель t является подмножеством носителя s (т. Е. Если все слова в _t появляются в _s). Кроме того, sum (pt) может быть близким к 0, если совпадение слов в _s и _t невелико. В частности, если пересечение _s и _t является пустым множеством, то sum (pt) == epsilon * len (_s).

Итак, я не думаю, что есть проблемы с кодом.

Кроме того, вопреки названию вопроса kldiv() не вычисляет симметричную KL-расходимость, а KL-расходимость между _s и сглаженной версией _t.

+0

Спасибо Tomer! «Они - вероятности за поддержку s» имеет смысл сейчас. Хотя в документе было указано, что это симметричный KLD, вы считаете, что реализация здесь немного ушла? – Blue482

+0

Не могли бы вы рассказать о остальной части кода? –

+0

Привет, Tomer, я внес некоторые небольшие изменения из [исходного кода] (https://gist.github.com/mrorii/961963), и его можно найти здесь [https://gist.github.com/bluemonk482/f3e2fd35a774a61dbedd). Модифицированный код вычисляет ps и pt на основе их объединения vocab, а не полагается на поддержку s. Считаете ли вы, что это лучшая версия kld, чем первоначальная реализация, чтобы измерить расстояние между двумя текстовыми корпусами? Спасибо! – Blue482

0

Сумма ваших распределений вероятностей для каждого документа сохраняются в переменных sc и st, те близки к 1.