Понимание того, насколько важна роль предварительной обработки и представления данных в обработке естественного языка и как это сделать.

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

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

Здесь на помощь приходит модуль NLTK или Natural Language Processing Toolkit в Python. NLTK - одна из ведущих платформ, используемых для работы с данными на человеческом языке. Он предоставляет готовые к использованию удобные методы обработки и предварительной обработки данных, которые наиболее часто используются для преобразования читаемого человеком текста в рабочий формат.

Поскольку в этой статье используется более практический подход к использованию NLTK в качестве фреймворка, я не буду слишком углубляться во все связанные с ним жаргоны и терминологию и буду рассматривать только те, которые либо наиболее часто используются, либо будут использоваться в следующей реализации. Если вам все еще интересно, ознакомьтесь с этим блогом одного из членов нашего Основного комитета, в котором объясняются все термины, с которыми можно встретиться при использовании NLTK.

Итак, приступим.

Токенизация

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

Стебель

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

Лемматизация

Лемматизация обычно означает приведение слова к его основной или корневой форме с использованием словарного запаса и морфологического анализа слов, вместо того, чтобы слепо отрубать окончания слов. Обычно он направлен на удаление только флективных окончаний и возвращает базовую или словарную форму слова, известную как лемма.

Пример: при столкновении с токеном "saw", основание может вернуть только букву "s", тогда как лемматизация попытается вернуть либо see, либо saw, в зависимости от того, использовался ли токен как глагол. или существительное.

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

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

Примеры: a, an, the, on, in, at и т. д.

POS-теги

Процесс обозначения слова в тексте или корпусе как соответствующего определенной части речи на основе как его определения, так и контекста.

Представление документов

Набор слов, оставшихся в документе после выполнения всех вышеперечисленных шагов, отличается от исходного документа и может рассматриваться как формальное представление документа. Цель представления документа - помочь процессу сопоставления ключевых слов. Однако сокращение или удаление некоторых слов может также привести к потере информации. Три наиболее распространенных правила представления документов - это полное, логическое значение и набор слов. Давайте рассмотрим их нюансы по порядку.

Полное представление:

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

Логическое представление:

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

Мешок слов:

Представление документа, которое включает только частоту терминов, но не положение термина, называется представлением «мешком слов».

Веб-парсинг

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

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

Постановка задачи

Часть 1

