【Python】机器学习笔记11-核密度估计(Kernel Density Estimation)

本文的参考资料:《Python数据科学手册》
本文的源代上传到了Gitee上;

本文用到的包:

%matplotlib inline
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

import cartopy.crs as ccrs
import cartopy.feature as cfeature
from cartopy.mpl.geoaxes import GeoAxesSubplot

from sklearn.base import BaseEstimator, ClassifierMixin
from sklearn.datasets import fetch_species_distributions, load_digits
from sklearn.model_selection import GridSearchCV, LeaveOneOut, train_test_split
from sklearn.neighbors import KernelDensity

sns.set()
plt.rc('font', family='SimHei')
plt.rc('axes', unicode_minus=False)

核密度估计(Kernel Density Estimation)

密度评估器是一种利用D维数据集生成D维概率分布估计的算法,GMM使用不同的高斯分布的加权汇总来表示概率分布估计。
核密度估计算法将高斯混合理念扩展到了逻辑极限,它通过对每一个点生成高斯分布的混合成分,获得本实质上是无参数的密度评估器(书本原话)。

核密度估计的自由参数是核类型和核带宽,前者指定每个点核密度分布的形状,后者指定每个点核的大小。

上边是书上讲的话,下面是我的理解:

核密度估计本质上是从有限的样本中尽可能地估算概率密度函数,类似于让直方图的区间趋向无穷小后得到的图形,当然由于样本数量是有限的不能直接实现这样的操作。

核密度估计示例

核密度估计在sklearn中由KernelDensity类实现,kernel参数指定需要用到的核函数,来适应不同的需求;
以下代码生成一组高斯分布的随机数据,分别绘制其直方图与KDE图,查看效果;

x_train = np.hstack((np.random.normal(2, 1.66, 200), np.random.normal(8, 2.33, 200)))  # 两个高斯分布组合到一起

model = KernelDensity(bandwidth=1.0, kernel='gaussian')
model.fit(x_train[:, np.newaxis])
x_range = np.linspace(x_train.min() - 1, x_train.max() + 1, 500)
x_log_prob = model.score_samples(x_range[:, np.newaxis])  # 这个东西返回概率的对数
x_prob = np.exp(x_log_prob)

plt.figure(figsize=(10, 10))
r = plt.hist(
    x=x_train,
    bins=50,
    density=True,
    histtype='stepfilled',
    color='red',
    alpha=0.5,
    label='直方图',
)
plt.fill_between(
    x=x_range,
    y1=x_prob,
    y2=0,
    color='green',
    alpha=0.5,
    label='KDE',
)
plt.plot(x_range, x_prob, color='gray')
plt.vlines(x=2, ymin=0, ymax=r[0].max() + 0.01, color='k', linestyle='--', alpha=0.7)  # 分布中心
plt.vlines(x=8, ymin=0, ymax=r[0].max() + 0.01, color='k', linestyle='--', alpha=0.7)  # 分布中心
plt.ylim(0, r[0].max() + 0.011)
plt.legend(loc='upper right')
plt.title('同一组数据的直方图与KDE图')

在这里插入图片描述

使用交叉检验确定带宽

在使用核密度估计时,如果带宽设置过小,会出现过拟合的现象,如果带宽设置过大,会出现欠拟合的现象,因此需要确定好最佳的带宽;
sklearn中的KernelDensity类支持使用GridSearchCV来寻找最佳参数,以下是一个示例:

x_train = np.hstack((np.random.normal(2, 1.66, 200), np.random.normal(8, 2.33, 200)))

grid = GridSearchCV(
    estimator=KernelDensity(kernel='gaussian'),
    param_grid={'bandwidth': 10 ** np.linspace(-1, 1, 100)},
    cv=LeaveOneOut(),
)
grid.fit(x_train[:, np.newaxis])
print(f'最佳带宽:{grid.best_params_["bandwidth"]}')

输出结果:

最佳带宽:0.7742636826811272

在球形空间中使用KDE

