一、SciPy概述¶前篇已经大致介绍了NumPy,接下来让我们看看SciPy能做些什么。NumPy替我们搞定了向量和矩阵的相关操作,基本上算是一个高级的科学计算器。SciPy基于NumPy提供了更为丰富和高级的功能扩展,在统计、优化、插值、数值积分、时频转换等方面提供了大量的可用函数,基本覆盖了基础科学计算相关的问题。在量化分析中,运用最广泛的是统计和优化的相关技术,本篇重点介绍SciPy中的统计和优化模块,其他模块在随后系列文章中用到时再做详述。本篇会涉及到一些矩阵代数,如若感觉不适,可考虑跳过第三部分或者在理解时简单采用一维的标量代替高维的向量。首先还是导入相关的模块,我们使用的是SciPy里面的统计和优化部分:In[1]:importnumpyasnpimportscipy.statsasstatsimportscipy.optimizeasopt二、统计部分¶2.1生成随机数¶我们从生成随机数开始,这样方便后面的介绍。生成n个随机数可用rv_continuous.rvs(size=n)或rv_discrete.rvs(size=n),其中rv_continuous表示连续型的随机分布,如均匀分布(uniform)、正态分布(norm)、贝塔分布(beta)等;rv_discrete表示离散型的随机分布,如伯努利分布(bernoulli)、几何分布(geom)、泊松分布(poisson)等。我们生成10个[0,1]区间上的随机数和10个服从参数$a=4$,$b=2$的贝塔分布随机数:In[2]:rv_unif=stats.uniform.rvs(size=10)printrv_unifrv_beta=stats.beta.rvs(size=10,a=4,b=2)printrv_beta[0.206302720.259292040.168592060.925734620.163833190.34756170.837920480.795741530.379450510.23439682][0.712164920.856884640.703101310.37836620.695075610.786265860.545299670.42610790.266467670.8519046]在每个随机分布的生成函数里,都内置了默认的参数,如均匀分布的上下界默认是0和1。可是一旦需要修改这些参数,每次生成随机都要敲这么老长一串有点麻烦,能不能简单点?SciPy里头有一个Freezing的功能,可以提供简便版本的命令。SciPy.stats支持定义出某个具体的分布的对象,我们可以做如下的定义,让beta直接指代具体参数$a=4$和$b=2$的贝塔分布。为让结果具有可比性,这里指定了随机数的生成种子,由NumPy提供。In[3]:np.random.seed(seed=2015)rv_beta=stats.beta.rvs(size=10,a=4,b=2)printmethod1:printrv_betanp.random.seed(seed=2015)beta=stats.beta(a=4,b=2)printmethod2:printbeta.rvs(size=10)method1:[0.438573380.94115510.751166710.920028640.620305210.565855480.418435480.59530960.889830360.94675351]method2:[0.438573380.94115510.751166710.920028640.620305210.565855480.418435480.59530960.889830360.94675351]2.2假设检验¶好了,现在我们生成一组数据,并查看相关的统计量(相关分布的参数可以在这里查到:):In[4]:norm_dist=stats.norm(loc=0.5,scale=2)n=200dat=norm_dist.rvs(size=n)printmeanofdatais:+str(np.mean(dat))printmedianofdatais:+str(np.median(dat))printstandarddeviationofdatais:+str(np.std(dat))meanofdatais:0.705195138069medianofdatais:0.658167882933standarddeviationofdatais:2.08967006905假设这个数据是我们获取到的实际的某些数据,如股票日涨跌幅,我们对数据进行简单的分析。最简单的是检验这一组数据是否服从假设的分布,如正态分布。这个问题是典型的单样本假设检验问题,最为常见的解决方案是采用K-S检验(Kolmogorov-Smirnovtest)。单样本K-S检验的原假设是给定的数据来自和原假设分布相同的分布,在SciPy中提供了kstest函数,参数分别是数据、拟检验的分布名称和对应的参数:In[5]:mu=np.mean(dat)sigma=np.std(dat)stat_val,p_val=stats.kstest(dat,'norm',(mu,sigma))print'KS-statisticD=%6.3fp-value=%6.4f'%(stat_val,p_val)KS-statisticD=0.045p-value=0.8195假设检验的$p$-value值很大(在原假设下,$p$-value是服从[0,1]区间上的均匀分布的随机变量,可参考),因此我们接受原假设,即该数据通过了正态性的检验。在正态性的前提下,我们可进一步检验这组数据的均值是不是0。典型的方法是$t$检验($t$-test),其中单样本的$t$检验函数为ttest_1samp:In[6]:stat_val,p_val=stats.ttest_1samp(dat,0)print'One-samplet-statisticD=%6.3f,p-value=%6.4f'%(stat_val,p_val)One-samplet-statisticD=4.761,p-value=0.0000我们看到$p$-value$0.05$,即给定显著性水平0.05的前提下,我们应拒绝原假设:数据的均值为0。我们再生成一组数据,尝试一下双样本的$t$检验(ttest_ind):In[7]:norm_dist2=stats.norm(loc=-0.2,scale=1.2)dat2=norm_dist2.rvs(size=n/2)stat_val,p_val=stats.ttest_ind(dat,dat2,equal_var=False)print'Two-samplet-statisticD=%6.3f,p-value=%6.4f'%(stat_val,p_val)Two-samplet-statisticD=5.565,p-value=0.0000注意,这里我们生成的第二组数据样本大小、方差和第一组均不相等,在运用$t$检验时需要使用Welch's$t$-test,即指定ttest_ind中的equal_var=False。我们同样得到了比较小的$p$-value$,在显著性水平0.05的前提下拒绝原假设,即认为两组数据均值不等。stats还提供其他大量的假设检验函数,如bartlett和levene用于检验方差是否相等;anderson_ksamp用于进行Anderson-Darling的K-样本检验等。2.3其他函数¶有时需要知道某数值在一个分布中的分位,或者给定了一个分布,求某分位上的数值。这可以通过cdf和ppf函数完成:In[8]:g_dist=stats.gamma(a=2)printquantilesof2,4and5:printg_dist.cdf([2,4,5])printValuesof25%,50%and90%:printg_dist.pdf([0.25,0.5,0.95])quantilesof2,4and5:[0.593994150.908421810.95957232]Valuesof25%,50%and90%:[0.19470020.303265330.36740397]对于一个给定的分布,可以用moment很方便的查看分布的矩信息,例如我们查看$N(0,1)$的六阶原点矩:In[9]:stats.norm.moment(6,loc=0,scale=1)Out[9]:15.000000000895332describe函数提供对数据集的统计描述分析,包括数据样本大小,极值,均值,方差,偏度和峰度:In[10]:norm_dist=stats.norm(loc=0,scale=1.8)dat=norm_dist.rvs(size=100)info=stats.describe(dat)printDatasizeis:+str(info[0])printMinimumvalueis:+str(info[1][0])printMaximumvalueis:+str(info[1][1])printArithmeticmeanis:+str(info[2])printUnbiasedvarianceis:+str(info[3])printBiasedskewnessis:+str(info[4])printBiasedkurtosisis:+str(info[5])Datasizeis:100Minimumvalueis:-4.12414564687Maximumvalueis:4.82577602489Arithmeticmeanis:0.0962913592209Unbiasedvarianceis:2.88719292463Biasedskewnessis:-0.00256548794681Biasedkurtosisis:-0.317463421177当我们知道一组数据服从某些分布的时候,可以调用fit函数来得到对应分布参数的极大似然估计(MLE,maximum-likelihoodestimation)。以下代码示例了假设数据服从正态分布,用极大似然估计分布参数:In[11]:norm_dist=stats.norm(loc=0,scale=1.8)dat=norm_dist.rvs(size=100)mu,sigma=stats.norm.fit(dat)printMLEofdatamean:+str(mu)printMLEofdatastandarddeviation:+str(sigma)MLEofdatamean:-0.249880829912MLEofdatastandarddeviation:1.89195303507pearsonr和spearmanr可以计算Pearson和Spearman相关系数,这两个相关系数度量了两组数据的相互线性关联程度:In[12]:norm_dist=stats.norm()dat1=norm_dist.rvs(size=100)exp_dist=stats.expon()dat2=exp_dist.rvs(size=100)cor,pval=stats.pearsonr(dat1,dat2)printPearsoncorrelationcoefficient:+str(cor)cor,pval=stats.pearsonr(dat1,dat2)printSpearman'srankcorrelationcoefficient:+str(cor)Pearsoncorrelationcoefficient:-0.0262911931014Spearman'srankcorrelationcoefficient:-0.0262911931014其中的$p$-v