13 votos

¿Cómo puedo dibujar un valor al azar de una estimación de densidad de kernel?

Tengo algunas observaciones, y quiero imitar el muestreo basado en estas observaciones. Aquí considero un no-modelo paramétrico, específicamente, yo uso el kernel smoothing para la estimación de un CDF a partir de las observaciones limitadas.A continuación, dibuje valores al azar de entre los obtenidos CDF.La siguiente es mi código,(la idea es que al azar una probabilidad acumulativa utilizando distribución uniforme, y tomar el inverso de la CDF con respecto al valor de probabilidad)

x = [randn(100, 1); rand(100, 1)+4; rand(100, 1)+8];
[f, xi] = ksdensity(x, 'Function', 'cdf', 'NUmPoints', 300);
cdf = [xi', f'];
nbsamp = 100;
rndval = zeros(nbsamp, 1);
for i = 1:nbsamp
    p = rand;
   [~, idx] = sort(abs(cdf(:, 2) - p));
   rndval(i, 1) = cdf(idx(1), 1);
end
figure(1);
hist(x, 40)
figure(2);
hist(rndval, 40)

Como se muestra en el código, he utilizado una síntesis de ejemplo para probar mi procedimiento, pero el resultado no es satisfactorio, como se ilustra por las dos figuras de abajo (la primera es para la simulación de las observaciones, y la segunda figura muestra el histograma extraídas de estima CDF):

Figure 1 Figure 2

Hay alguien que sabe dónde está el problema? Gracias de antemano.

19voto

jldugger Puntos 7490

Un estimador de densidad de kernel (KDE), que produce una distribución que es una ubicación de la mezcla de la distribución del núcleo, por lo que para dibujar un valor de la estimación de densidad de kernel todo lo que necesitas hacer es (1) la elaboración de un valor de la densidad de kernel y luego (2) de forma independiente seleccione uno de los puntos de datos al azar y añadir su valor para el resultado de (1).

Aquí está el resultado de este procedimiento se aplica a un conjunto de datos como el de la pregunta.

Figure

El histograma de la izquierda representa la muestra. Para su referencia, la curva negra parcelas de la densidad a partir de la cual la muestra fue tomada. La curva roja representa los KDE de la muestra (con un ancho de banda estrecho). (No es un problema, o incluso inesperadas, que los picos rojos son más cortos que los picos de negro: el KDE diferenciales de las cosas, de modo que los picos recibirá inferior para compensar.)

El histograma de la derecha muestra un ejemplo (del mismo tamaño) de KDE. El negro y el rojo curvas son las mismas que antes.

Evidentemente, el procedimiento utilizado para la muestra de la densidad de las obras. También es extremadamente rápido: el R de ejecución a continuación genera millones de valores por segundo desde cualquier KDE. Me han comentado mucho para ayudar en la migración a Python u otros idiomas. El algoritmo de muestreo mismo es implementado en la función rdens con las líneas

rkernel <- function(n) rnorm(n, sd=width) 
sample(x, n, replace=TRUE) + rkernel(n)  

rkernel dibuja n iid muestras de que el kernel funcione mientras sample dibuja n de muestras con reemplazo a partir de los datos x. El operador"+", agrega las dos matrices de muestras componente por componente.


Para aquellos que quieran una demostración formal de la corrección, me ofrezco aquí. Deje $K$ representan el núcleo de distribución con CDF $F_K$ y dejar que los datos se $\mathbf{x}=(x_1, x_2, \ldots, x_n)$. Por la definición de un núcleo de estimación, la CDF de KDE es

$$F_{\mathbf{\hat{x}};\, K}(x) = \frac{1}{n}\sum_{i=1}^n F_K(x-x_i).$$

The preceding recipe says to draw $X$ from the empirical distribution of the data (that is, it attains the value $x_i$ with probability $1/n$ for each $i$), independently draw a random variable $S$ from the kernel distribution, and sum them. I owe you a proof that the distribution function of $X+Y$ is that of the KDE. Let's start with the definition and see where it leads. Let $x$ be any real number. Conditioning on $X$ gives

$$\eqalign{ F_{X+Y}(x) &= \Pr(X+Y \le x) \\ &= \sum_{i=1}^n \Pr(X+Y \le x \a mediados de X=x_i) \Pr(X=x_i) \\ &= \sum_{i=1}^n \Pr(x_i + Y \le x) \frac{1}{n} \\ &= \frac{1}{n}\sum_{i=1}^n \Pr(Y \le x-x_i) \\ &= \frac{1}{n}\sum_{i=1}^n F_K(x-x_i) \\ &= F_{\mathbf{\hat{x}};\, K}(x), }$$

como se reivindica.


