Zestaw narzędzi języka naturalnego - krótki przewodnik
Co to jest przetwarzanie języka naturalnego (NLP)?
Metodą komunikacji, za pomocą której ludzie mogą mówić, czytać i pisać, jest język. Innymi słowy, my, ludzie, możemy myśleć, planować, podejmować decyzje w naszym naturalnym języku. Tutaj głównym pytaniem jest, czy w dobie sztucznej inteligencji, uczenia maszynowego i głębokiego uczenia się ludzie mogą komunikować się w języku naturalnym z komputerami / maszynami? Tworzenie aplikacji NLP jest dla nas ogromnym wyzwaniem, ponieważ komputery wymagają ustrukturyzowanych danych, ale z drugiej strony ludzka mowa jest nieustrukturyzowana i często ma niejednoznaczny charakter.
Język naturalny to ta dziedzina informatyki, a dokładniej sztucznej inteligencji, która umożliwia komputerom / maszynom rozumienie, przetwarzanie i manipulowanie ludzkim językiem. Krótko mówiąc, NLP to sposób maszyn do analizowania, rozumienia i czerpania znaczenia z ludzkich języków naturalnych, takich jak hindi, angielski, francuski, holenderski itp.
Jak to działa?
Zanim zagłębimy się w pracę nad NLP, musimy zrozumieć, jak ludzie używają języka. Każdego dnia my, ludzie, używamy setek lub tysięcy słów, a inni ludzie je interpretują i odpowiednio odpowiadają. To prosta komunikacja dla ludzi, prawda? Ale wiemy, że słowa sięgają znacznie, znacznie głębiej, i zawsze czerpiemy kontekst z tego, co mówimy i jak mówimy. Dlatego możemy powiedzieć, że zamiast skupiać się na modulacji głosu, NLP opiera się na wzorcu kontekstowym.
Zrozummy to na przykładzie -
Man is to woman as king is to what?
We can interpret it easily and answer as follows:
Man relates to king, so woman can relate to queen.
Hence the answer is Queen.
Skąd ludzie wiedzą, co oznacza słowo? Odpowiedź na to pytanie jest taka, że uczymy się poprzez nasze doświadczenie. Ale w jaki sposób maszyny / komputery uczą się tego samego?
Pozwól nam to zrozumieć, wykonując proste kroki -
Po pierwsze, musimy dostarczyć maszynom wystarczającą ilość danych, aby maszyny mogły uczyć się na podstawie doświadczenia.
Następnie maszyna utworzy wektory słów, korzystając z algorytmów głębokiego uczenia, na podstawie danych, które wprowadziliśmy wcześniej, a także z otaczających je danych.
Następnie, wykonując proste operacje algebraiczne na tych wektorach słów, maszyna byłaby w stanie udzielić odpowiedzi jako istoty ludzkie.
Składniki NLP
Poniższy diagram przedstawia komponenty przetwarzania języka naturalnego (NLP) -
Przetwarzanie morfologiczne
Przetwarzanie morfologiczne jest pierwszym składnikiem NLP. Obejmuje dzielenie fragmentów danych wejściowych języka na zestawy żetonów odpowiadające akapitom, zdaniom i słowom. Na przykład słowo takie jak“everyday” można podzielić na dwa żetony podsłów jako “every-day”.
Analiza składni
Analiza składni, drugi składnik, jest jednym z najważniejszych elementów NLP. Cele tego komponentu są następujące -
Aby sprawdzić, czy zdanie jest poprawnie sformułowane, czy nie.
Aby rozbić to na strukturę, która pokazuje związki składniowe między różnymi słowami.
Np. Zdania typu “The school goes to the student” zostanie odrzucony przez analizator składni.
Analiza semantyczna
Analiza semantyczna to trzeci składnik NLP, który służy do sprawdzania sensowności tekstu. Obejmuje rysowanie dokładnego znaczenia lub możemy powiedzieć znaczenie słownikowe z tekstu. Np. Zdania typu „To gorące lody”. zostałby odrzucony przez analizator semantyczny.
Analiza pragmatyczna
Analiza pragmatyczna to czwarty składnik NLP. Obejmuje dopasowanie rzeczywistych obiektów lub zdarzeń, które istnieją w każdym kontekście, do odniesień do obiektów uzyskanych przez poprzedni komponent, tj. Analizę semantyczną. Np. Zdania typu“Put the fruits in the basket on the table” może mieć dwie interpretacje semantyczne, stąd analizator pragmatyczny wybierze jedną z tych dwóch możliwości.
Przykłady zastosowań NLP
NLP, nowa technologia, wywodzi się z różnych form sztucznej inteligencji, które widzieliśmy w dzisiejszych czasach. W dzisiejszych i przyszłych, coraz bardziej poznawczych aplikacjach, wykorzystanie NLP w tworzeniu płynnego i interaktywnego interfejsu między ludźmi a maszynami będzie nadal głównym priorytetem. Poniżej przedstawiono niektóre z bardzo przydatnych zastosowań NLP.
Tłumaczenie maszynowe
Tłumaczenie maszynowe (MT) jest jednym z najważniejszych zastosowań przetwarzania języka naturalnego. MT to w zasadzie proces tłumaczenia jednego języka źródłowego lub tekstu na inny język. System tłumaczenia maszynowego może być dwujęzyczny lub wielojęzyczny.
Zwalczanie spamu
Ze względu na ogromny wzrost niechcianych wiadomości e-mail filtry spamu stały się ważne, ponieważ stanowią pierwszą linię obrony przed tym problemem. Biorąc pod uwagę kwestie fałszywie dodatnie i fałszywie ujemne jako główne problemy, funkcjonalność NLP może zostać wykorzystana do opracowania systemu filtrowania spamu.
Modelowanie N-gramowe, zapamiętywanie słów i klasyfikacja bayesowska to tylko niektóre z istniejących modeli NLP, które można wykorzystać do filtrowania spamu.
Wyszukiwanie informacji i wyszukiwanie w Internecie
Większość wyszukiwarek, takich jak Google, Yahoo, Bing, WolframAlpha itp., Opiera swoją technologię tłumaczenia maszynowego (MT) na modelach głębokiego uczenia NLP. Takie modele głębokiego uczenia pozwalają algorytmom odczytywać tekst na stronie internetowej, interpretować jego znaczenie i tłumaczyć go na inny język.
Automatyczne podsumowanie tekstu
Automatyczne podsumowanie tekstu to technika, która tworzy krótkie, dokładne podsumowanie dłuższych dokumentów tekstowych. W związku z tym pomaga nam uzyskać istotne informacje w krótszym czasie. W erze cyfrowej pilnie potrzebujemy automatycznego podsumowania tekstu, ponieważ mamy do czynienia z zalewem informacji w Internecie, który nie ustanie. NLP i jego funkcje odgrywają ważną rolę w tworzeniu automatycznego podsumowania tekstu.
Korekta gramatyczna
Poprawianie pisowni i poprawianie gramatyki to bardzo przydatna funkcja edytora tekstu, takiego jak Microsoft Word. W tym celu szeroko stosuje się przetwarzanie języka naturalnego (NLP).
Odpowiadanie na pytania
Odpowiadanie na pytania, kolejne główne zastosowanie przetwarzania języka naturalnego (NLP), koncentruje się na budowaniu systemów, które automatycznie odpowiadają na pytanie zadane przez użytkownika w jego języku naturalnym.
Analiza nastrojów
Analiza nastrojów jest jednym z innych ważnych zastosowań przetwarzania języka naturalnego (NLP). Jak sama nazwa wskazuje, analiza nastrojów służy do -
Zidentyfikuj nastroje w kilku postach i
Zidentyfikuj uczucie, w którym emocje nie są wyrażane bezpośrednio.
Firmy zajmujące się handlem elektronicznym online, takie jak Amazon, ebay itp., Używają analizy nastrojów do identyfikowania opinii i uczuć swoich klientów w Internecie. Pomoże im zrozumieć, co myślą klienci o ich produktach i usługach.
Silniki mowy
Silniki mowy, takie jak Siri, Google Voice, Alexa, są oparte na NLP, dzięki czemu możemy komunikować się z nimi w naszym naturalnym języku.
Wdrażanie NLP
Aby zbudować powyższe aplikacje, musimy mieć określone umiejętności z doskonałym zrozumieniem języka i narzędziami do wydajnego przetwarzania języka. Aby to osiągnąć, mamy dostępne różne narzędzia open source. Niektóre z nich mają charakter open source, podczas gdy inne są opracowywane przez organizacje w celu tworzenia własnych aplikacji NLP. Poniżej znajduje się lista niektórych narzędzi NLP -
Zestaw narzędzi języka naturalnego (NLTK)
Mallet
GATE
Otwórz NLP
UIMA
Genism
Zestaw narzędzi Stanford
Większość z tych narzędzi jest napisana w języku Java.
Zestaw narzędzi języka naturalnego (NLTK)
Wśród wyżej wspomnianego narzędzia NLP, NLTK osiąga bardzo wysokie wyniki, jeśli chodzi o łatwość użycia i wyjaśnienie koncepcji. Krzywa uczenia się Pythona jest bardzo szybka, a NLTK jest napisane w Pythonie, więc NLTK ma również bardzo dobry zestaw do nauki. NLTK włączyło większość zadań, takich jak tokenizacja, wyprowadzanie, lematyzacja, interpunkcja, liczba znaków i liczba słów. Jest bardzo elegancki i łatwy w obsłudze.
Aby zainstalować NLTK, musimy mieć zainstalowany Python na naszych komputerach. Możesz przejść do łącza www.python.org/downloads i wybrać najnowszą wersję dla swojego systemu operacyjnego, tj. Windows, Mac i Linux / Unix. Aby zapoznać się z podstawowym samouczkiem dotyczącym języka Python, możesz skorzystać z łącza www.tutorialspoint.com/python3/index.htm .
Teraz, po zainstalowaniu Pythona w systemie komputerowym, pozwól nam zrozumieć, jak możemy zainstalować NLTK.
Instalowanie NLTK
Możemy zainstalować NLTK w różnych systemach operacyjnych w następujący sposób -
W systemie Windows
Aby zainstalować NLTK w systemie operacyjnym Windows, wykonaj poniższe czynności -
Najpierw otwórz wiersz polecenia systemu Windows i przejdź do lokalizacji pliku pip teczka.
Następnie wprowadź następujące polecenie, aby zainstalować NLTK -
pip3 install nltk
Teraz otwórz PythonShell z menu Start systemu Windows i wpisz następujące polecenie, aby zweryfikować instalację NLTK -
Import nltk
Jeśli nie pojawi się żaden błąd, pomyślnie zainstalowałeś NLTK w systemie Windows z Python3.
W systemie Mac / Linux
Aby zainstalować NLTK w systemie Mac / Linux OS, wpisz następujące polecenie -
sudo pip install -U nltk
Jeśli nie masz zainstalowanego pip na swoim komputerze, postępuj zgodnie z instrukcjami podanymi poniżej, aby najpierw zainstalować pip -
Najpierw zaktualizuj indeks pakietu, wykonując następujące polecenie -
sudo apt update
Teraz wpisz następujące polecenie, aby zainstalować pip dla Pythona 3 -
sudo apt install python3-pip
Przez Anacondę
Aby zainstalować NLTK przez Anacondę, wykonaj poniższe czynności -
Najpierw, aby zainstalować Anacondę , przejdź do linku www.anaconda.com/distribution/#download-section, a następnie wybierz wersję Pythona, którą chcesz zainstalować.
Po zainstalowaniu Anacondy w systemie komputerowym przejdź do wiersza poleceń i wpisz następujące polecenie -
conda install -c anaconda nltk
Musisz przejrzeć dane wyjściowe i wpisać „tak”. NLTK zostanie pobrane i zainstalowane w Twoim pakiecie Anaconda.
Pobieranie zestawu danych i pakietów NLTK
Teraz mamy zainstalowany NLTK na naszych komputerach, ale aby z niego skorzystać, musimy pobrać dostępne w nim zbiory danych (korpus). Niektóre z ważnych dostępnych zbiorów danych tostpwords, guntenberg, framenet_v15 i tak dalej.
Za pomocą następujących poleceń możemy pobrać wszystkie zestawy danych NLTK -
import nltk
nltk.download()
Otrzymasz następujące okno pobierania NLTK.
Teraz kliknij przycisk pobierania, aby pobrać zestawy danych.
Jak uruchomić skrypt NLTK?
Poniżej znajduje się przykład, w którym implementujemy algorytm Portera Stemmera przy użyciu PorterStemmerklasa nltk. na tym przykładzie byłbyś w stanie zrozumieć, jak uruchomić skrypt NLTK.
Najpierw musimy zaimportować zestaw narzędzi języka naturalnego (nltk).
import nltk
Teraz zaimportuj plik PorterStemmer do implementacji algorytmu Portera Stemmera.
from nltk.stem import PorterStemmer
Następnie utwórz instancję klasy Porter Stemmer w następujący sposób -
word_stemmer = PorterStemmer()
Teraz wprowadź słowo, które chcesz wywołać. -
word_stemmer.stem('writing')
Wynik
'write'
word_stemmer.stem('eating')
Wynik
'eat'
Co to jest tokenizacja?
Można to zdefiniować jako proces dzielenia fragmentu tekstu na mniejsze części, takie jak zdania i słowa. Te mniejsze części nazywane są żetonami. Na przykład słowo jest tokenem w zdaniu, a zdanie jest tokenem w akapicie.
Ponieważ wiemy, że NLP jest wykorzystywane do budowania aplikacji, takich jak analiza sentymentów, systemy QA, tłumaczenia językowe, inteligentne chatboty, systemy głosowe itp., Dlatego aby je zbudować, konieczne jest zrozumienie wzorca w tekście. Wspomniane wyżej tokeny są bardzo przydatne w znajdowaniu i zrozumieniu tych wzorców. Możemy rozważyć tokenizację jako podstawowy krok dla innych przepisów, takich jak wyrastanie i lematyzacja.
Pakiet NLTK
nltk.tokenize to pakiet dostarczany przez moduł NLTK do realizacji procesu tokenizacji.
Tokenizacja zdań na słowa
Dzielenie zdania na słowa lub tworzenie listy słów z ciągu znaków jest istotną częścią każdej czynności przetwarzania tekstu. Zrozummy to za pomocą różnych funkcji / modułów dostarczonych przeznltk.tokenize pakiet.
moduł word_tokenize
word_tokenizeModuł służy do podstawowego tokenizacji słów. Poniższy przykład użyje tego modułu do podzielenia zdania na słowa.
Przykład
import nltk
from nltk.tokenize import word_tokenize
word_tokenize('Tutorialspoint.com provides high quality technical tutorials for free.')
Wynik
['Tutorialspoint.com', 'provides', 'high', 'quality', 'technical', 'tutorials', 'for', 'free', '.']
TreebankWordTokenizer Class
word_tokenize użyty powyżej jest w zasadzie funkcją opakowującą, która wywołuje funkcję tokenize () jako instancję TreebankWordTokenizerklasa. Daje taki sam wynik, jaki otrzymujemy podczas używania modułu word_tokenize () do dzielenia zdań na słowa. Zobaczmy ten sam przykład zaimplementowany powyżej -
Przykład
Najpierw musimy zaimportować zestaw narzędzi języka naturalnego (nltk).
import nltk
Teraz zaimportuj plik TreebankWordTokenizer klasa do implementacji algorytmu tokenizera słowa -
from nltk.tokenize import TreebankWordTokenizer
Następnie utwórz instancję klasy TreebankWordTokenizer w następujący sposób -
Tokenizer_wrd = TreebankWordTokenizer()
Teraz wprowadź zdanie, które chcesz zamienić na tokeny -
Tokenizer_wrd.tokenize(
'Tutorialspoint.com provides high quality technical tutorials for free.'
)
Wynik
[
'Tutorialspoint.com', 'provides', 'high', 'quality',
'technical', 'tutorials', 'for', 'free', '.'
]
Kompletny przykład wdrożenia
Zobaczmy poniżej pełny przykład wdrożenia
import nltk
from nltk.tokenize import TreebankWordTokenizer
tokenizer_wrd = TreebankWordTokenizer()
tokenizer_wrd.tokenize('Tutorialspoint.com provides high quality technical
tutorials for free.')
Wynik
[
'Tutorialspoint.com', 'provides', 'high', 'quality',
'technical', 'tutorials','for', 'free', '.'
]
Najważniejszą konwencją tokenizera jest oddzielanie skurczów. Na przykład, jeśli użyjemy do tego celu modułu word_tokenize (), to da wynik w następujący sposób -
Przykład
import nltk
from nltk.tokenize import word_tokenize
word_tokenize('won’t')
Wynik
['wo', "n't"]]
Taka konwencja wg TreebankWordTokenizerjest niedopuszczalne. Dlatego mamy dwa alternatywne tokenizery słów, a mianowiciePunktWordTokenizer i WordPunctTokenizer.
Klasa WordPunktTokenizer
Alternatywny tokenizer słów, który dzieli wszystkie znaki interpunkcyjne na oddzielne tokeny. Zrozummy to na prostym przykładzie -
Przykład
from nltk.tokenize import WordPunctTokenizer
tokenizer = WordPunctTokenizer()
tokenizer.tokenize(" I can't allow you to go home early")
Wynik
['I', 'can', "'", 't', 'allow', 'you', 'to', 'go', 'home', 'early']
Tokenizacja tekstu na zdania
W tej sekcji zamierzamy podzielić tekst / akapit na zdania. NLTK zapewniasent_tokenize moduł do tego celu.
Dlaczego jest to potrzebne?
Oczywistym pytaniem, które przyszło nam do głowy, jest to, że skoro mamy tokenizator słów, to po co nam tokenizator zdań lub dlaczego musimy tokenizować tekst na zdania. Załóżmy, że musimy policzyć przeciętne słowa w zdaniach, jak możemy to zrobić? Do wykonania tego zadania potrzebujemy zarówno tokenizacji zdań, jak i tokenizacji słów.
Zrozummy różnicę między tokenizatorem zdań i słów, posługując się prostym przykładem -
Przykład
import nltk
from nltk.tokenize import sent_tokenize
text = "Let us understand the difference between sentence & word tokenizer.
It is going to be a simple example."
sent_tokenize(text)
Wynik
[
"Let us understand the difference between sentence & word tokenizer.",
'It is going to be a simple example.'
]
Tokenizacja zdań przy użyciu wyrażeń regularnych
Jeśli uważasz, że dane wyjściowe tokenizera słów są niedopuszczalne i chcesz mieć pełną kontrolę nad sposobem tokenizacji tekstu, mamy wyrażenie regularne, którego można użyć podczas tokenizacji zdań. NLTK zapewniająRegexpTokenizer klasa, aby to osiągnąć.
Zrozummy tę koncepcję na dwóch poniższych przykładach.
W pierwszym przykładzie użyjemy wyrażenia regularnego do dopasowania tokenów alfanumerycznych i pojedynczych cudzysłowów, aby nie dzielić kontrakcji, takich jak “won’t”.
Przykład 1
import nltk
from nltk.tokenize import RegexpTokenizer
tokenizer = RegexpTokenizer("[\w']+")
tokenizer.tokenize("won't is a contraction.")
tokenizer.tokenize("can't is a contraction.")
Wynik
["won't", 'is', 'a', 'contraction']
["can't", 'is', 'a', 'contraction']
W pierwszym przykładzie użyjemy wyrażenia regularnego do tokenizacji białych znaków.
Przykład 2
import nltk
from nltk.tokenize import RegexpTokenizer
tokenizer = RegexpTokenizer('/s+' , gaps = True)
tokenizer.tokenize("won't is a contraction.")
Wynik
["won't", 'is', 'a', 'contraction']
Z powyższego wyniku widać, że znaki interpunkcyjne pozostają w tokenach. Parametr gaps = True oznacza, że wzorzec będzie identyfikował luki do tokenizacji. Z drugiej strony, jeśli użyjemy parametru gaps = False, to wzorzec zostanie użyty do identyfikacji tokenów, co widać w poniższym przykładzie -
import nltk
from nltk.tokenize import RegexpTokenizer
tokenizer = RegexpTokenizer('/s+' , gaps = False)
tokenizer.tokenize("won't is a contraction.")
Wynik
[ ]
To da nam puste wyjście.
Po co trenować własny tokenizer zdań?
Jest to bardzo ważne pytanie, a jeśli mamy domyślny tokenizer zdań NLTK, to dlaczego musimy szkolić tokenizator zdań? Odpowiedź na to pytanie leży w jakości domyślnego tokenizera zdań NLTK. Domyślny tokenizer NLTK jest w zasadzie tokenizatorem ogólnego przeznaczenia. Chociaż działa bardzo dobrze, ale może nie być dobrym wyborem w przypadku niestandardowego tekstu, który być może jest naszym tekstem, lub dla tekstu, który ma unikalne formatowanie. Aby tokenizować taki tekst i uzyskiwać najlepsze wyniki, powinniśmy wyszkolić własny tokenizer zdań.
Przykład implementacji
W tym przykładzie będziemy używać korpusu tekstu internetowego. Plik tekstowy, którego będziemy używać z tego korpusu, ma tekst sformatowany jako okna dialogowe pokazane poniżej -
Guy: How old are you?
Hipster girl: You know, I never answer that question. Because to me, it's about
how mature you are, you know? I mean, a fourteen year old could be more mature
than a twenty-five year old, right? I'm sorry, I just never answer that question.
Guy: But, uh, you're older than eighteen, right?
Hipster girl: Oh, yeah.
Zapisaliśmy ten plik tekstowy pod nazwą training_tokenizer. NLTK udostępnia klasę o nazwiePunktSentenceTokenizerza pomocą którego możemy trenować na surowym tekście, aby stworzyć niestandardowy tokenizer zdań. Możemy uzyskać surowy tekst, czytając w pliku lub z korpusu NLTK przy użyciu rozszerzeniaraw() metoda.
Zobaczmy poniższy przykład, aby uzyskać lepszy wgląd w to -
Najpierw importuj PunktSentenceTokenizer klasa od nltk.tokenize pakiet -
from nltk.tokenize import PunktSentenceTokenizer
Teraz importuj webtext korpus z nltk.corpus pakiet
from nltk.corpus import webtext
Następnie za pomocą raw() pobierz surowy tekst z training_tokenizer.txt plik w następujący sposób -
text = webtext.raw('C://Users/Leekha/training_tokenizer.txt')
Teraz utwórz wystąpienie PunktSentenceTokenizer i wydrukuj zdania tokenizacji z pliku tekstowego w następujący sposób -
sent_tokenizer = PunktSentenceTokenizer(text)
sents_1 = sent_tokenizer.tokenize(text)
print(sents_1[0])
Wynik
White guy: So, do you have any plans for this evening?
print(sents_1[1])
Output:
Asian girl: Yeah, being angry!
print(sents_1[670])
Output:
Guy: A hundred bucks?
print(sents_1[675])
Output:
Girl: But you already have a Big Mac...
Kompletny przykład wdrożenia
from nltk.tokenize import PunktSentenceTokenizer
from nltk.corpus import webtext
text = webtext.raw('C://Users/Leekha/training_tokenizer.txt')
sent_tokenizer = PunktSentenceTokenizer(text)
sents_1 = sent_tokenizer.tokenize(text)
print(sents_1[0])
Wynik
White guy: So, do you have any plans for this evening?
Aby zrozumieć różnicę między domyślnym tokenizatorem zdań NLTK a naszym własnym wyuczonym tokenizatorem zdań, tokenizujemy ten sam plik za pomocą domyślnego tokenizera zdań, czyli sent_tokenize ().
from nltk.tokenize import sent_tokenize
from nltk.corpus import webtext
text = webtext.raw('C://Users/Leekha/training_tokenizer.txt')
sents_2 = sent_tokenize(text)
print(sents_2[0])
Output:
White guy: So, do you have any plans for this evening?
print(sents_2[675])
Output:
Hobo: Y'know what I'd do if I was rich?
Przy pomocy różnicy w danych wyjściowych możemy zrozumieć koncepcję, dlaczego warto trenować nasz własny tokenizer zdań.
Co to są odrzucane słowa?
Niektóre popularne słowa, które są obecne w tekście, ale nie mają znaczenia w zdaniu. Takie słowa nie są wcale ważne dla celów wyszukiwania informacji lub przetwarzania języka naturalnego. Najczęstsze pomijane słowa to „the” i „a”.
Korpus haseł NLTK
W rzeczywistości zestaw narzędzi języka naturalnego zawiera korpus pomijanych słów zawierający listy słów dla wielu języków. Zrozummy jego użycie za pomocą następującego przykładu -
Po pierwsze, import odrzucanych słów Copus z nltk.corpus pakietu -
from nltk.corpus import stopwords
Teraz będziemy używać pomijanych słów z języków angielskiego
english_stops = set(stopwords.words('english'))
words = ['I', 'am', 'a', 'writer']
[word for word in words if word not in english_stops]
Wynik
['I', 'writer']
Kompletny przykład wdrożenia
from nltk.corpus import stopwords
english_stops = set(stopwords.words('english'))
words = ['I', 'am', 'a', 'writer']
[word for word in words if word not in english_stops]
Wynik
['I', 'writer']
Znajdowanie pełnej listy obsługiwanych języków
Za pomocą poniższego skryptu Python możemy również znaleźć pełną listę języków obsługiwanych przez korpus stopwords NLTK -
from nltk.corpus import stopwords
stopwords.fileids()
Wynik
[
'arabic', 'azerbaijani', 'danish', 'dutch', 'english', 'finnish', 'french',
'german', 'greek', 'hungarian', 'indonesian', 'italian', 'kazakh', 'nepali',
'norwegian', 'portuguese', 'romanian', 'russian', 'slovene', 'spanish',
'swedish', 'tajik', 'turkish'
]
Co to jest Wordnet?
Wordnet to duża leksykalna baza danych języka angielskiego, która została stworzona przez Princeton. Jest częścią korpusu NLTK. Rzeczowniki, czasowniki, przymiotniki i przysłówki są pogrupowane w zbiór synonimów, tj. Synonimów poznawczych. Tutaj każdy zestaw synsetów wyraża odrębne znaczenie. Oto kilka przypadków użycia Wordnetu -
- Można go użyć do wyszukania definicji słowa
- Możemy znaleźć synonimy i antonimy słowa
- Relacje między wyrazami i podobieństwa można badać za pomocą Wordnet
- Ujednoznacznienie sensu słów dla tych słów, które mają wiele zastosowań i definicji
Jak zaimportować Wordnet?
Wordnet można zaimportować za pomocą następującego polecenia -
from nltk.corpus import wordnet
Aby uzyskać bardziej kompaktowe polecenie, użyj następującego -
from nltk.corpus import wordnet as wn
Instancje synchronizacji
Synset to grupy słów synonimów, które wyrażają to samo pojęcie. Kiedy używasz Wordnetu do wyszukiwania słów, otrzymasz listę instancji Synset.
wordnet.synsets (słowo)
Aby uzyskać listę synchronizacji, możemy wyszukać dowolne słowo w Wordnet za pomocą wordnet.synsets(word). Na przykład w następnym przepisie w Pythonie będziemy szukać Synset dla „psa” wraz z niektórymi właściwościami i metodami Synsetu -
Przykład
Najpierw zaimportuj wordnet w następujący sposób -
from nltk.corpus import wordnet as wn
Teraz podaj słowo, dla którego chcesz wyszukać Synset -
syn = wn.synsets('dog')[0]
Tutaj używamy metody name (), aby uzyskać unikalną nazwę dla synsetu, której można użyć do bezpośredniego pobrania Synset -
syn.name()
Output:
'dog.n.01'
Następnie używamy metody definition (), która poda nam definicję słowa -
syn.definition()
Output:
'a member of the genus Canis (probably descended from the common wolf) that has
been domesticated by man since prehistoric times; occurs in many breeds'
Inną metodą są przykłady (), które dadzą nam przykłady związane ze słowem -
syn.examples()
Output:
['the dog barked all night']
Kompletny przykład wdrożenia
from nltk.corpus import wordnet as wn
syn = wn.synsets('dog')[0]
syn.name()
syn.definition()
syn.examples()
Pierwsze Hypernyms
Zbiór synchronizacji jest zorganizowany w strukturę podobną do drzewa dziedziczenia, w której pliki Hypernyms reprezentuje bardziej abstrakcyjne terminy while Hyponymsreprezentuje bardziej szczegółowe terminy. Jedną z ważnych rzeczy jest to, że to drzewo można prześledzić aż do hipernego korzenia. Zrozummy tę koncepcję za pomocą następującego przykładu -
from nltk.corpus import wordnet as wn
syn = wn.synsets('dog')[0]
syn.hypernyms()
Wynik
[Synset('canine.n.02'), Synset('domestic_animal.n.01')]
Tutaj widzimy, że psy i zwierzęta domowe są hiperonimami słowa „pies”.
Teraz możemy znaleźć następujące hiponimy słowa `` pies '' -
syn.hypernyms()[0].hyponyms()
Wynik
[
Synset('bitch.n.04'),
Synset('dog.n.01'),
Synset('fox.n.01'),
Synset('hyena.n.01'),
Synset('jackal.n.01'),
Synset('wild_dog.n.01'),
Synset('wolf.n.01')
]
Z powyższego wynika, że „pies” jest tylko jednym z wielu hiponimów „zwierzę domowe”.
Aby znaleźć źródło tych wszystkich, możemy użyć następującego polecenia -
syn.root_hypernyms()
Wynik
[Synset('entity.n.01')]
Z powyższego wyniku widać, że ma tylko jeden root.
Kompletny przykład wdrożenia
from nltk.corpus import wordnet as wn
syn = wn.synsets('dog')[0]
syn.hypernyms()
syn.hypernyms()[0].hyponyms()
syn.root_hypernyms()
Wynik
[Synset('entity.n.01')]
Lematy w Wordnecie
W językoznawstwie kanoniczna forma lub morfologiczna forma słowa nazywana jest lematem. Aby znaleźć synonim, a także antonim słowa, możemy również wyszukać lematy w WordNet. Zobaczmy, jak to zrobić.
Znajdowanie synonimów
Korzystając z metody lemma (), możemy znaleźć liczbę synonimów Synsetu. Zastosujmy tę metodę do synchronizacji `` psa '' -
Przykład
from nltk.corpus import wordnet as wn
syn = wn.synsets('dog')[0]
lemmas = syn.lemmas()
len(lemmas)
Wynik
3
Powyższy wynik pokazuje, że „pies” ma trzy lematy.
Uzyskanie nazwy pierwszego lematu w następujący sposób -
lemmas[0].name()
Output:
'dog'
Uzyskanie nazwy drugiego lematu w następujący sposób -
lemmas[1].name()
Output:
'domestic_dog'
Otrzymanie nazwy trzeciego lematu w następujący sposób -
lemmas[2].name()
Output:
'Canis_familiaris'
W rzeczywistości Synset reprezentuje grupę lematów, które mają podobne znaczenie, podczas gdy lemat reprezentuje odrębną formę słowa.
Znajdowanie antonimów
W WordNet niektóre lematy mają również antonimy. Na przykład słowo „dobry” ma łącznie 27 synetów, w tym 5 lematów z antonimami. Znajdźmy antonimy (gdy słowo „dobry” zostało użyte jako rzeczownik, a słowo „dobre” jako przymiotnik).
Przykład 1
from nltk.corpus import wordnet as wn
syn1 = wn.synset('good.n.02')
antonym1 = syn1.lemmas()[0].antonyms()[0]
antonym1.name()
Wynik
'evil'
antonym1.synset().definition()
Wynik
'the quality of being morally wrong in principle or practice'
Powyższy przykład pokazuje, że słowo „dobre” użyte jako rzeczownik ma pierwszy antonim „zło”.
Przykład 2
from nltk.corpus import wordnet as wn
syn2 = wn.synset('good.a.01')
antonym2 = syn2.lemmas()[0].antonyms()[0]
antonym2.name()
Wynik
'bad'
antonym2.synset().definition()
Wynik
'having undesirable or negative qualities’
Powyższy przykład pokazuje, że słowo „dobry” użyte jako przymiotnik ma pierwszy antonim „zły”.
Co to jest Stemming?
Stemming to technika używana do wyodrębnienia podstawowej formy słów poprzez usunięcie z nich afiksów. To tak, jak ścinanie gałęzi drzewa na łodygi. Na przykład rdzeń słóweating, eats, eaten jest eat.
Wyszukiwarki używają tempa do indeksowania słów. Dlatego zamiast przechowywać wszystkie formy wyrazu, wyszukiwarka może przechowywać tylko jego rdzenie. W ten sposób procesowanie zmniejsza rozmiar indeksu i zwiększa dokładność wyszukiwania.
Różne algorytmy Stemming
W NLTK stemmerI, które mają stem()method, interface zawiera wszystkie stemmery, które będziemy omawiać w następnej kolejności. Rozumiemy to na poniższym schemacie
Algorytm rdzenia Portera
Jest to jeden z najpopularniejszych algorytmów rymowania, który zasadniczo służy do usuwania i zastępowania dobrze znanych sufiksów angielskich słów.
PorterStemmer klasa
NLTK ma PorterStemmerklasa, za pomocą której możemy łatwo zaimplementować algorytmy Portera Stemmera dla słowa, które chcemy macierzystym. Ta klasa zna kilka regularnych form wyrazów i sufiksów, za pomocą których może przekształcić słowo wejściowe w końcowy temat. Wynikowy temat jest często krótszym słowem o tym samym znaczeniu źródłowym. Zobaczmy przykład -
Najpierw musimy zaimportować zestaw narzędzi języka naturalnego (nltk).
import nltk
Teraz zaimportuj plik PorterStemmer do implementacji algorytmu Portera Stemmera.
from nltk.stem import PorterStemmer
Następnie utwórz instancję klasy Porter Stemmer w następujący sposób -
word_stemmer = PorterStemmer()
Teraz wprowadź słowo, które chcesz wywołać.
word_stemmer.stem('writing')
Wynik
'write'
word_stemmer.stem('eating')
Wynik
'eat'
Kompletny przykład wdrożenia
import nltk
from nltk.stem import PorterStemmer
word_stemmer = PorterStemmer()
word_stemmer.stem('writing')
Wynik
'write'
Algorytm Lancastera
Został opracowany na Uniwersytecie Lancaster i jest kolejnym bardzo popularnym algorytmem rodującym.
Klasa LancasterStemmer
NLTK ma LancasterStemmerklasa za pomocą której możemy łatwo zaimplementować algorytmy Lancaster Stemmer dla słowa, które chcemy macierzystym. Zobaczmy przykład -
Najpierw musimy zaimportować zestaw narzędzi języka naturalnego (nltk).
import nltk
Teraz zaimportuj plik LancasterStemmer klasy do implementacji algorytmu Lancaster Stemmer
from nltk.stem import LancasterStemmer
Następnie utwórz wystąpienie LancasterStemmer klasę w następujący sposób -
Lanc_stemmer = LancasterStemmer()
Teraz wprowadź słowo, które chcesz wywołać.
Lanc_stemmer.stem('eats')
Wynik
'eat'
Kompletny przykład wdrożenia
import nltk
from nltk.stem import LancatserStemmer
Lanc_stemmer = LancasterStemmer()
Lanc_stemmer.stem('eats')
Wynik
'eat'
Algorytm rymowania wyrażeń regularnych
Za pomocą tego algorytmu rdzenia możemy skonstruować własny stemmer.
RegexpStemmer klasa
NLTK ma RegexpStemmerklasa za pomocą której możemy w łatwy sposób zaimplementować algorytmy Regular Expression Stemmer. Zasadniczo przyjmuje jedno wyrażenie regularne i usuwa przedrostek lub przyrostek pasujący do wyrażenia. Zobaczmy przykład -
Najpierw musimy zaimportować zestaw narzędzi języka naturalnego (nltk).
import nltk
Teraz zaimportuj plik RegexpStemmer do implementacji algorytmu Stemmer wyrażeń regularnych.
from nltk.stem import RegexpStemmer
Następnie utwórz wystąpienie RegexpStemmer class i zapewnia przyrostek lub przedrostek, który chcesz usunąć ze słowa w następujący sposób -
Reg_stemmer = RegexpStemmer(‘ing’)
Teraz wprowadź słowo, które chcesz wywołać.
Reg_stemmer.stem('eating')
Wynik
'eat'
Reg_stemmer.stem('ingeat')
Wynik
'eat'
Reg_stemmer.stem('eats')
Wynik
'eat'
Kompletny przykład wdrożenia
import nltk
from nltk.stem import RegexpStemmer
Reg_stemmer = RegexpStemmer()
Reg_stemmer.stem('ingeat')
Wynik
'eat'
Algorytm robienia śnieżki
Jest to kolejny bardzo przydatny algorytm bazujący.
Klasa SnowballStemmer
NLTK ma SnowballStemmerklasa za pomocą której możemy łatwo zaimplementować algorytmy Snowball Stemmer. Obsługuje 15 języków innych niż angielski. Aby użyć tej parującej klasy, musimy utworzyć instancję z nazwą używanego przez nas języka, a następnie wywołać metodę stem (). Zobaczmy przykład -
Najpierw musimy zaimportować zestaw narzędzi języka naturalnego (nltk).
import nltk
Teraz zaimportuj plik SnowballStemmer do implementacji algorytmu Snowball Stemmer
from nltk.stem import SnowballStemmer
Zobaczmy, jakie języki obsługuje -
SnowballStemmer.languages
Wynik
(
'arabic',
'danish',
'dutch',
'english',
'finnish',
'french',
'german',
'hungarian',
'italian',
'norwegian',
'porter',
'portuguese',
'romanian',
'russian',
'spanish',
'swedish'
)
Następnie utwórz instancję klasy SnowballStemmer w języku, którego chcesz używać. Tutaj tworzymy stemmer dla języka „francuskiego”.
French_stemmer = SnowballStemmer(‘french’)
Teraz wywołaj metodę stem () i wprowadź słowo, które chcesz wywołać.
French_stemmer.stem (‘Bonjoura’)
Wynik
'bonjour'
Kompletny przykład wdrożenia
import nltk
from nltk.stem import SnowballStemmer
French_stemmer = SnowballStemmer(‘french’)
French_stemmer.stem (‘Bonjoura’)
Wynik
'bonjour'
Co to jest lematyzacja?
Technika lematyzacji jest jak wyprowadzanie. Dane wyjściowe, które otrzymamy po lematyzacji, nazywa się „lemat”, które jest raczej słowem źródłowym niż rdzeniem rdzeniowym, wynikiem rdzenia. Po lematyzacji otrzymamy prawidłowe słowo, które oznacza to samo.
NLTK zapewnia WordNetLemmatizer klasa, która jest cienkim opakowaniem wokół wordnetciało. Ta klasa używamorphy() funkcji do WordNet CorpusReaderklasy, aby znaleźć lemat. Zrozummy to na przykładzie -
Przykład
Najpierw musimy zaimportować zestaw narzędzi języka naturalnego (nltk).
import nltk
Teraz zaimportuj plik WordNetLemmatizer klasy do implementacji techniki lematyzacji.
from nltk.stem import WordNetLemmatizer
Następnie utwórz wystąpienie WordNetLemmatizer klasa.
lemmatizer = WordNetLemmatizer()
Teraz wywołaj metodę lemmatize () i wprowadź słowo, którego chcesz znaleźć lemat.
lemmatizer.lemmatize('eating')
Wynik
'eating'
lemmatizer.lemmatize('books')
Wynik
'book'
Kompletny przykład wdrożenia
import nltk
from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
lemmatizer.lemmatize('books')
Wynik
'book'
Różnica między Stemming i Lemmatyzacją
Zrozummy różnicę między Stemming i Lemmatyzacją za pomocą następującego przykładu -
import nltk
from nltk.stem import PorterStemmer
word_stemmer = PorterStemmer()
word_stemmer.stem('believes')
Wynik
believ
import nltk
from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
lemmatizer.lemmatize(' believes ')
Wynik
believ
Dane wyjściowe obu programów pokazują główną różnicę między podstawianiem a lematyzacją. PorterStemmerklasa odcina „es” ze słowa. Z drugiej strony,WordNetLemmatizerclass znajduje prawidłowe słowo. Mówiąc prościej, technika odmierzania dotyczy tylko formy słowa, podczas gdy technika lematyzacji analizuje znaczenie słowa. Oznacza to, że po zastosowaniu lematyzacji zawsze otrzymamy prawidłowe słowo.
Stemming i lematyzacja mogą być traktowane jako rodzaj kompresji językowej. W tym samym sensie zamianę słów można traktować jako normalizację tekstu lub korektę błędów.
Ale dlaczego potrzebowaliśmy zamiany słów? Załóżmy, że jeśli mówimy o tokenizacji, oznacza to, że występują problemy ze skurczami (np. Nie mogę, nie chce, itp.). Tak więc, aby poradzić sobie z takimi problemami, potrzebujemy zamiany słów. Na przykład możemy zastąpić skurcze ich rozszerzonymi formami.
Zamiana słów za pomocą wyrażenia regularnego
Najpierw zamienimy słowa pasujące do wyrażenia regularnego. Ale w tym celu musimy mieć podstawową wiedzę na temat wyrażeń regularnych, a także modułu Python re. W poniższym przykładzie zastąpimy skrócenie ich rozszerzonymi formami (np. „Nie mogę” zostanie zastąpione „nie można”), a wszystko to za pomocą wyrażeń regularnych.
Przykład
Najpierw zaimportuj niezbędny pakiet do pracy z wyrażeniami regularnymi.
import re
from nltk.corpus import wordnet
Następnie zdefiniuj wybrane wzorce zastępcze w następujący sposób -
R_patterns = [
(r'won\'t', 'will not'),
(r'can\'t', 'cannot'),
(r'i\'m', 'i am'),
r'(\w+)\'ll', '\g<1> will'),
(r'(\w+)n\'t', '\g<1> not'),
(r'(\w+)\'ve', '\g<1> have'),
(r'(\w+)\'s', '\g<1> is'),
(r'(\w+)\'re', '\g<1> are'),
]
Teraz utwórz klasę, której można użyć do zamiany słów -
class REReplacer(object):
def __init__(self, pattern = R_patterns):
self.pattern = [(re.compile(regex), repl) for (regex, repl) in patterns]
def replace(self, text):
s = text
for (pattern, repl) in self.pattern:
s = re.sub(pattern, repl, s)
return s
Zapisz ten program w języku Python (powiedzmy repRE.py) i uruchom go z wiersza poleceń Pythona. Po uruchomieniu zaimportuj klasę REReplacer, jeśli chcesz zamienić słowa. Zobaczmy, jak to zrobić.
from repRE import REReplacer
rep_word = REReplacer()
rep_word.replace("I won't do it")
Output:
'I will not do it'
rep_word.replace("I can’t do it")
Output:
'I cannot do it'
Kompletny przykład wdrożenia
import re
from nltk.corpus import wordnet
R_patterns = [
(r'won\'t', 'will not'),
(r'can\'t', 'cannot'),
(r'i\'m', 'i am'),
r'(\w+)\'ll', '\g<1> will'),
(r'(\w+)n\'t', '\g<1> not'),
(r'(\w+)\'ve', '\g<1> have'),
(r'(\w+)\'s', '\g<1> is'),
(r'(\w+)\'re', '\g<1> are'),
]
class REReplacer(object):
def __init__(self, patterns=R_patterns):
self.patterns = [(re.compile(regex), repl) for (regex, repl) in patterns]
def replace(self, text):
s = text
for (pattern, repl) in self.patterns:
s = re.sub(pattern, repl, s)
return s
Teraz, po zapisaniu powyższego programu i uruchomieniu go, możesz zaimportować klasę i używać jej w następujący sposób -
from replacerRE import REReplacer
rep_word = REReplacer()
rep_word.replace("I won't do it")
Wynik
'I will not do it'
Wymiana przed przetwarzaniem tekstu
Jedną z powszechnych praktyk podczas pracy z przetwarzaniem języka naturalnego (NLP) jest czyszczenie tekstu przed przetworzeniem tekstu. W tym względzie możemy również skorzystać z naszegoREReplacer klasę utworzoną powyżej w poprzednim przykładzie, jako wstępny krok przed przetwarzaniem tekstu, czyli tokenizacją.
Przykład
from nltk.tokenize import word_tokenize
from replacerRE import REReplacer
rep_word = REReplacer()
word_tokenize("I won't be able to do this now")
Output:
['I', 'wo', "n't", 'be', 'able', 'to', 'do', 'this', 'now']
word_tokenize(rep_word.replace("I won't be able to do this now"))
Output:
['I', 'will', 'not', 'be', 'able', 'to', 'do', 'this', 'now']
W powyższej recepturze Pythona możemy łatwo zrozumieć różnicę między wyjściem tokenizera słów bez i przy użyciu zastępowania wyrażeń regularnych.
Usunięcie powtarzających się znaków
Czy w naszym codziennym języku posługujemy się ściśle gramatyką? Nie, nie jesteśmy. Na przykład czasami piszemy „Hiiiiiiiiiiii Mohan”, aby podkreślić słowo „Cześć”. Ale system komputerowy nie wie, że „Hiiiiiiiiiiii” jest odmianą słowa „Hi”. W poniższym przykładzie utworzymy klasę o nazwierep_word_removal które można wykorzystać do usunięcia powtarzających się słów.
Przykład
Najpierw zaimportuj niezbędny pakiet do pracy z wyrażeniami regularnymi
import re
from nltk.corpus import wordnet
Teraz utwórz klasę, której można użyć do usuwania powtarzających się słów -
class Rep_word_removal(object):
def __init__(self):
self.repeat_regexp = re.compile(r'(\w*)(\w)\2(\w*)')
self.repl = r'\1\2\3'
def replace(self, word):
if wordnet.synsets(word):
return word
repl_word = self.repeat_regexp.sub(self.repl, word)
if repl_word != word:
return self.replace(repl_word)
else:
return repl_word
Zapisz ten program w języku Python (powiedzmy removerepeat.py) i uruchom go z wiersza poleceń Pythona. Po uruchomieniu importujRep_word_removalklasy, gdy chcesz usunąć powtarzające się słowa. Zobaczmy jak?
from removalrepeat import Rep_word_removal
rep_word = Rep_word_removal()
rep_word.replace ("Hiiiiiiiiiiiiiiiiiiiii")
Output:
'Hi'
rep_word.replace("Hellooooooooooooooo")
Output:
'Hello'
Kompletny przykład wdrożenia
import re
from nltk.corpus import wordnet
class Rep_word_removal(object):
def __init__(self):
self.repeat_regexp = re.compile(r'(\w*)(\w)\2(\w*)')
self.repl = r'\1\2\3'
def replace(self, word):
if wordnet.synsets(word):
return word
replace_word = self.repeat_regexp.sub(self.repl, word)
if replace_word != word:
return self.replace(replace_word)
else:
return replace_word
Teraz, po zapisaniu powyższego programu i uruchomieniu go, możesz zaimportować klasę i używać jej w następujący sposób -
from removalrepeat import Rep_word_removal
rep_word = Rep_word_removal()
rep_word.replace ("Hiiiiiiiiiiiiiiiiiiiii")
Wynik
'Hi'
Zamiana słów na popularne synonimy
Podczas pracy z NLP, szczególnie w przypadku analizy częstotliwości i indeksowania tekstu, zawsze warto skompresować słownictwo bez utraty znaczenia, ponieważ oszczędza to dużo pamięci. Aby to osiągnąć, musimy zdefiniować przypisanie słowa do jego synonimów. W poniższym przykładzie utworzymy klasę o nazwieword_syn_replacer których można użyć do zastąpienia słów ich popularnymi synonimami.
Przykład
Najpierw zaimportuj niezbędny pakiet re pracować z wyrażeniami regularnymi.
import re
from nltk.corpus import wordnet
Następnie utwórz klasę, która przyjmuje odwzorowanie zamiany słów -
class word_syn_replacer(object):
def __init__(self, word_map):
self.word_map = word_map
def replace(self, word):
return self.word_map.get(word, word)
Zapisz ten program w języku Python (powiedzmy Replacesyn.py) i uruchom go z wiersza poleceń Pythona. Po uruchomieniu importujword_syn_replacerclass, gdy chcesz zamienić słowa na popularne synonimy. Zobaczmy, jak to zrobić.
from replacesyn import word_syn_replacer
rep_syn = word_syn_replacer ({‘bday’: ‘birthday’)
rep_syn.replace(‘bday’)
Wynik
'birthday'
Kompletny przykład wdrożenia
import re
from nltk.corpus import wordnet
class word_syn_replacer(object):
def __init__(self, word_map):
self.word_map = word_map
def replace(self, word):
return self.word_map.get(word, word)
Teraz, po zapisaniu powyższego programu i uruchomieniu go, możesz zaimportować klasę i używać jej w następujący sposób -
from replacesyn import word_syn_replacer
rep_syn = word_syn_replacer ({‘bday’: ‘birthday’)
rep_syn.replace(‘bday’)
Wynik
'birthday'
Wadą powyższej metody jest to, że powinniśmy zakodować synonimy na stałe w słowniku Pythona. Mamy dwie lepsze alternatywy w postaci pliku CSV i YAML. Możemy zapisać nasze słownictwo synonimów w każdym z wyżej wymienionych plików i konstruowaćword_mapsłownik od nich. Zrozummy koncepcję za pomocą przykładów.
Korzystanie z pliku CSV
Aby użyć w tym celu pliku CSV, plik powinien mieć dwie kolumny, pierwsza kolumna zawiera słowo, a druga zawiera synonimy, które mają je zastąpić. Zapiszmy ten plik jakosyn.csv. W poniższym przykładzie utworzymy klasę o nazwie CSVword_syn_replacer który się rozszerzy word_syn_replacer w replacesyn.py plik i będzie używany do konstruowania pliku word_map słownik z syn.csv plik.
Przykład
Najpierw zaimportuj niezbędne pakiety.
import csv
Następnie utwórz klasę, która przyjmuje odwzorowanie zamiany słów -
class CSVword_syn_replacer(word_syn_replacer):
def __init__(self, fname):
word_map = {}
for line in csv.reader(open(fname)):
word, syn = line
word_map[word] = syn
super(Csvword_syn_replacer, self).__init__(word_map)
Po uruchomieniu importuj CSVword_syn_replacerclass, gdy chcesz zamienić słowa na popularne synonimy. Zobaczmy jak?
from replacesyn import CSVword_syn_replacer
rep_syn = CSVword_syn_replacer (‘syn.csv’)
rep_syn.replace(‘bday’)
Wynik
'birthday'
Kompletny przykład wdrożenia
import csv
class CSVword_syn_replacer(word_syn_replacer):
def __init__(self, fname):
word_map = {}
for line in csv.reader(open(fname)):
word, syn = line
word_map[word] = syn
super(Csvword_syn_replacer, self).__init__(word_map)
Teraz, po zapisaniu powyższego programu i uruchomieniu go, możesz zaimportować klasę i używać jej w następujący sposób -
from replacesyn import CSVword_syn_replacer
rep_syn = CSVword_syn_replacer (‘syn.csv’)
rep_syn.replace(‘bday’)
Wynik
'birthday'
Korzystanie z pliku YAML
Ponieważ użyliśmy pliku CSV, możemy również użyć do tego pliku YAML (musimy mieć zainstalowany PyYAML). Zapiszmy plik jakosyn.yaml. W poniższym przykładzie utworzymy klasę o nazwie YAMLword_syn_replacer który się rozszerzy word_syn_replacer w replacesyn.py plik i będzie używany do konstruowania pliku word_map słownik z syn.yaml plik.
Przykład
Najpierw zaimportuj niezbędne pakiety.
import yaml
Następnie utwórz klasę, która przyjmuje odwzorowanie zamiany słów -
class YAMLword_syn_replacer(word_syn_replacer):
def __init__(self, fname):
word_map = yaml.load(open(fname))
super(YamlWordReplacer, self).__init__(word_map)
Po uruchomieniu importuj YAMLword_syn_replacerclass, gdy chcesz zamienić słowa na popularne synonimy. Zobaczmy jak?
from replacesyn import YAMLword_syn_replacer
rep_syn = YAMLword_syn_replacer (‘syn.yaml’)
rep_syn.replace(‘bday’)
Wynik
'birthday'
Kompletny przykład wdrożenia
import yaml
class YAMLword_syn_replacer(word_syn_replacer):
def __init__(self, fname):
word_map = yaml.load(open(fname))
super(YamlWordReplacer, self).__init__(word_map)
Teraz, po zapisaniu powyższego programu i uruchomieniu go, możesz zaimportować klasę i używać jej w następujący sposób -
from replacesyn import YAMLword_syn_replacer
rep_syn = YAMLword_syn_replacer (‘syn.yaml’)
rep_syn.replace(‘bday’)
Wynik
'birthday'
Zastąpienie antonimu
Jak wiemy, antonim to słowo o znaczeniu przeciwnym do innego słowa, a przeciwieństwo zamiany synonimu nazywa się zamianą antonimu. W tej sekcji zajmiemy się zastępowaniem antonimów, czyli zamianą słów na jednoznaczne antonimy za pomocą WordNet. W poniższym przykładzie utworzymy klasę o nazwieword_antonym_replacer które mają dwie metody, jedną do zastępowania słowa, a drugą do usuwania negacji.
Przykład
Najpierw zaimportuj niezbędne pakiety.
from nltk.corpus import wordnet
Następnie utwórz klasę o nazwie word_antonym_replacer -
class word_antonym_replacer(object):
def replace(self, word, pos=None):
antonyms = set()
for syn in wordnet.synsets(word, pos=pos):
for lemma in syn.lemmas():
for antonym in lemma.antonyms():
antonyms.add(antonym.name())
if len(antonyms) == 1:
return antonyms.pop()
else:
return None
def replace_negations(self, sent):
i, l = 0, len(sent)
words = []
while i < l:
word = sent[i]
if word == 'not' and i+1 < l:
ant = self.replace(sent[i+1])
if ant:
words.append(ant)
i += 2
continue
words.append(word)
i += 1
return words
Zapisz ten program w języku Python (powiedzmy replaceantonym.py) i uruchom go z wiersza poleceń Pythona. Po uruchomieniu importujword_antonym_replacerclass, gdy chcesz zamienić słowa na ich jednoznaczne antonimy. Zobaczmy, jak to zrobić.
from replacerantonym import word_antonym_replacer
rep_antonym = word_antonym_replacer ()
rep_antonym.replace(‘uglify’)
Wynik
['beautify'']
sentence = ["Let us", 'not', 'uglify', 'our', 'country']
rep_antonym.replace _negations(sentence)
Wynik
["Let us", 'beautify', 'our', 'country']
Kompletny przykład wdrożenia
nltk.corpus import wordnet
class word_antonym_replacer(object):
def replace(self, word, pos=None):
antonyms = set()
for syn in wordnet.synsets(word, pos=pos):
for lemma in syn.lemmas():
for antonym in lemma.antonyms():
antonyms.add(antonym.name())
if len(antonyms) == 1:
return antonyms.pop()
else:
return None
def replace_negations(self, sent):
i, l = 0, len(sent)
words = []
while i < l:
word = sent[i]
if word == 'not' and i+1 < l:
ant = self.replace(sent[i+1])
if ant:
words.append(ant)
i += 2
continue
words.append(word)
i += 1
return words
Teraz, po zapisaniu powyższego programu i uruchomieniu go, możesz zaimportować klasę i używać jej w następujący sposób -
from replacerantonym import word_antonym_replacer
rep_antonym = word_antonym_replacer ()
rep_antonym.replace(‘uglify’)
sentence = ["Let us", 'not', 'uglify', 'our', 'country']
rep_antonym.replace _negations(sentence)
Wynik
["Let us", 'beautify', 'our', 'country']
Co to jest korpus?
Korpus to duży zbiór w ustrukturyzowanym formacie tekstów nadających się do odczytu maszynowego, które zostały utworzone w naturalnym środowisku komunikacyjnym. Słowo Corpora jest liczbą mnogą od Corpus. Korpus można wyprowadzić na wiele sposobów w następujący sposób -
- Z tekstu, który był pierwotnie elektroniczny
- Z transkrypcji języka mówionego
- Od optycznego rozpoznawania znaków i tak dalej
Reprezentatywność korpusu, balans korpusu, próbkowanie, rozmiar korpusu to elementy, które odgrywają ważną rolę podczas projektowania korpusu. Do najpopularniejszych korpusów zadań NLP należą TreeBank, PropBank, VarbNet i WordNet.
Jak zbudować niestandardowy korpus?
Podczas pobierania NLTK zainstalowaliśmy również pakiet danych NLTK. Tak więc mamy już zainstalowany pakiet danych NLTK na naszym komputerze. Jeśli mówimy o systemie Windows, zakładamy, że ten pakiet danych jest zainstalowany wC:\natural_language_toolkit_data a jeśli mówimy o Linuksie, Uniksie i Mac OS X, założymy, że ten pakiet danych jest zainstalowany w /usr/share/natural_language_toolkit_data.
W poniższym przepisie Pythona utworzymy niestandardowe korpusy, które muszą znajdować się w jednej ze ścieżek zdefiniowanych przez NLTK. Dzieje się tak, ponieważ można go znaleźć NLTK. Aby uniknąć konfliktu z oficjalnym pakietem danych NLTK, utwórzmy niestandardowy katalog natural_language_toolkit_data w naszym katalogu domowym.
import os, os.path
path = os.path.expanduser('~/natural_language_toolkit_data')
if not os.path.exists(path):
os.mkdir(path)
os.path.exists(path)
Wynik
True
Teraz sprawdźmy, czy mamy katalog natural_language_toolkit_data w naszym katalogu domowym, czy nie -
import nltk.data
path in nltk.data.path
Wynik
True
Ponieważ otrzymaliśmy wynik True, oznacza, że mamy nltk_data katalogu w naszym katalogu domowym.
Teraz utworzymy plik listy słów o nazwie wordfile.txt i umieść go w folderze o nazwie corpus in nltk_data informator (~/nltk_data/corpus/wordfile.txt) i załaduje go za pomocą nltk.data.load -
import nltk.data
nltk.data.load(‘corpus/wordfile.txt’, format = ‘raw’)
Wynik
b’tutorialspoint\n’
Czytelnicy Corpus
NLTK udostępnia różne klasy CorpusReader. Omówimy je w poniższych przepisach na Pythona
Tworzenie korpusu listy słów
NLTK ma WordListCorpusReaderklasa, która zapewnia dostęp do pliku zawierającego listę słów. W przypadku poniższego przepisu w Pythonie musimy utworzyć plik listy słów, który może być plikiem CSV lub zwykłym plikiem tekstowym. Na przykład utworzyliśmy plik o nazwie „lista”, który zawiera następujące dane -
tutorialspoint
Online
Free
Tutorials
Teraz stwórzmy instancję WordListCorpusReader klasa tworząca listę słów z naszego utworzonego pliku ‘list’.
from nltk.corpus.reader import WordListCorpusReader
reader_corpus = WordListCorpusReader('.', ['list'])
reader_corpus.words()
Wynik
['tutorialspoint', 'Online', 'Free', 'Tutorials']
Tworzenie korpusu słów ze znacznikami POS
NLTK ma TaggedCorpusReaderclass za pomocą której możemy stworzyć korpus słów tagowanych POS. W rzeczywistości tagowanie POS to proces identyfikacji znacznika części mowy dla słowa.
Jednym z najprostszych formatów otagowanego korpusu jest forma „słowo / tag”, podobnie jak następujący fragment z brązowego korpusu -
The/at-tl expense/nn and/cc time/nn involved/vbn are/ber
astronomical/jj ./.
W powyższym fragmencie każde słowo ma tag, który oznacza jego POS. Na przykład,vb odnosi się do czasownika.
Teraz stwórzmy instancję TaggedCorpusReaderklasa produkująca słowa oznaczone tagami POS z pliku ‘list.pos’, który zawiera powyższy fragment.
from nltk.corpus.reader import TaggedCorpusReader
reader_corpus = TaggedCorpusReader('.', r'.*\.pos')
reader_corpus.tagged_words()
Wynik
[('The', 'AT-TL'), ('expense', 'NN'), ('and', 'CC'), ...]
Tworzenie fragmentów korpusu fraz
NLTK ma ChnkedCorpusReaderclass za pomocą której możemy stworzyć korpus fraz Chunked. W rzeczywistości kawałek to krótkie wyrażenie w zdaniu.
Na przykład mamy następujący fragment z tagged treebank korpus -
[Earlier/JJR staff-reduction/NN moves/NNS] have/VBP trimmed/VBN about/
IN [300/CD jobs/NNS] ,/, [the/DT spokesman/NN] said/VBD ./.
W powyższym fragmencie każdy fragment jest frazą rzeczownikową, ale słowa, które nie są w nawiasach, są częścią drzewa zdań, a nie częścią żadnego poddrzewa wyrażenia rzeczownikowego.
Teraz stwórzmy instancję ChunkedCorpusReader klasa produkująca fragmentowaną frazę z pliku ‘list.chunk’, który zawiera powyższy fragment.
from nltk.corpus.reader import ChunkedCorpusReader
reader_corpus = TaggedCorpusReader('.', r'.*\.chunk')
reader_corpus.chunked_words()
Wynik
[
Tree('NP', [('Earlier', 'JJR'), ('staff-reduction', 'NN'), ('moves', 'NNS')]),
('have', 'VBP'), ...
]
Tworzenie korpusu tekstu skategoryzowanego
NLTK ma CategorizedPlaintextCorpusReaderklasa, za pomocą której możemy stworzyć skategoryzowany korpus tekstu. Jest to bardzo przydatne w przypadku, gdy mamy duży korpus tekstu i chcemy podzielić go na osobne sekcje.
Na przykład brązowy korpus ma kilka różnych kategorii. Pozwól nam poznać je za pomocą następującego kodu Pythona -
from nltk.corpus import brown^M
brown.categories()
Wynik
[
'adventure', 'belles_lettres', 'editorial', 'fiction', 'government',
'hobbies', 'humor', 'learned', 'lore', 'mystery', 'news', 'religion',
'reviews', 'romance', 'science_fiction'
]
Jednym z najłatwiejszych sposobów kategoryzacji korpusu jest utworzenie jednego pliku dla każdej kategorii. Na przykład spójrzmy na dwa fragmenty zmovie_reviews korpus -
movie_pos.txt
Cienka czerwona linia jest wadliwa, ale prowokuje.
movie_neg.txt
Wysokobudżetowa i błyszcząca produkcja nie może nadrobić braku spontaniczności, który przenika ich program telewizyjny.
Tak więc z dwóch powyższych plików mamy dwie kategorie, a mianowicie pos i neg.
Teraz stwórzmy instancję CategorizedPlaintextCorpusReader klasa.
from nltk.corpus.reader import CategorizedPlaintextCorpusReader
reader_corpus = CategorizedPlaintextCorpusReader('.', r'movie_.*\.txt',
cat_pattern = r'movie_(\w+)\.txt')
reader_corpus.categories()
reader_corpus.fileids(categories = [‘neg’])
reader_corpus.fileids(categories = [‘pos’])
Wynik
['neg', 'pos']
['movie_neg.txt']
['movie_pos.txt']
Co to jest tagowanie POS?
Tagowanie, rodzaj klasyfikacji, to automatyczne przypisywanie opisu tokenów. Nazywamy deskryptor „znacznikiem”, który reprezentuje jedną z części mowy (rzeczowniki, czasownik, przysłówki, przymiotniki, zaimki, spójnik i ich podkategorie), informacje semantyczne i tak dalej.
Z drugiej strony, jeśli mówimy o tagowaniu części mowy (POS), można je zdefiniować jako proces konwersji zdania w postaci listy słów na listę krotek. Tutaj krotki mają postać (słowo, tag). Możemy też nazwać POS tagowanie procesem przypisywania jednej z części mowy do danego słowa.
Poniższa tabela przedstawia najczęstsze powiadomienia POS używane w korpusie Penn Treebank -
Sr.No | Etykietka | Opis |
---|---|---|
1 | NNP | Rzeczownik w liczbie pojedynczej |
2 | NNPS | Rzeczownik w liczbie mnogiej |
3 | PDT | Określenie wstępne |
4 | POS | Zaborcze zakończenie |
5 | PRP | Zaimek osobowy |
6 | PRP $ | Zaimek dzierżawczy |
7 | RB | Przysłówek |
8 | RBR | Przysłówek porównawczy |
9 | RBS | Przysłówek, stopień najwyższy |
10 | RP | Cząstka |
11 | SYM | Symbol (matematyczny lub naukowy) |
12 | DO | do |
13 | UH | Wykrzyknik |
14 | VB | Czasownik, forma podstawowa |
15 | VBD | Czasownik, czas przeszły |
16 | VBG | Czasownik odczasownikowy / imiesłów teraźniejszy |
17 | VBN | Czasownik przeszły |
18 | WP | Zaimek Wh |
19 | WP $ | Zaimek dzierżawczy Wh |
20 | WRB | Wh-przysłówek |
21 | # | Znak funta |
22 | $ | Znak dolara |
23 | . | Końcowa interpunkcja w zdaniu |
24 | , | Przecinek |
25 | : | Okrężnica, średnik |
26 | ( | Znak lewego nawiasu |
27 | ) | Znak prawego nawiasu |
28 | " | Prosty podwójny cudzysłów |
29 | ' | Zostawił otwarty pojedynczy cudzysłów |
30 | " | Zostawił otwarty podwójny cudzysłów |
31 | ' | Pojedynczy cudzysłów po prawej stronie |
32 | " | Podwójny cudzysłów otwarty z prawej strony |
Przykład
Zrozummy to za pomocą eksperymentu w Pythonie -
import nltk
from nltk import word_tokenize
sentence = "I am going to school"
print (nltk.pos_tag(word_tokenize(sentence)))
Wynik
[('I', 'PRP'), ('am', 'VBP'), ('going', 'VBG'), ('to', 'TO'), ('school', 'NN')]
Dlaczego tagowanie POS?
Tagowanie POS jest ważną częścią NLP, ponieważ działa jako warunek wstępny do dalszej analizy NLP w następujący sposób -
- Chunking
- Analiza składni
- Ekstrakcja informacji
- Tłumaczenie maszynowe
- Analiza nastrojów
- Analiza gramatyczna i ujednoznacznienie znaczenia słów
TaggerI - klasa bazowa
Wszystkie taggery znajdują się w pakiecie NLTK nltk.tag. Podstawową klasą tych taggerów jestTaggerI, oznacza, że wszystkie znaczniki dziedziczą z tej klasy.
Methods - Klasa TaggerI ma następujące dwie metody, które muszą być implementowane przez wszystkie jej podklasy -
tag() method - Jak sama nazwa wskazuje, ta metoda przyjmuje listę słów jako dane wejściowe i zwraca listę oznaczonych słów jako dane wyjściowe.
evaluate() method - Przy pomocy tej metody możemy ocenić dokładność taggera.
Podstawa tagowania POS
Podstawą lub podstawowym krokiem tagowania POS jest Default Tagging, co można wykonać za pomocą klasy DefaultTagger NLTK. Domyślne tagowanie po prostu przypisuje ten sam znacznik POS do każdego tokena. Etykietowanie domyślne zapewnia również podstawę do pomiaru poprawy dokładności.
Klasa DefaultTagger
Tagowanie domyślne jest wykonywane przy użyciu DefaultTagging class, która przyjmuje pojedynczy argument, tj. znacznik, który chcemy zastosować.
Jak to działa?
Jak powiedziano wcześniej, wszystkie znaczniki są dziedziczone z TaggerIklasa. PlikDefaultTagger jest dziedziczona z SequentialBackoffTagger który jest podklasą TaggerI class. Zrozummy to na poniższym schemacie -
Jako część SeuentialBackoffTagger, the DefaultTagger musi zaimplementować metodę choose_tag (), która przyjmuje następujące trzy argumenty.
- Lista tokenów
- Aktualny indeks tokena
- Lista poprzednich tokenów, czyli historia
Przykład
import nltk
from nltk.tag import DefaultTagger
exptagger = DefaultTagger('NN')
exptagger.tag(['Tutorials','Point'])
Wynik
[('Tutorials', 'NN'), ('Point', 'NN')]
W tym przykładzie wybraliśmy tag rzeczownikowy, ponieważ jest to najpowszechniejszy typ słów. Ponadto,DefaultTagger jest również najbardziej przydatny, gdy wybieramy najpopularniejszy tag POS.
Ocena dokładności
Plik DefaultTaggerjest również podstawą do oceny dokładności taggerów. To jest powód, dla którego możemy go używać razem zevaluate()metoda pomiaru dokładności. Plikevaluate() Metoda przyjmuje listę oznaczonych tokenów jako złoty standard do oceny taggera.
Poniżej znajduje się przykład, w którym użyliśmy naszego domyślnego taggera o nazwie exptaggerutworzony powyżej, aby ocenić dokładność podzbioru treebank zdania z tagiem korpusu -
Przykład
import nltk
from nltk.tag import DefaultTagger
exptagger = DefaultTagger('NN')
from nltk.corpus import treebank
testsentences = treebank.tagged_sents() [1000:]
exptagger.evaluate (testsentences)
Wynik
0.13198749536374715
Powyższe dane wyjściowe pokazują to, wybierając NN dla każdego tagu możemy osiągnąć około 13% dokładności testów na 1000 wpisów pliku treebank ciało.
Oznaczanie listy zdań
Zamiast oznaczać pojedyncze zdanie, NLTK TaggerI class zapewnia nam również plik tag_sents()metoda, za pomocą której możemy otagować listę zdań. Poniżej znajduje się przykład, w którym oznaczyliśmy dwa proste zdania
Przykład
import nltk
from nltk.tag import DefaultTagger
exptagger = DefaultTagger('NN')
exptagger.tag_sents([['Hi', ','], ['How', 'are', 'you', '?']])
Wynik
[
[
('Hi', 'NN'),
(',', 'NN')
],
[
('How', 'NN'),
('are', 'NN'),
('you', 'NN'),
('?', 'NN')
]
]
W powyższym przykładzie użyliśmy naszego wcześniej utworzonego domyślnego taggera o nazwie exptagger.
Usuwanie tagów z zdania
Możemy również odtagować zdanie. W tym celu NLTK udostępnia metodę nltk.tag.untag (). Przyjmuje tagowane zdanie jako dane wejściowe i dostarcza listę słów bez tagów. Zobaczmy przykład -
Przykład
import nltk
from nltk.tag import untag
untag([('Tutorials', 'NN'), ('Point', 'NN')])
Wynik
['Tutorials', 'Point']
Co to jest Unigram Tagger?
Jak sama nazwa wskazuje, unigram tagger to tagger, który używa tylko jednego słowa jako kontekstu do określenia tagu POS (Part-of-Speech). Krótko mówiąc, Unigram Tagger to tagger kontekstowy, którego kontekstem jest pojedyncze słowo, czyli Unigram.
Jak to działa?
NLTK udostępnia moduł o nazwie UnigramTaggerw tym celu. Zanim jednak zagłębimy się w jego działanie, zapoznajmy się z hierarchią za pomocą poniższego diagramu -
Z powyższego schematu wynika, że UnigramTagger jest dziedziczona z NgramTagger który jest podklasą ContextTagger, który dziedziczy z SequentialBackoffTagger.
Działanie UnigramTagger wyjaśniono za pomocą następujących kroków -
Jak widzieliśmy, UnigramTagger dziedziczy z ContextTagger, implementuje context()metoda. Tocontext() metoda przyjmuje te same trzy argumenty, co choose_tag() metoda.
Wynik context()metoda będzie słowem tokenem, który będzie dalej używany do tworzenia modelu. Po utworzeniu modelu żeton słowa jest również używany do wyszukiwania najlepszego tagu.
W ten sposób, UnigramTagger zbuduje model kontekstu z listy tagowanych zdań.
Szkolenie Unigram Taggera
NLTK UnigramTaggermożna trenować, udostępniając listę oznaczonych zdań w momencie inicjalizacji. W poniższym przykładzie użyjemy otagowanych zdań korpusu banku drzew. Będziemy używać pierwszych 2500 zdań z tego korpusu.
Przykład
Najpierw zaimportuj moduł UniframTagger z nltk -
from nltk.tag import UnigramTagger
Następnie zaimportuj korpus, którego chcesz użyć. Tutaj używamy korpusu banków drzew -
from nltk.corpus import treebank
Teraz weź te zdania w celach szkoleniowych. Bierzemy pierwsze 2500 zdań w celach szkoleniowych i oznaczymy je -
train_sentences = treebank.tagged_sents()[:2500]
Następnie zastosuj UnigramTagger na zdaniach używanych do celów szkoleniowych -
Uni_tagger = UnigramTagger(train_sentences)
Weź kilka zdań, równych lub mniejszych, przyjętych w celach szkoleniowych, np. 2500, na test. Tutaj bierzemy pierwsze 1500 do celów testowych -
test_sentences = treebank.tagged_sents()[1500:]
Uni_tagger.evaluate(test_sents)
Wynik
0.8942306156033808
Tutaj uzyskaliśmy około 89-procentową dokładność dla taggera, który używa wyszukiwania pojedynczego słowa do określenia tagu POS.
Kompletny przykład wdrożenia
from nltk.tag import UnigramTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
Uni_tagger = UnigramTagger(train_sentences)
test_sentences = treebank.tagged_sents()[1500:]
Uni_tagger.evaluate(test_sentences)
Wynik
0.8942306156033808
Zastępowanie modelu kontekstu
Z powyższego diagramu przedstawiającego hierarchię dla UnigramTagger, znamy wszystkie taggery, które dziedziczą po ContextTaggerzamiast trenować własny, może skorzystać z gotowego modelu. Ten gotowy model jest po prostu słownikiem Pythona mapującym klucz kontekstowy do znacznika. I dlaUnigramTagger, klawisze kontekstu to pojedyncze słowa, podczas gdy dla innych NgramTagger podklasy, będą to krotki.
Możemy przesłonić ten model kontekstu, przekazując inny prosty model do UnigramTaggerzajęcia zamiast przechodzenia zestawu treningowego. Zrozummy to za pomocą prostego przykładu poniżej -
Przykład
from nltk.tag import UnigramTagger
from nltk.corpus import treebank
Override_tagger = UnigramTagger(model = {‘Vinken’ : ‘NN’})
Override_tagger.tag(treebank.sents()[0])
Wynik
[
('Pierre', None),
('Vinken', 'NN'),
(',', None),
('61', None),
('years', None),
('old', None),
(',', None),
('will', None),
('join', None),
('the', None),
('board', None),
('as', None),
('a', None),
('nonexecutive', None),
('director', None),
('Nov.', None),
('29', None),
('.', None)
]
Ponieważ nasz model zawiera „Vinken” jako jedyny klucz kontekstowy, z powyższego wyniku można zauważyć, że tylko to słowo ma znacznik, a każde inne słowo ma jako tag Brak.
Ustawienie minimalnego progu częstotliwości
Aby zdecydować, który tag jest najbardziej prawdopodobny w danym kontekście, plik ContextTaggerklasa używa częstotliwości występowania. Zrobi to domyślnie, nawet jeśli słowo kontekstu i tag występują tylko raz, ale możemy ustawić minimalny próg częstotliwości, przekazująccutoff wartość do UnigramTaggerklasa. W poniższym przykładzie przekazujemy wartość odcięcia w poprzedniej recepturze, w której trenowaliśmy UnigramTagger -
Przykład
from nltk.tag import UnigramTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
Uni_tagger = UnigramTagger(train_sentences, cutoff = 4)
test_sentences = treebank.tagged_sents()[1500:]
Uni_tagger.evaluate(test_sentences)
Wynik
0.7357651629613641
Łączenie taggerów
Łączenie tagerów lub łączenie tagerów ze sobą jest jedną z ważnych cech NLTK. Główna koncepcja łączenia taggerów polega na tym, że w przypadku, gdy jeden tagger nie wie, jak oznaczyć słowo, zostanie ono przekazane do powiązanego taggera. Aby osiągnąć ten cel,SequentialBackoffTagger zapewnia nam Backoff tagging funkcja.
Oznaczanie wycofywania
Jak wspomniano wcześniej, tagowanie wycofywania jest jedną z ważnych funkcji platformy SequentialBackoffTagger, co pozwala nam łączyć taggery w taki sposób, że jeśli jeden tagger nie wie, jak oznaczyć słowo, słowo zostanie przekazane do następnego taggera i tak dalej, aż nie będzie już żadnych backoff taggerów do sprawdzenia.
Jak to działa?
Właściwie każda podklasa SequentialBackoffTaggermoże przyjąć argument słowa kluczowego „backoff”. Wartość tego argumentu słowa kluczowego jest kolejną instancją plikuSequentialBackoffTagger. Teraz, kiedy toSequentialBackoffTaggerclass zostanie zainicjowana, zostanie utworzona wewnętrzna lista znaczników wycofywania (ze sobą jako pierwszym elementem). Ponadto, jeśli podano znacznik wycofania, wewnętrzna lista tych znaczników została dołączona.
W poniższym przykładzie bierzemy DefaulTagger jako znacznik wycofywania w powyższej recepturze Pythona, z którym wytrenowaliśmy UnigramTagger.
Przykład
W tym przykładzie używamy DefaulTaggerjako znacznik wycofywania. Zawsze, gdyUnigramTagger nie jest w stanie oznaczyć słowa, backoff tagger, tj DefaulTagger, w naszym przypadku oznaczy go jako „NN”.
from nltk.tag import UnigramTagger
from nltk.tag import DefaultTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
back_tagger = DefaultTagger('NN')
Uni_tagger = UnigramTagger(train_sentences, backoff = back_tagger)
test_sentences = treebank.tagged_sents()[1500:]
Uni_tagger.evaluate(test_sentences)
Wynik
0.9061975746536931
Z powyższego wyniku można zauważyć, że przez dodanie znacznika wycofania dokładność wzrasta o około 2%.
Ratowanie taggerów z marynatą
Jak widzieliśmy, szkolenie taggera jest bardzo uciążliwe i wymaga czasu. Aby zaoszczędzić czas, możemy zalać wyszkolonego taggera do późniejszego wykorzystania. W poniższym przykładzie zrobimy to naszemu już przeszkolonemu taggerowi o nazwie‘Uni_tagger’.
Przykład
import pickle
f = open('Uni_tagger.pickle','wb')
pickle.dump(Uni_tagger, f)
f.close()
f = open('Uni_tagger.pickle','rb')
Uni_tagger = pickle.load(f)
Klasa NgramTagger
Z diagramu hierarchii omówionego w poprzednim rozdziale, UnigramTagger jest dziedziczona z NgarmTagger class, ale mamy jeszcze dwie podklasy NgarmTagger klasa -
Podklasa BigramTagger
W rzeczywistości ngram jest podciągiem n elementów, stąd, jak nazwa wskazuje, BigramTaggersubclass patrzy na te dwie pozycje. Pierwsza pozycja to poprzednie oznaczone słowo, a druga to bieżące słowo ze znacznikiem.
Podklasa TrigramTagger
Z tego samego powodu BigramTagger, TrigramTagger subclass przygląda się trzem elementom, tj. dwóm poprzednim słowom oznaczonym i jednemu aktualnemu słowu oznaczonemu.
Praktycznie, jeśli się zgłosimy BigramTagger i TrigramTaggerpodklasy indywidualnie, tak jak to zrobiliśmy z podklasą UnigramTagger, obie działają bardzo słabo. Spójrzmy na poniższe przykłady:
Korzystanie z podklasy BigramTagger
from nltk.tag import BigramTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
Bi_tagger = BigramTagger(train_sentences)
test_sentences = treebank.tagged_sents()[1500:]
Bi_tagger.evaluate(test_sentences)
Wynik
0.44669191071913594
Korzystanie z podklasy TrigramTagger
from nltk.tag import TrigramTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
Tri_tagger = TrigramTagger(train_sentences)
test_sentences = treebank.tagged_sents()[1500:]
Tri_tagger.evaluate(test_sentences)
Wynik
0.41949863394526193
Możesz porównać wydajność UnigramTaggera, którego używaliśmy wcześniej (dała około 89% dokładności) z BigramTagger (zapewnił około 44% dokładności) i TrigramTagger (dał około 41% dokładności). Powodem jest to, że znaczniki Bigram i Trigram nie mogą nauczyć się kontekstu z pierwszego słowa (słów) w zdaniu. Z drugiej strony, klasa UnigramTagger nie dba o poprzedni kontekst i zgaduje najpopularniejszy znacznik dla każdego słowa, dzięki czemu może mieć wysoką dokładność linii bazowej.
Łączenie taggerów ngram
Jak z powyższych przykładów, jest oczywiste, że taggery Bigram i Trigram mogą wnieść swój wkład, gdy połączymy je z tagowaniem wycofywania. W poniższym przykładzie łączymy taggery Unigram, Bigram i Trigram z tagowaniem wycofywania. Koncepcja jest taka sama, jak w poprzednim przepisie, łącząc UnigramTagger z backoff tagger. Jedyną różnicą jest to, że do operacji backoff używamy funkcji o nazwie backoff_tagger () z tagger_util.py, podanej poniżej.
def backoff_tagger(train_sentences, tagger_classes, backoff=None):
for cls in tagger_classes:
backoff = cls(train_sentences, backoff=backoff)
return backoff
Przykład
from tagger_util import backoff_tagger
from nltk.tag import UnigramTagger
from nltk.tag import BigramTagger
from nltk.tag import TrigramTagger
from nltk.tag import DefaultTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
back_tagger = DefaultTagger('NN')
Combine_tagger = backoff_tagger(train_sentences,
[UnigramTagger, BigramTagger, TrigramTagger], backoff = back_tagger)
test_sentences = treebank.tagged_sents()[1500:]
Combine_tagger.evaluate(test_sentences)
Wynik
0.9234530029238365
Z powyższego wyniku widać, że zwiększa dokładność o około 3%.
Affix Tagger
Kolejną ważną klasą podklasy ContextTagger jest AffixTagger. W klasie AffixTagger kontekstem jest prefiks lub sufiks słowa. To jest powód, dla którego klasa AffixTagger może uczyć się tagów na podstawie podciągów o stałej długości początku lub końca słowa.
Jak to działa?
Jego działanie zależy od argumentu o nazwie długość_drostka, który określa długość przedrostka lub sufiksu. Wartością domyślną jest 3. Ale w jaki sposób rozróżnia, czy klasa AffixTagger ma przedrostek czy sufiks słowa?
affix_length=positive - Jeśli wartość affix_lenght jest dodatnia, oznacza to, że klasa AffixTagger nauczy się przedrostków słów.
affix_length=negative - Jeśli wartość affix_lenght jest ujemna, oznacza to, że klasa AffixTagger nauczy się przyrostków słów.
Aby było to bardziej zrozumiałe, w poniższym przykładzie będziemy używać klasy AffixTagger na tagowanych zdaniach banku drzewa.
Example
In this example, AffixTagger will learn word’s prefix because we are not specifying any value for affix_length argument. The argument will take default value 3 −
from nltk.tag import AffixTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
Prefix_tagger = AffixTagger(train_sentences)
test_sentences = treebank.tagged_sents()[1500:]
Prefix_tagger.evaluate(test_sentences)
Output
0.2800492099250667
Let us see in the example below what will be the accuracy when we provide value 4 to affix_length argument −
from nltk.tag import AffixTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
Prefix_tagger = AffixTagger(train_sentences, affix_length=4 )
test_sentences = treebank.tagged_sents()[1500:]
Prefix_tagger.evaluate(test_sentences)
Output
0.18154947354966527
Example
In this example, AffixTagger will learn word’s suffix because we will specify negative value for affix_length argument.
from nltk.tag import AffixTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
Suffix_tagger = AffixTagger(train_sentences, affix_length = -3)
test_sentences = treebank.tagged_sents()[1500:]
Suffix_tagger.evaluate(test_sentences)
Output
0.2800492099250667
Brill Tagger
Brill Tagger is a transformation-based tagger. NLTK provides BrillTagger class which is the first tagger that is not a subclass of SequentialBackoffTagger. Opposite to it, a series of rules to correct the results of an initial tagger is used by BrillTagger.
How does it work?
To train a BrillTagger class using BrillTaggerTrainer we define the following function −
def train_brill_tagger(initial_tagger, train_sentences, **kwargs) −
templates = [
brill.Template(brill.Pos([-1])),
brill.Template(brill.Pos([1])),
brill.Template(brill.Pos([-2])),
brill.Template(brill.Pos([2])),
brill.Template(brill.Pos([-2, -1])),
brill.Template(brill.Pos([1, 2])),
brill.Template(brill.Pos([-3, -2, -1])),
brill.Template(brill.Pos([1, 2, 3])),
brill.Template(brill.Pos([-1]), brill.Pos([1])),
brill.Template(brill.Word([-1])),
brill.Template(brill.Word([1])),
brill.Template(brill.Word([-2])),
brill.Template(brill.Word([2])),
brill.Template(brill.Word([-2, -1])),
brill.Template(brill.Word([1, 2])),
brill.Template(brill.Word([-3, -2, -1])),
brill.Template(brill.Word([1, 2, 3])),
brill.Template(brill.Word([-1]), brill.Word([1])),
]
trainer = brill_trainer.BrillTaggerTrainer(initial_tagger, templates, deterministic=True)
return trainer.train(train_sentences, **kwargs)
As we can see, this function requires initial_tagger and train_sentences. It takes an initial_tagger argument and a list of templates, which implements the BrillTemplate interface. The BrillTemplate interface is found in the nltk.tbl.template module. One of such implementation is brill.Template class.
The main role of transformation-based tagger is to generate transformation rules that correct the initial tagger’s output to be more in-line with the training sentences. Let us see the workflow below −
Example
For this example, we will be using combine_tagger which we created while combing taggers (in the previous recipe) from a backoff chain of NgramTagger classes, as initial_tagger. First, let us evaluate the result using Combine.tagger and then use that as initial_tagger to train brill tagger.
from tagger_util import backoff_tagger
from nltk.tag import UnigramTagger
from nltk.tag import BigramTagger
from nltk.tag import TrigramTagger
from nltk.tag import DefaultTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
back_tagger = DefaultTagger('NN')
Combine_tagger = backoff_tagger(
train_sentences, [UnigramTagger, BigramTagger, TrigramTagger], backoff = back_tagger
)
test_sentences = treebank.tagged_sents()[1500:]
Combine_tagger.evaluate(test_sentences)
Output
0.9234530029238365
Now, let us see the evaluation result when Combine_tagger is used as initial_tagger to train brill tagger −
from tagger_util import train_brill_tagger
brill_tagger = train_brill_tagger(combine_tagger, train_sentences)
brill_tagger.evaluate(test_sentences)
Output
0.9246832510505041
We can notice that BrillTagger class has slight increased accuracy over the Combine_tagger.
Complete implementation example
from tagger_util import backoff_tagger
from nltk.tag import UnigramTagger
from nltk.tag import BigramTagger
from nltk.tag import TrigramTagger
from nltk.tag import DefaultTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
back_tagger = DefaultTagger('NN')
Combine_tagger = backoff_tagger(train_sentences,
[UnigramTagger, BigramTagger, TrigramTagger], backoff = back_tagger)
test_sentences = treebank.tagged_sents()[1500:]
Combine_tagger.evaluate(test_sentences)
from tagger_util import train_brill_tagger
brill_tagger = train_brill_tagger(combine_tagger, train_sentences)
brill_tagger.evaluate(test_sentences)
Output
0.9234530029238365
0.9246832510505041
TnT Tagger
TnT Tagger, stands for Trigrams’nTags, is a statistical tagger which is based on second order Markov models.
How does it work?
We can understand the working of TnT tagger with the help of following steps −
First based on training data, TnT tegger maintains several internal FreqDist and ConditionalFreqDist instances.
After that unigrams, bigrams and trigrams will be counted by these frequency distributions.
Now, during tagging, by using frequencies, it will calculate the probabilities of possible tags for each word.
That’s why instead of constructing a backoff chain of NgramTagger, it uses all the ngram models together to choose the best tag for each word. Let us evaluate the accuracy with TnT tagger in the following example −
from nltk.tag import tnt
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
tnt_tagger = tnt.TnT()
tnt_tagger.train(train_sentences)
test_sentences = treebank.tagged_sents()[1500:]
tnt_tagger.evaluate(test_sentences)
Output
0.9165508316157791
We have a slight less accuracy than we got with Brill Tagger.
Please note that we need to call train() before evaluate() otherwise we will get 0% accuracy.
Parsing and its relevance in NLP
The word ‘Parsing’ whose origin is from Latin word ‘pars’ (which means ‘part’), is used to draw exact meaning or dictionary meaning from the text. It is also called Syntactic analysis or syntax analysis. Comparing the rules of formal grammar, syntax analysis checks the text for meaningfulness. The sentence like “Give me hot ice-cream”, for example, would be rejected by parser or syntactic analyzer.
In this sense, we can define parsing or syntactic analysis or syntax analysis as follows −
It may be defined as the process of analyzing the strings of symbols in natural language conforming to the rules of formal grammar.
We can understand the relevance of parsing in NLP with the help of following points −
Parser is used to report any syntax error.
It helps to recover from commonly occurring error so that the processing of the remainder of program can be continued.
Parse tree is created with the help of a parser.
Parser is used to create symbol table, which plays an important role in NLP.
Parser is also used to produce intermediate representations (IR).
Deep Vs Shallow Parsing
Deep Parsing | Shallow Parsing |
---|---|
In deep parsing, the search strategy will give a complete syntactic structure to a sentence. | It is the task of parsing a limited part of the syntactic information from the given task. |
It is suitable for complex NLP applications. | It can be used for less complex NLP applications. |
Dialogue systems and summarization are the examples of NLP applications where deep parsing is used. | Information extraction and text mining are the examples of NLP applications where deep parsing is used. |
It is also called full parsing. | It is also called chunking. |
Various types of parsers
As discussed, a parser is basically a procedural interpretation of grammar. It finds an optimal tree for the given sentence after searching through the space of a variety of trees. Let us see some of the available parsers below −
Recursive descent parser
Recursive descent parsing is one of the most straightforward forms of parsing. Following are some important points about recursive descent parser −
It follows a top down process.
It attempts to verify that the syntax of the input stream is correct or not.
It reads the input sentence from left to right.
One necessary operation for recursive descent parser is to read characters from the input stream and matching them with the terminals from the grammar.
Shift-reduce parser
Following are some important points about shift-reduce parser −
It follows a simple bottom-up process.
It tries to find a sequence of words and phrases that correspond to the right-hand side of a grammar production and replaces them with the left-hand side of the production.
The above attempt to find a sequence of word continues until the whole sentence is reduced.
In other simple words, shift-reduce parser starts with the input symbol and tries to construct the parser tree up to the start symbol.
Chart parser
Following are some important points about chart parser −
It is mainly useful or suitable for ambiguous grammars, including grammars of natural languages.
It applies dynamic programing to the parsing problems.
Because of dynamic programing, partial hypothesized results are stored in a structure called a ‘chart’.
The ‘chart’ can also be re-used.
Regexp parser
Regexp parsing is one of the mostly used parsing technique. Following are some important points about Regexp parser −
As the name implies, it uses a regular expression defined in the form of grammar on top of a POS-tagged string.
It basically uses these regular expressions to parse the input sentences and generate a parse tree out of this.
Example
Following is a working example of Regexp Parser −
import nltk
sentence = [
("a", "DT"),
("clever", "JJ"),
("fox","NN"),
("was","VBP"),
("jumping","VBP"),
("over","IN"),
("the","DT"),
("wall","NN")
]
grammar = "NP:{<DT>?<JJ>*<NN>}"
Reg_parser = nltk.RegexpParser(grammar)
Reg_parser.parse(sentence)
Output = Reg_parser.parse(sentence)
Output.draw()
Wynik
Analiza zależności
Analiza zależności (DP), nowoczesny mechanizm analizy, którego główną koncepcją jest to, że każda jednostka językowa, tj. Słowa, są ze sobą powiązane poprzez bezpośrednie łącze. Te bezpośrednie linki są w rzeczywistości‘dependencies’w języku. Na przykład poniższy diagram przedstawia gramatykę zależności dla zdania“John can hit the ball”.
Pakiet NLTK
Mamy dwa sposoby wykonywania analizy zależności z NLTK -
Parser zależności probabilistycznej, rzutowej
To pierwszy sposób, w jaki możemy przeprowadzić analizę zależności za pomocą NLTK. Ale ten parser ma ograniczenie uczenia się z ograniczonym zestawem danych uczących.
Parser Stanford
To kolejny sposób, w jaki możemy przeprowadzić analizę zależności za pomocą NLTK. Stanford parser to najnowocześniejszy parser zależności. NLTK ma otokę. Aby z niego skorzystać, musimy pobrać następujące dwie rzeczy -
Parser Stanford CoreNLP .
Model językowy dla żądanego języka. Na przykład model języka angielskiego.
Przykład
Po pobraniu modelu możemy go używać za pośrednictwem NLTK w następujący sposób -
from nltk.parse.stanford import StanfordDependencyParser
path_jar = 'path_to/stanford-parser-full-2014-08-27/stanford-parser.jar'
path_models_jar = 'path_to/stanford-parser-full-2014-08-27/stanford-parser-3.4.1-models.jar'
dep_parser = StanfordDependencyParser(
path_to_jar = path_jar, path_to_models_jar = path_models_jar
)
result = dep_parser.raw_parse('I shot an elephant in my sleep')
depndency = result.next()
list(dependency.triples())
Wynik
[
((u'shot', u'VBD'), u'nsubj', (u'I', u'PRP')),
((u'shot', u'VBD'), u'dobj', (u'elephant', u'NN')),
((u'elephant', u'NN'), u'det', (u'an', u'DT')),
((u'shot', u'VBD'), u'prep', (u'in', u'IN')),
((u'in', u'IN'), u'pobj', (u'sleep', u'NN')),
((u'sleep', u'NN'), u'poss', (u'my', u'PRP$'))
]
Co to jest Chunking?
Chunking, jeden z ważnych procesów w przetwarzaniu języka naturalnego, służy do identyfikacji części mowy (POS) i krótkich fraz. Innymi prostymi słowami, dzięki fragmentacji możemy uzyskać strukturę zdania. Nazywa się to równieżpartial parsing.
Wzory kawałków i szczeliny
Chunk patternsto wzorce znaczników części mowy (POS), które definiują, jakiego rodzaju słowa składają się na fragment. Możemy definiować wzorce porcji za pomocą zmodyfikowanych wyrażeń regularnych.
Co więcej, możemy również zdefiniować wzorce dla rodzaju słów, które nie powinny znajdować się w kawałku, a te nieposortowane słowa są znane jako chinks.
Przykład realizacji
W poniższym przykładzie wraz z wynikiem parsowania zdania “the book has many chapters”, istnieje gramatyka wyrażeń rzeczownikowych, która łączy w sobie zarówno fragment, jak i wzór szczeliny -
import nltk
sentence = [
("the", "DT"),
("book", "NN"),
("has","VBZ"),
("many","JJ"),
("chapters","NNS")
]
chunker = nltk.RegexpParser(
r'''
NP:{<DT><NN.*><.*>*<NN.*>}
}<VB.*>{
'''
)
chunker.parse(sentence)
Output = chunker.parse(sentence)
Output.draw()
Wynik
Jak widać powyżej, wzorzec określania fragmentu polega na użyciu nawiasów klamrowych w następujący sposób -
{<DT><NN>}
Aby określić szczelinę, możemy odwrócić klamry w następujący sposób -
}<VB>{.
Teraz, dla określonego typu frazy, reguły te można połączyć w jedną gramatykę.
Wydobywanie informacji
Przeszliśmy przez taggery i parsery, których można użyć do zbudowania silnika ekstrakcji informacji. Przyjrzyjmy się podstawowemu procesowi wydobywania informacji -
Ekstrakcja informacji ma wiele zastosowań, w tym -
- Business Intelligence
- Wznów zbiory
- Analiza mediów
- Wykrywanie nastrojów
- Wyszukiwanie patentów
- Skanowanie poczty e-mail
Rozpoznawanie nazwanych podmiotów (NER)
Rozpoznawanie nazwanych jednostek (NER) jest w rzeczywistości sposobem na wyodrębnienie niektórych najpopularniejszych jednostek, takich jak nazwy, organizacje, lokalizacja itp. Zobaczmy przykład, który obejmował wszystkie etapy przetwarzania wstępnego, takie jak tokenizacja zdań, tagowanie POS, fragmentowanie, NER, i podąża za rurociągiem przedstawionym na powyższym rysunku.
Przykład
Import nltk
file = open (
# provide here the absolute path for the file of text for which we want NER
)
data_text = file.read()
sentences = nltk.sent_tokenize(data_text)
tokenized_sentences = [nltk.word_tokenize(sentence) for sentence in sentences]
tagged_sentences = [nltk.pos_tag(sentence) for sentence in tokenized_sentences]
for sent in tagged_sentences:
print nltk.ne_chunk(sent)
Niektóre ze zmodyfikowanych nazwanych jednostek rozpoznawania (NER) mogą być również używane do wyodrębniania jednostek, takich jak nazwy produktów, jednostki biomedyczne, marka i wiele innych.
Ekstrakcja relacji
Ekstrakcja relacji, inna powszechnie stosowana operacja wyodrębniania informacji, to proces wyodrębniania różnych relacji między różnymi podmiotami. Mogą istnieć różne relacje, takie jak dziedziczenie, synonimy, analogiczne itp., Których definicja zależy od potrzeb informacyjnych. Na przykład, załóżmy, że jeśli chcemy szukać zapisu książki, to autorstwo będzie zależało od nazwiska autora i tytułu książki.
Przykład
W poniższym przykładzie używamy tego samego potoku IE, jak pokazano na powyższym diagramie, którego używaliśmy do relacji nazwanej jednostki (NER) i rozszerzamy go o wzorzec relacji oparty na znacznikach NER.
import nltk
import re
IN = re.compile(r'.*\bin\b(?!\b.+ing)')
for doc in nltk.corpus.ieer.parsed_docs('NYT_19980315'):
for rel in nltk.sem.extract_rels('ORG', 'LOC', doc, corpus = 'ieer',
pattern = IN):
print(nltk.sem.rtuple(rel))
Wynik
[ORG: 'WHYY'] 'in' [LOC: 'Philadelphia']
[ORG: 'McGlashan & Sarrail'] 'firm in' [LOC: 'San Mateo']
[ORG: 'Freedom Forum'] 'in' [LOC: 'Arlington']
[ORG: 'Brookings Institution'] ', the research group in' [LOC: 'Washington']
[ORG: 'Idealab'] ', a self-described business incubator based in' [LOC: 'Los Angeles']
[ORG: 'Open Text'] ', based in' [LOC: 'Waterloo']
[ORG: 'WGBH'] 'in' [LOC: 'Boston']
[ORG: 'Bastille Opera'] 'in' [LOC: 'Paris']
[ORG: 'Omnicom'] 'in' [LOC: 'New York']
[ORG: 'DDB Needham'] 'in' [LOC: 'New York']
[ORG: 'Kaplan Thaler Group'] 'in' [LOC: 'New York']
[ORG: 'BBDO South'] 'in' [LOC: 'Atlanta']
[ORG: 'Georgia-Pacific'] 'in' [LOC: 'Atlanta']
W powyższym kodzie użyliśmy wbudowanego korpusu o nazwie ieer. W tym korpusie zdania są oznaczone do relacji nazwanych jednostek (NER). Tutaj musimy tylko określić wzorzec relacji, który chcemy, i rodzaj NER, który chcemy, aby relacja zdefiniowała. W naszym przykładzie zdefiniowaliśmy relację między organizacją a lokalizacją. Wyodrębniliśmy wszystkie kombinacje tych wzorów.
Po co przekształcać kawałki?
Do tej pory mamy fragmenty lub frazy ze zdań, ale co mamy z nimi zrobić. Jednym z ważnych zadań jest ich przekształcenie. Ale dlaczego? Ma to na celu:
- poprawka gramatyczna i
- przestawianie fraz
Filtrowanie nieistotnych / bezużytecznych słów
Załóżmy, że jeśli chcesz ocenić znaczenie frazy, istnieje wiele powszechnie używanych słów, takich jak „the”, „a”, które są nieistotne lub bezużyteczne. Na przykład zobacz następującą frazę -
'Film był dobry'.
Tutaj najważniejsze słowa to „film” i „dobry”. Innymi słowy, „to” i „było” są bezużyteczne lub nieistotne. To dlatego, że bez nich również możemy uzyskać to samo znaczenie wyrażenia. 'Dobry film'.
Z poniższego przepisu na Pythona dowiemy się, jak usuwać niepotrzebne / nieistotne słowa i zachować znaczące słowa za pomocą tagów POS.
Przykład
Po pierwsze, przeglądając treebankkorpusu odrzucanych słów musimy zdecydować, które znaczniki części mowy są istotne, a które nie. Spójrzmy na poniższą tabelę nieistotnych słów i tagów -
Słowo | Etykietka |
---|---|
za | DT |
Wszystko | PDT |
Na | DT |
I | CC |
Lub | CC |
Że | WDT |
Plik | DT |
Z powyższej tabeli widzimy inne niż CC, wszystkie pozostałe tagi kończą się na DT, co oznacza, że możemy odfiltrować nieistotne słowa, patrząc na sufiks tagu.
W tym przykładzie użyjemy funkcji o nazwie filter()która pobiera pojedynczą porcję i zwraca nową porcję bez żadnych nieistotnych oznakowanych słów. Ta funkcja odfiltrowuje wszystkie tagi, które kończą się na DT lub CC.
Przykład
import nltk
def filter(chunk, tag_suffixes=['DT', 'CC']):
significant = []
for word, tag in chunk:
ok = True
for suffix in tag_suffixes:
if tag.endswith(suffix):
ok = False
break
if ok:
significant.append((word, tag))
return (significant)
Teraz użyjmy tej funkcji filter () w naszym przepisie w Pythonie, aby usunąć nieistotne słowa -
from chunk_parse import filter
filter([('the', 'DT'),('good', 'JJ'),('movie', 'NN')])
Wynik
[('good', 'JJ'), ('movie', 'NN')]
Korekta czasownika
Wiele razy w prawdziwym języku widzimy nieprawidłowe formy czasowników. Na przykład „wszystko w porządku?” nie jest poprawne. Forma czasownika nie jest poprawna w tym zdaniu. Zdanie powinno brzmieć „wszystko w porządku?” NLTK zapewnia nam sposób na poprawienie takich błędów poprzez tworzenie odwzorowań korekcji czasowników. Te odwzorowania korekcji są używane w zależności od tego, czy w porcji znajduje się rzeczownik w liczbie mnogiej czy pojedynczej.
Przykład
Aby zaimplementować przepis w Pythonie, musimy najpierw zdefiniować odwzorowania korekcji czasowników. Utwórzmy dwa odwzorowania w następujący sposób -
Plural to Singular mappings
plural= {
('is', 'VBZ'): ('are', 'VBP'),
('was', 'VBD'): ('were', 'VBD')
}
Singular to Plural mappings
singular = {
('are', 'VBP'): ('is', 'VBZ'),
('were', 'VBD'): ('was', 'VBD')
}
Jak widać powyżej, każde odwzorowanie ma oznaczony czasownik, który odwzorowuje inny oznaczony czasownik. Początkowe mapowania w naszym przykładzie obejmują podstawy mapowaniais to are, was to were, i wzajemnie.
Następnie zdefiniujemy funkcję o nazwie verbs(), w którym można przekazać szczelinę z nieprawidłową formą czasownika i otrzymać z powrotem poprawiony fragment. Aby to zrobić,verb() funkcja używa funkcji pomocniczej o nazwie index_chunk() która przeszuka porcję pod kątem pozycji pierwszego słowa ze znacznikiem.
Zobaczmy te funkcje -
def index_chunk(chunk, pred, start = 0, step = 1):
l = len(chunk)
end = l if step > 0 else -1
for i in range(start, end, step):
if pred(chunk[i]):
return i
return None
def tag_startswith(prefix):
def f(wt):
return wt[1].startswith(prefix)
return f
def verbs(chunk):
vbidx = index_chunk(chunk, tag_startswith('VB'))
if vbidx is None:
return chunk
verb, vbtag = chunk[vbidx]
nnpred = tag_startswith('NN')
nnidx = index_chunk(chunk, nnpred, start = vbidx+1)
if nnidx is None:
nnidx = index_chunk(chunk, nnpred, start = vbidx-1, step = -1)
if nnidx is None:
return chunk
noun, nntag = chunk[nnidx]
if nntag.endswith('S'):
chunk[vbidx] = plural.get((verb, vbtag), (verb, vbtag))
else:
chunk[vbidx] = singular.get((verb, vbtag), (verb, vbtag))
return chunk
Zapisz te funkcje w pliku Python w katalogu lokalnym, w którym jest zainstalowany Python lub Anaconda, i uruchom go. Zapisałem to jakoverbcorrect.py.
A teraz zadzwońmy verbs() funkcja w oznaczonym punkcie sprzedaży is you fine kawałek -
from verbcorrect import verbs
verbs([('is', 'VBZ'), ('you', 'PRP$'), ('fine', 'VBG')])
Wynik
[('are', 'VBP'), ('you', 'PRP$'), ('fine','VBG')]
Eliminacja biernego głosu ze zwrotów
Kolejnym przydatnym zadaniem jest wyeliminowanie biernego głosu ze zwrotów. Można to zrobić za pomocą zamiany słów wokół czasownika. Na przykład,‘the tutorial was great’ można przekształcić w ‘the great tutorial’.
Przykład
Aby to osiągnąć, definiujemy funkcję o nazwie eliminate_passive()która zamieni prawą stronę fragmentu na lewą, używając czasownika jako punktu obrotu. Aby znaleźć czasownik do obrócenia, użyje równieżindex_chunk() funkcja zdefiniowana powyżej.
def eliminate_passive(chunk):
def vbpred(wt):
word, tag = wt
return tag != 'VBG' and tag.startswith('VB') and len(tag) > 2
vbidx = index_chunk(chunk, vbpred)
if vbidx is None:
return chunk
return chunk[vbidx+1:] + chunk[:vbidx]
A teraz zadzwońmy eliminate_passive() funkcja w oznaczonym punkcie sprzedaży the tutorial was great kawałek -
from passiveverb import eliminate_passive
eliminate_passive(
[
('the', 'DT'), ('tutorial', 'NN'), ('was', 'VBD'), ('great', 'JJ')
]
)
Wynik
[('great', 'JJ'), ('the', 'DT'), ('tutorial', 'NN')]
Zamiana rzeczowników kardynałów
Jak wiemy, kardynalne słowo, takie jak 5, jest oznaczone jako CD w kawałku. Te kardynalne słowa często występują przed rzeczownikiem lub po nim, ale w celu normalizacji dobrze jest umieścić je zawsze przed rzeczownikiem. Na przykład dataJanuary 5 można zapisać jako 5 January. Zrozummy to na następującym przykładzie.
Przykład
Aby to osiągnąć, definiujemy funkcję o nazwie swapping_cardinals()który zamieni każdy kardynał występujący bezpośrednio po rzeczowniku na rzeczownik. Dzięki temu kardynał wystąpi bezpośrednio przed rzeczownikiem. Aby dokonać porównania równości z danym znacznikiem, używa funkcji pomocniczej, którą nazwaliśmy jakotag_eql().
def tag_eql(tag):
def f(wt):
return wt[1] == tag
return f
Teraz możemy zdefiniować swapping_cardinals () -
def swapping_cardinals (chunk):
cdidx = index_chunk(chunk, tag_eql('CD'))
if not cdidx or not chunk[cdidx-1][1].startswith('NN'):
return chunk
noun, nntag = chunk[cdidx-1]
chunk[cdidx-1] = chunk[cdidx]
chunk[cdidx] = noun, nntag
return chunk
A teraz zadzwońmy swapping_cardinals() funkcjonować na randce “January 5” -
from Cardinals import swapping_cardinals()
swapping_cardinals([('Janaury', 'NNP'), ('5', 'CD')])
Wynik
[('10', 'CD'), ('January', 'NNP')]
10 January
Oto dwa powody, dla których warto przekształcić drzewa -
- Aby zmodyfikować drzewo głębokiej analizy i
- Aby spłaszczyć głębokie drzewa analizy
Konwertowanie drzewa lub poddrzewa na zdanie
Pierwszym przepisem, który tutaj omówimy, jest konwersja drzewa lub poddrzewa z powrotem do zdania lub fragmentu łańcucha. To bardzo proste, zobaczmy na poniższym przykładzie -
Przykład
from nltk.corpus import treebank_chunk
tree = treebank_chunk.chunked_sents()[2]
' '.join([w for w, t in tree.leaves()])
Wynik
'Rudolph Agnew , 55 years old and former chairman of Consolidated Gold Fields
PLC , was named a nonexecutive director of this British industrial
conglomerate .'
Głębokie spłaszczenie drzewa
Głębokie drzewa zagnieżdżonych fraz nie mogą być używane do trenowania fragmentu, dlatego musimy je spłaszczyć przed użyciem. W poniższym przykładzie użyjemy trzeciego parsowanego zdania, które jest głębokim drzewem zagnieżdżonych fraz, ztreebank ciało.
Przykład
Aby to osiągnąć, definiujemy funkcję o nazwie deeptree_flat()to zajmie jedno drzewo i zwróci nowe drzewo, które zachowuje tylko drzewa najniższego poziomu. Aby wykonać większość pracy, używa funkcji pomocniczej, którą nazwaliśmy jakochildtree_flat().
from nltk.tree import Tree
def childtree_flat(trees):
children = []
for t in trees:
if t.height() < 3:
children.extend(t.pos())
elif t.height() == 3:
children.append(Tree(t.label(), t.pos()))
else:
children.extend(flatten_childtrees([c for c in t]))
return children
def deeptree_flat(tree):
return Tree(tree.label(), flatten_childtrees([c for c in tree]))
A teraz zadzwońmy deeptree_flat() funkcja na trzecim zdaniu parsowanym, które jest głębokim drzewem zagnieżdżonych fraz, z treebankciało. Zapisaliśmy te funkcje w pliku o nazwie deeptree.py.
from deeptree import deeptree_flat
from nltk.corpus import treebank
deeptree_flat(treebank.parsed_sents()[2])
Wynik
Tree('S', [Tree('NP', [('Rudolph', 'NNP'), ('Agnew', 'NNP')]),
(',', ','), Tree('NP', [('55', 'CD'),
('years', 'NNS')]), ('old', 'JJ'), ('and', 'CC'),
Tree('NP', [('former', 'JJ'),
('chairman', 'NN')]), ('of', 'IN'), Tree('NP', [('Consolidated', 'NNP'),
('Gold', 'NNP'), ('Fields', 'NNP'), ('PLC',
'NNP')]), (',', ','), ('was', 'VBD'),
('named', 'VBN'), Tree('NP-SBJ', [('*-1', '-NONE-')]),
Tree('NP', [('a', 'DT'), ('nonexecutive', 'JJ'), ('director', 'NN')]),
('of', 'IN'), Tree('NP',
[('this', 'DT'), ('British', 'JJ'),
('industrial', 'JJ'), ('conglomerate', 'NN')]), ('.', '.')])
Budynek Shallow tree
W poprzedniej sekcji spłaszczamy głębokie drzewo zagnieżdżonych fraz, zachowując tylko poddrzewa najniższego poziomu. W tej sekcji zachowamy tylko najwyższe poddrzewa, tj. Zbudujemy płytkie drzewo. W poniższym przykładzie użyjemy trzeciego parsowanego zdania, które jest głębokim drzewem zagnieżdżonych fraz ztreebank ciało.
Przykład
Aby to osiągnąć, definiujemy funkcję o nazwie tree_shallow() to wyeliminuje wszystkie zagnieżdżone poddrzewa, zachowując tylko etykiety najwyższych poddrzew.
from nltk.tree import Tree
def tree_shallow(tree):
children = []
for t in tree:
if t.height() < 3:
children.extend(t.pos())
else:
children.append(Tree(t.label(), t.pos()))
return Tree(tree.label(), children)
A teraz zadzwońmy tree_shallow()Funkcja na 3 rd analizowany zdaniu, które jest głęboko drzewo wyrażeń zagnieżdżonych, odtreebankciało. Zapisaliśmy te funkcje w pliku o nazwie shallowtree.py.
from shallowtree import shallow_tree
from nltk.corpus import treebank
tree_shallow(treebank.parsed_sents()[2])
Wynik
Tree('S', [Tree('NP-SBJ-1', [('Rudolph', 'NNP'), ('Agnew', 'NNP'), (',', ','),
('55', 'CD'), ('years', 'NNS'), ('old', 'JJ'), ('and', 'CC'),
('former', 'JJ'), ('chairman', 'NN'), ('of', 'IN'), ('Consolidated', 'NNP'),
('Gold', 'NNP'), ('Fields', 'NNP'), ('PLC', 'NNP'), (',', ',')]),
Tree('VP', [('was', 'VBD'), ('named', 'VBN'), ('*-1', '-NONE-'), ('a', 'DT'),
('nonexecutive', 'JJ'), ('director', 'NN'), ('of', 'IN'), ('this', 'DT'),
('British', 'JJ'), ('industrial', 'JJ'), ('conglomerate', 'NN')]), ('.', '.')])
Różnicę możemy zobaczyć na podstawie wysokości drzew -
from nltk.corpus import treebank
tree_shallow(treebank.parsed_sents()[2]).height()
Wynik
3
from nltk.corpus import treebank
treebank.parsed_sents()[2].height()
Wynik
9
Konwersja etykiet drzew
W drzewach parsowych występuje różnorodność Treetypy etykiet, których nie ma w drzewach porcji. Ale podczas używania drzewa parsowania do trenowania fragmentu chcielibyśmy zmniejszyć tę różnorodność, konwertując niektóre etykiety drzewa na bardziej popularne typy etykiet. Na przykład mamy dwie alternatywne poddrzewa NP, mianowicie NP-SBL i NP-TMP. Możemy zamienić oba z nich na NP. Zobaczmy, jak to zrobić w poniższym przykładzie.
Przykład
Aby to osiągnąć, definiujemy funkcję o nazwie tree_convert() który przyjmuje następujące dwa argumenty -
- Drzewo do konwersji
- Mapowanie konwersji etykiet
Ta funkcja zwróci nowe drzewo ze wszystkimi pasującymi etykietami zamienionymi na podstawie wartości w mapowaniu.
from nltk.tree import Tree
def tree_convert(tree, mapping):
children = []
for t in tree:
if isinstance(t, Tree):
children.append(convert_tree_labels(t, mapping))
else:
children.append(t)
label = mapping.get(tree.label(), tree.label())
return Tree(label, children)
A teraz zadzwońmy tree_convert() funkcja na trzecim zdaniu parsowanym, które jest głębokim drzewem zagnieżdżonych fraz, z treebankciało. Zapisaliśmy te funkcje w pliku o nazwieconverttree.py.
from converttree import tree_convert
from nltk.corpus import treebank
mapping = {'NP-SBJ': 'NP', 'NP-TMP': 'NP'}
convert_tree_labels(treebank.parsed_sents()[2], mapping)
Wynik
Tree('S', [Tree('NP-SBJ-1', [Tree('NP', [Tree('NNP', ['Rudolph']),
Tree('NNP', ['Agnew'])]), Tree(',', [',']),
Tree('UCP', [Tree('ADJP', [Tree('NP', [Tree('CD', ['55']),
Tree('NNS', ['years'])]),
Tree('JJ', ['old'])]), Tree('CC', ['and']),
Tree('NP', [Tree('NP', [Tree('JJ', ['former']),
Tree('NN', ['chairman'])]), Tree('PP', [Tree('IN', ['of']),
Tree('NP', [Tree('NNP', ['Consolidated']),
Tree('NNP', ['Gold']), Tree('NNP', ['Fields']),
Tree('NNP', ['PLC'])])])])]), Tree(',', [','])]),
Tree('VP', [Tree('VBD', ['was']),Tree('VP', [Tree('VBN', ['named']),
Tree('S', [Tree('NP', [Tree('-NONE-', ['*-1'])]),
Tree('NP-PRD', [Tree('NP', [Tree('DT', ['a']),
Tree('JJ', ['nonexecutive']), Tree('NN', ['director'])]),
Tree('PP', [Tree('IN', ['of']), Tree('NP',
[Tree('DT', ['this']), Tree('JJ', ['British']), Tree('JJ', ['industrial']),
Tree('NN', ['conglomerate'])])])])])])]), Tree('.', ['.'])])
Co to jest klasyfikacja tekstu?
Klasyfikacja tekstu, jak sama nazwa wskazuje, jest sposobem klasyfikowania fragmentów tekstu lub dokumentów. Ale tutaj pojawia się pytanie, dlaczego musimy używać klasyfikatorów tekstu? Po zbadaniu użycia słowa w dokumencie lub fragmencie tekstu klasyfikatorzy będą mogli zdecydować, jaką etykietę klasy należy mu przypisać.
Klasyfikator binarny
Jak sama nazwa wskazuje, klasyfikator binarny zdecyduje między dwiema etykietami. Na przykład pozytywne lub negatywne. W tym przypadku fragment tekstu lub dokumentu może być jedną lub drugą etykietą, ale nie obydwoma.
Klasyfikator z wieloma etykietami
W przeciwieństwie do klasyfikatora binarnego, klasyfikator z wieloma etykietami może przypisać jedną lub więcej etykiet do fragmentu tekstu lub dokumentu.
Zestaw funkcji Labeled Vs Unlabeled
Mapowanie klucz-wartość nazw funkcji do wartości funkcji nazywa się zestawem funkcji. Oznaczone zestawy funkcji lub dane szkoleniowe są bardzo ważne dla uczenia klasyfikacji, aby później można było sklasyfikować zestaw funkcji bez etykiety.
Zestaw funkcji oznaczonych | Zestaw funkcji bez etykiety |
---|---|
To jest krotka, która wygląda jak (wyczyn, etykieta). | To samo w sobie wyczyn. |
Jest to instancja ze znaną etykietą klasy. | Bez powiązanej etykiety możemy to nazwać instancją. |
Służy do uczenia algorytmu klasyfikacji. | Po przeszkoleniu algorytm klasyfikacji może sklasyfikować zestaw funkcji bez etykiety. |
Wyodrębnianie elementów tekstowych
Wyodrębnianie cech tekstu, jak sama nazwa wskazuje, jest procesem przekształcania listy słów w zestaw funkcji, których może używać klasyfikator. Musimy przekształcić nasz tekst w‘dict’ style, ponieważ oczekuje się zestawu narzędzi języka naturalnego (NLTK) ‘dict’ zestawy funkcji stylu.
Model Bag of Words (BoW)
BoW, jeden z najprostszych modeli w NLP, służy do wyodrębniania cech z fragmentu tekstu lub dokumentu, tak aby można go było wykorzystać w modelowaniu w algorytmach ML. Zasadniczo konstruuje zestaw funkcji obecności słów ze wszystkich słów instancji. Koncepcja tej metody polega na tym, że nie dba o to, ile razy występuje słowo lub kolejność słów, dba tylko o to, czy słowo jest obecne na liście słów, czy nie.
Przykład
W tym przykładzie zdefiniujemy funkcję o nazwie bow () -
def bow(words):
return dict([(word, True) for word in words])
A teraz zadzwońmy bow()działają na słowach. Zapisaliśmy te funkcje w pliku o nazwie bagwords.py.
from bagwords import bow
bow(['we', 'are', 'using', 'tutorialspoint'])
Wynik
{'we': True, 'are': True, 'using': True, 'tutorialspoint': True}
Klasyfikatory szkolenia
W poprzednich sekcjach dowiedzieliśmy się, jak wyodrębnić cechy z tekstu. Więc teraz możemy wytrenować klasyfikator. Pierwszym i najłatwiejszym klasyfikatorem jestNaiveBayesClassifier klasa.
Naiwny klasyfikator Bayesa
Aby przewidzieć prawdopodobieństwo, że dany zestaw cech należy do określonej etykiety, używa twierdzenia Bayesa. Wzór twierdzenia Bayesa jest następujący.
$$P(A|B)=\frac{P(B|A)P(A)}{P(B)}$$Tutaj,
P(A|B) - Nazywa się je również prawdopodobieństwem późniejszym, tj. Prawdopodobieństwem wystąpienia pierwszego zdarzenia, tj. A, przy założeniu, że wystąpiło drugie zdarzenie, tj. B.
P(B|A) - Jest to prawdopodobieństwo drugiego zdarzenia, tj. B, które wystąpi po pierwszym zdarzeniu, tj. A.
P(A), P(B) - Nazywa się to również prawdopodobieństwem wcześniejszym, tj. Prawdopodobieństwem wystąpienia pierwszego zdarzenia, tj. A lub drugiego zdarzenia, tj. B.
Aby wytrenować klasyfikator Naïve Bayes, będziemy używać movie_reviewskorpus z NLTK. Ten korpus ma dwie kategorie tekstu, a mianowicie:pos i neg. Te kategorie sprawiają, że szkolony na nich klasyfikator jest klasyfikatorem binarnym. Każdy plik w korpusie składa się z dwóch, jeden to pozytywna recenzja filmu, a drugi to negatywna recenzja filmu. W naszym przykładzie użyjemy każdego pliku jako pojedynczej instancji zarówno do uczenia, jak i testowania klasyfikatora.
Przykład
Do klasyfikatora szkoleniowego potrzebujemy listy oznaczonych zestawów funkcji, która będzie miała postać [(featureset, label)]. Tutajfeatureset zmienna to dict a etykieta to znana etykieta klasy dla featureset. Stworzymy funkcję o nazwielabel_corpus() który weźmie korpus o nazwie movie_reviewsa także funkcję o nazwie feature_detector, który domyślnie bag of words. Zbuduje i zwróci mapowanie formularza, {etykieta: [zestaw cech]}. Następnie użyjemy tego mapowania, aby utworzyć listę oznaczonych instancji szkoleniowych i instancji testowych.
import collections
def label_corpus(corp, feature_detector=bow):
label_feats = collections.defaultdict(list)
for label in corp.categories():
for fileid in corp.fileids(categories=[label]):
feats = feature_detector(corp.words(fileids=[fileid]))
label_feats[label].append(feats)
return label_feats
Za pomocą powyższej funkcji uzyskamy mapowanie {label:fetaureset}. Teraz zamierzamy zdefiniować jeszcze jedną funkcję o nazwiesplit który przyjmie odwzorowanie zwrócone z label_corpus() funkcji i dzieli każdą listę zestawów funkcji na oznaczone szkolenia, a także instancje testowe.
def split(lfeats, split=0.75):
train_feats = []
test_feats = []
for label, feats in lfeats.items():
cutoff = int(len(feats) * split)
train_feats.extend([(feat, label) for feat in feats[:cutoff]])
test_feats.extend([(feat, label) for feat in feats[cutoff:]])
return train_feats, test_feats
Teraz użyjmy tych funkcji w naszym korpusie, tj. Przeglądy_filmów -
from nltk.corpus import movie_reviews
from featx import label_feats_from_corpus, split_label_feats
movie_reviews.categories()
Wynik
['neg', 'pos']
Przykład
lfeats = label_feats_from_corpus(movie_reviews)
lfeats.keys()
Wynik
dict_keys(['neg', 'pos'])
Przykład
train_feats, test_feats = split_label_feats(lfeats, split = 0.75)
len(train_feats)
Wynik
1500
Przykład
len(test_feats)
Wynik
500
Widzieliśmy to w movie_reviewskorpusu, istnieje 1000 plików pos i 1000 plików neg. W efekcie otrzymujemy również 1500 oznaczonych instancji szkoleniowych i 500 oznaczonych instancji testowych.
Teraz trenujmy NaïveBayesClassifier używając jego train() metoda klasowa -
from nltk.classify import NaiveBayesClassifier
NBC = NaiveBayesClassifier.train(train_feats)
NBC.labels()
Wynik
['neg', 'pos']
Klasyfikator drzewa decyzyjnego
Kolejnym ważnym klasyfikatorem jest klasyfikator drzewa decyzyjnego. Tutaj, aby go wyszkolićDecisionTreeClassifierclass utworzy strukturę drzewa. W tej strukturze drzewa każdy węzeł odpowiada nazwie elementu, a gałęzie - wartościom elementu. A w dół gałęzi dotrzemy do liści drzewa, czyli etykiet klasyfikacyjnych.
Aby wytrenować klasyfikator drzewa decyzyjnego, użyjemy tych samych funkcji szkoleniowych i testowych, tj train_feats i test_feats, zmienne, na podstawie których utworzyliśmy movie_reviews ciało.
Przykład
Aby wytrenować ten klasyfikator, zadzwonimy DecisionTreeClassifier.train() metoda klasy w następujący sposób -
from nltk.classify import DecisionTreeClassifier
decisiont_classifier = DecisionTreeClassifier.train(
train_feats, binary = True, entropy_cutoff = 0.8,
depth_cutoff = 5, support_cutoff = 30
)
accuracy(decisiont_classifier, test_feats)
Wynik
0.725
Maksymalny klasyfikator entropii
Innym ważnym klasyfikatorem jest MaxentClassifier który jest również znany jako conditional exponential classifier lub logistic regression classifier. Tutaj, aby to wyszkolićMaxentClassifier class przekonwertuje oznaczone zestawy funkcji na wektor przy użyciu kodowania.
Aby wytrenować klasyfikator drzewa decyzyjnego, użyjemy tych samych funkcji szkoleniowych i testowych, tj train_featsi test_feats, zmienne, na podstawie których utworzyliśmy movie_reviews ciało.
Przykład
Aby wytrenować ten klasyfikator, zadzwonimy MaxentClassifier.train() metoda klasy w następujący sposób -
from nltk.classify import MaxentClassifier
maxent_classifier = MaxentClassifier
.train(train_feats,algorithm = 'gis', trace = 0, max_iter = 10, min_lldelta = 0.5)
accuracy(maxent_classifier, test_feats)
Wynik
0.786
Klasyfikator Scikit-Learn
Jedną z najlepszych bibliotek uczenia maszynowego (ML) jest Scikit-learn. W rzeczywistości zawiera różnego rodzaju algorytmy ML do różnych celów, ale wszystkie mają ten sam wzór dopasowania, jak poniżej -
- Dopasowanie modelu do danych
- I użyj tego modelu do prognozowania
Zamiast bezpośredniego dostępu do modeli scikit-learning, tutaj użyjemy NLTK SklearnClassifierklasa. Ta klasa jest klasą opakowującą wokół modelu scikit-learning, aby była zgodna z interfejsem klasyfikatora NLTK.
Wykonamy następujące kroki, aby wyszkolić SklearnClassifier klasa -
Step 1 - Najpierw utworzymy funkcje treningowe, tak jak to zrobiliśmy w poprzednich przepisach.
Step 2 - Teraz wybierz i zaimportuj algorytm uczenia się Scikit.
Step 3 - Następnie musimy skonstruować plik SklearnClassifier klasę z wybranym algorytmem.
Step 4 - Na koniec będziemy trenować SklearnClassifier z naszymi funkcjami szkoleniowymi.
Zaimplementujmy te kroki w poniższym przepisie Pythona -
from nltk.classify.scikitlearn import SklearnClassifier
from sklearn.naive_bayes import MultinomialNB
sklearn_classifier = SklearnClassifier(MultinomialNB())
sklearn_classifier.train(train_feats)
<SklearnClassifier(MultinomialNB(alpha = 1.0,class_prior = None,fit_prior = True))>
accuracy(sk_classifier, test_feats)
Wynik
0.885
Pomiar precyzji i przywołanie
Podczas szkolenia różnych klasyfikatorów mierzyliśmy również ich dokładność. Ale oprócz dokładności istnieje wiele innych metryk, które są używane do oceny klasyfikatorów. Dwa z tych wskaźników toprecision i recall.
Przykład
W tym przykładzie obliczymy precyzję i pamięć klasy NaiveBayesClassifier, którą trenowaliśmy wcześniej. Aby to osiągnąć, utworzymy funkcję o nazwie metrics_PR (), która będzie pobierać dwa argumenty, jeden to wyuczony klasyfikator, a drugi to oznaczone funkcje testowe. Oba argumenty są takie same, jakie przekazaliśmy podczas obliczania dokładności klasyfikatorów -
import collections
from nltk import metrics
def metrics_PR(classifier, testfeats):
refsets = collections.defaultdict(set)
testsets = collections.defaultdict(set)
for i, (feats, label) in enumerate(testfeats):
refsets[label].add(i)
observed = classifier.classify(feats)
testsets[observed].add(i)
precisions = {}
recalls = {}
for label in classifier.labels():
precisions[label] = metrics.precision(refsets[label],testsets[label])
recalls[label] = metrics.recall(refsets[label], testsets[label])
return precisions, recalls
Nazwijmy tę funkcję, aby znaleźć precyzję i przypomnieć sobie -
from metrics_classification import metrics_PR
nb_precisions, nb_recalls = metrics_PR(nb_classifier,test_feats)
nb_precisions['pos']
Wynik
0.6713532466435213
Przykład
nb_precisions['neg']
Wynik
0.9676271186440678
Przykład
nb_recalls['pos']
Wynik
0.96
Przykład
nb_recalls['neg']
Wynik
0.478
Połączenie klasyfikatora i głosowania
Łączenie klasyfikatorów to jeden z najlepszych sposobów na poprawę wydajności klasyfikacji. Głosowanie to jeden z najlepszych sposobów łączenia wielu klasyfikatorów. Do głosowania potrzebujemy nieparzystej liczby klasyfikatorów. W poniższym przepisie Pythona połączymy trzy klasyfikatory, a mianowicie klasę NaiveBayesClassifier, klasę DecisionTreeClassifier i klasę MaxentClassifier.
Aby to osiągnąć, zdefiniujemy funkcję o nazwie voting_classifiers () w następujący sposób.
import itertools
from nltk.classify import ClassifierI
from nltk.probability import FreqDist
class Voting_classifiers(ClassifierI):
def __init__(self, *classifiers):
self._classifiers = classifiers
self._labels = sorted(set(itertools.chain(*[c.labels() for c in classifiers])))
def labels(self):
return self._labels
def classify(self, feats):
counts = FreqDist()
for classifier in self._classifiers:
counts[classifier.classify(feats)] += 1
return counts.max()
Nazwijmy tę funkcję, aby połączyć trzy klasyfikatory i znaleźć dokładność -
from vote_classification import Voting_classifiers
combined_classifier = Voting_classifiers(NBC, decisiont_classifier, maxent_classifier)
combined_classifier.labels()
Wynik
['neg', 'pos']
Przykład
accuracy(combined_classifier, test_feats)
Wynik
0.948
Z powyższego wyniku widać, że połączone klasyfikatory uzyskały najwyższą dokładność niż indywidualne klasyfikatory.