Теперь я не очень люблю большие слова, я верю в объяснение вещей в моем собственном понимании, и я обнаружил, что люди (новички) склонны понимать концепцию лучше/быстрее, когда новичок объясняет концепцию так, как он ее понимает, тем самым разрушая ее до его уровня. Но те, кто стремится к большому техническому определению, могут заняться исследованиями, они есть во всем Интернете.
Что такое детектор фраз
Детектор фраз — это реализованный алгоритм, который использует несколько техник, самой популярной из которых является счетная свертка (именно эта техника используется в gensim). Эта техника определяет общие слова, которые всегда встречаются вместе с минимальной предопределенной частотой или, согласно gensim, пороговой оценкой, где чем выше пороговое значение, тем строже процесс отбора.
Эта модель используется для выявления фраз (биграмм), которые присутствуют в ваших текстах, и особенно полезна при построении векторов слов. Поскольку она существенно снижает вычислительную сложность за счет уменьшения количества словарей в вашем векторе слов, она делает это путем объединения слов, которые часто встречаются вместе, в одно слово.
import os
import re
from typing import List
from itertools import islice
from gensim import utils
from gensim.models.phrases import Phrases, ENGLISH_CONNECTOR_WORDS
from nltk.tokenize import NLTKWordTokenizer, PunktSentenceTokenizer
view rawmodel.py
Эта модель обучена на всей серии «Малазанской книги павших», это не только отличный ресурс для обучения вашей модели, но и гораздо более отличное чтение, или это могут быть любые [или все] книги, которые в настоящее время находятся в вашем компьютере. Книги должны быть в формате .txt [или преобразованы в него] для удобства загрузки, и все они должны находиться в папке под названием «Книги» без вложенных папок, содержащих другие текстовые файлы.
class CustomPathLineSentences:
"""Custom implementaion of gensim.models.word2vec.PathLineSentences
It differs from gensim implementation in that it replaces the default
tokenizer with a more powerful tokenizer, while also adding more
functionalities to it.
Functionalities
1) Break the block of text into sentences using PunktSentenceTokenizer()
as each text is split on n
2) For each sentence
a) Tokenize sentence using NLTKWordTokenizer()
i) Clean each tokens
b) Join words that constitute phrases into a single word if a
phrase detector model is passed as argument
c) yield up the preprocessed tokens for further processing
2)
Parameters
source: str
File path of the folder containing the text file
limit: int
The maximum number of characters to read in each text block
include_phrase: bool
If True group words that constitue phrase into a single word,
this should only be set to True if a phrase detector model has
been trained
phrase_model: phrase detector model
The model used in detecting phrases in text
if include_phrase is True and phrase_model is None, a ValueError
is raised,
"""
def __init__(self, source, limit=None,
include_phrase=False, phrase_model=None):
self.source = source
self.limit = limit
self.include_phrase = include_phrase
self.word_tokenizer = NLTKWordTokenizer()
self.sentence_tokenizer = PunktSentenceTokenizer()
if self.include_phrase and phrase_model is not None:
self.phrase_model = phrase_model
elif self.include_phrase and phrase_model is None:
raise ValueError("phrase model detector not provided")
if os.path.isfile(self.source):
print('This is a file, use a folder next time')
self.input_files = [self.source]
elif os.path.isdir(self.source):
self.source = os.path.join(self.source, '')
self.input_files = os.listdir(self.source)
self.input_files = [self.source + fname
for fname in self.input_files]
self.input_files.sort()
else:
raise ValueError('input is neither a file or a directory')
def __word_cleaner(self, word, cleaned_word_tokens, punctuation) -> List[str]:
"""For each word if any punctuation is still found in the
beginning and ending, further split them, ignore any
punctuation found in between the alphabet
"""
beginning_punc = None
ending_punc = None
if len(word) > 1:
if word[0] in punctuation:
beginning_punc = word[0]
word = word[1:]
if word[-1] in punctuation:
ending_punc = word[-1]
word = word[:-1]
if beginning_punc is not None:
cleaned_word_tokens.append(beginning_punc)
# For Some reason Jupyter notebook keep restarting
# because of this recursive code
# if word[0] in punctuation or word[-1] in punctuation:
# cleaned_word_tokens = self.__word_cleaner(word, cleaned_word_tokens,
# punctuation)
# else:
# cleaned_word_tokens.append(word)
cleaned_word_tokens.append(word)
if ending_punc is not None:
cleaned_word_tokens.append(ending_punc)
return cleaned_word_tokens
def clean_token_words(self, sentence) -> List[str]:
"""Split a sentence into tokens for further preprocessing"""
word_tokens: list = sentence.split()
cleaned_word_tokens = []
punctuation = string.punctuation + "’" + "‘"
for word in word_tokens:
if not self.include_phrase:
cleaned_word_tokens.append(word.strip(punctuation))
else:
self.__word_cleaner(word, cleaned_word_tokens, punctuation)
return cleaned_word_tokens
def __iter__(self):
"""Iterate through the files"""
pattern = re.compile("[‘’]")
total_count = 0
for fname in self.input_files:
with utils.open(fname, 'rb') as fin:
# iterate through the text using the inbuilt
# readline function
for line in islice(fin, self.limit):
line = utils.to_unicode(line).strip()
if line:
# text broken at the line break point may contain
# many sentences in it, use a sentence segmenter
# to further break them into sentences
sentences = self.sentence_tokenizer.tokenize(line)
# for each of those sentences break them into tokens
for sentence in sentences:
sentence = pattern.sub("'", sentence)
word_tokens = self.clean_token_words(sentence)
if not self.include_phrase:
yield word_tokens
else:
# combine detected words that consitutes phrases
# into a single word
generator = self.phrase_model.analyze_sentence(word_tokens)
yield [word[0] for word in generator]
to
def __len__(self):
counts = 0
for sentences in self.__iter__():
counts += 1
return counts
Хорошо, это было весело, вы только что создали и добавили удобный инструмент в свой пояс инструментов, он пригодится нам в нескольких сценариях [особенно при построении вектора слов или модели стилевого вывода], поэтому сохраните его где-нибудь в текстовом файле python и назовите файл utils.py.
Я немного схитрил, я создал функцию
CustomPathLineSentences
, чтобы она была общей и имела много вариантов использования, не специфичных только для этого проекта, как вы увидите, когда я буду использовать ее при построении вектора слов и обучении модели стилевого анализа.
Вкратце этот класс выполняет следующие функции: он становится итератором для нас при инстанцировании, итерируя наши текстовые файлы и одновременно препроцессируя их для нас, оставляя нам более сложную задачу обучения модели детектора фраз. Чем мы и займемся ниже;
# train a phrase detector
def train_phrase_detector(*, threshold=400, reduce_model_memory_size=False):
sentences_iterator = CustomPathLineSentences('Books')
print("List of iles that will be analyzed for word phrase (bigrams)")
for file in sentences_iterator.input_files:
print(file)
phrases = Phrases(sentences_iterator, threshold=threshold,
connector_words=ENGLISH_CONNECTOR_WORDS)
print("Training completed")
return (phrases.freeze(), sentences_iterator) if reduce_model_memory_size
else (phrases, sentences_iterator)
Мы определили функцию, которая будет выполнять для нас задачу обучения модели, используя заданные и стандартные параметры. Далее мы перейдем к обучению модели, выполнив функцию.
threshold = 400
reduce_model_memory_size = False
phrase_model, sentences_iterator = train_phrase_detector(
threshold=threshold,
reduce_model_memory_size=reduce_model_memory_size)
# saving the trained model
fname = "malaz_phrase_detector"
phrase_model = phrase_model.save(fname)
Хорошо, мы закончили обучение модели и сохранили ее на диск для дальнейшего использования, когда нам понадобится построить вектор слов и модель стилевого вывода, давайте посмотрим, чему научилась модель, и проверим, может ли она обнаруживать словосочетания в текстах.
# print how many phrases the model detected in the trainng text
print(f"Total number of phrases (bigrams) detected: {len(phrase_model)}")
text = """The Foolish Dog Clan will join your companies on the other side,' Coltaine said. 'You and the Weasel Clan shall guard this side while the wounded and the refugees cross"""
# preprocess the text in the same way the training
# text was preprocessed
text_cleaned = sentences_iterator.clean_token_words(text)
# detect phrases (bigrams) in text
phrases_detected = phrase_model.analyze_sentence(text_cleaned)
print("Detected phrases")
for key, values in phrases_detected.items():
if values > 0:
print(key)
Мы успешно построили модель детектора фраз, модель была протестирована на тексте и смогла успешно обнаружить фразы в модели.
Это важно, данная модель может быть достаточно общей для обнаружения фраз, которые следуют шаблону обучающего текста [например, следующая серия авторского романа, если модель была обучена на предыдущей серии]. Но если модель будет предназначена для обнаружения фраз на совершенно другом образце текста, который даже не содержит той же лексики, что и учебный текст, модель потерпит серьезное фиаско.
Бог любит тебя!