Nota dell'editor: questo post รจ stato scritto in collaborazione con Milan van der Meer. Entrambi gli autori di questo post fanno parte del team di Real Impact Analytics, una startup belga innovativa nel big data che cattura il valore nei dati telecom "appificando i big data".
Questo tutorial ti dร un assaggio del perchรฉ potresti voler generare dataset casuali e cosa aspettarti. Ti guiderร anche attraverso alcuni primi esempi su come usare Trumania, una libreria Python per la generazione di dati.
Per maggiori informazioni, visita il GitHub di Trumania!
Perchรฉ generare dataset casuali?
Generare dataset casuali รจ utile sia per i data engineer che per i data scientist. Perchรฉ data scientist e data engineer lavorano con dati sintetici e come li ottengono?
Come data engineer, dopo aver scritto la tua nuova fantastica applicazione di data processing, pensi sia il momento di iniziare i test end-to-end e quindi ti serve qualche dato di input.
Come data scientist, puoi trarre vantaggio dalla generazione di dati perchรฉ ti permette di sperimentare vari modi di esplorare dataset, algoritmi, tecniche di visualizzazione dei dati o di validare ipotesi sul comportamento di un metodo su molti dataset diversi a tua scelta.
In entrambi i casi, l'opzione allettante รจ usare dati reali. Un piccolo problema perรฒ รจ che i dati di produzione sono tipicamente difficili da ottenere, anche parzialmente, e non sta diventando piรน facile con le nuove leggi europee su privacy e sicurezza.
Magari sei tra i fortunati e hai un bel set completo di dati di produzione sul tuo laptop. Anche allora, vorresti piรน variabilitร nel dataset per validare varie situazioni come diverse dimensioni della popolazione, differenti distribuzioni dei dati, vari problemi di qualitร dei dati come mancanti o non validi...
Per un approfondimento sul perchรฉ generare dataset casuali รจ utile, vai su "Perchรฉ i dati sintetici stanno per diventare un grande vantaggio competitivo".
Generazione di dati casuali basata su schema: servono buone relazioni!
Questa sezione prova a illustrare la generazione di dati casuali basata su schema e a mostrarne i limiti.
Esistono giร molti strumenti per generare dataset casuali. Un approccio comune tra questi strumenti รจ la generazione basata su schema che ti permette di definire un blueprint e usarlo per generare alcune entitร . Khermes e LogSynth sono due esempi di tali strumenti.
Un esempio di configurazione basata su schema potrebbe includere questo schema-persona:
{
{
"field": "Name",
"class": NameGenerator
},
{
"field": "Age",
"class": RandomInt(18, 65)
},
{
"field": "Gender",
"class": RandomPicker(["Male", "Female", "Other"])
}
}
Questo schema definisce la generazione di alcuni dati su una persona. Contiene nome, etร e genere. ร semplice, รจ veloce, ma ha dei limiti. Un limite principale รจ simulare relazioni tra entitร diverse o basate sul tempo.
Per esempio, come rendere alcuni nomi piรน probabili in base al genere? O come creare un log di azioni utente in cui certe azioni sono piรน probabili durante i weekend?
L'approccio basato su schema non rende facile esporre la tua nuova applicazione alle specificitร o difficoltร del mondo reale, come:
- Dataset sbilanciati (difficoltร con operazioni di tipo group-by);
- Schemi raggruppati nella rete di entitร . Cioรจ, scoprire gruppi sociali attraverso le interazioni degli utenti (per esempio, telefonate);
- Profili di attivitร temporale diversi. Alcune azioni sono piรน probabili in certi momenti del giorno o della settimana;
- Relazioni causali tra azioni. Cioรจ, molte azioni di acquisto in un negozio che alla fine generano un evento di "out-of-stock".
Trumania si basa su scenari per affrontare queste carenze e generare dataset piรน realistici. Man mano che lo scenario si svolge, varie popolazioni interagiscono tra loro, aggiornano le proprie proprietร ed emettono log.
Un esempio di scenario potrebbe essere persone che chiamano i loro amici. Quando una persona chiama paga a minuti, quando i minuti si esauriscono deve andare in negozio... Il dataset risultante potrebbe essere il log delle chiamate, il log delle azioni di acquisto e il livello di stock a ogni ora. Le azioni in uno scenario possono essere casuali o deterministiche.
In Trumania, i dataset generati sono tipicamente serie temporali perchรฉ risultano dall'esecuzione di uno scenario che si svolge nel tempo.
Generare dati inter-relati con Trumania (aka รจ ora del tutorial!)
Nell'esempio qui sotto, vedrai come elaborare uno scenario di base in cui varie persone si scambiano messaggi. Il dataset risultante sarร la serie temporale dei messaggi scambiati tra le persone.
La sequenza di passaggi che seguiremo รจ la seguente:
- creare un circus Trumania, il mondo all'interno del quale verrร eseguito lo scenario
- aggiungere una story "hello world" che produrrร log basilari hard-coded
- aggiungere una relationship per assegnare alcune citazioni preferite a ogni persona, che saranno usate per creare il contenuto dei messaggi
- parametrizzare i parametri temporali della story per ottenere una distribuzione dei messaggi piรน realistica durante la giornata
- aggiungere un'altra relationship per definire un social network, cosรฌ che il grafo sociale che emerge dal log dei messaggi sia piรน realistico
Creare un Trumania Circus
Scopo
Il primo passo consiste nel creare un circus, il mondo in cui esisteranno tutti gli elementi dello scenario. Creeremo anche una popolazione di base di persons. Poichรฉ molti aspetti di Trumania sono casuali, questo passaggio introdurrร anche il concetto di generators, usati per controllare molti comportamenti casuali.
Per ora non aggiungeremo alcuno scenario, quindi tutto sarร statico.
Iniziamo!
How-to
Un circus di Trumania si crea semplicemente cosรฌ:
from trumania.core import circus
example_circus = circus.Circus(name="example1",
master_seed=12345,
start=pd.Timestamp("1 Jan 2017 00:00"),
step_duration=pd.Timedelta("1h"))
In Trumania, tutti gli elementi legati al tempo sono controllati da un orologio centrale. La parte piรน importante nello snippet di codice sopra รจ step_duration=pd.Timedelta("1h"), che definisce che l'orologio verrร incrementato a passi di 1 ora.
Successivamente, aggiungi la popolazione person al circus. Una popolazione รจ essenzialmente un insieme di agenti con un id e alcuni attributi.
ร possibile specificare manualmente i valori di ogni attributo, ma nella maggior parte dei casi vorrai generarli casualmente, quindi definiamo prima alcuni generators per farlo:
from trumania.core.random_generators import SequencialGenerator, FakerGenerator, NumpyRandomGenerator
id_gen = SequencialGenerator(prefix="PERSON_")
age_gen = NumpyRandomGenerator(method="normal", loc=3, scale=5,
seed=next(example_circus.seeder))
name_gen = FakerGenerator(method="name", seed=next(example_circus.seeder))
Un generatore di Trumania รจ responsabile di fornire dati quando viene chiamato il suo metodo generate(). Nell'esempio sopra, id_gen genererร stringhe come PERSON_0001, PERSON_0002, ... age_gen campionerร ripetutamente dati da una distribuzione normale e name_gen fornirร nomi di persone casuali.
Nota che qualsiasi distribuzione statistica di numpy cosรฌ come qualsiasi provider di Faker รจ disponibile in Trumania, e Trumania puรฒ essere facilmente estesa con nuove opzioni.
Con questo in atto, puoi aggiungere una popolazione di 1000 persone con ID sequenziali e due attributi casuali di base:
person = example_circus.create_population(name="person", size=1000, ids_gen=id_gen)
person.create_attribute("NAME", init_gen=name_gen)
person.create_attribute("AGE", init_gen=age_gen)
Risultato
Puoi giร dare un'occhiata agli attributi generati di tutti i membri della popolazione person chiamando person.to_dataframe().
+-------------------+-----------------+---------+
| | NAME | age |
|-------------------+-----------------+---------|
| PERSON_0000000000 | Amy Berger | 28.588 |
| PERSON_0000000001 | Michael Curry | 28.7499 |
| PERSON_0000000002 | Robert Ramirez | 35.9242 |
| PERSON_0000000003 | Derek Gonzalez | 34.7091 |
| PERSON_0000000004 | Gregory Fischer | 25.6009 |
| PERSON_0000000005 | Erica Walker | 33.9758 |
| PERSON_0000000006 | Bradley Collins | 24.4428 |
| PERSON_0000000007 | James Rodriguez | 34.7835 |
| PERSON_0000000008 | Brandy Padilla | 34.6296 |
| PERSON_0000000009 | Mark Taylor | 38.2286 |
+-------------------+-----------------+---------+
Consiglio: se vuoi vedere l'intero script per questa popolazione utente di base, dai un'occhiata a questo snippet su Github!
Dichiarazioni Hello World: creare Stories
Scopo
Rendiamo la cosa un po' piรน interessante aggiungendo una story. Una story di Trumania รจ essenzialmente una parte di scenario che incapsula un aspetto dinamico. Una story viene eseguita ogni volta che l'orologio simulato avanza di un passo.
Ricorda che sopra hai impostato step_duration=pd.Timedelta("1h") nel circus, quindi ciรฒ implica che ogni ora logica ogni story avrร la possibilitร di essere eseguita.
Creerai una semplice story hello-world in cui tutti i membri della popolazione person sopra emetteranno regolarmente il messaggio "hello world".
How-to
Il primo aspetto principale da specificare quando crei una story รจ la popolazione che la avvia. In questo caso sarร person. Il secondo aspetto รจ definire il timer, che stabilisce quando ogni membro della popolazione attiva quell'azione. Per ora li imposti hard-coded a 1, il che implica che tutti i membri eseguiranno la story a ogni passo dell'orologio (costruirai timer piรน elaborati in un passaggio successivo):
hello_world = example_circus.create_story(
name="hello_world",
initiating_population=example_circus.populations["person"],
member_id_field="PERSON_ID",
timer_gen=ConstantDependentGenerator(value=1)
)
Finora, la story รจ vuota quindi non fa nulla: devi aggiungere alcune operations. Le operations possono essere casuali o deterministiche, possono leggere e aggiornare qualsiasi attributo di popolazione o altro stato nel circus, e persino avere effetti collaterali.
Per ora, aggiungiamo due semplici operazioni deterministiche e un logger per ottenere effettivamente dei log:
hello_world.set_operations(
example_circus.clock.ops.timestamp(named_as="TIME"),
ConstantGenerator(value="hello world").ops.generate(named_as="MESSAGE"),
FieldLogger(log_id="hello")
)
example_circus.clock.ops.timestamp genera un timestamp casuale all'interno dell'intervallo di 1 ora corrente e ConstantGenerator produce semplicemente valori costanti hard-coded.
Risultato
Eseguiamo il circus per 48 ore di tempo simulato:
example_circus.run(
duration=pd.Timedelta("48h"),
log_output_folder="example_scenario",
delete_existing_logs=True
)
Questo dovrebbe produrre il seguente dataset di base, in cui ciascuna delle 1000 persone ha detto "hello world" 48 volte in 2 giorni.
Il primo campo del dataset risultante, PERSON_ID, corrisponde a member_id_field della story. Gli altri due campi, TIME e MESSAGE, corrispondono alle due operazioni principali che hai inserito nella story.
+-------+-------------------+---------------------+-------------+
| | PERSON_ID | TIME | MESSAGE |
|-------+-------------------+---------------------+-------------|
| 0 | PERSON_0000000000 | 2017-01-01 01:14:12 | hello world |
| 1 | PERSON_0000000001 | 2017-01-01 01:23:51 | hello world |
| 2 | PERSON_0000000002 | 2017-01-01 01:37:11 | hello world |
| 3 | PERSON_0000000003 | 2017-01-01 01:33:12 | hello world |
| 4 | PERSON_0000000004 | 2017-01-01 01:08:02 | hello world |
| 5 | PERSON_0000000005 | 2017-01-01 01:13:36 | hello world |
| 6 | PERSON_0000000006 | 2017-01-01 01:35:08 | hello world |
| 7 | PERSON_0000000007 | 2017-01-01 01:24:30 | hello world |
| 8 | PERSON_0000000008 | 2017-01-01 01:01:51 | hello world |
| 9 | PERSON_0000000009 | 2017-01-01 01:41:41 | hello world |
| ... |
| 23990 | PERSON_0000000990 | 2017-01-02 23:33:28 | hello world |
| 23991 | PERSON_0000000991 | 2017-01-02 23:15:26 | hello world |
| 23992 | PERSON_0000000992 | 2017-01-02 23:45:56 | hello world |
| 23993 | PERSON_0000000993 | 2017-01-02 23:25:16 | hello world |
| 23994 | PERSON_0000000994 | 2017-01-02 23:33:55 | hello world |
| 23995 | PERSON_0000000995 | 2017-01-02 23:41:45 | hello world |
| 23996 | PERSON_0000000996 | 2017-01-02 23:39:23 | hello world |
| 23997 | PERSON_0000000997 | 2017-01-02 23:45:53 | hello world |
| 23998 | PERSON_0000000998 | 2017-01-02 23:29:25 | hello world |
| 23999 | PERSON_0000000999 | 2017-01-02 23:12:24 | hello world |
+-------+-------------------+---------------------+-------------+
Consiglio: guarda l'intero snippet su Github
Qualcuno a cui dire Hello World
Scopo
Miglioriamo un po' aggiungendo un'altra persona casuale nella conversazione. Per ora diremo che ogni persona puรฒ parlare con qualsiasi altra persona con uguale probabilitร , il che non รจ molto realistico (aggiungerai un social network in un passaggio successivo). Inoltre, arricchirai il dataset aggiungendo il nome delle persone in base al loro ID.
How-to
Diciamo che l'altra persona verrร memorizzata in un nuovo campo OTHER_PERSON. In questo caso semplicistico, vuoi solo inserire in quel campo il risultato di una selezione casuale non pesata dalla popolazione person. Puoi semplicemente usare l'operazione casuale select_one di quella popolazione:
example_circus.set_operations(
example_circus.clock.ops.timestamp(named_as="TIME"),
ConstantGenerator(value="hello world").ops.generate(named_as="MESSAGE"),
example_circus.populations["person"].ops.select_one(named_as="OTHER_PERSON"),
example_circus.populations["person"]
.ops.lookup(id_field="PERSON_ID", select={"NAME": "EMITTER_NAME"}),
example_circus.populations["person"]
.ops.lookup(id_field="OTHER_PERSON", select={"NAME": "RECEIVER_NAME"}),
FieldLogger(log_id="hello")
)
Risultato
Quando esegui di nuovo il circus, ottieni un dataset con il nuovo campo OTHER_PERSON:
+-------+-------------------+---------------------+-------------+-------------------+---------------------+--------------------+
| | PERSON_ID | TIME | MESSAGE | OTHER_PERSON | EMITTER_NAME | RECEIVER_NAME |
|-------+-------------------+---------------------+-------------+-------------------+---------------------+--------------------|
| 0 | PERSON_0000000000 | 2017-01-01 01:14:12 | hello world | PERSON_0000000852 | Ann Cruz | Sophia Black |
| 1 | PERSON_0000000001 | 2017-01-01 01:23:51 | hello world | PERSON_0000000429 | Kimberly Sanchez | Jeffrey Ryan |
| 2 | PERSON_0000000002 | 2017-01-01 01:37:11 | hello world | PERSON_0000000925 | Bethany Smith | Regina Brown |
| 3 | PERSON_0000000003 | 2017-01-01 01:33:12 | hello world | PERSON_0000000347 | Frank Middleton | Jacob Ross |
| 4 | PERSON_0000000004 | 2017-01-01 01:08:02 | hello world | PERSON_0000000211 | Cheryl Decker | Joshua Miller |
| 5 | PERSON_0000000005 | 2017-01-01 01:13:36 | hello world | PERSON_0000000779 | Thomas Rodriguez | Nicole Tanner |
| 6 | PERSON_0000000006 | 2017-01-01 01:35:08 | hello world | PERSON_0000000331 | James Peters | Melissa Rogers |
| 7 | PERSON_0000000007 | 2017-01-01 01:24:30 | hello world | PERSON_0000000234 | Allison Hansen | Taylor Smith |
| 8 | PERSON_0000000008 | 2017-01-01 01:01:51 | hello world | PERSON_0000000678 | Candice Sellers | James Smith |
| 9 | PERSON_0000000009 | 2017-01-01 01:41:41 | hello world | PERSON_0000000108 | Maria White | James Nguyen |
| ... |
| 23990 | PERSON_0000000990 | 2017-01-02 23:33:28 | hello world | PERSON_0000000689 | Natasha Brown | Bailey Ramirez DDS |
| 23991 | PERSON_0000000991 | 2017-01-02 23:15:26 | hello world | PERSON_0000000250 | Shelly Ponce | Jordan Johnson |
| 23992 | PERSON_0000000992 | 2017-01-02 23:45:56 | hello world | PERSON_0000000413 | Steven Mendez | Crystal Duffy |
| 23993 | PERSON_0000000993 | 2017-01-02 23:25:16 | hello world | PERSON_0000000670 | Morgan Rice | Jonathan Obrien |
| 23994 | PERSON_0000000994 | 2017-01-02 23:33:55 | hello world | PERSON_0000000411 | Crystal Vincent | George Mathis |
| 23995 | PERSON_0000000995 | 2017-01-02 23:41:45 | hello world | PERSON_0000000563 | Dawn Kim | Jennifer Martinez |
| 23996 | PERSON_0000000996 | 2017-01-02 23:39:23 | hello world | PERSON_0000000668 | Jimmy Franco | Dr. Mark Ruiz MD |
| 23997 | PERSON_0000000997 | 2017-01-02 23:45:53 | hello world | PERSON_0000000268 | Christian Christian | Victoria Donovan |
| 23998 | PERSON_0000000998 | 2017-01-02 23:29:25 | hello world | PERSON_0000000829 | David Hernandez | Margaret Anderson |
| 23999 | PERSON_0000000999 | 2017-01-02 23:12:24 | hello world | PERSON_0000000944 | Tamara Ramirez | Andrew Curtis |
+-------+-------------------+---------------------+-------------+-------------------+---------------------+--------------------+
Consiglio: puoi vedere l'intero codice qui
Lo dici sempre
Scopo
Miglioriamo ulteriormente generando una frase casuale nel campo MESSAGE invece di una noiosa stringa hard-coded hello world. Questo ti permetterร di illustrare un primo utilizzo base della Relationship di Trumania.
Assocerai a ogni persona 4 citazioni. Ogni volta che una persona emette un messaggio, il contenuto verrร scelto tra le 4 citazioni di quella persona. Inoltre, assocerai a ogni citazione un weight diverso che definisce quanto รจ probabile quella citazione: una citazione con peso alto verrร emessa piรน spesso dal suo proprietario rispetto a una con peso basso.
Come si comincia?
How-to
Il primo passo รจ creare un generatore di citazioni, simile agli altri generatori Faker che hai visto sopra:
quote_generator = FakerGenerator(method="sentence", nb_words=6, variable_nb_words=True,
seed=next(example_circus.seeder))
Potresti usare quel generatore cosรฌ com'รจ nella story come prima, ma rendiamo la cosa un po' piรน interessante vincolando ogni persona a usare sempre una delle sue 4 citazioni preferite. Lo fai creando una Relationship tra i membri della popolazione person e alcuni valori di frasi.
Per prima cosa, crei una relationship vuota:
quotes_rel = example_circus.populations["person"].create_relationship("quotes")
Poi, popoli questa relationship con 4 citazioni per ogni persona. Nel codice sotto person.ids รจ una Series pandas di dimensione 1000 con tutti gli id della popolazione person, e quote_generator.generate(size=person.size) fornisce un'altra Series pandas sempre di dimensione 1000, con citazioni casuali.
Questo significa che ogni passaggio del for-loop qui sotto popola 1000 relazioni nella relationship: aggiunge una citazione a ciascuno dei 1000 utenti. Le prime 1000 citazioni saranno associate a weight=1, le successive saranno rese piรน frequenti associandole a weight=2, ...
for w in range(4):
quotes_rel.add_relations(
from_ids=person.ids,
to_ids=quote_generator.generate(size=person.size),
weights=w
)
Ora puoi sostituire il ConstantGenerator nella tua story con un'operazione select_one su quella relationship. Questo si legge cosรฌ: per ogni valore attualmente nel campo PERSON_ID, cerca le relazioni in quotes che partono da quell'ID e seleziona casualmente un valore correlato. Poichรฉ nella seguente operazione non vengono sovrascritti i pesi, vengono usati i pesi di default della relationship definiti sopra in add_relations:
example_circus.set_operations(
example_circus.clock.ops.timestamp(named_as="TIME"),
example_circus.populations["person"].get_relationship("quotes")
.ops.select_one(from_field="PERSON_ID", named_as="MESSAGE"),
example_circus.populations["person"].ops.select_one(named_as="OTHER_PERSON"),
example_circus.populations["person"]
.ops.lookup(id_field="PERSON_ID", select={"NAME": "EMITTER_NAME"}),
example_circus.populations["person"]
.ops.lookup(id_field="OTHER_PERSON", select={"NAME": "RECEIVER_NAME"}),
FieldLogger(log_id="hello")
)
Risultato
Quando esegui il circus, il campo MESSAGE dovrebbe ora contenere la citazione casuale:
+-------+-------------------+---------------------+-----------------------------------------------------+-------------------+---------------------+---------------------+
| | PERSON_ID | TIME | MESSAGE | OTHER_PERSON | EMITTER_NAME | RECEIVER_NAME |
|-------+-------------------+---------------------+-----------------------------------------------------+-------------------+---------------------+---------------------|
| 0 | PERSON_0000000000 | 2017-01-01 01:14:12 | Become period risk wait now toward less. | PERSON_0000000158 | Ann Cruz | Victoria Washington |
| 1 | PERSON_0000000001 | 2017-01-01 01:23:51 | Month push down. | PERSON_0000000366 | Kimberly Sanchez | Steven Williams |
| 2 | PERSON_0000000002 | 2017-01-01 01:37:11 | Blue general carry else deep problem area. | PERSON_0000000613 | Bethany Smith | Frances Davis |
| 3 | PERSON_0000000003 | 2017-01-01 01:33:12 | Phone sister pretty suddenly allow conference. | PERSON_0000000086 | Frank Middleton | Ashley Fernandez |
| 4 | PERSON_0000000004 | 2017-01-01 01:08:02 | Each discussion several send wide process. | PERSON_0000000972 | Cheryl Decker | Latoya Flynn |
| 5 | PERSON_0000000005 | 2017-01-01 01:13:36 | Guess can issue writer. | PERSON_0000000030 | Thomas Rodriguez | Lindsay Bailey |
| 6 | PERSON_0000000006 | 2017-01-01 01:35:08 | Boy step claim camera common but our. | PERSON_0000000548 | James Peters | Thomas Ward |
| ... | 23993 | PERSON_0000000993 | 2017-01-02 23:25:16 | May course and kill from news. | PERSON_0000000202 | Morgan Rice | Patricia Williams |
| 23994 | PERSON_0000000994 | 2017-01-02 23:33:55 | Water door live hospital together safe. | PERSON_0000000268 | Crystal Vincent | Victoria Donovan |
| 23995 | PERSON_0000000995 | 2017-01-02 23:41:45 | Stage control management read although thousand. | PERSON_0000000466 | Dawn Kim | Ashley Baxter |
| 23996 | PERSON_0000000996 | 2017-01-02 23:39:23 | Their that region majority break article. | PERSON_0000000620 | Jimmy Franco | Alex Dominguez |
| 23997 | PERSON_0000000997 | 2017-01-02 23:45:53 | Lead simple audience response eye. | PERSON_0000000319 | Christian Christian | David Smith |
| 23998 | PERSON_0000000998 | 2017-01-02 23:29:25 | Vote man son yeah child. | PERSON_0000000487 | David Hernandez | Joshua Park |
| 23999 | PERSON_0000000999 | 2017-01-02 23:12:24 | Answer region wind condition someone bed cover. | PERSON_0000000237 | Tamara Ramirez | Beverly Rodriguez |
+-------+-------------------+---------------------+-----------------------------------------------------+-------------------+---------------------+---------------------+
Il punto della relationship usata per le citazioni รจ che ora i campi del dataset generato sono correlati: alcune frasi sono usate piรน frequentemente da alcuni utenti.
Consiglio: guarda l'intero snippet di codice su Github
Non รจ solo cosa fai, ma quando lo fai
Scopo
Finora, ogni membro della popolazione person produce esattamente un messaggio ogni ora del giorno. Rendiamolo un po' piรน realistico.
Trumania usa una combinazione di 2 concetti per controllare l'aspetto temporale dell'esecuzione di una story: livelli di attivitร e profili del timer. Insieme, determinano la probabilitร di attivare la story dato un utente specifico e l'ora del giorno.
How-to
Aggiornerai la story e parametrizzerai questi due aspetti.
Per prima cosa, creiamo il timer profile della story, che controlla i momenti in cui vengono attivate piรน o meno azioni. Questo profilo รจ lo stesso per tutti i membri della popolazione che attivano la story.
Trumania include alcuni profili predefiniti interessanti, come DefaultDailyTimerGenerator, che corrisponde all'uso del telefono giornaliero che abbiamo misurato su un dataset di produzione reale:

