K-Nearest Neighbors (KNN) y Procesamiento de Texto

K-Nearest Neighbors (KNN)

Características Fundamentales

K-Nearest Neighbors es un algoritmo no paramétrico que no realiza estimaciones de parámetros durante el proceso de entrenamiento. Esta característica lo distingue de otros algoritmos de machine learning, ya que almacena toda la información del conjunto de entrenamiento y realiza los cálculos únicamente durante la fase de predicción.

El algoritmo se basa en el principio de proximidad, utilizando distancias entre observaciones para tomar decisiones. Para problemas de clasificación, KNN asigna la clase mediante mayoría de votos entre los k vecinos más cercanos, mientras que para regresión calcula el promedio de los valores de los k vecinos.

Hiperparámetros Clave de KNN

Número de Vecinos (k)

La selección del valor k es crucial para el rendimiento del algoritmo. Valores pequeños de k pueden hacer que el modelo sea sensible al ruido, mientras que valores grandes pueden causar que el modelo se vuelva demasiado simple. Es recomendable usar valores impares para problemas de clasificación para evitar empates.

Métricas de Distancia

KNN utiliza diferentes métricas para calcular la proximidad entre puntos de datos:

Distancia Euclidiana: La más común, mide la distancia en línea recta entre dos puntos. Su fórmula es: deuclidiana(x,y)=i=1n(xiyi)2d_{euclidiana}(x, y) = \sqrt{\sum_{i=1}^{n} (x_i - y_i)^2}

Distancia Manhattan: También conocida como distancia de ciudad, suma las diferencias absolutas de las coordenadas. Es útil cuando los datos siguen patrones de cuadrícula: dmanhattan(x,y)=i=1nxiyid_{manhattan}(x, y) = \sum_{i=1}^{n} |x_i - y_i|

Distancia Minkowski: Generalización que incluye las anteriores según el parámetro p. Cuando p=1 es Manhattan, cuando p=2 es Euclidiana: dminkowski(x,y)=(i=1nxiyip)1/pd_{minkowski}(x, y) = \left(\sum_{i=1}^{n} |x_i - y_i|^p\right)^{1/p}

Distancia Chebyshev: Mide la diferencia máxima entre coordenadas, útil cuando el movimiento diagonal es equivalente al recto.

Pesos

KNN puede asignar pesos uniformes (todos los vecinos tienen la misma influencia) o pesos basados en distancia (vecinos más cercanos tienen mayor influencia).

Ejemplos de Código para KNN

from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_classification
import numpy as np

# Generar datos de ejemplo
X, y = make_classification(n_samples=1000, n_features=4, n_classes=3, 
                          n_informative=3, random_state=42)

# Dividir datos
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Crear modelo KNN
knn = KNeighborsClassifier(
    n_neighbors=5,        # k = 5 vecinos
    metric='euclidean',   # métrica de distancia
    weights='uniform'     # pesos uniformes
)

# Entrenar modelo
knn.fit(X_train, y_train)

# Realizar predicciones
y_pred = knn.predict(X_test)

# Evaluar precisión
accuracy = knn.score(X_test, y_test)
print(f"Precisión: {accuracy:.3f}")

Para regresión, el proceso es similar usando KNeighborsRegressor:

from sklearn.neighbors import KNeighborsRegressor
from sklearn.datasets import make_regression

# Generar datos de regresión
X, y = make_regression(n_samples=1000, n_features=3, noise=0.1, random_state=42)

# Crear modelo KNN para regresión
knn_reg = KNeighborsRegressor(
    n_neighbors=5,
    metric='euclidean',
    weights='distance'  # pesos basados en distancia
)

# Entrenar y predecir
knn_reg.fit(X_train, y_train)
y_pred = knn_reg.predict(X_test)

Procesamiento de Texto

Limpieza de Texto

El procesamiento de texto comienza con la limpieza, que incluye varios pasos fundamentales:

Conversión a Minúsculas

Estandariza el texto para que palabras como “Casa” y “casa” sean tratadas de manera idéntica.

Remoción de Acentos

Normaliza caracteres con acentos para reducir la variabilidad del vocabulario.

Eliminación de Caracteres Especiales

Remueve puntuación, números y símbolos que pueden no ser relevantes para el análisis.

