4 Modi per Quantificare le Code Grasse con Python

4 Metodi per Misurare le Code Grasse con Python

Intuizione e codice di esempio

Questo è il terzo articolo di una serie su Leggi di Potenza e Code Grasse. Nel post precedente, abbiamo esplorato come rilevare leggi di potenza dai dati empirici. Sebbene questa tecnica possa essere utile, le code grasse vanno oltre il semplice adattamento dei dati a una distribuzione di legge di potenza. In questo articolo, analizzerò 4 modi per quantificare le code grasse e condividerò codice di esempio Python che analizza dati del mondo reale.

Nota: se non sei familiare con termini come distribuzione di legge di potenza o code grasse, leggi questo articolo come introduzione.

Una coda grassa (di un gatto). Immagine da Canva.

Nel primo articolo di questa serie, abbiamo introdotto l’idea di code grasse, che descrive il grado in cui eventi rari influenzano le statistiche aggregate di una distribuzione. Abbiamo visto un esempio estremo di code grasse attraverso la distribuzione di Pareto, in cui ad esempio l’80% delle vendite è generato dal 20% dei clienti (e il 50% delle vendite è generato solo dall’1% dei clienti).

Pareto, leggi di potenza e code grasse

Ciò che non ti insegnano nelle statistiche

towardsdatascience.com

Sebbene la distribuzione di Pareto (e più in generale le leggi di potenza) ci offra un esempio evidente di code grasse, questa è una nozione più generale che si situa su uno spettro che va da code sottili (ad esempio una Gaussian) a code molto grasse (ad esempio Pareto 80-20).

Lo spettro delle code grasse. Immagine dell'autore.

Questa visione delle code grasse ci fornisce un modo più flessibile e preciso di classificare i dati rispetto alla semplice etichettatura come Legge di Potenza (o meno). Tuttavia, sorge la domanda: come definiamo le code grasse?

4 modi per quantificare le code grasse

Anche se non esiste una misura “vera” delle code grasse, ci sono alcune euristiche (cioè regole empiriche) che possiamo utilizzare per quantificare la presenza di code grasse nei dati. Qui, esamineremo 4 di tali euristiche. Inizieremo introducendo ogni tecnica concettualmente e poi approfondiremo con esempi di codice Python.

Euristica 1: Indice di code di legge di potenza

Le code più grasse si trovano nelle distribuzioni di legge di potenza, dove più piccolo è l’indice di code (ovvero α) di una legge di potenza, più grassa è la coda, come illustrato nell’immagine sottostante.

Esempi di distribuzioni di legge di potenza con vari valori di α. Immagine dell'autore.

Questa osservazione che indici di code più piccoli implicano code più grasse ci spinge naturalmente a utilizzare α per quantificare le code grasse. Nella pratica, ciò si traduce nell’adattamento di una distribuzione a legge di potenza a un determinato dataset e nell’estrazione del valore stimato di α.

Pur essendo un approccio diretto, ha una limitazione ovvia. Nello specifico, l’approccio fallisce quando si lavora con dati che seguono male una legge di potenza.

Euristica 2: Curtosi (ovvero non-gaussiana)

L’opposto di una coda grassa è una coda sottile (ovvero eventi rari così rari che sono insignificanti). Un esempio di coda sottile è la stimata distribuzione gaussiana, in cui la probabilità di un evento a 6 sigma dalla media è di circa 1 su un miliardo.

Da qui nasce una misura delle code grasse, valutando quanto i dati sono “NON-gaussiani”. Possiamo farlo attraverso misure di non-gaussianità. Anche se potremmo creare molte di queste misure, la più popolare è la Curtosi, definita dall’espressione sottostante.

Definizione di curtosi secondo ref [1] e [2]. Immagine dell'autore.

La curtosi è influenzata dai valori lontani dal centro, ovvero le code. Pertanto, più grande è la curtosi, più grassa è la coda.

