Imagen por editor
Con el creciente interés en el procesamiento del lenguaje natural, cada vez más profesionales se topan con la pared, no porque no puedan crear o ajustar los LLM, sino porque sus datos están desordenados.
Mostraremos procedimientos de codificación simples pero muy efectivos para corregir etiquetas ruidosas en datos de texto. Nos ocuparemos de 2 escenarios comunes en datos de texto del mundo real:
- Tener una categoría que contiene ejemplos mixtos de algunas otras categorías. Me encanta llamar a este tipo de categoría metacategoría.
- Tener 2 o más categorías que deben fusionarse en 1 categoría porque los textos que pertenecen a ellas se refieren al mismo tema.
Usaremos el conjunto de datos ITSM (Gestión de servicios de TI) creado para este tutorial (licencia CCO). Está disponible en Kaggle desde el siguiente enlace:
https://www.kaggle.com/datasets/nikolagreb/small-itsm-dataset
Es hora de comenzar con la importación de todas las bibliotecas necesarias y el examen de datos básicos. ¡Prepárate, el código está llegando!
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
Cada fila representa una entrada en la base de datos de ITSM. Intentaremos predecir la categoría del boleto en función del texto del boleto escrito por un usuario. Examinemos más a fondo los campos más importantes para los casos de uso empresarial descritos.
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
----------------------------------------------------------------------------------------------------
Si echamos un vistazo a los dos primeros tickets, aunque uno de ellos está en alemán, podemos ver que los problemas descritos se refieren al mismo software: Asana, pero llevan etiquetas diferentes. Esta es la distribución inicial de nuestras categorías:
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
La ayuda necesaria parece sospechosa, como la categoría que puede contener tickets de muchas otras categorías. Además, las categorías Outlook y Mail suenan similares, tal vez deberían fusionarse en una sola categoría. Antes de profundizar en las categorías mencionadas, nos desharemos de los valores faltantes en las columnas de nuestro interés.
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)
No existe un sustituto válido para el examen de datos a simple vista. La función elegante para hacerlo en pandas es .sample(), así que haremos exactamente eso una vez más, ahora para la categoría sospechosa:
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.
---------------------------------------------------------------------------
Obviamente, tenemos entradas que hablan de Discord, Asana y CRM. Por lo tanto, el nombre de la categoría debe cambiarse de "Se necesita ayuda" a categorías existentes más específicas. Para el primer paso del proceso de reasignación, crearemos la nueva columna “Palabras clave” que da la información si el ticket tiene la palabra de la lista de categorías en la columna “Texto”.
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)
Además, tenga en cuenta que el uso de "si palabra en str (palabras_categorías)" en lugar de "si palabra en palabras_categorías" captaría palabras de categorías con más de 1 palabra (navegador de Internet en nuestro caso), pero también requeriría más preprocesamiento de datos. Para mantener las cosas simples y directas, usaremos el código para las categorías hechas de una sola palabra. Así es como se ve nuestro conjunto de datos ahora:
df.head(2)
salida como imagen:
Después de extraer la columna de palabras clave, asumiremos la calidad de las entradas. Nuestra hipótesis:
- El boleto con solo 1 palabra clave en el campo Texto que es igual a la categoría a la que pertenece el boleto sería fácil de clasificar.
- Ticket con varias palabras clave en el campo Texto, donde al menos una de las palabras clave es la misma que la categoría a la que pertenece el ticket sería fácil de clasificar en la mayoría de los casos.
- El ticket que tiene palabras clave, pero ninguna de ellas es igual al nombre de la categoría a la que pertenece el ticket es probablemente un caso de etiqueta ruidosa.
- Otros boletos son neutrales según las palabras clave.
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
Hicimos nuestra nueva distribución y ahora es el momento de examinar los boletos clasificados como un problema potencial. En la práctica, el siguiente paso requeriría mucho más muestreo y observaría los fragmentos de datos más grandes a simple vista, pero la lógica sería la misma. Se supone que debe encontrar los tickets problemáticos y decidir si puede mejorar su calidad o si debe eliminarlos del conjunto de datos. Cuando se enfrente a un gran conjunto de datos, mantenga la calma y no olvide que el examen y la preparación de los datos suelen llevar mucho más tiempo que la creación de algoritmos de 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
--------------------------------------------------------------------
Entendemos que los tickets de las categorías de Outlook y Mail están relacionados con el mismo problema, por lo que fusionaremos estas 2 categorías y mejoraremos los resultados de nuestro futuro algoritmo de clasificación 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
Por último, pero no menos importante, queremos volver a etiquetar algunos tickets de la categoría meta "Se necesita ayuda" a la categoría adecuada.
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
Hicimos nuestro reetiquetado y limpieza de datos, pero no deberíamos llamarnos científicos de datos si no hacemos al menos un experimento científico y probamos el impacto de nuestro trabajo en la clasificación final. Lo haremos implementando el clasificador The Complement Naive Bayes en sklearn. Siéntase libre de probar otros algoritmos más complejos. Además, tenga en cuenta que se podría realizar una mayor limpieza de datos; por ejemplo, también podríamos descartar todos los tickets restantes en la categoría "Se necesita ayuda".
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
Bastante impresionante, ¿verdad? El conjunto de datos que usamos es pequeño (a propósito, para que pueda ver fácilmente lo que sucede en cada paso), por lo que diferentes semillas aleatorias pueden producir resultados diferentes, pero en la gran mayoría de los casos, el modelo funcionará significativamente mejor en el conjunto de datos después de la limpieza en comparación. al conjunto de datos original. ¡Hicimos un buen trabajo!
nikola greb Ha estado codificando durante más de cuatro años, y durante los últimos dos años se especializó en PNL. Antes de dedicarse a la ciencia de datos, tuvo éxito en ventas, recursos humanos, redacción y ajedrez.
- Distribución de relaciones públicas y contenido potenciado por SEO. Consiga amplificado hoy.
- Platoblockchain. Inteligencia del Metaverso Web3. Conocimiento amplificado. Accede Aquí.
- Acuñando el futuro con Adryenn Ashley. Accede Aquí.
- Fuente: 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
- :posee
- :es
- :no
- :dónde
- 1
- 10
- 100
- 11
- 2%
- 7
- 8
- 9
- a
- Acerca
- Mi Cuenta
- la exactitud
- Después
- Agente
- algoritmo
- algoritmos
- Todos
- también
- Aunque
- an
- y
- somos
- AS
- At
- Hoy Disponibles
- basado
- básica
- BE
- porque
- esto
- antes
- a continuación
- mejores
- bloqueado
- cada navegador
- build
- Construir la
- pero
- by
- llamar al
- PUEDEN
- llevar
- case
- cases
- GATO
- lucha
- categoría
- Categoría
- el cambio
- Ajedrez
- clasificación
- clasificado
- clasificar
- Limpieza
- Médico
- código
- Codificación
- Columna
- Columnas
- COM
- Algunos
- compañía
- en comparación con
- Complemento
- integraciones
- Contacto
- conexión
- contiene
- podría
- Para crear
- creado
- CRM
- datos
- Preparación de datos
- Ciencia de los datos
- Base de datos
- acuerdo
- tratar
- decidir
- más profundo
- descrito
- HIZO
- una experiencia diferente
- discord
- do
- don
- Soltar
- cada una
- pasan fácilmente
- Eficaz
- facilita
- entrada
- Éter (ETH)
- exactamente
- ejemplo
- ejemplos
- existente
- esperado
- experimento
- explicado
- ojos
- tener problemas con
- pocos
- campo
- Terrenos
- final
- Encuentre
- Nombre
- siguiendo
- Digital XNUMXk
- Gratuito
- en
- función
- promover
- futuras
- Alemán
- obtener
- Donar
- da
- Go
- candidato
- que sucede
- Tienen
- he
- auriculares
- ayuda
- golpeando
- Cómo
- hr
- HTTPS
- HubSpot
- i
- imagen
- Impacto
- implementación
- importar
- importante
- impresionante
- mejorar
- in
- índice
- información
- intereses
- Internet
- dentro
- IT
- Servicio de TI
- solo
- tan siquiera solo una
- nuggets
- Guardar
- Tipo
- Label
- Etiquetas
- idioma
- portátil
- large
- mayores
- bibliotecas
- Licencia
- como
- LINK
- Etiqueta LinkedIn
- Lista
- Mira
- mirando
- MIRADAS
- amar
- hecho
- Mayoría
- Management
- muchos
- Marketing
- Medios
- Miembros
- Salud Cerebral
- mencionado
- ir
- Meta
- Métrica
- podría
- que falta
- mezclado
- ML
- modelo
- más,
- MEJOR DE TU
- múltiples
- nombre
- Natural
- Lenguaje natural
- Procesamiento natural del lenguaje
- Neutro
- Nuevo
- nlp
- cuaderno
- ahora
- número
- numpy
- objeto
- of
- Oficina
- Viejo
- on
- ONE
- Optión
- or
- solicite
- reconocida por
- Otro
- nuestros
- Outlook
- salida
- Los pandas
- pasado
- PC
- realizar
- industrial
- Platón
- Inteligencia de datos de Platón
- PlatónDatos
- Por favor
- punto
- posible
- posible
- predecir
- probablemente
- Problema
- problemas
- procedimientos
- tratamiento
- producir
- apropiado
- propósito
- calidad
- azar
- mundo real
- relacionado
- representa
- exigir
- respuesta
- Resultados
- volvemos
- Eliminar
- creciente
- FILA
- ventas
- mismo
- escenarios
- Ciencia:
- los científicos
- ver
- semillas
- parece
- de coches
- set
- tienes
- Mostrar
- significativamente
- similares
- sencillos
- desde
- chica
- So
- Social
- redes sociales
- Software
- a medida
- algo
- Aislamiento de Sonido
- especializado
- soluciones y
- dividido
- comienzo
- Comience a
- quedarse
- paso
- detenido
- recto
- Cordón
- exitosos
- Supuesto
- suspicaz
- ¡Prepárate!
- escuchar
- hablar
- equipo
- Miembros del equipo
- test
- que
- esa
- El
- la información
- su
- Les
- Ahí.
- Estas
- ellos
- cosas
- así
- boleto
- entradas
- equipo
- a
- demasiado
- tema
- Total
- Entrenar
- Formación
- Turning
- tutoriales
- entender
- Actualizar
- actualizado
- us
- Uso
- utilizan el
- usado
- Usuario
- usando
- generalmente
- Valores
- Vasto
- muy
- vía
- Pared
- fue
- we
- ¿
- cuando
- que
- quien
- seguirá
- ventanas
- sin
- Palabra
- palabras
- Actividades:
- trabajando
- se
- la escritura
- escrito
- X
- años
- Usted
- a ti mismo
- zephyrnet