TowardsDataScience-博客中文翻译-2020-五十三-

TowardsDataScience 博客中文翻译 2020(五十三)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

通过无监督学习生成 Spotify 播放列表

原文:https://towardsdatascience.com/generating-spotify-playlists-with-unsupervised-learning-abac60182022?source=collection_archive---------25-----------------------

数字音乐

人工智能能区分愚蠢的朋克和混蛋吗?

图片— Stas Knop on Pexels

这个系列 ' 之前的博客中,我们探索了音乐流媒体巨头 Spotify 如何创建算法,完全基于其波形自动描述任何歌曲的音乐质量。这些算法可以计算一些显而易见的音乐属性(例如,一首歌有多快,它的调是什么)。然而,他们也可以得到更微妙的措施;一首歌有多快乐?是冰镇还是高能?你能随着它跳舞吗?

为了看看这是如何工作的,我创建了一个播放列表,比如说,一些折衷的内容——Kendrick Lamar 到黑色安息日,通过披头士和 Billie Eilish。当然,还有德帕西托。

让我们看看 Spotify 如何根据各种音频特征指标对这些歌曲进行分类(这些指标的完整描述可以在之前的博客中找到)。

节奏稳定、不间断的歌曲被认为更适合跳舞——因此像《真正的苗条阴影》和《卑微》这样的说唱歌曲得分很高。

正如我们在之前的博客中提到的,可跳舞性和能量并不像我们预期的那样高度相关。《黑桃 a》是最有活力的曲目,看过 motrhead 现场演出的人都不会感到惊讶。

回忆——高价曲目是‘快乐和欣快’,低价曲目是‘阴郁和悲伤’。看到比莉·埃利什在这个排名中垫底,我们不应该感到惊讶。

在这里,Spotify 给出了一个从 0 到 1 的置信度,来判断该曲目是否是原声的。“多灾多难的水上桥梁”被正确识别。黑色安息日的重金属敏感性也在排名中垫底。

“Speechiness”试图在音频文件中查找口语单词。播客得分接近 1,说唱音乐通常在 0.2 到 0.5 之间。

Spotify 正确地指出了播放列表中的一首器乐歌曲(蠢朋克),尽管也认为 Joy Division 是器乐歌曲(可能是因为伊恩·柯蒂斯的演唱风格,以及它在整体混音中的位置)。

当然,我们可以用这些方法来思考哪些歌曲在发音上相似。让我们暂时保持简单,并假设歌曲只有两个特征——舞蹈性和效价。这两个度量都取 0 到 1 之间的值,所以我们可以通过它们在散点上的两点之间的(欧几里德)距离来推断两首歌有多相似。

由红色箭头分隔的歌曲比由黄色箭头分隔的歌曲更“相似”,尽管第二对歌曲具有非常相似的舞蹈性。

我们可以扩展这个逻辑。给定播放列表中的一首歌曲,我们可以通过在散点上找到最近的 n 点来计算出 n 最相似的曲目。但是我们可以做得更复杂——假设我们想把这 32 首歌分成给定数量的播放列表(比如 5 首)。然后,我们需要某种方法来获取上面的散点图,并将这些点分成五个不同的组,其中组内的歌曲彼此“最佳相似”。

如果这听起来很像集群的用例,那是因为它是。具体来说,我们可以部署“分层聚集聚类”(HAC)。用外行人的话来说,HAC 首先将每个单独的点视为其自身的一组点。然后,它合并两个彼此“最接近”的现有集群(注意;在这种情况下,“距离”的定义是可变的——我们稍后将对此进行探讨)。HAC 算法将反复合并“闭合”聚类,直到得出所有数据点都属于一个聚类的自然结论。

HAC 阶段的示例-请记住,每个点都被视为一个“集群”,因此各个集群的数量随着每个阶段而减少

如前所述,算法如何考虑两个现有集群之间的“距离”是可变的。sci kit-lean 提供了三种“连锁标准”作为其 HAC 包的一部分:

  • 沃德(默认):选择两个聚类合并,使所有聚类内的方差增加最小。一般来说,这导致了大小相当的集群。
  • 平均:合并所有点间 平均 距离最小的两簇。
  • 完成(或称最大联动):合并两个点间 最大 距离最小的聚类。

考虑到 HAC 处理的是“距离”——抽象的或其他的——我们需要在将数据输入聚类算法之前对其进行标准缩放。这确保了我们的最终结果不会被特征单元扭曲。例如,速度通常在每分钟 70 到 180 拍之间,而大多数其他小节在 0 到 1 之间。如果没有缩放,两首节奏非常不同的歌曲将总是“相距甚远”,即使它们在其他指标上完全相同。

幸运的是,使用 Scikit-Learn 的标准缩放和 HAC 非常简单:

**from** sklearn.preprocessing **import** StandardScalersclaer = StandardScaler()
X_scaled = scaler.fit_transform(X)***#This scaled data can then be fed into the HAC alorithm* from** sklearn.cluster **import** AgglomerativeClustering***#We can tell it how many clusters we're aiming for***
agg_clust = AgglomerativeClustering(n_clusters=3)
assigned_clusters = agg_clust.fit_predict(X_scaled)

让我们将 HAC 应用到我们的播放列表中(记住,我们仍然将自己限制在两个维度上——水平轴上是 danceability,垂直轴上是 valence)。我们可以看到不同颜色的数量随着星团的融合而减少。

当然,由于两点之间的距离可以用二维来定义,所以也可以用三维来定义——下图显示了当我们添加第三个度量(“能量”)时,HAC 算法如何创建四个聚类。

接下来,我们可以继续添加维度,以同样的方式计算点之间的“距离”,我们只是失去了在“网格”上可视化结果的能力。然而,我们可以通过树状图来查看结果。按照下图从左到右,我们看到不同的歌曲是如何链接在一起成为越来越大的集群。

注意——水平距离表示两个链接的簇有多“接近”,较长的线表示歌曲“相距较远”。如果我们想要创建 n 个集群,我们可以使用树状图来完成。我们只需要在图表的适当位置画一条垂直的直线——不管相交多少条直线,都是创建的集群数。

可以说,这种聚类分析得出了一些有趣的结果。北极猴子和电台司令是显而易见的伙伴,杜阿·利帕和贾斯汀·比伯,莫特海德和黑色安息日也是如此。鲍伊、披头士、平克·弗洛伊德和埃尔维斯·普雷斯利听起来也是一个合理的组合,尽管迈克尔·杰克逊和阿姆是一个令人惊讶的组合。不过,总而言之,我们可以说,Spotify 的 metrics 结合 HAC,在对类似歌曲进行分组方面做得相当不错。

在接下来的几篇博客中,我们将看看如何用数学方法测量聚类结果的质量。然后,我们将从数千首歌曲中制作相似歌曲的播放列表,并研究如何使用 Spotify 的 API 将这些新的播放列表直接上传到用户的个人资料中。

这是我的“ Music By Numbers ”专栏中的最新博客,它使用数据来讲述关于音乐的故事。我很乐意听到对以上分析的任何评论——欢迎在下面留言,或者通过 LinkedIn 联系我!

使用 Mozilla DeepSpeech 为任何视频文件生成字幕

原文:https://towardsdatascience.com/generating-subtitles-automatically-using-mozilla-deepspeech-562c633936a7?source=collection_archive---------10-----------------------

对于那些嘴里薯条的噪音让你无法看电影的时候:)

玛利亚·特内娃在 Unsplash 上拍摄的照片

在 OTT 平台时代,仍然有一些人喜欢从 YouTube/脸书/Torrents 下载电影/视频(嘘🤫)过流。我就是其中之一,有一次,我找不到我下载的某部电影的字幕文件。然后, AutoSub 的想法打动了我,因为我以前和 DeepSpeech 合作过,我决定用它来为我的电影制作字幕。

给定一个视频文件作为输入,我的目标是生成一个。srt 文件。字幕可以导入任何现代视频播放器。在本文中,我将带您浏览一些代码。你可以在我的 GitHub 上找到这个项目,这里有关于如何在本地安装的说明。

先决条件:对 Python 的中级理解,对自动语音识别引擎的一些熟悉,以及对信号处理的基本理解将会很棒。

注意:这是我第一篇关于媒体的文章。如果你有任何建议/疑问,请写下来。快乐阅读:)

Mozilla DeepSpeech

DeepSpeech 是基于百度原创深度语音研究论文的开源语音转文本引擎。鉴于其多功能性和易用性,它是最好的语音识别工具之一。它是使用 Tensorflow 构建的,可以使用自定义数据集进行训练,在庞大的 Mozilla Common Voice 数据集上进行训练,并在 Mozilla Public License 下获得许可。最大的好处是我们可以下载模型文件并在本地执行推理只需几分钟!

虽然,DeepSpeech 确实有它的问题。该模型与非母语英语口音的语音进行斗争。对此有一个解决方法——使用我们想要预测的语言中的自定义数据集来微调模型。我将很快就如何做到这一点写另一篇文章。

如果你正在处理语音识别任务,我强烈建议你看看 DeepSpeech。

自动 Sub

让我们从安装一些我们需要的包开始。所有命令都已经在 Ubuntu 18.04 的 pip 虚拟环境中进行了测试。

  1. FFmpeg 是领先的多媒体框架,能够解码、编码、转码、复用、解复用、流式传输、过滤和播放人类和机器创造的几乎任何东西。我们需要它从我们的输入视频文件中提取音频。
$ sudo apt-get install ffmpeg
  1. DeepSpeech :从 PyPI 安装 python 包,下载模型文件。记分员文件是可选的,但大大提高了准确性。
*$* pip install deepspeech*==0.8.2**# Model file (~190 MB)* 
$ wget https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.pbmm*# Scorer file (~900 MB)* $ wget [https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.scorer](https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.scorer)

现在我们都设置好了,让我们首先使用 FFmpeg 从我们的输入视频文件中提取音频。我们需要创建一个子进程来运行 UNIX 命令。DeepSpeech 期望输入音频文件以 16kHz 采样,因此 ffmpeg 的参数如下。

现在,假设我们的输入视频文件有 2 小时长。通常不建议对整个文件运行 DeepSpeech 推断。我试过了,效果不太好。解决这个问题的一个方法是将音频文件分割成无声片段。分割后,我们有多个小文件包含我们需要推断的语音。这是使用 pyAudioAnalysis 完成的。

以下函数使用 pyAudioAnalysis 中的函数 read_audio_file()silenceRemoval() ,并从语音开始和结束的位置生成分段限制。参数以秒为单位控制平滑窗口大小,以(0,1)为单位控制权重因子。使用段限制,较小的音频文件被写入磁盘。

我们现在需要分别对这些文件运行 DeepSpeech 推断,并将推断的文本写入一个 SRT 文件。让我们首先创建一个 DeepSpeech 模型的实例,并添加 scorer 文件。然后,我们将音频文件读入一个 NumPy 数组,并将其送入语音转文本功能以产生推断。如上所述,pyAudioAnalysis 保存的文件具有以秒为单位的段限制时间。在写入 SRT 文件之前,我们需要提取这些限制并将其转换成合适的形式。这里的定义了写功能

整个过程不应超过原始视频文件持续时间的 60%。这里有一个视频,展示了在我的笔记本电脑上运行的一个例子。

自动 Sub 演示

还有一个领域我希望在未来改进。推断的文本是无格式的。我们需要添加适当的标点符号,纠正单词中可能的小错误(一个字母之外),并将很长的片段分成较小的片段(尽管这很难自动化)。

就是这样!如果您已经到达这里,感谢您的坚持:)

你可以在这里找到我: LinkedInGitHub

用 WGANs 生成合成金融时间序列

原文:https://towardsdatascience.com/generating-synthetic-financial-time-series-with-wgans-e03596eb7185?source=collection_archive---------18-----------------------

寻找稳定的平衡——泰勒·米利根在 Unsplash 上的照片

Pytorch 代码的首次实验

介绍

过度拟合是研究人员在尝试将机器学习技术应用于时间序列时遇到的问题之一。出现这个问题是因为我们使用我们已知的唯一时间序列路径训练我们的模型:实现的历史。毕竟,我们一生只见过这个世界的一种状态:无聊,不是吗?=)

特别是,并非所有可能的市场机制或事件都能在我们的数据中得到很好的体现。事实上,极不可能发生的事件,如异常高波动时期,通常会被低估,这使得模型无法得到足够好的训练。所以,当这些经过训练的算法面对新的场景时,它们可能会失败;如果我们在没有任何预防措施的情况下让它们生产足够长的时间,这种情况就会发生。

现在,如果我们可以教一个模型为相同的资产生成新的数据,会怎么样呢?如果我们有一种工具,可以产生与原始时间序列具有相同统计特性的替代现实时间序列,会怎么样?有了这样的工具,我们可以用关于不可能发生的事件或罕见的市场机制的数据来扩充我们的训练集;因此,研究人员将能够建立更好的模型,从业者将执行更好的模拟和交易回测。在这方面,最近在《金融数据科学杂志》上发表的论文的作者展示了在合成数据上训练深度模型如何减轻过度拟合并提高性能。

事实证明,生成对抗网络(GANs)可以做到这一点。GANs 是一个机器学习框架,其中两个神经网络,一个生成器(G)和一个鉴别器(D),互相玩游戏,前者试图欺骗后者生成类似真实事物的假数据。当我说“游戏”时,我指的是这里的博弈论!

然而,没有人应该获胜:GAN 的研究人员总是在 G 和 D 之间寻找纳什均衡,希望——GAN 可能很难训练——生成器已经学会如何产生虚假但真实的样本,鉴别器的最佳选择是随机猜测。

本文的目的

我在这里的目的不是深入研究 GANs 的理论(网上有很好的论文和资源),而是简单地触及基础,分享我和我的队友兼朋友 Andrea Politano 的实验结果。

虽然我们的最终目标是使用一个或多个经过训练的生成器一次生成多个时间序列,但我们选择从简单开始,逐步进行。在这方面,我们首先检查 GANs 是否能够学习我们完全理解的数据生成过程(DGP)的系列。当然,只有少数人——如果有的话——理解金融资产回报的 DGP;因此,我们开始产生假正弦波。

我们的模型

我们首先对 Pytorch 数据集进行编码,以产生不同的正弦函数。Pytorch 数据集是方便的实用程序,它使数据加载更容易,并提高了代码的可读性。点击查看

Pytorch 数据集生成正弦

然后,我们选择了 Wasserstein GAN (WGAN),因为这种特殊类型的模型具有坚实的理论基础,并显著提高了训练稳定性;此外,损失与生成器的收敛和样本质量相关-这非常有用,因为研究人员不需要不断检查生成的样本来了解模型是否在改进。最后,WGANs 比标准的 gan 对模式崩溃和架构变化更健壮。

WGANs 和 gan 有什么不同?

标准 GAN 中的损失函数量化了训练和生成的数据分布之间的距离。事实上,GANs 基于这样的思想,随着训练的进行,模型的参数逐渐更新,并且 G 学习的分布收敛到真实的数据分布。这种收敛必须尽可能平滑,重要的是要记住这个分布序列收敛的方式取决于我们如何计算每对分布之间的距离。

现在,WGANs 与标准 gan 在量化距离的方式上有所不同。常规 gan 使用Jensen–Shannon divergence(JS),而 WGANs 使用 Wasserstein distance ,其特征在于更好的属性。特别是,Wasserstein 度量是连续的,在任何地方都有良好的梯度,因此即使当真实分布和生成分布的支持位于非重叠低维流形中时,也允许更平滑的分布收敛查看这篇好的文章了解更多细节。

图片直接取自 WGANs 的原始文件。它显示了标准 GAN 的鉴别器如何饱和并导致梯度消失,而 WGAN critic 在空间的所有部分提供非常干净的梯度。

李普希茨约束

简单的 Wasserstein 距离是相当棘手的;因此,我们需要运用一个聪明的技巧——Kantorovich-Rubinstein 对偶——来克服这个障碍,获得我们问题的最终形式。按照理论,我们的瓦瑟斯坦度量的新形式中的函数 f_w 必定是 K-Lipschitz 连续的f_w 由我们的评论家学习,属于参数化函数序列; w 代表一组参数,即权重。

目标函数的最终形式——瓦瑟斯坦度量。相对于真实分布计算第一期望,而相对于噪声分布计算第二期望。z 是潜在张量,g_theta(z)代表 g 产生的伪数据。这个目标函数表明,t 批评家并不直接归因于一个概率。相反,它被训练来学习 K-Lipschitz 连续函数,以帮助计算我们的 Wasserstein 距离的最终形式。

我们说一个可微函数是 K-Lipschitz 连续的当且仅当它在任何地方都有范数至多为 K 的梯度。k 称为李普希茨常数。

Lipschitz 连续性是一种很有前途的改善 GANs 训练的技术。不幸的是,其实施仍然具有挑战性。事实上,这是一个活跃的研究领域,有几种方法可以加强约束。最初的 WGAN 论文提出了权重裁剪,但是我们采用了一种“梯度惩罚”(GP)方法,因为权重裁剪会导致容量问题,并且需要额外的参数来定义权重所在的空间。另一方面,GP 方法能够在几乎没有超参数调整的情况下实现更稳定的训练。

第一架构

我们的第一个架构来自这篇论文,其中提出了一个 WGAN-GP 架构来生成单变量合成金融时间序列——不从零开始总是一个好主意。所提出的架构混合了 G 和 D 中的线性层和卷积层,并且开箱即用。不幸的是,尽管最初的 WGAN-GP 论文明确规定“无批判批次归一化”,但使用这种设置训练看起来并不十分稳定,并且 D 是通过批次归一化(BN)实现的。

因此,我们摆脱了 BN,转而采用频谱归一化(SN)。简单来说,SN 确保 D 是 K-Lipschitz 连续的。为此,它逐步作用于你的批评家的每一层,以限制它的李普希兹常数。更多细节参见这篇伟大的文章和这篇论文

虽然从理论上讲 SN 可以消除损失中的 GP 项——SN 和 GP 应该被认为是加强 Lipschitz 连续性的替代方法——但我们的测试并不支持这一观点。然而,SN 提高了训练的稳定性并使收敛更快。因此,我们在 G 和 d 中都采用它。

最后,最初的 WGAN-GP 论文建议对 G 和 D 都使用 Adam 优化器,但是我们根据经验发现 RMSprop 更适合我们的需要。

批评家和生成器的 Pytorch 代码

要尝试一下,你还需要一段代码来计算损失,反向传递,更新模型权重,保存日志,训练样本等。你会在下面找到它。如果你需要更多关于如何使用这个代码的细节,请参考这个回购

培训师代码

结果

好消息是,我们的模型学会了生成真实的正弦样本;坏消息是正弦不是资产回报!=)那么,下一步如何增加我们对这种模式的信任呢?

用训练过的模型生成不同的真实正弦波

为什么我们不去掉简单的正弦信号,用来自一个我们知道参数的 ARMA 工艺的样本来填充 GAN 呢?!

我们选择一个简单的 ARMA(1,1)过程,其中 p =0.7 和 q =0.2,使用新的 Pytorch 数据集生成真实样本并训练模型。

Pytorch ARMA 数据集

我们现在生成一百个假样本,估计 pq看看下面的结果。pT22q是我们 DGP 唯一的参数。

用训练模型生成的合成 ARMA(1,1)样本

对合成 ARMA 样本进行的参数估计的分布。可以看出,模型很好地学习了 DGP。事实上,这些分布的模式接近 DGP 的真实参数 p 和 q,它们分别是 0.7 和 0.2。

这些结果加强了我们的信任,并鼓励进一步的研究。

奖金部分

亏损应该是什么样的?

在我们的第一次实验中,我们不停地问自己会从损失中得到什么。当然,一切都取决于训练数据、优化算法和你选择的学习率,但我们根据经验发现,成功的训练的特点是损失,尽管在开始时不稳定,但随后会逐渐收敛到较低的值。在其他条件相同的情况下,降低学习率可以稳定训练。

发电机损耗示例

评论家的损失例子

如何检查模式崩溃?

为了检查模式崩溃,我们在训练期间每次生成假样本时都使用不同的潜在张量。通过这样的程序,我们可以检查对噪声空间的不同部分进行采样时会发生什么。如果你对不同的随机张量进行采样,而 G 一直产生相同的序列,那么你正在经历模式崩溃。=(

GANs 比其他发电机制更有优势吗?

这是一个重要的问题,我想通过进一步的实验来回答:GANs 的复杂性必须通过明显更好的性能来证明。

GP 限值

我们必须提到,根据这篇论文的作者,标准 GP 方法可能不是 Lipschitz 正则化的最佳实现。此外,频谱归一化可能会不必要地限制评论家,并削弱其为 g 提供声音梯度的能力。当标准方法失败时,作者提出了一种替代方法。我们将很快试验他们的建议。

为什么要训练 D 多于 G?

一个训练有素的 D 在 WGAN 环境中至关重要,因为评论家估计真实和虚假分布之间的 Wasserstein 距离。一个最佳的评论家将提供我们的距离度量的良好估计,这反过来将导致梯度是健康的!

文献学

  • 【2019】在 GANs 中实现 Lipschitz 连续性的高效和无偏实现—周,沈等
  • 【2019】用生成式对抗网络丰富金融数据集,de Meer Pardo
  • 【2018】生成性对抗网络的谱归一化——宫藤,片冈等
  • 【2017】改善了 Wasserstein GANs — Gulrajani、Ahmed 等人的培训
  • 【2017】wasser stein GAN—Arjovsky,Chintala 等人

生成合成患者数据

原文:https://towardsdatascience.com/generating-synthetic-patient-data-b7901c3bd397?source=collection_archive---------33-----------------------

快速浏览使用 Synthea

马库斯·斯皮斯克在 Unsplash 上的照片

使用医疗保健数据进行研究可能会很棘手,为了使用某些数据,可能会遇到许多法律和财务障碍。在处理具体患者的信息时更是如此。但是,这些障碍可以通过使用开源患者生成器 Synthea 创建的合成数据来避免。Synthea 创建了可以无限制使用的真实数据。最重要的是,它非常人性化。

在你开始创建你自己的病人之前,确保你有最新版本的 JDK (JDK 14)。如果你还没有它,你可以遵循这个安装指南。确保你安装的是 JDK 14 ,而不是 JRE 14

下一步是安装 Synthea。如果你只是想运行 Synthea,而没有太多的灵活性和可定制性,你可以使用这里的链接安装基本版本。或者,如果你想更自由地处理代码,你可以创建一个 Github 库的本地副本。我将使用基本版本,并将探索更扩展版本的任务留给您(按照这些说明)。

一旦安装了 Synthea,打开您的终端并切换到下载文件的目录。对我来说,那是“下载”文件夹。

cd /directory/with/downloaded/file

一旦进入目录,只需一个命令就可以运行 Synthea!你需要做的就是打开 JAR 文件。

java -jar synthea-with-dependencies.jar

您应该会看到终端中弹出一串文本。

终端输出

就这样,你成功地创造了一个人造病人;但是,这只是 Synthea 所能提供的表面现象。

添加参数

有几个不同的参数可用于定制您创建的患者。如需完整的参数列表,请查看合成维基

下面我们来看看一些有用的。

-p size —生成指定大小的群体(该大小指定群体中活着的成员的数量,因此总群体大小可能会更大)

-g gender —生成一个性别的群体(M 代表男性,F 代表女性)

-a ageRange —生成一个年龄范围内的人口(即 30-40 岁)

-m module —生成患有特定疾病(如哮喘、皮炎、狼疮等)的人群。)完整的模块列表可在这里找到。

State City —生成特定区域内的人口(如明尼苏达州、得克萨斯州、达拉斯等)。)城市可选。一次只能运行一个状态;如果没有指定,默认的州是马萨诸塞州。

--exporter.csv.export true —将数据导出为 CSV 文件。默认格式是 FHIR。基于不同的数据,如“药物”、“就诊”、“提供者”等,患者信息被分割成多个 CSV 文件。您也可以从许多其他输出格式中进行选择。完整列表可在这里找到。

有了这些参数,我们可以生成一些非常有意义的数据。这些参数都可以组合,使用的参数越多,生成的数据就越具体。让我们看几个例子。

java -jar synthea-with-dependencies.jar -p 500 -a 20–50 Minnesota

这会生成一个居住在明尼苏达州的年龄在 20 到 50 岁之间的患者列表。该列表将有 500 个活着的患者和一些死亡的患者。

生成的患者输出示例

java -jar synthea-with-dependencies.jar -p 100 -g F -m Asthma --exporter.csv.export true

仅使用哮喘模块生成至少 100 名女性患者的列表,并将数据导出为 CSV 文件。

CSV 文件输出示例

有很多方法可以组合不同的参数来创建非常不同的数据集。我鼓励您进行试验,尝试不同的参数,看看您会得到什么。或者,如果您对基本模型感到满意,您可以安装完整存储库并探索 Synthea 提供的一切。

我希望您喜欢这个关于 Synthea 的简短介绍,也希望我向您展示了这个工具的易用性和强大功能。无论你是在做一个大规模的项目,还是在你的笔记本电脑上做实验,都有无限的可能性。

资源:

  1. https://docs . Oracle . com/javase/8/docs/technotes/guides/install/install _ overview . html # a 1097257
  2. https://synthetic health . github . io/synth ea/build/libs/synth ea-with-dependencies . jar
  3. https://github.com/synthetichealth/synthea
  4. https://github . com/synthetic health/synthetia/wiki/Developer-Setup-and-Running
  5. https://github.com/synthetichealth/synthea/wiki
  6. https://github . com/synthetic health/syntheea/wiki/Module-Gallery
  7. https://github . com/synthetic health/syntheea/wiki/CSV-File-Data-Dictionary
  8. https://github . com/synthetic health/synthetia/wiki/Common-Configuration

用 Python 生成合成地震图

原文:https://towardsdatascience.com/generating-synthetic-seismogram-in-python-519f23f07894?source=collection_archive---------13-----------------------

从测井曲线生成地震记录的七个步骤

地球物理学中最基本的概念之一是卷积。我们在地球物理操作中记录的地震数据是来自地球内部表面的反射能量,这些表面与相邻层具有不同的岩石物理特性。实际上,地震信号是地层反射率与能量源子波褶积的结果。

从测井曲线生成合成地震记录是一个建模过程。我们将使用零相位小波(如 Ricker 小波)对反射率序列(从测井数据中获得)进行卷积。我们需要地震图来将油井数据与地震数据联系起来,以完成解释任务。

在本文中,我将尝试在合成地震图的制作过程中加入一些编程的乐趣。我非常喜欢 python,因为它有各种各样的库,可以使任务比其他编程平台容易得多。
我已经上传了一个完整的 jupyter 笔记本文件和原始数据到我的 GitHub 账号里,如果你想自己尝试的话。我们将用 las 格式处理日志数据。如果你不熟悉如何将 las 文件读入 python 的过程,请查看我之前的文章。

生成地震记录所需步骤:
1-数据准备(单位转换和声波/密度测井处理)
2-时深关系构建
3-声阻抗(AI 或 Z)计算
4-反射系数(Rc)计算
5-重采样到时域和 Rc 重新计算
6-子波&卷积
7-可视化

1-数据准备

调节装置

将测井文件(las 格式)读入 python 并查看日志标题后,我们需要将密度和声波测井的单位转换为 SI 系统,因为我们需要这两种测井来计算阻抗。为了计算声阻抗,我们需要 s/m 单位的声波测井(DT)和 kg/m3 单位的密度测井(RHOB)。看标题:DT 有美制/英尺单位和 RHOB g/cm3。

w.data['DT'] = w.data['DT'] / 0.3048          #unit convert to µs/m
w.data['RHOB'] = w.data['RHOB'] * 1000        #unit convert to kg/m3

去毛刺和平滑

尖峰信号在测井记录中很常见,尤其是在声波测量中。这些尖峰并不能真正代表整个井段的岩石特性变化,需要消除。

#Sonic Despiking
dt = w.data['DT']
w.data['DT_DS'] = dt.despike(window_length=50, z=2)#Density Despiking
den = w.data['RHOB']
w.data['RHOB_DS'] = den.despike(window_length=50, z=2)

我们将输入要平滑的去尖峰数据:

#Sonic Smoothing
dt_ds = w.data['DT_DS']
w.data['DT_DS_SM'] = dt_ds.smooth(window_length=10, samples=False)#Density Smoothing
den_ds = w.data['RHOB_DS']
w.data['RHOB_DS_SM'] = den_ds.smooth(window_length=10, samples=False)

2-时间-深度关系

地震数据是在时间域测量的,而井数据主要在深度域测量。要将时间转化为深度,反之亦然,我们需要建立一种关系。有几种方法可以做到这一点,但在这里,我们使用声波测井,这是声波速度的倒数。从数学上讲,如果我们在深度区间上对 DT 积分,我们将计算出时间与深度的关系。在此之前,我们应该对上部测井数据进行补救,它与地面有数据缺口。由于这是岸上现场数据,我们没有水柱。测井曲线以上部分的替换速度几乎为 2600 米/秒。简单地说,用替换速度除以间隙层厚度(测井曲线开始深度减去 kb)就可以得到时间。

log_start = 1517          # Depth of logging starts(m) from header
kb = 15                   # Kelly Bushing elevation(m) from headergap_int = log_start - kb
repl_vel = 2632           # this is from VSP data knowledge (m/s)
log_start_time = 2.0 * gap_int / repl_vel        # 2 for twt

T-D 机构

让我们实施一体化。由于深度采样间隔为 0.1524 米,我们需要用测得的声波数据计算该厚度传播所需的时间。然后计算向下的累计行程时间。从测井起始深度计算显示第一个值为零,而我们知道零时间属于地表。所以,这个间隙的传播时间应该加到综合声波时间中。

#first replace NaN values with zero
dt_iterval = np.nan_to_num(dt) * 0.1524 / 1e6
t_cum =  np.cumsum(dt_iterval) * 2
w.data['TWT'] = t_cum + log_start_time

3-声阻抗

声阻抗(AI,有时用 Z 表示)定义为声波速度和介质密度的乘积。在反射地震学中,地质层之间的 AI 变化负责向我们收集地震数据的表面的能量反射。

df['Vsonic'] = 1e6/df.DT_DS_SM                   #(unit: m/s)
df['AI'] = df['Vsonic'] * df['RHOB_DS_SM']        #(unit: kg/m2.s)

4-反射系数

反射系数(Rc)定义为两个相邻层的阻抗差除以它们的总和。数学上,这是深度的导数。

Imp = df['AI'].values
Rc=[]
for i in range(len(Imp)-1):
    Rc.append((Imp[i+1]-Imp[i])/(Imp[i]+Imp[i+1]))

5-重采样到时域和 Rc 计算

虽然我们建立了时深关系(TDR ),但合成地震记录所需的分量在深度域。反射率系列应该转换到时域进行卷积。定义时间向量后,我们可以使用 numpy 库中的插值函数。

dt = 0.001   #sampleing interval
t_max = 3.0   # max time to create time vector
t = np.arange(0, t_max, dt)
AI_tdom = np.interp(x=t, xp = df.TWT, fp = df.AI)    #resampling# again Rc calulation but in reampled time domain
Rc_tdom = []
for i in range(len(AI_tdom)-1):
    Rc_tdom.append((AI_tdom[i+1]-AI_tdom[i])/(AI_tdom[i]+AI_tdom[i+1]))

6-小波和卷积

在反射地震学中,假设我们在地表记录的地震数据是用子波卷积(掩蔽)的能量反射。在各种子波中,里克子波是最常见的一种,因为它是零相位的,有利于地震解释任务。

# define function of ricker wavelet
def ricker(f, length, dt):
    t0 = np.arange(-length/2, (length-dt)/2, dt)
    y = (1.0 - 2.0*(np.pi**2)*(f**2)*(t0**2)) * np.exp(-(np.pi**2)*(f**2)*(t0**2))
    return t0, y

盘旋

在这一步中,我们将利用子波对反射率序列进行卷积,以创建一个合成地震图。这通常被称为翻转和滑动一个功能到另一个功能上。如果你有兴趣知道这个操作背后的数学原理,你可以看看这个伟大的视频

f=20            #wavelet frequency
length=0.512    #Wavelet vector length
dt=dt           # Sampling prefer to use smiliar to resampled AI
t0, w = ricker (f, length, dt) # ricker wavelet 
synthetic = np.convolve(w, Rc_tdom, mode='same')

7-可视化

图 1

在该图中,我们将绘制测井曲线(覆盖平滑和去尖峰结果),并计算深度域中的 AI 和反射率。关于 python 中的绘图程序,请参考笔记本文件这里的

图 2

在该图中,我们将在时域中绘制 AI 和卷积结果。我们还可以获得油井周围真实地面地震记录,这些记录可以与合成地震记录并置,以查看与数据的匹配程度。

查看最后一条轨迹表明,合成地震记录和地面地震数据之间存在适当的匹配,尤其是在关键层位。关于为什么匹配可以是相同的,有很多争论。一个重要的原因是地面地震和声波测井的频带。如果你有兴趣学习更多,请参考我的教授的书劳伦斯·r·莱恩斯

结论

在反射地震学中,合成地震记录是以褶积理论为基础的。地震图是地震解释的一个非常重要的工具,它是井和地面地震数据之间的桥梁。在这篇文章中,我试图展示我们如何用 python 中的真实数据用几行代码实现这个任务。请随意下载源代码,四处看看,并为自己的数据实现。对于评论和问题,请在这里留言。

使用 SQL 生成测试数据

原文:https://towardsdatascience.com/generating-test-data-using-sql-2a1162f5ef16?source=collection_archive---------28-----------------------

国立癌症研究所Unsplash 上拍摄的照片

数据工程

使用 SQL 支持应用程序测试和开发

开发人员在开发和测试应用程序时需要测试数据。测试数据对于应用程序开发至关重要,因为这是开发人员能够领先模仿 API 响应一步的唯一方法。生成测试数据涉及两种不同的方法。两者都应该用来使应用程序变得更好。

  • 使用应用程序期望的数据进行测试(高质量的数据)
  • 使用应用程序不期望的数据进行测试(质量差的数据)

质量差的数据通常由不支持的字符、较长的字符串、高精度浮点数等组成。了解坏数据通过系统时会发生什么总是很有帮助的。

你需要知道什么

用 SQL 生成数据非常容易。要编写测试数据生成查询,只需要了解一些事情

  • cte 和递归 cte-公用表表达式是命名的结果集。假设查询的输出有一个表名。它的工作原理和熊猫的数据框架非常相似。
  • rand(),md5()函数— rand()用于生成随机数,md5()不用于加密数据。
  • 基本字符串操作—基本字符串操作主要用于限制字段长度。
  • 子查询—使用简单的子查询为给定行生成列值。请记住,本质上,这些既不是内联子查询,也不是相关子查询。

使用 cte

递归 cte 很棒。它们可用于生成系列数据。类似的事情可以在 PostgreSQL 中使用generate_series,在 Oracle 中使用connect by level,在 MySQL 中使用会话变量@id := @id + 1来完成。几乎所有的数据库都有生成数字序列的变通方法。其中一些变通办法比其他的更好。

使用 MariaDB 的递归 cte。在 MySQL 中,您可以使用会话变量来模拟这种情况。在 Oracle 中,您可以使用“按级别连接”来实现这一点。

SQL 函数— rand()和 md5()

rand()函数给你一个 0 到 1 之间的数字。如果我们想要一个介于 0 和 100 之间的数字,我们只需将rand()函数的输出乘以 100。在下面分享的例子中,我正在生成一个介于 12 和 100 之间的数字。

生成一个介于 12 和 100 之间的数字,用于生成一个人的随机年龄数字

使用另一个 CTE 将城市列表用作表格。CTE 上的order by rand()将从城市列表中随机选择一个城市。请注意两个后续查询的结果是不同的。

从城市列表中随机选择一个城市

类似地,还有两个 cte,一个用于常见的名,另一个用于常见的姓。随机选取的这两个字段的任意组合将生成一个新名称。显然,由于order by rand()条款和提供给 CTE 的名称数量有限,名称可能会重复。

如果你不在乎名字看起来有多真实,你可以使用substring(md5(rand()),1,6)生成随机的字符串。这会给你一个包含六个字符的随机字符串。

从名和姓的列表中生成随机名称

生成随机日期

一旦你想好了在给定范围内生成随机数,那么生成一个随机日期就很容易了。以下示例显示了如何生成 1919 年 1 月 1 日到 2019 年 12 月 28 日之间的随机日期。唯一的警告是,这涵盖了任何给定月份的 1 日至 28 日之间的天数。我们完全可以编写一个查询,通过添加一些条件来覆盖所有日期。

最后,我们来看一个仅由 SQL 查询生成的样本数据集。用自动生成的真实数据获取数十万条记录只需要几秒钟的执行时间。

下面是生成以下数据的脚本

样本人口统计数据集

不使用任何外部依赖项生成测试数据的 SQL 脚本

显然,下一步是将查询参数化,并使其成为存储函数或存储过程。您可以传递要生成的记录的数量、出生日期的范围等等。

快速修复

您可能会看到一个错误,如下图所示。请注意,我试图获取 100000 条记录—在开始时在递归 CTE 中定义— id < 100000

配置变量cte_max_recursion_depth需要设置为 100000 或更大,以获取这些记录。

将会话变量 cte_max_recursion_depth 设置为 100001

获取 100K 条记录

在这之后,你应该可以走了。

用 LSTM 制作电视剧本

原文:https://towardsdatascience.com/generating-tv-scripts-with-lstm-e94be65a179?source=collection_archive---------30-----------------------

使用 LSTMs 的初学者项目

朋友们,我刚刚完成了这个项目,作为 Udacity 深度学习纳米学位的一部分。

该项目是关于预测脚本中的下一个单词,给定之前使用 LSTM 的上下文。

我会解释做这个项目时需要的主要和非常基本的概念。我介绍的部分包括:

如何将我们的数据转换成模型可以处理的形式?

  • 预处理数据
  • 批处理数据

模型架构如何处理批量数据,将数据从一层传递到另一层,以及它如何最终导致预测序列中的下一个单词。

目标受众和先决条件

这是 LSTM 完成的一个基础项目,任何对神经网络和 RNNs 有基础知识的人都可以很容易理解这一点。我试图尽可能简单地将项目分解到最基本的细节。

我在模型架构、输入形状、输出形状和每一层考虑的参数上投入了大量的精力。我已经编译并解释了这些输入/输出形状的含义,以及它们为什么以特定的方式成形,以便您更好地形象化。

注意:这个项目已经用 Pytorch 编码了。然而,LSTM 模型层考虑的参数没有太大的差别。所以,任何试图在 Keras 做这件事的人也可以参考我的解释。

我没有提到的是什么?

LSTM 是什么的理论细节,或者为什么它工作,虽然我已经触及了为什么在这种情况下它比神经网络更好的一部分。我附上了一个主项目的链接,但我没有逐行解释它的全部。

然而,我已经涵盖了我认为足以理解主要工作的部分,以便您可以将这个概念推广到其他类似的项目。

让我们直接跳进来吧🐬

照片由威廉·冈克尔Unsplash 上拍摄

文本预处理

我们有了文本,我们首先以一种可以输入 LSTM 的形式批量处理数据。

其中一个重要的部分是文本预处理,我们对文本应用了一些非常基本的必要但不充分的预处理:

  1. 用小写字母书写文本
  2. 将文本标记化:将较长的文本字符串分割成较小的片段或标记的步骤。
  3. 标点符号化,即替换“太好了!”由一个“太棒了”,“||感叹||”从而得出“太棒了!”和“伟大”不被认为是不同的词。
  4. 创建两个将单词映射到整数的查找表(因为神经网络只理解数字语言),反之亦然。

其他一些文本处理技术可能是词干化、词汇化。 这个 是文字处理上的好读物。

在对文本进行预处理并将其转换为整数后,文本数据以 LSTM 可以将其视为输入的方式进行批处理。

在进一步讨论之前,有一个非常基本但重要的问题:

为什么 RNN/LSTM 不是一个正常的神经网络?

RNN/ LSTMs 中最重要的两个术语是循环单元和隐藏单元。这两者都在考虑文本的上下文中起作用。例如,如果你加入了一个你很难交谈的讨论,你需要在你说话之前知道讨论的背景。这在隐藏单元的帮助下成为可能,隐藏单元从以前的上下文中携带信息,所以 LSTM/RNN 单元考虑 2 个输入:输入单词和隐藏单元。

正常的神经网络也可以工作,但它的工作方式不考虑前面的上下文,只给出一个单词作为下一个单词出现的概率,给定前面的单词。

输入批次:[什么,是,你,在想]目标:'问'

在上面的图像中,“h”是隐藏单元,“o”表示每个 LSTM 单元的输出,最终输出与目标的相似性匹配。

批处理示例:

让我们考虑一段文字,这是 quora 的摘录:

”“你在想什么?”老板问道我们没有问任何人任何问题。通过问几个问题,我们无法评估任何人的技能。所以我们的测试是评估这个人的态度。我们保留了一些基于候选人行为的测试,并通过闭路电视观察每个人。"

在选择了合适的序列长度和批量大小(这里分别为 4 和 3)后, LSTM 单元格的输入如下所示(这里我忽略了标点符号):

第一批:

[什么,你在想什么]->[问道]

[是,你,在想,在问]->[美]

[你,思考,问,]-->[老板]

第二批:

[思考,被问,那个,老板]->[我们]

[问,那个,老板,我们]->[没]

【那个,老板,我们,没有】-->【问】

当然,转换成整数

配料(照片由去毛刺上的刻痕拍摄)

相反,如果我们使用一个普通的神经网络,批次看起来会类似这样(批次大小:3):

第一批:

[什么]->[是]

【是】-->【你】

【思考】-->【关于】

所以很明显,神经网络没有考虑之前的环境。

模型架构和工作:

下面介绍 LSTMs 如何处理这些批次。

注意:

下面是一张带有参数的模型结构图

Batch_size:2,sequence_len:3,embedding_dim:15,output_size=vocab_size:20,hidden_dim:10

请参考它以更好地理解架构,为了便于表示,我使用了较小的数字。

1.嵌入层

因此,如果这些整数(在 vocab_to_int 字典中映射到整数的单词)被传递到 LSTM 单元,它可能会发现将这些整数视为一些权重的有偏见的含义,为了避免这个问题,我们有时一次性编码这些整数。但是,当词汇表很大时,编码会占用很多不必要的空间。

假设 vocab 字典大小=3

向量占据 3*3 单元大小的空间,即 9

[1,0,0]

[0,1,0]

[0,0,1]

现在想象一下词汇量为 10000 的情况。这将意味着 10 ⁰细胞大小的空间。

因此就有了 嵌入层 的概念。

这一次,我们没有用一次性编码替换这些单词,而是用随机选择的数字填充一些固定长度的向量。随着时间的推移,这个值矩阵与模型一起接受训练,并学习单词的近似矢量表示,这有助于为单词添加意义,并有助于提高整体准确性。

torch.nn.Embedding 图层接受以下参数:

  • num_embeddings (字典的大小),等于 vocab_size
  • embedding_dim (用于单词表示的嵌入向量的大小)

该层的输入形状为 (batch_size,seq_length) ,该层的输出形状为 (batch_size,seq_length,embedding_dim)。

对于 25000 的 vocab 大小,300 的嵌入向量工作良好,这比在一个热码编码向量的情况下 25000 的每个向量大小小得多。

一些预先训练的单词表示模型如 fastText、GloVe 是可用的,并且可以直接使用,而不是用嵌入层生成这些表示。

2.LSTM 层

torch.nn.LSTM 需要参数 input_size,hidden_dim,num_layersInput _ size&hidden _ dim分别是输入和隐藏状态下的特征个数。

注:熟悉 CNN 的人可以把它比作 CNN 层的【in _ channels】和【hidden _ dim】out _ channels

由于我们使用了嵌入层,嵌入向量长度就是输入特征的数量。因此,input _ size=embedding _ dim。参数 hidden_dimnum _ layers(LSTM 的层数,一般取值为 1 或 2)可以任意选择。

nn。LSTM 层返回一个输出和一个隐藏状态,输出的形状为 (batch_size,sequence_length,hidden_dim)。

3.线性层

该输出被整形为(batch _ size * sequence _ length,hidden_dim) 并传递到线性层,其中 in_features = hidden_dimout _ features = output _ size

在我们的例子中, output_size =词汇表大小,即输出节点的数量等于词汇表中存在的单词总数,因此网络可以从整个单词词汇表中选择最可能的下一个单词。

来自线性层的输出被整形为(batch _ size * sequence_length,output_size) ,其被进一步整形为以具有形状 (batch_size,sequence _ length,output_size) ,并且尽管我们在整个语料库上训练模型来预测序列的每个 单词下一个单词

因此,最终输出层的形状为 (batch_size,output_size)

我们的模型的输出为我们提供了给定批次的每个序列的最可能的下一个单词。💁

Batch_size:2,sequence_len:3,embedding_dim:15,output_size=vocab_size:20,hidden_dim:10(图片由作者提供)C

代码:

这个项目的完整代码可以在这里找到:

[## ankita-Das/深度学习-纳米学位

github.com](https://github.com/Ankita-Das/Deep-Learning-Nanodegree/blob/master/TV_script_generation/dlnd_tv_script_generation_copy.ipynb)

试试这个!💻

我已经试着涵盖了做这个项目的所有重要和必要的概念,但是如果你在任何地方遇到困难,如果你觉得我错过了一点,请在下面的评论中告诉我。

我将热切地等着看你完成这个项目。🙌

最美好的祝愿。

告别😁

乔纳森·肯珀在 Unsplash 上拍摄的照片

生成对抗网络

原文:https://towardsdatascience.com/generative-adversarial-network-74eef7a82117?source=collection_archive---------37-----------------------

更简单直观的解释。

超分辨率。GAN 的一个应用(来源)。

让我们假设塞尔吉奥正在计划他的下一次大抢劫,他需要他的团队前往外国。由于他的工作性质,他决定制作假护照。他不想冒险,因为他相信护照官员可以辨别出真假护照。他决定利用他的设计师和专家网络来有效地实施他的计划。

Generative Adversarial Networks have two components a generator and a discriminator. Just take my words as of now :)Let's get back to Sergio's plan and problems.

塞尔吉奥的护照生成器

下图显示了 Sergio 的行动计划,其中利用专业人员的综合技能制作假护照。

塞尔吉奥的发电机网络(图片由作者使用 ML-Visuals )。

如果我们要概括塞尔吉奥的计划,我们可以说,图表是假护照的生成器。一群基本上了解护照安全特征的专业人士试图利用他们的知识复制一个类似的护照。换句话说,给定一个空间,目标是画出一个与原始空间相似的例子。

这正是 GAN 的发生器组件的作用。它基于真实世界的例子来观察它们的特征,然后创建一个与原始例子相似的新例子。

护照官员作为鉴别者

下图显示了护照官员的工作流程。他每天检查数百本护照,塞尔吉奥希望他生成的护照能够被识别为真护照。

护照官员的工作流程(图片由作者使用 ML-Visuals 制作)。

护照官员类似于 GAN 的第二个组件,称为鉴别器鉴别器的工作是分类。它从伪造或生成的数据实例中识别出真实的数据实例。

在伪造的情况下,塞尔吉奥和护照官员是相互竞争的。塞尔吉奥希望他生成的护照被归类为真护照,而护照官员希望做好检测假护照的工作。这使他们成为对手,因此得名敌对网络

现在我们已经了解了 GAN 的两个组成部分,让我们看看如何训练它们以获得 GAN。

把它放在一起

甄别训练

在 GAN 的情况下,鉴别器只是一个分类器,它将给定的实例标记为真或假。你可以使用任何适合你的问题陈述的神经网络。

当训练一个鉴别器时,它被馈送来自真实世界的例子作为正例,以及从生成器网络生成的例子作为负例。当训练鉴别器时,发生器没有被训练,也就是说它的权重没有改变。简单地说,发生器的输出作为负实例被馈送给鉴别器。如果鉴别器随后将负实例分类为正实例,或者反之亦然,则它被损失函数惩罚,并且它的权重通过反向传播来更新。

鉴别器培训(作者使用ML-visual制作的图片)。

发电机培训

我们已经看到,生成器的工作是输出新的数据实例。发电机只不过是一个神经网络。然而,神经网络有输入。在发生器的情况下,噪声作为输入被馈送给它们,并且最终它学会生成可感知的数据。对于任何生成的图像,如果鉴别器将其归类为假的,则生成器将受到惩罚。在训练生成器时,仅更新生成器的权重。

发电机培训(图片由作者使用ML-visual)。

在实践中,使用迭代方法来训练 GAN,在这种方法中,您可以在为一次迭代训练生成器和为下一次迭代训练鉴别器之间切换。

生成性对抗网络:构建一个用 Streamlit 给 B&W 照片着色的 web 应用程序

原文:https://towardsdatascience.com/generative-adversarial-network-build-a-web-application-which-colorizes-b-w-photos-with-streamlit-5118bf0857af?source=collection_archive---------46-----------------------

使用 Streamlit 快速将生成式对抗网络模型转换为 web 应用程序,并部署到 Heroku

黑白照片彩色化的 Web 应用程序。

介绍

之前我做了一个 GAN 模型,给黑白照片上色。它运行良好,所以我希望与人们分享。在 Jupyter notebook 中编码非常方便开发,但不方便共享,因此我决定制作一个 web 应用程序并部署到 Heroku。

[## 人工智能给黑白照片上色。

利用 Fastai 的生成性对抗网络(GAN)使黑白照片变得丰富多彩

towardsdatascience.com](/colorize-black-and-white-photos-by-ai-cc607e164160)

我没有网页开发的经验和技能,所以我花了一些时间来弄清楚如何去做。我发现了一个有用的工具 Stremlit,它可以让我用 Python 编码,并快速将其转化为 web 应用程序。

我做这个 app 有几个步骤:

  1. 导出模型
  2. 下载模型
  3. 为用户创建照片上传工具
  4. 调整上传照片的大小
  5. 加载模型
  6. 分析上传的照片
  7. 显示结果
  8. 把它部署到 Heroku

导出模型

我使用 fastai 训练 GAN 模型,所以我只需使用

learner.export(export.pkl)

这会将模型导出为 pkl 文件。

下载模型

这个应用程序的第一件事是下载模型。因为模型尺寸太大(> 200MB),不方便推送到 Github 或者直接推送到 Heroku。因此,我需要应用程序从外部 url 下载文件,以确保模型准备就绪。

我将模型存储在我的 dropbox 账户中,并创建了一个可下载的链接。

EXTERNAL_DEPENDENCIES = {
"export_5.pkl": {
"url": "https://dl.dropboxusercontent.com/s/xxxxxxx/export_5.pkl?dl=0",
"size": 246698366}
}

然后我用 Streamlit 的演示代码(https://github.com/streamlit/streamlit)创建了一个带有进度条的下载功能

我可以调用函数并下载模型

for filename in EXTERNAL_DEPENDENCIES.keys():
    download_file(filename)

为用户创建上传工具

我想有一个工具,允许用户上传他们的 B&W 照片进行分析。

Streamlit 提供了一个工具来实现它:st.file_uploader

uploaded_file = st.file_uploader("upload a black&white photo", type=['jpg','png','jpeg'])

然后我将它保存到一个临时位置

if uploaded_file is not None:
   g = io.BytesIO(uploaded_file.read())  # BytesIO Object
   temporary_location = "image/temp.jpg"

   with open(temporary_location, 'wb') as out:  # Open temporary file as bytes
      out.write(g.read())  # Read bytes into file

      # close file
      out.close()

照片上传工具

调整上传照片的大小

由于计算时间和限制,如果上传的照片大于 800 像素,我想把它调整到 800 像素。我用 Opencv 写了一个简单的函数。

def resize_one(fn,img_size=800):
   dest = 'image/image_bw/temp_bw.jpg'

   # Load the image
   img=cv2.imread(str(fn))
   height,width  = img.shape[0],img.shape[1]if max(width, height)>img_size:
   if height > width:
      width=width*(img_size/height)
      height=img_size
      img=cv2.resize(img,(int(width), int(height)))
   elif height <= width:
      height=height*(img_size/width)
      width=img_size
      img=cv2.resize(img,(int(width), int(height)))cv2.imwrite(str(dest),img)

加载模型

如前所述,我使用 fastai 训练模型,所以我使用 fastai 加载模型,我创建了一个函数来加载它。

def create_learner(path,file):
   learn_gen=load_learner(path,file)
   return learn_gen

分析上传的照片并显示结果

然后我需要一个函数来预测图像的颜色,并使用 st.image 显示图像,请注意 st.image 无法读取 fastai 生成的张量,所以我需要 image2np()将其转换为 Numpy 数组。

def predict_img(fn,learn_gen,img_width=640):
   _,img,b=learn_gen.predict(open_image(fn))
   img_np=image2np(img)
   st.image(img_np,clamp=True,width=img_width)

把它们放在一起

现在我已经有了我需要的一切,让我们把它们放在主函数中。

首先,我从外部链接下载模型,并制作页面标题

def main():
   for filename in EXTERNAL_DEPENDENCIES.keys():
      download_file(filename) st.title("Black&White Photos Colorisation")

然后我制作照片上传器,调整上传照片的大小并显示它

 uploaded_file = st.file_uploader("upload a black&white photo", type=['jpg','png','jpeg'])

   if uploaded_file is not None:
      g = io.BytesIO(uploaded_file.read())  # BytesIO Object
      temporary_location = "image/temp.jpg"

      with open(temporary_location, 'wb') as out:  # Open temporary file as bytes
         out.write(g.read())  # Read bytes into file
         # close file
         out.close() resize_one("image/temp.jpg",img_size=800)
   st.image("image/temp.jpg",width=800)

然后,我制作一个按钮来调用创建模型和预测函数

start_analyse_file = st.button('Analyse uploaded file')
if start_analyse_file== True:
   learn_gen=create_learner(path='',file='export_5.pkl')
   predict_img("image/image_bw/temp_bw.jpg",learn_gen,img_width=800)

然后最后调用这个主函数

if __name__ == "__main__":
   main()

web 应用程序已准备就绪。我可以通过这个命令在我的本地机器上测试它。

黑白照片彩色化的 Web 应用程序。

部署到 Heroku

部署到 Heroku 非常简单——只需按下它。

我还需要三个文件:requirements.txt、setup.sh 和 Procfile。

requirements.txt

它包含 Heroku 需要安装的软件包。就我而言:

scikit_image==0.17.2
numpy==1.17.2
opencv_python==4.1.1.26
streamlit==0.64.0
pandas==0.25.1
https://download.pytorch.org/whl/cpu/torch-1.6.0%2Bcpu-cp36-cp36m-linux_x86_64.whl
fastai

setup.sh

mkdir -p ~/.streamlit
echo "[server]
headless = true
port = $PORT
enableCORS = false
" > ~/.streamlit/config.toml

Procfile

web: sh setup.sh && streamlit run run.py

然后注册一个免费的 Heroku 账号,下载并安装 Heroku CLI。

登录 Heroku,会弹出一个窗口输入账号和密码

heroku login

然后创建一个 web 应用程序

heroku create yourapp

将显示类似这样的内容

Creating app… done, ⬢ yourapp
https://yourapp.herokuapp.com/ | 
https://git.heroku.com/yourapp.git

然后把回购推给 Heroku

git add .
git commit -m "Enter your message here"
git push heroku master

它将开始下载和安装包,过一会儿,它就准备好了。

现在模型已经上线运行。但是…当我点击分析时,它崩溃了。这可能是由于 Heroku 自由层帐户的计算限制,它提供了 512MB 的内存,这是不够的。所以我不得不将照片的大小调整为 256 以使其运行,结果不是很令人满意,但至少有一些东西在运行。我觉得简单升级账号就能解决。

有兴趣可以试试。https://colorisation.herokuapp.com/

感谢阅读,随时给我任何建议和意见!

虚拟生成对抗网络(GAN)——循序渐进教程

原文:https://towardsdatascience.com/generative-adversarial-network-gan-for-dummies-a-step-by-step-tutorial-fdefff170391?source=collection_archive---------1-----------------------

理解、构建和训练具有防弹 Python 代码的 GANs 的终极初学者指南。

这篇文章介绍了你需要从生成性敌对网络中获得的一切。不需要预先了解 GANs。我们提供了如何在大型图像数据集上训练 GANs 并使用它们通过 Keras 生成新的名人脸的分步指南。

人工智能教父、脸书副总裁兼首席人工智能科学家 Yann LeCun 的“生成对抗网络——过去十年机器学习中最有趣的想法”。

Alex Iby 在 Unsplash 上拍摄的照片

虽然生成对抗网络(GAN)是一个源于博弈论的旧思想,但它们是由 Ian J. Goodfellow 和合著者在文章生成对抗网络中于 2014 年引入机器学习社区的。GAN 是如何工作的,它有什么用途?

甘斯可以创造出看起来像人脸照片的图像,尽管这些人脸并不属于任何真实的人。

阿甘创造的仿真人脸(来源)

我们在上一篇文章的中看到了如何使用可变自动编码器生成新的照片级逼真图像。我们的 VAE 是在著名的名人面孔数据集上接受训练的。

使用我们的 VAE 码(自创)的图像及其重建的例子

VAEs 通常会产生模糊和非真实感的人脸。这是建立生成性对抗网络的动机。

在本文中,我们将研究 GANs 如何提供一种完全不同的方法来生成与训练数据相似的数据。

概率游戏

生成新数据是一个概率游戏。当我们观察周围的世界并收集数据时,我们正在进行一项实验。一个简单的例子就是拍一张名人的脸。

这可以认为是一个概率实验,有一个未知的结果 X ,也叫随机变量

如果实验重复多次,我们通常将随机变量 X 得到值小 x概率定义为小 x 发生的次数的分数。

例如,我们可以定义这张脸是著名歌手泰瑞斯的概率。

泰瑞斯·吉布森

这种实验的所有可能结果构建了所谓的样本空间,表示为ω(所有可能的名人面孔)。

因此,我们可以将概率视为一个函数,它获取一个结果,即来自样本空间(一张照片)的一个元素,并将该结果映射到一个非负实数,使得所有这些数字的总和等于 1。

我们也称此为概率分布函数 P(X) 。当我们知道样本空间(所有可能的名人面孔)和概率分布(每个面孔出现的概率)时,我们就有了实验的完整描述,我们可以对不确定性进行推理。

你可以通过下面的文章来更新你的概率知识。

[## 理解概率。终于!

数据科学家概率概念实用指南

towardsdatascience.com](/understanding-probability-finally-576d54dccdb5)

名人脸概率分布

生成新面孔可以用一个随机变量生成问题来表示。脸部由随机变量描述,通过其 RGB 值表示,展平成一个由 N 个数字组成的向量。

名人头像的高度为 218 像素,宽度为 178 像素,有 3 个颜色通道。因此每个向量是 116412 维的。

如果我们建立一个有 116412 ( N )个轴的空间,那么每个面都将是那个空间中的一个点。名人脸概率分布函数 P(X) 会将每个脸映射到一个非负实数,使得所有脸的所有这些数字的总和等于 1。

该空间的一些点很可能代表名人的脸,而对于其他一些人来说,这是极不可能的。

名人脸概率分布函数(自创)

GAN 通过在 N 维向量空间上生成遵循名人面部概率分布的新向量来生成新的名人面部。

简单地说, GAN 会产生一个关于特定概率分布的随机变量。

如何从复杂分布中生成随机变量?

N 维向量空间上的名人脸概率分布非常复杂,我们不知道如何直接生成复杂的随机变量。

图片来自像素点上的数码相机

幸运的是,我们可以用一个适用于均匀随机变量的函数来表示复杂的随机变量。这就是变换方法的思想。它首先产生 N 个不相关的均匀随机变量,这很容易。然后它对这个简单的随机变量应用一个非常复杂的函数!非常复杂的函数自然地被神经网络近似。训练后,网络将能够接受一个简单的 N 维均匀随机变量作为输入,并返回另一个 N 维随机变量,该变量将遵循我们的名人脸概率分布。这是生成性敌对网络背后的核心动机。

为什么是生成性对抗网络?

在变换神经网络的每次训练迭代中,我们可以将名人训练集中的人脸样本与生成的人脸样本进行比较。

理论上,我们将使用最大平均差异(MMD)方法比较真实分布和基于样本生成的分布。

这将给出分布匹配误差,该误差可用于通过反向传播来更新网络。这种直接方法实际上实现起来非常复杂。

GANs 不是直接比较真实分布和生成分布,而是解决真实样本和生成样本之间的无差别任务。

一个 GAN 有三个主要组件:一个用于生成新数据的生成器模型,一个用于对生成的数据是真实人脸还是虚假人脸进行分类的鉴别器模型,以及使它们相互对抗的对抗网络

生成部分负责将 N 维均匀随机变量(噪声)作为输入,生成假面。生成器捕获概率 P(X) ,其中 X 为输入

鉴别部分是一个简单的分类器,用于评估和区分生成的人脸和真正的名人人脸。鉴别器捕获条件概率 P(Y|X) ,其中 X 为输入, Y 为标签

名人脸生成对抗网络(自创)

训练生成性对抗网络

生成网络被训练成最大化最终分类误差(真实数据和生成数据之间),而判别网络被训练成最小化最终分类误差。这就是对抗性网络概念的来源。

从博弈论的角度来看,当生成器产生遵循名人脸概率分布的样本,并且鉴别器以相等的概率预测假货或非假货时,就达到了均衡,就好像它只是抛硬币一样。

重要的是,两个网络在训练期间平等地学习,并且 汇聚到一起。一种典型的情况是,当鉴别网络在识别假货方面变得更好时,导致生成网络被卡住。

鉴别器训练过程中,我们忽略发生器损耗,只使用鉴别器损耗,这是对鉴别器将真实人脸误分类为假或将生成的人脸误分类为真实人脸的惩罚。生成器的权重通过反向传播来更新。发电机的重量没有更新。

生成器训练时,我们使用生成器损耗,惩罚生成器未能骗过鉴别器,生成一张被鉴别器归类为假的脸。鉴别器在生成器训练期间被冻结,并且只有生成器的权重通过反向传播被更新。

这就是用 GANs 合成名人脸的魔术。收敛经常被认为是短暂的,而不是稳定的。当你把一切都做对了,GANs 会提供令人难以置信的结果,如下所示。

通过细流合成 GAN-App(来源)

构建和训练 DCGAN 模型

在本节中,我们将介绍为名人面孔数据集创建、编译和训练 DCGAN 模型所需的所有步骤。深度卷积生成对抗网络(DCGANs)是使用卷积层的 gan。

鉴别器

鉴别器可以是任何图像分类器,甚至是决策树。我们使用一个卷积神经网络来代替,它有 4 层。每个块都包括一个卷积、批量归一化和另一个卷积,该卷积将图像缩小一倍,并进行另一个批量归一化。结果通过平均池,然后是返回单一输出概率的密集 sigmoid 层。

发电机

生成器获取潜在维度的噪声向量并生成图像。图像的形状应该与鉴别器输入的形状相同(spatial _ dimxspatial _ dim)。

发生器首先用密集层对噪声向量进行上采样,以便有足够的值来整形到第一个发生器块中。投影的目标是与鉴别器架构中的最后一个模块具有相同的维数。这相当于鉴频器最后一个卷积层中的 4 x 4 x 数量的滤波器,我们将在本文后面演示。

每个生成器模块应用去卷积来对图像进行上采样和批量归一化。我们使用 4 个解码器块和一个最终卷积层来获得一个 3D 张量,它表示一个具有 3 个通道的伪图像。

通过在生成器顶部添加鉴别器来构建联合 DCGAN。

在编译完整设置之前,我们必须将鉴别器模型设置为不可训练。这将冻结其权重,并告知整个网络中唯一需要训练的部分是发电机。

尽管我们编译了鉴别器,但我们不需要编译生成器模型,因为我们不单独使用生成器。

这个顺序确保鉴别器在正确的时间被更新,并在必要时被冻结。因此,如果我们训练整个模型,它将只更新生成器,而当我们训练鉴别器时,它将只更新鉴别器。

发电机架构

DCGAN 架构

甘培训

现在是艰难而缓慢的部分:训练一个生成性的对抗网络。因为 GAN 由两个独立训练的网络组成,收敛很难识别。

图像由 024–657–834 在 Pixabay 上显示

下面的步骤来回执行,让甘斯处理其他棘手的生殖问题。

步骤 1 —从训练集中选择若干真实图像。

第二步 —生成一些假图像。这是通过采样随机噪声向量并使用发生器从它们创建图像来完成的。

步骤 3 —使用假图像和真实图像训练鉴别器一个或多个时期。这将通过将所有真实图像标记为 1 并将虚假图像标记为 0 来仅更新鉴别器的权重。

鉴别器训练模式(自行创建)-不更新生成器的权重。仅调整鉴别器的权重。真假数据都用。鉴别器学会检测假图像。

步骤 4 —生成另一批伪图像。

步骤 5 —仅使用伪图像训练一个或多个时期的完整 GAN 模型。这将通过将所有假图像标记为 1 来仅更新生成器的权重。

生成器训练模式(自行创建)-鉴别器权重未更新。仅调整发生器的权重。发电机学会愚弄鉴别器。

甘训练时生成器生成的假面

上面我们可以看到我们的甘表现很好。即使照片质量不如 CelebA 训练集中的照片质量好,生成的人脸看起来也很合理。这是因为我们在重新调整的 64x64 图像上训练我们的 GAN,这些图像变得比原始的 218x178 更小更模糊。

与甘的区别

与我们上一篇文章中的中的 variable auto encoder 生成的人脸相比,DCGAN 生成的人脸看起来足够生动,足以代表足够接近现实的有效人脸。

训练时由一个可变自动编码器生成的假脸(来源

与 vae 相比,gan 是典型的高级深度生成模型。尽管 vae 注定要在一个潜在的空间工作,他们训练起来更容易也更快。VAEs 可以被认为是半监督学习器,因为它们被训练来最小化再现某个图像的损失。另一方面,GAN 正在解决一个无监督的学习问题。

结论

在这篇文章中,我解释了生成敌对网络如何能够近似一大组图像的概率分布,并使用它来生成照片级的图像。

我提供了可以工作的 Python 代码,允许您构建和训练一个 GAN 来解决您自己的任务。

你可以通过谷歌开发者Joseph Rocca 的文章了解更多关于 GANs 的信息。变型自动编码器将在我下面的文章中进一步探讨。

[## 用于假人的可变自动编码器(VAEs)——循序渐进教程

DIY 实践指南与实践证明代码建设和培训与 Keras 的名人脸上的 VAEs。

towardsdatascience.com](/variational-autoencoders-vaes-for-dummies-step-by-step-tutorial-69e6d1c9d8e9)

感谢《走向数据科学》的 Amber Teng 的编辑评论。

感谢阅读。注意安全。好好呆着。

生成对抗网络

原文:https://towardsdatascience.com/generative-adversarial-networks-6a17673db367?source=collection_archive---------13-----------------------

深度学习

用解读甘博弈

阿曼达·达尔比约恩在 Unsplash 上拍摄的照片

什么是生成性对抗网络?

Ian Goodfellow 和他的同事在 2014 年设计的 GANs 由两个神经网络组成,它们在零和游戏中一起训练,其中一个玩家的损失是另一个玩家的收益。

为了理解 GANs,我们需要熟悉生成模型和判别模型。

创成式模型 尝试使用训练集中的分布输出新的数据点。这些模型生成新的数据实例。这些模型捕捉联合概率 p(X,Y)

生成模型的类型 1。显式密度模型
2。隐式密度模型

显式密度模型定义了显式密度函数,而隐式密度模型定义了可直接生成数据的随机程序。

如果您有兴趣阅读更多关于生成模型的内容,请查看下面这个流行的 GitHub 知识库。

[## wise odd/生成模型

生成模型的集合,例如 GAN、Pytorch 中的和 Tensorflow。

github.com](https://github.com/wiseodd/generative-models)

另一方面,判别模型 捕捉条件概率 p(X/Y),它们区分不同的数据实例。

图片来源:谷歌开发者。根据知识共享署名 4.0 许可证进行许可。

生成模型解决困难的任务。与辨别模型相比,注意力细节的水平更高。简单地说,生成模型做更多的工作。生成模型试图尽可能接近真实的数据分布。

在上图中,我们可以看到判别模型试图分离 0 和 1 的数据空间。而生成模型非常接近 0 和 1 的数据空间。

现在你知道了生成模型和判别模型的基本定义,让我们来学习一下 gan。

鉴别器和发生器网络 GAN 游戏

JESHOOTS.COMUnsplash 上的照片

生成对抗网络是一种生成模型。它们并行生成完整的图像。GANs 由两个网络组成:鉴别器和发电机网络

图片来源:谷歌开发者。根据知识共享署名 4.0 许可证获得许可。

甘斯使用了一个可微函数。这通常是一个神经网络。我们称之为发电机网络。 本发电机网络采用随机输入。这些输入是噪声。这种噪声被提供给一个可微分函数,该函数将其转换和整形为一个可识别的结构。这可能是一个镜像,它高度依赖于可微分函数输入端的噪声。

对于各种噪声输入,我们可以生成许多图像。然而,生成器网络不会立即给出真实的图像。我们需要训练它。

我们如何训练这个发电机网络?可能和其他网络一样?其实没有!

生成器网络看到许多图像,并试图输出类似于相同概率分布的东西。这是怎么做到的?👀

鉴别器来了,常规的神经网络分类器。鉴别器引导我们的发电机网络。

为简单起见,我们称发电机网络的输出图像为假图像。发生器的输出,即假图像,作为输入提供给鉴别器。鉴别器还从训练数据中看到所谓的真实图像。鉴别器然后输出输入是真实图像的概率。所以 1 代表真实图像,0 代表虚假图像。与此同时,生成器还试图输出可能被鉴别器赋予概率为 1 的图像。

大多数机器学习模型试图通过优化参数来最小化一些成本函数。如果我们给 GANs 分配成本函数,我们可以说鉴别器的成本是发电机成本的负数,反之亦然。

因此,让我们通过假设鉴别器和生成器是两个参与者,a 是一个函数 f,来理解 GANs 是如何工作的。

发生器试图减少函数 f 的输出值,而鉴别器试图增加它。让我们假设这样做,直到我们达到一个平衡,在这个平衡中,发生器不能减少函数 f 的输出值,鉴别器也不能增加它。由于我们同时使用两种优化算法,一种用于发生器,另一种用于鉴别器,我们可能永远达不到平衡。亚当优化器是一个很好的选择。

简单来说,发生器和鉴别器竞争,发生器给鉴别器假数据。鉴别器也看到训练数据,预测接收到的图像是真的还是假的。

看看下面这个来自谷歌开发者机器学习速成班的例子。

生成器从不切实际的图像开始,很快学会了愚弄鉴别者。

图片来源:谷歌开发者。根据知识共享署名 4.0 许可证获得许可。

因此,随着时间的推移,生成器被训练来欺骗鉴别器,使其看起来像鉴别器看到的真实图像一样。

那么训练过程是怎样的呢?

在鉴别器的训练过程中,显示真实图像并使用计算鉴别器损失。它对来自生成器的真实和虚假图像进行分类,如果任何图像被错误分类,鉴别器损失惩罚鉴别器。通过反向传播,鉴别器更新其权重。

类似地,发生器被给予噪声输入以产生假图像。这些图像被提供给鉴别器,并且发生器损耗惩罚发生器产生被鉴别器网络分类为假的样本。权重通过从鉴别器到生成器的反向传播来更新。

需要注意的是,在鉴频器训练阶段,发生器必须保持不变。同样,鉴别器在发电机训练阶段保持不变。因此,GAN 训练以交替的方式进行。

在本节中,我们将学习设计一个 GAN,它可以生成手写数字的新图像。我们将使用著名的 MNIST 数据集。拿过来。

鉴别器架构

鉴别器将会是一个典型的线性分类器。

我们将使用的激活函数是泄漏 ReLu

图片来自 PyTorch 文档。(开源)

为什么会漏 ReLu?我们应该使用一个泄漏的 ReLU 来允许梯度不受阻碍地通过图层回流。泄漏的 ReLU 类似于正常的 ReLU,除了对于负输入值有一个小的非零输出。

作者代码。

发电机架构

生成器使用潜在样本制作假图像。这些潜在样本是映射到伪图像的向量。一个潜在向量只是一个图像的压缩的特征级表示!

为了理解什么是潜在样本,考虑一个自动编码器。连接网络的编码器和解码器部分的输出由压缩表示组成,该压缩表示也可以称为潜在向量。

所有层的激活函数保持不变,除了我们将在输出中使用 Tanh

图片来自 PyTorch 文档。(开源)

为什么在输出端出现 Tanh?
已经发现,对于发电机输出的𝑡𝑎𝑛ℎtanh,发电机表现最佳,其将输出缩放到-1 和 1 之间,而不是 0 和 1。

作者代码。

缩放图像

我们希望生成器的输出与真实图像的像素值相当,后者是 0 到 1 之间的归一化值。因此,当我们训练鉴别器时,我们还必须缩放我们的实际输入图像,使像素值在-1 和 1 之间。
这将在培训阶段完成。

一般化

为了帮助鉴别器更好地归纳,标签从 1.0 减少到 0.9 。为此,我们将使用参数 smooth 如果是真的,那么我们应该平滑我们的标签。在 PyTorch 中,这看起来像:
labels = torch.ones(size) * 0.9

我们还利用了脱落层来避免过度拟合。

损失计算

鉴别器的目标是为真实图像输出 1,为虚假图像输出 0。另一方面,生成器希望制作与真实图像非常相似的假图像。

由此我们可以说如果【D】代表了对于鉴别器的损失,那么下面可以陈述: 鉴别器的目标:D(real _ images)= 1&D(fake _ images)= 0 目标生成器: D(real_images)=)

作者代码

我们将使用 BCEWithLogitsLoss ,它结合了一个 sigmoid 激活函数(我们希望鉴别器输出一个 0–1 的值,指示一个图像是真实的还是伪造的)和二进制交叉熵损失。

Binar 交叉熵损失方程。图片由作者提供。

培养

如前所述,Adam 是一个合适的优化器。

生成器接收一个向量 z 并输出假图像。鉴别器在真实图像的训练和由生成器产生的伪图像的训练之间交替。

鉴别器培训中涉及的步骤:

  1. 我们首先计算真实图像的损失
  2. 生成假图像
  3. 计算假图像的损失
  4. 添加真实和虚假图像的损失
  5. 执行反向传播并更新鉴别器的权重

发电机培训涉及的步骤:

  1. 生成假图像
  2. 计算带有反向标签的伪图像的损失
  3. 执行反向传播并更新生成器的权重。

作者代码。

培训损失

我们将绘制发生器和鉴频器损耗与历元数的关系图。

作者代码。

培训损失。图片由作者提供。

生成器生成的样本

开始时

作者代码。

图片由作者提供。

加班

作者代码。

图片由作者提供。

这样,生成器从有噪声的图像开始,并随着时间的推移而学习。

您也可以在我的 GitHub 个人资料上查看代码和自述文件。

[## NvsYashwanth/MNIST 甘

了解 MNIST 实施的 GANs。

github.com](https://github.com/NvsYashwanth/MNIST-GAN)

结论

自从蒙特利尔大学的 Ian Goodfellow 和他的同事设计出 GANs 以来,它们就大受欢迎。申请的数量惊人。GAN 通过许多变体得到进一步改进,其中一些变体是循环 GAN、条件 GAN、渐进 GAN 等。要了解更多信息,请点击此链接。现在打开一个 Jupyter 笔记本,尝试实现你所学到的任何东西。

谢谢你。下一场见。

生成对抗网络

原文:https://towardsdatascience.com/generative-adversarial-networks-bf4e809180b3?source=collection_archive---------41-----------------------

combreakpix abay

生成对抗网络或简称 GANs 是一种神经网络,可用于生成数据,而不是试图对其进行分类。虽然有点令人不安,以下网站提供了一个令人印象深刻的例子。

[## 此人不存在

此人不存在

这个人不是 Existthispersondoesnotexist.com](https://thispersondoesnotexist.com/)

生成性对抗网络由两部分组成。一个学习生成似是而非的数据的生成器和一个学习区分生成器的假数据和真实数据的鉴别器。只要检测到虚假数据,鉴别器就会处罚生成器。

鉴别器和发生器的训练阶段是分开的。换句话说,生成器的权重保持固定,同时它为鉴别器提供训练样本,反之亦然。通常,我们交替训练鉴别器和生成器一个或多个时期。

鉴别器训练过程与任何其他神经网络的训练过程相当。鉴别器对来自发生器的真实样本和虚假数据进行分类。鉴别器损失函数惩罚将真实实例误分类为假实例或将假实例误分类为真实实例的鉴别器,并通过反向传播更新鉴别器的权重。

类似地,发生器产生样本,然后由鉴别器分类为假的或真的。然后将结果输入损失函数,该函数因生成器未能欺骗鉴别器而对其进行惩罚,并使用反向传播来修改生成器的权重。

随着生成器随着训练而改进,鉴别器的性能变得更差,因为鉴别器无法区分真假。如果生成器完全成功,那么鉴别器有 50%的准确性(不比随机机会好)。后者对 GAN 整体的收敛提出了真正的问题。如果 GAN 继续训练超过鉴别器给出完全随机反馈的点,那么发生器开始训练垃圾反馈,其自身的性能可能会受到影响。

Python 代码

让我们来看看如何用 Python 来实现一个生成式对抗网络。首先,我们导入以下库。

from keras.datasets import mnist
from keras.layers import Input, Dense, Reshape, Flatten, Dropout
from keras.layers import BatchNormalization, Activation
from keras.layers.advanced_activations import LeakyReLU
from keras.models import Sequential, Model
from keras.optimizers import Adam
import matplotlib.pyplot as plt
import sys
import numpy as np

我们将使用 MNIST 数据集,其中包含 28×28 的手写数字图像。我们用以下参数创建了一个名为GAN的类。

class GAN():
    def __init__(self):
        self.image_rows = 28
        self.image_cols = 28
        self.channels = 1
        self.image_shape = (self.image_rows, self.image_cols, self.channels)
        self.input_dim = 100
        optimizer = Adam(0.0002, 0.5)
        self.discriminator = self.build_discriminator()
        self.discriminator.compile(loss='binary_crossentropy', optimizer=optimizer, metrics=['accuracy'])
        self.generator = self.build_generator()_in = Input(shape=(self.input_dim,))
        image = self.generator(_in)self.discriminator.trainable = Falsevalidity = self.discriminator(image)self.combined = Model(_in, validity)
        self.combined.compile(loss='binary_crossentropy', optimizer=optimizer)

我们定义了发电机网络。

def build_generator(self):
        model = Sequential()
        model.add(Dense(256, input_dim=self.input_dim))
        model.add(LeakyReLU(alpha=0.2))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Dense(512))
        model.add(LeakyReLU(alpha=0.2))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Dense(1024))
        model.add(LeakyReLU(alpha=0.2))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Dense(np.prod(self.image_shape), activation='tanh'))
        model.add(Reshape(self.image_shape))
        model.summary()
        noise = Input(shape=(self.input_dim,))
        image = model(noise)
        return Model(noise, image)

我们定义鉴别器网络。

def build_discriminator(self):
        model = Sequential()
        model.add(Flatten(input_shape=self.image_shape))
        model.add(Dense(512))
        model.add(LeakyReLU(alpha=0.2))
        model.add(Dense(256))
        model.add(LeakyReLU(alpha=0.2))
        model.add(Dense(1, activation='sigmoid'))
        model.summary()
        image = Input(shape=self.image_shape)
        validity = model(image)
        return Model(image, validity)

接下来,我们定义一个函数来训练模型。我们首先对每个图像的像素进行归一化,使它们的范围从负到正。我们使用 Numpy 来创建随机噪声,它反过来被生成器用来产生假数据。除了已知为真实的样本之外,还对生成的数据训练鉴别器。最后,通过将输出与实际样本进行比较来计算发电机损耗。

def train(self, epochs, batch_size=128, sample_interval=50):
        (X_train, _), (_, _) = mnist.load_data()
        X_train = X_train / 127.5 - 1.
        X_train = np.expand_dims(X_train, axis=3)
        valid = np.ones((batch_size, 1))
        fake = np.zeros((batch_size, 1))for epoch in range(epochs):
            index = np.random.randint(0, X_train.shape[0], batch_size)
            images = X_train[index]
            noise = np.random.normal(0, 1, (batch_size, self.input_dim))
            gen_images = self.generator.predict(noise)
            d_loss_real = self.discriminator.train_on_batch(images, valid)
            d_loss_fake = self.discriminator.train_on_batch(gen_images, fake)
            d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)noise = np.random.normal(0, 1, (batch_size, self.input_dim))
            g_loss = self.combined.train_on_batch(noise, valid)print ("%d [Discriminator loss: %f, acc.: %.2f%%] [Generator loss: %f]" % (epoch, d_loss[0], 100*d_loss[1], g_loss))
            if epoch % sample_interval == 0:
               self.sample_images(epoch)

我们定期保存输出,以便在整个训练过程中评估模型的性能。

def sample_images(self, epoch):
        r, c = 5, 5
        noise = np.random.normal(0, 1, (r * c, self.input_dim))
        gen_images = self.generator.predict(noise)
        gen_images = 0.5 * gen_images + 0.5
        fig, axs = plt.subplots(r, c)
        count = 0
        for i in range(r):
            for j in range(c):
                axs[i,j].imshow(gen_images[count, :,:,0], cmap='gray')
                axs[i,j].axis('off')
                count += 1
        fig.savefig("images/%d.png" % epoch)
        plt.close()

最后,我们创建 GAN 类的一个实例并训练该模型。

gan = GAN()
gan.train(epochs=100000, batch_size=128, sample_interval=10000)

最初,GAN 的输出只是随机噪声。

然而,到最后,输出开始看起来像手写数字。

生成对抗网络

原文:https://towardsdatascience.com/generative-adversarial-networks-gans-2231c5943b11?source=collection_archive---------16-----------------------

一个温和的甘的介绍,为什么训练他们是有挑战性的,有什么主要的补救措施?

这些超现实的人脸图像不是真实的;它们是由英伟达风格的 GAN 制作的,可以控制图像的不同方面

生成对抗网络(又名 GANs)代表了深度学习领域最近最令人兴奋的创新之一。gan 最初是由蒙特利尔大学的 Ian Goodfellow 和 Yoshua Bengio 在 2014 年提出的,Yann LeCun 认为它们是“过去 10 年中最有趣的想法”

GAN 是一个生成模型,其中两个神经网络在典型的博弈论场景中竞争。第一个神经网络是生成器,负责生成类似于你的训练数据的新合成数据实例,而它的对手鉴别器试图区分生成器生成的真实(训练)和虚假(人工生成)样本。生成器的任务是试图愚弄鉴别器,鉴别器试图抵制被愚弄。这就是为什么整个系统被描述为对抗的原因。

如下图所示,生成器的输入只是一个随机噪声,而只有鉴别器可以访问用于分类目的的训练数据。该发生器仅基于鉴别器网络的反馈(在与训练数据匹配的情况下为正,在不匹配的情况下为负)来不断改进其输出。

生成对抗性网络架构

形式上,GANs 是基于零和(极小最大)非合作博弈,一方赢对方输。当第一个玩家试图最大化其行动时,第二个玩家的行动旨在最小化它们。从博弈论的角度来看,当鉴别器和发生器达到众所周知的纳什均衡时,GAN 模型收敛,该均衡是上述极小极大博弈的最佳点。由于两个参与者试图误导对方,当其中一个参与者不管对手做什么都不改变其行动时,纳什均衡就发生了。

因此,众所周知,gan 在实践中很难训练,存在严重的不收敛问题,在生成器开始产生接近真实数据的假数据之前需要一段时间。

共同面临的挑战

GANs 有许多常见的故障模式,在训练时可能会出现。在这些失败中,三大挑战问题是世界各地几个研究小组的工作重点。虽然这些问题都没有完全解决,但我们会提到一些人们已经尝试过的事情。

1。模式崩溃

在训练 GANs 时,目标是产生各种各样的模拟真实数据的假数据(即符合相同的分布)。从一个随机输入,我们想创造一个完全不同的新输出(例如一个新的现实的人脸)。然而,当发生器发现一个或一个有限多样性的样本而不考虑输入时,这对于鉴别器来说似乎是最合理的,发生器可以 合法地 学习只产生那个输出。即使它起初看起来是训练进展的良好迹象,但当训练被称为 模式崩溃helvetica 场景 的 gan 时,这是最具挑战性的失败之一。一旦鉴别器陷入局部最小值并且不能区分真实输入和发电机的输出,这种情况就可能发生。此时,生成器将很容易注意到这个黑洞,并不断生成相同的输出,或者最多是略有不同的输出。

尝试补救

  • 使用不同的损失函数,例如 Wasserstein 损失,让你训练鉴别器达到最优,而不用担心消失梯度。如果鉴别器没有陷入局部最小值,它会学习拒绝发电机稳定的输出。所以发电机必须尝试新的东西。
  • 展开的 GANs 使用发电机损耗函数,该函数不仅包含当前鉴别器的分类,还包含未来鉴别器版本的输出。所以生成器不能对单个鉴别器进行过度优化。
  • 不同的数据样本训练 GANs。

2.不收敛

GANs 经常无法收敛。通过假设两个神经网络相互竞争,目标是两个网络最终都将达到平衡,对抗性训练场景可能很容易看起来不稳定。如果不深入了解如何规避这种风险,这可能被认为是一个天真的假设,因为无法保证竞争梯度更新将导致收敛而不是随机振荡。

尝试补救

  • 一个简单的技巧是将噪声添加到鉴别器输入(真实和合成数据)中,以阻止它对其分类过于自信,或者依靠一组有限的特征来区分训练数据和生成器的输出。
  • 在与上一个技巧相同的方向上,我们可以尝试使用 NIPS'2017 中提出的 两个时标更新规则 ,其中作者提供了收敛到纳什均衡的数学证明。为鉴别器选择比生成器更高的学习速率。因此,我们的生成器将比鉴别器有更多的训练迭代和更多的训练时间。很容易理解,训练一个分类器比训练一个生成模型要容易得多。
  • 惩罚歧视者权重:参见,例如,通过正则化稳定生成性对抗网络的训练。

3.消失渐变

研究表明,如果你的鉴别器太好,那么发电机训练可能会因梯度消失而失败。实际上,最佳鉴别器不能为生成器提供足够的信息来取得进展。当我们应用反向传播时,我们使用微分的链式法则,它具有乘法效应。因此,梯度反向流动,从最后一层到第一层。当它向后流动时,它变得越来越小。有时,梯度太小,以至于初始层学习非常慢或者完全停止学习。在这种情况下,梯度根本不改变初始层的权重值,因此网络中初始层的训练被有效地停止。这就是所谓的消失渐变问题。

尝试补救

  • 我们可以使用激活功能,例如 ReLULeakyReLU ,而不是 sigmoidtanh 分别在 0 和 1 或-1 和 1 之间挤压输入值,导致梯度呈指数下降。
  • Wasserstein 损失旨在防止梯度消失,即使您将鉴别器训练到最佳状态。
  • 论文提出了一种改进的极大极小损失来处理消失梯度。

了解你的作者

拉贝赫·阿亚里是一名高级数据科学家,致力于信用风险建模和欺诈分析的应用人工智能问题,并在机器学习方面进行原创研究。我的专业领域包括使用深度神经网络的数据分析、机器学习、数据可视化、特征工程、线性/非线性回归、分类、离散优化、运筹学、进化算法和线性编程。欢迎随时给我留言这里

草图到彩色图像生成| GANs

原文:https://towardsdatascience.com/generative-adversarial-networks-gans-89ef35a60b69?source=collection_archive---------12-----------------------

GANS 系列

2-学习使用条件 GANs 构建草图到颜色图像生成模型

150 个纪元后发电机模型的输出(Gif 由作者制作)

本文是我在 towards data sciences on media 上发表的Gans-Series的一部分。如果您不知道什么是赶工,或者您对赶工有一个想法,但希望很快再复习一遍,我强烈建议您阅读 之前的文章,这只是一篇 7 分钟的阅读,为刚接触这一令人惊叹的深度学习领域的人提供了对赶工的简单理解。

如您从上面显示的 gif 中所知,本文将学习如何创建条件 GAN,以便在不了解实际情况的情况下,根据给定的黑白草图输入预测彩色图像。

在进入编码模式之前,一些需要知道的事情…

草图到彩色图像生成是一种使用条件生成对抗网络的图像到图像翻译模型,如 Phillip Isola、朱俊彦、周廷辉、Alexei A. Efros 2016、等在原论文中所述。**

当我第一次看到这篇论文时,看到作者展示的如此伟大的成果是令人惊讶的,基本的想法本身也是令人惊讶的。

应用程序

作者在原论文中描述了许多条件遗传算法的应用场景。部分选择如下。

  • 航空照片地图,航空照片地图
  • 拍照城市风景
  • 照片的建筑立面标签
  • 白天到晚上的照片
  • 照片修复
  • 彩色图像草图 (我们将在本文中构建的那个)

图片来自 Phillip Isola,朱俊彦,周廷辉,Alexei A. Efros 2016,条件敌对网络下的图像间翻译

我们将要建立一个条件生成对抗网络,它接受一个 256x256 px 的黑白草图图像,并在不知道基本事实的情况下预测该图像的彩色版本。该模型将在 Kaggle 上可用的 动漫素描着色对数据集 上进行训练,该数据集包含 14.2k 对素描着色动漫图像。

当我在我的系统上训练模型时,我在单个 GeForce GTX 1060 6GB 显卡和 16 GB RAM 上运行了 150 个 epochs,耗时约 23 小时。经过所有的努力和耐心,结果是完全值得的!

经过训练的生成器模型的输出(图片由作者提供)

现在让我们进入有趣的部分…

为了构建这个模型,我使用了 TensorFlow 2.x,大部分代码都是基于他们关于 pix 2 pix forCMP Facade Dataset的精彩教程,该教程从 Facade 标签预测建筑照片。TensorFlow 教程是理解框架和从事一些知名项目的好方法。我强烈推荐你浏览网站上的所有教程—https://www.tensorflow.org/tutorials

要求

要构建这个模型,您需要在您的系统上安装一些基本要求,以便它能够正常工作。

如果你计划使用任何像 Google Colab 这样的云环境,你需要记住训练将会花费很多时间,因为 GANs 运行起来计算量很大。Google Colab 有 12 个小时的绝对超时,这意味着笔记本内核被重置,所以你需要考虑一些要点,如安装 Google Drive 并定期保存检查点,以便你可以从超时前停止的地方继续训练。

下载数据集

下载 Kaggle 上的 动漫素描上色对数据集 并保存到文件夹目录。根文件夹将包含文件夹colorgramtrainval。为了方便起见,我们将根文件夹的路径称为path/to/dataset/

一旦检查了基本要求,并且数据集被下载到您的机器上,就该开始编写您自己的条件 GAN 了。

在我们开始之前,请注意,如果你想理解它背后的基本工作原理,我将要提供的代码不应该只是从这里复制和粘贴。不要犹豫提出你的问题,因为这是学习的方式——通过提问。

最后是代码!

首先,让我们初始化参数来配置模型的训练。如前所述,我们将使用 TensorFlow 框架,因此我们需要通过使用import tensorflow as tf来导入它。

os模块用于与操作系统交互。我们将使用它来访问和修改路径变量,以便在训练期间保存检查点。time模块让我们显示相对时间,因此,我们可以检查每个历元在训练中花费了多少时间。

matplotlib是另一个很酷的 python 库,我们将用它来绘制和显示图像。

BUFFER_SIZE用于我们在训练时混洗数据样本。这个值越高,洗牌的程度就越大,因此,模型的准确性就越高。但是对于大数据,打乱图像需要很大的处理能力。对于采用英特尔酷睿 i7–8750h CPU 和 16 GB 内存的系统,可以将其设置为等于训练数据集样本的大小,即 14,224。

N 注:shuffle()的最高效率是当你设置 buffer_size 等于数据样本的大小时。通过这种方式,它获取主存储器中的所有样本[在本例中为 14,224 个],并从中随机选择一个。如果你把它设置为 10,它会从内存中取出 10 个样本,从这 10 个样本中随机选择一个,然后对其余的样本重复这个过程。所以,检查你的机器性能,找出最佳点。

BATCH_SIZE用于将数据集分成小批量进行训练。该值越高,训练过程越快。但是您可能已经猜到了,更大的批量意味着机器上更高的负载。

现在,如果您看一下数据集,您有一个大小为 1024x512 px 的单个图像,其中左侧有一个大小为 512x512 px 的彩色图像,右侧有一个大小为 512x512 px 的黑白草图图像。

可视化数据(来自 动画草图-着色对数据集 的图像)

我们将定义一个函数load(),它将图像路径作为一个参数,并返回一个input_image,它是我们将作为模型输入的黑白草图,以及一个 real_image,它是我们想要的彩色图像。

预处理

现在我们已经加载了数据,我们需要做一些预处理,以便为模型准备数据。

下面给出了几个用于此目的的简单函数。

resize()功能用于返回 286x286 像素的图像。这样做是为了在数据集中偶然出现不同大小的图像时具有统一的图像大小。将大小从 512x512 px 减小到一半也有助于加速模型训练,因为它的计算量较小。

random_crop()函数返回所需尺寸为 256x256 px 的裁剪输入和真实图像。

normalize()函数,顾名思义,将图像归一化为[-1,1]。

在上面显示的random_jitter()函数中,所有之前的预处理函数被放在一起,随机图像被水平翻转。您可以从下面给出的图像中看到数据预处理的结果。

预处理图像(作者提供的图像)

加载训练和测试数据

load_image_train() function 用于将之前看到的所有函数放在一起,输出最终的预处理图像。

tf.data.Dataset.list_files()收集数据集的train/文件夹中所有可用 png 文件的路径。然后映射这些路径的集合,每个路径作为参数单独发送给load_image_train()函数,该函数返回最终的预处理图像并将其添加到train_dataset

最后,使用BUFFER_SIZE对这个train_dataset进行洗牌,然后如前所述分成小批量。

为了加载测试数据集,我们将使用一个类似的过程,除了一个小的变化。这里我们将省略random_crop()random_jitter()函数,因为不需要这样做来测试结果。同样,出于同样的原因,我们可以省略对数据集的混洗。

构建发电机模型

现在让我们构建生成器模型,它采用 256x256 px 的输入黑白草图图像,并输出有望类似于训练数据集中的彩色地面真实图像的图像。

生成器模型是一个 UNet 体系结构模型,并且跳过了与中间层以外的其他层的连接。请注意,由于输出和输入形状需要与连接的层相匹配,因此设计这样的架构会变得很复杂,所以要小心设计。

下采样叠层具有卷积层,这导致输入图像的尺寸减小。一旦缩小的图像通过具有某种“反向”卷积层的上采样堆栈,大小就会恢复到 256x256 像素。因此,发生器模型的输出是具有 3 个输出通道的 256x256 px 图像。

你可以看看下面给出的模型概要。

发电机模型的模型摘要(图片由作者提供)

建立鉴别器模型

鉴别器模型的主要目的是找出哪个图像来自实际训练数据集,哪个图像是生成器模型的输出。

可以看看下面给出的鉴频器的型号总结。这不像生成器模型那样复杂,因为它的基本任务只是对真实和虚假的图像进行分类。

鉴别器模型摘要(图片由作者提供)

模型的损失函数

由于我们有两个模型,我们需要两个不同的损失函数来独立计算它们的损失。

发生器的损耗通过寻找发生器输出的 sigmoid 交叉熵损耗和 1 的阵列来计算。这意味着我们正在训练它欺骗鉴别器输出值为 1,这意味着它是一个真实的图像。此外,为了使输出在结构上与目标图像相似,我们还考虑了 L1 损耗。 原论文 的作者建议LAMBDA的值保持为 100。

对于鉴别器损失,我们取真实图像和 1 阵列的相同 sigmoid 交叉熵损失,并将其与发生器模型和 0 阵列的输出图像的交叉熵损失相加。

优化者

优化器是用来改变神经网络属性的算法或方法,如权重和学习率,以减少损失。在大多数用例中,Adam Optimizer 是最好使用的优化器之一。

创建检查点

如前所述,云环境有一个特定的超时,它会中断训练过程。此外,如果您使用本地系统,可能会出现由于某些原因培训中断的情况。

gan 需要很长的训练时间,并且计算量很大。因此,最好定期保存检查点,这样您就可以恢复到最新的检查点,并从那里继续,而不会丢失您的机器之前所做的艰苦工作。

显示输出图像

上面给出的代码块是一个基本的 python 函数,它使用来自matplotlib库的pyplot模块来显示生成器模型预测的图像。

通过未训练的生成器模型显示预测图像(作者提供的图像)

记录损失

您可以将损失等重要指标记录在文件中,以便在 Tensorboard 等工具上进行训练时进行分析。

训练步骤

一个基本的训练步骤将包括以下过程:

  • 生成器输出预测
  • 鉴频器模型设计为一次有 2 个输入。第一次给出了输入的草图图像和生成的图像。下一次给它真实的目标图像和生成的图像。
  • 现在,发电机损耗和鉴频器损耗计算完毕。
  • 然后,根据损失计算梯度,并将其应用于优化器,以帮助生成器生成更好的图像,并帮助鉴别器以更好的洞察力检测真实的和生成的图像。
  • 使用之前使用tf.summary定义的summary_writer记录所有损失。

Model.fit()

TensorFlow 是一个非常棒的、易于使用的模型训练框架。像model.fit()这样的小命令就能为我们带来奇迹。

不幸的是,它在这里不能直接工作,因为我们已经创建了两个协同工作的模型。但是这也很容易做到。

在这里,我们对每个时期进行迭代,并将相对时间分配给start变量。然后我们展示了一个由生成器模型生成的图像的例子。这个例子帮助我们直观地看到生成器如何在每个时期更好地生成颜色更好的图像。然后我们调用模型的train_step函数,从计算的损耗和梯度中学习。最后,我们检查纪元编号是否能被 5 整除,以节省检查点。这意味着我们每完成 5 个训练周期就保存一个检查点。在整个时期完成后,从最终相对时间中减去开始时间,以计算该特定时期所用的时间。

啊!终于,我们到了…

我们现在要做的就是运行这一行代码,然后等待模型自己施展魔法。好吧,我们不要完全相信这个模型,我们已经做了很多艰苦的工作,现在是时候看看结果了。

恢复最新的检查点

在继续之前,我们必须恢复可用的最新检查点,以便在对映像进行测试之前加载最新版本的已定型模型。

测试输出

这从test_dataset中随机选择 5 幅图像,并将它们分别输入到发生器模型中。现在该模型被训练得足够好,并且预测输入草图图像的接近完美的彩色版本。

经过训练的生成器模型后的黑白草图输出(图片由作者提供)

保存模型

我们不要在做了这么多工作之后就把模型给毁了,好吗?

一个模特不应该在笔记本里结束自己的生命!
丹尼尔·伯克说得对

只需一行代码就可以将整个模型保存为 Keras 模型支持的. H5 文件。

结论

原来如此,原来如此!

我们不仅看到了条件 GAN 是如何工作的,而且还成功地实现了它来从给定的黑白输入草图图像预测彩色图像。

你可以从我的 GitHub 库 中浏览全部代码并下载下来,看看它在你的系统上是如何工作的。

** [## 使用条件高斯函数生成草图到彩色图像

草图到彩色图像的生成是一个图像到图像的翻译模型,使用条件生成的对抗…

tejasmorkar.github.io](https://tejasmorkar.github.io/sketch-to-color/)

如果您面临任何问题,想要提出一些改进建议,或者只是想留下一个快速反馈,请不要犹豫,通过任何最适合您的媒体与我联系。

我的联系信息:

LinkedIn:https://www.linkedin.com/in/tejasmorkar/ GitHub:https://github.com/tejasmorkar
Twitter:https://twitter.com/TejasMorkar**

生成性对抗网络

原文:https://towardsdatascience.com/generative-adversarial-networks-gans-8fc303ad5fa1?source=collection_archive---------50-----------------------

GANs 系列

1 —以更简单的方式理解 GANs

在谈到甘斯时,脸书首席人工智能科学家、ACM 图灵奖获得者扬·勒村(Yann LeCun)曾公开引用说,对抗性训练是,

“过去 10 年中最有趣的想法”

gan 是 ML 领域中相对较新的发明。它是由伊恩·古德菲勒等人在 2014 年通过这篇令人惊叹的研究论文介绍的。

那么,甘斯到底有什么了不起的?

与 Raj 在 Unsplash公路旅行照片

我们先来单独看一下术语— Generative Adversarial Network
生成性是什么意思?

深度学习可以分为两种类型的模型目标,它们是

  • 判别模型
    这些模型用于从给定的输入数据中映射出一个可能的输出。在这个领域中,你能想到的最常见的例子是分类器。他们的目标是简单地识别一类输入数据,如“垃圾邮件或非垃圾邮件”,或者像手写字符识别等。
    这些模型捕捉条件概率 P(y|x),即‘给定 x 的 y 的概率’。
  • 生成模型
    这些模型用于寻找数据集的概率分布,并生成类似结构的数据。
    生成模型主要是为了从给定的数据概率分布中找到密度函数。如下图所示,这些点表示数据在一维轴上的分布,该轴由右侧图像中的高斯密度拟合。

密度估计 —作者从 NIPS 2016 教程复制的图像:生成对抗网络

GANs 并不专注于精确地找到这个密度函数,而是观察给定的数据集,并在两个互为对手的模型的帮助下,生成符合给定数据样本中潜在结构的新样本。因此得名—

GANs 的工作

GANs 由两种模型组成,即:

  • 生成器
    其功能是获取输入噪声向量(z)并将其映射到一个图像,该图像有望类似于训练数据集中的图像。
  • 鉴别器
    鉴别器模型的主要目的是找出哪个图像来自实际训练数据集,哪个是生成器模型的输出。

由发生器和鉴别器模型组成的 GANs 的基本结构(图片由作者提供)

你可以把生成器模型想象成伪币制造者,他们想要生成假币并愚弄所有人相信它是真的,而鉴别器模型是警察,他们想要识别假币并抓住伪币制造者。

开始时,伪造者制造出完全不像真货币的随机货币。在被警察抓住后,他们从错误中吸取教训(在我们的案例中,模型丢失了),并创造出比以前更好的新货币。

假币与真币不相似的例子(图片由作者提供)

这样,警察就能更好地辨别假币和真币,同时,伪造者也能更好地制造看起来和真币相似的货币。

造假者在制造假币方面训练有素的时间点(图片由作者提供)

这是两个模型之间的最小-最大 2 人游戏,其中发电机模型试图最小化其损耗,最大化鉴别器损耗。
因此,生成器模型将输入向量(z)映射到与训练数据集中的数据相似的输出。

最后,当鉴频器不再能识别假输出时,它的准确度约为 50%。这意味着它现在是在进行随机猜测,以区分假数据和真实数据。这就是所谓的纳什均衡点。

注意:在实践中,很难达到这个平衡点,因此会产生一些问题。其中之一是模式崩溃问题,发生器在训练的早期阶段产生一个非常好的输出,然后更频繁地使用它,因为鉴别器还不能将其归类为假的。结果,生成器仅学习输出其中具有很少多样性的数据。有各种方法可以克服这一点,例如使用不同的损失函数,如 Wasserstein 损失

甘斯能做什么?

GANs 的主要目标是从给定的数据集生成新的样本。自从 GANs 发明以来,他们已经发展到可以用更好的结果和更多的特性来完成这个任务。

Ian J. Goodfellow 等人 2014 年,生成对抗网络

上图显示的是 Ian Goodfellow 等人在 2014 年发表的第一篇 GANs 论文的输出结果。集合 a)包含在手写数字的 MNIST 数据集上生成的输出,集合 b)示出了 Toronto Face 数据集的结果,集合 c)具有来自 CIFAR-10 数据集上的全连接模型的输出,集合 d)包含由 CIFAR-10 数据集上的卷积鉴别器和“去卷积”生成器模型生成的输出。

Progressive GAN 于 2017 年推出,作者表明,通过在开始时训练生成器输出低分辨率图像,并随着训练的进行提高分辨率,可以显著提高生成图像的质量。通过这种方式,他们能够从 CelebA HQ 数据集上训练的生成器中生成 1024x1024 分辨率的高质量人脸图像。

Tero Karras,Timo Aila,Samuli Laine,Jaakko Lehtinen 2017,为提高质量、稳定性和变化性而逐步种植 GANs】

关于DC GAN的论文是最重要的研究之一,它表明在 GAN 模型中使用深度卷积有助于产生更好的结果。他们没有使用任何有助于提高效率的完全连接和池化层。

本文中有趣的一点是向量空间算法,它显示输出结果可以根据简单的算术等式进行更改,如下图所示。

亚历克·拉德福德等 2015,深度卷积生成对抗网络的无监督表示学习

Cycle-gan能够将输入类映射到期望的输出集。训练是在两组数据上进行的,不需要其他标签。该模型学习将一组图像转换成另一组图像。

在下面的图像中,你可以看到马的图像是如何转换成斑马的图像的。这里值得注意的一点是,该模型了解到,相对于斑马,马主要与更绿的草原相关联。因此,该模型的结果是,斑马的输出背景较暗。当我们试图将斑马图像转换为马时,这也会产生更绿的马。

朱俊彦,朴泰星,菲利普·伊索拉,阿列克谢·埃夫罗斯 2017,使用循环一致对抗网络的不成对图像到图像翻译

最后,最有趣的 GAN 变体之一是 StarGAN。它获取面部的输入图像,然后将其映射到相应的提升面部特征。

例如,你可以输入一张脸并将其转换成相反的性别,使其更年轻或更老,改变其肤色,等等。

下图的右侧显示了如何使用 StarGAN 来改变任何输入人脸的面部表情。

Yunjey Choi 等人 2017, StarGAN:用于多领域图像到图像翻译的统一生成对抗网络

结论

所以,你已经看到甘有多强大,他们能做什么。关于 GANs 最令人惊奇的事情是,它是一个相当复杂的目标的非常简单的实现。

如果你对卷积神经网络的工作原理和反向传播有一个基本的了解,那么你可以马上开始研究 GANs。这篇文章是为了介绍生成性对抗网络背后的基本工作,以及它的变化如何有助于产生不同的和更好的结果。

在以后的帖子中,我会分享如何从头开始构建 GAN 并从中产生美妙的结果。我已经构建了一个 DCGAN 来从 CelebA 数据集生成新的面孔,以及一个条件 GAN 来学习获取一个动画的黑白草图并将其转换为彩色输出,如下所示。

***

在数据集上训练 DCGAN 模型,显示左边的 MNIST 和右边的西里巴(图片由作者提供)*

左栏为之前未见过的黑白草图测试图像,右栏为模型预测的彩色输出图像,但不知道真实情况(图片由作者提供)

生成对抗网络 GANs:初学者指南

原文:https://towardsdatascience.com/generative-adversarial-networks-gans-a-beginners-guide-f37c9f3b7817?source=collection_archive---------14-----------------------

关于 GAN 模型如何与 Python 中的示例一起工作的演练。

Unsplash 上的 drmakete 实验室拍摄的照片

T 机器学习的假设例子是围绕拥有一台能够思考并模仿通过某种程度智能测试的机器来设想的。虽然这是最终目标,但我们还没有达到,我们还有很长的路要走。在过去的几年中,已经开发了许多模型来在无人监督的模式下学习,试图与另一台计算机或人类进行竞争,以执行某项任务。这篇文章阐明了生成性对抗网络(GANs)的使用,以及如何在当今世界使用它们。

I. GANs 和机器学习

机器学习已经显示出一些识别数据分布、图像和事件序列等模式的能力,以解决分类和回归问题。Ian Goodfellow 等人在 2014 年[1]发表了一篇文章,使用两个独立的神经网络来生成与真实数据具有相似属性的合成数据。这项工作使研究界对生成逼真的图像、视频和通用合成结构数据更感兴趣。

图 1:渐进学习 GAN 模型生成人工人脸的例子。

gan 是无监督的深度学习技术。通常使用两个神经网络来实现:生成器和鉴别器。这两种模式以一种游戏设定的形式相互竞争。GAN 模型将在真实数据和由发生器产生的数据上被训练。鉴别器的工作是从真实数据中确定假数据。生成器是一个学习模型,因此最初,它可能会产生低噪声数据,甚至是完全噪声数据,这些数据不能反映真实数据的真实分布或属性。

生成器模型的主要目标是生成能够成功通过鉴别器的人工数据。该模型开始获取一些噪声,通常是高斯噪声,并产生一个格式化为像素矢量的图像。生成器必须学会如何欺骗鉴别器并赢得肯定的分类(生成的图像被分类为真实的)。每当这些生成的图像中的任何一个被成功检测为“假”时,就计算生成步骤的损失。鉴别者必须学会如何逐步识别那些假图像。每当模型不能识别假图像时,负损失被给予鉴别器。关键概念是同时训练发生器和鉴别器。

生成手写数字的示例:

研究社区有许多有趣的数据集来衡量 GAN 模型的准确性。在本文中,我们将详细使用其中的一些数据集,从 MNIST 开始。MNIST 是解释广泛用于图像处理的生成模型理论的最重要的例子之一。来自 MNIST 数据集的样本如图 2 所示。

图 2:来自 MNIST 数据集的手写数字图像样本。

为了生成人工手写图像,我们需要实现两个模型:一个用于生成假图像,另一个用于区分假图像和真图像。图 3 显示了训练 GAN 模型的总体流程。

图 GAN 学习框架,它同时训练了生成器和鉴别器。

在构建鉴别器和生成器时,有许多架构需要考虑。我们可以建立一个深度神经网络或卷积神经网络(CNN)和其他一些选项。我们将很快检查 GAN 模型的类型,但是首先,让我们现在选择 CNN。

这个例子的源代码在我的 Github 上有。

鉴别器模型架构从接收图像(28 x 28 x 1)开始,并将其通过两个卷积层,每个卷积层中有 64 个滤波器。或者,我们可以使用 128 个过滤器,这代表了每层中隐藏节点的数量。我们可以通过使用具有 64、128 和 256 个隐藏节点的三层来使神经网络架构更密集。为了简化 GAN 网络的工作方式,我们将在本教程中使用简单架构,它仍然具有很高的精度。图 4 显示了鉴频器的整体架构。

图 4:鉴别器模型的架构显示了层的数量和每个层中的参数。

生成器模型学习如何生成逼真的图像,但需要从潜在空间中的一些随机点开始。如果将图 5 中的生成器架构与图 4 中的鉴别器架构进行比较,您会发现它们看起来几乎相同。重要的是要知道,在构建发电机网络时,没有必要翻转 discrinmiator。生成器的架构可以有不同数量的层、过滤器和更高的整体复杂性。

图 5:显示每一层的生成器模型的架构。

鉴别器和发生器的另一个主要区别是激活函数的使用。discrminator 在输出层中使用 s 形。这是一个布尔分类问题,这将确保输出不是 0 就是 1。另一方面,生成器没有损失函数或任何要使用的优化算法。它使用转置卷积层从潜在空间对低分辨率密集层进行上采样,以构建更高分辨率的图像。构建生成器模型的技巧是我们不需要编译它。GAN 模型现在将结合完整的框架,该框架结合了生成器、鉴别器和编译模型。我们将在下一节详细讨论这些方面。

def building_gan(generator, discriminator):
    GAN = Sequential()
    discriminator.trainable = False
    # Adding the generator and the discriminator
    GAN.add(generator)
    GAN.add(discriminator)
    # Optimization function
    opt = tf.keras.optimizers.Adam(lr=2e-4, beta_1=0.5)
    # Compile the model 
    GAN.compile(loss='binary_crossentropy', optimizer=opt)
    return GAN

下一个动画显示了在训练过程中,发生器在每组时期的改进情况:

图 5:显示使用 GAN 模型生成的数字的渐进质量的动画图像。

GAN 的能力和挑战

(假可训练)

(1)评估

其中一个关键问题是生成的数据(无论是图像、文本还是歌曲)的质量,以及这些生成的文章的多样性。鉴别器帮助我们检查生成的数据是真是假。然而,从鉴别器的角度来看,生成的样本可能看起来很真实,但是对于人眼来说可能太明显而不会注意到。因此,我们需要与主观评价相关的评价指标。研究这个问题的一种方法是分析真实数据和生成数据之间的分布特性。

两个评估指标可以从统计上帮助测量生成数据的质量:Inception Score [3]和 Frechet Inception [4]。这两种客观指标都被研究团体广泛采用,尤其是用于测量生成图像的质量。由于本教程是一个介绍,我们不会详细介绍这些指标是如何工作的。

(2)损失函数

正如我们之前所讨论的,GAN 模型具有同时训练发生器和鉴别器的独特属性。这需要损失函数来平衡一侧(鉴别器)的训练,同时也改善另一侧(发生器)的训练。当构建鉴别器模型时,我们像任何其他神经网络架构一样明确定义损失函数。

*# Defining the discriminator model* 
**def** building_discriminator():
    *# The image dimensions provided as inputs*
    image_shape = (28, 28, 1)
    disModel = Sequential()
    disModel.add(Conv2D(64, 3, strides=2, input_shape=image_shape))
    disModel.add(LeakyReLU())
    disModel.add(Dropout(0.4))
    *# Second layer*
    disModel.add(Conv2D(64, 3, strides=2))
    disModel.add(LeakyReLU()) 
    disModel.add(Dropout(0.4))
    *# Flatten the output*
    disModel.add(Flatten()) 
    disModel.add(Dense(1, activation='sigmoid'))
    *# Optimization function*
    opt = tf.keras.optimizers.Adam(lr=2e-4, beta_1=0.5)
    *# Compile the model*
    disModel.compile(loss='binary_crossentropy', optimizer=opt, metrics = ['accuracy'])
    **return** disModel

另一方面,发电机模型没有明确定义损失函数。它基于鉴别器和根据其损失函数更新的发生器的训练。

*# Defining the generator model* 
**def** building_generator(noise_dim):
    genModel = Sequential()
    genModel.add(Dense(128 * 6 * 6, input_dim=noise_dim))
    genModel.add(LeakyReLU())
    genModel.add(Reshape((6,6,128)))
    *# Second layer*
    genModel.add(Conv2DTranspose(128, (4,4), strides=(2,2)))
    genModel.add(LeakyReLU())
    *# Third layer*
    genModel.add(Conv2DTranspose(128, (4,4), strides=(2,2)))
    genModel.add(LeakyReLU())
    genModel.add(Conv2D(1, (3,3), activation='sigmoid'))
    **return** genModel

选择损失函数的选项很少,例如:

  • 最小二乘法。
  • 瓦瑟斯坦损失函数。

(3)收敛性的确定

与 GAN 模型相关的关键问题之一是确定模型何时收敛。鉴别者和产生者之间的竞争使得游戏很难达到最后的赢家。这两种模型都希望最大化它们的增益并最小化它们的损耗。在我们的情况下,我们希望两个模型都达到这样的程度,即它们几乎可以完全猜测图像是假还是真,以及生成的图像是否会成功通过鉴别器。50-50 的机会是从博弈论中继承的完美的理想案例,其中两种模型都很难被赢得。

众所周知,GAN 模型存在收敛速度慢的问题。与其他无监督模型类似,真实标签的缺乏增加了确定训练何时可以停止的挑战。我们需要确保培训时间和产品质量之间的平衡。几个因素有助于减慢或加快训练过程,例如输入的归一化、批量归一化、梯度惩罚以及在训练 GAN 模型之前很好地训练鉴别器。

(4)产生的图像尺寸

众所周知,GAN 模型在生成图像的尺寸方面能力有限。我们在 MNIST 的例子中看到的图像尺寸只有 28 x 28 像素。这些是在实际应用中使用的非常小的图像。如果我们想要生成更大的图像,比如说 1024 x 1024,我们将需要一个更具可伸缩性的模型。研究团体一直对提高 GAN 能力感兴趣。例如,在 2017 年,T Karras 等人提出了一种称为渐进生长 GANs 的新模型来解决这种问题[2]。

GAN 模型的类型

前几节中介绍的一些挑战使得研究界扩展了 GAN 模型的思想,以解决上述一个或多个问题。本节涵盖一些流行的扩展和优化的 GAN 架构,以扩展原有的 GAN 功能。

图 6:GAN 模型架构和扩展类型的概述。

深度卷积 GAN (DCGAN): 这是一种扩展,用拉德福德等人提出的 CNN 架构取代前馈神经网络【5】。使用 CNN 架构和通过滤波器学习的想法提高了 GAN 模型的准确性。

wasser stein GAN(WGAN):WGAN 是由 M. Arjovsky 等人设计的【6】。WGAN 侧重于定义生成分布和真实分布之间的距离,这决定了模型的收敛性。他们建议使用推土机(EM)距离来有效地近似这些分布之间的差异。

Progressive GAN:Progressive GAN 由 T. Karras 等人[7]设计,并在 ICLR 会议上提出。这项工作对生成器和鉴别器从较低分辨率到较高分辨率层的渐进增长做出了很大贡献。该技术要求在计算小批量标准偏差时减少小批量的大小。ProgressiveGan 还使用均衡学习率和逐像素特征归一化。

研究从以前的类型发展到引入半监督学习模型。该模型可以转化为多类分类器,而不是让鉴别器对给定的图像进行真伪分类。例如,在 MNIST,我们有十个代表十个手写数字的类。鉴别器将有十加一个类,其中附加的类表示要分类的假图像。在这种情况下,鉴别器不仅从真实图像中学习伪像,而且将每个真实图像分类到其对应的类别。这将利用两种损失(Softmax 和 Sigmoid)拉伸目标函数,以使鉴别器更有效地对图像进行正确分类(见图 7)。我们列表中的其余类型(cGAN、CycleGAN)引入了类似的新目标。

图 7:一个生成的合成图像可能被归类为真实的,但是另一个数字分类器会把它归类为数字 8 吗?

条件 GAN (cGAN): cGAN 于 2014 年由 M. Mehdi 和 S. Osindero 发表[8]。它支持每个图像都有标签的想法,生成器学习如何为每个标签生成逼真的图像。鉴别者学会辨别假图像,同时确保它们带有正确的标签。如果我们在图 3 的学习框架上应用 cGAN,将需要进行以下更改:

图 8:基于条件 GAN 的学习框架,显示了潜在空间和用于生成图像的随机选择的标签。

pix 2 pix:pix 2 pix 模型通过考虑图像到另一组图像的转换,应用了条件 GAN 模型概念的特殊情况。P. Isola 等人[9]在 2017 年提出了这个想法。标签和产生的输出是成对图像的集合。就像翻译一部分文本内容一样,我们可以将一个图像翻译成另一个具有特定属性的图像(参见图 9)。后来,研究界提出了一种更有效的方法,如我们将在接下来讨论的 Cycle GAN。

图 9:展示图像到图像转换能力的示例。这些图片摘自于[9]中发表的原始论文。

Cycle GAN:Cycle GAN 的独特思想是使用多个生成器和鉴别器,而不是一对一的架构。Pix2pix 让模型从一对图像中学习。这个条件后来被 J-Y. Zhu 等人[10]放宽了。他们想法的新颖之处在于创造了一个循环,在这个循环中,产生的翻译被再次循环以产生原始图像。如果在翻译过程中有任何损失,差异就是我们需要优化的。可以使用两个生成器和鉴别器将输入翻译到“域 A”,然后翻译到“域 B”。这种结构化在本文中被称为前后一致性(反向翻译和再硅化)。两个鉴别器检查两个域的生成输出。这个概念非常类似于自动编码器的基本思想。

自动编码器由编码器和解码器两部分组成。这些模型超出了本文的范围,因为它们代表了使用单一模型的独立类别的学习者。自动编码器以压缩编码格式构建输入。然后,解码器从生成的压缩形式中重建输入。

渐进式氮化镓:

我们已经讨论了如何使用来自 MNIST 数据集的非常小的图像来构建 GAN 模型。图像大小仅为 128 x 128 像素。如前所述,渐进式 GAN 模型可以从低分辨率层增长到高分辨率层,从而可以扩大模型输出。我们将在下面的例子中看到如何从 64 x 64 像素生成 1024 x 1024 像素。

图 10:显示渐进 GAN 如何逐渐添加新层以达到目标分辨率的示意图。

该模型基于两个主要概念设计:淡入和微调。该模型从简单的 4 x 4 分辨率发展到更高的分辨率。它提供了在训练每一层之后增长的能力,并且我们将能够在我们逐步训练时监控输出(如图 10 所示)。alpha 参数被缩放为 0 到 1 之间的值。它决定了我们是应该使用先前训练的层还是放大。鉴别器

结论和进一步阅读

这篇文章简要介绍了 GAN 模型有多神奇。我们刚刚对 GAN 模型的工作原理有了一些基本的了解。我稍后将在单独的线程中扩展一些相关的主题。然而,如果你想了解更多,我推荐两个地方:

  • 由 Jakub Langr 和 Vladimir Bok 撰写的“GANs in Action”是一本很好的书,讲述了如何构建 GAN 模型,并详细介绍了本博客中介绍的各个方面。
  • “The-gan-zoo”是一个 Github 知识库,它跟踪该领域最近发表的所有研究文章。你可以从这个回购访问你感兴趣的文件,并导航到其他有趣的工作列表。

参考

[1]古德费勒,伊恩,等。“生成性对抗性网络。”神经信息处理系统的进展。2014.

[2] Karras,Tero 等,“为提高质量、稳定性和变化性而逐步种植甘蔗” arXiv 预印本 arXiv:1710.10196。 2017 年。

[3]萨利曼斯,蒂姆,等,“训练甘斯的改进技术”神经信息处理系统的进展。2016.

[4] Heusel,Martin 等人,“通过双时标更新规则训练的 Gans 收敛到局部纳什均衡。”神经信息处理系统的进展。2017.

[5]拉德福德,亚历克,卢克·梅斯,和苏密特·钦塔拉。"深度卷积生成对抗网络的无监督表示学习." arXiv 预印本 arXiv:1511.06434 (2015)。

[6] Arjovsky、Martin、Soumith Chintala 和 Léon Bottou。"瓦瑟斯坦·甘" arXiv 预印本 arXiv:1701.07875 (2017)。

[7] Karras,Tero 等,“为提高质量、稳定性和变化性而逐步种植甘蔗” arXiv 预印本 arXiv:1710.10196 (2017)。

[8]米尔扎、迈赫迪和西蒙·奥辛德罗。"条件生成对抗网络." arXiv 预印本 arXiv:1411.1784 (2014)。

[9] Isola,Phillip,等,“用条件对抗网络进行图像到图像的翻译”IEEE 计算机视觉和模式识别会议论文集。2017.

[10]朱,严军,等.“利用循环一致对抗网络进行不成对的映象对映象翻译”IEEE 计算机视觉国际会议论文集。2017.

生成性对抗网络——难吗?不是。

原文:https://towardsdatascience.com/generative-adversarial-networks-hard-not-eea78c1d3c95?source=collection_archive---------55-----------------------

GAN 工作流程简介。

米凯拉·帕兰特在 Unsplash 上的照片

自 2014 年问世以来,生成性对抗网络(俗称 GAN)已被广泛纳入众多研究工作。但是是什么让甘有如此神奇的魔力呢?

事实上,有很多教程都在教授如何实现 GAN 代码——但是没有足够简单地解释 GAN。在本教程中,我将介绍 GANs 背后的数学知识,并尝试涵盖最初的 GAN 论文中的大部分基础知识。您可能已经猜到这不是一个逐行代码的教程。

那么什么是甘呢?

一个生成对抗网络包含的不是一个单一的网络,而是一组至少两个总是相互“交战”的网络。一个网络被称为发电机,另一个是鉴别器。顾名思义,生成器生成由鉴别器评估的数据。两个网络之间的对抗部分或“战争”是,生成器反复尝试欺骗鉴别器,而鉴别器则被确定不在生成器的伪装下。

发电机所做的是我们的神经网络长期以来一直在做的事情。生成器试图估计数据分布,并基于该估计生成数据。一般而言,神经网络通常用于基于一些参数来估计函数。是什么使生成器不同于传统的神经网络?魔法在哪里?—发电机以噪音作为输入工作!一台机器可以从噪音中生成人的笔迹,这一事实让甘斯变得神奇。

由于我们的发电机网络以噪声作为输入,我们必须首先定义输入噪声变量的优先。让我们把先验表述为—

先验噪声分布

贝叶斯 统计推断中,一个不确定量的先验概率分布,通常简称为先验概率分布,它将表达一个人对这个量的信念之前,一些证据被考虑到了——https://en.wikipedia.org/wiki/Prior_probability

如果我们用 G 表示发电机网络,我们可以说 G 将噪声变量映射到数据空间,如下所示

发电机网络

简单地说,生成器 G 获取随机噪声,并尝试重建真实数据。假设我们将发生器给出的数据定义为 p 的输出。需要注意的是,我们没有优化p——我们优化了θ,这样我们就可以得到p的正确估计。现在,我们并不期望生成器自己训练并给出真实数据,对吗?我们需要某种东西来检查生成器,如果它不能从噪声中生成真正的数据,就对它进行某种“惩罚”。

这个“惩罚者”就是鉴别者。鉴别器(D)是其最基本的形式,是一个分类器,用于对其输入进行真假分类。因此,鉴别器输出单个标量。 D(x) 表示 x 来自真实数据而非生成器 g 的概率。由于我们已经定义了生成器和鉴别器模型以及它们如何工作,我们现在将讨论成本函数或损失函数。

损失函数

可以说,GAN 最重要的部分之一是损耗函数及其设计。在介绍 GAN 的论文中定义的损失函数是—

损失函数

这是一个“最小-最大”损失函数,我们训练鉴别器以最大化该损失函数,同时训练发生器以最小化该损失函数的最后一项。不同类型的 gan 还有其他损失函数。其中一些损失函数是对这个的修改。一个 GAN 甚至可以有多个损耗函数,一个用于发生器,一个用于鉴频器

培养

现在我们已经完成了损失函数,我们应该如何处理训练呢?我们先训练哪个网络?对于每个历元,首先计算鉴别器的梯度,并且首先更新其权重。然后,我们训练发电机。

训练算法(步骤)—

  1. 首先,我们从我们之前定义的噪声中采样一个小批量的 m 个噪声样本
  2. 然后,我们从数据生成分布(训练集)中抽取少量的 m 个样本
  3. 我们使用 SGD 根据计算的梯度更新鉴别器的权重。SGD 代表随机梯度下降。更多信息—https://medium . com/@ hmrishavbandyopadhyay/neural-network-optimizer-hard-not-2-7ecc 677892 cc
  4. 然后,我们再次从噪声先验中采样小批量的 m 个噪声样本
  5. 我们使用计算的梯度和应用 SGD 来更新生成器的权重。

训练算法

因此,我们现在已经成功地训练了一个非常原始和简单的 GAN 网络。然而,这只是对 2014 年推出的 GAN 论文的解释。从那时起,已经产生了数百种类型的 GAN,并且每一种都有它们自己的损失函数和它们自己的训练算法。

实现 GANs 可能会变得非常有趣。如果你有任何疑问,请在评论中告诉我——乐意效劳;)

查看我的博客以获得更快的更新,并订阅优质内容:D

[## 卷积博客

克罗伊斯,吕底亚(小亚细亚)的国王,曾经问特尔斐的神谕,他是否应该对波斯开战…

www.theconvolvedblog.vision](https://www.theconvolvedblog.vision)

Hmrishav Bandyopadhyay 是印度 Jadavpur 大学电子与电信系的二年级学生。他的兴趣在于深度学习、计算机视觉和图像处理。可以通过以下方式联系到他:hmrishavbandyopadhyay@gmail.com | |https://hmrishavbandy . github . io

Python 中的生成对抗网络

原文:https://towardsdatascience.com/generative-adversarial-networks-in-python-73d3972823d3?source=collection_archive---------17-----------------------

Python 中的 GANs 简介

来源

生成对抗网络(GANs)是一组用于产生合成数据的深度神经网络模型。该方法由伊恩·古德费勒于 2014 年开发,并在论文生成对抗网络中进行了概述。GAN 的目标是训练鉴别器能够区分真实和虚假数据,同时训练生成器产生可以可靠地欺骗鉴别器的数据的合成实例。

GANs 的一个流行应用是在“GANgogh”项目中,在这个项目中,经过 wikiart.org 绘画训练的 GANs 生成合成画。独立研究人员 Kenny Jones 和 Derrick Bonafilia 能够生成合成的宗教、风景、花卉和肖像图像,表现令人印象深刻。文章甘戈:用甘斯来创造艺术详细介绍了这种方法。在本帖中,我们将介绍用 python 构建基本 GAN 的过程,我们将使用它来生成手写数字的合成图像。这篇文章中使用的大部分代码可以在 GANs Tensorflow 教程页面上找到,可以在这里找到。

我们开始吧!

现在,让我们导入必要的包。让我们从导入‘matplotlib’,‘tensor flow . keras’层和‘tensor flow’库开始。让我们也定义一个变量,我们可以使用它来存储和清除我们的会话:

import matplotlib.pyplot as plt
from tensorflow.keras import layers
import tensorflow as tf
from tensorflow.python.keras import backend as K
K.clear_session()
config = tf.ConfigProto()
config.gpu_options.allow_growth = True

接下来,让我们加载“MNIST”数据集,它在“张量流”库中可用。数据包含手写数字的图像和对应于数字的标签:

(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()

让我们来看看训练数据中的第一幅图像:

plt.imshow(train_images[0], cmap='gray')

我们可以看到这是手写的‘5’。接下来,让我们重塑数据,将图像像素转换为浮点值,并将像素值归一化为-1 到 1 之间的值:

train_images = train_images.reshape(train_images.shape[0], 28, 28, 1).astype('float32')
train_images = (train_images - 127.5) / 127.5

现在让我们定义我们的发电机模型:

def generator_model():
    model = tf.keras.Sequential()
    model.add(layers.Dense(7*7*256, use_bias=False, input_shape=(100,)))
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU()) model.add(layers.Reshape((7, 7, 256)))
    assert model.output_shape == (None, 7, 7, 256) # Note: None is the batch size model.add(layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False))
    assert model.output_shape == (None, 7, 7, 128)
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU()) model.add(layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False))
    assert model.output_shape == (None, 14, 14, 64)
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU()) model.add(layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh'))
    assert model.output_shape == (None, 28, 28, 1) return model

我们首先初始化一个顺序模型对象。然后我们添加第一层,这是一个普通的密集神经网络层。还有一系列转置卷积层,是带填充的卷积层。对于那些不熟悉的,卷积层学习矩阵(核心)的权利,然后结合起来,形成过滤器用于特征提取。通过学习滤波器权重,卷积层学习表示关于图像的高级信息的卷积特征。通过学习的过滤器,这些层可以执行像边缘检测、图像锐化和图像模糊这样的操作。这些是计算机视觉中核心矩阵的一些例子:

来源

如果你有兴趣,可以在这里了解更多关于卷积神经网络的知识。还有一系列泄漏的“ReLu”层:

这些是经过修改的“ReLu”激活,通过增加“ReLu”功能的范围,有助于缓解神经元死亡问题。还有批量归一化图层,用于固定各图层输入的均值和方差。这有助于提高神经网络的速度、性能和稳定性。

发生器和鉴别器网络以类似于普通神经网络的方式被训练。即,随机初始化权重,评估损失函数及其相对于权重的梯度,并且通过反向传播迭代更新权重。

训练过程将帮助生成器模型从噪声中产生看起来真实的图像,并且鉴别器在检测看起来真实的假图像方面做得更好。让我们看一个生成器模型的输入示例。首先,让我们定义我们的生成器并初始化一些噪声“像素”数据:

generator = generator_model()
noise = tf.random.normal([1, 100])

接下来,让我们将噪声数据传入“generator_model”函数,并使用“matplotlib”绘制图像:

your_session = K.get_session()
generated_image = generator(noise, training=False)
array = generated_image[0, :, :, 0].eval(session=your_session)
plt.imshow(array, cmap='gray')

我们看到这只是一个嘈杂的黑白图像。我们的目标是让我们的生成器学习如何通过对这些嘈杂的数据进行迭代训练来生成看起来真实的数字图像,就像我们之前绘制的图像一样。经过充分的训练,我们的生成器应该能够从如上所示的噪声输入中生成真实的手写数字。

现在让我们定义我们的鉴别器函数。这将是一个用于分类的普通卷积神经网络:

def discriminator_model():
    model = tf.keras.Sequential()
    model.add(layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same',
                                     input_shape=[28, 28, 1]))
    model.add(layers.LeakyReLU())
    model.add(layers.Dropout(0.3)) model.add(layers.Conv2D(128, (5, 5), strides=(2, 2), padding='same'))
    model.add(layers.LeakyReLU())
    model.add(layers.Dropout(0.3)) model.add(layers.Flatten())
    model.add(layers.Dense(1)) return model

接下来,让我们定义损失函数和鉴别器对象:

discriminator = discriminator_model()
cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)

接下来,我们定义特定于鉴别器的损失函数。该函数测量鉴别器区分真实图像和虚假图像的能力。它将鉴别器的二进制预测与真实图像和伪图像上的标签进行比较,其中“1”对应于真实图像,“0”对应于伪图像:

def discriminator_loss(real_output, fake_output):
    real_loss = cross_entropy(tf.ones_like(real_output), real_output)
    fake_loss = cross_entropy(tf.zeros_like(fake_output), fake_output)
    total_loss = real_loss + fake_loss
    return total_loss

发生器损耗函数衡量发生器欺骗鉴别器的能力:

def generator_loss(fake_output):
    return cross_entropy(tf.ones_like(fake_output), fake_output)

由于生成器和鉴别器是独立的神经网络,它们各自都有自己的优化器。我们将使用“Adam”优化器来训练我们的鉴别器和生成器:

generator_optimizer = tf.keras.optimizers.Adam(1e-4)
discriminator_optimizer = tf.keras.optimizers.Adam(1e-4)

接下来,让我们定义历元数(训练数据的完整遍数)、噪声数据的维度大小以及要生成的样本数:

EPOCHS = 50
noise_dim = 100
num_examples_to_generate = 16

然后,我们为训练循环定义我们的函数。“@tf.function”装饰器编译该函数。“train_step()”函数从随机噪声生成图像开始:

@tf.function
def train_step(images):
    noise = tf.random.normal([BATCH_SIZE, noise_dim])
    with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
        generated_images = generator(noise, training=True) #random seed images

然后使用鉴别器对真实和伪造的图像进行分类:

@tf.function
def train_step(images):
      ...
          real_output = discriminator(images, training=True)
          fake_output = discriminator(generated_images, training=True)

然后,我们计算发生器和鉴频器损耗:

@tf.function
def train_step(images):
    ...gen_loss = generator_loss(fake_output)
        disc_loss = discriminator_loss(real_output, fake_output)

然后,我们计算损失函数的梯度:

@tf.function
def train_step(images):
    ...
    gradients_of_generator = gen_tape.gradient(gen_loss, generator.trainable_variables)
    gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.trainable_variables)

然后,我们应用优化器来找到使损失最小化的权重,并更新生成器和鉴别器:

@tf.function
def train_step(images):
    ...
    generator_optimizer.apply_gradients(zip(gradients_of_generator,        generator.trainable_variables))
    discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables))

接下来,我们定义一种方法,允许我们在训练完成后生成假图像,并保存它们:

def generate_and_save_images(model, epoch, test_input): predictions = model(test_input, training=False) fig = plt.figure(figsize=(4,4)) for i in range(predictions.shape[0]):
      plt.subplot(4, 4, i+1)
      plt.imshow(predictions[i, :, :, 0] * 127.5 + 127.5, cmap='gray')
      plt.axis('off') plt.savefig('image_at_epoch_{:04d}.png'.format(epoch))
  plt.show()

接下来,我们定义允许我们同时训练生成器和鉴别器的训练方法。接下来,让我们导入“时间”和“操作系统”模块。让我们也定义一个检查点对象,它将允许我们保存和恢复模型:

import time
import os
checkpoint_dir = './training_checkpoints'
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt")
checkpoint = tf.train.Checkpoint(generator_optimizer=generator_optimizer,                        discriminator_optimizer=discriminator_optimizer,
                                 generator=generator,
                                 discriminator=discriminator)

接下来,我们定义我们的函数,该函数从迭代历元数开始:

def train(dataset, epochs):
    for epoch in range(epochs):

在历元循环中,我们从每个训练步骤中生成图像:

def train(dataset, epochs):
        ...
        display.clear_output(wait=True)
        generate_and_save_images(generator,
                             epoch + 1,
                             seed)
        if (epoch + 1) % 5 == 0:
            checkpoint.save(file_prefix = checkpoint_prefix)print ('Time for epoch {} is {} sec'.format(epoch + 1, time.time()-start))

然后,我们从最后一个时期生成图像。让我们每隔 5 个时期保存我们的模型:

def train(dataset, epochs):
        ... display.clear_output(wait=True)
    generate_and_save_images(generator,
                           epochs,
                           seed)

最后,我们可以使用 epochs 参数对训练数据调用“train()”方法:

train(train_dataset, EPOCHS)

如果我们用两个时期运行我们的代码,我们应该得到假图像的如下输出:

我们看到输出噪声仍然很大。经过 50 个时期后,我们应该生成以下图(注意,这需要在 16 G 内存的 MacBook Pro 上运行几个小时):

正如我们所看到的,一些数字是可识别的,而另一些需要更多的训练来提高。可以推测,随着时代的增加,数字看起来会更可信。我就讲到这里,但是您可以随意使用数据并自己编码。还有许多其他数据集可以用来训练 GANs,包括英特尔图像分类数据集、 CIFAR 数据集和猫&狗数据集。其他有趣的应用包括深度假视频和深度假音频。

要开始在视频上训练 GAN,您可以查看论文 复杂数据集的对抗性视频生成 在本文中,作者在 UCF-101 动作识别数据集上训练 GAN,该数据集包含来自 YouTube 的 101 个动作类别的视频。要开始在音频上训练 GAN,请查看论文对抗性音频合成。在本文中,作者对 GAN 进行了第一个到第九个语音命令的训练,这些命令包含鼓的声音、鸟的叫声等等。

结论

总之,在这篇文章中,我们讨论了生成对抗网络(GAN)以及如何用 python 实现它。我们发现 GANs 同时训练两个神经网络,一个用于数据生成,另一个用于数据识别。鉴别器和生成器的层最显著地分别包含转置卷积和普通卷积层,它们学习图像的高级特征表示。我鼓励你尝试在一些其他有趣的数据上训练 GAN,比如我上面提到的语音或视频数据集。同样,这篇文章中使用的代码可以在 GANs Tensorflow 教程页面上找到,可以在这里找到。我希望你觉得这篇文章有用/有趣。这篇文章的代码也可以在 GitHub 上找到。感谢您的阅读!

使用 seq2seq 模型的生成型聊天机器人!

原文:https://towardsdatascience.com/generative-chatbots-using-the-seq2seq-model-d411c8738ab5?source=collection_archive---------4-----------------------

深度学习|自然语言处理

一个聊天机器人,产生一个响应,而不是从现有的选择!

聊天机器人是一种为用户提供真实对话体验的软件。有封闭域聊天机器人和开放域(生成型)聊天机器人。封闭域聊天机器人是一个用预定义文本进行响应的聊天机器人。顾名思义,生成型聊天机器人会生成响应。

UnsplashNeONBRAND 拍摄的照片

下面的文章展示了如何在机器学习分类器的帮助下创建封闭域聊天机器人。

[## 创建封闭域聊天机器人的朴素贝叶斯方法!

有一种简单有效的方法来创建使用朴素贝叶斯分类器的封闭域聊天机器人。

towardsdatascience.com](/a-naive-bayes-approach-towards-creating-closed-domain-chatbots-f93e7ac33358)

在上面的文章中,答案是固定的,机器学习帮助选择用户问题中给出的正确答案。但是在这里,我们不会从预定义的响应中进行选择,而是基于训练语料库生成响应。对于这种方法,我们将使用编码器-解码器(seq2seq)模型。

seq2seq 创建创成式聊天机器人方法介绍

seq2seq 模型也称为编码器-解码器模型,使用长短期记忆 LSTM 从训练语料库中生成文本。seq2seq 模型在机器翻译应用中也很有用。seq2seq 或编码器-解码器模型用简单的话来说是做什么的?它预测用户输入中给定的单词,然后使用该单词出现的可能性来预测接下来的每个单词。在构建我们的生成式聊天机器人时,我们将使用这种方法来生成用户输入中给出的文本

编码器-解码器模型

编码器输出最终状态向量(存储器),该向量成为解码器的初始状态。我们使用一种叫做 的方法,教师强制 来训练解码器,使其能够预测前面单词中给定的目标序列中的后续单词。如上所示,状态通过编码器传递到解码器的每一层。“嗨”、“怎么样”、“是”和“你”被称为输入标记,而“我”、“我”和“好”被称为目标标记。令牌“am”的可能性取决于前面的单词和编码器状态。我们正在添加'< END >'标记,让我们的解码器知道何时停止。你可以在这里了解更多关于 seq2seq 车型的信息。

让我们从头开始构建我们的生成性聊天机器人吧!我们要做的第一项任务是预处理我们的数据集。

预处理数据集

我们将要使用的数据集是从 Kaggle 中收集的。你可以在下面找到。它包含人类的反应和机器人的反应。每个条目有 2363 个。

[## rDany 聊天

157 次聊天和 6300 多条信息与一个(假的)虚拟伙伴

www.kaggle.com](https://www.kaggle.com/eibriel/rdany-conversations)

首先,我们必须在正则表达式的帮助下清理我们的语料库。然后,我们将需要像人类反应-机器人反应这样的配对,以便我们可以训练我们的 seq2seq 模型。我们将如下所示执行这些任务。

import re
import random
data_path = "human_text.txt"
data_path2 = "robot_text.txt"
# Defining lines as a list of each line
with open(data_path, 'r', encoding='utf-8') as f:
  lines = f.read().split('\n')with open(data_path2, 'r', encoding='utf-8') as f:
  lines2 = f.read().split('\n')lines = [re.sub(r"\[\w+\]",'hi',line) for line in lines]
lines = [" ".join(re.findall(r"\w+",line)) for line in lines]
lines2 = [re.sub(r"\[\w+\]",'',line) for line in lines2]
lines2 = [" ".join(re.findall(r"\w+",line)) for line in lines2]
# grouping lines by response pair
pairs = list(zip(lines,lines2))
#random.shuffle(pairs)

创建对子后,我们也可以在训练前洗牌。我们的对子现在看起来像这样:

[('hi', 'hi there how are you'), ('oh thanks i m fine this is an evening in my timezone', 'here is afternoon'),...]

这里,“hi”是输入序列,“hi there how are you”是目标序列。我们必须为输入序列和目标序列创建单独的列表,我们还需要为数据集中的唯一标记(输入标记和目标标记)创建列表。对于目标序列,我们将在序列的开头添加“”,在序列的结尾添加“”,以便我们的模型知道在哪里开始和结束文本生成。我们将这样做,如下所示。

import numpy as npinput_docs = []
target_docs = []
input_tokens = set()
target_tokens = set()for line in pairs[:400]:
  input_doc, target_doc = line[0], line[1]
  # Appending each input sentence to input_docs
  input_docs.append(input_doc)
  # Splitting words from punctuation  
  target_doc = " ".join(re.findall(r"[\w']+|[^\s\w]", target_doc))
  # Redefine target_doc below and append it to target_docs
  target_doc = '<START> ' + target_doc + ' <END>'
  target_docs.append(target_doc)

  # Now we split up each sentence into words and add each unique word to our vocabulary set
  for token in re.findall(r"[\w']+|[^\s\w]", input_doc):
    if token not in input_tokens:
      input_tokens.add(token)
  for token in target_doc.split():
    if token not in target_tokens:
      target_tokens.add(token)input_tokens = sorted(list(input_tokens))
target_tokens = sorted(list(target_tokens))
num_encoder_tokens = len(input_tokens)
num_decoder_tokens = len(target_tokens)

注意:为了简单起见,我们只取前 400 对,但结果是,我们会得到非常低的准确度。

我们的数据集有唯一的输入标记和目标标记。现在,我们将创建一个输入特征字典,将输入标记存储为键-值对,单词是键,值是索引。类似地,对于目标标记,我们将创建一个目标特性字典。特征字典将帮助我们把我们的句子编码成一个热点向量。毕竟计算机只懂数字。为了对句子进行解码,我们需要创建逆向特征字典,将索引存储为键,将单词存储为值。

input_features_dict = dict(
    [(token, i) for i, token in enumerate(input_tokens)])
target_features_dict = dict(
    [(token, i) for i, token in enumerate(target_tokens)])reverse_input_features_dict = dict(
    (i, token) for token, i in input_features_dict.items())
reverse_target_features_dict = dict(
    (i, token) for token, i in target_features_dict.items())

培训设置

为了训练我们的 seq2seq 模型,我们将使用三个独热向量矩阵,编码器输入数据、解码器输入数据和解码器输出数据。我们对解码器使用两个矩阵的原因是 seq2seq 模型在训练时使用的一种称为 教师强制 的方法。这背后的想法是什么?我们有一个来自前一个时间步的输入令牌来帮助模型训练当前的目标令牌。让我们创建这些矩阵。

#Maximum length of sentences in input and target documents
max_encoder_seq_length = max([len(re.findall(r"[\w']+|[^\s\w]", input_doc)) for input_doc in input_docs])
max_decoder_seq_length = max([len(re.findall(r"[\w']+|[^\s\w]", target_doc)) for target_doc in target_docs])encoder_input_data = np.zeros(
    (len(input_docs), max_encoder_seq_length, num_encoder_tokens),
    dtype='float32')
decoder_input_data = np.zeros(
    (len(input_docs), max_decoder_seq_length, num_decoder_tokens),
    dtype='float32')
decoder_target_data = np.zeros(
    (len(input_docs), max_decoder_seq_length, num_decoder_tokens),
    dtype='float32')for line, (input_doc, target_doc) in enumerate(zip(input_docs, target_docs)):
    for timestep, token in enumerate(re.findall(r"[\w']+|[^\s\w]", input_doc)):
        #Assign 1\. for the current line, timestep, & word in encoder_input_data
        encoder_input_data[line, timestep, input_features_dict[token]] = 1.

    for timestep, token in enumerate(target_doc.split()):
        decoder_input_data[line, timestep, target_features_dict[token]] = 1.
        if timestep > 0:
            decoder_target_data[line, timestep - 1, target_features_dict[token]] = 1.

为了清楚地了解编码器 _ 输入 _ 数据的尺寸如何工作,请参见下图。解码器 _ 输入 _ 数据解码器 _ 目标 _ 数据同样具有尺寸。

编码器-解码器训练设置

我们的编码器模型需要一个输入层和一个 LSTM 层,输入层定义了一个用于保存独热向量的矩阵,而层具有一些隐藏状态。解码器模型结构与编码器几乎相同,但这里我们将状态数据与解码器输入一起传入。

from tensorflow import keras
from keras.layers import Input, LSTM, Dense
from keras.models import Model#Dimensionality
dimensionality = 256#The batch size and number of epochs
batch_size = 10
epochs = 600#Encoder
encoder_inputs = Input(shape=(None, num_encoder_tokens))
encoder_lstm = LSTM(dimensionality, return_state=True)
encoder_outputs, state_hidden, state_cell = encoder_lstm(encoder_inputs)
encoder_states = [state_hidden, state_cell]#Decoder
decoder_inputs = Input(shape=(None, num_decoder_tokens))
decoder_lstm = LSTM(dimensionality, return_sequences=True, return_state=True)
decoder_outputs, decoder_state_hidden, decoder_state_cell = decoder_lstm(decoder_inputs, initial_state=encoder_states)
decoder_dense = Dense(num_decoder_tokens, activation='softmax')
decoder_outputs = decoder_dense(decoder_outputs)

您可以在这里了解更多关于如何编码编码器-解码器模型的信息,因为对它的完整解释超出了本文的范围。

建立和训练 seq2seq 模型

现在,我们将创建 seq2seq 模型,并使用编码器和解码器数据对其进行训练,如下所示。

#Model
training_model = Model([encoder_inputs, decoder_inputs], decoder_outputs)#Compiling
training_model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'], sample_weight_mode='temporal')#Training
training_model.fit([encoder_input_data, decoder_input_data], decoder_target_data, batch_size = batch_size, epochs = epochs, validation_split = 0.2)
training_model.save('training_model.h5')

这里,我们使用 rmsprop 作为优化器,使用分类交叉熵作为损失函数。我们称之为fit()【方法】通过给定编码器和解码器的输入数据(X/input)和解码器的目标数据(Y/label)。训练结束后,我们得到的训练准确率在 20%左右。这种较低准确性的原因是我们只使用了 400 对数据集。如果在更大的数据集上训练,可以实现更高的准确性。

测试设置

现在,为了处理模型没有看到的输入,我们需要一个逐步解码的模型,而不是使用教师强制,因为我们创建的模型只有在目标序列已知的情况下才能工作在生成型聊天机器人应用程序中,我们不知道对用户传入的输入会产生什么样的响应。为此,我们将不得不构建一个 seq2seq 模型。让我们首先用编码器输入和编码器输出状态构建一个编码器模型。我们将在之前训练好的模型的帮助下完成这项工作。

from keras.models import load_model
training_model = load_model('training_model.h5')encoder_inputs = training_model.input[0]
encoder_outputs, state_h_enc, state_c_enc = training_model.layers[2].output
encoder_states = [state_h_enc, state_c_enc]
encoder_model = Model(encoder_inputs, encoder_states)

接下来,我们将需要为解码器输入状态创建占位符,因为我们不知道我们需要解码什么或者我们将得到什么隐藏状态。

latent_dim = 256
decoder_state_input_hidden = Input(shape=(latent_dim,))
decoder_state_input_cell = Input(shape=(latent_dim,))
decoder_states_inputs = [decoder_state_input_hidden, decoder_state_input_cell]

现在,我们将借助之前培训的解码器 LSTM 和密集层来创建新的解码器状态和输出。

decoder_outputs, state_hidden, state_cell = decoder_lstm(decoder_inputs, initial_state=decoder_states_inputs)
decoder_states = [state_hidden, state_cell]
decoder_outputs = decoder_dense(decoder_outputs)

最后,我们有解码器输入层,来自编码器的最终状态,来自解码器密集层的解码器输出,以及解码器输出状态,它是网络从一个字到下一个字期间的存储器。我们现在可以将所有这些放在一起,并设置如下所示的解码器模型。

decoder_model = Model([decoder_inputs] + decoder_states_inputs, [decoder_outputs] + decoder_states)

测试我们的模型

最后,我们将创建一个函数,它接受我们的文本输入,并使用我们创建的编码器和解码器生成响应。在下面的函数中,我们传入表示文本句子的 NumPy 矩阵,并从中获取生成的响应。我为几乎每一行代码都添加了注释,以便您快速理解。下面的函数是这样的:1。)我们从编码器 2 中检索输出状态。)我们将输出状态传递给解码器(这是解码器的初始隐藏状态),以逐字解码句子 3。)在解码每个字之后更新解码器的隐藏状态,以便我们可以使用先前解码的字来帮助解码新的字

一旦我们遇到我们在预处理任务中添加到目标序列的''标记,或者我们达到序列的最大长度,我们就会停止。

def decode_response(test_input):
    #Getting the output states to pass into the decoder
    states_value = encoder_model.predict(test_input)
    #Generating empty target sequence of length 1
    target_seq = np.zeros((1, 1, num_decoder_tokens))
    #Setting the first token of target sequence with the start token
    target_seq[0, 0, target_features_dict['<START>']] = 1.

    #A variable to store our response word by word
    decoded_sentence = ''

    stop_condition = Falsewhile not stop_condition:
      #Predicting output tokens with probabilities and states
      output_tokens, hidden_state, cell_state = decoder_model.predict([target_seq] + states_value)#Choosing the one with highest probability
      sampled_token_index = np.argmax(output_tokens[0, -1, :])
      sampled_token = reverse_target_features_dict[sampled_token_index]
      decoded_sentence += " " + sampled_token#Stop if hit max length or found the stop token
      if (sampled_token == '<END>' or len(decoded_sentence) > max_decoder_seq_length):
        stop_condition = True#Update the target sequence
      target_seq = np.zeros((1, 1, num_decoder_tokens))
      target_seq[0, 0, sampled_token_index] = 1.
      #Update states
      states_value = [hidden_state, cell_state]return decoded_sentence

将所有这些放在一起——生成聊天机器人

让我们创建一个包含运行聊天机器人所需方法的类。

class ChatBot:
  negative_responses = ("no", "nope", "nah", "naw", "not a chance", "sorry")
  exit_commands = ("quit", "pause", "exit", "goodbye", "bye", "later", "stop")#Method to start the conversation
  def start_chat(self):
    user_response = input("Hi, I'm a chatbot trained on random dialogs. Would you like to chat with me?\n")

    if user_response in self.negative_responses:
      print("Ok, have a great day!")
      return
    self.chat(user_response)#Method to handle the conversation
  def chat(self, reply):
    while not self.make_exit(reply):
      reply = input(self.generate_response(reply)+"\n")

  #Method to convert user input into a matrix
  def string_to_matrix(self, user_input):
    tokens = re.findall(r"[\w']+|[^\s\w]", user_input)
    user_input_matrix = np.zeros(
      (1, max_encoder_seq_length, num_encoder_tokens),
      dtype='float32')
    for timestep, token in enumerate(tokens):
      if token in input_features_dict:
        user_input_matrix[0, timestep, input_features_dict[token]] = 1.
    return user_input_matrix

  #Method that will create a response using seq2seq model we built
  def generate_response(self, user_input):
    input_matrix = self.string_to_matrix(user_input)
    chatbot_response = decode_response(input_matrix)
    #Remove <START> and <END> tokens from chatbot_response
    chatbot_response = chatbot_response.replace("<START>",'')
    chatbot_response = chatbot_response.replace("<END>",'')
    return chatbot_response#Method to check for exit commands
  def make_exit(self, reply):
    for exit_command in self.exit_commands:
      if exit_command in reply:
        print("Ok, have a great day!")
        return True
    return False

chatbot = ChatBot()

在上面的代码中,所有方法都是不言自明的。下面是我们的生成式聊天机器人的最终输出!

与聊天机器人对话!

你可以在 GitHub 的这里找到上面的所有代码,在 LinkedIn 的这里找到我。

未来范围与限制

这里我们使用了一个非常小的数据集,得到了大约 20%的准确率。将来对于更大的数据集,该模型可能会提供更好的准确性。使用这种方法创建聊天机器人的局限性在于,我们需要一个非常大的数据集来为用户提供最佳响应,正如我们在上面的输出中可以看到的那样,由于数据集较小,聊天机器人在某些情况下不会给出正确的响应。

我们可以用上面显示的方法做的一个类似的任务是机器翻译。下面的文章展示了我们如何使用 seq2seq 模型来执行机器翻译。

[## 基于 seq2seq 模型的机器翻译:不同的方法

使用 seq2seq 模型讨论两种不同的机器翻译方法。

towardsdatascience.com](/machine-translation-with-the-seq2seq-model-different-approaches-f078081aaa37)

结论

当开放域架构使我们能够执行无限的文本生成时,封闭域架构侧重于从一组预定义的响应中选择响应。封闭域系统使用意图分类、实体识别和响应选择。但是对于一个开放领域的聊天机器人来说,意图分类更加困难,并且可能有大量的意图。开放域或生成模型不是选择完整的响应,而是逐字生成响应,允许新的语言组合。

LukasUnsplash 拍摄的照片

在行业中,一些公司使用封闭域聊天机器人来确保用户总是从预定义的聊天机器人那里收到正确的响应。自然语言处理(NLP)领域正在开发和训练神经网络,以模拟人脑处理语言的方式。这种深度学习策略可以让计算机更有效地处理人类语言。

从零开始的生成分类算法

原文:https://towardsdatascience.com/generative-classification-algorithms-from-scratch-d6bf0a81dcf7?source=collection_archive---------18-----------------------

机器从零开始学习

艾达、QDA 和朴素贝叶斯

二次判别分析决策边界。(图片由作者提供。来源。)

概率生成算法(如朴素贝叶斯、线性判别分析和二次判别分析)已经成为流行的分类工具。这些方法可以通过 scikit-learn 在 Python 中轻松实现,或者通过 e1071 在 R 中轻松实现。但是这些方法实际上是如何工作的呢?本文从零开始推导它们。

(注意本文改编自我的书机器从零开始学习中的一章,网上免费提供)。

符号和词汇

在本文中,我们将使用以下约定。

  • v [ i ]为向量 v 中的第 i 个条目。
  • 目标是我们试图建模的变量。预测值是我们用来模拟目标的变量。
  • 目标是一个标量,记为 y. 预测值组合成一个矢量,记为 x 。我们还假设 x 中的第一个条目是 1,对应截距项。
  • P(x)指的是xP(y = k)*指的是 y 等于 k 的概率*

1.生成分类

大多数分类算法分为两类:判别分类器和生成分类器。判别分类器将目标变量 y 建模为预测变量 x 的直接函数。例如,逻辑回归使用以下模型,其中是系数的长度-D 向量,而 x 是预测值的长度-D 向量:**

逻辑回归模型

相反,生成分类器将预测器视为根据其类别生成的——即,它们将 x 视为 y 的函数,而不是相反。然后他们使用贝叶斯法则从P(x| y = k)P(y = k |x),如下所述。

创成式模型可以分为以下三个步骤。假设我们有一个分类任务,有 K 个无序类,用 k = 1,2,…,K. 表示

  1. 估计目标属于任何给定类别的先验概率。即对于 k = 1,2,…,K. 估计 P(y = k)
  2. 在属于每个类别的目标上估计预测值条件的密度。即估计p(x| y = k)k = 1,2,…,K.
  3. 计算目标属于任何给定类别的后验概率。即通过贝叶斯法则计算出P(y = k |x)P(x| y = k)P(y = k)

然后,我们将一个观察结果分类为属于类别 k ,对于该类别,下面的表达式是最大的:

注意,我们不需要p(x),它将是贝叶斯规则公式中的分母,因为它在所有类中都是相等的。

2.模型结构

生成分类器模拟两种来源的随机性。首先,我们假设在𝐾可能的类之外,每个观察独立地属于𝑘类,其概率由向量中的第 k 个条目给出。𝝅【k】给出 P(y = k)。**

第二,我们假设的一些分布以 y. 为条件。我们通常假设x 来自于相同的分布,而不管 y,如何,尽管它的参数取决于类。例如,我们可以假设**

虽然我们不会假设 x 如果 y = 1 是分布 MVN 而是分布多元- t 否则注意,然而,向量 x 中的各个变量可能遵循不同的分布。例如,我们可以假设中的 i th 和 j th 变量分布如下

然后,机器学习任务是估计这些分布的参数——目标变量 y𝝅 以及索引x| y = k(在上述第一种情况下,_ k𝚺**) K. 一旦完成,我们就可以为每个类计算 P(y = k)P(x| y = k)。 然后通过贝叶斯法则,选择使 P 最大化的类k(y = k |x*)。***********

3.参数估计

现在让我们开始估计模型的参数。回想一下,我们计算P(y = k |x)

为了计算这个概率,我们需要首先估计(这告诉我们 P(y = k) )然后再估计分布p(x| y = k)中的参数。这些被称为类别先验和数据似然性。**

注意:由于我们将讨论跨观测值的数据,所以让 y_nx**_ n分别作为第 n 次观测值的目标和预测值。(下面的数学在原中稍微整齐一点。)**

3.1 类别优先级

让我们从推导的估计开始,类别先验。设 I_nk 为指示器,如果 y_n = k 则等于 1,否则等于 0。我们希望在给定数据的情况下找到一个表达式来表示 𝝅 的可能性。我们可以将第一次观察具有目标值的概率写为如下:

这相当于 𝝅 给定单个目标变量的可能性。要找出所有变量的可能性,我们只需使用乘积:

这给了我们类先验概率。为了估计 𝝅 通过的最大似然,我们先取对数。这给了

其中类别 k 中的观测值数量由下式给出

现在我们准备通过优化对数似然来寻找 𝝅 的 MLE。为此,我们需要使用拉格朗日函数,因为我们有一个约束条件,即中的条目之和必须等于 1。这个优化问题的拉格朗日函数如下:

拉格朗日最优化。第一个表达式表示对数似然,第二个表示约束。

更多关于拉格朗日的内容可以在原著中找到。接下来,我们对𝜆和中的每一项进行拉格朗日导数:**

这个方程组给出了下面直观的解,即我们对 P(y = k) 的估计只是来自 k. 类的观察值的样本分数

3.2 数据可能性

下一步是对给定 yx 的条件分布进行建模,以便我们可以估计这个分布的参数。这当然取决于我们选择用来建模 x 的分布族。下面详细介绍三种常见的方法。

3.2.1 线性判别分析

在 LDA 中,我们假设下面的分布为 x

对于 k = 1,2,…,k。注意,每个类都有相同的协方差矩阵,但有唯一的均值向量。

让我们推导这种情况下的参数估计。首先,我们来求似然和对数似然。请注意,我们可以将所有观测值的联合似然性写成

因为

然后,我们插入多元正态 PDF(去掉乘法常数)并取对数:

最后,我们有我们的数据可能性。现在我们通过最大化这个表达式来估计参数。

让我们从𝚺.开始首先,简化对数似然,使相对于 𝚺 的梯度更加明显。

然后,我们求导。注意,这里使用了“数学笔记”中介绍的矩阵导数(2)和(3)

然后我们设置这个梯度等于 0,并求解 𝚺.

在哪里

半路上!现在来估计_ k(第 k 类的均值向量),让我们单独看一下每个类。设 C_k 是类 k. 中的一组观测值,只看涉及 𝝁 _k、的项,我们得到**

使用“数学笔记”中的等式(4)在这里,我们得到梯度为

最后,我们将这个梯度设置为 0,并找到我们对平均向量的估计:

其中最后一项给出了类别 k.x 的样本均值

3.2.2 二次判别分析(QDA)

QDA 看起来非常类似于 LDA,但是假设每个类都有自己的协方差矩阵。即,

对数似然在 LDA 中是相同的,除了我们把 𝚺𝚺 _k:

同样,让我们单独看看第 k 类的参数。类别 k 的对数似然由下式给出

我们可以取这个对数似然相对于【𝝁_ k的梯度,并将其设为 0,以求解我们对【𝝁_ k的估计。然而,我们也可以注意到,LDA 方法的这个估计是成立的,因为这个表达式不依赖于协方差项(这是我们唯一改变的)。因此,我们再次得到**

为了估计 𝚺 _k,我们取类 k. 的对数似然的梯度

然后我们将它设为 0,得到我们的估计值:

在哪里

3.2.3 朴素贝叶斯

朴素贝叶斯假设 x 内的随机变量是独立的取决于观察的类别。即如果 x 是 D 维的,

这使得计算p(x| y = k)变得非常容易——为了估计p(x【j】| y)除了 j th 之外,我们可以忽略 x 中的所有变量。

作为一个例子,假设 x 是二维的,我们使用下面的模型,其中为了简单起见,σ是已知的。

和以前一样,我们通过只查看每一类中的项来估计每一类中的参数。设 θ _k = (μ_k,σ_k,p_k) 包含类别 k 的相关参数类别 k 的可能性由下式给出:

其中,由于 x 中的条目之间的假设独立性,两者相等。代入法向密度和伯努利密度分别为 x_n1 和 *x_n2,,*我们得到**

那么我们可以采用如下的对数似然

最后,我们准备寻找我们的估计。对 p_k 求导,我们得到

这将给我们一个合理的结果

请注意,这只是 x_2 的平均值。同样的过程将给出 μ_kσ_k. 的典型结果

4.进行分类

不管我们对p(x| y = k)的建模选择如何,对新的观察值进行分类都很容易。考虑一个测试观察值×x**_ 0。对于 k = 1,2,…,K ,我们用贝叶斯法则计算**

其中𝑝̂给出了以 y_0 为条件的x_ 0的估计密度。然后,我们预测最大化上述表达式的任何值 k。

结论

LDA、QDA 和朴素贝叶斯等生成模型是最常用的分类方法。然而,他们的试衣过程的细节(尽管是艰苦的)经常被掩盖。这篇文章的目的是让这些细节清晰。

虽然为生成模型估计参数的低级细节可能相当复杂,但高级直觉相当简单。让我们用几个简单的步骤来回顾一下这种直觉。

  1. 估计观测值来自任何给定类别的先验概率 k. 在数学中,估计 p(y = k) 的每个值 k.
  2. 估计预测值的密度条件对观测值的分类。即估计 k. 的每个值的p(x| y = k)**
  3. 使用贝叶斯规则获得一个观察值来自任何给定其预测值的类的概率(达到一个比例常数):p(y = k |x)。**
  4. 选择哪个值 k 最大化第三步中的概率(称之为 k) 估计 y = k。**

就是这样!要想从头看到更多像这样的衍生,请查看我的免费在线书籍!我保证他们大部分数学都比较差。

语言的生成模型和社会缺陷

原文:https://towardsdatascience.com/generative-models-of-language-and-societal-shortcomings-5ac994fbf099?source=collection_archive---------45-----------------------

OpenAI 生成模型的简史及其误用对社会的潜在影响。

对缺点的理解并不完全取决于某项特定技术的缺点或缺陷,而是取决于这项技术如何改变世界,无论是好是坏。

2015 年,一家名为 OpenAI 的公司由埃隆·马斯克、山姆·奥特曼、彼得·泰尔等人创立并向公众亮相。创始人以及微软和印孚瑟斯、等大公司承诺总计 10 亿美元用于创建“非营利企业”。

最初,OpenAI 是作为一个非营利组织成立的,部分原因是当时对人工智能近年来的发展感到担忧。OpenAI 作为非营利组织的理由与这些担忧没有太大关系,而是根据一篇介绍性博客文章的以下内容:

“作为一个非营利组织,我们的目标是为每个人而不是股东创造价值。研究人员将被强烈鼓励发表他们的工作,无论是作为论文、博客帖子还是代码,我们的专利(如果有的话)将与世界共享。我们将与许多机构的其他人自由合作,并期望与公司合作研究和部署新技术。”

2017 年,斯蒂芬·霍金(Stephen Hawking)将人工智能的出现描述为很可能是“我们文明史上最糟糕的事件”,突显出整个社会对其发展缺乏监督。早在 2014 年,马斯克本人在麻省理工学院(MIT)发表演讲时就认为,人工智能的发展是人类“最大的生存威胁”。

先锋大厦,OpenAI 和 Neuralink 的办公室所在地。(HaeB / CC BY-SA

几年后,在 2018 年,OpenAI 公布了第一篇关于生成性预培训的论文,这就是后来被称为 GPT 的开端。

这篇论文由亚历克·拉德福德和其他三位 OpenAI 同事撰写,得出的结论是,语言的生成模型实际上可以获得“重要的世界知识”和“处理长期依赖的能力”。由此,该模型还将能够解决“诸如问题回答、语义相似性评估、蕴涵确定和文本分类”等任务。

GPT-2:

关于 GPT-2 的研究论文于 2019 年 2 月发布,但由于围绕滥用措施的潜在利用,特别是关于假新闻的构建和发展的原因,其全面功能的发布被扣留,这一主题将在下文详述。

Transformer 语言模型的工作方式是通过人类主动输入至少几个单词到一页,然后模型继续自动预测和生成接下来人工生成的几行应该是什么。

《卫报》进行了一项类似于的实验,以乔治·奥威尔的小说《1984》开头为特色。该行如下所示:

这是四月里一个晴朗寒冷的日子,时钟正敲 13 下

GPT-2 设法使用这一行,这一行只产生了以下生成的文本片段,按照卫报及其文章,怪异地遵循“模糊的未来主义语气和小说风格:

“我在车里,正要去西雅图找一份新工作。我加油,插钥匙,然后让它跑。我只是想象着今天会是什么样子。一百年后。2045 年,我是中国农村贫困地区一所学校的老师。我从中国历史和科学史开始。”

当然,如果第二次、第三次或第四次输入完全相同的文本,该模型不会重复。有趣的是,这个文本明显不同于其他人工智能生成模型,尤其是在理解领域。

弗兰基·查马基在 Unsplash 上的照片

OpenAI 现任研究副总裁 Dario Amodei 表示,与以前相比,使用的模型“大了 12 倍,数据集大了 15 倍,范围也大了很多。实质上,向 GPT-2 提供的大量数据是其卓越的质量和可理解性背后的主要原因。

如果你有兴趣亲自体验 GPT-2,亚当·金创建了一个网站,利用 GPT-2 的完整模型,并将其命名为与变形金刚对话。

GPT-3:

2020 年 5 月,GPT-3 在 GitHub 上发布,与 GPT-2 的开发相比,它的大小有了天文数字的增长。前身模型是利用完整版本中的 15 亿个参数构建的。相比之下,GPT-3 是用 1750 亿个参数建造的,增加了 115 倍。

虽然由于 GPT-3 数据集和模型规模的增加,该模型的性能水平(与自然语言处理相关)甚至比 GPT-2 更好,但 OpenAI 也公开表示该模型可能接近其绝对极限。

这篇论文详细介绍了 GPT-3 的成功、局限性、更广泛的影响以及更多的内容,有效地证实了简单地向一个模型扔更多的数据并不能在无限的轨道上产生更好的结果。

它还围绕滥用的可能性,特别是在创建更大的模型时:

“任何依赖生成文本的对社会有害的活动都可能被强大的语言模型所增强。示例包括错误信息、垃圾邮件、网络钓鱼、滥用法律和政府程序、欺诈性学术论文写作和社会工程借口。这些应用中的许多限制了人们写出足够高质量的文本。产生高质量文本生成的语言模型可以降低执行这些活动的现有障碍,并提高它们的效率。”

一个语言生成模型必须发展得越多,特别是与它所拥有的数据和信息的数量相关,它就越适用于一般用途的应用程序,包括但不限于它对恶意行为的使用。

假文本的产生和问题:

虽然 OpenAI 最初是一家非营利性企业,但该公司转向了盈利模式,或者用他们的话说,一种“利润上限模式,根据他们的博客和 TechCrunch 的说法,这种模式将允许他们“在超过某个点后削减投资回报。

围绕这一举动的基本原理不仅仅是获得更多的投资资本,而是植根于一种理解,即积累比他们已经拥有的更多的计算能力,“建造人工智能超级计算机”等等,将需要在未来几年内投资数十亿美元

安娜·阿尔尚蒂在 Unsplash 上的照片

向盈利模式的转变当然与保持透明度和问责制有关,但对于 OpenAI 生产和开发 GPT 等模型也存在其他问题。

如前所述,2019 年 2 月,OpenAI 拒绝发布 GPT-2 ,纯粹是因为其被用于恶意目的的可能性。像 GPT-2 这样的模型的出现导致学者和记者将生成的文本称为“ deepfakes for text ”,该公司花时间“讨论技术突破的后果”。

滥用的例子包括上述主题:

“错误信息、垃圾邮件、网络钓鱼、滥用法律和政府程序、欺诈性学术论文写作和社会工程借口”

该公司承认,这些领域需要产生“高质量文本”的能力,但这正是为什么所谓的“deepfakes for text”的发展令人担忧,特别是在新闻、学术研究和小说家等领域。

该技术的当前状态,至少就 OpenAI 的开发而言,还远远没有完全消除和消除基于人类的输入。这一事实,再加上处理预先确定的语言和文本的神经网络的发展很可能肯定有其局限性,并没有引起人们的警惕。

尽管如此,不应该低估对其增长的关注,特别是随着时间的推移技术不断发展。

除了这些改进之外,OpenAI 还从该技术“太危险而不能积极使用”的心态转变为根据 The Verge 发布“其第一个商业产品”。

该公司最终得出结论,鉴于目前的技术状态,对 GPT-2 的恶意使用的担忧是不必要的,但新的发展要大得多,甚至更准确,并且“现在是你的,但要付出代价”。

照片由安德鲁·尼尔Unsplash 上拍摄

受到人工创建文本的发展积极影响的领域的例子包括“微软新闻和 MSN 组织”,其中“数十名记者和编辑工作者”截至 2020 年 5 月已被解雇。根据 The Verge 的一篇文章,这是由于微软更大力度地依靠人工智能来挑选新闻和内容……在 MSN.com,在微软的 Edge 浏览器内,以及在该公司的各种微软新闻应用

随着技术的发展,现实世界的影响肯定存在,而且只会继续增长。如果没有与这种生成性文本模型的增加的生产相关的任何种类的监督,整个工作领域在未来都有被关闭的风险。

虽然具体日期当然还不能确定,但微软的举动是所有类型的新闻和内容创作可能不幸未来的开始的一部分。

LSTM 的生成诗

原文:https://towardsdatascience.com/generative-poetry-with-lstm-2ef7b63d35af?source=collection_archive---------49-----------------------

在我的 Metis 数据科学训练营的最后一个项目中,我使用 LSTM 模型构建了一个诗歌生成器。

照片由Á·阿尔瓦罗·塞拉诺Unsplash 上拍摄

这是我 Metis 数据科学训练营的最后一个项目。我做的前四个项目如下:

这一次,我的目标是通过将诗歌语料库输入长短期记忆(LSTM)神经网络来生成短诗。

TL;博士:

  • 检索到一个三行诗的语料库
  • 用两种方法训练了一个 LSTM 模型:清洗单词序列;原始单词序列与斯坦福的手套嵌入配对
  • 对干净的单词序列的训练产生了不太有意义的诗歌;手套嵌入训练产生了更好的结果,但是不一致
  • 下一步将是尝试附加种子附加特征不同的模型超参数,以及更大和/或改进的诗歌语料库

一.背景

对于我的顶点,我想找到一种方法将我在机器学习方面的新兴技能与我现有的对诗歌的兴趣(阅读和写作;顺便说一下,我在 Instagram 上收集的俳句可以在这里找到。

[## 我的 Instagram 账户中的一个俳句,搭配一张我拍的照片。

www.instagram.com/kunojilym](https://www.instagram.com/p/B16if6WHvZ8/?utm_source=ig_web_copy_link)

生成性诗歌似乎是一个很好的起点。然而,除了吸引我的兴趣之外,这样的模型还可以有实际应用:

  • 它可以作为进一步创作诗歌和创造性写作的动力
  • 如果诗歌可以基于主题/图像生成,这可以在各种领域中具有更广泛的应用,例如在广告和营销中。

二。数据集

在这个项目中,我使用了杰里米·尼曼为他自己的生成诗帖子收集的三行诗数据集;在他的例子中,他专注于创作俳句(因此限制为 3 行)。

[## 用深度学习生成俳句

使用神经网络生成俳句,同时强化 5–7–5 音节结构。

towardsdatascience.com](/generating-haiku-with-deep-learning-dbf5d18b4246)

该数据集又是由如下各种其他数据集组合而成的。

总共 31,410 首诗

三。模型

我使用 Keras 构建了一个 LSTM 神经网络模型,该模型接受 15 个令牌的序列,并输出下一个令牌(或者更准确地说,下一个令牌的概率)。模型结构如下图所示。

我的 LSTM 模型

使用这个模型,我尝试了如下两种方法,训练了 200 个 epoches:

a)用干净的单词进行单词标记化

使用这种方法,我首先通过小写字母和删除所有非字母数字字符来清理单词;我保留了停用词,因为它们在诗歌语境中可能有意义。

大写字母和标点符号也可以有诗意,虽然可以说没有那么多,所以我决定在这种方法中忽略它们。

然后我将每首诗处理成一系列 15 个记号的序列:

  • 一首诗的第一个序列是用 14 个空格填充的第一个单词。
  • 每个后续序列会将下一个单词推入序列,丢弃多余的令牌。例如,第二个序列是用 13 个空格填充的前两个单词。
  • 特殊记号用于行尾和诗尾。

所有诗歌的结果序列被连接起来。下图说明了这一过程。

令牌是为了说明的目的

b)利用手套嵌入的单词标记化

这种方法类似于第一种方法,有两个主要区别:

  • 每个序列现在都与斯坦福手套的 300 维嵌入配对;正是这个 15 x 300 的向量,而不是 15 个标记的序列,被输入到 LSTM 中。下面举例说明。

令牌是为了说明的目的

  • 单词标记未被清除;换句话说,所有的大写和标点符号都被保留。这是因为手套嵌入物能够容纳这种代币

四。结果呢

培训结果如下。

基于分类交叉熵损失,使用手套的第二种方法似乎产生更好的结果。但是真正的诗歌呢?

这是从第一个模型中挑选出来的:

从第一种方法中选择最佳结果

即使在“最好”的情况下,第一种方法产生的诗歌似乎也不太有意义。将其与第二种方法中的选择进行比较:

从第二种方法中选择最佳结果

这些结果更加连贯,甚至富有诗意。

然后,我组装了一个 Flask 应用程序,它调用第二个模型,并访问存储在 PostgreSQL 数据库中的嵌入内容来生成诗歌,如下面的视频所示。

“创作温度”与诗歌创作人在选择诗歌的下一个词时的“冒险”程度相关。温度为 0 意味着生成器每次都选择最“可能”的单词,而温度越高,生成器选择不太“可能”的单词的可能性越大。

动词 (verb 的缩写)观察

  • 使用手套嵌入的第二种方法似乎比使用干净标记的第一种方法更经常地产生听起来自然的诗歌。也就是说,如视频所示,甚至第二种方法也不是万无一失的,平均来说,它似乎在超过 50%的时间里都不会产生“像样的”诗歌。
  • GloVe 方法产生了一个大小超过 1 GB 的模型,相比之下,cleaned tokens 方法的大小仅为 81 MB。由于包含了 300 维的单词嵌入,T4 的特征数量增加了 300 倍,这并不奇怪。可以尝试更少的嵌入(例如 100 维)来观察结果是如何受到影响的。
  • 两个模型都受到数据集词汇的限制。下一步可能是扩展这个词汇表,以包含斯坦福手套模型所包含的内容。

不及物动词后续步骤

除了上述观察结果,该项目在未来还有其他几个可能的方向:

  • 目前,该模型使用一个起始单词作为种子来生成诗歌的其余部分。我可以使用附加种子来提高相关性,例如情感、主题或图片。
  • 我还可以使用诗歌的附加特征来提高模型输出的质量,例如音节或词性。
  • 我可以调整我的 LSTM 模型的超参数,例如通过使用额外的层或节点,或者通过尝试不同的激活函数。
  • 最后,我可以将更多的诗歌添加到我的数据集中,和/或从数据集中移除低质量的诗歌。最后一点是非常主观的,因为不同的人对什么是一首好诗有不同的看法。

谢谢你坚持到最后。我的其他项目的链接如下:

** [## MTA 十字转门数据:我对数据科学项目的第一次体验

在 Metis 数据科学训练营的第一个项目中,我研究并分析了 MTA 十字转门 2 个月的数据。

towardsdatascience.com](/mta-turstile-data-my-first-taste-of-a-data-science-project-493b03f1708a) [## MyAnimeList 用户评分:网络抓取和线性回归的乐趣

在我在 Metis 数据科学训练营的第二个项目中,我使用线性回归模型来预测动画在…

towardsdatascience.com](/myanimelist-user-scores-fun-with-web-scraping-and-linear-regression-9dd97900a82b) [## 拖网渔船在捕鱼吗?模拟全球渔业观察数据集

在我在 Metis 数据科学训练营的第三个项目中,我根据以下特征来判断拖网渔船是否在捕鱼…

towardsdatascience.com](/is-a-trawler-fishing-modelling-the-global-fishing-watch-dataset-d1ffb3e7624a) [## 识别假新闻:骗子数据集及其局限性

在我的第四个 Metis 数据科学训练营项目中,我应用分类和 NLP 技术来确定一个片段是否…

towardsdatascience.com](/identifying-fake-news-the-liar-dataset-713eca8af6ac)

要关注我的数据科学之旅,您可以订阅我的博客或关注我的数据科学系列,链接如下。

[## 我的数据科学之旅

经过几年的涉猎,我的数据科学之旅真正开始于 Metis 数据科学训练营。总共…

medium.com](https://medium.com/series/my-data-science-journey-c99fa6378209)

下次再见了。**

生成性与鉴别性概率图形模型

原文:https://towardsdatascience.com/generative-vs-2528de43a836?source=collection_archive---------9-----------------------

朴素贝叶斯和逻辑回归的比较

作者照片

生成模型和判别模型是广泛使用的机器学习模型。例如,逻辑回归、支持向量机和条件随机场是流行的判别模型;朴素贝叶斯、贝叶斯网络和隐马尔可夫模型是常用的生成模型。

概率图形模型(PGM)是一个丰富的框架,用于编码复杂域上的概率分布,如大量相互作用的随机变量的联合分布。

在本文中,我们将以朴素贝叶斯和逻辑回归为例,将生成模型和判别模型的图形结构作为 PGM 进行探索。我们还将讨论这些模型的相似之处和不同之处。

模型结构

假设我们正在解决一个分类问题,根据邮件中的单词来决定一封邮件是否是垃圾邮件。我们有一个联名款的标签 Y=y ,特点是 X={x 1 ,x 2 ,…x n } 。模型的联合分布可以表示为 p(Y,X) = P(y,x 1 ,x 2 …x n ) 。我们的目标是估计垃圾邮件的概率: P(Y=1|X) 。生成模型和判别模型都可以解决这个问题,但方式不同。

让我们看看它们为什么以及如何不同!

为了得到条件概率 P(Y|X) ,生成模型从训练数据中估计先验 P(Y) 和似然 P(X|Y) ,并使用贝叶斯规则计算后验P(Y | X)

另一方面,判别模型直接假定 P(Y|X) 的函数形式,并且直接从训练数据估计 P(Y|X) 的参数。

上图显示了生成模型和判别模型的结构差异。圆圈代表变量,线的方向表示我们可以推断的概率。在我们的垃圾邮件分类问题中,给定 X:电子邮件中的单词,Y 是未知的。我们看到判别模型图(右)中的箭头从 X 指向 Y,这表明我们可以直接从给定的 X 推断出 P(Y|X) ,然而,生成模型图(左)中的箭头指向相反的方向,这意味着我们需要首先从数据中推断出 P(Y)P(X|Y) 的值,并使用它们来计算 P(Y|X)

数学推导

上图显示了扩展特征 X 时这两个模型的潜在概率分布。我们可以看到,每个特征 x i 依赖于前面所有的特征:{x 1 ,x 2 …x( i-1) }。这不会影响判别模型,因为它们只是将 X 视为给定的事实,并且它们需要估计的只是 P(Y|X ),但是这使得生成模型中的计算变得困难。

  1. 生成模型(朴素贝叶斯)

后验概率可以写成:

我们看到所有 X 的依赖性使得很难推断 P(X|Y ),因为我们需要将 x i 的概率限制在 Y 和{x 1 ,x 2 …x( i-1) }上。为了简化问题,我们假设所有的 X 是条件独立的:

有了这个假设,现在我们可以将后验分布改写为:

创成式模型的图形结构也发生了变化:

2。判别模型(逻辑回归)

如前所述,我们可以利用训练数据直接估计判别模型的后验概率:

在逻辑回归中,我们将后验概率参数化为:

最大似然估计用于估计参数。

比较

1.准确(性)

当不满足条件独立性的假设时,生成模型不如判别模型精确。比如在我们的垃圾邮件分类问题中,让 x 1 =邮件数据中“银行”出现的次数,邮件数据中 x 2 =邮件中“账户”出现的次数。不管是否垃圾,这两个词总是一起出现,即 x 1 = x 2。在朴素贝叶斯中学习得到p(x1| y)= p(x2 | y),对证据进行双重计数。逻辑回归没有这个问题,因为它可以设置α1=0 或α2=0。

2.缺失数据

生成模型可以处理缺失数据,而判别模型通常不能。在生成模型中,我们仍然可以通过忽略看不见的变量来估计后验概率:

然而,判别模型通常需要观察所有的特征 X。

3.表演

与判别模型相比,生成模型需要较少的数据来训练。这是因为生成模型在做出更强的假设(条件独立性假设)时更有偏见。

4.应用

判别模型之所以“判别”,是因为它有用但只对判别 Y 的标签有用,所以只能解决分类问题。除了分类之外,生成模型还有更多应用,例如抽样、贝叶斯学习、映射推理。

结论

生成模型和判别模型都是我们用来解决机器学习问题的非常有用的模型。使用哪种模型取决于用例及数据。一般来说,当我们对数据的基本分布有一个概念并希望找到该分布的隐藏参数时,通常使用生成模型,而当我们只想找到将数据分成不同类的边界时,判别模型更适合。

机器学习中的生成分类器与鉴别分类器

原文:https://towardsdatascience.com/generative-vs-discriminative-classifiers-in-machine-learning-9ee265be859e?source=collection_archive---------14-----------------------

它们的不同之处以及它们如何执行分类任务

莎伦·麦卡琴在 Unsplash 上的照片

分类是机器学习中的一项普遍任务。流失预测、垃圾邮件检测、图像分类只是一些常见的例子。

有许多不同的算法可以执行分类任务。这些算法可以分为两大类,生成型和鉴别型。

在这篇文章中,我将试着解释生成性和区别性分类器之间的区别,以及它们是如何分类的。

生成分类器

考虑这样一种情况,我们有一个特征 x 和一个目标变量 y,我们试图根据 x 的值来预测 y。

生成分类器学习联合概率分布 P(x,y)。重点是特性和目标变量如何一起出现。目标是能够解释数据是如何生成的。

一旦模型捕获了生成数据的过程,它就可以对新的示例(即数据点)进行预测。因此,生成分类器的关键因素是能够学习底层数据分布。

为了进行预测,生成分类器通过使用贝叶斯规则将联合概率(P(x,y))转换为条件概率(P(y|x))。如果你不熟悉这个符号,P(y|x)表示给定 x 值时 y 的概率。

朴素贝叶斯分类器和隐马尔可夫模型是生成分类器的例子。

假设我们有一些属于蓝色或橙色类的点。这些点绘制在下图中。图中还显示了基于 x 和 y(训练数据)的已知值的联合概率分布。

(图片由作者提供)

基于联合概率分布来决定新数据点的标签。例如,上图中的绿点标记为橙色。

由于创成式模型了解数据分布,因此它们也可用于生成新数据。

区别性分类器

鉴别分类器试图找到分隔类别的边界。检查所有可能的边界阈值,并选择误差最小的阈值。

这些边界可以是硬的或软的,这取决于算法。软边界意味着允许一些例子被错误分类。例如,软间隔支持向量机(SVM),顾名思义,创建一个软边界。

逻辑回归、SVM 和基于树的分类器(例如决策树)是区别分类器的例子。

判别模型直接学习条件概率分布 P(y|x)。回想一下,生成模型学习联合概率 P(x,y ),然后通过使用贝叶斯规则将其转换为 P(y|x)。

考虑下面的例子。数据点属于类别 0 或类别 1。逻辑回归模型绘制了一个边界,该边界指示数据点属于类 1 的概率(即 P(y=1 | x))。

(图片由作者提供)

极端值

生成模型对异常值更敏感,因为异常值有可能极大地影响分布。

在判别模型的情况下,异常值只是一个错误分类的例子。

考虑以下情况,在橙色类中有 2 个异常值。

(图片由作者提供)

由于这些异常值,橙色分布主导了一系列更有可能属于蓝色类的值。

我们不知道可能存在多少异常值,也不知道这些值有多极端。因此,在存在异常值的情况下,判别方法更适合。

结论

生成模型和判别模型都有优点和缺点。否则,我们就不会谈论这两个问题。

例如,生成型模型更需要数据。他们需要足够的数据来准确地表示分布。生成模型在计算上也比判别模型更昂贵。

判别模型对异常值更稳健,而异常值可能对数据分布有很大影响,从而对生成模型的准确性产生负面影响。

生成模型和判别模型在机器学习中都非常有用。最佳选择取决于任务和数据的特征。

感谢您的阅读。如果您有任何反馈,请告诉我。

遗传算法:简单直观的指南

原文:https://towardsdatascience.com/genetic-algorithm-a-simple-and-intuitive-guide-51c04cc1f9ed?source=collection_archive---------28-----------------------

了解什么是元试探法,以及为什么我们有时使用它们而不是传统的优化算法。通过一个简单的分步指南,学习元启发式遗传算法(GA)及其工作原理。

(图片由 Freepik 提供)

无论你是数据科学家、数据分析师还是机器学习工程师,运筹学和优化都应该是你工具箱的一部分。在深入研究遗传算法(GA)之前,我将解释什么是元启发式算法,以及为什么我们有时使用它们而不是传统的优化算法。之后,我将介绍元启发式算法 GA,并解释其工作原理及其背后的直觉。

什么是元启发式算法?

元启发式算法是强大的优化算法,不依赖于问题 —这意味着它们的框架不是专门为某个问题设计的,但你可以用它们来解决几乎任何优化问题(不像启发式算法通常适用于手边的问题)。

许多元启发法是受自然启发的。例如,模拟退火算法的灵感来自加热然后慢慢冷却金属或玻璃的过程。另一个例子是蚁群优化,它模仿蚂蚁在前往食物源并通过信息素相互交流时的行为方式。

为什么我们使用元启发式算法而不是传统的优化算法?

传统的优化算法,如贪婪算法、分支定界算法和 Dantzig 的单纯形算法等等,都有缺点。以下是我们倾向于使用元启发式算法而不是传统优化算法的几个重要原因:

#1-速度和问题大小:

简答:比传统算法更快,可以处理更大的问题。

为了解释这一点,让我们以旅行商问题(TSP) 为例。TSP 是一个广泛使用的优化问题,它表明有一个销售人员必须旅行到 n 个城市,每个城市只经过一次,然后返回他们出发的城市。给出的问题是,他们应该走哪条路线(从哪个城市到哪个城市)来最小化旅行的距离?

图 1: 一个有 6 个城市的 TSP(图片由作者提供)

假设您想要解决某个包含 6 个城市的 TSP,距离在左边的图像中给出(图 1)。可以看出,城市 A 和城市 B 之间的距离是 4 个单位的距离。

在这里,你需要找到推销员应该采取的最佳路线,以尽量减少旅行的距离。在这种情况下,最佳路线是,如果他们从 D 到 C 到 A 到 B 到 E,然后回到 D(因为你回到了出发城市),这个距离将是 41 个单位(7+11+4+6+13=41),而如果销售人员采取最差的路线,在这种情况下,它将是 E 到 A 到 D 到 B 到 C,然后回到 E,总距离将是 53 个单位,比最佳的 41 个单位要长。请记住,从 D 到 C 到 A 到 B 到 E,然后回到 D 与从 A 到 B 到 E 到 D 到 C,然后回到 A 是一样的,因为单个路由是一个闭环;你可以从环中的任何一点开始,以同一点结束,移动的距离是相同的。

对于 n 个城市,可能的路线组合数量将是 ((n-1)!)/2 。它是 (n-1) ,因为你从哪个城市开始并不重要,只有当城市之间的距离对称时(即城市 A 和城市 B 之间的距离等于城市 B 和城市 A 之间的距离),它才被除以 2。在不对称的情况下,可能的组合数量是 (n-1)!。在我们的 6 个城市的例子中,所有的距离都是对称的,组合的总数是((6–1)!)/2 有 60 种可能的组合。

现在想象一个场景,你有 25 个城市,而不是只有 6 个,在这种情况下组合的总数将是((25–1)!)/2 总共有 3.10224210 条可能的路径。客观地说,如果你有一台每秒能分析 10,000,000 个组合的计算机,你的计算机需要 3.10224210 ⁶秒才能找到所有的组合,也就是 983,041,000 年左右!

元启发式算法寻找从一个解决方案到一个更好的解决方案的方法,而不考虑那里的每一个组合;它会选择比现有解决方案更好的解决方案,并根据一些规则对其进行更新(第 2 点和第 3 点应该能更好地解释这一点)。

#2-局部最小值和全局最小值:

简而言之:它可以避免陷入局部最小值并逃离它,因为它使用随机性(或随机数)来接受更差的移动(对于最小化问题,更大的 f(x) ),因为它们可能导致更好的答案(即更好的局部最小值或全局最小值)。

当你处理一个最优化问题时,你总是试图最小化一个目标函数,比如总行程,或者最大化一个目标函数,比如利润。

图 2:f(x)的搜索空间中的局部极小值(x1)和全局极小值(x2)(图片由another bookon data science提供)

对于最小化问题,你会经常听到术语局部最小值全局最小值(最大化问题的局部最优和全局最优)。让我们看看左边的图 2,其中 x1 是局部最小值,而 x2 是全局最小值。让我们假设我们有一个函数 f(x) ,如果你输入 x1 ,我们将得到 f(x)=10 ,如果我们输入 x2 ,我们将得到 f(x)=6 ,显然 x2 是比 x1 更好的输入,因为 6 低于 10,10 比更好无论函数 f(x) 是什么,它只是问:要得到可能的最低值 f(x)x 应该是什么?

图 3: 我们当前的 x 值是 2(图片由作者编辑)

假设你从 x1 左边的一个点开始,这里 x=2 (图 3),你想用一个贪婪算法来最小化你的 f(x) 函数。贪婪算法倾向于只更新 x 如果它给你一个更好的答案,在我们的例子中,一个更低的 f(x)。现在我们试一下 x=2.1f(x=2.1)f(x=2)所以我们新的 x 会变成 2.1。仍然有改进的空间,所以我们继续这样做,直到我们到达 x1 这里 f(x=3)

图 4:a——我们当前 x 的值是 3。如果我们将 x 增加到 3.1,b- f(x)会变得更差(更大)。c- x2 是比 x1 更好的选择,因为 f(x=x2)比 f(x=x1)小(图片由作者编辑)

然而,如果我们想要将 x 增加到 3.1,您可以看到它给出了更高的 f(x) ,如图 5 所示。因此,贪婪算法的最佳 x 将是当 x 等于 3 时(在 x1 )。

通过查看图像(图 4),可以清楚地看到 x2 甚至是比 x1 更好的选择,以降低 f(x) 但是在处理实际问题时,搜索空间是未知的,您需要为 x 尝试许多许多值,以便能够绘制如图所示的搜索空间。尽管如此,由于 x 的值有无限多种可能性,找到能够产生最佳结果的 x 的值有时是不可能的。然而,如果我们有 x 的上界和下界,找到全局最小值(最佳解)是可能的。

回到我们为什么使用元试探法,使用贪婪算法,当我们的 x 变成值为 3 的 x1 时,任何其他更新都会给出更差的 f(x) ,因此找到的最佳解决方案将是 f(x=3) 并且算法将终止。使用元启发式算法,我们有时会接受更差的移动(在图像的情况下,当 x=3.1 )。我们接受更糟糕的举措的原因是,它们有可能让我们找到更好的解决方案,比如 x=x2 。如果我们继续朝着山顶更新 x ,我们将能够向下返回并找到 x2 其中 f(x2) < f(x1)

图 5: 具有两个输入变量的搜索空间(图片由 mathworks 提供)

注意:如果我们要计算一个问题的所有可能的解决方案,我们不会在意陷入局部最小值,因为我们可以从所有组合中选择最佳答案,这将为我们提供全局最小值,然而,正如前面所讨论的,随着问题变得越来越大,计算所有可能的解决方案所需的时间也越来越长。

如果你回头看一下图 2-4,你只会看到一个变量( x ),我们试图找到它的最佳值,使我们得到最低的 f(x) 。但是,在现实生活的问题中,你会有数量多得多的变量需要优化(找到每个变量的最佳值)。在图 5 中,我们有 2 个变量需要优化( xy ),其中 f(x) 将在 z 轴上。这个案子,还有上一个,只要看看剧情就能轻松解决。然而,当你有两个以上的变量时,就不可能通过查看图表来绘制和求解,因为你不能绘制超过 3 个维度。

#3-邻域搜索和基于人口的搜索:

简答:特别是在处理一个基于群体的搜索方法时,你会在你的搜索空间里一下子有很多解。这意味着您将能够评估许多点或解决方案,而不是只拥有一个解决方案并更新它。

图 6: 收敛到局部最优的邻域搜索算法(图片由 CMU 提供)

有了元试探法,你的算法要么是邻域(或局部)搜索算法,要么是基于种群的算法。如果你的算法是邻域搜索,这意味着你在整个搜索过程中有一个点或解,你在算法运行时更新这个解。由于它是一个元启发式算法,如果它陷入局部极小值,这个解决方案能够逃脱,这种情况会继续下去,直到算法终止,您收敛到一个最终的解决方案,如图 6 所示。当你的算法接近搜索结束时,接受更差走法的概率变小了,这是因为你的算法需要收敛到更好的解。邻域搜索算法的例子是模拟退火和禁忌搜索。

图 7: 基于群体的搜索算法中的解决方案(图片由作者编辑)

对于基于群体的搜索算法,您可以在搜索空间中同时拥有多个解决方案,就像它们的“群体”(图 7),其中随着算法的每次迭代,一定数量的解决方案会更新并成为新的解决方案。每种基于群体的搜索算法在如何选择要更新的解决方案以及如何进行更新方面都有自己的规则。基于群体的搜索算法往往非常强大,因为你可以探索搜索空间中的各个点,而不是一个点,最后,当你的算法终止时,你可以从它收敛到的最后一次更新中选择最佳解决方案,或者,跟踪所有更新并从中选择最佳解决方案。基于群体的搜索算法的例子有 GA(稍后将讨论)、进化策略、粒子群优化和蚁群优化。

在深入 GA 之前先总结一下…

虽然传统算法能够很好地处理小问题,但是当问题很大时我们倾向于使用元启发式算法,因此需要更多的时间。元启发式算法能够避免陷入局部极小值。虽然在处理一个非常大的问题时,例如无界问题,其中每个决策变量可以取任何实数,您的搜索空间将无限大,因此,您可能无法找到全局最小值,即使使用元启发式算法,但您将找到一个足够好的局部最小值。最后,基于群体的搜索算法具有在搜索空间中搜索各种点的巨大优势,这增加了算法找到更好的局部最小值或全局最小值的机会。

那么,什么是遗传算法呢?

遗传算法是由霍兰德在 20 世纪 70 年代开发的一种基于群体的元启发式算法。遗传算法使用从自然中获得灵感的技术,更具体地说是进化,来寻找问题的最优或接近最优的解决方案。它应用进化概念,如繁殖和适者生存来解决问题。遗传算法属于进化算法的大类。

如果我尝试用几句话来解释遗传算法,我会说遗传算法是一种优化问题的方法,通过创建许多解决方案并以与进化概念相关的某些方式更新这些解决方案,以达到“足够好”的解决方案或可能的最佳解决方案。

连续问题中,您想要找到最优值的决策变量采用实数,GA 中的解决方案如图 8 所示。这被称为染色体(有时被称为字符串)。下面的每个方块被称为一个“基因”,而每个基因取的值被称为一个“等位基因”

图 8:GA 中一条染色体的例子(图片由作者提供)

在现实生活的问题中,大多数决策变量是受约束和有界的,因此它不会取无穷大的值(这不是一个实数)。例如,如果你有一个优化问题,想让某个公司的利润最大化(或成本最小化),它可能会问你我们能设定的最大劳动小时数是多少,通常是给定其他条件。你可能首先倾向于说,我们可以有无限的小时数,但由于这是不可行的,公司往往会设定一个每月的最大限制,例如,它可能会说每周的小时数不应超过 120,因此,小时数的下限( x )将是 0,上限将是 120 ( 0≤x≤120 )。

既然我们可以将决策变量 x 放在界限之间,那么就可以找到计算小时数的实数。

图 9: 每个基因及其对应的 2^i(图片由作者提供)

对于图 9 中的染色体,或任何其他编码为 0 和 1 的 GA 染色体(在连续问题的情况下),每个基因将用 2^i 表示(2 的 I 次方,其中 i 从 0 开始,在最右边,染色体中的基因越多,就增加 1,即 2⁰,2,2,2,…,2^i )。

为了解码这个染色体(将其转换为实数值),我们使用公式 1,其中通过将基因中每个值与其对应的 2^i 的乘积相加来计算比特* 2^i 的总和。查看图 9,从右边开始,这将等于(02⁰)+(12)+(0 * 2)+(0 * 2)+(02⁴)+(12⁵)+(02⁶)+(12⁷)+(12⁸),这将给出值 418。*

公式 1: 解码 g a 染色体

对于公式 1 的第二部分,精度,公式在下面的公式 2 中给出,其中 l 是染色体的长度,在我们的情况下是 9,因为我们有 9 个基因, b 是上限,我们有 120(在该示例中给出为允许的最大小时数),而 a 是下限,为 0。现在的精度将是(120–0)/(2⁹-1),等于 0.234833,因此解码染色体将是 4180.234833+0* ,即 98.16 小时——一个介于 0 和 120 之间的值。

公式二: GA 精度

重要提示:如果我们将 9 基因染色体中的所有基因替换为 1,我们应该得到允许的最大值 120,如上限所定义,如果我们将所有基因替换为 0,我们应该得到允许的最小值 0,如下限所定义。当我们都是 1 时,让我们试着解码染色体。我们乘以 2^i 的比特总和将是(12⁰)+(12)+(1 * 2)+(1 * 2)+(12⁴)+(12⁵)+(12⁶)+(12⁷)+(12⁸),看,没有零,这将给出我们总共 511。如果我们用精度 0.234833 乘以 511,并加上 a (为 0),我们将得到 120。注:你实际上会得到 119.99963,因为精度 0.234833 有更多的位数但我只取了小数点后的前 6 位,然而,如果你包括所有的位数,你应该得到正好 120。***

染色体表示(编码)称为“基因型”,而染色体的解码值称为“表现型”

注:染色体的长度( l )由用户设定。字符串越长,解码值就越准确,但这需要在计算时间上有所取舍。

如果我们有不止一个决策变量呢?

假设我们有一个最小化问题,我们需要为 xy 找到最佳值,这将给出最低的 f(x) 。你会如何表达?简单,我们会有一条染色体,其中一半基因代表 x ,另一半代表y。请记住,对于每一个 xy ,代表每一个开始的基因都有一个相应的 2⁰.值

参见图 10,其中绿色基因代表 x 而蓝色基因代表 y它们都占据相同的字符串,但是在对每个字符串进行解码以获得其相应的值时,它们应该被分别对待。你用和上面完全一样的方法解码。当你有两个以上的决策变量时,同样的原则也适用。

图 10: 具有两个决策变量(x 和 y)的染色体(图片由作者提供)

在深入了解 GA 之前,您需要了解的术语:

除了上述术语,如染色体、基因、等位基因、基因型和表型,我在这里解释一些其他的术语,它们的解释可能会相互交织:

1-种群:我们说的种群,是指某一代的一组解( gen )。请记住,GA 是一种基于群体的搜索算法,这意味着在每一次(gen)中,我们在搜索空间中都有几个解决方案。所有这些都有可能更新并成为新的解决方案。在 GA 中,群体大小在整个搜索过程中保持不变,因此如果您的群体大小为 100,您将在每个 gen 中有 100 个解决方案,每个都是可以解码为某个值的染色体或字符串。

图 11: 人口规模为 10,向读者显示前 4 个(图片由作者提供)

图 11 显示了一个群体大小为 10 的例子(群体大小通常比 10 大得多,但是为了便于说明,我使用了 10),每个群体的染色体大小为 8。所有 10 条染色体都填充了 0 和 1(我只显示了填充的前 4 条,也是为了说明的目的,但它们都将填充 0 和 1)。

重要提示:您想要开始算法的初始群体是随机选择的。你最初设置染色体的长度和你想要在群体中有多少条染色体(群体大小),随机填入 0 和 1,你的第一代就是这种情况。下一代的种群是操纵和更新上一代种群的结果,,即创建一个 gen #1 的随机种群,产生的后代成为 gen #2 的种群,然后他们的后代成为 gen #3 的种群,以此类推。

2 代:您的算法在终止前将运行代。每一代都有相同的人口规模,但有不同的解决方案(有些可能与上一代相同)。在进入下一代(例如从 gen #1gen #2 )之前,您需要使用交叉和变异算子更新您的当前种群,以在搜索空间中创建新的解决方案(后代)。当你得到一组等于种群大小的新解后,你就可以进入下一代,重新开始使用新解作为你的种群。

3-父母和后代:在每一代中,你们当前的人口都是潜在的父母,有一些机会“交配”并产生“后代”,即有机会成为父母。这些后代是一组新的解决方案,将继续成为下一代的群体,然后他们的后代将成为下一代的群体,以此类推。把它想象成我们在现实生活中是如何产生后代的。

我们如何更新人口和创造后代?

GA 的灵感来源于进化和适者生存,意思是为了产生后代, 2 条染色体或“父母”会繁殖创造 2 个后代或“孩子”。

父选择:

因为我们在寻找解决问题的好的或最好的解决方案,我们需要尝试让我们的新的和更新的解决方案来自好的解决方案。

将有一个父代选择方法,我们将应用于群体以找到 2 个好的解决方案,这将是 2 个父代,并对所选的父代应用称为交叉的算子以产生子代。那么,我们如何才能确保选择 2 个好的解决方案来做父母呢?

首先,你需要知道仅仅因为一个解决方案(染色体)与群体中的其他部分相比不好,并不意味着它不会作为父代被选中,这仅仅意味着它被选中的机会更低。有许多父母选择方法发展,但两个广泛使用的是锦标赛选择和轮盘赌选择。

1-锦标赛选择:想法很简单,你从群体中随机选择 k 个解决方案(有或没有替换),其中你设置值 k ,并挑选最好的一个作为父#1,然后通过挑选另一个 k 解决方案并选择最好的一个作为父#2 来重复。简单吧?但是你怎么知道哪个是最好的呢?你通过比较它们对应的目标函数值就知道了至于说哪个染色体是你的 f(x) 的最佳选择。

举例:我们以布斯函数 f(x,y)=(x+2y-7) +(2x+y-5) 为一个最小化问题,其中 xy 均以 -10≤x,y≤10 为界,其中-10 和 10 为下界( a )和上界我们想知道xxy 的值是多少,这将使我们得到最低的 f(x)

图 12: 使用锦标赛选择方法的父母#1 选择(图片由作者提供)

现在我们要选择父母来产生后代,我们设置 k=3 。我们从我们拥有的群体中随机选择 3 条染色体,然后我们将每条染色体解码成实际值 xy 。从随机选取的第一条染色体开始,例如,如果解码后的 x 为 2.1,解码后的 y 为 3.6,我们将这些值代入 f(x) 得到f(x)=(2.1+2 * 3.6-7)+(2 * 2.1+3.6–5),等于 13.13。然后我们尝试另一条被选中的染色体,通过同样的过程发现,例如,它的 f(x) 是 8.32,那么我们选中的最后一条染色体和它的 f(x) 是 16.84。由于这是一个最小化问题,我们需要最低的 f(x) 作为更好的解决方案,因此,给我们 8.32 的染色体优于给我们 13.13 和 16.84 的另外两条染色体,所以这将是父代#1 ,这在图 12 中示出。为了找到父母#2,我们重复同样的事情。【f(x)】对于任何一条染色体都称为适应度,适应值,或目标函数值。

因此,使用以下步骤应用锦标赛选择方法:

  • 随机选择 k 个方案
  • 为每个 k 染色体找到 f(x)
  • 选择给出最佳 f(x) 的染色体,如果有多个解并列最佳,选择任意一个
  • 设置为父#1
  • 重复查找父#2

2-轮盘赌轮选择:染色体的适应度(【f(x)】)用于关联概率以选择亲本。对于最大化问题,f(x) 越高,被选中的概率就越高。如图 13 所示,我们需要从群体中选择 5 个解决方案。概率基于解决方案与其他解决方案相比有多好,概率越高,被选中的机会就越大,这就是适者生存理论,但仍然会给更差的解决方案一些被选中的机会。

图 13: 轮盘赌轮盘选择方法(图片由 NCL 提供)

图 14: 概率的累积和(图片由作者提供)

为了得到每个解的概率,你把所有的适应值( f(x) )加在一起得到总数,然后用每个 f(x) 除以总数得到它在总数中所占的百分比。然后,您选择一个介于 0 和 1 之间的随机数,并从概率集中选择解决方案作为父#1。如果 5 个解决方案基于它们的适合度得到概率 5%、12%、14%、31%和 38%,并且你的随机数出来是 0.89,那么它将在 0.62 和 1.00 的范围内,这将使我们选择染色体#3,它有 38%的概率被选中。如果我们的随机数是 0.16,那么我们会选择 4 号染色体,其概率为 12%。正如您在图 14 中看到的,范围是基于概率的累积和。

表 1:5 条染色体及其相应概率的示例(作者提供的表格)

另一个例子:如果我们有 5 条染色体,它们的适应值如下:#1: 3.12、#2: 5.18、#3: 6.46、#4: 4.23 和#5: 3.66,对于一个最大化问题,我们首先将它们相加得到它们的总和22.65。现在,我们将每个除以总数(即 3.12/22.65)得到百分比。我们将分别得到 0.13775、0.2287、0.28521、0.18675 和 0.16159,当你相加时,应该得到 1.00。之后,我们找到累积概率*,这允许我们创建一个范围,我们的随机数将从中进行选择。在表 1 中,如果我们得到一个介于 0 和 0.137748344 之间的随机数,那么染色体#1 被选为亲本的概率是,为了得到染色体#4,该随机数应该高于 0.651655629 并且低于 0.838410596。*

好吧,但是如果我们有一个最小化问题会发生什么呢?

最大化问题中,染色体的概率与其适应值相关,适应值越高越好,概率也越高。但是,如果我们有一个最小化问题,适应度越小越好,但我们需要将它与更高的概率相关联,如何实现?有许多方法可以做到这一点,我选择的一种方法是取每个适应度值的反相f(x) ,这样当你取最低数字的反相并与其他数字的反相比较时,它将是最高的。

例如,如果我们有一个最小化问题,3 条染色体的适应值是 2、4 和 6。我们希望 2(最低的 f(x) )得到最高的概率,6 得到最低的概率。所以,我们把它们反过来:2 会变成 1/2 (0.5),4 会变成 1/4 (0.25),6 会变成 1/6 (0.16667)。加上 0.5 到 0.25 到 0.16667,现在健身总数是 0.91667。因此,相关概率分别为 0.54545、0.27273 和 0.18182。可以看到 2,最低的 f(x) ,概率最高为 0.54545。

交叉:

现在我们有了 2 个父代,下一步是执行交叉操作并创建后代或子代。做交叉的方法有很多,这里我将解释两种常用的方法:

重要提示:我将使用字母而不是 0 和 1 来展示它是如何工作的,因为用 0 和 1 来解释可能会引起混淆。

#1-单点交叉:

图 15: 单点交叉示例(图片由作者提供)

当我们有 2 个双亲时,我们通过随机选择一个截止点来应用单点交叉。您可以通过选择一个随机整数来指定交叉发生的位置。例如,假设我们的随机整数是 6(这取决于您将使用什么编程语言,例如 Python,从 0 开始索引)。所以分界点之后的基因会在双亲之间交换。参见图 15,来自父#1 的[R,Z,P]将与来自父#2 的[A,F,W]互换,这将创建子代:子#1 和子#2。

#2-两点交叉:

图 16: 两点交叉示例(图片由作者提供)

这个想法和单点交叉是一样的,但是我们不是随机选择一个整数,而是选择两个整数并交换它们之间的值。在图 16 中,两点交叉使我们用[P,S,D]交换[T,B,L]来创建后代。您可以通过 if 或 while 语句使这两个随机整数彼此不同,也可以允许这两个整数偶然相同,但如果发生这种情况,它将成为单点交叉。这是基于用户的偏好。

注意:交叉算子可以基于概率来完成,因此您不会每次都执行交叉,但是,大多数研究倾向于应用概率 1 (100%),交叉确保算子将在每次选择父代后发生。

突变:

为了在搜索空间中产生多样性,以一定的概率(通常很低,例如 0.1 或 0.01)引入变异算子。在通过杂交两个父代来创建子代之后,对子代应用变异。

图 17: 突变实例(图片由作者提供)

这样做的方法很简单:你从第一个孩子开始,一个一个地检查每个基因。你从第一个基因开始,得到一个随机数,如果这个随机数小于突变的概率,你就突变,否则,移动到下一个基因,应用另一个随机数,以此类推。但是当我们变异时会发生什么呢?很简单,如果你想突变的基因的值是 0,它就会变成 1,如果基因的值是 1,它就会变成 0。请看图 17,红框表示哪些基因将被突变,绿框显示突变的结果。由于突变的概率很低,所以不会有很多(甚至零)基因会发生突变。

把所有的放在一起

下面的流程图,图 18,是我个人在使用锦标赛选择作为父选择方法时为 GA 开发的流程图。我发现网上几乎所有的流程图对初学者来说都有点难以理解。流程图中的符号如下: M 为世代数, N 为种群大小, p_c 为交叉概率, p_m 为变异概率, k 为锦标赛选择时随机选择的染色体数。

图 18: 带有锦标赛选择的 GA 流程图(图片由作者提供)

首先,我们选择世代数( M )、群体大小( N )、交叉概率( p_c )、突变概率( p_m )、锦标赛选择要选择的染色体数( k )。假设我们设置 M=100N=120p_c=1.00p_m=0.10k=3 。我们要解决的问题是一个连续最小化问题。

  1. 我们随机创建一个 120 条染色体的群体(每条染色体由 0 和 1 随机创建,长度由您选择( l )。此时此刻,我们在 gen #1
  2. 使用锦标赛选择选择 2 个父母的时间到了。我们从群体中随机选择 3 个解决方案,并找到具有最佳适应值(最低 f(x) ,因为我们正在处理最小化问题)的解决方案,这将是 parent #1 。然后,我们再次选择 3 个随机解决方案,并找到最佳方案,即 parent #2
  3. p_c 处,我们将两个父母杂交得到两个孩子。
  4. 下午,我们对 2 个孩子进行变异,得到 2 个变异的孩子。
  5. 我们将这两个变异的孩子存储在一个数组中。
  6. 步骤 2 到 5 N/2 次(60 次)——60 因为 120/2 是 60。我们需要为每一代后代重建一个 120* 的种群,以保持种群规模一致。因为每次我们产生 2 个孩子或者 2 个突变的孩子,我们需要执行步骤 2 到 5 60 次才能得到下一代的 120 个种群( 1202* )。将所有产生的变异子代存储在一个数组中。在这一点上,我们应该有 120 个种群,它们是 gen #1 的突变后代。*
  7. 我们转移到下一代, gen #2 ,重复步骤 2 到 6* 。产生的后代现在将成为第三代的种群。*
  8. 继续这样做,直到你完成所有的 100 代。
  9. 你有两个选择: 1) 要么从 gen #100 (收敛解:你的算法在终止前收敛到右边的解)中选择最佳解(变异的子染色体),要么, 2) 从每一代的变异子染色体中,在你进入下一代之前,将最佳的变异子染色体存储在一个单独的数组中。你对所有代都这样做,这样在你的算法结束时,你将有一个数组,它对每代都有最好的解,每代都有你的算法所见过的最好的 100 个解。然后从这 100 条染色体中选出最好的作为你的最终解决方案——我,我自己,选择选项#2,因为这样,你可以确保你有算法遇到的最好的答案*因为在数组中,如果你最终选择了算法收敛到的答案,解决方案#100 就是相同的解决方案,因为当你选择算法收敛到的答案(选项#1)时,你选择的是唯一的最好的 gen #100 ,它与数组#100 相同这样,你就能确保从所有 100 代人中选出最好的,而不仅仅是最后一代。因为很有可能你可能在更早的一代(例如 gen #42 )达到可能的最佳解决方案,但随后 GA 算法将开始进入搜索空间中比你在 gen #42 时更差的其他地方,并最终收敛到一个糟糕的解决方案。*
  10. 现在你有了最好的染色体,解码它得到真实的值,这样你就解决了问题!

恭喜你!您现在知道 GA 是什么以及它是如何工作的了!

摘要

遗传算法是一种强大的基于种群的搜索元启发式算法。它的灵感来自于进化论及其概念,如繁殖和适者生存。

在这个解释中,我介绍了遗传算法如何应用于连续优化问题,其中染色体用 0 和 1 表示(编码)。我们学习了如何将一条染色体解码成实际值如何选择父母进行交叉产生孩子,以及如何对他们进行变异关于如何执行遗传算法的流程图和逐步指南也已经过详细说明。

最后注意:交叉和变异的相同原理可以应用于组合问题,例如 TSP,其中您想要优化的不是采用实数的决策变量,而是离散元素,例如旅行者或车辆路线。虽然交叉和变异背后的思想对于组合问题来说是相同的,但是我们应用它们的方式略有不同,因为您不希望以像[A,D,B,D]这样的旅行者路径结束,其中城市 D 被提到两次,而城市 C 不包括在路径中,如果您在离散问题上使用连续的交叉或变异方法,这可能会发生。

2020 Dana Bani-Hani —未经许可和适当引用,不得使用由 Dana Bani-Hani 开发的文章、代码和图像。

参考

荷兰,约翰·亨利。自然和人工系统中的适应:生物学、控制和人工智能应用的介绍性分析。麻省理工学院出版社,1992 年。

Intro Image:https://www . free pik . com/free-photo/DNA-bacterias _ 923816 . htm # page = 3&query = DNA+genetics&position = 21

图二:https://www.anotherbookondatascience.com/chapter6.html

图 5:https://www . mathworks . com/matlabcentral/MLC-downloads/downloads/submissions/27178/versions/6/previews/html/gapeaksexample . html

图 6:https://www . cs . CMU . edu/AFS/cs/project/Jair/pub/volume 15/ambite 01 a-html/node 9 . html

http://www.edc.ncl.ac.uk/highlight/rhjanuary2007g02.php】图 13:

基于遗传算法的机器人控制器方法

原文:https://towardsdatascience.com/genetic-algorithm-based-approach-for-robotic-controllers-3966a9b874fb?source=collection_archive---------32-----------------------

用 Python 实现

埃里克·克鲁尔Unsplash 上拍摄的照片

今天,我们要解决的一个现实问题是设计一个机器人控制器。有许多技术可以用来解决这个问题。其中包括遗传算法、粒子群优化算法和神经网络。

我们需要做的是将一种算法应用于机器人,作为设计机器人控制器的方法,使机器人能够执行复杂的任务和行为。

自主机器人是指在没有人类帮助的情况下,能够独立完成一定工作的机器人。

机器人的能力之一是从一点移动到另一点,这称为自主导航。想象一下,我们建造了一个可以在仓库里移动货物的机器人。在本文中,我们将使用 Python 语言实现这一功能。机器人如何看到它的局部环境?是的,我们将安装传感器,这使机器人可以环顾四周,我们给了它轮子,所以它可以根据传感器的输入进行导航。最大的问题是我们如何将传感器数据与电机动作联系起来,以便机器人能够在仓库中导航。

一般来说,我们经常使用神经网络,通过在学习过程中使用强化学习算法,成功地将机器人传感器映射到输出。但是我们今天将使用另一种方法,那就是使用遗传算法。通常,遗传算法将通过使用适应度函数来评估大量个体,以找到下一代的最佳个体,该适应度函数基于某些预定义的规则来计算个体的表现。

然而,我们将面临一个新的挑战,对每个机器人控制器进行物理评估对于一个大群体来说是不可行的,因为对每个机器人控制器进行物理测试是困难的,而且这样做需要时间。为此,我们将使用我们的遗传算法知识来设计和实现机器人控制器,并将其应用于虚拟环境中的虚拟机器人。

目标

我们的机器人可以采取四种行动:向前一步,左转,右转,什么也不做。

下图中机器人也有六个传感器。

有 6 个传感器的机器人

  • 前面三个
  • 一个在左边
  • 一个在右边
  • 一个在后面

迷宫由机器人无法跨越的墙壁组成,并将有一条勾勒出的路线。我们将设计一个机器人控制器,它可以使用机器人传感器来成功地引导机器人通过迷宫。

解决方案

遗传算法伪代码

基本遗传算法的伪代码如下

generation = 0;
population[generation] = initializePopulation(populationSize); 
evaluatePopulation(population[generation]);
While isTerminationConditionMet() == false do 
    parents = selectParents(population[generation]); 
    population[generation+1] = crossover(parents); 
    population[generation+1] = mutate(population[generation+1]);
    evaluatePopulation(population[generation]);
    generation++;
End loop;

这个伪代码演示了一个遗传算法的基本过程。接下来,我们将用 Python 实现它们。

将传感器值映射到动作

如前所述,机器人有四个动作,可以用二进制表示如下:

  • “00”——什么都不做;
  • “01”——前进;
  • “10”——左转;
  • 还有“11”——右转。

我们还有六种不同的传感器。为了简化表示,我们将测量限制为二进制编码,也就是说,小于阈值的值表示检测到障碍物,大于阈值的值表示畅通无阻。6 个传感器为我们提供了 2⁶ = 64 种可能的传感器输入组合。由于一个动作需要 2 位,我们的控制器需要 64*2 = 128 位的存储来表示任何可能的输入。假设我们需要 128 位来表示不同组合指令。但是,我们应该如何组织染色体,以便对其进行编码和解码呢?

我们有一个人类可读的输入和输出列表,如下所示:

  • 传感器#1(前):开
  • 传感器#2(左前):关闭
  • 传感器#3(右前):开
  • 传感器#4(左侧):关闭
  • 传感器#5(右):关闭
  • 传感器#6(背面):关闭

我们还有一个二进制值为 10 的“左转”指令。下一步是获取六个传感器值并进一步编码。

000101 => 10

如果我们现在将传感器值的位串转换为十进制,我们会得到以下结果:

5 => 10

因此,我们可以使用传感器的十进制值作为染色体中的位置,表示传感器输入的组合,如下所示。

xx xx xx xx xx 10 xx xx xx xx (… 54 more pairs…)

从下图中可以看出,传感器值的组合产生了一个二进制输出,描述了典型的染色体如何将机器人的传感器值映射到动作。

这种编码方案初看起来可能很迟钝,染色体也不可读,但它有几个有用的特性。

  • 首先,染色体可以作为一组位来操作,这使得交叉、变异和其他操作更加容易。
  • 其次,每个 128 位的值都是有效的解。

履行

首先,我们需要在(world.py文件)中创建并初始化一个迷宫来运行机器人。我们创建的迷宫对象使用整数来表示不同的地形类型:

  • 1 定义了一面墙;
  • 2 是起始位置;
  • 3 描绘通过迷宫的最佳路线;
  • 4 是目标位置;
  • 0 是一个空位置,机器人可以走过,但不在通往目标的路线上。

我们编写了一个构造函数来从一个 double int 数组创建一个新的迷宫,并实现公共方法来获得起始位置,在迷宫中找到一条路线。

个人

一个个体由一条由多个基因组成的染色体代表。

机器人

接下来,我们需要创建一个能够遵循指令并通过执行这些指令来生成路线的机器人。

人口

群体是指一组染色体。

遗传算法

我们实现了计算适应度、选择个体、交叉和变异的方法。

机器人控制器

最后,我们可以编写一个实际执行算法的类。如下创建另一个名为main.py的新文件。

输出。

很简单,对吧?

参考

[1] 遗传算法简介

[2]https://github . com/house cricket/基于遗传算法的机器人控制器方法

优化机器学习超参数的遗传算法

原文:https://towardsdatascience.com/genetic-algorithm-to-optimize-machine-learning-hyperparameters-72bd6e2596fc?source=collection_archive---------11-----------------------

来自的照片

超参数调整对于机器学习模型的正确运行至关重要。您可以查看Timo bhm的文章,了解超参数调整的概述。

遗传算法为超参数调整提供了一种强大的技术,但它们经常被忽视。

在这篇文章中,我将展示遗传算法的概述。我还将提供一个详细的分步指南,介绍如何利用可用的库,使用遗传算法来优化机器学习模型的超参数。

遗传算法利用自然选择进化的基本概念来优化任意函数。

文章概述

这篇短文将介绍差分进化,并教授如何利用它来优化核岭回归中使用的超参数。

我提供了一些代码片段来展示如何在 Python 中使用差分进化算法。完整的代码和图表也在 GitHub 库中提供,因此任何人都可以深入了解细节。

差分进化算法概述

遗传算法,如差异进化,利用了自然选择进化的基本概念。在我们的例子中,我们有一个由包含具有不同值的参数向量构成的群体

参数相当于生物系统中的基因。它们的精确值在不同的向量之间是不同的。参数的不同组合导致向量显示不同的适应值。

随机参数突变被引入到群体中,并且具有较大适应度的向量比其他向量长寿。

作者图片

使用迭代过程,差分进化可以按照以下步骤最小化函数:

1 —初始化:用边界内随机参数值的 NP 个向量创建初始种群。

2 —初始评估:计算 NP 向量的函数值。

3 —对于群体中的每个载体:

3.1 —突变:我们构建了一个突变向量,其中每个参数的值被计算为从群体中随机选择的其他向量的参数的突变。计算该突变载体的常用策略是 best1bin ,其中突变载体的每个参数 pᵢ 如下式所示计算。突变参数是最佳载体(具有最低值的载体)的 pᵢ 参数加上突变率 (F) 乘以随机选择的两个载体【r₁】r₂差的变化。

3.2 —重组:通过选择其每个参数作为当前载体的值或突变载体的值来创建试验载体。对于每个参数,我们在(0,1)区间内生成一个随机均匀数 R 。如果 R 低于 a 重组率,那么我们接受突变参数;否则,我们使用当前参数的参数。

3.3 —替换:评估试验矢量的功能。如果它比当前向量更稳定,就用试验向量代替当前向量。

4 —重复步骤 3,直到群体收敛:当群体中函数的标准偏差小于函数平均值的特定百分比时,迭代停止。如果在最大迭代次数后没有达到收敛,循环也会停止。

所有这些过程都已经在主流编程语言的几个库中实现了。在这里,我们将使用 Python 中的 Scipy 的实现,它让我们只需使用几行代码就可以做任何我们想做的事情。

生成数据

例如,我们将使用遵循二维函数【f(x₁,x₂)=sin(x₁)+cos(x₂】的数据,加上区间(-2,2)中的一个小的随机变化来增加趣味。因此,我们的数据将遵循以下表达式:

在下图中,我们以灰度显示 sin(x₁)+cos(x₂) 的值作为参考。然后,我们用彩色点来表示我们的 441 个点(21 x 21 网格),在区间 x₁ 😦-10,10)和 x₂ 😦-10,10)中用上面的表达式计算。

作者图片

我们在下面提供了一个代码片段,其中包含用于生成数据的函数:

机器学习模型

我们的目标是使用之前生成的数据来训练一个 ML 模型,该模型将能够预测函数 f(x₁,x₂) 在不同配置下的值。

在本文中,我将使用核岭回归 (KRR)。我们将对 KRR 使用径向基函数核,它取决于高斯核方差 γ 。对于 KRR,我们还需要优化正则化超参数 α 。如果你想知道更多关于 KRR 及其实现的细节,请随意查看我最近关于这个主题的教程。

在这里,我们使用 10 重交叉验证,其中我们的数据分为用于优化模型的训练集和用于测量模型准确性的测试集。作为准确性度量,我们将使用均方根误差( RMSE ),它代表测试集中的 f(x₁,x₂) 值与我们的模型预测的值之间的平均误差。

上一步:探索超参数空间

作为可选的第一步,我们可以执行网格搜索,查看 RMSE 如何随两个超参数α和γ的值而变化。

我们在下面展示了这个网格的外观,以及用于执行超参数网格搜索的代码。下图让我们初步了解了什么样的超参数值会产生较小的 RMSE。

作者图片

超参数调谐

最后,我们可以使用 Scipy 提供的差分进化算法,通过最小化我们模型的 RMSE 来优化超参数。

Scipy 的差分进化函数需要输入:

  • KRR _ 功能 这是其输出(RMSE)将被最小化的功能。它需要输入:I)具有超参数的元组以优化(α和γ)和 ii) X,y 包含我们的数据的变量。
  • 定义超参数可能值的边界
  • KRR _ 函数使用的额外变量*。在我们的例子中,这将作为一个包含 Xy. 的元组给出*
  • 差分进化算法的其他相关选项有:
  1. 策略。在我们的例子中,默认的策略='best1bin'* 已经足够好了。采用这种策略,突变载体的每个参数值作为该参数的最佳载体值的变化而获得,与另外两个随机载体的差异成比例。*
  2. 人口规模。这就选择了我们要考虑的矢量数量。一个较大的数字将会减慢进度,但会使它更有可能发现全局最小值。这里,我们使用默认值 popsize=15。
  3. 突变常数。该值控制参数在突变阶段的变化程度。较大的值意味着较大的搜索半径,但会减慢收敛速度。我们使用突变的默认值=0.5。**
  4. 复合常数。该常数控制重组阶段试验载体的参数改变的可能性。更大的值意味着突变更容易被接受,这可能会加速收敛,但有导致群体不稳定的风险。我们使用默认值重组=0.7。**
  5. 公差。该值控制算法何时被视为收敛。我们将使用 tol=0.01 ,这意味着当群体中所有向量的 RMSE 的标准差小于平均 RMSE 的 1%时,该算法被认为是收敛的。

此代码返回导致最小化 RMSE 的收敛超参数值:

*Converged hyperparameters: alpha= 0.347294, gamma= 3.342522
Minimum rmse: 1.140462*

我们可以取消函数KRR _ 函数的最后一行的注释,以打印所有中间值:

*alpha: 63.925979 . gamma: 19.290688 . rmse: 1.411122
alpha: 59.527726 . gamma:  2.228886 . rmse: 1.421191
alpha: 24.470318 . gamma:  3.838062 . rmse: 1.379171
alpha: 61.944876 . gamma: 15.703799 . rmse: 1.407040
alpha: 68.141245 . gamma:  0.847900 . rmse: 1.431469
                        [...]
alpha:  0.347408 . gamma:  3.342461 . rmse: 1.140462
alpha:  0.347294 . gamma:  3.342522 . rmse: 1.140462
alpha:  0.347294 . gamma:  3.342522 . rmse: 1.140462
alpha:  0.347294 . gamma:  3.342522 . rmse: 1.140462*

我们可以采用差分进化算法探索这些配置,并在之前的超参数网格搜索的基础上绘制它们:

作者图片

除了研究的所有中间值,我们还用红色标出了收敛值。这样,我们可以观察算法如何在设定的边界内探索不同的配置,并最终收敛到最小化 RMSE 的(α,γ)组合。

结论

我们已经介绍了如何生成一个简单的二维数据集,以及如何用核岭回归来拟合它。我们已经介绍了差分进化的基础知识,以及如何使用这种算法来优化机器学习模型的超参数。

请记住这里展示的数据集、代码、图像等。在这个 GitHub 库中提供。

如果你对遗传算法优化机器学习超参数的更复杂的应用感到好奇,请随时查看我们最近在利物浦大学与东北师范大学合作的工作。在这项工作中,我们使用差分进化算法来优化几个机器学习模型,以预测有机太阳能电池的效率。

这篇文章对你有帮助吗?让我知道你是否能够成功地使用差分进化算法来优化你的机器学习模型的超参数!

使用 DEAP 库的 Python 中的遗传算法

原文:https://towardsdatascience.com/genetic-algorithms-in-python-using-the-deap-library-e67f7ce4024c?source=collection_archive---------12-----------------------

应用于大量营养素膳食计划的优化

在本文中,我将介绍 Python 中的遗传算法,以及一个优化膳食计划的例子。

示例以及如何应用优化

当优化膳食计划时,有许多事情要考虑。在这个例子中,我们将为一个人制定一个每周膳食计划,这个人已经决定了他们想要吃多少卡路里,以及这些卡路里中有多少百分比应该来自蛋白质、碳水化合物和脂肪。

除了这些固定值,优化程序还需要一个预定义的产品列表,用户可以从中进行选择。对于这些产品中的每一种,我们知道每单位的卡路里数,以及脂肪、蛋白质和碳水化合物的百分比。

我们示例中人员的目标数量是:

总热量= 2500 * 7 天= 17500 卡路里
蛋白质百分比= 30%
碳水化合物百分比= 50%
脂肪百分比= 20%

下面列出了可供选择的产品:

Python 中的遗传算法——产品表。作者配图。

优化的目标

优化程序的目标是找到一周的产品列表,其中每周总热量和宏量营养素尽可能接近目标量。

本文将使用 DEAP 的遗传算法。来源:https://deap.readthedocs.io/en/master/_images/deap_long.png

遗传算法优化

存在许多优化算法,遗传算法是其中之一。遗传算法之所以迷人,是因为其背后的思想非常耐人寻味:遗传算法是基于遗传学中自然选择的思想。

繁殖/交配

那么优化在遗传学中是如何工作的,比如在动物中?这是一个简单的原则:一个个体被编码为一系列基因。这种动物可能会也可能不会通过与伴侣繁殖将自己的基因组合传递给下一代。如果发生这种情况,后代将拥有来自母亲和父亲的基因组合。

变化

除了繁殖,还有第二个影响将决定新一代的基因库:突变。由于许多随机环境,有一些基因会在任何新个体中随机改变。

选择

达尔文的选择原则指出,适者生存。我们认为在繁殖前死亡的动物有不良基因。因为它们不繁殖,所以它们不会把基因传给下一代。这样下一代的基因会比上一代略好。

人口优化

这种自然选择的原理可以看作是一种优化算法。通过死亡,大自然把每一代人的坏基因都扔了出去。剩下的人口会越来越好。

将遗传算法应用于其他优化

对于优化的其他用例,遗传算法实现了相同的迭代交配、变异和选择方法。而不是用一个基因序列作为一个个体,它可以是许多其他的东西。

例如,在优化膳食计划的例子中,我们可以将“购物清单”写成个人。只买 1000 根香蕉而不买其他东西会是一个相对糟糕的购物清单。每样东西买 10 个已经很现实了。

因此,我们为这种遗传优化所做的如下:

  1. 生成大量随机购物清单
  2. 通过测量它们离目标数量的距离来选择最佳的。
  3. 然后,将这些顶级候选项混合在一起,以给出新的购物列表,这些列表是顶级父候选项的随机组合(应用了一些随机变异)
  4. 我们重复第 2 步和第 3 步,直到我们观察到几代人都没有改善(或者尽可能长)
  5. 然后,我们从最终群体中选择最佳个体,我们确信这是我们可能拥有的最佳购物清单之一。

Python 中的遗传算法

听起来很神奇,我们用 Python 做个实际案例吧。我们将使用 DEAP 图书馆,因为它有许多我们可以重复使用的基因功能。你可以跟着这里的总笔记本走。

在 Python 中设置输入

首先,让我们确定目标营养素的数量。我用不同的方式设定它们,因为实际上它们通常以每份营养素的百分比来表示,但为了优化,用克来表示更容易。

Python 中的遗传算法——目标数量。作者配图。

创建产品表的第二件事是:

Python 中的遗传算法——产品表。作者配图。

为我们的具体示例设置 Python 中的 DEAP 工具箱

设计 DEAP 工具箱设置

现在是更困难的部分,为我们的具体例子建立 DEAP 工具箱。你需要指定你的染色体的形状。最简单的形状是列表。

在本例中,我选择了长度为 21 的列表,因为在 products 表中有 21 个产品。然后我知道第一个元素是香蕉的数量,第二个元素是橘子的数量等等。

为 DEAP 工具箱设置的语法

我知道,但是算法不需要知道。它在个体中是不可见的。正如我们在下面看到的,这个个体是使用 creator.create 创建的,这里它被指定为 list,但是有一个附加的 fitness。这种适合度被定义为 FitnessMin。

个人现在还没有填写。填充发生在函数“个人”被注册到工具箱的地方。个体是基于函数 n_per_product 的,它返回 21 个随机数的列表:正如您所认识到的,这些是每个产品的数量。

人口只是登记为一份个人名单。

评估函数是我定义的,它计算总购物清单的卡路里数与目标卡路里数之间的绝对差值。就像你在笔记本上看到的,把其他的量加进去是相对容易的。

Python 中的遗传算法—建立 DEAP 工具箱。作者配图。

交配,变异和选择功能是直接从 DEAP 图书馆。

优化循环

下面的函数进行优化。几乎是从 DEAP 的例单中逐字抄来的。感谢我为这个例子选择的设置,只需要做很少的修改。

Python 中的遗传算法——主函数。作者配图。

遗传算法的结果

上一代的最佳个体是下面显示为“单变量 _ 选择”列的列表。

Python 中的遗传算法。作者配图。

Python 中的遗传算法。作者配图。

Python 中的遗传算法——解决方案。作者配图。

多元优化

目前,我们只优化了卡路里的数量,而没有考虑是否主要是蛋白质、脂肪或碳水化合物远离目标。DEAP 有可能非常容易地从单目标转移到多目标优化。

代码中唯一要改变的是 evaluate 函数,它现在应该返回四个值的元组(卡路里误差、蛋白质误差、脂肪误差和碳水化合物误差),并添加一个权重向量来平衡每一个值的权重。

Python 中的遗传算法——多目标评估。作者配图。

单目标与多目标优化

进一步检查单目标和多目标优化的结果是有趣的。在使用当前权重的情况下,它给出了以下内容:

  • 计算四个目标的误差,我们看到多元解的总误差更好
  • 我们还看到误差的分布是不同的。例如,如果蛋白质的正确性更重要,可以通过增加蛋白质的权重来调整。

Python 中的遗传算法——分析结果。作者配图。

最终,产品表总是限制因素:在某些时候,不可能找到完美达到目标的特定产品的组合。为了有一个更好的解决方案,我们必须增加更多的产品。

结论

关于遗传算法的实际工作还有很多要了解的,但是我希望这篇文章至少给你一个使用 Python 中的 DEAP 库开始使用遗传算法的快速方法,以及一个很好的用例例子。

不要犹豫,使用带有两个例子的示例笔记本,在遗传算法的学习道路上更进一步。现在,感谢阅读!

遗传算法——解决 IBM 的 2020 年 1 月问题

原文:https://towardsdatascience.com/genetic-algorithms-solving-ibms-january-2020-problem-e694d59f407d?source=collection_archive---------24-----------------------

遗传算法的 Python 介绍

蒂姆·莫斯霍尔德在 Unsplash 上的照片

你好。

这篇文章是对 GAs 的温和介绍,也是对 IBMs 2020 年 1 月问题的解决方案。如果你想创造你自己的 GAs 或者在读完这篇文章后想玩玩我的代码,请随意拿起这本装有所有代码的笔记本。尽情享受吧!

问题是

每个月 IBM 都会在他们的思考博客中发布一个与编程相关的挑战。通常,这些挑战与编程有关,但偶尔纸笔解决方案也是可行的。前一个是 2020 年 1 月挑战,下面是问题陈述:

“一个园丁有 12 桶特殊液体来浇灌他的兰花;正好有两桶有毒。使用任何数量,甚至一滴,从一个有毒的桶会杀死珍贵的兰花在 24 小时内。园丁在兰花死亡前只有三天时间,除非他能找出哪十桶是好的。他愿意牺牲四株兰花,用这些桶中的一个子集的混合物给它们浇水。他怎么能找到毒桶呢?”

表 1:挑战页面中的 8 筒配置

让我们花点时间思考一下问题是什么。本质上,我们有一个兰花浇水槽表,如上表所示。每个槽包括一组字母,每个字母代表一个桶。我们的任务是提出一个类似的表,其中有 4 朵兰花(行),3 天(列),总共 12 个桶,从 A 到 l 标记。我们想要这样的解决方案,即无论哪两个桶中毒,我们总是可以通过查看哪一天哪些兰花死亡来找出它。作为一个例子,让我们考虑在上面只有 8 个桶的环境中,A 和 B 中毒了。

  • 第一朵兰花在第一天死去
  • 第二朵兰花在第二天死去
  • 第三朵兰花也在第一天死去
  • 第四朵兰花存活了下来。

事实证明,无论你选择哪种桶的组合来下毒,你都不会得到相同的结果(兰花是如何死去的)。事实上,每一对中毒的桶都有一个独特的结果,这基本上是我们所追求的完美解决方案。

表 1:不起作用的 12 桶配置

乍一看,有 12 个不同的槽和 12 个桶,因此找到一个好的配置似乎很简单,但困难在于如果兰花在第一天死亡,剩下的两天浇水将不会提供任何额外的信息。上述解决方案不起作用的原因是不可能区分例如毒对 A&B 和 A&C,因为无论哪种方式,只有第一朵兰花会在第一天死亡,其余的存活下来!从第一张图中可以看出,2 天 8 桶的解决方案不包括在多天内对同一株兰花使用同一桶。

好的,我们可以猜测一个好的解决方案是每个槽大约有 2-3 桶。我们就不能试试不同的组合,看看什么有效吗?嗯,没有。

考虑到我们有 12 个不同的槽,为了简单起见,我们假设在每个槽中,我们正好使用 3 个不同的桶来给兰花浇水。可能的组合数将是(121110),大约等于 2.8*1⁰ ⁷,所以强制所有组合是不可能的。但是,这个问题在 NP(不确定是什么意思?→ 看这个。即使搜索空间呈指数增长,也只需要相对较少的努力就可以检查一个解决方案是否是好的。

验证解决方案

毒桶只有 66 对可能(|{AB,AC,AD… LL}| = 12 选 2 = 66)。给定一种配置(例如上表)并检查所有 66 种中毒桶组合,我们可以通过简单地检查是否有任何相同的结果来确定解决方案是否良好。为什么会这样?因为如上所述,一个完美的解决方案,园丁必须能够准确地找出有毒的桶,但只看可怜的兰花发生了什么。因此,如果给我们一个给兰花浇水的配置,如果我们发现重复的结果,这不是最终的解决方案。

量化兰花结果的一个简单方法是用一个从 0 到 3 的数字来表示它们的每一个命运,这表示兰花死于哪一天(从 0 开始)。因此,对于有八个桶的表 1,如果 A 和 B 中毒,结果将是(0,1,0,3)。这里的 3 只是表示兰花存活了下来。我们使用第 1→ 0 天,因为零索引使编程更简单。因此结果(0,1,0,3)可以理解为“第一天兰花 1 和 3 死亡,第二天兰花 2 和兰花 4 存活”。

现在我们的任务变成了寻找一个桶的配置(就像前面的表格一样),这样对于 66 个毒药桶对,所有的结果(我们用 0-3 的 4 个数字表示)都是唯一的。因为我们喜欢单一的解决方案(而不是计算所有的方案),所以我们可以利用 GAs。

遗传算法

作为进化算法的一个子类,遗传算法(GA)是一种元启发式算法,它使用进化过程的元素来解决搜索和优化问题。很拗口,但本质上归结起来就是不是迭代地改进一个解决方案,而是获取大量可能的解决方案,并将它们相互结合

这基本上是所有气体能量的来源。想象一下,给你一个随机配置的桶,你确定这不是最终的解决方案。您应该移动/移除/添加哪些桶?你越来越接近了吗?你离最终解决方案还有多远?

事实证明这些是很难问的问题,因为这不是一个凸或可微的问题,很多好的方法是不可行的。这就是 GAs 的疯狂之处:你不需要精确估计你离解决方案有多远——只是一种比较解决方案的方法。添加一些随机性和大量的迭代,我们就可以了!

遗传算法很大程度上受到进化论的启发,并且使用许多相同的术语,这可能并不令人惊讶,但是让我们更详细地看看遗传算法的两个基本组成部分:

人口

一组候选解称为群体。在我们的例子中,群体中的一个成员将是三天中桶的一种配置。随机初始化种群,并且进一步的世代是初始种群的更新和改进版本。就像进化一样,旧的单位被新的、可能更好的单位取代。如何测试哪些解决方案优于其他解决方案?

健身

适应度函数给每个候选人一个分数。这个分数有两个目的。

  1. 选择—删除不好的解决方案
  2. 结束条件—检查我们是否找到了最终解决方案

适应度是你想要最小化/最大化的东西(对于 ML 的那帮家伙,你可以把它想成一个损失函数)。

但是在我们的问题中,衡量一个解决方案有多好的好方法是什么?我们的问题是谨慎的,它需要一些严肃的问题工程来找出什么样的答案结构会给出好的结果的潜在原则。

一种方法是采用结束条件并详述它。我们的最终条件是找到一种给兰花浇水的方法,这样无论哪一对桶实际上有毒,园丁总能精确地找出它们是哪两个桶。如果有毒桶的组合会产生完全相同的结果,则解决方案无效(记住 4 位数表示)。现在让我们反过来想想,如果我们有最坏的解决方案,我们不会使用任何桶。这将给园丁零信息,因为所有的毒药桶组合将产生重复!所以也许有一种可能的方法来衡量一个答案有多好,就是简单地数一数有多少重复!

气体的神奇之处在于,我们的测量不必完全精确。这就足够了,这是一个我们想要着陆的大概估计,我们可以让随机过程来处理剩下的事情。

因此,为了我们的目的,我们可以用一个适应度函数来计算桶的给定配置

66 - # of unique outcomes.

如果有任何重复的结果(这是我们想要惩罚的),则适应性得分较高,而“更好”的解决方案得分较低。最优解的分数是 0,因为正好有 66 个唯一的结果。我们现在的目标是简单地最小化我们人口中成员的这种适应性。但是怎么才能最小化呢?

评估

第一步是评估人口。这是我们根据解决方案的好坏对其进行排名的地方。在我们的设置中,这是基于重复的数量。如果候选解具有较少的重复,则它们的排名较高,在没有重复的情况下,最好的总是有效的解。

选择

在我们对群体进行评估和排序之后,自然选择就发生了。有很多有趣的方法可以做到这一点,但关键的想法是去除不好的解决方案,以便为更好的解决方案留出空间

交叉

现在,我意识到大多数麻省理工学院的学生对有性生殖有了基本的了解,但是我发现在和学生的交谈中,很多时候他们对细节有点模糊。所以让我们先来思考一下它是如何工作的。— 帕特里克·温斯顿开始了关于遗传算法的讲座

交叉有多种形式,但 GAs 的基本思想是好的解决方案可以相互组合,以产生可能更好的解决方案。在我们的例子中,我们可以使用一种最简单的交叉方法,即单点交叉

单点交叉的工作原理如下:

  1. 取两个母解
  2. 选择一个随机的位置将它们分开
  3. 在子表之外,创建新的两个子解决方案,它们是两个父解决方案的组合。

在我们的例子中,分割位置(或支点)是一个随机的槽。在下面的图片中,单点杂交是在随机槽(兰花 3 |第 2 天)对两个任意亲本进行的

父配置

相应的子配置

对于交叉,可以包含精英主义、,这意味着在交叉后是否保留父代。如果保留父代,我们就不能创造同样多的子代,因为否则,种群规模将在每次迭代中增长,这可能会导致一些不稳定。通常,精英主义使算法稳定,因为好的解决方案停留的时间更长。如果我们在没有精英主义的情况下进行杂交,这意味着我们可以创造更多的后代,但如果进行过于随机的杂交,我们可能会失去潜在的可行解。

交叉的一个问题是,它本质上只是将旧的解决方案组合在一起。就其本身而言,这并不能保证找到一个好的解决方案,如果将两个好的解决方案组合在一起并不能构成一个更好的解决方案,我们可能会陷入局部最小值。那么,我们如何逃离死胡同,想出更新颖的解决方案呢?

突变

记住,当你在生活中不知道该做什么时,总是随机选择。省去了同样预期收益的麻烦。—组合学老师,2019

这里也是如此。与交叉相对应,突变是纯粹的随机变化。任意改变群体中个体成员的随机因素服务于一个重要的目的,因为我们不知道我们是否实际上接近实际的最佳解决方案,或者我们是否被困在局部体面的解决方案中。在更抽象的层面上,如果一个群体仅通过使用相同的候选人池来进化,它很可能变得非常同质,并可能错过更好的解决方案。

在我们的兰园中,变异将会从某个配置中随机添加和删除桶。通常,变异的作用较小,用于逃脱死胡同,因此变异率(即候选解发生变异的概率)较小。

过多的变异会使遗传算法变成一个随机猜测机器,过少的变异会导致它错过潜在的非常好的解决方案。慎用。

算法

总结我们到目前为止学到的东西,并放入算法框架中,

  1. 首先,初始化种群并定义一个适应度函数。

2.其次,重复以下步骤,直到找到有效的解决方案。

  • 评估:根据候选人的健康程度对其进行排名。
  • 选择:删除弱(不太适合)的候选人
  • 交叉:繁殖后代解(即通过合并旧解产生新的候选解)。
  • 突变:添加一些突变(在这里和那里随机调整候选)。

由于显而易见的原因,循环的每次迭代,新的群体被称为代、。这些操作的顺序可以根据不同的 GAs 而有所不同,但是理论上就是这样,现在到 Python!

代码

现在我们可以开始实现实际的算法了。在下面的代码中,我们从导入组合-方法和随机- 包开始。字母表是包含所有可能桶的列表,从 AL ,而 test_answer 显示了每个单独答案应该具有的结构,也就是一个 4x3 列表,其中每个元素也是桶的列表,即槽。

例如,在下面的代码中,slot ["D "," K"]是第一行第二列的元素,所以这意味着兰花 1 在第二天用桶 D 和桶 K 浇水。

from itertools import combinations
import randomALPHABET = list("ABCDEFGHIJKL")test_answer = [ 
    [["A","J"], ["D","K"], ["G"]],
    [["G","H"], ["A","B"], ["D","E"]],
    [["E","F"], ["H","I"], ["B",]],
    [["C","J"], ["F","K"], ["I","C"]]
]

init_population 创建第一代,即填充那些 4x3 列表的群体,其中每个槽(元素)填充 3 个随机桶。

def **init_population**(n):
    """Return a population of n random solutions. Each solution is
    a 4x3 list, with each element being a selection of 3 distinct
    random barrels.
    """
    return [[[random.sample(ALPHABET,k=3) for d in range(3)] \
             for o in range(4)] for i in range(n)]

接下来我们定义适应度函数,为每个候选解调用。概括地说,我们希望它

  1. 检查所有可能的有毒桶组合
  2. 给定一个桶形配置,模拟每种组合的兰花会发生什么
  3. 计算独特结果的数量
  4. 返回 66 -那个数字
def **fitness**(candidate):
    """Return number of unique outcomes. Iterate through all
    possible pairs of poisonous barrels and the twelve slots.
    For each poisonous pair generate the outcome as a list
    e.g. [0,1,2,3], where the indexes are the orchids and
    numbers they day that orchid died (3 indicates that it
    did not die). Calculate the number of unique outcomes by
    adding outcomes o a set and return 66 - the length of
    that set. For a perfect solution there are 66 unique
    outcomes, thus return 0.
    """
    combs = list(combinations(ALPHABET,2)) 
    outcomes = set()
    for poisoned in combs: # Iterate through all poisonous barrels
        died_on = []
        for o in range(4): # Orchid
            dead_orchid = False
            for d in range(3): # Day
                if not dead_orchid and any([p in candidate[o][d]
                                            for p in poisoned]):
                    dead_orchid = True
                    died_on.append(d)
                elif not dead_orchid and d==2:
                    died_on.append(3) # Add the "survive" token 3.
        outcomes.add(tuple(died_on))
    return 66 - len(outcomes)

评估相当简单,只返回按适应度排序的人口。

def **evaluation**(population):
    """Return a population sorted by fitness."""
    return sorted(population, key= lambda x:fitness(x))

选择返回人口中更好的一半(这样就有空间给更多优秀的候选人)

def **selection**(population):
    """Return top half of population."""
    return population[:len(population)//2]

接下来是性的部分,即交叉。请注意,交叉操作会返回一个两倍于输入大小的新群体!所以我们假设选择是预先完成的。

def **crossover**(population,elitism=False):
    """Return a new population, generated by randomly pairing
    members of population (out-of-place). For each random pair,
    select a random pivot slot and generate 2 children:
    child1[j] = parent1[j],
    child2[j] = parent2[j], when j < pivot slot
    and
    child1[j] = parent2[j],
    child2[j] = parent1[j], when j >= pivot slot
    If elitism
        return parents and the child1s.
    Else
        return child1s and child2s
    """
    children = []
    n_pop = len(population)
    for i in range(n_pop): # Cross N times
        parent1,parent2 = random.sample(population,k=2)
        child1 = [[None for a in range(3)] for b in range(4)]
        child2 = [[None for a in range(3)] for b in range(4)]
        pivot = random.randrange(12) # Select a pivot slot.
        for j in range(12): # Iterate through slots
            o = j//3
            d = j%3
            if j < pivot:
                child1[o][d] = parent1[o][d]
                child2[o][d] = parent2[o][d]
            else:
                child1[o][d] = parent2[o][d]
                child2[o][d] = parent1[o][d]
        children.append(child1)
        if not elitism: children.append(child2)
    if elitism:
        return population+children
    else:
        return children

还有最后一个成分,突变。对于每个候选,它选择是否变异,取决于 p_mutate。如果它确实发生了变异,无论是增加还是移除桶,它都会掷硬币。此外,如果只有一个或更少的桶,那么添加相同类型的桶和删除桶是没有意义的。返回一个(可能稍微)变异的群体。

def **mutation**(population,p_mutate):
    """Return a mutated population (out-of-place). For each
    candidate, mutate with probability p_mutate.
    If mutate:
        Select random slot.
        Flip a coin whether to add or remove a random barrel.
    Else:
        The candidate is not affected.
    Return new (partially mutated) population.
    """
    mutated_population = []
    for candidate in population:
        if random.random() < p_mutate:
            # Mutate
            # Choose random slot
            o,d = random.randrange(4),random.randrange(3)
            if random.random() < 0.5 and len(candidate[o][d]) > 1:
                # Remove a barrel
                remove = random.choice(candidate[o][d])
                new_slot = [e for e in candidate[o][d] if e!=remove]
            else:
                # Add a barrel
                addable = list(set(ALPHABET)-(set(candidate[o][d])))
                add = random.choice(addable)
                new_slot = [e for e in candidate[o][d]] + [add]
            mutated_candidate = [[d for d in o] for o in candidate]
            mutated_candidate[o][d] = new_slot
        else:
            # Don't mutate
            mutated_candidate = [[d for d in o] for o in candidate]
        mutated_population.append(mutated_candidate)
    return mutated_population

我们走吧!现在我们只需创建训练循环。我选择了 0.9 的突变率,因为即使会发生突变,它对解决方案的影响也很小,所以有更多的突变也不会有什么坏处。此外,我只是粗略估计了 1000 人的人口规模,但它同样适用于 10,1000 或 10,000 人。精英主义似乎加快了事情的进展,所以这是可行的,但是你可能还是想尝试一下不同之处!

p_mutate = 0.9
n_pop = 100
best_fitness = 9999# Initialize population
pop = init_population(n_pop)
pop = evaluation(pop)i = 0
while best_fitness > 0:
    pop = selection(pop)
    pop = crossover(pop,elitism=True)
    pop = mutation(pop,0.5)
    pop = evaluation(pop)

    if fitness(pop[0]) < best_fitness:
        best_fitness = fitness(pop[0])
        print(f"New best fitness: {best_fitness} | i={i}")
    i+=1

print(pop[0])

它打印出类似这样的东西(在普通的笔记本电脑上大约需要 1-5 分钟)

New best fitness: 14 | i=0
New best fitness: 11 | i=5
New best fitness: 9 | i=13
New best fitness: 7 | i=14
New best fitness: 6 | i=20
New best fitness: 4 | i=23
New best fitness: 3 | i=70
New best fitness: 2 | i=101
New best fitness: 1 | i=770
New best fitness: 0 | i=915
[[['J', 'H'], ['A', 'K'], ['D', 'K', 'A', 'B']], [['L', 'F'], ['G', 'E', 'I', 'F'], ['D', 'L', 'G']], [['G', 'B'], ['L', 'K'], ['E', 'H', 'K', 'G']], [['A', 'I'], ['F', 'D', 'J', 'A'], ['E']]]

这就是我们的解决方案!对于实际的挑战,我重用了适应度函数中的一些代码来验证它实际上是一个正确的解决方案,但是假设一切顺利,这个应该是可行的。但是我们学到了什么?

有趣的是,我们可以从迭代中看到,计算最后几步需要成倍增加的时间(我运行了几次,得到了类似的模式),这意味着从 1 或 2 适应度到 0 比从 14 到 2 要困难得多。有可能在适应度=1 附近存在局部最小值,其中交叉开始产生非常相似的结果,并且重要的多样性丢失。有可能这最后一步是通过纯粹的随机运气实现的,因为我们不知道有多少可能的正确解决方案。然而,突变率已经非常高了,所以将其更改为 1 不会有太大的差异,并且为了获得更稳定和更快的结果,该突变可能不只是一次更改一个插槽(可能在一次突变中更改几个?).

余波

当你处理一个搜索或优化问题时,遗传算法是有用的,而更传统的方法是不可行的(例如梯度下降或简化问题),然而搜索空间太大而不能蛮干。从本质上来说,GAs 只是一种更精细的有根据的猜测方式,但是它们通过利用概率和计算能力以一种优雅的方式做到了这一点。他们有能力解决一些非常棘手的问题(比如旅行推销员问题)。然而,这些问题需要是 NP 的,因为检查一个解决方案的良好性(即计算适应度)在计算上不能太昂贵。因此,应用 GAs 适合复杂问题的特殊情况,在这种情况下,其他方法不适用(一种思考方式是,如果其他方法都不起作用,您可能想尝试一下 GAs)。一般来说,我建议使用 GAs 作为最后的手段,例如,当没有特定领域的知识或者问题不能被映射到一个更简单的图问题(它会有自己的,可能更快的方法)时。

一些好的属性是 GAs 很容易创建,并且(如上所示)可以使用普通 Python 来完成。此外,一个人不需要对问题有深入的理解就能找到解决方案,有时一个大概的启发就足够了!这就是我个人喜欢 GAs 的原因,它们提供了一个很好的中间地带,一个相对简单的程序可以用一种天生直观的方法来解决一个复杂的问题(毕竟,有什么比进化更容易理解)。

基因组组装——基因组分析的圣杯

原文:https://towardsdatascience.com/genome-assembly-the-holy-grail-of-genome-analysis-fae8fc9ef09c?source=collection_archive---------17-----------------------

组装 2019 新型冠状病毒基因组

T he 2019 新型冠状病毒或冠状病毒病(新冠肺炎)疫情目前已经威胁到整个世界。科学家们正在夜以继日地研究新冠肺炎的起源。你可能最近听说了新冠肺炎的完整基因组已经发表的消息。科学家是如何算出新冠肺炎的完整基因组的?在这篇文章中,我将解释我们如何做到这一点。

基因组

一个基因组被认为是所有的遗传物质,包括一个生物体的所有基因。基因组包含了生物体构建和维持所需的所有信息。

定序

我们如何读取基因组中存在的信息?这就是序列发挥作用的地方。假设你已经读过我的上一篇关于 DNA 分析的文章,你知道测序是用来确定一个有机体的单个基因、完整染色体或完整基因组的序列。

图一。PacBio 测序仪。PacBio 是第三代测序技术,可产生长读数。图片由肯尼斯·罗德里格斯提供,来自皮克斯拜 (CC0)

被称为测序机器的特殊机器被用来从我们感兴趣的基因组中提取短的随机序列。目前的测序技术不能一次读取整个基因组。它读取平均长度在 50-300 个碱基(下一代测序/短读取)或 10,000-20,000 个碱基(第三代测序/长读取)之间的小片段,这取决于所使用的技术。这些短片被称为读作

如果你想了解更多关于病毒基因组如何从临床样本中测序的细节,你可以阅读以下文章。

  1. 临床样本病毒全基因组测序的完整方案:应用于冠状病毒 OC43
  2. 从临床样本中特异性捕获病毒并进行全基因组测序

基因组组装

一旦我们有了基因组的小片段,我们必须根据它们的重叠信息将它们组合(组装)在一起,并构建完整的基因组。这个过程叫做组装。组装就像解决一个拼图游戏。被称为组装器的特殊软件工具被用来根据它们如何重叠来组装这些读数,以便生成被称为重叠群的连续串。这些重叠群可以是整个基因组本身,也可以是基因组的一部分(如图 2 所示)。

图二。排序和组装

装配工分为两类,

  1. 从头组装器:不使用参考基因组进行组装(例如:黑桃SGAMEGAHIT天鹅绒卡努Flye )。
  2. 参考引导装配器:通过将序列映射到参考基因组进行装配

两种主要类型的装配工

在生物信息学文献中可以找到两种主要类型的装配器。第一种是重叠-布局-一致性(OLC)方法。在 OLC 方法中,首先,我们确定读数之间的所有重叠。然后我们将所有的读数和重叠以图表的形式排列出来。最后,我们识别共有序列。SGA 是一个基于 OLC 方法的流行工具。

第二种汇编程序是 DBG 图法。DBG 方法不是使用完整的读数,而是将读数分成更短的片段,称为k-mer(长度为 k ),然后使用所有的k-mer 构建一个德布鲁因图。最后,根据德布鲁因图推断基因组序列。黑桃是一个基于 DBG 方法的流行汇编程序。

基因组组装会出什么问题?

基因组包含在基因组中多次出现的核酸模式。这些结构被称为重复。这些重复会使组装过程变得复杂并导致歧义。

我们不能保证测序机器能够产生覆盖整个基因组的读数。测序机器可能会错过基因组的某些部分,并且不会有覆盖该区域的读数。这将影响装配过程,并且那些遗漏的区域将不会出现在最终装配中。

基因组组装者应该解决这些挑战,并尽量减少组装过程中造成的错误。

如何评估程序集?

组件的评估非常重要,因为我们必须决定最终的组件是否符合标准。其中一个广为人知且最常用的汇编评测工具是。下面列出了一些用于评估组件的标准。

  • N50: 覆盖组件总长度的 50%所需的最小重叠群长度。
  • L50: 比 N50 长的重叠群的数量
  • NG50: 覆盖 50%参考基因组长度所需的最小重叠群长度
  • LG50: 比 NG50 长的重叠群的数量
  • NA50: 要求覆盖组件总长度 50%的对齐砌块的最小长度
  • LA50: 比 NA50 长的重叠群的数量
  • 基因组比例(%): 与参考基因组比对的碱基百分比

弄脏手

让我们开始做实验吧。我将使用汇编程序****来汇编从测序患者样本中获得的读数。黑桃利用下一代测序读取。你也可以免费下载。您可以从相关的主页(我提供了链接)获得代码和二进制文件,并运行这些工具。********

键入以下命令,并验证工具是否正常工作。

****<your_path_to>/SPAdes-3.13.1/bin/spades.py -h
<your_path_to>/quast-5.0.2/quast.py -h****

下载数据

我想你知道如何从国家生物技术信息中心(NBCI)下载数据。如果没有,可以参考这个链接

我们实验的读数可以从 NCBI 下载,NCBI 登记号为 SRX7636886 。您可以下载运行 SRR10971381 ,其中包含从 Illumina MiniSeq 运行中获得的读数。确保下载 FASTQ 格式的数据。下载的文件可以找到为**sra_data.fastq.gz**。您可以使用 gunzip 提取 FASTQ 文件。

提取之后,您可以运行下面的 bash 命令来计算数据集中的读取次数。您将看到有 56,565,928 次读取。

**grep '^@' sra_data.fastq | wc -l**

你可以从 NCBI 下载公开的新冠肺炎完整基因组[3],GenBank 登录号为 MN908947 。你会看到一个 FASTA 格式的文件。这将是我们的参考基因组。注意,我们已经将其重命名为**MN908947.fasta**

装配

让我们把新冠肺炎的作品汇编起来。运行以下命令,使用黑桃来组合读数。您可以提供压缩的。gz 档直接给黑桃。

**<your_path_to>/SPAdes-3.13.1/bin/spades.py --12 sra_data.fastq.gz -o Output -t 8**

这里我们使用了通用的黑桃汇编器作为本文的演示。然而,由于 reads 数据集由 RNA-Seq 数据组成(从我的上一篇文章中了解更多关于 RNA 的信息),最好使用--rna选项。

Output文件夹中,你可以看到一个名为**contigs.fasta**的文件,其中包含我们最终组装的重叠群。

评估装配结果

使用以下命令在组件上运行撤销

**<your_path_to>/quast-5.0.2/quast.py Output/contigs.fasta-l SPAdes_assembly -r MN908947.fasta -o quastResult**

查看评估结果

一旦 QUAST 完成,您可以进入 quastResult 文件夹并查看评估结果。您可以通过在 web 浏览器中打开 report.html 文件来查看 QUAST 报告。您可以看到类似于图 3 所示的报告。您可以点击“扩展报告”了解更多信息,如 NG50 和 LG50。

图三。撤销报告

您可以研究不同评估标准的值,如基因组比例 NG50、NA50、错配和重叠群数量。此外,您可以使用 Icarus contig 浏览器(点击“在 Icarus contig 浏览器中查看”)查看与参考基因组的重叠群比对,如图 4 所示。

图 4。撤销报告

从 Icarus contig 浏览器中,我们可以看到名为NODE_1的 contig 与新冠肺炎的参考基因组非常接近。它的基因组比例为 99.99%(如图 3 所示)。此外,29,900 个碱基对的总比对长度非常接近 29,903 个碱基对的参考基因组的长度。

可视化装配图

有一个名为 绷带 的工具可以用来可视化装配图。您可以从它们的主页下载预编译的二进制文件并运行该工具。您可以加载可在黑桃输出文件夹中找到的图形文件**assembly_graph_with_scaffolds.gfa**(进入文件→加载图形→选择。在Output中打开 gfa 文件)进行包扎,点击“绘制图形”进行可视化,如图 5 所示。请注意,图 5 中第一行线段中间的绿色长曲线线段对应于我们的黑桃组合的 NODE_1。

图五。使用绷带可视化的新冠肺炎读数数据集的黑桃装配图的一部分。

他们最初是如何发现新冠肺炎基因组的?

由于新冠肺炎的参考基因组现在是可获得的,我们可以评估我们的装配。然而,起初,新冠肺炎没有确切的参考基因组。那么科学家们是怎么弄明白的呢?正如我在之前的文章中解释的,分析病毒基因组属于宏基因组学,有许多技术可以做到这一点。他们分析了重叠群的覆盖范围(覆盖重叠群中每个碱基位置的平均读数),并与蝙蝠 SARS 样冠状病毒(CoV)分离株— 蝙蝠 SL-CoVZC45 (GenBank 登录号mg 772933)【3】。结果显示,它们最长的组装重叠群具有高覆盖度(从我们的组装中,您可以看到 NODE_1 也具有高覆盖度值),并且与 bat SL-CoVZC45 非常接近。他们已经进行了更多的测试来证实这一点,我就不赘述了。

最后的想法

基因组组装为我们研究生物体基因组内部的实际情况铺平了道路。即使在新冠肺炎病毒爆发期间,基因组组装也在识别这种致命病毒的实际遗传密码方面发挥了重要作用。

如果你检查新冠肺炎基因组的大小,它是 29903 个碱基对(大约 30k 个碱基对)。随着第三代测序技术的进步,我们可能能够直接对小基因组如病毒基因组的全长进行测序。随着阅读长度变得更长,组装阅读的需求将会减少,最终,我们将可以从测序仪中直接获得基因组(特别是在宏基因组学中,基因组的范围从几千个碱基到几兆个碱基)!此外,革命性的基于纳米技术的方法,如量子测序技术【4】包括石墨烯纳米器件【5】可能会变得流行。

谢谢大家的阅读。如果你觉得我的文章有趣,请在你的网络上分享。我也很想听听你的想法。

干杯!

参考

[1]挖掘冠状病毒基因组寻找爆发起源的线索|科学|美国科学促进会(https://www . Science mag . org/news/2020/01/Mining-coronavirus-genomes-clues-outbreak-s-origins)

[2]李振玉等.两大类组装算法的比较:重叠-布局-一致性和 de-bruijn-graph,功能基因组学简报,第 11 卷,第 1 期,2012 年 1 月,第 25-37 页。https://doi.org/10.1093/bfgp/elr035**

[3]吴芳芳,赵,于等一种新型冠状病毒在中国发现与人类呼吸系统疾病相关。性质 (2020)。https://doi.org/10.1038/s41586-020-2008-3****

[4]张一日和金武南。从头全基因组组装的现在和未来。生物信息学简报,第 19 卷,第 1 期,2018 年 1 月,第 23–40 页。https://doi.org/10.1093/bib/bbw096**

[5]希雷玛和德克尔。用于 DNA 测序的石墨烯纳米器件。 Nature Nanotech 11,127–136(2016)。https://doi.org/10.1038/nnano.2015.307

使用德布鲁因图的基因组组装

原文:https://towardsdatascience.com/genome-assembly-using-de-bruijn-graphs-69570efcc270?source=collection_archive---------16-----------------------

来源

基因组测序后,我们可以找出基因组中 DNA 核苷酸或碱基的顺序——组成生物体 DNA 的 As、Cs、Gs 和 Ts 的顺序。整个基因组不能一次全部测序,因为可用的 DNA 测序方法一次只能处理很短的 DNA 片段。因此,相反,科学家必须将基因组分成小片段(缩写),对片段进行测序,然后按照正确的顺序重新组装,以获得整个基因组的序列。

基因组组装可以被描述为一种计算过程,它将之前提到的来自生物体细胞内靶 DNA 不同部分的称为读数的众多短序列集合在一起。这是一个算法驱动的自动化过程。DNA 序列组装程序利用序列重叠来以正确的顺序进行序列组装。

图 1-https://www.yourgenome.org/

实现基因组组装有许多挑战。一个主要的挑战是处理错误的读数。无论使用何种测序技术,读数都不会 100%准确。为了克服这种测序,可以多次使用相同的 DNA 片段。一个部分被排序的次数叫做覆盖率。覆盖面越广,可信度就越高。所以覆盖率高导致了大量的 DNA 序列的短阅读。这些短文像拼图中的小块碎片一样混在一起。它们应该被组织在一起,并按照正确的顺序组合成基因组序列。因此,组合这些短的阅读片段来获得原始基因组是一项艰巨的任务。

从头基因组组装

这是一种在不使用参考基因组的情况下将短的核苷酸序列组装成更长的序列的程序。在这种进行装配的方法中,假设没有源 DNA 序列长度、布局或组成的先验知识。序列汇编器的最终目标是从短序列中产生长的连续序列片段(重叠群)。然后,重叠群有时被排序并相对于彼此定向以形成支架。两种常见的从头组装器是贪婪算法组装器和布鲁因图组装器。在贪婪方法中,它的目标是局部最优,而在图方法中,它的目标是全局最优。我们将在本文中讨论后者。

一般 de nevo 装配也包括脚手架和间隙填充步骤。支架是将一系列不连续的基因组序列连接成一个支架,由已知长度的缺口分隔的序列组成。连接的序列通常是对应于阅读重叠的连续序列。

图 2-de nevo 装配的一般工作流程

德布鲁因图装配工

早期,一种应用于第一代测序数据的有效组装方法是重叠-布局-一致性方法,该方法涉及所有读数对的比较以识别重叠。但是这对于用第一代方法组合这些读数所需的计算既不实际也不困难。

在 20 世纪 40 年代,一位名叫 Nicolaas de Bruijn 的荷兰数学家开始对寻找最短的环形字符串感兴趣,该字符串包含给定字母表中所有可能的子字符串,每个子字符串长度相同。他想出的解决方案包括构建一个以所有可能的(k1)聚体为节点的图。如果节点 A 中的(k-mer 是 k-mer 的前缀,而节点 B 中的(k-mer 是 k-mer 的后缀,则每个 k-mer 都是从节点 A 到节点 B 的边。

现在这个问题的答案是找到一条穿过图的路径,这条路径恰好穿过每条边一次,或者换句话说,欧拉路径。下面是一个例子,其中长度为 10 的序列“ ATGCTAGCAC ”由五个长度为 6 的读取组合而成。

图 3-使用德布鲁因汇编程序的过程

读取被分成指定大小为 k 的较小片段。在上面的示例中,k 对应于 3。确定了 k-mers,并绘制了以(k–1)mers 为节点、k-mers 为边的德布鲁因图,如文中所述。通过这个网络追踪欧拉路径,导致原始基因组序列的重建。

在从给定的短读数重建原始序列的过程中,可以指定以下步骤。

步伐

  1. 从 k-mer 集合中取出所有(k-1)个 mer,例如 ATG、TGC-> AT、TG、GC。我们应该已经超过了 k-mer 读取的大小。
  2. 构造一个节点为 k-1-mers 的多图;仅当两个 k-1 mer 来自同一读数时,在两个 k-1 mer 之间画一条边。 Ex: GCT & CTA

带 GCT 和 CTA 的多重图

3.以这种方式构造的图保证具有欧拉轨迹,跟随该轨迹并连接节点以形成我们的原始序列。将出现与此类似的图形。

多重图重建序列 ATGCTAGCAC

现在这个算法可以用来组装 k-mer 读数。我们可以放宽条件,接受超过给定长度的读取,并将每个 k-mer 分成(k-mer,以考虑具有 k-n 个重叠而不是 k-1 个重叠的读取。此外,重建更容易组装的部分(重叠群)并省去不明确的部分是方便的。

以下 Jupyter 笔记本可用于实现德布鲁因汇编程序。

用于德布鲁因装配工的 Jupyter 笔记本

的确,基于 de Bruijn 图的组装方法开始时,有些违背直觉,用一组较短的固定长度的全重叠序列代替每个读数,但这是一种流行的基因组组装方法。

可以免费下载、使用和修改的稳定和健壮的软件包已经被开发出来,用于使用 de Bruijn 图从短阅读中组装基因组。一种名为 Velvet 的流行软件似乎在组装基因组方面表现得非常好(主要是在细菌上)。

虽然 de bruijn 组装器是实现组装的流行手段,但是对于 de bruijn 基因组组装来说仍然存在一些挑战。序列错误、不均匀的测序深度、重复的部分和计算成本是几个主要的挑战。

参考文献:

面向数据科学家的基因组学、转录组学和蛋白质组学

原文:https://towardsdatascience.com/genomics-transcriptomics-and-proteomics-for-data-scientists-60fd5b2d09ff?source=collection_archive---------26-----------------------

细胞、DNA、RNA 和蛋白质

图片来源:维基百科,归功于威廉·克罗夫特

你的基因组大约有 750 兆字节的信息(3 个 10⁹字母 x 1 个字节/4 个字母)。这大约是一个操作系统的一半大小,除了它为一个完整的人体编码,并且整个代码适合一个比一粒米小一百倍的体积。你的大脑是由你的基因组指定发展的,是一台不可思议的超级计算机,它需要的电力也比昏暗的灯泡少——实际上比人造超级计算机的能效高数万倍。

那么基因组是如何工作的呢?

基因组学、转录组学和蛋白质组学是数据驱动的领域,旨在回答基因组如何为一个有生命、有呼吸的人(或猫、或植物、或细菌)编码的问题。这篇文章向对“组学”数据感兴趣的计算科学家和工程师介绍了基因组学、转录组学和蛋白质组学,并希望快速介绍这些数据的来源和数据背后的关键生物学。这篇文章使用最少的术语和多种类比来阐明这些不同类型的“组学”数据之间的异同,以及它们如何为现存最复杂的软件之一——你的 DNA——提供不同的窗口。

牢房

细胞是所有生物的基本组成部分:人、狗、老鼠、树、花、苍蝇和细菌。所有形式的“组学”都在测量细胞内发现的大量物质。

这是用显微镜拍摄的一些细胞的照片。我用红色标出了一些单元格。每个红色圆圈对应一个单元格:

修改自维基百科

罗伯特·胡克在 1665 年发现并命名了细胞。他称它们为细胞,因为在显微镜下它们看起来像“细胞”或小房间——换句话说,“细胞”被称为“细胞”,因为它们在显微镜下看起来像监狱的细胞。

来自人、狗、老鼠、树、花和苍蝇的细胞是“真核细胞”,这意味着这些细胞将它们的 DNA 打包在一个袋子里(细胞核)。

来自细菌的细胞被称为“原核细胞”,因为它们不把 DNA 保存在袋子里(即它们没有细胞核):

这是早期(真核生物)细胞的特写照片,细胞核用棕色圈起来:

DNA 和基因

你的 DNA 是由 30 亿个字母组成的长序列,存在于你的细胞核内。你身体里的每个细胞(很少例外)都有你整个基因组的完整拷贝(即你所有的 DNA)。因为你的身体里大约有 37.2 万亿个细胞,这意味着你携带了大约 37.2 万亿份你的整个 DNA 序列!其中的含义很有趣:这意味着你指尖的一个细胞包含了构建整个大脑所需的所有指令。

“基因”是编码制造蛋白质指令的特定 DNA 片段。

我们可以把身体想象成一个工厂,它需要某些“机器”(蛋白质)来运转:

基因是一组如何建造特定机器的指令。例如,基因 B 包含建造机器 B(蛋白质 B)的指令,基因 Q 包含建造机器 Q(蛋白质 Q)的指令等等。

只有 1% 的基因组实际上由基因组成。基因被称为基因组的“编码”部分,因为基因“编码”蛋白质。人类基因组中大约有 25,000 个基因,相当于 25,000 个使你身体运转的小机器(蛋白质)。

剩下的 99%的基因组是“非编码的”基因组的“非编码”部分仍然很重要,因为它告诉细胞如何利用“编码”部分。

换句话说,如果“编码”部分作为如何制造不同机器的指令,那么“非编码”部分作为如何在工厂中使用这些机器的指令:何时需要打开机器,何时需要关闭机器,需要多少台机器,何时应该使用机器,等等。

如果我们把基因组想象成一本书,它将包含一些关于如何构建机器的文本(编码部分,在下面以橙色和蓝色显示),以及一些关于如何使用机器的文本(非编码部分,在下面以黑色显示):

维基百科上的空白开卷图片修改而来

核苷酸:DNA 的构件(A,T,C,G)

DNA 中的 30 亿个字母来自一个有限的字母表,只有 4 个可能的字母:A、T、C 和 G。(有趣的事实:这就是为什么电影《Gattaca》讲述了一个基因“劣等”的人战胜他的社会的故事,在片名中只使用了字母 A、T、C 和 G。)

这是人类基因 S100A10(也称为“p11”)的完整 DNA 序列,基因组中最短的基因之一:

CCGGTTACCTCTGGTTCTGCGCCACGTGCCCCACCGGCAGGACGGCCGGGTTCTTTGATT TGTACACTTTCTAAAACCAAACCCGAGAGGAAGGGCAGGCTCAGGGTGGGATGCCCTAAA TATTCGAGAGCAGGACCGTTTCTACTGAAGAGAAGTTTACAAGAACGCTCTGTCTGGGGC GGGCGAGCGCTCTGCGAGGCGGGTCCGGGAGCGAGGGCAGGGCGTGGGCCGCGCGCCCGG GGTCGGGGGAGTCGGGGGCAGGAAGAGGGGGAGGAGACAGGGCTGGGGGAGCGCCCTGCC GAGCGCCCGCCAGGCTCCTCCCCGTCCCGCACCGCCTCCCTCTACCCACCCGCCGCACGT ACTAAGGAAGGCGCACAGCCCGCCGCGCTCGCCTCTCCGCCCCGCGTCCACGTCGCCCAC GTCGCCCAGCTCGCCCAGCGTCCGCCGCGCCTCGGCCAAGGTGAGCTCCCAGTTCGGCCC

【序列来源: ebi.ac.uk

DNA 的组成部分(四个字母 A、T、C 和 G)被称为“核苷酸”它们的全称是鸟嘌呤(G)、腺嘌呤(A)、胞嘧啶和胸腺嘧啶(T)。

每个核苷酸构件依次由碳、氢、氧和氮组成。例如,胞嘧啶由 13 个原子组成。这是 2D 关于胞嘧啶的“棍球漫画”:

基于cs.boisestate.edu所示的化学结构

这是胞嘧啶的 3D 效果图:

3D 渲染来源:维基百科

(技术说明:上面胞嘧啶的图片实际上是“核碱基”胞嘧啶,它是最基本的化学部分。“核苷”是核碱基加上糖核糖。“核苷酸”DNA 的直接构建模块——是核碱基加上糖核糖再加上一个或多个磷酸基团。因此,从技术上来说,为了让上面显示的胞嘧啶图片代表真正的 DNA 构建模块,它需要添加一个核糖和一个磷酸。)

当我们将核苷酸 A、T、C 和 G 串在一起形成 DNA 时,我们得到了一种叫做“核酸”的东西——因此 DNA 的全称是“脱氧核糖核酸”。

DNA 是双链的;为了简单起见,我在上面的卡通图中只展示了一条线。DNA 的双链性质是“双螺旋”的原因:

来自维基百科的动画

这两股 DNA 相互缠绕形成双螺旋。一条链中的信息是另一条链中信息的“镜像拷贝”。这是由于 A、T、C 和 G 构件是如何相互配对的。a 与 T 配对,C 与 g 配对。因此,如果一条链读为“AAATTC ”,则相反的链将总是读为“TTTAAG”。一条链的信息量等于另一条链的信息量。

拥有两份相同的信息似乎是一种浪费,但事实上 DNA 的双链性质非常重要:

  • 双链促进了 DNA 复制(即复制整个基因组,这必须在每次一个细胞分裂成两个细胞时发生,因为每个“子细胞”都需要基因组的完整副本);
  • 双链使得身体能够错误纠正基因组(即,如果在复制过程中出现错误,双链能够纠正错误);
  • 双链比单链更稳定,这对生命蓝图的稳定非常重要。

从计算的角度来看,你只需要一条链的序列来进行分析。

人类基因组计划是一个国际项目,旨在找出一个人的完整 DNA 序列——即读出一个人基因组中所有 30 亿个 A、T、C 和 G 字母。人类基因组计划花费了 27 亿美元。如今,花少几个数量级的钱获得完整的基因组序列是可能的——例如,你可以花 299 美元通过 Nebula Genomics 获得你的整个基因组序列。

基因组学

基因组学是对人类、动物、细菌等的 DNA 序列的研究。为了了解健康和疾病,基因组经常被相互比较。

例如:

  • 可以比较健康人和病人的基因组,以了解影响疾病风险或直接导致疾病的基因(例如参见“全基因组关联研究”)。
  • 许多人的基因组可以进行比较,以了解与疾病无关的基因组中的自然变异——例如,影响头发颜色、眼睛颜色、身高和其他特征的基因。
  • 为了重建生命树和理解进化史,可以比较人和动物的基因组。

基因的异同

这个星球上任何随机选择的男人和这个星球上任何随机选择的女人有 99.9%的基因相同。

例如,竹井乔治奥普拉·温弗瑞有 99.9%的基因相同

黑猩猩和人类总体上有 96%的基因相同(在编码区域有 98%的基因相同):

两个人。

狗和狼有 99.9%的相似性,事实上它们在基因上是如此相似,以至于从技术上来说它们是同一物种:

狼的形象来自维基百科;吉娃娃图片来自维基百科

因此,大部分基因组学是关于识别导致差异的微小基因组部分(狗是一个特别有趣的研究物种,因为它们在大小、颜色、行为、寿命和疾病风险方面有很大差异)。基因组学可能是“大海捞针”,特别是在比较不同的人类基因组以了解疾病风险时,因为任何给定的两对人类几乎都是相同的。

各种基因组数据

假设一个人的 DNA 序列可以存储大约 750 兆字节。然而,在现实中,DNA 测序的过程并不完美,它不是从开始到结束获得完整基因组的一个完美读数,而是产生许多部分读数,这些读数必须像拼图一样组装在一起。例如,假设给你以下句子片段:

  • “鸟儿飞了进来”
  • 《天空中的苍蝇》
  • “在天空中歌唱”

把这些句子对齐叠加起来,就可以重构出“小鸟在天空中飞翔歌唱”这句话了。

因为 DNA 是以这种方式测序的,所以直接从测序机器上得到的原始 DNA 序列大约是 200 千兆字节,并且在分析之前必须被“清除”。想了解更多信息,你可以看看这篇文章。

到目前为止,我们只是在谈论获得完整的基因组序列,这被称为“全基因组测序”也可以用其他种类的基因组测量进行基因组研究:

  • 全外显子组测序(“WES”):在这项技术中,只有基因组的编码部分(编码蛋白质的部分)被测序。
  • SNP 基因分型:在这项技术中,只测量已知重要位置的单个字母。“SNP”是“单核苷酸多态性”:单一,因为它只有一个位置(例如“4,576,877 位”),核苷酸,因为 DNA 的构件是核苷酸,并且在该位置有一个核苷酸(A、T、C 或 G),以及多态性,因为这些是被考虑的特殊位置,已知它们在群体中是变化的(即它们是“多态性的”)。在一个 SNP 上有某些核苷酸而不是其他核苷酸会导致戏剧性的后果。例如,镰状细胞贫血症这种疾病可以由单个核苷酸的改变引起。

RNA &转录

像 DNA 一样,RNA 是一种核酸——具体来说,是核糖核酸。

DNA 和 RNA 的比较:

  • DNA 由 A、T、C 和 g 组成。RNA 由 A、U、C 和 g 组成。因此,RNA 含有 U(尿嘧啶)而不是 T(胸腺嘧啶)。
  • DNA 是双链的。RNA 是单链的。
  • DNA 是用来稳定、长期储存制造生物所需的所有信息的。RNA 被用作临时模板来帮助制造蛋白质。

这是可以从人类基因 S100A10 中提取的 RNA 序列:

AAUCAAAGAACCCGGCCGUCCUGCCGGUGGGGCACGUGGCGCAGAACCAGAGGUAACCGGUUUAGGGCAUCCCACCCUGAGCCUGCCCUUCCUCUCGGGUUUGGUUUUAGAAAGUGUACAGCCCCAGACAGAGCGUUCUUGUAAACUUCUCUUCAGUAGAAACGGUCCUGCUCUCGAAUACCGGGCGCGCGGCCCACGCCCUGCCCUCGCUCCCGGACCCGCCUCGCAGAGCGCUCGCCCGGCAGGGCGCUCCCCCAGCCCUGUCUCCUCCCCCUCUUCCUGCCCCCGACUCCCCCGACCACGUGCGGCGGGUGGGUAGAGGGAGGCGGUGCGGGACGGGGAGGAGCCUGGCGGGCGCUCGUGGGCGACGUGGACGCGGGGCGGAGAGGCGAGCGCGGCGGGCUGUGCGCCUUCCUUAGUGGGCCGAACUGGGAGCUCACCUUGGCCGAGGCGCGGCGGACGCUGGGCGAGCUGGGCGAC

[使用arep.med.harvard.edu计算]

RNA 被用作构建蛋白质的模板。首先,一段 RNA 是基于 DNA 中的一个基因构建的。从 DNA 上制造 RNA 的过程被称为“转录”,因为 RNA 是从 DNA 上“转录”下来的,利用了前面讨论的配对规则(除了这次不是 DNA 链-DNA 链配对来形成双螺旋,而是 D NA 链-RNA 链配对来制造 RNA 模板):

  • RNA C 与 DNA G 配对
  • RNA G 与 DNA C 配对
  • RNA U 与 DNA A 配对
  • RNA A 与 DNA T 配对

接下来,这段 RNA 被用来制造蛋白质,这个过程被称为“翻译”,因为 RNA 的核苷酸构件被“翻译”成蛋白质的氨基酸构件:

转录组学

“转录组学”是对 RNA 序列的研究。转录组学很有趣,因为它告诉我们在身体的不同部位什么基因被“开启”。

让我们回到 DNA 序列作为指导手册的类比:

回想一下,橙色和蓝色文本分别包含构建“机器 Z”和“机器 B”的指令(代表两个基因,它们提供构建蛋白质 Z 和蛋白质 B 的指令)。

现在,假设我们每次要向工厂的一个房间添加新的机器 Z 时,都必须为“机器 Z”影印页面—也许我们正在将机器 Z 指令的影印页面交给某个要去构建机器 Z 的工人。如果我们为“机器 Z”影印页面总共 25 次, 然后有人溜进工厂的房间,计算机器 Z 页的复印总数,就可以推断出在工厂的那个特定房间里,我们需要 25 台机器 Z。

这样,通过统计工厂某个房间(身体部位)的影印(RNA 转录物)数量,我们就可以推断出工厂那个部位使用最多的是哪些机器(蛋白质)。

身体是由组织构成的——比如肌肉是一种组织,神经细胞是另一种组织。这是来自 genevisible 的图表,显示了 S100A10 基因“表达”的前 10 个组织——换句话说,S100A10 基因在这些组织中最频繁地被转录成 RNA:

从图表中我们可以看到,S100A10 基因在身体的某些部位比其他部位使用得更多。“表达”只是从 DNA 中提取一段 RNA 的另一种说法。当一个基因被用来制作 RNA 模板时,我们说这个基因被“表达”了。短语“测量基因表达”指的是检测特定目的基因制造 RNA 的程度。换句话说,“测量基因表达”与“测量转录组”相同。

蛋白质&翻译

到目前为止,我们已经讨论了 DNA 是如何变成 RNA 的。现在我们将讨论 RNA 的用途:作为制造蛋白质的模板。

蛋白质是在体内执行不同工作的小机器。我不会轻易使用“机器”这个词——蛋白质确实是分子机器。下面是一个动画,展示了马达蛋白质驱动蛋白沿着微管(一种微观支撑结构,像建筑物中的木梁)拖动囊泡(一种微观存储容器,像背包):

GIF 来源

蛋白质是由氨基酸组成的。在人类中,有 20 种氨基酸可以作为蛋白质的组成部分。

以下是用于制造人体蛋白质的 20 种氨基酸,以及它们的单字母和三字母缩写:

  • G —甘氨酸
  • 脯氨酸(Pro)
  • ——丙氨酸
  • V —缬氨酸(Val)
  • L —亮氨酸
  • I —异亮氨酸(Ile)
  • M —蛋氨酸(Met)
  • C —半胱氨酸
  • F —苯丙氨酸
  • Y —酪氨酸
  • W —色氨酸
  • H —组氨酸(His)
  • K —赖氨酸
  • R —精氨酸
  • —谷氨酰胺(Gln)
  • N —天冬酰胺(Asn)
  • E —谷氨酸
  • D —天冬氨酸(Asp)
  • S —丝氨酸
  • T —苏氨酸

回到我们的 S100A10 的例子,这是最终由基因 S100A10 产生的蛋白质的完整蛋白质序列:

MPSQMEHAMETMMFTFHKFAGDKGYLTKEDLRVLMEKEFPGFLENQKDPLAVDKIMKDLD QCRDGKVGFQSFFSLIAGLTIACNDYFVVHMKQKGKK

【序列来源:uniprot.org

提醒:

  • 当你读出一个蛋白质序列时,“G”代表氨基酸“甘氨酸”,但当你读出一个 DNA 序列时,“G”代表核苷酸“鸟嘌呤”。
  • 类似地,“C”在蛋白质序列中代表“半胱氨酸”,但在 DNA 序列中代表“胞嘧啶”,
  • “T”代表蛋白质序列中的“苏氨酸”,但代表 DNA 序列中的“胸腺嘧啶”,
  • “A”在蛋白质序列中代表“丙氨酸”,但在 DNA 序列中代表“腺嘌呤”。
  • 幸运的是,你可以很快分辨出一个序列是蛋白质还是 DNA,因为蛋白质序列将包含比 ATCG 更多的字母。

尽管氨基酸和核苷酸的名字听起来很相似,但它们之间有很大的不同,具有不同的分子结构。这是 20 种氨基酸的示意图(其中 O 是氧,H 是氢,N 是氮,不带字母的角是碳):

来源:维基百科

蛋白质是用一段 RNA 作为模板制成的。RNA 模板规定了应该用什么样的氨基酸来制造蛋白质。

你可能会问,如果 RNA 只由 4 种核苷酸组成,怎么可能为由 20 种不同氨基酸组成的蛋白质指定指令?如果核苷酸和氨基酸之间有一对一的映射,那么我们只能编码 4 种不同的氨基酸。如果核苷酸和氨基酸之间存在二对一的映射,那么我们只能使用这些 2 元核苷酸编码来编码 4 x 4 = 16 种不同的氨基酸:

因为两个仍然不够,身体用 3 个核苷酸来表示一个氨基酸。使用 3 个氨基酸提供了 4×4×4 = 64 种可能性,这足以编码 20 种可用的氨基酸(留下一些三联体来编码“开始”和“停止”)。3 个氨基酸的组合被称为“三联体”或“密码子在“翻译”(从 RNA 制造蛋白质)的过程中,身体以三个字母为单位读取 RNA,一次产生一个氨基酸。

“打破遗传密码”发生在 1966 年,指的是通过实验确定哪些氨基酸对应于哪些核苷酸三联体的艰苦努力的结果。

这是遗传密码,显示了从 RNA 三联体(如“UUU”)到氨基酸(如“苯丙氨酸”)的映射:

遗传密码。CC 乘 3.0

序列“AUG”(标记为红色)既作为“起始”指示(“起始密码子”)又作为氨基酸甲硫氨酸(Met)的编码。序列“UAA”、“UAG”和“UGA”都代表“停止”剩下的三个字母代码都表示特定的氨基酸。从图中可以看出,遗传密码是多余的,即有多种方式编码同一种氨基酸。

这是我们的图表,包括所有的部分:DNA、RNA 和蛋白质。

注意,标记为“基因”的 DNA 序列具有序列 CGCCAT,根据前面描述的配对规则,它对应于所示的 RNA 序列:GCGGUA。然后,使用遗传密码表,我们可以看到,RNA 中的 GCG 对应的是氨基酸丙氨酸(Ala),而 RNA 中的 GUA 对应的是氨基酸缬氨酸(Val)。(为了简单起见,我在图中省略了“开始”和“停止”密码子)。

快速补充一下的实际大小:真正的基因比图片中显示的 6 个核苷酸要大得多。平均蛋白质编码基因由 53,600 个核苷酸组成(也写作“53.6 kb”,其中 kb =千碱基;53.6 x 1,000 个碱基)。最大的基因是 2.4 兆碱基(dystrophin),正如你所想象的,它编码了一段真正巨大的 RNA,最终是一段真正巨大的蛋白质。

可视化蛋白质

有许多方法可以看到一个给定基因最终产生的蛋白质。蛋白质是以氨基酸序列的形式产生的,但它们最终会折叠成对其功能非常重要的三维结构。确定蛋白质的三维结构需要大量的工作,确定蛋白质的功能也需要大量的工作。x 射线晶体学是一种可以用来确定蛋白质三维结构的技术。还有一个大的计算研究领域专注于预测仅给定其序列的蛋白质的 3D 结构(这是一个非常困难的问题)。

这是几个由 S100A10 基因产生的蛋白质的图像,来自瑞士模型。如果你想以一种互动的 3D 方式移动这些渲染图,你可以在这里这样做

首先,这是 S100A10 蛋白的“球和棒”渲染,其中每个原子是一个球,原子之间的连接是棒:

这是一个“空间填充”渲染:

下面是一个“表面”渲染:

最后,这是一幅卡通渲染图(螺旋是一种抽象的非文字形式的 3D 主题,称为“阿尔法螺旋”,在许多蛋白质中可见):

蛋白质组学

你可能已经猜到了,蛋白质组学指的是对蛋白质的大规模研究。你可能会奇怪,如果我们有基因组学(了解构建身体的所有指令)和转录组学(了解身体的哪些部分需要哪些机器),为什么还会有人想研究蛋白质组学。

事实证明,转录组学并不能完美地代表身体的哪个部位需要什么样的机器,因为 RNA 并不能以 1:1 的比例合成蛋白质。换句话说,你不能仅仅统计基因 A 产生的 RNA 片段的数量就得出结论,因为基因 A 有 100 个 RNA 片段,这意味着产生了 100 个版本的蛋白质 A。有时候,RNA 根本没有被制成蛋白质。有时,某一段 RNA 被用来制造许多蛋白质,而其他时候,一段 RNA 只被用来制造少数蛋白质。因此,蛋白质组学提供了一种更直接的方法来评估特定身体部位的机器总数。

通过结合基因组学、转录组学和蛋白质组学的分析,我们可以更全面地了解生物的健康状况和功能。

细胞的内部生命

最后,我强烈推荐观看 YouTube 视频“细胞的内部生活”它描绘了我们在这篇文章中谈到的许多过程,是对我们所有人体内分子机制的惊人和生物学上准确的描述。

总结

  • DNA 是生命的蓝图。人体内的 30 亿个 DNA 字母包含了构建身体的所有指令。
  • 基因组学是对大规模 DNA 序列的研究。
  • 转录是用 DNA 制造 RNA 模板的过程。
  • 翻译是使用 RNA 模板制造蛋白质的过程。
  • 转录组学是对 RNA 序列的大规模研究。
  • 蛋白质是在体内执行不同功能的分子机器。
  • 蛋白质组学是对大规模蛋白质的研究。

原载于 2020 年 4 月 11 日 http://glassboxmedicine.com**

利用 Spotify 的音频分析对电子舞曲进行流派分类

原文:https://towardsdatascience.com/genre-classification-of-electronic-dance-music-using-spotifys-audio-analysis-7350cac7daf0?source=collection_archive---------6-----------------------

使用机器学习深入研究 EDM

Aditya Chinchure 在 Unsplash 上拍摄的照片

介绍

电子舞曲有一个史诗般的起源故事。它始于 DJ 用鼓机给迪斯科唱片配音,并在非法的仓库派对上播放。我们今天所知的 EDM 已经发展成为一个价值 7 . 5 亿美元的庞大产业。随着受欢迎程度的提高,越来越多的听众将会接触到他们从未听过的流派和子流派。

随着 Spotify 等流媒体服务使用机器学习算法推出个性化歌曲推荐,发现新音乐也变得前所未有的简单。作为一名听众,第一次听到一首歌并沉浸在一种新的风格中是最令人愉快的部分。发现自己在一个有趣的兔子洞,异想天开地添加越来越多的歌曲到您保存的歌曲。可能会导致 Spotify 图书馆混乱无序。

该项目探索了机器学习算法的应用,使用 Spotify 的音频分析对给定歌曲的流派进行识别和分类。允许用户按流派自动组织他们的图书馆。

这个项目的所有代码可以在这里找到:【https://github.com/towenwolf/genre-classification

数据集

包含 7 个独特的电子舞曲类别的 21,000 首歌曲的音频分析:tech house,techno,trance,psy-trance,trap,drum & bass 和 hardstyle。这些歌曲是从 136 个用户创建的播放列表中收集来的,来自可靠的来源,如经过验证的唱片公司和官方 Spotify 播放列表。

为了获得数据集,我在 python 上编写了一个脚本,从 Spotify 的开发者应用程序获取凭证,读取播放列表的 csv 文件,检索播放列表中每首歌曲的音频特征,并创建一个按流派标记的歌曲数据框。该脚本还删除了任何重复的,低于 50 bpm 的低节奏歌曲,以及超过 16 分钟的歌曲。最终的数据集随机抽取了每个类别的 3000 首歌曲进行分析。

数据帧的每一行代表一首歌曲,列是歌曲的音频特征测量:

声学 —一首歌曲是纯声学的还是合成的概率。歌曲的录音将具有接近 1 的值。

乐器性 —一首歌不含人声的概率。纯器乐歌曲的值会更接近 1。

语音度 —一首歌只包含语音的概率。朗读单词轨道和声乐简介的值将接近 1。

可跳性 —一首歌的可跳性从 0 到 1 不等。

活跃度 —检测录像中是否有观众,范围从 0 到 1。

——一首歌的意境。听起来快乐的歌曲值接近 1,听起来悲伤的歌曲值接近 0。

能量 —强度和活动的感知度量。高能轨道感觉起来很快,很响,很嘈杂,接近 1。

Key —估计的轨道整体 Key。

响度 —音轨的整体响度,单位为分贝(dB)。

Mode —表示一个音轨的模态(大调或小调),大调用 1 表示,小调为 0。

速度 —轨道的总体估计速度,单位为每分钟节拍数(BPM)。

拍号 —一个音轨的估计整体拍号。

持续时间 —音轨的持续时间,单位为毫秒(ms)。

获取 _ 数据笔记本

使用 Spotify 的 API 来构建数据集而不是分析原始音频的优点是节省时间和计算能力,尤其是在大型数据集的情况下。要了解如何使用 Spotify 的 API,请查看这篇文章。

探索性数据分析

为了找到有助于按流派对歌曲进行分类的特征,我们应该听听它们之间的差异……一些歌曲比其他的快/慢吗?因为我们没有时间去听数据集中的每一首歌。让我们通过查看每种风格的速度分布直方图来直观地检查差异。

图 1:歌曲速度

我们看到一些节奏较低的歌曲,特别是陷阱、鼓和贝斯以及硬派风格的歌曲。我怀疑音频分析返回的是半场节奏,而不是全程节奏。这不是问题,考虑到中场休息在音乐上是正确的。只是换个角度看每分钟打多少拍,只数第一和第三个四分音符而不是一、二、三、四。比如一首 140 bpm 的歌,半场就 70 bpm 了,这对于某些流派来说很常见。为了解决这个问题,我编写了一个函数,将任何作为半场时间返回的速度更改为全时时间,以保持数据的一致性。

当使用用户创建的播放列表时,我们遇到的另一个潜在问题是将不属于该流派的歌曲添加到播放列表中,导致错误标记的观察。例如,用户可能错误地将一首说唱歌曲放在了家庭播放列表中。查看技术宅节奏的描述统计,我们可以看到最小值和最大值远远高于和低于平均值。

techhouse
count    3509.000000
mean      124.917453
std         2.845667
min        95.075000
25%       123.995000
50%       124.995000
75%       125.998000
max       217.009000

这些远离平均节奏的数据点告诉我们,它们实际上并不属于科技流派。如果我们像这样给算法错误标记的观察值,它会导致分类器正确预测的问题。因此,为了解决这个问题,我根据阿贝尔顿的音乐制作章节中关于节奏的内容,用流派的已知节奏为数据设置了一个阈值。

类型的速度范围

  • 配音:60-90 BPM
  • 嘻哈音乐:60-100 次/分钟
  • 房价:每分钟 115 至 130 美元
  • 技术/催眠:120-140 次/分钟
  • dubstep:135–145 BPM
  • 鼓和贝斯:160–180 BPM

图 2:调整半场/用户错误后的歌曲速度

图 3:按流派的节奏统计

在对用户的错误进行调整并将半拍节奏改为全拍节奏后,流派节奏的分布显示出围绕其均值和等方差的单峰结构。从统计学上讲,数据具有这些特征是很重要的,因为许多算法使用假设正态性的线性模型。这意味着在预测一首歌曲的风格时,节奏会有很大的分量。

现在,除了速度,还有什么其他音频分析功能可以帮助预测正确的流派?

图 4–15:音频分析特征直方图

如果你看一下可跳舞性的直方图(图 7),我们会发现技术宅和电子乐平均来说比所有其他流派更“适合跳舞”。这并不奇怪,豪斯和泰克诺以他们的高帽和掌声让舞者们点头而闻名。数据的结构是正常的,并且类型的平均值彼此不同,表明这将是另一个有助于分类的特征。

观察歌曲整体响度的差异(图 12)也给了我们一些对流派差异的洞察。陷阱,鼓&低音和 hardstyle 都是以非常高的分贝录制的,揭示了这些流派在扬声器上可以输出的强度和力量。听这些流派的时候不要把耳机开得太大。

歌曲的持续时间(图 15)也在它可能属于的流派中起作用。Psy-trance 和 techno 歌曲比其他类型的歌曲长得多,75%以上的数据在每首 6-15 分钟之间。

不适合分析的突出特征是调、调式和拍号,这些都是与歌曲的音乐性相关的分类特征。它们可能在以后的分析中有用,但对于本项目,它们将从要素选择中移除。

训练机器学习分类器

为了训练分类模型,我们需要将数据分成特征和标签。使用来自 sklearn 的标签编码器对类型标签进行编码。

X = data[features].copy()
y = LabelEncoder().fit_transform(data[‘genre’])

列车测试分离

然后使用 sklearn 的 train_test_split 将数据分成训练集和验证集,随机将数据分成 80/20%的块,用于训练和验证分类器。

X_train, X_test = train_test_split(X, test_size=0.2, random_state=98)
y_train, y_test = train_test_split(y, test_size=0.2, random_state=98)

数据预处理

使用 sklearn 的 MinMaxScaler,所有的特征将被转换为 0 到 1 之间的相同比例。

scaler = MinMaxScaler()
scaler.fit(X_train)X_train = pd.DataFrame(scaler.transform(X_train), columns = X.columns)
X_test = pd.DataFrame(scaler.transform(X_test), columns = X.columns)

分类器

既然数据准备好了,分类器就要被训练并预测每种类型的概率。分类器是一种算法或“机器”,它使用统计数据来输出一个数学模型,该模型与我们输入的数据相匹配。允许我们预测有用的东西,比如一首歌是什么类型的!在本文中,我们不打算深入研究每一种算法的数学原理,但会提供一个简短的解释,说明是什么使这些分类算法成为这个用例的候选算法。

逻辑回归

是一个线性数学模型,通常用于二元分类。在这种情况下,我们有 7 个类别,并将实施 One vs Rest 方法,该方法将训练 7 个单独的模型,概率最高的一个将是预测的类别。

# Train logistic regression model
logreg = LogisticRegression(penalty='l2', max_iter=10000, multi_class='ovr')
logreg.fit(X_train, y_train)# Probabilities of each genre
logreg_probs = logreg.predict_proba(X_test)

随机森林

是适合许多决策树分类器的集成分类器。使用 sklearn 的 GridSearchCV 找到了最佳参数。

# Train random forest model with optimal parameters
rf = RandomForestClassifier(max_depth=25, min_samples_leaf=1, min_samples_split=5, n_estimators=1200)
rf.fit(X_train, y_train)# Probabilities of each genre 
rf_probs = rf.predict_proba(X_test)

XGBoost

Boosting 是另一种通过组合多个弱学习器(如决策树)获得的集成分类器。使用 sklearn 的 GridSearchCV 找到了最佳参数。

# Train model with optimal parameters
xgb = XGBClassifier(max_depth=5, learning_rate=0.1, objective='multi:softprob', n_estimators=500, sub_sample = 0.8, num_class = len(genres))
xgb.fit(X_train, y_train)# Probabilities of each genre
xgb_probs = xgb.predict_proba(X_test)

SVM

经典的分类算法,常用于二元分类。就像逻辑回归一样,将使用一对其余的方法。

# Train model with optimal parameters
svm = SVC(gamma='auto', probability=True)
svm.fit(X_train, y_train)# Probabilities of each genre
svm_probs = svm.predict_proba(X_test)

评估分类模型

逻辑回归

准确率:84%

F1 得分:0.84

ROC AUC: 0.974

墙壁时间:543 毫秒

对于一个简单的分类器来说还不错,预测最正确的类型是技术宅和 psy-trance。

随机森林

准确率:93%

F1 得分:0.93

ROC AUC: 0.994

挂壁时间:40.6 秒

随机森林的表现明显更好。建议决策树分类器是使用该数据进行分类的好方法。

XGBoost

准确率:93%

F1 得分:0.93

ROC AUC: 0.994

挂壁时间:52.2 秒

得分几乎与 random forest 完全相同,只是在预测上有微小的变化。预测的准确性有一个清晰的结构。

支持向量机

准确率:88%

F1 得分:0.88

ROC AUC: 0.986

挂壁时间:16.1 秒

除了电子音乐和硬派音乐之外,大多数音乐类型都有相对较高的准确度。错误地预测了两者的关系。

受试者工作特征曲线

评估分类器算法性能的另一种方法。说明了特异性和敏感性的权衡,曲线下面积越大,预测越准确。

图 20:分类器的 ROC 曲线

XGBoost 和 Random forest 算法在预测歌曲类型方面表现最佳。在对技术宅进行分类时,所有算法都表现良好,在所有分类器上都具有近乎完美的准确性。一些 techno 的例子经常与 hardstyle 混淆,反之亦然,也是 psy-trance 的陷阱。这表明这些流派之间的差异可能比音频特征能够检测到的更微妙。

讨论

Random Forest 和 XGBoost 的性能在大规模自动分类流派的能力方面都很有前途。能够根据音频分析的特征来确定一首歌曲的流派,可以帮助听众组织他们的图书馆或推荐类似的歌曲。

但最终,真正让每种音乐风格独一无二的是它在聆听时激发的感觉和情感。自己听一听,这里有分析中使用的 Spotify 播放列表的链接。

接下来,我想找到算法有效分类一个流派的最少歌曲数量。这样一来,流派数量的规模就可以包括大量的小众流派。如果某个流派有足够多的播放列表,那么分类器甚至能够预测最狂野的流派,比如俄罗斯波尔卡硬核音乐(见下文)。所以,走出去,做一些你最喜欢的类型的公共播放列表。

Gif 由 Ohmagif.com 的未知

参考

[## 使用机器学习技术的音乐流派分类

在音乐信息检索领域,根据音乐文件的类型对其进行分类是一项具有挑战性的任务

arxiv.org](https://arxiv.org/abs/1804.01149) [## 开始使用 Spotify 的 API & Spotipy

《数据科学家快速入门指南》,指导如何浏览 Spotify 的 Web API 并使用 Spotipy Python 访问数据…

medium.com](https://medium.com/@maxtingle/getting-started-with-spotifys-api-spotipy-197c3dc6353b) [## 节奏和风格

一首音乐的风格(或流派)是由许多因素决定的,包括声音的类型和…

learningmusic.ableton.com](https://learningmusic.ableton.com/make-beats/tempo-and-genre.html) [## 欢迎来到 Spotipy!- spotipy 2.0 文档

Spotipy 是 Spotify Web API 的轻量级 Python 库。有了 Spotipy,您可以完全访问所有音乐…

spotipy.readthedocs.io](https://spotipy.readthedocs.io/en/2.9.0/) [## 制作自己的 Spotify Discover 每周播放列表

每周一醒来我都很兴奋。在你认为我是那种喜欢每天去上课的怪人之前…

towardsdatascience.com](/making-your-own-discover-weekly-f1ac7546fedb) [## Spotipy:如何从一个播放列表中读取超过 100 首曲目

感谢贡献一个堆栈溢出的答案!请务必回答问题。提供详细信息并分享…

stackoverflow.com](https://stackoverflow.com/questions/39086287/spotipy-how-to-read-more-than-100-tracks-from-a-playlist)

使用 Bandcamp 歌词的流派特征选择

原文:https://towardsdatascience.com/genre-feature-selection-using-bandcamp-lyrics-c61a3902c969?source=collection_archive---------94-----------------------

使用 Python 的 scikit-learn 和 langdetect 根据歌词关键字特征对音乐类型进行分类

照片由乔丹 N 圣约翰市中心

歌词通常根据其对应的音乐流派具有共同的关键词和短语。例如,民间音乐经常反映自然和朴实的主题,而朋克音乐反映个性和自由。

我最近一直在为最近发布的搜集 Bandcamp,这时我意识到我有了一个不错的数据集来根据流派进行文本分类。下面是如何处理数据的框图。

数据集大小超过 7500 首歌曲,涵盖 16 个流派,使用 BeautifulSoup4 web scraper 生成。请注意,这些歌曲来自加拿大的位置,所以许多(1000+)不得不删除,因为他们的法语内容。我使用 python langdetect 库来检测每首歌对应的语言。数据集也不是平均分布在各个流派中,但是这个项目的目的不是分类,而是简单的特征检索。具有较少数据点的类型在最终结果中被忽略。

为了执行文本分类,我使用了 scikit-learn 的 TF-IDF(术语频率逆文档频率)特征提取器以及 chi2 特征选择器,这是根据一个类似的项目这里TF-IDF 变换强调更罕见但更有趣的术语,而 chi2 特征选择器试图忽略“过于罕见”且与分类无关的术语。常见的停用词如“the”和“but”从该分类中移除,以生成更有意义的特征。最相关的单字(单个词)的最终无序结果如下所示。

虽然原声音乐和民间音乐有更健康的常用词,如“领域”和“价值”,但像嘻哈和朋克这样的流派有更多的世俗语言。我喜欢电子和 r&b 使用含糊不清的语言,而实验真的不知道它在做什么。

我可以创建一个分类器,但我认为我的数据集不够大。我知道 Genius API 相对容易使用,我可以从中获得更多的歌词,但那是以后的事了。感谢阅读:)

产生这些数据的加拿大音乐数据库可以在这里找到。当前代码在这里可用,存储库在这里可用。

卡方独立性检验简介

原文:https://towardsdatascience.com/gentle-introduction-to-chi-square-test-for-independence-7182a7414a95?source=collection_archive---------5-----------------------

统计数字

使用 Jupyter 笔记本的卡方初学者指南

卢克·切瑟Unsplash 上拍摄的照片

**Table of contents**[**Introduction**](#6a58) 1\. [Prerequisite](#19e2)
 2\. [SciPy package](#9b64)
 3\. [Setup](#b9f9)
 4\. [Python indexing](#794a)
 5\. [chi2_contingency](#92ef)
 6\. [Expected values](#77b7)
 7\. [𝜒2 value](#e764)
 8\. [Side note about Latex](#8a58)
 9\. [p-value](#bebc)
10\. [Degree of freedom](#72ba)
11\. [Importing data](#c195)
12\. [Pandas.DataFrame.transpose()](#53f4)
13\. [Critical values](#41b8)
14\. [The null and alternative hypotheses](#56a0)[**Conclusion**](#56b6)

介绍

独立性的卡方检验也称为皮尔逊卡方检验。卡方独立性检验用于科学、经济、营销或其他各种领域。有三种方法可以使用卡方。独立性卡方检验显示了两组数据是如何相互独立的。拟合优度检验的卡方显示了您的数据与期望值的差异。同质性测试确定两个或更多人口是否具有单一分类变量的相同分布。

在本文中,我们将使用 Jupyter 笔记本探索独立性的卡方检验。哦,顺便说一下,我们把 chi 发音为 kai,就像 kite 一样,而不是 Chili 中的 Chi。𝜒是希腊字母“Chi ”,所以𝜒2 读卡方。

先决条件

即使这篇文章是针对几乎没有编码经验的初学者,阅读的《Jupyter 笔记本入门指南》会帮助你如何入门。

[## Jupyter 笔记本初学者指南

从设置到描述性统计

towardsdatascience.com](/beginners-guide-to-jupyter-notebook-8bb85b85085)

SciPy 包

为了找到卡方,我们将使用 SciPy 包。SciPy 是一个基于 Python 的数学、科学和工程开源软件。[scipy.stats.chi2_contingency](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.chi2_contingency.html)是独立性卡方检验的有用工具。还有一个叫做[scipy.stats.chisquare](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.chisquare.html?highlight=stats%20chisquare#scipy.stats.chisquare)的,用于卡方拟合优度检验。

设置

启动 Anaconda,启动 Jupyter 笔记本

通过单击新建> Python 3 创建一个文件。

将文件重命名为“卡方独立性检验”。

在第一个单元格中,我们将导入 chi2_contingency、pandas 和 numpy 库。

from scipy.stats import chi2_contingency
import pandas as pd
import numpy as np

在 Jupyter 笔记本中运行代码时,按 SHIFT + RETURN。

我们将创建样本数据。假设我们收集了男女最喜欢的 t 恤颜色的数据。我们想弄清楚肤色和性别是否独立。我们使用 Pandas 数据帧创建一个小样本数据,并将我们的数据存储在一个名为tshirts的变量中。

熊猫indexcolumns用于命名行和列。为了打印我们的tshirts变量中的内容,我们只需在最后写下tshirts,并输入 SHIFT + RETURN。

tshirts = pd.DataFrame(
    [
        [48,22,33,47],
        [35,36,42,27]
    ],
    index=["Male","Female"],
    columns=["Balck","White","Red","Blue"])
tshirts

您可以通过使用columns找到列中的标签。

tshirts.columns

同样,您可以使用index来找出什么是索引。

Python 索引

Python 使用从零开始的索引。这意味着,第一个元素的索引为 0,第二个元素的索引为 1,依此类推。如果您想访问chi2_contingency(tshirts)中的第四个值,您需要使用[3]

chi2 _ 偶然性

SciPy 的chi2_contingency()返回四个值, 𝜒 2 值,p 值,自由度和期望值。

chi2_contingency(tshirts)

期望值

您可以在返回值的第四行找到期望值。它是一个数组形式。让我们友好地打印期望值。我们再次使用熊猫数据框架。我们将添加索引和列值,并将这些值四舍五入到两位小数round(2).

df=chi2_contingency(tshirts)[3]pd.DataFrame(
    data=df[:,:], 
    index=["Male","Female"],
    columns=["Black","White","Red","Blue"]
).round(2)

上表称为列联表。您可以使用以下公式根据观察数据计算期望值。

𝜒2 值

你可以在chi2_contingency返回的第一个值中找到 𝜒 2 的值。但是你如何手动找到𝜒2 呢?卡方的公式是:

卡方公式

𝜒公式告诉我们,要找到实际值和期望值之差的平方,然后除以期望值。然后将所有这些加在一起,得出 𝜒 2 值。

卡方的手工计算

这就是chi2_contingency在幕后做的事情。由于 Python 是基于 0 的索引,为了打印出 𝜒 2,我们需要使用第一个值[0]

chisquare=chi2_contingency(tshirts)[0]
chisquare

关于乳胶的补充说明

我用 Latex,发音为‘lah-Teck’在 Jupyter 笔记本上写了上面的等式。您正在写的单元格必须是 Markdown,这是您需要在单元格中键入的内容。

\begin{equation}
\chi^2=\Sigma\frac{(O-E)^2}{E} \\
\text{where O is the actual value and E is the expected value.}
\end{equation}

p 值

您可以在返回值的第二个位置找到 p 值。p 值衡量当零假设为真时看到效果的概率。因此,当 p 值足够低时,我们拒绝零假设,并得出结论,观察到的效果成立。我们将在本文后面讨论零假设。

pvalue=chi2_contingency(tshirts)[1]
pvalue

自由度

你可以在第三个返回值中找到自由度。我们待会要用这个来求临界值。你为独立的 𝜒 2 找到自由度(dof)的方式与 𝜒 2 拟合优度不同。

争取 𝜒争取 2 独立:

例如,如果您的数据有 4 行 x 3 列,则自由度为:

对于 𝜒 2 拟合优度,分类数据有一维。自由度是:

在从chi2_contingency返回的值中,第三个是自由度。我们用第三个[2]。下面将输出 3。

dof=chi2_contingency(tshirts)[2]
dof

[## 斯皮尔曼等级相关系数的微妙性

单调关系的未知部分

towardsdatascience.com](/the-subtlety-of-spearmans-rank-correlation-coefficient-29478653bbb9)

导入数据

水平数据

通常,您希望从文件中导入数据。第一个 CSV 文件包含横向数据。通过使用pd.read_csv,数据自动转换为熊猫数据帧。

CSV 文件包含以下数据。

gender,Black,White,Red,Blue
Male,48,12,33,57
Female,35,46,42,27

让我们将数据存储到一个名为tshirtshor的变量中。我们添加index_col="gender"使性别列成为索引。

csvfile = '[https://raw.githubusercontent.com/shinokada/python-for-ib-diploma-mathematics/master/Data/tshirts-horizontal.csv'](https://raw.githubusercontent.com/shinokada/python-for-ib-diploma-mathematics/master/Data/tshirts-horizontal.csv')
tshirtshor = pd.read_csv(csvfile,index_col='gender')
tshirtshor

我们在tshirtshor上运行chi2_contingency

chi2_contingency(tshirtshor)

垂直数据

我们将使用垂直布局的数据。让我们将数据存储到一个名为tshirtsver的变量中。

csvfile2 = '[https://raw.githubusercontent.com/shinokada/python-for-ib-diploma-mathematics/master/Data/tshirts-vertical.csv'](https://raw.githubusercontent.com/shinokada/python-for-ib-diploma-mathematics/master/Data/tshirts-vertical.csv')
tshirtsver = pd.read_csv(csvfile2,index_col='Color')
tshirtsver

我们在tshirtsver上运行chi2_contingency。除了期望值之外,我们得到了和以前一样的值。

chi2_contingency(tshirtsver)

熊猫。DataFrame.transpose()

如果你更喜欢水平数据而不是垂直数据,你可以通过使用Pandas.DataFrame.transpose()或简称T将数据从垂直转置为水平。

tshirtsver.T

使用chi2_contingency()

chi2_contingency(tshirtsver.T)

[## 建模功能

从线性回归到逻辑回归

towardsdatascience.com](/modeling-functions-78704936477a)

临界值

显著性水平和自由度可用于寻找临界值。正如我之前提到的,你可以从数组中找到自由度。为了找到临界值,您需要从 scipy.state 导入 chi2,并从显著性、1%、5% 10%等级别定义概率。

from scipy.stats import chi2
significance = 0.01
p = 1 - significance
dof = chi2_contingency(tshirtshor)[2]
critical_value = chi2.ppf(p, dof)
critical_value

当自由度为 3 且显著性水平为 1%时,临界值约为 11.34。您可以使用 cdf 确认该值。下面将输出 0.99。

p = chi2.cdf(critical_value, dof)
p

无效假设和替代假设

卡方检验要求陈述原假设 H0 和替代假设 H1。零假设是指我们的两个变量是独立的。另一个假设是他们不是独立的。

subjects = pd.DataFrame(
    [
        [25,46,15],
        [15,44,15],
        [10,10,20]
    ],
    index=['Biology','Chemistry','Physics'],
    columns=['Math SL AA','Math SL AI','Math HL'])
subjects

如果计算的卡方大于临界值,我们拒绝零假设。

chi, pval, dof, exp = chi2_contingency(subjects)
print('p-value is: ', pval)
significance = 0.05
p = 1 - significance
critical_value = chi2.ppf(p, dof)print('chi=%.6f, critical value=%.6f\n' % (chi, critical_value))if chi > critical_value:
    print("""At %.2f level of significance, we reject the null hypotheses and accept H1\. 
They are not independent.""" % (significance))
else:
    print("""At %.2f level of significance, we accept the null hypotheses. 
They are independent.""" % (significance))

或者,我们可以比较 p 值和显著性水平。如果p-value < the level of significance,我们拒绝零假设。

chi, pval, dof, exp = chi2_contingency(subjects)
significance = 0.05print('p-value=%.6f, significance=%.2f\n' % (pval, significance))if pval < significance:
    print("""At %.2f level of significance, we reject the null hypotheses and accept H1\. 
They are not independent.""" % (significance))
else:
    print("""At %.2f level of significance, we accept the null hypotheses. 
They are independent.""" % (significance))

结论

在本文中,我使用 Jupyter 笔记本解释了卡方检验的基础知识。独立性卡方检验需要零假设和替代假设、期望值、卡方值、p 值、自由度和临界值。

通过 成为 会员,获得媒体上所有故事的访问权限。

请订阅。

参考

[## 用 Jupyter 笔记本探索正态分布

使用 scipy 和 matplotlib 的正态分布初学者指南

towardsdatascience.com](/exploring-normal-distribution-with-jupyter-notebook-3645ec2d83f8)

知识表征学习简介

原文:https://towardsdatascience.com/gentle-introduction-to-knowledge-representation-learning-1ee873830219?source=collection_archive---------41-----------------------

知识表示学习(KRL)主要关注学习知识图嵌入的过程,同时保持语义的相似性。事实证明,作为特征输入,这对于各种预测和图形分析任务非常有用[1,2,3]。我们将在以后的文章中进一步阐述具体的应用。现在我们将主要关注技术实现。

一般来说,KRL 系统包括三个部分(图 1)。知识图数据、将图解码成低维向量空间的实体/关系嵌入,以及第三,评分组件测量事实的似然性,以采用嵌入之间的语义相似性。这里,我们可以区分基于相似性的评分函数和基于距离的评分函数。

图 1:知识表示学习系统的三个主要组成部分

知识图谱

知识图(KG)以图中节点和边之间的互连形式表示知识(图 2)。它提供了从实体之间的关系中提取的事实的结构化表示。实体可以是现实世界的对象,也可以是抽象的概念,关系是连接两者的箭头。

图 2:更大的生物医学知识图表的一部分

Fromally 定义为三元组(头实体,关系,尾实体),设 E={e_1,…,e_n} 为所有实体(头和尾)的集合, R={r_1,…,r_m} 为知识图中所有关系的集合。这组实体和关系上的每个潜在三元组 x_ijk 可以用一个压缩在三维邻接张量中的二元随机变量 y_ijk= 0y_ijk = 1,来表示。

图 3:表示现有相互作用的邻接张量 E × R × E ∈ KG

实体/关系嵌入

在第一步中,我们通过实体的潜在特征嵌入三元组:对以下事实的一种可能解释是:是 V 病毒与在人类中迅速传播的流感家族有关。这种解释使用实体的潜在特征(例如,流感家族的一部分)来解释可观察到的事实。这个概念不太直观,因为它不能在数据中直接观察到。图 4 提供了一个简单的例子。这里,我们应用两个特征来代表每个实体。实体电晕的潜在特征表示 θ_i 可以表示为二维特征向量。注意,在实践中,特征维度大约为 200,并且不像这个例子,通常由潜在特征模型推断,这使得它们通常不可能被翻译或解释。关系潜在特征模型的基本直觉是,实体之间的关系可以从它们潜在特征的数学交互中得到解释。有多种可能的方法来模拟这些交互,也有多种方法可以从中推导出关系的存在,其中一些我们将在第二步中探讨。

图 4:每个实体节点的二维嵌入向量的例子。

评分组件

这里,想法是在向量空间中嵌入相似/连接的节点。在内部,该模型试图最大化任何三重∈ KGf(θ_h,θ_r,θ_t) 的得分,并最小化不在 KG 中的三重的得分。这个过程通过多个时期进行迭代,以共同学习图中所有节点/关系的嵌入。在神经链接预测模型中,这两个步骤都由多层神经网络组成,该网络由编码层(CNN 工作得非常好)和多个评分组件(大多数是完全连接的层)组成,以测量三元组的似然性。各个模型之间的主要区别在于它们对评分函数 f 的选择。根据使用的评分函数,模型可以大致分为两种主流,平移距离模型和语义匹配模型。基于距离的评分函数通过计算实体之间的距离来衡量事实的似然性,其中广泛使用具有 h + r ≈ t 关系的附加翻译。基于语义相似度的评分通过语义匹配来衡量事实的似然性,通常采用乘法公式,即 h⊤M_r ≈ t⊤,来转换表示空间中靠近尾部的头部实体。

图 5:基于翻译距离的评分(左)和基于语义相似性的评分函数(右)[4]

参考

  1. 曹绍圣,,许琼凯。Grarep:用全局结构信息学习图形表示。在 2015 年第 24 届 ACM 国际信息和知识管理会议的会议记录中,第 891-900 页。
  2. 阿迪蒂亚·格罗弗和朱尔·莱斯科维奇。node2vec:网络的可扩展特征学习。载于第 22 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集,第 855–864 页,2016 年。
  3. 布莱恩·佩罗齐、拉米·艾尔弗和史蒂文·斯基纳。深度行走:在线学习社会表征。载于第 20 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集,第 701–710 页,2014 年。
  4. 季,邵雄,等。知识图的研究综述:表示,获取和应用。arXiv 预印本 arXiv:2002.00388 (2020)。

将图形地理参考为图像

原文:https://towardsdatascience.com/geo-referencing-a-figure-as-an-image-fc5e77caa00b?source=collection_archive---------38-----------------------

从矢量数据创建静态背景图像,用作 Jupyter 笔记本中 MatLibPlot 图形的标准图层。

动机

最近,我开始从事一项新的研究项目,研究欧洲自然事件观测的模式。为了使协作更容易,我想与其他人分享我的笔记本,一起解决问题,并展示数据分析的结果。

目前,我正在使用[ GeoPandas 0.7.0 作为地理数据处理库,其中包括一组矢量文件。然而,该版本中仅包含美国县轮廓和世界国家,分辨率非常低(见下图)。标准数据可用于生成地图,甚至进行一些粗略的空间分析。

边界文件足以在世界范围内显示国家统计数据,也可以在区域级别使用。当范围缩小到国家级别(例如法国的轮廓)时,地图就不再那么有用了。在这种情况下,应该使用外部数据来创建图形,以捕捉所需的细节。

欧洲的名胜(使用 GeoPandas)

外部矢量数据可以有许多不同的“形状”和格式,包括 Shapefiles(最常用的、ArcInfo Coverage、E00 ArcInfo Interchange、空间数据库引擎(ArcSDE)、数字线图(DLG)、GeoJSON、AutoCAD DXF 和 Keyhole 标记语言(KML)等等。

格式的独特处理是不可避免的,每种数据类型都需要特定的方法来加载和可视化数据。这让我想到,也许可以简化背景图的创建和共享。

比如,如果项目中的每个人都以相同的风格和布局看着相同的图像/图形,会怎么样?

一张静态背景图!

这不是一个新概念,也不会在所有情况下都有用。尽管如此,我还是对探索创造一种方法的可能性很感兴趣,这种方法:

  1. 标准化背景;这样我就可以专注于项目的其他方面,而不是为项目中的每个地块创建相同的布局(但略有不同)
  2. 简化了数据交换;shapefile 是最常使用和最容易得到的,使用 shape file 的缺点是它们不是作为一个单独的文件,而是作为一个集合使用(显示一个 shape file 需要最少 3 个文件,最多 7 个文件)。
  3. 减少磁盘空间;当在本地处理(shape)文件时,磁盘空间不是一个真正的问题,但是当将数据移动到(免费的)云计算环境(在这个例子中是 Google CoLab)时,磁盘空间可能会成为一个问题。背景光栅图像的传输大小只是其矢量图像的一小部分
  4. 减少图形创建/显示时间,同样取决于您的本地系统或云计算环境,这可能不是问题。但是,基于栅格的地图比基于矢量的地图生成速度快得多(主要是因为数据的分辨率,矢量比栅格有更多的计算“点”)。
  5. 是一个挑战。最后一点是个人的,是学习处理地理信息的新编码库的练习。

我相信这里概述的方法,并存储在链接的笔记本中,在将图像转换为地理标志并在另一个图形中重用信息方面做得相当不错。我很乐意分享这个笔记本,我希望代码对您有用,并且您可以在您的项目中测试它;我期待着评论中的反应和反馈。

一般说明

本文中的文本基于笔记本中的标记文本。我没有包括所有的代码(为了提高可读性),并且在某些地方的写作可能是技术性的(为了解释程序和提供一些背景信息)。

这个项目使用的所有数据都被压缩并存储在属于这个笔记本的 GitHub 文件夹中。要使用这个笔记本,要么运行在 Google Colab 中创建的将数据带到这个笔记本的代码,要么使用本地存储的数据在本地运行代码。

Google CoLab 笔记本链接:geo-referencing-a-figure-as-image . ipynb

数据链: 行政矢量数据

属国

这个笔记本背后的想法是创建一个可以在最少的依赖上运行的方法。有许多不同的方法和库可以处理地理数据和绘制地图。代码块中突出显示的是处理笔记本中地理数据的三个包。这些库是作为建议选择的,是完成本笔记本中的任务所必需的。还有其他包(例如 earthpy ipyleaflet 或 mpl_toolkits.basemap 等)同样适用于执行本文中描述的制图任务。

所选库:

# Data Science Packages
import numpy as np
import pandas as pd
import **geopandas** as gpd# Visualisation Package
import matplotlib.pyplot as plt
from matplotlib.backends.backend_agg import FigureCanvasAgg# Spatial Packages
import **gdal**, ogr, os, osr#Raster Packages
import **rasterio**
import rasterio.plot
from affine import Affine%matplotlib inline

装置

在下面的代码部分中,本程序中使用的所有库都被注释掉了。这是故意的,当所有的库都已经是最新的并且由用户在其他或先前的运行中安装时,笔记本敌人的加载更快(无需更新)。

#!pip install --upgrade numpy
#!pip install --upgrade pandas
#!pip install --upgrade geopandas
#!pip install --upgrade matplotlib
#!pip install --upgrade gdal
#!pip install --upgrade ogr
#!pip install --upgrade osr
#!pip install --upgrade rasterio
#!pip install --upgrade affine

使用的数据

本笔记本中的数据是开源的,与正在进行的项目或正在进行的研究无关。地图上显示的点(下图)是法国的主要城市,它们被选为示例位置,以显示对背景地图的操作是成功的。当使用其他数据运行代码时,可以对添加到图形中的点、线和多边形进行样式化(标记、格式化和显示)以最好地反映数据。如何格式化和可视化信息超出了本笔记本的范围。

#getting the data
url = 'https://github.com/GvdDool/
      Notebook-test/blob/master/Export.zip?raw=true'import requests, zipfile, io
#The copied URL goes here ->
r = requests.get(url) 
z = zipfile.ZipFile(io.BytesIO(r.content))
z.extractall("/AdministrativeData")

加载数据

本文/笔记本中突出显示的代码是出于显示比 GeoPandas 库中可用地图更详细的地图的需要而开发的。库中包含的矢量数据的质量足以创建大比例地图的小图形。但是,当放大到感兴趣的区域时,默认地图的质量不足以显示信息。

本笔记本中描述的方法是使用外部矢量数据创建自定义背景地图,并说明为法国所有国家收集的流程边界数据。对于法国,更高级别的行政边界(省)被添加到地图上,以在“感兴趣的区域”中给出更多细节。本项目的边界数据从http://www.diva-gis.org/gdata,获得,使用由https://gadm.org/提供的数据。点位置(城市)通过将 Diva-GIS 上列出的地名录数据与来自http://www.map-france.com/cities/的列表相结合而获得。

# Detailed map for France, with internal boundaries:
map_file_FR = "/AdministrativeData/Export/FRA_adm1.shp"# Detailed contry outlines
map_file_BEL = "/AdministrativeData/Export/BEL_adm0.shp"
map_file_NLD = "/AdministrativeData/Export/NLD_adm0.shp"
map_file_LUX = "/AdministrativeData/Export/LUX_adm0.shp"
map_file_DEU = "/AdministrativeData/Export/DEU_adm0.shp"
map_file_CHE = "/AdministrativeData/Export/CHE_adm0.shp"
map_file_ITA = "/AdministrativeData/Export/ITA_adm0.shp"
map_file_ESP = "/AdministrativeData/Export/ESP_adm0.shp"
map_file_GBR = "/AdministrativeData/Export/GBR_adm0.shp"
map_file_FRA = "/AdministrativeData/Export/FRA_adm0.shp"Code section <<Loading the Data>> not fully displayed

x/y 和纬度/经度之间的关系

使用地理数据和地图时,有必要对地图的投影(创建)方式有一个基本的了解。我在此仅强调地图定位术语的重要性:

  • 纬度值(lat)沿垂直轴(Y 轴,行)增加或减少。
  • 经度值(long)随着水平轴(X 轴)的变化而变化

本笔记本的其余部分将在绘制地图时使用“X/Y”作为坐标符号。查看输出中函数调用的打印输出,我们可以得出结论,原始投影和首选投影之间存在显著差异。

示例输出(针对法国范围):

从 EPSG 转换:4326 到 3395

另请注意,投影系统已发生变化,在本例中,原始数据(点和多边形)被投影到:

  • WGS 84/1984 年世界大地测量系统(EPSG:4326),并重新投影到
  • WGS 84 /世界墨卡托(EPSG:3395)

第一个投影系统用于 f.e. GPS 设备,可在全球范围内使用,单位为度(以及供应商定义的表示、小数位数)。后者更适合以欧洲为中心的世界地图,不包括极地地区。单位是米,主要用于南纬 80 度和北纬 84 度之间(https://epsg.io/)

表中的单位在 EPSG 是度:4326,在 EPSG 是米:3395。对于两个投影来说,零经度线都穿过格林威治,负左侧意味着法国从这条线以西开始。

创建示例地图

请注意,在本例中,(城市)点与下图一起显示和保存,以证明该方法正在返回所需的结果。该代码旨在不启用控制点的情况下运行。

# print(eea_FR.total_bounds)
# Expanding the area of interest to have a bit clearnace around the edges of the data
# Values are set to get an image which is almost square 
(~7.86 x7.86 // ~12.25x12.25)
# These values have to be set based on the area of interest and the projection:
('Map1 Width: ',  7.852  // Height:   7.877)
('Map2 Width: ', 12.245  // Height:  12.269)Code section <<Creating the Example maps>> not fully displayed

重新投影的结果

代码块下方的图像显示了矢量数据在原始投影系统和目标投影系统中的投影效果。

#Combining the two maps#figsize : (float, float), as width, height
#f, ax = plt.subplots(1, figsize=((maxx2 - minx2)/150000,(maxy2 - miny2)/150000))
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15,7.5))
fig.suptitle('Two map Projections', fontsize=20)
ax1.set_title('France in EPSG:4326 (Geodetic)', fontsize=15)
ax2.set_title('France in EPSG:3395 (Mercator)', fontsize=15)
ax1.set(xlim=(minx1, maxx1), ylim=(miny1, maxy1))
ax2.set(xlim=(minx2, maxx2), ylim=(miny2, maxy2))
ax1.set_axis_off()
ax2.set_axis_off()#plotting on the defined axis => ax1=ax1
eea_FR.plot(color='lightgrey', edgecolor='white', ax=ax1)
rdf.plot(facecolor='none', color='none', edgecolor='grey', ax=ax1)
eea_FRA.plot(facecolor='none', color='none', edgecolor='black', ax=ax1)#plotting on the defined axis => ax=ax2
eea_FR_rp.plot(color='lightgrey', edgecolor='white', ax=ax2)
rdf_rp.plot(facecolor='none', color='none', edgecolor='grey', ax=ax2)
eea_FRA_rp.plot(facecolor='none', color='none', edgecolor='black', ax=ax2)# In this example the points are on, and saved with the image, to prove that the 
# method is returnin the desired result.
# The code is intended to run without the contol points
geo_FR_df.plot(ax=ax1, facecolor='black', edgecolor='red')
points.plot(ax=ax2, facecolor='black', edgecolor='red')plt.savefig('FRA_map1.eps', dpi=1080, bbox_inches='tight')
plt.show()

地图投影的差异(EPSG: 4326 到 3395)

这是示例背景地图,法国为灰色,白色的省界,法国周围国家的边界设置为深灰色,没有填充。
当你用自己的数据运行这段代码时,布局可以根据你的个人喜好进行设置。我喜欢背景地图尽可能的中性,这样人们的注意力就会被吸引到地图的基本元素上,在这种情况下,就是法国的主要城市。

准备导出

代码的下一部分是准备格式化的图片,作为背景地图,以 GeoTIFF 格式保存。导出时使用 GeoTiff 格式的优势在于元数据信息嵌入在图像中。
在新图形中使用导出的 GeoTiff 时,元数据将用于重建背景图像,包括投影、像素大小和图形尺寸。

数据准备

背景图的数据可视化是不必要的,最终(右侧)图形在内存中处理。

Code section <<Data preparation>> not displayed, duplicating the earlier code block

转换数字

这是这个过程中最关键的一步,图形被转换成一个多维数组,存储像素的宽度和高度,以及颜色深度。有关该方法的详细信息,请点击下面的链接。

# MatPlotLib as another method to convert a Canvas to an Array:
# [https://matplotlib.org/3.1.1/gallery/](https://matplotlib.org/3.1.1/gallery/) 
     user_interfaces/canvasagg.htmlcanvas = FigureCanvasAgg(f)
# Save the figure to a string.
canvas.draw()
s, (width, height) = canvas.print_to_buffer()# Convert to a NumPy array.
X = np.frombuffer(s, np.uint8).reshape((height, width, 4))

转换数据数组

原始颜色存储在图像矩阵的最后一个维度中,作为具有四个属性的列表。在这个例子中,颜色被压缩为灰度值,因为创建的地图是具有中性色的背景地图。第四列用于 alpha(透明度),该列在本例中未使用,并设置为 0。当创建更复杂的背景地图时,可以使用第四个元素,但是有了这个地图,就不需要在多波段图像中存储原始值。

颜色转换功能:

Y = (0.2989 * (X[:,:,0])) + 
    (0.5870 * (X[:,:,1])) + 
    (0.1140 * (X[:,:,2]))

将数据数组存储为地理标志

在本笔记的下一个单元/步骤中,使用 GDAL 库将数据数组导出到图像,包括:

  1. GetDriverByName:导出为 GeoTIFF
  2. SetGeoTransform:保存坐标,以及
  3. osr。SpatialReference:以及投影,在本例中为硬编码(3395)

使用从图形数据创建图像

  • newRasterfn:文件名(str)
  • rasterOrigin:左上角(minx,maxy)
  • 像素宽度:单元尺寸(w)
  • 像素高度:单元格尺寸(h)
  • 数组:图中的展平数据(NxM)
Code section <<Storing the data array as a GeoTiff>> is not displayed fully, and is only giving the high level view of the functions# Export array to raster (main function)
def array2raster(newRasterfn,
       rasterOrigin,pixelWidth,pixelHeight,array):
       # newRasterfn: File Name
       # rasterOrigin: upper left corner
       # pixelWidth: cell dimetion (w)
       # pixelHeight: cell dimetion (h)
       # array: the data from the figure# Creating the Image from a Figure
def createImageFromFigure(newRasterfn,
       rasterOrigin,pixelWidth,pixelHeight,array):# Creating the image from the figure data, with:
createImageFromFigure (newRasterfn,
      rasterOrigin,pixelWidth,pixelHeight,Y)Rechecking the dimentions
cols (X):  881  // rows (Y):  883
Cell size:  2084  (w) ,  2084  (h)
rasterOrigin:  (-672599.7581629481, 6738853.145639915)
Image saved to disk

总结第一部分

代码的第一部分到此结束,总结了我们到目前为止所涵盖的内容:

转换工作流程

  1. 向量数据被加载到 MatPlotLib 图形中
  2. 为项目选择正确的投影,并非所有项目都使用相同的坐标系。
  3. 重构图像的像素信息,从多维到简单的数据阵列。
  4. 背景中只需要灰度值
  5. 图像的参数存储为元数据
  6. 该图形存储为地理标志

在下一部分中,转换后的图像被重新加载到项目中,并检查转换过程(查看图像是否投影到正确的位置)。

可视化导出的图像

笔记本的这一部分相对较短,演示了如何加载数据,并使用图像作为背景图来显示新信息。

该笔记本的主要目标是创建一个简单的程序,将标准背景图像包含到其他笔记本中,而无需管理制作地图所需的数据。因此,下一个代码部分也可用于项目的相关笔记本中,但没有生成地图所需的数据和代码开销。

只剩下两项任务:

  1. 加载已创建的 GeoTiff
  2. 显示创建的地理标志

相对于分析和笔记本而言,显示的图形可以被丰富得多的信息。

重新加载检查点

查看图像的范围并检查元数据中的条目,是验证该过程是否成功的一种方法。重新导入并在导出的地图上显示城市将提供一个直观的确认,即数据的重新投影、图形的转换以及图片作为新图形的重建都按设计进行。

Prompt: Current projection:  epsg:3395Code section <<Reloading the checkpoints>> is not displayed fully

加载导出的图像

本节中的代码将:

  • 读入带有 GeoTIFF 地理信息的文件
  • 使用元数据信息重新创建图像
  • 生成 X 和 Y 网格位置
  • 检查边界坐标
  • 将数据(颜色)作为数组读取
  • 检查方向(翻转阵列)
Code section <<Loading the exported image>> is not displayed, duplication of earlier code

显示转换的结果

在图片下面的红点是点(城市),在之前的段落中加载,它们完美地落在之前添加到地图的点上。在第一张地图中,这些点显示为带有红色轮廓的黑点。在转换过程中,所有颜色都被重新编码为“灰色”值,如果转换不成功,红点周围会出现“灰色/黑色”阴影。

# Creating the new figure with the image as background
fig, ax = plt.subplots(figsize=(15, 15))
rasterio.plot.show(src, ax=ax, cmap='gist_gray')
points.plot(ax=ax, facecolor='red', markersize=40, linewidth=2,alpha=1)     
plt.show()

带有检查点的转换背景图像

结论

可以从图形(GeoTiff)创建地理参考图像,然后将此新图像用作 MatPlotLib 图形的背景。

一些数字说明了不将原始矢量文件传递到过程的第二部分的好处:

汇总结果

使用预先配置好的背景图(可以轻松共享)在团队内部协作时会有所帮助,因为图像不会分散项目中交换的其他信息的注意力。然而,在拥有标准背景图的所有优点中,有一个(或更多)缺点。大多数人喜欢动态地图,构建的地图是静态的,只能用于一个目的和一个比例(范围)。因此,当缩放和平移地图是工作流的一部分时,标准静态地图对项目的探索阶段没有帮助。

结束语

希望这款笔记本有助于减少大数据集的转移,大数据集只用于显示静态背景图,对讲故事没有贡献。举个例子,我将在我的总体项目的下一阶段使用本笔记本中开发的技术。在这个子项目中,我将需要在我的下一个项目:“按地点和时间聚类事件数据”的所有地图轻量级背景图像

很抱歉,你可能已经注意到了,这篇文章没有包含笔记本中的所有代码(可以从下面的链接下载)。文本已经很长了,而且有些地方是技术性的,添加更多的代码会使长度增加一倍,但不会提高可读性。

请不要犹豫,我非常乐意提供更多关于所用方法的信息,或者纠正代码中在使用其他数据而不是本演示中使用的数据进行测试时可能不符合预期的部分。

感谢您的阅读,我希望这篇文章已经帮助您解决了一个问题,或者为您的下一个项目提供了一个思路。

Google CoLab 笔记本链接:https://gist . github . com/gvd dool/873 ed 1c 8 B3 de 4 CCC 7 ba 5 f 376671 b 7 BC 0

信用

由@dexplo 开发的“jupyter 到 medium”转换器使得从 Jupyter 笔记本到这篇 Medium 博客文章的转换成为可能

[## Jupyter 到 Medium

在 jupyter_to_medium 的帮助下,直接从您的笔记本中将 Jupyter 笔记本发布为中型博客文章。做…

www.dexplo.org](https://www.dexplo.org/jupyter_to_medium/)

封面图片由来自 Pixabay 的托比亚斯·哈默拍摄

Geobinning 星巴克

原文:https://towardsdatascience.com/geobinning-starbucks-88bc636f43c6?source=collection_archive---------65-----------------------

利用 Python、Geobinning 和 Matplotlib 生成 Choropleth 图

我看到外面有很多 choropleth 地图,它们看起来非常好,真的吸引了很多注意力。如果你有一个干净的数据集,创建它们是非常容易的,但是,我想探索的很多数据并没有按照我想要的方式分类。通常情况下,它以坐标(lat/lng)的形式出现,这让我来决定他们应该去地图的哪个区域。

即。我需要想出如何地理定位结果

为此,我创建了一个名为 Geobinning 的 pypi 库,它并不十分花哨,但可以让我们将点数据绑定到任意多边形中。这将允许我们生成 choropleth 地图,并做一些有趣的事情,如叠加原始点数据。今天,我们将使用这个 python 包和 matplotlib 重新创建上面的图像,以绘制最终的地图。

注意:我专门用 Kaggle 来做我的编码,因为我喜欢有一个基于云的平台,我可以到处玩。所有的数据集和代码对我的顾客都是可用的(如果你想要它,只要问,我会给你!)但是如果你想支持我的工作,请检查一下

[## Datastuffplus 正在创建数据驱动的图形和可视化。帕特里翁

嘿,欢迎光临!Datastuffplus 主要是我开始分享一些开发工作的 instagram 账号…

www.patreon.com](https://www.patreon.com/datastuffplus)

代码

首先,我们将安装我们的软件包

!pip install **geobinning**

接下来,我们将加载加载和处理数据所需的包

import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import geobinning as gb
import shapefile  # Shapefile processing

对于这个特定的研究,我将按美国县来收集数据,但我还想画出美国的州边界,以便以后更容易理解。所以我会加载。shp 和。dbf 文件,可从

[## 地图边界文件-形状文件

查看 2018 年及以前年份的 shapefile 格式的制图边界文件。

www.census.gov](https://www.census.gov/geographies/mapping-files/time-series/geo/carto-boundary-file.html)

**# Load in the shape data****# Counties**
myshp = open('**../input/us-county-
    shapefile/cb_2018_us_county_5m.shp**', "rb")
mydbf = open('**../input/us-county-
    shapefile/cb_2018_us_county_5m.dbf**', "rb")county = shapefile.Reader(shp=myshp, dbf=mydbf)
county_shapes = county.shapes()# **States**
myshp = open('.**./input/us-states-shapefile/tl_2017_us_state.shp**',
    "rb")
mydbf = open('**../input/us-states-shapefile/tl_2017_us_state.dbf**',
    "rb")
states = shapefile.Reader(shp=myshp, dbf=mydbf)
state_shapes = states.shapes()

接下来,我们将获取形状文件对象,并提取定义县和州形状的多边形

**state_polygons** = []
for s in state_shapes:
    state_polygons.append(s.points)**county_polygons** = []
for s in county_shapes:
    county_polygons.append(s.points)

加载我在 Kaggle 上找到的星巴克数据

[## 星巴克在全球的位置

运营中的每家星巴克店的名称、所有权类型和位置

www.kaggle.com](https://www.kaggle.com/starbucks/store-locations)

starbucks = pd.read_csv('**../input/store-locations/directory.csv**')**# Filter for US only**
starbucks = starbucks[starbucks['Country'].isin(['US'])]**# Extract the coordinates** points = []
for i,d in starbucks.iterrows():
    points.append([d['Longitude'],d['Latitude']])**# Use the geobinning package we created to bin the points in the polys**
star = gb.geobin(county_polygons,points)

剩下的就是使用 matplotlib 来生成我们的最终图像。不使用标准的绘图功能,我决定只使用多边形和圆形补丁对象。效果超级好!基本上使用 matplotlib 作为 MS paint

**# Load the packages**
import matplotlib.pyplot as plt
import matplotlib
from matplotlib.patches import Polygon,Circle
from matplotlib.collections import PatchCollection**# Generate a figure with a white background**
fig, ax = plt.subplots(figsize=(80,40), dpi=80, facecolor='w', edgecolor='k')**# Generate the patches (polygon objects) using the county data polygon set we created earlier**
patches = []
colors = []
for i,poly_data in enumerate(county_polygons):
    polygon = Polygon(poly_data, True)
    patches.append(polygon)
    colors.append(star[i])  ***# Colour by binning!!!!!*****# Make a patch collection of these polygons and use the BuGu colormap for the polygon colours (this creates a choropleth map)**
p = PatchCollection(patches, cmap=matplotlib.cm.BuGn, alpha=1,linewidth=0.1,edgecolor=(0,0,0))
p.set_array(np.array(colors))
ax.add_collection(p)**# Same treatment as above but for the state polygon set**
patches = []
colors = []
for i,poly_data in enumerate(state_polygons):
    polygon = Polygon(poly_data, True)
    patches.append(polygon)**# Notice facecolour is none since we only want the borders** p = PatchCollection(patches, alpha=1,linewidth=6,edgecolor='w',**facecolor='none'**)
ax.add_collection(p)**# Now we plot the actual raw point data.  Same deal as before but we are using the Circle instead of Polygon**
patches = []
for i,point_data in enumerate(points):
    pt = Circle(point_data,radius=0.06)
    patches.append(pt)
p = PatchCollection(patches,color='#0f713e',alpha=0.1)
ax.add_collection(p)**# Set the x/y ranges to be the rough boundary coordinates of the continental US**
ax.set_ylim(24, 50)
ax.set_xlim(-130, -60)**# Remove the axis and plot!**
plt.axis('off')
plt.show();

结果

上面代码的原始结果(原始内容)

哇,看起来真不错!在这一点上,我们可以继续下去,做任何其他编辑,我们想告诉这个故事。在这种情况下,有人指出,这基本上是一个人口地图,并没有提供太多的信息,但现在我们配备了工具来做更有趣的事情,如比较不同地点的不同商店密度等。

贡献者

凯尔·帕斯托尔和拉贝·纳齐姆

参考

[## 地理分箱

使用 geobinning 根据 geojson 几何来存储[lng,lat]点。任何包含 ID 和多边形的 geojson

pypi.org](https://pypi.org/project/geobinning/)

使用 Python 进行地理编码和反向地理编码

原文:https://towardsdatascience.com/geocoding-and-reverse-geocoding-using-python-36a6ad275535?source=collection_archive---------20-----------------------

当地址已知时查找纬度和经度,或者使用 OpenCage 的 geocoder & geopy 查找数据帧的纬度和经度。

照片由捕捉人心。号上的 Unsplash

地理编码是获取输入文本(如地址或地名)并返回纬度/经度位置的过程。简单来说,地理编码就是把物理地址转换成经纬度。

python 中有许多地理编码 API 选项。一些流行的有 GeoPy,OpenCage geocoder,google geocoding。Geopy 是为数不多的为非商业用途提供无限制访问的 API 服务之一。对于 Google API 和 OpenCage 地理编码器,每天有 2500 个请求的限制。使用 geopy,我的数据集中一些地址的纬度和经度显示了不同的国家,而不是美国。使用 OpenCage 地理编码器,令人惊讶的是所有的地址都是准确的,所以我使用 OpenCage 编码器。

使用 OpenCage 地理编码器和 pandas

要在 python 中使用 OpenCage Geocoder,应该首先使用pip install opencage安装 python 库。关于这个库的更多信息可以在这里找到:Github 上的 OpenCageGeocode

一旦安装了库,您将需要一个 OpenCage 地理编码器帐户来生成 API 密钥。可以使用opencagedata.com创建一个免费账户。注册帐户后,您可以在 Dashboard 中找到 API 密钥,如下图所示。

例子

from opencage.geocoder import OpenCageGeocode
key = "Enter_your_Api_Key"
geocoder = OpenCageGeocode(key)
address='1108 ROSS CLARK CIRCLE,DOTHAN,HOUSTON,AL'
result = geocoder.geocode(address, no_annotations="1")  
result[0]['geometry']

输出:{ '纬度':31.2158271,'液化天然气':-85.3634326}

我们得到了一家名为东南阿拉巴马医疗中心的医院的经度和纬度。在大多数情况下,我们会有多个地址需要像现在这样绘制在地图上。在这种情况下,使用 pandas 创建数据框将容易得多。我使用的数据集包含美国所有医院的列表,以及医院所在县的新冠肺炎病例总数。数据集可以从这里下载。

import pandas as pd
data=pd.read_csv(‘Final.csv’)
data.head(10)

医院位置数据框架

我们有一个数据框,其中包含美国所有医院的设施名称及其地址的列表,因此我们只需要找到位置坐标。

首先,我们应该将地址列转换为列表。因此,循环所有地址会更容易。

接下来,从 OpenCage geocoder 网站输入您的 API 密钥,并创建空列表来存储纬度和经度。创建空列表后,创建一个循环,给出所有地址的经度和纬度

addresses = data["Full_Address"].values.tolist()
key = "Enter-your-key-here"
geocoder = OpenCageGeocode(key)
latitudes = []
longitudes = []
for address in addresses: 
    result = geocoder.geocode(address, no_annotations="1")  

    if result and len(result):  
        longitude = result[0]["geometry"]["lng"]  
        latitude = result[0]["geometry"]["lat"] 
    else:  
        longitude = "N/A"  
        latitude = "N/A"  

    latitudes.append(latitude) 
    longitudes.append(longitude)

我们有数据框中所有地址列表的纬度和经度。我们可以使用这个简单的 pandas 命令将纬度和经度添加到现有的数据框中。

data["latitudes"] = latitudes
data["longitudes"] = longitudes
data.head(10)

最后,我们得到了所有医院地址的经度和纬度。为了更好地理解这个位置坐标,让我们使用 follow maps 将所有位置坐标绘制成地图中的点。

folium_map= folium.Map(location=[33.798259,-84.327062],zoom_start=4.4,tiles=’CartoDB dark_matter’)FastMarkerCluster(data[[‘latitudes’, ‘longitudes’]].values.tolist()).add_to(folium_map)folium.LayerControl().add_to(folium_map) for row in final.iterrows():
    row=row[1]
    folium.CircleMarker(location=(row["latitudes"],
                                  row["longitudes"]),
                        radius= 10,
                        color="#007849",
                        popup=row[‘Facility_Name’],
                        fill=False).add_to(folium_map)

folium_map

现在,我们可以看到美国所有医院的位置点。我使用 CircleMarker 聚类来更好地了解医院数量最多的地区。

使用 follow 创建的地图可视化快照(聚类位置)

反向地理编码

反向地理编码,另一方面,将地理坐标转换为位置的描述,通常是一个地点或可寻址位置的名称。地理编码依赖于地址点、街道/道路网络以及邮政和行政边界的计算机表示。

对于反向地理编码,我发现 Geopy API 的输出格式比 OpenCage Geocoder 更详细。此外,Geopy API 没有限制,因此我们将使用 Geopy 而不是 OpenCage Geocoder。

OpenCage 反向地理编码器示例

result = geocoder.reverse_geocode(31.2158271,-85.3634326)  
result[0][‘formatted’] 

输出:美利坚合众国 AL 36302 Dothan Alma 街东南健康医疗中心

Geopy 反向地理编码器示例

from geopy.geocoders import Nominatim
geolocator = Nominatim(user_agent="test_app")
location = geolocator.reverse("31.2158271,-85.3634326")
location.raw[‘display_name’]

输出:“美国阿拉巴马州休斯顿县多森莫里斯高地罗斯克拉克圈 1108 号东南健康校园,邮编 36301。”

使用 Geopy 地理编码器和熊猫

对于反向地理编码,如上所述,首先,我们将纬度和经度转换为列表并压缩在一起。

lats=data['latitudes'].to_list()
lons=data['longitudes'].to_list()
# Creating a zip with latitudes and longitudes
coords=list(zip(lats,lons))

因为,我们已经创建了列表,就像上面一样,我们将创建一个循环来查找每个位置坐标的地址,并将它们附加在一起。

from geopy.geocoders import Nominatim
geolocator = Nominatim(user_agent="test_app") 
full_address=[]
for i in range(len(coords)):
    location = geolocator.reverse(coords[i])
    address=location.raw['address']['country']
    full_address.append(address)
#Creating dataframe with all the addresses
addres=pd.DataFrame(data=full_address , columns=['Address'])
addres

最后,我们有美国所有医院的地址列表。

对于感兴趣的读者,我把代码放在我的 GitHub Repo 这里。如果您有任何疑问,请使用 linkedin 联系我。

使用 Google Maps API 在 Python 中进行地理编码

原文:https://towardsdatascience.com/geocoding-in-python-using-google-maps-api-56278816cdd6?source=collection_archive---------36-----------------------

本文将重点介绍 Python 中的地理编码,它获取地址或世界上任何地方的坐标,并计算两个位置之间的距离和路线。

米卡·鲍梅斯特在 Unsplash 上的照片

目录:

  • 介绍
  • 用 Python 对地址和位置进行地理编码
  • 在 Python 中计算测地线距离
  • 使用 Python 中的 Google 距离矩阵 API 计算行驶距离
  • 结论

介绍

公司可以访问大量基于位置的数据,例如客户地址、销售地址、办公地点、商店地点等等。从这些信息中可以得出很多对决策非常有用的见解。因此,投资于初步地理空间分析的愿望越来越强烈。

这就是数据科学空间变得开放的地方。帮助企业分析与某些位置、地区或地址相关的指标。他们向数据科学家寻求一些技术帮助。

在本文中,我将使用 googlemaps API 解释使用 geopy 和 Google Maps 库在 Python 中进行地理编码的基础知识。然后,我将演示在给定坐标的情况下,地图上两点之间的基本距离计算。

简而言之,地理编码作为一个过程是将地址或位置作为输入,并生成其坐标(纬度和经度)作为输出。稍后,这些数据可用于创建不同的地图或热图,以绘制路线或显示基于位置的指标。

用 Python 对地址和位置进行地理编码

为了继续学习本教程,我们需要三个 Python 库:pandas、geopy 和 googlemaps。

如果您没有安装它们,请打开“命令提示符”(在 Windows 上)并使用以下代码安装它们:

pip install pandas
pip install geopy
pip install googlemaps

导入所需的库:

一旦下载、安装和导入了库,我们就可以继续 Python 代码实现了。

步骤 1:创建 Google Maps API

作为第一步,您需要创建一个 Google Maps API 并启用它的服务。这不是免费的,但是你可以获得每月 200 美元的免费积分,这在大多数情况下是足够的,除非你试图对一个非常大的数据集进行地理编码。

一旦创建了 API,就应该将其作为字符串存储在 Python 中:

第二步:选择地点

在这篇文章中,我将使用我在纽约出差时最喜欢去的两个地方:帝国大厦(因为它的风景)和 Marea 餐厅(因为它的食物)。

使用我提供的代码,你将能够找到位置的坐标使用他们的地址或位置名称。两者都会产生相同的结果。

步骤 3:创建谷歌地理编码器

在 geopy 中,每个地理编码器都有自己的类。由于我们正在使用谷歌的地理定位服务,我们将创建一个谷歌地理编码器类,然后检查它的类型:

class 'geopy.geocoders.googlev3.GoogleV3'

现在我们有了一个地理编码器,它将使用我们的 Google API 代码来连接到 Google Maps,并为我们提供所需的位置数据。

步骤 4:用 Python 对位置进行地理编码

前期工作和设置已经完成。激动人心的部分从这里开始。仅用地名,我们就能找到它的地址和坐标:

20 W 34th St, New York, NY 10001, USA
40.7484405 -73.98566439999999

如你所见,它工作得很完美。这些数据相当于你去谷歌地图搜索“帝国大厦”得到的数据。

那么我们的代码到底产生了什么呢?首先,我们创建了一个 name 字符串,并给它分配了我们的地名。然后我们使用了来自步骤 3 的地理定位器,它创建了一个位置类,我们将其存储为位置。它有多个数据点,但是我们只打印我们感兴趣的数据点:地址、纬度和经度。

最后一步,我们需要存储我们的结果,我将把它保存为熊猫数据框:

name                   address
Empire State Building  20 W 34th St, New York, NY 10001, USA
lat        lon
40.748441 -73.985664

按照相同的步骤,我们现在将找到第二个位置的坐标,并将其全部合并到一个数据帧中:

name                       address        lat        lon
Empire State Building      20 W 34th St, New York, NY 10001, USA  40.748441 -73.985664
Marea Restaurant New York  240 Central Park S, New York, NY 10019, USA  40.767448 -73.981133

在 Python 中计算测地线距离

我发现 geopy 的一个特别有用的特性是它能够计算坐标之间的距离。默认情况下,测地线距离用于距离计算。

什么是测地线距离,它是如何计算的?测地线距离是两个坐标之间的最短距离,假设地球是椭球形的。

下面我在地图上标出了这些地点:

作者图片

如你所见,两个绿点是我们的位置。在这种情况下,测地线距离是连接两个绿点的直线的长度。

使用以下代码计算两个位置之间的测地线距离:

2.145211377374085

两个位置之间的测地线距离约为 2.15 公里。但是我们看到它有什么问题吗?如果你看地图,你的目标是找到距离,在这种特殊情况下,你可能对道路距离感兴趣。由于纽约曼哈顿的景观和建筑位置,你无法通过直线行走从 A 点到达 B 点。

有什么解决办法?在下一节中,我们将探索如何计算从帝国大厦到 Marea 餐厅的实际道路距离(在我们的例子中是步行距离)。

使用 Python 中的 Google 距离矩阵 API 计算行驶距离

在本节中,我们将使用 googlemaps 库和 Google 的距离矩阵 API 来计算从帝国大厦到 Marea 餐厅的“道路”距离。

和上一节有什么不同?在这种情况下,我们被限制只能使用适合驾驶的道路从 A 点到 B 点。在业务绩效分析的情况下,这通常可以方便地测量不同地点之间的平均通勤时间,而不仅仅是考虑直线距离。

步骤 1:创建谷歌地图客户端

由于我们使用 Google 的地理定位服务,我们将创建一个 Google Maps 客户端类,然后检查其类型:

class 'googlemaps.client.Client'

步骤 2:用两点之间的所有数据创建一个字典

使用步骤 4 中的位置坐标,我们现在将创建一个字典,其中包含通过谷歌距离矩阵 API 获得的两个坐标之间的所有信息:

{'destination_addresses': ['240 Central Park S, New York, NY 10019, USA'],
 'origin_addresses': ['14 W 34th St, New York, NY 10001, USA'],
 'rows': [{'elements': [{'distance': {'text': '3.2 km', 'value': 3246},
     'duration': {'text': '18 mins', 'value': 1070},
     'status': 'OK'}]}],
 'status': 'OK'}

让我们来分析一下上面这段代码做了什么。它从之前我们用 Python 执行地理编码的一个部分获取两个位置的坐标:P1p2,并从步骤 1 通过 Google Maps 客户端解析它。因此,上面的函数生成了一个包含这些坐标的所有“距离”数据的字典。

如您所见,字典包含大量数据点。我们感兴趣的是“行”->“元素”->“值”。让我们访问它:

3246

我们看到的输出距离是 3246 米,约为 3.25 千米。与 2.15 公里的测地线距离相比,它肯定更大。Google Maps APIs 允许您找到一条 excat 路线,这条路线会一直显示到这个距离,但这不在本文的讨论范围之内。我的近似路线如下所示:

作者图片

与两点之间的直线测地距离相比,谷歌距离是沿着道路上的实际行驶路线,这导致两点之间的距离明显更大。

结论

本文重点介绍了数据科学家可以用来学习用 Python 进行地理编码的工具。这应该是一个良好的基础,不断探索不同的坐标之间的距离测量,并可以进展到地理空间数据可视化。

如果你有任何问题或者对编辑有任何建议,请在下面留下你的评论。

原载于 2020 年 4 月 30 日【https://pyshark.com】

地理编码变得简单

原文:https://towardsdatascience.com/geocoding-made-simple-1f2904da2b4b?source=collection_archive---------54-----------------------

使用 Python 和 Google API 获得 Lat & Lon 的 10 行代码

照片由 Canva 的 Alesmuth 拍摄

我们现在生活在一个快速和视觉化的世界里,图像比语言更有说服力。决策越来越依赖于数据,数据以如此惊人的速度和数量向我们袭来,如果没有某种抽象层,比如视觉层,我们就无法理解它。

这可能是为什么数据可视化变得越来越重要的一个原因,它允许以一种既引人注目又易于消化的方式组织数据。

当数据位于地理位置时,地图可以非常有效地显示数据在特定区域的分布和比例。地理编码是将数据绘制成地图的关键过程。简而言之,地理编码意味着将地址或位置作为输入,并生成其坐标(纬度和经度)作为输出。

在本文中,我旨在向您展示使用 Google API 检索地理编码信息是多么容易。要做到这一点,我们首先需要建立一个谷歌开发人员帐户,并获得一个位置样本数据集。然后我们将实现 10 行简单的代码来获取这些位置的坐标。

我们需要的是…

1.设置您的 Google 开发者帐户

要获得 API 密匙,我们需要首先用你的谷歌账户邮箱和密码登录到谷歌开发者账户。如果你没有谷歌账户,就在这个链接创建一个。

下一步是为 Google 创建计费帐户,以便对 API 的使用进行收费。要创建计费账户,请进入谷歌开发者账户主页左上方的菜单,然后点击计费部分,然后点击添加计费账户。提供您的账单详情并选择谷歌地图平台 以完成帐户的创建。

每月可以获得 200 美元的谷歌地图平台积分,所以如果你每月的请求超过 40,000 次,我建议你在这个链接查看价格细节(考虑一个请求意味着获得一个位置的纬度和经度)。

我们还需要创建一个新项目。点击顶栏上的选择项目,然后点击窗口左上方的新建项目

现在我们已经有了我们的计费帐户和项目,我们需要为项目启用 API。访问您刚刚创建的项目,并点击Enable API and Services。搜索地理编码 API ,点击启用

我们需要做的最后一件事是创建 API 密钥,为此我们只需转到凭证选项卡,单击创建凭证,然后单击 API 密钥。复制 API 密钥,因为我们将在接下来的步骤中使用它。

2.导入库

现在让我们打开编码环境,导入所需的库。我们将使用熊猫谷歌地图

3.添加 API 密钥

现在,我们将在步骤 1 结束时创建的 API 键作为变量添加到代码中。

4.获取我们的样本数据

然后我们需要得到我们的数据。出于本练习的目的,我创建了一个 csv 文件,其中包含 10 个地点的列表(我在伦敦最喜欢的 5 个酒吧的地址加上其他 5 个随机地点)。

我们想要的输出是所有位置的纬度和经度,这就是为什么我还将创建两个新列来存储这些信息。

用 10 行代码进行地理编码

现在我们已经拥有了所需的一切,我们可以运行 10 行代码来检索样本位置的地理编码信息,并将结果存储在我们刚刚创建的两列中。

为了交叉检查我们的结果,我创建了两列,并手动插入 10 个位置的正确纬度和经度。如你所见,我们得到的结果相当准确。

我真正喜欢这个 API 的地方是地址或位置不必有特定的格式。您可能已经注意到,在示例数据中,我在 location 列中使用了不同的格式。我添加了没有邮政编码、街道号码、只有大写字母甚至罗马数字的地点。我还尝试过检测兴趣点、国家、餐馆名称和伦敦广场上的普通披萨店,结果仍然令人满意。

现在我们已经有了所有的地理编码信息,让我们把这个练习付诸实践。使用 Tableau,我们可以创建一个我在伦敦的前 5 家酒吧的简单地图,就是我们在样本数据文件中的那些。

好了,现在你有了一个结合 Python、Google API 和 Tableau 创建的简单地图。

结论

我希望这篇文章清楚地展示了使用 Google API 获得地理编码信息是多么容易。

说到数据可视化, 人人都爱一张图 。比图表更令人兴奋,比信息图更简单。因此,我希望这种方法能帮助你可视化你的地理数据,并利用你的洞察力。

请务必联系我,告诉我你所有的建议和意见。

感谢阅读!

我正在创建一个与数据科学和分析相关的所有我最喜欢的课程、书籍和用例的列表。点击 链接 即可在免费访问该内容。

[## 用我的推荐链接加入 Medium-Lore 那又怎样

阅读 Lore 的每一个故事那又怎样(以及媒体上成千上万的其他作家)。您的会员费直接支持…

medium.com](https://medium.com/@loresowhat/membership)

测地线回归

原文:https://towardsdatascience.com/geodesic-regression-d0334de2d9d8?source=collection_archive---------10-----------------------

机器学习遇上黎曼几何

黎曼几何可以被安全地称为数学中的“革命性”理论。首先,该理论通过将“平坦的”欧几里得空间推广到弯曲流形,提出了一种激进的空间和几何观点。后来,阿尔伯特·爱因斯坦利用这一理论解释了空间和引力,这就是我们所知的“广义相对论”,这是一场重大物理学革命的基础。

黎曼几何在机器学习中也有应用。在本文中,我们将学习测地线回归,它是线性回归到黎曼空间的延伸。假设读者对最小二乘线性回归模型有很好的理解,并有一定的黎曼几何知识。在深入主题之前,有必要讨论一下几何学的基础知识。解释将用简单的术语来表达,这是理解主题所必需的,我们不会深入到几何学的细节中。因此,我们可能会有一个不完全符合标准数学定义的随意解释。

再说空间!

在学校和高中,我们被教授大量建立在欧几里得空间基础上的几何定理。欧几里得几何是唯一流行的东西,直到天才高斯和黎曼暗示事情可以不同。他们提出了弯曲空间理论,该理论并不一定要求具有欧几里得性质。假设底层基础被破坏,这些定理对弯曲空间(流形)不再成立。因此,它要求我们重新思考我们迄今为止所学的一切。

图 1:球形流形(来源:维基百科)

欧几里得空间是众所周知的,然而,让我们从技术上定义它:一个有限维(a1,a2,a3,…an)的实数空间,有一个明确定义的内积(点积)。我们通常把它想象成一个由相互垂直的线性轴构成的向量空间。相反,黎曼空间是非线性轴的跨度。一个常见的例子是球面,它是纬线和经线的跨度。当我们深入研究弯曲空间的几何时,事情似乎很奇怪。例如,矢量空间的概念并不存在,毕达哥拉斯定理不再有效,在赤道上看似平行的经线最终会汇聚并在极点相遇。说了这么多,我们接着来解释一下它的一些概念。

*向量空间是在向量运算(加、减等)下封闭的空间。)

距离

计算点与点之间的距离是一种常见的几何运算。在欧几里得空间中,勾股定理允许我们进行简单的距离计算。现在让我们来考虑一下,在一个球体中寻找两点之间的距离。一旦我们认识到连接这些点的曲线不可能是直的,勾股定理在这里就不再适用了。然而,如果我们放大到曲线上足够小的一段,它可以安全地被认为是直的,我们有一个局部定义的向量空间。点与点之间的距离是这一小段的积分。

注意:由于坐标轴在局部向量空间中可以是非正交的,因此计算小段的长度并不简单。我们需要利用一种叫做“黎曼度规”的东西来计算距离。如果感兴趣,下面的链接已经涵盖了黎曼度量的良好细节:【https://www.ime.usp.br/~gorodski/teaching/mat5771/ch1.pdf】T2。

测地线

这是将“直线”的概念推广到曲线流形。测地线是空间中两点之间的最短路径,是弯曲流形中“最直的可能路径”。如图 2 所示,连接点 PQ 可以有无限多条路径。但是最短的,用红色突出显示的,是测地线。测地线距离的数学符号是 d(P,Q)

这里要注意的是,我们不能用一条直线连接 P 点和 Q 点来获得它们之间的最短路径,因为这条直线将位于球体的内部。记住,要定义一条曲线,曲线上的每个点都必须位于定义它的流形上。球体内部的任何东西都不在球面流形中。

图 2:测地线(来源:维基百科)

切空间

它是流形上一点的切向量所跨越的空间。这可以简单地想象成一个球面上一点的切平面。请注意,我们在黎曼流形中没有向量。所以,切空间不是它的一部分。它是一个独立的欧几里得空间,其中的切向量是黎曼流形上的点的泛函映射。

请注意,向量只能定义在一点的切空间上,而不能定义在流形上。

指数图

这是本文的一个重要概念。让我们回想一下,在欧几里得空间中,通过最短路径将一个点转换到另一个点只需要矢量加法。既然已经提到了黎曼流形中不存在向量空间的概念,那么任何向量运算(这里是加法)都没有意义。我们需要不同的数学运算才能从一点到达另一点。这就是指数地图发挥作用的地方。

我们将借助于切空间中流形上的一点 M 。如图 3 所示,我们可以在球面流形的一点上有一个平的切面。切面是一个向量空间,我们可以在这里进行平移。例如,在图 3 中, T_pM 是球面流形的点 P 处的切空间,并且我们已经通过切平面中的向量平移了点 P 。现在的重点是将向量映射回球面流形,就像球面中的 v 到点 A 的映射一样。这种映射称为指数映射,最后,我们能够在流形上从行进到,并且我们得到的路径是点之间的最短路径。**

图 3:指数图(图片作者)**

请注意,指数映射的存在涉及到一些数学上的手续,这里不做讨论。简而言之,求流形中各点之间的最短路径基本上就是 3 次运算。(1)在一个点上实现一个切空间,(2)通过一个向量平移切空间中的点,(3)将平移的点映射回流形。这样,我们将在流形上得到一条测地线。此外,映射被定义为使得向量 v(||v||) 的范数等于测地线距离 d(p,A) 。数学上,指数映射定义为:

映射函数 Exp(p,v) 取决于流形,并且可以解析地确定。

黎曼空间中的指数映射类似于欧氏空间中的直线方程。

测井图

这是指数映射的逆映射,将点从流形映射到切面。在图 2 中,这是从点到向量的映射。由于向量 v 的范数等于测地距离,我们可以推断| Log(p,A)| = d(p,A)。 它在数学上被定义为:**

平行运输

当我们定义切空间和切空间中的向量时,还有一点需要注意。在欧几里得几何中,大小和方向相同的向量在空间的任何一点都具有相同的意义。相比之下,对于弯曲流形,向量和切空间仅被局部定义,因此我们不能有相同的全局解释。

为了理解这一点,让我们把球面流形再次带入图中,如图 4 所示。我们可以把球体想象成我们的地球,把 A 和 B 想象成地球上的两个地方。对于住在点 A 的人,矢量 V_A 是水平方向。但是当我们继续定义同一个向量在点 B,时,它变成了一个垂直方向。要在 B 点定义水平方向,我们需要修改原始向量(在这种情况下,旋转它)。向量 V_B 是对向量 V_A 的修改,使得 V_B 对于点 B 的意义与 V_A 对于点A的意义相同。这种修改称为并行传输,我们称之为向量 V 从点 A 并行传输到平行运输的数学符号如图 4 所示。****

图 4:并行传输(图片作者)**

平行迁移是理解曲面和定义黎曼流形中曲率的一个重要概念。然而,对于我们这里的目的,我们坚持我们的简单定义。像指数映射一样,平行传输的表达式依赖于流形本身的性质。

现在,我们有了足够的数学概念来深入主题。先来回顾一下线性回归的案例**

线性回归

给定一个参变量 X 和相应的因变量Y =(Y _ 1,y_2,y_3…,y_n), 线性回归的目标是将 Y 表示为 X 的线性函数。****

通过最小化最小二乘误差来确定参数 wb :

我们有一个参数 wb 的闭合解,可以通过使用线性代数来解析地确定。在下一节中,我们使用类似的方法将测地线回归参数定义为最小二乘最小化任务。

测地线回归

GR 背后的动机是,现实生活中并非所有的数据点都位于欧几里德空间。例如,对于球形流形,数据点由球体表面上的点表示。然而,任何流形仍然可以在更高维的欧几里得空间中实现,就像二维球面流形可以在欧几里得空间中实现为三维表面一样。因此,欧几里得空间中的非线性回归可以对驻留在流形上的数据点进行建模。但是,由于维数增加和复杂的非线性关系,这样的模型将会相当复杂。模型的复杂性会导致很大的差异。

对于驻留在非欧几里德流形中的数据,自然要用 GR 来建模,我们假设欧氏空间中的自变量 X ,流形 M 中的因变量 Y 。GR 模型是 LR 模型的概括,如下所示:

注意,对于欧氏空间,指数映射只是向量加法。因此,当 M 是欧几里得空间时,上面的等式简化为 LR 模型。上式中的变量 Y 是测地线,因此得名测地线回归。参数 pv 由以下最小化确定:

与 LR 不同,在 LR 中,我们对误差最小化任务有一个封闭形式的解决方案,而在这里,我们需要对最小化误差函数执行梯度下降。给定误差函数,

应根据参数 pv 计算梯度。测地距离相对于其中一个点的梯度就是对数图(暂且认为是理所当然的):

这里的挑战是导出指数映射 Exp(p,xv)的梯度。 让我们先对此养成一种直觉。

图 5:雅可比场(图片由作者提供)

M是包含点 p 的黎曼流形。图 5 左边部分是指通过参数 p 来区分 Exp(p,xv) 。红线是具有相同平移向量 v 但在不同点 p 上的指数映射(测地线)。微分的结果是一个向量场,由穿过测地线的蓝色箭头表示。图的右边部分解释了关于参数 v 保持点 p 恒定的微分。结果是一个由蓝色箭头表示的向量场。这两种情况下产生的矢量场合称为雅可比场雅可比场也可以理解为附近测地线之间的分离向量。****

好的,它们是如何计算的?

像指数映射一样,雅可比场是流形本身的性质。因此,它们是解析计算的,并且依赖于流形。注意雅可比场的推导需要黎曼几何的一些核心概念,不在本文讨论范围之内。详情可在标准在线资源中找到。

既然我们已经解决了确定测地距离和指数地图的梯度,我们可以继续计算误差函数的梯度,并执行梯度下降。得到的参数就是我们的 GR 模型的参数。

所以我们看到,一旦我们对 LR 有所了解,对 GR 来说就没什么了。尽管如此,我们讨论的一切都是理论上的,如果我们是第一次学习 GR,关于实现,事情会变得非常混乱,尤其是在指数图和 Jacobi 场周围。让我们看一个简单的例子。

在球形管汇上实现

对于 LR,我们需要一组独立的和相应的因变量。对于 GR,我们需要一个额外的信息:因变量所在的流形的性质。让我们以嵌入在三维欧几里得空间中的二维球面流形为例。

首先,让我们定义球面流形的测地距离、指数映射、对数映射和平行传输的表达式。

(假设中心在(0,0,0)的单位球,其中 p 和 q 是其上的点)。

下面是函数定义的 python 代码:

如前所述,回归模型是

带误差函数

其中 p 和 v 是模型参数。计算梯度包括计算球体的雅可比场,并且可以通过以下等式来近似。

这些梯度的精确解可以在下面引用的论文稳健测地线回归中找到。****

最后一步是更新参数,这有点棘手。请注意,我们得到的梯度是一个矢量。在 LR 中,我们可以简单地通过学习速率来缩放梯度向量,并将其从当前参数值中减去。但是正如已经讨论过的, p 是流形上的一个点,我们没有这样的向量运算。因此,我们必须应用指数映射来更新参数 p

为了更新参数 v,让我们回忆一下图 3: v 本身是切空间中的一个向量。因此,这可以简单地通过向量减法来更新。

然而,还有一件事需要注意。参考图 3,我们看到向量 v 被定义在 p 所在的同一点上。因此,当我们将 p 更新为 p_new 时,新向量 v_new 必须位于点 p_new。但是由于更新后的向量 v' 仍然位于同一个旧点 p ,我们需要想办法在新点 p_new 定义 v' 。这可以通过将更新的向量v’p 并行传输到 p_new 来完成。****

这就完成了我们的参数更新,为了在 python 中实现这一点,让我们首先在球面上生成合成数据,并在数据上实现 GR。

现在我们有了独立变量 x 和相应的数据点 y ,我们准备学习一个 GR 模型来拟合数据:

100 次迭代的误差函数的递减值(根据数据点的数量归一化)如下:

图 6:误差函数的梯度下降最小化(作者的图片)**

获得的参数值为:

这是对真实值的很好的估计:

上例中描述的数据点和生成的测地线曲线可以如图 7 所示:

图 7:GR 示例的可视化(作者的图片)**

红色虚线点是球体表面上的噪声数据点,红色实线曲线是拟合到数据点的测地线。这与课文中的例子并不完全相同,但非常接近。

结论:

在这篇文章中,我们把对回归的理解从欧几里德空间扩展到黎曼空间。更一般地说,我们用不同的视角处理机器学习问题。我们讨论了球面流形上的 GR 的一个例子,但是更实际的例子在于形状分析和计算机视觉任务,尤其是医学成像和生物统计学。针对这些应用,正在研究和开发针对黎曼空间中的数据的机器学习算法。

此外,我们不仅探索了一种新的回归技术,而且讨论了一种新的几何理论本身。黎曼几何在机器学习中的应用仍处于萌芽阶段,但其有效性是有希望的。

参考文献:

1.黎曼流形上的测地线回归。https://www . sci . Utah . edu/publications/Fletcher 11/Fletcher _ mfca 2011 . pdf

******2.稳健的测地回归:【https://arxiv.org/abs/2007.04518 ******

3.https://ronnybergmann.net/mvirt/manifolds/Sn.html

4.流形值数据的非线性回归技术及其在医学图像分析中的应用。https://www . cv-foundation . org/open access/content _ cvpr _ 2016/app/S18-44 . pdf

使用 HDBSCAN 进行地理聚类

原文:https://towardsdatascience.com/geographic-clustering-with-hdbscan-ef8cb0ed6051?source=collection_archive---------19-----------------------

如何使用 HDBSCAN、H3、图论和 OSM 探索地理数据。

马丁·桑切斯在 Unsplash 上的照片

你的智能手机知道你何时在家或在办公室。至少,我的能,甚至能告诉我什么时候出发,准时到达我的一个共同目的地。我们都接受我们的智能设备收集我们的偏好信息,并将它们发送到云端进行处理。这些反馈回来作为购物、食物、交配以及何时离开办公室回家的建议。

推断一个通常位置背后的魔力是什么?云计算机是如何找到我们生活的“地方”的?答案包括时间戳地理区域和聚类的集合。

在本文中,我将使用 HDBSCAN [1]算法和车辆能源数据集来说明地理聚类的过程。请参考我的上一篇名为“ 中型数据集 ”的文章,在这篇文章中,我展示了数据集以及如何用 SQLite 数据库处理它的细节。本文共享同一个 GitHub 存储库,并在此基础上为地理数据分析提供更多功能。

聚类方法来自另一篇名为“ 绘制英国交通事故热点图 ”的文章,在这篇文章中,我使用 DBSCAN 帮助在英国最常报告的交通事故区域周围创建地理围栏。在这里,我使用著名的基于密度的聚类算法的改进版本来处理城市环境中自然出现的复杂聚类,并使用公开可用的数据以一种非常简单但有效的方式命名它们。

车辆能源数据集

2019 年,G. S. Oh、David J. Leblanc 和 Huei Peng 发表了一篇关于车辆能源数据集(VED)的论文,其中包含一年的车辆轨迹和能耗数据。这些数据是从 2017 年 11 月至 2018 年 11 月在安阿伯收集的,参考了 383 辆不同类型和动力源的车辆样本。在这里,我们将只使用数据集中的地理数据,并将能源动力学的分析推迟到以后的文章中。

本文讨论了一种有趣的个人数据去识别方法,并研究了与燃油经济性和能效相关的使用案例。最重要的是,该调查收集了超过 374,000 英里的 GPS 数据,我们可以将这些数据用于本文的地理聚类目的。

这项研究的数据收集过程通过一个相对简单的三步法确保了司机匿名。这个过程变得与本文非常相关,因为它产生了一个副产品,一个关键的信息:个性化的车辆轨迹。为了匿名化驾驶员信息,研究作者应用了随机模糊地理围栏主要交叉边界技术。随机雾化会移除行程起点和终点附近的观测位置,而地理围栏会在城市边界周围定义的边界框外裁剪观测值。作者还在第一个和最后一个十字路口附近修剪了行程。除了驾驶员匿名化,这些程序还具有生成易于使用的个人轨迹的好处。

我在上一篇文章中给出了如何提取和显示这些轨迹的示例。在这里,我将使用所有轨迹的端点来识别感兴趣的地方,以便将来进行分析。不幸的是,这些将指的是安娜堡最常用的十字路口,而不是司机的最终目的地本身,因为这些都不存在。但这足以说明构建由所有轨迹端点定义的地理聚类的过程。

在我们开始之前,我邀请您克隆本文的 GitHub 库,并运行前四个编号的笔记本。下面的每一节都详细介绍了接下来的三个 Jupyter 笔记本,引导您到达端点:集群命名。

使用 HDBSCAN 进行聚类

遵循笔记本中的这一部分*5-clustering-hdbscan.ipynb*

运行上述四个笔记本将使您准备好开始地理聚类过程。我们寻找的行程终点信息保存在 SQLite 数据库的move表中,我们使用下面的代码通过一个查询读取行程的开始和结束位置。

一旦数据可用,我们可以将它重新排列成只有两列的数组,一列表示纬度,另一列表示经度,如下所示:

现在,我们可以将位置信息提供给 HDBSCAN 算法,该算法的输出是一个集群标识符数组。下面的函数处理所有的工作。

请注意将地理坐标从度转换为米的要求。现在我们可以在端点坐标上调用这个函数,并以相同的顺序收集集群索引。

clusterer = fit_utm_clusterer(locations)

得到的数组在第一维上具有与位置数组相同的大小,并且计算出的聚类标识符位于相应的索引中,使得查询非常容易。下面的函数在给定 id 的情况下在地图中显示一个聚类。这里,点定义感兴趣的区域,而不是地理围栏。

您可以在第五台笔记本电脑上看到这个功能,它还配有一个交互式小部件来简化集群选择。使用这种设置,您可以快速检查生成的集群质量,并可能调整一些 HDBSCAN 算法参数。

处理异常值

毫无疑问,突出的问题之一是一些集群的质量差。一些聚集的点出现在离主要聚集非常远的地方,这些应该通过将它们标记为噪声来处理。下一张图展示了这种现象的一个明显例子。

聚类号 2 显示了东北方向的一组独特的边远点。每个点的异常值分数反映在它的颜色上,蓝色点分数低,红色点分数高。

幸运的是,HDBSCAN 算法为我们提供了一种处理这些点的方法,即异常值得分。异常值的范围从 0 到 1,其中 0 表示算法非常确定该位置属于该聚类,而接近 1 的值则表示相反。在上图中,计算出的异常值分数被转换成一个颜色条带,从代表零的蓝色到代表一的红色。看着地图,很明显红色的点是噪音,不属于中央集群。

尽管如此,我们必须想出一个阈值来区分离群值或其他。我的方法非常直观,所以我浏览了所有的聚类点,寻找一个合理的阈值。离群值分数高于该阈值的点将被转换为噪声,而所有其他点将被保留。原来,红色的位置总是在最奇怪的地方,红色意味着高于 0.8 的异常值。

这样一个值的选择似乎是任意的,所以我决定提供一些数字支持。我试图确定这样一个门槛是否会去掉太多的分数。简单看一下整个数据集的异常值分布让我放心了。

通过选择 0.8 的异常值分数阈值,我们保留了超过 97.85%的聚类点。

从数值上看,这种计算非常简单,并且产生了 97.85%的相对高的值。

scores = clusterer.outlier_scores_
scores[scores < 0.8].shape[0] / scores.shape[0]

如果您想在聚类质量上保守一点,保留少一点,比如 95%的点,该怎么办?这个计算也很容易执行。

pd.Series(scores).quantile(0.95)

事实证明,如果只考虑 95%的聚类点,可以将离群值阈值设置为 72.7%。让我们保留 0.8 的值,并过滤掉外围位置。

filtered_clusters = np.copy(clusterer.labels_)
filtered_clusters[scores >= 0.8] = -1

如您所见,过滤是将所有异常值标记为噪声的简单过程。我们现在可以将它们保存到数据库中。对于每个聚类点,我们存储相应的 id(对于离群值可能是-1)、地理位置和 12 级 H3 指数。正如我们将在下面看到的,这会给我们带来一点麻烦,解决起来会很有趣。

聚类已经有了很大的价值,因为它们让我们能够从地理上了解旅行的起点和终点。然而,我们可以更进一步,设计一种方法,在聚类点周围绘制地理围栏。此地理围栏将作为判别函数来测试某个位置是否属于某个聚类。

集群地理围栏

遵循笔记本中的这一部分*6-cluster-geofencing.ipynb*

为了解决地理围栏问题,我将再次求助于 H3。正如我在之前的一篇文章中所展示的,我们可以用 H3 来图形化地描述集群。对于每个 H3 索引,我们可以根据地理坐标查询相应的六边形顶点。下面的函数将 H3 六边形索引转换成相应顶点坐标的数组。请注意第一个坐标是如何复制到最后以产生一个闭合的多边形的。

通过将一个集群的所有六边形粘贴在一起,我们可以构建一个类似蜂巢的集群表示。

通过将所有六边形粘贴在一起,我们创建了一个类似蜂巢的集群表示。然而,我们只想保留大纲。

上图有助于理解基于哈希的聚类包含检测算法是如何工作的。这些六边形中的每一个都对应于 12 级的 H3 指数。为了测试一个随机点在聚类中的包含性,我们必须将其坐标转换为 H3 指数,并将其与聚类列表进行比较。这种计算速度很快,并且很容易在数据库索引或内存哈希表的帮助下进行编码。

我们将保留这种基于哈希的搜索功能,但将通过仅保留多边形的整体轮廓来改进表示。我们在 Shapely 包的帮助下合并所有的多边形。

merged = cascaded_union(polygons)

我们将六边形多边形列表提供给级联联合函数。对于上面的简单情况,它返回单个多边形对象,或者当六边形的放置产生分散的“岛”时,它返回多多边形对象这就是我们想要的结果。

与上面相同的簇,但是现在所有的六边形合并成一个形状。

但并不是所有的星团都会聚结成一个单一的形状。由于点分散和用于表示的固定 H3 水平,我们可能会看到一些不连续的区域,如下图所示。

由于点分散和用于表示六边形的固定 H3 水平,这些岛逐渐增大。

这个问题的解决方案似乎很简单:我们必须在某个地方放置另一个六边形,并将两个组件连接起来,这让我想起了网络组件。也许我们可以用一些图论来解决这个问题。

我们可以通过将六边形视为节点,将相邻关系视为边,来构思一个表示我们的集群单元的图。如果两个六边形是邻居,将有一条边连接它们。下面的函数就是这样做的。

该函数接收六边形索引列表作为输入参数,并扫描所有可能的紧邻对。产生的邻域图不是有向类型,所以该函数只测试所有可能关系的一半。

一旦生成,我们就可以查询该图,以了解它有多少个连通分量。从视觉上看,结果如下图所示。

上面的集群表示为一个图形。请注意两个明显的组件,以及较大组件中的节点是如何连接的。每条边都是邻居关系。为了将孤立的节点链接到更大的组件,我们必须至少添加另一个节点(六边形)。

NetworkX 包通过一个简单的查询证实了我们的直觉。

nx.number_connected_components(g)

这个查询返回值 2,我们甚至可以查询组件是什么。

list(nx.connected_components(g))

该查询生成一个列表,其中包含每个连接组件的一组节点。在这种情况下,结果如下。

[{'8c274994cbb45ff'},
 {'8c274994c85a3ff',
  '8c274994c85a7ff',
  '8c274994c85b1ff',
  '8c274994c85b3ff',
  '8c274994c85b5ff',
  '8c274994c85b7ff',
  '8c274994c85bdff',
  '8c274994cbb49ff',
  '8c274994cbb4bff',
  '8c274994cbb51ff',
  '8c274994cbb59ff',
  '8c274994cbb5bff',
  '8c274994cbb5dff'}]

现在,我们可以迭代这两个组件,并尝试找到它们之间最短的桥。幸运的是,H3 用一个在两个六边形之间“画线”的功能来拯救我们。下面的函数使用此服务来查找两个不同连接组件的任意两个六边形之间的最短可能直线。

该函数遍历输入列表中的前两个连接组件,并枚举它们之间所有可能的“桥”。选定的桥要么是枚举中最短的桥,要么是只有三个元素的第一个桥。

一旦我们有了桥,我们就可以在两个组件之间构建它,生成一个新的图,并进行迭代。找到最新的连接组件列表,如果我们有多个组件,重新运行整个列表。

下面是整个过程。

请注意,我们只保留桥中的内部六边形,因为外部六边形已经存在于连接的组件中。上面的代码还会在数据库中插入新的集群点。

现在,我们确信所有的集群都已连接并存储在数据库中。那么给它们命名呢?

集群命名

遵循笔记本中的这一部分*7-cluster-names.ipynb*

本文中的最后一个挑战是在不使用反向地理编码服务的情况下获得聚类名称。我们将使用 OSM 立交桥 API 来查询地理数据,并使用它来分配名称。每个查询都需要一个地理边界框,所以我们必须首先从数据库中获取它们。

现在可以跨线查询了,但是我们需要做额外的准备,以避免通过缓存所有返回的数据来加重公共 API 的负担。这个策略将允许我们在出错的情况下防止发出重复的调用。为此,我们创建了一个特定的目录,将所有收集到的数据存储为 JSON 格式的文件。请注意,如果您决定返回并调整集群定义,您将必须擦除所有缓存文件,因为集群编号可能会发生变化。

该函数在提取文件缓存的同时检索与集群相关的 OSM 数据。

我们现在可以迭代集群集合,并使用下面的代码计算相关的名称。

上面的代码有两处值得注意的地方。首先,我们使用一个转换 JSON 编码数据的辅助函数来构建每个 OSM 网络对象。第二,聚类名称是定义聚类本身的点集的函数。该函数计算距离每个输入点最近的 K 个位置,并使用简单的投票机制检索前两个最常见的街道名称。最终的集群名称仅仅是这两个名称的串联,因为我们正在命名街道交叉口。

位于帕卡德路和卡彭特路交叉口的一个命名集群。

结论

在本文中,我展示了一些处理地理聚类的技术,从聚类过程本身开始,然后是地理围栏过程,最后是一个轻量级地理编码器。

关于这些数据还有很多需要探索的地方,我打算在以后的文章中这样做。最令人兴奋的模式之一无疑是车辆在两个集群之间行驶时的路线。敬请关注。

参考

长度麦金尼斯,j .希利,s .阿斯特尔斯, hdbscan:基于层次密度的聚类,《开放源码软件杂志》,第 2 卷,第 11 期。2017

Ester,m .,Kriegel,H.P .等人(1996)一种基于密度的算法,用于在带有噪声的大型空间数据库中发现聚类。KDD,226–231

汽车能源数据集(VED),用于汽车能源消耗研究的大规模数据集

相关文章

中型数据集

绘制英国交通事故热点图

优步 H3 的地理空间索引

油管(国外视频网站)

闪电对话:用 HDBSCAN 集群

[## joo Paulo Figueira—数据科学家—TB . LX by Daimler Trucks & bus | LinkedIn

查看 joo Paulo Figueira 在全球最大的职业社区 LinkedIn 上的个人资料。圣保罗列出了 1 份工作…

www.linkedin.com](https://www.linkedin.com/in/joao-paulo-figueira/)

2020 年地理数据科学最佳书籍

原文:https://towardsdatascience.com/geographic-data-science-best-books-in-2020-f5fab770de16?source=collection_archive---------19-----------------------

地理数据科学方面的最佳书籍(大部分免费,可在线获得)

莎伦·麦卡琴在 Unsplash 上的照片

今年或最近出版了许多关于地理空间数据科学的优秀书籍。事实上,随着学习资源的提供以及地理空间数据科学图书馆的成熟,这是学习地理空间数据科学的最佳时机。

在我发表了一篇关于地理空间数据科学课程的文章后,一些读者问我地理空间数据科学资源中最好的书籍。

[## 2020 年如何免费学习地理空间数据科学

免费的在线课程,学习最先进的地理空间数据科学。

towardsdatascience.com](/how-to-learn-geospatial-data-science-for-free-in-2020-f486d91adfc7)

如果你喜欢通过读书来学习,这篇文章是给你的。我在这里分享地理数据科学中最好和最新的书籍。其中一些书正在制作中,可以在网上免费获得,这是一个很好的早期学习和帮助作者的机会。

1.使用 PySAL 和 PyData 堆栈的地理数据科学(工作正在进行中)

[## 主页

这本书提供了工具,方法和理论,以满足当代数据科学应用的挑战…

地理数据.科学](https://geographicdata.science/book/intro)

地理数据科学与 PySAL 和 PyData 堆栈,是学习地理数据科学的优秀入门书籍,为初学者和高级学习者提供了广泛的学习资源。这本书既包括地理空间计算的理论方面,也包括代码的实际例子。由于本书的作者是 PySAL、Python 空间分析库和 Geopandas 等 Python 库的贡献者,因此本书的内容与地理空间数据科学 Python 环境紧密集成。

这本书正在编写中,可以在网上免费阅读。 GitHub 仓库也有 Jupyter 笔记本,你可以试验、采用或扩展。

2.使用 R (2019)进行地理计算

[## 用 R 进行地理计算

用 R 进行地理计算是为那些想用开源软件对地理数据进行分析、可视化和建模的人设计的…

geocompr.robinlovelace.net](https://geocompr.robinlovelace.net/)

r 语言的地理空间数据可视化的简单和优雅经常让我吃惊。如果你想开始学习地理空间数据分析的 R 语言,这是现有的最好的书,它在网上是免费的。即使你刚开始学习 R 语言,如果你已经有一些地理信息系统的背景知识,这本书也能帮助你。

3.使用 Python 掌握地理空间分析(2018)

[## 使用 Python 掌握地理空间分析

您的浏览器似乎禁用了 JavaScript。为了在我们的网站上获得最佳体验,请确保在…

www.packtpub.com](https://www.packtpub.com/gb/application-development/mastering-geospatial-analysis-python)

这本书涉及了地理数据分析和 Python 编程的许多方面,为读者提供了在这些选定的主题中可能做的事情。本书涵盖的主题包括地理空间数据的云计算、使用 GeoDjango 和 Flask 的 web 制图以及几个著名的地理数据科学库。我发现它更像是一个案例研究,而不是一本需要学习的教科书,尽管如此,它提供了一个关于代码实现的很好的主题选择。

4.使用 Python 学习地理空间分析(2019)

[## 使用 Python 学习地理空间分析-第三版

了解地理空间数据分析的核心概念,以构建可操作的、有洞察力的 GIS 应用程序

www.packtpub.com](https://www.packtpub.com/gb/programming/learning-geospatial-analysis-with-python-third-edition)

用 Python 学习地理空间分析是一本优秀的书籍,用 Python 实现了地理数据分析的底层实现。在本书中,您可以学习地理空间任务的 API 和通用算法。它包含了大量的 python 代码,用于大多数地理空间数据处理任务,如计算距离、缓冲区分析和处理遥感数据。

5.用于地理数据分析的 Python 简介(工作进行中)

[## 用于地理数据分析的 Python 简介-用于地理数据的 Python 简介…

附录:有效使用 Python 附录包括有效使用 Python 的信息:如何…

pythongis.org](https://pythongis.org/index.html)

这本书的资料还没有发布。然而,在明年书出来之前,所有的材料都是在网上开发的。我认为这将是对 Python 中地理空间数据分析书籍的一个相当大的补充。这本书的内容非常优秀,包括一个均衡的课程。由于它是赫尔辛基大学提供的两门课程的结合,课程从基础开始,并逐步发展到高级水平。一旦资料可以在网上找到,请留意这本书。

6.地理空间数据科学快速入门指南(2019)

[## 地理空间数据科学快速入门指南

您的浏览器似乎禁用了 JavaScript。为了在我们的网站上获得最佳体验,请确保在…

www.packtpub.com](https://www.packtpub.com/big-data-and-business-intelligence/geospatial-data-science-quick-start-guide)

地理空间数据科学快速入门指南是一本介绍性书籍,提供了使用 Python 的实用地理空间数据科学。书中涵盖的主题包括探索性数据分析,地理围栏和地理空间数据的机器学习应用。我应该在这里提一下,我是这本书的合著者,因此在列表的最后一项。

结论

这些书是我最喜欢的关于学习 Python 和 r 的地理空间数据分析的书。如果你的阅读列表中有其他你认为可能是这个列表的极好补充,请告诉我。

GeoHealth:医疗和社会数据的统一仪表板

原文:https://towardsdatascience.com/geohealth-a-unified-dashboard-for-medical-and-social-data-d33a03b94c2e?source=collection_archive---------64-----------------------

介绍

GeoHealth 是一个公共卫生仪表板模型,旨在展示和连接来自不同来源的医疗和社会数据。目前的版本侧重于英格兰,使用公共卫生和社会人口统计信息,这些信息可从大约 8000 例手术的一般实践层面获得。作为该项目的一部分,收集和清理了他们的数据集,可对其进行查询,以生成国家、区域和地方各级疾病流行率、风险因素和社会贫困的地理空间表示。

一旦完成,仪表板可以支持公共卫生政策的形成和有关疾病治疗和预防的循证决策。数据来源是由 NHS 英格兰和公共健康英格兰管理的全科医疗数据中心国家全科医疗概况,它们建立了长期仪表板来监控药物处方行为疾病流行率和风险因素。仍处于发展阶段的地理健康受到了这些努力的启发,不应作为替代方案进行咨询。目的是建议开发一个统一的可视化平台,连接健康、人口和社会剥夺数据,并支持机器学习、统计和流行病学工具的开发。

仪表板演示

药物利用和疾病流行

该项目的大部分数据是处方数据,自 2011 年以来,每个月在英格兰的所有实践中均可获得。这些数据集可以支持药物利用研究,以量化、理解和评估药物的处方、配药和消费过程,并测试干预措施,以改善人群对药物的使用。该仪表板允许用户比较不同地理区域的药物利用(DU ),将 DU 与这些区域的发病率概况相关联,检查特定药物 groups⁴的治疗效果,或审查处方政策的影响,如英国 5 年抗菌药物耐药性策略。⁵

处方数据也被检查作为慢性病患病率的指标,其中监测是复杂的,并且经常依赖于临床和管理来源。geohealth 的流行率来源于质量和结果框架(QOF) ,该框架旨在监控医疗质量。由于报告是自愿的,并且由于病例发现、编码定义和实践记录之间的差异,QOF 登记册可能不符合流行病学标准(技术附件,2015-16,第 9 页);在一些研究中,它们被确定为低估了健康调查中模拟或测量的某些疾病的发病率。⁸ ⁹ ⁰这些因素使得使用 QoF 数据来解释逐年变化或评估适应症的实际患病率变得困难。然而,它们可能有助于确定地理变异的模式,以及对流行和威胁生命的疾病的诊断不足。

对处方和流行之间的复杂关系感兴趣的用户可以选择药物和适应症,放大特定的实践及其领域。图 1 中的曲线显示了糖尿病的患病率与抗糖尿病药物的量(a,c)以及抑郁症的患病率(18 岁以上)与每次治疗中开出的抗抑郁药的量(b,d)的关系。图 a 和 b,为利兹、布拉德福德和韦克菲尔德绘制,以呈现地区级别的流行率和处方;图 b 和 d 显示了单个临床委托组(Barnet,North London)的数据,该临床委托组构成了英格兰医疗保健提供的本地单位。流行程度用点的半径来表示,而它们的颜色则表示处方药物的数量。深色小圆圈表示诊断和处方水平可能不匹配,反之亦然。如果是这种情况,则该图表明与糖尿病和精神疾病相关的高处方或诊断不足。

图 1

新冠肺炎的风险群体

年龄、性别和背景疾病与严重感染新冠肺炎病毒的风险之间的关系表明,GeoHealth 也可能告知疫情的遏制措施。NHS 呼吁所有人呆在家里,以帮助阻止冠状病毒的传播,但重点是受某些慢性疾病影响的人,70 岁或以上的人和明显超重的人(身体质量指数> 40)。虽然建议他们遵守更严格和更谨慎的规定,但他们的地理差异可能会通知区域级别的预防计划,并用于相应地更新感染模型。图 2 显示了他们的地理差异,显示了冠心病(a)、糖尿病(b)、肥胖症(c)和慢性阻塞性肺病(COPDd)。模式各不相同,但总体情况是,与伦敦地区相比,英格兰北部和沿海地区的发病率有所上升。

图 2

性别和年龄组

可以结合人口统计数据探索显示高水平疾病流行的区域。实践中的性别和年龄构成被确定为对所诊断的疾病的流行程度和可能使用的药物有很大影响。⁴心血管疾病、神经系统疾病和糖尿病的发病率随着年龄的增长而增加,心理健康带来的最大负担发生在年轻人身上。冠状病毒感染流行的研究表明,在⁵ ⁶,男性的病死率高于女性,这一点在 2002-2003 年 SARS 流行期间、最近的中东呼吸综合征爆发和实验室研究中都有发现。⁷

图 3 比较了邻近的北中部城市诺丁汉(a)和特伦特河畔斯托克(b)的肥胖患病率(%)(点颜色)和 70 岁或以上患者的患病率(%)(根据圆圈的大小)。他们的图表显示了人口统计学和发病率模式的地方和区域差异。在诺丁汉,老龄化和肥胖的人口出现在城市的边缘,而在斯托克,他们更靠近市中心。观察到的变化表明了新冠肺炎风险的地理分布,这可能为城市、区域和次区域级别的遏制计划提供信息,也许是通过结合这些地区护理院的数据。

图 3

健康和贫困

对疾病和健康因素的监测还应了解所研究地区的社会经济状况。社会剥夺被确定为高血压、癫痫、冠心病、肺病、糖尿病和各种类型的癌症⁰ ⁸ ⁹ ⁴患病率增加以及为精神疾病开出更多抗生素和药物处方的主要决定因素。⁰:仪表板使用多重剥夺指数(IMD) ,这是英国相对剥夺的官方衡量标准,计算方法是收入(22.5%)、就业(22.5%)、教育、技能和培训(13.5%)、健康和残疾(13.5%)、犯罪(9.3%)、住房和服务障碍(9.3%)以及生活环境(9.3%)的地区级加权总和。这些分数是使用小范围的人口普查变量计算出来的,这些变量的值被标准化或转换,标准化为当地、地区或国家的平均值,并根据加权方案进行组合。

贫困指数通常对城乡差异敏感,但可能有助于比较城市之间和城市内部的差异,以确定需要重点关注的风险热点。伦敦玛丽女王大学全球公共卫生教授大卫·麦考伊批评英国政府不加批判地坚持科学顾问,没有考虑病毒对老年人和男性的不成比例的影响,以及“控制措施的附带损害将不成比例地影响更贫穷和更边缘化的社会阶层。”在疫情之前、期间和之后,应对这些影响的努力可以通过探索健康地理和贫困指数来识别健康和经济风险人群。

图 4 探讨了中西部地区 COPD 的患病率,重点是伯明翰和附近的伍尔弗汉普顿市。COPD 患病率单独显示,并与健康和残疾指数(a)或住房和服务障碍指数(b)相关。前者衡量过早死亡的风险和因身体或精神健康状况不佳而损害生活质量的风险,而后者指的是商店、手术室、学校和邮局以及负担得起的住房的可及性,包括家庭过度拥挤和无家可归。虽然 COPD 患病率不超过人口的 5%,但其与剥夺措施相关的标准化可能指向城市间的位置,在这些位置,由于住房条件、获得服务的机会或人口的健康状况,新冠肺炎风险可能会增加。

代码和开发

该项目是用 Python(3.7 版)编写的,使用了用于数据可视化和用户交互的 ipywidgetsbokeh 库。数据保存在的 PostgreSQL 数据库中,该数据库托管在 AWS 的一个私人账户中,该账户对所有用户开放只读访问。虽然不能作为 web 应用程序使用,但仪表板可以下载并在 Jupyter 笔记本中运行,这是一个方便的数据科学研究环境。代码和数据可免费获得,以支持数据探索、连接到额外的数据源,并在需要时开发用户界面。该软件包以模块化方式设计,允许分析师、开发人员和数据科学家使用 SQL 或 BI 软件查询数据,构建统计和机器学习模型,添加数据集和选择菜单,使仪表板适应其他国家的数据或改进用户界面。

1.Wettermark B,Elseviers MM,Almarsdottir ABirna 等(2016)药物利用研究导论。在:药物利用研究。

2.vlahovic-palc evski V,Wettermark B,Ibáez L 等人(2016)不同地理区域药物利用的比较。药物利用研究:151–159

3.拉米卡内·DC、吉里·布里、帕塔克·奥克等人(2006)尼泊尔西部一所教学医院门诊患者的发病率概况和处方模式。麦吉尔医学杂志 9:126–132

4.Lipska KJ,Yao X,Herrin J 等人(2017)药物利用、血糖控制和严重低血糖发生率的趋势,2006-2013。糖尿病护理,40:468–475

5.英国卫生和社会福利部(2019)2013 年至 2018 年五年期抗微生物药物耐药性战略。

6.斯洛伯·LCJ、Füssenich K、Wong A 等人(2019)使用随机森林算法从药物利用数据中估计疾病流行率。欧洲公共卫生杂志 29:615–621

7.Chini F,Pezzotti P,Orzella L 等(2011)我们能使用药房数据来估计慢性病的患病率吗?多个数据源的比较。BMC 公共卫生 11: 688

8.Standing P,Deakin H,Norman P 等(2005)高血压——英国全科医疗质量驱动下的高血压检测、患病率、控制和治疗。英国心脏病学杂志,12:471–6。

9.Kendrick T,Stuart B,Newell C 等人(2015)2003-2013 年英国初级保健中记录的抑郁症比率的变化:经济衰退影响的时间趋势分析和全科医生合同质量结果框架(QOF)。情感障碍杂志 180:68–78

10.阿什沃斯 M、梅迪纳 J 和摩根 M (2008)英国社会剥夺对血压监测和控制的影响:来自质量和结果框架的数据调查。BMJ 337:1215–1218

11.Nacul LC,Soljak M & Meade T(2007)用于估计慢性阻塞性肺疾病人群患病率的模型:来自英格兰健康调查的横断面数据。人口健康指标 5:1–8

12.Soljak M,Samarasundera E,Indulkar T 等人(2011)英格兰诊断不足的心血管疾病的变化:全国横断面空间分析。BMC 心血管疾病 11: 12

13.周芳,于婷,杜锐等(2020)中国武汉地区成年新冠肺炎住院患者的临床病程和死亡危险因素:一项回顾性队列研究。柳叶刀 395:1054–1062

14.Lloyd DCEF,Harris CM & Roberts DJ (1995)特定治疗组年龄-性别相关处方单位(STAR-PUs):用于分析英格兰一般实践处方的权重。BMJ 311: 991

15.杨军,郑燕,苟 X 等(2020)新型武汉冠状病毒(新冠肺炎)感染的共病患病率:一项系统综述和荟萃分析。国际传染病杂志 94:91–95

  1. Worldometer。冠状病毒年龄、性别、人口统计(新冠肺炎)。访问日期:26.4.20

17.Channappanavar R,Fett C,Mack M 等人(2017)对严重急性呼吸综合征冠状病毒感染易感性的性别差异。免疫学杂志 198:4046–4053

18.Steer S,Pickrell WO,Kerr MP 等人(2014)英格兰癫痫患病率和社会经济剥夺。癫痫症 55:1634–1641

19.牛顿 JN,布里格斯 ADM,默里 CJL 等人(2015)英国的健康变化,按英国地区和贫困地区分析,1990-2013 年:2013 年全球疾病负担研究的系统分析。柳叶刀 386:2257–2274

20.Hull SA,Aquino P & Cotter S(2005)解释了伦敦东部抗抑郁药处方率的变化:一项横断面研究。家庭实践 22:37–42

21.Hope EC、Crump RE、Hollingsworth TDeirdre 等人(2018 年)确定了英国的做法,即高抗生素处方说明了共病和变异的其他合法医学原因。临床医学 6:36–41

22.Bertin M,Chevrier C,Pelé F 等人(2014 年)贫困指数可以合法地用于城市和农村地区吗?国际健康地理杂志 13: 22

23.国家统计局(2009 年)《理解贫困模式》。区域趋势 41:93–114

24.Nacul L,Soljak M,Samarasundera E 等人(2011)英格兰的慢性阻塞性肺病:基于模型的预期患病率与从全科医学数据中观察到的患病率的比较。公共卫生杂志 33:108–116

地理健康:建立和建筑

原文:https://towardsdatascience.com/geohealth-build-up-and-architecture-29f3b45e68fb?source=collection_archive---------49-----------------------

或者如何从头开始构建 Python 仪表板

这篇文章介绍了 GeoHealth dashboard 的构建流程和架构,是项目文档的一部分,也是数据科学 dashboards 的一个诀窍。GeoHealth (Python,3.7)利用 ipywidgetsbokeh 库来捕捉用户输入并提供交互式地理空间图。这些数据是从一个私有账户中的 AWS 上托管的 PostgreSQL 数据库中查询的。该项目可以通过结合地块内外的小部件来构建您的仪表板原型,与云基础设施连接,并查询大数据和公开可用的来源。Jupyter 笔记本通常与 ipywidgets 和/或 bokeh 一起使用,以构建和共享交互式可视化。数据准备和查询代码的详细和图形化描述可能对希望增强笔记本体验的数据科学家或寻求分析后端的前端开发人员有用。文章随后向对 GeoHealth 感兴趣的读者以及希望在其他项目中使用 geo health 或其组件的其他人发表。

数据来源和准备

仪表板通过查询英国卫生和其他政府机构公开提供的数据来支持卫生地理的研究。如图 1 所示,准备工作从识别可以查询医疗、社会和地理数据的门户开始。 NHS Digital 是英格兰国家医疗服务系统的数字化分支,提供个体手术(GP 实践)层面的多样化数据集,包括治疗处方、疾病患病率、性别-年龄登记和每个实践的地址。

图 1:准备阶段(来源:作者)

数据集是手动下载的,或者在处方和性别/年龄(每月可用)的情况下,使用特定的爬虫程序下载。坐标文件可从英国国家测绘局获得,用于每个邮政编码,通过 GP 实践的邮政编码进行过滤(2)并结合形成 GP 位置文件,包含每个实践的名称、地址坐标和区域信息(3)。邮政编码也被用来从英国住房、社区和地方政府部为此目的建立的门户网站中提取贫困指数(4)。年度电子表格中可用的疾病患病率数据被下载(5),然后在笔记本中进行探索和预处理,就像对位置和剥夺数据集所做的那样(6)。每个数据集都与一个表构建脚本匹配,利用 Python PostgreSQL 连接器读取数据集并将其加载到数据库上的指定表。PostgreSQL 是一个开源的关系数据库,可以扩展到远远超过项目中的数据大小,并且可以通过编程或通过一个方便的用户界面来访问。表名由特征和周期组合而成(例如:gender_age_201907 ),以支持用户查询检索(见下文)。

处方数据集列出了英格兰所有诊所开出的所有药物、敷料和器械,每月提供大约 1000 万行和 1GB 的数据(2)。它们的文件大小需要特定的准备过程。爬虫和数据库连接器脚本被加载到一个虚拟机实例(EC2,Ubuntu 18:04,t2.micro machine ),并用于将文件从 NHS 数字门户复制到 S3 桶作为备份。这些文件随后被从这个桶运送到托管在 AWS 的关系数据库服务(RDS) 上的 PostgreSQL 数据库。Postgres 的安全特性允许将数据库管理员与仪表板用户角色分离,仪表板用户角色可以被授予只读角色权限。与家庭网络相比,EC2 实例享有增强的连接性,家庭网络被证明对于从 NHS Digital 向 S3 下载和上传文件是有用的。现在,所有数据集都存储为关系表,接下来就是构建具有用户界面、查询机制和绘图功能的仪表板了。

查询和绘图

为了增强代码的可重用性,仪表板以模块化的方式编写,这样它的功能模块(图 2)可以作为独立组件在其他项目中进行修改。主笔记本的运行构建选择部件开始,这些部件从每个特性的列表中获取它们的值。用户被指示选择最多两个特征,每个特征的测量值和感兴趣的时间段。选择值以数据帧的形式收集,并传递给 准备 模块(2)中的功能。它们验证选择,提取每个特征的表的名称,并捕获图标题的搜索词(3)。表名被添加到选择数据帧中,该选择数据帧被传递到合适的类build _ statements模块(4),该模块将搜索参数插入到合适的 SQL 语句中,这些 SQL 语句将被传递到查询数据库的 查询 模块(5)。为了保持过程的模块化,每个感兴趣的特性都被转换成一个单独的语句,用于查询一个单独的表。例如,将性别百分比与肥胖流行率相结合的选择将被转换为性别年龄表的语句和同一时期流行率表的另一个语句。各个查询的结果被收集到各个数据帧中(6)。这些与实践位置数据结合成构成搜索结果的单个数据框架。****

图 2:解决方案架构(来源:作者)

用散景写的 plot 函数是用来通过数据点的颜色或半径来显示特征值的。由于颜色条的范围反映了所显示特征的最小值和最大值,偏离该范围的异常值会掩盖数据中的变异。例如,在 1–50 之间有 7000 个值且在 200 附近有 3 个异常值的数据将使用 1–200 范围来隐藏中间范围内的点。用户可以选择保留异常值,特别是如果目的是通过其他统计工具将数据作为一个整体来研究,或者如果目标是检测异常。但是,如果选择了默认(也是推荐的)选项,则异常值模块会应用图基规则来排除 1.5 个四分位数范围之外的点,并生成一个干净的数据集进行绘制。绘图模块获取数据集、标题的搜索词以及在笔记本中显示绘图或在单独的浏览器选项卡上显示绘图之间的输出选择,浏览器选项卡也将绘图保存在 HTML 文件中。除了可以用一行代码配置的缩放、平移和悬停功能之外,该图还应用了带有 JavaScript 回调的散景小部件来实现对特定地图区域的聚焦。除了绘图之外,用户还可以获得 csv 或 excel 格式的连接数据,以便通过其他 dahaboard 软件或分析工具进行探索。虽然代码的结构可以被克隆并用作库,但它的模块可以用作其他 ui 的查询工具,或者为其他功能和数据集定制数据科学接口。

用于数据分析的地理定位和地理编码仪器组

原文:https://towardsdatascience.com/geolocations-and-geocodes-instrument-set-for-data-analysis-5eb4e33a1677?source=collection_archive---------27-----------------------

数据科学提示

four square+geopy+leav 完美共生

Unsplash 上由 Aron 视觉拍摄的照片

地理对象、地址或坐标的大型数据集的分析需要一些固定的仪器。您需要提取关键数据,获得必要的细节,在地图上可视化数据点,并为分析或某种学习算法做好准备。我想以我的家乡城市为例,分享我在这些任务中使用的工具集。

1.使用 geopy 获取城市区域位置

城市的地理标签本身有一点信息,所以我们应该发现城市所有区域的坐标。对于大城市来说,这可能是一项复杂的任务,需要额外的邮政编码数据集、一些网络抓取工具或其他资源。嗯,我的家乡(第聂伯)不是很大,所以这里是它的地区:

['Amur-Nyzhnodniprovskyi',
 'Shevchenkivskyi',
 'Sobornyi',
 'Industrialnyi',
 'Tsentralnyi',
 'Chechelivskyi',
 'Novokodatskyi',
 'Samarskyi']

现在我们将使用地理包来发现这些地区的地理标签。默认的地理编码器对我们来说已经足够了,尽管你可以在文档页面上找到更多的 API。为了以防万一,我们将设置响应的最大延迟和尝试次数。

from **geopy**.geocoders import **Nominatim**
from **geopy**.extra.rate_limiter import RateLimitergeolocator = **Nominatim**(user_agent="dnipro",timeout=10)
geocode = RateLimiter(geolocator.geocode, min_delay_seconds=2)longitudes = []
latitudes = []
for region in dnipro_regions['Region']:
    location = geocode('{}, Dnipro'.format(region))
    longitudes.append(location.longitude)
    latitudes.append(location.latitude)

将坐标连接到我们的数据集并继续。

带有地理标记的区域

2.使用 Foursquare 获取咖啡馆和商店的详细信息

让我们假设,我们为孤独的游客开发推荐系统,他们想去一个外国城市的咖啡馆或食品店吃饭。为此,我们需要一个咖啡馆、餐馆、食品店等的列表。在每个城市区域的邻近地区。我们可以在地理定位服务的帮助下形成数据集。我更喜欢 Foursquare API。它有非常方便的端点来搜索不同的地点(像旅游场所,咖啡馆,汽车站等。)通过具体的坐标或在一些邻居、端点内发现场地细节、评级和许多其他东西。这是有据可查的,其免费帐户允许足够数量的调用,所以让我们来看看代码。

2.1.获取场地

首先,我们必须找到所有符合“咖啡馆或食品店”类别的场所。“探索” endpoint 将帮助我们完成这项任务:

venues_list=[]
for name, lat, lng in zip(names, latitudes, longitudes):
    url = 'https://api.foursquare.com/v2/venues/**explore**?&**client_id**={}&**client_secret**={}&**v**={}&**ll**={},{}&**radius**={}&**limit**={}'.format(CLIENT_ID, CLIENT_SECRET, VERSION, lat, lng, 3000, 200)

    results = requests.get(url).json()["response"]['groups'][0]['items']
    venues_list.extend([
        [name, v['venue']['name'], v['venue']['id'],
         v['venue']['location']['lat'],
         v['venue']['location']['lng'],  
         v['venue']['categories'][0]['name']
        ] for v in results]) nearby_venues = pd.DataFrame(venues_list)
    nearby_venues.columns = ['Region', 'Venue', 'Venue ID',
                             'Venue Latitude', 'Venue Longitude',
                             'Venue Primary Category'] 

我们只保存了对我们的目的重要的信息:位置坐标、名称、id 和主要类别。简单看一下我们的场馆数据:

现在,通过“场馆主要类别”一栏,只过滤我们需要的“食品和咖啡馆”类别,我们就可以开始下一步了。

2.2.获取场馆信息

我们的数据集包含大量的场馆,并附有它们的类别、位置和区域。信息量很大,但肯定不够。任何学习算法都需要更多的信息。所以,是时候测试另一个 Foursquare 端点了— “场馆详情”。它的主要参数是 venue ID,这是我们在上一步中获得的。

venues_list=[]
for venue_id in venues_dataset['Venue ID'].values:
    url_venue = 'https://api.foursquare.com/v2/**venues**/{}?&**client_id**={}&**client_secret**={}&**v**={}'.format(venue_id, CLIENT_ID, CLIENT_SECRET, VERSION)
    venue_results = requests.get(url_venue).json()["response"]['venue']

    venues_list.append([
        venue_results['location']['formattedAddress'],
        [el['name'] for el in venue_results['categories']],
        venue_results['likes']['count'] if 'likes' in venue_results else 0, 
        venue_results['rating'] if 'rating' in venue_results else 0,
        venue_results['hours']['isOpen'] if 'hours' in venue_results else np.nan
        ])venues_table = pd.DataFrame(venues_list)
venues_table.columns = ['Venue Address', 'Venue Categories',
                        'Venue Likes', 'Venue Rating',
                        'Venue Is Open']

API 响应中有很多细节,不过,我们将只使用其中的几个:扩展类别、用户点赞数、评级以及场馆是否暂时开放的信息。到这个时候,我们的连接了场馆细节的数据集就快完成了。

3.用叶子想象咖啡馆和商店

我们的“地理管道”的最后一步是地图的可视化,以获得整个画面。我最喜欢的工具是叶库,所以,没有更多的话,只有地图。

import **folium**
import matplotlib.cm as cm
import matplotlib.colors as colorsmap_venues_food = folium.Map(location=[lat, lon], zoom_start=12)colors_array = cm.rainbow(np.linspace(0, 1, 7))
rainbow = [colors.rgb2hex(i) for i in colors_array]for lat, lng, name, region in zip(
                         dnipro_venues_food['Venue Latitude'],
                         dnipro_venues_food['Venue Longitude'],
                         dnipro_venues_food['Venue'],
                         dnipro_venues_food['Region']):
    label = folium.Popup('{}, {}'.format(name, region))
    folium.CircleMarker(
        [lat, lng],
        radius=5,
        popup= label,
        color=rainbow[region_index],
        fill=True,
        fill_color='#3186cc',
        fill_opacity=0.7,
        parse_html=False).add_to(map_venues_food)

带有按区域分组的场馆的树叶地图

4.使用数据

然而,地理工具仅仅为我们提供了数据分析的基础。接下来的步骤取决于你。

我们可以统计每个地区的场馆数量:

gp_venues = dnipro_venues_food.groupby('Region').count()['Venue']

grouped_venues.plot.bar()

找出每个地区的前 5 个类别:

dnipro_onehot = pd.get_dummies(venues[['Venue Primary Category']])
dnipro_onehot['Region'] = venues['Region']top_5 = dnipro_onehot.groupby('Region').sum().reset_index()for i in np.arange(top_5.shape[0]):
    row = top_5.iloc[i, 1:].sort_values(ascending=False)
    top_5_sorted.iloc[i, 1:] = row.index.values[0:5]

或者我们甚至可以将这些值转换成学习算法的特性表(参见 GitHub 上的完整代码)。

继续你想要的任何例子。

你可以看到,提供的“地理管道”让我们能够非常灵活地为您的项目提供坐标、地址和不同的位置,这肯定可以用于进一步的分析。您可以在我的 GitHub 上的 Jupyter 笔记本中看到当前的工作示例:

[## 中级/中等 _jupyter_notes

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/Midvel/medium_jupyter_notes/blob/master/geolocation_for_analysis/geolocations-for-analysis.ipynb)

你可能会注意到,“地理管道”包含了我自己更喜欢的工具。但是它可以扩展,元素可以改变。您使用哪些服务和工具来处理地理数据?

几何布朗运动

原文:https://towardsdatascience.com/geometric-brownian-motion-559e25382a55?source=collection_archive---------21-----------------------

模拟资产价格的随机、非线性过程

照片由来自佩克斯约翰尼斯·拉普里奇拍摄

如果你读过我以前的任何一篇金融文章,你会注意到在很多文章中我提到了一种被称为几何布朗运动的扩散或随机过程。我想在一篇完全致力于此的文章中正式讨论这个过程,它可以被看作是对鞅和马尔可夫过程的扩展。在本文中,我想讨论这个过程的目的和实际应用。

理论应用

解释几何布朗运动的最佳方式是给出一个需要模型本身的例子。考虑一个投资组合,该投资组合由一个期权和相对于期权 delta 的标的资产的抵消头寸组成。

对冲投资组合

变量:

  • P — 标的资产的股份
  • S — 标的资产的价格
  • Q — 衍生产品(期权)的份额
  • D — 导数的值
  • H — 投资组合的价值

对于那些有更多金融经验的人,或者读过我以前文章的人,你会认为这是布莱克-斯科尔斯理论期权定价模型的论据(完整的推导和解释见推导布莱克-斯科尔斯模型)。注意,我们可以确定投资组合中任一资产的份额( PQ ),但是我们不能控制它们的值( SD )。为了确定如何基于该投资组合对期权的价格进行建模,我们首先需要确定对基础资产进行建模的方法。

实际应用

虽然理论应用很重要,但你的主要兴趣可能是作为一名实践者。假设你是一个投资组合经理,基于你团队的市场研究,你试图确定你投资组合的平均回报。将几何布朗运动与你的研究结合起来,你可以得出投资组合中每种资产可能遵循的不同样本路径。这将给你一整套与投资组合表现相关的统计数据,从最大提款到预期回报。几何布朗运动也可以用于衍生产品的定价。如果你是一些异国情调的保险商,你需要一种方法来确定保费收取的风险。实现这一点的一种方法是在由几何布朗运动生成的一组样本路径中以编程方式实现奇异值,将平均收益贴现到现值,从而得到奇异值的公允价值。关于代码的完整解释,请参见 Python 为外来物种定价或查看以下视频。

无论是哪种应用,我们都需要一种方法来建模底层资产。

数学符号

为了在理论/实践中更准确地模拟基础资产,我们可以修改布朗运动,以包括一个漂移项,捕捉随时间的增长和对该增长的随机冲击。

几何布朗运动的表达式实际上很简单…

几何布朗运动

变量:

  • dS — 一段时间内资产价格的变化
  • S — 前一(或初始)期间的资产价格
  • 该时间段的预期收益或漂移
  • dt — 时间的变化(一段时间)
  • σ — 波动率术语(价差的一种度量)
  • dW — 布朗运动项的变化

条款:

  • dS/S — 返回给定的时间段
  • dt — 该时间段的预期收益
  • σdW — 对该时间段预期收益的随机冲击

由于这个模型中存在一定程度的随机性,每次它被用来模拟资产价格时,都会产生一条新的路径。

让我们使用这个等式和 Python 来为资产生成一个示例路径。

首先,我们需要构建一个接受与该模型相关的参数的类…

接下来,我们需要创建一个函数,它基于几何布朗运动和我们的 time_period 的大小向未来前进一步,直到我们到达 total_time。

注:time_period 和 total_time 均为年化含义 1,无论哪种情况,均指 1 年,1/365 =每日,1/52 =每周,1/12 =每月。

模拟函数中,我们基于几何布朗运动创建资产价格的新变化,并将其添加到前一期的价格中。这种变化可能是正的、负的或零的,并且基于漂移和随机性的组合,其正态分布的平均值为零,方差为 dt 。这在直觉上是有意义的,越大的 dt (时间或时间段的变化)样本路径的集合将越分散。为了在将来创建一个单一的样本路径,我们可以简单地创建一个 GBM 类的实例。然而,如果我们想要生成遵循几何布朗运动的样本路径的多个实例(并绘制它),我们可以编写以下代码…

因此,我们根据使用 matplotlib 绘制的参数为资产生成 1000 个样本路径…

结论

现在你应该对几何布朗运动及其理论/实际应用有了牢固的掌握。如果你对带代码的现场解释感兴趣,你可以看看下面的视频…

几何深度学习:快速浏览

原文:https://towardsdatascience.com/geometric-deep-learning-a-quick-tour-12cef72492ca?source=collection_archive---------70-----------------------

下面的文档提供了几何深度学习中一些基本概念的旋风之旅。

克林特·王茂林在 Unsplash 上拍摄的照片

找到这篇文章的乳胶版本在这里

下面的文档提供了几何深度学习中一些基本概念的旋风之旅。数学推导可能没有严格地显示出来,有些方程没有证明。这样做是为了使文档简短而又足够全面。更深入的分析请参考布朗斯坦等人(2017)、龚(2018)、基普夫等人(2017)、哈蒙德等人(2011)、等人(2011)。这是一份动态文档,如果您发现任何错误或不一致之处,请告诉我,我会尽快修复。我绝不是这方面的专家,因为这篇笔记只是为了我自己的学习目的而写的。

我们首先回顾图中拉普拉斯矩阵的概念及其特征值分解。接下来,我们在图中定义卷积运算,并表明它等价于在图的谱域中应用滤波器,这里的谱指的是拉普拉斯算子的特征值。我们表明,通过构造,谱卷积类似于将拉普拉斯算子应用于函数。最后,我们展示如何用切比雪夫多项式的和来近似拉普拉斯滤波器,以降低算法复杂度(因为执行完整的特征值分解是 O(n ) 其中 n 是图中顶点的数量。

图拉普拉斯算子

假设我们有一个无向、连通且加权的图 G = (V,e,W) 其中 V 是一组 |V| = n 个顶点, E 是一组边, W 是每条边的一组权重wᵢⱼI ~ j。定义 D 为度矩阵,其中 d =diag(σⱼwᵢⱼ).归一化图拉普拉斯δ可以定义如下。

我们可以如下对拉普拉斯矩阵δ执行特征值分解。

光谱卷积

受傅立叶变换中卷积运算的启发,我们将图形卷积定义为对拉普拉斯谱分量应用滤波器。简而言之,这个想法是将输入函数 f 投影到它的“傅立叶”基,或者这里借助于φf的拉普拉斯特征向量。将基乘以滤波后的特征值ĥ(λ),得到ĥ(λ)φf。最后,通过与φ的点积应用“逆傅立叶变换”,得到φĥ(λ)φf

在进行一些重新排列后,我们可以看到,等式的右侧可以转换为等式 5 中归一化拉普拉斯矩阵δ=φλφᵀ的函数。

现在,与卷积神经网络类似,我们希望应用 1 个以上的卷积滤波器,并增加一个非线性输出转换。假设我们使用带有 ξ 非线性变换的 p 滤波器,频谱卷积网络定义如下。

用切比雪夫多项式逼近

ChebNets

等式 12 的主要问题是我们需要计算所有特征向量,复杂度为 O(|V|)。当我们用|V| > >处理非常大的图时,这是不可伸缩的。ChebNets 的主要思想是用一组正交切比雪夫多项式来逼近φĥ(λ)φᵀ,这些多项式可以使用以下公式迭代计算。

我们首先用 r 切比雪夫多项式的加权和来近似特征值滤波器,其采用变换后的特征值矩阵λ^.需要这种变换,因为只有当输入域区间在 [-1,1】时,切比雪夫多项式才形成正交基。同时,特征值范围从【0,λ ,ₘₐₓ。因此,为了将后者转换成前者,我们可以应用 2x/λ ₘₐₓ -1 ,使得对于 x = 0,(2(0)/λₘₐₓ-1 = -1),对于 x = λₘₐₓ,(2λₘₐₓ/λₘₐₓ -1 = 1)。

现在,我们可以利用等式 12,用切比雪夫多项式代替滤波器。注意λ^ = 2λ/λₘₐₓ-I类似的,δ^ = 2δ/λₘₐₓ-I。通过重排,我们可以将右侧转换为应用于归一化拉普拉斯δ^的切比雪夫多项式之和。

图表网络

GraphConvNets 是 ChebNets 的一个特例,这里我们只取 2 个 Chebyshev 多项式项 r = 2 。由于使用了归一化拉普拉斯δ,已经证明了 λₘₐₓ = 2 。我们可以用等式 21 代替给定的假设。

我们现在有了一个纯粹使用度矩阵 D 和权重矩阵 W 定义的图形卷积网络。为了进一步简化,我们假设α₀ = -α₁ = α。

尽管在实践中,由于本征值在[0,2]范围内,重复应用这种乘法可能会导致数值不稳定。因此,我们通过让ŵ= w+I和 d̂= diag(σ{ j≠I } ŵᵢⱼ).正如在 Kipf 和 Welling (2017)中所写的,这相当于设置以下重整化技巧:I+d^(-1/2)w d^(-1/2)= d̂^(-1/2)w d̂^(-1/2)

使用这些假设,GraphConvNets 避开了对切比雪夫多项式的显式计算的需要,并导致了对每个顶点的邻域的加权和运算的纯应用。

参考

Bronstein,M. M .、布鲁纳,j .、LeCun,y .、Szlam,a .、Vandergheynst,P. (2017)。几何深度学习:超越欧几里德数据。IEEE 信号处理杂志,34(4):18{42。arXiv: 1611.08097。

龚,S. (2018)。几何深度学习。伦敦帝国学院硕士论文。

Hammond,D. K .,Vandergheynst,p .,和 Gribonval,R. (2011)。基于谱图论的图的小波。应用和计算谐波分析,30(2):129{150。

舒曼,D. I .,Vandergheynst,p .,和 Frossard,P. (2011)。分布式信号处理的切比雪夫多项式逼近。2011 年传感器系统和研讨会分布式计算国际会议(DCOSS),第 1-8 页。arXiv: 1105.1891。

T.Kipf,M. Welling,图卷积网络半监督分类ICLR 2017

线性回归的几何解释

原文:https://towardsdatascience.com/geometric-interpretation-of-linear-regression-dd10601a85b1?source=collection_archive---------32-----------------------

了解如何使用几何解释推导线性回归的成本函数,并从头开始实现算法。

艾萨克·史密斯在 Unsplash 上拍摄的照片

线性回归是一种建模标量响应(或因变量)和一个或多个解释变量(或自变量)之间关系的线性方法。在几何解释术语中,线性回归算法试图找到尽可能最适合数据点的平面或直线。线性回归是一种预测真实值的回归技术。

术语“寻找最符合数据点的平面”是什么意思?**

图 1:示例二维数据集的表示

对于上面给出的二维数据集样本(图 1),覆盖尽可能多的点的直线的一般方程是 y = m*x+c,其中 m 是直线的斜率,c 是截距项。线性回归算法试图找到成本函数最小化的线/平面。在本文的后面,你会知道一个成本函数是如何推导出来的。

我们将上述平面方程表示为 y = w1*x + b

图 2:样本三维数据集的表示

类似地,对于样本 3 维数据集(图 3),最适合尽可能多的点的平面方程是y = w1 * x1+w2 * x2+b。

同样的等式可以扩展到 d 维数据集:

所以,我们需要找到上面方程的一个平面 (W,b) 来最好地拟合大多数数据点。

深究推导几何解释的算法:

图 3

对于任意点 P (图 3), y_iAct 为该点的实际输出值,而 y_iPre 为预测值。因此,误差可以计算为:

由于误差可以是正的,也可以是负的,因为 y_iPred 可以在平面/直线之上或之下,所以为了保持正误差,我们对每个 x_i 的误差求平方

来源:谷歌地图,y=x 的地图

误差函数遵循抛物线,这意味着误差(Y 轴)将始终为正。

我们需要最小化所有点集的误差,这被称为 MSE(均方误差)。

而线性回归的成本函数是:

成本函数定义了我们需要找到一个具有给定的 W,b 的平面,使得所有点集的误差最小。用平面方程代替 y_iPred 新的成本函数变成:

使用优化器来计算使上述成本函数最小化的 W,b 的最佳值。梯度下降优化器可用于找到均方误差最小的平面的最佳值。

对查询点的预测:

图 5

对于查询点' Qx '(图 5),对应的预测值是 Ypred ,其可以使用平面(W,w0)的方程使用上述方程来计算。

使用梯度下降优化器实现线性回归模型:

为了找到平面(W,b),我们希望误差尽可能小。梯度下降是一种迭代方法,以达到最小误差。为了找到最小误差,我们找到函数的梯度。

梯度下降法应遵循的步骤:

  1. 初始化权重向量和偏差项。
  2. 求函数关于权重和偏差的导数。
  3. 更新权重和偏差

重复这三个步骤,直到我们达到最小误差。随着每次迭代,权重向量和偏置项被更新以达到最小值。

样本数据集 LR 算法的实现:

图 6:样本数据集点

我们取 300 个数据点的二维样本数据集(第 2 行)。将数据集分为训练和测试数据集,其中 210 个点(70%)属于训练数据,其余 90 个点(30%)用于测试(第 5 行)。上图(图 6)表示样本数据集,下面是代码实现。

代码实现

步骤#1:初始化权重向量和偏置项:

用随机值初始化权重向量和偏差项(第 8-10 行)。权重向量的维数将等于数据集的维数。

第二步:求函数关于权重和偏差的导数:

以上是文章上面推导的 MSE 的方程。我们需要找到函数 f(W,b)关于 W 的导数(第 21 行),以及函数 f(W,b)关于 b 的导数(第 22 行)。

上述两个方程分别表示函数 f 关于权向量和偏差项的导数。

步骤#1:更新权重和偏差:

权重向量和偏置项的更新方程分别如上所述。根据上述等式,为每次迭代更新权重向量和偏差项(第 24-25 行)。lr’代表学习率,其定义了更新应该发生的速度。

左图:大单反,右图:小单反

如果学习率很大,则永远无法达到最小值,如果学习率很小,则通过一定次数的迭代可以达到最小值。

上述 3 个步骤重复一定次数的迭代(第 16 行),直到 W(I+1)变得非常接近或等于 W_i。

观察:

计算出的权重向量和偏差项分别为[50.265],-0.131(第 2-3 行)。计算所有测试数据集的预测值(第 6–9 行)。绘制直线和所有数据点(第 12-19 行),观察结果。

图 8:线的观察

观察:可以观察到线图(图 8)与数据点尽可能吻合。

[## krsatyam 1996/Linear _ Regression _ 从头开始

在 GitHub 上创建一个帐户,为 krsatyam 1996/Linear _ Regression _ from _ scratch 开发做贡献。

github.com](https://github.com/krsatyam1996/Linear_Regression_from_scratch)

感谢您的阅读!

逻辑回归的几何解释

原文:https://towardsdatascience.com/geometric-interpretation-of-logistic-regression-4f85047a5860?source=collection_archive---------27-----------------------

理解如何使用几何解释导出逻辑回归的成本函数

Unsplash 上拍摄的 ThisisEngineering RAEng

逻辑回归是一种统计模型,它使用逻辑函数来模拟二元因变量。在几何解释术语中,逻辑回归试图找到一条线或一个平面来最好地区分这两类。逻辑回归处理几乎或完全线性可分的数据集。

术语线性可分是什么意思?

对于二元分类数据集,如果一条直线或一个平面可以几乎或完全分隔两个类,那么这样的数据集称为线性可分数据集。否则,如果这两个类不能被线或平面分开,则数据集不是线性可分的。

左图:线性分离,右图:非线性分离

从上面的二维样本数据集中,左边的样本数据集几乎可以用一条线线性分离,而对于右边的样本数据集,没有一条线可以将这两类点分开。

图片 2

在(图 2)中,该线最好地分隔了两类点,错误分类了 3 个点(红色圆圈)。

深入推导算法的几何解释:

图 3: Xi 和 Xj 是正确分类的点

对于上面的样本数据集,假设我们需要找到一个平面‘P’来分隔这两个类。

平面的一般方程由下式给出:

所以最后我们需要找到一个平面 P。设这两类点为 y_i = {1,-1}。对于任意两个随机点 x_i 和 x_j。

d_i =平面和 x_i 之间的距离

d_j =平面和 x_j 之间的距离

这里 W 垂直于平面。当一个点的方向垂直于平面时,那么距离为正,否则为负。

对于正确分类的点(图 3):

d_i > 0d_j < 0

Now for a positive class point: **y_i = +1**
**(d_i * y_i) > 0**, since **d_i > 0** and **y_i > 0**For a negative class point: **y_i = -1**
**(d_i * y_i) > 0,** since **d_i < 0** and **y_i < 0**

所以对于正确分类的点, (y_i * d_i)总是正的

对于错误分类的点(图 4):

图 4: Xi 和 Xj 是错误分类的点

d_i < 0d_j > 0

For a positive class point: **y_i = +1**
**(d_i * y_i) < 0**, since **y_i > 0 and d_i < 0 (because on wrong side)**For a negative class point: **y_i = -1**
**(d_i * y_i) < 0,** since **d_i > 0** and **y_i < 0 (because on wrong side)**

对于错误分类的点, (y_i * d_i)总是负的

因此,为了得到最优解,我们需要最大化 (y_i * d_i)。我们需要找到最优的 W,w0,它使下面的等式最大化。

乙状结肠挤压:

图 4

由于存在负类的离群点,因此上面获得的成本函数将获得平面“P2”作为最佳平面,但这不是真的。平面“P1”最好地分隔了这两类点。

异常值或极值点的存在会在很大程度上影响平面。为了避免这种情况,我们需要找到一个函数,使 (y_i * d_i) 值变小,如果它太大,id (y_i * d_i) 值变小,它应该保持小。

我们需要这样一个函数

图 5

如果 x 的值很大,那么 f(x)逐渐变小,如果 x 的值很小,那么它仍然很小。

乙状结肠功能:

sigmoid 函数的图形清楚地定义了它满足我们的条件。sigmoid 函数的数学方程:

来源:Google Plots,图片 6,sigmoid 函数的绘图

所以我们的方程式可以归结为:

最小化方程式:

如果 G(x)是单调递增函数,那么 G(F(x))也是单调递增函数。

把 F(x)作为上面推导的方程,G(x)作为 log(x)作为 log(x)是一个单调递增的函数。

来源:Google Plots,图 7,log_e(x)的绘图

方程式归结为:

正规化:

因为 log_e(z)的最小值是 0。因此,优化器将尝试将上述等式的值最小化为 0,这使得 log_e(z)的‘z’= 1。

所以 W,w0 趋向于无穷大来满足方程,这就趋向于进行逻辑回归。

添加 L2 正则化:

上面导出的等式是逻辑回归算法的成本函数。我们使用优化器来计算使上述成本函数最小化的最佳值 W,w0【lambda】上式中的‘lambda’是超参数。

偏差方差权衡:

如果λ= 0,则上述方程将不包含任何会使模型过拟合的正则化项。

如果 lambda -> infinite(大值),则正则化项的权重非常高,并且它将遮蔽该项的其余部分,这导致欠拟合模型。

预测查询点的目标类别:

图 7:查询

w,w0 通过最小化成本函数来计算

对于查询' q1 ',y _ pred>0(W 方向的 q1)

对于查询' q2 ', y_pred < 0 (与 W 方向相反的 q2)

感谢您的阅读!

计算机视觉中的几何变换:Python 示例的直观解释

原文:https://towardsdatascience.com/geometric-transformations-in-computer-vision-an-intuitive-explanation-with-python-examples-b0b6f06e1844?source=collection_archive---------21-----------------------

旋转,平移和缩放转换解码。

佩顿·塔特尔在 Unsplash 上拍摄的照片

几何变换是任何图像处理流水线中最常见的变换操作之一。在今天的帖子中,我们将看看其中的三种变换: 旋转 平移 缩放 ,然后仅使用 Numpy 从头开始构建它们。图 1 显示了我们想要实现的视觉效果。所以, 洛戈特!

图 1 我们的目标是将图像 a 顺时针旋转 45 度,以创建图像 b .来自带有 CC 许可证的 COCO 数据集的参考图像

OpenCV 方式

如果你使用任何图像库,如 OpenCV 或 PIL 内置函数,实现上述功能是非常简单的。使用 OpenCV,我们可以用两行代码来完成,如下所示。

使用 OpenCV 旋转图像

图 2 固定边界的旋转

我们得到的结果如图 2 所示。请注意,OpenCV 不会自动扩展图像的边界。为了确保我们看到整个旋转的图像,我们需要做另外两件事。首先,计算目标图像的大小,其次,由于新图像的中心不同于原始中心,我们需要考虑旋转矩阵中中心值的差异。有了这些补充,我们就是黄金!

使用动态边界旋转

这一次旋转包括了我们预期的整个图像!让我们来分析一下这些函数调用背后到底发生了什么。

旋转矩阵

我们使用上面的getrotationmatrix 2d()方法(片段 1 第 5 行)来创建一个旋转矩阵,我们稍后使用它来扭曲原始图像(片段 1 第 6 行)。这个函数以图像中心、旋转角度和缩放因子作为参数,并给出一个旋转矩阵。这个** 旋转矩阵 到底是什么?嗯,它源于线性代数。让我们考虑一个任意的 2D 点[x,y],那么旋转运算可以用下面的矩阵运算来表示。**

2D 旋转变换

其中,R 是旋转矩阵

旋转矩阵 R

更简单地说,旋转矩阵给出了“函数 f”x’,y’= f(x,y)** 将输入点映射到其旋转的对应点。矩阵 R 由两个列向量组成,表示我们的初始基向量在转换后的最终位置(如果你像我一样是一个 3blue1brown 的粉丝,这将立即敲响警钟!).**

点旋转示例

让我们用单位圆把事情说得更清楚些。

在这个单位圆中,考虑头部在 B = [1,0]的两个向量 u 和头部在 D [0,1]的两个向量 w 。然后,这些向量围绕中心 A(=原点= [0,0])旋转某个角度θ(),之后它们分别落在 C 点和 E 点。

经过变换后,向量 v 可以用其分别以 F 和 H 为头的正交投影向量来表示。使用基本的三角学并记住向量 v 和 a 具有单位长度,可以容易地看出,以 F 为头的向量的长度是 b = cos(theta) ,以 H 为尾的向量的长度是 d= sin(theta)

导出向量 v 的正交分量

向量 v 因此可以表示为列向量【cos(theta)sin(theta)】同样,我们可以证明,向量 a 可以表示为列向量[-sin(theta)cos(theta)】负号表示方向。****

将这些列向量放在一起,我们得到了旋转矩阵 r。为了简化矩阵乘法,通常在旋转矩阵中添加第三个轴。直觉上,这将是旋转 3D 结构的旋转轴。该轴上的所有点在变换后将保持不变,因此该附加轴对剩余的变换没有净影响。

旋转变换

类似地,平移操作可以由下面所示的平移矩阵来表示,其中 txty 是 X 和 Y 方向上的平移量。

平移变换

还有我们的缩放矩阵,其中SxansSy是我们在 x 和 y 方向的缩放因子

缩放变换

注意:通常,旋转和平移被组合成如下所示的单个变换矩阵。这与绕原点旋转θ然后平移 txty 的效果相同

旋转和平移操作打包到一个矩阵中

试试吧!取上面任意一个矩阵,给它们一些值乘以任意一个点【x,y】看看变换后的点值是不是你所期望的!

我们现在有了表达几何变换的所有必要成分。请记住几件重要的事情:

  1. 矩阵乘法是不可交换的也就是说,如果你将两个矩阵 A 和 B 相乘,A.B!因此,我们变换的顺序很重要。旋转一个点然后平移和先平移那个点然后旋转相同的因子是不一样的!
  2. 变换表达式的矩阵乘法是从右向左进行的。
  3. 注意你的坐标轴,因为方向很重要。像 OpenCV 这样的大部分图像框架都是考虑左上角的原点。这不是我们写方程的经典的“第一象限”,而是“第四象限”。实质上,y 轴的方向是反向的。我们可以将它直接放入旋转矩阵中,或者在计算过程中添加一个负号(我做第二个是为了保持转换操作与文献一致)。
  4. 旋转一般是围绕图像中心进行的。

很好,现在让我们回到我们的原始图像,看看我们需要做什么来得到想要的转换图像。操作的确切顺序如下:

  1. 平移图像,使图像的中心为原点。这是因为我们希望通过图像的中心而不是左上角来旋转图像,左上角通常是图像中的原点像素/坐标。让我们把这些翻译因子设为【tx1,tx2】。****
  2. 将图像旋转我们想要的角度θ。****
  3. 将图像平移回其原始中心。让我们把这个概括为【tx2,ty2】。****
  4. 计算新的中心,并利用这些新的和旧的中心之间的差异来平移图像。还要考虑新图像的大小。(我们已经为 OpenCV 计算完成了这一步)。设这些平移因子为【CX _ shift,cy_shift】。****

用矩阵的方式,我们可以将上述四个步骤表达如下。从右到左,我们将中心平移到原点(右数第一个矩阵),绕中心旋转并平移回中心(中心矩阵),最后调整新维度的中心(左数第一个矩阵)。

我们的转换矩阵

我们在这里没有使用缩放变换,但是如果你也想缩放你的图像,只需要把缩放变换加到上面的等式中(在正确的地方!).简化上述内容并替换a = cos(θ)b = sin(θ)****

简化变换矩阵

这是我们最终的旋转矩阵,我们将在下一节中使用 Numpy 来旋转我们的图像。

数字之路

调用 OpenCV 方法既快速又简单,但是一点也不好玩!因此,我们将把我们讨论的所有内容放入代码中,并使用 Numpy 旋转图像!

由于这个脚本有点太长,无法粘贴到这里,请点击下面的链接查看完整代码。

** [## 博拉克/伊穆蒂尔斯

成像实用程序脚本。在 GitHub 上创建一个帐户,为 borarak/imutils 的发展做出贡献。

github.com](https://github.com/borarak/imutils/blob/master/geometric/rotate.py)

在这之后,我们可以使用自己的函数旋转和平移图像!

今天就到这里,希望你喜欢。一如既往的感谢阅读!**

GeoPandas:实用指南

原文:https://towardsdatascience.com/geopandas-a-practical-guide-c1e15d4d58d5?source=collection_archive---------32-----------------------

入门

测绘 1965 年至 2016 年的地震

Andrew BuchananUnsplash 上拍摄的照片

GeoPandas 是一个 Python 库,旨在处理地理空间数据。这使得基于地理位置创建可视化变得相当容易。

在本帖中,我们将可视化 1965 年至 2016 年间发生的重大地震。数据集可在 Kaggle 上获得。

GeoPandas 有两种主要的数据结构,即地理数据框架和地理系列。它们可以被认为是熊猫系列和数据框的子类。

让我们从安装和导入 GeoPandas 以及我们将使用的其他库开始。

pip install geopandas
import geopandasimport pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

可以通过修改熊猫数据框来创建地理数据框。因此,我们首先将数据集读入熊猫数据帧。

eq = pd.read_csv("/content/earthquakes.csv")eq.shape
(23412, 21)

该数据集包含超过 23412 个事件,其中大部分是地震。我们将过滤数据帧,使其仅包含地震数据。

eq = eq[eq['Type'] == 'Earthquake']

我们的分析中还有一些冗余的列,因此我也将过滤掉这些列。

eq = eq[['Date', 'Time', 'Latitude', 'Longitude', 'Depth', 'Magnitude']]eq.head()

(图片由作者提供)

我们有一个数据框架,包含了两万多次地震的数据、位置、深度和震级。为了使用 GeoPandas,我们需要将此 Pandas 数据框架转换为地理数据框架。

我们将按如下方式使用地理数据框架函数:

gdf = geopandas.GeoDataFrame(eq, geometry=geopandas.points_from_xy(eq.Longitude, eq.Latitude))gdf.head()

(图片由作者提供)

地理数据框架和 pandas 数据框架之间的区别是一个称为“几何”的地理系列。当空间方法应用于地理数据框架时,它将作用于几何列。

可以将“geometry”列看作是纬度和经度值的重新格式化版本。

我们现在将地震数据存储在地理数据框架中。下一步是绘制世界地图,使用“世界”地理数据框架可以轻松完成。

world = geopandas\
.read_file(geopandas.datasets.get_path('naturalearth_lowres'))world.columns
Index(['pop_est', 'continent', 'name', 'iso_a3', 'gdp_md_est', 'geometry'], dtype='object')

它包含关于国家及其位置的基本信息。我们现在画一张空的世界地图。

world.plot(color='white', edgecolor='black', figsize=(12,8))

(图片由作者提供)

为了绘制地震图,我们将创建一个世界地图的轴对象,然后根据“几何”列绘制地震。

ax = world.plot(color='white', edgecolor='black', figsize=(16,12))
gdf.plot(ax=ax, color='red', markersize=2)
plt.show()

(图片由作者提供)

这张地图包含了 1965 年至 2016 年间发生的所有重大地震。如果你在谷歌上快速搜索地震断层线,你会发现它们与上面的地图重叠。

markersize 参数调整定位地震的标记的大小。您还可以传递一个列名,标记的大小将根据该列中的值进行调整。我想过用大小来调整标记的大小,但是差别似乎并不明显。

我们还可以画出特定地点的地震地图。例如,日本发生过多次地震。我不确定,但它可能是世界上地震最多的国家。

关注特定国家的一种方法是根据纬度和经度值过滤地震。日本的纬度和经度值如下所示:

  • 纬度= 36.204824
  • 经度= 138.252924

我们可以围绕这些值创建一个范围,用作过滤范围。

japan_lat = 36.204824
japan_long = 138.252924japan_eq = eq[(eq.Latitude > 30) & (eq.Latitude < 42) & (eq.Longitude > 130) & (eq.Longitude < 145)]japan_eq = japan_eq.reset_index(drop=True)

我调整了范围,使位置占据了日本的面积。请注意,这些数值并不是日本的国界。

让我们创建一个仅包含日本境内或周边发生的地震的地理数据框架。

japan_gdf = geopandas.GeoDataFrame(japan_eq, geometry=geopandas.points_from_xy(japan_eq.Longitude, japan_eq.Latitude))

我们将绘制日本地图,并在日本 gdf 中标记地震。

ax = world[world.name == 'Japan'].plot(color='white', edgecolor='black', figsize=(12,8))japan_gdf.plot(ax=ax, color='blue', markersize=japan_gdf['Magnitude']*4)plt.title("Earthquakes, 1965-2016", fontsize=16)plt.show()

为了过滤地图,我们使用了世界地理数据框的“名称”列。

这是由此产生的日本地震地图。

(图片由作者提供)

日本发生过多次地震。标记的密度表明大部分都在东海岸。

结论

GeoPandas 是一个函数库,可以加速地理空间可视化的创建过程。它提供了许多功能和方法来丰富地图。

如果你正在或者计划使用地理空间数据,我强烈推荐你查看 GeoPandas 的文档。它们还提供了一些示例,有助于更容易地调整函数和方法。

感谢您的阅读。如果您有任何反馈,请告诉我。

Geopandas 安装 Windows 的简便方法!

原文:https://towardsdatascience.com/geopandas-installation-the-easy-way-for-windows-31a666b3610f?source=collection_archive---------4-----------------------

Unsplash 上的奥克萨娜 v 拍摄的照片

如果你想做一些房地产分析, GeoPandas 软件包提供了一种处理地理信息的惊人方法。它扩展了 pandas 使用的数据类型,允许对几何类型进行空间操作。

空间操作的例子有地图叠加(将两张地图结合在一起)、简单缓冲,但更普遍的是,GeoPandas 可用于地理可视化。

安装

虽然 GeoPandas 是一个强大的空间操作包,但安装对一些人来说有点困难。它需要难以协调的依赖性。

我发现了一种在我的笔记本电脑上有效安装它的方法,下面的步骤可能对你也有用。

这些步骤假设你已经安装了 wheel ( *pip install )。cmd 上的 whl)。

  1. 转到Python 扩展包的非官方 Windows 二进制文件
  2. 在一个特定的文件夹中下载以下二进制文件:GDAL、Pyproj、Fiona、Shapely 和 Geopandas 匹配 Python 的版本,以及你的笔记本电脑上安装的是 32 位还是 64 位操作系统

(例如对于 Python 3.7x(64 位),GDAL 包应该是GDAL-3 . 1 . 2-cp37-cp37m-win _ amd64 . whl。)

下载的依赖于一个文件夹

3.转到下载二进制文件的文件夹。

使用命令提示符并转到下载二进制文件的文件夹

4.重要提示:使用 pip 安装的以下安装顺序是必要的。注意文件名。如果文件名是正确的,它应该工作:(提示:键入“pip install”后跟一个空格,并键入二进制文件的前两个字母,然后按 Tab 键。(例如 pip install gd(按 Tab))

  • pip 安装。\ GDAL-3 . 1 . 1-cp37-cp37m-win _ amd64 . whl
  • pip 安装。\ pyproj-2 . 6 . 1 . post 1-cp37-cp37m-win _ amd64 . whl
  • pip 安装。\ Fiona-1 . 8 . 13-cp37-cp37m-win _ amd64 . whl
  • pip 安装。\ Shapely-1 . 7 . 0-cp37-cp37m-win _ amd64 . whl
  • pip 安装。\ geo pandas-0 . 8 . 0-py3-无-任何

5.就是这样!检查 GeoPandas 是否已正确安装,并通过导入它和查看模块上的帮助选项进行浏览。

注意:如果以下步骤不起作用,可能是因为系统上安装的其他不同的软件包与当前版本不兼容。我重新安装了 Anaconda,并确保首先安装 GeoPandas。

使用 Python 和自然语言处理进行地理解析

原文:https://towardsdatascience.com/geoparsing-with-python-and-natural-language-processing-4762a7c92f08?source=collection_archive---------21-----------------------

提取地名和指定坐标-教程

纳蕾塔·马丁在 Unsplash 上的照片

大量的可用文本数据具有可以从自动信息提取中受益的位置特征。自然语言处理(NLP)在过去的五年中取得了显著的进步。然而,从文本中提取地理信息的研究仍处于起步阶段。在本教程中,我们使用 Python 和 NLP 来 Geoparse twitter 数据集。

地质公园

Geoparsing 是一个地名解析过程,将对地点的自由文本描述(如“伦敦以东两公里”)转换为地理标识符(带经纬度的坐标)。

地理解析在许多应用中是必不可少的,包括地理信息检索(GIR)、地理信息提取(GIE)和地理信息分析(GIA)任务。

我们可以使用地理解析来确定文档的地理范围,解码灾难响应、商业新闻分析以及其他多个领域的位置信息。

为了说明什么是地质公园,让我们考虑这个讽刺标题示例

“抗议者偷走纽约市的环卫车,用它们来阻挡特朗普大厦”

通常,地理区划包含两个部分:地名识别和地名解析。首先,是地名提取或识别[纽约市,特朗普大厦]。下一步是将地名链接到地理坐标[(40.768121,-73.981895),(40.762347,-73.973848)]。

在下一节中,我们将使用 Python 地理解析库 Mordecai 对简单文本进行地理解析。

Python 地理解析示例

对于本教程,我们将使用 Mordecai 库进行地理解析。Mordecai 是全文地理解析 Python 库。使用这个库,您可以从一段文本中提取地名,将它们解析到正确的位置,并返回它们的坐标和结构化的地理信息。

让我们从一个简单的地质分析例子开始。Mordecai Python Geoparsing 库具有 Geoparse 函数,该函数接收文本并从文本中返回结构化的地理信息。

from mordecai import Geoparsergeo = Geoparser()
geo.geoparse(“Eiffel Tower is located in Paris”)

对于任何文本输入,末底改返回文本中存在的位置特征。在这个例子中,它正确地预测了埃菲尔铁塔和巴黎城。有趣的是,与这两个位置相关联的纬度和经度是不同的。预测的埃菲尔铁塔坐标比巴黎这座城市还要具体。

[{'word': 'Eiffel Tower',
  'spans': [{'start': 0, 'end': 12}],
  'country_predicted': 'FRA',
  'country_conf': 0.611725,
  'geo': {'admin1': 'Île-de-France',
   'lat': '48.85832',
   'lon': '2.29452',
   'country_code3': 'FRA',
   'geonameid': '6254976',
   'place_name': 'Tour Eiffel',
   'feature_class': 'S',
   'feature_code': 'MNMT'}},
 {'word': 'Paris',
  'spans': [{'start': 27, 'end': 32}],
  'country_predicted': 'FRA',
  'country_conf': 0.9881995,
  'geo': {'admin1': 'Île-de-France',
   'lat': '48.85339',
   'lon': '2.34864',
   'country_code3': 'FRA',
   'geonameid': '2988506',
   'place_name': 'Paris',
   'feature_class': 'A',
   'feature_code': 'ADM3'}}]

Mordecai Python 库采取了不同的步骤来实现这一结果。首先,它使用 spaCy 的命名实体识别从文本中提取地名。然后,它使用 Geonames gazetteer 查找地名的潜在坐标。最终过程使用神经网络从地名录条目中预测国家和地名。

地质公园推文

为了抓取 tweets,首先,我们设置了 Tweepy API 来抓取标签。下面这段代码使用 Tweepy 抓取一个标签(#BlackLivesMatter),并将标签中的所有 tweets 保存到本地 CSV 文件中。

用 Tweepy 抓取推文

让我们读一下关于熊猫的 CSV 推文,看看前几个专栏。

df = pd.read_csv(“tweets.csv”, header=None, names=[“date”, “tweet”])
df.head()

推特数据帧

数据框现在保存了推文和文本的日期。让我们使用 Mordecai Geoparsing 功能来提取位置信息并分配坐标。我们设置了这个函数,它获取一个数据帧,并生成一个干净的数据帧,其中包含来自地理解析的附加位置信息。

我们的干净数据集现在已经提取了地名,并通过预测和预测的置信度为 tweet 文本中的每个地名分配了坐标。

清理 Geoparsed 数据帧

为了绘制使用 Mordecai Geoparsing Python 库提取的#BlackLivesMatter hashtag 的地理范围,我们现在可以使用任何您喜欢的地理空间数据可视化 Python 库。我用 Plotly Express 来绘制数据。

fig = px.scatter_mapbox(df_clean, lat=”lat”, lon=”lon”, size_max=15, zoom=1, width=1000, height=800, mapbox_style=”dark”)
fig.data[0].marker = dict(size = 5, color=”red”)
fig

BlackLivesMatter 标签的地理范围-地理公园

结论

地理句法分析是从文本中自动提取位置特征的重要组成部分。在本教程中,我们了解了如何使用 Mordecai Geoparsing Python 库对文本进行 Geoparse 处理。

要使用 Mordecai 运行 Geoparsing,您需要安装它。您还需要有一个正在运行的 docker 容器。你可以在这里找到安装说明。

本教程的代码可以在这个 Jupyter 笔记本中找到。

[## shaka som/地质公园

github.com](https://github.com/shakasom/geoparsing/blob/master/Geoparsing with Python.ipynb)

佐治亚理工的 MS Analytics 项目值得吗?

原文:https://towardsdatascience.com/georgia-tech-ms-analytics-review-c0f1378da83?source=collection_archive---------3-----------------------

我在佐治亚理工学院 MS 分析项目的经历

来源:Burst-Shopify

2017 年末,我开始关注不同的在线硕士项目,重点关注数量。这包括统计学、数据科学、分析学、经济学和各种 MBA 课程。不幸的是,许多顶级项目,如卡内基梅隆大学的商业分析或伯克利的数据科学项目,都有 50,000 美元或更多的疯狂价格。虽然高薪不是我想要硕士学位的唯一原因,但高昂的学费大大降低了潜在的投资回报。在研究了几个星期的程序后,我终于找到了我要找的东西。这个分析程序的价格低于 15,000 美元,在不同的专业领域具有灵活性,并且来自一所著名的大学。这是佐治亚理工学院最近成立的在线分析科学硕士项目 (OMSA)。

快进到今天,我现在正在参加他们的金融建模课程。完成后,这将是我完成这个项目所需的 36 学分中的第 21 学分。如果一切顺利,我将在明年年底前完成这个项目。因为我的全职工作,我采取了保守的方法,每学期只报一门课。如果你对注重数量的在线硕士项目感兴趣,请继续阅读我对这个项目的诚实评论。

承认

选择乔治亚理工学院项目的便利之一是最低入学要求。他们不需要 GRE 或 GMAT 成绩,这在申请过程中节省了大量时间。缺乏需求既可以被视为优势,也可以被视为劣势。我对这个项目最大的抱怨之一是入学要求和课堂期望之间的巨大脱节。的要求声明你只有需要至少一门大学水平的课程或者“Python 中的计算机编程,达到 Python 中的计算入门的水平”的同等知识。我的计算机编程背景包括几门本科课程、在大会上为期两周的训练营以及一些工作经验;然而,我在课程中的两门必修课上挣扎了很久。

上层社会

数据分析计算简介

压力。愤怒。挫败感。正如我当时的任何一个室友可以告诉你的那样,在这个项目的第一堂课上,我一直处于混乱状态。数据分析计算入门让我想起了我的大学经历。这类似于我们在马里兰大学描述 STEM 专业的微积分 I 和 II。清除课程。根据佐治亚理工学院的分布报告,自 2018 年以来,约有 17%的学生最终退出了这门课程。

本课程的讲座只是浅尝辄止,所以大部分 python 编程都是我们自己学的。幸运的是,在在线可以找到大量的 python 教程和指南。虽然每周的家庭作业还不错,但考试却一点也不。我们进行了多次限时两天的考试。这听起来不错,只是一般人需要 10-12 个小时来完成每项考试。为什么需要 10 个小时才能充分检验一个人是否掌握 python?这在现实世界中是完全不现实的。我从这门课上学到了很多,但考试让我尝到了苦涩的滋味。

数据和可视化分析

在一个学期中,专注于软件工具的最佳数量是多少?如果你回答了 10 分或更高,那么这就是为你准备的课程!这个高级核心需求结合了不同的可视化和大数据工具的大杂烩,将它们投入到四个广泛的项目中,然后就到此为止。对于非分析人员或高管来说,这可能看起来合乎逻辑;但是技术岗位需要相当的深度才能成为专家。从概念的角度来看,这是真的,对于软件工具也是如此,因为概念可以很好地转换,BI 工具通常是相似的。如果你只花一周时间学习 Tableau,我保证几个月后你会忘记几乎所有的事情。然而,如果你花一整个学期的时间在一个老式的 MySQL 数据库上,这些概念和技能中的许多将无缝地转化为云中的现代数据库环境。我和我的一个同事一起亲眼目睹了这一点,他因为拥有 10 多年的 SQL 数据库经验,已经非常快地掌握了 Azure 中的数据工程。这个课程需要大量的努力,平均每周 14 个小时,根据 OMS 中央课程评估网站。这意味着大约 50%的学生每周需要超过 14 个小时。对于有家庭和/或全职工作的人来说,这是一项艰巨的工作。我会争辩说,这是一个不公平的的时间来期待 3 学分,但我跑题了。不幸的是,这门课的糟糕设计使得学生付出的努力与学到的知识不均衡。

模拟

模拟是我一生中上过的最好的课程之一。戈德曼教授对所有模拟事物的极大热情可以让任何讨厌数学的人变成书呆子。到目前为止,他是唯一一个在这个节目的预先录制的视频讲座中加入一些角色的教授。不断有老笑话,youtube 音乐视频的链接,闪烁的颜色或噪音。任何学生都知道,在学习方面,热情和创造力可以创造一个不同的世界。

虽然这门课程比大多数课程更重数学,但它的主题对许多类型的工作都非常有用。从交通模拟到医院的病人流动,每个行业都有模拟实验。这门课涵盖了概率分布、随机变量生成、泊松过程和在 ARENA 中设计模拟实验等主题。如果你对这些主题更详细的内容感兴趣,我把课堂讲稿整合到这里

社区

有句老话说,你知道什么并不重要,重要的是你知道谁是 T2。虽然面对面交流或通过在线项目建立长期关系很难,但我认为这种经历最有价值的部分是在线社区。OMSA 项目管理着一个松散的网络,包括每个班级的特定频道、学生发布的工作信息等等。每时每刻你都会收到来自世界各地成千上万聪明的学生和助教的有趣帖子。我在我们的 Slack 频道上发布了一个调查,看看在开始这个项目之前,每个人最感兴趣的话题是什么。有趣的是,这个游泳池非常多样化。大约 60%的学生在数学、工程、商业或经济方面有很强的背景。知识和经验的多样性促进了难以置信的对话,以及在数据分析中对思想、链接和笔记的奇妙的、经过过滤的选择。它比任何谷歌搜索都好!

OMSA 松弛频道民意调查

虽然社区是在线的,但还是有一些机会可以见到人。对于拥有大量学生追随者的城市,比如纽约,有专门的渠道,在那里人们会安排面对面的会面。我去年在纽约参加了一个,遇到了几个同学。

替代方案和成本

随着数据在过去几年中变得越来越受欢迎,在线硕士选项比我在 2017 年时要多得多。然而,一旦你把学费考虑进去,选择过程就变得容易多了。如果你需要一个 30,000 美元以下的知名项目,那么剩下的选择就不多了。这里有几个符合这个标准的项目,按照美国新闻研究生计算机科学或统计学排名的顺序排列。

选项#1*
MS Analytics,佐治亚理工
学费:~1 万美元(未收费)
CS 排名:#8

选项#2*
德克萨斯大学奥斯汀分校 MS 数据科学
学费:~10000 美元(未收费)
CS 排名:#10

选项#3
宾夕法尼亚州立大学世界校区 MS 应用统计学 学费:~27000 美元(未收费)
统计排名:#20 (CS 排名:#30)

选项#4
印第安纳大学 MS 数据科学
学费:~ $ 23400(未收费)
CS 排名:#55

选项#5
MS Data Analytics,科罗拉多州立大学
学费:~ 19000(未收费)
CS 排名:#75

*GT MS Analytics 与德克萨斯大学 MS 数据科学项目的比较

在线硕士课程的两种选择是新兵训练营和自学。我在大会上有过很好的经历,但是训练营的变化很大。证书主义的重要性正在改变,但如果你打算参加训练营,我会做你的尽职调查。至于自学,我在节目中学到的东西在网上都能很容易找到。你在 Coursera 和麻省理工学院有大量的在线公开课。我最喜欢的学习数据科学、分析和数学的资源可以在这里找到。自学需要大量的训练和时间来设计课程。就我个人而言,我知道我必须参加一个正式的项目来推动自己学习这些材料。

回首

当我回顾我参加 OMSA 项目的决定时,我不禁要分析我是否做出了正确的决定。在你做出选择之前,你只能在网上找到这么多信息。以我现在所知,我还会选择这个项目吗?老实说,我不知道,但是这山望着那山高。

如果你对我在佐治亚理工学院 OMSA 项目的经历有任何其他问题,请随时联系 out
数据通才

更新:第二部分的评论在这里发表。

Apache Sedona 在大规模处理地理空间数据方面表现突出

原文:https://towardsdatascience.com/geospark-stands-out-for-processing-geospatial-data-at-scale-548077270ec0?source=collection_archive---------7-----------------------

空间数据洪流

在过去十年中,可用的地理空间数据量大幅增加。这些数据包括但不限于:天气地图、社会经济数据和地理标记的社交媒体。例如,美国国家航空航天局的宇宙飞船一直在监测地球的状况,包括陆地温度、大气湿度。截至今天,美国宇航局已经发布了超过 22PB 的卫星数据。今天,我们在全球拥有近 50 亿台移动设备。因此,移动应用程序产生了大量的网络视频数据。例如,Lyft、优步和摩拜单车每天从数百万骑行者那里收集万亿字节的 GPS 数据。事实上,我们在移动设备上所做的一切都会在地球表面留下数字痕迹。此外,配备 GPS 的移动设备和物联网(IoT)传感器的前所未有的普及,导致不断产生结合周围环境状态的大规模位置信息。例如,一些城市已经开始在十字路口安装传感器,以监测环境、交通和空气质量。

理解隐藏在数据中的丰富的地理空间属性可能会极大地改变我们的社会。这包括许多正在进行深入研究的课题,如气候变化分析、森林砍伐研究、人口迁移、疫情扩散分析、城市规划、交通、商业和广告。这些数据密集型地理空间分析应用高度依赖底层数据管理系统(DBMSs)来高效地检索、处理、争论和管理数据。

阿帕奇塞多纳(前 GeoSpark)概述

Apache Sedona(以前的 GeoSpark)(http://sedona.apache.org)是一个集群计算框架,可以大规模处理地理空间数据。GeoSpark 扩展了 Apache Spark 中的核心数据结构弹性分布式数据集(RDD ),以在集群中容纳大地理空间数据。SpatialRDD 由分布在 Spark 集群中的数据分区组成。空间 RDD 可以通过 RDD 变换创建,也可以从永久存储的文件中加载。该层提供了许多 API,允许用户从各种数据格式中读取异构空间对象。

GeoSpark 允许用户使用现成的空间 SQL API 和 RDD API 进行查询。RDD API 提供了一组用操作编程语言编写的接口,包括 Scala、Java、Python 和 r。空间 SQL 接口为用户提供了一个声明性语言接口,因此他们在创建自己的应用程序时可以享受更多的灵活性。这些 SQL API 实现了 SQL/MM Part 3 标准,该标准广泛用于许多现有的空间数据库,如 PostGIS(在 PostgreSQL 之上)。接下来,我们将展示如何使用 GeoSpark。

Apache Sedona 中支持的空间数据源

过去,研究人员和从业人员开发了许多用于不同目的的地理空间数据格式。然而,异构数据源使得将地理空间数据集成在一起极其困难。例如,WKT 格式是一种广泛使用的空间数据格式,它将数据存储在人类可读的制表符分隔值文件中。Shapefile 是一个空间数据库文件,它包括多个子文件,如索引文件和非空间属性文件。此外,地理空间数据通常具有不同的形状,如点、多边形和轨迹。

目前,Sedona (GeoSpark)可以从本地磁盘、亚马逊 S3 和 Hadoop 分布式文件系统(HDFS)等不同的外部存储系统中读取 WKT、WKB、GeoJSON、Shapefile 和 NetCDF / HDF 格式的数据到空间 RDDs。空间 RDDs 现在可以容纳七种类型的空间数据,包括点、多点、面、多面、线串、多线串、几何集合和圆。此外,具有不同形状的空间对象可以共存于同一空间 RDD 中,因为 Sedona 采用了灵活的设计,该设计概括了不同空间对象的几何计算接口。

空间 RDD 内置几何库:空间数据科学家需要在 Apache Sedona 中挖掘空间对象的一些几何属性,比如周长、面积、交集,这是相当常见的。空间 RDD 配备了一个内置的几何库来执行大规模的几何运算,因此用户不会涉及复杂的计算几何问题。目前,系统在该库中提供了 20 多种不同的功能,并将它们分为两个不同的类别

常规几何函数应用于空间 RDD 中的每个空间对象。对于每个对象,它都会生成相应的结果,如周长或面积。输出必须是常规 RDD 或空间 RDD。

几何聚合函数应用于空间 RDD 以生成聚合值。它只为整个空间 RDD 生成单个值或空间对象。例如,系统可以计算整个空间 RDD 的边界框或多边形并集。

使用 RDD API 运行查询

这里,我们概述了使用 GeoSpark RDD API 创建空间 RDD 和运行空间查询的步骤。示例代码是用 Scala 编写的,但也适用于 Java。

设置依赖关系:在开始使用 Apache Sedona(即 GeoSpark)之前,用户必须将相应的包作为依赖关系添加到他们的项目中。为了便于管理依赖项,GeoSpark 的二进制包托管在 Maven 中央存储库中,该存储库包含了全世界所有基于 JVM 的包。只要项目由 Apache Maven 和 sbt 等流行的项目管理工具管理,用户就可以通过在 POM.xml 和 build.sbt 等项目规范文件中添加工件 id 来轻松添加 Apache Sedona。

初始化 Spark Context:Spark 或 Apache Sedona 中的任何 RDD 都必须由 Spark Context 创建。因此,GeoSpark 应用程序的第一项任务是启动 SparkContext。下面的代码片段给出了一个例子。为了使用自定义空间对象和索引序列化程序,用户必须在 SparkContext 中启用它们。

val conf = new SparkConf()conf.setAppName(“GeoSparkExample”)// Enable GeoSpark custom Kryo serializer
conf.set(“spark.serializer”, classOf[KryoSerializer].getName)conf.set(“spark.kryo.registrator”, classOf[GeoSparkKryoRegistrator].getName)val sc = new SparkContext(conf)

创建一个空间 RDD:Spatial rdd 中的空间对象并不局限于某种几何类型,而是对更多的场景开放。它允许包含混合类型几何图形的输入数据文件。例如,WKT 文件可能包括三种类型的空间对象,如线串、多边形和多重多边形。目前,该系统可以加载许多不同数据格式的数据。这是由一组文件阅读器完成的,如 WktReader 和 GeoJsonReader。例如,用户可以调用 ShapefileReader 来读取 ESRI 形状文件。

val spatialRDD = ShapefileReader.readToGeometryRDD(sc, filePath)

变换坐标参考系统: Apache Sedona 不控制空间 RDD 中对象的坐标单位(即基于度数或基于米)。计算两个坐标之间的距离时,GeoSpark 只需计算欧几里得距离。在实践中,如果用户想要获得精确的地理空间距离,他们需要将坐标从基于度数的坐标参考系统(CRS),即 WGS84,转换到平面坐标参考系统(即 EPSG: 3857)。GeoSpark 为用户提供了这一功能,使他们可以对空间 RDD 中的每个对象执行这一转换,并使用集群扩展工作负载。

// epsg:4326: is WGS84, the most common degree-based CRSval sourceCrsCode = “epsg:4326" // epsg:3857: The most common meter-based CRSval targetCrsCode = “epsg:3857"objectRDD.CRSTransform(sourceCrsCode, targetCrsCode)

构建空间索引:用户可以调用 API 在空间 RDD 上构建分布式空间索引。目前,系统提供两种类型的空间索引,四叉树和 R 树,作为每个分区上的本地索引。这一步的代码如下:

spatialRDD.buildIndex(IndexType.QUADTREE, false) // Set to true only if the index will be used join query

编写一个空间范围查询:空间范围查询返回位于一个地理区域内的所有空间对象。例如,范围查询可能会找到菲尼克斯大都市地区的所有公园,或者返回用户当前位置一英里范围内的所有餐馆。就格式而言,空间范围查询以一组空间对象和一个多边形查询窗口作为输入,并返回位于查询区域内的所有空间对象。空间范围查询将范围查询窗口和空间 RDD 作为输入,并返回与查询窗口相交/被查询窗口完全覆盖的所有几何。假设用户拥有空间 RDD。他或她可以使用以下代码对该空间 RDD 发出空间范围查询。空间范围查询的输出格式是另一种空间 RDD。

val rangeQueryWindow = new Envelope(-90.01, -80.01, 30.01, 40.01) /*If true, return gemeotries intersect or are fully covered by the window; If false, only return the latter. */val considerIntersect = false// If true, it will leverage the distributed spatial index to speed up the query executionval usingIndex = falsevar queryResult = RangeQuery.SpatialRangeQuery(spatialRDD, rangeQueryWindow, considerIntersect, usingIndex)

编写空间 K 最近邻查询:将 K、查询点和空间 RDD 作为输入,并在 RDD 中找到与查询点最近的 K 个几何。如果用户拥有空间 RDD,他或她可以执行如下查询。空间 KNN 查询的输出格式是包含 K 个空间对象的列表。

val geometryFactory = new GeometryFactory()val pointObject = geometryFactory.createPoint(new Coordinate(-84.01, 34.01)) // query pointval K = 1000 // K Nearest Neighborsval usingIndex = falseval result = KNNQuery.SpatialKnnQuery(objectRDD, pointObject, K, usingIndex)

编写一个空间连接查询:空间连接查询是用一个空间谓词组合两个或更多数据集的查询,比如距离和包含关系。生活中也有一些真实的场景:告诉我所有有湖的公园,告诉我所有 500 英尺内有杂货店的加油站。空间连接查询需要两组空间对象作为输入。它从这两个数据集的叉积中找到一个子集,使得每个记录都满足给定的空间谓词。在 Sedona 中,空间连接查询将两个空间 RDDs A 和 B 作为输入。对于 A 中的每个对象,从 B 中查找被它覆盖/相交的对象。a 和 B 可以是任何几何类型,并且不必具有相同的几何类型。空间 RDD 空间分区可以显著提高连接查询的速度。有三种空间划分方法:KDB 树、四叉树和 R 树。两个空间 rdd 必须由同一个空间分区网格文件进行分区。换句话说,如果用户首先对空间 RDD A 进行分区,那么他或她必须使用 A 的数据分割器对 b 进行分区。示例代码如下:

// Perform the spatial partitioningobjectRDD.spatialPartitioning(joinQueryPartitioningType)queryWindowRDD.spatialPartitioning(objectRDD.getPartitioner)// Build the spatial indexval usingIndex = truequeryWindowRDD.buildIndex(IndexType.QUADTREE, true) // Set to true only if the index will be used join queryval result = JoinQuery.SpatialJoinQueryFlat(objectRDD, queryWindowRDD, usingIndex, considerBoundaryIntersection)

使用 SQL APIs 运行空间查询

这里,我们概述了使用 GeoSpark 的空间 SQL 接口管理空间数据的步骤。SQL 接口遵循 SQL/MM Part3 空间 SQL 标准。具体来说,GeoSpark 将可用的空间 SQL 函数分为三类:(1)构造函数:创建一个几何类型列(2)谓词:评估一个空间条件是真还是假。谓词通常用于 WHERE 子句、HAVING 子句等(3)几何函数:对给定的输入执行特定的几何运算。这些函数可以生成几何图形或数值,如面积或周长。

为了使用该系统,用户需要添加 GeoSpark 作为他们项目的依赖项,如前一节所述。

启动 SparkSession:Spark 或 Sedona 中的任何 SQL 查询都必须由 SparkSession 发出,Spark session 是集群的中央调度器。要启动 SparkSession,用户应使用如下代码:

var sparkSession = SparkSession.builder().appName(“GeoSparkExample”)// Enable GeoSpark custom Kryo serializer.config(“spark.serializer”, classOf[KryoSerializer].getName).config(“spark.kryo.registrator”, classOf[GeoSparkKryoRegistrator].getName).getOrCreate()

注册 SQL 函数: GeoSpark 在 Spark 的 catalyst 优化器中增加了新的 SQL API 函数和优化策略。为了启用这些功能,用户需要使用如下代码将 GeoSpark 显式注册到 Spark 会话。

GeoSparkSQLRegistrator.registerAll(sparkSession)

创建一个几何类型列: Apache Spark 提供了一些格式解析器,可以将数据从磁盘加载到 Spark DataFrame(一个结构化的 RDD)中。在获得数据帧之后,想要运行空间 SQL 查询的用户必须首先在该数据帧上创建几何类型列,因为在关系数据系统中每个属性都必须有一个类型。这可以通过一些构造函数来完成,例如 ST_GeomFromWKT。在这一步之后,用户将获得一个空间数据框架。以下示例显示了该函数的用法。

SELECT ST_GeomFromWKT(wkt_text) AS geom_col, name, address
FROM input

转换坐标参考系:与 RDD API 类似,空间 SQL APIs 也提供了一个函数,即 ST_Transform,用于转换空间对象的坐标参考系。它的工作原理如下:

SELECT ST_Transform(geom_col, “epsg:4326", “epsg:3857") AS geom_col
FROM spatial_data_frame

编写一个空间范围查询: GeoSpark 空间 SQL APIs 有一组谓词,用于评估空间条件是真还是假。ST_Contains 是一个经典函数,它将两个对象 A 作为输入,如果 A 包含 B,则返回 true。在给定的 SQL 查询中,如果 A 是单个空间对象,B 是列,则这将成为 GeoSpark 中的空间范围查询(请参见下面的代码)。

SELECT *
FROM spatial_data_frame
WHERE ST_Contains (ST_Envelope(1.0,10.0,100.0,110.0), geom_col)

编写一个空间 KNN 查询:要使用 SQL APIs 执行空间 KNN 查询,用户需要首先计算查询点和其他空间对象之间的距离,按升序排列距离,并取前 K 个对象。以下代码查找点(1,1)的 5 个最近邻点。

SELECT name, ST_Distance(ST_Point(1.0, 1.0), geom_col) AS distance
FROM spatial_data_frame
ORDER BY distance ASC
LIMIT 5

编写一个空间连接查询:空间 SQL 中的空间连接查询也使用前面提到的评估空间条件的空间谓词。但是,要触发连接查询,空间谓词的输入必须至少包含两个几何类型的列,这两个列可以来自两个不同的数据帧,也可以来自同一数据帧。以下查询涉及两个空间数据帧,一个面列和一个点列。它查找每一对可能的$ < \(polygon,point\) > $以使多边形包含该点。

SELECT *
FROM spatial_data_frame1 df1, spatial_data_frame2 df2
WHERE ST_Contains(df1.polygon_col, df2.point_col)

执行几何运算: GeoSpark 提供超过 15 个 SQL 函数。用于几何计算。用户可以在其空间 SQL 查询中轻松调用这些函数,GeoSpark 将并行运行该查询。例如,获取每个空间对象的面积的一个非常简单的查询如下:

SELECT ST_Area(geom_col)
FROM spatial_data_frame

系统还提供空间对象的聚集功能。它们通常将数据帧中的所有空间对象作为输入,并产生单个值。例如,以下代码计算数据框中所有面的并集。

SELECT ST_Union_Aggr(geom_col)
FROM spatial_data_frame

通过 Zeppelin 笔记本与 GeoSpark 互动

尽管 Spark 在每个版本中都捆绑了交互式 Scala 和 SQL shells,但这些 shell 并不用户友好,并且无法进行复杂的分析和图表。数据科学家倾向于使用图形界面交互式地运行程序和绘制图表。从 1.2.0 开始,GeoSpark (Apache Sedona)提供了一个为 Apache Zeppelin 基于 web 的笔记本量身定制的氦插件。用户可以在 Zeppelin web 笔记本上执行空间分析,Zeppelin 会将任务发送到底层 Spark 集群。

用户可以在 Zeppelin 笔记本上创建一个新段落,并用 Scala、Python 或 SQL 编写代码,与 GeoSpark 进行交互。此外,用户可以点击界面上的不同选项,并要求 GeoSpark 在查询结果上呈现不同的图表,如条形图、折线图和饼图。例如,Zeppelin 可以将以下查询的结果可视化为条形图,并显示美国每个县的地标数量。

SELECT C.name, count(*)
FROM US_county C, US_landmark L
WHERE ST_Contains(C.geom_col, L.geom_col)
GROUPBY C.name

另一个例子是找到美国每个县的面积,并将其可视化在条形图上。相应的查询如下。这实际上利用了 GeoSpark 中提供的几何功能。

SELECT C.name, ST_Area(C.geom_col) AS area
FROM US_county C

Apache Sedona 如何处理空间数据洪流

空间数据划分

此外,空间 rdd 配备了分布式空间索引和分布式空间分区来加速空间查询。所采用的数据分区方法适合集群中的空间数据处理。空间 rdd 中的数据根据空间数据分布进行分区,并且附近的空间对象很可能被放入同一个分区中。空间分区的效果是双重的:(1)当运行以特定空间区域为目标的空间查询时,GeoSpark 可以通过避免对空间上不接近的分区进行不必要的计算来加速查询。(2)它可以将空间 RDD 分割成多个数据分区,每个分区具有相似数量的记录。这样,系统可以确保负载平衡,并避免在集群中执行计算时掉队。

空间索引

Sedona 使用分布式空间索引来索引集群中的空间 rdd。这个分布式索引由两部分组成(1)全局索引:存储在主机上,在空间分区阶段生成。它索引空间 rdd 中分区的包围盒。拥有这样一个全局索引的目的是修剪那些保证没有合格的空间对象的分区。(2)局部索引:建立在空间 RDD 的每个分区上。因为每个本地索引只作用于它自己分区中的数据,所以它可以有一个很小的索引大小。给定一个空间查询,空间 RDD 中的本地索引可以加速并行查询。

空间 RDD 定制串行器

Sedona 为空间对象和空间索引提供了定制的序列化程序。所提出的序列化器可以将空间对象和索引序列化为压缩的字节数组。该序列化程序比广泛使用的 kryo 序列化程序更快,并且在运行复杂的空间操作(例如空间连接查询)时占用的内存更少。将空间对象转换为字节数组时,序列化程序遵循 Shapefile 的编码和解码规范。

序列化器还可以序列化和反序列化本地空间索引,如四叉树和 R 树。对于序列化,它使用深度优先搜索(DFS)按照预先排序策略遍历每个树节点(首先写入当前节点信息,然后写入其子节点)。对于反序列化,它将遵循序列化阶段使用的相同策略。反序列化也是一个递归过程。当序列化或反序列化每个树节点时,索引序列化程序将调用空间对象序列化程序来处理单个空间对象。

结论

总之,Apache Sedona 为数据科学家处理大规模地理空间数据提供了一个易于使用的界面。目前,该系统支持 SQL、Python、R 和 Scala 以及许多空间数据格式,例如 ShapeFiles、ESRI、GeoJSON 和 NASA 格式。以下是 GitHub 资源库的链接:

[## 阿帕奇塞多纳(孵化中)

Apache Sedona(孵化)是一个用于处理大规模空间数据的集群计算系统。塞多纳扩展阿帕奇…

sedona.apache.org](http://sedona.apache.org)

GeoSpark 有一个活跃的小型社区,由来自工业界和学术界的开发人员组成。您还可以在此尝试更多编码示例:

[## 阿帕奇/孵化器-塞多纳

Apache Sedona(孵化)是一个用于处理大规模空间数据的集群计算系统。塞多纳扩展阿帕奇…

github.com](https://github.com/apache/incubator-sedona/)

如果您有更多问题,请随时在 Twitter 上给我发消息

地理空间冒险。第一步:匀称。

原文:https://towardsdatascience.com/geospatial-adventures-step-1-shapely-e911e4f86361?source=collection_archive---------16-----------------------

使用 KeplerGL 生成的图像

快速浏览使用 Shapely 库在 Python 中处理几何对象的基础知识。

这是一系列文章中的第一篇,总结了过去几年中使用 PropTech 处理地理空间数据的一些关键成果。这些将会有所有的东西——地理空间数据集、几何形状、栅格文件、地图、可视化。从最基础的开始,在后面的文章中,朝着更有趣和更有挑战性的方向努力...

让我们从介绍身材匀称的开始吧。毫无疑问,这是我最喜欢的 Python 库之一——非常重要,对于你最终从事的任何几何/地理相关的工作都是绝对必要的。

该库允许您使用三种主要类型的几何对象:点、线串和多边形+几何图形集合(如果您想要组合它们)。还有一堆其他的——线性环、多点、多多边形等。,但是现在这些就够了,这些方法是可以移植的。

安装

非常标准的安装,使用 pip。如果你像我一样使用 jupyter,你可以直接运行

!pip install shapely

请注意,GeoPandas 正在使用 Shapely,因此如果您已经安装了 GeoPandas,您可能已经有了 Shapely 的最新版本。您可以在导入 Geopandas 后执行一些 Shapely 操作,而无需单独导入,但是,如果您想要直接处理点和面对象,您仍需要首先加载它们。关于 Geopandas 已经说得够多了,但是我们将在下一篇文章中更详细地讨论它。

安装完成后,将其导入笔记本并加载主要几何图形类型:

import shapely
from shapely.geometry import Point, Polygon, LineString, GeometryCollection
import numpy as np

我也在进口 numpy,因为我太喜欢了。不过说真的,我经常发现自己在 shapely 对象和等价的 numpy 坐标数组之间来回跳跃,因为 numpy 允许您以显式矢量化形式更快地进行一些操作,所以从一开始就了解这两者之间的联系是一个好主意。

点状物体

顾名思义,这只是二维平面上的一个点,以一对坐标为特征。

Shapely 的一个超级方便的功能是——它允许您查看所有的几何对象,而不必求助于任何图形包。请注意,无论对象在坐标系中的位置如何,当您想要查看它时,它总是以对象为中心。

pt = Point(10, 10)
pt1 = Point(100, 101)

您还可以显示对象的字符串表示,只需将 str()括起来,或者将其转换为坐标的 numpy 数组。正如我提到的,我发现后者特别有用,因为我经常发现自己在处理大型几何对象阵列(例如来自 OSM 的超过 600 万个建筑多边形),如果我想以矢量格式进行计算,numpy 是绝对不可替代的。

还有一个将这个字符串表示加载回几何格式的方法,当您必须加载以非几何格式存储的数据(例如从 csv 文件)时,这将非常方便。

如果您想要快速查看几个对象,并查看它们如何相互缩放,您所要做的就是将它们转换为几何体集合:

其他一些简便的方法——距离、坐标采集。

在[8]中:

pt.distance(pt1)

Out[8]:

127.98828071350908

在[9]中:

pt.x, pt.y, pt.xy

Out[9]:

(10.0, 10.0, (array('d', [10.0]), array('d', [10.0])))

在继续学习线条之前,还有最后一件事。所有 shapely 对象都有一个. name 属性。例如,当您要将 GeoPandas 或 Pandas 数据帧中存储的大型集合中的每个多边形转换为一组较小的多边形(如格网)时,并且希望有一种简单的方法将它们与原始多边形相关联时,这将非常有用。

在[10]中:

pt.name = 'My Point'
pt.name

Out[10]:

'My Point'

线串

LineStrings 以非常相似的方式启动,只是这次我们有一个元组列表,而不是单个元组。它们可以交叉并多次通过相同的点,但是,不建议使用后者,因为它会对性能产生负面影响,您最好将它们拆分为单独的组件。请注意,点的顺序很重要,因为它决定了您通过它们的顺序(这同样适用于多边形,您将在下面看到)。

ln = LineString([(0, 1), (20, 100), (100, 3), (120, 102), (200, 5)])

与点一样,可以将 LineString 对象转换为点坐标数组。这里保留了顺序,因此这可用于快速获得第一个和最后一个点的坐标——例如,这对于构建表示道路网络的树对象很方便。

在[13]中:

np.array(ln)

Out[13]:

array([[  0.,   1.],
       [ 20., 100.],
       [100.,   3.],
       [120., 102.],
       [200.,   5.]])

或者,如果您希望首先使用与创建 LineString 相同的元组列表表示:

在[14]中:

list(ln.coords)

Out[14]:

[(0.0, 1.0), (20.0, 100.0), (100.0, 3.0), (120.0, 102.0), (200.0, 5.0)]

您也可以只分离出 X 坐标或 Y 坐标(当然,您也可以使用 numpy 来完成):

在[15]中:

list(ln.xy[0]), list(ln.xy[-1])

Out[15]:

([0.0, 20.0, 100.0, 120.0, 200.0], [1.0, 100.0, 3.0, 102.0, 5.0])

快速浏览一下图形表示以及我们之前创建的点:

计算点到线的距离、线上的点投影(从起点沿着线的距离)和线的长度非常简单:

在[17]中:

pt.distance(ln)

Out[17]:

8.01980198019802

在[18]中:

ln.project(pt), ln.length

Out[18]:

(10.801980198019802, 453.46769176178475)

在[19]中:

list(ln.interpolate(ln.project(Point(1, 1))).coords)

Out[20]:

[(0.039211841976276834, 1.1940986177825703)]

请注意,如果点在线上的投影恰好位于定义的区域之外,则距离将计算到最近的线端。如果你在实际的投影之后,你将需要做一些额外的几何。最简单的方法是延伸直线的第一段和最后一段,并仍然使用相同的投影方法。

线交点也很简单,即使你有多个交点。

结果是一个多点对象,您可以对其进行迭代,就像这是一个常规列表一样,将点对象作为可迭代对象:

在[21]中:

str(ln.intersection(LineString([(0, 0), (200, 100)])))

Out[22]:

'MULTIPOINT (72.55474452554745 36.27737226277372, 110.561797752809 55.28089887640449, 144.5255474452555 72.26277372262774)'

在[22]中:

[np.array(a) for a in ln.intersection(
    LineString([
        (0, 0),
        (200, 100)
    ])
)]

Out[22]:

[array([72.55474453, 36.27737226]),
 array([110.56179775,  55.28089888]),
 array([144.52554745,  72.26277372])]

多边形

毫不奇怪,创建一个与创建一个 LineString 非常相似,并且与 LineString 一样,列出点的顺序很重要。

多边形内部可以有洞,这些洞的定义遵循一个简单的规则:多边形([多边形坐标列表],[洞列表]),其中每个洞本身就是一个多边形。请注意,表示洞的多边形必须完全位于原始多边形内部,或者只能在一个地方接触到原始多边形。

请注意,多边形不能像线串和点那样直接转换成点的集合。相反,我们必须处理它们的外部和内部轮廓(它们本身就是线条,也就是一个自身循环的线条)。对于内部边界,我们得到一个迭代器:

在[25]中:

np.array(poly.exterior)

Out[25]:

array([[0., 0.],
       [0., 1.],
       [1., 1.],
       [1., 0.],
       [0., 0.]])

在[26]中:

[np.array(a) for a in poly.interiors]

Out[26]:

[array([[0.5, 0.5],
        [0.5, 0.6],
        [0.6, 0.6],
        [0.6, 0.5],
        [0.5, 0.5]]), array([[0.1, 0.1],
        [0.1, 0.5],
        [0.5, 0.5],
        [0.5, 0.1],
        [0.1, 0.1]])]

几个额外的方法作为一个追赶者:

多边形的质心(或者,类似地,线对象)

在[27]中:

np.array(poly.centroid)

Out[27]:

array([0.53795181, 0.53795181])

检查点是否在多边形内的两种不同方法:

在[28]中:

Point(0.7, 0.7).within(poly), poly.contains(Point(0.7, 0.7))

Out[28]:

(True, True)

你可以很容易地将线串和点对象转换成多边形通过在它们周围添加一个缓冲区

注意-这仍然是一个多边形(不是严格意义上的圆),在这种情况下,由 66 个点组成。

在[30]中:

len(np.array(Point(0.7, 0.7).buffer(1).exterior))

Out[30]:

66

如果需要,您可以通过在缓冲区中传递分辨率参数来提高默认分辨率(16)的精度:

在[31]中:

len(np.array(Point(0.7, 0.7).buffer(1, resolution=32).exterior))

Out[31]:

130

缓冲区允许您轻松地关联多边形和其他几何体对象。例如,如果你想用一条特定宽度的线切割一个多边形

或者切割它而不损失任何表面积:

最后,超级有用的 bounds metod,可以应用于多边形、线串和多对象,返回最小边界矩形的左下角和右上角的坐标,与 XY 轴对齐。

在[34]中:

Point(10, 10).buffer(5).bounds

Out[34]:

(5.0, 5.0, 15.0, 15.0)

今天到此为止。下一站熊猫大战地质熊猫

本系列其他帖子:

地理空间冒险。第二步:熊猫大战地球熊猫

地理空间历险记。第三步。多边形生长在 R 树上

地理空间历险记。第四步。魔法的色彩或者如果我没有看到它——它就不存在

地理空间历险记。第五步。离开平地或飞越多边形的海洋

地理空间冒险。第二步:熊猫大战地质熊猫

原文:https://towardsdatascience.com/geospatial-adventures-step-2-pandas-vs-geopandas-16e842d0e3a7?source=collection_archive---------35-----------------------

使用 KeplerGL 生成

探索熊猫和 GeoPandas 之间的差异,并介绍一些真实世界的地理空间数据集,我们将在本系列的稍后部分进行分析。

在我的 第一篇帖子 中介绍了 shapely 之后,是时候看看一些有趣的地理数据集了,为了做到这一点,我们不可能没有熊猫,更具体地说是地理熊猫。我假设你以前遇到过熊猫,会试着强调两者之间的一些区别,更重要的是,你如何将一个转换成另一个。

如果您以前从未使用过 GeoPandas,我们将从头开始——继续安装它,特别是如果您想自己按照这篇文章中的步骤操作数据。你只需要一个值得信任的老皮普。

!pip install geopandas

如果你愿意(你绝对应该这样),你可以在这里阅读这些文件。

让我们从导入熊猫和 GeoPandas 开始。

import pandas as pd
import geopandas as gpd

现在,在我们对这两个进行任何操作之前,我们需要一个数据集。在本文的最后有一些有趣的地理特定数据集的链接(一定要查看它们),但让我们从相对简短但足够现实的东西开始:英国地方当局边界。我喜欢这个数据集的原因是,一方面,它只有 380 条记录,另一方面,它使用的边界和形状一点也不简单,所以它很好地说明了您可能会在现实生活中使用的数据集。我还认为这是对英国数据进行任何地理空间分析的一个很好的起点,因为它允许你将所有东西分成易于管理的小块。相信我——有时候真的很有帮助。

浏览数据集。英国地方当局界限。

所以,事不宜迟,数据集在这里存放。点击你右边的下载按钮。您将获得一个压缩文件,文件名简短而甜美,大约 35mb(在撰写本文时,他们偶尔会更新)。继续解压缩,您将得到一个如下所示的文件夹:

我们要的是形状文件,带*的那个。shp 扩展。

据我所知,普通的熊猫不能处理这种格式,所以这是熊猫和地理熊猫的第一个区别,当然后者可以。让我们打开它:

la = gpd.read_file(
'Downloads/Local_Authority_Districts__December_2017__Boundaries_in_Great_Britain-shp/Local_Authority_Districts__December_2017__Boundaries_in_Great_Britain.shp'
)

确保您使用的是与您的系统相关的路径。如果你不确定你的笔记本默认使用的是哪个文件夹,只需在其中一个单元格中运行即可——你将获得当前的目录内容,因此你应该能够从这里找到下一步。如果你需要进入一个文件夹,使用<../>。

让我们来看看数据是什么样子的。所有标准的 Pandas 命令都有效,所以我们可以这样做:

la.head()

得到

不错!好吧,这到底是什么意思?

让我们一栏一栏地来看:
objectid 相当简单,坦率地说,对我们来说不是很有用。
lad17cd 为当地权限代码。这实际上非常方便,因为它与 ONS 的超级输出区域等一起使用,所以这给了我们一个很好的参考系统,可以在不同的地理分区和相应的数据集之间来回移动。非英国人——我很抱歉在这里表现得如此党派化,事实是,大多数国家看待事物的方式都有些相似,所以即使你发现这不是直接的兴趣所在,这仍然是可以转移和有用的。
lad17nm: 地方机关名称。其中有些很诡异很奇妙,绝对值得一探究竟。没有吗?那就只有我…
lad17nmw,里面好像都是看起来友好的<没有> s(抱歉,忍不住)。这一列也有名称,而“ w ”有点泄露了这一点——这是威尔士的地方当局名称,因此前五个记录中没有值,因为这些都是英格兰的地方当局。如果你想知道的话,我们要到 317 号才能离开英国。
bng_ebng _ n——邪恶的双胞胎。说真的,这些是东/北——我稍后会再多谈一点。基本上,坐标显示这个地区在地图上的位置。
——这次多了一些坐标——经纬度。

st_lengths —边界长度(也以米为单位)。
最后,这是我们真正需要的!请敲鼓。
几何图形-这是实际的多边形,或者在某些情况下,是多重多边形。不要让我开始谈论苏格兰群岛…Geometry 是 GeoPandas 表的关键属性,许多使用 geo pandas 表的应用程序基本上都假设这个列在那里,并且它被准确地称为“geometry”。所以,不管出于什么原因,如果你想给它取一个更友好的名字,请三思。

在我们进一步深入之前,因为我们要比较 Pandas 和 GeoPandas,我们可以用常规的 Pandas 格式创建这个表的副本。

la_pd = pd.DataFrame(la)
la_pd.head()

你会注意到这张新桌子看起来完全一样。不仅如此,几何表中的对象仍然非常完整:

到目前为止一切顺利。我们还可以像在 Pandas 中一样查看数据帧的所有统计数据,这两个表看起来是一样的,所以我将只在这里显示 GeoPandas 的结果(您必须相信我,不是吗?好的,在您自己的笔记本上运行它,以便检查)。

注意,这个函数只给出数字数据列的统计信息。

在[9]中:

la.info()

Out[9]:

<class 'geopandas.geodataframe.GeoDataFrame'>
RangeIndex: 380 entries, 0 to 379
Data columns (total 11 columns):
objectid      380 non-null int64
lad17cd       380 non-null object
lad17nm       380 non-null object
lad17nmw      22 non-null object
bng_e         380 non-null int64
bng_n         380 non-null int64
long          380 non-null float64
lat           380 non-null float64
st_areasha    380 non-null float64
st_lengths    380 non-null float64
geometry      380 non-null geometry
dtypes: float64(4), geometry(1), int64(3), object(3)
memory usage: 32.7+ KB

最后:

在[10]中:

la.memory_usage()

Out[10]:

Index           80
objectid      3040
lad17cd       3040
lad17nm       3040
lad17nmw      3040
bng_e         3040
bng_n         3040
long          3040
lat           3040
st_areasha    3040
st_lengths    3040
geometry      3040
dtype: int64

深部热疗

到目前为止,一切顺利。是时候发现另一个不同之处了。此命令不适用于您的熊猫数据帧:

在[11]中:

la.crs

Out[11]:

<Projected CRS: EPSG:27700>
Name: OSGB 1936 / British National Grid
Axis Info [cartesian]:
- E[east]: Easting (metre)
- N[north]: Northing (metre)
Area of Use:
- name: UK - Britain and UKCS 49°46'N to 61°01'N, 7°33'W to 3°33'E
- bounds: (-9.2, 49.75, 2.88, 61.14)
Coordinate Operation:
- name: British National Grid
- method: Transverse Mercator
Datum: OSGB 1936
- Ellipsoid: Airy 1830
- Prime Meridian: Greenwich

哇哦。!!那是什么意思?!还记得我答应过要扩展北/东吗?是时候看看坐标参考系统了。你可以在这里阅读一个更专业的 GeoPandas 作为具体的解释。简而言之,定义坐标系并不像听起来那么简单。这里的主要问题是地球有不平坦的大胆。不仅如此——它甚至不是球形的,所以在表面上定义一个精确的点可能很棘手(如果你不相信我——试着用一张方面纸包裹橄榄球)。更有趣的是,因为它太大了——有时假装它是平的是有道理的,因为在规模上甚至大到足以覆盖整个国家,如英国,这不会引入足够的误差来真正担心。因此,您可能会遇到两个主要的参考系统——经度和纬度(伪 3D)和北距/东距(2D)。我不得不承认,在大多数情况下,我更喜欢和后者一起工作。原因是——这很容易,而且我很懒。不过说真的,北距和东距都是用米来表示的,并且测量的是直接的距离。所以,如果你想知道事物之间的距离,你所要做的就是得到 Xs(东距)和 Ys(北距)之间的差异,应用毕达哥拉斯,就大功告成了。请注意,我们在之前的帖子中谈到的 Shapely 库也内置了 CRS 的概念,但是,我们并不真的需要使用它,因为 GeoPandas 为我们提供了所有可能需要的高精度弹药。

CRS 转换

GeoPandas 中有许多 CRS 系统。上表中使用的这个特别的是“epsg:27700”——如果你计划使用英国数据,这是你会经常使用的东西,所以你要记住它,要小心。在英国,使用 lat/long 的另一种方法是“epsg:4326”。GeoPandas 为我们提供了一种简单的转换方法。我们要做的就是跑:

la_4326 = la.to_crs("epsg:4326")
la_4326.head()

获得:

眼尖的人会发现,这个表中唯一的变化是我们的多边形/多多边形对象列,现在每个对象都由引用纬度和经度的点组成。您仍然可以看到与我们之前看到的相同的图形表示,它看起来应该是相同的。我会让你来验证的。

保存和读取非地理特定格式(csv)。几何对象转换。

在我们在这些之上进行一些计算之前,让我们看一下保存到 csv 和从 Pandas 转换到 GeoPandas。在 Pandas 的较新版本中,您应该能够将数据帧直接保存到 csv 文件中,尽管最后一列中有几何对象,即

la.to_csv('Downloads/la.csv', compression='gzip')

会成功的。更重要的是,结果文件只有 39.9mb,而 shapefile 只有 63.7mb(当然,我们已经在这里应用了压缩)。然而,这是有代价的。据我所知,您不能直接从 GeoPandas 读取 csv 文件,所以您必须将其作为普通的数据帧加载回来。只需运行:

la_new = pd.read_csv('Downloads/test.csv', compression='gzip')

乍一看,没什么变化:

la_new.head()

本质上,我们有一个单独的额外列,通过运行

la_new = la_new[la_new.columns[1:]]

然而,这还不是全部,如果我们像以前一样尝试查看我们的一个几何对象,我们会得到非常不同的结果:

在[17]

la_new['geometry'].iloc[0]

Out[17]:

'MULTIPOLYGON (((447213.8995000003 537036.1042999998, 447228.7982999999 537033.3949999996, 447233.6958999997 537035.1045999993, 447243.2024999997 537047.6009999998, 447246.0965 537052.5995000005, 447255.9988000002 537102.1953999996, 447259.0988999996 537108.8035000004, 447263.6007000003 537113.8019999992, 447266.1979 537115.6015000008, 447273.1979999999 537118.6007000003, 447280.7010000004 537120.1001999993, 447289.3005999997 537119.6004000008, 447332.2986000003 537111.5026999991, 447359.5980000002 537102.3953000009, 447378.0998999998 537095.0974000003, 447391.0033999998 537082.9009000007, 447434.6032999996 537034.5046999995, 447438.7011000002 537030.9956999999, 447443.7965000002 537027.6966999993...

好吧,我在这里作弊,在现实中,输出比这长得多。实际上,我们所有的几何对象都被转换成了字符串。然而,这一切并没有失去,因为 shapely 为我们提供了一种将它们转换回来的方法。除了在这里加载 shapely,我还需要更快的库。通过使用直接应用方法,您可以不使用它,但除此之外,swifter 为您提供了一个很好的进度条和时间估计(它也可以提高性能,但这超出了本文的范围)。

import swifter
from shapely import wkt
la_new['geometry1'] = la_new['geometry'].swifter.apply(lambda x: wkt.loads(x))

这里发生的事情是,我将转换函数应用于几何列的每个元素,并将输出存储在新列中。在我的笔记本电脑上,在我们的 380 记录长的数据集上,这需要 12 秒。我在非常非常大的数据集上做过,公平地说,还不算太差。

然后,我们可以通过运行以下命令来抽查新元素是否确实是几何图形对象

la_new['geometry1'].iloc[0]

但是我们还没有完成。事实上,如果我们运行 la_new.info(),我们会得到以下结果:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 380 entries, 0 to 379
Data columns (total 12 columns):
 #   Column      Non-Null Count  Dtype  
---  ------      --------------  -----  
 0   objectid    380 non-null    int64  
 1   lad17cd     380 non-null    object 
 2   lad17nm     380 non-null    object 
 3   lad17nmw    22 non-null     object 
 4   bng_e       380 non-null    int64  
 5   bng_n       380 non-null    int64  
 6   long        380 non-null    float64
 7   lat         380 non-null    float64
 8   st_areasha  380 non-null    float64
 9   st_lengths  380 non-null    float64
 10  geometry    380 non-null    object 
 11  geometry1   380 non-null    object 
dtypes: float64(4), int64(3), object(5)
memory usage: 35.8+ KB

新列显示为对象类型,而不是几何图形类型。但是,这不会阻止我们将其转换为地理数据框架。我们所要做的就是去掉我们不再需要的额外的 geometry 列,并将 geometry1 重命名为 geometry(记住—必须这样命名),然后(!)这一点很重要,在转换为地理数据框架后,我们必须为其设置 crs,

la_new_geo = la_new.drop(columns=['geometry']).rename(columns={'geometry1': 'geometry'})
la_new_geo = gpd.GeoDataFrame(la_new_geo)
la_new_geo.crs = 'epsg:27700'

瞧啊。la_new_geo.info()为我们提供了:

<class 'geopandas.geodataframe.GeoDataFrame'>
RangeIndex: 380 entries, 0 to 379
Data columns (total 11 columns):
 #   Column      Non-Null Count  Dtype   
---  ------      --------------  -----   
 0   objectid    380 non-null    int64   
 1   lad17cd     380 non-null    object  
 2   lad17nm     380 non-null    object  
 3   lad17nmw    22 non-null     object  
 4   bng_e       380 non-null    int64   
 5   bng_n       380 non-null    int64   
 6   long        380 non-null    float64 
 7   lat         380 non-null    float64 
 8   st_areasha  380 non-null    float64 
 9   st_lengths  380 non-null    float64 
 10  geometry    380 non-null    geometry
dtypes: float64(4), geometry(1), int64(3), object(3)
memory usage: 32.8+ KB

基本计算示例

最后,对我们新的闪亮地理数据框架进行一些快速计算:

验证长度和面积:

la_new_geo['area']=la_new_geo['geometry'].swifter.apply(lambda x: x.area)
la_new_geo['length'] = la_new_geo['geometry'].swifter.apply(lambda x: x.length)
la_new_geo[['lad17cd', 'lad17nm', 'st_areasha', 'st_lengths', 'area', 'length']].head()

或者,如果我们想要验证整个列,我们可以这样做:

(la_new_geo.st_lengths == la_new_geo.length).all()

您会注意到,由于舍入误差,这实际上会返回 False。例如,在第一条记录中,st_lengths 的值是 71,707.455227013,length 的值是 7 . 1676767771

因此,要进行检查,我们可以以设定的精度运行它:

(la_new_geo.st_lengths.round(4)==la_new_geo.length.round(4)).all()

在任何情况下,当处理地理对象时,考虑到现有数据的质量,移动超过 25 厘米的精度可能是不合理的,对于大多数应用程序,您可能可以将其限制在最近的米。

让我们也看看哪个区域具有最复杂的多边形/多多边形。我们将通过描述它所需的点数来判断。本质上,这意味着计算外部和内部边界的点:

la_new_geo['point_count'] = la_new_geo['geometry'].swifter.apply(
    lambda x: np.sum([len(np.array(a.exterior)) + np.sum([len(np.array(b)) for b in a.interiors]) for a in x]) if x.type == 'MultiPolygon' 
    else len(np.array(x.exterior)) + np.sum([len(np.array(a)) for a in x.interiors])
)

好了,这个有点复杂,我们来看看是怎么回事。首先,我们正在寻找多多边形对象,如果我们有一个,我们必须迭代通过每个多边形,将其转换为外部边界,然后 numpy 数组获得一个坐标数组。我们取数组的长度。我们还获得了内部边界的列表,因此我们还必须遍历它们,将它们转换为数组并取长度。类似地,如果我们处理一个简单的多边形,我们减少一级迭代,所以只有一个外部边界,但是我们仍然需要迭代潜在的多个洞。

然后我们对这些值进行排序,瞧,我们得到了前十名:

la_new_geo[
    ['lad17cd', 'lad17nm', 'point_count']
].sort_values('point_count', ascending=False).head(10)

这就是为什么每个人都如此热爱苏格兰。

没有吗?那就只有我了…

下一个帖子是关于多边形相互匹配,人类最酷的发明——R 树(Erm..算是)。嗯……好吧,也许还有一两张照片。

最后是承诺的…

数据集

世界各地的 OSM 数据集:http://download.geofabrik.de/

英国的 OSM 数据集:http://download.geofabrik.de/europe/great-britain.html

ONS 开放数据:https://www . ordnance survey . co . uk/opendata download/products . html

NOMIS(劳动力市场/人口普查数据):
-这些通常包含特定区域的数据,然后您可以通过使用它们的边界形状文件(通过 ID 匹配它们)将这些数据与地图相关联

我相信还有很多很多,请在评论中随意添加任何有趣的地理空间数据集(最好是免费使用的)。

回头见…

还在这个系列:

地理空间冒险。第一步:匀称。

地理空间历险记。第三步。多边形长在 R 树上

地理空间历险记。第四步。魔法的颜色或者如果我没有看到它——它就不存在

地理空间历险记。第五步。离开平地或飞越多边形的海洋

地理空间冒险。第四步。魔法的颜色,或者如果我看不到它,它就不存在。

原文:https://towardsdatascience.com/geospatial-adventures-step-4-the-colour-of-magic-or-if-i-dont-see-it-it-doesn-t-exist-56cf7fb33ba9?source=collection_archive---------51-----------------------

使用 KeplerGL 生成

快速浏览几何/地理对象(建筑多边形、道路、水路等)的可视化工具。).

继续第三步 。现在我们已经有了约克郡东骑马区的所有(OSM 已知的)建筑的数据集,让我们看看可视化数据的方法。

简单回顾一下——在上一篇文章中,我们观察了英国的地方政府多边形,并把它们与 OSM 建筑多边形结合起来。然后,我们讨论了一种将所有建筑多边形归属于相应的地方当局多边形的方法,并集中讨论了约克郡的 East Riding,这是由它的形状之美和与赫尔的邻近性所激发的。然后,我们继续创造一个非常不恰当的结果视觉化,我们即将纠正它。这篇文章是关于在地图上查看几何/地理数据的不同方法。

在我们能正确开始之前,我们确实需要一些小步骤。

首先,让我们加载我们在上一篇文章中使用的所有库:

import geopandas as gpd
import swifter
import numpy as np
from shapely.geometry import Polygon, GeometryCollection

在此之上,我们仍然有我们的数据框架和属性化的建筑,我们称之为“bd_ery”。让我们快速浏览一下:

bd_ery.head()

用 GeoPandas 绘图

我们将逐步进行,首先,让我们看看地理数据框架本身可以做些什么,因为除了显示几何对象之外,它还具有一些额外的绘图功能。如果你是 GeoPandas 的新手——看看本系列的第二篇文章

我们仍然需要使用 MatPlotLib,所以让我们继续加载它。

import matplotlib.pyplot as plt
%matplotlib inline

还有一件事——策划整个地方当局将使我们所有美丽的建筑形状变得非常小,这将是不可原谅的。因此,相反,我们将首先利用我们创建的图块来对它们进行属性化(详见上一篇文章)。我们不想处理它们的多边形,然而,我们需要的只是一种简单的方法来选择位于特定瓦片中的建筑物。为此,我们将把多边形转换成 id。最简单的方法是获取左下角的坐标(整数形式)并将它们合并成一个 12 位的 id(您也可以考虑散列多边形的字符串表示,但是我们不需要走那么远)。您可以将我们的 12 位 id 保存为字符串或整数(后者占用的内存更少)。我将把它们保存为字符串,因为无论如何它们都必须留在列表中,所以 DataFrame 最终会把它们视为对象。
转换只需一行代码,使用一些基本的列表理解即可完成:

bd_ery['ids']=bd_ery['grid'].swifter.apply(
    lambda x: [
        ''.join(np.array(a.exterior)[0].astype(int).astype(str)) for a in x
    ]
)

我将使用瓷砖' 499323426360 '没有任何具体原因,除了它有相当多的建筑,所以它非常适合我们的目的。

fig, ax = plt.subplots(1, figsize=(15, 15))
ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)
bd_ery[bd_ery['ids'].apply(lambda x: 1 if '499323426360' in x else 0) == 1].plot(ax=ax)

好吧,这还是有些乏味,不是吗?你肯定能看到一堆建筑形状,但也就这些了。当然,我们可以做得更多一点。

让我们这次使轴可见,让我们也根据建筑的类型给每个建筑分配颜色,让我们在看的时候放一张色图。
网格线,有人吗?哦,好吧,网格线也是…那图例呢?是的,是的,好的…

fig, ax = plt.subplots(1, figsize=(15, 15))
colormap="RdYlBu"
ax.grid()
bd_ery[bd_ery['ids'].apply(lambda x: 1 if '499323426360' in x else 0) == 1].plot(
    column='type',
    ax=ax, 
    cmap=colormap, 
    legend=True
)

那更好…这实际上在合适的人手里是有用的,尤其是考虑到制作一个这样的东西是多么容易。把它贴在你的网络应用或交互式仪表盘上,或者至少把截图粘贴到一个中型博客上,假装你知道你在说什么。

然而,我们还没有完全达到目标。我们可以做得更好。

输入…

叶子

关于 folium 的伟大之处在于,虽然它仍然完全由您的应用程序控制,并且输出仍然可以用于 webapps 和仪表盘,但输出是一个 html 文件,这使用户能够对生成的地图进行大量控制。是的,这是一张地图,我们现在要在实际的地图上画出我们可爱的多边形!

在我们开始多边形之前,让我们看看是否可以自己创建地图。奔跑

!pip install folium

如果你还没有,让我们加载库和底图。

import folium
state_geo = '[http://geoportal1-ons.opendata.arcgis.com/datasets/01fd6b2d7600446d8af768005992f76a_4.geojson'](http://geoportal1-ons.opendata.arcgis.com/datasets/01fd6b2d7600446d8af768005992f76a_4.geojson')

我们还需要传递一个起点,这样 leav 就知道我们要找的是地图的哪个部分。这需要以纬度/经度格式完成,因此我将创建一个迷你地理数据框架,以我们的切片中心作为唯一的点,然后使用 crs 转换方法来获得纬度/经度。这是一种有点复杂的方式,但它确实有效。曾经有一篇 Hannah Fry(BBC4 科学播客 fame——很棒,看看吧)的优秀博客文章,其中有转换代码,你仍然可以在 GitHub 上找到用 Python 写的版本,但我相信博客本身已经不在了。我觉得这是值得一提的,因为我仍然偶尔使用这些代码,并且知道你仍然可以在那里找到它的版本。

from shapely.geometry import Point
tile = gpd.GeoDataFrame(
    {'geometry':[Point(499323+1000,426360+1000)]}
)
tile.crs = 'epsg:27700'
tile = tile.to_crs(epsg=4326)

这为我们处理了转换,现在我们要做的就是绘制:

m = folium.Map(location=[tile.geometry.iloc[0].y, tile.geometry.iloc[0].x], zoom_start=15)
m

看起来有些眼熟?

现在让我们画一些多边形。

首先,我们将把图块的内容转换成一个单独的数据帧,并将其转换成 epsg:4326,这样整个事情就更容易理解了:

bd_tile = bd_ery[
    bd_ery['ids'].apply(lambda x: 1 if '499323426360' in x else 0) == 1
].to_crs('epsg:4326').reset_index(drop=True)

现在我们可以开始了:

folium.GeoJson(bd_tile['geometry'].to_json()).add_to(m)
m

啊哈!我们快到了!请注意,我们只是在之前的地图上添加了一些东西,并没有重新绘制整个地图。

让我们给它添加一些样式。我要从 Seaborn 那里偷调色板,把它变成一个字典,然后把它传到 leav。

import seaborn as sns
types = list(bd_tile['type'].unique())
color_dict = dict(
    zip(
        types,
        sns.color_palette("Paired", len(types)).as_hex()
    )
)
m = folium.Map(
    location=[
        tile.geometry.iloc[0].y,
        tile.geometry.iloc[0].x
    ],
    zoom_start=15
)
folium.GeoJson(
    bd_tile[['osm_id', 'type', 'geometry']].to_json(),
    style_function = lambda feature: {
        'fillColor': color_dict[feature['properties']['type']],
        'color': 'black',
        'weight': 0.2,
        'fillOpacity': 0.7
    }
).add_to(m)
m

然后,您可以像下面这样简单地将其保存为 html:

m.save_to('map.html')

还不算太差,但还是有一些弊端。除非你准备创建一个自定义的 html 图例,就像这里的一样,否则你会陷入没有图例的困境。标准方法只允许添加自动生成的颜色图,这对于分类变量来说一点也不好玩。还有另一种方法使用 choropleth 方法创建相同的地图,你可以在这里选择,但是同样没有可定制的图例和工具提示/弹出窗口。后者你可以通过添加圆形物体到多边形质心并混合它们。这些家伙可以有弹出窗口和工具提示,所以它让你的生活变得更容易一点。不过,你可能明白我的意思——还有另一个选择,我认为这可能是最好的方法。

进入

开普勒格尔

你可以在这里阅读。它可以用在 jupyter 笔记本上,这里有一篇非常详细的文章(包括最后的安装说明)。它不是没有一些缺点,因为它不能通过笔记本本身的代码完全控制,地图需要一些手动定制。尽管如此,它仍然可以保存为 html 格式。

让我们看看开普勒的例子。

from keplergl import KeplerGl
map_1 = KeplerGl(height=500)

Height 参数是指 jupyter 中窗口的大小。

现在我们要做的就是将地理数据框添加到地图对象中。请确保不要传递任何带有几何对象的其他列,因为这会使其混淆。

map_1.add_data(
    data=bd_tile[['osm_id', 'type', 'geometry']], 
    name='Building types'
)
map_1

看起来很熟悉,第一眼看上去没什么印象。关键是——从现在开始,您可以非常轻松地进行定制,并将其放在需要的地方。

你所需要做的就是点击左上角带箭头的小方块,进入下面的菜单:

在第一个(层)菜单中,您可以调整对象的颜色和边界,颜色可以由您上传的数据帧的列决定:

交互菜单允许你控制工具提示的内容。右边的菜单允许你切换到 3D 模式,添加图例等等。同样,3D 表示的高度可以由数据框列决定,也可以设置为特定值。

你还可以放大和缩小,移动到其他位置,改变视角等。

这是一个 3D 效果的示例,根据类型进行颜色编码,并显示带有 osm_id 和类型的工具提示:

最后一步——将其保存为 html 格式并分享出去…

map_1.save_to_html(file_name='kepler_example.html')

还不错…唯一的主要缺点是必须手动将最终图像调整到正确的状态,所以这只对 webapp 中的一次性演示或静态数据表示有好处。尽管如此,注意这个领域——这些缺点可能会相对较快地得到纠正。

哦,对了……差点忘了——标题图片是威斯敏斯特所有的建筑,都是由同一个开普勒格尔建造的。这实际上指出了它的另一个优势——它可以处理相当多的数据,因此在地图上绘制超过 20000 个多边形对象根本不是问题。

今天到此为止。下次—我们来看看光栅文件及其分析/解释

还在这个系列:

地理空间历险记。第一步:匀称。

地理空间冒险。第二步:熊猫大战地球熊猫

地理空间冒险。第三步。多边形长在 R 树上

地理空间历险记。第五步。离开平地或飞越多边形的海洋

地理空间冒险。第五步。离开平地或飞越多边形的海洋。

原文:https://towardsdatascience.com/geospatial-adventures-step-5-leaving-the-flatlands-or-flying-over-the-sea-of-polygons-846e45c7487e?source=collection_archive---------57-----------------------

使用 KeplerGL 生成

使用激光雷达数据(栅格文件)估计 OSM 多边形对象的高度。

顾名思义,是时候让我们做一些真正酷的事情,用“激光”去飞翔了。字面上。我们将了解如何解释激光雷达数据并将其连接到我们的多边形。

第 4 步中,我们集中精力以各种方式绘制约克郡 East Riding 的特定瓷砖。我们将继续使用同一个 bd_tile 数据集,它是约克郡某个特定位置的建筑物集合(具体来说,是一个 2 公里长的正方形,左上角位于 N:426360,E:499323)。如果您计划遵循本文的步骤,我建议您查看以前的帖子(参见本文末尾的完整链接列表)来重新创建相同的数据集。

我们在这里要尝试和解决的问题是:在公开的街道地图上确定建筑物的高度

事实上,它不一定是建筑物——它可以是任何我们知道位置和形状的物体。

所以事不宜迟:

激光雷达

首先,我们必须找到数据,因此我们将向环境署寻求帮助。他们进行定期调查,在夜间飞越英国的特定地区,并向地面发射激光。测量返回的光束,结合平面的位置,我们可以计算出光束反射的物体的高度。数据然后被分成数字表面模型 DSM(包括一切)和数字地形模型 DSM(去除地面物体)。这些以光栅文件的形式出现。asc ),分辨率为 0.25 米、0.5 米、1 米、2 米。

并不是所有的英国都在所有的分辨率下可用,存在差距,并且数据是在不同的时间点获取的,它不是每年都更新,所以当然存在(在某些情况下是显著的)缺点。尽管如此,这可能是我们目前能做的最好的事情了,此外,建筑物往往会在一段时间内保持不变,因此对于它们中的大多数来说,2-3 年的旧数据不是问题。
数据可以在这里找到。我们现在正在寻找两块瓷砖:SE92NE 和 TA02NW。原来我们到目前为止处理的区域正好位于多个瓷砖之间,这虽然有点烦人,但为我们提供了一个方便的机会来完成将这些瓷砖拼接在一起的过程。

我们的目标是合成 DTM 和合成 DSM 数据集,在这些数据集内,我们将达到 50 厘米的分辨率。每个 asc 文件的前六行包含有关其位置和分辨率的信息。随后是一个 2000 乘 2000 的数字方阵,每个数字代表一个 0.5 米乘 0.5 米的像素,并给出它的高度。对于相同的像素,DSM 和 DTM 数之间的差异给出了相应物体距地平面的高度,单位为米。

准备数据

该切换到 jupyter 了,让我们先加载库。除了 geopandas 和 numpy,我们还需要编解码器来读取我们的 asc 文件和 matplotlib/seaborn 以进行一些可视化。

import geopandas as gpd
import numpy as np
import codecsimport matplotlib.pyplot as plt
import seaborn as sns%matplotlib inline

接下来会有一大段代码,做好准备。加载相关的图块,进行一些滤光,然后将它们组合在一起

with codecs.open('LIDAR-DSM-50CM-SE92ne/se9926_DSM_50CM.asc', encoding='utf-8-sig') as f:
    X00 = np.loadtxt(f, skiprows=6)X00[X00 < 0] = 0with codecs.open('LIDAR-DSM-50CM-SE92ne/se9927_DSM_50CM.asc', encoding='utf-8-sig') as f:
    X01 = np.loadtxt(f, skiprows=6)X01[X01 < 0] = 0with codecs.open('LIDAR-DSM-50CM-SE92ne/se9928_DSM_50CM.asc', encoding='utf-8-sig') as f:
    X02 = np.loadtxt(f, skiprows=6)X02[X02 < 0] = 0X_ = np.vstack([X02, X01, X00])with codecs.open('LIDAR-DSM-50CM-TA02nw/ta0026_DSM_50CM.asc', encoding='utf-8-sig') as f:
    X10 = np.loadtxt(f, skiprows=6)X10[X10 < 0] = 0with codecs.open('LIDAR-DSM-50CM-TA02nw/ta0027_DSM_50CM.asc', encoding='utf-8-sig') as f:
    X11 = np.loadtxt(f, skiprows=6)X11[X11 < 0] = 0with codecs.open('LIDAR-DSM-50CM-TA02nw/ta0028_DSM_50CM.asc', encoding='utf-8-sig') as f:
    X12 = np.loadtxt(f, skiprows=6)X12[X12 < 0] = 0X_1 = np.vstack([X12, X11, X10])with codecs.open('LIDAR-DSM-50CM-TA02nw/ta0126_DSM_50CM.asc', encoding='utf-8-sig') as f:
    X20 = np.loadtxt(f, skiprows=6)X20[X20 < 0] =0with codecs.open('LIDAR-DSM-50CM-TA02nw/ta0127_DSM_50CM.asc',  encoding='utf-8-sig') as f:
    X21 = np.loadtxt(f, skiprows=6)X21[X21 < 0] = 0with codecs.open('LIDAR-DSM-50CM-TA02nw/ta0128_DSM_50CM.asc', encoding='utf-8-sig') as f:
    X22 = np.loadtxt(f, skiprows=6)X22[X22 < 0] = 0X_2 = np.vstack([X22, X21, X20])X = np.hstack([X_, X_1, X_2])

好了,这里实际发生了什么:我们正在读取每个文件,跳过前 6 行,因为它们包含描述性信息。您可以在文本编辑器中打开它们进行查看(或者使用 print 在笔记本中显示它们)。我们现在正在追求 2000 乘 2000 矩阵。我们用零代替所有的负值。这是因为数据中的缺口是用-9999 值填充的,我们肯定要忽略这些。然后,我们垂直堆叠得到的矩阵,得到 2 公里乘 6 公里的区域,最后水平堆叠这些矩阵,得到一个 6 公里乘 6 公里的区块。

让我们来看看:

dim = (15, 15)
fig, ax = plt.subplots(figsize=dim)
sns.heatmap(X, cmap="binary", square=True, ax=ax)

还不是很鼓舞人心。请注意左上角的大块缺失数据。恐怕对此无能为力。我们还需要加载 DTM 文件(可以在上面的代码块中用 DTM 替换 DSM)。我将结果保存为 X_t。

让我们直接看结果:

看起来更糟,不是吗?让我们来看一下不同之处,将地图的高度比例限制为 20 米,以使所有内容更加突出:

Xdiff = X-X_t
Xdiff[Xdiff < 0] = 0
dim = (15, 15)
fig, ax = plt.subplots(figsize=dim)
sns.heatmap(Xdiff, vmax=20, cmap="binary", square=True, ax=ax)

啊哈!我们有所进展,这实际上开始看起来像一张地图。现在,这个地图左下角的坐标由我们加载的第一个图块给出— N:426000,E:499000。我们需要在左下角的 N:426360,E:499323 处切出一个 2 公里乘 2 公里的正方形。请记住,我们矩阵的元素是从左上角开始索引的,而不是从底部,所以我们需要进一步调整,然后还要记住,我们矩阵中的每个点都是 0.5 米宽,所以我们需要将索引乘以 2,使它们等于北距/东距(因此,我们需要移动 720 和 646,而不是 360 和 323,2 公里的瓷砖边变成 4000 像素)

Xtile = Xdiff[6000-4720: 6000-720, 646: 4646]

画出它,我们会得到与原始瓷砖非常相似的东西:

和...相对

fig, ax = plt.subplots(1, figsize=(15, 15))
ax.axes.get_xaxis().set_visible(True)
ax.axes.get_yaxis().set_visible(True)
ax.grid()
bd_tile.plot(ax=ax)

匹配多边形

下一步是匹配两组值,点和面。我们将要采取的方式与步骤 3 中详细描述的非常相似。我们取每个多边形,用 0.5 米的步长创建一个包围盒的网格。然后,我们可以遍历网格单元,检查它们中的哪些与我们的多边形相交。它们的坐标将与我们的高度矩阵的元素直接关联,因此我们可以简单地选择相关的元素,并获得我们的建筑物的高度轮廓。听起来合理吗?让我们试一试。

加载 shapely Polygon 和 GeometryCollection,我将使用数据集中的第一个多边形:

from shapely.geometry import Polygon, GeometryCollection
bounds = bd_tile['geometry'].iloc[0].bounds

创建网格并将每个元素转换为多边形:

X, Y = np.mgrid[int(bounds[0]): int(bounds[2]) + 1: 0.5,
                int(bounds[1]): int(bounds[3]) + 1: 0.5]
grid = list(
            map(
                list,
                list(
                    zip(
                        list(
                            zip(X.flatten(), Y.flatten())
                        ),
                        list(
                            zip(X.flatten(), Y.flatten() + 0.5)
                        ),
                        list(
                            zip(X.flatten() + 0.5, Y.flatten() + 0.5)),
                        list(
                            zip(X.flatten() + 0.5, Y.flatten())
                        )
                    )
                )
            )
        )
grid_poly = [Polygon(a) for a in grid] 

这与我们在步骤 3 中使用的方法完全相同,只是现在我们使用 0.5 米的步长,而不是 2000 米。

让我们看看我们对多边形的近似程度:

poly = [
    a for a in grid_poly if a.intersects(
        bd_tile['geometry'].iloc[0]
    )
]
g = GeometryCollection(poly + [bd_tile['geometry'].iloc[0]])
g

这是非常整洁的。

现在我们需要从我们的矩阵中得到相应的点。

让我们抓住坐标并把它们转换成矩阵指数。

poly_coords = np.array([np.array(a.exterior)[0] for a in poly])

这给了我们每个左下角的坐标对。现在把它们分成 x 数组和 y 数组:

inds_array = np.moveaxis(poly_coords, -1, 0)

调整以使它们与我们的矩阵坐标一致:

inds_array[0]=(inds_array[0] - 499323) * 2
inds_array[1]=(2000 - inds_array[1] + 426360) * 2

最后,使用花式索引(老实说,这是一个技术术语):

heights = Xtile[
    inds_array[1].astype(int),
    inds_array[0].astype(int)
]

让我们检查一下我们所选择的实际上看起来像我们的原始多边形:

dim=(15,15)
fig, ax = plt.subplots(figsize=dim)
sns.heatmap(
    Xtile[
        np.min(inds_array[1].astype(int)): np.max(inds_array[1].astype(int)),
        np.min(inds_array[0].astype(int)): np.max(inds_array[0].astype(int))
    ], 
    cmap="binary",
    square=True,
    ax=ax
)

嘣!我会说——完全正确。

现在,理论上,我们得到了一个很好的唯一的数字来显示我们建筑的高度。当然,在现实中,这是极不可能发生的。你可以从上面的图片中看到,我们得到了相当多的分布——倾斜的屋顶,多个建筑块,烟囱,等等。等等。一个不错的猜测是,使用这样的中值,在这个特定的例子中,我们得到了不到 3.6 米。更好的是,我们可以丢弃选择中的零值,这将使我们的中值不到 4 米。对于某些应用程序,您可能想要最大高度,尽管在这种情况下,我们得到 9 米,这很可能是由附近的树驱动的。要做出更明智的选择,您可以查看总体分布并选择特定的百分位数,或者创建与不同身高值对应的总面积相关的条件。另一种选择是排除边界网格销售(通过迭代相关网格销售并检查哪些销售与边界相交来识别它们)。外景法)。

我们可以使高度更谨慎一点,例如将它们四舍五入到最接近的半米,并获得计数,以给我们一个稍微好一点的画面:

h, c = np.unique(np.round((heights * 2), 0)/2, return_counts=True)
dict(zip(h, c))

生产

{0.0: 184,
 0.5: 30,
 1.0: 19,
 1.5: 22,
 2.0: 16,
 2.5: 70,
 3.0: 118,
 3.5: 43,
 4.0: 56,
 4.5: 79,
 5.0: 98,
 5.5: 92,
 6.0: 89,
 6.5: 38,
 7.0: 7,
 7.5: 2,
 8.0: 2,
 8.5: 1,
 9.0: 1}

现在剩下的就是选择你的规则,把我们的步骤包装成一个函数,然后把它应用到数据集中的每个多边形。我要把它留给你去玩,否则我会得到所有的乐趣,那只是贪婪。

本系列到此结束,希望你喜欢它,或者至少发现它在某些方面是有用的。当然,这还不是全部。例如,我们可以看看当没有 OSM 作为后盾时,如何将栅格数据转换为实际的建筑物多边形(他们缺少许多建筑物,因此这不仅仅是一个理论练习)。这是一个很好解决的问题,我可能会回来。但是还有很多很多地理空间(不仅仅是地理空间)项目值得探索,所以请继续关注。

再见,

本系列的前几篇文章

地理空间历险记。第一步:匀称。

地理空间历险记。第二步:熊猫大战地球熊猫

地理空间历险记。第三步。多边形在 R 树上生长

地理空间冒险。第四步。魔法的颜色或者如果我没有看到它——它就不存在

地理空间冒险。第五步。离开平地或飞越多边形的海洋

Python 和 Jupyter 笔记本中的地理空间分析

原文:https://towardsdatascience.com/geospatial-analysis-in-python-and-jupyter-notebooks-f90de25b0777?source=collection_archive---------9-----------------------

使用 geopandas 和 kepler.gl 对巴塞罗那自行车租赁服务(bicing)进行地理空间分析。

世界上大多数国家的首都都在使用公共城市自行车服务,这减少了燃料消耗、排放和市中心的拥堵。自行车共享还鼓励体育活动,有助于城市居民的健康。

照片由 Jasser GómezUnsplash 拍摄

数据摄取

幸运的是,它有一个开放的 CityBikes API ,可以用来实时检查自行车站点的状态(例如,我们可以检查任何站点的空闲位置的数量)。此外,还有一个用于查询 CityBikes API 的 python 包[python-citybikes](https://github.com/eskerda/python-citybikes)

巴塞罗那是使用 CytyBikes API 公开数据的城市之一。使用上面提到的包,巴塞罗那的自行车服务(又名 bicing )可以使用以下代码进行查询:

client = citybikes.Client()
bicing = citybikes.Network(client, uid='bicing')
bicing.stations

前一个调用以 JSON 格式返回工作站的数据:

{
    "company": ["Barcelona de Serveis Municipals, S.A. (BSM)", "CESPA", "PBSC"],
    "href": "/v2/networks/bicing",
    "id": "bicing",
    "location": {
        "city": "Barcelona",
        "country": "ES",
        "latitude": 41.3850639,
        "longitude": 2.1734035
    },
    "name": "Bicing",
    "stations": [
        {
            "empty_slots": 17,
            "extra": {
                "ebikes": 0,
                "has_ebikes": true,
                "normal_bikes": 16,
                "online": true,
                "uid": 361
            },
            "free_bikes": 16,
            "id": "ed25291d0f5edd91615d154f243f82f9",
            "latitude": 41.376433,
            "longitude": 2.17871,
            "name": "PG. DE COLOM (LES RAMBLES)",
            "timestamp": "2020-10-16T18:19:06.097000Z"
        },
        ...
    ]
}

处理完数据后,我们将数据从 JSON 模式转换成表格模式:

自行车站数据框

该 API 不提供历史服务,但是您可以开发自己的脚本来每 5 分钟下载一次数据(Bicing refresh rate)。配套的笔记本显示如何下载和处理数据;在data/bicing_saturday_morning.parquet中,处理后的数据样本也作为拼花文件提供。

巴塞罗那——自行车站

第一个空间操作将是使用从 CityBikes API 下载数据时可用的经度和纬度信息在地图上绘制车站:

df_stations = df[["name","latitude","longitude"]].drop_duplicates()

第一张地图会将所有这些站放在地图上:

stations_map = KeplerGl(height=600, data={"stations": df_stations})
stations_map

巴塞罗那自行车站

kepler.gl很聪明地推断出列latitudelongitude代表了车站的地理坐标。该地图可以显示在 Jupyter 笔记本中,并且可以使用 UI 配置该地图,以在不同的地图样式(平面或卫星)和图层(道路、建筑物等)之间切换。这些 UI 调整可以导出为 python 字典,然后在下次加载地图时使用。查看 kepler.gl 文档了解更多关于定制地图的信息。

细川玉子区—自行车站

CityBikes API 不提供按地区划分的车站信息(只有车站的名称,也就是车站的地址)。但是不用担心,我们仍然可以使用社区提供的公开数据。在这种情况下,我们将使用巴塞罗那开放地理数据存储库,以及那里提供的地区地理位置。

Geopandas 可以阅读。geojson 文件使用:

df_districts = geopandas.read_file("data/districtes.geojson")

对象df_districts类似于一个常规的 Pandas dataframe,但是包含一个名为geometry的列。Geopandas 数据帧可以根据需要包含任意多的地理列,但是我强烈建议每个数据帧只使用一个,并将其命名为geometry。在这种情况下,文件包含 10 个地区(行)和 47 列(带有地区名称、网站、区域等信息)。

巴塞罗那地区数据框架

geopandas 数据帧可以按原样绘制:

巴塞罗那区

或者,我们可以在另一个地图实例中沿着自行车站投影该地区的边界:

district_map = KeplerGl(height=600, data={"stations": df_stations,                                          "districts": df_districts})

巴塞罗那自行车站和区

在上图中,我们可以直观地查看哪些车站位于细川玉子区,但是有没有办法以表格的方式提取这些信息呢?是的,您可以:欢迎使用空间连接。

首先,我们需要将包含站点位置的数据帧转换为 Geopandas 数据帧:

df_stations = geopandas.GeoDataFrame(df_stations.name, geometry=geopandas.points_from_xy(df_stations.longitude, df_stations.latitude, crs='epsg:4326'))

在上面的代码片段中,您可以观察到一个名为crs的参数。总结一下:经纬度数字是有规律的数字,但是当你对它们应用一个坐标参考系 ( CRS )的时候,这些数字就可以投影到一张地图上。参考系比较多,课题比较复杂,我就把我的研究缩减到只有两个 CRS 的(请 GIS 专家原谅我的无礼):

  • 通用 WGS 86 (EPSG: 4326) 以经度/纬度表示世界上的位置
  • 墨卡托 (EPSG: 3395) 当与距离一起工作时

当我们使用两个坐标系来投影世界地图时,可以理解两个坐标系之间的差异:

使用 WGS86 和墨卡托投影的世界地图

如果您需要有关投影和使用不同参考系统的更多信息,我建议查看管理投影 GeoPandas 文档

空间连接将返回包含在每个区内的点(=自行车站):

df_stations_districte = geopandas.sjoin(df_stations,  df_districts[["NOM","geometry"]], how="inner", op='intersects')

从那里,过滤掉细川玉子区的电台就这么简单:

df_stations_district_gracia = df_stations_district[df_stations_district.NOM=='Gràcia']

格拉西亚区的自行车站

细川玉子区——自行车站“影响区”

影响区域可以显示为以每个站为中心的圆。圆的半径可以是用户定义的参数(例如,300 米)。正如我们之前提到的,为了处理距离,我们需要暂时将参考系统切换到墨卡托:

def buffer_in_mercator(geometry, distance_x_meters):
    crs = geometry.crs
    return geometry.to_crs(epsg=3395).buffer(distance_x_meters).to_crs(crs)

将函数应用于站点的位置后,我们可以绘制每个自行车站点周围的影响区域:

自行车站影响区域

细川玉子区——骑自行车的最佳区域

在这种情况下,所采用的方法是,地图中的每个区域都可能受到许多站点的影响,因此该区域中可用的自行车数量将是与该区域接触的影响区域中可用自行车数量的总和。

自行车站点区域和统计数据

我们需要计算所有影响区域之间所有交集的并集。这个操作可以使用库shapely来解决(感谢 stackoverflow ):

shapes = areas.to_list()
areas_overlay = list(polygonize(unary_union(list(x.exterior for x in shapes))))

该操作为每个叠加交点创建一个形状(区域),因此总共生成 68 个形状。如前所述,我们可以绘制图形来更好地理解操作本身:

自行车站区

免费自行车的数量可通过在区域和车站影响区域之间执行空间连接,并将同一区域中的所有行相加来获得:

df_gracia_area_stats = gpd.sjoin(df_areas_overlay, 
                                 df_gracia_stats.reset_index(), 
                                 how="left", op='intersects')\
                                .reset_index()\
                                .rename(columns={'index':'index_left'})
df_gracia_area_stats['free_bikes_area'] = df_gracia_area_stats.groupby("index_left")['free_bikes'].transform(sum)

同样,实例df_gracia_area_stats是一个 geopandas 数据帧,可以投影到地图上,直观地检查 Gràcia 区的自行车可用性:

free_bikes_map = KeplerGl(height=600, data={"areas": df_gracia_free_bikes})

格拉西亚区

与之前相同,可以用表格的方式提取最佳区域:

df_gracia_free_bikes.loc[df_gracia_free_bikes.free_bikes_median.idxmax()]

总之,geopandaskepler.gl是您数据分析工具箱的强大补充。geopandas基于 Pandas dataframe API,而kepler.gl在其核心支持 Pandas dataframe,因此这两个库的学习曲线都很快,同时好处也很大。

这篇文章的完整代码可以在这里找到——https://github.com/franperezlopez/blog_spatial

安装kepler.gl

安装这个库有点棘手,这方面缺少文档,所以我会尽量简化这一步。首先,这个库似乎不能在 Windows 中工作,所以你需要使用 MacOS、Linux 或 WSL(2)。

其次,这个库需要安装一个 Jupyter 扩展。按照我自己关于如何安装 Jupyter Notebook 的建议,您应该在您的 base 环境中安装这个扩展,执行以下命令:

conda activate base
pip install --user --use-feature=2020-resolver keplergljupyter nbextension install --system --py keplergl
jupyter nbextension enable --system --py keplergl

参考

[1] 智能城市自行车服务:经济、环境&社会影响

地理空间聚类:种类和用途

原文:https://towardsdatascience.com/geospatial-clustering-kinds-and-uses-9aef7601f386?source=collection_archive---------8-----------------------

对所有不同种类的集群及其用例的详细回顾

丹尼斯·库默在 Unsplash 上拍摄的照片

地理空间聚类

地理空间聚类是将一组空间对象分组为称为“簇”的组的方法。一个聚类中的对象表现出高度的相似性,而这些聚类尽可能地不相似。聚类的目标是进行概化并揭示空间和非空间属性之间的关系。

让我们用一个小例子来理解空间聚类。

假设你是一家大都市食品配送连锁店的负责人,你想了解顾客的偏好,以便扩大业务规模。因为查看每个客户的详细信息是不可行的,所以你将他们分成不同的组,并为每个组/群制定商业计划。

空间聚类可分为以下五大类型:

1.划分聚类

2.分层聚类

3.模糊聚类

4.基于密度的聚类

5.基于模型的聚类

通过 Locale ,我们致力于让每个在地面上移动资产的企业都可以访问位置数据。让我们深入研究集群的类型,并详细了解每一种类型!

划分聚类

分区聚类是将数据点分离成不重叠的子集(聚类),使得每个数据点恰好在一个子集中。基本上,它通过满足这两个要求 : 将数据分类到

1.每个数据点仅属于一个聚类。

2.每个聚类至少有一个数据点。

划分聚类有三种类型:K-means 聚类、K-medoids 聚类/PAM 和 CLARA(分类大型应用)

1.k 均值聚类

K-means 聚类是一种分区方法,这种方法根据属性将数据集分解成一组 K-分区。你可以在这里阅读更多关于 k 的意思

来源

2.K-medoids 聚类/PAM

K-medoids 聚类是一种类似 K-means 聚类的划分方法med oid 是聚类中与该聚类中所有其他点具有最小相异度的点。查看这个来了解更多关于帕姆的信息。

来源

3.克拉拉

这是 PAM 方法对大型数据集的扩展。CLARA 不是为整个数据集寻找几何图形,而是考虑一个固定大小的小样本数据,并应用该算法为该样本生成一组最佳几何图形。

来源

使用案例:

通常,基于分区的聚类用于查找数据中没有明确标记的组。这有助于将任何新数据点分配到正确的聚类。企业使用基于分区的聚类来划分购买历史、按销售活动分组库存、在健康监控中识别组等。

优步使用聚类进行意图检测,他们将其用于一键式聊天/建议回复系统【来源】

分层聚类

分层聚类是一种类似于基于分区的聚类的聚类方法,但它对数据点进行分类的方式不同。它首先将每个数据点视为一个单独的聚类。然后合并彼此最接近的相似聚类。它不断迭代,直到所有的集群被合并。

两种类型的层次聚类如下:聚集和分裂

凝聚层次聚类

这与计算点/簇的邻近矩阵的简单算法一起工作。在每次迭代中,它合并最近的点/簇,并更新邻近矩阵。这一直持续到形成一个簇或 k 个簇。这可以被认为是一种“自下而上”的方法。

来源

分裂层次聚类

这与聚集聚类正好相反。在该方法中,最初,所有数据点被认为属于单个聚类。在每次迭代中,将不相似的数据点从聚类中分离出来。每个分离的数据点被认为是一个单独的聚类。这个过程一直持续到我们有了 K-clusters。这可以被认为是一种【自上而下】的方法

来源

使用案例:

虽然分层聚类在计算上可能是昂贵的,但是产生直观的结果。由于层次聚类不需要太多的假设,所以当手头的数据不太为人所知时,这是很有用的。分层聚类广泛应用的一个现实场景是在流行病传播期间绘制病毒图,以及在银行业或零售业中进行客户细分。

使用层次聚类将美国参议员分组到他们各自的党派中。红色代表共和党,蓝色代表民主党,黑色代表独立【来源】

模糊聚类

在模糊 c 均值聚类中,我们找出数据点的质心,然后计算每个数据点到给定质心的距离,直到形成的聚类变得恒定。它不同于基于分区的聚类,它允许将数据点部分分类到多个聚类中。

卫星图像的模糊聚类[ 来源

理论上,每个数据点可以属于隶属函数范围在 0 和 1 之间的所有组。 0 是数据点距离聚类中心可能最远的点, 1 是数据点距离聚类中心最近的点

使用案例:

当您需要进行图像分割或者您的目标是分割卫星图像中的水域、植被和岩石区时,模糊聚类非常有用。这在不能先验地确定聚类数的情况下是有用的。在这种情况下,可以合并具有弱边界的聚类。与 K-means 相比,模糊聚类在计算上是昂贵的,因为对于每个点,is 计算它属于每个聚类的概率。

基于密度的聚类

基于密度的聚类通过将高密度的区域分组并将它们与低密度区域分开来工作。最著名的基于密度的聚类算法是 DBSCAN 算法(应用噪声的基于密度的空间聚类)。

使用以下两个参数计算密度

  1. EPS: 这定义了数据点周围的邻域,即如果两点之间的距离小于或等于 EPS,则称它们为邻居

  2. MinPts :定义形成一个邻域的数据点的最小数量。数据集的大小和 MinPts 的值成正比。

DBSCAN 算法访问每个点,并且如果它包含 eps 内的 MinPts,则聚类形成开始。任何其他点都被定义为噪声。这一过程一直持续到形成一个密度连通的集群,然后从一个新的点重新开始。

左图:传统聚类;右图:DBSCAN 聚类(DBSCAN 允许点采用任何形状或维度来形成聚类)

使用案例:

DBSCAN 主要用于平面空间的聚类。如果将它用于绘制自然灾害的影响图或绘制城市中气象站的位置图,可以获得良好的结果。当数据由非离散点组成时,也可以使用这种方法,这有利于处理异常值。推荐引擎/系统利用 DBSCAN 向他们的客户推荐产品/节目。

基于模型的聚类:

这种分类方法使用特定的分类模型,并尝试优化数据和模型之间的匹配。在基于模型的聚类方法中,数据被视为来自概率分布的混合,每个概率分布代表一个不同的聚类。换句话说,在基于模型的聚类中,假设数据是由混合概率分布生成的,其中每个分量代表一个不同的聚类。每个分量(即,集群)由正态分布或高斯分布建模。

期望最大化是一种众所周知的基于模型的聚类算法。当数据符合模型时,特定的聚类算法被认为工作良好。

使用案例:

这在聚类具有弱边界并且数据点在聚类之间具有混合成员的情况下非常有用。它在聚类协方差方面也更加灵活。在这种情况下,集群分配更加灵活,集群可以根据分布采用任何形状。

用于分析新冠肺炎的地理空间数据和工具

原文:https://towardsdatascience.com/geospatial-data-and-tools-for-analyzing-covid-19-9eaf298512?source=collection_archive---------29-----------------------

一个数据,可视化,工具和项目的集合,参与到周围的新冠肺炎

新冠肺炎对世界各地的生活产生了巨大的、改变生活的影响,这一点无需赘述。随着我们周围的世界每天都在变化,人们越来越关注地理。

连线文章在疫情的热潮中,地理强势回归强调了我们重新关注我们与地理的关系。**

疫情正在重新定义我们与太空的关系。不是外太空,是物理空间。热点、距离、传播、规模、接近度。一句话:地理。突然,我们无法停止思考 在哪里

这不仅体现在我们如何思考我们与物理空间的日常关系,也体现在我们与数据和信息的关系。几乎在每一份新闻出版物中,你都可以找到与位置相关的地图和数据,信息每天都会被添加和更新很多次。

来自《纽约时报》的新冠肺炎病例总数(截至 2020 年 4 月 15 日)

虽然这种规模的危机在许多方面都是前所未有的,但对于那些处理地理空间数据的人来说,许多人都熟悉危机测绘的概念,即使用地理空间工具、数据和数字的力量来收集数据和信息,供应对危机的人使用。

这方面的第一个例子是对 2010 年海地地震的反应。在海地,可靠的地理空间数据(如道路和设施)有限,无法用来告诉当地的人们往哪里走。在地震后的几天里,许多人向 OpenStreetMap 贡献了自己的力量,这是一个类似于维基百科的开放项目,用户可以在地图上添加地理空间数据。

反应非常热烈。这些来自世界银行和 OpenStreetMap 博客维基的帖子描述了人们的反应,但是这段视频展示了地震后增加的数据量。

2010 年 1 月添加到 OpenStreetMap 的数据

从那时起,已经发生了许多使用地理空间数据和工具的不同灾难。从洪水、飓风、地震、火灾、流行病、人道主义危机、龙卷风等等,都利用地理空间数据来应对这些灾害。

新冠肺炎是一场规模更大的危机,但地理空间社区对这场危机做出了压倒性的回应,提供了数据、工具和参与方式。这篇文章的其余部分将旨在分享其中的一些举措。

如果有你知道的不在列表中的资源,请随意添加到回复中!

免责声明 :我的专长是地理空间数据和分析,而不是流行病学或空间流行病学。该指南只是地理空间社区提供的资源的集合。

数据

约翰·霍普金斯大学系统科学与工程中心(JHU·CSSE)的新冠肺炎数据仓库

JHU·CSSE 仪表板

该数据集被全球许多不同的机构和新闻组织使用,是疫情期间最常引用的数据源之一。

** [## CSSEGISandData/新冠肺炎

这是由约翰·霍普金斯大学运营的 2019 年新型冠状病毒视觉仪表板的数据存储库…

github.com](https://github.com/CSSEGISandData/COVID-19)

谷歌云也在谷歌云平台上提供了 JHU 的数据集,并且正在与一些组织合作。

未发布

未预测的社交距离记分卡

Unacast 是一家人类移动数据和见解公司,它已经建立了一个社会距离记分卡,使用移动数据来分析移动模式的变化,直到县一级。他们的首席执行官托马斯·沃勒(Thomas Walle)在 LinkedIn 上发帖称:

如果您希望将位置数据用于研究和公共卫生目的,请联系我们,我们将免费向您提供我们的全球数据集。我们相信我们的数据具有强大的力量——强大的力量意味着巨大的责任。

[## 托马斯·沃勒在 LinkedIn 上发帖

上周,一些研究机构、大学和健康组织联系了 Unacast

www.linkedin.com](https://www.linkedin.com/posts/thomaswalle_dataforgood-locationintelligence-geospatialdata-activity-6644427802152095744-IdHY)

疾病控制中心

美国县级的 SVI 数据

社会脆弱性也会对个人和社区如何受到疾病的影响产生重大影响。疾病控制中心(CDC)发布了其社会脆弱性指数,定义为:

社会脆弱性是指社区在面临人类健康面临的外部压力,如自然或人为灾害或疾病爆发时的复原力。降低社会脆弱性可以减少人类痛苦和经济损失。疾病预防控制中心的社会脆弱性指数使用 15 个美国人口普查变量来帮助当地官员识别在预防灾害方面可能需要支持的社区;或者从灾难中恢复。

您可以在县或美国人口普查区级别下载 shapefiles 形式的数据。

[## 社会脆弱性指数(SVI):数据和工具下载| CDC

完整的 SVI 文档可在每年的数据标题下下载。SVI 地理空间数据…

svi.cdc.gov](https://svi.cdc.gov/data-and-tools-download.html)

天气来源

天气和气候学会对新冠肺炎的发展产生影响,但人类对社会距离命令的反应也会产生影响。WeatherSource 是一个数据提供商,拥有大量与天气相关的数据集,包括预报和气候学,并向研究新冠肺炎的人开放其 API。

[## 天气资源-商业天气和气候技术。

仅在美国,天气造成的年收入损失就超过 6000 亿美元。每个人都谈论天气…

weathersource.com](https://weathersource.com/)

脸书

墨西哥 60 岁以上人口的分布。

通过他们的 Data for Good 计划,脸书正与不同的研究人员和网络合作,提供广泛的匿名数据,如高密度人口地图、社交连接、协同定位地图、移动数据等。一些资源是公开的,例如人口密度地图,而其他资源是为特定组织保留的。

[## 脸书-人道主义数据交换

我们很想听听那些使用这些数据集来改进我们的产品并更好地了解……

data.humdata.org](https://data.humdata.org/organization/facebook)

OpenStreetMap

纽约市的开放街道地图

OpenStreetMap 通过一个名为 Planet.osm 的项目,在一个可下载的文件中提供其全球数据集和不同地理上更小的摘录。这包含了你在地图上看到的所有数据:道路、建筑、交通、兴趣点、医院、土地、水等。您还可以使用用户界面transition Turbo来提取通过transition API从 OSM 查询的数据。请记住,OSM 数据是用户生成的,在某些领域可能不完整。

[## 星球网

这里找到的文件是定期更新的,OpenStreetMap.org 数据库的完整副本,以及那些出版的…

planet.openstreetmap.org](https://planet.openstreetmap.org/)

纽约时报

《纽约时报》正在 GitHub 上提供美国地图背后的国家、州和县级数据。

[## 纽约时报/新冠肺炎数据

美国州级数据(原始 CSV) |美国县级数据(原始 CSV)】纽约时报发布了一系列数据…

github.com](https://github.com/nytimes/covid-19-data)

新冠肺炎移动数据网

新冠肺炎移动网络被描述为:

…一个由世界各地大学的传染病流行病学家组成的网络,与科技公司合作,使用聚合的移动数据来支持新冠肺炎应对措施。我们的目标是利用来自移动设备的匿名聚合数据集,以及对解释的分析支持,为州和地方层面的决策者提供关于社交距离干预效果的每日更新。

有一个电子邮件联系他们,但你可能需要成为一个学术机构的一部分,才能使用这些数据。

[## 新冠肺炎移动数据网络

COVID19 移动数据网络的参与者共同致力于隐私价值和数据保护,因为…

www.covid19mobility.org](https://www.covid19mobility.org/)

联合国人道主义事务协调厅(OCHA)人道主义数据交换

联合国 OCHA 新冠肺炎资料页

联合国 OCHA 人道主义数据交换有许多不同的数据集可用于新冠肺炎(以及其他国家),包括上述一些数据集以及意大利的移动模式数据、测试数据和其他国家的特定数据。

[## 新冠肺炎·疫情

新冠肺炎旅行限制监测-使用二级数据源,如国际航空运输…

data.humdata.org](https://data.humdata.org/event/covid-19)

工具

卡通

CARTO 是一个空间平台,提供了广泛的工具来存储、分析和可视化空间数据,他们正在将其平台提供给公共和私人组织:

出于这个原因,CARTO 将通过我们的资助项目向抗击冠状病毒爆发的公共和私营部门组织开放其平台。无论您是为公众分享建议的媒体机构、优化资源配置的医疗保健组织还是希望评估封锁影响的政府实体,我们都希望帮助您处理您的使用案例,并确保我们在此次疫情期间共同做出数据驱动的决策。

该程序已经被许多组织使用,包括 ForceManagermendesaltaren 之间的合作,以及来自 TelefónicaFerrovialGoogleSantander 的额外支持,以开发 AsistenciaCOVID-19 ,一个自我诊断和新冠肺炎信息应用程序。

[## CARTO 为对抗新冠肺炎的组织提供免费的可视化软件

在抗击新冠肺炎的斗争中,地图已经成为了解疾病传播的一个有价值的工具。许多…

carto.com](https://carto.com/blog/carto-free-for-fight-against-coronavirus/)

ESRI

ESRI 是一家地理空间软件和平台提供商,为世界各地许多不同的私人和公共组织提供广泛的地理空间分析工具和产品。从他们的新冠肺炎资源页面:

随着围绕冠状病毒疾病 2019(新冠肺炎)的形势继续发展,Esri 正在为我们的用户和整个社区提供位置智能、地理信息系统(GIS)和制图软件、服务以及人们用来帮助监控、管理和交流疫情影响的材料。使用并分享这些资源来帮助你的社区或组织做出有效的反应。

在这里,您可以请求 GIS 帮助、访问 GIS 资源、查看地图和仪表盘,以及获得与新冠肺炎相关的信息。

[## 冠状病毒疾病(新冠肺炎)地图、资源和见解

随着围绕冠状病毒疾病 2019(新冠肺炎)的形势继续发展,Esri 正在为我们的用户提供支持…

www.esri.com](https://www.esri.com/en-us/covid-19/overview)

QGIS

QGIS 是一个免费的开源桌面 GIS 工具,允许您使用地理空间数据、创建地图、执行地理空间操作、连接到外部工具以及与非常广泛的插件生态系统集成。

[## QGIS

了解 QGIS 项目及其社区的进展情况。

www.qgis.org](https://www.qgis.org/en/site/)

仪表板

谷歌移动报告

样本谷歌移动报告

谷歌正在使用其平台上收集的移动数据来创建和发布移动报告,这些报告捕捉了几个不同场所类别(如零售和娱乐、公园、杂货店和药店等)中移动模式的变化。

社区流动性报告旨在提供对旨在抗击新冠肺炎的政策发生了哪些变化的见解。这些报告按地理位置绘制了不同类别场所(如零售和娱乐场所、杂货店和药店、公园、中转站、工作场所和住宅)的移动趋势。

[## 新冠肺炎社区流动性报告

随着全球社区对新冠肺炎做出反应,我们从公共卫生官员那里听说,同样类型的聚集…

www.google.com](https://www.google.com/covid19/mobility/)

Domo

多莫新冠肺炎地理空间仪表板

BI 公司 Domo 使用约翰·霍普斯金新冠肺炎公司的数据创建了一整套地理空间和非地理空间仪表板,包括每日更新、地图、测试、经济、预测等主题。

[## 冠状病毒(新冠肺炎)美国和全球地图| Domo

冠状病毒(新冠肺炎)使用 Domo 的商业云按国家、地区、州或县绘制的交互式地图。看…

www.domo.com](https://www.domo.com/covid19/geographics#global-tracker)

画面

Tableau 共享了一个使用 Tableau 发布的不同仪表板的图库,以及一个使用约翰·霍普斯金新冠肺炎数据的入门工作簿。

[## 新冠肺炎冠状病毒数据资源中心

太平洋标准时间每天晚上 10 点更新,这个全球指标仪表板可视化约翰霍普金斯大学数据的子集…

www.tableau.com](https://www.tableau.com/covid-19-coronavirus-data-resources)

Cuebiq

Cuebiq 是一家人类移动数据提供商,它发布了一系列交互式可视化和分析,使用的数据涉及广泛的主题,包括《纽约时报》的几篇文章,分析意大利的移动模式等。

[## 新冠肺炎视觉画廊-奎比格

可视化公司如何使用 Cuebiq 的位置数据来构建自己的仪表板,以分析…

www.cuebiq.com](https://www.cuebiq.com/visitation-insights-covid19-dashboard-gallery/)

路灯数据

StreetLightData 使用移动数据来分析道路上的交通模式,以了解汽车流量计数、交通分析等。使用他们的数据结合 Cuebiq 数据来分析美国每天的车辆行驶里程(VMT)是如何变化的。您可以使用地图并下载数据。

[## 3,000 多个美国县的近实时每日 VMT

在这个前所未有的旅游波动时期,汽车行驶里程(VMT)的下降如何影响您的…

www.streetlightdata.com](https://www.streetlightdata.com/VMT-monitor-by-county/)

参与其中

火辣的 OSM

人道主义 OpenStreetMap 团队(HOT)是一个即使只有几分钟空闲时间也能参与进来的好地方。HOT OSM 是一个任务系统,不同的组织可以请求帮助收集受重大灾害影响的不同地区或社区的数据,类似于前面描述的 2010 年海地地震。

任务管理器是为人道主义 OpenStreetMap 团队在 OpenStreetMap 中的协作制图过程而设计和构建的制图工具。该工具的目的是将一个制图项目划分为较小的任务,这些任务可以由许多人在同一个整体区域内快速完成。它显示了哪些区域需要映射,哪些区域需要验证映射。

这种方法允许在紧急情况或其他人道主义绘图情况下将任务分配给许多单独的绘图者。它还允许监控整个项目进度,并帮助提高映射的一致性(例如,要覆盖的元素、要使用的特定标签等)。).

在全球各地的社区中,有许多不同的与新冠肺炎相关的开放任务。你只需要在 OpenStreetMap 上创建一个账户,然后选择你想要参与的项目。从那里你将简单地跟踪一个卫星图像,找到该项目所要求的不同功能。

[## 热门任务管理器

为了充分利用任务管理器中的许多功能,请使用台式机或笔记本电脑,而不是…

tasks.hotosm.org](https://tasks.hotosm.org/contribute?difficulty=ALL&text=covid)

其他资源

NAPSG 基金会

公共安全 GIS 国家联盟(NAPSG)正在其网站上收集与新冠肺炎相关的各种资源,包括地图、仪表盘、数据、资源等。

[## 新冠肺炎地理空间和态势感知资源

最后更新:上午 11:40 美国东部时间 04/13/2020 NAPSG 基金会正在编制公开可访问的新冠肺炎地理空间和…

www.napsgfoundation.org](https://www.napsgfoundation.org/resources/covid-19/)

OGC

开放地理空间联盟(OGC)正在收集许多地理空间资源,包括底图、数据和数据管道、资源、仪表盘以及关于可视化数据和制图最佳实践的建议。

[## 来自 OGC 的新冠肺炎资源

了解新冠肺炎疫情的范围及其与人口、基础设施和其他方面的关系

www.ogc.org](https://www.ogc.org/resources-for-COVID-19-from-ogc)

编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 **

使用四键的地理空间索引

原文:https://towardsdatascience.com/geospatial-indexing-with-quadkeys-d933dff01496?source=collection_archive---------16-----------------------

给地球正方

斯蒂夫·约翰森Unsplash 上拍照

当你在网上或手机上浏览交互式地图时,你看到的是一幅幅方形拼贴画的效果。每个图块包含一点地图信息,并与其周围的八个图块完美匹配。这种安排非常有效,以至于你几乎不可能察觉到你不是在浏览一个无限的位图,而是一个有限的小方块。

本文的目的不是深入研究所谓的“滑动地图的复杂性,而是讨论一个有趣的数学副产品,它用于唯一地引用瓦片,但在地理空间索引应用程序中也非常有用。为了跟踪他们的交互式地图解决方案,微软开发了一个索引概念,这在其在线文档中有详细描述,即 Bing 地图磁贴系统

这个索引系统还有其他不太明显的应用,比如地理空间区域的划分和它们在数据库中的有效索引。它的工作原理有点像优步的 H3,但是它没有使用“六边形”,而是使用了“正方形”的层次结构我在几何形状的名字周围加了引号,因为它们在球体上的投影自然会扭曲它们。

我们之前已经看到了使用 H3 地理空间索引系统的优势,不仅用于快速参考,还用于快速距离查询。由于它们的几何形状,正方形的工作效率不高。不过,它们也有显著的优势,不仅在为光滑地图生成定制切片时,而且在索引矩形数据时。这里我考虑的是对在线地图服务的查询。这些查询通常需要一个边界框规格,矩形(至少在投影坐标中),而不是六边形。

缓存使用案例

为了激励使用 Bing 地图磁贴系统及其“四键”概念背后的数学,让我们回到我已经发布的关于探索车辆能源数据集的代码。在之前的一组文章中,我通过将数据转换成数据库,将出行数据聚类成其端点簇,使用 H3 计算地理围栏多边形,并最终命名它们来接近 VED。

这个命名过程包括通过他们的公共和免费的天桥 APIOpenStreetMap 服务中检索数据。我还设计了一个非常简单的缓存机制,以避免在开发代码时重复调用 API。用户不应该滥用 API 并尽可能缓存检索到的数据。我缓存 API 结果的方法很幼稚,因为我使用集群标识符作为文件名的基础。这里没有地理参考,并且如果聚类算法参数化改变,这些文件名容易改变。

我在本文中探索的另一个解决方案涉及到使用以某种方式在地理上被引用并且与算法变化无关的文件名。输入四键代码。

四键

quadkey 这个名字是 quadtree key 的缩写。这些键中的每一个都编码了由细节级别组织的纬度和经度空间中的正方形区域。在第一层,整个可绘制的地球表面分成四个四键。可以把它想象成一个地图缩放级别,让你看到整个世界。每个四键都有一个一位数的代码,从 0 到 3。通过放大到下一个级别,四个原始四键中的每一个都分裂成四个,我们在代码中添加另一个数字。下面的图片来自微软官方文档,描述了这个过程。

上图说明了如何根据位置和细节层次导出四键代码。(图片来源:微软- 必应地图磁贴系统)

通过查看上面的图像,我们可以立即想象一个可能的“代数”来操作四键。计算特定四键的邻居、孩子或父母的操作会立即浮现在脑海中。也可以查询四键的地理属性,比如角、中心和边的长度。幸运的是,这种数学工具已经以" pyquadkey2 " Python 包的形式存在。

如果你用低级软件开发人员的眼光来看待四键编码,你会发现编码一个细节层次只需要两位。典型的 23 级最大值只需要 46 位来编码,这允许我们使用 64 位整数来存储这些代码。幸运的是,上面的包所遵循的二进制四键的规范已经存在。

缓存示例

让我们看看如何在缓存用例中使用四键。这个想法是收集包含所有聚类点的最小四键集,然后只查询 OSM 的边界坐标。然后,代码将每个回复存储在一个相应的 JSON 编码的文本文件中,该文件根据使用的四键命名。通过这种方式,我们得到了一个仅依赖于地理位置的 OSM 数据缓存,而不是依赖于聚类方案。下图显示了编号为 52 的簇的 18 级四键。

上图显示了 52 号星团,叠加的四键用于缓存其 OSM 数据。作者创造的形象。

正如您所看到的,细节层次的选择是一个重要的决定,它允许您在四键的数量和为每个键收集的信息量之间进行权衡。官方文档包含一个指导您选择细节层次的表格。表格的第三列显示了在赤道以米/像素测量的地面分辨率。选择每像素米作为单位揭示了它的最终目的:使用 256 像素宽的方形图块的光滑地图。您需要将列值乘以 256,以获得赤道上四键边的米数。在第 18 层,我们得到 152.88 米。请记住,当你远离赤道,宽度缩小到零。

密码

要遵循代码描述,请克隆 GitHub 库并运行名为:

07-cluster-names-quadkey.ipynb

这个文件是一个已有文件的修订版,具有相同的前缀号码和旧的缓存实现。请注意,在运行上面的笔记本之前,您可能必须执行以前的笔记本,以准备好要使用的数据库。

我们从管理缓存的函数开始。第一个是对 OSM API 的低级调用,在没有缓存信息时使用。

下一个函数使用四键作为输入来查询数据。它确定数据是否已经被缓存,在这种情况下,它只从相应的文件中读取数据,如果没有,则从 API 中查询数据并缓存它。

注意我们是如何查询 quadkey 在西南角和东北角的地理坐标的。现在我们有了四键数据,我们必须在查询它之前合并它。请记住,每个簇通常有多个四键。为了连接数据,我们必须首先查询它的元素类型,即“node”和“way”,为此我们使用了 next 函数。

执行实际合并的函数剥离所有元数据,只保留“元素”数组。

现在,当合并 OSM 数据包列表时,我们可以使用前面的函数作为构建块。

该代码使用下面的函数检索与单个集群相关联的四键。每个点被转换成一个四键代码,并添加到一个集合中,为了唯一性,转换回一个列表,并返回。

我们现在准备将所有代码放在一个函数中,该函数检索单个集群的合并 OSM 数据。

从这个函数开始,笔记本代码非常接近于它的原始版本。唯一有意义的增加是在地图上再现了四键“方块”,如上面星团 52 的图像所示。

结论

本文展示了如何使用四键数学来生成地理空间索引。这些操作非常类似于 H3,但是是正方形而不是六边形。我们已经看到六边形对于某些应用更好,例如 KNN 搜索。尽管如此,正方形对于模拟 sippy 地图瓦片和与地球的纬线和经线对齐的矩形区域是完美的。由于将四键代码打包成 64 位整数更加方便,并且支持非常高效的 Python 包,四键确实是地理空间工具包中的另一个好工具。

参考

必应地图磁贴系统

资源

GitHub 资源库

pyquadkey2 资源库

CartoDB python-quadkey 存储库(这里使用的替代包)

YouTube: 地球平铺显示四键

相关文章

[## 使用 HDBSCAN 进行地理聚类

如何使用 HDBSCAN、H3、图论和 OSM 探索地理数据。

towardsdatascience.com](/geographic-clustering-with-hdbscan-ef8cb0ed6051) [## H3 的快速地理空间索引

H3 六角电力重装上阵!

towardsdatascience.com](/fast-geospatial-indexing-with-h3-90e862482585)

使用 R 的地质统计学实践

原文:https://towardsdatascience.com/geostatistics-in-practice-using-r-4b7d32b7840d?source=collection_archive---------24-----------------------

照片由捕捉人心。 on Unsplash

如何使用带有 R 的地理定位数据进行估计

介绍

在本文中,您将了解什么是地质统计学,以及如何使用克里金法(一种插值方法)利用地理位置数据进行估算。在我们的示例中,我们将获取纽约的房地产销售价格,并创建一个模型,为我们提供城市中任何位置的价格估计。

开始之前,让我们先了解一下如何将地统计数据插入到空间统计数据的字段中。

空间统计

空间统计学是统计学中一个相对较新的领域,它基于数据之间的空间相关性的思想:两个观测值在空间上越接近,它们的相关性就越强。时间相关性已经研究了很长时间,但是不可能将时间序列模型直接应用于空间数据,因为时间相关性假设通常使用序列相关性结构,而空间相关性发生在二维或三维。然而,有时空模型同时结合了两者。

在空间统计中,有四类数据:地统计格网。我们在这里只讨论地质统计学,但是知道其他的有助于我们理解什么是地质统计学。

地统计数据中,随机变量可以在集合中的任意无限点(例如,一个城市或一个国家)进行测量,尽管实际上,它只在某些点进行测量。这就是我们将使用的例子的情况:你可以在纽约的任何一点(我们的集合)有房地产价格(我们的随机变量),我们只在其中的一些点(销售实际发生的点)测量它。然后我们的兴趣将是为没有发生销售的点估计相同的变量。

地统计数据示例-按作者分类的影像

点阵数据中,一个随机变量在一个有限集中被度量,用一个矩阵表示,可以是正则的,也可以不是。一个例子是,当我们把一个国家分成几个州,然后测量每个州的平均收入。

晶格数据的例子。如果你想探索这张地图,这里是它的链接——作者图片

点数据中,随机性不一定来自变量,而是来自它的位置。例如,如果我们想要了解或预测城市中的犯罪地点:我们会有一系列犯罪地点,并对寻找高密度的聚类(危险区域)感兴趣。

点数据示例-按作者分类的图像

流数据中,我们有一个随机变量,它不仅与一个位置相关,而且与两个位置相关。迁移数据就是一个例子:对于任意两两组合的地点,我们知道从一个地点到另一个地点的人数。

流量数据示例—按作者分类的图像

现在我们知道什么是地质统计学(什么不是)。在了解克里金法之前,我们还有最后一个话题要讲:变异函数。

变异函数

如果空间统计基于“两个观测值在空间上的距离越近,它们的相关性就越强”这一思想,则变异函数会根据这些观测值之间的距离显示相关性的表现。

变异函数被定义为“给定两次观测之间的距离,返回这两次观测之间差异的方差的函数”。

以下是纽约房地产价格的经验变异函数示例。

作者图片

正如我们所见,两栋建筑离得越远,它们的价格差异就越大,相关性就越低。

基于这些点,我们可以估计一个非常适合它们的函数,然后将它用于克里金法。

作者图片

克里金法

克里金法是一种插值方法:给定一些数据点,它试图找到一个穿过这些点的函数,这样就可以对中间值进行估计。

虽然线性回归和反距离加权插值法基于假设的预定义模型,但克里金法基本上是根据经验构建的。它的优势之一是它不是一个确定性的模型,而是一个概率性的模型,这意味着它不仅给你一个估计,它还告诉你你对这些估计有多确定。

进行这些估计的公式如下:

权重是根据变异函数估算的,并且完全取决于观测值之间的距离。

用 R 怎么做

数据

我们将使用在 Kaggle 上提供的数据集,其中包含 2016 年纽约市的房产销售数据:位置、价格、面积、税收等级等。鉴于我们在这里的目标,我们将忽略除了它的位置,价格和面积的财产的所有信息。我们使用面积的原因是我们想计算每平方英尺的价格,而不仅仅是销售价格。从现在起,我们将只谈每平方英尺的价格,并把它称为“价格”。

代码

完整的代码可以在这里找到。在本文中,我们将只浏览它的主要部分。

在进行了一些数据清理之后,我们首先来看看价格在地图上的表现:

**IN:**
# Plotting prices
mapnyc <- data.frame(latitude = db$lat,
                     longitude = db$lon,
                     price = db$PRICE.SQUARE.FEET)Token_map_box = #<mapbox API token>palette_rev <- rev(brewer.pal(10, "RdYlBu"))pal <- colorNumeric(palette = palette_rev, domain = c(max(mapnyc$price):min(mapnyc$price)))
leaflet() %>%  addTiles(urlTemplate = Token_map_box) %>%
  addCircleMarkers(data = mapnyc, color = ~pal(price), radius = 2)

是的,这和我们在开头看到的情节是一样的——作者的图片

正如我们所看到的,曼哈顿的销售少了很多,尤其是在较低的部分。此外,那里的价格似乎比皇后区(东部)要高很多。此外,我们可以看到,紧挨着水的房产也更贵,这是有道理的,因为他们可能有很好的风景。

现在,让我们看看价格是否遵循正态分布:

**IN:**
hist(db$PRICE.SQUARE.FEET)**OUT:**

作者图片

正如我们所看到的,我们的数据不是正态分布的,所以让我们使用它的日志来代替。请注意,这一步并非绝对必要:遵循正态分布的数据不是克里金法的假设之一。然而,在这种情况下,预测能力有所提高。

**IN:**
db$PRICE.SQUARE.FEET.log = log(db$PRICE.SQUARE.FEET)
hist(db$PRICE.SQUARE.FEET.log)**OUT:**

作者图片

目前,我们所做的只是使用一个常规的数据帧。然而,空间数据在 r 中的行为方式完全不同。我们可以将我们的数据框架转换为 SpatialPointsDataFrame,它将点数据存储为位置,以及关于它们的附加信息(如价格)。在此之前,我们还将把数据帧分成训练集和测试集,以便在最后计算一些误差指标。

**IN:**
# Train/test split
smp_size <- floor(0.75 * nrow(db))set.seed(123)
train_ind <- sample(seq_len(nrow(db)), size = smp_size)train <- db[train_ind, ]
test <- db[-train_ind, ]# Converting to spatialpointsdataframe
projection = "+proj=longlat +ellps=WGS84 +no_defs"train_spdf = SpatialPointsDataFrame(train[28:29], train[-c(28,29)], proj4string = CRS(projection))
test_spdf = SpatialPointsDataFrame(test[28:29], test[-c(28,29)], proj4string = CRS(projection))
db_spdf = SpatialPointsDataFrame(db[28:29], db[-c(28,29)], proj4string = CRS(projection))

请注意“sp”包中的函数 SpatialPointsDataFrame。它将位置列作为第一个参数,其余数据作为第二个参数,投影作为第三个参数。投影是将球面坐标转换成平面坐标的函数。有许多不同的方法可以做到这一点,我们使用了 WGS84 系统。

然后我们移除所有重复的位置,因为克里金法在每个位置只取一个值(价格)。

**IN:**
# Removing duplicate locations
train_spdf = train_spdf[-zerodist(train_spdf)[,1],]
test_spdf = test_spdf[-zerodist(test_spdf)[,1],]
db_spdf = db_spdf[-zerodist(db_spdf)[,1],]

现在,让我们通过查看一般经验变异函数来看看是否存在任何空间相关性。同时,我们还可以找到变差函数的最佳拟合,并将两者一起绘制。

**IN:**
# Choosing the best variogram
vario.fit = autofitVariogram(PRICE.SQUARE.FEET.log~1,
                             train_spdf,
                             model = c("Exp", "Sph"),
                             kappa = c(0, 0.01, 0.05, seq(0.2, 2, 0.1), 5, 10),
                             fix.values = c(NA),
                             start_vals = c(NA),
                             verbose = T)fit.v = vario.fit$var_modellzn.vgm <- variogram(PRICE.SQUARE.FEET.log~1, train_spdf) # calculates sample variogram values 
lzn.fit <- fit.variogram(lzn.vgm, model=fit.v, fit.kappa = TRUE) # fit modelplot(lzn.vgm, lzn.fit) # plot the sample values, along with the fit model**OUT:**

作者图片

这里的经验变异函数用圆圈表示,而我们的拟合用直线表示。“automap”软件包有一个名为“autofitVariogram”的功能,它从用户给定的参数组合(如函数的形状)中找出经验变异函数的最佳拟合。空间相关性似乎很明显,我们的线与数据相当吻合,所以我们继续。

现在我们已经从可用数据中获得了变差函数,我们希望绘制新数据的估计值,以便创建纽约的价格热图。要做到这一点,我们需要一个 NY 网格,它实际上是城市边界内的一组小方块。这也许是讨论 r 中不同类型的空间数据的好时机。空间坐标可以给你线多边形。我们的价格数据是以点数给出的,纽约市的边界是以多边形给出的,可以在这里下载作为 shapefile(。shp)。

**IN:**
# Getting NY polygon
ny_polygon = st_read('data/borough_boundaries/geo_export_a88ff5b0-7fb1-479d-a22b-224328f6d976.shp')
ny_polygon = st_transform(ny_polygon, projection)spd <- sf::as_Spatial(st_geometry(ny_polygon), IDs = as.character(1:nrow(ny_polygon)))
spd_data = ny_polygon
spd_data$geometry = NULL
spd_data <- as.data.frame(spd_data)
spd <- sp::SpatialPolygonsDataFrame(spd, data = spd_data)grid <- makegrid(spd, cellsize = 0.001)
grid <- SpatialPoints(grid, proj4string = CRS(projection))
grid <- grid[spd, ]

我们在这里做的是使用与原始数据相同的投影获得 NY 多边形,将其转换为 SpatialPolygonsDataFrame,然后使用它来制作网格,其中每个单元格的大小等于变量“cellsize”。该数值越小,地图就越详细(或像素化程度越低),但构建地图的时间就越长。

然后,我们转到克里金法部分本身,将它应用到网格中:

**IN:**
# Kriging
heat = krige(PRICE.SQUARE.FEET.log ~ 1, locations = train_spdf, newdata = grid, model = fit.v)heat %>% as.data.frame %>%
  ggplot(aes(x=x1, y=x2)) + geom_tile(aes(fill=var1.pred)) + coord_equal() +
  scale_fill_gradient(low = "yellow", high="red") +
  scale_x_continuous(labels=comma) + scale_y_continuous(labels=comma) +
  theme_bw()**OUT:**

作者图片

这里,我们使用函数“克里格”,告诉它使用什么模型(“fit.v”是我们拟合变差函数的地方),“newdata”是我们的网格。然后我们将其绘制成热图,我们可以清楚地看到曼哈顿下城周围的高价格区域为红色区域,尽管我们在那里没有太多的数据。

然后,让我们评估我们的模型在测试数据中的性能,将其与另一个更简单的方法进行比较:K-最近邻 (KNN)。简而言之,KNN 要做的是,对于测试集上的每一栋建筑,取最近的 K 栋建筑的价格(在我们的例子中,K 的最佳值是 14),并用它们的平均值来估算价格。我不会在这里讨论我们的 KNN 模型的细节,因为这不是本文的范围,但是您可以在 GitHub 上的完整代码中找到它。

**IN:**
kriging_error = rmse(test_spdf$PRICE.SQUARE.FEET, exp(kriging_test_prediction$var1.pred))knn_error = rmse(test$PRICE.SQUARE.FEET, exp(knn_model$pred))# final results
cat(paste('Kriging error:', kriging_error, '\nKNN error:', knn_error))**OUT:**
Kriging error: 159.360604969667 
KNN error: 162.557634288862

这里,我们使用了均方根误差 (RMSE)来比较这两个模型,它取预测值和实际值之间的平均平方差的平方根。正如我们所见,克里金法误差略小,但幅度非常小。根据应用的不同,选择 KNN 可能会更好,因为它计算起来更快更容易。然而,这里的目标是展示克里金法的工作原理以及如何使用 r。

更进一步

如果您想使用这些数据尝试更高级的方法,那么查看克里金回归可能会很有意思,它使用其他解释变量(例如建筑物的建造年份)将克里金与回归结合起来。

此外,如果您喜欢这篇文章,您可能也会对另外两篇文章感兴趣:

[## 数据科学的抽样方法

从人群中获取样本的最好方法是什么?

towardsdatascience.com](/sampling-methods-for-data-science-ddfeb5b3c8ed) [## 如何提高你的机器学习模型质量?

数据科学家减少分类 ML 模型错误的逐步方法

towardsdatascience.com](/how-can-you-improve-your-machine-learning-model-quality-b22737d4fe5f)

如果你想进一步讨论,请随时通过 LinkedIn 联系我,这将是我的荣幸(老实说)。

用 JavaScript 实现 GeoTIFF 坐标查询

原文:https://towardsdatascience.com/geotiff-coordinate-querying-with-javascript-5e6caaaf88cf?source=collection_archive---------28-----------------------

如何在没有外部库的情况下从地理空间栅格像元中检索数据

如果您在 Node.js 或客户端 JavaScript 中构建地理空间应用程序,您最终可能需要从特定坐标的栅格中提取数据,或者提取大量数据。从历史上看,这在 JavaScript 中并不简单,因为地理空间栅格最常见的格式是 GeoTIFF 文件类型,不容易解析。

作者图片

有一些可用的解决方案,随着 JavaScript 语言和节点生态系统的最新进展,这不再是过去的技术障碍。

GDAL?

在 JavaScript 真正有能力解析 GeoTIFF 文件之前——除非你用自己的包装器包装底层编程语言——最好的办法是通过exec()调用另一个应用程序,比如 python 脚本或命令行实用程序。第一个想到的是gdallocationinfo,它是 GDAL 套件的一部分,可用于使用纬度和经度查询栅格,如下所示:

gdallocationinfo -valonly -wgs84 <geotiff filename> <longitude> <latitude>

如果您只是查询栅格中的一个点,这种方法就足够了。然而,有一些问题:

  • 如果在客户端这样做,用户必须安装 GDAL。
  • 除了每次解析文件之外,通过exec()调用它还有一个开销。

作为一个现实世界的例子,使用这种方法查询 60 个 GeoTIFF 文件中的一个点,每个文件有数百个波段,在速度相当快的计算机上需要大约 10 秒钟的处理时间。多个点会很快累积成不合理的时间量。

如果调用 shell 脚本和加载文件是大部分开销,那么为什么不使用为库提供绑定的gdal npm 包呢?截至 2020 年 9 月,这也不是一个很好的选择,主要是因为它需要 GDAL 版本 2(当前版本是 3.1),所以如果你在你的机器或服务器上安装了 GDAL,你将不得不做一些困难的版本杂耍来使它工作,如果你甚至可以让它从源代码开始构建。它也不提供异步绑定,这意味着如果您不希望您的线程被阻塞,您必须设置 web workers(如果运行 Node.js 服务器,这是有问题的,取决于您打算做多少处理)。

作者图片

GeoTIFF.js

这个库已经存在了 4-5 年,几个月前才发布了 1.0.0 版本。GeoTIFF.js 不仅为同名文件类型提供了读写功能,还提供了内置的异步功能,甚至还有一个 web worker 池来处理更重要的任务。

该库本身没有提供一种简单的方法来查询栅格中的地理坐标,因此您需要自己编写该功能。然而,一旦您从 GeoTIFF 中提取地理元数据,这就非常容易了。

首先,加载 GeoTIFF 及其相关图像。为了获得最佳效果,请确保首先将其投影到 WGS84。如果您将文件保存在内存中,您将不会处理从磁盘中重复读取它的开销,尽管它可能很小:

const file = await geoTIFF.fromFile(<geotiff filename>);
const image = await file.getImage();

现在,获取地理信息并计算一些数字,您将使用这些数字来计算哪个像素对应于给定的纬度和经度:

const bbox = image.getBoundingBox();
const pixelWidth = image.getWidth();
const pixelHeight = image.getHeight();
const bboxWidth = bbox[ 2 ] - bbox[ 0 ];
const bboxHeight = bbox[ 3 ] - bbox[ 1 ];

边界框数据存储为[xMin, yMin, xMax, yMax]。我们现在可以获得坐标,并计算出它对应于哪个像素:

const widthPct = ( <longitude> - bbox[ 0 ] ) / bboxWidth;
const heightPct = ( <latitude> - bbox[ 1 ] ) / bboxHeight;
const xPx = *Math*.floor( pixelWidth * widthPct );
const yPx = *Math*.floor( pixelHeight * ( 1 - heightPct ) );

注意, *heightPct* 已经被倒置,因为这个天气模型的原点在左下角。一些天气模型在右上角有它。你可能需要写一些代码来决定是否基于这个事实反转 *heightPct*

现在怎么办?当然,您可以从image中提取整个光栅。对于较小的图像,这很好,您可以将整个数据数组保存在内存中,这样查询起来非常便宜和快速。但是,如果您正在处理大型栅格和/或大量波段,这将需要很长时间和相当多的内存。

幸运的是,GeoTIFF.js 提供了一种使用边界框提取栅格的方法,因此我们将只使用一个逐个像素的边界框。事实证明,这非常快速,即使是在具有大量波段的非常大的栅格上也是如此(此外,GeoTIFF.js 支持切片栅格-切片大栅格应该可以进一步提高性能,但我尚未对其进行测试。):

const window = [ xPx, yPx, xPx + 1, yPx + 1 ];
const data = await image.readRasters( {window} );

现在你有了这个特定点上所有波段的数组。

[
  Float32Array [ 0.07990912348031998 ],
  Float32Array [ 0.16144123673439026 ],
  Float32Array [ 0.1751343011856079 ],
  Float32Array [ 0.2101452350616455 ],
  Float32Array [ 0.2505287826061249 ],
  Float32Array [ 0.3461601734161377 ]
  ...
]

请注意,您可以让readRasters使用一个 web worker 池,这增加了多线程的潜力,但是使用这样小的边界框,启动一个新的 web worker 的开销会大大降低性能,所以不建议使用这种方法。

作者图片

性能比较

GeoTIFF.js 查询逻辑如何应对对gdallocationinfo的调用?这可能取决于你打开了多少个文件(尤其是重复打开),但是我的实验和实践结果是决定性的。在一个固态硬盘上,我使用相同的纬度和经度查询了相同的栅格(大约 500px 乘 200px,有 250 个波段),并记录了经过的毫秒数。

exec(gdallocationinfo…)

Run 1: 62ms
Run 2: 163ms
Run 3: 64ms
Run 4: 68ms
Run 5: 176ms
----
Average: 106.6ms

这种方法似乎每运行几次就会经历随机的停顿,这对它的总处理时间是有害的。除了我的服务器之外,我的开发计算机也注意到了这一点。

GeoTIFF.js

Run 1: 58ms
Run 2: 60ms
Run 3: 60ms
Run 4: 54ms
Run 5: 57ms
----
Average: 57.8ms

这个库不仅比调用gdallocationinfo稍快,而且性能非常稳定,几乎将平均处理时间减半。

使用这种技术,我能够将 JavaScript 天气预报算法的性能提高近三倍,因为它可以读取大约 60 个地理位置和数千个波段。使用gdallocationinfo,这通常需要大约十秒钟。在使用 GeoTIFF.js 切换到上述技术后,该算法运行时间不到三秒。如今,通过一些额外的缓存技术,我的生产服务器可以在不到一秒钟的时间内检索到从几千个栅格波段生成的预测-只有迁移到完整的二进制或其他一些更具编译性的解决方案,性能才有可能得到显著提高。

当然,还有其他读取 GeoTIFF 数据的外部库,但是用exec()调用它们似乎不太可能比 GeoTIFF.js 提供更多的优势,特别是因为您无法将 GeoTIFF 图像或数据本身(作为原始数值数组)缓存在您的 JavaScript 应用程序中。

是的,你总是可以用一种实际上适合处理这些数据的语言或框架来阅读 GeoTIFFs,但是这种范式正在开始改变。JavaScript 继续发展和成熟,Node.js 中构建的服务器变得越来越常见,实现类似基于浏览器的天气模型分析应用程序不再是白日梦。您可能需要使用这种技术。也许你会想出更快的东西,如果是这样,我很想听听!

使用 Bitnami 获得完全配置的 Apache Airflow Docker 开发堆栈

原文:https://towardsdatascience.com/get-a-fully-configured-apache-airflow-docker-dev-stack-with-bitnami-ed1671d63ea0?source=collection_archive---------48-----------------------

我已经使用它大约两年了,来构建定制的工作流界面,如用于实验室信息管理系统(LIMs)、计算机视觉预处理和后处理管道的界面,以及设置和忘记其他基因组学管道。

我最喜欢的气流特征是,它对你正在做的工作或工作发生的地点完全不可知。它可以发生在本地、Docker 映像上、Kubernetes 上、任意数量的 AWS 服务上、HPC 系统上等等。使用 Airflow 可以让我专注于我试图完成的业务逻辑,而不会在实现细节上陷入太多。

在那段时间里,我采用了一套系统,通过 Docker 和 Docker Compose 快速构建主开发堆栈,使用了Bitnami Apache air flow stack。一般来说,我要么使用相同的 Docker compose 堆栈(如果它是一个足够小的独立实例)将堆栈部署到生产环境中,要么在我需要与其他服务或文件系统交互时使用 Kubernetes。

比特纳米 vs 滚自己的

我曾经用康达卷自己的气流容器。我仍然对我的大多数其他容器使用这种方法,包括与我的气流系统交互的微服务,但是配置气流不仅仅是安装包。此外,即使只是安装这些软件包也是一件痛苦的事情,我很少能指望一个没有痛苦的重建工作。然后,在包的顶部,您需要配置数据库连接和消息队列。

在来了 Bitnami 阿帕奇气流 docker 组成栈为开发和 Bitnami 阿帕奇气流舵图为生产!

用他们自己的话说:

Bitnami 使您可以轻松地在任何平台上安装和运行您最喜爱的开源软件,包括您的笔记本电脑、Kubernetes 和所有主要的云。除了流行的社区产品之外,现已成为 VMware 一部分的 Bitnami 还为 IT 组织提供了一种安全、合规、持续维护且可根据组织策略进行定制的企业产品。https://bitnami.com/

Bitnami 堆栈(通常)从 Docker 构建堆栈到舵图的工作方式完全相同。这意味着我可以使用我的 compose 栈进行本地测试和开发,构建新的映像、版本、包等,然后部署到 Kubernetes。配置、环境变量和其他一切都是一样的。从头开始做这一切将是一项相当大的任务,所以我使用 Bitnami。

他们有大量的企业产品,但这里包含的所有东西都是开源的,不涉及付费墙。

不,我不属于 Bitnami,虽然我的孩子吃得很多,对出卖没有任何特别的道德厌恶。;-)我刚刚发现他们的产品非常棒。

项目结构

我喜欢把我的项目组织起来,这样我就可以运行tree并且对正在发生的事情有一个大概的了解。

Apache Airflow 有 3 个主要组件,应用程序、工作程序和调度程序。每个都有自己的 Docker 映像来区分服务。此外,还有一个数据库和一个消息队列,但是我们不会对它们进行任何定制。

.
└── docker
    └── bitnami-apache-airflow-1.10.10
        ├── airflow
        │   └── Dockerfile
        ├── airflow-scheduler
        │   └── Dockerfile
        ├── airflow-worker
        │   └── Dockerfile
        ├── dags
        │   └── tutorial.py
        ├── docker-compose.yml

所以我们这里有一个名为bitnami-apache-airflow-1.10.10的目录。这就引出了非常重要的一点!钉住你的版本!它会让你省去那么多的痛苦和挫折!

那么我们有一个 docker 文件每个气流件。

使用以下内容创建此目录结构:

mkdir -p docker/bitnami-apache-airflow-1.10.10/{airflow,airflow-scheduler,airflow-worker,dags}

Docker 撰写文件

这是我对docker-compose.yml文件的偏好。我根据自己的喜好做了一些更改,主要是我固定版本,构建我自己的 docker 映像,我为dagspluginsdatabase backups安装了卷,并添加了 Docker 插槽,这样我就可以在我的堆栈中运行DockerOperators

你随时可以去抢原文docker-compose 这里

version: '2'

services:
  postgresql:
    image: 'docker.io/bitnami/postgresql:10-debian-10'
    volumes:
      - 'postgresql_data:/bitnami/postgresql'
    environment:
      - POSTGRESQL_DATABASE=bitnami_airflow
      - POSTGRESQL_USERNAME=bn_airflow
      - POSTGRESQL_PASSWORD=bitnami1
      - ALLOW_EMPTY_PASSWORD=yes
  redis:
    image: docker.io/bitnami/redis:5.0-debian-10
    volumes:
      - 'redis_data:/bitnami'
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
  airflow-scheduler:
#    image: docker.io/bitnami/airflow-scheduler:1-debian-10
    build:
      context: airflow-scheduler
    environment:
      - AIRFLOW_DATABASE_NAME=bitnami_airflow
      - AIRFLOW_DATABASE_USERNAME=bn_airflow
      - AIRFLOW_DATABASE_PASSWORD=bitnami1
      - AIRFLOW_EXECUTOR=CeleryExecutor
      # If you'd like to load the example DAGs change this to yes!
      - AIRFLOW_LOAD_EXAMPLES=no
      # only works with 1.10.11
      #- AIRFLOW__WEBSERVER__RELOAD_ON_PLUGIN_CHANGE=true
      #- AIRFLOW__CORE__DAGS_ARE_PAUSED_AT_CREATION=False
    volumes:
      - airflow_scheduler_data:/bitnami
      - ./plugins:/opt/bitnami/airflow/plugins
      - ./dags:/opt/bitnami/airflow/dags
      - ./db_backups:/opt/bitnami/airflow/db_backups
      - /var/run/docker.sock:/var/run/docker.sock
  airflow-worker:
#    image: docker.io/bitnami/airflow-worker:1-debian-10
    build:
      context: airflow-worker
    environment:
      - AIRFLOW_DATABASE_NAME=bitnami_airflow
      - AIRFLOW_DATABASE_USERNAME=bn_airflow
      - AIRFLOW_DATABASE_PASSWORD=bitnami1
      - AIRFLOW_EXECUTOR=CeleryExecutor
      - AIRFLOW_LOAD_EXAMPLES=no
      # only works with 1.10.11
      #- AIRFLOW__WEBSERVER__RELOAD_ON_PLUGIN_CHANGE=true
      #- AIRFLOW__CORE__DAGS_ARE_PAUSED_AT_CREATION=False
    volumes:
      - airflow_worker_data:/bitnami
      - ./plugins:/opt/bitnami/airflow/plugins
      - ./dags:/opt/bitnami/airflow/dags
      - ./db_backups:/opt/bitnami/airflow/db_backups
      - /var/run/docker.sock:/var/run/docker.sock
  airflow:
#    image: docker.io/bitnami/airflow:1-debian-10
    build:
      # You can also specify the build context
      # as cwd and point to a different Dockerfile
      context: .
      dockerfile: airflow/Dockerfile
    environment:
      - AIRFLOW_DATABASE_NAME=bitnami_airflow
      - AIRFLOW_DATABASE_USERNAME=bn_airflow
      - AIRFLOW_DATABASE_PASSWORD=bitnami1
      - AIRFLOW_EXECUTOR=CeleryExecutor
      - AIRFLOW_LOAD_EXAMPLES=no
      # only works with 1.10.11
      #- AIRFLOW__WEBSERVER__RELOAD_ON_PLUGIN_CHANGE=True
      #- AIRFLOW__CORE__DAGS_ARE_PAUSED_AT_CREATION=False
    ports:
      - '8080:8080'
    volumes:
      - airflow_data:/bitnami
      - ./dags:/opt/bitnami/airflow/dags
      - ./plugins:/opt/bitnami/airflow/plugins
      - ./db_backups:/opt/bitnami/airflow/db_backups
      - /var/run/docker.sock:/var/run/docker.sock
volumes:
  airflow_scheduler_data:
    driver: local
  airflow_worker_data:
    driver: local
  airflow_data:
    driver: local
  postgresql_data:
    driver: local
  redis_data:
    driver: local

锁定您的版本

这里用的阿帕奇气流的版本是1.10.101.10.11有一些我想加入的很酷的更新,所以我会继续关注它!

您可以通过查看主站点上的变更日志来随时了解最新的 Apache Airflow 版本。

我们正在使用 Bitnami,它的机器人可以在新版本发布时自动构建和更新它们的映像。

虽然这种方法对机器人来说很棒,但我不推荐仅仅希望最新版本能够向后兼容并与你的设置兼容。

相反,固定一个版本,当新版本出现时,在您的开发堆栈中测试它。在写这篇文章的时候,最新的版本是1.10.11,但是它不能开箱即用,所以我们使用1.10.10

比特纳米阿帕奇气流码头标签

一般来说,一个 docker 标签对应一个应用版本。有时也有其他变体,如基本操作系统。在这里,我们可以只使用应用程序版本。

Bitnami Apache air flow Scheduler 图像标签

Bitnami Apache 气流工人图片标签

Bitnami Apache Airflow 网页图片标签

构建自定义图像

在我们的docker-compose中,我们有占位符来构建自定义图像。

我们现在只创建一个最小的 Docker 文件。稍后我将展示如何用额外的系统或 python 包定制 docker 容器。

气流应用

echo "FROM docker.io/bitnami/airflow:1.10.10" > docker/bitnami-apache-airflow-1.10.10/airflow/Dockerfile

会给你这个气流申请 docker 文件。

FROM docker.io/bitnami/airflow:1.10.10

气流调度程序

echo "FROM docker.io/bitnami/airflow-scheduler:1.10.10" > docker/bitnami-apache-airflow-1.10.10/airflow-scheduler/Dockerfile

会给你这个气流调度 docker 文件。

FROM docker.io/bitnami/airflow-scheduler:1.10.10

气流工人

echo "FROM docker.io/bitnami/airflow-worker:1.10.10" > docker/bitnami-apache-airflow-1.10.10/airflow-worker/Dockerfile

会给你这个气流工 docker 文件。

FROM docker.io/bitnami/airflow-worker:1.10.10

调出堆栈

抓住上面的docker-compose文件,让我们开始吧!

cd docker/bitnami-apache-airflow-1.10.10 
docker-compose up

如果这是您第一次运行该命令,这将需要一些时间。Docker 将获取它还没有的任何图像,并构建所有的 airflow-*图像。

导航到用户界面

一旦一切就绪并开始运行,导航到位于[http://localhost:8080](http://localhost:8080.) 的 UI。

除非您更改了配置,否则您的默认username/passworduser/bitnami

登录查看您的气流网络用户界面!

添加自定义 DAG

这里有一个我从阿帕奇气流教程中抓取的 DAG。为了完整起见,我把它包括在这里。

from datetime import timedelta

# The DAG object; we'll need this to instantiate a DAG
from airflow import DAG
# Operators; we need this to operate!
from airflow.operators.bash_operator import BashOperator
from airflow.utils.dates import days_ago
# These args will get passed on to each operator
# You can override them on a per-task basis during operator initialization
default_args = {
    'owner': 'airflow',
    'depends_on_past': False,
    'start_date': days_ago(2),
    'email': ['airflow@example.com'],
    'email_on_failure': False,
    'email_on_retry': False,
    'retries': 1,
    'retry_delay': timedelta(minutes=5),
    # 'queue': 'bash_queue',
    # 'pool': 'backfill',
    # 'priority_weight': 10,
    # 'end_date': datetime(2016, 1, 1),
    # 'wait_for_downstream': False,
    # 'dag': dag,
    # 'sla': timedelta(hours=2),
    # 'execution_timeout': timedelta(seconds=300),
    # 'on_failure_callback': some_function,
    # 'on_success_callback': some_other_function,
    # 'on_retry_callback': another_function,
    # 'sla_miss_callback': yet_another_function,
    # 'trigger_rule': 'all_success'
}
dag = DAG(
    'tutorial',
    default_args=default_args,
    description='A simple tutorial DAG',
    schedule_interval=timedelta(days=1),
)

# t1, t2 and t3 are examples of tasks created by instantiating operators
t1 = BashOperator(
    task_id='print_date',
    bash_command='date',
    dag=dag,
)

t2 = BashOperator(
    task_id='sleep',
    depends_on_past=False,
    bash_command='sleep 5',
    retries=3,
    dag=dag,
)
dag.doc_md = __doc__

t1.doc_md = """\
#### Task Documentation
You can document your task using the attributes `doc_md` (markdown),
`doc` (plain text), `doc_rst`, `doc_json`, `doc_yaml` which gets
rendered in the UI's Task Instance Details page.
![img](http://montcs.bloomu.edu/~bobmon/Semesters/2012-01/491/import%20soul.png)
"""
templated_command = """
{% for i in range(5) %}
    echo "{{ ds }}"
    echo "{{ macros.ds_add(ds, 7)}}"
    echo "{{ params.my_param }}"
{% endfor %}
"""

t3 = BashOperator(
    task_id='templated',
    depends_on_past=False,
    bash_command=templated_command,
    params={'my_param': 'Parameter I passed in'},
    dag=dag,
)

t1 >> [t2, t3]

不管怎样,把这个文件放到你的code/bitnami-apache-airflow-1.10.10/dags文件夹里。文件名本身并不重要。DAG 名称将是您在文件中设置的名称。

气流会自动重启,如果你刷新用户界面,你会看到新的tutorial DAG 列表。

建立自定义气流码头集装箱

如果你想添加额外的系统或 python 包,你可以这样做。

# code/bitnami-apache-airflow-1.10.10/airflow/Dockerfile
FROM docker.io/bitnami/airflow:1.10.10
# From here - https://github.com/bitnami/bitnami-docker-airflow/blob/master/1/debian-10/Dockerfile

USER root

RUN apt-get update && apt-get upgrade -y && \
    apt-get install -y vim && \
    rm -r /var/lib/apt/lists /var/cache/apt/archives

RUN bash -c "source /opt/bitnami/airflow/venv/bin/activate && \
    pip install flask-restful && \
    deactivate"

明确地说,我不再特别赞同这种方法,除了我喜欢添加flask-restful来创建定制的 REST API 插件。

我喜欢像对待 web 应用程序一样对待 Apache Airflow。我已经被烧了太多次,所以现在我的 web 应用程序只负责路由和渲染视图,其他的什么都不管。

除了它处理我的工作流的业务逻辑之外,气流几乎是一样的。如果我有一些疯狂的熊猫/tensor flow/opencv/任何我需要做的东西,我会将它们构建到一个单独的微服务中,而不会触及我的主要业务逻辑。我喜欢把气流想象成盘踞在网中的蜘蛛。

不过,我有足够的偏执,我喜欢建立自己的图像,这样我就可以把它们推到我自己的 docker repo。

总结和从这里去哪里

现在您已经有了基础,是时候构建您的数据科学工作流了!添加一些自定义 Dag,创建一些自定义插件,一般构建东西

如果你想要一个教程,请随时联系我,在 jillian@dabbleofdevops.com 或者在推特上。

小抄

这里是一些有希望帮助的命令和资源。

登录到 Apache Airflow 实例

默认的用户名和密码是userbitnami

Docker 编写命令

建设

cd code/bitnami-apache-airflow-1.10.10/ 
docker-compose build

拿出你的筹码!运行docker-compose up会让您的所有日志出现在 STDERR/STDOUT 上。

cd code/bitnami-apache-airflow-1.10.10/ 
docker-compose build && docker-compose up

如果您想在后台运行,请使用-d

cd code/bitnami-apache-airflow-1.10.10/ 
docker-compose build && docker-compose up -d

比特纳米阿帕奇气流配置

您可以使用传递到 docker-compose 文件中的环境变量来进一步定制气流实例。查看自述文件了解详情。

加载 DAG 文件

定制的 DAG 文件可以挂载到/opt/bitnami/airflow/dags或者在 Docker 构建阶段复制。

使用 Docker Compose 指定环境变量

version: '2'

services:
  airflow:
    image: bitnami/airflow:latest
    environment:
      - AIRFLOW_FERNET_KEY=46BKJoQYlPPOexq0OhDZnIlNepKFf87WFwLbfzqDDho=
      - AIRFLOW_EXECUTOR=CeleryExecutor
      - AIRFLOW_DATABASE_NAME=bitnami_airflow
      - AIRFLOW_DATABASE_USERNAME=bn_airflow
      - AIRFLOW_DATABASE_PASSWORD=bitnami1
      - AIRFLOW_PASSWORD=bitnami123
      - AIRFLOW_USERNAME=user
      - AIRFLOW_EMAIL=user@example.com

码头后清理

Docker 会在你的文件系统上占据很多空间。

如果您只想清理气流通道,那么:

cd code/docker/bitnami-apache-airflow-1.10.10 
docker-compose stop 
docker-compose rm -f -v

运行docker-compose rm -f会强制删除所有容器,-v也会删除所有数据卷。

移除所有 docker 图像

这将停止所有正在运行的容器并删除它们。

docker container stop $(docker container ls -aq) 
docker system prune -f -a

这将删除所有容器和数据卷

docker system prune -f -a --volumes

最初发表于【https://www.dabbleofdevops.com】

冷静点。线性回归中何时添加协变量

原文:https://towardsdatascience.com/get-a-grip-when-to-add-covariates-in-a-linear-regression-f6a5a47930e5?source=collection_archive---------3-----------------------

精确测量效果指南!

丹·万鲁宁

图片通过 Pixabay

线性回归模型使得在其他变量(协变量)不变的情况下测量治疗效果变得容易。但是什么时候以及为什么要包含协变量呢?

这篇文章将回答这个问题。

首先,我们将在预测的上下文中讨论协变量:当它们改进超出样本拟合时添加它们。

然后,我们将讨论何时应该使用协变量来衡量因果效应,何时不应该:

获得正确的测量结果

  • 添加可能导致估计偏差的混杂因素
  • 不要添加下游结果
  • 不要添加碰撞器

得到精确的估计

  • 添加可预测结果的质控品,而非治疗品,以提高精确度
  • 不要添加预测治疗但不预测结果的质控品

帖子摘要

预测:使用样本外性能

如果您不影响回归中任何变量的值,您可能只关心预测。例如,如果你想卖一套公寓,你可能想预测销售价格。你可以对其他公寓的销售价格进行回归训练,包括卧室数量等协变量。在这种情况下,您可能只关心如何准确预测销售价格。你可能不想评估如果你增加一间卧室,你能多卖多少钱(相比之下,这是一个因果问题)。

要决定是否应将协变量添加到预测上下文中的回归中,只需将数据分为训练集和测试集。使用协变量而不使用训练数据来训练模型。无论哪个模型在测试数据中预测得更好,都应该使用。

添加协变量会减少预测中的偏差,但会增加方差。样本外拟合是这种权衡的评判标准。如果你有很多变量,像 L1 正则化这样的技术可以帮助你决定包括哪些变量。你也可以考虑更复杂的黑盒模型,因为你不关心可解释性。

当你试图测量因果关系时,事情变得更加复杂。

因果效应

回归是可以解释的。通过回归系数,很容易确定回归中变量的变化如何与结果的变化相关联。例如,如果你拥有很多狗狗美容沙龙,你可能会考虑是否要在狗狗离开时给它们头巾,让它们看起来很可爱。

泰迪熊

您想知道赠送头巾是否会增加收入,因此您进行了回归分析:

其中 gives_bandanas 是一个 0,1 的指示变量,表示沙龙是否提供头巾。\beta_1 将准确地告诉您赠送头巾对收入的影响。

向回归中添加或不添加控件的原因通常分为两类:

  1. 获得正确的测量结果(如减少偏差)
  2. 效果测量的精度

获得正确的测量

在 3 种主要情况下,向您的回归中添加协变量会影响或破坏您的最终治疗效果估计。

  1. 混杂因素(包括它们)
  2. 下游结果(不包括它们)
  3. 碰撞器(不包括它们)

添加可能使评估产生偏差的混杂因素
如果不考虑混杂因素,它们可能会使您的治疗效果评估不正确。混杂因素是指影响治疗价值和结果的因素。

例如,让我们说,在高档社区的顾客更倾向于要求头巾。高档社区也往往会有人在狗狗美容上花更多的钱。因此,花哨会影响治疗(不管美容院是否提供头巾)和结果(收入),而且是一个混杂因素。

让我们举例说明:

现在让我们看看如果我们不控制幻想会发生什么。

混杂、有偏模型(gives_bandanas 系数包括花哨效应)

gives _ bandanas 的真正效果是收入增加 10000 美元,但我们测量的效果要大得多。事实上,真实的效果甚至不在我们模型的 95%置信区间内。

但是如果我们在回归中加入幻想会怎么样呢?

控制混杂因素模型是无偏的

现在我们有了一个精确的效果测量!

检查这些混杂因素的一个好方法是在有和没有混杂因素的情况下进行回归。如果感兴趣的系数(如 gives _ bandanas)变化很大,这是存在偏见的迹象。

扩展:查看我的 stats stackexhange 帖子,看看无偏系数需要什么数学假设。关键假设是严格的外生性(类似于感兴趣的变量(如 gives _ bandanas)和回归中不受控制但也会影响结果的其他变量之间没有相关性)。

虽然控制混杂因素是有帮助的,但是控制下游结果或碰撞会扭曲我们估计的治疗效果。

不添加下游结果

如果我们加入由我们的治疗引起并影响结果的变量,我们将通过增加的变量去除我们的治疗对结果的影响。例如,让我们想象这样一种情况,给狗送头巾会使顾客更有可能回到美容院,而收入会受到有多少顾客回来的影响。

让我们看看当我们将回报率作为协变量时,赠送头巾的效果是如何丧失的。

让我们看看回归是如何运行的:

当不包括下游效应时,我们想要什么

当我们不包括下游变量时,我们得到一个非常接近真实的+100 效应的估计效应。

但是如果我们包括进去呢:

下游效应吸收并消除处理的影响

将 return_rate 添加到回归中消除了使用头巾的影响。这是因为保持 return_rate 不变,赠送头巾实际上没有影响。但是我们仍然对使用头巾的效果感兴趣(即使通过其他变量),所以我们不应该控制下游的影响。

我们不仅需要担心添加下游效果,还需要担心添加碰撞器。

不要加对撞机

对撞机是一个受治疗和结果影响的变量。在回归中加入对撞机会扭曲治疗和结果之间的关联。例如,一个沙龙是否作为储藏室。如果你的沙龙赠送手帕,你可能需要一个壁橱来存放它们,因此赠送手帕会影响是否有储藏室。此外,收入高的沙龙可能会看到更多的顾客留下东西,因此这些沙龙需要一个地方来存放失物。让我们考虑一个例子,其中头巾对收入没有任何影响,但如果我们意外地控制了这个碰撞器,就可以找到关联。

回归在没有碰撞器的情况下运行良好。

没有对撞机,没有问题

我们没有测量任何给头巾的效果,碰撞器不包括在内。这是一件好事,因为在这种情况下,头巾没有收入的影响。但是当我们加入对撞机时会发生什么呢?

对撞机让头巾看起来有效果,其实没有!

现在我们测量了赠送头巾和实际上并不存在的收入之间的显著负相关。这是因为回归的“固定不变”解释。对于给定的存储价值,收入与赠送手帕成负相关。

知道是否添加协变量来精确测量效果是最重要的,但知道协变量何时可以提高估计的精确度也很重要。

协变量对系数估计精度的影响

如果协变量可以预测结果,并且与您试图估计其系数的变量不高度相关,则协变量可以提高您估计特定系数的精确度。

这个结果可能看起来与直觉相反:增加协变量不是应该增加方差从而降低精度吗?对结果的预测是这样,但对回归系数的估计却不是这样。

如果我们满足普通最小二乘法的一些标准假设(我们的结果和协变量之间的关系是线性的,单位之间不相互影响,治疗和影响结果的其他协变量之间没有相关性,homoskedastity—请参见我的 stats stackexchange 帖子了解所有假设和含义)治疗系数的 OLS 估计方差为:

分母中的和指的是在我们的治疗应用中有多少差异(给予头巾)。这与我们添加的协变量无关。

\sigma 是回归的误差方差。我们对回归结果的预测越好,这个值就越低。因此,如果我们添加对结果有高度预测性的协变量,sigma 将会降低,我们将会有更高的精确度。

但是,如果我们以 gives _ bandana 作为结果,以所有其他协变量作为解释变量来运行回归,R _ { gives _ bandanas }代表 R。这意味着,如果我们添加与治疗高度相关的协变量,我们对治疗系数的估计将具有更高的方差。这说明了一个事实,你不应该增加与治疗高度相关的变量,除非它们是与结果高度相关的混杂因素。

我们来举例说明。假设赠送头巾与美容院所在位置的狗的数量无关,但美容院的收入相关(将狗的数量加入回归将提高精确度)。还有,假设沙龙是否从当地的大手帕供应商那里获得广告影响了沙龙是否赠送大手帕,但不直接影响沙龙的收入(加上沙龙是否收到广告会降低精准)。

让我们从仅使用治疗的回归开始。

公正处理的无偏测量

我们测量了一个相当接近 5 的真实影响的精确效果。

现在让我们添加预测协变量。

当我们增加一个好的预测器时,测量更精确

现在我们可以更精确地测量效果了!gives _ bandanas 上的系数更接近 5,标准误差更低。

但是如果我们增加了一个与治疗相关的非预测因素呢?

当我们增加一个与治疗相关的非预测因子时,精确度会降低

现在我们的精度更低了,离 5 的真实效果更远了。

摘要

总结一下,请参考下面的图表。如果你想了解更多关于通过实验测量效果的知识,请查看我的其他帖子:

帖子摘要

以最简单的方式在谷歌云平台上获得深度学习

原文:https://towardsdatascience.com/get-deep-learning-on-google-cloud-platform-the-easy-way-53f74bab5ee9?source=collection_archive---------28-----------------------

两分钟内在 GCP 上创建一个深度学习虚拟机

照片由 lalo HernandezUnsplash 上拍摄

亲爱的读者:

我问你这些问题:

  • 你想快速开始在云端训练你的深度神经网络吗?
  • 想学点云计算但是不知道从哪里开始?
  • 买不起 GPU 却租得起?

如果你回答“是的!”我的朋友们,请继续读下去。会让你的生活轻松一点!

(注意:我喜欢详细地设置我的虚拟机。有趣的是,我发现这里描述的步骤完全不令人满意!)

食谱

我假设你登录了你的 GCP 账户。

在您的菜单中,转到AI Platform -> Notebooks:

这会带你去Notebook Instances:

点击NEW INSTANCE并选择您想要使用的图像。作为一名谷歌粉丝,我选择最新的TensorFlow图片。

其中一些图像是为深度学习而构建的。如果你想用 GPU 训练你的网络,选择With 1 NVIDIA Telsa K80

好的好的好的。我能听到你。我也问过自己同样的问题:

“如果我想使用运行在具有 96 个 vCPUs 的虚拟机上的 8 个 NVIDIA Tesla V100s,我该怎么做?”

如果你愿意支付这些费用,你可以点击CUSTOMIZE获得。如果你接受默认值,不要担心。此过程将创建一个成熟的计算引擎虚拟机,您可以在以后轻松地对其进行修改。

在我们继续之前,勾选Install NVIDIA GPU driver automatically for me。这照顾我们的 GPU 设置!

现在按下那个CREATE按钮。

稍等一会儿…

看到绿色勾号后,点击OPEN JUPYTERLAB

瞧啊。现在,您可以使用云中的 GPU“深入学习”了!这就是全部,我的朋友们。

如果我想进一步定制我的虚拟机,该怎么办?

这个也很容易做到!

点击主菜单中的Compute Engine。你会在那里看到你漂亮的虚拟机。

停止虚拟机以开始编辑它。像这样做你所有平常的奇妙变化:

  • 添加防火墙规则,以便您可以在另一个端口上运行 TensorBoard
  • 添加额外磁盘
  • 增加虚拟 CPU 的数量,但随后却减少了数量,因为您已经被触手可及的处理能力搞疯了
  • 对你的公羊做同样的事
  • 用你的 GPU 做同样的事情

就是这样!各位,不使用虚拟机时,一定要记得关闭它们。

直到下一次,

贾斯廷

原载于 2020 年 4 月 4 日【https://embracingtherandom.com】

熟悉数据科学最强大的武器~变量(Stat-02)

原文:https://towardsdatascience.com/get-familiar-with-the-most-important-weapon-of-data-science-variables-48cc7cd85dc5?source=collection_archive---------29-----------------------

图片由皮克斯拜的 Gerd Altmann 提供

变量类型的基本概念、测量级别和不同的 python 表示技术

"你可以拥有没有信息的数据,但你不能拥有没有数据的信息."—丹尼尔·凯斯·莫兰

数据是信息时代的原材料。没有数据,我们就无法想象现代技术。如果我们有数据,我们就能获得大量关于任何事件或空间的信息。当今世界对数据有着强烈的渴望。就现代技术而言,它可以与石油相提并论。

但是如果你不知道数据,这没有任何意义。首先,我们必须熟悉我们正在探索的数据。如果我们不了解数据,我们建立在数据之上的系统或分析模型将会以无用的分析或系统而告终。因此,我们需要熟悉数据类型及其表示技术。

该参数保存的数据在统计学中称为变量。一个数据集可能描述股票市场,其他数据集可能描述人口、雇员数据等等。因系统而异。具有变化值的属性是变量

这篇文章将在这方面帮助你。这里将显示所有变量类型和变量的可能图形表示。如果你感兴趣,这将是最适合你的文章。让我们开始吧。

内容

  1. 变量的类型
  2. 测量级别
  3. 使用 python 的数据表示(条形图、饼图、排列图

1.变量的类型

数据来源庞大。我们可能会从不同的数据源中找到不同类型的数据。但是了解数据的特征是很重要的。变量定义了数据的特征。有一些参数,我们可以很容易地划分或分类的变量。基本上有两种类型的变量。

变量类型(作者照片)

主要有两种变量类型:I)分类变量和 ii)数值变量

分类:分类变量代表可以分组的数据类型。它也被称为定性变量。

示例 : 汽车品牌是一个分类变量,包含奥迪、丰田、宝马等分类数据。答案是保存分类数据是/否的分类变量

二。数值:所有用数字表示的变量称为数值变量。它也被称为定量变量。它可以是 a)离散的,或 b)连续的。

a)离散:简单来说,所有包含可数数据的变量称为离散变量。

示例 : 变量-子女数量、SAT 分数、人口等。,所有这些变量都包含离散数据。

b)连续:不可数的变量称为连续变量。它需要永远计数,计数过程将永远不会结束。

例子:年龄是一个连续变量。但是为什么呢?假设,你的年龄是 25 年 2 个月 10 天 7 小时 40 秒 44 毫秒 10 纳秒 99 皮秒……等等。它永远不会结束。另一个例子可能是"平均值"变量。取平均数 1.232343542543245……永无止境。

变量的快速比较。

定量对比定性(作者照片)

2.测量级别

根据维基百科,“衡量标准衡量尺度是一种分类,描述了分配给变量 s 的值内的信息的性质。”

心理学家斯坦利·史密斯·史蒂文斯提出了最著名的四个测量等级的分类。音程 iv。比率

标称序数标尺用于测量定性/分类变量。另一方面,区间比值刻度用于测量定量/数值变量。

测量水平(作者照片)

一、名义上的:它是一个拉丁语单词,意思是只有名字。名义层代表不能按任何顺序排列的类别。该级别仅代表单个类别或名称。

  • 它只代表质量。
  • 有了名义尺度,我们可以确定变量中两个个体之间的差异。
  • 它没有提供任何关于差异大小的概念。

:假设,一个变量代表汽车品牌→奥迪、丰田、宝马等。我们不能以任何方式排列这些名字。因此,这类变量属于名义计量水平。

二世。序数:是有序的级别或等级。它表示可以排序的分类变量。有了这个尺度,我们可以确定一个变量的差异方向,但不能确定差异的大小。

举例:我们有一个名为 Height 的变量,代表矮、中、高三种人的身高。我们可以很容易地将这些值排序为高→中→矮。这个顺序提供了一个很好的关于差异方向的直觉,但是它没有提供任何线索来识别彼此之间的高度差异。

序数尺度直觉(照片通过统计如何进行)

三世。区间:一个代表水平之间相等的区间,可以用实数表示的变量称为区间标度。它不仅对测量值进行分类和排序,而且还指定标尺上每个区间之间的距离在从低区间到高区间的标尺上是相等的。

:温度是一个变量,其中 10 摄氏度与 20 摄氏度、70 摄氏度、80 摄氏度之间的间隔相同。考试成绩、身高、时间等。可以作为区间尺度的一个很好的例子。

四。比率:它具有区间标度一样的所有性质。此外,它必须满足标度中有意义的零。先说清楚。

假设,我们在考虑 C 和 F 标度的体温。我们发现两个人的体温分别是 10 摄氏度和 20 摄氏度,或者 10 华氏度和 20 华氏度。我们不能说第二个人的体温比第一个人高两倍。因为 0°C 和 0°F 不是真正的零度,这意味着不存在温度。如果你想用一个比例标度来表示温度,那么我们必须考虑开尔文标度,因为 0 开尔文表示没有温度。

3。用 Python 进行数据表示

在这里,我们将讨论柱状图、饼状图和排列图来表示变量。

分类变量表示:

假设,我们有一个汽车销售市场的数据集,我们将分析汽车品牌变量。首先,我们计算不同汽车品牌的频率。好像是下面这样的东西。

演示汽车品牌频率

让我们把它转换成数据帧。因为我们要用这个演示数据来分析图形表示。频率代表每个品牌售出汽车的数量。您可以对任何数据集进行同样的操作。让我们用熊猫数据帧来转换图像。

import pandas as pd
import matplotlib.pyplot as plt
df=pd.DataFrame({"Brand":['Audi',"BMW","Mercedes"],"Frequency":[124,98,113]})

熊猫数据框

计算相对频率

相对频率表示个体频率分布的百分比。

相对频率(%)=(个别频率/总频率)100*

df['Relative Frequency(%)']=
round((df.Frequency/sum(df.Frequency))*100,2)

我们在主数据集中添加了一个相对频率列。

具有相对频率栏的数据框

让我们用频率画一个条形图。

条形图:

import matplotlib.pyplot as pltfig,ax=plt.subplots()
var=plt.bar(df.Brand, df.Frequency, align='center', alpha=0.5)#this loop is used to represent frequency on each bar
for idx,rect in enumerate(var):
        height = rect.get_height()
        ax.text(rect.get_x() + rect.get_width()/2., 1.01*height,
                df.Frequency[idx],
                ha='center', va='bottom', rotation=0)#adding labels and title
plt.ylabel('Frequency')
plt.xlabel('Brand Name')
plt.title('Car Sales Statistics')plt.show()

这是一个频率条形图。

条形图代表频率

我们还可以用饼图来表示不同分类数据之间的频率分布。

饼图:

fig = plt.figure()
ax = fig.add_axes([0,0,1,1])
ax.axis('equal')ax.pie(df.Frequency, labels = df.Brand,autopct='%1.2f%%')
plt.show()

相对频率饼图。

相对频率饼图

帕累托图

帕累托图是一种特殊类型的条形图,其中类别按频率降序显示,单独的曲线显示累计频率。

具有累积频率的数据帧。

我们用 python 来画图吧。

from matplotlib.ticker import PercentFormatterdf = df.sort_values(by='Frequency',ascending=False)
df["Cumulative Frequency"] = round(df["Frequency"].cumsum()/df["Frequency"].sum()*100,2)
fig, ax = plt.subplots(figsize=(10,5))
ax.bar(df.Brand, df["Frequency"], color="blue")
ax2 = ax.twinx()
ax2.plot(df.Brand, df["Cumulative Frequency"], color="red", marker="D", ms=7)
ax2.yaxis.set_major_formatter(PercentFormatter())ax.tick_params(axis="y", colors="black")
ax2.tick_params(axis="y", colors="black")
ax2.set_ylim(0,105)
ax.set_ylim(0,130)
plt.show()

频率表的排列图。

图表的左侧代表频率,右侧代表累积频率

到目前为止一切顺利。我们在文章的最后。

数字变量表示:

我们还可以用条形图、饼图和排列图来表示数字数据。如果我们想找到数字数据的频率,我们可能会发现每个数据的频率为 1。但是表示数据是不可行的。那么,我能做什么呢?

我们可以把数值数据分成不同的区间,然后统计区间内数据出现的频率。让我们试着对 python 数据框架有更好的直觉。

df=pd.DataFrame({"data":[10,40,20,5,30,100,110,70,80,63,55,32,45,85,87,77,65,44,33,4,56,90,95,96]})

数据帧的前 5 个数据。

如果要统计频率,大部分数据的频率会是 1。

df['data'].value_counts()

这给出了频率..

数字数据的频率。

现在,如果我们想用条形图、饼图来表示上述频率,它不提供任何信息。所以,我们需要计算间隔内的频率。假设,我们将数据分成 5 个相等的区间。

d=df['data'].value_counts(bins = 5).sort_index()

它显示了下面的频率分布。

左栏表示间隔,右栏表示频率。

我们可以用柱状图,饼状图和排列图来表示数字变量的频率。试着按照上面的技巧画出数字变量的图表。这是你的任务。

照片由杰克逊在 Unsplash 上煨

结论

分母变量对于数据科学任务非常重要。在我们分析的最开始,我们必须看一看它。我们经常忘记把它考虑进去。希望这几分钟的阅读能让你对变量,变量的类型等等有一个很好的直觉。你将在 Github 中获得完整的 jupyter 笔记本文件。

如果你有任何问题,请在评论区告诉我。

数据科学统计系列文章

  1. 少即是多;采样的‘艺术’(Stat-01)
  2. 熟悉数据科学最重要的武器~变量(Stat-02)
  3. 要提高数据分析能力,您必须了解频率分布(Stat-03)
  4. 通过可视化频率分布找到数据集的模式(Stat-04)
  5. 比较多个频率分布,从数据集中提取有价值的信息(Stat-05)
  6. 通过简短的讨论消除你对 Mean 的误解(Stat-06)
  7. 通过规范化提高您的数据科学模型效率(Stat-07)
  8. 【数据科学基础概率概念(Stat-08)
  9. 从朴素贝叶斯定理到朴素贝叶斯分类器路线图(Stat-09)
  10. 数据科学爱好者关于假设检验需要知道的一切(Stat-10)
  11. 用 ANOVA 进行多组间的统计比较(Stat-11)
  12. 用卡方检验比较分类变量的相关性(Stat-12)

通过参加兼职项目,在你的 DS 工作中获得额外的学分

原文:https://towardsdatascience.com/get-noticed-and-get-credit-at-your-ds-job-with-this-simple-trick-ef3f3c51862f?source=collection_archive---------37-----------------------

是时候探索你舒适区之外的一些未被触及的数据库了。

保罗·吉尔摩在 Unsplash 上的照片

你已经开始工作一段时间了,事情看起来很好,你的日子可能充满了完善一些核心模型。但是过了一段时间,你可能会对更新你的任务清单感兴趣:你刚刚完成了一件大事,正在寻找一个小任务来打破常规吗?遭遇“文思枯竭”,不确定下一步该怎么做?或者,也许你只是想让别人注意到你打算要求的加薪?有很多方法可以处理这些情况,但是偶尔,如果你想在你的时间表中增加一些新的东西,我建议你做一个工作方面的项目!

什么是“兼职项目”?

即使你的公司确实有一个数据科学团队,也有理由猜测仍然有很多地方和大量数据没有发挥出它们的全部潜力。我说的是数据科学团队以外的任务,这些任务可能会帮助其他员工或公司:你是否熟悉一些还没有人接触过的数据,并且你可以帮助从中提取一些见解或预测?也许销售部门想要一个季节性的模型?或者下一个可能流失的客户是谁?也许反欺诈部门可以得到帮助,自动抓捕坏人?如果你很难想出例子,就问问你的老板或同事,看他们是否能想出什么。如果失败,去找最近的分析师团队。

分析师?

分析师是伟大的人。他们天生好奇,超级透彻,通常拥有无价的领域知识,这些知识是他们经过数月甚至数年完善的。他们可能很擅长 SQL、数据库和仪表板。最好的甚至用一些 python 脚本,使用 pandas 或 sklearn。但是,即使他们是顶尖的,他们通常也达不到大多数数据科学家能做的事情:使用机器学习,这就是的用武之地!

如果到目前为止,您仍然想不出您可以帮助谁以及如何帮助,请直接与分析师团队交谈:询问他们的任务,他们做什么会占用他们的大部分时间,他们在进行分析时会关注什么特性。如果他们已经使用了某种结构化数据,那么明智地将它与其他数据混合在一起可能会奏效?礼貌地请求,只有少数人会拒绝帮助。如果你能为一项可能的任务找到线索——现在是赚钱的时候了。试着拿着一个你可以摆弄的虚拟 CSV 走开。它不需要很长或很复杂,甚至不需要所有可能的栏目,只要能让你开始就行了。

不要做什么?

不要(不要!)光顾,看不起或认为你可以通过简单的自动化和一个花哨的 jupyter 笔记本来消除某人的工作。无论你写的是什么代码,都可能被你采访的人使用。他们将是运行它的人,是判断你所做的是否有任何好处的人。他们的合作对这个项目的成功至关重要。试着看看他们的痛点是什么。描述一下你们合作项目的可能成果,看看这是否能让他们兴奋起来。

好的,我有一个 CSV 文件。现在怎么办?

确保你不要选择那些需要大费周章和清理的数据。记住,你实际上已经有了一份全职工作,我们只是伸手去摘一些容易摘到的果子。获取数据,了解你试图解决的问题类型(回归?分类?),那么就运行一个简单的模型。看看你是否真的能预测到什么。看看特征重要性,看看是否有有用的东西跳出来。

我的案例研究

我被安排帮助公司的反欺诈团队对欺诈进行建模。到目前为止,分析师一直在对一些数据库进行 SQL 查询。他们之前了解了 2-3 个运行良好的特性,并通过 SQL 查询查看了那些特性中得分最高的项目。这些项目被标记为可疑,分析师将手动检查它们,以检查它们的其他质量是否也同样可疑。尽管这很有效,但它花了很长时间,对我来说,很明显我们可以一起做得更好:当我们有几十个其他功能时,为什么只看 2-3 个功能呢?

我得到了一个包含 1600 行历史欺诈和非欺诈交易的样本 CSV,有 8 个特征。我用 python 的 Catboost tree boosting 包来建模这个分类问题。该模型现在由分析师运行,他们定期添加他们认为可以改进该模型的更多特性。据估计,这使得消除欺诈的过程至少加快了 5 倍。

使用 Catboost

我强烈推荐这些任务的 Catboost 梯度推进包。它是如此强大和简单易用,以至于可能只需要 1-2 个小时就可以建立起第一个工作模型,即使你以前从未听说过这个软件包。即使在电脑上运行也很快;非常好地处理表格数据并使用分类特征而不需要预处理(no 1-热编码!只是标记哪一列是分类的)。即使没有超参数调整,它也能很好地工作。当然,你喜欢和熟悉的其他东西也很好,只要你记住,有一天,不是你的人可能会想经营它,所以保持简单。

很快

基本就是这样。最糟糕的情况是这个实验浪费了 3-4 个小时却没有任何效果。最好的情况是,你交了一个新朋友,也许学到了一些新东西,做了一些会在很长一段时间内有用(我敢说甚至非常有用)的事情。试试看!

资源:

  1. 关于 Catboost 的所有相关信息:https://catboost.ai/

获得真实世界的数据分析师经验

原文:https://towardsdatascience.com/get-real-world-data-analyst-experience-e7b0504f58d4?source=collection_archive---------34-----------------------

更多的实践机会可以让未来的分析师练习他们的技能,并真正理解手头的任务。

简介

对于有抱负的数据科学家和分析师来说,参加工作面试可能会令人紧张。对工作内容知之甚少或一无所知,使得在与经理或潜在团队成员的面试中很难进行有意义的对话。消除这种焦虑的方法之一是获得真实世界的经验,然而这是先有鸡还是先有蛋的问题的开始。在你获得经验之前,你需要被雇佣,但是在你被雇佣之前,你需要经验(看起来很熟悉?).

为了在讨论数据分析主题时有信心,你需要具备的一件事仍然是实际获得现实世界的经验,但是要获得这种经验,你需要通过面试。

这就是实习大有帮助的地方。我目前是一名分析师,但获得额外的实践经验不会有坏处,我听说了的虚拟实习,以及他们如何帮助有抱负的分析师获得丰富的实际经验,并在谈论数据科学和分析主题时更加自信。

实习流程

在虚拟实习期间,你将在分析主管的领导下与客户一起工作。首先,你将评估数据的质量。接下来,您将着手计划并详细说明从数据中获得洞察力所需采取的步骤。这涉及诸如数据探索、模型开发和解释之类的事情。在客户项目的最后阶段,您还可以创建一个将呈现给客户的自助式高管级仪表板。

我们将详细讨论这些步骤,我将在接下来的段落中分享我的工作成果。

实习很巧妙的一点就是可以看到资深咨询师的样板作品。他们可以用来衡量你的工作如何比较,并给你一个机会来更新你自己的。

任务 1 —数据质量评估

您将获得客户用例及其数据。您必须对数据进行评估,这项任务包括确定需要关注的领域,并给出缓解这些问题的建议。

[## 毕马威 2.pdf 数据质量评估

在线存储照片和文档。从任何 PC、Mac 或手机访问它们。在 Word、Excel 或……上创建和协同工作

1drv.ms](https://1drv.ms/b/s!AqcNgsjUVF_BidtoywVth6QZwb9Ifg?e=73ashc)

任务 2 —分析方法(两周计划)

对于第二个任务,你应该给出一个详细的两周计划来概述你的方法。您应该包括数据探索、模型开发和解释的步骤。一个好的介绍将证明对客户是有用的。

[## 模块 2 _ 演示文稿 _v2.pdf

在线存储照片和文档。从任何 PC、Mac 或手机访问它们。在 Word、Excel 或……上创建和协同工作

1drv.ms](https://1drv.ms/b/s!AqcNgsjUVF_BidtnjJIJug6MmoNmRA?e=Usb6ww)

任务 3 —仪表板

最后,您需要创建一个交互式自助服务控制面板,客户可以用它来回答以下问题:

  • 如何利用现有客户和普查数据锁定新的高价值客户?
  • 我们当前的哪个客户对我们的利润贡献最大?
  • 关于我们的高价值客户,调查显示了什么?

哪个客户对我们的利润贡献最大?【Tableau 链接此处】

关于我们的高价值客户,调查显示了什么?【Tableau 链接此处】

如何利用数据锁定我们的客户?【Tableau 链接此处】

总结

除了自学和参加 Kaggle 比赛,从实习中获得工作经验有助于保证你成为一名数据分析师。你将从中获得的一些技能是利用你的分析技能解决业务问题,确保数据质量,制作可解释的和准确的模型,并将这些见解传达给执行领导。这些都是任何有抱负的数据分析师或科学家的关键技能。

在分析工具方面,你也将获得大量使用微软 Power BI 和 Tableau 的实践。以及遵循和实施行业级数据质量评估框架。这意味着您将使用现有的公司指南来衡量您的数据的完整性、一致性和有效性。

作为一名分析师,我最喜欢的事情之一是,您可以使用外部数据源来揭示使用主数据集时不明显的模式。例如,我整合了澳大利亚人口普查数据和客户数据。这有助于我的洞察力,我建议你也去看看。

让我知道进展如何。如果你需要任何支持或者你想分享你的实习成果。你可以在这里找到我。

祝你好运!一定要把手弄脏,更重要的是,享受。

开始在 R 中使用反连接

原文:https://towardsdatascience.com/get-started-using-anti-joins-in-r-837af13be286?source=collection_archive---------36-----------------------

什么是反联接&我如何使用它?

图片由 Free-Photos 来自 Pixabay

介绍

假设您已经对其他更常见的连接类型(内、左、右和外)有了一些了解;添加 semi 和 anti 可以证明非常有用,可以节省您原本可以采取的多个步骤。

在之前的一篇文章中,我概述了半连接的好处以及如何使用它们。在这里,我将用一个非常相似的反连接解释来跟进。

如果你想先复习一下半连接,你可以在这里找到。

过滤连接

反连接和半连接与我刚才强调的其他四个有很大的不同;最大的区别是它们实际上被归类为所谓的过滤连接。

从语法上看,它与任何其他连接都非常相似,但其目的不是用额外的列或行来增强数据集,而是使用这些连接来执行过滤。

过滤连接不是通过添加新的信息列来分类的,而是它有助于保持或减少给定数据集中的记录。

反加入者

使用反连接的目的是获取一个数据集,并根据某个公共标识符是否不在某个附加数据集中对其进行过滤。如果它出现在两个数据集中…它被排除。

一个很好的方法就是编写替代方案。

地区分析示例

假设您是一名数据分析师,正在帮助您的销售团队工作,该团队刚刚聘用了一名新的客户经理。这位新代表需要客户,销售主管希望确保这些客户目前没有被占用。对于这个问题,假设我们有两个数据集;一个包含所有帐户,另一个记录所有销售活动,这将有一个活动 id 和一个帐户 id。

第一个数据集

|帐户 id |当前所有者|帐户名称|收入

第二数据集

|活动标识|帐户标识|活动类型|

您需要做的是使用第二个数据集过滤第一个数据集。

在一个没有反联接的世界里

让我们首先尝试在不使用反连接的情况下解决这个问题

根据我们现在对左连接的了解,我们可以做以下事情:

accounts %>%
left_join(activity, by = 'account_id')%>%
filter(is.na(activity_type))

如您所见,我们可以将活动数据集连接到我们的帐户数据集。对于在该数据集中没有匹配的任何账户,活动类型将被填充为 NULL。因此,如果您想要一个不在第二个数据集中的帐户列表,您可以在 activity type 为 NULL 的地方进行筛选。

这很好,并且有效地执行了我上面解释的相同功能。两个讨厌的事情是 1。它为您提供了一个新字段 activity _ type2.如果同一个帐户在活动数据集中出现多次,那么当你加入时,它将为尽可能多的匹配创建一个新记录。

之后,我们还可以添加一条 select 语句来提取该字段,这只是增加了另一行代码,您可以编写这些代码来实现该功能。

accounts %>%
left_join(activity, by = 'account_id')%>%
filter(is.na(activity_type))%>%
select(-activity_type)

使用反连接进行简化

现在让我们用一个反连接来进一步简化事情。

accounts %>%
semi_join(activity, by = 'account_id')

这将使我们得到与上面每个例子完全相同的输出。它将过滤出出现在活动数据集中的客户记录。因此,在我们的场景中,只有未被处理的客户会被转移到新代表那里。这种方法不会向数据集中添加列或行。它专门存在,并用于过滤目的。

结论

现在,在短短的几分钟内,我们已经介绍了很多内容,并提供了一些 dplyr 功能,可以简化您的代码和工作流程。

我们了解到:

  • 变异连接和过滤连接之间的区别
  • 如何在没有反连接的情况下执行“过滤连接”
  • 反连接的特定输出和意图
  • 如何使用反连接

我希望这能对你作为数据专家的日常工作有所帮助。

祝数据科学快乐!

开始学习数据科学并在新冠肺炎期间获胜

原文:https://towardsdatascience.com/get-started-with-data-science-and-win-during-covid-19-97365da7bccb?source=collection_archive---------39-----------------------

了解企业如何从数据中获得洞察力,以降低成本并提高员工的工作效率。

www.mltrons.com 新冠肺炎期间的数据策略

都在你的数据里

“由于最近的疫情,游戏规则被颠倒了。随着物理接触的消失,企业需要走向数字化。”

目前的情况再糟糕不过了,但与此同时,它也为我们提供了创新的机会,因为新的人类需求每天都在涌现。从网上购物的繁荣到网上协作工作的转变,由于我们在过去十年中建立的虚拟世界,我们正在疫情中生存。

如今,当企业考虑数字化时,首先想到的是数据。每天都会产生大量的数据,这是我们利用这些数据制定决策的最佳时机。在这个不确定的时代,企业需要在更高的风险水平下,以更大的紧迫感和更广泛的影响力做出更好的决策。这比以往任何时候都更需要高速、大容量的高质量数据分析。

因此,如果你正在考虑如何开始利用数据科学,那么恭喜你,你已经领先了。为了帮助您踏上数据科学之旅,以下是研究表明企业现在应该做什么的指南。

1.构建清晰、集中的数据战略

对于一个组织来说,现在最糟糕的决定是减少其转型计划,并恢复到传统的工作模式。组织需要一个强大的集中式数据科学战略,并采用支持投资的方法。借助人工智能和高级分析,大部分价值将来自降低成本、提高生产率和缩短洞察时间。如果实施得当,这可以帮助公司提高 10-15%的总体底线。

因此,简而言之,企业应该将数据科学和分析建立为卓越中心。高管需要坐下来,用清晰的里程碑来定义转型的指导性愿景。更重要的是,公司的每一个员工都需要成为这种转变的一部分。

2.确定并构建目标业务用例

一旦定义了高级分析策略,数据科学家和业务用户需要在 2 到 3 个月的敏捷冲刺中一起工作,从原始数据到可操作的见解。识别为业务创造价值的用例是在病毒期间脱颖而出的关键。我们的研究表明,大部分投资都在数字营销和内部生产力方面,因此利用此类用例非常有益。最后一步是将移动数据应用于业务的多个方面。在这一步中,公司将开始看到思维方式向生产力的转变,因为数据驱动的思维节省时间,最终节省金钱。

3.在应用数据科学领域培训现有员工

组织应开展内部活动,对当前员工进行基本数据科学概念和基本技能的培训。

目标应该是让每个员工都掌握高级分析的基本应用。理想的结果是,组织希望其员工了解他们可以提出的问题类型,他们可以从高级分析中获得的价值,以及他们如何解释技术信息来推动业务决策。对于旨在直接提高员工生产率的企业来说,这种再培训将是一项重要的竞争要务,这一点在今天比以往任何时候都更加重要。

根据麦肯锡的一项研究,总的来说,年收入超过 1 亿美元的公司中,82%的高管认为,再培训和再技能培训至少是解决技能缺口的一半方法。

为什么是现在?

今天很明显,公司正在积极反思他们的数字化转型之旅,并探索建立强大的数字化足迹的方法。这是一个投资系统的好时机,这些系统可以帮助公司分析从在线来源收集的数据,以产生可操作的见解。我们必须承认,人工智能和高级分析已被证明是依赖它来推动业务决策的公司的竞争优势。

尽管经济增长率为负,但企业现在有足够的时间通过加强高级分析实践、将数据转化为竞争优势以及培训现有员工来赶上竞争对手。我们非常肯定,一旦经济复苏,实施这一计划的公司将看到两位数的增长前景。我们都知道数据是新的石油,利用它将产生巨大的价值,因此公司应该立即开始关注它。

为了给高管们提供建议,我们在新冠肺炎举办免费的 30 分钟一对一办公时间 来帮助这些高管建立他们的数据科学战略。 点击这里 即可报名

关于作者:Raheel Ahmad是一名企业家,是 NYU 坦登可视化成像与数据分析(VIDA)中心的访问研究员学者。他也是m trons 的联合创始人。

深度学习 OCR 入门

原文:https://towardsdatascience.com/get-started-with-deep-learning-ocr-136ac645db1d?source=collection_archive---------13-----------------------

现代 OCR 的实用介绍,包括培训和测试所需的一切。

一项人类不该做的字符识别任务。

不久前,我开始研究潜在的 OCR 实现,目标是仅使用生成的训练数据在 tf.keras 2 中创建一个清晰的卷积递归神经网络(CRNN)基线。另一个目标是创建一个存储库,允许以后使用相同的模板探索不同的体系结构和数据域。该存储库应该是模块化的,易于使用,并充满解释性评论,以便我的同事可以很容易地跟进。

在高强度的谷歌搜索之后,我没能找到一个满足我要求的库。虽然有一些好的资源和实现,但我决定创建自己的[123

在我的笔记本电脑 GPU 上训练下面的简单模型需要几分钟,但是没有 GPU 你也可以很容易地训练它。

传统的文档处理流水线通过应用 OCR 软件从文本图像中解析文本来工作。通常,图像由边界框模块预先准备,边界框模块为 OCR 模块隔离图像内的文本区域。管道的后续阶段将:解析文本,提取含义、关键字、值和表格,并以更易于编程的形式返回结果,如:数据库条目、CSV,或将输出与公司的内部系统集成。

在这篇文章中,重点是 OCR 阶段,以基于深度学习的 CRNN 架构为例。在 GitHub 中共同发布了一个完整的功能实现,旨在作为一个端到端管道模板,包括数据生成和推理。重点是提供一个清晰的、有良好文档记录的管道,可以很容易地扩展到不同的架构,而不是神经网络(NN)架构本身。

我的目标是让人们能够在不访问 GPU 或任何训练数据的情况下,仅使用存储库中的指令来训练和测试简单的 OCR 模型。这篇文章将讨论一些实现细节,但是对于那些只想尝试代码的人来说,这些并不是真正需要的。

注意,虽然在这个例子中为了简单起见我们只解析数字,但是在回购中使用的 trdg 文本生成器可以从维基百科生成随机句子,用于训练更通用的 OCR 模型。也就是说,为了在更具挑战性的数据领域(如噪声图像、手写文本或自然场景中的文本)上实现良好的性能,需要调整模型和数据增强方法。

CRNN

OCR 中常用的神经网络架构很少,比如 CRNN 和各种基于注意力的模型[ 45 ]。CRNN 模型使用卷积神经网络(CNN)来提取视觉特征,这些视觉特征被整形并馈入长短期记忆网络(LSTM)。然后,LSTM 的输出被映射到具有密集层的字符标签空间。

CRNN OCR 模型的基本构件。块内的层数和具体参数在不同的实现中有所不同。在推理时,不使用 CTC 丢失,而是将来自密集层的输出解码成相应的字符标签。详情见代码。

有时 LSTM 层可以被去除

LSTM 层的功能是学习文本的语言模型。例如,考虑一种情况,其中 CNN 特征提取层产生“tha_k you”的编码,但是 place _ 处的字符没有被很好地识别。也许在那个地方有一个污垢点或者字符是以一种草率的方式手写的。但由于 LSTM 层通过数据了解到文本中有大量的“谢谢”输入,OCR 可以预测正确的缺失字母。

同样的推理对随机字符串不起作用,比如“1252 _ 5”;在这种情况下,没有“语言模型”的上下文历史,所以实际上我们可以删除这个任务的 LSTM 部分,使模型更快更轻。这正是我们的数字唯一的例子,但真实的话,LSTM 层应该使用。

在提供的示例存储库中,LSTM 的使用由 use_lstm 布尔控制,它是 models.make_standard_CRNN()的输入参数。

实施

这里的重点是高层次的概述和 tf.keras 实现中几个稍微复杂的部分,尤其是与 CTC 损失相关的部分。鼓励有兴趣更详细了解 CTC 损失的人阅读 这篇 的优秀文章。

在最高级别上,训练代码构建由图像高度和我们的字典中的字符总数参数化的神经网络,创建数据生成器并训练模型。注意,在我们的实现中,训练和推理可以接受任何长度的文本,图像宽度不需要预先定义。

单个批次中的图像必须具有相同的尺寸,但这由数据生成器(下面的 datagen)负责,将图像填充到批次中最大图像的尺寸。训练数据完全由 trdg 模块生成。

以下代码行构造了回调函数,用于在每个时期后可视化批图像及其预测,并在训练期间保存已训练的权重。在此之后,我们编译模型,选择我们喜欢的优化器,并为选定数量的时期进行训练。

tf.keras 中的高级函数

破解 tf.keras 2.1 中的 CTC 丢失

在 tf.keras 2.1 中为 CRNN 实现 CTC loss 可能会很有挑战性。这是由于来自 NN 模型的输出(最后一个密集层的输出)是形状的张量(batch_size、时间分布长度、数据中唯一字符的数量),但是批量条目的实际预测目标是单词中的字符标签,例如[1,3,6,2,0,0,0]。因此,预测和目标将不会具有相同的形状。tf.keras 2.1 中的一个限制是 y_true 和 y_pred 的维度必须匹配。在推理时,我们只需要模型输出和 CTC 解码函数来产生字符标签。

除了批次的 y_pred 和 true 标签(batch_labels),ctc_batch_cost 还需要每个输入单词的字符数(label_length)。这需要忽略 batch_labels 中的“虚拟标签”,例如,在一个最长的字为 7 个字符长的批处理中,4 个字符的字在位置[4:7]中的标签,因此 batch_labels 的形状为(batch_size,7)。还有,我们要馈入 input_length,也就是 y_pred (y_pred.shape[1])的时间维度。

在某些 keras 实现中,损耗是在神经网络内部实现的,输出不是上面的 y_pred。在这些实现中,模型已经返回计算的 ctc 批次损失,并且在 model.compile()中使用虚拟损失来最小化来自 NN 的输出(CTC 损失)。我不想在模型中实现 loss,因为我认为这使得代码与标准的 tf.keras 格式不同,并可能在以后搜索不同的架构和参数时导致复杂性。

但是我仍然需要依靠一些黑客技术来解决 y_true 和 y_pred 的不匹配维度。最后,我将标签、输入长度和 batch_labels 嵌入到一个形状为 y_pred 的数组中,并将其作为 y_true 返回。这种打包在数据生成器中完成,张量在损失函数中解包。

数组的打包实际上也考虑了所需的参数。只有当发送到 CTC loss 的 y_pred 的时间维度大于批中最长文本的字符数时,打包才可能导致错误。但这是使用太多卷积的结果,或者是由于输入定义不当。一个 6 个字符长的单词不能通过建议 5 个字符来识别。

如何自己测试 OCR

要开始使用,下载或克隆 github repo 并设置包含 Tensorflow 2.1、 trdg (pip install trdg)和 Jupyter notebook 的 Python 环境。自述文件包含如何使用 Docker 设置环境的说明。

设置好环境后,用 jupyter 笔记本打开 笔记本 (点击查看示例输出)。执行第一个单元以创建模型、数据生成器和编译模型。第二个单元将训练模型。第三个单元格将调用推理函数来预测放置在 inference_test_imgs/文件夹中的所有图像中的文本。训练也可以通过主文件夹中的“python train.py”来完成,但是你会错过训练过程中的可视化输出。

从推理输出的例子来看,预测的准确性取决于训练参数、神经网络结构和所使用的数据生成参数。在这个例子中,我们将与第一和第三个例子相似的数字输入神经网络。人们可以通过探索不同的神经网络结构、训练参数、字体、背景和其他数据扩充参数来改进结果。

希望你能从这个简短的介绍开始!更多详情和评论请查看 Github 我们也希望聘请有好奇心的、久经考验的软件工程师来开发人工智能/人工智能产品,请随时联系我们。感谢您的阅读!

我在 Medium 的其他帖子:

使用 Rigetti 的量子计算& pyQuil

https://medium . com/@ akikutvonen/how-to-train-sentence piece-tokenizers-for-any-language-with-large-data-pretrained-models-for-e84bb 225 ed4a

图论入门

原文:https://towardsdatascience.com/get-started-with-graph-theory-2b4460eeafc?source=collection_archive---------31-----------------------

图论简化版

图论简介

这是我全新系列 图论:围棋英雄 的第一个帖子。查看本系列下一篇文章的索引页面。它总是得到很好的维护和更新。

图论本质上是对图或网络的性质和应用的研究。正如我上面提到的,这是一个巨大的主题,本系列的目标是了解如何应用图论来解决现实世界的问题。如果我们看看我们生活的前提,我们可以看到许多问题突然出现,这些问题又可以被建模为图表。例如,从所有给定的类别中选择一个服装组合可以被认为是一个完美的场景。

作者照片

如果我们从每个类别中选择一件商品,比如从帽子中选择一件,从 T 恤衫中选择另一件,等等,我们最终会有 n 个可能的选项。我们这里的限制是,每个类别只有有限数量的资源。尽管如此,我们还是有相当多的组合。在这种情况下,我们可以使用图表来展示每个节点中不同类别的服装,以及它们之间通过的关系。希望节点和边背后的想法大家都知道。如果没有,节点可以被认为是每个类别的每个项目,例如,红色的帽子是一个节点,绿色的裤子也是一个节点。不同节点之间的关系可以使用边来描述,即从红色帽子到蓝色 t 恤。

图的另一个典型例子是朋友的社交网络。将数据可视化到图表上使我们能够生成并回答关于数据的不同有趣问题。

来自触摸屏的截图

在社交网络的情况下,我们可以问这样的问题:约翰有多少朋友,或者凯西和米兰之间有多少共同的朋友。

图形的类型

有不同类型的图形表示可用,我们必须确保在编程解决包含图形的问题时,我们理解我们正在处理的图形的类型。

  • 无向图

顾名思义,节点之间不会有任何指定的方向。因此,从节点 A 到 B 的边与从 B 到 A 的边是相同的。

照片researchgate.net 的哈坎·特拉利乌斯

在上图中,每个节点可以代表不同的城市,边显示双向道路。

  • 有向图

与无向图不同,有向图在不同的节点之间有方向或者说方向。这意味着如果你有一条从节点 A 到 B 的边,你只能从 A 移动到 B。

来自维基媒体的截图

和前面的例子一样,如果我们把节点看作城市,我们有一个从城市 1 到城市 2 的方向。这意味着,你可以从城市 1 开车到城市 2,但不能回到城市 1,因为没有从城市 2 回到城市 1 的方向。但是如果我们仔细观察图表,我们可以看到双向的城市。例如,城市 3 和 4 有指向两边的方向。

  • 加权图

许多图可以有包含权重的边,以表示真实世界的含义,如成本、距离、数量等

照片由Estefania Cassingena Navone通过freecodecamp.org拍摄

加权图可以是有向图,也可以是无向图。在这个例子中,我们有一个无向加权图。从绿色节点到橙色节点的成本或距离是 3,反之亦然。我们可以将这种关系表示为类似于 (u,v,w) 的三元组,该三元组显示了边从哪里进入、去往哪里以及两个节点之间的成本或距离。就像我们之前的例子一样,如果你想在两个城市之间旅行,比如城市绿色和橙色,我们将不得不支付 3 美元的费用,或者换句话说,我们将不得不开车 3 英里。这些指标是自定义的,可以根据情况进行更改。对于一个更详细的例子,考虑你必须从绿色到粉红色的城市。如果你看看城市图,我们找不到两个城市之间的任何直接道路或边缘。所以我们能做的就是经由另一个城市旅行。最有希望的路线是从绿色开始,经过橙色和蓝色,变成粉红色。如果权重是城市之间的成本,我们将不得不花费 11 美元通过蓝色到达粉红色,但如果我们通过橙色选择另一条路线,我们将只需支付 10 美元。

特殊图形

除了上面的划分,我们还有另一组图叫做特殊图。

最重要的特殊图是树。这是一个没有圈的无向图。等价地,它有 N 个节点和 N — 1 条边。

作者照片

上面给出的所有图都是树,甚至最左边的图也是,因为它没有圈。

  • 有根树

有根树是具有指定的根节点的树,其中所有其他节点或者朝向根或者远离根。

作者照片

红色的节点是根节点。最左边的树被称为树内,因为所有其他节点都向根节点靠近。另外两棵树是外树,因为所有其他节点都离开了根。

  • 有向无环图 ( DAG s)

Dag 是没有圈的有向图。这些图在表示具有依赖关系的结构(如调度程序和编译器)时起着重要的作用。

作者照片

我们可以用这个图来表示有意义的事物之间的拓扑顺序。例如,如果我们在流程管理器中使用 DAGs,我们可以说子流程 x 和 y 应该在继续处理 z 之前完成。

  • 二部图

二部图的顶点可以分成两个不相交的集合,比如 U 和 V,其中图中的每条边连接 U 和 V 之间的顶点。

截图来自 Wolfram Mathworld

如果我们看这个图,我们可以看到每个图可以分成两个不相交的集合(U,V ),每个边连接 U 和 V 之间的节点。

  • 完整图形

我们称一个图为完全的当且仅当,每一对顶点之间有唯一的边连接。具有 n 个顶点的完整图被表示为 Kn。

截图来自 Wolfrom Mathworld

由于要遍历的边的数量,完全图被认为是最坏情况图。

图形的表示

在这里,我们讨论如何在内存中存储一个图形,以便进一步处理。

  • 邻接矩阵

有效的方法是使用大小为 NxN 的矩阵,其中 N 是节点的数量。我们称这个矩阵为邻接矩阵。

截图来自softwaretestinghelp.com

上面给出的是一个有向加权图及其对应的邻接矩阵 M 。该矩阵的大小为 5×5,因为总共有 5 个节点。从节点 A 到 B 的成本是 4,在 M[A][B]中给出。类似地,从一个节点到其自身的成本是零,因此所有对角线元素将总是零。这是存储密集结构的图形信息的空间有效的方法,并且边查找将总是花费恒定的时间。但是,随着节点数量的增加,跟踪边信息所需的空间也将呈指数增长。如果大部分的边都没有适当的信息,我们将最终建立一个稀疏矩阵。

  • 邻接表

我们用来存储节点和边信息的另一个重要结构是邻接表。这是从节点到边列表的映射。

摄影:苏伦德·巴斯瓦纳经由 researchgate.net

给出的例子是一个无向加权图。如果我们看最右边的图,我们可以看到从每个顶点开始的几个列表。节点 1 有两条输出边,即 2 和 5,我们用它的成本来表示这些信息。列表中的每个元素都有目标节点和相应的成本或权重。

如果邻接表是稀疏的,则邻接表是存储图信息的有效机制,即,与相同情况下的邻接矩阵相比,邻接表将占用更少的存储器。但是,这仍然是一个比邻接矩阵稍微复杂的表示。

  • 边缘列表

边列表是一种简单地将图表示为无序边列表的方式。假设任何三元组(u,v,w)的符号表示:
从 u 到 v 的成本是 w ”。

作者照片

对应于左侧的有向加权图,右侧给出了边列表。列表中的每一对都显示了两个节点之间的边信息以及相关的权重。

在接下来的帖子中,我们将讨论可以通过图论解决的不同问题。

Python 入门的 3 个简单技巧(放弃 Excel!)

原文:https://towardsdatascience.com/get-started-with-python-and-ditch-excel-85e7f67318b?source=collection_archive---------29-----------------------

面向 Excel 高级用户的熊猫介绍

让我们学一些蟒蛇和熊猫吧!资料来源:Nik Piepenbreier

所以你已经实现了思想上的飞跃,想要学习 Python——这太棒了!但是从哪里开始呢?

让我来指导您完成您已经知道如何在 Excel 中以及如何在 Python 中完成的任务!

您将使用 Pandas,这是 Python 中的主要数据分析库。

如果您需要安装 Pandas,您可以使用 pip 或 conda:

pip install pandas
#or
conda install pandas

Pandas 将数据加载到数据框中,你可以把它想象成 Excel 表格。

让我们将数据集加载到数据报中。您可以通过使用以下代码来实现这一点。我们还将使用熊猫头方法探索前五行:

用熊猫生成我们的数据框架。资料来源:Nik Piepenbreier

为了跟随 Excel 中的教程,文件可以在这里找到

Excel 表格和 Pandas 数据框架之间有许多不同之处。让我们快速浏览一下!

比较 Excel 工作表和 Pandas 数据框架。资料来源:Nik Piepenbreier

好了,现在我们开始吧!

过滤、排序和重新排序列

Excel 是一个更加可视化的工具,可以很容易地点击一个按钮,抽象出你想要完成的功能。

按单列排序

在 Excel 中对单个列进行排序。资料来源:Nik Piepenbreier

例如,如果您想在 Excel 中对一列进行排序,您只需:

  • 选择数据选项卡,
  • 突出显示要排序的列,然后
  • 单击从 A 到 Z 排序或从 Z 到 A 排序。

为了在熊猫身上做到这一点,你应该写:

熊猫按单列排序。资料来源:Nik Piepenbreier

按多列排序

有时您可能希望按多列排序。

在 Excel 中按多列排序。资料来源:Nik Piepenbreier

同样,Excel 使这变得很容易:

单击数据选项卡

  • 点击排序
  • 输入要作为排序依据的列

对于熊猫,只需在“by”参数中添加一个列表:

在 Pandas 中按多列排序。资料来源:Nik Piepenbreier

过滤列

在 Excel 中筛选列是一项简单的任务!只需点击数据选项卡,然后过滤。这将在所有列标题上创建箭头。当您点击这些时,只需填写您的选择:

在 Excel 中筛选列。资料来源:Nik Piepenbreier

对熊猫来说,这同样简单:

在 Pandas 中过滤一个列。资料来源:Nik Piepenbreier

最棒的是,您还可以使用比较运算符来选择 10 个以上的单位,或者基于多个条件进行选择:

  • 比较:可以用>(大于)、<(小于)、==(等于)、> =(大于等于)、< =(小于等于),
  • 和【条件】条件:将每个条件用括号括起来,并用与符号(&)将括号分开
  • 条件:用括号将每个条件括起来,并用竖线(|)将括号隔开

熊猫身上不同类型的过滤器。资料来源:Nik Piepenbreier

重新排序列

重新排序列更多的是给你自己一个视觉提示。

要在 Excel 中拖动对列进行重新排序,您可以通过单击列的标题来选择该列,将鼠标悬停在旁边,直到光标变为四向箭头,然后按住 SHIFT 键并将该列拖动到新位置:

在 Excel 中移动列。资料来源:Nik Piepenbreier

要在 Pandas 中完成同样的事情,您只需按照您想要的列的顺序将它们放入一对方括号中:

熊猫栏目重新排序。资料来源:Nik Piepenbreier

数据透视表(含百分比)

数据透视表是那些在 Excel 中把你带到下一个级别的东西之一。

它们允许您轻松快速地汇总数据,而无需依赖复杂的公式。

假设您想知道每个地区的总销售额,您可以:

  1. 选择数据,单击“插入”选项卡上的“数据透视表”,然后单击“确定”创建表格。
  2. 将 Region 拖动到“行”框中,将 Sales 拖动到“值”选项卡中。Excel 会自动假设我们要将这些值相加。

在 Excel 中创建数据透视表。资料来源:Nik Piepenbreier

要在 Pandas 中完成同样的事情,您可以简单地使用 pivot_table 函数:

在 Pandas 中创建数据透视表。资料来源:Nik Piepenbreier

让我们稍微分解一下:

  • 我们创建一个名为 pivot 的新变量。
  • 我们使用熊猫数据透视表函数。我们的第一个论点是数据帧 df。
  • 索引参数是' region ',它告诉 Pandas 基于' Region '列创建行。
  • 我们将参数值分配给字段“Sales”,让 Pandas 知道我们想要计算销售列。
  • 最后,我们使用 agg func(' aggregation func ')参数告诉 Pandas 对值求和。默认值为“平均值”。

要深入了解熊猫数据透视表的功能,请查看我在熊猫的数据透视表上的另一篇文章。

将数据透视表值显示为百分比

您可能希望将值显示为列总数的百分比。同样,Excel 使这变得非常容易:

在 Excel 中计算数据透视表中的百分比。资料来源:Nik Piepenbreier

  • 只需右键单击一个值,
  • 选择将值显示为→占列总数的%

在熊猫身上也一样容易做到这一点。最简单的方法是为此创建一个新列:

计算熊猫的数据透视表百分比。资料来源:Nik Piepenbreier

让我们来看看发生了什么:

  • 我们通过使用 pivot['% of column total'],声明了一个新列——这将为该列指定名称' % of column total '
  • 然后,我们将行中的每个值(pivot['sales'])除以整个列的总和(pivot['sales']sum())并乘以 100

创建图表

在 Excel 中创建图表。资料来源:Nik Piepenbreier

现在,如果你想创建一些图表,这在 Excel 和 Python 中都非常容易。

我们先来看 Excel。如果要将此数据透视表绘制成柱形图:

  • 将指针放在表格中的一个单元格上,
  • 转到插入→二维柱形图

对熊猫来说,这甚至更容易。Pandas 内置了 Python 顶级的数据可视化库功能之一。就像加法一样简单。plot(kind = 'bar ')到代码的结尾:

在 Pandas 和 Matplotlib 中创建图表。资料来源:Nik Piepenbreier

这可能看起来有点令人生畏。让我们来分解一下:

  • 从 matplotlib 导入 pyplot 作为 plt
  • 重写您之前的代码(第 2-3 行)
  • 现在画出“销售”列,并指定一个 kind =“bar”作为参数
  • 最后,使用 savefig 方法保存文件。

注意:如果你使用的是 Jupyter 笔记本,你可以在导入你的库后,通过编写以下代码来显示图表:

%matplotlib inline

额外提示:正确格式化值

在处理数据时,正确设置值的格式可能会有所帮助。

在 Excel 中设置数据格式。资料来源:Nik Piepenbreier

例如,将货币格式化为美元(等等。)或百分比。

要在 Excel 中做到这一点,您需要:

  • 选择要格式化的值,
  • 在“主页”选项卡的“号码”部分中,选择所需的类型

熊猫将这一点隐藏了一点,这可能会让新来者颇感困惑。

实现这一点的一个简单方法是使用 apply()函数。这个函数的作用是获取一个序列,并对其应用另一个函数。应用的函数将是格式化值的函数。

如果您想设置透视数据框架中销售列的格式,您可以编写:

在 Pandas 中格式化值。资料来源:Nik Piepenbreier

这可能看起来有点不全面(确实如此),但是在如何设计数据样式方面,它确实给了您很大的灵活性。让我们仔细看看:

  • 我们定义了一个名为 format()的函数,它接受一个参数(x)
  • 该函数仅用于返回使用特定格式的字符串格式的格式化值。
  • ${:,. 2f}部分表示实际的格式。冒号(:)用于表示格式的开始,逗号(,)用于表示千位逗号分隔符,而. 2 表示两位小数。
  • 这种符号可能有点难以适应,我倾向于谷歌搜索我想要的样式,然后复制粘贴。

同样,如果你想保持百分比,你可以写:

熊猫中的格式化百分比。资料来源:Nik Piepenbreier

在这段代码中,我们创建了另一个名为 format_percent()的函数,并执行了与上面类似的步骤。

注意:列总计的“% 1”列已被修改为不将该值乘以 100。这是因为格式化程序会自动完成这项工作。

在那里你可以学到更多

非常感谢您阅读这篇文章!希望你觉得有用!

我已经写了一些文章,解释了如何用 Python 处理普通和高级的 Excel 任务,如果你想看看的话!

如果你准备好投入 Python 和 Pandas,我还写了一本电子书,提供了对 Python、Pandas 和 Matplotlib 的完整介绍,可以让你很快上手!

你可以通过点击这个链接找到它。

祝您愉快!

从这 5 个基本功能开始使用 PyTorch。

原文:https://towardsdatascience.com/get-started-with-pytorch-with-these-5-basic-functions-33ae428bab97?source=collection_archive---------18-----------------------

PyTorch 基础

对深度学习的需求不断增长。更多的开发人员和数据科学家正在加入深度学习的行列,提供量身定制的库。

功能 1 —火炬.设备()

PyTorch 是一个由脸书开发的开源库,在数据科学家中很受欢迎。其崛起背后的一个主要原因是 GPU 对开发者的内置支持。

torch.device 使您能够指定负责将张量加载到内存中的设备类型。该函数需要一个指定设备类型的字符串参数。

您甚至可以传递一个序号,如设备索引。或者不指定 PyTorch 使用当前可用的设备。

示例 1.1

示例 1.2

对于 例 1.1 ,我们选择运行时要存储张量的设备类型。注意,我们已经将我们的设备类型指定为 cuda ,并在相同的字符串中附加了序号,用“:”分隔。

例 1.2 通过为设备类型和索引传入单独的参数,获得了相同的结果。

创建张量时定义设备类型

torch.device()中预期的设备类型是 cpu、cuda、mkldnn、opengl、opencl、ideep、hip、msnpu 。为了正确使用此方法,设备类型应该存在于预期设备列表中。

让我们看看当我们尝试将 GPU 指定为设备类型时会发生什么。

示例 1.3 (a) —创建“gpu”类型设备实例时出现运行时错误

运行笔记本的计算机上应该有指定的设备类型。否则将导致错误,如示例 1.3 (b)所述。

1.3 (b) 中,我们使用需要 NVIDIA GPU 的 cuda 设备类型定义了一个张量。由于我们的机器没有任何可用的 GPU,内核抛出了一个运行时错误。

示例 1.3 (b) —指定不存在的设备类型时出现运行时错误

功能 2 — torch.view()

torch.view()方法将张量(无论是向量、矩阵还是标量)的视图更改为所需的形状。转换后的张量修改了表示维度,但保留了相同的数据类型。

让我们来看一个例子——定义一个样本张量 x,并转换它的维度以存储在另一个张量 z 中。

示例 2.1

例 2.1 中,我们对一个表示为单行向量的 4 x 5 矩阵的维数进行了变换。默认情况下,行优先顺序连续打印行的元素。变换视图中的每个行元素都以与原始张量中相同的顺序出现。

此外,新张量的形状必须支持原始张量中相同数量的元素。您不能在 5 x 3 视图中存储 4 x 5 形状的张量。

对于 例 2.2 ,我们将用-1 来表示一个维度。PyTorch 自动从其他维度解释未知维度。变换张量在大小和步幅上与原始张量兼容。

示例 2.3 —不正确的形状

请注意,一次只能推断一个维度。对多个维度使用-1 只会引入歧义和运行时错误!

PyTorch 只允许-1 作为最多 1 维的可接受值。如果不止一个维度作为-1 传递,它将抛出一个运行时错误

函数 3 — torch.set_printoptions()

很多时候,你想在执行某些任务之前打印出张量的内容。为此,在笔记本中打印张量时,您可能需要更改显示模式。

使用 set_printoptions,您可以调整精度级别、线宽、结果阈值等属性。

在我们的例子中,我们将采用一个代表 20 x 30 矩阵的张量。通常不需要在笔记本中表示如此庞大的矩阵。打印张量变量背后的一个常见用例是查看前几行和最后几行。

示例 3.1(a)-使用默认打印选项打印

我们将根据自己的喜好,利用阈值、边项和线宽属性来改变张量的视觉表示。我们还可以使用 precision 属性改变小数点后显示的位数。

示例 3.1 (b) —更新了打印选项以显示更少的行

在该方法中,我们有三种可用的配置文件:默认、微小和完整。将配置文件名与其他属性一起传递是不正确的用法。在这种情况下,该函数会忽略 profile 属性。

示例 3.2

函数 4 — Tensor.backward()

张量用于简化机器学习管道中所需的常见任务。为了执行梯度下降(一种流行的损失最小化技术),我们需要计算损失函数的梯度(召回导数)。

PyTorch 使用 backward()方法简化了这一过程,它在每次方法调用时存储渐变。注意:PyTorch 仅在其 require_grad 属性设置为 True 时计算张量的梯度。

示例 4.1

我们会用线性方程 y = mx + c 来求 y w.r.t 对方程中每个变量的偏导数。

示例 4.1 (a)

在调用 y.backward()方法并打印出计算出的梯度后,我们可以访问。张量 x 的梯度性质。

示例 4.1 (b)

因为我们没有将 require_grad 选项设置为 True,所以我们在调用时不会得到结果。m 的 grad 属性。

再次调用 y.backward()将导致 y . w . r . t 张量的二阶微分。注意 PyTorch 累积存储梯度。

函数 5 — torch.linspace()

linspace()方法返回一个包含一系列数字的一维张量。与随机生成数字的 rand()函数不同,返回的数字是 linspace()中等差数列的成员。

每个成员的差异由 steps 属性和范围(end-start)指定。

示例 5.1

输出张量包含 50 个 1-10 范围内的等距数字。 dtype 属性是 int 所以不存储小数位。

例 5.2—out属性也可用于指定张量来存储方法的结果。

请注意,在使用 linspace()方法创建张量时, dtype 值必须与输出张量定义的 dtype 一致。

示例 5.3-dtype 属性不匹配

结束语

本文介绍了 PyTorch API 中的一些基本方法,帮助您开始使用它。由于大部分实现都是从 NumPy 库中借用来的,以 Python 开发人员现有的理解和经验为基础,因此该 API 很容易上手。

通读这些功能后的下一步是浏览官方文档。由于 PyTorch 是一个深度学习库,所以强烈建议您在开始使用这些函数之前先学习 ML 基础知识。

就这样,你坚持到了我 PyTorch 系列的第一篇博客的结尾!

参考

PyTorch 官方文件https://pytorch.org/docs/stable/torch.html

如果你喜欢这篇文章,并希望在未来阅读我的更多内容,你可以在这里以及在 LinkedInTwitter 上关注我。此外,请在评论中提出你的建议,告诉我在这一页上还能覆盖哪些功能。

照片由特伦特·欧文Unsplash 拍摄

在 LinkedIn和 Twitter上关注我,获取关于数据科学、机器学习和数据结构的内容。

如何使用 Python 获取每日新闻

原文:https://towardsdatascience.com/get-the-latest-news-using-python-and-performing-analysis-on-it-using-wordclouds-b4541b3b14fd?source=collection_archive---------16-----------------------

使用 Python 中的 NewsAPI 获取新闻,并生成词云来理解新闻和观点。

图片来源:作者

你有没有想过如何通过编程获得最新的新闻?新闻 API 就是 Python 中的一个这样的模块,可以在这方面帮助你。它有大约 120 个来源的数据,包括路透社、BBC 新闻、ABC 新闻、ESPN。

[## Python 客户端库—新闻 API

使用非官方的 Python 客户端库将新闻 API 集成到您的 Python 应用程序中,而不用担心…

newsapi.org](https://newsapi.org/docs/client-libraries/python)

首先,从 NewsAPI 获取 API 密钥,开始提取新闻文章。你可以在这里看到更多关于如何得到一个。

[## 开始—文档—新闻 API

要开始使用,您需要一个 API 密钥。它们免费用于开发、开源和非商业用途,您可以…

newsapi.org](https://newsapi.org/docs/get-started)

导入相关的库。

from newsapi import NewsApiClient

这是用于 NewsAPI 导入的。现在初始化 NewsAPI 的变量

newsapi = NewsApiClient(api_key=api_key)from pandas.io.json import json_normalizeimport pandas as pd

我们将使用 Python 中漂亮的 Soup 包来帮助清理数据中的 HTML 标签。

from bs4 import BeautifulSoup

现在,让我们看看实际用途。

L最新消息

获取最新消息:

def top_headlines():    
   country=input("Which country are you interested in?") 
   category=input("""Which category are you interested in? \nHere 
   are the categories to choose from:\nbusiness\nentertainment   
   \ngeneral\nhealth\nscience\ntechnology""")        
   top_headlines =newsapi.get_top_headlines(category=category,
   language='en',country=country)     
   top_headlines=json_normalize(top_headlines['articles'])   
   newdf=top_headlines[["title","url"]]    
   dic=newdf.set_index('title')['url'].to_dict()

让我们来谈谈这段代码是做什么的。我写过一个函数叫 top_headlines。我接受两个输入,国家和类别。当我向该国提供输入时,你必须以特定的格式书写。新闻 API 中的国家参数遵循以下代码系统:

[## ISO 3166 国家代码列表

下面的可排序表格包含 249 个国家中每个国家的三组 ISO 3166-1 国家代码,链接到…

en.wikipedia.org](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes)

USA 是“us”,英国是“gb”,印度是“in”。有关其他国家的标志,请参考上面的链接。

在代码本身中,我已经提到了如何向 category 参数提供输入。“一般”代表一般新闻,“体育”代表体育新闻,以此类推。

使用 get_top_headlines,您可以获得最新的新闻。现在,输出是 JSON 格式的,所以我想把它转换成数据帧。因此,我使用了在本教程前面导入的 json_normalize 方法。然后,我将它存储到一个新的 Dataframe 中,该 data frame 只包含从 JSON 输出中返回的列列表中选择的几个列。

然后我决定,我要搞清楚这个新闻信息。我用了一个案例来看媒体的观点在一个特定的时间段内是如何变化的。新闻 API 有一个付费版本,提供长达两年的信息。在免费版本中,你可以检索 30 天的新闻,这也是我选择的时间范围。

搜索特定的主题

为了进行这种分析,我们需要使用这种方法:

get_everything(query,language,sort_by='relevancy',from_param,to)

这意味着它可以获得与特定搜索查询相关的所有信息。比方说,您想要获取有关当今世界最热门话题——新冠肺炎病毒或冠状病毒——的所有信息,您可以在上述函数的“query”参数中指定。

上述函数中的“from_param”参数和“to”参数是日期参数。它会要求您指定希望获得搜索查询结果的时间范围。因为我提到过,我想获得 30 天的所有结果,这是免费版本允许的最大时间范围,我将指定 from_param 为今天的日期前 30 天。然而,我需要在一个循环中写这个,这样我可以确保我每天都得到。

所以,我首先构建了一个日期函数来帮助我。

import datetime
from datetime import datetime, timedelta
def date(base):    
    date_list=[]    
    yr=datetime.today().year    
    if (yr%400)==0 or ((yr%100!=0) and (yr%4==0)):          
        numdays=366        
        date_list.append([base - timedelta(days=x) for x in    
        range(366)])   
    else:        
        numdays=365        
        date_list.append([base - timedelta(days=x) for x in    
        range(365)])    
        newlist=[]    
        for i in date_list:        
           for j in sorted(i):            
               newlist.append(j)    
        return newlist 
def last_30(base):     
    date_list=[base - timedelta(days=x) for x in range(30)]      
    return sorted(date_list)  
def from_dt(x):    
    from_dt=[]    
    for i in range(len(x)):          
        from_dt.append(last_30(datetime.today())[i-1].date())         
    return from_dt        
def to_dt(x):    
    to_dt=[]    
    for i in range(len(x)):        
        to_dt.append(last_30(datetime.today())[i].date())    
    return to_dt
from_list=from_dt(last_30(datetime.today()))
to_list=to_dt(last_30(datetime.today()))

我构建的第一个日期函数(date)是一个更通用的日期函数,如果需要的话,我想在很长的时间内使用它。我正在使用 first date 函数获取所有日期的列表。我只需要 30 天,所以我确保使用 last_30 来完成。这将给我从当前日期和时间开始的过去 30 天的列表。继续讨论 from_dt 函数,它专门用于上面提到的 get_everything 函数的 from_param。这是您需要所有新闻文章的时间范围的开始,to_dt 是结束日期。

我现在有两个单独的列表,分别是开始日期和结束日期。

现在我们将处理查询参数,它是 get_everything 函数的搜索词。

def func(query): 
    newd={}    
    newdf=pd.DataFrame()    
    for (from_dt,to_dt) in zip(from_list,to_list):           
        all_articles =   
        newsapi.get_everything(q=query,language='en',
        sort_by='relevancy',from_param=from_dt,to=to_dt)          
        d=json_normalize(all_articles['articles'])         
        newdf=d[["url","publishedAt","source.name","author"]]
        dic=newdf.set_index(["source.name","publishedAt","author"]) 
        ["url"].to_dict()        
        for (k,v) in dic.items():            
            page = requests.get(v)            
            html = page.content            
            soup = BeautifulSoup(html, "lxml")            
            text = soup.get_text()            
            d2=soup.find_all("p")            
            newd[k]=re.sub(r'<.+?>',r'',str(d2))     
    return newd

遍历日期的 from 和 to 列表的压缩版本,我们得到了 30 天时间范围内的所有文章的列表。我选择循环的原因是,这样我就可以对每一天进行分析。然后我将它存储在数据框中。然后,我获取相关的列,并将它们存储回字典中。我想解析新闻 URL 中的内容,以便只从文章中获取内容。我在这里使用 Python 中的 BeautifulSoup 包来解析内容,并获取信息所在的相关

标签。因为我们在这里主要关注文本数据,所以我们需要这些段落标签之间的信息。你可以在这里找到更多关于 BeautifulSoup 的信息:

[## 美丽的汤文档—美丽的汤 4.9.0 文档

Beautiful Soup 是一个 Python 库,用于从 HTML 和 XML 文件中提取数据。它与您最喜欢的解析器一起工作…

www.crummy.com](https://www.crummy.com/software/BeautifulSoup/bs4/doc/)

一旦我们有了更清晰的数据,我们现在就可以继续使用单词云来分析模式。

N使用 WordCloud 进行 ews 分析

现在,我们来看看单词云。我们可以从新闻中理解数据的部分。有哪些常见的模式?

def wordcld(dictionary):        
    newd={}    
    for (k,v) in dictionary.items():        
    if v!='[]':            
        wordcloud = WordCloud().generate(str(dictionary[k]))                
        fig, axes= plt.subplots(figsize=(20,12),clear=True)                     
        plt.imshow(wordcloud, interpolation='bilinear')            
        plt.show()                 
    else:            
        print(str(k[0])+"_"+str(k[1][5:10])+"_"+str(k[1][11:13])              
        +"_"+str(k[1][14:16]) +"_"+str(k[1][17:19])+"_"+str(k[2]))             
        print("Wordcloud Not applicable")
dic=func("Indian Economy")
wordcld(dic)

我在搜索一些关于印度经济的常用词,得到了下面的图片。我得到的图像是一天。我上面的代码会给你 30 天的结果。

图片来源:作者

试试这个,如果你有任何问题,请随时告诉我。

下一步,您可以使用 Twilio API/SendGrid 电子邮件 API 将此作为文本消息/电子邮件通知发送给自己,我将在另一个教程中介绍,或者您可以看到一些现有的 API,如下所示:

[## 用 AWS Lambda & Twilio 创建一个无服务器的 SMS-Twitter 应用程序

我们将使用 AWS Lambda 函数来创建 Tweets,并通过 SMS 向/从 Twilio 发送 Twitter 事件通知…

medium.com](https://medium.com/@osaimola/creating-a-serverless-sms-twitter-app-with-aws-lambda-twilio-b33f63254cbb) [## v3 API Python 代码示例

让我们知道我们做得怎么样!请评价此页面:如果您需要 Twilio SendGrid 的即时帮助,请…

sendgrid.com](https://sendgrid.com/docs/for-developers/sending-email/v3-python-code-example/)

总结一下:

图片来源:作者

如果你有任何问题,欢迎在这里评论或者给我发邮件。你也可以在 GitHub 上看到这段代码:https://github.com/mukund14/News/tree/news_api_Python

mukundan.sankar14@gmail.com

充分利用 scikit——学习面向对象编程

原文:https://towardsdatascience.com/get-the-most-out-of-scikit-learn-with-object-oriented-programming-d01fef48b448?source=collection_archive---------28-----------------------

浏览一个数据科学示例,增强您的 Python 编码能力!

作为数据科学家,我们都熟悉 scikit-learn ,这是 Python 中最常用的机器学习和数据分析库之一。我个人在我的大部分专业项目中都使用它和熊猫。

然而,直到最近,当我需要构建一个定制的回归估计器时,我才充分利用了 scikit-learn。我惊喜地发现,创建一个新的兼容的估计器类是如此容易,这都归功于 scikit-learn 组件的面向对象设计。

在本文中,我将带您了解一个常见的数据科学工作流,并演示面向对象编程(OOP)的一个用例。特别是,您将学习如何使用继承的概念来定制 transformer 对象,这允许我们扩展现有类的功能。由于继承,这个转换器将很容易适合 scikit-learn 管道,以构建一个简单的机器学习模型。

激励人心的例子。

为了更清楚地说明问题,让我们看一个受零售商营销启发的实际例子。假设我有一个数据集,其中每条记录代表一个客户,并且有与购买最近、频率和货币价值相关的度量(即特征)。使用这些功能,我们希望预测客户是否会加入零售商的奖励卡计划。这模拟了一个真实的场景,我们希望预测哪些客户是营销的最佳目标。请参见下面的客户记录数据示例:

我们客户数据的前十行。请注意用红色圈出的缺失值。

数据的一个显著特点是缺失,即在观察值中存在缺失值。这些值将被渲染为 NaN 的,一旦被熊猫读取,将不会在我们的机器学习模型中工作。为了构建我们的模型,我们需要估算缺失特征的值(即,用推断的数量替换缺失值)。虽然有多种数据插补技术,但为了简单起见,假设我们想尝试对任何缺失值进行列均值或中值插补。

那么,我们应该使用哪个统计量,平均值还是中间值?找出答案的一个简单方法是尝试两个选项,并评估哪一个在网格搜索中产生最佳性能,也许可以使用 scikit-learn 的 GridSearchCV

一个错误是计算整个训练集的平均值和中值,然后用这些值进行估算。更严格地说,我们需要计算这些数据的统计数据,不包括坚持折叠。这看起来很复杂,但是多亏了 OOP,我们可以通过继承轻松实现我们自己的转换器,它将与 scikit-learn 兼容。从那里,我们可以将 transformer 插入到 scikit-learn 管道 中,这是一个与 transformer 对象列表以及 estimator 对象一起排序的对象,用于构建我们的模型。

构建自定义输入转换器。

为了开始为我们的转换器构建类,我们将编写类定义和构造函数。特别注意( TransformerMixinBaseEstimator ),这表明我们继承了这两个类。这将使我们创建的custom impute transformer类的对象与 scikit-learn 的其他组件兼容,方法是提供 GridSearchCV (如 get_params )所期望的方法的实现,并指示我们创建的对象是正确的类型(如 transformers)。

接下来,我们将实现 fit 方法。给定数据集X,fit计算每列的平均值或中值,可用于以后的插补。

最后,我们编写了 转换 的方法。该方法将我们希望转换的数据集作为参数,应用已经计算的“估算值”并用它们填充 NaN 值。

下面是一个在小样本上使用自定义 transformer 对象的例子。

以下是打印到控制台的结果:

红色表示 x1 的平均值,蓝色表示特征 x2 的平均值。

注意,我们创建的功能已经在 scikit-learn 的simple impute类中可用。我决定在这里从头实现它,因为它易于构建,并且很好地展示了创建更复杂的转换器所需的内容。

将转换结果传输到 ML 模型中。

我们将创建一个管道,将自定义转换器的结果级联到逻辑回归模型中。

加载数据。

通过传递元组列表来创建管道。每个元组都有流水线阶段的名称(在这个例子中是估算模型)以及用于估计器的变换器的对象。

对于网格搜索,我们将搜索以确定哪种类型的插补是最好的,因此在 param_grid 中有条目" imput _ _ imput _ type ":[" mean "," median"]。

我们将获得最好的管道,并从中获得训练预测。注意,我们可以在 best_pipe 对象上调用 预测 函数。这有效地将首先从custom impute transformer运行 转换 ,然后从逻辑回归运行 预测

最佳流水线和训练精度的输出如下。

GridSearchCV 确定的最佳管道。请注意红色方框中的最佳超参数值。

演示变压器做我们想要的。

在这个例子中,我们清楚地表明,我们需要 transformer 来计算除了保留折叠之外的所有折叠的统计数据。为了证明我们的代码确实做到了这一点,我们将进一步利用继承来构建一个 impute transformer 对象,该对象完全执行我们最初的 transformer 所做的事情,并添加了在交叉验证的每次迭代中输出不同统计数据的功能。

我们将再次使用继承来创建customimputoutputtransformer,它是customimputtransformer的子类:

我们唯一需要实现的功能就是 fit 。事实上,我们将使用通过使用调用标准 fit 函数得到的结果,并简单地用控制台输出扩充它,如下所示。

现在我们需要做的就是改变我们在管道中使用的对象,并在运行它时监视输出是什么。

为了简洁起见,我可视化了一个特性的输出。你可以在 Github 上看到实际的打印输出。

它的行为符合预期。 GridSearchCV 的每次迭代都产生四个训练折叠的统计数据,而不是计算一个全局值。

结论

在本文中,我们了解了如何使用继承(OOP 的一个基础方面)来解决现实世界中的数据科学问题。我展示的例子很简单,但是,您可以使用相同的框架为您的项目构建更复杂的类。

所有的代码、数据和结果都可以从这个 Github repo 中提取。本文中展示的例子是完全可复制的,所以您可以随意提取代码并自己使用它。

用自然语言处理认识你的朋友

原文:https://towardsdatascience.com/get-to-know-your-friends-with-natural-language-processing-nlp-38a1f6e56e09?source=collection_archive---------32-----------------------

准备、探索、了解 WhatsApp 用户使用 Python 的习惯。

马科斯·保罗·普拉多在 Unsplash 上的照片

D 做一个新项目并有一个好的想法可能具有挑战性。在过去的几个月里,在奇怪的情况下,我们都在,我不知道该做什么项目。我开始了几个项目,但没有完成,因为结果并不乐观,不值得一篇文章。我知道我不想使用 Kaggle 或其他地方的数据集,但我想通过使用我需要收集的数据来做一个端到端的项目。

在浏览了 Medium 上的文章/项目后,多亏了 Samir Sheriff 的文章,我发现可以分析来自 WhatsApp 组的数据,由于我没有做过自然语言处理或 NLP 的项目,我认为这是提高我的技术技能的绝佳机会。

[## 构建自己的 Whatsapp 聊天分析器

使用 Python 的分步指南

towardsdatascience.com](/build-your-own-whatsapp-chat-analyzer-9590acca9014)

什么是自然语言处理?

自然语言用于人类之间的日常交流,如 Messenger、电子邮件、Whatsapp、社交媒体(Twitter、脸书等)。).这些来源的数据对于文本和语音来说都是高度非结构化的,因此很难被机器解析和理解。自然语言处理(NLP)涉及自然人类语言和计算机之间的交互。它是语言学、计算机科学和人工智能领域的交叉。

如今,大部分数据被归类为非结构化数据,这意味着收集的数据没有像在 Microsoft Excel 中那样组织在表格中。因此,它更难分析,也不容易搜索,这就是为什么它直到最近几年才对组织有用。往往需要大量的时间来清理和组织数据到一个有用的数据框中,这对于很多人来说是一个枯燥的任务。如果这一信息被忽视,公司就没有利用他们所能获得的一切来取得成功。现在在就业市场上,越来越多的公司正在寻找专家来分析这些数据,因为他们希望利用这些宝贵的信息。我以前写过一篇类似的文章,讲的是如何收集和处理推文到亚马逊 S3 桶。

[## 如何通过云计算从 Twitter 中提取数据

通过使用 Python 和 Tweepy

medium.com](https://medium.com/analytics-vidhya/how-to-create-a-dataset-with-twitter-and-cloud-computing-fcd82837d313)

人工智能算法现在有助于从每天生成的大量非结构化数据中自动提取意义。公司使用 Hadoop 等大数据工具和软件从原始非结构化数据中准备、挖掘、集成、存储、跟踪、索引和报告业务见解。

我把 NLP 的主要应用总结如下:

  • 分类:根据内容对文档进行分类,这种技术用于电子邮箱中的垃圾邮件过滤器或分析产品评论。
  • 推荐:通过基于内容的算法,根据给定的信息选择最相关的文档。这项技术被谷歌、网飞、亚马逊用来根据你之前的搜索推荐一些东西。
  • 主题建模:通过解释模式来理解文本的含义,并识别每个个体背后的结构。

现在让我们看看我的项目

作为 WhatsApp 小组的一员,我可以导出数据并开始探索它。这个组是在 2015 年创建的,但由于 WhatsApp 数据的加密最近发生了变化,我只能从 2019 年 10 月开始拉数据。此外,为了让广大公众理解这篇文章,我不打算将我的代码粘贴到文章中。相反,你会看到用包 plotly 制作的很酷的图。如果你对代码感兴趣,请查看我在 GitHub 上的库。

请注意,WhatsApp 群组中的任何人都可以从对话中提取数据,在 messenger 上也可以这样做。请随意复制我的代码,并使用它来研究您的数据。

现在回到我的项目,从 Whatsapp 应用程序中提取数据后,我获得了一个文本文件,看起来就像这样:

文本文件—非结构化数据

正如我之前提到的,我不能使用这种格式的数据,这些数据是非结构化的,一团乱麻。为了将这些数据转换成包含列的数据框架,我对数据进行了标记。但是,什么是标记化呢?

标记化是对输入字符串的各部分进行划界和可能的分类的过程。

在一个文本文件中,每行代表一个注释,我确定了 4 个标记:

<2019–10–19>T3

经过进一步的清理,我能够生成下面的数据框。我不会深入讨论我如何获得数据帧的所有细节。相反,我建议查看我在上文和文章末尾链接的回购。

结构化数据帧

此外,为了确保所有这些信息的隐私,并且因为我希望我的朋友在这篇文章发表后仍然是我的朋友,我用一些著名的职业自行车运动员代替了我们的名字,因为群聊最初是由于我们对自行车和山地自行车的共同爱好而创建的。以下是该小组 17 位作者的名单:

克里斯·弗鲁姆、伊根·贝尔纳尔、阿尔贝托·康塔多、奈罗·金塔纳、罗曼·巴尔德、文森佐·尼巴里、彼得·萨根、伊曼纽尔·布赫曼、朱利安·阿拉菲利普、托尼·盖洛平、蒂博·皮诺、汤姆·杜穆林、法比奥·阿鲁、亚当·耶茨、沃伦·巴吉尔、沃特·范阿尔特、鲍克·莫勒姆。

群组中最活跃的用户

现在让我们开始研究数据。群聊包含 8,337 条消息、2,818 个表情符号和 229 个链接。对数据的第一个简单观察是检查谁在聊天中发送了最多的消息。下面是每个作者的邮件数量和字数的图表。

Vincenzo 是该组中发送消息最多的作者(1,470 条),其次是 Chris、Egan、Julian 和 Nairo,大约有 1,000 条消息。让我们看看尼巴利在环法自行车赛上是否会像在这个团体中一样活跃。

Jonny Kennaugh 在 Unsplash 上拍摄的照片

我们还可以看看谁发送了最多的表情符号,上面的图显示,文森佐·尼巴里在聊天中发送了最多的表情符号,其次是伊根、克里斯和彼得。前 5 名和之前剧情差不多。我注意到朱利安·阿拉菲利普发送的表情符号很少。

探索不同变量之间是否存在相关性的另一种方法是创建一个相关矩阵。基于此,变量之间没有强相关性。表情符号的数量和每个表情符号的字数比率(0.38)之间有相当的相关性。字母数和单词数之间有很强的相关性,这种相关性被认为是单词越多字母越多。

网址专员

为了完成描述部分,我查看了每个作者发送的 URL,你会注意到 Nairo 将大多数链接(118 个)发送到该组,接下来是 Julian (36 个)和 Vincenzo(28 个)。

关于前 5 名作者的更多统计数据

接下来,我总结了该组中每个用户的统计数据,长话短说,我只公布了该组中的前 5 名用户。

我还观察了一周中哪一天最活跃。根据下面的雷达图,周二、周五和周六是最忙的日子:这几天大约发送了 1400 条消息。

时间

雷达图—一周中每天的消息数量

现在让我们来看看通过时间发送的消息数量。在下图中,可以明显看出,自 2020 年 3 月左右以来,该群体明显比以前更加活跃(p 值:2.63e-06)。

我认为这种增长可能是由于法国在三月和五月之间的封锁:更多的空闲时间=更多的时间发送信息。

最活跃的一天是 4 月 27 日,这一天已经发送了 150 条消息。

你会说表情符号吗?

截至 2020 年 8 月,Unicode 标准中共有 3304 个表情符号。在我的 Whatsapp 群中,总共使用了 143 个独特的表情符号。下面的饼状图显示了该群体中表情符号的总使用比例:

使用表情符号的总比例

大约 50%的表情符号被分成 4 种类型:

😂: 脸上带着喜悦的泪水

😁:眉开眼笑的脸

😄:咧着嘴笑的脸带着微笑的眼睛

👍:竖起大拇指

尽管 WhatsApp 包含了 3304 个表情符号,但绝大多数作者只使用了 4 个表情符号。看起来这个群聊真的很有趣,因为大多数表情符号都有很多微笑和喜悦的泪水,这很有意义,因为我们一直在相互开玩笑。

作为一名训练有素的生物学家,我不禁注意到多样性指数是如何应用在这个场景中的。多样性指数是一种定量方法,反映了一个生态系统中有多少种类的物种,基于每个物种的丰度和物种的多样性。因此,我开始计算表情符号的丰富程度,也就是说我统计了群聊中每个作者使用的独特表情符号的数量。我们可以通过比较不同的生态系统来解释多样性指数。在这种情况下,每个作者就是一个生态系统。在前 5 名用户中,Vincenzo 是多样性最高的用户,Egan 是多样性最低的用户,尽管他正在发送大量表情符号!我们可以从建议 Egan 多样化他的表情符号开始。为了更深入地挖掘,我们来看看文森佐和伊根使用表情符号的比例:

文森佐·尼巴里 vs 伊根·伯纳尔

在前 5 名中,文森佐的多样性指数最高,伊根的多样性指数最低。文森佐 50%以上的时间使用 3 个表情符号,伊根 75%以上的时间使用一个表情符号。

云之语

单词云是文本数据的可视化表示,其中大小表示每个单词的频率,在本例中,是群聊。创建单词云的第一步是将所有评论合并成一个包含 335,093 个单词的长字符串。

WordCloud

英语中的“Oui”或“yes”用了 118 次,“moi”或“me”用了 214 次。我在这个云上看到一些和骑行有关的词:“vélo”、“Zwift”、“Garmin”、“vtt”、“strava”、“course”、“sortie”。令人惊讶的是,我没有看到关于饮料或食物的单词。“bière”或“beer”这个词用了 17 次,而“vin”或“wine”只用了 8 次。在冠状病毒时代,封锁或“禁闭”这个词已经被使用了 33 次。在做这个分析之前,我预计会看到更多不健康的习惯,但根据单词 cloud,这个群体相当健康,并且更加关注体育运动。

这个分析现在即将结束,如果你对代码感兴趣,可以通过我的 GitHub repo 访问。作为总结,在这篇文章中,我探讨了人们如何互相发短信的倾向,什么是最忙的日子,以及随着时间的推移趋势是什么。此外,我还可以进行一些有趣的分析,分析哪些作者发送的表情符号最多或最少,以及使用的表情符号的多样性如何。

我希望你喜欢阅读这篇文章,希望你学到了一些关于如何准备和探索 Whatsapp 数据的见解,希望你现在看到了 NLP 对企业的潜力,或者只是想了解你的朋友和他们的习惯。

为了进一步探索这些数据,我可以进行情感分析,试图找到作者之间的倾向。例如,我可以调查谁是最积极/消极的作者?或者,随着时间的推移,情绪在变化吗?

这个项目打开了我对数据科学的视野,我迫不及待地想继续探索 NLP 世界。例如,我读过 Sharon Lim 的一篇非常酷的文章,他在文章中应用了主题建模和朴素贝叶斯进行分类。在文章中,Sharon 能够找到最佳的主题数量,并确定各种主题类别和结构。

[## 利用自然语言处理释放文本分析的力量

主题建模的潜在狄利克雷分配和文本分类的朴素贝叶斯

medium.com](https://medium.com/towards-artificial-intelligence/unlock-the-power-of-text-analytics-with-natural-language-processing-2e6d83b35f99)

最后,如果你喜欢我的工作,你可以在 LinkedIn 上联系我。

让您的决策树模型随车移动

原文:https://towardsdatascience.com/get-your-decision-tree-model-moving-by-cart-82765d59ae09?source=collection_archive---------26-----------------------

Pixabay 上的 Alexas_Fotos 拍摄的照片

基尼杂质——另一种决策树节点划分标准

作为最流行的经典机器学习算法之一,决策树在可解释性方面比其他算法更直观。在我以前的文章中,我介绍了用于构建决策树模型的 ID3 和 C4.5 算法。

[## 出去锻炼还是不锻炼?让数据科学来决定

决策树机器学习算法简介

towardsdatascience.com](/go-out-for-exercise-or-not-let-data-science-decide-34f8f28ce7b4)

[## 不要像这样使用决策树

展示 ID3 中信息获取的局限性以及使用 C4.5 的优势

towardsdatascience.com](/do-not-use-decision-tree-like-this-369769d6104d)

在本文中,我将介绍另一种叫做 CART 的算法,用于构建决策树模型,这可能也是最常用的。顺便说一句,当你使用 Scikit-Learn 库作为决策树分类器时,这是默认的算法。

什么是 CART 算法?

683440Pixabay 上拍摄的照片

CART 算法是 C 分类AdR回归 T rees 的缩写。它是由 Breiman 等人在 1984 年发明的[1]。

它通常与 C4.5 非常相似,但具有以下主要特征:

  1. 与可能有多个分支的一般树不同,CART 使用二叉树,每个节点只有两个分支。
  2. CART 使用 Gini 杂质作为划分节点的标准,而不是信息增益。
  3. CART 支持数字目标变量,这使得它能够成为预测连续值的回归树。

本文将把重点放在 CART 作为分类树上。

基尼杂质

照片由奇莫诺Pixabay 上拍摄

就像 ID3 和 C4.5 算法依赖信息增益作为分割节点的标准一样,CART 算法使用另一个称为 Gini 的标准来分割节点。

如果你学过经济学,你一定熟悉基尼指数,它表明一个国家或任何其他人群内部的收入不平等或财富不平等[2]。

在 CART 算法中,出于类似的目的,直观地使用基尼系数。即基尼系数越大,意味着节点的杂质越大。类似于 ID3 和 C4.5 使用信息增益选择不确定性较大的节点,基尼系数会引导 CART 算法找到不确定性较大(即杂质)的节点,然后进行分裂。

基尼系数的公式比我们在其他两个决策树算法中使用的信息增益和信息增益比率相对简单。如下图所示。

  • p(Ck|t) 是节点 t 成为类别 Ck 的概率。
  • 节点 t 的基尼系数为 1 减去所有类别的概率之和。

不要被公式吓到。我们举个例子来演示一下。我保证不难理解。

下面的例子在我写的所有关于决策树的文章中都被使用过。

假设我们想通过使用“天气”特性进行分割来启动决策树。然后,我们需要计算其条件下的基尼系数。让我们关注天气属性和结果,如下表所示。

计算概率 p(Ck|t)是相当容易的。例如,如果我们考虑属性“天气=晴朗”,则总共 3 个样本中有 1 个“是”和 2 个“否”。因此,类别“是”的概率是 1/3,类别“否”的概率是 2/3。然后我们可以很容易地计算出基尼系数如下。

我们从上面 3 个等式中得到的直觉是

  • 当天气晴朗时,会有一些不确定性,因为我们可能会出去跑步,也可能不会。
  • 当天气多云时,我们肯定要出去跑步。完全没有不确定性(100%纯度)
  • 当天气下雨时,我们肯定不会出去跑步。也没有任何不确定性(100%纯度)

这些数字也反映了我们的直觉。天气晴朗的时候基尼系数是 0.444,因为不纯。当天气多云或下雨时,基尼系数为 0。因此,使用属性“天气=多云”和“天气=下雨”来分割节点没有任何意义,因为我们知道决策必须是全是或全否。

CART 算法如何选择根/下一个节点

cocoparisiennePixabay 上拍摄的照片

我们如何决定根节点,从而使用相同的逻辑来决定如何分割内部节点?这与使用所有可能的子节点的基尼系数的加权和一样简单。

由于 CART 算法是利用二叉树的 CART 算法,每次我们只需要计算两个节点的基尼系数的加权和。公式如下。

  • |t_left|和|t_right|分别是左边和右边节点的样本大小。
  • |T|是候选父节点 T 的样本大小

还是那句话,不要被公式吓到。让我们用同样的例子,天气特征。

如果我们使用天气作为根节点,有 3 种不同的情况:

  1. 除以“晴”和“不晴”,基尼系数= 0.476

2.除以“多云”和“不多云”,基尼系数= 0.229

3.除以“多雨”和“不多雨”,基尼系数= 0.343

同样的逻辑将应用于所有其他可能性,直到我们找到最大的基尼系数,这将是根节点。类似地,对于内部节点,应用相同的逻辑来确保每个分裂具有最大的基尼系数。

摘要

照片由 geraltPixabay 上拍摄

在本文中,我介绍了另一种决策树算法,称为 CART(分类和回归树)。它构造只有两个分支的二叉树。它还支持将连续数值作为目标。CART 最显著的特点是使用基尼系数作为划分节点的标准。

[## 通过我的推荐链接加入 Medium 克里斯托弗·陶

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@qiuyujx/membership)

如果你觉得我的文章有帮助,请考虑加入 Medium 会员来支持我和成千上万的其他作者!(点击上面的链接)

参考

[1] Breiman,Leo,等.分类和回归树.CRC 出版社,1984 年。

[2]基尼系数。维基百科。https://en.wikipedia.org/wiki/Gini_coefficient

我如何用 AWS 构建一个可伸缩的 Web Scraper

原文:https://towardsdatascience.com/get-your-own-data-building-a-scalable-web-scraper-with-aws-654feb9fdad7?source=collection_archive---------10-----------------------

我对完全托管的基于云的 Python scraper 的提议

我如何想象我的 AWS 控制台…(照片由帕特里克·grądysUnsplash 上拍摄)

去年年初,我在 Craigslist 上发现了一个疯狂的二手车交易。经过反复检查,证明这不是一个骗局(事实并非如此)。我很自然地直接去了《凯利蓝皮书》,以了解我的新车的“真正价值”——但这让我想到:

凯利蓝皮书是如何计算私人汽车价值的?我凭什么相信他们?

似乎他们必须使用的第一个资源是 Craigslist——因为这是最受欢迎的点对点二手车列表平台(直到最近,也是唯一的主要平台)。如果是这种情况,凯利蓝皮书必须以某种方式访问 Craigslist 的数据。然而,Craigslist 不提供 API,也不向公众开放他们的数据集(假设他们有)。这让我想到,也许像 KBB 这样的公司正在搜集他们的一些数据(这可能是一个安全的猜测)。

因此,我决定收集数据来建立我自己的凯利蓝皮书式的平台。为此,我需要构建一个满足以下要求的刮刀:

  1. 易于扩展和动态的刮板,以适应许多 Craigslist 城市,上市,和上市类型。
  2. 每天管理数百个作业的处理——交错并仔细安排,以避免 DDoS Craigslist 服务器(或被它们阻塞)。
  3. 监控每个作业,以便在出现任何运行时故障时立即通知我。
  4. 最后,CI/CD 用于管理所有相关服务的快速部署。

这是我的解决方案的高级示意图:

作者图片

本质上,我需要构建一个 ETL 管道来每天收集 Craigslist 数据,以便记录每个汽车列表的生命周期和事件(价格变化、除名)。本文重点介绍这些数据的提取过程。在接下来的几周里,我会写更多关于我如何转换/加载和处理数据的内容(稍后先看一些结果——继续阅读!).

免责声明:请理解这个项目只是为了研究而建。虽然它有能力在很短的时间内点击 Craigslist 上千个请求(或者让你的电脑崩溃),但我一直很小心地限制给定时间内的请求数量,通过战略性地间隔作业,以免垃圾邮件/DDoS Craigslist 服务器。如果你在 Craigslist(或任何这方面的网站),一定要阅读并遵守robots . txt

让我们开始吧…

虽然我不会像教程那样一步一步地讲解整个过程;我想给你一个刮刀本身如何工作的概念。

scraper 在 Docker 容器中运行——代码本身非常简单,你可以在这里找到整个项目。它是用 Python 构建的,并使用了 BeautifulSoup 库。

有几个环境变量被传递给 scraper。这些变量定义了每个作业的搜索参数。本质上,容器的生命周期遵循以下三个步骤:

  1. 向容器传递几个变量,主要是城市/搜索区域和车辆制造商。
  2. 容器根据给定的参数搜索 Craigslist,并从 HTML 生成结构化结果。
  3. 容器将这些结果以 CSV 格式发送给 S3。

流程和基础设施

这是最酷的部分…

现在,让我们详细回顾一下提取/调度流程。

  1. 每天,我的 AWS CloudWatch 事件规则触发 lambdas 为不同的州和汽车制造商分派刮擦工作。
  2. 调度程序将每个城市的任务提交给 AWS 批处理。
  3. AWS Batch 加速计算环境( ECS )并根据环境的配置运行作业(计算环境决定作业并发性——点击阅读更多关于 AWS Batch 的信息)。
  4. CloudWatch 在批处理发送状态更新时处理并通知故障。
  5. 在每个批处理作业结束时,scraper 将发送一个新生成的搜索结果 CSV 到我的 S3 桶,命名约定为:search type _ make _ city _ timestamp . CSV。我选择将“品牌”放在“城市”之前,因为品牌对车辆列表的价格和寿命更重要。

下面是刮擦过程的高级示意图:

作者图片

从图中可以看出,我用的是 CloudWatch,Lambda,Batch,S3。我还将 SNS 用于由“批处理-作业-监视器”触发的通知

以下是我选择服务的理由:

CloudWatch 拥有“规则”,其行为类似于 Cron 作业,可以将 JSON 有效负载传递给 lambda 函数。这使我能够提交多个带有 JSON 格式的作业参数的 CloudFormation 模板,以便根据预先确定的 Cron 表达式执行。

Lambda 对于较小的任务(分派和通知)来说非常棒,并且可以很容易地与几乎所有的亚马逊服务集成。

AWS 批次非常适合我的刮刀容器。我决定以每个城市为基础运行作业,这意味着在相对较短的时间内会有数千个请求。为了提高每项工作的速度,我决定在 python scraper 中对请求进行多线程处理。这意味着我需要一个允许长运行时间和高 I/O 速率的服务。由于这些条件,Lambda 是不可能的(并且 Lambda 不支持 Python 的多线程包)。我发现 AWS Batch 是完美的——我能够配置计算环境以满足我的需求(和预算),同时在按使用付费的服务中拥有易于维护的 Dockerized scraper。另一个主要的好处是,AWS Batch 使用 ECS 来运行作业,因此,每次处理新队列时,AWS Batch 都会启动新的 EC2 实例— 和新的 IP 地址(实质上是轮换 IP)。

S3… 好吧,S3 是一个快速又便宜的方法,可以把我的半结构化刮刀暂时存放在一个容易接近的位置。我确实必须考虑我的对象命名标准。如果不考虑命名标准,S3 桶可能会对成千上万的对象造成混乱 AWS SDK 不提供健壮的对象搜索功能。很快,我将把我的数据从 S3 迁移到一个结构化的关系数据库中。

对于我需要自己发送的少量文本通知来说,SNS 非常棒——并且很容易与 CloudWatch 和 Lambda 集成。

CI/CD 概述

这一部分对我来说很重要,主要是因为我的铲运机有许多移动部件 AWS 控制台可能很乏味。

对于提交触发的构建/部署,我使用了代码管道TravisCI 。这主要是为了我自己的实验。我发现 TravisCI 能够做我需要的一切,所以我将把我的代码管道项目转移到 TravisCI,每月节省额外的 1 美元😉

我使用了 无服务器框架 通过 TravisCI 的构建脚本来处理 Lambda 部署。

python scraper 被打包并部署到 Amazon 的 ECR 中,AWS Batch 根据需要引用/启动图像。

我承认,我对我的 Cron 事件规则采取了一种黑客式的方法:我编写了 CloudFormation 模板,将事件有效负载嵌入为 JSON。

转义的“jsonInput”有点混乱,但是我可以通过这些模板轻松地添加或删除作业。例如,如果我想添加另一个抓取作业,我只需添加带有新的“jsonInput”和“cronExpression”值的“group2a”。

我应该注意到“TemplateURL”路由到指向单个 Lambda 函数的事件规则 CloudFormation 模板,该函数被配置为接收“jsonInput”并相应地将作业分派给 AWS 批处理。

当需要更改时,模板被修改并提交给 Github。一旦 pull-request 被合并到我的主分支,TravisCI 就用最新的更改更新 CloudFormation 堆栈。这个过程让我可以非常简单地放大或缩小我的可伸缩刮刀。

现在整个事情

…这是我的整个解决方案—从 CI/CD 到文本提醒:

作者图片

敬请期待!

你想知道如何在这样一个美女身上得到一笔好交易(你不会相信它的价格)吗?或者你可能对项目本身更感兴趣…

1998 年奔驰 SLK 230(机械增压),50k 英里,硬顶敞篷车(一切工作完美)。是的,它是我的。(图片作者)

如上所述,我将很快写关于我的数据集的后处理。作为先睹为快,我对来自加利福尼亚-梅赛德斯-奔驰两个月的数据的样本数据集进行了一些分析(我现在有大约 6 个月的数据!).猜猜我发现了什么?

根据这个(小)数据集,我的 SLK 是 Craigslist 上所有梅赛德斯-奔驰房源中销售率最高的!

看看这个:

有一款 SLK,销售率约为 38%。作者创建的图表。

这是一些很酷的数据,对不对?

我很想听听你对这个解决方案的想法——剥猫皮的方法不止一种。在下面留下评论!

我们上 Linkedin 连线吧!

干杯!

—亚伦·兰利

使用 Python 获取您的 Spotify 流媒体历史记录

原文:https://towardsdatascience.com/get-your-spotify-streaming-history-with-python-d5a208bbcbd3?source=collection_archive---------8-----------------------

上面有美味的歌曲。

没有这些特征就不一样了。来源

这是我的第一个媒介故事!感谢任何反馈。

如果你像我一样是一个专注的 Spotifyer,通过查看你的流数据,你可以学到很多东西。你倾向于在冬天听悲伤的歌吗?恋爱时你的音乐喜好发生了什么变化?

幸运的是,Spotify 允许你请求下载你所有的流媒体历史记录在本教程中,我将向您展示如何提取这些数据,用美妙的歌曲特色为其调味,并将其组织成一个方便的 CSV 文件,您可以用自己喜欢的工具进行分析。

但是还有更多。到那时,你也将基本了解 Spotify API 如何工作,如何完成授权代码流,以及如何构建自己的 Spotify 应用。继续读下去!

但是如果你赶时间的话,完整的代码可以在我的 GitHub 获得。

特征,特征

Spotify 的音频特征是复杂的指标,旨在描述一首歌曲的个性和对听众的总体印象。以下是对每种方法的简要描述:

声学 —如何声学 舞蹈性 —不言自明 能量 —如何‘快、大、吵’ 乐器性 —人声较少, 活跃度越高 —录音中是否有听众 响度 —不言而喻 语速 价态越高

Spotify 还会测量每个曲目的时长、调、模式和拍号。你可以在 Spotify 的文档中了解更多关于功能的信息。

我们需要做的是

首先,我们从 Spotify 获取流媒体数据。由于不包含这些功能,我们从 Spotify API 请求它们。最后,我们将数据导出为我们喜欢的格式。

要求

这个任务的主要需求是 Spotipy 库。我们还将使用请求模块来处理 API。虽然不是必需的,但我还包含了 Pandas ,因为它使得保存和加载表格数据变得非常容易。

确保安装了必要的依赖项:

行动

获取数据

https://www.spotify.com/访问您的 Spotify 账户仪表盘。在隐私设置中,您会发现请求您的数据的选项。这需要一些耐心。Spotify 说需要 30 天,但通常要快得多。就我而言,我等了三天。

最终你会收到一封电子邮件,里面有你的 Spotify 数据,格式为. zip 文件。提取 MyData 文件夹,并将其复制到您的工作文件夹中。

获取流

我们的文件夹里有几个文件。让我们感兴趣的是这样的: StreamingHistory0.json 。您可能有一个或多个文件,这取决于您的流历史的大小。让我们打开文件。我的第一首歌是这样的:

不错的选择,对吧?

让我们编写一个 Python 函数,它将收集所有的 StreamingHistory 文件,提取 JSON 对象并将它们转换成 Python 字典。

就是这样。现在我们有了历史上所有曲目的时间戳列表。

成为 Spotify 开发者

Spotify 的数据下载中不包括歌曲功能。我们必须通过 Spotify API 请求它们。

访问 API 是免费的,但我们需要注册一个 Spotify 应用程序。别担心:只需要几分钟。在这里报名即可。

恭喜你:你正式成为 Spotify 开发者了!

转到您的新开发者仪表板并点击“创建应用”。不要担心细节。Spotify 将允许你创建虚拟应用,只要你承诺不将它们货币化。但你应该避免在名字中使用“Spotify ”,否则它可能会被屏蔽。

授权代码流

没人能简单地向我解释,所以我来了。一个应用程序可以访问 Spotify API,但前提是它必须获得至少一个用户的许可。因此,我们将使用该应用程序询问自己是否允许访问我们的用户的数据。

我们需要提供一个“重定向链接”,我们将用来收集用户的许可。在开发者仪表盘的应用面板中,点击“编辑设置”并在重定向 URIs 下添加一个链接。这不一定是真实的链接:如果你没有网站,你可以简单地使用http://localhost:7777/callback

你还需要你的应用程序的客户端 ID客户端密码。您可以在应用面板中的应用名称下找到它们。现在,您已经拥有了访问 Spotify API 所需的一切!

访问 Spotify API

现场救援。在这些字段中插入您刚刚收集的变量:

该函数将一个请求打包,该请求从您的应用程序(通过客户端 Id客户端机密识别)发送给用户(通过 Spotify 用户名识别)。

该请求有一个范围,它定义了您将要请求的权限。你可以在这里了解更多关于示波器的信息。

最后,你需要提供一个重定向 URI 。这必须与您在应用程序设置中列入白名单的项目相对应(见上一节)。

该函数返回一个令牌,它基本上是一个字符串,我们将使用它向 Spotify API 保证我们拥有用户授权。

一旦您使用正确的参数运行该函数,它将在您的 web 浏览器中打开一个授权面板。点击链接,使用您的 Spotify 凭据登录,您应该会看到如下内容:

现在您终于可以授权您的应用程序了。一旦你点击同意,你将被带到重定向 URI,这很可能是一个不存在的页面。只需复制地址并将其粘贴到 Python 控制台中。

就是这样。如果您在控制台中打印您的令牌变量,您应该会看到类似这样的内容:

访问令牌和刷新令牌

但是还有更多。如果您关闭代码并再次运行,您将不必提供授权,尽管内存中已经丢失了令牌变量。斯波蒂皮似乎记得你的令牌。这里发生了什么事?

如果您进入工作文件夹并启用隐藏文件可视化,您将看到 Spotipy 已经创建了一个名为的新文件。缓存您的用户名。**

如您所见,您的访问令牌有一个有效期,通常为一个小时。但是 Spotify 也给你提供了一个刷新令牌。当原始令牌过期时,您的应用程序可以使用刷新令牌来请求新令牌。

因此,每次运行脚本时调用 prompt_for_user_token 函数来加载令牌是很重要的。如果它找到一个缓存文件,它将使用它。如果您移动或删除缓存文件,您的令牌将会丢失,用户必须再次授权您。

获取身份证

Spotify 数据下载没有为我们提供曲目的id。我们需要这些 id 来获取特性。

我们可以通过使用 API 来搜索我们的轨道名称,获取第一个结果并提取 ID,从而获得 ID。Spotify 在文档中展示了如何构建这样的请求。

我想使用 Python 中的请求库来执行这个任务。由于我还不熟悉它,我在 https://curl.trillworks.com/使用脚本将 curl 命令转换成 Python 请求代码。以下是 Spotify 的 curl 命令示例:

*curl -X GET "https://api.spotify.com/v1/search?q=tania%20bowra&type=artist" -H "Authorization: Bearer {your access token}"*

这是我在 curlconverter 的帮助下写的函数:

让我们测试我们的功能:

很好。将 ID 粘贴到 Open Spotify 中,获得大量经典音乐。

获取特征

现在我们有了自己的 id,从 API 中获取特性就变得轻而易举了。

让我们在赛道上测试一下:

包装它

精彩!现在我们已经拥有了构建我们的流历史数据框架所需的一切。最简单的方法是创建一个字典列表:

(如果您的历史记录中有数千首歌曲,从 API 获取数据可能需要相当长的时间。我建议您首先在一个样本上测试您的代码。)

瞧。我们有一堆不错的流媒体工具,还有一些功能。现在,我们可以使用 Pandas 将字典列表转换成数据帧,并将其导出为 CSV 格式。

我们完成了!

如果你浏览我的 GitHub ,你会发现我的代码有点不同。当您重复 API 请求时,您可能会得到在第一次运行时被拒绝的响应。此外,将来您可能希望用新的一批流重新运行代码。但是 API 请求很慢,所以我添加了保存已经收集的 id 和特性的函数,允许您在不重复旧请求的情况下提出新请求。

下一步是什么?

一旦你有了所有特性的流媒体历史,你就可以拿出你的 Pandas/Matplotlib 技能来分析和绘制它们。你甚至可以应用机器学习来回答一些有趣的问题。

如果你有一个朋友和伙伴喜欢 Spotify,你可以用这个脚本向他们展示他们的历史。只需在您的代码中输入他们的用户名,向他们发送授权链接,并确保他们向您发送重定向 URI。

接下来,我将探讨如何分析我们刚刚收集的数据。同时,你可以查看其他关于这个主题的酷文章

我的第一个媒介故事到此结束。感谢阅读!

在亚马逊获得商业智能实习:我是如何做到的

原文:https://towardsdatascience.com/getting-a-business-intelligence-internship-at-amazon-how-i-did-it-a55c81b0da6b?source=collection_archive---------17-----------------------

办公时间

这个过程的不同阶段,这样你也能做到。

尼古拉斯·J·勒克莱尔在 Unsplash 上的照片

获得第一份工作经历是有史以来最难的事情。如果你在此之前做过一两次实习,事情会变得容易得多。这就是为什么我决定用间隔年的时间让自己获得一些实习经验。我的第一份实习是在巴黎的一家法国初创公司,当时我是一名全栈开发人员。就在刚才,我得到了我在亚马逊卢森堡的第二份实习,作为一名商业分析师。

我总是从外部寻找力量和信心,但它来自内心。它一直都在那里。—安娜·弗洛伊德

我知道没错。亚马逊。这是一次如此伟大而宝贵的经历。除了作为一家知名的科技公司,他们还会给实习生提供真实、有趣的工作,所以他们有具体的工作主题和产品。

在亚马逊或其他大型科技公司实习也不是不可能的。这个过程可能会很长,但如果这是你想要的,那就值得你花时间去做。

我 6 个月前开始申请

回到 2020 年 4 月,深陷新冠肺炎危机的我不得不找一份实习工作。所以我打开了亚马逊工作申请每一个符合我兴趣和能力的实习岗位。我没有错过一个,我不断地检查我的申请状态,并检查新开放的职位。

它可能看起来又长又整洁,而且完全令人沮丧。但这是值得的。亚马逊有大量的应用程序,所以可能他们还没有打开你的。直到他们知道。就那一次你确实被注意到了。这就是我的遭遇。

我参加了第一轮面试

我记不太清楚了,因为那是 6 个月前的事了,当时我从没想过我会真的得到实习机会。但是有三个主要步骤:

  • 30 分钟 RH 筛选,关于我的背景和性格的基本问题。
  • 1h 技术面试关于我的项目、经验和知识。这是由亚马逊领导原则和技术问题准备押韵。
  • 1h 技术面试,真的技术,关于机器学习和数据科学。这是一个带有基本问题的研究案例。

不幸的是,当时我对数据科学并不是很感兴趣,我在机器学习方面的知识也很贫乏。第三位面试官给了我一些关于阅读书籍和在线课程的建议。很明显,他告诉我他不能接受我的实习。

我学习了很多。

虽然我很失望,因为我觉得我的机会已经消失了,但我也对自己能够走这么远印象深刻。事实上,上一位面试官建议我如何进步并获得实习机会,这意味着我可以做到。

所以我一头扎进去,打开书,订阅课程,用额外的时间争取实习机会。这是他告诉我要学的东西,为了在亚马逊获得应用科学实习。

  • 【Coursera.org】:机器学习,作者吴恩达。斯坦福大学。如果你之前没有任何机器学习方面的知识,或者你想加强你的知识,这是从哪里开始。
  • coursera . org:深度学习专业化(5 门课程证书)。Deeplearning.ai.** 是更高级的课程,几乎涵盖了你开始职业生涯需要知道的一切。**
  • : 统计学习入门。特雷弗·哈斯蒂和艾尔。这本书很棒,可以让你更多地了解数据科学的数学方面。没有任何统计知识,感觉一个人对机器学习理解不了多少。

照片由陈茂三潭Unsplash 上拍摄

我向前看了。

最终,我需要找到一份实习工作。由于危机,我不能出国,所以我把注意力集中在巴黎的报价上。在那里,我找到了一份完整的开发者实习。获得一些新的经验,迈出在团队和公司工作的第一步,这很棒。

6 个月后我又试了一次

终于,我到了需要找第二份实习的时候了。我在想我想做什么,我想研究的课题。我知道我不想成为一名网络开发人员,尽管我喜欢这种经历,但我想尝试一些新的东西。

机会向我走来。

一天早上,我在 LinkedIn 上收到了一条私人信息,然后是一封来自亚马逊招聘人员的电子邮件,问我是否有兴趣在一个尚未确定的团队和地点进行商业智能实习。我想了想,尽管存在不确定性,但实习的目的吸引了我。我决定试一试。这一次,它可能会成功。

我又经历了一遍面试过程。

由于实习的主题不同,实习的过程也不同。我需要其他技能。事情是这样的。

  • 与招聘人员打 10 分钟电话,确认我对实习感兴趣,并向我解释接下来的步骤。
  • ****1 技术带回家测试。这是 3 个 SQL 问题。
  • ****2 个 30 分钟的技术访谈。同样,他们是基于亚马逊领导原则他们的问题准备

关于 SQL 带回家测试。

任何形式的实习都需要技术测试。有用来测试你的逻辑技能,你的效率,和你的能力,以提供适当的结果。这里有一个 SQL 测试是有意义的,因为我将不得不使用数据库。

这个测试是一个基本的 SQL 测试。我得到了一个大约有 5 个表的数据库,我必须回答 3 个带有查询的问题。它们的难度相同,但是测试了不同的 SQL 行为和功能。

这里唯一的准备方法是了解你的 SQL 基础知识(实际上不仅仅是基础知识)。参加一个课程,或者读一本书,练习一下。你需要掌握 SQL 函数和特性。

关于技术面试。

对于技术面试,亚马逊明确告诉你如何准备。你必须准备好将你的经验与他们的领导原则联系起来,并且准备好回答他们的问题。

如果招聘人员问你的问题并不总是在他们的问题清单上(这是最好的),所有的问题都非常相关,如果你准备好回答他们列出的所有问题,你应该能够正确回答。

招聘人员不是来骗你的,他们是真的对你和你的工作感兴趣。试着向他们展示你对自己的工作充满热情,一切都会进展顺利。

分析采访。

在两次 30 分钟的面试后,我思考了一下,发现了招聘者感兴趣的四大类。我把我被问到的问题分成了几类,这样你就可以知道会发生什么了。

关于自己

  • 你为什么对这个实习感兴趣?
  • 你认为你的实习会怎么样?
  • 在技术团队中工作,你会更舒服,还是与从事技术性较低主题的人一起工作更舒服?

经历

  • 你什么时候冒过险,犯过错误,或者失败过?你是如何回应的,你是如何从那次经历中成长的?
  • 告诉我你培养同事的一次经历:阻止他们犯错,帮助他们?
  • 告诉我你分析过的最大的课题。你是如何进行的?为什么?结果如何?

团队项目

  • 说说你作为工程师在团队中的角色?具体做了什么?
  • 你是如何在团队之间分配工作的?你是如何计划时间,组织你们之间的工作的?
  • 你从这个团队项目中学到了什么?

手法

  • 您必须处理的最大数据集是什么?你害怕处理那么多数据吗?
  • 习惯使用 SQL 和 Python 吗?
  • 你最习惯哪种编码语言?给我一些你做过的项目的例子。

现在呢?

技术面试后的第二天,我收到了一封电子邮件,提供了运输和物流团队的一个职位。考虑过后,权衡利弊,我接受了这个提议。现在我正处于入职流程中。不过不用担心,一旦到了,就顺其自然吧,一切都会按时发生的。

所以,如果这是你真正想要的,请不要放弃。努力工作。即使你没有马上看到结果,你的工作总会在以后得到回报。如果上个月有招聘人员联系我,那是因为我已经花了一些时间事先申请、参加考试、回答问题等。

当你觉得某样东西是为你而做的时候,得到它的最好方法是努力完成过程的每一步,并确保你检查了每一个要求。祝好运!

获得数据科学工作比以往任何时候都难

原文:https://towardsdatascience.com/getting-a-data-science-job-is-harder-than-ever-fb796aae1922?source=collection_archive---------6-----------------------

如何利用找工作的困难来为自己谋利

马丁·佩希在 Unsplash 上的照片

介绍

在写这篇文章的时候,我正在寻找一份新的工作,作为一名数据科学家,因为我和前一家公司的新冠肺炎通信有困难。

这一次,我注意到事情似乎比我上次上市时要困难得多,但我没有利用这些挑战来延长我们成为数据科学家的梦想,或在最糟糕的情况下结束这些梦想,而是努力更好地理解这些挑战,以便我可以提出一些解决方案,使它们最有利于我,现在也有利于你!

古怪的工作要求

这似乎是我与数据科学求职者进行的大多数讨论中的一个主题

没人觉得自己有资格了。

许多数据科学职位描述没有传达广告中角色的实际要求。

这种情况的一个主要影响是,有抱负的数据科学家根据工作描述优先考虑他们的个人和技术技能,这可能会误导对履行角色的要求。另一个问题是招聘人员会收到大量不符合要求的申请。

根据 Jeremie Harris 的一篇精彩文章,标题为 数据科学职位发布的问题 有很多原因可以解释为什么一份工作描述看起来难以理解,这取决于你来辨别你所在的职位属于哪一类:

  • 解决问题的方法很多,所以很难把范围缩小到一个工作描述
  • 新的数据科学团队可能会鼓励人们成为万事通,这将转化为工作描述
  • 公司缺乏经验来了解他们有什么问题,以及能够解决这些问题的人应该具备什么能力
  • 由招聘人员撰写

解决方案

虽然这需要你有一定的洞察力,但重要的是要确定奇怪的工作描述的潜在原因,因为一些场景可能对你作为数据科学家的成长有害,例如成为一名万事通。

克服这一挑战的一个很好的方法是承认职位描述只是公司的愿望清单,他们想雇用他们认为有能力解决他们实际存在的问题的人。

关于这一点,一定要展示你的能力,让别人(公司)觉得你有能力应对他们的挑战。此外,如果你满足了任何职位描述中至少 50%的要求,那么你很有可能是合格的,并且绝对应该尝试去应聘这个职位——如果你 100%满足了职位描述,那么你很有可能资历过高。

数据科学变得越来越商业化

能够旋转 Jupyter 笔记本并进行一些可视化,然后建立一个模型,这在过去是可行的,但在我看来,这已经不足以引起你的注意。

Jupyter 笔记本电脑非常适合进行实验,但是当你进入现实世界时,我们就会越过实验阶段。我相信,每个数据科学家都应该知道如何组装 Jupyter 笔记本,但随着数据科学变得越来越生产化,可以编写生产级代码的数据科学家会获得加分,因为这样可以节省成本和时间。

以下是每个数据科学家都应该知道如何编写生产级代码的 3 个理由:

  • 在从数据科学家到工程师的翻译过程中,有些东西可能会丢失
  • 消除流程中的延迟
  • 一石二鸟,因为一个人可以做两个人的工作——让你更有价值

解决方案

虽然有争议,但我相信当涉及到面向数据科学应用的产品时,数据科学家和软件工程师的技能正在趋同,因此更多的数据科学家应该学习软件工程最佳实践。

[## 数据科学家应该知道软件工程的最佳实践

成为不可或缺的数据科学家

towardsdatascience.com](/data-scientist-should-know-software-engineering-best-practices-f964ec44cada)

鉴于你已经知道如何编写生产级代码,你可能想看看肖恩·惠勒的文章标题为 “生产化”数据科学意味着什么? 异常总结了数据科学生产的代码级最佳实践之外的系统应用焦点——至少可以说这是一篇非常有趣的文章。

“某样东西‘投入生产’意味着它是从企业到客户的管道的一部分。[……]在数据科学中,如果某样东西在生产中,它就在将信息放在消费它的地方的路上。”

竞争

数据科学是这个星球上发展最快的新兴技术之一,成千上万的人蜂拥而至更新他们的技能,以尝试成为一名数据科学家。如果你不相信我,自 Coursera 开设吴恩达机器学习课程(这是数据科学的重要组成部分)以来,已经有超过 350 万人注册了该课程。

这是 21 世纪最性感的工作。

现在越来越多的人试图进入这个领域,因此工作竞争非常激烈。但是,这不一定要成为决定不找工作的理由!

解决方案

是的,我们应该做得更多来脱颖而出,但是根据我最近在 LinkedIn 上做的一项民意调查,这并不一定意味着拥有最漂亮的简历。

来源: Kurtis Pykes 领英

当然,拥有一个优秀的投资组合是脱颖而出的一个很好的方式,然而,在增加你获得机会的机会方面,似乎是不可战胜的是接触招聘经理或你申请的职位中的高级职位的数据科学家。

LinkedIn 让找到在特定公司工作的人变得如此容易,所以在申请工作时,它应该成为工作申请过程的一部分。

结论

在数据科学领域很难找到工作的事实永远不应该成为你没有工作的理由。任何工作本身都会面临许多挑战,获得这份工作只是一个资格阶段,看看雇主是否相信你有能力面对挑战,以及你是否相信雇主是你希望加入的团队。永远寻求提升自己,不要等着准备好申请,因为你可能永远都不会觉得自己准备好了,不要害怕被拒绝或拒绝与你的目标不一致的公司。

让我们在 LinkedIn 上继续讨论…

[## Kurtis Pykes -人工智能作家-走向数据科学| LinkedIn

在世界上最大的职业社区 LinkedIn 上查看 Kurtis Pykes 的个人资料。Kurtis 有一个工作列在他们的…

www.linkedin.com](https://www.linkedin.com/in/kurtispykes/)

获得一份机器学习工程学士学位的工作

原文:https://towardsdatascience.com/getting-a-machine-learning-engineering-job-with-a-bachelors-degree-ec45f3575b9b?source=collection_archive---------57-----------------------

Unsplash 上发现的图像。com

我是一名机器学习工程师,是人工智能语音识别初创公司的一部分。现在,对于机器学习工程师来说,有大量不同的工作描述,所以让我们定义一下我是做什么的。

我是我们小型创业公司深度学习团队的一员。为了强调我们有多小,我是整个创业公司的第二个机器学习工程师和第三个雇员。我的工作是研究和开发各种深度学习方法,这需要实施和训练新的神经网络架构,在大型计算集群上扩展我们的 ml 训练基础设施,并找出如何最佳地优化生产模型。作为一个小团队,我很自豪地说,我们已经构建了世界上性能最好的语音识别服务之一,击败了谷歌、AWS 和微软等科技巨头!

我从经验中知道,看任何机器学习的招聘信息都会令人沮丧。遇到要求硕士或博士等高层次学位的职位是很常见的。有些帖子甚至要求一个框架的经验比这个框架存在的时间还要长。

我有计算机科学的学士学位。我和拥有非相关计算机科学领域学位的人一起工作过。我和一些连学位都没有,还在专业做机器学习的人合作过。

在这篇文章中,我想谈谈我为找一份机器学习的工作所采取的步骤,以及它对你来说是如何可能的。现在我知道我的道路不是唯一的道路,但它是一条适合我的道路,我希望向你展示一条通往你想要的职业生涯的可行之路。

从对基本面的高度理解开始

我几乎是从有史以来最伟大的知识库--互联网上学习机器学习的。很多资源会建议你先从基础开始,比如统计和概率、线性代数和微积分。他们说你需要在开始之前深刻理解那些数学科目。这是因为这是一个博士持有人最有可能进入机器学习的方式。

但我是一名创造者,通过构建项目学习效果最好,所以我选择了一条可以让我最快开始创作的道路,那就是对 ML 理论有一个非常简要和高层次的理解。对 ml 理论有一个简要和高层次的理解就像有一个指南针来指导你解决 ML 问题。你可以通过阅读一堆与 ml 相关的博客文章、快速浏览一本综合书籍或参加在线课程来达到这种理解水平。

开始建造吧

第二步是我学到最多的地方。开始制造垃圾吧。任何事。做什么项目都不用想太多。当你开始自己动手建造时,你会遇到各种各样的问题。你的 ml 算法不行,你的数据乱七八糟,你连一个简单的 python 库都无法正确安装。这是你在实际工作中会遇到的事情。

当这种情况发生时,不要放弃,使用互联网,寻求帮助,解决你和你的目标之间的问题。当你被迫深入挖掘,让东西发挥作用时,那就是你真正开始理解直觉的时候。你将知道什么是张量,或者正确的损失函数如何依赖于你的模型目标,或者为什么数据的基本统计和分布很重要。

我建议继续建设,从一个项目跳到另一个项目。一个项目建议是选择一个你感兴趣的人工智能领域,例如,deep fakes。通读一些论文,然后尝试实现它们。作为一名机器学习工程师,我花了很多时间阅读和实现不同的论文,因此技能集至关重要。

但是说实话,你已经完成的任何项目在你的投资组合中都是不错的,因为这是你在专业工作中会接触到的东西。目标是获得一些实际的实施经验,而不需要大量的手工操作,同时也形成一个体面的投资组合来炫耀。

如果你想加入一个社区来展示你的项目,提出问题,分享知识,或者只是一般的互相帮助,加入我的不和谐频道 人工智能黑客

接触创业公司

第三步,说服一家公司给你一个机会。对某些人来说,这可能是你旅途中最艰难的部分,但也不尽然。我说服了我以前工作过的一家初创公司给我一个实习机会。我被许多人忽视,但我很自信。为了获得我在机器学习领域的第一个实习机会,我发出了多封电子邮件,让他们知道如果他们愿意,我有信心为他们提供价值。

不要发太多垃圾邮件,那样会让人讨厌,所以在找工作时要考虑周到。他们最终雇用了我,因为我就像一只友好的蜜蜂在他们的空间附近嗡嗡叫,提醒他们嘿,如果你让我,我可以给你做一些非常甜的蜂蜜。

这一部分并不容易,甚至会比到达这里的学习之旅更加令人沮丧。充分利用大数定律。走出去,向各种各样的公司推销自己。

如果你坚持不懈,就会有回报。

交付!

如果你获得了第一份工作,现在你需要去实现它!你已经从自己的项目中获得了大量解决 ml 问题的技巧,你只需要在为一家公司工作时运用同样的原则和技巧。

唯一的区别是你现在有公司资源。这意味着更多的计算、更多的数据和一个让你负责的老板。这是你学习机器学习或大规模进行机器学习的实用性的地方。当你有公司资源的时候。你将开始在 ML 的真正力量上建立直觉。您还将学习如何在现实世界的约束下构建可用的系统。例如,构建一个需要在移动设备上实时运行的模型。

机器学习专家

在你的第一份工作之后,无论是实习还是全职,你现在都有了 ML 工程师的职业经验。现在如果你选择开始申请其他工作,你会更有信心。你会成为一个非常抢手的人,可能比拥有博士学位的人有更多的行业经验。

包裹

这是我走上尖端 ML 的道路。它对我有效,我相信如果这是你的选择,这条路也会对你有效。归根结底,不管你有没有学士学位、硕士学位,或者根本没有学位,ML 领域都是部分艺术部分科学。

科学是理论,艺术是将理论付诸实践。如果你能在 ml 中建立理论和艺术的能力,即使你有更高的学位也没关系。无论如何,许多公司都不再需要学位了。如果你生活在一个前所未有的获取知识的世界,那么你能做的就是一切,有收据为证。

🥇注册我的 电子邮件简讯 ,了解最新文章和视频!

✍🏽想要更多内容?查看我的博客https://www.michaelphi.com

📺喜欢看基于项目的视频?看看我的 Youtube

使用这个 Python 脚本获取 Amazon 价格下降警报

原文:https://towardsdatascience.com/getting-amazon-price-drop-alert-using-this-python-script-616a98bcba6b?source=collection_archive---------39-----------------------

刮亚马逊获得降价预警!

格伦·卡斯滕斯·彼得斯——Unsplash的照片

Python 做了很多奇妙的事情。而且,这种美丽的语言几乎没有做不到的事情。当涉及到数据分析、web 抓取或任务自动化时,大量的库使得这种语言一枝独秀。

试想一下,你想买一部新 iPhone。你厌倦了一遍又一遍地查看亚马逊网站。但是,它的价格没有下降,你总是失望。

如果,有一个自动价格检查器,会给你一个电子邮件提醒,如果有价格下降。令人兴奋,不是吗?让我们通过编写一个 Python 脚本来做同样的事情。

库配料

import smtplib
import time
import requests as rq
from bs4 import BeautifulSoup

主要有三个库可以为我们完成这项工作。Requests 库将与 HTTP 服务器通信,Beautiful Soup 将与网页通信并提取网页元素,smtplib 将向您发送电子邮件警报。

site = "https://www.amazon.in/Apple-iPhone-11-64GB-Green/dp/B07XVKBY68/ref=sr_1_7?keywords=iphone+11&qid=1573668357&sr=8-7"header = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36'}

首先,我已经请求了亚马逊 iPhone 网页的网络服务器。然后,我创建了一个 soup 对象来解析网页。我们只想要产品的价格。所以,使用“选择”方法,我们可以得到产品的价格。

def get_price():
    html = rq.get(site, headers=header).text
    soup = BeautifulSoup(html, 'html.parser')
    price = [i.get_text() for i in
             soup.find_all('span', {'class': 'a-size-medium a-color-price priceBlockBuyingPriceString'})]

    final_price = ''.join(price)[2:8]
    final_price = int(final_price.replace(',', ''))

    if final_price < 64900:
        send_email()

现在,每当“新价”变得小于“刮价”时。必须向用户发送一封关于价格下降的电子邮件。

我们将使用 smtplib 库向用户发送电子邮件。首先,我们将创建一个 SMTP 对象来与域的 SMTP 服务器通信。

一旦一切都完成并设置好,我们就可以登录我们的电子邮件帐户了。然后,将电子邮件发送给收件人。

def send_email():
    server = smtplib.SMTP('smtp.gmail.com', 587)
    server.ehlo()
    server.starttls()
    server.ehlo()

    server.login('Your email address', 'Application-specific password')

    subject = "Price fell down"
    body = "Check this link: https://www.amazon.in/Apple-iPhone-11-64GB-Green/dp/B07XVKBY68/ref=sr_1_7?keywords=iphone+11&qid=1573668357&sr=8-7"
    msg = f"Subject:{subject}\n\n{body}"

    server.sendmail('Sender's email', 'Recipient email', msg)

    print("Hey, email has been sent!")
    server.quit()

注意:smtplib 中的参数可能会更改。SMTP()取决于域的 SMTP 服务器。如果您有 Gmail 帐户,您必须为您的电子邮件地址生成特定于应用程序的密码。否则,当您的程序试图登录时,您将得到一个特定于应用程序的需要密码的错误消息。

while True:
    get_price()
    time.sleep(60)

这 40-50 行代码将为您完成这项工作。下一次,你不必一次又一次地查看网站上的价格下降。为其他电子商务网站制作这样的程序,节省您的时间和精力。

有关讨论和疑问,请通过 Linkedin 联系我!

Shell + 5 常用命令入门

原文:https://towardsdatascience.com/getting-comfortable-with-shell-5-common-commands-to-know-dbfa3aeb47c5?source=collection_archive---------46-----------------------

面向初学者的 Shell 介绍

Goran IvosUnsplash 上的照片

唱空壳可能会令人生畏。喜欢拥有漂亮用户界面的工具是可以理解的。在我们看 shell 之前,shell 到底是什么?

定义外壳

让我们简单点,从我们如何使用电脑开始。把你的电脑想象成一个等待指令的机器人。对于您的大多数需求,您使用应用程序让计算机执行操作。例如,现在你正在使用一个互联网浏览器应用程序(比如谷歌 Chrome)来阅读这篇文章(除非你使用的是中型移动应用程序,我绝对推荐下载)。应用程序是你与计算机交流的方法。换句话说,我们不会对着电脑说话,口头告诉它“打开互联网浏览器,进入 Medium。”我们让应用程序来做这件事。应用程序扮演着重要的角色——它们将我们想要做的事情翻译成计算机可以理解的指令。不同的应用服务于不同的角色。谷歌 Chrome 用于浏览互联网,微软 Word 用于键入文章,Finder/File Explorer 用于访问文件。

Shell 是我们与计算机交流并使其执行动作的直接方式。用专业术语来说,它是一种命令解释程序和编程语言。不用通过 Finder 之类的应用程序来查看你的文档,你可以使用 shell 直接指示电脑显示你的文档。这种与计算机直接交流的渠道给了我们更多的权力去控制我们想要计算机做的事情。

看贝壳

现在回到我们关于壳牌令人生畏的观点。让我们看一个例子。

在 Finder vs. Shell 上删除文件

假设您想要删除一个名为myFile的文件。在 Finder(或 PC 的文件资源管理器)上这样做既简单又直观。你进入 Finder,找到myFile,右键点击文件,选择移动到垃圾桶/删除。简单。

使用 Finder 删除文件

当使用命令行时,它可能看起来更困难和可怕,尤其是对于第一次使用的用户。在 Mac 上,打开“终端”(按 command 和空格键,键入 Terminal,然后按 Enter)。要删除myFile,你可以输入代码进入你的文档,然后输入代码查看你的文档以确保myFile在那里,最后用更多的代码删除myFile。见下文。

使用终端删除文件

如果你以前从未打开过命令行界面(命令行界面是你输入 shell 命令的程序 Mac 上的终端或 Windows 上的命令提示符),你可能对上面的 gif 很感兴趣。或者受到恐吓。或者两者都有。以下是用户喜欢避免 shell 的三个原因:

  • 你需要知道命令。在 Finder 上你可以用鼠标导航,但是命令行界面只接受通过键盘输入的文本。这需要记忆必要的命令。在上面的例子中,rm是删除文件的命令(rm 是 remove 的缩写)。
  • 更容易搞砸。使用 shell 可以让您更好地控制任务。所以害怕输入错误的文本,害怕做错事,比如删除一堆文件,是可以理解的。
  • 有好用的应用 (Finder/File Explorer,FileZilla 等。)

您可能已经被说服避免使用命令行界面。但是壳牌证明了它的强大。

为什么要用 Shell?

大多数开发人员角色都需要了解 Shell

如果您正在从事任何涉及编码的工作(软件开发人员、数据工程师、数据科学家等),您可能会在职业生涯的某个阶段使用 shell。熟悉使用 shell 将提高您的工作效率,并向您的团队展示您的经验。

对于许多开发人员工作来说,如果一个候选人不知道如何使用 shell,那么得出他们没有太多经验的结论是合理的。作为一名数据工程师/科学家,我每天都需要使用 shell。

Shell 允许您自动化重复的任务

您可以在命令行上完成许多任务,而使用 Finder 等标准应用程序则不那么容易。假设你正在研究加拿大的新冠肺炎病例。要获得每日更新病例数的 CSV 文件,您需要访问加拿大公共卫生网站并下载 CSV 文件。如果文件每天下午 6 点更新,那么您需要每天获取更新的文件。这意味着每天下午 6 点以后,你需要去网站下载文件。

从加拿大公共卫生部下载新冠肺炎病例的 CSV 文件

将这与在 Shell 中下载文件进行比较。你所需要做的就是打开终端,并键入以下内容:

curl -O [https://health-infobase.canada.ca/src/data/covidLive/covid19.csv](https://health-infobase.canada.ca/src/data/covidLive/covid19.csv)

让我们分解代码。curl是从链接下载文件的命令(curl 是 C lient URL 的简称)。-O是一个可选的标志(我们将很快探索这个标志),它告诉计算机我们想要以原始名称保存文件(O 代表原始)。最后我们传递下载链接。总而言之,我们告诉计算机在给定的链接下载文件,并以其原始名称 covid19.csv 保存文件。

使用 Shell 下载文件链接

真快!无需打开互联网浏览器,转到链接,然后滚动到下载按钮。只需键入一行,就大功告成了。你可能会想,从网站上下载文件真的没什么大不了的。但是,如果您的研究需要您每天下载文件,您可以使用编写一个简单的 shell 脚本(只需一次)来自动完成这项日常任务。因此,每天下午 6:05(或者我们在脚本中指定的任何时间),新的每日文件都在您的下载文件夹中。这已经为你节省了几分钟的时间。现在想象一下,如果您每天需要下载多个文件,您将节省多少时间。

使用 shell 还有许多额外的好处。但是我们先来探究一下 shell,简单了解一下如何使用。

Shell 命令快速介绍

Shell 命令的使用方式如下:

command [-flag] [parameter]
  • 命令是您想要采取的操作。例如,ls命令的意思是列出一个文件夹的内容。我们将很快回到ls
  • [-flag]是您可以指定的可选详细信息。请注意,您实际上不需要键入方括号。方括号表示这部分代码是可选的。例如,默认情况下,ls命令不会列出以点号开头的文件。你的探测器也一样。要列出这些文件,键入ls -a (-a 表示列出 a ll 文件)。

  • [parameter]是要对其执行命令或操作的实体(路径/文件/链接)。注意方括号,意味着参数部分是可选的。对于ls,默认情况下,它会列出你所在文件夹的内容。你可以通过阅读%符号前的文字来判断你在哪个文件夹。在这种情况下,我们在文档中。如果要列出不同文件夹的内容,需要将文件夹名作为参数传递。假设我们的文档中有一个名为“StayPositive”的文件夹。要查看 StayPositive 文件夹中的内容,请将 StayPositive 作为参数:ls StayPositive

保持乐观的 5 个理由:)

需要知道的 5 个命令

你不需要掌握使用命令行界面。如果你试图学习它,你会不知所措。另外,如果您不经常使用命令,您很可能会忘记它们。这里有五个您应该知道的经常使用的 shell 命令。

ls(列表)

List 的缩写,ls是列出一个目录的命令。如果你输入ls并按下回车键,你会得到一个存储在你所在文件夹中的文件列表。

光盘(更改目录)

cd命令用来改变你正在查看的目录。这就像在 Finder 中用鼠标点击目录/文件夹来查看其内容一样。例如,cd Documents将带您到您的文档目录。使用前面的命令,如果您键入ls,您可以列出您的文档中的内容。

cd 和 ls

手动(手动)

每当你不知道如何使用一个命令,或者忘记传递哪个标志时,使用manman将显示你作为参数传递的命令的帮助手册。这里我们用man来列出如何使用ls。请注意,您可以使用鼠标或按空格键来滚动手册。每按一次space,页面就会向下滚动。当您准备退出手册时,按q退出。

rm (删除文件)

rm用于删除一个文件。需要注意的是rm将会完全删除文件,而不是将它移动到垃圾箱。要使用rm,包括文件名作为参数。所以要删除我的文件,输入rm myFile

mkdir (制作目录)

mkdir将制作一个目录/文件夹。将目录名作为参数传递。要创建 myFolder,请键入mkdir myFolder

学习 Shell 的后续步骤

虽然这篇文章向您介绍了 shell 和常见命令,但我建议您参加一个关于 shell 的入门课程,以便更好地理解。网上可以找到一堆。谷歌一下“学壳”就行了。我最喜欢的两个 shell 课程是 DataCamp 的—Shell 简介使用 Shell 进行数据处理。注意,这些课程只有第一章是免费的。我和 DataCamp 没有任何关系,我只是从他们的互动练习中受益匪浅。

当你遇到一个你要执行的任务并想自动完成它时,你的学习成果就会显现出来。一定要在 google 上搜索如何使用 shell 自动完成这项任务。很可能有人已经问过同样的问题并得到了答案。你将开始自动化你从来不知道的任务,这些任务是如此容易自动化。下次再见,学习愉快!

更有效地利用谷歌搜索查找数据

原文:https://towardsdatascience.com/getting-datasets-for-data-analysis-tasks-advanced-google-search-b1c01f9cc324?source=collection_archive---------39-----------------------

作者图片

“数据!数据!数据!”他不耐烦地喊道。"没有粘土,我无法制砖。"

《铜榉树历险记》中的夏洛克·福尔摩斯,亚瑟·柯南·道尔爵士

在数据科学过程中,数据的重要性怎么强调都不为过。数据分析任务的结果代表了输入其中的数据类型。但是,有时候获取数据本身也是一大痛点。最近,我用免费工具做了一个名为 数据新闻和可视化的短期课程,通过这个课程分享了一些很棒的资源。我将通过一系列文章来分享一些有价值的技巧。在这些文章中,我将试图强调一些你可以在互联网上免费找到数据的方法,然后用它来创造一些有意义的东西。

这篇文章是寻找好数据集的完整系列文章的一部分。以下是该系列中包含的所有文章:

第 1 部分 : 为数据分析任务获取数据集——高级谷歌搜索

第 2 部分 : 为数据分析任务寻找数据集的有用站点

第三部分 : 为深度学习项目创建定制图像数据集

第四部分 : 毫不费力地将 HTML 表格导入谷歌表单

第 5 部分 : 使用 Camelot,从 pdf 中提取表格数据变得很容易。

第六部分 : 从 XML 文件中提取信息到熊猫数据框架

第 7 部分 : 5 个真实世界的数据集,用于磨练您的探索性数据分析技能

高级谷歌搜索

让我们从高级谷歌搜索开始,这是访问公开可用数据集的最常见方式之一。只需在搜索栏中键入所需数据集的名称,我们就可以访问大量的资源。然而,这里有一个简单的技巧,可以在很大程度上简化这个过程,并帮助您在互联网上找到特定类型的文件。

1.使用要下载的文件的文件名和扩展名

假设我们手头有一项任务,要查找 CSV 格式的医疗保健相关数据。CSV 文件表示逗号分隔值文件,允许以表格形式保存数据。要获取此类文件,请进入谷歌搜索栏并键入以下内容:

filetype < the extension of the file to be downloaded>: <category of data> data

作者图片

谷歌将列出与搜索结果最匹配的链接。大多数情况下,这将是指向网站上特定文件的直接链接,这些文件可以下载到本地系统上,供以后分析。

2.使用文件名、扩展名和站点名称

如果你想进一步缩小搜索范围,这个选项会派上用场。提到文件名就会指向很多文件。但是,如果您想查找特定网站的数据,也可以在搜索栏中提及,如下所示:

filetype < the extension of the file to be downloaded> : site <website> <category of data> filetype xlsx: who.int health

作者图片

现在所有的结果都只与世卫组织有关,这有助于大大缩小搜索结果的范围。

与搜索命令兼容的文件

与搜索命令兼容的文件有哪些种类?可以通过主页上的设置轻松访问这些信息,如下所示:

  • 点击Settings > Advanced Search
  • 向下滚动到file type选项,寻找可用的类型。您会看到有许多选项,包括 pdf 和 ppt 文件类型。

作者图片

结论

在本文中,我们研究了通过标准的 google 搜索更快更有效地找到我们想要的数据集的方法。我们研究了仅仅添加一个文件扩展名和一个网站名称如何帮助更有效地过滤结果。当我们知道我们在寻找什么样的数据时,这些技术会很方便。

最初发表于【parulpandey.com】

通过 Streamlit 获得能力:为数据科学家创建和部署 web 应用程序

原文:https://towardsdatascience.com/getting-empowered-with-streamlit-creating-and-deploying-web-app-for-data-scientists-e575e1204a3?source=collection_archive---------53-----------------------

如何开始

Unsplash 上由halance拍摄的照片

无论是新手还是经验丰富的数据科学家,我敢打赌,在某个时候,您可能会想到超越本地 machine & Jupyter 笔记本,将您的数据科学项目发布到野外。

那么是什么阻碍了你呢?

人们普遍认为数据科学家是无所不知的独角兽——从 HTML、CSS、Javascript 到各种软件工程工具和框架。但我们知道事实并非如此。仅仅因为你擅长为数据科学问题编写代码,不一定你也会有 web 开发和软件工程技能。将代码投入生产需要完全不同的技能,你可能有也可能没有。

现在在这条生产流水线上有了一条捷径。你可以成为一名伟大的数据科学家,并且仍然能够部署你的项目,而不需要具备 web 开发和软件工程技能。

Streamlit 为您带来。

什么是 Streamlit?

" Streamlit 的开源应用框架是数据科学家和机器学习工程师在几个小时内创建漂亮、高性能应用的最简单方法!全是纯 Python。全部免费”——这解释了你需要知道的关于定义的一切。

在所有这些好东西的背景下,我想提前警告你——Streamlit 是为 Pythonistas 准备的!不幸的是,如果您对 R 或另一种编程语言感兴趣,除了将几个项目翻译成 Python 并探索 Streamlit 及其功能之外,您什么也做不了。

为什么说 Streamlit 是革命性的?

在公共话语中,我们经常听到诸如赋权、赋权于人等流行词汇。我认为描述 Streamlit 对数据科学领域的贡献的最简单的方式是,它真正赋予了所有应用领域的数据科学家力量。

我已经说过了,但如果还不够清楚的话——你不必是 web 开发或软件工程方面的专家,Streamlit 让你只需付出一点点努力,就能把你的项目变成一个专业外观的应用程序。我几乎可以保证,即使你以前从未听说过 Streamlit,你仍然可以在接下来的一两天内创建你的第一个 web 应用。试一试吧!

如何开始

首先,除了streamlit包本身,你完全不需要任何东西来开始构建第一个应用。将包导入到您的 Python 环境中,您就可以开始了!

以下是我对你从绝对起点开始的建议:

  • 首先,查看一些其他人制作的示例项目,以便您了解 Streamlit 的功能。例子: COVID 数据跟踪器文本分类
  • 观看 Streamlit 团队发布的 4 个 YouTube 视频:简介安装搭建 app用例
  • 查看 Streamlit 的欢迎页面了解如何安装软件包。
  • 通读 API 参考页面(将该页面标记为书签,因为您会经常回到该页面)。
  • 启动您的 Python 环境,开始您自己的项目。不要从一个复杂的项目开始,而是做一些非常简单的事情。你所在领域的探索性数据分析的 app 怎么样?

总之,我要再次强调的是,Streamlit 的真正贡献是它能够让数据科学家做一些事情,如开发和部署应用程序,这些工作传统上是由组织中不同类型的专家完成的。如果你已经在用 Python 做你的项目了,这只是感觉被授权的一个额外的步骤!

熟悉生物朱莉娅:朱莉娅的生物信息学

原文:https://towardsdatascience.com/getting-familiar-with-biojulia-bioinformatics-for-julia-796438aa059?source=collection_archive---------50-----------------------

走出我的舒适区,用 Julia 语言尝试一门新的应用科学。

ulia 是一种伟大的编程语言,通常与它强大的统计分析和机器学习能力联系在一起。然而,许多人可能知道,Julia 实际上有一套相当成熟和成熟的其他应用科学软件包。一些著名的例子包括 Yao.jl 的量子模拟,JuliaAstro.jl 的天文学(我也很想看看这个),QuantEcon.jl 的定量经济学,甚至 QuantumBFS.jl 和 QuantumOptics.jl 的量子物理学。有了 Julia 的这个丰富的科学计算生态系统,就很容易明白为什么许多科学家在业余爱好或工作上是朱利安。

这个软件包生态系统激起了我的兴趣,所以我决定利用最近由于病毒而有的空闲时间深入其中一个。毕竟,这是做一些有成效的事情的好时机,比如用我最喜欢的编程语言学习一门新的应用科学;因为我认为这很有成效。或许这也是学习更多生物学和基因组测序的最佳时机。明确地说,我在生物信息学领域没有任何领域知识,但我正在寻求在其中获得一个立足点,随着时间的推移,我可以通过实践和研究来提高。我也有兴趣看看我如何能够与 Julia 一起将机器学习和统计学应用于生物学,并交叉我非常感兴趣的两个应用科学。

添加包

为了使用 BioJulia 的软件包,我们当然需要添加它们。对于我的选择,我几乎去了 BioJulia 的 Github 并挑选了一些听起来有趣的库。在我的方法中我没有意识到的是,BioJulia 实际上有自己的包注册表。我没有通过 Pkg REPL 和 Github 单独添加软件包,而是决定使用注册表。在 Pkg REPL 中,我们可以使用以下命令添加 BioJulia 注册表:

registry add https://github.com/BioJulia/BioJuliaRegistry.git

然后我就可以像平常一样添加我的包了。这些包激起了我的兴趣:

  • 生物序列. jl
  • GenomeGraphs.jl
  • BioSymbols.jl

然而,这种体验最终有点不像我添加我一无所知的包,而有点像糖果店的孩子……我还决定选择 XAM.jl 和 BigBed.jl。我们还需要 BioCore.jl,我继续选择了 BioGenerics.jl(不确定我是否需要它。)最后,我打开了一大堆 Github 页面。幸运的是,我在谷歌浏览器上启用了实验性的标签分组。

我喜欢这个功能。

pkg> add BioCore
pkg> add BioSymbols
pkg> add GenomeGraphs
pkg> add BioGenerics
pkg> add BigBed
pkg> add BioSequences
pkg> add XAM

令人惊讶的是,我的包列表看起来还不算太差!

当然,现在我要做的只是进行超出人类能力范围的研究,并从我刚刚添加的几个包中选择一个…

但是我全押了!

我偶然发现了这个视频,如果你想看的话:

这真的很有帮助,让我知道我可以从哪里开始学习,以便有一个坚实的知识基础来处理这些包。实际上,我最初并没有意识到我的机器学习、编程和统计领域知识会在这里应用到多大程度,当我知道她的第一个复选框完全为我所用时,我非常高兴。总而言之,她说在开始学习生物信息学时要做五件事:

№1:编程基础

  • 统计编程语言中的 Apt 能力。✔
  • 熟悉 Bash。✔
  • 能够将数据读入您选择的编程语言。✔
  • 能够进行基本的统计检验(如 t 检验,卡方检验,f 检验)✔

№2:做一个项目

  • 找到一些有趣的数据,并将其读入您选择的编程语言中。
  • 使用绘图库可视化数据。

这里是她建议的获取数据的网站:

[## UCSC 基因组浏览器主页

2000 年 6 月 22 日,UCSC 和国际人类基因组计划联盟的其他成员完成了第一个…

genome.ucsc.edu](https://genome.ucsc.edu/)

强调了理解所收集数据的重要性。

她还建议机器学习——这一天我是一个快乐的年轻人。我不认为我意识到生物信息学和机器学习有多少共同之处。

№3:带着工具旅行

(我已经这样做了,我喜欢狩猎)

  • 在做之前,找到与你想做的事情相关的行业标准工具。
  • 一旦你有了更多的经验,拓展业务,甚至尝试创建自己的工具。

№4:重复步骤 2 和 3

所以在看完这个简短的介绍后,我决定下一步最好的行动是开始我的第一个项目。

我的第一个项目

对于我的第一个生物信息学项目,我决定浏览前面提到的 UCSC 网站寻找数据。该网站不仅有大量的数据,而且有很多查看这些数据的好方法!今天,我只是读取数据,但在未来,我将探索它,用它进行可视化和测试,也许我甚至可以找到一些实用的机器学习用途。

我从这个网站上得到了一些我认为很酷的穿山甲数据。这样做有点奇怪,因为你被带到一个没有样式的 html 页面,花了 30 分钟谈论如何用 wget 获得一个文件……这当然很奇怪,并使找到 ftp://或 http://链接变得非常困难。这是我最后使用的一个:

wget --timestamping 
        'ftp://hgdownload.cse.ucsc.edu/goldenPath/manPen1/bigZips/*'

有趣的是,我的 512GB NVME 驱动器的存储空间非常低,因为我是一个数据囤积者,所以我非常害怕我可能会用这些数据填满我的 SSD,并需要四处清理。你知道我真正需要什么吗?

NAS。

以下是我用 wget 从存储库中收集的文件:

现在,我将在这个目录中创建一个笔记本服务器。

cd ~/Projects/bioproject
jupyter-notebook

这是一个巨大的数据量,所以我决定尝试进入 Julia 的第一个是 manPen1.2bit。这是因为虽然我不知道如何将这些数据读入 Julia,但我知道我有一个包可以做到这一点。BioSequences.jl 中有一个 2 位阅读器,您可以在此处找到文档:

[## 生物序列. jl

2bit 是一种二进制文件格式,用于存储由多个染色体序列组成的基因组。阅读…

biojulia.net](https://biojulia.net/BioSequences.jl/v1.0/io/twobit.html)

BioSequences.jl 有一个存储在名为 TwoBit 的子模块中的类型。然而,当我试图导入它时,我遇到了一个问题…

" TwoBit 未定义"

考虑到这一点,我决定检查我拥有的 BioSequences.jl 的版本:

在文档页面的左侧,我将版本更改为我电脑上的正确版本,然后搜索 TwoBit。这表明这个包不再是一个子模块,而是成为了它自己的包,所以我必须添加它:

pkg> add TwoBit

现在我们可以将它导入 Julia 并创建我们的阅读器:

using TwoBit
reader = TwoBit.Reader(open("manPen1.2bit", "r"))

现在,我们可以在我们的阅读器上使用 seqnames()方法查看刚刚读入的基因组序列:

sequences = TwoBit.seqnames(reader)

现在我们有了生物数据!

结论

那相当有趣!我非常兴奋地看到所有的基因组学,我将能够在朱莉娅身上进行实验。虽然我肯定还有很长的路要走,但我认为一些实践和反复会让我达到可以开始用核苷酸和 DNA 进行机器学习的地步。虽然这肯定不是我的知识领域或技能领域,但我真的认为我会喜欢基因组学,因为我一开始就很喜欢生物学。

我的下一步是尝试将数据可视化,并从中得出结论。我真的没有意识到这和我每天做的事情有多么相似。我很感激这一点,也非常兴奋地想了解更多。我在亚马逊上订购了一些可能有助于我了解这些海量信息的书籍,但现在,我只想熟悉与基因组学相关的工具和数据格式。

熟悉 Keras

原文:https://towardsdatascience.com/getting-familiar-with-keras-dd17a110652d?source=collection_archive---------20-----------------------

两个神经网络回归问题

像素上的赖爷子拍摄的照片

神经网络是由大脑连通性松散启发的计算系统。简而言之,神经网络对输入进行一系列转换,其结果在学习过程中被用作特征。Keras 是 python 中的一个开源库,可以轻松地对神经网络进行实验。Keras 提供了许多神经网络的构建模块,包括目标函数、优化器、激活函数、各种类型的层和许多附加工具。

在本帖中,我们将使用 Keras 库构建三个回归神经网络模型。

我们开始吧!

预测汽车的价值

在第一个例子中,我们将根据客户属性预测汽车销售的潜在价值。这些属性包括年龄、收入和性别等信息。数据可以在这里找到。

首先,让我们导入 pandas 并将数据读入数据框:

import pandas as pd 
df = pd.read_csv("cars.csv")

让我们打印前五行:

print(df.head())

接下来,我们将定义输入和输出变量。我们将使用“年龄”、“性别”、“英里数”、“债务”和“收入”来预测“销售额:

import numpy as np
X = np.array(df[['age', 'gender', 'miles', 'debt', 'income']])
y = np.array(df['sales'])

我们现在需要分割数据用于训练和测试。我们将从“sklearn”中导入“train_test_split”方法:

from sklearn.model_selection import train_test_split

然后,我们将测试集定义为随机样本(20%的数据):

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 42)

接下来,我们需要重塑我们的标签系列:

y_train = np.reshape(y_train, (-1,1))

现在我们可以定义我们的模型了。首先,我们需要导入几个包:

from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Dense

接下来,我们定义一个顺序模型对象:

model = Sequential()

让我们建立一个简单的神经网络,它有一个输入层、一个隐藏层和一个输出层。我们还将在输入层和隐藏层使用“ReLu”激活功能。对于输出层,我们将使用线性激活函数。输入层和隐藏层将有 32 个神经元:

model.add(Dense(32, input_dim=5, kernel_initializer='normal', activation='relu'))
model.add(Dense(32, activation='relu'))
model.add(Dense(1, activation='linear'))

接下来,我们编译模型。我们将使用“adam”优化器和均方误差损失函数:

model.compile(loss='mse', optimizer='adam', metrics=['mse','mae'])

最后,我们拟合我们的模型。让我们以 100 个时期和 10:

model.fit(X_train, y_train, epochs=100, batch_size=10)

我们看到,与销售额相比,均方误差和平均绝对误差都非常低,这很好。

现在,让我们对测试集进行预测:

y_pred = model.predict(X_test)

接下来,我们可以可视化我们的结果。让我们导入 matplotlib 和 seaborn,并显示真实值与预测值的散点图:

import matplotlib.pyplot as plt 
plt.scatter(y_test, y_pred)
plt.xlabel('True Values')
plt.ylabel('Predictions')

对于第一次传球来说,这是一个不错的表现。通过进一步的超参数调整,我们可以做得更好。为了进一步提高性能,我鼓励您尝试一下层数、神经元、时期和批量大小。你也可以尝试一些其他的优化器,而不是“adam”,比如“rmsprop”或“sgd”。您还可以尝试使用规范化、标准化或最小/最大缩放来转换数据。

预测燃油效率

现在,让我们继续讨论另一个问题。在本例中,我们将以每加仑英里数来预测燃油效率。我们将使用马力、重量和气缸数量等信息作为预测模型的输入。数据可以在这里找到。

让我们导入数据并打印前五行:

df = pd.read_csv("auto-mpg.csv")
print(df.head())

接下来我们将定义我们的输入和输出。我们将使用“气缸”、“排量”、“马力”、“重量”、“加速度”、“车型年”和“来源”来预测每加仑英里数(MPG):

X = np.array(df[['Cylinders','Displacement','Horsepower','Weight',
                'Acceleration', 'Model Year', 'Origin']])
y = np.array(df['MPG'])

我们现在需要分割数据用于训练和测试。我们将测试集定义为数据的随机样本:

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 42)

接下来,我们需要重塑我们的标签系列:

y_train=np.reshape(y_train, (-1,1))

现在让我们定义我们的模型。让我们从一个具有 64 个神经元的输入和隐藏层的神经网络开始。输入维度为 7,优化器为“adam”,损失函数为“mse”。我们还将使用 1000 个历元和 10:

model = Sequential()
model.add(Dense(64, input_dim=7, kernel_initializer='normal', activation='relu'))
model.add(Dense(64, activation='relu'))
model.add(Dense(1, activation='linear'))
model.compile(loss='mse', optimizer='adam', metrics=['mse','mae'], validation_split = 0.2)
model.fit(X_train, y_train, epochs=1000, batch_size=10)

现在,让我们来看看我们的结果:

y_pred = model.predict(X_test)
plt.scatter(y_test, y_pred)
plt.xlabel('True Values')
plt.ylabel('Predictions')

我们可以看到性能相当不错。我鼓励您尝试提高性能,或者尝试为其他预测问题建立神经网络模型。例如,您可能对使用神经网络来预测野火规模感兴趣,使用美国野火数据

总之,在这篇文章中,我们介绍了两个回归问题的建模过程:预测汽车的价值和预测燃油效率。我们讨论了如何初始化顺序模型对象、添加层、添加神经元、指定优化器、指定时期和指定批量大小。我们还使用真实散点图和预测散点图进行了模型验证。我希望这篇文章对你有用。这篇文章的代码可以在 GitHub 上找到。感谢阅读,机器学习快乐!

熟悉 Julia 中的循环

原文:https://towardsdatascience.com/getting-familiar-with-loops-in-julia-cfbcc344728c?source=collection_archive---------22-----------------------

朱莉娅综合教程

Julia 编程语言中循环和条件一起使用的介绍。

(图片由作者提供)

Github 回购

笔记本

介绍

如果一个人想进一步提高他们在软件工程方面的技能,仅仅通过观看是很难学会的。即使对文献或多媒体中的所有概念都了如指掌,如果不实际创建代码并查看代码如何与数据交互,也很难学习。大约十五年前,我一头扎进了 C++这门美丽的语言。为了学习 C++,我会花几个小时研究和复制粘贴代码,以找出它是做什么的。问题是我没有自己写代码,即使它是直接复制的。

需要澄清的是,我并不是说复制和粘贴代码是一件坏事,我总是从我以前的笔记本、我当前的项目,甚至是万维网上复制和粘贴代码片段。然而,很多工程是关于学习如何学习的。其中一部分是知道什么时候复制和粘贴,而不是什么时候你需要进一步研究材料。在我的 C++例子中,我记得使用了 STD 库和<

有趣的是,在地球上所有的语言中,我从未真正对 Python 感兴趣,直到大约三年前。虽然没错——它确实比 C++容易学得多,但我发现许多不同之处令人震惊。不管这种语言与其祖先相比有多简单,我发现自己陷入了一个陷阱,从谷歌上转移大量我并不真正理解的代码,这阻碍了我对这种新语言的学习能力。

所有这些证据都是为了支持一个说法:

想学编程,需要写代码。

我有一个导师,他参考了 Zed Shaw 的书《艰难地学习 Python》。这本书里的观点反映了我所讨论的内容的重要性,并且让我真正认识到,只要有互动,教育就变得简单多了。我也认为自己是一个视觉学习者,所以对我来说,这可以适用于任何试图学习计算机编程的人。

带着这些想法,我想如果我要提供具体和充分的教程,将一个人从一个绝对的初学者变成一个绝对的专业人士,那么我当然应该包括学生自己学习的资源。Github repo 中现在提供了笔记本的空副本,我坚持让较新的程序员自己键入代码!

在编程领域,开发人员可以使用一些不同的操作来处理数据。最常用的两种操作是循环和条件。循环是一种编程技术,它不仅允许检查、比较和计算类型内部的元素,而且是程序本身的基础。

编程中使用的循环主要有三种类型,一些独特的应用与特定的语言有关,例如 Julia 的语法循环。在 Julia 中,我们有以下循环应用程序供我们使用:

  • 迭代循环
  • 循环时
  • 递归循环
  • 语法循环

也就是说,语法循环仍然使用迭代器,只是在迭代器旁边使用语法表达式,用更多的表达式进行更快的循环——迭代也是如此。

让我们来看看一个迭代循环。迭代循环不同于递归循环和 while 循环,因为它们需要 dim 来循环。包含这种 dim 的类型的一个例子是数组。在数组的例子中,我们可以使用迭代循环连续地逐个循环每个元素。这也可以使用生成器类型来完成,它只是一种能够自己创建类型的类型。一个基本的例子是一个范围,其中范围类型生成一个位于范围的给定边界之间的 dims 数组。在这个例子中,我们将遍历一个由 10 到 20 之间的所有整数组成的数组:

**for** number in 10:20
    println(number)
**end**

(图片由作者提供)

while 循环将采用 bool 类型,这是一个读取 true 或 false 的条件,并将其用作循环的中断。只要不满足提供的条件,循环就会停止。而循环实际上是在机器上运行的大多数应用程序的基础。这是因为,只要你想让他们执行任务,他们就能始终如一地执行任务。当然,为了创建 while 循环,我们将使用关键字“while”,后跟一个条件。

*# while loop*
number = 1
**while** number <= 5
    number += 1
    print(number)
**end**

另一个要看的是打破循环的能力。这通常是在有条件的情况下完成的,但它使用了关键字“break”例如,虽然上面的循环将打印 1 到 6 之间的每个数字,但如果我们打破它,我们将得不到任何打印结果。

*# while loop*
number = 1
**while** number <= 5 break
    number += 1
    print(number)
**end**

最后,还有递归循环。递归以及何时使用它是一个完全不同的讨论。一般来说,递归会降低性能,但是,有许多函数式算法是利用递归的现代计算的基础。也就是说,在迭代和 while 循环不能完成工作的情况下,递归有一些很好的用途。阶乘的计算是递归在科学、高级计算中合理应用的一个完美例子。大多数递归算法将使用一个条件来决定是否应该用一个返回来中断一个循环。在阶乘函数中,我们要做的第一件事是检查我们想要阶乘的数字是否为 1。如果是这样的话,1 的阶乘当然只是 1,所以我们将返回 1。

**function** fact(n)
    **if** n == 1
        **return**(1)

这会打破我们的循环。考虑递归循环的一个很好的方法是想象函数本身既是循环又是循环的初始化。接下来,我们要把这个数乘以它本身的阶乘减一。这在数学上本质上是非常递归的,因此计算中的应用程序也应该是递归的。

**else**
        **return** n * fact(n-1)

只要满足 else 条件,这个函数就会调用自己。如果 n-1 不等于 1,那么它将再次调用自己——这就是递归。这是我们的最终结果:

**function** fact(n)
    **if** n == 1
        **return**(1)
    **else**
        **return** n * fact(n-1)
    **end**
**end**

有趣的事实:

Julia 的基本阶乘函数 factorial()实际上并没有使用递归来计算阶乘。相反,它使用查找表将值与相应的阶乘相匹配。这意味着大于一个数的值,在 Julia 的例子中是 22,是无法计算的。虽然这可能是一个缺点,但这也意味着数字小于 22 的运算要比其他情况快得多。

拉链环

zip 循环是一个很好的工具,当你想同时遍历多个数组的时候可以使用它。这对于阈值以及跨数组比较或操作值都很有用。Julia 中的 zip 语法与大多数语言略有不同,所以确保应用正确的语法很重要,使用 zip 作为方法,两个 dim 成对使用。

array2 = [30, 40, 50, 60]
**for** (i, w) in zip(array, array2)
    println(i, w)
**end**

把我们知道的和循环结合起来

现在我们已经有了循环、条件和函数的坚实基础知识,让我们把所有这些技能结合起来。

newarray = [] **for** element in array
    **if** element == 10
        append!(newarray, element)
    **elseif** element == 20
        append!(newarray, element)
    **end**
**end**

在这个例子中,我们循环遍历一个数组。如果它满足等于 10 的条件,那么我们将把它附加到新的空数组中。如果数字不等于 10 和等于 20,我们也将这样做。然而,如果它等于 10 和 20,那么它将只运行初始 if。

你自己试试!

你能创建一个函数来遍历字符串“Hello World”中的每个字母,并且只打印 H、W、l、r、o 或 D 中的一个字母吗?

我们要做的第一件事当然是定义我们的 hello world 字符串变量。

Hello = "hello world"

接下来,让我们写一个函数。

**function** filterstring(input)

该方法的下一步是遍历字符串中的每个字符。为此,我们可以用 for 循环调用字符串。

**for** character in input

接下来,我们需要检查该值是否在我们想要打印的值列表中。每当我们想要检查某个东西时,我们很可能会使用条件。对于这个例子,你可以使用 to 方法。其中一个是新手方法,另一个要简单得多。创建一个可接受值的列表并检查循环元素是否在该列表中,或者为每个单独的字符创建一个条件。无论哪种方式,都会产生相同的结果,坦率地说,只是简单和容易得多。

**function** filterstring(input)
    validchars = ['H', 'W', 'l', 'r', 'o', 'd']
    **for** character in input
        **if** character in validchars
            print(character)
        **end**
    **end**
**end**

(图片由作者提供)

结论

恭喜你!你正在成为一名优秀的 Julia 开发者。虽然事情在开始时看起来很复杂,但是您需要获得的大部分知识,至少在开始时,将会学习更多使用操作符、条件、类型和循环来处理数据的方法。虽然还有更多的东西需要学习,但是在这些教程中已经介绍了用 Julia 语言编程的基础知识。

被解雇,在新冠肺炎中部被聘为数据科学家

原文:https://towardsdatascience.com/getting-fired-and-hired-as-a-data-scientist-in-the-middle-of-covid-19-2c6626556cf8?source=collection_archive---------23-----------------------

来自 Pexels汤姆·斯温南的照片

困难时期找工作的心得。

我在 YC 的一家初创公司开始了机器学习方面的新工作,该公司的核心产品是一个让计算机视觉 ML 建模变得简单的平台。产品、同事、文化和薪酬都很棒。几个星期后,我们开始在家工作,就像几乎所有其他与疫情打交道的公司一样。即使在那时,一切都超级顺利。

有一天,我在 slack 上收到一条 CEO 发来的 DM,说他想和我聊聊天。我就知道会这样。我只是不知道该如何反应。我问原因,我明明知道。不知何故,这场尴尬的对话在 5-10 分钟内就结束了。

老实说,我并不感到太难过。我在那里只呆了一个多月。令人烦恼的是未来——又一次求职。找工作很累人。通常情况下,你可以轻松地寻找工作,因为你已经有了一份工作。你花时间去评估公司,评估你在公司的未来。我没有。像我这样的人越来越多,而空缺职位却比以往任何时候都少。

我的第一反应

我做的第一件事就是处理这个情况。打电话给几个密友告诉他们这个消息。真的帮我镇定了神经,减少了紧张的兴奋感。

很快我为我的下一次狩猎做了一些预感—

  1. 我不能太挑剔。我需要尽快评估谁在招人。对于一份工作,我需要有一套清晰的最低标准。如此之少,以至于即使我拿掉一个,我的工作生活也会像地狱一样。
  2. 既然我被解雇了,我就可以公开放出消息说我正在找工作。我希望我的朋友和网络能帮助我。他们做到了。因为我在 LinkedIn 上的一篇帖子,我得到了这么多线索。
  3. 从我过去的求职经历中,我发现哪些求职网站有用,哪些没用。但是要注意,许多工作列表是存在的,但是没有人去检查它们。它们正在恢复黑洞。
    工作— iimjobshiristangel
    浪费时间— Linkedin jobs
  4. 除了工作列表网站,我更依赖推荐。不要申请 LinkedIn 的工作,使用搜索栏搜索带有数据科学、机器学习等标签的内容。 通过帖子连接到发布空缺职位的人员。

冷静一下:)

完全披露——那段时间我住在孟买的家里。我有足够的积蓄来养活自己和家人。

我对我的失业很轻松。我知道一件事——整天申请工作是没有意义的。我有一个清晰的申请策略——每两天,浏览工作列表,找到任何感兴趣的东西,然后申请。反正我在 LinkedIn 上很活跃。我留意了提到任何空缺职位的帖子。只需将它加入书签。在求职申请上浪费时间没有意义。我能做的最好的事就是耐心等待。对于每一份重要的申请,找一个可以推荐你的人。90%的时间都在工作。

同时,我养成了许多好习惯。我开始锻炼,玩很多室内和室外游戏(在我的社会里),对瑜伽感兴趣。

在技术方面,我决定学习新的东西。我一直有一个遗憾,就是没有学习数据结构和算法。至少有 4 次我开始学然后放弃了。这次我屁股下面着火了。任务完成。

https://giphy.com/explore/hacker-man

接下来,我真的很怀念孟买公司过去组织的技术聚会。我喜欢行业层面的讨论和结交新朋友。在这个失业+禁闭的时期,我决定和网上的人联系。这是最好的!我被介绍给很多人。不仅仅是数据科学,还有时尚、管理等等。

那么面试呢?

让我们看看。我完成了 6 次 T21 的任务,10-15 次面试,以及数不清的申请。我将突出重要的几个。

排名第一的大型食品订购公司

  1. 职位——ML 工程师
  2. 公司类型——大型创业公司
  3. 状态—第一轮后被拒绝
  4. 来源— LinkedIn 推荐

过程—

通常,当人力资源代表给你打电话寻求机会时,他们会问你具体的技能、目前的薪水和工作地点。但这次不同。她很好地向我解释了角色和问题陈述。直到她问了一些琐碎的人事细节,我才意识到她是一名人事。她问我知不知道 Scala。我没有。她以一种非常合法的方式解释了 Scala 对于他们的系统是多么的重要。印象深刻!

数据科学家/ML 工程师这两个术语可以互换使用。不在这里。整个面试基本上都是 ML 系统工程。我们只讨论了工程部分,没有讨论科学部分。我完全没有准备好。

总的来说,这是一次积极的学习经历!

危险信号——无

#2 大型美容和时尚电子商务公司

  1. 职位—数据科学家
  2. 公司类型——最近资助的大型创业公司
  3. 状态—在两轮和一次分配后被拒绝(因为蹩脚的原因)
  4. 来源——一名员工在 LinkedIn 上联系

过程—

采访者不是数据科学家。他是产品经理。该公司外包了大量的分析工作。第一轮很标准。谈到我过去的工作。他给了我一个任务,是关于产品描述的数据集。目标是为搜索查询排列产品。努力工作并取得了好成绩。在下一轮中,向他介绍了该方法,并展示了一些有趣的结果。

他没有问我任何关于我的方法。相反,有人问我能做些什么改进。我解释了我关于使用过去的购买和协作过滤等方法的想法。我得到的只有嗯嗯……

后来,当我询问我的申请情况时,他打电话告诉我,我被拒绝了。酷毙了。我要求反馈。他说了两件事—

  1. 我不是 CS 出身— 为什么你在让我做作业之前不看我的简历或者问我????
  2. 我们需要资深的人— 我已经在简历上明确提到我的经历和日期了!!数数并不难。

危险信号—

  1. 面试官不适合。
  2. 在讨论作业时,他没有质疑我的方法。我知道他没有技术知识。从业务或者产品角度还是可以问很多的。

#3 一家小型分析公司

  1. 职位—数据科学家
  2. 公司类型—分析公司(基于服务)
  3. 状态——我拒绝了他们
  4. 来源——一名员工在 LinkedIn 上联系

过程—

人力资源部打电话来了。询问关于我的标准信息。然后事情变得很奇怪。问我父亲的生意。我在想为什么?这合法吗?我说了那是什么。然后她问我爸爸挣多少钱?是时候说-

https://cnb.cx/2KulS1E

危险信号—

你知道的。

顺便说一句,要知道

[## 非法面试问题——不要问应聘者什么

非法工作面试问题从求职者那里获取信息,这些信息可能被用来歧视…

www.betterteam.com](https://www.betterteam.com/illegal-interview-questions)

#4 一家 SaaS 公司

  1. 职位—数据科学家
  2. 公司类型——Saas 公司
  3. 状态—报价已收到。我拒绝了他们。
  4. 来源——一名员工在 LinkedIn 上联系

过程—

总共 4 轮,1 次任务。这家公司在印度并不出名,至少在我的网络中是这样。经过跟踪,我发现了他们的产品,员工背景。不过没什么特别的。面试是标准的。解决了任务,并在其中一轮中与数据科学家进行了讨论。在随后的几轮中与高层管理人员进行了交谈。主要是案例研究。他们最终提供了一份不错的薪水。

我仍然对这家公司感到有些不安。没有任何危险信号。除了一件事——在作业讨论中,我提到了一些我无法在截止日期内尝试的方法。她说,“嗯,24 小时的期限在这里很常见。”然后一笑置之。当时我并没有过多地去理解它。

我看了 glassdoor 上的评论。积极的看起来是假的。消极的人有共同的痛点。我决定联系前雇员。最后,我出于绝望决定不打错电话,拒绝了他们的提议。

危险信号—

  1. 可疑文化
  2. 一致的负面评价

#5 一家位于硅谷的食品科技创业公司

  1. 职位—数据科学家
  2. 公司类型——A 轮募集
  3. 状态——在分配后出现幻影(在 4-5 次提醒后)。
  4. 来源—匹配天使

过程—

在我之前找工作的时候,我们在安吉尔上匹配过。因为我在比赛结束后得到了一份工作邀请,所以我们没有继续。这次我联系了他们是否还在招人?他们给了我一个任务。这是一个多标签分类任务。这似乎是他们正在解决的问题之一。

我在这项任务中工作最努力。无法完成所有子任务。然而,这足以表达我的努力。

我要求下周的审查和状态。他们说过几天。同样的动作重复 4 次以上。每次都有不同的蹩脚借口。

很可能,他们从申请人那里得到了解决问题的方法。

危险信号—

  1. 一连串的借口。除非你要求,否则人力资源部不会与你联系。

是什么让我保持理智?

虽然我说我对裁员感到非常冷静,但当我发现顶级公司都在裁员 1000 人时,我开始思考——我要如何同时与所有这些公司竞争?这么少的空缺也是这样吗?我得加快速度。

在这两个月里,我的朋友和家人给了我很多支持。朋友们经常来看我,我的家人给了我足够的空间来解决我的问题。

我第一份工作的 CEO 一听到我的消息就让我回来。我也确保在身体和精神上照顾好自己。

我学到了什么?

对我来说,处理不确定性的机会并不多。这段艰难的经历教会了我如何应对。有关心你的人让这种经历变得可以忍受。

尽快开始建立一个强大的网络。与人们联系,询问他们当前的项目,你如何帮助他们。尽可能多交朋友。意识到当你是一个团体的一部分时,你总是更强大。

我都不敢想象背负沉重助学贷款的应届毕业生有多难。如果你是一个很难找到工作的求职者,请在 LinkedIn 上联系我,并说明我可以如何帮助你(当然是免费的)。请具体说明你的问题。在这里找到我。

通过 Discord 服务器获得群体行为洞察

原文:https://towardsdatascience.com/getting-group-behavior-insights-through-discord-servers-732e4941d8f8?source=collection_archive---------27-----------------------

分析不和谐信息数据如何提供关于社交媒体行为和社交团体的有价值的见解。

耐嚼Unsplash 上拍照

介绍

在浏览互联网的时候,社交媒体基本上是不可避免的。几乎每个人都因为各种原因使用至少一个社交媒体平台,它们通常代表了一个人社交生活的重要部分。

正是因为这个原因,分析社交媒体平台中的行为数据是了解人们,甚至是群体的一种很好的方式。在基于聊天的社交媒体平台上,这种群体洞察变得更加明显。

出于这个原因,我将向您展示如何获得 Discord、消息传递数据,并为分析做好准备,以及使用一点点。您可以跟随包含本文代码的 google colab。

数据

在一个基于聊天的平台中,特别是像 Discord 这样的服务器被分成多个频道的平台,在制作数据集时,我们可以跟踪许多变量。

对于我将在这里使用的数据,所有消息都来自同一个通道,这意味着我们不需要跟踪消息被发送到哪里。对于我们将要进行的分析来说,所有重要的变量是消息的作者、消息发送的时间以及消息本身的内容。

我们将使用的数据框,总共包含 3 列。

在开始之前

当处理这样的数据时,如果这些数据包含其他人的姓名(在本例中是用户名),而这些人不一定允许您公开他们的信息,您应该始终匿名化这些数据,以避免任何不必要的问题,同时也尊重他们的隐私。

准备数据

在我们开始分析之前,我们必须确保我们的数据包含我们需要的一切。

使用 Pandas 查看文件概述后,您应该会注意到数据集中有丢失的值。其背后的原因是,在这个数据集中,在消息中发送的图像和嵌入被表示为 NaN 值。

data.info()

使用 DataFrame.info() 方法获得数据集的概览。

由于这些消息只代表了数据集的一小部分,对我们没有任何用处,我们可以简单地丢弃它们。我们还应该将 time 列转换成 DateTime 以便更容易地处理日期。

一旦我们解决了这个问题,我们就可以专注于做一些更好的工作来分析更多的列。例如消息中包含什么表情或者每条消息有多少单词。

除了我们都习惯的常规表情符号,discord 还有专属的公会表情符号,可以是动画的,也可以不是。为了表示所有这三种表情,我们将为每一种表情添加一个单独的列,每一列都由包含消息中发送的该类型的所有表情的数组组成。

要创建这些数组,我们可以使用正则表达式来识别哪些消息包含表情,然后将它们添加到各自的列中。

我利用 python 的表情库更容易地从消息中提取表情,因为并非所有表情都符合我使用的正则表达式模式。

之后,我们只需将字数统计列添加到数据框中,就可以开始处理数据了。

分析数据

有了转换后的数据集,我们可以开始分析,以深入了解我们的消息传递历史数据。

在经历了所描述的整个过程之后,数据帧的前 5 行。

例如,我们可以进行的一种可能的分析是,观察服务器中的用户活动在整个数据集内的表现,该数据集包含来自该服务器的一年多的信息。

然而,在这样做的时候,我们遇到了一个问题,即有太多的作者,他们中的许多人缺乏足够的数据来为分析做出任何实质性的贡献。

这是因为数据还包括来自服务器中不活动的机器人和用户的消息,因此不会告诉我们关于整个群体的任何信息。

fig = px.histogram(data, x='author', title='Messages Sent Per Author', labels={'author':'Author'})fig.update_layout(title_font_size=30, template='plotly_white')fig.show()

列出的大多数作者在服务器历史上几乎没有发送过消息。

通过设置一个最小的消息量作为基线,去掉发送少于这个数量的作者,我们可以过滤掉那些没有贡献足够数据的作者。

有了更少的作者,他们都贡献了大量的消息,我们最终可以绘制一个图表,更好地表示服务器中用户活动随时间的变化。

fig = px.histogram(data, x='time', color='author', opacity=0.5, title="User Activity Over Time", labels={'time':'Date'})fig.update_layout(barmode='overlay', title_font_size=30, template='plotly_white')fig.show()

通过缩小时间窗口,您可以深入了解服务器最近的活动情况,甚至可以发现服务器在一天中的哪些时段最活跃。

我们还可以画出每个作者发送的消息总量,看看谁是最活跃的,以及服务器成员在频率上如何比较。

fig = px.bar(x=data.author.value_counts().index, y=data.author.value_counts(), color=data.author.value_counts().index, title='Messages Sent per User', labels={'x': 'Author', 'y': 'Messages Sent'})fig.update_layout(title_font_size=30)fig.show()

请注意,上图计算了数据帧中包含的所有已发送消息。您还可以限制时间范围以获得更多的最新数据,而不是考虑这么大的时间窗口。

并且,通过对数据集进行简单的过滤,您可以用同一个图来表示包含某个字符串但仍被作者划分的消息的数量。

term = 'LOL'
term_data = data[data.content.str.contains(term)]# The exact same plot, but replaced data by term_datafig = px.bar(x=term_data.author.value_counts().index, y=term_data.author.value_counts(), color=term_data.author.value_counts().index, title=f'Messages Containing "{term}" Per User', labels={'x': 'Author', 'y': 'Messages Sent'})fig.update_layout(title_font_size=30, template='plotly_white')fig.show()

另一种可能的分析是绘制和比较每个用户发送的表情的总量,同时也根据表情的类型对它们进行划分,例如,这可以指示组中谁有 nitro,因为只有那些有 nitro 的用户才能发送动画表情。

然而,对于这个图,首先,我们需要将数据框转换成“整齐”的格式,这就是 Pyplot 用于条形图的格式,就像我们将要绘制的这样。我们可以通过使用 pd.melt() 方法来做到这一点,这是一种非常有用的方法,可以轻松地将数据帧转换为“整齐”的格式。

将 emote 列从数组转换为整型,并应用 pd.melt( )方法。

fig = px.bar(data_line, x ='author', y='value', color='variable', labels={'value':'Emotes Sent', 'author':'Author'}, title="Emotes Sent per User")fig.update_layout(title_font_size=30, template='plotly_white')fig.show()

结论

在所有这些例子之后,应该很明显,从聊天数据中可以获得很多潜在的洞察力,比如来自 Discord 服务器的聊天数据。

从洞察某人的日常行为到他们作为更广泛群体的一部分的行为,来自社交媒体的数据是发现人们新事物的最佳方式之一,这就是为什么它值得更多关注

参考

本文的灵感来自以下两个处理类似数据分析的仓库,但分别用于 WhatsApp 和 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨:

[## kurasaiteja/Whatsapp-分析

GitHub 是超过 5000 万开发人员的家园,他们一起工作来托管和审查代码、管理项目和构建…

github.com](https://github.com/kurasaiteja/Whatsapp-Analysis) [## 预期代码/电报分析

一个处理 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-history-dump Venn _ userlist . py 输出的工具:比较聊天之间的用户重叠…

github.com](https://github.com/expectocode/丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-analysis)

从谷歌地图获得关于企业和位置的见解

原文:https://towardsdatascience.com/getting-insights-about-businesses-and-locations-from-google-maps-3f8a5739059a?source=collection_archive---------14-----------------------

让我们看看如何利用 Python 和 Selenium 的能力来挖掘 Google Maps 中关于感兴趣的企业和位置的数据

谷歌地图充满了你感兴趣的任何类型的商业或位置的有用数据。在这篇循序渐进的文章中,我将使用 PythonSelenium 从其中提取关于某个企业(或位置,我们将研究 3 个主要示例)的数据,然后以快速和自动化的方式对与之非常接近的类似或竞争企业进行同样的操作。

这个操作的输出是一个包含有用数据的数据帧(名字、商业类型、星级、联系信息、坐标、流行时间等。)我们可以用它来获得关于业务/位置及其周围环境的许多见解。

如果你想了解你的竞争对手的情况,这将是很有用的,但如果你想快速生成某个城市某类企业的列表,这也是很有用的。它还适用于历史地标、公园和各种景点,而不仅仅是企业,我们将在后面的第三个也是最后一个示例中看到。

您可以通过在我的 GitHub 存储库中下载 Jupyter 笔记本来阅读本文,这里是 、以及 CSV 格式的提取数据。

ps:我不隶属于任何企业。本文中的示例是随机选取的,仅用于说明和教育目的。

软件包和设置:

插图作者:明蒂·rawpixel.com

我们将需要Seleniumpython 包来执行数据抓取。如果您还没有它,您可以使用 pip: pip install seleniumconda install selenium安装它,如果您使用的是 Anaconda 发行版的话。

为了与浏览器互动,我们还需要一个网络驱动(这里我们将使用 Chrome),所以你必须 到这里并把它 下载到你的机器上(确保它与你当前的 Chrome 版本兼容) :

from selenium import webdriver

我们还需要 Selenium 中几个有用的类。我们将在这里导入它们:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import NoSuchElementException, TimeoutException, ElementNotInteractableException, ElementClickInterceptedException

现在我们来获取 tqdm ,一个必不可少的进度条 python 包。估计你的代码的 web 抓取部分要花多少时间是非常有用的(我用 tqdm_notebook 是因为我在 Jupyter 笔记本上工作。在 IDEs 中你应该做from tqdm import tqdm,然后用tqdm代替tqdmn):

from tqdm import tqdm_notebook as tqdmn

除此之外,我们还需要 Pandas 来读取和操作数据集,以及 Numpy 来处理空值:

import pandas as pd
import numpy as np

同样,让我们导入 MatplotlibSeaborn 来做数据可视化:

import matplotlib.pyplot as plt
import seaborn as sns

为了在地图上显示我们的企业/位置,我们需要 叶子 。如果没有叶子,使用pip install foliumconda install -c conda-forge folium安装:

import folium

最后,我们需要内置的 python 模块 timere (第一个模块在元素加载时停止代码一段时间,第二个模块使用 RegEx 或正则表达式 从模式的原始文本中提取数据):

import time, re

这是可选的,只是为了给我们的数据帧添加一些 CSS 样式:

%%HTML
<style>.dataframe th,td:first-child{background: rgb(63,87,124);background: linear-gradient(180deg, rgba(63,87,124,1) 0%, rgba(101,124,161,1) 100%, rgba(0,212,255,1) 100%);;
padding: 10px;font-family: monospace;font-size: 110%;color: white;border:1px dashed white;text-align:left !important;
-moz-border-radius: 3x;-webkit-border-radius: 3px;}.dataframe thead{border:none; !important;}</style>

澳大利亚布里斯班的打印店:

图片由布拉德·斯克鲁斯——Flickr.com(CC)拍摄

Ryan 是一名获得印刷行业管理文凭的应届毕业生,他正在澳大利亚布里斯班找工作。他刚刚把他的简历送到了打印店 Kwik Kopy Brisbane (因为它碰巧离他家最近)。他还能在城市的什么地方找到合适的工作?让我们帮帮莱恩。

我们要做的第一件事是去谷歌地图搜索该企业的名称,或者我们可以在浏览器地址栏的www.google.com/maps/search/后添加名称。然后,如果我们单击业务类别,这里是Print shop(见下图),我们将获得不同打印相关业务的列表。我们航行的时间越长,就离我们最初的打印店越远:

在编写为我们进行网络搜集的代码之前,让我们先列出我们将经历的所有步骤:

1。绕场比赛:

  • 答:取我们公司的名字,加在www.google.com/maps/search/之后,然后访问那个网址
  • b:点击业务类别
  • c:获取参赛者的姓名和地址,然后点击下一步按钮>。我们反复这样做,直到我们对有多少竞争者感到满意。这一步的输出是一个竞争对手的列表(名字和地址),让我们把它命名为competition(名字本身不足以唯一地标识一个企业,这就是为什么我们还要捕获地址)

2。提取数据:

  • d:获取competition的第一个元素并将其添加到www.google.com/maps/search/之后,然后访问该 URL
  • e:提取名称、业务类别、平均评级、评论总数、地址、电话号码和网站,然后从competition开始使用另一个元素再次循环到步骤 D,直到结束。

下面是这样做的代码:

执行这段代码后,您将看到一个 Chrome 窗口打开,我们之前概述的步骤会自动一个接一个地执行。有时,谷歌地图会将一个企业名称/地址与另一个混淆,并给你一个选择:

出现这种情况时,只需在搜索栏中点击最接近查询的业务,代码就会正常继续。你也可以忽略它,由于有了tryexcept模块,代码会在 25 秒后自动跳到competition中的下一次迭代。

如果一切按计划进行,让我们用提取的列表制作一个熊猫数据框架。姑且称之为PS打印店:

PS = pd.DataFrame(data={'full_name':full_name, 'rating':rating, 'total_ratings':total_ratings, 'business_category':business_cat, 'address':address, 'phone':phone, 'website':website, 'latitude':lat, 'longitude':long})

这是我们的数据框架,包含 Kwik Kopy 和大约 100 家竞争对手的信息:

此时,最好将该数据帧保存为 CSV 文件以便安全保存:

PS.to_csv('print_shops.csv', index=False)

下次我们打开笔记本时,我们所要做的就是读取 CSV 文件,而不是再次运行 web 抓取代码:

PS = pd.read_csv('print_shops.csv')

经过一些数据清理和准备(见 Jupyter 笔记本),我们最终得到了 84 个不同的企业,Ryan 在找工作时可以考虑。还不错!但是它们在城市中有多分散呢?要回答这个问题,让我们将它们绘制出来,并在单击标记时显示的弹出窗口中添加它们的信息:

你可以在这里下载这个 HTML 格式的地图: ps_map.html

现在,这看起来更像是一个求职冒险的路线图!瑞安可以开始联系离他家最近的企业,如果需要的话,可以向外扩展。

在这个用例中,平均评级和评级总数对 Ryan 来说意义不大。在下一个例子中,我们将探索这两个变量更重要的行业:我们将在生机勃勃的格拉斯哥寻找最好的牛排馆。

苏格兰格拉斯哥的牛排馆:

戴夫·谢伊——Flickr.com(CC)摄影

Moira 想请她的男朋友吃一顿美味的牛排晚餐作为生日礼物,但她不知道具体去哪里。她在一个专门的博客上搜索,发现迷你烧烤牛排店是格拉斯哥最好的牛排店之一。让我们帮助 Moira 决定哪家牛排馆最适合这个场合,因为她认为好的葡萄酒(或鸡尾酒)和音乐是美好体验的必备条件。

我们将遵循与之前完全相同的步骤,除了添加两种新类型的有用信息:价格范围(从$$$$$)和评论主题(数字指有多少评论谈到了该主题) :

下面是我们将使用的代码(有时谷歌地图根本不显示评论主题。如果发生这种情况,只需关闭 Chrome 窗口,停止代码并再次重新运行单元格) :

现在让我们用提取的列表制作一个数据框架。我们将它命名为SH牛排餐厅:

SH = pd.DataFrame(data={'full_name':full_name, 'rating':rating, 'total_ratings':total_ratings, 'business_category':business_cat, 'price_range':price_range, 'address':address, 'phone':phone, 'website':website, 'review_topics':review_topics, 'latitude':lat, 'longitude':long})

让我们来看看我们得到的业务类别:

SH.business_category.value_counts()

我们希望只保留那些名称中带有“牛排”或“烧烤”字样的、酒吧、&烧烤店、餐馆。让我们称这个新的数据框架SBR(用于牛排店、酒吧&烧烤店和餐馆) 😗***

steak_houses = SH[SH.business_category == 'Steak house']
bar_grills  = SH[SH.business_category == 'Bar & grill']
restaurants  = SH[(SH.business_category.str.contains('Restaurant', case=False)) & (SH.full_name.str.contains('steak|grill', case=False, regex=True))]SBR = pd.concat([steak_houses, bar_grills, restaurants])

这就让出了 47 个名额。现在让我们帮助 Moira 从这些高级餐厅中挑选最划算的。如果你还记得的话,莫伊拉想要一次享受美酒、鸡尾酒和音乐的美好经历。让我们来看看有一个或多个这些要求的地方的review_topics:

list(SBR[SBR.review_topics.str.contains('\Wwine|cocktail|music', case=False, regex=True)].review_topics)

正如我们在上面看到的,16 个不同的地方至少有 3 个关键词中的一个。为了能够做出选择,让我们添加 3 个新列winecocktailsmusic,包含这些关键词被评论提及的次数(这是在提取的review_topics中位于\\n之后的数字)。我们没有统计这些词被提到了多少)。我们将使用 RegEx 提取我们想要的信息:首先我们用wine......|$提取部分'wine\\n8',然后我们用\d+|$提取数字。如果模式不存在,这里确保我们得到一个空值:

wine = []
for i in SBR.review_topics :
    wine.append(re.findall('\d+|$', re.findall('wine......|$', i)[0])[0] )SBR['wine'] = winecocktail = []
for i in SBR.review_topics :
    cocktail.append(re.findall('\d+|$', re.findall('cocktail......|$', i)[0])[0] )SBR['cocktail'] = cocktailmusic = []
for i in SBR.review_topics :
    music.append(re.findall('\d+|$', re.findall('music......|$', i)[0])[0] )SBR['music'] = music

3 个新列winecocktailmusic是字符串类型。让我们将它们转换成数值(但在此之前,让我们用 0 替换空值) :

SBR.wine = SBR.wine.replace('', 0)
SBR.cocktail = SBR.cocktail.replace('', 0)
SBR.music = SBR.music.replace('', 0)SBR.wine = SBR.wine.astype(int)
SBR.cocktail = SBR.cocktail.astype(int)
SBR.music = SBR.music.astype(int)

现在让我们添加一个名为score的新列,它是三个新变量winecocktailmusic的总和:

SBR['score'] = SBR.wine + SBR.cocktail + SBR.music

现在让我们按scoreSBR数据框进行分类,假设机构满足这两个条件:

  • winecocktails中至少有一个不为空
  • 对于music,它没有空值
SBR[((SBR.wine != 0)|(SBR.cocktail != 0)) & (SBR.music != 0)].sort_values(by='score', ascending=False)

范围缩小到两个地方了!这对莫伊拉来说已经足够了,但是不行!她希望有一种方法来设想所有的选择,以便做出一个好的选择。好吧,莫伊拉,如你所愿!

让我们将变量rating(代表平均升值幅度)total_ratings(表示受欢迎程度)和price_range(表示一个地方的可负担程度)考虑在内,并将SBR中的所有机构绘制在一个网格上。

但在此之前,我们需要删除total_ratings中的括号和逗号,将系列转换为数字,并将price_range中的美元符号改为更有意义的符号(美元符号出于某种原因会导致错误) :

SBR.total_ratings = SBR.total_ratings.replace('(\(|\)|,)', '', regex=True)SBR.total_ratings = SBR.total_ratings.astype(int)SBR.price_range = SBR.price_range.replace({'$$':'Affordable', '$$$':'Pricy' })

现在是网格。我们将使用一个散点图,X 轴是total_ratings,Y 轴是rating。颜色会根据price_range变化。我还添加了注释,以显示牛排馆、【迷你烧烤牛排馆】(MG) (博客推荐)的位置,以及获得良好评分的两个地方,、【肉吧】(MB)、【生活格拉斯哥】(LG) :

结果是,博客推荐的“迷你烧烤牛排屋”(Mini Grill steak house)(MG)(T13)在平均评分方面表现异常出色,但在对 Moira 最重要的东西(饮料和音乐)方面得分很低。“肉吧”(MB) 另一方面得分很高(33),在受欢迎程度和平均评分方面仅略低于 MG

莫伊拉现在很满意,她已经下定决心了。希望现在打电话预订还不算太晚!

意大利罗马的历史地标:

sbmeaper 1——Flickr.com 的照片(公共领域)

安东尼奥是一名高中历史老师。他计划和他的一群学生去意大利首都罗马进行为期三天的实地考察,参观那里最受欢迎的历史地标。然而,他知道每年的这个时候罗马都挤满了游客,他主要关心的是在参观某些地点时避免排长队和拥挤的人群,尤其是在高峰时段。这就是为什么我们要帮助他安排他的访问,以确保他的学生最大程度的舒适。

和往常一样,我们将使用我们的代码从谷歌地图中抓取有用的信息。这一次,我们将增加一种新的信息:流行次数:

当你访问万神殿的页面时,谷歌地图会显示上图(一个以前的大寺庙,现在是罗马的教堂)。根据谷歌地图:“在流行时间图上,任何给定小时的流行度相对于该企业一周的典型峰值流行度来显示”。因此,周六下午 4 点参观万神殿是一个非常糟糕的主意,因为这是一周中最繁忙的时间(因此属性aria-label的值为 100%)。

在这种情况下,我们不会搜索特定的地方。我们将简单地在谷歌地图上搜索【罗马旅游景点】(尽量宽泛)。现在让我们运行我们的代码:

完成后,让我们用提取的列表制作一个数据框架。我们称之为HL历史地标:

HL = pd.DataFrame(data={'full_name':full_name, 'rating':rating, 'total_ratings':total_ratings, 'landmark_category':landmark_cat, 'description':description, 'address':address, 'hours':hours})

像往常一样,让我们保存这个数据帧:

HL.to_csv('historical_landmarks.csv', index=False)

打开它:

HL = pd.read_csv('historical_landmarks.csv')

如果你记得的话,安东尼奥希望团队只参观最受欢迎的景点,因为行程只有 3 天。为了从HL中选择 10 个最受欢迎的历史地标,我们需要将total_ratings转换成一个数字向量:

HL.total_ratings = HL.total_ratings.replace('\(|\)|,', '', regex=True)HL.total_ratings = HL.total_ratings.astype(float)

让我们制作一个新的数据框架HL10,包含来自HL的最受欢迎的城市:

HL10 = HL.sort_values(by='total_ratings', ascending=False).head(10).copy()HL10

我们选择的罗马十大最受欢迎的景点(您的结果可能会有所不同)

我们主要关心的是在游览这些热门目的地时避开高峰时间。例如,让我们看看变量hours在罗马竞技场中是什么样子的:

str(list(HL10[HL10.full_name == 'Colosseum'].hours))

在我们的HL10数据帧中,hours是一个列表,描述了 7 天内(从周日到周六)任何一个小时(从早上 6 点到晚上 11 点)有多忙。为了使分析更容易,我们将为HL10中的 8 个位置中的每一个位置创建一个新的空数据帧,以天为索引,以小时为列。为此,我们将使用这个自定义函数:

让我们用斗兽场来测试一下:

colosseum = visit_planner('Colosseum')
colosseum

现在让我们用相应的值填充10 AM列。我们将在这里使用正则表达式:首先,我们捕获字符串***% busy at 10 AM,然后我们使用\d+捕获其中的数字,由于这里有 2 个数字(百分比和 10),我们使用索引[0]选择第一个数字。最后,我们将向量转换为整数:

成功了!让我们将相同的代码应用于循环中的所有时间:

现在让我们在热图上显示这些数据:

如果我们认为大约 50%的比率对团队来说已经足够舒适(其人口是一周中最繁忙时间的一半),并且我们需要至少 2 个小时才能参观完一个地方,那么参观罗马圆形大剧场的最佳日期和时间是:

  • 星期三一天中的任何时间
  • 周一周二周四上午8 点到 11 点和下午2 点到 7 点
  • 周五周末但仅从下午 4 点到 6 点
  • 避开周末,尤其是从上午 11 点到下午 2 点(T42)

让我们在另一个地方尝试同样的事情,那就是梵蒂冈博物馆。在这种情况下,事情有点不同,因为这个地方在周日关闭,我们用于两个预览地方的方法将不起作用,除非我们将周日行从数据框中删除:

现在,这是一个很难安排的时间,因为我们只有 7 个小时的访问时间,从上午 9 点到下午 4 点。所以,参观梵蒂冈博物馆的最佳日子和时间是:

  • 周三全天
  • 周二下午2 点到 4 点和周四上午9 点到 11 点和下午2 点到 4 点****
  • 周一周五周六要避开

安东尼奥对这一新获得的信息很满意。这将有助于他计划这次访问,最大限度地利用他与学生在欧洲最具历史意义的城市之一度过的三天时间。

注意:如果你想为一个地方做一个热图,你得到了错误Length of values does not match length of index,确保那个地方的hours列表有从早上 6 点到晚上 11 点的所有时间(总共 18 个,重复 7 次,总共 126 个元素)。如果缺少一个或多个,请尝试再次运行 web 抓取代码。

如果您有任何意见或问题,请随时在这里或 LinkedIn 上给我发消息。我很乐意回答。

没有研究生学位就进入数据科学领域

原文:https://towardsdatascience.com/getting-into-data-science-without-a-graduate-degree-59397401e6be?source=collection_archive---------12-----------------------

我是如何凭借一个学士学位得到一份最令人垂涎的工作的

作者照片

早在 2017 年,我曾休学一个学期,去埃克森美孚(ExxonMobil)的博蒙特炼油厂(Beaumont Refinery)做工程合作。我清楚地记得,在德克萨斯州华氏 95 度的潮湿天气里,我穿着阻燃工作服、钢头靴和安全帽,沿着大型管道和设备行走。作为一个最近才发现对编程有热情的中西部男孩,我感到格格不入。

如果你查看今天的任何数据科学家招聘信息,大多数(如果不是全部的话)都在寻找拥有数据科学硕士或博士学位的候选人。更不用说技术技能要求的流水账了。

这是一个关于我如何在没有硕士学位的情况下,用我的安全帽换来 21 世纪最性感的工作和 22 世纪最性感的工作的故事。

从基础开始

让我们倒回去。

2016 年,我在内布拉斯加大学林肯分校开始了大三化学工程和经济学双专业的学习。在各大学和美国国家航空航天局获得了大约一年的研究经验后,我决定要探索工业。

但是化学工程并不是我唯一的兴趣。我发现我也喜欢编码,所以我决定增加一个计算机科学辅修专业,并在 2016 年底报名参加 Udacity 的在线数据分析师 Nanodegree 。是的,我喜欢学习。

Udacity 的项目非常棒。他们与谷歌和脸书等顶级科技公司合作,建立在线课程,以帮助缩小技术技能差距。Nanodegree 现在有一个稍微不同的课程——当我参加它的时候,它曾经包括一个介绍性的机器学习和探索性的数据分析课程。

2017 年,我在埃克森美孚的第一个任期由与数据科学无关的工作组成。作为一个合作社,我推进资本项目,并帮助支持炼油厂的运作。到野外去,爬梯子,和操作员交谈是一种享受!

2017 年在埃克森美孚公司博蒙特办公室前穿着安全装备的我[作者图片]

我亲身体验了做一名化学工程师的感受,并对炼油厂的生活了如指掌。谢天谢地,他们给了我一个机会,我得到了一份返校邀请,回到博蒙特参加 2018 年夏天的实习。

在埃克森工作期间,我继续完成纳米学位,并在一年内完成。每天,我早上 8 点到下午 5 点工作,然后下午 6 点到 10 点学习。然后,在我的合作社,这是相同的时间表,但我切换到正常的大学课程工作。

很艰难吗?是的。我会再做一次吗?绝对的。

运用知识

自从完成了纳米学位,我对数据科学比对过程工程更感兴趣。有了新的证书,我联系了我大学的埃克森美孚招聘主管戴夫(他也是我第一任期的系主任)。

我问他是否有可能将我的实习工作转到他们的总部办公室,大部分数据科学工作都在那里进行。我想要这个有四个原因:

  1. 获得数据科学的真实世界经验,看看我是否真的喜欢这份工作
  2. 更多地了解公司,对全球产生影响,而不是在炼油厂进行特定的改进
  3. 让自己在毕业时有更多的选择——在一个网站实习的毕业生几乎注定要在那个网站开始他们的早期职业生涯
  4. 并且在崭新的现代化校园工作——这就像一个未来城市!

不幸的是,没有可用的开关。

所以在 2018 年,我又开始回到炼油厂实习。但这一次不同,我掌握了一些数据科学知识。

从第一天起,我就让我的新主管雷切尔知道我想进入数据科学领域。尽管精炼厂内没有任何数据科学职位,但我能够说服她将我将在夏天从事的三个项目中的一个与数据科学相关的项目进行交换。

更好的是,在那个项目中,Rachel 帮我联系了 George,他是炼油厂的一名高级工程师,之前有数据科学方面的经验。这是完美的一对。我们高度的正能量相匹配,他最终成为了一名导师。

我的项目?使用机器学习来建立一个推理模型并改善一个数百万美元炼油资产的过程控制。我非常兴奋,以至于我可以应用从 Nanodegree 学到的主题,如监督学习和超参数调整。

实习进行到一半的时候,我和我的主管以及我的伙伴(埃克森美孚为我们安排了一名全职员工作为导师)讨论了如果给我一份全职工作,我可能希望从哪里开始。我说的是作为数据科学家的总部办公室。

有人告诉我,进入那个角色最现实的途径至少需要 5 年。作为流程工程师在现场做几次轮换,担当协调员的角色,然后也许,仅仅是也许,能够转变为数据科学家。

但是我不想等。我想尽快在全球范围内产生影响。

因此,我需要证明,作为一名数据科学家,我会比作为一名流程工程师对埃克森美孚更有价值。我的策略?做好工作,确保合适的人知道这件事。

建立一个伟大的网络

我重新聘用了戴夫,他现在成了乔治主管的经理(多方便啊,对吧?).我负责的项目成了戴夫路线图上的一个大项目。所以我让他参与进来,并请他帮助我接触数据科学社区。

我也把网络掌握在自己手中。在成功交付数据科学项目后,我抓住机会,安排了一次与总部数据科学经理的通话。我有点害怕被拒绝,因为哪个忙碌的经理会有时间去数百英里外的炼油厂实习?

令我惊讶的是,她接受了。她很友好,虽然她重申如果我有多年的现场经验或研究生学位,我开始成为数据科学家的机会会更大,但她也给了我关于数据科学在埃克森美孚如何工作的深刻见解。

我了解到埃克森美孚不止有一个而是多个数据科学团队。有些已经很久了,而有些只有一两年的历史!

几个星期过去了,戴夫给我回复了。他联系了自己的关系网,提到一位数据科学主管愿意在总部接待我一天。然后我问雷切尔我是否可以去。她很支持我,但想确定我有计划。

我给了她一个计划。

上游。下游。它。我安排了一个时间,与尽可能多接触埃克森美孚数据科学领域的人交谈。取消我之前与之通话的数据科学经理也有所帮助。

在我的最后一周,我前一天开车一个小时去了休斯顿的一个大学朋友的公寓,那天晚上带着背包和毯子睡在了地板上(他刚刚在埃克森美孚开始工作,还没有任何家具)。

这是我第二天的日程安排:

  • 上午 8:00—8:30 |上游研究公司—数据科学主管
  • 上午 8:30—9:00 |埃克森美孚 IT —数据科学家
  • 上午 9:00—10:00 |价值链优化—数据科学家
  • 上午 10:00-11:00 |实时优化-优化工程师
  • 上午 11:00—下午 12:00 |上游研究公司—数据科学家
  • 中午 12:00—下午 1:00 |与数据科学家共进午餐
  • 下午 1:00—1:30 |埃克森美孚 IT —数据科学顾问
  • 下午 1:30—2:15 |燃料和润滑油—数据科学主管
  • 下午 3:00—3:30 |埃克森美孚 IT —数据科学主管
  • 下午 3:30—4:00 |价值链优化—部门主管
  • 下午 4:00-5:00 | Python 兴趣交流活动

是的,我基本上给自己安排了一整天的信息采访,我学到了很多。

我遇到的一些人问我关于我从事的数据科学项目,而其他人分享了他们的工作和建议。由此,我意识到埃克森美孚有多大,以及正在处理的大量有趣的项目。

然而,我注意到的一个共同趋势是,每个人都有研究生学位。

最终结果

在我第二次实习的最后一天,雷切尔和我的朋友让我坐下来进行离职面谈。在那里,我会知道我是否收到了一份全职工作的回复。

令我惊讶的是,我获得了总部的一个数据科学家职位!

我付出的所有努力终于有了回报,这种感觉太棒了。我过去和现在都非常感谢所有支持我的人,他们帮助我打开大门,让这一切成为可能。

我后来得知,在我临时凑合的超级日那天和我交谈过的部门主管给我的主管打了电话,让他做出了改变。其中一个原因是因为我给数据科学团队带来了他们没有的新东西——我整整 8 个月的实习经历。

自 2019 年 5 月在埃克森美孚全职工作以来,我有机会参与各种项目,从交易建议到定价指导和设备优化,每年帮助获得 1500 多万美元。

有趣的事实:在我的一个新项目中,我帮助交付了一个全球性的产品,该产品扩展了我作为实习生所做的工作。猜猜谁是第一批产品所有者之一?——是乔治。这真是一个小世界。

外卖食品

获得数据科学职位可以归结为确保您了解基础知识,将这些知识应用到您当前的角色中,并与能够支持您并打开正确大门的正确人员联系。

所有这些都从你开始。你是司机,你的决心是带你到达目的地的燃料。

记住,你的背景是独一无二的。利用这一点,和那些认识到这一点的人在一起。当正确的门打开时,确保你准备好走进去!

最后,感激并善待你遇到的每一个人。你永远不知道将来什么时候会需要它们。

你想进入数据科学领域吗?在 LinkedIn 上留言 me !我很乐意成为你旅程的一部分。

从 Kaggle 笔记本电脑中获得“更多”

原文:https://towardsdatascience.com/getting-more-out-of-your-kaggle-notebooks-fb2530ece942?source=collection_archive---------40-----------------------

关于如何让你的 Kaggle 笔记本更具吸引力的一些建议

大约五年前,我加入了 Kaggle。我是从当时正在进行的一个 MOOC 项目中了解到这个网站的。从 2015 年到 2019 年,我一直只使用 Kaggle 下载数据集。我确实尝试了非常受欢迎的泰坦尼克号比赛来改变我的状态,从绿色变成蓝色,也就是从新手变成贡献者。尽管如此,除此之外,我在平台上并不活跃。直到 2019 年末,我才开始在 Kaggle 上积极投稿和写笔记本。从分析到探索性的数据分析,我试验了很多想法。我研究了其他人的作品,获得了灵感,学到了很多东西。最后,经过几个月的 Kaggle,我在 2020 年 6 月成为了一名 Kaggle 笔记本电脑大师。

这篇文章是我在写有效的笔记本时学到的知识的汇编。这不是指南,只是我几个月来的经历。我们先从了解什么是 Kaggle 笔记本以及如何使用开始。

什么是 Kaggle 笔记本?

一个笔记本是一种分享代码和分析的讲故事的格式。这是一个云计算环境,支持可重复的协作工作。任何人都可以在 Kaggle 中创建一个笔记本,并将图表直接嵌入其中。Kaggle 笔记本分为两种:

  • 脚本 —按顺序执行所有代码的文件
  • 笔记本 —由一系列单元格组成的 Jupyter 笔记本

在笔记本 IDE 中,您可以访问在 Docker 容器中运行的交互式会话,其中包含预安装的软件包、安装版本化数据源的能力、GPU 等可定制的计算资源等等。

让 Kaggle 笔记本发挥“更多”作用的技巧

现在,让我们快速进入我在创建新笔记本之前牢记的一些提示。

1.通过笔记本讲述引人入胜的故事

讲故事者的目的不是告诉你如何思考,而是给你问题去思考

布兰登·桑德森, 王者之道

笔记本是传达你想法的绝佳工具。它们允许您以交互方式探索数据,创建可视化效果,然后与世界共享结果。在某种程度上,你可以在同一个环境中把代码和文章结合起来。使用清晰的视觉效果来创造引人入胜的故事情节。请选择一个独特的问题,并尝试解决它。首先确定笔记本的目的,然后用一个合适的结论来总结,以创造一个有影响力的故事。

在名为 的笔记本中,极客女孩崛起:神话还是现实! 我分析了 2019 年 Kaggle ML 和 DS 关于机器学习和数据科学中女性代表性的调查数据。我选择的问题陈述是女性在 Kaggle 的参与度是否有所提高,与前几年相比如何。我通过分析性别、国家、年龄组等各种属性的数据创建了一份报告。最后,我总结了分析的要点和一些建议。

笔记本摘录: 极客少女崛起:神话还是现实!

2.与他人合作

"许多想法移植到另一个头脑中时,会比移植到它们产生的那个头脑中时长得更好。"

奥利佛·文德尔·霍马斯

协作是数据科学不可或缺的一部分,无论是在研究领域还是开源领域。在 Kaggle 比赛中,团队合作的重要性怎么强调都不为过。然而,即使是 Kaggle 笔记本也有引人注目的协作功能。多个用户可以共同拥有和编辑一个笔记本这在几种情况下可能会有帮助。

  • 当你参加比赛时,你可以在笔记本上与你的队友一起协作编写你的代码。
  • 在分析数据集时,您可以与他人协作并创建有影响力的项目报告。

创作,阅读&写数据先进熊猫 Kaggle 学习轨迹的笔记本,就是一个巨大的协作笔记本的例子。

通过 Kaggle 笔记本进行协作

3.通过初学者笔记本电脑参与竞赛

贡献是关键

你想为比赛做贡献,但还没有准备好比赛?好吧,当一个新的比赛开始时,开始写入门笔记本。这种笔记本通常有两种类型:

  • 执行基本或高级探索性数据分析的笔记本电脑。这些笔记本帮助其他人快速理解数据的性质和模式,从而节省他们大量的时间。也有人高度赞赏一款优秀的 EDA 笔记本。
  • 包含快速基线的笔记本。这种笔记本充当了寻求在比赛中竞争的人的垫脚石。他们可以使用基线来构建他们的分析。

以下是一些 EDA 和竞赛入门笔记本的浏览: SIIM-ISIC 黑色素瘤分类用于识别病变图像中的黑色素瘤

SIIM-ISIC 黑色素瘤分类竞赛笔记本

4.教一些新东西

学东西的最好方法是把它教给别人

尝试教授一个新的库或一些新的功能。这对于有时难以理解官方文档的初学者尤其有用。但是,请确保使用一些新的数据集来展示库/函数的工作。照原样复制整个文档不是一个好主意。

在笔记本 对数据科学有用的 Python 库 中,我整理了一些有用但鲜为人知的 Python 库,可以在数据分析和机器学习任务中派上用场。

Kaggle 笔记本中涵盖的库:对数据科学有用的 Python 库

同样,在笔记本用于探索性数据分析的高级 Pyspark中, Tien Tran 展示了如何使用 py spark 及其相对于 Pandas 在处理大数据方面的优势。

用于探索性数据分析的高级 py sparkka ggle 笔记本

5.当心数据可视化陷阱

观想的目的是洞察力,而不是图画。

本·施奈德曼

data-to-viz.com收集的十大 DataViz 警告

一张图肯定胜过千言万语,但是太多的图就违背了清晰的目的。如果你想让形象突出,并有助于故事情节,有几点你应该考虑。

  • 保持视觉效果简单明了。
  • 简明地解释每个图表。不要把图表留给读者去理解。让别人意识到你的观点。
  • 制作清晰易读的图表。注意色盲,制作每个人都能理解的图表。
  • 不要过度动画。只有当它们符合故事情节时才使用它。
  • 使轴和标签清晰可见。使用合适的字体选择和字体大小。显示图例和标题。

6.让您的笔记本具有可复制性

“你为什么要关心再现性呢?

因为最有可能需要复制你作品的人……就是你。”

Rachael Tatman 博士——可复制的机器学习

一个可重复的例子允许其他人使用相同的数据重新创建您的分析。这很有意义,因为你把你的作品公之于众,让他们使用。如果其他人不能不间断地复制你的作品,这个目的就失败了。Rachael Tatman 在 可重复研究最佳实践 上放了一个很棒的内核,里面列出了一些可重复工作的最佳实践。以下是来自上述研究的一些建议:

  • 把你所有的导入,导入 x 或者库(x)放在你笔记本的顶部
  • 在合乎逻辑的地方打断长行
  • 让你的变量名变得有意义和易读
  • 注释您的代码!
  • 确保设置所有的随机数发生器(RNG)
  • 确保你的代码和数据都是逻辑有序的。

下面的例子(同样取自 Rachel 的幻灯片)清楚地强调了编写干净、模块化和可重复代码的力量。

编写可重复代码的注意事项。来源

7.注意错误

“一个人的蹩脚软件是另一个人的全职工作。”

杰西卡·加斯顿

发布前运行整个笔记本。包含无法渲染的错误或图形的笔记本不是您想要与世界共享的东西;忘了拉选票吧。此外,确保连接到笔记本的数据集也没有错误。

8.分叉前向上投票

术语“分叉”来自版本控制。派生笔记本意味着按其当前状态制作一份副本。人们倾向于使用好的笔记本或基线来构建他们的代码。然而,有些人会叉一个笔记本或使用其他人的工作,但不会通过投票支持原来的工作来表示赞赏。如果你发现某人的代码如此有价值,以至于你最终使用了它,为什么不对作者表示一些感谢呢?

下面突出显示的笔记本的分叉数多于上行投票数。奇怪!

【推论,PyTorch】鸟叫 ResNet 基线 作者新井秀久

9.遵循笔记本礼仪

获得灵感是人之常情,但抄袭是邪恶的

  • 不要直接从其他笔记本中提取内容。如果你认为你想重用一大块代码,给出明确的归属。
  • 避免通过要求投票来滥发笔记本。一个好的笔记本会吸引其他同事的注意。你也可以把你的内容放在社交媒体上,比如 Linkedin 到 Twitter,告诉全世界你已经创建了一个新的笔记本。但是不要一直要求投票,尤其是为了回报你投的票。

10.对好的工作表示赞赏

表达感激是人类能为彼此做的最简单也是最有力的事情之一

最后,请不要回避欣赏伟大的笔记本,给他们投票并大声喊出来。这里有一个欣赏他人作品的好例子,作者是 Kaggle GM — 正面还是反面。他定期展示 Kaggle 笔记本,他觉得这些笔记本没有得到应有的重视。

正面或反面显示的隐藏宝石笔记本帖子

结论

Kaggle 笔记本是传达你想法的好工具。搜索或管理一些很酷的数据集,并使用笔记本来创建一些出色的分析。最后,不要忘记享受这个过程。从奇妙的 Kaggle 社区可以学到很多东西。但最重要的是尝试——因为成功的秘诀在于开始。

这个故事最初发表于 这里

为你的下一个地理项目获取 NASA 数据

原文:https://towardsdatascience.com/getting-nasa-data-for-your-next-geo-project-9d621243b8f3?source=collection_archive---------31-----------------------

访问 GES 光盘数据文件

美国宇航局在 Unsplash 拍摄的照片

美国宇航局提供了一个庞大的数据点库,这些数据点是他们多年来从卫星上捕捉到的。这些数据集包括温度、降水等。美国国家航空航天局将这些数据保存在一个网站上,你可以根据需要搜索和获取信息,无论你想要的是整个世界的数据还是特定区域的数据。用户可以选择特定的日期范围,寻找总的时间范围(小时,天,月等)。).可能性是无限的。

在本文中,让我们探索这个巨大的资源,我将描述一个从网站收集数据的一步一步的过程。

GES 圆盘

GES 圆盘代表 NASA 戈达德地球科学(GES)数据和信息服务中心。这是一个数据仓库,存放着关于降水、水文、大气等方面的遥感数据。它旨在使研究人员和应用程序开发人员能够访问 NASA 的数据,然后他们可以使用这些数据进行分析和创建应用程序。

[## GES 圆盘

美国宇航局统一用户界面,UUI,数据,GES 光盘,数据集

disc.gsfc.nasa.gov](https://disc.gsfc.nasa.gov/)

数据收集

让我们浏览一下从 GES 光盘中检索数据的步骤。在这篇特别的文章中,我将介绍下载降水数据的步骤,为此,我将下载 GPM 月数据。 GPM 代表全球降水测量,这是 JAXA 和美国宇航局的一个合资项目,旨在获取全球降水数据。

1.注册

数据仓库位于这里。在下载数据之前,您需要在 earthdata 网站上创建一个帐户。只需在这个网站上创建一个帐户,验证你自己,你应该可以去。

选择右上角的登录按钮。如果您有帐户,请登录,否则选择注册按钮进行注册。

2.搜索

一旦我们登录,我们就可以开始了。网站会用一个搜索框来欢迎你,默认情况下会选择数据收集。我们正在这个集合本身中寻找数据,所以我们将顺其自然,并开始在搜索框中键入。

在这里,我将在搜索框中输入降水,然后按黄色搜索按钮来获取可用的数据集。您会注意到一个加载图标,表明系统正在处理我们的搜索查询,并将返回与搜索查询匹配的数据集列表。

GES 光盘主页

3.浏览数据集列表

搜索完成后,您将看到一个包含与查询匹配的各种数据集的表格,并在左侧看到一个过滤器部分。该表包括图像、数据集名称、源、空间半径、数据收集开始日期和数据收集结束日期等信息。根据您的具体要求,您可以使用左侧的过滤器,并选择有助于获得最精确数据的条件。

降水的搜索结果

在这个例子中,我在寻找 GPM 月度数据。因此,在过滤器中,在项目下,我选择了 GPM。这过滤了属于 GPM 的数据集。从时间分辨率列,我寻找分辨率为 1 个月的数据集。这意味着数据是按月汇总的。

使用 GPM 过滤器搜索降水的结果

从列表上看是第三个数据集叫做 GPM IMERG 最终降水量 L3 1 月 0.1 度 x 0.1 度 V06 (GPM_3IMERGM 06) 。为了探索关于这个数据集的更多信息,我只需单击它的名称(这是一个超链接),它就会将我带到数据集页面。

4.浏览数据集页面

该页面包含数据集的详细信息以及一幅图像。接下来是数据集的汇总(称为产品)。最重要的部分是我们在屏幕右侧看到的按钮。您可以探索各种服务等等,但我们感兴趣的是链接子集/获取数据。这是我们开始下载数据的步骤。点击此链接。

数据集页面

5.选择数据

单击该链接时,会出现一个弹出窗口,如下图所示。

带有下载选项的弹出窗口

我们得到的数据集非常庞大,因为它涵盖了全球数年的信息。一个好主意是选择你正在寻找的某个日期范围和地球的某个区域。

在这里的例子中,我将捕获所有的原始文件,这意味着所有的变量。我把范围细化一下,从 2001 年 1 月 1 日到 2020 年 12 月 31 日。最后,根据上面的选择,您可能会看到输出格式的某些选项。当我选择原始文件时,我只看到 HDF5。

从完整数据集中选择特定数据

我使用过 HDF5 文件格式,有一个非常简单的包 h5py 可以让你直接将这些文件读入 python。但是为了查看这些文件,经常使用一个流行的软件,HDFView。

接下来,按下按钮获取数据,它将开始运行,以生成一些链接,允许您下载数据。

6.下载数据

弹出窗口显示链接列表,每个链接对应于基于选择的一个数据文件。从这里下载数据有两种方式。

下载数据集的链接

6.1 一次一个文件

单击您要下载的数据文件的链接。如果您已登录,数据集将开始下载。它快速、简单,不需要额外的步骤来下载数据。

6.2 一次多个文件

但是,如果您正在下载多个文件(比如 30-40 个文件),这不是最有效的方法。使用 curl ,你可以使用一个简单的命令下载所有的文件。

curl 是一个命令行工具,用于使用各种网络协议传输数据。

然而,要使用 curl 下载这些数据文件,我们第一次需要执行一些步骤。完整的说明因操作系统而异,此处提供

以下是以最简单的方式理解术语的步骤概述(在 MacOS 上是这样的):

获取所有链接

在链接列表上方,您会看到一个名为下载链接列表的链接。当你点击它,一个新的标签打开,所有的链接都在一个地方。选择并复制所有文本,并将其保存到机器上名为 url.txt 的文件中。

创建所需文件

在终端中,执行以下操作:

  • 使用cd ~前往您的家
  • 创建一个新文件。使用touch .netrc的 netrc 和使用touch .urs_cookies的另一个文件,用于在多个 curl 调用期间跟踪会话
  • 我们现在将登录凭证保存在该文件中。键入命令echo “machine urs.earthdata.nasa.gov login <uid> password <password>” >> .netrc,同时用您的用户名替换 < uid > ,用您的密码替换 <密码>
  • 使用chmod 0600 .netrc更改其访问权限
  • 在您的文件 url.txt 所在的终端中键入命令cat url.txt | tr -d ‘\r’ | xargs -n 1 curl -LJO -n -c ~/.urs_cookies -b ~/.urs_cookies,所有文件将被一个接一个地下载。

wget 也是另一个选项,但是我没有用过它,因为 curl 表现很好,而且我觉得没有必要尝试 wget。

7.图像数据

一旦下载了 HDF5 文件,您就可以使用 HDFView 打开这些文件并查看数据集。你需要一个帐户来下载这个软件。

[## HDF 观点-HDF 集团

当前版本:HDFView 3.1.1 HDFView 软件由 HDFView 实用程序和 Java HDF 对象包组成…](https://www.hdfgroup.org/downloads/hdfview/)

数据可以以其他格式下载,如 netCDF、ASCII 等。也有处理这些文件的方法,但是我没有亲自处理过。

高清视图

我们都准备好了!!

结论

您现在有一组数据文件,其中包含 NASA 多年来收集的丰富数据,您可以将这些数据用于自己的工作。在下一篇文章中,我将描述用 Python 读取 HDF5 文件并理解其组件以使用数据的步骤。

希望这是有见地的。如果你有任何问题、想法或建议,请在评论中提出。

开始使用:Python I/O

原文:https://towardsdatascience.com/getting-start-with-python-i-o-9a28ce635ba4?source=collection_archive---------48-----------------------

Python I/O 概述

Python 如何与 I/O 交互的快速演示

照片由克里斯蒂娜·莫里尔Unsplash 拍摄

有几种方法可以显示程序的输出;数据可以以人类可读的形式打印出来,或者写入文件以备将来使用。

Python 3 文档。

在开始时,ASCII 由 128 个字节表示;这些人物是在考虑使用英语的情况下创造出来的;因此,如果你死在一个像中国这样的国家,那里你的语言基础是特殊字符,这是不可能的,因为那时新的编码类型被创造出来了。例如,ISO-8859–1 编码(也称为 Latin_1)考虑的是西欧,如法国、西班牙、葡萄牙,但问题仍然存在,如果日本开发人员试图读取我们的文件怎么办?然后,一种新的编码类型 utf-8 诞生了,它支持超过 100 万个字符,包括阿拉伯语、汉语、俄语字符以及特殊字符。我们硬盘上的文件是以字节写的,所以我们可以知道读取这些字节的正确方式,编码提供了这一点,所以我们可以找出解码这些字节的正确方式。

开文件

首先,要知道我们文件的内容,我们需要打开它。

>>> f = open(‘workfile’ ,’r’, encoding='utf-8')

函数 open return 是我们文件的一个表示,或者你也可以理解为一个文件对象。函数 open 的第二个参数是我们的文件将被打开的模式,在这个例子中我们使用模式 r。

读取文件

现在,我们将看到读取文件的三种可能方式。

>>> f = open(‘workfile’ ,’r’)>>> f.readline()
>>> f.readlines()
>>> f.read()

方法 readline: 从文件中读取一行。

方法 readlines: 返回一个列表,其中每一项都是文件中的一行。因此,您可以迭代内容变量,以显示文件中的所有行。

方法 read: 以字符串格式返回文件的所有内容。

写文件

我们已经知道如何打开一个现有的文件,现在我们将了解如何写入一个文件。

>>> f = open(‘workfile’ ,’w’)>>> f = open(‘workfile’ ,’w’)>>> new_content = 'someContent'
>>> f.write(new_content)

在这个例子中,我将写入一个现有的文件。当我使用 W(录制)模式时,如果你打开文件,你会看到旧的内容已经被删除,现在只有我们添加的内容在文件中。这就是录音模式的工作原理。
另一种保存文件的方式是使用 A()模式,这种模式不替换文件的内容,相反,新的内容被添加在文件内容的末尾。

关闭方法

你可能会问自己:我为什么要关闭我的文件?当我完成我的任务时,一切都将从记忆中清除,一切都很好。

嗯,你没有错。当你写一个文件时,Python 只在我们的应用程序完全完成时才释放我们的文件,也就是说,如果你有一个正在运行的进程或一个需要很长时间才能完成的大任务,如果你将信息写入一个文件,你将无法访问这些内容,直到你的应用程序完全完成,close 方法来帮助我们解决这个问题。

>>> f = open(‘workfile’ ,’w’)>>> new_content = 'someContent'
>>> f.write(new_content)
>>> f.close()

冲洗方法

考虑上面的相同场景,您有一个需要在文件中插入一些数据的长任务,并且有几个例程将被执行,直到您的应用程序完成。但是,您需要向该文件添加更多信息。关闭并打开文件不是最佳解决方案。

你可以刷新,基本上,强迫 Python 插入文件中已经存在的东西,这样,如果你在应用程序完全完成之前打开它,数据将已经保存在文件中。

>>> f = open(‘workfile’ ,’w’)>>> new_content = 'someContent'
>>> f.write(new_content)
>>> f.flush()
.
.
.

求法

这个方法将内存指针指向作为参数传递的数值位置,这个函数没有返回值,所以您需要使用它,然后使用一个读取方法在您指定的位置准确地显示它的内容。

>>> f = open(‘workfile’ ,’w’)>>> new_content = 'someContent'
>>> f.write(new_content)
>>> f.seek(0)
>>> line = f.readline()
>> print line
someContent

结论

使用 Python 文件很容易,这种语言的工作方式和给我们的反馈令人印象深刻。使用这些示例性的方法,您将能够在某些情况下有效地工作,但是如果您想迈出更大的一步,您必须理解,存在文件竞争的环境是一个更复杂的情况,但是更现实的是,这里展示的是以简单和正确的方式处理文件的基础。

入门指南— Anaconda

原文:https://towardsdatascience.com/getting-started-guide-anaconda-80a4d30d3486?source=collection_archive---------21-----------------------

Python 发行版的开源平台

简·kopřiva 在 Unsplash 上的照片

随着对 Python 编程语言需求的不断增长,任何初学者都面临的第一个任务是建立正确的开发环境。

本教程旨在向您介绍 Anaconda 平台,这是 Python 和 R 编程语言的免费开源发行版,用于科学计算,以简化包管理和部署。

a.)为什么是 Anaconda?

有多种原因使得 Anaconda 成为 Python 初学者的首选:

  • 一个完整的解决方案——与其他 Python ide(py charm、Pydev、Spyder)不同,Anaconda 不仅提供了易于使用的编程接口,还使包管理、虚拟环境管理等任务变得简单。
  • 预装包—Python 的强大来自于社区多年来开发的数千个包。如果使用标准 Python 安装,所有第三方 Python 包的安装都需要 pip (Python 事实上的标准包管理系统)。Anaconda 解决了这个问题,因为它预装了最常用的 Python 包。
  • 简单的 GUI—Anaconda 发行版预装了两个最用户友好的 Python IDEs,Jupyter Notebook(本教程的重点)和 Spyder。

b.)入门

下面列出了首次使用 Anaconda 的简单说明:

1。)下载 —转到此链接并选择您系统的操作系统(Windows/ Mac/ Linux)。检查您的系统详细信息,确定您的系统是 64 位还是 32 位处理器。根据以上信息,下载 Python 的版本 3。X (X 是最新版本)。

Anaconda 下载屏幕(图片由作者提供)

2.)启动安装程序 —在 Windows 上安装 Anaconda 就像安装其他任何软件一样简单。只需启动安装程序,并继续点击下一步下一步。安装程序会在几个地方寻求您的偏好。我的建议是去安装推荐的设置,不要改变任何东西。安装将在 8 到 10 分钟内完成。

3.)启动 Anaconda 提示符 —默认情况下,Anaconda 发行版会安装 Python 和支持软件应用程序。你可以在你的窗口开始菜单Anaconda 文件夹中找到这些应用程序。启动名为 Anaconda 提示符的 Python open 应用程序。提示如下所示:

蟒蛇提示(图片由作者提供)

4。)启动 Python —在提示符下,键入 python,并按回车。您将看到屏幕上出现一个带有 Python 版本号的标准文本。除此之外,提示还会变成 3 个尖括号> > >。现在,你可以开始编写你的 Python 代码了。要退出 Python 环境,请键入 exit() 并按 enter 键

启动 Python(图片由作者提供)

5。)一个更好的界面——在上一步中,我们看到了 Anaconda 提示符,这是 Python 的命令行界面。Jupyter notebook 是一个基于 GUI 的 IDE,与 Anaconda 打包在一起。我们也可以从 Windows 开始菜单文件夹中启动它。由于应用程序是在网络浏览器中打开的,因此对于使用多种浏览器的用户来说,在启动应用程序时会出现一个提示,要求输入您的首选浏览器选项。主屏幕将如下所示:

Jupyter 主屏幕(图片由作者提供)

6。)创建新笔记本——Jupyter Notebook 是一个一站式商店,从编写 Python 代码创建可视化、编写减价文档。要创建一个新的笔记本,点击主屏幕右上角的 new 下拉菜单,然后点击 Python 3

启动笔记本(图片由作者提供)

7。)编写您的第一个 Python 代码 —以上步骤将在 web 浏览器的新标签页上打开一个笔记本,其中有一个单元格处于编辑模式。在这个单元格中,您可以编写 Python 程序。写一个简单的数学运算(1+2)和shift+enter 。您将看到数学运算的结果,以及在前一个单元格之后在编辑模式中添加的新单元格。下面是一个示例截图供您参考:

Jupyter 笔记本(图片由作者提供)

8。)快捷方式—Jupyter 笔记本中的每个单元格既可以处于编辑 ( ,光标闪烁,单元格以绿色高亮显示)也可以处于选择模式(,没有光标,单元格以蓝色高亮显示)。每款笔记本都提供了一些快捷方式,方便用户快速浏览笔记本:

与单元模式无关的快捷键:

  • 执行写入当前单元格的代码— Cntrl + Enter
  • 执行当前单元格中写入的代码,并在下面插入一个新代码— Shift + Enter

选择模式下的快捷键

  • 在当前单元格之前添加新单元格— A
  • 在当前单元格后添加一个新单元格— B
  • 切割一个单元格— X
  • 复制单元格— C
  • 粘贴单元格— V
  • 删除单元格— D..D(按两次 D)
  • 撤消删除的单元格— Z
  • 向下滚动笔记本— 空格键
  • 向上滚动笔记本— Shift +空格键
  • 将单元格模式从选择改为编辑— 输入

处于编辑模式时

  • 退出编辑模式— Esc
  • 自动完成 Python 命令— 选项卡
  • 右缩进代码—Cntrl+】
  • 左缩进代码— Cntrl+[
  • 撤消— Cntrl+Z
  • 重做— Cntrl+Y

c.)结束语

我希望该教程易于理解,并且您可以开始使用 Anaconda。

接下来,学习使用 Anaconda 管理 Python 环境。

快乐学习!!!!

人工智能研究入门

原文:https://towardsdatascience.com/getting-started-in-ai-research-a683e6845537?source=collection_archive---------45-----------------------

关于如何有助于确认一些最新论文的可重复性和加入开放搜索研究的指南。

菲利普·伯恩特在 Unsplash 上的照片

介绍

如今,对人工智能(AI)研究的关注每年都在增长,特别是在深度学习、强化学习和自然语言处理等领域(图 1)。

图 1:人工智能研究的增长[1]

人工智能的最新研究通常是在顶尖大学的研究小组和专注于研究的公司进行的,如 Deep Mind 或 Open AI,但如果你想在业余时间做出自己的贡献呢?

在这篇文章中,我们将探讨你可以采取的不同的方法,以便始终跟上最新的研究,以及如何提供你自己的贡献。

再现性挑战

影响人工智能研究领域的一个主要问题是可能无法有效地再现一些出版物中声称的模型和结果(再现性挑战)。

事实上,每年发表的许多研究文章只包含对被嘲笑的主题和开发的模型的解释,而没有源代码来重现他们的结果。研究人员有时可能会忽略这类信息的一些原因是:保持对其他机构的竞争优势、保密协议、将他们的研究转化为产品等…

为了使研究更容易获得并产生现实世界的影响,已经创建了不同的竞赛,以鼓励公众研究不同的出版物并试图再现他们的结果。这一领域最著名的两个竞赛是 NeurIPSICLR 再现性挑战。如果你正在寻找任何实际的例子,我最近开始了一个关于这个主题的 GitHub 知识库

此外,像代码为的论文这样的网站最近已经创建,以便于找到已经公开代码的研究出版物。这样,任何人都可以完全免费地为自己的项目使用最先进的模型!

[## 带代码的论文——机器学习的最新进展

带代码的论文突出了 ML 研究的趋势和实现它的代码。

paperswithcode.com](https://paperswithcode.com/)

医生的季节

“文档季”是 Google 组织的一项年度计划,旨在将技术作者与开源组织联系起来,以改进图书馆文档。

图 2:文档的季节[2]

事实上,通过加入该计划,作者将能够为诸如 Julia、Numpy、Matplotlib、Bokeh 等开源组织的文档做出贡献。

[## 文档季|谷歌开发者

让我们把开源和技术作者社区聚集在一起,让双方都受益。我们一起提高意识…

developers.google.com](https://developers.google.com/season-of-docs)

GitHub 开源贡献

许多现在最流行的机器学习和深度学习库都可以在 GitHub 上获得,其中大多数都很乐意接受外部贡献者的帮助。一些流行的 GitHub 库的例子有许多问题和接受贡献者的拉请求:

如果你想探索更多可用的项目, GitHub 集合是一个很好的起点(例如机器学习)。

两份会议记录文件

另一种保持与最新研究保持同步的方法是关注在线出版物,如走向数据科学和关注研究的 YouTube 频道,如 Two Minute Papers。

[## 两份会议记录文件

每个人都很棒的研究。每周两个新的科学视频。你会喜欢的!我们的链接:Web →…

www.youtube.com](https://www.youtube.com/channel/UCbfYPyITQ-7l4upoX8nvctg)

事实上,这个 YouTube 频道每周都会为您回顾和总结一些最有趣的最新出版物,并提供演示和示例应用程序。

临时演员

最后,为了保持对人工智能的不断更新,其他可能的方法是:

如果你有任何可以添加到这个列表中的其他技术的建议,请在评论区告诉我!

希望你喜欢这篇文章,谢谢你的阅读!

联系人

如果你想了解我最新的文章和项目,请在媒体上关注我,并订阅我的邮件列表。以下是我的一些联系人详细信息:

文献学

[1]Yoav sho ham 等人的《人工智能指数 2018 年度报告》。艾尔。访问网址:http://cdn . aiindex . org/2018/AI % 20 index % 202018% 20 annual % 20 report . pdf

[2] Reactome,Docs 的季节。访问地点:https://reactome.org/about/news/136-season-of-docs

从 Ken Jee 开始学习数据科学

原文:https://towardsdatascience.com/getting-started-in-data-science-with-ken-jee-98045a74651d?source=collection_archive---------71-----------------------

山姆·伯克的照片。

“你是如何开始机器学习和数据科学的?”【面试】

丹尼尔·伯克 — 10 分钟阅读

有一天,绝对完整的活着的传奇人物,数据科学的负责人和令人难以置信的数据科学相关 YouTube 视频的创作者,Ken Jee 找到我,问我是否想合作一个(或两个)视频。

如何赋予您的微生物组数据生命

露丝·施密特 — 8 分钟阅读

我是一名微生物生态学家,这意味着我研究微生物如何相互作用及其环境。最近,我进入了数据科学的世界,这要感谢我从 Mitacs 获得的与数据分析和可视化公司 Plotly 合作的奖学金。

背景照片由内森·奎洛兹拍摄

德勤的数据科学

由杰瑞米·哈里斯 — 3 分钟阅读

不同公司的数据科学看起来可能大相径庭,通常很难就数据科学家到底是什么这个问题达成一致意见。这就是为什么与在不同组织(从初创公司到企业)应用其技能的数据科学家交流如此重要。

在交互式可视化中最小化重叠标签

韦德·法詹-乌尔姆·施奈德——4 分钟阅读

用户控制和实时数据可视化最具挑战性的领域之一是标签放置。在我的许多可视化中,我试图设计标签不可能重叠的可视化——完全避免这个挑战性的问题——但在我最近的可视化中,这不是一个选项。

R markdown 入门

原文:https://towardsdatascience.com/getting-started-in-r-markdown-2d3de636bde3?source=collection_archive---------21-----------------------

如何在 R 中生成动态的、可复制的 PDF 或 HTML 文档

乔恩·泰森拍摄的照片

如果你花了一些时间用 R 编写代码,你可能听说过生成包含 R 代码、R 输出(结果)和文本或注释的动态报告。在本文中,我将解释 R Markdown 是如何工作的,并为您提供在制作这些动态报告时轻松入门所需的基本要素。

R Markdown:什么、为什么和如何?

R Markdown 允许生成一个报告(大部分时间以 PDF、HTML、Word 或 beamer 演示的形式),该报告是从 RStudio 中编写的文件自动生成的。生成的文档可以作为您的分析的整洁记录,可以在详细和完整的报告中共享和发布。即使你从没想过要把结果展示给别人,它也可以作为一个个人笔记本来回顾,这样你就可以看到你当时做了什么。R Markdown 文件的扩展名为.Rmd,而 R script 文件的扩展名为.R

与 R 相比,使用 R Markdown 的第一个主要优点是,在 R Markdown 文档中,您可以组合任何统计分析的三个重要部分:

  • r 代码显示分析是如何完成的。例如,您使用的数据和函数。这允许读者跟踪您的代码,并检查分析是否正确执行。
  • 代码的结果,也就是分析的输出。例如,线性模型的输出、图或刚刚编码的假设检验的结果。这使得读者可以看到你的分析结果。
  • 结果的文本、注释和解释。例如,在计算主要的描述性统计数据并绘制一些图表后,您可以在您的问题的上下文中解释它们并突出重要的发现。由于你的解释和评论,读者能够理解你的结果,就好像你写了一份文件来解释你的工作一样。

R Markdown 的另一个优点是报告是动态的,任何有权访问.Rmd文件(如果使用外部数据,当然还有数据)的人都可以复制,这使得它非常适合协作和结果的传播。所谓动态,我们的意思是,如果您的数据发生变化,您的结果和解释也会相应地发生变化,而无需您做任何工作。

报告的制作分两个阶段完成:

  1. 包含 R 代码块(称为块)和文本的.Rmd文件被提供给{knitr}包,该包将执行 R 代码以获得输出,并创建 markdown ( .md)格式的文档。然后,这个文档包含 R 代码、结果(或输出)和文本。
  2. 然后这个.md文件被基于 pandoc 的markdown包(即一个文档转换工具)转换成想要的格式(HTML、PDF 或 Word)。

开始之前

要创建一个新的 R Markdown 文档(.Rmd),您首先需要安装并加载以下软件包:

install.packages(c("knitr", "rmarkdown", "markdown"))library(knitr)
library(rmarkdown)
library(markdown)

然后点击文件->新文件-> R Markdown,或者点击左上角带有绿色十字的白色小表格,然后选择R Markdown:

创建新的 R Markdown 文档

一个窗口将会打开,选择标题和作者,然后点击确定。默认的输出格式是 HTML。以后可以改成 PDF 或者 Word。

点击 OK 后,一个新的用作示例的.Rmd文件就创建好了。我们将使用这个文件作为我们更复杂、更个性化的文件的起点。

要将 R Markdown 文档编译成 HTML 文档,请点击顶部的Knit按钮:

编织一个 R 减价文件

出现 HTML 报告的预览,它也保存在您的工作目录中(参见什么是工作目录的提示)。

.Rmd文件的组成部分

R Markdown 文档的主要组成部分如下:

这些组件将在以下章节中详细介绍。

YAML 头球

一个.Rmd文件以 YAML 头文件开始,由两个---序列包围。默认情况下,这包括报告的标题、作者、日期和格式。如果您想在 PDF 文档中生成报告,请将output: html_document替换为output: pdf_document。编译报告后(即编制文档后),YAML 标题中的信息将出现在所生成报告的顶部。

要向您的文档添加目录,请将output: html_document替换为

output:
  html_document:
    toc: true

以下是我关于 HTML 文档格式的常用设置(如果你以 PDF 格式呈现文档,请删除number_sections: true之后的所有内容,因为 PDF 文档不接受 YAML 标题中的这些选项):

output:
  html_document:
    toc: true
    toc_depth: 6
    number_sections: true
    toc_float: true
    code_folding: hide
    theme: flatly
    code_download: true

除了添加目录外,它还设置了深度,添加了章节编号,向下滚动文档时目录是浮动的,默认情况下代码是隐藏的,使用了flatly主题,并增加了下载.Rmd文档的可能性。

甚至在编织文档之前,您就可以可视化您的目录,或者通过单击右上角的小图标直接转到特定部分。您的目录将会出现,单击一个部分即可转到您的.Rmd文档中的该部分:

可视化你的目录

除了这个增强的目录之外,我通常在 YAML 页眉中设置以下日期:

R 降价中的动态日期

这段代码允许我写下当前的日期,而不必自己修改。这对于持续几周或几个月的项目来说非常方便,因为在文档的顶部总是有一个更新的日期。

代码块

在 YAML 标题的下面,有一个第一代码块,用于你的整个文档的设置选项。目前最好就这样,如果需要的话,我们可以以后再换。

R Markdown 文档中的代码块用于编写 R 代码。每次你想包含 R 代码时,你都需要用三个反撇号把它括起来。例如,为了计算值 1、7 和 11 的平均值,我们首先需要通过点击位于顶部的Insert按钮并选择 R 来插入一个 R 代码块(见下图),然后我们需要在刚刚插入的代码块中写入相应的代码:

在 R Markdown 中插入 R 代码块

代码块示例

在示例文件中,可以看到第一个 R 代码块(setup 代码块除外)包含了预加载数据集cars : summary(cars)的函数summary()。如果您查看从这个示例文件生成的 HTML 文档,您将会看到汇总度量就显示在代码块之后。

这个示例文件中的下一个代码块是plot(pressure),它将产生一个绘图。尝试编写其他 R 代码并编织(即,通过单击编织按钮来编译文档)文档,以查看您的代码是否正确生成。

如果您已经用 R 脚本编写了代码,并且希望在 R Markdown 文档中重用它,那么您可以简单地将代码复制粘贴到代码块中。不要忘记总是将代码包含在代码块中,否则 R 会在编译文档时抛出错误。

如你所见,与我上面给出的平均值的代码块相比,该图的代码块中有两个额外的参数。字母r后面的第一个参数(两者之间没有逗号)用于设置块的名称。一般来说,不要为此费心,它主要用于指代特定的代码块。您可以删除程序块的名称,但是不要删除{}之间的字母r,因为它告诉 R 后面的代码对应于 R 代码(是的,您读得很好,这也意味着您可以包含来自另一种编程语言的代码,例如 Python、SQL 等。).

在块的名称之后(在示例文件中的pressure之后),您可以看到有一个附加的参数:echo=FALSE。这个参数称为选项,表示您想要隐藏代码,只显示代码的输出。试着去掉它(或者改成echo=TRUE),你会看到在编织文档之后,代码和输出都会出现,而之前只出现结果。

您可以为每个代码块单独指定是隐藏还是显示代码以及该代码的输出,例如,如果您希望显示某些代码块的代码,而不是其他代码块的代码。或者,如果您想总是隐藏/显示整个文档的代码和输出,您可以在位于 YAML 头后面的安装代码块中指定它。传递给此安装程序代码块的选项将决定所有代码块的选项,除了那些已被特别修改的代码块。

默认情况下,当您打开一个新的 R Markdown 文件时,唯一的设置选项是knitr::opts_chunk$set(echo = TRUE),这意味着默认情况下,所有输出都将伴随有其相应的代码。如果您想只显示结果而不显示整个文档的代码,请用knitr::opts_chunk$set(echo = FALSE)替换它。通常传递给这个设置代码块的另外两个选项是warning = FALSEmessage = FALSE,以防止在报告上显示警告和消息。如果要传递几个选项,不要忘记用逗号分隔它们:

代码块的几个选项

您也可以选择显示代码,但不显示结果。为此,传递选项results = "hide"。或者,使用选项include = FALSE,您可以防止代码和结果出现在完成的文件中,而 R 仍然运行代码,以便在以后的阶段使用它。如果你想阻止代码和结果出现,并且不想让 R 运行代码,使用eval = FALSE。要编辑图形的宽度和高度,使用选项fig.widthfig.height。另一个非常有趣的选项是tidy = 'styler'选项,它会自动重新格式化输出中显示的 R 代码

在此查看所有选项及其描述或通过运行str(knitr::opts_chunk$get())查看默认选项列表。

提示:在编写 R Markdown 时,你经常需要插入新的 R 代码块。要更快地插入新的 R 代码块,在 Windows 上按CTRL + ALT + I或在 Mac 上按command + option + I。如果你对这些让你更有效率的快捷方式感兴趣,请看 R Markdown 中的其他提示和技巧。

请注意,如果您想检查某个特定代码块的结果,代码块可以在不需要编译整个文档的情况下运行。为了运行特定的代码块,选择代码并像在 R 脚本(.R)中一样运行它,方法是单击 run 或按 Windows 上的CTRL + Enter或 Mac 上的command + Enter。这个代码块的结果将直接显示在 R Markdown 文档中,就在代码块的下面。

文本

文本可以添加到代码块之外的任何地方。R Markdown 文档使用 Markdown 语法来格式化文本。在我们的示例文件中,就在安装代码块的下面,插入了一些文本。要插入文本,您只需简单地编写没有任何封闭的文本。尝试添加一些句子并编织文档,看看它在 HTML 文档中是如何出现的。

R 代码块示例下面的文本示例

Markdown 语法可用于更改出现在输出文件中的文本格式,例如将某些文本格式化为斜体粗体粗体等。下面是一些常见的格式化命令:

  • 标题:# Title
  • 字幕:## Subtitle
  • 子标题:### Subsubtitle。如果您包含目录,这些标题将自动包含在目录中。
  • 斜体 : *italics*_italics_
  • 加粗 : **bold**__bold__
  • 链接 : [link](https://www.statsandr.com/)(如果是外部 URL,不要忘记https://)
  • 方程式:

用一个$将你的方程式(用 LaTeX 写的)附在正文中:

$A = \pi*r^{2}$

这是一个众所周知的等式 a =π∫r^2.

用两个$$把你的 LaTeX 方程括起来,让它集中在新的一行上:

$$A = \pi*r^{2}$$

这是另一个众所周知的等式:

列表:

  • 无序列表,项目 1: * Unordered list, item 1
  • 无序列表,项目 2: * Unordered list, item 2
  1. 有序列表,项目 1: 1\. Ordered list, item 1
  2. 有序列表,项目 2: 2\. Ordered list, item 2

文本中的代码

在继续之前,我想介绍一下 R Markdown 的一个重要特性。通常情况下,当撰写解释或详细分析时,我们希望在文本中直接引用结果。例如,假设我们在iris数据集上工作(预加载在 R 中)。我们可能要用文字解释,花瓣长度的平均值是某个值,而中位数是另一个值。

如果没有 R Markdown,用户将需要计算平均值和中值,然后手动报告。由于 R Markdown,可以直接在文本中报告这两个描述性统计数据,而无需手动编码。更好的是,如果数据集因为我们删除了一些观察值而发生了变化,那么生成的文档中报告的平均值和中值将会自动变化,而我们这边的文本不会有任何变化。

我们可以通过放置一个反撇号、字母r、空格、代码,然后用另一个反撇号结束它,直接在解释(即文本)中插入结果:

R Markdown 中的内联代码

以下是一个句子中整合的iris数据集的萼片长度的平均值和中值:

内联代码和文本的示例

文本和代码的组合将在生成的报告中给出以下输出:

萼片长度的平均值为 5.8433333,标准差为 0.8280661。

这种技术被称为内联代码,允许您将结果直接插入到 R Markdown 文档的文本中。如前所述,如果数据集发生变化,包含在文本中的结果(在我们的例子中是平均值和标准偏差)将自动调整到新的数据集,就像数据集发生变化时代码块的输出会动态更新一样。

这种内联代码技术,以及可以组合代码、代码输出和文本来注释输出的事实,使得 R Markdown 成为我进行统计分析时最喜欢的工具。自从我发现了 R Markdown 的强大功能(我仍在学习,因为它有大量的可能性和特性),我几乎再也不用脚本编写 R 代码了。我写的每一个 R 代码都由 R Markdown 文档中的文本和内联代码补充,从而产生一个专业而完整的最终文档,可以随时共享、发布或存储以供将来使用。如果您对这种类型的文档不熟悉,我邀请您了解更多,并在您的下一个分析中尝试一下,您很可能不会再使用 R 脚本了。

突出显示文本,就像它是代码

除了内联代码技术之外,您可能希望在生成的报告中让一些文本看起来像是一段代码,而不是实际运行它。

为此,用反勾号(内联代码使用的同一个反撇号)将文本括起来,不带字母r。写下以下内容:

将在生成的报告中生成以下内容:

例如,在这句话中,我想突出显示数据帧 *iris* 中的变量名 *Species* ,就好像它是一段代码。

单词“物种”和“鸢尾”出现并被突出显示,就好像它是一段代码。

形象

除了代码、结果和文本,您还可以在最终文档中插入图像。要插入图像,请将其放在工作目录中,并放在代码块之外,编写:

![](path_to_your_image.jpg)

请注意,文件/url 路径没有用引号括起来。要为您的图像添加替代文本,请将其添加到方括号[]之间:

![alt text here](path_to_your_image.jpg)

桌子

在 R Markdown 文档中插入表格有两个选项:

  1. {knitr}包中的kable()功能
  2. {pander}包中的pander()功能

下面是一个没有任何格式的表格示例,同样的代码在iris数据集上应用了两个函数:

# without formatting
summary(iris)##   Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
##  Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100  
##  1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300  
##  Median :5.800   Median :3.000   Median :4.350   Median :1.300  
##  Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199  
##  3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800  
##  Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500  
##        Species  
##  setosa    :50  
##  versicolor:50  
##  virginica :50  
##                 
##                 
### with kable()
library(knitr)
kable(summary(iris))

# with pander()
library(pander)
pander(summary(iris))

pander()相对于kable()的优势在于,它可以用于比 table 更多的不同输出。尝试你自己的代码,例如线性回归或简单向量的结果。

附加说明和有用的资源

对于更高级的用户来说,R Markdown 文件也可以用来创建闪亮的应用、网站(这个网站的建立得益于 R Markdown 和{blogdown}包),根据几个国际期刊的模板写科学论文(用{rticles}包),甚至写书(用{bookdown}包)。

要继续了解 R Markdown,请查看 R 工作室团队的两个完整的备忘单这里这里,以及由 Yihui Xie、J. J. Allaire 和 Garrett Grolemund 编写的更完整的指南这里

感谢阅读。我希望这篇文章能说服你在未来的项目中使用 R Markdown。查看 R Markdown 中的更多提示和技巧以进一步提高 R Markdown 的效率。

和往常一样,如果您有与本文主题相关的问题或建议,请将其添加为评论,以便其他读者可以从讨论中受益。

相关文章:

原载于 2020 年 2 月 18 日 https://statsandr.com**

入门:Nvidia Jetson Nano,对象检测和分类

原文:https://towardsdatascience.com/getting-started-nvidia-jetson-nano-object-detection-and-classification-161ad566d594?source=collection_archive---------17-----------------------

设置 Jetson Nano 进行物体检测的分步指南

Nvidia Jetson Nano

边缘计算的未来

由于传感器技术、网络连接和人工智能(AI)的发展,边缘计算预见到指数级增长。对物联网、人工智能和数字化的大肆宣传已经让企业和政府机构做好准备,将这一技术作为真正的问题解决代理。随着新冠肺炎进一步推动数字化转型的需求,对于解决社会面临的一些问题,将会有更大的需求和期望。积极的一面是,我们看到了边缘计算领域新的发展,旨在解决延迟、隐私、可靠性和带宽方面的挑战。

存在不同的边缘计算平台。在本帖中,我们将介绍 Nvidia Jetson Nano 的安装过程。可以在 Nvidia 提供的链接上找到详细的指南。然而,我使用了硬件和方法的组合,可以给出不同的见解。实验设置包括 Nvidia Jetson Nano、USB 摄像头、Gstreamer-CLI、分类和对象检测算法。

正在准备 SD 卡映像

  1. 最好选择 32 GB SD 卡,使用 SD 卡格式化器对 SD 卡进行格式化。
  2. 从 Nvidia 链接下载图像
  3. 使用 BalenaEtcher 在 SD 卡上刻录/蚀刻图像
  4. 打开蚀刻软件 BalenaEtcher 并选择下载的图像
  5. 闪现图像。
  6. 当卡显示 100%完成时,卸载卡。

设置 Jetson Nano

  1. 将 SD 卡插入捷信纳米板
  2. 按照安装步骤,选择用户名、语言、键盘和时间设置。
  3. 登录杰特森纳米
  4. 使用 v4l-utils 安装媒体设备包。v4l-utils 是一系列用于处理媒体设备的软件包。
sudo apt-get update 
sudo apt-get install v4l-utils

5.检查连接的 USB 摄像头、支持的格式和分辨率。这些信息将有助于视频和图像数据处理。

v4l2-ctl --list-devices --list-formats
v4l2-ctl --list-formats-ext

6.检查摄像机是否退出。我会检查 id 为 0 的相机。

ls /dev/video0 

7.使用其中一个命令检查相机属性,更多细节

v4l2-ctl — list-formats-ext — device /dev/video0
v4l2-ctl -d /dev/video0 -D 
v4l2-ctl -d 0 -D

gstreamer:Jetson Nano 上的 USB 摄像头

jetson 的默认映像安装了 GStreamer。在示例中,我们将使用 USB 摄像头,并且我们已经安装了 v4l2 驱动程序(v4l2src)。由于本例中的摄像头是流 MJPG,我们必须在 device=/dev/video0 之前使用 pad jpegdec ,然后开始在管道中添加其他元素。下面的 GStreamer 管道将显示一个摄像机实时流。

gst-launch-1.0 -v v4l2src device=/dev/video0 ! jpegdec ! video/x-raw,framerate=30/1,width=1280,height=720 ! videoconvert ! xvimagesink 

链接可以找到一些好的资源。

设置 Jetson Nano 进行推理:对象检测和分类

在进行下一步之前,请检查对话框包的安装。对话框包将下载 CMake 中的模型。

sudo apt-get update sudo apt-get update
sudo apt-get install dialog
sudo apt-get install git cmake libpython3-dev python3-numpy 
git clone --recursive [https://github.com/dusty-nv/jetson-inference](https://github.com/dusty-nv/jetson-inference)
cd jetson-inference 
mkdir build $ cd build
cmake ../  # Make choice for the models. If the models are not downloading, make sure you have installed the dialog. Still see problems, please use link [https://github.com/dusty-nv/jetson-inference/releases](https://github.com/dusty-nv/jetson-inference/releases)

用于模型选择的对话窗口

make
sudo make install
sudo ldconfig

运行推理:对象分类和检测

在终端中,键入

cd /jetson-inference/build/aarch64/bin 
  • 图像分类示例
./imagenet-console.py --network=googlenet images/orange_0.jpg output_0.jpg 
  • USB 摄像头馈送的分类示例
./imagenet-camera.py --camera=/dev/video0 
  • 对象(行人)检测示例。
    V4L2 USB 摄像机通过指定其/dev/video 节点(/dev/video0,/dev/video1 等)来使用。).通过指定传感器索引(0 或 1 等)来使用 MIPI CSI 摄像机。)详见链接
./detectnet-camera.py --network=pednet --camera=/dev/video0 

由于活跃的社区,有许多例子都是开源代码。

  • 使用 SSD-Mobilenet-v2 进行对象检测
./detectnet-camera.py --network=ssd-mobilenet-v2 --camera=/dev/video0 

  • 可以使用以下方式查看资源利用率
top or htop

资源利用

计时报告

  • 表演

23-26 帧/秒

硬件和软件

NVIDIA Jetson Nano 开发者套件
32GB Scandisk Ultra SD card
微软 USB LifeCam 1080p HD(网络摄像头)
Raspberry Pi 官方通用电源 2.5A

发行商 ID: Ubuntu
描述:Ubuntu 18.04.3 LTS
发布时间:18.04
代号:仿生

相关文章:

[## NVIDIA Jetson Nano vs Google Coral vs Intel NCS。比较

用于计算机视觉和机器学习的边缘人工智能硬件加速器

towardsdatascience.com](/nvidia-jetson-nano-vs-google-coral-vs-intel-ncs-a-comparison-9f950ee88f0d) [## 在 Windows 上使用 GStreamer 和 QT 的 OpenCV

使用 OpenCV 的 GStreamer 管道的分步指南和实例

towardsdatascience.com](/opencv-with-gstreamer-and-qt-on-windows-6f0fdb075993)

强化学习入门—井字游戏

原文:https://towardsdatascience.com/getting-started-to-reinforcement-learning-tic-tac-toe-f1d32d53acb4?source=collection_archive---------45-----------------------

实现一个简单的双代理强化学习模型

想象你自己试图通过选择一系列活动(学习、疯狂观看、做白日梦)来最大化你的日常生产力。在这里,你是试图获得最大回报的代理人。生产力)通过选择一组合理的行动。你选择的每一个行动都会把你带到一个新的状态(例如,选择狂看而不是训练你的 RL 模型会影响你的情绪,这将进一步削弱你的生产力)。

强化学习(RL)很好地抓住了这个想法。它关注的是代理人如何通过采取特定的行动来最大化他们的奖励功能。每一个动作及其对应的奖励都会产生一种新的状态,这种新的状态会影响后续的动作-奖励交互。当我们开始实现我们自己的 RL 模型时,这些概念将变得更加清晰,这个模型可以和我们一起玩井字游戏。我们开始吧!

在 RL 世界中构建井字游戏

图 1:井字游戏板设置

井字游戏的目标是第一个在水平、垂直或对角线排列中放置标记(十字或十字)。现在,让我们根据前面提到的 RL 关键字来定义游戏:

  1. 代理涉及两个井字游戏玩家,他们试图通过轮流放置标记来智胜对方,
  2. 奖励指的是获胜代理人获得的任意值,
  3. 动作规定每个代理只允许在一个空盒子中放置他们相应的标记,
  4. 状态是每回合后井字游戏棋盘的配置,直到游戏以赢或平结束。

国家

我们将初始化State类,它将监视每个代理如何交互、接收奖励和玩游戏。

这里我们用 0 初始化一个 3x3 的棋盘,2 个玩家和第一个开始游戏的玩家。isEnd是一个标志,表示游戏是否还可以继续,或者已经确定了获胜者。每个玩家被分配一个特定的playerSymbol,其中p1用 1 和p2 -1 表示。

getHash是一个方便的功能,可以使电路板配置变平,便于以后的分析。输出形状从(3,3)转换为(9)。getAvailablePosition将获取棋盘上尚未被占据的箱子集合,因此可用于下一步棋。

在为代理定义了可用的动作空间之后,我们需要定义如何确定获胜者(这将打破边玩边循环)。这里,每轮游戏后可以获得 4 种可能的break结果:列赢、行赢、对角赢、和棋

每次成功执行一个动作后,updateStates将使用当前的playerSymbol更新板卡配置。下一个玩家将会被选出来继续游戏。如果游戏结束(无论是赢还是平),giveReward将输入一个任意值(即。赢的玩家得 1 分,输的玩家得 0 分,平局的情况下两者都得 0.1–0.5 分)。

代理人

现在让我们初始化Agent类来指定它们的行为(选择一个最大化奖励的动作,计算奖励)

以下超参数需要更多解释:

  1. lr (learning_rate)每个代理完成学习的速度,
  2. decay_gamma每回合奖励衰减的因子(即。迫使代理人以最少的可能移动赢得胜利,因为以更多的移动赢得胜利会导致衰减的奖励,
  3. exp_rate探索率,允许代理选择可用的随机位置,而不是贪婪地从当前学习的策略集合中寻找(利用)最佳的可能下一步行动。较高的值允许代理人的决策有更多的随机性。

states将存储给定游戏中每个玩家的棋盘配置列表,而states_val是一个键值字典,保存与特定棋盘配置/状态(‘key’)相关联的奖励(‘value’)。

然后我们定义chooseAction,它允许代理人或者探索(选择随机动作)或者利用(在给定当前棋盘配置/状态的情况下,选择具有最大回报的动作)。

代理采取行动后,addStates 会将结果板配置添加到states。当游戏结束时,feedReward会以一种(1)相反的方式给每个配置分配一个奖励:最新的移动/状态优先;以一种(2)折扣/衰减的方式:惩罚更多的移动。

图 2:值迭代(针对强化学习问题)

feedReward计算与特定状态相关的值(即 states_val)通过累加 当前值和给定学习率下一个和当前状态之间的折扣/衰减差(图 2)。

对于内务处理,我们将保存训练过的策略,并在以后使用训练过的 RL 机器人时加载它们!😃

让机器人玩吧!

在定义了StatesPlayer类之后,我们将实现游戏的实际运行!

playBot函数在State类中定义,作为我们玩游戏的逻辑。两位玩家将轮流选择一个动作(随机或贪婪),直到选出一个赢家。奖励将根据我们之前定义的价值分配给两个代理。

让人类去玩吧!

在策略被保存后,现在是我们和我们训练过的机器人比赛的时候了!我们首先需要稍微修改之前定义的playBot函数来加载学习到的策略(让 bot 使用它之前学习到的智能!)

此外,我们还需要稍微修改一下HumanPlayer的定义:通过用户输入选择下一组动作!

图 3:我们试图击败超级机器人!

就这样,很酷吧?祝你训练愉快!你可以在这里查看完整代码和文档:代码

做订阅我的邮件简讯:https://tinyurl.com/2npw2fnz在这里我定期用通俗易懂的语言和漂亮的可视化方式总结 AI 研究论文。

参考

[1]https://github . com/JaeDukSeo/reinforcement-learning-an-introduction

从本地和远程开始使用气流

原文:https://towardsdatascience.com/getting-started-with-airflow-locally-and-remotely-d068df7fcb4?source=collection_archive---------6-----------------------

气流已经存在了一段时间,但最近它获得了很大的牵引力。那么什么是气流呢?怎么用呢?以及如何在本地和远程设置?

图像信用

为什么是气流?

Airflow 是 AirBnB 于 2014 年开发并开源的工作流管理平台,旨在帮助该公司管理其复杂的工作流。快进到今天,数百家公司正在利用气流管理他们的软件工程、数据工程、ML 工程管道。

Airflow 的开发遵循了四个原则,即可伸缩性、动态性、可扩展性和优雅性。可扩展意味着您可以毫不费力地横向扩展您的管道。动态意味着动态管道生成,可扩展意味着您可以轻松编写您的自定义操作符/集成。最后,优雅的意味着你可以通过参数和 Jinja 模板使你的管道简洁明了。

气流架构(我对气流文档的解释)

以下是气流的一些特征:

  • 用纯 Python 开发:只用 Python 开发你的管道,Python 是数据科学家和数据工程师的首选语言。
  • 有用的用户界面:气流用户界面有助于可视化您的工作流程,并为您的管道提供可见性。
  • 大量集成:air flow 可能已经与您的数据系统集成。一些值得注意的集成包括 AWS、GCP、Spark 和大多数 SQL 数据库。
  • 易于使用:任何懂 Python 的人都可以创建带有气流的管道,用于各种目的,包括数据工程师管道,自动构建机器学习模型,或者基础设施自动化。

您可以使用 Airflow 构建和自动化各种系统,它在数据专业人员中尤其受欢迎。几年前,我开始使用 Airflow 为我们公司在 GCP 的数据湖编排 ETL 过程。它已经成为我工具箱中必不可少的一部分。

你能用气流做什么?

通俗地说,气流是一个编排工具,这意味着它会按计划触发任务,或者在某些事件发生时(如 API 调用或传感器操作员感知到某个动作时)触发任务。以下是气流的一些可能使用案例:

  • 替换 cron 作业:监控 cron 作业既困难又繁琐。您可以通过 UI 直观地查看您的代码是否运行,并让 Airflow 在作业失败时通知您,而不是手动 ssh 到服务器来找出您的作业是否/为什么失败。
  • 提取数据: Airflow 具有许多集成,大量用于数据工程任务。您可以编写任务来从生产数据库中提取数据,检查数据质量,并将结果写入您的云上数据仓库。
  • 转换数据:您可以与外部服务接口来处理您的数据。例如,您可以有一个管道向 EMR 提交一个作业,用 Spark 在 S3 处理数据,并将结果写入您的红移数据仓库。
  • 训练机器学习模型:你可以从数据仓库中提取数据,进行特征工程,训练模型,并将结果写入 NoSQL 数据库,供其他应用程序使用。
  • 从互联网上抓取数据:你可以编写任务来定期从互联网上抓取数据并写入你的数据库。例如,你可以从你公司的脸书页面获得每日竞争对手的价格或所有评论。

可能性是无限的。

词汇表

在我们继续设置气流之前,让我们看看一些基本的术语。

熟练的技艺

DAG 是有向无环图的首字母缩写,这是一种描述有向且不形成循环的图的奇特方式(后面的节点从不指向前面的节点)。可以把 Airflow 中的 DAG 想象成一个有节点(DAG 中的任务,比如“start”、“section-1-task-1”、…)和边(箭头)的管道。

气流 Dag 示例(来源)

您可以使用 Python 定义 dag,并且可以为 DAG(管道)设置各种属性。例如开始日期、结束日期、执行时间表等。

Python 中的 dag 定义

操作员、传感器、任务

操作员定义了在一个任务中完成什么。一些示例操作符是 PythonOperator(执行 python 脚本)、BashOperator(运行 bash 脚本)…

传感器是等待特定事件发生的操作员。例如,一个文件被写入 S3 桶,一个数据库行被插入,或者一个 API 调用发生。

任务只是一个实例化的操作符。在您的 dag 定义中,您可以使用 Python 代码定义任务依赖关系。即在任务 A 之后执行 B,C,在任务 B,C 之后执行 D。

任务相关性定义的示例

安装和设置

气流相当复杂,从上面的架构可以看出。对于本地开发,我们不需要架构中的所有组件,但是对于部署到服务器,我们当然需要所有组件。让我们先来看看局部安装气流

用于开发的本地安装

  1. 创建一个空气流通的环境(可选,但推荐):您可以使用以下命令轻松创建一个有 Anaconda 的环境:
conda create -n airflow python=3.7
conda activate airflow

2.用 pip 安装气流

pip install -U apache-airflow

3.创建一个文件夹,并将其设置为气流主页

mkdir -p ~/airflow/dags
export AIRFLOW_HOME='~/airflow'
export PATH=$PATH:~/.local/bin

4.启动气流。初始化后,您可以在airflow.cfg中调整气流设置

cd ~/airflow
airflow initdb

5.启动气流调度程序

airflow scheduler

6.在新的终端窗口中启动 airflow webserver

# Activate airflow env if needed
conda activate airflow
airflow webserver

就是这样。

现在,如果您在localhost:8080访问您的 web 浏览器,您将能够看到加载了许多示例的 Airflow UI。您可以触发一些 Dag,它将在您的本地机器上运行。参考示例 Dag 将有助于开发新的 Dag。

本地主机的气流 UI:8080

现在你可以在目录~/airflow/dags/中定义一个新的 DAG 文件,Airflow 会将你的 DAG 渲染到 UI 中。我将为下一篇文章保存定义 DAG 的指令。现在,让我们看看如何将气流部署到服务器。

部署到服务器

如前所述,Airflow 的架构很复杂,从头开始设置所有组件既麻烦又容易出错。幸运的是,我们可以使用 Docker 毫不费力地将 Airflow 架构中的所有组件部署到服务器上。

  1. SSH 到您的服务器,并确保 Docker 已安装。如果不是,你将不得不安装Dockerdocker-compose来使其工作。有很多在不同操作系统上安装 Docker 的指南,你可以简单地谷歌一下如何安装。
  2. 在本指南中,我在这个回购中使用由puckel管理的docker-airflow。我建议你把回购分叉到你的 GitHub 账户,把分叉的回购克隆到远程服务器。
# Replace the URL with your forked repo
git clone [https://github.com/puckel/docker-airflow](https://github.com/puckel/docker-airflow)

3.配置气流:在 repo 中,你会发现一个名为docker-compose-CeleryExecutor.yml的文件,这是 docker 为你的气流部署编写的配置文件。

  • 为了安全起见,请确保您更改了所有默认的用户名和密码。
  • 取消如下所示的三行注释,将元数据数据库文件保存到系统文件中
# Uncomment these lines to persist data on the local filesystem.                
  - PGDATA=/var/lib/postgresql/data/pgdata        
volumes:
  - ./pgdata:/var/lib/postgresql/data/pgdata
  • 将以下代码添加到 webserver、worker 和 scheduler 的环境变量中,以启用基本登录。请注意,您必须使用以下脚本或使用 Airflow CLI 创建一个管理员用户。
- AIRFLOW__WEBSERVER__AUTHENTICATE=True- AIRFLOW__WEBSERVER__AUTH_BACKEND=airflow.contrib.auth.backends.password_auth

4.创建.envrequirements.txt(可选):您可以在 repo 中创建这两个文件。您可以在.env.requirements.txt中为您的气流部署存储环境变量。通过将以下内容添加到 webserver、worker 和 scheduler 的卷中,确保将它们公开给容器。

- ./requirements.txt:/requirements.txt

5.启动容器:现在我们已经完成了所有的配置,您可以使用下面的命令启动容器。查看docker-compose 文档了解更多您可以使用的命令。

docker-compose -f docker-compose-CeleryExecutor.yml up

6.创建一个Makefile以便于管理(可选):您可以创建一个 Makefile 来发布长而重复的命令。看看下面我的:

up:. ./.env && docker-compose -f docker-compose-CeleryExecutor.yml uprun:. ./.env && docker-compose -f docker-compose-CeleryExecutor.yml up -d --scale worker=2 && docker-compose logs -tfdown:docker-compose -f docker-compose-CeleryExecutor.yml downrestart:docker-compose down && . ./.env && docker-compose up -d --scale worker=2logs:docker-compose logs -tf

这样,您可以简单地运行make up来启动容器,make down来停止,然后make restart来重启。

摘要

在这篇文章中,我将带你了解什么是气流,为什么,以及我们如何使用气流。我还展示了如何在本地安装和运行 Airflow,以及如何为远程服务器配置它。

希望你今天学到了一些东西:)

开始分析医疗保健中的表格数据

原文:https://towardsdatascience.com/getting-started-with-analyzing-tabular-data-in-healthcare-d02041aae468?source=collection_archive---------71-----------------------

除了使用 Kaggle 提供的图像数据之外,还使用表格数据为医疗保健部门做出更明智的决策带来了挑战。

演职员表:弗兰基·查马基在 Unsplash 上的照片

如今,随着医疗保健领域中成熟的计算机视觉方法的使用越来越多,其他类型(如表格数据)的正确使用并不广为人知。使用与图像数据一起出现的现有数据的优点是,它可以用于得出关于整个场景的更好的结论。对于本教程,我们将使用皮肤黑色素瘤数据集,虽然这主要是一个计算机视觉问题,但数据来自训练和测试 csv 文件,正如我们所讨论的,除了使用这些文件来准备图像数据集(标记图像之外,了解如何利用这些文件总是有用的。

  1. 实时数据(加载、检查、浏览、可视化)

一旦您从上述链接下载了数据集,您就可以进入下一步,即加载 csv 文件并开始浏览表格数据,以发现数据中其他有趣的关系。有趣的是,稍后来自图像分类器和这个表格数据集的结果可以被组合以形成更健壮的模型。但是现在让我们把重点放在处理表格数据上。首次加载数据的代码如下:

输出:

现在我们已经加载了数据,绘制数据中不同变量之间的关系会很有趣。这些关系可能对以后的解决方案建模有用。从这个过程开始,我们在这里使用的第一种图是 SPLOM(ScatterPlotMatrix),它是一种更方便的散点图形式,因为在这里可以一次使用多个变量来绘制数据,并且研究相关性更容易。下面是使用 plotly 的代码片段,这是 Python 中一个流行的数据可视化库。

输出:

上面我们有一个 SPLOM,其中有三个从数据集中精选的特征。这里我们有二元目标,即一个人是否患有黑色素瘤,因此该图仅显示两种颜色,但仍然可以从该图中推断出许多信息。首先清楚的是,一般来说,女性中发现/发现黑色素瘤的年龄高于男性。现在,这可能源于很多原因,如遗传或医疗保健系统的固有偏见。在详细研究这些主题时,这种观察可以派上用场。下一个有趣的关系是在可疑斑块的解剖位置年龄之间,很明显,在头部/颈部有可疑斑块且年龄在 50-70 岁之间的人更有可能患有黑色素瘤,而任何年龄的人都有不同外观的口腔或生殖器皮肤斑块。

在绘制和分析 SPLOM 之后,我们已经对可能相互影响的特性有了一个粗略的想法,因此,我们将继续绘制盒图。根据 mighty Wikipedia 的说法, boxplot 是一种通过四分位数图形化描述数字数据组的方法。你问的四分位数是什么,四分位数可以想象为基于中位数的数据分段,有五个部分,即最小值第一个四分位数中位数第三个四分位数最大值。任何超出最小或最大T21 的数据点都被称为异常值。我们发现患者的年龄和可疑斑块的解剖位置之间存在有趣的关系,因此我们将使用这两列来绘制箱线图并详细研究这种关系。下面是基于 seaborn 的代码,用于绘制和显示箱线图。**

输出:

很明显,某些解剖结构比其他解剖结构具有更多的异常值。我们可以在这里看到以前在 SPLOM 中看不到关系。一些观察包括口腔/生殖器斑块仅在很小的年龄范围内可能是癌性的,并且 60 岁以上的人更可能患有癌性头部/颈部皮肤斑块,而这些斑块在 40 岁以下是非常不可能危险的。这种分析只是提供一种思路,即如果仔细分析数据,如何回答更大的问题,以及如何帮助形成一个更具包容性的系统。

在我们继续阅读缺失值之前,最后一个重要的主题是数据集中存在的不同类型的数据列,以及如何对它们进行编码以便有效使用。可用的三种主要数据列类型是:

a.分类 : 这些列是那些假定有限值的列,例如在该数据集中片的解剖位置。这些变量取离散值,并且是可数的。

b.序数:这些变量是有一定顺序的变量,例如:学校的年级,如高中、初中、小学。这些可以被认为是分类变量的特殊情况。

c.连续:这些是数值变量,不取任何确定的离散值,在该数据集中,一个这样的变量是年龄。应该注意,年龄是可变的,可以取任何实数。

了解这些类型很重要,因为默认情况下大多数算法都需要数值,因此很多时候我们需要在使用它们之前对非数值变量进行编码。请记住,编码不会改变不同要素之间的关系,非数字值只是简单地转换为数字映射。我们将在下一节中更详细地讨论这个主题,作为机器学习算法的数据准备的一部分。

2。处理缺失值、数据编码和插补

可能会有许多数据行缺少某些变量的数据。数据缺失的原因可能包括测量仪器故障、受访者不愿意或信息不可用。尽管删除这些带有不完整数据的数据行似乎是一个显而易见的合理选择,但它对模型的性能没有好处,因为它可能会在数据中引入偏差。这使得仔细研究数据并建立无偏模型成为必要。

缺失数据的类别:尽管找出数据集缺失数据所属的类别很困难,但了解这些类别及其可能引入的偏差类型仍然很有用:

1。完全丢失随机:完全随机记录数据,也就是说,数据记录是基于抛硬币,每次抛硬币出现反面时,就进行一次数据录入。在这种类型的采集之后丢失的数据完全是随机的,因此不会在训练模型中引入任何偏差。

2。随机丢失:这里的数据收集过程不是完全随机的,它有一些规则,这些规则决定了必须收集数据,而数据收集的其余部分可能仍然依赖于一个相当随机的过程,比如上面提到的扔硬币。这是一种有条件的数据缺失,尽管导致该数据缺失的因素是所收集的信息的一部分。

例如: 如果患者来诊所进行常规检查,并且其年龄超过 40 岁,则不变地检查其血糖水平,但是如果患者年龄小于 40 岁,则该数据收集可能基于掷硬币,或者如果患者具有影响血糖水平变化的其他状况。

3。非随机缺失:这种缺失数据最难发现,因为它无法从记录的数据中观察到,而且影响记录数据的不仅仅是随机因素。

既然我们已经知道了丢失的数据,那么深入研究寻找和可视化具有空值的列的代码将会很有趣。

下面我们可以看到一张 seaborn 热图,其中深色部分显示的值不为空,浅色部分显示的是缺失的值。例如:列“良性 _ 恶性”没有缺少值,而“年龄 _ 大约”缺少一些值。

包含来自数据框的数据的热图

在我们继续之前,让我们看一下代码,它可以帮助我们找出数据帧中丢失数据的行。

上面提到的代码将打印数据帧中带有 NaN 的行,后跟带有 NaN 的行数。当我们必须决定是应该估算(缺失值的近似计算)数据还是简单地删除有缺失数据的行或列时,这些值非常有用。现在,如果开发人员不想使用数据插补,他/她只需删除相应列中具有 NaN/null 值的行,并继续使用模型。

数据插补:现在我们知道缺失数据可以分为三类,下一步应该是找出可以对这些缺失数据做些什么。数据插补是指通过估计缺失值来填充/输入缺失值。需要记住的一点是测试训练数据集应该使用相同的估算值。有两种主要的方法来计算要估算的数据。它们如下:

  1. 基于均值/中值/众数的插补:顾名思义,这是通过计算所考虑特征的均值/中值/众数来实现的。虽然很容易计算,但它有一个问题,即这种类型的插补不一定能保持独立变量之间的关系。下面的代码演示了如何将简单估算器与替换策略“most _ frequency”一起使用,因为从策略的名称可以明显看出,它使用最频繁出现的值来替换丢失的值。

2.基于回归的插补:对于该方法,需要学习一个线性模型,显示带有缺失值的变量与其他独立变量的关系。这种数据插补方法被称为迭代插补。依次计算不同特征的所有缺失值,这些新计算的值用于预测后续特征的值。由于所用的估算器是回归算法,需要所有数值输入,但我们的数据集目前包含数值和非数值,我们不会使用迭代估算器来实现我们的目的,但下面是一段代码,可用于对数据集应用这种估算。

注意:关于这个库和函数的更多信息可以在这个 链接 找到。

对数据进行编码:因为我们已经了解了为什么要对数据进行编码(提醒:机器学习算法喜欢处理数字)。我们应该从顺序类别编码加标签编码开始,然后是一键编码。但是在我们开始编码之前,让我们做一些数据准备。下面的代码片段将分离数据帧中的因变量(也称为:目标变量或标签)和独立变量(非目标列,它们有助于对数据进行分类)变量,以便我们可以分别使用标签分类编码

顺序类别和标签编码:编码基本上是将所有列值的数据转换成数字(整数)。这里我们使用了来自 scikit-learn编码器。OrdinalEncoder 用于对自变量进行编码,主要由多列组成。虽然有可能只对少数非数字列进行编码,但为了简单起见,我们已经对所有列进行了编码(为此,我们之前已将它们转换为字符串)有一个单独的编码器,称为标签编码器,它主要将一列作为输入,并给出相应的输出,因此我们使用它来编码目标变量。尽管我们为这个特定的数据集提供了一个数字标签,但可能会有只使用字符串作为标签的情况,因此这是一个方便的概念。

注意:如果特定变量没有数量限制或重复值,如该数据集的患者 Id,OrdinalEncoder 将为这些列分配一个唯一的整数值。

One-hot encoding :这种类型的编码不是简单地将一个整数值分配给不同的类别,而是根据列中有多少个类别来分配长度向量。

例如:比方说我们有两种类型的肿瘤,“良性”和“恶性”,那么我们会将“良性”编码为“01”,将“恶性”编码为“10”,反之亦然。这里 1 的位置决定了条件类型。为了详细说明这个例子,假设我们还有一个被标记为“未确定”的类型,那么这些类别将分别是“良性”、“恶性”和“未确定”的“001”、“010”和“100”(或者不同的顺序)。

我们将再次使用来自 scikit-learn 的内置函数 OneHotEncoder上述分类编码代码可更新如下,使用 OneHotEncoder 代替 OrdinalEncoder:

3。实现和分析不同的机器学习和深度学习方法

既然我们已经为机器学习算法分析和准备了数据,现在是我们走向最终训练步骤的时候了。尽管在这个人工智能领域中,神经网络的使用受到青睐,尽管对于表格数据看不到这种趋势,即使在今天,像决策树和随机森林这样的传统算法也是优选的。虽然我们将学习实现一个基本的神经架构来处理表格数据,但我们将首先实现上面提到的方法。

决策树:与神经网络类似,决策树也可以很好地模拟非线性。在大多数情况下,基于树的方法是首选,因为它们具有高的可解释性并且计算成本低。以下代码显示了如何进行数据分割,使用决策树分类器和绘制树。为训练模型的初始验证保留一些保留数据集(也称为验证集)总是一个好主意。我们只使用了决策树分类器中的两个属性,尽管有可能使用许多其他的组合,细节可以在这里找到。

决策树图示例

尽管决策树很快,并且可以很好地对数据建模,但是它们仍然遭受过拟合(训练和测试精度之间的差距很大),这个问题主要是因为因素 max_depth 而引入的。为了克服这个问题,我们将使用下面讨论的随机森林,它们有助于算法生成多个决策树

随机森林:如上所述,尽管决策树有其优点,但它们会遭受过拟合。因此,为了解决这个问题,我们现在来看看随机森林。随机森林性能更好的两个主要原因是:

a)他们从整个数据集中随机抽取样本,并进行替换。

b)当决定决策树边界时,他们使用特征的子集。

随机森林的实现也像决策树一样直接(如下所示),关于参数的进一步细节可以在这里查看。除了改变模型类型之外,没有任何改变,模型将以相同的方式被拟合和用于预测。

该模型的输出是在该过程中构建的所有子树的集合。

梯度提升:正如我们所看到的,随机森林是一种创建多个子决策树的方法,其结果在最终预测之前被聚合,还有其他被称为“提升”算法的方法,其本质上是多个弱分类器堆叠在一起,形成一个更强、更健壮的分类器。一个这样的例子是梯度增强。更多关于它的用法的信息可以在这里找到。

针对表格数据的深度学习:现在我们已经重温了大量传统的机器学习方法,看看我们是否可以使用深度学习来解决这样的问题将会很有趣。对于我们能否使用深度学习这个问题的答案是肯定的,我们可以将深度学习方法应用于表格数据。下面是一小段代码,演示了同样的情况。在使用深度学习方法时要记住的一件重要事情是,一次性编码应该优先于分类编码

至此,我们结束了这篇文章,在这里,我们定义了一组处理表格数据时要遵循的步骤。

4。结论&未来工作

在这里,我们讨论了在处理表格数据时需要遵循的基本流程,但是我们仍然没有讨论如何处理数据中的类别不平衡及其对机器学习方法的结果的影响。但是这将在下一篇文章中讨论。此外,讨论如何实现多模式(处理多种形式的数据,如图像和文本数据)网络对于未来也是很有意思的。

Apache Avro 和 Python 入门

原文:https://towardsdatascience.com/getting-started-with-apache-avro-and-python-59239ae7f5e?source=collection_archive---------6-----------------------

了解如何创建和使用基于 Apache Avro 的数据,以便在 Python 应用程序中更好、更高效地传输数据

https://unsplash.com/photos/LqKhnDzSF-8

在这篇文章中,我将谈论 Apache Avro ,这是一个开源数据序列化系统,被 Spark、Kafka 和其他工具用于大数据处理。

什么是阿帕奇 Avro

根据维基百科:

Avro 是在 Apache 的 Hadoop 项目中开发的面向行的远程过程调用和数据序列化框架。它使用 JSON 来定义数据类型和协议,并以紧凑的二进制格式序列化数据。它的主要用途是在 Apache Hadoop 中,可以为持久数据提供序列化格式,为 Hadoop 节点之间的通信以及从客户端程序到 Hadoop 服务的通信提供有线格式。Avro 使用一个模式来组织被编码的数据。它有两种不同类型的模式语言;一个用于人工编辑(Avro IDL ),另一个基于 JSON,更适合机器阅读。[3]

基本上,Avro 是由 Hadoop 之父 Doug Cutting 开发的独立于语言的数据序列化系统。在我进一步讨论 Avro 之前,请允许我简单讨论一下数据序列化及其优势。

什么是数据序列化和反序列化

数据序列化是将复杂对象(数组、字典、列表、类对象、JSON 等)转换成字节流的过程,这样它们就可以被存储或转移到其他机器上。在具有不同体系结构、硬件或操作系统的计算机之间传输数据时进行数据序列化的原因。一旦数据在另一端被接收到,它就可以被还原回原来的形式。这个过程被称为反序列化

现在你知道它是关于什么的了,让我们深入研究并使用一些代码。

开发和安装

Python 应用程序中目前使用了两个库。一个简单地叫做avro,你可以在这里访问。而另一个是 FastAvro 号称比上一个更快。两者的工作原理是一样的。因为我们正在做一个玩具例子,所以前面的库对我们来说已经足够了。因此,总是使用典型的 pip 工具来安装它:

pip install avro

Avro 模式

{"namespace": "me.adnansiddiqi",
 "type": "record",
 "name": "User",
 "fields": [
     {"name": "name", "type": "string"},
     {"name": "age",  "type": ["int", "null"]},
     {"name": "gender", "type": ["string", "null"]}
 ]
}

Apache Avro 格式实际上是一种 JSON 结构。你可以说 Avro 格式实际上是一个 JSON 数据结构和一个用于验证目的的模式的组合。因此,在我们创建扩展名为.avro的 Avro 文件之前,我们将创建它的模式。

好了,我已经想出了一个模式,上面是一个 JSON 结构。我们将首先提到名称空间。它只是一个字符串。通常,它遵循 Java 打包命名约定使用的相同格式,这是域名的反码,但不是必需的。这里我提到了我的博客网址的反面。在那之后你提到了你的模式的类型,这里它是record类型。还有其他类型的也像enumarrays等。之后,我们提到模式的名字,这里是User。下一个是field项,可以是一个或多个。它有必填字段nametype以及可选字段docaliasdoc字段用于记录您的字段,而alias用于给字段一个不同于name中提到的名称。到目前为止一切顺利。我们创建的模式将保存在一个名为users.avsc的文件中。

现在,我们将编写从模式文件中读取模式的代码,然后在 Avro 文件中添加一些记录。稍后,我们将检索记录并显示它们。让我们写代码吧!

import avro.schema
from avro.datafile import DataFileReader, DataFileWriter
from avro.io import DatumReader, DatumWriterschema = avro.schema.parse(open("user.avsc").read())writer = DataFileWriter(open("users.avro", "wb"), DatumWriter(), schema)
writer.append({"name": "Alyssa", "age": 25,"gender":"female"})
writer.append({"name": "Ahmad", "age": 35,"gender":"male"})
writer.close()reader = DataFileReader(open("users.avro", "rb"), DatumReader())
for user in reader:
    print(user)
    print('===================')
reader.close()

导入必要的模块后,我要做的第一件事就是读取模式文件。DatumWriter负责将数据翻译成 Avro 格式 w.r.t 输入模式。DataFileWriter负责将数据写入文件。插入几条记录后,我们关闭编写器。DataFileReader的工作方式类似,唯一的区别是DatumReader()负责存储在users.avro中的数据的反序列化,然后使其可用于显示。当您运行代码时,它将显示如下:

python play.py
{'name': 'Alyssa', 'age': 25, 'gender': 'female'}
===================
{'name': 'Ahmad', 'age': 35, 'gender': 'male'}

到目前为止还好吗?现在让我们对模式做一点改变。我将age字段更改为dob,当我运行时,它显示以下错误:

python play.py
Traceback (most recent call last):
  File "play.py", line 8, in <module>
    writer.append({"name": "Alyssa", "age": 25,"gender":"female"})
  File "/Users/AdnanAhmad/Data/anaconda3/lib/python3.7/site-packages/avro/datafile.py", line 303, in append
    self.datum_writer.write(datum, self.buffer_encoder)
  File "/Users/AdnanAhmad/Data/anaconda3/lib/python3.7/site-packages/avro/io.py", line 771, in write
    raise AvroTypeException(self.writer_schema, datum)
avro.io.AvroTypeException: The datum {'name': 'Alyssa', 'age': 25, 'gender': 'female'} is not an example of the schema {
  "type": "record",
  "name": "User",
  "namespace": "me.adnansiddiqi",
  "fields": [
    {
      "type": "string",
      "name": "name"
    },
    {
      "type": [
        "int",
        "null"
      ],
      "name": "dob"
    },
    {
      "type": [
        "string",
        "null"
      ],
      "name": "gender"
    }
  ]
}

很酷,不是吗?同样,如果你改变了数据,它会尖叫着告诉你把事情弄好。

结论

我希望您已经了解了一些关于 Apache Avro 的知识,以及 Python 如何让您使用它跨设备和系统传输数据。我只是触及了它的表面,还有更多关于它的内容。Avro 也被阿帕奇 Spark T1 和 T2 Kafka T3 大量用于数据传输。

原载于 2020 年 8 月 6 日http://blog . adnansiddiqi . me

开始使用 Python 中的 API 收集数据

原文:https://towardsdatascience.com/getting-started-with-apis-in-python-to-gather-data-1185796b1ec3?source=collection_archive---------4-----------------------

使用 API

Python 中 API 的友好(一点也不可怕)介绍

Python 中的 API 入门不需要吓人!(来源:Nik Piepenbreier)

PIs,或者说应用程序编程接口,提供了简单的方法来检索(和发布)数据。它们是由服务器提供的接口,您可以使用它们通过代码检索和发送数据。本质上,它们简化了复杂的指令来提供来自服务器的请求。他们可以比作餐馆的服务员。作为顾客,你向服务员发出用餐指示,然后服务员将要求反馈给厨房,在那里厨师采取复杂的步骤准备一道菜,而你根本不知道他或她付出了多少努力!然后你就可以拿回你点的餐,而不必计算到达那里的步骤!

与使用静态数据下载(比如 CSV 文件)相比,API 提供了很多效率。这些功能包括处理快速变化的数据或只处理一小部分数据的能力(比如,与下载大量天气数据相比,今天的温度)。

在真实、抽象的世界中,您可能每天都在不知不觉中使用 API。正是这种抽象使得 API 如此有用——网站可能依赖谷歌地图的 API 将你链接到方向,或者你的 Twitter 客户端让你直接将数据发布到你的帐户。

但是我们如何利用 API 来收集数据呢?

在本教程中,我们将首先探索在不需要身份验证的情况下收集数据,然后探索另一个需要我们进行身份验证的 API。我们将首先找到国际空间站(ISS)目前在哪里使用 Open Notify API,然后使用对 Dark Sky 的天气 API 的身份验证来收集有趣的天气数据。我们将通过探索如何将法兰克福证券交易所的数据添加到熊猫数据框架中来结束这篇文章!

让我们看看这个 API 实际上是如何工作的(来源:Nik Piepenbreier)

好的……但是它们是如何工作的呢?

(来源:Nik Piepenbreier)

类似于与常规网站的交互,当你想从一个 API 获取数据时,你需要向服务器发出一个请求。为了能够使用 Python 从 API 中提取数据,我们需要使用请求库(请看图!).Requests 或多或少是 Python 中进行 HTTP 请求的标准包。由于它的抽象性,使用起来非常简单,尤其是在使用 API 的时候。

首先,您可能需要安装请求库,因为它不是标准 Python 包的一部分。这可以通过 pip 或 conda 实现。

pip install requestsconda install requests

请求由四部分组成:

  1. 一个端点——看起来像数据的 URL
  2. 一个方法 —获取、上传、发布或删除。在这篇文章中,我们将只探讨 GET 请求。
  3. 报头——提供认证密钥等信息。
  4. 数据/主体——它不是 GET 请求的一部分(所以,现在假装我没有提到它)

当我们使用 requests 库运行一个请求时,它返回一个 request 对象,其中包含我们希望提取的数据,还包含一个 requests 状态代码。状态代码告诉我们请求发生了什么,它们是我们发出的每个请求的一部分。我们将处理 GET 请求,有许多响应代码与我们的工作相关。根据代码返回的信息,代码被分成数百个不同的值:

  • 1xx:提供信息
  • 2xx:通常是成功的
  • 3xx:提供重定向信息
  • 4xx:指客户端错误(我们的错误)
  • 5xx:指服务器错误(他们的错误)

当一个页面找不到的时候,你可能很熟悉看到(有时很滑稽)404 页面。这就是状态代码。

同样,状态代码 200 让我们知道一切正常!这就是我们想要的,并且有希望得到的!

API 101—ISS 当前位置

对双关语爱好者的特别款待(来源:Nik Piepenbreier)

在本教程的第一部分,我们将看看提供国际空间站数据的开放式通知 API。你可以通过访问他们的文档找到更多关于 API 的信息。

这个 API 的一个优点是它不需要认证,这意味着我们可以直接提取一些数据,而不需要额外的设置。

让我们首先用请求库生成一个 URL 请求,并访问它的状态代码属性。

我们可以通过使用下面列出的代码来做到这一点。为简单起见,输出显示在虚线下面。

的。get()函数请求一个请求对象。在这里,我们可以使用。status_code 属性来发现状态代码返回的内容。在本例中,返回的 status_code 是 200,这意味着我们可以继续前进了!

我们得到的数据以 JSON 格式返回。JSON 文件类似于 Python 字典,可以确保数据容易被机器读取。理解 JSON 文件的一个简单方法是将它们想象成用字符串表示的 Python 字典。

要开始处理 JSON 文件,让我们导入 JSON 库,它是标准包的一部分(所以我们不需要安装任何东西)。为了便于阅读,我在虚线下包含了代码的输出。

这个响应返回的字符串很短,很容易阅读。然而,许多 API 响应将会很长,并且可能需要一些解析来确定您想要在哪里查找您的数据(如果您对某个特定部分感兴趣的话)。让我们使用。dumps()函数将 JSON 字符串转换成 Python 对象。为了保持连续性,我们将重复一些代码。

这是一种更容易阅读的格式,使我们能够更容易地解析数据。假设我们只对纬度和经度感兴趣,我们可以像解析 Python 中的字典数据一样解析它。

这里需要注意的一点是,我们在这里调用的是 response.json()对象,而不是我们使用。dumps()函数。

从这里开始,我们现在可以使用这些数据轻松地将数据添加到数据集,使用我们想要的任何方法。

现在让我们把注意力转向黑暗天空 API,在我们开始之前需要做一些设置。

API 201—黑暗天空 API &添加身份验证

让我们给你报名吧!

你来学习,你留下来是为了双关语!(来源:Nik Piepenbreier)

首先,我们需要获得一个所谓的 API 密匙。密钥是允许用户在不需要提供用户名和密码的情况下进行身份验证的方法。因此,应该安全地对待它们,而不是共享它们。要获得你自己的黑暗天空密钥,在 https://darksky.net/dev/register注册一个黑暗天空账户。免费层将是很好的实验。

注册后,导航到 https://darksky.net/dev/account的账户页面,它会给你 API 密匙。记下这个密钥,并确保它是保密的。

作为免费等级的一部分,您每天最多可以拨打 1,000 次电话。

黑暗天空 API 里有什么?

《黑暗天空》提供了关于 API 中包含哪些数据的完整资源,你可以访问:https://darksky.net/dev/docs

有两种主要的呼叫类型:(1)预测请求,和(2)时间机器请求。前者提供当前天气(直到下周),后者提供过去和未来的数据。

让我们假设我们想要提取安大略省多伦多市的当前天气状况(概要、温度和风速)。

预测请求采用以下格式:[https://API . dark sky . net/forecast/[key]/latitude,[ 经度 ]

这意味着我们需要三样东西:

  1. 我们的 API 密钥,
  2. 我们的纬度,和
  3. 我们的经度。

为了轻松找到您的纬度和经度,您可以将您要找的地址输入到谷歌地图中。比如我搜了多伦多的 CN 塔。返回的 URL 将包含坐标:【https://www.google.com/maps/place/CN+Tower/@】T243.6425701-79.3892455 ,17z/

在@符号之后,首先是经度(43.6425701),然后是纬度(-79.3892455)。

让我们以一种冗长但易于理解的方式写出代码。我们将利用 f 字符串使代码更容易阅读。如果你对 f 弦不熟悉,请查看他们的 Python 文档

根据文档,我们可以看到通用请求提取了比我们需要的更多的数据。虽然不是必需的,但我们可以使用 Dark Sky 的 exclude 块来减少这个问题,这将减少请求的延迟。我们将只使用当前的块,所以我们将排除所有其他的块。

前面我们提到我们会对当前的状况感兴趣(特别是概要、温度和风速)。通过查看上面的结构,我们可以看到,通过访问这些项目的键值对,我们可以很容易地提取这些数据。

黑暗天空 API 也允许你设置单位。目前,我们的声明还不清楚我们提取的数据是以什么单位表示的。再明确一点吧。由于我们正在提取加拿大位置的数据,所以让我们指定他们的地区。黑暗天空 API 文档告诉你我们应该设置 units=si。

到目前为止,我们已经学习了如何使用和不使用身份验证进行 API 调用。让我们更进一步,将它添加到熊猫数据框架中。

变得非常有趣:将数据添加到熊猫数据框中

假设我们正在进行一个项目,我们需要生成一个包含财务数据的数据框架。我们可以使用熊猫的内置函数轻松做到这一点。

这个双关语没那么好。但是,我努力了。(来源:Nik Piepenbreier)

为此,我们将使用 Quandl 的财务 API。特别是,我们将为法兰克福证券交易所使用免费的 API,关于它的文档可以在这里找到

让我们稍微研究一下这些数据。我们将按照在网站上生成 URL 的说明加载数据,并使用上述 json.dumps()函数打印数据。我们需要像以前一样导入相同的库,以及熊猫。

数据实际上会持续很长很长时间,但在这里被截断了。

由此,我们可以看出:

  • 列名在['dataset']['column_names']中找到
  • 数据在['dataset']['data']中找到

让我们利用这些知识创建一个数据框架:

结论:我们学到了什么?

在这篇文章中,我们探讨了什么是 API,如何在 Python 中使用它们,包括认证和不认证,以及如何将 API 中的数据添加到 pandas 数据帧中。对于 API,我们还有很多没有在这里介绍,但是希望这能让您很好地理解从这里学到什么!

AutoKeras 入门

原文:https://towardsdatascience.com/getting-started-with-autokeras-8c5332b829?source=collection_archive---------8-----------------------

用几行代码利用神经结构搜索的能力

来源

我在 中提到的 2020 年人工智能的状态 中最强大的即将到来的概念之一是神经架构搜索(NAS) 。关于 NAS 有很多东西需要了解,但是为了理解本教程,我只做一个总结。简而言之,NAS 本质上是一种将人类设计的局限性从神经网络架构中去除的方法。为了实现这一点,许多不同的架构被并行考虑、训练和评估。接下来,可以基于所选择的算法来调整每一个,以尝试另一种架构。最终结果是在每个尝试的模型上模型损失的一种梯度下降(可能是几千个!),而不是每一步。表现最好的模型是赢家,数据科学家可以在晚上睡得很好,因为他们知道他们可能没有使用低劣的算法。

动画来自 ENAS PyTorch 实现

过去,要实现成功的 NAS,需要非常复杂的 Tensorflow、PyTorch 或 Keras 脚本实现。除此之外,企业级的计算硬件要求。输入 AutoKeras 。德克萨斯州 A & M 实验室的数据分析开发了一个用 Keras 构建的开源框架,为任何狂热的 Keras + python 用户带来 NAS。在一年的预发布版本之后,1.0 版本于 2019 年 1 月刚刚发布,这使它可以随时投入使用。对于年轻的数据科学家和小公司来说,这是一个非常好的工具,因为它允许他们跟上大型竞争对手发誓要采用的技术。

该库使用最先进的 NAS 算法,以及现有的预处理模块,以确保 NAS 培训会议顺利进行。这在 AutoKeras 论文中有详细阐述。这对于小型研究操作来说非常令人兴奋的部分原因是,他们已经优化了动态 GPU 内存的算法,以避免我们都习惯的邪恶的 OOM 异常。鉴于所有这些,AutoKeras 预装了以下功能:

  • 图像分类/回归
  • 文本分类/回归
  • 结构化数据分类/回归(典型的行 x 列数据类型)
  • 多任务学习

我将首先简要介绍一下设置和简单的实现,然后深入介绍定制实现和“块”的概念

设置

AutoKeras 在 Tensorflow 之上的 Keras 上运行时有以下要求,特别是版本 2.1.0。

  • Python3
  • TensorFlow ≥ 2.1.0(重要!)

一旦这些都就绪,这个简单的 pip 命令就应该安装 AutoKeras 了

pip3 install autokeras

如果安装没有任何问题,你就可以开始了!

简单用例

如果你的唯一目标是为一个分类任务训练最好的架构,那么代码是相当少的。使用内置的 mnist 数据集,您可以如下加载

x_train, y_train = mnist.load_data()

现在我们有了想要拟合的数据,我们可以创建ImageClassifier对象:

import autokeras as ak
model = ak.ImageClassifier(max_trial = 100)

这为我们的培训课程创建了结构。max_trials 指的是将尝试多少不同的模型。AutoKeras 已经实现了像 ResNet、Xception、可分离 CNN 这样的模型,这些模型必然是强大的。

接下来,我们需要拟合模型。这个极其复杂和漫长的过程取决于您的硬件,可以通过以下方式触发:

model.fit(x_train, y_train)

附加选项也有助于理解拟合方法:

ImageClassifier.fit(x=None, y=None, epochs=None, callbacks=None, validation_split=0.2, validation_data=None, **kwargs )

我们在这里可以看到,我们还可以选择设置时期的数量,并根据我们的选择进行验证分割。这对于验证数据来说很好,因为它不需要我们自己去分割它。

一旦模型完成了最大数量的试验,将选择具有最佳“分数”的模型。现在,您可以输入一个新的图像并保存模型,如下所示。

x = load_some_image()
model.predict(x) #Returns a softmax array
model.export_model()

导出方法的输出将是 TensorFlow 模型文件类型。这可以用来做典型的张量流模型可以用来做的任何事情。对于其他两种模型类型(文本、结构化),过程几乎是相同的。例如,文本分类器甚至可以接受一个字符串作为输入,并自己执行嵌入!

自动建模和模块

如果 AutoKeras 被用于生产级软件,那么基本用例可能就不够用了。幸运的是,AutoModel 和 Blocks 允许用户构建他们可能需要的任何管道和潜在架构。

来源

上图是一个 AutoModel,它是上面列出的分类器对象的基类。建造一个这样的可以完成同样的任务,但是对管道有更多的控制。图中的每一步称为一个块。这些范围从预处理到完整的神经网络,并按顺序串在一起。初始模块(输入、标准化等。)很容易理解,但是网络可能会令人困惑。例如,当谈到卷积块时,我们不是在顺序网络中使用单个卷积,而是使用整个 CNN。上面的 CNN 和 ResNet 模块将把每种网络类型的完整架构添加到要尝试的网络列表中。与回归输出相反,合并块仅意味着将分类头信号视为相等,以执行分类(softmax/binary)。

对于fitpredict步骤来说,完成类似任务的代码是相同的,但是每个程序块需要一行代码。下面是我创建的一个自动模型的例子:

input_node = ak.ImageInput()
out_node = ak.Normalization()(input_node)
out_node1 = ak.ConvBlock()(out_node)
out_node2 = ak.XceptionBlock()(out_node)
out_node3 = ak.ResNetBlock()(out_node)out_node = ak.Merge()([out_node1, out_node2, out_node3])
out_node_c = ak.ClassificationHead()(out_node)auto_model = ak.AutoModel(inputs=input_node, outputs=[out_node_c], max_trials=20)auto_model.fit(x=x_train, y=y_train, epochs=100)

当这个 NAS 开始时,AutoKeras 将尝试 CNN、类 Xception 和类 ResNet 架构的变体,平均分布在我指定的 20 个试验中。同样重要的是要注意,这些块不是连续的,即使它们在代码中看起来是这样的。它们可以被认为是添加到每一行的 AutoModel 的服务。

除了网络模块之外,还有许多其他模块可以添加到流水线中。例如,在ImageInput()方法之后添加这个函数可以在搜索期间执行一系列的增强:

ak.ImageAugmentation(percentage=0.25, rotation_range=180, random_crop=True)

在反馈到网络之前,AutoKeras 现在会对我们的图像进行所有这些放大。

此外,如果我们需要切换到回归任务(图像质量从 0 到 1),那么ak.ClassificationHead()(out_node)可以转换为:

ak.RegressionHead()(out_node)

我还可以举出更多关于块提供的适应性的例子。这同样适用于其他两种类型的任务,文本的自定义单词嵌入和结构数据的特征工程。

多任务学习

我想介绍的最后一个复杂特性是多任务学习。神经网络体系结构的底层通常需要多种输出类型。例如,我最近为一个客户做的实现需要图像类别和质量输出。渴望在 AutoKeras 中实现这一点,我研究了如何用多任务框架来实现这一点。下面的代码实现了这一点。

input_node = ak.ImageInput()
out_node = ak.Normalization()(input_node)
out_node1 = ak.ConvBlock()(out_node)
out_node2 = ak.XceptionBlock()(out_node)
out_node3 = ak.ResNetBlock()(out_node)out_node = ak.Merge()([out_node1, out_node2, out_node3])
out_node_t = ak.ClassificationHead()(out_node)

out_node_q = ak.RegressionHead()(out_node)

auto_model = ak.AutoModel(inputs=input_node, outputs=[out_node_t, out_node_q], max_trials=20)
auto_model.fit(x=im_in, y=[ty_y, qual_y], epochs=100)

该模型同时创建 softmax 数组和原始浮点输出。您可能注意到的主要变化是在 ClassificationHead 旁边添加了 RegressionHead。接下来,在 AutoModel 的构造函数中描述这两个输出。最后,两个输出数据集被输入到y=[ty_y, qual_y],这样模型就知道对每个头部进行什么样的训练。这总体上创建了初始块的两个独立的网络分支。来自 CNN 的相同输出被传递给每个分支,但是从每个分支接收所需的质量分数和分类数组。

AutoKeras 的附加功能几乎是无穷无尽的。除了给予任何数据科学家构建最佳的、强大的架构的能力之外;它还允许初学者获得新应用程序所需的张量流模型。我很高兴看到 AutoKeras 扩展到哪里,他们已经宣布了时间序列和其他功能即将推出。我希望这有助于你看到这项伟大技术的潜力,我期待着听到你可能已经能够使用它!

参考文献

[1]https://github.com/keras-team/autokeras

[2]https://en.wikipedia.org/wiki/Neural_architecture_search

https://autokeras.com

https://github.com/carpedm20/ENAS-pytorch

[5]https://dl.acm.org/doi/10.1145/3292500.3330648

[6]https://autokeras.com/tutorial/customized/

AutoML 和 AWS 自动引导入门

原文:https://towardsdatascience.com/getting-started-with-automl-and-aws-autogluon-6bc7ed7aef95?source=collection_archive---------32-----------------------

利用 AWS AutoML 库自动生成建立了一个目标检测模型

维克托·加西亚在 Unsplash 上拍摄的照片

原载于 2020 年 4 月 20 日https://www . philschmid . de

介绍

谷歌首席执行官桑德尔·皮帅写道“…设计神经网络是极其耗时的,并且需要专业知识,这限制了它在较小的科学家和工程师群体中的使用。“在这之后不久,谷歌于 2018 年初推出了其服务 AutoML。

AutoML 旨在使机器学习专业知识有限的开发人员能够针对其业务需求训练高质量的模型。AutoML 的目标是自动化所有主要的重复性任务,如特征选择超参数调整。这允许在更短的时间内创建更多的模型,并提高质量和准确性。

机器学习的基本两步方法:首先,通过使模型符合数据来创建模型。第二,该模型用于预测新(以前未见过的)数据的输出。

这篇博客文章演示了如何快速开始使用 AutoML。它会给你一步一步的教程,如何建立一个对象检测模型使用自动旋转,具有一流的准确性。我用一个完整的例子创建了一个 Google Colab 笔记本

AWS 正在进入 AutoML 领域

在 Re:Invent 2019 上,AWS 为他们的托管机器学习服务 Sagemaker 以及其他“ Sagemaker 自动驾驶 ”推出了一系列附加组件。Sagemaker Autopilot 是一项 AutoML 服务,可与 Google AutoML 服务相媲美。

2020 年 1 月,亚马逊网络服务公司(AWS)秘密推出了一个名为autoglon的开源库,这是 Sagemaker Autopilot 背后的库。

AutoGluon 使开发人员能够编写基于机器学习的应用程序,这些应用程序使用图像、文本或表格数据集,只需几行代码。

凭借这些工具,AWS 进入了托管 AutoML 服务(MLaas)领域,并与谷歌的 AutoML 服务展开竞争。

什么是自转?

“autoglon支持易于使用和易于扩展的 AutoML,专注于深度学习和跨图像、文本或表格数据的现实应用。面向 ML 初学者和专家,AutoGluon 使您能够…”

  • 快速原型化深度学习解决方案
  • 自动超参数调整、模型选择/架构搜索
  • 改进现有的定制模型和数据管道**

AutoGluon 使您只需 3 行代码即可构建机器学习模型。

目前,AutoGluon 可以为图像分类、对象检测、文本分类和使用表格数据集的监督学习创建模型。

如果你对 autoglon 如何在幕后完成所有的魔术感兴趣,可以看看 AWS 开源博客上的“autoglon 机器学习,一个开源的 AutoML 库”帖子。

辅导的

我们将建立一个目标检测模型,检测图像上的水果(苹果、橘子和香蕉)。我用大约 300 张图片建立了一个小数据集来实现快速训练过程。你可以在这里找到数据集。

在本教程中,我使用了带有 GPU 运行时的 Google Colab。如果你不确定如何使用 GPU 运行时,看看这里的。

好了,现在让我们开始教程。

安装自动旋转

AutoGluon 为不同的硬件首选项提供不同的安装包。如需更多安装说明,请查看此处的自动引导安装指南。

第一步是用 pip 和 CUDA 支持安装AutoGluon

为了让 AutoGluon 在 Google Colab 中工作,我们还必须安装ipykernel并重启运行时。

成功重启运行时后,您可以导入autogluon并打印出版本。

加载数据和创建数据集

下一步是加载我们用于对象检测任务的数据集。在 AutoGluon 的ObjectDetection任务中,通过将Dataset()format参数调整为cocovoc,可以使用 PASCAL VOC 格式或 COCO 格式。 Pascal VOC 数据集包含两个目录:AnnotationsJPEGImagesCOCO 数据集的格式为JSON,是“信息”、“许可证”、“图像”、“注释”、“类别”的集合。

对于训练,我们将使用我构建的tiny _ fruit _ object _ detection数据集。该数据集包含大约 300 张香蕉、苹果、橙子或它们的组合的图片。

我们使用 240 幅图像进行训练,30 幅用于测试,30 幅用于评估模型。

数据集的样本图像

使用下面的命令,我们可以downloadunzip这个只有 29MB 的数据集。在这之后,我们用task.Dataset()创建我们的Dataset用于训练和测试。

训练模型

第三步是用创建的dataset训练我们的模型。在 AutoGluon 中,您将分类器定义为变量,此处为detector,并在训练期间在fit()函数中定义参数。例如,您可以定义一个time_limit,它会在特定时间后自动停止训练。您可以为自己的learning_rate定义一个范围或设置epochs的数量。最重要的参数之一是num_trials。该参数定义了可尝试的超参数配置的最大数量。您可以在这里找到可配置参数的完整文档。

我们将为20 epochs训练我们的模型,并通过设置num_trials=3训练 3 个不同的模型。

结果,我们得到了一个具有平均精度(mAP)和历元数的图表。地图是计算对象检测模型的准确度的常用度量。

我们最好的模型(蓝线)完成了0.9198171507070327的地图

评估模型

完成培训后,我们现在将在我们的test数据集上评估/测试我们的模型的性能。

测试数据集上的地图是0.8724113724113725,考虑到我们只使用 240 幅图像和 20 个时期进行训练,这已经很不错了。

预测图像

要使用我们训练好的模型进行预测,您可以简单地运行detector.predict(image_path),它将返回一个元组(ind),其中包含检测到的对象的类 id、置信度得分(prob)以及相应的预测边界框位置(loc)。

保存模型

在撰写本文时,保存对象检测模型还没有在 *0.0.6* 版本中实现,但是将在下一个部署版本中实现。

要保存你的模型,你只需要运行detector.save()

负载模型

在撰写本文时,加载对象检测模型还没有在版本 *0.0.6* 中实现,但是将在下一个部署版本中实现。

感谢阅读。你可以在这里找到 Google Colab 笔记本包含完整示例

在 Python 中使用比特币数据

原文:https://towardsdatascience.com/getting-started-with-bitcoin-historical-data-set-with-python-and-pandas-cd31417d1736?source=collection_archive---------27-----------------------

用 Python 和熊猫入门比特币历史数据集。

最近几个月,比特币和加密货币总体上一直在上涨。从 3 月份的突然崩盘开始,比特币的反应非常好,价格几乎翻了一倍。再加上本月早些时候大肆宣传的减半事件,现在有很多人好奇并希望开始投资和交易。

作者创建的图像

好吧,在这里我展示了你开始分析比特币并将其转化为可用形式所需的 Python 代码。我将满怀希望地展示使用 pandas 库在 Python 中做到这一点是多么容易。完整的代码可以在文章的底部找到。

如果您对加密货币不感兴趣,那么这可能也是一个很好的教程,展示了 Python 和 pandas 在数据操作和分析方面的强大功能,并且可能有一些有用的代码片段可以应用于其他项目。

安装熊猫图书馆

首先,如果你还没有熊猫库,你需要安装它。只需在命令行中运行以下命令。

pip install pandas

或者,如果您像我一样使用 Anaconda,您可以在您使用的环境中打开 Anaconda 终端,然后输入以下命令。

conda install pandas

如果没有出现错误,您应该已经正确安装了库。我们马上会做最后一次测试。

对于数据分析,我发现 Jupyter Notebook 是最好的 IDE,因为它允许您以块的形式运行代码片段,因此在导入和操作大型数据集时可以节省大量时间。但是,任何 IDE 都可以。

所以现在对于一些编码…

打开一个新脚本并保存它。第一个任务是测试 pandas 库是否安装正确。运行以下代码将库导入到脚本中。如果没有出现错误,那么您可以继续本教程的其余部分。如果没有,你必须正确安装熊猫图书馆——谷歌将是你的朋友。

import pandas as pd

获取数据集

我将使用的数据来自 Kaggle,这是世界上最大的数据科学社区,也是寻找大量数据集的最佳地点之一。这个特殊的数据集是比特币从 2012 年 1 月 1 日到 2020 年 4 月 22 日的历史分钟数据。

一旦您将 csv 文件下载并保存到与您的脚本相同的目录中,您现在将希望加载该数据。为此,我们在 pandas 中使用了 pd.read_csv() 方法,将数据文件名作为字符串传递。这将创建一个包含 csv 文件中所有数据的数据框。

我们还将运行 head()【方法】在数据帧上向我们显示我的前 5 行数据。如您所见,有一行数据后跟四行连续的 NaN 值。这是因为有些数据丢失了,因此我们需要做一些清理工作。这是由多种原因造成的,但似乎在这个数据集的早期,数据没有每分钟归档一次,因此丢失了大量数据块。

raw_data = pd.read_csv("bitstampUSD_1-min_data_2012-01-01_to_2020-04-22.csv")
raw_data.head()

运行 。数据帧上的 tail() 方法将显示最后 5 行,您可以看到这些行实际上已满。此外,请注意数据框索引列(最左侧)中该数据集中的行数。超过四百万!对于 Excel 来说太多了,但是 Python 和 pandas 可以轻松处理。

raw_data.tail()

清理并格式化数据框

因此,现在我们想要创建一个数据框,其中包含 NaN 值的所有行都被移除。对于熊猫来说,这非常简单,我们只需使用 。dropna() 方法,并将其分配给一个新的数据帧,我们称之为 df 。这是包含所有有用数据的数据框,我们将在以后的分析中使用这些数据。

我们也称之为。reset _ index()方法在数据帧上使索引列复位。这将为第一行数据分配一个从 0 开始的索引值,为第二行分配 1,依此类推。我们还将传递参数 inplace=True 。这在 pandas 中很常用,它告诉 Python 我们希望原始数据框成为该数据框的新编辑版本。如果 原位 未设置为 ,那么我们正在处理的数据帧将在生产线运行后保持不变。使用 探究这种行为。 头()【方法】查看指标值。

我们还传递第二个参数 drop=True 。默认情况下。reset _ index()方法将重置我们数据的索引,但原始索引列将被复制到一个名为 "index" 的新列中。我们不需要这个额外的列,因此我们将删除它。这也可以使用 来实现。drop()【方法】对数据框和指定列名进行 drop。

df = raw_data.dropna()
df.reset_index(inplace=True, drop=True)
df.head()

更改时间戳格式

您可以看到'时间戳''列的格式很奇怪,这实际上是 UNIX 时间格式,因此我们想将其转换为 UTC 时间。我们使用 pd.to_datetime() 方法来实现。我们将传递我们想要对其执行此函数的数据的参数,这是我们数据的‘时间戳’列,我们还将传递参数unit =‘s’,它告诉函数我们输入的 UNIX 时间的单位是秒。我们使用下面的代码行将该函数的输出保存到数据框中的‘Timestamp’列。注意,在 pandas 中引用列中的数据,我们使用下面的概念df[‘Timestamp’]。其中方括号内传递的字符串是列的名称。

df['Timestamp'] = pd.to_datetime(df['Timestamp'], unit='s')
df.head()

我们可以看到,部分数据集实际上来自 2011 年。为了完整起见,我将删除这四行。当只有几行要删除时,最简单的方法是简单地指定列表中行的索引,并将其传递给 降()法。我们还必须再次传入参数 inplace=True 。最后像之前一样修正指数。

df.drop([0,1,2,3], inplace=True)
df.reset_index(inplace=True, drop=True)
df.head()

绘制数据以进行目视检查

现在,我们的数据有了一个很好的结构,希望所有数据都在我们的数据框中。验证此时一切正常的一个非常快速的方法是简单地绘制比特币随时间变化的价格。我们将通过以下方式做到这一点

运行 。plot() 方法在数据帧上然后指定我们想要在 x 轴和 y 轴上的列。 。pandas 中的 plot() 方法实际上在后台使用 matplotlib 库来显示图形,并将尝试为轴选择合理的默认设置。如果你愿意,这个图表当然可以定制。

df.plot(x="Timestamp",y="Weighted_Price")

创建新列

太好了!因此,我们的数据看起来是正确的,因此我们可以进行更有趣的部分,即分析或处理数据。您可能想做的一件事是创建一个新列,以某种方式处理数据。一个例子是找出每个连续时间点之间的差异。

我们可以使用 pandas 内置的一个名为 的方法来做到这一点。diff()。我们只需使用下面的符号 df["新列的标题"] 指定我们希望创建的列,并将其设置为我们希望找到的与 不同的列。diff()方法。

df["closeDiff"] = df["Close"].diff()
df.head()

注意我们创建的名为“closeDiff”的新列。

现在,让我们假设我们想要为数据中的每一年创建数据框。比如 2019 年所有数据的一个数据帧 df19 。一种方法是首先创建一个名为“year”的列,其中包含每个数据点的年份值。然后我们将创建一个新的 dataframe,只包含“年”列等于 2019 年的数据行。

为此,我们将首先创建一个' year' 列。我们将'时间戳'列输入到 pd 中。DatetimeIndex 类并请求。年份属性。这将返回我们每个时间戳的年值,我们将该数据分配给一个新列,我们将其定义为' year'

df["year"] = pd.DatetimeIndex(df["Timestamp"]).year
df.head()

所以现在我们想要一个新的数据帧 df19 ,它包含我们的数据帧 df 中的所有行,这些行在“year”列中的值为 2019。为此,我们编写了下面一行代码。这种表示法可能有点令人困惑,但在这里我们只是说,获取所有带有数据框 df 的行,其中“year”列等于 2019,并将其分配给一个名为 df19 的新数据框。

df19 =  df[df["year"] == 2019]
df19.reset_index(inplace=True, drop=True)
df19.head()

现在,我们可以像之前的数据一样绘图,但这一次只针对 2019 年。

df19.plot(x="Timestamp",y="Weighted_Price")

保存数据

现在你有了干净的数据,也许你已经增加了数据或者产生了一个子集。通常,您希望保存这些数据,这样就不必再次运行这些代码。使用非常简单。to _ CSV()数据帧上的方法。下面是我用来保存 df19 数据帧的代码,这样我将来就可以很容易地使用它。您传递给该方法的第一个参数是您希望保存它的文件名,并且 index=False 告诉 Python 不要将数据帧的索引保存到 csv 文件中通常不需要的列。

df19.to_csv('btc19.csv', index=False)

现在你有了它,一个让你开始使用这个比特币历史数据集的基本框架,以及一些你可以在 Python 和 pandas 中做的基本事情。没有的全精简代码。头() 尾巴()【通话记录】见下图。

散景入门

原文:https://towardsdatascience.com/getting-started-with-bokeh-effortlessly-elegant-interactive-data-visualisations-in-python-703249565bb3?source=collection_archive---------27-----------------------

入门

轻松优雅的 Python 交互式数据可视化

照片由丹尼斯·约翰逊Unsplash 拍摄

在这篇文章中,我的目标是给你一个关于散景的介绍,详细说明它是什么,为什么你应该使用它,以及如何可以轻松开始!

什么是散景?

Bokeh 是一个简洁的 Python 库,它允许我们快速、轻松地创建高性能、专业的交互式数据可视化和 web 应用程序。你可以在这里 查看一些例子,看看散景可以做什么

用散景可以做什么的一个例子。

Bokeh 最吸引人的品质是它成功地平衡了简单性(创建复杂的交互式可视化所需的代码很少)和高级定制的灵活性(如果你需要的话)。无论您只是想在 Jupyter 笔记本上创建更漂亮的图形,还是开发和部署完整的 web 应用程序,Bokeh 对于任何 Python 用户来说都是一个很好的可视化工具。

散景的基础

情节

Bokeh 的 Plot 类提供了画布,我们可以在上面构建我们的可视化。要开始在散景中创建可视化效果,我们可以简单地实例化一个figure对象:

如果我们要运行上面的代码,我们将生成一个空白的图形对象,然后输出为 HTML 文件,保存到指定的路径,然后显示在 web 浏览器的新选项卡中。如果我们在 Jupyter 笔记本上工作,并且想要在输出单元格中直接显示我们的可视化,我们也可以使用output_notebook()函数。

到目前为止,这还不是很鼓舞人心,因为我们还没有添加任何数据——但是我们将在下一节中看到我们如何开始在我们的数字基础上快速添加细节。

字形

字形是散景中最基本的绘图单位。它们本质上由可视标记组成,带有可能与我们的数据相关联的属性。从简单的线条象形文字,到六边形的瓷砖格子(六边形象形文字),根据我们的观想需要,有许多不同的象形文字可供我们使用。

我们可以扩展上面的代码,为我们的图形添加一个字形,就像:

散景的威力显而易见。通过一行额外的代码,我们向我们的绘图添加了一些数据,我们可以利用散景的开箱即用交互性立即摆弄和探索这些数据。图右侧的绘图工具使我们能够拖动、缩放和重置我们的绘图。我们甚至可以使用SaveTool功能将视图保存到图像文件中。

探索散景的内置绘图工具,用一个简单的线条字形。

你可以探索我们能够选择的各种字形,以及它们的相关属性, 这里

向一个图形添加多个字形不成问题,我们只需分别调用我们需要的所有字形方法,Bokeh 就会按照指定的顺序将它们分层到我们的图形上。

覆盖在图形上的多个字形。

数据源

将我们的数据指定为散景对象再简单不过了。Bokeh 兼容大家熟悉的数据格式 lists、NumPy 数组和 pandasdata frames;所有这些我们都可以作为参数直接传递给 glyph 方法。

NumPy 源数据的线条标志符号。

散景也内置了自己的数据格式,即 ColumnDataSource 。这形成了散景对象使用的基本底层数据结构。事实上,当我们向 Bokeh 提供列表、NumPy 数组或 pandasdata frame时,这些在后台被隐式转换为 ColumnDataSource 对象。ColumnDataSource 使在字形之间共享数据和链接所选数据变得容易,并允许我们提供额外的数据,正如我们将在后面看到的,这些数据可以用来给我们的可视化添加注释。

我们可以用以下方式定义 ColumnDataSource:

一旦我们定义了一个 ColumnDataSource ,我们可以通过简单地指定它的列名,并将我们的 CDS 作为绘图方法的source参数来轻松地访问数据。下面我们使用 Bokeh 的一个 CSV 样本数据集创建一个示例图,我们将它读入熊猫数据帧,然后转换为列数据源。

一段时间内苹果股票的开盘价(来自 Bokeh 样本数据的数据集)。

定制可视化

配置绘图工具

正如我们在 Bokeh 中实例化一个figure对象时所看到的,绘图带有各种内置的交互特性。如果我们不明确表达这些,Bokeh 将提供默认的工具套件。然而,如果我们愿意,我们也可以在创建我们的图形对象时定义它们:

您可以在此 浏览官方文档 中提供的所有绘图工具选项。

悬浮工具

Bokeh 中的一个绘图工具是 HoverTool 类,值得单独列出来。这是一个很好的功能,让我们只需将鼠标悬停在一个对象上,就可以从数据中发现更多的细节。

我们可以通过为我们希望包含的数据提供一个(label, value)元组列表来指定一个 HoverTool。

前缀为@的字段名称与ColumnDataSource列标题相关联,以$开头的名称是“特殊字段”,对应于绘图元数据,如$index (数据点索引)、$x (光标的 x 坐标)。

向我们的苹果股票图添加悬停工具。

色彩映射

散景提供了各种内置调色板供我们选择,完整的列表可以在 这里 找到。用特定的调色板来设计我们的可视化数据的一个有用的特性是在散景中我们可以使用的“颜色映射器”。这些允许我们直观地阐明数据的一些属性,取决于它的值。

例如,linear_cmap功能允许我们根据数值在线性标尺上的位置来分配颜色:

线性颜色映射示例,应用于我们之前的正弦图。

类似地,还有一个log_cmap函数,以完全相同的方式工作,但是使用对数标度。我们甚至可以在图的旁边加入一个ColorBar来解释颜色到值的映射。

对于分类数据,我们可以使用CategoricalColorMapper类来定义各种分类因子和指定调色板之间的关系。Bokeh 有一个处理分类数据的详细指南 这里 ,如果你愿意,你可以在这里读到更多。

释文

标题、图例、轴标签、数据标签等注释也可以添加到绘图中。这里有许多不同的选项来定制我们的地块;我不会在这些问题上深究太多细节,因为有很多好的文档说明可以做什么这里这里

以下示例显示了我们在创建图形时可能想要定义的一些最常见的属性:

安排情节

如果我们想要在同一个输出中组合多个图,我们可以使用bokeh.layouts模块来定义这些图是如何排列的。

行和列

rowcolumn功能允许我们将图形组织成行、列或由两者组合而成的嵌套布局。

网格

使用gridplot功能可以轻松创建统一的网格图。

制表符

我们甚至可以在选项卡式布局中显示我们的可视化,能够在不同的图之间切换。

关联图

要链接图的轴,我们可以简单地将它们的轴范围属性定义为相等:

p3.x_range = p2.x_range = p1.x_range
p3.y_range = p2.y_range = p1.y_range

为了在我们的可视化中链接数据选择,所有需要的是它们共享相同的数据源:

结论

照片由 Josh BootUnsplash 上拍摄

我们现在已经很好地掌握了散景的基础知识,应该已经具备了开始实验和创建我们自己的自定义可视化所需的一切。也就是说,就散景作为可视化工具的全部功能而言,这只是冰山一角。

在我的下一篇文章中,我们将探索如何将我们所学的知识更进一步,从创建美丽的可视化过渡到开发具有更多交互性的迷人的 web 应用程序。到时见,但现在:

感谢阅读!

这篇文章的所有源代码都可以在这里找到:

[## Emile gill 743/散景基础

我在 Medium 上的博文附带的源代码,介绍了 Python 中的 Bokeh 库以及它所提供的功能。

github.com](https://github.com/emilegill743/bokeh-basics)

如果你喜欢这篇文章,可以看看我的其他文章:

[## 使用 GitHub 页面,通过 5 个简单的步骤免费创建一个网站

不到 10 分钟就能在网上建立你的个人投资组合网站。

towardsdatascience.com](/launch-a-website-for-free-in-5-simple-steps-with-github-pages-e9680bcd94aa) [## 聪明的方法是找到一个杂货递送点

使用 Python、Heroku 和 Twilio 从一个杂货网站的 API 中抓取数据,并在出现插槽时获得文本通知…

towardsdatascience.com](/finding-a-grocery-delivery-slot-the-smart-way-f4f0800c4afe) [## PostgreSQL 入门实用指南🐘

Python 的 PostgreSQL、pgAdmin 和 SQLAlchemy 入门。将 SQL 融入 Python 的核心…

towardsdatascience.com](/a-practical-guide-to-getting-set-up-with-postgresql-a1bf37a0cfd7)

批量使用 CellProfiler 入门

原文:https://towardsdatascience.com/getting-started-with-cellprofiler-in-batch-31dcb8001a5a?source=collection_archive---------83-----------------------

批处理模式下运行 CellProfiler 是自动化大规模分析的理想方式。或者没有你喜欢自动化的大规模分析!

批量运行 CellProfiler 的好处之一是您可以拆分您的分析。当您有一个非常大的数据集时,这很有帮助。假设您有一个需要 1 小时才能完成的大型数据集。你可以将分析分成 4 个部分,每个部分在 15 分钟内完成。

如果内存或 CPU 不足,这也是一个重要的考虑因素。您分析的数据集越大,它消耗的内存就越多。如果你需要找到一种方法来减少你的计算资源,你通常可以分割你的数据集。CreateBatchFiles 模块的说明描述了如何设置 CellProfiler 管道并将其提交给群集。这里有一个步骤 7 的教程,提交你的批处理到集群。我们开始吧!

如果你喜欢看,这里有一个视频,我会按照描述的步骤进行。

Docker 是一种打包应用程序的方式。docker 容器就像一个虚拟机,只是没有可视界面。一旦你设置好了,你就可以像对待一台普通电脑一样对待它。

快速免责声明,如果您对命令行感到非常不舒服,您可能需要寻求帮助。这不需要太多的 Linux 命令行知识,但是您需要能够键入命令和导航目录结构。这里有一个来自 Ubuntu 的快速解释和教程来帮助你开始。

我们将使用默认的 CellProfiler docker 图像,稍作修改。我们进行这些更改是因为映像的设置方式非常适合作业队列环境,但我们在这里想要的是进行一些探索性分析。

在其中创建一个项目目录、cellprofiler-batch-tutorial 和 cd。

mkdir cellprofiler-batch-tutorial 
cd cellprofiler-batch-tutorial

然后用下面的代码创建一个名为 Dockerfile 的文件:

FROM cellprofiler/cellprofiler:3.1.9RUN apt-get update -y; apt-get install -y unzip imagemagickENV TINI_VERSION v0.16.1 ADD 
[https://github.com/krallin/tini/releases/download/](https://github.com/krallin/tini/releases/download/)${TINI_VERSION}/tini /usr/bin/tini 
RUN chmod +x /usr/bin/tini

现在我们将构建新的 CellProfiler 图像!

docker build -t cellprofiler .

使用示例人类数据集进行简单分析

我们将从一个非常简单的例子开始,来感受一下我们如何使用批处理模式运行。一旦我们到达那里,我们将进入更复杂的管道。(WOOOO!)

让我们来看看第一批数据集。

wget [http://cellprofiler-examples.s3.amazonaws.com/ExampleHuman.zip](http://cellprofiler-examples.s3.amazonaws.com/ExampleHuman.zip)
unzip ExampleHuman

这是数据集的样子-

. 
├── ExampleHuman.cppipe 
├── README.md 
└── images 
 ├── AS_09125_050116030001_D03f00d0.tif 
 ├── AS_09125_050116030001_D03f00d1.tif 
 └── AS_09125_050116030001_D03f00d2.tif

“ExampleHuman.cppipe”是一个 CellProfiler 管道,“README”是通常的 README,图像是我们要用 CellProfiler 管道分析的图像!

之前我说过你的 docker 镜像是一台电脑。它(大部分)是。我们现在要把它当电脑用。

现在,您将 docker 容器用作外壳。Cd 到您的项目目录,并检查您期望的文件是否在那里。

cd /project/ExampleHuman
ls -lah # Should show the ExampleHuman dataset

确保您可以通过在帮助下执行 CellProfiler 来运行 CellProfiler CLI。(这总是一张不错的支票。)

cellprofiler — run — run-headless — help

现在让我们运行我们的示例人类数据集!

cellprofiler — run — run-headless \ 
 -p ExampleHuman.cppipe \ 
 -o output -i images

首先,这个 CellProfiler 分析只使用了一个 imageset,所以它并不有趣,但是它提供了很多信息。

您可以使用-f 和-l 标志来告诉 CellProfiler 启动,或者使用-f 作为第一个标志,使用-l 作为最后一个标志来拆分数据集。

完成后,您应该会在输出目录中看到一个图像和一些 csv 文件!

如果你正在用 CellProfiler 设计一个大规模的批处理管道,你需要知道你使用了多少内存和 CPU。我们将使用名为 Portainer 的工具来获取这些信息。

Portainer 做了很多事情,这些事情非常酷,但现在我们只使用它来分析在 docker 容器中运行的 cellprofiler 进程。

像这样启动 portainer 服务:

docker volume create portainer_data 
docker run -d -p 8000:8000 -p 9000:9000 — name=portainer — restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer

转到浏览器并打开 localhost:9000 来查看 Portainer 服务。可能会提示您创建用户名和密码。如果是这样,就这样做,然后您应该会看到一个如下所示的主页:

现在像这样分析数据集:

请注意,运行单个映像的命令会很快退出。您必须快速地实时查看内存分析,否则您可能需要多次重新运行它。

现在,我们已经讨论了如何通过一个简单的例子开始计划和考虑批处理我们的 CellProfiler 管道。现在让我们进入一个真实的数据集!让我们使用来自 Broad bio image Benchmark Collection 的 BBBC021。我们将使用第 1 周的数据,大约 15GB。

我将向您展示我是如何运行这个数据集的,但 CellProfiler 非常灵活,我相信还有其他方法。

你应该还在你的码头集装箱里。到了那里,让我们获取一些数据!

cd /project
mkdir -p BBBC021/Week1
mkdir -p BBBC021/Week1_output
cd BBBC021/Week1
wget https://data.broadinstitute.org/bbbc/BBBC021/BBBC021_v1_images_Week1_22123.zip
wget https://data.broadinstitute.org/bbbc/BBBC021/BBBC021_v1_images_Week1_22141.zip
wget https://data.broadinstitute.org/bbbc/BBBC021/BBBC021_v1_images_Week1_22161.zip
wget https://data.broadinstitute.org/bbbc/BBBC021/BBBC021_v1_images_Week1_22361.zip
wget https://data.broadinstitute.org/bbbc/BBBC021/BBBC021_v1_images_Week1_22381.zip
wget https://data.broadinstitute.org/bbbc/BBBC021/BBBC021_v1_images_Week1_22401.zip
find $(pwd) -name "*zip" | xargs -I {} unzip {}
# Clean up the zips, we don't need them anymore
find $(pwd) -name "*zip" | xargs -I {} rm -rf {} 
cd ../..
# Run $(pwd) to check where you are. You should be in /project/BBBC021
wget https://data.broadinstitute.org/bbbc/BBBC021/BBBC021_v1_image.csv
wget https://data.broadinstitute.org/bbbc/BBBC021/BBBC021_v1_compound.csv
wget https://data.broadinstitute.org/bbbc/BBBC021/BBBC021_v1_moa.csv
wget https://data.broadinstitute.org/bbbc/BBBC021/analysis.cppipe
wget https://data.broadinstitute.org/bbbc/BBBC021/illum.cppipe

我认为最好从数据集本身来解释。

您还会看到有两条管道,一条是照明校正管道,另一条是分析管道。我不得不摆弄精确的输入和输出,以使它正确无误地工作,但它是如何工作的:

illum.cppipe 
Week1/Week1_22123/ 
 # Inputs to the Illumination AND Analysis Pipeline 
 Week1*.tif 
 # Outputs to the Illumination Pipeline 
 # Inputs to the Analysis Pipeline 
 Week1_22123_Illumctin.npy 
 Week1_222123_IllumActinAvg.npy 
 Week1_222123_IllumDAPI.npy 
 Week1_222123_IllumDAPIAvg.npy 
 Week1_222123_IllumTubulin.npy 
 Week1_222123_IllumTubulinAvg.npy 
 # Outputs to the Analysis Pipeline 
 overlay 
 labels 
 measurements 
 illum_corrected

illum_corrected、labels 和 overlay 目录中应有图像,measurements 目录中应有 csv 文件。

分析管道似乎期望来自照明管道的输出存在于相同的目录中。

器械包附带的数据文件包含所有周的数据。我们只使用第 1 周,因为我在笔记本电脑上做这个。

cd /project/BBBC021 
head -n 1 BBBC021_v1_image.csv > images_week1.csv 
cat BBBC021_v1_image.csv | grep Week1_ >> images_week1.csv

我们实际上不会使用这个文件,但是它有助于理解分析的结构。

让我们确保至少能处理第一张图像。

您应该会看到如下所示的输出:

这是一张支票,而且只是一张支票。因为照明管道计算一些平均照明文件,我们不应该使用分而治之的方法。当您希望将整个管道作为一个整体运行时,您应该不带-f 或-l 重新运行 illum.cpipe。对于故障排除和考虑您希望如何批处理您的分析,您只需运行第一个图像集就可以了。

# Rerun this when you want to run the entire analysis 
# It will take some time, so don’t run until you’re sure! 
cellprofiler — run — run-headless \ 
 -p illum.cppipe \ 
 -o Week1/Week1_22123 -i Week1/Week1_22123

该数据集附带一个 BBBC021_v1_image.csv,这是一个 CellProfiler CSV 数据文件。这些是根据实验中的分组创建的,创建它们的具体细节取决于您的具体情况。您还可以使用-f 和-l 标志来选择第一个和最后一个进行批处理,或者两者的某种组合。声明,我不是生物学家,实际上生成这些管道超出了我的能力。;-)

因为我们可以分割分析,所以我们希望确保每个分割都有自己的输出目录。这是必要的,以确保我们不会每次都破坏输出!

这将需要一些时间来完成。在我的笔记本电脑上,花了大约 10 分钟完成。为了好玩,让我们看看门户网站的统计数据!

奖金-人类可读的图像

当在常规文件查看器中打开时,HCS 图像经常显得非常暗。当用 CellProfiler 打开时,它们很好,但在其他情况下非常暗。如果您希望能够使用系统图像查看器或通过网络浏览器查看图像,您可以使用 imagemagick 对其进行转换。

cd /project/BBBC021/Week1/Week1_22123/f1-l1/labels/Week1_22123 
find -name ‘*tiff’ | sed ‘s/tiff//g’ | xargs -I {} convert -auto-level -quality 100 {}tiff {}png

请注意,产生的。png 图像不适合在 CellProfiler 中进行后续的重新分析。它们仅供人类观赏!

就是这样!我希望您更好地了解如何运行 CellProfiler 管道批处理!

特别感谢 Carpenter Lab 对内容和客座博文的指导和反馈!

引用和数据集

我们使用图像集 BBBC021v1 【蔡锷等人,分子癌症治疗学,2010】,可从广泛的生物图像基准收集获得【Ljosa 等人,自然方法,2012】。

https://cellprofiler.org/examples/页面中的直接生成了示例人类数据集

原载于 2020 年 5 月 18 日 https://carpenterlab.broadinstitute.org

COCO 数据集入门

原文:https://towardsdatascience.com/getting-started-with-coco-dataset-82def99fa0b8?source=collection_archive---------6-----------------------

理解计算机视觉常用数据集的格式

介绍

COCO ( 官网 ) dataset,意为“上下文中的常见对象”,是一组具有挑战性的高质量数据集,用于计算机视觉,大多是最先进的神经网络。该名称也用于命名这些数据集使用的格式。

引用 COCO creators:

COCO 是一个大规模的对象检测、分割和字幕数据集。COCO 有几个特点:

-对象分割

-在上下文中识别

-超像素素材分割

  • 33 万张图片(超过 20 万张)

-150 万个对象实例

  • 80 个对象类别

该数据集的格式由高级神经网络库自动理解,例如脸书检测器 2 ( 链接)。甚至还有专门为 COCO 格式的数据集构建的工具,例如 COCO-annotatorCOCOapi 。了解数据集的表示方式将有助于使用和修改现有数据集,也有助于创建自定义数据集。具体来说,我们对注释文件感兴趣,因为完整的数据集由图像目录和注释文件组成,提供了机器学习算法使用的元数据。

你能拿可可怎么办?

实际上有多个 COCO 数据集,每个数据集都是为特定的机器学习任务而制作的,带有额外的数据。3 个最受欢迎的任务是:

  • 对象检测 —模型应该得到对象的包围盒,即返回对象类的列表及其周围矩形的坐标;对象(也称为“东西”)是离散的、独立的对象,通常由部分组成,如人和汽车;该任务的官方数据集还包含用于对象分割的附加数据(见下文)

来源

  • 对象/实例分割 —模型不仅应获得对象(实例/“事物”)的边界框,还应获得分割遮罩,即紧密围绕对象的多边形坐标

来源

  • 素材分割 —模型应该进行对象分割,但不是在单独的对象(“事物”)上,而是在背景连续模式上,如草地或天空

来源

在计算机视觉中,这些任务有着巨大的用途,例如自动驾驶车辆(检测人和其他车辆)、基于人工智能的安全(人体检测和/或分割)和对象重新识别(对象分割或使用填充分割去除背景有助于检查对象身份)。

COCO 数据集格式

基本结构和共同要素

COCO annotations 使用的文件格式是 JSON,它以 dictionary(大括号内的键值对,{…})作为顶值。它还可以有列表(括号内的有序项目集合,[…])或嵌套的字典。

基本结构如下:

{
  "info": {…},
  "licenses": […],
  "images": […],
  "categories": […],
  "annotations": […]
}

让我们仔细看看其中的每一个值。

“信息”部分

该字典包含关于数据集的元数据。对于官方 COCO 数据集,如下所示:

{
  "description": "COCO 2017 Dataset",
  "url": "http://cocodataset.org",
  "version": "1.0",
  "year": 2017,
  "contributor": "COCO Consortium",
  "date_created": "2017/09/01"
}

如你所见,它只包含基本信息,带有指向数据集官方网站的"url"值(例如 UCI 存储库页面或在一个单独的域中)。在机器学习数据集中,这是一种常见的事情,指向他们的网站以获得额外的信息,例如,数据是如何和何时获得的。

“许可证”部分

以下是数据集中图像许可证的链接,例如具有以下结构的知识共享许可证:

[
  {
    "url": "http://creativecommons.org/licenses/by-nc-sa/2.0/", 
    "id": 1, 
    "name": "Attribution-NonCommercial-ShareAlike License"
  },
  {
    "url": "http://creativecommons.org/licenses/by-nc/2.0/", 
    "id": 2, 
    "name": "Attribution-NonCommercial License"
  },
  …
]

这里需要注意的重要一点是"id"字段——"images"字典中的每个图像都应该指定其许可证的“id”。

当使用图片时,确保你没有违反它的许可——全文可以在 URL 下找到。

如果您决定创建自己的数据集,请为每个图像分配适当的许可-如果您不确定,最好不要使用该图像。

“图像”部分

可以说是第二重要的,这个字典包含了关于图像的元数据:

{
  "license": 3,
  "file_name": "000000391895.jpg",
  "coco_url": "http://images.cocodataset.org/train2017/000000391895.jpg",
  "height": 360,
  "width": 640,
  "date_captured": "2013–11–14 11:18:45",
  "flickr_url": "http://farm9.staticflickr.com/8186/8119368305_4e622c8349_z.jpg",
  "id": 391895
}

让我们一个接一个地浏览这些字段:

  • "license":来自"licenses" 部分的图像许可证的 ID
  • "file_name":图像目录下的文件名
  • "coco_url""flickr_url":在线托管映像副本的 URL
  • "height""width":图像的大小,在 C 语言这样的低级语言中非常方便,因为在 C 语言中获取矩阵的大小是不可能的或者很困难的
  • 照片拍摄的时间

最重要的字段是"id"字段。这是在"annotations"中用来识别图像的编号,所以如果你想识别给定图像文件的注释,你必须在"images"中检查"id"中合适的图像文件,然后在"annotations"中交叉引用它。

在官方 COCO 数据集中,"id""file_name"相同(去掉前导零之后)。请注意,自定义 COCO 数据集可能不一定如此!这不是一个强制规则,例如,由私人照片制作的数据集可能具有与"id"毫无共同之处的原始照片名称。

“类别”部分

这个部分对于对象检测和分割任务和对于填充分割任务有点不同。

物体检测/物体分割:

[
  {"supercategory": "person", "id": 1, "name": "person"},
  {"supercategory": "vehicle", "id": 2, "name": "bicycle"},
  {"supercategory": "vehicle", "id": 3, "name": "car"},
  …
  {"supercategory": "indoor", "id": 90, "name": "toothbrush"}
]

这些是可以在图像上检测到的对象的类别(COCO 中的"categories"是类别的另一个名称,您可以从有监督的机器学习中知道)。

每个类别都有一个唯一的"id",它们应该在范围[1,类别数]内。类别也分组在“超级类别”中,你可以在你的程序中使用,例如,当你不在乎是自行车、汽车还是卡车时,检测一般的车辆。

素材分割:

[
  {"supercategory": "textile", "id": 92, "name": "banner"},
  {"supercategory": "textile", "id": 93, "name": "blanket"},
  …
  {"supercategory": "other", "id": 183, "name": "other"}
]

类别数开始很高,以避免与对象分割的冲突,因为有时这些任务可以一起执行(所谓的 全景分割 任务,也具有非常具有挑战性的 COCO 数据集)。ID 从 92 到 182 是实际的背景材料,而 ID 183 代表所有其他没有单独类别的背景纹理。

“注释”部分

这是数据集最重要的部分,包含特定 COCO 数据集每个任务的重要信息。

{
  "segmentation":
  [[
    239.97,
    260.24,
    222.04,
    …
  ]],
  "area": 2765.1486500000005,
  "iscrowd": 0,
  "image_id": 558840,
  "bbox":
  [
    199.84,
    200.46,
    77.71,
    70.88
  ],
  "category_id": 58,
  "id": 156
}
  • "segmentation":分割掩模像素的列表;这是一个扁平的对列表,所以你应该取第一个和第二个值(图中的 x 和 y),然后是第三个和第四个值,依此类推。得到坐标;注意,这些不是图像索引,因为它们是浮点数——它们是由 COCO-annotator 等工具从原始像素坐标创建和压缩的
  • "area":分割掩模内的像素数
  • "iscrowd":标注是针对单个对象(值 0),还是针对彼此靠近的多个对象(值 1);对于材料分段,该字段始终为 0 并被忽略
  • "image_id":“图像”字典中的“id”字段;警告:该值应该用于与其他字典交叉引用图像,而不是"id"字段!
  • "bbox":边框,即物体周围矩形的坐标(左上 x,左上 y,宽度,高度);从图像中提取单个对象非常有用,因为在很多语言中,比如 Python,可以通过访问图像数组来实现,比如cropped_object = image[bbox[0]:bbox[0] + bbox[2], bbox[1]:bbox[1] + bbox[3]]
  • "category_id":对象的类别,对应于"categories"中的"id"字段
  • "id":标注的唯一标识符;警告:这只是注释 ID,并不指向其他字典中的特定图像!

在处理群组图像("iscrowd": 1)时,"segmentation"部分可能略有不同:

"segmentation":
{
  "counts": [179,27,392,41,…,55,20],
  "size": [426,640]
}

这是因为对于许多像素来说,明确列出所有像素来创建分段掩码将占用大量空间。相反,COCO 使用自定义游程编码(RLE)压缩,这是非常有效的,因为分段掩码是二进制的,只有 0 和 1 的 RLE 可以多次减小大小。

总结

我们已经探索了 COCO 数据集格式,用于最流行的任务:对象检测、对象分割和材料分割。官方 COCO 数据集质量高,规模大,适合初学者项目、生产环境和最先进的研究。我希望这篇文章能帮助您理解如何解释这种格式,并在您的 ML 应用程序中使用它。

计算机视觉数据集入门:5 步入门

原文:https://towardsdatascience.com/getting-started-with-computer-vision-datasets-a-5-step-primer-5aaf6d63552b?source=collection_archive---------30-----------------------

人工智能时代 CV 数据集的原因/时间/内容/地点/内容

就像我们需要教科书/博客/视频等材料来学习新技能和测试我们的知识一样,机器学习算法需要数据集来做同样的事情。

明信片不就是我们学习如何识别一个地方的真实数据集吗?(图片由埃克托·里瓦斯Unsplash 上拍摄)

数据集的选择至关重要。这恰恰是杰出的机器学习模型或另一项实验之间的区别。

有很多关于基于文本的数据集的优秀文章。在过去几年讲授计算机视觉主题的过程中,我注意到学生们很难理解计算机视觉数据集的内容/时间/地点/方式。

下面是我通常给那些新手的入门指南:

  1. 为什么我们需要数据集?
  2. 我们什么时候需要数据集?
  3. 我们衡量什么?
  4. 哪些数据集可用?
  5. 我们在哪里可以找到数据集?

我们开始吧。

1-为什么我们需要数据集?

根据定义,数据集是用于定型和测试模型的相关示例的集合。这可以是属于特定主题或领域的示例的选择,数据集通常旨在迎合一个或多个应用。数据集可以被标记,因此非常适合训练和测试监督模型。然而,也存在用于训练无监督模型的未标记数据集。

培训和测试

从机器学习的角度来看,我们需要数据集来训练模型,并随后测试它们。这一过程要求我们选择数据集的一部分(例如 70%)并将其“展示”给机器学习算法以用于学习目的。然后,我们选择数据集中剩余的未看到的示例(例如,剩余的 30%),并使用它们来测试模型的学习效果。至关重要的是,我们不要使用已经用于训练的示例进行测试,因为模型将预测它已经知道的东西,这被称为“过度拟合”模型。这是我们不想要的,因为一旦在不同的数据集上使用它,它只会保证模型的失败。组织训练测试集的方法有很多种,您可以看看这些例子。

标杆管理

当涉及到机器学习技术的性能时,数据集也可以作为一种测量工具。需要对执行相同任务的模型进行公平的比较。这是通过对一系列数据集运行不同的方法来实现的。因此,每种方法的性能测量将是可比较的,并且允许结果的简单比较。

Ali Borji 实施并发布了一套关于显著性技术的杰出基准测试练习。这些是我推荐给我学生的一些他的论文:

  1. 显著目标检测:一项调查 (2019)
  2. 重访视频显著性:大规模基准和新模型 (2018)
  3. 显著物体检测:基准 (2015)

旁注:理解偏见

偏见本身就是一个巨大的话题。我们需要记住一些重要的事情。

就像任何其他信息来源一样,数据集本身带有一定程度的偏见。

这不一定会有负面影响,尤其是如果你想让你的模型在一个已经有偏见的世界里经受住相关性的考验。然而,非常重要的是,我们要意识到任何偏见,并衡量任何影响。

2-我们什么时候需要数据集?

本文的目的不是关注特定的计算机视觉技术。但是,我将快速向您介绍一些主题,并强调对数据集的需求。

目标检测和识别

目标检测处理识别和定位图像中特定类别的目标。可以用各种方式来解释对象定位。数据集标注中常用的方法包括在对象周围绘制边界框或多边形,如下所述。这种注释允许数据集用于检测。如果每个注释都附有标签,则可以使用相同的数据集进行识别。一旦选择了对象,它们也可以用于标记图像中包含该对象的每个像素(分割)。

对象分割

分割是将图像分割成对应于特定区域或对象的多个片段(像素组)的过程。这可以应用于使用阈值技术的对象,例如 Otsu 的方法。
分割也可以利用特征。现代方法利用深度学习方法,其中模型在包含数千个像素级注释标签的数据集上训练。这些方法包括语义分割(带标签的区域选择)和实例分割(每类识别多个独立对象的语义分割)。

视觉显著性

视觉显著性是计算机视觉中一个不太受欢迎的领域,它回答了以下问题:图像的哪一部分更吸引人的注意?显著性检测技术接收彩色图像作为输入,并返回 8 位显著性图,其中像素值越亮(最大 255)意味着像素非常显著。视觉显著性用于从数据压缩到产品放置和图像处理的不同应用中。数据集,如下面介绍的 MSRA10K,提供了一个二进制图像作为基本事实,表明哪些像素是显著的或不显著的。

3-我们衡量什么?

数据集中可用注释的类型和质量对其相关性至关重要。在这一节中,我将快速向您介绍注释的主要类型。这要归功于 @jiayin_Supahands 对这方面的简洁概述,我鼓励你阅读她的文章。这里,我只给出最常用的注释和它们与主题的关系的概述。

边界框

边界框方法是最简单的注释类型,自然包括围绕感兴趣的对象绘制边界框。它通常由一对坐标和相应的宽度和高度来定义。如果用于分类或识别,边界框定义通常需要附有标签。使用边界框的主要缺点是,它以与目标对象像素相同的方式标记边界框中捕捉到的任何背景像素。从错误度量的角度来看,它有助于追踪回忆,但是对于精确度来说它是弱的,因此产生了对更具体的东西的需求。

使用边框注释的简单例子(来源:佳音

多边形

边界框的限制带来了对更精确的东西的需求:多边形注释。多边形标注的思想类似于边界框,但是通过减少被误标注的背景像素的数量,允许标注中更好的像素精度。这种注释需要一种工具,如 LabelMe 。Label me 是一个开源的在线注释工具,用于为计算机视觉研究建立图像数据库。它还提供自己的数据集。

来自官方 LabelMe 网站的多边形注释示例

线条注释

顾名思义,这种方法使用线条来注释图像中的特定区域。在边界框会占用大量像素区域的情况下,线条会很有用。车道检测是使用这种注释的一种容易应用的情况。这也可用于监控队列和质量控制情况。

用于车道检测的线标注(来源:佳音)

点注释

这些注释是图像上关键点组的规范,通常带有语义内涵。这种方法非常常用于姿态估计和面部识别。不同点之间的几何属性被用作特征,并且使用这些特征来训练机器学习算法。这种方法被用于我们最近在 2019 年发表的题为“通过视频生成模型 检测异常人类行为”的工作中。

你想要一些实际的东西吗?查看这个优秀的姿态估计 TensorFlow 教程,这是这张图的来源。

4-哪些数据集可用?

嗯,很多:)

有几十个出色的计算机视觉数据集,它们对于正在改变世界的模型的开发至关重要。在本节中,我将重点介绍每个计算机视觉专业人员都应该了解的一些标志性数据集。

图像网络

官网:http://www.image-net.org/

Image-Net 是传说中的计算机视觉数据集,它促进了深度学习的兴起。这是一个根据 WordNet 层次结构组织的图像数据库,其中每个有意义的概念,可能由多个单词描述,被称为“同义词集”或“同义词集”。图像网络通常用于物体分类/识别。该数据集总共包含 14,197,122 个带有边界框注释的图像,共计 1,034,908 个。

这个数据集因 Image-net 竞赛而广受欢迎,在 AlexNet 于 2012 年赢得这场竞赛后,深度学习通过它获得了牵引力。它是由费-李非创建的,她在我下面的 Ted 演讲中分享了这个数据集背后的非凡历程:

不管你认为/感觉自己在计算机视觉方面多么有经验,我强烈建议你花点时间听听这个鼓舞人心的演讲。尽管自 2015 年发布以来,技术已经有所进步,但该视频中呈现的心态和谦逊仍然高度相关。

MNIST

Yann Le Cun 领导的原始 MNIST 数据集由大量手写图像组成。它为早期的卷积神经网络提供了一个非常需要的简单的基准。到 2017 年,CNN 在 MNIST 上实现了持续出色的准确性(超过 99%),对更具挑战性的基准数据集的需求出现了。这是时尚 MNSIT 数据集的一个动机。后一个版本包括 60,000 个样本的训练集和 10,000 个样本的测试集,其中每个样本都是来自 10 个不同类别的 28×28 像素的时尚项目。

这是来自官方 GitHub 库的时尚 MNIST 数据库的一个很酷的可视化。

CIFAR-10

官网:https://www.cs.toronto.edu/~kriz/cifar.html

该数据集由加拿大高级研究所(CIFAR)发布,并可能通过 Geoffrey Hinton 及其同事的参与而获得了一定的知名度。CIFAR-10 数据集包含 10 个不同类别的 60,000 幅 32x32px 彩色图像。它用于训练/测试对象识别模型。

从 CIFAR-10 数据集的 10 个类别中选择的图像(来源: CIFAR 网站

椰子树

官网:【http://cocodataset.org/】T4

上下文中的公共对象(COCO)数据集是一个对象检测、分割和字幕数据集。COCO 2017 具有 123,287 个图像的训练和验证集合,包含总共 886,284 个实例。这些实例分布在 80 个对象类别中。

这是 COCO 数据集中一幅图像的截屏。

Face2Text

官网:https://rival.research.um.edu.mt/

有大量的数据集涵盖了不同种类的面部数据。在这里,我选择了一个新的和创新的数据集,由我在马耳他大学的同事编辑。与其他面部检测或识别数据集不同,这个数据集使用描述性文本进行注释。这允许机器学习模型被训练来返回仅给定图像的人脸的文本描述。介绍该数据集的出版物的全部详细信息可在此处找到并且数据集本身可通过填写该项目官方网站上的联系表获得。

从官方出版物中提取的数据集样本

MSRA10K

官网:https://mmcheng.net/msra10k/

这是一个显著目标图像数据库。该数据集中的每个图像都有一个用于图像中最显著区域的遮罩。MSRA10K 数据集从其包含的大量图像中获得了相关性。它由 10,000 幅彩色图像和相应的显著物体的二进制图像掩模组成。

图像中最突出的是什么?在 MSRA10K 数据集中的每一幅彩色图像都伴随着一幅二进制图像,作为地面实况。

MSR 3D

官网:【https://www.microsoft.com/en-us/download/details.aspx? id=52358

微软研究数据集(MSR)包括一系列 100 幅图像(颜色和深度),这些图像是从 8 台摄像机捕捉的,显示了霹雳舞和芭蕾场景。该数据集包含每个场景的帧。每一帧都有一幅彩色图像和高质量的灰度深度图像,由红外相机拍摄。

这是 MSR3D 数据集中“霹雳舞”序列的样本帧,通过 8 个摄像机的线性设置拍摄。还有另一个序列,通过 8 个摄像机的圆形配置拍摄的“芭蕾”序列。

集装箱卸货与传输系统

官网:www . cots dataset . info

这是我去年精心设计和构建的数据集,用于评估图像处理技术。这样的应用之一是在物体从图像中移除的地方进行修补。修复技术通常使用主观或基于意见的方法进行评估,因为数据集将缺乏足够的地面真相。这是该数据集背后的一个动机,该数据集有一系列渐进的场景,如下所示。关于此数据集的更多细节及其构建背后的经验将在单独的工作中分享。

来自 COTS 数据集的样本显示了场景的渐进性质,其中在每个实例中都引入了新的对象。这意味着修补可以应用于第 n 个实例,并使实例 n-1 充当基础事实。

5-我们在哪里可以找到数据集?

在学术界,你通常会在同行评审的出版物中遇到关于你感兴趣的主题的数据集。然而,你有时只需要浏览你的选项,为此,你需要一个好的平台。以下是我最喜欢的 4 个来源:

谷歌数据集搜索

[## 数据集搜索

了解有关在数据集搜索中包含数据集的详细信息。‫العربية‬‪deutsch‬‪english‬‪español(españa)‬‪español…

datasetsearch.research.google.com](https://datasetsearch.research.google.com/)

  • 优点:非常广泛
  • 缺点:比较不同数据集时容易迷失。

VisualData

www.visualdata.io

  • 优点:专注于计算机视觉数据集,界面优秀,易于使用,快速到达直接存储库。
  • 缺点:在可用数据集的选择方面仍然有限。

卡格尔

www.kaggle.com

  • 优点:不同领域的各种数据集,活跃的社区,竞争。
  • 缺点:可能需要更长时间才能看到每个数据集提供了什么。

张量流

[## 张量流数据集

一个数据集集合,可以与 TensorFlow 或其他 Python ML 框架(如 Jax)一起使用,实现易用性…

www.tensorflow.org](https://www.tensorflow.org/datasets)

  • 优点:为每个数据集提供广泛的直截了当的页面选择。每一个数据集还伴随着优秀的使用资源。
  • 缺点:为了完整,我需要挤出一个缺点。这样的话,缺点就是(很明显)这个网站只提供 Tensorflow 资源。

这篇文章旨在提供一个覆盖所有基础知识的初级读本,让你习惯计算机视觉这个令人兴奋的领域。我希望现在你对数据集更有信心了,这个话题本身已经为你揭开了神秘的面纱。如果没有,我期待收到您的反馈,以便我可以解决您可能会发现的任何挑战。

我们已经了解了如何使用数据集,以及哪些数据集适合不同的情况。然而,这并不是故事的结尾。机器学习和数据集有着非常复杂和苛刻的关系。有时,机器学习模型无法满足需求,数据集可能会有局限性。这就是需要数据扩充的地方。在这篇博客中,我还解释了数据集对于不同技术的基准测试是多么重要。话说回来,说起来容易,做起来也容易,因为评估指标的选择是一个微妙的配方,需要进行调整。

总之,这篇文章离计算机视觉数据集的主题还很远。这是一个快速发展的领域,有许多主题有待探索。我只能承诺在这个过程中继续分享我的观点。

Dylan Seychell 是马尔他大学人工智能系的常驻学者,专攻计算机视觉。出版了几本国际同行评审的出版物和两本书。他的工作获得了许多国际奖项,如 CeBit 的电子卓越金章,2010 年欧洲航天局卫星导航竞赛的一等奖和 2017 年的亚军。2015 年,迪伦被选中领导马耳他的谷歌开发者小组,并担任马耳他政府国家人工智能特别工作组成员。迪伦在创业领域也非常活跃,他创立了屡获殊荣的创业公司,并指导其他创业公司,帮助他们超越商业的最初挑战。

可以通过 TwitterLinkedIn 或者 Instagram 联系。

Dask 和 SQL 入门

原文:https://towardsdatascience.com/getting-started-with-dask-and-sql-b8e2058dd563?source=collection_archive---------51-----------------------

免责声明:作者为 Coiled 工作,Coiled 是这篇文章中的一个供应商。

很多人谈论“民主化”数据科学和机器学习。从可广泛访问的意义上来说,还有什么比 SQL、PyData 和将数据科学扩展到更大的数据集和模型更民主呢?

Dask 正迅速成为可扩展计算的首选技术。尽管有强大而灵活的 dataframe API,Dask 在历史上并不支持 SQL 来查询大多数原始数据。

在本文中,我们来看看 dask-sql,这是一个令人兴奋的新开源库,它为 dask 提供了一个 sql 前端。跟着一起的还有这本笔记本。如果你想免费访问一些严肃的 Dask 集群,你也可以把它加载到 Coiled Cloud 上。为此,在此登录 Coiled Cloud,导航到我们的示例笔记本,并启动 dask-sql 笔记本。

在本帖中,我们:

  • 启动 Dask 集群并使用 dask-sql 在其上运行 sql 查询!
  • 进行一些基本的速度测试,
  • 使用 SQL 和缓存数据来加速我们的分析,
  • 调查 dask-sql 中的 SQL 内置助手函数,
  • 提供一个从大数据快速绘图的例子。

非常感谢 dask-sql 的创建者 Nils Braun,感谢他对这篇文章的深思熟虑和建设性的反馈。

(图片由作者提供)

启动 Dask 集群并为 SQL 做好准备

dask-sql 是免费的+开源的,可以在任何 dask 集群上运行,所以你可以在任何环境下运行它(只需要很少的修改)。在 AWS (Azure 和 GCP 即将推出)上运行集群的一个简单方法是使用盘绕云。简单的一个原因是你不需要和 Docker 和/或 Kubernetes 混在一起!这就是我们在这里要做的,并且可以随意编码。

如果你还没有注册 Coiled beta,你可以在这里用 Github 或 Google ID 免费注册。

然后,我们执行导入并启动我们的集群!

import coiled from dask.distributed
import Clientcluster = coiled.Cluster(n_workers=20)
client = Client(cluster) client

接下来,我们将安装 dask-sql。这是一个简单的安装,但可能需要一两分钟。

分析云中的数据

至此,我们已经准备好开始查询数据了!

在运行我们的第一个 SQL 查询之前,让我们在感兴趣的数据集上用一个“starter”查询来测试一下:这个查询计算纽约出租车数据集中 2019 年记录的乘客计数的平均小费金额。

然后我们用 SQL 再试一次。

import dask.dataframe as dddf = dd.read_csv(
       "s3://nyc-tlc/trip data/yellow_tripdata_2019-*.csv", 
       dtype={ "payment_type": "UInt8", 
               "VendorID": "UInt8", 
               "passenger_count": "UInt8", 
               "RatecodeID": "UInt8" },
       storage_options={"anon": True} ) df.groupby("passenger_count").tip_amount.mean().compute()

太好了!

我们的集群和代码正在运行。

现在让我们用 dask-sql 来尝试一些 SQL!

dask-sql 使用一些代码来“自动地”定位我们将需要的 JVM 共享库,但是它在这个部署在云上的 Jupyter 容器中没有找到正确的路径。

正如我们稍后看到的,dask-sql 使用一个 Java 库来处理一些查询分析,所以我们将给出一个关于 JVM 路径的提示。

import os os.environ["JAVA_HOME"] = "/opt/conda/lib/server"

dask-sql 使用一个完善的 Java 库 Apache 方解石来解析 sql 并对查询执行一些初始工作。这是一件好事,因为这意味着 dask-sql 没有重新发明另一个查询解析器和优化器,尽管它确实创建了对 JVM 的依赖。注意,启动和管理 JVM 的速度缺点只是在解析查询时出现的问题,而不是在执行查询时出现的问题。我们很快就会看到,这并没有显著增加开销。

from dask_sql import Context c = Context()

这个上下文实例将让我们运行查询…但首先我们需要一些数据源。

用 dask-sql 定义数据源有多种方法,但最简单的一种方法是提供 dask 数据帧作为数据源。Dask 数据帧:

  • 是懒惰的,所以直到需要时才检索数据,
  • 可以发现数据模式,
  • 支持核外访问—这是一种不需要将数据加载到内存中的奇特说法(例如,数据可能不适合内存,或者您可能希望内存用于其他计算),
  • 知道如何从底层来源检索数据(例如,“S3 的 CSV 文件”)。

为了在我们的 SQL 查询中使用数据,我们需要在 dask-sql 中为它分配一个标识符(名称)。

以下代码:

  1. 将表名 taxi 与 df 相关联
  2. 创建一个查询来计算该表中的行数
  3. 以 Dask 数据帧的形式返回惰性结果集的句柄
c.register_dask_table(df, "taxi")result = c.sql('SELECT count(1) FROM taxi') result

在几乎所有情况下,运行 c.sql(…)实际上不会运行完整的查询,而只是产生一个表示结果的 Dask dataframe 句柄。(在 dask-sql 文档中有一些边缘情况确实会触发即时计算,但长期目标是尽可能地减少懒惰。)

我们如何得到实际的行数?同样的方式,我们评估任何其他小 Dask 结果,我们想检索:通过。计算()

result.compute()

(图片由作者提供)

好了,我们已经运行了第一个 dask-sql 查询并获得了结果!

转速试验

现在让我们再来看一下“起始查询”——根据乘客数量计算平均小费金额的查询。

我们有两个目标:

  • 用 Dask/Python 和 SQL 编写相同的查询,可以看到它们工作并产生相同的结果,
  • 对执行进行计时,以验证 SQL 不会增加任何显著的性能开销

如果您正在尝试这样做,这也是查看 Dask 任务流仪表板的好时机,可以看到集群的运行情况。您可以通过 JupyterLab 扩展或通过 Coiled Cloud GUI 来实现这一点。

%%time df.groupby("passenger_count").tip_amount.mean().compute() %%time c.sql('SELECT avg(tip_amount) FROM taxi GROUP BY passenger_count').compute()

您应该看到相同的输出(我们看到两者都是大约 25 秒)。此外,您应该会看到几乎相同的挂钟时间。SQL 处理增加了 100 毫秒或更少的时间,并且是一次性的固定成本。

SQL +缓存数据=涡轮增压分析

让我们看看如何通过在集群中缓存该数据集,然后对缓存的数据运行 SQL 查询来加速分析。

这不仅速度快,而且有利于整个团队,因为:

  • 我们可以向其他 Dask 分析师公开这个数据集,鼓励他们共享一个“大型 RAM 池”集群来分析数据,
  • dask-sql 公开了 Presto wire 协议,因此使用 Presto 兼容客户端或可视化工具的人可以零编程访问这些数据!

首先,我们将要求 Dask 缓存该表。

dfp = df.persist()

可能需要几秒钟(对于非常大的数据集,可能需要更长时间)才能加载到集群 RAM 中。

我们可以在 Dask Graph 仪表板中实时查看块加载情况。这显示任务在计算时变成绿色,然后在结果载入内存时变成红色。在这种情况下,每个任务从 S3 检索数据的一个分区。

(图片由作者提供)

在其他情况下,我们可能不想查看 GUI,而是以编程方式等待数据加载。

我们可以使用 distributed.wait(…)来实现:

import dask.distributedcached_tasks = dask.distributed.wait(dfp)print(f'cached {len(cached_tasks[0])} results')

接下来,我们将为数据集的这种新的缓存风格赋予一个新的表名(上面我们将 df.persist 的结果分配给它的 dfp)。

dfp 有点不透明,所以我们将这个表命名为 taxi_cached。

c.register_dask_table(dfp, "taxi_cached")

作为一个快速测试,看看它在内存不足的情况下运行的速度有多快,让我们再次计算行数。

result = c.sql('SELECT count(1) FROM taxi_cached')result.compute()

让我们也尝试一下按乘客计数查询平均小费,这次是从缓存中查询。

%%time c.sql('SELECT avg(tip_amount) FROM taxi_cached GROUP BY passenger_count').compute()

不足为奇的是,由于从缓存的数据中工作消除了作业中的大部分 I/O、解析和服务,它的运行速度比以前快得多。

SQL 内置函数

dask-sql 还在 sql 中公开了许多助手函数——就像传统的关系数据库公开数学、日期/时间处理、字符串操作等助手函数一样。

下面是对静态文字值运行的 floor 函数:

c.sql('SELECT floor(3.14)').compute()

使用 floor 来离散化(或划分)行程距离,我们可以查看距离桶的粗粒度平均费用。

我们的下一个查询查看距离在 0 到 50 之间的乘车,拆分(分组)分段(floor())距离,然后对于每个分段,返回分段距离、平均费用和乘车次数。

因为我们知道——基于我们的查询——报告输出将只包含 50 行和 3 列,我们可以安全地计算,并在本地获得一个作为常规 Pandas 数据帧的结果。如果我们的结果非常大——或者是我们希望在后续操作中使用的中间转换——我们要么将它写入持久存储,要么将结果保存在集群中。毕竟,大型数据集不适合我们的本地流程,Dask 客户端dask-sql 上下文对象就在本地流程中(注意,dask-sql 查询的输出可以再次输入 Dask-sql——这使得在 SQL 中获得类似的“视图”成为可能)。

%%timec.sql("""SELECT floor(trip_distance) 
AS dist, avg(fare_amount) as fare, count(1) as t 
FROM taxi_cached 
WHERE trip_distance < 50 AND trip_distance >= 0 
GROUP BY floor(trip_distance)
""").compute()

由于 Dask 已经实现了如此多的计算构建块,dask-sql 能够涵盖大多数 sql 组件——包括子查询、连接和聚合。

贡献的机会

如果您查看 dask-sql 文档,您会注意到还没有实现多少帮助函数。例如,大多数数据库都有几个日期和时间处理助手函数,而现在 dask-sql 并没有实现所有这些函数。

大多数数据库都有几个字符串处理辅助函数,而今天 dask-sql 只有一个。

这是一个添加有价值的功能并对库做出贡献的好机会,因为实现这些功能只需要找到现有的 Dask 函数并将其连接起来。

我们可能想添加很多功能,但每个功能都很小,所以这是一个很好的众包机会。点击这里可以看到现有的实现

再举一个例子:从大数据中快速绘图

因为我们的结果反馈很快,而且作为熊猫的数据框架,我们可以很容易地进行可视化。这种模式可以帮助我们接近实时的交互式数据探索和可视化。

如果您没有安装 matplotlib,可以使用以下命令安装它:

! conda install -y matplotlib -c conda-forge

现在,我们可以运行一个查询,并立即使用 Pandas 绘图语法绘制结果的可视化图形!

c.sql("""SELECT floor(trip_distance) 
AS dist, avg(fare_amount) as fare 
FROM taxi_cached 
WHERE trip_distance < 50 AND trip_distance >= 0 
GROUP BY floor(trip_distance) 
""").compute().plot(x='dist', y='fare')

(图片由作者提供)

引擎盖下的一瞥

技术如何契合?

dask-sql 依赖于完善的 Apache 方解石(https://calcite.apache.org/),一个 Java 项目

  • 解析 SQL
  • 将查询表示为操作符树
  • 规范化和优化查询
  • 方解石的优化器是可扩展的,因此有许多“插件”可以在将来添加更多的功能

太多了!还剩下什么?

方解石的输出是一个逻辑操作符树的查询表示。这些是像投影(把它们想象成选择的抽象)和过滤器(哪里的抽象)这样的东西。

dask-sql 的下一项工作是提供插件,将纯粹抽象的操作符转换成用 Dask APIs 表达操作的逻辑。结果仍然是逻辑操作符,但是更具体一些——类似于您自己编写 Dask dataframe 查询所得到的结果,因此它可以在您的 Dask 集群上执行。在执行时,Dask 提供操作的物理实现,例如,根据数据的存储方式而变化。

创造更多机会

协同增效如今已经是老生常谈了。但是向 Dask 添加一个 SQL 前端使大量新用户和新用例能够共享最先进的 Python 数据解决方案。

例如,精通 SQL 但不写命令性代码的分析师和商务人士现在可以利用 Dask、PyData、Coiled 等等……同时与喜欢编码的人合作。

dask-sql 中的自定义函数支持意味着编码人员可以围绕复杂的流程创建简单的包装器(例如,应用机器学习模型对记录进行评分),sql 用户可以使用这些函数创建报告。

最后,通过 Presto 的数据库服务器功能(也许很快就是 JDBC,因为方解石包括 JDBC 支持),可以采用像 Tableau 这样的可视化解决方案,并将其指向 Dask 集群进行大规模可视化分析。

链接:

最后,如果您喜欢这种方法,“感觉需要速度”,并且有可用的 GPU,一定要看看 BlazingSQL ,它在 GPU 计算的基础上提供了类似的 SQL+Dask 架构,以获得令人惊叹的查询速度。

原载于 2020 年 10 月 30 日https://coiled . io

AWS 数据分析入门

原文:https://towardsdatascience.com/getting-started-with-data-analysis-on-aws-7b74ecbfe572?source=collection_archive---------14-----------------------

了解如何使用 AWS Glue、Amazon Athena 和 Amazon QuickSight 来转换、丰富、分析和可视化半结构化数据。

帖子的音频介绍

介绍

根据维基百科的说法,数据分析是"一个检查、清理、转换和建模数据的过程,目的是发现有用的信息,告知结论,并支持决策。“在这篇文章中,我们将探索如何开始在 AWS 上进行数据分析,使用亚马逊 Athena、AWS Glue、亚马逊 QuickSight、亚马逊 S3 和 AWS Lambda 的无服务器功能。我们将学习如何使用这些补充服务来转换、丰富、分析和可视化半结构化数据。

数据分析——发现有用的信息,提供结论,支持决策。–维基百科

我们将学习如何使用亚马逊 S3、AWS Glue、亚马逊 Athena 和 AWS Lambda 以多种格式接收、转换和丰富原始的半结构化数据。我们将构建一个基于 S3 的数据湖,并了解 AWS 如何利用开源技术,如 Presto、Apache Hive 和 Apache Parquet。

亚马逊最近增加了全套aws quicksightAPI,用于与 QuickSight 交互。然而,对于演示的最后一部分,我们将从亚马逊 QuickSight 控制台进行操作,而不是 AWS CLI、AWS CDK 或 CloudFormation 模板。

示范

在本次演示中,我们将扮演一家美国大型电力供应商的角色。这家能源提供商开发了其下一代智能电力监控中心(Smart Hub)。他们已经向美国的大量居民客户出售了智能集线器。这个假想的智能集线器通过无线方式从分散在住宅各处的单个智能电源插座和电路仪表中收集详细的用电数据。电力使用数据经过加密,并安全地从客户的智能枢纽传输到电力供应商,后者在 AWS 上开展业务。

客户能够以精细的粒度、每台设备和一段时间来分析他们的用电情况。智能集线器的目标是使客户能够利用数据降低电力成本。由于客户将使用转移到非高峰时间以节省资金,该提供商受益于现有电网上负载的减少和每日电力负载的更好分配。

亚马逊 QuickSight 中 post 的数据预览。

这篇文章将关注数据分析,而不是数据捕获的实时流方面或数据如何在 AWS 上持久化。

演示的高级 AWS 架构图。

特色技术

以下 AWS 服务和开源技术是这篇文章的重点。

基于亚马逊 S3 的数据湖

一个基于亚马逊 S3 的数据湖使用亚马逊 S3 作为其主要存储平台。亚马逊 S3 为数据湖提供了一个最佳的基础,因为它具有几乎无限的可扩展性,从千兆字节到千兆字节的内容。亚马逊 S3 提供“11 个 9”(99.999999999%)的耐用性。它具有可扩展的性能、易于使用的特性以及本机加密和访问控制功能。

AWS 胶水

AWS Glue 是一个完全托管的提取、转换和加载(ETL)服务,用于准备和加载数据进行分析。AWS Glue 发现您的数据,并将关联的元数据(例如,表定义和模式)存储在 AWS Glue 数据目录中。一旦编目,您的数据就可以立即被搜索、查询和用于 ETL。

AWS 粘合数据目录

AWS 粘合数据目录是一个 Apache Hive Metastore 兼容的中央存储库,用于存储数据资产的结构和操作元数据。对于给定的数据集,存储表定义、物理位置、添加与业务相关的属性,以及跟踪数据随时间的变化。

AWS 胶水爬行器

一个 AWS Glue Crawler 连接到一个数据存储,通过一个优先的分类器列表提取数据和其他统计数据的模式,然后用这些元数据填充 Glue 数据目录。爬网程序可以定期运行,以检测新数据的可用性以及对现有数据的更改,包括表定义的更改。爬网程序会自动添加新表、现有表的新分区以及新版本的表定义。你甚至可以定制胶水爬虫来分类你自己的文件类型。

AWS 粘合 ETL 作业

AWS Glue ETL 作业是在 AWS Glue 中执行提取、转换和加载(ETL)工作的业务逻辑。当您启动一个作业时,AWS Glue 运行一个脚本,该脚本从源中提取数据,转换数据,并将其加载到目标中。AWS Glue 生成 PySpark 或 Scala 脚本,运行在 Apache Spark 上。

亚马逊雅典娜

Amazon Athena 是一种交互式查询服务,使用标准 SQL 可以轻松分析亚马逊 S3 的数据。Athena 支持并使用各种标准数据格式,包括 CSV、JSON、Apache ORC、Apache Avro 和 Apache Parquet。Athena 集成了现成的 AWS 粘合数据目录。Athena 是无服务器的,所以不需要管理基础设施,您只需为运行的查询付费。

亚马逊 Athena 背后的底层技术是 Presto ,这是由脸书创建的用于大数据的开源分布式 SQL 查询引擎。根据 AWS,Athena 查询引擎基于Presto 0.172(2017 年 4 月 9 日发布)。除了 Presto 之外,Athena 还使用 Apache Hive DDL 来定义表。

亚马逊 QuickSight

Amazon QuickSight 是一项完全托管的商业智能(BI)服务。QuickSight 允许您创建和发布包含 ML Insights 的交互式仪表盘。仪表板可以从任何设备访问,并嵌入到您的应用程序、门户和网站中。QuickSight 无需服务器即可自动从数十名用户扩展到数万名用户,无需任何基础架构管理。

自动气象站λ

AWS Lambda 自动运行代码,无需配置或管理服务器。AWS Lambda 通过运行代码来响应触发器,从而自动扩展应用程序。Lambda 代码并行运行。有了 AWS Lambda,您的代码每执行 100 毫秒就要付费,代码被触发的次数也是如此。您只需为消耗的计算时间付费。

智能枢纽数据

这篇文章中的一切都围绕着数据。为了这篇文章的演示,我们将从四类原始的合成数据开始。这些数据类别包括智能集线器用电数据、智能集线器传感器映射数据、智能集线器住宅位置数据和电费数据。为了展示 AWS Glue 处理多种数据格式的能力,四类原始数据由三种不同的文件格式组成:XML、JSON 和 CSV。我试图将尽可能多的“真实世界”的复杂性融入到数据中,同时又不忽略这篇文章的主题。样本数据集故意很小,以使您的 AWS 成本在演示中保持最低。

为了进一步降低成本,我们将使用多种数据分区方案。根据 AWS 的说法,通过对你的数据进行分区,可以限制每次查询扫描的数据量,从而提高性能,降低成本。我们只有很少的数据用于演示,在这种情况下,分区可能会对查询性能产生负面影响。然而,在“真实世界”的场景中,将会有数百万潜在的住宅用户产生万亿字节的数据。在这种情况下,数据分区对于成本和性能都是至关重要的。

智能集线器用电数据

Smart Hub 的时序用电数据是从客户的 Smart Hub 中收集的。在演示的示例用电数据中,每一行代表完全任意的五分钟时间间隔。总共有十个电传感器,其用电量以千瓦小时(kW)为单位进行记录和传输。每个智能集线器记录并传输 10 个设备传感器的用电量,每天 288 次(24 小时/ 5 分钟间隔),每个智能集线器每天总共 2,880 个数据点。该演示有两天的使用数据,总共有 5,760 个数据点。数据以 JSON 行格式存储。使用数据将按照日期(例如,“dt = 2019–12–21”)在基于亚马逊 S3 的数据湖中进行分区。

请注意,用电数据包含嵌套数据。十个传感器中的每一个传感器的用电量都包含在 JSON 数组中的每个时间序列条目中。该数组包含十个 double 类型的数值。

真实数据通常很复杂,而且嵌套很深。在这篇文章的后面,我们将看到 AWS Glue 可以映射许多常见的数据类型,包括嵌套的数据对象,如下图所示。

智能集线器传感器映射

智能集线器传感器映射数据将使用数据中的传感器列(例如“s_01”)映射到相应的实际设备(例如“中央空调”)。该数据包含设备位置、瓦特数和上次修改记录的时间。数据也以 JSON 行格式存储。传感器映射数据将在基于亚马逊 S3 的数据湖中按照居住的州进行划分(例如,俄勒冈州的“state=or”)。

智能枢纽位置

智能中心位置数据包含每个住宅智能中心的地理空间坐标、家庭地址和时区。数据以 CSV 格式存储。本次演示中包含的四个城市的数据来自 OpenAddresses免费开放的全球地址收集。‘大概有 4k 的位置记录。位置数据将在基于亚马逊 S3 的数据湖中按照安装智能中心的居住州进行划分(例如,俄勒冈州的“state=or”)。

电费

最后,电价数据包含电费。在本演示中,假设汇率因州、月份和一天中的小时而异。数据存储在 XML 中,这种数据导出格式在旧的遗留系统中仍然很常见。电价数据不会在基于亚马逊 S3 的数据湖中被分割。

数据分析过程

由于演示中的数据分析过程涉及的步骤很多,我将该过程分为四个逻辑阶段:1)原始数据接收,2)数据转换,3)数据丰富,以及 4)数据可视化和商业智能(BI)。

全数据分析工作流程图(点击放大…)

原始数据摄取

在原始数据接收阶段,半结构化 CSV、XML 和 JSON 格式的数据文件被复制到一个安全的亚马逊简单存储服务 (S3)桶中。在存储桶中,数据文件根据其物理数据结构(模式)组织到文件夹中。由于数据文件的数量可能没有限制,文件被进一步组织(分区)到子文件夹中。数据文件的组织策略基于日期、时间、地理位置、客户 id 或其他常见的数据特征。

这种半结构化数据文件、S3 桶和分区的集合形成了所谓的数据湖。根据 AWS 的说法,数据湖是一个集中式存储库,允许您存储任何规模的所有结构化和非结构化数据。

一系列的 AWS 胶合爬虫处理原始的 CSV-、XML-和 JSON-格式文件,提取元数据并在 AWS 胶合数据目录中创建表定义。根据 AWS,AWS Glue 数据目录包含元数据表,其中每个表指定一个数据存储。

数据转换

在数据转换阶段,转换前一阶段的原始数据。数据转换可以包括修改数据和改变数据格式。数据修改包括数据清理、重新转换数据类型、更改日期格式、字段级计算和字段连接。

然后,数据从 CSV、XML 和 JSON 格式转换成 Apache Parquet 格式,并写回到基于亚马逊 S3 的数据湖。Apache Parquet 是一种压缩的、高效的列存储格式。和许多基于云的服务一样,Amazon Athena 按每次查询扫描的数据量收费。因此,使用数据分区、分桶、压缩和列存储格式(如 Parquet)将降低查询成本。

最后,将转换后的 Parquet 格式数据编目到新的表中,与原始的 CSV、XML 和 JSON 数据放在一起,放在 Glue 数据目录中。

数据丰富

根据 ScienceDirect 的说法,数据丰富或扩充是通过补充缺失或不完整的数据来增强现有信息的过程。通常,数据丰富是通过使用外部数据源实现的,但情况并非总是如此。

数据丰富——通过补充缺失或不完整的数据来增强现有信息的过程。–科学指导

在数据丰富阶段,Parquet 格式的 Smart Hub 使用数据会增加来自其他三个数据源的相关数据:传感器映射、位置和电费。基于客户的地理位置和一天中的时间,客户的 Smart Hub 使用数据丰富了客户的设备类型、客户的时区以及每个监控期的客户电力成本。

一旦数据得到丰富,它就被转换成 Parquet 并针对查询性能进行优化,存储在数据湖中,并被编目。此时,原始的 CSV、XML 和 JSON 格式的原始数据文件、转换后的 Parquet 格式的数据文件和 Parquet 格式的丰富数据文件都存储在基于亚马逊 S3 的数据湖中,并在 Glue 数据目录中编目。

数据可视化和商业智能

在最后的数据可视化和商业智能(BI)阶段,呈现和分析丰富的数据。有许多企业级服务可用于可视化和商业智能,它们与 Athena 集成。亚马逊服务包括亚马逊 QuickSight亚马逊 EMR亚马逊 SageMaker 。来自 AWS 合作伙伴的第三方解决方案可在 AWS Marketplace 上获得,包括 TableauLookerSisenseDomo 。在本次演示中,我们将重点介绍 Amazon QuickSight。

入门指南

要求

为了进行演示,您需要一个 AWS 帐户和当前版本的 AWS CLI 。为了从演示中获得最大收益,您还应该在您的工作环境中安装 Python 3jq

源代码

这篇文章的所有源代码可以在 GitHub 找到。使用以下命令克隆项目的副本。

本文中的源代码示例显示为 GitHub Gists ,在一些移动和社交媒体浏览器上无法正确显示。

TL;博士?

不看说明书就想跳进去?这篇文章中的所有 AWS CLI 命令都整合在 GitHub 项目的 README 文件中。

云形成堆栈

首先,使用smart-hub-Athena-glue . yml模板创建“smart-hub-Athena-glue-stack”cloud formation 堆栈。该模板将创建(3)亚马逊 S3 桶,(1) AWS 胶水数据目录数据库,(5)数据目录数据库表,(6) AWS 胶水爬虫,(1) AWS 胶水 ETL 作业,以及(1)AWS 胶水 IAM 服务角色。

首先,确保将DATA_BUCKETSCRIPT_BUCKETLOG_BUCKET变量更改为您自己唯一的 S3 存储桶名称。我总是建议使用标准的 AWS 三部分约定来命名您的存储桶(例如,“smart-hub-data-123456789012-us-east-1”)。

原始数据文件

接下来,将原始的 CSV、XML 和 JSON 格式的数据文件从本地项目复制到DATA_BUCKET S3 存储桶中( 中的步骤 1a-1b)工作流程图** )。这些文件代表了 S3 数据湖的开端。每一类数据都使用不同的策略来组织和分离文件。注意使用了 Apache Hive 风格的分区(例如/smart_hub_data_json/**dt=2019-12-21**)。如前所述,假设数据湖中实际的大量数据需要使用分区来提高查询性能。

用以下命令确认DATA_BUCKET S3 桶的内容。

DATA_BUCKET S3 桶中应该总共有(14)个原始数据文件。

λ函数

接下来,打包(5)基于 Python3.8 的 AWS Lambda 函数进行部署。

将五个 Lambda 包复制到SCRIPT_BUCKET S3 桶中。第二个 CloudFormation 堆栈 smart-hub-serverless 访问 ZIP 存档 Lambda 包。如果在SCRIPT_BUCKET S3 桶中没有找到包,这个创建 Lambda 函数的 CloudFormation 栈将无法部署。

我选择将包放在不同的 S3 桶中,然后是原始数据文件。在真实的生产环境中,出于安全考虑,这两种类型的文件至少会被分隔到不同的存储桶中。请记住,只有数据应该进入数据湖。

使用smart-hub-lambda . ymlcloud formation 模板创建第二个“smart-hub-lambda-stack”cloud formation 堆栈。该模板将创建(5) AWS Lambda 函数和(1) Lambda 执行 IAM 服务角色

此时,我们已经使用 CloudFormation 部署了演示所需的所有 AWS 资源。我们还复制了亚马逊 S3 数据湖中所有原始的 CSV、XML 和 JSON 格式的数据文件。

AWS 胶水爬行器

如果您还记得,我们在 Glue Data Catalog 数据库中创建了五个表,作为 CloudFormation 堆栈的一部分。四种原始数据类型各有一个表,一个表用于保存稍后演示中的临时 ELT 数据。要确认这五个表是在粘合数据目录数据库中创建的,请使用粘合数据目录控制台,或者运行以下 AWS CLI / jq 命令。

五个数据目录表应该如下所示。

我们还创建了六个 Glue 爬虫作为 CloudFormation 模板的一部分。其中四个爬虫负责将来自 S3 的原始 CSV、XML 和 JSON 格式的数据编目到相应的现有 Glue Data Catalog 数据库表中。爬行器将检测任何新的分区,并将它们添加到表中。每个爬虫对应于四种原始数据类型中的一种。爬虫可以被调度定期运行,编目新数据并更新数据分区。爬虫还会创建一个数据目录数据库表。我们使用爬虫来创建新的表格,稍后在文章中。

使用 AWS CLI 运行四个胶水爬行器( 工作流程图 中的步骤 1c)。

您可以检查 Glue Crawler 控制台,以确保四个 Crawler 成功完成。

或者,使用另一个 AWS CLI / jq 命令。

完成后,所有爬网程序都应处于“仍在估计=假”和“TimeLeftSeconds = 0”的状态。根据我的经验,爬虫程序在估计阶段后需要一分钟来启动,完成后需要一分钟来停止。

成功运行四个爬行器完成了演示的原始数据接收阶段。

用 CTAS 改造成拼花地板

原始数据接收阶段完成后,我们现在将使用三个 AWS Lambda 函数将原始 Smart Hub 使用数据、传感器映射数据和位置数据转换为 Parquet 格式。每个 Lambda 随后调用 Athena,后者执行一个CREATE TABLE AS SELECT SQL 语句(又名 CTAS )。每个 Lambda 都执行类似的命令,不同之处仅在于数据源、数据目的地和分区方案。下面是用于智能集线器用电数据的命令示例,取自基于 Python 的 Lambda,Athena-JSON-to-parquet-data/index . py

这个简洁而强大的 CTAS 语句将原始 JSON 和 CSV 格式数据文件的副本转换为 Parquet 格式,并将结果文件分区并存储回基于 S3 的数据湖。此外,CTAS SQL 语句将拼花地板格式的数据文件编入胶合数据目录数据库的新表中。不幸的是,这种方法不适用于 XML 格式的原始数据文件,这是我们接下来要解决的问题。

从 Lambda 控制台的 functions 选项卡上应该可以看到五个已部署的 Lambda 函数。

使用 AWS CLI 调用三个 Lambda 函数。(工作流程图 中步骤 2a 的一部分)。

这是同一个 CTAS 命令的一个例子,上面显示了 Smart Hub 电力使用数据,因为它是由 Athena 成功执行的。

我们可以从 Athena 控制台的 History 选项卡中查看任何 Athena SQL 查询。单击一个查询(粉色)会将其复制到查询编辑器选项卡并执行它。下面,我们看到 Lamba 函数执行的三个 SQL 语句。

AWS 为 XML 粘合 ETL 作业

如果您还记得,电价数据是 XML 格式的。我们刚刚执行的 Lambda 函数使用 Athena 将 CSV 和 JSON 数据转换为 Parquet。目前,与 CSV、JSON、ORC、Parquet 和 Avro 不同, Athena 不支持更老的 XML 数据格式。对于 XML 数据文件,我们将使用 AWS Glue ETL 作业将 XML 数据转换成 Parquet。Glue ETL 作业是用 Python 编写的,使用了 Apache Spark ,以及几个 AWS Glue PySpark 扩展。对于这项工作,我使用在 Glue ETL 作业控制台中创建的现有脚本作为基础,然后修改脚本以满足我的需要。

脚本期望的三个 Python 命令行参数(上面的第 10-12 行)在 CloudFormation 模板smart-hub-Athena-glue . yml中定义。下面,我们在 CloudFormation 代码片段的第 10–12 行看到了它们。它们是在作业运行时自动注入的,并且可以在启动作业时从命令行覆盖。

首先,将 Glue ETL Job Python 脚本复制到SCRIPT_BUCKET S3 桶中。

接下来,启动 Glue ETL 作业( 工作流程图 中步骤 2a 的部分)。虽然转换是一组相对简单的任务,但是创建 Apache Spark 环境来执行这些任务需要几分钟的时间。尽管 Glue Crawlers 平均需要大约 2 分钟,但是根据我的经验,Glue ETL 工作可能需要 10-15 分钟。实际执行时间只需要 10-15 分钟中的 1-2 分钟。在我看来,等待 15 分钟对于针对较小数据集的临时作业来说太长了;Glue ETL 作业肯定是针对大数据的。**

要检查作业的状态,请使用 Glue ETL 作业控制台,或者使用 AWS CLI。

完成后,您应该会看到类似下面的结果。请注意,“JobRunState”为“SUCCEEDED”这个特定的作业总共运行了 14.92 分钟,而实际执行时间是 2.25 分钟。

作业的进度和结果也可以在 AWS Glue 控制台的 ETL 作业选项卡中看到。

CloudWatch 管理控制台中也提供了详细的 Apache Spark 日志,可以从 AWS Glue 控制台的 ETL Jobs 选项卡中的 logs 链接直接访问。

数据转换阶段的最后一步是使用另一个 Glue Crawler(在 工作流图 中的步骤 2b 的一部分)将之前的 Glue ETL 作业创建的拼花格式的电费数据转换成目录。启动下面的 Glue Crawler 来编目 Parquet 格式的电费数据。**

数据转换阶段到此结束。原始数据和转换后的数据在数据湖中,下面的九个表应该在 Glue 数据目录中。

如果我们检查这些表,我们应该观察到我们用来组织基于亚马逊 S3 的数据湖中的数据文件的数据分区包含在表元数据中。下面,我们看到了基于状态的拼花格式位置数据的四个分区。

数据丰富

为了开始数据丰富阶段,我们将调用 AWS Lambda,Athena-complex-ETL-query/index . py。这个 Lambda 接受输入参数(下面的第 28–30 行),在 Lambda 处理程序的事件参数中传递。参数包括 Smart Hub ID、请求数据的开始日期和请求数据的结束日期。演示的场景是,一个具有位置 id 值的客户使用电力供应商的应用程序请求特定日期范围(开始日期和结束日期)的数据,以进行可视化和分析。

Lambda 执行一系列 Athena INSERT INTO SQL 语句,每个语句对应一个可能的 Smart Hub 连接的电气传感器s_01s_10,Smart Hub 电气使用数据中有这些传感器的值。亚马逊刚刚在 2019 年 9 月发布了亚马逊 Athena INSERT INTO一个使用选择查询功能结果的表,这是对 Athena 的一个重要补充。Athena 的新功能在发行说明中列出。

这里,选择查询实际上是一系列链式子查询,使用 Presto SQL 的 WITH 子句功能。这些查询将基于 S3 的数据湖中的拼花格式智能集线器用电数据源与其他三个基于 S3 的拼花格式数据源(传感器映射、位置和电费)连接起来。拼花格式的数据作为单独的文件写入 S3,并插入到现有的“etl_tmp_output_parquet”胶合数据目录数据库表中。与传统的基于关系数据库的查询相比,Glue 和 Athena 能够跨存储在 S3 的多个半结构化数据文件进行复杂的 SQL 查询,这真是令人惊叹!

Glue 和 Athena 能够对存储在 S3 的多个半结构化数据文件进行复杂的 SQL 查询,这真是令人惊叹!

下面,我们看到从第 43 行开始的 SQL 语句。

下面是 Athena 对s_10传感器执行的最终查询之一的示例。所有输入参数值、Python 变量和环境变量都已被解析到查询中。

在丰富数据的同时,该查询使用其他数据源执行额外的数据转换。例如,根据客户的位置,Unix 时间戳被转换为包含日期和时间的本地化时间戳(上面的第 7 行)。转换日期和时间是一项频繁且痛苦的数据分析任务。数据丰富的另一个例子是用新的计算列增加数据。该列的值是使用另外两列的值计算的(上面的第 33 行)。

使用有效负载中的以下三个参数调用 Lambda(工作流图 中的步骤 3a)。**

十个INSERT INTO SQL 语句的结果状态(每个设备传感器一个)可从 Athena 控制台的 History 选项卡中看到。

每次 Athena 查询执行都将查询结果作为单独的、未压缩的 Parquet 格式数据文件保存到基于 S3 的数据湖中。数据在基于亚马逊 S3 的数据湖中按照智能电表位置 ID(例如‘loc _ ID = b6a8d 42425 FDE 548’)进行分区。

以下是客户洗衣机(传感器 s _ 04’)的丰富数据片段。请注意,时间戳现在是客户当地时区的实际日期和时间(例如,“2019–12–21 20:10:00.000”)。传感器 ID ('s_04 ')被替换为实际的设备名称('洗衣机')。增加了设备的位置(“地下室”)和用电时段的类型(如“高峰”或“部分高峰”)。最后,计算成本列。

为了将丰富的 CSV 格式数据转换为 Parquet 格式,我们需要使用另一个爬虫对 CSV 格式的结果进行编目,首先( 中的步骤 3d,工作流图** )。

优化丰富的数据

上一步创建了丰富的拼花格式数据。然而,这些数据在查询效率方面并没有得到应有的优化。使用 Athena INSERT INTO WITH SQL 语句,允许对数据进行分区。然而,该方法不允许拼花数据被容易地组合成更大的文件并被压缩。为了执行这两个优化,我们将使用最后一个 Lambda,Athena-parquet-to-parquet-ELT-data/index . py。Lambda 将在基于亚马逊 S3 的数据湖中创建一个新位置,在一个文件中包含所有丰富的数据,并使用 Snappy 压缩进行压缩。

生成的拼花文件可以在 S3 管理控制台中看到。

数据丰富阶段的最后一步是对优化的 Parquet 格式的丰富 ETL 数据进行编目。为了对数据进行分类,运行下面的 Glue Crawler(在 工作流程图 中的步骤 3i)

最终数据湖和数据目录

在基于 S3 的数据湖中,我们现在应该有以下十个分区数据的顶级文件夹。可以忽略“tmp”文件夹。

类似地,我们现在应该在 Glue 数据目录中有以下十个对应的表。使用 AWS Glue 控制台确认这些表是否存在。

或者,使用以下 AWS CLI / jq 命令列出表名。

“未知”错误

您可能已经注意到,使用 CTAS SQL 语句,用 AWS Lambda 函数创建的四个表错误地将“分类”设为“未知”,而不是“拼花”。我不知道为什么,我相信这是一个与 CTAS 功能可能的错误。这似乎对桌子的功能没有负面影响。但是,要解决此问题,请运行以下命令集。这个aws glue update-table攻击将把桌子的“分类”切换到“拼花”。

从 AWS Glue 控制台可以看到修复的结果。所有十个表现在都被正确分类。

探索数据

在开始使用 Amazon QuickSight 可视化和分析数据之前,尝试使用 Athena 查询编辑器对 Glue Data Catalog 数据库中的表执行一些 Athena 查询。在编辑器中工作是理解数据、学习 Athena 以及调试 SQL 语句和查询的最佳方式。Athena 查询编辑器具有方便的开发人员特性,如 SQL 自动完成和查询格式化功能。

在编写查询和在互联网上搜索 SQL 参考时要注意,Athena 查询引擎是基于 Presto 0.172 的。Presto 的当前版本, 0.229 ,比当前雅典娜版本领先 50 多个版本。Athena 和 Presto 的功能都发生了变化和分化。对于 Athena 中的 SQL 查询,还有一些额外的注意事项和限制

下面是一些在 Athena 查询编辑器中运行的简单的特别查询。

使用 QuickSight 实现数据可视化和商业智能

对于演示的最后一部分,我们将使用 Amazon QuickSight 控制台,而不是 AWS CLI、CloudFormation 模板和 Python 脚本。

注册 QuickSight

要使用 Amazon QuickSight,您必须注册 QuickSight。

亚马逊 QuickSight 有两个版本,标准版和企业版。对于这个演示,标准版就足够了。

QuickSight 数据集

Amazon QuickSight 使用数据集作为所有数据可视化的基础。据亚马逊称,QuickSight 数据集可以从各种各样的数据源中创建,包括亚马逊 RDS、亚马逊 Aurora、亚马逊 Redshift、亚马逊 Athena 和亚马逊 S3。您还可以上传 Excel 电子表格或平面文件(CSV、TSV、CLF、ELF 和 JSON),连接到 SQL Server、MySQL 和 PostgreSQL 等内部数据库,并从 Salesforce 等 SaaS 应用程序导入数据。下面,我们看到了 QuickSight 新数据集控制台中可用的最新数据源列表。

演示数据集

为了演示,我创建了三个 QuickSight 数据集,它们都基于 Amazon Athena 作为数据源。当使用 Amazon Athena 作为数据源时,您有两种选择。第一个选项是从 AWS Glue Data Catalog 数据库中选择一个表,比如我们在文章的第一部分“smart_hub_data_catalog”中创建的数据库第二个选项是基于 AWS Glue 数据目录数据库中的一个或多个表创建一个定制的 SQL 查询。

在本演示第二部分创建的三个数据集中,两个数据集直接使用数据目录中的表,包括“etl_output_parquet”和“electricity_rates_parquet”第三个数据集使用自定义 SQL 查询,基于单个数据目录表“smart_hub_locations_parquet”用于创建数据集的所有三个表都代表了位于 S3 的数据湖中丰富、高效的 Parquet 格式数据源。

数据集特征

创建和配置数据集时,有大量功能可用。我们不可能在这篇文章中涵盖所有的内容。让我们来看三个特性:地理空间字段类型、计算字段和自定义 SQL。

地理空间数据类型

QuickSight 可以智能地检测数据源中常见类型的地理字段,并分配 QuickSight 地理数据类型,包括国家、县、城市、邮政编码和州。QuickSight 还可以检测地理空间数据,包括纬度和经度。我们将利用 QuickSight 特性来处理三个数据集的数据源,包括州、邮政编码、纬度和经度字段类型。

计算字段

一个常用的 QuickSight 数据集功能是“计算字段”对于“etl_output_parquet”数据集,我创建了一个新字段(列)“cost_dollar”

cost字段是设备在五分钟时间间隔内的电力成本,单位为美分()。计算出的cost_dollar字段是cost字段除以 100 的商。该值表示设备在五分钟时间间隔内的电力成本,单位为美元($)。这是一个简单的例子。但是,计算字段可能非常复杂,由多个算术、比较和条件函数、字符串计算和数据集字段构成。

数据集计算字段也可以从 QuickSight 分析控制台创建和编辑(稍后讨论)。

自定义 SQL

第三个 QuickSight 数据集基于 Amazon Athena 定制 SQL 查询。

虽然您可以在 QuickSight 数据准备控制台中编写查询,但我更喜欢使用 Athena 查询编辑器编写自定义 Athena 查询。首先,使用编辑器,您可以编写、运行、调试和优化查询,以确保它们正常运行。

然后 Athena 查询可以粘贴到自定义 SQL 窗口中。在窗口中单击“完成”相当于在 Athena 查询编辑器控制台中单击“运行查询”。查询运行并返回数据。

与 Athena 查询编辑器类似,在 QuickSight 数据准备控制台中执行的查询将显示在 Athena 历史选项卡中,带有一个/* QuickSight */注释前缀。

香料

您会注意到三个 QuickSight 数据集被标记为“SPICE”据亚马逊网站称,首字母缩写 SPICE 代表“超高速、并行、内存计算引擎”。QuickSight 的内存计算引擎 SPICE 可在大规模应用中实现极快的性能。SPICE 自动复制数据以实现高可用性,允许成千上万的用户同时执行快速、交互式的分析,同时保护您的底层数据基础架构,节省您的时间和资源。使用 QuickSight 的标准版,作为第一作者,您可以免费获得 1 GB 的 SPICE 内存数据。

快速视力分析

QuickSight 分析控制台是创建分析的地方。特定的 QuickSight 分析将包含一组数据集和数据可视化(视觉效果)。每个视觉与单个数据集相关联。

QuickSight 分析视觉效果的类型包括:水平和垂直、单个和堆叠条形图、折线图、组合图、面积折线图、散点图、热图、饼图和圆环图、树状图、数据透视表、仪表图、关键性能指标(KPI)、地理空间图和文字云。可以轻松修改单个可视标题、图例、轴和其他可视方面。视觉效果可以包含下钻

可以从分析控制台中修改数据集的字段。可以为显示自定义字段类型和格式,如日期、数字、货币字段。该分析可以包括标题和副标题。有一些可定制的主题可以用来改变分析的整体外观。

分析过滤器

使用过滤器条件格式参数的组合,可以进一步调整视觉效果中显示的数据。下面,我们将看到一个基于日期和时间范围的典型过滤器示例。数据集包含两整天的数据。在这里,我们将数据过滤到 14 小时的用电高峰期,即 2019 年 12 月 21 日上午 8 点到晚上 10 点。

向下钻取、向上钻取、聚焦和排除

根据 AWS 的说法,除了数据透视表之外的所有可视类型都提供了为可视元素创建字段层次结构的能力。层次结构允许您向下或向上钻取,以查看层次结构不同级别的数据。焦点可以让你专注于字段层次结构中的单个元素。“排除”允许您从字段层次结构中删除元素。下面,我们看到一个例子,所有这四个特点,可适用于“中央空调”。由于空调设备是平均每天最大的电力消耗者,应用这些滤波器来了解其对整体电力使用的影响可能有助于分析。我们还可以从几小时深入到几分钟,或者从几小时深入到几天。

示例 QuickSight 分析

分析作者将 QuickSight 分析作为 QuickSight 仪表板进行共享。下面,我们将看到一个 QuickSight 仪表盘示例,它是为本次演示而构建和共享的。“住宅用电分析”是根据之前创建的三个数据集构建的。根据这些数据集,我们构建了几个视觉效果,包括地理空间图、圆环图、热图、关键性能指标、堆叠垂直条形图和折线图。每个视频的标题、布局和字段显示都是定制的。视觉效果中显示的数据经过了不同的过滤,包括按日期和时间、按客户 id ( loc_id)和按州。条件格式用于增强视觉效果的视觉外观,例如“总电力成本”KPI。

QuickSight APIs

虽然我们在这次演示中没有使用它们,但 Amazon 最近添加了一整套用于以编程方式与 QuickSight 交互的API。例如,要预览在演示的这一部分创建的三个 QuickSight 数据集,使用 AWS CLI,我们可以使用list-data-sets命令。

要使用 AWS CLI 检查单个数据集的细节,我们可以使用describe-data-set命令。

清理

要清理在本演示中创建的 AWS 资源,请执行以下 AWS CLI 命令。为了避免失败,请确保在运行后续命令之前完成每个命令。您需要使用 AWS CloudFormation 控制台或 AWS CLI 确认 CloudFormation 堆栈已删除。请注意,这些命令不会删除您可能从控制台创建的任何 Amazon QuickSight 数据集、分析和仪表板。但是,删除 AWS 粘合数据目录和底层数据源将影响在 QuickSight 中可视化数据的能力。

结论

在这篇文章中,我们学习了如何使用亚马逊 S3、AWS Glue、亚马逊 Athena 和 AWS Lambda 以多种格式接收、转换和丰富原始的半结构化数据。我们建立了一个基于 S3 的数据湖,并了解了 AWS 如何利用开源技术,包括 Presto、Apache Hive 和 Apache Parquet。最后,我们使用存储在数据湖中的经过转换和丰富的数据集,通过 Amazon QuickSight 创建引人注目的可视化效果。

本文表达的所有观点都是我个人的,不一定代表我现在或过去的雇主或他们的客户的观点。

posted @ 2024-10-15 13:48  绝不原创的飞龙  阅读(296)  评论(0)    收藏  举报