Questa misura funziona bene quando tutti i momenti sono finiti. Tuttavia, una delle principali limitazioni è che la curtosi non è definita per alcune distribuzioni, ad esempio la distribuzione di Pareto con α < 4, il che la rende inutile per molti dati con code grasse.

Euristica 3: σ delle log-normali

In passati articoli di questa serie, abbiamo discusso della distribuzione log-normale, definita dalla funzione di densità di probabilità sottostante.

Funzione di densità di probabilità della distribuzione log-normale [4]. Immagine dell'autore.

Come abbiamo visto in precedenza, questa distribuzione è un po’ birichina perché può sembrare simile a una gaussiana per σ bassi, ma simile a una distribuzione di Pareto per σ alti. Questo ci fornisce naturalmente un altro modo per quantificare le code grasse, dove più grande è σ, più grassa è la coda.

Possiamo ottenere questa misura in modo simile all’Euristica 1. In altre parole, adattiamo una distribuzione log-normale ai nostri dati ed estraiamo il valore σ dell’adattamento. Anche se è una procedura semplice, questa (come l’Euristica 1) fallisce quando l’adattamento log-normale non spiega bene i dati sottostanti.

Euristica 4: κ di Taleb

Le euristiche precedenti (H) partivano da una distribuzione specifica in mente (ossia, H1 – Legge di Potenza e H3 – Log-normale). In pratica, tuttavia, raramente i nostri dati seguono esattamente una particolare distribuzione.

Inoltre, le comparazioni utilizzando queste misure possono essere problematiche quando si valutano due variabili che seguono distribuzioni qualitativamente diverse. Ad esempio, utilizzare l’indice di coda di una legge di potenza per confrontare dati simili a Pareto e dati simili a una gaussiana potrebbe avere poco significato, dato che una legge di potenza si adatta male ai dati simili a una gaussiana.

Ciò giustifica l’uso di misure non specifiche per una distribuzione delle code grasse. Una misura del genere è stata proposta da Taleb in ref [3]. La misura proposta (κ) è definita per dati unimodali con media finita e assume valori compresi tra 0 e 1, dove 0 indica dati con code minimamente grasse e 1 implica dati con code massimamente grasse. È definita secondo l’espressione sottostante.

Definizione della metrica κ di Taleb [3]. Immagine dell'autore.

La metrica confronta due campioni (diciamo, Sₙ₀ e Sₙ) dove Sₙ è la somma di n campioni estratti da una particolare distribuzione. Ad esempio, se valutiamo una distribuzione gaussiana e scegliamo n=100, estrarremmo 100 campioni da una gaussiana e li sommeremmo tutti insieme per creare S₁₀₀.

M(n) nell’espressione sopra indica la deviazione assoluta media, definita secondo l’equazione qui sotto. Questa misura della dispersione intorno alla media tende ad essere più robusta rispetto alla deviazione standard [3][5].

Definizione della deviazione assoluta media dall'equazione κ [3]. Immagine dell'autore.

Per semplificare le cose, possiamo scegliere n₀=1, ottenendo l’espressione qui sotto.

κ con n₀=1. Immagine dell'autore.

Il termine chiave qui è M(n)/M(1), dove M(n) quantifica la dispersione intorno alla media per la somma di n campioni (di una certa distribuzione).

Per le distribuzioni a coda sottile, M(30) sarà relativamente vicino a M(1) poiché i dati generalmente si concentrano vicino alla media. Quindi, M(30)/M(1) ~ 1.

Tuttavia, per i dati a coda grassa, M(30) sarà molto più grande di M(1). Quindi, M(30)/M(1) >> 1. Questo viene illustrato di seguito, dove il grafico a sinistra mostra come la dispersione scala per una somma di gaussiane, e il grafico a destra mostra come scala per una distribuzione di Pareto.

Scaling di M(n) e M(1) per distribuzioni gaussiana (sinistra) e Pareto 80-20 (destra). Notare le etichette degli assi y. Nota: la scala della dispersione gaussiana aumenta a causa della somma di n distribuzioni. Immagine dell'autore.

