Vai al contenuto principale

Conteggio in Python: pattern moderni, insidie ed esempi pratici

Conta velocemente in Python, valida i dati ed evita errori comuni con Counter, count() e pandas
· 4 min leggi

Scopri con l'IA

Contare le cose sembra banale finché i risultati non sono sballati di poco—o di molto. Ho visto controlli di frequenza fatti con ripetute chiamate a list.count() o metodi pandas usati male che saltano silenziosamente i valori mancanti. Il risultato: codice lento e numeri sbagliati. La soluzione è usare lo strumento giusto: collections.Counter per mappe di frequenza, count() integrato per ricerche rapide su un singolo valore e value_counts() di pandas quando sei in un DataFrame.

Cos’è Counter e come funziona

collections.Counter è una sottoclasse di dizionario per conteggiare oggetti hashable (un multiset). Puoi costruire un Counter da un iterabile o da una mappa. Le chiavi mancanti restituiscono 0; i conteggi possono essere incrementati o decrementati; e diversi metodi di comodo rendono semplici le operazioni più comuni.

from collections import Counter

# From an iterable (one pass over the data)
nyc_eatery_types = [
    "Mobile Food Truck", "Food Cart", "Snack Bar", "Restaurant", "Food Cart",
    "Restaurant", "Mobile Food Truck", "Snack Bar", "Mobile Food Truck"
]
eatery_type_counts = Counter(nyc_eatery_types)
print(eatery_type_counts)  # dict-like view
print(eatery_type_counts["Restaurant"])  # missing keys return 0 instead of KeyError
print(eatery_type_counts["Kiosk"])
Counter({'Mobile Food Truck': 3, 'Food Cart': 2, 'Snack Bar': 2, 'Restaurant': 2})
2
0

Non fare affidamento sull’ordine di iterazione di un Counter. Quando ti serve una vista ordinata, usa most_common().

Trova i valori più comuni con most_common()

Counter.most_common(n) restituisce un elenco di coppie (elemento, conteggio) in ordine decrescente di frequenza. Fornisci n per limitare il risultato, oppure omettilo per ottenere tutte le coppie.

top_3 = eatery_type_counts.most_common(3)
print(top_3)
[('Mobile Food Truck', 3), ('Food Cart', 2), ('Snack Bar', 2)]

Usalo quando ti servono analisi di frequenza, classifiche o controlli rapidi su dati categoriali.

Fai di più con Counter

aggiorna e sottrai i conteggi

I dati di business cambiano. update() aggiunge ai conteggi, mentre subtract() li riduce. Entrambi accettano iterabili o mapping.

new_permits = ["Restaurant", "Food Cart", "Restaurant"]
eatery_type_counts.update(new_permits)  # add 1 for each occurrence
print(eatery_type_counts)

closures = {"Snack Bar": 1}
eatery_type_counts.subtract(closures)   # reduce counts (can go negative)
print(eatery_type_counts)
Counter({'Mobile Food Truck': 3, 'Restaurant': 4, 'Food Cart': 3, 'Snack Bar': 2})
Counter({'Restaurant': 4, 'Mobile Food Truck': 3, 'Food Cart': 3, 'Snack Bar': 1})

Se un conteggio scende a 0 o sotto, metodi come elements() e most_common() lo ignorano. Per rimuovere del tutto una chiave, usa del counter[key].

calcola totali e top-N

Da Python 3.10, Counter.total() restituisce la somma di tutti i conteggi. È utile quando ti servono proporzioni o quote.

total_permits = eatery_type_counts.total()
for eatery, count in eatery_type_counts.most_common(3):
    share = count / total_permits
    print(f"{eatery}: {count} ({share:.1%})")

ricostruisci sequenze con elements()

elements() restituisce ogni elemento tante volte quanto è il suo conteggio. L’ordine è arbitrario.

expanded = list(eatery_type_counts.elements())
print(len(expanded), "items reconstructed from counts")

usa operazioni matematiche e in stile set

Puoi combinare counter con operazioni aritmetiche e tipo min/max. I risultati eliminano i conteggi a zero e negativi.

from collections import Counter

a = Counter({"Food Cart": 5, "Restaurant": 2})
b = Counter({"Food Cart": 3, "Snack Bar": 4})

print(a + b)   # add counts
print(a - b)   # subtract (keeps positives only)
print(a & b)   # intersection: min of counts
print(a | b)   # union: max of counts
Counter({'Food Cart': 8, 'Snack Bar': 4, 'Restaurant': 2})
Counter({'Food Cart': 2, 'Restaurant': 2})
Counter({'Food Cart': 3})
Counter({'Food Cart': 5, 'Snack Bar': 4, 'Restaurant': 2})

