概率统计方法

简介

Python 中常用的统计工具有 Numpy, Pandas, PyMC, StatsModels 等。

Scipy 中的子库 scipy.stats 中包含很多统计上的方法。

导入 numpymatplotlib

In [1]:

  1. %pylab inline
  1. Populating the interactive namespace from numpy and matplotlib

In [2]:

  1. heights = array([1.46, 1.79, 2.01, 1.75, 1.56, 1.69, 1.88, 1.76, 1.88, 1.78])

Numpy 自带简单的统计方法:

In [3]:

  1. print 'mean, ', heights.mean()
  2. print 'min, ', heights.min()
  3. print 'max, ', heights.max()
  4. print 'standard deviation, ', heights.std()
  1. mean, 1.756
  2. min, 1.46
  3. max, 2.01
  4. standard deviation, 0.150811140172

导入 Scipy 的统计模块:

In [4]:

  1. import scipy.stats.stats as st

其他统计量:

In [5]:

  1. print 'median, ', st.nanmedian(heights) # 忽略nan值之后的中位数
  2. print 'mode, ', st.mode(heights) # 众数及其出现次数
  3. print 'skewness, ', st.skew(heights) # 偏度
  4. print 'kurtosis, ', st.kurtosis(heights) # 峰度
  5. print 'and so many more...'
  1. median, 1.77
  2. mode, (array([ 1.88]), array([ 2.]))
  3. skewness, -0.393524456473
  4. kurtosis, -0.330672097724
  5. and so many more...

概率分布

常见的连续概率分布有:

  • 均匀分布
  • 正态分布
  • 学生t分布
  • F分布
  • Gamma分布
  • 离散概率分布

  • 伯努利分布

  • 几何分布
  • … 这些都可以在 scipy.stats 中找到。

连续分布

正态分布

正态分布为例,先导入正态分布:

In [6]:

  1. from scipy.stats import norm

它包含四类常用的函数:

In [7]:

  1. x_norm = norm.rvs(size=500)
  2. type(x_norm)

Out[7]:

  1. numpy.ndarray

直方图:

In [8]:

  1. h = hist(x_norm)
  2. print 'counts, ', h[0]
  3. print 'bin centers', h[1]
  1. counts, [ 7. 21. 42. 97. 120. 91. 64. 38. 17. 3.]
  2. bin centers [-2.68067801 -2.13266147 -1.58464494 -1.0366284 -0.48861186 0.05940467
  3. 0.60742121 1.15543774 1.70345428 2.25147082 2.79948735]

04.03 概率统计方法 - 图1

归一化直方图(用出现频率代替次数),将划分区间变为 20(默认 10):

In [9]:

  1. h = hist(x_norm, normed=True, bins=20)

04.03 概率统计方法 - 图2

在这组数据下,正态分布参数的最大似然估计值为:

In [10]:

  1. x_mean, x_std = norm.fit(x_norm)
  2.  
  3. print 'mean, ', x_mean
  4. print 'x_std, ', x_std
  1. mean, -0.0426135499965
  2. x_std, 0.950754110144

将真实的概率密度函数与直方图进行比较:

In [11]:

  1. h = hist(x_norm, normed=True, bins=20)
  2.  
  3. x = linspace(-3,3,50)
  4. p = plot(x, norm.pdf(x), 'r-')

04.03 概率统计方法 - 图3

导入积分函数:

In [12]:

  1. from scipy.integrate import trapz

通过积分,计算落在某个区间的概率大小:

In [13]:

  1. x1 = linspace(-2,2,108)
  2. p = trapz(norm.pdf(x1), x1)
  3. print '{:.2%} of the values lie between -2 and 2'.format(p)
  4.  
  5. fill_between(x1, norm.pdf(x1), color = 'red')
  6. plot(x, norm.pdf(x), 'k-')
  1. 95.45% of the values lie between -2 and 2

Out[13]:

  1. [<matplotlib.lines.Line2D at 0x15cbb8d0>]

04.03 概率统计方法 - 图4

默认情况,正态分布的参数为均值0,标准差1,即标准正态分布。

可以通过 locscale 来调整这些参数,一种方法是调用相关函数时进行输入:

In [14]:

  1. p = plot(x, norm.pdf(x, loc=0, scale=1))
  2. p = plot(x, norm.pdf(x, loc=0.5, scale=2))
  3. p = plot(x, norm.pdf(x, loc=-0.5, scale=.5))

04.03 概率统计方法 - 图5