Quindi, per i dati a coda grassa, il denominatore nell’equazione κ sarà più grande del numeratore, rendendo il secondo termine sul lato destro più piccolo e, alla fine, κ più grande.

Se tutto questo è stato troppo matematico per te, ecco il concetto principale: Grande κ = coda grassa, piccolo κ = coda sottile.

Codice di Esempio: Quantificare la Coda Grassa dei Dati (Reali) dei Social Media

Concetti eccessivamente concettuali a parte, vediamo come utilizzare queste euristiche nella pratica. Qui, utilizzeremo ciascuna delle approcci descritti sopra per analizzare gli stessi dati dell’articolo precedente di questa serie.

I dati provengono dai miei account di social media, che includono i follower mensili acquisiti su VoAGI, guadagni per video su YouTube, e impression giornaliere su LinkedIn. I dati e il codice sono liberamente disponibili nel repository GitHub.

YouTube-Blog/power-laws/3-quantifying-fat-tails at main · ShawhinT/YouTube-Blog

Codici per integrare video di YouTube e post del blog su VoAGI. – YouTube-Blog/power-laws/3-quantifying-fat-tails at main…

github.com

Iniziamo importando alcune librerie utili.

import matplotlib.pyplot as pltimport pandas as pdimport numpy as npimport powerlawfrom scipy.stats import kurtosis

Successivamente, importeremo ciascun dataset e li memorizzeremo in un dizionario.

filename_list = ['VoAGI-followers', 'YT-earnings', 'LI-impressions']df_dict = {}for filename in filename_list:    df = pd.read_csv('data/'+filename+'.csv')    df = df.set_index(df.columns[0]) # impostiamo l'indice    df_dict[filename] = df

A questo punto, è sempre una buona idea guardare i dati. Possiamo farlo tracciando degli istogrammi e stampando i primi 5 record per ciascun dataset.

for filename in filename_list:    df = df_dict[filename]        # tracciamo gli istogrammi (la funzione sotto è definita nel notebook su GitHub)    plot_histograms(df.iloc[:,0][df.iloc[:,0]>0], filename, filename.split('-')[1])    plt.savefig("images/"+filename+"_istogrammi.png")        # stampiamo i primi 5 record    print("Primi 5 record in percentuale")    print((df.iloc[:,0]/df.iloc[:,0].sum()).sort_values(ascending=False)[:5])    print("")
Istogrammi per i followers mensili di VoAGI. Immagine dell'autore.
Istogrammi per i guadagni dei video di YouTube. Nota: se noti una differenza rispetto all'articolo precedente, è perché ho trovato un record anomalo nei dati (ecco perché guardare è una buona idea 😅). Immagine dell'autore.
Istogrammi per le impressioni giornaliere di LinkedIn. Immagine dell'autore.

In base agli istogrammi sopra, ciascun dataset sembra avere una coda grassa in qualche misura. Vediamo i primi 5 record in percentuale per dare un’ulteriore occhiata a questo.

Primi 5 record in percentuale per ciascun dataset. Immagine dell'autore.

Da questa visione, i followers di VoAGI sembrano essere la categoria più grassa, con il 60% dei followers provenienti da soli 2 mesi. Anche i guadagni di YouTube presentano una coda grassa importante, con circa il 60% dei ricavi provenienti da soli 4 video. Le impressioni di LinkedIn sembrano essere la categoria con la coda meno grassa.

Anche se possiamo avere un’idea qualitativa della presenza di code grasse semplicemente guardando i dati, rendiamo questa valutazione più quantitativa attraverso le nostre 4 euristiche.

Euristica 1: Indice di coda di legge di potenza

Per ottenere un α per ciascun dataset, possiamo utilizzare la libreria powerlaw come abbiamo fatto nell’articolo precedente. Ciò viene fatto nel blocco di codice riportato di seguito, in cui eseguiamo l’adattamento e stampiamo le stime dei parametri per ciascun dataset in un ciclo for.

