¡¡¡INCREÍBLE oferta!!! Visita https://tienda.com 😍😍Envía un msg al +591-71234567#Descuento @tienda_bo precio: $99.99 USD
Problemas para una máquina:
Mayúsculas / minúsculas
Puntuación repetida
URLs, emails, emojis
Hashtags, menciones
Espacios irregulares
Números en distintos formatos
Regla de Oro del NLP
Basura entra, basura sale (Garbage in, garbage out). La calidad de cualquier modelo depende directamente de la calidad del preprocesamiento.
El Pipeline de Preprocesamiento
Code
flowchart LR A[📄 Texto<br>crudo] --> B[🔤 Tokenización] B --> C[🔡 Normalización] C --> D[🚫 Stopwords] D --> E[🌱 Stemming /<br>📖 Lematización] E --> F[✅ Texto<br>limpio] style A fill:#fff3cd,color:#000 style B fill:#cfe2ff,color:#000 style C fill:#d1e7dd,color:#000 style D fill:#f8d7da,color:#000 style E fill:#e2d9f3,color:#000 style F fill:#d4edda,color:#000
flowchart LR
A[📄 Texto<br>crudo] --> B[🔤 Tokenización]
B --> C[🔡 Normalización]
C --> D[🚫 Stopwords]
D --> E[🌱 Stemming /<br>📖 Lematización]
E --> F[✅ Texto<br>limpio]
style A fill:#fff3cd,color:#000
style B fill:#cfe2ff,color:#000
style C fill:#d1e7dd,color:#000
style D fill:#f8d7da,color:#000
style E fill:#e2d9f3,color:#000
style F fill:#d4edda,color:#000
Cada paso transforma el texto para que sea más útil para nuestros modelos.
Tokenización
¿Qué es Tokenizar?
Dividir un texto en unidades mínimas significativas llamadas tokens.
Tipos de tokenización:
Nivel
Ejemplo
Oración
“Hola. ¿Qué tal?” → 2 oraciones
Palabra
“el gato negro” → 3 tokens
Subpalabra
“jugando” → “jug” + “##ando”
Carácter
“gato” → g, a, t, o
¿Por qué importa?
Define la unidad básica de análisis
Afecta el vocabulario del modelo
Diferente en cada idioma
No es trivial: “New York” → ¿1 o 2 tokens?
Método 1: split() (Naïve)
texto ="El gato, que estaba en el jardín, cazó un ratón."# split() divide por espaciostokens = texto.split()print(f"Tokens: {tokens}")print(f"Cantidad: {len(tokens)}")
“gato,” se considera un solo token (incluye la coma)
No separa puntuación
No maneja contracciones (“del” = “de” + “el”)
No detecta límites de oración
Método 2: Regex (Mejor)
import retexto ="El gato, que estaba en el jardín, cazó un ratón."# Tokenización con regextokens = re.findall(r"\w+|[^\w\s]", texto)print(f"Tokens: {tokens}")print(f"Cantidad: {len(tokens)}")
import nltknltk.download('punkt_tab', quiet=True)from nltk.tokenize import word_tokenize, sent_tokenizetexto ="El Dr. García vive en La Paz. Trabaja en la U.C.B. desde 2019."# Tokenización por oracionesoraciones = sent_tokenize(texto, language='spanish')print("Oraciones:")for i, sent inenumerate(oraciones):print(f" {i+1}. {sent}")# Tokenización por palabrastokens = word_tokenize(texto, language='spanish')print(f"\nTokens: {tokens}")
Oraciones:
1. El Dr. García vive en La Paz.
2. Trabaja en la U.C.B.
3. desde 2019.
Tokens: ['El', 'Dr.', 'García', 'vive', 'en', 'La', 'Paz', '.', 'Trabaja', 'en', 'la', 'U.C.B', '.', 'desde', '2019', '.']
Método 4: spaCy
import spacynlp = spacy.load("es_core_news_sm")texto ="El Dr. García vive en La Paz. Trabaja en la U.C.B. desde 2019."doc = nlp(texto)# Tokenización por oracionesprint("Oraciones:")for i, sent inenumerate(doc.sents):print(f" {i+1}. {sent.text}")# Tokenización por palabras con información adicionalprint("\nTokens con POS tags:")for token in doc:print(f" '{token.text:12s}' → POS: {token.pos_:6s} | Lema: {token.lemma_}")
Oraciones:
1. El Dr. García vive en La Paz.
2. Trabaja en la U.C.B. desde 2019.
Tokens con POS tags:
'El ' → POS: DET | Lema: el
'Dr. ' → POS: PROPN | Lema: Dr.
'García ' → POS: PROPN | Lema: García
'vive ' → POS: VERB | Lema: vivir
'en ' → POS: ADP | Lema: en
'La ' → POS: DET | Lema: el
'Paz ' → POS: PROPN | Lema: Paz
'. ' → POS: PUNCT | Lema: .
'Trabaja ' → POS: VERB | Lema: trabajar
'en ' → POS: ADP | Lema: en
'la ' → POS: DET | Lema: el
'U.C.B. ' → POS: PROPN | Lema: U.C.B.
'desde ' → POS: ADP | Lema: desde
'2019 ' → POS: NOUN | Lema: 2019
'. ' → POS: PUNCT | Lema: .
Comparación de Tokenizadores
import reimport nltkimport spacyfrom nltk.tokenize import word_tokenizenlp = spacy.load("es_core_news_sm")texto ="No puedo creer que cueste $99.99 en EE.UU."# Comparar los 4 métodosmetodos = {"split()": texto.split(),"regex": re.findall(r"\w+|[^\w\s]", texto),"NLTK": word_tokenize(texto, language='spanish'),"spaCy": [t.text for t in nlp(texto)]}for nombre, tokens in metodos.items():print(f"{nombre:8s} ({len(tokens):2d} tokens): {tokens}")
from nltk.corpus import stopwordsfrom nltk.tokenize import word_tokenizestops =set(stopwords.words('spanish'))texto ="El procesamiento de lenguaje natural es una rama de la inteligencia artificial"tokens = word_tokenize(texto.lower(), language='spanish')# Filtrar stopwordstokens_limpios = [t for t in tokens if t notin stops and t.isalpha()]print(f"Original ({len(tokens)} tokens):")print(f" {tokens}")print(f"\nSin stopwords ({len(tokens_limpios)} tokens):")print(f" {tokens_limpios}")
Reducir una palabra a su lema: la forma canónica que aparecería en un diccionario, considerando el contexto gramatical.
Ejemplo:
Palabra
Lema
jugando
jugar
jugador
jugador
juegos
juego
mejores
mejor
fue
ir / ser
Características:
✅ El resultado es una palabra real
✅ Considera el contexto (POS)
✅ Más preciso que stemming
❌ Más lento
❌ Necesita diccionario / modelo
Lematización con spaCy
import spacynlp = spacy.load("es_core_news_sm")texto ="Los estudiantes corrieron rápidamente hacia las mejores universidades del país"doc = nlp(texto)print(f"{'Token':<18}{'Lema':<16}{'POS':<8}{'¿Cambió?'}")print("-"*52)for token in doc: cambio ="✅"if token.text.lower() != token.lemma_ else""print(f"{token.text:<18}{token.lemma_:<16}{token.pos_:<8}{cambio}")
Token Lema POS ¿Cambió?
----------------------------------------------------
Los el DET ✅
estudiantes estudiante NOUN ✅
corrieron correr VERB ✅
rápidamente rápidamente ADV
hacia hacia ADP
las el DET ✅
mejores mejor ADJ ✅
universidades universidad NOUN ✅
del del ADP
país país NOUN
Palabra Stem Lema (spaCy)
----------------------------------------------
corriendo corr correr
mejores mejor mejor
ciudades ciudad ciudad
producción produccion producción
dificultades dificultad dificultad
haciendo hac hacer
¿Cuándo usar cuál?
Stemming: Búsqueda de información, indexación, cuando la velocidad importa
Lematización: Análisis de sentimiento, chatbots, cuando la precisión importa
Pipeline Completo
Función de Preprocesamiento
import reimport spacyfrom nltk.corpus import stopwordsnlp = spacy.load("es_core_news_sm")stops =set(stopwords.words('spanish'))def preprocesar(texto, usar_lemas=True, quitar_stops=True):"""Pipeline completo de preprocesamiento para NLP en español."""# 1. Lowercase texto = texto.lower()# 2. Eliminar URLs y emails texto = re.sub(r"https?://\S+|www\.\S+", "", texto) texto = re.sub(r"\S+@\S+", "", texto)# 3. Eliminar caracteres especiales (mantener letras y espacios) texto = re.sub(r"[^\w\sáéíóúñü]", " ", texto)# 4. Normalizar espacios texto = re.sub(r"\s+", " ", texto).strip()# 5. Tokenizar y lematizar con spaCy doc = nlp(texto) tokens = []for token in doc: palabra = token.lemma_ if usar_lemas else token.textif quitar_stops and palabra in stops:continueifnot palabra.isalpha():continue tokens.append(palabra)return tokens
Demo del Pipeline
texto_crudo ="""¡¡Los MEJORES estudiantes de la Universidad Católica están desarrollando proyectos increíbles!! 🎓🚀Visita https://ucb.edu.bo para más información.Contacto: info@ucb.edu.bo"""print(f"TEXTO ORIGINAL:\n{texto_crudo}")# Con lemas y sin stopwordsresultado1 = preprocesar(texto_crudo, usar_lemas=True, quitar_stops=True)print(f"Con lemas, sin stops:\n{resultado1}\n")# Sin lemas, sin stopwordsresultado2 = preprocesar(texto_crudo, usar_lemas=False, quitar_stops=True)print(f"Sin lemas, sin stops:\n{resultado2}\n")# Con lemas, con stopwordsresultado3 = preprocesar(texto_crudo, usar_lemas=True, quitar_stops=False)print(f"Con lemas, con stops:\n{resultado3}")
TEXTO ORIGINAL:
¡¡Los MEJORES estudiantes de la Universidad Católica están
desarrollando proyectos increíbles!! 🎓🚀
Visita https://ucb.edu.bo para más información.
Contacto: info@ucb.edu.bo
Con lemas, sin stops:
['mejor', 'estudiante', 'universidad', 'católico', 'desarrollar', 'proyecto', 'increíble', 'visitar', 'información', 'contacto']
Sin lemas, sin stops:
['mejores', 'estudiantes', 'universidad', 'católica', 'desarrollando', 'proyectos', 'increíbles', 'visita', 'información', 'contacto']
Con lemas, con stops:
['el', 'mejor', 'estudiante', 'de', 'el', 'universidad', 'católico', 'estar', 'desarrollar', 'proyecto', 'increíble', 'visitar', 'para', 'más', 'información', 'contacto']
Procesando Múltiples Documentos
documentos = ["El procesamiento de lenguaje natural permite analizar textos automáticamente.","Las redes neuronales han revolucionado la inteligencia artificial moderna.","Bolivia tiene una gran diversidad lingüística con más de 30 idiomas nativos.",]print("DOCUMENTOS PREPROCESADOS:\n")for i, doc inenumerate(documentos): tokens = preprocesar(doc)print(f"Doc {i+1}: {tokens}")