Eine Zahl, deren Wert noch nicht feststeht
Eine Zufallsvariable ist eine Größe, deren Wert vom Zufall abhängt: der Wurf eines Würfels, die Rendite von morgen, der Kurs einer Aktie bei Fälligkeit. Eine diskrete Zufallsvariable nimmt eine Liste möglicher Werte an, jeden mit einer Wahrscheinlichkeit. Werte und Wahrscheinlichkeiten bilden zusammen die Verteilung. Die Wahrscheinlichkeiten sind nie negativ und summieren sich zu 1. In Python sind das einfach zwei gleich lange Listen, values und probs. Ein fairer Würfel ist values = [1, 2, 3, 4, 5, 6] mit probs = [1/6] * 6.
import math
values = [1, 2, 3, 4, 5, 6]
probs = [1 / 6] * 6
# A valid distribution: no negatives, and the probabilities add up to 1
print(all(p >= 0 for p in probs)) # True
print(math.isclose(sum(probs), 1.0)) # True (compare floats with isclose)
# A stock tomorrow: down 5%, up 2% or up 8%
returns = [-0.05, 0.02, 0.08]
chances = [0.2, 0.5, 0.3]
print(math.isclose(sum(chances), 1.0)) # TrueDer Erwartungswert: der mit Wahrscheinlichkeiten gewichtete Mittelwert
Der Erwartungswert E[X] ist der Durchschnitt über viele Wiederholungen: Multiplizieren Sie jeden Wert mit seiner Wahrscheinlichkeit und addieren Sie, sum(v * p). Ein Würfel hat E[X] = 3.5, eine Zahl, die er nie zeigt, und das ist in Ordnung: Es ist ein Langzeitdurchschnitt, keine Vorhersage eines Ergebnisses. Der Erwartungswert ist linear: E[a*X + b] = a*E[X] + b. Der Erwartungswert einer Funktion E[g(X)] wendet zuerst g auf jeden Wert an: sum(g(v) * p). Vorsicht: Im Allgemeinen ist E[g(X)] nicht g(E[X]). Der Payoff einer Option max(S - K, 0) ist der klassische Fall.
def expected_value(values, probs):
return sum(v * p for v, p in zip(values, probs))
die = [1, 2, 3, 4, 5, 6]
fair = [1 / 6] * 6
print(round(expected_value(die, fair), 4)) # 3.5
# E[g(X)]: apply g to each value first. Call payoff with strike 100:
prices = [90, 100, 110, 120]
chances = [0.1, 0.4, 0.3, 0.2]
mean_price = expected_value(prices, chances)
print(mean_price) # 106.0
print(expected_value([max(s - 100, 0) for s in prices], chances)) # 7.0 = E[max(S - K, 0)]
print(max(mean_price - 100, 0)) # 6.0 = max(E[S] - K, 0), not the sameDie Varianz: wie breit streut sie?
Zwei Anlagen können denselben erwarteten Ertrag und sehr unterschiedliches Risiko haben. Die Varianz misst die Streuung um den Mittelwert: Var(X) = E[(X - mu)^2], auch berechenbar als E[X^2] - E[X]^2. Die Standardabweichung ist ihre Wurzel, in denselben Einheiten wie X; bei Renditen ist das die Volatilität. Beim Würfel ist Var = 35/12 = 2.9167. Beide entstehen aus Erwartungswerten von Funktionen von X; eine gut geschriebene expected_of(g, values, probs) liefert Mittelwert, zweites Moment und alles Weitere.
def expected_value(values, probs):
return sum(v * p for v, p in zip(values, probs))
def expected_of(g, values, probs):
return expected_value([g(v) for v in values], probs)
def variance(values, probs):
mean = expected_of(lambda v: v, values, probs)
return expected_of(lambda v: v * v, values, probs) - mean ** 2
die, fair = [1, 2, 3, 4, 5, 6], [1 / 6] * 6
print(round(variance(die, fair), 4)) # 2.9167
returns, chances = [-0.05, 0.02, 0.08], [0.2, 0.5, 0.3]
print(round(expected_value(returns, chances), 4)) # 0.024
print(round(variance(returns, chances), 6)) # 0.002044Simulation und das Gesetz der großen Zahlen
Einen Erwartungswert kann man auch durch Ziehen von Stichproben schätzen. rng.choices(values, weights=probs, k=n) liefert n Ziehungen, und deren Mittelwert nähert sich E[X], wenn n wächst: das Gesetz der großen Zahlen. Es ist der Kern der Monte-Carlo-Bewertung. Verwenden Sie Ihr eigenes random.Random(seed), damit der Lauf wiederholbar ist und anderen Code nicht stört. Bei wenigen Ziehungen ist der Mittelwert verrauscht; der Fehler schrumpft nur wie eins durch die Wurzel aus n, 100-mal mehr Ziehungen bringen also nur 10-mal mehr Genauigkeit.
import random
die, fair = [1, 2, 3, 4, 5, 6], [1 / 6] * 6
def sample_mean(values, probs, n, seed):
rng = random.Random(seed) # private, repeatable generator
draws = rng.choices(values, weights=probs, k=n)
return sum(draws) / n
for n in (10, 1000, 100000):
print(n, round(sample_mean(die, fair, n, 1), 4))
# 10 3.1
# 1000 3.598
# 100000 3.5017 (closing in on 3.5)
print(sample_mean(die, fair, 1000, 1) == sample_mean(die, fair, 1000, 1)) # True: same seed, same answermath.isclose(sum(probs), 1.0). Lösen Sie sonst ValueError aus. Bedenken Sie auch, dass ein Erwartungswert ein Langzeitdurchschnitt ist: Eine Strategie mit positivem Erwartungswert kann an einem einzelnen Tag trotzdem Geld verlieren.- Eine Verteilung ist
valuesplusprobs(keine negativen, Summe 1);E[X] = sum(v * p). E[g(X)] = sum(g(v) * p), nichtg(E[X]);Var = E[X^2] - E[X]^2.- Stichprobenmittel konvergieren gegen
E[X](Gesetz der großen Zahlen); nutzen Sie Ihr eigenesrandom.Random(seed).
Als Nächstes: NumPy-Arrays und dtypes, die schnellen, typisierten Arrays, auf denen der Rest des Kurses aufbaut.
Lab: Was bewertet wird
- Mit
expected_valueErgebnisse nach ihren Wahrscheinlichkeiten mitteln25 Pkt. - Mit
expected_ofden Erwartungswert eines Payoffs bilden25 Pkt. - Mit
variancedie Streuung messen25 Pkt. - Mit
sample_meanden Erwartungswert per Simulation schätzen25 Pkt.