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

Это модели, которые мы будем запускать

  1. Модель мешка слов
  2. TF-IDF
  3. N-граммы

Обработка текста

  • Проблема с моделированием текста состоит в том, что он беспорядочный, а алгоритмы машинного обучения предпочитают четко определенные входные и выходные данные фиксированной длины. Алгоритмы машинного обучения не могут работать напрямую с необработанным текстом; текст необходимо преобразовать в числа. В частности, векторы чисел.
  • Некоторые из важных шагов предварительной обработки текста включают:
  1. Токенизация - преобразование предложений в слова.
  2. Удаление ненужных знаков препинания и тегов.
  3. Удаление стоп-слов - часто встречающихся слов, таких как «то», «есть» и т. Д., Не имеющих определенной семантики.
  4. Stemming - слова сокращаются до корня путем удаления перегиба путем удаления ненужных символов, обычно суффикса.
  5. Лемматизация - еще один подход к устранению интонации путем определения части речи и использования подробной базы данных языка.

1. Мешок слов

BoW модели предложение или документ рассматривается как «мешок», содержащий слова. Он будет учитывать слова и их частоту встречаемости в предложении или документе, игнорируя семантические отношения в предложениях.

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

Простая реализация одного предложения

import pandas as pd
import nltk
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
a = "The dog is on the table"
from sklearn.feature_extraction.text import CountVectorizer

CountVectorizer

  • Преобразует коллекцию текстовых документов в матрицу счетчиков токенов. Эта реализация дает разреженное представление счетчиков.
  • CountVectorizer предоставляет простой способ как токенизировать коллекцию текстовых документов и создать словарь известных слов, так и кодировать новые документы с использованием этого словаря.
  • Вы можете использовать его следующим образом:
  1. Создайте экземпляр класса CountVectorizer.
  2. Вызовите функцию fit (), чтобы выучить словарь из одного или нескольких документов.
  3. Вызовите функцию transform () для одного или нескольких документов по мере необходимости, чтобы закодировать каждый как вектор.
c_vec = CountVectorizer()
count_occurs = c_vec.fit_transform([a])
# Convert the sparse matrix representation into dataframe with columns words and count
count_occur_df = pd.DataFrame((count, word) for word, count in zip(count_occurs.toarray().tolist()[0],
                                                                   c_vec.get_feature_names()))
count_occur_df.columns = ['Word', 'Count']
count_occur_df.sort_values('Count', ascending=False, inplace=True)
count_occur_df

Когда можно использовать ЛУК?

  • Когда набор данных невелик, а контекст зависит от предметной области, BoW может работать лучше, чем встраивание слов. Контекст очень зависит от предметной области, что означает, что вы не можете найти соответствующий вектор из предварительно обученных моделей встраивания слов (GloVe, fastText и т. Д.).

Недостатки Мешка слов.

  • Словарь: словарь требует тщательного проектирования, особенно для управления размером, что влияет на разреженность представлений документа.
  • Редкость: разреженные представления труднее моделировать как по вычислительным причинам (пространственная и временная сложность), так и по информационным причинам, когда модели должны использовать так мало информации в таком большом пространстве представлений.
  • Значение: при отказе от порядка слов игнорируется контекст и, в свою очередь, значение слов в документе (семантика). Контекст и значение могут многое предложить модели, что при моделировании можно было бы различить одни и те же слова, расположенные по-разному («это интересно» против «это интересно»), синонимы («старый велосипед» против «подержанный велосипед»). , и многое другое.

Импорт библиотек

В следующих строках кода мы импортируем необходимые библиотеки для выполнения необходимой задачи:

  • Pandas: библиотека для работы с файлами csv, excel и импорта данных для использования в python. Основной тип данных здесь называется DataFrame. Столбец также называется серией.
  • NLTK: библиотека NLP, которая имеет множество модулей, предназначенных для предварительной обработки текстовых данных. Лематизация, стоп-слова и т. Д. Являются неотъемлемой частью этой библиотеки.
  • Генсим: Еще одна библиотека НЛП, которая включает модули для предварительной обработки данных.
