Imagine de editor
Odată cu creșterea interesului pentru procesarea limbajului natural, din ce în ce mai mulți practicieni se lovesc de zid nu pentru că nu pot construi sau ajusta LLM-uri, ci pentru că datele lor sunt dezordonate!
Vom arăta proceduri de codare simple, dar foarte eficiente pentru remedierea etichetelor zgomotoase în datele text. Ne vom ocupa de 2 scenarii comune în datele text din lumea reală:
- Având o categorie care conține exemple mixte din alte câteva categorii. Îmi place să numesc acest tip de categorie meta categorie.
- Având 2 sau mai multe categorii care ar trebui îmbinate într-o singură categorie deoarece textele care le aparțin se referă la același subiect.
Vom folosi setul de date ITSM (IT Service Management) creat pentru acest tutorial (licență CCO). Este disponibil pe Kaggle din linkul de mai jos:
https://www.kaggle.com/datasets/nikolagreb/small-itsm-dataset
Este timpul să începem cu importul tuturor bibliotecilor necesare și cu examinarea datelor de bază. Pregătiți-vă, codul vine!
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
Fiecare rând reprezintă o intrare în baza de date ITSM. Vom încerca să prezicem categoria biletului pe baza textului biletului scris de un utilizator. Să examinăm mai profund cele mai importante domenii pentru cazurile de utilizare descrise în afaceri.
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
----------------------------------------------------------------------------------------------------
Dacă ne uităm la primele două bilete, deși un bilet este în germană, putem vedea că problemele descrise se referă la același software? —? Asana, dar poartă etichete diferite. Aceasta începe distribuirea categoriilor noastre:
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
Ajutorul necesar pare suspect, la fel ca categoria care poate conține bilete din mai multe alte categorii. De asemenea, categoriile Outlook și Mail sună similar, poate ar trebui să fie îmbinate într-o singură categorie. Înainte de a ne aprofunda în categoriile menționate, vom scăpa de valorile lipsă din coloanele de interes.
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)
Nu există un substitut valid pentru examinarea datelor cu ochiul liber. Funcția de lux pentru a face acest lucru în panda este .sample(), așa că vom face exact asta încă o dată, acum pentru categoria suspectă:
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.
---------------------------------------------------------------------------
Evident, avem bilete care vorbesc despre Discord, Asana și CRM. Deci, numele categoriei ar trebui schimbat din „Ajutor necesar” în categorii existente, mai specifice. Pentru primul pas al procesului de reatribuire, vom crea noua coloană „Cuvinte cheie” care oferă informații dacă biletul are cuvântul din lista de categorii din coloana „Text”.
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)
De asemenea, rețineți că folosirea „dacă cuvânt în str(words_categories)” în loc de „dacă cuvânt în words_categories” ar prinde cuvinte din categorii cu mai mult de 1 cuvânt (Internet Browser în cazul nostru), dar ar necesita și mai multă preprocesare a datelor. Pentru a menține lucrurile simple și drepte la obiect, vom merge cu codul pentru categoriile format dintr-un singur cuvânt. Iată cum arată acum setul nostru de date:
df.head(2)
ieșire ca imagine:
După extragerea coloanei de cuvinte cheie, ne vom asumă calitatea biletelor. Ipoteza noastra:
- Biletul cu un singur cuvânt cheie în câmpul Text care este același cu categoria căreia îi aparține biletul ar fi ușor de clasificat.
- Biletul cu mai multe cuvinte cheie în câmpul Text, unde cel puțin unul dintre cuvintele cheie este același cu categoria căreia îi aparține biletul, ar fi ușor de clasificat în majoritatea cazurilor.
- Biletul care are cuvinte cheie, dar niciunul dintre ele nu este egal cu numele categoriei căreia îi aparține biletul este probabil un caz de etichetă zgomotos.
- Alte bilete sunt neutre pe baza cuvintelor cheie.
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
Am făcut noua noastră distribuție și acum este momentul să examinăm biletele clasificate ca o potențială problemă. În practică, următorul pas ar necesita mult mai mult eșantionare și ar analiza bucățile mai mari de date cu ochiul liber, dar rațiunea ar fi aceeași. Ar trebui să găsiți bilete problematice și să decideți dacă le puteți îmbunătăți calitatea sau dacă ar trebui să le eliminați din setul de date. Când vă confruntați cu un set de date mare, rămâneți calm și nu uitați că examinarea și pregătirea datelor durează de obicei mult mai mult timp decât construirea algoritmilor 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
--------------------------------------------------------------------
Înțelegem că biletele din categoriile Outlook și Mail sunt legate de aceeași problemă, așa că vom îmbina aceste 2 categorii și vom îmbunătăți rezultatele viitorului nostru algoritm de clasificare 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
Nu în ultimul rând, vrem să reetichetăm unele bilete din metacategoria „Ajutor necesar” la categoria corespunzătoare.
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
Ne-am reetichetat și curățat datele, dar nu ar trebui să ne numim cercetători de date dacă nu facem cel puțin un experiment științific și nu testăm impactul muncii noastre asupra clasificării finale. Vom face acest lucru prin implementarea clasificatorului Complement Naive Bayes în sklearn. Simțiți-vă liber să încercați alți algoritmi mai complexi. De asemenea, rețineți că s-ar putea face o curățare suplimentară a datelor - de exemplu, am putea elimina și toate biletele rămase în categoria „Ajutor necesar”.
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
Destul de impresionant, nu? Setul de date pe care l-am folosit este mic (în mod intenționat, astfel încât să puteți vedea cu ușurință ce se întâmplă în fiecare pas), astfel încât diferite semințe aleatorii ar putea produce rezultate diferite, dar în marea majoritate a cazurilor, modelul va funcționa semnificativ mai bine pe setul de date după curățare comparativ cu la setul de date original. Am făcut o treabă bună!
Nikola Greb codifică de mai bine de patru ani, iar în ultimii doi ani s-a specializat în NLP. Înainte de a se ocupa de știința datelor, a avut succes în vânzări, resurse umane, scris și șah.
- Distribuție de conținut bazat pe SEO și PR. Amplifică-te astăzi.
- Platoblockchain. Web3 Metaverse Intelligence. Cunoștințe amplificate. Accesați Aici.
- Mintând viitorul cu Adryenn Ashley. Accesați Aici.
- Sursa: 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
- :are
- :este
- :nu
- :Unde
- 1
- 10
- 100
- 11
- 2%
- 7
- 8
- 9
- a
- Despre Noi
- Cont
- precizie
- După
- Agent
- Algoritmul
- algoritmi
- TOATE
- de asemenea
- Cu toate ca
- an
- și
- SUNT
- AS
- At
- disponibil
- bazat
- de bază
- BE
- deoarece
- fost
- înainte
- de mai jos
- Mai bine
- blocat
- browser-ul
- construi
- Clădire
- afaceri
- dar
- by
- apel
- CAN
- transporta
- caz
- cazuri
- CAT
- Captură
- categorii
- Categorii
- Schimbare
- Şah
- clasificare
- clasificate
- Clasifica
- Curățenie
- Grup
- cod
- Codificare
- Coloană
- Coloane
- COM
- Comun
- companie
- comparație
- Completa
- complex
- Conectați
- conexiune
- conține
- ar putea
- crea
- a creat
- CRM
- de date
- Pregătirea datelor
- știința datelor
- Baza de date
- afacere
- abuzive
- decide
- Mai adânc
- descris
- FĂCUT
- diferit
- discordie
- distribuire
- do
- don
- Picătură
- fiecare
- cu ușurință
- Eficace
- activat
- intrare
- Eter (ETH)
- exact
- exemplu
- exemple
- existent
- de aşteptat
- experiment
- a explicat
- ochi
- cu care se confruntă
- puțini
- camp
- Domenii
- final
- Găsi
- First
- următor
- Pentru
- patru
- Gratuit
- din
- funcţie
- mai mult
- viitor
- Germană
- obține
- Da
- oferă
- Go
- bine
- se întâmplă
- Avea
- he
- Căşti
- ajutor
- lovind
- Cum
- hr
- HTTPS
- HubSpot
- i
- imagine
- Impactul
- Punere în aplicare a
- import
- important
- impresionant
- îmbunătăţi
- in
- index
- informații
- in schimb
- interes
- Internet
- în
- problema
- IT
- Serviciu IT
- doar
- doar unul
- KDnuggets
- A pastra
- Copil
- Etichetă
- etichete
- limbă
- laptop
- mare
- mai mare
- biblioteci
- Licență
- ca
- LINK
- Listă
- Uite
- cautati
- Se pare
- dragoste
- făcut
- Majoritate
- administrare
- multe
- Marketing
- Mass-media
- Membri actuali
- Memorie
- menționat
- Îmbina
- meta
- Metrici
- ar putea
- dispărut
- mixt
- ML
- model
- mai mult
- cele mai multe
- multiplu
- nume
- Natural
- Limbajul natural
- Procesarea limbajului natural
- necesar
- Neutru
- Nou
- nlp
- caiet
- acum
- număr
- NumPy
- obiect
- of
- Birou
- Vechi
- on
- ONE
- Opțiune
- or
- comandă
- original
- Altele
- al nostru
- Perspectivă
- producție
- panda
- trecut
- PC
- efectua
- conducte
- Plato
- Informații despre date Platon
- PlatoData
- "vă rog"
- Punct
- posibil
- potenţial
- practică
- prezice
- probabil
- Problemă
- probleme
- Proceduri
- proces
- prelucrare
- produce
- adecvat
- scop
- calitate
- aleator
- lumea reală
- legate de
- reprezintă
- necesita
- răspuns
- REZULTATE
- reveni
- Scăpa
- în creștere
- RÂND
- de vânzări
- acelaşi
- scenarii
- Ştiinţă
- oamenii de stiinta
- vedea
- seminţe
- pare
- serviciu
- set
- să
- Arăta
- semnificativ
- asemănător
- simplu
- întrucât
- mic
- So
- Social
- social media
- Software
- soluţie
- unele
- Suna
- de specialitate
- specific
- împărţi
- Începe
- Pornire
- şedere
- Pas
- oprit
- drept
- Şir
- de succes
- a presupus
- suspicios
- Lua
- Vorbi
- vorbesc
- echipă
- Membrii echipei
- test
- decât
- acea
- informațiile
- lor
- Lor
- Acolo.
- Acestea
- ei
- lucruri
- acest
- bilet
- bilete
- timp
- la
- de asemenea
- subiect
- Total
- Tren
- Pregătire
- Cotitură
- tutorial
- înţelege
- Actualizează
- actualizat
- us
- Folosire
- utilizare
- utilizat
- Utilizator
- folosind
- obișnuit
- Valori
- Fixă
- foarte
- de
- Perete
- a fost
- we
- Ce
- cand
- care
- oricine
- voi
- ferestre
- cu
- fără
- Cuvânt
- cuvinte
- Apartamente
- de lucru
- ar
- scris
- scris
- X
- ani
- tu
- te
- zephyrnet