数据科学算法的一星期指南全绝不原创的飞龙

数据科学是一个交叉学科,涵盖了机器学习、统计学和数据挖掘,旨在通过算法和统计分析从现有数据中获得新知识。本书将教您数据科学中分析数据的七种最重要方法。每一章首先以简单的概念解释其算法或分析,并通过一个简单的例子进行支持。随后,更多的例子和练习将帮助您构建并扩展对特定分析类型的知识。

本书适合那些熟悉 Python,并且有一定统计学背景的有志数据科学专业人士。对于那些目前正在实现一两个数据科学算法并希望进一步扩展技能的开发者,本书将非常有用。

为了最大化地利用本书,首先,您需要保持积极的态度来思考问题——许多新内容会在每章末尾的 Problems 部分的练习中呈现出来。然后,您还需要能够在您选择的操作系统上运行 Python 程序。作者在 Linux 操作系统上使用命令行运行了这些程序。

您可以按照以下步骤下载代码文件:

选择 SUPPORT 标签。

点击“Code Downloads & Errata”。

在搜索框中输入书名,并按照屏幕上的指示操作。

文件下载后,请确保使用最新版本的工具解压或提取文件夹:

WinRAR/7-Zip for Windows

Zipeg/iZip/UnRarX for Mac

7-Zip/PeaZip for Linux

本书中使用了许多文本约定。

CodeInText:指示文本中的代码字词,数据库表名,文件夹名,文件名,文件扩展名,路径名,虚拟 URL,用户输入和 Twitter 句柄。例如:"将下载的WebStorm-10*.dmg磁盘映像文件挂载为系统中的另一个磁盘。"

代码块设置如下:

任何命令行输入或输出如下所示:

粗体:表示新术语,重要单词或屏幕上显示的单词。例如,菜单或对话框中的单词在文本中出现如此。例如:"从管理面板中选择系统信息。"

警告或重要提示如下所示。

提示和技巧如下所示。

我们随时欢迎读者的反馈。

请留下您的评论。一旦您阅读并使用了这本书,为什么不在购买它的网站上留下评论呢?潜在的读者可以看到并使用您的公正意见来做购买决定,我们在 Packt 可以了解您对我们产品的看法,而我们的作者也可以看到您对他们的书的反馈。谢谢!

最近邻算法根据邻居对数据实例进行分类。通过k-最近邻算法确定的数据实例的类别是k个最近邻居中出现次数最多的类别。

在本章中,我们将涵盖以下主题:

如何通过 Mary 及其温度偏好示例实现 k-NN 算法的基本原理

如何选择正确的k值,以便算法能够正确执行,并且在使用意大利地图示例时具有最高的准确度

如何调整值的比例并为 k-NN 算法做准备,以房屋偏好为例

如何选择一个合适的度量标准来测量数据点之间的距离

例如,如果我们知道我们的朋友 Mary 在 10°C 时感觉冷,在 25°C 时感觉温暖,那么在一个温度为 22°C 的房间里,最近邻算法会猜测她会感觉温暖,因为 22 比 10 更接近 25。

假设我们想知道 Mary 在何时感到温暖,何时感到寒冷,如前面的例子所示,但此外,风速数据在询问 Mary 是否感到温暖或寒冷时也可用:

我们可以通过图表来表示数据,如下所示:

现在,假设我们想通过使用1-NN 算法来了解当温度为 16°C、风速为 3 km/h 时,Mary 的感受:

为了简化起见,我们将使用曼哈顿距离度量法来测量网格上相邻点之间的距离。邻居N[1]=(x[1],y[1])到邻居N[2]=(x[2],y[2])的曼哈顿距离d[Man]定义为d[Man]=|x[1]**- x[2]|+|y[1]**- y[2]|。

让我们给网格标上邻居的距离,看看哪个已知类别的邻居距离我们希望分类的点最近:

我们可以看到,距离该点最近的已知类别的邻居是温度为 15°C(蓝色)且风速为 5 km/h 的邻居。它与该点的距离为三单位。它的类别是蓝色(冷)。最近的红色(温暖)邻居与该点的距离为四单位。由于我们使用的是 1-最近邻算法,我们只需要查看最近的邻居,因此该点的类别应为蓝色(冷)。

通过对每个数据点应用这个过程,我们可以完成图表,如下所示:

请注意,有时数据点可能距离两个已知类别的距离相同:例如,20°C 和 6 km/h。在这种情况下,我们可以偏好一个类别,或者忽略这些边界情况。实际结果取决于算法的具体实现。

现在,我们将在 Python 中实现 k-NN 算法来查找玛丽的温度偏好。在本节结束时,我们还将实现上一节中生成的数据的可视化,即玛丽和她的温度偏好。完整的可编译代码和输入文件可以在本书附带的源代码中找到。最重要的部分已提取并在此呈现:

输入:

输出:

可视化:

在本章前面描述的可视化中,使用了matplotlib库。数据文件被加载后,显示为散点图:

在我们的数据中,我们获得了一些来自意大利及其周围地区地图的点(大约 1%)。蓝色点代表水域,绿色点代表陆地;白色点是未知的。从我们所拥有的部分信息中,我们希望预测白色区域是水域还是陆地。

仅绘制地图数据的 1%会使其几乎不可见。如果我们从意大利及其周围地区的地图中获取大约 33 倍的数据,并将其绘制在图中,结果将如下所示:

对于这个问题,我们将使用 k-NN 算法——这里的k表示我们将查看k个最接近的邻居。给定一个白色点,如果它的k个最接近的邻居大多数位于水域区域,它将被分类为水域;如果它的k个最接近的邻居大多数位于陆地区域,它将被分类为陆地。我们将使用欧几里得度量来计算距离:给定两个点,X=[x[0],x[1]]和Y=[y[0],y[1]],它们的欧几里得距离定义为d[Euclidean] = sqrt((x[0]-y[0])²+(x[1]-y[1])²)。

欧几里得距离是最常用的度量。给定纸面上的两点,它们的欧几里得距离就是通过尺子量测得的两点之间的长度,如下图所示:

为了将 k-NN 算法应用到不完整的地图中,我们必须选择k值。由于一个点的最终分类是其k个最接近邻居的多数类别,因此k应为奇数。让我们将此算法应用于k=1,3,5,7,9的值。

将此算法应用到不完整地图上的每一个白点,将得到以下完整地图:

k=1

k=3

k=5

k=7

k=9

正如你所注意到的,k的最高值会导致一个边界更平滑的完整地图。这里展示了意大利的实际完整地图:

我们可以使用这个实际的完整地图来计算不同k值下错误分类点的百分比,从而确定 k-NN 算法在不同k值下的准确性:

因此,对于这种特定类型的分类问题,k-NN 算法在k=1时达到了最高准确性(最小误差率)。

然而,在现实生活中,问题在于我们通常没有完整的数据或解决方案。在这种情况下,我们需要选择一个适合部分可用数据的k值。有关这一点,请参阅本章末尾的问题 4。

对于每个人,我们都知道他们的年龄、年收入,以及是否拥有房屋:

房屋拥有情况与年收入

目标是预测 50 岁、年收入 80,000 美元的彼得是否拥有房屋,并可能成为我们保险公司的潜在客户。

在这种情况下,我们可以尝试应用 1-NN 算法。然而,我们需要小心如何衡量数据点之间的距离,因为收入范围远大于年龄范围。收入为 11.5 万美元和 11.6 万美元之间相差 1,000 美元。这两个数据点在收入上差距很大。但相对而言,这些数据点之间的差异实际上并没有那么大。由于我们认为年龄和年收入这两个度量大致同等重要,我们将根据以下公式将它们都缩放到 0 到 1 之间:

在我们特定的案例中,这简化为以下内容:

缩放后,我们得到以下数据:

现在,如果我们使用欧几里得度量应用 1-NN 算法,我们会发现 Peter 很可能拥有一套房子。请注意,如果不进行重新缩放,算法将得出不同的结果。有关更多信息,请参见练习 1.5。

那些高频出现算法和计算机词汇的文档属于信息学类。数学类的文档偶尔也包含大量的算法词汇,例如涉及欧几里得算法的数论领域的文档。但由于数学类在算法领域的应用较少,计算机一词在这些文档中的出现频率较低。

我们想要分类一份文档,该文档中每千字出现 41 次算法,每千字出现 42 次计算机:

例如,使用 1-NN 算法和曼哈顿距离或欧几里得距离,结果会将该文档归类为 mathematics 类别。然而,直观上我们应该使用不同的度量方法来衡量文档之间的距离,因为该文档中的 computer 词汇出现频率远高于其他已知的 mathematics 类文档。

另一个可选的度量方法是,测量文档实例之间词汇的比例或角度。你可以使用角度的余弦值,cos(θ),然后使用著名的点积公式来计算 cos(θ)。

设我们使用 a=(a[x],a[y]), b=(b[x],b[y]),使用以下公式:

这将得出以下结果:

使用余弦距离度量方法,你可以将该文档归类为 informatics 类:

假设我们有一些文档,并希望基于它们的词频来分类其他文档。例如,出现在《金色圣经》项目古腾堡电子书中的 120 个最常出现的词汇如下:

任务是设计一种度量方法,给定每个文档的词频,能够准确判断这些文档在语义上的相似度。因此,这样的度量方法可以被 k-NN 算法用来基于现有文档对新文档中的未知实例进行分类。

假设我们考虑,例如,语料库中最常出现的 N 个词。然后,我们统计每个 N 个词在给定文档中的出现频率,并将它们放入一个 N 维向量中,代表该文档。接着,我们定义两个文档之间的距离为这两个文档的词频向量之间的距离(例如,欧几里得距离)。

这种方法的问题在于,只有某些词汇才代表书籍的实际内容,其他词汇之所以出现在文本中,是因为语法规则或它们的一般基础意义。例如,在《圣经》中,120 个最常出现的词语中,每个词的意义不同。下表中,我们标出了那些在《圣经》中既频繁出现又具有重要意义的词语:

lord - 使用频率 1.00%

god - 0.56%

Israel - 0.32%

king - 0.32%

David - 0.13%

Jesus - 0.12%

然而,如果我们只看《圣经》中六个最常见的词,它们在检测文本意义方面其实没有什么用:

the - 8.07%

and - 6.51%

of - 4.37%

to - 1.72%

that - 1.63%

in - 1.60%

因此,为了确定两个文档之间的相似性距离,我们只需要查看重要词汇的频率统计。一些词汇不太重要——这些维度最好减少,因为它们的包含可能最终导致结果的误解。因此,我们需要做的就是选择那些对分类文档至关重要的词汇(维度)。为此,请参考问题 6。

在本章中,我们了解到k-最近邻算法是一种分类算法,它将给定数据点的k-最近邻中多数类别分配给该数据点。两个点之间的距离是通过度量来衡量的。我们介绍了几种距离的例子,包括欧几里得距离、曼哈顿距离、切线距离和余弦距离。我们还讨论了如何通过不同参数的实验和交叉验证,帮助确定应使用哪个参数k以及哪个度量。

我们还学到了数据点的维度和位置是由其特征决定的。大量的维度可能导致 k-NN 算法的准确性较低。减少重要性较小的特征维度可以提高准确性。同样,为了进一步提高准确性,每个维度的距离应该根据该维度特征的重要性进行缩放。

在下一章,我们将讨论朴素贝叶斯算法,该算法基于贝叶斯定理使用概率方法对元素进行分类。

在本节中,我们将讨论以下问题:

玛丽和她的温度偏好问题

意大利地图 – 选择k的值

房屋所有权

为了尽可能最佳地学习本章的内容,请先独立分析这些问题,然后再查看本章末尾的分析部分。

问题 1:假设你知道你的朋友玛丽在-50°C 时感到寒冷,而在 20°C 时感到温暖。那么 1-NN 算法会怎么判断玛丽的感受呢?在 22°C、15°C 和-10°C 的温度下,她会感到温暖还是寒冷?你认为算法预测玛丽对温度的感知是正确的吗?如果不是,请给出你的理由,并指出为什么算法没有给出合适的结果,以及需要改进哪些方面,以便算法能够做出更好的分类。

问题 2:你认为 1-NN 算法会比使用k-NN 算法(其中k>1)产生更好的结果吗?

问题 3:我们收集了更多数据,发现玛丽在 17°C 时感觉温暖,在 18°C 时却感觉寒冷。根据我们自己的常识,温度越高,玛丽应该越觉得温暖。你能解释数据中不一致的可能原因吗?我们如何改进数据分析?我们是否也应该收集一些非温度数据?假设我们只有一条温度数据,你认为仅用这些数据,1-NN 算法是否仍然能够得出更好的结果?我们应该如何选择k值来让k-NN 算法表现得更好?

问题 4:我们得到意大利部分地图用于意大利地图问题。然而,假设完整数据不可用。因此,我们无法对不同k值的所有预测点计算误差率。你应如何选择k值,来使用k-NN 算法,完成意大利地图并最大化其准确性?

a) 不进行数据重新缩放

b) 使用缩放后的数据

最近的邻居是否在:

a) 与该邻居相同?

b) 哪个邻居拥有房屋?

问题 1:8°C 比-50°C 更接近 20°C。因此,算法会将玛丽在-8°C 时归类为感觉温暖。但如果我们运用常识和知识,这种判断不太可能成立。在更复杂的例子中,由于我们缺乏专业知识,可能会被分析结果误导,得出错误的结论。但请记住,数据科学不仅仅依赖数据分析,还需要实际的专业知识。为了得出合理的结论,我们应该对问题和数据有深刻的理解。

算法进一步指出,在 22°C 时,玛丽应该感觉温暖,这是毫无疑问的,因为 22°C 高于 20°C,人类在较高的温度下会感觉更温暖;这再次是我们常识的一个简单应用。对于 15°C,算法会认为玛丽感觉温暖,但如果我们使用常识,可能无法对这个结论完全确信。

为了能够使用我们的算法得到更好的结果,我们应该收集更多数据。例如,如果我们发现玛丽在 14°C 时感到寒冷,那么我们就有一个与 15°C 非常接近的数据实例,因此,我们可以更有信心地推测玛丽在 15°C 时也会觉得寒冷。

问题 2:我们处理的数据只是单维的,并且也分为两部分,冷和暖,具有以下特性:温度越高,人感觉越暖。即使我们知道 Mary 在温度-40、-39、…、39 和 40 时的感觉,我们的数据实例仍然非常有限——大约每摄氏度只有一个实例。因此,最好只查看一个最接近的邻居。

问题 3:数据中的差异可能是由于进行的测试不准确所致。这可以通过进行更多实验来缓解。

除了不准确性,还有其他因素可能会影响 Mary 的感觉:例如风速、湿度、阳光、Mary 的穿着(她是穿着外套和牛仔裤,还是仅仅穿着短裤和无袖上衣,甚至是泳衣),以及她是湿的还是干的。我们可以将这些附加维度(风速和她的穿着)添加到数据点的向量中。这将为算法提供更多且更高质量的数据,因此可以期望得到更好的结果。

如果我们只有温度数据,但数据量更多(例如,每摄氏度有 10 个分类实例),那么我们可以增加k值,查看更多的邻居以更准确地确定温度。但这纯粹依赖于数据的可用性。我们可以调整算法,使其基于某个距离d内的所有邻居来进行分类,而不是仅仅基于k个最接近的邻居进行分类。这将使算法在数据量较大且距离较近时以及数据实例与我们想要分类的实例距离较近时都能有效工作。

问题 4:为此,你可以使用交叉验证(请参考附录 A – 统计学中的交叉验证部分)来确定具有最高准确性的k值。例如,你可以将来自意大利部分地图的可用数据分为学习数据和测试数据,80%的分类像素将交给 k-NN 算法来完成地图。然后,剩余的 20%分类像素将用于根据 k-NN 算法计算正确分类的像素百分比。

问题 5:

a) 在没有数据重缩放的情况下,Peter 最近的邻居年收入为 78,000 美元,年龄为 25 岁。这个邻居没有房子。

b) 在数据重缩放之后,Peter 最近的邻居年收入为 60,000 美元,年龄为 40 岁。这个邻居拥有房子。

问题 6:为了设计一个准确衡量两个文档相似度距离的度量,我们需要选择能够构成文档频率向量维度的重要单词。那些不能确定文档语义意义的单词,通常在所有文档中具有大致相同的词频。因此,我们可以创建一个包含文档相对词频的列表。例如,我们可以使用以下定义:

