Sok programnak van szüksége (látszólag) véletlen értékekre valós helyzetek szimulálásához.
Gyakori, ismerős példák:
('Heads', 'Tails') halmazból.Valóban véletlen értékeket generálni számítógéppel meglepően nehéz technikai kihívás, ezért találkozhatsz úgy, hogy ezeket az eredményeket „pszeudovéletlennek” nevezik.
A gyakorlatban egy jól megtervezett könyvtár, mint a Python szabványos könyvtárában található random modul, gyors, rugalmas, és olyan eredményeket ad, amelyek bőven elég jók a legtöbb modellezési, szimulációs és játékbeli alkalmazáshoz.
A lap további részében a random néhány leggyakoribb függvényét soroljuk fel.
Bátorítunk, hogy böngészd át a teljes random dokumentációt, mert sokkal több lehetőséget kínál, mint amit itt tárgyalunk.
Mielőtt használhatnád a random modul eszközeit, először importálnod kell:
>>> import random
# Choose random integer from a range
>>> random.randrange(1000)
360
>>> random.randrange(-1, 500)
228
>>> random.randrange(-10, 11, 2)
-8
# Choose random integer between two values (inclusive)
>>> random.randint(5, 25)
22
Hogy elkerüld a modul nevének beírását, egyes függvényeket név szerint is importálhatsz:
>>> from random import choice, choices
# Using choice() to pick Heads or Tails 10 times
>>> tosses = []
... for side in range(10):
... tosses.append(choice(['H', 'T']))
>>> print(tosses)
['H', 'H', 'H', 'H', 'H', 'H', 'H', 'T', 'T', 'H']
# Using choices() to pick Heads or Tails 8 times
>>> picks = []
... picks.extend(choices(['H', 'T'], k=8))
... print(picks)
['T', 'H', 'H', 'T', 'H', 'H', 'T', 'T']
A randrange() függvénynek három formája van, amellyel véletlen értéket választhatsz a range(start, stop, step) halmazból:
randrange(stop) olyan n egész számot ad, hogy 0 <= n < stop
randrange(start, stop) olyan n egész számot ad, hogy start <= n < stop
randrange(start, stop, step) olyan n egész számot ad, hogy start <= n < stop, és n a start, start + step, start + 2*step... sorozatba esikA gyakori step == 1 esetben a randint(a, b) függvény kényelmesebb és olvashatóbb lehet.
A randint() lehetséges eredményei tartalmazzák a felső határt, így a randint(a, b) ugyanaz, mintha a randrange(a, b+1) függvényt használnád:
>>> import random
# Select one number at random from the range 0, 499
>>> random.randrange(500)
219
# Select 10 numbers at random between 0 and 9 two steps apart.
>>> numbers = []
... for integer in range(10):
... numbers.append(random.randrange(0, 10, 2))
>>> print(numbers)
[2, 8, 4, 0, 4, 2, 6, 6, 8, 8]
# roll a die
>>> random.randint(1, 6)
4
Az ebben a szakaszban szereplő függvények feltételezik, hogy valamilyen sorozatból vagy más konténerből indulsz ki.
Ez jellemzően egy list, vagy bizonyos megszorításokkal egy tuple vagy egy set (a tuple módosíthatatlan, a set pedig rendezetlen).
choice() és choices()
A choice() függvény egy véletlenszerűen kiválasztott elemet ad vissza egy adott sorozatból.
A legegyszerűbb esetben ez egy érmefeldobás lehet:
# This will pick one of the two values in the list at random 5 separate times
>>> [random.choice(['H', 'T']) for _ in range(5)]
['T', 'H', 'H', 'T', 'H']
Lényegében ugyanezt elérhetjük a choices() függvénnyel is, ha a lista hosszát egy kulcsszóargumentumként megadjuk:
>>> random.choices(['H', 'T'], k=5)
['T', 'H', 'T', 'H', 'H']
A fenti példákban szabályos érmét feltételeztünk, amelynél a fej és az írás valószínűsége egyenlő, de súlyokat is megadhatunk. Ha például egy zsákban 10 piros és 15 zöld golyó van, és szeretnénk véletlenszerűen kihúzni egyet:
>>> random.choices(['red', 'green'], [10, 15])
['red']
sample()A fenti choices() példa azt feltételezi, amit a statisztikusok „visszatevéses mintavételnek” neveznek.
Minden húzás vagy választás nincs hatással a későbbi választások valószínűségére, és a lehetséges választások eloszlása húzásról húzásra ugyanaz marad.
A piros és zöld golyós példában minden választás után visszatesszük a golyót a zsákba, és a következő húzás előtt jól megrázzuk. Ez ellentétben áll azzal a helyzettel, amikor kihúzunk egy piros golyót, és az kint marad. Ha nem tesszük vissza a golyót, most kevesebb piros golyó van a zsákban, így a következő választás kisebb valószínűséggel lesz piros.
Ennek a „visszatevés nélküli mintavételnek” a szimulálásához a random modul a sample() függvényt kínálja.
A sample() szintaxisa hasonló a choices()-hoz, azzal a különbséggel, hogy hozzáad egy counts kulcsszóparamétert:
>>> random.sample(['red', 'green'], counts=[10, 15], k=10)
['green', 'green', 'green', 'green', 'green', 'red', 'red', 'red', 'red', 'green']
A minták abban a sorrendben térnek vissza, ahogy kiválasztották őket.
shuffle()A choices() és a sample() egyaránt új listát ad vissza, ha k > 1.
Ezzel szemben a shuffle() helyben véletlenszerűsíti egy lista sorrendjét, és az eredeti sorrend elveszik:
>>> my_list = [1, 2, 3, 4, 5]
>>> random.shuffle(my_list)
>>> my_list
[4, 1, 5, 2, 3]
Eddig azokra az esetekre összpontosítottunk, amelyekben minden kimenet egyformán valószínű.
Például a random.randrange(100) ugyanolyan valószínűséggel ad bármely egész számot 0 és 99 között.
Sok valós helyzet ennél jóval bonyolultabb.
Ezért a statisztikusok az distributions széles választékát alkották meg, hogy matematikailag leírják a „valós” eredményeket.
Egész számok esetén a randrange() és a randint() függvényt használjuk, amikor minden valószínűség egyenlő.
Ezt uniform eloszlásnak nevezik.
A randrange() és a randint() függvénynek van lebegőpontos megfelelője is.
A random() olyan x float értéket ad, hogy 0.0 <= x < 1.0.
A uniform(a, b) olyan x-et ad, hogy a <= x <= b.
>>> [round(random.random(), 3) for _ in range(5)]
[0.876, 0.084, 0.483, 0.22, 0.863]
>>> [round(random.uniform(2, 5), 3) for _ in range(5)]
[2.798, 2.539, 3.779, 3.363, 4.33]
Ezt „normális” eloszlásnak vagy „harang alakú” görbének is nevezik; ez a mért értékek pontatlanságának nagyon gyakori leírási módja.
Tegyük fel például, hogy a gyár, amelyben dolgozol, éppen 10 000 darab csavart vásárolt, amelyeknek egyformáknak kellene lenniük.
Szeretnéd beállítani a gyári robotot, hogy kezelni tudja őket, ezért lemérsz egy 100 darabos mintát, és azt találod, hogy az átlagtömegük (vagyis a mean) 4,731 g.
Ez korántsem jelenti azt, hogy mindegyik pontosan 4,731 g-ot nyom.
Lehet, hogy az értékek 4,627 és 4,794 g között szórnak, de 4,731 g körül csoportosulnak.
Ez a Gaussian distribution: itt a valószínűségek az átlagnál érik el a csúcsukat, és mindkét oldalon szimmetrikusan lecsengenek (innen a „harang alakú” elnevezés).
Ahhoz, hogy ezt szoftverben szimuláljuk, kell valamilyen mód, amellyel megadjuk a görbe szélességét (jellemzően a drága csavarok szorosabban csoportosulnak az átlag körül, mint az olcsók!).
Megállapodás szerint erre a standard deviation szolgál: kis értékek éles, keskeny görbét adnak, nagyok alacsony, széles görbét.
A matematikusok imádják a görög betűket, ezért a μ („mu”) jelöli az átlagot, a σ („szigma”) pedig a szórást.
Így ha azt olvasod, hogy „az értékek 95%-a μ-től 2σ-on belül van”, vagy hogy „a Higgs-bozont 5 szigmás biztonsággal észlelték”, az ilyen megjegyzések a szórásra vonatkoznak.
>>> mu = 4.731
>>> sigma = 0.316
>>> [round(random.gauss(mu, sigma), 3) for _ in range(5)]
[4.72, 4.957, 4.64, 4.556, 4.968]