Domine o `Counter` do Python: Contagem eficiente de itens em iteráveis

Neste guia, você explorará o uso do objeto contador, fornecido pelo módulo `collections` do Python.

Ao manipular longas sequências no Python, como listas ou strings, surge a necessidade de rastrear a frequência de cada item. Um dicionário Python tradicional é uma estrutura de dados capaz de lidar com isso, no entanto, a classe `Counter` do módulo `collections` oferece uma abordagem mais direta, criando um dicionário de itens e suas respectivas contagens de forma eficiente.

Nesta exploração, você aprenderá a:

  • Utilizar o objeto contador do Python.
  • Construir dicionários para armazenar as contagens de itens em iteráveis.
  • Implementar o contador do Python, simplificando o processo de criação de contadores.
  • Realizar operações como atualização, subtração de elementos e encontrar interseções entre objetos contadores.
  • Identificar os elementos mais frequentes em um contador usando o método `most_common()`.

Vamos começar!

Módulo `collections` e a Classe `Counter` no Python

Frequentemente, um dicionário Python é utilizado para armazenar os itens e suas contagens em um iterável. Os itens servem como chaves, enquanto as contagens atuam como valores.

A classe `Counter` faz parte do módulo `collections` embutido do Python, portanto, você a importa no seu script da seguinte forma:

from collections import Counter

Após importar a classe, você instancia um objeto contador assim:

<objeto_contador> = Counter(iterável)

Onde:

  • `iterável` representa qualquer sequência válida do Python, como lista, string ou tupla.
  • Os itens dentro do iterável devem ser “hashable” (imutáveis).

Agora que você sabe como criar objetos contadores, vamos a exemplos práticos. Você encontra todos os exemplos no seguinte gist no GitHub.

Criando um Objeto Contador a partir de Iteráveis

Criaremos uma string, digamos, “renascimento”, armazenando-a em uma variável chamada `palavra`.

>>> palavra = "renascimento"

Nosso objetivo é construir um dicionário onde cada letra na `palavra` seja mapeada para o número de ocorrências na string. Uma maneira de conseguir isso é usar loops `for`:

>>> contagem_letras = {}
>>> for letra in palavra:
...     if letra not in contagem_letras:
...         contagem_letras[letra] = 0
...     contagem_letras[letra] += 1
...
>>> contagem_letras
{'r': 1, 'e': 2, 'n': 2, 'a': 2, 'i': 1, 's': 2, 'c': 1}

Analisando o código:

  • Inicializa `contagem_letras` como um dicionário vazio.
  • Itera sobre a string `palavra`.
  • Verifica se cada `letra` está presente no dicionário.
  • Se a letra não existir, ela é adicionada com o valor inicial 0, que é incrementado por 1.
  • O valor associado a cada letra é incrementado a cada ocorrência na string.
  • O processo se repete até que toda a string seja percorrida.

Com isso, criamos o dicionário `contagem_letras` utilizando um loop `for`. No entanto, podemos simplificar esse processo com a classe `Counter`.

Basta passar a string `palavra` para `Counter()`:

>>> from collections import Counter
>>> contagem_letras = Counter(palavra)
>>> contagem_letras
Counter({'e': 2, 'n': 2, 'a': 2, 's': 2, 'r': 1, 'i': 1, 'c': 1})

O objeto contador também é um dicionário Python. Podemos verificar com `isinstance()`:

>>> isinstance(contagem_letras,dict)
True

O resultado `True` confirma que `contagem_letras` é uma instância da classe `dict`.

Modificando o Objeto Contador

Até agora, você aprendeu a criar objetos contadores a partir de strings. É possível modificar esses objetos adicionando ou removendo elementos.

Atualizando um Contador com Elementos de outro Iterável

Vamos criar uma segunda string `outra_palavra`:

>>> outra_palavra = "efervescência"

Suponha que você precise atualizar o objeto contador `contagem_letras` com os itens da string `outra_palavra`. Para isso, utilize o método `update()`:

>>> contagem_letras.update(outra_palavra)
>>> contagem_letras
Counter({'e': 7, 'n': 3, 's': 3, 'c': 3, 'r': 2, 'a': 2, 'f': 2, 'i': 1, 'v': 1})

O objeto contador agora inclui letras e suas contagens da string `outra_palavra`.

Subtraindo Elementos de Outro Iterável

Para remover as contagens correspondentes aos itens de `outra_palavra` em `contagem_letras`, utilize o método `subtract()`. A sintaxe é: `.subtract()`.

>>> contagem_letras.subtract(outra_palavra)
>>> contagem_letras
Counter({'e': 2, 'n': 2, 'a': 2, 's': 2, 'r': 1, 'i': 1, 'c': 1, 'f': 0, 'v': 0})

Os valores correspondentes às letras em `outra_palavra` foram subtraídos, mas as chaves ‘f’ e ‘v’ adicionadas não foram removidas, apenas seus valores foram alterados para 0.

O método `subtract()` não se limita a strings, aceitando objetos contadores ou outros iteráveis como argumento.

Interseção entre Dois Objetos Contadores

É possível encontrar as chaves comuns entre dois objetos contadores. Para isso, criamos um segundo objeto, `contagem_letras_2`, a partir de `outra_palavra` (“efervescência”).

>>> outra_palavra = "efervescência"
>>> contagem_letras_2 = Counter(outra_palavra)
>>> contagem_letras_2
Counter({'e': 5, 'f': 2, 'c': 2, 'r': 1, 'v': 1, 's': 1, 'n': 1})

O operador `&` identifica a interseção:

>>> contagem_letras & contagem_letras_2
Counter({'e': 2, 'r': 1, 'n': 1, 's': 1, 'c': 1})

Assim, você obtém as chaves e as contagens comuns às duas palavras. Tanto “renascimento” quanto “efervescência” possuem duas ocorrências de ‘e’ e uma ocorrência de ‘r’, ‘n’, ‘s’ e ‘c’ em comum.

Identificando os Itens Mais Frequentes com `most_common()`

É útil identificar os itens com maior frequência em um objeto contador. O método `most_common()` faz exatamente isso. Ao chamarmos `most_common(k)` em um objeto contador, obtemos os `k` itens mais frequentes.

>>> contagem_letras.most_common(3)
[('e', 2), ('n', 2), ('a', 2)]

As letras ‘e’, ‘n’ e ‘a’ são as três mais frequentes na palavra “renascimento”, com duas ocorrências cada.

Isso é especialmente útil para analisar conjuntos de dados grandes e encontrar os elementos mais relevantes.

Conclusão

Revisando o que foi aprendido:

  • A classe `Counter` do módulo `collections` do Python simplifica a criação de dicionários de contagem de itens em iteráveis, desde que esses itens sejam “hashable”.
  • O método `update()` adiciona ou atualiza as contagens de um objeto contador. Sua sintaxe é: `contador1.update(contador2)` (ou qualquer iterável no lugar de `contador2`).
  • O método `subtract()` remove contagens de um objeto contador, usando a sintaxe `contador1.subtract(contador2)`.
  • O operador `&` realiza a interseção entre dois objetos contadores, identificando os itens comuns. A sintaxe é: `contador1 & contador2`.
  • O método `most_common(k)` identifica os `k` elementos mais frequentes em um objeto contador, retornando uma lista de tuplas com os itens e suas contagens.

Aprofunde seus conhecimentos com a classe `defaultdict`, também do módulo `collections`, que auxilia na manipulação de chaves ausentes em dicionários.