Counter del módulo collections es una subclase de dict diseñada para contar elementos. Elimina el bucle manual de conteo y añade métodos propios para los patrones más habituales: los más frecuentes, operaciones aritméticas entre contadores y actualización incremental.
Crear un Counter
from collections import Counter
# Desde una lista
votos = ["python", "python", "javascript", "python", "rust", "javascript"]
c = Counter(votos)
print(c)
# Counter({'python': 3, 'javascript': 2, 'rust': 1})
# Desde una cadena (cuenta caracteres)
c2 = Counter("programacion")
print(c2)
# Counter({'r': 2, 'a': 2, 'o': 2, 'p': 1, 'g': 1, 'm': 1, 'c': 1, 'i': 1, 'n': 1})
# Con kwargs
c3 = Counter(a=3, b=1, c=2)
print(c3) # Counter({'a': 3, 'c': 2, 'b': 1})
most_common(): los más frecuentes
from collections import Counter
palabras = """python es un lenguaje de programacion python es muy
popular python se usa en ciencia de datos y en web""".split()
c = Counter(palabras)
# Los 3 más comunes
print(c.most_common(3))
# [('python', 3), ('es', 2), ('de', 2)]
# Menos común: invertir
print(c.most_common()[:-4:-1])
# los 3 menos comunes
Acceso a claves sin KeyError
from collections import Counter
c = Counter(["a", "b", "a", "c"])
print(c["a"]) # 2
print(c["z"]) # 0 no lanza KeyError, devuelve 0
# 'in' para comprobar si existe
print("a" in c) # True
print("z" in c) # False
update() y subtract()
from collections import Counter
votos_manana = Counter({"python": 10, "rust": 5, "go": 8})
votos_tarde = Counter({"python": 7, "go": 3, "kotlin": 4})
# update: SUMA los conteos (no sobreescribe)
total = votos_manana.copy()
total.update(votos_tarde)
print(total)
# Counter({'python': 17, 'go': 11, 'rust': 5, 'kotlin': 4})
# subtract: RESTA los conteos (permite negativos)
diferencia = votos_manana.copy()
diferencia.subtract(votos_tarde)
print(diferencia)
# Counter({'rust': 5, 'python': 3, 'go': 5, 'kotlin': -4})
Operaciones aritméticas entre Counters
from collections import Counter
a = Counter(manzanas=3, peras=2, uvas=5)
b = Counter(manzanas=1, peras=4, kiwis=2)
print(a + b) # suma
# Counter({'uvas': 5, 'peras': 6, 'manzanas': 4, 'kiwis': 2})
print(a - b) # resta (solo valores positivos)
# Counter({'uvas': 5, 'manzanas': 2})
print(a & b) # intersección: mínimo de cada uno
# Counter({'manzanas': 1, 'peras': 2})
print(a | b) # unión: máximo de cada uno
# Counter({'uvas': 5, 'peras': 4, 'manzanas': 3, 'kiwis': 2})
Caso real: frecuencia de palabras en logs
from collections import Counter
import re
log = """
2026-06-01 ERROR timeout en servidor db1
2026-06-01 INFO usuario admin conectado
2026-06-02 ERROR timeout en servidor db2
2026-06-02 ERROR disco lleno en servidor app1
2026-06-03 WARN memoria alta en servidor web1
2026-06-03 ERROR timeout en servidor db1
"""
niveles = Counter(re.findall(r"(ERROR|WARN|INFO)", log))
print(niveles.most_common())
# [('ERROR', 4), ('INFO', 1), ('WARN', 1)]
servidores_con_error = Counter(
m.group(1)
for m in re.finditer(r"ERROR.+?(dbd+|appd+|webd+)", log)
)
print(servidores_con_error)
# Counter({'db1': 2, 'db2': 1, 'app1': 1})
Counter elimina el patrón repetitivo de if k in d: d[k] += 1 else: d[k] = 1. Úsalo siempre que necesites contar ocurrencias de elementos de un iterable.