然后,文档可以通过一个N维向量来表示,该向量由相对频率最高的N个单词的词频组成。这样的向量通常会包含比由频率最高的N个单词组成的向量更重要的单词。

朴素贝叶斯分类算法根据贝叶斯定理将最可能的类别分配给一组元素。

假设 A 和 B 是概率事件。P(A) 是 A 为 true 的概率。P(A|B) 是在 B 为 true 的情况下,A 为 true 的条件概率。如果是这种情况,那么贝叶斯定理声明如下:

P(A) 是在没有 P(B) 和 P(B|A) 概率知识的情况下,A 为 true 的先验概率。P(A|B) 是考虑到 B 为 true 额外知识的条件概率。

在本章中,您将学习以下主题:

如何在简单的医学检测示例中以基础方式应用贝叶斯定理来计算医学测试的正确概率

如何通过证明贝叶斯定理的陈述及其扩展来掌握贝叶斯定理

如何在国际象棋的示例中将贝叶斯定理应用于独立和依赖变量

如何在医学测试和国际象棋的离散随机变量示例中应用贝叶斯定理,以及如何在性别分类的连续随机变量示例中使用连续随机变量的概率分布应用贝叶斯定理

如何在 Python 中实现算法,利用贝叶斯定理计算后验概率

到本章结束时,您将能够通过解决问题验证您对朴素贝叶斯的理解。您还将能够辨别在什么情况下贝叶斯定理是合适的分析方法,以及在何时不适用。

一位病人接受了一项特殊的癌症检测,准确率为test_accuracy=99.9%——如果结果为阳性,那么 99.9%的接受检测的患者会患有该特定类型的癌症。反之,99.9%接受检测的患者如果结果为阴性,则不会患有该特定类型的癌症。

假设病人接受了检测且结果为阳性。那么该病人患某种特定类型癌症的概率是多少?

我们将使用贝叶斯定理来确定病人患癌症的概率:

为了确定病人患癌症的先验概率,我们必须了解癌症在人群中的发生频率。假设我们发现每 10 万人中就有 1 人患有这种癌症。因此,P(cancer)=1/100,000。因此,P(test_positive|cancer) = test_accuracy=99.9%=0.999,这是由检测的准确性给出的。

P(test_positive) 需要按以下方式计算:

因此,我们可以计算以下内容:

所以,即使测试结果是阳性,且测试的准确率为 99.9%,患者患所测试癌症的概率也只有大约 1%。与测试的高准确率相比,测试后患癌症的概率相对较低,但远高于在测试前已知的 1/100,000(0.001%)的概率,这是基于该癌症在整个群体中的发生率。

在本节中,我们将陈述并证明贝叶斯定理及其扩展。

贝叶斯定理指出如下:

我们可以通过使用初等集合论在事件A和B的概率空间上证明这个定理。换句话说,在这里,概率事件将被定义为概率空间中可能结果的集合:

图 2.1:两个事件的概率空间

如你在上面的图示中所见,我们可以陈述如下关系:

将这些关系重新排列,我们得到如下:

这实际上就是贝叶斯定理:

这完成了证明。

我们可以通过考虑更多的概率事件来扩展贝叶斯定理。假设事件B1,…,Bn在给定A的情况下是条件独立的。让~A表示A的补集。那么,我们有如下结果:

由于事件B1,…,Bn在给定A(以及给定~A)的情况下是条件独立的,我们得到如下结论:

应用贝叶斯定理的简易形式和这一事实,我们得到如下结果:

这完成了证明。

我们希望通过使用贝叶斯定理来判断,如果温度是温暖的,风速较强,且阳光明媚,我们的朋友是否愿意在公园与我们下棋。

在这种情况下,我们可能希望将Temperature、Wind和Sunshine作为独立随机变量。扩展后的贝叶斯定理公式如下:

让我们计算表格中所有已知值的列数,以确定各个概率。

P(Play=Yes)=6/10=3/5,因为有 10 列完整数据,其中6列的Play属性值为Yes。

P(Temperature=Warm|Play=Yes)=3/6=1/2,因为有6列的Play属性值为Yes,其中有3列的Temperature属性值为Warm。同样地,我们得到以下内容:

因此:

因此,我们得到以下内容:

这意味着,在给定的天气条件下,我们的朋友很可能会高兴地与我们在公园下棋,概率大约为67%。由于这是多数,我们可以将数据向量(Temperature=Warm, Wind=Strong, Sunshine=Sunny)归类为Play=Yes类别。

在本节中,我们将实现一个程序,通过使用贝叶斯定理来计算一个数据项属于某一类别的概率:

我们使用公共库中的字典部分:

输入:

输出:

假设我们想要了解我们的朋友是否愿意在英国剑桥的公园与我们下棋。但这次,我们提供了不同的输入数据:

所以,现在我们想知道,当数据中温度为温暖,风为强风,季节为春季时,我们朋友是否会在英国剑桥的公园玩耍,答案会如何变化。

我们可能会倾向于使用贝叶斯概率来计算我们朋友是否会在公园与我们下棋。然而,我们应该小心,问一下这些事件的概率是否相互独立。

在之前的例子中,我们使用了贝叶斯概率,给定的概率变量是温度、风和阳光。这些变量是合理独立的。常识告诉我们,特定的温度和阳光与特定的风速之间并没有强相关性。的确,阳光明媚的天气会带来更高的气温,但即使温度很低,阳光明媚的天气也很常见。因此,我们认为即使是阳光和温度作为随机变量也是合理独立的,并应用了贝叶斯定理。

然而,在这个例子中,温度和季节是紧密相关的,特别是在像英国这样的位置——我们所说的公园所在地。与靠近赤道的国家不同,英国的气温全年变化很大。冬天很冷,夏天很热。春天和秋天的气温介于其中。

因此,我们不能在这里应用贝叶斯定理,因为这些随机变量是相关的。然而,我们仍然可以通过对部分数据使用贝叶斯定理来进行一些分析。通过消除足够的相关变量,剩余的变量可能会变得独立。由于温度比季节更为具体,且这两个变量是相关的,因此我们只保留温度变量。剩下的两个变量,温度和风,是独立的。

因此,我们得到以下数据:

我们可以保留重复的行,因为它们提供了该特定数据行发生的更多证据。

输入:

保存该表格,我们得到以下 CSV 文件:

输出:

第一个类别 Yes 有 50%的概率为真。由于使用 Python 的非精确浮点数算术导致数值上的差异。第二个类别 No 也有相同的 50%概率为真。因此,根据我们目前的数据,我们无法对向量的类别(温暖,强)做出合理的结论。然而,您可能已经注意到,这个向量已经在具有结果类别 No 的表格中出现。因此,我们的猜测是,这个向量应该刚好存在于一个类别 No 中。但是,要有更高的统计置信度,我们需要更多的数据或涉及更多的独立变量。

到目前为止,我们已经得到了属于有限数量类别中的一个概率事件,例如,一个温度被分类为冷、温暖或热。但是如果我们获得的是以°C 为单位的温度,我们如何计算后验概率呢?

在这个例子中,我们得到了五名男性和五名女性的身高数据,如下表所示:

假设下一个人的身高为 172 厘米。那么这个人更可能是什么性别,以及概率是多少?

解决这个问题的一种方法是为数值赋予类别;例如,身高在 170 厘米和 179 厘米之间的人将属于同一类。使用这种方法,我们可能会得到一些非常宽的类,例如,具有较高厘米范围的类,或者具有更精确但成员较少的类,因此我们不能充分利用贝叶斯分类器的全部潜力。同样地,使用这种方法,我们不会考虑身高区间(170, 180)和(180, 190)之间的类比考虑(170, 180)和(190, 200)之间的类更接近。

让我们在这里回顾一下贝叶斯公式:

在这里表达出最终形式的公式消除了归一化 P(身高|男性) 和 P(身高) 以获得基于身高判断一个人是男性的正确概率的需要。

假设人们的身高服从正态分布,我们可以使用正态概率分布来计算 P(男性|身高)。我们假设 P(男性)=0.5,即被测量的人是男性或女性的可能性相等。正态概率分布由总体的均值μ和方差 σ² 决定:

下表显示了按性别分组的平均身高和方差:

因此,我们可以计算以下内容:

请注意,这些不是概率值,而是概率密度函数的值。然而,从这些值中,我们可以观察到,身高为 172 厘米的人更有可能是男性而不是女性,原因如下:

更准确地说:

因此,身高为172厘米的人是男性的概率为68.9%。

在这一章中,我们学习了朴素贝叶斯算法及其在不同场景下的应用。

贝叶斯定理如下所述:

这里,P(A|B)是条件概率,即在B为真的情况下,A为真的概率。它用于更新在新的观测值下,A为真时的概率值。这个定理可以扩展到含有多个随机变量的命题:

随机变量B1,...,Bn在给定A的条件下需要相互独立。这些随机变量可以是离散的或连续的,并且遵循概率分布,例如正态(高斯)分布。

我们还研究了离散随机变量。我们了解到,最佳做法是通过收集足够的数据,确保在给定任何条件(具有值A)的情况下,为离散随机变量的每个值收集一个数据项。

随着独立随机变量的增多,我们可以更准确地确定后验概率。然而,更大的危险在于,这些变量中的某些可能是相关的,导致最终结果不准确。当变量相关时,我们可以去除一些相关变量,只考虑相互独立的变量,或考虑采用其他算法来解决数据科学问题。

在下一章中,我们将学习如何使用决策树算法对元素进行分类。

问题 1:一名患者接受病毒V的检测,测试的准确率为 98%。该病毒V在患者所在地区每 100 人中有 4 人感染:

a) 如果患者检测结果为阳性,患者感染病毒V的概率是多少?

b) 如果测试结果为阴性,患者仍然感染病毒的概率是多少?

问题 2:除了评估患者是否感染病毒V(见问题 1)外,医生通常还会检查其他症状。根据一位医生的说法,大约 85%的患者在出现发热、恶心、腹部不适和乏力等症状时,感染了病毒V:

a) 如果病人出现了之前提到的症状,并且病毒检测结果为阳性,病人感染病毒V的概率是多少?

b) 如果病人出现了之前提到的症状,但测试结果为阴性,病人感染病毒的概率有多大?

问题 3:在某个岛屿上,每两个海啸中就有一个是由地震引发的。过去 100 年内发生了 4 次海啸和 6 次地震。一个地震站记录到岛屿附近海洋发生了地震。这个地震会导致海啸的概率是多少?

问题 4:病人接受四项独立测试,以确定是否患有某种疾病:

我们接诊了一位新病人,第二项和第三项测试为阳性,而第一项和第四项测试为阴性。该病人患有该疾病的概率是多少?

问题 5:我们给出以下包含在邮件中的词汇及这些邮件是否为垃圾邮件的数据:

a) 创建一个朴素贝叶斯算法来判断一封邮件是否为垃圾邮件。当一封邮件包含Money、Rich和Secret这几个词,但不包含Free和Naughty时,算法的结果是什么?

b) 你同意算法的结果吗?在这里使用的朴素贝叶斯算法,作为分类邮件的好方法吗?请证明你的回答。

问题 6:这是一个性别分类问题。假设我们有关于十个人的以下数据:

第 11 个人,身高 172 cm,体重 60 kg,长发的情况下,他是男性的概率是多少?

问题 1:在患者接受测试之前,他们患有病毒的概率是 4%,P(virus)=4%=0.04。测试的准确性为 test_accuracy=98%=0.98。我们应用医学测试示例中的公式:

因此,我们有以下公式:

这意味着,如果测试结果为阳性,患者患有病毒 V 的概率约为 67%:

如果测试结果为阴性,患者仍然可能携带病毒 V,概率为 0.08%。

问题 2:在这里,我们可以假设给定患者已感染病毒 V 的情况下,症状和阳性测试结果是条件独立的事件。我们有以下变量:

由于我们有两个独立的随机变量,因此我们将使用扩展的贝叶斯定理:

所以,患者如果有病毒 V 的症状,并且测试结果为阳性,则该患者有大约 92% 的概率是感染了病毒。

请注意,在前一个问题中,我们得知在测试结果为阳性的情况下,患者患有病毒的概率仅约为 67%。但是,在加入另一个独立随机变量后,即使症状评估仅对 85% 的患者可靠,概率也提高到了 92%。这意味着通常,加入尽可能多的独立随机变量来计算后验概率,以提高准确性和信心,是一个非常好的选择。

b) 在这里,患者有病毒 V 的症状,但测试结果为阴性。因此,我们有以下内容:

因此,某患者在测试中结果为阴性,但有病毒症状V,其感染病毒的概率为 0.48%。

问题 3:我们应用了贝叶斯定理的基本形式:

记录到的地震后,发生海啸的概率为 33%。

请注意,这里我们将P(海啸)设置为过去 100 年某一天发生海啸的概率。我们也使用了一天作为单位来计算P(地震)的概率。如果我们将单位改为小时、周、月等,P(海啸)和P(地震)的结果仍然会保持不变。计算中的关键在于比例P(海啸)😛(地震)=4:6=2/3:1,也就是说,海啸发生的概率大约是地震的 66%。

问题 4:我们将数据输入程序,计算从观测数据得出的后验概率,得到以下结果:

[['否', '是', '是', '否', {'是': 0.0, '否': 1.0}]]

根据这个计算,患者应当没有感染病毒。然而,'否'的概率似乎相当高。为了获得更精确的健康概率估计,获取更多的数据可能是个好主意。

问题 5:

a) 算法的结果如下:

[['是', '否', '是', '否', '是', {'是': 0.8459918784779665, '否': 0.15400812152203341}]]

因此,根据朴素贝叶斯算法,当应用于表格中的数据时,电子邮件是垃圾邮件的概率大约为 85%。

b) 这种方法可能不如预期,因为垃圾邮件中某些词语的出现并不是独立的。例如,包含“money”(钱)一词的垃圾邮件,通常会试图说服受害者相信他们可以通过垃圾邮件发送者获得金钱,因此其他词语,如Rich(富有)、Secret(秘密)或Free(免费)等,更有可能出现在这类邮件中。最近邻算法在垃圾邮件分类中可能表现得更好。你可以通过交叉验证来验证实际方法。

问题 6:对于这个问题,我们将使用扩展的贝叶斯定理,适用于连续和离散随机变量:

让我们通过以下表格总结给定的信息:

从这些数据中,让我们确定确定最终为男性的概率所需的其他值:

因此,身高 172 厘米、体重 60 公斤且有长发的人是男性的概率为 20.3%。因此,他们更可能是女性。

决策树是将数据按树状结构排列的方式,在每个节点处,根据该节点的属性值将数据分成不同的分支。

为了构建决策树,我们将使用标准的 ID3 学习算法,该算法选择一个属性,能以最好的方式对数据样本进行分类,从而最大化信息增益——这是一个基于信息熵的度量方法。

本章我们将涵盖以下主题:

决策树是什么,如何通过游泳偏好的示例在决策树中表示数据

信息熵和信息增益的概念,首先在理论上进行说明,然后在信息论部分通过游泳偏好的示例进行实际应用

如何使用 ID3 算法从训练数据构建决策树,并在 Python 中实现

如何通过游泳偏好的示例,使用构建的决策树对新的数据项进行分类

如何使用决策树对第二章中的国际象棋问题进行替代分析,采用朴素贝叶斯方法,并比较两种算法结果的差异

你将在问题部分验证自己的理解,并了解何时使用决策树作为分析方法

如何在决策树构建过程中处理数据不一致性,使用购物问题示例进行说明

我们可能有一些偏好,决定是否游泳。这些偏好可以记录在表格中,如下所示:

这张表中的数据可以通过以下决策树呈现:

图 3.1:游泳偏好示例的决策树

在根节点,我们问一个问题——你有泳衣吗?问题的回答将可用数据分成三个组,每个组有两行。如果属性是泳衣 = 无,那么这两行的游泳偏好都是否。因此,不需要再问水温的问题,因为所有具有泳衣 = 无属性的样本都会被分类为否。泳衣 = 小属性也一样。对于泳衣 = 好,剩下的两行可以分为两类——否和是。

如果没有更多的信息,我们将无法正确分类每一行。幸运的是,对于每一行,还有一个问题可以问,这个问题能够正确地将其分类。对于水=冷的行,游泳偏好是否;对于水=温暖的行,游泳偏好是是。

总结一下,从根节点开始,我们在每个节点上提问,并根据答案向下移动树直到到达叶节点,在那里我们可以找到与这些答案对应的数据项的类别。

这就是我们如何使用现成的决策树来分类数据样本。但同样重要的是,知道如何从数据中构建决策树。

哪个属性在什么节点上有一个问题?这如何影响决策树的构建?如果我们改变属性的顺序,最终得到的决策树能否比另一棵树更好地进行分类?

信息论研究信息的量化、存储和传递。我们引入了信息熵和信息增益的概念,它们用于使用 ID3 算法构建决策树。

任何给定数据的信息熵是表示该数据项所需的最小信息量的度量。信息熵的单位是熟悉的——比特、字节、千字节等等。信息熵越低,数据就越规律,数据中出现的模式也就越多,从而表示该数据所需的信息量越小。这就是为什么计算机上的压缩工具可以将大型文本文件压缩到更小的大小,因为单词和短语不断重复,形成了模式。

假设我们抛一枚不偏的硬币。我们想知道结果是正面还是反面。我们需要多少信息来表示这个结果?无论是正面还是反面,两个单词都由四个字符组成,如果我们用一个字节(8 位)来表示一个字符,按照 ASCII 表的标准,那么我们需要四个字节,或者 32 位,来表示这个结果。

但信息熵是表示结果所需的最小数据量。我们知道结果只有两种可能——正面或反面。如果我们同意用 0 表示正面,用 1 表示反面,那么 1 比特足以有效地传达结果。在这里,数据是硬币抛掷结果可能性的空间。它是集合{head, tail},可以表示为集合{0, 1}。实际的结果是该集合中的一个数据项。结果表明,这个集合的熵是 1。因为正面和反面的概率都是 50%。

现在假设硬币是偏的,每次抛出时正面朝上的概率是 25%,反面朝上的概率是 75%。这时,概率空间{0,1}的熵是多少?我们当然可以用 1 比特的信息表示结果。但是我们能做得更好吗?1 比特当然是不可分割的,但也许我们可以将信息的概念推广到非离散的量。

在前面的例子中,除非我们查看硬币,否则我们对前一次抛硬币的结果一无所知。但在偏向硬币的例子中,我们知道结果更可能是反面。如果我们在文件中记录了n次抛硬币的结果,将正面表示为 0,反面表示为 1,那么其中大约 75%的比特将为 1,25%的比特将为 0。这样的文件大小将为n比特。但由于它更有规律(1 的模式占主导地位),一个好的压缩工具应该能够将其压缩到小于n比特。

为了学习压缩背后的理论以及表示数据项所需的信息量,让我们来看一下信息熵的精确定义。

假设我们给定了一个概率空间S,其中包含元素1, 2, ..., n。从概率空间中选择元素i的概率为p[i]。该概率空间的信息熵定义如下:

在前面的公式中,log[2]是二进制对数。

因此,公正抛硬币的概率空间的信息熵如下:

当硬币偏向时,正面出现的概率为 25%,反面为 75%,此时该空间的信息熵如下:

这个值小于 1。因此,例如,如果我们有一个大文件,其中约 25%的比特是 0,75%的比特是 1,那么一个好的压缩工具应该能够将其压缩到大约 81.12%的大小。

信息增益是通过某一过程获得的信息熵量。例如,如果我们想知道三次公正的抛硬币结果,那么信息熵为 3。但如果我们能查看第三次抛掷的结果,那么剩下两次抛掷的结果的信息熵为 2。因此,通过查看第三次抛掷,我们获得了一位信息,所以信息增益为 1。

我们也可以通过将整个集合S划分为按相似模式分组的集合,来获得信息熵。如果我们按属性A的值对元素进行分组,那么我们将信息增益定义如下:

这里,S[v] 是集合S中所有属性A值为v的元素集合。

让我们通过将游泳衣作为属性,计算游泳偏好示例中六行数据的信息增益。因为我们关心的是给定数据行是否会被分类为否或是,即是否应该去游泳的问题,因此我们将使用游泳偏好来计算熵和信息增益。我们用游泳衣属性来划分集合S:

S[none]={(none,cold,no),(none,warm,no)}

S[small]={(small,cold,no),(small,warm,no)}

S[good]={(good,cold,no),(good,warm,yes)}

S 的信息熵为:

划分后的信息熵为:

E(S[none])=-(2/2)log2=-log2=0*,原因类似。

因此,信息增益为:

IG(S,泳装)=E(S)-[(2/6)E(S[none])+(2/6)E(S[small])+(2/6)E(S[good])]*

=0.65002242164-(1/3)=0.3166890883

如果我们选择 水温 属性来划分集合 S,那么信息增益 IG(S,水温) 会是多少?水温将集合 S 划分为以下集合:

S[cold]={(none,cold,no),(small,cold,no),(good,cold,no)}

S[warm]={(none,warm,no),(small,warm,no),(good,warm,yes)}

它们的熵如下:

E(S[cold])=0,因为所有实例都被分类为否。

E(S[warm])=-(2/3)log2-(1/3)log2~0.91829583405

因此,使用 水温 属性划分集合 S 得到的信息增益如下:

IG(S,水温)=E(S)-[(1/2)E(S[cold])+(1/2)E(S[warm])]

= 0.65002242164-0.50.91829583405=0.19087450461*

这小于 IG(S,泳装)。因此,我们可以通过根据 泳装 属性划分集合 S(其实例的分类)来获得更多信息,而不是使用 水温 属性。这一发现将成为 ID3 算法在下一节构建决策树的基础。

ID3 算法基于信息增益从数据中构建决策树。一开始,我们从集合 S 开始。集合 S 中的数据项有各种属性,根据这些属性,我们可以对集合 S 进行划分。如果某个属性 A 有值 {v[1], ..., v[n]},那么我们将集合 S 划分为 S[1], ..., S[n],其中集合 S[i] 是集合 S 的一个子集,包含属性 A 对应值为 v[i] 的元素。

如果集合 S 中的每个元素都有属性 A[1], ..., A[m],那么我们可以根据任意可能的属性划分集合 S。ID3 算法根据产生最大信息增益的属性来划分集合 S。现在假设它有属性 A[1],那么对于集合 S,我们有划分 S[1], ..., S[n],其中 A[1] 的可能值为 {v[1], ..., v[n]}。

由于我们还没有构建树,因此首先放置一个根节点。对于 S 的每一个划分,从根节点放置一条新分支。每一条分支代表选定属性的一个值。一条分支包含该属性具有相同值的数据样本。对于每一条新分支,我们可以定义一个新节点,该节点将包含其祖先分支的数据样本。

一旦我们定义了一个新的节点,我们就选择剩余属性中信息增益最高的属性,以便进一步划分该节点上的数据,然后定义新的分支和节点。这个过程可以重复进行,直到节点上的所有属性用完,或者更早地,当节点上的所有数据具有相同的分类(我们感兴趣的类)时。在游泳偏好示例的情况下,游泳偏好只有两个可能的类别——no类和yes类。最后的节点称为叶节点,并决定数据项的分类。

在这里,我们一步一步地描述 ID3 算法如何从给定的游泳偏好示例数据中构建决策树。初始集合由六个数据样本组成:

在前面的章节中,我们计算了两个属性的增益,以及唯一的非分类属性游泳衣和水温的增益,计算如下:

因此,我们会选择游泳衣属性,因为它具有较高的信息增益。此时还没有画出树,所以我们从根节点开始。由于游泳衣属性有三个可能的值——{none, small, good},我们为每个值绘制三个可能的分支。每个分支将有一个来自划分集S:S[none],S[small],和S[good]的划分。我们在分支的末端添加节点。S[none]数据样本具有相同的游泳偏好类别=no,因此我们不需要用进一步的属性来分支该节点并划分集合。因此,包含数据S[none]的节点已经是叶节点。对于包含数据S[small]的节点也一样。

但是,包含数据的节点,S[good],有两种可能的游泳偏好类别。因此,我们会进一步分支该节点。剩下的唯一非分类属性是水温。因此,使用数据S[good]计算该属性的信息增益就没有必要了。从节点S[good]开始,我们会有两个分支,每个分支都来自集合S[good]的一个划分。一个分支将包含数据样本S[good,][cold]={(good,cold,no)};另一个分支将包含划分S[good,][warm]={(good,warm,yes)}。这两个分支将以一个节点结束。每个节点将是叶节点,因为每个节点的数据样本在分类游泳偏好属性上具有相同的值。

结果决策树有四个叶节点,并且是图 3.1 – 游泳偏好示例的决策树中的树。

我们实现了一个 ID3 算法,它从 CSV 文件中给定的数据构建决策树。所有的源代码都位于章节目录中。源代码中最重要的部分如下:

程序输入:

我们将游泳偏好示例的数据输入程序以构建决策树:

程序输出:

一旦我们从具有属性 A[1], ..., A[m] 和类别 {c[1], ..., c[k]} 的数据中构建了决策树,我们就可以使用该决策树将一个具有属性 A[1], ..., A[m] 的新数据项分类到类别 {c[1], ..., c[k]} 中。

给定一个我们希望分类的新数据项,我们可以将每个节点,包括根节点,视为对数据样本的一个问题:该数据样本在选定属性 A[i] 上的值是什么? 然后,根据答案,我们选择决策树的一个分支并继续前进到下一个节点。然后,关于数据样本会再问一个问题,继续这样下去,直到数据样本到达叶节点。叶节点与某个类别 {c[1], ..., c[k]} 相关联;例如,c[i]。然后,决策树算法将该数据样本分类到该类别 c[i] 中。

让我们使用 ID3 算法为游泳偏好示例构建决策树。现在我们已经构建了决策树,我们希望使用它将一个数据样本,(好,冷,?) 分类到 {否, 是} 这两个类别中的一个。

从树的根开始一个数据样本。第一个从根分支出的属性是 泳衣,所以我们询问样本的 泳衣 属性值 (好,冷,?)。我们得知该属性值为 泳衣=好;因此,沿着带有该值的数据样本的最右分支向下移动。我们到达了一个带有 水温 属性的节点,并问:对于该数据样本,水温属性的值是什么(好,冷,?)?我们得知对于该数据样本,水温为 冷;因此,我们向下移动到左侧分支进入叶节点。这个叶节点与 游泳偏好=否 类别相关联。因此,决策树会将数据样本 (好,冷,?) 分类为该游泳偏好类别;换句话说,完成它(通过用确切的数据替换问号),变为数据样本 (好,冷,否)。

因此,决策树表示,如果你有一件好的泳衣,但水温很冷,那么根据表中收集的数据,你仍然不想游泳。

我们再来一个来自第二章的例子,朴素贝叶斯:

我们想知道我们的朋友是否愿意在公园里和我们下棋。这一次,我们希望使用决策树来找到答案。

我们有初始的数据集S,如下所示:

首先,我们确定三个非分类属性的信息增益:temperature(温度)、wind(风速)、sunshine(阳光)。temperature的可能值为Cold(冷)、Warm(温暖)和Hot(热)。因此,我们将集合S划分为三个子集:

我们首先计算这些集合的信息熵:

wind(风速)属性的可能值为None(无风)、Breeze(微风)和Strong(强风)。因此,我们将集合S划分为三个子集:

这些集合的信息熵如下:

最后,第三个属性Sunshine(阳光)有两个可能值:Cloudy(阴天)和Sunny(晴天)。因此,它将集合S划分为两个子集:

这些集合的信息熵如下:

IG(S,wind)和IG(S,temperature)大于IG(S,sunshine)。这两个值相等,因此我们可以选择任意一个属性来形成三个分支;例如,选择第一个属性Temperature(温度)。在这种情况下,每个分支会包含数据样本S[cold]、S[warm]和S[hot]。在这些分支上,我们可以进一步应用算法来形成剩余的决策树。相反,我们可以使用程序来完成这个过程:

输入:

输出:

现在我们已经构建了决策树,我们想用它来将一个数据样本(warm,strong,sunny,?)分类到集合{no,yes}中的一个类别。

我们从根节点开始。该实例的temperature属性值是什么?是温暖,因此我们进入中间分支。该实例的wind属性值是什么?是强,因此该实例将归类为否,因为我们已经到达了叶节点。

因此,根据决策树分类算法,我们的朋友不会在公园与我们下棋。请注意,朴素贝叶斯算法得出的结论恰好相反。要选择最佳的方法,需要对问题有一定的理解。在其他时候,准确性更高的方法是考虑多个算法或多个分类器结果的方法,正如在第四章中所示的随机森林算法。

我们有以下关于我们朋友简的购物偏好的数据:

我们希望通过决策树来找出,如果外部温度寒冷且没有雨,简是否会去购物。

在这里,我们需要小心,因为某些数据实例在相同属性下有相同的值,但类别不同;即(cold,none,yes)和(cold,none,no)。我们编写的程序会形成以下决策树:

但在叶节点[Rain=None]且父节点为[Temperature=Cold]时,有两个数据样本分别属于否和是两个类别。因此,我们无法准确地分类一个实例(cold,none,?)。为了使决策树算法更有效,我们需要在叶节点提供权重最大、即占多数的类别。一个更好的方法是为数据样本收集更多属性值,这样我们就可以更准确地做出决策。

因此,鉴于现有数据,我们无法确定简是否会去购物。

在这一章中,我们了解了决策树 ID3 算法如何从输入数据中首先构建决策树,然后使用构建好的树对新数据实例进行分类。决策树是通过选择信息增益最高的属性来进行分支构建的。我们研究了信息增益如何衡量在信息熵增益方面能够学到的知识量。

我们还了解到,决策树算法可能与其他算法,如朴素贝叶斯算法,产生不同的结果。

在下一章中,我们将学习如何将多种算法或分类器组合成一个决策森林(称为随机森林),以获得更准确的结果。

问题 1:以下多重集合的信息熵是多少?

a) {1,2},b) {1,2,3},c) {1,2,3,4},d) {1,1,2,2},e) {1,1,2,3}

问题 2:偏置硬币的概率空间的信息熵是多少?该硬币显示正面概率为 10%,反面为 90%?

问题 3:让我们来看一下第二章中的另一个例子,朴素贝叶斯,关于下棋的例子:

a) 表中每个非分类属性的信息增益是多少?

b) 根据给定的表格,构建出的决策树是什么?

c) 如何根据构建的决策树对数据样本(温暖, 强风, 春季, ?)进行分类?

问题 4:玛丽与温度偏好:让我们来看一下第一章中的例子,使用 K 近邻进行分类,关于玛丽的温度偏好:

我们想使用决策树来判断我们的朋友玛丽在温度为 16°C,风速为 3 km/h 的房间中会感觉温暖还是寒冷。

你能解释一下如何在这里使用决策树算法吗?并说明使用它对于这个例子的益处?

问题 1:以下是多重集的熵值:

需要注意的是,具有多个类别的多重集的信息熵大于 1,因此我们需要多个比特来表示结果。但对于每个具有多个类别元素的多重集,这种情况都成立吗?

问题 3:a) 三个属性的信息增益如下:

b) 因此,我们会选择季节属性作为从根节点分支的依据,因为它具有最高的信息增益。或者,我们可以将所有输入数据放入程序中,构建决策树,如下所示:

c) 根据构建的决策树,我们将数据样本(warm,strong,spring,?)分类为Play=Yes,方法是从根节点向下走到最底层分支,然后通过走中间分支到达叶子节点。

问题 4:在这里,决策树算法在没有对数据进行任何处理的情况下可能表现不佳。如果我们考虑每一种温度类别,那么 25°C 仍然不会出现在决策树中,因为它不在输入数据中,因此我们无法分类玛丽在 16°C 和 3 km/h 的风速下的感受。

我们可以选择将温度和风速划分为区间,以减少类别数,从而使得最终的决策树能够对输入实例进行分类。但正是这种划分,即 25°C 和 3 km/h 应该归类到哪些区间,才是分析这种问题的基本过程。因此,未经任何重大修改的决策树无法很好地分析这个问题。

随机森林是由一组随机决策树组成的(类似于第三章中描述的决策树),每棵树都是在数据的随机子集上生成的。随机森林通过大多数随机决策树投票所选的类别来分类特征。与决策树相比,随机森林通常能够提供更准确的分类,因为它们的偏差和方差较低。

本章将涵盖以下主题:

作为随机森林构建的一部分,树袋法(或自助聚合)技术,但也可以扩展到数据科学中的其他算法和方法,以减少偏差和方差,从而提高准确性

如何构建一个随机森林并使用通过游泳偏好示例构建的随机森林对数据项进行分类