#
# Define a function to sample from the density.
# This one implements only a Gaussian kernel.
#
rdens <- function(n, density=z, data=x, kernel="gaussian") {
  width <- z$bw                              # Kernel width
  rkernel <- function(n) rnorm(n, sd=width)  # Kernel sampler
  sample(x, n, replace=TRUE) + rkernel(n)    # Here's the entire algorithm
}
#
# Create data.
# `dx` is the density function, used later for plotting.
#
n <- 100
set.seed(17)
x <- c(rnorm(n), rnorm(n, 4, 1/4), rnorm(n, 8, 1/4))
dx <- function(x) (dnorm(x) + dnorm(x, 4, 1/4) + dnorm(x, 8, 1/4))/3
#
# Compute a kernel density estimate.
# It returns a kernel width in $bw as well as $x and $y vectors for plotting.
#
z <- density(x, bw=0.15, kernel="gaussian")
#
# Sample from the KDE.
#
system.time(y <- rdens(3*n, z, x)) # Millions per second
#
# Plot the sample.
#
h.density <- hist(y, breaks=60, plot=FALSE)
#
# Plot the KDE for comparison.
#
h.sample <- hist(x, breaks=h.density$breaks, plot=FALSE)
#
# Display the plots side by side.
#
histograms <- list(Sample=h.sample, Density=h.density)
y.max <- max(h.density$density) * 1.25
par(mfrow=c(1,2))
for (s in names(histograms)) {
  h <- histograms[[s]]
  plot(h, freq=FALSE, ylim=c(0, y.max), col="#f0f0f0", border="Gray",
       main=paste("Histogram of", s))
  curve(dx(x), add=TRUE, col="Black", lwd=2, n=501) # Underlying distribution
  lines(z$x, z$y, col="Red", lwd=2)                 # KDE of data

}
par(mfrow=c(1,1))

2voto

alexs77 Puntos 36

Muestra de la FCD primero invirtiéndolo. La inversa CDF se llama la función cuantil; es una asignación de [0.1] el dominio de la RV Usted muestra aleatorias uniforme RVs como percentiles y pasarlos a la función del quantile para obtener una muestra aleatoria de esa distribución.

1voto

Fred Beondo Puntos 11

Aquí, también quiero postear el siguiente código de Matlab la idea descrita por whuber, para ayudar a aquellos que están más familiarizados con Matlab que R.

x = exprnd(3, [300, 1]);
[~, ~, bw] = ksdensity(x, 'kernel', 'normal', 'NUmPoints', 800);

k = 0.25; % control the uncertainty of generated values, the larger the k the greater the uncertainty
mstd = bw*k;
rkernel = mstd*randn(300, 1);
sampleobs = randsample(x, 300, true);
simobs = sampleobs(:) + rkernel(:);

figure(1);
subplot(1,2,1);
hist(x, 50);title('Original sample');
subplot(1,2,2);
hist(simobs, 50);title('Simulated sample');
axis tight;

El resultado es el siguiente:results

Dime por favor si alguien encuentra algún problema en mi entendimiento y el código. Gracias.

0voto

Jan Puntos 1

Sin mirar demasiado en su implementación, no totalmente recibir su indexación procedimiento de extraer de la ICDF. Creo que sacar de la CDF, no es inversa. Aquí está mi aplicación:

import sys
sys.path.insert(0, './../../../Python/helpers')
import numpy as np
import scipy.stats as stats
from sklearn.neighbors import KernelDensity

def rugplot(axis,x,color='b',label='draws',shape='+',alpha=1):
    axis.plot(x,np.ones(x.shape)*0,'b'+shape,ms=20,label=label,c=color,alpha=alpha);
    #axis.set_ylim([0,max(axis.get_ylim())])

def PDF(x):
    return 0.5*(stats.norm.pdf(x,loc=6,scale=1)+ stats.norm.pdf(x,loc=18,scale=1));

def CDF(x,PDF):
    temp = np.linspace(-10,x,100)
    pdf = PDF(temp);
    return np.trapz(pdf,temp);

def iCDF(p,x,cdf):
    return np.interp(p,cdf,x);

res = 1000;
X = np.linspace(0,24,res);
P = np.linspace(0,1,res)
pdf  = np.array([PDF(x) for x in X]);#attention dont do [ for x in x] because it overrides original x value
cdf  = np.array([CDF(x,PDF) for x in X]);
icdf = [iCDF(p,X,cdf) for p in P];

#draw pdf and cdf
f,(ax1,ax2) = plt.subplots(1,2,figsize=(18,4.5));
ax1.plot(X,pdf, '.-',label = 'pdf');
ax1.plot(X,cdf, '.-',label = 'cdf');
ax1.legend();
ax1.set_title('PDF & CDF')

#draw inverse cdf
ax2.plot(cdf,X,'.-',label  = 'inverse by swapping axis');
ax2.plot(P,icdf,'.-',label = 'inverse computed');
ax2.legend();
ax2.set_title('inverse CDF');

#draw from custom distribution
N = 100;
p_uniform = np.random.uniform(size=N)
x_data  = np.array([iCDF(p,X,cdf) for p in p_uniform]);

#visualize draws
a = plt.figure(figsize=(20,8)).gca();
rugplot(a,x_data);

#histogram
h = np.histogram(x_data,bins=24);
a.hist(x_data,bins=h[1],alpha=0.5,normed=True);

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X