import re
from unicodedata import normalize

def limpiar_texto(texto):
    # Convertir a minúsculas
    texto = texto.lower()
    
    # Remover acentos
    texto = normalize('NFD', texto).encode('ascii', 'ignore').decode('utf-8')
    
    # Remover caracteres especiales y números
    texto = re.sub(r'[^a-z\s]', '', texto)
    
    # Remover espacios extra
    texto = ' '.join(texto.split())
    
    return texto

Stop Words

Las stop words son palabras comunes que aparecen frecuentemente en un idioma pero aportan poco valor semántico. Ejemplos incluyen “el”, “la”, “de”, “que”, “y”, “a”.

Cuándo Remover Stop Words

Tareas que se benefician de la remoción:

  • Clasificación de texto y análisis de sentimientos
  • Recuperación de información y motores de búsqueda
  • Modelado de temas y clustering
  • Extracción de palabras clave

Tareas que requieren preservar stop words:

  • Traducción automática (mantiene estructura gramatical)
  • Resumen de texto (preserva coherencia de oraciones)
  • Sistemas de preguntas y respuestas
  • Verificación gramatical y parsing
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize

def remover_stopwords(texto, idioma='spanish'):
    # Tokenizar
    tokens = word_tokenize(texto)
    
    # Obtener stop words
    stop_words = set(stopwords.words(idioma))
    
    # Filtrar tokens
    tokens_filtrados = [token for token in tokens if token not in stop_words]
    
    return tokens_filtrados

Count Vectorizer

Count Vectorizer transforma texto en una representación matricial basada en frecuencias de palabras. Cada documento se representa como un vector donde cada dimensión corresponde a una palabra única del corpus, y el valor es la frecuencia de esa palabra en el documento.

Características del Count Vectorizer

  • Tokenización: Divide el texto en tokens individuales
  • Conteo: Cuenta la frecuencia de cada token
  • Vectorización: Representa el texto en formato matricial
from sklearn.feature_extraction.text import CountVectorizer
import pandas as pd

# Corpus de ejemplo
corpus = [
    "me gusta el fútbol",
    "no me gusta el básquet", 
    "el fútbol es divertido",
    "el básquet es aburrido"
]

# Crear Count Vectorizer
vectorizer = CountVectorizer(
    stop_words=None,    # no remover stop words automáticamente
    lowercase=True,     # convertir a minúsculas
    max_features=20     # máximo 20 características
)

# Transformar corpus
X = vectorizer.fit_transform(corpus)

# Mostrar vocabulario
print("Vocabulario:")
print(vectorizer.get_feature_names_out())

# Crear DataFrame para visualizar
df = pd.DataFrame(X.toarray(), columns=vectorizer.get_feature_names_out())

TF-IDF Vectorizer

TF-IDF (Term Frequency-Inverse Document Frequency) es una medida estadística que evalúa la importancia de una palabra en un documento dentro de una colección. Combina dos componentes:

Term Frequency (TF)

Mide cuántas veces aparece una palabra en un documento: TF=NuˊmeroderepeticionesdelapalabraNuˊmerototaldepalabraseneldocumentoTF = \frac{Número de repeticiones de la palabra}{Número total de palabras en el documento}

Inverse Document Frequency (IDF)

Mide qué tan común o rara es una palabra en todo el corpus: IDF=log(NuˊmerototaldedocumentosNuˊmerodedocumentosquecontienenlapalabra)IDF = \log\left(\frac{Número total de documentos}{Número de documentos que contienen la palabra}\right)

TF-IDF Final

TFIDF=TF×IDFTF-IDF = TF \times IDF

TF-IDF es superior a Count Vectorizer porque reduce el peso de palabras muy frecuentes que aparecen en muchos documentos y aumenta el peso de palabras distintivas.

from sklearn.feature_extraction.text import TfidfVectorizer

# Crear TF-IDF Vectorizer
tfidf_vectorizer = TfidfVectorizer(
    lowercase=True,
    max_features=20,
    stop_words=None
)

# Transformar corpus
X_tfidf = tfidf_vectorizer.fit_transform(corpus)

# Crear DataFrame
df_tfidf = pd.DataFrame(
    X_tfidf.toarray(), 
    columns=tfidf_vectorizer.get_feature_names_out()
)

