NgramModelμμ λ°±μ€ν ννμ κ³μ°νλ λ°©λ²μ μ€λ₯κ° μλ€κ³ μκ°ν©λλ€.
λ°±μ€ν κ³μ°μ 컨ν μ€νΈ 'b'μ λν΄ λ€μμ μνν΄μΌ νλ€κ³ μκ°νμ΅λλ€.
μ΄κ²μ λ³Έμ§μ μΌλ‘ λΉ κ·Έλ¨ μ»¨ν μ€νΈμμ κ΄μ°°λμ§ μμ λ¨μ΄μ λν μ λκ·Έλ¨ νλ₯ μ μ μ νκ² μ‘°μ νμ¬ λλ½λ νλ₯ μ§λμ μ±μλλ€.
λ΄κ° λκ°λ₯Ό λμΉκ³ μμ΅λκΉ? NgramModelμ μ½λλ 보기μ λ€μ λ€λ₯Έ μμ μ μννλ©° μ΄ν΄ν μ μμμ΅λλ€.
λλ μ΄κ²μ΄ μ€μ λ‘ λ²κ·ΈλΌκ³ λΉμ μ΄ μ³λ€κ³ λ―Ώμ΅λλ€.
μ΄ μ€μ μ κ°μ νλ©΄:
from nltk.model import NgramModel
from nltk.probability import LidstoneProbDist
word_seq = list('aaaababaaccbacb')
words = ['a', 'b', 'c', '']
est = lambda freqdist, bins: LidstoneProbDist(freqdist, 0.2, bins=bins)
model = NgramModel(2, word_seq, True, True, est, 4)
μ°λ¦¬λ λ§€μ° λΉ λ₯΄κ² λΆμΌμΉλ₯Ό λ³Ό μ μμ΅λλ€.
sum(model.prob(w, ['b']) for w in words)
Out[150]: 2.4583333333333335
sum(model.prob(w, ['a']) for w in words)
Out[151]: 1.0
[(w, model.prob(w, ['b'])) for w in words]
Out[152]:
[('a', 0.6666666666666667),
('b', 0.875),
('c', 0.6666666666666667),
('', 0.25)]
[(w, model.prob(w, ['a'])) for w in words]
Out[153]:
[('a', 0.47727272727272724),
('b', 0.25),
('c', 0.25),
('', 0.022727272727272728)]
μΌλ§ μ μ NgramModelμ μμ ν λ λ°±μ€νκ° κ΅¬νλλ λ°©μμ΄ μ½κ° νΌλμ€λ¬μ λ κΈ°μ΅μ΄ μμ΅λλ€. μ€λ«λμ κ·Έκ²μ λ³΄μ§ μμκΈ° λλ¬Έμ μ΄λ»κ² μλνλμ§ μ§κ΄μ μΌλ‘ μ΄ν΄νμ§ λͺ»νμ΅λλ€. μ°λ¦¬κ° Katz Back-offλ₯Ό ꡬννκ³ μλ€κ³ μ£Όμ₯νμ§λ§ κ³μ°μ Wikipedia μ κ³μ°κ³Ό μ½κ° λ€λ¦ λλ€.
NgramModel._beta
μμ νΈμΆλλ LidstoneProbDist.discount
ν¨μκ° μ΄λ―Έ ν©μ°μ κ³ λ €νκ³ μκΈ° λλ¬Έμ΄λΌκ³ μκ°νμ§λ§ λ μ΄ν΄λ΄μΌ ν©λλ€.
def _alpha(self, tokens):
return self._beta(tokens) / self._backoff._beta(tokens[1:])
def _beta(self, tokens):
return (self[tokens].discount() if tokens in self else 1)
λ΄κ° 보기μ λ² ν κ³μ°μ μΌμ΄ μλͺ»λκ³ μλ κ² κ°μ΅λλ€. μλνλ©΄ λ°μ΄κ·Έλ¨ μμ€μ λ² νκ° μ λκ·Έλ¨ μμ€μ λ² νλ³΄λ€ ν¨μ¬ 컀μ λΉμ¨ μνλ₯Ό μμλ‘ λ§λ€κΈ° λλ¬Έμ λλ€.
model._beta(('b',))
Out[154]: 0.16666666666666669
model._backoff._beta(())
Out[155]: 0.05063291139240506
model._alpha(('b',))
Out[155]: 3.291666666666667
λλ λν λ¬Έμ κ° μλ μ€μ LidstoneProbDist μ체μμ λ°°μ νμ΅λλ€.
[(w, model._model[('b',)].prob(w)) for w in words]
Out[159]:
[('a', 0.6666666666666667),
('b', 0.04166666666666667),
('c', 0.04166666666666667),
('', 0.25)]
sum([model._model[('b',)].prob(w) for w in words])
Out[161]: 1.0
μ΄ λͺ¨λ λΆλΆμ΄ μ΄λ»κ² λ€μ μ°κ²°λλμ§ μμλ΄κ³ μ΄ λ¬Έμ λ₯Ό ν΄κ²°ν μ μλμ§ νμΈνλ €κ³ ν©λλ€. λ€λ₯Έ μ¬λμ΄ @desilinguistμ κ°μ΄ λ°μ΄λ€κ³ μΆμ΄νλλΌλ μ΄μ λν λ€λ₯Έ μκ°μ μ£Όμλ©΄ κ°μ¬νκ² μ΅λλ€.
μλ νμΈμ. νμΈν΄ μ£Όμ μ κ°μ¬ν©λλ€. λͺ κ°μ§λ§ λ μκ°νλ©΄ λ€μκ³Ό κ°μ΅λλ€.
첫째, νΌλμ€λ¬μ΄ ν κ°μ§λ "ν μΈ"μ λ€λ₯Έ κ°λ μ λλ€. λ€μν ννν λ°©λ²μ μν΄ λ¬μ±λλ ν μΈμ΄ μμ΅λλ€. μλ₯Ό λ€μ΄, λ¨μ Laplacian(1 μΆκ°) νννλ κ΄μ°°λ λ¨μ΄μ νλ₯ μ ν μΈνκ³ ν΄λΉ μ§λμ κ΄μ°°λμ§ μμ λ¨μ΄λ‘ μ΄λν©λλ€. _beta ν¨μμμ νΈμΆλλ discount() ν¨μλ ProbDistμ μν΄ μνλλ νννλ₯Ό μν κ²μ΄λ©° λ°±μ€ν νννμ κ΄λ ¨μ΄ μλ€κ³ μκ°ν©λλ€. ν μΈμ λν λ°±μ€ν κ°λ μ κ³ μ°¨ λͺ¨λΈμ λ€λ₯Έ 컨ν μ€νΈμ λν΄ "λλ½"(κ΄μ°°λμ§ μμ)λ λ¨μ΄ νμ μ§ν©μ νλ₯ κ³Ό κ΄λ ¨μ΄ μλ€κ³ μκ°ν©λλ€.
κ·Έλμ μ λ μ λͺ©μ μ λ§κ² μ½λλ₯Ό μμ νμ¬ μ κ° μ³λ€κ³ μκ°νλ μμ μ μννμΌλ©° μλμμ μΌλΆ μ€λν«μ 곡μ νμ΅λλ€. κΈ°λ³Έμ μΌλ‘ μ£Όμ΄μ§ 컨ν μ€νΈμ λν λͺ¨λΈμμ λλ½λ λ¨μ΄μ νμ μ§ν©μ μλ³νκ³ ν΄λΉ νμ μ§ν©μ λν΄ μ΄λ¬ν "λλ½λ" λ¨μ΄μ μ΄ νλ₯ κ³Ό λ°±μ€ν λͺ¨λΈμ ν΄λΉ μλμ κ³μ°ν©λλ€. λΉμ¨μ "μν"μ΄λ©° μ΄κ²μ 컨ν μ€νΈμ ν¨μμ λλ€. λλ μ΄ κ΅¬νμ΄ λΉμ μ΄ μ 곡ν Wikipedia λ§ν¬μ μλ κ²κ³Ό μΌμΉνλ€κ³ μκ°ν©λλ€. λν μ κ²½μ°μλ _beta ν¨μλ₯Ό λ μ΄μ μ¬μ©νμ§ μμ΅λλ€.
μ΄κ²μ΄ ν λ‘ μ μ μ©νκΈ°λ₯Ό λ°λλλ€. λ€μ νλ² κ°μ¬ν©λλ€.
# (Code fragment for calculating backoff)
# Now, for Katz backoff smoothing we need to calculate the alphas
if self._backoff is not None:
self._backoff_alphas = dict()
# For each condition (or context)
for ctxt in self._cfd.conditions():
pd = self._model[ctxt] # prob dist for this context
backoff_ctxt = ctxt[1:]
backoff_total_pr = 0
total_observed_pr = 0
for word in self._cfd[ctxt].keys(): # this is the subset of words that we OBSERVED
backoff_total_pr += self._backoff.prob(word,backoff_ctxt)
total_observed_pr += pd.prob(word)
assert total_observed_pr <= 1 and total_observed_pr > 0
assert backoff_total_pr <= 1 and backoff_total_pr > 0
alpha_ctxt = (1.0-total_observed_pr) / (1.0-backoff_total_pr)
self._backoff_alphas[ctxt] = alpha_ctxt
# Updated _alpha function, discarded the _beta function
def _alpha(self, tokens):
"""Get the backoff alpha value for the given context
"""
if tokens in self._backoff_alphas:
return self._backoff_alphas[tokens]
else:
return 1
μλ νμΈμ μ¬λ¬λΆ, μ λ μ΄ ν λ‘ μ μ°Έμ¬νκ³ μΆμκ³ , λ¬Έμ κ° λ¨μν 1.0μ΄ λμ§ μμ νλ₯ μ κ°λ κ²λ³΄λ€ ν¨μ¬ λ λμλ€λ μ μ μ§μ νκ³ μΆμμ΅λλ€.
λ€μ νΈλΌμ΄κ·Έλ¨ μλ₯Ό κ³ λ €νμμμ€.
#!/usr/bin/python
from nltk.model import NgramModel
from nltk.probability import LidstoneProbDist
word_seq = ['foo', 'foo', 'foo', 'foo', 'bar', 'baz']
# Set up a trigram model, nothing special
est = lambda freqdist, bins: LidstoneProbDist(freqdist, 0.2, bins)
model = NgramModel(3, word_seq, True, True, est, 3)
# Consider the ngram ['bar', 'baz', 'foo']
# We've never seen this before, so the trigram model will fall back
context = ('bar', 'baz',)
word = 'foo'
print "P(foo | bar, baz) = " + str(model.prob(word,context))
# Result:
# P(foo | bar, baz) = 2.625
μ -- μ΄ μ‘°κ±΄λΆ νλ₯ μ > 1.0μ λλ€.
λΆμΎν λΆλΆμ λͺ¨λΈμ΄ λ€λ‘ λ¬Όλ¬λ μλ‘ νλ₯ μ΄ λ λΆνλ €μ§λ€λ κ²μ λλ€.
λ λ§μ νλ ¨ μμ λ₯Ό μΆκ°ν μλ‘ λ¬Έμ λ λμ± μ νλ©λλ€!
word_seq = ['foo' for i in range(0,10000)]
word_seq.append('bar')
word_seq.append('baz')
est = lambda freqdist, bins: LidstoneProbDist(freqdist, 0.2, bins)
model = NgramModel(3, word_seq, True, True, est, 3)
# Consider the ngram ['bar', 'baz', 'foo']
# We've never seen this before, so the trigram model will fall back
context = ('bar', 'baz',)
word = 'foo'
print "P(foo | bar, baz) = " + str(model.prob(word,context))
# Result:
P(foo | bar, baz) = 6250.125
νμ¬ μνλ‘ NgramModelμ μ λ’°ν μ μμ΅λλ€.
@afourney : μ΄κ²μ΄ μλλ κ²μ΄λΌκ³ μκ°ν©λλ€(LidstoneProbDistμλ SUM_TO_ONE = False
μμ±μ΄ μμ΅λλ€)
@afourney μ΄ λ¬Έμ κ° ν΄κ²°λ λκΉμ§ NgramModelμ μ€μ λ‘ μ¬μ©ν μ μλ€λ λ° λμν©λλ€. λΆννλ, λλ μ΅κ·Όμ μ΄κ²μ μ°λ¬λ³Ό μκ°μ΄ μμμ΅λλ€.
@kmike SUM_TO_ONEμ LidstoneProbDistμ λν΄ Falseμ λλ€. μ΄κΈ° λ°°ν¬μ μλ μ΄λ²€νΈκ° λ°μνκ³ bins κ°μ κ°λ₯ν μ΄λ²€νΈ μλ‘ μ€μ νμ§ μμ κ²½μ° ν©μ΄ 1μ΄ λμ§ μκΈ° λλ¬Έμ λλ€. κ·Έλ¬λ μ μ νκ² μ¬μ©νλ©΄ μ€μ λ‘ ν©μ΄ νλλ‘ λ©λλ€. μ¬κΈ°μ λ¬Έμ λ LidstoneProbDist μμ²΄κ° μλλΌ NgramModelμ λ² ν κ³μ°μ λλ€.
@kmike : μ, SUM_TO_ONEμ΄ κ±°μ§μμ μμμ°¨λ Έμ΅λλ€. λ΄ μ°λ €λ λͺ¨λΈμ΄ ν©κ³μ ν΅ν©νκΈ° μ μ μ΄λ―Έ 1λ³΄λ€ ν° κ°λ³ μ‘°κ±΄λΆ νλ₯ (λ¨μΌ μ΄λ²€νΈμ κ²½μ°)μ λ°ννλ€λ κ²μ λλ€.
@bcroy κ·νμ μ루μ μ΄ μ¬λ°λ₯Έ μ κ·Ό λ°©μμ΄λΌκ³ μκ°ν©λλ€. κ°λ¨ν λ§ν΄μ _alphaλ λ κ°μ§ μ€μν μμ μ μνν©λλ€.
μ¦, NgramModelμ΄ λ°±μ€ν μ λ΅μ λμμΌλ‘ λ³΄κ° μ λ΅λ μ 곡νλ©΄ μ’μ κ²μ λλ€. μ΄κ²μ Jelinek-Mercer λλ Witten-Bell νννμ λν μ§μμ κ°λ₯νκ² ν©λλ€. νμλ κ°λ¨νκ³ λ§€μ° μ μλν©λλ€. μ°Έμ‘°: http://nlp.stanford.edu/~wcmac/papers/20050421-smoothing-tutorial.pdf
λκ΅°κ° μ΄κ²μ΄ μ¬μ ν κ³΅κ° λ²κ·ΈμΈμ§ νμΈν μ μμ΅λκΉ?
μ, μ¬μ ν P(foo | bar, baz) = 2.625λ₯Ό μ»κ³ μμ΅λλ€.
μλ νμΈμ μ¬λ¬λΆ,
μ΄ λ¬Έμ μ μ§μ μ΄ μμ΅λκΉ? μμ§ μ€ν λ²κ·ΈμΈκ°μ? λλ P(foo | bar, baz) = 2.625λ₯Ό μ»κ³ μμΌλ―λ‘ λ¬Έμ κ° κ³μλ©λλ€.
NLPμ κ±°μ λͺ¨λ μ ν리μΌμ΄μ μ μΈμ΄ λͺ¨λΈμ΄ μ¬μ©λκΈ° λλ¬Έμ μ΄κ²μ΄ μ€μν λ¬Έμ μ΄κ³ μμ λμ΄μΌ νλ€κ³ μκ°ν©λλ€.
λΆννλ μ λ NgramModel
μ μλ§μ λ¬Έμ λ₯Ό μ΄ν΄λ³Ό μκ°μ΄ μμκ³ μ‘°λ§κ° κ·Έλ κ² ν μ μμ κ²μ΄λΌκ³ μκ°νμ§ μμ΅λλ€. λκ΅°κ° μ΄ λ²κ·Έλ₯Ό λ€λ£° λκΉμ§ NgramModel
λ nltkμμ μ κ±°λμμ΅λλ€.
λ, λ΅λ³ κ°μ¬ν©λλ€.
μ λ°μ΄νΈλ₯Ό νμΈνλ μ€μ λλ€. μΌλΆ λ¬Έμ κ° μ’ λ£λ κ²μ λ³Ό μ μμ§λ§ μμ§ μ¬μ©ν μ μλμ§ νμΈνκ³ μΆμ΅λκΉ?
@ZeerakW λΆννλ ngram λͺ¨λΈμλ κ±°μ μ§μ μ΄ μμκ³ μ무λ μμ§ μ΄λ₯Ό ν΄κ²°νκΈ°λ‘ μ½μνμ§ μμμ΅λλ€.
2016λ μ λ€μ΄μλ©΄μ 'ngram λͺ¨λΈ' λ¬Έμ λ λ³ μ§μ μ΄ μμλ€.
μ¬λ¬λΆ, μ°λ¦¬λ λ§μΉ¨λ΄ μ΄κ²μ λ«μ μ μμ΅λλ€ :)
μ λ°μ΄νΈ 2018. μ΄λ―Έ μ‘Έμ νκ³ μμ μ μμνμ§λ§ μ¬μ ν Ngram λ¬Έμ κ° μ‘΄μ¬ν©λλ€.
μ¬λ¦!
κ°μ₯ μ μ©ν λκΈ
2016λ μ λ€μ΄μλ©΄μ 'ngram λͺ¨λΈ' λ¬Έμ λ λ³ μ§μ μ΄ μμλ€.