МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ “ЛЬВІВСЬКА ПОЛІТЕХНІКА”
ІНСТИТУТ КОМП’ЮТЕРНИХ НАУК ТА ІНФОРМАЦІЙНИХ ТЕХНОЛОГІЙ
Кафедра “Системи автоматизованого проектування”
Звіт до лабораторної роботи №6
ВИВЧЕННЯ БІБЛІОТЕКИ ПРИКЛАДНИХ ПРОГРАМ NLTK, ДЛЯ ОПРАЦЮВАННЯ ТЕКСТІВ ПРИРОДНОЮ МОВОЮ. АВТОМАТИЧНИЙ МОРФОЛОГІЧНИЙ АНАЛІЗ (частина2).
МЕТА РОБОТИ
Вивчення основ програмування на мові Python.
Ознайомлення з автоматичним морфологічним аналізом в NLTK.
КОРОТКІ ТЕОРЕТИЧНІ ВІДОМОСТІ
Початкова точка та багатопрохідний аналізатор (baselines and backoff).
Продуктивність аналізаторів, які розглядалися в попередній лабораторній роботі є невисокою. Для підвищення продуктивності, приблизно до 90%, необхідно виконати наступні дії. Потрібно встановити більш принципову початкову точку продуктивності ніж в аналізатора по замовчуванню, який є занадто простий та в аналізатора на основі регулярних виразів, який також дає довільні результати. Потрібно забезпечити багато прохідність аналізу, таким чином, що якщо більш спеціалізований аналізатор не може знайти відповідного тега то відбувається повернення до більш загального аналізатора.
Двопрохідний аналізатор (backoff).
У випадку, коли спочатку потрібно використати аналізатор на основі підстановок, а потім, якщо він не зміг встановити відповідного тега, використати аналізатор по замовчуванню необхідно поєднати ці два аналізатори. Для цього потрібно визначити аналізатор по замовчуванню, як аргумент в аналізаторі на основі підстановок і який буде викликати його кожен раз коли не зможе встановити самостійно відповідний тег.
Юніграм аналізатор (unigram).
Tag.Unigram – це клас, який реалізовує простий статистичний алгоритм маркування слів. Кожному слову (tokens) ставиться у відповідність тег, який має найбільшу ймовірність. Наприклад, згідно цього алгоритму тег jj буде поставлений у відповідність до кожного слова frequent (випадку появи) в тексті, оскільки це слово частіше використовується, як прикметник (a frequent word) і рідко як дієслово (I frequent this lecture).
Перед використанням юніграм аналізатора для аналізу тексту потрібно провести його тренування на розміченому корпусі текстів. Аналізатор використовує корпус для визначення тегів, які властиві кожному слову. Тренування проводиться за допомогою метода train(), який має один аргумент – розмічений корпус.
Комбінування аналізаторів.
Одним з методів знаходження балансу між точністю аналізаторів та охопленням лексики це використовувати більш точні алгоритми коли можливо це зробити і повертатись до алгоритмів з більшим охопленням коли це необхідно. Наприклад, можна комбінувати результати роботи біграм аналізатора, юніграм аналізатора та аналізатора по замовчуванню наступним чином:
Визначаємо теги за допомогою біграм аналізатора
Якщо біграм аналізатор не встановив тег для поточного слова – використовується юнігам аналізатор.
Якщо юніграм аналізатор не встановив тег для поточного слова – використовується аналізатор по замовчуванню.
Кожен NLTK аналізатор, крім аналізатора по замовчувані може мати вказівку на використання іншого аналізатора для побудови багато прохідного аналізатора.Хід роботи
6.1 >>> import nltk
>>> from nltk import corpus
>>> fd = nltk.FreqDist(nltk.corpus.brown.words(categories='l'))
>>> most_freq_words = fd.sorted()[:100]
>>> most_freq_words
['.', ',', 'the', 'to', 'and', 'a', 'of', 'was', '``', "''", 'he', '?', 'in', 'I', 'his', 'had', 'it', 'that', 'on', 'He', 'for', 'you', 'him', 'with', 'at', 'her', 'as', '--', 'The', 'be', ';', 'she', 'have', 'up', 'out', 'said', 'not', 'but', 'would', 'from', 'one', 'back', 'were', 'been', 'there', 'all', 'no', 'this', 'into', 'could', 'It', 'like', 'She', 'if', 'or', 'about', 'an', 'them', 'is', 'me', 'when', 'what', 'over', 'they', 'man', 'by', 'so', '!', 'my', 'then', 'get', 'do', 'just', 'know', 'now', 'down', 'time', 'There', 'door', 'go', 'two', 'But', 'who', 'see', 'off', 'more', 'went', 'got', 'around', 'You', 'here', "didn't", 'some', 'too', "don't", 'car', 'before', 'your', 'And', 'going']
>>> cfd = nltk.ConditionalFreqDist(nltk.corpus.brown.tagged_words(categories='l'))
>>> likely_tags = dict((word, cfd[word].max()) for word in most_freq_words)
>>> baseline_tagger = nltk.UnigramTagger(model=likely_tags)
>>> nltk.tag.accuracy(baseline_tagger, nltk.corpus.brown.tagged_sents(categories='l'))
0.52640417009218288
>>> baseline_tagger = nltk.UnigramTagger(model=likely_tags, backoff=nltk.DefaultTagger('NN'))
>>> nltk.tag.accuracy(baseline_tagger, nltk.corpus.brown.tagged_sents(categories='l'))
0.63298291031852927
>>> baseline_tagger = nltk.UnigramTagger(model=likely_tags)
>>> nltk.tag.accuracy(baseline_tagger, nltk.corpus.brown.tagged_sents(categories='l'))
0.52640417009218288
>>> def performance(cfd, wordlist):
lt = dict((word, cfd[word].max()) for word in wordlist)
baseline_tagger = nltk.UnigramTagger(model=lt, backoff=nltk.DefaultTagger('NN'))
return nltk.tag.accuracy(baseline_tagger, nltk.corpus.brown.tagged_sents(categories='l'))
>>> def display():
import pylab
words_by_freq = nltk.FreqDist(nltk.corpus.brown.words(categories='l')).sorted()
cfd = nltk.ConditionalFreqDist(nltk.corpus.brown.tagged_words(categories='l'))
sizes = 2 ** pylab.arange(5)
perfs = [performance(cfd, words_by_freq[:size]) for size in sizes]
pylab.plot(sizes, perfs, '-bo')
pylab.title('Lookup Tagger Performance with Varying Model Size')
pylab.xlabel('Model Size')
pylab.ylabel('Performance')
pylab.show()
>>> display()
>>> def display():
import pylab
words_by_freq = nltk.FreqDist(nltk.corpus.brown.words(categories='l')).sorted()
cfd = nltk.ConditionalFreqDist(nltk.corpus.brown.tagged_words(categories='l'))
sizes = 2 ** pylab.arange(30)
perfs = [performance(cfd, words_by_freq[:size]) for size in sizes]
pylab.plot(sizes, perfs, '-bo')
pylab.title('Lookup Tagger Performance with Varying Model Size')
pylab.xlabel('Model Size')
pylab.ylabel('Performance')
pylab.show()
>>> display()
6.4 >>> import nltk
>>> from nltk import corpus
>>> brown_a = nltk.corpus.brown.tagged_sents(categories='a')
>>> sent = nltk.corpus.brown.sents(categories='a')[2007]
>>> g=[-1,-2,-3]
>>> for i in g:
nltk.AffixTagger(brown_a, affix_length=i, min_stem_length=3).tag(sent)
[('Various', 'NNS'), ('of', None), ('the', None), ('apartments', 'NNS'), ('are', None), ('of', None), ('the', None), ('terrace', 'NN'), ('type', 'NN'), (',', None), ('being', 'VBG'), ('on', None), ('the', None), ('ground', 'VBD'), ('floor', 'NN'), ('so', None), ('that', 'NN'), ('entrance', 'NN'), ('is', None), ('direct', 'NN'), ('.', None)]
[('Various', 'JJ'), ('of', None), ('the', None), ('apartments', 'NNS'), ('are', None), ('of', None), ('the', None), ('terrace', 'NN'), ('type', None), (',', None), ('being', 'VBG'), ('on', None), ('the', None), ('ground', 'NN'), ('floor', 'NN'), ('so', None), ('that', None), ('entrance', 'NN'), ('is', None), ('direct', 'NN'), ('.', None)]
[('Various', 'JJ'), ('of', None), ('the', None), ('apartments', 'NNS'), ('are', None), ('of', None), ('the', None), ('terrace', 'NN'), ('type', None), (',', None), ('being', None), ('on', None), ('the', None), ('ground', 'RB'), ('floor', None), ('so', None), ('that', None), ('entrance', 'NN'), ('is', None), ('direct', 'NN'), ('.', None)]
>>> brown_l = nltk.corpus.brown.tagged_sents(categories='l')
>>> sent = nltk.corpus.brown.sents(categories='l')[2006]
>>> g=[-1,-2,-3,-4]
>>> for i in g:
nltk.AffixTagger(brown_l, affix_length=i, min_stem_length=3).tag(sent)
[('Nothing', 'VBG'), ('bald', 'VBD'), (',', None), ('open', 'NN'), (';', None), (';', None)]
[('Nothing', 'VBG'), ('bald', None), (',', None), ('open', None), (';', None), (';', None)]
[('Nothing', 'VBG'), ('bald', None), (',', None), ('open', None), (';', None), (';', None)]
[('Nothing', 'PN'), ('bald', None), (',', None), ('open', None), (';', None), (';', None)]
>>> sent = nltk.corpus.brown.sents(categories='l')[2007]
>>> for i in g:
nltk.AffixTagger(brown_l, affix_length=i, min_stem_length=3).tag(sent)
[('but', None), ('enough', 'IN'), ('.', None)]
[('but', None), ('enough', 'IN'), ('.', None)]
[('but', None), ('enough', 'IN'), ('.', None)]
[('but', None), ('enough', None), ('.', None)]
>>>
6.6 >>> import nltk
>>> from nltk import corpus
>>> brown_l = nltk.corpus.brown.tagged_sents(categories='l')
>>> sent = nltk.corpus.brown.sents(categories='l')[2007]
>>> t0 = nltk.DefaultTagger('NN')
>>> unigram_tagger = nltk.UnigramTagger(brown_l)
>>> unigram_tagger.tag(sent)
[('but', 'CC'), ('enough', 'QLP'), ('.', '.')]
>>> nltk.tag.accuracy(unigram_tagger, brown_l)
0.8659238398432717
>>> bigram_tagger = nltk.BigramTagger(brown_l, cutoff=0)
>>> bigram_tagger.tag(sent)
[('but', 'CC'), ('enough', 'AP'), ('.', '.')]
>>> nltk.tag.accuracy(bigram_tagger, brown_l)
0.81951757071139952
>>> t1 = nltk.UnigramTagger(brown_l, backoff=t0)
>>> t2 = nltk.BigramTagger(brown_l, backoff=t1)
>>> nltk.tag.accuracy(t2, brown_l)
0.90398642621000891
>>> import nltk
>>> from nltk import corpus
>>> brown_l = nltk.corpus.brown.tagged_sents(categories='l')
>>> sent = nltk.corpus.brown.sents(categories='l')[2007]
>>> t0 = nltk.DefaultTagger('NN')
>>> unigram_tagger = nltk.UnigramTagger(brown_l)
>>> unigram_tagger.tag(sent)
[('but', 'CC'), ('enough', 'QLP'), ('.', '.')]
>>> nltk.tag.accuracy(unigram_tagger, brown_l)
0.8659238398432717
>>> bigram_tagger1 = nltk.BigramTagger(brown_l, cutoff=1)
>>> bigram_tagger1.tag(sent)
[('but', 'CC'), ('enough', 'AP'), ('.', '.')]
>>> nltk.tag.accuracy(bigram_tagger1, brown_l)
0.2526019346149137
>>> t1 = nltk.UnigramTagger(brown_l, backoff=t0)
>>> t2 = nltk.BigramTagger(brown_l, backoff=t1)
>>> nltk.tag.accuracy(t2, brown_l)
0.90398642621000891
>>> import nltk
>>> from nltk import corpus
>>> brown_l = nltk.corpus.brown.tagged_sents(categories='l')
>>> sent = nltk.corpus.brown.sents(categories='l')[2007]
>>> t0 = nltk.DefaultTagger('NN')
>>> unigram_tagger = nltk.UnigramTagger(brown_l)
>>> unigram_tagger.tag(sent)
[('but', 'CC'), ('enough', 'QLP'), ('.', '.')]
>>> nltk.tag.accuracy(unigram_tagger, brown_l)
0.8659238398432717
>>> bigram_tagger2 = nltk.BigramTagger(brown_l, cutoff=2)
>>> bigram_tagger2.tag(sent)
[('but', 'CC'), ('enough', None), ('.', None)]
>>> nltk.tag.accuracy(bigram_tagger2, brown_l)
0.18574752050936696
>>> t1 = nltk.UnigramTagger(brown_l, backoff=t0)
>>> t2 = nltk.BigramTagger(brown_l, backoff=t1)
>>> nltk.tag.accuracy(t2, brown_l)
0.90398642621000891
>>> import nltk
>>> from nltk import corpus
>>> brown_l = nltk.corpus.brown.tagged_sents(categories='l')
>>> sent = nltk.corpus.brown.sents(categories='l')[2007]
>>> t0 = nltk.DefaultTagger('NN')
>>> bigram_tagger2 = nltk.BigramTagger(brown_l, cutoff=2)
>>> bigram_tagger2.tag(sent)
[('but', 'CC'), ('enough', None), ('.', None)]
>>> nltk.tag.accuracy(bigram_tagger2, brown_l)
0.18574752050936696
>>> t1 = nltk.BigramTagger(brown_l, backoff=t0)
>>> t2 = nltk.BigramTagger(brown_l, backoff=t1)
>>> nltk.tag.accuracy(t2, brown_l)
0.78142000034983994
6.7 IDLE 1.2.2
>>> import nltk
>>> from nltk import corpus
>>> corpus.mac_morpho.files()
('ag94ab12.txt', 'ag94ag02.txt', 'ag94de06.txt', 'ag94fe1.txt', 'ag94ja11.txt', 'ag94jl12.txt', 'ag94ju07.txt', 'ag94ma03.txt', 'ag94mr1.txt', 'ag94no01.txt', 'ag94ou04.txt', 'ag94se06.txt', 'br94ab02.txt', 'br94ag01.txt', 'br94de01.txt', 'br94fe1.txt', 'br94ja04.txt', 'br94jl01.txt', 'br94ju01.txt', 'br94ma01.txt', 'br94mr1.txt', 'br94no01.txt', 'br94ou01.txt', 'br94se01.txt', 'co94ab02.txt', 'co94ag01.txt', 'co94de01.txt', 'co94fe1.txt', 'co94ja04.txt', 'co94jl01.txt', 'co94ju01.txt', 'co94ma01.txt', 'co94mr1.txt', 'co94no01.txt', 'co94ou01.txt', 'co94se01.txt', 'di94ab02.txt', 'di94ag01.txt', 'di94de01.txt', 'di94fe1.txt', 'di94ja04.txt', 'di94jl01.txt', 'di94ju01.txt', 'di94ma01.txt', 'di94mr1.txt', 'di94no01.txt', 'di94ou02.txt', 'di94se01.txt', 'es94ab02.txt', 'es94ag01.txt', 'es94de01.txt', 'es94fe1.txt', 'es94ja04.txt', 'es94jl01.txt', 'es94ju01.txt', 'es94ma01.txt', 'es94mr1.txt', 'es94no01.txt', 'es94ou01.txt', 'es94se01.txt', 'fc96ma10.txt', 'fc96ma23.txt', 'if94ab13.txt', 'if94ag03.txt', 'if94de07.txt', 'if94fe16.txt', 'if94ja05.txt', 'if94jl06.txt', 'if94ju01.txt', 'if94ma04.txt', 'if94mr16.txt', 'if94no02.txt', 'if94ou05.txt', 'if94se07.txt', 'il94ab02.txt', 'il94ag01.txt', 'il94de01.txt', 'il94fe1.txt', 'il94ja04.txt', 'il94jl01.txt', 'il94ju01.txt', 'il94ma01.txt', 'il94mr1.txt', 'il94no01.txt', 'il94ou01.txt', 'ma94ab10.txt', 'ma94ag07.txt', 'ma94de04.txt', 'ma94fe13.txt', 'ma94ja16.txt', 'ma94jl03.txt', 'ma94ju05.txt', 'ma94ma01.txt', 'ma94mr13.txt', 'ma94no06.txt', 'ma94ou02.txt', 'ma94se04.txt', 'mu94ab02.txt', 'mu94ag01.txt', 'mu94de01.txt', 'mu94fe1.txt', 'mu94ja04.txt', 'mu94jl01.txt', 'mu94ju01.txt', 'mu94ma01.txt', 'mu94mr1.txt', 'mu94no01.txt', 'mu94ou01.txt', 'mu94se01.txt')
>>> fd = nltk.FreqDist(nltk.corpus.mac_morpho.words('mu94ab02.txt'))
>>> most_freq_words = fd.sorted()[:100]
>>> most_freq_words
['de', 'o', ',', 'a', 'em', 'que', 'os', 'e', '"', 'por', 'um', 'as', 'para', 'O', 'A', 'foi', 'com', 'n\xe3o', 'uma', 'se', 'EUA', 'Colosio', 'sua', 'ontem', '\xe9', 'Os', '(', ')', 'disse', 'anos', 'milh\xf5es', 'Em', '-', 'pessoas', 'Jap\xe3o', 'mais', 'seu', 'foram', 'As', 'sobre', 'mas', 'caso', 'eles', 'presidente', 'Um', 'seguran\xe7a', 'PRI', 'onde', 'Nakamura', 'at\xe9', 'est\xe1', 'ele', 'desde', 'ano', 'US$', 'ter', 'pol\xedcia', 'japoneses', 'jornal', 'Ele', 'elei\xe7\xf5es', 'segundo', 'quando', 'dois', 'candidato', 's\xe3o', 'decis\xe3o', 'vez', 'pa\xeds', 'ser', 'governo', 'h\xe1', 'norte-americano', 'ONU', 'tr\xeas', 'apenas', 'extremistas', 'do', 'suas', 'depois', 'semana', 'maior', 'japon\xeas', 'como', 'pris\xe3o', 'durante', 'partido', 'Asahi', 'tem', 'vai', 'in\xedcio', 'Mas', '%', 'M\xe9xico', 'China', 'mil', 'seus', 'Eles', 'outro', 'era']
>>> brown_a = nltk.corpus.mac_morpho.tagged_sents('mu94ab02.txt')
>>> unigram_tagger = nltk.UnigramTagger(brown_a)
>>> sent = nltk.corpus.mac_morpho.sents('mu94ab02.txt')[3]
>>> unigram_tagger.tag(sent)
[('Autoridades', 'N'), ('francesas', None), ('disseram', 'V'), ('ontem', 'ADV'), ('que', 'PRO-KS-REL'), ('n\xe3o', 'ADV'), ('h\xe1', 'V'), ('vest\xedgios', 'N'), ('de', 'PREP'), ('radia\xe7\xe3o', None), ('em', 'PREP|+'), ('a', 'ART'), ('\xe1rea', None), ('pr\xf3xima', None), ('a', 'ART'), ('o', 'ART'), ('reator', 'N'), ('nuclear', None), ('Rapsodie', None), (',', ','), ('em', 'PREP|+'), ('Cadarache', None), (',', ','), ('70', None), ('km', 'N'), ('a', 'ART'), ('o', 'ART'), ('norte', 'N'), ('de', 'PREP'), ('Marselha', None), ('(', '('), ('sul', 'N'), (')', ')')]
>>> nltk.tag.accuracy(unigram_tagger, brown_a)
0.65268650947042905
>>> bigram_tagger = nltk.BigramTagger(brown_a, cutoff=0)
>>> bigram_tagger.tag(sent)
[('Autoridades', 'N'), ('francesas', 'ADJ'), ('disseram', 'V'), ('ontem', 'ADV'), ('que', 'KS'), ('n\xe3o', 'ADV'), ('h\xe1', 'V'), ('vest\xedgios', 'N'), ('de', 'PREP'), ('radia\xe7\xe3o', 'N'), ('em', 'PREP|+'), ('a', 'ART'), ('\xe1rea', 'N'), ('pr\xf3xima', 'ADJ'), ('a', 'PREP'), ('o', 'ART'), ('reator', 'N'), ('nuclear', 'ADJ'), ('Rapsodie', 'NPROP'), (',', ','), ('em', 'PREP|+'), ('Cadarache', None), (',', None), ('70', None), ('km', None), ('a', None), ('o', None), ('norte', None), ('de', None), ('Marselha', None), ('(', None), ('sul', None), (')', None)]
>>> nltk.tag.accuracy(bigram_tagger, brown_a)
0.62330885195206798
>>> t0 = nltk.DefaultTagger('NN')
>>> t1 = nltk.UnigramTagger(brown_a, backoff=t0)
>>> t2 = nltk.BigramTagger(brown_a, backoff=t1)
>>> nltk.tag.accuracy(t2, brown_a)
0.66505604947815999
>>>
Висновок. На цій лабораторній роботі я ознайомилася з морфологічними аналізаторами і навчилася застосовувати їх на практиці.