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