常见 Pipenv 错误
Pipenv 错误及其解决方案的集合。
作者: Edward Krueger 数据科学家兼讲师和 Douglas Franklin 助教兼开发者倡导者。
在本文中,我们将讨论 Pipenv 虚拟环境,在您的机器上的什么地方使用它们,如何利用 Pipfile 和 Pipfile.lock 特性,以及当这些操作不正确时可能出现的一些问题。我们从为什么环境对于数据科学和软件开发至关重要开始。
开发者最好的朋友:照片由 Timothy Dykes 在 Unsplash 上拍摄
有关 Pipenv 环境或入门的更多信息,请查看本文
数据科学和部署问题
数据科学家通常是跨学科的,他们还没有开发出编码技能来与其他人合作并将项目推向生产。因此,通常缺乏环境和依赖性管理技能。这给代码可复制性和项目协作带来了困难。其他人可以轻松地重新创建、修改和运行的数据科学项目是可复制的数据科学项目
正确执行的环境管理实践减少了项目之间的依赖版本冲突,并防止开发环境变得臃肿和不可管理,从而帮助用户创建可重复的项目。
Pipenv 是什么?
Pipenv 将软件包管理和虚拟环境控制结合到一个工具中,用于安装、删除、跟踪和记录您的依赖关系;以及创建、使用和管理您的虚拟环境。Pipenv 将 pip 和 virtualenv 结合成一个产品。有关 Pipenv 或虚拟环境的更多信息,请查看本文!
Pipenv 将包管理和虚拟环境控制结合到一个工具中,使其成为数据科学家和开发人员的绝佳工具。
Pipenv 基于每个项目来管理依赖项,因此最好在项目目录中使用 Pipenv。要安装软件包,请转到您的项目目录并运行:
$ cd myproject
$ pipenv install requests
当您使用 Pipenv 开始一个项目时,该工具会自动创建一个虚拟环境、一个 Pipfile 和一个 Pipfile.lock。Pipfile 存储运行项目代码所需的包或依赖项。对于那些使用 pip 开发的人来说,Pipfile 非常类似于 requirements.txt 文件。Pipfile.lock 存储特定的依赖版本,这些版本支持环境的确定性构建。当您使用pipenv install
来获得一个新的依赖项时,Pipfile 和 Pipfile.lock 会自动用这个新的依赖项进行更新。在上面的例子中,您的 Pipfile 将包含包“requests”,而您的 Pipfile.lock 将包含已安装的版本。
常见问题:虚拟环境和 Pipfile 位置
使用 Pipenv,您需要为每个项目创建一个新目录。这允许您隔离依赖项及其关联的文件。这通常是一个好的实践,尤其是在创建隔离的开发环境时。
> mkdir new_project> cd new_project> pipenv install pandas matplotlib
完成上述命令后,您将拥有一个需要 Python、Pandas 和 Matplotlib 的项目的基础设施。这个基础结构由目录 new_project、包含已安装包的 Pipfile 和包含它们的特定版本的 Pipfile.lock 组成。
为每个项目创建一个新的目录和 Pipenv 环境将使您的机器保持有序,并允许从一个项目到另一个项目的无缝转换。要参与项目,请切换到一个新目录,并通过运行以下命令激活该目录的环境:
> pipenv install> pipenv shell
丢失的 pip 文件
假设出于某种原因,你在一个奇怪的地方有一个 Pipfile,比如在根目录下。当你使用
> pipenv install
例如,在一个较低的目录~/Desktop/new_project
中,Pipenv 将找到并使用根目录下的 Pipfile。这实际上阻止了您使用该包来管理依赖项。在本例中,在根目录下有一个 Pipfile,它为您在较低目录下创建的所有 Pipenv 虚拟环境提供资源。如果您遇到这种情况,您必须删除导致问题的杂散 pip 文件。
现在我们将重新创建这个错误。下面是一个没有 Pipfile 放在根目录那么极端的例子,但是将说明相同的概念,在路径的一个级别上有一个 Pipfile,然后尝试在该路径的较低级别上创建另一个 Pipfile。
这里我们已经创建了目录 pipenv_nesting_test 并运行pipenv install pandas
。请注意,这将在该目录中创建 Pipfile 和 Pipfile.lock。
更高级目录中的 Pipfile
请注意,Pipfile 与 nested_directory 处于同一级别。现在我们将导航到这个目录并运行pipenv install matplotlib
。
安装 matplotlib
注意,在运行ls
之后,没有生成 Pipfile 或 Pipfile.lock。这是因为 Pipenv 找到了路径中较高位置的 Pipfile,并修改了这些文件中的数据以包含 matplotlib。下面我们使用cat ../Pipfile
来可视化 matplotlib 确实已经被添加到路径中更高的 Pipfile 中。
包含熊猫和 matplotlib 的 Pipfile
将 pip 文件保存在它们的项目目录中是避免在您的机器上出现不明确或不确定的 pip 文件的最好方法。此外,当您在一个在线项目存储库中有一个 pip 文件时,例如 Github,其他用户可以很容易地克隆您的 repo,从 pip 文件重新创建您的环境,并运行您的代码!
常见问题:锁定失败
锁定失败!
Pipfile.lock 是做什么的?
当您使用命令pipenv install
时,会创建一个 Pipfile.lock 文件。此外,命令pipenv lock
可以用来创建一个Pipfile.lock
,它在最新可用版本中声明项目的所有依赖项(和子依赖项),并存储下载文件的当前散列。这意味着依赖项和子依赖项的所有特定版本都存储在 Pipfile.lock 中。这确保了可重复的,最重要的是, 确定性的 构建。然而,许多不良做法可能导致锁定失败。下面我们将介绍一些避免和解决这个问题的方法。
命令pipenv install
首先尝试从 Pipfile.lock 构建虚拟环境,如果 Pipfile.lock 不可用,Pipenv 将从 Pipfile 创建虚拟环境,然后创建 Pipfile.lock。
锁定问题:Pipfile 包含对不存在的包的引用
Pipfile.lock 在尝试安装不存在的软件包(即错别字)时不会锁定。
pipenv install panadas
Pipenv 查找您指定的包,不管它是否存在。当包不存在或由于其他原因找不到时,您会在终端中看到以下错误以及更多错误。现在,我们将把重点放在这两个方面。
安装错别字
Pipenv 找不到 Panadas 的版本
锁定失败!请注意,“panadas”被添加到 Pipfile 的包中。这种打字错误将成为一个问题,因为现在我们的 Pipfile 包含一个错误,任何使用这个 Pipfile 的人都会遇到锁定和依赖错误。请注意,“安装成功”警报是不真实的;没有要安装的 Panadas。所发生的只是将“panadas”添加到 Pipfile 中。Pipfile 中的拼写错误是锁定失败的最常见原因。
只要 Pipfile 中存在这种输入错误,安装一个包,不管存在与否,都会导致锁定失败。您需要在文本编辑器中修复 Pipfile。我用的是纳米。你可以使用任何你觉得舒服的编辑器;Sublime,VS 代码,Atom 等。简单地把 Panadas 改成熊猫然后pipenv install.
现在让我们看看锁定失败时控制台中出现的其他一些错误消息。
注意建议pipenv install --skip-lock
。这应该只在极端或因果编程环境中使用,因为它绕过了 Pipfile。锁的主要用途;锁定软件包版本并创建安装环境依赖项的公式。
当在另一台机器上克隆存储库时,可能会遇到 Pipfile.lock 不兼容问题。这是因为 Pipfile.lock 是特定于系统的。如果合作开发人员使用不同的系统,即 macOS 和 Windows,最好删除 Pipfile.lock,让每个系统解决其依赖性。在这种情况下,确保每个人都使用相同版本的包,方法是手动将它们固定在 Pipfile 中。
锁定失败的另一个常见原因是,如果 Pipfile 中的包只作为预发布版本存在。要允许预发布软件包,您必须在 install 命令中添加— pre 标志,否则锁定将会失败。
pipenv install --pre black
您可以通过在安装命令pipenv install --pre
中添加 pre 标志来解决预发布版本冲突。在这个命令之后,您的 Pipfile 有了一个新变量;allow_prereleases = true。请注意,这将允许在您的环境中安装任何预发行软件包。现在是固定特定包版本有用的时候了。固定版本是一个很好的习惯,可以防止将来出现依赖问题。
允许 Pipfile 中的预发布
Pipfile 管理:指定 Python 版本
请注意上面“要求”部分下的 Pipfile 图像;你看 python_version = 3.7。Pipenv 可用于指定 Python 版本和包版本。
要使用特定的 Python 版本构建 Pipfile 或环境,请使用以下语法。
pipenv --python <path>
#or
pipenv --python python3
注意:需要时可以指定包的版本。
展示 pip 文件的样子,并说明您也可以直接在 pip 文件中修改它
pipenv install flask1.1.1
注意,这个版本被固定在下面的 Pipfile 中。
您可能还想直接编辑您的 Pipfile 来更改版本。
常见问题:在虚拟环境中运行 Jupyter
许多数据科学家使用 Jupyter 进行探索性数据分析和模型选择。Jupyter 可能很难与包管理器一起使用。但是,我们可以很容易地用 Pipenv 创建一个环境,并用一个内核将其连接到 Jupyter。
在 Jupyter 中,您可以访问指向虚拟环境的 Jupyter 内核。虚拟环境是用 Pipenv 创建的。
Pipenv 自动将项目映射到其特定的虚拟环境。命令pipenv shell
指向你计算机上的一个虚拟环境。虚拟环境以项目根目录的名称加上项目根目录的完整路径的散列(即my_project-a3de50
)进行全局存储。因此,如果您更改项目的路径,就会破坏这样的默认映射,Pipenv 将不再能够找到并使用项目的虚拟环境。
在使用下面的命令之前,您需要知道您的 Python 版本并安装 Jupyter。设置指南可在“Pipenv 工作流教程:Jupyter”标题下的另一篇文章**、**、、中找到。
将 Pipenv 虚拟环境连接到 Jupyter 内核。首先,运行pipenv shell.
,然后在 shell 中创建 Jupyter 内核,使其指向虚拟环境。
python3.7 -m ipykernel install --user --display-name matpltlib --name matpltlib
当让内核指定一切时,为了安全起见。一些计算机的内核总是被命名为 Python 3,当--display-name
或--name
没有通过时,会覆盖其他虚拟环境。我们建议对--name
和--display-name
使用相同的名称,以避免混淆。
如果你只有一个版本的 Python,你应该可以使用python
而不是上面的python3.7
。如果您使用的是 Mac,默认情况下您将拥有 Python 版本。如果您不确定您使用的是哪个 Python 版本,请查看:
python --version
#and/or
python3 --version
在 Jupyter 中选择内核
完成上述操作后,您现在应该能够运行:
jupyter notebook
或者您更喜欢实验室用户界面和附加功能。
jupyter lab
在 **Jupyter Notebook 中,**选择“新建”查看下拉列表,查看可用内核列表。请注意,上面第 3 步中创建的“example_env”是内核的名称。
选择笔记本中的内核
在 **Jupyter Lab,**你必须点击右上角的内核框来访问内核列表。或者,您可以单击“内核”选项卡,然后选择“更改内核”来访问同一个下拉菜单。
实验室中选择内核的两个位置
测试导入
在一个新的。ipynb 文件,尝试在单元格中运行以下代码。
import pandas
如果成功的话,你正在改进你的开发工作流程!
如果出现任何问题,请确保您选择了正确的内核,在连接内核和运行jupyter lab
或jupyter notebook
之前,您已经运行了pipenv shell
。
结论
Pipenv 是开发人员和数据科学家的优秀工具。然而,在学习这些工具和方法时,我们会遇到一些常见的错误。对于 Pipenv,Pipfile.lock 在默认情况下固定特定的版本;然而,由于提到的锁定问题和其他复杂性,当在开发人员之间共享时,锁可能会失败。因此,将您的依赖项固定在 Pipfile 中用于生产是一个最佳实践,并且在从 Pipfile.lock 构建环境时要小心。此外,在共享 Pipfile 或使用它来构建环境之前,您需要检查您的 Pipfile 是否有拼写错误!
Jupyter 笔记本是学习代码或制作使用代码创建可视化的报告的有用工具。在 Pipenv 虚拟环境中使用 Jupyter 可以让您将所有环境依赖项导入笔记本,从而简化依赖项管理。将虚拟环境连接到 Jupyter 内核可能会很棘手,但是如果您按照上面的步骤操作,应该没有任何困难!
作为数据科学家和开发人员,正确的开发、打包和虚拟环境管理实践都是需要学习的关键技能。使用 Pipenv 来管理虚拟环境可以加速生产,并允许您创建确定性的构建来复制代码和将项目推向生产。
将 pip 文件保存在它们的项目目录中是避免在您的机器上出现任何含糊不清或杂乱无章的 pip 文件的方法。此外,当您在一个在线存储库中有一个 Pipfile 时,例如 Github,其他用户可以很容易地克隆您的 repo,重新创建您的环境,并使用您的代码。通过 Pipenv 和 Pipfile,您向其他人展示了一种安装项目依赖项以及测试和开发需求的标准化方法。任何拥有您的 Pipfile 副本的人都可以使用以下内容重新创建您的环境。
pipenv install
这个命令创建一个由 Pipfile 指定的环境。在分享它之前,只要确保它没有打字错误,并且指定了正确的包和 Python 版本就可以了!
我们希望这是信息丰富和有帮助的。祝你好运,继续编码!
常见实践—第 1 部分
FAU 讲座笔记关于深度学习
优化者和学习率
FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座
这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是与幻灯片匹配的讲座视频&的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。如果你发现了错误,请告诉我们!
航行
欢迎大家来到今天的深度学习讲座!今天,我们想谈谈常见的做法。你需要知道的在实践中实现一切的东西,
接下来几节课的概述。 CC 下的图片来自深度学习讲座的 4.0 。
因此,我对接下来的几个视频和我们将关注的主题有一个小的概述。因此,我们将思考我们目前面临的问题以及我们已经走了多远。我们将讨论训练策略、优化和学习率,以及一些调整策略、架构选择和超参数优化。一个真正有用的技巧是集合。通常人们不得不处理阶级不平衡,当然,也有非常有趣的方法来处理这个问题。最后,我们来看看评估,以及如何得到一个好的预测器。我们还评估网络的实际运行情况。
神经网络训练概述。 CC 下的图片来自深度学习讲座的 4.0 。
到目前为止,我们已经看到了如何训练网络的所有细节。我们必须完全连接卷积层、激活函数、损失函数、优化、正则化,今天我们将讨论如何选择架构、训练和评估深度神经网络。
只有在我们设置了关于培训过程的所有其他重要选项之后,才会查看测试数据。来自深度学习讲座的 CC BY 4.0 下的图片。
第一件事就是测试。“理想情况下,测试数据应保存在保险库中,仅在数据分析结束时取出。”哈斯蒂和他的同事们正在讲授统计学学习的要素。
过拟合神经网络很容易实现。因此,我们必须谨慎地做出许多选择。 CC 下的图片来自深度学习讲座的 4.0 。
所以,首先,神经网络很容易过度拟合。记住 ImageNet 随机标签。当您使用测试集进行模型选择时,真正的测试集误差和泛化能力可能会被大大低估。因此,当我们选择架构时——通常是模型选择中的第一个元素——这永远不应该在测试集上进行。我们可以对数据的一个较小的子集进行初步实验,试图找出什么有效。当你做这些事情的时候,千万不要在测试集上工作。
使用数字渐变检查您的渐变实现。 CC 下的图片来自深度学习讲座的 4.0 。
让我们来看看几个训练策略:在训练之前,检查你的梯度,检查损失函数,检查自己的层实现,它们正确地计算结果。如果您实现了自己的图层,请比较解析梯度和数值梯度。你可以用中心差分来表示数字渐变。你可以用相对误差代替绝对差异,并考虑数字。使用双精度进行检查,暂时调整损失函数,如果观察到非常小的值,适当选择您的 h 作为步长。
梯度调试的更多提示。 CC 下的图片来自深度学习讲座的 4.0 。
然后,我们有几个额外的和建议:如果你只使用几个数据点,那么损失函数的不可微部分的问题会更少。您可以在短时间内训练网络,然后再执行梯度检查。可以先查梯度,再用正则项。所以,你首先关闭正则项,检查梯度,最后用正则项。此外,关闭数据增强并退出。因此,您通常在相当小的数据集上进行这种检查。
也检查你的初始化。来自深度学习讲座的 4.0CC 下的图片。
初始化的目标是对层进行正确的随机初始化。因此,您可以在关闭正则化的情况下计算未训练网络上每个类的损失,当然,这应该会给出一个随机分类。所以在这里,我们可以将这种损失与随机选择课程时的损失进行比较。它们应该是相同的,因为你是随机初始化的。重复多次随机初始化,以检查初始化是否没有问题。
训练前测试训练设置。 CC 下的图片来自深度学习讲座的 4.0 。
我们去训练吧。首先,您检查架构是否总体上能够学习任务。因此,在使用完整数据集训练网络之前,您需要数据的一个小子集。也许 5 到 20 个样本,然后尝试使网络过载以获得零损失。用这么少的样本,你应该能够记住整个数据集。尽量做到零损失。然后,你知道你的训练程序实际上是有效的,你真的可以降到零损失。或者,您可以关闭正则化,因为它可能会阻碍这种过度拟合过程。现在,如果网络不能过度拟合,你可能在实现中有一个 bug,或者你的模型可能太小。因此,您可能希望增加参数/模型容量,或者只是模型可能不适合此任务。此外,首先要了解数据、丢失和网络的行为。
损耗曲线有助于识别爆炸和消失梯度。来自深度学习讲座的 CC BY 4.0 下的图片。
记住,我们应该监控损失函数。这些是典型的损失曲线。确保没有爆炸或消失的渐变。你想要有适当的学习率,所以检查学习率以识别学习曲线中的大跳跃。如果您有非常嘈杂的曲线,尝试增加批量大小。噪音损失曲线可能与过小的小批量有关。
监控验证损失将有助于您在训练期间发现过度拟合。 CC 下的图片来自深度学习讲座的 4.0 。
接下来,获取验证数据集并监控验证损失。你记得,这个图像:随着时间的推移,你的训练损失当然会下降,但是测试损失会上升。当然,您从来没有在测试数据集上计算过,但是您将验证集作为测试损失的替代。然后,您可以确定您的网络中是否出现过拟合。如果训练和验证有分歧,你有过度拟合。所以,你可能想增加正则化或尝试早期停止。如果训练和验证损失很接近,但非常高,您可能有欠拟合。因此,减少正则化并增加模型大小。您可能想要保存中间模型,因为您可以在以后的测试中使用它们。
查看经过训练的卷积核可以帮助识别噪声模式检测器。 CC 下的图片来自深度学习讲座的 4.0 。
此外,在训练期间,监控重量和激活。跟踪权重更新的相对幅度。他们应该在一个合理的范围内,也许是 10⁻。在卷积层中,您可以检查前几层的滤波器。它们应该朝着平滑和规则的过滤器发展。你可能想检查一下。你需要像这里一样的过滤器,在右手边。左手边的那些包含相当多的噪声,并且这可能不是非常可靠的特征。你可以从这里开始建造一个噪音探测器。所以这可能是个问题。此外,检查大量饱和激活。请记住,死亡可能会发生。
小费选择优化。来自深度学习讲座的 CC BY 4.0 下的图片。
所以让我们看一下优化和学习率。你想选择一个优化器。现在批量梯度下降需要大内存,太慢,更新太少。所以人们追求的是典型的随机梯度下降。这里,损失函数和梯度变得非常嘈杂,特别是,如果你只使用你的一个样本。你想要小批量的。小批量是两全其美的。它具有频繁但稳定的更新,并且梯度的噪声足以避开局部最小值。因此,您希望根据您的问题和优化调整小批量大小,以产生更平滑或更嘈杂的梯度。此外,您可能希望使用动量来防止振荡并加速优化。超参数的影响相对简单。我们的建议是你从小批量、梯度下降和动量开始。一旦你有了一个好的参数集,你就可以使用 Adam 或者其他优化器来优化不同的权重。
时刻关注亏损曲线。 CC 下的图片来自深度学习讲座的 4.0 。
记住观察损失曲线。如果你的学习速率设置不正确,你在网络的训练中就有麻烦了。对于几乎所有基于梯度的优化器,你必须设置η。所以,我们经常直接在损失曲线中看到,但这是一个简化的视图。因此,我们实际上希望有一个自适应的学习速率,然后逐步用更小的步骤找到最优。正如我们已经讨论过的,你需要调整学习速度。
关于如何提高学习速度的提示。来自深度学习讲座的 CC BY 4.0 下的图片。
现在,学习率衰减是你必须以某种方式设置的另一个超参数。你要避免振荡以及过快的冷却。所以,有几个衰变策略。逐步衰减每 n 个时期,你以某一因子降低学习率,如 0.5,常数值如 0.01,或者当验证误差不再降低时,你降低学习率。在每个时期都有指数衰减,你可以用这个指数函数来控制衰减。还有 1/t 衰减,在时间 t,你基本上用 1 / (1 + kt )来缩放初始学习速率。逐步衰减是最常见的,超参数也很容易解释。二阶方法目前在实践中并不常见,因为它们不能很好地扩展。这么多关于学习率和一些相关的超参数。
在这个深度学习讲座中,更多令人兴奋的事情即将到来。来自深度学习讲座的 CC BY 4.0 下的图片。
下一次在深度学习中,我们将进一步研究如何调整我们刚刚发现的所有超参数。你会发现这些提示对你自己的实验非常有价值。非常感谢大家的聆听,下节课再见!
如果你喜欢这篇文章,你可以在这里找到更多的文章,或者看看我们的讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTube 、 Twitter 、脸书或 LinkedIn 。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。
参考
[1] M. Aubreville,M. Krappmann,C. Bertram 等,“用于组织学细胞分化的导向空间转换器网络”。载于:ArXiv 电子版(2017 年 7 月)。arXiv: 1707.08525 [cs。简历】。
【2】詹姆斯·伯格斯特拉和约舒阿·本吉奥。“随机搜索超参数优化”。在:j .马赫。学习。第 13 号决议(2012 年 2 月),第 281-305 页。
【3】让·迪金森·吉本斯和 Subhabrata Chakraborti。“非参数统计推断”。载于:国际统计科学百科全书。斯普林格,2011 年,第 977-979 页。
[4]约舒阿·本吉奥。“深度架构基于梯度训练的实用建议”。《神经网络:交易的诀窍》。斯普林格出版社,2012 年,第 437-478 页。
[5]·张,Samy Bengio,Moritz Hardt 等,“理解深度学习需要反思泛化”。载于:arXiv 预印本 arXiv:1611.03530 (2016)。
[6]鲍里斯·T·波亚克和阿纳托利·B·朱迪斯基。“通过平均加速随机逼近”。摘自:SIAM 控制与优化杂志 30.4 (1992),第 838-855 页。
【7】普拉吉特·拉马钱德兰,巴雷特·佐夫,和阔克诉勒。“搜索激活功能”。载于:CoRR abs/1710.05941 (2017 年)。arXiv: 1710.05941。
[8] Stefan Steidl,Michael Levit,Anton Batliner 等,“所有事物的衡量标准是人:情感的自动分类和标签间的一致性”。在:过程中。ICASSP 的。电气和电子工程师协会,2005 年 3 月。
常见实践—第 2 部分
FAU 讲座笔记关于深度学习
超参数和集合
FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座
这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是与幻灯片匹配的讲座视频&的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。如果你发现了错误,请告诉我们!
航行
欢迎大家来深度学习!因此,今天我们想进一步了解常见实践,特别是在本视频中,我们想讨论架构选择和超参数优化。
记住:测试数据还在保险库中! CC 下的图片来自深度学习讲座的 4.0 。
请记住,测试数据仍在保险库中。我们不碰它。然而,我们需要以某种方式设置我们的超参数,你已经看到有大量的超参数。
许多超参数与我们的训练过程相关。 CC 下的图片来自深度学习讲座的 4.0 。
您必须选择架构、层数、每层的节点数、激活函数,然后您拥有优化中的所有参数:初始化、损失函数等等。优化器仍然有选项,如梯度下降的类型、动量、学习率衰减和批量大小。在正则化中,有不同的正则化 L2 和 L1 损失,批量归一化,辍学,等等。你想以某种方式算出这些不同种类的程序的所有参数。
架构的选择对您的系统至关重要。来自深度学习讲座的 CC BY 4.0 下的图片。
现在,让我们选择一个架构和损失函数。第一步是考虑问题和数据。特征看起来像什么?你期望什么样的空间相关性?什么样的数据增强有意义?课程将如何分配?关于目标应用程序,什么是重要的?然后,你从简单的架构和损失函数开始,当然,你做你的研究。首先尝试知名车型。它们正在被出版,并且有如此多的论文在那里。因此,没有必要事事亲力亲为。在图书馆呆一天可以节省数小时、数周甚至数月的实验时间。做研究。它真的会节省你的时间。通常他们只是不发表论文,但在非常好的论文中,不仅仅是科学结果,他们还分享源代码,有时甚至是数据。试着找到那些文件。这对你自己的实验有很大帮助。因此,您可能需要改变架构,使其适应您在文献中发现的问题。如果你改变了什么,找到好的理由为什么这是一个合适的改变。有相当多的论文似乎将随机变化引入到架构中。后来,事实证明,他们所做的观察基本上是随机的,他们只是运气好,或者在自己的数据上做了足够多的实验,以获得改进。通常,也有一个合理的理由来解释为什么特定的变化会提高性能。
超参数搜索的搜索策略。 CC 下的图片来自深度学习讲座的 4.0 。
接下来,您需要进行超参数搜索。所以你记得学习率衰减,正规化,辍学,等等。这些都要调音。尽管如此,网络可能需要几天或几周的时间来训练,你必须搜索这些超参数。因此,我们建议使用对数刻度。例如对于η,这里是 0.1,0.01 和 0.001。你可以考虑网格搜索或随机搜索。所以在网格搜索中,你会有相等的距离步长,如果你看参考文献[2],他们已经表明随机搜索比网格搜索有优势。首先,它更容易实现,其次,它对影响很大的参数有更好的探索。所以,你可能想看看,然后相应地调整你的策略。所以超参数是高度相互依赖的。您可能希望使用从粗到细的搜索。你在开始时在一个非常粗糙的尺度上进行优化,然后使它变得更精细。你可以只训练网络几个时期,然后将所有的超参数带入合理的范围。然后,您可以使用随机和网格搜索进行细化。
集成旨在融合多个独立的分类器。来自深度学习讲座的 CC BY 4.0 下的图片。
一个非常常见的可以给你一点点性能提升的技术是集成。这也能真正帮助你获得你仍然需要的额外的一点点性能。到目前为止,我们只考虑了单个分类器。集成的想法是使用许多这样的分类器。如果我们假设 N 个分类器是独立的,执行正确预测的概率将是 1 — p。现在,看到 k 个错误的概率是 N 选择 k 乘以 p 到 k 的幂次(1 — p 到的幂次(N — k )。这是一个二项分布。所以,多数意为 k > N /2 错的概率是 N 选择 k 乘以 p 到 k 乘以(1 — p )的幂( N — k )之和。
分类器的集合比单个分类器更强。 CC 下的图片来自深度学习讲座的 4.0 。
所以,我们在下面的图中想象一下。在这个图表中,你可以看到如果我采用更多的弱分类器,我们会变得更强。让我们把他们出错的概率设为 0.42。现在,我们可以计算这个二项分布。在这里,你可以看到,如果我选择 20,我得到的概率约为 14%,多数是错误的。如果我选择 N=32,我得到小于 10%的概率多数是错误的。如果我选择 70,超过 95%的情况下大多数将是正确的。因此,你可以看到,对于较大的 n,这个概率是单调递减的,如果 n 接近无穷大,那么精度将趋向于 1。这里最大的问题当然是独立性。因此,通常情况下,我们会遇到从相同的数据中生成独立分类器的问题。所以,如果我们有足够的数据,我们就可以训练许多独立的弱分类器。那么,我们如何把它作为一个概念来实现呢?我们必须以某种方式产生 N 个独立的分类器或回归器,然后我们通过多数或平均来组合预测。我们如何实际生产这样的组件?
不同的局部最小值产生不同的模型。 CC 下的图片来自深度学习讲座的 4.0 。
嗯,你可以选择不同的型号。在这个例子中,我们看到了一个非凸函数。显然,它们有不同的局部极小值。因此,不同的局部最小值会导致不同的模型,然后我们可以将它们结合起来。此外,你可以尝试一个循环学习率,然后随着学习率上下波动,以避开某些局部极小值。这样,您就可以尝试找到不同的局部最小值,并存储它们以进行组合。
创建不同的或多或少独立的分类器或回归器的一些想法。来自深度学习讲座的 CC BY 4.0 下的图片。
这样,您还可以在优化的不同点提取不同的模型检查点。稍后,您可以重新使用它们进行组装。此外,权重的移动平均 w 可以生成新模型。你甚至可以走这么远,结合不同的方法。所以,我们仍然有传统机器学习方法的完整目录,你也可以训练它们,然后将它们与你的新深度学习模型相结合。通常,如果您只需要一点点,这是一个简单的性能提升。顺便说一下,这也是最终帮助人们打破网飞挑战的想法。前两队差点打破挑战,他们组队训练合奏。这样他们一起打破了挑战。
在这个深度学习讲座中,更多令人兴奋的事情即将到来。 CC 下的图片来自深度学习讲座的 4.0 。
因此,下一次在深度学习中,我们将讨论课堂失衡,这是一个非常常见的问题,以及如何在您的培训过程中处理这一问题。非常感谢您的收听,再见!
如果你喜欢这篇文章,你可以在这里找到更多的文章,或者看看我们的讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTube 、 Twitter 、脸书或 LinkedIn 。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。
参考
[1] M. Aubreville,M. Krappmann,C. Bertram 等,“用于组织学细胞分化的导向空间转换器网络”。载于:ArXiv 电子版(2017 年 7 月)。arXiv: 1707.08525 [cs。简历】。
【2】詹姆斯·伯格斯特拉和约舒阿·本吉奥。“随机搜索超参数优化”。在:j .马赫。学习。第 13 号决议(2012 年 2 月),第 281-305 页。
【3】让·迪金森·吉本斯和 Subhabrata Chakraborti。“非参数统计推断”。载于:国际统计科学百科全书。斯普林格,2011 年,第 977-979 页。
[4]约舒阿·本吉奥。“深度架构基于梯度训练的实用建议”。《神经网络:交易的诀窍》。斯普林格出版社,2012 年,第 437-478 页。
[5]·张,Samy Bengio,Moritz Hardt 等,“理解深度学习需要反思泛化”。载于:arXiv 预印本 arXiv:1611.03530 (2016)。
[6]鲍里斯·T·波亚克和阿纳托利·B·朱迪斯基。“通过平均加速随机逼近”。摘自:SIAM 控制与优化杂志 30.4 (1992),第 838-855 页。
【7】普拉吉特·拉马钱德兰,巴雷特·佐夫,和阔克诉勒。“搜索激活功能”。载于:CoRR abs/1710.05941 (2017 年)。arXiv: 1710.05941。
[8] Stefan Steidl,Michael Levit,Anton Batliner 等,“所有事物的衡量标准是人:情感的自动分类和标签间的一致性”。在:过程中。ICASSP 的。电气和电子工程师协会,2005 年 3 月。
常见做法—第 3 部分
FAU 讲座笔记关于深度学习
阶级不平衡
FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座
这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是与幻灯片匹配的讲座视频&的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。如果你发现了错误,请告诉我们!
航行
欢迎回到深度学习!今天,我们想继续谈谈我们的常见做法。我们今天感兴趣的方法是关于阶级不平衡的。因此,一个非常典型的问题是,一门课——尤其是非常有趣的一门课——并不经常上。所以,这是对所有机器学习算法的挑战。
今日问题:如何应对阶层失衡? CC 下的图片来自深度学习讲座的 4.0 。
让我们以欺诈检测为例。在 10,000 笔交易中,9,999 笔是真实的,只有一笔是欺诈性的。所以,如果你把所有东西都归类为正品,你会得到 99.99%的准确率。显然,即使在不太严重的情况下,如果你有一个模型,它会从一百个交易中错误地分类出一个,那么你最终只能得到一个准确率为 99%的模型。这当然是一个很难的问题。特别是,在筛选应用程序时,你必须非常小心,因为仅仅将所有东西归类到最常见的类别中仍然可以获得非常非常好的准确性。
为了评估癌症的侵袭性,有丝分裂细胞是重要的。 CC 下的图片来自深度学习讲座的 4.0 。
不一定是信用卡,比如这里检测有丝分裂细胞就是一个非常类似的问题。有丝分裂细胞是正在进行细胞分裂的细胞。正如我们在引言中所听到的,这些细胞非常重要。如果你计算处于有丝分裂状态的细胞,你就会知道相关的癌症是如何迅速增长的。所以这是一个非常重要的特征,但是你必须正确地检测它们。它们只占组织中细胞的很小一部分。所以,这个类的数据在训练期间被看到得少得多,并且像准确度、L2 范数和交叉熵这样的度量没有显示出这种不平衡。所以,他们对此反应不是很强烈。
欠采样是对抗类不平衡的第一个想法。来自深度学习讲座的 CC BY 4.0 下的图片。
你可以做的一件事是,比如重新采样。这个想法是,你通过对类进行不同的采样来平衡类的频率,所以,你可以理解这意味着你必须丢弃很多最频繁类的训练数据。这样你就可以训练一个分类器来平衡这两个类。现在他们几乎和其他班级一样频繁地出现。这种方法的缺点是,您没有使用所有看到的数据,当然,您也不想丢弃数据。
过采样是处理类不平衡的另一种策略。 CC 下的图片来自深度学习讲座的 4.0 。
另一种技术是过采样。你可以更多地从代表性不足的班级中取样。在这种情况下,您可以使用所有的数据。缺点当然是它会导致对不太常见的例子的过度拟合。欠采样和过采样的组合也是可能的。
SMOTE 是在深度学习中执行重采样的一种相当不常见的方法。更常见的是,您会发现对数据扩充的巧妙使用。来自深度学习讲座的 CC BY 4.0 下的图片。
这就产生了先进的重采样技术,试图避免合成少数过采样的欠采样缺点。在深度学习中相当少见。由欠采样引起的欠拟合可以通过在每个时期之后采用不同的子集来减少。这很常见,你也可以使用数据扩充来帮助减少对代表性不足的类的过度拟合。所以,你实际上增加了更多你不常看到的样本。
一个很常见的选择是根据上课频率调整损耗。 CC 下的图片来自深度学习讲座的 4.0 。
当然,除了固定数据之外,你还可以尝试调整损失函数,使其相对于类别不平衡保持稳定。在这里,您可以选择一个与类别频率相反的损失。然后,您可以创建加权交叉熵,其中您引入了一个额外的权重 w,它被简单地确定为逆类频率。分割问题中更常见的是基于骰子系数的骰子损失。在这里,您将评估测量区域重叠的 dice 系数的损失。这是一种非常典型的用于评估分段而不是类别频率的方法。权重也可以根据其他考虑因素进行调整,但我们不会在本次讲座中讨论它们。
在这个深度学习讲座中,更多令人兴奋的事情即将到来。 CC 下的图片来自深度学习讲座的 4.0 。
这已经把我们带到了这一部分的结尾,在通用实践的最后一节,我们现在将讨论评估的方法以及如何恰当地评估我们的模型。所以,非常感谢大家的收听,再见!
如果你喜欢这篇文章,你可以在这里找到更多的文章,在这里找到更多关于机器学习的教育材料,或者看看我们的深度 学习 讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTube、Twitter、脸书、LinkedIn 或 T21。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。
参考
[1] M. Aubreville,M. Krappmann,C. Bertram 等,“用于组织学细胞分化的导向空间转换器网络”。载于:ArXiv 电子版(2017 年 7 月)。arXiv: 1707.08525 [cs。简历】。
【2】詹姆斯·伯格斯特拉和约舒阿·本吉奥。“随机搜索超参数优化”。在:j .马赫。学习。第 13 号决议(2012 年 2 月),第 281-305 页。
【3】让·迪金森·吉本斯和 Subhabrata Chakraborti。“非参数统计推断”。载于:国际统计科学百科全书。斯普林格,2011 年,第 977-979 页。
[4]约舒阿·本吉奥。“深度架构基于梯度训练的实用建议”。《神经网络:交易的诀窍》。斯普林格出版社,2012 年,第 437-478 页。
[5]·张,Samy Bengio,Moritz Hardt 等,“理解深度学习需要反思泛化”。载于:arXiv 预印本 arXiv:1611.03530 (2016)。
[6]鲍里斯·T·波亚克和阿纳托利·B·朱迪斯基。“通过平均加速随机逼近”。摘自:SIAM 控制与优化杂志 30.4 (1992),第 838-855 页。
【7】普拉吉特·拉马钱德兰,巴雷特·佐夫,和阔克诉勒。“搜索激活功能”。载于:CoRR abs/1710.05941 (2017 年)。arXiv: 1710.05941。
[8] Stefan Steidl,Michael Levit,Anton Batliner 等,“所有事物的衡量标准是人:情感的自动分类和标签间的一致性”。在:过程中。ICASSP 的。电气和电子工程师协会,2005 年 3 月。
常见做法—第 4 部分
FAU 讲座笔记关于深度学习
性能赋值
FAU 大学的深度学习。下图 CC BY 4.0 来自深度学习讲座
这些是 FAU 的 YouTube 讲座 深度学习 的讲义。这是与幻灯片匹配的讲座视频&的完整抄本。我们希望,你喜欢这个视频一样多。当然,这份抄本是用深度学习技术在很大程度上自动创建的,只进行了少量的手动修改。如果你发现了错误,请告诉我们!
航行
最后,我们可以深入研究测试数据。 CC 下的图片来自深度学习讲座的 4.0 。
欢迎大家进入深度学习的下一部分!今天,我们想结束对常见实践的讨论,特别是,我们想看一下评估。当然,我们需要评估到目前为止我们已经训练过的模型的性能。现在,我们已经设置了训练,设置了超参数,并配置了所有这些。现在,我们想要评估之前未见过的数据的泛化性能。这意味着测试数据,是时候打开保险库了。
请记住,我们正在处理的大多数类别都是人造的。其中一些定义可能远不如乍看上去那样清晰。 CC 下的图片来自深度学习讲座的 4.0 。
记住“万物的尺度是人”。因此,数据由人工标注和标记,在训练期间,所有的标记都被认为是正确的。当然,犯错是人之常情。这意味着我们可能有模棱两可的数据。您实际上希望您的数据的理想情况是,它已经由多个人类投票者进行了注释。然后你可以采取平均或多数投票。还有一篇由 Stefan Steidl 在 2005 年发表的非常好的论文。它引入了一种基于熵的测量方法,考虑了人类参考标签的混淆。这在标签不清楚的情况下非常有用。特别是,在情感识别中,这是一个问题,因为人类有时会混淆愤怒和烦恼等类别,而他们不太可能混淆“愤怒”和“快乐”,因为这是一个非常明显的区别。有不同程度的快乐。有时候你只是有点开心。在这些情况下,真的很难区分开心和中立。这对人类来说也很难。在原型中,如果你让演员扮演,你会得到超过 90%的情感识别率。如果你有真实的数据情绪,如果你有日常生活中发生的情绪,那就很难预测了。这也可以在标签和标签的分布中看到。如果你有一个原型,所有的评分者都会同意这个观察显然是这个特殊的类。如果你有细微差别和不那么明确的情绪,你会发现我们的评分者在标签上的分布也不太明显,甚至是均匀的,因为他们也不能评估特定的样本。因此,如果人类也混淆了同一个类,分类器的错误显然不那么严重。这正是 Steidl 基于熵的度量所考虑的。
两类问题的典型评价措施。来自深度学习讲座的 CC BY 4.0 下的图片。
现在,如果我们研究绩效评估,您需要考虑典型的分类评估。它们通常围绕假阴性、真阴性、真阳性和假阳性而建立。从二进制分类问题,你可以计算真和假阳性率。这通常会产生一些数字,比如准确率,即正的数量加上负的数量除以正的数量和负的数量。然后是精确度或阳性预测值,计算方法是真阳性的数量除以真阳性加上假阳性的数量。有一种所谓的召回,它被定义为真阳性与真阳性加上假阴性之比。特异性或真负值是真阴性除以真阴性加上假阳性。F1 分数是混合这些指标的中间方式。你有真正的正值乘以真正的负值,除以两个正值和真正的负值之和。我通常推荐接收机工作特性(ROC)曲线,因为你在上面看到的所有测量都依赖于阈值。如果你有 ROC 曲线,你基本上评估了所有不同阈值的分类器。这将为您分析它在不同场景下的表现。
多类问题的典型措施。来自深度学习讲座的 CC BY 4.0 下的图片。
此外,在多类分类中还有性能测量。这些是上述措施的变通版本。top- K 误差是真实类别标签不在具有最高预测分数的 K 估计中的概率。常见的实现是前 1 名和前 5 名错误。例如,ImageNet 通常使用 top-5 错误。如果你真的想了解多类分类中发生了什么,我建议看看混淆矩阵。混淆矩阵对 10 到 15 个班级很有用。如果你有一千个类,混淆矩阵不再有任何意义。尽管如此,如果您在类较少的情况下查看混淆矩阵,您可以对正在发生的事情有更多的了解。
交叉验证是估计样本外误差的常用工具。 CC 下的图片来自深度学习讲座的 4.0 。
现在,有时你只有很少的数据。因此,在这些情况下,您可能希望选择交叉验证。在 k 倍交叉验证中,您将数据分成 k 倍,然后使用 k-1 倍作为训练数据,并在 k 倍上进行测试。然后,重复 k 次。这样,你在评估数据中看到了所有的数据,但是你是在独立数据上训练的,因为你在训练的时候拿出来了。这在深度学习中相当少见,因为这意味着非常长的训练时间。你必须重复整个训练 K 次,如果你训练 7 天,这真的很难。如果你有七次交叉验证,你知道你可以做数学,这将需要很长时间。如果用于超参数估计,就得嵌套。不要只对所有数据进行交叉验证,选择超参数,然后对相同的数据进行测试。这会给你带来乐观的结果。你应该始终确保,如果你选择了参数,你在你想要测试的地方拿出了测试数据,所以有将交叉验证嵌套到交叉验证中的技术,但这也会在计算上变得非常昂贵,所以如果你想嵌套交叉验证,那就更糟了。你必须记住的一点是,结果的方差通常被低估了,因为训练授权不是独立的。你还需要注意 通过合并架构选择和超参数选择,可能会引入额外的偏差,因此这应该在不同的数据上进行,如果您正在使用交叉验证,即使没有交叉验证,这也是非常困难的。训练是一个高度随机的过程,因此如果您选择随机初始化,您可能需要使用不同的初始化来多次重新训练您的网络,然后报告标准偏差,以确保您的训练实际执行得有多好。
两个识别率之间的差异可能是训练过程的统计性质的产物。来自深度学习讲座的 CC BY 4.0 下的图片。
现在,你想比较不同的分类器。问题是:“我 91.5%准确率的新方法比 90.9%的最先进方法好吗?”当然,训练一个系统是一个随机过程。因此,仅仅比较这两个数字会产生有偏差的结果。你要问的实际问题是:“分类器之间有显著的差异吗?”这意味着您需要为每种方法运行多次培训。例如,只有这样,您才能使用 t-test 来查看结果的分布是否有显著差异(参见链接部分)。t 检验比较两个方差相等的正态分布数据集。然后,您可以确定均值在显著性水平α(即随机性水平)方面存在显著差异。你经常会在文献中发现 5%或 1%的显著性水平。所以,如果这个观察结果是随机的,概率小于 5%或 1%,你就有了显著的不同。
针对相同数据的多次测试需要进行统计校正,如 Bonferroni 校正。来自深度学习讲座的 CC BY 4.0 下的图片。
现在,如果您在相同的数据上训练多个模型,请小心。如果你多次询问相同的数据,你实际上必须修正你的重要性计算。这被称为 Bonferroni 校正。如果我们比较多个分类器,这将引入多个比较,然后您必须对此进行校正。如果你进行了显著性水平为α的 n 次测试,那么总风险为 n 乘以α。因此,为了达到α的总显著性水平,对于每个单独的测试,调整后的α’将是α除以 n 。因此,对相同的数据运行的测试越多,需要除以的次数就越多。当然,这假设了测试之间的独立性,这是一种对显著性的悲观估计。但在这种情况下,你想要悲观,只是为了确保你不是在报告一件偶然产生的事情。仅仅因为你测试的次数足够多,而且你的测试是一个随机的过程,可能会有一个非常好的结果碰巧出现。更准确,但非常耗时的是排列测试,相信我,你可能想用 Bonferroni 校正来代替。置换一切将比我们之前看到的交叉验证方法花费更长的时间。
深度学习常用实践总结。 CC 下的图片来自深度学习讲座的 4.0 。
好的,让我们总结一下我们之前所看到的:在训练之前检查你的实现,梯度初始化,持续监控训练过程,训练,验证损失,权重,和激活。在重新发明轮子之前,坚持已建立的架构。使用少量数据进行实验,并在评估之前保持评估数据的安全。随着时间的推移,学习率逐渐下降。随机搜索,而不是网格搜索超参数。执行模型集合以获得更好的性能,当然,当您检查您的比较时,您希望进行显著性测试以确保您没有报告随机观察。
在这个深度学习讲座中,更多令人兴奋的事情即将到来。来自深度学习讲座的 CC BY 4.0 下的图片。
因此,下一次在深度学习中,我们实际上想看看神经网络架构的演变。所以从深层网络到更深层的网络。我们想看看稀疏和密集的连接,我们将介绍许多常见的名称,到处都可以听到的名称,LeNet、GoogLeNet、ResNet 等等。因此,在接下来的系列讲座视频中,我们将了解许多有趣的最新方法。所以,非常感谢大家的收听,下期视频再见!
如果你喜欢这篇文章,你可以在这里找到更多的文章,或者看看我们的讲座。如果你想在未来了解更多的文章、视频和研究,我也会很感激关注 YouTube 、 Twitter 、脸书或 LinkedIn 。本文以 Creative Commons 4.0 归属许可发布,如果引用,可以转载和修改。
链接
参考
[1] M. Aubreville,M. Krappmann,C. Bertram 等,“用于组织学细胞分化的导向空间转换器网络”。载于:ArXiv 电子版(2017 年 7 月)。arXiv: 1707.08525 [cs。简历】。
【2】詹姆斯·伯格斯特拉和约舒阿·本吉奥。“随机搜索超参数优化”。在:j .马赫。学习。第 13 号决议(2012 年 2 月),第 281-305 页。
【3】让·迪金森·吉本斯和 Subhabrata Chakraborti。“非参数统计推断”。载于:国际统计科学百科全书。斯普林格,2011 年,第 977-979 页。
[4]约舒阿·本吉奥。“深度架构基于梯度训练的实用建议”。《神经网络:交易的诀窍》。斯普林格出版社,2012 年,第 437-478 页。
[5]·张,Samy Bengio,Moritz Hardt 等,“理解深度学习需要反思泛化”。载于:arXiv 预印本 arXiv:1611.03530 (2016)。
[6]鲍里斯·T·波亚克和阿纳托利·B·朱迪斯基。“通过平均加速随机逼近”。摘自:SIAM 控制与优化杂志 30.4 (1992),第 838-855 页。
【7】普拉吉特·拉马钱德兰,巴雷特·佐夫,和阔克诉勒。“搜索激活功能”。载于:CoRR abs/1710.05941 (2017 年)。arXiv: 1710.05941。
[8] Stefan Steidl,Michael Levit,Anton Batliner 等,“所有事物的衡量标准是人:情感的自动分类和标签间的一致性”。在:过程中。ICASSP 的。电气和电子工程师协会,2005 年 3 月。
机器学习学生和从业者在 LinkedIn 上问的常见问题
经验
本文中的答案可以为您的机器学习之旅节省一些时间和麻烦
介绍
LinkedIn 多年来越来越受欢迎,它已经成为专业人士的社交网络空间。
我见过许多专业人士以各种方式利用 LinkedIn。一些人把它作为个人品牌建设的工具,而另一些人把它作为潜在客户和营销的工具。
LinkedIn 的一个突出用途是联系个人寻求职业和学术建议。这些人可能在物理上无法接触到,因此 LinkedIn 是一个沟通渠道,它弥合了个人之间的物理距离。
使用 LinkedIn 作为建议平台是本文的重点。个人已经阅读了我的文章,并通过 LinkedIn 联系我,以获得更多关于特定主题的信息和建议,所有这些都与机器学习相关。
在这篇文章中,我将包括机器学习从业者和学生提出的一些常见问题,我还将包括我提供的相应答案。
我已经从问题中删除了任何姓名和个人信息,以保护联系过我的个人的身份。
如何阅读这篇文章
个人提出的问题将遵循您正在阅读的这份特定陈述的格式 。
“我的声明看起来像这样”
答案将遵循以下格式:
回答:
包含对问题的回答的段落
问题 1(在线学习)
问题:
你好,Richmond,我正在学习计算机视觉,如果你有任何对我有帮助的课程链接/文章/电子书,我将不胜感激。谢谢!
这是好奇的人问的一个常见问题,他们希望获得一些关于机器学习相关主题的基础知识。我倾向于引导新学员使用我利用的免费资源。我认为,在花钱购买课程和参加证书课程之前,最好先了解一下学科领域和主题。
回答
要学习计算机视觉,你必须了解机器学习、神经网络和图像处理的基础知识。
神经网络
在机器学习中,理解线性代数、微积分和偏微分等主题是必不可少的。
在神经网络中,理解基本概念和思想是至关重要的。理解诸如反向传播、消失梯度下降和不同的神经网络架构(例如卷积神经网络(CNN))的概念也很重要;深度神经网络(deep)和递归神经网络(RNN)。
斯坦福计算机视觉讲座
在了解 ML 和神经网络的基础知识之后,您可以深入斯坦福大学的一些学术内容,这些内容解释了一些标准的计算机视觉技术、理论和算法。
深度蜥蜴机器学习&深度学习
如果你对神经网络和一些机器学习算法背后的理论和数学有坚实的掌握,你可以继续使用标准的机器学习库,如 PyTorch ,进行一些实际的项目和网络实现。
有了你积累的所有知识,你应该能够开始你的个人项目,并拥有获得入门级计算机视觉工作职位所需的专业知识。
我建议你创建自己的项目,并参加一些竞赛。此外,如果你尝试在媒体上写作,展示你对计算机视觉和机器学习的主题和概念的理解,也会有所帮助。
本文列出了一些可以用来学习计算机视觉的方法,这是一个机器学习相关领域
towardsdatascience.com](/5-ways-you-can-learn-computer-vision-6dae3f312686)
问题 2(博士与硕士)
问题:
我最近开始了我作为毕业生的第一份人工智能工作,特别是在计算机视觉方面。我有计算机工程学士学位,但我正在考虑在大学里开始非全日制人工智能硕士课程,我会在工作时间之外的业余时间做这些。只是想知道,你有没有考虑过读博士,或者你觉得在人工智能领域工作一个硕士就足够了?
回答:
直接回答你的问题,我觉得一个硕士对于在 AI 领域工作来说绰绰有余。
高级资格证书的好处是,它提供了学术权威,也向潜在雇主表明你已经花时间专攻某一特定领域。
在进行求职时,我看到一些机器学习和人工智能职位要求申请人获得博士学位,但大多数职位要么非常专业,要么在公司的研究部门内。
博士学位向雇主表明,你可以在某个领域的某个特定领域投入时间,成为某种程度上的专家,并为该领域的发展做出贡献。对于行业中的大多数机器学习角色来说,这并不完全必要。
我会说,你应该去攻读硕士学位,并全力以赴,或许如果你在机器学习领域找到了自己感兴趣的领域,那么你可以攻读博士学位。
目前,我没有考虑读博士,因为我想在机器学习和计算机视觉领域建立一个坚实的五年职业生涯。
也许我会在 7 年左右的时间里评估我的决定。
探索攻读机器学习博士学位的好处
towardsdatascience.com](/should-you-take-a-phd-in-machine-learning-79530e1cb01c)
问题 3(机器学习研究与工程)
问题:
我希望从事这样一份工作:一半时间研究新的、令人兴奋的东西,一半时间阅读、写论文和编写代码,同时管理人员,解决现实世界的问题(我知道解决现实世界的问题是研究的一部分)。我不确定这样的角色是否存在。我觉得我正处于职业生涯的一个重要阶段,我需要做出重要的决定。考虑到你的经历,如果你能给我以上的建议,那就太神奇了。
回答:
关于寻找一个在工程和研究之间保持 50/50 平衡的角色,我将诚实地告诉你,并不是很多工作角色都能提供这种平衡,甚至不能在工作角色描述中定义正确的平衡。
正如我在我的文章中提到的,有很多工程师进行研究,反之亦然。但是我没有提到的一个关键点是,ML 研究人员角色和工程角色的平衡可以基于当前的需求和业务要求。
我发现在你为公司工作期间,工程和研究变化之间的平衡是基于公司当前的目标和重点。
以我为例,我申请了现在的职位,在工作描述和面试中,并没有提到我将进行任何深入的研究。但是在头两个月,我做的研究比工程多,但是头两个月后到现在,我做的工程比研究多。
我的建议是你继续尽你所能从人群中脱颖而出。使用最先进的机器学习方法的工程工具,还可以培养阅读和撰写研究论文的技能。
当你到了申请角色的阶段,一定要问清楚工程和研究之间的平衡是什么。
你会发现很难找到一个完美的 50/50 平衡的角色,但有一些工作机会,你可以定义你想要的平衡类型,尽管它们很少,但它们仍然存在。
问题 4(机器学习职业可能性)
问题:
我一直在想我是否有可能成为一名计算机视觉工程师。我不是博士,也没有硕士学位,我只是一名毕业生。你有什么建议?
回答
我建议看看你所在的地方对计算机视觉工程师的工作角色要求。
确定你需要了解哪些技能、技术、算法、编程语言和工具,并确保你正在获取它们。
接下来,为了弥补资格的不足,我建议如果可以的话,考虑攻读硕士学位。但如果你无法追求机器学习的高级学位,那么你可以考虑以下选项:
- 参加在线计算机视觉相关课程,完成后提供证书。 Udacity 适合这个:
2.拥有 3-5 个令人印象深刻的计算机视觉/机器学习项目的项目组合。
3.看看如何完成 Kaggle 挑战。
结论
我希望您已经从这篇文章的内容中发现了一些价值。
有人将我的经验和专业知识视为一个学习点,这非常令人羞愧。如果你有任何问题想问我,或者你可能更喜欢我更详细地阐述一些问题的答案,那么你可以像往常一样通过 LinkedIn 联系我。
我不愿意回答机器学习相关的问题或疑问,因为我知道这个领域有多困难和具有挑战性,所以请不要羞于问任何紧迫的问题。我会尽力提供合适的答案。
我希望这篇文章对你有用。
要联系我或找到更多类似本文的内容,请执行以下操作:
Python 中常用的时间序列数据分析方法和预测模型
使用 ARIMA 和 LSTM 模型分析用于预测的时间序列数据
作者照片
时间序列是以相等的时间间隔按时间顺序获取的数据样本序列。时间序列包括来自金融、医学、科学研究(如全球变暖、语音分析、地震)等不同领域的多种真实实验数据。[1][2].时间序列预测在各个领域都有很多实际应用,例如商业预测(如销售、股票)、天气、死亡等[1]。
给定用于预测的监督机器学习的传统(时间顺序独立)数据集,在可以执行特征工程之前需要数据探索和预处理,并且在可以选择机器学习模型并将其应用于工程特征以进行预测之前需要完成特征工程。
与传统数据集类似,给定一个时间序列数据集,在可以分析时间序列数据之前,需要进行数据探索和预处理,并且在可以选择时间序列预测模型并将其应用于所分析的数据集以进行预测之前,需要进行时间序列数据分析。
在本文中,我使用 Kaggle [2]的全球变暖数据集来演示 Python 中一些常见的时间序列数据预处理/分析方法和时间序列预测模型。演示包括以下内容:
- 时间序列数据预处理
- 时间序列数据分析
- 时间数列预测法
1.时间序列数据预处理
如前所述,对于时间序列数据,在进行数据分析之前,需要进行数据预处理。
1.1 加载数据
数据预处理的第一步是从 csv 文件加载数据。
时间顺序在时间序列数据分析和预测中起着至关重要的作用。特别是,时间序列中的每个数据样本必须与唯一的时间点相关联。这可以在 Pandas DataFrame/Series 中通过使用 DatetimeIndex 类型的值作为其索引值来实现。
一旦 Kaggle [2]中的地球表面温度数据集被下载到本地机器上,数据集 csv 文件可被加载到 Pandas 数据帧中,如下所示:
df_raw = pd.read_csv('./data/GlobalTemperatures.csv', parse_dates=['dt'], index_col='dt')
df_raw.head()
选项 parse_dates 是告诉 Pandas 将 dt 列中的字符串值解析为 Python datatime 值,而选项 index_col 是告诉 Pandas 将 dt 列的解析值转换为 DatatimeIndex 类型,然后将它们用作索引。
为了简单起见,我提取了 LandAverageTemperature 列作为 Pandas 系列,以便在本文中进行演示:
df = df_raw['LandAverageTemperature']
1.2 处理缺失数据
与传统数据集类似,时间序列数据中经常出现缺失数据,在对数据进行进一步预处理和分析之前,必须对其进行处理。
以下代码可以检查缺少多少数据条目:
df.isnull().value_counts()
地球表面温度时间序列中有 12 项缺失数据。在不破坏过去的时间相关性的情况下,这些丢失的值不能简单地被移除或设置为零。有多种方法可以恰当地处理时间序列中的缺失数据[3]:
- 向前填充
- 反向填充
- 线性内插法
- 二次插值法
- 最近邻居的平均值
- 季节对比平均值
我使用向前填充来填充本文中缺少的数据条目:
df = df.ffill()
2.时间序列数据分析
一旦数据预处理完成,下一步就是分析数据。
2.1 可视化数据
作为一种常见的实践[1][3][4],时间序列数据分析的第一步是将数据可视化。
以下代码使用 Pandas DataFrame/Series 内置绘图方法绘制地球表面温度时间序列:
ax = df.plot(figsize=(16,5), title='Earth Surface Temperature')
ax.set_xlabel("Date")
ax.set_ylabel("Temperature")
图 1: 地球表面温度。
上图显示,地球表面的平均温度大约在[5,12]的范围内,总体趋势是缓慢上升。由于不同时间序列成分(如基准水平、趋势、季节性)和其他成分(如误差和随机噪声)的混合,图中没有显示其他明显的模式[1][3]。时间序列可以分解成单个的部分,以便进一步分析。
2.2 将数据分解成组件
为了将一个时间序列分解成组件以供进一步分析,可以将该时间序列建模为基准水平、趋势、季节性和误差(包括随机噪声)的加法或乘法[3]:
- 加法时间序列 :
数值 = 基数 + 趋势 + 季节性 + 误差 - 乘法时间序列 :
数值 = 基数水平 x 趋势 x 季节性 x 误差
本文将地表温度时间序列建模为相加时间序列;
additive = seasonal_decompose(df, model='additive', extrapolate_trend='freq')
选项extrapolate_trend='freq'
是处理时间序列开始时趋势和残差中的任何缺失值[3]。
理论上,通过将选项模型=‘加法’替换为模型=‘乘法’,可以很容易地将相同的数据集建模为乘法时间序列。然而,乘法模型不能应用于该特定数据集,因为数据集包含零值和/或负值,这在乘法季节性分解中是不允许的。
加法分解的结果分量可以被提取以形成如下的熊猫数据帧:
additive_df = pd.concat([additive.seasonal, additive.trend, additive.resid, additive.observed], axis=1)
additive_df.columns = ['seasonal', 'trend', 'resid', 'actual_values']
additive_df.head()
下面的代码是可视化的相加分解成分:趋势、季节和残差(即,基础水平+误差)。
plt.rcParams.update({'figure.figsize': (10,10)})
additive.plot().suptitle('Additive Decompose')
图 2: 时间序列分解。
对于地表温度时间序列数据,我们最感兴趣的是其长期趋势,可提取如下:
trend = additive.trend
图 3: 地表温度趋势。
3.时间数列预测法
一旦数据预处理和分析完成,时间序列预测就可以开始了。
本节介绍了将两种常见的时间序列预测模型应用于地球表面温度趋势数据的结果:
3.1 ARIMA 模式
ARIMA 模型[1][4]由三个参数决定:
- p :自回归顺序
- d :使时间序列平稳的差分顺序
- 问:均线下单
ARIMA 模型由三部分组成[4]:自回归(AR)、移动平均(MA)和一个常数:
ARIMA =常数+ AR + MA
在哪里
AR =过去时间点的 p 连续值的线性组合(即滞后)
MA =线性组合 q 过去时间点的连续预测误差(即滞后预测误差)
AR 和 MA 都只能应用于平稳的时间序列,这是通过 ARIMA 差分实现的。
3.1.1 确定差分 d 的阶数
一个时间序列是(弱)平稳的如果它的均值是常数(与时间无关)并且它的 自协方差 在时间序列的两个不同时间点 s 和 t 之间的函数只取决于时间间隔|s - t|(即滞后),而不是特定的时间点[1]。
时间序列预测仅对平稳时间序列有效,因为只有平稳时间序列的行为是可预测的。
我们可以使用 ADF 检验(扩展的 Dickey Fuller 检验 ) [4]来检验一个时间序列是否是平稳的。例如,下面的代码将检查地球表面温度时间序列的平稳性:
from statsmodels.tsa.stattools import adfullerresult = adfuller(trend.values)
print('ADF Statistic: %f' % result[0])
print('p-value: %f' % result[1])
测试的 p 值为 0.012992。
ADF 检验的默认零假设是时间序列是非平稳的。由于上述 ADF 测试的 p 值小于 0.05 的显著性水平,我们拒绝零假设,并得出时间序列是平稳的结论(在这种情况下只有趋势平稳)。
一般来说,要使时间序列平稳,需要做以下工作:
- 移除会随时间改变均值和/或协方差的不规则行为
- 去除可能随时间改变均值和/或协方差的常规行为,如趋势和季节性
差分是一种常用的数据转换方法,用于消除非平稳行为(尤其是趋势)。
以下代码用于对地表温度时间序列进行一阶和二阶差分:
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf# Original Series
fig, axes = plt.subplots(3, 2, sharex=True)
axes[0, 0].plot(trend.values); axes[0, 0].set_title('Original Series')
plot_acf(trend.values, ax=axes[0, 1]).suptitle('Original Series', fontsize=0)# 1st Differencing
diff1 = trend.diff().dropna()
axes[1, 0].plot(diff1.values)
axes[1, 0].set_title('1st Order Differencing')
plot_acf(diff1.values, ax=axes[1, 1]).suptitle('1st Order Differencing', fontsize=0)# 2nd Differencing
diff2 = trend.diff().diff().dropna()
axes[2, 0].plot(diff2.values)
axes[2, 0].set_title('2nd Order Differencing')
plot_acf(diff2.values, ax=axes[2, 1]).suptitle('2nd Order Differencing', fontsize=0)
下图显示一阶差分足以消除趋势。二阶差分没有任何改进。因此,在本文中,差分顺序 d 被设置为 1。
图 4: 一阶和二阶差分。
3.1.2 确定自回归阶数 p
通过分析时间序列数据[1][4]的一阶差分的 PACF ( 偏自相关函数)的结果,可以确定自回归阶数 p :
plt.rcParams.update({'figure.figsize':(9,3), 'figure.dpi':120})size = 100fig, axes = plt.subplots(1, 2, sharex=True)
axes[0].plot(diff1.values[:size])
axes[0].set_title('1st Order Differencing')
axes[1].set(ylim=(0,5))
plot_pacf(diff1.values[:size], lags=50, ax=axes[1]).suptitle('1st Order Differencing', fontsize=0)
我们可以观察到 PACF 滞后 1 远远高于显著性线(灰色区域)。因此,自回归顺序 p 在本文中被设置为 1。
图 5: 一阶差分 PACF。
3.1.3 确定移动平均顺序 q
移动平均阶数 q 可以通过分析时间序列数据的一阶差分的自相关函数(ACF)的结果来确定[1][4]:
plt.rcParams.update({'figure.figsize':(9,3), 'figure.dpi':120})size = 100fig, axes = plt.subplots(1, 2, sharex=True)
axes[0].plot(diff1.values[:size])
axes[0].set_title('1st Order Differencing')
axes[1].set(ylim=(0,1.2))
plot_acf(diff1.values[:size], lags=50, ax=axes[1]).suptitle('1st Order Differencing', fontsize=0)
我们可以观察到 ACF 滞后 1 远远高于显著性线(灰色区域)。因此,在本文中,移动平均顺序 q 也被设置为 1。
图 6: 一阶差分的 ACF。
3.1.4 培训 ARIMA 模型
以下代码首先将地表温度趋势时间序列分为训练和测试子序列,然后使用训练数据训练一个 ARIMA 模型,其确定值为 p =1, d =1, q = 1。
传统的数据集通常被随机分为训练和测试子集。但是,这对时间序列无效,因为它打破了顺序时间依赖性。为了避免这个问题,温度趋势时间序列数据通过保持其原始顺序来划分。
from statsmodels.tsa.arima_model import ARIMAtrain = trend[:3000]
test = trend[3000:]# order = (p=1, d=1, q=1)
model = ARIMA(train, order=(1, 1, 1))
model = model.fit(disp=0)
print(model.summary())
从上面的模型训练结果可以看出,p>|z|列中 AR1 和 MA1 的 P 值是高度显著的(<< 0.05). This indicates that the choices of p =1 and q =1 are appropriate.
The code below is to plot the residuals.
# Plot residual errors
residuals = pd.DataFrame(model.resid)
fig, ax = plt.subplots(1,2)
residuals.plot(title="Residuals", ax=ax[0])
residuals.plot(kind='kde', title='Density', ax=ax[1])
The plot of the residuals shows no patterns (i.e., with constant mean and variance) except for the first 20% of the time series. This indicates that the trained ARIMA model behaves appropriately.
图 7: 残差分布。
3.1.5 使用训练好的 ARIMA 模型进行预测
下面的代码使用经过训练的 ARIMA 模型来预测 192 个(可以是任何正整数)温度值,然后将它们与测试时间序列进行比较:
# Forecast: 192 forecasting values with 95% confidence
fc, se, conf = model.forecast(192, alpha=0.05)# Make as pandas series
fc_series = pd.Series(fc, index=test.index)
lower_series = pd.Series(conf[:, 0], index=test.index)
upper_series = pd.Series(conf[:, 1], index=test.index)# Plot
plt.figure(figsize=(12,5), dpi=100)
plt.plot(train, label='training')
plt.plot(test, label='actual')
plt.plot(fc_series, label='forecast')
plt.fill_between(lower_series.index, lower_series, upper_series,
color='k', alpha=.15)
plt.title('Forecast vs Actuals')
plt.legend(loc='upper left', fontsize=8)
图 8: 利用 ARIMA 进行气温预报。
上述预测结果表明,经过训练的 ARIMA 模型预测的温度往往低于实际温度。
3.2 LSTM 模式
本节介绍将著名的 LSTM 模型应用于地球表面温度趋势时间序列的结果。
3.2.1 准备数据集
与[6]类似,下面的代码从温度时间序列中生成特征向量对(过去时间点的温度值序列)和标签对(当前时间点的目标温度),用于 LSTM 模型训练和评估。
from numpy import array
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers import Densedef split_sequence(sequence, n_steps):
X, y = list(), list()
for i in range(len(sequence)):
# find the end of this pattern
end_ix = i + n_steps
# check if we are beyond the sequence
if end_ix > len(sequence)-1:
break
# gather input and output parts of the pattern
seq_x, seq_y = sequence[i:end_ix], sequence[end_ix]
X.append(seq_x)
y.append(seq_y)
return array(X), array(y)# define input sequence
raw_seq = trend.tolist()
# choose a number of time steps
n_steps = 12
# split into samples
X, y = split_sequence(raw_seq, n_steps)
为了简单起见,在本文中,我使用过去 12 个月的温度来预测下个月的温度。以下是生成的数据集的两个示例:
生成的数据集分为两部分:前 3000 个数据集用于模型训练,其余数据集用于模型测试:
X_train = X[:3000]
y_train = y[:3000]
X_test = X[3000:]
y_test = y[3000:]
3.2.2 选择 LSTM 型号
以下 LSTM 模型[6]将一系列温度值作为输入,并生成一个目标温度作为输出。由于温度预测是一个回归问题,LSTM 模型的输出可以取任何值,因此没有相关的激活函数。
n_features = 1X_train = X_train.reshape((X_train.shape[0], X_train.shape[1], n_features))# define model
model = Sequential()
model.add(LSTM(50, activation='relu', input_shape=(n_steps, n_features)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
# fit model
model.fit(X_train, y_train, epochs=200, verbose=1)
3.2.3 培训 LSTM 模型
以下是模型训练的结果:
3.2.4 使用训练好的 LSTM 模型进行预测
一旦模型训练完成,经过训练的 LSTM 模型就可以应用于测试时间序列来预测温度:
X_test = X_test.reshape((X_test.shape[0], X_test.shape[1], n_features))
y_pred = model.predict(X_test, verbose=0)
下面的代码将预测温度与测试时间序列中的实际温度进行了对比:
def plot_forecosting(df1, df2, line_stype1='b-', line_stype2='r--', title="", xlabel='Date', ylabel='Temperature', dpi=100):
plt.figure(figsize=(16,5), dpi=dpi)
plt.plot(df1.index, df1, line_stype1, label='actual')
plt.plot(df2.index, df2, line_stype2, label='forecast')
plt.gca().set(title=title, xlabel=xlabel, ylabel=ylabel)
plt.title('Forecast vs Actuals')
plt.legend(loc='upper left', fontsize=8)
plt.show()y_pred_1 = y_pred.reshape((y_pred.shape[0]))
y_pred_series = pd.Series(y_pred_1)
y_test_1 = y_test.reshape((y_test.shape[0]))
y_test_series = pd.Series(y_test_1)plot_forecosting(y_test_series, y_pred_series, title='Land Average Temperature')
图 9: 利用 LSTM 进行气温预报。
预测温度与整个温度趋势时间序列的关系如下:
X_all = X.reshape((X.shape[0], X.shape[1], n_features))
y_pred_all = model.predict(X_all, verbose=0)
y_pred_all_1 = y_pred_all.reshape((y_pred_all.shape[0]))
y_pred_all_series = pd.Series(y_pred_all_1)
y_all = y.reshape((y.shape[0]))
y_all_series = pd.Series(y_all)
plot_forecosting(y_all_series, y_pred_all_series, title='Land Average Temperature')
图 10: 利用 LSTM 进行全时间序列的温度预报。
上述预报结果表明,预报温度与实际温度非常接近。
4.摘要
在本文中,我使用了 Kaggle [2]的全球变暖数据集来演示一些常见的时间序列数据预处理/分析实践,以及 Python 中两个广泛采用的时间序列预测模型 ARIMA 和 LSTM。
从第 3 节可以看出,ARIMA 模型的性能严重依赖于数据预处理和分析,以使时间序列平稳,而 LSTM 可以用最少的数据预处理和分析来处理时间序列(例如,在 LSTM 模型中不需要通过差分来消除趋势)。
本文中使用的所有源代码都可以在 Github [7]中找到。
参考
- R.Shumway 和 D. Stoffer,时间序列分析及其应用,Springer,第 4 版,2017 年
- 气候变化:地表温度数据
- 南 Prabhakaran,Python 中的时间序列分析—带示例的综合指南
- 南普拉巴卡兰, ARIMA 模型 Python 中时间序列预测的完整指南
- J.Brownlee,如何用 Python 中的差分变换去除趋势和季节性
- J.Brownlee,如何开发用于时间序列预测的 LSTM 模型
- Y.张 Github 中的 Jupyter 笔记本
您是否有效地传播了您的数据?
你可能听说过,数据已经成为一种东西。这个空间迅速成长,它的受欢迎程度和兴趣从未如此之大。
然而,尽管对数据的需求很大,你可能会惊讶地发现,为了有效地交流结果,你需要为你的数据和分析(DNA)实践建立多大的兴奋度。有效地宣传你的团队的使命和成果应该是一个关键的焦点领域,以便给你的工作带来它需要的曝光率。您现在可能没有想到这一点,但您的部分职责是教育人们如何使用数据,并管理围绕数据的对话。
这里有一些有用的提示,告诉你如何做到这一点。
仪表板丰富多彩。
好吧,也许不多。你不希望有太多的仪表板,但是你做的那些仪表板应该既引人注目又能提供信息。仪表板的主要目的是自动化您收到请求的任何机械报告。然而,次要目的是可见性。
仪表板是您的团队工作的最直接和可见的表示。甚至在你的团队下班回家后,它们仍然可以被访问,而且,正如在许多组织中越来越受欢迎的那样,它们可以被打开并显示在分散在你办公室的监视器上,就像在交易大厅一样。考虑到它们的可见性,花些时间设计它们,以便它们能抓住你的观众的注意力,并传达具有清晰、明确和有价值的目的的信息,同时展示数据在你的组织内是如何被使用的。
走老派路线——用模拟方式交流,以建立关系
我相信高质量的人际交往有很多价值。在一个一切都是数字化的世界,一个极大地促进了您的工作的世界,找到识别和增强模拟通信通道的方法会有很大的好处。如果你想传福音,面对面做是有好处的。
做到这一点的一个方法是找到鼓励人们提交工作请求或问题陈述或假设的方法,他们希望你亲自解决,而不是通过数字方式。这有很多好处。首先,他们会见到你和你的团队。其次,你会发现,当提交问题需要花费更多努力时,人们会更严谨地思考问题。像这样一个简单的改变可以提高你开始收到的问题的质量。最后,你能够开始对话,并直接从源头获得有价值的背景信息。对话的流程可能会向多个方向发展,让你和你的对手更好地了解情况,这是所有相关方的双赢。
发现像这样的小块机会将会提高你的团队的可见性和有效性。
未知的未知
随着许多组织的数据急剧增长,非数据人员很难跟上可用的数据。不管你是否知道,你的一部分职责是教育人们什么样的数据在那里,以及如何使用。存在的数据越清晰,你的涉众的思维就会越快开始思考,并为你的团队设计要解决的问题。这意味着您将获得更多的参与度和知名度!把这些数据公之于众,激发人们的好奇心,以此来激励非技术人员。
这可以通过在前面提到的仪表板上突出它们来实现。也可以通过展示来自其他业务部门的见解来实现,这样你的受众就可以了解哪些数据正在被使用,哪些问题正在被组织的其他部门解决,而不是他们自己的部门
请谈谈你的数据。
使用数据语言交谈的人越多越好。优秀的数据科学家的职责之一(在一些组织中是完全独立的角色)是成为优秀的数据翻译者。如果翻译的东西少了,这项工作会变得容易些。所以,定期向非数据人员传授你的方法,这是你自己的责任。花点时间谈谈你所使用的方法,以及你在这个过程中所做的任何选择的原因——而不仅仅是你所取得的结果。明确指出你所做的工作应该如何被使用,它意味着什么,包括它可能会被误解。实际上,你是在总结自己的工作——让别人更容易理解。
因此,在传达团队成果时,要像产生这些成果一样认真对待自己的角色。确保由你来主导对话,因为这有助于确定数据在您的组织内的使用效率
这个故事最初出现在这里
基于朋友社区特征的 R 语言社区检测
每个角色都有自己的迷你网络,但是它是什么样子的呢?
在本文中,我将使用 R 中的igraph
包中的社区检测功能来展示如何检测网络中的社区。在文章结束时,我们将能够看到 Louvain 社区检测算法如何将朋友角色分成不同的社区(忽略六个主要角色的明显社区),如果你是该剧的粉丝,你可以决定这个分析对你是否有意义。
读者注意: 如果你发现在中等格式的环境中很难理解代码,你也可以在这里 以降价格式 重新阅读。
用于组合朋友角色网络的数据
在我之前的文章中,我展示了如何使用迭代编程为《老友记》的整个系列生成一个网络边缘列表。网络边列表是一个简单的数据集,包含以下内容:
from
和to
列为了确定我们的(无向)网络中字符对之间的连接,每个字符将是一个节点,每个连接将是一条边。- 一个
weight
列(这是边的一个属性),表示线对之间的连接强度。在这种情况下,这是由这对搭档一起出现在不同场景中的次数决定的。
我使用的 edgelist 是使用前两篇文章中的技术生成的,并在这个项目的 repo 中加载到 Github。我现在将所有十个季节的数据集拉下来,我们可以看看它。
library(tidyverse)
library(readr)
library(igraph) # get friends full series edgelist
edgefile_url <- "https://github.com/keithmcnulty/friends_analysis/blob/master/data/friends_full_series_edgelist.RDS?raw=true" download.file(edgefile_url, "edgelist.RDS")
edgelist <- readRDS("edgelist.RDS") knitr::kable(edgelist %>% head(10))
这看起来和我们预期的一样。所以我们准备开始一些工作。
在igraph
使用鲁文算法寻找社区
现在,首先,我们要假装六个主要人物彼此不认识,并删除我们网络中他们之间的所有边。这是因为我们对其他角色如何围绕主要角色形成社区感兴趣。如果我们让主要角色的联系保持完整,我们知道他们会在他们之间形成一个非常强大的社区,这当然是这部剧的全部意义。
friends <- c("Phoebe", "Monica", "Rachel", "Joey", "Ross", "Chandler") edgelist_without <- edgelist %>%
dplyr::filter(!(from %in% friends & to %in% friends))
现在,我们将把新的 edgelist 转换成一个矩阵,然后用它来构建一个 graph 对象,该对象将weight
列作为边的属性:
edgelist_matrix <- as.matrix(edgelist_without[ ,c("from", "to")]) friends_graph <- igraph::graph_from_edgelist(edgelist_matrix, directed = FALSE) %>%
igraph::set.edge.attribute("weight", value = edgelist_without$weight)
我们现在可以快速浏览一下我们的朋友图表:
真是一团糟
好吧,真是一团糟——考虑到这个网络中有 650 个顶点(字符)和 2961 条边(连接),这并不奇怪。我们将不得不在稍后为一些好的情节做一些格式化。但是现在我们准备要求 Louvain 算法将这个网络分成不同的社区。该算法将尝试最大化社区内部的连接强度,并最小化不同社区之间的连接。
# run louvain with edge weights
louvain_partition <- igraph::cluster_louvain(friends_graph, weights = E(friends_graph)$weight) # assign communities to graph
friends_graph$community <- louvain_partition$membership # see how many communities there are
unique(friends_graph$community) ## [1] 4 6 1 7 3 8 5 2
看起来算法找到了 8 个社区。但是我们不知道谁在里面。我们可以做一些事情来更好地了解每个社区。
- 我们可以看看每个社区有多大。有时,社区可能很小,代表着网络中几乎完全不相连的部分(就像一些角色之间的随机场景,再也不会出现)。
- 我们可以看看每个社区中“最重要”的人(顶点)。这样做的一种方式是寻找具有最高中间中心性的顶点,即连接该社区中最多角色的人。
communities <- data.frame() for (i in unique(friends_graph$community)) { # create subgraphs for each community subgraph <- induced_subgraph(friends_graph, v = which(friends_graph$community == i)) # get size of each subgraph
size <- igraph::gorder(subgraph) # get betweenness centrality
btwn <- igraph::betweenness(subgraph) communities <- communities %>%
dplyr::bind_rows(data.frame(
community = i,
n_characters = size,
most_important = names(which(btwn == max(btwn)))
)
)
} knitr::kable(
communities %>%
dplyr::select(community, n_characters, most_important)
)
好的——我们看到有几个社区看起来很小,可能很不相关(我们将在附录中查看这些社区),但主要的六个社区都围绕着六个朋友,这是我们所期望的。这证实了六个角色中的每一个,尽管他们彼此很接近,但也在整个系列中培养了相当独立的社区。
我们可以通过查看每个社区(不包括小社区)中最重要的五个角色来了解这些社区。这一次,我们将着眼于一个更简单的性能指标——每个角色拥有的连接数,或者他们在网络中的度。
top_five <- data.frame() for (i in unique(friends_graph$community)) { # create subgraphs for each community
subgraph <- induced_subgraph(friends_graph, v = which(friends_graph$community == i)) # for larger communities
if (igraph::gorder(subgraph) > 20) { # get degree
degree <- igraph::degree(subgraph) # get top five degrees
top <- names(head(sort(degree, decreasing = TRUE), 5)) result <- data.frame(community = i, rank = 1:5, character = top)
} else {
result <- data.frame(community = NULL, rank = NULL, character = NULL)
} top_five <- top_five %>%
dplyr::bind_rows(result)
} knitr::kable(
top_five %>%
tidyr::pivot_wider(names_from = rank, values_from = character)
)
我们在这里看到一些通用的角色名字,如“男”或“女”。如果我们忽略这些,我们可以看到以下人物群体:
- 菲比和她生命中的男人:她最终的丈夫迈克,她吸毒成瘾的按摩客户史蒂夫,以及她同父异母的弟弟弗兰克(也是她父亲的名字)
- 莫妮卡,她的父母和男朋友们:钱德勒在这里失踪了,当然是因为施工!
- 钱德勒和珍妮丝:在《六人行》之外,钱德勒限制了与珍妮丝之外的重复角色的联系。
- 乔伊和他的演艺人脉:除了巩特尔——他属于乔伊的圈子——乔伊大部分时间都和导演和经纪人在一起。
- 瑞秋,她的孩子和她的妹妹:瑞秋的社区主要围绕着她在第八季的孩子的出生。
- 罗斯、卡罗尔和苏珊:罗斯的社区被他的前妻卡罗尔和她的女友苏珊,以及他的古生物学教授女友查理·惠勒的场景所占据。
可视化社区
我们现在可以试着把这些社区想象成整个网络的一部分。为了更容易理解,我们将去掉除了六个朋友以外的所有人的标签,然后我们将按社区对顶点和边进行颜色编码。
# give our nodes some properties, incl scaling them by degree and coloring them by community V(friends_graph)$size <- 3 V(friends_graph)$frame.color <- "white" V(friends_graph)$color <- friends_graph$community V(friends_graph)$label <- V(friends_graph)$name V(friends_graph)$label.cex <- 1.5 # also color edges according to their starting node edge.start <- ends(friends_graph, es = E(friends_graph), names = F)[,1]
E(friends_graph)$color <- V(friends_graph)$color[edge.start] E(friends_graph)$arrow.mode <- 0 # only label central characters v_labels <- which(V(friends_graph)$name %in% friends) for (i in 1:length(V(friends_graph))) {
if (!(i %in% v_labels)) { V(friends_graph)$label[i] <- "" }
}
现在我们可以绘制图表了。“最漂亮”的地块可能是球形布局:
l1 <- layout_on_sphere(friends_graph)
plot(friends_graph, rescale = T, layout = l1, main = "'Friends' Network - All Seasons")
球形布局
但是为了更好地从视觉上区分社区,武力导向的情节是合适的:
l2 <- layout_with_mds(friends_graph)
plot(friends_graph, rescale = T, layout = l2, main = "'Friends' Network - All Seasons")
力导向布局
第二张图片更有帮助,因为它暗示乔伊和罗斯可能会过着更“独立”的生活,与其他四个角色相比,他们有更多自己的社区,因为力导向算法使他们与其他人的距离更远。
附录:谁是较小的社区?
让我们看看在我们之前的分析中出现的两个较小的社区。我们来看看这些社区都有哪些人。
small_communities <- data.frame() for (i in unique(friends_graph$community)) { # create subgraphs for each community
subgraph <- induced_subgraph(friends_graph, v = which(friends_graph$community == i)) # for larger communities
if (igraph::gorder(subgraph) < 20) {
# get degree
degree <- igraph::degree(subgraph) # get top ten degrees
top <- names(sort(degree, decreasing = TRUE)) result <- data.frame(community = i, rank = 1:length(top), character = top)
} else {
result <- data.frame(community = NULL, rank = NULL, character = NULL)
} small_communities <- small_communities %>%
dplyr::bind_rows(result)
} knitr::kable(
small_communities %>%
tidyr::pivot_wider(names_from = rank, values_from = character)
)
有趣的是,我们的算法似乎已经选取了几个特定的剧集,并将其中的场景视为它们自己的断开网络。
- 第一个社区似乎来自雷莫尔博士去世的地方
- 第二个似乎是来自在我做之后的那个
最初我是一名纯粹的数学家,后来我成为了一名心理计量学家和数据科学家。我热衷于将所有这些学科的严谨性应用到复杂的人的问题上。我也是一个编码极客和日本 RPG 的超级粉丝。在LinkedIn或Twitter上找我。也可以看看我在drkeithmcnulty.com上的博客。
Neo4j 图形数据科学对世界各国的社区检测
使用 Neo4j 图形数据科学库进行网络分析,包括要素缩减技术、相似性网络推理和社区检测
在我等待发面的时候,我想,消磨时间的最好方式是使用 Neo4j 图形数据科学库进行网络分析。嗯,也许还可以试着画一幅丙烯画,但我不会让你厌烦的。如果这是你第一次听说 GDS 图书馆,我可以推荐一些我以前的博客文章,试图解释基本知识:
如果你准备好了,是时候戴上我们的图形数据科学的帽子,进入正题了。
要求:
图表模式
我们将使用由 Fernando Lasso 在 Kaggle 上提供的世界各国数据集。看一下致谢,数据来源于中情局的世界概况。不幸的是,贡献者没有提供数据汇编的年份。我的猜测是 2013 年,但我可能是错的。该数据集包含各种指标,如面积大小、人口、婴儿死亡率以及世界上约 227 个国家的数据。
图表模式
图表模式由标记为国家的节点组成,这些节点将它们的特征存储为属性。一个国家也是一个地区的一部分。
图形导入
首先,我们需要下载数据集,并将其复制到$Neo4j/import
文件夹中。出于某种原因,CSV 文件中的数字使用逗号作为浮点,而不是点( 0,1 而不是 0.1 )。我们需要对数据进行预处理,以便能够将数字转换为 Neo4j 中的浮点数。在 APOC 过程apoc.cypher.run
的帮助下,我们可以在一个 cypher 查询中预处理和存储数据。apoc.cypher.run
允许我们在主 cypher 查询中运行独立的子查询,非常适合各种用例。
LOAD CSV WITH HEADERS FROM "file:///countries%20of%20the%20world.csv" as row
// cleanup the data and replace comma floating point with a dot
CALL apoc.cypher.run(
"UNWIND keys($row) as key
WITH row,
key,
toFloat(replace(row[key],',','.')) as clean_value
// exclude string properties
WHERE NOT key in ['Country','Region']
RETURN collect([key,clean_value]) as keys",
{row:row}) YIELD value
MERGE (c:Country{name:trim(row.Country)})
SET c+= apoc.map.fromPairs(value.keys)
MERGE (r:Region{name:trim(row.Region)})
MERGE (c)-[:PART_OF]->(r)
识别缺失值
另一个有用的 APOC 程序是apoc.meta.nodeTypeProperties
。有了它,我们可以检查图的节点属性模式。我们将使用它来确定国家的每个要素有多少个缺失值。
// Only look at properties of nodes labeled "Country"
CALL apoc.meta.nodeTypeProperties({labels:['Country']})
YIELD propertyName, propertyObservations, totalObservations
RETURN propertyName,
(totalObservations - propertyObservations) as missing_value,
(totalObservations - propertyObservations) / toFloat(totalObservations) as pct_missing_value
ORDER BY pct_missing_value DESC LIMIT 10
结果
看起来我们没有太多缺失的值。然而,为了简单起见,我们将在进一步的分析中忽略缺失值超过四个的特性。
高相关滤波器
高相关滤波是一种简单的数据降维技术。具有高相关性的特征可能携带相似的信息,并且更加线性相关。使用具有相关信息的多个特征会降低各种模型的性能,可以通过删除两个相关特征中的一个来避免。
// Only look at properties of nodes labeled "Country"
CALL apoc.meta.nodeTypeProperties({labels:['Country']})
YIELD propertyName, propertyObservations, totalObservations
WITH propertyName,
(totalObservations - propertyObservations) as missing_value// filter our features with more than 5 missing values
WHERE missing_value < 5 AND propertyName <> 'name'
WITH collect(propertyName) as features
MATCH (c:Country)
UNWIND features as feature
UNWIND features as compare_feature
WITH feature,
compare_feature,
collect(coalesce(c[feature],0)) as vector_1,
collect(coalesce(c[compare_feature],0)) as vector_2
// avoid comparing with a feature with itself
WHERE feature < compare_feature
RETURN feature,
compare_feature,
gds.alpha.similarity.pearson(vector_1, vector_2) AS correlation
ORDER BY correlation DESC LIMIT 10
结果:
有趣的是出生率和婴儿死亡率密切相关。死亡率也与婴儿死亡率密切相关,因此我们将降低出生率和死亡率,但保持婴儿死亡率。手机数量和净移民似乎与国内生产总值相关。我们也将放弃这两项,保持 GDP 不变。我们还将减少人口,保留面积和人口密度,这两者携带类似的信息。
特征统计
至此,我们只剩下八个特征。我们将用apoc.agg.statistics
函数来检验它们的分布。它计算数值统计,例如一组值的最小值、最大值和百分位数。
// define excluded features
WITH ['name',
'Deathrate',
'Birthrate',
'Phones (per 1000)',
'Net migration',
'Population'] as excluded_features
CALL apoc.meta.nodeTypeProperties({labels:['Country']})
YIELD propertyName, propertyObservations, totalObservations
WITH propertyName,
(totalObservations - propertyObservations) as missing_value
WHERE missing_value < 5 AND
NOT propertyName in excluded_features
// Reduce to a single row
WITH collect(propertyName) as potential_features
MATCH (c:Country)
UNWIND potential_features as potential_feature
WITH potential_feature,
apoc.agg.statistics(c[potential_feature],
[0.5,0.75,0.9,0.95,0.99]) as stats
RETURN potential_feature,
apoc.math.round(stats.min,2) as min,
apoc.math.round(stats.max,2) as max,
apoc.math.round(stats.mean,2) as mean,
apoc.math.round(stats.stdev,2) as stdev,
apoc.math.round(stats.`0.5`,2) as p50,
apoc.math.round(stats.`0.75`,2) as p75,
apoc.math.round(stats.`0.95`,2) as p95,
apoc.math.round(stats.`0.99`,2) as p99
结果
密克罗尼西亚联邦的海岸与面积之比为 870,令人印象深刻。另一方面,世界上共有 44 个国家的海岸线为零。另一个有趣的事实是,格陵兰有 56361 名居民和 2166086 平方英里的人口密度约为每平方英里 0。这可能是一个进行社交距离的好地方。
我们可以观察到,大多数特征似乎是描述性的,除了其他的(%),大多数在 80 到 100 之间。由于低方差,我们将在进一步的分析中忽略它。
填充缺少的值
我们只剩下七个特征,我们将用它们来推断国家之间的相似性网络。在此之前,我们需要做的一件事是填充缺失的值。我们将使用一种简单的方法,用国家所在地区的平均值来填充要素的缺失值。
UNWIND ["Arable (%)",
"Crops (%)",
"Infant mortality (per 1000 births)",
"GDP ($ per capita)"] as feature
MATCH (c:Country)
WHERE c[feature] IS null
MATCH (c)-[:PART_OF]->(r:Region)<-[:PART_OF]-(other:Country)
WHERE other[feature] IS NOT null
WITH c,feature,avg(other[feature]) as avg_value
CALL apoc.create.setProperty(c, feature, avg_value)
YIELD node
RETURN distinct 'missing values populated'
最小最大归一化
最后但同样重要的是,我们必须将我们的特征标准化,以防止任何单一特征由于较大的规模而支配其他特征。我们将使用标准化的简单的最小最大方法在 0 和 1 之间重新调整特征。
UNWIND ["Arable (%)",
"Crops (%)",
"Infant mortality (per 1000 births)",
"GDP ($ per capita)",
"Coastline (coast/area ratio)",
"Pop. Density (per sq. mi.)",
"Area (sq. mi.)"] as feature
MATCH (c:Country)
// Calculate the min and the max value for each feature
WITH max(c[feature]) as max,
min(c[feature]) as min,
feature
MATCH (c1:Country)
WITH c1,
// define property name to store back results
"n_" + feature AS newKey,
// normalize values
(toFloat(c1[feature]) - min) / (max - min) as normalized_value// store results to properties
CALL apoc.create.setProperty(c1, newKey, normalized_value)
YIELD node
RETURN distinct 'normalization done'
余弦相似的相似网络
我们已经完成了数据预处理,可以专注于数据分析部分。分析的第一步是借助于余弦相似性算法推断相似性网络。我们基于所选特征为每个国家构建一个向量,并比较每对国家之间的余弦相似性。如果相似性高于预定义的阈值,我们以相似节点对之间的关系的形式存储回结果。定义一个最佳阈值是艺术和科学的结合,通过实践你会做得更好。理想情况下,您想要推断一个稀疏图,因为社区检测算法在完整或密集图上表现不佳。在这个例子中,我们将使用 0.8 的similarityCutoff
值(范围在-1 和 1 之间)。除了相似性阈值,我们还将使用topK
参数来仅存储前 10 个相似的邻居。我们这样做是为了确保图形更稀疏。
MATCH (c:Country)// build the vector from features
WITH id(c) as id, [c["n_Arable (%)"],
c["n_Crops (%)"],
c["n_Infant mortality (per 1000 births)"],
c["n_GDP ($ per capita)"],
c["n_Coastline (coast/area ratio)"],
c["n_Pop. Density (per sq. mi.)"],
c["n_Area (sq. mi.)"]] as weights
WITH {item:id, weights: weights} as countryData
WITH collect(countryData) as data
CALL gds.alpha.similarity.cosine.write({
nodeProjection: '*',
relationshipProjection: '*',
similarityCutoff:0.8,
topK:10,
data: data})
YIELD nodes, similarityPairs
RETURN nodes, similarityPairs
图形数据科学图书馆
借助 Neo4j 的图形数据科学库,我们可以直接在 Neo4j 中运行 30 多种不同的图形算法。算法被公开为密码程序,类似于我们上面看到的 APOC 程序。
GDS 使用存储图形的投影,这完全是在内存中实现更快的执行时间。我们可以利用gdn.graph.create
过程来投影存储图的视图。关于 GDS 图形投影的更多细节,请查看我在之前的博文。在本例中,我们将投影标签为 Country 且关系类型为 SIMILAR 的节点。
CALL gds.graph.create('similarity_network','Country','SIMILAR');
弱连通分量
通常,我们用弱连接成分算法开始图形分析。这是一种社区检测算法,用于在我们的图中找到断开的网络或孤岛。因为我们只对断开组件的计数感兴趣,所以我们可以运行算法的stats
变体。
CALL gds.wcc.stats('similarity_network')
YIELD componentCount, componentDistribution
RETURN componentCount,
componentDistribution.min as min,
componentDistribution.max as max,
componentDistribution.mean as mean,
componentDistribution.p50 as p50,
componentDistribution.p75 as p75,
componentDistribution.p90 as p90
结果
该算法在我们的图中只找到了一个组件。这是一个有利的结果,因为断开的岛会扭曲各种其他图算法的结果。
卢万算法
另一种社区检测算法是 Louvain 算法。用基本术语来说,密集连接的节点更有可能形成社区。它依靠模块化优化来提取社区。模块化优化分两步进行。第一步包括局部优化模块化。在第二步中,它将属于同一社区的节点聚合到单个节点中,并从这些聚合的节点构建新的网络。这两个步骤反复重复,直到获得最大的模块化。这些迭代的一个微妙的副作用是,我们可以在每次迭代结束时查看社区结构,因此 Louvain 算法被视为分层社区检测算法。要包含分层社区结果,我们必须将includeIntermediateCommunities
参数值设置为 true。
CALL gds.louvain.write('similarity_network',
{maxIterations:20,
includeIntermediateCommunities:true,
writeProperty:'louvain'})
YIELD ranLevels, communityCount,modularity,modularities
结果
我们可以通过ranLevels
值观察到,Louvain 算法在我们的网络中发现了两个层次的社区。在最后一层,它发现了八个组。我们现在可以检查最后一级的提取社区,并比较它们的特征平均值。
MATCH (c:Country)
RETURN c.louvain[-1] as community,
count(*) as community_size,
avg(c['Arable (%)']) as pct_arable,
avg(c['Crops (%)']) as pct_crops,
avg(c['Infant mortality (per 1000 births)']) as infant_mortality,
avg(c['GDP ($ per capita)']) as gdp,
avg(c['Coastline (coast/area ratio)']) as coastline,
avg(c['Pop. Density (per sq. mi.)']) as population_density,
avg(c['Area (sq. mi.)']) as area_size,
collect(c['name'])[..3] as example_members
ORDER BY gdp DESC
结果
Louvain 算法在相似性网络中找到了八个不同的社区。最大的组织有 51 个成员国,平均 GDP 最高,接近 22,000 美元。它们在婴儿死亡率和海岸线比例上位居第二,但在人口密度上遥遥领先。有两个社区的平均 GDP 在 2 万美元左右,然后我们可以观察到第三名的 GDP 急剧下降到 7000 美元。随着 GDP 的下降,我们还可以发现婴儿死亡率的上升几乎是线性的。另一个有趣的发现是,大多数更贫困的社区几乎没有海岸线。
使用 PageRank 查找社区代表
我们可以使用 PageRank 算法来评估最终级别社区的顶级代表。如果我们假设每个相似的关系都是国家间相似度的投票, PageRank 算法会给社区内最相似的国家分配最高分。我们将对每个社区分别执行 PageRank 算法,并且只考虑给定社区中的节点和关系。这可以通过密码投影轻松实现,无需任何额外的变换。
WITH 'MATCH (c:Country) WHERE c.louvain[-1] = $community
RETURN id(c) as id' as nodeQuery,
'MATCH (s:Country)-[:SIMILAR]->(t:Country)
RETURN id(s) as source, id(t) as target' as relQuery
MATCH (c:Country)
WITH distinct c.louvain[-1] as community, nodeQuery, relQuery
CALL gds.pageRank.stream({nodeQuery:nodeQuery,
relationshipQuery:relQuery,
parameters:{community:community},
validateRelationships:False})
YIELD nodeId, score
WITH community, nodeId,score
ORDER BY score DESC
RETURN community,
collect(gds.util.asNode(nodeId).name)[..5] as top_5_representatives
结果
使用 Gephi 实现网络可视化
优秀的可视化胜过千言万语。Gephi 是一个创建网络可视化的伟大工具。正如我们现在可能预期的那样,APOC 提供了一个方便的程序apoc.gephi.add
,可以将网络数据从 Neo4j 无缝地传输到 Gephi。在文档或我的前一篇博文中找到更多信息。
节点颜色表示社区,节点大小表示 GDP,文本大小表示社区 PageRank 值
正如我们之前观察到的,我们的网络中有八个不同的社区。平均 GDP 最高的社区在右上角,平均 GDP 最高到最低的国家按顺时针方向排列。我发现一个有趣的三角形正好位于俄罗斯、中国和巴西形成的图像中间。此外,如果你仔细观察,你会发现巴拿马是红色社区的一部分,但位于中间。这是因为它与大多数社区中的一两个国家有类似的关系,但与红色社区中的三个国家有关系,因此属于红色社区。
基于 Louvain 算法的层次社区
我们之前提到过,Louvain 算法可用于查找带有includeIntermediateCommunities
参数的分层社区,在我们的示例中,它找到了两个级别的社区。我们现在将考察第一层次的国家集团。一条经验法则是,较低级别的社区将更细粒度、更小。
MATCH (c:Country)
RETURN c.louvain[0] as community,
count(*) as community_size,
avg(c['Arable (%)']) as pct_arable,
avg(c['Crops (%)']) as pct_crops,
avg(c['Infant mortality (per 1000 births)']) as infant_mortality,
avg(c['GDP ($ per capita)']) as gdp,
avg(c['Coastline (coast/area ratio)']) as coastline,
avg(c['Pop. Density (per sq. mi.)']) as population_density,
avg(c['Area (sq. mi.)']) as area_size,
collect(c['name'])[..3] as example_members
ORDER BY gdp DESC
结果
不出所料,第一层的社区数量几乎是第二层(也是最后一层)的两倍。一个激动人心的社区由平均 GDP 排在第二位。它只包含五个国家,这些国家很小,平均面积只有 364 平方英里。另一方面,他们有很高的人口密度,大约每平方英里 10000 人。例如澳门、摩纳哥和香港。
Neo4j Bloom 的图形探索
另一个非常好的网络可视化工具是 Neo4j Bloom 。它提供了定制图形透视图和搜索查询的能力,没有任何 cypher 查询语言技能的人可以使用它来探索和搜索图形中的见解。如果你有兴趣了解更多,可以查看威廉·里昂写的这篇博文。
我们将看看最后一组 GDP 最高的国家。它是一个由 51 个国家组成的共同体,在第一层级上有四个不同的共同体。
节点颜色表示一级社区,节点大小表示 GDP
之前,我们提到了一个令人兴奋的社区,由五个人口密度极高的小国组成。在这个图像中,它们被涂成红色。蓝色社区的平均 GDP 比黄色社区高 25%左右,婴儿死亡率几乎是黄色社区的一半。另一方面,黄色社区平均比蓝色社区有更多的海岸线。
结论
Neo4j 生态系统非常适合执行和可视化网络分析。图形数据科学库是生态系统的一个实用补充,允许我们运行各种图形算法并执行图形分析,而没有太多麻烦。你可以在你的电脑上试用,也可以创建一个 Neo4j 沙盒账户,几分钟内就可以开始使用。
和往常一样,代码可以在 GitHub 上获得。
紧凑预测树
实践教程
有限字母表上精确序列预测的无损模型
图片来自 Pixabay 的 Bela Geletneky
什么是序列预测问题?
序列预测问题包括仅通过查看序列的项目来查找有序序列的下一个元素。
这个问题涵盖了各种领域中的许多应用。它包括产品推荐、预测和网页预取等应用程序。
许多不同的方法被用来解决这个问题,流行的方法包括 PPM(部分匹配预测),马尔可夫链,以及最近的 LSTM(长短期记忆)。
紧凑预测树(CPT)是 2015 年发布的一种方法,旨在通过对整个训练集进行无损压缩来匹配精度并超越流行算法的性能(训练和预测的时间)。
我们现在将详细介绍训练和预测的方法,以及这种方法的优缺点。
紧凑预测树定义
在进入如何使用它进行预测的细节之前,让我们描述一下组成紧凑预测树(CPT)的不同元素:
- 一个 trie ,用于序列的有效存储。
- 一个倒排索引,用于恒定时间检索包含某个单词的序列。
- 一个查找表,用于从序列 Id 中检索序列。
特里
trie 通常称为前缀树,是一种基于有序树的数据结构,用于存储序列(如字符串)。序列的元素存储在边中,因此给定节点的每个后代都有相同的前缀。
在这个众所周知的例子中,我们希望存储["tea", "ten", "inn"]
。我们先把“茶”放在空树上。这棵树的每一根树枝对应一个字母。然后我们添加“ten”:因为“tea”和“ten”共享同一个“te”前缀,所以我们只是在“te”前缀之后创建一个新的分支。最后,我们将“inn”添加到与前两个序列没有共同前缀的树中。
Trie 通常用于获取,对每个以前缀开头的单词进行树搜索。在我们的例子中,我们使用它来压缩和有效地存储我们的训练集。
倒排索引
倒排索引是用于存储从元素到其位置的映射的索引。这里我们用它来存储从序列元素到序列 id 的映射。
再次考虑我们之前的示例,我们注意到“T”出现在序列 0 和 1 中,“E”出现在序列 0 和 1 中,“A”出现在序列 0 中,“N”出现在序列 1 和 2 中,而“I”仅出现在序列 2 中。
因此,我们有以下反向索引:
{
"T": [0, 1],
"E": [0, 1],
"A": [0],
"N": [1, 2],
"I": [2]
}
为了提高效率,我们将使用位集来存储倒排索引(这也有助于高效地找到“相似序列”)。
查找表
查找表是一种数据结构(通常是一个数组),用于存储每个序列的最后一个节点(叶)的指针。
这种数据结构对于迭代给定序列的元素来说是必不可少的。
例如,如果我们想要检索 id 为 0 的序列,我们可以简单地迭代它的父序列。在我们的例子中,id 0 序列的叶的父代与“A”链接,然后与“E”链接,最后与“T”链接。这倒过来给了我们第一个序列:“茶”。
紧凑预测树使用
训练
训练时间与训练集中的序列数成线性关系。
对于每个训练序列,我们需要执行 3 个步骤:
- 在 trie 中插入序列。
- 添加倒排索引中的元素。
- 添加查找表中最后一个节点的位置。
一张图胜过千言万语,这里是一个经过充分训练的紧凑预测树一步一步来。
预测
为了预测序列 S,我们需要做这三个步骤:
- 寻找相似序列(包含 S 的每个元素的序列)。
- 计算每个相似序列的后续序列(从与 S 相同的最后一项之后开始的子序列)。
- 计算每个元素在所有后续序列中的出现次数。
对于这一部分,让我们举一个稍微复杂一点的例子,我们的模型在["ABC", "ABD", "BC", "BAC"]
进行训练。我们应该将算法训练成:
让我们试着预测一下"AB"
之后会发生什么。
首先,让我们计算相似的序列。
与 S 相似的序列是包含 S 中任意顺序、任意位置的每一项的序列。为了计算相似的序列,我们可以简单地使用我们的倒排索引并计算交集。对于我们的例子,我们需要相交[0, 1, 3]
(A 出现的序列的 id)和[0, 1, 2, 3]
(B 出现的位置)。这就给了[0, 1, 3]
。
然后,我们需要计算consequent sequences
。
序列 Y 相对于序列 S 的后件是从与 S 相同的最后一项之后开始直到 Y 结束的 Y 的子序列。
我们例子的后件序列应该是"C"
、"D"
和"C"
。(对于我们相对于"AB"
的序列 0、1 和 3)。
最后,我们简单地计算每个元素在所有后续序列中出现的次数,并预测出现次数最多的字母。
在我们的例子中是"C"
(2 次出现)。
紧凑预测树性能
测试框架
简而言之,作者用几种算法(包括 CPT、依赖图、类马尔可夫算法……)在几个公共数据集上预测了下一个元素。
要看结果(要慎用),建议你看一下原论文, 紧凑预测树:精确序列预测的无损模型 。
另一篇论文, 从智能卡数据预测火车行程:序列预测问题的现实应用 *,*展示了解决序列预测问题的步骤。从字母表的构建到模型的选择。在这篇论文中,Hoekstra 博士将 CPT 与 PPM 和 AKOM 等不同方法进行了比较。根据您的需要,它还显示 CPT 可以是一个具有相对较好准确性的相关解决方案。
利弊
紧凑预测树的优点是:
- CPT 是一种无损存储来自训练集的所有数据的算法。
- 该算法是高度可解释的(容易追溯相似序列,后续序列…)
- 快速预测。一些基准可以在原论文或者这里找到。
紧凑预测树的缺点是:
- CPT 忽略序列中的顺序,因此 CPT 倾向于预测最频繁出现的项目。(如果您准备好了考虑顺序的稍微慢一点的预测。我建议你去看看由一个共同作者开发的子序列算法。)
- CPT 对噪音相当敏感。如果一个新元素在要预测的序列中,CPT 将无法找到任何相似的序列。CPT+已经解决了这个问题,您可以在“更进一步”一节中找到详细信息。
走得更远
Python 示例
对于这个小例子,我们将使用这个实现。在合著者之一的官网上引用为 CPT 的实现。还包括了降噪等 CPT+的一些特性。
from cpt.cpt import Cptmodel = Cpt()# training
model.fit([['hello', 'world'],
['hello', 'this', 'is', 'me'],
['hello', 'me']
])# predictions
model.predict([['hello'], ['hello', 'this']])# Output: ['me', 'is']
有关predict
方法的参数或超参数的更多信息,您可以查看文档。
进一步阅读
如果你对这个主题感兴趣,我强烈建议你阅读以下论文:
- 【CPT+】:降低紧凑预测树的时间/空间复杂度 这增加了噪声降低技术和训练集策略的两次压缩。
- 基于序列预测和 Pagerank 算法改进网页访问预测本文的思路是增加一个 Pagerank 算法,只在相关序列上训练 CPT。总体上有很好的改善。
- 简洁的基于 BWT 的序列预测(subseq) CPT 的合著者之一开发的算法。这种算法需要更多的时间来预测,需要更多的空间来存储整个训练集,但更重视序列的顺序。你可以看看这个实现。
特别感谢约瑟夫·罗卡的所有帮助。感谢我的朋友们也校对了这篇文章。
使用 Python 的概率模型进行公司估值
采用蒙特卡洛模拟确定上市公司的股权价值
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
在一个完全可预测的世界中,我们将拥有关于企业未来增长率和现金流的准确信息,这将导致该公司单一准确的内在价值。然而现实中,事情的不确定性更大。事实上,虽然一些分析师给出了准确的股价目标,但金融模型的各种输入实际上是随机分布的变量。由此产生的复杂性加剧了寻找合适的公司价值的挑战。虽然在随机输入的情况下不再有“单一版本的真相”,但如果我们的输入遵守某些规则,就有可能找到可能包含我们公司真实平均值的一系列值。在编写下面的模型时,我借鉴了 NYU 大学教授 Aswath Damodaran 在他关于使用概率方法进行公司估值的论文[1]中提供的见解。
一.统计迂回
假设我们只有四个随机变量作为股票估值模型的输入:收入 CAGR、EBIT 利润率、加权平均资本成本(WACC)和公司的长期增长率(假设微软)。我们可以进一步假设这些值有一个确定的平均值,并且是正态分布的。这需要这些变量的分布遵循一套规则,例如,关于它们的传播。
鉴于这些随机变量,有一些“真正的”平均公司价值,我们试图确定。这个真实均值是基于我们随机输入变量的无限多内在价值预测的均值。因为不可能找到这个精确的总体平均值,所以我们需要限制自己创建一个值的单一样本,并从这个样本中推断总体平均值。
I.1 抽样分布
为了理解样本相对于公司价值总体的表现,首先设想一个假设场景是有意义的,在这个场景中,我们知道真实的平均公司价值及其标准差。如果我们现在从公司价值总体中抽取重复样本,这些样本的平均值将遵循一个抽样分布,该分布可以用正态分布来近似。该分布的平均值是公司价值的真实平均值,其标准偏差是公司价值的标准偏差除以样本中观察值数量的平方根。利用这个标准差,我们可以预测某些事件发生的概率。例如,我们知道 68%的样本均值将落在总体均值的一个标准差内,大约 95%将落在两个标准差内,等等。
I.2 推断
那么这对我们有什么帮助呢?如果我们知道总体均值及其抽样分布的标准差,我们就可以从理论上生成一个样本,并推断出真实的总体均值。例如,如果我们取样本的平均值,并创建一个从该平均值向任一侧延伸两个标准差的范围,我们可以有 95%的把握认为真正的平均值将位于该区间内。唯一的问题是我们不知道总体标准偏差。
事实证明,我们可以将样本标准差作为真实总体值的近似值,并通过扩大置信区间的宽度(通过使用 t 值)来说明这一点。如果从总体中抽取足够大的样本,这将提高我们总体标准差估计的准确性,因此我们可以使用 z 分数来代替。
本质上,所有这些意味着我们可以预测我们公司的价值一定次数,这将导致从公司价值的人口样本。然后,我们可以为真实平均值创建 95%的置信区间,以获得真实平均值(基于四个随机输入变量)可能位于何处的指示。
二。用 Python 实现
尽管基础理论有些复杂,但用 Python 实现该模型实际上相当简单,这将在随后的章节中解释。
II.1 计算公司的公允价值
使用 yahoo_fin 库,可以获得上市公司的财务数据。我们可以使用此信息来导出在以下模拟中使用的正态分布变量的平均值。在模拟的每次迭代中,我们根据随机变量的值预测一个特定的公司价值。我用来获取这个值的代码和我前段时间写的代码很相似(除了 yahoo_fin 让我不用手动抓取所有的财务数据)。因为这里的重点是从蒙特卡罗模拟生成的样本数据中进行推断,所以我不会详细讨论代码和它背后的简化假设。重要的是,在给定公司收入 CAGR、EBIT 利润率、WACC 和长期增长率的特定输入的情况下,下面的代码块将(希望)返回对公司内在价值的较为准确的估计。
from yahoo_fin import stock_info as si
from matplotlib import pyplot as plt
import pandas_datareader as dr
import numpy as np
import pandas as pd
'''----// General input variables //----'''
company_ticker = 'MSFT'
market_risk_premium = 0.059
debt_return = 0.01
long_term_growth = 0.01
tax_rate = 0.3
iterations = 1000
'''----// Get financial information from yahoo finance //----'''
income_statement_df = si.get_income_statement(company_ticker)
pars_df = income_statement_df.loc[['totalRevenue', 'ebit']]
input_df = pars_df.iloc[:, ::-1]
'''----// Calculate average revenue CAGR & EBIT margin //----'''
def get_cagr(past_revs):
CAGR = (past_revs.iloc[0,3]/past_revs.iloc[0,0])**(1/4)-1
return(CAGR)
def get_average_margin(past_ebit):
margin = 0
margin_lst = []
for i in range(len(past_ebit.columns)):
margin = past_ebit.iloc[1,i]/past_ebit.iloc[0,i]
margin_lst.append(margin)
return(sum(margin_lst)/len(margin_lst))
mean_cagr = get_cagr(input_df)
mean_margin = get_average_margin(input_df)
'''----// Create forecast function through which random variables will flow //----'''
def get_forecast(input_df, cagr, margin, long_term_growth):
forecast_lst = []
for i in range(6):
if i < 5:
forecast_lst.append(input_df.iloc[0,3]*(1+cagr)**(i+1)*margin)
else:
forecast_lst.append(input_df.iloc[0,3]*(1+cagr)**(i)*(1+long_term_growth)*margin)
return forecast_lst
'''----// Get WACC and net debt //----'''
def get_wacc(company_ticker, market_risk_premium, debt_return, tax_rate):
risk_free_rate_df = dr.DataReader('^TNX', 'yahoo')
risk_free_rate = (risk_free_rate_df.iloc[len(risk_free_rate_df)-1,5])/100
equity_beta = si.get_quote_table('msft')['Beta (5Y Monthly)']
equity_return = risk_free_rate+equity_beta*(market_risk_premium)
balance_sheet_df = si.get_balance_sheet(company_ticker)
short_term_debt_series = balance_sheet_df.loc['shortLongTermDebt']
long_term_debt_series = balance_sheet_df.loc['longTermDebt']
cash_series = balance_sheet_df.loc['cash']
net_debt = short_term_debt_series.iloc[0] + + long_term_debt_series.iloc[0] - cash_series.iloc[0]
market_cap_str = si.get_quote_table(company_ticker)['Market Cap']
market_cap_lst = market_cap_str.split('.')
if market_cap_str[len(market_cap_str)-1] == 'T':
market_cap_length = len(market_cap_lst[1])-1
market_cap_lst[1] = market_cap_lst[1].replace('T',(12-market_cap_length)*'0')
market_cap = int(''.join(market_cap_lst))
if market_cap_str[len(market_cap_str)-1] == 'B':
market_cap_length = len(market_cap_lst[1])-1
market_cap_lst[1] = market_cap_lst[1].replace('B',(9-market_cap_length)*'0')
market_cap = int(''.join(market_cap_lst))
company_value = market_cap + net_debt
WACC = market_cap/company_value * equity_return + net_debt/company_value * debt_return * (1-tax_rate)
return WACC
def get_net_debt():
balance_sheet_df = si.get_balance_sheet(company_ticker)
short_term_debt_series = balance_sheet_df.loc['shortLongTermDebt']
long_term_debt_series = balance_sheet_df.loc['longTermDebt']
cash_series = balance_sheet_df.loc['cash']
return short_term_debt_series.iloc[0] + long_term_debt_series.iloc[0] - cash_series.iloc[0]
mean_wacc = get_wacc(company_ticker, market_risk_premium, debt_return, tax_rate)
net_debt = get_net_debt()
'''----// Discount EBIT figures to arrive at the PV of the firm's cash flows //----'''
def discount(forecast, discount_rate, long_term_rate):
discount_lst = []
for x,i in enumerate(forecast):
if x < 5:
discount_lst.append(i/(1+discount_rate)**(x+1))
else:
discount_lst.append(i/(discount_rate-long_term_rate)*(1/(1+discount_rate)**5))
return sum(discount_lst)forecast = get_forecast(input_df, cagr, margin, long_term_rate)
present_value = discount(forecast, discount_rate, long_term_rate)-net_debt
其思想是使用循环反复预测公司价值,并将结果模型输出存储在一个列表中,该列表稍后用于确定样本均值和标准差。
II.2 用 Python 生成正态分布的随机变量
我通过假设这些变量的过去值是未来值的准确预测值,得出了平均 CAGR 值、EBIT 边际值和 WACC 值。公司的长期增长率更难确定,应根据具体情况输入。四个变量的标准差也是如此。给定四个变量中每一个的平均值和标准偏差,很容易用 numpy 从随机分布中得出结论。实际上,导入库后我们只需要一行代码。
cagr = np.random.normal(mean_cagr, 0.01)
对 EBIT 边际利润、WACC 和长期增长率做同样的处理,我们可以用得到的数字来计算公司价值。这样做一次需要从公司价值观中抽取一个单一的价值观。使用一个循环,我们可以重复这个过程几次(在本例中是 1000 次),并将结果公司值存储在一个列表中。
'''----// Run simulation //----'''
hist_lst = []
for i in range(iterations):
cagr = np.random.normal(mean_cagr, 0.01)
margin = np.random.normal(mean_margin, 0.005)
long_term_rate = np.random.normal(long_term_growth, 0.001)
discount_rate = np.random.normal(mean_wacc, 0.001)
forecast = get_forecast(input_df, cagr, margin, long_term_rate)
hist_lst.append(discount(forecast, discount_rate, long_term_rate)-net_debt)
hist_array = np.array(hist_lst)
使用 numpy,我们可以很容易地找到这个列表的均值和标准差。随后,可以计算出我们 95%置信区间的上下界。
mean = hist_array.mean()
standard_error = hist_array.std()/(iterations**(1/2))
lower_bound = mean-1.96*standard_error
upper_bound = mean+1.96*standard_error
二. 3 绘制产出图
使用 matplotlib,我们还可以图形化地显示样本数据。这有助于更好地理解样本数据的分布,也使我们能够验证推断的正态性假设。
plt.hist(hist_array, bins=50, align='mid', color = 'steelblue', edgecolor='black')
plt.title('Sample Distribution ' + company_ticker, {'fontname':'Calibri'})
plt.xlabel('Equity Value in $', {'fontname':'Calibri'})
plt.ylabel('Frequency', {'fontname':'Calibri'})
plt.show()
图 1:预测公司价值的分布直方图。由于数据近似正态分布,我们能够如上所述计算置信区间。
II.4 模型性能
为了了解模型的表现,我计算了不同公司真实平均值的置信区间,并随后将区间与实际公司市值进行了比较。结果如下所示。
图 2:AAPL 的模型输出(实际市场。cap = 19.41 亿美元)和 MSFT(实际市场。上限= 1,554 美元)
图 3:WMT 的模型输出(实际市场。cap = 388 b 美元)和 PG(实际市场。上限= 3400 亿美元)
图 4:NKE 的模型输出(实际市场。cap = 179 亿美元)和 MRK(实际市场。上限= 211 亿美元)
当将置信区间与公司的实际市值进行比较时,该模型似乎有些偏差。虽然该程序肯定不是真实世界的完美代表,但我们仍然必须考虑到置信区间为公司的真实均值 值提供了一个范围,而不是为单个点估计提供了一个范围。
三。结束语
像我之前建立的计算公司公允价值的模型一样,这个程序也做了几个简化的假设。例如,我隐含地假设四个随机输入变量的过去值是它们未来总体均值的适当近似值。然而,这种假设可能是没有根据的,即使允许这些输入变量有一些随机性也不能解决这个问题。尽管如此,我相信将随机性纳入模型会使它更接近于成为真实世界动态的充分代表。
III.1 免责声明
该模型和代码只是将 Python 编程应用于公司估值的一个练习。因此,该代码显然不应用于投资决策。此外,从雅虎财经获得的信息不应用于任何商业目的。
III.2 最终代码
下面是运行模拟并从结果样本数据中得出推论所需的全部代码。它的工作只需要 Python(我用的是 3.7.8)和几个包,即 yahoo_fin、matplotlib、pandas-datareader、numpy 和 pandas。
from yahoo_fin import stock_info as si
from matplotlib import pyplot as plt
import pandas_datareader as dr
import numpy as np
import pandas as pd
'''----// General input variables //----'''
company_ticker = 'MSFT'
market_risk_premium = 0.059
debt_return = 0.01
long_term_growth = 0.01
tax_rate = 0.3
iterations = 1000
'''----// Get financial information from yahoo finance //----'''
income_statement_df = si.get_income_statement(company_ticker)
pars_df = income_statement_df.loc[['totalRevenue', 'ebit']]
input_df = pars_df.iloc[:, ::-1]
'''----// Calculate average revenue CAGR & EBIT margin //----'''
def get_cagr(past_revs):
CAGR = (past_revs.iloc[0,3]/past_revs.iloc[0,0])**(1/4)-1
return(CAGR)
def get_average_margin(past_ebit):
margin = 0
margin_lst = []
for i in range(len(past_ebit.columns)):
margin = past_ebit.iloc[1,i]/past_ebit.iloc[0,i]
margin_lst.append(margin)
return(sum(margin_lst)/len(margin_lst))
mean_cagr = get_cagr(input_df)
mean_margin = get_average_margin(input_df)
'''----// Create forecast function through which random variables will flow //----'''
def get_forecast(input_df, cagr, margin, long_term_growth):
forecast_lst = []
for i in range(6):
if i < 5:
forecast_lst.append(input_df.iloc[0,3]*(1+cagr)**(i+1)*margin)
else:
forecast_lst.append(input_df.iloc[0,3]*(1+cagr)**(i)*(1+long_term_growth)*margin)
return forecast_lst
'''----// Get WACC and net debt //----'''
def get_wacc(company_ticker, market_risk_premium, debt_return, tax_rate):
risk_free_rate_df = dr.DataReader('^TNX', 'yahoo')
risk_free_rate = (risk_free_rate_df.iloc[len(risk_free_rate_df)-1,5])/100
equity_beta = si.get_quote_table('msft')['Beta (5Y Monthly)']
equity_return = risk_free_rate+equity_beta*(market_risk_premium)
balance_sheet_df = si.get_balance_sheet(company_ticker)
short_term_debt_series = balance_sheet_df.loc['shortLongTermDebt']
long_term_debt_series = balance_sheet_df.loc['longTermDebt']
cash_series = balance_sheet_df.loc['cash']
net_debt = short_term_debt_series.iloc[0] + + long_term_debt_series.iloc[0] - cash_series.iloc[0]
market_cap_str = si.get_quote_table(company_ticker)['Market Cap']
market_cap_lst = market_cap_str.split('.')
if market_cap_str[len(market_cap_str)-1] == 'T':
market_cap_length = len(market_cap_lst[1])-1
market_cap_lst[1] = market_cap_lst[1].replace('T',(12-market_cap_length)*'0')
market_cap = int(''.join(market_cap_lst))
if market_cap_str[len(market_cap_str)-1] == 'B':
market_cap_length = len(market_cap_lst[1])-1
market_cap_lst[1] = market_cap_lst[1].replace('B',(9-market_cap_length)*'0')
market_cap = int(''.join(market_cap_lst))
company_value = market_cap + net_debt
WACC = market_cap/company_value * equity_return + net_debt/company_value * debt_return * (1-tax_rate)
return WACC
def get_net_debt():
balance_sheet_df = si.get_balance_sheet(company_ticker)
short_term_debt_series = balance_sheet_df.loc['shortLongTermDebt']
long_term_debt_series = balance_sheet_df.loc['longTermDebt']
cash_series = balance_sheet_df.loc['cash']
return short_term_debt_series.iloc[0] + long_term_debt_series.iloc[0] - cash_series.iloc[0]
mean_wacc = get_wacc(company_ticker, market_risk_premium, debt_return, tax_rate)
net_debt = get_net_debt()
'''----// Discount EBIT figures to arrive at the PV of the firm's cash flows //----'''
def discount(forecast, discount_rate, long_term_rate):
discount_lst = []
for x,i in enumerate(forecast):
if x < 5:
discount_lst.append(i/(1+discount_rate)**(x+1))
else:
discount_lst.append(i/(discount_rate-long_term_rate)*(1/(1+discount_rate)**5))
return sum(discount_lst)
'''----// Run simulation and plot distribution of model forecasts //----'''
hist_lst = []
for i in range(iterations):
cagr = np.random.normal(mean_cagr, 0.01)
margin = np.random.normal(mean_margin, 0.005)
long_term_rate = np.random.normal(long_term_growth, 0.001)
discount_rate = np.random.normal(mean_wacc, 0.001)
forecast = get_forecast(input_df, cagr, margin, long_term_rate)
hist_lst.append(discount(forecast, discount_rate, long_term_rate)-net_debt)
hist_array = np.array(hist_lst)
plt.hist(hist_array, bins=50, align='mid', color = 'steelblue', edgecolor='black')
plt.title('Sample Distribution ' + company_ticker, {'fontname':'Calibri'})
plt.xlabel('Equity Value in $', {'fontname':'Calibri'})
plt.ylabel('Frequency', {'fontname':'Calibri'})
plt.show()
mean = hist_array.mean()
standard_error = hist_array.std()/(iterations**(1/2))
lower_bound = mean-1.96*standard_error
upper_bound = mean+1.96*standard_error
print(lower_bound)
print(upper_bound)
参考资料:
[1] A. Damodaran,直面不确定性:在估值中使用概率方法 (2018),SSRN
不平衡数据过采样技术的比较分析
关键词 -不平衡数据,过采样,对比分析
简介
对不平衡数据建模是我们在训练模型时面临的主要挑战。我的项目的主要目标是找到最佳的过采样技术,我将应用于五个与老化相关的 bug 问题相关的数据集。我会用七个机器学习分类模型来训练模型。
不平衡数据通常指的是分类问题,其中每个类别的观察值数量不是均匀分布的;通常,一个类别(称为多数类别)会有大量数据/观察值,而一个或多个其他类别(称为少数类别)的观察值会少得多。
数据
我使用的数据集与老化相关的错误(ARB)有关,这些错误发生在长期运行的系统中,是由于内存泄漏或未释放的文件和锁等问题的积累而导致的错误条件。与衰老有关。在软件测试过程中,bug 很难被发现,复制起来也很困难。下面是表 1 中每个数据集的描述。
表 1:实验数据集描述
使用的平衡方法
1。类别重量
首先,我使用了一种最简单的方法来解决类不平衡的问题,即简单地为每个类提供一个权重,这个权重更多地强调少数类,这样最终的结果是一个分类器可以从所有类中平等地学习。
2.过采样
其次,我使用了三种过采样技术来消除这种不平衡。对于过采样,少数类将增加少数观察的数量,直到我们达到一个平衡的数据集。
2.1 随机过采样
这是最简单的过采样方法。它随机采样少数类,并简单地复制采样的观察值。通过这种技术,我们人为地减少了数据集的方差。
2.2 SMOTE
然而,我们也可以使用现有的数据集为少数类综合生成新的数据点。合成少数过采样技术(SMOTE)是一种通过在原始数据集中的观测值之间进行插值来生成新观测值的技术。
对于给定的观测值 xi,通过在 k 个最近邻之一 xzi 之间进行插值来生成新的(合成)观测值。
xnew = Xi+λ(xzi Xi)xnew = Xi+λ(xzi Xi)
其中λ是在[0,1][0,1]范围内的随机数。这个插值将在 xi 和 xzi 之间的线上创建一个样本。
2.3 ADASYN
自适应合成(ADASYN)采样与 SMOTE 相同,但是,为给定 xi 生成的样本数量与附近与 xi 不属于同一类别的样本数量成比例。因此,ADASYN 在生成新的合成训练样本时往往只关注离群值。
使用的分类模型
- K 最近邻— 首先,我使用了一个简单的分类模型,即 KNN 分类器。在这个模型中,分类是根据每个点的 k 个最近邻的简单多数投票来计算的。
2。逻辑回归- 其次我用的是逻辑回归。在该算法中,描述单次试验可能结果的概率使用逻辑函数(即 sigmoid 函数)建模。
3。朴素贝叶斯- 接下来我使用了朴素贝叶斯算法,它基于贝叶斯定理,假设每对特征之间是独立的。朴素贝叶斯分类器在许多现实情况下工作良好,例如文档分类和垃圾邮件过滤。
4。决策树- 然后我用了决策树分类器。决策树产生一系列可用于对数据进行分类的规则。这个分类器易于理解和可视化,可以处理数字和分类数据。
***5。*随机森林-**接下来我用的是随机森林分类器。它是一种元估计器,可以在数据集的各种子样本上拟合许多决策树,并使用平均值来提高模型的预测准确性,并控制过度拟合。子样本大小始终与原始输入样本大小相同,但样本是替换绘制的。
**6*6。*支持向量机-**接下来我用的是 SVM。它将训练数据表示为空间中的点,这些点被尽可能宽的明显间隙分成不同的类别。然后,新的例子被映射到相同的空间,并根据它们落在差距的哪一边来预测属于哪个类别。
7。山脊 CV- 最后我用的是山脊 CV。该分类器首先将目标值转换为{-1,1},然后将问题视为回归任务(多类情况下的多输出回归)。
观察分析
1。调谐模式
我超调了每个数据集上的每个模型,以找到模型可以预测的最佳精度。我使用 GridSearchCV 和 K-Fold 来优化模型。我将不同的 K 值设置为 5、10、15 和 20,发现 10 倍的效果最好。
你可以在文章末尾我提供的 GitHub 链接中看到代码
**2。技术相对比较
我使用了 AUC 指标来比较模型,因为当我们必须比较分类模型时,ROC AUC 是最好的。AUC 值越大,模型越好。从我的结果中,我发现平均 AUC 值,即 0.89 的 随机抽样 与其他不平衡学习策略相比是最好的。 SMOTE 和 ADAYSN 的平均 AUC 值次之,为 0.88。 类权重 t 的平均 AUC 值为 0.58。精度和 f 值显示出相同的趋势。根据 f-measure 值和精确度两者, 随机超过采样器 性能最好,其次是和 ADASYN 。
我们还推断出 脊分类器 是最好的,并且具有 0.93 的平均 AUC 值。其次是平均 AUC 值为 0.83 的 随机森林 和平均 AUC 值为 0.80 的 决策树KNN各为 0.80。 Logistic 回归 和 SVM 的平均 AUC 值各为 0.79。 朴素贝叶斯 表现最差,平均 AUC 为 0.76。根据 F-测度,脊分类器的平均 F-测度值为 0.916。决策树和随机森林的平均 F-测度值分别为 0.90 和 0.91,高于 SVM 和 Logistic 回归的平均 F-测度值 0.85。朴素贝叶斯表现最差,平均 F 值为 0.81
此外,我绘制了条形图,显示了过采样技术和分类模型的比较。从可视化结果中,我们还可以看到,在大多数情况下,由绿色条表示的随机过采样技术比其他技术高。
你可以在文章末尾提供的我的 GitHub 链接中查看可视化代码。
AUC 分数的条形图
准确性得分条形图
F1-度量的条形图
结果
在这篇文章中,我通过应用 7 种机器学习算法,对 5 个老化相关错误的不平衡数据集进行了过采样技术的比较分析。从我的项目,我们得出结论,随机过采样器被证明是最好的过采样技术相比,其他和岭分类器,最好的机器学习算法。
我的 GitHub 链接-https://github.com/vanisinghal0201/Comparative_Analysis
我也将很快在geeks forgeeks上发表。
参考文献
[1] Lov Kumar,Ashish Sureka,实验结果,结论,针对老化相关错误预测的类不平衡问题的特征选择技术,2018
[2]双吉,预测职称分类中的等级关系,2020
[3]从不平衡数据中学习。检索自 https😕/www . Jeremy Jordan . me/unbalanced-data/
ML 系统的比较案例研究:Tensorflow 与 PyTorch
在这篇文章中,我将对 TensorFlow:一个用于大规模机器学习的系统和 PyTorch:一个命令式的高性能深度学习库的背景架构进行一个小的比较研究
下面提到的信息是从这两篇论文中摘录的。
我选择了 TensorFlow 和 PyTorch 来进行比较研究,因为我已经使用了这两个系统,理解它们的基本设计原理让我着迷。我想知道这些系统如何在幕后处理模型,使它们成为行业标准。解决以行业为中心的机器学习问题所需的速度和复杂架构很难实现,这两个系统都设法做到了这一点。
这篇文章旨在提供两个系统的架构差异。为了更深入地了解每个人的背景工作,请阅读他们的学术论文!它们信息量大,易于阅读。
张量流
好处:
数据流图: Tensorflow 是对dist faith的改进,它是以前使用参数服务器模型的 Google ML 平台。Tensorflow 结合了数据流的高级编程模型和参数服务器的低级效率,因此比它的前身强大得多。它结合了在基于参数服务器的架构中由单独的工作线程完成的计算和状态管理。它还使用在提供性能方面比 CPU 和 GPU 更好的 TPU。这使得研究人员开发复杂(和新颖)的深度学习模型变得相对容易。
数据流图是一个神经网络,由占位符和更新规则组成。它可以用于确定操作的顺序,以估计内存消耗等。
**高 GPU 利用率:**它提供了一个单语言平台来开发新的 ML 架构,速度很快,并使用单个数据流图来表示算法中的所有计算和状态。通过推迟执行直到程序完成,它提高了整体执行性能,即高 GPU 利用率。Tensorflow 的主要功能在于并发和分布式执行整个图的重叠子图。
社区支持: Tensorflow 也有巨大的社区支持,在生产中表现相当不错。所以很多大公司像 Google,Twitter,Airbnb,Open AI 等等。为他们的 ML 项目使用 Tensorflow 后端。
**移动接口:**它还提供跨集群的分布式执行和动态工作流,允许复杂的 ML 程序在 CPU、GPU 和 TPU 上运行,同时在移动设备上拥有一个接口。Tensorflow-Lite 的推出考虑到了移动设备。
大规模 ML: 对于密集的大规模任务,如图像分类和语言建模,Tensorflow 提供了一个非常容错、分布式和优化的架构,可用于训练非常大的 ML 模型,如通过谷歌的 ML 聚焦应用程序可见。
Tensorflow 架构(来源)
缺点:
陡峭的学习曲线: Tensorflow 有一个学习曲线,旨在使研究人员更容易开发 ML 模型,它增加了理解其架构的难度。它也不像 Spark 的 RDDs 那样为单个操作提供容错。
**调试和动态执行:**调试 ML 程序的容易程度并不是 Tensorflow design 关注的重点。它也不支持早期的动态计算图,模型只能在已经定义了计算图的情况下运行。尽管它在最新版本中增加了对此的支持。
虽然它的架构非常可扩展和高效,但随着 Python 用户花一些时间来习惯它,可以做出更多努力来改善用户体验。
来源:活动状态
PyTorch
好处:
易用性: PyTorch 是一个专注于 python 的 ML 框架,开发它是为了让用户牢记在心。它侧重于维护性能,同时保持最终用户的高易用性。PyTorch 的“一切都是程序”的方法使它成为一个非常用户友好的平台。
**C++核心:**由于大多数深度学习研究人员都熟悉 python,所以它的开发者开发了这个 python 库,尽管它的核心是用 C++编写的,以提高速度和性能。与 Tensorflow 不同,它不使用静态数据流方法,因此为了克服 Python 的全局解释器锁(确保一次只有一个线程运行)问题,它的核心“libtorch”库(用 C++编写)实现了张量数据结构、自动 diff 集成等。多线程环境中的功能。
Python 库支持: PyTorch 保持简单高于性能,因此做出了折衷。所有的 Python 功能:打印语句、调试器、Numpy、Matplotlib 等的使用。使用 PyTorch 轻松工作。
从论文本身来看:
用 10%的速度换取一个简单得多的模型是可以接受的;100%不是。
**CPU-GPU 同步:**它具有高度的互操作性和可扩展性,可以很好地与其他使用库的 GPU 配合使用。它使用 CUDA 在 GPU 上异步执行操作符,这有助于获得高性能,即使对于 Python 这样的语言也是如此。这样,它通过 CPU 在 Python 中运行模型的控制流,并在 GPU 上运行张量运算,一切都在 CPU-GPU 同步中进行。
**多重处理:**它使用多重处理模块(torch.multiprocessing)来允许并发线程加速程序。它还通过引用计数(计算每个张量的使用次数)和删除不再使用的张量来仔细管理内存。
PyTorch 中的一个简单神经网络程序(来源
动态执行: PyTorch 还支持动态计算图,这有助于用户随时开发和运行模型。这在像 RNN 这样使用运行时可变长度输入的模型中非常有用。
缺点:
**性能:**由于 PyTorch 是为 Python 打造的,所以不得不在性能上做一些取舍。它不使用其他 ML 系统中流行的数据流图,如 TensorFlow、Theano 等。以提高性能著称。
依赖:它还必须依赖许多其他独立的库来克服 Python 的限制,比如使用 CUDA 流。由于 CUDA 流遵循 FIFO 方法,PyTorch 需要保持 CPU 和 GPU 周期之间的同步,因为它遵循“每个流一个池”的设计。这可能会导致碎片,同步开销和一些奇怪的角落情况,但 PyTorch 确保用户可能永远不会遇到它们。
共享的共同特征
- 这两个系统都使用高效的 C++内核来实现高性能。由于计算损失函数的梯度,而使用 SGD 是由所有 ML 程序完成的,PyTorch 和 Tensorflow 都提供了有效的自动微分算法。
- 两者都利用工作线程/子计算中的分布式执行和多重处理来提高性能。这两个系统都是开源的,在 ML 研究社区中很受欢迎。两者都使用异步参数更新来执行算法。
差异
py torch 比 TensorFlow 来得晚,它覆盖了 tensor flow 的很多弱点。
- PyTorch 提供了数据并行性以及调试功能,而这两者对于 TensorFlow 来说都是一个问题。相比 Tensorflow,PyTorch 对研究人员来说更容易学习。
- PyTorch 保持了控制和数据流之间的分离,而 Tensorflow 将其合并到一个数据流图中。
- PyTorch 执行反向模式自动微分,TensorFlow 也执行反向微分,尽管区别在于 Tensorflow 提供的消除开销的优化算法。
- TensorFlow 利用延迟执行直到整个程序可用,而这在 PyTorch 的情况下是不可能的,因此使用其他方法来提高效率,如自定义缓存张量收集器和引用计数。
结论
总的来说,PyTorch 在很多方面都比 Tensorflow 表现得更好,包括易用性,同时又不牺牲性能。
考虑到 PyTorch 论文中的基准测试,它比 Tensorflow 实现所有主要的 ML 算法(如 AlexNet、VGG-19 等)的性能都要好。尽管对于大规模生产系统,Tensorflow 由于其社区支持和强大的架构仍然是主要选择。
没有一种方法可以设计大型系统。每个 ML 平台在设计其特性时都考虑到了一些核心方面。对于 TensorFlow,它是性能,而对于 PyTorch,它是用户体验。