print("Matriz TF-IDF:")
print(df_tfidf.round(3))

Ingeniería de Variables de Texto

La ingeniería de características de texto va más allá del simple conteo de palabras. Incluye extracción de características avanzadas que pueden proporcionar información adicional sobre el contenido del texto.

Características Estructurales

Longitud del texto: Número de caracteres y palabras Características tipográficas: Conteo de mayúsculas, signos de puntuación, números Elementos de redes sociales: Emojis, URLs, menciones (@usuario), hashtags (#etiqueta)

import re

def extraer_caracteristicas_texto(texto):
    características = {}
    
    # Longitud del texto
    características['longitud_caracteres'] = len(texto)
    características['longitud_palabras'] = len(texto.split())
    
    # Conteo de caracteres especiales
    características['num_mayusculas'] = sum(1 for c in texto if c.isupper())
    características['num_signos_puntuacion'] = sum(1 for c in texto if c in '.,!?;:')
    características['num_numeros'] = sum(1 for c in texto if c.isdigit())
    
    # Conteo de emojis (patrón básico)
    emojis = re.findall(r'[😀-🙏🌀-🗿]', texto)
    características['num_emojis'] = len(emojis)
    
    # Conteo de URLs
    urls = re.findall(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', texto)
    características['num_urls'] = len(urls)
    
    return características

Características Lingüísticas

N-gramas: Secuencias de n palabras adyacentes que capturan contexto. Los bigramas (n=2) y trigramas (n=3) son particularmente útiles para entender relaciones entre palabras.

Etiquetado POS (Part-of-Speech): Identifica la función gramatical de cada palabra (sustantivo, verbo, adjetivo).

Reconocimiento de Entidades Nombradas (NER): Identifica y categoriza entidades como personas, organizaciones, lugares.

Ejemplo Práctico: Clasificación de Texto con KNN

La combinación de KNN con procesamiento de texto es efectiva para tareas de clasificación de documentos. El siguiente ejemplo muestra una implementación completa:

from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics import classification_report
from sklearn.pipeline import Pipeline

# Dataset de ejemplo para clasificación de sentimientos
textos = [
    "me encanta este producto es increíble",
    "odio este servicio es terrible",
    "el producto está bien no es malo",
    "excelente calidad muy recomendado",
    "pésima experiencia nunca más"
]

# Etiquetas: 0=negativo, 1=neutral, 2=positivo
etiquetas = [2, 0, 1, 2, 0]

# Crear pipeline combinando TF-IDF y KNN
pipeline = Pipeline([
    ('tfidf', TfidfVectorizer(
        lowercase=True,
        max_features=100,
        ngram_range=(1, 2)  # unigramas y bigramas
    )),
    ('knn', KNeighborsClassifier(
        n_neighbors=3,
        metric='cosine',  # cosine es efectiva para texto
        weights='distance'
    ))
])

# Entrenar pipeline
pipeline.fit(textos, etiquetas)

# Predecir nuevos textos
texto_nuevo = ["este producto es bueno pero caro"]
prediccion = pipeline.predict(texto_nuevo)

Consideraciones para la Optimización

Selección de Hiperparámetros

La validación cruzada es esencial para encontrar el valor óptimo de k. El método del codo puede ayudar a identificar el punto donde el rendimiento deja de mejorar significativamente.

Escalamiento de Características

Para datos de texto vectorizados, es importante considerar el escalamiento cuando se combinan diferentes tipos de características. Las matrices sparse de TF-IDF requieren consideraciones especiales en el preprocessing.

Métricas Específicas para Texto

La similaridad del coseno es particularmente efectiva para datos de texto representados como vectores TF-IDF, ya que normaliza por la longitud del documento y se enfoca en la orientación del vector más que en su magnitud.

La combinación de KNN con técnicas de procesamiento de texto ofrece una solución robusta y interpretable para muchas tareas de NLP, especialmente cuando se cuenta con datasets de tamaño moderado y se requiere un enfoque no paramétrico que pueda adaptarse a diferentes tipos de patrones en los datos textuales.

KNN y Procesamiento de Texto - Machine Learning

Author

Juan Fuentes

Publish Date

06 - 29 - 2023