Obraz autorstwa redaktora
Wraz z rosnącym zainteresowaniem przetwarzaniem języka naturalnego coraz więcej praktyków uderza w ścianę nie dlatego, że nie mogą budować ani dostrajać LLM, ale dlatego, że ich dane są bałaganiarskie!
Pokażemy proste, ale bardzo skuteczne procedury kodowania poprawiające zaszumione etykiety w danych tekstowych. Zajmiemy się 2 typowymi scenariuszami w rzeczywistych danych tekstowych:
- Posiadanie kategorii zawierającej mieszane przykłady z kilku innych kategorii. Uwielbiam nazywać tego rodzaju kategorię metakategorią.
- Posiadanie 2 lub więcej kategorii, które należy połączyć w 1 kategorię, ponieważ należące do nich teksty odnoszą się do tego samego tematu.
Wykorzystamy zestaw danych ITSM (IT Service Management) utworzony na potrzeby tego samouczka (licencja CCO). Jest dostępny na Kaggle z poniższego linku:
https://www.kaggle.com/datasets/nikolagreb/small-itsm-dataset
Czas zacząć od zaimportowania wszystkich potrzebnych bibliotek i podstawowego zbadania danych. Przygotuj się, nadchodzi kod!
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
Każdy wiersz reprezentuje jeden wpis w bazie danych ITSM. Postaramy się przewidzieć kategorię biletu na podstawie tekstu biletu napisanego przez użytkownika. Przyjrzyjmy się bliżej najważniejszym obszarom opisanych przypadków użycia biznesowego.
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
----------------------------------------------------------------------------------------------------
Jeśli przyjrzymy się dwóm pierwszym biletom, mimo że jeden jest w języku niemieckim, zobaczymy, że opisane problemy dotyczą tego samego oprogramowania?—?Asana, ale mają różne etykiety. Rozpoczyna się dystrybucja naszych kategorii:
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
Potrzebna pomoc wygląda podejrzanie, podobnie jak kategoria, która może zawierać bilety z wielu innych kategorii. Również kategorie Outlook i Mail brzmią podobnie, być może powinny zostać połączone w jedną kategorię. Zanim zagłębimy się we wspomniane kategorie, pozbędziemy się brakujących wartości w interesujących nas kolumnach.
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)
Nie ma ważnego substytutu badania danych gołym okiem. Fajną funkcją do tego w pandach jest .sample(), więc zrobimy dokładnie to jeszcze raz, teraz dla podejrzanej kategorii:
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.
---------------------------------------------------------------------------
Oczywiście mamy bilety mówiące o Discord, Asanie i CRM. Należy więc zmienić nazwę kategorii z „Potrzebna pomoc” na istniejące, bardziej szczegółowe kategorie. W pierwszym kroku procesu zmiany przydziału utworzymy nową kolumnę „Słowa kluczowe”, która poda informację, czy zgłoszenie posiada słowo z listy kategorii w kolumnie „Tekst”.
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)
Zwróć też uwagę, że użycie „if word in str(words_categories)” zamiast „if word inwords_categories” przechwytywałoby słowa z kategorii zawierających więcej niż 1 słowo (w naszym przypadku przeglądarka internetowa), ale wymagałoby również więcej wstępnego przetwarzania danych. Aby zachować prostotę i prostotę, pójdziemy z kodem dla kategorii składających się tylko z jednego słowa. Tak wygląda teraz nasz zbiór danych:
df.head(2)
wyjście jako obraz:
Po wyodrębnieniu kolumny słów kluczowych przyjmiemy jakość zgłoszeń. Nasza hipoteza:
- Bilet z tylko 1 słowem kluczowym w polu tekstowym, który jest taki sam jak kategoria, do której należy bilet, byłby łatwy do sklasyfikowania.
- Bilet z wieloma słowami kluczowymi w polu Tekst, gdzie przynajmniej jedno ze słów kluczowych jest tożsame z kategorią, do której należy bilet, w większości przypadków będzie łatwy do sklasyfikowania.
- Bilet, który ma słowa kluczowe, ale żadne z nich nie jest tożsame z nazwą kategorii, do której należy bilet, to prawdopodobnie głośna etykieta.
- Inne bilety są neutralne w oparciu o słowa kluczowe.
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
Zrobiliśmy naszą nową dystrybucję i teraz jest czas na zbadanie biletów sklasyfikowanych jako potencjalny problem. W praktyce następny krok wymagałby znacznie większego próbkowania i spojrzenia na większe fragmenty danych gołym okiem, ale uzasadnienie byłoby takie samo. Twoim zadaniem jest znalezienie problematycznych biletów i podjęcie decyzji, czy możesz poprawić ich jakość, czy też usunąć je ze zbioru danych. Kiedy masz do czynienia z dużym zbiorem danych, zachowaj spokój i nie zapominaj, że analiza i przygotowanie danych zwykle zajmuje dużo więcej czasu niż budowanie algorytmów ML!
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
--------------------------------------------------------------------
Rozumiemy, że zgłoszenia z kategorii Outlook i Mail dotyczą tego samego problemu, dlatego połączymy te 2 kategorie i poprawimy wyniki naszego przyszłego algorytmu klasyfikacji 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
Na koniec chcemy zmienić etykietę niektórych zgłoszeń z metakategorii „Potrzebna pomoc” na odpowiednią kategorię.
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
Przeprowadziliśmy ponowne etykietowanie i czyszczenie danych, ale nie powinniśmy nazywać się naukowcami danych, jeśli nie przeprowadzimy przynajmniej jednego eksperymentu naukowego i nie sprawdzimy wpływu naszej pracy na ostateczną klasyfikację. Zrobimy to, implementując klasyfikator The Complement Naive Bayes w sklearn. Zachęcamy do wypróbowania innych, bardziej złożonych algorytmów. Należy również pamiętać, że można przeprowadzić dalsze czyszczenie danych — na przykład możemy również usunąć wszystkie zgłoszenia pozostawione w kategorii „Potrzebna pomoc”.
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
Całkiem imponujące, prawda? Zbiór danych, którego użyliśmy, jest mały (celowo, aby można było łatwo zobaczyć, co dzieje się na każdym kroku), więc różne losowe ziarna mogą dawać różne wyniki, ale w zdecydowanej większości przypadków model będzie działał znacznie lepiej na zbiorze danych po oczyszczeniu w porównaniu do oryginalnego zestawu danych. Wykonaliśmy dobrą robotę!
Nikola Greb programuje od ponad czterech lat, a od dwóch lat specjalizuje się w NLP. Zanim zajął się nauką o danych, odnosił sukcesy w sprzedaży, HR, pisaniu i szachach.
- Dystrybucja treści i PR oparta na SEO. Uzyskaj wzmocnienie już dziś.
- Platoblockchain. Web3 Inteligencja Metaverse. Wzmocniona wiedza. Dostęp tutaj.
- Wybijanie przyszłości w Adryenn Ashley. Dostęp tutaj.
- Źródło: 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
- :ma
- :Jest
- :nie
- :Gdzie
- 1
- 10
- 100
- 11
- 2%
- 7
- 8
- 9
- a
- O nas
- Konto
- precyzja
- Po
- Agent
- algorytm
- Algorytmy
- Wszystkie kategorie
- również
- Chociaż
- an
- i
- SĄ
- AS
- At
- dostępny
- na podstawie
- podstawowy
- BE
- bo
- być
- zanim
- poniżej
- Ulepsz Swój
- zablokowany
- przeglądarka
- budować
- Budowanie
- biznes
- ale
- by
- wezwanie
- CAN
- nieść
- walizka
- Etui
- CAT
- zapasy
- kategorie
- Kategoria
- zmiana
- Szachy
- klasyfikacja
- sklasyfikowany
- Klasyfikuj
- Sprzątanie
- Grupa
- kod
- Kodowanie
- Kolumna
- kolumny
- COM
- wspólny
- sukcesy firma
- w porównaniu
- Komplement
- kompleks
- Skontaktuj się
- połączenie
- zawiera
- mógłby
- Stwórz
- stworzony
- CRM
- dane
- Przygotowywanie danych
- nauka danych
- Baza danych
- sprawa
- czynienia
- zdecydować
- głębiej
- opisane
- ZROBIŁ
- różne
- niezgoda
- 分配
- do
- darowizna
- Spadek
- każdy
- z łatwością
- Efektywne
- włączony
- wejście
- Eter (ETH)
- dokładnie
- przykład
- przykłady
- Przede wszystkim system został opracowany
- spodziewany
- eksperyment
- wyjaśnione
- oko
- okładzina
- kilka
- pole
- Łąka
- finał
- Znajdź
- i terminów, a
- następujący
- W razie zamówieenia projektu
- cztery
- Darmowy
- od
- funkcjonować
- dalej
- przyszłość
- niemiecki
- otrzymać
- Dać
- daje
- Go
- dobry
- dzieje
- Have
- he
- słuchawki
- pomoc
- uderzanie
- W jaki sposób
- hr
- HTTPS
- HubSpot
- i
- obraz
- Rezultat
- wykonawczych
- importować
- ważny
- imponujący
- podnieść
- in
- wskaźnik
- Informacja
- zamiast
- odsetki
- Internet
- najnowszych
- problem
- IT
- obsługa informatyczna
- właśnie
- tylko jeden
- Knuggety
- Trzymać
- Uprzejmy
- Etykieta
- Etykiety
- język
- laptopa
- duży
- większe
- biblioteki
- Licencja
- lubić
- LINK
- Lista
- Popatrz
- poszukuje
- WYGLĄD
- miłość
- zrobiony
- Większość
- i konserwacjami
- wiele
- Marketing
- Media
- Użytkownicy
- Pamięć
- wzmiankowany
- Łączyć
- Meta
- Metryka
- może
- brakujący
- mieszany
- ML
- model
- jeszcze
- większość
- wielokrotność
- Nazwa
- Naturalny
- Język naturalny
- Przetwarzanie języka naturalnego
- potrzebne
- Neutralny
- Nowości
- nlp
- notatnik
- już dziś
- numer
- tępy
- przedmiot
- of
- Biurowe
- Stary
- on
- ONE
- Option
- or
- zamówienie
- oryginalny
- Inne
- ludzkiej,
- Outlook
- wydajność
- pandy
- Przeszłość
- PC
- wykonać
- rurociąg
- plato
- Analiza danych Platona
- PlatoDane
- Proszę
- punkt
- możliwy
- potencjał
- praktyka
- przewidzieć
- prawdopodobnie
- Problem
- problemy
- procedury
- wygląda tak
- przetwarzanie
- produkować
- właściwy
- cel
- jakość
- przypadkowy
- Prawdziwy świat
- związane z
- reprezentuje
- wymagać
- odpowiedź
- Efekt
- powrót
- Pozbyć się
- podniesienie
- RZĄD
- sole
- taki sam
- scenariusze
- nauka
- Naukowcy
- widzieć
- posiew
- wydaje
- usługa
- zestaw
- powinien
- pokazać
- znacznie
- podobny
- Prosty
- ponieważ
- mały
- So
- Obserwuj Nas
- Media społecznościowe
- Tworzenie
- rozwiązanie
- kilka
- Dźwięk
- wyspecjalizowanym
- specyficzny
- dzielić
- początek
- Startowy
- pobyt
- Ewolucja krok po kroku
- zatrzymany
- proste
- sznur
- udany
- domniemany
- podejrzliwy
- Brać
- Mówić
- rozmawiać
- zespół
- Członkowie Zespołu
- test
- niż
- że
- Połączenia
- Informacje
- ich
- Im
- Tam.
- Te
- one
- rzeczy
- to
- bilet
- bilety
- czas
- do
- także
- aktualny
- Kwota produktów:
- Pociąg
- Trening
- Obrócenie
- Tutorial
- zrozumieć
- Aktualizacja
- zaktualizowane
- us
- Stosowanie
- posługiwać się
- używany
- Użytkownik
- za pomocą
- zazwyczaj
- Wartości
- Naprawiono
- początku.
- przez
- Ściana
- była
- we
- Co
- jeśli chodzi o komunikację i motywację
- który
- ktokolwiek
- będzie
- okna
- w
- bez
- słowo
- słowa
- Praca
- pracujący
- by
- pisanie
- napisany
- X
- lat
- ty
- siebie
- zefirnet