Zu

Zufall in Python

{one: "1 Übung", other: "%{count} Übungen"}

Über Zufall

Viele Programme brauchen (scheinbar) zufällige Werte, um Ereignisse aus der realen Welt zu simulieren.

Häufige, vertraute Beispiele sind:

  • Ein Münzwurf: ein zufälliger Wert aus ('Heads', 'Tails').
  • Der Wurf eines Würfels: eine zufällige Ganzzahl von 1 bis 6.
  • Das Mischen eines Kartendecks: eine zufällige Reihenfolge einer Kartenliste.

Wirklich zufällige Werte mit einem Computer zu erzeugen, ist eine überraschend schwierige technische Herausforderung, deshalb werden solche Ergebnisse manchmal als „pseudozufällig" bezeichnet.

In der Praxis ist eine gut entworfene Bibliothek wie das Modul random in der Python-Standardbibliothek schnell, flexibel und liefert Ergebnisse, die für die meisten Anwendungen in Modellierung, Simulation und Spielen vollkommen ausreichen.

Der Rest dieser Seite listet einige der gebräuchlichsten Funktionen in random auf. Wir ermutigen dich, die vollständige random-Dokumentation zu erkunden, denn es gibt viel mehr Möglichkeiten, als wir hier behandeln.

Caution

Das random-Modul sollte NICHT für Sicherheits- oder Kryptografieanwendungen verwendet werden.

Stattdessen bietet Python das Modul secrets. Es ist speziell für kryptografische Sicherheit optimiert. Einige der früheren Probleme und Gründe für die Erstellung des secrets-Moduls findest du in PEP 506.

Importieren

Bevor du die Werkzeuge im random-Modul nutzen kannst, musst du es zuerst importieren:

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

Um nicht jedes Mal den Namen des Moduls tippen zu müssen, kannst du bestimmte Funktionen direkt mit ihrem Namen importieren:

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

Zufällige Ganzzahlen erzeugen

Die Funktion randrange() hat drei Formen, um einen zufälligen Wert aus range(start, stop, step) auszuwählen:

  1. randrange(stop) liefert eine Ganzzahl n, sodass 0 <= n < stop gilt
  2. randrange(start, stop) liefert eine Ganzzahl n, sodass start <= n < stop gilt
  3. randrange(start, stop, step) liefert eine Ganzzahl n, sodass start <= n < stop gilt und n in der Folge start, start + step, start + 2*step... liegt

Für den häufigen Fall, in dem step == 1 gilt, ist die Funktion randint(a, b) oft bequemer und besser lesbar. Mögliche Ergebnisse von randint() umfassen die obere Grenze, daher entspricht randint(a, b) der Verwendung von 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

Mit Sequenzen arbeiten

Die Funktionen in diesem Abschnitt gehen davon aus, dass du von einer Sequenz oder einem anderen Container ausgehst.

Meist ist das eine list oder, mit gewissen Einschränkungen, ein tuple oder ein set (ein tuple ist unveränderlich und ein set ist ungeordnet).

choice() und choices()

Die Funktion choice() gibt einen zufällig ausgewählten Eintrag aus einer gegebenen Sequenz zurück. Im einfachsten Fall ist das ein Münzwurf:

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

Im Wesentlichen dasselbe erreichen wir mit der Funktion choices(), indem wir ein Schlüsselwortargument mit der Länge der Liste angeben:

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

In den Beispielen oben sind wir von einer fairen Münze mit gleicher Wahrscheinlichkeit für Kopf oder Zahl ausgegangen, aber es lassen sich auch Gewichtungen angeben. Wenn eine Tüte zum Beispiel 10 rote und 15 grüne Kugeln enthält und wir eine davon zufällig herausziehen möchten:

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

sample()

Das obige Beispiel mit choices() geht von dem aus, was Statistiker „Ziehen mit Zurücklegen" nennen. Jede Auswahl hat keinen Einfluss auf die Wahrscheinlichkeit zukünftiger Auswahlen, und die Verteilung der möglichen Auswahlen bleibt von Auswahl zu Auswahl gleich.

