單變量的樣本分佈檢驗(python3)

import numpy as np               #科學計算基礎庫,多維數組對象ndarray
import pandas as pd              #數據處理庫,DataFrame(二維數組)
import matplotlib as mpl         #畫圖基礎庫
import matplotlib.pyplot as plt  #最常用的繪圖庫
from scipy import stats          #scipy庫的stats模塊

mpl.rcParams["font.family"]="SimHei"  #使用支持的黑體中文字體
mpl.rcParams["axes.unicode_minus"]=False # 用來正常顯示負號  "-"
plt.rcParams['font.sans-serif']=['SimHei'] # 用來正常顯示中文標籤
# % matplotlib inline  #jupyter中用於直接嵌入圖表,不用plt.show()
import warnings
warnings.filterwarnings("ignore") #用於排除警告
 
#用於顯示使用庫的版本
print("numpy_" + np.__version__)
print("pandas_" + pd.__version__)
print("matplotlib_"+ mpl.__version__)
numpy_1.17.4
pandas_0.23.4
matplotlib_2.2.3

一、單變量的樣本分佈檢驗

問題: 如何檢驗數據的抽樣的某個維度是符合某種分佈的?譬如,是否是正態分佈,或,是否與總體的分佈相同等?

1.1.用數字特徵檢驗

分佈的數字特徵是否與理論的數字特徵一致?

例:t分佈序列數字特徵檢驗

# 例:生成一個t分佈序列
import numpy as np 
from scipy import stats   #scipy庫的stats模塊
np.random.seed(10) # 先生成一個種子生成器,以後生成的隨機數就是一定的,參數爲任意數字
x = stats.t.rvs(10, size=10000) #生成服從t分佈,自由度爲10的10000個隨機數(rvs生成隨機數)
#display(x)
#計算其數字特徵
print(np.min(x), np.max(x),np.mean(x),np.median(x),np.var(x),np.std(x),stats.mode(x)) 
#最小值,最大值,均值,中位數,方差,標準差,衆數及個數

display(stats.describe(x)) #使用stats.describe()做統計
n, (smin, smax), sm, sv, ss, sk = stats.describe(x)
print( n, (smin, smax), sm, sv, ss, sk) #數量,(最小值,最大值),均值,方差,偏度,峯度
-11.589863255656732 5.703833815270785 0.007167368275245448 0.011582997970647449 1.2174942741284087 1.1034012298925575 ModeResult(mode=array([-11.58986326]), count=array([1]))

DescribeResult(nobs=10000, minmax=(-11.589863255656732, 5.703833815270785), mean=0.007167368275245448, variance=1.2176160357319818, skewness=-0.1220063780573783, kurtosis=1.8544784100842557)

10000 (-11.589863255656732, 5.703833815270785) 0.007167368275245448 1.2176160357319818 -0.1220063780573783 1.8544784100842557
#計算理論數字特徵---發現隨機樣本和理論還是存在差異的
m, v, s, k = stats.t.stats(10, moments='mvsk')
print(m,v,s,k)#m均值,v方差,s偏度,k峯度
0.0 1.25 0.0 1.0

1.2. T-test(嚴格的檢驗)

t-test檢驗是檢驗一個或兩個樣本之間的均值是否有明顯的差別,也就是檢驗單變量對因變量的影響。

stats.ttest_1samp(x,m) # 用t-test檢驗來檢驗樣本數據均值和理論均值差異性檢驗。一組數據與指定均值比較。

stats.ttest_ind(rvs1,rvs2) # 對兩個樣本進行t檢驗

#結果分析:p值越小我們拒絕原假設(樣本是t分佈)

#比較兩個樣本(比較兩組均值)

帶參數的假設檢驗

# 單樣本檢驗
import numpy as np
from scipy import stats

rvs1=stats.norm.rvs(loc=5,scale=10,size=50000) #均值爲5,標準差爲10的正態分佈,隨機隨機生成50000個樣本
display(stats.describe(rvs1)) #輸出統計特徵值
display(stats.ttest_1samp(rvs1,[1,5])) #單樣本與均值=1比較,拒絕原假設(均值存在差異),與均值=5比較,接受原假設(均值不存在差異)
display(stats.ttest_1samp(rvs1,3)) #樣本與均值=3比較,p=0.0,拒絕原假設(均值存在差異)
DescribeResult(nobs=50000, minmax=(-36.99682593051555, 46.54608091676229), mean=4.9810497540176195, variance=100.12070769576394, skewness=0.010258428597114096, kurtosis=0.006975059803436157)

Ttest_1sampResult(statistic=array([88.96530093, -0.42348487]), pvalue=array([0.        , 0.67194336]))

Ttest_1sampResult(statistic=44.27090802960711, pvalue=0.0)
# 兩個樣本的檢驗
import numpy as np
from scipy import stats

