В общем, вам нужно сделать это численно.Я предлагаю 2 различных подхода:
- Интеграция
- Моделирование Монте-Карло
Эти подходы работают для любого ядра и любого bandwidth .
Интеграция
Использует тот факт, что как только мы знаем функцию плотности вероятности , мы можем легко вычислить среднее и дисперсию посредством интегрирования.
Обратите внимание, что в scikit-learn
метод score_samples
возвращает log pdf и, следовательно, его нужно "exp".
Monte CarloМоделирование
Идея состоит в том, чтобы просто произвести выборку из вашего KDE и оценить среднее значение и дисперсию популяции через среднее значение и дисперсию выборки.
Код
import numpy as np
from scipy.integrate import quad
from sklearn.neighbors import KernelDensity
N = 100
np.random.seed(1)
X = np.concatenate((np.random.normal(0, 1, int(0.3 * N)),np.random.normal(5, 1, int(0.7 * N))))[:, np.newaxis]
X_plot = np.linspace(-5, 10, 1000)[:, np.newaxis]
kde = KernelDensity(kernel='gaussian', bandwidth=0.5).fit(X)
# Mean and Variance - Integration
pdf = lambda x : np.exp(kde.score_samples([[x]]))[0]
mean_integration = quad(lambda x: x * pdf(x), a=-np.inf, b=np.inf)[0]
variance_integration = quad(lambda x: (x ** 2) * pdf(x), a=-np.inf, b=np.inf)[0] - mean_integration ** 2
# Mean and Variance - Monte Carlo
n_samples = 10000000
samples = kde.sample(n_samples)
mean_mc = samples.mean()
variance_mc = samples.var()
print('Mean:\nIntegration: {}\nMonte Carlo: {}\n'.format(mean_integration, mean_mc))
print('Variance\nIntegration: {}\nMonte Carlo: {}\n'.format(variance_integration, variance_mc))
Вывод:
Значение: интеграция: 3.560582852075697 Монте-Карло: 3.5595633705830934
Дисперсия: интеграция: 6.645066811078639 Монте-Карло: 6.646732489654485