Классификация всего (CoE) — это негипотетическая структура, объясняющая все известные классификационные явления во Вселенной. Исследователи искали такую ​​модель с момента разработки вычислительной науки и теории информации Клода Шеннона в начале 20-го века. Вы хотите классифицировать, я собираюсь уточнить. Просто следуйте этой статье, и все будет хорошо!

Доверие — это хорошо, но классификация лучше!

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

Цель

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

  1. Установите Python

Загрузите Python и любую среду разработки (python.org). Используйте систему управления пакетами «Pip» для установки необходимых пакетов, модулей и библиотек.

Для общей независимой от платформы функциональности был установлен модуль «os». Модули «строка» и «nltk» использовались для процедур НЛП и стоп-слов. Для математических функций и многомерных матриц были установлены «Numpy» и «Pandas», для алгоритмов ML — «Scikit-Learn».

  • ОС, строка, nltk, numpy, pandas, scikit-learn

Просто сначала получите Python и среду разработки (IDE). Разбираемся с модулями и библиотеками со следующим кодом раз и навсегда. Просто убедитесь, что вы знаете, как использовать «Pip» заранее.

#Preprocessing
from string import punctuation
from string import digits
import nltk
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
# data import
import pandas as pd
import os
import numpy as np
# train test split
from sklearn.model_selection import train_test_split
#pipelines and classifier
from sklearn.pipeline import Pipeline
from sklearn.naive_bayes import MultinomialNB
from sklearn.linear_model import SGDClassifier 
from sklearn.neighbors import KNeighborsClassifier
from sklearn.neural_network import MLPClassifier
# validation
from sklearn.metrics import f1_score, precision_score, recall_score
# optimize
from sklearn.model_selection import GridSearchCV

2. Подготовка к предварительной обработке

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

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

def punctuation_number(text):
 
    remove_pun = str.maketrans('', '', punctuation)
    text_wo_pun = text.translate(remove_pun)
    remove_digits = str.maketrans('', '', digits)
    text_wo_num_pun = text_wo_pun.translate(remove_digits)
    
    return text_wo_num_pun

Вводятся так называемые «токенизаторы». Они помогают разделить текстовый документ на более мелкие части. Мы также используем «лемматизатор», он впоследствии преобразует каждый из терминов в его основную форму. Например, лемматизация идентифицирует базовую форму «иметь» как «иметь».

def tokenize_lemmatize(text):
    
    lemmatizer = WordNetLemmatizer()
    word_list = nltk.word_tokenize(text)
    lemmatized_output = ' '.join([lemmatizer.lemmatize(w) for w in       word_list])
    
    return lemmatized_output

В некоторых языках тоже есть странные буквы. Например, в немецком языке есть «умлауты», которые алгоритм не распознает. Следовательно, они также должны быть преобразованы в типичные буквы. Если вы англичанин, вам не нужно заботиться о следующей функции.

def remove_umlaut(text): 
    
    tempVar = text
    
    tempVar = tempVar.replace('ä', 'ae')
    tempVar = tempVar.replace('ö', 'oe')
    tempVar = tempVar.replace('ü', 'ue')
    tempVar = tempVar.replace('Ä', 'Ae')
    tempVar = tempVar.replace('Ö', 'Oe')
    tempVar = tempVar.replace('Ü', 'Ue')
    tempVar = tempVar.replace('ß', 'ss')

    return tempVar

На следующем этапе с помощью модуля nltk удаляются так называемые стоп-слова. Это список часто встречающихся терминов в языке, информационное содержание которых не имеет или имеет минимальное значение для классификации предмета. Мы хотим избавиться от них! Например, в английском языке «the», «is» и «and» называются стоп-словами. Но есть еще много!

stop_words = stopwords.words('english')

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

stop_words = stopwords.words('german')
german_stop_words = []
for word in stop_words:
     german_stop_words.append(remove_umlaut(word))

Чтобы сделать данные удобочитаемыми для алгоритма, в качестве инструмента NLP используется CountVectorizer, соответствующий методу Bag-of-Words. CountVectorizer предоставляется scikit-learn в Python. CountVectorizer используется для преобразования данного текста в вектор на основе частоты каждого слова.

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

vects = CountVectorizer(stop_words)

