Pandas & NumPy Academy · Lezione

Ranghi e percentili all'interno dei gruppi

Calcoli i ranghi all'interno dei gruppi usando groupby().rank() e crei intervalli percentile con pd.qcut per confronti relativi.

Lezione 4 di 413 passaggi

Ranghi e percentili all'interno dei gruppi è una lezione Pandas & NumPy Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Pandas & NumPy Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Pandas & NumPy Academy include 4 lezioni in totale.

Perché calcolare il rango all'interno dei gruppi?

I valori grezzi sono spesso meno significativi delle posizioni relative. Un rappresentante commerciale con un fatturato mensile di 50.000 $ è un ottimo performer se la media è di 30.000 $, ma è un performer scarso se la media è di 80.000 $. Calcolando i ranghi all'interno dei gruppi (ad esempio, il rango all'interno di ciascuna regione o di ciascun trimestre), ottiene un confronto normalizzato che tiene conto delle diverse basi di riferimento tra i gruppi. Pandas semplifica il calcolo dei ranghi all'interno dei gruppi con groupby().rank().

import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    'rep': ['Alice', 'Bob', 'Carol', 'Dave', 'Eve',
            'Frank', 'Grace', 'Hank', 'Iris', 'Jake'],
    'region': ['East']*5 + ['West']*5,
    'sales': np.random.randint(30000, 100000, 10)
})
print(df.sort_values('region'))

Series.rank() — Calcolo di base dei ranghi

Series.rank() assegna un rango a ogni valore: il rango 1 corrisponde al valore più piccolo, mentre il rango n al più grande. Il parametro ascending=False inverte la direzione, quindi il rango 1 corrisponde al valore più grande. Il risultato è una Series di tipo float, non intero, perché per impostazione predefinita i valori a pari merito vengono risolti calcolando la media dei ranghi corrispondenti. Per una colonna con 5 valori, i ranghi vanno da 1.0 a 5.0; in presenza di pari merito, alcuni valori possono condividere un rango come 2.5.

import pandas as pd

s = pd.Series([80, 45, 90, 45, 70])

print('Values:', s.values)
print('Rank (ascending=True, default):', s.rank().values)
print('Rank (ascending=False — best=1):', s.rank(ascending=False).values)
# Note: two 45s share ranks 1 and 2 → both get 1.5

Metodi di risoluzione dei pari merito in rank()

Il parametro method controlla il comportamento dei valori a pari merito. Le opzioni sono: 'average' (predefinita: i valori a pari merito condividono la media dei rispettivi ranghi), 'min' (a tutti i valori a pari merito viene assegnato il rango più basso), 'max' (a tutti viene assegnato il rango più alto), 'first' (i ranghi vengono assegnati in ordine di apparizione, senza pari merito) e 'dense' (non ci sono salti nei ranghi: 1, 2, 3, 3, 4 diventa 1, 2, 3, 3, 4 invece di 1, 2, 3, 3, 5). Il metodo 'dense' è particolarmente utile per i ranghi in stile percentile.

import pandas as pd

s = pd.Series([80, 45, 90, 45, 70])

result = pd.DataFrame({
    'value': s,
    'average': s.rank(method='average'),
    'min': s.rank(method='min'),
    'max': s.rank(method='max'),
    'first': s.rank(method='first'),
    'dense': s.rank(method='dense')
})
print(result)

Calcolo dei ranghi all'interno dei gruppi con groupby().rank()

groupby('group_col')['value_col'].rank() calcola i ranghi indipendentemente all'interno di ogni gruppo. Il rango riparte dall'inizio di ciascun gruppo: quindi il performer migliore nella regione East ottiene il rango 1 in East e il migliore nella regione West ottiene anch'egli il rango 1 in West. È questo che rende il calcolo dei ranghi con groupby così utile per confronti equi tra gruppi.

import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    'rep': list('ABCDEABCDE'),
    'region': ['East']*5 + ['West']*5,
    'sales': np.random.randint(30000, 100000, 10)
})

# Rank within each region (best = rank 1)
df['rank_in_region'] = df.groupby('region')['sales'].rank(ascending=False, method='min')
df_sorted = df.sort_values(['region', 'rank_in_region'])
print(df_sorted.to_string(index=False))

Calcolo del percentile con rank(pct=True)