如何在 Python 中实现一个构建随机森林的算法

使用下棋的例子,分析 Naive Bayes 算法、决策树和随机森林的区别

随机森林算法如何克服决策树算法的缺点,并通过购物的例子展示其优势

如何通过购物的例子展示随机森林如何表达其对特征分类的置信度

如何通过减少分类器的方差来获得更准确的结果,在问题部分进行讨论

通常,为了构建一个随机森林,首先我们需要选择它包含的树的数量。随机森林通常不会过拟合(除非数据非常嘈杂),因此选择更多的决策树不会降低预测的准确性。随机森林通常不会过拟合(除非数据非常嘈杂),因此增加决策树的数量不会显著降低预测准确性。重要的是要选择足够数量的决策树,以便在随机选择用于构建决策树的数据时,更多的数据用于分类。另一方面,树木越多,所需的计算能力越大。此外,增加决策树的数量并不会显著提高分类准确度。

在实践中,你可以在特定数量的决策树上运行算法,增加它们的数量,并比较较小和较大森林的分类结果。如果结果非常相似,那么就没有必要增加树木的数量。

为了简化演示,本书中我们将使用少量的决策树来构建随机森林。

我们将描述如何以随机的方式构建每棵树。我们通过随机选择N个训练特征来构建决策树。这个从数据中随机选择并进行替换的过程,称为自助聚合(bootstrap aggregating),或树袋法(tree bagging)。自助聚合的目的是减少分类结果中的方差和偏差。

假设一个特征有M个变量,这些变量用于使用决策树对特征进行分类。当我们在节点上做出分支决策时,在 ID3 算法中,我们选择产生最大信息增益的变量。在这里,在随机决策树中,每个节点我们最多只考虑m个变量。我们不考虑那些已经被随机选择且没有替换的M个变量中的变量。然后,在这m个变量中,我们选择产生最大信息增益的变量。

随机决策树的其余构建过程与第三章中的决策树构建过程相同,参见决策树部分。

我们将使用来自第三章的关于游泳偏好的示例。我们有相同的数据表,具体如下:

我们希望从这些数据构建一个随机森林,并使用它来对一个项目(好,冷,?)进行分类。

我们给定了M=3个变量,根据这些变量可以对特征进行分类。在随机森林算法中,我们通常不会在每个节点使用所有三个变量来形成树枝。我们只会使用从M中随机选择的一个子集(m)的变量。所以我们选择m使得m小于或等于M。m的值越大,每个构建的树中的分类器就越强。然而,正如前面提到的,更多的数据会导致更多的偏差。但是,因为我们使用多棵树(每棵树的m较小),即使每棵构建的树是一个弱分类器,它们的联合分类准确度仍然较强。为了减少随机森林中的偏差,我们可能希望选择一个略小于M的m参数。

我们提供以下特征:

在构建随机森林中的随机决策树时,我们只会随机选择这些特征的一个子集,并且进行替换。

我们将构建一个由两棵随机决策树组成的随机森林。

我们得到六个特征作为输入数据。在这些特征中,我们随机选择六个特征并带有替换地用于构建这个随机决策树:

我们从根节点开始构建,创建树的第一个节点。我们想要向[root]节点添加子节点。

我们有以下可用变量:['swimming_suit', 'water_temperature']。由于这些变量少于m=3参数的数量,我们将考虑这两个变量。在这些变量中,信息增益最高的是游泳衣。

因此,我们将根据该变量继续分支节点。我们还将从当前节点的子节点可用变量列表中移除此变量。使用swimming_suit变量,我们在当前节点上划分数据,如下所示:

swimming_suit=Small的划分:[['Small', 'Cold', 'No']]

swimming_suit=None的划分:[['None', 'Warm', 'No'], ['None', 'Warm', 'No']]

swimming_suit=Good的划分:[['Good', 'Cold', 'No'], ['Good', 'Cold', 'No'], ['Good', 'Cold', 'No']]

使用前述的划分,我们创建了分支和子节点。

现在我们向[root]节点添加一个子节点[swimming_suit=Small]。该分支对一个特征进行分类:[['Small', 'Cold', 'No']]。

我们希望向[swimming_suit=Small]节点添加子节点。

我们有以下可用变量:['water_temperature']。由于这里只有一个变量,且少于m=3参数,因此我们将考虑这个变量。信息增益最高的是water_temperature变量。因此,我们将根据该变量继续分支节点。我们还将从当前节点的子节点可用变量列表中移除此变量。对于选定的变量water_temperature,所有剩余特征的值都是Cold。因此,我们在此分支的末尾加上一个叶节点,添加[swim=No]。

现在我们向[root]节点添加一个子节点[swimming_suit=None]。该分支对两个特征进行分类:[['None', 'Warm', 'No'], ['None', 'Warm', 'No']]。

我们希望向[swimming_suit=None]节点添加子节点。

我们有以下可用变量:['water_temperature']。由于这里只有一个变量,且少于m=3参数,因此我们将考虑这个变量。信息增益最高的是water_temperature变量。因此,我们将根据该变量继续分支节点。我们还将从当前节点的子节点可用变量列表中移除此变量。对于选定的变量water_temperature,所有剩余特征的值都是Warm。因此,我们在此分支的末尾加上一个叶节点,添加[swim=No]。

现在我们向[root]节点添加一个子节点[swimming_suit=Good]。该分支对三个特征进行分类:[['Good', 'Cold', 'No'], ['Good', 'Cold', 'No'], ['Good', 'Cold', 'No']]

我们希望向[swimming_suit=Good]节点添加子节点。

我们可以使用以下变量:['water_temperature']。由于这里只有一个变量,它小于m=3参数,因此我们会考虑这个变量。信息增益最高的变量是water_temperature变量。因此,我们将继续在这个变量上分支。我们还会将该变量从当前节点子节点的可用变量列表中移除。对于选择的变量water_temperature,所有剩余特征的值相同:Cold。所以,我们以叶节点结束这个分支,添加[swim=No]。

现在,我们已经将所有子节点添加到[root]节点。

我们提供了六个特征作为输入数据。我们从中随机选择六个特征,并允许重复,以构建这个随机决策树:

随机决策树 1 的其余构建过程与之前的随机决策树 0 类似。唯一的区别是,树是使用不同的随机生成子集(如之前所见)构建的。

我们从根节点开始构建,以创建树的第一个节点。我们希望向[root]节点添加子节点。

我们可以使用以下变量:['swimming_suit', 'water_temperature']。由于这里只有一个变量,它小于m=3参数,因此我们会考虑这个变量。在这些变量中,信息增益最高的是swimming_suit变量。

因此,我们将在这个变量上继续分支。我们还会将该变量从当前节点子节点的可用变量列表中移除。使用swimming_suit变量,我们将当前节点的数据划分如下:

swimming_suit=Small的划分:[['Small', 'Warm', 'No']]

swimming_suit=None的划分:[['None', 'Warm', 'No'], ['None', 'Cold', 'No'], ['None', 'Warm', 'No']]

swimming_suit=Good的划分:[['Good', 'Warm', 'Yes'], ['Good', 'Cold', 'No']]

现在,给定划分后,让我们创建分支和子节点。我们向[root]节点添加一个子节点[swimming_suit=Small]。这个分支分类了一个特征:[['Small', 'Warm', 'No']]。

我们希望向[swimming_suit=Small]节点添加子节点。

我们可以使用以下变量:['water_temperature']。由于这里只有一个变量,它小于m=3参数,因此我们会考虑这个变量。信息增益最高的变量是water_temperature变量。因此,我们将继续在这个变量上分支。我们还会将该变量从当前节点子节点的可用变量列表中移除。对于选择的变量water_temperature,所有剩余特征的值相同:Warm。所以,我们以叶节点结束这个分支,添加[swim=No]。

我们将一个子节点[swimming_suit=None]添加到[root]节点。此分支分类了三个特征:[['None', 'Warm', 'No']]、[['None', 'Cold', 'No']]和[['None', 'Warm', 'No']]。

我们想要为[swimming_suit=None]节点添加子节点。

我们有以下可用的变量:['water_temperature']。由于这里只有一个变量,这个数量小于m=3参数,我们将考虑这个变量。信息增益最高的是water_temperature变量。因此,我们将基于这个变量进一步拆分节点。我们还将从当前节点的子节点的可用变量列表中移除此变量。使用water_temperature变量,我们将数据在当前节点中进行如下分区:

water_temperature=Cold的分区:[['None', 'Cold', 'No']]。

water_temperature=Warm的分区:[['None', 'Warm', 'No']];现在,根据这些分区,让我们创建分支和子节点。

我们将一个子节点[water_temperature=Cold]添加到[swimming_suit=None]节点。此分支分类了一个特征:[['None', 'Cold', 'No']]。

我们没有任何可用的变量可以进一步拆分该节点;因此,我们在当前树分支上添加一个叶节点。我们添加了[swim=No]叶节点。我们将一个子节点[water_temperature=Warm]添加到[swimming_suit=None]节点。此分支分类了两个特征:[['None', 'Warm', 'No']]和[['None', 'Warm', 'No']]。

我们没有任何可用的变量可以进一步拆分该节点;因此,我们在当前树分支上添加一个叶节点。我们添加了[swim=No]叶节点。

现在,我们已经将所有子节点添加到[swimming_suit=None]节点。

我们将一个子节点[swimming_suit=Good]添加到[root]节点。此分支分类了两个特征:[['Good', 'Warm', 'Yes']]和[['Good', 'Cold', 'No']]。

我们想要为[swimming_suit=Good]节点添加子节点。

我们有以下可用的变量:['water_temperature']。由于这里只有一个变量,这个数量小于m=3参数,我们将考虑这个变量。信息增益最高的是water_temperature变量。因此,我们将基于这个变量进一步拆分节点。我们还将从当前节点的子节点的可用变量列表中移除此变量。使用water_temperature变量,我们将数据在当前节点中进行如下分区:

water_temperature=Cold的分区:[['Good', 'Cold', 'No']]。

water_temperature=Warm的分区:[['Good', 'Warm', 'Yes']]。

现在,根据这些分区,让我们创建分支和子节点。

我们将一个子节点[water_temperature=Cold]添加到[swimming_suit=Good]节点。此分支分类了一个特征:[['Good', 'Cold', 'No']]。

我们没有任何可用的变量来进一步划分节点;因此,我们向当前树的分支添加了一个叶节点。我们添加了[swim=No]叶节点。

我们在[swimming_suit=Good]节点下添加了一个子节点[water_temperature=Warm]。该分支分类一个特征:[['Good', 'Warm', 'Yes']]。

我们没有任何可用的变量来进一步划分节点;因此,我们向当前树的分支添加了一个叶节点。我们添加了[swim=Yes]叶节点。

现在,我们已经添加了[swimming_suit=Good]节点的所有子节点。

我们也已经添加了[root]节点的所有子节点。

我们已经完成了随机森林的构建,随机森林由两个随机决策树组成,如下方代码块所示:

因为我们只使用了原始数据的一个子集来构建随机决策树,所以可能没有足够的特征来构建能够分类每个特征的完整树。在这种情况下,树不会为应该分类的特征返回任何类别。因此,我们只会考虑能够分类特定类别特征的树。

我们希望分类的特征是['Good', 'Cold', '?']。随机决策树通过相同的方法对特征进行分类,就像在第三章《决策树》中那样。树 0 为No类别投票。树 1 为No类别投票。获得最多投票的类别是No。因此,构建的随机森林将特征['Good', 'Cold', '?']分类为No类别。

我们使用上一章节中的修改版决策树算法实现了一个随机森林算法。我们还在程序中添加了一个选项,可以设置详细模式,描述算法在特定输入上的整个工作过程——如何用随机决策树构建一个随机森林,以及如何使用这个构建好的随机森林来分类其他特征。

输入:

作为已实现算法的输入文件,我们提供了来自游泳偏好示例的数据:

输出:

我们在命令行中输入以下命令来获取输出:

我们将再次使用第二章的示例,朴素贝叶斯,以及第三章,决策树,如下所示:

然而,我们希望使用由四棵随机决策树组成的随机森林来进行分类结果的预测。

我们提供了M=4个变量用于特征分类。因此,我们选择在节点中考虑的变量的最大数量为:

我们提供了以下特征:

在构建随机森林中的随机决策树时,我们将仅随机选择这些特征中的一部分,并对其进行替换。

我们将构建一个随机森林,由四棵随机决策树组成。

随机决策树构建 0

我们提供了 10 个特征作为输入数据。在这些特征中,我们随机选择所有特征及其替换项来构建这棵随机决策树:

我们从根节点开始构建,以创建树的第一个节点。我们希望为[root]节点添加子节点。

我们有以下可用的变量:['Temperature', 'Wind', 'Sunshine']。由于这些变量的数量少于m=4的参数,因此我们考虑所有的变量。在这些变量中,信息增益最高的是Temperature变量。因此,我们将基于此变量进一步分支当前节点。同时,我们会将该变量从当前节点的子节点可用变量列表中移除。利用Temperature变量,我们将当前节点的数据划分如下:

Temperature=Cold的划分:[['Cold', 'Breeze', 'Cloudy', 'No'], ['Cold', 'None', 'Sunny', 'Yes'], ['Cold', 'Breeze', 'Cloudy', 'No'], ['Cold', 'Breeze', 'Cloudy', 'No']]

Temperature=Warm的划分:[['Warm', 'Strong', 'Cloudy', 'No'], ['Warm', 'Strong', 'Cloudy', 'No'], ['Warm', 'Breeze', 'Sunny', 'Yes']]

Temperature=Hot的划分:[['Hot', 'Breeze', 'Cloudy', 'Yes'], ['Hot', 'Breeze', 'Cloudy', 'Yes'], ['Hot', 'Breeze', 'Cloudy', 'Yes']]

现在,给定这些划分,让我们创建分支和子节点。

我们为[root]节点添加一个子节点[Temperature=Cold]。此分支对四个特征进行分类:[['Cold', 'Breeze', 'Cloudy', 'No'],['Cold', 'None', 'Sunny', 'Yes'],['Cold', 'Breeze', 'Cloudy', 'No'],['Cold', 'Breeze', 'Cloudy', 'No']]。

我们希望为[Temperature=Cold]节点添加子节点。

我们有以下可用变量:['Wind', 'Sunshine']。由于这些变量的数量少于m=3参数,我们考虑了这两个变量。信息增益最高的是Wind变量。因此,我们将在此变量上进一步分支。我们还会将该变量从当前节点子节点的可用变量列表中移除。使用Wind变量,我们将当前节点的数据划分如下:

Wind=None的划分为:[['Cold', 'None', 'Sunny', 'Yes']]

Wind=Breeze的划分为:[['Cold', 'Breeze', 'Cloudy', 'No'], ['Cold', 'Breeze', 'Cloudy', 'No'], ['Cold', 'Breeze', 'Cloudy', 'No']]

现在,根据这些划分,让我们创建分支和子节点。

我们在[Temperature=Cold]节点下添加了一个子节点[Wind=None]。这个分支对单一特征进行分类:[['Cold', 'None', 'Sunny', 'Yes']]。

我们想要在[Wind=None]节点下添加子节点。

我们有以下变量:available['Sunshine']。由于这些变量的数量少于m=3参数,我们考虑了这两个变量。信息增益最高的是Sunshine变量。因此,我们将在此变量上进一步分支。我们还会将该变量从当前节点子节点的可用变量列表中移除。对于所选变量Sunshine,所有剩余特征的值相同:Sunny。因此,我们将分支终止,并添加叶子节点[Play=Yes]。

我们在[Temperature=Cold]节点下添加了一个子节点[Wind=Breeze]。这个分支对三个特征进行分类:[['Cold', 'Breeze', 'Cloudy', 'No'], ['Cold', 'Breeze', 'Cloudy', 'No'], ['Cold', 'Breeze', 'Cloudy', 'No']]。

我们想要在[Wind=Breeze]节点下添加子节点。

我们有以下可用变量:['Sunshine']。由于这些变量的数量少于m=3参数,我们考虑了这两个变量。信息增益最高的是Sunshine变量。因此,我们将在此变量上进一步分支。我们还会将该变量从当前节点子节点的可用变量列表中移除。对于所选变量Sunshine,所有剩余特征的值相同:Cloudy。因此,我们将分支终止,并添加叶子节点[Play=No]。

现在,我们已经为[Temperature=Cold]节点添加了所有子节点。