import warnings
warnings.filterwarnings(action='ignore', category=UserWarning, module='gensim')
import pandas as pd
from wordcloud import WordCloud
import nltk
from sklearn.feature_extraction.text import CountVectorizer
from nltk.corpus import stopwords
from sklearn.model_selection import train_test_split
import gensim
from gensim.utils import simple_preprocess
from gensim.parsing.preprocessing import STOPWORDS
from nltk.stem import WordNetLemmatizer, SnowballStemmer
from nltk.stem.porter import *

О наборе данных, который мы будем обрабатывать

  • В обзоре imdb набор данных есть столбцы для обзора, которые представляют собой текстовый обзор фильмов и столбец с метками, который помечен как отрицательный (отрицательный) и положительный (положительный).

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

Теперь мы читаем данные из нашего файла CSV (значения, разделенные запятыми), используя метод read_csv из библиотеки pandas. read_csv возвращает объект класса DataFrame (часть библиотеки pandas).

DataFrame.head () возвращает первые 5 строк в файле CSV.

Исходя из этого, мы удаляем файл столбца из фрейма данных с помощью метода drop. inplace = True - это флаг, который гарантирует, что изменения, вызванные командой drop, отражены в DataFrame.

df = pd.read_csv('imdb_master.csv', error_bad_lines = False, encoding = 'ISO-8859-1', index_col = 0)
print(df.head())
df.drop(['file'], axis = 1, inplace = True)

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

  • Удаление HTML-тега из уничтоженных данных.
  • Удаление стоп-слов - часто встречающихся слов, таких как «то», «есть» и т. Д., Не имеющих определенной семантики.
  • Лемматизация - еще один подход к устранению интонации путем определения части речи и использования подробной базы данных языка.
stemmer = SnowballStemmer('english')

def lemmatize_stemming(text):
    return stemmer.stem(WordNetLemmatizer().lemmatize(text, pos='v'))
def preprocess(text):
    result = []
    for token in gensim.utils.simple_preprocess(text):
        if token not in gensim.parsing.preprocessing.STOPWORDS and len(token) > 3:
            result.append(lemmatize_stemming(token))
    return result


for i in range(df.shape[0]):
    strs = []
    strs1 = df.iloc[i][1].replace("<br />" ,"").lower()
    strs = preprocess(strs1)
    strs1 = ""
    for j in range(len(strs)):
        strs1 += strs[j] + " "
    df.iloc[i][1] = strs1
    if i % 10000 == 0:
        print("", i/1000 , "% completed")
df1=df.copy()
df1 = df1[df1.label != 'unsup'] # Only retaining rows with text recognise as pos(positive review) and neg(negative review)
df1.label.value_counts().plot(kind='bar',figsize=(5,5))
df1['b_label']=df1['label'].map({'neg':0,'pos':1}) #mapping neg and pos to numerical values

Сентиментальный анализатор

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

Подход

  • Затем текстовые данные будут преобразованы в модель BOW, которую затем можно использовать для обучения модели контролируемой классификации для классификации внешнего текста как положительного или отрицательного отзыва.
count_vectorizer = CountVectorizer()#Design the Vocabulary
# The default token pattern removes tokens of a single character. 
bag_of_words = count_vectorizer.fit_transform(df1['review'])#Create the Bag-of-Words Model
X_train, X_test, y_train, y_test = train_test_split(bag_of_words, df1['b_label'], test_size=0.20, random_state=42)
  • Разделить на данные обучения и данные тестирования. Обучающий набор содержит известные выходные данные, и модель учится на этих данных, чтобы впоследствии обобщить их на другие данные. У нас есть тестовый набор данных (или подмножество), чтобы проверить предсказание нашей модели на этом подмножестве.
  • Имеет соотношение поезд: тест 80:20.

