提交 c51f43c7 编写于 作者: W wizardforcel
......@@ -323,3 +323,36 @@
+ [五、强化学习](docs/ml-for-humans/5.md)
+ [六、最好的机器学习资源](docs/ml-for-humans/6.md)
+ [机器学习超级复习笔记](docs/super-machine-learning-revision-notes/README.md)
+ [Python 自然语言处理 第二版](docs/nlp-py-2e/README.md)
+ [前言](docs/nlp-py-2e/0.md)
+ [1 语言处理与 Python](docs/nlp-py-2e/1.md)
+ [2 获得文本语料和词汇资源](docs/nlp-py-2e/2.md)
+ [3 处理原始文本](docs/nlp-py-2e/3.md)
+ [4 编写结构化程序](docs/nlp-py-2e/4.md)
+ [5 分类和标注词汇](docs/nlp-py-2e/5.md)
+ [6 学习分类文本](docs/nlp-py-2e/6.md)
+ [7 从文本提取信息](docs/nlp-py-2e/7.md)
+ [8 分析句子结构](docs/nlp-py-2e/8.md)
+ [9 构建基于特征的语法](docs/nlp-py-2e/9.md)
+ [10 分析句子的意思](docs/nlp-py-2e/10.md)
+ [11 语言学数据管理](docs/nlp-py-2e/11.md)
+ [后记:语言的挑战](docs/nlp-py-2e/12.md)
+ [索引](docs/nlp-py-2e/14.md)
+ [计算与推断思维](docs/data8-textbook-zh/README.md)
+ [一、数据科学](docs/data8-textbook-zh/1.md)
+ [二、因果和实验](docs/data8-textbook-zh/2.md)
+ [三、Python 编程](docs/data8-textbook-zh/3.md)
+ [四、数据类型](docs/data8-textbook-zh/4.md)
+ [五、表格](docs/data8-textbook-zh/5.md)
+ [六、可视化](docs/data8-textbook-zh/6.md)
+ [七、函数和表格](docs/data8-textbook-zh/7.md)
+ [八、随机性](docs/data8-textbook-zh/8.md)
+ [九、经验分布](docs/data8-textbook-zh/9.md)
+ [十、假设检验](docs/data8-textbook-zh/10.md)
+ [十一、估计](docs/data8-textbook-zh/11.md)
+ [十二、为什么均值重要](docs/data8-textbook-zh/12.md)
+ [十三、预测](docs/data8-textbook-zh/13.md)
+ [十四、回归的推断](docs/data8-textbook-zh/14.md)
+ [十五、分类](docs/data8-textbook-zh/15.md)
+ [十六、比较两个样本](docs/data8-textbook-zh/16.md)
+ [十七、更新预测](docs/data8-textbook-zh/17.md)
# 一、数据科学
> 原文:[Data Science](https://github.com/data-8/textbook/tree/gh-pages/chapters/01)
> 译者:[飞龙](https://github.com/wizardforcel)
> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
> 自豪地采用[谷歌翻译](https://translate.google.cn/)
## 什么是数据科学
数据科学是通过探索,预测和推断,从大量不同的数据集中得出有用的结论。探索涉及识别信息中的规律。预测涉及使用我们所知道的信息,对我们希望知道的值作出知情的猜测。推断涉及量化我们的确定程度:我们发现的这些规律是否也出现在新的观察中?我们的预测有多准确?我们用于探索的主要工具是可视化和描述性统计,用于预测的是机器学习和优化,用于推理的是统计测试和模型。
统计学是数据科学的核心部分,因为统计学研究,如何用不完整的信息做出有力的结论。计算是一个重要组成部分,因为编程允许我们将分析技巧应用于大量不同的数据集,它们在真实应用中出现:不仅包括数字,还包括文本,图像,视频和传感器读数。数据科学就是所有这些东西,但是由于应用的原因,它不仅仅是其部分的总和。通过理解一个特定的领域,数据科学家学习提出有关他们的数据的适当的问题,并正确地解释我们的推理和计算工具提供的答案。
## 简介
数据是对我们周围世界的描述,通过观察来收集并存储在计算机上。计算机使我们能够从这些描述中推断出世界的特性。数据科学是使用计算从数据中得出结论的学科。有效的数据分析有三个核心方面:探索,预测和推理。本文对三者进行了一致的研究,同时介绍了统计思想和计算机科学的基本思想。我们专注于一套最小的核心技巧,应用于广泛的实际应用。数据科学的基础不仅需要理解统计和计算技巧,还需要认识到它们如何应用于真实场景。
对于我们希望研究的世界的任何方面,无论是地球气象,世界市场,政治民意调查还是人类思想,我们收集的数据通常都提供了这个主题的不完整描述。数据科学的核心挑战是使用这部分信息作出可靠的结论。
在这个努力中,我们将结合两个基本工具:计算和随机化。例如,我们可能想使用温度观测来了解气候变化的趋势。计算机允许我们使用所有可用的信息得出结论。我们不仅仅关注一个地区的平均气温,而是将整个温度的范围一起考虑,来构建更加细致的分析。随机性允许我们考虑许多不同方式,来完善不完整的信息。我们不会假设温度会以某种特定的方式变化,而是学习使用随机性来设想许多可能的情景,这些情景都与我们观察到的数据一致。
应用这种方法需要学习,如何为一台计算机编程,所以这个文本穿插了编程的完整介绍,并假设没有任何先验知识。 具有编程经验的读者会发现,我们涵盖了计算中的几个主题,这些主题并没有出现在典型的计算机科学课程中。 数据科学也需要对数量进行仔细的推理,但是本书并不假设超出基本代数的数学或统计背景。 在本文中你会发现很少的方程。 相反,技巧使用一种编程语言描述,对于读者和执行它们的计算机来说,是相同的。
### 计算工具
本文使用 Python 3 编程语言,以及数值和数据可视化的标准工具集,它们在商业应用,科学实验和开源项目中广泛使用。 Python 已经招募了许多专业人士,它们使用数据得出结论。通过学习 Python 语言,你将加入一个拥有百万人口的,软件开发人员和数据科学家社区。
入门。开始用 Python 编写程序的最简单和推荐的方法是,登录到本文的配套网站 <https://datahub.berkeley.edu/>。如果你拥有`@ berkeley.edu`电子邮件地址,则你已经可以完全访问该网站上托管的编程环境。如果没有,请填写[此表格](https://goo.gl/forms/saQpxdqzS2rKxjTc2)来申请访问。
你不能完全仅仅使用这个基于 Web 的编程环境。 Python 程序可以由任何计算机执行,无论其制造商或操作系统如何,只要安装了该语言的支持。如果你希望安装符合本文的 Python 版本及其附带库,我们推荐将 Anaconda 发行版与 Python 3 语言解释器,IPython 库和 Jupyter 笔记本环境打包在一起。
本文包括所有这些计算工具的完整介绍。你将学习编写程序,从数据生成图像,并使用在线发布的真实世界的数据集。
### 统计技巧
统计学科长期以来一直面临与数据科学相同的根本挑战:如何使用不完整的信息得出有关世界的有力结论。统计学最重要的贡献之一是,用于描述观察与结论之间关系的,一致而准确的词汇。本文继续保持同样的传统,重点是统计学中的一组核心推断问题:假设检验,置信度估计和未知量预测。
数据科学通过充分利用计算,数据可视化,机器学习,优化和信息访问来扩展统计领域。快速计算机和互联网的结合使得任何人都能够访问和分析大量的数据集:数百万篇新闻文章,完整的百科全书,任何领域的数据库以及大量的音乐,照片和视频库。
真实数据集的应用激发了我们在整个文本中描述的统计技巧。真实数据通常没有规律或匹配标准方程。如果把过多的注意力集中在简单的总结上,比如平均值,那么真实数据中有趣的变化就会丢失。计算机使一系列基于重采样的方法成为可能,它们适用于各种不同的推理问题,考虑了所有可用的信息,并且需要很少的假设或条件。虽然这些技巧经常留作统计学的研究生课程,但它们的灵活性和简单性非常适合数据科学应用。
## 为什么是数据科学
最重要的决策仅仅使用部分信息和不确定的结果做出。然而,许多决策的不确定性,可以通过获取大量公开的数据集和有效分析所需的计算工具,而大幅度降低。以数据为导向的决策已经改变了一大批行业,包括金融,广告,制造业和房地产。同时,大量的学科正在迅速发展,将大规模的数据分析纳入其理论和实践。
学习数据科学使个人能够将这些技巧用于工作,科学研究和个人决策。批判性思维一直是严格教育的标志,但在数据支持下,批判往往是最有效的。对世界任何方面的批判性分析,可能是商业或社会科学,涉及归纳推理;结论很少直接证明,仅仅由现有的证据支持。数据科学提供了手段,对任何一组观测结果进行精确,可靠和定量的论证。有了信息和计算机的前所未有的访问,如果没有有效的推理技巧,对世界上任何可以衡量的方面的批判性思考都是不完整的。
世界上有太多没有答案的问题和困难的挑战,所以不能把这个批判性的推理留给少数专家。所有受过教育的社会成员都可以建立推断数据的能力。这些工具,技巧和数据集都是随手可用的;本文的目的是使所有人都能访问它们。
## 绘制经典作品
在这个例子中,我们将探讨两个经典小说的统计:马克吐温(Mark Twain)的《哈克贝利·芬历险记》(The Adventures of Huckleberry Finn)和路易莎·梅·奥尔科特(Louisa May Alcott)的《小女人》(Little Women)。任何一本书的文本都可以通过电脑以极快的速度读取。 1923 年以前出版的书籍目前处于公有领域,这意味着每个人都有权以任何方式复制或使用文本。 [古登堡计划](http://www.gutenberg.org/)是一个在线出版公共领域书籍的网站。使用 Python,我们可以直接从网络上加载这些书籍的文本。
这个例子是为了说明本书的一些广泛的主题。如果还不理解程序的细节,别担心。相反,重点关注下面生成的图像。后面的部分将介绍下面使用的 Python 编程语言的大部分功能。
首先,我们将这两本书的内容读入章节列表中,称为`huck_finn_chapters``little_women_chapters`。在 Python 中,名称不能包含任何空格,所以我们经常使用下划线`_`来代表空格。在下面的行中,左侧提供了一个名称,右侧描述了一些计算的结果。统一资源定位符或 URL 是互联网上某些内容的地址;这里是一本书的文字。`#`符号是注释的起始,计算机会忽略它,但有助于人们阅读代码。
```py
# Read two books, fast!
huck_finn_url = 'https://www.inferentialthinking.com/chapters/01/3/huck_finn.txt'
huck_finn_text = read_url(huck_finn_url)
huck_finn_chapters = huck_finn_text.split('CHAPTER ')[44:]
little_women_url = 'https://www.inferentialthinking.com/chapters/01/3/little_women.txt'
little_women_text = read_url(little_women_url)
little_women_chapters = little_women_text.split('CHAPTER ')[1:]
```
虽然计算机不能理解书的文本,它可以向我们提供文本结构的一些视角。名称`huck_finn_chapters`现在已经绑定到书中章节的列表。我们可以将其放到一个表中,来观察每一章的开头。
```py
# Display the chapters of Huckleberry Finn in a table.
Table().with_column('Chapters', huck_finn_chapters)
```
| Chapters |
| --- |
| I. YOU don't know about me without you have read a book ... |
| II. WE went tiptoeing along a path amongst the trees bac ... |
| III. WELL, I got a good going-over in the morning from o ... |
| IV. WELL, three or four months run along, and it was wel ... |
| V. I had shut the door to. Then I turned around and ther ... |
| VI. WELL, pretty soon the old man was up and around agai ... |
| VII. "GIT up! What you 'bout?" I opened my eyes and look ... |
| VIII. THE sun was up so high when I waked that I judged ... |
| IX. I wanted to go and look at a place right about the m ... |
| X. AFTER breakfast I wanted to talk about the dead man a ... |
(已省略 33 行)
每一章都以章节号开头,以罗马数字的形式,后面是本章的第一个句子。古登堡计划将每章的第一个单词变为大写。
### 文本特征
《哈克贝利·芬历险记》描述了哈克和吉姆沿着密西西比河的旅程。汤姆·索亚(Tom Sawyer)在行动进行的时候加入了他们的行列。在加载文本后,我们可以快速地看到这些字符在本书的任何一处被提及的次数。
```py
# Count how many times the names Jim, Tom, and Huck appear in each chapter.
counts = Table().with_columns([
'Jim', np.char.count(huck_finn_chapters, 'Jim'),
'Tom', np.char.count(huck_finn_chapters, 'Tom'),
'Huck', np.char.count(huck_finn_chapters, 'Huck')
])
# Plot the cumulative counts:
# how many times in Chapter 1, how many times in Chapters 1 and 2, and so on.
cum_counts = counts.cumsum().with_column('Chapter', np.arange(1, 44, 1))
cum_counts.plot(column_for_xticks=3)
plots.title('Cumulative Number of Times Each Name Appears', y=1.08);
```
![](img/1-1.png)
在上图中,横轴显示章节号,纵轴显示每个字符在该章节被提及到的次数。
吉姆是核心人物,它的名字出现了很多次。请注意,第 30 章中汤姆出现并加入了哈克和吉姆,在此之前,汤姆在本书中几乎没有提及。他和吉姆的曲线在这个位置上迅速上升,因为涉及两者的行动都在变多。至于哈克,他的名字几乎没有出现,因为他是叙述者。
《小女人》是南北战争期间四个姐妹一起长大的故事。 在这本书中,章节号码拼写了出来,章节标题用大写字母表示。
```py
# The chapters of Little Women, in a table
Table().with_column('Chapters', little_women_chapters)
```
| Chapters |
| --- |
| ONE PLAYING PILGRIMS "Christmas won't be Christmas witho ... |
| TWO A MERRY CHRISTMAS Jo was the first to wake in the gr ... |
| THREE THE LAURENCE BOY "Jo! Jo! Where are you?" cried Me ... |
| FOUR BURDENS "Oh, dear, how hard it does seem to take up ... |
| FIVE BEING NEIGHBORLY "What in the world are you going t ... |
| SIX BETH FINDS THE PALACE BEAUTIFUL The big house did pr ... |
| SEVEN AMY'S VALLEY OF HUMILIATION "That boy is a perfect ... |
| EIGHT JO MEETS APOLLYON "Girls, where are you going?" as ... |
| NINE MEG GOES TO VANITY FAIR "I do think it was the most ... |
| TEN THE P.C. AND P.O. As spring came on, a new set of am ... |
(已省略 37 行)
我们可以跟踪主要人物的提及,来了解本书的情节。 主角乔(Jo)和她的姐妹梅格(Meg),贝丝(Beth)和艾米(Amy)经常互动,直到第 27 章中她独自搬到纽约。
```py
# Counts of names in the chapters of Little Women
counts = Table().with_columns([
'Amy', np.char.count(little_women_chapters, 'Amy'),
'Beth', np.char.count(little_women_chapters, 'Beth'),
'Jo', np.char.count(little_women_chapters, 'Jo'),
'Meg', np.char.count(little_women_chapters, 'Meg'),
'Laurie', np.char.count(little_women_chapters, 'Laurie'),
])
# Plot the cumulative counts.
cum_counts = counts.cumsum().with_column('Chapter', np.arange(1, 48, 1))
cum_counts.plot(column_for_xticks=5)
plots.title('Cumulative Number of Times Each Name Appears', y=1.08);
```
![](img/1-2.png)
劳里(Laurie)是个年轻人,最后和其中一个女孩结婚。 看看你是否可以使用这个图来猜测是哪一个。
### 另一种文本特征
在某些情况下,数量之间的关系能让我们做出预测。 本文将探讨如何基于不完整的信息做出准确的预测,并研究结合多种不确定信息来源进行决策的方法。
作为从多个来源获取信息的可视化的例子,让我们首先使用计算机来获取一些信息,它们通常手工难以获取。在小说的语境中,“特征”(Character)这个词有第二个含义:一个印刷符号,如字母,数字或标点符号。 在这里,我们要求计算机来计算《哈克贝利·芬》和《小女人》的每章中的字符和句号数量。
```py
# In each chapter, count the number of all characters;
# call this the "length" of the chapter.
# Also count the number of periods.
chars_periods_huck_finn = Table().with_columns([
'Huck Finn Chapter Length', [len(s) for s in huck_finn_chapters],
'Number of Periods', np.char.count(huck_finn_chapters, '.')
])
chars_periods_little_women = Table().with_columns([
'Little Women Chapter Length', [len(s) for s in little_women_chapters],
'Number of Periods', np.char.count(little_women_chapters, '.')
])
```
这里是《哈克贝利·芬》的数据。 表格的每一行对应小说的一个章节,并显示章节中的字符和句号数量。 毫不奇怪,字符少的章节往往句号也少,一般来说 - 章节越短,句子越少,反之亦然。 然而,这种关系并不是完全可以预测的,因为句子的长度各不相同,还可能涉及其他标点符号,例如问号。
`chars_periods_huck_finn`
| 《哈克贝利·芬》章节长度 | 句号数量 |
| --- | --- |
| 7026 | 66 |
| 11982 | 117 |
| 8529 | 72 |
| 6799 | 84 |
| 8166 | 91 |
| 14550 | 125 |
| 13218 | 127 |
| 22208 | 249 |
| 8081 | 71 |
| 7036 | 70 |
(已省略 33 行)
这里是《小女人》的对应数据:
`chars_periods_little_women`
| 《小女人》章节长度 | 句号数量 |
| --- | --- |
| 21759 | 189 |
| 22148 | 188 |
| 20558 | 231 |
| 25526 | 195 |
| 23395 | 255 |
| 14622 | 140 |
| 14431 | 131 |
| 22476 | 214 |
| 33767 | 337 |
| 18508 | 185 |
(已省略 37 行)
你可以看到,《小女人》的章节总的来说比《哈克贝利·芬》的章节要长。让我们来看看这两个简单的变量 - 每一章的长度和句子数量 - 能否告诉我们这两本书的更多内容。 我们实现它的一个方法是在同一个图上绘制两组数据。
在下面的图中,每本书的每一章都有一个点。 蓝色圆点对应于《哈克贝利·芬》,金色圆点对应于《小女人》。横轴表示句号数量,纵轴表示字符数。
```py
plots.figure(figsize=(6, 6))
plots.scatter(chars_periods_huck_finn.column(1),
chars_periods_huck_finn.column(0),
color='darkblue')
plots.scatter(chars_periods_little_women.column(1),
chars_periods_little_women.column(0),
color='gold')
plots.xlabel('Number of periods in chapter')
plots.ylabel('Number of characters in chapter');
```
![](img/1-3.png)
这个绘图向我们展示,《小女人》的许多章节,而不是所有章节都比《哈克贝利·芬》的章节长,正如我们通过查看数字所看到的那样。 但它也向我们展示了更多东西。 请注意,蓝点粗略聚集在一条直线上,黄点也是如此。 此外看起来,两种颜色的点可能聚集在同一条直线上。
现在查看包含大约 100 个句号的所有章节。 绘图显示,这些章节大致包含约 10,000 个字符到约 15,000 个字符。每个句子大约有 100 到 150 个字符。
事实上,从这个绘图看来,这两本书的两个句号之间平均有 100 到 150 个字符,这是一个非常粗略的估计。 也许这两个伟大的 19 世纪小说正在表明我们现在非常熟悉的东西:Twitter 的 140 个字符的限制。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
# 十四、回归的推断
> 原文:[Inference for Regression](https://github.com/data-8/textbook/tree/gh-pages/chapters/14)
> 译者:[飞龙](https://github.com/wizardforcel)
> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
> 自豪地采用[谷歌翻译](https://translate.google.cn/)
到目前为止,我们对变量之间关系的分析纯粹是描述性的。我们知道如何找到穿过散点图的最佳直线来绘制。在所有直线中它的估计的均方误差最小,从这个角度来看,这条线是最好的。
但是,如果我们的数据是更大总体的样本呢?如果我们在样本中发现了两个变量之间的线性关系,那么对于总体也是如此嘛?它会是完全一样的线性关系吗?我们可以预测一个不在我们样本中的新的个体的响应变量吗?
如果我们认为,散点图反映了被绘制的两个变量之间的基本关系,但是并没有完全规定这种关系,那么就会出现这样的推理和预测问题。例如,出生体重与孕期的散点图,显示了我们样本中两个变量之间的精确关系;但是我们可能想知道,对于抽样总体中的所有新生儿或实际中的一般新生儿,这样的关系是否是真实的,或者说几乎是正确的。
一如既往,推断思维起始于仔细检查数据的假设。一组假设被称为模型。大致线性的散点图中的一组随机性的假设称为回归模型。
## 回归模型
简而言之,这样的模型认为,两个变量之间的底层关系是完全线性的;这条直线是我们想要识别的信号。但是,我们无法清楚地看到这条线。我们看到的是分散在这条线上的点。在每一点上,信号都被随机噪声污染。因此,我们的推断目标是将信号从噪声中分离出来。
更详细地说,回归模型规定了,散点图中的点是随机生成的,如下所示。
+ `x``y`之间的关系是完全线性的。我们看不到这个“真实直线”,但它是存在的。
+ 散点图通过将线上的点垂直移动,或上或下来创建,如下所示:
+ 对于每个`x`,找到真实直线上的相应点(即信号),然后生成噪声或误差。
+ 误差从误差总体中带放回随机抽取,总体是均值为 0 的正态分布。
+ 创建一个点,横坐标为`x`,纵坐标为“`x`处的真实高度加上误差”。
+ 最后,从散点图中删除真正的线,只显示创建的点。
基于这个散点图,我们应该如何估计真实直线? 我们可以使其穿过散点图的最佳直线是回归线。 所以回归线是真实直线的自然估计。
下面的模拟显示了回归直线与真实直线的距离。 第一个面板显示如何从真实直线生成散点图。 第二个显示我们看到的散点图。 第三个显示穿过散点图的回归线。 第四个显示回归线和真实直线。
为了运行模拟,请使用三个参数调用`draw_and_compare`函数:真实直线的斜率,真实直线的截距以及样本量。
运行模拟几次,用不同的斜率和截距,以及不同的样本量。 因为所有的点都是根据模型生成的,所以如果样本量适中,你会看到回归线是真实直线的一个良好估计。
```py
# The true line,
# the points created,
# and our estimate of the true line.
# Arguments: true slope, true intercept, number of points
draw_and_compare(4, -5, 10)
```
![](img/14-1.png)
实际上,我们当然不会看到真实直线。 模拟结果表明,如果回归模型看起来合理,并且如果我们拥有大型样本,那么回归线就是真实直线的一个良好近似。
## 真实斜率的推断
我们的模拟表明,如果回归模型成立,并且样本量很大,则回归线很可能接近真实直线。 这使我们能够估计真实直线的斜率。
我们将使用我们熟悉的母亲和她们的新生儿的样本,来开发估计真实直线的斜率的方法。 首先,我们来看看我们是否相信,回归模型是一系列适当假设,用于描述出生体重和孕期之间的关系。
```py
correlation(baby, 'Gestational Days', 'Birth Weight')
0.40754279338885108
```
总的来说,散点图看起来相当均匀地分布在这条线上,尽管一些点分布在主云形的周围。 相关系数为 0.4,回归线斜率为正。
这是否反映真实直线斜率为正的事实? 为了回答这个问题,让我们看看我们能否估计真实斜率。 我们当然有了一个估计:我们的回归线斜率。 这大约是 0.47 盎司每天。
```py
slope(baby, 'Gestational Days', 'Birth Weight')
0.46655687694921522
```
但是如果散点图出现的方式不同,回归线会有所不同,可能会有不同的斜率。 我们如何计算,斜率可能有多么不同?
我们需要点的另一个样本,以便我们可以绘制回归线穿过新的散点图,并找出其斜率。 但另一个样本从哪里得到呢?
你猜对了 - 我们将自举我们的原始样本。 这会给我们自举的散点图,通过它我们可以绘制回归线。
### 自举散点图
我们可以通过对原始样本带放回地随机抽样,来模拟新样本,它的次数与原始样本量相同。 这些新样本中的每一个都会给我们一个散点图。 我们将这个称为自举散点图,简而言之,我们将调用整个过程来自举散点图。
这里是来自样本的原始散点图,以及自举重采样过程的四个复制品。 请注意,重采样散点图通常比原始图稀疏一点。 这是因为一些原始的点没有在样本中被选中。
![](img/14-3.png)
### 估计真实斜率
我们可以多次自举散点图,并绘制穿过每个自举图的回归线。 每条线都有一个斜率。 我们可以简单收集所有的斜率并绘制经验直方图。 回想一下,在默认情况下,`sample`方法带放回地随机抽取,次数与表中的行数相同。 也就是说,`sample`默认生成一个自举样本。
```py
slopes = make_array()
for i in np.arange(5000):
bootstrap_sample = baby.sample()
bootstrap_slope = slope(bootstrap_sample, 'Gestational Days', 'Birth Weight')
slopes = np.append(slopes, bootstrap_slope)
Table().with_column('Bootstrap Slopes', slopes).hist(bins=20)
```
![](img/14-4.png)
然后,我们可以使用`percentile `方法,为真实直线的斜率构建约 95% 置信区间。 置信区间从 5000 个自举斜率的第 2.5 百分位数,延伸到第 97.5 百分位数。
```py
left = percentile(2.5, slopes)
right = percentile(97.5, slopes)
left, right
(0.38209399211893086, 0.56014757838023777)
```
### 用于自举斜率的函数
让我们收集我们估计斜率的方法的所有步骤,并定义函数`bootstrap_slope`来执行它们。 它的参数是表的名称,预测变量和响应变量的标签,以及自举复制品的所需数量。 在每个复制品中,该函数自举原始散点图并计算所得回归线的斜率。 然后绘制所有生成的斜率的直方图,并打印由斜率的“中间 95%”组成的区间。
```py
def bootstrap_slope(table, x, y, repetitions):
# For each repetition:
# Bootstrap the scatter, get the slope of the regression line,
# augment the list of generated slopes
slopes = make_array()
for i in np.arange(repetitions):
bootstrap_sample = table.sample()
bootstrap_slope = slope(bootstrap_sample, x, y)
slopes = np.append(slopes, bootstrap_slope)
# Find the endpoints of the 95% confidence interval for the true slope
left = percentile(2.5, slopes)
right = percentile(97.5, slopes)
# Slope of the regression line from the original sample
observed_slope = slope(table, x, y)
# Display results
Table().with_column('Bootstrap Slopes', slopes).hist(bins=20)
plots.plot(make_array(left, right), make_array(0, 0), color='yellow', lw=8);
print('Slope of regression line:', observed_slope)
print('Approximate 95%-confidence interval for the true slope:')
print(left, right)
```
当响应变量为出生体重,预测变量为孕期时,我们调用`bootstrap_slope`来找到真实斜率的置信区间,我们得到了一个区间,非常接近我们之前获得的东西:大约 0.38 到 0.56 盎司每天。
```py
bootstrap_slope(baby, 'Gestational Days', 'Birth Weight', 5000)
Slope of regression line: 0.466556876949
Approximate 95%-confidence interval for the true slope:
0.378663152966 0.555005146304
```
![](img/14-5.png)
现在我们有一个函数,可以自动完成估计在回归模型中展示斜率的过程,我们也可以在其他变量上使用它。
例如,我们来看看出生体重与母亲身高的关系。 更高的女性往往有更重的婴儿吗?
回归模型似乎是合理的,基于散点图,但相关性不高。 这只有大约 0.2。
```py
scatter_fit(baby, 'Maternal Height', 'Birth Weight')
```
![](img/14-6.png)
```py
correlation(baby, 'Maternal Height', 'Birth Weight')
0.20370417718968034
```
像之前一样,我们使用`bootstrap_slope `来估计回归模型中真实直线的斜率。
```py
bootstrap_slope(baby, 'Maternal Height', 'Birth Weight', 5000)
Slope of regression line: 1.47801935193
Approximate 95%-confidence interval for the true slope:
1.0403083964 1.91576886223
```
![](img/14-7.png)
真实斜率的 95% 置信区间,从约 1 延伸到约 1.9 盎司每英寸。
### 真实斜率可能为 0 嘛?
假设我们相信我们的数据遵循回归模型,并且我们拟合回归线来估计真实直线。 如果回归线不完全是平的,几乎总是如此,我们将观察到散点图中的一些线性关联。
但是,如果这种观察是假的呢? 换句话说,如果真实直线是平的 - 也就是说,这两个变量之间没有线性关系 - 我们观察到的联系,只是由于从样本中产生点的随机性。
这是一个模拟,说明了为什么会出现这个问题。 我们将再次调用`draw_and_compare`函数,这次要求真实斜率为 0。我们的目标是,观察我们的回归线是否显示不为 0 的斜率。
请记住函数`draw_and_compare`的参数是真实直线的斜率和截距,以及要生成的点的数量。
```py
draw_and_compare(0, 10, 25)
```
![](img/14-8.png)
运行模拟几次,每次保持真实直线的斜率为 0 。你会注意到,虽然真实直线的斜率为 0,但回归线的斜率通常不为 0。回归线有时会向上倾斜,有时会向下倾斜,每次都给我们错误的印象,即这两个变量是相关的。
为了确定我们所看到的斜率是否真实,我们想测试以下假设:
原假设。真实直线的斜率是 0。
备选假设。真实直线的斜率不是 0。
我们很有条件来实现它。由于我们可以为真实斜率构建一个 95% 的置信区间,我们所要做的就是看区间是否包含 0。
如果没有,那么我们可以拒绝原假设(P 值为 5% 的截断值)。
如果真实斜率的置信区间确实包含 0,那么我们没有足够的证据来拒绝原假设。也许我们看到的斜率是假的。
我们在一个例子中使用这个方法。假设我们试图根据母亲的年龄来估计新生儿的出生体重。根据样本,根据母亲年龄估计出生体重的回归线的斜率为正,约为 0.08 盎司每年。
```py
slope(baby, 'Maternal Age', 'Birth Weight')
0.085007669415825132
```
虽然斜率为正,但是很小。 回归线非常接近平的,这就产生了一个问题,真实直线是否是平的。
```py
scatter_fit(baby, 'Maternal Age', 'Birth Weight')
```
![](img/14-9.png)
我们可以使用`bootstrap_slope`来估计真实直线的斜率。 计算表明,真实斜率的约 95% 的自举置信区间左端为负,右端为正 - 换句话说,区间包含 0。
```py
bootstrap_slope(baby, 'Maternal Age', 'Birth Weight', 5000)
Slope of regression line: 0.0850076694158
Approximate 95%-confidence interval for the true slope:
-0.104335243815 0.272791852339
```
![](img/14-10.png)
因为区间包含 0,所以我们不能拒绝原假设,母亲年龄与新生儿出生体重之间的真实线性关系的斜率为 0。基于此分析,使用母亲年龄作为预测变量,基于回归模型预测出生体重是不明智的。
## 预测区间
回归的主要用途之一是对新个体进行预测,这个个体不是我们原始样本的一部分,但是与样本个体相似。在模型的语言中,我们想要估计新值`x``y`
我们的估计是真实直线在`x`处的高度。当然,我们不知道真实直线。我们使用我们的样本点的回归线来代替。
给定值`x`的拟合值,是基于`x`值的`y`的回归估计。换句话说,给定值`x`的拟合值就是回归线在`x`处的高度。
假设我们试图根据孕期天数来预测新生儿的出生体重。我们在前面的章节中看到,这些数据非常适合回归模型,真实直线的斜率的 95% 置信区间不包含 0。因此,我们的预测似乎是合理的。
下图显示了预测位于回归线上的位置。红线是`x = 300`
![](img/14-11.png)
红线与回归线的相交点的高度是孕期天数 300 的拟合值。
函数`fitted_value`计算这个高度。像函数的相关性,斜率和截距一样,它的参数是表的名称和`x``y`的列标签。但是它也需要第四个参数,即`x`的值,在这个值上进行估算。
```py
def fitted_value(table, x, y, given_x):
a = slope(table, x, y)
b = intercept(table, x, y)
return a * given_x + b
```
孕期天数 300 的拟合值约为 129.2 盎司。 换句话说,对于孕期为 300 天的孕妇,我们估计的新生儿体重约为 129.2 盎司。
```py
fit_300 = fitted_value(baby, 'Gestational Days', 'Birth Weight', 300)
fit_300
129.2129241703143
```
### 预测的可变性
我们已经开发了一种方法,使用我们样本中的数据,根据孕期天数预测新生儿的体重。 但作为数据科学家,我们知道样本可能有所不同。 如果样本不同,回归线也会不一样,我们的预测也是。 为了看看我们的预测有多好,我们必须了解预测的可变性。
为此,我们必须生成新的样本。 我们可以像上一节那样,通过自举散点图来实现。 然后,我们为每个散点图的复制品拟合回归线,并根据每一行进行预测。 下图显示了 10 条这样的线,以及孕期天数 300 对应的出生体重预测。
![](img/14-12.png)
```py
lines
```
| slope | intercept | prediction at x=300 |
| --- | --- | --- |
| 0.503931 | -21.6998 | 129.479 |
| 0.53227 | -29.5647 | 130.116 |
| 0.518771 | -25.363 | 130.268 |
| 0.430556 | -1.06812 | 128.099 |
| 0.470229 | -11.7611 | 129.308 |
| 0.48713 | -16.5314 | 129.608 |
| 0.51241 | -23.2954 | 130.428 |
| 0.52473 | -27.2053 | 130.214 |
| 0.409943 | 5.22652 | 128.21 |
| 0.468065 | -11.6967 | 128.723 |
每一行的预测都不相同。 下表显示了 10 条线的斜率、截距以及预测。
### 自举预测区间
如果我们增加重采样过程的重复次数,我们可以生成预测的经验直方图。这将允许我们创建预测区间,使用为斜率创建自举置信区间时的相同的百分比方法。
让我们定义一个名为`bootstrap_prediction`的函数来实现。该函数有五个参数:
+ 表的名称
+ 预测变量和响应变量的列标签
+ 用于预测的`x`的值
+ 所需的自举重复次数
在每次重复中,函数将自举原始散点图,并基于`x`的指定值查找`y`的预测值。具体来说,它调用我们在本节前面定义的函数`fitted_value`,来寻找指定`x`处的拟合值。
最后,绘制所有预测值的经验直方图,并打印由预测值的“中间 95%”组成的区间。它还打印基于穿过原始散点图的回归线的预测值。
```py
# Bootstrap prediction of variable y at new_x
# Data contained in table; prediction by regression of y based on x
# repetitions = number of bootstrap replications of the original scatter plot
def bootstrap_prediction(table, x, y, new_x, repetitions):
# For each repetition:
# Bootstrap the scatter;
# get the regression prediction at new_x;
# augment the predictions list
predictions = make_array()
for i in np.arange(repetitions):
bootstrap_sample = table.sample()
bootstrap_prediction = fitted_value(bootstrap_sample, x, y, new_x)
predictions = np.append(predictions, bootstrap_prediction)
# Find the ends of the approximate 95% prediction interval
left = percentile(2.5, predictions)
right = percentile(97.5, predictions)
# Prediction based on original sample
original = fitted_value(table, x, y, new_x)
# Display results
Table().with_column('Prediction', predictions).hist(bins=20)
plots.xlabel('predictions at x='+str(new_x))
plots.plot(make_array(left, right), make_array(0, 0), color='yellow', lw=8);
print('Height of regression line at x='+str(new_x)+':', original)
print('Approximate 95%-confidence interval:')
print(left, right)
bootstrap_prediction(baby, 'Gestational Days', 'Birth Weight', 300, 5000)
Height of regression line at x=300: 129.21292417
Approximate 95%-confidence interval:
127.300774171 131.361729528
```
![](img/14-13.png)
上图显示了基于 5000 次重复的自举过程,孕期天数 300 的预测出生体重的自举经验直方图。经验分布大致是正泰的。
我们已经通过预测的“中间 95%”,即预测的第 2.5 百分位数到第 97.5 百分位数的区间,构建了分数的约 95% 的预测区间。 区间范围从大约 127 到大约 131。基于原始样本的预测是大约 129,接近区间的中心。
### 改变预测变量的值的效果
下图显示了孕期天数 285 的 5,000 次自举预测的直方图。 基于原始样本的预测是约 122 盎司,区间范围从约 121 盎司到约 123 盎司。
```py
bootstrap_prediction(baby, 'Gestational Days', 'Birth Weight', 285, 5000)
Height of regression line at x=285: 122.214571016
Approximate 95%-confidence interval:
121.177089926 123.291373304
```
![](img/14-14.png)
请注意,这个区间比孕妇天数 300 的预测区间更窄。 让我们来调查其原因。
孕妇天数均值约为 279 天:
```py
np.mean(baby.column('Gestational Days'))
279.10136286201021
```
所以 285 比 300 更接近分布的中心。 通常,基于自举样本的回归线,在预测变量的分布中心附近彼此更接近。 因此,所有的预测值也更接近。 这解释了预测区间的宽度更窄。
你可以在下面的图中看到这一点,它显示了 10 个自举复制品中每一个的`x = 285``x = 300`的预测值。 通常情况下,直线在`x = 300`处比`x = 285`处相距更远,因此`x = 300`的预测更加可变。
![](img/14-15.png)
### 注意事项
我们在本章中进行的所有预测和测试,都假设回归模型是成立的。 具体来说,这些方法假设,散点图中的点由直线上的点产生,然后通过添加随机正态噪声将它们推离直线。
如果散点图看起来不像那样,那么模型可能不适用于数据。 如果模型不成立,那么假设模型为真的计算是无效的。
因此,在开始基于模型进行预测,或者对模型参数进行假设检验之前,我们首先要确定回归模型是否适用于我们的数据。 一个简单的方法就是,按照我们在本节所做的操作,即绘制两个变量的散点图,看看它看起来是否大致线性,并均匀分布在一条线上。 我们还应该使用残差图,执行我们在前一节中开发的诊断。
此差异已折叠。
此差异已折叠。
# 十七、更新预测
> 原文:[Updating Predictions](https://github.com/data-8/textbook/tree/gh-pages/chapters/17)
> 译者:[飞龙](https://github.com/wizardforcel)
> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
> 自豪地采用[谷歌翻译](https://translate.google.cn/)
我们知道如何使用训练数据将一个点划分为两类之一。 我们的分类只是对类别的预测,基于最接近我们的新点的,训练点中最常见的类别。
假设我们最终发现了我们的新点的真实类别。 然后我们会知道我们的分类是否正确。 另外,我们将会有一个新点,可以加入到我们的训练集中,因为我们知道它的类别。 这就更新了我们的训练集。 所以,我们自然希望,根据新的训练集更新我们的分类器。
本章将介绍一些简单的情况,其中新的数据会使我们更新我们的预测。 虽然本章中的例子在计算方面较简单,但是更新方法可以推广到复杂的设定,是机器学习最强大的工具之一。
## “更可能”的二分类器
让我们尝试使用数据,将一个点划分为两个类别之一,选择我们认为更可能的类别。 为此,我们不仅需要数据,而且还要清楚地描述几率是什么样。
我们将从一个简单的人造情况开始,开发主要的技术,然后跳到更有趣的例子。
假设有个大学班级,其组成如下:
+ 60% 的学生为二年级,其余的 40% 是三年级
+ 50% 二年级学生已经声明了他们的专业
+ 80% 三年级学生已经声明了他们的专业
现在假设我从班上随机挑选一个学生。 你能否用“更可能”的标准,将学生划分为二年级或三年级?
你可以,因为这个学生是随机挑选的,所以你知道这个学生是二年级的几率是 60%。 这比三年级的 40% 的可能性更大,所以你会把学生划分为二年级。
专业的信息是无关紧要的,因为我们已经知道班上二,三年的比例。
我们有了非常简单的分类器! 但是现在假设我给了你一些被挑选的学生的更多信息:
这个学生已经声明了专业。
这个知识会改变你的分类吗?
## 基于新信息更新预测
现在我们知道学生已经宣布了专业,重要的是要看看年级和专业声明的关系。 二年级的学生比三年级多,这仍然正确。 但是,三年级的学生,比二年级的学生,声明专业的比例更高,这也是事实。 我们的分类器必须考虑到这两个观察。
为了使这个可视化,我们将使用`students`表,它包含 100 个学生,每个学生一行,学生的年级和专业比例和数据中相同。
```py
students.show(3)
```
| Year | Major |
| --- | --- |
| Second | Undeclared |
| Second | Undeclared |
| Second | Undeclared |
(省略了 97 行)
为了检查比例是否正确,我们使用`pivot`,按照这两个变量对每个学生进行交叉分类。
```py
students.pivot('Major', 'Year')
```
| Year | Declared | Undeclared |
| --- | --- | --- |
| Second | 30 | 30 |
| Third | 32 | 8 |
![](img/17-1.png)
总人数为 100 人,其中二年级 60 人,三年级 40 人。 二年级中,每个专业类别有 50%。 三年级的 40 人中,20% 是未声明的,80% 已声明。 因此,这 100 人的比例和我们问题中的班级相同,我们可以假定,我们的学生是从 100 名学生中随机抽取的。
我们必须选择学生最可能进入的那一行。当我们对这个学生一无所知时,他或她可能在四个单元格中的任何一个,因此更可能在第一行(二年级),因为那里包含更多的学生。
但是现在我们知道这个学生已经声明了专业,所以可能结果的空间已经减少了:现在学生只能在两个已声明的单元格中的一个。
这些单元格共有 62 名学生,其中 32 名是三年级。 这是一半以上,即使不是太多。
所以,考虑到学生专业的新信息,我们必须更新我们的预测,现在将学生划分为三年级。
我们的分类的正确几率是多少? 对于所有声明了专业的 32 个三年级,我们是正确的,对于那 30 个二年级,我们是错误的。 因此,我们的正确几率大约是 0.516。
换句话说,我们正确几率是声明专业的学生中三年级的比例。
```py
32/(30+32)
0.5161290322580645
```
## 树形图
我们刚刚计算的比例基于 100 名学生。 但是班级没有理由没有 200 名学生,只要单元格中的所有比例都是正确的。 那么我们的计算就变成了`64 /(60 + 64)`,就是 0.516。
所以计算只取决于不同类别的比例,而不是计数。 为了便于比较,比例可以用树形图可视化,直接显示在数据透视表下方。
```py
students.pivot('Major', 'Year')
```
| Year | Declared | Undeclared |
| --- | --- | --- |
| Second | 30 | 30 |
| Third | 32 | 8 |
像数据透视表一样,该图将学生分成四个不同的组,称为“分支”。请注意,“三年级已声明”分支中的学生比例为`0.4 x 0.8 = 0.32`,对应于数据透视表中“三年级已声明”单元格中的 32 名学生。 “二年级已声明”分支中包含学生的`0.6 x 0.5 = 0.3`,对应于数据透视表中“二年级已声明”单元格中的 30 个。
我们知道,被挑选的学生属于“已声明”分支。也就是说,学生在两个顶层分支之一。这两个分支现在形成了我们的简化概率空间,所有几率的计算必须相对于这个简化空间的总概率。
所以,考虑到学生已声明专业,他们是三年级的几率可以直接从树中计算出来。答案是相对于两个“已声明”分类的总比例,“三年级已声明”分类的比例。
也就是说,答案是和以前一样,已声明的学生中三年级的比例。
```py
(0.4 * 0.8)/(0.6 * 0.5 + 0.4 * 0.8)
0.5161290322580645
```
### 贝叶斯法则
我们刚刚使用的方法来源于托马斯·贝叶斯牧师(1701-1761)。他的方法解决了所谓的“逆向概率”问题:假设有了新的数据,如何更新之前发现的几率?虽然贝叶斯生活在三个世纪之前,但他的方法现在在机器学习中广泛使用。
我们将在学生总体的背景下讲述这个规则。首先,一些术语:
先验概率。在我们知道所选学生的专业声明状态之前,学生是二年级的几率是 60%,学生是三年级的几率是 40%。这是两个类别的先验概率。
可能性。这是专业状态在给出学生类别情况下的几率;因此可以从树形图中读出。例如,假设学生是二年级,已声明的可能性是 0.5。
后验概率。这些是考虑专业声明状态的信息后,二年级的概率。我们计算了其中的一个:
假设学生已经声明,学生是三年级的后验概率表示为 ![](img/tex-17-1.gif),计算如下。
![](img/tex-17-2.gif)
另一个后验概率是:
![](img/tex-17-3.gif)
```py
(0.6 * 0.5)/(0.6 * 0.5 + 0.4 * 0.8)
0.4838709677419354
```
这大概是 0.484,还不到一半,与我们三年的分类一致。
请注意,两个后验概率的分母相同:新信息,也就是学生已声明的几率。
正因为如此,贝叶斯方法有时被归纳为比例陈述:
![](img/tex-17-4.gif)
公式非常便于高效地描述计算。 但是在我们的学生示例这样的情况中,不用公式来思考更简单。 我们仅仅使用树形图。
## 做出决策
贝叶斯规则的一个主要用途,是基于不完整的信息做出决策,并在新的信息到来时纳入它们。本节指出了在决策时保持你的假设的重要性。
许多疾病的医学检测都会返回阳性或阴性结果。阳性结果意味着,根据检测患者有疾病。阴性结果意味着,检测的结论是患者没有这种疾病。
医学检测经过精心设计,非常准确。但是很少有检测是 100% 准确的。几乎所有检测都有两种错误:
假阳性是,检测结果为阳性,但患者没有该疾病的错误。
假阴性是,检测结果为阴性,但患者确实有这种疾病的错误。
这些错误可能会影响人们的决策。假阳性可能引起焦虑和不必要的治疗(在某些情况下,这是昂贵的或危险的)。如果由于其阴性检测结果,患者未接受治疗,则假阴性可能具有更严重的后果。
### 罕见疾病的检测
假设总体很大,疾病只占总体的一小部分。 下面的属性图总结了这种疾病的信息,以及它的医学检测。
![](img/17-2.png)
总的来说,只有千分之四的总体有这种疾病。 检测相当准确:假阳性几率非常小,为 5/1000,但是假阴性更大(尽管还是很小),为 1/100。
个体可能知道也可能不知道他们是否患有这种疾病;通常情况下,人们会进行检测来确认他们是否拥有。
所以假设随机从总体中挑选一个人并进行检测。 如果检测结果是阳性的,你会如何分类:患病还是没有患病?
我们可以通过应用贝叶斯规则,和使用我们的“更可能”的分类器来回答这个问题。 鉴于该人已经检测出阳性,他或她患病的几率是相对于`Test Positive`分支中的总比例,顶层分支的比例。
```py
(0.004 * 0.99)/(0.004 * 0.99 + 0.996*0.005 )
0.44295302013422816
```
鉴于这个人已经检测出阳性,他或她有这种疾病的几率是大约 44%。 所以我们将它们分类为:没有疾病。
这是一个奇怪的结论。 我们有一个相当准确的检测,一个人检测出阳性,我们的分类是...他们没有这种疾病? 这似乎没有任何意义。
面对一个令人不安的答案,首先要做的是检查计算。 上面的算法是正确的。 我们来看看是否可以用不同的方式得到相同的答案。
函数`population`群体返回 100,000 名患者的结果表格,它的列展示了实际情况和检测结果。 检测与树中描述的相同。 但是有这种疾病的比例是这个函数的参数。
我们将 0.004 用作参数来调用`population`,然后调用`pivot `,对这十万人中的每一个人进行交叉分类。
```py
population(0.004).pivot('Test Result', 'True Condition')
```
| True Condition | Negative | Positive |
| --- | --- | --- |
| Disease | 4 | 396 |
| No Disease | 99102 | 498 |
表的单元格计数正确。 例如,根据总体的描述,一千人中有四人患有这种疾病。 表格中有十万人,所以 400 人应该有这种病。 这就是表格所显示的:`4 + 396 = 400`。在这 400 认中,99% 获得了阳性检测结果:`0.99 x 400 = 396`
```py
396/(396 + 498)
0.4429530201342282
```
这就是我们通过使用贝叶斯规则得到的答案。`Positives`列中的计数显示为什么它小于 1/2。 在阳性的人中,更多的人没有疾病而不是有疾病。
原因是,很大一部分人没有这种疾病。检测出假阳性的一小部分人比真阳性要多。 这在树形图中更容易可视化:
![](img/17-2.png)
真阳性的比例是总体一小部分(0.004)的很大一部分(0.99)。
假阳性的比例是总体很大一部分(0.996)的一小部分(0.005)。
这两个比例是可比的;第二个大一点。
所以,鉴于随机选择的人检测为阳性,我们将他们划分为,更有可能没有疾病,是正确的。
### 主观先验
正确并不总令人满意。将阳性患者划分为不患有该疾病似乎仍然有些错误,对于这样的精确检测来说。由于计算是正确的,我们来看看我们的概率计算的基础:随机性假设。
我们的假设是,一个随机选择的人进行了检测,并得到了阳性结果。但是这在现实中并没有发生。因为他们认为他们可能有疾病,或者因为他们的医生认为他们可能有疾病,人们去接受检测。被检测的人不是随机选择的总体的成员。
这就是为什么,我们对被检测者的直觉与我们得到的答案不太相符。我们正在想象一个病人接受检测的现实情况,因为有一些理由让他们这样做,而计算基于随机选择的人进行检测。
所以让我们在更现实的假设下重做我们的计算,即病人正在接受检测,因为医生认为病人有发病的机会。
这里需要注意的是,“医生认为有机会”是指医生的意见,而不是总体中的比例。这被称为主观概率。在病人是否患有这种疾病的情况下,这也是主观的先验概率。
一些研究人员坚持认为,所有的概率必须是相对的频率,但主观概率导出都是。候选人赢得下一次选举的几率,大地震在下一个十年将会袭击湾区的几率,某个国家赢得下一届足球世界杯的几率:这些都不是基于相对频率或长期的频率。每个都包含主观因素。涉及它们的所有计算也都有主观因素。
假设医生的主观意见是,患者有 5% 的几率患病。那么树形图中的先验概率将会改变:
![](img/17-3.png)
鉴于病人检测为阳性,他或她有这种疾病的几率是由贝叶斯规则给出。
```py
(0.05 * 0.99)/(0.05 * 0.99 + 0.95 * 0.005)
0.9124423963133641
```
改变先验的效果是惊人的。 即使病人患病的医生的先验概率(5%)很低,一旦患者检测出阳性,患病的后验概率高达 91% 以上。
如果患者检测出阳性,医生认为患者患病是合理的。
### 确认结果
虽然医生的意见是主观的,但我们可以产生一个人造总体,5% 的人患有这种疾病,并且使用相同的检测来进行检测。 然后,我们可以计算不同类别的人数,看看这些计数是否与我们使用贝叶斯规则得到的答案一致。
我们可以使用`population(0.05)``pivot`构建相应的总体,并看看四个单元格中的计数。
```py
population(0.05).pivot('Test Result', 'True Condition')
```
| True Condition | Negative | Positive |
| --- | --- | --- |
| Disease | 50 | 4950 |
| No Disease | 94525 | 475 |
在这个人工创建的 10 万人的总体中,有 5000 人(5%)患有这种疾病,其中 99% 的人检测为阳性,导致 4950 人为真阳性。 将其与 475 个假阳性相比:在阳性中,拥有疾病的比例与我们通过贝叶斯规则得到的结果相同。
```py
4950/(4950 + 475)
0.9124423963133641
```
因为我们可以一个具有合适比例的总体,我们也可以使用模拟来确认我们的答案是否合理。 `pop_05`表包含 10 万人的总体,使用医生的先验患病概率 5%,以及检测的错误率来生成。 我们从总体中抽取一个规模为 10,000 的简单随机样本,并提取`positive`表,仅包含样本中阳性检测结果的个体。
```py
pop_05 = population(0.05)
sample = pop_05.sample(10000, with_replacement=False)
positive = sample.where('Test Result', are.equal_to('Positive'))
```
在这些阳性结果中,真实比例是多少? 那是拥有这种疾病的阳性的比例:
```py
positive.where('True Condition', are.equal_to('Disease')).num_rows/positive.num_rows
0.9131205673758865
```
运行这两个单元格几次,你会发现,阳性中真阳性的比例位于我们通过贝叶斯规则计算的值 0.912 周围。
你也可以以不同参数调用`population`函数,来改变先验患病概率,并查看后验概率如何受到影响。
# 二、因果和实验
> 原文:[Causality and Experiments](https://github.com/data-8/textbook/tree/gh-pages/chapters/02)
> 译者:[飞龙](https://github.com/wizardforcel)
> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
> 自豪地采用[谷歌翻译](https://translate.google.cn/)
“这些问题已经,而且可能永远留在自然界难以捉摸的秘密之中,它们属于人类智力根本难以接近的一类问题。 - 1849 年 9 月,伦敦时报,霍乱如何传染和传播
死刑有威慑作用吗?巧克力对你有好处吗?什么导致乳腺癌?
所有这些问题试图为结果找到一个原因。仔细检查数据可以帮助揭示这些问题。在本节中,你将学习建立因果关系所涉及的一些基本概念。
观察是良好科学的关键。观察研究是一项研究,科学家根据他们所观察到的,但却无法产生的数据作出结论。在数据科学中,许多这样的研究涉及对一组个体的观察,称为实验的利害关系(factor of interest),以及对每个个体的测量结果。
将个体视为人是最容易的。在研究巧克力是否对健康有好处时,个体确实是人,实验是吃巧克力,结果可能是血压的测量。但观察研究中的个体不一定是人。在研究死刑是否具有威慑作用时,个体可以为联盟的 50 个州。允许死刑的州的法律是实验,结果可能是州的谋杀率。
根本问题是实验是否对结果有影响。实验和结果之间的任何关系被称为关联。如果实验导致结果发生,那么这个关联是因果关系。因果关系是本节开头提出的所有三个问题的核心。例如,问题之一是巧克力是否直接导致健康状况的改善,而不是巧克力与健康之间是否存在关联。
因果关系的建立往往分两个阶段进行。首先,观察一个关联。接下来,更仔细的分析决定了因果关系。
## John Snow 和 Broad 街水泵
### 观察和可视化:John Snow 和 Broad 街水泵
精确观察导致建立因果关系的例子之一,最早可以追溯到 150 多年前。为了将你的思维带回正确的时间,试着想象一下 19 世纪 50 年代的伦敦。这是世界上最富裕的城市,但其中许多人却极度贫困。那时,查尔斯·狄更斯(Charles Dickens)在名气鼎盛时,正在写作关于他们的困境的文章。这个城市的贫困地区疾病盛行,霍乱是最可怕的。那个时候还不知道细菌会导致疾病,主流理论是“瘴气”是主要的罪魁祸首。 瘴气表现为恶臭,被认为是由腐烂物质引起的无形的有毒颗粒。伦敦的部分地区气味非常糟糕,特别是在炎热的天气里。为了保护自己免受感染,那些有能力的人把甜的东西放在鼻子上。
几年来,一个名叫约翰·斯诺(John Snow)的医生一直在跟踪着时不时袭击英国的巨大霍乱。疾病突然到来,几乎立即致命:人们在一两天内死亡,数百人在一个星期内死亡,单批总死亡人数可能达到数万人。斯诺对瘴气理论持怀疑态度。他注意到,当整个家庭被霍乱摧毁时,邻居有时完全没有受到影响。当他们呼吸和邻居一样的空气和瘴气时,不好的气味和霍乱的发生之间没有什么紧密的联系。
斯诺还注意到,这种疾病的发作几乎总是牵涉呕吐和腹泻。因此,他认为这种感染是由人们吃或喝的东西来进行的,而不是他们所呼吸的空气。他主要怀疑被污染的水。
1854 年 8 月底,霍乱在过度拥挤的伦敦苏豪区爆发。随着死亡人数的增加,斯诺用一种在疾病传播研究中成为标准的方法,勤奋地将它们记录下来:他画了一张地图。在该地区的街道地图上,他记录了每次死亡的地点。
这是斯诺的原始地图。每个黑色条形代表一次死亡。黑色圆圈标记了水泵的位置。地图上显示了一个惊人的启示 - 死亡大致集中在 Broad 街水泵周围。
![](img/2-1.jpg)
斯诺仔细研究了他的地图,并调查了明显的异常。他们都设计 Broad 街水泵。例如:
+ 死亡发生在离 Rupert 街水泵更近的房子,而不是 Broad 街。尽管 Rupert 街水泵直线上更近,但由于街道布局不方便,是死路一条。那些房子里的居民使用了 Broad 街水泵。
+ 泵东边的两个街区没有死亡。那是 Lion Brewery 的位置,那里的工人喝了他们酿造的东西。如果他们想喝水,啤酒厂有自己的井。
+ Broad 街水泵几个街区之外的房子里,发生了少量死亡。那些孩子在上学路上从 Broad 街水泵饮水。泵的水清凉爽口。
最后一个支持斯诺的理论的证据是,在距离 Soho 区很远的 Hampstead 地区的两个孤立的死亡事件。斯诺对这些人感到困惑,直到他得知死者是住在 Broad 街的 Susannah Eley 夫人和她的侄女。Eley 夫人每天都将 Broad 街水泵的水带到 Hampstead 给她。她喜欢水的味道。
后来发现了一个粪坑,距离 Broad 街水泵几英尺远,渗入了井里面。因此,来自霍乱受害者房子的污水污染了水泵的水。
斯诺用他的地图来说服当地政府,拆除 Broad 街水泵的手柄。虽然霍乱疫情已经在减少,但是停止使用这种水泵有可能阻止了许多人死于未来的疾病。
Broad 街水泵的手柄的拆除已成为一个传奇。在亚特兰大的疾病控制中心(CDC),当科学家寻找流行病问题的简单答案时,他们有时会互相问:“这个水泵的手柄在哪里?”
斯诺的地图是数据可视化的最早和最强大的用法之一。现在各种疾病地图是跟踪流行病的标准工具。
### 因果关系
虽然地图给了斯诺强有力的证据,说明了供水的清洁是控制霍乱的关键,但是,为了使“污染的水导致疾病的传播”这个科学论证有说服力,还有很长一段路要走。为了使案例更有说服力,他必须使用比较法。
科学家使用比较来确定实验与结果之间的关联。他们比较了一组接受实验的个体(实验组)的结果,和一组没有接受实验的个体的结果(对照组)。例如,现在的研究人员可能会比较死刑国家和没有死刑的国家的平均谋杀率。
如果结果不同,那就是表明关联的证据。但是为了确定因果关系,需要更加小心。
## 斯诺的“大实验”
斯诺为自己在 Soho 中学到的东西感到鼓舞,他对霍乱的死亡情况做了更彻底的分析。一段时间中,他一直在收集伦敦一个地区的数据,这里由两家水厂服务。Lambeth 水厂从污水排入泰晤士河的地方的上游抽水。它的水比较干净。但 Southwark and Vauxhall (S&V) 公司在污水排放的下游抽水,因此其供水受到污染。
下图显示了两家公司所服务的地区。斯诺专注于两个服务地区重叠的地方。
![](img/2-2.jpg)
斯诺注意到,S&V 供应的人和 Lambeth 供应的人之间没有系统的差别。 “每家公司都供应富人和穷人,大房子和小房子,接受不同公司的供水的人的状况或职业并没有差别......接受两家公司供水的人或者房子都没什么区别,它们周围的物理状况也没什么区别...”
唯一的区别是供水方面,“一组供水含有伦敦的污水,其中有一些可能来自霍乱病人,另一组则不含。”
斯诺相信他能够得出一个清楚的结论,斯诺在下表中总结了他的数据。
| Supply Area | Number of houses | cholera deaths | deaths per 10,000 houses |
| --- | --- | --- | --- |
| S&V | 40,046 | 1,263 | 315 |
| Lambeth | 26,107 | 98 | 37 |
| Rest of London | 256,423 | 1,422 | 59 |
数字在指责 S&V。 S&V 供应的房屋的霍乱死亡率几乎是 Lambeth 供应的房屋的十倍。
## 建立因果
用本节前面提出的语言,可以将 S&V 房屋中的人作为实验组,Lambeth 房屋中的人作为对照组。斯诺的分析中的一个关键因素是,除了实验组以外,两组相互比较。
为了确定供水是否引起霍乱,斯诺必须比较两个彼此相似的群体,它们只有一方面不同:供水。只有这样,他才能够将其结果的差异归因于供水。如果这两个群体在其他方面有所不同,那么就很难把供水视为疾病的来源。例如,如果实验组由工厂工人组成,而对照组不是,那么两组之间的结果之间的差异可能是由于供水,工厂工作或两者兼有,或使两组彼此不同的其它因素。最后的图景会更加模糊。
斯诺的才智在于,确定可以使他的比较清晰的两组。他开始着手建立水污染和霍乱感染之间的因果关系,并且在很大程度上他成功了,尽管瘴气学说忽视甚至嘲笑他。当然,斯诺并不了解人类感染霍乱的详细机制。这个发现是在 1883 年,当时德国科学家罗伯特·科赫(Robert Koch)分离出霍乱弧菌,这种霍乱弧菌是进入人体小肠并引起霍乱的细菌。
事实上,霍乱弧菌在 1854 年由意大利的菲利波·帕齐尼(Filippo Pacini)发现,就在斯诺在伦敦分析他的数据的时候。由于意大利瘴气学说的统治,帕齐尼的发现并不为人所知。但到了十九世纪末,瘴气学说正在消失。随后的历史证明了帕齐尼和约翰·斯诺。斯诺的方法导致了流行病学领域的发展,它是疾病传播的研究。
### 混淆
现在让我们回到更现代化的时代,带着我们一路上学到的重要经验:
在一项观察研究中,如果实验组和对照组在实验以外的方面有所不同,则很难对因果关系作出结论。
两组之间的根本区别(除了实验)被称为混淆因素,因为当你试图得出结论时,它可能会混淆你(也就是搞砸你)。
示例:咖啡和肺癌。二十世纪六十年代的研究表明,喝咖啡的人患肺癌的比率高于不喝咖啡的人。因此,有些人认为咖啡是肺癌的一个原因。但咖啡不会导致肺癌。分析包含一个混淆因素 - 吸烟。在那些日子里,喝咖啡的人也可能是吸烟者,吸烟确实会导致肺癌。喝咖啡与肺癌有关,但不会导致疾病。
混淆因素在观察研究中很常见。良好的研究需要非常小心,以减少混淆。
## 随机化
避免混淆的一个很好的方法是,将个体随机分配到实验和对照组,然后将实验给予分配到实验组的人。随机化使两组除了实验之外都相似。
如果你能够将个体随机分为实验组和对照组,你正在进行一项随机对照试验(RCT)。有时候,人们在实验中的反应会受到他们知道他们在哪个群体的影响。所以你可能希望进行盲法实验,其中个体不知道他们是在实验组还是对照组。为了使它有效,你必须把安慰剂给控制组,这是一种和实验看起来完全一样的东西,但实际上没有效果。
随机对照实验早已成为医学领域的黄金标准,例如确定新药是否有效。在经济学等其他领域也越来越普遍。
示例:墨西哥的福利补贴。在 20 世纪 90 年代的墨西哥村庄,贫困家庭的孩子往往没有入学。其中一个原因是年龄较大的孩子可以上班,从而帮助家庭。墨西哥财政部长 Santiago Levy 着手调查福利项目是否可以用来提升入学率和改善健康状况。他在一组村庄进行了一项随机对照试验,随机选择其中的一些来接受一个名为 PROGRESA 的新福利项目。如果他们的孩子定期上学,并且家庭使用了预防性医疗保险,那么这个项目会把钱捐给贫困家庭。如果孩子上中学而不是小学,会给他们更多钱,来补偿孩子的工资损失,女孩上学比男孩给的更多。其余的村庄没有得到这个实验,并形成了对照组。由于随机化,没有销魂因素,可以确定 PROGRESA 增加了入学率。对于男孩,入学率从对照组的 73% 上升到 PROGRESA 组的 77%。对于女孩来说,增长幅度更大,从对照组的 67% 增加到 PROGRESA 组的近75%。由于这个实验的成功,墨西哥政府以 OPORTUNIDADES 这个新名称支持这个项目,作为对一个健康和受过良好教育的人口的投资。
在某些情况下,即使目标是调查因果关系,也不可能进行随机对照实验。例如,假设你想研究怀孕期间饮酒的影响,你随机将一些孕妇分配到你的“酒精”组。如果你给他们喝一杯,你不应该期待她们会合作。在这种情况下,你几乎总是在进行观察研究,而不是实验。要警惕混淆因素。
## 尾注
根据我们开发的术语,约翰·斯诺进行了一项观察研究,而不是一个随机的实验。但是他把自己的研究称为“大实验”,因为他写道:“至少三十万人......被分成两组,他们无法选择,在大多数情况下,他们并不知情......”
斯诺的这种研究有时被称为“自然实验”。然而,真正的随机化并不仅仅意味着,实验和对照组“在他们无法选择的情况下”进行选择。
随机化的方法可以像掷硬币一样简单。它也可能更复杂一点。但是随机化的每一种方法都是由一系列精心定义的步骤组成的,这些步骤允许几率以数学方式指定。这有两个重要的结果。
+ 它使我们能够以数学方式,计算随机化产生实验和对照组的可能性。
+ 它使我们能够对实验组和对照组之间的差异作出精确的数学表述。这反过来帮助我们对实验是否有效作出正确的结论。
在本课程中,你将学习如何进行和分析你自己的随机实验。这将涉及比本节更多的细节。目前,只需关注主要思想:尝试建立因果关系,如果可能,进行随机对照实验。如果你正在进行一项观察研究,你可能能够建立联系而不是因果关系。在根据观察研究得出因果关系的结论之前,要非常小心混淆因素。
### 术语
+ observational study:观察研究
+ treatment:实验
+ outcome:结果
+ association:关联/联系
+ causal association:因果联系
+ causality:因果(关系)
+ comparison:比较
+ treatment group:实验组
+ control group:对照组
+ epidemiology:流行病学/传染病学
+ confounding:混淆
+ randomization:随机化
+ randomized controlled experiment:随机对照实验
+ randomized controlled trial (RCT):随机对照实验
+ blind:盲法
+ placebo:安慰剂
### 有趣的事实
+ 约翰·斯诺有时被称为流行病学之父,但他是专业的麻醉师。 他的病人之一是维多利亚女王,她是分娩时麻醉剂的早期接受者。
+ 弗洛伦斯·南丁格尔,现代护理实践的创始人,因其在克里米亚战争中的工作而闻名,是一位顽固瘴气主义者。 她没有时间研究传染病和细菌的理论,也没有时间讲述她的话。 她说:“与这个学说相关的荒谬是无穷无尽的。一言以蔽之,从一般意义上说,没有任何科学研究可以接受的证据表明,存在传染病这样的事情。”
+ 后来的随机对照试验表明,PROGRESA 坚持的条件 - 孩子上学,预防性医疗保险 - 对于提升入学率没有必要。 只是提高福利金就足够了。
### 扩展阅读
+ [The Strange Case of the Broad Street Pump: John Snow and the Mystery of Cholera](http://www.ucpress.edu/book.php?isbn=9780520250499) 由 Sandra Hempel 所著,加利福尼亚大学出版社出版,读起来像是侦探小说。 这是本节中约翰·斯诺和他的工作的主要来源之一。 一些警告:这本书的一些内容令人反胃。
+ [Poor Economics](http://www.pooreconomics.com/) 由 MIT 的 Abhijit V. Banerjee 和 Esther Duflo 所著的畅销书,是对抗全球贫困的方式的易理解的真实记录。 它包含了很多 RCT 的例子,包括本节中的 PROGRESA 示例。
此差异已折叠。
# 四、数据类型
> 原文:[Data Types](https://github.com/data-8/textbook/tree/gh-pages/chapters/04)
> 译者:[飞龙](https://github.com/wizardforcel)
> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
> 自豪地采用[谷歌翻译](https://translate.google.cn/)
每个值都有一个类型,内建的`type`函数返回任何表达式的结果的类型:
```py
type(3)
int
type(3/1)
float
```
表达式的`type`是其最终值的类型。 所以,`type`函数永远不会表明,表达式的类型是一个名称,因为名称总是求值为它们被赋予的值。
```py
x = 3
type(x) # The type of x is an int, not a name
int
```
我们已经遇到的另一种类型是内置函数。 Python 表明这个类型是一个`builtin_function_or_method`;函数和方法之间的区别在这个阶段并不重要。
```py
type(abs)
builtin_function_or_method
```
这一章会探索其他实用的数据类型。
## 字符串
世界上大部分的数据都是文本,计算机中表示的文本被称为字符串。 字符串可以代表一个单词,一个句子,甚至是图书馆中每本书的内容。 由于文本可以包含数字(如`5`)或布尔值(`True`),字符串也可以描述这些东西。
表达式的含义取决于其结构和正在组合的值的类型。 因此,例如,将两个字符串加在一起会产生另一个字符串。 这个表达式仍然是一个加法表达式,但是它组合了一个不同类型的值。
```py
"data" + "science"
'datascience'
```
加法完全是字面的;它将这两个字符串组合在一起而不考虑其内容。 它不增加空间,因为这些是不同的词;它取决于程序员(你)来指定。
```py
"data" + " " + "science"
'data science'
```
单引号和双引号都可以用来创建字符串:`'hi'``"hi"`是相同的表达式。 双引号通常是首选,因为它们允许在字符串中包含单引号。
```py
"This won't work with a single-quoted string!"
"This won't work with a single-quoted string!"
```
为什么不能? 试试看。
`str`函数返回任何值的字符串表示形式。 使用此函数,可以构建具有嵌入值的字符串。
```py
"That's " + str(1 + 1) + ' ' + str(True)
"That's 2 True"
```
## 字符串方法
可以使用字符串方法,从现有的字符串中构造相关的字符串,这些方法是操作字符串的函数。 这些方法通过在字符串后面放置一个点,然后调用该函数来调用。
例如,以下方法生成一个字符串的大写版本。
```py
"loud".upper()
'LOUD'
```
也许最重要的方法是`replace`,它替换字符串中的所有子字符串的实例。 `replace`方法有两个参数,即被替换的文本和替代值。
```py
'hitchhiker'.replace('hi', 'ma')
'matchmaker'
```
字符串方法也可以使用变量名称进行调用,只要这些名称绑定到字符串。 因此,例如,通过首先创建`"ingrain" `然后进行第二次替换,以下两个步骤的过程从`"train"`生成`"degrade"`一词。
```py
s = "train"
t = s.replace('t', 'ing')
u = t.replace('in', 'de')
u
'degrade'
```
注意`t = s.replace('t', 'ing')`的一行,不改变字符串`s`,它仍然是`"train"`。 方法调用`s.replace('t', 'ing')`只有一个值,即字符串`"ingrain"`
```py
s
'train'
```
这是我们第一次看到方法,但是方法并不是字符串仅有的。 我们将很快看到,其他类型的对象可以拥有它们。
## 比较
布尔值通常来自比较运算符。 Python 包含了各种比较值的运算符。 例如,`3 > 1 + 1`
```py
3 > 1 + 1
True
```
`True`表明这个比较是有效的;Python 已经证实了`3``1 + 1`之间关系的这个简单的事实。下面列出了一整套通用的比较运算符。
| 比较 | 运算符 | True 示例 | False 示例 |
| --- | --- | --- | --- |
| 小于 | `<` | `2 < 3` | `2 < 2` |
| 大于 | `>` | `3 > 2` | `3 > 3` |
| 小于等于 | `<=` | `2 <= 2` | `3 <= 2` |
| 大于等于 | `>=` | `3 >= 3` | `2 >= 3` |
| 等于 | `==` | `3 == 3` | `3 == 2` |
| 不等于 | `!=` | `3 != 2` | `2 != 2` |
一个表达式可以包含多个比较,并且为了使整个表达式为真,它们都必须有效。 例如,我们可以用下面的表达式表示`1 + 1``1``3`之间。
```py
1 < 1 + 1 < 3
True
```
两个数字的平均值总是在较小的数字和较大的数字之间。 我们用下面的数字`x``y`来表示这种关系。 你可以尝试不同的`x``y`值来确认这种关系。
```py
x = 12
y = 5
min(x, y) <= (x+y)/2 <= max(x, y)
True
```
字符串也可以比较,他们的顺序是字典序。 较短的字符串小于以较短的字符串开头的较长的字符串。
```py
"Dog" > "Catastrophe" > "Cat"
True
```
## 序列
值可以分组到集合中,这允许程序员组织这些值,并使用单个名称引用它们中的所有值。 通过将值分组在一起,我们可以编写代码,一次执行许多数据计算。
在几个值上调用`make_array`函数,将它们放到一个数组中,这是一种顺序集合。 下面,我们将四个不同的温度收集到一个名为`temps`的数组中。 这些分别是 1850 年,1900 年,1950 年和 2000 年的几十年间,地球上所有陆地的估计日平均绝对高温(摄氏度),表示为 1951 年至 1980 年间平均绝对高温的偏差,为 14.48 度。
集合允许我们使用单个名称,将多个值传递给一个函数。 例如,`sum`函数计算集合中所有值的和,`len`函数计算其长度。 (这是我们放入的值的数量。)一起使用它们,我们可以计算一个集合的平均值。
```py
sum(highs)/len(highs)
14.434000000000001
```
日高温和低温的完整图表在下面。
### 日高温均值
![](img/4-1.png)
### 日低温均值
![](img/4-2.png)
## 数组
Python 中有很多种类的集合,我们在这门课中主要使用数组。 我们已经看到,`make_array`函数可以用来创建数值的数组。
数组也可以包含字符串或其他类型的值,但是单个数组只能包含单一类型的数据。 (无论如何,把不相似的数据组合在一起,通常都没有意义)。例如:
```py
english_parts_of_speech = make_array("noun", "pronoun", "verb", "adverb", "adjective", "conjunction", "preposition", "interjection")
english_parts_of_speech
array(['noun', 'pronoun', 'verb', 'adverb', 'adjective', 'conjunction',
'preposition', 'interjection'],
dtype='<U12')
```
> 译者注:
> ```py
> import numpy as np
> make_array = lambda *args: np.asarray(args)
> ```
返回到温度数据,我们创建 1850 年,1900 年,1950 年和 2000 年的几十年间,[日平均高温](http://berkeleyearth.lbl.gov/auto/Regional/TMAX/Text/global-land-TMAX-Trend.txt)的数组。
```py
baseline_high = 14.48
highs = make_array(baseline_high - 0.880,
baseline_high - 0.093,
baseline_high + 0.105,
baseline_high + 0.684)
highs
array([ 13.6 , 14.387, 14.585, 15.164])
```
数组可以用在算术表达式中来计算其内容。 当数组与单个数组合时,该数与数组的每个元素组合。 因此,我们可以通过编写熟悉的转换公式,将所有这些温度转换成华氏温度。
```py
(9/5) * highs + 32
array([ 56.48 , 57.8966, 58.253 , 59.2952])
```
![](img/4-3.png)
数组也有方法,这些方法是操作数组值的函数。 数值集合的均值是其总和除以长度。 以下示例中的每对括号都是调用表达式的一部分;它调用一个无参函数来对数组`highs`进行计算。
```py
highs.size
4
highs.sum()
57.736000000000004
highs.mean()
14.434000000000001
```
### 数组上的函数
`numpy`包,在程序中缩写为`np`,为 Python 程序员提供了创建和操作数组的,方便而强大的函数。
```py
import numpy as np
```
例如,`diff`函数计算数组中每两个相邻元素之间的差。 差数组的第一个元素是原数组的第二个元素减去第一个元素。
```py
np.diff(highs)
array([ 0.787, 0.198, 0.579])
```
[完整的 Numpy 参考](http://docs.scipy.org/doc/numpy/reference/)详细列出了这些功能,但一个小的子集通常用于数据处理应用。 它们分组到了`np`中不同的包中。 学习这些词汇是学习 Python 语言的重要组成部分,因此在你处理示例和问题时,请经常回顾这个列表。
但是,你不需要记住这些,只需要将它用作参考。
每个这些函数接受数组作为参数,并返回单个值。
| 函数 | 描述 |
| --- | --- |
| `np.prod` | 将所有元素相乘 |
| `np.sum` | 将所有元素相加 |
| `np.all` | 测试是否所有元素是真值 (非零数值是真值) |
| `np.any` | 测试是否任意元素是真值(非零数值是真值) |
| `np.count_nonzero` | 计算非零元素的数量 |
每个这些函数接受字符串数组作为参数,并返回数组。
| 函数 | 描述 |
| --- | --- |
| `np.char.lower` | 将每个元素变成小写 |
| `np.char.upper` | 将每个元素变成大写 |
| `np.char.strip` | 移除每个元素开头或末尾的空格 |
| `np.char.isalpha` | 每个元素是否只含有字母(没有数字或者符号) |
| `np.char.isnumeric` | 每个元素是否只含有数字(没有字母) |
每个这些函数接受字符串数组和一个搜索字符串。
| 函数 | 描述 |
| --- | --- |
| np.char.count | 在数组的元素中,计算搜索字符串的出现次数 |
| np.char.find | 在每个元素中,搜索字符串的首次出现位置 |
| np.char.rfind | 在每个元素中,搜索字符串的最后一次出现位置 |
| np.char.startswith | 每个字符串是否以搜索字符串起始 |
## 范围
范围是一个数组,按照递增或递减的顺序排列,每个元素按照一定的间隔分开。 范围在很多情况下非常有用,所以值得了解它们。
范围使用`np.arange`函数来定义,该函数接受一个,两个或三个参数:起始值,终止值和“步长”。
如果将一个参数传递给`np.arange`,那么它将成为终止值,其中`start = 0``step = 1`。 两个参数提供了起始值和终止值,`step = 1`。 三个参数明确地提供了起始值,终止值和步长。
范围始终包含其`start`值,但不包括其`end`值。 它按照`step`计数,并在到达`end`之前停止。
```py
np.arange(end): An array starting with 0 of increasing consecutive integers, stopping before end.
np.arange(5)
array([0, 1, 2, 3, 4])
```
要注意,数值从`0`起始,并仅仅增加到`4`,并不是`5`
```py
np.arange(start, end): An array of consecutive increasing integers from start, stopping before end.
np.arange(3, 9)
array([3, 4, 5, 6, 7, 8])
np.arange(start, end, step): A range with a difference of step between each pair of consecutive values, starting from start and stopping before end.
np.arange(3, 30, 5)
array([ 3, 8, 13, 18, 23, 28])
```
这个数组从`3`起始,增加了步长`5`变成`8`,然后增加步长`5`变成`13`,以此类推。
当你指定步长时,起始值、终止值和步长可正可负,可以是整数也可以是分数。
```py
np.arange(1.5, -2, -0.5)
array([ 1.5, 1. , 0.5, 0. , -0.5, -1. , -1.5])
```
### 示例:莱布尼茨的 π 公式
伟大的德国数学家和哲学家戈特弗里德·威廉·莱布尼茨(Gottfried Wilhelm Leibniz,1646 ~ 1716年)发现了一个简单分数的无穷和。 公式是:
![](img/tex-4-1.gif)
虽然需要一些数学来确定它,但我们可以用数组来说服我们自己,公式是有效的。 让我们计算莱布尼茨的无穷和的前 5000 个项,看它是否接近 π。
我们将计算这个有限的总和,首先加上所有的正项,然后减去所有负项的和 [1]:
![](img/tex-4-2.gif)
> [1] 令人惊讶的是,当我们将无限多个分数相加时,顺序可能很重要。但是我们对 π 的近似只使用了大量的数量有限的分数,所以可以按照任何方便的顺序,将这些项相加。
和中的正项的分母是`1, 5, 9`,以此类推。数组`by_four_to_20`包含`17`之前的这些数。
```py
by_four_to_20 = np.arange(1, 20, 4)
by_four_to_20
array([ 1, 5, 9, 13, 17])
```
为了获得 π 的准确近似,我们使用更长的数组`positive_term_denominators`
```py
positive_term_denominators = np.arange(1, 10000, 4)
positive_term_denominators
array([ 1, 5, 9, ..., 9989, 9993, 9997])
```
我们实际打算加起来的正项,就是一除以这些分母。
```py
positive_terms = 1 / positive_term_denominators
```
负向的分母是`3, 7, 11`,以此类推。这个数组就是`positive_term_denominators`加二。
```py
negative_terms = 1 / (positive_term_denominators + 2)
```
整体的和是:
```py
4 * ( sum(positive_terms) - sum(negative_terms) )
3.1413926535917955
```
这非常接近于`π = 3.14159...`。莱布尼茨公式看起来不错。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
+ [计算与推断思维](README.md)
+ [一、数据科学](1.md)
+ [二、因果和实验](2.md)
+ [三、Python 编程](3.md)
+ [四、数据类型](4.md)
+ [五、表格](5.md)
+ [六、可视化](6.md)
+ [七、函数和表格](7.md)
+ [八、随机性](8.md)
+ [九、经验分布](9.md)
+ [十、假设检验](10.md)
+ [十一、估计](11.md)
+ [十二、为什么均值重要](12.md)
+ [十三、预测](13.md)
+ [十四、回归的推断](14.md)
+ [十五、分类](15.md)
+ [十六、比较两个样本](16.md)
+ [十七、更新预测](17.md)
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册