Vé

Véletlen ebben a kurzusban: Python

{one: "1 feladat", other: "%{count} feladat"}

A(z) Véletlen fogalomról

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:

  • Érmefeldobás: véletlen érték a ('Heads', 'Tails') halmazból.
  • Kockadobás: véletlen egész szám 1-től 6-ig.
  • Kártyapakli megkeverése: egy kártyalista véletlen sorrendje.

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.

Caution

A random modult NEM szabad biztonsági vagy kriptográfiai célra használni.

Ehelyett a Python a secrets modult kínálja. Ez kifejezetten a kriptográfiai biztonságra van optimalizálva. A secrets modul létrehozásának néhány korábbi problémáját és okát a PEP 506 írja le.

Importálás

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']

Véletlen egész számok létrehozása

A randrange() függvénynek három formája van, amellyel véletlen értéket választhatsz a range(start, stop, step) halmazból:

  1. A randrange(stop) olyan n egész számot ad, hogy 0 <= n < stop
  2. A randrange(start, stop) olyan n egész számot ad, hogy start <= n < stop
  3. A 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 esik

A 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

Munka sorozatokkal

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]

Munka eloszlásokkal

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.

Egyenletes eloszlások

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]

Gauss-eloszlás

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]
Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg