【机器学习sklearn】简单易懂核密度估计KernelDensity

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
简介: 【机器学习sklearn】简单易懂核密度估计KernelDensity

前言


       作业中遇到了需要使用KernelDensity的情况,但是网上的资料参差不齐,找了不短的时间却失望而归,最后还是靠着自己的理解才弄懂sklearn个函数的使用,特此纪念。


官方文档


image.png

官方Sample解读


       这个例子使用KernelDensity类来演示一维核密度估计的原理。


直方图


       下图显示了使用直方图可视化一维点密度的一个问题。直观上,直方图可以被认为是一种方案,其中一个单元“块”堆叠在规则网格上的每个点之上。然而,正如上面的两个面板所显示的那样,对这些块的网格选择可能会导致对密度分布的潜在形状产生截然不同的想法。


       补充:可以看出直方图表达数据密度受带宽的取值影响非常之大,同一个数据不同的带宽完全是两种不同的图性,可见这种方式对于表达密度来讲并不理想。


1dc618a0ed9580ce8bfa6facb208c08f.png


核密度


       如果我们将每个块放在它所代表的点的中心,我们就会得到面板所示的估计值。这是一个带有“大礼帽”核的核密度估计。这个想法可以推广到其他核形状:下图的右下面板显示了相同分布上的高斯核密度估计。


       补充:以每个数据作为中心点设置带宽b,(x-b,x+b)区间范围内存在数据便统计在该柱形图上(这里和微积分的思想有一点类似,把一个不规则形状用无数个无线小的柱形描述他们的面积),这意味着带宽越小,那么数据划分的就越细致,但是也更加尖锐,容易欠拟合;带宽越大,那么数据划分的自然也就较粗糙,但是更加平滑,容易过拟合。


5d4c6812c8535adbb050f4ddf2e1bce8.png


内核可视化


       Scikit-learn使用球树或KD树结构,通过内核密度估计器实现高效的内核密度估计。可用的内核显示在本示例的下图中。


       补充:不同的数据分布使用不同的内核,比如符合高斯分布的数据请使用gaussian内核。


46a9d80a6e05e4e3b19d57a0ee70bcdf.png


官方实例代码解析:


# ----------------------------------------------------------------------
# Plot a 1D density example
# ---------------------------------------------------------------------------
'''
用随机种子生成100个数据,其中30个是符合高斯分布(0,1)的数据,70个是符合高斯分布(5,1)的数据,
(0,1)表示以x轴上的0为中心点,宽度为1的高斯分布。
(5,1)表示以x轴上5为中心店,宽度为1的高斯分布
'''
# ---------------------------------------------------------------------------
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]
# ---------------------------------------------------------------------------
# 创建一个[-5,10]范围内包含1000个数据的等差数列
X_plot = np.linspace(-5, 10, 1000)[:, np.newaxis]
# 使用简单的高斯模型norm得到两个高斯分布的概率密度作为真实值(我不觉得这是最佳的办法)
true_dens = 0.3 * norm(0, 1).pdf(X_plot[:, 0]) + 0.7 * norm(5, 1).pdf(X_plot[:, 0])
fig, ax = plt.subplots()
# 填充出用简单高斯模型得出的密度真实值
ax.fill(X_plot[:, 0], true_dens, fc="black", alpha=0.2, label="input distribution")
colors = ["navy", "cornflowerblue", "darkorange"]
# 使用不同的内核进行拟合,我也不推荐这样做,我们首先应该是观察数据的分布,然后选择模型,而不是
# 一个个尝试,应该做的是调整我们的带宽。
kernels = ["gaussian", "tophat", "epanechnikov"]
# 划线的粗细
lw = 2
for color, kernel in zip(colors, kernels):
    # 用X数据进行训练模型
    kde = KernelDensity(kernel=kernel, bandwidth=0.5).fit(X)
    # 在X_plot数据上测试
    log_dens = kde.score_samples(X_plot)
    # 画图
    ax.plot(
        X_plot[:, 0],
        np.exp(log_dens),
        color=color,
        lw=lw,
        linestyle="-",
        label="kernel = '{0}'".format(kernel),
    )