rvs1=stats.norm.rvs(loc=5,scale=10,size=50000) #均值爲5,標準差爲10的正態分佈,隨機隨機生成50000個樣本
display(stats.describe(rvs1)) #輸出統計特徵值
rvs2=stats.norm.rvs(loc=5,scale=10,size=50000)
display(stats.ttest_ind(rvs1,rvs2))  #對兩個樣本進行t檢驗,pvalue即p值,接受原假設,即樣本均值和理論均值不存在差異
rvs3=stats.norm.rvs(loc=8,scale=10,size=50000)
display(stats.ttest_ind(rvs1,rvs3)) #p=0.0,拒絕原假設,即樣本均值和理論均值存在差異
DescribeResult(nobs=50000, minmax=(-34.84341762895822, 48.77390861744411), mean=4.913290841946327, variance=99.5744094623477, skewness=-0.0034722709934522345, kurtosis=0.018126574218927605)

Ttest_indResult(statistic=-1.7861203119186366, pvalue=0.07408280895829028)

Ttest_indResult(statistic=-48.627977359124166, pvalue=0.0)

1.3. K-S test (嚴格的檢驗)

stats.kstest(x,‘t’,(10,)) #檢驗樣本數據x是否是自由度爲10的t分佈

K-S test 還可以檢驗其他分佈:正態分佈…

stats.kstest(x,‘norm’,(x.mean(),x.std())) #對x進行檢驗。正態分佈有兩個參數-均值和期望;分別樣本的均值和方差來估計。

使用K-S test對x進行t分佈和正態分佈檢驗時,如果都不能拒絕(因爲正態分佈和t分佈在中間的時候非常像,但是尾部有顯著差別)。
這時候就用卡方檢驗…

#如果比較兩組分佈

Kolmogorov-Smirnov雙樣本檢測ks_2samp

stats.ks_2samp(rvs1,rvs2)

stats.ks_2samp(rvs1,rvs3)

import numpy as np
from scipy import stats

x1 = stats.t.rvs(10, size=100)
x2 = stats.norm.rvs(loc=10,scale=10,size=1000)

display(stats.kstest(x1,'t',(10,))) #x1是否服從自由度爲10的t分佈,p>0.05接受原假設,服從t分佈
display(stats.kstest(x1,'norm',(x1.mean(),x1.std()))) #x1是否服從正態分佈,p>0.05接受原假設,服從正態分佈
#使用K-S test對x進行t分佈和正態分佈檢驗時,如果都不能拒絕(因爲正態分佈和t分佈在中間的時候非常像,但是尾部有顯著差別)。 這時候就用卡方檢驗...

display(stats.kstest(x2,'t',(10,))) #x2是否服從自由度爲10的t分佈,p<0.05拒絕原假設,不服從t分佈
display(stats.kstest(x2,'norm',(x2.mean(),x2.std()))) #x2是否服從正態分佈,p>0.05接受原假設,服從正態分佈

display(stats.ks_2samp(x1,x2)) #檢查兩樣本之間是否存在差異,p<0.05,拒絕原假設
KstestResult(statistic=0.06866106990810628, pvalue=0.7449808598539311)

KstestResult(statistic=0.04853095923048054, pvalue=0.9725714755831804)

KstestResult(statistic=0.7704367841895967, pvalue=0.0)

KstestResult(statistic=0.014475654942241234, pvalue=0.9848110113960367)

Ks_2sampResult(statistic=0.776, pvalue=2.695396223072419e-49)

1.4. 卡方檢驗

卡方檢驗是在給定樣本X1,X2,……Xn,觀察值x1,x2……xn的情況下,檢驗總體是否服從有關分佈F(X)的一種非參數統計方法。

(1)建立零假設和備擇假設:H0:總體分佈函數爲F(x);H1:總體分佈函數不爲F(x)。

(2)構造和計算統計量
◆把實軸(-∞,+∞)分成k個不相交的區間(-∞,a1],(a1,a2]……(ak-1,+∞)
●設樣本觀察值x1,x2,…,xn 落入每個區間的實際頻數爲fi則實際頻率爲fi/n
◆當零假設成立時,樣本值落在每個區間的概率pi;可以由分佈函數F(x)精確計算,則每個區間的理論頻數爲n*pi
◆當假設成立時,理論頻數np,與實際頻數fi,應該相差很小
◆構造統計量
在這裏插入圖片描述
(3)設定顯著性水平和確定否定域
◆給定顯著性水平a。
◆在零假設成立時,x^2統計量服從自由度爲k-1的卡方分佈。
在這裏插入圖片描述
(4)做出統計決策
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ffNwuKzc-1581155876675)(attachment:image.png)]參考文獻:https://wenku.baidu.com/view/cc9209a3760bf78a6529647d27284b73f342365f.html