我们在[root]节点下添加了一个子节点[Temperature=Warm]。这个分支对三个特征进行分类:[['Warm', 'Strong', 'Cloudy', 'No'], ['Warm', 'Strong', 'Cloudy', 'No'], ['Warm', 'Breeze', 'Sunny', 'Yes']]。

我们想要在[Temperature=Warm]节点下添加子节点。

我们仍然剩下的可用变量是['Wind', 'Sunshine']。由于这些变量的数量少于m=3的参数,我们考虑这两个变量。信息增益最高的是Wind变量。因此,我们将在这个变量上进一步分支节点。我们还会从当前节点的可用变量列表中移除这个变量。使用Wind变量,我们将当前节点中的数据进行划分,每个数据分区将对应当前节点的一个新分支,[Temperature=Warm]。我们得到以下分区:

Wind=Breeze的分区为:[['Warm', 'Breeze', 'Sunny', 'Yes']]

Wind=Strong的分区为:[['Warm', 'Strong', 'Cloudy', 'No'], ['Warm', 'Strong', 'Cloudy', 'No']]

现在,根据这些分区,让我们形成分支和子节点。

我们在[Temperature=Warm]节点上添加一个子节点,[Wind=Breeze]。这个分支对一个特征进行分类:[['Warm', 'Breeze', 'Sunny', 'Yes']]。

我们希望为[Wind=Breeze]节点添加子节点。

我们剩下的可用变量是['Sunshine']。由于这些变量的数量少于m=3的参数,我们考虑这两个变量。信息增益最高的是Sunshine变量。因此,我们将在这个变量上进一步分支节点。我们还会从当前节点的可用变量列表中移除这个变量。对于选择的变量Sunshine,所有剩余特征的值相同:Sunny。所以,我们以一个叶子节点结束这个分支,添加[Play=Yes]。

我们在[Temperature=Warm]节点上添加一个子节点,[Wind=Strong]。这个分支对两个特征进行分类:[['Warm', 'Strong', 'Cloudy', 'No'], 和 ['Warm', 'Strong', 'Cloudy', 'No']]

我们希望为[Wind=Strong]节点添加子节点。

我们剩下的可用变量是['Sunshine']。由于这些变量的数量少于m=3的参数,我们考虑这两个变量。信息增益最高的是Sunshine变量。因此,我们将在这个变量上进一步分支节点。我们还会从当前节点的可用变量列表中移除这个变量。对于选择的变量Sunshine,所有剩余特征的值相同:Cloudy。所以,我们以一个叶子节点结束这个分支,添加[Play=No]。

现在,我们已经为[Temperature=Warm]节点添加了所有子节点。

我们在[root]节点上添加一个子节点,[Temperature=Hot]。这个分支对三个特征进行分类:[['Hot', 'Breeze', 'Cloudy', 'Yes'], ['Hot', 'Breeze', 'Cloudy', 'Yes'], 和 ['Hot', 'Breeze', 'Cloudy', 'Yes']]。

我们希望为[Temperature=Hot]节点添加子节点。

我们可以使用以下变量:['风', '阳光']。由于这些变量少于m=3参数,所以我们考虑这两个变量。信息增益最高的是风变量。因此,我们将在该变量上进一步分支节点。我们还将从当前节点的可用变量列表中移除此变量。对于选择的变量风,所有剩余的特征值相同:微风。因此,我们以一个叶子节点结束该分支,添加[Play=Yes]。

现在,我们已经将所有子节点添加到[root]节点。

构建随机决策树 1、2、3

我们以类似的方式构建接下来的三棵树。需要注意的是,由于构建是随机的,执行另一个正确构建的读者可能会得到不同的结果。然而,如果在随机森林中有足够数量的随机决策树,那么分类结果应该在所有随机构建中非常相似。

构建的随机森林:

给定构建的随机森林,我们将特征['Warm', 'Strong', 'Sunny', '?']分类:

树 0 投票给类别:No

树 1 投票给类别:No

树 2 投票给类别:No

树 3 投票给类别:No

拥有最多投票数的类别是No。因此,构建的随机森林将特征['Warm', 'Strong', 'Sunny', '?']分类为No类别。

输入:

为了执行前面的分析,我们使用了本章早些时候实现的程序。首先,我们将表格中的数据插入到以下 CSV 文件中:

输出:

我们通过执行以下命令行来生成输出:

我们从上一章的问题开始。我们有关于我们朋友简(Jane)购物偏好的以下数据:

在上一章中,决策树无法对特征 (Cold, None) 进行分类。因此,这次我们希望使用随机森林算法来判断,如果温度寒冷且没有降雨,简会不会去购物。

为了使用随机森林算法进行分析,我们使用已实现的程序。

输入:

我们将表格中的数据插入以下 CSV 文件:

输出:

我们希望使用比前面的示例和解释中更多的树来获得更精确的结果。我们希望构建一个包含 20 棵树的随机森林,并且输出的详细程度为低级别——级别 0。因此,我们在终端中执行以下操作:

然而,我们应该注意到,只有 20 棵树中的 12 棵投了“是”的票。因此,虽然我们有了明确的答案,但它可能不那么确定,类似于我们使用普通决策树时得到的结果。然而,与决策树中的数据不一致导致无法得出答案不同的是,在这里我们得到了一个答案。

此外,通过衡量每个类别的投票权重,我们可以衡量答案正确的置信度。在此案例中,特征['Cold', 'None', '?']属于*Yes*类别,置信度为 12/20,或者 60%。为了更精确地确定分类的确定性,需要使用一个更大的随机决策树集成。

在本章中,我们了解到随机森林是一组决策树,其中每棵树都是从初始数据中随机选择的样本构建的。这个过程叫做自助聚合。它的目的是减少随机森林在分类时的方差和偏差。在构建决策树的过程中,通过仅考虑每个分支的随机变量子集,进一步减少偏差。

我们还了解到,一旦构建了随机森林,随机森林的分类结果就是所有树中的多数投票。多数票的水平也决定了答案正确的置信度。

由于随机森林由决策树组成,因此它适用于所有决策树表现良好的问题。因为随机森林可以减少决策树分类器中的偏差和方差,所以它们的性能优于决策树算法。

在下一章中,我们将学习将数据聚类到相似簇中的技术。我们还将利用该技术将数据分类到已创建的簇中。

问题 1:让我们以第二章《朴素贝叶斯》中的下棋例子为例,如何根据随机森林算法对 (Warm, Strong, Spring, ?) 数据样本进行分类?

问题 2:只使用一棵树和一个随机森林是一个好主意吗?请说明你的理由。

问题 3:交叉验证能否改善随机森林分类的结果?请说明你的理由。

问题 1:我们运行程序来构建随机森林并对特征(Warm, Strong, Spring)进行分类。

输入:

输出:

我们在随机森林中构建了四棵树,具体如下:

再次执行前面的命令很可能会导致不同的输出和不同的随机森林图。然而,由于随机决策树的多样性及其投票权的结合,分类结果很可能相似。单个随机决策树的分类可能会受到显著的方差影响。然而,多数投票将所有树的分类结果结合起来,从而减少了方差。为了验证你的理解,你可以将你的分类结果与以下随机森林图中的分类进行比较。

随机森林图和分类:

我们来看看随机森林图的输出和特征的分类:

问题 2:当我们在随机森林中构建一棵树时,我们只使用数据的随机子集,并进行有放回抽样。这样做是为了消除分类器对某些特征的偏向。然而,如果只使用一棵树,这棵树可能恰好包含有偏向的特征,并且可能缺少一些重要特征,无法提供准确的分类。因此,使用仅有一棵决策树的随机森林分类器可能会导致非常差的分类结果。因此,我们应该在随机森林中构建更多的决策树,以便从减少偏差和方差的分类中获益。

问题 3:在交叉验证过程中,我们将数据分为训练数据和测试数据。训练数据用于训练分类器,测试数据用于评估哪些参数或方法最适合改进分类。交叉验证的另一个优点是减少了偏差,因为我们只使用部分数据,从而减少了过拟合特定数据集的可能性。

然而,在决策森林中,我们以一种替代的方式解决交叉验证所解决的问题。每个随机决策树仅在数据的子集上构建——从而减少了过拟合的可能性。最终,分类是这些树的结果的组合。最终的最佳决策,并不是通过在测试数据集上调优参数来做出的,而是通过对所有树进行多数投票,从而减少偏差。

因此,决策森林算法的交叉验证并不会太有用,因为它已经内置于算法中了。

聚类是一种将数据划分为簇的技术,相同特征的项会被归为同一个簇。

在本章中,我们将覆盖以下主题:

如何使用k-均值聚类算法,通过涉及家庭收入的例子来演示

如何通过将特征与已知类别一起聚类,使用性别分类的例子来对特征进行分类

如何在实现 k 均值聚类算法部分中使用 Python 实现k-均值聚类算法

房屋拥有情况的例子,以及如何为你的分析选择合适的簇数

如何通过使用聚类算法,利用房屋拥有情况的例子,合理地缩放给定的数值数据,以提高分类的准确性

理解不同簇数如何改变簇与簇之间分界线的含义,通过文档聚类的例子来说明

例如,我们来看一下年收入分别为 40,000 美元、55,000 美元、70,000 美元、100,000 美元、115,000 美元、130,000 美元和 135,000 美元的家庭。然后,如果我们将这些家庭根据收入作为相似度标准分为两个簇,第一个簇会包括年收入为 40k、55k 和 70k 的家庭,而第二个簇会包括年收入为 100k、115k、130k 和 135k 的家庭。

这是因为 40k 和 135k 相距最远,所以我们希望分成两个簇,它们必须分别属于不同的簇。55k 比 135k 更接近 40k,因此 40k 和 55k 会在同一个簇。类似地,130k 和 135k 会在同一个簇。70k 比 130k 和 135k 更接近 40k 和 55k,因此 70k 应该和 40k、55k 在同一个簇。115k 比 40k、55k 和 70k 所在的第一个簇更接近 130k 和 135k,因此它会在第二个簇。最后,100k 更接近包含 115k、130k 和 135k 的第二个簇,因此它会被归类到那里。因此,第一个簇将包括年收入为 40k、55k 和 70k 的家庭。第二个簇将包括年收入为 100k、115k、130k 和 135k 的家庭。

聚类具有相似属性的组的特征,并将簇分配给某个特征是一种分类形式。数据科学家需要解释聚类结果以及它所引发的分类。在这里,包含年收入为 40k、55k 和 70k 家庭的簇代表了低收入家庭类。第二个簇,包括年收入为 100k、115k、130k 和 135k 的家庭,代表了高收入家庭类。

我们根据直觉和常识,非正式地将家庭收入划分为两个簇。也有一些聚类算法根据精确的规则对数据进行聚类。这些算法包括模糊 C 均值聚类算法、层次聚类算法、高斯(EM)聚类算法、质量阈值聚类算法和k均值聚类算法,本章将重点介绍后者。

k均值聚类算法将给定的点分类到k个组中,使得同一组内的成员之间的距离最小。

k均值聚类算法确定初始的k质心(每个簇的中心点)——每个簇一个质心。然后,每个特征会被分类到与该特征距离最近的簇中。分类所有特征之后,我们就形成了初始的k个簇。

对于每个簇,我们重新计算质心,作为该簇内所有点的平均值。在移动了质心之后,我们再次重新计算类别。类别中的特征可能会发生变化。在这种情况下,我们需要重新计算质心。如果质心不再移动,则k均值聚类算法终止。

我们可以将初始的k个质心选择为数据中任意的k个特征。但是,理想情况下,我们希望从一开始就选择属于不同簇的点。因此,我们可能希望通过某种方式最大化它们之间的相互距离。简化过程后,我们可以将第一个质心选为数据中任意一个点。第二个质心可以选为距离第一个质心最远的点。第三个质心可以选为同时距离第一个和第二个质心最远的点,依此类推。

我们将应用k聚类算法来分析家庭收入的例子。一开始,我们有收入分别为$40,000、$55,000、$70,000、$100,000、$115,000、$130,000 和$135,000 的家庭。

第一个被选择的质心可以是任何特征,例如,$70,000. 第二个质心应该是与第一个最远的特征,即 135 k,因为 135 k 减去 70 k 是 65 k,这是任何其他特征与 70 k 之间的最大差异。因此,70 k 是第一个簇的质心,而 135 k 是第二个簇的质心。

现在,通过差异,40 k、55 k、70 k 和 100 k 更接近 70 k 而不是 135 k,因此它们将位于第一个簇中,而 115 k、130 k 和 135 k 更接近 135 k 而不是 70 k,因此它们将位于第二个簇中。

在根据初始质心对特征进行分类之后,我们重新计算质心。第一个簇的质心如下:

第二个簇的质心如下:

使用新的质心,我们重新分类特征如下:

包含质心 66.25 k 的第一个簇将包含特征 40 k、55 k 和 70 k

包含质心 126.66 k 的第二个簇将包含特征 100 k、115 k、130 k 和 135 k

我们注意到,100 k 特征从第一个簇移动到第二个簇,因为它现在更接近第二个簇的质心(距离 |100 k-126.66 k|=26.66 k),而不是第一个簇的质心(距离 |100 k-66.25 k|=33.75 k)。由于簇中的特征已经改变,我们必须重新计算质心。

第一个簇的质心如下:

第二个簇的质心如下:

使用这些质心,我们将特征重新分类到簇中。第一个质心,55 k,将包含特征 40 k、55 k 和 70 k。第二个质心,120 k,将包含特征 100 k、115 k、130 k 和 135 k。因此,在更新质心时,簇没有改变。因此,它们的质心将保持不变。

因此,算法以两个簇终止:第一个簇包含特征 40 k、55 k 和 70 k,第二个簇包含特征 100 k、115 k、130 k 和 135 k。

下面的数据来自性别分类示例,问题 6,第二章,朴素贝叶斯:

为了简化问题,我们将移除名为 Hair length 的列。我们还将移除名为 Gender 的列,因为我们希望根据身高和体重对表中的人进行聚类。我们希望通过聚类判断表中第十一位人的性别更可能是男性还是女性:

我们可以对初始数据进行缩放,但为了简化问题,我们将在算法中使用未经缩放的数据。我们将把已有数据聚类为两个簇,因为性别只有两种可能——男性或女性。然后,我们将根据聚类结果来分类一个身高为 172 厘米、体重为 60 公斤的人,如果且仅当该聚类中男性更多时,才将其归类为男性。聚类算法是一种非常高效的技术。因此,以这种方式进行分类非常快速,尤其是在需要分类的特征非常多的情况下。

所以,让我们对已有数据应用 k-均值聚类算法。首先,选择初始质心。例如,将第一个质心设为一个身高 180 厘米、体重 75 公斤的人,用向量表示为 (180,75)。与 (180,75) 最远的点是 (155,46)。所以它将作为第二个质心。

通过计算欧几里得距离,离第一个质心 (180,75) 最近的点是 (180,75), (174,71), (184,83), (168,63), (178,70), (170,59) 和 (172,60)。所以这些点将属于第一个簇。离第二个质心 (155,46) 最近的点是 (155,46), (164,53), (162,52) 和 (166,55)。所以这些点将属于第二个簇。涉及这两个聚类的当前情况如下面的图示所示:

图 5.1:根据身高和体重对人的聚类

让我们重新计算聚类的质心。具有特征 (180,75), (174,71), (184,83), (168,63), (178,70), (170,59) 和 (172,60) 的蓝色聚类将有质心 ((180+174+184+168+178+170+172)/7,(75+71+83+63+70+59+60)/7)~(175.14,68.71)。

红色聚类包含特征 (155,46), (164,53), (162,52) 和 (166,55),其质心为 ((155+164+162+166)/4,(46+53+52+55)/4)=(161.75, 51.5)。

使用新的质心重新分类点时,点的类别没有变化。蓝色聚类将包含点 (180,75), (174,71), (184,83), (168,63), (178,70), (170,59) 和 (172,60)。红色聚类将包含点 (155,46), (164,53), (162,52) 和 (166,55)。因此,聚类算法在以下图示中结束,得到了聚类:

图 5.2:根据身高和体重对人的聚类

现在我们希望将实例 (172,60) 分类为男性还是女性。实例 (172,60) 位于蓝色簇中,因此它与蓝色簇中的特征相似。剩余的特征是在蓝色簇中更可能是男性还是女性呢?六个特征中有五个是男性,只有一个是女性。由于蓝色簇中的大多数特征是男性,而且 (172,60) 也位于蓝色簇中,因此我们将身高 172 cm、体重 60 kg 的人分类为男性。