Im Beispiel mit den roten und grünen Kugeln: Nach jeder Auswahl legen wir die Kugel zurück in die Tüte und schütteln gut durch, bevor wir die nächste ziehen. Das steht im Gegensatz zu einer Situation, in der wir eine rote Kugel herausnehmen und sie draußen bleibt. Legen wir die Kugel nicht zurück, sind jetzt weniger rote Kugeln in der Tüte, und die nächste Auswahl ist nun weniger wahrscheinlich rot.

Um dieses „Ziehen ohne Zurücklegen" zu simulieren, bietet das random-Modul die Funktion sample(). Die Syntax von sample() ähnelt der von choices(), außer dass sie einen counts-Schlüsselwortparameter hinzufügt:

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

Die Stichproben werden in der Reihenfolge zurückgegeben, in der sie ausgewählt wurden.

shuffle()

Sowohl choices() als auch sample() geben neue Listen zurück, wenn k > 1 gilt. Im Gegensatz dazu randomisiert shuffle() die Reihenfolge einer Liste an Ort und Stelle, und die ursprüngliche Reihenfolge geht verloren:

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

Mit Verteilungen arbeiten

Bisher haben wir uns auf Fälle konzentriert, in denen alle Ergebnisse gleich wahrscheinlich sind. Zum Beispiel liefert random.randrange(100) mit gleicher Wahrscheinlichkeit jede Ganzzahl von 0 bis 99.

Viele Situationen aus der realen Welt sind weit weniger einfach. Deshalb haben Statistiker eine große Vielfalt an distributions entwickelt, um Ergebnisse aus der „realen Welt" mathematisch zu beschreiben.

Gleichverteilungen

Für Ganzzahlen werden randrange() und randint() verwendet, wenn alle Wahrscheinlichkeiten gleich sind. Das nennt man eine uniform Verteilung.

Für Gleitkommazahlen gibt es Entsprechungen zu randrange() und randint().

random() liefert einen float-Wert x, sodass 0.0 <= x < 1.0 gilt.

uniform(a, b) liefert x, sodass a <= x <= b gilt.

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

Gauß-Verteilung

Sie wird auch „Normalverteilung" oder „Glockenkurve" genannt und ist eine sehr verbreitete Art, Ungenauigkeiten bei gemessenen Werten zu beschreiben.

Angenommen, die Fabrik, in der du arbeitest, hat gerade 10.000 Schrauben gekauft, die eigentlich identisch sein sollten. Du möchtest den Fabrikroboter so einrichten, dass er sie handhabt, also wiegst du eine Stichprobe von 100 Stück und stellst fest, dass sie ein durchschnittliches (oder mean) Gewicht von 4,731 g haben. Es ist äußerst unwahrscheinlich, dass das bedeutet, dass sie alle genau 4,731 g wiegen. Vielleicht stellst du fest, dass die Werte von 4,627 bis 4,794 g reichen, sich aber um 4,731 g häufen.

Das ist die Gaussian distribution, bei der die Wahrscheinlichkeiten am Mittelwert am höchsten sind und zu beiden Seiten symmetrisch abfallen (daher „glockenförmig"). Um das in Software zu simulieren, brauchen wir eine Möglichkeit, die Breite der Kurve anzugeben (typischerweise häufen sich teure Schrauben enger um den Mittelwert als billige!).

Üblicherweise geschieht das mit der standard deviation: kleine Werte für eine scharfe, schmale Kurve, große für eine flache, breite Kurve. Mathematiker lieben griechische Buchstaben, deshalb verwenden wir μ („mu") für den Mittelwert und σ („sigma") für die Standardabweichung. Wenn du also liest, dass „95 % der Werte innerhalb von 2σ um μ liegen" oder dass „das Higgs-Boson mit 5-Sigma-Konfidenz nachgewiesen wurde", beziehen sich solche Aussagen auf die Standardabweichung.

>>> 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]
Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab