非参数估计——核密度估计(Parzen窗)

1279613编辑收藏

  核密度估计,或称Parzen窗,目标是利用离散的数据本身拟合出一个连续的分布,属于非参数估计。所谓非参数估计,即该估计并没有预设某种分布函数来对其参数进行求解或拟合,比如机器学习中K近邻法也是非参估计的一种。

1  直方图#

  首先从直方图切入。对于随机变量X的一组抽样,即使X的值是连续的,我们也可以划分出若干宽度相同的区间,统计这组样本在各个区间的频率,并画出直方图。下图是均值为0,方差为2.5的正态分布。从分布中分别抽样了100000和10000个样本:

  这里的直方图离散地取了21个相互无交集的区间:[x0.5,x+0.5),x=10,9,...,10,单边间隔h=0.5h>0在核函数估计中通常称作带宽,或窗口。每个长条的面积就是样本在这个区间内的频率。如果用频率当做概率,则面积除以区间宽度后的高,就是拟合出的在这个区间内的平均概率密度。因为这里取的区间宽度是1,所以高与面积在数值上相同,使得长条的顶端正好与密度函数曲线相契合。如果将区间中的x取成任意值,就可以拟合出实数域内的概率密度(其中Nx为样本xi[xh,x+h),i=1,...,N的样本数):

f^(x)=NxN12h

  这就已经是核函数估计的一种了。显然,抽样越多,这个平均概率密度能拟合得越好,正如蓝条中上方几乎都与曲线契合,而橙色则稂莠不齐。另外,如果抽样数N,对h取极限h0,拟合出的概率密度应该会更接近真实概率密度。但是,由于抽样的数量总是有限的,无限小的h将导致只有在抽样点处,才有频率1/N,而其它地方频率全为0,所以h不能无限小。相反,h太大的话又不能有效地将抽样量用起来。所以这两者之间应该有一个最优的h,能充分利用抽样来拟合概率密度曲线。容易推理出,h应该和抽样量N有关,而且应该与N成反比。

2  核函数估计#

  为了便于拓展,将拟合概率密度的式子进行变换:

f^(x)=Nx2hN=1hNi=1N{1/2xhxi<x+h0else

=1hNi=1N{1/2,1xixh<10,else

 =1hNi=1NK(xixh),whereK(x)={1/2,1x<10,else

  得到的K(x)就是uniform核函数(也又叫方形窗口函数),这是最简单最常用的核函数。形象地理解上式求和部分,就是样本出现在x邻域内部的加权频数(因为除以了2,所以所谓“加权”)。核函数有很多,常见的还有高斯核函数(高斯窗口函数),即:

K(x)=12πex2/2,<x<

  各种核函数如下图所示:

2.1  核函数的条件#

  并不是所有函数都能作为核函数的,因为f^(x)是概率密度,则它的积分应该为1,即:

Rf^(x)dx=R1hNi=1NK(xixh)dx=1hNi=1NK(xixh)dx

  令t=xixh

=1Ni=1NK(t)dt

=1Ni=1NK(t)dt=1

  因积分部分为定值,所以可得K(x)需要的条件是:

K(x)dx=1

  通常K(x)是偶函数,而且不能小于0,否则就不符合实际了。

2.2  带宽选择与核函数优劣#

  正如前面提到的,带宽h的大小关系到拟合的精度。对于方形核函数,N时,h通常取收敛速度小于1/N的值即可,如h=1/N。对于高斯核,有证明指出h=(4σ^53N)15时,有较优的拟合效果(σ^2是样本方差)。具体的带宽选择还有更深入的算法,具体问题还是要具体分析,就先不细究了。使用高斯核时,待拟合的概率密度应该近似于高斯分布那样连续平滑的分布,如果是像均匀分布那样有明显分块的分布,拟合的效果会很差。我认为原因应该是它将离得很远的样本也用于拟合,导致本该突兀的地方都被均匀化了。

  Epanechnikov在均方误差的意义下拟合效果是最好的。这也很符合直觉,越接近x的样本的权重本应该越高,而且超出带宽的样本权重直接为0也是符合常理的,它融合了均匀核与高斯核的优点。

2.3  多维情况#

  对于多维情况,假设随机变量Xm维(即m维向量),则拟合概率密度是m维的联合概率密度:

f^(x)=1hmNi=1NK(xixh)

  其中的K(x)也变成了m维的标准联合概率密度。另外,既然1Ni=1NK(xixh)代表的是概率,m维的概率密度自然是概率除以hm而不是h

2.4  实验拟合情况#

  分别取带宽h=0.1,0.3,0.7,1.4时,使用三种核函数对分布pX(x)=x+550,x[5,5]进行拟合:

   抽样数量N=100000,可以看出随着h增大,偏差增大,而h太小时,方差变大了。可以发现高斯核的拟合从来都是光滑的(方差比较小),这样看起来似乎在h取得很小时,高斯核是比较好的核函数。而当h因为抽样较少而不得不取大时,另外两个核函数则更能勾勒出待拟合函数的轮廓。

  以下是实验代码:

复制代码
import numpy as np
import matplotlib.pyplot as plt
from scipy.special import comb,perm

sample_num = 100000
#获取要拟合的分布抽样并排序 Y = 5-10*(1-X)**0.5 
ran = np.random.rand(sample_num)
ran = 5-10*(1-ran)**0.5 
ran = np.sort(ran) 

#高斯核
def ker_gass(x0):
    return (1/(2*np.pi)**0.5)*np.e**-(x0**2/2)
#Epanechnikov核
def ker_Epanechnikov(x0):
    return 3/4*(1-x0**2)

#拟合概率密度函数
def fitting_proba_density(X,h,way): 
    if way == 1:    #使用均匀核
        i_X = 0
        begin_ran = 0
        end_ran = 0
        sum0 = np.zeros(len(X)+1)
        while i_X < len(X):  
            while begin_ran < sample_num:
                if X[i_X] - h > ran[begin_ran]:
                    sum0[i_X] -= 0.5
                    begin_ran+=1 
                else:
                    break
            while end_ran < sample_num:
                if X[i_X] + h >= ran[end_ran]:
                    sum0[i_X]+=0.5
                    end_ran+=1
                else:
                    break
            sum0[i_X+1] = sum0[i_X] 
            i_X+=1
        return sum0[0:-1]/h/sample_num 
    elif way == 2:    #使用高斯核 
        sum0 = np.zeros(len(X))
        for i in range(sample_num):
            sum0 += ker_gass((ran[i]-X)/h)
        return sum0/h/sample_num
    else:    #使用Epanechnikov核 
        i_X = 0
        begin_ran = 0
        end_ran = 0
        sum0 = np.zeros(len(X))
        while i_X < len(X):  
            while begin_ran < sample_num:
                if X[i_X] - h > ran[begin_ran]: 
                    begin_ran+=1 
                else:
                    break
            while end_ran < sample_num:
                if X[i_X] + h >= ran[end_ran]: 
                    end_ran+=1
                else:
                    break
            i = begin_ran
            while i < end_ran:
                sum0[i_X] += ker_Epanechnikov((ran[i]-X[i_X])/h)
                i+=1
            i_X+=1
        return sum0/h/sample_num 

#画出拟合概率密度
def paint_(a):
    X = np.linspace(-10,10,500)
    j=0
    for h in a: 
        j+=1
        ax = plt.subplot(2,2,j)
        ax.set_title('h='+ str(h))#设置子图

        X0 = np.linspace(-5,5,10)
        Y0 = (-X0+5)/50
        plt.plot(X0,Y0,label = 'Probability density')#分布密度函数 

        Y = fitting_proba_density(X,h,1)#均匀核
        ax.plot(X,Y,label = 'Uniform kernel') 
        Y = fitting_proba_density(X,h,2)#高斯核
        ax.plot(X,Y,label = 'Gassian kernel')
        Y = fitting_proba_density(X,h,3)#Epanechnikov核
        ax.plot(X,Y,label = 'Epanechnikov kernel')
        ax.legend()
paint_([0.1,0.3,0.7,1.4])
 
#图像参数
plt.xlim(-10,10)
plt.show()
复制代码

 

编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
很高兴能帮到你~
点赞
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示