从sklearn中加载物种分布数据(fetch_species_distributions函数),返回的数据中包含了森林小稻鼠和褐喉树懒在南美中的分布数据;
我们将用KDE从这些分布数据中计算这两个物种的分布密度,并显示在地图上(还真是在球面上的数据);

由于书本介绍的Basemap已经停止维护了,所以这里我是用了cartopy这个库来显示地图(费了不少力气);
书本代码用到了一个在如今的sklearn中已经被废弃的函数construct_grids,我从网上找到了它的源码,凑合用一下;

def construct_grids(batch):  # 这个函数在现在版本的sklearn中被废弃了,从网上找到了以前的源码
    """Construct the map grid from the batch object

    Parameters
    ----------
    batch : Batch object
        The object returned by :func:`fetch_species_distributions`

    Returns
    -------
    (xgrid, ygrid) : 1-D arrays
        The grid corresponding to the values in batch.coverages
    """
    # x,y coordinates for corner cells
    xmin = batch.x_left_lower_corner + batch.grid_size
    xmax = xmin + (batch.Nx * batch.grid_size)
    ymin = batch.y_left_lower_corner + batch.grid_size
    ymax = ymin + (batch.Ny * batch.grid_size)

    # x coordinates of the grid cells
    xgrid = np.arange(xmin, xmax, batch.grid_size)
    # y coordinates of the grid cells
    ygrid = np.arange(ymin, ymax, batch.grid_size)

    return xgrid, ygrid

species_data = fetch_species_distributions()
species_names = ['褐喉树懒', '森林小稻鼠']

lat_and_lon = np.vstack((
    species_data.train['dd lat'],
    species_data.train['dd long'],
)).T

species_train = np.array([
    d.decode('ascii').startswith('micro')  # 这样写的话,森林小稻鼠(microryzomys minutus)就是1,褐喉树懒(bradypus variegatus)就是0
    for d in species_data.train['species']
], dtype=np.int)

fig = plt.figure(figsize=(20, 10))  # type: plt.Figure
fig.suptitle('用散点图显示物种分布')
for i in range(2):
    ax = fig.add_subplot(1, 2, i + 1, projection=ccrs.PlateCarree())  # type: GeoAxesSubplot
    ax.set_extent([-30, -90, 15, -60], crs=ccrs.PlateCarree())  # 南美洲的经纬度
    ax.add_feature(cfeature.LAND)
    ax.add_feature(cfeature.OCEAN)
    ax.add_feature(cfeature.COASTLINE)
    ax.add_feature(cfeature.BORDERS, linestyle=':')
    ax.add_feature(cfeature.LAKES, alpha=0.5)
    ax.add_feature(cfeature.RIVERS)
    ax.scatter(
        x=lat_and_lon[:, 1][species_train==0], y=lat_and_lon[:, 0][species_train==0],
        c='green' if i == 0 else 'red', cmap='rainbow', edgecolor='k', alpha=0.1
    )
    ax.set_title(f'{species_names[i]}分布')

x_grid, y_grid = construct_grids(species_data)
X, Y = np.meshgrid(x_grid[::5], y_grid[::5][::-1])
land_reference = species_data.coverages[6][::5, ::5]
land_mask = (land_reference > -9999).ravel()  # -9999代表的区域是海洋
xy = np.vstack((Y.ravel(), X.ravel())).T
xy = np.radians(xy[land_mask])

