Le correlazioni nascoste possono fuorviare le strategie di ottimizzazione
p99, ovvero il valore al di sotto del quale cade il 99% delle osservazioni, è ampiamente utilizzato per monitorare e ottimizzare le prestazioni nel caso peggiore in tutti i settori. Ad esempio, il tempo impiegato per caricare una pagina, evadere un ordine di acquisto o consegnare una spedizione può essere ottimizzato monitorando p99.
Sebbene p99 sia indubbiamente prezioso, è fondamentale riconoscere che ignora l'1% delle osservazioni più importanti, che potrebbero avere un impatto inaspettatamente ampio quando sono correlate ad altri parametri aziendali critici. Inseguire ciecamente p99 senza verificare tali correlazioni può potenzialmente compromettere altri obiettivi aziendali.
In questo articolo analizzeremo i limiti di p99 attraverso un esempio con dati fittizi, capiremo quando fare affidamento su p99 ed esploreremo metriche alternative.
Considera una piattaforma di e-commerce in cui un team ha il compito di ottimizzare l'esperienza di pagamento del carrello. Il team ha ricevuto lamentele da parte dei clienti secondo cui il check-out è piuttosto lento rispetto ad altre piattaforme. Quindi, il team acquisisce gli ultimi 1.000 checkout e analizza il tempo impiegato per il checkout. (Ho creato alcuni dati fittizi per questo, sei libero di usarli e armeggiarci senza restrizioni)
import pandas as pd
import seaborn as sns
order_time = pd.read_csv('https://gist.githubusercontent.com/kkraoj/77bd8332e3155ed42a2a031ce63d8903/raw/458a67d3ebe5b649ec030b8cd21a8300d8952b2c/order_time.csv')
fig, ax = plt.subplots(figsize=(4,2))
sns.histplot(data = order_time, x = 'fulfillment_time_seconds', bins = 40, color = 'k', ax = ax)
print(f'p99 for fulfillment_time_seconds: {order_time.fulfillment_time_seconds.quantile(0.99):0.2f} s')
Come previsto, la maggior parte delle operazioni di pagamento del carrello sembrano essere completate in pochi secondi. E il 99% dei checkout avviene entro 12,1 secondi. In altre parole, il p99 è di 12,1 secondi. Ci sono alcuni casi a coda lunga che richiedono fino a 30 secondi. Dato che sono così pochi, potrebbero essere valori anomali e dovrebbero essere ignorati in modo sicuro, giusto?
Ora, se non ci fermiamo e non analizziamo le implicazioni dell'ultima frase, potrebbe essere piuttosto pericoloso. È davvero sicuro ignorare l’1% più ricco? Siamo sicuri che gli orari di checkout non siano correlati ad altri parametri aziendali?
Diciamo che la nostra società di e-commerce si preoccupa anche del valore lordo delle merci (GMV) e ha l'obiettivo generale a livello aziendale di aumentarlo. Dovremmo verificare immediatamente se il tempo impiegato alla cassa è correlato al GMV prima di ignorare l'1% più ricco.
import matplotlib.pyplot as plt
from matplotlib.ticker import ScalarFormatter
order_value = pd.read_csv('https://gist.githubusercontent.com/kkraoj/df53cac7965e340356d6d8c0ce24cd2d/raw/8f4a30db82611a4a38a90098f924300fd56ec6ca/order_value.csv')
df = pd.merge(order_time, order_value, on='order_id')
fig, ax = plt.subplots(figsize=(4,4))
sns.scatterplot(data=df, x="fulfillment_time_seconds", y="order_value_usd", color = 'k')
plt.yscale('log')
ax.yaxis.set_major_formatter(ScalarFormatter())
Oh ragazzo! Non solo il valore del carrello è correlato ai tempi di pagamento, ma aumenta esponenzialmente per tempi di pagamento più lunghi. Qual è la penalità se si ignora l'1% più ricco degli orari di checkout?
pct_revenue_ignored = df2.loc(df1.fulfilment_time_seconds>df1.fulfilment_time_seconds.quantile(0.99), 'order_value_usd').sum()/df2.order_value_usd.sum()*100
print(f'If we only focussed on p99, we would ignore {pct_revenue_ignored:0.0f}% of revenue')
## >>> If we only focussed on p99, we would ignore 27% of revenue
Se ci concentrassimo solo su p99, ignoreremmo il 27% delle entrate (27 volte maggiore dell’1% che pensavamo di ignorare). Cioè, p99 dei tempi di pagamento corrispondono a p73 delle entrate. Concentrarsi su p99 in questo caso danneggia inavvertitamente l'azienda. Ignora le esigenze dei nostri acquirenti di maggior valore.
df.sort_values('fulfillment_time_seconds', inplace = True)
dfc = df.cumsum()/df.cumsum().max() # percent cumulative sum
fig, ax = plt.subplots(figsize=(4,4))
ax.plot(dfc.fulfillment_time_seconds.values, color = 'k')
ax2 = ax.twinx()
ax2.plot(dfc.order_value_usd.values, color = 'magenta')
ax.set_ylabel('cumulative fulfillment time')
ax.set_xlabel('orders sorted by fulfillment time')
ax2.set_ylabel('cumulative order value', color = 'magenta')
ax.axvline(0.99*1000, linestyle='--', color = 'k')
ax.annotate('99% of orders', xy = (970,0.05), ha = 'right')
ax.axhline(0.73, linestyle='--', color = 'magenta')
ax.annotate('73% of revenue', xy = (0,0.75), color = 'magenta')
Sopra vediamo perché c’è una grande discrepanza tra i percentili degli orari di checkout e il GMV. La curva GMV sale bruscamente vicino al 99° percentile degli ordini, facendo sì che l’1% più ricco degli ordini abbia un impatto enorme sul GMV.
Questo non è solo un artefatto dei nostri dati fittizi. Tali correlazioni estreme purtroppo non sono rare. Ad esempio, rappresenta l'1% più ricco dei clienti di Slack 50% delle entrate. Circa il 12% delle entrate di UPS proviene da solo 1 cliente (Amazzonia).
Per evitare le insidie dell’ottimizzazione solo per p99, possiamo adottare un approccio più olistico.
Una soluzione è monitorare simultaneamente sia p99 che p100 (il valore massimo). In questo modo, non saremo inclini a ignorare gli utenti di alto valore.
Un'altra soluzione consiste nell'utilizzare p99 ponderato in base ai ricavi (o ponderato in base al valore lordo della merce, al profitto o a qualsiasi altro parametro aziendale di interesse), che assegna maggiore importanza alle osservazioni con entrate associate più elevate. Questa metrica garantisce che gli sforzi di ottimizzazione diano priorità alle transazioni o ai processi di maggior valore, anziché trattare tutte le osservazioni allo stesso modo.
Infine, quando esistono correlazioni elevate tra prestazioni e parametri aziendali, p99.5 o p99.9 più rigorosi possono mitigare il rischio di ignorare utenti di alto valore.
È forte la tentazione di fare affidamento esclusivamente su parametri come p99 per gli sforzi di ottimizzazione. Tuttavia, come abbiamo visto, ignorare l’1% delle osservazioni più importanti può avere un impatto negativo su un’ampia percentuale di altri risultati aziendali. Il monitoraggio sia di p99 che di p100 o l'utilizzo di p99 ponderato in base ai ricavi può fornire una visione più completa e mitigare i rischi dell'ottimizzazione solo per p99. Per lo meno, ricordiamoci di evitare di concentrarci esclusivamente su alcuni parametri di prestazione perdendo di vista i risultati complessivi del cliente.
Fonte: towardsdatascience.com