第47单元 以 Python 的方式完成统计
Python对随机数和统计的支持分散在以下多个模块中:statistics、numpy.random、pandas和scipy.stats。
生成随机数
numpy.random模块中包含所有主要概率分布的随机数生成器。
本书在第1章中就指出,数据分析的代码应该是可复现的:任何人都应该能够使用相同的输入数据运行相同的程序,并获得相同的结果。因此,你应该始终使用seed()函数来初始化伪随机种子,否则,随机数生成器在每个程序运行时会产生不同的伪随机序列,这可能使结果难以乃至不可能复现。
import numpy.random as rnd rnd.seed(z)
下面的函数产生均匀、正态以及二项分布的整数和实值随机数。这些函数都返回一个具有shape或size的numpy数组(shape是一个由各个维度组成的列表),除非size的参数设置为None。
rnd.uniform(low=0.0, high=1.0, size=None) rnd.rand(shape) # 等同于uniform(0.0, 1.0, None) rnd.randint(low, high=None, size=None) rnd.normal(loc=0.0, scale=1.0, size=None) rnd.randn(shape) # 等同于normal(0.0, 1.0, shape) rnd.binomial(n, p, size=None)
当需要设置预测实验并将数据分为训练集和测试集时,二项分布是必不可少的(更多关于预测实验的内容,请参考第48单元)。令训练集的相对大小为p,测试集的相对大小为1-p。你可以准备一个二值序列,然后将其转换为True和False值的布尔序列,最后通过pandas的frame选出两个集合:
selection = rnd.binomial(1, p, size=len(data)).astype(bool) training = df[selection] testing = df[-selection]
计算统计度量
作为一种快速而随性的计算统计度量的方式,statistics模块(本书首次提及该模块是在第14单元)提供低端函数mean()和stdev()。
pandas的frame和series具有用于计算与其他frame和series的相关性和协方差的函数,也有计算frame的列之间的两两相关性和协方差(但没有p值)以及其他统计度量的函数。
让我们再次使用第31单元中被转换为frame的NIAAA监控报告,来探索pandas的统计功能。(我们不是醉汉!我们是数据科学家:一旦得到了一个好的数据集,我们将最大限度地使用它!)准备两个series,然后计算它们的相关性、协方差和偏斜度:
beer_seriesNY = alco.ix['New York']['Beer'] beer_seriesCA = alco.ix['California']['Beer'] beer_seriesNY.corr(beer_seriesCA) ➾ 0.97097785391654789 beer_seriesCA.cov(beer_seriesNY) ➾ 0.017438162878787872 [x.skew() for x in (beer_seriesCA, beer_seriesNY)] ➾ [0.16457291293004678, 0.32838100586347024]
我们也可以对frame应用相同的函数:
frameNY = alco.ix['New York'] frameNY.skew() ➾ Beer 0.328381 ➾ Wine 0.127308 ➾ Spirits 0.656699 ➾ dtype: float64 frameNY.corr() # 所有的两两相关性 ➾ Beer Wine Spirits ➾ Beer 1.000000 0.470690 0.908969 ➾ Wine 0.470690 1.000000 0.611923 ➾ Spirits 0.908969 0.611923 1.000000 frameNY.cov() # 所有的两两协方差 ➾ Beer Wine Spirits ➾ Beer 0.016103 0.002872 0.026020 ➾ Wine 0.002872 0.002312 0.006638 ➾ Spirits 0.026020 0.006638 0.050888
后两个函数分别返回包含所有两两相关性及所有两两协方差的frame。
我们还可以将一个series和一个frame相关联,也可以将一个frame和另一个frame相关联。例如,使用美国人口普查局2000年至2009年间的数据1,分析纽约的酒精消费与国家人口之间是否存在某种相关性:
1www.census.gov/popest/data/historical/2000s/vintage_2009/state.html
# 移除最后两行:因为这两行数据包含了对未来的估计值 pop_seriesNY = pop.ix["New York"][:-2] # 将索引由日期变为整数年 pop_seriesNY.index = pop_seriesNY.index.str.split().str[-1].astype(int) frameNY.ix[2000:2009].corrwith(pop_seriesNY) ➾ Beer -0.520878 ➾ Wine 0.936026 ➾ Spirits 0.957697 ➾ dtype: float64
请注意,frame和series中的行是以相反的顺序排列的。pandas非常智能,可以使用行索引来匹配正确的行。当然,真正起作用的是数据对齐机制。(第36单元详细讨论了数据对齐方式。)
要估计相关性的显著程度,请使用scipy.stats模块中的pearsonr()函数。该函数返回相关性和p值,但它不能与pandas的frame集成,也不支持索引,所以你需要将索引对齐并将结果转换回frame。
from scipy.stats import pearsonr # 手动排列索引 pop_sorted = pop_seriesNY.sort_index() alco_10 = alco.ix['New York'][-10:] # 使用列表解析的方式计算所有的相关性和p值 corrs = [(bev,) + pearsonr(alco_10[bev], pop_sorted) for bev in alco_10.columns] # 将列表转换为frame pd.DataFrame(corrs, columns=("bev", "r", "p-value")).set_index("bev") ➾ r p-value ➾ bev ➾ Beer -0.520878 0.122646 ➾ Wine 0.936026 0.000068 ➾ Spirits 0.957697 0.000013
请注意,“啤酒”相关性的p值是非常高的。根据第46单元中的表6,我们得出结论,人口与啤酒消费之间不存在线性关系。
我们现在完全有能力重新审视第36单元中的交叉表的例子。根据交叉表的分析,我们得出2009年的人均啤酒消费量和葡萄酒消费量可能是线性独立的。皮尔逊相关性分析完全证实了我们的说法:
alco2009.corr() ➾ Beer Wine Spirits ➾ Beer 1.000000 -0.031560 0.452279 ➾ Wine -0.031560 1.000000 0.599791 ➾ Spirits 0.452279 0.599791 1.000000
相关性具有极高的p值,这为我们的假设提供了致命一击:
pearsonr(alco2009["Wine"], alco2009["Beer"]) ➾ (-0.031560488300856844, 0.82598481310787297)
下面的散点图解释了原因:这些点差不多散布在整幅图上,没有特定的顺序或规律。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论