for filename in filename_list:    df = df_dict[filename]    # esegui l'adattamento al modello di legge potenza    results = powerlaw.Fit(df.iloc[:,0])    # stampa i risultati    print("")    print(filename)    print("-"*len(filename))    print("Adattamento al modello di legge potenza")    print("a = " + str(results.power_law.alpha-1))    print("xmin = " + str(results.power_law.xmin))    print("")
Risultati dell'adattamento al modello di legge potenza. Immagine dell'autore.

I risultati sopra corrispondono alla nostra valutazione qualitativa secondo cui i follower di VoAGI sono quelli con la coda più grassa, seguiti dai guadagni di YouTube e dalle impressioni di LinkedIn (ricorda, un α più piccolo significa una coda più grassa).

Euristica 2: Kurtosi

Un modo semplice per calcolare la Kurtosi è utilizzare una implementazione predefinita. Qui, utilizzo Scipy e stampo i risultati in modo simile a prima.

for filename in filename_list:    df = df_dict[filename]    # printa i risultati    print(filename)    print("-"*len(filename))    print("kurtosis = " + str(kurtosis(df.iloc[:,0], fisher=True)))    print("")
Valori di Kurtosi per ciascun dataset. Immagine dell'autore.

La Kurtosi ci racconta una storia diversa rispetto all’Euristica 1. La classifica dell’ampiezza di coda secondo questa misura è la seguente: LinkedIn > VoAGI > YouTube.

Tuttavia, questi risultati dovrebbero essere presi con le pinze. Come abbiamo visto con gli adattamenti al modello di legge potenza sopra, tutti e 3 i dataset si adattano a una legge di potenza con α < 4, il che significa che la Kurtosi è infinita. Quindi, sebbene il calcolo restituisca un valore, è probabile che siate scettici su questi numeri.

Euristica 3: σ di Log-normal

Possiamo di nuovo utilizzare la libreria powerlaw per ottenere stime σ simili a quanto fatto per l’Euristica 1. Ecco cosa appare.

for filename in filename_list:    df = df_dict[filename]    # esegui l'adattamento al modello di legge potenza    results = powerlaw.Fit(df.iloc[:,0])    # stampa i risultati    print("")    print(filename)    print("-"*len(filename))    print("Adattamento a Log-normal")    print("mu = " + str(results.lognormal.mu))    print("sigma = " + str(results.lognormal.sigma))    print("")
Risultati dell'adattamento a Log-normal. Immagine dell'autore.

Osservando i valori σ sopra, vediamo che tutti gli adattamenti implicano una coda grassa dei dati, dove i follower di VoAGI e le impressioni di LinkedIn hanno stime di σ simili. I guadagni di YouTube, al contrario, hanno un valore σ significativamente maggiore, il che implica una coda (molto) più grassa.

Una causa di sospetto, tuttavia, è che l’adattamento stimi un μ negativo, il che potrebbe suggerire che un adattamento a Log-normal potrebbe non spiegare bene i dati.

Euristica 4: κ di Taleb

Dato che non ho trovato un’implementazione Python prefabbricata per il calcolo di κ (non ho cercato molto a fondo), questo calcolo richiede alcuni passaggi aggiuntivi. In particolare, dobbiamo definire 3 funzioni di supporto, come mostrato di seguito.

def mean_abs_deviation(S):    """        Calcolo della deviazione media assoluta di un campione di input S    """    M = np.mean(np.abs(S - np.mean(S)))    return Mdef generate_n_sample(X,n):    """        Funzione per generare n campioni casuali di dimensione len(X) da un array X    """    # inizializza il campione    S_n=0        for i in range(n):        # campiona casualmente len(X) osservazioni da X e aggiungile al campione        S_n = S_n + X[np.random.randint(len(X), size=int(np.round(len(X))))]        return S_ndef kappa(X,n):    """        Misura kappa di Taleb da n0=1 come descritto qui: https://arxiv.org/abs/1802.05495        Nota: K_1n = kappa(1,n) = 2 - ((log(n)-log(1))/log(M_n/M_1)), dove M_n indica la deviazione media assoluta della somma di n campioni casuali    """    S_1 = X    S_n = generate_n_sample(X,n)        M_1 = mean_abs_deviation(S_1)    M_n = mean_abs_deviation(S_n)        K_1n = 2 - (np.log(n)/np.log(M_n/M_1))    return K_1n