Istanziamone uno nel tuo scenario:
from trumania.components.time_patterns.profilers import DefaultDailyTimerGenerator
story_timer_gen = DefaultDailyTimerGenerator(
clock=example_circus.clock,
seed=next(example_circus.seeder))
In secondo luogo, ci sono i livelli di attivitร dei membri della popolazione per quella story, che definiscono quanto รจ attivo ciascun utente all'interno della story. Sei libero di impostare un livello diverso per ogni membro, in modo che alcuni attivino quell'azione piรน o meno spesso di altri.
Potresti specificare ogni livello manualmente se lo desideri, ma qui userai semplicemente un generatore casuale che assegnerร un livello di attivitร a ogni membro della popolazione.
Per prima cosa, definiamo tre livelli di attivitร di 3, 10 e 20 attivazioni al giorno in media:
low_activity = story_timer_gen.activity(n=3, per=pd.Timedelta("1 day"))
med_activity = story_timer_gen.activity(n=10, per=pd.Timedelta("1 day"))
high_activity = story_timer_gen.activity(n=20, per=pd.Timedelta("1 day"))
Poi, puoi creare il generatore di attivitร vero e proprio, che sarร un altro generatore Numpy, stavolta basato sul metodo choice. Quello sotto assegnerร un'attivitร bassa al 20% della popolazione, media al 70% e alta al 10%:
activity_gen = NumpyRandomGenerator(
method="choice",
a=[low_activity, med_activity, high_activity],
p=[.2, .7, .1],
seed=next(example_circus.seeder))
Ora puoi usare questo profilo di timer e il generatore di attivitร come parte della tua story:
hello_world = example_circus.create_story(
name="hello_world",
initiating_population=example_circus.populations["person"],
member_id_field="PERSON_ID",
timer_gen=story_timer_gen,
activity_gen=activity_gen
)
Risultato
Il dataset risultante ha lo stesso schema di prima:
+-------+-------------------+---------------------+---------------------------------------------------------+-------------------+---------------------+----------------------+
| | PERSON_ID | TIME | MESSAGE | OTHER_PERSON | EMITTER_NAME | RECEIVER_NAME |
|-------+-------------------+---------------------+---------------------------------------------------------+-------------------+---------------------+----------------------|
| 0 | PERSON_0000000016 | 2017-01-01 00:14:12 | Still try sex sure. | PERSON_0000000739 | Johnny Moore | Adam Barrett |
| 1 | PERSON_0000000063 | 2017-01-01 00:23:51 | Resource magazine wide. | PERSON_0000000511 | Cody Pham | Tina Simmons |
| 2 | PERSON_0000000064 | 2017-01-01 00:37:11 | Heat sure simple letter better forget. | PERSON_0000000044 | Katherine Fleming | Angela Gray |
| 3 | PERSON_0000000076 | 2017-01-01 00:33:12 | Star our conference always place ball. | PERSON_0000000959 | Benjamin Reese II | Barbara Alexander |
| 4 | PERSON_0000000088 | 2017-01-01 00:08:02 | Hot event five left become time commercial. | PERSON_0000000000 | Zachary Cook | Ann Cruz |
| ... |
| 28556 | PERSON_0000000962 | 2017-01-04 00:07:45 | Then include rock rule scientist condition. | PERSON_0000000448 | Johnny Washington | Melissa Adams |
| 28557 | PERSON_0000000980 | 2017-01-04 00:04:44 | Collection full argue interview property pattern never. | PERSON_0000000731 | James Ramirez | David Morrow |
| 28558 | PERSON_0000000983 | 2017-01-04 00:23:21 | High day prepare see. | PERSON_0000000509 | Evan Horne | Robert Sims |
| 28559 | PERSON_0000000988 | 2017-01-04 00:43:56 | Likely south school result case federal seat. | PERSON_0000000819 | Benjamin Campbell | Michelle Jackson DDS |
+-------+-------------------+---------------------+---------------------------------------------------------+-------------------+---------------------+----------------------+
Consiglio: dai un'occhiata allo snippet su Github
Analisi dei risultati
I pattern temporali che hai incluso nella configurazione del tuo scenario dovrebbero ora essere visibili nella struttura interna del dataset risultante. Puoi dimostrarlo facendo un'analisi dati di base sul resulting_dataset risultante:
- il numero di messaggi a ogni ora del giorno dovrebbe seguire la distribuzione specificata (nota quanto รจ simile alla curva del
DefaultDailyTimerGeneratorsopra):
time_profile = (
resulting_dataset[["MESSAGE", "TIME"]]
.groupby(by=example_5_df.TIME.dt.hour)["MESSAGE"]
.count()
)
time_profile.plot()

