case history
Case #01 · Data Analysis

Analisi quantitativa di una chat di team per verificare un bias percettivo

Uno sviluppatore convinto di essere ignorato. 18 mesi di messaggi. Un parser Python. La risposta era nei dati, non nelle impressioni.

SettoreTeam remoto / Startup
StrumentiPython, regex, datetime
Durata analisi~30 minuti
OutputConfutazione statistica

Il problema

Marco, sviluppatore backend in un team remoto di 5 persone, si convince nel tempo che le sue proposte tecniche vengano sistematicamente ignorate nelle discussioni sul canale di team.

La sensazione è precisa: quando propone qualcosa — una libreria, un approccio architetturale, una modifica al workflow — la conversazione continua come se non avesse scritto nulla. Quando lo fa Giulia (la tech lead) o Dario (il senior più prolisso del team), la risposta arriva in pochi minuti.

Marco ne parla con una collega di fiducia. La collega dice: "Sicuro che non sia una tua impressione?" Marco: "Sicurissimo. Ti mando i messaggi dove si vede."

Ma invece di raccogliere esempi selettivi, decidono di analizzare l'intera chat.

L'analisi

Il team usa WhatsApp per le comunicazioni rapide. Marco esporta la chat: 18 mesi di conversazioni, ~15.000 messaggi.

WhatsApp esporta in formato .txt con struttura GG/MM/AA, HH:MM - Mittente: Testo. Un parser regex standard estrae ogni messaggio con timestamp e autore.

import re
from datetime import datetime

pattern = re.compile(r'^(\d{2}/\d{2}/\d{2}, \d{2}:\d{2}) - ([^:]+): (.+)$')

messages = []
with open("chat.txt", "r", encoding="utf-8") as f:
    for line in f:
        m = pattern.match(line.strip())
        if m:
            ts_str, sender, text = m.groups()
            ts = datetime.strptime(ts_str, "%d/%m/%y, %H:%M")
            messages.append({"ts": ts, "sender": sender, "text": text})

Metrica 1 — Topic-starter rate: quando qualcuno rompe il silenzio (gap >30 min dal suo ultimo messaggio) e apre un nuovo filone, quanto spesso viene raccolto entro 60 minuti? Filtra i messaggi "di risposta" e isola le iniziative genuine.

Questo metodo ha però un limite fondamentale: conta come "risposta" qualsiasi messaggio successivo, anche se qualcun altro ha nel frattempo cambiato argomento. Se Marco scrive "guardate questo link" e poi Luca dice "raga, ho comprato una macchina nuova" e tutti rispondono a Luca — il sistema contava la risposta di Luca come risposta a Marco.

Metrica 2 — Word overlap (più accurata): per ogni messaggio di apertura topic, si analizza il primo messaggio di risposta e si verifica se condivide parole significative col messaggio originale. Se l'overlap è zero, il primo a rispondere ha cambiato argomento — bypass. Se c'è overlap, stava rispondendo al topic originale.

STOPWORDS = {'e', 'è', 'la', 'il', 'ok', 'dai', 'raga', 'ma', 'che', ...}

def get_keywords(text, min_len=3):
    words = re.findall(r'[a-zA-ZàèéìíîòóùúÀÈ]+', text.lower())
    return {w for w in words if len(w) >= min_len and w not in STOPWORDS}

def topic_overlap(text_a, text_b):
    kw_a = get_keywords(text_a)
    kw_b = get_keywords(text_b)
    if not kw_a:
        return 0
    return len(kw_a & kw_b)

# Per ogni topic-starter di X:
# - trova il primo messaggio non-X entro 60 min
# - se overlap > 0 → risposta diretta
# - se overlap = 0 e X aveva keywords → bypass (cambio topic)

Risultati — Metrica 1 (topic-starter rate)

PersonaTopic avviatiRisposta entro 60 min%
Giulia (tech lead)~800~70488%
Sara (PM)~420~35785%
Dario (senior)~760~63183%
Luca (junior)~280~22781%
Marco~700~57482%

Marco è sostanzialmente identico agli altri. Ma questo include il caso "Luca risponde di macchine mentre Marco parlava di link".

Risultati — Metrica 2 (word overlap)

PersonaRisposta direttaBypass (cambio topic)Ignorato
Giulia (tech lead)22%57%21%
Sara (PM)19%63%18%
Dario (senior)17%64%19%
Luca (junior)16%68%16%
Marco24%55%21%

Il bypass rate alto per tutti (55–68%) riflette la natura delle chat di gruppo: le conversazioni si sovrappongono costantemente. La colonna rilevante è quella relativa tra i membri. Marco ha il miglior direct reply rate e il minor bypass rate del team.

Diagnosi

Il bias di conferma funziona così: si nota e si memorizza ogni caso in cui si viene ignorati o scavalcati. Non si nota quando si riceve risposta, perché è la norma — non fa notizia. Nel tempo, i casi salienti (bypass, silenzio) sovrastimano la frequenza reale.

Con entrambe le metodologie — la semplice e quella che tiene conto del cambio topic — Marco risulta trattato come tutti gli altri. Anzi leggermente meglio. Il problema percepito non è nella chat, è nel modo in cui il cervello seleziona i ricordi.

Applicazioni pratiche

Dati necessari: solo l'export .txt di WhatsApp (o .json di Slack). Zero API, zero infrastruttura. Un file Python di ~100 righe.

Limitazioni

Dare un numero a una percezione la trasforma da conflitto interpersonale a dato analizzabile. In questo caso il dato ha rassicurato Marco e chiuso una ruminazione che stava diventando logorante. In altri scenari — dove il dato avesse confermato la percezione — avrebbe fornito evidenza concreta su cui agire.

Python data analysis WhatsApp bias di conferma team dynamics