Immagine dell'editore
Con il crescente interesse per l'elaborazione del linguaggio naturale, sempre più professionisti stanno colpendo il muro non perché non siano in grado di costruire o mettere a punto LLM, ma perché i loro dati sono disordinati!
Mostreremo procedure di codifica semplici ma molto efficaci per fissare etichette rumorose nei dati di testo. Tratteremo 2 scenari comuni nei dati di testo del mondo reale:
- Avere una categoria che contiene esempi misti di poche altre categorie. Mi piace chiamare questo tipo di categoria una meta categoria.
- Avere 2 o più categorie che dovrebbero essere unite in 1 categoria perché i testi che le appartengono si riferiscono allo stesso argomento.
Useremo il set di dati ITSM (IT Service Management) creato per questo tutorial (licenza CCO). È disponibile su Kaggle dal link sottostante:
https://www.kaggle.com/datasets/nikolagreb/small-itsm-dataset
È tempo di iniziare con l'importazione di tutte le librerie necessarie e l'esame dei dati di base. Preparati, il codice sta arrivando!
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
Ogni riga rappresenta una voce nel database ITSM. Cercheremo di prevedere la categoria del biglietto in base al testo del biglietto scritto da un utente. Esaminiamo più in profondità i campi più importanti per i casi d'uso aziendali descritti.
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
----------------------------------------------------------------------------------------------------
Se diamo un'occhiata ai primi due biglietti, anche se uno dei biglietti è in tedesco, possiamo vedere che i problemi descritti si riferiscono allo stesso software?—?Asana, ma portano etichette diverse. Questa è l'inizio della distribuzione delle nostre categorie:
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
L'aiuto necessario sembra sospetto, come la categoria che può contenere ticket di più altre categorie. Inoltre, le categorie Outlook e Mail sembrano simili, forse dovrebbero essere unite in un'unica categoria. Prima di approfondire le categorie menzionate, elimineremo i valori mancanti nelle colonne di nostro interesse.
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)
Non c'è un valido sostituto per l'esame dei dati ad occhio nudo. La funzione di fantasia per farlo nei panda è .sample(), quindi lo faremo ancora una volta, ora per la categoria sospetta:
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.
---------------------------------------------------------------------------
Ovviamente, abbiamo biglietti che parlano di Discord, Asana e CRM. Quindi il nome della categoria dovrebbe essere cambiato da "Aiuto necessario" a categorie esistenti e più specifiche. Per la prima fase del processo di riassegnazione, creeremo la nuova colonna "Parole chiave" che fornisce le informazioni se il ticket ha la parola dall'elenco delle categorie nella colonna "Testo".
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)
Inoltre, si noti che l'utilizzo di "if word in str(words_categories)" invece di "if word in words_categories" catturerebbe parole da categorie con più di 1 parola (browser Internet nel nostro caso), ma richiederebbe anche una maggiore preelaborazione dei dati. Per mantenere le cose semplici e dritte al punto, andremo con il codice per le categorie composte da una sola parola. Ecco come appare ora il nostro set di dati:
df.head(2)
output come immagine:
Dopo aver estratto la colonna delle parole chiave, assumeremo la qualità dei biglietti. La nostra ipotesi:
- Il biglietto con solo 1 parola chiave nel campo Testo che è la stessa della categoria a cui appartiene il biglietto sarebbe facile da classificare.
- Ticket con più parole chiave nel campo Testo, dove almeno una delle parole chiave è la stessa della categoria a cui appartiene il biglietto sarebbe facile da classificare nella maggior parte dei casi.
- Il ticket che ha parole chiave, ma nessuna di esse è uguale al nome della categoria a cui appartiene il ticket è probabilmente un caso di etichetta rumorosa.
- Altri ticket sono neutri in base alle parole chiave.
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
Abbiamo fatto la nostra nuova distribuzione e ora è il momento di esaminare i biglietti classificati come un potenziale problema. In pratica, il passaggio successivo richiederebbe un campionamento molto maggiore e l'osservazione a occhio nudo di blocchi di dati più grandi, ma la logica sarebbe la stessa. Dovresti trovare i ticket problematici e decidere se puoi migliorarne la qualità o se dovresti eliminarli dal set di dati. Quando ti trovi di fronte a un set di dati di grandi dimensioni, mantieni la calma e non dimenticare che l'esame e la preparazione dei dati di solito richiedono molto più tempo rispetto alla creazione di algoritmi 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
--------------------------------------------------------------------
Comprendiamo che i ticket delle categorie Outlook e Mail sono correlati allo stesso problema, quindi uniremo queste 2 categorie e miglioreremo i risultati del nostro futuro algoritmo di classificazione 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
Ultimo, ma non meno importante, vogliamo rietichettare alcuni ticket dalla meta categoria "Aiuto necessario" alla categoria appropriata.
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
Abbiamo rietichettato e ripulito i dati, ma non dovremmo definirci data scientist se non facciamo almeno un esperimento scientifico e testiamo l'impatto del nostro lavoro sulla classificazione finale. Lo faremo implementando il classificatore Complement Naive Bayes in sklearn. Sentiti libero di provare altri algoritmi più complessi. Inoltre, tieni presente che potrebbe essere eseguita un'ulteriore pulizia dei dati, ad esempio potremmo anche eliminare tutti i ticket rimasti nella categoria "Aiuto necessario".
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
Abbastanza impressionante, vero? Il set di dati che abbiamo utilizzato è piccolo (apposta, quindi puoi facilmente vedere cosa succede in ogni passaggio), quindi semi casuali diversi potrebbero produrre risultati diversi, ma nella stragrande maggioranza dei casi, il modello funzionerà significativamente meglio sul set di dati dopo la pulizia rispetto al set di dati originale. Abbiamo fatto un buon lavoro!
Nikola Greb codifica da più di quattro anni e negli ultimi due anni si è specializzato in PNL. Prima di dedicarsi alla scienza dei dati, ha avuto successo nelle vendite, nelle risorse umane, nella scrittura e negli scacchi.
- Distribuzione di contenuti basati su SEO e PR. Ricevi amplificazione oggi.
- Platoblockchain. Web3 Metaverse Intelligence. Conoscenza amplificata. Accedi qui.
- Coniare il futuro con Adryenn Ashley. Accedi qui.
- Fonte: 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
- :ha
- :È
- :non
- :Dove
- 1
- 10
- 100
- 11
- 2%
- 7
- 8
- 9
- a
- Chi siamo
- Il mio account
- precisione
- Dopo shavasana, sedersi in silenzio; saluti;
- Agente
- algoritmo
- Algoritmi
- Tutti
- anche
- Sebbene il
- an
- ed
- SONO
- AS
- At
- disponibile
- basato
- basic
- BE
- perché
- stato
- prima
- sotto
- Meglio
- bloccato
- del browser
- costruire
- Costruzione
- affari
- ma
- by
- chiamata
- Materiale
- trasportare
- Custodie
- casi
- CAT
- lotta
- categoria
- Categoria
- il cambiamento
- Scacchi
- classificazione
- classificato
- classificare
- Pulizia
- Cluster
- codice
- codifica
- Colonna
- colonne
- COM
- Uncommon
- azienda
- rispetto
- Complemento
- complesso
- Connettiti
- veloce
- contiene
- potuto
- creare
- creato
- CRM
- dati
- Preparazione dei dati
- scienza dei dati
- Banca Dati
- affare
- trattare
- decide
- più profondo
- descritta
- DID
- diverso
- discordia
- distribuzione
- do
- don
- Cadere
- ogni
- facilmente
- Efficace
- abilitato
- iscrizione
- Etere (ETH)
- di preciso
- esempio
- Esempi
- esistente
- previsto
- esperimento
- ha spiegato
- occhio
- di fronte
- pochi
- campo
- campi
- finale
- Trovare
- Nome
- i seguenti
- Nel
- quattro
- Gratis
- da
- function
- ulteriormente
- futuro
- Tedesco
- ottenere
- Dare
- dà
- Go
- buono
- accade
- Avere
- he
- cuffia
- Aiuto
- colpire
- Come
- hr
- HTTPS
- HubSpot
- i
- Immagine
- Impact
- Implementazione
- importare
- importante
- impressionante
- competenze
- in
- Index
- informazioni
- invece
- interesse
- Internet
- ai miglioramenti
- problema
- IT
- Servizio IT
- ad appena
- solo uno
- KDnuggets
- mantenere
- Genere
- Discografica
- per il tuo brand
- Lingua
- laptop
- grandi
- superiore, se assunto singolarmente.
- biblioteche
- Licenza
- piace
- LINK
- Lista
- Guarda
- cerca
- SEMBRA
- amore
- fatto
- Maggioranza
- gestione
- molti
- Marketing
- Media
- Utenti
- Memorie
- menzionato
- Unire
- Meta
- Metrica
- forza
- mancante
- misto
- ML
- modello
- Scopri di più
- maggior parte
- multiplo
- Nome
- Naturale
- Linguaggio naturale
- Elaborazione del linguaggio naturale
- di applicazione
- Neutres
- New
- nlp
- taccuino
- adesso
- numero
- numpy
- oggetto
- of
- Office
- Vecchio
- on
- ONE
- Opzione
- or
- minimo
- i
- Altro
- nostro
- Outlook
- produzione
- panda
- passato
- PC
- eseguire
- conduttura
- Platone
- Platone Data Intelligence
- PlatoneDati
- per favore
- punto
- possibile
- potenziale
- pratica
- predire
- probabilmente
- Problema
- problemi
- procedure
- processi
- lavorazione
- produrre
- corretto
- scopo
- qualità
- casuale
- mondo reale
- relazionato
- rappresenta
- richiedere
- risposta
- Risultati
- ritorno
- Rid
- crescita
- RIGA
- vendite
- stesso
- Scenari
- Scienze
- scienziati
- vedere
- semi
- sembra
- servizio
- set
- dovrebbero
- mostrare attraverso le sue creazioni
- significativamente
- simile
- Un'espansione
- da
- piccole
- So
- Social
- Social Media
- Software
- soluzione
- alcuni
- Suono
- specializzata
- specifico
- dividere
- inizia a
- Di partenza
- soggiorno
- step
- fermato
- dritto
- Corda
- di successo
- suppone
- sospettoso
- Fai
- Parlare
- parlando
- team
- Membri del team
- test
- di
- che
- I
- le informazioni
- loro
- Li
- Là.
- Strumenti Bowman per analizzare le seguenti finiture:
- di
- cose
- questo
- biglietto
- biglietti
- tempo
- a
- pure
- argomento
- Totale
- Treni
- Training
- Svolta
- lezione
- capire
- Aggiornanento
- aggiornato
- us
- Impiego
- uso
- utilizzato
- Utente
- utilizzando
- generalmente
- Valori
- Fisso
- molto
- via
- Muro
- Prima
- we
- Che
- quando
- quale
- chiunque
- volere
- finestre
- con
- senza
- Word
- parole
- Lavora
- lavoro
- sarebbe
- scrittura
- scritto
- X
- anni
- Tu
- te stesso
- zefiro