另一种则是将 loc, scale 作为参数直接输给 norm 生成相应的分布:

In [15]:

  1. p = plot(x, norm(loc=0, scale=1).pdf(x))
  2. p = plot(x, norm(loc=0.5, scale=2).pdf(x))
  3. p = plot(x, norm(loc=-0.5, scale=.5).pdf(x))

04.03 概率统计方法 - 图6

其他连续分布

In [16]:

  1. from scipy.stats import lognorm, t, dweibull

支持与 norm 类似的操作,如概率密度函数等。

不同参数的对数正态分布

In [17]:

  1. x = linspace(0.01, 3, 100)
  2.  
  3. plot(x, lognorm.pdf(x, 1), label='s=1')
  4. plot(x, lognorm.pdf(x, 2), label='s=2')
  5. plot(x, lognorm.pdf(x, .1), label='s=0.1')
  6.  
  7. legend()

Out[17]:

  1. <matplotlib.legend.Legend at 0x15781c88>

04.03 概率统计方法 - 图7

不同的韦氏分布

In [18]:

  1. x = linspace(0.01, 3, 100)
  2.  
  3. plot(x, dweibull.pdf(x, 1), label='s=1, constant failure rate')
  4. plot(x, dweibull.pdf(x, 2), label='s>1, increasing failure rate')
  5. plot(x, dweibull.pdf(x, .1), label='0<s<1, decreasing failure rate')
  6.  
  7. legend()

Out[18]:

  1. <matplotlib.legend.Legend at 0xaa9bc50>

04.03 概率统计方法 - 图8

不同自由度的学生 t 分布

In [19]:

  1. x = linspace(-3, 3, 100)
  2.  
  3. plot(x, t.pdf(x, 1), label='df=1')
  4. plot(x, t.pdf(x, 2), label='df=2')
  5. plot(x, t.pdf(x, 100), label='df=100')
  6. plot(x[::5], norm.pdf(x[::5]), 'kx', label='normal')
  7.  
  8. legend()

Out[19]:

  1. <matplotlib.legend.Legend at 0x164582e8>

04.03 概率统计方法 - 图9

离散分布

导入离散分布:

In [20]:

  1. from scipy.stats import binom, poisson, randint

离散分布没有概率密度函数,但是有概率质量函数

离散均匀分布的概率质量函数(PMF):

In [21]:

  1. high = 10
  2. low = -10
  3.  
  4. x = arange(low, high+1, 0.5)
  5. p = stem(x, randint(low, high).pmf(x)) # 杆状图

04.03 概率统计方法 - 图10

二项分布

In [22]:

  1. num_trials = 60
  2. x = arange(num_trials)
  3.  
  4. plot(x, binom(num_trials, 0.5).pmf(x), 'o-', label='p=0.5')
  5. plot(x, binom(num_trials, 0.2).pmf(x), 'o-', label='p=0.2')
  6.  
  7. legend()

Out[22]:

  1. <matplotlib.legend.Legend at 0x1738a198>

04.03 概率统计方法 - 图11

泊松分布

In [23]:

  1. x = arange(0,21)
  2.  
  3. plot(x, poisson(1).pmf(x), 'o-', label=r'$\lambda$=1')
  4. plot(x, poisson(4).pmf(x), 'o-', label=r'$\lambda$=4')
  5. plot(x, poisson(9).pmf(x), 'o-', label=r'$\lambda$=9')
  6.  
  7. legend()

Out[23]:

  1. <matplotlib.legend.Legend at 0x1763e320>

04.03 概率统计方法 - 图12

自定义离散分布

导入要用的函数:

In [24]:

  1. from scipy.stats import rv_discrete

一个不均匀的骰子对应的离散值及其概率:

In [25]:

  1. xk = [1, 2, 3, 4, 5, 6]
  2. pk = [.3, .35, .25, .05, .025, .025]

定义离散分布:

In [26]:

  1. loaded = rv_discrete(values=(xk, pk))

此时, loaded 可以当作一个离散分布的模块来使用。

产生两个服从该分布的随机变量:

In [27]:

  1. loaded.rvs(size=2)

Out[27]:

  1. array([3, 1])

产生100个随机变量,将直方图与概率质量函数进行比较:

In [28]:

  1. samples = loaded.rvs(size=100)
  2. bins = linspace(.5,6.5,7)
  3.  
  4. hist(samples, bins=bins, normed=True)
  5. stem(xk, loaded.pmf(xk), markerfmt='ro', linefmt='r-')