- L'istogramma del numero di messaggi per utente dovrebbe anch'esso rispettare la tua configurazione:
- hai configurato
low_activitya 3 messaggi al giorno in media,med_activitya 10 ehigh_activitya 20 ed eseguito la simulazione su 5 giorni. Questo dovrebbe produrre 3 gruppi dipersoncon circa 15, 50 e 100 messaggi totali, che corrispondono ai 3 centri dell'istogramma sotto - hai configurato le probabilitร di questi livelli di attivitร a .2, .7 e .1, e questo di nuovo corrisponde approssimativamente all'area rispettiva di ogni "gobba" dell'istogramma:
- hai configurato
usage_per_user = resulting_dataset[["MESSAGE", "PERSON_ID"]].groupby("PERSON_ID")["MESSAGE"].count()
usage_per_user.plot(kind="hist")

Il social network
Scopo
Puoi migliorare ulteriormente lo scenario collegando le persone in modo che inviino messaggi ai loro amici durante l'esecuzione della story, invece che a una persona casuale. Questo introdurrร molta struttura nel dataset risultante, poichรฉ ora il grafo sociale dovrebbe essere individuabile dal log dei messaggi.
How-to
Puoi modellare il social network ancora con una Relationship, lo stesso concetto usato sopra per le citazioni. Ricorderai che la relationship quotes aveva un peso. Quel peso definiva quale citazione fosse piรน o meno probabile, data una persona. Puoi fare lo stesso qui e usare i pesi per definire quali amici sono piรน o meno probabili da contattare rispetto ad altri.
Nota che qui stai definendo una relationship da person a person, sebbene in generale Trumania permetta di definire relazioni tra qualsiasi coppia di popolazioni.
Ci sono molti modi per generare gli archi di un grafo sociale. Uno semplice e classico รจ affidarsi all'algoritmo di Erdos-Renyi. Questo รจ particolarmente facile in Trumania poichรฉ รจ giร integrato nel framework. Devi solo iniettarlo nel tuo scenario per creare una relationship.
Qui, definirai un grafo sociale tra i membri della relationship person in cui ogni persona ha 20 amici. Nota che a quella relationship verrร automaticamente aggiunto un peso con una distribuzione di Pareto.
from trumania.components.social_networks.erdos_renyi import WithErdosRenyi
# self รจ il circus qui, vedi il codice di esempio su github per dettagli
self.add_er_social_network_relationship(
self.populations["person"],
relationship_name="friends",
average_degree=20)
Con questa relationship in atto, puoi rivedere ancora una volta la nostra story. Stavolta, OTHER_PERSON non verrร piรน scelto a caso tra la popolazione, ma sarร selezionato tra gli amici di ciascun membro person, con una probabilitร proporzionale al peso definito nel social network:
hello_world.set_operations(
self.clock.ops.timestamp(named_as="TIME"),
self.populations["person"].get_relationship("quotes")
.ops.select_one(from_field="PERSON_ID",named_as="MESSAGE"),
self.populations["person"]
.get_relationship("friends")
.ops.select_one(from_field="PERSON_ID", named_as="OTHER_PERSON"),
self.populations["person"]
.ops.lookup(id_field="PERSON_ID", select={"NAME": "EMITTER_NAME"}),
self.populations["person"]
.ops.lookup(id_field="OTHER_PERSON", select={"NAME": "RECEIVER_NAME"}),
operations.FieldLogger(log_id="hello_6")
)
Risultato
Ancora una volta, il dataset risultante ha lo stesso schema dati di prima, anche se stavolta รจ ancora piรน strutturato grazie al tuo social network di base:
+-------+-------------------+---------------------+----------------------------------------------------+-------------------+-------------------+------------------+
| | PERSON_ID | TIME | MESSAGE | OTHER_PERSON | EMITTER_NAME | RECEIVER_NAME |
|-------+-------------------+---------------------+----------------------------------------------------+-------------------+-------------------+------------------|
| 0 | PERSON_0000000004 | 2017-01-01 00:14:12 | Clearly see sure. | PERSON_0000000321 | Cheryl Decker | Ian White |
| 1 | PERSON_0000000012 | 2017-01-01 00:23:51 | Offer or interview clear structure watch capital. | PERSON_0000000697 | Kelly Green | Ashley Turner |
| 2 | PERSON_0000000018 | 2017-01-01 00:37:11 | Recently race draw thousand around ahead. | PERSON_0000000989 | Laura Stephenson | Hannah James |
| 3 | PERSON_0000000040 | 2017-01-01 00:33:12 | To protect man image power beyond. | PERSON_0000000418 | Jeffrey Miller | Scott Collins |
... |
| 28966 | PERSON_0000000985 | 2017-01-04 00:09:23 | However agreement fear door land hotel. | PERSON_0000000211 | Laura Mason | Joshua Miller |
| 28967 | PERSON_0000000995 | 2017-01-04 00:48:08 | Top heat window quite forward friend somebody. | PERSON_0000000171 | Dawn Kim | Sandra Phillips |
| 28968 | PERSON_0000000999 | 2017-01-04 00:58:46 | Answer region wind condition someone bed cover. | PERSON_0000000252 | Tamara Ramirez | Jordan Collins |
+-------+-------------------+---------------------+----------------------------------------------------+-------------------+-------------------+------------------+
Consiglio: puoi dare un'occhiata allo snippet su Github
Analisi dei risultati
Un modo molto grezzo per esplorare quel social network รจ semplicemente contare il numero di amici unici chiamati da ogni persona. Se esegui la simulazione abbastanza a lungo, questo dovrebbe fornirti un limite inferiore del numero effettivo di persone nel social network di ciascuno (poichรฉ usi pesi con distribuzione di Pareto, molte persone hanno amici che sono davvero poco probabili da chiamare, quindi serve che la simulazione sia molto lunga per osservare davvero ogni possibile persona chiamata).
Hai eseguito il nostro scenario per 15 giorni simulati e ottenuto questo, che รจ centrato molto vicino e un po' al di sotto del grado medio di 20 impostato nel grafo sociale:
social_group_size = (
resulting_dataset[["PERSON_ID", "OTHER_PERSON"]]
.groupby("PERSON_ID")
.agg(lambda friends_ids: len(friends_ids.unique()))
)
social_group_size.plot(kind="hist")

