Конвейер НЛП

Прежде чем перейти к этапам предварительной обработки текста в обработке естественного языка (NLP), давайте взглянем на стандартный конвейер НЛП, основанный на машинном обучении.
Конвейер НЛП — это набор шагов, которые необходимо выполнить для создания комплексного программного обеспечения НЛП.

Он состоит из следующих шагов:

  • Сбор данных
  • Подготовка текста
    – Очистка текста
    – Базовая предварительная обработка
    – Расширенная предварительная обработка
  • Разработка функций
  • Моделирование
    – Построение модели
    – Оценка
  • Развертывание
    – Развертывание
    – Мониторинг
    – Обновление модели

В этом блоге мы рассмотрим основные этапы предварительной обработки обработки естественного языка на основе машинного обучения.

Если вы хотите получить краткий обзор НЛП, вы можете просмотреть мой предыдущий блог:



Предварительная обработка текста

Для предварительной обработки текста перед разработкой функций и моделированием используются различные методы. Ниже представлены наиболее популярные техники:

Нижний регистр

Данные должны быть записаны строчными буквами, чтобы избежать усложнения модели. Это связано с тем, что Python будет рассматривать Basically и basically по-разному. Код для этого может быть:

# suppose we have a dataframe which includes movie reviews along with it's 
# sentiments
# reviews are in review column and sentiments are in sentiment column

df['review'] = df['review'].str.lower()

# and this simple line of code will transform every review into lowercase 
# uniformly

Удаление HTML-тегов

Часто данные получаются посредством парсинга веб-страниц или с помощью различных API, и в результате данные содержат HTML-теги, которые используются для семантического значения, важного для браузера, а не для нас. Поэтому нам важно заранее удалить эти HTML-теги. Это делается с помощью регулярных выражений или широко известных как регулярные выражения.

# in our case we scraped data from the IMDB website and thus it does contain 
# HTML tags
# we'll define a simple function that uses regex to remove the HTML tags

import re
def remove_html_tags(text):
 '''
 takes a string `text` as the input
 returns a string without HTML tags
 '''
 pattern = re.compile('<.*?>')
 return pattern.sub(r'', text)

df['review'] = df['review'].apply(remove_html_tags)

Удаление URL-адресов

Удаление URL-адресов из наших данных — еще один распространенный шаг предварительной обработки данных при построении модели НЛП. Это связано с тем, что URL-адреса на самом деле не влияют на смысл/настроение текстового сообщения и вместо этого могут запутать нашу модель, поэтому их лучше удалить. Опять же, регулярные выражения используются для удаления URL-адресов из наших данных.

# our movie review data doesn't really have any urls in them (obv)
# so I'll use sample data to demonstrate this

import re
text1 = 'Google search here www.google.com'
text2 = 'My Linkedin: https://www.linkedin.com/in/pranshavpatel/'

def remove_url(text):
 '''
 takes a string `text` as the input
 returns a string without any URL
 '''
 pattern = re.compile(r'https?://\S+|www\.\S+')
 return pattern.sub(r'', text)

text_without_url = []
text_without_url.append(remove_url(text1))
text_without_url.append(remove_url(text2))

print(text_without_url) 
# will print a list containing both the text without any url

Удаление знаков препинания

Пунктуация — это специальные символы, которые помогают в построении предложений на определенном языке. В большинстве случаев рекомендуется удалять знаки препинания из наших данных, поскольку это может привести к дополнительной сложности и даже запутать модель. Например, при токенизации данных (о токенизации речь пойдет позже) Hello и Hello! будут считаться разными. Библиотека строк Python предоставляет знаки пунктуации, присутствующие в английском языке.

import string
print(string.punctuation) # prints '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'

def remove_punc(text):
 '''
 takes a string `text` as the input
 returns a string without any punctuation
 '''
 for char in string.punctuation:
   text = text.replace(char, '')
 return text

