Kira-kira penduga kepadatan kernel (KDE) menghasilkan distribusi yang merupakan campuran lokasi dari distribusi kernel, sehingga untuk menggambar nilai dari estimasi kepadatan kernel yang Anda butuhkan adalah (1) mengambil nilai dari kepadatan kernel dan kemudian (2) pilih salah satu titik data secara acak dan tambahkan nilainya ke hasil (1) secara independen.
Berikut adalah hasil dari prosedur ini yang diterapkan pada dataset seperti yang ada di pertanyaan.
Histogram di sebelah kiri menggambarkan sampel. Untuk referensi, kurva hitam memplot kepadatan dari mana sampel diambil. Kurva merah memplot KDE sampel (menggunakan bandwidth sempit). (Ini bukan masalah, atau bahkan tidak terduga, bahwa puncak merah lebih pendek dari puncak hitam: KDE menyebarkan berbagai hal, sehingga puncak akan menjadi lebih rendah untuk mengimbangi.)
Histogram di sebelah kanan menggambarkan sampel (dengan ukuran yang sama) dari KDE. Kurva hitam dan merah sama dengan sebelumnya.
Terbukti, prosedur yang digunakan untuk sampel dari kepadatan bekerja. Ini juga sangat cepat: R
implementasi di bawah ini menghasilkan jutaan nilai per detik dari setiap KDE. Saya telah banyak berkomentar untuk membantu dalam porting ke Python atau bahasa lain. Algoritma sampling itu sendiri diimplementasikan dalam fungsi rdens
dengan garis
rkernel <- function(n) rnorm(n, sd=width)
sample(x, n, replace=TRUE) + rkernel(n)
rkernel
mengambil n
sampel iid dari fungsi kernel sementara sample
mengambil n
sampel dengan penggantian dari data x
. Operator "+" menambahkan dua larik komponen sampel dengan komponen.
Bagi mereka yang menginginkan demonstrasi formal tentang kebenaran, saya menawarkannya di sini. Biarkan mewakili distribusi kernel dengan CDF dan biarkan datanya . Dengan definisi estimasi kernel, CDF dari KDE adalahKFKx =( x1, x2, ... , xn)
Fx^;K( x ) = 1n∑i = 1nFK( x - xsaya) .
Resep sebelumnya mengatakan untuk menggambar dari distribusi empiris data (yaitu, ia mencapai nilai dengan probabilitas untuk setiap ), menggambar secara mandiri variabel acak dari distribusi kernel, dan menjumlahkannya. Saya berutang bukti bahwa fungsi distribusi adalah fungsi KDE. Mari kita mulai dengan definisi dan melihat ke mana ia mengarah. Biarkan menjadi bilangan real. Pengkondisian pada memberiXxsaya1 / nsayaYX+ YxX
FX+ Y( x )= Pr ( X+ Y≤ x )= ∑i = 1nPr ( X+ Y≤ x ∣ X= xsaya) Pr ( X= xsaya)= ∑i = 1nPr ( xsaya+ Y≤ x ) 1n= 1n∑i = 1nPr ( Y≤ x - xsaya)= 1n∑i = 1nFK( x - xsaya)= Fx^;K( x ) ,
seperti yang diklaim.
#
# 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))