#4、卡方檢驗
import numpy as np
import pandas as pd
from scipy import stats

x=stats.t.rvs(10,size=1000)
""" 用自定義的區間來做,強調了尾部,把中間當作一個,雖然中間數多但
是權重小,跟其他區間的權重是一樣的,將相對明顯的差別單列出來,以後
分析數據的時候都可以這樣做,就比較某一段。"""
quantiles=[0.0,0.01,0.05,0.1,1-0.10,1-0.05,1-0.01,1.0] #分位數對應的百分比--概率分佈函數。
crit=stats.t.ppf(quantiles,10)  #確定理論的分爲數在哪。分位數對應的百分比序列輸入後,對應生成一個服從自由度爲10的t分佈的分位數。
#cdf:累計分佈函數;  ppf:分位點函數(CDF的逆)
print(crit)
print(np.histogram(x,bins=crit))#數據x落入到分位數確定的隔段中,以及分位數形成的隔段。
plt.hist(x,bins=crit)  #數據x落在分位數確定的隔段中的直方圖
n_sample=x.size  #樣本x數量
np.histogram(x,bins=crit)  #數據x落入到分位數確定的隔段中,以及分位數形成的隔段。
print(np.histogram(x,bins=crit))
freqcount=np.histogram(x,bins=crit)[0]  #數據x落入每段的數量--實際值。

tprob=np.diff(quantiles)  #分位數百分比前後作差形成每段的概率。
tprob*n_sample  #理論上落入每段的數量--理論值。(這個值一般和實際值freqcount進行比較,感性認識下差別)

nprob=np.diff(stats.norm.cdf(crit))#假設是正態分佈,進行構造。stats.norm.cdf():正態分佈累計概率密度函數.
nprob*n_sample  #正態分佈的理論值 (這個值一般和實際值freqcount進行比較,感性認識下差別)
"""
卡方檢驗。 每一塊理論上應該落多少個,其實就是二項分佈,在中心極限定
理中:本來有多少概率落在裏面,與實際落進去的有誤差的,這個誤差是受二
項分佈影響的,當二項分佈數比較大的時候可以將他構造成一個正態分佈,標
準化後進行平方和,也就是每一塊理論上都有一個概率值落在裏面,但是和實
際值有差別,這個差別我們認爲是服從正態分佈的。每一個構造爲:
[(理論值N0-實際值N)/sqrt(二項分佈的誤差nprob)]~N(0,1),將其平
方和,然後將每段都加起來,構造的隨機變量服從卡方分佈。
"""
tch,tpval=stats.chisquare(freqcount,tprob*n_sample)  #卡方檢驗。(判斷p值是否拒絕原假設:數據爲卡方分佈)
print(tch,tpval)
nch,npval=stats.chisquare(freqcount,nprob*n_sample)  #看看是否符合正態分佈
print(nch,npval)
"""最終結果是:不能拒絕它是來自t分佈,但是拒絕它是來自正態分佈的。
爲什麼要用卡方分佈呢:對尾部特別感興趣的時候,就需要檢驗下。卡方檢驗
完全是自己構造,對於區間完全是自己選的,尾部有多少自己來定。非常強大的
比k-s還要強大。卡方檢驗是根據(每個區間的)分佈函數來算的,每段理論有多
少個和實際多少個進行比較的。還有一種是根據樣本來估計一些數字特徵來檢驗。"""

#基於樣本估計的數字特徵進行卡方檢驗
tdof,tloc,tscale=stats.t.fit(x)  #用t分佈去模擬數據,輸出最好的變量:自由度,期望,方差。
nloc,nscale=stats.norm.fit(x) #用正態分佈去模擬現在的樣本
tprob=np.diff(stats.t.cdf(crit,tdof,loc=tloc,scale=tscale))  #這個是用理論值算出來的,剛纔的是分位數算出來的。
nprob=np.diff(stats.norm.cdf(crit,loc=nloc,scale=nscale))
tch,tpval=stats.chisquare(freqcount,tprob*n_sample)
print(tch,tpval)
nch,npval=stats.chisquare(freqcount,nprob*n_sample)
print(nch,npval)
"""兩種結果可能都不能拒絕,這種方法也不是太好。爲什麼不如直接剛纔的尾部卡方檢驗好呢?
因爲在中間核心的部分,正態分佈和t分佈還是比較像的,只是在尾部比較像的,全體的去考慮,
用一個擬合曲線去考慮,尾部的區別被中間相同性掩蓋了。"""
[       -inf -2.76376946 -1.81246112 -1.37218364  1.37218364  1.81246112
  2.76376946         inf]