我们现在将实现 k-means 聚类算法。它以 CSV 文件作为输入,每一行代表一个数据项。每个数据项被转换为一个点。算法将这些点分为指定数量的簇。最终,聚类结果将在图表上可视化,使用 matplotlib 库:

我们将性别分类示例中的数据保存到 CSV 文件中,如下所示:

我们运行程序,实施 k-means 聚类算法在性别分类示例的数据上。数值参数 2 表示我们希望将数据聚类成两个簇,如下方代码块所示:

程序还输出了一个图表,见于图 5.2。last 参数表示我们希望程序进行聚类直到最后一步。如果我们只想显示第一步(步骤 0),可以将 last 改为 0,如下面的代码所示:

在程序执行后,我们将得到一个关于聚类及其质心的图像,如图 5.1所示。

让我们以第一章中的房屋所有权示例为例:

我们希望通过聚类预测 Peter 是否是房屋拥有者。

就像第一章一样,我们需要对数据进行缩放,因为 收入 轴的数值明显大于 年龄 轴,从而减少了 年龄 轴的影响,而实际上在这种问题中,年龄 具有很好的预测能力。因为预期年长的人有更多的时间定居、存钱并购买房产,而相较于年轻人,年长的人更可能是房屋拥有者。

我们应用了第一章中的相同重缩放方法,基于 K 最近邻的分类,并得到了以下表格:

根据该表,我们生成算法的输入文件并执行它,将特征聚类为两个簇。

输入:

两个簇的输出:

蓝色簇包含已缩放的特征–(0.09375,0.2),(0.25,0.65),(0.15625,0.48),(0.46875,1),(0.375,0.75),和未缩放的特征–(23,50000),(28,95000),(25,78000),(35,130000),(32,105000),和(20,100000)。红色簇包含已缩放的特征–(0.53125,0.04),(0.875,0.1),(1,0),(0.625,0.3),和(0.9375,0.5),以及未缩放的特征–(37,34000),(48,40000),(52,30000),(40,60000),和(50,80000)。

所以,彼得属于红色簇。那么,在不计彼得的情况下,红色簇中房主的比例是多少?红色簇中有 2/4,或者说 1/2 的人是房主。因此,彼得所在的红色簇似乎在判断彼得是否为房主上没有太高的预测能力。我们可以尝试将数据聚类成更多簇,希望能获得一个更纯粹的簇,这样对预测彼得是否为房主会更可靠。因此,让我们尝试将数据聚类成三个簇。

三个簇的输出:

红色簇保持不变。所以我们将数据聚类成四个簇。

四个簇的输出:

现在,彼得所在的红色簇发生了变化。那么,红色簇中房主的比例是多少呢?如果不计算彼得,红色簇中有 2/3 的人是房主。当我们聚成两个簇或三个簇时,这个比例只有 1/2,这并没有告诉我们彼得是否是房主。现在,红色簇中房主的比例多数(不算彼得),所以我们更相信彼得也是房主。然而,2/3 仍然是一个相对较低的置信度,无法将彼得确定为房主。让我们将数据聚类成五个簇,看看会发生什么。

五个簇的输出:

现在,红色聚类只包含彼得和一名非所有者。这种聚类表明,彼得更可能是一个非所有者。然而,根据之前的聚类,彼得更可能是房主。因此,是否拥有房产的问题可能并不那么清晰。收集更多数据将有助于改善我们的分析,并应在做出最终分类之前进行。

通过我们的分析,我们注意到,聚类的不同数量可能会导致分类结果不同,因为单个聚类中的成员性质可能会变化。收集更多数据后,我们应进行交叉验证,以确定能够以最高准确率对数据进行分类的聚类数量。

我们提供了关于来自古腾堡计划的 17 本书中 money 和 god(s) 词汇频率的信息如下:

我们希望根据所选的单词频率,将该数据集按照其语义上下文聚类成不同的组。

首先,我们将进行重缩放,因为单词 money 的最高频率为 0.08%,而单词 “god(s)” 的最高频率为 1.72%。因此,我们将 money 的频率除以 0.08,god(s) 的频率除以 1.72,计算结果如下:

现在我们已经对数据进行了重缩放,接下来我们通过尝试将数据划分为不同数量的聚类,应用 k-均值聚类算法。

输入:

两个聚类的输出:

我们可以观察到,将数据聚类成两个类别时,书籍被划分为宗教书籍(蓝色聚类)和非宗教书籍(红色聚类)。现在我们尝试将书籍分成三个聚类,看看算法是如何划分数据的。

三个聚类的输出:

这一次,算法将《可兰经》从宗教书籍中分离出来,单独放入一个绿色聚类。这是因为事实上,god(上帝)一词是《可兰经》中第五大高频词。这里的聚类恰好是根据书籍的写作风格将其划分的。四个聚类的结果将一本高频出现 money(金钱)一词的书从红色的非宗教书籍聚类中分离出来,单独成类。现在我们来看一下五个聚类的情况。

五个聚类的输出:

这种聚类进一步将蓝色宗教书籍聚类划分为印度教书籍的蓝色聚类和基督教书籍的灰色聚类。

我们可以通过这种方式使用聚类将具有相似属性的项分组,然后基于给定示例快速找到相似的项。聚类的粒度由参数 k 决定,它决定了我们可以期望组内项目之间的相似度。参数越高,聚类中的项目相似度越大,但聚类中的项目数量会减少。

在本章中,我们学习了数据聚类的高效性,并且了解了如何通过将特征分类为属于该特征所在聚类的类别,从而加速新特征的分类。通过交叉验证,可以确定一个合适的聚类数量,选择最能提供准确分类结果的聚类数。

聚类根据数据的相似性对其进行排序。聚类的数量越多,聚类中各特征的相似性越大,但每个聚类中的特征数越少。

我们还了解到,k-均值算法是一种聚类算法,它试图以最小化簇内特征之间的互相距离为目标将特征聚集在一起。为了实现这一点,算法计算每个簇的质心,并且一个特征会归属于其质心最近的簇。算法在簇或其质心不再变化时结束计算。

在下一章中,我们将使用数学回归分析因变量之间的关系。与分类和聚类算法不同,回归分析将用于估算一个变量的最可能值,例如体重、距离或温度。

问题 1:计算以下簇的质心:

a) 2, 3, 4

b) 100 美元,400 美元,1,000 美元

c) (10,20),(40,60),(0,40)

d) (200 美元,40 公里),(300 美元,60 公里),(500 美元,100 公里),(250 美元,200 公里)

e) (1,2,4), (0,0,3), (10,20,5), (4,8,2), (5,0,1)

问题 2:使用 k-均值聚类算法将以下数据集聚成两个、三个和四个簇:

a) 0,2,5,4,8,10,12,11

b) (2,2),(2,5),(10,4),(3,5),(7,3),(5,9),(2,8),(4,10),(7,4),(4,4),(5,8),(9,3)

问题 3:我们给出了一对夫妇的年龄以及他们的子女数量:

我们想通过聚类来猜测一对夫妻的子女数量,其中丈夫的年龄为 37 岁,妻子的年龄为 38 岁。

问题 2: a) 我们添加第二个坐标,并将其设置为所有特征的 0。这样,特征之间的距离保持不变,我们可以使用本章早些时候实现的聚类算法。

输入:

对于两个簇:

对于三个簇:

对于四个簇:

b) 我们再次使用实现的算法。

输入:

两个簇的输出:

三个簇的输出:

四个簇的输出:

问题 3:我们给出了 17 对夫妇的年龄和他们的孩子数量,并希望找出第 18 对夫妇的孩子数量。我们将使用前 14 对夫妇的数据作为训练数据,接下来的 3 对夫妇用于交叉验证,以确定我们将用来估算第 18 对夫妇孩子数量的聚类数k。

聚类后,我们会说,一对夫妇很可能会拥有该聚类中的平均孩子数量。通过交叉验证,我们将选择能够最小化实际孩子数量与预测孩子数量之间差异的聚类数。我们将通过聚类内所有项的差异的平方和的平方根来累计捕捉这种差异。这将最小化随机变量与第 18 对夫妇预测的孩子数量之间的方差。

我们将进行两个、三个、四个和五个聚类的聚类分析。

输入:

两个聚类的输出:

列出的每对夫妇对应一个聚类的形式是(couple_number,(wife_age,husband_age)):

我们希望确定第 15 对夫妇(30,32)的预计孩子数量,即妻子 30 岁,丈夫 32 岁。(30,32)属于聚类 1。聚类 1 中的夫妇如下:(24.0, 28.0),(32.0, 34.0),(24.0, 27.0),(29.0, 32.0),(35.0, 35.0),(33.0, 36.0),(22.0, 27.0),以及(30.0, 32.0)。其中,包括前 14 对夫妇的数据,剩余的夫妇是:(24.0, 28.0),(32.0, 34.0),(24.0, 27.0),(29.0, 32.0),(35.0, 35.0),(33.0, 36.0),以及(22.0, 27.0)。这些夫妇的孩子数量平均值是est15=8/7~1.14。这是基于前 14 对夫妇数据估算的第 15 对夫妇的孩子数量。

第 16 对夫妇的估计孩子数量是est16=23/7~3.29。第 17 对夫妇的估计孩子数量也是est17=23/7~3.29,因为第 16 对和第 17 对夫妇属于同一聚类。

现在我们将计算E2误差(对于两个聚类来说是两个)在估计孩子数量(例如,第 15 对夫妇的孩子数量用est15表示)与实际孩子数量(例如,第 15 对夫妇的孩子数量用act15表示)之间的差异,如下所示:

现在我们已经计算了E2误差,我们将根据其他聚类来计算估算误差。我们将选择包含最少误差的聚类数来估算第 18 对夫妇的孩子数量。

三个聚类的输出:

现在,第 15 对夫妇在聚类 1,第 16 对夫妇在聚类 2,第 17 对夫妇在聚类 2。因此,每对夫妇的估计孩子数量是5/4=1.25。

估算的 E3 错误如下:

四个聚类的输出:

第 15^(th) 对夫妻位于聚类 3,第 16^(th) 对夫妻位于聚类 2,第 17^(th) 对夫妻也位于聚类 2。因此,第 15^(th) 对夫妻的估计子女数为 5/4=1.25。第 16^(th) 和第 17^(th) 对夫妻的估计子女数为 8/3=2.67。

估算的 E4 错误如下:

五个聚类的输出:

第 15^(th) 对夫妻位于聚类 3,第 16^(th) 对夫妻位于聚类 2,第 17^(th) 对夫妻也位于聚类 2。因此,第 15^(th) 对夫妻的估计子女数为 1。第 16^(th) 和第 17^(th) 对夫妻的估计子女数为 5/3=1.67。

估算的 E5 错误如下:

使用交叉验证来确定结果

我们使用了 14 对夫妻作为估算的训练数据,并使用另外三对夫妻进行交叉验证,以找出在 2、3、4 和 5 个聚类值之间的最佳 k 聚类参数。我们可以尝试聚类为更多的聚类,但由于数据量相对较小,最多聚类为五个聚类就足够了。让我们总结一下估算过程中产生的错误:

3 和 5 个聚类的错误率最低。错误率在 4 个聚类时上升,随后在 5 个聚类时下降,这可能表明我们没有足够的数据来做出准确的估计。一个自然的预期是,对于 k 大于 2 的值,不应存在局部最大错误值。此外,3 个聚类和 5 个聚类的错误率差异非常小,而且 5 个聚类中的单个聚类要比 3 个聚类中的单个聚类小。因此,我们选择 3 个聚类而非 5 个聚类来估算第 18^(th) 对夫妻的子女数量。

当聚类为三个时,第 18^(th) 对夫妻位于聚类 2。因此,第 18^(th) 对夫妻的估计子女数为 1.25。

在本章中,您将学习以下主题:

通过对完美数据进行简单线性回归来执行回归分析的核心思想,以便从第一原理推导华氏度与摄氏度转换示例。

使用梯度下降算法来找到最佳拟合的回归模型(采用最小均方误差规则),并学习如何在 Python 中实现它。

使用最小二乘法建立非线性回归模型,应用于弹道飞行分析示例和问题 4,细菌种群预测。

华氏度和摄氏度之间的关系是线性的。给定一个包含华氏度和摄氏度数据对的表格,我们可以估计常数,推导出华氏度与摄氏度之间的转换公式,或者反过来:

我们希望推导出一个将F(华氏度)转换为C(摄氏度)的公式,如下所示:

现在,我们有以下内容:

因此,我们得到以下内容:

这里,我们取前两个数据对(F1,C1)=(5,-15)和(F2,C2)=(14,-10)。这将给我们以下内容:

因此,从华氏度计算摄氏度的公式如下:

让我们通过表格中的数据验证这一点:

我们可以看到公式完美地拟合了 100%的输入数据。我们所处理的数据是完美的。在后续的示例中,我们将看到我们推导出的公式并不完全符合数据。我们的目标是推导出一个最适合数据的公式,以使预测值与实际数据之间的差异最小化。

通常使用平方函数而不是绝对值,因为平方函数具有更理想的数学性质。

最小二乘法找出 a 和 b,使得以下项(称为误差)最小化:

输入:

输出:

因此,我们可以看到摄氏度(C)和华氏度(F)之间的以下近似线性依赖关系:

请注意,这与我们之前的计算相对应。

这是用于通过直线从华氏度预测摄氏度的线性模型。其含义是,只有当(F,C)点在绿色线上时,F才能转换为C,反之亦然:

这里,我们通过线性回归使用以下数据来预测一个人的体重:

我们想要估算一个人的体重,已知他的身高是 172 厘米。

在前一个示例中,华氏度与摄氏度的转换数据完美地符合线性模型。因此,我们甚至可以进行简单的数学分析(求解基本方程)来获得转换公式。然而,现实世界中的大多数数据并不完全符合一个模型。对于这种分析,找到一个拟合给定数据且误差最小的模型是非常有益的。我们可以使用最小二乘法来找到这样的线性模型。

输入:

我们将前面表格中的数据放入向量中,并尝试拟合线性模型:

输出:

为了更好地理解如何利用线性回归从基本原理出发预测一个值,我们需要研究梯度下降算法,并将其在 Python 中实现。

梯度下降算法是一种迭代算法,通过更新模型中的变量来拟合数据,使误差尽可能小。更一般地说,它找到一个函数的最小值。

我们希望通过使用线性公式来表达体重与身高的关系:

梯度下降算法通过在(∂/∂ p[j]) E(p)的方向上更新p[i]参数来实现这一点,具体为:

在这里,learning_rate决定了E(p)收敛速度的最小值。更新p参数将导致E(p)收敛到某个值,前提是learning_rate足够小。在 Python 程序中,我们使用learning_rate为 0.000001。然而,这种更新规则的缺点是E(p)的最小值可能只是局部最小值。

要通过编程更新p参数,我们需要展开对E(p)的偏导数。因此,我们更新p参数如下:

我们将继续更新p参数,直到其变化非常微小;即,直到p[0]和p[1]的变化小于某个常数acceptable_error。一旦p参数稳定,我们可以利用它从身高估计体重。

输入:

我们使用前一个示例中的数据 身高预测体重 并将其保存在 CSV 文件中:

输出:

线性模型的输出意味着体重可以通过身高来表示,如下所示:

因此,一个身高为 172 厘米的人预测的体重大约是:

请注意,这个 71.455 公斤的预测与使用最小二乘法预测得到的 67.016 公斤略有不同。这可能是因为 Python 梯度下降算法仅找到了局部最小值。

通过使用基于身高的体重预测,我们可以可视化最小二乘法和梯度下降算法的线性预测模型,以下是在 Python 中实现的代码:

我们可以推理,飞行时间由两部分组成——第一部分是起飞和着陆的时间;第二部分是飞机在空中以某一速度飞行的时间。第一部分是一个常数。第二部分与飞机的速度成线性关系,我们假设所有航班的速度在表格中是相似的。因此,飞行时间可以通过一个线性公式来表示,涉及飞行距离。

输入:

输出:

根据线性回归,平均飞行的起飞和着陆时间大约为 1.2335890 小时。飞行 1 公里的时间为 0.0008387 小时;换句话说,飞机的速度为每小时 1192 公里。对于像前述表格中的短途航班,飞机的实际通常速度大约是每小时 850 公里。这为我们的估算留出了改进的空间(参见 问题 3)。

