计算(分析\画出)给定数据的分布(概率密度函数)

目录

一、背景知识

1.累积分布函数

2.概率密度函数

3.核密度估计

二、画出一组数据的分布(概率密度函数)

1.数据的频率分布直方图

2.画出给定数据的频率分布直方图

3.画出给定数据的概率密度函数

做ML时,往往需要先分析手头的数据,比如数据集中某个特征的分布特性。很多时候,拿到的数据分布不那么尽如人意,比如长尾分布,这时就需要做数据变换(比如box-cox变换),来得到分布特性好的数据(比如正态分布)。
为什么很多模型要假设变量服从正太分布?参考这里
 

一、背景知识

1.累积分布函数

累积分布函数(Cumulative Distribution Function),又叫分布函数,是概率密度函数的积分,能完整描述一个实随机变量X的概率分布。
《计算(分析\画出)给定数据的分布(概率密度函数)》
参考百度百科

2.概率密度函数

是累积分布函数的导数:
《计算(分析\画出)给定数据的分布(概率密度函数)》
▲概率密度等于一段区间(事件的取值范围)的概率除以该段区间的长度
▲概率密度函数在R上的积分为1
▲几个性质
    《计算(分析\画出)给定数据的分布(概率密度函数)》
    《计算(分析\画出)给定数据的分布(概率密度函数)》
    《计算(分析\画出)给定数据的分布(概率密度函数)》

3.核密度估计

