核密度估计

---PRML

假设观测服从D维空间的某个未知的概率密度分布p(x)。我们把这个D维空间选择成欧⼏⾥得空间,并且我们想估计p(x)的值。根据我们之前对于局部性的讨论,让我们考虑包 含x的某个⼩区域R。这个区域的概率质量为

现在假设收集了服从p(x)的N次观测。由于每个数据点都有一个落在区域R中的概率P,显然位于区域R内部的数据点的总数K将服从二项分布

根据二项分布的期望[  E(x)=N*μ ]和方差[  var(m)=N*μ(1-μ)  ] ,则落在区域内部的数据点的平均比例为E(K/N)=P;类似的以此为均值的概率分布的方差为var(K/N)=P(1-P)/N.对于大的N值,这个分布将会在均值附近产生尖峰,且

另外,如果假设区域R足够小,使得在该区域内的概率密度p(x)大致为常数,则

其中V是区域R的体积。则结合上述两式,得到概率密度的估计,

注意,公式的成⽴依赖于两个相互⽭盾的假设,即区域R要⾜够⼩,使得这个区域内 的概率密度近似为常数,但是也要⾜够⼤,使得落在这个区域内的数据点的数量K能够⾜够让 ⼆项分布达到尖峰。

我们有两种⽅式利⽤上式的结果。我们可以固定K然后从数据中确定V的值,这就是K近邻⽅法

我们还可以固定V然后从数据中确定K,这就是核⽅法。在极限N →∞的情况 下,如果V随着N⽽合适地收缩,并且K随着N增⼤,那么可以证明K近邻概率密度估计和核⽅法概率密度估计都会收敛到真实的概率密度(Duda and Hart, 1973)

1.核方法。

⾸先,我们把区域R取成以x为中⼼的⼩超⽴⽅体,我们想确定概率密度。为了统计落在该区域的数据点的数量K,定义下面函数比较方便

这表⽰⼀个以原点为中⼼的单位⽴⽅体。函数k(u)是核函数(kernel function)的⼀个例⼦, 在这个问题中也被称为Parzen窗(Parzen window)。根据公式(2.247),如果数据点xn位于 以x为中⼼的边长为h的⽴⽅体中,那么量的值等于1,否则它的值为0。于是,位于这个⽴⽅体内的数据点的总数为

把这个表达式代⼊公式(2.246),可以得到点x处的概率密度估计

这里使⽤了D维边长为h的⽴⽅体的体积公式V = h^D。使⽤函数k(u)的对称性,我们现在可以重新表述这个⽅程。之前我们把这个函数表述为以X为中⼼的⼀个⽴⽅体,但是现在我们把这个函数表述为以N个数据点Xn为中⼼的N个⽴⽅体.

核密度估计(2.249)有⼀个问题,这个问题也是直⽅图⽅法具有的问题中的⼀个。这个问题就是⼈为带来的⾮连续性。在之前所述的核密度估计⽅法中就是⽴⽅体的边界。如果我们选 择⼀个平滑的核函数,那么我们就可以得到⼀个更加光滑的模型。⼀个常见的选择是⾼斯核函 数。使⽤⾼斯核函数,可以得到下⾯的核概率密度模型,

其中h表⽰⾼斯分布的标准差。因此我们的概率密度模型可以通过这种⽅式获得:令每个数据点都服从⾼斯分布,然后把数据集⾥的每个数据点的贡献相加,之后除以N,使得概率密度正确地被归⼀化。参数h对平滑参数起着重要的作⽤。⼩的h会造成模型对噪声 过于敏感,⽽⼤的h会造成过度平滑,因此要进⾏⼀个折中。对h的优化是⼀个模 型复杂度的问题,类似于直⽅图概率密度估计中对于箱⼦狂赌的选择,也类似于曲线拟合问题 中的多项式阶数。

我们可以任意选择公式(2.249)中的核函数,只要满⾜下⾯的条件

公式(2.249)给出的概率密 度模型被称为核密度估计,或者Parzen估计。它由⼀个很⼤的优点,即不需要进⾏“训练”阶段的 计算,因为“训练”阶段只需要存储训练集即可。然⽽,这也是⼀个巨⼤的缺点,因为估计概率密度的计算代价随着数据集的规模线性增长。

2. 近邻方法

核⽅法进⾏概率密度估计的⼀个困难之处是控制核宽度的参数h对于所有的核都是固定的。

在⾼数据密度的区域,⼤的h值可能会造成过度平滑,并且破坏了本应从数据中提取出的结构。 但是,减⼩h的值可能导致数据空间中低密度区域估计的噪声。因此,h的最优选择可能依赖于数据空间的位置。这个问题可以通过概率密度的近邻⽅法解决。 因此我们回到局部概率密度估计的⼀般结果(2.246)。与之前固定V然后从数据中确定K的值不同,我们考虑固定K的值然后使⽤数据来确定合适的V值。为了完成这⼀点,我们考虑⼀个以x为中⼼的⼩球体,然后我们想估计概率密度p(x)。并且,我们允许球体的半径可以⾃由增长,直到它精确地包含K个数据点。这样,概率密度p(x)的估计就由公式(2.246)给出,其 中V等于最终球体的体积。这种⽅法被称为K近邻⽅法。图2.26给出了对于不同参数K,使⽤与图2.25相同的数据集,K近邻⽅法的结果。我们看到K的值现在控制了光滑的程度,并且与之前⼀样,K的最有选择既不能过⼤也不能过⼩。

注意,由K近邻⽅法得到的模型不是真实的概率密度模型,因为它在整个空间的积分是发散的。

说明:概率密度估计的K近邻⽅法如何推⼴到分类问题

把K近邻概率密度估计⽅法分别应⽤到每个独⽴的类别中,然后使⽤贝叶斯定理。假设有一个数据集,其中个数据点属于类别,数据点总数为N,因此。如果要对一个新的数据点x进行分类,那么可以画一个以x为中心的球体,这个球体精确地包含K个数据点(无论属于哪个类别)。假设球体的体积为V,并且包含来自类别数据点。这样公式(2.246)提供了与每个类别关联的⼀个概率密度的估计

使⽤贝叶斯定理将公式(2.253)、公式(2.254)和公式(2.255)结合起来,可以得到类别的后验概率

如果我们想最⼩化错误分类的概率,那么我们可以把测试点x分配给有着最⼤后验概率的类别,这对应于最⼤的。因此为了分类⼀个新的数据点,我们从训练数据中选择K个最近的数据点,然后把新的数据点分配为这个集合中数量最多的点的类别。K = 1的特例被称为最近邻 规则(nearest-neighbour rule),因为测试点简单地被分类为训练数据集⾥距离最近的数据点的 类别。图2.27给出了这些概念的说明。

在实际应用中,K 值一般选择一个较小的数值,通常采用交叉验证的方法来选择最优的 K 值。随着训练实例数目趋向于无穷和 K=1 时,误差率不会超过贝叶斯误差率的2倍,如果K也趋向于无穷,则误差率趋向于贝叶斯误差率

距离度量一般采用 Lp 距离,当p=2时,即为欧氏距离,在度量之前,应该将每个属性的值规范化,这样有助于防止具有较大初始值域的属性比具有较小初始值域的属性的权重过大

KNN算法不仅可以用于分类,还可以用于回归。通过找出一个样本的k个最近邻居,将这些邻居的属性的平均值赋给该样本,就可以得到该样本的属性。更有用的方法是将不同距离的邻居对该样本产生的影响给予不同的权值(weight),如权值与距离成比。该算法在分类时有个主要的不足是,当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。 该算法只计算“最近的”邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。无论怎样,数量并不能影响运行结果。可以采用权值的方法(和该样本距离小的邻居权值大)来改进。

在图2.28中,⽯油数据集在不同的K值下的K近邻算法的结果。正如我们期望的那样,我们看到K控制了光滑的程度,即⼩的K值会使得每个类别有许多⼩区域,⽽⼤的K值会产⽣数量较少⾯积较⼤的区域。

最近邻(K = 1)分类器的⼀个有趣的性质是在极限N →∞的情况下,错误率不会超过最优分类器(即使⽤真实概率分布的分类器)可以达到的最⼩错误率的⼆倍(Cover and Hart,1967)。

K近邻⽅法和核密度估计⽅法都需要存储整个训练数据。如果数据集很⼤的话,这会造成很⼤的计算代价。通过建⽴⼀个基于树的搜索结构,使得(近似) 近邻可以⾼效地被找到,⽽不必遍历整个数据集,这种计算代价可以被抵消,代价就是需要进 ⾏⼀次性的额外计算量。

下面是KNN的python实现代码:

#根据百度百家号电影分类的例子:https://baijiahao.baidu.com/s?id=1607065207237272861&wfr=spider&for=pc
#电影[武打次数,接吻次数]进行分类,即接吻次数多简单的划分为爱情片。。。
#coding:utf-8
import scrapy
import xlwt, lxml
import re, json
import matplotlib.pyplot as plt
import numpy as np
import pylab
from scipy import linalg
#KNN--k近邻算法,主要适用于标称型和数值型
#使用numpy可快速地进行多维矩阵的欧几里得距离的快速计算。
def create_dataset():
 
    #电影[武打次数,接吻次数]进行分类,即接吻次数多简单的划分为爱情片。。。
    group=np.array([[3,104],[2,100],[1,81],[90,5],[99,7],[110,7]])
    labels=['A','A','A','B','B','B']
    return group,labels
def classifier(new_x,dataset,labels,k):#k近邻分类:(测试集,训练集,分类标签,K值)
    dataset_size=dataset.shape[0]#得到训练集的维度
    print(dataset_size)
    diff_matrix=np.tile(new_x,(dataset_size,1))-dataset#将测试集拓展为维数与训练集相同的矩阵并做差
    print(diff_matrix)
    euclid_distance=((diff_matrix**2).sum(axis=1))**0.5#计算欧氏距离
    print(euclid_distance)#[ 15.65247584  12.80624847  12.72792206 116.7261753  121.69634341 129.95768542]
    sort_ed_idx=euclid_distance.argsort()#对距离对应的索引进行排序(升序)
    print(sort_ed_idx)#[2 1 0 3 4 5]
    class_count={}
    for i in range(k):#统计以new_x为中心距离最近的K个数据点中属于(标签)类最多的点【那么new_x也属于该(标签)类】
        label_i=labels[sort_ed_idx[i]]#得到距离最近的数据点所属标签(类)
        class_count[label_i]=class_count.setdefault(label_i,0)+1#统计个数【以元组形式表式(label_i,cnt)】
    sort_class_count=sorted(class_count.items(),reverse=True)#降序排列
    # print(sort_class_count)
    return sort_class_count[0][0]#得到所属标签(类)

if __name__ == '__main__':
        test=[10,90]
        group,labels=create_dataset()
        result=classifier(test,group,labels,3)
        print('test所属类别为:%s'%result)

 

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值