Proyecto II: El Analizador de Texto
El proyecto integrador construyó un almacén de productos. Este miniproyecto es más corto y ataca otra habilidad: procesar texto. Vas a leer un archivo y averiguar qué palabras aparecen más veces. Es la base de cosas tan reales como un buscador o un detector de spam.
A diferencia de los ejercicios, aquí sí te muestro la solución paso a paso. Pero inténtalo primero: el plano completo está en estas cuatro piezas.
El Reto
Dado un archivo de texto, el programa debe:
- Leer todo su contenido.
- Contar cuántas veces aparece cada palabra (sin distinguir mayúsculas).
- Mostrar las 5 palabras más frecuentes.
Pieza 1: Conseguir el texto
Para no depender de tener un archivo a mano, lo creamos en el momento. En un caso real, este texto vendría de Path("documento.txt").read_text().
texto = """
el almacén guarda cajas el almacén ordena cajas
el gerente cuenta cajas y el gerente revisa cajas
"""
Pieza 2: Partir en palabras y normalizar
.lower() iguala mayúsculas y minúsculas; .split() sin argumentos parte por cualquier espacio o salto de línea y descarta los vacíos.
palabras = texto.lower().split()
Pieza 3: Contar con un diccionario
El patrón acumulador, pero sobre un diccionario: la clave es la palabra, el valor es cuántas veces apareció. .get(palabra, 0) devuelve el conteo actual (o 0 la primera vez), le sumamos uno y lo guardamos.
conteo: dict[str, int] = {}
for palabra in palabras:
conteo[palabra] = conteo.get(palabra, 0) + 1
Aquí se ve por qué .get() con valor por defecto es tan útil: sin él, la primera vez que ves una palabra obtienes un KeyError.
Pieza 4: Ordenar y mostrar el top 5
El sorted() que conociste en el Capítulo 5 ordena las parejas por su conteo, de mayor a menor. Las piezas nuevas son dos: key, que le dice por qué campo ordenar (el valor, no la clave), y esa criatura llamada lambda. El orden “de mayor a menor” lo pone reverse=True; sin él, sorted() ordena de menor a mayor.
ranking = sorted(conteo.items(), key=lambda par: par[1], reverse=True)
print("Top 5 palabras:")
for palabra, veces in ranking[:5]:
print(f"{veces:>3} {palabra}")
Nota: así se lee una
lambda. Es una función sin nombre, escrita en una línea.lambda par: par[1]equivale exactamente a esto:def obtener_conteo(par): return par[1]Es decir: “recibe
pary devuelvepar[1]”.sortedla llama con cada pareja("cajas", 4)para saber por cuál número ordenar. Podrías escribir la versión condefy pasarlekey=obtener_conteo: resultado idéntico. La lambda solo se ahorra el nombre cuando la función es tan pequeña que no lo merece. Si te estorba, usadef; nadie te va a multar.
ranking[:5] es el rebanado que ya conoces: solo las cinco primeras. Y {veces:>3} alinea los números a la derecha en tres espacios, para que la lista quede en columna.
El Archivo Completo
def contar_palabras(texto: str) -> dict[str, int]:
"""Cuenta cuántas veces aparece cada palabra, sin distinguir mayúsculas."""
conteo: dict[str, int] = {}
for palabra in texto.lower().split():
conteo[palabra] = conteo.get(palabra, 0) + 1
return conteo
def top_palabras(conteo: dict[str, int], n: int = 5) -> list[tuple[str, int]]:
"""Devuelve las n palabras más frecuentes, de mayor a menor."""
ranking = sorted(conteo.items(), key=lambda par: par[1], reverse=True)
return ranking[:n]
texto = (
"el almacén guarda cajas el almacén ordena cajas el gerente cuenta cajas"
)
conteo = contar_palabras(texto)
for palabra, veces in top_palabras(conteo):
print(f"{veces:>3} {palabra}")
Lleva más Lejos
- Lee el texto de un archivo real con
Path("documento.txt").read_text(encoding="utf-8"). - Ignora palabras vacías como “el”, “y”, “de” (las llaman stop words): guárdalas en un
sety sáltalas concontinue. - Guarda el conteo en un
conteo.jsonconjson.dump, para no recalcularlo cada vez.
Cada mejora reutiliza algo que ya sabes. Eso es construir sobre tus propios cimientos.