fig = plt.figure(figsize=(20, 10))  # type: plt.Figure
fig.suptitle('用KDE密度图显示物种分布')
for i in range(2):
    ax = fig.add_subplot(1, 2, i + 1, projection=ccrs.PlateCarree())  # type: GeoAxesSubplot
    ax.set_extent([-30, -90, 15, -60], crs=ccrs.PlateCarree())  # 南美洲的经纬度
    ax.add_feature(cfeature.LAND)
    ax.add_feature(cfeature.OCEAN)
    ax.add_feature(cfeature.COASTLINE)
    ax.add_feature(cfeature.BORDERS, linestyle=':')
    ax.add_feature(cfeature.LAKES, alpha=0.5)
    ax.add_feature(cfeature.RIVERS)

    kde = KernelDensity(bandwidth=0.03, metric='haversine')  # 一个球形空间的KDE
    kde.fit(np.radians(lat_and_lon[species_train == i]))
    Z = np.full(land_mask.shape[0], -9999)
    Z[land_mask] = np.exp(kde.score_samples(xy))
    Z = Z.reshape(X.shape)

    ax.contourf(
        X, Y, Z,
        levels=np.linspace(0, Z.max(), 50),
        cmap='Greens' if i == 0 else 'Reds',
    )
    ax.set_title(f'{species_names[i]}分布')
fig.savefig('GIS.png')

结果:
在这里插入图片描述
在这里插入图片描述

案例:不是很朴素的贝叶斯

朴素贝叶斯分类为每一个类创建了一个简单的生成模型,并用这些模型构建了一个快速的分类器。在朴素贝叶斯分类中,生成模型是与坐标轴平行的某种分布(高斯分布、多项式分布、etc)。
如果利用KDE这样的核密度估计算法,我们就可以去掉“朴素”的成分,使用更成熟的生成模型描述每一个类。虽然它还是贝叶斯分类,但是它不再NAIVE!

步骤如下:

  • 通过标签将训练数据分割成为若干个集合
  • 为每一个集合你和一个KDE模型来获得其生成模型,获得 P ( x ∣ y ) P(x|y) P(xy)
  • 根据没一个集合中的样本数量,计算先验概率 P ( y ) P(y) P(y)
  • 对于每一个未知数据,计算 P ( x ∣ y ) P ( y ) P(x|y)P(y) P(xy)P(y),并将其分配给概率最大的标签

(好神奇)

使用网格搜索找到最佳参数后,这个自定义的KDE贝叶斯分类器对于sklearn手写数字的分类准确率可以达到96.7%,如果只是使用高斯朴素贝叶斯进行分类的话准确率只有85%(之前做过);

当然,我们的模型还存在改进空间,比如可以允许每一类的KDE带宽各不相同;

class KDEClassifier(BaseEstimator, ClassifierMixin):
    """
    bandwidth: 用于KDE模型的带宽
    kernel: 用于KDE模型的核函数名称
    """
    def __init__(self, bandwidth=1.0, kernel='gaussian'):
        self.bandwidth = bandwidth
        self.kernel = kernel
        self.classes_ = None
        self.models_ = None
        self.logpriors_ = None

    def fit(self, X, y):
        self.classes_ = np.sort(np.unique(y))  # 找到所有的类
        training_sets = [X[y == yi] for yi in self.classes_]
        # 为每一个类训练一个KDE,从样本中计算每一个类在D维空间中出现的概率密度
        self.models_ = [KernelDensity(bandwidth=self.bandwidth, kernel=self.kernel).fit(Xi) for Xi in training_sets]
        self.logpriors_ = [np.log(Xi.shape[0] / X.shape[0]) for Xi in training_sets]  # 根据样本数量计算每一个类的先验概率
        return self

    def predict_proba(self, X):
        logprobs = np.array([
            m.score_samples(X) for m in self.models_  # 计算输入样本作为每一个类在其所在位置出现的概率
        ]).T
        result = np.exp(logprobs + self.logpriors_)  # 概率的对数相加,等于概率相乘,乘以每一个类的先验概率
        return result / result.sum(axis=1, keepdims=True)

    def predict(self, X):
        return self.classes_[np.argmax(self.predict_proba(X), axis=1)]  # 找概率最大的那一个类

digits = load_digits()
bandwidths = 10 ** np.linspace(0, 2, 100)
grid = GridSearchCV(estimator=KDEClassifier(), param_grid={'bandwidth': bandwidths}, cv=5)
grid.fit(digits.data, digits.target)

#%%

