Изображение от редактора
С ростом интереса к обработке естественного языка все больше и больше практиков упираются в стену не потому, что они не могут построить или настроить LLM, а потому, что их данные беспорядочны!
Мы покажем простые, но очень эффективные процедуры кодирования для исправления зашумленных меток в текстовых данных. Мы будем иметь дело с двумя распространенными сценариями в реальных текстовых данных:
- Наличие категории, которая содержит смешанные примеры из нескольких других категорий. Я люблю называть такого рода категории метакатегорией.
- Наличие 2 или более категорий, которые следует объединить в 1 категорию, поскольку тексты, относящиеся к ним, относятся к одной и той же теме.
Мы будем использовать набор данных ITSM (управление ИТ-услугами), созданный для этого руководства (лицензия CCO). Он доступен на Kaggle по ссылке ниже:
https://www.kaggle.com/datasets/nikolagreb/small-itsm-dataset
Пришло время начать с импорта всех необходимых библиотек и проверки основных данных. Приготовьтесь, код придет!
import pandas as pd
import numpy as np
import string from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import ComplementNB
from sklearn.pipeline import make_pipeline
from sklearn.model_selection import train_test_split
from sklearn import metrics df = pd.read_excel("ITSM_data.xlsx")
df.info()
RangeIndex: 118 entries, 0 to 117
Data columns (total 7 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 ID_request 118 non-null int64 1 Text 117 non-null object 2 Category 115 non-null object 3 Solution 115 non-null object 4 Date_request_recieved 118 non-null datetime64[ns] 5 Date_request_solved 118 non-null datetime64[ns] 6 ID_agent 118 non-null int64 dtypes: datetime64[ns](2), int64(2), object(3)
memory usage: 6.6+ KB
Каждая строка представляет одну запись в базе данных ITSM. Мы попытаемся предсказать категорию тикета на основе текста тикета, написанного пользователем. Давайте более подробно рассмотрим наиболее важные поля для описанных вариантов использования в бизнесе.
for text, category in zip(df.Text.sample(3, random_state=2), df.Category.sample(3, random_state=2)): print("TEXT:") print(text) print("CATEGORY:") print(category) print("-"*100)
TEXT:
I just want to talk to an agent, there are too many problems on my pc to be explained in one ticket. Please call me when you see this, whoever you are. (talk to agent)
CATEGORY:
Asana
----------------------------------------------------------------------------------------------------
TEXT:
Asana funktionierte nicht mehr, nachdem ich meinen Laptop neu gestartet hatte. Bitte helfen Sie.
CATEGORY:
Help Needed
----------------------------------------------------------------------------------------------------
TEXT:
My mail stopped to work after I updated Windows.
CATEGORY:
Outlook
----------------------------------------------------------------------------------------------------
Если мы посмотрим на первые два тикета, хотя один тикет на немецком языке, мы увидим, что описанные проблемы относятся к одному и тому же программному обеспечению — Asana, но имеют разные метки. Это стартовая раздача наших категорий:
df.Category.value_counts(normalize=True, dropna=False).mul(100).round(1).astype(str) + "%"
Outlook 19.1%
Discord 13.9%
CRM 12.2%
Internet Browser 10.4%
Mail 9.6%
Keyboard 9.6%
Asana 8.7%
Mouse 8.7%
Help Needed 7.8%
Name: Category, dtype: object
Необходимая помощь выглядит подозрительно, как и категория, которая может содержать заявки из нескольких других категорий. Кроме того, категории Outlook и Mail звучат одинаково, возможно, их следует объединить в одну категорию. Прежде чем углубиться в упомянутые категории, мы избавимся от пропущенных значений в интересующих нас столбцах.
important_columns = ["Text", "Category"]
for cat in important_columns: df.drop(df[df[cat].isna()].index, inplace=True)
df.reset_index(inplace=True, drop=True)
Нет достойной замены проверке данных невооруженным глазом. Причудливая функция для этого в pandas — .sample(), поэтому мы сделаем именно это еще раз, теперь для подозрительной категории:
meta = df[df.Category == "Help Needed"] for text in meta.Text.sample(5, random_state=2): print(text) print("-"*100)
Discord emojis aren't available to me, I would like to have this option enabled like other team members have.
---------------------------------------------------------------------------
Bitte reparieren Sie mein Hubspot CRM. Seit gestern funktioniert es nicht mehr
---------------------------------------------------------------------------
My headphones aren't working. I would like to order new.
---------------------------------------------------------------------------
Bundled problems with Office since restart:
Messages not sent
Outlook does not connect, mails do not arrive
Error 0x8004deb0 appears when Connection attempt, see attachment
The company account is affected: AB123
Access via Office.com seems to be possible.
---------------------------------------------------------------------------
Asana funktionierte nicht mehr, nachdem ich meinen Laptop neu gestartet hatte. Bitte helfen Sie.
---------------------------------------------------------------------------
Очевидно, у нас есть билеты, говорящие о Discord, Asana и CRM. Поэтому название категории следует изменить с «Требуется помощь» на существующие, более конкретные категории. На первом этапе процесса переназначения мы создадим новый столбец «Ключевые слова», в котором будет информация о том, есть ли в заявке слово из списка категорий в столбце «Текст».
words_categories = np.unique([word.strip().lower() for word in df.Category]) # list of categories def keywords(row): list_w = [] for word in row.translate(str.maketrans("", "", string.punctuation)).lower().split(): if word in words_categories: list_w.append(word) return list_w df["Keywords"] = df.Text.apply(keywords) # since our output is in the list, this function will give us better looking final output. def clean_row(row): row = str(row) row = row.replace("[", "") row = row.replace("]", "") row = row.replace("'", "") row = string.capwords(row) return row df["Keywords"] = df.Keywords.apply(clean_row)
Кроме того, обратите внимание, что использование «if word in str(words_categories)» вместо «if word in words_categories» будет отлавливать слова из категорий, содержащих более 1 слова (в нашем случае интернет-браузера), но также потребует дополнительной предварительной обработки данных. Чтобы все было просто и понятно, мы будем использовать код для категорий, состоящих всего из одного слова. Вот как теперь выглядит наш набор данных:
df.head(2)
вывод как изображение:
После извлечения столбца ключевых слов мы будем исходить из качества билетов. Наша гипотеза:
- Билет с одним ключевым словом в текстовом поле, которое совпадает с категорией, к которой принадлежит билет, будет легко классифицировать.
- Билет с несколькими ключевыми словами в текстовом поле, где хотя бы одно из ключевых слов совпадает с категорией, к которой принадлежит билет, в большинстве случаев будет легко классифицировать.
- Заявка, в которой есть ключевые слова, но ни одно из них не совпадает с названием категории, к которой принадлежит заявка, вероятно, является шумным случаем с этикеткой.
- Другие билеты являются нейтральными на основе ключевых слов.
cl_list = [] for category, keywords in zip(df.Category, df.Keywords): if category.lower() == keywords.lower() and keywords != "": cl_list.append("easy_classification") elif category.lower() in keywords.lower(): # to deal with multiple keywords in the ticket cl_list.append("probably_easy_classification") elif category.lower() != keywords.lower() and keywords != "": cl_list.append("potential_problem") else: cl_list.append("neutral") df["Ease_classification"] = cl_list
df.Ease_classification.value_counts(normalize=True, dropna=False).mul(100).round(1).astype(str) + "%"
neutral 45.6%
easy_classification 37.7%
potential_problem 9.6%
probably_easy_classification 7.0%
Name: Ease_classification, dtype: object
Мы сделали новый дистрибутив, и сейчас самое время изучить тикеты, классифицированные как потенциальные проблемы. На практике следующий шаг потребует гораздо большей выборки и просмотра больших фрагментов данных невооруженным глазом, но обоснование будет таким же. Вы должны найти проблемные заявки и решить, можете ли вы улучшить их качество или вам следует исключить их из набора данных. Когда вы сталкиваетесь с большим набором данных, сохраняйте спокойствие и не забывайте, что проверка и подготовка данных обычно занимают гораздо больше времени, чем построение алгоритмов машинного обучения!
pp = df[df.Ease_classification == "potential_problem"] for text, category in zip(pp.Text.sample(5, random_state=2), pp.Category.sample(3, random_state=2)): print("TEXT:") print(text) print("CATEGORY:") print(category) print("-"*100)
TEXT:
outlook issue , I did an update Windows and I have no more outlook on my notebook ? Please help !
Outlook
CATEGORY:
Mail
-------------------------------------------------------------------- TEXT:
Please relase blocked attachements from the mail I got from name.surname@company.com. These are data needed for social media marketing campaing.
CATEGORY:
Outlook
--------------------------------------------------------------------
TEXT:
Asana funktionierte nicht mehr, nachdem ich meinen Laptop neu gestartet hatte. Bitte helfen Sie.
CATEGORY:
Help Needed
--------------------------------------------------------------------
Мы понимаем, что заявки из категорий Outlook и Mail связаны с одной и той же проблемой, поэтому объединим эти 2 категории и улучшим результаты нашего будущего алгоритма классификации ML.
mail_categories_to_merge = ["Outlook", "Mail"] sum_mail_cluster = 0
for x in mail_categories_to_merge: sum_mail_cluster += len(df[df["Category"] == x]) print("Number of categories to be merged into new cluster: ", len(mail_categories_to_merge))
print("Expected number of tickets in the new cluster: ", sum_mail_cluster) def rename_to_mail_cluster(category): if category in mail_categories_to_merge: category = "Mail_CLUSTER" else: category = category return category df["Category"] = df["Category"].apply(rename_to_mail_cluster) df.Category.value_counts()
Number of categories to be merged into new cluster: 2
Expected number of tickets in the new cluster: 33
Mail_CLUSTER 33
Discord 15
CRM 14
Internet Browser 12
Keyboard 11
Asana 10
Mouse 10
Help Needed 9
Name: Category, dtype: int64
И последнее, но не менее важное: мы хотим переименовать некоторые заявки из мета-категории «Требуется помощь» в соответствующую категорию.
df.loc[(df["Category"] == "Help Needed") & ([set(x).intersection(words_categories) for x in df["Text"].str.lower().str.replace("[^ws]", "", regex=True).str.split()]), "Category"] = "Change" def cat_name_change(cat, keywords): if cat == "Change": cat = keywords else: cat = cat return cat df["Category"] = df.apply(lambda x: cat_name_change(x.Category, x.Keywords), axis=1)
df["Category"] = df["Category"].replace({"Crm":"CRM"}) df.Category.value_counts(dropna=False)
Mail_CLUSTER 33
Discord 16
CRM 15
Internet Browser 12
Asana 11
Keyboard 11
Mouse 10
Help Needed 6
Name: Category, dtype: int64
Мы сделали перемаркировку и очистку данных, но нам не следует называть себя учеными данных, если мы не проведем хотя бы один научный эксперимент и не проверим влияние нашей работы на окончательную классификацию. Мы сделаем это, внедрив классификатор Complement Naive Bayes в sklearn. Не стесняйтесь пробовать другие, более сложные алгоритмы. Кроме того, имейте в виду, что может быть выполнена дальнейшая очистка данных — например, мы также можем удалить все заявки, оставшиеся в категории «Требуется помощь».
model = make_pipeline(TfidfVectorizer(), ComplementNB()) # old df
df_o = pd.read_excel("ITSM_data.xlsx") important_categories = ["Text", "Category"]
for cat in important_categories: df_o.drop(df_o[df_o[cat].isna()].index, inplace=True) df_o.name = "dataset just without missing"
df.name = "dataset after deeper cleaning" for dataframe in [df_o, df]: # Split dataset into training set and test set X_train, X_test, y_train, y_test = train_test_split(dataframe.Text, dataframe.Category, test_size=0.2, random_state=1) # Training the model with train data model.fit(X_train, y_train) # Predict the response for test dataset y_pred = model.predict(X_test) print(f"Accuracy of Complement Naive Bayes classifier model on {dataframe.name} is: {round(metrics.accuracy_score(y_test, y_pred),2)}")
Accuracy of Complement Naive Bayes classifier model on dataset just without missing is: 0.48
Accuracy of Complement Naive Bayes classifier model on dataset after deeper cleaning is: 0.65
Довольно впечатляюще, правда? Набор данных, который мы использовали, небольшой (намеренно, чтобы вы могли легко увидеть, что происходит на каждом этапе), поэтому разные случайные начальные значения могут давать разные результаты, но в подавляющем большинстве случаев модель будет работать значительно лучше на наборе данных после очистки по сравнению с к исходному набору данных. Мы хорошо поработали!
Никола Греб занимается программированием более четырех лет, а последние два года специализировался на НЛП. Прежде чем заняться наукой о данных, он был успешным в продажах, HR, писательстве и шахматах.
- SEO-контент и PR-распределение. Получите усиление сегодня.
- Платоблокчейн. Интеллект метавселенной Web3. Расширение знаний. Доступ здесь.
- Чеканка будущего с Эдриенн Эшли. Доступ здесь.
- Источник: https://www.kdnuggets.com/2023/04/dealing-noisy-labels-text-data.html?utm_source=rss&utm_medium=rss&utm_campaign=dealing-with-noisy-labels-in-text-data
- :имеет
- :является
- :нет
- :куда
- 1
- 10
- 100
- 11
- 2%
- 7
- 8
- 9
- a
- О нас
- Учетная запись
- точность
- После
- Агент
- алгоритм
- алгоритмы
- Все
- Также
- Несмотря на то, что
- an
- и
- МЫ
- AS
- At
- доступен
- основанный
- основной
- BE
- , так как:
- было
- до
- ниже
- Лучшая
- заблокировал
- браузер
- строить
- Строительство
- бизнес
- но
- by
- призывают
- CAN
- нести
- случаев
- случаев
- КПП
- Привлекайте
- категории
- Категории
- изменение
- шахматы
- классификация
- классифицированный
- классифицировать
- Уборка
- Кластер
- код
- Кодирование
- Column
- Колонки
- COM
- Общий
- Компания
- сравненный
- комплемент
- комплекс
- Свяжитесь
- связи
- содержит
- может
- Создайте
- создали
- CRM
- данным
- Подготовка данных
- наука о данных
- База данных
- сделка
- занимавшийся
- решать
- более глубокий
- описано
- DID
- различный
- раздор
- распределение
- do
- Дон
- Падение
- каждый
- легко
- Эффективный
- включен
- запись
- Эфир (ETH)
- точно,
- пример
- Примеры
- существующий
- ожидаемый
- эксперимент
- объяснены
- Глаза
- всего лишь пяти граммов героина
- несколько
- поле
- Поля
- окончательный
- Найдите
- First
- после
- Что касается
- 4
- Бесплатно
- от
- функция
- далее
- будущее
- Немецкий
- получить
- Дайте
- дает
- Go
- хорошо
- происходит
- Есть
- he
- наушники
- помощь
- ударять
- Как
- hr
- HTTPS
- HubSpot
- i
- изображение
- Влияние
- Осуществляющий
- Импортировать
- важную
- впечатляющий
- улучшать
- in
- индекс
- информация
- вместо
- интерес
- Интернет
- в
- вопрос
- IT
- ИТ сервис
- всего
- только один
- КДнаггетс
- Сохранить
- Вид
- этикетка
- Этикетки
- язык
- портативный компьютер
- большой
- больше
- библиотеки
- Лицензия
- такое как
- LINK
- Список
- посмотреть
- искать
- ВЗГЛЯДЫ
- любят
- сделанный
- Большинство
- управление
- многих
- Маркетинг
- Медиа
- Участники
- Память
- упомянутый
- идти
- Мета
- Метрика
- может быть
- отсутствующий
- смешанный
- ML
- модель
- БОЛЕЕ
- самых
- с разными
- имя
- натуральный
- Естественный язык
- Обработка естественного языка
- необходимый
- Нейтральные
- Новые
- НЛП
- ноутбук
- сейчас
- номер
- NumPy
- объект
- of
- Офис
- Старый
- on
- ONE
- Опция
- or
- заказ
- оригинал
- Другое
- наши
- Outlook
- выходной
- панд
- мимо
- PC
- выполнять
- трубопровод
- Платон
- Платон Интеллектуальные данные
- ПлатонДанные
- пожалуйста
- Точка
- возможное
- потенциал
- практика
- предсказывать
- вероятно
- Проблема
- проблемам
- Процедуры
- процесс
- обработка
- производит
- правильный
- цель
- случайный
- реальный мир
- Связанный
- представляет
- требовать
- ответ
- Итоги
- возвращают
- избавиться
- повышение
- РЯД
- главная
- то же
- Сценарии
- Наука
- Ученые
- посмотреть
- семена
- кажется
- обслуживание
- набор
- должен
- показывать
- существенно
- аналогичный
- просто
- с
- небольшой
- So
- Соцсети
- социальные сети
- Software
- Решение
- некоторые
- Звук
- специализированный
- конкретный
- раскол
- Начало
- Начало
- оставаться
- Шаг
- остановившийся
- прямой
- строка
- успешный
- предполагаемый
- подозрительный
- взять
- Говорить
- говорить
- команда
- Члены команды
- тестXNUMX
- чем
- который
- Ассоциация
- информация
- их
- Их
- Там.
- Эти
- они
- вещи
- этой
- билет
- билеты
- время
- в
- слишком
- тема
- Всего
- Train
- Обучение
- Поворот
- учебник
- понимать
- Обновление ПО
- обновление
- us
- Применение
- использование
- используемый
- Информация о пользователе
- через
- обычно
- Наши ценности
- Огромная
- очень
- с помощью
- стена
- законопроект
- we
- Что
- когда
- который
- кто бы ни
- будете
- окна
- без
- Word
- слова
- Работа
- работает
- бы
- письмо
- письменный
- X
- лет
- являетесь
- себя
- зефирнет