Sfrutta alcune semplici equazioni per generare colonne correlate nelle tabelle di test.

Immagine generata con DALL-E 3

Recentemente ho giocato con Databricks Labs Data Generator per creare set di dati completamente sintetici da zero. Come parte di questo, ho esaminato la creazione di dati di vendita su diversi negozi, dipendenti e clienti. Pertanto, volevo creare relazioni tra le colonne che stavo popolando artificialmente, ad esempio mappando dipendenti e clienti in un determinato negozio.

Utilizzando le UDF PySpark e un po’ di logica, possiamo generare colonne correlate che seguono una relazione molti-a-uno. Con un po’ di magia, siamo anche in grado di estendere la logica per apportare qualche variazione a questa mappatura, come un cliente che generalmente acquista dal negozio locale ma a volte da un negozio diverso.

Nota: puoi saltare questa sezione se non è richiesta!

Per prima cosa, dobbiamo creare un DataFrame con la nostra prima colonna generata casualmente. Nel nostro caso, inizieremo con il negozio, poiché logicamente avremo “molti dipendenti per negozio” e “molti clienti che fanno acquisti ripetutamente in un negozio”.

Tenendo presente un modello di dati con schema a stella, inizieremo con la nostra tabella Sales Fact, una tabella transazionale che conterrà valori chiave per ID vendita, ID negozio, ID dipendente e ID cliente, l’importo della vendita insieme ad alcune date/ora dati per l’acquisto. Possiamo quindi compilare le specifiche relative a Negozio, Dipendente e Cliente nelle tabelle delle dimensioni più avanti nella riga.

Inizieremo in piccolo: andrà bene una tabella con 1000 vendite. Ora dobbiamo decidere come suddividere queste vendite tra negozi, dipendenti e clienti. Suggeriamo quanto segue:

  • # Negozi = 20
  • # Dipendenti = 100
  • # Clienti = 700

Possiamo anche dire che le vendite verranno registrate nel corso dell’ultimo mese:

  • Data della prima vendita = 2023–11–01
  • Data dell’ultima vendita = 2023–11–30

L’ID vendita deve essere una colonna univoca in modo da poter generare una colonna ID per questo. Ora dobbiamo distribuire le 1000 vendite tra i 20 negozi. Per semplicità supponiamo che questo sia casuale.

Utilizzando Databricks Lab Generator possiamo farlo con il seguente codice:

Ora aggiungi del codice per registrare quando sono state effettuate le vendite e il loro importo. Per semplificare le cose, arrotonderemo il timestamp della vendita all’ora più vicina.

Per calcolare l’importo della vendita, possiamo utilizzare il parametro “expr” nella nostra espressione withColumn per consentirci di generare un numero casuale, con alcune regole/limiti.

In questo caso, l’espressione è piuttosto semplice: produci un numero casuale (tra 0 e 1), aggiungi 0,1 (assicurandoti che i valori di vendita non siano 0) e moltiplica per 350.

Ora abbiamo la nostra forma base per DataFrame, quindi mettiamo tutto insieme:

Possiamo creare un rapido profilo dati per osservare la distribuzione dei valori nelle colonne:

Immagine dell’autore: profilo dati generato in Databricks

Possiamo vedere che la distribuzione StoreId è relativamente uniforme nei 20 negozi, senza valori mancanti e medie attorno al centro come ci aspetteremmo. Lo stesso vale per i timestamp e i valori di importo.

Ora possiamo aggiungere la nostra colonna Employee Id al DataFrame. Ora abbiamo finito con Databricks Lab Data Generator, quindi utilizzeremo semplicemente le operazioni PySpark per aggiungere colonne a DataFrame.

Facendo un passo indietro rispetto al codice, vogliamo modellarlo come le seguenti istruzioni:

  • Ci sono 20 negozi.
  • Ogni negozio ha più di 1 dipendente.
  • Ogni dipendente lavora in un solo negozio.

Per prima cosa dobbiamo dividere i dipendenti tra i negozi. A tale scopo è possibile utilizzare la seguente funzione Python:

Ora che abbiamo la distribuzione dei dipendenti per ciascun negozio, iniziamo ad assegnare gli ID!

L’elenco EmployeePerStore garantisce che gli ID dipendente per negozio non si sovrappongano. Possiamo usarlo per assegnare in modo casuale un ID dipendente a una vendita nella tabella con la seguente equazione:

Questa funzione attualmente funziona solo per un singolo valore: dobbiamo inserirlo in qualcosa con cui PySpark DataFrame possa funzionare (funzionalmente e rapidamente!)

Possiamo passare le UDF PySpark al file conColonna metodo, quindi riformattiamo questa logica in una funzione e impostiamola su una UDF:

Ora chiamala come una nuova colonna nel DataFrame:

Possiamo verificare rapidamente che questo sia corretto utilizzando lo strumento di visualizzazione in Databricks per visualizzare il conteggio distinto degli ID dipendente per ID negozio. Questa è la mia preferenza, ma potresti anche utilizzare il raggruppamento per logica o altri moduli di disegno, se lo desideri.

