¿Sabías que Python tiene miles de bibliotecas externas, pero muchas de las herramientas más poderosas ya están incluidas en la biblioteca estándar?

Esta serie se centra en el tema de la 'profundización en la biblioteca estándar de Python', donde vamos a desmenuzar una por una las bibliotecas estándar que se utilizan mucho pero no se tratan en profundidad.

El objetivo no es solo enumerar funciones, sino comprender los conceptos a través de ejemplos prácticos y desarrollar la capacidad de aplicar el código, elevando así tu habilidad para utilizar Python a un nuevo nivel.


Uso avanzado de collections: de lo básico a la aplicación práctica

1. ¿Por qué empezar con collections?

collections complementa los tipos de datos incorporados en Python (list, dict, tuple), proporcionando colecciones avanzadas que son muy eficientes en términos de rendimiento y estructura. A menudo aparecen en la práctica, pero no se abordan en profundidad.

Este artículo se centrará en cinco de las clases más prácticas, explicando 'por qué se usan', 'cómo se usan' y 'cuándo es bueno usarlas'.


2. Counter – Una referencia para el conteo de frecuencias, y más

¡Cuenta todas las cosas!

Concepto básico

collections.Counter es una de las clases más útiles incluidas en el módulo de la biblioteca estándar de Python collections. Literalmente, es un "contador", un diccionario especial optimizado para contar las ocurrencias (frecuencia) de los datos.

from collections import Counter

c = Counter(['a', 'b', 'c', 'a', 'b', 'a'])
print(c)  # Counter({'a': 3, 'b': 2, 'c': 1})

Es una estructura de datos que cuenta cuántas veces aparece cada elemento al insertar objetos iterables como listas, cadenas, tuplas o diccionarios.


Funciones y métodos principales

📌 Varios métodos de inicialización

Counter se puede inicializar de diversas maneras, permitiendo un análisis de datos flexible.

from collections import Counter

print(Counter(['a', 'b', 'a']))
# Counter({'a': 2, 'b': 1}) → lista

print(Counter({'a': 2, 'b': 1}))
# Counter({'a': 2, 'b': 1}) → diccionario

print(Counter(a=2, b=1))
# Counter({'a': 2, 'b': 1}) → argumentos con palabras clave

📌 Acceso a elementos

Counter funciona como un dict, pero al intentar acceder a una clave que no existe, devuelve 0 en lugar de KeyError.

c = Counter('hello')
print(c['l'])  # 2 (el carácter 'l' aparece 2 veces)
print(c['x'])  # 0 ('x' no aparece, pero devuelve 0 en lugar de error)

📌 Adición/modificación de elementos

Puedes agregar valores a un elemento existente o modificarlos directamente. Las claves que no existen también se añaden automáticamente.

c = Counter('hello')
c['l'] += 3
print(c)
# Counter({'l': 5, 'o': 1, 'h': 1, 'e': 1})

📌 most_common(n) – Extraer los elementos más comunes

Devuelve los n elementos más frecuentes en forma de lista de tuplas.

c = Counter('banana')
print(c.most_common(2))
# [('a', 3), ('n', 2)] → 'a' aparece 3 veces, 'n' aparece 2 veces

📌 elements() – Iterador que repite los elementos

Proporciona un iterador que repite los elementos según los valores del contador.

c = Counter('banana')
print(list(c.elements()))
# ['b', 'a', 'a', 'a', 'n', 'n']

Sin embargo, los elementos con valores 0 o menores no se incluyen.


📌 Soporte para operaciones matemáticas (operaciones +, -, &, | entre Counters)

Una de las ventajas de Counter sobre los diccionarios es que soporta operaciones aritméticas/conjuntos.

c1 = Counter(a=3, b=1)
c2 = Counter(a=1, b=2)

print(c1 + c2)
# Counter({'a': 4, 'b': 3}) → las mismas claves se combinan

print(c1 - c2)
# Counter({'a': 2}) → se ignoran los negativos, 'b' se omite porque se convierte en negativo

print(c1 & c2)
# Counter({'a': 1, 'b': 1}) → intersección, basado en el mínimo

print(c1 | c2)
# Counter({'a': 3, 'b': 2}) → unión, basado en el máximo

Ejemplos de aplicación práctica

📌 Análisis de palabras en una cadena
text = "the quick brown fox jumps over the lazy dog"
counter = Counter(text.split())
print(counter)
📌 Análisis de frecuencia de logs
logs = ['INFO', 'ERROR', 'INFO', 'DEBUG', 'ERROR', 'ERROR']
print(Counter(logs))  # Counter({'ERROR': 3, 'INFO': 2, 'DEBUG': 1})
📌 Contando elementos duplicados en una lista
nums = [1, 2, 2, 3, 3, 3]
print(Counter(nums))  # Counter({3: 3, 2: 2, 1: 1})

Puntos a tener en cuenta

  • Counter hereda de dict, pero no garantiza el orden. Si se necesita orden, se debe utilizar most_common().
  • Aunque el valor caiga por debajo de 0, los elementos no se eliminan, por lo que puede ser necesario filtrarlos manualmente.
c = Counter(a=3)
c.subtract({'a': 5})
print(c)  # Counter({'a': -2})  # Ten en cuenta que los elementos no desaparecen al bajar a 0 o menos

Sugerencia: Cómo acumular sin inicialización

counter = Counter()
with open("data.txt") as f:
    for line in f:
        counter.update(line.strip().split())

Resumen

collections.Counter es una herramienta poderosa que se utiliza casi como un estándar en análisis de datos, procesamiento de logs y minería de texto. Para principiantes, es una herramienta fácil para contar frecuencias, mientras que para usuarios avanzados, puede evolucionar hacia una herramienta de procesamiento avanzado al combinar operaciones y filtrado.


Próximo episodio

  • defaultdict – ¡Un mundo sin KeyError, más flexible que dict! ¡Esperen el próximo episodio!

Entender y utilizar correctamente la biblioteca estándar 'en profundidad' seguramente mejorará la calidad de su código.