C'รจ dell'altro!
Diverse funzionalitร di Trumania non sono state descritte in questo post:
- avere diverse popolazioni in uno scenario
- avere diverse stories in uno scenario
- aggiungere dipendenze probabilistiche tra stories (es. una persona chiama un amico dopo essere stata chiamata)
- aggiornamento dello stato (es. decremento dei saldi in base alla durata della chiamata)
- pezzi di scenario riutilizzabili, come geografie, piรน profili di timer, ...
- persistenza di parti dello scenario
Conclusione
Abbiamo introdotto Trumania come libreria di generazione dati basata su scenari in Python. I dataset generati possono essere usati per un'ampia gamma di applicazioni come testing, apprendimento e benchmarking.
Abbiamo spiegato che per testare correttamente un'applicazione o un algoritmo, servono dataset che rispettino alcune proprietร statistiche attese. Abbiamo illustrato che Trumania รจ in grado di farlo in un esempio in cui abbiamo generato un "message log" di base che rispetta una distribuzione del numero di messaggi per utente, una distribuzione delle ore del giorno e una distribuzione delle chiamate su un grafo sociale.
Speriamo di aver anche dimostrato che la flessibilitร dei componenti di Trumania permette la creazione di un'ampia gamma di scenari.
Uno scenario Trumania puรฒ includere relazioni tra entitร e puรฒ essere configurato con distribuzioni casuali teoriche, distribuzioni empiriche osservate in un dataset reale o persino dati di produzione reali (es. un dataset di id di location). Lo abbiamo dimostrato riutilizzando una distribuzione statistica dei timestamp di uso del telefono osservata in un dataset reale per configurare il timer casuale del tempo della nostra story.
Con questo in mente, scatena la creativitร ! Vai al Github di Trumania e scrivi il tuo scenario ;)
Altrimenti, contatta pure Svend Vanderveken o il coautore Milan van der Meer:
- Svend Vanderveken รจ un software engineer freelance con esperienza in soluzioni di data processing, soprattutto in Kafka, Scala, SQL, Python... Seguilo tramite il suo blog svend.kelesia.com e su Twitter @sv3ndk.
- Milan van der Meer lavora attualmente come software engineer per Real Impact Analytics. Puoi sempre connetterti con lui su LinkedIn


