Bir çekirdek yoğunluk tahmininden rastgele bir değeri nasıl çizebilirim?


10

Bazı gözlemlerim var ve bu gözlemlere dayalı örneklemeyi taklit etmek istiyorum. Burada parametrik olmayan bir modeli göz önünde bulunduruyorum, özellikle, sınırlı gözlemlerden bir CDF tahmin etmek için çekirdek yumuşatma kullanıyorum.Ardından elde edilen CDF'den rastgele değerler çiziyorum.Aşağıdaki kodum, tekdüze dağılım kullanarak olasılık ve olasılık değerine göre CDF'nin tersini almak)

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)

Kodda gösterildiği gibi, prosedürümü test etmek için sentetik bir örnek kullandım, ancak aşağıdaki iki şekil ile gösterildiği gibi sonuç tatmin edici değil (birincisi simüle gözlemler içindir ve ikinci şekil tahmini CDF'den alınan histogramı gösterir) :

Şekil 1 şekil 2

Sorunun nerede olduğunu bilen var mı? Şimdiden teşekkür ederim.


Ters dönüşüm örnekleme, ters CDF kullanımına bağlıdır. tr.wikipedia.org/wiki/Inverse_transform_sampling
Sycorax, Reinstate Monica'yı

1
Çekirdek yoğunluğu tahmin ediciniz, çekirdek dağılımının konum karışımı olan bir dağıtım üretir, bu nedenle çekirdek yoğunluğu tahmininden bir değer çizmeniz için gereken tek şey (1) çekirdek yoğunluğundan bir değer çizmek ve sonra (2) bağımsız olarak veriler rastgele işaret eder ve değerini (1) sonucuna ekler. KDE'yi doğrudan tersine çevirmeye çalışmak çok daha az verimli olacaktır.
whuber

@Sycorax Ama gerçekten Wiki'de açıklanan ters dönüşüm örnekleme prosedürünü izliyorum. Lütfen kodu inceleyin: p = rand; [~, idx] = sıralama (abs (cdf (:, 2) - p)); rndval (i, 1) = cdf (idx (1), 1);
emberbillow

@whuber Fikrinizi anlamanın doğru olup olmadığından emin değilim. Lütfen kontrol etmeye yardımcı olun: önce gözlemlerden bir değeri yeniden örnekleyin; ve sonra standart normal dağılım, örneğin çekirdekten bir değer çizin; nihayet, onları bir araya getirmek?
emberbillow

Yanıtlar:


12

Bir çekirdek yoğunluğu tahmincisi (KDE), çekirdek dağılımının bir konum karışımı olan bir dağılım üretir, bu nedenle çekirdek yoğunluğu tahmininden bir değer çizmek için yapmanız gereken tek şey (1) çekirdek yoğunluğundan bir değer çizmek ve sonra (2) bağımsız olarak veri noktalarından birini rastgele seçin ve değerini (1) sonucuna ekleyin.

İşte bu prosedürün, sorudakine benzer bir veri kümesine uygulanan sonucu.

şekil

Soldaki histogram örneği gösterir. Referans için siyah eğri, numunenin çekildiği yoğunluğu çizer. Kırmızı eğri, numunenin KDE'sini çizer (dar bir bant genişliği kullanarak). (Kırmızı piklerin siyah piklerden daha kısa olması bir sorun, hatta beklenmedik bir şey değildir: KDE işleri dağıtır, bu nedenle pikler telafi etmek için daha düşük olur.)

Sağdaki histogram KDE'den (aynı boyutta) bir örneği gösterir . Siyah ve kırmızı eğriler öncekilerle aynıdır.

Açıkçası, yoğunluktan numune almak için kullanılan prosedür çalışır. Ayrıca son derece hızlı: RAşağıdaki uygulama herhangi bir KDE'den saniyede milyonlarca değer üretir. Ben Python veya diğer diller için taşıma yardımcı olmak için yorumladı. Örnekleme algoritmasının kendisi, rdensçizgilerle fonksiyonda uygulanır

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

rkernelçeker niken çekirdek işlevinden IID örnekleri sampleçeken nverilerden değiştirme ile örnekleri x. "+" İşleci iki bileşen dizisini bileşene göre ekler.


KFKx=(x1,x2,,xn)

Fx^;K(x)=1ni=1nFK(xxi).

Yukarıdaki tarif verilerin ampirik dağılımından (yani her i için 1 / n olasılığı olan x i değerini elde ettiğini ), bağımsız olarak çekirdek dağılımından rastgele bir Y değişkeni çektiğini ve topladığını söylüyor. X + Y'nin dağıtım işlevinin KDE'nin işlevi olduğuna dair bir kanıt borçluyum . Tanımla başlayalım ve nereye götürdüğünü görelim. Let x be gerçek sayı. Üzerinde Klima X verirXxi1/niYX+YxX

FX+Y(x)=Pr(X+Yx)=i=1nPr(X+YxX=xi)Pr(X=xi)=i=1nPr(xi+Yx)1n=1ni=1nPr(Yxxi)=1ni=1nFK(xxi)=Fx^;K(x),

iddia edildiği gibi.


#
# 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))

Merhaba @whuber, bu fikri makalemde belirtmek istiyorum. Bunun için yayınlanmış makaleleriniz var mı? Teşekkür ederim.
emberbillow

2

CDF'den önce ters çevirerek örnek alın. Ters CDF'ye kuantil fonksiyon denir; [0,1] 'den RV'nin alanına bir eşlemedir. Daha sonra rastgele tekdüze RV'leri yüzdelik olarak örneklersiniz ve bu dağılımdan rastgele bir örnek elde etmek için bunları kantil fonksiyona geçirirsiniz.


2
Bu zor yol: soruya yaptığım yoruma bakın.
whuber

2
@whuber iyi bir nokta. Programlı yönlerden çok fazla etkilenmeden, bu durumda bir CDF ile çalışmamız gerektiğini varsayıyordum. Hiç şüphe yok ki böyle bir fonksiyonun içselleri bir çekirdek düzgünleştirilmiş yoğunluk alır ve daha sonra bir CDF elde etmek için onu entegre eder. Bu noktada, ters dönüşüm örneklemesi kullanmak muhtemelen daha iyi ve daha hızlıdır. Bununla birlikte, yoğunluğu ve numuneyi doğrudan karışımdan kullanma öneriniz daha iyidir.
AdamO

@AdamO Cevabınız için teşekkür ederim. Ama benim kodum aslında burada söylediğin aynı fikri izliyor. Üç modlu modellerin neden çoğaltılamadığını bilmiyorum.
emberbillow

@AdamO Burada yorumunuzdaki "içsel" kelimesinin "aralıklar" olması gerekip gerekmediği? Teşekkür ederim.
emberbillow

Ember, "içsel" benim için çok mantıklı. Böyle bir fonksiyon, karışım yoğunluğunu entegre etmek ve tersini yapmak zorundadır: bu, AdamO'nun ima ettiği gibi dağınık, sayısal olarak karmaşık bir süreçtir ve bu nedenle fonksiyonun içine gömülecektir - onun "içsel".
whuber

1

Burada, Matlab kodunu Ruber'den daha aşina olanlara yardım etmek için whuber tarafından açıklanan fikri izleyerek de göndermek istiyorum.

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;

Sonuç şudur: Sonuçlar

Lütfen bana anlayışım ve kodumla ilgili herhangi bir sorun olup olmadığını söyleyin Teşekkür ederim.


1
Ek olarak, sorudaki kodumun doğru olduğunu buldum. Desenin çoğaltılamadığı gözlemi büyük ölçüde bant genişliği seçiminden kaynaklanmaktadır.
emberbillow

0

Uygulamanıza çok yakından bakmadan, ICDF'den çekmek için indeksleme prosedürünüzü tam olarak alamıyorum. Sanırım CDF'den çiziyorsun, ters değil. İşte benim uygulama:

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);

2
Bir cdf F'niz varsa, F (X) üniform olduğu ttrue olur. Böylece, eşit bir dağılımdan rastgele bir sayının ters cdf'sini alarak X elde edersiniz. Bence sorun, bir çekirdek yoğunluğu üretirken tersinin nasıl belirleneceğidir.
Michael R.Chickick

Cevabınız için teşekkür ederim. Doğrudan CDF'den örnek almadım. Kod ters dönüşüm örnekleme ile aynı şeyi yaptığımı gösterir. p = rand; Bu satır kümülatif olasılık olarak düzgün bir rasgele sayı alır. [~, idx] = sıralama (abs (cdf (:, 2) - p)); rndval (i, 1) = cdf (idx (1), 1); bu iki satır, kümülatif olasılığa karşılık gelen
kantili
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.