Quando usare list.count(), Counter o pandas

Scegli lo strumento più semplice che soddisfa i tuoi requisiti e i vincoli di performance.

verifiche su singolo valore con count()

Usa il count() integrato quando ti serve solo sapere quante volte un valore compare in una sequenza o il conteggio non sovrapposto di una sottostringa in una stringa.

numbers = [1, 2, 2, 3, 2]
print(numbers.count(2))  # 3

word = "banana"
print(word.count("a"))   # 3

text = "aaa"
print(text.count("aa"))  # 1: non-overlapping matches only
print("cat".count(""))   # 4: empty string counts len(s)+1 positions

Attenzione con boolean e interi: True == 1 e False == 0. Questo può gonfiare i conteggi se mescoli i tipi.

mixed = [1, True, 0, False, True]
print(mixed.count(1))  # 3 (counts 1 and True)
print(mixed.count(0))  # 2 (counts 0 and False)

Evita di chiamare count() ripetutamente dentro cicli su dati grandi; ogni chiamata scansiona l’intera sequenza.

# Inefficient: O(n^2) for large lists
# freq = {x: numbers.count(x) for x in numbers}

# Efficient: one pass
from collections import Counter
freq = Counter(numbers)

frequenze multiple con Counter

Quando ti servono i conteggi per molti valori unici, costruisci un Counter una volta sola e interroga all’occorrenza. È chiaro, veloce e progettato proprio per questo caso d’uso.

dati tabellari con pandas

In pandas, DataFrame.count() e Series.count() calcolano i conteggi di valori non mancanti. Per ottenere una tabella di frequenza dei valori, usa Series.value_counts().

import pandas as pd
df = pd.DataFrame({
    "line": ["A", "A", "B", None, "B", "B"],
    "ridership": [100, None, 120, 130, None, 150],
})

print(df["line"].count())         # 5 (non-missing)
print(df["line"].value_counts())  # value frequencies

# For full row count, use len(df), not df.count()
print(len(df))                    # 6

Valida e pulisci i dati con Counter

Prima dell’analisi, controllo la coerenza delle categorie, i valori imprevisti e i duplicati. Counter rende questi controlli rapidi e ripetibili.

from collections import Counter

# Example: validate allowed categories
allowed_types = {"Mobile Food Truck", "Food Cart", "Snack Bar", "Restaurant"}
type_counts = Counter(nyc_eatery_types)

unexpected = {t: c for t, c in type_counts.items() if t not in allowed_types}
if unexpected:
    print("Unexpected categories found:", unexpected)

# Example: flag duplicates (e.g., station IDs appearing more than once)
station_ids = ["ST-001", "ST-002", "ST-003", "ST-002", "ST-004", "ST-002"]
dup_counts = Counter(station_ids)
duplicates = [sid for sid, c in dup_counts.items() if c > 1]
print("Duplicate station IDs:", duplicates)

Note pratiche e insidie comuni

Questi dettagli fanno risparmiare tempo ed evitano bug sottili.

  • Counter è simile a un dict: le chiavi mancanti restituiscono 0; usa del counter[key] per rimuovere voci. Evita di archiviare zeri a meno che non ti servano temporaneamente.
  • Non affidarti all’ordine di iterazione. Usa most_common() per un output ordinato per ranking.
  • str.count() conta le occorrenze non sovrapposte. Per contare sottostringhe sovrapposte, usa re.finditer().
  • Evita chiamate ripetute a list.count() sulla stessa sequenza grande. Costruisci un unico Counter.
  • In pandas, .count() serve per i conteggi di non-mancanti; usa .value_counts() per le frequenze dei valori.

Pattern minimi su cui faccio affidamento

Questi sono gli snippet che uso più spesso in produzione e in didattica.

  • Mappa di frequenza in un solo passaggio: Counter(iterable)
  • Categorie top-N: Counter(data).most_common(n)
  • Aggiornamenti incrementali: counter.update(batch) o counter.subtract(batch)
  • Verifica per singolo valore: sequence.count(x) (evita nei cicli)
  • Frequenze tabellari: df["col"].value_counts() (non df.count())

Conclusione

collections.Counter è lo strumento giusto per contare rapidamente e con chiarezza più valori. Usa count() integrato per verifiche spot, Counter per mappe di frequenza e analisi top-N, e Series.value_counts() quando lavori in pandas. Tieni d’occhio i casi limite nel conteggio delle stringhe, l’equivalenza booleano–intero e la differenza tra conteggi di non-mancanti e frequenze dei valori. Con questi pattern, i tuoi conteggi saranno sia veloci che corretti.

Argomenti

Correlato