Out[28]:

  1. <Container object of 3 artists>

04.03 概率统计方法 - 图13

假设检验

导入相关的函数:

In [29]:

  1. from scipy.stats import norm
  2. from scipy.stats import ttest_ind, ttest_rel, ttest_1samp
  3. from scipy.stats import t

独立样本 t 检验

两组参数不同的正态分布:

In [30]:

  1. n1 = norm(loc=0.3, scale=1.0)
  2. n2 = norm(loc=0, scale=1.0)

从分布中产生两组随机样本:

In [31]:

  1. n1_samples = n1.rvs(size=100)
  2. n2_samples = n2.rvs(size=100)

将两组样本混合在一起:

In [32]:

  1. samples = hstack((n1_samples, n2_samples))

最大似然参数估计:

In [33]:

  1. loc, scale = norm.fit(samples)
  2. n = norm(loc=loc, scale=scale)

比较:

In [34]:

  1. x = linspace(-3,3,100)
  2.  
  3. hist([samples, n1_samples, n2_samples], normed=True)
  4. plot(x, n.pdf(x), 'b-')
  5. plot(x, n1.pdf(x), 'g-')
  6. plot(x, n2.pdf(x), 'r-')

Out[34]:

  1. [<matplotlib.lines.Line2D at 0x17ca7278>]

04.03 概率统计方法 - 图14

独立双样本 t 检验的目的在于判断两组样本之间是否有显著差异:

In [35]:

  1. t_val, p = ttest_ind(n1_samples, n2_samples)
  2.  
  3. print 't = {}'.format(t_val)
  4. print 'p-value = {}'.format(p)
  1. t = 0.868384594123
  2. p-value = 0.386235148899

p 值小,说明这两个样本有显著性差异。

配对样本 t 检验

配对样本指的是两组样本之间的元素一一对应,例如,假设我们有一组病人的数据:

In [36]:

  1. pop_size = 35
  2.  
  3. pre_treat = norm(loc=0, scale=1)
  4. n0 = pre_treat.rvs(size=pop_size)

经过某种治疗后,对这组病人得到一组新的数据:

In [37]:

  1. effect = norm(loc=0.05, scale=0.2)
  2. eff = effect.rvs(size=pop_size)
  3.  
  4. n1 = n0 + eff

新数据的最大似然估计:

In [38]:

  1. loc, scale = norm.fit(n1)
  2. post_treat = norm(loc=loc, scale=scale)

画图:

In [39]:

  1. fig = figure(figsize=(10,4))
  2.  
  3. ax1 = fig.add_subplot(1,2,1)
  4. h = ax1.hist([n0, n1], normed=True)
  5. p = ax1.plot(x, pre_treat.pdf(x), 'b-')
  6. p = ax1.plot(x, post_treat.pdf(x), 'g-')
  7.  
  8. ax2 = fig.add_subplot(1,2,2)
  9. h = ax2.hist(eff, normed=True)

04.03 概率统计方法 - 图15

独立 t 检验:

In [40]:

  1. t_val, p = ttest_ind(n0, n1)
  2.  
  3. print 't = {}'.format(t_val)
  4. print 'p-value = {}'.format(p)
  1. t = -0.347904839913
  2. p-value = 0.728986322039

p 值说明两组样本之间没有显著性差异。

配对 t 检验:

In [41]:

  1. t_val, p = ttest_rel(n0, n1)
  2.  
  3. print 't = {}'.format(t_val)
  4. print 'p-value = {}'.format(p)
  1. t = -1.89564459709
  2. p-value = 0.0665336223673

配对 t 检验的结果说明,配对样本之间存在显著性差异,说明治疗时有效的,符合我们的预期。

p 值计算原理

p 值对应的部分是下图中的红色区域,边界范围由 t 值决定。

In [42]:

  1. my_t = t(pop_size) # 传入参数为自由度,这里自由度为50
  2.  
  3. p = plot(x, my_t.pdf(x), 'b-')
  4. lower_x = x[x<= -abs(t_val)]
  5. upper_x = x[x>= abs(t_val)]
  6.  
  7. p = fill_between(lower_x, my_t.pdf(lower_x), color='red')
  8. p = fill_between(upper_x, my_t.pdf(upper_x), color='red')

04.03 概率统计方法 - 图16

原文: https://nbviewer.jupyter.org/github/lijin-THU/notes-python/blob/master/04-scipy/04.03-statistics-with-scipy.ipynb