0
引言
问题:如何检验数据的抽样的某个维度是符合某种分布的?譬如,是否是正态分布,是否与总体的分布相同等?工具:python。接下来一起看看数据分析中重要的一环“单变量的样本分布检验”。
探索数据变量之间是否存在某种关系/关联。大致思路有:
①确认变量的类型:[类别型、数值型];
②可视化给出可能的方向:[散点图、箱型图、直方图、…];
③需建立更严格的分析方式:假设检验。假设变量间存在某种函数/逻辑等关联关系,进行检验。
打开jupyter notebook (或者你自己使用的python代码编辑器),安装并导入几个数据分析固定库。
import numpy as np #科学计算基础库,多维数组对象ndarrayimport 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 warningswarnings.filterwarnings("ignore") #用于排除警告# 用于显示使用库的版本print("numpy_" + np.__version__)print("pandas_" + pd.__version__)print("matplotlib_"+ mpl.__version__)
分布的数字特征是否与理论的数字特征一致?
t分布序列数字特征检验。
# 例:生成一个t分布序列import numpy as npfrom 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))#最小值,最大值,均值,中位数,print(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)#数量,(最小值,最大值),均值,方差,偏度,峰度

#计算理论数字特征---发现随机样本和理论还是存在差异的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
t-test检验是检验一个或两个样本之间的均值是否有明显的差别,也就是检验单变量对因变量的影响。
stats.ttest_1samp(x,m) # 用t-test检验来检验样本数据均值和理论均值差异性检验。一组数据与指定均值比较。
stats.ttest_ind(rvs1,rvs2) # 对两个样本进行t检验
#结果分析:p值越小我们拒绝原假设(样本样本均值存在差异)
#比较两个样本(比较两组均值)
带参数的假设检验
# 单样本检验import numpy as npfrom scipy import statsrvs1=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,拒绝原假设(均值存在差异)

# 两个样本的检验import numpy as npfrom scipy import statsrvs1=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,拒绝原假设,即样本均值和理论均值存在差异

stats.kstest(x,‘t’,(10,)) #检验样本数据x是否是自由度为10的t分布
K-S test 还可以检验其他分布:正态分布…
#如果比较两组分布
import numpy as npfrom scipy import statsx1 = 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,拒绝原假设

卡方检验是在给定样本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)做出统计决策
#4、卡方检验import numpy as npimport pandas as pdfrom scipy import statsx=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分布还是比较像的,只是在尾部比较像的,全体的去考虑,用一个拟合曲线去考虑,尾部的区别被中间相同性掩盖了。"""


stats.normaltest(x) #检验x字段样本是否符合正态分布
#5、正态分布检验# import ...见02工具x=stats.t.rvs(10,size=1000)stats.normaltest(x) #结果是拒绝的。#结果:NormaltestResult(statistic=61.25, pvalue=5.00e-14)
'''某餐厅顾客消费记录.解释数据结构:total_bill:消费,tip:小费,sex:服务员性别,smoker:是否抽烟,day:星期几,time:午餐/晚餐,size:本桌人数数据源:https://download.csdn.net/download/weixin_41685388/12144418'''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'])#结果接受原假设



帕累托分析依据的原理是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.9696783490389687plt.plot(-np.sort(-x),"ro")plt.show()

扫码关注
更多干货在等你