Кроме того, вводится дополнительная мера релевантности терминов в данных, которая определяет модифицированную схему взвешивания встречающихся терминов. tf-idf учитывает не только частоту термина (tf), но и обратную частоту документа (idf). Чем ниже значение idf слова, тем менее уникальным оно является для конкретного документа. Смотри сюда"!

tf_idf = TfidfTransformer(use_idf = True)

3. Импортируйте свои данные

Теперь мы готовы идти. Если ваши данные уже расположены в упорядоченном CSV-файле, разделенном текстом и классификатором, вы можете пропустить этот шаг. В противном случае продолжите следующую процедуру.

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

Так, например, все имена документов в папке, которые начинаются с XY, имеют метку Z. А документы, начинающиеся с AB, имеют метку C. (Например, все имена документов, начинающиеся с tennis_news, получают метку sports, а все имена документов, начинающиеся с selection_news, получают метку politics. .) Конечно, вы можете ввести более двух меток.

Благодаря этому назначению алгоритмы могут позже изучить общие черты класса. Вы можете использовать следующий код. Настройте только путь к вашим файлам и имя ярлыка. Легкий!

data_lst=[] #list with all the training data
label =[] #list with labels
for root, dirs, files in os.walk("C:\\Users\\nollr\\USED_DATA"): 
   #path with the data
   
   for name in files:
      if name.endswith(".txt"): # data saved as a txt file.
          file = os.path.join(root, name)
          file= open(file, "r")
          lines= file.read()
          
          lines = remove_umlaut(lines) 
          #replacing 'umlauts' for german texts
          
          lines = punctuation_number(lines) 
          #removing punctuation and numbers
          
          lines = tokenize_lemmatize(lines)
          #tokenize and lemmatize
          data_lst.append(lines)
          if name.startswith('XY'):
              label.append('Z')
          elif name.startswith('AB'):
              label.append('C')
          
          file.close()

4. Преобразуйте свои данные в CSV-файл и создайте матрицу данных

Документы преобразуются в формат данных CSV с помощью функции dataframe.to_csv() в Python и структурируются в формате столбцов с помощью словаря. Первый столбец содержит свободный текст данных, а второй столбец — метку соответствующего текста.

dict = {
        'text': data_lst,
        'class': label
        }
df = pd.DataFrame(dict)
df.to_csv('csv_data.csv',index=False,header=True) 
# store data in csv with two columns.

data = pd.read_csv('csv_data.csv') 
#text in column 1, classifier in column 2.
data_numpy_array = data.as_matrix() #create data matrix
X = data_numpy_array[:,0] #text
Y = data_numpy_array[:,1] #classifier

5. Тренировочный тестовый сплит

Метод разделения поезда-теста используется для сравнения производительности алгоритмов машинного обучения в прогнозном моделировании. В этом методе набор данных разбивается на два подмножества. Первое подмножество используется для соответствия модели машинного обучения и называется обучающим набором данных. Второе подмножество не используется для обучения модели. Вместо этого входной элемент набора данных предоставляется модели, чтобы затем сравнить сделанные прогнозы с ожидаемыми значениями. Этот второй набор данных называется набором тестовых данных и оценивает производительность модели машинного обучения на новых данных. Мы выбрали классический сплит 80:20. Смотри сюда"!

X_train, X_test, Y_train, Y_test = train_test_split(
X, Y, train_size = 0.8, random_state=1)

Теперь мы можем посмотреть на ЦМР тренировочных данных и проанализировать форму.

word_count_vector=vects.fit_transform(X_train)
word_count_vector.shape # (X, Y) X documents with Y unique words

4. Внедрение и создание конвейера для различных классификаторов

Теперь давайте повеселимся, собирая вещи вместе. Назначение конвейера – объединить несколько шагов (CountVectorizer, Tfidf, Classifier). Используемые нами классификаторы основаны на следующих методах: машина опорных векторов (SVM), наивный байесовский метод (NB), K-ближайший сосед (KNN) и многоуровневый классификатор персептрона (MLP). Они реализованы с помощью следующего кода.

text_clf_SVM = Pipeline([('vect', vects),
 ('tfidf', tf_idf),
 ('clf', SGDClassifier())
])
text_clf_NB = Pipeline([('vect', vects),
 ('tfidf', tf_idf),
 ('clf', MultinomialNB())
])
  