(array([ 10,  35,  50, 817,  42,  36,  10], dtype=int64), array([       -inf, -2.76376946, -1.81246112, -1.37218364,  1.37218364,
        1.81246112,  2.76376946,         inf]))
(array([ 10,  35,  50, 817,  42,  36,  10], dtype=int64), array([       -inf, -2.76376946, -1.81246112, -1.37218364,  1.37218364,
        1.81246112,  2.76376946,         inf]))
2.666249999999988 0.8494173678927932
37.95236071494776 1.1477081193011593e-06
2.1367205239473317 0.9067045984049802
14.020935348692674 0.029403176707172213

在這裏插入圖片描述

1.5. 正態分佈檢驗

stats.normaltest(x) #檢驗x字段樣本是否符合正態分佈

#5、正態分佈檢驗
import numpy as np
import pandas as pd
from scipy import stats

x=stats.t.rvs(10,size=1000)
stats.normaltest(x) #結果是拒絕的。
NormaltestResult(statistic=61.25169685165855, pvalue=5.0045268662821025e-14)

案例:

數據源:https://download.csdn.net/download/weixin_41685388/12144418

# import... 略(見文章頭部)
'''
某餐廳顧客消費記錄.
解釋數據結構:
total_bill:消費,tip:小費,sex:服務員性別,
smoker:是否抽菸,day:星期幾,time:午餐/晚餐,size:本桌人數
'''
tips = pd.read_csv(r"E:\tips.csv",encoding='utf-8') #導入csv格式數據
display(tips.sample(5))  #隨機抽樣5行

print("tips['tip']:",stats.normaltest(tips['tip'])) #結果拒絕

tips['tip_pct']=tips['tip']/tips['total_bill']
plt.hist(tips['tip_pct'],bins=50) #視圖感性分析:很像正態分佈
plt.title("tips['tip']/tips['total_bill']分佈直方圖")

print("tips['tip']/tips['total_bill']:",stats.normaltest(tips['tip_pct'])) #結果拒絕

"""但是結果比較奇怪,猜測是圖像右邊尾巴的異常點引起的。"""
print(tips[tips['tip_pct']>0.3])  #查看異常點,只有三個

tips1=tips.drop([67,172,178]) #異常點太少也不好分析,直接去除
stats.normaltest(tips1['tip_pct'])  #結果接受原假設
total_bill tip sex smoker day time size
166 20.76 2.24 Male No Sun Dinner 2
161 12.66 2.50 Male No Sun Dinner 2
238 35.83 4.67 Female No Sat Dinner 3
147 11.87 1.63 Female No Thur Lunch 2
219 30.14 3.09 Female Yes Sat Dinner 4
tips['tip']: NormaltestResult(statistic=79.37862574074785, pvalue=5.796294322907102e-18)
tips['tip']/tips['total_bill']: NormaltestResult(statistic=220.8879728815828, pvalue=1.0833932598440914e-48)
     total_bill   tip     sex smoker  day    time  size   tip_pct
67         3.07  1.00  Female    Yes  Sat  Dinner     1  0.325733
172        7.25  5.15    Male    Yes  Sun  Dinner     2  0.710345
178        9.60  4.00  Female    Yes  Sun  Dinner     2  0.416667

NormaltestResult(statistic=0.7724869721322898, pvalue=0.6796050311777623)

在這裏插入圖片描述

1.6.帕累託分佈

帕累託分析依據的原理是20/80定律,80%的效益常常來自於20%的投入,而其他80%的投入卻只產生了20%的效益,這說明,同樣的投入在不同的地方會產生不同的效益。

帕累託分佈圖的繪製過程是按照貢獻度從高到低依次排列,並繪製累積貢獻度曲線。當樣本數量足夠大時,貢獻度通常會呈現20/80分佈。

在帕累託分佈中,如果X是一個隨機變量, 則X的概率分佈如下面的公式所示:
在這裏插入圖片描述
  其中x是任何一個大於xmin的數,xmin是X最小的可能值(正數),k是爲正的參數。帕累託分佈曲線族是由兩個數量參數化的:xmin和k。分佈密度則爲
在這裏插入圖片描述在這裏插入圖片描述

#帕累託分佈
#P(X>x)=(x/xmin)**(-k)
#E(P)=xmin*k/(k-1)
#構造一組帕累託分佈,均值爲50,k值(shape爲1.2),且具有大於1000的點
#size爲多少纔有把我裏面有大於1000的數
x=stats.pareto.rvs(b=1.2,loc=50,size=1000)
p=1-stats.pareto.cdf(1000,b=1.2,loc=50)
print(p)
#0.0002671355417115384  不存在

print(1-stats.binom.cdf(1,20000,p))
#0.9696783490389687
plt.plot(-np.sort(-x),"ro")
plt.show()

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章