Impostando pct=True in rank() si ottiene il rango percentile: un valore compreso tra 0 e 1 che rappresenta la frazione dei valori del gruppo minori o uguali al valore corrente. Un rango percentile pari a 0.8 significa che il valore si trova all'80º percentile, cioè è superiore all'80% di tutti i valori. Questa normalizzazione rende direttamente confrontabili i valori appartenenti a gruppi di dimensioni diverse, senza conoscere l'effettiva dimensione dei gruppi.

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({
    'name': list('ABCDEFGHIJ'),
    'region': ['East']*5 + ['West']*5,
    'score': np.random.randint(50, 100, 10)
})

# Percentile rank within region
df['pct_rank'] = df.groupby('region')['score'].rank(pct=True)
df['percentile'] = (df['pct_rank'] * 100).round(0).astype(int)
print(df.sort_values(['region', 'percentile'], ascending=[True, False]).to_string(index=False))

pd.qcut: suddivisione basata sui quantili

pd.qcut(series, q) suddivide i valori in q intervalli con la stessa frequenza, in modo che ogni intervallo contenga approssimativamente lo stesso numero di osservazioni. A differenza di pd.cut, che utilizza intervalli di uguale ampiezza, pd.qcut adatta i limiti degli intervalli alla distribuzione dei dati. È ideale per creare quartili (q=4), quintili (q=5) o decili (q=10) per fasce di performance.

import pandas as pd
import numpy as np

np.random.seed(42)
sales = pd.Series(np.random.exponential(scale=50000, size=100))

# Divide into quartiles
quartiles = pd.qcut(sales, q=4, labels=['Q1', 'Q2', 'Q3', 'Q4'])

result = pd.DataFrame({'sales': sales, 'quartile': quartiles})
print('Quartile counts (should be ~25 each):')
print(result['quartile'].value_counts().sort_index())
print('\nMean sales per quartile:')
print(result.groupby('quartile')['sales'].mean().round(0))

pd.cut e pd.qcut a confronto

pd.cut(series, bins=n) crea intervalli di uguale ampiezza (stesso intervallo, quantità diverse). pd.qcut(series, q=n) crea intervalli con la stessa frequenza (stessa quantità, intervalli diversi). Per i dati asimmetrici, pd.cut produce intervalli quasi vuoti nelle code, mentre pd.qcut distribuisce uniformemente le osservazioni. Scelga pd.cut quando i limiti degli intervalli hanno un significato aziendale naturale (fasce di prezzo, gruppi di età); scelga pd.qcut per le fasce di performance quando desidera gruppi della stessa dimensione.

import pandas as pd
import numpy as np

np.random.seed(0)
# Right-skewed data
data = pd.Series(np.random.exponential(1, 100))

cut_result = pd.cut(data, bins=5).value_counts().sort_index()
qcut_result = pd.qcut(data, q=5).value_counts().sort_index()

print('Equal-width bins (pd.cut) — uneven counts:')
print(cut_result.to_string())
print('\nEqual-frequency bins (pd.qcut) — even counts:')
print(qcut_result.to_string())

Creazione delle etichette dei decili con pd.qcut

pd.qcut(series, q=10, labels=range(1,11)) assegna ogni osservazione al proprio decile (da 1 a 10). È una tecnica standard nell'analisi di marketing (decili del valore dei clienti), nel credit scoring (decili di rischio) e nei test AB (decili di traffico per l'analisi delle coorti). Il parametro labels può contenere qualsiasi elenco della stessa lunghezza di q: utilizzi stringhe come ['Bottom 10%', ..., 'Top 10%'] per ottenere un risultato più leggibile.

import pandas as pd
import numpy as np

np.random.seed(7)
customer_value = pd.Series(np.random.exponential(500, 1000))

# Assign to deciles 1-10
decile_labels = [f'D{i}' for i in range(1, 11)]
customer_decile = pd.qcut(
    customer_value,
    q=10,
    labels=decile_labels
)

result = pd.DataFrame({'value': customer_value, 'decile': customer_decile})
print('Mean customer value per decile:')
print(result.groupby('decile')['value'].mean().round(0))

Intervalli percentili all'interno dei gruppi

Combini groupby con pd.qcut usando transform per creare intervalli percentili all'interno di ogni gruppo. È utile quando desidera classificare i clienti all'interno di ciascuna regione, anziché a livello globale: un cliente nel decile globale più basso potrebbe trovarsi nel decile regionale più alto. Utilizzi groupby('group')['value'].transform(lambda x: pd.qcut(x, q=4, labels=['Q1','Q2','Q3','Q4'])).