Выбор алгоритма

  • Мы будем обучать Sentimental Analyzer, используя два отдельных алгоритма, чтобы сравнивать их характеристики.

Полиномиальный наивный байесовский классификатор

  • Наивный Байес - это семейство алгоритмов, основанное на применении теоремы Байеса с сильным (наивным) предположением, что каждая функция не зависит от других, для прогнозирования категории данной выборки. Они являются вероятностными классификаторами, поэтому будут вычислять вероятность каждой категории с использованием теоремы Байеса, и будет выведена категория с наивысшей вероятностью. Наивные байесовские классификаторы успешно применяются во многих областях, в частности, в обработке естественного языка (NLP).
  • У нас есть другие альтернативы при решении проблем NLP, такие как машина опорных векторов (SVM) и нейронные сети. Однако простая конструкция наивных байесовских классификаторов делает их очень привлекательными для таких классификаторов.
from sklearn.naive_bayes import MultinomialNB
model=MultinomialNB() #Create an instance of the CountVectorizer class.
model.fit(X_train,y_train) #Call the fit() function in order train the model
MultinomialNB(alpha=1.0, class_prior=None, fit_prior=True)
predict=model.predict(X_test)#Generating the predicted labels from the unused test set

Оценка модели

  • Истинно положительные результаты - это точки данных, классифицируемые моделью как положительные, которые на самом деле являются положительными (то есть они верны).
  • Ложноотрицательные значения - это точки данных, которые модель определяет как отрицательные, которые на самом деле являются положительными (неверными).
  • Ложные срабатывания - это случаи, когда модель неправильно помечает как положительные, а на самом деле отрицательные.
  • Отзыв: точное определение отзыва - это количество истинных положительных результатов, разделенное на количество истинных положительных результатов плюс количество ложных отрицательных результатов.
  • Точность: определяется как количество истинных положительных результатов, деленное на количество истинных положительных результатов плюс количество ложных срабатываний.
  • Оценка F1: это среднее гармоническое значение точности и запоминания. Используется оценка F1, поскольку носить оба этих параметра неудобно для всех целей подсчета очков.
from sklearn.metrics import f1_score
f1_score(y_test, predict, average='macro')
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, predict)
plt.matshow(cm)
plt.title('Confusion matrix')
plt.colorbar()
plt.ylabel('True label')
plt.xlabel('Predicted label')
plt.show()

Матрица неточностей - это таблица, которая часто используется для описания эффективности модели классификации (или «классификатора») на наборе тестовых данных, для которых известны истинные значения.

from sklearn.metrics import classification_report
print (classification_report(y_test, predict))
def visualize(label):
    words = ''
    for msg in df[df['label']==label]['review']:
        msg=msg.lower()
        words+=msg+ ''
    wordcloud = WordCloud(width=600, height=400).generate(words)
    plt.imshow(wordcloud)
    plt.axis('off')
    plt.title(label)
    plt.show()
visualize('pos')
visualize('neg')

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

Анализируя отзывы, которые были неправильно классифицированы

predict1=model.predict(bag_of_words) #generating prediction label on entire dataset
df_new= pd.read_csv('imdb_master.csv', error_bad_lines = False, encoding = 'ISO-8859-1', index_col = 0)
df_new=df_new.join(pd.DataFrame(predict1)) #appending the label for comparison
df_new.rename(columns={0:"n_label"},inplace=True)
df_test1= df_new[((df_new['label'] =='neg') & (df_new['n_label'] == 1))] #Negative reviews classified as positive
a=df_test1['review']
a=list(a)
a[:3]

Классификатор опорных векторов

  • В этом алгоритме мы строим каждый элемент данных как точку в n-мерном пространстве (где n - количество имеющихся у вас функций), причем значение каждой функции является значением конкретной координаты. Затем мы выполняем классификацию, находя оптимальную гиперплоскость, которая очень хорошо различает два класса.
  • Гиперплоскость будет точкой в ​​случае одномерных данных, линией в случае двухмерных данных, плоскостью в случае трехмерных данных и так далее.
