Eseguire calcoli con Envision - Software di ottimizzazione delle scorte

Eseguire calcoli con Envision












Home » Risorse » Qui

Envision offre la possibilità di eseguire qualsiasi calcolo disponibile anche con Excel. A tal proposito, la sintassi usata per eseguire i calcoli è molto simile a quella delle formule di Excel. Envision pone l'accento in particolare sui calcoli vettoriali, a cui ricorriamo per elaborare più valori alla volta, invece di procedere per singoli valori. In questa pagina ci concentreremo su tabelle e vettori, per aiutarvi a eseguire i primi calcoli con Envision.

Per seguire meglio il nostro ragionamento, suggeriamo di configurare il nostro campione dati. Non abbiamo ancora spiegato in dettaglio come caricare dati di input in Envision; se, però, viene usato il nostro campione, basterà aggiungere una sola riga (read "/sample" all) all'inizio dello script.

Tabelle e vettori

Il modello che è alla base di Envision è incentrato su tabelle e vettori. Una tabella Envision è simile alle tabelle dei database relazionali. In Excel, una tabella è un foglio di calcolo ben definito, in cui la prima riga contiene l'intestazione della colonna e le (numerose) righe successive contengono dati allineati correttamente con l'intestazione. In uno script Envision, le tabelle hanno sempre un nome, di solito derivato dal nome dei file tabellari corrispondenti. I vettori, anch'essi con un nome preciso, sono associati alle colonne della tabella. Envision usa il termine “vettore” anziché “colonna” per sottolineare la possibilità di calcolare tutti i valori del vettore insieme (ossia, tutti i valori contenuti nelle righe della tabella originale).

Vediamo un esempio illustrato di script da applicare ai nostri dati campione. Qui di seguito, per ogni linea di ordine, calcoliamo il tasso delle imposte, ossia il rapporto tra tasse e importo al netto delle tasse da applicare al cliente.
read "/sample/Lokad_Items.tsv"
read "/sample/Lokad_Orders.tsv" as Orders
read "/sample/Lokad_PurchaseOrders.tsv" as PO

Orders.TaxRate = Orders.TaxAmount / Orders.NetAmount
Qui, Orders (ordini) fa riferimento alla tabella con tutti i dati storici, in cui ogni transazione è rappresentata da tante righe quanti sono gli articoli all'interno della transazione. La variabile Orders.TaxAmount (ordini.importo tasse) fa riferimento al vettore associato alla colonna TaxAmount (importo delle tasse) all'interno della tabella Orders. Facciamo notare che, nella sintassi di Envision, è spesso usato un punto (.) tra il nome della tabella e il nome del vettore.

Le operazioni con il segno = sono definite assegnamenti: il calcolo è a destra del segno =, mentre il risultato è a sinistra. Nell'esempio sopra, abbiamo un'operazione di divisione a destra. Poiché né Orders.TaxAmount (importo delle tasse) né Orders.NetAmount (importo al netto delle tasse) sono definiti nello script, Envision tenta di caricare i dati direttamente dal set di input. Poiché la tabella Orders nel set di dati contiene due colonne NetAmount e TaxAmount, lo script è stato eseguito correttamente. A sinistra, invece, abbiamo Orders.TaxRate (ordini.tasso imposte), che dà il risultato appena calcolato. Un assegnamento è l'equivalente logico della creazione di una nuova colonna in Excel, denominata secondo la variabile di assegnamento (in questo caso, TaxRate).

Nei prossimi esempi, per pura concisione, omettiamo le righe read “/sample/Lokad_XYZ.tsv”, ma diamo per scontato che siano incluse sempre all'inizio dello script.

La sintassi usata per i calcoli in Envision è simile a quella delle formule di Excel. Nello script qui sotto, eseguiamo una serie di calcoli (piuttosto arbitrari) per illustrarla.
Orders.A = 42
Orders.B = 5 * (1 + Orders.A)
Orders.C = (Orders.A + Orders.B) * (1 + Orders.A)
Qui, lo script definisce tre vettori, A, B e C, tutti legati alla tabella Orders. La prima riga è un semplice assegnamento, in cui il valore 42 è assegnato a Orders.A. Tuttavia, poiché Orders.A è un vettore, non è un valore pari a 42, ma un valore per ogni riga della tabella originale. Envision pone l'accento sui vettori e i calcoli vettoriali vengono eseguiti su tutti i valori del vettore in una volta.

