Вычисления симметрических Кульбака-Лейблера расхождение между двумя документами
Я следил за бумагой здесь и код здесь (реализовано с использованием симметричной kld и обратной модели, предложенной в статье в 1-й ссылке) для вычисления KLD между двумя наборами текстовых данных. Я изменил for-loop в конце, чтобы вернуть распределение вероятностей двух наборов данных для проверки, если обе суммы равны 1:
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 когда:
есть ли что-то, что неправильно в коде или иначе? Спасибо!
обновление:
чтобы сделать сумму pt и ps равной 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
2 ответов
как сумма (ps), так и сумма(pt) являются общей массой вероятности _s и _t над поддержкой s (под" поддержкой s " я подразумеваю все слова, которые появляются в _s, независимо от слов, которые появляются в _t). Это значит, что
- sum (ps)==1, так как for-loop суммирует все слова в _s.
- sum (pt)
Так, я не думаю, что есть проблема с кодом.
кроме того, вопреки названию вопроса, kldiv () вычисляет не симметричную KL-дивергенцию, а KL-дивергенцию между _s и сглаженной версией _t.
сумма ваших вероятностных распределений для каждого документа хранится в переменных sc
и st
, они близки к 1.