Этот код будет работать отлично, но поскольку мы разработали эту функцию, используя нашу собственную логику, она довольно медленная, а на больших наборах данных (что-то вроде обзоров фильмов IMDB) это займет значительное количество времени, поэтому мы будем использовать следующий код, который делает то же самое. вещь, но это намного быстрее.

import string
def remove_punc_fast(text):
 '''
 takes a string `text` as the input
 returns a string without any punctuation
 '''
 return text.translate(str.maketrans('', '', string.punctuation))

df['review'] = df['review'].apply(remove_punc_fast)

Обработка слов/сленгов в чате

В современном быстро меняющемся мире люди обычно используют аббревиатуры и короткие формы вместо того, чтобы вводить слова целиком. Например, LMAO, ROFL, LOL, GN, ASAP, FYI и т. д., и нам важно преобразовать их в длинные формы, чтобы достичь их семантического значения и не запутать нашу модель. Это можно сделать, используя простой словарь с ключом в качестве краткой формы и значением в качестве полной формы, а затем написав функцию, которая проверяет каждое слово предложения, заменяя его длинной формой, если оно присутствует в словаре.
Ссылка на репозиторий Github, содержащий сленги и их длинные формы:



chat_words = {}  # the dictionary containing the slang words and full forms
def chat_conversion(text):
 '''
 takes a string `text` as the input
 returns a string with the slangs replaced by their full forms
 '''
 new_text = []
 for w in text.split():
  if w.upper() in chat_words:
   new_text.append(chat_words[w.upper()])
  else:
   new_text.append(w)
 return ' '.join(new_text)

print(chat_conversion('IMO he is the best'))
# Output: In My Opinion he is the best

Исправление орфографии

Думаю, не нужно объяснять, почему это важно. Орфографическая ошибка может полностью изменить семантическое значение предложения или запутать модель, снизив ее точность, поэтому важно исправить написание наших текстовых данных без обучения модели. Для этого можно использовать различные библиотеки. В этом блоге я буду использовать textblob.

from textblob import TextBlob
incorrect_text = 'i doont knoww howw to typpe.'
textBlb = TextBlob(incorrect_text)
print(textBlb.correct().string)

#output: 'i dont know how to type.'

Удаление стоп-слов

Стоп-слова — это слова, которые помогают в формировании предложения, но на самом деле не влияют на его смысл и поэтому обычно удаляются из набора данных. В английском языке есть несколько распространенных стоп-слов: a, the of, are, my и т. д. Эти слова бесполезны для таких задач, как анализ настроений или классификация документов. Стоп-слова можно легко удалить с помощью библиотеки NLTK.

Примечание. В некоторых задачах НЛП, таких как маркировка частей речи, стоп-слова не удаляются.

from nltk.corpus import stopwords
print(stopwords.words('english')) # prints the stopwords present in english
# the method followed is very similar to that followed in chat word treatment

def remove_stopwords(text):
 '''
 takes a string `text` as the input
 returns a string with stop words removed
 '''
 new_text = []
 for w in text.split():
  if w in stopwords.words('english'):
   new_text.append('')
  else:
   new_text.append(w)
 return ' '.join(x)

print(remove_stopwords('NLP is very interesting'))
# output: 'NLP   interesting'

df['review'] = df['review'].apply(remove_stopwords)

Обработка смайлов

В наши дни смайлы очень распространены, и мы используем их в наших ежедневных разговорах, но машинам может быть довольно сложно расшифровать их значение. Есть два способа обработки смайлов:

  • Удалите их: просто используйте регулярные выражения, чтобы удалить их из данных (да, шаблоны могут быть довольно сложными из-за кодировки «utf-8» :/)
  • Замените их текстовым значением. Библиотека смайлов в Python предоставляет нам функцию «демоджиза», которая заменяет смайлик его текстовым описанием.