Poi, ricordiamo che Orders non è l'unica tabella presente nel nostro set di dati. Ad esempio, il set di dati contiene anche una tabella PO (ordini di acquisto). Anche in questo caso, possiamo eseguire lo stesso tipo di operazioni.
PO.A = 42
PO.B = 5 * (1 + PO.A)
PO.C = PO.A + PO.B
Ora che abbiamo introdotto una seconda tabella, sorge spontanea una domanda: Envision può eseguire operazioni tra tabelle diverse? Sì, certo, ma è necessario uno sforzo in più. Consideriamo lo script qui sotto:
Orders.A = 1
PO.A = Orders.A + 1 // SBAGLIATO!
Poiché le due tabelle Orders e PO non hanno alcun motivo per essere allineate (persino il numero di righe è diverso), la semantica associata a queste operazioni sarebbe piuttosto confusa. Quindi, un'operazione come questa non sarebbe valida in Envision: se anche proviamo a eseguire lo script, questo non viene eseguito correttamente e visualizziamo un messaggio di errore.

Ciò nonostante, Envision offre molti metodi per combinare dati provenienti da tabelle diverse. Vediamoli in dettaglio.

La tabella speciale “Articoli”

Le tabelle di Envision hanno tutte un nome, con una sola, importante eccezione: la tabella articoli. Nel settore commerciale, infatti, osserviamo che, per la stragrande maggioranza dei calcoli, c'è una sola tabella che domina costantemente le altre: la lista dei prodotti (o varianti, o SKU, a seconda dei casi e del settore di attività dell'azienda). A differenza, per esempio, dei database relazionali, in cui tutte le tabelle sono trattate allo stesso modo, Envision riserva un trattamento particolare alla tabella articoli, consentendo così di gestire in maniera ottimale quasi tutte le situazioni tipiche di un'attività commerciale.

A un certo punto della propria attività, ogni rivenditore, indipendentemente dalle dimensioni dell'azienda, si ritrova con un foglio di calcolo, contenente tutti i prodotti in catalogo, un prodotto per riga, e tante colonne piene di informazioni aggiuntive, dalle informazioni statiche (come le categorie dei prodotti) alle informazioni dinamiche (come le vendite totali nelle ultime 5 settimane). A seconda della situazione, le righe saranno associate a prodotti o SKU, o a un'altra rappresentazione specifica degli articoli venduti. Creare una tabella così dettagliata è una scelta pratica sotto molti punti di vista: identificazione dello stock morto, aggiornamento dei prezzi, classificazione dei prodotti più venduti, etc. Come professionisti del retail, vi saranno capitati sicuramente fogli di calcolo di questo tipo.

Noi di Lokad abbiamo constatato che simili fogli di calcolo sono praticamente onnipresenti nel retail e abbiamo quindi deciso di tenerne conto nella nostra tecnologia. Abbiamo, anzi, concepito Envision proprio per riflettere questa pratica così comune in ambito commerciale.

Ma torniamo ai nostri dati campione. Il set di dati contiene una lista di articoli. Supponiamo di voler calcolare il valore delle scorte per ogni prodotto. Se la tabella degli articoli è stata chiamata Items, potremmo scrivere così:
Items.StockValue = (Items.StockOnHand + Items.StockOnOrder) * BuyPrice
Tuttavia, solo ed esclusivamente nel caso di questa tabella, possiamo omettere il nome della tabella e scrivere:
StockValue = (StockOnHand + StockOnOrder) * BuyPrice
Il prefisso Items. viene rimosso e, per convenzione, tutte le variabili che non includono un punto (.) saranno implicitamente riferite a un vettore associato alla tabella degli articoli. Poiché i calcoli che riguardano i prodotti sono di gran lunga i più comuni per un'attività commerciale, questo sistema rende Envision molto più leggibile.

