In questo post vedremo come generare numeri casuali attraverso il linguaggio di programmazione Python. Prima di passare al codice, tuttavia, รจ necessario chiarire cosa sia un numero casuale.
Un numero casuale (o numero random) รจ un valore numerico generato attraverso un processo non predeterminato, casuale, appunto. Questa definizione introduttiva potrebbe apparire scontata ma รจ necessaria per chiarire da subito un concetto apparentemente contraddittorio: in teoria i linguaggi di programmazione possono essere utilizzati per produrre dei numeri casuali ma nella realtร ci si deve riferire ad essi parlando di numeri pseudo casuali.
Indice
Differenza tra numeri casuali e numeri pseudo casuali
Un numero pseudo casuale presenta proprietร statistiche in buona parte simili a quelle dei numeri casuali tranne quella forse piรน rilevante, lโindeterminatezza.
Ciรฒ accade perchรฉ un numero casuale generato da un linguaggio di programmazione, o piรน propriamente da unโapplicazione basata su di esso, utilizza per questo scopo un algoritmo. Un algoritmo รจ rappresentato da delle istruzioni destinate a restituire un output in seguito alla manipolazione di un input, tali istruzioni vengono definite a priori e ciรฒ esclude lโindeterminatezza. Naturalmente, piรน un algoritmo รจ complesso maggiore sarร lโapprossimazione delle proprietร dei numeri pseudo casuali a quelle dei numeri casuali veri e propri, ma in qualche misura tali valori saranno sempre prevedibili.
Detto questo i numeri (pseudo) casuali possono essere utili in diversi ambiti della programmazione, basti pensare al video gaming, per la generazione degli scenari di gioco, o al machine learning, per la produzione di condizioni e comportamenti piรน o meno imprevedibili che rappresenteranno il contesto in cui verranno sviluppati i modelli di apprendimento.
Il modulo random di Python
Il riferimento al machine learning ci porta automaticamente a parlare di quello che sta diventando uno dei linguaggi di programmazione piรน utilizzati per le tecnologie basate su di esso: Python. In Python sono disponibili diversi strumenti per la RNG (Random Number Generation), in questo approfondimento verranno trattati quelli utilizzati piรน di frequente.
Il modulo random di Python รจ stato concepito appositamente per lโimplementazione di generatori di numeri pseudo casuali. Nella sua applicazione piรน immediata esso fornisce un metodo chiamato random() che ha il compito di produrre un numero decimale (float) dal valore compreso tra 0 e 1. Lโesecuzione di unโistruzione come la seguente:
# Generazione di numeri casuali in Python
import random
numero_casuale = random.random()
print(numero_casuale)
potrebbe generare in output la sequenza โ0.6629126069331859โ, cosรฌ come โ0.20027701305376144โ o โ0.20549576436251982โ e cosรฌ via. In ogni caso il costrutto prevede lโimportazione del modulo tramite la keyword import, lโeventuale associazione della chiamata al metodo ad una variabile e la stampa a video del valore generato. Volendo ricorrere ad una sintassi essenziale sarebbe possibile ottenere il medesimo risultato tramite una stampa del risultato derivante dalla chiamata diretta al metodo:
import random
print(random.random())
Un altro caso interessante riguarda la generazione di numeri random compresi allโinterno di un intervallo. Per far questo รจ possibile utilizzare un altro metodo denominato randint() che accetta come argomenti due valori denominati start e stop. Dato un valore X come start e un valore Y come stop, lโoutput N sarร un numero intero superiore ad X e inferiore a Y. Unโistruzione come quella proposta di seguito:
# Generazione di numeri casuali con randint()
import random
numero_intero_casuale = random.randint(2,43)
print(numero_intero_casuale)
potrebbe produrre โ19โ, cosรฌ come โ31โ o โ40โ.
Per avere un maggior controllo sullโoutput Python prevede anche la possibilitร di utilizzare il metodo seed() che ha il compito di inizializzare il generatore dei numeri random. Questโultimo necessita infatti di un valore (detto appunto โseedโ) da cui partire per la generazione del numero casuale:
# Inizializzare il generatore di numeri casuali con un seed
import random
random.seed(9)
print(random.random())
# possibile output
# 0.46300735781502145
Per ottenere risultati differenti รจ necessario utilizzare valori diversi per il seed, la medesima istruzione eseguita 2 volte nella stessa espressione con il medesimo seed genererร infatti un output equivalente. Come รจ possibile notare grazie agli esempi proposti in precedenza, in Python il seed non deve essere necessariamente esplicitato e, quando assente, il generatore viene inizializzato tramite il valore corrispondente al system time corrente.
Liste e sequenze di numeri casuali
Python dispone di un tipo nativo, detto lista, con cui rappresentare delle sequenze mutabili, a lunghezza variabile, di oggetti. Nel caso dei numeri random le liste possono essere utilizzate per generare sequenze di valori prodotti casualmente, ciรฒ รจ possibile attraverso lโuso di un costrutto dโiterazione come per esempio il ciclo for:
# Generare una lista di numeri random
import random
lista_numeri_casuali = []
for x in range(0,6):
y = random.randint(1,45)
lista_numeri_casuali.append(y)
print(lista_numeri_casuali)
Nellโespressione viene creata innanzitutto una lista vuota (โlista_numeri_casuali[]โ), successivamente viene inizializzato un ciclo for che prevede 6 interazioni alla fine delle quali verrร prodotta una sequenza composta da 6 valori interi, non necessariamente univoci, delimitati da un intervallo compreso tra 1 e 45. Ad ogni interazione successiva alla prima i valori prodotti vengono concatenati a quelli precedenti. Lโoutput generato potrebbe essere quindi simile al seguente:
[31] [31, 31] [31, 31, 44] [31, 31, 44, 16] [31, 31, 44, 16, 1] [31, 31, 44, 16, 1, 27]
Un’alternativa al costrutto precedente viene data dallโimpiego del metodo sample(), appartenente anchโesso al modulo random, che ha il compito di generare immediatamente una lista:
import random
lista_numeri_casuali = random.sample(range(1, 45), 6)
print(lista_numeri_casuali)
# possibile output
# [42, 22, 15, 28, 33, 34]
In questo caso la chiamata al metodo viene effettuata passando ad esso come argomenti lโintervallo da cui estrarre casualmente i valori e il numero di valori che devono comporre la sequenza.
Numeri random con NumPy
Python offre le liste in sostituzione degli array disponibili con altri linguaggi di programmazione. Le liste possono essere manipolate come degli array ma funzionano in modo differente: mentre รจ possibile accedere direttamente ad un elemento di un array, le liste supportano unicamente lโaccesso sequenziale. In parole molto semplici, dato ad esempio un array composto da 6 elementi possiamo accedere immediatamente al terzo o al quarto componente della sequenza, mentre nel caso di una lista per accedere a quegli stessi elementi si dovrร passare obbligatoriamente dal primo.
Tali caratteristiche rendono gli array piรน performanti rispetto alle liste e per questo motivo รจ stata sviluppata la libreria NumPy che permette di utilizzarli anche in Python. Invocabile tramite la keyword from, tale libreria puรฒ essere impiegata in combinazione con il metodo random in questo modo:
# Generare numeri random con NumPy
from numpy import random
x = random.randint(8,21)
print(x)
# possibile output
# 20
Lโesempio procedente genera randomicamente un numero intero nellโintervallo compreso tra 8 e 21, volendo invece produrre un valore decimale casuale si dovrร utilizzare il metodo rand() in sostituzione di randint():
# Generare numeri decimali random con NumPy
from numpy import random
x = random.rand()
print(x)
# possibile output
# 0.8798337584569168
Nel caso in cui si voglia produrre un singolo numero decimale casuale dal valore compreso tra 0 e 1 non sarร necessario passare alcun argomento al metodo, in alternativa questโultimo accetta come parametro un intero con cui definire il numero di elementi da cui deve essere composto lโarray generato in output:
# Generare un array composto da 5 numeri decimali random con NumPy
from numpy import random
x = random.rand(5)
print(x)
# possibile output
# [0.38251211 0.66259408 0.84368404 0.18947054 0.42459943]
E’ inoltre possibile generare randomicamente un array multidimensionale passando al metodo 2 argomenti separati da una virgola: il primo rappresenterร il numero di valori contenuti in ciascun array, il secondo il numero di array che comporrร lโarray multidimensionale restituito in output:
# Generare con NumPy un array multidimensionale random
# composto da 5 array contenenti 4 valori ciascuno
from numpy import random
x = random.rand(5,4)
print(x)
L’output prodotto dal codice precedente potrebbe essere simile al seguente:
[[0.84066741 0.22630641 0.6844477 0.68623831] [0.1804765 0.46100125 0.96735634 0.96621097] [0.14255415 0.41749025 0.66848924 0.91620726] [0.11695108 0.24364053 0.47374776 0.14658333] [0.56971487 0.10945109 0.09462591 0.50644689]]
Volendo invece partire da un array definito a priori ed estrarre un valore casuale da esso รจ possibile utilizzare il metodo choice() che, appunto, restituisce in output uno qualsiasi dei valori che compongono un array:
# Estrarre un valore casuale da un array
from numpy import random
x = random.choice([4, 7, 12, 13])
print(x)
# possibile output
# 7
Anche in questo caso รจ possibile generare degli array multidimensionali ricorrendo al metodo size() che accetta come primo parametro il numero di array da produrre e come secondo la quantitร di valori per ciascun array:
# Estrazione di valori casuali in un array multidimensionale
from numpy import random
x = random.choice([4, 8, 11, 29], size = (2, 6))
print(x)
# possibile output
# [[29 29 11 4 11 11]
# [8 11 29 8 11 29]]
Chiaramente, nel caso in cui il valore del secondo argomento di size() sia maggiore del numero di valori contenuti nellโarray passato come parametro a choice() gli array risultanti presenteranno dei valori ripetuti al loro interno.

