statistics.kde_random genera valores aleatorios a partir de una distribución estimada mediante kernel density estimation (KDE). En lugar de suponer que los datos siguen una distribución normal, uniforme o exponencial, puedes partir de una muestra real y construir una aproximación suave de su densidad. Esto resulta útil en simulaciones, pruebas, generación de datos sintéticos, análisis exploratorio y prototipos estadísticos.
La función complementa a statistics.kde. Puedes estimar una densidad con la misma muestra y crear una función que produzca nuevos valores con una forma parecida. El resultado depende de la calidad de los datos, del tamaño de la muestra y, especialmente, del ancho de banda.
Cómo funciona una estimación por kernel
Una KDE coloca una pequeña curva, llamada kernel, alrededor de cada observación. La suma de esas curvas forma una densidad continua. El ancho de banda controla cuánto influye cada dato en sus vecinos. Un valor demasiado pequeño crea muchos picos y ruido. Un valor demasiado grande puede borrar asimetrías, huecos o grupos separados.
La KDE no inventa información. Suaviza lo que ya existe en la muestra. Por eso, los valores atípicos, el sesgo de selección y las zonas sin datos también afectan las muestras generadas.
Ejemplo básico
from statistics import kde, kde_random
datos = [1.2, 1.4, 1.5, 1.8, 2.0, 2.1, 2.2, 2.7, 3.0]
h = 0.25
densidad = kde(datos, h=h)
generar = kde_random(datos, h=h, seed=42)
muestras = [generar() for _ in range(10)]
print(muestras)
print(densidad(2.0))
La función devuelta por kde_random puede llamarse muchas veces. Una semilla fija hace reproducible la secuencia, algo útil en documentación, pruebas automatizadas y comparaciones controladas.
Cómo elegir el ancho de banda
El ancho de banda, normalmente llamado h, es la decisión principal del modelo. No existe un valor universal. Una estrategia práctica consiste en probar varios valores y observar cómo cambian la densidad y las estadísticas de las muestras generadas.
Imagina una muestra con dos grupos separados. Un ancho muy grande puede fusionarlos. Uno muy pequeño puede convertir cada observación en un pico aislado. Si los datos usan escalas diferentes, normaliza o estandariza antes de estimar.
from statistics import kde_random, mean, median
base = [10, 11, 11, 12, 13, 20, 21, 22]
for h in (0.3, 1.0, 3.0):
generar = kde_random(base, h=h, seed=7)
simulados = [generar() for _ in range(5000)]
print(h, mean(simulados), median(simulados), min(simulados), max(simulados))
Esta comparación ayuda a detectar un suavizado excesivo o una dispersión inesperada. También conviene revisar histogramas, cuantiles y curvas acumuladas.
Reproducibilidad con seed
En ciencia de datos, pruebas y benchmarks, repetir la misma secuencia puede ser esencial. El argumento seed evita depender de operaciones aleatorias ajenas al modelo. Usa semillas fijas en ejemplos y tests, y semillas variables cuando necesites escenarios independientes.
La reproducibilidad no implica seguridad. Este generador no sirve para contraseñas, tokens, claves o cualquier uso criptográfico. Para esos casos, utiliza secrets.
Validación de los datos
Antes de construir el generador, comprueba que la muestra no esté vacía, que todos los valores sean finitos y que las unidades sean compatibles. Un modelo basado en datos inválidos puede producir resultados visualmente plausibles, pero estadísticamente engañosos.
from math import isfinite
from statistics import kde_random
def crear_generador(valores, h, seed=None):
datos = [float(valor) for valor in valores]
if not datos:
raise ValueError("la muestra no puede estar vacía")
if h <= 0:
raise ValueError("h debe ser positivo")
if not all(isfinite(valor) for valor in datos):
raise ValueError("la muestra contiene valores no finitos")
return kde_random(datos, h=h, seed=seed)
También debes evaluar el tamaño de la muestra. Con muy pocas observaciones, la función puede ejecutarse, pero la densidad difícilmente representará una población compleja.
Generación de datos sintéticos
Una aplicación práctica es crear datos de prueba que conserven aproximadamente la forma de una muestra original sin copiar cada registro directamente. Esto es útil en prototipos y pruebas de carga, pero no garantiza privacidad. Con un ancho pequeño, algunos valores generados pueden quedar muy cerca de los originales.
generar_latencia = crear_generador(
[120, 135, 128, 160, 142, 150, 131],
h=8,
seed=123,
)
latencias_sinteticas = [round(generar_latencia(), 2) for _ in range(1000)]
Después de generar, compara media, mediana, desviación, cuantiles, colas y proporción de valores fuera de límites aceptables. No basta con revisar solo la media.
Control del dominio natural
Una KDE común puede producir valores fuera del dominio real. Las duraciones pueden ser negativas, las probabilidades superar uno y las edades quedar por debajo de cero. Puedes rechazar valores inválidos, transformar los datos o elegir otro modelo.
def muestrear_no_negativo(generar, intentos=1000):
for _ in range(intentos):
valor = generar()
if valor >= 0:
return valor
raise RuntimeError("no fue posible obtener un valor válido")
El rechazo es sencillo, pero puede ser ineficiente cuando gran parte de la densidad queda fuera del rango permitido. Para proporciones, una transformación logística puede ser mejor.
Pruebas automatizadas
Las pruebas estadísticas no deberían depender únicamente de una secuencia exacta, salvo que la semilla y la implementación estén controladas. Es preferible verificar propiedades: cantidad de resultados, valores finitos, límites razonables, media aproximada y comportamiento estable.
def test_muestras_kde():
generar = crear_generador([1, 2, 3, 4, 5], h=0.5, seed=10)
valores = [generar() for _ in range(2000)]
assert len(valores) == 2000
assert all(isfinite(valor) for valor in valores)
assert 2.5 < sum(valores) / len(valores) < 3.5
Evita tolerancias excesivamente estrechas. Un cambio interno puede modificar la secuencia sin volver incorrecta la distribución.
Rendimiento y producción
Para cientos o algunos miles de datos, la solución de la biblioteca estándar suele ser práctica. En volúmenes grandes o generación masiva, mide el rendimiento. Construir el modelo y extraer muestras puede ser más costoso que usar una distribución paramétrica simple.
En producción, registra la versión de Python, el ancho de banda, el tamaño de la muestra, la política de semillas, el preprocesamiento y la versión del conjunto de datos cuando necesites trazabilidad. Crea el generador una vez y reutilízalo.
Errores frecuentes
Un error común es elegir el ancho de banda solo porque la primera gráfica se ve suave. Otro es usar KDE para ocultar problemas de calidad de datos. También es incorrecto considerar anónimos los datos sintéticos por defecto. Además, esta API es univariante y no conserva dependencias entre varias variables.
Documenta por qué el ancho elegido es razonable, valida los resultados según las reglas del dominio y compara varios diagnósticos. Si la muestra es multimodal, verifica que los modos sigan visibles después del suavizado.
Cuándo usarla
Usa statistics.kde_random cuando tengas datos numéricos unidimensionales, quieras una forma no paramétrica y prefieras una solución de la biblioteca estándar. Evítala cuando existan límites rígidos, haya muy pocos datos, debas preservar correlaciones entre variables o necesites garantías formales de privacidad.
Para ampliar fundamentos, consulta en Academify los artículos sobre colas de prioridad con heapq, graphlib, archivos ZIP seguros y comunicación entre threads con queue. Como fuentes externas, revisa la documentación oficial de statistics y la documentación oficial de random.
Conclusión
statistics.kde_random ofrece una forma directa de muestrear una densidad aprendida desde observaciones. La API es compacta, pero su uso responsable exige decisiones explícitas sobre ancho de banda, calidad de datos, dominio, reproducibilidad, validación y privacidad. Con esos controles, se convierte en una herramienta valiosa para simulaciones, pruebas y análisis estadístico sin dependencias externas.