Uno dei motivi principali per cui i fogli di calcolo dedicati agli articoli sono così diffusi è che la maggioranza dei dati storici di un'attività commerciale possono essere facilmente rappresentati come una lista di eventi, ognuno dei quali è collegato a un articolo. Ad esempio, lo storico delle vendite è (come minimo) una tabella di tre colonne: identificativo dell'articolo, data e quantità acquistata. Lo storico degli acquisti può essere rappresentato con le stesse tre colonne, più, possibilmente, una quarta colonna con la data di arrivo per calcolare il lead time tra ordine e consegna. Anche i resi dei clienti possono essere rappresentati in una tabella contenente identificativo del prodotto, data, quantità e possibilmente identificativo del cliente, se vogliamo analizzare il comportamento dei clienti regolari.

La lista potrebbe continuare all'infinito. Il commercio è soprattutto una questione di flussi: flussi di beni, dai fornitori ai clienti; e flussi di denaro, dai clienti ai fornitori. Tutti questi flussi possono essere rappresentati in semplici righe, ognuna corrispondente a un articolo diverso. Nel caso delle attività commerciali, non cerchiamo delle tabelle qualsiasi, ma tabelle che siano incentrate sui prodotti. Questo è esattamente quello che fa Envision.

La tabella “Articoli” deve includere obbligatoriamente una sola colonna: l'identificativo del prodotto, “Id” secondo le convenzioni di Envision. Anche le altre tabelle che carichiamo su Envision hanno una propria colonna “Id”. Abbiamo visto prima come non sia possibile combinare le tabelle Orders e PO perché queste non sono allineate. Proprio la colonna Id è il “ponte” che ci consentirà di combinare le diverse tabelle.

Vediamo un esempio pratico con un calcolo in denaro. Supponiamo di voler calcolare per ogni articolo le entrate (associate all'intero storico delle vendite) e le uscite (associate all'intero storico degli acquisti). Scriviamo quindi lo script qui sotto.
CashIn = sum(Orders.NetAmount)
CashOut = sum(PO.NetAmount) 
CashFlow = CashIn - CashOut
Vediamo come a sinistra degli assegnamenti abbiamo gli “articoli”, mentre a destra abbiamo le altre tabelle, almeno alle righe 1 e 2. Usare più tabelle contemporaneamente, in questo caso, ha senso, data la presenza di una somma (sum()). La somma è un aggregatore, che non esamineremo in dettaglio in questa sede: basti sapere che, come suggerisce il nome, un aggregatore sum() calcola la somma di ogni importo netto (NetAmount) per ogni articolo. La corrispondenza tra articoli e ordini è evidente, poiché anche la tabella Orders ha una colonna Id.

Per maggiore chiarezza, abbiamo impiegato tre righe per illustrare il calcolo. Possiamo, però, riscrivere lo script in modo più conciso, senza le variabili intermedie:
CashFlow = sum(Orders.NetAmount) - sum(PO.NetAmount)
Oltre la somma, Envision supporta tutti gli aggregatori tradizionali: media, min, max, mediana … Questi aggregatori offrono la possibilità di aggiungere a ogni prodotto una serie di attributi descrittivi, che si rivelano utilissimi nell'affrontare molte delle sfide del commercio. Se è possibile creare un nuovo vettore all'interno degli “articoli” sfruttando un'altra tabella e un aggregatore, è anche possibile fare l'inverso e usare un vettore della tabella degli “articoli” mentre eseguiamo un calcolo associato a un'altra tabella.

