2017-07-11 32 views
0

我很努力在小輸入範圍內實現KDE的scikit-learn實現。以下代碼有效。除數變量增加至100和KDE鬥爭:sklearn:KDE不能用於小數值

import numpy as np 
import matplotlib.pyplot as plt 
import seaborn as sns 
sns.set_style('whitegrid') 
from sklearn.neighbors import KernelDensity 

# make data: 
np.random.seed(0) 
divisor = 1 
gaussian1 = (3 * np.random.randn(1700))/divisor 
gaussian2 = (9 + 1.5 * np.random.randn(300))/divisor 
gaussian_mixture = np.hstack([gaussian1, gaussian2]) 

# illustrate proper KDE with seaborn: 
sns.distplot(gaussian_mixture); 

enter image description here

# now implement in sklearn: 

x_grid = np.linspace(min(gaussian1), max(gaussian2), 200) 

kde_skl = KernelDensity(bandwidth=0.5) 
kde_skl.fit(gaussian_mixture[:, np.newaxis]) 
# score_samples() returns the log-likelihood of the samples 
log_pdf = kde_skl.score_samples(x_grid[:, np.newaxis]) 
pdf = np.exp(log_pdf) 

fig, ax = plt.subplots(1, 1, sharey=True, figsize=(7, 4)) 
ax.plot(x_grid, pdf, linewidth=3, alpha=0.5) 

enter image description here

工作正常。但是,將「除數」變量更改爲100,scipy和seaborn可以處理較小的數據值。 Sklearn的KDE不能與我的實現:

enter image description here

什麼我做錯了,我該怎麼糾正呢?我需要KDE的sklearns實現,所以不能使用其他算法。

回答

2

核密度估計被稱爲非參數方法,但實際上它有一個參數,稱爲帶寬

KDE的每個應用程序都需要這個參數集!

當你做對seaborn積:

sns.distplot(gaussian_mixture); 

你不給任何帶寬和seaborn使用默認的啓發式(斯科特·西爾弗曼或)。這些正在使用數據以依賴方式選擇一些帶寬。

你的sklearn代碼看起來像:

kde_skl = KernelDensity(bandwidth=0.5) 

有一個固定/恆定帶寬!這可能會給你帶來麻煩,並可能是這裏的原因。但至少應該看一些東西。一般來說,將sklearn的KDE和GridSearchCV作爲交叉驗證工具來選擇良好的帶寬。在很多情況下,這比較慢,但比上面的啓發式更好。

很遺憾,你沒有解釋你爲什麼要使用sklearn的KDE。我個人對3位受歡迎的候選人的評價是statsmodels > sklearn > scipy

+0

嗨@sascha。我剛剛用自己的KDE實現了一種類似於海運的方法。它使用Silverman的帶寬參考規則,似乎適當地估計帶寬: 'x = gaussian_mixture' 'bandwidth = 1.06 * x.std()* x.size **(-1/5)' 但是,我希望能夠在sklearn中使用交叉驗證方法,因此會將其用作初始值,然後圍繞該值執行小型網格搜索以在成本函數中查找局部最小值。謝謝。 – EB88