因此,我们推导出了以下公式:

利用这个,我们估算从布拉迪斯拉发到阿姆斯特丹的航程(978 公里)大约需要 0.0008387978 + 1.2335890 = 2.0538376* 小时,约为 2 小时 03 分钟,这比从维也纳到阿姆斯特丹的时间(1 小时 55 分钟)稍长,比从布达佩斯到阿姆斯特丹的时间(2 小时 10 分钟)稍短。

一艘星际飞船降落在一个大气层几乎不存在的行星上,并以不同的初速度发射了三枚携带探测机器人的投射物。当机器人降落在表面后,测量它们的距离并记录数据,结果如下:

为了使携带第四个机器人的投射物落地在距飞船 300 公里的地方,应该以什么速度发射?

对于这个问题,我们需要理解投射物的轨迹。由于该行星的大气层较弱,轨迹几乎等同于没有空气阻力的弹道曲线。从地面发射的物体所经过的距离 d,忽略行星表面的曲率,近似由以下方程给出:

尽管 d 和 v 之间没有线性关系,但 d 和 v 的平方之间有线性关系。因此,我们仍然可以应用线性回归来确定 d 和 v 之间的关系。

输入:

输出:

因此,通过回归可以预测速度平方与距离之间的关系,如下所示:

截距项的存在可能是由测量误差或方程中其他力的影响所造成的。由于它相对较小,最终的速度应该能被合理估计出来。将 300 公里的距离代入方程,我们得到如下结果:

因此,为了使投射物从源头到达 300 公里的距离,我们需要以大约 1123.157 米/秒的速度发射它。

在这一章中,我们学习了回归分析。我们可以将变量看作是相互依赖的函数关系。例如,y 变量是 x 的函数,记作 y=f(x)。函数 f(x) 拥有常数参数。如果 y 线性依赖于 x,那么 f(x)=ax+b*,其中 a 和 b 是 f(x) 函数中的常数参数。

我们看到,回归是一种估算这些常数参数的方法,目的是使得估算出的 f(x) 尽可能接近 y。这通常通过计算 f(x) 和 y 之间的平方误差来衡量,以 x 数据样本为基础。

我们还介绍了梯度下降法,通过更新常数参数,沿着最陡的下降方向(即误差的偏导数)来最小化误差,从而确保参数快速收敛到使误差最小的值。

问题 1:云存储费用预测:我们的软件应用程序每月生成数据,并将这些数据与前几个月的数据一起存储在云存储中。我们得到以下云存储费用账单,并希望估算使用云存储的第一年的运营费用:

问题 2:华氏度与摄氏度转换:在本章前面我们看过的例子中,我们制定了一个将华氏度转换为摄氏度的公式。现在,制定一个将摄氏度转换为华氏度的公式。

问题 3:基于距离的飞行时间预测:你认为为什么线性回归模型得出的飞行速度估算为 1192 km/h,而实际速度大约是 850 km/h?你能提出一种更好的方法来建模基于飞行距离和时间的飞行时长估算吗?

问题 4:细菌种群预测:实验室观察到了一种细菌——大肠杆菌,并通过各种在 5 分钟间隔进行的测量估算了其种群数量,具体数据如下:

假设细菌继续以相同的速度生长,那么在 11:00 时,预计细菌数量是多少?

问题 1:每个月,我们都需要支付存储在云端的数据费用,包括本月新增的数据。我们将使用线性回归来预测一般月份的费用,然后计算前 12 个月的费用来计算全年的费用。

输入:

输出:

这意味着基础费用为base_cost=109.01欧元,然后每月存储新增数据的费用为month_data=11.03欧元。因此,第n^(月)账单的公式如下:

全年的费用将如下所示:

可视化

问题 2:有多种方法可以获得将摄氏度转换为华氏度的公式。我们可以使用最小二乘法,并从初始的 Python 文件中提取以下几行:

model, _, _, _ = lstsq(M,celsius)

然后我们将其更改为以下内容:

model, _, _, _ = lstsq(M,fahrenheit)

然后,我们将得到期望的反向模型:

因此,可以通过以下方式将摄氏度转换为华氏度:

另外,我们可以通过修改以下公式得到前面的公式:

问题 3:估计的速度如此之高,因为即使是短途航班也需要相当长的时间;例如,从伦敦到阿姆斯特丹的航班,两个城市之间的距离仅为 365 公里,但需要约 1.167 小时。然而,另一方面,如果距离只稍微变化,则飞行时间也只会略有变化。这导致我们估计初始设置时间非常长。因此,飞行速度必须非常快,因为只剩下少量时间来完成某个距离的旅行。

问题 4:在 5 分钟间隔内,细菌数量分别为 47.5、56.5、67.2 和 79.9 百万。这些数字之间的差值为 9、10.7 和 12.7。序列是递增的。因此,我们需要查看相邻项的比率,以观察序列的增长方式:56.5/47.5=1.18947,67.2/56.5=1.18938,79.9/67.2=1.18899。相邻项的比率接近,因此我们有理由相信,生长中的细菌数量可以通过模型的指数分布进行估算:

其中 n 是细菌数量(单位:百万),b 是常数(底数),字母 m 是指数,表示自 10:00 以来的分钟数,10:00 是第一次测量的时间,47.7 是当时的细菌数量(单位:百万)。

为了估算常数b,我们使用序列项之间的比率。我们知道 b⁵ 大约等于 (56.5/47.5 + 67.2/56.5 + 79.9/67.2)/3=1.18928。因此,常数b 大约等于 b=1.18928^(1/5)=1.03528。于是,细菌数量(单位:百万)如下:

在 11:00,也就是比 10:00 晚 60 分钟时,估算的细菌数量如下:

季节性:数据是否依赖于某些定期事件?例如,餐馆的利润在星期五比星期二要高吗?

在本章中,你将学习以下主题:

通过商业利润的例子,使用回归分析数据趋势

通过电子商店的销售例子,观察和分析数据中的季节性模式

我们希望预测 2018 年企业的利润,基于其前几年的利润:

在这个例子中,利润一直在增长,所以我们可以将利润看作是一个依赖于时间变量的增长函数,而时间变量用年份表示。各年份之间的利润变化分别为$3,000、$2,000、$5,000、$4,000、$3,000 和$2,000。这些差异似乎不受时间影响,而且它们之间的变化相对较小。因此,我们可以尝试通过进行线性回归来预测未来几年的利润。我们用线性方程表示利润p,它与年份y相关,也叫做趋势线:

我们可以通过线性回归找到常数a和b。

输入:

我们将前表中的数据存储在 Python 代码中的year和profit向量中:

输出:

现在,我们将趋势线添加到图表中:

商业利润 - 数据分析

该公司利润的趋势线方程如下:

从这个方程中,我们可以预测 2018 年的利润为:

这个示例很简单——我们仅通过对趋势线进行线性回归就能够做出预测。

在下一个示例中,我们将查看既受趋势又受季节性影响的数据。

我们有一个小型电子商店从 2010 年到 2017 年的每月销售数据,单位为千美元。我们想要预测 2018 年每个月的销售额:

表格中的数据是以千美元为单位的销售额。

为了能够分析这个问题,我们将首先绘制数据图表,以便观察模式并进行分析:

从图表和表格中,我们注意到,从长远来看,销售额呈线性增长。这是趋势。然而,我们也可以看到,12 月的销售额往往比其他任何月份都高。因此,我们有理由相信,销售额也受到月份的影响。

我们如何预测未来几年的月度销售额?首先,我们确定数据的确切长期趋势。然后,我们分析每个月的变化。

输入:

年份列表包含按小数表示的年份周期 年+月/12。销售列表包含对应周期的千美元销售额。我们将使用线性回归来建立趋势线。从初步图表中,我们观察到趋势呈线性:

输出:

因此,趋势线的方程如下:

现在,我们将趋势线添加到图表中:

现在,我们可以分析季节性——即数据如何随着月份变化。从我们的观察中,我们知道在某些月份,销售额往往较高,而在其他月份,销售额则较低。我们评估线性趋势与实际销售额之间的差异。根据这些差异中的模式,我们构建了一个季节性模型,以便更准确地预测每个月的销售额:

我们无法观察到实际销售额与趋势线销售额之间的差异有任何明显的趋势。因此,我们仅计算每个月这些差异的算术平均值。

例如,我们注意到,12 月的销售额通常比趋势线预测的销售额高出大约 3,551.58 美元。类似地,1 月的销售额通常较低,平均低于趋势线预测的销售额约 2,401 美元。

假设月份对实际销售额有影响,这是根据我们观察到的不同月份销售额的变化来得出的,我们采用以下预测规则:

然后我们将其更新为新的规则:

这里,sales 是所选月份和年份的销售额预测值,month_difference 是我们在给定数据中实际销售额与趋势线销售额之间的平均差异。更具体地说,我们得到以下 12 个方程和 2018 年的销售额预测(单位:千美元):

该表格包含了 2018 年基于前面季节性方程的销售数据。

我们可以将预测的数据可视化为图形:

我们还了解到,季节性分析试图发现时间中反复出现的规律模式,例如圣诞节前的销售增加。为了检测季节性模式,必须将数据划分为不同的季节,以便模式在同一季节中重复出现。此划分可以将一年分为月份,一周分为天数或工作日和周末等。合理的季节划分和对这些季节中的模式分析是良好季节性分析的关键。

本章介绍了本书中呈现的最后一种数据分析方法。在本章之后,您可以找到关于统计学、Python 编程语言概念以及数据科学中算法和方法的参考资料。

问题 1:确定比特币价格的趋势:

a) 我们给出了一个包含 2010-2017 年比特币价格(美元)的表格。请确定这些价格的线性趋势线。每月价格取自每个月的第一天:

b) 根据 a)部分的线性趋势线,预计 2020 年比特币的价格是多少?

c) 讨论线性趋势线是否适合作为预测比特币未来价格的良好指标。

问题 2:电子商店销售: 使用电子商店销售示例中的数据,预测 2019 年每个月的销售情况。

问题 1:

输入:

输出:

趋势线:

从 Python 代码的输出中,我们发现比特币美元价格的线性趋势线如下:

这为我们提供了以下趋势线图:

根据趋势线,预计 2020 年 1 月 1 日比特币的价格为 1,731.10 美元。

线性趋势线可能不是比特币价格的一个良好指标或预测工具。这是因为有许多因素在起作用,而且比特币价格有可能呈现出技术趋势中常见的指数性增长。例如,Facebook 活跃用户的数量和低于 1000 美元的最佳消费类 CPU 中的晶体管数量。

有三个重要因素可能促使比特币的指数型采用,从而推动其价格上涨:

技术成熟度(可扩展性):每秒交易数量可以确保即时转账,即使许多人使用比特币进行收付款。

稳定性:一旦卖家不再害怕因收到比特币付款而失去利润,他们会更加愿意接受比特币作为货币。

用户友好性:一旦普通用户能够自然地进行比特币的收付款,就不会有技术障碍,使用比特币就像使用他们习惯的任何其他货币一样。

要分析比特币的价格,我们必须考虑更多的数据,并且很可能其价格不会遵循线性趋势。

问题 2:我们使用示例中的 12 个公式,每个月一个,来预测 2019 年每个月的销售额:

sales_january = 1.279(year+0/12) - 2557.778 - 2.401*

= 1.279(2019 + 0/12) - 2557.778 - 2.401 = 22.122*

sales_february = 1.279(2019+1/12) - 2557.778 - 1.358 = 23.272*

sales_march = 1.279(2019+2/12) - 2557.778 - 0.464 = 24.272*

sales_april = 1.279(2019+3/12) - 2557.778 - 0.608 = 24.234*

sales_may = 1.279(2019+4/12) - 2557.778 - 0.165 = 24.784*

sales_june = 1.279(2019+5/12) - 2557.778 - 0.321 = 24.735*

sales_july = 1.279(2019+6/12) - 2557.778 - 0.003 = 25.160*

sales_august = 1.279(2019+7/12) - 2557.778 - 0.322 = 24.947*

sales_september = 1.279(2019+8/12) - 2557.778 - 0.116 = 25.259*

sales_october = 1.279(2019+9/12) - 2557.778 + 0.090 = 25.572*

sales_november = 1.279(2019+10/12) - 2557.778 + 1.833 = 27.422*

sales_december = 1.279(2019+11/12) - 2557.778 + 3.552 = 29.247*

电子商店销售额 - 数据分析

Python 是一种通用编程和脚本语言。其简洁性和丰富的库使得开发出快速符合现代技术需求的应用成为可能。

Python 代码写在以.py为后缀的文件中,可以通过python命令执行。

Python 中最简单的程序会打印一行文本。

输入:

输出:

注释在 Python 中不会被执行。它们以#字符开头,并以行尾结束。

输入:

输出:

Python 中可用的一些数据类型如下:

数值数据类型:int和float

文本数据类型:str

复合数据类型:tuple、list、set和dictionary

int数据类型只能存储整数值。

输入:

输出:

float数据类型也可以存储非整数的有理数值。

输入:

输出:

字符串变量可以用来存储文本。

输入:

输出:

tuple数据类型类似于数学中的向量;例如,tuple = (整数, 浮点数)。

输入:

输出:

Python 中的列表是一个有序的值集合。

输入:

输出:

Set是 Python 中的一个无序的数学集合类型。

输入:

输出:

dictionary是一种数据结构,可以通过键存储对应的值。

输入:

输出:

Python 编程语言通过使用条件语句、for循环(包括break和continue语句)以及函数来控制程序执行流程。

如果满足特定条件,可以使用if语句执行一定的代码。如果条件不满足,则可以执行else语句后的代码。如果第一个条件不满足,我们可以设置下一个条件,通过elif语句来执行代码。

输入:

输出:

for循环可以遍历一组元素中的每个元素,例如,range、python set和list。

输入:

输出:

输入:

输出:

for循环可以通过break语句提前退出。使用continue语句可以跳过for循环中的剩余部分。

输入:

输出:

Python 支持函数的定义,这是一种很好的方式,可以在程序的多个地方执行相同的代码。函数是使用def关键字定义的。

输入:

输出:

让我们看看如何向 Python 程序传递参数,以及如何读写文件。

我们可以通过命令行向程序传递参数。

输入:

输出:

输入:

输出:

符号

两个集合A和B的交集,表示为A ∩ B,是集合A或B的一个子集,包含所有在A和B中都有的元素。换句话说,A ∩ B := { x : x in A and x in B}。

两个集合A和 B 的并集,表示为A ∪ B,是一个包含所有在A中或在B中的元素的集合。换句话说,A ∪ B := { x : x in A or x in B}。

两个集合A和B的差集,表示为A – B或A\B,是集合A的一个子集,其中包含所有在A中但不在B中的元素。换句话说,A – B := { x : x in A and x not in B}。

求和符号∑表示集合中所有成员的和,例如:

定义与术语

总体:一组相似的数据或项,用于分析。

样本:总体的一个子集。

一组的算术平均数:一组中所有值的总和除以该组的大小。

中位数:一个有序集合中的中间值,例如,集合{x1, …, x2k+1}的中位数,其中x1 <…< x2k+1 是值xk+1。

随机变量:从可能结果集合(例如,正面或反面)到值集合(例如,正面为 0,反面为 1)的一个函数。

期望:随机变量的期望是随机变量给定的值的增加集的平均值的极限。

斜率:线性方程y=ax+b中的a*变量。

截距:线性方程y=ax+b中的b*变量。

设P(A)和P(B)分别为A和B的概率,P(A|B)为在给定B的条件下A的条件概率,P(B|A)为在给定A的条件下B的概率。

然后,贝叶斯定理给出了以下公式:

P(A|B)=(P(B|A) * P(A))/P(B)

概率分布是一个从可能结果集合(例如,正面和反面)到这些结果的概率集合(即,正面和反面各 50%)的函数。

许多自然现象的随机变量可以通过正态分布来建模。正态分布具有以下概率密度:

均值为 10,标准差为 2 的正态分布

交叉验证是一种验证数据假设的方法。在分析过程开始时,数据被划分为学习数据和测试数据。一个假设被拟合到学习数据上,然后其实际误差在测试数据上进行测量。通过这种方式,我们可以估计假设在未来数据上的表现。减少学习数据的数量也有好处,因为它可以减少假设过拟合的机会。这是指假设被训练到数据的特别狭窄子集上。

原始数据随机分成k个子集。一个子集用于验证,剩余的k-1 个子集用于假设训练。