Supponiamo di voler ricalcolare l'IVA (o, in inglese, VAT) associata a ogni ordine di vendita. Per maggiore semplicità, ipotizziamo che l'IVA sia del 20% per tutti gli articoli e per tutto il periodo considerato. Dovremmo, quindi, scrivere:
VatRate = 0.2 // ipotesi
Orders.Vat = Orders.NetAmount * VatRate / (1 - VatRate)
Il vettore VatRate si espande naturalmente in un vettore allineato alla tabella Orders, perché ogni ordine è associato a un singolo articolo originale. Questa espansione diventa esplicita se scriviamo:
VatRate = 0.2 // ipotesi
Orders.VatRate = VatRate
Orders.F = Orders.VatRate / (1 - Orders.VatRate)
Orders.Vat = Orders.NetAmount * Orders.F
Nell'esempio sopra, il vettore F all'interno della tabella Orders viene introdotto semplicemente per illustrare meglio tutti i passaggi del calcolo.

Un piccolo appunto: è possibile caricare tabelle arbitrarie su Envision, anche se queste non comprendono una colonna Id. Non discuteremo, però, questi scenari avanzati in questa sede.

Particolarità delle date

La tabella articoli è un caso particolare, perché, come abbiamo visto, molte delle operazioni essenziali al commercio ruotano intorno ai prodotti. Tuttavia, queste operazioni sono anche legate a date specifiche. Ogni riga dello storico delle vendite, o dello storico degli acquisti, o di quasi tutti gli altri dati che possiamo considerare "storici", corrisponde a una data specifica. Data l'importanza dei dati storici nel commercio, dove tutte le operazioni aziendali possono essere descritte come date che indicano movimenti delle scorte o pagamenti, Envision tiene conto anche delle date.

Ogni tabella può avere una colonna Date (data) oltre alla colonna Id. Quando è presente una colonna Date, la tabella può essere indicizzata non solo in base all'identificativo del prodotto, ma anche in base alle date. L'indicizzazione per date è spesso molto pratica, perché, quando si cerca di restringere un calcolo a un periodo particolare, può essere usata per filtrare i dati storici, indipendentemente dal tipo di entrate.

Ma torniamo al calcolo dei nostri flussi di cassa. Supponiamo di voler calcolare, invece che i valori per l'intero periodo, solo i flussi di cassa dell'ultimo anno. Possiamo quindi scrivere:
end := max(date)
when date > end - 365
  CashFlow = sum(Orders.NetAmount) - sum(PO.NetAmount)
La variabile end (fine) definisce la data più recente osservabile nell'intero set di dati. Considerando che end è una data, Envision è quindi in grado di eseguire calcoli di aritmetica delle date, come mostra lo script precedente. Aggiungendo la convenzione +1 a ogni data, aggiungiamo un giorno a ogni data. Così, sottraendo 365 giorni, ci spostiamo indietro di un anno.

Lo script inizia con un filtro when (quando), che rappresenta una condizione che ogni riga all'interno di un blocco di script dovrà soddisfare. Quando si tratta di articoli, non possiamo indicizzarli per data: il filtro per data non ha nessun effetto e tutti gli articoli continuano a essere presenti nel blocco when. Sia gli ordini che gli ordini di acquisto, però, hanno una colonna Date e, di conseguenza, tutte le righe che non soddisfano la condizione del filtro when verranno filtrati dal blocco di script.

Dunque, l'aggregazione sum() all'interno del blocco when elaborerà solo le righe non filtrate, ossia quelle più recenti di un anno. Lo stesso calcolo può essere eseguito anche con le variabili intermedie, come abbiamo visto prima con l'intero storico.
end := max(date)
when date > end - 365
  CashIn = sum(Orders.NetAmount)
  CashOut = sum(PO.NetAmount)
  CashFlow = CashIn - CashOut
L'esempio qui sopra mostra probabilmente in modo più chiaro perché usiamo when all'inizio del blocco di filtro: tutte le righe all'interno del blocco, infatti, che si riconoscono per i due spazi ulteriori all'inizio delle righe 2, 3 e 4, rappresentano lo stesso filtro per data.

Lo script illustra la capacità di Envision di riallineare le tabelle “articoli” con i dati complessi di altre tabelle. Se vogliamo fare un paragone con Excel, è un po' come se si potesse trasformare gli altri fogli (come lo storico degli ordini) in colonne all'interno del foglio principale con la lista dei prodotti. Envision rende tutto ciò molto più facile.