print(f'自定义的KDE贝叶斯分类器在分类手写数字时的最佳准确率:{grid.best_score_}')
print(f'自定义的KDE贝叶斯分类器在分类手写数字时的最佳参数{grid.best_params_["bandwidth"]}')

plt.figure(figsize=(10, 10))
plt.semilogx(bandwidths, grid.cv_results_['mean_test_score'])
plt.vlines(x=grid.best_params_['bandwidth'], ymin=0, ymax=1, color='gray', linestyle='--')
plt.xlabel('KDE bandwidth')
plt.ylabel('模型交叉验证平均准确率')
plt.ylim(0, 1)
plt.title('KDE分类器交叉验证平均准确率与KDE带宽的关系')

在这里插入图片描述

完整代码(Jupyter Notebook)

#%% md

# 核密度估计

密度评估器是一种利用D维数据集生成D维概率分布估计的算法,GMM使用不同的高斯分布的加权汇总来表示概率分布估计。
核密度估计算法将高斯混合理念扩展到了逻辑极限,它通过对每一个点生成高斯分布的混合成分,获得本实质上是无参数的密度评估器。

核密度估计的自由参数是核类型和核带宽,前者指定每个点核密度分布的形状,后者指定每个点核的大小。

上边是书上讲的话,下面是我的理解:<br>
核密度估计本质上是从有限的样本中尽可能地估算概率密度函数,类似于让直方图的区间趋向无穷小后得到的图形,当然由于样本数量是有限的无法实现这样的操作。

## 核密度估计示例

以下代码生成一组高斯分布的随机数据,分别绘制其直方图与KDE图,查看效果;

#%%

%matplotlib inline
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

import cartopy.crs as ccrs
import cartopy.feature as cfeature
from cartopy.mpl.geoaxes import GeoAxesSubplot

from sklearn.base import BaseEstimator, ClassifierMixin
from sklearn.datasets import fetch_species_distributions, load_digits
from sklearn.model_selection import GridSearchCV, LeaveOneOut, train_test_split
from sklearn.neighbors import KernelDensity

sns.set()
plt.rc('font', family='SimHei')
plt.rc('axes', unicode_minus=False)

#%%

x_train = np.hstack((np.random.normal(2, 1.66, 200), np.random.normal(8, 2.33, 200)))

model = KernelDensity(bandwidth=1.0, kernel='gaussian')
model.fit(x_train[:, np.newaxis])
x_range = np.linspace(x_train.min() - 1, x_train.max() + 1, 500)
x_log_prob = model.score_samples(x_range[:, np.newaxis])  # 这个东西返回概率的对数
x_prob = np.exp(x_log_prob)

print(x_range.shape)
print(x_log_prob.shape)

plt.figure(figsize=(10, 10))
r = plt.hist(
    x=x_train,
    bins=50,
    density=True,
    histtype='stepfilled',
    color='red',
    alpha=0.5,
    label='直方图',
)
plt.fill_between(
    x=x_range,
    y1=x_prob,
    y2=0,
    color='green',
    alpha=0.5,
    label='KDE',
)
plt.plot(x_range, x_prob, color='gray')
plt.vlines(x=2, ymin=0, ymax=r[0].max() + 0.01, color='k', linestyle='--', alpha=0.7)
plt.vlines(x=8, ymin=0, ymax=r[0].max() + 0.01, color='k', linestyle='--', alpha=0.7)
plt.ylim(0, r[0].max() + 0.011)
plt.legend(loc='upper right')
plt.title('同一组数据的直方图与KDE图')

#%% md

## 使用交叉检验确定带宽

在使用核密度估计时,如果带宽设置过小,会出现过拟合的现象,如果带宽设置过大,会出现欠拟合的现象,因此需要确定好最佳的带宽;
sklearn中的KernelDensity类支持使用GridSearchCV来寻找最佳参数;

#%%

x_train = np.hstack((np.random.normal(2, 1.66, 200), np.random.normal(8, 2.33, 200)))

