TowardsDataScience 博客中文翻译 2020(九百一十八)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

分类的最终功能

原文:https://towardsdatascience.com/ultimate-function-for-classification-82f1fc711ab9?source=collection_archive---------34-----------------------

使用自定义函数评估分类器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

贝勒·格拉姆林在 Unsplash 上的照片

在这篇文章中,我将回顾我是如何用 Python 创建一个函数的,这个函数可以轻松地显示一个训练好的分类模型的一些性能指标。因为这个功能是作为一个更大的任务的一部分出现的,所以我将在分享我的过程的图像和代码时提供上下文来帮助澄清。我将主要使用 Sci-Kit LearnMatplotlib 包,但有一个来自 Pandas 绘图方法、 Yellowbrick 的分类器模块的特殊外观。

背景

我得到了一个简单的项目:使用预先制作的数据集来创建一个分类模型的用例,然后创建这个模型。基本上是从一张白纸开始,我面对的是一整个互联网价值的可能的数据集,作为的一个。最终我决定做一些与体育相关的事情,在所有我预料会遇到的运动中,我找到了一个关于终极格斗赛的。

如果你不熟悉这项运动,终极格斗锦标赛( UFC )是一个混合武术推广机构。混合武术,通常被称为 MMA,是一种由多种传统格斗学科非特定混合而成的格斗风格。混合格斗风格的一个很好的例子是拳手乔恩·琼斯。他从全国大专摔跤冠军到获得巴西柔术(BJJ)紫带和跆拳道黑带;跆拳道本身是 1992 年由 Greg Jackson 发展起来的一种格斗方式,使用了摔跤、BJJ、跆拳道和柔道的技术。

在 MMA 比赛中,除了在比赛方式上有更大的自由外,比赛结构通常遵循拳击或摔跤等其他格斗项目的结构。如果你对这一切是如何在更精细的层面上运作感到好奇,我推荐你阅读这个维基百科页面上的“规则”部分。

在 21 世纪初,我是一个超级粉丝;我玩电子游戏,看表演,了解拳手,等等。如果说我对观看这些比赛有什么印象的话,那就是他们感受到的不可预测的。似乎直到有人被击倒或投降,无论情况如何,任何一方都有可能获胜。不管某个拳手在统计上是多么的不被看好,他们仍然有机会获胜,并且偶尔会震惊 MMA 社区。正是这些不可预知的时刻激发了我将这个数据集用于我的项目。我想回答的大问题是:

我能根据他们之前的表现预测 MMA 比赛的获胜者吗?

数据集

如前所述,我在这个项目中的几个限制之一是数据集需要在我开始使用它之前已经编译好。我首先去了 Kaggle,花了很多时间查找数据集。在使用“体育”标签时,我发现了 Rajeev Warrier ( 链接)发布的“UFC-Fight 1993 年至 2019 年的历史数据”。这个数据集有超过 5000 场比赛的大量信息,包含了比赛各个方面的 145 个特征。

有以下信息:

  • 拳击手在比赛前赢/输/平的记录
  • 一个拳击手赢得多场比赛的方法
  • 首选战斗姿态
  • 物理属性
  • 战斗相关平均值

** 这些平均值处理高级统计数据,例如:重大打击、提交、地面传球等。**

带什么

您需要安装这些软件包才能继续操作:

我将根据我在 UFC 上的项目来完成这个函数的创建,尽管这个函数应该在任何为机器学习准备的干净数据集上工作。如果你需要关于如何做到这一点的任何信息和一些好的策略,请查看 Omar Elgabry 的数据清理指南(链接)。

否则,为了简洁起见,我将直接跳到可以创建分类器评估函数的地方。此时,我有了数据集:

  • 填充和/或删除任何缺失的数据
  • 独热编码分类特征
  • 数字要素的最小-最大缩放
  • 训练测试分为 X 和 y 数据
  • 使用 SMOTE 对训练数据进行综合重采样(修复目标类不平衡)

这里有一个窥视数据帧的样子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

详细显示红角战斗机缩放信息的列

拟合和预测

这是容易的部分!Sci-Kit Learn 使模型适应训练数据和预测新输入变得非常简单。你需要做的就是首先实例化你选择的 Sci-Kit Learn 机器学习模型,并使用它的*。fit()* 和*。预测()*方法。

使用多类逻辑回归模型进行设置、拟合和预测

这段代码的一个独特之处是使用了multi_class=参数,只有当您试图预测更多的这两个类时,这个参数才有意义。在我的项目中,对于每一个拳击手,我都希望预测他们的比赛是否会以如下方式结束:

  • 胜利
  • 失去

这个重要的细节就是为什么我们稍后在预测结果时可视化我们的模型的性能时需要使用 Yellowbrick 包,但是现在让我们看看如何将这个过程函数化。

广义 Sci-Kit 学习分类器的拟合与预测

如果你仔细看看,这里真的没有太大的变化。变量(包括分类器本身)需要一般化,并作为必需的参数放置。但是除了为预测添加一个“返回”语句之外,这就是我需要做的全部工作!

获得结果

所以现在我有了一个可以预测 UFC 比赛获胜者的模型,我需要一种方法来确认它的准确性。我可以通过将输入的数据用作与地面事实相同的预测的输入来做到这一点,因为我们已经有了模型可以学习的正确结果。这就是为什么这种类型的任务被称为 监督学习 的原因,因为我们将能够调整(或监督)我们的模型如何学习,希望提高它在预测未知数据时的性能。

再一次,Sci-Kit Learn 使得一旦一个模型在一些数据上被训练,这变得非常容易。指标模块中的 分类报告 功能可以方便用户生成四种常用的分类指标。所有需要做的就是为数据输入真实的和预测的标签来得到结果!

这是我项目中的一个例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

K-Neighbors 分类器的分类报告示例

对于这样一个简单的实现,当试图评估分类器的性能时,Sci-Kit Learn 的分类报告带来了很多东西。它提供了聚合和单个标签级别的主要分类指标,有助于确定调整模型或解释模型性能的策略。一般来说,这些指标是:

  • 精度——真实阳性与所有预测阳性的比率;具有高精度的模型很少预测不正确的标签,但是经常有许多假阴性
  • 召回——真实阳性与所有可能阳性的比率;召回率高的模型通常会捕获许多误报
  • F1 分数—使用精确度和召回分数计算;用于尽量减少假阴性假阳性
  • 准确性真阳性与所有预测的比率;简单地说,预测正确的百分比

如果这些东西看起来有点过时,你想知道更多,我推荐你看看克莱尔·刘的帖子。

炫耀

虽然看起来分类报告已经包含了所有的内容(实际上是这样),但是实际上还有更多的内容可以轻松地添加到这个函数中,以帮助完善所显示的信息。接下来我将展示如何创建一个混淆矩阵和一个 ROC 曲线,然后将它们放入一个函数中。

混淆矩阵

混淆矩阵是可视化分类模型性能的一个很好的工具。简而言之,它是一个分成小方块的正方形,这些小方块除了表示真阴性和假阴性之外,还表示真阳性和假阳性的值。视觉上更容易理解:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

二元分类器的示例混淆矩阵

从左上角开始,沿对角线向下,这些值代表真值;或者,它们是该特定类别的召回值。关于他们的更多信息可以在 Sarang Narkhede ( 链接)的帖子中找到。

由于 Sci-Kit Learn,混淆矩阵也很容易实现,以下是实现方法:

大鹏曲线

我添加到函数中的第二个图有点高级,但是可以在评估模型性能时提供一些有趣的见解。ROC ( 接收器工作特性)曲线,简单来说,说明了真阳性率 (TPR)和假阳性率 (FPR)之间的权衡。如果你想更深入地了解这些比率背后的数学,维基百科做了一个密集但很棒的工作来详述这些公式。

理想的 ROC 曲线看起来像一个更平滑、倾斜的倒“L”型。希望这在看完一个之后会更有意义:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ROC 曲线示例(不良表现)

上面的例子来自我在项目期间测试的一个性能较差的模型。代表每个类别的 TPR 和 FPR 的两条线相对靠近黑色虚线;这条黑线代表“随机机会”线,其中正确的机会基本上是 50%。因此,这个模型并不比抛硬币选择哪个战士会赢好多少。理想的 ROC 曲线应该有一个比 FPR 增长更快的 TPR,这导致了我所说的倒“L”形。

通常,如果一个人正在训练一个二元分类模型,这个图可以使用 Sci-Kit Learn 生成。然而,因为我预测了三个不同的类,所以我将展示如何使用允许多类曲线的 Yellowbrick 包创建 ROC 曲线(不需要指定任何一个)。

我是这样做的:

黄砖 ROC 曲线的单一实现

包装它

现在是时候把上面的所有代码放到一个可重用的函数中了,这个函数可以在一行代码中产生前面讨论过的所有内容!

我会一步一步地分解它:

  1. 拟合模型并创建预测
  2. 使用预测生成分类报告
  3. 为绘图创建图形和轴
  4. 生成并格式化混淆矩阵
  5. 生成和风格化 ROC 曲线
  6. 显示绘图
  7. 返回预测

开始了。(马里奥的声音):

先前章节的功能化版本

附注:在第 48 行,我使用了一个名为 plot_importance() 的自定义函数。作为一个附件,它的目的是作为一个选项显示一个只与决策树分类模型相关的附加图。更多关于特征重要性的信息代号为*【剧情 _ 重要性()*

这是一个输出结果的例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

根据 UFC 数据训练的标准逻辑回归示例

现在怎么办?

因此,如果您一直在跟进,您应该有一个功能完整的函数函数,它将很容易地显示一个总报告和两个关于监督分类模型性能的图。通过使用该函数,可以快速评估模型学习训练数据的程度;在比这三个工具单独提供的更深的层次上这样做。当选择一个分类器在特定数据集上进行训练时,我打算将这个函数用作多个分类器的一个评判标准,并作为一种在调优过程中提供洞察力的方式。我很想知道它的其他用途是什么,或者被改变了(请告诉我!).

当然,为了创建这个函数,确实需要做一些准备,但是总体来说,在这个项目中使用它节省了我很多时间。我希望它能为其他人做同样的事情!

链接到 UFC 分类项目

强化学习终极指南第 2 部分——培训

原文:https://towardsdatascience.com/ultimate-guide-for-ai-game-creation-part-2-training-e252108dfbd1?source=collection_archive---------7-----------------------

在这个全面的文章系列中,我们将构建自己的环境。稍后,我们将使用强化学习来训练一个神经网络。最后,我们将创建一个视频,展示人工智能在环境中的表现。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

环境、培训和展示的完整代码可以在 https://github.com/danuo/rocket-meister/的 GitHub : 上找到

我们将涵盖的内容:

第 1 部分——用 Pygame 创建一个可玩的环境

链接:https://medium . com/@ d . brummer loh/ultimate-guide-for-reinforced-learning-part-1-creating-a-game-956 f1 F2 b 0 a 91

  • 创造一个健身房的环境。Env 子类。
  • 通过step()函数实现环境逻辑。
  • Pygame 获取用户输入,使环境适合人类玩。
  • Pygame 实现一个render()函数来可视化环境状态。
  • Matplotlib 实现交互级设计。

第 2 部分—开始培训

  • 在理解可能性和挑战的同时,定义合适的观察。
  • 定义合适的奖励。
  • gym环境训练神经网络。
  • 对结果的讨论

这是该系列的第二部分,涵盖了神经网络的训练。在我们开始训练之前,我们必须进一步指定环境和人工智能之间的 API。

要求

由于我们要训练的模型相对较小,因此可以在合理的时间内(不到一天)在消费级桌面 CPU 上进行训练。你不需要一个强大的 GPU 或访问云计算网络。本指南中使用的 python 包如下所示:

**Python** 3.8.x
**ray 1.0**
**tensorflow** 2.3.1
**tensorflow-probability** 0.11
**gym 0.17.3
pygame 2.0.0**

观察

观察是从环境反馈给代理或神经网络的反馈。这真的是唯一的事情,代理可以看到,以推导出它的下一步行动。更重要的是,代理没有记忆。它的决定将完全基于对当前状态的观察。

定义合适的观察对于获得良好的培训效果至关重要。在我们当前的例子中,定义观察可能是一个微不足道的任务,但是我们将探索几个选项。这可能不是其他机器学习项目的情况,在其他机器学习项目中,开发合适的观测值可能是一项具有挑战性的关键任务。

在我们讨论合适的观测的要求之前,让我们先用最直观的方法来研究:由于火箭不会撞向边界,使用间隙作为观测是有意义的。所以我们计算了各种角度下火箭与环境的距离(-90,-60,…,+90),如下图所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

归一化现在,我们需要确定每个观测值的取值范围是[-1,1]。这个过程称为规范化,不是强制性的。但是,大多数神经网络将受益于标准化值。这是因为大多数神经网络在计算结束时都有一个反正切函数。在这种情况下,归一化值范围在数值上更合适。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

观察的标准化。

实现标准化的一种方法是应用线性插值。实现这一点的简单方法是使用下面的 numpy 函数:

obs_norm = np.interp(obs, [0, 1000], [-1, 1])

观察值的唯一性用数学术语来说,把模型想象成一个确定性函数 f ,它根据观察值*【o】计算动作*【a】*。*在本例中,有 n 个观察值和 2 个动作:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里有很多理论要探讨,但重要的含义如下:如果两种不同的情况或状态需要两种不同的行动才能成功,那么它们各自的观察也必须不同。只有当观察结果不同时,代理才能产生两种不同的动作。那么这到底意味着什么呢?让我们来看一个例子:

下图中显示的两个场景显示火箭处于完全相同的位置。因此,距离l1,…,l7是相同的。然而,左边场景中的火箭速度要高得多。因为速度不是观测的一部分,代理人不知道火箭太快了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

具有相同观测值的不同状态(观测值集 7)

要执行的适当行动分别是:

  • 左图:减速,右转。
  • 右场景:增加/保持速度,右转。

由于对两种情况的观察是相同的,神经网络将不可避免地对两种情况执行相同的动作。因此,它根本无法在两种情况下执行适当的操作,最多只能完成其中一种。因此,单独使用距离作为整个观测值 o=[l1,…,l7]不是一个好主意。出于测试的目的,我们将把它作为观测的第一次迭代。

观测值 o7 的第一次迭代:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接下来,我们将扩展这个集合。从最近的考虑中,我们已经得出结论,神经网络需要知道火箭的速度。因此,速度大小将起作用:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

观测值 o8 的第二次迭代:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然而,我们可以很容易地想出两个场景,这两个场景需要不同的操作,尽管产生了相同的观察结果。速度转向的方向不能从这组观测值中扣除。因此,移动方向未知,需要另一次观察。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

具有相同观测值的不同状态(观测值集 8)

显然,我们需要使观测范围内的速度有方向。作为一个小注释,简单地分别传递 x 和 y 方向的速度是行不通的。火箭的绝对方位也不知道,所以这个问题可以简单地转换成另一个问题。因此,建议将火箭方向与其速度之间的相对角度作为附加观测值:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用角度有点棘手。首先我们需要决定是要有度的工作还是要光芒四射的工作。其次,如果角度不在-180°范围内< α

第三次迭代观测 o9:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后但同样重要的是,我们将提供某种导航辅助。对于奖励功能,我们稍后将沿着轨迹定义目标,当达到时将获得奖励。下一个目标的方向是垂直于下一个目标的向量,因此指示到所述目标的直接路线。火箭方向和目标向量之间的角度差是第 10 次也是最后一次观察:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第四次迭代观测 o10:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在我们评估不同组的观察值之前,请记住,神经网络不知道已定义观察值的含义或上下文。然而,也不尽然。机器学习的目标是找到观察和成功行动之间的数字相关性。对于这一点,数据的上下文无关紧要。

对观察结果的评估

所有四种变体都已经通过用 SAC 代理进行总共 200 万步的训练进行了测试。不要担心,我们稍后将经历开始培训的步骤。现在,让我们先看看观测值的选择所导致的后果。通过查看图表,我们可以看到 o9 & o10 比其他两个表现好得多。设置 o9 产生最好的结果,这是一个小惊喜。然而,我们不应急于下结论,并记住以下几点:首先,200 万步并不多。虽然 o7o8 的曲线看似收敛,但本试验无法确定 o9o10 的最终性能。经过更长时间的训练, o10 很有可能超过 o9 。甚至 o7o8 的停滞都不确定。如果这不是一个有趣的项目,更长时间的训练应该被考虑。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

四组不同观察值之间的性能比较。

奖励函数

如前所述,奖励功能是环境的一部分,据说在强化学习中被代理人最大化。想出一个好的奖励函数比你想象的要难得多。当最大化奖励函数并不完全符合你实际上想要 AI 做的事情时,问题就出现了。拥有一个只重视符合你意图的行为的奖励功能,实际上比预期的要困难得多。

Rob Miles [Youtube]有一个非常好的视频,讲述了一个被设计用来收集邮票的人工智能,它可能会在收集邮票的过程中引发一场世界大战。该视频非常有趣,同时也很有见地。

回到奖励函数的定义:假设我们在更高的速度下给予更多的奖励。预测代理最有可能以尽可能高的速度撞上墙并不需要太多的创造力。当然,一个更慢的轨迹,实际上是穿过整个过程,会产生更高的总回报。然而,放弃目前最成功的策略,探索一种完全不同的方法,总是令人乏味的。在数学术语中,给定的高速碰撞进近是所有可能进近空间中的局部最大值。

摆脱局部极值并进一步优化其策略是智能体的基本能力。但是,不能保证代理真的做到了这一点。因此,明智的做法是不要在奖励函数中包含速度,或者不给它很大的权重,这样就不会产生这种障碍。相反,我们选择设立检查站,在通过时给予奖励。

设置检查点

为了计算奖励,我在赛道上一共设置了 40 个检查站。这是一种跟踪赛道进展的简单方法,也可以计算完成的圈数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

此外,我们提出了三个变量来推断火箭通过的检查站的回报。变量如下所列,并在之后进行比较:

变体 1:每个关卡的静态奖励

静态变量将以固定的数量奖励每个到达的检查点。

# for each goal 1 point
reward_total += 1

变体 2:每个关卡的动态奖励

动态变量将奖励每一个达到略低于一点的关卡。到达下一个关卡花费的时间越长,奖励的一分被扣除的就越多。根据所用时间的不同,奖励在 1 到 0.9 分之间不等。变量 steps 保存自达到最后一个目标以来执行的步数。这个变量间接依赖于火箭的速度。

# for each goal give:
reward_total += max(1, (500 - steps)) / 500

变体 3:对每个目标的持续奖励

类似于变体 1,这种连续变体将奖励每个目标恰好一分。但是,在执行的每一步中,奖励都是连续分配的。如果火箭正好位于目标 3 和目标 4 之间,那么到目前为止获得的总奖励是 3.5 分。后退时,奖励分别减少。这个奖励变量的计算相当繁琐,但是可以看看 GitHub 库中的代码。

比较

正如我们所看到的,在长时间的训练之后,所有的奖励函数都给出了相似的好结果。所有的变化都会产生一个神经网络,它可以相当好地完成课程。这并不奇怪,因为这些奖励函数非常相似。我们可以看到,在很大一部分训练中,有动态奖励的训练有更高的平均奖励。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

培养

为了在我们的环境中训练神经网络,我们将使用强化学习(RL),机器学习的领域之一。虽然有很多方法可以部署 RL,但是我们将使用一个叫做 Ray 的框架。

Ray 的核心功能是提供一个多处理框架,允许代码在多个 CPU 核心甚至多个机器上并行运行。这非常有帮助,因为它使我们能够同时用多个代理/环境来训练我们的神经网络。Ray 还包含了一个强化学习库,因此我们可以在很少甚至没有编程的情况下进行训练。我们只需要知道 API,不可否认的是,它很少被记录,而且有时很复杂。

在 Windows 10、OSX 和 Linux 上安装 Ray

Ray 刚刚发布了 1.0 版本,终于添加了期待已久的 Windows 10 支持。现在,您可以通过运行简单的 pip 安装在任何主要平台上安装 Ray:

pip install --upgrade ray

雷入门

我们使用 Ray 的主要原因是包含了专用于 RL 的库 RLlib 。它实现了大量先进的机器学习代理。正如下面的概述所示,大多数代理都支持 TensorFlow 2 和 Pytorch。你想用哪个框架完全取决于你。如果你不确定,就用 TensorFlow。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

RLlib 提供的机器学习代理。

ray 的伟大之处在于已经实现了许多训练代理,并且所有的代理都可以以相同的方式使用。这使得我们可以用 14 个不同的代理来训练网络,只需要在它们之间改变一个字符串。

Ray 的文档可能有点令人不知所措,并且由于普遍缺乏示例而令人困惑。尽管如此,这个库非常强大,完全值得学习,因为繁琐的任务可以通过少量的步骤来完成。如果我们使用算法 PPO 在健身房环境 CartPole-v0 上开始训练,我们所要做的就是执行这两行代码:

from ray import tune
tune.run('PPO', config={"env": "CartPole-v0"})

如果您遇到一个错误,您很可能会丢失包tensorflow-probability包。要安装,请运行:

pip install --upgrade tensorflow-probability

为了在一个定制的环境中训练网络(例如,一个不属于gym包的环境),我们需要在配置字典中修改 env 关键字。我们可以传递环境类,而不是环境的名称字符串。参考见 start_ray_training.py: 中的代码

https://github . com/danuo/rocket-meister/blob/master/start _ ray _ training . py

结果

最终,9 个不同的代理被用来训练不同的神经网络。并不是前面列出的所有代理都可以被使用,因为一些代理经常崩溃,而另一些代理只适合于不连续的动作(记住,我们使用的是连续动作)。以下是培训的结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们看到一些代理人表现很好,比人类更好地通过了课程。还要记住,所有代理都是未调整的,也就是说,它们使用默认参数运行。当选择其他参数时,它们的性能可能会提高很多。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结论

还有其他一些因素使得很难在两种药物之间进行直接比较。在这个测试场景中,每个代理接受了总共 1500 万步的训练。请注意,并非所有代理的计算速度都一样快。如果我每次训练的时间相同,结果可能会不同。此外,对于大多数代理来说,培训可能不一致,因此更长时间的培训可以进一步改进策略。快速学习代理是伟大的,但有人可能会说,长期训练后的最终表现可能更重要。

另外请注意,SAC 并不像测试中显示的那样优越。SAC 代理的得分明显高于其他代理。然而,人们不得不相信,这些有争议的伟大成果是受制于过度拟合。这意味着,代理人实际上记住了轨道,而不是实际学习如何控制火箭。如果环境被改变,代理人被认为是失败的,因为没有在未知环境中机动的一般知识。为了防止过度拟合,训练应该在动态环境中进行,在每次迭代中都会发生变化。rocketmeister 环境有一个级别生成器,也许你想尝试一下!有关更多信息,请查看自述文件:

[## 达诺/火箭-梅斯特

RocketMeister 是一个广泛而复杂的健身房环境,用于开发和比较强化学习…

github.com](https://github.com/danuo/rocket-meister)

感谢阅读!

强化学习终极指南第 1 部分——创建游戏

原文:https://towardsdatascience.com/ultimate-guide-for-reinforced-learning-part-1-creating-a-game-956f1f2b0a91?source=collection_archive---------5-----------------------

入门

在这个全面的文章系列中,我们将构建自己的环境。稍后,我们将使用强化学习来训练一个神经网络。最后,我们将创建一个视频,展示人工智能播放环境。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

环境、培训和展示的完整代码可以在GitHub:https://github.com/danuo/rocket-meister/上找到

我们将涵盖的内容:

第 1 部分——用 Pygame 创建一个可玩的环境

  • 创造一个环境作为健身房。Env 子类。
  • 通过step()函数实现环境逻辑。
  • Pygame 获取用户输入,使环境适合人类玩。
  • Pygame 实现一个render()函数来可视化环境状态。
  • Matplotlib 实现交互级设计。

第 2 部分——用强化学习训练神经网络

https://medium . com/@ d . brummer loh/ultimate-guide-for-ai-game-creation-part-2-training-e 252108 DFB D1

  • 在理解可能性和挑战的同时,定义合适的观察。
  • 定义合适的奖励。
  • gym环境训练神经网络。
  • 对结果的讨论

这是这个系列的第一部分。我们将实现游戏逻辑,为控件获取用户输入数据,并实现渲染,使人类有可能玩游戏。为此,我们将使用一个叫做 Pygame 的流行 python 包。

要求

由于我们要训练的模型相对较小,因此可以在合理的时间内(不到一天)在消费级桌面 CPU 上进行训练。你不需要一个强大的 GPU 或访问云计算网络。本指南中使用的 python 包如下所示:

**Python** 3.8.x
**ray 1.0**
**tensorflow** 2.3.1
**tensorflow-probability** 0.11
**gym 0.17.3
pygame 2.0.0**

环境

在强化学习的背景下,环境可以被看作是一个互动的问题,需要以最好的方式来解决。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代理与环境的相互作用。

为了量化成功,在环境中定义了一个奖励函数。代理可以看到所谓的观察,这些观察给出了关于环境当前状态的信息。然后,它可以采取特定的行动,返回观察结果和下一个环境状态的标量奖励。代理人的目标是在有限的步骤中获得最大的回报。

从技术角度来看,有许多不同的方式来构建环境。不过最好的方法是采用gym包中定义的结构。gym包是一个现成环境的集合,为强化学习提供了事实上的标准 API。所有的gym环境共享相同的函数和变量名称,这使得环境和代理很容易互换。为了采用gym结构,我们将使我们的环境成为体育馆的子类。Env 类。该类的基本和强制元素如下所示:

这些函数和变量中的大部分将在后面进行更深入的讨论。下面是一个简短的总结,首先列出了最重要的项目:

  • **动作(对象)😗*在step()功能中要执行的动作。在国际象棋比赛中,这个动作是由一个玩家执行的特定的、合法的移动。
  • **观察(对象)😗*这是可供代理选择下一个动作的所有信息。该观察仅基于环境的当前状态。
  • **奖励(浮动)😗*分别是上一次执行动作或上一步得到的奖励。人工智能将试图最大化总回报。回报也可能是负的。
  • done (boolean): 如果设置为 true,则环境到达终点。无法执行更多操作,需要重置环境。
  • info (dict): 允许提取环境数据用于调试目的。数据对代理不可见。
  • env_config(dict): 这个可选的字典可以用来配置环境。
  • **观察 _ 空间和行动 _ 空间:**正如你所想象的,对于特定的环境,只有某些行动和观察是有效的。为了定义格式,需要将observation_spaceaction_space变量分配给各自的 gym.space 类。空间可以有不同的维度和值范围。连续空间和离散空间都是可能的。有关健身房空间的更多信息,请查看文档健身房 GitHub
self.observation_space = <gym.space>
self.action_space = <gym.space>

示例:动作空间的定义

正如在视频中看到的,我们想要控制一个可以向前/向后加速(动作 1)和向左/向右旋转(动作 2)的火箭。因此,我们将动作定义为大小为 2 的线性向量。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

每个数组单元格的值都是连续的,并且必须在[-1,1]的范围内。相应的健身房空间在下面一行代码中定义:

gym.spaces.Box(low=-1., high=1., shape=(2,), dtype=np.float32)

Pygame 实现

Pygame是一个为创建简单游戏而设计的 Python 库。主要特性是 2d 渲染能力、用户输入采集和音频输出选项。下一节将介绍一个非常基本的Pygame实现,只包含最少的功能。如果你更有野心,你可以考虑实现动态帧速率或动态分辨率等功能。

翻译

为了在 Pygame 中渲染,我们需要创建一个窗口(也称为表面)来绘制视觉输出。

window = pygame.display.set_mode((window_width, window_height))

接下来,我们可以为创建的窗口排队 draw 调用。你可以在 Pygame 纪录片中找到可用抽奖呼叫的概述。我们将在添加到我们的 CustomEnv 类的新函数中实现几个示例性的绘制调用。该函数名为 render() ,如下所示:

在进行绘制调用后,需要用pygame.display.update()命令更新并实际呈现窗口。

基本渲染循环

现在是时候通过创建一个渲染循环例程来让我们的环境保持运行了。我们用pygame.init()初始化 Pygame,然后创建一个时钟对象,它可以与tick(fps)一起保持静态帧速率。我们为视觉输出创建一个大小为 1000*500 像素的窗口。然后我们开始一个 while 循环,在用update()生成一帧之前,执行一次step()render()。显然,这个渲染循环只有在render()实际上反映了step()引起的变化时才有意义。

用户输入

Pygame 提供了两种从键盘获取用户输入数据的方法:

  • 第一个名为 pygame.event.get()将在按键状态从未按下变为按下时生成一个事件,反之亦然。其他事情,比如关闭 Pygame 窗口,也会创建一个事件。后者(event.type == pygame.QUIT)使我们能够在不崩溃的情况下结束 while 循环和 Python 脚本。在 Pygame 文档中可以找到密钥常量列表。

  • 第二个方法叫做py game . key . get _ pressed()将返回一个布尔类型的元组,每个条目代表键盘上的一个键。未按下的键的值为 0,按下的键的值为 1。为了评估键状态,我们需要知道哪些键映射到元组的哪个索引。例如,向上箭头键位于索引 273 处。

运动学

接下来,我们将实现火箭的运动学。当我们用一个简单的方法来处理旋转时,平移运动将有惯性。数学上,火箭的轨迹就是运动方程的解,是平滑的。位置不能跳,反而需要不断变化。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因为我们对近似解很满意,所以我们可以用欧拉向前法进行时间离散来计算轨迹。下面的代码显示了一个简单的二维实现:

现在我们将所有东西(游戏逻辑、输入和渲染)合并到我们之前定义的CustomEnv类中。我们还将把所有与 Pygame 相关的东西移到render()和一个单独的init()函数中。这样,我们可以用step()reset()执行机器学习例程,而不用加载更重的 Pygame 包。如果为 AI 训练加载了环境,则不需要渲染,并且可以提高性能。

下面是上面运行的代码,带有一些键盘输入:

水平设计

现在,我们将使用手动创建的静态级别。创建一个可能是一项单调乏味的任务。我们将使用 Matplotlib 让我们的生活变得更简单。使用 plt.ginput() 函数,可以通过在图形内部点击来获取坐标。

这些坐标将被打印到控制台中,您可以从那里将它们复制到您的代码中。稍微重新格式化应该可以将它们包含到我们的环境中,例如将它们存储在 numpy 数组中,如rocket_gym.py所示。

碰撞检测

假设我们将级别边界存储为大小为 n*4 的数组,每行保存一个段的点:

两条直线是否相交可以通过下面的函数来检查。如果线相交,则返回交点的坐标。如果没有交集,则不返回任何交集。

现在,我们可以将公式应用于我们的问题。我们通过检查是否有任何环境边界与运动向量相交来做到这一点

继续第 2 部分

在第二部分中,我们将讨论并实现环境返回的观察和奖励。之后,进行实际训练。请在这里阅读:

https://medium . com/@ d . brummer loh/ultimate-guide-for-ai-game-creation-part-2-training-e 252108 DFB D1

选择合适视觉效果的终极指南

原文:https://towardsdatascience.com/ultimate-guide-to-choosing-the-right-visual-2a77aa8eec08?source=collection_archive---------46-----------------------

从“用数据讲故事:商业专家数据可视化指南”中吸取的经验教训

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

威廉·艾文在 Unsplash 上的照片

说到有效的数据可视化,第一步也是最关键的一步是为您想要呈现的数据选择正确的图形/视图。由于有各种各样的可视化软件可以提供大量不同的图表,选择正确的软件通常是一项具有挑战性的任务,它以尽可能简单的方式解释数据和见解。我最近读了一本关于数据可视化的非常著名的书——《用数据讲故事:商业人士的数据可视化指南》,作者是 Cole Nussbaumer Knaflic。这本书是迄今为止我所见过的关于数据可视化的最佳资源,在本文中,我将解释书中的一个主题——选择有效的可视化。

大多数数据可以使用我将在本文中讨论的 12 种视觉效果中的任何一种来可视化。视觉效果可分为:

  1. 简单文本
  2. 表格(表格、热图)
  3. 点(散点图)
  4. 线(线形图、斜率图)
  5. 条形图(水平、垂直、堆积、瀑布)
  6. 面积

注:

  1. 所有显示的图表都是使用 Google Sheets 制作的。 链接到文档
  2. 用于生成图表的数据完全是虚构的,并非取自任何来源

所以让我们开始探索列表中的每一个。

简单文本

你不必总是用图表来显示数字。如果只有一些数字和一些支持文本,直接显示数字可能是最好的方法。让我们看一个例子来更好地理解。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

在上面的例子中,图表没有为解释提供太多的帮助,只是占据了很大的空间。所以,当你只有几个数字的时候,直接展示出来。

如果你想用多种计量单位进行交流,表格可能是最合适的选择。创建一个表格很容易,但是一定要确保设计淡出背景,数据是主要焦点。下面是一个将设计淡化到背景并专注于数据的例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

你能观察到每次迭代后的改进吗?这就是它如此重要的原因。

热图

热图只是一个表格的升级版本,我们在其中添加颜色来更好地解释数据或数字。在一个简单的表格中,读者必须浏览每一个元素,才能对其中的内容有所了解。通过添加颜色,我们让读者直接关注感兴趣的区域,从而更好地理解数据。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

像 Excel 这样的绘图应用程序具有创建热图的条件格式选项。为了更好地理解,加入图例也是一种很好的做法。

散点图

散点图用于显示两个变量之间的关系,其中每个变量分别用 X 轴和 Y 轴编码。这在解释相关性时特别有用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

线图

折线图是绘制连续数据(如日期和时间)的最佳方式。由于所有的点都用一条线连接起来,所以很容易解释连续的数据,但同时,这对于绘制分类变量没有意义。折线图可用于显示单个系列或多个系列的数据,如图所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

斜率图

斜率图只是线形图的一个特例,非常适合比较两个不同点或时间段的指标变化。这对于直观地显示变化率(增加或减少率由线条的斜率表示)以及绝对值非常有用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

接下来,我们将看看条形图的一些变化,这是分类变量的理想选择。条形图往往被避免,因为它们是常见的,但由于它们是常见的,与其他类型的视觉效果相比,读者很容易理解条形图。这使得条形图成为最重要的视觉形式之一。

竖线

这是一个普通的条形图,每一列代表一个类别。与折线图类似,条形图也可以包含多个系列。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

堆叠竖条

堆积条形图可用于比较不同类别的子组件。它可以使用 100%堆积图来保存实际数字或百分比。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

同样,你不能用太多的子组件来填充类别,因为这会变得难以理解和比较。

瀑布

瀑布图是垂直条形图的另一种特殊情况,它可以用于拉动堆积条形图的子组件,一次聚焦一个组件,或者显示起点、增加和减少以及最终的终点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

单杠

水平栏通常是分类数据的首选项,因为它比垂直栏更容易阅读,并且还可以容纳大型类别名称。与垂直条形图类似,它也可以有单个或多个数据系列。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

堆叠的水平条

这类似于堆叠垂直条形图,但由于水平条形图所讨论的原因,相对更好。

面积图

应尽可能避免面积图,因为人眼不太擅长比较二维空间中的值。但是,如果您非常想包含多个指标,那么面积图可能行得通。

至此,我已经介绍了可以用来可视化大部分可用数据的图表。因此,选择一个图表,可以清楚地解释你试图传达的信息。

我们已经讨论了最佳实践,现在是时候看看一些应该避免的实践了。

要避免的视觉实践

避免使用饼图,因为读者必须比较弧线的区域,这变得非常困难且不直观。使用一个标准的条形图会使它更容易解释。看看下面的例子可以更好的理解。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

永远不要使用三维图表。3D 图表会产生不必要的干扰,使其难以解读。所以千万不要用 3D

结论

我希望这篇文章能让你很好地理解不同的视觉效果,以及在什么地方使用每种视觉效果。所以,一定要选择能充分传达你想要展示的信息的视觉效果。说到您可以使用的应用程序/软件,这完全取决于您。Excel,Tableau,Power BI,Google Sheets 是一些可用的应用程序,你可以使用任何你觉得舒服的东西。请记住,图形应用程序并不知道视觉对象的实际用途,而是由您根据需要定制它。我希望它有帮助。

神经网络中输入形状和模型复杂性的最终指南

原文:https://towardsdatascience.com/ultimate-guide-to-input-shape-and-model-complexity-in-neural-networks-ae665c728f4b?source=collection_archive---------3-----------------------

计算神经网络输入形状和复杂性的直观指南

在构建神经网络时,许多初学者和非初学者似乎都陷入了计算需要输入到神经网络中的输入形状的困境。

但是我们为什么要知道输入的形状,又为什么要喂它呢?神经网络不能自己算出来吗? 这个问题的答案在于矩阵乘法的基础知识。

假设我们有两个矩阵 A 和 B,设 B 的维数为 m 行 x n 列。现在,为了使两个矩阵在乘法上兼容,A 的列维度应该与 b 的行维度相同,这意味着 A 的维数应该是 k x m,其中 k 可以是任何数字。

现在,图片 A 作为输入张量(一组图像、一组输入特征样本、特定词汇大小的文本数据等)。)和 B 作为神经网络中的第一个隐藏层。k 是输入样本的数量,m 是每个输入样本的维数。m 的形状取决于输入的类型和隐藏层的类型。

