Ra

Random σε Python

{one: "1 άσκηση", other: "%{count} ασκήσεις"}

Σχετικά με την έννοια Random

Πολλά προγράμματα χρειάζονται (φαινομενικά) τυχαίες τιμές για να προσομοιώσουν καταστάσεις του πραγματικού κόσμου.

Συνηθισμένα, οικεία παραδείγματα περιλαμβάνουν:

  • Τη ρίψη ενός νομίσματος: μια τυχαία τιμή από το ('Heads', 'Tails').
  • Τη ρίψη ενός ζαριού: έναν τυχαίο ακέραιο από το 1 έως το 6.
  • Το ανακάτεμα μιας τράπουλας: μια τυχαία σειρά από μια λίστα με κάρτες.

Η δημιουργία πραγματικά τυχαίων τιμών με έναν υπολογιστή είναι μια προκλητικά δύσκολη τεχνική πρόκληση, οπότε μπορεί να δεις αυτά τα αποτελέσματα να αναφέρονται ως "ψευδοτυχαία".

Στην πράξη, μια καλά σχεδιασμένη βιβλιοθήκη όπως η ενότητα random στην τυπική βιβλιοθήκη της Python είναι γρήγορη, ευέλικτη και δίνει αποτελέσματα που είναι υπεραρκετά καλά για τις περισσότερες εφαρμογές σε μοντελοποίηση, προσομοίωση και παιχνίδια.

Η υπόλοιπη σελίδα θα απαριθμήσει μερικές από τις πιο συνηθισμένες συναρτήσεις της ενότητας random. Σε ενθαρρύνουμε να εξερευνήσεις την πλήρη τεκμηρίωση της random, καθώς υπάρχουν πολλές περισσότερες επιλογές από όσες καλύπτουμε εδώ.

Caution

Η ενότητα random ΔΕΝ πρέπει να χρησιμοποιείται για εφαρμογές ασφάλειας ή κρυπτογραφίας.

Αντ' αυτού, η Python παρέχει την ενότητα secrets. Αυτή είναι ειδικά βελτιστοποιημένη για κρυπτογραφική ασφάλεια. Μερικά από τα παλαιότερα προβλήματα και τους λόγους για τη δημιουργία της ενότητας secrets μπορείς να τα βρεις στο PEP 506.

Εισαγωγή

Πριν μπορέσεις να χρησιμοποιήσεις τα εργαλεία της ενότητας random, πρέπει πρώτα να την εισάγεις:

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

Για να αποφύγεις να πληκτρολογείς το όνομα της ενότητας, μπορείς να εισάγεις συγκεκριμένες συναρτήσεις με το όνομά τους:

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

Δημιουργία τυχαίων ακεραίων

Η συνάρτηση randrange() έχει τρεις μορφές, για να επιλέξεις μια τυχαία τιμή από το range(start, stop, step):

  1. Η randrange(stop) δίνει έναν ακέραιο n τέτοιον ώστε 0 <= n < stop
  2. Η randrange(start, stop) δίνει έναν ακέραιο n τέτοιον ώστε start <= n < stop
  3. Η randrange(start, stop, step) δίνει έναν ακέραιο n τέτοιον ώστε start <= n < stop και το n ανήκει στην ακολουθία start, start + step, start + 2*step...

Για τη συνηθισμένη περίπτωση όπου step == 1, η συνάρτηση randint(a, b) μπορεί να είναι πιο βολική και ευανάγνωστη. Τα πιθανά αποτελέσματα της randint() περιλαμβάνουν το άνω όριο, οπότε η randint(a, b) είναι το ίδιο με τη χρήση της randrange(a, b+1):

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

Εργασία με ακολουθίες

Οι συναρτήσεις σε αυτό το τμήμα υποθέτουν ότι ξεκινάς από κάποια ακολουθία ή άλλον περιέκτη.

Αυτή θα είναι συνήθως μια list, ή, με κάποιους περιορισμούς, ένα tuple ή ένα set (ένα tuple είναι αμετάβλητο και το set δεν έχει σειρά).

choice() και choices()

Η συνάρτηση choice() επιστρέφει ένα στοιχείο που επιλέγεται τυχαία από μια δεδομένη ακολουθία. Στην απλούστερη περίπτωσή της, αυτό μπορεί να είναι η ρίψη ενός νομίσματος:

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

Θα μπορούσαμε να πετύχουμε ουσιαστικά το ίδιο πράγμα χρησιμοποιώντας τη συνάρτηση choices(), περνώντας ένα όρισμα λέξης-κλειδιού με το μήκος της λίστας:

>>> random.choices(['H', 'T'], k=5)
['T', 'H', 'T', 'H', 'H']

Στα παραπάνω παραδείγματα, υποθέσαμε ένα δίκαιο νόμισμα με ίση πιθανότητα για κορώνα ή γράμματα, αλλά μπορούν να οριστούν και βάρη. Για παράδειγμα, αν ένα σακούλι περιέχει 10 κόκκινες μπάλες και 15 πράσινες μπάλες και θέλουμε να τραβήξουμε μία τυχαία:

>>> random.choices(['red', 'green'], [10, 15])
['red']

sample()

Το παράδειγμα με τη choices() παραπάνω υποθέτει αυτό που οι στατιστικολόγοι ονομάζουν "δειγματοληψία με επανατοποθέτηση". Κάθε επιλογή δεν έχει καμία επίδραση στην πιθανότητα των μελλοντικών επιλογών και η κατανομή των δυνητικών επιλογών παραμένει ίδια από επιλογή σε επιλογή.