ax.text(6, 0.38, "N={0} points".format(N))
ax.legend(loc="upper left")
# 用'+'代表真实的数据并且画出,用于观察数据分布集中情况
ax.plot(X[:, 0], -0.005 - 0.01 * np.random.random(X.shape[0]), "+k")
ax.set_xlim(-4, 9)
ax.set_ylim(-0.02, 0.4)
plt.show()

       上诉代码画出的示例图如下:该图比较了一维中100个样本分布的核密度估计。虽然本例使用1D分布,但核密度估计也可以轻松有效地扩展到更高的维度。补充:是有两个符合正态分布的数据叠加而成的。


66ba272a0bfc97be54a5fa679e3d5482.png


在此,我更愿意提供一个更加合适的作业帮助大家理解KDE 。


我的示例:


所需文件获取:


百度网盘提取码:q4ef

https://pan.baidu.com/s/1eyyaxF51X4d9hZL_fQOVrA%C2%A0


题目:


       Use the provided dataset, ‘Question_1.csv’, to estimate the density of the dataset using Kernel Density Estimation (KDE). You can consider the Gaussian kernel with three bandwidth

parameters (0.15, 0.5 and 1). The data is generated from a Gaussian distribution with mean 1 and variance 1.


       使用提供的数据集“Question_1.csv”,使用核密度估计(KDE)来估计数据集的密度。你可以考虑三个带宽的高斯核参数(0.15,0.5和1)。数据由均值1和方差1的高斯分布生成。


a. Find and report the MSE between the estimated density and the ground truth density?


a.发现并报告估计密度与地面真实密度之间的MSE ?


b. What do you notice as you change the bandwidth parameter and why?


b.修改带宽参数时,您注意到什么?为什么?


参考答案:(jupyter notebook下环境)


0.导入包


# import package
import sklearn 
from sklearn.neighbors import KernelDensity
from scipy.stats import norm
import pandas as pd 
import numpy as np
import matplotlib.pyplot as plt
from collections import defaultdict


1、数据预处理

# Step1、Data pretreatment
Q1_data = pd.read_csv('hw3/Question_1.csv')
X = np.array(Q1_data['X'].tolist())[:, np.newaxis]
N = len(X)
print('max_value_in_X:{}'.format(max(X)))
print('min_value_inX:{}'.format(min(X)))
X.shape


2、得到最佳带宽作为真实值(我认为比较合理的方式去选取真实值)


# from sklearn.grid_search import GridSearchCV
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import LeaveOneOut
bandwidths = 10 ** np.linspace(-1, 1, 100)
grid = GridSearchCV(KernelDensity(kernel='gaussian'),{'bandwidth': bandwidths},cv=LeaveOneOut())
grid.fit(X)
# The best estimated bandwidth density is used as the truth value
best_KDEbandwidth = grid.best_params_['bandwidth']
kernel = "gaussian"
lw = 2
kde = KernelDensity(kernel=kernel, bandwidth=best_KDEbandwidth).fit(X)
truth_density = np.exp(kde.score_samples(X))
grid.best_params_


3、开始使用KDE


# Step2、Kernel Density Estimation. 
MSE_MAP = defaultdict(list)
fig, ax = plt.subplots()
ax.fill(X[:, 0], truth_density, fc="black", alpha=1, label="truth density")
bandwidths = [0.15, 0.5, 1]
colors = ["navy", "cornflowerblue", "darkorange"]
for bandwidth, color in zip(bandwidths, colors): 
    kde = KernelDensity(kernel=kernel, bandwidth=bandwidth).fit(X)
    log_dens = kde.score_samples(X)
    if bandwidth == best_KDEbandwidth:
        bandwidth = 'ground truth'
    ax.plot(
        X[:, 0],
        np.exp(log_dens),
        color=color,
        lw=lw,
        linestyle="-",
        label="bandwidth = '{0}'".format(bandwidth),
    )
    MSE_MAP[bandwidth] = log_dens
