【python数据分析】正态分布、正态性检验与相关性分析


手动反爬虫: 原博地址

 知识梳理不易,请尊重劳动成果,文章仅发布在CSDN网站上,在其他网站看到该博文均属于未经作者授权的恶意爬取信息

如若转载,请标明出处,谢谢!

1 正态分布

正态分布概念是由法国数学家和天文学家棣莫弗(Abraham de Moivre)于1733年首次提出的,后由德国数学家Gauss率先将其应用于天文学研究,故正态分布又叫高斯分布

若随机变量 X X X服从一个数学期望为 μ μ μ、方差为 σ 2 σ^{2} σ2的正态分布,记为 N ( μ , σ 2 ) N(μ,σ^{2}) N(μσ2)。其概率密度函数为正态分布的期望值μ决定了其位置,其标准差 σ σ σ决定了分布的幅度。当 μ = 0 , σ = 1 μ = 0,σ = 1 μ=0,σ=1时的正态分布是标准正态分布

正态分布对应的概率密度函数:
f ( x ) = 1 2 π σ e x p ( − ( x − μ ) 2 2 σ 2 ) f(x) = \frac{1}{\sqrt{2\pi}σ}exp(-\frac{(x-μ)^{2}}{2σ^{2}}) f(x)=2π σ1exp(2σ2(xμ)2)标准正态分布对应的概率密度函数:
f ( x ) = 1 2 π e ( − x 2 2 ) f(x) = \frac{1}{\sqrt{2\pi}}e^{(-\frac{x^{2}}{2})} f(x)=2π 1e(2x2)正态分布曲线呈钟型,两头低,中间高,左右对称因其曲线呈钟形,因此人们又经常称之为钟形曲线
在这里插入图片描述

  • (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()
s_r

输出结果为:
在这里插入图片描述
第三步,求解p(i)

s_r['p'] = (s_r.index - 0.5) / len(s_r)
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:样本的总体分布不服从某特定分布

F n ( x ) ⇒ F_{n}(x) \Rightarrow Fn(x) 样本的累计分布函数
F 0 ( x ) ⇒ F_{0}(x) \Rightarrow F0(x)理论分布的分布函数
D ⇒ F n ( x ) 与 F 0 ( x ) D \Rightarrow F_{n}(x)与F_{0}(x) DFn(x)F0(x)差值的绝对值最大值,即 D = m a x ( ∣ F n ( x ) − F 0 ( x ) ∣ ) D = max(|F_{n}(x) - F_{0}(x)|) D=max(Fn(x)F0(x))

判断依据: D > D ( n , α ) D > D(n,\alpha) D>D(n,α)
如果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) / std

df_s

输出结果为:
在这里插入图片描述
既然求解出标准化的取值,然后对照着下表就可以求解出理论分布对应的值,比如最后一个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代表着无相关性,负值代表着负相关,正值为正相关。前提:样本必须是正态分布

0 < ∣ r ∣ < 1 0<|r|<1 0<r<1表示不同程度的线性相关

  • ∣ r ∣ < = 0.3 ⇒ |r| <= 0.3 \Rightarrow r<=0.3不存在线性相关
  • 0.3 < ∣ r ∣ < = 0.5 ⇒ 0.3<|r|<=0.5 \Rightarrow 0.3<r<=0.5低度线性相关
  • 0.5 < ∣ r ∣ < = 0.8 ⇒ 0.5<|r|<=0.8 \Rightarrow 0.5<r<=0.8显著线性相关
  • 0.8 < ∣ r ∣ ⇒ 0.8<|r| \Rightarrow 0.8<r高度线性相关
    在这里插入图片描述
    代码实现:(就是按照上面的公式进行求解)
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

输出结果为:(可以发现最后的结果和上面的计算推导是一致的)
在这里插入图片描述

4 总结

(1)正态分布直接先通过柱状图和密度曲线查看
(2)正态性检验:stats.kstest(df['value'], 'norm', (u, std))
(3)Pearson相关系数:前提是正态分布,data.corr()
(4)Sperman秩相关系数:不要求是正态分布,data.corr(method='spearman')

  • 11
    点赞
  • 110
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lys_828

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值