正态分布、正态性檢驗與相關性分析
- 1 正态分布
- 2 正态性檢驗
- 2.1 直方圖初判
- 2.2 QQ圖
- 2.3 K-S檢驗
- 2.3.1 計算推導
- 2.3.2 代碼一步到位
- 3 相關性分析
- 3.1 圖示初判
- 3.2 Pearson相關系數
- 3.2.1 計算推導
- 3.2.2 代碼一步到位
- 3.3 Sperman秩相關系數
- 3.3.1 計算推導
- 3.3.2 代碼一步到位
- 4 總結
手動反爬蟲:
原博位址
知識梳理不易,請尊重勞動成果
如若轉載,請标明出處,謝謝!
1 正态分布
正态分布概念是由法國數學家和天文學家棣莫弗(Abraham de Moivre)于1733年首次提出的,後由德國數學家Gauss率先将其應用于天文學研究,故正态分布又叫高斯分布
若随機變量服從一個數學期望為、方差為的正态分布,記為。其機率密度函數為正态分布的期望值μ決定了其位置,其标準差決定了分布的幅度。當時的正态分布是标準正态分布
正态分布對應的機率密度函數:
标準正态分布對應的機率密度函數:
正态分布曲線呈鐘型,兩頭低,中間高,左右對稱因其曲線呈鐘形,是以人們又經常稱之為鐘形曲線。
- (1)集中性:正态分布曲線的高峰位于正中央,即均數所在的位置
- (2)對稱性:正态曲線以均數為中心,左右對稱,曲線兩端永遠不與橫軸相交
- (3)均勻變動性:正态曲線有均數所在處開始,分别向左右兩側逐漸均勻下降
- (4)機率為1:曲線與橫軸間的面積總等于1,相當于機率密度函數從從負無窮到正無窮的積分值為1,即頻率的總和為100%
- (5)決定分布的中心位置;越大,曲線越矮胖,總體分布越分散,反之曲線越瘦高,總體分布越集中
對于資料分析過程中的正态分布的了解:
- 并不是所有的資料都是滿足正态分布(比如幂律分布)
- 并不是必須滿足正态分布才能作分析
- 通過正态分布作為參考去了解事物規律
- 可以通過多種方式進行正态性檢驗
2 正态性檢驗
程式設計環境是在jupyter notebook中
2.1 直方圖初判
這裡随機生成資料
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
s = pd.DataFrame(np.random.randn(1000)+10,
columns = ['values'])
fig = plt.figure(figsize=(10,6),dpi = 500)
ax1 = fig.add_subplot(2,1,1)
ax1.scatter(s.index,s.values,edgecolor = 'black')
ax2 = fig.add_subplot(2,1,2)
s.hist(bins = 20,ax = ax2,edgecolor = 'black')
s.plot(kind = 'kde', secondary_y = True, ax = ax2)
輸出結果為:(可以發現繪制的密度曲線滿足正态分布的曲線樣式)
2.2 QQ圖
QQ圖通過把測試樣本資料的分位數與已知分布相比較,進而來檢驗資料的分布情況
QQ圖是一種散點圖,對應于正态分布的QQ圖,就是由标準正态分布的分位數為橫坐标,樣本值為縱坐标的散點圖
參考直線:四分之一分位點和四分之三分位點這兩點确定,看散點是否落在這條線的附近
繪制思路:
- (1) 在做好資料清洗後,對資料進行排序(次序統計量:x(1)<x(2)<…<x(n))
- (2) 排序後,計算出每個資料對應的百分位p(i),即第i個資料x(i)為p(i)分位數,其中p(i)=(i-0.5)/n (pi有多重算法,這裡以最常用方法為主)
- (3)繪制直方圖 + QQ圖,直方圖作為參考
第一步求解樣本資料的均值和标準差
s = pd.DataFrame(np.random.randn(1000)+10,
columns = ['values'])
mean = s['values'].mean()
std = s['values'].std()
print('均值為:{},标準差為:{}'.format(mean,std))
輸出結果為:(由于是随機數,這裡的均值和标準差會每次運作都有所不同)
均值為:10.032453869072762,标準差為:1.0290379115139239
第二步,進行數值排序
s_r = s.sort_values(by = 'values').reset_index()
輸出結果為:
第三步,求解p(i)
s_r['p'] = (s_r.index - 0.5) / len(s_r)
輸出結果為:
第四步,根據分位數繪制QQ圖
st = s['values'].describe()
x1,y1 = 0.25, st['25%']
x2,y2 = 0.75, st['75%']
plt.figure(figsize = (10,4),dpi = 200)
plt.plot(s_r['p'],s_r['values'],'k.',alpha = 0.1)
plt.plot([x1,x2],[y1,y2],'-r')
輸出結果為:(QQ圖繪制完成,資料滿足正态分布)
2.3 K-S檢驗
Kolmogorov–Smirnov test (K-S test) 是比較一個頻率分布f(x)與理論分布g(x)或者兩個觀測值分布的檢驗方法
以樣本資料的累計頻數分布與特定的理論分布比較(比如正态分布),如果兩者之間差距小,則推論樣本分布取自某特定分布
2.3.1 計算推導
假設檢驗的問題:
H0:樣本的總體分布服從某特定分布
H1:樣本的總體分布不服從某特定分布
樣本的累計分布函數
理論分布的分布函數
內插補點的絕對值最大值,即
判斷依據:
如果p>0.05則接受H0,p<0.05則拒絕H0,接受H1
第一步,準備樣本資料:35位健康男性在未進食之前的血糖濃度,并求解出均值和标準差
data = [87,77,92,68,80,78,84,77,81,80,80,77,92,86,
76,80,81,75,77,72,81,72,84,86,80,68,77,87,
76,77,78,92,75,80,78]
df = pd.DataFrame(data, columns = ['value'])
u = df['value'].mean()
std = df['value'].std()
print('均值為:{},标準差為:{}'.format(u,std))
輸出結果為:
均值為:79.74285714285715,标準差為:5.937631024648968
第二步,值計數後按照索引排序,接着求解出累計次數和對應的标準取值
s = df['value'].value_counts().sort_index()
df_s = pd.DataFrame({'血糖濃度':s.index, '次數':s.values})
df_s['累計次數'] = df_s['次數'].cumsum()
df_s['累計頻率'] = df_s['累計次數']/len(data)
df_s['标準化取值'] = (df_s['血糖濃度'] - u) /
輸出結果為:
既然求解出标準化的取值,然後對照着下表就可以求解出理論分布對應的值,比如最後一個2.064315,查表後對應的分布值為0.9803,若是負值,比如-1.977701,則先取正值對應的結果後,用1減去就是最終的結果,這裡1.977701查表為0.9756,最終的結果就為0.0244。由此可以計算出所有的理論分布
第三步,查表得理論分布後,求解D值
df_s['理論分布'] =[0.0244,0.0968,0.2148,0.2643,0.3228,0.3859,0.5160,0.5832,0.7611,0.8531,0.8888,0.9803] # 通過查閱正太分布表
df_s['D'] = np.abs(df_s['累計頻率'] - df_s['理論分布'])
dmax = df_s['D'].max()
print("實際觀測D值為:%.4f" % dmax)
# D值序列計算結果表格
輸出結果為:
實際觀測D值為:0.1597
第四步,根據顯著性表核實p值大小。參考上表,這裡的樣本為35,D值為0.1597,那麼對應的p值為0.2-0.4之間,要大于0.05,故可以認定樣本是服從正态分布的)
2.3.2 代碼一步到位
data = [87,77,92,68,80,78,84,77,81,80,80,77,92,86,
76,80,81,75,77,72,81,72,84,86,80,68,77,87,
76,77,78,92,75,80,78]
df = pd.DataFrame(data, columns =['value'])
u = df['value'].mean()
std = df['value'].std()
stats.kstest(df['value'], 'norm', (u, std))
# .kstest方法:KS檢驗,參數分别是:待檢驗的資料,檢驗方法(這裡設定成norm正态分布),均值與标準差
# 結果傳回兩個值:statistic → D值,pvalue → P值
# p值大于0.05,為正态分布
輸出結果為:(pvalue=0.3066,D值也和之前算的值約相等)
KstestResult(statistic=0.1590180704824098, pvalue=0.3066297258358026)
3 相關性分析
相關性分析是指對兩個或者多個具備相關性的變量元素進行分析,進而衡量兩個因素的相關密切程度
相關性的元素之間需要存在一定的聯系或者機率才可以進行相關性分析
分析的方式也是有多種:
- (1)圖示初判(散點矩陣)
- (2)Pearson相關系數(皮爾遜相關系數)
- (3)Sperman秩相關系數(斯皮爾曼相關系數)
3.1 圖示初判
data1 = pd.Series(np.random.rand(50)*100).sort_values()
data2 = pd.Series(np.random.rand(50)*50).sort_values()
data3 = pd.Series(np.random.rand(50)*500).sort_values(ascending = False)
# 建立三個資料:data1為0-100的随機數并從小到大排列,data2為0-50的随機數并從小到大排列,data3為0-500的随機數并從大到小排列,
fig = plt.figure(figsize = (10,4))
ax1 = fig.add_subplot(1,2,1)
ax1.scatter(data1, data2)
plt.grid()
# 正線性相關
ax2 = fig.add_subplot(1,2,2)
ax2.scatter(data1, data3)
plt.grid()
# 負線性相關
輸出結果:(這裡是兩個因素之間的相關性比較)
如果是多個因素,那麼就可以使用散點矩陣
# (2)散點圖矩陣初判多變量間關系
data = pd.DataFrame(np.random.randn(200,4)*100, columns = ['A','B','C','D'])
pd.plotting.scatter_matrix(data,figsize=(8,8),
c = 'k',
marker = '+',
diagonal='hist',
alpha = 0.8,
range_padding=0.1)
輸出結果為:(直接通過分布就可以看出)
3.2 Pearson相關系數
3.2.1 計算推導
最常見的衡量相關性的标準,輸出的結果範圍為:-1到1之間,0代表着無相關性,負值代表着負相關,正值為正相關。前提:樣本必須是正态分布
表示不同程度的線性相關
- 不存線上性相關
- 低度線性相關
- 顯著線性相關
- 高度線性相關
- 代碼實作:(就是按照上面的公式進行求解)
data1 = pd.Series(np.random.rand(100)*100).sort_values()
data2 = pd.Series(np.random.rand(100)*50).sort_values()
data = pd.DataFrame({'value1':data1.values,
'value2':data2.values})
print(data.head())
print('------')
# 建立樣本資料
u1,u2 = data['value1'].mean(),data['value2'].mean() # 計算均值
std1,std2 = data['value1'].std(),data['value2'].std() # 計算标準差
print('value1正态性檢驗:\n',stats.kstest(data['value1'], 'norm', (u1, std1)))
print('value2正态性檢驗:\n',stats.kstest(data['value2'], 'norm', (u2, std2)))
print('------')
# 正态性檢驗 → pvalue >0.05
data['(x-u1)*(y-u2)'] = (data['value1'] - u1) * (data['value2'] - u2)
data['(x-u1)**2'] = (data['value1'] - u1)**2
data['(y-u2)**2'] = (data['value2'] - u2)**2
print(data.head())
print('------')
# 制作Pearson相關系數求值表
r = data['(x-u1)*(y-u2)'].sum() / (np.sqrt(data['(x-u1)**2'].sum() * data['(y-u2)**2'].sum()))
print('Pearson相關系數為:%.4f' % r)
# 求出r
# |r| > 0.8 → 高度線性相關
輸出結果為:(先檢驗正态性,然後按照公式求解即可)
3.2.2 代碼一步到位
使用pandas的
.corr()
方法
data1 = pd.Series(np.random.rand(100)*100).sort_values()
data2 = pd.Series(np.random.rand(100)*50).sort_values()
data = pd.DataFrame({'value1':data1.values,
'value2':data2.values})
print(data.head())
print('------')
# 建立樣本資料
data.corr()
# pandas相關性方法:data.corr(method='pearson', min_periods=1) → 直接給出資料字段的相關系數矩陣
# method預設pearson
輸出結果為:(0.9937,很明顯具有相關性)
3.3 Sperman秩相關系數
皮爾遜相關系數主要用于服從正态分布的連續變量,不服從正态分布的變量,分類的關聯性可以采用Sperman秩相關系數,也稱等級相關系數
計算邏輯:
- 對兩個變量成對的取值按照從大到小順序編秩,Rx代表Xi的秩次,Ry代表Yi的秩次,如果兩個值大小相同,則秩次為(index1 + index2)/ 2
- di = Rx - Ry
- Sperman秩相關系數和Pearson相關系數在效率上是等價的
3.3.1 計算推導
data = pd.DataFrame({'智商':[106,86,100,101,99,103,97,113,112,110],
'每周看電視小時數':[7,0,27,50,28,29,20,12,6,17]})
print(data)
print('------')
# 建立樣本資料
data.sort_values('智商', inplace=True)
data['range1'] = np.arange(1,len(data)+1)
data.sort_values('每周看電視小時數', inplace=True)
data['range2'] = np.arange(1,len(data)+1)
print(data)
print('------')
# “智商”、“每周看電視小時數”重新按照從小到大排序,并設定秩次index
data['d'] = data['range1'] - data['range2']
data['d2'] = data['d']**2
print(data)
print('------')
# 求出di,di2
n = len(data)
rs = 1 - 6 * (data['d2'].sum()) / (n * (n**2 - 1))
print('Pearson相關系數為:%.4f' % rs)
# 求出rs
輸出結果為:(可以看出每周看電視的小時數和智商沒有太大相關性)
3.3.2 代碼一步到位
參數中有個method,換一下即可
data = pd.DataFrame({'智商':[106,86,100,101,99,103,97,113,112,110],
'每周看電視小時數':[7,0,27,50,28,29,20,12,6,17]})
print(data)
print('------')
# 建立樣本資料
data.corr(method='spearman')
# pandas相關性方法:data.corr(method='pearson', min_periods=1) → 直接給出資料字段的相關系數矩陣
# method預設pearson
輸出結果為:(可以發現最後的結果和上面的計算推導是一緻的)