計算(分析\畫出)給定數據的分佈(概率密度函數)

目錄

一、背景知識

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)爲:
f(x)=\frac{1}{nh}\sum_{j=1}^{n}K(\frac{x-a_{j}}{h})
K()是核函數(非負、積分爲1,符合概率密度性質,並且均值爲0)
h>0爲一個平滑參數,稱作帶寬(bandwidth),也看到有人叫窗口。
核密度函數的原理比較簡單:在我們知道某一事物的概率分佈的情況下,如果某一個數在觀察中出現了,我們可以認爲這個數的概率密度很大,和這個數比較近的數的概率密度也會比較大,而那些離這個數遠的數的概率密度會比較小。
基於這種想法,針對觀察中的第一個數,我們可以用K去擬合我們想象中的那個遠小近大概率密度。對每一個觀察數擬合出的多個概率密度分佈函數,取平均。如果某些數是比較重要的,則可以取加權平均。需要說明的一點是,核密度的估計並不是找到真正的分佈函數。
如果使用高斯核函數(標準正態分佈):
(1)K(x)=\frac{1}{\sqrt{2\pi}}\exp(-\frac{x^{2}}{2})
那麼估計的密度函數爲:(下面式子去掉求和符號以及n之後,就和正態分佈的一般形式一樣)
(2)f(x)=\frac{1}{\sqrt{2\pi}nh}\sum_{j=1}^{n}\exp(-\frac{(x-a_{j})^{2}}{2h^{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'表示檢驗給定的數據是否服從正態分佈



 

發佈了45 篇原創文章 · 獲贊 88 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章