Извлеките исходный контент с веб-сайта (https://en.wikipedia.org/wiki/Natural_language_processing) и отобразите количество терминов и соответствующую им частоту терминов после удаления стоп-слова . Кроме того, примените выделение корней и лемматизацию к одному и тому же документу и отобразите количество терминов вместе с соответствующими им корневыми, а также лемматизированными корневыми словами. Подсчитайте общее количество полученных таким образом слов с основами и лемматизацией.

Установка библиотек и зависимостей

import requests
from bs4 import BeautifulSoup
from nltk.corpus import stopwords
from nltk.stem import PorterStemmer, WordNetLemmatizer
import pandas as pd
from nltk import pos_tag
import io
  • Запросы - HTTP-библиотека на Python для разбора URL-адресов и ссылок.
  • BeautifulSoup - библиотека Python для извлечения данных из HTML-документов и веб-страниц.
  • Stopwords - часть nltk.corpus, предоставляет нам список стоп-слов, с которыми можно работать.
  • PorterStemmer - алгоритм стемминга, встроенный в НЛТК.
  • WordNetLemmatizer - алгоритм лемматизации, встроенный в NLTK.
  • Pandas - библиотека Python для анализа данных и построения фреймов данных.
  • Pos_tag - часть речевого теггера, встроенного в NLTK для тегирования данного списка токенов.
  • Io - библиотека, используемая для интеграции веб-данных.

Извлечение текста

После импорта всех необходимых зависимостей мы затем анализируем данный URL-адрес в BeautifulSoup () с помощью библиотеки запросов, чтобы удалить все теги javascript и style и сохранить только текстовый контент, присутствующий на веб-странице.

url = “https://en.wikipedia.org/wiki/Natural_language_processing"
r = requests.get(url)
html_text = r.text
soup = BeautifulSoup(html_text)
for script in soup(["script", "style"]):
    script.extract()

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

Теперь мы выполним удаление стоп-слов, проверив полученный выше текст на наличие стоп-слов и удалив слова, которые присутствуют как в тексте, так и в списке ранее импортированных стоп-слов.

sample = soup.get_text()
stopword = stopwords.words(“english”)
sample_stop = [x for x in sample.lower().split() if x not in stopword]

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

Затем мы выполняем стемминг и лемматизацию текста, который мы получаем после удаления стоп-слова, и сохраняем полученные таким образом выходные данные в списках stem_words и lemmatize_words соответственно.

stem_words = []
stemmer = PorterStemmer()
for x in list(d.keys()):
 stem_words.append(stemmer.stem(x))
lemmatize_words = []
lemmatizer = WordNetLemmatizer()
for x in list(d.keys()):
 lemmatize_words.append(lemmatizer.lemmatize(x))

Печать вывода в виде фрейма данных.

words = list(d.keys())
freq = list(d.values())
final_dict = {“Word”:words, “Stemmed Word”:stem_words, “Lemmatized Words”:lemmatize_words, “Frequency”:freq}
df = pd.DataFrame(final_dict)
print(“Total Terms before stopword removal:”,len(sample.split()))
print(“Total Terms after stopword removal:”,sum(freq))
print(“Unique Stemmed Words:”,len(list(set(stem_words))))
print(“Unique Lemmatized Word:”,len(list(set(lemmatize_words))))
df.head()

Выход

Часть 2

Добавьте одно новое слово в список запрещенных слов NLTK и отфильтруйте контент, извлеченный с веб-сайта, чтобы отобразить количество терминов и их частоту использования после исключения вновь добавленного стоп-слова. Отобразите тег POS для всех игнорируемых слов, которые удалены из содержания.

Давайте добавим слово «язык» к нашему списку игнорируемых слов, а затем отфильтруем контент на основе этого недавно полученного списка.

stopword.append(“language”)
sample_stop = [x for x in sample.lower().split() if x not in stopword]

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

d ={}
for x in sample_stop:
    if(x not in d.keys()):
        d[x] = 1
    else:
        d[x] += 1
words = list(d.keys())
freq = list(d.values())

Отображение вывода в виде фрейма данных.

df = pd.DataFrame(final_dict)
final_dict = {“Word”:words, “Frequency”:freq}
print(“Total Terms before stopword removal:”,len(sample.split()))
print(“Total Terms after stopword removal:”,sum(freq))
df.head()

Выход

Часть речи или теги POS.

Распечатка тега POS для всех игнорируемых слов, которые были удалены из текстового содержания.

removed_words = [x for x in stopword if x in sample.lower().split()]
removed_words_pos = pos_tag(removed_words)
removed_words_pos

Выход

Теперь, когда мы немного познакомились с NLTK, давайте поднимемся на ступеньку выше, извлекая, анализируя и сравнивая текстовое содержимое двух разных веб-страниц.

Часть 3

Извлеките содержимое двух веб-сайтов (https://en.wikipedia.org/wiki/Natural_language_processing и https://en.wikipedia.org/wiki/Machine_learning ) и сохраните содержание в двух отдельных документах. Удалите игнорируемые слова из содержания и представляйте документы, используя логическое, краткое и полное представление. Обработайте поисковый запрос, сравните содержание обеих страниц на предмет наличия запроса и отобразите результат сходства на основе максимального количества совпадений ( мешок слов).

Извлечение текста

Сначала мы извлекаем текст из двух вышеупомянутых URL-адресов с помощью той же процедуры, которая была развернута выше для удаления javascript и других тегов Html.

url_1 = “https://en.wikipedia.org/wiki/Natural_language_processing"
url_2 = “https://en.wikipedia.org/wiki/Machine_learning"
r = requests.get(url_1)
html_text = r.text
soup = BeautifulSoup(html_text)
for script in soup([“script”, “style”]):
 script.extract()
content_1 = soup.get_text()
r = requests.get(url_2)
html_text = r.text
soup = BeautifulSoup(html_text)
for script in soup([“script”, “style”]):
 script.extract()
content_2 = soup.get_text()

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

Затем мы сохраняем полученный таким образом текст в двух отдельных файлах документации и удаляем стоп-слова.

with io.open(‘nlp.doc’, mode = ‘w+’,encoding=”utf-8") as file_1:
 file_1.write(content_1)
with io.open(‘ml.doc’, mode = ‘w+’,encoding=”utf-8") as file_2:
 file_2.write(content_2)
stopword = stopwords.words(“english”)
content_1_stop = [x for x in content_1.lower().split() if x not in stopword]
content_2_stop = [x for x in content_2.lower().split() if x not in stopword]
all_words = content_1_stop + content_2_stop
all_words = list(set(all_words))

Логическое представление

Чтобы сформулировать логическое представление, в котором указывается наличие каждого слова в двух документах, мы просматриваем список слов, полученный после удаления стоп-слова, и проверяем наличие каждого слова. Полученный таким образом результат отображается в виде кадра данных.

bool_1 = []
bool_2 = []
for x in all_words:
    if x in content_1_stop:
        bool_1.append(1)
    else:
        bool_1.append(0)
    if x in content_2_stop:
        bool_2.append(1)
    else:
        bool_2.append(0)
final_dict = {"Word":all_words, "Doc 1":bool_1, "Doc 2":bool_2}
df = pd.DataFrame(final_dict)
df.head()

Выход

Обработка запроса

Следующий блок кода просит пользователя ввести запрос и ищет вхождение этого конкретного ключевого слова в обоих документах. Отображается «1», если искомое слово найдено в документе, и «0» в противном случае.

query=input("Enter query:")
for q in query.lower().split():
    try:
        f1=df['Doc 1'][all_words.index(q)]
        print("Presence of \""+ query +"\" in Doc 1:",f1)
    except ValueError:
        print("Presence of \"" + query + "\" in Doc 1:",0)
    try:
        f2=df['Doc 2'][all_words.index(q)]
        print("Presence of \""+ query +"\" in Doc 2:",f2)
    except ValueError:
        print("Presence of \"" + query + "\" in Doc 2:",0)

Мешок слов

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

d1 = {}
d2 = {}
for x in all_words:
        if x in content_1_stop:
            for y in content_1_stop:
                if x == y:
                    if x not in d1.keys():
                        d1[x] = 1
                    else:
                        d1[x] += 1
        else:
            d1[x] = 0
        if x in content_2_stop:
            for y in content_2_stop:
                if x == y:
                    if x not in d2.keys():
                        d2[x] = 1
                    else:
                        d2[x] += 1
        else:
            d2[x] = 0
final_dict = {"Word":all_words, "Freq in Doc 1": list(d1.values()), "Freq in Doc 2": list(d2.values())}
df = pd.DataFrame(final_dict)
df

Выход

Поскольку позиция, в которой встречаются слова, часто имеет значение, пренебрежение тем, как их найти, может не соответствовать нашей цели обучения предварительной обработке данных. Следовательно, следующий фрагмент кода создает фрейм данных, содержащий все слова и их соответствующую позицию в Документе 1.

word = []
pos = []
for x in all_words:
    i = 0
    if x in content_1_stop:
        for y in content_1_stop:
            i += 1
            if x == y:
                word.append(x)
                pos.append(content_1_stop.index(x,i-1))
final_dict = {"Word":word, "Position":pos}
df = pd.DataFrame(final_dict)
df.head()

Выход

Затем тот же процесс можно повторить и для второго документа.

word = []
pos = []
for x in all_words:
    i = 0
    if x in content_2_stop:
        for y in content_2_stop:
            i += 1
            if x == y:
                word.append(x)
                pos.append(content_2_stop.index(x,i-1))
final_dict = {"Word":word, "Position":pos}
df = pd.DataFrame(final_dict)
df.head()

Выход

Надеюсь, в этой статье можно познакомиться с некоторыми основами, связанными с предварительной обработкой данных и представлением в NLP с помощью NLTK. Вот ссылка на Github, содержащая исходный код проблем, обсуждаемых выше.



Пожалуйста, отпустите аплодисменты [или, может быть, подписаться? :)], если вы нашли это информативным, следите за обновлениями в следующих статьях.