# Remove emojis
import re
def remove_emoji(text):
    emoji_pattern = re.compile("["
                           u"\U0001F600-\U0001F64F"  # emoticons
                           u"\U0001F300-\U0001F5FF"  # symbols & pictographs
                           u"\U0001F680-\U0001F6FF"  # transport & map symbols
                           u"\U0001F1E0-\U0001F1FF"  # flags (iOS)
                           u"\U00002702-\U000027B0"
                           u"\U000024C2-\U0001F251"
                           "]+", flags=re.UNICODE)
    return emoji_pattern.sub(r'', text)

print(remove_emoji('Loved the movie. It was 😘'))
# output: 'Loved the movie. It was '

# Replace emojis with text
import emoji
print(emoji.demojize('Loved the movie. It was 😘'))
#output: 'Loved the movie. It was :face_blowing_a_kiss:'

Токенизация

Вероятно, это самый важный шаг в предварительной обработке текстовых данных. Это включает в себя токенизацию текстовых данных в предложения, фразы или слова. Например, 'NLP is very interesting' можно преобразовать в слово ['NLP', 'is', 'very', 'interesting'].

Токенизация очень важна, поскольку это базовый этап разработки функций, который определяет, как наша модель будет интерпретировать данные. Таким образом, для инженера НЛП очень важно правильно маркировать данные, чтобы избежать путаницы. Вот несколько примеров, отражающих проблемы, с которыми сталкиваются во время токенизации:
$20 : Здесь важно токенизировать $ отдельно и 20 отдельно.
10km : Здесь важно токенизировать 10 отдельно и км отдельно. U.S.: Здесь важно токенизировать США как один токен вместо токенизации U отдельно и S отдельно.
Таким образом, для правильной токенизации наших данных необходимо сделать множество исключений.

Я рассмотрю код нескольких методов, которые можно применить для токенизации наших данных.

# 1. Using the split function
# The most naive approach, and obviously it won't cover any corner cases
sent = 'NLP is very interesting'
print(sent.split())
# output: ['NLP', 'is', 'very', 'interesting']

# 2. Using regular expressions
# This might work but one has to make many complex patterns to fit corner cases
# can be tedious at times but better than the split function
import re
sent = 'NLP is very interesting'
tokens = re.findall("[\w']+", sent)
print(tokens)
# output: ['NLP', 'is', 'very', 'interesting']

# 3. Using python libraries
# The most optimal solution, handles the complexes cases on its own
# 3.1 NLTK
from nltk.tokenize import word_tokenize
sent = 'NLP is very interesting!'
print(word_tokenize(sent))
# output: ['NLP', 'is', 'very', 'interesting', '!']
# Note: In the first two cases the exclamation mark wouldn't have been 
# considered as a separate token
# Still NLTK doesn't provide the best solution and misses a few exceptions

# 3.2 Spacy
import spacy
nlp = spacy.load('en_core_web_sm')
doc = nlp(sent)
for token in doc:
 print(token)
#output:
# NLP
# is
# very
# interesting
# !
# Spacy is the preferred choice because it handles corner cases more 
# effectively than NLTK.

Стемминг/лемматизация

Переходим к последнему, но не менее важному методу предварительной обработки текста.
Сначала давайте разберемся, что такое флексия? В грамматике флексия — это модификация слова для выражения различных грамматических категорий, таких как время, падеж , голос, аспект, лицо, число, пол и настроение. Например, прогулка может быть выражена как ходьба, шел, прогулка и т. д. И как вы правильно догадались, перегиб является проблемой для нашей модели, поскольку он приводит к дополнительной сложности и может запутать нашу модель.

Так как же это связано со Стеммингом? Стемминг – это процесс приведения слов к их корневым формам, например сопоставление группы слов с одной и той же основой даже если сама основа не является допустимым словом в языке.

Стемминг в основном используется в системах информационного поиска. Например, когда вы ищете рыбу в Google, вы также получаете результаты рыбалки. Это из-за Стемминга.

Алгоритмы, используемые для стемминга, называются стеммерами, и в этом блоге мы обсудим конкретный стеммер под названием Porter Stemmer, который используется специально для английского языка.

Реализовать стемминг мы будем через библиотеку NLTK.