from sklearn.svm import LinearSVC
clf = LinearSVC(random_state=0, tol=1e-5)
clf.fit(X_train,y_train) #Call the fit() function in order train the model
LinearSVC(C=1.0, class_weight=None, dual=True, fit_intercept=True,
     intercept_scaling=1, loss='squared_hinge', max_iter=1000,
     multi_class='ovr', penalty='l2', random_state=0, tol=1e-05, verbose=0)
predict=clf.predict(X_test) #Generating the predicted labels from the unused test set
from sklearn import metrics
acc_score = metrics.accuracy_score(y_test, predict)
f1_score = metrics.f1_score(y_test, predict, average='macro')
print('Total accuracy classification score: {}'.format(acc_score))
print('Total F1 classification score: {}'.format(f1_score))

2. TF-IDF (частота термина - частота обратного члена)

Чтение и предварительная обработка

  • Мы будем использовать тот же предварительно обработанный набор данных, который мы использовали для реализации лука.

TF-IDF

  • После предварительной обработки данных мы конвертируем предложения в вектор TF-IDF.
  • TF: Term Frequency - это отношение количества раз, когда слово встречается в тексте, к общему количеству слов в этом тексте.
  • IDF: частота обратных терминов - это отношение общего количества текстов к количеству текстов, содержащих определенные слова, которые мы ищем.

Чтобы найти вес (важность) конкретного слова, мы умножаем значение TF на значение IDF и представляем его в виде матрицы.

from sklearn.feature_extraction.text import TfidfVectorizer
tfidf = TfidfVectorizer(sublinear_tf=True, min_df=5,norm='l2', encoding='latin-1', ngram_range=(1, 2), stop_words='english')
features = tfidf.fit_transform(df1.review)
X_train, X_test, y_train, y_test = train_test_split(features, df1['b_label'], test_size=0.20, random_state=42)

Полиномиальный наивный байесовский классификатор

model=MultinomialNB() 
model.fit(X_train,y_train)
predict=model.predict(X_test)
acc_score = metrics.accuracy_score(y_test, predict)
f1_score = metrics.f1_score(y_test, predict, average='macro')
print('Total accuracy classification score: {}'.format(acc_score))
print('Total F1 classification score: {}'.format(f1_score))

Классификатор опорных векторов

from sklearn.svm import LinearSVC
clf = LinearSVC(random_state=0, tol=1e-5)
clf.fit(X_train,y_train)
LinearSVC(C=1.0, class_weight=None, dual=True, fit_intercept=True,
     intercept_scaling=1, loss='squared_hinge', max_iter=1000,
     multi_class='ovr', penalty='l2', random_state=0, tol=1e-05, verbose=0)
from sklearn import metrics
pred = clf.predict(X_test)
acc_score = metrics.accuracy_score(y_test, pred)
f1_score = metrics.f1_score(y_test, pred, average='macro')

print('Total accuracy classification score: {}'.format(acc_score))
print('Total F1 classification score: {}'.format(f1_score))

Заключение

  • Неудивительно, что tf-idf работает лучше, чем реализация Bag-Of-Words, поскольку модель учитывает важность слова.
  • SVC снова превосходит Multinomial NB.

3. N-ГРАММ.

Что такое N-граммы

  • N-граммы текстов широко используются в задачах интеллектуального анализа текста и обработки естественного языка. По сути, они представляют собой набор совпадающих слов или букв в заданном окне, и при вычислении n-граммов вы обычно перемещаетесь на одно слово или символ вперед.
  • N-граммы - это просто все комбинации соседних слов или букв длины n, которые вы можете найти в исходном тексте.
  • Например, учитывая слово name, все 2-граммы (или «биграммы») - это па, я и я. Это называется представлением символьных N-грамм, точнее, символьным представлением биграмм.
  • Например, для предложения «DSC Introduction to NLP Workshop». Если N = 2 (так называемые биграммы), то диаграммы будут следующими:
    1. Введение в DSC
    2. Введение в
    3. в НЛП
    4. Семинар по НЛП