让我们来看看最常用的神经网络类型,并弄清楚输入形状应该是什么:

  1. (DNN)深度神经网络:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个 4 层神经网络(承蒙:http://alexlenail.me/NN-SVG/index.html)

这些是用于分类和回归任务的完全连接的神经网络。这些有时也会附加到某些更高级架构的末端( ResNet50VGG16AlexNet 等)。)

让我们看一个这样的神经网络:

model = Sequential()
model.add(Dense(units=12, activation='relu', input_shape=(32,)))
model.add(Dropout(0.5))
model.add(Dense(units=8, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(units=6, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(units=1, activation='softmax'))

该模型由三个隐藏层和一个输入层组成。在每对致密层之间添加脱落层,以实现规整化。Dropout 层采用参数“rate ”,该参数指定前一密集层中应取零值的神经元的比例。在这个模型中,比率设置为 0.5,这意味着隐藏层中 50%的神经元的权重为 0。

在 Keras 中,需要给出输入维度,不包括批量大小(样本数)。在这个神经网络中,输入形状被给定为(32,)。32 是指每个输入样本中的特征数量。不要提批量大小,甚至可以给出一个占位符。另一种给出上述模型中输入维度的方法是(None,32,)。

如果数据是多维的,比如图像数据,那么输入数据必须以(m,n)的形式给出,其中 m 是高度维度,n 是宽度维度。

因为 32 是特征大小,所以它是输入矩阵的列维数。这意味着隐藏层的行尺寸也是 32。现在我们已经对输入游戏进行了分类,让我们看看这个模型并理解它的复杂性。这里,复杂性是指可训练参数的数量(权重和偏差参数)。可训练参数的数量越多,模型越复杂。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

深度神经网络模型综述

由于每个输入特征都连接到隐藏层中的每个神经元,因此连接总数是输入特征大小(m)和隐藏层大小(n)的乘积。由于每个连接与一个权重参数相关联,权重参数的数量为 m×n。每个输出神经元与一个偏置参数相关联,因此偏置参数的数量为 n。可训练参数的总数= m×n+n

第一密/隐层有 12 个神经元,这是它的输出维度。这在模型摘要中作为第二个输出参数出现,与第一个隐藏层相对。后续的脱落层不会改变输出的尺寸。它只是改变了神经元的重量。第二个隐层有 8 个输出神经元,下一层有 6 个。最终输出层有 1 个神经元。让我们验证这个模型的全部可训练参数。

第一隐藏层(m = 32,n = 12):32 x 12+12 =396
396
第二隐藏层(m = 12,n = 8) : 12 x 8 + 8 = 104 第三隐藏层(m = 8,n = 6) : 8 x 6 + 6 = 54 输出层(m = 6,n = 1) : 6 x 1 + 1 = 7

总可训练参数= 396 + 104 + 54 + 7 = 561

  1. 卷积神经网络(CNN): 这些大多用于处理各种计算机视觉应用的图像数据,如图像检测、图像分类、语义分割等。由于图像数据是多维数据,因此需要不同类型的处理层来检测图像的最重要特征。这就是卷积神经网络的作用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个示例性的 CNN 模型(承蒙:http://alexlenail.me/NN-SVG/index.html)

图像被表示为一个三维元组——水平维度(宽度)、垂直维度(高度)和通道数量。如果图像是灰度的,那么通道参数取值为 1,如果是彩色的,那么取值为 3,红色、绿色和蓝色通道各一个。

Input_shape=(None, 284, 284, 3)
cnn=Sequential()
cnn.add(Conv2D(16, kernel_size=(2,2), padding="same", activation='relu', input_shape=Input_shape[1:]))cnn.add(MaxPooling2D(4))
cnn.add(Conv2D(32, kernel_size=(2,2), padding="same", activation='relu', input_shape=Input_shape[1:]))cnn.add(MaxPooling2D(2))
cnn.add(Flatten())cnn.add(Dense(10, activation='softmax'))

卷积神经网络有两种特殊类型的层。卷积层(模型中的 Conv2D)和池层(MaxPooling2D)。维度为 k 的 2-D 卷积层由一个 k x k 过滤器组成,该过滤器通过图像中的每个像素。因为 k×k 滤波器覆盖 k×k 个像素,所以当它经过一个像素时,它的 k -1 个邻居也被覆盖。执行滤波器矩阵和覆盖图像矩阵的逐元素乘法。这些值相加并填充到相应的输出像素中。

例如,如果 2×2 维的卷积滤波器通过位置(1,1)处的图像像素,则它也覆盖(0,0)、(0,1)和(1,0)。滤镜的(0,0)值乘以图像的(0,0)值,依此类推。我们得到四个值,它们相加并填充到输出的(1,1)位置。

请注意,这会缩小图像的大小。如果滤波器要通过一个边界像素,比如(0,1),那么就没有输出,因为这个像素没有相邻像素可供卷积通过。这将在宽度为 k/2 的图像周围显示为黑色边框。

当大小为 k x k 的卷积滤波器通过大小为 n x n 的图像时,输出大小变为 n-k+1。

为了防止缩水,边框周围加了衬垫。参数 padding 设置为“same”,这意味着以不改变原始图像大小的方式在图像周围添加填充。

池层就是这样做的;它汇集图像中一定数量的像素,并捕获最显著的特征(最大汇集)或像素的集合(平均汇集)作为输出。该模型包含一个大小为 2 x 2 的最大池层,它捕获每个 4 像素聚类的最大像素值。这将输出的大小减少到其原始大小的 1/4(或者对于大小为 k x k 的池层,减少 1/k)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们仔细看看这个模型。输入尺寸为 284 x 284 x 3。它通过 16 个 2×2 滤波器的第一卷积层,带有填充。因此,该层的输出尺寸为 284 x 284 x 16。随后的层是尺寸为 4 x 4 的最大池层,它将图像缩小 16 倍,高度方向缩小 4 倍,宽度方向缩小 4 倍。所以输出尺寸是 71 x 71 x 16。下一个卷积层也有填充和 32 个滤波器,输出为 71 x 71 x 32。维度为 2 x 2 的下一个池层将输入缩小到维度 35 x 35 x 32。

该输出被馈送到输出层(全连接/密集层)。但是,在将数据提供给密集层之前,需要将数据重新整形为一维。这是通过展平层实现的。

对于 m 个输入通道和 n 个滤波器/内核大小为 k×k 的滤波器(输出通道)的卷积层,内核单独检查图像的每个通道,并产生每个输出通道的输出。因此,对于输入-输出通道的每个组合,我们需要分配 k×k 个权重。因此,权重参数的数量为 m×k×k×n,偏差的数量等于通道的数量 n。参数的总数为m×k×k×n+n

池层只不过是聚合像素值。因此这里没有可训练的参数。

让我们验证卷积神经网络的模型参数的吻合。

第一 Conv 层(m = 3,k = 2,n = 16):3×2×2×16+16 =208 第二 Conv 层(m = 16,k = 2,n = 32):16×2×2×32+32 =2080 输出层(m = 39200,n = 10):39200×10+10 =392010

总可训练参数= 208+2080+392010 =394298

3。递归神经网络(RNN): 这些神经网络用于处理顺序数据,或者当前输出不仅取决于当前输入,还取决于先前输入的数据。它用于时间序列预测、自然语言处理等。
RNNs 的一个独特特征是它包含门,允许或省略来自先前隐藏状态的输入添加到当前输入,完全可由用户配置。

有三种主要的 RNN。最基本的是“香草”RNN,其中包含一个门。另外两个是长短期记忆单元(LSTM)和门控循环单元(GRU)。LSTM 有 4 个门,而 GRU 有 3 个,这使得它在计算上比 LSTM 单位更快。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由 Michael Phi 提供:https://towardsdatascience . com/illustrated-guide-to-lstms-and-gru-s-a-step-by-step-a-step-explain-44e 9 EB 85 BF 21

上面是一幅区分 LSTM 和 GRU 建筑的插图,由 Michael Phi 的博客提供,你可以在这里参考。

model=Sequential()
model.add(LSTM(32, input_shape=(100,2)))
model.add(Dense(1))

我们这里有一个简单的 LSTM 模型(4 门),它馈入一个密集输出层。该模型接受三维输入:批量大小、时间戳和特征。与所有 Keras 层的情况一样,批量大小不是一个强制参数,但需要给出其他两个参数。在上述示例中,输入包含 100 个时间步长和 2 个要素。每一个时间步都是一个观察序列(例如一个单词序列)。特征类似于卷积神经网络中的通道。在该模型中,有 2 个输入通道。

在具有 g 个门、m 个输入特征和 n 个输出单元的递归神经网络中,每个门与当前输入以及前一个单元的隐藏状态(输出)有联系。因此,对于每个门,权重参数的数量为 n x n+ m x n。每个输出单元都有一个偏置参数,因此偏置参数的数量为 n。单个门的总参数为 n x n + n x m + n。对于 g 个门,总参数为 g x (n x n + n x m + n)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

LSTM 模式概述

对于上述模型,让我们验证参数吻合。

LSTM 层(g = 3,m = 2,n = 32):3 x(32 x 32+32 x 2+32)=4480 输出层(m = 32,n = 1) : 32 x 1 + 1 = 33

总可训练参数= 4480 + 33 = 4513

知道输入形状对于建立神经网络非常重要,因为所有的线性代数计算都是基于矩阵维数的。然而,这篇文章试图解决围绕它的谜团。此外,Keras 对每个模型和输入形状都有非常全面的文档,这使得处理这个挑战变得稍微容易一些。

参考:

[## LSTM 和 GRU 的图解指南:一步一步的解释

嗨,欢迎来到长短期记忆(LSTM)和门控循环单位(GRU)的图解指南。我是迈克尔…

towardsdatascience.com](/illustrated-guide-to-lstms-and-gru-s-a-step-by-step-explanation-44e9eb85bf21)

https://keras . io/API/Layers/#:~:text = Layers % 20 are % 20 basic % 20 building,variables%20(层的%20weights)。

Python 调试终极指南

原文:https://towardsdatascience.com/ultimate-guide-to-python-debugging-854dea731e1b?source=collection_archive---------12-----------------------

让我们探索使用 Python 日志记录、回溯、装饰器等等进行调试的艺术…

即使您编写了清晰易读的代码,即使您用测试覆盖了您的代码,即使您是非常有经验的开发人员,奇怪的错误还是会不可避免地出现,您需要以某种方式调试它们。许多人求助于仅仅使用一堆print语句来查看他们的代码中发生了什么。这种方法远非理想,还有更好的方法来找出代码中的问题,其中一些我们将在本文中探讨。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由丹尼·麦克Unsplash 上拍摄

记录是必须的

如果您编写的应用程序没有某种日志设置,您最终会后悔的。没有来自应用程序的任何日志会使排除任何错误变得非常困难。幸运的是——在 Python 中——设置基本记录器非常简单:

这就是开始将日志写入文件所需要的全部内容,文件看起来会像这样(您可以使用logging.getLoggerClass().root.handlers[0].baseFilename找到文件的路径):

这种设置可能看起来足够好了(通常如此),但是拥有配置良好、格式化、可读的日志可以让您的生活变得更加轻松。改进和扩展配置的一个方法是使用由记录器读取的.ini.yaml文件。例如,您可以在配置中执行以下操作:

在 python 代码中包含这种大量的配置将很难导航、编辑和维护。将东西保存在 YAML 文件中使得用非常特殊的设置来设置和调整多个记录器变得更加容易。

如果你想知道所有这些配置字段是从哪里来的,这些在这里有记录,其中大部分只是第一个例子中所示的关键字参数

所以,现在文件中有了配置,意味着我们需要加载 is。对于 YAML 文件,最简单的方法是:

Python logger 实际上并不直接支持 YAML 文件,但它支持字典配置,可以使用yaml.safe_load从 YAML 轻松创建。如果你倾向于使用旧的.ini文件,那么我只想指出,根据文档,使用字典配置是新应用的推荐方法。更多例子,请查看日志食谱

伐木装饰工

继续前面的日志记录技巧,您可能会遇到需要记录一些有问题的函数调用的情况。您可以使用 logging decorator 来代替修改所述函数的主体,它会用特定的日志级别和可选的消息来记录每个函数调用。让我们来看看装潢师:

不骗你,这可能需要一点时间来理解(你可能想直接复制粘贴并使用它)。这里的想法是,log函数获取参数,并使它们对内部的wrapper函数可用。然后,通过添加附属于装饰器的访问函数,使这些参数变得可调整。至于functools.wraps装饰器——如果我们不在这里使用它,函数名(func.__name__)将被装饰器名覆盖。但是这是一个问题,因为我们想打印名字。这由functools.wraps解决,因为它将函数名、文档字符串和参数列表复制到装饰函数上。

无论如何,这是上面代码的输出。很漂亮,对吧?

repr 获取更多可读的日志

使代码更易调试的简单改进是在类中添加__repr__方法。如果你不熟悉这个方法,它所做的只是返回一个类的实例的字符串表示。使用__repr__方法的最佳实践是输出可用于重新创建实例的文本。例如:

如果如上所示表示对象不可取或不可能,好的替代方法是使用<...>表示,例如<_io.TextIOWrapper name='somefile.txt' mode='w' encoding='UTF-8'>

除了__repr__之外,实现__str__方法也是一个好主意,默认情况下,当print(instance)被调用时使用这个方法。有了这两种方法,你就可以通过打印变量获得大量信息。

用于字典的 missing Dunder 方法

如果你出于某种原因需要实现自定义字典类,那么当你试图访问一些实际上并不存在的键时,你会发现一些来自KeyError的错误。为了避免在代码中摸索并查看哪个丢失,您可以实现特殊的__missing__方法,该方法在每次KeyError被引发时被调用。

上面的实现非常简单,只返回并记录丢失了的消息,但是您也可以记录其他有价值的信息,以提供更多关于代码中哪里出错的上下文。

调试崩溃应用程序

如果您的应用程序在您有机会看到发生了什么之前就崩溃了,您可能会发现这个技巧非常有用。

-i参数(python3 -i app.py)运行应用程序会导致程序一退出就启动交互式 shell。此时,您可以检查变量和函数。

如果这样还不够好,可以带个更大的锤子—pdbPython 调试器。有相当多的特性足以保证一篇独立的文章。但这里有一个例子和最重要的位的纲要。让我们先看看我们的小崩溃脚本:

现在,如果我们用-i参数运行它,我们就有机会调试它:

上面的调试会话非常简要地展示了您可以用pdb做什么。程序终止后,我们进入交互式调试会话。首先,我们导入pdb并启动调试器。此时,我们可以使用所有的pdb命令。作为上面的例子,我们使用p命令打印变量,使用l命令列出代码。大多数时候,你可能想设置断点,你可以用b LINE_NO来设置,然后运行程序直到断点被命中(c),然后用s继续单步执行函数,也可以用w打印堆栈跟踪。关于命令的完整列表,您可以查看[pdb](https://docs.python.org/3/library/pdb.html#debugger-commands) 文档

检查堆栈跟踪

比方说,你的代码是运行在远程服务器上的 Flask 或 Django 应用程序,在那里你不能获得交互式调试会话。在这种情况下,您可以使用tracebacksys包来更深入地了解代码中的失败之处:

运行时,上面的代码将打印最后一次引发的异常。除了打印异常,您还可以使用traceback包来打印堆栈跟踪(traceback.print_stack())或提取原始堆栈帧,将其格式化并进一步检查(traceback.format_list(traceback.extract_stack()))。

调试期间重新加载模块

有时,您可能正在调试或试验交互式 shell 中的某些功能,并对其进行频繁的更改。为了使运行/测试和修改的循环更容易,您可以运行importlib.reload(module)以避免每次更改后都必须重启交互会话:

这个技巧更多的是关于效率而不是调试。能够跳过一些不必要的步骤,让你的工作流程更快更有效率,这总是很好的。一般来说,不时地重新加载模块是一个好主意,因为它可以帮助您避免试图调试同时已经修改了很多次的代码。

调试是一门艺术

结论

大多数时候,编程的真正含义只是大量的尝试和错误。另一方面,在我看来,调试是一门艺术,精通它需要时间和经验——你对你使用的库或框架了解得越多,就越容易。上面列出的提示和技巧可以让您的调试更高效、更快速,但是除了这些特定于 Python 的工具,您可能还想熟悉一些通用的调试方法——例如,Remy Sharp 的调试艺术

如果你喜欢这篇文章,你应该看看我下面的其他 Python 文章!

本文原帖martinheinz . dev

[## 下一个 Python 项目的最终设置

从零开始任何项目都可能是一项艰巨的任务…但如果您有这个最终的 Python 项目蓝图就不会了!

towardsdatascience.com](/ultimate-setup-for-your-next-python-project-179bda8a7c2c) [## 自动化 Python 项目的各个方面

每个 Python 项目都可以从使用 Makefile、优化的 Docker 映像、配置良好的 CI/CD、代码…

towardsdatascience.com](/automating-every-aspect-of-your-python-project-6517336af9da) [## 让 Python 程序快得惊人

让我们看看我们的 Python 程序的性能,看看如何让它们快 30%!

towardsdatascience.com](/making-python-programs-blazingly-fast-c1cd79bd1b32)

熊猫终极指南——创建数据框架

原文:https://towardsdatascience.com/ultimate-pandas-guide-creating-a-dataframe-9f063e590e78?source=collection_archive---------43-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

劳拉·伍德伯里摄于佩克斯

用 Python 从头开始构建数据

任何数据分析工作的第一步,或许也是最重要的一步,是获取你的原材料;你的数据。

根据项目的成熟度,这个阶段可能非常简单——向同事请求 csv,查询结构良好的数据库,等等。或者更复杂一些,比如构建一个定制的 web scraper。

但并不是所有项目所需的数据都来自外部来源。有时候你需要自己编造。

在这篇文章中,我将从头开始介绍创建数据帧的过程。

理解“数据框架”方法

创建新数据帧的最简单方法是使用“DataFrame”方法。如果你熟悉面向对象编程,你会注意到这实际上是一个构造函数调用,它实例化了一个新的 DataFrame 对象。

所有参数都是可选的,这意味着您可以通过传入… nothing 来创建一个空的数据帧:

import pandas as pd
empty_df = pd.DataFrame()

如果您希望稍后用数据填充一个空的数据帧,这可能会很有帮助。例如,您可以存储几个机器学习模型的汇总结果,方法是从一个空的数据帧开始,然后编写一个循环来填充每个模型的行。

然而,在大多数情况下,您会希望从一开始就用数据填充数据帧。幸运的是,Pandas 非常灵活,允许程序员将各种数据结构转换成数据帧。下面是一个综合指南:

从列表的列表中创建数据帧

将一个列表列表传递给 DataFrame 方法的第一个参数,其中每个内部列表都将是未来的一行。您通常还需要包含一个“columns”参数,它是您想要使用的列名的简单列表。

data = [[‘panda’, ‘bamboo’, 100], 
       [‘koala’, ‘eucalyptus’, 100]]pd.DataFrame(data, columns = [‘animal’, ‘favorite_food’, ‘cuteness_level’])

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从字典创建数据帧—方法 1

传递一本字典作为第一个参数。字典中的键将成为数据帧中的列。字典中的值应该是将填充列的列表:

data = {‘animal’: [‘panda’, ‘koala’],
        ‘favorite_food’: [‘bamboo’, ‘eucalyptus’],
        ‘cuteness_level’: [100, 100]}pd.DataFrame(data)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从字典创建数据帧—方法 2

还可以使用 DataFrame 类的类方法中的 from_dict 方法从字典中创建 DataFrame。

这样做的好处是,您可以将“orient”参数设置为“index”,这将改变字典填充数据帧的方式。在这种情况下,字典的键将成为行索引,其值将成为行:

data = {‘animal’: [‘panda’, ‘koala’],
        ‘favorite_food’: [‘bamboo’, ‘eucalyptus’],
        ‘cuteness_level’: [100, 100]}pd.DataFrame.from_dict(data, orient = ‘index’, columns = [‘first_animal’, ‘second_animal’])

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从字典列表创建数据帧

将字典列表传递给第一个参数。对于每个字典,键对应于列名,值对应于数据帧每一行中的值:

data = [{'animal': 'panda', 
         'favorite_food': 'bamboo', 
         'cuteness_level': 100}, {'animal': 'koala', 
          'favorite_food': 'eucalyptus', 
           'cuteness_level': 100}]pd.DataFrame(data)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从 numpy 数组创建数据帧

将 numpy 数组直接传递给 DataFrame 方法:

data = np.array([(‘panda’, ‘bamboo’, 100), 
                 (‘koala’, ‘eucalyptus’, 100)],
               dtype=[(‘animal’, ‘U6’), 
              (‘favorite_food’, ‘U6’), 
               (‘cuteness_level’, int)])pd.DataFrame(data)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我的建议

在这篇文章中,我们介绍了创建新数据框架的各种方法。

当我从头开始构建一个表时,我更喜欢使用列表列表方法,因为它有最直观的翻译。每个内部列表都是水平呈现的,实际上看起来就像它在数据帧中变成的行。编码快乐!

终极熊猫指南——像专家一样检查数据

原文:https://towardsdatascience.com/ultimate-pandas-guide-inspecting-data-like-a-pro-9b4f13c39c94?source=collection_archive---------26-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

劳拉·伍德伯里摄于佩克斯

无论您正在进行简单的分析还是复杂的机器学习模型,能够快速回答关于数据性质的探索性问题都有很大的价值。

幸运的是,熊猫让这变得容易了。在本文中,我将介绍几个 DataFrame 属性和方法,它们使数据检查变得轻松而高效。

头/尾

**用例:**快速浏览我们的数据框架。

默认情况下,head 方法返回数据的前 5 行:

#returns the first five rows
df.head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

但是我们也可以指定不同的行数来返回:

#returns the first six rows 
df.head(6)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

tail 方法以同样的方式工作,但是从数据帧的底部而不是顶部开始返回行:

df.tail(2)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

**用例:**从我们的数据框架中获取列名。

df.columns

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当我需要记住列名的确切拼写或者当我发现哪些数据点可用时,我发现这很有用。

如果这个对象更方便,我们也可以将索引转换为列表:

list(df.columns)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

形状

**用例:**确定数据帧中的行数和列数。

此方法返回一个元组,其第一个值是行数,第二个值是列数:

df.shape

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为了只获得行数,我们简单地索引元组以提取第一个元素:

df.shape[0]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我喜欢使用这个属性来查找符合特定条件的数据的百分比。

例如,我们可以筛选数据帧,以获取一列中小于 70 的值和另一列中小于 1000 的值的百分比:

df[ (df.ints < 70) & (df.floats < 1000) ].shape[0] / df.shape[0]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

唯一/值计数

**用例:**获取 DataFrame 列中的不同值(即系列对象)。

df[‘strings’].unique()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Value_counts 类似于 unique,但它不是返回唯一值的数组,而是返回每个值的频率序列:

df[‘strings’].value_counts()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

信息

**用例:**获取关于我们的索引、列和内存使用的汇总信息。

df.info(verbose = True)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们将“True”传递给“verbose”参数,以确保我们在处理更大的数据集时能够获得完整的列摘要。

形容

**用例:**获取数据中列的汇总统计信息。

默认情况下,describe 方法只包含数字列:

df.describe()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以用几种方式定制我们的输出。

首先,我们可以通过向“percentiles”参数传递一组介于 0 和 1 之间的值来获得不同的百分点值:

df.describe(percentiles = [.1, .99])

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们还可以使用“include”和“exclude”参数来指定我们希望在输出中包含哪些类型的列。

如果我们将“all”传递给“include”参数,那么除了数字列之外,我们还将获得非数字列的摘要。

对于非数字列,我们将获得计数、唯一计数、top(最常见值)和 freq(最常见值的频率):

df.describe(include = 'all')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后,如果我们想在输出中进一步定制列,我们可以将数据类型列表传递给 include 或 exclude 参数。

奖金-最大行数和列数

默认情况下,pandas 将输出中的行数和列数分别限制在 60 和 20。

如果我们试图返回一个 70 行的数据帧,我们将得到如下结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当我们想要查看所有数据时,这可能会很烦人。

我们可以通过将“max_rows”或“max_columns”传递给 pandas 的“set_option”方法并指定一个值来解决这个问题:

pd.set_option(‘max_rows’, 70)

当我想灵活地查看我的数据的一小部分时,我发现这个技巧非常有用。

结束语

Pandas 通过许多用户友好的方法和属性使数据检查变得相当简单。您还可以编写自己的检查和探索方法来扩展功能。这是使用 Python 这样的脚本语言进行数据分析的优势之一。

编码快乐!

熊猫终极指南-使用 Python 连接数据

原文:https://towardsdatascience.com/ultimate-pandas-guide-joining-data-with-python-48d9feff77ea?source=collection_archive---------31-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

劳拉·伍德伯里摄于佩克斯

掌握“合并”和“加入”的区别

每个从事数据工作的人都知道这一点:在你建立机器学习模型或产生令人惊叹的可视化之前,你必须让你的手弄脏数据争论。

数据争论的核心技能之一是学习如何将不同的数据源连接在一起。

在这篇文章中,我将通过介绍两种核心连接方法——连接和合并,为 pandas 中的连接提供一个全面的指南

如果您需要复习加入数据的含义,我建议您在继续之前查看我的加入数据初学者指南:

[## 连接数据的初学者指南

左接合。内部联接。外部联接。啊?

towardsdatascience.com](/a-beginners-guide-to-joining-data-935c8e579fb7)

“合并”方法

与连接的情况一样,进行 Pandas 合并需要三个基本要素:

1.你的两个数据集

2.要执行的联接类型

3.您的连接密钥

数据源

Merge 是 DataFrame 类的一个方法。这意味着无论何时你调用一个合并,它实际上是被一个数据帧调用的。

“调用”数据帧是您的左侧表。

该方法的第一个参数是您的右表。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

再次注意,table1 是您的左表,table2 是您的右表。

连接类型

你需要的第二个关键因素是你想要使用的连接类型。

在 merge 函数中,您可以通过“how”参数来实现这一点:

table1.merge(table2, **how = ‘left’**)

“How”可以取值为:left、right、inner 或 outer——类似于大多数版本的 SQL。

连接键

在选择连接键时,Pandas 提供了高度的灵活性。

下面是传递连接键的三种主要方法:

  1. 使用“on”参数 —这是最直观的解决方案,但是它要求您试图连接的列具有相同的名称。
companies.merge(stock_price, how = 'left', on = 'Stock Ticker')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.使用“left_on”和“right_on”参数 —对于此方法,您将“left_on”设置为您想要在左侧表格中使用的列,将“right on”设置为您想要在右侧表格中使用的列:

companies.merge(stock_price, how = ‘left’, left_on = ‘Stock Ticker’, right_on = ‘Ticker’)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.使用“left_index”和“right_index”参数:这些是布尔参数——将它们设置为 True 以表明您想要使用索引作为您的连接键:

companies.merge(stock_price, how = ‘left’, left_index = True, right_index = True)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注意,如果您想要连接多个键,您可以简单地将列名列表传递给“on”、“left_on”或“right_on”参数。

另请注意,根据您的使用情况,您可以混合搭配“left_on”、“right_on”、“left_index”和“right_index”。

“加入”方法

join 方法实际上非常类似于 merge 方法。关键的区别在于连接方法强制使用右连接键的索引,默认使用左连接键的索引:

companies.join(stock_price, how = ‘left’)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果您总是喜欢索引连接,您可能会发现这更容易,因为它需要的参数更少。

另一个区别非常小 join 方法默认将“how”参数设置为“left ”,而 merge 方法默认为“inner”。

我的偏好

就个人而言,我更喜欢使用 merge 方法并用“on”参数连接列。如果我需要重命名列,就简单性和可读性而言,这是值得的。

但这只是我的看法。关于 pandas 的一个伟大的事情是,它为您提供了很大程度的灵活性来选择最适合您的语法。编码快乐!

熊猫终极指南——驾驭群体

原文:https://towardsdatascience.com/ultimate-pandas-guide-mastering-the-groupby-104306251739?source=collection_archive---------17-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

劳拉·伍德伯里摄于佩克斯

加深对“分组”和“聚集”的理解

数据分析中最常见的练习之一是将数据分组并执行聚合。

例如,假设您有几个不同维度的客户销售数据:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个自然的问题可能是问——各州的总销售额是多少?还是按性别?还是按月?

在这篇文章中,我将介绍熊猫“groupby”的来龙去脉,帮助你自信地回答 Python 中的这类问题。

“分组”数据的可视化表示

记住“分组”是做什么的最简单的方法是把它分成三个步骤:“分割”、“应用”和“组合”。

  1. Split: 这意味着基于数据中的一列创建单独的组。例如,我们可以将销售数据分成个月。

2.应用:这意味着我们对每个组执行一个功能。例如,我们可以合计每个月的销售额。

3.合并:这意味着我们返回一个新的数据表,包含“应用”阶段的每个结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

“groupby”的神奇之处在于它可以帮助你在非常紧凑的代码中完成所有这些步骤。

在熊猫中进行“分组”

为了获得每月的销售额,我们可以简单地运行以下命令:

sales_data.groupby('month').agg(sum)[['purchase_amount']]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

了解熊猫的“分裂”步骤

首先要指出的是,当我们运行上面的代码时,我们实际上是在运行两个不同的函数——groupby 和 agg——其中 group by 处理“拆分”阶段,agg 处理“应用”阶段。

例如,下面的代码实际上将我们的数据分成“月”组:

sales_data.groupby('month')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

虽然这个输出并不特别有趣,但是在到达聚合阶段之前,我们还可以对这个对象做一些事情:

  1. 查看“组”属性:
grouped = sales_data.groupby('month')
grouped.groups

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注意,“groups”属性返回一个字典,它的键是组,值是每个组的行索引。

2。使用“获取组”方法检查单个组:

grouped.get_group('August')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3。遍历每个组:

for name, group in grouped:
    print(name, group)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

了解熊猫的“agg”步骤

现在我们来探讨一下“agg”函数。

我们可以传递给“agg”的最简单的东西是我们想要在每个组上执行的聚合的名称:

sales_data.groupby('month').agg(sum)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请注意,这种方法将返回数据帧中所有可用数字列的总和。

但是,在本例中,返回“year”或“customer_id”列的总和没有任何意义。我们可以通过使用我们希望在 agg 调用结束时看到的列列表进行索引来解决这个问题:

sales_data.groupby('month').agg(sum)[['purchase_amount']]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们也可以用一个单独的列进行索引(与 list 相反):

sales_data.groupby('month').agg(sum)['purchase_amount']

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这种情况下,我们得到的是一个 Series 对象,而不是 DataFrame。我倾向于使用数据框架,所以我通常选择第一种方法。

高级“分组依据”概念

现在我们已经有了基本的东西,让我们来看看我们能做的一些更高级的事情。

多重聚合

首先,假设我们想要总销售额和每月平均销售额。为此,我们可以向“agg”传递一个函数列表:

sales_data.groupby(‘month’).agg(**[sum, np.mean]**)[‘purchase_amount’]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是有帮助的,但是现在我们被以聚合函数命名的列(即总和及平均值)。

当我们想要为多个列返回多个聚合时,这就变得更加困难了:

sales_data.groupby(‘month’).agg(**[sum, np.mean]**)[[‘purchase_amount’, 'year']]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这种情况下,我们坚持使用多索引作为列名:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为了解决这个问题,我们可以利用 Pandas 提供的“NamedAgg”对象。这里的语法有点不同,但是我们的输出非常清楚地表明了这里发生的事情:

sales_data.groupby(“month”).agg(
   total_sales=pd.NamedAgg(column=’purchase_amount’, aggfunc=sum),
   avg_sales=pd.NamedAgg(column=’purchase_amount’, aggfunc=np.mean),
   max_year=pd.NamedAgg(column=’year’, aggfunc=max))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是一种非常有用的机制,可以在不同的列上执行多种功能,同时保持对输出中列名的控制。

我们还可以向 agg 函数传递一个字典,但是这并没有给我们提供相同的灵活性来命名我们得到的列:

sales_data.groupby(“month”).agg(         {‘purchase_amount’: [sum, np.mean],
        ‘year’: [max]})

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

多列分组

我们可能想做的另一件事是按月份和州获取总销售额。

为了按多列分组,我们只需将一个列表传递给 group by 函数:

sales_data.groupby(["month", "state"]).agg(sum)[['purchase_amount']]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

您还会注意到我们的“分组关键字”——月份和州——已经成为我们的索引。通过运行“reset_index”函数,我们可以很容易地将它们转换成列:

g = sales_data.groupby([“month”, “state”]).agg(sum) g[[‘purchase_amount’].reset_index()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结束语

一旦你对“分割-应用-组合”方法有了坚实的直觉,在 Pandas 中运行“分组”就相当简单了。

尽管如此,当您第一次熟悉这些函数时,仍然可能会遇到语法问题。如果您面临错误,我建议您更仔细地查看您传递的数据类型。

例如,如果您正在运行类似于下面的代码,请确保您正在将一个函数列表的传递给 agg,并且您正在将一个列列表放置在另一组括号内以进行列索引:

sales_data.groupby(‘month’).agg(**[sum, np.mean]**)[**[‘purchase_amount’, ‘year’]**]

关于熊猫索引的快速回顾,请查看我下面的直观指南。编码快乐!

熊猫终极指南——重塑您的数据

原文:https://towardsdatascience.com/ultimate-pandas-guide-reshaping-your-data-75bc40ab05c4?source=collection_archive---------41-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

劳拉·伍德伯里摄于佩克斯

通过掌握“pivot_table”和“melt”来控制您的数据

概括地说,数据可以用两种形状来组织——长型或宽型。

例如,我们可以用两种方式表示总统选举结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当我们的数据很长时,这意味着每条记录代表我们测量的变量的一个实例。在上面的例子中,每个记录都有候选人、州和他们收到的票数。

当我们的数据很宽时,这意味着我们测量的变量是跨行和列分布的。在上面的例子中,每条记录是一个州,我们有为每个候选人投票的列。

Pandas 最有用的功能之一是能够快速轻松地重塑数据。

在这篇文章中,我将介绍如何毫不费力地在各种形状之间转换,以最好地满足您的分析需求。

为什么我们需要不同的形状?

最终,“正确”的形状将总是取决于用例。不同的场景需要不同的形状——这就是为什么我们需要在它们之间切换的功能。

比方说,我们的选举数据有一个“长”形:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果我们想建立一个模型来预测希拉里·克林顿获得总票数的百分比,这种形状是行不通的。为了创建州级预测模型,我们需要州级数据。

另一方面,如果我们想使用 seaborn 可视化软件包绘制一个条形图,我们将需要长格式。这并不是因为任何高度技术性的原因,只是因为 seaborn barplot 方法期望数据是这种格式。

长到宽—“数据透视表”

“pivot_table”方法是一种将数据形状从长变宽的简单方法。

这是一个 DataFrame 方法,因此它会被您想要整形的 DataFrame 调用:

data.pivot_table()

有四个主要参数要传递给此方法:

  1. Index :我们希望在输出表中用作索引的列的名称
  2. :其唯一值将成为输出表中的列的列名
  3. :我们想要聚合的列的名称
  4. Aggfunc :我们要使用的聚合函数的名称

为了让这一点变得生动,下面是一个使用“pivot_table”方法将数据从长变宽的例子:

long_data.pivot_table(index = ‘state’, columns= ‘candidate’,
 values = ‘candidatevotes’, aggfunc = ‘sum’)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注意,如果我们的索引/列对有重复的值,那么只需要传递“values”和“aggfunc”参数。

换句话说,如果我们有希拉里·克林顿在阿拉巴马州的两个计票记录,我们将希望传递“values”和“aggfunc ”,以便告诉该方法如何处理这些重复的记录(即将它们相加、平均等等。).

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

默认方法是使用 np.mean 函数。这可能导致**潜在的陷阱,**因为我们不总是想要在上面的例子中取平均值。为了避免问题,您应该确保知道您的数据中是否有重复项。

还有另一种方法——“pivot”——类似于 pivot_table。

但是,“pivot”不允许您拥有副本。如果我们尝试使用“pivot ”,并且我们有两个阿拉巴马州希拉里·克林顿的记录,此方法将返回 ValueError:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因为“pivot”限制性更强,所以我建议在需要从 long 转换到 wide 时,只需使用“pivot_table”即可。

从宽到长—“融化”

Melt 是我在 Pandas 中最喜欢的方法之一,因为它提供了“反透视”功能,这比它的 SQL 或 excel 等价物要简单得多。

与我们的“pivot_table”方法类似,我们将使用几个主要参数来取消数据透视:

  1. id_vars :您希望在输出中保持不变的列的名称
  2. value_vars: 要在输出中折叠成单个分类列的列名
  3. var_name: 输出表中 value_vars 的列名。
  4. value_name :输出表中值的列名。

下面是一个使用我们的选举数据的例子:

wide_data.melt(id_vars = 'state', 
            value_vars = ['Clinton, Hillary','Johnson, Gary','Stein, Jill','Trump, Donald J.'],
            var_name = 'candidate',
            value_name = 'candidatevotes')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请注意,默认情况下,该方法会将“value_vars”参数设置为表中不在“id_vars”中的列的完整列表。因此,如果我们确实想使用所有这些列,从技术上讲,我们不需要向“value_vars”传递任何东西。

另一方面,通过在“value_vars”参数中仅包含一个候选项,很容易获得该候选项的数据:

wide_data.melt(id_vars = 'state', 
            value_vars = ['Clinton, Hillary'],
            var_name = 'candidate',
            value_name = 'candidatevotes')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在帖子的开头,我提到了 seaborn 函数,barplot 要求我们的数据是长格式的。

如果你感到好奇,下面的代码可以比较佛罗里达州和德克萨斯州候选人的投票结果:

sns.barplot(x=”candidate”, y=”candidatevotes”, hue=”state”, data=long_data[long_data.state.isin([‘Texas’, ‘Florida’])])

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

同样,请注意,如果我们的数据是宽格式的,这是行不通的,因为我们没有一个单独的数字列传递给“y”参数。

结束语

与 SQL 或 Excel 等其他分析工具相比,Pandas 在重塑数据方面更胜一筹。

通过两个简单的函数 pivot _ table 和 melt 您可以有效地重塑您的数据,以帮助促进分析管道中接下来的连接、可视化或模型训练。编码快乐!

终极熊猫指南:时间序列窗口函数

原文:https://towardsdatascience.com/ultimate-pandas-guide-time-series-window-functions-a5362b782f3e?source=collection_archive---------19-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

劳拉·伍德伯里摄于佩克斯

掌握时间序列分析的“移位”、“滚动”和“扩展”

在我的上一篇文章中,我演示了如何基于列值在 Pandas 中运行窗口函数。

这种方法在我们想要知道关于单个记录 和它们所属的 组的信息时非常有用。

例如,如果我们有客户级别的交易数据,像这样的方法可以为我们提供关于每笔交易的信息,以及交易发生当月的总销售额:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在本文中,我将介绍另一种类型的窗口函数——我们根据行的位置而不是分类列的值来执行计算。

关于数据的注释

对于我下面的例子,我将使用来自 Kaggle 上的 NCAA 大联盟比赛的一些游戏级别的篮球数据。

如果你不喜欢篮球,不要害怕。

这里有一个快速数据字典,告诉你所有你需要知道的变量:

  1. DayNum: 我们对时间的度量。它计算游戏进行到赛季的第几天。
  2. 游戏发生的年份。
  3. Team1/Team2: 参赛队伍的 id。
  4. **效率:**衡量团队 1 在游戏中的表现。
  5. **结果:**团队 1 是否赢得比赛的标志(1 表示赢,0 表示输)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后,让我们假设我们的目标是预测谁赢得了每场比赛。我们不会在这里做任何机器学习,但这将有助于激发用例。

创建“移位”列

让我们从做一个简单的“转移”开始。

这个方法确实像它听起来那样。它将一列中的值向前或向后移动。

下面我们将游戏效率提高 1:

game_data[‘prior_game_outcome’] = game_data[‘Outcome’].shift(1)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在,对于每场比赛,我们都知道团队 1 在前一场比赛中表现如何。也许这能帮助我们预测结果。

请注意,我们可以传递正整数或负整数来向前或向后移动:

game_data['NextEfficiency'] = game_data['GameEfficiency'].shift(-1)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

还要记住,当我们对第一行进行正移位时,我们会得到一个空值,因为前一行中没有可用的数据。我们可以通过设置“fill_value”参数用我们选择的不同值替换空值来解决这个问题。

在滚动窗口上执行聚合

虽然 shift 方法很有用,但它不允许我们对之前或未来的行执行任何功能。

例如,我们可能想要找出团队 1 在前三场比赛中的平均效率。

这是我们可以利用滚动方法的地方。

基本语法非常简单——我们只需要传递我们想要查看的先前行数,然后执行聚合:

game_data[‘AvgEfficiency’] = game_data[‘GameEfficiency’].rolling(3).mean()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请注意,这里有两个技术步骤:“rolling”方法创建一个滚动对象,然后“mean”方法返回新列。

我们可能想在这里再做一次调整。默认情况下,每个记录都包含在自己的窗口平均值中。如果我们想预测每场比赛,这是不好的,因为这意味着我们有关于结果的信息编码在平均值中。

为了解决这个问题,我们可以添加一个移位函数,以便包含前 3 行的数据(而不是当前行和前 2 行):

game_data[‘AvgEfficiency’] = game_data[‘GameEfficiency’].shift(1).rolling(3).mean()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在扩展窗口上执行聚合

扩展方法与滚动方法非常相似,只是它会根据给定的数据创建尽可能大的窗口。

这里有一个例子:

game_data[‘AvgEfficiency’] = game_data[‘GameEfficiency’].shift(1).expanding().mean()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请注意,倒数第二行中的 AvgEfficiency 值与我们运行上面的滚动方法(12.02)时相同,但最后几行不同(2.41 对 13.46)。

这是因为当我们在倒数第二行时,我们只有 3 个先前的记录可用,但是当我们到达最后一行时,我们有 4 个先前的记录。同样,扩展方法使用尽可能多的数据。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后,如果我们希望确保扩展窗口至少有一定数量的记录,以便应用聚合,我们可以使用“min_periods”参数:

game_data[‘AvgEfficiency’] = game_data[‘GameEfficiency’].shift(1) .expanding(min_periods = 4).mean()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

将所有这些放在一起:一个高级用例

我们从区分基于列的窗口和基于位置的窗口开始这篇文章。

我们的最终用例利用了这两者。

以上所有工作的问题是:我们的数据集中实际上有多个球队和赛季,所以我们在分类数据的边缘遇到了问题:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为了解决这个问题,我们需要将我们的数据分成团队/赛季组 执行扩展窗口聚合:

game_data[‘AvgEfficiency’] = game_data.groupby([‘Season’, ‘Team1’])[[‘GameEfficiency’]].transform(lambda x: x.shift(1).expanding().mean())

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我们的扩展平均计算开始为每个队的时间表新鲜!

上面的代码中有很多内容,但我是这样想的:

  1. 首先,我们将数据分成季节组和团队组 1
  2. 然后,我们将一个定制的匿名函数(λ)应用到每一组,该函数会移动数据并计算一个扩展平均值
  3. 最后,我们将这些值返回到原始索引

结束语

在这篇文章中,我们浏览了熊猫的时间序列窗口函数。其中一些方法的语法可能有点复杂,但是当你把它分解成更小的步骤时,一切都会变得更加清晰。花些时间尝试每种方法,直到你掌握了窍门,这也没有坏处。编码快乐!

熊猫终极指南——窗口功能

原文:https://towardsdatascience.com/ultimate-pandas-guide-window-functions-f527f64fd550?source=collection_archive---------25-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

劳拉·伍德伯里摄于佩克斯

掌握您对数据中的组的理解

窗口函数是一种有效的方法,可以更好地了解数据中的每条记录与其所属的组之间的关系。

它们也是常见的数据科学面试问题,因此很好地理解它们是件好事。

在这篇文章中,我将对窗口函数以及如何在 Pandas 中实现它们进行直观的解释。

了解窗口功能

在标准的“分组”中,我们将数据分成组,应用聚合,然后将每个结果合并到一个新表中。

这有助于我们回答关于数据中群体特征的问题。

例如,如果我们有每月客户级别的销售数据,我们可以使用 groupby 来了解我们每月的总销售额:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你对这个功能有点生疏,我建议你看看我在 groupby 函数上的帖子:

[## 熊猫终极指南——驾驭群体

数据分析中最常见的练习之一是将数据分组并执行聚合。

towardsdatascience.com](/ultimate-pandas-guide-mastering-the-groupby-104306251739)

如果我们只关心月销售额,上面的输出是有用的。

但是这个结果的缺点是,我们的信息现在分布在两个表中——第一个表给出销售明细,第二个表给出每个月的汇总信息。

窗口函数通过将组级别的聚合返回到初始表来帮助我们弥合这一差距:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果不清楚这为什么有用,让我们在输出中添加一个百分比列:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我们可以看到每个记录占每月总销售额的百分比。

窗口函数很有用,因为它帮助我们运行这些类型的计算,而不必执行任何单独的连接。

使用变换方法的 pandas 中的窗口函数

Pandas 中窗口函数的语法非常简单,非常类似于我们在 groupby 聚合中使用的语法。

关键区别在于,要执行窗口功能,我们使用“transform”方法,而不是“agg”方法:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

transform 方法返回一个序列而不是一个数据帧,所以如果我们希望它成为原始数据帧的一部分,我们需要将它作为一列添加:

sales_data[“monthly_sales”] = sales_data.groupby(“month”).transform(
sum)[“purchase_amount”]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

就是这样!不算太坏。

让我们再举一个例子。下面我们按州对每笔交易进行排名:

sales_data['state_rank'] = sales_data.sort_values(by =                   'purchase_amount', ascending = False).groupby("state")
.transform('rank', method = 'min')["purchase_amount"]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请注意以下几点:

  1. 我们使用“sort_values”函数来确保我们按照购买金额的顺序进行排序。
  2. 我们将一个参数(“min”)传递给转换中的“method”参数。这是 rank 方法的一个参数,在执行时传递给它。
  3. 当我们想要返回组内的“顶部”值时,这种类型的分析往往很有用。例如,我们可以筛选每个州内前 2 笔交易的结果,然后将这些结果传递给覆盖每个州的销售代表。

Pandas 中的窗口函数与 SQL

对于那些有很强 SQL 背景的人来说,这个语法可能有点奇怪。

在 SQL 中,我们通过从聚合开始执行窗口函数,然后将它应用于可选的“partition by”和“order by”之上:

select rank() over (partition by state order by purchase_amount desc)

为了帮助协调这两种方法,我将上面的 Pandas 代码的元素转换成它们的 SQL 等价物:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结束语

在 Pandas 中,窗口函数功能强大、高效,并且实现起来相当简单。

但是,值得注意的是,“transform”方法并不是执行基于位置的聚合的正确方法,比如对前 5 条记录的列值求和。为了解决这个问题,我们将在以后的文章中更深入地研究熊猫的“转变”和“扩展”功能。

[## 终极熊猫指南:时间序列窗口函数

掌握时间序列分析的“移位”、“滚动”和“扩展”

towardsdatascience.com](/ultimate-pandas-guide-time-series-window-functions-a5362b782f3e)

编码快乐!

终极 PySpark 备忘单

原文:https://towardsdatascience.com/ultimate-pyspark-cheat-sheet-7d3938d13421?source=collection_archive---------5-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由Genessa pana intetUnsplash 拍摄

数据科学

PySpark 数据帧 API 的简短指南

S park 是当今数据工程、数据科学领域的主要参与者之一。随着处理更多数据的需求不断增加,企业经常将 Spark 集成到数据堆栈中,以解决快速处理大量数据的问题。由 Apache 维护,Spark 生态系统中的主要商业参与者是 Databricks(由 Spark 的最初创建者所有)。Spark 已经被各种公司和机构广泛接受——本地的和云中的。一些最受欢迎的底层使用 Spark 的云产品有 AWS GlueGoogle DataprocAzure Databricks

没有一种技术,没有一种编程语言对所有用例都足够好。Spark 是用于解决大规模数据分析和 ETL 问题的众多技术之一。在 Spark 上工作了一段时间后,我想到用真实的例子来编写一份备忘单。尽管有很多关于在 Scala 中使用 Spark 的参考资料,但除了 Datacamp 上的之外,我找不到一个像样的备忘单,但我认为它需要更新,需要比一页纸更广泛一点。

首先,一个关于 Spark 如何工作的体面介绍—

[## 这就是 Spark 运行应用程序的方式

回想一下之前的 Spark 101 博客,您的 Spark 应用程序是作为一组并行任务运行的。在这篇博文中…

mapr.com](https://mapr.com/blog/how-spark-runs-your-applications/)

配置和初始化

在开始编写哪几行代码来启动和运行 PySpark 笔记本/应用程序之前,您应该了解一点关于SparkContextSparkSessionSQLContext的知识。

  • SparkContext —提供与 Spark 的连接,能够创建 rdd
  • SQLContext —提供与 Spark 的连接,能够对数据运行 SQL 查询
  • SparkSession —包罗万象的上下文,包括对SparkContextSQLContextHiveContext的覆盖。

我们将在一些例子中使用 MovieLens 数据库。这是那个数据库的链接。你可以从 Kaggle 下载。

[## 电影数据集

超过 45,000 部电影的元数据。超过 270,000 名用户的 2,600 万次评分。

www.kaggle.com](https://www.kaggle.com/rounakbanik/the-movies-dataset)

读取数据

Spark 支持从各种数据源读取数据,比如 CSV、Text、Parquet、Avro、JSON。它还支持从 Hive 和任何具有可用 JDBC 通道的数据库中读取数据。以下是如何在 Spark 中阅读 CSV 的方法—

在您的 Spark 之旅中,您会发现有许多方法可以编写相同的代码来获得相同的结果。许多函数都有别名(例如dropDuplicatesdrop_duplicates)。下面的例子展示了在 Spark 中读取文件的几种方法。

写入数据

一旦你完成了数据转换,你会想把它写在某种持久存储上。这里有一个例子,展示了将一个拼花文件写入磁盘的两种不同方式—

显然,基于您的消费模式和需求,您也可以使用类似的命令将其他文件格式写入磁盘。写入 Hive 表时,可以用bucketBy代替partitionBy

[## Pyspark 中使用分桶的 5 分钟指南

世界上有许多不同的工具,每一种都可以解决一系列问题。他们中的许多人是如何判断…

luminousmen.com](https://luminousmen.com/post/the-5-minute-guide-to-using-bucketing-in-pyspark)

bucketBypartitionBy背后的思想都是拒绝不需要查询的数据,即修剪分区。这是一个来自传统关系数据库分区的老概念。

创建数据框架

除了您在上面的读取数据部分看到的直接方法df = spark.read.csv(csv_file_path)之外,还有一种创建数据帧的方法,那就是使用 SparkSQL 的行构造。

还有一个选项,您可以使用 Spark 的.paralellize.textFile特性将文件表示为 RDD。要将其转换成数据帧,显然需要指定一个模式。这就是pyspark.sql.types出现的原因。

我们将在 PySpark 中使用大量类似 SQL 的功能,请花几分钟时间熟悉下面的文档

修改数据帧

数据帧抽象出 rdd。数据集做同样的事情,但是数据集没有表格、关系数据库表那样的 rdd 表示。数据帧有。因此,DataFrames 支持类似于您通常在数据库表上执行的操作,即通过添加、删除、修改列来更改表结构。Spark 提供了 DataFrames API 中的所有功能。事情是这样的—

除了创建新列之外,我们还可以使用以下方法重命名现有的列

如果我们必须删除一列或多列,我们可以这样做—

连接

Spark 使用类似 SQL 的接口背后的整个想法是,有许多数据可以用一个松散的关系模型来表示,即一个没有 ACID、完整性检查等的表模型。考虑到这一点,我们可以预期会发生很多连接。Spark 完全支持连接两个或多个数据集。这里是如何—

过滤

过滤器就像 SQL 中的子句一样。事实上,你可以在 Spark 中互换使用filterwhere。下面是一个在 MovieLens 数据库电影元数据文件中过滤分级在 7.5 和 8.2 之间的电影的示例。

过滤器支持所有类似 SQL 的特性,例如使用比较运算符、正则表达式和按位运算符进行过滤。

过滤掉空值和非空值是查询中最常见的用例之一。Spark 对列对象提供了简单的isNULLisNotNull操作。

聚集

聚合是处理大规模数据的巨大工作的核心,因为这通常归结为 BI 仪表板和 ML,这两者都需要某种聚合。使用 SparkSQL 库,您几乎可以实现在传统关系数据库或数据仓库查询引擎中所能实现的一切。这里有一个例子展示了 Spark 是如何进行聚合的。

窗口功能和排序

与大多数分析引擎一样,窗口函数已经成为rankdense_rank等的标准。,被大量使用。Spark 利用传统的基于 SQL 的窗口函数语法rank() over (partition by something order by something_else desc)

请注意sortorderBy在 Spark 中可以互换使用,除非是在窗口函数中。

这些是我收集的一些例子。很明显,除了一张小抄,还有很多东西值得一试。如果您感兴趣或者在这里没有找到任何有用的东西,可以去看看文档——它相当不错。

下一个 Python 项目的最终设置

原文:https://towardsdatascience.com/ultimate-setup-for-your-next-python-project-179bda8a7c2c?source=collection_archive---------0-----------------------

从零开始任何项目都可能是一项艰巨的任务…但如果你有这个终极的 Python 项目蓝图就不会了!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Unsplash 上 @sxoxm 的原图

无论您是在从事一些机器学习/人工智能项目,在 Flask 中构建 web 应用程序,还是只是编写一些快速的 Python 脚本,为您的项目提供一些满足您所有需求的模板总是有用的,即:预定义的目录结构,所有必要的配置文件,如pytest.inirequirements.txt,测试,林挺和静态代码分析设置,CI/CD 工具,应用程序的 dockering,以及在自动化之上使用 Makefile 。因此,在这里,我为您带来的正是这个*“终极”通用 Python 项目设置*。

TL;博士:这是我的储存库,里面有完整的源代码和文档:【https://github.com/MartinHeinz/python-project-blueprint】T21

目录结构

当我为 Golang ( 此处为)写这类文章时,我很难用 Python 弄清楚理想的项目结构,不过,这很简单:

让我们从顶部开始,概述一下我们这里有什么:

  • blueprint -这是我们的源代码目录,应该根据你正在使用的应用程序或软件包来命名。在里面,我们有通常的__init__.py文件,表明它是一个 Python 包,接下来是__main__.py,当我们想用python -m blueprint直接运行我们的应用程序时会用到它。这里的最后一个源文件是app.py,这里只是为了演示。在真实的项目中,你会有更少的顶级源文件和更多的目录(内部包),而不是这个app.py。稍后我们将讨论这些文件的内容。最后,我们这里还有resources目录,用于您的应用程序可能需要的任何静态内容,例如图像、密钥库等。
  • 这个目录中存放着我们的测试套件。我不会在这里讲太多的细节,因为我们将把整个部分用于测试,但只是简单地说:
  1. test_app.py是源目录中app.py对应的测试文件
  2. 如果你曾经使用过 Pytest ,那么conftest.py可能对你来说很熟悉——这是一个用于指定 Pytest fixtures ,钩子或者加载外部插件的文件。
  3. context.py通过操纵类路径,帮助从blueprint目录导入源代码文件。我们将在稍后看到它是如何工作的。
  • 这是我们在这个项目中的最后一个目录。它保存了我们用于 CI/CD 的 GitHub 动作的配置。我们有两个文件,第一个- build-test.yml负责构建、测试和林挺我们每次推送的源代码。第二个文件- push.yml在每次我们在 GitHub 上创建标签/发布时,将我们构建的应用程序推送到 GitHub 包注册表。在另一篇博客文章中有更多关于这方面的内容。
  • Makefile -除了目录之外,我们的项目中还有一些顶级文件,其中第一个——Makefile包含目标,帮助我们自动化通常执行的任务,如构建、测试、林挺或清理我们的项目
  • 这是一个方便的脚本,为你建立一个项目。它实际上重命名并替换了这个项目模板中的虚拟值来代替真实值,比如项目名或包名。很方便,对吧?

这里的其余文件是我们将在这个项目中使用的所有工具的配置文件。让我们跳到下一部分,探索它们的功能和内容。

配置文件

在设置 Python 项目时,有一件事可能会变得相当混乱,那就是当你使用一堆工具时,你最终会得到的配置文件汤,比如 pylintcoverage.pyflake8 等等。这些工具中的每一个都希望有自己的文件,通常是像.flake8.coveragerc这样的文件,这会在你的项目的根目录中产生许多不必要的混乱。为了避免这种情况,我将所有这些文件合并成一个文件- setup.cfg:

如果您不熟悉这里使用的所有工具,我将快速描述一下:

  • flake 8——是一个在你的项目中强制代码风格的工具——换句话说——它是类似于 pylint 的 linter,我们也将使用它。为什么两个都用?它们确实有重叠,但是它们都有一些规则,而另一个没有,所以以我的经验来看,它们都值得使用。
  • Bandit —是一个在 Python 代码中寻找常见安全问题的工具。它的工作原理是从你的代码中创建 AST(抽象语法树),并针对其节点运行插件。开发人员通常不是安全专家,而且我们所有人都会犯这样或那样的错误,所以有一个工具能够为我们发现至少一些安全错误总是很好的。
  • Coverage.py —是一个测量 Python 程序代码覆盖率的工具。当我们用 Pytest 运行测试套件并从测试运行中生成覆盖率报告时,它被触发。这些报告可以是终端输出的形式,也可以是 XML 格式,然后可以被 CI 工具使用。

说完这些,让我们来回顾一下setup.cfg中的内容。对于 Flake8 我们定义了排除模式,这样我们就不会忽略我们不关心的代码。下面是一个空的ignore部分,以防我们需要全局忽略一些规则。我们还将最大线长度设置为 120,因为在我看来,对于今天的屏幕尺寸来说,将线长度保持为 80 是不合理的。Final line 将 McCabe 复杂度阈值设置为 10,如果你不熟悉圈复杂度你可以在这里找到更多

接下来是 Bandit ,我们在这里配置的只是目标目录,这是我们的包的名称。我们这样做是为了避免在命令行上指定目标。

之后是 Coverage.py 。首先,我们启用分支覆盖,这意味着在程序中的一行可能会跳转到多个下一行的地方, Coverage.py 会跟踪实际访问了那些目的行中的哪些。接下来,我们省略了一些不应该或者不能包含在覆盖率测量中的文件,比如测试本身或者虚拟环境文件。我们也排除特定的行,例如标有pragma: no cover注释的行。最后一个 Coverage.py 配置行告诉工具将生成的报告存储在reports目录中。如果该目录不存在,将自动创建。

我们需要配置的最后一个工具是 Pylint ,不过这个配置非常广泛,大概有 100 多行……所以,我就不写这个了,在这里给你指出源代码以及在 Pylint 仓库这里的注释和解释pylintrc

我们检查了setup.cfg中的所有工具,但是还有一个工具不能添加到setup.cfg中,那就是Pytest——尽管 Pytest 医生告诉你可以使用setup.cfg,但这并不完全正确…根据本期,使用setup.cfg的选项已被否决,并且存在一些错误,如插值错误,这些错误不会被修复,因此我们还需要pytest.ini文件来配置 Pytest :

我们在这里做的第一件事是设置一组命令行参数——我们在终端输出中启用颜色,然后我们为blueprint目录启用覆盖报告,之后我们启用 XML 和 stdout ( term)覆盖报告的生成。最后两个参数(-ra)告诉 Pytest 输出未通过测试的简短摘要。

在下一行,我们有filterwarnings选项,它允许我们禁用输出中一些烦人的警告,例如,来自我们无法控制的某个库的不赞成警告。

配置的其余部分设置日志记录。第一个只是打开它,其他 3 个配置级别,格式和日期时间格式。比解释格式配置更容易的是查看输出本身,这将在下一节中显示。

有了pytest.ini中的所有配置,我们运行测试套件所需要做的就是运行pytest,甚至不需要包参数!

我们拥有的最后一个实际配置文件是requirement.txt,它包含了我们的依赖项列表。在这个文件中你能找到的就是一个 Python 包的列表,每行一个可选版本的包。如上所述,包版本是可选的,但是我强烈建议您在requirements.txt中锁定版本,以避免在构建和部署期间下载更新的、不兼容的包,并最终破坏您的应用程序。

还有两个文件实际上不是配置文件——我们的docker 文件,即dev.Dockerfileprod.Dockerfile,分别用于开发和生产映像。我将暂时不讨论这些内容,因为我们将在另一篇文章中探讨这些内容,在那篇文章中,我们将讨论 CI/CD 和部署。但是,您可以在这里的 GitHub 存储库中查看这些文件-https://GitHub . com/Martin Heinz/python-project-blue print/blob/master/dev。文档文件

实际源代码

我们已经做了很多,甚至没有提到我们的应用程序的源代码,但是我认为是时候看看项目框架中的几行代码了:

这个蓝图中唯一实际的源代码就是这个带有静态方法的类。这真的是不需要的,这样我们就可以运行一些东西,得到一些输出并测试它。这也是整个应用程序的入口点。在实际项目中,您可以使用run()方法来初始化您的应用程序或 web 服务器。

那么,我们实际上如何运行这段代码呢?

在一个特别命名的文件__main__.py中的这一小段是我们在项目中需要的,这样我们就可以使用python -m blueprint运行整个包。这个文件和它的内容的好处是,它将只用那个命令运行,因此,如果我们想从这个包的源代码导入一些东西而不运行整个东西,那么我们可以这样做而不触发Blueprint.run()

我们的包中还有一个特殊的文件,那就是__init__.py文件。通常,你会让它为空,只用来告诉 Python 这个目录是一个包。然而,在这里,我们将使用它从我们的包中导出类、变量和函数。

如果没有上面的这一行,你将无法从这个包的外部调用Blueprint.run()。这样我们可以避免人们使用我们代码中不应该公开的内部部分。

这就是我们软件包的全部代码,但是测试呢?首先,我们来看看context.py

通常当你使用某人的包时,你像import blueprintfrom blueprint import Blueprint一样导入它,为了在我们的测试中模仿它,因此使它尽可能接近真实使用,我们使用context.py文件将包导入到我们的测试环境中。我们还将项目根目录插入到系统路径中。当用pytest运行测试时,这实际上是不必要的,但是如果你用python ./tests/context.py直接运行context.py,或者可能用unittest而不包括sys.path.insert...,那么你将得到ModuleNotFoundError: No module named 'blueprint',所以这一行有点像保险单

现在,让我们来看看测试示例:

我们这里有一个简单的测试,它使用内置的 Pytest 夹具capsys(捕获系统输出)来检查Blueprint.run()的标准输出。那么,当我们运行测试套件时会发生什么呢?

我从输出中删除了几行,这样您可以更好地看到相关的部分。这里有什么要注意的?嗯,我们的测试通过了!除此之外,我们还可以看到覆盖率报告,我们还可以看到该报告按照pytest.ini中的配置写入coverage.xml。输出中还有一件事是来自conftest.py的 2 条日志消息。这是怎么回事?

您可能已经注意到,除了capsys夹具,我们还在小测试的参数中使用了example_fixture。该夹具驻留在conftest.py中,我们制作的所有定制夹具也应如此:

顾名思义,这真的只是一个示例设备。它所做的只是记录一条消息,然后让测试运行,最后再记录一条消息。关于conftest.py文件的好处是它被 Pytest 自动发现,所以你甚至不需要将它导入到你的测试文件中。如果你想了解更多,那么你可以看看我以前关于Pytest这里或者 docs 这里的帖子。

一个命令搞定一切

如果我们分别运行我们的每个工具,并且必须记住它们的参数,即使它们总是相同的,这将是非常费力的。同样,如果后来我们决定将所有这些工具放入 CI/CD(下一篇文章!),对吧?所以,让我们用Makefile来简化事情:

在这个Makefile中,我们有 4 个目标。首先,- run使用我们在源文件夹的根目录下创建的__main__.py运行我们的应用程序。接下来,test只是运行pytest。感谢pytest.ini中的所有配置,就是这么简单。这里最长的目标- lint -运行我们所有的林挺工具。首先,它对项目中的所有.py文件运行pylint,包括测试文件。之后,它运行flake8并最终运行bandit。对于这两个,它只针对blueprint目录中的源运行。如果这些工具中的任何一个发现我们的代码有问题,它会以非零代码退出,这意味着目标会失败,这在 CI/CD 中很有用。该文件中的最后一个目标是clean,哪口井…清理我们的项目——它删除所有由前面提到的工具生成的文件。

结论

在本文中,我们已经构建了 project skeleton,它可以用于您可能正在从事或正在考虑的任何类型的 Python 项目,因此,如果您想尝试或更深入地挖掘,请查看我的资源库中的源代码:【https://github.com/MartinHeinz/python-project-blueprint】。Repo 还包括关于如何使用方便的脚本设置您的项目的信息,以及一些更多的文档。如果你喜欢这种内容,请随时以问题的形式留下反馈/建议,或者直接开始。🙂

在未来,我们会考虑将 CI/CD 加入到 GitHub 动作GitHub 包注册表的组合中。我们还将对我们的项目进行 Docker 化,创建可调试和优化的生产就绪 Docker 映像,并使用 CodeClimateSonarCloud 添加更多代码质量工具。

资源

本文最初发布于martinheinz . dev

机器学习算法的最终对决

原文:https://towardsdatascience.com/ultimate-showdown-of-machine-learning-algorithms-af68fbb90b06?source=collection_archive---------45-----------------------

有线电视新闻网、移动网络、KNN、兰登森林和 MLP。哪种算法最好?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Jaime Spaniol 在 Unsplash 上拍摄的照片

故事

gif 由 Giphy

这一切都是从我年轻的表弟开始的,他迷失在自己的世界里,在他的画本上涂鸦。我问他在做什么。他回答说他正在做一只猫;它看起来一点也不像猫。他让我和他一起玩一个游戏,在这个游戏中,我可以认出他在画什么。有一段时间很有趣,但很快,我就厌倦了。我不想因为不和他玩而伤害他的感情,所以我用我的计算机视觉和 python 技巧做了一个涂鸦分类器。现在的问题是我将如何实现它;对涂鸦进行分类的方法有数百种,我必须选择最准确的一种,它需要最少的训练时间,占用更少的内存,需要更少的处理能力,并且不需要 TB 的数据来给出有意义的结果。

在网上冲浪后,我找到了能以最佳方式完成这项任务的前 5 种算法,但我访问的每个网站都讲述了不同的故事。有人说 CNN 是最好的,有人说移动网络是最好的。我想——好吧,让我们全部测试一下。我发现了一个很棒的数据集,其中包含了很多涂鸦,它们的标签都在一个 Kaggle 竞赛中,可以免费下载。

图像分类是一个庞大的主题,因为有大量的算法可用于各种应用。图像分类是如此庞大和不断变化,以至于每天都有新的算法被创造出来,新的应用程序不断涌现。因此,对我来说,挑选几个算法是很困难的,因为它们有数百种变化。因此,这篇文章将专门研究哪种算法对涂鸦分类效果最好。

我还将测试这些算法在其他情况下的可靠性,如手写字符分类、车牌识别等。

涵盖哪些内容

  1. 研究中使用的 ML 技术简介
  2. 评估指标
  3. 为研究选择的参数详情
  4. 结果
  5. 局限性和结论

让我们先简单介绍一下所使用的机器学习算法

gif by Giphy

涂鸦分类的算法有成千上万种,这里我列出了几个著名的算法,我将探索它们

1)随机森林

我们可以使用随机森林算法进行分类和回归。它就像决策树,只不过它使用数百棵决策树来得出一个结论。决策树根据相似的特征将数据分成不同的类别。对于每个数据点,它检查它是否具有某个特征,最常见的数据属于同一类。在随机森林算法中,我们采用许多决策树,并随机给它们较少的特征来检查,例如,如果我们有 100 个特征,我们可能给每棵树 10 个随机特征。一些树会分配不正确的类,但许多将是正确的!我们取大多数并创建我们的分类模型。

随机森林算法研究论文;

利奥·布雷曼

饶彤彤关于随机森林算法的一篇很棒的文章:

[## 了解随机森林

该算法如何工作以及为什么如此有效

towardsdatascience.com](/understanding-random-forest-58381e0602d2)

2) KNN

k-最近邻(KNN)既可用作分类算法,也可用作回归算法。在 KNN 中,数据点被分成几类以预测新样本点的分类。为了实现这一任务,它使用距离公式来计算各种数据点之间的距离,基于该距离,它然后为每个类定义区域边界。任何新的数据点都将落入这些区域中的一个,并将被分配到该类别。

关于 KNN 的研究论文:

功德果

雷努·汉德尔瓦尔的一篇关于 KNN 的精彩文章:

[## k-最近邻(KNN)

在这篇文章中,我们将了解什么是 K-最近邻,这个算法是如何工作的,有什么好处和…

medium.com](https://medium.com/datadriveninvestor/k-nearest-neighbors-knn-7b4bd0128da7)

3) MLP

多层感知(MLP)是一种前馈人工神经网络。MLP 有许多层,但在其隐藏层只有一个逻辑函数,在输出层只有一个 softmax 函数。该算法将单个大向量作为输入,并在输入层和隐藏层上执行矩阵运算,然后结果通过逻辑函数,其输出通过另一个隐藏层。重复此过程,直到网络到达输出层,在输出层使用 softmax 函数产生单个输出。

关于 MLP 的研究论文:

波佩斯库·马里乌斯

Jorge Leonel 的一篇关于 MLP 的精彩文章:

[## 多层感知器

我们在这里已经看到感知器,这个神经网络的名字唤起了人们对未来的看法…

medium.com](https://medium.com/@jorgesleonel/multilayer-perceptron-6c5db6a8dfa3)

4) CNN

卷积神经网络(CNN)是最容易实现深度学习的计算机视觉算法之一。首先,它采用给定大小的输入图像,并为其创建多个滤波器/特征检测器(最初是给定大小的随机生成的矩阵),滤波器旨在识别图像中的某些模式,滤波器在图像上移动,矩阵和图像之间进行矩阵乘法。该滤波器在整个图像中滑动以收集更多特征,然后我们使用激活函数(通常是校正的线性单位函数)来增加非线性或仅保留重要特征,然后我们使用 max-pooling 函数将给定矩阵大小中的所有值相加(例如,如果我们选择 4 个矩阵,则它将所有 4 个值相加以创建 1 个值),从而减小输出的大小以使其更快。最后一步是展平最终矩阵,该矩阵作为输入传递给基本 ANN(人工神经网络)并获得类别预测。

CNN 的研究论文:

凯龙·泰洛·奥谢

纳格什·辛格·肖汉在 CNN 上发表的一篇精彩文章:

[## 卷积神经网络(CNN)简介

本文重点介绍与 CNN 相关的所有概念及其使用 Keras python 库的实现。

levelup.gitconnected.com](https://levelup.gitconnected.com/introduction-to-convolutional-neural-networks-cnn-1ee504bc20c3)

5)移动网络

移动网络架构使用深度方向可分离卷积,其包括深度方向卷积和点方向卷积。深度方向卷积是通道方向 Dk * Dk 空间卷积,假设我们在图像中有 3 个通道(R,G,B ),那么我们将有 3DkDk 空间卷积。在逐点卷积中,我们的内核大小为 11M,其中 M 是深度卷积中的通道数,在本例中为 3。因此,我们有一个大小为 113 的内核;我们通过我们的 3DkDk 输出迭代这个内核,得到 DkDk1 输出。我们可以创建 N 个 113 内核,每个内核输出一个 DkDk1 图像,以获得形状为 DkDkN 的最终图像。最后一步是将深度方向卷积添加到点方向卷积。这种类型的架构减少了训练时间,因为我们需要调整的参数较少,同时对准确性的影响较小。

关于移动网络的研究论文:

安德鲁·霍华德

Sik-Ho Tsang 的一篇关于移动网络的文章:

[## 复习:MobileNetV1 —深度方向可分离卷积(轻型模型)

在这个故事中,来自 Google 的 MobileNetV1 被回顾。深度方向可分离卷积用于减少模型尺寸

towardsdatascience.com](/review-mobilenetv1-depthwise-separable-convolution-light-weight-model-a382df364b69)

评估指标

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用于研究的涂鸦样本

以上是用于这项研究的涂鸦样本。

我在ka ggle quick draw 数据集上训练我的机器学习模型,该数据集包含 5000 万张不同类型涂鸦的图像。我把这个庞大的数据集分成两部分:35000 张图片用于训练,15000 张图片用于测试。然后,我在随机选择的 5 种不同类型的涂鸦上计算了每种算法的训练时间。在测试集上,我计算了每个算法的平均精度、准确度和召回率。

评估指标-

训练时间

平均精度

准确(性)

回忆

Shashwat Tiwari 16MCA0068 提供更多评估指标

[## 机器学习评估指标完全指南

投入探索吧!

medium.com](https://medium.com/analytics-vidhya/complete-guide-to-machine-learning-evaluation-metrics-615c2864d916)

此外,Shervin Minaee 的一篇好文章

[## 20 个流行的机器学习指标。第 1 部分:分类和回归评估指标

介绍评估分类,回归,排名,视觉,自然语言处理和深度…

towardsdatascience.com](/20-popular-machine-learning-metrics-part-1-classification-regression-evaluation-metrics-1ca3e282a2ce)

所选参数的详细信息

gif by Giphy

1)随机森林

n_estimators —一个森林中决策树的数量。[10,50,100]

max_features —分割时要考虑的特性[‘auto ‘,’ sqrt’]

max_depth —树中的最大层数[2,4,6,8,10]

n_jobs —并行运行的进程数,通常设置为-1,一次执行最多的进程。

标准 —这是一种计算损失并因此更新模型以使损失越来越小的方法。[‘熵’,‘交叉验证’]

我用*‘auto’*作为max _ feature8max _ depth-1 作为 n_jobs【熵】 作为我的准则因为它们通常给出最好的结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

寻找最佳树数的图表

然而,为了找出最佳的树数,我使用了 GridSearchCV。它尝试所有给定的参数组合,并创建一个表来显示结果。从图中可以看出,80 棵树后的测试分数并没有明显的提高。因此,我决定在 80 棵树上训练我的分类器。

2)K-最近邻(KNN)

n_neighbors —要比较的最近数据点的数量[2,5,8]

n_jobs —并行运行的进程数,通常设置为-1,一次执行最多的进程

我没有改变这个模型的任何默认参数,因为它们会给出最好的结果。

然而,为了找到最佳数量的 n_neighbors ,我使用了 GridSearchCV,这是我得到的图表:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

寻找最佳 N-邻居数量的图

根据图表,测试分数在528】n _ neighbors 之后下降,这意味着 5 是最佳邻居数。

3)多层感知器(MLP)

alpha——俗称学习率,它告诉网络调整梯度的速度。[0.01, 0.0001, 0.00001]

hidden_layer_sizes — 它是一个值元组,由每层的隐藏节点数组成。[(50,50), (100,100,100), (750,750)]

激活 —为图像中的重要特征赋予价值,删除无关信息的功能。[‘relu ‘,’ tanh ‘,’ logistic’]。

解算器— 也称为优化器,该参数告诉网络使用哪种技术来训练网络中的权重。[‘sgd ‘,’ adam’]。

batch_size — 一次要处理的图像数量。[200,100,200].

我选择了激活为‘relu ’,选择解算器为‘Adam ’,因为这些参数给出了最好的结果。

然而,为了选择隐藏层alpha 的数量,我使用了 GridSearchCV。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

查找最佳 N 邻居数量的表

从表中可以看出,当 alpha 为 *0.001、*和 hidden_layer_size(784,784) 时,得到的结果最好。因此,我决定使用这些参数。

4)卷积神经网络(CNN)

l earning_rate -它告诉网络调整梯度的速度。[0.01, 0.0001, 0.00001]

hidden_layer_sizes — 它是一个值元组,由每层的隐藏节点数组成。[(50,50),(100,100,100),(750,750)]

激活 —为图像中的重要特征赋予价值,删除无关信息的功能。[‘relu ‘,’ tanh ‘,’ logistic’]。

解算器— 也称为优化器,该参数告诉网络使用哪种技术来训练网络中的权重。[‘sgd ‘,’ adam’]。

batch_size — 一次要处理的图像数量。[200,100,200]

时期 —程序应该运行的次数或模型应该训练的次数。[10,20,200]

我选择了激活函数作为“relu ”,选择解算器作为“adam ”,因为这些参数通常会给出最佳结果。在网络中,我添加了 3 个卷积层,2 个 maxpool 层,3 个 dropout 层,最后还有一个 softmax 激活函数。我在这里没有使用 GridSearchCV,因为可以尝试很多可能的组合,但是结果不会有太大的不同。

5)移动网络

Input_shape- 它是一个由图像的维度组成的元组。[(32,32,1),(128,128,3)].

Alpha- 是网络的宽度。[ < 1,> 1,1]

激活 —为图像中的重要特征赋予价值,删除无关信息的功能。[‘relu ‘,’ tanh ‘,’ logistic’]。

优化器— 也称为解算器,该参数告诉网络使用哪种技术来训练网络中的权重。[‘sgd ‘,’ adam’]。

batch_size — 一次要处理的图像数量。[200,100,200].时期 —程序应该运行的次数或模型应该训练的次数。[10,20,200]

类别- 要分类的类别数量。[2,4,10]

损耗- 它告诉网络使用哪种方法计算损耗,即预测值和实际值之间的差异。[‘分类交叉熵’,’ RMSE’]

首先,我将 2828 的图像调整为 140140 的图像,因为移动网络要求最少 3232 的图像,所以我使用的最终 input_shape 值是(140,140,1),其中 1 是图像通道(在本例中是黑白的)。我将 alpha 设置为 1 ,因为它通常会给出最好的结果。激活功能被设置为默认*,即’ relu’ 。我使用了’Adadeltaoptimizer,因为它给出了最好的结果。 batch_size 被设置为 128 以更快地训练模型。为了更准确,我使用了20历元。类别被设置为 5 ,因为我们有 5 个类别要分类。

结果

gif by Giphy

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最终结果(祈祷)

以上是使用的所有机器学习技术的性能。衡量标准包括准确度、召回率、精确度和训练时间。看到移动网络的训练时间是 46 分钟,这让我感到震惊,因为它被认为是一个轻型模型。我不确定为什么会这样,如果你知道为什么,请告诉我。

局限性和结论

  1. 在这项研究中,只使用了 28*28 大小的黑白涂鸦,而在现实世界中,不同的颜色可以描绘或表示不同的事物,图像大小可能会有所不同。因此,在这些情况下,算法的行为可能会有所不同。
  2. 在所有讨论的算法中,有许多可以改变和使用的超参数,它们可能给出不同的结果。
  3. 训练这些算法的训练集仅限于 35000 幅图像,添加更多图像可以提高这些算法的性能。

结果表明,移动网络实现了最高的准确度、精确度和召回率,因此就这三个参数而言,它是最好的算法。然而,移动网络的培训时间也是最高的。如果我们将其与 CNN 进行比较,我们可以看到,CNN 花了更少的时间进行训练,给出了类似的准确性、精确度和召回率。因此,根据这项研究,我会得出结论,CNN 是最好的算法。

在做了这项研究后,我得出结论,像 mobile-net 和 CNN 这样的算法可以用于手写字符识别、车牌检测和世界各地的银行。像 mobile-net 和 CNN 这样的算法达到了超过 97%的准确率,这比人类 95%的平均表现要好。因此,这些算法可以在现实生活中使用,使困难或耗时的过程自动化。

您可以在此处找到代码:

[## 谷歌联合实验室

编辑描述

colab.research.google.com](https://colab.research.google.com/drive/1aefccgDjDIPW6RVImtFG5fAlaI91ysbg?usp=sharing)

参考

手机网研究论文演练(YouTube)

深度方向可分离卷积 (YouTube)

[## 20 个流行的机器学习指标。第 1 部分:分类和回归评估指标

介绍评估分类,回归,排名,视觉,自然语言处理和深度…

towardsdatascience.com](/20-popular-machine-learning-metrics-part-1-classification-regression-evaluation-metrics-1ca3e282a2ce) [## 卷积神经网络(CNN)简介

本文重点介绍与 CNN 相关的所有概念及其使用 Keras python 库的实现。

levelup.gitconnected.com](https://levelup.gitconnected.com/introduction-to-convolutional-neural-networks-cnn-1ee504bc20c3) [## 用深度学习涂鸦!

草图识别之旅

towardsdatascience.com](/doodling-with-deep-learning-1b0e11b858aa) [## k-最近邻(KNN)

在这篇文章中,我们将了解什么是 K-最近邻,这个算法是如何工作的,有什么好处和…

medium.com](https://medium.com/datadriveninvestor/k-nearest-neighbors-knn-7b4bd0128da7)

Unity3D 中 ML-agent 的终极演练

原文:https://towardsdatascience.com/ultimate-walkthrough-for-ml-agents-in-unity3d-5603f76f68b?source=collection_archive---------18-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从头到尾通过机器学习训练人工智能

嘿!这将是一个快节奏的,完整的用 Unity 的 ML-agent 构建人工智能的演练。像一个优秀的电视厨师一样,我已经准备了一个简单的游戏,你可以从 GitHub 中克隆。如果你想继续下去,一定要做到!🙂

储存库 : 人工智能跳车

目前,它只是一个人类控制的游戏,没有涉及机器学习,还没有!按下空格键,你可以让汽车跳跃,以躲避驶来的车辆。

我们将通过机器学习来训练人工智能做同样的事情,希望比我们— 或至少是我能做得更好。如果你更喜欢看视频,这是给你的:

步骤 1:将我们的玩家转化为代理

这是一个简单的游戏,我们可以在以后增加复杂性。但是从简单开始会减少潜在的错误数量。我总是试图简单地开始,这几乎是无聊的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你打开主场景,你可以看到位于环境中的 Spawner 对象。在这里你可以决定被繁殖的敌人汽车以及它们被繁殖的间隔。但是我们可以让它保持原样。接下来,在我们的产卵器中,我们的玩家被一个叫做 Jumper 的简单脚本定位,它负责跳井。

Jumper.cs 剧本是我们真正关心的唯一剧本,因为这是我们的人工智能将控制的。顾名思义,我们的 ML-Agents 世界中的主角是特工——所以让我们把我们的 jumper 改造成一个。它应该从代理继承,而不是从monobehavior继承。

public class **Jumper** : Agent

哒哒🧙‍♂️,它现在是一个代理。接下来,我们向我们的玩家添加一个行为参数sscript,因为没有它,我们的代理是无脑的。姑且称之为“Jumper”之类的有用的东西吧。

现在,对于困难的部分,我们必须考虑我们的代理需要收集的观察结果——意味着它需要什么信息以及它可以采取什么行动。先从简单的开始,动作。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们的代理可以跳转并且它可以不做任何事情。就是这样。所以我们有两个选项,这意味着我们有一个大小为 2 的离散动作空间,并且只有一个分支。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果我们想把运动和跳跃结合起来,多分支是很有用的,例如:我们可以用一个分支运动,一个分支跳跃。一个单独的分支只能允许移动或跳跃,但不能同时允许两者。如果你想了解更多,可以看看 跳墙 的例子。在我们的情况下,一个单独的分支就可以了。

接下来,观察。在这里,没有正确或错误的答案。试着想一想一个代理可以观察环境的几种可能的方法,每种方法需要多少数据,一个代理要做多少过滤,才能推断出有用的信息。真的,现在暂停阅读,好好想想…

…我的想法是非常简单地开始,我认为我们的代理人只需要到下一辆车的距离,就可以正确地选择跳跃时间。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

所以我会用一个射线投射,你可以想象它就像从代理射出的激光束,直到它击中某个东西。它可以记录是否有东西被击中,什么被击中,以及被击中的东西离它有多远。由于这是一种非常常见的观察方式,Unity 已经方便地准备了一个简单的脚本,我们可以使用它,很好👌

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们将 RayPerceptionSensor3D 组件添加到我们的播放器中。我们已经可以在场景视图中看到光线的预览。首先,我们必须添加要检测的标签。在我们的例子中,产生的敌人有移动者标签,所以让我们添加它。接下来,每个方向的光线描述了中心左右的光线数量。因为我们只需要一条中心光线,所以可以将该值设置为 0。下一个相关值是光线长度。在我们的情况下,它至少应该走到路的尽头,为了安全起见,让我们在这里使用 50。为了确保光线不会碰到地面,让我们在起点和终点给它们一个 0.5 的垂直偏移量。

就是这样。我的建议是,只是玩玩滑块,看看会发生什么,以了解更多。光线投射真的很强大,是除了视觉信息之外观察环境最常见的方式。

如果我们现在开始游戏,如果前面有车,我们可以看到光线变成红色,太好了。起作用了。这个传感器的优点是它会自动将自己添加到观察中,因此不需要额外的代码,我们可以将观察大小设置为 0,因为它是为我们处理的。这个框架是不是很奇妙?

步骤 2:向我们的代理添加逻辑

好了,现在让我们进入 Jumper.cs 脚本。代理类中有一些基本的方法。让我们将它们添加到我们的代理中。初始化(),on action received(),以及 OnEpisodeBegin ()。这一次,我们实际上不需要 CollectObservations() ,因为我们只使用了传感器。但是我们应该添加启发式()方法,因为这是可以处理人类输入的地方。

总是先手动测试你的代理,这样你可以更快更容易地找到 bug。

public override void Initialize(){...}

public override void OnActionReceived(float[] vectorAction){...}

public override void OnEpisodeBegin(){...}

public override void Heuristic(float[] actionsOut){...}

首先,让我们把所有东西从唤醒()移到初始化()。简单。把 Awake ()方法删掉就行了,我们已经不需要了。

public override void Initialize()
{
    rBody = GetComponent<Rigidbody>();
    startingPosition = transform.position;
}

现在我们必须处理行动。 OnActionReceived ()方法有一个浮点数组参数。因为我们只有一个分支,所以我们只对第一个元素感兴趣。这个值要么是 0,要么是 1,所以也很简单。我们来确定 0 是什么都不做,1 是跳跃。不编码的好处是我们不需要编码任何东西,这意味着我们只需要检查 1 的情况。为了安全起见,在等式检查之前,我将把 float 底数设为 int。,这是我们的动作功能:

public override void OnActionReceived(float[] vectorAction)
{
    if (Mathf.FloorToInt(vectorAction[0]) == 1)
        Jump();
}

现在,我们将在启发式()函数中检查输入,而不是在更新()中检查输入。现在只需将更新()中的所有内容移动到启发式()中,并删除更新()。由于调用这个函数的学院运行在 Unity 的固定更新循环中,如果我们试图使用 KeyDownMouseDown ,输入检查可能会有点问题,所以使用 GetKey ()或 GetAxis ()来确保没有输入丢失。

现在,我们不调用跳转()函数,而是必须修改 aactions out[],因为动作处理是由*on actions received()函数管理的。无论我们放入actions out[]中的是什么,都会被on actions received()方法接收到。首先,我们将 aactions out[0]*设置为零,如果某个键被按下则为 1。

public override void Heuristic(float[] actionsOut)
{
    actionsOut[0] = 0;

    if (Input.GetKey(jumpKey))
        actionsOut[0] = 1;
}

现在如果我们开始游戏…我们可以看到…什么都没发生😢。

这是因为现在不需要做出任何决定。改变这种情况的一个方法是给我们的播放器添加一个决策请求器组件。它与学院相关联,要求对学院的每一步做出决定。如果该值设置为默认的 5,则每隔 5 步。如果我们添加这个组件并将其设置为 1,它就可以工作了。但是我不会用。

为什么?因为我们可以优化它。当汽车在空中时,没有什么可做的,因为只有在路上才允许跳跃。简单来说,当汽车还在空中时,我们甚至不要请求做出决定。想象一下大脑在这段时间里是关闭的。让我们添加 FixedUpdate ()方法和 Request a Decision 如果jump ready

private void **FixedUpdate**()
{
    if(jumpIsReady)
        RequestDecision();
}

同样,这只是做这件事的一种方式。如果你想到别的,试试看。

我们几乎准备好训练了,但是最重要的部分仍然缺失。奖励⭐️ !每个人都喜欢奖励,尤其是 A.Is。这一部分又很简单,但如果你做得不好,你真的会把一切都搞砸。不过不要担心😄。大多数情况下,简单直接的方法就可以了。一个基本的经验法则是输的时候惩罚-1,赢的时候奖励+1。由于这是一个高分游戏,没有输赢,所以我只是决定每辆车加 0.1 奖励。

这绝不是设计得最好的奖励系统,但它确实有效。如果您不确定—通过多次运行和预定义的步骤数进行测试,然后比较结果可能是您的最佳选择。但是稍后会有更多的测试。

OnTriggerEnter ()方法内部的脚本中,我们将调用 AddReward ()方法。

private void **OnTriggerEnter**(Collider collidedObj)
{
    if (collidedObj.gameObject.CompareTag("score"))
    {
        AddReward(0.1f); //New
        score++;
        ScoreCollector.Instance.AddScore(score);
    }
}

这个游戏中的计分方式是这样的:每辆车后面都有一个隐藏的立方体,在碰撞时触发 OnTriggerEnter() 方法。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接下来,在 OnCollisionEnter ()方法中,我们发现玩家被传入的流量击中的情况。首先,我们用结束模式()方法替换复位()方法。接下来,我们将在这里添加一个负奖励。

private void **OnCollisionEnter**(Collision collidedObj)
{
    if (collidedObj.gameObject.CompareTag("Street"))
        jumpIsReady = true;

    else if (collidedObj.gameObject.CompareTag("Mover") || collidedObj.gameObject.CompareTag("DoubleMover"))
    {
        AddReward(-1.0f);
        EndEpisode();
    }
}

步骤 3:培训代理

我们现在终于可以开始训练了!为了优化训练,我们应该添加多个代理并构建一个独立的应用程序,但是我总是先用一个代理在编辑器中测试,以发现任何错误。现在,这个游戏有希望没有 bug,但是正如你所想象的,情况并不总是这样。

我假设你的系统上已经安装了带 ML-Agents 的 Python,如果没有,请点击查看安装指南

我们只需打开终端,将 cd 放入存储库,然后放入 TrainerConfig 文件夹。现在我们开始培训,输入:

mlagents-learn trainer_config.yaml --run-id="JumperAI_1"

您可以将 run-id 更改为您最喜欢的。第二个参数引用位于存储库内部的 trainer_config 文件。只有当您在下载的库TrainerConfig 文件夹中时,这个命令才有效!

如果你看到团结标志,一切都很好。现在我们切换到编辑器,按下播放,让人工智能训练足足 10 分钟。现在是观察训练过程的时候了,看看你是否能发现任何明显的错误。

通过放入

tensorboard --logdir=summaries

进入另一个终端选项卡,我们可以进一步检查它。左边的图表显示了一段时间内累积的奖励。

大约 10 分钟后。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对我来说,在 8 分钟左右,第一次真正的改善开始出现,然后很快就变好了。这很好,它证实了我们的环境正在起作用。

下一步是用多个代理进行训练,以加快和稳定训练。在我们的例子中,这就像多次复制环境游戏对象一样简单。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

同样,我们首先按 play 并测试是否一切正常。如果是的话,那太好了。现在,让我们再次在编辑器中开始第二个培训过程,以确保多个代理按预期工作。我们将使用相同的命令,但改变 ID,以便我们可以比较运行。

mlagents-learn trainer_config.yaml --run-id="JumperAI_2"

10 分钟后。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在我的情况下,它工作得非常好。我们可以看到第二张图要大得多。这是因为由于我们拥有的代理数量,我们在相同的时间内处理了更多的步骤。这也是我们从简单开始的原因—我们能够在几分钟的培训时间内验证我们的环境正在工作,而不是几个小时。

现在,为了正确和完整的培训,我们可以构建应用程序。再次执行 mlagents-learn 命令,这一次引用我们的构建文件,将时间刻度设置为 10,意思是 10 倍的速度,这在我的系统上运行良好,将图形质量级别设置为 0,将窗口宽度和高度设置为 512 或您喜欢的任何值。

mlagents-learn trainer_config.yaml --run-id=JumperAI_3 --env=../Build/build.app --time-scale=10 --quality-level=0 --width=512 --height=512

60 分钟后。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果我们对结果满意,我们按 control+c,然后一个模型就生成了。我们可以拖动它。 nn 文件到我们的项目中,通过在层级中搜索玩家选择所有代理,并将其放入模型槽中。如果我们现在按 play,我们可以看到它正在执行我们的模型。自豪吧,你培养了一个人工智能,有多少人这么做过?

如果你在途中的某个地方迷路了,你可以随时查看库 中的【tutorial completed】分支,在那里你可以找到带有训练好的模型和完成的脚本的项目。

我鼓励你尝试这个项目,创造你自己的风格。

和平!查看我的 Youtube 频道的人工智能相关内容。✌️

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值