grid = GridSearchCV(
    estimator=KernelDensity(kernel='gaussian'),
    param_grid={'bandwidth': 10 ** np.linspace(-1, 1, 100)},
    cv=LeaveOneOut(),
)
grid.fit(x_train[:, np.newaxis])
print(f'最佳带宽:{grid.best_params_["bandwidth"]}')

#%% md

## 在球形空间中使用KDE

从sklearn中加载物种分布数据(fetch_species_distributions),返回的数据中包含了森林小稻鼠和褐喉树懒在南美中的分布数据;
我们将用KDE从这些分布数据中计算这两个物种的分布密度,并显示在地图上;

由于书本介绍的Basemap已经停止维护了,所以这里我是用了cartopy这个库来显示地图;
书本代码用到了一个在如今的sklearn中已经被废弃的函数construct_grids,我从网上找到了它的源码,凑合用一下;

#%%

def construct_grids(batch):  # 这个函数在现在版本的sklearn中被废弃了,从网上找到了以前的源码
    """Construct the map grid from the batch object

    Parameters
    ----------
    batch : Batch object
        The object returned by :func:`fetch_species_distributions`

    Returns
    -------
    (xgrid, ygrid) : 1-D arrays
        The grid corresponding to the values in batch.coverages
    """
    # x,y coordinates for corner cells
    xmin = batch.x_left_lower_corner + batch.grid_size
    xmax = xmin + (batch.Nx * batch.grid_size)
    ymin = batch.y_left_lower_corner + batch.grid_size
    ymax = ymin + (batch.Ny * batch.grid_size)

    # x coordinates of the grid cells
    xgrid = np.arange(xmin, xmax, batch.grid_size)
    # y coordinates of the grid cells
    ygrid = np.arange(ymin, ymax, batch.grid_size)

    return xgrid, ygrid

species_data = fetch_species_distributions()
species_names = ['褐喉树懒', '森林小稻鼠']

lat_and_lon = np.vstack((
    species_data.train['dd lat'],
    species_data.train['dd long'],
)).T

species_train = np.array([
    d.decode('ascii').startswith('micro')  # 这样写的话,森林小稻鼠(microryzomys minutus)就是1,褐喉树懒(bradypus variegatus)就是0
    for d in species_data.train['species']
], dtype=np.int)

fig = plt.figure(figsize=(20, 10))  # type: plt.Figure
fig.suptitle('用散点图显示物种分布')
for i in range(2):
    ax = fig.add_subplot(1, 2, i + 1, projection=ccrs.PlateCarree())  # type: GeoAxesSubplot
    ax.set_extent([-30, -90, 15, -60], crs=ccrs.PlateCarree())  # 南美洲的经纬度
    ax.add_feature(cfeature.LAND)
    ax.add_feature(cfeature.OCEAN)
    ax.add_feature(cfeature.COASTLINE)
    ax.add_feature(cfeature.BORDERS, linestyle=':')
    ax.add_feature(cfeature.LAKES, alpha=0.5)
    ax.add_feature(cfeature.RIVERS)
    ax.scatter(
        x=lat_and_lon[:, 1][species_train==0], y=lat_and_lon[:, 0][species_train==0],
        c='green' if i == 0 else 'red', cmap='rainbow', edgecolor='k', alpha=0.1
    )
    ax.set_title(f'{species_names[i]}分布')

x_grid, y_grid = construct_grids(species_data)
X, Y = np.meshgrid(x_grid[::5], y_grid[::5][::-1])
land_reference = species_data.coverages[6][::5, ::5]
land_mask = (land_reference > -9999).ravel()
xy = np.vstack((Y.ravel(), X.ravel())).T
xy = np.radians(xy[land_mask])