Реализация N-Gram

sentence = 'Tyler, the Creator, is an American rapper, record producer, and music video director.'

for n in range(2,5,1):
    grams = ngrams(sentence.split(), n) #takes the tokens of the sentce and no of grams required as the input
    print('\n')
    print(n,' Grams')
    for i in grams:
        print(i)
t = "NLP is fun"
chrs = [c for c in t]

for n in range(1,5,1):
    grams = ngrams(chrs, n)#takes the tokens of the sentce and no of grams required as the input
    print('\n')
    print(n,' Grams')
    for i in grams:
        print(i)

Чтение и предварительная обработка

  • Мы будем использовать тот же предварительно обработанный набор данных, который мы использовали для реализации лука.

Сентиментальный анализ символов N-граммы и слова N-граммы

  • Выбор алгоритма останется таким же, как и в реализации BoW (например, Multinomial Naive Baiyes).
  • Входной вектор признаков изменится.

1. Юниграмма, биграммы и триграммы персонажей

countngram = CountVectorizer(analyzer='char',token_pattern=r'\w{1,}', ngram_range=(1,1))
ngram = countngram.fit_transform(df1['review'])
  • Мы используем анализатор и параметры n_gram.
    1. анализатор: строка, {‘word’, ‘char’, ‘char_wb’}
    Должна ли функция состоять из словарных или символьных н-граммов. Опция «char_wb» создает символьные n-граммы только из текста внутри границ слова; n-граммы по краям слов заполняются пробелами.
    2. ngram_range: tuple (min_n, max_n)
    Нижняя и верхняя границы диапазона n-значений для различных n-грамм, которые нужно извлечь. Будут использоваться все значения n такие, что min_n ‹= n‹ = max_n.

Полиномиальный наивный байесовский классификатор

X_train, X_test, y_train, y_test = train_test_split(ngram, df1['b_label'], test_size=0.20, random_state=42)
from sklearn.naive_bayes import MultinomialNB
model=MultinomialNB() #Create an instance of the CountVectorizer class.
model.fit(X_train,y_train) #Call the fit() function in order train the model
predict=model.predict(X_test)
acc_score = metrics.accuracy_score(y_test, predict)
f1_score = metrics.f1_score(y_test, predict, average='macro')
print('Total accuracy classification score: {}'.format(acc_score))
print('Total F1 classification score: {}'.format(f1_score))

Классификатор опорных векторов

from sklearn.svm import LinearSVC
clf = LinearSVC(random_state=0, tol=1e-5)
clf.fit(X_train,y_train
pred = clf.predict(X_test)
acc_score = metrics.accuracy_score(y_test, pred)
f1_score = metrics.f1_score(y_test, pred, average='macro')

print('Total accuracy classification score: {}'.format(acc_score))
print('Total F1 classification score: {}'.format(f1_score)

Заключение

  • Оценка F1 для всех трех моделей Multinoial NB:
    1. юниграмма: 0.6082673750024808
    2.биграмма: 0,7140269405433393
    3. триграмма: 0,7836180227571388
  • Оценка F1 для всех трех моделей для SVC:
    1. юниграмма: 0,4208909884125778
    2.биграмма: 0,7313761232427807
    3. триграмма: 0,8274787436560058
  • Ни одна из трех моделей не превосходит базовую реализацию BoW или tf-idf, поэтому символьная N-грамма не добавляет никакого дополнительного контекста к вектору признаков.
  • За исключением символов Unigram SVM превосходит Multinomial NB во всех случаях.

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