La prima funzione, mean_abs_deviation(), calcola la deviazione media assoluta come definito in precedenza.

In seguito, abbiamo bisogno di un modo per generare e sommare n campioni dai nostri dati empirici. Qui, adotto un approccio ingenuo e campiono casualmente un array di input (X) n volte e sommo i campioni insieme.

Infine, unisco mean_abs_deviation(S) e generate_n_sample(X,n) per implementare il calcolo di κ definito in precedenza e calcolarlo per ciascun dataset.

n = 100 # numero di campioni da includere nel calcolo di kappafor filename in filename_list:    df = df_dict[filename]    # stampa i risultati    print(filename)    print("-"*len(filename))    print("kappa_1n = " + str(kappa(df.iloc[:,0].to_numpy(), n)))    print("")
Valori di κ(1,100) per ciascun dataset. Immagine dell'autore.

I risultati sopra ci danno un’altra storia. Tuttavia, data la casualità implicita di questo calcolo (ricordare la definizione di generate_n_sample()) e il fatto che stiamo trattando code grasse, le stime puntuali (cioè eseguire il calcolo una sola volta) non possono essere affidate.

Pertanto, eseguo lo stesso calcolo 1000 volte e stampo la media di κ(1,100) per ciascun dataset.

num_runs = 1_000kappa_dict = {}for filename in filename_list:    df = df_dict[filename]    kappa_list = []    for i in range(num_runs):        kappa_list.append(kappa(df.iloc[:,0].to_numpy(), n))        kappa_dict[filename] = np.array(kappa_list)    print(filename)    print("-"*len(filename))    print("media kappa_1n = " + str(np.mean(kappa_dict[filename])))    print("")
Valori medi di κ(1,100) da 1000 esecuzioni per ciascun dataset. Immagine dell'autore.

Questi risultati più stabili indicano che i follower di VoAGI sono i più a code grasse, seguiti dalle impressioni di LinkedIn e dai guadagni di YouTube.

Nota: Si possono confrontare questi valori con la Tabella III del riferimento [3] per comprendere meglio ciascun valore di κ. In particolare, questi valori sono paragonabili a una distribuzione di Pareto con α compreso tra 2 e 3.

Sebbene ogni euristica abbia raccontato una storia leggermente diversa, tutti gli indizi indicano che i follower di VoAGI acquisiti sono quelli con code più grasse tra i 3 dataset.

Conclusion

Anche se etichettare i dati come “fat-tailed” (o meno) può essere allettante, la presenza di code grasse è graduale. Qui abbiamo analizzato 4 euristiche per quantificare la presenza di dati con code grasse.

Sebbene ogni approccio abbia limitazioni, forniscono agli specialisti delle modalità quantitative per confrontare la presenza di code grasse nei dati empirici.

👉 Altro su Power Laws & Fat Tails: Introduzione | Adattamenti a legge di potenza

Risorse

Contatti: Il mio sito web | Prenota una chiamata | Chiedimi qualsiasi cosa

Socials: YouTube 🎥 | LinkedIn | Twitter

Supporto: Offrimi un caffè ☕️

The Data Entrepreneurs

Una comunità per gli imprenditori nel campo dei dati. 👉 Unisciti a Discord!

VoAGI.com

[1] Scipy Kurtosis

[2] Scipy Moment

[3] arXiv:1802.05495 [stat.ME]

[4] https://en.wikipedia.org/wiki/Log-normal_distribution

[5] Pham-Gia, T., & Hung, T. (2001). The mean and median absolute deviations. Mathematical and Computer Modelling, 34(7–8), 921–936. https://doi.org/10.1016/S0895-7177(01)00109-1