(+351) 21 24 10006  ·  info@bconcepts.pt
Carnaxide, Lisboa

Cómo crear un modelo de clasificación de texto en Machine Learning

João Barros 05 de September de 2026 6 min de lectura

Este tutorial muestra cómo transformar texto en características y entrenar un modelo de clasificación en Machine Learning para categorizar mensajes o reseñas. Es útil para automatizar la triage de soporte, análisis de sentimiento o clasificación de contenidos con un ejemplo práctico en Python y scikit-learn. Explicaré el porqué de cada paso y daré consejos prácticos para mejorar resultados reales.

Requisitos previos

  • Python 3.8+ instalado
  • Paquetes: scikit-learn, pandas, numpy (pip install scikit-learn pandas numpy)
  • Conocimientos básicos de Python y pandas

Recomiendo trabajar en un entorno virtual (venv) para evitar conflictos de versiones. Para conjuntos de datos reales, idealmente tienes algunas centenas a miles de ejemplos para obtener modelos robustos — con sólo 50-100 muestras los resultados son muy inestables.

Paso 1: Preparar un conjunto de datos sencillo

Comenzamos con un pequeño conjunto de ejemplos etiquetados (por ejemplo, mensajes de entrenamiento). Mantén texto y etiqueta en un pandas DataFrame. Estructurar bien los datos facilita la posterior expansión a CSV o bases de datos.

import pandas as pd

data = [
    ("Adorei o produto, chegou rápido e funciona bem", "positivo"),
    ("Produto avariado, quero reembolso", "negativo"),
    ("Entrega atrasada, má experiência", "negativo"),
    ("Muito satisfeito com a qualidade", "positivo"),
    ("Suporte lento e pouco útil", "negativo"),
    ("Excelente, recomendo", "positivo")
]

df = pd.DataFrame(data, columns=["text", "label"]) 
print(df.head())

Este dataframe es sólo un ejemplo didáctico. En producción, guarda también un id, fecha y metadatos (canal, producto) para análisis posteriores.

Paso 2: Limpieza básica del texto

Normalizamos mayúsculas/minúsculas y eliminamos espacios superfluos. Dependiendo del caso puedes eliminar puntuación, URLs o teléfonos; sin embargo, TF-IDF suele ignorar palabras muy frecuentes si se configura correctamente. Evita el over-preprocessing: a veces la eliminación excesiva pierde señales importantes (p. ej.: "não gosto"). Aquí hacemos un preprocesado simple y legible:

def clean_text(s):
    return s.lower().strip()

df["text_clean"] = df["text"].apply(clean_text)
print(df[["text", "text_clean"]].head())

Si tienes clases desequilibradas (p. ej.: 90% positivo), considera técnicas como remuestreo o pesos de clase en el clasificador.

Paso 3: Dividir datos en entrenamiento y prueba

Usa train_test_split para evaluar el modelo en datos nuevos. La estratificación es importante cuando existen pocas muestras por clase. En conjuntos pequeños usa test_size=0.2-0.33; en conjuntos grandes puedes reservar sólo el 10%.

from sklearn.model_selection import train_test_split

X = df["text_clean"]
y = df["label"]

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.33, random_state=42, stratify=y
)

Con stratify=y garantizamos que la proporción de clases en entrenamiento/prueba se mantenga. Para validación más robusta, usa Cross-Validation en lugar de una única división.

Paso 4: Transformar texto en vectores con TF-IDF

TF-IDF convierte texto en vectores numéricos ponderando términos por su importancia relativa. Aquí elegimos ngram_range=(1,2) para captar uni- y bi-gramas (p. ej.: "muito bom", "não gostei") y usamos max_df/min_df para reducir ruido.

from sklearn.feature_extraction.text import TfidfVectorizer

vect = TfidfVectorizer(ngram_range=(1,2), max_df=0.9, min_df=1)
X_train_tfidf = vect.fit_transform(X_train)
X_test_tfidf = vect.transform(X_test)

print("Número de features:", X_train_tfidf.shape[1])

En una muestra pequeña tendrás pocas features (10-100). En conjuntos de datos medianos (1000+ textos) normalmente tienes miles de features; en ese caso evalúa reducción dimensional (TruncatedSVD) o límites mayores para min_df.

Paso 5: Entrenar un clasificador sencillo (Logistic Regression)

Logistic Regression funciona bien para texto y es rápido. El parámetro max_iter=1000 evita no convergencia en casos con muchas features.

from sklearn.linear_model import LogisticRegression

model = LogisticRegression(max_iter=1000)
model.fit(X_train_tfidf, y_train)

y_pred = model.predict(X_test_tfidf)

Alternativas para probar: SVM (bueno para datos dispersos y de alta dimensionalidad) o RandomForest (más lento, puede necesitar vectores densos).

Paso 6: Evaluar el modelo

Calcula métricas simples: precisión, recall y matriz de confusión para entender errores comunes (falsos positivos/negativos). En problemas desequilibrados, el f1-score es más informativo que la accuracy.

from sklearn.metrics import accuracy_score, classification_report, confusion_matrix

acc = accuracy_score(y_test, y_pred)
print("Acurácia:", acc)
print(classification_report(y_test, y_pred))
print("Matriz de confusión:\n", confusion_matrix(y_test, y_pred))

En un toy dataset la accuracy puede variar mucho — valores entre 50% y 90% son comunes dependiendo de la partición. En conjuntos de datos reales, se busca >70-80% para tareas sencillas de sentimiento; para tareas más complejas podrías necesitar modelos más avanzados o más datos.

Paso 7: Interpretar las features más importantes

Comprueba qué términos más contribuyen a cada clase usando los coeficientes del modelo. Esto ayuda a entender errores y a mejorar el preprocesamiento (por ejemplo, tratar negaciones).

import numpy as np

feature_names = vect.get_feature_names_out()
coefs = model.coef_[0]

top_pos = np.argsort(coefs)[-10:][[::-1]][0]
top_neg = np.argsort(coefs)[:10]

print("Top termos positivos:")
for i in top_pos:
    print(feature_names[i], round(coefs[i], 3))

print("Top termos negativos:")
for i in top_neg:
    print(feature_names[i], round(coefs[i], 3))

Si encuentras términos ambiguos, considera ajustar ngram_range o normalizar expresiones (p. ej.: "não gostei" manteniendo la negación).

Verificar el resultado

Confirma que tienes una accuracy coherente e inspecciona la matriz de confusión. Prueba el modelo con frases nuevas para ver si las predicciones tienen sentido:

samples = [
    "Quero devolução, chegou danificado",
    "Produto excelente, muito bom",
    "A entrega demorou mas o produto é bom"
]

samples_tfidf = vect.transform([s.lower().strip() for s in samples])
print(model.predict(samples_tfidf))

Haz también pruebas de esfuerzo con 50-100 frases variadas para evaluar estabilidad. Si el modelo falla sistemáticamente en frases con negaciones, añade reglas de preprocesamiento o features específicas.

Conclusión

Ahora tienes un pipeline completo: limpieza básica, TF-IDF, entrenamiento y evaluación con Logistic Regression para clasificación de texto. Próximos pasos prácticos: aumentar el conjunto de datos a cientos de ejemplos, probar modelos como RandomForest o SVM, y añadir limpieza avanzada (eliminación de stopwords, stemming, lematización). Usa Cross-Validation y GridSearchCV para elegir hiperparámetros y reducir overfitting. Observa qué términos están causando más errores e itera en el preprocesamiento hasta obtener la robustez deseada.