Immagine per autore: conteggio distinto di ID dipendente per negozio

Nota importante: Questa logica consente ai dipendenti di esserlo perse dai risultati. Ciò significa che è possibile che un dipendente effettui 0 vendite e quindi non venga incluso nel DataFrame. Nella sezione successiva esamineremo come garantire che tutti i clienti abbiano vendite registrate a loro carico.

La colonna dei clienti è leggermente diversa… mentre il nostro caso d’uso suggerisce che è comune per un cliente fare acquisti in un singolo negozio più volte, è del tutto possibile che un giorno arrivi in ​​un negozio diverso. Come lo modelliamo?

Abbiamo i punti di partenza con la colonna del lavoro svolto per i nostri dipendenti, quindi possiamo ripeterlo get_employees funzione e logica UDF per i clienti come di seguito:

Ancora una volta abbiamo potenzialmente perso alcuni clienti qui. Ecco alcuni approcci per risolvere questo problema:

  • Ricalcola dentro Mentre loop finché non si converge su un DataFrame che contiene tutti i clienti (inefficiente, costoso, potrebbe funzionare indefinitamente)
  • Aggiorna casualmente gli ID cliente in Mentre loop fino a quando tutti i clienti in DataFrame (richiede la logica per sovrascrivere solo gli stessi negozi, potrebbe anche funzionare indefinitamente)
  • Restituisce un elenco di tutti gli ID cliente con più di 1 record nella tabella delle vendite e sovrascrive in modo casuale finché non vengono aggiunti tutti gli ID mancanti (è necessaria anche la logica per sovrascrivere i clienti nello stesso negozio, potrebbe anche essere necessario Mentre logica del ciclo)
  • Invertire il processo e iniziare dai dipendenti. Ciò garantisce che ogni dipendente venga assegnato in modo casuale alle righe. Possiamo quindi utilizzare la mappatura e applicare l’ID del negozio.

Speriamo che sia chiaro il motivo per cui l’ultima opzione richiede il minimo sforzo di calcolo: abbiamo tutto il codice richiesto, quindi dobbiamo solo riformattare leggermente le cose.

I nostri nuovi script appaiono come segue:

Immagine dell’autore: profilo dati Databricks per il nuovo DataFrame

Ciò di cui ora abbiamo bisogno è un po’ di casualità, che dobbiamo definire. Per il nostro esempio, supponiamo che ogni cliente abbia il 90% di possibilità di fare acquisti nel solito negozio (il negozio “locale”). Se non abbiamo bisogno che tutti i clienti vengano restituiti nel set di risultati, possiamo semplicemente modificare il nostro clienti_udf come segue, e utilizzare df2:

La logica prevede l’utilizzo di scelte.casuali funzione per fornire un elenco ponderato e restituire un singolo valore.

Per calcolare l’elenco ponderato, abbiamo il peso del nostro negozio “locale” per il cliente, in questo caso il 90%, quindi dobbiamo assegnare il restante 10% agli altri negozi, in questo caso 19 negozi. La probabilità che ogni altro negozio venga selezionato sarà quindi 10/19 = 0,526%. Possiamo popolare un array con queste percentuali, che sarebbe simile al seguente:(0.526,0.526,0.526,…,90,0.526,…0.526)

Passandolo a random.choices, selezioniamo quindi casualmente un ID negozio dall’elenco con i pesi corrispondenti e lo utilizziamo come input per identificativo del cliente variabile, come prima.

Nota: L’output di random.choices restituisce un elenco (poiché puoi richiedere k risultati), quindi accedi all’elemento 0 dell’elenco per ottenere store_id come valore intero.

Se dobbiamo combinare questa logica con un DataFrame che includa tutti i clienti, possiamo invertire leggermente il processo. La logica dei pesi è ancora valida, quindi possiamo semplicemente collegarla alla selezione casuale di un negozio e restituire questo come risultato:

Immagine dell’autore: esempio del DataFrame finale in Databricks

Eccolo! Un DataFrame creato sinteticamente con mappature sia rigide che libere tra le colonne. Ora puoi procedere con i passaggi successivi per popolare tabelle correlate che potrebbero contenere informazioni più descrittive, come tabelle dimensionali di nomi di negozi, indirizzi, nomi di dipendenti, ruoli, ecc. Questo può essere fatto anche utilizzando Databricks Labs Data Generator o qualsiasi altro strumento/ processo con cui ti senti a tuo agio.

Ci sono alcuni ottimi esempi nel Databricks Labs Data Generator Deposito GitHub insieme alla documentazione, quindi dai un’occhiata a questo se sei curioso di saperne di più.

È possibile accedere a tutto il mio codice da quanto segue Deposito GitHub.

Se hai pensieri, commenti o alternative a questa demo, contattaci nei commenti. Grazie!

Fonte: towardsdatascience.com

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *