Contar por rango
La media y la desviación típica comprimen mil rendimientos en dos números. Un histograma conserva la forma: divide el rango de valores en intervalos y cuenta cuántas observaciones caen en cada uno. Barras altas en el centro y bajas en los extremos dan la campana conocida; una forma desequilibrada o con extremos pesados es una advertencia. np.histogram(values, bins=edges) devuelve los conteos y trabaja sobre un array entero. El intervalo i toma los valores desde edges[i] incluido hasta edges[i + 1] excluido; solo el último intervalo incluye también su borde derecho.
import numpy as np
returns = np.array([-0.021, -0.012, -0.008, -0.004, -0.002, 0.000, 0.001, 0.003, 0.004, 0.006, 0.009, 0.015, 0.032])
edges = np.array([-0.03, -0.01, 0.0, 0.01, 0.03]) # four bins: -3%..-1%, -1%..0%, 0%..1%, 1%..3%
counts, _ = np.histogram(returns, bins=edges)
print(counts.tolist(), counts.sum(), len(returns)) # [2, 3, 6, 1] 12 13 the 3.2% return is outside every bin
# bins=4 asks numpy for 4 equal-width bins between the minimum and the maximum
counts, edges4 = np.histogram(returns, bins=4)
print(counts.tolist(), edges4.round(4).tolist()) # [3, 6, 3, 1] [-0.021, -0.0078, 0.0055, 0.0188, 0.032]Frecuencia o densidad
Los conteos dependen del número de observaciones y del ancho de los intervalos, así que dos histogramas con tamaños de muestra distintos no se pueden comparar. Una densidad lo arregla: divide cada conteo por el total contado y por el ancho del intervalo, de modo que el área de las barras sume 1. Entonces una densidad se puede comparar con una curva teórica, como la campana normal, o con otra muestra. np.histogram(values, bins=edges, density=True) lo hace, igual que counts / (counts.sum() * np.diff(edges)).
counts, _ = np.histogram(returns, bins=edges)
density = counts / (counts.sum() * np.diff(edges))
print(density.round(2).tolist()) # [8.33, 25.0, 50.0, 4.17]
print((density * np.diff(edges)).sum()) # 1.0 the areas add up to 1Dibujarlo y leer las colas
ax.hist(values, bins=10) cuenta y dibuja en una llamada: una barra por intervalo (ax.patches), cuyas alturas son los conteos. Rotula siempre los ejes, porque un histograma de rendimientos no significa nada sin «Rendimiento diario» debajo. Lo que importa es la forma, y lo que duele son las colas: contar la proporción de observaciones a más de k desviaciones típicas de la media, np.mean(np.abs(x - mean) > k * std), dice con qué frecuencia ocurren los extremos. En una normal, alrededor del 4,6 % de los valores están más allá de 2 desviaciones y el 0,27 % más allá de 3. Los mercados son peores, como mostrarán los próximos temas.
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.hist(returns, bins=5)
ax.set_xlabel("Daily return")
ax.set_ylabel("Frequency")
print(len(ax.patches), [round(p.get_height()) for p in ax.patches]) # 5 [2, 4, 5, 1, 1] one bar per bin; the heights are the counts
# How often are the returns more than 1 standard deviation from the mean?
mean, std = returns.mean(), returns.std(ddof=1)
print(round(float(np.mean(np.abs(returns - mean) > 1 * std)), 3)) # 0.308 about 4 of 13 days# The number of bins changes the picture: compare a few
for bins in (2, 4, 8):
print(bins, np.histogram(returns, bins=bins)[0].tolist())
# 2 [9, 4]
# 4 [3, 6, 3, 1]
# 8 [1, 2, 2, 4, 2, 1, 0, 1]np.histogram(values, bins=edges)cuenta los valores de cada intervalo; el último intervalo incluye su borde derecho.- Una densidad divide por el total contado y el ancho del intervalo: las áreas suman 1 y las muestras se vuelven comparables.
ax.hist(values, bins=n)lo dibuja;np.mean(np.abs(x - mean) > k * std)mide las colas. Rotula los ejes y compara con los mismos límites.
A continuación: media y varianza de los rendimientos, los dos números que resumen una distribución, calculados a partir de sus definiciones.
Lab: qué se califica
- Contar los rendimientos de cada intervalo con
bin_counts25 pts - Convertir los conteos en densidad con
density25 pts - Medir las colas con
fraction_beyond25 pts - Dibujar el histograma con
plot_histogram25 pts