A/B 测试是对数据的两个假设进行验证——通常是在真实数据上进行。然后,选择具有更好结果(更低估计误差)的假设作为未来数据的估计器。

k近邻算法:一种算法,根据与数据项最接近的k个邻居的多数情况来估算未知数据项的分类。

朴素贝叶斯分类器:一种使用贝叶斯定理对数据项进行分类的方法,涉及条件概率P(A|B)=(P(B|A) * P(A))/P(B)。它还假设数据中的变量是独立的,这意味着没有任何变量会影响其他变量取某一值的概率。

决策树:一种通过树叶节点中的类别对数据项进行分类的模型,分类基于树枝与实际数据项之间的匹配属性。

随机决策树:一种决策树,其中每个分支在构建时仅使用可用变量的随机子集。

随机森林:由多棵随机决策树组成的集成算法,这些决策树是在数据的随机子集上进行构建的,并且允许重复采样。每个数据项会根据其树木中的多数投票结果进行分类。

K均值算法:一种聚类算法,将数据集划分为k个组,使每个组中的成员尽可能相似,即彼此之间距离最小。

回归分析:一种用于估计功能模型中未知参数的方法,该模型用于从输入变量预测输出变量。例如,估计线性模型y=ax+b中的a和b*。

支持向量机:一种分类算法,通过找到一个超平面将训练数据划分到给定的类别中。然后,通过这个超平面进一步对数据进行分类。

主成分分析:对给定数据的各个组成部分进行预处理,以便实现更好的准确性,例如根据变量对最终结果的影响程度,调整输入向量中变量的尺度。

文本挖掘:对文本的搜索和提取,并可能将其转化为用于数据分析的数值数据。

神经网络:一种机器学习算法,由一系列简单的分类器构成,分类器根据输入数据或网络中其他分类器的结果做出决策。

深度学习:神经网络提高其学习过程的能力。

先验关联规则:可以在训练数据中观察到的规则,并基于这些规则对未来的数据进行分类。

PageRank:一种搜索算法,赋予搜索结果最大的相关性,这些结果来自于具有最多、最相关搜索链接的网页。用数学术语来说,PageRank 计算出一个特定的特征向量,表示这些相关性的度量。

集成学习:一种学习方法,使用不同的学习算法来得出最终结论。

袋装法:通过对训练数据的随机子集训练出的分类器进行多数投票来对数据项进行分类的方法。

遗传算法:受遗传过程启发的机器学习算法,例如,经过训练的分类器中具有最高准确度的分类器将进一步训练。

归纳推理:一种机器学习方法,用于学习生成实际数据的规则。

贝叶斯网络:表示随机变量及其条件依赖关系的图模型。

奇异值分解:矩阵的分解方法,是特征值分解的推广,常用于最小二乘法。

提升法:一种机器学习元算法,通过基于分类器的集成做出预测,从而减少估计的方差。

期望最大化:一种迭代方法,用于搜索模型中能够最大化预测准确度的参数。

THE END
0.数学挑战:从炮弹轨迹到高斯公式文章浏览阅读2.1k次。本文通过一系列挑战,涵盖了飞行炮弹的空气阻力计算、海啸等级评估、受力分析、时间单位换算以及数学中的求根公式,其中涉及到Python的math和numpy库在解决实际问题中的应用。jvzquC41dnuh0lxfp0tfv8Owpfy11jwvkerf1mjvckrt1:7465729A
1.EarthquakeTsunamiRiskAssessmentDataset)全球地震数据库一键获取完整项目代码python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 文件名为 earthquake_data_tsunami.csv,包含了地震和海啸的相关信息。 该数据集共有 782 行,包含了magnitude、cdi、mmi等13 个字段。 二、地震震级分布 #二、地震震级分布importmatplotlib.pyplotasplt# 查看地震震级分布,并保留两位小数jvzquC41dnuh0lxfp0tfv87623e99;973970c{ykenk0fnyckny03>883;<2;
2.某海啸预警中心在某海域布设了能监测海波高度的浮标。浮标中内置某海啸预警中心在某海域布设了能监测海波高度的浮标。浮标中内置传感器和智能终端,智能终端每15秒从传感器获取一次海波高度数据,初步处理后,每分钟将数据经卫星上传至中心服务器。服务器实时计算海啸发生概率,并在概率超过阈值时向沿海地区发布不同等级的警报。公众可通过官方App或网站查看实时数据和预警信息。请回答下列jvzquC41|wpvcw3zmy4dqv449s8:6><:374ivvq
3.75并行软件框架下的混合海啸模拟器与HPCMW问题求解环境1. 混合海啸模拟器的构建 在创建并行的波传播模拟器时,我们的目标是设计一个灵活的框架,使得现有的串行波传播代码能够轻松集成到混合并行模拟器中。这一框架可从用于求解偏微分方程(PDE)的Schwarz算法通用库扩展而来。虽然我们在下面的文本中使用C++语法,但面向对象的策略同样可以用Python等其他语言实现。 1.1 通用jvzquC41dnuh0lxfp0tfv8{wnmgo8puw1cxuklqg1fkucrqu13;4;:73;6
4.Python海洋潮汐与水位控制回归分析法计算验潮站长期平均海面文章介绍了使用回归分析法进行海平面预测的原理和算法步骤,包括线性关系假设、观测方程组的构建以及法方程的求解。通过Python程序实现了数据处理和计算,展示了以10天、15天和30天为时段的误差分析。结果表明,时段越长,预测精度越高,建议使用超过10天的时段进行计算。 jvzquC41dnuh0lxfp0tfv8r2a6?7:==561gsvrhng1jfvjnnu1742B7643:
5.海洋灾害预警:海啸预警系统(2).海啸基础知识.docx海洋灾害预警:海啸预警系统_(2).海啸基础知识.docx 19页内容提供方:kkzhujl 大小:27.5 KB 字数:约1.15万字 发布时间:2025-04-23发布于境外 浏览人气:0 下载次数:仅上传者可见 收藏次数:0 需要金币:*** 金币 (10金币=人民币1元)海洋灾害预警:海啸预警系统_(2).海啸基础知识.docx 关闭预览 想jvzquC41o0hpqt63:0ipo8mvon532;:126831>6464814=92347527xjvo
6.计算机、波浪、模拟:使用Python的数值方法实用入门|Coursera有兴趣学习如何用数值方法求解偏微分方程并将其转化为 python 代码吗?本课程将为您介绍如何将有限差分法、伪谱法、线性和谱元法等方法应用于一维(或二维)标量波方程。计算算法的数学推导附有嵌入 Jupyter 笔记本的 python 代码。通过这种独特的设置,您可以看到数学方程是如何转化为jvzq<84yyy3ptrlkp0ipw{xgtc4ptp4ngezvtn4eqovvvnwu/ygwg|2uko{mc}nqpu5x76/hwtdvrtp/ktug{uqnczjqw2vtkmppxrgvtod/kfuku3gwwhvkqtt/|fnnIEbw}mOqfk>urlpwr
7.海洋灾害预警:海啸预警系统(11).国际海啸预警合作.docx海洋灾害预警:海啸预警系统_(11).国际海啸预警合作.docx 14页内容提供方:kkzhujl 大小:23.27 KB 字数:约7.65千字 发布时间:2025-04-23发布于境外 浏览人气:0 下载次数:仅上传者可见 收藏次数:0 需要金币:*** 金币 (10金币=人民币1元)jvzquC41oc~/dxtm33>/exr1jvsm1;5471654;4735614=7662733=50ujzn
8.精品解析:2026届浙江省绍兴市高三上学期11月选考科目诊断性考试技术服务器实时计算海啸发生概率,并在概率超过阈值时向沿海地区发布不同等级的警报。公众可通过官方App或网站查看实时数据和预警信息。请回答下列问题:(1)浮标中的智能终端_____(单选,选字母:A.有/B.没有)数据存储功能。(2)该系统的部分数据处理在智能终端完成,可以_____(单选,填字母)A.提升中心服务器硬件的运算速度jvzquC41yy}/|}m0eun1|thv1;59@<8644ivvq
9.python可视化小波分析——​海温数据的时频域分解算法进阶 2023/10/26 9900 数据可视化之matplotlib绘制正余弦曲线图 数据可视化pythonnumpy 在python里面,数据可视化是python的一个亮点。在python里面,数据可视可以达到什么样的效果,这当然与我们使用的库有关。python常常需要导入库,并不断调用方法,就很像一条流数据可视化的库,有很多,很多都可以后续开发,然后我们调用jvzquC41enuvf7ygpekov7hqo1jfxnqqrgx0c{ykenk03A5864?
10.Python计算经纬度坐标点距离:从原理到实战地球表面两点间的距离计算看似简单,实则涉及复杂的球面几何。当用经纬度坐标表示位置时(如GPS数据),直接使用平面距离公式会导致巨大误差——北京到上海的直线距离若用勾股定理计算,误差可能超过50公里。本文将用Python实现精确的球面距离计算,覆盖从基础公式到工程优化的全流程。 jvzquC41fg|fnxugt0gmk‚zp0eun1jwvkerf1:;:879:
11.Python人工智能:11~15Python 人工智能:11~15 11 遗传算法和遗传编程 在本章中,我们将学习遗传算法。 首先,我们将描述什么是遗传算法,然后将讨论进化算法和遗传编程的概念,并了解它们与遗传算法的关系。 我们将学习遗传算法的基本构建模块,包括交叉,变异和适应度函数。 然后,我们将使用这些概念来构建各种系统。jvzquC41fg|fnxugt0gmk‚zp0eun1jwvkerf1:948:=8
12.创世理论达成从量子真空到时空海啸:GRB、黑洞与宇宙创世的终极关联从量子真空的“0”平衡态出发,通过涨落的“±”对称态破缺,经暴胀引擎的“≈”指数放大,最终形成星系、黑洞、伽马射线暴(GRB),并在时空曲率中刻下“时空海啸级”原初引力波的印记。本文严格遵循“0≈±极限小量”逻辑链,从量子场论真空涨落出发,串联GRB起源、黑洞形成与时空海啸演化,完整呈现宇宙“从无到有”的jvzquC41dnuh0lxfp0tfv8vsa5<83B;421gsvrhng1jfvjnnu1765B:89;9
13.通过Python的海洋模型进行模拟风暴潮要通过Python的海洋模型进行风暴潮模拟,你可以使用海洋模型库如ECOMSED(Ecosystem Modeling and Synthesis System for theEastCoast of the United States)或ROMS(Regional Ocean Modeling System)。以下是一个简单的示例代码,演示如何使用ROMS模型进行风暴潮模拟: jvzquC41dnuh0lxfp0tfv8iwectxcwl1ctzjeuj1fgzbkux135<15?98:
14.创世理论达成从量子海虚粒子对到时空海啸(暴涨)宇宙的本质是一场量子涨落的宏观放大——早期宇宙的虚粒子对涨落,通过引力相互作用激发时空波浪,触发量子黑洞坍缩并释放超强引力波,最终驱动宇宙进入指数膨胀的“时空海啸”(暴涨)。以下从量子场论基础、时空波浪产生、QHBH与引力波、暴涨动力学到结构遗产,完成每一步都可验证的严格推导。 jvzquC41dnuh0lxfp0tfv8vsa5<83B;421gsvrhng1jfvjnnu1765@:652>
15.现代Fortran海啸模拟器项目常见问题解决方案运行可视化脚本:一旦依赖安装完成,你就可以运行 Python 脚本来可视化海啸模拟数据了。 2.3 如何理解并行缩放及遇到的问题? 解决步骤: 并行计算:从第7章开始,代码被设计为并行执行。但是,如果你发现并行运行程序比串行慢,这可能是因为默认的网格尺寸太小,以至于并行带来的开销大于其优势。 jvzquC41dnuh0lxfp0tfv8lkvdrpih532570c{ykenk0fnyckny03=977484;
16.高效Python提高数据处理效率的迫切需要数据处理速度增长帮助你理解CPU设计、GPU、存储替代方案、网络协议和云架构以及其他系统考虑因素(图1.4)的影响,从而为提高Python代码的性能做出正确的决策。无论是单台计算机、支持GPU的计算机、集群还是云环境,本书都将帮助您评估计算架构的优缺点,并实施必要的更改以充分利用其优势。jvzquC41dnuh0lxfp0tfv8Lghcthgwju1cxuklqg1fkucrqu139:9>>384
17.探索现代Fortran的威力:海啸模拟器「tsunami」并行计算友好:利用最新Fortran特性进行高效并行,适合大规模仿真。 可视化支持:借助Python脚本,轻松展示模拟结果,增强理解和互动体验。 详尽文档和注释:每一步的演进都有清晰解释,便于跟踪学习和调试。 结语 tsunami项目不仅是现代Fortran编程艺术的展示,也是科学研究与教育的宝贵资源。对于那些渴望深入并行计算、提升软件工 jvzquC41dnuh0lxfp0tfv8lkvdrpih5229<0c{ykenk0fnyckny03<>894=54
18.创世理论达成时空海啸生成超强引力波的来源:从量子真空到宇宙尺度的完“时空海啸”是原初引力波的形象化表述——这类引力波并非由天体碰撞、超新星爆发等后期宇宙事件产生,而是源于宇宙诞生初期(普朗克时期)量子真空与时空几何的深度耦合,经宇宙暴胀的极端放大后,形成的宇宙级时空波动。其“超强”特性(相对于双黑洞合并等普通引力波源)的核心,在于它是量子力学与广义相对论在宇宙原初阶段jvzquC41dnuh0lxfp0tfv8vsa5<83B;421gsvrhng1jfvjnnu1765A628:=
19.创世理论达成超强引力波驱动的“时空海啸”:从量子黑洞到宇宙暴涨“时空海啸”是宇宙早期由超强引力波主导的指数膨胀阶段(即“暴涨”)的核心过程,其本质是量子场的真空涨落通过引力相互作用,转化为经典时空的剧烈震荡。以下从量子场论基础、QHBH形成、引力波产生、暴涨动力学、结构遗产五个维度,完成全链条、无简化的物理推导,涵盖数学细节与物理机制。 jvzquC41dnuh0lxfp0tfv8vsa5<83B;421gsvrhng1jfvjnnu1765@:636>
20.实用编程|Python+Matplotlib制作超高分辨率动态气象/海洋要素数据可视化matlab编程算法numpy python-matplotlib 在地理空间数据可视化绘制方面也还是有一定的优势的,为更新colorbar绘制应用范围,我们把gis,遥感等专业的需要常做的空间可视化图,试着用matplotlib 进行绘制(也是小伙伴提出:用arcgis等软件在对多子图绘制colorbar时,存在无法共用的情况,即软件是一幅一幅的出图,导致汇总jvzquC41enuvf7ygpekov7hqo1jfxnqqrgx0c{ykenk03B5388=
21.实时波浪能监测系统构建全记录,手把手教你用Python处理传感器时序数据该函数实现传感器数据采集与封装,pressure经校准算法转换为有效波高,TIMESTAMP确保数据时序一致性,适用于长期趋势分析。 2.2 使用Python串口通信实时读取传感器数据 在物联网和嵌入式系统开发中,通过串口实时获取传感器数据是常见需求。Python凭借其简洁语法和丰富的库支持,成为实现该功能的理想选择。 jvzquC41dnuh0lxfp0tfv8KcuvIpoynng1gsvrhng1jfvjnnu1765:5;62=
22.基于球坐标系点源计算的海啸射线追踪matlab模拟仿真目录 1.算法仿真效果 2.MATLAB源码 3.算法概述 4.部分参考文献 1.算法仿真效果 matlab2022a仿真结果如下: 2.MATLAB源码 %*** %订阅用户可以获得任意一份完整代码,私信博主,留言文章链接和邮箱地址, %一般第二天下午4点前会将完整程序发到邮箱中。 %***jvzquC41dnuh0lxfp0tfv8Xkow}ptui1ctzjeuj1fgzbkux136;49<=:;
23.Python做相关性检验的底层理论3.3 Python代码实现 4.总结对比 众所周知,在做特征筛选以及相关性检验的时候会经常用到相关系数,知其所以然,这次完完全全通过理论、案例计算以及多种方法Python的实现展示一下,方便理解。其他相关的也可以参考之前的文章数值型变量的简单相关性分析python应用 jvzquC41dnuh0lxfp0tfv8r2a6<799=721gsvrhng1jfvjnnu1766=9986=