ax.text(6, 0.32, "N={0} points".format(N))
ax.legend(loc="upper right")
ax.plot(X[:, 0], -0.005 - 0.01 * np.random.random(X.shape[0]), "+k")
ax.set_xlim(-4, 9)
ax.set_ylim(-0.02, 0.50)
plt.show()


88b9988b40447cb37c7e3c492d49867f.png


(预测效果)


4,计算估计密度与地面真实密度之间的MSE


def cal_mse(a, b):
    if len(a) == len(b):
        n = len(a)
    else:
        return 'len(a) != len(b)'
    res = 0
    for i in range(n):
        res += (a[i]-b[i])**2
    return res/n
for bandwidth in MSE_MAP:
    estimate_density = MSE_MAP[bandwidth]
    MSE = cal_mse(estimate_density, truth_density)
    print("When bandwidth is {:.2f} ----> MSE(estimate, truth): {:.3f}".format(bandwidth, MSE))
When bandwidth is 0.15 ----> MSE(estimate, truth): 2.603
When bandwidth is 0.50 ----> MSE(estimate, truth): 2.803
When bandwidth is 1.00 ----> MSE(estimate, truth): 3.059

       可以看出MSE表示与3.中的图表示出的信息是一致的。


好啦,到此就结束啦!希望本文能帮到你。


如果觉得有用的话,欢迎大家三连~。祝你玩的开心。


相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
6月前
|
机器学习/深度学习 算法 数据挖掘
机器学习之sklearn基础——一个小案例,sklearn初体验
机器学习之sklearn基础——一个小案例,sklearn初体验
142 6
|
2月前
|
机器学习/深度学习 算法 数据可视化
【机器学习】决策树------迅速了解其基本思想,Sklearn的决策树API及构建决策树的步骤!!!
【机器学习】决策树------迅速了解其基本思想,Sklearn的决策树API及构建决策树的步骤!!!
|
7月前
|
机器学习/深度学习 数据采集 算法
机器学习之sklearn基础教程
机器学习之sklearn基础教程
|
4月前
|
机器学习/深度学习 数据采集 算法
机器学习到底是什么?附sklearn代码
机器学习到底是什么?附sklearn代码
|
4月前
|
机器学习/深度学习 数据采集 算法
如何使用机器学习神器sklearn做特征工程?
如何使用机器学习神器sklearn做特征工程?
|
5月前
|
机器学习/深度学习 数据采集 数据可视化
Sklearn入门指南:构建你的第一个机器学习模型
【7月更文第22天】在数据科学与机器学习领域,Scikit-learn(简称sklearn)是一个广泛使用的Python库,以其简洁的API和丰富的功能集而著称。本指南将引领你从安装到使用sklearn构建你的第一个机器学习模型,以一个简单的线性回归任务为例,逐步深入理解这个强大的工具。
116 2
|
6月前
|
机器学习/深度学习 数据采集 自然语言处理
机器学习之sklearn基础教程
机器学习之sklearn基础教程
|
6月前
|
机器学习/深度学习 数据处理 计算机视觉
机器学习- Sklearn (交叉验证和Pipeline)
机器学习- Sklearn (交叉验证和Pipeline)
|
7月前
|
机器学习/深度学习 数据采集 人工智能
机器学习之sklearn基础教程
【5月更文挑战第9天】Sklearn是Python热门机器学习库,提供丰富算法和预处理工具。本文深入讲解基础概念、核心理论、常见问题及解决策略。内容涵盖模型选择与训练、预处理、交叉验证、分类回归、模型评估、数据集划分、正则化、编码分类变量、特征选择与降维、集成学习、超参数调优、模型评估、保存加载及模型解释。学习Sklearn是迈入机器学习领域的关键。
121 3
|
7月前
|
机器学习/深度学习 数据可视化 数据处理
python 机器学习 sklearn——一起识别数字吧
python 机器学习 sklearn——一起识别数字吧