fig = plt.figure(figsize=(20, 10))  # type: plt.Figure
fig.suptitle('用KDE密度图显示物种分布')
for i in range(2):
    ax = fig.add_subplot(1, 2, i + 1, projection=ccrs.PlateCarree())  # type: GeoAxesSubplot
    ax.set_extent([-30, -90, 15, -60], crs=ccrs.PlateCarree())  # 南美洲的经纬度
    ax.add_feature(cfeature.LAND)
    ax.add_feature(cfeature.OCEAN)
    ax.add_feature(cfeature.COASTLINE)
    ax.add_feature(cfeature.BORDERS, linestyle=':')
    ax.add_feature(cfeature.LAKES, alpha=0.5)
    ax.add_feature(cfeature.RIVERS)

    kde = KernelDensity(bandwidth=0.03, metric='haversine')  # 一个球形空间的KDE
    kde.fit(np.radians(lat_and_lon[species_train == i]))
    Z = np.full(land_mask.shape[0], -9999)
    Z[land_mask] = np.exp(kde.score_samples(xy))
    Z = Z.reshape(X.shape)

    ax.contourf(
        X, Y, Z,
        levels=np.linspace(0, Z.max(), 50),
        cmap='Greens' if i == 0 else 'Reds',
    )
    ax.set_title(f'{species_names[i]}分布')
fig.savefig('GIS.png')

#%% md

## 案例:不是很朴素的贝叶斯

朴素贝叶斯分类为每一个类创建了一个简单的生成模型,并用这些模型构建了一个快速的分类器。在朴素贝叶斯分类中,生成模型是与坐标轴平行的某种分布(高斯分布、多项式分布、etc)。
如果利用KDE这样的核密度估计算法,我们就可以去掉“朴素”的成分,使用更成熟的生成模型描述每一个类。虽然它还是贝叶斯分类,但是它不再NAIVE!

步骤如下:
-   通过标签将训练数据分割成为若干个集合
-   为每一个集合你和一个KDE模型来获得其生成模型,获得$P(x|y)$
-   根据没一个集合中的样本数量,计算先验概率$P(y)$
-   对于每一个未知数据,计算$P(x|y)P(y)$,并将其分配给概率最大的标签

(好神奇)

最后,这个自定义的KDE贝叶斯分类器对于sklearn手写数字的分类准确率可以达到96%,如果只是使用高斯朴素贝叶斯进行分类的话准确率只有85%(之前做过);

当然,我们的模型还存在改进空间,比如可以允许每一类的KDE带宽各不相同;

#%%

class KDEClassifier(BaseEstimator, ClassifierMixin):
    """
    bandwidth: 用于KDE模型的带宽
    kernel: 用于KDE模型的核函数名称
    """
    def __init__(self, bandwidth=1.0, kernel='gaussian'):
        self.bandwidth = bandwidth
        self.kernel = kernel
        self.classes_ = None
        self.models_ = None
        self.logpriors_ = None

    def fit(self, X, y):
        self.classes_ = np.sort(np.unique(y))  # 找到所有的类
        training_sets = [X[y == yi] for yi in self.classes_]
        # 为每一个类训练一个KDE,从样本中计算每一个类在D维空间中出现的概率密度
        self.models_ = [KernelDensity(bandwidth=self.bandwidth, kernel=self.kernel).fit(Xi) for Xi in training_sets]
        self.logpriors_ = [np.log(Xi.shape[0] / X.shape[0]) for Xi in training_sets]  # 根据样本数量计算每一个类的先验概率
        return self

    def predict_proba(self, X):
        logprobs = np.array([
            m.score_samples(X) for m in self.models_  # 计算输入样本作为每一个类在其所在位置出现的概率
        ]).T
        result = np.exp(logprobs + self.logpriors_)  # 概率的对数相加,等于概率相乘,乘以每一个类的先验概率
        return result / result.sum(axis=1, keepdims=True)

    def predict(self, X):
        return self.classes_[np.argmax(self.predict_proba(X), axis=1)]  # 找概率最大的那一个类

digits = load_digits()
bandwidths = 10 ** np.linspace(0, 2, 100)
grid = GridSearchCV(estimator=KDEClassifier(), param_grid={'bandwidth': bandwidths}, cv=5)
grid.fit(digits.data, digits.target)

