Un número cuyo valor aún no se conoce
Una variable aleatoria es una cantidad cuyo valor depende del azar: la tirada de un dado, el rendimiento de mañana, el precio de una acción al vencimiento. Una variable aleatoria discreta toma una lista de valores posibles, cada uno con una probabilidad. Los valores y las probabilidades forman su distribución. Las probabilidades nunca son negativas y suman 1. En Python son simplemente dos listas de la misma longitud, values y probs. Un dado justo es values = [1, 2, 3, 4, 5, 6] con 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)) # TrueLa esperanza: el promedio ponderado por probabilidades
La esperanza E[X] es el promedio que obtendrías tras muchas repeticiones: multiplica cada valor por su probabilidad y suma, sum(v * p). Un dado tiene E[X] = 3.5, un número que nunca puede salir, y no pasa nada: es un promedio a largo plazo, no la predicción de un resultado. La esperanza es lineal: E[a*X + b] = a*E[X] + b. La esperanza de una función E[g(X)] aplica primero g a cada valor: sum(g(v) * p). Cuidado: en general E[g(X)] no es g(E[X]). El pago de una opción max(S - K, 0) es el caso clásico.
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 sameLa varianza: ¿cuán dispersa es?
Dos inversiones pueden tener la misma rentabilidad esperada y un riesgo muy distinto. La varianza mide la dispersión alrededor de la media: Var(X) = E[(X - mu)^2], que también se calcula como E[X^2] - E[X]^2. La desviación típica es su raíz cuadrada, en las mismas unidades que X; para rendimientos es la volatilidad. Para el dado, Var = 35/12 = 2.9167. Ambas se construyen con esperanzas de funciones de X, así que una expected_of(g, values, probs) bien escrita da la media, el segundo momento y todo lo demás.
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.002044Simulación y ley de los grandes números
También puedes estimar una esperanza sacando muestras. rng.choices(values, weights=probs, k=n) devuelve n extracciones, y el promedio de las extracciones se acerca a E[X] al crecer n: la ley de los grandes números. Es el corazón de la valoración Monte Carlo. Usa tu propio random.Random(seed) para que la ejecución sea repetible y no perturbe otro código. Con pocas extracciones el promedio es ruidoso; el error solo decrece como uno entre la raíz de n, así que 100 veces más extracciones dan solo 10 veces más precisión.
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). Lanza ValueError en cualquier otro caso. Recuerda también que una esperanza es un promedio a largo plazo: una estrategia con esperanza positiva puede perder dinero un día cualquiera.- Una distribución es
valuesmásprobs(sin negativos, suma 1);E[X] = sum(v * p). E[g(X)] = sum(g(v) * p), que no esg(E[X]);Var = E[X^2] - E[X]^2.- Las medias muestrales convergen a
E[X](ley de los grandes números); usa tu propiorandom.Random(seed).
A continuación: arreglos NumPy y dtypes, los arreglos rápidos y tipados sobre los que se construye el resto del curso.
Lab: qué se califica
- Promediar resultados según sus probabilidades con
expected_value25 pts - Calcular la esperanza de un pago con
expected_of25 pts - Medir la dispersión con
variance25 pts - Estimar la esperanza por simulación con
sample_mean25 pts