正态(高斯)分布在机器学习中起着核心作用。在线性回归模型中,假设随机误差具有等方差并服从正态分布。如果变量服从正态分布,则更容易建立理论结果。统计领域的很大一部分研究都假设数据是正态分布的,所以如果我们的数据是正态分布的,那么我们就能得到更好的结果。但是一般来说,我们的数据并不是正态分布的,所以如果我们能够将这些数据转化为正态分布,对于我们建立模型会有很大的帮助。standard_normal=np.random.normal(0,1,size=1_000_000)fontdict={'family':'serif','color':'darkgreen','size':16}fig,axs=plt.subplots(1,1,figsize=(8,8))axs.hist(standard_normal,bins=1000,density=True,fc=(0,0,1,0.4))axs.set_title('标准正态分布',fontdict=fontdict,fontweight='bold',pad=12)axs.set_xlabel('X',fontdict=fontdict,fontweight='normal',labelpad=12)axs.set_ylabel('Density',fontdict=fontdict,fontweight='normal',labelpad=12)axs.grid()如果你正在处理密度(近似)线性下降的特征(见下图)。x=np.linspace(0,1,1001)sample=(3-np.sqrt(9-8*np.random.uniform(0,1,1_000_000)))/2fontdict={'family':'serif','color':'darkgreen','size':16}fig,axs=plt.subplots(1,1,figsize=(8,8))axs.hist(sample,bins=1000,density=True,fc=(0,0,1,0.4))axs.scatter(x,np.full_like(x,0.01),c=x,cmap=cmap)axs.set_title('原始特征分布',fontdict=fontdict,fontweight='粗体',pad=12)axs.set_xlabel('X',fontdict=fontdict,fontweight='normal',labelpad=12)axs.set_ylabel('密度',fontdict=fontdict,fontweight='normal',labelpad=12)axs.grid()把这个特征转换成钟形分布的变量,可能没那么简单。如果我用某种变换把左边密度最高的那一端放在中心,那么中心两边剩下的点呢??如果变换是将点从中间的[0,1]向右移动到均值的任一侧(N(0,1)=0)那么它本质上是一个非单调变换,这不是很好,因为那么,变换后的特征值就没有意义了。虽然我们能够得到钟形分布,但它对变换后的值没有任何意义,排序也不再保留(请参见下面图3中变换后的特征值的散点图)。log_transform=lambdaar:np.multiply(1.6*np.log10(ar+1e-8),np.random.choice((-1,1),size=ar.size)fontdict={'family':'serif','color':'darkgreen','size':16}fig,axs=plt.subplots(1,1,figsize=(8,8))axs.hist(standard_normal,bins=1_000,density=True,fc=(0,0,1,0.4),label='标准正态')axs.hist(log_transform(sample),bins=1_000,density=True,fc=(1,0,0,0.4),label='对数变换')axs.scatter(log_transform(x),np.full_like(x,3e-3),c=x,cmap=cmap)axs.set_xlim(-5,5)axs.set_title('对数变换',fontdict=fontdict,fontweight='bold',pad=12)axs.set_xlabel('$\pm$1.6log(X)',fontdict=fontdict,fontweight='normal',labelpad=12)*axs.set_ylabel('density',fontdict=fontdict,fontweight='normal',labelpad=12)axs.legend()axs.grid()特征的密度是单调递减的。目标是使用范围(-∞,∞)不同点周围的[0,1]范围与压缩不同,变换后空间中每个点的密度应由N(0,1)给出。那么你可以尝试使用其他方法吗?首先看一下特征的原始CDF函数:如果我们确保转换函数将原始分布的(i-1)??和i??百分位数之间的点映射到N(0,1)会怎么样?g是我们要寻找的变换,Φ是N(0,1)的CDF。但这可能只是这种方法对最终目标的延伸。因为我们的方法不应该局限于由百分位数定义的区间,而是想要一个满足上面原始CDF公式中每个区间的函数。这将得出以下公式如果您熟悉概率论,请回想一下概率是由其分布函数表征的(JeanJacod和PhilipProtter的ProbabilityEssentials中的定理7.1)。我将自己限制在单调递增函数的范围内。单调递增函数的一组约束假设,如果我能找到一个函数,使转换特征的CDF等于N(0,1)的CDF,那岂不是很好。这与上式中的单调递增约束一起导致以下公式。将函数g变换为Φ的反函数和F的复合函数,下面看一下结果。我们使用上面总结的结果对特征进行转向,使它们具有标准正态分布。fontdict={'family':'serif','color':'darkgreen','size':16}fig,axs=plt.subplots(1,1,figsize=(8,8))axs.hist(standard_normal,bins=1_000,density=True,fc=(0,0,1,0.4),label='StandardNormal')axs.hist(scipy.stats.norm.ppf(1.5*sample-0.5*(sample**2)),bins=1000,density=True,fc=(1,0,0,0.4),label='方程式4变换')axs.scatter(norm.ppf(1.5*x-0.5*(x**2)),np.full_like(x,3e-3),c=x,cmap=cmap)axs.set_xlim(-5,5)axs.set_title("变换特征密度",fontdict=fontdict,fontweight='bold',pad=12)axs.set_xlabel('$\Phi^{-1}(F$(X))',fontdict=fontdict,fontweight='normal',labelpad=12)axs.set_ylabel('密度',fontdict=fontdict,fontweight='normal',labelpad=12)axs.legend()axs.grid()任何分布(只要是连续分布函数)都可以使用这个方法。但在使用它之前,您仍然需要查看它是否对您的用例有意义。fontdict={'family':'serif','color':'darkgreen','size':16}fig,axs=plt.subplots(1,1,figsize=(8,8))axs.scatter(x,norm.ppf(1.5*x-0.5*(x**2)),c=x,cmap=cmap)axs.set_xlim(0,1)axs.set_title('转换',fontdict=fontdict,fontweight='bold',pad=12)axs.set_xlabel('X',fontdict=fontdict,fontweight='normal',labelpad=12)axs.set_ylabel('$\Phi^{-1}(F$(X))',fontdict=fontdict,fontweight='normal',labelpad=12)axs.grid()我们的变换函数看起来是这样的,这个过程给出了图5所示的变换。需要注意的是当取值时输出波动较大该特征的值接近于0或接近1,但该值接近0.5时输出波动较小。如果不这样做,会给模型提供错误的特征解释,可能会损害其性能。