from nltk.stem.porter import PorterStemmer
ps = PorterStemmer
def stem_words(text):
 '''
 takes a string `text` as the input
 returns a string with every word transformed into its stem word
 '''
 return ' '.join([ps.stem(word) for word in text.split()])
# list comprehensions are so concise, that's the reason I love them!

sample = 'walk walks walking walked'
stem_words(sample)
# output: 'walk walk walk walk'

# now let's try this with another sentence
text = 'probably my all time favorite horror movie is the conjuring'
stem_words(text)
# output: 'probabl my all time favorit horror movi is the conjur'

Обратите внимание, что во втором предложении основы даже не являются настоящими словами. Это может быть проблемой, если по какой-то причине вы хотите показать этот вывод своему пользователю/клиенту.

Таким образом, чтобы решить эту проблему, используется Лемматизация, которая по сути делает то же самое, но вместо этого ищет настоящие английские слова (или язык, над которым вы работаете) в качестве основных слов для каждого слова.
По этой причине лемматизация выполняется медленнее, чем стемминг, и если вам не нужно показывать этот вывод пользователю, обычно используется стемминг, поскольку он быстрее.
Лемматизация, в отличие от стемминга, правильно уменьшает количество измененных слов, гарантируя, что корень слова принадлежит языку. В лемматизации корневое слово называется леммой.

В отличие от стемминга, который использует алгоритм, в лемматизации словарь используется для преобразования слов в лемму (мы будем использовать WordNet Lemmatizer, который представляет собой лексический словарь, в котором хранятся связи между английскими словами). Теперь, поскольку мы ищем в словаре замену слов, а не просто используем определенный алгоритм, лемматизация работает медленнее, чем стемминг.

Примечание. При лемматизации вам также необходимо указать части речи, в которых вы хотите, чтобы ваша лемма (глагол, существительное, прилагательное и т. д.)

Мы можем реализовать лемматизацию, используя библиотеку NLTK:

import nltk
from nltk.stem import WordNetLemmatizer
wordnet_lemmatizer = WordNetLemmatizer()

sentence = "I love coding whilst listening to music."
punctuations="?:!.,;"
sentence_words = nltk.word_tokenize(sentence)
for word in sentence_words:
    if word in punctuations:
        sentence_words.remove(word)

sentence_words
print("{0:20}{1:20}".format("Word","Lemma"))
for word in sentence_words:
    print ("{0:20}{1:20}".format(word,wordnet_lemmatizer.lemmatize(word,pos='v')))
#output:
# Word                Lemma               
# I                   I                   
# love                love                
# coding              code                
# whilst              whilst              
# listening           listen              
# to                  to                  
# music               music

Заключение

В этом блоге мы углубились в важнейший мир этапов предварительной обработки текста НЛП. Целью НЛП является понимание человеческого языка, и эти этапы предварительной обработки являются основой, на которой мы строим значимые идеи. От преобразования текста в нижний регистр до обработки сложных элементов, таких как смайлы, мы изучили все важные аспекты подготовки текстовых данных для задач НЛП. Эти шаги не только повышают точность наших моделей, но и открывают путь к более четкому общению между людьми и машинами. Поскольку мы продолжаем продвигаться в области обработки естественного языка, овладение этими методами предварительной обработки становится все более важным. Итак, продолжайте экспериментировать, продолжайте учиться и продолжайте расширять границы возможного в НЛП!

и это конец!

Свяжитесь со мной:

Идентификатор электронной почты:[email protected]
Linkedin:
https://www.linkedin.com/in/pranshavpatel/
Github:https://www.github.com/pranshavpatel

Стеккадемический

Спасибо, что дочитали до конца. Прежде чем уйти:

  • Пожалуйста, рассмотрите возможность аплодировать и следовать автору! 👏
  • Следуйте за нами в Twitter(X), LinkedIn и YouTube.
  • Посетите Stackademic.com, чтобы узнать больше о том, как мы демократизируем бесплатное образование в области программирования во всем мире.