Nota dell'editor: questo post รจ stato scritto in collaborazione con Milan van der Meer. Entrambi gli autori di questo post fanno parte del team di Real Impact Analytics, una startup belga innovativa nel big data che cattura il valore nei dati telecom "appificando i big data".
Questo tutorial ti dร un assaggio del perchรฉ potresti voler generare dataset casuali e cosa aspettarti. Ti guiderร anche attraverso alcuni primi esempi su come usare Trumania, una libreria Python per la generazione di dati.
Per maggiori informazioni, visita il GitHub di Trumania!
Perchรฉ generare dataset casuali?
Generare dataset casuali รจ utile sia per i data engineer che per i data scientist. Perchรฉ data scientist e data engineer lavorano con dati sintetici e come li ottengono?
Come data engineer, dopo aver scritto la tua nuova fantastica applicazione di data processing, pensi sia il momento di iniziare i test end-to-end e quindi ti serve qualche dato di input.
Come data scientist, puoi trarre vantaggio dalla generazione di dati perchรฉ ti permette di sperimentare vari modi di esplorare dataset, algoritmi, tecniche di visualizzazione dei dati o di validare ipotesi sul comportamento di un metodo su molti dataset diversi a tua scelta.
In entrambi i casi, l'opzione allettante รจ usare dati reali. Un piccolo problema perรฒ รจ che i dati di produzione sono tipicamente difficili da ottenere, anche parzialmente, e non sta diventando piรน facile con le nuove leggi europee su privacy e sicurezza.
Magari sei tra i fortunati e hai un bel set completo di dati di produzione sul tuo laptop. Anche allora, vorresti piรน variabilitร nel dataset per validare varie situazioni come diverse dimensioni della popolazione, differenti distribuzioni dei dati, vari problemi di qualitร dei dati come mancanti o non validi...
Per un approfondimento sul perchรฉ generare dataset casuali รจ utile, vai su "Perchรฉ i dati sintetici stanno per diventare un grande vantaggio competitivo".
Generazione di dati casuali basata su schema: servono buone relazioni!
Questa sezione prova a illustrare la generazione di dati casuali basata su schema e a mostrarne i limiti.
Esistono giร molti strumenti per generare dataset casuali. Un approccio comune tra questi strumenti รจ la generazione basata su schema che ti permette di definire un blueprint e usarlo per generare alcune entitร . Khermes e LogSynth sono due esempi di tali strumenti.
Un esempio di configurazione basata su schema potrebbe includere questo schema-persona:
Questo schema definisce la generazione di alcuni dati su una persona. Contiene nome, etร e genere. ร semplice, รจ veloce, ma ha dei limiti. Un limite principale รจ simulare relazioni tra entitร diverse o basate sul tempo.
Per esempio, come rendere alcuni nomi piรน probabili in base al genere? O come creare un log di azioni utente in cui certe azioni sono piรน probabili durante i weekend?
L'approccio basato su schema non rende facile esporre la tua nuova applicazione alle specificitร o difficoltร del mondo reale, come:
Trumania si basa su scenari per affrontare queste carenze e generare dataset piรน realistici. Man mano che lo scenario si svolge, varie popolazioni interagiscono tra loro, aggiornano le proprie proprietร ed emettono log.
Un esempio di scenario potrebbe essere persone che chiamano i loro amici. Quando una persona chiama paga a minuti, quando i minuti si esauriscono deve andare in negozio... Il dataset risultante potrebbe essere il log delle chiamate, il log delle azioni di acquisto e il livello di stock a ogni ora. Le azioni in uno scenario possono essere casuali o deterministiche.
In Trumania, i dataset generati sono tipicamente serie temporali perchรฉ risultano dall'esecuzione di uno scenario che si svolge nel tempo.
Generare dati inter-relati con Trumania (aka รจ ora del tutorial!)
Nell'esempio qui sotto, vedrai come elaborare uno scenario di base in cui varie persone si scambiano messaggi. Il dataset risultante sarร la serie temporale dei messaggi scambiati tra le persone.
La sequenza di passaggi che seguiremo รจ la seguente:
Creare un Trumania Circus
Scopo
Il primo passo consiste nel creare un circus, il mondo in cui esisteranno tutti gli elementi dello scenario. Creeremo anche una popolazione di base di
persons. Poichรฉ molti aspetti di Trumania sono casuali, questo passaggio introdurrร anche il concetto digenerators, usati per controllare molti comportamenti casuali.Per ora non aggiungeremo alcuno scenario, quindi tutto sarร statico.
Iniziamo!
How-to
Un circus di Trumania si crea semplicemente cosรฌ:
In Trumania, tutti gli elementi legati al tempo sono controllati da un orologio centrale. La parte piรน importante nello snippet di codice sopra รจ
step_duration=pd.Timedelta("1h"), che definisce che l'orologio verrร incrementato a passi di 1 ora.Successivamente, aggiungi la popolazione
personal circus. Una popolazione รจ essenzialmente un insieme di agenti con unide alcuni attributi.ร possibile specificare manualmente i valori di ogni attributo, ma nella maggior parte dei casi vorrai generarli casualmente, quindi definiamo prima alcuni
generatorsper farlo:Un generatore di Trumania รจ responsabile di fornire dati quando viene chiamato il suo metodo
generate(). Nell'esempio sopra,id_gengenererร stringhe comePERSON_0001,PERSON_0002, ...age_gencampionerร ripetutamente dati da una distribuzione normale ename_genfornirร nomi di persone casuali.Nota che qualsiasi distribuzione statistica di
numpycosรฌ come qualsiasi provider di Faker รจ disponibile in Trumania, e Trumania puรฒ essere facilmente estesa con nuove opzioni.Con questo in atto, puoi aggiungere una popolazione di 1000 persone con ID sequenziali e due attributi casuali di base:
Risultato
Puoi giร dare un'occhiata agli attributi generati di tutti i membri della popolazione
personchiamandoperson.to_dataframe().Consiglio: se vuoi vedere l'intero script per questa popolazione utente di base, dai un'occhiata a questo snippet su Github!
Dichiarazioni Hello World: creare Stories
Scopo
Rendiamo la cosa un po' piรน interessante aggiungendo una
story. Una story di Trumania รจ essenzialmente una parte di scenario che incapsula un aspetto dinamico. Una story viene eseguita ogni volta che l'orologio simulato avanza di un passo.Ricorda che sopra hai impostato
step_duration=pd.Timedelta("1h")nel circus, quindi ciรฒ implica che ogni ora logica ogni story avrร la possibilitร di essere eseguita.Creerai una semplice story hello-world in cui tutti i membri della popolazione
personsopra emetteranno regolarmente il messaggio "hello world".How-to
Il primo aspetto principale da specificare quando crei una
storyรจ la popolazione che la avvia. In questo caso sarรperson. Il secondo aspetto รจ definire iltimer, che stabilisce quando ogni membro della popolazione attiva quell'azione. Per ora li imposti hard-coded a 1, il che implica che tutti i membri eseguiranno la story a ogni passo dell'orologio (costruirai timer piรน elaborati in un passaggio successivo):Finora, la story รจ vuota quindi non fa nulla: devi aggiungere alcune operations. Le operations possono essere casuali o deterministiche, possono leggere e aggiornare qualsiasi attributo di popolazione o altro stato nel circus, e persino avere effetti collaterali.
Per ora, aggiungiamo due semplici operazioni deterministiche e un logger per ottenere effettivamente dei log:
example_circus.clock.ops.timestampgenera un timestamp casuale all'interno dell'intervallo di 1 ora corrente eConstantGeneratorproduce semplicemente valori costanti hard-coded.Risultato
Eseguiamo il circus per 48 ore di tempo simulato:
Questo dovrebbe produrre il seguente dataset di base, in cui ciascuna delle 1000 persone ha detto "hello world" 48 volte in 2 giorni.
Il primo campo del dataset risultante,
PERSON_ID, corrisponde amember_id_fielddellastory. Gli altri due campi,TIMEeMESSAGE, corrispondono alle due operazioni principali che hai inserito nella story.Consiglio: guarda l'intero snippet su Github
Qualcuno a cui dire Hello World
Scopo
Miglioriamo un po' aggiungendo un'altra persona casuale nella conversazione. Per ora diremo che ogni persona puรฒ parlare con qualsiasi altra persona con uguale probabilitร , il che non รจ molto realistico (aggiungerai un social network in un passaggio successivo). Inoltre, arricchirai il dataset aggiungendo il nome delle persone in base al loro ID.
How-to
Diciamo che l'altra persona verrร memorizzata in un nuovo campo
OTHER_PERSON. In questo caso semplicistico, vuoi solo inserire in quel campo il risultato di una selezione casuale non pesata dalla popolazioneperson. Puoi semplicemente usare l'operazione casualeselect_onedi quella popolazione:Risultato
Quando esegui di nuovo il circus, ottieni un dataset con il nuovo campo
OTHER_PERSON:Consiglio: puoi vedere l'intero codice qui
Lo dici sempre
Scopo
Miglioriamo ulteriormente generando una frase casuale nel campo
MESSAGEinvece di una noiosa stringa hard-codedhello world. Questo ti permetterร di illustrare un primo utilizzo base dellaRelationshipdi Trumania.Assocerai a ogni persona 4 citazioni. Ogni volta che una persona emette un messaggio, il contenuto verrร scelto tra le 4 citazioni di quella persona. Inoltre, assocerai a ogni citazione un
weightdiverso che definisce quanto รจ probabile quella citazione: una citazione con peso alto verrร emessa piรน spesso dal suo proprietario rispetto a una con peso basso.Come si comincia?
How-to
Il primo passo รจ creare un generatore di citazioni, simile agli altri generatori
Fakerche hai visto sopra:Potresti usare quel generatore cosรฌ com'รจ nella
storycome prima, ma rendiamo la cosa un po' piรน interessante vincolando ogni persona a usare sempre una delle sue 4 citazioni preferite. Lo fai creando unaRelationshiptra i membri della popolazionepersone alcuni valori di frasi.Per prima cosa, crei una relationship vuota:
Poi, popoli questa relationship con 4 citazioni per ogni persona. Nel codice sotto
person.idsรจ unaSeriespandas di dimensione 1000 con tutti gli id della popolazioneperson, equote_generator.generate(size=person.size)fornisce un'altraSeriespandas sempre di dimensione 1000, con citazioni casuali.Questo significa che ogni passaggio del for-loop qui sotto popola 1000 relazioni nella relationship: aggiunge una citazione a ciascuno dei 1000 utenti. Le prime 1000 citazioni saranno associate a weight=1, le successive saranno rese piรน frequenti associandole a weight=2, ...
Ora puoi sostituire il
ConstantGeneratornella tua story con un'operazioneselect_onesu quella relationship. Questo si legge cosรฌ: per ogni valore attualmente nel campoPERSON_ID, cerca le relazioni inquotesche partono da quell'ID e seleziona casualmente un valore correlato. Poichรฉ nella seguente operazione non vengono sovrascritti i pesi, vengono usati i pesi di default della relationship definiti sopra inadd_relations:Risultato
Quando esegui il circus, il campo
MESSAGEdovrebbe ora contenere la citazione casuale:Il punto della relationship usata per le citazioni รจ che ora i campi del dataset generato sono correlati: alcune frasi sono usate piรน frequentemente da alcuni utenti.
Consiglio: guarda l'intero snippet di codice su Github
Non รจ solo cosa fai, ma quando lo fai
Scopo
Finora, ogni membro della popolazione
personproduce esattamente un messaggio ogni ora del giorno. Rendiamolo un po' piรน realistico.Trumania usa una combinazione di 2 concetti per controllare l'aspetto temporale dell'esecuzione di una story: livelli di attivitร e profili del timer. Insieme, determinano la probabilitร di attivare la
storydato un utente specifico e l'ora del giorno.How-to
Aggiornerai la
storye parametrizzerai questi due aspetti.Per prima cosa, creiamo il timer profile della story, che controlla i momenti in cui vengono attivate piรน o meno azioni. Questo profilo รจ lo stesso per tutti i membri della popolazione che attivano la story.
Trumania include alcuni profili predefiniti interessanti, come
DefaultDailyTimerGenerator, che corrisponde all'uso del telefono giornaliero che abbiamo misurato su un dataset di produzione reale:Istanziamone uno nel tuo scenario:
In secondo luogo, ci sono i livelli di attivitร dei membri della popolazione per quella story, che definiscono quanto รจ attivo ciascun utente all'interno della story. Sei libero di impostare un livello diverso per ogni membro, in modo che alcuni attivino quell'azione piรน o meno spesso di altri.
Potresti specificare ogni livello manualmente se lo desideri, ma qui userai semplicemente un generatore casuale che assegnerร un livello di attivitร a ogni membro della popolazione.
Per prima cosa, definiamo tre livelli di attivitร di 3, 10 e 20 attivazioni al giorno in media:
Poi, puoi creare il generatore di attivitร vero e proprio, che sarร un altro generatore
Numpy, stavolta basato sul metodochoice. Quello sotto assegnerร un'attivitร bassa al 20% della popolazione, media al 70% e alta al 10%:Ora puoi usare questo profilo di timer e il generatore di attivitร come parte della tua story:
Risultato
Il dataset risultante ha lo stesso schema di prima:
Consiglio: dai un'occhiata allo snippet su Github
Analisi dei risultati
I pattern temporali che hai incluso nella configurazione del tuo scenario dovrebbero ora essere visibili nella struttura interna del dataset risultante. Puoi dimostrarlo facendo un'analisi dati di base sul
resulting_datasetrisultante:DefaultDailyTimerGeneratorsopra):low_activitya 3 messaggi al giorno in media,med_activitya 10 ehigh_activitya 20 ed eseguito la simulazione su 5 giorni. Questo dovrebbe produrre 3 gruppi dipersoncon circa 15, 50 e 100 messaggi totali, che corrispondono ai 3 centri dell'istogramma sottoIl social network
Scopo
Puoi migliorare ulteriormente lo scenario collegando le persone in modo che inviino messaggi ai loro amici durante l'esecuzione della story, invece che a una persona casuale. Questo introdurrร molta struttura nel dataset risultante, poichรฉ ora il grafo sociale dovrebbe essere individuabile dal log dei messaggi.
How-to
Puoi modellare il social network ancora con una
Relationship, lo stesso concetto usato sopra per le citazioni. Ricorderai che la relationshipquotesaveva un peso. Quel peso definiva quale citazione fosse piรน o meno probabile, data una persona. Puoi fare lo stesso qui e usare i pesi per definire quali amici sono piรน o meno probabili da contattare rispetto ad altri.Nota che qui stai definendo una relationship da
personaperson, sebbene in generale Trumania permetta di definire relazioni tra qualsiasi coppia di popolazioni.Ci sono molti modi per generare gli archi di un grafo sociale. Uno semplice e classico รจ affidarsi all'algoritmo di Erdos-Renyi. Questo รจ particolarmente facile in Trumania poichรฉ รจ giร integrato nel framework. Devi solo iniettarlo nel tuo scenario per creare una relationship.
Qui, definirai un grafo sociale tra i membri della relationship
personin cui ogni persona ha 20 amici. Nota che a quella relationship verrร automaticamente aggiunto un peso con una distribuzione di Pareto.Con questa relationship in atto, puoi rivedere ancora una volta la nostra story. Stavolta,
OTHER_PERSONnon verrร piรน scelto a caso tra la popolazione, ma sarร selezionato tra gli amici di ciascun membroperson, con una probabilitร proporzionale al peso definito nel social network:Risultato
Ancora una volta, il dataset risultante ha lo stesso schema dati di prima, anche se stavolta รจ ancora piรน strutturato grazie al tuo social network di base:
Consiglio: puoi dare un'occhiata allo snippet su Github
Analisi dei risultati
Un modo molto grezzo per esplorare quel social network รจ semplicemente contare il numero di amici unici chiamati da ogni persona. Se esegui la simulazione abbastanza a lungo, questo dovrebbe fornirti un limite inferiore del numero effettivo di persone nel social network di ciascuno (poichรฉ usi pesi con distribuzione di Pareto, molte persone hanno amici che sono davvero poco probabili da chiamare, quindi serve che la simulazione sia molto lunga per osservare davvero ogni possibile persona chiamata).
Hai eseguito il nostro scenario per 15 giorni simulati e ottenuto questo, che รจ centrato molto vicino e un po' al di sotto del grado medio di 20 impostato nel grafo sociale:
C'รจ dell'altro!
Diverse funzionalitร di Trumania non sono state descritte in questo post:
Conclusione
Abbiamo introdotto Trumania come libreria di generazione dati basata su scenari in Python. I dataset generati possono essere usati per un'ampia gamma di applicazioni come testing, apprendimento e benchmarking.
Abbiamo spiegato che per testare correttamente un'applicazione o un algoritmo, servono dataset che rispettino alcune proprietร statistiche attese. Abbiamo illustrato che Trumania รจ in grado di farlo in un esempio in cui abbiamo generato un "message log" di base che rispetta una distribuzione del numero di messaggi per utente, una distribuzione delle ore del giorno e una distribuzione delle chiamate su un grafo sociale.
Speriamo di aver anche dimostrato che la flessibilitร dei componenti di Trumania permette la creazione di un'ampia gamma di scenari.
Uno scenario Trumania puรฒ includere relazioni tra entitร e puรฒ essere configurato con distribuzioni casuali teoriche, distribuzioni empiriche osservate in un dataset reale o persino dati di produzione reali (es. un dataset di id di location). Lo abbiamo dimostrato riutilizzando una distribuzione statistica dei timestamp di uso del telefono osservata in un dataset reale per configurare il timer casuale del tempo della nostra story.
Con questo in mente, scatena la creativitร ! Vai al Github di Trumania e scrivi il tuo scenario ;)
Altrimenti, contatta pure Svend Vanderveken o il coautore Milan van der Meer: