Ein Kernel-Dichteschätzer (KDE) erzeugt eine Verteilung, die eine Ortsmischung der Kernel-Verteilung ist. Um also einen Wert aus der Kernel-Dichteschätzung zu ziehen, müssen Sie lediglich (1) einen Wert aus der Kernel-Dichte ziehen und dann (2) Wählen Sie einen der Datenpunkte unabhängig voneinander nach dem Zufallsprinzip aus und addieren Sie seinen Wert zum Ergebnis von (1).
Hier ist das Ergebnis dieser Prozedur, die auf einen Datensatz wie den in der Frage angewendeten angewendet wird.
Das Histogramm links zeigt die Probe. Als Referenz zeigt die schwarze Kurve die Dichte, aus der die Probe gezogen wurde. Die rote Kurve zeigt die KDE der Probe (unter Verwendung einer schmalen Bandbreite). (Es ist kein Problem oder sogar unerwartet, dass die roten Peaks kürzer als die schwarzen Peaks sind: Der KDE verteilt die Dinge, sodass die Peaks zum Ausgleich niedriger werden.)
Das Histogramm rechts zeigt eine Probe (gleicher Größe) aus dem KDE. Die schwarzen und roten Kurven sind die gleichen wie zuvor.
Offensichtlich funktioniert das Verfahren zur Probenahme aus der Dichte. Es ist auch extrem schnell: Die folgende R
Implementierung generiert Millionen von Werten pro Sekunde aus jedem KDE. Ich habe es stark kommentiert, um die Portierung auf Python oder andere Sprachen zu unterstützen. Der Abtastalgorithmus selbst ist in der Funktion rdens
mit den Linien implementiert
rkernel <- function(n) rnorm(n, sd=width)
sample(x, n, replace=TRUE) + rkernel(n)
rkernel
zieht n
IId Proben aus der Kernel - Funktion während sample
ziehen n
Proben mit Ersatz aus den Daten x
. Der Operator "+" fügt die beiden Arrays von Samples Komponente für Komponente hinzu.
Für diejenigen, die eine formelle Demonstration der Korrektheit wünschen, biete ich sie hier an. Es sei die Kernelverteilung mit CDF und die Daten seien . Nach der Definition einer Kernelschätzung ist die CDF der KDEF K x = ( x 1 , x 2 , … , x n )KFKx=(x1,x2,…,xn)
Fx^;K(x)=1n∑i=1nFK(x−xi).
Das vorhergehende Rezept besagt, dass aus der empirischen Verteilung der Daten gezogen werden soll (dh es wird der Wert mit einer Wahrscheinlichkeit von für jedes ), unabhängig eine Zufallsvariable aus der Kernverteilung gezogen und summiert werden soll. Ich schulde Ihnen einen Beweis dafür, dass die Verteilungsfunktion von die des KDE ist. Beginnen wir mit der Definition und sehen, wohin sie führt. Sei eine beliebige reelle Zahl. Konditionierung auf gibtx i 1 / n i Y X + Y x X.Xxi1/niYX+YxX
FX+Y(x)=Pr(X+Y≤x)=∑i=1nPr(X+Y≤x∣X=xi)Pr(X=xi)=∑i=1nPr(xi+Y≤x)1n=1n∑i=1nPr(Y≤x−xi)=1n∑i=1nFK(x−xi)=Fx^;K(x),
wie behauptet.
#
# 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))