text_clf_KNN = Pipeline([('vect', vects),
 ('tfidf', tf_idf),
 ('clf', KNeighborsClassifier())
])
    
text_clf_MLP = Pipeline([('vect', vects),
 ('tfidf', tf_idf),
 ('clf', MLPClassifier())
])

5. Обучение и прогнозирование новых случаев

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

pred_NB = text_clf_NB.fit(X_train, Y_train).predict(X_test)
pred_SVM = text_clf_SVM.fit(X_train, Y_train).predict(X_test)
pred_KNN = text_clf_KNN.fit(X_train, Y_train).predict(X_test)
pred_MLP = text_clf_MLP.fit(X_train, Y_train).predict(X_test)

5. Проверка

Проверка модели — самая важная часть создания контролируемой модели.

Не используйте точность! Вместо этого используйте F1.

Показатель F1 можно использовать в качестве меры надежности статистического анализа при классификации. Значение состоит из двух параметров Precision и Recall. Оценка F1 часто используется в исследованиях обработки естественного языка, особенно при оценке предсказания именованных сущностей и сегментации слов.

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

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

Оценка F1 – это среднее гармоническое между Точность и Отзыв. Наибольшее значение показателя F1 равно 1,0, что означает оптимальное значение точности и отзыва. Если оценка принимает значение 0, одно из двух соотношений также равно 0.

F1 = 2 * ((точность*отзыв))/((точность+отзыв))

С помощью следующего кода вы получите результат для значений производительности!

print('\nNB_PRECISION: ', precision_score(pred_NB, Y_test, average='macro'))
print('NB_RECALL: ', recall_score(pred_NB, Y_test, average='macro'))
print('NB_F1: ', f1_score(pred_NB, Y_test, average='macro'))
print('\nSVM_PRECISION: ', precision_score(pred_SVM, Y_test, average='macro'))
print('SVM_RECALL: ', recall_score(pred_SVM, Y_test, average='macro'))
print('SVM_F1: ', f1_score(pred_SVM, Y_test, average='macro'))
print('\nKNN_PRECISION: ', precision_score(pred_KNN, Y_test, average='macro'))
print('KNN_RECALL: ', recall_score(pred_KNN, Y_test, average='macro'))
print('KNN_F1: ', f1_score(pred_KNN, Y_test, average='macro'))
print('\nMLP_PRECISION: ', precision_score(pred_MLP, Y_test, average='macro'))
print('MLP_RECALL: ', recall_score(pred_MLP, Y_test, average='macro'))
print('MLP_F1: ', f1_score(pred_KNN, Y_test, average='macro'))

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

Макрос (average = ‘macro’) означает, что мы сначала вычисляем оценку для каждого класса/ярлыка, а затем усредняем их.

6. Оптимизация

Если вам все еще недостаточно, вы можете улучшить свои результаты, оптимизировав гиперпараметры для каждого классификатора. Для получения дополнительной информации смотрите здесь!

Сначала вы должны определить ключи отдельных классификаторов.

text_clf_SVM.get_params().keys()
text_clf_NB.get_params().keys()
text_clf_KNN.get_params().keys()
text_clf_MLP.get_params().keys()

Затем вы можете приступить к поиску оптимального параметра с помощью GridSearch. Для этой цели параметры различных шагов могут быть установлены с использованием их имен и имени параметра, разделенных «__».

parameters = {
             'vect__ngram_range': [(1, 1), (1, 2)],
             'vect__max_df': (0.2, 0.5, 0.8, 1.0),
             'vect__min_df': (0.0, 0.01, 0.02, 1),
             'tfidf__use_idf': (True, False),
}
def gridsearch(classifier):
    gs_clf = GridSearchCV(classifier, parameters, n_jobs=-1, scoring='f1_macro')
    gs_clf = gs_clf.fit(X_train, Y_train)
    return gs_clf.best_params_
gridsearch(text_clf_SVM)
gridsearch(text_clf_NB)  
gridsearch(text_clf_KNN)  
gridsearch(text_clf_MLP)

Это было легко, верно? Есть хорошие результаты? Нашли ошибки? Скажи мне!

Рекомендуйте, комментируйте, делитесь, если вам понравилась эта статья.

Ссылки

https://scikit-learn.org