Cómo extraer entidades nombradas en Python para datos: paso a paso
Extraer entidades nombradas en Python para datos permite transformar texto suelto en columnas estructuradas (personas, organizaciones, lugares, fechas). Con este enfoque obtienes columnas que pueden alimentar informes, crear features para modelos de Machine Learning o automatizar etiquetado en pipelines ETL. Vamos a explicar el porqué de cada paso y mostrar cómo aplicar la técnica a ejemplos reales, con consejos de rendimiento y validación.
Requisitos previos
- Python 3.8+ instalado
- pip para instalar paquetes
- Conocimientos básicos de Python y pandas
- Conexión a Internet para instalar spaCy y descargar un modelo
Recomiendo un entorno virtual (venv) para no entrar en conflicto con otras bibliotecas. Para conjuntos de datos pequeños (100–1 000 textos) un portátil común basta; para miles o millones de textos conviene usar una máquina con más CPU/RAM o paralelizar el procesamiento.
Paso 1: Instalar spaCy y pandas
Usaremos spaCy para la identificación de entidades y pandas para manipular los datos. Instala los paquetes y descarga un modelo preentrenado. El modelo en_core_web_sm es un buen punto de partida para inglés; para portugués usa pt_core_news_sm.
pip install spacy pandas
python -m spacy download en_core_web_sm
# para portugués, usa:
# python -m spacy download pt_core_news_sm
Nota: los modelos pequeños son más rápidos y ligeros, pero tienden a ser menos precisos en dominios especializados (p. ej. jurídico o médico). Si necesitas mayor precisión, considera modelos más grandes o fine-tuning.
Paso 2: Preparar un DataFrame de ejemplo
Crea un DataFrame con textos que quieras procesar — por ejemplo, descripciones de noticias o comentarios. Mantén el texto en una columna, aquí llamada text. Es útil tener un id único por fila para trazabilidad.
import pandas as pd
data = {
'id': [1, 2, 3],
'text': [
'Apple lançará o novo iPhone em Setembro em Cupertino.',
'O primeiro-ministro visitou Lisboa e o Museu Nacional ontem.',
'Tesla anuncia fábrica em Berlim prevista para 2024.'
]
}
df = pd.DataFrame(data)
print(df)
En escenarios reales puedes cargar el archivo CSV con pd.read_csv() o extraer de una base de datos. Si tienes 10 000+ registros, evita usar apply fila a fila sin optimización (ver Paso 4).
Paso 3: Cargar el modelo spaCy y crear función de extracción
Carga el modelo en_core_web_sm (u otro apropiado). Crea una función que reciba un texto y devuelva una lista de entidades con tipo y texto. Mantén la función simple para facilitar la posterior transformación en columnas.
import spacy
nlp = spacy.load('en_core_web_sm') # usa un modelo pequeño; cambia si necesitas otro idioma
def extract_entities(text):
doc = nlp(text)
ents = []
for ent in doc.ents:
ents.append({'text': ent.text, 'label': ent.label_})
return ents
# Test rápido
print(extract_entities('Barack Obama visited Berlin in 2013.'))
Consejo de rendimiento: si solo necesitas el componente NER, puedes cargar con nlp = spacy.load('en_core_web_sm', exclude=['parser','tagger']) para acelerar. Para grandes volúmenes usa nlp.pipe en el paso siguiente.
Paso 4: Aplicar la extracción al DataFrame
Usa pandas.apply para crear nuevas columnas con las entidades. Para conjuntos medianos o grandes es más eficiente usar nlp.pipe que procesa en batch y reduce el overhead de Python.
def ents_to_dict(ents):
# transforma lista de entidades en diccionario con tipos como claves
out = {'PERSON': [], 'ORG': [], 'GPE': [], 'DATE': []}
for e in ents:
if e['label'] in out:
out[e['label']].append(e['text'])
return out
# Extrae todas las entidades
df['entities'] = df['text'].apply(extract_entities)
# Convierte a diccionario de tipos
df_types = df['entities'].apply(ents_to_dict).apply(pd.Series)
# Une al DataFrame original
df = pd.concat([df, df_types], axis=1)
print(df[['id','text','entities','PERSON','ORG','GPE','DATE']])
Ejemplo con nlp.pipe (más eficiente para 1k+ textos):
docs = list(nlp.pipe(df['text'].astype('str')))
# después iteras sobre docs para construir la columna entities
Paso 5: Normalizar y limpiar entidades
Las entidades pueden repetirse o tener variantes (ej.: "Lisboa" vs "Lisboa, Portugal"). Normaliza eliminando duplicados, limpiando espacios y transformando listas en strings separadas por comas para análisis/almacenamiento. También puedes aplicar lematización o usar reglas para unificar formas.
def normalize_list(lst):
seen = []
for item in lst:
item = item.strip()
if item not in seen:
seen.append(item)
return ', '.join(seen) if seen else ''
for col in ['PERSON','ORG','GPE','DATE']:
df[col] = df[col].apply(normalize_list)
print(df[['id','PERSON','ORG','GPE','DATE']])
Para eliminar variaciones más complejas, considera usar fuzzy matching (fuzzywuzzy) o normalización por reglas (regex) antes de agregar resultados.
Verificar el resultado
Confirma que las columnas nuevas contienen las entidades esperadas. Haz validación manual en muestras (p. ej. 100 filas) para estimar precisión y recall. Busca errores comunes: entidades vacías, etiquetas incorrectas por idioma o modelos débiles.
# Visualizar filas donde GPE (lugar) no está vacío
print(df[df['GPE'] != ''][['id','text','GPE']])
# Ver ejemplos sin entidades detectadas
print(df[df['entities'].apply(len) == 0][['id','text']])
Si encuentras muchos falsos positivos, ajusta el modelo, usa un modelo específico de dominio o aplica reglas de postprocesado para filtrar resultados irrelevantes.
Conclusión
Has completado la extracción de entidades nombradas en Python para datos usando spaCy y pandas, transformando texto en columnas estructuradas listas para análisis o features de ML. Próximos pasos: probar modelos en lengua portuguesa (p. ej. pt_core_news_sm), ajustar el pipeline para normalización (lematización, resolución de correferencia) o almacenar resultados en CSV/SQL con df.to_csv('entities.csv', index=False) o vía SQLAlchemy. Consejo final: comienza validando con muestras manuales (p. ej. 100–300 ejemplos) para medir la calidad antes de automatizar en producción.