核密度估计是在概率论中用来估计未知的概率密度函数,属于非参数检验方法之一。
假设有n个数据a1,a2,…an,互相独立同分布,设其概率密度函数为f(x),则通过核密度估计出来的f(x)为:
《计算(分析\画出)给定数据的分布(概率密度函数)》
K()是核函数(非负、积分为1,符合概率密度性质,并且均值为0)
h>0为一个平滑参数,称作带宽(bandwidth),也看到有人叫窗口。
核密度函数的原理比较简单:在我们知道某一事物的概率分布的情况下,如果某一个数在观察中出现了,我们可以认为这个数的概率密度很大,和这个数比较近的数的概率密度也会比较大,而那些离这个数远的数的概率密度会比较小。
基于这种想法,针对观察中的第一个数,我们可以用K去拟合我们想象中的那个远小近大概率密度。对每一个观察数拟合出的多个概率密度分布函数,取平均。如果某些数是比较重要的,则可以取加权平均。需要说明的一点是,核密度的估计并不是找到真正的分布函数。
如果使用高斯核函数(标准正态分布):
(1)《计算(分析\画出)给定数据的分布(概率密度函数)》
那么估计的密度函数为:(下面式子去掉求和符号以及n之后,就和正态分布的一般形式一样)
(2)《计算(分析\画出)给定数据的分布(概率密度函数)》
以上参考这里
总结一句:核密度估计其实就是通过核函数(如高斯)将每个数据点的数据+带宽当作核函数的参数,得到n个核函数,再线性叠加取平均就形成了核密度的估计函数(参考这里
计算时,给定核函数,只需要一组数据an和带宽h
 

二、画出一组数据的分布(概率密度函数)

1.数据的频率分布直方图

    1.1 定义可查看百度百科,具体例子可参考这里
    1.2 各组频率之和的值为1,在频率分布直方图中表现为所有矩形的面积之和等于1

2.画出给定数据的频率分布直方图

    2.1找到最大值max 最小值min, 将区间[min, max]等分, 得到几个bin(因为是等分, 所以bin的宽度是一样的)
    2.2根据点的值大小, 统计落在各个bin中的点的个数, 即频数
    2.3计算各个bin的频率=频数/全部数据点的个数
    2.4画直方图, 其中bin的高度=频率/bin的宽度
例子:

import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

x = np.arange(10, step=1)
n = len(x)
print('x= ',x)
nbins = 3
freq, bins = np.histogram(x, bins=nbins)
print('bin划分:{}, 分成{}个bin'.format(bins, len(bins)-1))
print('各个bin的频数', freq)
freq_rate = freq / n
print('各个bin的频率', freq_rate)
bin_w = bins[1]-bins[0]
bin_h = freq_rate / bin_w
print('各个bin的高度', bin_h)
ax= sns.distplot(x, bins=nbins,
                 hist=True, # Whether to plot a (normed) histogram.
                 kde=False, 
                 norm_hist=True, # norm_hist = norm_hist or kde or (fit is not None); 如果为False且kde=False, 则高度为频数
#                 kde_kws={"label": "density_est_by_sns",
#                          "bw": bin_w}
                 )
ax.grid(True)
ax.set_yticks(np.arange(0.16, step=0.01))

下面是结果图
《计算(分析\画出)给定数据的分布(概率密度函数)》
x是一组数据,分成了[0,3), [3,6), [6,9)(第三个后面是开区间闭区间?),带宽h=3
《计算(分析\画出)给定数据的分布(概率密度函数)》

3.画出给定数据的概率密度函数

假设核函数使用高斯核函数(公式(1)),则密度函数的估计式子就是(公式(2)).
带宽h就是上面频率分布直方图中每个bin的宽度: bin_w
那就可以手动算出这个密度函数了(在density_est中实现)
此外,seaborn的distplot可以直接画出概率密度函数(kde=True, kde_kws是相关的参数)
并且,distplot其实是调用了kdeplot来画图
下面是代码:

# -*- coding: utf-8 -*-
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt


x = np.arange(10, step=1)
n = len(x)
print('x= ',x)
nbins = 3
freq, bins = np.histogram(x, bins=nbins)
print('bin划分:{}, 分成{}个bin'.format(bins, len(bins)-1))
print('各个bin的频数', freq)
freq_rate = freq / n
print('各个bin的频率', freq_rate)
bin_w = bins[1]-bins[0]
bin_h = freq_rate / bin_w
print('各个bin的高度', bin_h)
# ==================1. 通过distplot
ax= sns.distplot(x, bins=nbins,
                 hist=True, # Whether to plot a (normed) histogram.
                 kde=True, 
                 norm_hist=True, # norm_hist = norm_hist or kde or (fit is not None); 如果为False且kde=False, 则高度为频数
                 kde_kws={"label": "density_est_by_sns.distplot",
                          "bw": bin_w # 带宽h, 确保和density_est的h一样, 和kdeplot的bw一样
                          }
                 )
ax.grid(True)
ax.set_yticks(np.arange(0.16, step=0.01))


# ==================2. 通过手动计算density_est
def density_est(x, xs, h):
    """
    给定一组数据xs和带宽h, 计算概率密度函数,
    x: 是f(x)的自变量
    """
    f = 0
    n=len(xs) # 观测点的个数
    a = 1/(np.sqrt(2*np.pi)*n*h)
    for xi in xs:
        f = f + np.exp(-(x-xi)**2/(2*(h**2)))
    f = a*f
    return f
dots = np.linspace(x.min()-bin_w*n*0.5, x.max()+bin_w*n*0.5, num=1000)
ax.plot(dots, density_est(dots, x, h=bin_w), c='r', label='density_est_manual')
ax.legend(loc='best')


# ==================3. 通过kdeplot
sns.kdeplot(x, bw=bin_w, ax=ax, label='density_est_by_sns.kdeplot')

下面是结果图
《计算(分析\画出)给定数据的分布(概率密度函数)》
可以看出,三种方法画出来的曲线完全重合

最后,整理一下,计算给定数据的概率密度函数(概率分布),需要1数据2核函数3带宽。

扩展
    1.qq图,全称quantile-quantile plot,用来 检验一组数据是否服从某一分布 或者 两个分布是否服从同一分布,参考这里这里
    2.scipy的stats.probplot可以画qq图,参考这里,默认参数dist=’norm’表示检验给定的数据是否服从正态分布

 

    原文作者:五四三两幺-发射!
    原文地址: https://blog.csdn.net/ying86615791/article/details/103391083
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