Στο παράδειγμα με τις κόκκινες και τις πράσινες μπάλες: μετά από κάθε επιλογή, επιστρέφουμε τη μπάλα στο σακούλι και το ανακινούμε καλά πριν από την επόμενη επιλογή. Αυτό έρχεται σε αντίθεση με μια κατάσταση όπου τραβάμε μια κόκκινη μπάλα και αυτή παραμένει έξω. Το να μην επιστρέψουμε τη μπάλα σημαίνει ότι υπάρχουν τώρα λιγότερες κόκκινες μπάλες στο σακούλι και η επόμενη επιλογή είναι τώρα λιγότερο πιθανή να δώσει κόκκινο.

Για να προσομοιώσουμε αυτή τη "δειγματοληψία χωρίς επανατοποθέτηση", η ενότητα random παρέχει τη συνάρτηση sample(). Η σύνταξη της sample() είναι παρόμοια με αυτή της choices(), με τη διαφορά ότι προσθέτει μια παράμετρο λέξης-κλειδιού counts:

>>> random.sample(['red', 'green'], counts=[10, 15], k=10)
['green', 'green', 'green', 'green', 'green', 'red', 'red', 'red', 'red', 'green']

Τα δείγματα επιστρέφονται με τη σειρά που επιλέχθηκαν.

shuffle()

Τόσο η choices() όσο και η sample() επιστρέφουν νέες λίστες όταν k > 1. Αντίθετα, η shuffle() τυχαιοποιεί τη σειρά μιας λίστας επί τόπου, και η αρχική σειρά χάνεται:

>>> my_list = [1, 2, 3, 4, 5]
>>> random.shuffle(my_list)
>>> my_list
[4, 1, 5, 2, 3]

Εργασία με κατανομές

Μέχρι τώρα, έχουμε επικεντρωθεί σε περιπτώσεις όπου όλα τα αποτελέσματα είναι εξίσου πιθανά. Για παράδειγμα, η random.randrange(100) έχει την ίδια πιθανότητα να δώσει οποιονδήποτε ακέραιο από το 0 έως το 99.

Πολλές καταστάσεις του πραγματικού κόσμου είναι πολύ λιγότερο απλές από αυτό. Ως αποτέλεσμα, οι στατιστικολόγοι έχουν δημιουργήσει μια μεγάλη ποικιλία από distributions για να περιγράψουν μαθηματικά αποτελέσματα του "πραγματικού κόσμου".

Ομοιόμορφες κατανομές

Για ακεραίους, οι randrange() και randint() χρησιμοποιούνται όταν όλες οι πιθανότητες είναι ίσες. Αυτό ονομάζεται uniform κατανομή.

Υπάρχουν ισοδύναμα κινητής υποδιαστολής για τις randrange() και randint().

random() δίνει μια τιμή float x τέτοια ώστε 0.0 <= x < 1.0.

uniform(a, b) δίνει x τέτοιο ώστε 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]

Κανονική κατανομή

Ονομάζεται επίσης "κανονική" κατανομή ή καμπύλη "σχήματος καμπάνας" και είναι ένας πολύ συνηθισμένος τρόπος να περιγράψουμε την ανακρίβεια σε μετρούμενες τιμές.

Για παράδειγμα, ας υποθέσουμε ότι το εργοστάσιο όπου δουλεύεις μόλις αγόρασε 10.000 μπουλόνια που θα έπρεπε να είναι πανομοιότυπα. Θέλεις να ρυθμίσεις το ρομπότ του εργοστασίου να τα χειριστεί, οπότε ζυγίζεις ένα δείγμα 100 από αυτά και βρίσκεις ότι έχουν μέσο βάρος (ή mean) 4,731g. Είναι εξαιρετικά απίθανο αυτό να σημαίνει ότι όλα ζυγίζουν ακριβώς 4,731g. Ίσως βρεις ότι οι τιμές κυμαίνονται από 4,627 έως 4,794g αλλά συγκεντρώνονται γύρω από τα 4,731g.

Αυτή είναι η Gaussian distribution, στην οποία οι πιθανότητες κορυφώνονται στον μέσο όρο και φθίνουν συμμετρικά και στις δύο πλευρές (εξ ου και το "σχήμα καμπάνας"). Για να την προσομοιώσουμε σε λογισμικό, χρειαζόμαστε κάποιον τρόπο να προσδιορίσουμε το πλάτος της καμπύλης (συνήθως, τα ακριβά μπουλόνια συγκεντρώνονται πιο σφιχτά γύρω από τον μέσο όρο από τα φθηνά!).

Κατά σύμβαση, αυτό γίνεται με τη standard deviation: μικρές τιμές για μια απότομη, στενή καμπύλη, μεγάλες για μια χαμηλή, πλατιά καμπύλη. Οι μαθηματικοί λατρεύουν τα ελληνικά γράμματα, οπότε χρησιμοποιούμε το μ ('mu') για τον μέσο όρο και το σ ('sigma') για την τυπική απόκλιση. Έτσι, αν διαβάσεις ότι "το 95% των τιμών βρίσκονται εντός 2σ από το μ" ή ότι "το μποζόνιο Higgs ανιχνεύθηκε με βεβαιότητα 5 σίγμα", τέτοια σχόλια σχετίζονται με την τυπική απόκλιση.

>>> 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]
Επεξεργασία μέσω GitHub Ο σύνδεσμος ανοίγει σε νέο παράθυρο ή καρτέλα