#%%

print(f'自定义的KDE贝叶斯分类器在分类手写数字时的最佳准确率:{grid.best_score_}')
print(f'自定义的KDE贝叶斯分类器在分类手写数字时的最佳参数{grid.best_params_["bandwidth"]}')

plt.figure(figsize=(10, 10))
plt.semilogx(bandwidths, grid.cv_results_['mean_test_score'])
plt.vlines(x=grid.best_params_['bandwidth'], ymin=0, ymax=1, color='gray', linestyle='--')
plt.xlabel('KDE bandwidth')
plt.ylabel('模型交叉验证平均准确率')
plt.ylim(0, 1)
plt.title('KDE分类器交叉验证平均准确率与KDE带宽的关系')
  • 28
    点赞
  • 133
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: 核密度估计Kernel Density Estimation)是一种通过概率密度函数的方式对数据进行分布估计的非参数方法。该方法可以对数据进行平滑处理,并估计出数据的概率密度函数,从而更好地理解数据的分布情况。在核密度估计中,通过选取一个核函数来估计数据的概率密度函数,常用的核函数有高斯核函数、矩形核函数、三角核函数等。核密度估计在数据分析、信号处理、图像处理等领域有着广泛的应用。 ### 回答2: 核密度估计Kernel Density Estimation)是一种非参数统计学方法,用于估算概率密度函数(PDF)的形状和位置。 核密度估计的核心思想是通过在每个数据点周围放置核函数来创建平滑的密度估计。核函数是一个标准的概率密度函数,它在数据点周围生成一个密度窗口,并将每个数据点的贡献从它们的位置向密度窗口中积累。 当数据点越集中在一起,核函数的数量会增加,产生更平坦的密度窗口来避免过拟合。数据点距离越远,核函数的数量就会减少,产生更尖锐的密度窗口来捕捉较小的细节。 核密度估计还包含一个重要的参数,带宽(bandwidth),它控制了核函数窗口的大小。当带宽较小时,密度曲线会变得更窄,这可能会导致低偏差但高方差的估计。相反,当带宽较大时,密度曲线会变得更平坦,这可能会导致高偏差但低方差的估计。 核密度估计可以用于可视化和比较数据分布,或者作为其他统计方法的前提,例如分类和聚类问题。由于它是一种非参数方法,因此它不依赖于假设或先验分布,因此可以应用于多种数据集和统计问题中。 ### 回答3: Kernel density estimation是一种非参数统计方法,它可以用来估计概率密度函数。简单来说,它在数据点处放置一些核函数,然后将它们加起来得到密度估计。核函数可以是任何连续函数,且它必须是关于原点对称的非负函数,积分以后等于1。 Kernel density estimation的优点在于可以处理非常复杂的概率分布,而不需要假设一个具体的分布类型。这个方法有着非常广泛的应用,其中最常用的是在数据分析、数据挖掘、模式识别和信号处理等领域。 Kernel density estimation的实现过程可以分为三个步骤:核函数的选择、带宽的选择和估计密度函数。对于核函数的选择,通常选择高斯核函数或Epanechnikov核函数。高斯核函数的形式为$K(x)=\frac{1}{\sqrt{2\pi}}e^{-\frac{1}{2}x^2}$,Epanechnikov核函数的形式为$K(x)=\frac{3}{4}(1-x^2)$。带宽的选择通常使用交叉验证来确定。在估计密度函数时,可以通过对核函数进行平移和缩放得到不同的密度估计,然后将它们平均起来得到最终的估计结果。当数据点变得非常多的时候,随着核函数密度的增加,会导致估计结果的波动性也随之增加,可以通过增加带宽来缓解导致的问题。 总的来说,kernel density estimation是一种非常有用的统计方法,在许多实际应用中都有着广泛的应用,并且它的可解释性和伸缩性可以满足许多实际问题的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值