import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    'customer': range(20),
    'region': ['North']*10 + ['South']*10,
    'spend': np.random.randint(100, 1000, 20)
})

# Quartile within each region
def quartile_label(x):
    return pd.qcut(x, q=4, labels=['Q1','Q2','Q3','Q4'])

df['region_quartile'] = df.groupby('region')['spend'].transform(quartile_label)
print(df.sort_values(['region', 'region_quartile']).to_string(index=False))

Top-N all'interno dei gruppi

Una domanda aziendale frequente è: «chi sono i 3 performer migliori in ogni regione?». Utilizzi groupby().rank() e poi filtri in base al rango: df[df['rank_col'] <= 3]. Questo funziona correttamente con gruppi di qualsiasi dimensione e gestisce bene i pari merito, mantenendo più di 3 righe se al limite sono presenti ranghi uguali. In alternativa, utilizzi groupby().nlargest(n), che restituisce direttamente i n valori più grandi per ogni gruppo senza aggiungere una colonna con il rango.

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({
    'rep': [f'Rep_{i}' for i in range(15)],
    'region': ['East']*5 + ['West']*5 + ['North']*5,
    'revenue': np.random.randint(40000, 120000, 15)
})

df['region_rank'] = df.groupby('region')['revenue'].rank(ascending=False, method='min')

print('Top 2 per region:')
top2 = df[df['region_rank'] <= 2].sort_values(['region', 'region_rank'])
print(top2[['rep', 'region', 'revenue', 'region_rank']].to_string(index=False))

Combinare rango e transform per la normalizzazione

Può usare groupby().rank(pct=True) insieme a transform per aggiungere una colonna con il rango percentile al DataFrame originale. Questa colonna normalizzata è spesso più utile come feature di un modello rispetto al valore grezzo: non dipende dalla scala ed è confrontabile tra gruppi. Nel machine learning, i ranghi percentili sono una semplice alternativa alla standardizzazione (z-score), più robusta rispetto agli outlier.

import pandas as pd
import numpy as np

np.random.seed(1)
df = pd.DataFrame({
    'product': np.random.choice(['A', 'B', 'C'], 30),
    'score': np.random.randint(50, 100, 30)
})

# Percentile rank within each product group
df['global_pct'] = df['score'].rank(pct=True).round(3)
df['group_pct'] = df.groupby('product')['score'].rank(pct=True).round(3)

print(df.sort_values(['product', 'score']).head(12).to_string(index=False))

Verifica rapida

Verifichi la Sua comprensione delle operazioni sui ranghi e sui percentili presentate in questa lezione.

Riepilogo della lezione

In questa lezione ha imparato che: Series.rank() calcola ranghi numerici con una gestione configurabile dei pari merito; groupby().rank() riavvia i ranghi all'interno di ogni gruppo per consentire confronti equi tra gruppi; pct=True converte i ranghi in percentili (da 0 a 1); pd.qcut crea intervalli con la stessa frequenza per assegnare fasce di quartili, decili e percentili. Ora esamineremo i suggerimenti sulle prestazioni di Pandas: profilazione, come evitare i cicli lenti e tipi di dati efficienti.

Gratis per iniziare

Impara Python con un tutor IA — gratis

Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.

Corsi
30
Lezioni
120

Domande Frequenti

La lezione «Ranghi e percentili all'interno dei gruppi» è gratuita?

Sì — il testo completo di «Ranghi e percentili all'interno dei gruppi» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Pandas & NumPy Academy, passa a CoddyKit PRO. Il corso Pandas & NumPy Academy include 4 lezioni in totale.

Cosa imparerò in «Ranghi e percentili all'interno dei gruppi»?

Calcoli i ranghi all'interno dei gruppi usando groupby().rank() e crei intervalli percentile con pd.qcut per confronti relativi. Eserciti Pandas & NumPy Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Pandas & NumPy Academy?

Non è richiesta alcuna esperienza precedente. Pandas & NumPy Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Ranghi e percentili all'interno dei gruppi»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Pandas & NumPy Academy?

Sì. Ogni lezione Pandas & NumPy Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Finestre mobili
  2. Finestre espandibili
  3. Media mobile ponderata esponenzialmente
  4. Ranghi e percentili all'interno dei gruppi
← Torna a Pandas & NumPy Academy