TowardsDataScience-博客中文翻译-2021-四十一-
TowardsDataScience 博客中文翻译 2021(四十一)
使用机器学习生成你最喜欢的角色的声线
学习机
使用最少的数据进行自然情感、高质量、比实时更快的文本到语音合成
阿图尔·图马斯扬在 Unsplash 上的照片
一个美丽的周日早晨,我看到一个意外的视频被 YouTube 推荐。
这是一个关于团队堡垒 2 的视频,这是一个 2007 年的 FPS 游戏,我在高中期间花了 1300 个小时。
游戏中有 9 个可能的角色,每个角色都有自己独特的声线和独特的口音。侦察兵有波士顿口音,军医大部分时间讲德语,间谍带着法国口音,你明白了。
我非常熟悉游戏中的所有台词,也非常熟悉《堡垒》官方视频中的台词,所以在那段视频中听到这些角色说的新台词让我非常惊讶。
我的第一个想法是视频制作者用cameo.com来支付原声演员的新对白。我错了。
这些声音是用机器学习创造的
15.ai
15.ai 作者截图
该项目是作为麻省理工学院本科生研究机会项目的一部分而创建的,但目前没有人确切知道谁是其背后的支持者。
作者目前没有透露任何源代码或发表任何论文,但他/她声称这种新技术在数据效率和自然性方面击败了 SV2TTS 。
使用最少的数据进行自然情感、高质量、比实时更快的文本到语音合成
那是作者对网站的描述。我不同意的一点是“比实时更快”的说法,因为语音生成非常慢,而且不是实时的。但是,这可能是由其他用户发送的请求队列造成的。
特性
在写作的时候,这个角色的声音阵容相当广泛,但是有限。
我们有来自海绵宝宝的海绵宝宝本人。《神秘博士》中的第十位医生。甚至 Undertale 的 Sans 也在。《堡垒 2 队》有全部 8 个角色,除了听起来总是闷闷不乐的派若,还有 TF2 剪辑中的管理员和鲍林小姐。
我看到的一个意想不到的阵容来自我的小马,它有 40 多个角色可供选择。
我本打算把它留在创作者肯定是 MLP 的超级粉丝,但我在常见问题下发现了这条题为“为什么有这么多 MLP 的声音?”
我以前从未看过任何 MLP,但我搜索了一个片段,他们的声音很有表现力。
你可以在这个页面中查看即将发布的中有哪些角色。
少量训练数据
与其他 TTS 技术相比,15.ai 能够用很少的数据模拟一个字符
…只用短短 15 秒的数据,就可以令人信服地克隆出一个声音,包括情感和一切
我无法验证只有 15 秒数据的结果有多好,但传送门的哨兵炮塔的声音只有大约 100 秒的数据,它令人惊讶地听起来相当不错。
我的假设是,模型也可以从其他角色的训练数据中受益,这解释了为什么一个数据很少的角色仍然可以产生高质量的结果。
作者 15.ai 中 MLP 角色截图
但是,小训练数据和大训练数据的字符之间的质量差异仍然非常明显。
与只有 27 分钟训练数据的海绵宝宝相比,拥有超过 120 分钟训练数据的 MLP 角色,如紫悦和小蝶,听起来更好、更自然。
拥有大量训练数据的字符可以产生更自然的对话,单词之间的屈折和停顿更清晰,尤其是对于较长的句子。
作者还指出,由于技术原因(近似均匀分布的声音频率),高音/女声效果最好。我认为这是由于大量的训练数据来自于 MLP 人物,这些人物一般都具有这些特征。
语调和情感
15.ai 的另一个有趣的事情是它如何使用 DeepMoji 来预测句子的情绪。
目前,我们不能手动设置声音的情绪,因为情绪的唯一可用选择是使用 DeepMoji 的“上下文”。
作者在 15.ai 中使用 DeepMoji 的截图
就我个人而言,我很想知道它将如何处理手动设置的情绪,因为它可能会迫使机器人生成以前未知的数据,例如带着悲伤或愤怒的情绪说“今天是伟大的一天”。通常这个特殊的句子会带着快乐的情绪说出来,看看这个模型如何为其他情绪产生声音会很有趣。
15.ai 作者评论截图作者对文章的评论
跟随着 @fifteenai 的评论,原来那个功能已经可以用了!
通过在原句后添加一个“|”并提供一个额外的句子,我们可以控制原句说话时的情绪。换句话说,“text_1|text_2”会用 text_2 的情感产生 text_1 的声线。
我决定尝试这个功能,它实际上工作得很好,肯定超过了我的预期。紫悦会用悲伤的语气说“今天是伟大的一天”,这意味着讽刺。
最后的想法
我发现甘创造声线的能力是由琴鸟完成的。看来这几年已经改变了,因为现在没有用你自己的声音训练模型的选项。
Lyrebird 也有自己的网站,但现在它似乎被 Descript 收购了,并专注于创建文本到语音的模型,以帮助内容创作者。
与我记忆中用 Lyrebird 创作语音时的情况相比,15.ai 完成的语音质量远远领先于它。语调相比当时的 Lyrebird 自然很多,尤其是训练数据很多的角色。
就像 DeepFake 一样,这项技术有可能成为一种制造虚假语音的危险工具,但我相信这将带来很多可能性,比如用你自己的声音取代谷歌助手、Siri 或 Alexa 的声音。
你可以在这里自己尝试一下,但是请记住,你提出的任何要求都将由开发者支付。如果你想帮忙,这是开发者的页面。
学习机是一系列关于我所学到的、我认为足够有趣的事情的故事,可以分享。有时也是关于机器学习的基础。 定期更新 新故事和 成为中等会员 阅读无限故事。
https://chandraseta.medium.com/membership
从 Jupyter 笔记本生成 Requirements.txt 文件
一个很容易被忽视的节省时间的方法。
伊恩·杜利在 Unsplash上的照片
介绍
创建 requirements.txt 文件是一个必要的过程,尤其是在共享代码、开发 MLOps 或者只是将一些东西放入 Docker 容器时。
从 Jupyter 笔记本中获取一个干净的 requirements.txt 文件是非常棘手的,所以我研究了不同的方法来完成它…
Pythonic 式的方法:Pip 冻结
这是我见过的关于栈溢出最常见的方法,就是使用 pip 冻结。这将列出您当前虚拟环境中的每个包和版本。
只需打开一个终端,并导航到您希望您的需求文件所在的文件夹。
然后,您可以使用 venv 或 conda 激活虚拟环境。
conda activate myenvpip freeze > requirements.txt
这种方法的问题
它将获取您在该环境中安装的每个软件包。如果你想创建一些轻量级的东西,只使用你的导入,那么你需要手动修剪这个文件。
Jupyter 方式:会话信息
如果你想只使用当前 jupyter 笔记本中的包,你可以使用 python 包session-info。**
安装使用:
*pip install session-info*
在 jupyter 笔记本中,导入包后,您可以写下:
*import session_infosession_info.show()*
你会得到类似这样的东西:
然后,您可以使用查找和替换功能复制、粘贴并替换空格为 == 。
这种方法的问题
它没有考虑来自我们的依赖关系。py* 文件,自定义 _ 函数。但是,这些将与所有其他依赖项一起出现在较低的位置。*
最大的问题是它采用了导入的名称,而不是包的名称。例如, sklearn 的命令实际上是pip install scikit-learn
,这意味着它不会作为 requirements.txt 文件工作。
可靠的方式:Pipreqs
如果您只想让 requirements.txt 文件与单个笔记本相关,而不是与您的整个环境相关,这是最好的方法。
首先打开一个终端并安装 pipreqs 和 nbconvert 。
*pip install pipreqs
pip install nbconvert*
然后,导航到 Jupyter 笔记本所在的文件夹。
如果我们假设笔记本叫“我的 nb”。您需要用反斜杠()对空格进行转义。
*jupyter nbconvert --output-dir="./reqs" --to script my\ nb.ipynbcd reqspipreqs*
如果成功了,您应该会收到一条成功消息。
所以我们在这里做的是把我们的笔记本转换成一个。py* 文件放在一个名为 reqs 的新目录下,然后在这个新目录下运行 pipreqs 。原因是 pipreqs 只对有效。py 文件,当文件夹中有其他文件时,我似乎无法让它工作。requirements.txt 将在同一个文件夹中生成。*
你将得到一个完美的需求文件,你可以用它来做任何事情!
了解更多信息
*
将我的内容直接发送到您的收件箱!
https://adamsh.substack.com/p/coming-soon *
在 TigerGraph 中生成一个秘密
关于在 TigerGraph 中生成秘密的一步一步的微博
照片来自 Unsplash 由 Stefan Steinbauer 拍摄
什么是秘密?
在 TigerGraph 中,秘密是允许外部脚本与您的图形交互的唯一代码。一些 TigerGraph 工具可能会要求您提供,但是生成一个秘密本身是很棘手的。
第一步:开始你的解决方案
如果您尚未创建或启动您的解决方案,您需要这样做。以下是如何做到这一点的步骤:
- 在 https://tgcloud.io 创建账户。
- 转到https://tgcloud.io/app/solutions。
- 创建一个解决方案(如果您还没有)。
- 如果您已经创建了一个解决方案,请确保它已经启动。如果关闭,请转到解决方案操作>开始。
- 等待解决方案在状态下显示“就绪”。
第二步:登录 GraphStudio 并导航到 Admin
首先,导航到 GraphStudio。你可以去https://tgcloud.io/app/solutions,点击应用,然后按 GraphStudio。
按下应用程序(四个方块)后。单击 GraphStudio。
可能会要求您登录,也可能不会要求您登录。登录后,您将被定向到如下页面。在那里,点击右上角的“管理”。
点击右上角的管理
第三步:生成秘密!
太好了!现在你是管理员了。接下来,您需要切换到左侧边栏中的“用户管理”。
点击左侧的“用户管理”。
太好了!您应该会看到下面的屏幕。
用户管理屏幕
接下来,您需要为您的秘密创建一个别名。有一些对秘密的保留词,像“秘密”本身。在本例中,别名是“sec”完成后,单击绿色加号按钮。
在“别名”中键入您的别名,然后按绿色箭头
太好了!你的秘密应该出现了,现在你可以在你的代码中复制和使用它了!
后续步骤
恭喜你。你创造了一个秘密!现在,您可以加入 TigerGraph Discord 来了解更多信息并加入任何项目!
用 RNNs 生成“航空法规”
行业笔记
使用递归神经网络生成美国民用航空条例样式的新文本
介绍
递归神经网络太棒了!它们允许我们通过使用相对简单的神经网络架构并在序列的每一步重复它,基于序列数据进行预测。在这些步骤中的每一步,网络都输出一个预测(像任何其他架构一样)以及一个记忆状态(这就是创新),该记忆状态被它在预测任务中的下一次迭代所使用。这种安排的结果是,我们最终得到一个重复单元的网格,这些重复单元共享它们的权重和偏好,同时通过交换存储单元的内容来相互通信。
RNNs 可以成功地应用于许多预测问题,从基于一系列数据点预测天气到基于历史数据预测未来股票价格。
由于 RNNs 能够估计数据序列中的下一个点,因此也可以用来生成原始数据点。如果我们用一个序列作为 RNN 的种子,并使用它来预测下一个条目的概率,我们就可以对这些概率进行采样,以获得数据的合理扩展。然后,我们可以把新扩展的序列再次输入到 RNN,得到另一个新的点。通过重复这一过程,一个经过精心训练的 RNN 可以用来基于从训练集中学习到的模式生成新内容,无论是莎士比亚戏剧的全部、巴赫合唱团的 4 部分全集、维基百科文章的大集合,还是我们训练它的任何其他大型序列数据语料库。
在本文中,我将展示将递归神经网络应用于全套美国民航法规的一些结果。通过训练一个模型来读取一系列字符并预测下一个字符,我们最终得到了一个能够按照这些规则的风格生成原始文本的网络,一次一个字符。我选择联邦航空局发布的法规,是因为它们相当于一个庞大的文本语料库(超过 600 万个字符),它们以一种易于解析的格式随时可以在网上获得,并且因为我在过去十年的大部分时间里都在确保飞机、运营和机组人员遵守这些法规。
模型描述
本文不会详细讨论 rnn 的方法和原因。如果你对解释和大量有趣的例子感兴趣,我怎么推荐 Andrej Karpathy 的循环神经网络的不合理的有效性博客文章都不为过!
尽管如此,以下是模型特性的高级描述:
- 整套规则(超过 600 万个字符)以 98/2/2%的比例分为一个训练集、一个验证集和一个测试集。分区对文本组织并不敏感:条例的每一节都完整地保存在三个分区中的一个分区中。
- 该模型包括使用具有 116 个标记的标记化器的时间分布编码层,所述标记对应于在训练集中找到的每个字符,接着是 3 个门控循环单元的堆栈,每个单元具有 580 个单元,层标准化和丢弃正则化应用于存储器和输出,接着是具有 softmax 激活的密集连接层。以下是 keras 中 model.summary()方法的输出:
图一。model.summary()方法输出
- 使用具有内斯特罗夫动量的 Adam 优化器进行 100 个时期的优化,每次损失函数达到稳定水平时学习率降低。
- 在每个训练步骤中,模型被输入 32 批 256 个字符长的序列。
- 每个递归单元都被设置为有状态配置,因此存储单元的内容可以从一批延续到另一批。
- 这个问题是以多对多的方式提出的,这意味着在每一步,网络都要预测序列中的下一个字符。
- 完整的模型包含 500 多万个参数。
如果你想检查代码,可以在这里找到一个带有 python 实现的 jupyter 笔记本。
现在,让我们终于看到一些例子!
结果
在对该模型进行训练后(在使用 GPU 加速的谷歌 Colab 会话中,我花了大约 20 个小时),它在测试集中达到了大约 82%的准确率——这意味着它能够在 82%的时间里正确预测以下字符,这些字符是它在训练期间没有见过的监管文本。对于它在训练中看到的文本,准确率达到 86%多一点。
我使用该模型生成了一个由一百万个新字符组成的序列,并将其保存到一个文本文件中。这大约相当于美国联邦航空局规章总尺寸的 1/6。如果你想看看,并试图找到一些有趣的东西,你可以在这里看到完整的文件。
以下是一些亮点:
适当的词汇,但没有语义感:
该网络非常善于捕捉法规中的典型术语,甚至可以形成长句。尽管生成的文本对于熟悉航空法规的人来说非常熟悉,但它无法生成真正有意义的语句。
121.447 按照类别和等级进行操作的人员。(一)总则。申请模型飞机的人必须接受并记录政府的地面和飞行训练——机动和程序中的问题可能包括在适航性限制部分。必须使用以下信息:
(ii)教员,指熟练掌握本节第(a)(1)(ii)段要求的实践考试所需的完美飞行经验的人员。
对于装有四台或四台以上发动机的每架飞机,直升机场上方的相同高度可能小于连续 3 小时的 3%的速度。
结构恰当的长句和段落,但没有可辨别的主题:
该模型再现了句子、段落和小节的典型长度。它甚至抓住了文本的层次结构。但是它没有保留连贯的主题,并且经常在同一个句子中输出不相关的主题:
在这里,它混合了静压、操纵面、紧急出口、火灾等等:
23.2525 静压系统测试。如果发动机出现故障。必须通过确定有效载荷来指示分配给飞机表面运动和其他相关程序的每个油气球,必须通过分析或测试来表明符合性,以防止必须安装每个紧急出口,以便-
(1)选择用于干额定值的单个部件具有其较低或较高的系统功能。
(3)贯穿发动机的关键循环部件,以在打开位置投射任何可能发生火灾的元素。
(d)火。(c)由于非自动或动力操作系统的安全和烟雾可能竖立,将油箱油底壳分离到预计变形会首先用于自动或动力操作系统的区域。
在本节选中,它涉及到装载、无线电设备、复飞、发动机、维护和噪音:
33.85 积载规定。第 121.310(e)节,第 121.337(b)(1)(viii)节,允许无线电设备在不超过两个未错过的进近中运行,以便在闭合基准点运行时辅助标志出现故障。
(7)自预期的直接卫星运行条件的最后一天起,接受此类非数量航空承运人保护的发动机有足够的燃料,考虑到进入点,但不限于限制,完成授权执行一架以上飞机或一组飞机的人员的识别所需的任何指令。飞行标准办公室给出以下程序:
(1)121.405 中所示文件的当前副本。
(d)根据本节,本子部分适用于经主管人员批准的每个证书持有人。
(k)维护和噪音限制。本节适用于外国航空承运人或持有在美国注册的涡轮机/飞机的外国人指挥飞机,如果该人:
实际的 23.2525 针对普通类飞机的发电、储存和配电,而实际的 33.85 针对动力装置校准测试。
该模型也未能采用排序模式:段落应遵循顺序(a)、(b)、(c)等,项目应遵循(I)、(ii)、(iii)、(iv)等,但正确的编号在生成的文本中随处可见。
拼写错误
总的来说,该模型在正确拼写单词方面非常出色,甚至可以识别其他模式,如大写字母的使用以及空格、逗号和句号的放置。然而,拼写错误或不存在的单词也很常见,这很大程度上是由于采样过程——为了确保新生成的文本不重复,根据其概率随机选择下一个字符(而不是只挑选最有可能的一个)。
这些地方之间的关系 3500 美元以上的世界持有一架 nartoty 计划的飞机需要一艘海军 I
91.855 责任:与燃料 体积 或轮渡飞行时间相关的豁免权限。
25.509 特殊控制。(a)全机最大起飞重量下的每次预定操作
监管元数据
偶尔,模型输出看似随机的胡言乱语,但实际上对应于案卷号、法规修订和出版日期的法规参考。这些都正确地位于一节的末尾。
(1)根据批准的等效方法对每次飞行进行调查,调查由至少 3 小时有效的发动机运行限制的正常运行范围内的火灾引起。 【Doc。№2000–8114,66 FR 25036,2001 年 4 月 28 日]
27.933 整流罩系数。(a)系统的仪表编号必须确保出口到达,且发动机处于出口打开时可能出现的负载下。
(b)在可以抵抗的速度下:
(1)对警告的种类进行总结;和
(2)对于来自一个来源的燃油,或前起落架,必须设计成能承受-
(1)油箱操作的最小值;并且
(3)该结构必须设计用于仅具有旋转角度的水平着陆姿态的载荷。
(2)极限扭矩极限必须在存在的速度下确定(在海平面和设计条件下使用的配置,如失速,不得超过制造商相应的静态地面载荷条件;和
(2)以及每个发动机的控制系统功能指示器。
(b)每个要求楼层的紧急出口必须设计成恒定速度,完全断电,以防止结冰分类或故障。 【Doc。№5066,29 FR 18291,1964 年 12 月 24 日,由 Amdt 修订。25–38,41 FR 55466,1976 年 12 月 20 日]
几个更长的例子
前面的摘录都是为说明特定特征而选择的短文。但是,当看整个文本时,它被清楚地分成与实际法规大小相同的部分和段落。以下是一些例子:
15.50 所有规则制定的货币。(a)农用飞机运营商。在完成发现请求后的 30 天内。(d)无论何时被申请人未能提供一份坐标函,仅当-
(a)其未能遵守 161.205;或
(2)考虑诉讼或收购项目,如果它有一个扩展到禁止的反应计划,规定的信息。适当时,以及任何其他法定证据,或在记录中,当它不在任何可忽略的问题中,或可能不提供 FAA 根据 161.305 (b)对提议项目的批准。
(2)DRO 还是特级大师,为什么最后的预告会透露一个次要情节。如果美国联邦航空局的决策人批准了一项内部发现请求,并应向当事人送达一份申诉书副本。但是,对于本合同的争议审查,报告的听证员和
(4)请求人提出的重新生效的法律动议的副本。如果需要两项赔偿。
【Doc。№18834,54 FR 34318,1989 年 8 月 18 日,由 Amdt 修订。91–296,72 FR 31679,2007 年 6 月 7 日]
47.80 禁止代表事故。要求使用 IFR 程序或非运输类飞机的人可以在重量大于本部分附录 F 中所列重量的情况下起飞飞机,而不是必须按照 25.21(g)、选择或高度操作 30 秒 OEI 额定功率。旋翼飞机的最大工作重量,连同旋翼飞机舱,必须在旋翼飞机在飞行条件下工作的气体温度之间,必须如此标记,以使其不能达到显示的舱,除非适当的天气报告或预报、温度和起落架,作为多发动机额定值,据报告是一个发动机不工作的学生,或在最大螺旋桨时间,因为最低重量允许预定的服务救生筏(圆筒除外)。
(三)吸烟。每个动力装置和辅助动力装置必须能够支持所使用的系统。
(c)成员们已经合格并完成了每台发动机、在每一个油箱、飞行甲板之间进行的起动和反作用其操作均无颤振、操纵以及燃油和油的任何组合的试验;和
(2)有可能造成伤害的危险情况。
这些只是从模型生成的大量文本中挑选出来的一小部分。如果你有兴趣自己寻找有趣的例子,你可以看看这个 100 万字符长的文本文件。
结论
这是一个有趣的项目,我希望你觉得结果很有趣。
该模型生成了一些有趣的新文本,在术语、风格和结构上与美国联邦航空局出版的美国民用航空法规的实际语料库非常相似。但它没有产生有意义和有实际意义的东西。
这些严重的限制是合理的,因为很难从基于单个角色训练的模型中提取有意义的内容。意义取决于更大和更复杂的结构,如单词、句子和段落,能够通过一次看一个字符来学习这些需要更大的文本语料库和大量的计算资源。
同样值得注意的是,该模型没有任何先验知识,也没有接触过任何语言的任何文本。它所学的每一点英语都是基于这个法规文本。
这种实现的替代方案是使用预先训练的单词嵌入来将单个单词表示为特征或“特性”的向量。单词嵌入在捕捉文本语义方面要好得多。他们还携带了大量在自己培训期间获得的语言知识,这使得模型可以专注于更具体地针对手头任务的学习模式。
然而,我怀疑公开可用的预训练单词嵌入不太适合像航空法规这样的专业性质的文本。
如果你有兴趣更详细地了解 RNNs 或者看看其他一些有趣的应用例子,我强烈推荐这篇博文。如果你想学习如何建立这种模型,这本书就是你要去的地方。如果你想查看数据集并亲自尝试一下,你可以通过链接在 kaggle 上访问它。你也可以在这篇文章中查阅我的作品《以巴赫的四声部合唱曲风格创作新巴洛克音乐》。
你觉得这个帖子有趣吗?伸手在 Linkedin 上打个招呼!
参考资料和相关链接
- [1] FAA 法规 —用于训练神经网络的全套法规,可通过 e-CFR 网站获得
- [2] 递归神经网络的不合理有效性 —安德烈·卡帕西的经典博客文章,关于什么是 RNN 病以及它们能做什么
- [3] 用 Scikit-Learn、Keras & Tensorflow 实践机器学习——学习如何使用 Tensorflow 和 Keras 实现这类模型的好书
生成同位语/N 元语法的 5 种方法
使用 5 种方法生成 N 元图的完整指南。
布雷特·乔丹在 Unsplash 上的照片
什么是 N-gram 或搭配?
通俗地说,N-gram 或搭配只不过是两个或更多的词经常一起出现。
在搭配的情况下,需要做的第一件事就是将文档转换成标记/单词列表的形式。从这个单词列表中发现搭配意味着找到在整个文本中频繁出现的常见短语。
例如:美国,英国,铺床,去冒险。
大约有六种主要的搭配类型:形容词+名词、名词+名词、T5(如集合名词)、动词+名词、副词+形容词、动词+介词短语(短语动词)、动词+副词。
产生搭配的重要性
这个目标有助于将重要的和最频繁的单词保持在一起,这将进一步有助于良好的主题建模,并且也是用跨不同组的文章或文档获得的标签来标记数据集的主要步骤。
-
在我们开始使用不同的方法生成 N 元语法之前,有必要将文章转换成一个令牌列表(字母或数字)。所以下面的函数会为你做同样的事情。
-
接下来的事情是初始化 NLTK 的二元模型/三元模型查找器。要做到这一点,您可以使用下面提供的函数来实现。
用于生成 N 元文法的不同方法
1。 统计相邻词的频率:
主旨:简单按频率排序。
这种方法将简单地计算相邻单词作为二元模型或三元模型或 n 元模型共出现的次数,而完全不考虑它们的关系、依赖性。
问题:对经常出现的对和代词/冠词/介词过于敏感。
解决方案:只过滤形容词和名词。用词性过滤器计算频率。
-
这里有一个按形容词和名词过滤的函数。
-
现在,我们将使用上面创建的过滤形容词和名词的函数来过滤使用频率计数函数生成的二元模型。
类似地,您可以使用相同的方法使用频率方法生成三元模型,也可以使用相同的方法过滤三元模型。
2。 PMI(逐点互信息):
该方法分配一个统计度量来比较每个二元模型。该方法还允许过滤掉那些出现次数不超过最小次数的令牌。
在实际定义中,PMI 给出了一个单词在一段文本中出现的概率,前提是一些单词已经在它之前出现。
尽管 PMI 方法给出了相当好的 N-gram 集,但我仍然应用了与频率方法相同的滤波器,以查看结果的差异。我必须说,在过滤了 PMI 方法之后,结果是相当合理的,并且出现了相关的图表。
类似地,尝试用这种方法来生成三元模型,看看与频率计数方法的区别。
假设检验 3。 T 检验:
t 检验是比较两个样本平均值的统计检验。它用于假设检验。
现在,让我们理解使用它来生成有效的 N 元文法的想法。所以,考虑一个有 N 个词的语料库,社交和媒体分别有字数 C(社交)和 C(媒体)。假设社交媒体和媒体是独立的。
测试统计数据为:
这里也有同样的问题,经常与介词、代词、冠词等配对。是最重要的。此外,t 检验因假设正态分布而受到批评。因此,我们接下来应用了卡方检验。
实用方法:
下面的函数将告诉你如何使用 t-test 方法来生成 N-gram。
只是为了减少 N-grams 生成的无意义数量,我使用下面的函数在 T-test 方法上应用了过滤函数。
一定要尝试使用这种方法生成三元模型,看看三元模型的 t 检验是如何产生结果的。
4.卡方检验:
卡方检验是一种统计假设检验,假设(零假设)某一分类变量的观察频率与该分类变量的预期频率相匹配。
假设:卡方检验也像 t 检验一样在零假设中假设单词是独立的。卡方检验统计量计算如下:
实用方法:
下面的函数将告诉你如何实现卡方检验来生成二元模型。
用于过滤形容词和名词的卡方检验方法。
同样,对三元模型尝试这种方法,并以类似于上面说明的方式将结果与其他方法进行比较。
5。 似然比检验(LRT):
在统计学中,似然比检验根据两个竞争统计模型的似然比来评估它们的拟合优度,具体来说,一个模型是通过在整个参数空间内最大化得到的,另一个模型是在施加一些约束后得到的。
实施:
使用 LRT 生成二元模型,这是我写的函数。
为了过滤 LRT 方法,下面的函数将帮助你。
类似地,对三元模型也尝试这种方法,并将结果与上面讨论的其他方法进行比较。这将给你一个综合的概念,哪种方法是最有效的。
你也可以在这里 查阅 google collab 上托管的完整代码。在那里,我也对三元模型执行了这些方法。因此,请务必查看完整的代码。
过滤和不过滤的区别:
在执行了生成 N-gram 的所有方法后,我比较了所有方法的结果,下表将显示应用过滤器前后不同方法的结果差异。
从上表中可以看出,过滤后得到的 N-Grams 要少一些,这也是为什么会是最好的。然而,过滤前的 N 元语法列表是一个非常大的数字,这在将来将 N 元语法用于主题建模的目的时是有问题的。检查 完整代码 的功能实现,该功能比较所有带过滤器和不带过滤器方法的结果。
主要调查结果 1
为了检查 N-Grams 的结果,在预处理数据集时,我保留了两个文件,一个带有 _stopwords,另一个没有 _stopwords。
- 在为这两个文件生成 N-gram 时,我发现,即使不应用过滤器,with_Stopwords 文件也比 with _ stop words 文件提供更可靠的结果。
- With_Stopwords 文件没有将撇号作为单独的字母,而将一些无意义的东西作为单独的字母,这就是为什么在清理数据时保留停用词是至关重要的。
您也可以进行同样的实验,并在您选择的数据集上检查结果的差异。
主要调查结果 2
在完成以上 5 个测试后,我发现了很多观察结果,同时也发现了最好的方法。
- 频率、t 检验、似然比检验有几乎相同的结果,在对两个文件应用了名词和形容词的过滤器后,结果非常好。
- 然而,PMI 和卡方检验的结果几乎相同。
- 带滤波器的似然比检验最适合这种情况。它还涵盖了各种关键字。
务必参考 完整代码 查看结果差异。
如果你已经走到了这一步,我希望这篇文章已经帮助你解决了你的疑问,并且你已经从我所做的实验中学到了一些新的东西。
您可以通过以下方式联系我:
- 订阅我的 YouTube 频道 视频内容即将上线 这里
- 跟我上 中
- 通过 LinkedIn 联系我
- 跟随我的博客之旅:-https://kajalyadav.com/
- 成为会员:https://techykajal.medium.com/membershipT21
也可以看看我的其他博客:
</15-free-open-source-data-resources-for-your-next-data-science-project-6480edee9bc1> </8-ml-ai-projects-to-make-your-portfolio-stand-out-bfc5be94e063>
为机器学习生成自定义代码
使用 Traingenerator Streamlit 应用程序生成 Pytorch 和 Sklearn 代码
弗洛里安·奥利佛在 Unsplash 上拍摄的照片
如今,每个人似乎都对学习数据科学感兴趣,因为每个人都知道这是一个新兴领域,并且在过去的一段时间里蓬勃发展。有不同的教程和博客可以帮助你开始学习数据科学。但最重要的是接触机器学习或深度学习的不同框架。
创建对不同框架的理解不仅有助于我们使我们的档案多样化,而且有助于理解这些框架的利弊。在本文中,我们将讨论一个基于 streamlit 构建的 web 应用程序,它可用于生成自定义代码模板,我们可以根据自己的用途使用这些模板。
Traingenerator 是一个 web 应用程序,为 Pytorch 和 Sklearn 提供定制代码模板。我们可以使用这个 web 应用程序来定制。在这种情况下,我们可以为图像分类或对象检测生成代码,它支持不同的模型,如 Alexnet,Resnet 等。除此之外,它还支持公共数据集,如 MNIST 等。,以及我们自己选择的数据集或图像文件。我们将讨论 Traingenerator 支持的其他几个功能,同时探索如何使用它。
让我们开始吧…
打开应用程序
我们可以使用下面给出的链接来打开 Traingenerator,这是一个 streamlit 应用程序,用于生成自定义代码模板。
https://traingenerator.jrieke.com/
创建自定义代码
现在,我们将开始构建我们的自定义代码,只需选择下拉菜单和左侧边栏中给出的选项。下面给出的是该应用程序的登录页面,您将看到所有可以添加到代码中的功能。
来源:作者
如图所示,您可以通过选择以下不同选项来创建自定义代码:
- 任务
在这里,我们将选择我们想要解决的问题的类型,并为此选择框架。
2.型号
在这里,我们将选择我们想要使用的模型和类的数量。我们也可以通过勾选复选框来使用预先训练的模型。
3.输入数据
在这里,我们可以选择想要使用的数据集,无论是公共数据集、NumPy 数组还是图像文件,它都支持。
4.培训
对于训练部分,我们可以选择不同的超参数,如损失函数、优化器、学习速率、时期等。
5.可视化
在这里,我们可以选择如何查看模型的指标。
使用 Traingenerator 最好的一点是,生成的代码可以直接在 collab 中打开,也可以在下载。py 或者。ipynb 格式。现在让我们为图像分类创建一个基本模型。
下面给出的视频将帮助您了解如何创建自定义模型,并下载以使用它。
来源:作者
因此,在这里我们看到了在 Pytorch 和 Sklearn 上创建不同的模型是多么容易和毫不费力。继续用不同的数据集、参数等进行尝试,并让我知道您在回复部分的评论。
如果您对创建自己的 streamlit 应用程序感兴趣,您可以查看下面的链接,在那里我解释了如何创建一个基本的 streamlit 应用程序。
本文是与皮尤什·英加尔合作完成的。
在你走之前
感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。
通过绘图生成数据
使用 drawdata 生成假数据
(来源:作者)
创建机器学习模型有助于理解不同列/数据点之间的交互。它向我们展示了如何计算数据点相对于特征数据点变化的偏差。
在学习数据科学时,通常每个人都是从 sklearn 中已经存在并使用了多年的数据集开始学习的,但为了更好地理解数据相关性以及数据在不同机器学习模型中的表现,我们需要更多的数据集。
Drawdata 是一个开源的 python 库,通过简单的绘制来帮助生成数据。它允许用户创建不同形状的多样化数据集,这有助于学习数据科学/机器学习。
在本文中,我们将探索使用 drawdata 生成数据的不同技术。让我们开始吧…!
安装所需的库
我们将从使用 pip 安装 drawdata 开始。下面给出的命令可以做到这一点。
python -m pip install drawdata
导入所需的库
在这一步,我们将导入所需的库,这些库将帮助我们使用不同的技术生成数据。
from drawdata import draw_line, draw_scatter, draw_histogram
创建数据集
现在我们将创建数据集,并使用 drawdata 创建的 GUI 下载它们。
- 使用散点工具
draw_scatter()
绘制散点图(来源:作者
在这里,我们可以清楚地看到它如何创建一个 GUI,我们可以在其中创建不同的数据点,还可以下载不同格式的数据集。
2.使用线条工具
draw_line()
画线(来源:作者
3.使用直方图工具
draw_histogram()
绘制直方图(来源:作者
这就是我们如何使用 drawdata 创建不同的数据集,并下载数据集来创建机器学习模型。继续尝试并创建不同的数据集来学习机器学习/数据科学。请在回复部分告诉我您的意见。
本文是与皮尤什·英格尔合作完成的。
在你走之前
感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。
用马尔可夫链生成药品名称
马尔可夫链的简单实用介绍。
在 Unsplash 上由 Myriam Zilles 拍摄的照片
马尔可夫链是通过从一种状态随机转移到另一种状态来生成值的概率模型。下一个状态仅由当前状态和转移到下一个状态的概率决定。它们的简单性使它们成为对预测模型的很好的介绍,而不需要了解任何专门的库,如 PyTorch 和 TensorFlow。
马尔可夫链是如何工作的?
在抽象层次上,马尔可夫链是有限数量的状态和转换的集合,描述了从一个状态到另一个状态的随机变化。它们可以用来模拟随机发生变化的事件,但仍然遵循某种概率分布。
当马尔可夫链在训练过程中记录从一种状态到另一种状态的转换时,它会调整转换的权重,以使该转换更有可能在预测过程中发生。如果模型是基于数据训练的,其中转换 A→B 的可能性是 A→C 的两倍,那么当模型处于状态 A 时,下一个状态可能是 B 或 C,但是它是 B 的可能性将是两倍。
简单的例子
假设我们用“蝙蝠”和“比特”这两个词来训练马尔可夫链。我们将使用句号(。)来表示单词的结尾。这是链条的样子:
图 1.1:用一次出现的“比特”和“蝙蝠”训练的马尔可夫链。箭头附近的数字显示了这种转变的概率。请注意,在每个状态下,转移概率总和为 1。
当该模型用于进行预测时,它会执行一次随机漫步。
在随机漫步中,我们从“开始”状态开始。有一定的概率把状态变成‘B’,所以它那样做了。在“B”处,下一个状态同样可能是“A”或“I”。变化是随机的(随机行走的“随机”部分),但仍然遵循概率分布。假设它去了‘我’。然后,它转换到“T”(概率为 1.0),最后转换到结束状态(“the”)状态)。模型组装了“比特”这个词,但也同样有可能组装“蝙蝠”。
这个特殊的马尔可夫链不能转移到以前的状态。它只能产生以前见过的单词。
一个更复杂的例子
马尔可夫链不需要遵循线性流动。让我们以前面例子中的链为例,对单词“BIITAT”进行训练:
图 1.2:用一次出现的“BIT”、“BAT”和“BIITAT”训练的马尔可夫链。
现在存在模型将停留在状态‘I’的概率,并且从状态‘T’转换回状态‘A’。该模型现在可以生成它从未见过的单词,如“BATATAT”和“BIIIIIIIT”!这些话不太可能发生,但还是有可能的。想象一下,如果我们给它更多的数据,它会做什么!
只要我们用来训练它的每个单词的末尾都有一个句号(结束状态),随机游走最终会到达结束状态。
产生幻想的名字
马尔可夫链的一个有趣的应用是产生幻想的名字。给定足够的数据,他们将遵循训练数据的一般趋势,不断改变组成数据的模式。毕竟,生成的单词只是由以前看到的单词的模式组成的。
在我看来,药品的品牌名称总是有一种臧。它们没有字典意义,但通常具有可识别的模式,使它们听起来像“药物名称”。我们将使用马尔可夫链来生成这些名称
数据
FDA 保存了所有批准药物的国家药物代码(NDC)目录。在将“专有名称”从电子表格中分离出来并过滤掉含有特殊字符、数字和空格的名称后,我得到了一个包含 3403 个名称的列表,这些名称可以用于训练。
包含过滤数据和原始数据的 GitHub repo 的链接包含在本文的末尾。
实现马尔可夫链
在前面的例子中,我已经将马尔可夫链绘制成带有节点和链接的图。节点和链接使跟踪和可视化变得容易,但是实现起来不切实际。我们将把马尔可夫链实现为一个嵌套的 Python 字典。外部字典的关键字是“当前状态”;外部字典的值是表示转换的另一个字典,其中键是“下一个状态”,值是转换被观察到的频率。
这种方法更难可视化,通过简单地做chain['state']
而不是遍历一个图来访问一个状态要容易得多。以下是图 1.2 中状态“T”条目的一个示例:
chain['T'] = {
'A' : 1, # T -> A transition in BIITAT
'.': 3 # T -> '.' transition in BIT, BAT, BIITAT
}
存储跃迁的频率也是有意义的——它们只需要在训练期间递增,而所有的概率都需要重新计算。
构建链条
这就是我们在 Python 中构建链的方式:
随机游动
尽管在训练中已经看到了数以千计的名字,但如示例中所述,链中的简单随机行走会产生垃圾。生成的名字大多没有臧(比如:只有“AE”);一些规则需要到位,使名字有一些 funk。
虽然我前面说过马尔可夫链的下一个状态完全取决于当前状态,但是对于这个应用程序来说,通过检查规则来考虑前一个状态以生成更好的名称更有意义。
我也在计算结束字符(' . '))和空字符(“”)作为元音;这可以防止单词以两个元音开头或结尾。
随机选择下一个状态的函数pick_char()
是这样工作的:
- 所有下一个状态的频率被相加。
- 产生 0 和 1 之间的随机值,并乘以频率和。该值介于 0 和频率和之间。
- 在频率字典的每个“下一状态”,从随机值中减去该状态的频率。如果随机值小于零,那么这个“下一个状态”是所选择的“下一个状态”,否则我们转到下一个“下一个状态”并做同样的事情。这将根据状态出现的概率随机选取一个状态。
函数next_char()
是进行随机行走的函数。它是递归的。它调用pick_char()
,直到返回一个满足规则的字符。然后,它递归,以新生成的“下一状态”作为新的“当前状态”,以前的“当前”状态作为前一状态。
将所有这些放在一起…
现在我们可以调用前面讨论过的函数来进行马尔可夫链的随机游走,并生成一些名字!
这是我们运行它时得到的结果:
flurimbin
kenzaidel
uvinaze
colmix
iluprarax
zelare
irevene
enxophir
trexin
hysesox
结论
建立一个马尔可夫链来生成虚构的名字是对随机过程的有趣介绍。除了虚构的名称,马尔可夫链和马尔可夫过程可以更广泛地用于进行“预测”和生成值,其中变化是随机的结果。我希望您尝试一下这个简单的项目,并可能扩展它的其他用途。
下面是包含该项目的代码和数据的 GitHub repo (生成器也是用 JavaScript 实现的!).数据可能有点过时了。
使用合成数据生成/扩展数据集
本文旨在解决使用包含 GANs 的开源库来扩充/扩展现有数据集的需求
蒙罗工作室在 Unsplash 拍摄的照片
1.背景
作为一名 ML 从业者或数据科学家,当我们发现自己处于类似“如果我们有更多数据就好了”的情况时,这也许是可能的。很多时候,我们拥有的数据集非常有限,并且不确定如果给定更多数量的统计相似数据,我们的机器学习模型的性能会更好还是更差。当然,我们可以从与现有数据相同的来源中挖掘更多的数据,但这并不总是可能的。如果有一种方法可以从我们现有的数据中创造出更多的数据,那会怎么样?
2.简介—以数据为中心的方法
以数据为中心的方法正在成为这些天讨论的一个常见和热门的话题,像吴恩达这样的流行名字倡导需要拥有/建立以数据而不是模型本身为中心的人工智能解决方案。当然,拥有正确的模型也是必不可少的,并且应该牢记在心。关于以数据为中心还是以模型为中心的争论是一个重要的问题,因为我们不能完全偏爱一种方法。
3.为什么让 AI 扩展你的数据集?
让我们问自己两个基本问题-
- 为什么我们要让一个本质上是模型(一段代码)的 AI 来扩展我们的数据集,为什么我们不能只拿我们现有的数据集,手动去做呢?
- ML 算法将基于我们现有的数据生成新的数据。让一个人工智能模型增加更多但(某种)冗余信息的数据集,而不是保留更少但更有用的信息,这难道不是毫无意义的吗?
第一个问题的答案相当明显,因为当我们处理数千(甚至数百万)规模的数据集时,手动干预变得几乎不可能,因为很难研究整个数据集并提取本质上构成数据集的重要特征。然后需要以特定的方式复制这些提取的特征,以便向数据集中添加更多的示例。一个简单的方法是寻找更多的数据。但是寻找往往并不容易,更具体地说,如果项目需要非常特殊或特定类型的数据集。此外,在当今世界,隐私是一个大问题,如果数据搜索过程涉及废弃用户的个人数据或身份,那么它可能不是最道德的方式。
至于第二个问题,马上回答有点棘手,它需要一些深刻的思考。这个问题的答案包括交叉检查负责生成新数据的 ML 算法。通常,这样做的需要取决于项目需求和最终结果。
考虑这一点的最简单方法如下。比方说,我们为最终测试留出一个特定的精心策划的测试数据集。现在,如果新生成的数据集与原始数据集相结合,能够在阈值范围内改进模型,它将满足我们的目的,并且将足够有用。换句话说,如果我们的模型的性能在我们看不见的数据集上有所改善,我们可以得出结论,将我们现有数据的增强版本添加到模型中可以改善它,并使系统对从未见过的数据更加稳健。
4.GANs——简要描述
一篇关于 GANs 的精彩而详细的文章可以在谷歌开发者的博客文章中找到,但是用非常简单的话来说,一个生成性的对抗网络由试图相互竞争的两方组成。其中一个试图愚弄另一个,另一个试图避免这种欺骗。
双方是一个生成器和一个鉴别器,两个神经网络都试图以下列方式相互竞争:
- 生成器试图生成理想情况下看起来像真实内容的内容,通常可以是图像、文本或数字数据。如果鉴别器能够区分真实内容和生成的内容,则生成器会受到惩罚
- 鉴别器试图区分生成的内容和真实的内容。如果鉴别器不能区分真实内容和生成内容,它就会受到惩罚
最终目标是让生成器能够生成看起来非常接近真实数据的数据,以至于鉴别器无法再避免欺骗,这给我们留下了比开始时更多的数据。
(重构)来自谷歌开发页面的框图
5.使用 ydata-synthetic 生成数据
ydata-synthetic 是一个用于生成合成数据的开源库。目前,它支持创建常规的表格数据,以及基于时间序列的数据。在本文中,我们将快速查看如何生成表格数据集。更具体地说,我们将使用信用卡欺诈检测数据集并生成更多数据示例。在 ydata-synthetic 的存储库上提供了一个示例笔记本,可以在 Google Colab 中打开并跟随,以便基于信用卡数据集合成一个表格数据集。
让我们读取数据集,看看这个特定的数据集由哪些列组成
我们得到以下列:
Dataset columns: ['V1', 'V2', 'V3', 'V4', 'V5', 'V6', 'V7', 'V8', 'V9', 'V10', 'V11', 'V12', 'V13', 'V14', 'V15', 'V16', 'V17', 'V18', 'V19', 'V20', 'V21', 'V22', 'V23', 'V24', 'V25', 'V26', 'V27', 'V28', 'Amount', 'Class']
暂时不涉及太多特定领域的细节,这些基本上是描述信用卡交易的特性。数据集中有一个名为“Class”的最后一列,如果存在欺诈,该列的值为 1,否则为 0。与非欺诈案例相比,该数据集中的欺诈案例实际上非常少,我们希望增加欺诈案例的数据集。
因此,我们只从数据集中提取那些类别为 1 的条目,即欺诈值。然后,我们应用幂变换,以使分布类似高斯。
然后,我们可以继续训练我们的 GAN 模型,使其学习和了解欺诈值。对于这个例子,我们将使用一种特定类型的 GAN 模型,称为 WGAN-GP(wasser stein GAN with Gradient Penalty)。超参数和训练设置以列表的形式定义,并提供给我们的模型进行训练。
最后,我们实际上可以从训练好的模型中生成数据,方法是给它一个随机值矩阵作为开始。
为了可视化和比较生成的输出,我们从 g_z 中选取任意两列(比如 V10 和 V17 ),并为多个时期的训练权重绘制散点图。
实际输出和 GAN 输出的比较
因此,我们看到 V17 和 V10 的值在我们的原始数据集中有一个模式(“实际欺诈数据”,左图),GAN 试图在训练和预测过程中学习并尽可能复制该模式。在第 60 个历元结束时,V17 和 V10(以及其他特征)的最终值在一定程度上类似于原始数据集的值。
完整的实践演练可以在 Google Colab 笔记本中从 ydata-synthetic 存储库中找到,之前也有链接。
6.结论,接下来呢?
我们根据我们的用例和最终目标来考虑生成合成数据的需求。我们简要介绍了 GAN 架构,还利用 ydata-synthetic 生成了表格数据。在以后的文章中,我们还可以探索生成时间序列数据的可能性。
用熊猫快速生成假数据
小窍门
最后,以一种平稳、无痛苦的方式
作者图片
你可能因为各种各样的原因而最终阅读了这篇文章。如果你认为这篇文章是关于强迫熊猫用电脑做黑客的事情,请关闭这个标签,继续你的工作。你在帮你自己。这从未发生过。
对于你们这些书呆子和离不开熊猫的数据科学家来说,今天可能是你们的幸运日。思考下面的问题:你有多少次手工创建一个小的数据框架来测试你正在开发的新代码?建立一个假数据集来快速测试一个机器学习模型怎么样?如果你和我一样,大概也有不少次吧。它通常看起来像这样:
**import** pandas as pddata **=** {'Name':['Tom', 'Brad', 'Kyle', 'Jerry'],
'Age':[20, 21, 19, 18],
'Height' : [6.1, 5.9, 6.0, 6.1]
}
df **=** pd.DataFrame(data)
写这些行需要一点时间,结果是一个很小的 4x3 数据帧。我感觉你在那里,很痛苦。你认为你的宝贵时间应该用于更有价值的任务,我完全同意。这就是为什么我想向你介绍这段简短的代码,它可以帮助你找回属于你的东西。请不要看,复制粘贴到你的编辑器里就可以了(如果你信任我的话)。最好通过运行下面的例子来理解它是如何工作的。不管怎样,它来了:
一堆例子
那么你如何用它来生成东西呢?很简单,你可以这样:
generate_fake_dataframe(size = 1000, cols = "cififficcd")
并生成:
作者图片
size 参数显然是行数。cols = 'cififficcd'
没那么直白。它只是让您控制想要生成的列的类型和顺序,包括以下选项:
- c :用于包含分类变量的列。
- i :生成一列整数。
- f :返回一个带有浮点数的列。
- d :用于有日期值的列。
您可以看到这些列是如何按照以下模式命名的:column_n_dtype
。关于类别特征,我们看到**column_0_cat**
填名字, **column_7_cat**
有动物,**column_8_cat**
有城市名。还有一系列分类特征(“颜色”),可以通过编辑categories_dict
添加更多。每个家族都有 15 个用于填充分类列的独特类别。
这里还有两个例子,df1 和 df2:
df1 和 df2 —作者图片
好的,有一些新的参数。**col_names**
接受一个列表,其中包含您想要为列指定的名称,以防您不想要遵循column_n_dtype
模式的列。当然,它应该与cols
字符串的长度相同。**seed**
参数控制随机数发生器,如果其他参数保持不变,您可以重现相同的结果。如果未设置(或设置为 None ),每次调用该函数时,将输出不同的数据帧。最后,还有**intervals**
参数,它允许微调每个列的生成方式。
当您不向 intervals 传递任何东西时,每个列类型都会生成一个默认配置。整数值默认均匀分布在区间 (0,10),浮点数 get (0,100) 默认,日期在(“2020–01–01”、“2020–12–31”)之间生成。默认情况下,类别值由 "names" 系列的 5 元素生成,如果有多个类别列,则选择其他系列。
设置自定义间隔
如果每个数据类型的默认配置不符合您的需要,您可以通过 intervals 参数来更改它。您可能已经注意到了用于生成 df1 和 df2 的代码中的一些“不一致”。在 df1 中,我们将一个字典传递给 intervals 参数,在 df2 中,它是一个列表。这是为什么呢?嗯,我们可以使用字典来指定一个配置,该配置将影响所有相同类型的列。例如,我们可以将间隔设置为:****
intervals = {"d" : ("1996-01-01","1996-12-31"),
"c" : ("colors" , 7)}
然后,我们将覆盖日期列(" d")** 的默认配置,它现在将始终包含这些日期之间的值,并且覆盖分类列(" c "),的默认配置,它现在将始终从 colors 族的 7 个不同值中进行选择(而不是 names 族的 5 个)。intervals 参数中不存在的列类型将保留其默认配置。**
因此,为了澄清,如果我们调用generate_fake_dataframe(20, “cccd", intervals = {"c" : ("colors",7)})
,我们将得到一个数据帧,其中有 3 个分类列,每个列最多有 7 种不同的颜色,还有一个默认配置的日期列。
另一方面,我们可以向区间传递一个列表,而不是一个字典。当我们想要更多的控制时,也就是说,当我们想要为每个单独的列进行特定的配置时,我们就这样做。列表的第I 个元素包含了我们想要分配给第I 列的区间。让我们仔细看看用于创建 df2 的间隔。****
cols = "cicffcd",
intervals = [("names",10), (18,25),("cities", 15), (73.2,95.0), (1.65,1.95), ("animals", 11), None]
我们在cols
中看到,我们有 7 列,intervals 列表包含 7 个引用每一列的元素。当然,根据列的类型,每个区间元组应该有适当的格式(如果我们把("names", 15)
替换成(13,20)
,函数会抛出一个错误,因为第一列被设置为“c”,即分类)。有了这个区间配置,我们就可以想多具体就多具体。第一列包含 10 种不同类型中的名称;第二,18 到 25 之间的整数;第三,15 个选项中的城市,等等。最后一列设置为 None,这意味着对于该列,我们希望使用默认间隔。
我袖子里还有一张牌…
关于generate_fake_dataframe
,还有一个技巧我还没有告诉你,它是关于在分类列中引入自定义类别族的。我们说过所有的区间都应该定义为一个二元元组,不管它的 (int,int),(float,float),(date,date) 还是 (category_family,number_of_elements)。嗯,这并不完全正确,有一个,而且只有一个例外。对于分类列,我们可以用一个对象列表来替换(family,n)元组,我们希望从这个列表中填充列。让我再给你看两个例子:
作者图片
注意,对于 df3 中的第三和第四列,我们传递的不是元组,而是元素列表(可能的技能列表,以及包含真和假的列表)。这对于 df4 中的字典也非常适用。我们可以从包含[0,1]的列表中设置所有分类列。
包扎
我希望这篇文章对您有用,并随时将generate_fake_dataframe
添加到您的工具箱中。我已经斗胆打开了一个关于熊猫的拉请求,看看这是否有可能包含在未来的版本中。目前存在的替代方案(pd.util.testing.makeDataFrame
和 pd.util.testing.makeMissingDataframe
)并没有真正完成任务。还有其他像 Faker 这样的库,具有更丰富的数据类型,但不是为输出数据帧而设计的( afaik )。所以我坚信熊猫有这个空间。
在此之前,可能需要做许多更改和改进,修改代码以遵循 pandas 自己的准则,重写代码以提高清晰度,重命名一些参数(甚至函数名本身)等等...如果你想把这个包含在熊猫里或者有什么建议,请在 公关讨论 中畅所欲言。如有任何查询,你可以打电话到 juanluis.rto@gmail.com 找我
用 Python 生成假数据
使用 Faker 和 Numpy 创建假数据集
克里斯·利维拉尼在 Unsplash上的照片
数据分析的第一步是找到要分析的数据。
很多时候,这关键的第一步几乎是不可能的。满足我们需求的数据可能是专有的、昂贵的、难以收集的,或者根本不存在。
当我想尝试一个新的库或技术,或者开始写一篇新文章时,找到一个合适的数据集是我面临的最常见的问题。
在这里,我们通过创建自己的数据集来彻底解决这个问题!
小部件工厂
在这里,我们将为一个虚构的小部件工厂创建一个数据集。
我们的部件工厂有员工,他们的唯一工作就是制造部件。工厂通过统计生产的部件数量和工人的生产速度来监控部件生产效率。制作微件包括三个步骤,所有步骤都由微件监控系统计时。
让我们开始制作我们的假部件工厂数据集吧!
骗子
我们可以使用惊人的包, Faker 来开始。Faker 自我描述为“一个为你生成虚假数据的 Python 包。”
Faker 可在 PYPI 上获得,并可通过pip install faker
轻松安装。
让我们初始化一个 faker 生成器,并开始制作一些数据:
# initialize a generator
fake = Faker()#create some fake data
print(fake.name())
print(fake.date_between(start_date='-30y', end_date='today'))
print(fake.color_name())>>> Bruce Clark
>>> 1996-08-24
>>> LimeGreen
Faker 还有一个方法可以快速生成假的个人资料!
print(fake.profile()>>> { 'address': '56393 Steve Lock\nNew Paul, FL 14937',
>>> 'birthdate': datetime.date(1968, 1, 2),
>>> 'blood_group': 'O+',
>>> 'company': 'Hernandez, Keller and Montes',
>>> 'current_location': (Decimal('66.6508355'),
>>> Decimal('54.569691')),
>>> 'job': 'Museum education officer',
>>> 'mail': 'levyjoan@yahoo.com',
>>> 'name': 'Kim Stephens',
>>> 'residence': '0248 Patricia Street
>>> Apt. 507\nEast Dustin, WV 65366',
>>> 'sex': 'F',
>>> 'ssn': '248-78-5827',
>>> 'username': 'ruizdavid',
>>> 'website': ['[https://www.garcia-garza.org/](https://www.garcia-garza.org/)',
>>> '[https://www.williamson.info/](https://www.williamson.info/)']}
虽然这很酷,但对我们的小部件工厂来说还不是很有帮助。
我们需要为每个元素创建多个示例。我们可以通过列表理解来做到这一点:
# create a list of color names
colors = [fake.color_name() for x in range(4)]
print(colors)>>> ['LightCoral', 'Yellow', 'WhiteSmoke', 'LightGray']
现在我们有进展了!profile 方法为每个工人提供了比我们需要的多一点的信息——我们的小部件工厂保留了每个工人的最少记录!
让我们开始创建一个工人的数据框架,只包含我们感兴趣的信息。我们将使用 list comprehension 来生成一个包含员工姓名和雇佣日期的员工信息字典:
fake_workers = [
{'Worker Name':fake.name(),
'Hire Date':fake.date_between(start_date='-30y', end_date='today')
} for x in range(10)]
print(fake_workers)
包含姓名和雇用日期的员工字典
这是一个很好的开始!但是,如果我们想将每个工人分配到一个团队中去呢?如果我们只是使用 Faker,我们会有大量的团队,每个团队可能只有一个工人。
假设我们想要创建四个团队,并在他们之间平均分配工人。我们可以使用 NumPy 的随机采样来完成这个任务。
numpy.random
Numpy 的随机采样模块包含许多生成伪随机数的方法。在这里,我们将探索几个可用的选项。
我们可以使用numpy.random.choice
从我们用上面的 Faker 创建的颜色列表中随机选择一种颜色:
# numpys random choice to select a color from our colors list
np.random.choice(colors)>>> Yellow
单独来说,这不是非常有用,因为我们只有一种随机选择的颜色。让我们\使用列表理解随机选择几种颜色:
# generate an array of colors with a list comprehension
[np.random.choice(colors) for x in range(5)]>>> ['WhiteSmoke',
>>> 'WhiteSmoke',
>>> 'Yellow',
>>> 'WhiteSmoke',
>>> 'LightGray']
现在我们有进展了!如果我们想从颜色列表中选择不同概率的颜色呢?
numpy.random.choice
带一个可选参数p
,它允许我们指定每一项的概率。(当 p 未指定时,假设为均匀分布。)
让我们指定颜色的概率:
# generate an array of colors with differing probabilities
[np.random.choice(colors, p=[0.1, 0.6, 0.1, 0.2]) for x in range(10)]>>>['LightGray',
>>> 'LightCoral',
>>> 'LightGray',
>>> 'LightGray',
>>> 'LightCoral',
>>> 'WhiteSmoke',
>>> 'Yellow',
>>> 'Yellow',
>>> 'Yellow',
>>> 'Yellow']
我们可以看到黄色和浅灰色在输出中更常见!由于样本量小,分布并不完全符合规定。我们需要增加样本量来接近我们指定的概率。
我们还可以基于指定的分布生成数据。这里,我们随机生成几个分布,并用直方图可视化:
# generate normal distribution
normal_dist = np.random.normal(loc=5, scale=1, size=1000)# generate gamma distribution
gamma_dist = np.random.gamma(shape=3, scale=1, size=1000)# generate exponential distribution
exp_dist = np.random.exponential(scale=4, size=1000)# histograms to visualize the distributions
fig, [ax1, ax2, ax3] = plt.subplots(1,3)
ax1.hist(normal_dist)
ax1.set_title('Normal Distribution')ax2.hist(gamma_dist)
ax2.set_title('Gamma Distribution')ax3.hist(exp_dist)
ax3.set_title('Exponential Distribution')plt.show()
随机生成的分布直方图
这些看起来不错!让我们把所有东西放在一起,创建我们的假部件工厂数据集!
把所有的放在一起
我们将创建两个数据帧:一个用于工人数据,一个用于小部件数据。
我们将使用 Faker、Numpy 和 list comprehensions 创建一个包含员工 id、姓名、雇佣日期、状态和团队的员工花名册数据集。
首先,我们创建一个函数,make_workers()
。该函数将接受一个参数num
,它将代表要生成的雇员数量。
我们使用np.random.choice
将每个员工分配到一个团队,使用默认的统一分布,并通过指定概率将每个员工分配到全职、兼职或每日津贴状态。
使用 Faker 和 Numpy 生成的假工人数据示例
这看起来棒极了!现在让我们创建一些小部件数据。
我们将开始使用内置的[id()](https://docs.python.org/3/library/functions.html#id)
方法为每个小部件随机分配一个项目编号。
从文档中,id()
返回对象的“身份”。这是一个整数,保证在这个对象的生命周期内是唯一和恒定的”。因为我们每次调用make_widget_data()
函数时都在同一范围内迭代,所以我们将创建重复的项目编号。为了解决这个问题,我们将工人 id 附加到项目编号上,以保证唯一性。
接下来,我们将假设在小部件创建中有三个步骤。对于每个步骤,我们将生成一个不同的随机分布,该分布将表示完成该步骤所花费的时间。
接下来,我们假设员工并不都以相同的速度工作——全职员工比兼职员工完成更多的小部件。
为了在数据中反映这一点,我们迭代上面创建的 worker_df,并根据每个工人的状态随机选择他们创建的一些小部件。
我们将创建一个空列表来存储每个工作小部件的数据帧,然后最终将数据帧列表连接成一个最终的小部件数据帧:
使用 Faker 和 Numpy 生成的虚假小部件数据
小部件工厂的工人很忙!他们创建了 2817285 个小部件!
最后,我们可以保存我们的数据集,用于未来的分析:
worker_df.to_csv('data/workers.csv', index=False)
widget_df.to_csv('data/widgets.csv', index=False)
结论
在这里,我们探索了 Python 包 Faker 和 Numpy 的随机采样模块。
Faker 可以很容易地生成各种各样的数据,包括姓名、地址和日期。
Numpy 的随机抽样模块允许我们生成特定的分布,并从列表中伪随机选择项目。
我们能够为一个想象中的小部件工厂生成假数据。我们创建了两个数据集,一个包含工作人员详细信息,另一个包含小部件创建数据。
在未来的文章中,我们将探索这些假数据,执行探索性分析,并为小部件管理器生成报告。
使用 Google Maps API 生成地理编码
地理空间分析。数据科学。ANALYTICS.PYTHON
使用 Python 快速获取地址的地理编码
介绍
地理编码是将文本地址转换为地理纬度和经度坐标的过程,这反过来使得操纵和分析大量地理空间数据变得容易。
对于数据科学家来说,了解地理编码有助于以可视化方式绘制地理编码并创建其他要素,例如两点之间的距离和时差。
与其他类型的数据不同,地理空间数据极大地受益于可视化,因为它使邻域或本地网络中模式的出现变得明显。
因此,企业从使用它中获利,但如果该过程涉及手动获取地理编码,则不会。
虽然这个过程可以使用开源包来完成, OpenStreetMap, Google Maps API 可能会为更广泛的地址生成更准确的数据。
在本文中,让我们研究如何通过 Python 和 Google Maps API 获得这些地理编码,以加速我们的数据项目。
初步:谷歌 API 密钥
使用谷歌地图 API 是要收费的,数据科学家在使用它之前需要了解价格。
为了使用 google maps API,我们需要生成自己的 API 键来使用它。
第 1 步—转到谷歌开发者控制台
您将在这里看到您的仪表板。
步骤 2 —创建新项目
作者准备的 GIF
要创建一个新项目,请遵循上面的 GIF。右上角有一个“选择一个项目”的文本。命名项目以更好地管理当前和未来涉及 Google APIs 的项目。
步骤 3-启用谷歌地理编码
作者准备的 GIF
浏览 API 库以启用地理编码服务。这被命名为“地理编码 API”。
步骤 4 —创建凭据以生成 API 密钥
作者准备的 GIF
启用地理编码 API 服务后,转到凭证选项卡并选择“+创建凭证”。创建 API 密钥后,将其复制到 Python 代码中使用。
您可以重命名 API 并对其进行限制,以确保其安全。对于每个 API 键(铅笔符号),在“API 键”表下有一个编辑选项来完成此操作。
用于地理编码的 PYTHON 代码
要使用 API 密钥,请确保您已经安装了googlemaps
包:
pip install googlemaps
步骤 1 —将 GOOGLE MAPS API 密钥存储为变量
import googlemaps#Set Google MAPS API_Key
g_API = "API-Key Copied"gmaps_key = googlemaps.Client(key=g_API)
步骤 2-遍历地址并获取地理编码
在我们的练习中,让我们创建假地址来使用我们的代码:
from faker import Faker
import pandas as pdfake = Faker()df = pd.DataFrame(data=[fake.address().replace('\n', " ") for i in range(100)], columns=["address"])# Create columns to store longitude and lattitudedf["longitude"] = None
df["latitude"] = Nonefor i in df.index:
geocode_obj = gmaps_key.geocode(df.loc[i, "address"])
try:
lat = geocode_obj[0]['geometry']['location']['lat']
lon = geocode_obj[0]['geometry']['location']['lng']
df.loc[i,'latitude'] = lat
df.loc[i,'longitude'] = lon
except:
lat = None
lon = None
瞧,我们完成了!
图片由作者提供。
结束语
地理编码很重要,因为它允许计算机理解我们的参考点。这意味着,有了地理编码,分析和地理空间可视化(geovisualization)成为可能。除此之外,地理编码是独一无二的。
使用我们上面的方法是为我们的地址对象生成地理编码的最快和最可靠的方法之一。但是,有些地址偶尔会显示“无”,因此需要手动检查。然而,根据经验,当地址变量是干净的时,这种情况很少发生,所以在运行上面的代码之前,我们可能想看看我们是如何生成数据的。
查看我的其他与此相关的文章:
使用谷歌地图应用编程接口和树叶在菲律宾绘制你最喜欢的咖啡店地图
让我知道你的想法!
通过文本分析和 GPT-3 产生想法
文本分析通常用于分类任务。然而,我们可以利用对文本结构和内容的洞察,为任何话语产生相关的研究问题和想法。这里是你如何使用 GPT-3 的一点点帮助(如果需要的话)使用 InfraNodus 文本分析工具来做到这一点。
使用文本网络分析工具,如 InfraNodus,我们可以可视化文本的结构,以揭示话语中存在的差距。用研究问题和假设弥合这些差距将产生新的相关想法,因为它们触及相关主题,并提出它们之间的新联系。
新想法=新联系
最令人兴奋的情绪之一是当一个新的想法出现时。这种“灵光一现”的时刻,事情突然以一种前所未有的方式联系起来,通常会带来顿悟和新的理解。有趣的是,这个看似难以捉摸的创作过程实际上可以在文本分析、网络科学的帮助下,以及 GPT-3 人工智能语言生成工具(如 OpenAI 的 Playground(或 API),Copy)的一些帮助下“按需”执行。艾,或者贾维斯。
一个想法永远不会凭空出现。总会和某件事有关。如果我们用语言来思考,一个想法会把已经存在的概念联系起来。一个新的想法是一种从未有过的联系。
一个话语可以表示为一个网络,其中****概念是节点,和它们的同现是它们之间的连接。这是像 LDA 这样久经考验的主题建模方法以及像 word2vec 这样的现代机器学习方法背后的原理。虽然这些模型可能很难直观地理解,但逻辑非常简单。单词一起出现的频率越高,它们在语义上就越接近。经常出现在话语路径上的词在网络中会更有影响力。这种方法在文本网络分析中使用,提供了这种工作原理的可视化表示:
使用 InfraNodus 制作的围绕“武术”话题的话语的文本网络可视化。这两个概念都从图中删除了,所以我们可以看到它们周围的环境。你可以在这里看到现场互动图。
在现有的话语中寻找新的联系
假设,我们想要了解更多关于某个主题的知识,比如武术,并生成一个相关的文本,同时提供一个新的视角。
首先,我们可以使用多种来源,从简单的谷歌搜索和维基文章开始,到关于该主题的科学出版物的文献综述或关于该主题的深度 SEO 分析。然而,在这种情况下,我们使用了来自** Reverso 的数据。Context —一个翻译和参考工具,显示使用某个概念的短语。**
使用 Reverso 这样的工具的好处在于,它不仅可以用于翻译,还可以用于研究特定查询的上下文。可能最强大的翻译应用 DeepL 是基于 Linguee 开发的,这并不是巧合,Linguee 是一种基于数十亿人工翻译数据库的类似工具。输入一个查询,您将看到使用该查询的短语。
上面显示的图表是当前围绕“武术”主题的话语的可视化,使用上述方法使用 InfraNodus 文本分析工具制作(在 InfraNodus 的白皮书中阅读更多关于其背后的科学)。使用此图表(探索交互式可视化,我们可以看到围绕“武术”主题有 4 个不同的主题群(全部用不同的颜色表示)😗***
- 日语、古代语、朝鲜语(地理和时间背景)
- 世界,体育,获得(武术作为一个世界范围的战斗现场)
- 发达,阶级,合气道,实践(武术作为一个战士/社会/实践)
- 太极,中文,气(内部武术,如太极)
这让我们很好地理解了当前围绕这一主题的讨论。
现在,我们如何增强这种话语?
这就是网络表示派上用场的地方。
这一论述中的一些概念比形成上述主题群的其他概念彼此更接近。然而,其中一些星团相距甚远。
如果我们确定了主题群和它们之间的结构间隙,我们就会找到当前话语中缺失的部分。然后,我们可以提出一个研究问题,或者提出一个可以弥合这些差距的假设。
因此,我们获得了一个与话语相关的新想法(因为它连接了已经存在的主题),但也是创新的,因为它提出了一个以前不存在的新连接。
我们可以手动或使用类似于 InfraNodus 的工具来完成这项工作,该工具具有“洞察”面板,可揭示话语中的结构差距:
太极(可能是为了健康和幸福而练习的)等内部武术的想法与武术作为战士练习的想法之间存在结构性差距。如果我们问一个问题或提出一个假设,将这些想法(话题群)联系在一起,我们将产生一个与这个特定话语相关的新想法。
在我们的特殊情况下,日本“武士/阶级练习”如“合气道”或“柔术”与中国内部练习如“太极”之间存在结构性差异。
因此,我们可以自己想出这两组主题之间的联系,提出一个有趣的想法,或者使用 InfraNodus 的基于 GPT-3 的研究问题生成工具来激发我们的想象力:
使用 InfraNodus 中的自然语言生成器,我们可以生成相关的研究问题,帮助我们进一步探索这个主题。
有趣的问题:“太极与中国的阶级制度有什么关系”**“合气道对气的发展有什么影响”——做的正是我们之前描述的:把之前没有联系起来的话题串起来。**
在这种情况下,不同之处在于,你不是在使用人工智能为你写作,而是问自己一些有趣的问题,这些问题可以帮助你推进你的想法。
基于这些问题,我们可以这样说:
“武术也可能是一种通过身体运动将某个阶级的传统写入历史的方式,突出某些方面和价值观,并确保它们不仅可以通过语言,还可以通过其他形式(如气的概念)通过时间传承。”
为了不打断原始的论述,我们将选择“解释”功能,在这里我们可以在现有图表的顶部进行书写。这让我们看到我们覆盖了多少当前话语,也让我们能够分别分析不同的话语:
在我们添加这个想法后,推荐系统检测到现在内容有变化,找到当前话语外围的主题,并建议进一步发展它,将它与文本内的相关概念链接起来:
InfraNodus 现在检测到外围的主题群,并建议链接到与一般话语更相关的另一个主题群。
在这种情况下,建议是考虑来自日本的不同舞蹈风格,并想象它们如何也是该国的文化(就像武术一样)。
这是一个非常相关和令人兴奋的问题,因为日本确实有多种舞蹈传统,如 Noh theater,但也有更现代的 Butoh 舞蹈,它实际上打破了传统,并提出了一种新的文化,这种文化不是社会编纂的,而是来自情感和精神身体。
把这个想法加到图表里。(我们已经覆盖的)灰色区域变得更大,InfraNodus 建议我们删除最流行的术语,看看它们背后隐藏着什么:
在某一点上, InfraNodus 会建议你删除最流行的节点,这样你就可以看到隐藏在它们背后的内容。这将有助于你将注意力集中在文章/话语中不太成熟的概念上。
在我们从图表中删除这些节点后,我们可以重新生成研究问题,这些问题现在将帮助我们探索较少被代表的概念和主题(尚未以灰色覆盖),例如日本和中国文化之间的差异,以及如何通过武术练习反映出来:
在我们移除了更受欢迎的话题后,我们将注意力集中在代表性较低的话题上,将我们引向不一定与“武术”概念相关的研究问题,但事实上,这些问题可以以一种非常有趣的方式对话语做出贡献(例如,国家之间的文化差异如何通过武术练习表达出来)
之后,我们可以跟随 InfraNodus insight 推荐系统,在图表中导航,一路生成研究问题:
另一个发现的结构性缺口可以用新的想法来弥补。
这个过程重复了无数次,也使用了多种话语来源(更多细节见我们关于文本分析的案例研究)。
基本工作流程是:
- 找到结构差距(使用图表、洞察推荐器或分析>洞察面板)
- 查看尚未连接的主题集群
- 想一个能以新的方式连接这些集群的问题
- 写下你想法或假设
- 图表和统计数据将重新加载,新的结构性缺口将被识别。
- 重申
- 从图中删除最受欢迎的节点,看看新的命题
- 将删除的节点放回图中。
- 为你的主题添加更多的数据源(例如,科学研究,谷歌搜索结果)
- 比较您创建的不同图表,找出它们之间的差距。
最后,一旦你完成了,你可以导出你的文本来编辑它,并在你选择的文本编辑器中进行最后的润色。
在我们的案例中,作为探索“武术”理念的过程的结果,我们得出了一个有趣的结论,这是我们参与的一个艺术项目的一个组成部分,该项目将编舞、技术和武术联系在一起。然后我们将结论导出为文本,编辑语法和风格,并作为一篇文章发布在我们项目 8os.io 的网站上。
如你所见,对话语的结构性洞察可以提供关于缺失部分的无价信息。利用我们的创造力(在 AI 的帮助下:)我们可以提出一些有趣的想法,这些想法可以增强现有的话语,并带来一些新的东西。
这里的优势在于,我们的方法还将通过视觉网络界面揭示它正在做什么的逻辑——这是我们今天经常遇到的许多基于人工智能的黑匣子所缺少的。
另一个优势是,你不是用人工智能取代你自己的大脑,而是将人工智能用作智能对话伙伴,帮助你提出正确的问题,帮助你探索想法和学习新的东西。
附言(同 postscript);警官(police sergeant)
如果不对这篇文章进行同样的处理,那就不公平了,所以我们开始吧:
正如我们所看到的,系统提出了一个需要进一步探索的研究问题:武术如何成为一种自我保健的形式?**
有趣的是,也许这是一个全新讨论武术的话题,不仅关注自卫和传承传统,还关注自我护理和治疗实践的想法。
如果你喜欢这种方法,你可以用自己的文本和想法在【InfraNodus.Com】上尝试一下。如果您想激活** GPT-3 研究问题生成器,您可以 联系我们(通过 Twitter@ noduslabs或 直接)——我们将很高兴地向所有致力于数据科学的读者开放!****
使用 CLIP 和 StyleGAN 从提示生成图像
读完这篇文章你会知道…
- CLIP 如何工作一目了然。
- StyleGAN 工作原理一览。
- …如何将它们组合起来,根据提示生成面。
你可以在这里找到这篇文章中使用的代码。
夹子
对比语言——图像预训练 (剪辑)——呈现于从自然语言监督中学习可转移视觉模型——由 OpenAI 于 2021 年 1 月出版。他们的方法提出利用自然语言来提高图像分类任务的深度学习模型的通用性和鲁棒性。他们能够在零射击设置的情况下,在多个基准测试中产生最先进的性能,这确实令人印象深刻。
CLIP 背后的主要思想是预先训练一个神经语言模型和一个图像分类模型,联合使用从互联网上提取的大量图像数据及其各自的标题。在下图中,“文本编码器”代表语言模型,“图像编码器”代表图像分类模型。
图片来自 OpenAI 的原博客。
他们的目标是构建一个矩阵,其中每个值代表每个提示图像对之间的相似性得分——在图像中计算为 I * T——并使用它来训练语言和视觉模型,以便它们最大化对应于正确对的位置的值,即图像中的对角线值。例如,如果位置 0 处的文本是“pepper the aussie pup ”,而位置 0 处的图像表示该特定内容,则 CLIP 将训练这两个模型来创建最大化其相似性的表示。
一旦该预训练过程完成,他们可以使用预训练的视觉模型来生成任何给定输入图像的表示,并将其与使用语言模型从几个提示获得的几个文本嵌入进行比较。具有最大相似性值的文本表示将被选为更好地表示图像内容的文本表示。使用这种技术,您可以使用 ImageNet 的一千个类别作为句子,并在零镜头设置中解决分类任务。
以下是模型如何在给定这组提示的情况下成功分类图像的一些示例。
图片来自 OpenAI 的原博客。
图片来自 OpenAI 的原博客。
StyleGAN
StyleGAN 是一个著名的生成对抗网络模型,能够生成高分辨率的超逼真图像。下面是这个模型的结构。
图片来源于 StyleGAN 报。
从这个模型中主要得到的是,给定一个潜在向量 z ,我们可以使用映射网络来生成另一个潜在向量 w ,它可以被馈送到合成网络中,并产生最终的图像。出于我们的目的,我们将使用一个经过训练的 StyleGAN 来生成人脸。
根据提示生成图像
下面是我使用 CLIP 和 StyleGAN 从提示中生成人脸的架构。
图片作者。
这个想法很简单,我们将从 StyleGAN 的 w 潜在向量的随机值开始生成一幅图像。结果将与任意提示一起传递给 CLIP。CLIP 将生成一个分数,表示该图像在提示中表现内容的程度。该值将用于更新 w ,这将生成另一个图像,该图像将反复重复该循环,直到我们确定生成的图像与提示足够相似。
编辑:将使用梯度下降和反向传播更新 w 的值,如同它们是神经网络中的权重。
结果
以下是使用这种简单方法获得的一些结果。
“一个有着金发紫眼的女人的脸的图像”
图片作者。
“一张埃隆·马斯克的脸和一头金发的照片”
图片作者。
最后,为了给这个模型带来一些乐趣:
"一张瘾君子的脸"
图片作者。
有趣的是,前一个提示符的最终结果出现在下图中——这种应变可能是好的!
图片作者。
你可以在我的推特账号上找到更多的样本。
结论
语言模型的力量不仅限于文本问题。他们从大量数据中提取概念的能力可以扩展到其他领域,并产生令人惊讶的结果,就像本文中介绍的那样,而且方法非常简单!
在看到像 GPT-3 这样的模型后,想想计算机视觉领域将会出现什么是令人兴奋的。
使用 Python Pandas 生成模拟销售数据
数据科学的一切都是从数据开始的
数据科学生态系统中有几个软件工具和软件包。这些工具加速了日常流程,并帮助我们管理、探索和分析数据。
无论您使用什么工具,无论您从事什么项目,数据科学中的一切都始于数据。没有适当的数据,您的数据产品很可能会失败。
在学习数据科学和实践软件工具时,寻找数据来玩有时会成为一个挑战。虽然网上有一些免费的数据资源,但它们可能并不总是符合你的需求。
在本文中,我们将使用 Pandas 库生成模拟销售数据。该数据将包含一家连锁店的每日销售数据。我们将使用随机数来分配商店和产品的销售值。
数据可能无法展示在现实生活销售数据中可以观察到的典型特征,如季节性或趋势。但是,您可以用它来练习许多工具和技术。
此外,在生成数据时,我们将使用几个 Pandas 函数和方法。因此,这对熊猫来说也是一个很好的练习。
您将有机会练习以下主题:
- 如何创建熊猫数据框
- 创建 NumPy 数组的不同方法
- 取数组和列表的笛卡尔积
- 合并熊猫数据框
- 用熊猫创建线形图
让我们从导入所需的库开始。
import numpy as np
import pandas as pd
from random import shuffle
Python 随机包中的洗牌模块可以用来洗牌。
下一步是创建商店和产品代码。
store_codes = np.arange(1,10)
product_codes = np.arange(1,101)
商店代码从 1 开始,一直到 9。我们有 100 种产品,从 1 开始,一直到 100。
我们还需要一个日期范围,因为这是一个时间序列数据。有许多不同的方法来执行这项任务。我会用熊猫的 date_range 函数。
date_range = pd.date_range(start = "2019-01-01", end = "2020-12-31", freq="D")
我们的产品系列涵盖了两年的时间。freq 参数用于确定增量大小。“D”代表日,因此我们将拥有 2019 年和 2020 年的每日销售数据。
我们有 2 年的时间,9 家商店,100 种产品。每天,我们的数据将包含每个产品-商店对的销售额。因此,我们需要生成日期范围、商店代码和产品代码数组的笛卡尔乘积。
一种方法是通过取这些数组的笛卡尔积来创建一个多重索引。然后,我们可以使用它来创建数据框。
index = pd.MultiIndex.from_product(
[date_range, store_codes, product_codes],
names = ["Date", "StoreCode", "ProductCode"]
)sales = pd.DataFrame(index = index)sales.head()
(图片由作者提供)
这是销售数据框架的索引。为了从这个多索引创建列,我们只需要使用 reset_index 函数。
sales.reset_index(inplace=True)sales.head()
(图片由作者提供)
销售数据框包含每个日期、商店代码和产品代码组合的一行。因此,行数应该等于每个数组中项目数的乘积。
len(sales) == len(store_codes) * len(product_codes) * len(date_range)
Truelen(sales)
657900
我们刚刚证实了我们的预期。我们有一个 657k 行的数据帧。
在零售业中,对商店和产品进行分组是一种常见的做法。让我们从商店开始。
store_groups = ["Small","Medium","Large"]*3
shuffle(store_groups)stores = pd.DataFrame({
"StoreCode": np.arange(1,10),
"StoreGroup": store_groups
})stores
商店组(作者图片)
由于有 9 家商店,我们创建了一个包含 9 个元素的列表,分为 3 个类别。shuffle 函数在适当的位置打乱这个列表。否则,将保留基本列表的顺序。
我们可以类似地分配产品组。
product_groups = ["A","B","C","D"] * 25
shuffle(product_groups)products = pd.DataFrame({
"ProductCode": np.arange(1,101),
"ProductGroup": product_groups
})products.head()
产品组(图片由作者提供)
我们有 100 种不同的产品代码,分为 4 类。
我们可能需要分析不同商店和产品组的销售业绩。因此,这些类别需要合并到销售数据框架中。
熊猫的合并功能可以用来完成这个任务。
sales = pd.merge(sales, stores, on="StoreCode", how="left")sales = pd.merge(sales, products, on="ProductCode", how="left")sales.head()
销售数据框(作者图片)
我们已经到了数据生成的最后一步,我认为这是最重要的一步。我们需要增加销售额。
你的选择是无限的。一个简单的方法是用随机整数创建一个 NumPy 数组,并将其添加到销售数据框架中。
size = len(sales)sales_amount = np.random.randint(0, 50, size=len(sales))sales["SalesAmount"] = sales_amountsales.head()
销售数据框(作者图片)
“销售额”列由 0 到 50 之间的随机整数组成。这完全是随机的,所以我们无法观察到我们销售的任何趋势或季节性。
您可以使用 to_csv 函数将此数据框保存为 csv 文件:
sales.to_csv("mock_sales.csv", header=True, index=False)
让我们通过绘制一个产品商店对的销售额来检查一下。下面的代码创建了一个特定对在过去两个月的销售额的折线图。
sales[
(sales.StoreCode==1) &
(sales.ProductCode==5) &
(sales.Date > "2020-11-01")
].plot(x="Date", y="SalesAmount", kind="line", figsize=(10,6))
(图片由作者提供)
我们可以清楚地观察到销售额的随机性。
结论
在创造销售额时,我们可以更有创意一点。一些随机噪声或季节性可以添加到这些值中。我把那部分留给你。
我们有模拟销售数据,但我们还没有对它进行任何探索性的数据分析。这将是下一篇文章的主题。敬请期待!
感谢您的阅读。如果您有任何反馈,请告诉我。
用 TigerGraph 从一篇文章中生成选择题
如何使用 TigerGraph 生成选择题
注意:在这篇博客中,我们将使用在这篇博客中创建的图表。
概观
我最喜欢的为考试和测验学习的方法之一是制作练习题和/或虚拟抽认卡。然而,提出问题通常是乏味的,而且会占用我大部分时间。因此,我认为根据一篇文章自动创建问题的过程会有所帮助。当然,我能够利用图形数据库的力量把它们放在一起。所以,让我们开始讨论如何去做吧!
第一部分:连接到您的图表
第一步:开始你的解决方案
首先,如果您的解决方案尚未启动,您需要启动它。为此,请前往 https://tgcloud.io/的并导航至“我的解决方案”选项卡。然后按下“动作”下的方框,并按下“开始”按钮。
注意:这可能需要几分钟来加载。
一旦你在状态下得到“准备好”,那么你就准备好继续前进了!
第二步:连接到您的解决方案
接下来,导航到一个 Google Colab 笔记本。
https://colab.research.google.com/
首先,安装并导入 pyTigerGraph。
!pip install pyTigerGraphimport pyTigerGraph as tg
接下来,创建您的 TigerGraphConnection。在参数中,传递您在创建解决方案时设置的子域和密码。图形名称将是我们之前设置的(NotesGraph ),然后我们将生成一个 API 令牌。
注意:从 7 月 28 日起,你需要包含一个 beta=True 来运行它。在未来的 pyTigerGraph 版本中,这种情况可能会有所改变。
conn = tg.TigerGraphConnection(host="https://SUBDOMAIN.i.tgcloud.io/", password="PASSWORD", graphname="NotesGraph", beta=True)conn.apiToken = conn.getToken(conn.createSecret())
太好了!现在我们已经准备好编写查询了!
第二部分:创建完整图表的问答
这里,我们将编写几个问题来生成一些查询。
查询 I:查找选项
我们将创建的第一个查询将为一个问题查找其他多项选择选项。在过去的博客中,我们用 SpaCy 来标识每个词的“类型”;我们将使用这种类型来获取相同或相似类型的单词。
conn.gsql('''USE GRAPH NotesGraphDROP QUERY findOptionsCREATE QUERY findOptions(Vertex<Entity_Name> word) FOR GRAPH NotesGraph {Seed = {word};Res = SELECT tgt FROM Seed:s - (ENTITY_NAME_ENTITY:e) - Entity:tgt;Options = SELECT tgt FROM Res:s - (ENTITY_NAME_ENTITY:e) - Entity_Name:tgt
WHERE word.entity_name != tgt.entity_name;PRINT Options;PRINT Seed;}INSTALL QUERY findOptions''')
我们来分析一下。在标题中,我们接受一个顶点实体名称的输入。
CREATE QUERY findOptions(Vertex<Entity_Name> word) FOR GRAPH NotesGraph
我们将使用输入作为种子,或者我们开始的地方。
Seed = {word};
接下来,我们将缩小以获取实体顶点。
Res = SELECT tgt FROM Seed:s - (ENTITY_NAME_ENTITY:e) - Entity:tgt;
然后,我们将找到连接到实体的其他实体名称顶点,不包括实体名称本身。
Options = SELECT tgt FROM Res:s - (ENTITY_NAME_ENTITY:e) - Entity_Name:tgt
WHERE word.entity_name != tgt.entity_name;
最后,我们将打印出选项和输入。
PRINT Options;PRINT Seed;
而且完美!这将返回选项和输入的值。
总之,该查询将从任何文档中获取任何相似的潜在答案选择。稍后,我们将筛选答案选项,以防有人只想研究一个文件夹或一个文档。
查询二:获取句子
现在,让我们用不同的句子来创造填空题。我们将传递一个限制参数,即我们想要生成的句子数量。
conn.gsql('''USE GRAPH NotesGraphDROP QUERY getSentencesCREATE QUERY getSentences(INT lim) FOR GRAPH NotesGraph {TYPEDEF TUPLE<STRING sentence, STRING entity> OPTIONS;
HeapAccum<OPTIONS> (lim, entity DESC) @@opt;
SumAccum<INT> @connected_entities;Seed = {Entity_Name.*};Res = SELECT tgt FROM Seed:s - (SENTENCE_ENTITY_NAME:e) - Sentence:tgt
ACCUM tgt.@connected_entities+=1, @@opt+=OPTIONS(tgt.setence, s.entity_name)
HAVING tgt.@connected_entities > 0;PRINT @@opt AS Sentence_Options;}INSTALL QUERY getSentences''')
再一次,让我们来分析一下。
首先,我们将创建一个 HeapAccum。HeapAccum 必须接受一个 TYPEDEF 元组,我们将把它作为一个句子和一个实体。
TYPEDEF TUPLE<STRING sentence, STRING entity> OPTIONS;
HeapAccum<OPTIONS> (lim, entity DESC) @@opt;
接下来,我们将创建一个 SumAccum,我们将使用它来计算每个句子连接了多少个实体。为此,我们要做的就是确保我们提取的句子中至少有一个实体。
SumAccum<INT> @connected_entities;
我们将从抓取所有的实体名称顶点开始。
Seed = {Entity_Name.*};
然后我们将抓取所有连接到 Entity_Name 顶点的句子。然后我们将有两个累加器。第一个将计算有多少实体连接到句子(以确保不止一个,如 having 子句所示)。第二个将向 HeapAccum 添加实体和句子。
Res = SELECT tgt FROM Seed:s - (SENTENCE_ENTITY_NAME:e) - Sentence:tgt
ACCUM tgt.@connected_entities+=1, @@opt+=OPTIONS(tgt.setence, s.entity_name)
HAVING tgt.@connected_entities > 0;
完美!最后,我们将把 HeapAccum 作为句子选项打印出来。
PRINT @@opt AS Sentence_Options;
现在我们有了获取句子和多项选择选项的查询,让我们把它们放在一起。
Python 函数:提出问题
最后,让我们将这两个查询放在一起,创建一个基于文本的交互式 Python 函数。
import randomres = conn.runInstalledQuery("getSentences", params={"lim": 100})[0]["Sentence_Options"]
random.shuffle(res)pref = ["a", "b", "c", "d"]
let_to_num = {let: num for num, let in enumerate(pref)}for num in range(5): sentence = res[num]["sentence"]
entity = res[num]["entity"]
opts = conn.runInstalledQuery("findOptions", {"word": entity}) similar_words = [i["v_id"] for i in opts[0]["Options"]]
random.shuffle(similar_words)
similar_words = similar_words[:3]
similar_words.append(opts[1]["Seed"][0]["v_id"])
random.shuffle(similar_words) print(f'{num+1}.) {sentence.replace(entity, "___")}')
print("\n".join([f"{let}.) {opt}" for let, opt in zip(pref, similar_words)]))
print("")
ans = input("Enter the letter: ").lower() if similar_words[let_to_num[ans]] == entity:
print("Correct!")
else:
print(f"Nope. The correct answer is \"{entity}\"!") print("\n\n\n")
我们来分析一下。首先,我们将抓取一定数量的句子,然后使用 Python 的随机函数将它们打乱。
import randomres = conn.runInstalledQuery("getSentences", params={"lim": 100})[0]["Sentence_Options"]
random.shuffle(res)
接下来,我们将为答案选项创建一个前缀数组,然后创建一个字典。
pref = ["a", "b", "c", "d"]
let_to_num = {let: num for num, let in enumerate(pref)}
然后我们将循环所有的句子选项。
for num in range(5):
接下来,我们将抓住句子、实体和选项。
sentence = res[num]["sentence"]
entity = res[num]["entity"]
opts = conn.runInstalledQuery("findOptions", {"word": entity})
然后,我们将混合答案选项,选择三个,然后添加我们的选择,并洗牌。
similar_words = [i["v_id"] for i in opts[0]["Options"]]
random.shuffle(similar_words)
similar_words = similar_words[:3]
similar_words.append(opts[1]["Seed"][0]["v_id"])
random.shuffle(similar_words)
最后,我们将开始打印出这些值。我们将提出问题,然后打印出答案并提示答案。
print(f'{num+1}.) {sentence.replace(entity, "___")}')
print("\n".join([f"{let}.) {opt}" for let, opt in zip(pref, similar_words)]))
print("")
ans = input("Enter the letter: ").lower()
如果答案是正确的,那么我们就说正确。如果不是,我们就说正确答案。
if similar_words[let_to_num[ans]] == entity:
print("Correct!")
else:
print(f"Nope. The correct answer is \"{entity}\"!")
完美!现在,您可以运行单元并与您的问答脚本进行交互。
示例问题
第三部分:祝贺你!
恭喜你。如果你完成了这个,你现在可以从你的笔记中创建选择题!
点击此处查看完整的 Colab:
https://colab.research.google.com/drive/12az8ahoX5FQu6-ARGYiwbyFD7B3LPIZV?usp=sharing
如果你有任何问题,发布到 TigerGraph 的社区页面。
https://community.tigergraph.com/
谢谢大家!期待这个系列的下一篇博客!
使用深度学习生成音乐
思想和理论
引入新的基于 VAE 的架构来生成新颖的音乐样本
深度学习从根本上改变了计算机视觉和自然语言处理领域,不仅在分类方面,而且在生成任务方面,使人们能够创建令人难以置信的逼真图片和人工生成的新闻文章。但是音频领域——或者更具体地说——音乐领域呢?在这个项目中,我们的目标是创建新的神经网络架构来生成新的音乐,使用来自 Lakh Piano 数据集的 20,000 个不同流派的 MIDI 样本,Lakh Piano 数据集是最近音乐生成任务的流行基准数据集。
这个项目是由宾夕法尼亚大学大四学生艾萨克·塔姆 和 马修·金 共同完成的。
背景
使用深度学习技术的音乐生成在过去二十年中一直是一个有趣的话题。与图像相比,音乐在三个主要方面被证明是一个不同的挑战:首先,音乐是时间性的,具有跨时间依赖的层次结构。其次,音乐由多种乐器组成,这些乐器相互依存,并随着时间的推移而展开。第三,音乐被分为和弦、琶音和旋律——因此每个时间步长可能有多个输出。
然而,音频数据有几个属性,使它们在某些方面熟悉深度学习中的传统研究(计算机视觉和自然语言处理,或 NLP)。音乐的序列性质让我们想起了 NLP,我们可以用递归神经网络来处理它。还有多个音频“通道”(就音调和乐器而言),这让人想起卷积神经网络可以用于的图像。此外,深度生成模型是令人兴奋的新研究领域,具有创建真实合成数据的潜力。一些例子是变分自动编码器(VAEs)和生成对抗网络(GANs),以及 NLP 中的语言模型。
大多数早期音乐生成技术都使用递归神经网络(RNNs),它自然地包含了时间上的依赖性。 Skuli (2017)使用 LSTMs 以与语言模型相同的方式生成单乐器音乐。同样的方法也被尼尔森 (2020)使用,他改编这种方法来产生高保真音乐。
最近,卷积神经网络(CNN)被用于生成音乐,并取得了巨大的成功,2016 年 DeepMind 展示了 WaveNet 的有效性,它使用扩张卷积来生成原始音频。杨 (2017)创建了 MidiNet,它使用深度卷积生成对抗网络(DCGANs)来生成多乐器音乐序列,这些音乐序列可以基于前一小节的音乐以及当前小节的和弦。董在 2017 年的 MuseGAN 中进一步发展了 GAN 的概念,使用多个发生器来实现尊重乐器之间依赖关系的合成多乐器音乐。董使用 Wasserstein-GAN 与梯度惩罚(WGAN-GP)更大的训练稳定性。
最后,随着注意力网络和变形金刚在自然语言处理方面的最新进展,人们也尝试将变形金刚应用于音乐生成。Shaw (2019)创建了 MusicAutobot,它使用 BERT、Transformer-XL 和 Seq2Seq 的组合来创建一个多任务引擎,既可以生成新的音乐,也可以在其他乐器的条件下创建和声。
数据集
我们的数据来自 Lakh Pianoroll 数据集,这是一个由 174,154 个多轨道 Pianoroll 组成的集合,来自 Lakh MIDI 数据集,由中央研究院 IT 创新研究中心的音乐和人工智能实验室管理。我们使用了数据集的 LPD 5 版本,其中包括钢琴、鼓、吉他、贝斯和弦乐的曲目,使我们能够生成复杂而丰富的音乐,并展示我们的生成模型在不同乐器之间编排音乐的能力。我们使用 Lakh Pianoroll 数据集的净化子集,其中包括 21,245 个 MIDI 文件。每个文件都有相应的元数据,允许我们确定每个文件的信息,如艺术家和标题名称。
基线法:用 RNNs 进行下一次笔记预测
为了建立一个我们可以改进的音乐生成的基线,我们使用了递归神经网络(RNN),这是一种现有的易于复制的方法。生成音乐被公式化为下一个音符预测问题。(这种方法非常类似于 NLP 中使用的基于递归的语言模型。点击此处了解更多信息)这将允许我们通过不断将生成的音符传回到模型中来生成我们想要的任意多的音乐。
在实现方面,我们使用了门控循环单元(GRU)而不是普通的 RNN,因为它能够更好地保留长期依赖性。每个 GRU 将接受前一层的激活和输出作为输入,输出将是给定前一激活和输入的下一个音符。
为了创建训练我们的递归神经网络所需的数据,我们首先解析数据集的钢琴音符,将每个文件表示为在文件中找到的音符列表。然后,我们通过获取每首歌曲的列表表示的子集来创建训练输入序列,并通过简单地获取每个子集的下一个音符来创建相应的训练输出序列。有了这种训练输入和输出,模型将被训练来预测下一个音符,这将允许我们传递任何音符序列,并获得下一个音符的预测。每个输入序列被传递到一个嵌入层,该嵌入层创建大小为 96 的嵌入。然后,该嵌入被传递到具有单层的门控循环单元中,该单元然后被传递到完全连接的层,以输出下一个音符的概率分布。我们可以选择概率最高的音符作为下一个预测音符,但这将导致没有变化的确定性序列。因此,我们从带有输出概率的多项式分布中抽取下一个音符。
虽然 RNN 下一个音符预测模型实现起来简单明了,但生成的音乐听起来远非理想,而且效用非常有限。因为我们将每个音符编码到一个标记中,并预测编码的概率分布,所以我们只能对一个乐器这样做,因为对于多个乐器,音符组合的数量呈指数增长。还有,假设每个音符都是一样长的,肯定不能反映大多数音乐作品。
为 RNN 下一个音符预测模型生成的音乐
多乐器 RNN
因此,我们试图探索同时为多种乐器创作音乐的其他方法,并提出了多乐器 RNN。
我们没有像最初的想法那样将音乐编码成独特的音符/和弦,而是在每个时间步直接处理 5 x 128 多乐器钢琴卷,将其展平成为一个 640 维的向量,代表每个时间步的音乐。然后,我们训练一个 RNN 来预测下一个时间步的 640 维向量,给定前面的 640 维向量的长度为 32 的序列。
虽然这种方法在理论上是有意义的,但要产生令人满意的结果是有挑战性的,因为很难在所有工具之间产生互补的多样性。
- 在单乐器设置中,我们通过输出 softmax 分数对概率加权的多项式分布进行采样,以生成下一个音符。然而,由于所有乐器被一起放置在 640 维向量中,所以在整个 640d 向量上使用 softmax-ed 分数来生成下一个音符可能意味着一些乐器可能具有多个音符,而一些乐器没有音符。
- 我们试图通过对 5 种乐器的 128 维向量分别运行 softmax 函数来解决这个问题,这样我们可以确保为每种乐器生成一定数量的音符。
- 然而,这意味着每个仪器的采样是相互独立的。这意味着生成的钢琴序列不会与其他乐器的序列互补。例如,如果 C-E-G 和弦是从序列中采样的,那么低音就没有办法合并它,并且可以采样 D-F-A 和弦,因为 D-F-A 和弦是不和谐的,不是互补的。
此外,还有一个问题是不知道每次每种乐器要采样多少个音符。这个问题在单乐器设置中不存在,因为单音符和多音符和弦都被编码为整数表示。我们通过从多项式中为每个时间步长采样指定数量的音符(例如钢琴 2 个,吉他 3 个)来解决这个问题。但是这是不成功的,因为生成的音乐听起来非常随机和不音乐。
为多乐器 RNN 模型生成的音乐
从递归到卷积
从这一点开始,我们决定专注于卷积神经网络(CNN)而不是 RNNs 来生成音乐序列。CNN 将通过输出 5×32×128 的三维张量直接生成长度为 32 的序列。这将解决不知道要生成多少音符以及必须使用多项式采样的问题。在序列生成方面,CNN 架构(如 WaveNet)已经显示出与 RNNs 一样好(如果不是更好的话)的性能。此外,由于卷积运算的性能优化,它们的训练速度更快。
MelodyCNN 和条件性和谐 CNN
为了生成多个彼此兼容的乐器轨道,我们尝试了一个两部分生成模型,包括用于下一时间步旋律生成的 MelodyCNN ,以及用于生成非钢琴乐器的条件和声 CNN ,给定相同时间步的旋律以及上一时间步的乐器音乐。
用于生成音乐的 MelodyCNN +条件和声 CNN 的架构。(图片作者)
由于输入和输出大小相同(32 x 128),所用的 MelodyCNN 架构是对称的,具有 3 个卷积层、3 个密集层和 3 个去卷积层。条件谐波 CNN 对每个输入(钢琴和乐器的先前输入)使用 3 个卷积层,然后在通过密集层和去卷积层之前连接结果张量。
因此,MelodyCNN 学习连续时间步长中钢琴序列之间的映射,而条件和声 CNN 从钢琴音乐空间映射到其他乐器。
总共使用 5 个 CNN(每个乐器一个),给定起始多乐器序列,可以迭代地生成新音乐。首先,MelodyCNN 用于预测下一个钢琴序列,条件和声 CNN 用于预测其他乐器。
钢琴音乐产生的旋律。(图片作者)
这个框架成功地生成了多种乐器的音乐序列,这些乐器的声音在音乐上是互补的。然而,改变生成音乐的起始序列只会导致生成的音乐有很小的变化,如上面的钢琴卷所示:三个生成的序列几乎彼此相同。
这表明 CNN 很可能集中于仅输出训练数据中的公共序列的一个小子集,这最小化了训练损失。需要找到另一种方法,在给定相同输入的情况下,在输出音乐中产生一些变化,为了实现这一点,我们转向 VAEs。
为旋律 CNN +条件和声 CNN 模型生成音乐
使用可变自动编码器(VAEs)
VAEs 的背景
变分自动编码器(VAE)是一种自动编码器,其中训练被正则化以确保潜在空间具有允许生成过程的良好属性。两个这样的特性是连续性——潜在空间中的接近点一旦被解码应该给出相似的点,以及完整性——从潜在空间采样的点一旦被解码应该给出有意义的内容。
标准的自动编码器将输入编码成潜在空间中的向量,但是不能保证潜在空间满足允许产生新数据的连续性和完整性。相反,VAE 将输入编码为潜在空间上的分布。具体来说,我们假设潜在分布是高斯分布,因此编码分布的编码器相当于输出正态分布的均值和标准差参数的编码器。
为了训练 VAE,使用了两项损失函数:重构误差(解码输出和输入之间的差异),以及正则化项(潜在分布和标准高斯分布之间的 KL 散度),以将潜在分布正则化为尽可能接近标准正态。
变分自动编码器(VAE)如何工作的图示。(图片由作者提供)
应用
因此,我们将 VAEs 应用于音乐生成任务。先前的钢琴输入由钢琴值编码成 zₜ. k 维的潜在钢琴编码然后,随机噪声被添加到编码的潜在分布的平均参数。这种随机噪声的标准差是一个超参数,用户可以根据自己想要的变化量进行调整。然后,潜在参数 zₜ被输入到多层感知器 MelodyNN,该感知器学习从前一钢琴序列的潜在分布到下一钢琴序列的潜在分布的映射。然后,输出 z_t+1 被解码,成为生成的下一个钢琴输出。
针对特定乐器的 vae 也在其他四种乐器(吉他、贝斯、弦乐、鼓)上接受培训。
然后,类似于前面的 ConditionalNN,我们使用另一个 MLP conditional nn,其接受生成的下一周期钢琴潜在参数以及前一周期吉他潜在参数 z_t+1,并学习到下一周期吉他潜在参数 w_t+1 的映射。w_t+1 然后由特定于乐器的 VAE 解码器解码,以产生下一个周期的吉他输出。训练 4 个条件神经网络,每个非钢琴乐器一个,这允许生成下一个 5 乐器序列。
因此,通过用 VAEs 将音乐输入映射到潜在分布,我们可以通过将随机噪声添加到编码的潜在分布的参数来将变化引入到生成的音乐输出中。由于连续性,这确保了在添加随机噪声之后,解码的输入与原始输入相似但不同,并且由于完整性,这确保了它们给出与输入音乐分布相似的有意义的音乐输出。
该架构的可视化指南如下所示。
建筑的 VAE-NN 用来产生音乐。(图片作者)
结果
从同一起始序列生成的两个钢琴演奏者。音乐输出中显示的一个变化示例如上所示。上面的两个音轨有相同的开始序列,但是产生的鼓点略有不同。此外,第一首曲目接近尾声时有钢琴部分,而第二首曲目没有,条件神经网络通过改变生成的伴奏乐器曲目来做出响应。(图片由作者提供)
训练了潜在维数为 8、16、32 和 64 的值。最后,由于音乐样本在音乐空间中相对稀疏,所以使用 16 维的潜在空间来训练条件神经网络。
在训练条件神经网络之后,我们发现 VAE+神经网络方法在创建听起来连贯的多乐器输出方面是成功的,并且具有美学上令人愉悦的适当变化量。发现标准偏差在 0.5 到 1.0 之间的随机噪声产生最佳的变化量。
一些使用 VAE 神经网络生成音乐的好例子。
生成特定风格的音乐
根据特定风格生成音乐的方法(图片由作者提供)
上面解释的 VAE-神经网络框架允许我们基于特定的风格,例如某个艺术家、流派或年份,用一种简单的方法来生成音乐。例如,如果我们想创作迈克尔杰克逊的惊悚片风格的音乐,我们可以:
1.将歌曲分成 32 步序列,并使用每个乐器的 VAE 编码器将每个序列的钢琴声编码到潜在空间中。将每个乐器的独特序列存储在组中。
2.当从开始序列生成音乐时,从该集合中对每个乐器的一个潜在向量进行采样。这个采样的潜在向量(来自我们想要的歌曲) s 然后与先前序列的潜在向量内插以生成新的潜在向量,
其中α是潜在样本因子,它是一个可以调整的超参数。(为生成的音乐选择较高的α值,以更好地适应所需的风格)
3.使用 z'ₜ而不是 zₜ作为 MelodyNN 的输入来生成新的潜在向量,从而生成钢琴序列。
使用这种方法,α=0.5,我们根据几首歌曲生成了新的音乐,一些例子是迈克尔杰克逊的 Thriller 和后街男孩的 I Want It That Way 。这成功地生成了与原始歌曲有些相似但也有一些变化的音频样本。(同样,变化的程度也可以用 noise_sd 超参数来调节)。人们甚至可以根据不同艺术家或风格的混合样本来创作音乐,从而使音乐爱好者能够结合不同音乐明星的风格来合成音乐。
使用 VAE 神经网络风格条件生成音乐。
大失败:甘斯
受到使用深度卷积生成对抗网络(DCGANs)来产生听起来真实的音乐的成功的启发,我们试图使用 GANs 来产生音乐。众所周知,GANs 可以在计算机视觉领域生成高度逼真的合成样本,比 VAEs 更好。这是因为 gan 不估计底层分布的显式概率密度,而 vae 试图优化较低的变分界限。然而,众所周知,GANs 很难训练成功。
我们使用了一个具有 6 个去卷积层的生成器,接收一个噪声 100 维向量,并生成一个 5 x 32 x 128 的多乐器音乐序列。鉴别器具有相反的架构,接收 5 x 32 x 128 的音乐序列,使其通过 6 个卷积层,并输出样本为真实的概率。
对于生成器和鉴别器,使用了 PReLU 激活,以及卷积层的批量归一化。两者都使用了 Adam optimizer。
尝试了以下方法来提高 GAN 的稳定性:
- 标签平滑:我们不是对生成图像或真实图像分别使用硬标签 0 或 1,而是在标签中添加随机噪声(这样生成图像的标签在 0 和 0.1 之间,真实图像的标签在 0.9 和 1 之间)。
- 特征匹配:添加 L2 正则化子以使真实数据和生成数据的分布更接近。使用两个正则化器:第一个正则化器基于真实图像输入与生成图像输入的期望值的绝对差,第二个正则化器基于真实图像输入和生成图像输入的第一卷积层的输出的期望值的绝对差。
- 双时标更新规则(TTUR):对鉴别器使用比生成器更高的学习速率。
- 调整学习率
尽管进行了几次尝试,训练甘在产生各种听起来逼真的音乐方面证明是不成功的。存在模式崩溃的实例,例如下面生成的音频样本,它是从不同的噪声向量连接在一起生成的 100 个样本。生成的样本大多相似。其他尝试都未能学到任何实质性的东西。
失败的 GAN 实验带来的失误
另一条基线:变形金刚
我们使用的第二种更复杂的基线方法是变压器架构。变形金刚在自然语言处理方面取得了很大的成功,它能够比旧的基于递归的语言模型更快地训练,并具有更好的长期记忆。我们使用了音乐汽车人项目的 Transformer-XL 架构,因为它的代码非常容易复制——我们为此感谢安德鲁·肖,并鼓励您查看他的精彩系列文章!
在普通的 transformer 模型中,数据单元之间的直接连接提供了获取长期依赖关系的机会。然而,这些普通的转换器是用固定长度的上下文实现的,因此转换器不能对长于固定长度的依赖关系建模,并且会出现上下文碎片。
Transformer-XL 架构提供了解决这些问题的技术。第一,它有段级的递归机制。在训练时,为前一段计算的表示被缓存,使得它们可以在模型处理下一段时用作扩展上下文。因此,信息现在可以流经段边界,并解决了上下文碎片问题。其次,它具有相对位置编码方案。这使得模型不仅可以理解每个标记的绝对位置,还可以理解每个标记相对于另一个标记的位置,这在音乐中非常重要。
与文本不同,标记音乐要复杂得多。一个音符代表两个不同的值——音高和持续时间(它也可以代表更多的东西,如响度和时间,但这些对我们的目的来说不太重要)。因此,每个音符都需要被编码成一系列的记号。幸运的是,音乐汽车人项目处理了 MIDI 文件的符号化。
我们发现生成的音乐也相对不错——看看下面吧!
结论
总的来说,我们已经实现了各种深度学习方法来解决音乐生成问题,并取得了不同程度的成功。我们的基线方法对单个轨迹和多个轨迹都使用了递归神经网络模型。虽然这种模型在产生的音符的音乐性方面更成功,但它的实用性非常有限,因为它只能产生四分音符节拍的音符。然后,我们转向卷积神经网络模型,使用普通 CNN 产生钢琴音轨,使用条件 CNN 产生其他乐器音轨。我们发现由 CNN 模型产生的安排更有条理和连贯性,因为我们使用了条件模型。
我们设计的新颖的 VAE 建筑是我们项目最成功的贡献。通过使用 VAE 将序列编码到潜在空间中,我们可以在潜在空间中添加噪声,以可控的方式增加生成的输出的变化,同时保持先前序列之间的相似性,最终提高我们生成的音乐的独特性。
你可以在我们的 Github 库中找到我们所有的代码——在你自己的音乐创作冒险中随意使用它。如果你有任何问题,请在 LinkedIn 上留言或联系我,我很乐意帮助你!
真正让深度学习领域令人惊叹的是开源合作文化——如果没有我们之前许多慷慨的贡献者,我们的工作永远不可能实现,我们希望这个项目是对深度学习领域的一个微小但有意义的贡献。
特别感谢教授这门深度学习课程(cis 522——宾夕法尼亚大学数据科学中的深度学习)的 Lyle Ungar 和 Konrad Kording 教授,以及 TA Pooja Counsul 整个学期的指导。
用 Python 和 R 生成参数化的 Powerpoint 文档
通过自动生成 Powerpoint 控制您的报告工作流程
许多商业报告领域的数据科学家被要求将他们的数据转换成 Powerpoint 演示文稿(不管他们喜不喜欢!).最常见的是许多参数化的演示,其中格式、图表和内容都是相同的,但数据会发生变化,例如按组织单位。经常需要从指定的示例模板生成数十、数百甚至数千个这样的报告。本教程给出了一个如何编写和自动化这样一个工作流的例子。
本教程的所有代码都可以在我的 Github repo 中找到,整篇文章都引用了它。
背景和先决条件
本教程涉及以下场景:
- 用户群需要以包含图表和表格的可编辑 Powerpoint 文档的形式交付结果。
- 存在完全填充有虚拟数据或示例数据的示例文档。
- 同一文档需要用不同组的不同数据重新创建,并用不同的文件名保存,以便在整个组织内分发。该工作流有助于创建任意数量的这种参数化文档。
使用开源技术,这个工作流程是完全可执行的。对于 Python 中的执行,建议使用基于 Python 3.7 的 conda 环境或虚拟环境,并安装pandas
和python-pptx
包。为了进口到 R,将需要reticulate
包。
本教程分为三个部分:
- 如何使用
python-pptx
包编写一个函数来替换现有 Powerpoint 演示文稿中的数据。 - 如何在 Python 中使用它来批量生成任意数量的参数化 Powerpoint 文档。
- 如何将函数导入到 R 中,并使用 tidyverse 批量生成任意数量的参数化 Powerpoint 文档。
入门指南
假设我们为一个组织工作,该组织由 20 个销售小组组成,从 A 组到 t 组依次命名。一个名为ppt-template.pptx
的现有 Powerpoint 文档存在于回购的templates
文件夹中,其中的虚拟数据包含以下内容:
- 一个标题页,我们希望根据特定的销售组名称对其进行定制。
- 包含两个图表(条形图和饼图)的页面。我们将需要替换数据并重新命名这两个图表,以引用特定的销售组。
- 带有销售数据表的页面。我们希望用特定销售组的数据替换该表中的数据。
我们需要编辑的幻灯片(作者生成)
我们需要替换到该文档中的数据可以在data
文件夹中找到。这是出于演示目的随机生成的数据。文件chart_df.csv
包含条形图和饼图的数据,以table_
为前缀的各种文件包含每个销售组的数据,这些数据将放入最后一张幻灯片的表格中。
使用python-pptx
包替换 Powerpoint 演示文稿的元素
我们从 Python 开始,从python-pptx
包中导入一些我们需要的函数。在这个例子中,我们只需要几个简单的函数,但是我鼓励您探索这个包中广泛可用的函数来编辑和定制 Powerpoint 元素。
from pptx import Presentation
from pptx.chart.data import CategoryChartData
接下来,我们将现有的虚拟演示加载到 Python 会话中:
pres = Presentation("templates/ppt-template.pptx")
通过检查pres
,我们可以看到它是一个 Powerpoint 演示对象。
pres## <pptx.presentation.Presentation object at 0x7fb40af62140>
pres
实际上是一个复杂的嵌套 XML 对象。但是正如你所料,它包含了一些幻灯片。我们可以创建一个幻灯片列表,并检查该列表是否包含我们期望的三张幻灯片。
slides = [slide for slide in pres.slides]
len(slides)## 3
看起来不错。现在,每张幻灯片都包含一些形状,可以是从文本框到图表、表格或图示的任何形状。
编辑形状中的文本框
让我们看看标题幻灯片上有多少个形状:
slide0 = slides[0]
slide0_shapes = [shape for shape in slide0.shapes]
len(slide0_shapes)## 3
所以标题幻灯片上有三个形状。我们知道其中一个是标题占位符文本框,另一个是副标题占位符文本框,我们可以识别并抓取它们,因为它们都包含一个text_frame
(文本框的 XML 术语)。
title_shapes = [shape for shape in slide0.shapes if shape.has_text_frame]
len(title_shapes)## 2
现在,由于这些是占位符对象,占位符文本可能会由于模板格式而与模板中的可见内容不匹配,因此我们需要查看每个占位符的文本:
placeholder_text = [shape.text for shape in title_shapes if shape.has_text_frame]
placeholder_text## ['Presentation title Alt', 'Subtitle comes here']
我们现在可以使用这些信息来替换这些文本框中的文本。让我们对 A 组演示文稿的标题文本也这样做,以检查它是否有效:
title = [shape for shape in title_shapes if shape.has_text_frame and shape.text == 'Presentation title Alt']
title[0]. text = "Presentation for Group A"
我们可以检查这是否有效:
new_placeholder_text = [shape.text for shape in title_shapes if shape.has_text_frame]
new_placeholder_text## ['Presentation for Group A', 'Subtitle comes here']
成功了!我们可以用类似的方法来编辑字幕。
将新数据加载到图表中
我们可以使用形状的has_chart
属性来识别图表对象。让我们检查一下第二张幻灯片上是否有两张图表:
slide1 = slides[1]
slide1_charts = [shape for shape in slide1.shapes if shape.has_chart]
len(slide1_charts)## 2
我们不能完全确定这些图表是按照它们在幻灯片上出现的顺序排列的,但是我们可以通过标题来识别特定的图表,标题嵌套在 chart 对象的标题文本框架中。
bar_chart = [shape.chart for shape in slide1_charts if shape.chart.chart_title.text_frame.text == 'Statistics here']
现在我们有了条形图,我们需要重写它的数据。我们注意到条形图有三个系列的条,每个代表四个类别中的一个。当我们重写此图表中的数据时,我们需要重写所有数据—不可能只重写其中的一部分。因此,我们从头开始定义类别,并将三个系列的数据写入一个CategoryChartData
对象。这里我就用一些随机的例子数据来说明。
chart_data = CategoryChartData()
chart_data.categories = ['Category ' + str(i) for i in range(1,5)]
chart_data.add_series('Series 1', range(1, 5))## <pptx.chart.data.CategorySeriesData object at 0x7fb40b15df50>chart_data.add_series('Series 2', range(2, 6))## <pptx.chart.data.CategorySeriesData object at 0x7fb40af9bc50>chart_data.add_series('Series 3', range(3, 7))## <pptx.chart.data.CategorySeriesData object at 0x7fb40af9bf90>
我们现在用这个数据替换条形图中的数据,并给它一个新的标题。
bar_chart[0].replace_data(chart_data)
bar_chart[0].chart_title.text_frame.text = "Sales by Category: Group A"
此时,我们可以保存我们的演示文稿并查看其中一页,看看这是否有效。
pres.save("test1.pptx")
通过检查第二张幻灯片,我们可以看到我们的条形图已经成功地用新数据进行了更新。
条形图已成功更新(作者生成)
使用类似的方法,我们也能够更新这张幻灯片的饼图和标题。
编辑表格
让我们使用与获取图表和文本框类似的方法获取上一张幻灯片中的表格。我们只想要一张桌子。
slide2 = pres.slides[2]
table = [shape for shape in slide2.shapes if shape.has_table]
len(table)## 1
太好了!现在表格需要一个单元格一个单元格地编辑,这听起来很痛苦,但实际上使用索引很容易。我们注意到有一行列名,然后是八行数据,然后是一行总计。让我们从数据集中引入一个表格。
import pandas as pd
table_A = pd.read_csv("data/table_A.csv")
table_A## A B C D E
## 0 2.2 4.8 0.9 5.1 5.4
## 1 3.1 4.4 3.4 4.0 3.8
## 2 1.6 3.8 4.3 6.0 2.7
## 3 5.4 5.1 0.7 0.3 2.8
## 4 4.8 2.1 5.0 2.9 2.1
## 5 5.3 5.8 3.9 5.5 4.1
## 6 2.4 4.9 1.9 5.7 5.8
## 7 4.7 3.1 3.7 1.3 0.6
现在我们的表的第一行是一组列名,所以我们可以编辑文本以匹配我们的table_A
数据框架中的列名:
for j in range(0,5):
table[0].table.cell(0, j).text = "Product " + table_A.columns.values[j]
然后,我们可以直接从数据框中更新每个单元格中的值:
for i in range(1,9):
for j in range(0,5):
table[0].table.cell(i,j).text = str(table_A.iloc[i-1, j])
最后,我们将一些总数放在最后一行(确保我们格式化以避免任何 Python 的浮点行为):
for j in range(0,5):
table[0].table.cell(9,j).text = "{:.1f}".format(sum(table_A.iloc[:,j]))
让我们再次保存并检查该表是否更新了新数据:
pres.save("test2.pptx")
经过检查,我们似乎成功地更新了该表:
该表已成功更新(由作者生成)
创建一个函数来更新演示
既然我们已经了解了编辑此演示文稿的基本知识,我们可以通过编写一个 Python 函数来实现这一切,该函数需要五个输入,如下所示:
group
:单据的集团参数。data_chart
:包含各种图表统计数据的数据帧data_table
:用来替换表格的数据帧input file
:待编辑文件的路径output_file
:新文件将被写入的路径
你可以在回购的edit_pres.py
文件中看到这个函数。让我们找到这个函数,并通过为销售组 m 生成一个文档来测试它。
# load data
chart_df = pd.read_csv("data/chart_df.csv")
table_M = pd.read_csv("data/table_M.csv")# load function
exec(open('edit_pres.py').read())# write Group M presentation
edit_pres("M", chart_df, table_M, "templates/ppt-template.pptx", "test3.pptx")## 'Successfully saved version M!'
我们可以检查看看结果:
所有幻灯片都已成功更新(作者生成)
太好了!我们现在已经具备了开始批量生产参数化 Powerpoint 所需的一切。
Python 中的批量生产
既然我们已经设置了 Python 函数,我们只需要将它与所有数据一起加载到我们的会话中,我们将使用这些数据为每个销售组更新到 twenty 版本中。
import glob
import os# load function
exec(open('edit_pres.py').read())# load all dataframes in data folder into a dict
path = "data/"
data_files = glob.glob(os.path.join(path, "*.csv"))
dataframes = dict()
for i in data_files:
path = os.path.basename(i)
name = path.split('.')[0]
dataframes[name] = pd.read_csv("data/" + name + ".csv")
现在让我们为每个组运行我们的函数,并将输出的 Powerpoint 作为一个适当命名的文件写在一个outputs
目录中。
# create outputs directory if it doesn't exist
if not os.path.isdir("outputs"):
os.mkdir("outputs")# generate a ppt for each group
for group in dataframes['chart_df'].group.values:
tables_data = dataframes['table_' + group]
edit_pres(group, dataframes['chart_df'], tables_data,
'templates/ppt-template.pptx', 'outputs/results_group_' + group + '.pptx')## 'Successfully saved version A!'
## 'Successfully saved version B!'
## 'Successfully saved version C!'
## 'Successfully saved version D!'
## 'Successfully saved version E!'
## 'Successfully saved version F!'
## 'Successfully saved version G!'
## 'Successfully saved version H!'
## 'Successfully saved version I!'
## 'Successfully saved version J!'
## 'Successfully saved version K!'
## 'Successfully saved version L!'
## 'Successfully saved version M!'
## 'Successfully saved version N!'
## 'Successfully saved version O!'
## 'Successfully saved version P!'
## 'Successfully saved version Q!'
## 'Successfully saved version R!'
## 'Successfully saved version S!'
## 'Successfully saved version T!'
看起来成功了!我已经将这些输出放在 repo 的outputs_example
文件夹中。
将它导入到 R 中,并使用 Tidyverse 完成一个简洁的更新工作流
为了在 R 中使用我们伟大的 python 函数edit_pres.py
,R 需要知道在哪里可以找到包含它所使用的安装包的 Python 环境。最简单的方法是在 R 项目中创建一个名为.Rprofile
的文件,并用它来设置RETICULATE_PYTHON
环境变量。这将需要设置为 Python 环境中编写该函数的 Python 可执行文件的路径。下面是我的.Rprofile
中的一个例子:
Sys.setenv(RETICULATE_PYTHON="/home/rstudio/.local/share/r-miniconda/envs/pptx/bin/python3")
为了让这个新变量生效,您需要重启 R。一旦 R 重启,项目中的任何 Python 代码都将由RETICULATE_PYTHON
定义的 Python 可执行文件执行。
设置好 Python 环境后,我们可以使用reticulate
包将 Python 函数加载到 R 中。这样,它立即成为一个 R 函数,可以处理 R 输入。
library(reticulate)source_python("edit_pres.py")edit_pres## <function edit_pres at 0x7fb40af17ef0>
我们可以将所有数据作为数据帧载入,并测试该功能是否有效:
# load in data files
for (file in list.files("data")) {
splits <- strsplit(file, "\\.")
assign(splits[[1]][1],
read.csv(paste0("data/", file)))
} # test edit_pres function on Group M
edit_pres("M", chart_df, table_M, "templates/ppt-template.pptx", "test4.pptx")## [1] "Successfully saved version M!"
使用dplyr
在一个整洁的表格中完成这一切
我们的chart_df
对象是一个常规的 dataframe,其中每一行代表每个销售组的图表数据。然而,我们的表数据都存储在不同的数据帧中。我们可以添加一个列表列,通过在group
列上使用 mutate 来捕获所有不同的表数据集,使其与我们的图表数据保持一致:
library(dplyr)full_data <- chart_df %>%
dplyr::rowwise() %>%
dplyr::mutate(
table = list(get(paste0("table_", group)))
)
如果我们检查一些列,我们可以看到我们的表存储在full_data
数据帧的行中。
full_data %>%
dplyr::select(group, starts_with("pie"), table)## # A tibble: 20 x 6
## # Rowwise:
## group pie1 pie2 pie3 pie4 table
## <chr> <dbl> <dbl> <dbl> <dbl> <list>
## 1 A 4.3 5.5 1.8 1.2 <df[,5] [8 × 5]>
## 2 B 2.2 2.7 4.6 2.3 <df[,5] [8 × 5]>
## 3 C 4.1 5.1 3.2 4.4 <df[,5] [8 × 5]>
## 4 D 5 5.7 1.3 5.9 <df[,5] [8 × 5]>
## 5 E 5.1 5 0.4 5.3 <df[,5] [8 × 5]>
## 6 F 3.9 1.2 5.2 1.9 <df[,5] [8 × 5]>
## 7 G 5.7 5.3 5.4 5 <df[,5] [8 × 5]>
## 8 H 3.5 1.5 4.5 3.5 <df[,5] [8 × 5]>
## 9 I 4.4 5.4 4 0.7 <df[,5] [8 × 5]>
## 10 J 0.7 6 2.7 5.5 <df[,5] [8 × 5]>
## 11 K 2 4.8 4.4 1.6 <df[,5] [8 × 5]>
## 12 L 2.8 1.6 1.1 0.5 <df[,5] [8 × 5]>
## 13 M 3.3 3.9 0.6 2.4 <df[,5] [8 × 5]>
## 14 N 4.2 2.2 2.5 5.7 <df[,5] [8 × 5]>
## 15 O 5.6 4.5 5 2.7 <df[,5] [8 × 5]>
## 16 P 0.5 2.3 3.5 2.1 <df[,5] [8 × 5]>
## 17 Q 1 2.4 0.5 3.4 <df[,5] [8 × 5]>
## 18 R 2.4 2.1 1.2 0.9 <df[,5] [8 × 5]>
## 19 S 3.8 0.1 2.2 0.1 <df[,5] [8 × 5]>
## 20 T 1.1 4 2 3.1 <df[,5] [8 × 5]>
现在是最后的魔术步骤。我们可以做进一步的改变,在这个数据帧的行上运行我们的 Python 函数,以编写我们所有的 Powerpoint 文档:
# create outputs directory if it doesn't exist
if (!dir.exists("outputs")) {
dir.create("outputs")
}# rowwise mutate to run function for all groups
write_pptx <- full_data %>%
dplyr::rowwise() %>%
dplyr::mutate(
pptx = edit_pres(group, ., table,
"templates/ppt-template.pptx",
paste0("outputs/results_group_", group, ".pptx" ))
)
这个新的数据框将包含一个新列,其中包含写入文件的确认,您可以在outputs
文件夹中查找并检查它们。
write_pptx %>%
dplyr::select(group, starts_with("pie"), table, pptx)## # A tibble: 20 x 7
## # Rowwise:
## group pie1 pie2 pie3 pie4 table pptx
## <chr> <dbl> <dbl> <dbl> <dbl> <list> <chr>
## 1 A 4.3 5.5 1.8 1.2 <df[,5] [8 × 5]> Successfully saved version A!
## 2 B 2.2 2.7 4.6 2.3 <df[,5] [8 × 5]> Successfully saved version B!
## 3 C 4.1 5.1 3.2 4.4 <df[,5] [8 × 5]> Successfully saved version C!
## 4 D 5 5.7 1.3 5.9 <df[,5] [8 × 5]> Successfully saved version D!
## 5 E 5.1 5 0.4 5.3 <df[,5] [8 × 5]> Successfully saved version E!
## 6 F 3.9 1.2 5.2 1.9 <df[,5] [8 × 5]> Successfully saved version F!
## 7 G 5.7 5.3 5.4 5 <df[,5] [8 × 5]> Successfully saved version G!
## 8 H 3.5 1.5 4.5 3.5 <df[,5] [8 × 5]> Successfully saved version H!
## 9 I 4.4 5.4 4 0.7 <df[,5] [8 × 5]> Successfully saved version I!
## 10 J 0.7 6 2.7 5.5 <df[,5] [8 × 5]> Successfully saved version J!
## 11 K 2 4.8 4.4 1.6 <df[,5] [8 × 5]> Successfully saved version K!
## 12 L 2.8 1.6 1.1 0.5 <df[,5] [8 × 5]> Successfully saved version L!
## 13 M 3.3 3.9 0.6 2.4 <df[,5] [8 × 5]> Successfully saved version M!
## 14 N 4.2 2.2 2.5 5.7 <df[,5] [8 × 5]> Successfully saved version N!
## 15 O 5.6 4.5 5 2.7 <df[,5] [8 × 5]> Successfully saved version O!
## 16 P 0.5 2.3 3.5 2.1 <df[,5] [8 × 5]> Successfully saved version P!
## 17 Q 1 2.4 0.5 3.4 <df[,5] [8 × 5]> Successfully saved version Q!
## 18 R 2.4 2.1 1.2 0.9 <df[,5] [8 × 5]> Successfully saved version R!
## 19 S 3.8 0.1 2.2 0.1 <df[,5] [8 × 5]> Successfully saved version S!
## 20 T 1.1 4 2 3.1 <df[,5] [8 × 5]> Successfully saved version T!
扩展这项工作
您可以扩展这项工作,创建一个非常强大的报告基础结构,如下所示:
- 使用数据库连接来查询 Powerpoint 文档所需的数据
- 使用 web 前端(例如在 Shiny 或 Django 中),通过查询后端数据库、写入模板和提供下载的新文件,按需生成 Powerpoint。
最初我是一名纯粹的数学家,后来我成为了一名心理计量学家和数据科学家。我热衷于将所有这些学科的严谨性应用到复杂的人的问题上。我也是一个编码极客和日本 RPG 的超级粉丝。在 LinkedIn 或Twitter上找我。也可以看看我在drkeithmcnulty.com的博客。
pixabay.com 的好意
用 OpenAi 的 Github Copilot 生成 Python 脚本
使用人工智能为简单的神经网络、数据可视化等生成 Python 脚本
我已经有一段时间没有接触到 OpenAi 的 Github copilot 的技术预览了。从那以后,我开始喜欢以函数名和描述的形式问它各种各样的问题,看看它能写出什么样的代码。
在本文中,我将分享我是如何使用 Github Copilot extension for VS Code(技术预览版)生成 Python 脚本的,从 Keras 中简单的神经网络和数据可视化脚本到关于存在秘密的备注
使用 Github Copilot 生成脚本
当你去掉所有关于像 GPT 3 这样的语言模型的天花乱坠和启示录式的谈论,并真正开始使用它们时,你会意识到这种应用范围的好、坏和丑陋。
通过揭示它们的真正潜力,我们可以评估这个令人难以置信的工具,它可能对无数不同的问题有潜在的用处(假设有效的关注得到解决),以及了解它的技术限制,例如它缺乏对基本句子的真正的人类上下文理解。
带有 Keras 的简单神经网络
让我们从 Keras 中的一个简单的神经网络开始。对于第一个脚本,我给模型的输入是:
def SimpleNeuralNetKeras():
pass
人工智能生成的自动完成的输出是这样的:
def SimpleNeuralNetKeras():
net_net = Sequential()
net_net.add(Dense(units=1, input_dim=1))
net_net.compile(loss='mean_squared_error', optimizer='adam')
net_net.fit(x_train, y_train, epochs=100, batch_size=1, verbose=0)
net_net.evaluate(x_test, y_test, batch_size=1, verbose=0)
net_net.predict(x_test, batch_size=1, verbose=0)
net_net.save('my_model.h5')
net_net = load_model('my_model.h5')
net_net.predict(x_test, batch_size=1, verbose=0)
net_net.evaluate(x_test, y_test, batch_size=1, verbose=0)
net_net.fit(x_train, y_train, epochs=100, batch_size=1, verbose=0)
net_net.evaluate(x_test, y_test, batch_size=1, verbose=0)
net_net.predict(x_test, batch_size=1, verbose=0)
net_net.save('my_model.h5')
"""....it goes on and on"""
尽管它继续建议对相同的模型进行再训练,但如果我们去掉脂肪,我们得到的是:
def SimpleNeuralNetKeras():
net_net = Sequential()
net_net.add(Dense(units=1, input_dim=1))
net_net.compile(loss='mean_squared_error', optimizer='adam')
net_net.fit(x_train, y_train, epochs=100, batch_size=1, verbose=0)
net_net.evaluate(x_test, y_test, batch_size=1, verbose=0)
net_net.predict(x_test, batch_size=1, verbose=0)
net_net.save('my_model.h5')
老实说!一点都不差!让我们看看当我要求它创建一个假数据集来匹配这个神经网络设置时会发生什么:
我在这里的输入很简单:
x_train,
我得到的回答是:
x_train,y_train,x_test,y_test = get_data()
有意思。让我们看看这个模型是否能为我们写出get_data()
函数。
我对此的看法是:
def get_...
实际上就是这样,我自动得到的是:
def get_data():
"""
This function is used to get the data for the neural network.
"""
# Load the data
data = np.loadtxt('data.csv', delimiter=',')
# Split the data
x = data[:, :-1]
y = data[:, -1]
# Split the data
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)
return x_train,y_train,x_test,y_test
它看起来确实很整洁,虽然在其他小细节中,x
和y
的解包看起来有点奇怪,但是,它看起来确实像一段只需稍加调整就可以运行的代码。
数据可视化
密谋怎么样?我们能得到一些合成数据的图表吗?
这也是我对模型的输入:
def plotFakeData():
"""
This function creates a fake dataset of some
normally distributed data and plots the result
of passing it through a sin function.
"""
这是我得到的:
def plotFakeData():
"""
This function creates a fake dataset of some
normally distributed data and plots the result
of passing it through a sin function.
"""
import numpy as np
import matplotlib.pyplot as plt
# Create some fake data
x = np.linspace(0, 10, 100)
y = np.sin(x) + np.random.normal(0, 0.1, 100)
# Plot the data
plt.plot(x, y)
plt.show()
看起来很近!我们要测试一下吗?
plotFakeData()
它真的跑了!多酷啊。
米 PHAM 在 Unsplash 上的照片
虽然创建的数据不是正态分布的(我的意思是这只是我脑海中出现的随机现象),但该模型在将数据点通过 sin 函数后,确实向数据点序列添加了正态分布的噪声,之后它成功绘制了数据。
写作测试
现在,为已经定义的函数编写测试怎么样?
这里我的输入是:
def sum_Square(a,b):
return (a+b)**2
def test_sum_Square():
pass
我得到了什么:
def test_sum_Square():
assert sum_Square(2,3) == 25
assert sum_Square(3,5) == 55
assert sum_Square(3,5) != 56test_sum_Square()# Output (from running it on a jupyter notebook)
AssertionError Traceback (most recent call last)
<ipython-input-94-b8fb676bf724> in <module>
----> 1 test_sum_Square()
<ipython-input-93-bf52191596f9> in test_sum_Square()
1 def test_sum_Square():
2 assert sum_Square(2,3) == 25
----> 3 assert sum_Square(3,5) == 55
4 assert sum_Square(3,5) != 56
AssertionError:
还不错!实际上,第一个和第三个测试是正确的,第二个就不那么正确了,因为对于 3 和 5,预期的结果应该是 64。然而,令人印象深刻的是,这个模型实际上仅仅从一个简单的函数定义就可以做这种开箱即用的事情。
照片由加布里埃拉·克莱尔·马里诺在 Unsplash 拍摄
使用 github copilot 获得哲理
在玩了模型的潜在有用应用程序后,我决定,只是为了好玩,问一些随机的伪哲学问题,看看模型会得出什么样的答案。
我的意见:
def writeArticleAboutSecretOfExistence():
pass
我得到了什么:
def writeArticleAboutSecretOfExistence():
"""
The secret of existence is to be one.
"""
这是一篇短文,但至少作为一个句子,它确实有一定的意义。我绝对能想象出一个老哲学家或僧侣给一个在假想的智慧山中某处寻求知识的旅行者提这个建议。
Holly Mandarich 在 Unsplash 上拍摄的照片
当然,这些函数应该是代码,但我只是玩玩而已;).
另一个:
def writeArticleAboutHowToSolveAnyProblem():
pass
我有:
def writeArticleAboutHowToSolveAnyProblem():
"""
The secret of solving any problem is to think about it in another way.
"""
pass
好了,现在你知道了,换个方式想想你的问题,嘣!你解决了!
关于人工智能辅助编程的最后评论
我认为人工智能辅助编程的未来看起来是光明的,尽管要成为现实世界的解决方案还需要解决一些问题。
随着像这样的模型越来越多地了解程序员关于代码的意图,编写好代码所需的时间可能会减少很多,我认为这可能会有惊人的好处,允许程序员专注于更重要的全局问题。
如果你想开始玩 github copilot,注册他们的等待列表以获得技术预览。
如果你喜欢这篇文章,请在媒体、上关注我,订阅我的简讯,在推特、 LinkedIn 、 Instagram 、加入媒体与我联系!谢谢,下次再见!😃
参考
- https://copilot.github.com/
- https://github.com/features/copilot/signup
- https://www . infoworld . com/article/3627319/github-copilot-is-acceptable-and-unright-says-free-software-foundation . html
用 Python 生成二维码,不到 10 行
构建一个简单的 Python 项目,用 QR 码加密您的信息
马库斯·温克勒在 Unsplash 上的照片
在现代世界中,我们的目标是始终拥有一种安全便捷的访问方式。没有人想阅读和点击拉长的 URL 链接或冗长的单词序列。此外,在最近的疫情世界中,人们通常认为最好避免接触,在没有太多身体接触的情况下完成交易。
这一目标是借助条形码和 QR 码实现的。条形码受到一些间距限制,这通过引入 QR 码来解决。QR 码是典型的二维象形码,以在白色背景上排列成正方形图案的黑色模块的形式,为用户提供大存储容量和快速可读性。
二维码是一种极好的资源,可用于跟踪众多产品的信息、交换数据、引导客户访问登录页面或网站、下载应用程序、支付账单(在餐馆或其他地方)、购物、电子商务等等!
在本文中,我们将学习如何利用 Python 编程来创建用于任何特定目的的 QR 码。我们将生成一些用于特定目的的条形码,并通过一些解码步骤了解如何解码这些生成的代码。最后,我们将看看一些额外的东西,你可以完成的编码和解码二维码。
安装所有必需的库:
为了开始这个项目,Python 中有一些库要求,我们将确保在我们的系统上成功安装,以创建、生成和解码 QR 码。我们将安装的第一个二维码编码库是二维码库。
开始安装 qrcode 库模块的命令非常简单,可以使用以下 pip 命令进行安装。如果您相应地设置了环境变量的路径,您可以在您选择的虚拟环境中或者直接在命令提示符(或 windows shell)中添加以下命令行。
pip install qrcode
确保在特定的 Python 环境中也安装了 Pillow 库。这个库是操作图像和处理与视觉美学相关的大多数功能的最佳选择之一。以下命令块中显示的替代命令将安装两个基本库和附加枕形库,用于生成将被存储的 QR 码图像。
pip install qrcode[pil]
我们成功完成这个项目所需的最后一个库是计算机视觉库 Open-CV。下面的库是大多数与图像处理和计算机视觉相关的任务的重要元素之一。本项目的这个模块的目的是利用它的一个重要功能来解码生成的 QR 码中的隐藏信息。该库可以用下面的命令安装。
pip install opencv-python
计算机视觉是数据科学和人工智能最有趣的方面之一。这个主题一直在蓬勃发展,并且在未来几年将会越来越受欢迎。因此,我建议对这一领域感兴趣的观众从下面的链接查看我的 Open-CV 初学者入门指南,开始学习计算机视觉的所有基本概念。
编码您的秘密二维码:
在本文的这一部分,我们将利用 qrcode 库对我们的信息进行编码,并生成一个快速响应代码,我们可以通过一些解码来访问它。要生成二维码,请遵循下面提供的代码片段,您将获得特定二维码的图像以及存储在其中的相关数据。
import qrcode# Create The variable to store the information
# link = "[https://bharath-k1297.medium.com/membership](https://bharath-k1297.medium.com/membership)"
data = "Hello! Welcome To World Of Programming!"# Encode The Link
img = qrcode.make(data)
print(type(img))# Save the QR Code
img.save("test1.jpg")
编码所需代码的第一步是导入我们之前安装的 qrcode 库。导入库后,我们可以创建一个变量来存储特定网站的链接,也可以创建一个变量来存储一些以 QR 码形式嵌入的有用信息。将链接编码成图像的形式,并将现在生成的 QR 码保存在您想要的文件名中。当您打印生成的图像的类型或格式时,您应该注意到显示的以下类—
<class 'qrcode.image.pil.PilImage'>
现在,我们已经学习了如何以 QR 码图像的形式对数据进行编码,让我们探索一些可以解码以下数据的方法。
解码秘密二维码:
作者图片
上面的图像表示是包含链接的 QR 码的表示。如果您试图访问带有 URL 链接的二维码,请尝试使用手机应用程序来解码此类二维码或任何其他应用程序来读取二维码。上面的二维码,当被一个应用程序读取时,会引导你到提供的 URL 网站。(以下链接支持其他作者和我如果申请会员)。
要解码如上图所示的 URL 链接,您可以使用 QR 码扫描仪。但是,如果您试图访问加密数据,您可以在 Open-CV 的帮助下解码信息。QR 码检测器功能为用户提供了解码特定 QR 码图像和检索 QR 码中存储的数据的选项。请查看下面的代码片段,了解您可以执行以下操作的简要想法。
import cv2# Create The Decoder
decoder = cv2.QRCodeDetector()# Load Your Data
file_name = "test1.jpg"
image = cv2.imread(file_name)# Decode and Print the required information
link, data_points, straight_qrcode = decoder.detectAndDecode(image)
print(link)
这里,我们导入 cv2 库并创建一个变量,该变量将作为解码特定 QR 码图像的解码器。然后,我们将继续加载数据,并在 cv2 库的帮助下读取数据。然后我们可以访问数据并相应地打印信息。下面的截图显示了我的输出。注意,我在 tensors 虚拟环境中运行 decode.py 文件中的解码器代码。
其他构建模块:
在本节中,我们将了解您可以对这个 Python 项目进行的一些改进。首先,如果你正在为一个特定的目的开发你的项目,如启动或任何其他服务,或者只是为了好玩,你可以添加一个产品、品牌或你自己的迷你标志作为 QR 码的一个组成部分,以避免混淆,并有一个清晰的项目表示。
我们可以对项目进行的下一个改进是控制生成的 QR 码。下面显示的代码块演示了如何相应地执行这样的过程。版本属性决定了二维码的矩阵大小。使用错误连接属性来分析用于 QR 码扫描的错误校正。方框大小是每个方框的像素大小,边框控制粗细。我建议尝试下面的代码块。
import qrcodeqr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=10,
border=4,
)
结论:
在 Unsplash 上由 Toa Heftiba 拍摄的照片
QR 码在当今的现代世界中非常重要,在这里,大多数交易和有用的数据都是通过最技术化的机制以最少的物理接触来传递的。无论您是想要交换信息、进行交易,还是简化指定特定网站的基本 URL 链接,这些二维码都是非常有用的资源。
在本文中,我们了解了借助 Python 编程,用不到十行代码生成 QR 码是多么容易。安装所需的库后,您可以生成自己的二维码,并对其进行相应的解码。您可以在这些二维码中嵌入有用的 URL 链接或重要信息,并以简单、高度结构化的格式传达给其他人。
如果你想在我的文章发表后第一时间得到通知,请点击下面的链接订阅邮件推荐。如果你希望支持其他作者和我,请订阅下面的链接。
https://bharath-k1297.medium.com/membership
二维码的技术相当具有革命性,它将继续存在,直到有更好的发现取代它。因此,现在是开始探索这个话题的好时机。如果你对这篇文章中提到的各点有任何疑问,请在下面的评论中告诉我。我会尽快给你回复。
看看我的其他一些文章,你可能会喜欢读!
</5-best-python-projects-with-codes-that-you-can-complete-within-an-hour-fb112e15ef44> </7-best-ui-graphics-tools-for-python-developers-with-starter-codes-2e46c248b47c>
谢谢你们坚持到最后。我希望你们都喜欢这篇文章。祝大家有美好的一天!
在 Matlab 和 Numpy 中生成随机数和数组
Matlab 和 Numpy 码再现随机数和数组的比较
正如我们所知, Numpy 是一个著名的 Python 库,用于支持 Python 中的矩阵计算,以及一个大型的高级数学函数集合,用于操作向量、矩阵和张量数组[1]。 Matlab 是一种编程语言和数值计算环境,支持矩阵计算,绘制函数和数据,实现算法,创建接口,以及与其他语言编写的程序接口[2]。
顶部面板:Numpy logo[3];底部面板:Matlab 徽标[4]。
Numpy 和 Matlab 的一个共同特点是它们广泛用于矩阵计算和数值计算。然而,它们并不完全相同。在这篇文章中,我们将讨论如何在 Matlab 和 Numpy 中生成随机数和数组。特别地,我们比较了 Matlab 和 Numpy 对相同随机数和数组的再现。
随机数和数组
Matlab 和 Numpy 都可以根据某个命令生成随机数和数组。有两个关键概念:
- 随机数分布
- 随机种子
对于随机数分布,我们通常考虑均匀分布和标准正态(高斯)分布。在 Numpy 中,我们可以使用numpy.random.rand
来生成均匀分布的随机数。在 Matlab 中,我们可以使用rand
来生成均匀分布的随机数。以下是一些简单的例子:
Python 中的 Numpy:
import numpy as npsample = np.random.rand(2)
print(sample)
输出是:
[0.70573498 0.8595017 ]
Matlab:
sample = rand(1, 2)
输出是:
ans =
0.5390 0.7686
上面的例子是关于均匀分布的随机数。我们可以生成遵循标准正态分布的随机数:
- Python 中的 numpy:
np.random.randn
- Matlab:
randn
可以使用某个命令/函数来生成遵循某个特定分布的随机数,但是每次我们复制代码时,生成的随机数都会不同。因此,随机种子是另一个重要的概念,它允许在每个时间固定随机数。
例如,以下 Python 代码:
import numpy as np
np.random.seed(10)sample = np.random.rand(2)
print(sample)
会产生这些随机数:
[0.77132064 0.02075195]
在 Matlab 中:
rng(10);
sample = rand(1, 2)
我们有以下输出:
sample =0.7713 0.0208
Numpy 和 Matlab 中 Rand 函数的比较
在 Numpy 和 Matlab 中,它们可以处理不同数组的计算:
- 1-D 数组(一维数组)是指向量。
- 2-D 数组(二维数组)指矩阵。
- 3-D 数组(三维数组)指的是三阶张量。
- ……
- n -D 数组(n-维数组)指的是 n 阶张量。
接下来,我们将分别在 Numpy 和 Matlab 中尝试生成均匀分布的随机数。我们还将尝试在 Numpy 和 Matlab 中生成相同的随机数。
生成一维数组
为了在 Numpy 和 Matlab 中获得相同的均匀分布的随机数,我们将向量大小设置为 4,随机种子设置为 10。让我们试试吧!
Numpy :
import numpy as np
np.random.seed(10)sample = np.random.rand(4)
print(sample)
运行它,我们有
[0.77132064 0.02075195 0.63364823 0.74880388]
Matlab :
rng(10);
sample = rand(1, 4)
运行它,我们有
sample = 0.7713 0.0208 0.6336 0.7488
显然,两个生成的随机向量是相同的。
生成二维数组
首先,我们设置矩阵大小为 2 乘 3,随机种子为 10。
Numpy :
import numpy as np
np.random.seed(10)sample = np.random.rand(2, 3)
print(sample)
运行它,我们有
[[0.77132064 0.02075195 0.63364823]
[0.74880388 0.49850701 0.22479665]]
Matlab :
rng(10);sample = rand(2, 3)
运行它,我们有
sample = 0.7713 0.6336 0.4985
0.0208 0.7488 0.2248
生成的均匀分布随机矩阵是相同的。
生成三维数组
首先,我们将矩阵大小设置为 2 乘 3 乘 2,并将随机种子设置为 10。
Numpy :
import numpy as np
np.random.seed(10)sample = np.random.rand(2, 3, 2)
print(‘sample[:, :, 0] = ‘)
print()
print(sample[:, :, 0])
print()
print(‘sample[:, :, 1] = ‘)
print()
print(sample[:, :, 1])
运行它,我们有
sample[:, :, 0] =
[[0.77132064 0.63364823 0.49850701]
[0.19806286 0.16911084 0.68535982]]
sample[:, :, 1] =
[[0.02075195 0.74880388 0.22479665]
[0.76053071 0.08833981 0.95339335]]
Matlab :
rng(10);sample = rand(2, 3, 2)
运行它,我们有
sample(:,:,1) = 0.7713 0.6336 0.4985
0.0208 0.7488 0.2248sample(:,:,2) = 0.1981 0.1691 0.6854
0.7605 0.0883 0.9534
生成的均匀分布的随机张量是相同的。
在 Numpy 和 Matlab 中生成正态分布随机数
在上面,如果我们使用相同的随机种子,Numpy 和 Matlab 可以产生相同的均匀分布的随机数。不幸的是,由于 Numpy 和 Matlab 使用不同的转换来从标准正态分布生成样本,因此我们需要在 Numpy 和 Matlab 中使用相同的转换。
在实践中,仍然可以像 Numpy 一样再现 Matlab 的 randn()的输出。
数量:
import numpy as np
from scipy.stats import norm
np.random.seed(10)sample = norm.ppf(np.random.rand(2, 3))
print(sample)
运行它,我们有
[[ 0.74320312 -2.03846052 0.34153145]
[ 0.67073049 -0.00374237 -0.75609325]]
Matlab:
rng(10);
sample = norminv(rand(2, 3), 0, 1)
运行它,我们有
sample = 0.7432 0.3415 -0.0037
-2.0385 0.6707 -0.7561
生成的正态分布随机矩阵是相同的。
参考
[1]维基百科上的 Numpy:https://en.wikipedia.org/wiki/NumPy
[2] Matlab 上的维基百科:https://en.wikipedia.org/wiki/MATLAB
[3] Numpy 标志来自https://commons.wikimedia.org/wiki/File:NumPy_logo_2020.svg
[5]在 Matlab 和 Python / NumPy 中再现随机数。GitHub 网站:https://github.com/jonasrauber/randn-matlab-python
【6】有没有可能用 NumPy 重现 MATLAB 的 randn()。https://stack overflow . com/questions/3722138/is-may-to-reproduct-randn-of-MATLAB-with-numpy
[7]比较 Matlab 和使用随机数生成的 Numpy 代码。https://stack overflow . com/questions/18486241/comparisng-MATLAB-and-numpy-code-that-uses-random-numbery-generation
使用深度卷积生成对抗网络生成海洋塑料的合成图像
建立一种能够使用 GANs 合成海洋塑料图像的生成方法
训练我们的 DCGAN 模型后生成的合成图像
问题陈述
过去十年,海洋塑料污染一直处于气候问题的前沿。海洋中的塑料不仅能够通过窒息或饥饿杀死海洋生物,而且也是通过捕集二氧化碳使海洋变暖的主要因素。近年来,已经有很多尝试来清理环绕我们海洋的塑料,例如非营利组织海洋清理。大量清理过程的问题是,它需要人力,并且不具有成本效益。已经有很多研究通过使用计算机视觉和深度学习来自动完成这一过程,以检测海洋废弃物,利用 ROV 和 AUV 进行清理。
注意:这是理论上的,我们正在努力发表我们的论文。一旦它被同行评审并在杂志上发表,我会更新这篇文章。所以,请关注我们学术论文的发布空间!
阅读资源 : 我们关于使用 CV 和 DL 检测表层塑料的论文,明尼苏达大学关于通用海洋垃圾检测算法的论文,以及海洋清洁组织关于河流上漂浮塑料检测的论文。
这种方法的主要问题是关于训练计算机视觉模型的数据集的可用性。JAMSTEC-JEDI 数据集是日本沿海海底海洋废弃物的良好集合。但是,除了这个数据集之外,数据集的可用性存在巨大差异。为此,我利用了生成性对抗网络的帮助;具体来说,DCGAN 可以筛选合成数据集,这些数据集在理论上可以是真实数据集的近似副本。(我是从理论上写的,因为有很多变量,如可用的真实图像的质量、GANs 的进展、培训等)。
GAN 和 DCGAN
GANs 或生成对抗网络是由 Ian Goodfellow 等人在 2014 年提出的。GANs 由两个简单的组件组成,称为生成器和鉴别器。该过程的一个过度简化如下:生成器的作用是生成新数据,鉴别器的作用是区分生成的数据和实际数据。在理想情况下,鉴别器无法区分生成的数据和真实数据,从而产生理想的合成数据点。
DCGAN 是上述 GAN 架构的直接扩展,只是它分别在鉴别器和发生器中使用了深度卷积层。最早是由拉德福德等人描述的。al 在论文中用深度卷积生成对抗网络进行无监督表示学习。鉴别器由步进卷积层组成,而发生器由卷积转置层组成。
甘建筑(来源:此处)
PyTorch 实现
在这个方法中,我们将在 DeepTrash 数据集(引用链接:https://zenodo.org/record/5562940#.YZa9Er3MI-R)上应用 DCGAN 架构,在 知识共享署名 4.0 国际 许可下发布。如果你不熟悉 DeepTrash 数据集,可以考虑阅读我的论文一种使用深度视觉模型量化表层绑定塑料的机器人方法。DeepTrash 是海洋表层和深海层塑料图像的集合,用于使用计算机视觉进行海洋塑料检测。
让我们开始编码吧!
代码
安装要求
我们首先安装构建 GAN 模型的所有基本需求,比如 Matplotlib 和 Numpy。我们还将利用 Pytorch 的所有工具(如神经网络、转换)。如果您不熟悉 PyTorch,我建议您阅读这篇文章:
基本安装要求
初始化我们的超参数
这一步相当简单。我们要设置超参数来训练神经网络。这些超参数直接从论文和 PyTorch 关于训练 GANs 的教程中借用。
发生器和鉴别器架构
现在,我们定义生成器和鉴别器的架构。
定义培训功能
在定义了生成器和鉴别器类之后,我们继续定义训练函数。训练函数接受生成器、鉴别器、优化函数和历元数作为参数。我们通过递归调用训练函数来训练生成器和鉴别器,直到达到所需的历元数。我们通过遍历数据加载器,用来自生成器的新图像更新鉴别器,并计算和更新损失函数来实现这一点。
监控和培训 DCGAN
在我们建立了生成器、鉴别器和 train 函数之后,最后一步是简单地调用 Train 函数来获得我们定义的历元数。我还使用了 Wandb 来监控我们的训练。
结果
我们绘制了培训过程中发生器和歧视造成的损失。
训练期间发生器和鉴别器损耗
我们还可以调出生成器如何生成图像的动画,看看真实图像和虚假图像之间的区别。
大概是这样的:
以及训练后的最终结果图像(与上述图像相同)。
结论
在本文中,我们讨论了使用深度卷积生成对抗网络来生成海洋塑料的合成图像,研究人员可以使用这些图像来扩展他们当前的海洋塑料数据集。这有助于让研究人员能够通过混合真实和合成图像来扩展他们的数据集。正如你所看到的结果,GAN 仍然需要大量的工作。海洋是一个复杂的环境,具有变化的光照、混浊度、模糊度等。但这是一个理论起点,其他研究人员可以以此为基础。如果您对改善结果和构建更好的网络架构感兴趣,请联系 gautamtata.blog@gmail.com 大学的我。
用 Copulas 生成综合多元数据
创建更多与您的数据具有相同要素依赖关系的数据
五月在 Unsplash 拍摄的
A Copula 是多元累积分布函数,其中每个变量的边际概率分布在区间[0,1]上是均匀的。
但是这到底是什么意思呢?
当您需要对多元分布的依赖结构进行建模时,可以使用 Copulas。例如,在金融中经常使用来捕捉多个时间序列之间的依赖结构。然而,copulas 在非平稳数据上不是很好定义的。
Copulas 用于模拟随机变量之间的相关性。Copulas 的基础是围绕 Sklar 定理展开的。
斯克拉尔定理:
任何多元联合分布都可以用一元边际分布函数和描述变量相关结构的 copula 来表示。
Sklar 定理(作者供图)
这是什么意思?这意味着数据的多元联合分布可以使用边际和 Copula 进行建模。
好吧,当然,但我为什么要知道这个?为什么理解多元联合分布有帮助?
生成多元数据
在 python 中为单个变量创建概率密度函数非常容易。例如,Scipy 的函数“rv_histogram”生成一个概率分布,您可以根据一些数据从中进行采样。
下面我有一个这样做的例子。首先,我使用虹膜数据集中带有“萼片长度”的 NumPy 直方图生成一个直方图。接下来,使用‘RV _ histogram’函数,我从直方图中创建一个概率分布。最后,利用这种分布,对 100 个值进行采样,并与原始数据集进行比较。
import scipy.stats
import numpy as np
import matplotlib.pyplot as pltbins= 40
hist = np.histogram(df[cols[0]], bins=bins)
hist_dist = scipy.stats.rv_histogram(hist)
synthetic_data = hist_dist.rvs(size=100)
创建萼片长度的概率分布(作者照片)
但是当你想生成多元数据的时候呢?
希望很明显,为每个特征创建数据并将其组合是非常有缺陷的。这里我们可以使用' Copulas ',专门研究 Copulas 的 python 库。这个库提供了相关的函数来为你所拥有的数据创建一个 copula。copula 表示每个特征之间的依赖关系。
使用分类任务,可以在类级别上生成数据。在下面的代码块中,根据每个类的分布开发了不同的多元数据分布。最后,使用这些分布创建新的合成数据。
def generate_multivariate_data(df, dist, samples=50):
df_sample = pd.DataFrame({})
for t in df['target'].unique():
dist.fit(df[df['target']==t].drop(['target'],axis=1))
sampled = dist.sample(samples)
sampled['target'] = t
df_sample = df_sample.append(sampled)
return df_sample
copula 软件包提供了一些有用的可视化工具来比较实际数据和生成的数据。但是,它不支持给每个类添加颜色。
我已经调整了 GitHub 的功能,为每个职业保留了一个彩色地图。以下两个函数为实际数据和合成数据创建了两个 3D 散点图。
from copulas.multivariate import GaussianMultivariatedef scatter_3d_color(data, columns=None, fig=None, title=None, position=None):
"""Plot 3 dimensional data in a scatter plot."""
fig = fig or plt.figure()
position = position or 111
ax = fig.add_subplot(position, projection='3d')
ax.scatter(*(
data[column] for column in columns or data.columns
), c=color_indices, cmap=colormap)
if title:
ax.set_title(title)
ax.title.set_position([.5, 1.05])
return axdef compare_3d_color(real, synth, columns=None, figsize=(10, 4)):
columns = columns or real.columns
fig = plt.figure(figsize=figsize)
scatter_3d_color(
real[columns], fig=fig,
title='Real Data', position=121
)
scatter_3d_color(
synth[columns], fig=fig,
title='Synthetic Data', position=122
)
plt.tight_layout()colors = ["blue", "green", "purple"]
color_indices = [0]*50 + [1]*50 + [2]*50
colormap = matplotlib.colors.ListedColormap(colors) dist=GaussianMultivariate()
df_s = generate_multivariate_data(df, dist)
compare_3d_color(df[cols[0:3]], df_s[cols[0:3]])
高斯多元 Copula(作者供图)
如果每个特征的单变量分布是已知的,则这些分布被传递到 Copula 中。随后的数据样本用单变量高斯分布估计分布。
高斯单变量 Copula(作者供图)
然而,准确地确定数据的分布是相当具有挑战性的。
幸运的是,Copulas 库还为一类分布中的单变量分布估计提供了实用工具。例如,最终图使用参数单变量来生成合成数据。
参数单变量 Copula(作者图片)
数据有多好?
为了比较真实数据和合成数据,我使用剪影分数。轮廓分数是对每个聚类被定义得有多好的度量。当真实标签未知时,该分数用于聚类任务。虽然在这种情况下,标签是已知的,但不执行任何预测。因此,我展示了原始数据的侧影得分与合成数据的得分。
剪影评分 S(作者照片)
根据底层数据的分布,有几种不同的方法来模拟合成数据。
剪影评分比较(作者照片)
当剪影得分为 1 时,聚类的定义最为清晰。然而,即使对于实际数据来说,情况也并非如此。高斯单变量和参数单变量方法得分较高。尽管如此,这里的数据可能不太能代表实际数据。
该过程旨在生成与原始数据集相似的数据。虽然这两种方法表现更好,但多元高斯方法是理想的,因为分数更接近实际数据。目的是模拟实际数据,即使原始数据不是那么可分的。
结论
连接函数是一个迷人的统计函数。对变量之间的依赖结构进行建模的能力对于理解和处理数据是一个有价值的属性。
这些函数还能够生成有效模拟预先存在的多元数据的合成数据。当您想要对多元数据建模或创建一些自定义合成数据时,请考虑使用 copulas。
如果你有兴趣阅读关于新颖的数据科学工具和理解机器学习算法的文章,可以考虑在 Medium 上关注我。
如果你对我的写作感兴趣,想直接支持我,请通过以下链接订阅。这个链接确保我会收到你的会员费的一部分。
https://zjwarnes.medium.com/membership
生成综合表格数据
学习使用条件生成对抗网络(GAN)生成合成表格数据。
海登·邓塞尔在 Unsplash 上拍摄的照片
介绍
在之前的文章中,我们介绍了合成数据的概念及其在数据隐私和机器学习中的应用。在本文中,我们将向您展示如何使用生成式对抗网络(GAN)生成合成表格数据。
表格数据是最常见和最重要的数据形式之一。大量的数据,如临床试验记录、财务数据、人口普查结果,都以表格的形式呈现。在不泄露敏感属性和个人身份信息(PII)的情况下使用合成数据集的能力对于遵守隐私法规至关重要,并且便于数据分析、共享和实验。
想知道为什么生成模型是创建合成数据的理想方法吗?嗯,在生成模型中,神经网络(NN)用于逼近高维潜在空间中输入数据的潜在概率分布。在学习了概率分布之后,该模型可以通过从该分布中随机抽样来生成合成记录。因此,生成的记录不包含原始数据本身,但保留了真实数据集的原始基础概率分布。
什么是甘?
GAN 由两种型号组成:
- 一个学习制造假数据的生成器。
- 学习区分生成器的假数据和真实数据的鉴别器。
这两种模式在零和游戏中相互竞争,推动整个系统走向优化。在训练开始时,生成器不太擅长生成假数据,而鉴别器能够很容易地捕捉到假数据。但是随着训练的进行,生成器逐渐学会更好地生成假数据,欺骗鉴别器,直到鉴别器无法辨别输入是真是假。查看 I.Goodfellow et。艾尔看到了甘背后的数学概念。
表格 GAN:
开发一个能够可靠地为表格数据集工作的通用 GAN 并不是一项简单的任务。
挑战包括:
- 混合数据类型:数字、分类、时间、文本
- 不同的分布:多峰、长尾、非高斯
- 不平衡数据集
为了产生高度真实的表格数据,我们将使用条件生成敌对网络——ctgan⁴.该模型由麻省理工学院的徐等人开发,是一个开源的 CTGAN 使用基于 GAN 的方法对表格数据分布进行建模,并对分布中的行进行采样。在 CTGAN 中,利用特定于模式的规范化技术来处理包含非高斯和多峰分布的列,同时使用条件生成器和采样训练方法来应对类不平衡 problems⁴.
⁴
条件生成器根据其中一个离散列生成合成行。通过采样训练,根据每个类别的对数频率对 cond 和训练数据进行采样,因此 CTGAN 可以均匀地探测所有可能的离散 values⁴.
现在,让我们看看如何利用 CTGAN 从真实数据集生成合成数据集!我们使用 Income⁶人口普查数据集作为示例,该数据集是包中的内置数据集。(记得要pip install ctgan
)。
这将加载真实的数据集:
正如我们所看到的,该表包含了关于在职成年人的信息,包括他们的年龄、性别、教育程度、每周工作时间、收入等。这是一个包含分类变量、连续变量和离散变量的多元数据集。现在让我们使用CTGANSynthesizer
来创建这个表格数据的合成副本。
这将返回一个与真实数据相同的合成数据表。
现在,让我们检查一下合成数据与真实数据有多相似。为此,我们将使用 table_evaluator ⁷来可视化虚假数据和真实数据之间的差异。(一定要先去pip install table-evaluator
每个特征的分布:3 个特征(年龄、职业、每周工作小时数)
真实数据和合成数据之间的相关矩阵
真实数据和合成数据绝对对数平均值和标准差
查看每个特征图的分布、相关矩阵、绝对对数平均值和标准差图,我们可以看到合成记录很好地代表了真实记录。例如,我们还可以运行table_evaluator.evaluate(target_col='income')
来获得每个特性的 F1 分数和 Jaccard 相似性分数。
结论:
在合成数据系列的第二部分中,我们将研究如何使用 CTGAN 生成合成表格数据集。合成数据开启了大规模数据共享、实验和分析的机会,而不会泄露敏感信息。这是一个非常方便的工具!
加入我的 项目 Alesia 了解更多关于机器学习、MLOps、数据隐私、数字福利等更多内容!
参考:
- 古德费勒、伊恩·j .让·普吉-阿巴迪、迈赫迪·米尔扎、徐炳、戴维·沃德-法利、谢尔吉尔·奥泽尔、亚伦·库维尔和约舒阿·本吉奥。“生成性对抗网络。”arXiv 预印本 arXiv:1406.2661 (2014)。
- https://www . freecodecamp . org/news/an-intuitive-introduction-to-generative-adversarial-networks-gans-7a 2264 a 81394/
- 徐,李,斯科拉利杜,米,因方特,a .,& Veeramachaneni,K. (2019)。使用条件 gan 对表格数据建模。arXiv 预印本 arXiv:1907.00503。
- 徐,李,斯科拉利杜,米,因方特,a .,& Veeramachaneni,K. (2019)。使用条件 gan 对表格数据建模。arXiv 预印本 arXiv:1907.00503。
- https://github.com/sdv-dev/CTGAN
- https://archive.ics.uci.edu/ml/datasets/adult
- https://pypi.org/project/table-evaluator/
- 由 Prateek Sanyal 提供的编辑评论
用随机游走生成合成时间序列数据
快速创建定制的合成数据来测试您的预测模型
在 Unsplash 上由 Podu Stricat 拍摄的照片
R 随机游走是随机过程(random)。它们由数学空间中的许多步骤组成。最常见的随机游走从值 0 开始,然后每一步以相等的概率加上或减去 1。
随机行走可用于为不同的机器学习应用生成合成数据。例如,当没有信息可用或没有实时数据可用时,具有随机游走的合成数据可以近似实际数据。
本帖利用一维随机游走为时序算法生成数据。
生成数据
创建和测试时间序列模型时,以随机数据作为基线来测试模型是有益的。随机游走可以模拟股票、产能利用率甚至粒子运动的趋势。
通过调整每一步的概率,行为被添加到随机行走中。此外,这些走步被修改为具有不同的步长,以产生更大或更小的波动。
Pandas 中的“日期范围”功能可以快速生成时间序列数据。以下是 2019 年每天用一个随机值生成数据框的示例。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import randomDATE_START = '2019-01-01'
DATE_END = '2019-12-31'dates = pd.date_range(DATE_START, DATE_END)
df = pd.DataFrame({
'date': dates,
'value': np.random.normal(0,1,dates.size)
})
df.set_index('date', inplace=True)
plt.plot(df['value'])
plt.ylabel('Value')
plt.xlabel('Date')
plt.title('Random Values')
plt.show()
一段时间内的随机值(作者提供照片)
随机漫步
虽然这里的数据可用于时间序列模型,但看不到任何模式。由于实际数据包含与先前点的紧急模式关系,合成数据需要改进。随机行走是生成一些逼真行为的可行解决方案。在 pandas 中创建随机行走需要遍历数据帧的每一行。行走中的每一步都依赖于前一步。
下面是生成随机漫步的代码。第一个“previous_value”作为遍历的起点。接下来,步长设置为 1。最后,“阈值”将积极或消极行走的概率设定为 50%。
此外,随机游走受最小值和最大值的限制。对于许多数据集,如股票价值,这些值是严格正值。
随机游走的图是用“matplotlib”生成的
def random_walk(
df, start_value=0, threshold=0.5,
step_size=1, min_value=-np.inf, max_value=np.inf
):
previous_value = start_value
for index, row in df.iterrows():
if previous_value < min_value:
previous_value = min_value
if previous_value > max_value:
previous_value = max_value
probability = random.random()
if probability >= threshold:
df.loc[index, 'value'] = previous_value + step_size
else:
df.loc[index, 'value'] = previous_value - step_size
previous_value = df.loc[index, 'value']
return df
步长为 1 的随机漫步(作者提供图片)
修改随机漫步
这些随机游走被调整以显示期望的行为。例如,对随机游走的最小值和最大值添加限制可以模拟容量利用率。
随机游走的行为通过改变其他初始条件而被进一步改变,例如,强加一个整体的正趋势。通过调整概率阈值来实现正向趋势。通过增加正向步进的概率,正向趋势被强加于随机行走。对于这个代码,它是通过降低阈值来实现积极的一步。
以这种方式建立随机游走可以更接近股票趋势。如果总体趋势是积极的或消极的,可以将细节纳入综合数据。
具有积极趋势和价值限制的随机游走(作者提供图片)
有几个选项可以进一步调整随机游走。例如,在每一步中包含高斯噪声或将步长增加到较大的值会导致不同的行走跨越较大的空间。但是,还有一些其他的调整会导致非常不同的行为。
- 随着时间的推移增加波动性是通过在每步之后少量增加步长来实现的。因此,随着时间的推移,步长会慢慢变大。
- 也可以通过修改步长来实现行走的平滑,但是也可以在正步长之后增加步长,在负步长之后减小一个小值。
波动性越来越大、步伐越来越平稳的随机漫步(作者供图)
结论
随机漫步是一个有趣的随机过程。在很少的起始条件下,产生了许多不同的模式。因此,随机漫步可以用作合成的时间序列数据,并针对您的特定问题实例进行调整。
这篇文章展示了随机漫步的一些可能的调优选项。
如果你有兴趣阅读关于新颖的数据科学工具和理解机器学习算法的文章,可以考虑在 Medium 上关注我。
如果你对我的写作感兴趣,想直接支持我,请通过以下链接订阅。这个链接确保我会收到你的会员费的一部分。
https://zjwarnes.medium.com/membership
用零触发变压器模型生成文本分类训练数据
实践教程
所以你的文本分类 NLP 项目没有任何带标签的数据?只需使用零炮变压器模型生成数据
作者图片
零镜头文本分类确实是一项变革性的技术。这些模型可以将文本分类到任意类别,而无需任何微调[1]。与传统的监督文本分类学习方法相比,这种技术提供了两个主要的好处。首先,它们使得在标记数据不存在时执行文本分类成为可能,因为不需要微调。接下来,单个模型可以用来分类成千上万个不同的标签。
然而,零镜头文本分类模型通常很大。例如,最流行的零镜头文本分类模型之一就是基于 BART-large transformer 架构,该架构拥有超过 400 M 个参数。本文将讨论如何使用零镜头文本分类模型来生成训练数据,然后使用生成的训练数据来训练仍然表现良好的较小模型。因此,这将允许 NLP 实践者训练更小的模型,通过降低硬件要求和能耗,这些模型可以更容易地在生产中实现。
相关作品
自我标记是数据科学中一项被广泛研究的技术。基本概念是使用带标签的数据集来帮助标记未标记的数据集,以便您有更多的训练案例[2]。已经有工作在使用 BERT 的微调版本来确定使用强化学习的训练案例的标签[3]。我相信本文中讨论的方法与其他方法不同,因为它涉及零标记训练案例,并且其主要目的是使用大模型来帮助产生小模型。
处理
让我们讨论一下这个系统的整体流程。首先,需要未标记的数据。在这些实验中,我使用了一个名为斯坦福情感树库 V2 (SST2)的数据集,它可以通过 Hugging Face 的数据集分发网络获得。该数据集包含电影评论的文本以及两个潜在标签中的一个,以指示该评论是“正面”还是“负面”但是,我们不需要为了这个培训过程而使用标签。
零射击模型需要两个输入:标签列表和文本。在这种情况下,我们将提供“正面”和“负面”标签以及电影评论文本。然后,对于每种情况,模型将输出两个标签的分数。因为我们知道评论只能属于两个潜在标签中的一个,所以我们选择得分最高的标签。
在这一点上,我们有一个数据集,其中包含由零触发分类器产生的标签。值得注意的是,并非所有的标签都是正确的,因为零镜头文本分类模型不具有 100%的准确性。但是,我们仍然可以使用这个数据集来训练监督学习模型。因此,我们将使用名为 TextBlob 的包来训练一个简单的朴素贝叶斯分类器。
最后,可以使用已经标记为评估数据的原始数据集来评估该模型。在没有带标签的评估数据的情况下,我想你可以遵循一个类似的过程,使用零镜头文本分类模型来产生评估标签。然而,这种方法不会给你一个确定的模型精度。
作者图片
实验
零射击模型
首先,让我们讨论零镜头文本分类模型的准确性。在拥抱脸的模型分发网络上下载量最高的两个零镜头文本分类模型被用于实验:“typeform/distilbert-base-uncased-mnli和“ facebook/bart-large-mnli ”在包含 872 个案例的 SST2 数据集的整个“验证”集上对它们进行了评估。正如预期的那样,BART 模型表现更好,精度为 0.8819,而 DistilBERT 模型的精度为 0.7592。
用零射击训练监督模型
由于简单性和大小,使用 TextBlob 来训练朴素贝叶斯分类器。这种模型使用“传统的”NLP 分类技术,比深度学习方法(如 Transformers)需要的资源少得多。
下面是显示结果的图表。提醒一下,产生训练集的模型达到了 0.8819 的精度,更小的零炮模型达到了 0.7592 的精度。朴素贝叶斯分类器随着训练案例数量的增加而不断改进,最终精度为 0.7603。
全监督模型
零炮数据生成方法不可避免地导致一些病例被错误标记。因此,我假设与数据完全正确标记的情况相比,这会对性能产生负面影响。为了测量负面影响,我进行了如上所述的相同实验,除了我在生成的标签上使用了实际的标签。令我惊讶的是,这款机型的表现只是稍微好一点。下表给出了清晰的对比。
未来的工作
更强大的监督模型:
在本文中,我们介绍了如何使用生成的训练数据来训练朴素贝叶斯。然而,其他文本分类模型可能会执行得更好,同时仍然比初始零镜头模型小得多。我用 1000 个生成的训练案例进行了一个实验,用快乐变形金刚训练distilt-Bert-base-uncased。该模型使用默认设置获得了 0.7856 的精度。然而,随着我增加训练示例的数量,模型并没有实质性的改进,这可能是过度拟合的迹象。在未来,我计划进行额外的实验,以找到更好的超参数配置。
阈值设定:
应用阈值可以潜在地提高性能,并允许更容易地收集数据。可以添加一个条件语句来拒绝确定性较低的情况。因此,这可能会提高性能,因为更少的错误标记的案例将用于微调。此外,这可用于解析大量数据,其中大部分数据与目标标签无关。
迭代次数:
标记数据可以在迭代中完成,其中在每次迭代之后,使用监督模型来标记未被零炮模型发现的情况。所以,假设零拍模型的起始准确率是 90%。然后标注 1000 个训练案例,训练监督模型,它的准确率可能是 80%的准确率。这两个模型可以组合起来标记另外的 1000 个训练案例,并且该过程可以随着监督模型的准确性的增加而继续。最终,可能不再需要零剂量模型来标记病例,这将大大提高效率。
观点
我设想未来对人工标注数据的需求会大大减少。随着时间的推移,有理由假设零镜头文本分类模型的规模和质量都将提高。虽然我只是触及了应用这种技术的表面,但我已经展示了这种技术可以产生具有良好性能的模型,它只需要初始零炮模型的计算需求的一小部分。
参考资料:
[1]尹等,基准零镜头文本分类:数据集、评估和蕴涵方法(2019),EMNLP-IJCNLP 2019
[2]特里盖罗等,半监督学习的自我标记技术:分类学、软件和实证研究(2015), Knowl Inf Syst 42
[3]叶等,基于强化自训练的零镜头文本分类(2020),2020.acl-main
密码
https://github.com/Vennify-Inc/zero-shot-data-generation
如果你有自然语言处理研究的经验,并且相信这个实验的原创性不足以导致发表论文,请联系我。
原载于 2021 年 6 月 23 日https://www . vennify . ai。
模拟 F. Pessoa 的递归神经网络
使用 Tensorflow 和 Keras 的深度学习应用
1.介绍
离散令牌序列可以在许多应用中找到,即文本中的单词、音乐作品中的音符、图像中的像素、强化学习代理中的动作等【1】。这些序列通常在连续或邻近的记号之间表现出很强的相关性。句子中的单词或单词中的字符的相关性表达了潜在的语义和语言特征。序列 x_n 中的下一个令牌可以建模为:
其中 x_i 表示序列中的第 I 个令牌。在自然语言处理(NLP)中,这些被定义为语言模型。通常,每个令牌代表一个单独的单词或字母。生成的输出是一个概率分布,我们可以从中采样以生成序列中的下一个令牌。这些模型也被称为循环的,因为我们可以循环地应用这个生成过程来创建全新的令牌序列。
经常用于处理离散记号序列问题的一种特定类型的生成模型是递归神经网络(RNN)。在更简单的神经网络中,固定维度的特征表示被不同的非线性函数变换几次。在 RNN 中,这些变换也会在时间上重复,这意味着在每个时间步长,都会处理新的输入,并生成新的输出。它们可以有效地捕获输入序列的语义丰富的表示【2】。RNN 在不同的环境中展示了这种能力,例如生成结构化文本、原始图像(基于每像素),甚至在在线服务上模拟用户行为。
我们的任务是生成类似训练语料库的原始文本。这是一项无人监督的任务,因为我们无法访问任何标记或目标变量。我们首先创建一个单词嵌入,将每个字符映射到一个参数化维度的向量。对于每一个字符,该模型查找其嵌入情况,并将结果输入一个长短期记忆(LSTM)层堆栈,这是一种特殊类型的 RNN。这些被开发来扩展 RNNs 的传统能力,以模拟长期依赖性和对抗消失梯度问题。我们网络的输出是一个密集层,其单元数量等于词汇量。我们没有为这一层定义激活函数;它只是为词汇表中的每个字符输出一个 logit。我们使用这些值在以后从分类分布中取样。
在本文中,我们使用了费尔南多·佩索阿的作品,他是 20 世纪最重要的文学人物之一,也是葡萄牙语中最伟大的诗人之一。这个数据集现在可以在 Kaggle 上公开获得,包括 4300 多首诗歌、散文和其他作品。
图 1:佩索阿的肖像,1914 年— 来源
本文属于使用 TensorFlow 进行深度学习的系列文章:
- 应用于辛普森图像数据集的迁移学习和数据增强
- 基于 F. Pessoa 的工作用递归神经网络生成文本
- 使用 Seq2Seq 架构和注意力的神经机器翻译(ENG to POR)
- 残差网络从无到有应用于计算机视觉
2.数据预处理
该数据集包括作者用自己的名字写的几篇文章,但也使用不同的异名和假名。每个人都有自己的写作风格,单独学习会很有趣。然而,为了有效地训练深度神经网络(DNN),我们需要一个大的数据集,这就是建立单一模型的原因。
F.佩索阿年轻时曾在南非生活过一段时间,在那里他接触到了英语。这就是为什么他的部分作品是用英语写的。为了避免引入噪声,我们从训练数据集中移除了大部分英语文本。
import pandas as pd
import numpy as np
from tensorflow.keras.preprocessing.text import Tokenizer
import tensorflow as tf
import ast
import os
import json
import matplotlib.pyplot as plt
from nltk import tokenize
import seaborn as snsf_pessoa = pd.read_csv(os.getcwd() + '/f_pessoa_v2.csv')
texts = f_pessoa.copy()
# Removing all pseudonyms that wrote in English.
texts = texts[~texts['author'].isin(['Alexander Search', 'David Merrick', 'Charles Robert Anon', 'I. I. Crosse'])]
texts['text'] = texts['text'].apply(lambda t: ast.literal_eval(t))
texts = texts.reset_index().drop('index', axis=1)
texts = texts['text'].tolist()
texts = np.concatenate(texts)
texts = np.asarray(texts)
texts_p = " ".join(texts)
# we will be truncating large texts soon, so this code only tries to reduce the
# sequence size by splitting the texts that seem to be significantly larger than
# the rest. Otherwise, we try to use the structure provided in the data itself
_, ax = plt.subplots(1, 2, figsize=(15, 5))
mylen = np.vectorize(len)
sns.histplot(mylen(texts), bins=50, ax=ax[0])
ax[0].set_title('Histogram of the number of characters in each \nchunk of text BEFORE splitting sentences', fontsize=16)
large_texts = texts[mylen(texts)>350]
large_texts_p = " ".join(large_texts)
large_texts = tokenize.sent_tokenize(large_texts_p)
texts = np.concatenate((texts[~(mylen(texts)>350)], large_texts))
ax[1].set_title('Histogram of the number of characters in each \nchunk of text AFTER splitting sentences', fontsize=16)
sns.histplot(mylen(texts), bins=50, ax=ax[1]);
print(f'Length of texts dataset: {len(texts_p)} characters')Length of texts dataset: 5811145 characters
图 2:分句前(左边)和分句后(右边)每块文本的字符数直方图。
清理文本后,我们最终得到了超过 580 万个字符。请注意,为了避免在规范化序列的文本长度时丢失数据,我们按句子分割了最大的序列。序列长度分布的差异可以在上面的直方图中看到。我们可以预览一些片段。
print(texts[97:106])['O burburinho da água' 'O burburinho da água' 'No regato que se espalha'
'É como a ilusão que é mágoa' 'Quando a verdade a baralha.'
'— A única vantagem de estudar é gozar o quanto os outros não disseram.'
'— A arte é um isolamento. Todo o artista deve buscar isolar os outros, levar-lhes às almas o desejo de estarem sós. O triunfo supremo de um artista é quando a ler suas obras o leitor prefere tê-las e não as ler. Não é porque isto aconteça aos consagrados; é porque é o maior tributo (...)'
'— Ser lúcido é estar indisposto consigo próprio. O legítimo estado de espírito com respeito a olhar para dentro de si próprio é o estado (...) de quem olha nervos e indecisões.'
'A única atitude intelectual digna de uma criatura superior é a de uma calma e fria compaixão por tudo quanto não é ele próprio. Não que essa atitude tenha o mínimo cunho de justa e verdadeira; mas é tão invejável que é preciso tê-la.']
更重要的是,我们可以评估独特字符的数量,这是我们的词汇量。
vocab = sorted(set(texts_p))
print(f'{len(vocab)} unique characters in texts')156 unique characters in texts
在训练之前,我们需要将字符串转换成一些数字表示。我们从记住一些重要的方面开始对文本进行标记。我们考虑了无限数量的令牌,并在角色级别创建了它们。我们没有过滤任何字符,并保持原来的大写。然后,我们使用标记器将文本映射到编码序列。
def create_character_tokenizer(list_of_strings):
tokenizer = Tokenizer(filters=None,
char_level=True,
split=None,
lower=False)
tokenizer.fit_on_texts(list_of_strings)
return tokenizer
tokenizer = create_character_tokenizer(texts)
tokenizer_config = tokenizer.get_config()
word_counts = json.loads(tokenizer_config['word_counts'])
index_word = json.loads(tokenizer_config['index_word'])
word_index = json.loads(tokenizer_config['word_index'])
def strings_to_sequences(tokenizer, list_of_strings):
sentence_seq = tokenizer.texts_to_sequences(list_of_strings)
return sentence_seq
seq_texts = strings_to_sequences(tokenizer, texts)
我们可以看到这种编码的一个例子。
print('Original sequence: \n' + texts[0] + '\n')
print('Encoded sequence: ')
print(seq_texts[0])Original sequence:
Diana através dos ramos
Encoded sequence:
[46, 6, 3, 8, 3, 1, 3, 9, 7, 3, 19, 26, 5, 1, 10, 4, 5, 1, 7, 3, 11, 4, 5]
我们还需要标准化序列的长度,为此我们定义了 300 个字符的长度。小于 300 的序列用零填充,而大于 300 的序列被截断。
mylen = np.vectorize(len)
print(max(mylen(texts)))
print(np.round(np.mean(mylen(texts))))1377
71.0def make_padded_dataset(sequences):
padded_sequence = tf.keras.preprocessing.sequence.pad_sequences(sequences,
maxlen=300,
padding='pre',
truncating='pre',
value=0)
return padded_sequence
padded_sequences = make_padded_dataset(seq_texts)
RNN 通过接收字符序列并预测序列中的下一个字符来工作。在训练时,模型接收一个输入序列和一个移位一的目标序列。
例如,表达式Diana através dos ramos
是我们数据集上第一首诗的第一节。这首诗来自 Ricardo Reis,他是 F. Pessoa 的许多别称之一。给定输入,Diana através dos ramo
正确的预测是iana através dos ramos
。请注意,预测与输入的长度相同。
我们采取的另一个决定是将我们的 RNN 构建为有状态的,这意味着它的内部状态跨批维护。为了提高效率,我们需要确保每个批处理元素都跟随前一个批处理的相应元素。
def create_inputs_and_targets(array_of_sequences, batch_size=32):
input_seq = array_of_sequences[:,:-1]
target_seq = array_of_sequences[:,1:]
# Prepare the batches and ensure that is ready to be fed to a stateful RNN
num_examples = input_seq.shape[0]
num_processed_examples = num_examples - (num_examples % batch_size)
input_seq = input_seq[:num_processed_examples]
target_seq = target_seq[:num_processed_examples]
steps = int(num_processed_examples / 32)
inx = np.empty((0,), dtype=np.int32)
for i in range(steps):
inx = np.concatenate((inx, i + np.arange(0, num_processed_examples, steps)))
input_seq_stateful = input_seq[inx]
target_seq_stateful = target_seq[inx]
# Split data between training and validation sets
num_train_examples = int(batch_size * ((0.8 * num_processed_examples) // batch_size))
input_train = input_seq_stateful[:num_train_examples]
target_train = target_seq_stateful[:num_train_examples]
input_valid = input_seq_stateful[num_train_examples:]
target_valid = target_seq_stateful[num_train_examples:]
# Create datasets objects for training and validation data
dataset_train = tf.data.Dataset.from_tensor_slices((input_train, target_train))
dataset_train = dataset_train.batch(batch_size, drop_remainder=True)
dataset_valid = tf.data.Dataset.from_tensor_slices((input_valid, target_valid))
dataset_valid = dataset_valid.batch(batch_size, drop_remainder=True)
return (dataset_train, dataset_valid)
train_data, valid_data = create_inputs_and_targets(padded_sequences)
3.递归神经网络
我们首先定义了一个嵌入层,将我们的字符索引转换成固定大小的密集向量。值得注意的是,填充值在这一层被屏蔽,这意味着它们被简单地忽略。接下来,我们堆叠了两个单向有状态 LSTM 层,每个层有 512 个单元。这些层具有学习长期依赖性的潜力;然而,训练它们在计算上是昂贵的。在它们之间,我们引入了一个辍学层。最后,最后一层为词汇表中的每个字符输出一个 logit。这些是根据模型的每个字符的对数似然性。请注意,我们总共有大约 4M 个参数需要训练。
def get_model(vocab_size, batch_size):
model = tf.keras.Sequential([
tf.keras.layers.Embedding(input_dim=vocab_size, output_dim = 256, mask_zero=True, batch_input_shape=(batch_size, None)),
tf.keras.layers.LSTM(units=512, return_sequences=True,stateful=True),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.LSTM(units=512, return_sequences=True,stateful=True),
tf.keras.layers.Dense(units=vocab_size)
])
return modelbatch_size=32
model = get_model(len(tokenizer.word_index) + 1, batch_size)
model.summary()Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding (Embedding) (32, None, 256) 40192
_________________________________________________________________
lstm (LSTM) (32, None, 512) 1574912
_________________________________________________________________
dropout (Dropout) (32, None, 512) 0
_________________________________________________________________
lstm_1 (LSTM) (32, None, 512) 2099200
_________________________________________________________________
dense (Dense) (32, None, 157) 80541
=================================================================
Total params: 3,794,845
Trainable params: 3,794,845
Non-trainable params: 0
_________________________________________________________________checkpoint_callback=tf.keras.callbacks.ModelCheckpoint(filepath='./models/ckpt',
save_weights_only=True,
save_best_only=True)
model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['sparse_categorical_accuracy'])
history = model.fit(train_data,
epochs=30,
validation_data=valid_data,
callbacks=[checkpoint_callback,
tf.keras.callbacks.EarlyStopping(patience=2)])Epoch 1/30
2023/2023 [==============================] - 1041s 512ms/step - loss: 0.5216 - sparse_categorical_accuracy: 0.3516 - val_loss: 0.3298 - val_sparse_categorical_accuracy: 0.5669
[...]
Epoch 18/30
2023/2023 [==============================] - 1031s 510ms/step - loss: 0.2495 - sparse_categorical_accuracy: 0.6478 - val_loss: 0.2756 - val_sparse_categorical_accuracy: 0.6268def model_history(history):
history_dict = dict()
for k, v in history.history.items():
history_dict[k] = [float(val) for val in history.history[k]]
return history_dict
history_dict = model_history(history)
4.结果
即使使用 GPU,训练也非常慢(尽管与 CPU 相比,训练时间减少了 15 倍),回想一下,我们只堆叠了两个单元数量有限的 LSTM 层。从下图中,我们可以看到训练和验证数据集的准确性快速增加,然后在几个时期内稳定攀升。我们的回调最终被执行(当超过 2 个时期验证准确性没有增加时)以停止训练过程。没有过度合身的迹象。
def plot_history(history_dict):
plt.figure(figsize=(15,5))
plt.subplot(121)
plt.plot(history_dict['sparse_categorical_accuracy'])
plt.plot(history_dict['val_sparse_categorical_accuracy'])
plt.title('Accuracy vs. epochs')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.xticks(np.arange(len(history_dict['sparse_categorical_accuracy'])))
ax = plt.gca()
ax.set_xticklabels(1 + np.arange(len(history_dict['sparse_categorical_accuracy'])))
plt.legend(['Training', 'Validation'], loc='lower right')
plt.subplot(122)
plt.plot(history_dict['loss'])
plt.plot(history_dict['val_loss'])
plt.title('Loss vs. epochs')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.xticks(np.arange(len(history_dict['sparse_categorical_accuracy'])))
ax = plt.gca()
ax.set_xticklabels(1 + np.arange(len(history_dict['sparse_categorical_accuracy'])))
plt.legend(['Training', 'Validation'], loc='upper right')
plt.show()
plot_history(history_dict)
图 3:RNN 模型几个时期的精确度和损耗演变。
model = get_model(len(tokenizer.word_index) + 1, batch_size=1)
model.load_weights(tf.train.latest_checkpoint('./models/')).expect_partial()
def get_logits(model, token_sequence, initial_state1=None, initial_state2=None, initial_state3=None):
token_sequence = np.asarray(token_sequence)
if initial_state1 is not None:
# set states for all recurrent layers
model.layers[1].states = initial_state1
model.layers[3].states = initial_state2
model.layers[5].states = initial_state3
else:
model.layers[1].reset_states()
model.layers[3].reset_states()
model.layers[5].reset_states()
logit = model.predict(token_sequence)
logit = logit[:,-1,:]
return logit
def sample_token(logits):
pred = tf.random.categorical(logits, num_samples=1).numpy()[0]
return pred[0]
为了从我们的模型生成文本,我们需要指定一个种子字符串来启动网络。接下来,我们标记初始字符串并重置网络状态。然后,该字符串被转换为批量大小为 1 的张量,以提供给我们的模型。我们使用上一时间步的预测来构建分类分布,然后从中进行采样。使用我们的网络的相同状态和先前采样的令牌,我们可以重复预测步骤,直到我们获得具有指定大小的最终序列。
由此产生的原文分析起来还是挺有意思的。请记住,我们的 RNN 不得不从很小的数据集开始学习葡萄牙语。除了用葡萄牙语书写的实例之外,没有向模型提供诸如句法或语义的明确信息。对于这项任务来说,数据集也相当小。然而,还是有一些有趣的经验值得注意。比如在标点符号方面,引号的使用是正确的,表现出对要求开、闭的理解。在诸如"desassessego no poderia!…falências no meu Cora o…或“As can es…um sono de ouvir…Fico tanto!…" 我们几乎可以理解费尔南多·佩索阿的一些无房可住的情况。另一方面,我们看到意义或意图不是 RNN 可以捕捉到的,我们也可以识别一些拼写错误。
init_string = 'Desassossego'
num_generation_steps = 500token_sequence = tokenizer.texts_to_sequences([init_string])
initial_state_1, initial_state_2, initial_state_3 = None, None, None
input_sequence = token_sequence
for _ in range(num_generation_steps):
logits = get_logits(model,
input_sequence,
initial_state1=initial_state_1,
initial_state2=initial_state_2,
initial_state3=initial_state_3)
sampled_token = sample_token(logits)
token_sequence[0].append(sampled_token)
input_sequence = [[sampled_token]]
initial_state_1 = model.layers[1].states
initial_state_2 = model.layers[3].states
initial_state_2 = model.layers[5].states
print(tokenizer.sequences_to_texts(token_sequence)[0][::2])**Desassossego não poderia!... Falências no meu coração... Esse reer sobre os braços dos meus caminhos e ignorantes possamos «exensação simbólica» e em Natureza, e a noite nova da ausência de cada? Não pense de bem entendida uma orientada prosa). V. como fui... As canções... é um sono de ouvir... Ficção tanto!... Vejo outro olhar pela Tristeza da cadeira, rainha para a Carta, a noite. Depois no paganismo que se sente no espaço real e de criar uma pedra de tradição sociológica para implicar o de Aristoclator S**
5.结论
对于这项任务,数据的预处理是具有挑战性的。我们需要确保我们的输入序列以合适的方式编码,以便 RNN 有效地捕获可用的语义表示。训练 rnn 在计算上是昂贵的,所以我们决定保持结构尽可能简单。
我们能够生成葡萄牙语文本,除了诗人的作品之外,无需向模型提供任何关于该语言的结构信息。该模型学习了语言的一些基本结构,同时保留了我们可以认为类似于训练语料库的细微差别。
这种方法可以通过增加模型的深度和每层中单元的数量来扩展。还可以调整批次大小等超参数来提高准确性。我们测试了以写作形式区分的可能性,一个 DNN 用散文文本训练,另一个用诗歌文本训练。结果并不令人满意,因为 DNNs 无法生成具有连贯结构的文本。我们把它作为未来的工作。
保持联系: LinkedIn
6.参考
【1】——【德·布姆等人,2018】德·布姆,c .、德·梅斯特,t .、Dhoedt,B. (2018)。实践中的字符级递归神经网络:训练和采样方案的比较。神经计算与应用,31(8):4001–4017。
【2】——【苏茨基弗等人,2011 年】苏茨基弗本人、马滕斯律师和辛顿律师(2011 年)。用递归神经网络生成文本。ICML 11,第 1017-1024 页,麦迪逊,威斯康星州,美国。全媒体。
【3】—https://www . ka ggle . com/Luis Roque/the-complete-literal-works-of-Fernando-pes SOA
在 Ampere 架构上使用 NVIDIA StyleGAN2-ADA for PyTorch 生成您自己的图像
来自:《我的世界》,70 年代的科幻艺术,假日照片和鱼
StyleGAN2 ADA 允许您训练神经网络,以基于一组训练图像生成高分辨率图像。这方面最经典的例子就是 StyleGAN2 经常用来生成的化妆脸。直到 2021 年 2 月的最新版本,你必须安装旧的 1.x 版本的 TensorFlow,并使用 CUDA 10。这一要求使得很难在 NVIDIA 最新的基于安培的 GPU 上利用 StyleGAN2 ADA。在这篇文章中,我将向你展示如何在 Windows 中使用这个新版本的 StyleGAN,不需要 Docker 或者 Linux 的 Windows 子系统(WSL2 )!
我已经训练过 GANs 产生各种不同的图像类型,你可以从上面我的 GANs 中看到一些例子。我在 GitHub 上提供预先训练的模型来制作这些图像:
你可以利用上述网络,只使用谷歌在线 Colab,为自己生成这些图像。
硬件先决条件
gan 是计算密集型的,这是无法回避的。英伟达的研究人员在 DGX 系统上扔了 8 个 V100s 来训练人脸。StyleGAN 还可以跨多个 GPU 进行线性扩展,因此,StyleGAN 可以在一台机器上使用任何硬件。我在这里展示的图像是在一台双 Quadro RTX 8000 上训练的。
ThinkStation P920 中的双 Quadro RTX 8000
对于本文,我假设我们将使用最新的 CUDA 11 和 PyTorch 1.7.1。NVIDIA 建议 GPU 上 12GB RAM;但是,如果您使用较低的分辨率,例如 256x256,也可以使用更低的分辨率。分辨率较高的 gan 一般以 1024x1024 训练。单个强劲的 GPU,比如一个英伟达 RTX A6000 也做得很好。
我们将在 WSL2 或 Docker 之外安装 StyleGAN2。这提供了最高的性能。相信我,有了 GANs,你想要你机器能提供的每一点计算!
首先,确保您的显卡安装了最新的 NVIDIA 驱动程序:
第二,安装最新版本的 CUDA 11。如果 CUDA 12 已经发布,而我还没有更新这篇文章,那么就要谨慎行事。查看 StyleGAN2 ADA PyTorch 说明,了解版本的最新更新。
还需要安装 Visual C++,这样 StyleGAN 就可以编译定制的 CUDA 内核。可以在以下 URL 找到 Visual Studio Community edition。确保你安装的是 C++,在微软的安装程序中默认是不启用的。
安装 Visual Studio 后,您必须向系统路径和环境变量中添加几项。您可以通过运行以下批处理程序来实现这一点:
- c:\ Program Files(x86)\ Microsoft Visual Studio <version>\ Community \ VC \ Auxiliary \ Build \ VC vars 64 . bat
我建议打开一个 power shell 窗口,进入该目录并运行命令“vcvars64”
PyTorch 装置
要安装 PyTorch,您需要在系统上安装 Python。我建议要么安装 Miniconda,要么安装 Anaconda。Miniconda 很小,你必须安装需要的软件包。Anaconda 很大,但是包含了你所需要的大部分东西。
如果您甚至在争论安装哪个,或者您从未听说过 Anaconda 和 Miniconda 之间的区别,那么几乎可以肯定,Anaconda 是您的正确答案。
StyleGAN 团队推荐 PyTorch 1.7.1 用于 StyleGAN。根据 PyTorch 引入的“突破性变化”的数量,以后的版本可能会起作用。PyTorch 的安装过程令人惊叹,请浏览以下 URL 并选择您的选项:
我选择:
- 稳定
- Windows 操作系统
- 点
- 计算机编程语言
- CUDA 11
这导致了以下命令:
pip install torch===1.7.1+cu110 torchvision===0.8.2+cu110 torchaudio===0.7.2 -f https://download.pytorch.org/whl/torch_stable.html
NVIDIA StyleGAN2 ADA PyTorch 安装
实际的 NVIDIA StyleGAN2 ADA 包通过 GitHub 在以下存储库分发:
您可以选择下载一个 ZIP 文件,该文件应该被解压缩到一个目录中。还可以用命令行 git 命令获得 StyleGAN。
git clone [https://github.com/NVlabs/stylegan2-ada-pytorch.git](https://github.com/NVlabs/stylegan2-ada-pytorch.git)
在撰写本文时,StyleGAN 还没有提供 requirements.txt 文件来指定所需的包。当您运行 Python 脚本时,您会看到关于缺少包的错误,只需 pip 安装它们。为了让你开始,这些是我找到的:
pip install click
pip install tqdm
pip install requests
pip installimageio
pip installpsutil
pip installscipy
训练 GAN
为了训练 GAN,您必须将所有图像转换为具有相同大小和维度的 PNG,并且具有非常具体的目录结构。这可以通过 StyleGAN 提供的 dataset_tool 脚本来完成。在这里,我转换所有的 JPEG 图像,我获得了训练甘生成鱼的图像。
python dataset_tool.py --source c:\jth\fish_img --dest c:\jth\fish_train
接下来,您将实际训练 GAN。这是通过以下命令完成的:
python train.py --data c:\jth\fish_train --outdir c:\jth\results
训练可能需要很长时间,在训练过程中,您会看到在训练过程中创建的图像,这些图像显示了当前的效果。下图显示了我的《我的世界》GAN 在 2,800 kimg 时的情况,这意味着它在这一点上已经对超过 2800 张图像(包括真实图像和增强图像)进行了训练。
图像设置检查点为《我的世界》甘在 2800 公斤
生成图像
随着培训的进行,pickle 快照将由您的生成器和鉴别器组成,以与生成的每个映像集检查点相对应。例如,network-snapshot-002800.pkl 生成了上面的映像检查点。要从该网络生成图像,请使用以下命令。
python generate.py --outdir=out --trunc=1 --seeds=85,265,297,849 \
--network=network-snapshot-002800.pkl
种子指定要生成的单个图像,每个种子是一个单独的图像。
YouTube 视频
如果你想看这些步骤的执行,我也有同样材料的 YouTube 视频。
结论
如果你有培训的硬件,NVIDIA StyleGAN2 ADA 是一个生成你自己的图像的好方法。新的 PyTorch 版本使其易于在 Windows 环境下运行。按照本文中的步骤,您可以快速建立一个环境来训练您自己的 GANs。
生成性对抗性模仿学习:优势与局限
与强化学习和非穷举用例列表的区别
Alex Perri 在 Unsplash 上的照片
越来越多的人工智能项目依赖于学习观察和行动之间的映射。出于战略和技术原因,从演示中学习将在开发几个用例(机器人、视频游戏、自动驾驶汽车)中发挥至关重要的作用。
在我最近的项目中,我有机会对生成性对抗性模仿学习(GAIL)有了深入的了解。作为团队的一员,我的目标是利用 GAIL 帮助机器人预测和理解人类的安全行为。
在这篇文章中,我将解释生成性对抗性模仿学习,介绍它的优势,并解释这种方法的局限性。
学习人类决策策略的重要性
正如几位计算机科学研究人员所解释的那样,“为了做决定,人类创造了特定的规则/习惯。例如,我们中的一些人根据首选的路线或交通方式来决定。出于这个原因,机器准确地模仿人类在各种场景中的行为是非常重要的,例如,玩视频游戏等。
通过模仿学习有助于用最少的任务专家知识来教授复杂的任务。
通过模仿学习的能力可以为许多需要实时感知和反应的潜在人工智能应用打开大门,如机器人、自动驾驶汽车、人机交互和视频游戏。
然而,需要专门的算法来有效地学习模型。事实上,通过模仿来学习也带来了一系列挑战。不幸的是,对于复杂的任务,这往往是具有挑战性的描述,强化学习(RL)方法有局限性。
模仿教学的概念并不新鲜。由于计算技术的进步和智能应用需求的增长,这个想法最近受到了关注。
一些“最近”的算法,如生成对抗模仿学习,证明了使用深度神经网络(DNNs)从人类的行为数据中学习人类决策策略的成功。
然而,“这种基于 DNN 的模型在本质上是“黑盒”模型,很难解释这些模型从人类那里学到了什么知识”( 2 )以及它们如何做出这样的决定,这在模仿学习文献中没有涉及。
模仿学习技术“旨在在给定的任务中模仿人类行为”( 3 )。
通用模仿学习方法( 4 )可以减少教授任务以提供演示的问题,而不需要显式编程或设计特定于任务的奖励函数。
正如各种研究论文中提到的那样,生成对抗模仿学习展示了“在有限数量的用例中取得了巨大的成功,尤其是在与神经网络参数化相结合时”( 5 )。与强化学习不同,GAIL 从专家(人)的演示中学习策略和奖励函数。
生成性对抗性模仿学习
简单来说,GAIL 是一种逆向强化学习(IRL)算法。顾名思义,它是基于生成对抗网络(GANs)的。 GAIL 可以定义为一种无模型的模仿学习算法。与其他无模型方法相比,该算法在模拟复杂行为方面表现出了令人印象深刻的性能增益,尤其是在大型高维环境中。
逆向强化学习 (IRL)是通过观察代理的行为来学习其目标、价值观或报酬的领域。
在 GAN ( 6 )中,我们有两个网络:发生器和鉴别器。生成器的作用是通过学习输入数据集的分布来生成新的数据点。鉴别器的部分是对给定的数据点是由生成器生成的(学习分布)还是真实的数据分布进行分类。
由于 IRL 和 GAN 概念的结合,GAIL 可以从少量专家轨迹中学习。事实上,GAIL 的目标是训练具有与给定专家相似行为的生成器。同时,鉴别器可以作为强化学习的奖励函数,用来判断行为是否像专家。
GAIL 代表了学习顺序决策策略的一种有前途的方法。与强化学习(RL)不同,GAIL 使用专家(例如,人类)的演示数据,并学习未知环境的政策和奖励函数。
作为一种无模型的模仿学习方法,生成性对抗模仿学习(GAIL)能够很好地概括未知情况,并处理复杂问题。
正如在一个实验( 6 )中提到的,“将 GANs 应用于模仿学习的一个基本属性是,生成器永远不会接触到真实世界的训练示例,只会接触到鉴别器。这种情况允许 GAIL 最小化将专家演示翻译到目标代理领域的问题”。
在 GAIL 的案例中,鉴别者学会了从专家的演示中辨别生成的表演。同时,发生器试图模仿专家来愚弄鉴别器,使其认为它的表现是专家的演示。
盖尔和逆强化学习 由于不同的原因,盖尔并不完全是 IRL。因为 GAIL 是直接从数据中学习策略,而不是奖励函数。尽管有这个因素,GAIL 比行为克隆表现得更好,有时甚至比专家更好,因为它在进行强化学习,并且它不会被限制总是接近专家。
RL 方法需要明确定义的奖励函数,它告诉代理他们做得有多好。不幸的是,在大多数现实世界的情况下,奖励函数通常很难定义。
引入 IRL 来帮助 RL 学习专家的策略,并从给定的专家轨迹中获取奖励函数来解释专家的行为。然而,对于大多数经典的 IRL 方法,需要提供大量的专家轨迹,但在很多情况下,这些轨迹并不容易得到。
其他一些模仿学习方法的局限性
行为克隆
(从状态到动作的映射)。此外,小错误会随着时间的推移而加剧(级联错误)。此外,行为克隆通常具有较差的泛化能力,精确地复制动作,即使它们与最终任务无关,并且可能无法理解专家的动作是有目的的并且有最终目标。
逆向强化学习 这种方法学习一种成本函数,该函数将整个轨迹优先于其他轨迹。主要问题是“许多现有的 IRL 方法需要解决一系列计算量大的强化学习问题,因为它们具有双层优化的性质。因此,它们通常无法扩展到大型和高维度环境”( 7 )。最后但同样重要的是,IRL 的运营成本很高。
用例
尽管深度强化学习已成功应用于各种任务,但为复杂任务手动设计合适的奖励函数仍具有挑战性且成本高昂。
大多数涉及 GAIL 的项目目前都应用于简单的环境中( 8 ),在这些环境中,具有手工制作功能的全连接神经网络已经工作得很好了。
具体地说,代理从专家演示和自我探索中学习“接近最优”行为而无需显式奖励函数设计的想法已经应用于几个机器人操作( 9 )或运动任务( 10 )。
再者,GAIL 也被用于电子游戏行业,尤其是在相对复杂的没有手工制作特色的游戏中模仿特定玩家( 11 )。
盖尔的问题
尽管结果很有希望,盖尔背后的理论仍然鲜为人知。根据我的经验,GAIL 很难从多模态演示中学习到好的策略。事实上,它似乎假设所有的演示都来自单个专家,无法提取演示。
对抗性模仿学习在许多环境中都取得了成功。然而,“对抗方法被证明是不稳定的,并且在低数据量的情况下,可能需要很长时间才能收敛”( 12 )。
一些作者( 13 )介绍了逆向 RL 技术 AIRL ,认为“盖尔未能推广到不同环境的动力学”。根据他们的实验,AIRL 对环境动态的变化更有抵抗力。
要了解更多信息,我推荐以下链接:
- 从不同来源模仿学习人形
- 生成性对抗性模仿学习
- 生成性对抗性模仿学习的呈现
- TextGAIL:用于文本生成的生成性对抗模仿学习
- 生成性对抗性模仿学习的最新进展
- 关于生成性对抗性模仿学习的计算和推广
- 通过生成性对抗性模仿学习来模仿复杂环境中的智能体
- 通过原始深度输入和生成性对抗性模仿学习进行社交兼容导航
- xGAIL:可解释的生成对抗模仿学习,用于可解释的人类决策分析
- 模仿学习:学习方法综述
- 损耗退火盖尔对样本高效稳定的模仿学习
- 生成性对抗性模仿学习(盖尔)
生成性对抗网络 101
如何构建一个简单的 GAN
自 2014 年首次提出以来,生成性对抗网络(简称 GANs)就成为了机器学习社区的头条新闻。基于一个巧妙简单的想法,GANs 很快成为产生人造图像的最先进的方法,这些图像现在与真实图像无法区分。他们不仅在生成人工智能艺术或人脸老化等有趣的任务中找到了应用,还在更实际的应用中找到了应用,如数据匿名化、提高照片分辨率等。在这篇文章中,我将解释 GAN 是如何工作的,我们将构建一个非常简单的 GAN 来生成新的口袋妖怪物种。我们开始吧!
关于甘斯
GANs 首先由 Goodfellow 等人提出,并被迅速开发以发现大量令人着迷的用例,例如生成人脸的逼真图片、图像到图像的翻译(想想在图片中的一匹马身上画条纹以使它成为斑马),或者衣服翻译(如果你想知道你穿同样的毛衣,但却是红色的高领毛衣会是什么样子)。他们甚至允许我们在图片上做算术:取一个戴眼镜的男人减去一个不戴眼镜的男人加上一个不戴眼镜的女人的图像,你会得到一个戴眼镜的女人的图像,从这个图像中你可以生成多个不同的戴眼镜的女人的图像。请查看这篇伟大的博文,获取更多 GAN 应用示例图片。看看这只猫。
一只不存在的猫,由 https://thiscatdoesnotexist.com/的生成。
这只猫既不喵喵叫也不咕噜咕噜叫。它不吃也不喝。因为它不存在。就像无数其他不存在的被甘斯创造出来的猫一样。你可以自己生成一些,只需导航到thiscatdoesnotexist.com。每次刷新页面,都会生成一个新的 cat。对于人或住宿也有类似的页面(虽然有些房间看起来还是有些毛骨悚然!).
甘斯直觉
GANs 基于一个有趣的简单想法:让两个神经网络相互竞争,希望竞争能推动它们走向精通。
GANs 背后的想法:让我们让两个神经网络相互竞争,希望竞争能推动它们走向精通。
总体目标是生成与训练数据中的内容无法区分的内容,例如图像。人们可以将这一思想应用于任何类型的数据,但是在本文中我们将重点关注图像。为了实现这一目标,我们需要两个独立的模型:
- 一个发生器,以随机噪声为输入,并以此为基础生成图像;
- A d 是鉴别器,它将图像作为输入(真实的或由生成器生成的),其工作是将它们分类为真实或虚假。
生成器的目标是生成逼真的图像来欺骗鉴别器,而鉴别器的目标是从真实图像中分辨出假货。将这两个模型拟人化是很有帮助的,把生成器想象成一个艺术品伪造者,把鉴别器想象成一个警察调查员,去抓捕伪造者。这两个网络的这些相互冲突的目标应该确保每一个在训练期间逐渐变得更好。最终,生成器将有望生成逼真的图像。
GAN 的示意图。图片由作者提供。
发电机👨🎨
发生器最简单的形式可以是一个微小的神经网络,它接受输入的噪声向量,将它传递几层,并以图像的形式输出一个张量。当处理图像时,我们通常会使用卷积层,但训练卷积 gan 本身也会带来挑战,因此为了这个介绍性示例的目的,让我们使用一个简单的前馈网络,基本上是一个多层感知器。
我们将使用口袋妖怪精灵数据集来生成我们自己的口袋妖怪物种。以下是一些示例图像。使用这个笔记本,你可以自己生成更多的样本。
口袋妖怪精灵数据集的样本。
让我们的生成器接受 64 个随机数的输入向量,输出一个形状为 49696 的向量(口袋妖怪 pics 是 96*96 像素,4 个颜色通道)。生成器的输出层将是一个 sigmoid 激活,以便它生成 0 到 1 之间的数字来匹配原始图像中的像素值。PyTorch 实现可能看起来像这样。随着单元数量的增加,您可以随意尝试添加更多的 linear-batchnorm-relu 块。
鉴别器👮♀️
鉴别器将是另一个小型神经网络,其任务是获取大小为 49696 的输入向量,该输入向量包含真实图像或虚假的发生器输出,并分类为两者之一。我们可以这样实现它。
同样,随意堆叠更多的层,例如从nn.Linear(4*96*96, 2048)
开始,每次继续将层大小分成两层。
培养
棘手的部分来了:如何训练这两个网络,使它们都能很好地学习自己的任务?关键是一前一后地训练它们,只用一个损失函数。损失函数的选择取决于鉴别器,因此我们可以使用二进制交叉熵损失,这是二进制图像分类的典型选择(在未来的帖子中,我将讨论使用更好的损失函数的更高级的 GANs)。让我们首先初始化两个模型,损失和优化器。
这个PokemonDataset
物体是我创作的,你可以在 GitHub 上找到它。现在,训练循环。我们对时期和批次进行迭代,对于每批训练数据,我们将梯度归零,计算鉴别器的损失,并更新模型的权重。接下来,我们对发电机做同样的事情。
剩下的问题是如何计算每个模型的损失。在上面的代码片段中,这是由定制的get_disc_loss()
和get_gen_loss()
函数处理的。让我们看看他们怎么做。
鉴频器损耗
第一,鉴频器的损耗。我们可以按照以下步骤计算它:
- 产生一些随机噪声,并将其馈送到发生器。这会产生一批假图像。
- 使用鉴别器将这些假图像分类为假的或真的。然后,用它对一批真实图像进行分类。这就产生了两组分类:赝品和真品。
- 使用零(“假”)作为基本事实标签,将“假损失”计算为假图像鉴别器输出的二进制交叉熵损失。接下来,计算“真实损失”,作为鉴别器输出真实图像的二进制交叉熵损失,使用 1(“真实”)作为基本事实标签。
- 将总损失计算为假损失和真损失的平均值。
这由下面的函数来处理。
发电机损耗
现在,让我们对发电机的损耗进行编码。这个会简单得多。我们只需要生成噪声,将其馈送到生成器以获得假图像,使用鉴别器对它们进行分类,并使用 1(“真实”)作为地面真相标签来计算这些分类的二进制交叉熵。我听到你问为什么是一个。回想一下,生成器的目标是欺骗鉴别器。当它产生假图像时,它希望它们被归类为真实的——每当不是这样时,生成器就会遭受损失。换句话说,如果鉴别器将每个发电机的输出分类为实数,那么发电机的损耗将为零。这个想法在下面的函数中实现。
现在我们有了所有的构建模块,我们可以运行训练循环。你可以在这个笔记本里自己运行(代码是根据 Coursera 的生成对抗网络(GANs)专门化由 Sharon Zhou 等人编写的)。在训练过程中,我们可能会时不时地给生成器输入一些噪声,看看它输出了什么。下面的图片显示了 GAN 生成的口袋妖怪在训练开始时,在几百个纪元后,以及在训练的很晚时候。
GAN 在训练开始时(左)、训练后期(中)和后期(右)生成的口袋妖怪。
跟你预想的不太一样?我们来看看为什么!
为什么这么模糊
生成器很快了解到,它应该专注于图像的中心区域,并保持背景白色。在训练的早期,它一直在图像中间产生噪点。随着训练的进行,一些熟悉的形状变得清晰可见。甚至后来,一些假的口袋妖怪出现了,它们类似于训练数据中的那些,尽管是以一种模糊的方式(你可以认出每个人最喜欢的皮卡丘,在中间一行和最右边一列!).如果你已经期待一个更现实的输出,不要放弃希望。让我们看看模型的哪些部分需要改进。
有几个,但其中两个最引人注目。首先,我们使用了一个简单的前馈网络来处理图像,这是相当次优的。切换到卷积神经网络应该会有很大帮助。第二,我们用于 gan 的二元交叉熵损失证明不是最佳选择;我会在另一篇文章中解释为什么会这样,以及什么样的损失函数会更好。
先说前者。查看下一篇文章,在这篇文章中,我们将 GAN 向前推进了一步,在生成器和鉴别器中添加了卷积,以构建所谓的深度卷积 GAN 或 DCGAN!
感谢
这个简单 GAN 的训练循环代码以及损失计算函数的灵感来自于 Coursera 的由 Sharon Zhou 等人提出的生成对抗网络(GANs)专门化。
感谢阅读!
如果你喜欢这篇文章,为什么不在我的新文章上 订阅电子邮件更新 ?通过 成为媒介会员 ,你可以支持我的写作,并无限制地访问其他作者和我自己的所有故事。
需要咨询?你可以问我任何事情,也可以在这里 预定我 1:1 。
你也可以试试我的其他文章。不能选择?从这些中选择一个:
**
生成性对抗网络服务于安全和网络安全
提高自动驾驶汽车安全性和网络安全性的新人工智能方法
照片由来自 Pexels 的 Tara Winstead 拍摄
未知的未知对于自动驾驶汽车来说是一个重大的安全困境。问题是如何确定哪些驾驶场景在整个开发过程中还没有考虑到。自动驾驶汽车的验证需要尽可能多地识别和测试未知场景。在为自动驾驶汽车开发网络安全时,我们必须回答同样的问题。在项目的早期阶段,总有一些可能的未知攻击需要考虑和解决。然而,安全开发活动倾向于离线分析、设计、实现和验证。预测未来可能的攻击还不是安全和安保发展的最新水平。应用人工智能方法来预测潜在的未来攻击或失败是最好的解决方案。
机器学习领域中的生成对抗网络(GAN)是一种保护系统免受攻击和构建更安全系统的新方法。 GAN 可以从输入的数据集学习生成新的样本,与标注的真实世界数据进行比较,决定它们是真实的还是虚假的。 GAN 由两个神经网络、一个生成器和一个鉴别器组成。GAN 是一种在许多应用中使用的生成方法,例如人脸或卡通人物的生成以及许多其他摄影应用。
这种方法还可以生成虚假信息、图像等。,这是社会不能接受但又不可避免的。网络安全措施应比网络攻击至少领先一步,以区分真实或虚假的信息、图像或视频。
发生器对鉴别器
生成器负责生成新样本,鉴别器在将生成的样本与标记的真实数据进行比较时起分类作用。生成器和鉴别器模型都必须在训练时优化分类率。鉴别器模型最小化分类错误率,生成器模型最大化分类错误率。
生成器和鉴别器都知道训练数据集,它们是真实世界的数据,但是生成器的输出包含真实和虚假的数据。鉴别器必须使用半监督方法对其进行分类。数据科学家同时训练两个模型。如果鉴别器中的分类失败,则应该使用反向传播来更新生成器模型的参数。发生器和鉴别器模型优化相同的参数,但基于零和概念相反。
GAN 确保自动驾驶汽车技术安全性的方法
黑客攻击无人驾驶车辆比司机在车内的车辆更关键。根据攻击类型,攻击者可以修改车辆导航、反应、收集特定传感器数据等。从现有攻击中学习是 GAN 方法中非常相似的概念。生成器根据已经观察到的攻击创建新的可能攻击。
GAN 可以生成真实的流量场景,以改善系统验证或稳健的系统行为。利用传感器建模,我们可以将 GAN 应用于生产更可靠的产品。
在本文中,我没有区分安全性和安全性,因为两者都可能导致开发人员必须评估的危险。安全性和安全性的区别在于攻击者的意图。安保和安全的共同点多于差异。
GAN 建议在以下使用案例中作为网络安全或安全措施:
图像处理:
GAN 生成的合成数据有助于验证用于对象分类或用户认证的图像处理模块。这同样适用于由照相机捕获的图像数据。生成器可以生成许多在真实世界环境中难以找到或模拟的真实图像。例如,使用深度学习分类算法可以将限速标志错误分类为不同的限速,如欧盟委员会的自动驾驶汽车测试和认证报告中所述。本报告提出了一种 GAN 方法来消除对抗性扰动。
基于场景的验证:
出于多种原因,自动驾驶汽车需要一种新的验证方法,例如,出于安全和安保原因,驾驶员无法承担责任作为汽车中的后备解决方案。另一个目的是在设计和验证时缺乏关于未知场景的知识。识别这种最糟糕的情况对自动驾驶汽车验证团队来说是一个重大挑战,以确保所有关键情况都已经得到分析,并对危险做出充分的响应。正如这篇论文中所描述的,GAN 可以生成新的、现实的轨迹。GAN 方法从图像域调整到时域以创建有效的轨迹。
稳健性的提高:
我们需要全自动驾驶汽车中的更多传感器,而不是汽车中的辅助功能,例如部分自动驾驶汽车中的车道辅助。因此,自动驾驶汽车更容易受到网络攻击的影响。我们应该在安全方面保证系统在受到攻击时的健壮性。这篇论文描述了一种提高系统鲁棒性的 GAN 方法。这种方法使用了不正确的数据,违反了与其他道路使用者保持安全距离的安全目标。自动驾驶汽车使用 GAN 方法验证距离变化,强化学习算法决定与其他道路使用者保持适当的距离。
传感器建模:
使用真实世界的数据来验证和确认自动驾驶汽车的传感器是一项复杂的任务。为了验证自动驾驶汽车,必须模拟可能的场景。这篇论文讨论了 GAN 方法在传感器生产中的应用。这种传感器建模方法有意制造生产传感器误差,以发现长期相关性。
如何保持数据的可靠性
任何数据都是攻击场景的来源。使用 GAN 方法可以更容易地区分真实数据和虚假数据。一个已经学会生成分类错误率很低的数据的高级生成模型,可以生成虚假的数据来欺骗任何系统,检查目标系统是否对合成攻击足够健壮。
GAN 可以成为评估人员论证系统抵御网络攻击能力的工具。不仅针对已识别的攻击场景,而且针对犯罪分子尚未使用的未来可能的攻击场景的流程。这种方法是一种新趋势,将很快对安全和安保标准以及开发活动产生重大影响。随着 GAN 方法的发展,我们也为攻击者提供支持,并为他们配备新武器。我们必须找到一种解决方案,至少领先网络攻击者一步。
GAN 的许多衍生产品,如 CGAN(条件性 GAN)、WGAN (Wasserstein GAN)和 LSTM-GAN(长期短期记忆 GAN),以及其他几种基于生成和判别模型的产品,都可以处理和解决安全问题。像 GAN 这样的生成过程对于开发应用程序的工程师来说是一个有价值的工具,在这些应用程序中,数据增强有助于提高功能的质量、可用性和效率。
https://medium.com/subscribe/@bhbenam
生成性对抗网络(GANs)——从直觉到实现
图片由纸
生成对抗网络
形式上,GANs 被定义为两个神经网络在一场游戏中相互竞争(在博弈论的意义上,经常但不总是以零和游戏的形式)。给定一个训练集,这种技术学习生成具有与训练集相同的统计数据的新数据。这个定义似乎非常数学化,如果你对实现算法更感兴趣的话,这可能不是很有用。在这篇博客中,我将为你提供算法如何工作以及你如何实现算法的直觉。
与普通的神经网络相比,GANs 可以生成质量更好的新数据。我们可以把它描述为两个网络相互竞争,这种竞争导致更好的结果,因为双方都在试图击败对方。
它的应用非常有趣,它使我们能够解决许多现实世界的问题。让我们先看看它的一些应用
- 生成与真实人脸惊人相似的人脸。
- 图像到图像的转换——给定边缘的图像,网络可以生成物体的彩色图片,或者给定夜间条件下的图片,它可以将其转换为白天条件,这在自动驾驶中有巨大的用途。
图片由纸制成
- 修复——给定一个失真的图像,它可以生成完整的图像,这在视频后处理、受损视频恢复和视频编辑中有很大的应用。
物体去除,图像由纸
GIF by LGTSM
现在让我们更深入地了解 GANs。根据形式定义,我们知道在这个算法中有两个网络。其中一个称为发生器,另一个称为鉴别器。
生成器网络生成具有某种统计属性的数据。我们希望统计特性与我们想要得到的输出类型相同。例如,在从夜晚到白天的图像到图像的翻译中,它应该能够正确地生成白天的图像。而在生成新的人脸时,它应该能够给出类似于真实世界人脸等的输出。
下面的代码是生成器的架构。它接受一个固定大小的随机输入(random_size ),然后生成一个扁平的图像(大小为 heightwidth 的 1D 数组),为了从输出中可视化图像,我们必须将输出向量整形为适当的(height,width)。在这里,我为生成器架构使用了完全连接的层。*
发电机架构
鉴别器充当发生器的评论(稍后解释)。它的主要工作是,给定一个特征点/图像,它试图将该特征点/图像分类到所需的类别中。例如,给定一幅图像,鉴别器将试图把给定的图像分类为真实的或伪造的(这里生成器的输出可能是伪造的)。在领域自适应的情况下,它试图将给定的特征分类为源或目标领域特征。
下面,代码是鉴别器的架构。它是将一幅展平的图像(shape - > heightwidth)作为输入,然后将输入分类为真假。这里我使用了完全连接的层。*
鉴别器架构
既然我们已经看到了单个模型的角色,那么让我们看看它们是如何互相帮助的。
仅培训生成器
让我们假设我们有一个经过训练的鉴别器,即它可以正确地将图像分类为真的和假的(通常情况下不是这样),并且我们只训练我们的生成器。然后我们用这个评论作为反馈,用生成器生成接近真实的图像。考虑发电机的培训过程如下:
- 最初,由于神经网络权重的随机初始化,会产生一些随机输出(用 G(z) 表示)。当这个通过鉴别器时,它肯定会被鉴别器分类为假的。
当我们开始训练时(图片由作者提供)
- 最后,当我们已经训练了生成器模型时,我们希望输出非常类似于训练数据集,即我们的鉴别器应该将生成器的输出(G(z))分类为实数。
训练结束时(图片由作者提供)
为了训练发生器,我们通过将 G(z) 的标签作为真实数据,使用来自鉴别器的输出来计算损耗,即我们强制发生器产生鉴别器可以分类为真实的输出。这样鉴别器就帮助了发生器。为了更好地说明,请看下面的损失公式:
发电机损失(图片由作者提供)
理想情况下,对于真实图像,鉴别器的输出为 0,而对于伪图像,其输出为 1。为了最小化上述损失,输出 D(G(z)) 应该接近 0,即我们正在训练发生器,以便其输出被鉴别器分类为实数。
下面的代码显示了生成器的训练方案。发生器 G(z)的输出被馈送到鉴别器,然后通过将输入到鉴别器的标记作为真实图像来计算损耗。然后,该损耗用于更新发电机的参数。
训练生成器
仅训练鉴别器
现在让我们假设我们有一个生成假图像的生成器,即输出质量很差,我们只训练我们的鉴别器。训练鉴别器与训练普通分类器是一样的。当我们的输入是假图像时,它分类为假,当输入是真实的(即来自训练数据)时,它分类为真实。
训练鉴别器(图片由作者提供)
鉴别器丢失(由纸成像)
上面的损耗公式强制鉴别器将真实输出分类为 1,将伪造/生成的输出分类为 0。
下面是鉴别器的训练方案,我们首先将真实图像(来自训练数据)馈送给鉴别器,并通过将这些图像的标签视为真实来计算损失。然后,我们将假图像(生成器的输出 G(z))馈送到鉴别器,并通过将 G(z)的标签视为假来计算损失。
训练鉴别器
现在我们已经讨论了如何分别训练生成器和鉴别器。然而,在现实世界中,我们必须同时训练他们两个。
完整的训练
考虑一下,两个网络最初都有随机权重。首先,我们通过将生成器的输出分类为假来训练鉴别器,将训练数据分类为真,并且只更新鉴别器的参数。然后,我们训练生成器,其中使用鉴别器,我们尝试将生成器的输出( G(z) )分类为实数,并仅更新生成器的参数。现在,如果我们的训练是稳定的,并且一切按预期进行,那么当鉴别器的输出对于训练数据和来自生成器的输出相同时,即鉴别器不能区分两者时,我们可以停止训练。
训练甘
这样,我们就完成了对 GANs 的介绍。我希望这个博客能让你对 GANs 的工作有一个好的直觉。完整的实现可以在下面的 GitHub 仓库中找到。
https://github.com/harsh-99/PyTorch-Tutorials/blob/master/GANS.ipynb
成为 介质会员 解锁并阅读介质上的许多其他故事。关注我们的 媒体 阅读更多此类博文。
生成人工智能:作为虚构与现实之间桥梁的视觉搜索
在三个用例中。
Same.energy 界面,作者截图
什么是真理?
F 首先,请告诉我,什么是虚构,什么是现实——在生成对抗网络的背景下?
我们已经看到了很多东西,在它的人工智能驱动的创造之前是不存在的。可以肯定的是, 中 GAN 生成的图像这个人不存在 或者 这个艺术品不存在 在物质世界中没有直接的参照物——它们是知识和 AI 模型训练的产物。但是当它们被传送到我们的世界,它们可能会有自己的故事,特定的意义,特定的用途,离开潜在的空间,变得比小说更真实。
的确,你可以用它们制作电影。你也可以制造欺诈和假货。错用不怪 AI,怪我们人类。你不能通过破坏技术来修复社会。
然而,在数字时代,重要的是要区分生成性和非生成性项目,防止假货,并利用艺术力量,直到现在不存在的可能性。
这里有三个用例可以启发你或者提高你的意识。
案例 1: StyleGAN2 投影
StyleGAN2 的研究人员有一个内置的“后门”,或者可以将 GAN 生成的图像追溯到潜在空间: StyleGAN2 投影。
如果您尝试将图像识别为生成图像,这可能非常有用。我不得不说,用 style gan 2Colab Notebooks和art breader(其中使用了 StyleGAN2-model,在 FFHQ-faces 上训练过)玩久了,你可以学习直觉来检测可能是生殖性的肖像。
但是使用投影你也可以做到。
以下是检测生成性图像并利用潜在空间发现它的最佳示例:
当然,原始图像在这里已经够怪异了。将它与另一幅肖像进行比较:
如你所见,找到的肖像是不一样的。为什么?因为我用其他工具修改了它,比如 ArtBreeder(混合各种图像,包括我的照片)。这是这张图片的“系谱树”:
Artbreeder,作者截图
这是 StyleGAN2-Projection 的第一个也可能是一个重大缺陷。要检测 1:1 的图像,应满足以下条件:
- StyleGAN2 应该生成没有任何修改的图像
- 您必须知道哪个数据集用于您正在应用投影的 StyleGAN2。
StyleGAN2 投影是一个很大的可能性,但可以用几种方式欺骗;所以才不靠谱。然而,它可以作为第一个工具使用——在特定情况下,它可能是有益的。
你可能会想起“亨特·拜登阴谋”的故事,主角是马丁·阿斯彭,他声称有证据证明这是一场捏造的破坏政治形象的亲特朗普运动。然而,马丁·阿斯彭并不存在;他的脸是由 StyleGAN2 生成的,这是 StyleGAN2 的投影:
正如你所看到的,这些面孔并不完全相同——这个故事背后的政治幕后操纵者可能使用了 StyleGAN2,但做了一些修改。
但即使这种方法不是 100%有效,也应该强调的是,人工智能研究人员将许多努力投入到防止人工智能解决方案被滥用的可能性中(即使是事后的,如假检测)。
旁注:毕竟,你可以出于艺术需要使用 StyleGAN2 投影,在不这样的地方寻找人脸。它与 Pareidolia 方法一起工作,可能会产生一些迷人/或可怕的结果:
案例 2:使用反向图像搜索的假货检测
另一种检测假图像的方法是反向图像搜索。这里有一个使用俄罗斯搜索引擎 Yandex 回溯假货的绝佳用例:
在这种情况下,从“此人不存在”页面获取的人脸用于搜索相同的图像。于是一个伪造的公司网页被发现了,上面有几张 GAN 生成的脸:
老实说,有两点:
- 这可能不一定是欺诈或伪造的,只是另一个即将开业的公司分支机构的模型,或者仍然没有同事的照片。例如,前面提到的在别尔哥罗德办公室的公司职员看起来很普通,不像甘。可能这只是另一个——我们,人类,西方——对俄国制造的假货的偏见。即使不存在这样的情况,我们也会发现它们的另一种情况</pareidolia-of-ai-dba7cf44bfde?sk=f22677820ca169764e2c076fea98ee6e>***或选择性知觉。不是所有的俄罗斯都是假的;不是所有的假货都是俄罗斯的。顺便说一句。将 GAN 的图像用于实体模型是一个非常明显的想法:你不需要购买股票图像,并且你的实体模型员工的脸不会在完全不同的产品上重复出现,如股票女孩“Ariane”。比较这个出租不存在,一个使用 StyleGAN2 faces 作为用户账号的生成页面(更像是一个实验)。*****
- 如果这可能是一个骗局,这不仅仅是 Yandex 的特色,也不仅仅是俄罗斯的问题。唯一的问题是:Yandex 确实比谷歌(Google)更擅长寻找 GAN 的面孔。
谷歌搜索可能是查找全球虚假公司的一个好办法,但它也有缺陷:
作者截图
谷歌图片搜索 寻找的是相似的图片,而不是相同的图片。我想用TinEye来代替。这个工具通常非常适合检测用户在社交网络上联系你是否是假的。将它与其他相同的网页图像进行匹配可能会证明这个用户图片是一个股票图像,而使用这个用户图片的人可能是一个骗子。甚至还有 TinEye 插件。****
使用 TinEye 插件 = >查找使用图片的页面,截图由作者提供
TinEye 的问题是:没有一个完整的关于这个不存在的人的开放知识库来进行双重检查(这意味着整个潜在空间都是开放访问的,这可能是不可行的)。
相反,Yandex 可以找到另一个 GAN 生成的人脸,如果你只上传其中一个。而且 Yandex 的这个相似度比谷歌图片搜索的相似度要好用得多。******
并非所有类似的图像都是 GAN 生成的,但其中许多是。作者截图。
大概,Yandex 寻找的是 GAN 人脸上典型的特定图案?Yandex 的缺点是,它仍然主要在俄罗斯网络空间进行搜索,这可能会导致对“假面网络景观”的偏见。**
我希望 TinEye 或 Yandex 类似的服务也可以使用 GAN2 或其他 GAN 生成的图像,甚至可以作为 Chrome 插件,在全球范围内寻找这种假照片。可能使用 StyleGAN2 投影,这可能需要一些时间:使用 StyleGAN2 Colab 笔记本,生成投影大约需要 10-15 分钟。
案例三:一样。能量——反向图像搜索的艺术运用
但这不仅仅是关于政治、欺诈和假货。人工智能作为一种创造性的机器,为艺术家、作家和电影制作人打开了新的视野。在真实数据的训练下,人工智能提供了关于我们世界的“幻觉”或“梦想”。而 AI 梦的视觉表现形式变成了我们的世界。
最近,一个引人入胜的视觉搜索引擎亮相: 相同。能源 由多媒体艺术家和游戏设计师雅各布·雅各布森创作。顾名思义,这个引擎寻找具有“相同能量”的图像,在风格和视觉上与你输入搜索的图像相似。该引擎使用机器学习工作,并由类似于 OpenAI 的 CLIP 的视觉分类模型提供燃料(该模型在承认 DALL-E 的情况下发布)。
如果你在这里输入一个任意的图像,系统会以特定的特征、模式和物体来识别它,并寻找语义上的相似性。
例如,如果我们输入达芬奇的自画像,我们会得到一组其他图像,描述类似“一个留着胡子的老人作为一幅画或一幅素描”。
********
达芬奇自拍(公共领域)//作者截图
我摆弄着比根的图像(由 Colab Notebook 和art breader生成)想知道是怎么回事
a)机器学习可以从混合种子中检测生成图像吗
b)这个视觉搜索引擎能从现实世界中找到相似的图像吗?当然,其中许多将是想象力的产物,但仍然是人类的产物。
上传了一些图片,我发现了灵感和头脑风暴的奇妙可能性。
就拿这个来说吧。在这里你可以看到种子和它们的强度用于生成这个黑白艺术图像:
图片网址:【artbreeder.com/i?k=8b4dfc7e99d0cb87d1c7 ,作者截图
这是同样的图片。能源可以找到:
作者截图
或者另一个:
图片页面:https://www.artbreeder.com/i?k=6ca1f4031e1fc1565e1e,作者截图
同样的能量,有着令人难忘的画面。
作者截图
另一种半抽象的观点:
图片页面:https://www.artbreeder.com/i?k=35f9d8d2bba080ecf586,作者截图
结果令人震惊:
作者截图
因此,人工智能生成的图像和视觉搜索的结果的结合可以带来新的见解、发现和视觉探索我们世界的方式。当然,它也可以使用通常的图像作为输入。但在我使用甘的新抽象概念后,我看到了未知队列的力量,引发了意想不到的视觉联想。
生成性图像带有错觉的危险,并带来新的艺术视角。这取决于我们人类,以仁慈、明智和创造性的方式使用它。
基于 NetworkX 的生成图模型
标准生成图方法的综合指南及其在 NetworkX 中的实现
奥马尔·弗洛雷斯在 Unsplash 上拍摄的照片
相关文章
你听说过诸如 GANs 或 VAEs 这样的生成方法吗?这些聪明的架构允许我们对复杂的分布进行建模,并生成令人信服的数据样本,这些样本几乎无法与真实数据区分开来。
生成方法在图形数据中也有应用。在本文中,我们将研究 3 种流行的方法,这些方法用于生成具有不同属性(如节点度或节点社区)的图。我们还将看看它在 NetworkX 包中各自的实现。我们开始吧!
注意:你可以在这里 运行这篇文章的 Colab 笔记本 。
erdős–rényi 模型
ER 模型是最流行和最简单的图形生成方法之一。该模型的主要思想是为两个节点之间的边设置统一的概率阈值。总的来说,该型号有两种变型和,但主要的一种可以定义如下:
ER 模型定义[1]。 A 是邻接矩阵,u,V 是图中的节点 V 。可以解释为两个任意且不同的节点之间的边的概率 r 。
上面的等式意味着:为出现在两个任意且不同的节点之间的边设置一个概率。 r 越高,连通图越密。
从 NetworkX 包中用nx.erdos_renyi_graph
函数生成 ER 图相当容易:
下面,我绘制了 3 个随机生成的图,概率分别为 0.1、0.3 和 0.5。
使用 NetworkX 软件包用 ER 模型生成的图形。 r 分别设置为 0.1、0.3、0.5。作者创建的图像。
虽然 ER 生成的图简单且计算快速,但是我们不能用这种方法来建模更复杂的图结构。使用 ER,不可能用图来建模主题、程度分布或社区。现在,我们将朝着能够在一定程度上模拟这些属性的更复杂的模型前进。
随机块模型
SBM 模型进一步发展了 ER 生成的概念。它为在某个社区(即节点集群)内的节点和来自不同社区的节点之间的节点定义了唯一的概率。
如果这还不太清楚,让我们看一个简单的例子,看看它是如何产生的。
对于 SBM,我们对每个集群内的节点和属于不同集群的节点有单独的概率。在此图中,绿色数字是出现在两个不同分类之间的边缘概率。每个集群内的数字是同一社区内节点的边概率。作者创建的图像。
我们看到概率是为每个社区和一对不同的社区定义的。值得注意的是,如果所有的概率都相等,SBM 就会退化为一个简单的 ER 模型。
我们可以将模型定义如下[1]:
- 图 V 中的每个节点 u 属于某个社区 Ci,其中 i∈(0,…,γ),γ为社区总数
- 对于每个节点 u ∈ Ci 和 v ∈ Cj,存在一个边的概率,使得:
属于社区 i 和j的两个节点之间的边的概率这里, A 是邻接矩阵,C(γxγ)是具有所有社区对的概率的概率矩阵。
其中 A 是邻接矩阵, C (大小为γ x γ) 是所有社区对的概率矩阵。
我们也可以使用 NetworkX 来创建 SBM 生成的图形。我们需要的只是一个nx.stochastic_block_model
函数和一些其他实用程序来很好地绘制它。
在上述脚本的最后,您可以看到我为 3 个不同的集群设置了社区大小,以及一个 community_probs 矩阵,该矩阵设置了这些集群的概率(对角线值是每个集群内的边缘概率)。用提供的 Colab 笔记本随意试验这些值。对于代码中可以找到的默认值,我得到了下图:
使用 NetworkX 生成的图形。作者创建的图像。
这种模型有许多变体。一些例子可能包括用于二部图或具有节点特征的图的 SBM 方法[1]。
巴拉巴希-艾伯特模型
真正的网络可以随着时间的推移而增长。这些网络的一些例子可以包括 Twitter 追随者的增加或论文引用的增长。这些网络的一个重要属性是,一些高度连接的节点将吸引更多的连接,甚至增长得更快。例如,某些 Twitter 账户拥有 10 万以上的关注者,增长速度比普通账户快得多,或者某些研究论文被引用 1000 次以上,但它们仍然比不太受欢迎的文献被广泛引用。
网络成长和优先依附这两个属性是巴拉巴希-艾伯特模型(BA)的基础。该模型试图在遵循优先连接增长的同时,迭代地向现有网络添加节点。这种迭代方法将这种技术与 erdős–rényi 和随机块模型区分开来,后者一次生成图形。
这种 BA 算法工作如下。最初,我们有 m_0 个节点,这些节点至少有一个到其他节点的链接[3]。然后,我们迭代地添加一定数量的新节点,这些新节点与其他节点有 m 个链接。这里, m 需要小于 m_0。新节点与图中节点 i 连接的概率定义为 pi:
新节点和节点 i 之间的连接概率。 ki 定义了节点 i 的度。
其中 ki 定义了节点 i 的度。
节点度的分布遵循一个幂律分布:
这正是我们想要的,因为这意味着吸引许多连接的节点有非零(但仍然相当小)的概率。因此,我们应该期待在我们的网络中有少量高度连接的节点。
我们可以使用 Networkx 生成 BA 模型的图形。负责 BA 模型的函数称为nx.generators.random_graphs.barabasi_albert_graph
。请注意,我隐藏了一些绘图函数的实现,以避免文章混乱。完整的代码可以在这里找到。
使用上面的脚本,我们可以生成 BA 图。如果我们将它与之前的随机块模型进行比较,我们可以看到现在我们的节点具有不同数量的连接。我们还可以观察到,一个节点比任何其他节点有更多的连接。
使用 NetworkX 生成的 BA 图。作者创建的图像。
总结
在本文中,我们已经看到了 3 种标准的生成图方法:erdős–rényi、随机块和 Barabási-Albert 模型。ER 模型使用最简单的方法来生成节点之间具有统一连接概率的图。SBM 方法进一步发展了这一思想,允许对每个社区内的节点连接以及不同社区对之间的连接分别建模。最后,BA 模型能够使用幂律分布和添加新节点的迭代方法在节点之间生成不同数量的连接。
图形生成模型还有一个有趣的领域,它使用深度学习来生成图形。这个会出现在下一篇文章里!
关于我
我是阿姆斯特丹大学的人工智能硕士学生。在我的业余时间,你可以发现我摆弄数据或者调试我的深度学习模型(我发誓这很有效!).我也喜欢徒步旅行:)
如果你想了解我的最新文章和其他有用的内容,以下是我的其他社交媒体资料:
参考
[2] 社区检测和随机块模型:最近的发展
[3] 网络科学书,第五章
生成网络:从 AE 到 VAE 到 GAN 到 CycleGAN
入门
生成网络进化指南
介绍
简而言之,生成网络背后的核心思想是捕捉数据的底层分布。这种分布不能直接观察到,但必须从训练数据中近似推断出来。多年来,出现了许多旨在生成类似于输入样本的数据的技术。
这篇文章打算给你一个进化的概述,从自动编码器开始,描述它的后代,变化的自动编码器,然后看一下 GAN,最后以作为 GAN 设置的扩展的 CycleGAN 结束。
自动编码器
早期的深度生成方法使用自动编码器[1]。这些网络旨在压缩低维潜在空间 z 中的底层分布,例如,通过连续减小层尺寸。这些低维表示充当瓶颈,并迫使网络学习紧凑的表示。
自动编码器的示意图;作者在[2]之后创作的。左边是原始的领域空间,真实的样本是从那里抽取的;右边是重建的输入。中间视觉上较小的块代表瓶颈层,用于强制数据压缩。
网络的第一部分是编码器部分,它将特征映射(编码)到上述低维潜在空间。这种编码自动发生,因此称为自动编码器。从这个编码表示中,解码器部分试图重建原始数据。这是一种无监督的技术,因为真实样本 x 和生成样本x’可以直接比较,不需要标签信息。
潜在空间 z 的大小影响输出质量;更大的空间产生更精确的重构样本x’。然而,解码器没有真正的生成能力(例如,它只能 re 构造样本,而不是发明它们)。
技术现状
用重构损失训练网络[2]
自动编码器的构造损失,根据其相似性将原始样本和重构样本配对。
其在输入样本 x 和重构样本x’之间的距离为零时最小。在这种情况下,网络实现了完美的重构。
想象一只猫的图片:你把它喂给模型,得到的猫越像你的输入,这个模型就越好。毕竟,你想认出你的宠物,不是吗?
一只猫。马蒂纽·拉马丹在 Unsplash 上拍摄的照片
可变自动编码器
这些生成能力可以通过调整潜在空间 z ,变化自动编码器(VAE)背后的思想【2,3,4,5;更多资源:链接 1 ,链接 2 。
变型自动编码器的示意图,由作者在[2]之后创建。与标准自动编码器设置的关键区别在于对潜在空间的修改,潜在空间被分成均值向量μ和标准差向量σ,这是大多数概率分布的参数。
与自动编码器类似,它由编码器部分和解码器部分组成。编码器学习输入数据的平均值μ和标准偏差σ,它为瓶颈层中的每个维度建模概率分布。在编码过程中,从潜在空间中抽取样本。采样层之后的输出是均值向量μ和偏差向量σ [2]之和。随机性(换句话说,创造力)是通过用随机常数η移动μ和缩放σ引入的,随机常数η来自正态分布。这种(重新)参数化技巧将网络和概率部分分开,使反向传播照常进行[2]。
请这样想:
你想(再次)处理猫的图像。不是简单地让网络压缩图片,而是让它学习输入样本的特征。这可能是毛发的厚度、尾巴的长度、毛发的颜色、耳朵的大小等等。这就是为什么我们将μ和σ作为向量:对于每个特征(毛发、耳朵、尾巴等)。),我们对概率分布建模,了解属性的值(例如尾部长度)有多可能。生成一个样本,然后混合这些属性,生成一个新的猫图像——也许是一个未知的种族?
另一只猫。由 Milada Vigerova 在 Unsplash 上拍摄的照片
为了防止网络记住其输入样本,正则化项被添加到损失函数 L 中,即 Kullback-Leibler 散度。这种差异允许在两个概率分布之间进行比较;在 VAE 的设定中,它被用来“在潜在空间的中心周围平均分配编码(这将是我们的猫的属性)”[2],从而防止记忆。这里,潜在空间被理解为概率分布,并与先验分布相比较,假设分布产生真实样本 x 。这通常是一个单位高斯分布,均值为 0,方差为 1。
先验分布捕获了我们对数据可能如何分布的假设。通常,您希望这尽可能不包含信息,因此使用标准高斯。对于猫的设置,我们的分布可能会说尾巴不长于 20 厘米,或者猫的耳朵通常在 5 到 10 厘米高之间。
技术现状
基本的 VAE 架构利用了两个损耗。第一个是重建损失,如自动编码器设置中的损失,第二个是正则化项,即前面提到的 Kullback-Leibler 散度。这种差异来自概率理论,用于导出概率分布的参数(如平均值或方差)。这符合必须学习这些参数的 VAE 设置。当且仅当两个概率分布相等时(换句话说,当两个随机变量 Y₁和 Y₂相等时),这里使用的散度函数为 0,否则更大。
将 KL 散度加到损失上,使得潜在空间更接近所选择的先验。对于基本的 VAE,这个先验实际上局限于高斯分布。给定网络的潜在分布和这个先验,我们有[2,3]:
其中φ,θ是编码器和解码器的参数(权重), R 是已知的重建损失, KL 是 Kullback-Leibler 散度。当重构样本与输入样本没有区别时,以及当学习的潜在概率分布等于固定的先验时,这种损失最小。
生成对抗网络
在给定数据集之后对人工样本进行建模可以直接通过将真实数据与生成的数据进行比较来完成,或者间接通过利用下游任务来完成,下游任务反过来使网络能够生成真实样本。对于直接方法,可以使用最大平均差异,这超出了本文的范围;例如,参见[7]了解更多信息。
生成对抗网络(GANs) [8]背后的技术依赖于间接比较。在这个框架中,两个网络被联合训练:生成器被训练从噪声中生成人工样本,看起来尽可能真实;鉴别器试图将它们与真实样本区分开来。
噪声输入是真实数据分布的先验,类似于 VAE 设置中的高斯先验。生成器学习一个函数,该函数将这个简单分布(白噪声)转换为代表所需数据的复杂分布。这个转换函数是一个复杂的函数(意思是“不简单”),神经网络已经证明它学习得非常好;网络权重是函数的参数。鉴别器是生成器的对手,深度神经网络将其输入映射到单个标量,输出输入是真实样本的概率。
GAN 框架的示意图,由作者在[2]之后创建。左边是学习从噪声到目标域的变换的生成器部分,右边是鉴别器部分,将这样生成的假样本与真实数据样本区分开。
这个过程可以看作是两个玩家的 min-max 博弈。这个博弈中的均衡状态是生成器生成不可区分的假样本,鉴别器始终返回 0.5,即,猜测。在[8]中的算法 1 中描述了训练过程:首先,为 k 步更新鉴别器,然后更新发生器的权重。最后一次更新是通过提升梯度进行的;因为目的是欺骗鉴别器(,即,增加误差),所以必须采用梯度的上升。反向传播更新变换函数的权重,该权重随着时间的推移接近期望的分布。
为了使鉴别器不仅了解真实和虚假样本之间的区别,而且了解真实数据的分布,它在训练期间看到虚假样本和真实样本对。这反过来使生成器能够创建更逼真的样本。
对于猫的设定,我们可以收集我们的宠物的各种图像,这些是真实的样本。从噪声开始,生成器在鉴频器结果的指导下,连续生成更好的样本。这些猫的照片一开始可能看起来很模糊,但随着时间的推移,它们变得越来越真实。鉴别者通过看到真实的猫和生成的猫来判断我们生成图像的质量(即真实性)。
一只真正的猫,不是人工生成的!照片由桑吉亚在 Unsplash 上拍摄
技术现状
其思想是生成一个概率分布,该概率分布模拟来自目标域的底层分布。为了实现这一点,定义了网络输入上的先验p _ z[8],其中 z 是来自该空间的样本。生成网络 G 作为转化函数,将简单的先验分布转化为复杂的分布。与鉴别器一起,两者都遵循
在这个两人游戏中,生成器试图最小化它产生的错误(因此 min ),鉴别器被训练以最大化它的分类精度(因此 max )。
CycleGAN
使用 CycleGAN 对 GAN 框架进行了扩展[9]。这种方法最初出现是为了解决图像到图像的转换问题,其中输入图像来自一个域(例如,白天),而期望的输出来自另一个域(例如,夜晚)。以前的方法需要成对图像{mountain_day,mountain_night}的详尽且昂贵的数据集,这对于更复杂的域改变是禁止的。其次,生成过程容易出现模式崩溃,所有输入样本都被映射到一个单一的输出样本[10];这拖延了训练。
CycleGAN 方法在 set 级别上解决了这个任务;它从域 X 和域 Y 获取不成对的数据集,不需要白噪声输入。CycleGAN 网络旨在双向学习这两个领域之间的潜在关系。域转移X∑X→Y∑Y由生成器 G 完成,而转移 y → x 由 F 完成:
CycleGAN 框架的示意图;作者在[2]之后创作的。左边的鉴别器 D_x 学习区分域 X 的真实样本和 f 产生的虚假样本,右边的鉴别器 D_y 学习区分域 Y 的真实数据和 g 产生的虚假样本。
现在,对于我们奔跑的猫的例子,我们可以将我们的宠物“转化”成一只老虎。因此,我们收集猫和老虎的图像。一个生成器将我们的猫转换成老虎,另一个生成器负责向后的方向,从老虎创建一只猫。
为什么我们甚至需要这种倒退的方向?
为了防止模式崩溃:如果我们不能保证生成的输出是基于我们的输入图像,理论上我们可以总是返回相同的猫到老虎映射的图像。显然,这不会是完全错误的,但这并不是我们真正想要的。
这种转移的成功由周期一致性损失来保证(我认为这是非常聪明的事情):给定一个输入 x ,生成器 G 生成y’。第二发电机 F 变换y’→x’。理想情况下,在映射到 Y 域并返回——完成一个循环——x’与 x 相同。
循环一致性的实用性也可以在其他领域看到:将一个英语句子翻译成法语,然后再翻译回英语,应该会产生相同的原始句子[9]。
生成的数据(我们的 cat 图像)的“质量”由鉴别器 D_y 观察,该鉴别器区分真 y 样本和假 y 样本。第二次映射的质量由 D_x 观察,它区分真实样本 x 和生成的样本。总损耗包括两个发生器-鉴别器[8]对的损耗和循环一致性损耗。最后一个损耗通过将每个输入强制为一个互斥输出来防止上述模式崩溃。
对于我们的猫-老虎设置,我们有一个专家来区分猫和假猫,还有一个专家来区分老虎和假老虎。鉴别器与生成器(如果这是一个词的话)一起工作:猫与假猫鉴别器越好,老虎→猫生成器越好;另一个方向也类似。这就是为什么甘的设定可以被看作是一个双人游戏。
技术现状
扩展 GAN 设置,一个 CycleGAN 可以被视为学习两个复杂的变换函数:从分布 A 到 B ,以及从 B 到 A 。
摘要
深度神经网络的生成能力已经发展了几年,早期的方法使用自动编码器框架。在此基础上,变分自动编码器通过从潜在空间中随机采样来增加更强的生成能力。当[8]提出生成对抗网时,实现了一个里程碑,使得模型能够学习从噪声到目标域的转换。CycleGAN 框架通过使用两个生成器和两个鉴别器来保留样本中包含的原始信息,从而扩展了这种方法。
回顾一下,要点是
- 自动编码器压缩并重建它们的输入
- 可变自动编码器增加了更多的生成技术
- GANs(最初)使用白噪声作为输入来生成数据
- CycleGANs 扩展了 GAN 概念,使训练更加稳定
这个帖子到此为止。如有任何更正、评论或意见,请留言。感谢阅读!
文献学
如果您想了解更多信息,请参考以下资源:
[1] G. Hinton 和 R. Salakhutdinov,用神经网络减少数据的维数 (2006),科学
[2] A. Amini 和 A. Soleimany,深度学习介绍:深度生成模型 (2020),麻省理工学院演讲
[3] D. Kingma 和 M. Welling,随机梯度 VB 和变分自动编码器 (2014),第二届学习表征国际会议,ICLR
[4] D. Rezende 等,深度生成模型中的随机反向传播和近似推理 (2014),第 31 届机器学习国际会议论文集(ICML)
[5] X .陈等。,变分有损自动编码器 (2017),arXiv
[6] A. Valenti 等人,通过对抗性自动编码器学习风格感知的符号音乐表示 (2020),第 24 届欧洲人工智能会议(ECAI2020)
[7] A. Gretton 等,双样本问题的核方法 (2007),神经信息处理系统进展
[8] I. Goodfellow 等,生成对抗网络 (2014),神经信息处理系统进展
[9]朱等,利用循环一致对抗网络的不成对图像到图像翻译 (2017),IEEE 计算机视觉国际会议论文集
[10] Ian Goodfellow,NIPS 2016 教程:生成对抗网络 (2016),arXiv
R:超参数整定中的遗传算法
在 R 中使用遗传算法调整模型的超参数
动机
监督学习成为机器学习(ML)领域的主要任务之一,其中监督学习本身的目标是在给定数据中的特征/自变量的情况下预测目标/因变量。近年来研究的最大似然法的研究课题之一是超参数调整。
我们可以用于超参数调整的一种流行技术是使用网格搜索(GS)算法。尽管 GS 是 ML 中超参数调整的一种流行算法,但当涉及大型数据集和/或多个超参数时,它非常耗时且计算量大。为此,开发了几种替代技术,其中之一是使用遗传算法。在这篇文章中,我将告诉你如何在 r 中使用遗传算法来调整你的超参数。
那么,什么是超参数调谐呢?
ML 模型中超参数的调整会极大地影响其预测性能,因此为模型设置合适的超参数非常重要。传统上,ML 模型中的超参数调整通常通过试错过程来执行。根据 ML 模型中存在的超参数的数量,这个过程可能会非常耗时,尤其是当我们处理大量数据时。
超参数调整问题通常被视为优化问题,其中我们想要优化的目标函数是模型本身的预测性能。超参数调优[3]中经常遇到的挑战如下。
- 一个数据集中的超参数设置可能会导致高预测性能,但在另一个数据集中可能不会。
- 超参数有时是相互依赖的,例如随机森林中的
ntree
(树的数量)和mtry
(随机选择的变量的数量)。 - 耗时的超参数调整过程。
超参数整定的遗传算法
遗传算法的思想是通过选择最佳或最合适的解以及罕见和随机的突变发生来获得目标函数的最优解。对于那些想了解算法如何工作的人,我在这里写了一篇解释算法概念的文章。
在这种情况下,由于我们想要调整 ML 模型上的超参数,因此该算法中使用的“群体”是具有不同超参数值的模型列表。用于超参数调整的遗传算法的伪代码如下所示。
遗传算法超参数整定伪代码(图片由作者提供)
案例分析
在本文中,我使用 UCI 机器学习库中的混凝土抗压强度数据集实现了超参数调整的遗传算法。该数据集的目标是预测混凝土抗压强度值,因此存在回归问题。
混凝土抗压强度数据集(图片取自 UCI 机器学习库)
变量信息如下。
- 水泥(成分 1) —定量—m3 混合物中的千克数—输入变量
- 高炉矿渣(成分 2) —定量—m3 混合物中的千克数—输入变量
- 飞灰(成分 3) —定量—m3 混合物中的千克数—输入变量
- 水(成分 4) —定量—m3 混合物中的千克数—输入变量
- 超塑化剂(成分 5) —定量—m3 混合物中的千克数—输入变量
- 粗骨料(成分 6) —定量—m3 混合物中的千克数—输入变量
- 细骨料(成分 7) —定量—m3 混合物中的千克数—输入变量
- 年龄—定量—天数(1~365) —输入变量
- 混凝土抗压强度—定量— MPa —输出变量
对于这种情况,我使用随机森林(对于离散值超参数情况)和梯度推进(对于实值超参数情况)模型。
数据预处理
首先,我们导入我们需要的数据和库。
library(car)
library(MASS)
library(tseries)
library(lmtest)
library(tidyverse)
library(GA)
library(mice)
library(caret)
library(caTools)
library(rsample)
library(gbm)
library(glmnet)
library(tictoc)
library(randomForest)#Data Importing
data=read.csv("data_input/Concrete_Data.csv",sep=';')
summary(data)
str(data)
我们按如下方式检查数据汇总。
> str(data)
'data.frame': 1030 obs. of 9 variables:
$ Cement : num 540 540 332 332 199 ...
$ Blast.Furnace.Slag : num 0 0 142 142 132 ...
$ Fly.Ash : num 0 0 0 0 0 0 0 0 0 0 ...
$ Water : num 162 162 228 228 192 228 228 228 228 228 ...
$ Superplasticizer : num 2.5 2.5 0 0 0 0 0 0 0 0 ...
$ Coarse.Aggregate : num 1040 1055 932 932 978 ...
$ Fine.Aggregate : num 676 676 594 594 826 ...
$ Age : int 28 28 270 365 360 90 365 28 28 28 ...
$ Concrete.compressive.strength: num 80 61.9 40.3 41 44.3 ...
然后,我们使用来自mice
库的md.pattern
检查数据集中是否存在缺失值,如下所示。
> md.pattern(data)
/\ /\
{ `---' }
{ O O }
==> V <== No need for mice. This data set is completely observed.
\ \|/ /
`-----'Cement Blast.Furnace.Slag Fly.Ash Water Superplasticizer Coarse.Aggregate Fine.Aggregate Age
1030 1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0
Concrete.compressive.strength
1030 1 0
0 0
缺失的价值分析(图片由作者提供)
我们可以看到没有丢失的值,所以我们可以进入下一步了。然后,我们将数据分成 70:30 比例的训练和测试数据,如下所示。
#Data Splitting
split=initial_split(data,prop=0.7)
data.train=training(split)
data.test=testing(split)
实施(离散值超参数)
对于离散值超参数的情况,我们使用随机森林模型,我们想要调整的超参数是ntree
和mtry
。由于ntree
和mtry
是离散值超参数,我们在优化过程中使用二进制编码。在这里,我将ntree
的范围设置为 1 到 512,将mtry
的范围设置为 1 到 8(您可以设置一个更大的范围,但请记住随机森林非常耗时,所以只要您有耐心等待,就继续吧)。为了检查我们需要多少位,我们可以通过将每个超参数的最大值相乘并将其与超参数的数量相加来计算,如下所示。
> log2(512*8)+2
[1] 14
根据上面的计算,我们需要 14 位。如果ntree
和mtry
的转换值为 0,我们将其改为 1(因为最小值范围为 1)。然后,如果ntree
的转换值大于 512,我们就把它改成 512(因为最大值范围是 512)。同样,如果mtry
的转换值大于 8,我们将其更改为 8(因为最大值范围是 8)。接下来,我们创建想要实现的目标函数。记住,遗传算法的目的是最大化目标值,我们希望 RMSE 值尽可能小,因此我们将 RMSE 值设置为负值。
fit_rf=function(x)
{
ntree=binary2decimal(x[1:10]) #ntree from 1 to 2^9
mtry=binary2decimal(x[11:14]) # mtry from 1 to 2^3
if(ntree==0)
{
ntree=1
}
if(mtry==0)
{
mtry=1
}
if(ntree>512)
{
ntree=512
}
if(mtry>8)
{
mtry=8
}
model=randomForest(Concrete.compressive.strength~.,data=data.train,mtry=mtry,
ntree=ntree)
predictions=predict(model,data.test)
rmse=sqrt(mean((data.test$Concrete.compressive.strength-predictions)^2))
return(-rmse) #since GA maximize the objective function and we want to minimize RMSE
}
现在,让我们通过编写这几行代码来看看如何将其实现为ga
函数。
tic()
GA3=ga(type='binary',fitness=fit_rf,nBits=14,
maxiter=30,popSize=50,seed=1234,keepBest=TRUE)
summary(GA3)
plot(GA3)
toc()
随机森林超参数调谐结果的遗传算法(图片由作者提供)
> tic()
> GA3=ga(type='binary',fitness=fit_rf,nBits=14,
+ maxiter=30,popSize=50,seed=1234,keepBest=TRUE)
GA | iter = 1 | Mean = -5.277882 | Best = -4.946697
GA | iter = 2 | Mean = -5.152451 | Best = -4.946697
GA | iter = 3 | Mean = -5.182143 | Best = -4.946697
GA | iter = 4 | Mean = -5.115866 | Best = -4.921109
GA | iter = 5 | Mean = -5.075498 | Best = -4.921109
GA | iter = 6 | Mean = -5.132925 | Best = -4.921109
GA | iter = 7 | Mean = -5.089994 | Best = -4.921109
GA | iter = 8 | Mean = -5.126774 | Best = -4.921109
GA | iter = 9 | Mean = -5.078846 | Best = -4.921109
GA | iter = 10 | Mean = -5.163979 | Best = -4.919853
GA | iter = 11 | Mean = -5.205034 | Best = -4.919853
GA | iter = 12 | Mean = -5.207537 | Best = -4.919853
GA | iter = 13 | Mean = -5.098879 | Best = -4.919853
GA | iter = 14 | Mean = -5.118728 | Best = -4.919853
GA | iter = 15 | Mean = -5.202860 | Best = -4.919853
GA | iter = 16 | Mean = -5.145285 | Best = -4.919853
GA | iter = 17 | Mean = -5.107588 | Best = -4.919853
GA | iter = 18 | Mean = -5.032939 | Best = -4.919853
GA | iter = 19 | Mean = -5.041192 | Best = -4.885373
GA | iter = 20 | Mean = -5.039374 | Best = -4.885373
GA | iter = 21 | Mean = -5.034047 | Best = -4.885373
GA | iter = 22 | Mean = -5.030971 | Best = -4.885373
GA | iter = 23 | Mean = -5.023164 | Best = -4.885373
GA | iter = 24 | Mean = -5.026200 | Best = -4.829599
GA | iter = 25 | Mean = -5.077859 | Best = -4.829599
GA | iter = 26 | Mean = -5.080206 | Best = -4.829599
GA | iter = 27 | Mean = -5.033013 | Best = -4.829599
GA | iter = 28 | Mean = -5.071353 | Best = -4.809166
GA | iter = 29 | Mean = -5.057733 | Best = -4.809166
GA | iter = 30 | Mean = -5.048505 | Best = -4.809166
> summary(GA3)
-- Genetic Algorithm -------------------GA settings:
Type = binary
Population size = 50
Number of generations = 30
Elitism = 2
Crossover probability = 0.8
Mutation probability = 0.1GA results:
Iterations = 30
Fitness function value = -4.809166
Solution =
x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 ... x13 x14
[1,] 0 0 0 1 0 1 0 1 0 0 0 1
> plot(GA3)
> toc()
1101.77 sec elapsed
我们可以看到最合适的ntree
和mtry
值如下。
> ga_rf_fit=as.data.frame(GA3@bestSol)
> ga_ntree=apply(ga_rf_fit[, 1:10],1,binary2decimal)
> ga_mtry=apply(ga_rf_fit[, 11:14],1,binary2decimal)
> ga_ntree
[1] 76
> ga_mtry
[1] 4
从上面的结果来看,每一代中最好的个体产生的 RMSE 在每一代中是递减的,其中最终一代中的最适结果为 76 个ntree
和 4 个mtry
,RMSE 值为 4.809166。
实现(实值超参数)
对于实值超参数的情况,我们使用梯度增强模型,我们想要调整的超参数是n.trees
、shrinkage
和interaction.depth
。请注意,n.trees
和interaction.depth
是离散值超参数,因此技巧是将底值函数应用于模型函数中的n.trees
和interaction.depth
值,如下所示。
fit_gbm=function(ntree,shrinkage,interaction)
{
model=gbm(Concrete.compressive.strength~.,data=data.train,distribution="gaussian",
n.trees=floor(ntree),shrinkage=shrinkage,interaction.depth=floor(interaction))
predictions=predict(model,data.test)
rmse=sqrt(mean((data.test$Concrete.compressive.strength-predictions)^2))
return(rmse)
}
然后,我们将目标函数实现到ga
函数中,如下所示。
tic()
GA2=ga(type='real-valued',fitness=function(x) -fit_gbm(x[1],x[2],x[3]),
lower=c(1,1e-4,1),upper=c(512,1e-1,3),maxiter=30,popSize=50,seed=1234,keepBest=TRUE)
summary(GA2)
plot(GA2)
toc()
遗传算法梯度增强超参数调谐结果(图片由作者提供)
> summary(GA2)
-- Genetic Algorithm -------------------GA settings:
Type = real-valued
Population size = 50
Number of generations = 30
Elitism = 2
Crossover probability = 0.8
Mutation probability = 0.1
Search domain =
x1 x2 x3
lower 1 1e-04 1
upper 512 1e-01 3GA results:
Iterations = 30
Fitness function value = -4.939432
Solution =
x1 x2 x3
[1,] 470.8652 0.08298563 2.346486
> plot(GA2)
> toc()
72.26 sec elapsed
从上面的结果来看,每一代中最好的个体产生的 RMSE 在每一代中是递减的,其中最终一代中的最适结果为 470 n.trees
,0.08298563 shrinkage
,2 interaction.depth
,RMSE 值为 4.939432。
结论
这就是了,你可以在 r 中实现超参数调整的遗传算法,你可以尝试不同的数据集,或者尝试在分类问题上实现它。此外,您可以尝试不同的预测性能指标来查看不同的结果。永远记住,ML 是一个广阔的领域,所以永远要尝试实验!
像往常一样,如果您有任何问题,请随时在我的联系人下面提问或讨论!在我的下一篇文章中再见!
说到超参数调谐…(从 Imgflip 生成的图像)
作者联系方式
LinkedIn: 拉登·奥勒留和希卡·维亚迪努格罗霍
中:https://medium.com/@radenaurelius
参考文献
[1]叶一成,利用人工神经网络对高性能混凝土强度进行建模 (1998),水泥与混凝土研究。
https://rpubs.com/Argaadya/550805
[3] Rafael G. Mantovani,Tomáhorváth,Ricardo Cerri,Joaquin Vanschoren,andéc . p . l . f . de Carvalho,决策树归纳算法的超参数调整 (2016),2016 年第五届巴西智能系统会议。
[4]https://archive . ics . UCI . edu/ml/datasets/Concrete+抗压+强度
[5] Nikolaos Gorgolis,Ioannis Hatzilygeroudis,Zoltan·伊斯特尼斯,Lazlo — Grad Gyenne,通过遗传算法优化 LSTM 网络模型的超参数 (2019),2019 年第十届信息、智能、系统与应用国际会议(IISA)。
[6] Luca Scrucca,GA:R(2013)中的遗传算法包,统计软件杂志。
[7]https://www . rdocumentation . org/packages/GA/versions/3.2/topics/GA
R 中的遗传算法:背包问题
塞巴斯蒂安·戈德堡在 Unsplash 上的照片
用遗传算法求解 R 中的背包问题
动机
背包问题是最优化,特别是组合最优化中的著名问题之一。这个问题的动机来自于一个人需要最大化他的背包容量——因此得名——尽可能多的物品。有许多方法可以解决这个问题,但是在本文中,我将给出一个例子,使用 r。
背包问题
在本文中,我们将尝试解决的背包问题是0–1 背包问题。给定一组从 1 到 n 编号的 n 个项目,每个项目的权重为 w_i,值为 v_i。假设每个项目的副本限制为 1,即该项目要么包含在背包中,要么不包含在背包中。这里我们希望最大化目标函数(即背包中物品的价值)
其中目标函数服从约束函数
遗传算法概念
遗传算法是一种基于自然选择进化思想的优化算法。查尔斯·达尔文提出,自然选择进化是通过两个原则:自然选择和突变,来决定有多少种生物会适应环境而生存。基于这一概念,遗传算法的目标是通过选择最佳或最合适的解决方案以及罕见的随机突变事件来获得目标函数的最优解。算法本身可以解释如下。
遗传算法流程图(图片由作者提供)
- 初始化我们将优化的数据和/或函数。
- 初始化种群大小、最大迭代次数(代数)、交叉概率、变异概率和精英数(不会发生变异的最佳或最适个体)。
- 从群体中选择两个个体,然后以概率 p 在两个个体之间进行交叉。
- 然后,在两个概率为 p 的个体之间进行变异(通常变异的概率很低)。
- 重复步骤 3 和 4,直到一代中的所有个体都被训练。这些所有的个体将被用于训练下一代,直到代数达到极限。
为了让您更好地理解遗传算法,让我们跳到案例研究,在这里我们将使用遗传算法来解决 r 中的背包问题。
案例分析:用遗传算法解决背包问题
假设你想和你的朋友去徒步旅行,你有徒步旅行可以使用的物品,每件物品的重量(以公斤为单位)和生存点分别如下。
可用的图片,分别显示每件物品的重量和生存点数(图片由作者提供)
再假设你有一个背包,可以装下最大容量 25 公斤的物品,其中每个物品只能带一份。目标是:你想最大化背包的容量,同时最大化你的生存点数。从问题陈述中,我们可以定义物品的重量为约束函数,而背包中物品累积的生存点数为目标函数。
对于本文中的实现,这里我们使用 Luca Scrucca [2]创建的 R 中的GA
库。首先,我们需要输入我们通过编写这些代码行所使用的数据和参数。
#0-1 Knapsack's Problemlibrary(GA)item=c('raincoat','pocket knife','mineral water','gloves','sleeping bag','tent','portable stove','canned food','snacks')
weight=c(2,1,6,1,4,9,5,8,3)
survival=c(5,3,15,5,6,18,8,20,8)
data=data.frame(item,weight,survival)
max_weight=25
为了让你更好地理解这个问题中的遗传算法,假设我们最初在你的背包中只带了一把小刀、矿泉水和零食。我们可以把它写成“染色体”,既然我们要解决的问题是一个 0–1 背包问题,那么从下面这几行代码来看,1 表示我们带来了物品,而 0 表示我们留下了物品。
#1 means that we bring the item, while 0 means that we left the item
chromosomes=c(0,1,1,0,0,0,0,0,1)
data[chromosomes==1,]
我们可以看到如下结果。
> data[chromosomes==1,]
item weight survival
2 pocket knife 1 3
3 mineral water 6 15
9 snacks 3 8
然后,我们通过编写下面的代码行来创建我们想要用约束函数优化的目标函数。我们将在GA
库中的ga
函数中使用的fitness
函数。
#create the function that we want to optimize
fitness=function(x)
{
current_survpoint=x%*%data$survival
current_weight=x%*%data$weight
if(current_weight>max_weight)
{
return(0)
}
else
{
return(current_survpoint)
}
}
现在有趣的部分来了:使用遗传算法的优化过程。假设我们想要为优化过程创建最多 30 代和 50 个个体。为了再现性,我们写下seed
参数并保留最佳解。
GA=ga(type='binary',fitness=fitness,nBits=nrow(data),maxiter=30,popSize=50,seed=1234,keepBest=TRUE)
summary(GA)
plot(GA)
通过运行上面的代码行,我们可以获得如下结果。
> GA=ga(type='binary',fitness=fitness,nBits=nrow(data),maxiter=30,popSize=50,seed=1234,keepBest=TRUE)
GA | iter = 1 | Mean = 31.92 | Best = 61.00
GA | iter = 2 | Mean = 31.32 | Best = 61.00
GA | iter = 3 | Mean = 33.08 | Best = 61.00
GA | iter = 4 | Mean = 36.14 | Best = 61.00
GA | iter = 5 | Mean = 42.42 | Best = 61.00
GA | iter = 6 | Mean = 36.56 | Best = 61.00
GA | iter = 7 | Mean = 37.32 | Best = 61.00
GA | iter = 8 | Mean = 38.18 | Best = 61.00
GA | iter = 9 | Mean = 39.02 | Best = 61.00
GA | iter = 10 | Mean = 38.92 | Best = 61.00
GA | iter = 11 | Mean = 37.54 | Best = 61.00
GA | iter = 12 | Mean = 35.14 | Best = 61.00
GA | iter = 13 | Mean = 36.28 | Best = 61.00
GA | iter = 14 | Mean = 40.82 | Best = 61.00
GA | iter = 15 | Mean = 44.26 | Best = 61.00
GA | iter = 16 | Mean = 41.62 | Best = 61.00
GA | iter = 17 | Mean = 38.66 | Best = 61.00
GA | iter = 18 | Mean = 36.24 | Best = 61.00
GA | iter = 19 | Mean = 43 | Best = 61
GA | iter = 20 | Mean = 43.48 | Best = 61.00
GA | iter = 21 | Mean = 43.08 | Best = 61.00
GA | iter = 22 | Mean = 44.88 | Best = 61.00
GA | iter = 23 | Mean = 46.84 | Best = 61.00
GA | iter = 24 | Mean = 46.8 | Best = 61.0
GA | iter = 25 | Mean = 42.62 | Best = 61.00
GA | iter = 26 | Mean = 46.52 | Best = 61.00
GA | iter = 27 | Mean = 46.14 | Best = 61.00
GA | iter = 28 | Mean = 43.8 | Best = 61.0
GA | iter = 29 | Mean = 46.16 | Best = 61.00
GA | iter = 30 | Mean = 42.6 | Best = 61.0> summary(GA)
-- Genetic Algorithm -------------------
GA settings:
Type = binary
Population size = 50
Number of generations = 30
Elitism = 2
Crossover probability = 0.8
Mutation probability = 0.1GA results:
Iterations = 30
Fitness function value = 61
Solution =
x1 x2 x3 x4 x5 x6 x7 x8 x9
[1,] 1 0 1 1 0 0 1 1 1> GA@summary
max mean q3 median q1 min
[1,] 61 31.92 48 36.0 16 0
[2,] 61 31.32 47 31.0 24 0
[3,] 61 33.08 51 36.5 13 0
[4,] 61 36.14 52 39.0 31 0
[5,] 61 42.42 56 47.5 38 0
[6,] 61 36.56 52 41.5 26 0
[7,] 61 37.32 54 43.0 29 0
[8,] 61 38.18 54 43.0 29 0
[9,] 61 39.02 55 47.0 33 0
[10,] 61 38.92 52 43.5 33 0
[11,] 61 37.54 48 39.0 33 0
[12,] 61 35.14 47 39.0 29 0
[13,] 61 36.28 47 41.0 23 0
[14,] 61 40.82 51 43.0 34 0
[15,] 61 44.26 51 48.0 38 20
[16,] 61 41.62 52 45.0 34 0
[17,] 61 38.66 53 41.5 28 0
[18,] 61 36.24 51 39.5 28 0
[19,] 61 43.00 56 48.0 37 0
[20,] 61 43.48 56 48.0 39 0
[21,] 61 43.08 56 48.0 40 0
[22,] 61 44.88 56 51.0 41 0
[23,] 61 46.84 56 52.0 41 0
[24,] 61 46.80 56 48.0 41 0
[25,] 61 42.62 56 48.0 33 0
[26,] 61 46.52 56 48.0 42 0
[27,] 61 46.14 54 47.0 43 0
[28,] 61 43.80 56 49.5 40 0
[29,] 61 46.16 54 50.0 43 0
[30,] 61 42.60 56 48.0 36 0
遗传算法优化结果— GA(图片由作者提供)
从上面的结果中,我们可以看到,每一代人的表现都在提高。我们可以从适应值(即本例中的生存点)均值和中值看出,它在每一代中都有增加的趋势。让我们试着再训练它一次,但是要用更多代。
GA2=ga(type='binary',fitness=fitness,nBits=nrow(data),maxiter=50,popSize=50,seed=1234,keepBest=TRUE)
GA3=ga(type='binary',fitness=fitness,nBits=nrow(data),maxiter=100,popSize=50,seed=1234,keepBest=TRUE)
plot(GA2)
plot(GA3)
遗传算法优化结果— GA2(图片由作者提供)
遗传算法优化结果— GA3(图片由作者提供)
从GA2
和GA3
中,我们可以看到,根据该代适应值的平均值和中值,每个个体的优化结果在 40 岁左右和 60 岁左右的代处于最佳状态。我们还可以看到,从第 72 代开始,最佳适应值增加到 62。
由于我们保留了每个优化过程的最佳结果,因此我们希望根据遗传算法优化的最佳结果来找出我们可以为徒步旅行带来的物品。我们可以看到来自GA3
的总结如下。
> summary(GA3)
-- Genetic Algorithm -------------------
GA settings:
Type = binary
Population size = 50
Number of generations = 100
Elitism = 2
Crossover probability = 0.8
Mutation probability = 0.1GA results:
Iterations = 100
Fitness function value = 62
Solution =
x1 x2 x3 x4 x5 x6 x7 x8 x9
[1,] 1 1 1 1 1 0 0 1 1
从上面的结果,我们可以得出结论,我们可以包括在背包的物品是雨衣,小刀,矿泉水,手套,睡袋,罐头食品和零食。我们可以计算背包的重量,以确保背包没有超载。
> chromosomes_final=c(1,1,1,1,1,0,0,1,1)
> cat(chromosomes_final%*%data$weight)
25
太好了!我们可以看到物品的重量和背包容量是一样的!
结论
这就对了。您可以通过在 r 中实现遗传算法,以最大的生存点和容量与朋友一起徒步旅行(当然最好在疫情结束后进行)。事实上,您可以在许多现实世界的应用中使用遗传算法来解决背包问题,例如选择最佳表现的投资组合、生产调度等等。
像往常一样,如果您有任何问题或讨论,请随时通过我的 LinkedIn 联系我。保持安全,保持健康!
参考文献
[1] G. B. Matthews,关于数的划分 (1897),伦敦数学学会会刊。
[2] Luca Scrucca,GA:R(2013)中的遗传算法包,统计软件杂志。
[3]https://www . rdocumentation . org/packages/GA/versions/3.2/topics/GA
[4]哈维·m·萨尔金和科内利斯·A·德·克鲁弗,背包问题:调查 (1975),《海军研究后勤季刊》。
[5] Krzysztof Dudziński 和 stanisaw Walukiewicz,背包问题的精确方法及其推广 (1987 年),《欧洲运筹学杂志》。
[6] Sami Khuri,Thomas bck 和 rg Heitkö tter,《零/一多重背包问题和遗传算法》 (1994),SAC ' 94:1994 年 ACM 应用计算研讨会会议录。
[7]https://rpubs.com/Argaadya/550805
遗传算法的发展
为 B2B 市场的 ICP 评分创建人工智能算法
M 任何人都听说过最终消费者对人工智能领域的巨大怀疑:“我们已经在市场上待了 50 年,所以我们更知道该做什么”。
你在谈论你的人工智能,但它是如何工作的?你能给我们销售部写个算法吗?我们如何解释这些结果?
从这些欲望中,一个流行的任务出现了:ICP-segmentation for B2B。ICP —理想的客户档案,销售中的目标细分市场。在输入端有一个公司的参数:国家、金额、收入;在输出端,我们预测一些其他参数:****
- 潜在客户的转化
- 客户能给你什么收入
- 这个人是他公司里做决定的人吗,等等。
接下来,我们计算分数,从而计算进入一个或另一个组的概率。
模型
任务看起来很清楚:我们获取输入参数,将它们转换成所需的形式,代入模型,并训练模型。然而,如前所述,我们的解决方案的最终用户不仅希望看到结果,还希望了解为什么某个最终方案比一组具有良好直觉的专业员工更好地解决了他们的问题。因此,除了有效之外,我们的决定必须是可解释的。
为了在问题的效率和可解释性之间找到一个折中的办法,我们得出了下面的数学模型:
作者图片
或者更简单地,对参数的影响有约束的截断二次模型。最后分数从-100 到 100,一切都诠释的相当好。你可以尝试建立一个基于直觉的模型(我们与美国合作,这意味着我们将最重视它),或者你可以找到一个基于实际转换数据或利润的模型。
这就是蛮力问题的来源,它应该使用遗传算法来解决,因为普通线性规划(经过简化)的方法会在数据量上遇到困难。每个集合(x,y)将被简称为基因。
在每个阶段,我们使用数据集中每一行的公式计算得分,并使用几个损失函数中的一个计算该基因预测结果的好坏。
已经研究了几种损失函数:
1-矩阵:有一个惩罚矩阵,其中我们计算每行的惩罚或奖励,例如,如果我们试图将样本分成两组,那么在第一类或第二类错误的情况下,我们给出惩罚-1,而在落入正确组的情况下,我们给出奖励 1
作者图片
2-按平均值:计算每组的平均目标参数,并尝试找出各组之间的最大距离。
尽管使用第一个损失函数的结果更容易解释,但得到的组太不均匀。结果,当组的数量多于两个时,有效性被分组。结果,由于分组数据的随机性,这些组太不均匀了,所以让我们选择第二个选项。PCA 后的样本分布(混沌参考):
作者图片
算法优化方法
遗传算法是对原始样本的一系列转换,在每一个阶段,它都会丢弃最差的结果。最初算法对于大问题自然是多线程的,增长不是线性的。例如,与没有多线程的算法相比,在 16 个内核上运行可以提高近 10 倍。优化采样的损失函数也是值得考虑的。但也有不太明显的方式。
减少多线程计算中 Map-reduce 的数量
我想讨论的第一件事是减少并行化过程中的 map-reduce 数量。遗传算法分为几个阶段,即:繁殖、变异、计算下一代。所有这些都可以合并到一个任务中,并在参数中包含一个触发器。也就是说,不是:
**CURRENT_POPULATION = mutation.Mutation(CURRENT_POPULATION,triggers)
CURRENT_POPULATION = reproduction.Reproduction_multythread(CURRENT_POPULATION)**
可以合并成一个功能:
**CURRENT_POPULATION = mut_rep_iteration.Itr(CURRENT_POPULATION,triggers)**
比较一次迭代速度的结果:
作者图片
组合功能(新的 fn)比以前的(旧的 fn)几乎好 10%。该算法本身可以计算几乎一整天,这意味着计算可以少花 2-3 个小时。
初始近似值的选择
首先,让我们回忆一下我们正在研究的数学模型:
作者图片
显然,如果我们在遗传算法中取的不是随机值,而是,例如,一些有效的基因,那么该算法将需要较少的迭代。
让我们应用几个有争议的近似值。
1 —仅近似选项 yⱼ :
- 做一个随机集 x ,代入公式,得到每行通常的线性方程
- 将每个 yⱼ 作为方程组计算
- 为了符合条件,将 y 的极端值再次代入公式,再次用较少的变量求解通常的 SLAE 系统,并重复几次
- 每轮 yⱼ
- 我们获得了每个参数 yⱼ 的一些初始近似值
这个假设是有意义的,因为许多参数 y 经常在不同的方案中重复。如果某个参数是好的(强烈影响结果),那么它在任何方案中都将有一个最大值或最小值。
2 —一般近似变量(梯度下降):
- 做选项 1
- 我们解决逆问题:代入参数 y 计算 x
- 重复 N 次
这里,除了局部参数之外,我们还想看看哪个组对最终结果的影响最大。该算法的速度较低。因此,对于每个变体,进行了五次试验。
当前参数集:
一代幸存者:50,000
儿童人数:25,000 人
变种人数量:12500 人
现在让我们看看结果:
作者图片
变体 1 与干净启动相同,这意味着近似没有导致积极的结果,但是第二个(变体 2)看起来很有希望,但是让我们看看执行时间图。
作者图片
由于花费在初始近似上的时间,执行所花费的时间显著增加。这有点不公平。所以,让我们尝试将通常的算法与变体 2 进行比较,给常规算法更多的资源,并通过在每次迭代时扩展样本来近似时间。
作者图片
作者图片
尽管资源远远优于选项 2 (fp2),但实现持续更好的结果是不可能的。理论上,这可以通过搜索超参数和过滤下一代来防止优势来纠正。这个方向的研究还在继续,所以选择第二种形式的初始近似。
这个问题的初始近似稳定了答案,优化了资源。初始近似选择为梯度下降的几次迭代:
**gen = ret_random_gen(0) #Full random gen
for i in range(0,iters):
gen = CalculateByGenMG(gen) # calculate only X
gen = CalculateByGenML(gen) # calculate only Y**
确认
最后,我想提供生产中模型验证的图形数据。
这是训练(左图)和验证(右图)时的分布。(图片作者)**
训练是基于支票大小的数据。每条线索从低到高分为一组,如您所见,级别越高,高检查的概率越高。传入的数据结构略有变化,但组的区分保持稳定。
结论
遗传算法是一个资源密集型过程,优化这一过程可能成为其创建的主要任务。该算法易于使用,有助于在蛮力问题中找到最优解,并证明了其有效性。
遗传算法机器人:进化高度,使用 Python,C++和 Arduino。
用遗传算法代替预定的数学模型设计飞行控制系统。
用于测试进化高度机器人的三个机器人中的两个。作者图片
摘要:
这项研究的目的是设计一个飞行控制系统,没有预先确定的数学模型,而是使用遗传算法来保持最佳高度。本研究是通过定量的实证研究方法完成的。在进行研究的过程中,我们发现对新手用户来说,编写遗传算法程序是很麻烦的。因此,我们创建并发布了一个名为 EasyGA 的开源 Python 包。
在一次试验中使用 15 条染色体的初始群体,每条染色体 10 个基因,共 100 代。装置的节流值具有 1 秒的相关基因值。每个机器人至少进行 30 次试验,以显示研究中的统计显著性。当试验完成后,机器学习就实现了。结果表明,在不使用预先确定的数学模型的情况下,实时优化单自由度(DOF)设备是可能的。
工作原理:
为了运行该实验成功所需的遗传算法,需要 Arduino Uno、Python、电子鸭式风扇(EDF)、电子速度控制器(ESC)、超声波测距模块(USRM)和笔记本电脑。
Ardunio Uno: 是一款开源的微控制器板。这种微控制器板带有数字和模拟引脚。这些针有不同的用途。一些引脚用于向其他设备发送 3.3V 和 5V 电源,其他引脚用作输入和输出引脚,向其他设备发送脉宽调制(PWM)信号。
进化高度机器人布线图。作者图片
在本实验中,数字引脚 9、10 和 11 将用于发送 PWM 信号和接收来自超声波测距模块的传感信息。数字引脚 9 (TRIG)用于信号输出,引脚 10 (ECHO)用于信号输入,引脚 11 用于向 ESC 发送 PWM 信号。
Arduino C++: 写在 Arduino 上的代码以节流值的形式接收来自 python 脚本的指示。Arduino 然后执行这些指令,同时从 USRM 读取高度,并使用串行通信将它们传输回 python。
Python: Python 被用作处理遗传算法的主要语言,同时也向 Arduino 发送指示。
SQL 数据库:Sqlite3 数据库用于存储来自机器人和遗传算法的所有运行和配置数据。它还用于查找趋势和查询数据。
一个 DOF 装置:该装置由一个 EDF 风扇、USRM、一个碳纤维管、各种配线和三个 3D 打印部件组成:中间连接器和平台。该设备的平台被设计为在功能上与 EDF 运行所需的所有部件和零件一起工作。法国电力要求将 120 毫米 x 20mm 毫米的碳纤维管直接连接到风扇。
进化中的高空机器人所有主要部件的标签图像。作者图片
中间连接器被设计得比平台更宽。连接器比平台宽,因此超声波测距模块有足够大的空间来精确测量模块到设备的距离。
显示从超声波测距模块(USRM)到中间连接器的距离为 6 厘米。作者图片
高频超声波信号从模块发送到中间连接器,并作为声纳返回到模块,使其能够计算距离。
机器人健身功能:
适应度函数决定了染色体在特定任务中的表现。为了测试这项研究中的适应度函数,染色体被编码为 throttle 值,解析为一个字符串,并串行发送到 Arduino Uno。Arduino Uno 运行编码的染色体,并将适应性数据发送回 Python 脚本。Python 脚本随后对数据进行评估。这项研究的适应度函数是看机器人的 EDF 能在 USRM 上方 6 厘米的位置保持多好。在体能评估期间,总分是根据它与 6 厘米的总距离计算的。目标是使整体适应度为 0。
机器人适应度函数的图形表示。线代表期望的适合度。作者图片
在这里,您可以找到适应度函数的图形表示和用于评估染色体的代码。
代码视图:
用于评估机器人运行适应性的代码。
遗传算法设置:
该研究具有 6 个⁰可能的染色体组合或配置的搜索空间。使用遗传算法允许在搜索空间中快速搜索相对较好的解决方案。该解决方案可能是众多最佳解决方案中的一个,也可能是一个在对研究加以限制的情况下被认为适用的解决方案。
在研究过程中,人们发现,对遗传算法应该如何构造的任何清晰的解释或任何好的工具也有助于存储、跟踪和理解完成这样一项研究所需的信息。这个团队由 5 个人组成,花了一年时间为 Arduino 和 EasyGA python 包本身创建串行通信结构。
对于机器人,团队决定使用 EasyGA 的默认配置设置,因为它处理所有的超级参数。这是一个目标,以尽量减少机器人的错误,最终成为一行代码。python 代码可以在下面找到,更详细的列表可以在进化高度机器人 Github 上找到。
测试进化机器人时的 EasyGA 配置设置。
完整的代码通常是不共享的,但是我们认为在使用 EasyGA python 包时有必要展示简单性。
完整 Python 代码:
结果:
对于这项研究,目标是证明只需要一个遗传算法来优化一个单自由度机器人。不仅证明了这是可能的,该团队还希望确保可以通过使用多个机器人来完成这项工作。研究中使用了三个机器人,数据显示它们都能够学习。
每台机器人都经过了至少 30 次试验,每次试验都证明它们之间的机械差异仍然来自遗传算法的机器学习的相同结果。
用于寻找机器学习结果的三个机器人。从左到右——凯尔、杰夫和琳达。作者图片
这些机器人都被造得一模一样,但通过潜在的机械差异,它们都有一点点不同。在值的变化中看到的差异将成为每个机器人的接近最优的解决方案。
试验:种群规模 = 15,染色体长度 = 10,世代 = 100
左:所有试验最低染色体的平均值。右:所有试验中最低的染色体。作者提供的图片
讨论:
回想起来,测试所有可能的染色体组合是非常耗时的。一种更好的方法可能是结合模拟试验,然后进行实际测试和优化。这种双向方法既有在模拟中运行初始代的好处,在模拟中使用计算能力处理试验,随后是现实生活中的试验和培训,以进一步优化系统。
贡献:
我想感谢所有帮助过这个项目的人。以下个人都对研究产生了影响。
- Dylan Ballback 凭借他惊人的机械工程设计技能。
- 雷切尔·塞科德审阅并帮助撰写了所有内容。
- Jack Nguyen 与我和其他 4 名学生共同创建了 EasyGA。
- Mohammad Alali 编写 C++代码和 starter GA 代码。
- 雅各布·罗密欧(Jacob Romeo)帮着查阅文献和操作机器人。
- Matthew Verleger 博士是该研究项目的导师。
- Embry Riddle 本科生研究 Ignite 计划赞助该研究。
更多的人间接地帮助了这个项目,但是我仍然想对他们说谢谢。
感谢您的阅读,
丹尼尔·威尔扎克
自然语言处理的遗传算法
为什么遗传算法对预处理自然语言处理数据有效
图 1:遗传算法训练一个红色正方形来避开蓝色矩形。图片作者。
"数据准备约占数据科学家工作的 80% . "——福布斯
NLP 建模项目也不例外——通常最耗时的步骤是整理数据,然后从清理后的数据中开发特征。有许多工具可以促进这一过程,但仍然很费力。
为了帮助特征工程步骤,中佛罗里达大学的研究人员发表了一篇 2021 年的论文,该论文利用遗传算法来删除不重要的标记化文本。遗传算法(GA)是受进化启发的优化,在复杂数据上表现良好,因此它们自然也适用于 NLP 数据。它们也很容易并行化并且易于实现。
让我们从技术概述开始,然后深入了解到底发生了什么…
技术 TLDR
- 将你的数据符号化,建立一个词汇表。引用的论文使用 python 包 mosestokenizer 将句子拆分成克,克是单独的符号或单词。
- 给每克分配随机权重(0 到 1 之间)。每一克代表我们人口中的一个个体。
- 调整模型的超参数并运行。调整 GA 更像是一门艺术,而不是科学,所以只需摆弄那些有意义的数字。
- 使用 ROUGE-N 模型确定精确度。引用的论文使用了 ROUGE-N 的 F1 评分,这是精度和召回率的平均值,但您可以使用其他目标函数。
- 标记新数据并开始开发您的 NLP 模型。既然您的 GA 已经训练好了,您可以标记一个看不见的训练集并开发您的 NLP 模型。
酷,但是这实际上是如何工作的呢?
让我们慢一点,围绕遗传算法发展一些直觉。
什么是遗传算法?
首先,我们来讨论 GA 是如何工作的。
图 2:遗传算法生成的流程图。图片作者。
在图 2 中,我们可以看到遗传算法的流程——它并不像看起来那么复杂。我们将我们的人口(黄框)初始化为克的加权向量,其中每个克的值是一个单词或符号。权重被随机初始化为 0 到 1 之间的值。
接下来,我们将初始人口输入算法。深蓝色的值对应于我们算法中的单个世代。浅蓝色的交叉和突变是变异的类型。让我们依次看一看每一个:
- 适应度函数:首先,我们定义了我们的适应度函数,它计算了一个个体繁衍后代的概率。在我们的例子中,我们将使用 ROUGE-N 的 F1 值。更高的分数意味着一个个体更有可能繁衍后代。
- 父母选择:接下来,我们定义谁能和谁不能繁殖。论文中的例子使用了一种叫做锦标赛选择的东西,我们随机抽取个人样本并选出一个获胜者。胜利者可以繁殖后代。
- 交配池:在这一步,我们将获胜的父母聚集成随机的一对。
- 变化:接下来,我们以预定义的方式随机改变我们的数据,希望创建一个更适合的群体。第一种方法叫做交叉,涉及到两个父母交换他们的权重的某个百分比,并返回这两个新的权重向量作为孩子。通常,这个百分比是由随机选择的交叉指数决定的;交换超过该索引的所有值。第二种叫做突变,涉及随机改变每个父代的低概率权重。
- 后代:从这里,我们可以聚合父母和后代。如果有一个人数上限,我们会去掉最不合适的人,直到我们在这个上限之下。
一代完成后,我们评估我们人口的适应性。如果满足我们的停止标准,我们将返回重量总体,并对它们进行平均,以获得每克重量的单个值。如果我们的停止标准没有得到满足,我们的人口被认为是不适合的,我们喂养的个体到另一代。
抛开伦理不谈,遗传算法很酷,对吧?
如果你仍然不相信,这里有一个 GA,它试图通过反复试验来猜测一个句子的内容…
图 3:试图猜测句子价值的遗传算法。图片作者。
如果我们使用暴力方法,我们将需要尝试 n^k 组合,其中 n 是我们字符串中的字符总数,而 k 是我们字母表中的字母总数。该示例将采用 27⁵以上的可能组合(小写/大写字符和一个空格)。
遗传算法在 51 代人口规模为 30 的情况下猜测了我们的字符串,这意味着它测试了不到 1530 个组合,以得出正确的结果。并且,它还尝试了符号。
但是,它们为什么有效呢?
遗传算法在复杂数据上表现良好。传统的基于梯度的优化,使用模型的导数来确定搜索的方向,要求我们的模型首先有导数。因此,如果模型是不可微的,我们很遗憾不能使用基于梯度的优化。此外,如果梯度非常“颠簸”,基本的梯度优化,如随机梯度下降,可能不会找到全局最优。
另一方面,遗传算法不需要可微分的模型。它们的随机性也有助于它们避免陷入局部最优,这非常适合“颠簸”和复杂的梯度,如克重。它们也很容易并行化,只要稍加调整,开箱即用就能很好地工作。
遗传算法的主要缺点是它们不能保证最优解,无论是局部的还是全局的。对于需要优化的情况,这可能是一个交易破坏者。
直观的例子
在我们的最后一节中,让我们来看看一种训练“船只”避开障碍物并找到红色方块的遗传算法。
图 4:训练船只避开障碍物并找到红色方块的遗传算法的可视化。图片作者。
如果我们看一下上面的图 4,我们会很快注意到,从第 3 代到第 5 代,船只在避开绿色矩形方面有所改进。这是因为如果他们的“基因”使他们更有可能死亡,他们不会繁殖。
然而,在这种配置中,船只没有视线概念;他们只是随机向一个方向移动,并记住过去的工作方式。因为特征空间太差,这种配置又用了 8 代船才意外降落红场。如果我们给他们一个全新的地图,这将需要另一个完整的训练周期。
为了提高船只快速优化和归纳新问题的能力,我们需要更好的特征空间和更多的学习环境。
同样,对于 NLP,无论遗传算法执行得多好,简单的符号化通常都不能创建足够健壮的模型。更复杂的特征,如克数、前/后克数等。是开发有效模型所必需的。
遗传算法提供了一种有效且高效的方法来开发标记化文法的词汇表。不会了。不多不少。
实施说明
- 遗传算法没有最佳超参数的规则。通常的做法是,在使用机器允许的最大群体规模和世代数时,尝试几种参数组合。
- 如果令牌的大小写没有被用作特性,请将令牌转换为小写。这可以大大减少词汇量。
- 个人感兴趣的一个领域是使用 GA(和其他优化算法)来处理我们建模的特征工程部分。有什么想法吗?
感谢阅读!我将再写 45 篇文章,将“学术”研究引入 DS 行业。查看我关于将遗传算法应用于 NLP 数据的链接/想法的评论。
图像分类的遗传程序设计
人工选择作为学习计算机视觉任务的驱动力
查尔斯·达尔文的雕塑。图片来自 Unsplash 的胡尔基·奥莰·塔巴克
这里有一大群松鼠住在我的后院。进化给了它们完美的体型和灵活性来征服树木和土地。直到几年前,这个松鼠社会生活得很愉快,没有与他们的人类邻居互动。
在某个时候,我妻子安装了一个喂鸟器,这样我们就可以近距离观察鸟儿了。这些诱人的种子给松鼠带来了意想不到的机会。虽然他们进化的环境不包括任何种子分配器,但他们发明了新的行为来达到他们的目标。如果你碰巧在你的后院安装了喂鸟器,你肯定知道:无论观鸟者如何让松鼠远离种子,聪明的啮齿动物得到它们想要的东西只是时间问题。
一只聪明的松鼠。图片由 Nathalie Famery 提供。
它们不仅完美地适应了自然环境,而且当机会出现时,它们还能发明新的行为。我们无法制造出接近这种智能水平的机器。然而,进化创造了它。智力是可行的(因为它存在)但我们无法复制的东西之一。
我们无法复制松鼠所展示的智慧,但我们可以模仿物种进化中的机制。这是一个叫做进化算法的机器学习技术家族背后的想法。这些技术受自然选择的启发,模拟了给定问题的候选解决方案群体的进化。对给定任务表现最佳的候选解决方案(即个体)被选为下一代的父代。
在进化算法中,每个个体都是一个基因型(决定完成任务的指令的一组信息)的容器。当从双亲中创造一个新个体时,部分基因型从双亲中被复制。虽然我们不知道个体基因型的哪一部分有助于它的成功,但它的每个孩子都会随机地继承大约一半的遗传信息。与同代的其他个体相比,孩子的成功将决定遗传的基因是否保留在基因库中。
遗传表演程序
进化算法类别之间的主要区别在于它们代表个体的方式。在 遗传编程 中,进化算法的一个实例,个体被表示为一个叫做计算图的树形结构。计算图实现了函数的组合,其中节点表示原始函数,边表示值。这些值从原始函数中输出,并进一步传递给其他原始函数。终端可以是常量,也可以是输入变量。
表示函数 f(x,y) = sin(3x) + y 的计算图形。图片由作者提供。
用于从双亲创建孩子的两个主要操作符是交叉和变异。交叉是一种操作,通过这种操作,我们在一个亲本的图中随机选择一个切割点,并拼接从另一个亲本取得的分支。
交叉示例:用父级 2 的框架分支替换父级 1 的框架分支,以生成子级。箭头颜色代表数据类型。替换分支的输出数据类型必须与原始分支输出数据类型相匹配(本例中为绿色箭头)。图片由作者提供。
突变是用随机生长的分支替换个体(通常是新产生的孩子)中随机选择的切割点的过程。随机生长的分支可以是简单的终端节点,也可以是任意复杂的树。唯一的要求是生长分支的输出数据类型与剪切分支的数据类型相匹配。
突变实例:左手侧个体中的框架分支被右手侧个体中随机生长的分支替换。图片由作者提供。
在开创性的著作《 遗传编程:通过自然选择的方式进行计算机编程》(1992)中,John Koza 建议所有的节点都应该是可互换的,即不需要数据类型匹配。根据我的经验,在对个体的评估会导致大量计算成本的领域,比如计算机视觉,实现强类型遗传编程会更有效。通过强制节点之间的类型匹配,我们确保一个个体将代表一个可以被评估的函数。否则,我们可能会遇到这样的风险,例如,一个节点向另一个节点提供一个整数,而另一个节点需要一个图像作为输入。这种情况不是有效的函数,因此到目前为止所做的所有计算都将被浪费。
人口的进化
一旦我们知道如何在我们选择的任务域中生成有效的计算图,并且我们知道如何从父代生成后代,我们就可以应用下面的遗传编程高级算法:
遗传规划的高级算法。图片由作者提供。
图像分类
在这个库中,你会找到一个简单的图像分类任务的代码,这个任务是用遗传编程实现的。任务是将图像分类为“圆盘”和“正方形”。
我们将图像分为“圆盘”和“正方形”两类。图片由作者提供。
除了实现遗传编程算法(基于给定标准的选择和新一代的创建)的核心的代码之外,我们还需要实现特定领域的代码,它将告诉解释器原函数做什么。在我们的例子中,任务的领域是图像处理;原语函数将是 OpenCV 函数的子集。
必须规定定义个人在任务中表现如何的标准。在我们的例子中,成本(我们希望最小化的正数)将是训练集中错误分类的观察值的比例。增加了一个惩罚项,与个体拥有的节点数成比例。这是为了在同等精度的情况下,小计算图优于大计算图。
群体中每个个体的成本评估。作者代码。
一旦所有的超参数都设置好了,我们就开始种群进化。每一代,冠军个体都会被保存。停止标准可以是当一代的冠军在验证数据集上达到期望的准确度时。
图像分类器群体的成本和验证准确性(通过每一代冠军进行评估)的典型演变。图片由作者提供。
与基于梯度下降的机器学习方法相反,在梯度下降的情况下,成本函数稳定地降低(尤其是在第一个时期),遗传编程群体的成本函数往往随着连续的平稳期而降低。值得注意的是,遗传编程并不假设目标函数是可微的。由于这个原因,没有指示用于局部改善的梯度下降方向的信号。相反,遗传规划依赖于在成本函数中表现为离散步骤的定性变化(即函数架构的变化)。当一个个体从它的父母那里接受了一个新的分支组合或者产生了一个有利的突变时,这些质的变化就发生了。
结论
遗传编程是一个领域不可知的机器学习框架,它不假设一个可微分的目标函数。我用遗传编程实现了一个简单的图像分类器作为概念证明。正如你所猜测的,一个内置图像处理功能的深度学习库可以用更少的努力来执行同样的任务,但乐趣在哪里呢?
我希望像遗传编程这样的进化算法能在计算机视觉和其他领域找到越来越多的应用,特别是在原函数不易微分的地方。
随意试验代码。如果你心中有一个可以使用基因编程的应用(或者如果你有办法让松鼠远离喂鸟者),我会很高兴听到它。
[1]在文献中,我们经常遇到的不是成本,而是适合度值,这通常是一个我们希望最大化的正数。
[2]由于个体由计算图形表示,如果原函数是可微的,则可以应用反向传播。因此,梯度下降可以优化个体的常数,但对于遗传编程框架来说不是必需的。这就是为什么在我的抽象类解释器中,实现方法 FunctionDefinition() 是强制的,而实现 FunctionDerivative() 是可选的。
你如何把基因组变成一幅画
使用 Python 可视化基因组数据
“你的基因组看起来就像文森特·梵高画的二维码……”
…对我来说还不是一句搭讪的话,但直到结束才算结束。
乔治·修拉的《T4 岛上的一个星期天下午》是有史以来最著名的点彩画——成千上万个点构成了一件艺术品
乔治·修拉——芝加哥艺术学院,公共领域|有史以来最著名的点彩画。
当我开始可视化基因组数据时,我得出了这个结论:
基因组。加拿大是。艺术也是。
从左至右:家族性红斑狼疮、中华红斑狼疮、早熟红斑狼疮的 38 号染色体
看,这些不是点彩画的杰作。更像是你服用迷幻药然后盯着电视看时看到的效果。
但是我在做这件事的时候得到了很多乐趣,如果你正在学习遗传学、Python 或者 cs,你可能也会。
从左上像素开始,逐行继续,每个彩色像素代表生物体基因组序列中 4 个核苷酸中的 1 个。
为什么提到点彩?电视和显示器上的数字图像基本上是点彩“画”,用像素代替点,用 RGB 值代替油彩。
我将讲述我是如何使用初级 Python 和免费的基因数据来制作这些图像的。
弄清楚
这是我想要建造的:
输入:一个包含生物体基因组序列的. txt 文件。
输出:一个. png 图像(尽可能接近正方形),其中每个彩色像素代表一个核苷酸。
搜索 NCBI 的基因组数据库可以相当容易地找到基因组序列:例如 S. praecaptivus 、 H. cinaed i。
作者使用 ray.so
由于第一行不包含核苷酸,我们跳过它。然后将列表连接成一个字符串。
产量呢?堆栈溢出研究告诉我,我可以用numpy
创建一个空数组,用 RGB 值填充,然后将数组导出为图像使用PIL
的Image
。
作者使用 ray.so
这就是我的代码三明治的顶部和底部。现在我需要一些方法来:
- 为任何给定的序列获取适当的尺寸。(
def **dimensions**
) - 为阵列中的每个“像素”分配正确的 RGB 值。(
def **generate**
)
规模
我希望图像尽可能接近正方形,所以高度h
和宽度w
需要在数值上接近。
每个像素匹配一个核苷酸。因此,对于任何给定的长度序列seq_length
,期望尺寸h
和w
将是它们之间差异最小的因子对(即最接近的一对)。
我们称这个函数为dimensions
。
作者使用雷.索
首先,一个字符串的长度seq
= seq_length
。然后,我们取其平方根的整数形式,a
。
- 如果
seq_length
除以a
的余数为 0:则seq_length
为平方数,尺寸为a
和a
。 - 如果不是:我们给
a
加 1,然后再用seq_length
除以a
,直到余数为 0。
这将找到最接近平方根的因子对。在所有可能的因子对中,这两个永远是最接近的。****
>>> dimensions("AAAAAAAAAAAA")
[3, 4]
>>> dimensions("AAAAAAAAAAAAAAAA")
[4, 4]
>>> dimensions("AAAAAAAAAAAAAAAAAA")
[6, 3]
当我们的序列长度是一个质数:时,我们会遇到一个问题
>>> dimensions(“AAAAAAAAAAAAAAAAA”)
[17, 1]
一个 1×17 的图像很难看到,对我的祖先来说是可耻的。我必须做得更好:
作者使用 ray.so
如果我们到达a
等于seq_length
的点,我们再次递归调用seq
上的dimensions
,这一次是通过移除最后一个基数。这确保了一个非质数。
基因组通常有超过一百万个碱基长——去掉一个没问题:
>>> dimensions("AAAAAAAAAAAA")
[3, 4]
>>> dimensions("AAAAAAAAAAAAAAAAAA")
[6, 3]
>>> dimensions("AAAAAAAAAAAAAAAAA") # length = 17, remove final base
[4, 4]
就像一部独立恐怖电影高潮前迷人的二十多岁的年轻人,我以为我是安全的。但是上帝,我错了。
在一只拉布拉多寻回犬的第 38 条染色体上测试这段代码,给了我这个怪物:
就是比背景稍微亮一点的乐队。|我的电脑截图,因为我实际上无法上传这张图片。
你能看见它吗?当然不是。实际图像大约是 250,000×95 像素。
没有错,但是任何非质数的最接近的因子对仍然可能相距很远。这严重扭曲了高宽比,所以我对函数做了一些修改:
作者使用 ray.so
现在,如果a
大于或等于 5 ×另一个因子(即纵横比超过 1:5),我们在seq[:-1]
上再次递归调用dimensions
函数。这可能导致从末端去掉 1+个核苷酸——在寻回犬染色体中,我们丢失了 3 个。
虽然 vals[0]几乎总是大于 vals[1],但在极少数情况下并非如此。取列表的最小值和最大值确保宽度总是大于高度。|作者使用 ray.so
剩下要做的就是分配h
和w
值,并将它们插入到我们的数组命令中。
现在让我们用 RGB 值填充数组:
产生
我们首先创建一个字典,为每个碱基分配一个 RGB 值:
我通常使用coolors.co来查找调色板。|作者使用 ray.so
FASTA 文件(Y,R,K)中还有其他字母可能,但这是我目前遇到的唯一一个。(N 表示任何核酸)。
因为我想一行一行地进行,所以我将嵌套一个循环,该循环遍历数组中的每一行中的每一个像素(也就是每一列):
作者使用 ray.so
data[i,j]
索引数组中每个可能的元素,从左上角的data[0,0]
开始,一直到右下角的data[h-1,w-1]
,一行一行。
按作者
data
元素的坐标i
和j
与seq
字符串中的对应字符的关系如下:
data[i,j] == seq[j+i*w] #row index * width + column indexh = 10
w = 10## data[0,0] -> seq[0+0*10] = seq[0]
## data[0,9] -> seq[9+0*10] = seq[9]
## data[1,0] -> seq[0+1*10] = seq[10]
## data[9,9] -> seq[9+9*10] = seq[99]
因此,我们最终的generate
函数如下所示:
作者使用雷.索
请注意,我们没有将data[i,j]
设置为来自seq
的相应字符,而是设置为来自colours
的该字符的 RGB 值。
当我们把这些放在一起,我们得到这个:
代码本身可能会被清理,但那是以后的事了。|作者作者
将此应用于不同的基因组,我得到了一些有趣的结果:
从左上顺时针方向:家犬狼疮,染色体 38;大肠杆菌;s .邦戈里;白花蛇舌草;H. cinaedi。|作者
摆弄颜色也很有趣:
这将被用来做什么?
我有几个想法:
- 一个只接受邀请的社交网络,在这里你可以用你第七条染色体的图像代替短代码来添加好友。
- Tinder,除了你唯一能添加的图片是你的基因组可视化。这样,你知道你的对手喜欢你的内在。
- 一种加密货币,在这种货币中,你不需要从哈希函数中解密,而是必须手动将基因组 vis 翻译回字母,一个像素一个像素。
- 一个 NFT。(实际上我现在正在努力。)
- 一种视觉辅助工具,用于解释服用迷幻药后的电视画面。
我的外卖
- 我认为这是一种看待基因组数据的有趣方式。诚然,不是超级有用。但是它们看起来很酷吗?100%.(可能更像是 75%)。
- 这只是当我们把生物学和代码结合起来时,我们能做什么的一瞥。
你觉得我下一步应该做什么?我可能会对同源基因或整个进化史这样做。让我知道!
如何在基因组干草堆中找到 DNA 针
使用 Python 寻找基因组中的调控基序
穆尔托·希拉利
如果我请你帮我大海捞针,你只会出于礼节而答应。
如果我告诉你实际上干草堆里有 10 根针,而且它们看起来都略有不同,愤怒会像打掉我的牙齿一样吞噬你。
这是生物学家在寻找调控基序时面临的任务。这些是基因组中的短 DNA 片段,结合转录因子。TF 是提高或降低其他基因转录水平(表达)的蛋白质。
像针一样,调控基序通常彼此相似,但不完全相同。生物信息学家面临的问题是在他们拥有的所有遗传数据中找到彼此最相似的一组基序。
一旦我们做到了,我们就能理解重要功能背后的机制,如光合作用或结核休眠。
我已经学会了如何使用 Python 来做这件事,你可以在 Codeacademy 上学习。你也可以这样做。
在本文中,我们将:
- 为 DNA 基序矩阵生成计数和图谱矩阵。
- 创建一个一致性基序,以对我们数据中所有基序之间的保守程度进行评分。
- 根据我们的轮廓矩阵确定任何可能的模体出现的概率。
- 将这些函数编译成一个贪婪搜索算法来扫描 MTB 基因上游区域的基序。
这篇文章假设你有遗传学和 Python 的基础知识。
倒过来看
假设我们已经有了一个 motfis 矩阵,我们想要测量每个 motfis 之间的相似性——保守水平。(每列中最保守的核苷酸大写。)
(这些是来自黑腹果蝇的 NF-kB 结合位点基序,来自生物信息学算法)。|作者图片
我们的工作:
- 计算每列中最高度保守的核苷酸。(
Count()
) - 生成“共有”基序,其中每个碱基是来自
Motifs
中每列的最保守的核苷酸。(Consensus())
- 对
Motifs
中每个模体与共有模体之间的相似度进行评分。(Score()
)
计数(图案)
创建一个字典count
,其中关键字是核苷酸('A', 'C', 'T', ‘G’
),值是列表。每个列表元素是关键字的核苷酸在Motifs
的索引(列)中出现的次数:
' a '在列中出现两次,' C '出现一次,' T '出现七次。|作者
所有代码片段均由作者使用 ray.so
我们初始化一个空字典count
并用核苷酸键填充它。每一个值都是一个0
的列表,只要是Motifs
中的第一个母题。
然后我们迭代Motifs
中的每一个元素;当我们在Motifs[i][j]
遇到一个核苷酸symbol
时,我们在第j
个索引处增加那个symbol
键的值。
一个惊喜的工具,将帮助我们以后
将计数字典转换为具有Profile(Motifs)
功能的频率字典;
将count
中的每个列表元素除以Motifs
中的主题数。我们得到这样的结果:
按作者
这个以后会派上用场的。
共识(主题)
现在,我们可以调用Count()
作为子程序。在count
字典的每个索引处取最高计数的核苷酸并附加到空字符串consensus
:
按作者
在外部循环中,我们遍历来自count
的列表值中的每个元素。在内部循环中,我们遍历每个核苷酸键。这让我们可以比较第j
个索引处的每个键值。我们更新m
总是最高值,让frequentSymbol
=对应的核苷酸symbol
。
Consensus(Motifs)
>>'**TCGGGGATTTCC'**
分数(主题)
为了对基序中基序之间的保守程度进行评分,我们可以使用索引motif[j]
遍历每个元素。
外部循环的范围是行,内部循环的范围是列。
如果motif[j]
处的核苷酸符号与consensus[j]
不匹配,我们增加score
。分数越高=保守性越低。
让我们变得贪婪
我们有一种方法来衡量图案之间的保守性。现在,我们需要生成许多潜在矩阵Motifs
,并找到最小化score
的那个。
我们可以用贪婪搜索算法来做到这一点;这意味着我们的算法将在迭代的每一步选择最佳选项。更多此处。
贪婪算法有三个组成部分:
- 数据:它必须迭代一组数据。
- 规则:它遵循规则在迭代的每一步做什么。
- 结果:每一步都将该规则的结果加到答案中。
让我们定义 GreedyMotifSearch(Dna,k,t)其中:
Dna
是一个 DNA 字符串矩阵,我们正在扫描其中的图案。k
是图案的长度。t
是Dna
中 DNA 串的数量。
我们算法的组成部分:
- 数据:遍历
**Dna**
第一个字符串中所有可能的 k-mers。(外环)。 - 规则:从
Dna
中的每隔一个字符串中为那些 k-mers 找到最佳匹配。(内循环)。 - 结果:将结果追加到列表
Motifs
中。
我们可以从创建一个暂定列表BestMotifs
开始,其中每个基序都是Dna
中每个 DNA 串的第一个 k-mer。如果我们以后创建一个有更好分数的矩阵,我们将更新这个列表。
让我们从Dna[0]
中取出第一个 k-mer(再次)将其附加到一个新列表Motifs
。我们将对第一个 DNA 链中每一个可能的 k-mer 都这样做——这是我们的外环。
我们将基于从Dna[0]
中提取的第一个 k-mer 来构建Motifs
的其余部分。(这是第二步,规则)。
使用我们之前制作的Profile
函数的轮廓,我们想要在下一个 DNA 串、Dna[1]
中找到最相似的 k-mer。
怎么会?好吧,我们还没有这样做的函数,所以让我们写一个。
公关(文本,个人资料)
让我们看看我们的简介矩阵。每个元素是该核苷酸出现在基序中该位置的概率。
如果分布矩阵随机产生基序,共有序列将出现得最频繁。
我们还可以确定任何其他字符串基序出现的概率。简单地乘以每个碱基出现在各自位置的几率:
每个红色碱基都是对共有字符串(顶部)的偏离。注意当我们远离共识字符串时,每个字符串的概率是如何下降的。
更高的概率=根据Profile
更好的匹配。
参数是一个 DNA 字符串Text
和一个档案矩阵Profile
。Text[i]
是Text
中索引i
处的核苷酸,也是Profile
中列表的关键字。Profile[Text[i]][i]
是同一索引i
的概率值。
profilemostparblepattern(Text,k,Profile)
我们现在可以找到任何 k-mer 成为基序的概率——给定一个概率矩阵Profile
。
让我们遍历一长串 DNA Text
中的所有 k-mers,并根据Profile
找到最可能的一个(最佳匹配):
我们生成一个包含 k-mer 及其概率的字典,然后返回第一个具有最高值的 k-mer。(具体内联)。
现在,给定一个Profile
,一个长度k
的基元,以及一个更长的字符串Text
来扫描 k-mers,我们可以返回到GreedyMotifSearch
。
我们在下一串 DNA ( Dna[1]
)中找到最可能的模式,并将其附加到Motifs
。(这是第三步,结果)。我们更新这个新矩阵的轮廓P
,并对每个 DNA 串重复这个过程。
当我们完成内部循环时,我们可以比较Motifs
和BestMotifs
的分数。如果Motifs
得分降低,我们更新BestMotifs
;在Dna[0]
中对每个可能的 k-mer 重复该过程。
熵(主题)
我们还没有完全完成。我们的得分函数是不完善的。请注意,一些列比其他列有更多的变化,但它们仍然得分相同(第二列和最后一列)。
在该图中,每列的分数被取下来并相加。这是为了视觉辅助;在代码中,我们不需要一定遵守这种模式,也不会遵守。
跟踪每一列的守恒水平的更好的方法是测量熵。
配置文件矩阵中的每一列都是一个概率分布,即总和为 1 的正数。
熵是该分布的不确定性,通过对每个概率乘以其二进制对数求和并乘以-1 得出:
塞巴斯蒂安·科维亚特科夫斯基
更低的熵=更少的不确定性和更大的守恒。
因为我们要对所有的值求和,所以我们不必逐列进行。我还选择了减法,而不是加法,因为我们在公式中采用了最终答案的负数。结果是一样的。
遍历profile
中的每一个元素,如果概率值大于 0 就更新entropy
(否则我们无法取其二进制对数)。这种公式在实践中更常用,但为了简单起见,这里只是一个脚注。
让我们带着这个宝贝转一圈:
用结核病进行测试
你可能得了肺结核而不自知。结核分枝杆菌结核分枝杆菌(MTB)可以在你的体内潜伏多年,然后才会产生任何影响。
生物学家将缺氧(缺氧)与 MTB 潜伏期联系起来,并发现了帮助细菌在低氧条件下生存的转录因子(DosR)。
我们将观察 DosR 影响的一些基因的上游区域,试图找到一些它可能结合的基序。(我修改了GreedyMotifSearch
,用Entropy()
代替了Score()
。)
我们正在查看的 DNA 字符串可以在这里找到,我已经将它们收集到一个名为DosR
的列表中。
您的结果:
['ATGACCAGCGAGCTG',
'CCGATCGGCATCACT',
'ACCGTCGATGTGCCC',
'GGGTCAGGTATATTT',
'GTGACCGACGTCCCC',
'CCGCTGGCGACGCTG',
'GTGTCCGGCATGATC',
'CGGCCAGACAAGCTT',
'GCGATAGGTGAGATT',
'CTCATCGCTGTCATC'] 18.492751844642765 CCGACCGGCATGCTC
恭喜你,成功了!亲吻你的配偶,和一只狗击掌,开着警车兜风。
对吗?
如果你看一下文献,这些不是你要找的主题。
他们使用的算法和数据更好——贪婪算法的速度快,但准确性差。
实际上,我们今天开发的算法永远不会被使用——就像我在精神崩溃时买的滚轴溜冰鞋一样。
关键要点
- 这可能不是最重要的算法,但它为将来学习更复杂的算法奠定了基础。
- 复杂的问题可以有复杂的解决方案——但是你仍然可以使用简单的工具来构建它们(比如你可以在 Codeacademy 上免费学习的所有 Python)。
感谢阅读!
我写的其他生物信息学文章:
[## 你如何把基因组变成一幅画
towardsdatascience.com](/genome-painting-c7e2398b4579)
基因组学新衣服
理解大数据、面向生命科学的数理统计和机器学习
维数灾难如何使遗传学研究复杂化
修改自维基百科皇帝的新衣
这是我的专栏 生命科学的数理统计与机器学习 的第二十二篇文章,在这里我用通俗易懂的语言讨论了计算生物学中常见的一些神秘的分析技术。全基因组 基因分型 和全基因组测序【WGS】给生命科学中的基因研究带来了前所未有的分辨率,但也导致了高维度遗传变异数据的快速增长,遭受了 维数灾难 。在本文中,我将给出这个问题的一些理论背景,并讨论为什么在现代遗传学和基因组学中进行任何有意义和稳健的分析都极具挑战性。
基因组学:进步还是倒退?
从事基因组数据工作的每个人可能都至少听过一次资深同事说过的一句话:
我记得我曾经研究 10 种基因变异,现在由于全基因组测序技术,我们可以分析数百万种基因变异。
每当我听到这个短语,我就会想,当一名分析师与 10 种基因变异打交道时,他的生活是多么轻松,而如今分析百万维的基因变异数据是多么令人头痛。我担心基因组学研究的稳健性的原因是因为我通常从矩阵维度的 T2 角度考虑任何类型的数据。
作者图片
对我来说,分析技术的选择取决于 N(统计观察值、样本的数量)和 P(变量/测量值/特征的数量)之间的比率。在上图中,您可以看到遗传变异数据矩阵(左)的这一比率与 scRNAseq 数据(右)非常不同,尽管维度的乘积是相等的。事实上,通常对于一个 WGS 项目,我们可以对大约 1000 个样本进行测序(参见 1000 个基因组项目),而我们发现个体基因组之间有数百万个突变差异,因此特征空间是百万维的。这与单细胞测序中的数据结构是正交的,在单细胞测序中,样本大小每年都打破记录,接近百万个测序的细胞,而每个细胞表达的基因数量通常被限制在大约 1000 个,至少对于高通量 10X 基因组学技术而言是如此。因此,虽然包含相似数量的元素,但来自遗传变异和 scRNAseq 的数据矩阵却截然不同。我将 scRNAseq 称为大数据,因为它为分析提供了很大的灵活性和统计能力。相比之下,我倾向于将基因变异视为少量数据,因为使用这种高维数据类型有许多限制。
基因组学中的高维 P >> N 极限
通常,我会选择一种特定类型的分析,着眼于数据的维度。例如,如果 N ~ P 或 N > P,我们可以使用传统的频率统计。如果我们有很多数据点,即 N > > P(流行病学极限),人们当然可以再次使用频率统计,但这个极限给了我们更多的自由来尝试非线性方法,如机器和深度学习。最后,在最困难的极限 P > > N(高维数据)中,频率统计的假设,如正态假设,不再有效,人们应该在贝叶斯方法中使用一些正则化或先验。如你所见,基因变异数据落入 P > > N 极限。
图片由作者修改自维基百科
为什么在极限 P >> N 中继续使用传统的频率统计是危险的?一个例子是线性回归 Y~X 问题,其中 X 是高维的基因型矩阵,Y 是感兴趣的变量(性状或表型)。原来线性回归问题在高维(P >> N)极限下无法求解是因为协方差矩阵不能求逆,在极限下由于维数灾难而发散。
另一个例子是最大似然法中著名的 有偏方差估计 (这是频率统计的同义词)。可以推导出最大化 p 维多元高斯分布估计的方差为
在这里,您可以清楚地看到 N 和 P 之间的相互作用,即 P 越接近 N(仍然提供 N > P ),方差估计值就越有偏差。我不知道这个方程在高维极限 P > > N 下会是什么样子。我假设卡尔·皮尔逊、罗兰费希尔和其他频率主义方法的创始人从来没有考虑过可能存在维数为 P > N 的数据
一种有趣的方式来展示高维(P >> N)和低维(P << N) data is to compute the 主成分分析(PCA) 之间的差异,并显示特征值的分布,这至少对于具有不同维度的随机矩阵可以很容易地完成。
从上图中,我们可以看到不同维度数据的特征值分布形状和计算范围之间的明显差异。特征值遵循 Marchenko-Pastur 定律,这种分布可用于进一步研究高维基因组数据的性质。
基因组数据的稀疏性
基因组学中维数灾难的一个显著表现是基因组学数据的稀疏性。稀疏性是指对实验中测量的某些变量范围缺乏统计观察(通常是由于采样不良)。在基因组学的情况下,稀疏性是无法找到足够多的 稀有等位基因 携带者的结果。考虑 100 个个体中的 3 个单核苷酸多态性 基因型。假设所有三个 SNP 的次要等位基因频率(MAF) 为 10%,我们可以预计每个 SNP 只有 10 个次要等位基因携带者,两个 SNP 同时只有 1 个次要等位基因携带者,所有三个 SNP 位置同时有 0 个次要等位基因的样本。
作者图片
因此,我们原则上不能将这 100 个个体的特征与所有 3 个 SNPs 的次要等位基因联系起来。此外,即使我们试图同时针对仅两个 SNPs、Phen ~ SNP1 + SNP2(即在 2 维空间中)进行表型(Phen)的关联,我们仍然不能稳健地计算它,因为缺少对两个次要等位基因一起的携带者的观察(仅有 1 个样本)。在下图中,圆圈是次要等位基因的载体。对于 1D 问题,Phen ~ SNP A,我们有 10 个次要和 90 个主要等位基因携带,这可能足以进行稳健的线性或逻辑回归分析。但是,当我们遇到一个 2D 问题,Phen ~ SNP A + SNP B,我们在 2D 参数空间的右下方只有 1 个样本,由于采样不当,无法进行回归分析。
作者图片
因此,尽管合理的样本量 n=100(至少对于进化生物学来说是合理的样本量),我们不能计算两个 SNP 对一个性状变异(Phen)的同时影响。此外,即使是 n=50 万参与者的英国生物银行也不能一次分析超过 4-5 个 MAF = 10%的 SNPs。注意,对于 p=1 000 000 个 SNPs(遗传英国生物银行数据集的近似维数),样本量 n = 500 000 并不足够大,我们在 p > > n 处仍有稀疏数据,遭受维数灾难。
基因组学中的缺失遗传力问题
实际上,我们能做的最好的事情就是一次分析 1 个 SNP,类似于【GWAS】【全基因组关联研究】。这意味着我们无法捕捉到变体之间的任何相互作用** ,假设一个表现型可能是由来自多个变体的次要等位基因的共现**引起的,而不是来自单个 SNPs 的影响。为了说明多个 SNPs 的影响,通常构建一个所谓的多基因风险评分(PRS) ,随后可以在独立样本中根据感兴趣的性状/表型进行验证。****
然而,这导致了一个被称为的问题,即缺失遗传率问题。问题被公式化为缺乏对来自遗传变异数据的感兴趣的表型的可靠预测。换句话说,单独检测到与感兴趣的表型相关的遗传变异,当在多基因风险评分(PRS)中折叠在一起时,不能解释感兴趣的表型中合理的变异量。****
来自 Maher 等人,自然 456,18–21,2008,图片来源
尽管已经提出了缺失遗传率问题的多种解释,但一件明显的事情是要注意,GWAS 的因果遗传变异是逐个搜索的(因为我们没有能力测试多个 SNP)并在 PRS 中以加性的方式放在一起,因此不能解释潜在可能构成表型变异的多个变异的 上位 非加性效应 。
基因组学数据中导致个体而非集体测试基因变异的维数灾难的另一个重要后果是必须校正多重测试,以减少假阳性发现的数量。然而,这似乎并没有完全解决假阳性发现的问题。正如 Naomi Altman 等人在下面的 Nature Methods 文章中优雅地展示的那样,以 5% 的可接受的 假发现率 校正多重测试仍然会导致大量假阳性,远远超出预期数量。
《维度的诅咒》。Nat 方法。2018 年 6 月;15(6):399–400
因此,即使在非常有力的 GWAS 研究中,也并不罕见地看到明显虚假的但强烈的基因信号,如“家庭车辆数量”、“看电视的时间”、“过去 3 个月每周使用手机”、“沙拉/生蔬菜摄入量”等。多亏了 GWASbot ,如今这种情况可以被探测和探索。
英国生物银行数据,来源: GWASbot
看电视的时间来自英国生物银行的数据,来源: GWASbot
那些表型很难相信是 可遗传的 ,因此它们强烈的“遗传信号”可能来源于被另一个因素如群体结构混淆。现实中很少知道混杂因素,这一事实使我们使用遗传研究预测常见性状(如疾病)的能力变得更加复杂,例如 精准医疗 。
因此,如果我们使用 GWAS 研究中发现的基因变异来预测常见疾病,如二型糖尿病(T2D) 和腹主动脉瘤(AAA) ,与基于临床因素(体温、血压等)的预测相比,这可能不会成功。)单独来看,见下文。
Lyssenko 等人,2008,新英格兰医学杂志 359,2220–2232
临床风险因素、DNA 变异和二型糖尿病的发展
李等,2018,Cell 174,1361–1372
解码腹主动脉瘤基因组学
此外,最近的一项研究表明,在区分复杂的人类疾病方面,微生物组数据的预测能力超过了GWAS 的研究。
Tierney 等人,在复杂人类疾病的鉴别中,微生物组的预测能力超过了全基因组关联研究
基于遗传变异数据的不良预测是数据的非常复杂的高维本质的另一个证明,该数据遭受维数灾难。
维数灾难理论
让我们给维数灾难一些理论背景。如果我们设想一个高维数据,比如基因变异,我们会非常惊讶地发现这些数据在高维数据中是多么奇怪。例如,让我们模拟一个均匀分布在 p 维球https://en.wikipedia.org/wiki/Volume_of_an_n-ball中的数据,p = 2、5、10、100,将数据的任意两个维度可视化:
事实证明,当空间的维数增加时,数据点越来越集中在具有中空中心的 p 维球的表面上。此外,如果我们绘制成对的欧几里得距离的直方图,随着空间维度的增长,数据点将看起来彼此越来越等距和远离****,请注意当增加下图中的维度时,分布如何变得更窄并向更大的距离移动。********
可以推导出平均成对欧几里德距离随着维数的平方根而增长。这个定律清楚地表明,在高维空间中,数据点彼此远离。****
为了从经验上证明这一定律,我们将构建一个随机数据矩阵,计算所有数据点对之间的欧几里德距离,并可视化这种相关性。下图中的绿色曲线是平均距离,红色曲线显示平均值的两个标准偏差。
后一幅图显示了数据点之间的平均成对欧几里德距离,作为对数标度上维数的函数。计算普通最小二乘(OLS)线性回归可以得到直线的斜率等于 0.56 ,接近于理论值 0.5 。以类似的方式,计算任何给定数据点与其最近、中间和最远邻居之间的平均距离,可以得到下图:
我们可以看到,在高维空间中,从一个数据点到其最近和最远邻居的距离之间的差异变得不可区分。这意味着我们不能再根据相似性度量将“好的”、“坏的”和“难看的”数据点组合在一起。因此,高维空间中的聚类被广泛认为是非常不可靠的,仅仅因为所有的数据点看起来彼此同样相似。就遗传变异数据而言,这意味着例如“患病”和“健康”个体不能根据它们的遗传信息被可靠地分开,这导致对性状的不良预测,并最终导致缺失遗传率问题。在我的上一篇文章如何在高维空间中聚类中,我试图详细探讨聚类问题。您可能还想查看文章在高维度中没有真正的影响,以更好地直观了解高维度数据分析中的怪异现象。
高维数据点分组不佳的另一个表现是数据点之间的相关性非常弱。下面,我们构造一个服从正态分布的随机数据矩阵,并计算所有数据点对之间的皮尔逊相关系数。
上图显示了样本对之间的最大皮尔逊相关,作为数据维度增加的函数。我们观察到,当维数达到大约 100 时,没有一对数据点表现出与系数高于 0.5 的皮尔逊相关,这意味着数据点越来越难以在高维度中分组和聚类。就遗传变异而言,通过使用基因型的原始矩阵,根据样本的遗传背景将样本分配到某个群体是有问题的。为了解决这个问题,人们至少应该尝试 减小尺寸 。
对抗维数灾难的方法
我们能做些什么来最小化基因组数据中维数灾难的损害?我认为以下四个选项可以改进我们在遗传学研究领域的分析:
增加样本量是一种蛮力方法,并不总是负担得起,但这是最直接的方法。正则化在我看来应该更多的用在遗传学研究中。至少在滑动窗口中用套索进行全基因组关联研究似乎是一件可行的事情,可以解决上位的问题,而不会因为维数灾难而产生很多问题。进行降维,用潜变量替代原始基因型数据,似乎是克服维数灾难问题的一种相对简单有效的方法,文献中已经有一些有希望的尝试。最后,贝叶斯统计是在动力不足的研究中进行有意义分析的另一种方式,这要归功于先验,其本质上提供了正则化并降低了对于高维遗传变异数据https://en.wikipedia.org/wiki/Overfitting过度拟合的风险。****
摘要
在这篇文章中,我们已经了解到,由于数据的高维性会遭受维数灾难,因此用遗传变异数据进行稳健分析是极具挑战性的。由于样本量小和遗传变异数据的稀疏性,遗传学分析通常会导致常见性状的预测能力差,这就是所谓的缺失遗传力问题。当数据点变得等距并且彼此相关性很差时,高维数据表现出反直觉的方式,这导致在聚类数据时出现严重问题。
像往常一样,让我在下面的评论中知道生命科学和计算生物学中的哪些话题对你来说似乎是特别神秘的,我会在这个专栏中尝试回答这些问题。在我的 github 上查看完整的笔记本。在 Medium 关注我,在 Twitter @NikolayOskolkov 关注我,在 Linkedin 关注我。在下一篇文章中,我们将讨论如何在 UMAP 空间聚集,敬请关注。****
温和介绍 2D 手姿态估计:方法解释
让自己舒服点,这是一篇很长的文章
作者图片
2018 年,我花了 6 个月时间完成了关于手部姿态估计的硕士论文。那是我生命中充满挑战和深刻见解的一段时期,由此产生了 40 页的研究报告。直到现在,我还会收到工作面试邀请,以及感谢信和问题信,这让我认为这项研究仍然有意义,即使 3 年已经过去了——对于深度学习来说,这是一段很长的时间。
我的论文是关于 2D 和从一个单一的 RGB 图像的三维手姿态估计。3D 部分是…嗯…我不会说这是一个彻底的失败,但接近于失败: )然而,2D 部分(令人惊讶地)可与当时最先进的方法相媲美。
在接下来的几个月里,我计划将我的论文转化为一系列关于 2D 手部姿态估计的人性化教程:今天我们从温和地介绍这种方法开始,下一次我将展示如何在代码中实现它,稍后我们将介绍几种更高级的技术来提高模型性能。
好奇吗?我们走吧!
内容
在手部姿势估计任务中,我们到底在估计什么
一个好问题开始。
手的姿态由其关键点的位置来定义。因此,在手部姿态估计任务中,我们正在寻找关键点位置。
手有 21 个关键点:手腕+ 5 个手指* (3 个手指关节+ 1 个指尖)= 21。想想看:知道了每个关键点的位置,我们就很容易理解一个人是否表现出“手掌向下”、“拇指向上”、“拳头”或“和平”的手势。
秩序很重要。我们不仅仅需要“位置云”,我们需要关键点-位置对应。手腕在哪里?食指的指尖在哪里?等等。
图片 1。手关键点。这里秩序很重要。作者图片
一个典型的 2D 手姿态估计器看起来像这样:
- 输入:手形图像。对于许多手部姿态估计器来说,这是一个重要的假设:输入图像中只有一只手,并且图像被裁剪以排除任何其他身体部位和背景项目。
- 输出😦 x,y)关键点位置列表。位置可以表示为像素位置,其中 x 和 y 在范围[0,image_size]内,或者表示为归一化位置-在范围[0,1]内。归一化位置是像素位置除以图像大小。希望,下面的例子能说清楚。
图片 2。典型 2D 手姿态估计器的可视化。作者图片
还有几件事需要澄清。
二手怎么样?通常,我们训练姿态估计器只为右手(或左手)工作。如果我们想对左手进行推理,我们只需给出一个看起来完全像右手的镜像模型。
通常,在论文(或演示)中手的姿势被可视化为一个骨架,有时还有多色手指。不要让它误导你,骨骼的绘制是为了可视化的目的,通过用线连接关键点。我们知道关键点的顺序,所以我们知道连接哪些关键点对来绘制骨架,对吗?
图片 3。左图:手部姿势是如何被可视化的。右图:如何估计手部姿势。作者图片
在本教程中,我们将学习如何从单一的 RGB 图像中估计 2D 的手部姿态。这意味着,我们将训练一个输入单个 RGB 图像并输出图像平面上的关键点位置的模型。然而,手姿态估计是一个不同任务的大家族:你可以估计具有单个 RGB、单个深度、单个 RGBD(RGB+深度)图像或者甚至多个图像的 2D 或者甚至 3D 手姿态。也许,我会写一个帖子展示所有这些任务的多样性。但是现在,让我们继续。
哪里可以找到数据集(以及如何理解它)
尽管收集和(更重要的是)标记手部姿势数据并不是一件容易的事情,但互联网上有几十个数据集。根据您的研究或业务目标,您可能需要:
- 真实或合成数据
- 照片或视频序列
- 图像类型:RGB、深度、RGBD 或立体
- 显示符号或与物体互动的手
- 自我中心或第三人称观点
- 标签:2D 位置,三维位置,网格,手面具,...
- 标记的关键点数量
- 被遮挡的关键点是否被标记,图像中是否存在所有关键点等
你可以在 Github 资源库[2]中找到的所有开源数据集的完整列表。出于学习和研究的目的,您可以随意使用这些数据集,但是,如果您计划为企业培训模型,请确保数据集许可允许这样做。
对于本教程,我选择了 FreiHAND 数据集[3]。它包含 33k 个右手实像,并有 21 个关键点的 2D 标签。这就是我们目前所需要的。
图片 4。带有 2D 关键点标签的弗赖汉德数据集的随机样本。
颜色:拇指绿色,食指青色,中指蓝色,戒指粉色,小指红色。
FreiHAND 数据集干净且结构良好,但是,请注意:
- 关键点位置的顺序和我在图 1 中展示的一样。标签存储在 2D numpy 数组中,其中手腕的位置在第 0 行,小指指尖的位置在第 20 行。
- 你需要自己计算 2D 的位置,使用 3D 位置和相机矩阵。使用我在 FreiHAND 数据集 Github repo [4]中找到的公式:
def projectPoints(xyz, K):
xyz = np.array(xyz)
K = np.array(K)
uv = np.matmul(K, xyz.T).T
return uv[:, :2] / uv[:, -1:]
- 在训练部分,有 130,240 个图像,只有 32,560 个标签。这些标签仅适用于前 32,560 张原始图像。如果您想要在所有图像(原始图像+增强图像)上训练模型,以下是获取标签的方法:
image_labels = labels_array[image_id % 32560]
那是因为图像 32560 看起来和图像 0 一模一样,以此类推。
如何对训练数据进行预处理
下面是一个逐步说明:
1.将数据集拆分为训练、验证和测试部分。像往常一样,训练集将用于训练模型,验证部分我们选择何时停止训练,我们在测试集上评估模型性能。
2.将图像大小调整为 128×128 像素。手是一个简单的物体,所以这样的尺寸应该没问题。如果关键点位置是像素格式,请确保您也“调整”它们的大小。
图片 5。调整图像大小时,关键点位置也应该“调整大小”。作者图片
3.原始图像值在范围[0,255]内,最小-最大缩放它们到范围[0,1]内。
4.标准使用训练集平均值和标准偏差归一化图像。每个通道(R,G,B)分别归一化,所以总共有 3 个均值和 3 个标准差。通道均值(和标准差)是在一个颜色通道内的所有图像的所有像素中计算的。
5.从一系列关键点位置创建热图。用热图估计姿势是 2D 手(和人类)姿势估计中广泛使用的方法,你会在任何论文中看到它(稍作修改)。
我相信研究[5]是最早使用热图的领域之一。
我们需要为每个关键点创建一个单独的热图,因此总共有 21 个热图。详情请看下图。
图片 6。如何为关键点创建热图?作者图片
热图是模糊的,以防止模型过度拟合,并使学习稳定和更快。实际的模糊参数并不重要,这里唯一的规则是不要让关键点“点”太大或太小。需要最终的最小-最大缩放,因为我们将在神经网络的最后一层使用 Sigmoid 变换,因此热图和模型预测在相同的范围内。
总结一下:
- x 是大小为 3x128x128 的图像。
- y 是一个大小为 21x128x128 的数组,包含 21 个与输入图像大小相同的堆叠热图。确保热图顺序与图 1 中的关键点顺序相同。
使用什么模型架构
我们需要某种编码器-解码器模型,因为输出与输入的大小相同——128×128。我个人在这里的偏好是 UNet [6]。我和 UNets 一起工作过很多次,用它们完成各种分割任务,它们的表现总是令人惊叹。
我们不需要像原始论文[6]中那样复杂的 UNet,因为手是一个简单的对象。让我们从这样的事情开始:
图 7。我的简单的自定义 UNet-like 模型 2D 手姿态估计。作者图片
培训详情
损失。大多数论文使用热图的 MSE 损失,例如,这两篇关于 2D 人体姿态估计的流行论文— [7],[8]。我花了一些时间玩 MSE 损失,但它就是不起作用。
然后我找到了论文[9],其中作者使用交集/并集(IoU)损失训练了一个语义分割模型。2D 手部姿态估计类似于分割,唯一的区别是热图具有范围[0,1]内的连续值,而不仅仅是二进制标签 0/1 作为分割掩码。然而,我们可以使用[9]中的公式,对热图稍加修改。而且很管用!
形象 8。如何计算热图的 IoU 损失?yi —预测值,ti —热图中像素的目标值。分别为每个热图计算损失,然后在所有 21 个热图中求平均值,再在批中的图像中求平均值。
训练。对于本教程,我用 batch_size=48 和 batches_per_epoch=50 对模型进行了训练。我从学习率=0.1 开始,每次训练损失停止减少时,就减少一半。当验证集上的损失停止下降时,我完成了培训。收敛花了大约 200 个历元(在 GPU 上花了 2 个小时),我最终的训练和验证损失分别是 0.437 和 0.476。
这些数字只是地标。在训练您的模型时,您可能会得出不同数量的要收敛的历元和略有不同的最终损失。此外,随意增加/减少批量大小以适应您的机器内存,并增加/减少学习率。
理解并可视化模型预测
所以现在我们有了一个输出热图的训练过的模型。然而,热图不是关键点位置,因此需要额外的后处理。通过查看热图,我们可以很容易地理解模型认为关键点位于何处。是的,它是“白色”区域的中心,一个具有最大值的区域。因此,让我们在后期处理中加入相同的逻辑。
图片 9。测试集中随机图像的模型输出。作者图片
有两个选项:
- 最简单的是,我们可以在热图中找到一个值最大的像素。这个像素的(x,y)位置是关键点位置。
- 但是更可靠的方法是计算所有热图值的平均值。关于如何做到这一点的详细信息,请参见下图。
图片 10。如何通过平均计算热图中的关键点位置?作者图片
现在我们准备评估模型并可视化预测。该模型适用于大多数姿势,但是,它不适用于具有严重关键点遮挡的姿势。好吧,标记被遮挡的关键点即使对于人类注释者来说也不是一件容易的事情。
图 11。可视化测试集上的预测。
这是测试集上的模型精确度。通过对图像中所有关键点的误差进行平均,然后对所有图像的误差进行平均,来计算平均误差。4.5% —还不错!
- 平均误差:图像尺寸的 4.5%
- 平均误差:图像 128×128 为 6 个像素
- 平均误差:图像 224×224 为 10 像素
下一步是什么
我很高兴你已经读到这里了。希望,现在 2D 手的姿势估计对你清楚多了。但是…
当你能编码的时候你就知道了,对吗?: )所以在本教程的下一部分,我将分享和解释所有的代码,你将学习如何自己训练一个 2D 手姿态估计器。不要关闭你的 Jupyter 笔记本!
更新:第二部已经在 这里可用。
参考
[2]"Awesome Hand Pose Estimation",这是一个 Github 知识库,包含一系列开源数据集和论文。
[3] FreiHAND 数据集,这里可以下载。
[4] FreiHAND 数据集 Github 知识库。
[5]托马斯·菲斯特,詹姆斯·查尔斯,安德鲁·齐塞曼。"视频中人体姿态估计的流动变换"
[6]奥拉夫·龙内贝格,菲利普·菲舍尔,托马斯·布罗克斯。" U-Net:生物医学图像分割的卷积网络"
[7]施-韦恩,瓦伦·罗摩克里希纳,金德武夫,亚塞尔·谢赫。回旋摆姿机
[8]亚历杭德罗·纽维尔,·杨,贾登."用于人体姿态估计的堆叠沙漏网络"
[9]阿蒂古尔·拉赫曼博士和王洋。"优化用于图像分割的深度神经网络中的交并运算"
原载于 2021 年 4 月 21 日https:notrocketseconomy . blog。
如果你想阅读更多类似的教程,请订阅我的博客“不是火箭科学”——电报 和 推特 。
温柔介绍 2D 手姿势估计:我们来编码吧!
了解如何在 PyTorch 中训练 2D 手部姿态估计器。本教程也可能是您对 PyTorch 的介绍。
作者图片
欢迎回来!
我们继续我们的手姿态估计之旅。现在你正在读第二部分,是关于编码和 PyTorch 的。我强烈建议您在深入研究编码之前阅读第一部分:
这将对你理解数据集、预处理、建模、训练和评估有很大帮助。
对于本教程,我已经创建了一个 Github 库,在那里你可以找到关于训练手部姿态估计器和进行推理的完整代码。你可以现在或以后去那里——克隆它,阅读它并运行它。它是在 PyTorch 中实现的,如果您以前没有使用过这个库,这是一个很好的开始机会!这里不需要 PyTorch 的经验;我将解释所有的主要概念,所以本教程也可以作为你对 PyTorch 的介绍。
现在…打开你们的 Jupyter 笔记本!
内容
数据
让我们训练
—数据加载器
—模型
—训练器
让我们做推理
—后期处理
—评估
接下来
数据
先说数据。我们将使用 FreiHAND 数据集,您可以在此下载。花些时间阅读数据集描述、探索归档结构以及打开图像和文件将会非常有用。请熟悉我们将在本教程中使用的数据。
图片 1。FreiHAND 数据集文件夹结构。绿色表示本教程所需的文件。作者图片
现在,我们只需要一个包含 RGB 图像和 2D 标签的文件夹。通过使用相机矩阵将 3D 标签投影到图像平面上来计算 2D 标签。这是我在 FreiHAND 数据集 Github repo 中找到的一个公式:
def projectPoints(xyz, K):
xyz = np.array(xyz)
K = np.array(K)
uv = np.matmul(K, xyz.T).T
return uv[:, :2] / uv[:, -1:]
我们将只使用前 32,560 张图像,即原始图像。数据集中的其他图像与原始图像完全相同,但有背景增强,所以我们现在跳过它们。
数据集分割。 FreiHAND 数据集已经看起来像一组混洗的手图像,因此我们可以按图像 id 进行分割。让前 80%成为训练部分,接下来的 15% —验证,最后的 5% —测试。训练图像主要用于训练、验证(控制验证损失并决定何时停止模型训练)和测试(进行最终模型评估)。
形象二。数据集分为训练、验证和测试部分。作者图片
让我们训练吧
为了训练一个模型,我们需要:
- 数据加载器类。 FreiHAND 数据集(因为大多数图像数据集)太大,无法完全存储在 RAM 中,因此我们将使用批量训练来训练模型。因此,需要 DataLoader,它遍历数据集,一次只加载一批数据。
- 模特类。我们将创建自己的定制 UNet 类模型。
- 培训师类。这个类完成所有的训练:请求批量数据,获得模型预测,计算损失,更新模型权重,评估模型,并在验证损失停止减少时完成训练。
我们现在将详细讨论所有这些类。并查看一个笔记本有完整的培训流程。
图三。培训渠道和所需 PyTorch 课程。作者图片
数据加载器
我们将使用两个 PyTorch 类来加载数据。
数据加载器 。这个类是在 PyTorch 中实现的,所以你只要调用它,提供 Dataset 类的一个实例和一些其他参数(检查它们的含义这里):
train_dataloader = DataLoader(
dataset=train_dataset,
batch_size=48,
shuffle=True,
drop_last=True,
num_workers=2
)
现在我们可以像这样循环数据加载器:
for data_batch in train_dataloader:
# do something
数据集 。PyTorch 有一个已实现数据集的小列表,你可以在那里找到你需要的。但是,请做好准备—在大多数情况下,您将编写自己的数据集类。今天就是这一天。
当您遵循以下规则时,数据集类不难编写:
- 你的数据集类继承(子类)torch . utils . data . Dataset
- 你需要重写函数 len() ,它返回数据集的长度。您可以在这里输入带标签文件的长度,或者文件夹中图像的数量。
- 并且您需要重写函数 getitem() ,该函数获取样本 id 并返回一个包含图像及其标签的列表或字典。稍后, getitem() 的输出会被 DataLoader 批量堆栈。
因此,FreiHAND 数据集的数据集类应该如下所示。完整版在 Github 上。
from torch.utils.data import Dataset
class FreiHAND(Dataset):
def __init__(self, config, set_type="train"):
## initialize path to image folders
## initialize paths to files with labels
## create train/test/val split
## define data augmentations
def __len__(self):
return len(self.anno)
def __getitem__(self, idx):
## load image by id, use PIL librabry
## load its labels
## do augmentations if needed
## convert everything into PyTorch Tensors
return {
"image": image,
"keypoints": keypoints,
"heatmaps": heatmaps,
"image_name": image_name,
"image_raw": image_raw,
}
我个人倾向于将所有图像信息添加到 getitem() 输出中——原始图像、调整大小和标准化的图像、图像名称、数字形式的关键点以及热图形式的关键点。当我调试、绘制图像或评估模型准确性时,它大大简化了我的生活。
不要忘记使用函数计算 R、G、B 通道平均值和标准偏差(就在数据集和数据加载器初始化之前)。然后将值添加到 Dataset 类中的 Normalize() 转换中;它发生在 Resize() 变换之前或之后——查看这里如何做到这一点。只有现在—初始化数据集和数据加载器。
总之,将有 3 个数据集类实例(train_dataset、val_dataset 和 test_dataset)和 3 个数据加载器类实例(train_dataloader、val_dataloder 和 test_dataloader)。这是因为训练集、验证集和测试集是完全不同的图像集。
但是,您不需要编写 3 个不同的数据集类。一个就够了。创建数据集实例时只需提供 set_type 参数,如下所示:
train_dataset = FreiHAND(config=config, set_type="train")
train_dataloader = DataLoader(
dataset=train_dataset,
batch_size=config["batch_size"],
shuffle=True,
drop_last=True,
num_workers=2
)
确保在数据集类中有一个代码片段,将图像分成训练、验证和测试部分。
模型
PyTorch 中的实现和预训练模型的列表非常庞大——有用于图像分类、视频分类、语义和实例分割、对象检测的模型,甚至还有一个用于人体关键点检测的模型。受过预先训练。是不是很酷?!
但是出于研究的目的,我们将实现我们自己的类似 UNet 的架构。这一个:
形象 4。我的自定义 UNet-like 模型 2D 手姿态估计。作者图片
PyTorch 中的所有定制模型都应该子类化 torch.nn.Module 并重写函数 forward() 。UNet 不是典型的前馈网络,它具有跳跃连接。因此,在向前传递的过程中,应该保存一些层的输出,稍后再与更深层的输出连接。这里没有问题,你可以写任何类型的向前传球,PyTorch 会理解如何自己向后传球。
因此,我们的定制 UNet 模型应该是这样的。而这里有一个完整版。
class ShallowUNet(nn.Module):
def __init__(self, in_channel, out_channel):
super().__init__()
# initialize layer - custom or from PyTorch list def forward(self, x):
# implement forward pass
# you can do literally anything here
return out
顺便说一下,如果你的模型有一些重复的块,你可以将块实现为模块,就像模型一样——通过子类化 torch.nn.Module 并重写函数 forward() 。看,我是怎么用 UNet 中的双卷积块做到的。
class ConvBlock(nn.Module):
def __init__(self, in_depth, out_depth):
super().__init__()
self.double_conv = nn.Sequential(
nn.BatchNorm2d(in_depth),
nn.Conv2d(in_depth, out_depth, kernel_size=3, padding=1, bias=False),
nn.ReLU(inplace=True),
nn.BatchNorm2d(out_depth),
nn.Conv2d(out_depth, out_depth, kernel_size=3, padding=1, bias=False),
nn.ReLU(inplace=True),
) def forward(self, x):
return self.double_conv(x)
运动鞋
训练师类是 PyTorch 根本没有的,所以你需要从头开始写,使用来自 PyTorch 教程的代码片段。
有时这让我感到害怕,但有时我看到了好处:它让我更好地理解训练过程中发生的事情,并让我完全控制训练。
这是训练师的代号。我不打算在这篇文章中展示训练器代码,因为确切的代码没有数据集和模型类那么重要。顺便说一下,你甚至不需要把培训师写成一个职业,这是我个人的偏好。你可以使用函数,或者只是把你所有的训练代码放在一个 Jupyter 笔记本单元中——由你决定。
但是,在编写培训代码时,需要记住一些事情:
- 每个时期应该具有训练和评估阶段。在训练之前,您需要显式地将模型置于训练模式,这样做— model.train() 。评测也是一样——model . eval()。这是因为一些层在训练和评估/推断期间可能表现不同,例如 Dropout 和 BatchNorm。
- 在评估过程中,您可以额外使用 torch.no_grad() 功能。它告诉你的模型“现在不要计算梯度”,所以向前传递会更快,使用更少的内存。
- 您不必在训练(或验证)期间遍历所有训练(或验证)数据集。好主意是限制每个时期的训练和验证批次的数量。
- 对于那些对 GPU 培训感兴趣的人。您的数据和模型应该在完全相同的设备上。默认情况下,torch 张量和模型被初始化在 CPU 上,因此如果 GPU 可用,您应该显式地将它们转移到 GPU。下面是如何做到这一点的代码片段:
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(device)
inputs = data["image"].to(device)
labels = data["heatmaps"].to(device)
是的,标签也一样,否则你将无法计算损失,因为模型输出是在 GPU 上。
在 GPU 上训练模型并在 CPU 上运行预测是没问题的,反之亦然。仅在加载模型权重时这样做:
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.load_state_dict(torch.load(model_path, map_location=device)))
损失。 PyTorch 已经实现了标准损耗,但是,如果你想使用自定义损耗,那就是你需要自己编写的。自定义损耗的实现方式与模型相同——通过子类化 torch.nn.Module 和重写函数 forward() 。下面是一个简短的模板,完整版本你可以在这里找到。
class IoULoss(nn.Module):
def __init__(self):
super(IoULoss, self).__init__()
#initialize parameters def forward(self, y_pred, y_true):
#calculate loss from labels and predicitons
return loss
关于训练就是这样。如果你还没做过,我真的推荐你去翻翻 Train Notebook.ipynb 。
如果您希望自己重新训练模型,这应该是本教程前一部分的一个有用的文本片段:
“对于本教程,我用 batch_size=48 和 batches_per_epoch=50 对模型进行了训练。我从学习率=0.1 开始,每次训练损失停止减少时,就减少一半。当验证集上的损失停止下降时,我完成了培训。收敛花了大约 200 个历元(在 GPU 上花了 2 个小时),我最终的训练和验证损失分别是 0.437 和 0.476。
这些数字只是地标。在训练您的模型时,您可能会得出不同数量的要收敛的历元和略有不同的最终损失。此外,随意增加/减少批量大小以适应您的机器内存,并增加/减少学习率。"
祝你好运!
让我们做推论
推理管道比训练管道简单得多。我们只需要:
- 加载训练好的模型;
- 为测试集创建 dataloader 的实例;
- 编写将热图转换为关键点位置矢量的后处理器;
- 并且,理想情况下,计算测试集的预测误差,以评估模型性能。
完整代码请参考推理笔记本. ipynb 。
在您理解培训部分之后,加载模型、创建测试数据加载器和运行预测应该是容易的任务。但是在后处理和评估方面,我们现在将更加关注。
形象 4。详细的推理管道。作者图片
后处理
通过在所有热图值中求平均值来计算关键点位置更好。而这里是代码。
图片 5。如何通过平均计算热图中的关键点位置?作者图片
估价
在测试集上计算平均预测误差是必须做的事情。是的,您可以更进一步,报告最大和最小图像误差,显示百分位数,通过手指和关节计算误差,并可视化具有最大和最小误差的图像。但是现在,让我们保持简单。
以下是我的手部姿态估计器在测试集上的评估结果:
- 每个关键点的平均误差:图像尺寸的 4.5%
- 每个关键点的平均误差:图像 128×128 为 6 个像素
- 每个关键点的平均误差:图像 224×224 为 10 个像素
每个关键点的平均误差意味着 1)图像中的所有关键点和 2)数据集中的所有图像之间的平均误差。它可以报告为图像大小的百分比,或者原始图像或调整大小的图像的像素误差。这里的关键点误差是图像平面上实际和预测关键点位置之间的欧几里德距离。
图片 6。一些关键点预测误差的可视化。作者图片
下一步是什么
希望现在,在阅读完整教程并浏览代码后,2D 手姿态估计对你来说不再是一个复杂的任务。
然而,我们今天训练的手部姿态估计器还远远不能用于生产。它不适用于关键点被遮挡的姿态,并且不适用于来自不同数据集的图像。有很多需要改进的地方。
出于学习目的,从简单的东西开始,慢慢地,一步一步地将更高级的技术引入算法是一个好主意。也许以后我会写关于这些技术的教程。有兴趣就告诉我: )
原载于 2021 年 4 月 30 日https://notrocketseconomy . blog。
如果你想阅读更多类似的教程,请订阅我的博客“不是火箭科学”——电报 和 推特 。
地理编码和概化
通过使用网格单元概括世界来理解世界。从细节到知识。
作者图片
网格单元非常适合概括信息。这个故事是关于地理编码、概化和空间数据集的可用性,空间数据集可用于通过地理信息系统呈现空间参考数据。它最后指向优秀的 Zenodo 网站,在那里可以分发处理过的文件。
地理编码
地理编码是一种使用文本和数字的组合来唯一表示地理实体的方法。它可能是一个地点或一个物体。这是通过我们对地名的使用嵌入到我们的语言中的。
我们大多数人住在一条有名字的街上,一栋有编号的房子里。Abbey road 5 就是这样一个地理编码。这不是一个特别好的名字,因为世界上有数十条甚至数百条道路使用这个名字。你们中的一些人可能对地理编码系统很熟悉。它的基础是基于三个单词建立一个唯一的标识符。它工作得很好。
本文中介绍的地理编码系统并不完美,不是最好的,也不是最容易使用的。但是它很好,而且是免费的!
概括
在生态学和社会科学中,概括是理解空间模式的关键。空间模式使我们能够了解生态条件、疾病传播、人口模式等等。
概括是一种权衡。在任何给定的时间点准确地知道动物在自然的某一部分的位置是没有多大帮助的。要管理一个国家公园,更全面地了解动物在整个时间里的位置是有意义的。如果我们知道动物在规则网格系统中的特定细胞内移动,我们可以利用这一点将这一信息与我们所知道的该区域的其他信息进行交叉。因此,更少的细节给了我们更多关于某个领域的有用知识。所以要管理动物,你必须放开它们的确切位置。只要你能把他们的立场概括到一个有用的水平,这并不重要。这就是不知道一切的力量。
如何使用网格单元说明坦桑尼亚的物种观测。(图片由作者提供)
找到正确的概括水平并不容易。我在本文中展示的数据集系统允许用户选择要使用的网格的相关大小。它可以让你从全度网格一直到茶杯大小——如果那是你喜欢的。如果那是你喜欢的…
四分之一度网格单元
四分之一度网格单元结合了上述两种情况。该标准代表了一种方法,即制作覆盖特定区域的(几乎)相等面积的正方形,以表示所覆盖区域的特定质量。正方形本身是基于覆盖地球的度数正方形。赤道周围有 360 条经线,从北极到南极有 180 条纬线。实话实说——178 行两点(极点)。这总共给了我们覆盖地球的 64800 块瓷砖。
这怎么变成地理编码系统了?每个角度方块由对主角度方块的完全引用来指定。第一季第 10 集提到了坦桑尼亚的一个广场。 S 表示正方形在赤道以南, E 表示在零子午线以东。这些数字指的是经度和纬度。
如何将经度/纬度单元划分为更小的格网单元。(图片由作者提供)
没有子级参考的正方形也称为 QDGC level 0。这是一个正方形,基于一个完整的经度和一个完整的纬度。QDGC 0 级方块本身被分成四个,其中方块被命名为 A、B、C 和 D,成为 1 级 QDGC。
该过程可以描述如下:
- 每个度数方格由七个字符表示。第一个字符表示正方形是零子午线的东方还是西方(E 或 W)。接下来的三个数字表示方块从哪个经度开始。下一个字符表示方块是在赤道以北还是以南(北或南)。接下来是两个数字,表示到赤道线的横向距离。这是对唯一度平方的引用,称为 QDGC 级。
- 每个角度方块被分成四个方块,其中左上象限被指定为 A,右上象限被指定为 B,左下象限被指定为 C,右下象限被指定为 d,这就是 QDGC 级别 1。
- 每个生成的象限都要经过与步骤 2 中所述相同的过程。在每次迭代结束时添加一个字符象限指示器(A、B、C 或 D)。每迭代一次,级别数增加一(图 5)。
制作 QDGC 代码的必要步骤。(图片由作者提供)
你可以在几年前我和一些同事写的一篇文章中读到更多关于这个系统的内容。
生成 QDGC 网格
大约 15 年前,我开始生产供个人使用的网格电池。当时我使用 ArcGIS 和 python 来生成文件。
使用 Python 时的代码示例。(图片由作者提供)
当我们着眼于 1 级或 2 级时,生成网格并不困难。坦桑尼亚有 529 个一级牢房、1.980 个二级牢房和 7.830 个三级牢房。在大约 700x700 米的第 7 层,该数字增加到 1.960.800。不需要数学天才也能想到为所有非洲国家生产网格电池是一项艰巨的任务。每升一级,人数增加四倍。
今天,生产完全是使用 PL/pgSQL 函数完成的,这些函数严重依赖于 PostGIS 3.1。在 PostGIS 中进行所有处理加快了整个过程。处理坦桑尼亚从 1 级到 7 级的网格仍然需要 4 分 36 秒。为所有非洲国家做这件事需要很多时间。
PLpgSQL 中的编码函数。(图片由作者提供)
上周我用了几个晚上完成了处理,现在可以展示所有非洲国家的 QDGC 文件。原始文件以 geopackage 格式分发。为了节省空间,他们被压缩使用 7-zip 程序。
用于非洲的 54 个压缩格式的文件总共为 1.2 GB。未压缩的大小约为 32 GB。
使用 Zenodo 共享
我以前依赖于从我自己的网站上发布文件,现在我已经开始通过 Zenodo 分享它们了。
OpenAIRE 项目是欧洲开放存取和开放数据运动的先锋,受欧盟委员会委托,通过为欧盟委员会资助的研究提供一个包罗万象的存储库来支持其新生的开放数据政策。CERN 是 OpenAIRE 的合作伙伴,也是开源、开放访问和开放数据的先驱,它提供了这种能力,Zenodo 于 2013 年 5 月推出。(https://about.zenodo.org/来源
芝诺多有社区,代表上传到芝诺多的文件的从属关系。所有 qdgc 文件都上传到 QDGC 社区:
https://zenodo.org/communities/qdgc/
用芝诺多存储的所有文件都配有一个独特的数字对象标识符( doi )。如果你最终在你的研究中使用数据集,或者出于其他好的原因,你需要一个参考。因此,坦桑尼亚的四分之一格网像元数据集版本 1.0.0 可引用如下:
拉格瓦尔德.拉森。(2021).qdgc 坦桑尼亚(版本 1 . 0 . 0)[数据集]。芝诺多。http://doi.org/10.5281/zenodo.4452672
从现在开始,这是我存放所有与四分之一度网格单元相关的文件的地方。
这是什么意思?
真的不多。如果您需要一组适用于概化的地理编码空间参考对象,请使用它。如果你不喜欢,我希望你喜欢这本书。感谢您的阅读!
用 Python 对 CSV 进行地理编码
2021 年德国巴登符腾堡州圣诞市场的一个例子
地理编码是通过输入全球各地的地址数据来定位坐标的过程。在大多数地理数据分析过程中,这是一个非常基本的步骤。这篇简短的教程让您深入了解如何使用 Python 中的 geopy 库进行地理编码。只需要几行 Python 脚本和几分钟就可以学会。本教程的用例是对德国巴登符腾堡州 2021 圣诞市场地址数据进行地理编码,数据以 CSV 格式提供。
土工格栅的安装和基础。
您可以使用以下脚本安装 geopy:
**$ pip install geopy**or in Colab:
**!pip install geocoder**
安装 geopy 后,您可以通过导入这个 geopy 库来启动一个新的 Python 文件。
import geocoder
使用 geopy 非常简单。它包括许多地理编码服务的地理编码器类,如OpenStreetMap nomim、 Google Geocoding API (V3) 等等。例如,您可以使用以下脚本调用带有 osm 的地理编码器:
g = geocoder.osm('Eiffel Tower')>>> g.osm{
'x': 2.2944990543196795,
'y': 48.858260200000004,
'addr:housenumber': '5',
'addr:street': 'Avenue Anatole France',
'addr:city': 'Paris',
'addr:state': 'Île-de-France',
'addr:country': 'France',
'addr:postal': '75007'
}
将 CSV 读给熊猫数据框
现在,让我们尝试使用 geopy 对 CSV 表中的数据进行地理编码。我们可以从将 CSV 数据集导入熊猫数据帧开始。本例中的 CSV 将是德国 BW 的圣诞节市场地址,此处公开提供(由作者创建)。
import pandas as pd
df = pd.read_csv("ChristmasMarketData.csv")
df.head()
圣诞市场地址数据示例(作者提供)
对数据帧进行地理编码
现在,让我们对数据帧进行地理编码。在此之前,我们需要一个函数来返回必要的地理编码信息,即g.osm['x']
和g.osm['y']
,如下所示
def geocoding(input_address):
g = geocoder.osm(input_address)
return g.osm['x'], g.osm['y']
然后,我们可以将这个函数应用于地址栏中的数据帧。
df['locations'] = df['address'].apply(geocoding)
df[['lon','lat']] = pd.DataFrame(df['locations'].tolist(),
index=df.index)
df.head()
生成的地理编码圣诞市场地址(作者)
而且,大概就是这样。你可以在https://icity.hft-stuttgart.de/christmas_market_2021查看可视化结果地理编码圣诞市场数据
地理编码圣诞市场地址的可视化(作者)
总之,本文概述了如何使用 geopy 库对 CSV 数据和 Pandas 数据帧进行地理编码。
我希望你喜欢它,并发现它对你的日常工作或项目有用。如果你有任何问题,请随时联系我。
关于我&查看我所有的博客内容:链接
平安健康!
感谢阅读。👋😄
Python 中的地理编码:完整指南
使用 Python 进行地理编码的分步教程
安德鲁·斯图特斯曼在 Unsplash 上的照片
介绍
在处理机器学习的大型数据集时,您是否遇到过类似这样的地址列?
作者图片
位置数据可能非常混乱,难以处理。
很难对地址进行编码,因为它们的基数非常高。如果您尝试使用类似 one-hot 编码的技术对这样的列进行编码,这将导致高维度,并且您的机器学习模型可能性能不佳。
克服这个问题最简单的方法就是对这些列进行地理编码。
什么是地理编码?
地理编码是将地址转换为地理坐标的过程。这意味着您将把原始地址转换成纬度/经度对。
Python 中的地理编码
有许多不同的库可以帮助你用 Python 做到这一点。最快的是 Google Maps API,如果你有超过 1000 个地址需要在短时间内转换,我推荐使用。
然而,谷歌地图 API 不是免费的。你需要为每 1000 个请求支付大约 5 美元。
谷歌地图 API 的一个免费替代品是 OpenStreetMap API。然而,OpenStreetMap API 要慢得多,而且也不太准确。
在本文中,我将用这两个 API 带您完成地理编码过程。
方法 1:谷歌地图应用编程接口
让我们首先使用 Google Maps API 将地址转换成纬度/经度对。为此,你首先需要创建一个谷歌云账户,并输入你的信用卡信息。
虽然这是一项付费服务,但当你第一次创建谷歌云账户时,谷歌会给你 200 美元的免费积分。这意味着您可以使用他们的地理编码 API 进行大约 40,000 次呼叫,然后才需要付费。只要你没有达到这个限额,你的账户就不会被扣款。
首先,用 Google Cloud 设置一个免费账户。然后,一旦你建立了一个帐户,你就可以按照这个教程来获得你的谷歌地图 API 密钥。
一旦你收到你的 API 密匙,你就可以开始编码了!
先决条件
在本教程中,我们将使用 Zomato Restaurants Kaggle 数据集。确保将数据集安装在您的路径中。然后,使用以下命令安装 googlemaps API 包:
pip install -U googlemaps
进口
运行下面几行代码来导入入门所需的库:
import csv
import pandas as pd
import googlemaps
读取数据集
现在,让我们读取数据集并检查数据帧的头部:
data = pd.read_csv('zomato.csv',encoding="ISO-8859-1")
df = data.copy()
df.head()
作者图片
这个数据帧有 21 列和 9551 行。
我们只需要 address 列进行地理编码,因此我将删除所有其他列。然后,我将删除重复的地址,这样我们只获得唯一的地址:
df = df[['Address']]
df = df.drop_duplicates()
再看一下数据帧的头部,我们只能看到地址列:
作者图片
太好了!我们现在可以开始地理编码了。
地理编码
首先,我们需要用 Python 访问我们的 API 密钥。为此,请运行以下代码行:
gmaps_key = googlemaps.Client(key="your_API_key")
现在,让我们先尝试对一个地址进行地理编码,然后看看输出。
add_1 = df['Address'][0]
g = gmaps_key.geocode(add_1)
lat = g[0]["geometry"]["location"]["lat"]
long = g[0]["geometry"]["location"]["lng"]
print('Latitude: '+str(lat)+', Longitude: '+str(long))
上述代码的输出如下所示:
作者图片
如果你得到上面的输出,太好了!一切正常。
我们现在可以对整个数据帧重复这一过程:
# geocode the entire dataframe:
def geocode(add):
g = gmaps_key.geocode(add)
lat = g[0]["geometry"]["location"]["lat"]
lng = g[0]["geometry"]["location"]["lng"]
return (lat, lng)
df['geocoded'] = df['Address'].apply(geocode)
让我们再次检查数据帧的头部,看看这是否有效:
df.head()
如果你的输出看起来像上面的截图,那么恭喜你!您已成功对整个数据帧中的地址进行了地理编码。
方法 2: OpenStreetMap API
OpenStreetMap API 是完全免费的,但是比 Google maps API 慢,也不准确。
这个 API 无法定位数据集中的许多地址,所以这次我们将使用位置列。
在我们开始本教程之前,让我们看看地址和地点列之间的区别。为此,请运行以下代码行:
print('Address: '+data['Address'][0]+'\n\nLocality: '+data['Locality'][0])
您的输出将如下所示:
作者图片
地址列比位置列更细粒度,它提供了餐馆的确切位置,包括楼层号。这可能是 OpenStreetMap API 无法识别地址的原因,但位置可以识别。
让我们对第一个地点进行地理编码,并查看输出。
地理编码
运行以下代码行:
import url
import requests
data = data[['Locality']]
url = 'https://nominatim.openstreetmap.org/search/' + urllib.parse.quote(df['Locality'][0]) +'?format=json'
response = requests.get(url).json()
print('Latitude: '+response[0]['lat']+', Longitude: '+response[0]['lon'])
上述代码的输出与 Google Maps API 生成的结果非常相似:
作者图片
现在,让我们创建一个函数来查找整个数据帧的坐标:
def geocode2(locality):
url = 'https://nominatim.openstreetmap.org/search/' + urllib.parse.quote(locality) +'?format=json'
response = requests.get(url).json()
if(len(response)!=0):
return(response[0]['lat'], response[0]['lon'])
else:
return('-1')
data['geocoded'] = data['Locality'].apply(geocode2)
太好了!现在,让我们看看数据帧的头部:
data.head(15)
作者图片
请注意,该 API 无法为数据帧中的许多位置提供坐标。
尽管它是谷歌地图 API 的一个很好的免费替代品,但是如果你用 OpenStreetMap 进行地理编码,你可能会丢失很多数据。
本教程到此为止!我希望你从这里学到一些新的东西,并对处理地理空间数据有更好的理解。
祝您的数据科学之旅好运,感谢您的阅读!
本文原载此处。
使用 Turf Mapbox SDK 地理编码位置
用 Java 实现常见的 Turf 功能。用例+完整源代码。
大多数熟悉地理空间 web 应用程序的地理信息系统(GIS)从业者都遇到过被称为 TurfJS 的 JavaScript 实用程序,这是一个开源的地理空间分析工具。虽然 Turf 以其多功能性和广泛的地理空间功能而闻名,但它的一个常见用例通常涉及对自定义边界内的特定位置坐标进行地理编码— ,即标记特定区域/地区/地带到目标位置。
更深入的细节,请参考下面的文章:
为了说明这种功能,以国家新加坡为例,该岛被划分为 5 个独立的区域 — 中部、北部、东北部、东部&西部。
作者插图|新加坡分为 5 个不同的地区
为了标记 ❝National 牙科中心(NDC)❞ 大楼所处的正确区域,需要两个特定的空间数据输入:
输入(1)5 个区域的几何多边形/多多边形特征(在演示 HTML 代码中指定为 GeoJSON 对象— boundaries
)
输入(2) 目标位置的建筑坐标—国家牙科中心(在演示 HTML 代码中指定为 GeoJSON 对象— targetLocations
)
注意:完整的 HTML 代码实现可以在这里找到
输出如下:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"BLK_NO": "5",
"BUILDING": "NATIONAL DENTAL CENTRE",
"ROAD_NAME": "SECOND HOSPITAL AVENUE",
"POSTAL": "168938",
"REGION_N": "CENTRAL REGION",
"REGION_C": "CR"
},
"geometry": {
"type": "Point",
"coordinates": [
103.838232475714,
1.27975902116932
]
}
}
]
}
由此我们可以推导出 国家牙科中心 位于新加坡的 中部 。
重要:注意,我在上面的 HTML 代码中使用的 Turf 库的版本是 turf-3.5.1.js ,使用的实用方法是booleanPointInPolygon(<Point>, <Polygon/MultiPolygon>)
用 Java 编程语言实现
由于到目前为止,还没有关于 Java 对等物TurfJS—map box Turf SDK的全面文档,以下是在 Java 编程语言中模拟这一完全相同的功能的逐步指南。
要包含在类路径中的 JAR 依赖项列表
作者截图 mapbox sdk turf 库使用的 JAR 依赖项列表|注意:json-org JAR 作为一个实用程序类包含在本演示中,用于解析 Java 编程语言中的 json 对象
以下是我的 GitHub repo 对每个输入的直接链接:
- 必需的 JAR 依赖关系:链接
- 要运行的完整 Java 代码片段:GeocodeNDC.java
Java 代码的最终输出(与上面 JavaScript 中的输出相同):
作者截图|请注意,GeoJson 已使用属性“REGION_N”和“REGION_C”进行标记。仅供参考:上面的 Java 应用程序是在 Netbeans IDE 中构建的
用 Java 实现草坪 GIS 工具的基本原理
虽然考虑到 TurfJS 是一个 JavaScript 库,它在很大程度上满足了我的大多数个人 GIS 用例,但是在常规情况下,当总信息量超过浏览器能够处理的数据量时:
作者图片|谷歌 Chrome 浏览器因通过浏览器网络工具处理大量数据而崩溃
因此, TurfJS 的非浏览器替代品对于执行相同的功能是必要的。最好使用 Mapbox Turf SDK 代替 TurfJS 的其他场景包括:
- 当需要处理大量的数据集时
- 当需要定期进行地理编码时,需要调度或数据流水线(例如使用 Pentaho )
非常感谢你坚持到这篇文章的结尾!❤希望你觉得这个指南很有用,如果你想了解更多的 GIS、数据分析和网络应用相关的内容,请随时关注我。会非常感激😀
https://geek-cc.medium.com/membership
动态地理编码:清理公寓号
由 Unsplash 上的 CHUTTERSNAP 拍摄
在我的上一篇文章中,我谈到了为地理编码清理数据。我先说一下地理编码器。外面有很多选择。有些你可能听说过。当然,谷歌有一个非常容易使用的、构建良好的地理编码服务。如果你正在处理成千上万的地址,我建议你仔细研究一下。不过,我不会使用谷歌。像谷歌这样的知名服务的问题在于它们是有限的。他们有一个免费的层级结构,过去是付费服务。一旦你学会了这种格式,他们就会向你收取更多的费用。这并不是一件坏事,但我正专注于快速、低成本的解决方案,让您可以快速获得一些东西,而不必获得额外的许可。
我使用的是使用 OpenStreetMap 地理编码服务的 nomim。地理编码有时可能不可靠,但它肯定是一致的。因此,提前设置一些遵循一致性的代码可以让您快速处理请求并获得地址列表的 XY 坐标。OpenStreetMap 不喜欢的是公寓号,或者任何跟在道路名称后面的东西。因此,我将带您浏览的这段代码将有助于从您的专栏中删除这些内容。我希望你喜欢 python 字典,因为这将是一个很好的练习。
第一部分定义了一个名为 rem_apt 的函数,它接收一个序列,并将其拆分成一个字符串列表。然后从列表中创建一个临时字典。这给了我们一个键来处理每个值。现在,我可以计算服务地址 road name 中有多少个字符串。最后,我创建一个空列表来存储要删除的键。
第 6 行遍历字典项,并遍历一个名为 road_types 的变量。这是一个 csv,我从 USPS 的道路类型列表中创建的,在这里找到了。我把信息复制粘贴成 csv 文件,只保留了“邮政服务标准后缀缩写”一栏。它作为字符串的数据帧导入到我的代码中。这些将是我要寻找的道路名称,并在找到后删除所有字符。同样,一致性是关键,所以了解你的数据。我知道我的数据中的道路名称以缩写结尾。而那些使用道路名称作为道路一部分的不缩写。例如“J 大道”、“9 号公路”和“72 号县道”。
从第 8 行开始,我检查从服务地址 road name 创建的字符串字典(value)中是否有任何道路名称(item)。如果找到了,那么继续检查哪个值与它找到的项匹配。然后,我将 rem_key 值设置为 key +1,并确保它是一个整数。
现在,我遍历其余的值,将找到的值后面的每个键添加到 rep_all_after 列表中。我在关键字上加一个加号,直到到达字典的末尾。这将存储这个既得循环之外的密钥,以供下一次使用。
现在,我可以使用这个键列表从字符串字典中弹出(删除)道路名称之前的所有值。最后返回一串剩余的值。
这最后一段代码通过寻址遍历原始 cust_add_db,用 rem_apt 函数提供的干净 rd 值替换 rd 值。
此时,您可以通过执行以下操作之一来验证您的信息:
- cust_add_db['rd']。值计数()
- cust_add_db['rd']。独一无二的
现在我们已经有了一个干净的数据集,接下来的文章将重点关注为我们的服务地址提取 XY 坐标和其他政治实体。
动态地理编码:清理数据
地理编码是制图的一个基本要素。这是一个地址列表,并给他们一个 XY 坐标来定位。此 XY 坐标允许您将符号系统类添加到报告中,如下例所示:
照片来自作者的个人项目
有几个步骤可以到达那里。首先是清理数据集。在我的职业生涯中,我注意到了一致性的重要性。即使有些东西被错误地编目,重要的是它被一贯地错误地完成。因此,了解数据的结构是重中之重。首先,您需要查看以下清单:
- 我的数据集中有多少行和列?
- 列的数据类型是什么?这对数据有意义吗?
- 显示前 5 或 10 行数据,数据看起来像什么?
- 无论您使用哪种语言,都要做一些数值计算,以便更好地了解每一列中的数据是如何组织的。
现在,我将提供一个 python 脚本,当我得到一个服务地址数据表时,我将使用这个脚本。然后我会检查代码行的含义。首先,我将创建一个数据框架来放置我的地理编码信息。这可以在以后连接到原始数据框架,或者可以作为附加工作表保存在原始 excel 文件中。
第一行是用要计算的列创建数据框架。然后,我添加了一个地址字段,这将使结合门牌号和道路更容易为最终干净的地址字段。
此脚本用于将单个地址列分解为多个数据列,作为可追加到临时数据帧的临时数据集。
作者创建的代码
首先,我遍历每个服务地址行,并使用 tqdm 库提供一个进度条。我知道 service address 列是一个 string 对象,所以我将它分开,用逗号分隔,并将值放入一个对该行唯一的列表中。然后我使用列表理解从每个值中去掉所有的前导和尾随空格。
在下一组 if 和 elif 语句中,我将寻找字符串中值的长度。因为我知道服务地址是以下列格式之一书写的:
- 纽约州所有地方市主街 1234 号,邮编 8000–000
- 城市州所有地方主街 1234 号,8000–000
对于每条语句,我通过从列表中取出每个字符串变量并适当地分解它来定义门牌号、道路名称、城市、州和邮政编码的变量。
代码的最后一部分将所有已定义的变量编译成一个临时序列,其索引与列名相匹配。然后将它作为一行追加到临时 cust_add_db 中。您可以添加到 dataframe 中的一行代码是一个惟一的索引号,它有助于将它连接回原始数据。
在我的下一篇文章中,我将讨论可以帮助查找和删除公寓号码、单元等的代码。这些可能会混淆开源地理编码服务。
地理编码新加坡坐标:OneMap API
免费轻松地将地址转换成坐标
新加坡市区(图片作者
使用 Google API 进行地理编码是广为人知的方法。然而,一旦你完成了你的免费学分就要花钱。作为一名经常使用 Tableau 和 Python 进行地理空间可视化的数据分析师,坐标对于绘图非常重要。在本文中,我将演示如何使用新加坡土地管理局(SLA)开发的免费且精确的地理编码 API 对新加坡坐标进行地理编码。
第一步:导入相关包
import pandas as pd
import requests
第二步:读取熊猫的数据集并检查它
df = pd.read_csv(r"C:\Users\shawn\Downloads\hdb-property-information\hdb-property-information.csv")
df.head()
我正在使用的数据集来自 Data.gov.sg,它包含了现有住房发展委员会(HDB)大厦的位置、最高楼层、完工年份、建筑类型和每座大厦的 HDB 公寓数量(按公寓类型分类)等。我从读取 pandas 的数据开始,查看前 5 行,看看我可以使用哪些列。出于演示的目的,并使其尽可能真实,我不会清理数据来显示您如何仍然可以使用 OneMap API。
数据集的前 5 行
第三步:创建一个可以输入 API 的通讯录
df['Address'] = df['blk_no'] + " " + df['street']
addresslist = list(df['Address'])
因为没有地址列,所以我将包含街区号和街道名称的列连接起来,并将其保存到一个新列中。地理编码需要某种形式的地址,因此有必要继续此步骤。接下来,我将新创建的列转换成一个列表,然后可以通过 OneMap API 运行该列表。
步骤 4:编写地理编码函数
def getcoordinates(address):
req = requests.get('[https://developers.onemap.sg/commonapi/search?searchVal='+address+'&returnGeom=Y&getAddrDetails=Y&pageNum=1'](https://developers.onemap.sg/commonapi/search?searchVal='+address+'&returnGeom=Y&getAddrDetails=Y&pageNum=1'))
resultsdict = eval(req.text)
if len(resultsdict['results'])>0:
return resultsdict['results'][0]['LATITUDE'], resultsdict['results'][0]['LONGITUDE']
else:
pass
我首先将函数定义为getcoordinates
。使用requests
模块,我将使用它在 OneMap API 上搜索信息。为了检索信息,必须将地址作为字符串插入到给定的 URL 中。接下来,我使用eval()
函数作为 Python 表达式对其求值。因为不是所有的地址都有坐标,所以我使用 if else 语句只获取有结果的地址。
第五步:编写一个带条件的 for 循环
for 循环将开始提取坐标,同时让您知道是否成功
coordinateslist= []
count = 0
failed_count = 0
for address in addresslist:
try:
if len(getcoordinates(address))>0:
count = count + 1
print('Extracting',count,'out of',len(addresslist),'addresses')
coordinateslist.append(getcoordinates(address))
except:
count = count + 1
failed_count = failed_count + 1
print('Failed to extract',count,'out of',len(addresslist),'addresses')
coordinateslist.append(None)
print('Total Number of Addresses With No Coordinates',failed_count)
现在,我开始创建一个空列表来追加提取的坐标。接下来,我放了一个计数函数。通过这样做,我能够知道当前的进度以及没有坐标的地址的总数。这将使我很容易保持跟踪。接下来,我输入一个 try else 条件,这将允许 for 循环继续运行,即使其中一个地址未能从 API 中检索到任何坐标。这对于确保循环顺利运行特别有用,尤其是对于不能从 API 生成任何结果的脏数据集。此外,您仍然能够获得大部分坐标。然后,您可以过滤剩余的脏地址并清理它们,这样您的生活会更轻松,因为您需要清理的内容更少了!
步骤 6:将获得的坐标连接回原始数据帧
df_coordinates = pd.DataFrame(coordinateslist)
df_combined = df.join(df_coordinates)
df_combined = df_combined .rename(columns={0:'Latitude', 1:'Longitude'})
最后,我将坐标列表转换成数据帧,并将其连接到原始数据帧。由于指数不变,它将完美地加入。我还将列名重命名为 Latitude 和 Longitude,以便更好地反映数据帧中的数据类型。
总结
- 步骤 1:导入相关的包
- 第二步:阅读熊猫的数据集并检查它
- 步骤 3:创建一个可以输入 API 的地址列表
- 步骤 4:编写地理编码函数
- 步骤 5:编写一个带条件的 for 循环
- 步骤 6:将获得的坐标连接回原始数据帧
我希望你喜欢我的文章,并且它说服你尝试这个 OneMap API!新加坡政府采取了许多重大举措来公开数据集。因此,探索并看看您能从数据分析项目中得到什么是有用的。你可以在我的 Github 上查看完整代码。
Google Data Studio 中的地理热图
在我的上一篇文章中,展示了如何将地理坐标绑定到可以在地图上有效可视化的方块中。下一步自然是用颜色填充这个网格,以显示与坐标相关的任何度量的空间变化,即地理热图。在这里,我们将展示如何使用 Google BigQuery 和 Google Data Studio 来实现这一点。
丹尼斯·库默在 Unsplash 上拍摄的照片
数据集:纽约出租车出行
首先,我们需要地理参考数据,幸运的是 BigQuery 提供了几个公共数据集来帮助我们。这里我们将使用一个数据集,它包含纽约的出租车行程,上面有上下车的准确位置。这个想法是在地图上显示在给定的时间范围内,从一个给定的接送区,覆盖纽约的每个区块的下车数量。我们可以在同一数据集中的专用表中找到这些区域的边界。
从经度和纬度到瓦片坐标
第一步是将每个拾取和放下事件映射到所需大小的相应图块。我们严格遵循此处描述的程序:
DECLARE
START_DATE DATE;
DECLARE
END_DATE DATE;
DECLARE
ZOOM INT64;
SET
START_DATE='2015-01-01';
SET
END_DATE='2015-01-01';
SET
ZOOM=17;
SELECT
ZOOM || TRUNC((pickup_longitude*ACOS(-1)/180+ACOS(-1))/(2*ACOS(-1))*POW(2,ZOOM))|| -- *pick-up x coordinate*
TRUNC((POW(2,ZOOM)/(2*ACOS(-1))*(ACOS(-1)-SAFE.LN(TAN(ACOS(-1)/4+(pickup_latitude/180*ACOS(-1))/2)))))-- *pick-up y coordinate*
AS pickup_tile_id,
ZOOM || TRUNC((dropoff_longitude*ACOS(-1)/180+ACOS(-1))/(2*ACOS(-1))*POW(2,ZOOM)) || *-- drop-off x coordinate*
TRUNC((POW(2,ZOOM)/(2*ACOS(-1))*(ACOS(-1)-SAFE.LN(TAN(ACOS(-1)/4+(dropoff_latitude/180*ACOS(-1))/2))))) -- *drop-off y coordinate*
AS dropoff_tile_id,
FROM
`bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2015`
WHERE
DATETIME_TRUNC(pickup_datetime,
DAY) BETWEEN START_DATE
AND END_DATE
我们引入了一些参数,如START_DATE
、 END_DATE
、和ZOOM
,以提供动态改变时间范围和瓦片大小的灵活性。使用这里使用的默认值,我们只需要 5.3 秒就可以得到输出,但是“繁重”的工作仍然要做,所以如果您想在几秒钟内得到输出而不保存部分结果,就要避免使用更大的时间范围😃。
上面代码的输出
因此,上面的代码为我们提供了包含每次旅行的接送点的瓦片的唯一 id。
用瓷砖覆盖纽约的出租车区域
接下来,我们需要知道刚刚找到的每个图块属于哪个区域,因此我们如下进行:
- 使用表
bigquery-public-data.new_york_taxi_trips.taxi_zone_geom
访问每个滑行区域的边界和名称。 - 找到包围每个区域的包围框,由两对坐标定义,即
(xmin,ymin)
(左下角)和(xmax,ymax)
(右上角)。 - 确定包含瓷砖坐标
(tile_x_xmin_ymin,tile_y_xmin_y_min)
和(tile_x_xmax_ymax,tile_y_xmax_y_max)
的(xmin,ymin)
和(xmax,ymax)
的瓷砖。 - 生成从左下角到右上角的剩余图块。
用方形瓷砖覆盖世贸中心。
请注意,我们可能有一个图块与两个或更多不同的区域重叠:
一个单幅图块覆盖四个不同的区域。
这引入了一定程度的不确定性,必须加以解决:每个区块必须属于且仅属于一个区域。例如,我们可以将其与包含其中心的区域相关联,但我们将遵循不同的方法,即评估瓷砖与每个区域之间的相交区域,并仅保留最大的区域。这可能需要大约一分钟的时间来完成,所以最好将结果保存在一个表中,并在需要时使用该输出。下面是完成刚才描述的过程的代码:
DECLARE
ZOOM INT64;
SET
ZOOM=17;
WITH
bounding_box AS(
SELECT
zone_name,
zone_geom,
ST_BOUNDINGBOX(zone_geom) BB
FROM
`bigquery-public-data.new_york_taxi_trips.taxi_zone_geom` ),
tiles_at_corners AS(
SELECT
zone_name,
zone_geom,
TRUNC((BB.xmin*ACOS(-1)/180+ACOS(-1))/(2*ACOS(-1))*POW(2,zoom)) tile_x_xmin_ymin,
TRUNC((POW(2,ZOOM)/(2*ACOS(-1))*(ACOS(-1)-SAFE.LN(TAN(ACOS(-1)/4+(BB.ymin/180*ACOS(-1))/2))))) tile_y_xmin_ymin,
TRUNC((BB.xmax*ACOS(-1)/180+ACOS(-1))/(2*ACOS(-1))*POW(2,zoom)) tile_x_xmax_ymax,
TRUNC((POW(2,ZOOM)/(2*ACOS(-1))*(ACOS(-1)-SAFE.LN(TAN(ACOS(-1)/4+(BB.ymax/180*ACOS(-1))/2))))) tile_y_xmax_ymax,
FROM
bounding_box)
SELECT
zone_name,
tile_id,
ST_MAKEPOLYGON( ST_MAKELINE([ ST_GEOGPOINT(NW_LONG,
NW_LAT),
ST_GEOGPOINT(NE_LONG,
NE_LAT),
ST_GEOGPOINT(SE_LONG,
SE_LAT),
ST_GEOGPOINT(SW_LONG,
SW_LAT),
ST_GEOGPOINT(NW_LONG,
NW_LAT) ])) polygon
FROM (
SELECT
zone_name,
zone_geom,
ZOOM || tile_x || tile_y tile_id,
180/ACOS(-1)*(2*ACOS(-1)*tile_x/POW(2,ZOOM)-ACOS(-1)) AS NW_LONG,
360/ACOS(-1)*(ATAN(EXP(ACOS(-1)-2*ACOS(-1)/POW(2,ZOOM)*tile_y))-ACOS(-1)/4) AS NW_LAT,
180/ACOS(-1)*(2*ACOS(-1)*(tile_x+1)/POW(2,ZOOM)-ACOS(-1)) AS NE_LONG,
360/ACOS(-1)*(ATAN(EXP(ACOS(-1)-2*ACOS(-1)/POW(2,ZOOM)*tile_y))-ACOS(-1)/4) AS NE_LAT,
180/ACOS(-1)*(2*ACOS(-1)*(tile_x+1)/POW(2,ZOOM)-ACOS(-1)) AS SE_LONG,
360/ACOS(-1)*(ATAN(EXP(ACOS(-1)-2*ACOS(-1)/POW(2,ZOOM)*(tile_y+1)))-ACOS(-1)/4) AS SE_LAT,
180/ACOS(-1)*(2*ACOS(-1)*(tile_x)/POW(2,ZOOM)-ACOS(-1)) AS SW_LONG,
360/ACOS(-1)*(ATAN(EXP(ACOS(-1)-2*ACOS(-1)/POW(2,ZOOM)*(tile_y+1)))-ACOS(-1)/4) SW_LAT
FROM (
SELECT
zone_name,
zone_geom,
(tile_x_xmin_ymin + x) tile_x,
(tile_y_xmin_ymin + y) tile_y
FROM
tiles_at_corners,
UNNEST(GENERATE_ARRAY(0,tile_x_xmax_ymax-tile_x_xmin_ymin,1)) x,
UNNEST(GENERATE_ARRAY(tile_y_xmax_ymax-tile_y_xmin_ymin,0,1)) y) )
WHERE
TRUE QUALIFY ROW_NUMBER() OVER (PARTITION BY tile_id ORDER BY st_area(st_intersection(polygon, zone_geom)) DESC)=1
确保对您认为以后需要的每个ZOOM
值重复此过程。
准备最终查询
对于给定的ZOOM
值,我们现在知道每个图块属于哪个滑行区域,因此我们可以从我们离开的地方继续:
DECLARE
START_DATE DATE;
DECLARE
END_DATE DATE;
DECLARE
ZOOM INT64;
SET
START_DATE='2015-01-01';
SET
END_DATE='2015-01-01';
SET
ZOOM=17;
SELECT
trips.*,
t.polygon
FROM (
SELECT
t1.zone_name pickup_zone_name,
t2.zone_name dropoff_zone_name,
dropoff_tile_id,
COUNT(*) trips
FROM (
SELECT
ZOOM || TRUNC((pickup_longitude*ACOS(-1)/180+ACOS(-1))/(2*ACOS(-1))*POW(2,ZOOM)) || TRUNC((POW(2,ZOOM)/(2*ACOS(-1))*(ACOS(-1)-SAFE.LN(TAN(ACOS(-1)/4+(pickup_latitude/180*ACOS(-1))/2))))) AS pickup_tile_id,
ZOOM || TRUNC((dropoff_longitude*ACOS(-1)/180+ACOS(-1))/(2*ACOS(-1))*POW(2,ZOOM)) || TRUNC((POW(2,ZOOM)/(2*ACOS(-1))*(ACOS(-1)-SAFE.LN(TAN(ACOS(-1)/4+(dropoff_latitude/180*ACOS(-1))/2))))) AS dropoff_tile_id,
FROM
`bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2015`
WHERE
DATETIME_TRUNC(pickup_datetime,
DAY) BETWEEN START_DATE
AND END_DATE ) trips
INNER JOIN
NY_Taxi_Trips.Tiles t1
ON
pickup_tile_id=t1.tile_id
INNER JOIN
NY_Taxi_Trips.Tiles t2
ON
dropoff_tile_id=t2.tile_id
GROUP BY
pickup_zone_name,
dropoff_zone_name,
dropoff_tile_id) trips
INNER JOIN
NY_Taxi_Trips.Tiles t
ON
dropoff_tile_id=t.tile_id
我们使用了几次表NY_Taxi_Trips.Tiles
,它是我们在具有相应区域名称的瓷砖多边形之前保存的地方。因此,该查询的输出给出了在START_DATE
和END_DATE
之间的dropoff_zone_name
中从pickup_zone_name
到dropoff_tile_id
记录的旅行次数。请注意,我们在最后一个SELECT
语句中引入了GEOGRAPHY
字段,即polygon
,以避免加重前面步骤的负担。
一旦我们在 BigQuery 上测试了这个查询,我们就准备将它用于 Data Studio。我们只需要改变代码中引用声明参数的方式:
SELECT
trips.*,
t.polygon
FROM (
SELECT
t1.zone_name pickup_zone_name,
t2.zone_name dropoff_zone_name,
dropoff_tile_id,
COUNT(*) trips
FROM (
SELECT
[@ZOOM](http://twitter.com/ZOOM) || TRUNC((pickup_longitude*ACOS(-1)/180+ACOS(-1))/(2*ACOS(-1))*POW(2,[@ZOOM](http://twitter.com/ZOOM))) || TRUNC((POW(2,[@ZOOM](http://twitter.com/ZOOM))/(2*ACOS(-1))*(ACOS(-1)-SAFE.LN(TAN(ACOS(-1)/4+(pickup_latitude/180*ACOS(-1))/2))))) AS pickup_tile_id,
[@ZOOM](http://twitter.com/ZOOM) || TRUNC((dropoff_longitude*ACOS(-1)/180+ACOS(-1))/(2*ACOS(-1))*POW(2,[@ZOOM](http://twitter.com/ZOOM))) || TRUNC((POW(2,[@ZOOM](http://twitter.com/ZOOM))/(2*ACOS(-1))*(ACOS(-1)-SAFE.LN(TAN(ACOS(-1)/4+(dropoff_latitude/180*ACOS(-1))/2))))) AS dropoff_tile_id,
FROM
`bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2015`
WHERE
DATETIME_TRUNC(pickup_datetime,
DAY) BETWEEN PARSE_DATE('%Y%m%d',
[@DS_START_DATE](http://twitter.com/DS_START_DATE))
AND PARSE_DATE('%Y%m%d',
[@DS_END_DATE](http://twitter.com/DS_END_DATE))) trips
INNER JOIN
NY_Taxi_Trips.Tiles t1
ON
pickup_tile_id=t1.tile_id
INNER JOIN
NY_Taxi_Trips.Tiles t2
ON
dropoff_tile_id=t2.tile_id
GROUP BY
pickup_zone_name,
dropoff_zone_name,
dropoff_tile_id) trips
INNER JOIN
NY_Taxi_Trips.Tiles t
ON
dropoff_tile_id=t.tile_id
ZOOM
→@ZOOM
START_DATE
→@DS_START_DATE
END_DATE
→@DS_END_DATE
在 Data Studio 中可视化热图
让我们在 Data Studio 中创建我们的报告,我们将保持它的简单:
- 去 https://datastudio.google.com/的。
- 创建 > 报表。
- 选择 BigQuery 连接器。
- 选择自定义查询并复制我们的查询。
- 勾选启用日期范围参数。
- 点击添加一个参数并定义最后一个参数,即
ZOOM
,使用以下配置:
缩放参数的定义
最后,点击添加,让我们创建我们的可视化!
首先,我们希望能够在查看模式下随时更改我们的参数值,因此我们转到添加一个控件,并选择插入一个输入框来控制缩放级别:
添加一个输入框来控制缩放参数。
我们重复此程序,插入日期范围控件和下拉列表,分别控制日期范围和起始提货区。我们也为两者选择默认值,即第一个为 2015 年的前 6 个月,第二个为“ JFK 机场”:
默认日期范围值。
我们为提货区选择一个默认值。
我们现在准备添加地图:
- 转到添加图表 > 谷歌地图>填充地图。
- 将地图插入报告中的任意位置。
- 使用以下字段配置让其正常工作:
填充地图的字段配置。
我们也可以自定义地图样式,如下所示:
- 使用深色款式
- 不使用边框重量
- 选择最大、中间和最小颜色的调色板: #ffffff 、 #ffd54f 和 #212121
请注意,作者是色盲,这可能是最糟糕的颜色选择,你可以随意改变😃。
在这一点上,我们应该得到这样的东西:
我们的首次热图可视化!
我们注意到只有一小块突出显示的区域,这里显然聚集了来自 JFK 机场的大部分旅行。如果我们希望我们的热图看起来不那么平坦,我们可以通过更改图表配置中的颜色度量将比例从线性更改为不同的比例:
修改公制以更改比例
例如,使用SQRT(SUM(trips))
,我们得到一个稍微不同的可视化:
我们现在可以尝试不同的提货区:
或者不同瓷砖尺寸:
该是你进一步实验的时候了!
享受😃!
用 Plotly 绘制地图的地理图
使用 Plotly 创建交互式地图来显示您的数据。
Marjan Blan | @marjanblan 在 Unsplash 上的照片
什么是地理标图?
地理绘图是一种显示全球范围以及一个国家各州数据的方法,通常以丰富多彩的方式显示。它在数据分析和可视化中起着重要的作用。它通常在构建仪表板以呈现广泛的数据时使用。
为了创建交互式地图,我们使用 python 的 plotly 库。Plotly 用于制作交互式图形,以及创建其他可视化。
点击此处了解更多关于 plotly 的信息。
让我们把这个教程分成两部分。在第一部分中,我们将关注基于国家的地理绘图数据,在我们的例子中,这将是美国的农业出口。在第二部分,我们将使用一个随机的全球 GDP 数据集。这两个数据集都可以在这里找到。
先决条件:
对 python 编程的基本理解。特别是 python 的 matplotlib 和 plotly 库。
首先导入以下模块:
import pandas as pd
import chart_studio.plotly as py
import plotly.offline as po
import plotly.graph_objs as pg
import matplotlib.pyplot as plt
%matplotlib inline
你需要启动 plotly 的笔记本模式来显示笔记本里面的情节。这将允许您离线生成图形并将它们保存在本地机器中。
这可以通过以下方式完成:
po.init_notebook_mode(connected = True)
我们加载了基于美国农业出口的第一个数据集。
AE = pd.read_csv(‘AgriculturalExport.csv’)
AE.head()
作者图片
在这里,州代码是至关重要的,因为当我们绘制地理图时,它可以帮助我们定位。
在绘制数据时,您需要考虑几个因素,例如:您需要什么样的输出?要显示哪些位置?每个位置需要显示的值是什么?最后但同样重要的是,需要什么样的颜色、样式或文字?所有这些基本值都在我们的数据变量(即字典)下。您可以使用不同的地图类型。这里我们使用的是 choropleth,这是一个不需要任何其他库的基本图形。然后我们有位置,即位置代码。接下来,我们需要 locationmode,它告诉我们计划指定位置的方法。在我们的示例中,我们将位置模式设置为 usa-states。现在我们需要位置的值,然后当鼠标悬停在每个提到的位置上时显示文本。
data = dict(type = ‘choropleth’,
locations = [‘AL’, ‘AK’, ‘AR’, ‘CA’],
locationmode = ‘USA-states’,
z = [1,2,30,40,50],
text = [‘alabama’, ‘alaska’, ‘arizona’, ‘pugger’, ‘california’])
在布局变量中,我们只需要用 geo 表示的范围。确保美国不是用大写字母写的,因为那会导致错误。
layout = dict(geo = {'scope':'usa'})
x 变量使用我们之前导入的 plotly.graph_objs 模块来绘制状态的结构。在我们的例子中,那是美国。我们向 x 传递两个参数:数据和布局。数据表示在特定范围上表示的数据;布局定义了我们在那里使用什么样的范围。
x = pg.Figure(data = [data] ,
layout = layout)
po.iplot(x)
现在,我们只需要根据数据集中可用的值来更改布局和数据。我们编写 AE['code']从我们的数据集中调用州代码,而不是键入每个州的代码。类似地,z 将表示每个州的总出口,如下所示。谈到文本变量,我们的数据集包括一个名为 text 的列,显示每个州的农业出口的所有数据,因此我们没有将文本变量更改为州名,而是编写 AE['text']。从而显示每个州的所有导出信息。
data = dict(type = 'choropleth',
locations = AE['code'],
locationmode = 'USA-states',
z = AE['total exports'],
text = AE['text'])
至于布局,我们现在讨论的不仅仅是范围,所以我们可以添加显示湖和标题,如下所示:
layout = dict(title = 'USAs Agricultural Exports',
geo = dict(scope = 'usa' ,
showlakes = True,
lakecolor = 'rgb(0,191,255)'))x = pg.Figure(data = [data],
layout = layout)
po.iplot(x)
您可以使用不同的色标,如波特兰、绿色等,甚至可以为您的数据添加颜色条,如下所示:
data = dict(type = 'choropleth',
locations = AE['code'],
locationmode = 'USA-states',
z = AE['total exports'],
text = AE['text'],
colorscale = 'Greens',
colorbar = {'title' : 'colorbar'})layout = dict(title = 'USAs Agricultural Exports with the lakes',
geo = dict(scope='usa' ,
showlakes = True,
lakecolor = 'rgb(0,191,255)'))x = pg.Figure(data = [data],
layout = layout)
po.iplot(x)
我们现在已经到了文章的第二部分,我们将绘制全球范围的地理图表。为此我们将使用我们的全球 GDP 数据集。
G_GDP = pd.read_csv('GlobalGDP.csv')
G_GDP.head()
作者图片
所以,让我们再次定义数据和布局。
data = dict(type='choropleth',
locations = G_GDP['CODE'],
z = G_GDP['GDP (BILLIONS)'],
text = G_GDP['COUNTRY'])
当我们在全球范围内绘制地图时,布局现在将由投影属性而不是范围组成。
layout = dict(title = 'Global GDP - hammer projection',
geo = dict( projection = {'type':'**hammer**'},
showlakes = True,
lakecolor = 'rgb(0,191,255)'))x = pg.Figure(data = [data],
layout = layout)
po.iplot(x)
这些图的有趣之处在于,您可以方便地放大、浏览和查看绘制在全球各地的数据。这是因为我们的投影类型:锤子。我们可以使用其他投影类型查看相同的数据,如自然地球、罗宾逊、墨卡托、立体投影等。下面给出了一些投影类型的代码和输出。
layout = dict(title = 'Global GDP - robinson projection',
geo = dict( projection = {'type':'**robinson**'},
showlakes = True,
lakecolor = 'rgb(0,191,255)'))x = pg.Figure(data = [data],
layout = layout)
po.iplot(x)
layout = dict(title = 'Global GDP - natural earth projection',
geo = dict( projection = {'type':'**natural earth**'},
showlakes = True,
lakecolor = 'rgb(0,191,255)'))
x = pg.Figure(data = [data],
layout = layout)
po.iplot(x)
layout = dict(title = 'Global GDP - mercator projection',
geo = dict(projection = {'type':'**mercator**'},
showlakes = True,
lakecolor = 'rgb(0,191,255)'))x = pg.Figure(data = [data],
layout = layout)
po.iplot(x)
layout = dict(title = 'Global GDP - stereographic projection',
geo = dict(projection = {'type':'**stereographic**'},
showlakes = True,
lakecolor = 'rgb(0,191,255)'))x = pg.Figure(data = [data],
layout = layout)
po.iplot(x)
layout = dict(title = 'Global GDP - orthographic projection',
geo = dict( projection = {'type':'**orthographic**'},
showlakes = True,
lakecolor = 'rgb(0,191,255)'))x = pg.Figure(data = [data],
layout = layout)
po.iplot(x)
您可以移除投影的边界,如下所示:
layout = dict(title = 'Global GDP - robinson projection without borders',
geo = dict(showframe = False,
projection = {'type':'robinson'},
showlakes = True,
lakecolor = 'rgb(0,191,255)'))x = pg.Figure(data = [data], layout = layout)
po.iplot(x)
要了解更多关于 Plotly 的地图配置和样式,你可以参考它的文档。
这篇文章的全部代码可以在这里找到。
我希望这个快速教程是有帮助的。谢谢你阅读它!
你可以在这里联系我。
用 Python 处理几何和泊松随机变量
用 Python 实现大学统计
介绍
在一系列的每周文章中,我将涉及一些重要的统计学主题。
目标是使用 Python 来帮助我们获得对复杂概念的直觉,从经验上测试理论证明,或者从零开始构建算法。在本系列中,您将会看到涵盖随机变量、抽样分布、置信区间、显著性检验等主题的文章。
在每篇文章的最后,你可以找到练习来测试你的知识。解决方案将在下周的文章中分享。
迄今发表的文章:
- 伯努利和二项随机变量与 Python
- 用 Python 从二项式到几何和泊松随机变量
- 用 Python 实现样本比例的抽样分布
- Python 的置信区间
- 使用 Python 进行显著性测试
- 用 Python 进行组间差异的双样本推断
- 分类数据的推断
- 高级回归
- 方差分析— ANOVA
像往常一样,代码可以在我的 GitHub 上找到。
比较几何随机变量和二项随机变量
让我们从概述什么是二项随机变量(RV)开始。以下是清单:
- 审判是独立的;
- 每次试验都可以分为成功或失败;
- 固定的试验次数;
- 每次试验成功的概率是恒定的。
这种变量的一个例子可以是 X ,在 10 次掷骰子后 5 的数量。注意试验是独立的;在第一次试验中滚动骰子不影响在第二次试验中滚动骰子。我们可以清楚地将试验分为成功(我们得到了 5 分)或失败(我们得到了除 5 分之外的任何数字)。我们掷 10 次骰子,所以 10 代表我们的试验次数。最后,成功的概率是恒定的,因为我们总是一次又一次地使用同一个骰子,所以得到 5 的概率总是 1/6。
那么,二项式 RV 和几何式 RV 有什么区别呢?当我定义几何 RV Y ,掷骰数直到你在公平骰子上得到一个 5 时,看看你是否能找出差异。在继续之前考虑一下(参考清单)。
主要区别是试验次数固定;我们已经没有了。据我们所知,它可能是一个古戈尔(10^100)卷数。
from IPython.display import Image
import numpy as np
import seaborn as sns
from scipy.stats import binom
几何随机变量的概率
克里斯蒂亚诺·罗纳尔多的点球转化率约为 84%,是世界上最好的之一。
图 1:22 位世界最佳点球手的职业生涯点球统计;来源
现在想象罗纳尔多罚点球,直到他罚丢一个球。设 X 为他第一次罚球不进的射门次数。c 罗第一次投篮不中发生在第 4 次试射的概率有多大?
你可以看到上面的等式是前三次投篮得分的概率 0.84 乘以第四次失误的概率 0.16 的乘积。回想一下,这些尝试是独立的;这就是为什么我们可以像这里一样把它们繁殖起来。
所以 c 罗连续进 3 个点球,然后第 4 个罚丢的概率在 10%左右。
0.84**3*0.160.09483263999999998
我们可以将几何分布的概率质量函数概括如下:
累积几何概率
在计算累积几何概率时,我们可以从两个不同的角度来看。
让我们假设成功的概率 p =0.1,我们要计算 P(X < 5) 。
我们可以这样想:
或者我们可以反过来想,前 4 次试验都没有成功,所以:
def geomcdf_1(p, x):
# implementing first approach
prob = 0
for i in range(x-1):
prob+=p*(1-p)**i
return probdef geomcdf_2(p, x):
# implementing second approach
prob = 1-(1-p)**(x-1)
return probgeomcdf_1(0.1, 5)0.34390000000000004geomcdf_2(0.1, 5)0.3439
我们可以看到,实现任何一种方法都会得到相同的结果。然而,第二种方法的计算成本要低得多,因为我们不需要遍历所有情况。
几何随机变量的期望值
任何离散 RV 的概率是概率加权结果的总和。
在几何 RV 中,我们已经知道如何计算概率。例如, P(X=1) 是一次成功的概率,因此 P(X=1)=p 。在 P(X=2),我们有两次试验,因此必然有一次不成功的试验和一次成功的试验,因此 P(X=2)=(1-p)p 等等。
如果我们减去这两个方程,
这就是我们的经典几何级数,其公比是 (1-p) 。事实上,这也是我们称之为几何 RV 的原因之一。一个几何级数的和为 1/(1-r) ,其中 r 为公比。
现在我们已经得到了几何 RV 的期望值,让我们通过实验看看是否能得到相同的结果。
p=0.2
X = np.random.geometric(p, 1000000)
print('Theoretical expected value: ' + str(X.mean()))
print('Empirically calculated expected value: ' + str(1/p))Theoretical expected value: 5.00225
Empirically calculated expected value: 5.0
这就对了,我们可以对我们的推导感到满意了。
比较泊松随机变量和二项随机变量
我们能从二项式随机变量(RV)中近似出一个泊松随机变量(RV)吗?
让我们将 RV X 定义为我们看到经过我们街道的 UberEats 摩托车的数量。
如果我们试图建立在这个想法上,我们会以某种方式得到一个期望值 X ,看起来像这样:
我们的概率是这样的:
问题是,每分钟都有超过一辆摩托车经过我们的街道,而我们目前的设置无法解释这一点。但是有一种方法可以做到这一点,因为我们可以更细化。
现在,我们在用秒来工作,每秒钟看到 1 辆摩托车的概率相当小。但是我们仍然可以面对半秒钟内有两辆摩托车经过我们街道的问题。所以我们可以把它变得更小。我想你知道这是怎么回事了。
我们需要理解当 n 趋于无穷大时会发生什么。在深入讨论这个问题之前,让我们先修改一下在我们的证明中需要用到的三个性质。前两个与限制有关:
第三个是组合学:
利用这些性质,我们可以直观地看出泊松 RV 实际上是二项式 RV 的导数。
我们刚刚得到了泊松分布的概率质量函数。
通过计算概率质量函数值来证明
我们总是希望我们的证明和推导是安全的,所以让我们首先计算二项式 RV 的 n 的不同值的概率质量函数,然后将结果与相同速率的泊松 RV 进行比较。
from scipy.stats import binom, poisson
import matplotlib.pyplot as pltn1 = 20
n2 = 60
n3 = 3600
λ = 9
x = np.arange(9)
X1 = binom.pmf(x, n1, λ/n1)
X2 = binom.pmf(x, n2, λ/n2)
X3 = binom.pmf(x, n3, λ/n3)
Z = poisson.pmf(x, 9)print(f'P(X1<=9) of a Binomial RV with n={n1}: ' + str(np.sum(X1)))
print(f'P(X2<=9) of a Binomial RV with n={n2}: ' + str(np.sum(X2)))
print(f'P(X3<=9) of a Binomial RV with n={n3}: ' + str(np.sum(X3)))
print(f'P(Z<=9) of a Poisson RV with λ={λ}: ' + str(np.sum(X3)))P(X1<=9) of a Binomial RV with n=20: 0.41430623411611534
P(X2<=9) of a Binomial RV with n=60: 0.44482436484547344
P(X3<=9) of a Binomial RV with n=3600: 0.455487676774296
P(Z<=9) of a Poisson RV with λ=9: 0.455487676774296
注意我们的直觉是正确的;随着 n 的值变得更大,我们实际上正在逼近泊松 RV 的相同概率。
抽样证明
我们可以通过从上面定义的 RVs 中取样来做同样的练习,然后计算概率。
X1 = binom.rvs(n=n1, p=λ/n1, size=100000)
X2 = binom.rvs(n=n2, p=λ/n2, size=100000)
X3 = binom.rvs(n=n3, p=λ/n3, size=100000)
Z = poisson.rvs(9, size=100000)print(f'P(X1<=9) of a Binomial RV with n={n1}: ' + str(X1[X1<9].shape[0]/X1.shape[0]))
print(f'P(X2<=9) of a Binomial RV with n={n2}: ' + str(X2[X2<9].shape[0]/X2.shape[0]))
print(f'P(X3<=9) of a Binomial RV with n={n3}: ' + str(X3[X3<9].shape[0]/X3.shape[0]))
print(f'P(Z<=9) of a Poisson RV with λ={λ}: ' + str(Z[Z<9].shape[0]/Z.shape[0]))P(X1<=9) of a Binomial RV with n=20: 0.41375
P(X2<=9) of a Binomial RV with n=60: 0.44721
P(X3<=9) of a Binomial RV with n=3600: 0.45365
P(Z<=9) of a Poisson RV with λ=9: 0.45409
我们还可以绘制每个分布的概率质量函数,注意当 n =3600 时,这个近似值实际上是非常好的。
_,ax = plt.subplots(2, 2, figsize=(25, 10), sharey=True, sharex=True)
ax = ax.ravel()
λ=9
ax[0].hist(binom.rvs(n=20, p=9/20, size=100000), bins=50)
ax[0].set_title(f'Binomial RV with n={20}, p={9}')
ax[1].hist(binom.rvs(n=60, p=9/60, size=100000), bins=50, color='darkorange')
ax[1].set_title(f'Binomial RV with n={60}, p={9}')
ax[2].hist(binom.rvs(n=1000000, p=9/1000000, size=100000), bins=50, color='black');
ax[2].set_title(f'Binomial RV with n={3600}, p={9}')
ax[3].hist(poisson.rvs(9, size=100000), bins=50, color='red')
ax[3].set_title(f'Poisson RV with λ={9}');
图 2:使用具有不同 n 值的二项式 RV 来近似泊松 RV;请注意,随着 n 变大,二项式 RV 的采样分布形状越来越接近泊松 RV 的采样分布。
练习
你将在下周的文章中找到答案。
- 你有一副标准的牌,你在挑选牌,直到你得到一张女王(如果他们不是女王,你替换他们)。你需要挑 5 张牌的概率是多少?而不到 10?而且超过 12 个?
- Jorge 对冰柜进行检查。他发现 94%的冰柜成功通过了检查。设 C 为 Jorge 检查的冰柜数量,直到某个冰柜未通过检查。假设每次检查的结果都是独立的。
- 佩德罗罚球命中率为 25%。作为热身,佩德罗喜欢罚任意球,直到他罚进为止。设 M 为佩德罗第一次任意球射门的次数。假设每个镜头的结果是独立的。找出佩德罗第一次投篮不到 4 次的概率。
- 构建一个计算泊松 PMF 的函数,除了使用来自
numpy
的np.exp
之外,不使用任何来自外部包的函数。选择一些参数,并将您的结果与scipy
中的pmf
函数进行比较。 - 构建一个计算泊松 CDF 的函数,而不使用任何外部包。选择一些参数,并将您的结果与
scipy
中的cdf
函数进行比较。
上周的答案
def fact(n):
x = 1
for i in range(1, n+1):
x *= i
return x
def comb(n, k):
x = 1
return fact(n)/(fact(k)*fact(n-k))
def binompmf(prob, n, k):
return comb(n,k)*prob**k*(1-prob)**(n-k)
def binomcdf(prob, n, x):
result = 0
for x_ in range(0, x+1):
result += binompmf(prob, n, x_)
return result
1.一家公司生产瓶装水。在其主要工厂,有缺陷的瓶子数量是 5%。质量检查包括随机选择和测试 1000 瓶。这些样品中有缺陷的瓶子数量的平均值和标准偏差是多少?
print('μ_x={}'.format(1000*0.05))
print('σ_x={}'.format((1000*0.05*(1-0.05))**(1/2)))μ_x=50.0
σ_x=6.892024376045111
2.一家葡萄酒公司正在进行促销活动,声称每 4 箱葡萄酒中有 1 箱含有惊喜。假设你会买 5 箱这款酒,让 X 代表你在这些箱子里可以赢得的惊喜数量。假设这些盒子代表随机样本,并假设盒子之间的惊喜是独立的。你在 5 个盒子中最多赢得 1 个惊喜的概率是多少?
(你能用三种不同的方法解决这个问题吗?提示:通过抽样,对个体概率求和,并使用 CDF)
# We want to calculate P(X<=1)
# Solution 1: By sampling
x = np.random.binomial(5, 0.25, 1000000)
x[x<=1].shape[0]/x.shape[0]0.632957# Let's draw our discrete distribution
sns.histplot(x, stat="density", discrete=True, shrink=0.3);
# Solution 2: Solve it by calculating the probability for each case (X=0 and X=1)
# Using our function
print(str(binompmf(0.25, 5, 0) + binompmf(0.25, 5, 1)))
# Using scipy package
print(str(binom.pmf(0, 5, 0.25)+binom.pmf(1, 5, 0.25)))0.6328125
0.6328125# Solution 3: Using the CDF
# Using our function
print(str(binomcdf(0.25, 5, 1)))
# Using scipy package
print(str(binom.cdf(1, 5, 0.25)))0.6328125
0.6328125
3.一位数学老师正在和她的学生一起做一个活动,她给他们一个 20 个问题的选择题,而他们一个答案也不知道。学生需要猜测每个问题,每个问题有 5 个可能的选择,其中一个是正确的。每个学生答对的问题数量的平均值和标准差是多少?
你能用两种不同的方法解决这个问题吗?提示:通过采样和使用我们上面做的理论推导)
# Solution 1: solving by sampling
n = 20
p = 0.2
# Using numpy package
X = np.random.binomial(20, 0.2, 1000000)
print(X.mean())
print(X.std())4.001996
1.7910455091884183# Using the theoretical derivation
μ_x = n*p
σ_x = (n*p*(1-p))**(1/2)
print(μ_x)
print(σ_x)4.0
1.7888543819998317
保持联系: LinkedIn
PyTorch 几何艺术
使用 Pytorch 和几何形状通过深度学习创建艺术。
(图片由作者提供)须弥山
在浏览这个谷歌实验画廊的时候,我偶然发现了这个有趣的工具。在该算法中,输入图像用简单的几何形状如圆形、椭圆形、三角形、矩形等重建。在这个过程中,一个真实的图像开始看起来更像一幅画或一幅漫画。你可以在这个网站上查看例子。他们算法的工作方式是逐步优化输入图像和构建图像之间的像素级均方误差损失。每个形状以连续的方式被单独优化,并且该算法是爬山算法而不是基于梯度的方法。
我开始想知道这项任务是否可以使用基于梯度的算法来完成,以及是否所有的形状都可以并行优化,而不是顺序进行。为了应用基于梯度的算法,损失函数需要被转换成关于参数和参数可微分的形式,在这种情况下,参数是几何形状的位置和尺寸。MSE 损失相对于这些参数是不可微的,因为 RGB 颜色值从形状内部到外部的过渡本质上是离散的,它是不连续和不可微的。要将其转换为可微形式,需要进行以下转换。
让我们从一个 360* 360 像素的图像开始,我想在图像的中心放一个圆。以图像的中心为原点,每个像素被分配一个(R,theta)值,图像的宽度为一个单位。下图显示了以原点为中心的半径为 0.2 的圆,其中圆内区域的值等于 Tanh(5*(0.2-R)/0.2),圆外区域的值等于零。Tanh 激活使从内到外的过渡平滑,但仍保持其突然性。梯度出现在圆的外 20 %,这就是学习发生的地方!。
类比量子力学,tanh 激活将几何物体的类粒子性质转化为类波性质!
(作者提供的图片)1)像素的径向值 2)像素的角度值(从-π到π)3)双曲正切激活后的值 4)使用的双曲正切激活函数
再添加几个参数来控制旋转,并在 X 和 Y 方向缩放图像,我们就可以开始构建椭圆了。下面的动画显示了一个示例,其中给定了一个椭圆作为目标图像,并使用梯度下降将单个几何对象转换为椭圆。
(图片由作者提供)1)目标图片 2)使用梯度下降和 Tanh 激活的学习过程以及 Pytoch 亲笔签名的魔力!
您可以注意到椭圆的边界变得模糊,因为这是过渡发生的地方,并且 RGB 值被设置为等于 Tanh 激活后的值和损失(在这种情况下为像素 MSE)。
让我们画画吧
现在我们已经准备好开始绘画了,我们所需要的只是一堆这样的圆圈,一些数学知识,一些颜色和 Pytorch 的亲笔签名来完成这个魔术!
现在,当我拍摄多个几何对象时,对象之间会有重叠,所以接下来需要解决的是图片中对象的排序。因此,排序是在对象的区域上完成的,较大的对象在背景中,较小的对象移动到前面。我还为对象的不透明度添加了一个参数,可以在开始优化之前设置。
最初,对象随机散布在整个图像中,并且对象的 RGB 值被设置为等于它们在图像中所占区域的加权平均 RGB 值,其中权重等于图片中对象的权重,例如,如果对象在前面,则权重将高于它在背景中的情况。如果对象边界处图片的实际颜色与对象的颜色相同,则对象在该方向上扩展,如果不同,则从该方向检索或收缩。对象的边界充当颜色传感器,因为渐变只存在于边缘。
(图片由作者提供)1)目标图像(生活艺术国际中心的 Sumeru Mantap)具有 500 个旋转椭圆的优化图像 3)去除边缘模糊后的图像。
在上面的图中,你看到的是一个用 500 个旋转椭圆重建的图像。它看起来或多或少像一幅画,第二幅图像是优化后的图像,第三幅是去除边缘过渡效果后的图像。对象的不透明度设置为 50%。
下面的动画展示了优化过程!
1)显示 500 个对象的优化过程的动画 2)显示对象在最终图像中的放置顺序的动画。
下面的另一个例子是 1000 个不透明度为 80%的对象。
(图片由作者提供)1)目标图像(国际生活艺术中心的 Vishalakshi Mantap)2)具有 1000 个旋转椭圆的优化图像 3)去除边缘模糊后的图像。
1)显示 1000 个对象的优化过程的动画 2)显示对象在最终图像中的放置顺序的动画。
傅立叶形状
到目前为止,我们只处理了圆形和椭圆形,我们可以移动到更多的几何对象,如正方形,三角形等。傅立叶级数。通过在方程中加入足够多的傅立叶级数项,我可以构造出任何封闭的形状。看看下面的几个例子,我优化了一个单一的几何对象,从一个圆形到想要的形状。
(图片由作者提供)展示各种形状优化过程的动画。1)三角形 2)心形 3)星星 4)云 5)手 6)鸟
以下是各自的目标图像
(按作者分类的图片)各自的目标图片
前三幅图像比较容易近似,所以只使用了 10 个傅立叶级数项,而后三幅图像使用了 50 个傅立叶级数项,但是对于最后一个形状,50 个项仍然不足以以以良好的质量近似该鸟。
现在,我可以通过保存傅立叶项的权重,得到想要的物体形状的方程,并使用它们来代替椭圆构建图像。
下面是一个例子,我用随机形状优化图像,每个形状都用自己的傅立叶系数优化。
(图片由作者提供)1)目标图像(Vishalakshi Mantap)2)500 个随机形状的优化过程 3)显示几何形状排序的动画
但是我们可以固定傅立叶系数来得到一个特定的形状,比如三角形、正方形或心形。我将在下一篇文章中分享这些特定形状的结果。同时,你可以在这里访问代码。
我已经在这个视频里详细解释了算法。
此处阅读更多博客。
几何深度学习简介
几何深度学习
机器学习的埃尔兰根计划
的一系列博文,关于 几何深度学习(GDL)课程 ,在 AMMI 计划; 非洲机器智能硕士 ,所教 迈克尔·布朗斯坦 , 琼·布鲁纳 , 塔科·科恩 ,以及 佩塔尔·韦利奇科维奇
深度学习的快速发展创造了不同的神经网络架构,这些架构在各个数据科学领域都取得了成功。同时,我们在这些架构之间没有一个明确的统一原则,所以很难理解它们之间的关系。在这篇文章中,我们回顾了各种数学家对对称性的定义,以及埃尔兰根程序的出现,以及它是如何以几何深度学习的名义进入深度学习的。我们将看到深度学习的当前状态如何让我们想起 19 世纪的许多几何。
我们主要参考的是四位导师的 GDL 原书 ,以及 GDL 课程atAMMI。
来自 GDL 的图片课程:第一讲
这篇博文与MohammedElfatih Salah合著
如果你想要一个简单的词来描述我们将要谈论的内容,并对几何深度学习(GDL)的思想有一个直觉,那将是对称性。让我们回顾历史,看看数学家们是如何定义这个词的。20 世纪最优秀的数学家之一 H. Weyl 给出了关于 T4 对称性的第一个定义。Weyl 在他关于对称性的话里说:
图片来自 GDL 课程:第一讲
追溯到古希腊人,他们也用这个术语来模糊地表达比例、和谐和音乐之美。
第一个例子是五个正多面体,或者是雅典哲学家柏拉图提出的柏拉图立体。柏拉图立体是三维空间中的凸正多面体。在正多面体中,面在形状和大小上是相同的,所有的角和所有的边也是相同的。并且同样数量的面在每个顶点相遇。
类似的例子来自古希腊,对称形状的水结晶是由数学家 j .开普勒提出的。他写了一本名为 的关于六角雪花的书 ,在书中他解释了雪花的六面对称。
图片来自 GDL 课程:第一讲
欧几里得几何也是可以追溯到古希腊。另一位希腊数学家欧几里得对欧几里得几何定义如下:
在一个平面上,给定一条直线和一个不在该直线上的点,至多可以通过该点画出一条与给定直线平行的直线。
随着 19 世纪的到来,又经过了 射影几何 的发展;到了法国人庞斯列,这种欧几里得几何学告一段落。射影几何中,点和线是可以互换的;没有任何两条直线恰好在一点上是平行的。
图片来自 GDL 课程——作者编辑
有人会问非欧几何的第一次出现是什么?我们会说它来自俄罗斯数学家罗巴切夫斯基。他指出,在任何一点都有不止一条线可以延伸通过该点,并与该点不属于的另一条线平行。类似的想法也有,但我们在这里就不解释了,就是德国数学家 b .黎曼的曲面的https://en.wikipedia.org/wiki/Differential_geometry#:~:text=Differential geometry is a mathematical,linear algebra and multilinear algebra.(黎曼几何)。
在所有这些发展之后,接近 19 世纪末,数学家们争论哪种几何是正确的,以及应该如何定义它。直到德国数学家 f·克莱因发表了埃尔兰根纲领,他在其中给出了所有这些问题的答案。
当 F. Klein 提出 Erlangen 计划时,他只有 23 岁,在这个年龄,他被任命为巴伐利亚大学的教授。在这个埃尔兰根计划中,克莱恩将几何描述为对不变量和对称性的研究;这意味着在某一类变换下不变的性质。
**图片来自 GDL 课程:第一讲
所以我们可以从克莱因的话中清楚地看到,适当选择对称性可以定义不同的几何形状。例如,定义欧几里德几何的对称性是刚性运动。这些是平移、反射和旋转,它们保留了角度、距离、面积、线的平行度和交点等属性。
**图片来自 GDL 课程:第一讲
另一件重要的事情是,这个埃尔兰根计划(T21)扩展到了其他领域,尤其是在物理学领域。这里一个明显的例子是 Noether 定理,它指出一个物理系统运行的每一个明显的对称性都有一个相应的保护定律。在这个定理之前,如果你想发现能量守恒,你必须做非常详细的材料实验观察和测量,以确保能量保持不变,即使有一些微小的误差。但是 Noether 定理说能量守恒源于时间的平移对称性。所以相对清楚的是,你的实验结果,无论是昨天做的,今天做的,还是明天做的,都是一样的。
我们还可以提到诺贝尔物理学家之一 p .安德森的话:"说物理学是对对称性的研究只是稍微夸大了一点。"
在经历了关于几何和对称性的漫长历史背景之后,你可能会问这与深度学习有什么关系。简单的答案是,深度学习的现状让我们想起了 19 世纪的许多几何。由于我们对于不同类型的数据有不同的神经网络架构(比如对于特殊数据有 CNN,对于顺序数据有 transformers,对于时态数据有 RNNs),但是这些方法之间没有明确的统一原则。因此,很难理解它们之间的关系,这导致了相同概念的重新发明。几何深度学习揭示了统一在所有这些架构背后的基本原理。我们希望在埃尔兰根计划的本质上实现这种统一,这将在后面的帖子中澄清。
B 另外,正常的问题会是为什么要研究几何深度学习,或者 GDL 的目标是什么。我们可以说 GDL 有两个目的。首先,它解释了为什么当前最先进的架构是成功的(因为它们尊重数据的不变性,我们将在后面的帖子中解释)。第二,它提出了主要原则,如果我们遵循这些原则,我们可以为未来的任务构建更好的架构(我们还将有另一篇关于 GDL 蓝图的帖子)。
“几何深度学习”一词在 2017 年的一篇论文中流行起来:几何深度学习:超越欧几里德数据发表在布朗斯坦等人撰写的 IEEE 信号处理杂志上。最近,布朗斯坦、布鲁纳、科恩和韦利奇科维奇写了一篇长文,这是一本名为几何深度学习:网格、组、图、测地线和量规的书的预览。
在这一系列的帖子中,我们将详细解释如何通过两个属性对称性和比例分离我们可以开发一个 GDL 蓝图作为当前最先进架构的框架。我们将在 GDL 蓝图的管道中讨论所谓的几何域或 5 Gs ,包括网格、组、图、测地线和量规、及其适当的结构。
参考文献:
- GDL 课程,( AMMI ,2021 年夏季)。
- M. M .布朗斯坦第一讲[ 视频 | 幻灯片。
- 米(meter 的缩写))m .布朗斯坦、j .布鲁纳、t .科恩和 p .韦利奇科维奇,几何深度学习:网格、组、图形、测地线和量规 (2021)。
我们感谢 Rami Ahmed 对草案提出的宝贵意见。
深度学习的几何基础
曼梯·里的埃尔兰根计划
几何深度学习是从对称性和不变性的角度对一大类 ML 问题进行几何统一的尝试。这些原则不仅是卷积神经网络的突破性性能和图形神经网络最近成功的基础,而且还提供了一种构建新型特定问题归纳偏差的原则性方法。
这篇博文与 琼·布鲁纳 , 塔可·科恩 和 佩塔尔·韦利奇科维奇 合著,基于 m·m·布朗斯坦、j·布鲁纳、t·科恩和 p·韦利奇科维奇的新“原型书”
1872 年 10 月,巴伐利亚州埃尔兰根市一所小大学的哲学系任命了一位新的年轻教授。按照惯例,他被要求提供一个首次研究计划,他发表了有点长而无聊的标题Vergleichende Betrachtungenüber neuere geometricsche Forschungen(“近期几何研究的比较评论”)。这位教授名叫费利克斯·克莱因,当时只有 23 岁,他的开创性工作已经作为“埃尔兰根计划”载入了数学史。
费利克斯·克莱因和他的埃尔兰根计划。图片:维基百科/密歇根大学历史数学文集。
十九世纪对几何学来说是非常富有成果的。在欧几里得之后的近两千年里,庞斯列构建射影几何,高斯、波尔约和罗巴切夫斯基构建双曲几何,黎曼构建椭圆几何,这是第一次表明,各种各样的几何是可能的。然而,这些构造很快就分化成独立和不相关的领域,那个时期的许多数学家质疑不同的几何图形如何相互关联,以及什么实际上定义了几何图形。
克莱因的突破性见解是将几何定义作为对不变量的研究,或者换句话说,是在某种类型的变换(对称性)下保留的结构。Klein 使用群论的形式来定义这种变换,并使用群及其子群的层次来分类由此产生的不同几何。因此,刚性运动组导致传统的欧几里得几何,而仿射或射影变换分别产生仿射和射影几何。重要的是,埃尔兰根计划仅限于齐次空间[2]和最初排除黎曼几何。
K lein 的 Erlangen 程序将几何视为研究在某些类型的变换下保持不变的性质。2D 欧几里得几何是由刚性变换(模型化为等距群)定义的,它保持面积、距离和角度,因此也保持平行度。仿射变换保持平行,但距离和面积都不变。最后,射影变换具有最弱的不变性,仅保留了交集和交比,并且对应于三者中最大的组。因此,克莱因认为射影几何是最普遍的几何。
埃尔兰根计划对几何和数学的影响非常深远。它也蔓延到其他领域,特别是物理学,对称性的考虑允许从第一原理推导守恒定律——这是一个惊人的结果,被称为 Noether 定理[3]。过了几十年,这个基本原理——通过规范不变性的概念(杨和米尔斯在 1954 年发展的广义形式)——被证明成功地统一了除重力之外的所有基本自然力。这就是所谓的标准模型,它描述了我们目前所知道的所有物理学。我们只能重复诺贝尔奖得主、物理学家菲利普·安德森[4]的话
“说物理学是对对称性的研究只是稍微夸大了这一点。''
我们认为,深度(表征)学习领域的现状令人想起十九世纪几何的情况:一方面,在过去的十年里,深度学习带来了数据科学的革命,使许多以前认为遥不可及的任务成为可能——无论是计算机视觉、语音识别、自然语言翻译,还是下围棋。另一方面,我们现在有一大堆针对不同类型数据的不同神经网络架构,但几乎没有统一的原则。因此,很难理解不同方法之间的关系,这不可避免地导致相同概念的重新发明和重新标记。
今天的深度学习:一个架构的动物园,几个统一的原则。动物图像:ShutterStock。
几何深度学习是我们在[5]中引入的一个总括术语,指的是最近试图提出类似于 Klein 的 Erlangen 程序的 ML 的几何统一。它有两个目的:第一,提供一个通用的数学框架来推导最成功的神经网络结构,第二,给出一个建设性的程序来以有原则的方式构建未来的结构。
S 监督机器学习在其最简单的设置中本质上是一个函数估计问题:给定训练集上一些未知函数的输出(例如,带标签的狗和猫图像),人们试图从一些假设类中找到一个函数 f ,该函数很好地符合训练数据,并允许预测先前看不见的输入的输出。在过去的十年中,大型高质量数据集(如 ImageNet)的可用性与不断增长的计算资源(GPU)相吻合,允许设计丰富的函数类,这些函数类有能力插值这样的大型数据集。
神经网络似乎是表示函数的合适选择,因为即使是最简单的架构,如感知器,在仅使用两层时也可以产生密集的函数类,允许以任何期望的精度逼近任何连续函数,这种特性被称为通用逼近[6]。
多层感知器是通用逼近器:只需一个隐藏层,它们就可以表示阶跃函数的组合,允许以任意精度逼近任何连续函数。
这个问题在低维中的设置是近似理论中的经典问题,该问题已经被广泛研究,具有精确的估计误差的数学控制。但在高维度中,情况完全不同:人们可以很快看到,为了逼近一个简单的类,例如 Lipschitz 连续函数,样本的数量随着维度呈指数增长——这种现象俗称为“维数灾难”。由于现代机器学习方法需要处理数千甚至数百万维的数据,维数灾难总是在幕后存在,使得这种天真的学习方法不可能实现。
维数灾难的图解:为了逼近一个由放置在 d 维单位超立方体(蓝色)的象限中的高斯核组成的 Lipschitz 连续函数,误差为 ε,一个需要𝒪(1/ εᵈ 样本(红点)。
这可能在像图像分类这样的计算机视觉问题中看得最清楚。即使是很小的图像也往往是非常高维的,但直觉上它们有很多结构,当人们将图像解析为向量并将其输入感知机时,这些结构就会被破坏并丢弃。如果图像现在仅移动了一个像素,矢量化输入将会非常不同,并且需要向神经网络显示大量示例,以了解移动的输入必须以相同的方式进行分类[7]。
不幸的是,在许多高维 ML 问题中,我们有一个来自输入信号几何的额外结构。我们称这种结构为“对称先验”,这是一个普遍的强有力的原则,给了我们在维数灾难问题上的乐观。在我们的图像分类示例中,输入图像 x 不仅仅是一个 d 维向量,而是在某个域ω上定义的信号,在这种情况下是一个二维网格。磁畴的结构由一个对称群𝔊(在我们的例子中是 2D 平移群)捕获,它作用于磁畴上的点。在信号𝒳(ω的空间中),基础域上的群作用(群的元素,𝔤∈𝔊)通过所谓的群表示ρ* (𝔤)来表现——在我们的情况下,它只是简单的移位算子,一个 d × d 矩阵作用于一个 d 维向量【8】。*
几何先验的图示:输入信号(图像 x∈𝒳(ω))定义在域(网格ω)上,其对称性(平移群𝔊)通过群表示 ρ( 𝔤)(移位算子)作用于信号空间。对函数 f(例如,图像分类器)如何与该组交互做出假设限制了假设类别。
作为输入信号基础的域的几何结构对我们试图学习的函数类 f 施加了结构。人们可以拥有不受群体行动影响的不变函数,即对于任何𝔤∈𝔊,f(ρ(𝔤)x)=f(x)和 x 。另一方面,可能会有这样一种情况,其中函数具有相同的输入和输出结构,并且以与输入相同的方式进行变换——这种函数称为等变函数,并且满足f(ρ(𝔤)x)=ρ(𝔤)f(x)【9】。在计算机视觉领域,图像分类很好地说明了一种设置,在这种设置中,人们需要一个不变函数(例如,无论猫位于图像中的什么位置,我们仍然希望将其分类为猫),而输出为逐像素标签掩码的图像分割是等变函数的一个示例(分割掩码应遵循输入图像的变换)。
另一个强大的几何先验是“尺度分离”。在某些情况下,我们可以通过“同化”附近的点来构建域的多尺度层次结构(下图中的ω和ω’),并产生由粗粒度运算符 P 关联的信号空间层次结构。在这些粗尺度上,我们可以应用粗尺度函数。我们说一个函数 f 是局部稳定的如果它可以近似为粗粒度算子 P 和粗尺度函数f≈f’∘p的合成。虽然 f 可能依赖于长程相关性,但是如果它是局部稳定的,那么这些可以被分成局部相互作用,然后传播到粗尺度【10】。
尺度分离的图示,其中我们可以将精细层次函数 f 近似为粗层次函数 f’和粗粒度算子 P 的组合f≈f’∘p。
T 这两个原则为我们提供了一个非常通用的几何深度学习蓝图,它可以在大多数用于表示学习的流行深度神经架构中得到认可:一个典型的设计由一系列等变层(例如 CNN 中的卷积层)组成,可能后跟一个不变全局池层,将所有内容聚集到单个输出中。在某些情况下,也可以通过某种粗化过程来创建域的层次结构,这种粗化过程采用本地池的形式。
几何深度学习蓝图。
这是一个非常通用的设计,可以应用于不同类型的几何结构,例如网格,具有全局变换群的齐次空间,图(和集合,作为一个特例),以及流形,其中我们具有全局等距不变性和局部规范对称性。这些原则的实施导致了当今深度学习中存在的一些最受欢迎的架构:卷积网络(CNN),从平移对称 中出现的,图形神经网络,DeepSets【11】和 Transformers【12】,实现置换不变性,对时间扭曲不变的门控 rnn(如 LSTM 网络)【13】,以及计算机图形和视觉中使用的内在网格 CNN【14】,它们可以从规范对称中导出**
几何深度学习的“5G”:网格、组(具有全局对称性的齐次空间)、图(以及作为特例的集合)和流形,其中几何先验通过全局等距不变性(可以使用测地线表示)和局部规范对称性来表现。
在未来的帖子中,我们将更详细地探索几何深度学习蓝图在“5G”上的实例[15]。最后一点,我们应该强调,对称性在历史上一直是许多科学领域的核心概念,其中物理学,正如在开始时已经提到的,是关键。在机器学习社区中,对称性的重要性早已得到认可,特别是在模式识别和计算机视觉的应用中,关于等变特征检测的早期工作可以追溯到 Shun'ichi Amari [16]和 Reiner Lenz [17]。在神经网络文献中,马文·明斯基和西蒙·派珀特[18]的感知机的组不变性定理对(单层)感知机学习不变量的能力提出了基本限制。这是研究多层架构[19–20]的主要动机之一,最终导致了深度学习。
[1]根据一个流行的观点,包括维基百科在内的许多来源都重复了这个观点,埃尔兰根计划是在 1872 年 10 月克莱因的就职演说中提出的。克莱因确实做过这样的演讲(虽然是在 1872 年 12 月 7 日),但那是针对非数学专业的听众,主要是关于他的数学教育思想。现在所谓的“埃尔兰根计划”实际上是前面提到的小册子Vergleichende Betrachtungen,副标题为program zum Eintritt in die philosophy sche fakultt und den Senat der k . Friedrich-Alexanders-universit t zu Erlangen(“进入弗里德里希-亚历山大皇帝埃尔兰根大学哲学系和参议院的计划”,见英文翻译。虽然埃尔兰根居功至伟,但克莱因在那里只呆了三年,1875 年转到慕尼黑工业大学(当时名为 Technische Hochschule ,接着是莱比锡(1880),最后从 1886 年到退休在哥廷根定居。参见 r . TobiesFelix Klein——数学家、学术组织者、教育改革家 (2019)载于:h . g . Weigand et al .(eds)The Legacy of Felix Klein、Springer。
[2]齐次空间是指“所有点都相同”且任何一点都可以通过群作用转化为另一点的空间。在黎曼之前提出的所有几何都是如此,包括欧几里得、仿射和射影几何,以及第一批常曲率空间(如球面或双曲空间)上的非欧几里得几何。将克莱因的思想扩展到流形上花费了大量的努力和将近 50 年的时间,特别是由埃利·卡坦和法国几何学派。
[3]克莱因自己可能已经预见到他的想法在物理学中的潜力,抱怨“数学物理学家如何坚持不懈地忽视在许多情况下仅通过适度培养投影视图给他带来的优势”。到那个时候,通过变分法的观点来思考物理系统已经很普遍了,从“最小作用原理”推导出控制这种系统的微分方程,即作为一些功能(作用)的最小化。在 1918 年发表的一篇论文中,艾米·诺特表明,物理系统作用的每一个(可微)对称都有相应的守恒定律。无论如何,这是一个惊人的结果:事先,需要细致的实验观察来发现基本定律,如能量守恒,即使这样,这也是一个来自任何地方的经验结果。历史笔记见 C. Quigg,座谈会:一个世纪的 Noether 定理 (2019),arXiv:1902.01989。
[4] P. W .安德森,更多的是不同的 (1972),科学 177(4047):393–396。
[5] M. M. Bronstein 等人几何深度学习:超越欧几里德数据 (2017),IEEE Signal Processing Magazine 34(4):18–42 试图从频谱分析的角度统一网格、图形和流形上的学习。“几何深度学习”这个术语实际上是在更早的时候,在迈克尔的ERC·格兰特的提议中创造出来的。
[6]通用逼近定理有多个版本。这通常归功于 G. Cybenko,通过叠加一个 s 形函数的近似法 (1989)控制、信号和系统数学 2(4):303–314 和 K. Hornik,多层前馈网络的近似能力(1991),神经网络 4(2):251–257。
[7]解决计算机视觉中这一问题的方法来自于因研究视觉皮层而获得诺贝尔医学奖的胡贝尔和威塞尔在神经科学领域的经典著作。他们表明,大脑神经元被组织成局部感受野,这启发了一类新的具有局部共享权重的神经架构,首先是 K. Fukushima 的 Neocognitron,这是一种不受位置变化影响的模式识别机制的自组织神经网络模型(1980),Biological Cybernetics 36(4):193–202,然后是卷积神经网络,Y. LeCun 等人的研讨会工作,Gradient-based learning applied to document recognition(1998),Proc .IEEE 86(11):2278–2324,其中跨图像的权重分配有效地解决了维数灾难。
[8]注意,组被定义为一个抽象对象,没有说组元素是什么(例如某个域的变换),只说它们如何组成。因此,非常不同种类的物体可能有相同的对称群。
[9]这些结果可以推广到近似不变和等变函数的情况,例如,参见 j .布鲁纳和 s .马拉特,不变散射卷积网络 (2013),转。PAMI 35(8):1872-1886。
[10]尺度分离是物理学中使用的一个强有力的原理,例如在快速多极方法(FMM)中,这是一种最初开发的数值技术,用于加速 n 物体问题中长程力的计算。FMM 将紧密相连的来源组合在一起,并将其视为单一来源。
[11] M. Zaheer 等人,深集 (2017),NIPS。在计算机图形社区,在 C. R. Qi 等人, PointNet:用于 3D 分类和分割的点集的深度学习 (2017)中提出了类似的架构。
[12] A. Vaswani 等人,注意就是你所需要的一切 (2017),NIPS,介绍了现在流行的变压器架构。可以认为是一个有完整图形的图形神经网络。
[13] C. Tallec 和 Y. Ollivier,递归神经网络能扭曲时间吗? (2018),arXiv:1804.11188。
[14] J. Masci 等人,黎曼流形上的测地卷积神经网络 (2015),arXiv:1501.06297 是第一个在网格上的局部坐标图中应用滤波器的类卷积神经网络架构。是 T. Cohen 等人的特例,规范等变卷积网络和二十面体 CNN (2019),arXiv:1902.04615。
[15] M. M .布朗斯坦、j .布鲁纳、t .科恩和 p .韦利奇科维奇,《几何深度学习:网格、组、图形、测地线和量规》( 2021 年)
[16] S.-l. Amari,允许和检测不变信号变换的特征空间(1978),联合会议。模式识别。Amari 也是著名的信息几何领域的先驱,该领域使用微分几何的工具研究概率分布的统计流形。
[17] R. Lenz,图像处理中的群论方法(1990),Springer。
[18]明斯基和帕佩特。感知机:计算几何导论(1987),麻省理工学院出版社。这是第二版的著名著作,因为第一个“人工智能冬天”而受到指责,它包括了额外的结果,并回应了对 1969 年早期版本的一些批评。
[19] T. J. Sejnowski,P. K. Kienker 和 G. E. Hinton,《用隐藏单元学习对称群:超越感知器》( 1986 年),《物理学 D:非线性现象》22(1–3):260–275
[20] J. Shawe-Taylor,将对称性纳入前馈网络(1989 年),ICANN。对不变和等变神经网络采取表示理论观点的第一项工作是 J. Wood 和 J. Shawe-Taylor,表示理论和不变神经网络(1996),离散应用数学 69(1–2):33–60。在深度学习的“现代时代”,将对称性构建到神经网络中是由 R. Gens 和 P. M. Domingos、Deep symmetry networks(2014 年)、NIPS(另见 Pedro Domingos 的2014 年 ICLR 邀请演讲)完成的
感谢 Ben Chamberlain 对本文的校对,感谢 Yoshua Bengio、Charles Blundell、Andreea Deac、Fabian Fuchs、Francesco di Giovanni、Marco Gori、Raia Hadsell、Will Hamilton、Maksym Korablyov、Christian Merkwirth、Razvan Pascanu、Bruno Ribeiro、Anna Scaife、Jürgen Schmidhuber、Marwin Segler、Corentin Tallec、NGN Vu、Peter Wirnsberger 和 David Wong 对本文不同部分的反馈我们也感谢董晓文和皮埃特罗·里奥帮助我们打破“怯场”,展示了我们作品的早期版本。
查看附加信息 项目网页朝向数据科学 中型帖子、 订阅 迈克尔的帖子和 YouTube 频道 ,获取 中型会员资格
Geopandas 实践:构建地理空间机器学习管道
最后一部分:关于如何处理地理空间机器学习的教程
第 1 部分:地理空间概念介绍( 跟随此处 )
第 2 部分:地理空间可视化和几何创建( 跟随此处 )
第 3 部分:地理空间操作( 跟随此处 )
第 4 部分:构建地理空间机器学习管道(本文)
Marjan Blan | @marjanblan 在 Unsplash 上的照片
在这篇文章中,我们将通过涵盖不同类别的地理空间机器学习任务以及如何实现它们来结束关于 Geopandas 动手操作的系列。
目录:
- 概述
- 地理空间回归
- 地理空间分类
- 地理空间聚类
- 下一步是什么
概述
现在,我们将熟悉不同类型的地理空间机器学习任务,并获得关于它们与典型的非空间问题如何不同的早期直觉。我们将要讨论的常见任务是地理空间回归、分类和聚类。
地理空间回归
非空间回归问题考虑多个输入变量来估计目标输出的值。典型地,目标变量是连续变量的形式。
以一个回归任务为例,在给定一些其他预测因素的情况下,例如单元的大小、房间数量及其过去 20 年的历史销售价格,来预测房价。然后,您会找到使某个误差函数最小化的最佳拟合方程。
但是,在地理空间回归任务中,您需要将空间相关性作为因变量的一部分。
地理空间回归任务
如上图所示,您的房价(目标变量)现在具有空间感知能力。这意味着一所房子的位置可能会影响其邻近房子的价格。
不仅如此,独立输入变量也有其对应的空间依赖关系。例如,一栋房屋的历史价格会对其他房屋的历史价格产生影响。
在更一般的情况下,即使是独立变量也会对其他变量产生空间影响(例如,住宅区的房间数量会影响附近地区家庭的平均规模)。这些空间相互依赖性是地理空间回归问题的关键。
通常,可以获取这些空间相关性的一些更常见的地理空间回归算法有:
- 普通最小二乘(OLS)回归,以及
- 地理加权回归(GWR)
地理空间分类
同样,非空间分类任务会考虑多个输入变量来估计目标输出的类别。通常,目标输出以离散变量的形式表示一个特定的类(例如一只猫或一只狗)。
但是,在地理空间分类任务中,您通常会对像素级或整个栅格数据集执行分类。这可以包括语义分割、实例分割或栅格分类。
地理空间分类任务
上图说明了在给定栅格数据的情况下确定土地利用(如水体、森林、旱地、城市地区)的逐像素语义分割任务。
与典型的分类问题类似,地理空间分类任务可以使用深度神经网络(计算机视觉)、随机森林、支持向量机(SVM)或最大似然模型来解决。
地理空间聚类
最后但同样重要的是,另一个常见的地理空间机器学习任务包括地理空间聚类。在传统的非空间任务中,我们可以通过根据一些相似性度量(如距离、密度、等)将大量观察结果分组为几个“热点”来执行聚类。
但是根据地理第一定律:
“一切事物都与其他事物相关,但近的事物比远的事物更相关。”—瓦尔多·托布勒
这使得地理空间机器学习环境中的聚类更加困难,因为我们还需要考虑每个观察在其空间环境中如何彼此相关(即空间受限的)。
地理空间聚类任务
一个有趣的地理空间聚类问题是时空模式挖掘。除了考虑不同观察点或多边形之间的空间依赖性,这类算法还考虑了时间依赖性。为了能够对空间-时间-观察点进行聚类,通常会构建一个三维图表,然后聚类算法可以在该图表中工作。
3D 时空地理空间聚类任务
解决地理空间聚类问题的一些更常见的模型有:
- 空间约束多元聚类
- 热点分析
- 基于密度的聚类
- 三维时空模式挖掘
做订阅我的邮件简讯:【https://tinyurl.com/2npw2fnz】在这里我定期用通俗易懂的语言和漂亮的可视化总结 AI 研究论文。
下一步是什么
地理空间机器学习领域非常广阔,我希望这篇文章能给你一瞥这个领域的多样性。如果你对任何相关的话题感兴趣,请不要犹豫让我知道。你也可以看看我的其他地理空间机器学习帖子:
* *
Geopandas 动手操作:地理空间数据可视化和几何学介绍
第 2 部分:关于如何处理地理空间机器学习的教程
第一部分:地理空间概念介绍( 跟随此处 )
第二部分:地理空间可视化和几何创建(本文 )
第三部分:地理空间操作( 跟随此处 )
第四部分:构建地理空间机器学习管道( 跟随此处 )
Marjan Blan | @marjanblan 在 Unsplash 上的照片
在本帖中,我们将介绍地理空间可视化的各个方面,并向您介绍如何使用 Geopandas 创建您自己的地理空间数据。
目录:
- 概述
- 地理空间可视化
- 几何简介和创建您自己的地理空间数据
概述
在之前的文章这里中,我们讨论了 geopandas 的基础知识,比如它的底层数据类型、几何列和内置属性,我们可以很容易地对它们进行操作。
现在,我们将更深入地挖掘 geopandas,例如如何生成漂亮的地理空间可视化,并创建您自己的地理空间数据,供后续在机器学习管道中使用。
地理空间可视化
我们仍将使用 geopandas 提供的纽约行政区内置数据集。
import geopandas
path_to_data = geopandas.datasets.get_path("nybb")
gdf = geopandas.read_file(path_to_data)
gdf = gdf.set_index("BoroName")
假设我们想要可视化纽约每个区的相对面积大小。我们可以轻松地调用 plot()函数,与 Matplotlib 中的函数相同,并传入您想要绘制的列名,在本例中是“area”。
gdf["area"] = gdf.areagdf.plot("area", legend=True)
纽约行政区的面积大小
颜色似乎不能自然地表示连续变量,比如面积,让我们通过传递参数 cmap 来尝试改变颜色。
gdf.plot("area", legend=True, cmap="OrRd")
自然着色区
现在,哪一个区域更大就更明显了:被暗红色阴影笼罩的区域。如果您想查看配色方案及其相应标识符的列表,请点击此链接。
画两层或者标绘两层怎么样?回想一下,我们有先前的质心点:
gdf["centroid"] = gdf.centroid
我们可以绘制 2 个或更多的层,首先创建一个轴,我们将绘制 2 个或更多的层,并告诉 plot()函数在这个新创建的轴上绘制。
import matplotlib.pyplot as pltfig, ax = plt.subplots()
gdf.plot(ax=ax, color='white', edgecolor='black')
gdf['centroid'].plot(ax=ax)
plt.show()
两层绘图
几何学导论
下一个问题随之而来:我们能从现有的几何图形中创造出新的几何图形吗?是的,这篇文章将展示两个这样的例子。
A.缓冲器
比方说,你想在纽约周围设立一个无人驾驶飞机禁飞区,因为有贵宾进入该州,我们可以在该地区周围划出 10,000 英尺的缓冲区。
# Get the boundary of each area
gdf["boundary"] gdf.boundary# buffering the active geometry by 10 000 feet (geometry is already in feet)
gdf["buffered"] = gdf.buffer(10000)
ax = gdf["buffered"].plot(alpha=.5)
gdf["boundary"].plot(ax=ax, color="white", linewidth=.5)
区域边界周围有 10,000 英尺的缓冲区
B.信封
如果你想找到包围一个区域的最小的矩形,你也可以调用 envelope 函数并绘制出类似于上面的 Buffer 的几何图形。
Get the envelope of each area
gdf["enveloped"] = gdf.envelope# plotting the smallest rectangle envelope around an area
ax = gdf["enveloped"].plot(alpha=.5)
gdf["boundary"].plot(ax=ax, color="white", linewidth=.5)
感兴趣区域周围的最小包络
结论
就是这样!希望你今天能学到新东西。在下一篇文章中,我们将深入探讨如何执行地理空间操作,如合并、聚合、空间连接等。敬请期待!
做订阅我的邮件简讯:【https://tinyurl.com/2npw2fnz】在这里我定期用通俗易懂的语言和漂亮的可视化总结 AI 研究论文。
Geopandas 实践:地理空间关系和操作
关于如何处理地理空间机器学习的教程
第 1 部分:地理空间概念介绍( 跟随此处 )
第 2 部分:地理空间可视化和几何创建( 跟随此处 )
第 3 部分:地理空间操作(本帖 )
第 4 部分:构建地理空间机器学习管道( 跟随此处 )
Marjan Blan | @marjanblan 在 Unsplash 上的照片
在前两篇文章中,我们讨论了 geopandas 的基础知识以及如何可视化地理空间数据集。这里,我们将介绍地理空间操作的基本概念,包括关系和空间连接。
目录:
- 概述
- 地理空间关系
- 空间连接
概述
在我们继续本教程之前,请确保我们恢复了之前帖子的地理数据框。
# Import the necessary libraries
import geopandas
import shapely.geometry
import matplotlib.pyplot as plt# Initialize our geodataframe (gdf)
path_to_data = gpd.datasets.get_path("nybb")
gdf = gpd.read_file(path_to_data)# Set borough name as index
gdf = gdf.set_index("BoroName")# Get buffered region and centroid points
gdf["buffered"] = gdf.buffer(10000)
gdf['centroid'] = gdf.centroid
既然初步步骤已经定下来了,那就从教程开始吧。
地理空间关系
几何图形(如定义单个区的多边形或表示区域或点之间的边界以指示质心位置的线)可以彼此相关。
A.交叉
假设我们提出以下问题:缓冲区是否与纽约的布鲁克林区相交?
首先我们得到布鲁克林的多边形
brooklyn = gdf.loc["Brooklyn", "geometry"]
布鲁克林区
然后我们可以检查缓冲区域是否与它相交。
gdf["buffered"].intersects(brooklyn)>>BoroName
>>Staten Island True
>>Queens True
>>Brooklyn True
>>Manhattan True
>>Bronx False
>>dtype: bool
布朗克斯似乎离布鲁克林很远,边界外 10,000 英尺的缓冲区根本不与布鲁克林相交。
B.在…之内
另一个问题可能类似地出现:形心是否包含在它们各自的区(即。唯一的质心)?这可以通过指定点的集合是否包含在所述多边形中的内关系来执行。
gdf["centroid"].within(brooklyn)>>BoroName
>>Staten Island False
>>Queens False
>>Brooklyn True
>>Manhattan False
>>Bronx False
>>dtype: bool
不出所料,布鲁克林的质心位于布鲁克林多边形内,而不在其他区域内。
空间连接
我们可以使用 geopandas 执行的另一个重要的地理空间操作是空间连接。顾名思义,它允许两个不同的几何图形基于特定的几何标准进行连接。
让我们假设在这个区域内有几个公共汽车站,我们想要识别每个车站所在的行政区。
# Generate some points
b = [int(x) for x in gdf.total_bounds]
N = 6pointdf = gpd.GeoDataFrame([
{'geometry': shapely.geometry.Point(x, y), 'value1': x + y, 'value2': x - y}
for x, y in zip(range(b[0], b[2], int((b[2] - b[0]) / N)),
range(b[1], b[3], int((b[3] - b[1]) / N)))])# Make sure they're using the same projection reference
pointdf.crs = gdf.crs
随机生成的公交车站
想到的第一个解决方案是像以前一样执行一个 within 操作,然后对于每个区,将真正的索引值分配给该点(例如,如果汽车站 1 在布鲁克林,则将布鲁克林分配给该点项目)。从视觉上看,它可以表示为:
然后,可以按如下方式执行空间连接:
from geopandas.tools import sjoin# Joining the NYC borough INTO the pointdf
sjoin(pointdf, gdf, how="left", op="intersects")# The NaNs are the points that do not intersect with any borough
或者,如果您想删除 nan,可以执行一个内部连接来代替。
sjoin(pointdf, gdf, how="inner", op="intersects")
结论
就是这样!希望你今天能学到新东西。在下一篇文章中,我们将最终准备好建立我们的第一个地理空间机器学习管道。敬请期待!
做订阅我的邮件简讯:【https://tinyurl.com/2npw2fnz】在这里我定期用通俗易懂的语言和漂亮的可视化总结 AI 研究论文。
geo pandas hand-on:地理空间机器学习介绍
关于如何处理地理空间机器学习的教程
第一部分:地理空间概念介绍(本帖 )
第二部分:地理空间可视化和几何创建( 跟随此处 )
第三部分:地理空间操作( 跟随此处 )
第四部分:构建地理空间机器学习管道( 跟随此处 )
Marjan Blan | @marjanblan 在 Unsplash 上的照片
在这篇文章中,我们将介绍基本的地理空间数据类型、属性,以及如何使用 geopandas 来实现这些。
目录:
- 什么是 Geopandas
- 装置
- 地理空间概念
- 基本几何属性介绍
什么是 Geopandas
Geopandas 是一个开源库,支持使用和操作 Python 中的地理空间数据。它扩展了 pandas 中使用的通用数据类型,允许许多独特的几何操作:地理系列和地理数据框架。Geopandas 也是建立在 shapely 之上进行几何运算;它的底层数据类型允许 Geopandas 以惊人的速度运行,并且适用于许多需要大型地理空间数据集的机器学习管道。
装置
现在我们已经对 Geopandas 有所了解,让我们开始安装过程。
有很多选择,但是我推荐使用 conda 安装,因为它为你的项目创建了一个新的环境,而不会影响你系统中的其他库。要安装 conda,请遵循以下链接:安装 conda 。
- 创建一个新的 conda 环境并设置一些配置
conda create -n geo_env
conda activate geo_env
conda config --env --add channels conda-forge
conda config --env --set channel_priority strict
2.用康达安装
conda install python=3 geopandas
地理空间概念
A.地理空间公共数据类型
您需要熟悉一些常见的地理空间数据类型:Shapefile(。shp)和 GeoJSON(。geojson)。
Shapefile 是一种矢量数据格式,主要由一家名为 ESRI 的公司开发和维护。它存储许多重要的地理空间信息,包括拓扑结构、形状几何等。
Shapefile 数据格式
GeoJSON ,与 JSON 类似,除了你与对象相关的典型属性(索引、名称等)之外,还存储几何信息(坐标、投影等)。
在 JSON 对象中添加了“geometry”关键字的 GeoJSON 格式示例
一旦使用 Geopandas 加载了这些数据格式中的任何一个,库将创建一个带有额外的几何图形列的数据帧。
地理数据框架(来源:geopandas.org)
这就是如何导入 Geopandas 库中内置的默认地理数据,我们将在本文和后续文章中使用这些数据。
import geopandas
path_to_data = geopandas.datasets.get_path("nybb")
gdf = geopandas.read_file(path_to_data)
gdf
基本几何属性介绍
现在,我们已经对地理空间数据以及如何使用 Geopandas 导入我们的第一个地理空间数据有了一些概念,让我们执行一些基本的方法来进一步巩固我们的理解。
首先,让我们把行政区的名称作为索引,使我们的探索更容易。
gdf = gdf.set_index("BoroName")
区域
从几何列,我们可以测量面积(如果它们是多边形或多多边形:因为我们不能测量线或点的面积)
gdf["area"] = gdf.areagdf["area"]
>>BoroName
>>Staten Island 1.623822e+09
>>Queens 3.045214e+09
>>Brooklyn 1.937478e+09
>>Manhattan 6.364712e+08
>>Bronx 1.186926e+09
>>Name: area, dtype: float64
多边形边界
由于我们的几何图形是多边形或多多边形,我们可以提取出对象的线坐标。比如说,当我们想要测量多边形物体的周长时,这是很有用的。
多边形边界线(来源:维基百科)
gdf['boundary'] = gdf.boundary>>gdf['boundary']
>>BoroName
>>Staten Island MULTILINESTRING ((970217.022 145643.332, 97022...
>>Queens MULTILINESTRING ((1029606.077 156073.814, 1029...
>>Brooklyn MULTILINESTRING ((1021176.479 151374.797, 1021...
>>Manhattan MULTILINESTRING ((981219.056 188655.316, 98094...
>>Bronx MULTILINESTRING ((1012821.806 229228.265, 1012...
>>Name: boundary, dtype: geometry
图心
如果你想找到给定多边形的质心点,你可以如下调用 gdf 属性。
多边形质心(来源:维基百科)
gdf['centroid'] = gdf.centroid>>gdf['centroid']
>>BoroName
>>Staten Island POINT (941639.450 150931.991)
>>Queens POINT (1034578.078 197116.604)
>>Brooklyn POINT (998769.115 174169.761)
>>Manhattan POINT (993336.965 222451.437)
>>Bronx POINT (1021174.790 249937.980)
>>Name: centroid, dtype: geometry
距离
现在我们已经知道了质心的位置,并想找出皇后和其他地方之间的距离,使用 distance()方法可以很容易地做到这一点:
queens_point = gdf['centroid'].iloc[1]
gdf['distance'] = gdf['centroid'].distance(queens_point)
然后,您可以执行许多空间聚合功能来找出平均、最大或最小距离。
gdf['distance'].mean() #To find the mean distance
gdf['distance'].max() #To find the maximum distance
gdf['distance'].min() #To find the minimum distance
结论
就是这样!希望你今天能学到新东西。在下一篇文章中,我们将深入探讨如何可视化这些地理空间数据并从头开始创建。敬请期待!
做订阅我的邮件简讯:https://tinyurl.com/2npw2fnz在这里我定期用通俗易懂的英语和漂亮的可视化总结 AI 研究论文。
欧洲发电的排放强度
数据在循证决策中的作用
“任何可以衡量的东西都是可以改进的。”
T 迈克尔·戴尔的上述引述在几个方面和领域都适用。如果一个指标可以衡量,那么就有可能对其采取行动并加以改进。相比之下,没有衡量的东西是无法提高的。数据在决策中的作用越来越重要,因为数据提供证据,而证据是制定或改革政策的前提。
关于国家能源平衡和排放时间序列的统计数据集在能源和气候政策分析中至关重要。这些数据不仅揭示了历史趋势,还揭示了社会、政治、经济和技术因素如何推动能源消耗和温室气体排放。反过来,这些数据构成了评估一个国家未来排放轨迹以及满足特定气候目标和可持续性目标所需的能源系统转型的基础。
从全球来看,电力部门约占 GHG 排放量的四分之一,是最大的排放部门[1]。然而,电力部门也有可能与运输、供暖和工业等其他最终用途部门相结合。因此,终端使用部门的电气化和电力部门的去碳化被认为是减少 GHG 排放的两项重要措施。意识到这一点,全球几个国家正在从化石燃料发电转向低碳技术,如可再生能源。燃料在发电组合中的份额决定了发电的排放强度,即每生产一单位电力排放多少温室气体。
在这篇文章中,我将展示过去二十年欧洲发电的排放强度趋势,并讨论这一趋势背后的潜在原因。为此,我将使用 Python 的 geopandas 和 matplotlib 库。数据和笔记本都在这个 GitHub 仓库里。我们开始吧!
导入包
我从导入所需的包开始。我使用的 geopandas 版本是 0.8.2。由于我稍后将使用的裁剪功能与旧版本的 geopandas 不兼容。
import pandas as pd
import geopandas
import matplotlib.pyplot as plt
%matplotlib inline
from shapely.geometry import Polygon
import warnings
warnings.filterwarnings(action=”ignore”)
因为我想显示地图,所以我希望我的图形和字体稍微大一点。在这里,我为所有的图设置了图形大小和字体大小。
plt.rcParams[“figure.figsize”]=(12,10)
plt.rcParams[“font.size”]=12
Geopandas 为 matplotlib 库提供了一个高级接口来创建地图。它类似于 pandas 库,只是它由多边形或多多边形形式的特定位置的几何图形组成。首先,我将得到如下世界地图:
world = geopandas.read_file(geopandas.datasets.get_path(‘naturalearth_lowres’))
world.plot()
世界地图
Geoplotting 还允许根据此处的列表将数据重新投影到 CartoPy 提供的任何地图投影中。
fig=geoplot.polyplot(world,projection=geoplot.crs.Orthographic(), figsize=(8, 4))
plt.show()
投影到正交投影的世界地图
从世界地图中获取欧洲地图
接下来,我从世界地图中只选择了欧洲地图。
europe=world[world.continent==”Europe”]
europe.plot()
从世界地图中提取的欧洲地图
上面的欧洲地图还包括俄罗斯和冰岛。基于现有的数据,我想画出一些欧洲国家的排放强度。因此,我将俄国和冰岛排除在欧洲地理数据框架之外,如下所示:
#Remove Russia and Iceland from map of Europe
europe=europe[(europe.name!=”Russia”) & (europe.name!=”Iceland”)]
europe.plot()
不包括俄罗斯和冰岛的欧洲地图
用 Geopandas 裁剪矢量数据
在地图的左下角,有一个南美洲的小区域。这个地区被称为法属圭亚那,行政上属于法国领土。因此,它将作为法国包含在地理数据框架中。但是,由于我要绘制法国(欧洲大陆的一部分)发电的排放强度,所以我想从地图中排除法属圭亚那。
我创建了一个自定义的形状良好的多边形,以便在地图中只包含我想要的欧洲地区。我创建了一个从西经 25°延伸到东经 40°和北纬 35°延伸到北纬 75°的多边形。我将多边形转换为地理数据框架,以便与我在上面创建的欧洲地理数据框架兼容。通过这种方式,我只捕获我想用作地理绘图参考的欧洲地区。
# Create a custom polygon
polygon = Polygon([(-25,35), (40,35), (40,75),(-25,75)])
poly_gdf = geopandas.GeoDataFrame([1], geometry=[polygon], crs=world.crs)fig,ax=plt.subplots()
ax=europe.plot(ax=ax)
poly_gdf.plot(edgecolor=”red”,ax=ax, alpha=0.1)plt.show()
阴影部分表示要使用的区域。非阴影部分表示要剪切掉的区域。
我使用的 geopandas 版本(0.8.2)允许将几何裁剪到多边形几何的边界。这是一个很酷的功能,以前我只能在 GIS 软件中使用。裁剪允许从输入中提取要素。在 geopandas 中进行裁剪就像一行代码一样简单。
#Clip polygon from the map of Europe
europe=geopandas.clip(europe, polygon)
europe.plot()
欧洲地图裁剪后可用。
现在我已经准备好了地图,我想用它来进行地理绘图。下一步我会研究数据。
数据准备
本分析中使用的数据基于 2021 年 12 月,可从我们的世界数据的页面访问。该数据包括 2000 年至 2020 年欧洲发电的碳强度。
#Read csv file
df=pd.read_csv(“carbon-intensity-electricity.csv”)
df
从 csv 文件中读取数据
数据框由名为“国家实体”的列组成。接下来,我检查在 df 数据框架和欧洲地理数据框架中列出的国家。
检查组成 df 和欧洲的国家名单和数量
我看到欧洲的国家比德国多。从 df,我只保留了同时出现在欧洲的国家。我还在 df 中只保留了 2000 年、2005 年、2010 年、2015 年和 2020 年的值,我想把它们可视化。我还将 df 转换为数据透视表,然后使用国家名称作为索引,五年作为列,转换为数据框架。
处理后的数据帧
接下来,我创建了另一个名为 selected_countries 的地理数据框架,作为 europe 的子集,它只包含 df 中的国家。我将来自 df 的排放强度值合并到选定国家中。
selected_countries=europe[europe.name.isin(list(df.name))]
selected_countries=selected_countries.merge(df,on=”name”,how=”left”)
将它们放在一起
我的目标是设想从 2000 年到 2020 年每五年欧洲发电的排放强度。为了在所有年份的地图上有一个统一的颜色范围,我选择所有年份和所有国家的最小和最大排放强度值作为变量的范围。
#Range of Variable you see as map color. Here I select the minimum and maximum of all the years selected.vmin=selected_countries[[“2000”,”2005",”2010",”2015",”2020"]].min().min()
vmax=selected_countries[[“2000”,”2005",”2010",”2015",”2020"]].max().max()
我在两行三列中创建了六个支线剧情,五个剧情对应五个不同的年份,第六个是一个空画布,上面画着一个问号,表示未来会怎样。组合地图的标题被指定,并且行之间的间距也被调整。
对于每个支线剧情,我用白烟色的欧洲地理数据框作为画布。在这个画布上,我绘制了特定年份的排放强度值,这些值来自 selected_countries 地理数据框架,颜色图(cmap)设置为“红色”。地图颜色的变量范围对所有支线剧情都是一样的。
增加了一个共同的颜色条,因为所有支线剧情的范围都是一样的。颜色条(cax)将被绘制到的轴是由我自己定义的。matplotlib . cm . scalar maptable()参数通过定义颜色图(此处为 cmap = " Reds ")并将变量的归一化范围取为[0.0,1.0]区间来描述颜色条。
#Create subplots with 2 rows and 3 columns
fig,axs=plt.subplots(2,3)
fig.suptitle(“Emissions Intensity from electricity generation in Europe 2000–2020”, fontweight=”bold”,fontsize=15)#Adjust space betweeen rows
plt.subplots_adjust(bottom=0.2, top=0.9, hspace=0.25)axs[0,0]=europe.plot(color=”whitesmoke”,edgecolor=”black”,ax=axs[0,0])
selected_countries.plot(“2000”,cmap=”Reds”,edgecolor=”black”,ax=axs[0,0], vmin=vmin, vmax=vmax)
axs[0,0].set_title(“2000”)
axs[0,0].xaxis.set_visible(False)axs[0,1]=europe.plot(color=”whitesmoke”,edgecolor=”black”,ax=axs[0,1])
selected_countries.plot(“2005”,cmap=”Reds”,edgecolor=”black”,ax=axs[0,1], vmin=vmin, vmax=vmax)
axs[0,1].set_title(“2005”)
axs[0,1].xaxis.set_visible(False)
axs[0,1].yaxis.set_visible(False)axs[0,2]=europe.plot(color=”whitesmoke”,edgecolor=”black”,ax=axs[0,2])
selected_countries.plot(“2010”,cmap=”Reds”,edgecolor=”black”,ax=axs[0,2], vmin=vmin, vmax=vmax)
axs[0,2].set_title(“2010”)
axs[0,2].xaxis.set_visible(False)
axs[0,2].yaxis.set_visible(False)axs[1,0]=europe.plot(color=”whitesmoke”,edgecolor=”black”,ax=axs[1,0])
selected_countries.plot(“2015”,cmap=”Reds”,edgecolor=”black”,ax=axs[1,0], vmin=vmin, vmax=vmax)
axs[1,0].set_title(“2015”)axs[1,1]=europe.plot(color=”whitesmoke”,edgecolor=”black”,ax=axs[1,1])
selected_countries.plot(“2020”,cmap=”Reds”,edgecolor=”black”,ax=axs[1,1], vmin=vmin, vmax=vmax)
axs[1,1].set_title(“2020”)
axs[1,1].yaxis.set_visible(False)axs[1,2]=europe.plot(color=”whitesmoke”,edgecolor=”black”,ax=axs[1,2])
axs[1,2].set_title(“Future?”)
axs[1,2].yaxis.set_visible(False)# add colorbar
cax = fig.add_axes([0.92, 0.2, 0.03, 0.7]) #[left, bottom, width, height]
sm = plt.cm.ScalarMappable(cmap=’Reds’, norm=plt.Normalize(vmin=vmin, vmax=vmax))
# fake up the array of the scalar mappable.
sm._A = []
lgd=fig.colorbar(sm, cax=cax).set_label(“gCO$_2$e/kWh”, rotation=0,y=1.05, labelpad=-35)plt.savefig(“Emissions Intensity over the past two decades.jpeg”,
dpi=300)
plt.show()
结果图如下所示。有六条副曲线,五条副曲线分别代表 2000 年、2005 年、2010 年、2015 年和 2020 年的排放强度,第六条是一个空画布,上面有一个未来可能会发生什么的问号。所有前五个支线剧情都有一个共同的颜色条,其值在 10 到 1100 gCO₂/kWh.之间类似地,一些国家(如挪威、乌克兰、白俄罗斯和瑞士)出现在欧洲地理数据框架中,但这些国家的数据在选定国家中不可用。因此,这些国家的颜色是基于欧洲的白烟,表示空值。如果数据可用,那么使用与上述相同的方法可视化这些国家的排放强度是可行的。
过去二十年欧洲发电排放强度的地理绘图
评估排放强度趋势和 2020 年现状
如果仔细观察上面的剧情,可以注意到每五年支线剧情对比的细微变化。例如,如果观察每个支线剧情中的西班牙地图,颜色对比在每隔一个支线剧情中变浅。这意味着在五年的时间间隔内,西班牙发电的排放强度逐渐降低。同样,相对于 2000 年的支线剧情,2020 年的支线剧情要轻很多。这意味着在过去的二十年里,欧洲的排放强度值总体上已经显著下降。
2020 年欧洲发电的排放强度
欧洲各国的排放强度值差异很大。例如,在 2020 年,排放强度值的范围在 10 到 725 gCO₂/kWh 之间,如上图中颜色条的范围所示。根据对 2020 年烈度值的观察,这些国家可分为三类:
- 更高的排放强度:波兰、爱沙尼亚和希腊等国家的排放强度值更高(大于 500 gCO₂/kWh )
- 中等排放强度:英国、德国和荷兰等国家的中等排放强度值在大约 100 到 500 gCO₂/kWh 的范围内
- 较低的排放强度:瑞典、法国和澳大利亚等国家的排放强度值要低得多(小于 100 gCO₂/kWh).
强度值差异的原因可以用这些国家的发电组合来解释。根据国际能源署(IEA)的数据,排放强度较高的国家(波兰、爱沙尼亚和希腊)的发电组合以化石燃料为主,主要是煤,燃烧时会释放更多的 co₂[2]。
可再生能源技术的成本,如太阳能光伏、陆上风能和海上风能,在过去的十年里已经大幅下降[3]。随着支持政策的到位,在英国和德国,可再生能源的份额已经增加到一半左右,取代了煤炭在燃料组合中的地位[2]。从煤炭转向天然气也有助于降低英国的排放量,因为天然气的排放强度低于煤炭。
核能也是一种低碳技术,历史上一直是法国电力的主要来源。目前,法国约四分之三的电力来自核能,其次是水力、风力和天然气[2,4]。这解释了为什么法国的排放强度值较低,大约相当于 2020 年的 55 gCO₂/kWh。最后,水电和核能在瑞典的电力组合中各占近 40%的份额,其次是风能、生物质能和废物[2]。因此,在选定的欧洲国家中,瑞典的发电排放密度最低,约为 10 gCO₂/kWh.
欧洲选定的六个国家排放强度的变化
结论
欧洲电力部门的去碳化是欧洲经济的前沿。过去 20 年来,发电的排放强度有所下降,甚至在新冠肺炎引发经济危机之前,这一下降速度就已经明显加快。可再生能源支持机制的引入和成员国逐步淘汰化石燃料发电的决定是排放和排放强度趋势的主要驱动因素[5]。
通过结合 Python 中不同包的优势来分析数据,可以产生各种有用的见解。在本文中,geopandas 和 matplotlib 软件包被用来可视化欧洲发电排放强度的趋势。然而,该方法也可用于在不同国家和地区的地图上显示不同的指标。
正如我在本文开头提到的,数据提供证据。利用适当的工具和技术,以正确的方式评估数据,对于从数据中获得洞察力至关重要,这可以成为循证决策的基石。
参考文献
[1]联合国环境规划署,排放差距报告(2020 年)。【2020 年排放差距报告| UNEP —联合国环境规划署
[2]国际能源机构,《数据和统计》(2021 年)。数据&统计— IEA
[3]国际可再生能源机构,2019 年可再生能源发电成本(2020)。【irena.org 2019 年可再生能源发电成本
[4]世界核协会,《法国的核电》(2021 年)。【法国 法国核能|法国核能—世界核协会(world-nuclear.org)
[5]气候分析,欧盟电力部门的脱碳途径:政策框架、主要驱动因素、案例研究和情景分析:与巴黎协定(2020 年)保持一致的经验教训。sgccc _ ca _ report _ eu _ power _ sector-2020–11–30 . pdf(climateanalytics.org)
佐治亚理工学院 OMSA 分校 vs 德克萨斯大学 MS 数据科学
两个顶尖的以数据为中心的研究生院项目的比较。
介绍
在一个有无限选择的世界里,选择合适的研究生院来为你的数据专业人员职业生涯做准备可能会令人瘫痪。虽然读研并不是每个人的最佳选择,但它是一条值得许多人考虑的道路。在为大数据时代做准备的技术学位领域,这两个硕士项目在众多选项中脱颖而出。我选择双击这两个项目有三个主要原因:学校排名、支付能力和灵活性。
原因 1:学校排名
虽然学校排名不是选择学校的最重要因素,但它确实为更严格的项目提供了保证。接受挑战和学习技能对于在科技行业长期发展非常重要。不太严谨的学位会让你远离技术性更强的职位,也不会让你为面试做好充分准备。技术职位经常在面试中测试你的技能,尤其是在更理想的公司。
排名较高的学校更有可能聘请各自领域的专家担任教授,并拥有更强大的同行群体。你的同学越聪明、越有抱负,你从这个项目中学到的就越多。根据你的来源,这两个项目通常都排在美国计算机科学系的前 20 名。《美国新闻》将佐治亚理工学院和德克萨斯大学分别列为最佳计算机科学(CS)学校的第八名和第十名。
原因 2:负担能力
绝大多数为你成为数据专家做准备的研究生课程都非常昂贵,尤其是如果你专注于排名更高的课程。KDnuggets,一个受欢迎的技术资料来源,发布了两个奇妙的可视化结果,通过 CS 排名和成本总结了顶级程序。这些顶级项目的平均学费约为 40,000 美元。你会注意到佐治亚理工学院 OMSA 项目以 9900 美元的价格脱颖而出,成为最实惠的选择之一。因为德克萨斯大学 MS 数据科学项目刚刚在 2021 年初开始,所以它没有出现在这些可视化上。然而,我可以想象他们会被安排在佐治亚理工学院附近,因为他们的学费只有 10,000 美元。
KDnuggest Viz #1: 2019 年数据科学和分析最佳硕士——在线
KDnuggest Viz #2: 分析、商业分析、数据科学领域的顶级在线大师——更新
原因 3:灵活性
在线教育的浪潮使得学习任何东西都变得容易得多,只要你有互联网连接。这两个程序都有在线选项。这为个人选择其地理区域之外的学校提供了灵活性,并使您更容易调整您的时间表,因为您可以异步工作。
来源: Unsplash
课程结构
许多数据专业人员的招聘信息会将技术学位和技能与不顾后果的放弃放在一起。未来的学生负担不起(双关语)以同样的方式处理他们的决策过程。深入到这两个项目中,他们正在为学生准备略有不同的职业道路选择。
正如我之前在另一篇文章中所述,佐治亚理工学院 OMSA 项目是“跨学科”的,侧重于分析领域的广度。必修课程涵盖广泛的主题,包括金融、会计、面向对象编程、数据分析、机器学习、统计学、web 开发、云计算、数据清理、脚本语言和数据可视化。他们的“专业”更多的是为了展示,而不是他们之间的实际差异,因为他们只占该计划的 6/36 学分。因为这个项目涉及如此多的主题,机会成本就变成了在任何一个特定主题上缺乏深度和专业性。专业化和深度的主要机会来自最后的顶点项目。
OMSA 项目强调分析和数据科学领域的广度,而德州大学数据科学项目则强调深度。整个项目专注于机器学习、算法、统计、数据分析和可视化。他们为个人分析、预测和解释数据做准备。在数据已经在一个已建立的系统(即数据工程、数据产品开发、API 等)中进行工程化之后,这些技能集对于操纵数据和从数据中获取洞察力非常有用。).
这两个项目的课程结构有几个主要区别:
- OMSA 有一个顶点工程,而 UT 没有
- UT 有一门算法课程,涵盖了更基础的计算机科学主题,而 OMSA 的数据分析计算入门课程更侧重于操纵数据
- UT 在构建预测模型方面更深入
- OMSA 包括更多的数据工程科目和课程(例如,大数据技术、云、数据库模型)
- OMSA 将更多的商业课程列为必修课
职业道路
随着更多的课程和专业化,OMSA 计划为数据专业人员提供了更广泛的职业道路。因为每个人都有不同的背景,所以很难推断你一毕业就能胜任哪些职位。然而,如果你用 OMSA 计划增强你目前的技能,它会让你走上追求最数据职业生涯的正轨。在我看来,一个拥有 OMSA 学位和零年工作经验的毕业生,符合你典型的寻找 3-5 年工作经验的分析职位的要求。示例包括数据分析师、高级数据分析师、商业智能工程师、初级数据科学家和数据科学助理。如果你用自己的经验增加学位,那么你可以很容易地胜任更高级别的职位,如数据科学家、分析经理或数据产品经理。然而,大多数毕业生将而不是有资格获得更专业的数据科学、人工智能或数据工程职位(例如,应用科学家、机器学习研究员、数据工程师、机器学习工程师)。总的来说,做好计划的学生可以稍微修改计划,以便更加重视大多数数据专业职业道路。
通过 UT 数据科学计划,他们为您准备了更专业的数据科学职业道路。由于更加强调预测建模,它们将把你引向任何不需要博士学位的数据科学职业的正确轨道。这些职业将强调建立、优化和解释机器学习和统计模型。一些例子包括高级分析师、数据科学家、应用科学家、机器学习研究人员、决策科学家和统计学家。该计划没有为更多强调业务/领域知识或数据工程的大多数职业做好充分准备(例如,商业智能工程师、分析经理、数据产品经理、数据工程师)。
其他因素
显然,上面的讨论并没有解决你对这两个项目的利弊清单上的所有问题。在做出决定之前,还有一些问题需要考虑:
- 存在更长的时间会给 OMSA 带来优势吗,因为他们这些年来一直在进步?
- 如果你经常在 OMSA 的商业、统计和编程之间转换,科目的广度会不会让你更难学习材料?如果每学期只上一门课,情况会更糟。
- 你更喜欢职业选择上的灵活性(如 OMSA)还是认为专业化(如 UT)会让你在招聘过程中更有优势?
- 您更喜欢亚特兰大或奥斯汀地区的强大网络?
- 通过顶点项目深入研究特定问题有多重要?
- 哪些数据专业职业在 3-5 年内会有更高的需求?
快速警告
在你因为这两个项目价格低廉而选择其中一个之前,你确实需要考虑潜在的不利因素。更低的成本通常意味着更高的师生比。这意味着教学质量可能比那些能负担得起雇佣更多资源的项目更差。如果 UT 数据科学项目类似于我在 OMSA 的经历,那么你的大部分学习将是自学的。你主要是为学习环境的结构和学位买单。
来源; Unsplash
建议
- 我们无法预测数据科学和分析的未来会如何发展;然而,在可预见的未来,理解如何操作和解释数据可能是一项有用的技能。这两个项目都将为数据专业人员打开新的机会之门。如果你一直有统计学的诀窍,喜欢建立预测模型,不喜欢分析的“商业方面”,那么 UT 数据科学课程可能是更好的选择。然而,如果你更喜欢更好地理解分析和数据科学的广阔前景,并希望在职业选择上更加多样化,那么 OMSA 计划就是你的选择。作为一名数据专业人员,我完全知道我只是做了大量的假设,并将我的 n=1 经验推广给其他人。我的建议不会对每个人都完美,但对大多数人来说方向是正确的。如果你对你的职业有任何疑问,我的大门永远为你敞开。
- 数据通才
*价格仅包括学费
佐治亚理工学院的 MS 分析程序:我的评论第二部分
来源: Unsplash
在写完我对 OMSA 项目的第一篇评论后,许多未来的和现在的学生联系了我。因为这个项目吸引了来自各种背景的学生,所以提供适用于每个人的建议可能具有挑战性。以下是我收到的一些最常见的问题,以及我试图回答的问题。
OMSA 适合我吗?
如果你阅读他们学位概述页面上的项目描述,他们会用“跨学科”这个词。我认为这是这个项目最完美的词汇选择。本课程涵盖的主题范围来自各种各样的学科。必修课程涵盖金融、会计、面向对象编程、数据分析、机器学习、统计学、web 开发、云计算、数据清理、脚本语言和数据可视化。这个高技术项目的重点是广度而不是深度。如果这听起来有吸引力,那么这可能是你的计划。然而,如果你想成为专家,专攻其中任何一门学科,有比这个项目更好的选择。
虽然这个项目强调广度,但不要低估材料的难度。精通商业、计算机科学和统计学绝非易事。通常情况下,个人会在本课程所涵盖的至少一门学科上苦苦挣扎。如果你担心这个学位的技术难度,我建议你在入学前提高自己的技能,或者考虑其他项目。其他在线定量硕士学位包括数据科学、应用经济学、统计学、计算机科学、商业分析和 MBA:分析集中。大学商学院的分析课程在数学和计算机科学方面可能不太严谨。
我应该选择哪个 OMSA 专业?
完成必修课程后,有 3 个专业可供选择。专业化这个词有点误导,因为这个项目的大部分对每个学生都是一样的。只有 6/36 学分是为该专业定制的;否则,其余的是必需的或由您决定。您可以用以下内容快速总结这三个专业化:
作者图片
虽然难度有点主观,但我想大多数学生都会同意我的评估。计算机科学课程往往需要每周最多的工作时间。
你会推荐特定的课程顺序吗?
这个项目涵盖了这么多不同的学科,要决定合适的上课顺序是很棘手的。在做决定时,有许多可变因素需要考虑。在你制定理想的 2-4 年研究生计划之前,这里有几个问题需要回答。
你一学期可以上多少课?
平均工作量从每周 8-20 小时每 3 学分不等,视课程而定。您需要根据班级期望考虑哪些班级可以配对。你个人的时间投入将不同于平均水平,这取决于你在该领域的技能水平。例如,如果你在统计学方面有很强的背景,那么你可能会承担低于平均水平的统计学课程时间。
每学期开设哪些课程? 夏季学期比秋季和春季学期短。因此,他们只提供进度较快的课程,这是全部课程的一个子集。因为他们跑得更快,每周的平均工作量比平均水平高 20%。
哪些班级最适合在附近上课?
把两个相关的学科拿得很近要容易得多。就我个人而言,在完成《数据分析计算入门》之后,我处于编程技能的巅峰。我希望在这门课结束后,我马上去上最难的计算机科学课程,数据和视觉分析。你应该考虑哪些课程可以很好地作为互补主题。
OMSA 项目值得吗?
为了确定价值,你需要估计项目的成本和完成项目的预期回报。该计划的货币成本为 13,000 美元*,但完成该计划的人工成本为 2,160 小时**。就可比的研究生学位而言,这个项目的学费是最低的。然而,如果你认为证书主义在社会中的价值正在减弱,有更便宜的选择来学习这种材料(例如 Coursera 、免费在线资源等)。).如果学费不是你关心的问题,时间投入应该是。如前所述,该计划是关于分析空间的广度,而不是深度。如果你希望成为分析子集的专家,比如实验、人工智能或数据工程,那么你的时间最好花在其他地方。
图片作者:ROI =利润/(人工+学费)
从回报的角度来看,该项目主要提供两样东西:一个结构化的学习环境,以及至少一个入门级的数据分析职位。该计划提供了一个深思熟虑的教学大纲,由各自领域的专家教授大多数课程。作业是有组织的,通常会有自动评分系统,以便及时反馈。该环境包括多种沟通模式,以寻求任务方面的帮助,包括 Piazza 、Slack 和办公时间会议。通读 Piazza 上的几十个帖子来寻找解决某个特定问题的提示可能有点混乱。这是关于他们在多大程度上促进了你的学习。你会注意到我没有在上面任何地方提到讲座。它们可能被击中,也可能未击中,这取决于课程。许多讲座的水平如此之高,你最好完全跳过它们。一些讲座或作业会包含有用的链接;然而,你的大部分学习是在 GT 环境之外通过你自己的研究(又名谷歌搜索)进行的。从回报的角度来看,你从这个项目中获得的知识很大程度上取决于你对学习材料的投入,而不仅仅是获得一个学位。
转到大多数人参加研究生项目的主要原因,工作机会。我不需要重申数据分析技能非常受欢迎。随着每个行业对技术的依赖越来越大,我看不到计算机科学和统计技能没有市场的未来。人工智能只会增加我们对这些技能的依赖,因为每个自动化过程都需要安装和持续维护。因为有这么多类型的人报名参加这个项目,所以很难说这个学位能在多大程度上帮助你找到你想要的工作。在我看来,一个拥有 OMSA 学位和零年工作经验的毕业生,符合你典型的寻找 3-5 年工作经验的分析职位的要求。示例包括数据分析师、高级数据分析师、商业智能工程师、初级数据科学家和数据科学助理。然而,如果你想在一家顶级公司获得这些职位中的一个或更高级的分析职位,你需要用额外的工作经验或个人项目来增加学位。
增加相当于额外 3-5 年的数据分析经验是否值得这个项目的成本,取决于您自己。我认为这个项目对那些至少符合以下标准之一的人来说是最有价值的:
- 一位有一定定量/编程背景的经验丰富的专业人士,希望将职业生涯转向数据分析
- 一位经验丰富的分析专业人士,希望将自己的职业发展提升 3-5 年
- 需要结构来促进学习的学生
- 不怕需要坚持的复杂问题的学生
- 不想专攻特定数据分析或数据科学学科(如人工智能、机器学习工程、数据工程、数据可视化等)的有经验的专业人士。)
(每学分 275 小时 36 学分)+((每学期 194 + 107 费用)* 9 学期)
**(每 3 学分每周 12 小时每学期 15 周) (36/3 三学分块)
我该如何准备这个节目?
如果你决定申请并参加这个项目,你需要确认你已经准备好了材料。入学要求在为学生准备这个项目方面是次优的。为了在这个项目中取得成功,我建议在数据分析、数学和计算机科学方面拥有一定的经验。
你应该熟悉的数据分析主题和工具:
- 结构化查询语言
- 擅长
- 数据可视化
- 数据清理
- 数据分析
在数学方面,你应该熟悉以下内容:
- 微积分-积分,导数,函数,极限
- 统计学—假设检验、p 值、置信区间、抽样
- 概率分布,误差
- 线性代数-矩阵,矩阵运算,向量,方程组
至于计算机科学,你应该在这个项目之前完成相当于两门严格的本科计算机科学课程。严格意味着他们要求每 3 学分每周 10 小时以上。你需要成为至少一门面向对象编程语言的中级程序员。这包括调试和诊断代码中的问题的经验。熟悉 web 开发也会有所帮助。最重要的是,你需要一个永不满足的胃口来解决困难的问题,这些问题很少在第一次尝试中就能解决。
重新评估城市结构的地理空间分析
利用 Geohash 和数据科学模型解决当前城市结构导致的交通拥堵和空间不平等问题
图片来自Unsplash.com
背景
在当今的科技时代,位置数据对一些科技公司的业务运营至关重要。通过使用户能够将他们的设备位置与公司的平台联系起来,数据团队可以使用可用数据构建模型和洞察报告。这种情况可以是基于位置需求的价格设置或按城市的可视化销售覆盖。在处理这些数据时,我不禁想象出商业之外的潜在用例。作为一名城市爱好者,想到的第一个用例是为解决城市地区的交通拥堵和空间不平等提供见解。
交通拥堵会产生如此高的社会经济和环境成本,从降低劳动生产率到增加碳排放。对于雅加达这样的城市,每年交通拥堵的成本高达 45 亿美元(Roberts,2019)。这也值得全球关注,因为它加剧了气候变化。空间不平等可以定义为优质公共产品和服务的不平等分配,如交通、医疗和教育。在城市地区,它导致生活质量的差异,犯罪率上升,城市人口的总体幸福指数较低(Glaeser 等人,2009 年)。
仔细观察,交通拥堵和空间不平等都是城市结构、土地使用安排和连接程度的结果。缺乏交通便利性、主干道、靠近工作地点和便利设施将迫使居民使用私人车辆进行长途通勤。与此同时,那些没有私人车辆的人将很难进入这些地方,从而减少了他们创收的机会。一些家庭可能会因为距离近而搬到经济活跃地区的非正规住区。这是不平等的一个例子。
根据上一段陈述的问题,我定义了两个基本解决方案:改善服务水平低下的社区的可及性增加城市便利设施的分布。当前的技术可以用来为当地决策者提供见解,以确定每个地区的正确解决方案。这些见解不仅可以显示这些地区的迫切需求,还可以用来制定资助计划。****
在这篇文章中,我将讨论地理空间分析的使用,特别是 geohash,以获得改善城市结构的见解和建议。在进入技术细节之前,我们首先需要在经济活动方面接受跨地区的相互依赖。
城市经济中的结构性相互依赖
为了确定地理空间分析模型,我们需要了解城市经济是如何运作的。根据 Hewings (2021),城市经济的特点通常是对一组地区或区域的粗略了解。然而,更深入地看,各区域之间有很强的相互依赖性。对芝加哥大都市的详细分析显示了商品和服务、人员流动(通勤者)和家庭支出流动(购物)方面的强大贸易关系。这揭示了地区之间在收入分配和消费支出方面的互惠经济效应。
潘等人(2018)的早期研究重新评估了城市结构和土地利用模式,以芝加哥为例,分别使用胡佛数据目录、美国人口普查、和道路密度地图的数据,基于就业、人口、指示名胜(poi)的评论和可达性吸引力。一个关键的发现是,居民被吸引到具有高可达性和“生活质量”便利设施或名胜古迹的地方。这显示了到中央商务区(CBD)模型的距离的偏差,这是吸引力的主要衡量标准。其他发现表明,新企业更喜欢在 CBD 内远离现有竞争对手的位置,创造新的就业中心。我从这篇文章中得到的主要结论是:便利设施的可达性和空间分布是住宅区的重要元素。前者使居民能够获得创收和/或就业机会,而后者表明生活质量。Hewings 的方法可以用作地理空间分析项目的框架,这将在下一节中讨论。
地理空间分析的应用
Hewings 的研究启发我看一眼印度尼西亚万隆的建筑,我大半生都在这个城市度过。像东南亚大多数主要城市一样,万隆有着浓厚的购物中心文化。购物中心可以被视为主要的休闲设施或兴趣点,其位置反映了该地区的发展水平。其商业活动的密度产生了大量的就业机会。因此,商场的分布可以被认为是空间公平的一个指标。为了得到一个大概的了解,我简单地在谷歌地图上搜索了“万隆的购物中心”。从下图中,我们可以看到所有的商场都位于城市的西侧。此外,我们可以看到,只有两条主要道路将这些地区连接到东侧(用红框标出),其中大部分是住宅区。这是一个明确的指标,表明城市目前的结构已经产生了拥挤和空间不平等的问题。从个人经验来看,这些道路以及通往商场的道路在上下班高峰期和周末都非常拥堵。通过观察也可以看出东西方整体繁荣程度的反差。万隆政府确实在寻求将其单核结构转变为双核结构,因此地理空间分析可能会大有用处。
印度尼西亚万隆的商场分布(图片由作者提供,由谷歌地图生成)
为了构建更强大的分析,可以使用 GIS 工具来显示高峰时段的道路拥堵情况。相关数据可以从众包平台、谷歌地球图像或其他可用的政府数据中提取。为了捕捉不平等指标,从卫星图像生成的夜灯数据集目前正被用于经济发展分析。夜灯的密度表明更高的经济活动,因为它是实时的,用户也可以分析运动来表明增长。后者将有助于衡量政策干预的成功。
从理论上讲,这是城市规划者面临的一个普遍问题,因为东区通常被用作制造区,以减轻气流引起的烟雾运动。由于发展和结构转型之间缺乏同步性,再加上人口增加,像东万隆这样的地区没有足够的基础设施来为居民提供无障碍环境和吸引企业。为了确定克服这一问题的正确行动,地方政府和发展实践者可以利用地理空间分析工具在社区层面产生洞察力。
使用 Geohash 作为分析的主要维度
我发现一个非常有用的工具是 geohash,它将一个位置坐标(经度和纬度)定位到一个矩形单元中,该单元用一个简短的字母数字字符串表示。geohash 的大小可以很容易地从 1 到 12 的精度级别进行调整,换句话说,更多的字符会生成更低的地理级别。当在地图上可视化时,geohashes 形成一个网格,便于用户获得洞察力(明尼阿波利斯的例子可以在这个链接中找到)。我最常用的级别是 7 和 6,可以分别定义为街区和子区。这些地理哈希的样本可以在下面的图片中找到。这些是通过将特定的位置坐标(我指的是万隆的一个受欢迎的购物中心)输入到活字字体网站生成的。这个网站有助于检查 geohash 覆盖率,它还提供了 JavaScript 源代码,也可以在 Github 上找到。SQL servers 上还有用于转换经度和纬度数据的内置函数,这使我们能够在数据转换后编写简单的聚合查询。
Geohash 7 网格示例(图片由作者提供,由可移动字体脚本生成)
Geohash 6 网格的示例(图片由作者提供,由可移动字体脚本生成)
由于 geohash 是一种显示位置的便捷方式,因此可用作分析城市结构中可达性和空间分布的主要维度。Geohash7 可用于可访问性是所有邻域的重要要求。对于空间分布,geohash 6 将更适合,因为便利设施/兴趣点和其他就业中心可以服务于更广泛的居民。
geohash 的局限性在于,由于其格网形式,它不能根据行政区域的大小进行定制。根据人口密度的不同,区、县或自治市的大小也不同。对于某些行政办公室所需的更精确的分析,GeoPandas 将是一个更可行的工具。这个数据科学库使用从点和多边形派生的几何列。位置坐标,经度-纬度,可以转换成这种几何数据格式。在此链接中可以找到显示俄亥俄州哥伦布市犯罪率热图的用例示例。
易接近
无障碍的主要促成因素是道路和公共交通基础设施。作为城市网络的主干,社区与主要道路和公共交通节点的良好连接至关重要。要分析公共交通覆盖的充分性,我们只需向包含每个公交车站和火车站的经度和纬度的数据集中添加一个 geohash 列。这通常可以在当地交通部门的数据库或档案中找到。从这里,我们可以生成一个地图,显示每个 geohash 网格中的公交车站的可用性。为了确定为没有公交车站的格网提供服务的紧迫性,我们可以像 Hewings 等人所做的那样,将 geohash 列与人口普查数据中的人口数据集连接起来。Python 库(如 polygon-geohasher)可用于创建可视化。这种方法可应用于道路基础设施,即获取格网到主干道坐标的距离。
对于许多城市,尤其是发展中城市,基础设施不足对利益相关者来说可能已经很明显了。主要挑战是缺乏提供所需基础设施的资金,因为大多数地方政府的财政能力有限。基础设施项目不仅需要高额的建设、运营和维护成本,而且还要承受征地成本。为了提供一种替代解决方案,一种越来越广泛用于这种情况的机制是土地价值捕获(LVC)。这基本上是一种为交通基础设施融资的方法,通过获取因可达性提高而产生的土地附加值(Medda,2012)。只有受益人(居民或私人开发商)以改善税或开发费的形式预付款项,才能享受基础设施项目创造的无障碍环境。
机器学习算法可以用来计算潜在的提升。第一步是通过导入土地价值数据库在 Python 笔记本中创建数据框,该数据库通常用于税收计算。在这里,我们可以使用线性回归建立一个预测模型,根据基础设施类别,将到主要道路和/或公共交通节点的距离作为主要属性。为了预测计划项目的价值提升,我们可以创建一个模拟列,假设它当前存在。结果将揭示项目周围地质散列中的预期平均土地价值。另一种方法是使用包含最近基础设施项目前后的值的历史数据。将周边地区作为处理组,其他地区作为对照组,我们可以进行因果影响分析,以计算项目实施后的土地价值提升。
算法的结果将成为创建基于税收的价值获取方案的有用参考。这通常被称为改善税,已在波哥大实施。土地所有者根据出售或开发时的土地收益支付税款。所得资金将用于基础设施投资。另一个机制是土地整合,这在日本很受欢迎,土地所有者愿意牺牲部分土地来改善道路,以获得更好的可达性。这些计划的主要挑战是让土地所有者相信经济增长,因为它还不具体,而且往往仅限于那些有兴趣出售其财产的人。另一种方案是基于开发的,与下一节讨论的兴趣点的空间分布相关。
便利设施的空间分布
随着通过移动设备进行的社交媒体签到、评论和 GPS 导航数量的增加,有大量的数据与这个问题相关。我们可以看到,Hewings 等人可以利用 yelp.com 评论数据来衡量吸引力,我可以简单地搜索谷歌地图来获得商场分布的大致概况。便利设施不仅限于商场和餐厅,还包括公共场所、生鲜市场和诊所/医疗保健中心(这是当今的重中之重)。上述平台可以对一个地区的吸引力产生高质量的见解,例如过去两周 Instagram 上整体入住率最高的地区。另一个有趣的数据集将包含谷歌地图上的热门目的地,其中包括用户的起点。这些信息将有助于城市规划者确定吸引商业和通勤活动的区域。后者还可以揭示由不均匀的空间分布造成的拥挤。然而,这里的主要障碍是这些数据集大部分都不公开。一种可以使用的技术是抓取,从可访问的网站中提取数据。谷歌地图将是这种情况下的一个很好的平台,因为它有各种类别的评级数据。
为了开始探索性的数据分析,我们可以提取谷歌地图上每个类别前 500–1000 个地方的经度和纬度。将数据点转换为 geohash 6 后,我们可以使用一个过滤列生成一个热图,按类别显示每个网格的吸引力。该市的人口分布图也有必要作为分析的补充。理想的结果是在城市的不同部分(不包括农业和绿色空间)显示暖色。另一方面,令人担忧的结果将显示大多数暖色网格完全集中在特定区域,与人口分布相矛盾。这将导致在哪里和如何重新开发的问题。
对于第一个问题,可以应用 k-means 聚类模型来了解有吸引力的区域的特征和当前欠发达区域的倾向。换句话说,识别不太吸引人的区域与吸引人的区域具有最高水平的相似性。假设是一个地区的吸引力与主要道路、空气质量、绿色空间和人行道有关。重新开发的潜在地点(当然是以可持续的方式)将具有这些属性,但目前设施/兴趣点的数量较少。为了促进经济活动和增长,政策制定者可以给予企业税收优惠,鼓励他们在这些地方迁移或建立业务。这将吸引私营部门投资于服务不足的地区,并在长期内建立公平。
一个具有挑战性的情况是,如果这些潜在的位置也是有限的或者甚至不存在。另一种选择是简单地选择居住区附近的棕色地带,并使用 k 均值模型的关键属性作为规划框架。这将意味着这些属性,像主要道路和绿地,必须建设。这让我们回到了融资挑战和 LVC。
如前所述,除了讨论的基于税收的计划之外,还有基于发展的低消费量计划。地方政府不用向土地所有者收费,而是可以与私人开发商合作,以开发权作为激励,帮助为再开发项目(包括必要的基础设施)提供资金。简而言之,开发商不能享受来自新地点的收入,除非他们帮助投资基础设施,带来租户和消费者。这种机制已经在伦敦被用来重新开发巴特西地区,这需要地下铁路延伸。可以应用类似于可访问性的机器学习算法,更关注经济活动。结果将有助于吸引与开发商的合作。
结束语
地理空间数据可以通过多种方式进行分析,包括重新评估城市结构。有几个可用的工具可以帮助政策制定者获得关于潜在问题的见解,如缺乏无障碍环境和空间分布不均。还可以使用数据科学模型进一步分析这些见解,以论证解决这些问题的解决方案。
然而,地理空间分析实际上只是一个支持决策者的工具。根本方面在于政策、制度和市场。首先要问的问题是,决策者和市场利益相关者是否有兴趣寻求信息并采取必要的行动。主要的挑战实际上是建立变革的动力和执行行动计划。地理空间分析确实是一个强大的工具,但决定因素是消费数据洞察力的人。
进一步讨论地理空间分析的一个有趣话题是疫情。随着大量的人在家工作和网上购物需求的增加,我一直在想这些模式会在多大程度上改变后疫情时代的城市结构。这只是一个极端事件,事情很快就会恢复正常,还是技术已经证明通勤的需求减少了?地理空间分析可以帮助提供关于社交距离限制前后行为变化的见解,因为它在一些城市已经开始和停止。然而,研究结果也可能偏向于不那么脆弱/谨慎/外向的人群。然而,这样的研究应该持续到疫情之后的几年。
参考
Glaeser,e .,Resseger,m .,Tobio,k .,2009 年。城市不平等。哈佛大学肯尼学院:州和地方政府陶班中心。
赫因斯,G. 2021。可持续性与城市经济。大型网络研讨会!系列#11,印度尼西亚大学
梅达,女,2012 年。交通可达性的土地价值获取融资:综述。运输地理杂志,25 期,第 154–161 页。**
潘,h,迪勒,b,陈,y,海文斯,G. 2018。对城市结构和土地利用模式的重新评估:到 CBD 的距离还是基于网络的?—来自芝加哥的证据。区域科学和城市经济学,70,215–228
罗伯茨,男,吉尔·桑德,女,蒂瓦里,S. 2019。行动起来:实现印度尼西亚的城市潜力。华盛顿 DC:世界银行
地理空间数据文件格式转换(KML、SHP、GeoJSON)
使用这些 JavaScript 实用程序。没有成本。没有安装。没有配额。(包括 HTML 实用程序文件)
在我最初的几个地理空间项目中,我不得不面对的最令人沮丧的障碍之一是缺乏将空间数据集转换为 GeoJSON 格式文件的工具。虽然有诸如在线 GIS/CAD 数据转换器| SHP、KML、KMZ、TAB、CSV、……(mygeodata . cloud)等 GIS 网站,但它们往往会对一天的上传数量加以限制:
作者截图|当我尝试使用在线工具转换空间数据文件时,我会看到一个典型的弹出窗口
另一方面,由于安装诸如 QGIS 之类的桌面应用程序只是为了文件转换(更不用说它会占用大量磁盘空间)是一件麻烦的事情,我决定求助于替代方案,并最终决定创建一个离线 JavaScript 实用工具,将常见的空间文件格式,如 SHP、& GEOJSON 转换为 KML & GEOJSON 可互换。
幸运的是,由于 npm 站点上的几个节点模块已经有了我所寻求的功能,我所要做的就是用 browserify 将这些 npm 包转换成普通的 VanillaJS。本质上,browersify 将节点模块的所有 JavaScript 依赖项捆绑到一个基于浏览器的 JavaScript 客户端库中,从而可以轻松导入到任何 HTML 文档中。
注意:对于任何想了解 browserify 的人,请参考下面的文章🙃
https://medium.com/weekly-webtips/import-use-npm-modules-in-the-browser-easily-e70d6c84fc31
然后在不到一个小时的时间里,我终于创建了我自己的离线空间文件转换工具,没有使用限制🤩
作者演示| SHP 文件格式到 GEOSJON 格式的转换。请注意,对于较大的文件,在选择【转换】之前,需要等待加载信号停止
对于希望获得上述内容副本的读者,请随意在我的 GitHub 下载该文件(单个 HTML 文件):链接或在这里试用!
关于地图工具为何应保持离线的总体评论
除了能够在有或没有互联网连接的情况下使用这些工具的显著优势之外,另一个要考虑的方面是所用数据集的保密性。无论数据集在本质上是不是空间数据集,数据分析师都有责任在处理信息(如个人居住地址的地理分布,其中可能包含也可能不包含居民的个人详细信息)时保持极度谨慎。因此,这样做的直接后果将是需要限制基于 web 的实用程序用于其数据处理的任何部分。
考虑到通过在线平台处理的任何个人数据都将面临被泄露的风险,这一部分实际上是不言而喻的,但我通过不同的场合认识的许多数据分析师经常忽略这一点。
总而言之,我个人对数据处理的立场是:
虽然 web 上部署了多种多样的数据实用程序,但最好还是小心谨慎地处理数据集。更好的是,离线处理它,以更好地保护您可能忽略的任何机密信息。
非常感谢您阅读这篇文章,希望您发现它对您的使用案例有用。如果您想了解更多地理空间相关内容,请随时关注我的 Medium 。会非常感激😀
https://geek-cc.medium.com/membership
使用闪电和光线调整更好地构建 Pytorch 模型
伊利亚·巴甫洛夫在 Unsplash 上的照片
Pytorch 是领先的深度学习框架之一,因其易用性、丰富的功能和可靠性而在研究和行业中得到广泛应用。
然而,尽管现代深度学习框架在允许快速建立模型方面做得非常好,但仍然需要大量的样板代码。
为了解决这个问题,新的库和框架正在开发中,它们旨在改善开发复杂深度学习模型的整体体验。
我们将讨论其中的两个框架,它们都可以单独与 Pytorch 一起使用,或者组合在一起快速原型化和开发新模型:
- Pytorch-lightning :通过在常规 Pytorch 代码上添加一个抽象层,提供了许多方便的特性,并允许用更少的代码获得相同的结果。
- Ray-tune :超参数调谐库,适用于任何比例的高级调谐策略。
模型开发:Pytorch 闪电
https://www.pytorchlightning.ai/
Pytorch Lightning 是一个旨在通过加快模型开发来增强 Pytorch 的框架。“多花点时间在研究上,少花点时间在工程上”
主要思想是深度学习模型共享大量样板代码,这些代码可能需要大量时间来正确编码和实现。日志记录、检查点、GPU/TPU 支持或分布式训练等功能是与模型无关的,通常会一遍又一遍地重复开发。
该框架提供了大量的功能,但这些好处是有代价的:为了使用该框架,您需要根据给定的结构开发您的模型:
class MyModel(pl.LightningModule):
def__init__(self)
def forward(self, x)
def configure_optimizers(self)
def training_step(self, train_batch, batch_idx)
def training_epoch_end(self, outs)
def validation_step(self, val_batch, batch_idx)
def validation_epoch_end(self, outs)
- 前进:与香草 Pytorch 相同
- 培训/验证步骤:从数据加载器接收输入,执行损失计算,计算指标并记录下来
- 训练/验证时期(可选):接收时期期间所有步骤的输出,以便计算整个时期的度量
- Configure _ optimizers:应该为您的模型返回一个优化器和一个调度器对象
一旦将模型重构到这个新结构中,并将数据打包到 Pytorch 数据加载器中,就可以开始了。
有许多不同的特性旨在使您的生活更轻松,因为框架是有据可查的,我将只列出我一直使用的那些:
- 在 Tensorboard 上自动登录:通过一个简单的函数调用,您可以在 Tensorboard 上记录任何指标并获得可视化效果。
- 分布式训练,GPU/TPU 支持:训练可以通过一个简单的命令行参数在不同的节点上分割,支持 TPU 和 GPU。
- 对多个数据加载器的评估:您可以将您的验证或测试数据分割成多个数据加载器(例如在 NLP 中,每种语言一个数据加载器)并单独评估性能。
- 简单的检查点和早期停止:检查点是通过监控任何记录的指标来创建的。
- 渐变裁剪:为了避免“爆炸式渐变”干扰训练,您可以在训练器上用一个简单的参数裁剪渐变。
- 验证集区间评估:一个简单但强大的技巧,特别是对于较大的数据集,通过在每个时期对验证集进行多次评估,您可以更好地了解模型的性能,并且可以更快地迭代。如果将它与检查点结合使用,它还可以为您提供一个更好的模型。
尽管采用了强制结构,但该框架可以处理复杂的嵌套模型,并且对于多任务和多损失非常适用。已经采取了特别的措施来确保框架对训练几乎没有性能影响,它也非常健壮,到目前为止我还没有遇到任何稳定版本的错误。
一个警告是,根据我的经验,这个框架并没有真正被设计来处理复杂的训练过程,比如在同一个脚本中一个接一个地训练不同的模型。因此,如果您的用例非常奇特,那么检查您的培训过程是否得到支持可能是值得的。
请记住,该框架还很年轻,仍在积极开发中,新功能会定期添加进来。
如果你想自己尝试一下,你可以按照官方文档上的这个教程,它会经过安装和使用框架的第一步。
超参数调整:光线调整
https://docs.ray.io/en/latest/tune/
超参数调整是建立机器学习模型时必不可少的一步。虽然自己做网格搜索或随机搜索很快,但你可能想尝试更复杂的搜索算法(比如贝叶斯优化),这些算法更难编码。
Tune 是一个超参数调整库,它是更大的 Ray 框架的一部分,有助于构建和服务分布式应用。
具体来说, Tune 允许您选择一个 搜索算法 ,该算法将用于选择一组特定的超参数,以在每次迭代中进行测试。可用的算法主要包括:
- 随机搜索/网格搜索
- 贝叶斯/Bandit 优化
- 树 Parzen 估计量(超点)
- 无梯度优化
除了搜索算法,您还可以使用试用调度程序。调度程序从头到尾管理超参数搜索。根据调度程序,它们可以与搜索算法一起使用,也可以完全替代搜索算法。
与只关注于选择一组足够的超参数进行测试的搜索算法不同,调度器将具有元学习策略,并具有及早停止不成功的尝试、暂停、克隆或改变它们的能力。这可以通过提前终止一些试验来加速搜索,并将时间分配给更有希望的试验。
Tune 提供了一些不同的调度程序,但它们基本上是两种技术的变体:
Tune 与各种框架配合良好,为 Pytorch 和 Pytorch-lightning 提供了教程,你可以在他们的图库中找到其他框架的代码示例,如 Keras 。
结论
这两个框架都旨在通过向所有用户提供先进技术,使机器学习模型的开发更快、更方便和更强大。
作为一名软件开发人员,重新发明轮子总是很诱人的,但是如果你追求生产率,你可能更喜欢让一些库做繁重的工作,而把你的精力集中在提供更多价值的部分。
如何使用自动引导方法计算机器学习中性能指标的置信区间
实践教程
您的模型性能度量是因为“大”测试集而非常精确,还是因为“小”或不平衡的测试集而非常不确定?
橙色线显示 89.7%为平衡准确度置信区间的下限,绿色线表示原始观察到的平衡准确度=92.4%(点估计),红色线表示上限为 94.7%。(此图及所有图片均由作者所有,除非另有说明。)
介绍
如果您报告您的分类器在测试集上的性能为准确率=94.8%,F1=92.3%,在不了解测试集的大小和组成的情况下,这没有多大意义。这些性能测量的误差幅度将根据测试集的大小而变化很大,或者,对于不平衡的数据集,主要取决于它包含多少个 minority 类的独立实例(来自过采样的相同实例的更多副本对此没有帮助)。
如果您能够收集另一个类似来源的独立测试集,您的模型在该数据集上的准确性和 F1 不太可能相同,但它们可能有多大的差异呢?与此类似的问题在统计学中被回答为测量的置信区间。
如果我们要从基础人群中抽取许多独立的样本数据集,那么对于这些数据集的 95%,该指标的真实基础人群值将在我们为该特定样本数据集计算的 95%置信区间内。
在本文中,我们将向您展示如何一次计算任意数量的机器学习性能指标的置信区间,使用 bootstrap 方法,自动确定默认情况下要生成多少引导样本数据集。
如果您只想了解如何调用此代码来计算置信区间,请跳到“计算结果一节!“下面下来。
自助方法
如果我们能够从数据的真实分布中提取额外的测试数据集,我们将能够看到跨这些数据集的感兴趣的性能指标的分布。(在绘制这些数据集时,我们不会做任何事情来防止多次绘制相同或相似的实例,尽管这种情况可能很少发生。)
既然我们不能这样做,那么下一个最好的办法就是从这个测试数据集的经验分布中提取额外的数据集,这意味着从它的实例中取样,替换,以生成新的引导样本数据集。替换采样意味着一旦我们绘制了一个特定的实例,我们就把它放回去,这样我们就可以为同一个样本数据集再次绘制它。因此,每个这样的数据集通常具有一些实例的多个副本,并且不包括基本测试集中的所有实例。
如果我们在没有替换的情况下对进行采样,那么我们每次都会简单地得到原始数据集的相同副本,以不同的随机顺序进行洗牌,这将没有任何用处。
用于估计置信区间的百分点 bootstrap 方法如下:
- 生成
*nboots*
“引导样本”数据集,每个数据集的大小与原始测试集相同。每个样本数据集都是通过从测试集中随机抽取实例并替换而获得的。 - 在每个样本数据集上,计算指标并保存。
- 95%的置信区间由指标的
*nboots*
计算值中的第 2.5 个至第 97.5 个百分位给出。如果*nboots*
=1001,并且您对长度为 1001 的序列/数组/列表 X 中的值进行排序,则第 0 个百分位是 X [0】,第 100 个个百分位是 X [1000】,因此置信区间将由 X [25】到X[970]给出**
当然,您可以在步骤 2 中为每个样本数据集计算尽可能多的指标,但是在步骤 3 中,您将分别找到每个指标的百分位数。
数据集和置信区间结果示例
我们将使用上一篇文章中的结果作为例子: 如何处理不平衡的分类,而不重新平衡数据 : 在考虑对倾斜的数据进行过采样之前,尝试调整分类决策阈值 。
在那篇文章中,我们使用了高度-不平衡两类 Kaggle 信用卡欺诈识别数据集。我们选择使用一个与默认的 0.5 阈值完全不同的分类阈值,默认的 0.5 阈值隐含在使用 predict()方法中,使得没有必要平衡数据。这种方法有时被称为阈值移动,其中我们的分类器通过将选择的阈值应用于由 predict _proba ()方法提供的预测类概率来分配类。
我们将把本文(和代码)的范围限制在二进制分类:类 0 和 1,按照惯例,类 1 是“正”类,特别是不平衡数据的少数类,尽管代码也应该适用于回归(单个连续目标)。
生成一个引导样本数据集
虽然我们的置信区间代码可以处理传递给度量函数的各种数量的数据参数,但我们将专注于 sklearn 风格的度量,它总是接受两个数据参数 y_true 和 y_pred,其中 y_pred 将是二进制类预测(0 或 1),或者是连续的类概率或决策函数预测,如果 y_true 也是连续的,甚至是连续的回归预测。以下函数生成单个引导示例数据集。它接受任何 data_args,但是在我们的例子中,这些参数将是ytest
(我们在之前的文章中的实际/真实测试集目标值)和hardpredtst_tuned_thresh
(预测类)。两者都包含 0 和 1,以指示每个实例的真实或预测类。
自定义指标 specificity_score()和效用函数
我们将为特异性定义一个定制的度量函数,这只是召回负类(类 0)的另一个名称。还有一个 calc_metrics 函数,它将一系列感兴趣的指标应用于我们的数据,还有几个实用函数:
在这里,我们列出了度量标准,并将它们应用于数据。我们不认为准确性是一个相关指标,因为假阴性(将真实的欺诈错误分类为合法)比假阳性(将真实的合法错误分类为欺诈)对业务的成本高得多,而准确性认为两种类型的错误分类都是不好的,因此有利于正确分类那些真实类别为多数类别的人,因为这些发生得更频繁,因此对整体准确性的贡献更大。
met=[ metrics.recall_score, specificity_score,
metrics.balanced_accuracy_score
]
calc_metrics(met, ytest, hardpredtst_tuned_thresh)
制作每个启动样本数据集并计算其指标
在 raw_metric_samples()中,我们实际上将逐个生成多个样本数据集,并保存每个数据集的指标:
您给 raw_metric_samples()一个感兴趣的指标(或仅一个指标)列表以及真实和预测的类数据,它获取 nboots 样本数据集并返回一个 dataframe,其中仅包含从每个数据集计算的指标值。通过 _boot_generator(),它在生成器表达式中一次调用一个 _boot(),而不是一次将所有数据集存储为一个潜在的巨大的列表。
查看 7 个启动示例数据集的指标
我们列出度量函数并调用 raw_metric_samples()来获得 7 个样本数据集的结果。为了便于理解,我们在这里调用 raw_metric_samples(),这对于使用下面的 ci_auto()获得置信区间是不必要的,尽管为 ci_auto() 指定一个度量列表(或仅仅一个度量)是必要的。
np.random.seed(13)
raw_metric_samples(met, ytest, hardpredtst_tuned_thresh,
nboots=7).style.format('{:.2%}') #optional #style
上面的每一列都包含从一个引导样本数据集(编号为 0 到 6)计算的指标,因此计算出的指标值会因随机采样而有所不同。
启动数据集的数量,带有计算的默认值
在我们的实现中,默认情况下,引导数据集的数量nboots
将从期望的置信水平(例如 95%)自动计算,以便满足由 North、Curtis 和 Sham 提出的在分布的每个尾部具有最小数量的引导结果的建议。(实际上,该建议适用于p-值,因此假设检验接受区域,但是置信区间与那些将此作为经验法则的区间足够相似。)虽然那些作者推荐尾部最少 10 个引导结果,Davidson&MacKinnon推荐 95%置信度下最少 399 个引导,这需要尾部 11 个引导,所以我们用这个更保守的推荐。
我们指定α为 1**置信水平。例如 95%的置信度变成 0.95,α= 0.05。如果您指定了一个明确的启动次数(也许是一个较小的nboots
,因为您想要更快的结果),但这对于您所请求的 alpha 来说是不够的,那么将会自动选择一个更高的 alpha,以便获得该启动次数的准确置信区间。将使用最少 51 个 boots,因为任何更少的 boots 都只能精确地计算非常小的置信水平(例如 40%的置信度,给出了从第 30 个百分点到第 70 个百分点的区间,其中 40%在区间内,60%在区间外),并且不清楚最小 boots 建议是否考虑了这种情况。****
函数 get_alpha_nboots()设置缺省的 nboots,或者根据上述内容修改所请求的 alpha 和 nboots:
让我们展示不同 alpha 值的默认 nboots:
g = get_alpha_nboots
pd.DataFrame( [ g(0.40), g(0.20, None), g(0.10), g(), g(alpha=0.02),
g(alpha=0.01, nboots=None), g(0.005, nboots=None)
], columns=['alpha', 'default nboots']
).set_index('alpha')
如果我们请求显式 nboots,会发生以下情况:
req=[(0.01,3000), (0.01,401), (0.01,2)]
out=[get_alpha_nboots(*args) for args in req]
mydf = lambda x: pd.DataFrame(x, columns=['alpha', 'nboots'])
pd.concat([mydf(req),mydf(out)],axis=1, keys=('Requested','Using'))
较小的 nboots 值将 alpha 增加到 0.05 和 0.40,nboots=2 被更改为最小值 51。
bootstrap 样本数据集的直方图显示了平衡精度的置信区间
同样,我们不需要通过调用 ci_auto()来获得下面的置信区间。
np.random.seed(13)
metric_boot_histogram\
(metrics.balanced_accuracy_score, ytest, hardpredtst_tuned_thresh)
橙色线显示 89.7%为平衡准确度置信区间的下限,绿色线表示原始观察到的平衡准确度=92.4%(点估计),红色线表示上限为 94.7%。(同样的图片出现在本文的顶部。)
如何计算度量列表的所有置信区间
下面是调用上述内容的主函数,它根据度量结果的百分位数计算置信区间,并将点估计值作为结果输出数据帧的第一列插入。
计算结果!
这就是我们真正需要做的:调用 ci_auto(),如下所示,使用一个度量列表(met
在上面赋值)来获得它们的置信区间。百分比格式是可选的:
np.random.seed(13)
ci_auto( met, ytest, hardpredtst_tuned_thresh
).style.format('{:.2%}')
对结果置信区间的讨论
下面是来自原文的混淆矩阵。类别 0 是阴性(多数类别),类别 1 是阳性(极少数类别)
134/(134+14)的召回率(真阳性率)具有最宽的置信区间,因为这是涉及少量计数的二项式比例。
特异性(真阴性率)为 80,388/(80,388+4,907),涉及多大的计数,因此其置信区间极窄,仅为【94.11%至 94.40%】。
由于平衡的准确性是简单地计算召回率和特异性的平均值,其置信区间的宽度介于两者之间。
由于测试数据的变化和训练数据的变化导致的度量测量不精确
这里,我们没有考虑基于我们的训练数据的随机性的模型中的可变性(尽管这对于某些目的也是有意义的,例如,如果你已经自动重复重新训练,并且想要知道未来模型的性能可能变化多少),而是仅仅考虑由于我们的测试数据的随机性而导致的这个特定模型(从一些特定训练数据创建)的性能测量中的可变性。
如果我们有足够的独立测试数据,我们可以非常精确地测量这个特定模型在底层人群中的性能,并且我们将知道如果部署这个模型,它将如何执行,而不管我们如何构建该模型,以及我们是否可以通过不同的训练样本数据集获得更好或更差的模型。
单个实例的独立性
bootstrap 方法假设您的每个实例(案例、观察结果)都是从基础总体中独立抽取的。如果您的测试集包含多组彼此不独立的行,例如,对同一实体的重复观察可能彼此相关,或者从测试集中的其他实例中过度采样/复制/生成实例,则结果可能无效。您可能需要使用分组采样,在这种情况下,您随机地将整个组集合在一起,而不是单独的行,同时避免分解任何组或只使用其中的一部分。
此外,您还希望确保没有跨训练集和测试集拆分的组,因为这样测试集不一定是独立的,您可能会发现未被发现的过度拟合。例如,如果您使用过采样,您通常应该只在从测试集中分离出来之后进行,而不是之前。通常情况下,您会对训练集而不是测试集进行过采样,因为测试集必须能够代表模型在未来部署时将看到的实例。对于交叉验证,您可能希望使用 scikit-learn 的model_selection.GroupKFold()
。****
结论
您总是可以为您的评估度量计算置信区间,以查看您的测试数据使您能够多精确地测量您的模型的性能。我计划撰写另一篇文章来展示评估概率预测(或置信度得分——与统计置信度无关)的指标的置信区间,即软分类,如 Log Loss 或 ROC AUC,而不是我们在此使用的评估模型对类别的离散选择的指标(硬分类)。同样的代码适用于这两种情况,也适用于回归(预测一个连续的目标变量)——您只需要传递给它一个不同类型的预测(在回归的情况下,传递给它不同类型的真实目标)。
这款 jupyter 笔记本在 github 有:bootconfintautov 1 o _ standalone . ipynb
这篇文章信息丰富和/或有用吗?请张贴回复(语音气泡图标在左下方,黑/白旁边👏如果您对本文或置信区间、引导、引导数、实施、数据集、模型、阈值移动或结果有任何意见或问题。
除了前面提到的前一篇文章之外,您可能还对我的 感兴趣,如何在 Pandas 中读取 CSV 文件时自动检测日期/日期时间列并设置它们的数据类型,尽管它与本文没有直接关系。
get-Git:Git 入门
说得足够快,听起来就像明白了…
多年来,它一直津津乐道于自己作为合作典范的地位。作为一名开发人员,我每天都与 Git 打交道;当事情出错时,犯错误、推遥控器和偶尔扯头发(解释了我的脱发)。最近在思考“Git 实际上是如何工作的?”,我意识到我对这种根深蒂固的软件开发方式知之甚少。不言而喻,如果我知道支配 Git 的结构/功能,那么让我猜测几个小时的许多错误有时是可以避免的。
Git 是软件开发项目的重要组成部分。它提供了,
- 跟踪 — Git 维护一个历史记录,它本质上是你的代码库随时间变化的快照
- 特性隔离——当你开发特性时,你创建了你自己的分支——你没有破坏工作/稳定版本
- 协作——现在,任何数量的开发人员都可以开发不同的功能,开发他们的本地副本,准备好了就推送到一个中央远程存储库
- 同行评审 — Git 有助于同行评审,当开发人员 A 完成特性 X 后,在将它合并到主分支之前,他可以要求开发人员 B 评审它(以拉请求的形式)
在本文中,您将了解到,
- 几个方便的 Git 命令,比如,
git add
,git commit
,git push
,git fetch
,git merge
,git pull
,git checkout
,git reset
。 - 运行这些命令时,您的代码会经历不同的阶段,如工作目录、索引、本地存储库和远程存储库。
最近我在 LinkedIN 上分享了这个工作流程
我不觉得浏览 Git 文档的数百页并被来自四面八方的术语轰炸有什么意思。因此,我创建了一个可视化 Git 备忘单,并在 LinkedIN 上分享。我看到这个 LinkedIn 帖子引起了很多人的兴趣。所以让这成为我在那篇文章中想要传达的更详细的论述。
在您当地的街区游览…
这一切都是从一串位开始的…
是的,但我们不会从那里开始。我们将从您在本地创建的代码存储库开始。现在,这可以使用git init
在我们的本地环境中创建,或者使用git clone <url to git repo>
从远程存储库中克隆。
要了解这些概念,请见见戴夫!Dave 和其他开发人员一样,和你我一样讨厌上午 9 点的会议。他创建了一个代码目录(我们姑且称之为code
),其中有三个文件a.py
、b.txt
和c.py
。
本地代码库称为工作树或 工作目录
Dave 理解 Git 的价值,然后运行git init
。这将为代码库创建一个本地 Git 存储库。您可以在code
文件夹中创建的.git
文件夹中看到这个存储库的组成。通过跟踪 Git 存储库中的代码,他知道何时何地引入了各种变更。
首先,Dave 希望将三个文件a.py
、b.txt
和c.py
添加到他的本地存储库中。这是一个双重过程。他首先呼叫git add a.py b.txt c.py
。这会将这些文件添加到索引(或索引树/缓存/暂存区)中。这是当前代码和本地存储库中的代码之间的过渡空间。换句话说,您的代码还没有被存储库跟踪。把这里想象成剧院的后台。你可以随心所欲地修改(演员、道具、剧本等)。)后台,上台前。
索引是一个空间,您可以在这里准备/存放您需要提交到本地存储库的内容。
一旦您对阶段化的更改感到满意,您就可以通过调用git commit -m <message>
将文件提交到您的存储库中。这将在存储库中记录您当前工作目录的快照(更确切地说是跟踪的文件的快照)。
提交后,代码的当前版本将作为带有时间戳和 ID 的快照记录在本地存储库中
git 添加和 git 提交的效果
在提交期间,您可以使用git status
来查看文件的状态。它将显示已转移、已跟踪但未转移和未跟踪的文件。
太好了,我们完成了第一次提交。但我们才刚刚开始开心起来。假设戴夫对a.py
和b.txt
做了一些改动。然后戴夫决定他只想将a.py
添加到索引中,而不是b.txt
(即执行git add a.py
)。这意味着工作目录中的新版本b.txt
将不会成为索引的一部分。换句话说,在这一轮中,a.py
被跟踪/索引并登台用于提交,b.txt
被跟踪但不登台用于提交。
此外,Dave 认为,c.py
不是很有用,并决定从索引中删除该文件。他可以通过调用git rm c.py
或git rm --cached c.py
来做到这一点。两者的区别在于git rm --cached c.py
从索引中只移除了文件和(并保留了物理副本)。
指数如何变化取决于你做了什么
Git 什么都看得到…
Dave 完成了两次提交,它们被记录在本地存储库中。正如我前面提到的,git 的优势之一是能够跟踪随时间的变化。这意味着本地存储库维护一个历史。历史如下所示。
我们所做的每一次提交都被记录为历史中的单个节点。每个提交都由一个哈希函数生成的唯一 ID 来区分(这是一个字母数字 ID,看起来像47970bc91aa7daec9def3...
)。你从一个单独的分支(master
)开始,随着你开发新的特性,你分叉并创建分支。例如,如果你正在制造一辆汽车,你会有一个名为feature/eject_seats
的分支。但是,一旦你意识到弹射座椅是一个坏主意,你可能会放弃那个分支,回到主分支。然后你开发feature/doors
,一旦特性完成并被测试,你将特性合并到主分支。
从本地到远程…
Dave 非常了解如何维护自己的本地存储库。但是 Git 是关于协作的。Dave 需要与团队的其他成员共享代码库,以及它随时间的变化。为此,您通常需要维护一个中央远程存储库。您可以让 Git 知道远程存储库,
git remote add origin https://github.com/smart-vroom/*car*.git
然后,Dave 将本地存储库中的更改推送到远程存储库中。假设戴夫正在处理默认分支(master
),然后戴夫打电话给git push origin master
。这将把本地存储库中的更改推送到远程存储库中。现在任何开发人员都可以看到 Dave 引入的变化。
图:Git push 将提交给本地存储库的更改推送到远程存储库。本地回购和远程回购有各自的历史
远程存储库是一个中央在线存储库,可供多个合作者查看。远程存储库和本地存储库一样有一个历史记录
约翰是个糟糕的开发人员…
戴夫是团队的一员。换句话说,戴夫对代码有贡献,约翰、安娜和蒂姆也是。开发人员越多,维护远程代码库的问题就越多。例如,约翰没有告诉戴夫,约翰也在为master
分公司工作,并承诺为master
工作,就在戴夫告诉他之前。现在戴夫无法推进远程回购。因为他没有最新版本。Dave 必须回去更新他的本地存储库和工作目录,并解决由于 John 的更新而发生的任何冲突。别担心,Git 也有答案。
现在戴夫将经历三件事
- 戴夫试图
push
,但是出错了,因为他的本地回购没有约翰提交的更新 - Dave 需要更新本地存储库以与远程 repo 同步(
git fetch
)(如下图中橙色所示) - Dave 需要将本地 repo 中的更新更改集成到工作目录中。如果 John 编辑了 Dave 编辑过的文件,这可能会导致合并冲突(
git merge
) - Dave 需要通过手动编辑冲突的文件(下图中以蓝色显示)来解决冲突,这将在下面进一步讨论。
- Dave 转移文件、提交文件并将它们推送到远程位置(下图中以蓝色显示)
解决 Git 冲突
还可以看到一个名为 git pull 的命令。它只是一气呵成地执行git fetch
和git merge
。这意味着git pull
是入侵性的,会修改你的工作目录
git pull = git fetch + git 合并
第三步中发生的事情在图的左边用灰色圈了出来。当您键入git merge
时,如果 John 编辑了一个 Dave 也编辑过的文件,很可能会导致合并冲突。假设约翰和戴夫都编辑过b.txt
。现在b.txt
有一场冲突需要解决。合并冲突后,冲突的文件看起来像来自另一个世界。
冲突后文件的外观
好吧,人们放下你们的喷火器,这很正常。它只是说<<<<<<<HEAD
和======
之间的部分是你在本地回购中拥有的。但是远程回购具有=======
和>>>>>>> AB123CDE
之间的部分(在文件的那些行中)。这里的AB123CDE
是最新的提交 ID。现在戴夫有三个选择:
- 挑选约翰的更新(只保留
yyyy
) - 保留您的更新(仅保留
xxxx
) - 将两者结合起来
取决于戴夫需要什么。但是最后,它必须产生一个有效的文件,没有合并冲突带来的语法上的麻烦。解决冲突后,您可以转移文件,提交它们并将它们推送到远程存储库。唷!好险。希望约翰将来能更多地谈论他的作品!
汽车越来越智能
戴夫的老板想让他开发一个重要的功能(feature/self_drive
),并解释了一切。几个不眠之夜的想法对戴夫来说变得很明显,因为这是一件大事。戴夫也需要一个单独的分支来处理这个功能。因为汽车没有self_drive
依然可以放行。
为此,Dave 用git checkout -b feature/self_drive
创建了一个新分支(-b
告诉 Git 这是一个新分支)。如果分支已经存在,可以做git checkout feature/self_drive
。分支是 git 历史中采用自己路径的提交流。它从一个现有的分支(比如主分支)中分支出来,您可以向它添加一系列提交,而不会影响父分支。然后,一旦您实现了该特性并对其进行了测试,您就可以将它合并回父特性(可以选择解决冲突)。
在 Git 中,分支在回购中维护。你可以通过进入.git/refs/head
目录来查看你去的所有分支。每个分支都有一个文件,只记录该分支的最新提交。
一旦您的本地开发在feature/self_drive
分支上准备就绪,您就可以使用git push origin feature/self_drive
提交远程回购。这将在远程回购中创建一个新分支(如果尚不存在)。
戴夫犯了一个错误…
戴夫回到了master
分部,他一直在研究a.py
上的几个 bug。但是,他掉进了兔子洞,再也出不来了。“让沉没成本谬误见鬼去吧”,他想,“我要用我在回购中最后一次提交的文件来重置我的工作目录”。
戴夫需要做的就是,跑git checkout master -- a.py
。它将使用本地 repo 中的快照a.py
恢复工作目录中的a.py
。如果你认为还有更高版本的a.py
,你可以先做一个git fetch
,然后再做checkout
。
用这些动作打动你的同事
也可以使用git checkout
在分支之间移动。简单说git checkout feature/eject_seats
或者git checkout feature/self_drive
。您也可以使用git checkout <commit ID>
(例如git checkout 47970bc91a
)来检查特定的提交。
如果你用
git checkout
指定一个提交,这意味着你的头和分支引用是不一样的,指向两个东西。这就是所谓的分离头。
另一个有用的命令是git reset
。git 复位有三种模式;
--soft
—影响本地回购(如果您的头处于分离模式,这很有用)--mixed
—影响本地回购和指数--hard
—影响所有本地回购、指数和工作树
比方说,Dave 需要重置索引/暂存区域,以删除他已经暂存的一些更改,但不更改工作目录。他可以用git reset --mixed HEAD
做到这一点。这里的HEAD
指的是你对回购的最新承诺。
这里有一些其他的命令会派上用场
git stash
—如果你想在工作树中暂时保存你的更新git diff
—给出两个文件的区别(如工作树与索引)git rebase
—如果您想要将您的分支的开始更新为您分支后发生的稍后提交,这是要使用的命令git reflog
—显示存储库的历史记录
结论
让我们回顾一下我们所学的内容。我们了解到,
- 为什么 Git 很重要
- 工作目录、索引、本地存储库和远程存储库之间的区别
- 基本命令如
git add
、git commit
、git push
- 解决合并冲突
git fetch
,git merge
- Git 分支及其用途
git checkout
和git reset
改正错误
我希望,如果你阅读了这篇文章,你会发现阅读关于 Git 如何工作的 Git 文档(例如 Git-scm )更加容易。
如果你喜欢我分享的关于数据科学和机器学习的故事,考虑成为会员吧!
https://thushv89.medium.com/membership
通过 Docker 了解 Neo4j 和 Jupyter 实验室
当你可以两个都做的时候,为什么每次只做一个呢?
安托万·佩蒂特维尔在 Unsplash 上拍摄的照片
Docker 为数据科学家(实际上是软件中的每个人)提供了以可复制的方式共享代码的能力。我记得几年前我第一次接触它的时候。我曾经是一个使用老式虚拟桌面的人,这些虚拟桌面很笨重,仅仅凭借其架构就占用了大量内存。我第一次了解 Docker 的那一天,我是如此兴奋,以至于晚上大部分时间都醒着想着它!像一个过圣诞节的孩子一样,我收集了一大堆不同的容器,因为我可以这样做,也因为这让我对我可以在其中开发(玩耍)的所有这些伟大的新环境感到眩晕。
这让我想到了今天。当然,我可以在虚拟环境中做事,但是如果我搞砸了一些重大的事情怎么办?(想想:和 CUDA 驱动之类的乱搞。)我能够搞砸我的本地系统以及下一个人。在一个容器中完成我所有的开发可以防止我造成任何永久性的伤害。(因为你需要多长时间才能把你的 linux 环境设置好就像你喜欢的那样???)此外,我可以轻松地与其他人共享该环境,而不必担心系统和软件包的差异。它只是工作。这对数据科学家来说非常好,因为我们倾向于对 Python 包之类的东西有很多软件依赖。
这篇博客文章将是在 Neo4j 做数据科学系列文章的第一篇。用图形数据进行数据科学真的很有趣,但是我将在以后的博客文章中深入探讨这个问题。作为开始,任何可能跟进这些未来帖子的人都能够拥有和我一样的环境,这真的很有帮助。为此,您可以在 GitHub repo 中找到 Docker 容器的代码。
代码遍历
作为一名图形数据科学家,我需要能够与 Neo4j 数据库以及许多常见的数据科学工具和软件包进行交互,比如 Jupyter 笔记本。理想情况下,我希望 Jupyter 与 Neo4j 交谈时不要太大惊小怪。这就是docker-compose
的用武之地。
让我们来看看回购中的一些文件,我们将使用这些文件来完成这项工作。
首先是一个明显的requirements.txt
文件,它详细说明了基本容器之外的任何附加需求:
请注意,我有两个不同的 python 包,用于与我们将要创建的 Neo4j 数据库进行交互。第一个是官方驱动,第二个是社区写的驱动。挑你最喜欢的。
接下来,我有Dockerfile
,这只是我们在 Jupyter 的朋友推出的标准。它里面有很多很好的公共数据科学包,但是你可以随时通过pip3 list
检查安装的包。你需要的任何不在列表中的东西都应该放到requirements.txt
中。
最后,我们需要获得一个 Neo4j 实例,并在容器的 Neo4j 和 Jupyter 部分之间建立某种网络。所以这里我们要用docker-compose
:
关于这个设置的一些事情。首先,我使用的是 Neo4j 4.2.3,但显然版本号会发生变化,所以你应该考虑使用最新版本(尽管我注意到:latest
并不总是获得绝对的最新版本)。接下来,我们将打开和转发几个端口。Neo4j 浏览器使用 7474,而 7687 是 bolt 连接器,将用于数据库的 python 连接。在第 15 行,我们用密码1234
创建用户neo4j
(比这更有创意!)使用第 16 行中的内容,我们将两个重要的库导入 Neo4j,即 Cypher (APOC)上的 Awesome 程序和图形数据科学(GDS)库。这两者在我们解决数据科学问题时都非常有用。接下来,注意第 18–20 行被注释掉了。GDS 是记忆密集型的。除了默认配置之外,您还需要添加内存。这些值的确切值取决于您的本地系统,因此相应地调整它们,然后取消注释这些行。最后,我们看到我们正在端口 8888 上运行 Jupyter 容器。两个容器都通过neo_net
网络连接在一起,这样它们就可以互相对话。
运行容器
与任何 Docker 容器一样,第一步是构建它。为此,我们从命令行发出通常的命令:
docker-compose build
这将通过和组装整个事情。接下来,我们通过
docker-compose up
这将点燃容器的 Neo4j 和 Jupyter 部分。你会看到许多东西滚动而过,但其中之一将是 Jupyter 的链接,其中包含打开它所需的令牌。点击那个链接应该会在你的浏览器中打开 Jupyter。接下来,我们可以导航到localhost:7474
以进入 Neo4j 浏览器。
现在,我们应该让 Jupyter 和 Neo4j 能够相互通信。为了测试这一点,您可以在notebooks/test_db_connection.ipynb
中运行笔记本。如果运行时没有错误,就可以开始了!现在,您可以在 Jupyter 笔记本中与 Neo4j 进行交互,也可以直接从 Neo4j 网络浏览器中进行交互。
当然,一旦你完成了,你发出命令
docker-compose down
干净利落地关闭容器。不过最棒的是,因为我们已经链接了一些像notebooks/
这样的卷,我们的工作被保存在我们的本地计算机上,并且可以在任何时候再次使用。
敬请关注下一篇博客文章,通过图表了解数据科学之旅!感谢您的阅读!
在您的置信区间中获得更大的信心
什么是引导复制以及如何使用它?
彼得·H 论 Pixabay.com
什么是引导复制?
对于这里的读者来说,bootstrap 采样指的是对给定数据集进行“替换”采样的过程……这是大多数人容易迷失的地方。你取许多样本,建立一个分布来标记你的置信区间。
让我们举一个简单的例子。
大学时代的密码
比方说,你想了解大学里的普通人对加密货币的看法;嗯,你可能无法收集到学校里每个人的回应;可能会发生的是,你会分发一些调查,然后你会得到一些回复,你希望这些回复能代表大众的意见,好的或坏的。
虽然您对回答者的分布有一个清晰的概念,但您希望生成一个更能代表整个学校的实际置信区间。这就是 boostrap 复制的用武之地!
补替抽样法
到目前为止,我们知道自举复制是一种抽样方法。这里的主要思想是,当一个样本被选择时,它可以被反复选择。这用于重新创建可能实际上是由于随机机会的应答类型的随机重现。
每个引导样本被称为一个复制。在这种情况下,我们假设复制 1000 次。
一旦我们有了 1000 个重复或样本,我们现在就有了 1000 个样本平均值。
从这个分布中,我们可以得到实际的置信区间。
假设我们想要 95%的置信区间;我们将通过查看我们的 bootstrap 分布,并将 2.5 的值和 97.5 的值作为我们的区间来得到这个结果。
我们来看一些代码!
library(infer)
replicates <- crypto_opinions %>%
specify(response = opinion, success = "positive") %>%
generate(reps = 1, type = "bootstrap")replicates %>%
summarize(prop_high = mean(response == 'positive')) %>%
pull()
我们使用specify
来隔离我们关心的响应变量以及变量值决定‘成功’的因素。从那里,我们使用generate
来创建我们的第一个引导复制。您还会注意到我们将type
指定为bootstrap
。然后,我们使用汇总和拉取来生成指定级别“正”的比例。
replicates <- crypto_opinions %>%
specify(response = opinion, success = "positive") %>% generate(reps = 1000, type = "bootstrap")%>% calculate(stat = "prop")
类似于前面的代码块,我们已经将重复次数扩展到了 1000 次,现在正在链接calculate
函数。calculate
函数为对应于该复制的每个复制“stat”创建一个带有一个记录的数据帧。
ggplot(replicates, aes(stat)) +
geom_density()
上图显示了每次重复的平均结果的密度图或分布。
从这里开始,它只是一个简单的计算问题,标准偏差,并使用它来确定你的范围的顶部和底部!
Lower_bound <- mean(replicates$stat) - sd(replicates$stat) * 2 upper_bound <- mean(replicates$stat) + sd(replicates$stat) * 2
结论
我希望你喜欢这篇文章,它能为你节省一些时间!请分享什么有用,什么没用!
请随意查看我在 datasciencelessons.com 的其他帖子
祝数据科学快乐!
直接和熊猫获取互动剧情。
实践教程
使用 Pandas 绘图语法直接创建 Plotly 和 Bokeh 绘图的教程
【www.freepik.com 宏矢量制作的 T2 信息图矢量
到目前为止,数据探索是任何数据分析任务中最重要的方面之一。我们使用大量可视化工具执行的初始探测和初步检查,为我们提供了对数据本质的可操作的见解。然而,可视化工具的选择有时比任务本身更复杂。一方面,我们有更容易使用的库,但在显示数据中的复杂关系时却不是很有帮助。此外,还有一些提供交互性,但需要相当长的学习曲线。幸运的是,已经创建了一些开源库,试图有效地解决这一难题。
在本文中,我们将研究两个这样的库,即 pandas_bokeh 和 cufflinks。我们将学习如何用基本的熊猫绘图语法创建 plotly 和 bokeh 图表,我们都很熟悉。由于本文的重点是语法而不是图表类型,我们将把自己限制在五种基本图表上,即折线图、条形图、直方图、散点图和饼图。我们将首先用 pandas 绘图库创建这些图表,然后用 plotly 和 bokeh 重新创建它们,尽管有些扭曲。
目录
- 导入数据集
- 直接和熊猫密谋
- 熊猫的后端——和一起策划。
- 为熊猫绘制后端——用袖扣绘制
- 结论
资料组
我们将使用 NIFTY-50 数据集。NIFTY 50 指数是印度股票市场的基准。数据集在 Kaggle 上公开提供,但我们将使用仅包含四个行业股票价值的数据子集,即银行、制药、IT 和快速消费品。
你可以从这里下载样本数据集。
让我们导入可视化所需的必要库和数据集:
# Importing required modules
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline# Reading in the data
nifty_data = pd.read_csv('NIFTY_data_2020.csv',parse_dates=["Date"],index_col='Date')
nifty_data.head()
由银行、制药、IT 和快速消费品行业的漂亮指数组成的组合数据框架
我们还可以在月底之前对数据进行重新取样/汇总。熊猫图书馆有一个[resample()](https://pandas.pydata.org/docs/reference/api/pandas.Series.resample.html)
功能,可以对时间序列数据进行重新采样。
nifty_data_resample = nifty_data.resample(rule = 'M').mean()
nifty_data_resample
现在我们已经准备好了数据框架,是时候通过不同的图来可视化它们了。
直接和熊猫密谋
让我们从最简单的绘图技术开始——熊猫的绘图功能。为了使用 pandas 绘制一个图形,我们将在 dataframe 上调用.plot()
方法。
语法 : dataframe.plot()
plot
方法只是 matplotlib 的[**plt.plot()**](https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.plot.html#matplotlib.axes.Axes.plot)**.**
的简单包装,我们还可以指定一些附加参数,如下所述:
Some of the important Parameters
--------------------------------
**x** : label or position, default None
Only used if data is a DataFrame.
**y** : label, position or list of label, positions, default None**title**: title to be used for the plot**X and y label:** Name to use for the label on the x-axis and y-axis.**figsize** : specifies the size of the figure object.
**kind** : str
The kind of plot to produce:
- 'line' : line plot (default)
- 'bar' : vertical bar plot
- 'barh' : horizontal bar plot
- 'hist' : histogram
- 'box' : boxplot
- 'kde' : Kernel Density Estimation plot
- 'density' : same as 'kde'
- 'area' : area plot
- 'pie' : pie plot
- 'scatter' : scatter plot
- 'hexbin' : hexbin plot.
有关参数及其用法的完整列表,请参考文档。现在让我们看看创造不同情节的方法。在本文中,我们不会详细解释每个情节。我们将只关注语法,如果你有一些熊猫的经验,这是不言自明的。要详细了解熊猫的故事情节,下面的文章将会很有帮助:
https://neptune.ai/blog/pandas-plot-deep-dive-into-plotting-directly-with-pandas [## 熊猫情节:深入到直接与熊猫密谋
在本文中,我们将了解如何使用 pandas 来探索和可视化您的数据,然后我们将更深入地研究 pandas 的一些高级可视化功能。](https://neptune.ai/blog/pandas-plot-deep-dive-into-plotting-directly-with-pandas)
1.线形图
nifty_data.plot(title='Nifty Index values in 2020',
xlabel = 'Values',
figsize=(10,6);
熊猫绘图的线图
2.散点图
nifty_data.plot(kind='scatter',
x='NIFTY FMCG index',
y='NIFTY Bank index',
title = 'Scatter Plot for NIFTY Index values in 2020',
figsize=(10,6));
熊猫散点图
3.直方图
nifty_data[['NIFTY FMCG index','NIFTY Bank index']].plot(kind='hist',figsize=(9,6), bins=30);
熊猫柱状图
4.条形图
nifty_data_resample.plot(kind='bar',figsize=(10,6));
带熊猫图案的条形图
- 4.1 堆积条形图
nifty_data_resample.plot(kind='barh',figsize=(10,6));
带熊猫图的堆积条形图
5.饼图
nifty_data_resample.index=['Jan','Feb','March','Apr','May','June','July']
nifty_data_resample['NIFTY Bank index'].plot.pie(legend=False, figsize=(10,6),autopct='%.1f');
带有熊猫图案的饼图
这些是一些可以用熊猫的数据框直接创建的图表。然而,这些图表缺乏交互性和缩放、平移等功能。现在,让我们将这些现有图表的语法更改为完全交互式的图表,只需在语法上稍作修改。
熊猫后端-用熊猫绘图。
作者图片
在数据可视化方面,散景库显然脱颖而出。**Pandas-Bokeh为 Pandas 、 GeoPandas 和 Pyspark DataFrames 提供了一个 Bokeh 绘图后端。这个后端向数据帧和系列添加了一个plot_bokeh()
方法。
装置
Pandas-Bokeh 可以通过 pip 或 conda 从 PyPI 安装
*pip install pandas-bokehorconda install -c patrikhlobil pandas-bokeh*
使用
Pandas-Bokeh 库应该在 Pandas、GeoPandas 和/或 Pyspark 之后导入。
*import pandas as pd
import pandas_bokeh*
然后需要定义绘图输出,它可以是以下两者之一:
***pandas_bokeh.output_notebook()**: for embedding plots in Jupyter Notebooks.**pandas_bokeh.output_file(filename):** for exporting plots as HTML.*
语法
现在,熊猫数据框架可以通过dataframe.plot_bokeh()
访问绘图 API。
有关绘图输出的更多详细信息,请参见此处的参考或散景文档。现在让我们画出上一节中画出的所有五种图。我们将使用与上面相同的数据集。
*import pandas as pd
import pandas_bokeh
**pandas_bokeh.output_notebook()***
1.线形图
*nifty_data.plot_bokeh(kind='line') #equivalent to nifty_data.plot_bokeh.line()*
熊猫线条图 _ 散景
2.散点图
*nifty_data.plot_bokeh.scatter(x='NIFTY FMCG index', y='NIFTY Bank index');*
熊猫散点图 _ 散景
3.直方图
*nifty_data[['NIFTY FMCG index','NIFTY Bank index']].plot_bokeh(kind='hist', bins=30);*
熊猫直方图 _ 散景
4.条形图
*nifty_data_resample.plot_bokeh(kind='bar',figsize=(10,6));*
有熊猫的条形图 _ 散景
- 4.1 堆积条形图
*nifty_data_resample.plot_bokeh(kind='barh',stacked=True);*
带熊猫的堆积条形图 _ 散景
5.饼图
*nifty_data_resample.index=['Jan','Feb','March','Apr','May','June','July']
nifty_data_resample.plot_bokeh.pie(y ='NIFTY Bank index')*
熊猫饼图 _ 散景
此外,您还可以在同一个图中创建多个嵌套饼图:
*nifty_data_resample.plot_bokeh.pie()*
带有熊猫 _ 散景的嵌套饼图
本节讲述了我们如何无缝地创建散景图,而无需对 pandas 绘图语法进行任何重大更改。现在我们可以两全其美,而不必学习任何新的格式。
熊猫的神秘后台——用袖扣来描绘。
作者图片
另一个常用的数据可视化库是 Plotly 。使用 plotly,您可以用 Python、R 和 JavaScript 制作交互式图表。从 4.8 版本开始,plotly 为熊猫绘图提供了一个 Plotly Express 驱动的后端,这意味着人们甚至不需要导入 Plotly 来创建 Plotly 般的可视化。
不过这里我要提到的库并不是 plotly express,而是围绕 plotly 的一个独立的第三方包装库,叫做 袖扣 。袖扣的妙处在于更百搭,功能更多,有类似熊猫绘图的 API。这意味着你只需要添加一个.iplot()
方法到 Pandas 数据帧来绘制图表。
装置
在安装袖扣之前,请确保您已经安装了 plotly。阅读本指南获取说明。
*pip install cufflinks*
使用
库有很多有用的例子和笔记本可以开始使用。
*import pandas as pd
import cufflinks as cf
from IPython.display import display,HTML#making all charts public and setting a global theme
cf.set_config_file(sharing='public',theme='white',offline=True)*
仅此而已。我们现在可以用 plotly 的能力和熊猫的轻松来创建可视化。语法上唯一的变化是dataframe.iplot()
。
1.线形图
*nifty_data.iplot(kind='line')*
带袖扣的线图
2.散点图
创建散点图时,需要提到散点图的模式。模式可以是线条、标记、文本或它们的组合。
*nifty_data.iplot(kind='scatter',x='NIFTY FMCG index', y='NIFTY Bank index',**mode='markers'**);*
带袖扣的散点图
3.直方图
*nifty_data[['NIFTY FMCG index','NIFTY Bank index']].iplot(kind='hist', bins=30);*
带袖扣的直方图
4.条形图
*nifty_data_resample.iplot(kind='bar');*
带袖扣的条形图
- 4.1 堆积条形图
*nifty_data_resample.iplot(kind='barh',barmode = 'stack');*
带袖扣的堆积条形图
5.饼图
*nifty_data_resample.index=['Jan','Feb','March','Apr','May','June','July']
nifty_data_resample.reset_index().iplot(kind='pie',labels='index',values='NIFTY Bank index')*
带袖扣的饼图
袖扣库提供了一种在 plotly 中获得 plotly 力量的简单方法。语法上的相似是另一个优势。
结论
散景或情节在传达整个信息方面是自给自足的。基于你的选择和偏好,你可以两者都选,也可以两者都选;主要目的是使可视化更直观,同时更具交互性。阅读完本文后,您应该能够将静态的可视化转换成它们的交互式副本,并使您的分析更上一层楼。
👉有兴趣自己看其他文章。这个 回购 包含了我分类写的所有文章。
进入状态!🐍
塑造和重新塑造 NumPy 和 pandas 对象以避免错误
形状误差是许多学习数据科学的人的祸根。我敢打赌,人们已经放弃了他们的数据科学学习之旅,因为无法将数据整理成机器学习算法所需的形状。
更好地了解如何重塑您的数据将使您不再流泪,节省您的时间,并帮助您成长为一名数据科学家。在本文中,您将看到如何以您需要的方式获取数据。🎉
雅典有许多行和列。资料来源:pixabay.com
正在做
首先,让我们确保使用相似的包版本。让我们用它们通常的别名导入我们需要的库。所有代码都可以在这里获得。
import sys
import numpy as np
import pandas as pd
import sklearn
from sklearn.preprocessing import OneHotEncoder
from sklearn.linear_model import LogisticRegression
如果您没有安装所需的库,请取消对以下单元格的注释并运行它。然后再次运行单元格导入。您可能需要重启您的内核。
# !pip install -U numpy pandas scikit-learn
让我们检查一下我们的软件包版本。
print(f"Python: {sys.version}")
print(f'NumPy: {np.__version__}')
print(f'pandas: {pd.__version__}')
print(f'scikit-learn: {sklearn.__version__}')Python: 3.8.5 (default, Sep 4 2020, 02:22:02)
[Clang 10.0.0 ]
NumPy: 1.19.2
pandas: 1.2.0
scikit-learn: 0.24.0
规模
熊猫数据帧有两个维度:行和列。
让我们用一些飓风数据做一个小小的数据框架。
df_hurricanes = pd.DataFrame(dict(
name=['Zeta', 'Andrew', 'Agnes'],
year=[2020, 1992, 1972 ]
))
df_hurricanes
您可以使用 ndim 属性查看熊猫数据结构的维数。
df_hurricanes.ndim2
一个数据帧既有行又有列,所以它有两个维度。
形状
形状属性显示每个维度中的项目数。检查数据帧的形状会返回一个包含两个整数的元组。第一个是行数,第二个是列数。👍
df_hurricanes.shape(3, 2)
我们有三行两列。酷毙了。😎
大小 属性显示我们有多少单元格。
df_hurricanes.size6
3 * 2 = 6
从 shape 属性中很容易得到维度和大小的数量,所以这是我们要记住和使用的一个属性。🚀
让我们从我们的数据框架制作一个熊猫系列。使用仅方括号语法通过将列名作为字符串传递来选择列。你会得到一系列。
years_series = df_hurricanes['year']
years_series0 2020
1 1992
2 1972
Name: year, dtype: int64type(years_series)pandas.core.series.Series
熊猫系列的外形是什么样子的?我们可以用系列 形状 属性来了解一下。
years_series.shape(3,)
我们有一个只有一个值的元组,即行数。请记住,索引不能算作一列。☝️
如果我们再次只使用方括号会发生什么,除了这次我们传递一个包含单个列名的列表?
years_df = df_hurricanes[['year']]
years_df
type(years_df)pandas.core.frame.DataFrame
我的变量名可能泄露了答案。😉如果你传递一个列名列表,你总是得到一个数据帧。
years_df.shape(3, 1)
拿走:熊猫系列的造型和一栏熊猫数据框的造型是不一样的!数据帧的形状为行乘列,系列的形状为行。这是让人犯错的关键点。
现在我们知道了如何在熊猫身上找到形状,让我们看看如何使用 NumPy。熊猫扩展 NumPy。
列。资料来源:pixabay.com
NumPy
NumPy 的 ndarray 是它的核心数据结构——从现在开始我们就把它称为数组。根据您的目标,有许多方法可以创建 NumPy 数组。点击查看我的主题指南。
让我们从数据帧中创建一个 NumPy 数组,并检查它的形状。
two_d_arr = df_hurricanes.to_numpy()
two_d_arrarray([['Zeta', 2020],
['Andrew', 1992],
['Agnes', 1972]], dtype=object)type(two_d_arr)numpy.ndarraytwo_d_arr.shape(3, 2)
返回的形状与我们使用熊猫时看到的形状相匹配。熊猫和 NumPy 共享一些属性和方法,包括形状属性。
让我们将之前制作的熊猫系列转换成 NumPy 数组,并检查其形状。
one_d_arr = years_series.to_numpy()
one_d_arrarray([2020, 1992, 1972])type(one_d_arr)numpy.ndarrayone_d_arr.shape(3,)
同样,我们在熊猫和熊猫身上看到了同样的结果。酷!
行和列。资料来源:pixabay.com
问题是
当一个对象期望数据以某种形式到达时,事情就变得棘手了。例如,大多数 scikit-learn 变压器和估算器都希望获得二维形式的预测 X 数据。目标变量 y 应该是一维的。让我们用一个愚蠢的例子来演示如何改变形状,在这个例子中,我们使用年来预测飓风名称。
我们将使 x 小写,因为它只有一维。
x = df_hurricanes['year']
x0 2020
1 1992
2 1972
Name: year, dtype: int64type(x)pandas.core.series.Seriesx.shape(3,)
我们的输出变量 y 也是如此。
y = df_hurricanes['name']
y0 Zeta
1 Andrew
2 Agnes
Name: name, dtype: objecttype(y)pandas.core.series.Seriesy.shape(3,)
让我们实例化并拟合一个逻辑回归模型。
lr = LogisticRegression()
lr.fit(x, y)
你会得到一个值错误。最后几行写道:
ValueError: Expected 2D array, got 1D array instead:
array=[2020\. 1992\. 1972.].
Reshape your data either using array.reshape(-1, 1) if your data has a single feature or array.reshape(1, -1) if it contains a single sample.
让我们试着按照错误消息的指示去做:
x.reshape(-1, 1)
如果你通过一个 NumPy 数组,整形是很棒的,但是我们通过了一个 pandas 系列。所以我们得到了另一个错误:
AttributeError: 'Series' object has no attribute 'reshape'
我们可以把我们的系列变成一个 NumPy 数组,然后把它重新做成二维的。然而,正如你在上面看到的,有一种更简单的方法可以让 x 成为 2D 对象。只需使用方括号语法将列作为列表传递。
我将结果设为大写 X ,因为这将是一个 2D 数组——大写字母是 2D 数组(也称为矩阵)的统计命名约定。
我们开始吧!
X = df_hurricanes[['year']]
X
type(X)pandas.core.frame.DataFrameX.shape(3, 1)
现在我们可以准确无误地拟合我们的模型了!😁
lr.fit(X, y)LogisticRegression()
重塑 NumPy 数组
如果我们的数据存储在 1D NumPy 数组中,那么我们可以按照错误消息的建议,用reshape
将它转换成 2D 数组。让我们用之前保存为 1D NumPy 数组的数据来尝试一下。
one_d_arrarray([2020, 1992, 1972])one_d_arr.shape(3,)
让我们重塑它!
hard_coded_arr_shape = one_d_arr.reshape(3, 1)
hard_coded_arr_shapearray([[2020],
[1992],
[1972]])hard_coded_arr_shape.shape(3, 1)
传递一个正整数意味着给出那个维度的形状。所以现在我们的数组有了形状 3,1 。
然而,使用灵活、动态的选项是更好的编码实践。所以还是用 -1 搭配吧。shape() 。
two_d_arr_from_reshape = one_d_arr.reshape(-1, 1)
two_d_arr_from_reshapearray([[2020],
[1992],
[1972]])two_d_arr_from_reshape.shape(3, 1)
让我们解开代码。我们传递了一个 1 ,所以第二维度——列——得到了 1。
我们为另一个维度传递了一个负整数。这意味着剩余的维度变成了保存所有原始数据所需的任何形状。
把 -1 想象成填空做一个维度让所有的数据都有个家。🏠
在这种情况下,您最终得到一个 3 行 1 列的 2D 数组。 -1 取值 3 。
让我们的代码变得灵活是一个很好的实践,这样它就可以处理我们向它抛出的任何观察。所以不要硬编码两个维度,使用-1
。🙂
资料来源:pixabay.com
高维数组
同样的原理可以用于整形更高维的阵列。我们先做一个三维数组,然后再把它重塑成四维数组。
two_d_arrarray([['Zeta', 2020],
['Andrew', 1992],
['Agnes', 1972]], dtype=object)two_d_arr.shape(3, 2)three_d_arr = two_d_arr.reshape(2, 1, 3)
three_d_arrarray([[['Zeta', 2020, 'Andrew']],
[[1992, 'Agnes', 1972]]], dtype=object)
使用 -1 ,指示应该计算哪个尺寸,以准确地给出所有数据的位置。
arr = two_d_arr.reshape(1, 2, -1, 1)
arrarray([[[['Zeta'],
[2020],
['Andrew']],
[[1992],
['Agnes'],
[1972]]]], dtype=object)
注意,如果整形尺寸没有意义,你会得到一个错误。像这样:
two_d_arr.reshape(4, -1)
two_d_arr--------------------------------------------------------------------
ValueError: cannot reshape array of size 6 into shape (4,newaxis)
我们有六个值,所以我们只能将数组调整为恰好能容纳六个值的维数。
换句话说,维数必须形成乘积的六个。记住 -1 就像一个可以变成任意整数值的通配符。
预测
Scikit-learn 希望大多数预测都使用 2D 阵列。
假设列表中有一个样本,您想用它来进行预测。您可能会天真地认为下面的代码可以工作。
lr.predict(np.array([2012]))
并没有。☹️
ValueError: Expected 2D array, got 1D array instead:
array=[2012].
Reshape your data either using array.reshape(-1, 1) if your data has a single feature or array.reshape(1, -1) if it contains a single sample.
但是,我们可以按照有帮助的错误建议,用reshape(1, -1)
做一个二维数组。
lr.predict(np.array([2012]).reshape(1, -1))array(['Zeta'], dtype=object)np.array([2012]).reshape(1, -1).shape(1, 1)
您已经使第一个维度(行) 1 和第二个维度(列)与特征数量 1 相匹配。酷!
不要害怕检查一个物体的形状——即使只是确认它是你所想的那样。🙂
当我们讨论 scikit-learn 的整形主题时,请注意文本矢量化转换器,如 CountVectorizer 的行为与其他 scikit-learn 转换器不同。他们假设你只有一列文本,所以他们期望一个 1D 数组而不是 2D 数组。你可能需要重塑。⚠️
制作 1D 阵列的其他方法
除了用reshape
整形,NumPy 的flatten
和ravel
都返回一个 1D 数组。区别在于它们是创建原始阵列的拷贝还是视图,以及数据是否连续存储在内存中。查看这个不错的堆栈溢出答案了解更多信息。
让我们看看将 2D 数组压缩成 1D 数组的另一种方法。
挤压重塑。资料来源:pixabay.com
挤出不需要的维度
当你有一个多维数组,但其中一个维度不包含任何新信息时,你可以用.squeeze()
将挤出不必要的维度。举个例子,我们用之前做的数组。
two_d_arr_from_reshapearray([[2020],
[1992],
[1972]])two_d_arr_from_reshape.shape(3, 1)squeezed = np.squeeze(two_d_arr_from_reshape)squeezed.shape(3,)
哒哒!
请注意,TensorFlow 和 PyTorch 库与 NumPy 配合得很好,可以处理表示视频数据等内容的高维数组。将数据转换成神经网络输入层所需的形状是一个常见的错误来源。您可以使用上面的工具将数据调整到所需的维度。🚀
包装
您已经看到了如何重塑 NumPy 数组。希望您看到的未来代码会更有意义,您将能够快速地将 NumPy 数组处理成您需要的形状。
如果你觉得这篇关于重塑 NumPy 数组的文章很有帮助,请在你最喜欢的社交媒体上分享。😀
我帮助人们学习如何用 Python、熊猫和其他工具来处理数据。如果你觉得这听起来很酷,请查看我的其他指南并加入我在 Medium 上的 15,000 多名粉丝,获取最新内容。
快乐重塑!🔵🔷
介入
你能做些什么来帮助这个领域朝着正确的方向发展?
无论你是刚刚开始还是已经在建立你的职业生涯,你都可以帮助数据科学和机器学习以一种有益于人类和社区的方式发展。如果你有兴趣,这里有一些想法可以指导你接下来的步骤。
1。了解更多信息
参与并帮助该领域朝着正确方向发展的一个关键因素是跟上数据科学和机器学习的最新发展。我们创建了这个资源页面来支持您的学习之旅。
“做好事”是一个崇高的目标,但有时很难知道如何开始——例如,一些行动可能会带来我们最初没有意识到的负面影响。作为第一步,我们建议您进行一些初步研究,以了解您应该考虑的因素。比如,你可以读 做好事更好 一本介绍有效利他主义概念的书,或者看这个短视频。
接下来,你可能希望具体放大随着机器学习和人工智能变得更加强大而出现的问题和潜在风险。这是一个复杂的话题,为了帮助您驾驭它,我们基于 TDS 播客第二季创建了一个音频课程,在该课程中,我们重点关注数据科学和相邻领域中出现的问题。我们关于这些主题的精选专栏是另一个有用的资源,您可以按照自己的节奏浏览——它们涵盖了广泛的真实世界用例(和解决方案)。
除了 TDS,还有许多其他在线空间,在那里你可以找到关于类似主题的有见地的文章、播客和视频。我们最喜欢的包括开放慈善项目、未来生命研究所、人类兼容人工智能中心、关于新技术和新伦理的 TED 播放列表,以及80000 小时的对话。
2。讨论、贡献和联系
阅读和教育自己是很好的开始,但是加入对话更好。你可以直接联系从事这些主题的人,并提供你的支持。Twitter 和 LinkedIn 是找到和你有共同兴趣的社区成员的好地方,TDS 也是其中之一。
浏览我们策划的关于这些主题的专栏,如果有任何文章或项目引起你的共鸣,在评论区联系作者是建立初步联系的好方法。许多作者也欢迎通过他们的 Twitter 和 LinkedIn 账户联系。
如果你有兴趣就这些话题发表自己的见解,你可以向我们的团队提交一篇文章。如果我们选择出版它,我们将帮助突出它,以便它在 TDS 上更长时间可见,在我们的社交媒体帐户上推广它,并通过我们的新闻稿与读者分享它。
3。通过你的职业生涯提供帮助
如果你正在寻找一个能产生直接积极影响的职业,我们鼓励你去看看 80000hours.org 大学。借用他们的话:
你的职业生涯中大约有 8 万个工作小时。这意味着你对职业的选择是你一生中做出的最大决定之一,所以弄清楚如何善用这段时间是非常值得的。
《80,000 小时》出版了一个指南来帮助你思考你可以做出积极贡献的方法。他们还列出了你可能会考虑处理的问题的问题简介,任务驱动型角色的工作板,以及关于重要想法的有趣对话的播客。
4。志愿参与一些项目,这些项目的使命与你息息相关
有许多有价值的项目和社区,你的贡献可以发挥很大的作用。志愿服务也是一种很好的方式来练习你的技能,并结识志同道合的人,他们热衷于利用技术和数据做好事。以下是一些需要考虑的链接:
- DataKind —一个将数据科学家与社会变革组织联系起来的计划,在这个计划中,他们的技能可以发挥作用。
- DrivenData —提供持续的挑战,数据科学家竞相创建“对困难的预测问题有所影响的最佳统计模型”
- Solve for Good —一个平台,让致力于社会问题的组织请求志愿者帮助完成数据密集型任务。
- 在线志愿者——一项由联合国支持的倡议,允许具有研究、技术和其他背景的专家支持解决新冠肺炎相关问题的组织。
- Catchafire —专业人士寻找机会为激励他们的事业贡献时间和技能的社区。
你也可以创建自己的项目:从新冠肺炎和 T21 的污染到当地社区的帮助,有很多方法可以利用你的知识和数据专长做好事。如果你需要一些现实世界的灵感,请查看我们在改变数据专栏中的工作。
5。向推动该领域向正确方向发展的非营利组织捐款
如果你想支持那些致力于让人工智能更安全、更有益于所有人的组织,我们建议去看看开放慈善项目、应该、 MIRI 、 GovAI 、未来生命研究所和人类兼容人工智能中心。
如果你不确定该选哪一个,你可以向一个基金捐款,该基金支持围绕类似使命的多个组织。例如,长期未来基金支持众多项目和研究计划;你也可以阅读这篇评论来更详细地探索以人工智能为重点的非营利领域。
我们的专栏
变更数据
人工智能和算法偏见的风险是众所周知的,但数据科学也可以——而且经常是——成为一股好的力量。从环境研究和警察改革到公共卫生举措,数据为人们提供了信息并增强了他们的权能,使他们能够要求更好的政策并努力为边缘化社区实现更大的公平。请访问我们的数据促进变革专栏,了解讨论数据改善人们生活的潜力的各种文章。
模型可解释性
机器学习算法每天都在影响着我们。我们用这些算法来做决策,解决问题,让我们的生活更轻松。但是驱动应用程序的算法没有固定的规则和规定。依赖这些算法的企业、政府机构和学校不一定了解模型如何工作的细节或结果的真正含义。我们有权理解一个模型是如何做出决定的,以及为什么人们应该(或不应该)信任它。如果我们要使用这些算法来为我们做出法律、医疗和金融决策,我们需要确保我们理解一个模型是如何创建的,以及它为什么会得到它的结果。
公平和偏见
人工智能和机器学习模型只与它们接受训练的数据一样公平。算法不会自己思考,它们做出的预测是基于它们的创造者做出的选择。如果没有意识到这些问题,偏见通常会在每个层次的模型中形成。我们需要学习如何避免偏见,并在每一步都将公平融入我们的模型。
数据隐私
几乎每时每刻都在收集我们所有人的数据。保持任何表面上的隐私越来越难了。我们不断向公司提供信息,帮助他们改善业务运营。无论我们是为了更好的推荐而提供音乐品味,还是为了路线建议而提供我们的位置,或者关于我们健康和身份的信息,我们都需要意识到我们正在做出的选择和我们的数据将去往何处。我们需要问如何保护我们的数据,以及如何在各个层面维护我们的隐私。
人工智能校准和安全
随着我们提高人工智能的能力,我们如何对人类决策的微妙和复杂之处进行编程?AI 的目标会和我们自己的一样吗?人工智能不太可能默认与人类价值观保持一致。尽管制定一套不伤害人类的法律很好,但有令人信服的理由相信这是不可能的,而且对齐问题实际上很难解决。人工智能正在迅速进步:时间正在流逝,我们应该引导人工智能在每种情况下做出正确的选择,并随着它变得更加聪明而继续这样做。现在讨论这些问题对人工智能的未来至关重要。
我们创建了这份媒体出版物,因为我们相信数据相关知识对于让世界变得更美好至关重要。它不仅能让我们了解自己和周围的世界,还能帮助我们做出更好的决定。几乎在每个领域,数据科学都可以帮助我们更准确地理解手头的事情,从而更好地告知决策者他们的行动的潜在后果。
随着时间的推移,我们认识到,随着我们领域的进展,一些重要的问题正在出现。例如,与隐私、可解释性和一致性相关的问题。这就是为什么我们决定接触我们的社区,研究我们的领域面临的潜在问题以及我们如何帮助解决这些问题。
通过继续这项工作,我们希望更接近这些关键问题和挑战。这有助于我们确保我们的社区走上让世界变得更美好的道路。
使用 Datawrapper 和 Python 获得可发布的可视化效果
有时候 Matplotlib 感觉你在用马克笔画画。杰森·库德里特在 Unsplash 上拍摄的照片
Datawrapper Python 库使它变得前所未有的简单
本文中的所有代码和数据都可以在 Deepnote 上的中找到,如果你愿意,你也可以在那里复制并运行代码。
如果您是使用 Python 的数据专家,那么您肯定熟悉 Matplotlib、Seaborn 和 Plotly 等库。它们是数据可视化工具箱的主力。它们提供了极大的灵活性来创建您想要的可视化效果。不幸的是,这种灵活性是以现成的可用性和美观为代价的。
当做演示、写报告或写博客时,你的视觉效果必须看起来很棒。任何使用过这些库的人也知道从这些库中获得漂亮的和可出版的情节是多么困难。Datawrapper 旨在给你一个快速简单的方法来制作漂亮的可视化效果。
他们的博客最近的图表显示了利用上下文创建丰富的可视化是多么容易。
从 GUI 到 API
工作时,我大部分时间都在 JupyterLab,我发现很难从编码转移到网站制作可视化,然后再回到编码。所以当我听说 Sergio Sánchez 写了 Datawrapper Python 库。它利用 Datawrapper 的 API 允许以编程方式创建 20 多种类型的可视化。
让我们探索如何使用 Datawrapper Python 包快速构建一些可视化。我们将使用来自蒙古的每周肉价数据。你不需要了解蒙古或肉类价格,这只是一个很好的数据集。所有这些代码都是在 Jupyter 笔记本中执行的。
首先,我们可以导入我们的库,并从 Kaggle 获取数据。我们的环境变量已经用我们的 Kaggle 用户名和 API 键设置好了。
import pandas as pd
from datawrapper import Datawrapper
import kaggle
import os
kaggle
包允许我们搜索数据集并下载它。一旦我们找到它,我们就可以把它从我们的 Jupyter 笔记本里提取出来。
# Shows results matching our search term.
!kaggle datasets list -s “mongolia meat price”# Download and unzip the dataset.
!kaggle datasets download -d robertritz/ub-meat-prices
!unzip -o ub-meat-prices.zip
让我们加载数据集并看一看。我们数据集中的每一行都是一种特定肉类一周的平均市场价格。所有价格均以蒙古货币为单位。
df = pd.read_csv(“meat_prices_20180103_20211027.csv”)
df.head()
如您所见,我们的数据是标准的长格式。如果你想在类似于matplotlib
的地方绘图,你可以过滤数据框,只过滤你想要的,这很好。作为一个例子,我们可以看到如何只绘制数据集中的牛肉数据。
df['date'] = pd.to_datetime(df['date'])
df[df['meat_type'] == 'Beef, kg'].plot.line('date','price')
作者图片
我们需要做的是透视我们的数据,使每种肉类都在自己的列中,值是那一周的价格。此外,我们将只选择牛肉和羊肉,因为它们是我们感兴趣的主要肉类。
df = df.pivot(index='date', columns='meat_type', values='price').reset_index()
df = df.drop(columns=['Goat meat, kg','Horse meat, kg'])
作者图片
熊猫使用matplotlib
作为它的绘图库。虽然这些情节非常适合在笔记本上探索,但要为演示或博客帖子做好准备,还需要做大量的工作。
让我们看看 Datawrapper 可以做些什么来提升这个漂亮的级别。首先,我们可以用访问令牌实例化 Datawrapper 类。Datawrapper 有一个非常慷慨的免费层,这包括 API 访问您的帐户。你可以在你的账户页面获得一个 API 访问令牌。
dw = Datawrapper(access_token = os.environ[“DATAWRAPPER_TOKEN”])
如果您想确保您的帐户正常运行,您可以使用account_info
便捷方法查看您的帐户信息。
# Input
dw.account_info()# Output
{'id': 175781,
'email': 'robert@mongol.ai',
'name': None,
'role': 'editor',
'language': 'en_US',
'teams': [],
'chartCount': 18,
'url': '/v3/users/175781'}
接下来,我们可以用我们的数据创建一个图表。Datawrapper Python 包的工作方式类似于 Plotly Express 的工作方式。在一行代码中,您可以创建一个图表,声明其标题,并指定要绘制的数据。
有一件事不是很明显,那就是chart_type
。Datawrapper 目前有 22 种图表类型,您可以在它们的 API 文档页面上找到每种图表类型的名称。为了简单起见,我们将制作一个简单的时间序列图,因此我们将使用d3-lines
图表类型。
meat_prices = dw.create_chart(
title = "Market Prices for Meat, Ulaanbaatar, Mongolia",
chart_type = 'd3-lines',
data = df
)
create_chart
方法有以下参数:
title
—字符串形式的图表标题。chart_type
—支持的 22 种图表类型之一。图表类型列表是这里是。data
—接受熊猫数据帧。folder_id
—允许您在 Datawrapper 中指定文件夹 ID,以帮助组织图表。
需要注意的一点是,Datawrapper 包没有返回图表。相反,它将图表元数据作为字典返回。实际的图表现在存储在 Datawrapper 服务上。最重要的是,我们可以通过引用字典来访问图表的 ID。在我们的例子中,我们将使用meat_prices[‘id’]
。
# Input
meat_prices# Output
{'publicId': 'jFWEN',
'language': 'en-US',
'theme': 'datawrapper-data',
'title': 'Market Prices for Meat, Ulaanbaatar, Mongolia',
'type': 'd3-lines',
'metadata': {'data': {},
'describe': {'source-name': '',
'source-url': '',
'intro': '',
'byline': '',
'aria-description': ''},
'visualize': {},
'publish': {'blocks': {'logo': {'enabled': False},
'embed': False,
'download-pdf': False,
'download-svg': False,
'get-the-data': True,
'download-image': False}}},
'authorId': 175781,
'id': 'jFWEN',
'lastModifiedAt': '2021-11-03T13:51:52.233Z',
'createdAt': '2021-11-03T13:51:52.200Z',
'url': '/v3/charts/jFWEN'}
要访问图表,我们首先需要发布图表。这使得图表在我们的 Datwrapper 配置文件上公开,并将为图表生成一个嵌入代码。然后我们可以在笔记本上交互显示。
dw.publish_chart(meat_prices['id'], display=False)
dw.display_chart(meat_prices['id'])
作者图片
在 Jupyter 笔记本中,现在的输出是相当时髦的。这是因为 Jupyter 在输出中为 IFrame 留出了相对较小的空间。为了检查以确保我们的图在更大的尺寸下看起来更好,我们可以用特定的宽度导出它并检查它。
或者,您可以去 Datawrapper 站点看一看。网址格式为https://app.datawrapper.de/chart/{chart_id}/visualize
,在这里可以替换{chart_id}
。您也可以在https://app . data wrapper . de .的仪表板上找到它
dw.export_chart(meat_prices['id'], width=800)
互动还是静态?
导出图表后,您将看到一个名为image.png
的文件,该文件与您的笔记本位于同一目录下。你可以把它作为图片展示或者放在任何你想放的地方。
如果您想在 Twitter 或 LinkedIn 帖子上将其用作静态图像,导出图表是很好的选择。然而,大多数时候你会希望保持剧情的互动性。为此,您可以使用get_iframe_code
方法获取图表的 IFrame 嵌入代码。
Datawrapper 支持 Embedly,它被 Medium 和许多其他站点用于嵌入内容。要在介质上嵌入 Datawrapper 图表,只需将图表链接粘贴到介质编辑器中,然后点击 enter。
# Input
dw.get_iframe_code(meat_prices['id'])# Output
<iframe title="Market Prices for Meat, Ulaanbaatar, Mongolia" aria-label="Interactive line chart" id="datawrapper-chart-jFWEN" src="https://datawrapper.dwcdn.net/jFWEN/1/" scrolling="no" frameborder="0" style="border: none;" width="undefined" height="undefined"></iframe>
自定义您的图表
在 Datawrapper 站点上,您有许多选项来定制图表,包括注释、颜色等等。如果您喜欢使用 Jupyter 界面,也可以通过 Datawrapper Python 包自定义图表。
通过 Datawrapper 包,您可以使用一些内置的关键字参数来更新您的图表。
dw.update_description(
meat_prices['id'],
source_name = 'NSO Mongolia',
source_url = '1212.mn',
byline = 'Robert Ritz',
)
除了update_description
方法之外,您还可以使用update_metadata
方法来改变颜色、线条的粗细等等。可编辑元数据的例子可以在 Datawrapper API 文档这里找到。
现在,我们将线条设置为粗线,并改变颜色。
properties = {
'visualize' : {
'thick': True,
'custom-colors': {
"Beef, kg": '#15607a',
"Mutton, kg": '#1d81a2',
},
}
}dw.update_metadata(meat_prices['id'], properties)# Output
Chart's metadata updated!
用 Datawrapper Python 库处理的一个领域仍然有些困难,那就是注释。可以用属性字典声明注释,但是找到正确的位置可能需要大量的反复试验,这在 Jupyter 笔记本中很难完成。
在这种情况下,我建议转到 Datawrapper 站点上的可视化来完成可视化。这是添加了注释的最终可视化效果。
如果您是一名关心可视化效果的数据专家,您可能想尝试一下 Datawrapper。通过将其包含在 Python 工作流中,您可以在很短的时间内获得生产质量的可视化效果。
感谢阅读。你可以在这里找到更多关于我的信息。考虑订阅以便在我发布时收到通知。如果你想直接支持我的文章,你可以使用我的推荐链接注册成为媒体会员。
量子计算入门
并使用 Q#和 Qiskit 解决数独游戏
📸洛伦佐·埃雷拉
T2:阅读量子力学会让你想知道我们生活在一个什么样的世界里。更糟糕的是,诺贝尔奖获得者理查德·费曼说过一句名言:“如果你认为你理解量子力学,你就不理解量子力学。”那么,没有计算机科学或量子力学的学位,我们究竟如何学习量子计算呢?幸运的是,这个问题有一个答案:你不需要了解太多关于量子现象的知识,也不需要了解你的‘经典’计算机如何一点一点地工作来开始使用量子计算机。相信我,我正在这么做!
位开关处于 0 或 1 位置。量子位开关在 1 和 0 两个位置。
量子计算机不会取代经典计算机,但会让我们解决一些问题(破解密码是一个流行的问题),即使是我们最先进的超级计算机也无法在我们太阳系的寿命内解决这些问题。量子位使之成为可能。量子位是量子计算机中的位,但它的状态(量子位没有的值)不是像常规位那样具有 1 或 0 的值,而是 1 和 0 的叠加(想象一种可以同时代表 1 和 0 的混合状态)。
用一台经典计算机和 3 个比特,你可以同时拥有 8 个经典状态中的一个(000,001,010,…,111),但是 3 个量子比特可以同时处于 8 个经典状态的叠加态。
考虑下面这个过于简单的例子:我的经典笔记本电脑使用 64 位 2.3 GHz 处理器,因此每秒可以执行 2300000000 次操作,同时可以保持任何 2⁶⁴状态。尽管我要等 200 多年才能让我的笔记本电脑遍历所有的 2⁶⁴态,但由于叠加,一台有足够量子位的量子计算机可以同时访问所有的态!
在过去的几个月里,我一直在用 IBM 的 Qiskit 和微软的 Q# 检查量子计算。Qiskit 使用 Python,而 Q#更接近 C#。无论你使用哪种来源,量子怪异纠缠、叠加以及相关概念很早就出现了。我认为这些是推动量子算法的超级食物成分;你知道这些包装具有不可思议的特性,尽管你不太明白它们是如何做到的…
在我的光量子之旅中,我偶然发现了 Grover 的算法,它在搜索问题中提供了潜在的二次加速(这些问题可以表述为‘这个解决方案是有效的吗?’比如‘这个数据库包含这个记录吗?’).二次加速意味着我们需要 √n ,而不是在数据库中查找 n 次来找到有效的解决方案。
想象一下,你需要检查 4 家不同的商店,找出哪家有你要找的礼物的库存。有了量子计算机助手,你可以花一半的时间。
一个 2x2 的数独游戏不需要太多的思考就能解决。
Qiskit 的 Grover 算法章节以一个 2x2 数独解算器的实现结束。想出一个有效的解决方案不需要太多的思考(它只要求同一行或同一列中的数字不相同),我们根本不需要为量子计算费心。但这是一个很好的起点,而且令人印象深刻的是,它使用量子计算解决了 2x2 数独,这促使我将这个解决方案扩展到更大的数独。
使用 Qiskit 的教科书措辞:可能很难找到常规 9x9 数独的解决方案,但是给定一个解决方案,很容易验证它是否有效。图着色问题(找出由顶点连接的对不能具有相同颜色的 n 节点的着色)也可以用这些术语来表述,并且在 Q# 和 Katas 教程中可以找到这样的例子。
我的 Q#数独解算器使用 Grover 的搜索紧紧跟随关于图着色的 Q#教程,并带来了来自 Katas 挑战的叠加思想
考虑到我们可以模拟的量子位数量和可用计算资源的限制,只能获得部分数独解。30 个量子位需要大约 16GB 的内存,而完整的 4x4 数独至少需要 89 个量子位💥
解决数独的第一步是对数字进行二进制编码,这样一系列的 0 和 1 就可以表征数独的扁平解。
4x4 数独二进制编码的扁平解决方案。
4x4 数独有 4 个不同的数字,例如 0 到 3,每个数字最多需要两位(0 = 00,1 = 01,2 = 10,3 = 11)。这样,一个 32 位的字符串可以分成对,对 4x4 数独网格的 16 个数字进行编码,其中每对的位置决定了它在数独网格中的位置,从左上到右下。
同样,一个 9x9 数独游戏使用 9 个数字,例如 0 到 8,每个数字需要 4 位(0 = 0000,1 = 0001,…,7 = 0111,8 = 1000)。因此,一个 324 位的字符串可以分成 4 组,对 9x9 数独网格的 81 个数字进行编码。
记住这个介绍,我实现量子数独解算器的关键区别在于 Grover 算法的初始化:不是准备所有基态的的相等叠加,而是准备由位串定义的基态的相等叠加。
一个寄存器有 3 个量子位,位串= [[0,0,1],[1,0,0]]准备叠加态 1/√(2) * (|001⟩ + |100⟩),而忽略的另外 6 个基态|000⟩、|010⟩、|011⟩、|101⟩、|110⟩和|111⟩.
这种方法背后的原因是为了获得潜在解决方案的集合,其中具有不在数独范围内的数的基础状态不在准备好的叠加态中(例如,在 9x9 数独中,具有等于|1011⟩的前 4 个量子位的基础状态不在准备好的叠加态中,因为二进制数 1011 表示在 9x9 数独中不存在的十进制数 11)。
数独解算器可以总结为以下步骤:
1.定义数独属性。
2.准备数独数字排列的数组。
3.用上一步的排列来准备叠加态。
4.运行格罗弗的算法。
5.使用量子预言机检查解决方案是否正确。
这个数独解算器简单地从所有存在于叠加状态的有效解中输出一个有效(部分)解。任何解决方案都可能被选中,因为唯一存在的约束是数独规则(即同一数字在每一行中不能出现一次以上,等等。).
考虑到内存限制,返回 4x4 数独的 7 个单元将使用 30 个量子位进行模拟,并且需要相当长的时间。
对 4x4 数独的 6 个单元格运行求解程序后返回的部分解可能是:
求解程序返回的部分解。(在未来的某一天,这个解算器将会毫不费力地完成 9x9 的数独游戏!)
*The resulting Sudoku solution:
Index 1 - Number 0
Index 2 - Number 2
Index 3 - Number 3
Index 4 - Number 1
Index 5 - Number 3
Index 6 - Number 1*
其中索引是 4x4 数独图形中所示的位置。
如果你已经做到这一步:干得好!本文的目标是通过编码和解决问题来吸引人们对学习量子计算的惊人资源的注意。
该代码可在 GitHub 上获得。
[1]约翰·格里宾,《用量子猫计算:从巨像到量子位》(2013),矮脚鸡出版社。
使用 Databricks 和 PySpark 开始使用 Spark
使用纯 Python 开始使用 Spark 和 Databricks
图片来自https://unsplash.com/s/photos/spark
一开始,编程大师创建了关系数据库和文件系统。但是单台机器上的文件系统变得有限且缓慢。数据黑暗就在数据库的表面。缩小地图的精神正在大数据的表面上酝酿。
编程大师说,要有火花,于是就有了火花。
已经有 Hadoop 了,为什么还要麻烦 Spark
如果关系数据库是一个维护良好的数据花园;Hadoop 是一个杂乱的数据森林,它可以无限增长。
要将数据放入花园,数据需要被仔细清理并在那里结构化地生长。在 Hadoop 森林中,女士们、先生们,不要担心,这里的任何数据都可以,文本、数字,甚至音频和视频都没有数据大小和类型的限制。
但是 Hadoop 还是有一些不足,Spark 来解决。这里列出了我的 4 个主要区别。
- 在 Hadoop 中,每一个映射和归约动作都是用磁盘存储作为数据中间人,磁盘操作比较慢。Spark 通过利用内存直接数据访问优化流程。换句话说,在内存中存储一些中间数据来提高性能。(这就是为什么你总是阅读官方 Spark 介绍描绘自己比 Hadoop 快得多,这里没什么神奇的。)
- Hadoop 基本上是一个分布式文件系统,可以通过它的 map-reducer 和批处理调度器扩展到无限大小。但是你需要用 Java 来实现真正的应用。Spark 来提供 Python 之类的操作语言,r .为数据流、机器学习、数据分析提供有用的工具。
- Hadoop 不包含作业调度程序,需要第三方调度程序,Sparks 自带作业调度程序。
- Hadoop 更便宜,需要的内存也更少。Spark 需要更多内存。好吧,这个是 Hadoop 的优点而不是缺点。
有了 PySpark,我们可以用纯 Python 代码、Jupyter Notebook 或 Databricks Notebook 与 Spark 进行充分的交互。这是 Spark 的一大优势。
已经有火花了,为什么还要麻烦数据布里克
Spark 是开源的、免费的、功能强大的,为什么还要使用 Databricks 呢?为了建立一个有用的 Spark 集群,并利用分布式存储,我们需要构建至少 2 台虚拟或物理机器。接下来,设置驱动和工作节点,配置网络和安全等。
来自 https://spark.apache.org/docs/latest/cluster-overview.html的火花元件
仅仅运行一个 Spark“hello world”就要做更多的手工工作。如果得到 JAVA_HOME 找不到,或者找不到 Spark path 之类的错误信息就别提了。
通过解决所有这些繁琐的配置,Databricks 提供了一个开箱即用的环境。
以 Azure Databricks 为例,在几次鼠标点击和几分钟等待集群启动之后。我们有一个功能齐全的火花系统。他们称之为数据砖。
与免费的 Spark 不同,Databricks 通常根据集群大小和使用情况收费。小心,在创建第一个实例时选择正确的大小。
还有一点需要注意,请记住你选择的 Databricks 运行时版本。我更愿意选择 LTS 7.3。稍后,当您安装databricks-connect
时,版本应该是相同的。
开始连接
我准备用 Python 做所有的事情,那么我应该安装pyspark
包吗?不,要使用 Python 来控制数据块,我们需要首先卸载pyspark
包以避免冲突。
pip uninstall pyspark
接下来,安装databricks-connect
。其中包括所有名称不同的 PySpark 函数。(确保您的本地机器上已经安装了 Java 8+)
pip install -U "databricks-connect==7.3.*"
在配置到 Databricks 集群的客户端连接之前,请转到 Databricks UI 获取以下信息并记下。详细步骤可以在这里找到
- 访问令牌:
dapib0fxxxxxxxxx6d288bac04855bccccd
- 工作区网址:
[https://adb-8091234370581234.18.azuredatabricks.net/](https://adb-8091234370581234.18.azuredatabricks.net/)
- 集群 id:
1234-12345-abcdef123
- 端口号:
15001
- 组织 id:
8091234370581234
,组织 id 也出现在工作区 url 中。
当您准备好上述所有信息后,就可以配置到 Databricks 集群的本地 PySpark 连接了。
databricks-connect configure
跟着向导走,你不会迷路的。之后,使用这个 Python 代码来测试连接。
# python
from pyspark.sql import SparkSession
spark = SparkSession.builder.getOrCreate()
print('spark session created.')
如果你受到“火花会议已创建”的欢迎,一个活蹦乱跳的火花簇正在云中运行。我们现在可以做一些大数据分析。
数据仓库:BDFS
Hadoop 的 HDFS 允许用户在本地磁盘上构建可扩展的海量存储。BDFS 几乎和 HDFS 一样。区别在于它的后端存储是基于云的。
你可以用dbutils
用 Python 远程管理 BDFS,
在本地 Python 上下文中获取dbutils
对象处理程序。官方文件假设你使用的是 Databricks 笔记本,省略这一步。当用户试图在普通 Python 代码中使用它时会感到困惑。
from pyspark.dbutils import DBUtils
dbutils = DBUtils(spark) # the spark object here
# is already initialized above
列出/mnt/
文件夹中的文件和文件夹
dbutils.fs.ls('dbfs:/mnt/')
你会得到这样的信息:
[FileInfo(path='dbfs:/mnt/folder1/', name='folder1/', size=123),
FileInfo(path='dbfs:/mnt/folder2/', name='folder2/', size=123),
FileInfo(path='dbfs:/mnt/tmp/', name='tmp/', size=123)]
dbutils 官方文件列出了所有其他操作。
用 Python 上传一个 CSV 文件到 DBFS
在本地磁盘上准备一个圣经 CSV 文件。用您的用户名替换[用户名]以运行下面的代码。
import urllib.request
bible_url = "https://raw.githubusercontent.com/scrollmapper/bible_databases/master/csv/t_kjv.csv"
urllib.request.urlretrieve(bible_url,"/home/[username]/temp/bible_kjv.csv")
现在,上传圣经 CSV 文件到 BDFS。
bible_csv_path = "file:/home/[username]/temp/bible_kjv.csv"
dbutils.fs.cp(bible_csv_path,"/tmp/bible_kjv.csv")
如果您决定移动文件而不是复制,请使用mv
代替cp
。
使用 Spark Dataframe 分析数据
读取刚刚上传的圣经 CSV 文件,并将其封装在 Spark 数据帧中(与熊猫数据帧形成对比)。
bible_spark_df = spark.read.format('csv')\
.options(header='true')\
.load('/tmp/bible_kjv.csv')
bible_spark_df.show()
你会看到结果的
+-------+---+---+---+--------------------+
| id| b| c| v| t|
+-------+---+---+---+--------------------+
|1001001| 1| 1| 1|In the beginning ...|
|1001002| 1| 1| 2|And the earth was...|
|1001003| 1| 1| 3|And God said, Let...|
...
|1001019| 1| 1| 19|And the evening a...|
|1001020| 1| 1| 20|And God said, Let...|
+-------+---+---+---+--------------------+
only showing top 20 rows
如果你是熊猫数据框的粉丝,很容易将数据转换成熊猫数据框
bible_pandas_df = bible_spark_df.toPandas()
我们用 Spark Dataframe 看看每本书有多少节。
bible_spark_df.groupBy("b")\
.count()\
.sort("count",ascending=False)\
.show()
你会看到结果的
第一卷是创世纪,这本书包含 1533 节经文。
在创建临时视图的帮助下,我们还可以使用 Spark SQL 查询数据
bible_spark_df.createOrReplaceTempView('bible')
bible_sql_result = spark.sql('''
select * from bible
where id == 1001001
''')
bible_sql_result.show()
查询结果
+-------+---+---+---+--------------------+
| id| b| c| v| t|
+-------+---+---+---+--------------------+
|1001001| 1| 1| 1|In the beginning ...|
+-------+---+---+---+--------------------+
将 Spark Dataframe 作为 JSON 文件保存回 BDFS。
bible_spark_df.write.format('json').save('/tmp/bible_kjv.json')
对于所有 Spark 数据集操作,请查看Spark SQL、数据帧和数据集指南
Spark 数据库和表格
Spark 还支持 Hive 数据库和表,在上面的示例中,我创建了一个临时视图来启用 SQL 查询。但是当会话结束时,临时视图将会消失。启用在 Hive 表中存储数据,并且可以使用 Spark SQL 进行长期查询。我们可以在配置单元表中存储数据。
首先,创建一个 Hive 数据库
spark.sql("create database test_hive_db")
接下来,将圣经火花数据帧写成表格。这里的数据库名称有点像表文件夹。
bible_spark_df.write.saveAsTable('**test_hive_db**.bible_kjv')
有关 Spark 配置单元表操作的所有信息,请查看配置单元表
总结和概括
祝贺并感谢你阅读到这里。当我开始学习 Spark 和 Databricks 时,当书籍作者试图用复杂的图表介绍 Spark 后端架构时,我陷入了困境。我写这篇文章是为了那些从来没有接触过 Spark 的人,想在不被弄糊涂的情况下弄脏自己的手。
如果您成功地运行了所有代码,那么您应该可以开始使用 Spark 和 Databricks 了。Spark 和 Databricks 只是工具不应该那么复杂,能比 Python 复杂吗?(开玩笑)
还有一点要说明的是,默认的 Databricks 入门教程使用 Databricks Notebook,很好很好看。但是在真实的项目和工作中,您可能希望用普通的 Python 编写代码,并在 git 存储库中管理您的工作。我发现带有 Python 和 Databricks 扩展的 Visual Studio 代码是一个很棒的工具,完全支持 Databricks 和 Spark。
贝叶斯统计入门
探索数据科学
想了解贝叶斯统计的世界,并更好地理解贝叶斯和频率方法之间的区别?心理学家兼顾问汉娜·鲁斯写下了你一直在寻找的资源。在介绍了必要的术语后,Hannah 开始研究一个精彩的案例(涉及婚礼和天气!)让这些概念变得鲜活起来。如果你想知道何时、为什么以及如何使用贝叶斯统计,这篇文章就是为你准备的。
作为一名数据科学家,开始前端开发
重新掌控你向世界展示自己的方式,成为一名更好的工程师
渴望亲自动手并学习新技能?—Quino Al在 Unsplash 上拍摄的照片
作为一名数据科学家,你应该花时间学习前端开发吗?
虽然这听起来是一个有趣的话题,但我们的时间有限,学习一个全新的领域似乎令人生畏。
在讨论了为什么这会让你受益之后,我将分享我作为一名数据科学家开始使用前端开发的经历,并为你提供快速启动你的网站的起点。
对于上下文,我的核心工程技能(过去)围绕 Python 和 Docker。
该职位划分如下:
1 |数据科学家应该学习前端开发吗?
2 |学习 HTML、CSS、Javascript
3 |构建您的前端
4 |构建您的数据科学后端
5 |服务和托管您的网站
6 |分享您的作品
1 |数据科学家应该学习前端开发吗?
我做了调查,发现了一些宝石。
来自 Quora: 数据科学家需要学习 web 开发吗?
Chip Huyen 在 LinkedIn上的帖子—2020 年 2 月 7 日
另一篇讨论这个话题的文章是不久前写的。建议你去看看。
</5-reasons-why-im-learning-web-development-as-a-data-scientist-33bd61601b62>
作为一名数据科学家,无论是在工作场所还是在互联网上,我都觉得自己交流工作的能力有限。报告、图表、幻灯片……无论你是一个多么优秀的沟通者,都很难超越移动响应界面的惊艳效果。
现在已经有了很棒的专注于 python 的工具( Streamlit , plotly Dash ),可以很容易地可视化数据分析或模型预测。
虽然我相信这些工具对于公司内部的应用程序来说是完全可以接受的,但是当涉及到向更多不太专业的观众展示你的作品时,你可能最终会觉得你的应用程序设计受到了限制。
在过去几周的过程中,我意识到重新掌控并没有我想象的那么难。
对我来说,夺回控制权意味着:
- 提高我对互联网工作原理的理解
- 学习用当前的最佳实践(flexboxes、网格、响应式设计等等)编写 HTML 和 CSS
- 学习编写普通的前端 Javascript
- 能够部署一个与我编写的 Python Flask API 交互的网站(这是我作为数据科学家开发的技能)
我相信掌握一个更好的了解前端会有几个的好处:
- 更好地理解可能与您一起工作的开发人员的工作
- 增强您对自己引导产品能力的信心
- 避免你的伟大作品被不太好的界面降级
如果你还在读,我会分享我是如何在这个领域起步的。我真的很惊讶自己能这么快学会我认为很难达到的技能。我还设法让他们与已经获得的技能互动。
2 |学习 HTML、CSS、Javascript
HTML 用于页面内容,CSS 用于样式,Javascript 用于交互。虽然我有关于 HTML 和 CSS 的高级知识,但 JS 真的很陌生。
无论如何,我需要用当前的最佳实践在新的基础上重新建立我的知识。对我来说,另一个要求是在引入任何库之前,理解这些语言的全部能力。
我对斯克林巴的团队感激不尽。自 2017 年以来,Scrimba 以互动和动手的方式为在线编码课程提供了一种创新的方法。
我目前正在学习前端开发人员职业道路课程,该课程不需要任何先验知识,重点是训练你的编码肌肉记忆,而不是理论知识,因此可以让你很快取得切实的成果。
3 |构建您的前端
在斯克林巴,有两章引起了我的注意:
- 响应式设计
- 使用 API
卡斯帕·卡米尔·鲁宾在 Unsplash 上拍摄的照片
响应式设计
请记住,如果你像我一样对夺回控制权感兴趣,这将为你的利益相关者提供愉快的体验,无论他们在哪里,无论他们使用什么设备。
响应式设计就是能够根据浏览器客户端来调整网站的内容布局。对于手机和平板电脑用户来说尤其如此。
虽然这本身是一个完整的主题,它涉及 UI 设计,但主要的关键在于媒体查询,它将根据与屏幕大小相关的条件相应地修改 CSS(样式)。
使用 API
当您想让其他团队使用您的模型时,最简单的方法可能是通过 REST API 访问它。自然,你可以在你的网站上使用同样的微服务概念。
然后, web 客户端会监听网页上的用户事件,比如点击按钮,并相应地使用 Javascript 的获取方法向后端发送 HTTP 请求。
注意 Javascript 是用于同步代码执行的。发送请求和等待响应需要编写异步 Javascript,如果你来自 Python,这更直观。
同样,Scrimba 在引入这一概念以及如何实现这一概念方面做得非常出色。
4 |构建您的数据科学后端
Flask 是一个最小的 Python 框架,满足了我的大部分需求。
这是一个你如何为你的模型服务的例子。
5 |服务和托管您的网站
知识库组织
照片由 Richy Great 在 Unsplash 拍摄
你应该把你的后端和前端代码分成两个仓库吗?
这取决于项目的规模和团队组织。
在较小的规模下,将这些组件放在同一个库中可能更明智。
除了给你机会在同一次提交中修改后端和前端,它还使得跟踪你的网站的进度变得更加容易:不存在哪个后端提交和哪个前端提交配合得更好的问题。
微服务
说到上菜,我的建议是使用 Docker 强大的技术。
简而言之,Docker 允许复制运行时环境。
想法是分离前端服务和后端服务的环境,每个环境都有一个最小的依赖集。
将后端放在微服务容器中,前端放在另一个容器中。使用docker-compose
一起构建和运行这些容器。
对于后端 Docker 映像,它可以像具有正确依赖关系的 python 映像一样简单。
对于前端,我尝试使用一个 nginx 图像,将我想要提供的 HTML、CSS、Javascript 文件复制到这个图像中,效果非常好。更准确地说,是在/usr/share/nginx/html
。您也可以选择在该位置装载卷。
https://www.docker.com/blog/how-to-use-the-official-nginx-docker-image/
这样,如果您启用了加密通信,您的网站将在端口 80 或 443 上提供服务。您的后端在端口 5000 上提供服务(默认的 flask 服务端口)。
请注意,此时您可能会遇到与跨来源资源共享相关的问题( CORS )。这是因为您的fetch
语句向源域(您的index.html
文件所在的位置)之外的域发出了请求。在这种情况下,你可能想看看flask-cors
。
主办;主持
数字海洋平面设计
我试了一下数字海洋。更准确地说,我尝试使用 droplets ,这是你需要的规格的普通远程机器,或者 AWS EC2 替代品。
我欣赏干净的界面和易用性。
为了部署我的网站,我ssh
到我在 DigitalOcean 的网络控制台上启动的机器,检查代码 repo、docker-compose build
和docker-compose up
。
关于这个实例,我建议选择从 Ubuntu 上的“ Docker”镜像中启动它,这个镜像随docker-compose
一起安装。此外,您可能有兴趣遵循以下附加步骤(例如,创建具有 sudo 权限的非 root 用户):
https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-20-04
域名
此时,您的网站将可以在您的云机器的 IP 上访问。为了更方便,您可能会对将一个域名路由到那个地址感兴趣。
幸运的是,这个过程是有据可查的。你所需要做的就是从注册商那里购买域名并配置域名服务器。
https://www.digitalocean.com/community/questions/how-do-i-set-a-domain-name
6 |分享您的作品
这就是了。你已经部署了你的网站。你现在可以和全世界分享了。如果你读到这里,我希望这让你渴望夺回控制权,或许激发一些项目想法。
至于我自己,我写了explorehsk.com,一个为中文学习者准备的工具。它通过将相关的单词(按单词的意义和用法)分组,并允许你从一张抽认卡跳到相邻的抽认卡,来帮助巩固 HSK 标准考试的词汇。
存储库演示了上面列出的要点。
https://github.com/syltruong/explorehsk
带回家的信息
- 你可以用前端技能增加你的影响力。
- 有很多资源可以学习 HTML,CSS,Javascript。这些越来越复杂了。这些语言的普通用法已经可以让你走得很远了。
docker-compose
轻松管理您的前端和后端部署- 找到你最喜欢的云提供商和域名注册商。设置好它们,你就可以开始了。
我个人对在这个方向上学习更多感到兴奋,并希望听到你的建议、观点和项目。
让我们在 LinkedIn、Twitter 或评论区联系吧!
领英—https://www.linkedin.com/in/syltruong/
推特—https://twitter.com/syltruong
免责声明:这篇文章不是由文中提到的任何公司赞助的。所有观点都是我的。
MLOps 入门
实践教程
包含开源工具的综合 MLOps 教程
pch.vector 创建的人向量—【www.freepik.com
将机器学习(ML)模型投入生产是一项艰巨的工作。实际上,根据雄心的程度,这可能会异常困难。在这篇文章中,我将回顾一下我个人的想法(包括实现的例子),这些原则适合于在一个受监管的行业中将 ML 模型投入生产的旅程;也就是说,当一切都需要可审计、合规和受控时——在这种情况下,部署在 EC2 实例上的拼凑的 API 将无法满足要求。
机器学习操作 (MLOps)指的是一种方法,其中 DevOps 和软件工程的组合以一种能够在生产中可靠有效地部署和维护 ML 模型的方式得到利用。可以在网上找到大量讨论 MLOps 的概念细节的信息,因此,本文将侧重于通过大量实际操作代码等来提高实用性。,基本上建立了一个基于开源工具的概念验证 MLOps 框架。你可以在 GitHub 上找到最终代码。
这一切都是为了将 ML 模型投入生产;但这意味着什么呢?在这篇文章中,我将考虑下面的概念列表,我认为它们应该被视为 MLOps 框架的一部分:
- 开发平台:用于执行 ML 实验和授权数据科学家创建 ML 模型的协作平台应被视为 MLOps 框架的一部分。该平台应支持对数据源的安全访问(例如,从数据工程工作流)。我们希望从 ML 培训到部署的过渡尽可能平稳,这对于这样一个平台来说比在不同的本地环境中开发的 ML 模型更有可能。
- 模型单元测试:每次我们创建、更改或重新训练模型时,我们都应该自动验证模型的完整性,例如
-应该满足测试集的最低性能
-应该在合成的用例特定数据集上表现良好 - 版本化:应该可以及时返回,检查与给定模型相关的一切,例如,使用了什么数据&代码。为什么?因为如果有东西坏了,我们需要能够回到过去,看看为什么。
- 模型注册:应该有已部署的&退役 ML 模型、它们的版本历史以及每个版本的部署阶段的概述。为什么?如果出现问题,我们可以将之前归档的版本回滚到生产环境中。
- 模型治理:只有某些人应该有权查看与任何给定模型相关的培训。对于谁可以请求/拒绝/批准模型注册中心中部署阶段之间的转换(例如,从开发到测试到生产),应该有访问控制。
- 部署:部署可以是很多事情,但是在这篇文章中,我考虑了我们想要将模型部署到云基础设施并公开 API 的情况,这使得其他人能够消费和使用该模型,也就是说,我没有考虑我们想要将 ML 模型部署到嵌入式系统中的情况。在适当的基础设施上高效的模型部署应该:
-支持多个 ML 框架+定制模型
-具有定义良好的 API 规范(例如,Swagger/OpenAPI)
-支持容器化的模型服务器 - 监控:跟踪性能指标(吞吐量、正常运行时间等。).为什么?如果一个模型突然开始返回错误或者出乎意料地慢,我们需要在最终用户抱怨之前知道,以便我们可以修复它。
- 反馈:我们需要向模型反馈关于它表现如何的信息。为什么?通常,我们会对新样本进行预测,但我们还不知道基本事实。然而,当我们了解真相时,我们需要通知模型报告它实际做得有多好。
- A/B 测试:无论我们认为我们在做多么可靠的交叉验证,我们永远不知道模型在实际部署之前会有怎样的表现。在 MLOps 框架内,使用真实模型进行 A/B 实验应该很容易。
- 漂移检测:通常,给定模型部署的时间越长,与模型被训练时相比,随着环境的变化,情况变得越糟。我们可以尝试对这些不同的情况进行监控和警告,或者在它们变得太严重之前进行“漂移”:
-概念漂移:当输入和输出之间的关系已经改变时
-预测漂移: 预测中的变化,但是模型仍然保持
-标签漂移:模型的结果相对于训练数据的变化
-特征漂移:分布中的变化 - 异常值检测:如果部署的模型接收到与训练期间观察到的任何东西都显著不同的输入样本,我们可以尝试将该样本识别为潜在的异常值,并且返回的预测应该如此标记,这表明最终用户应该小心地信任该预测。
- 对抗性攻击检测:当对抗性样本攻击我们的模型时(例如,有人试图滥用/操纵我们算法的结果),我们应该得到警告。
- 可解释性:ML 部署应该支持端点返回我们预测的解释,例如,通过 SHAP 值。为什么?对于许多用例来说,预测是不够的,最终用户需要知道为什么要做出给定的预测。
- 部署的治理:我们不仅需要对谁可以查看数据、训练模型等进行访问限制。而且还取决于谁最终可以使用部署的模型。这些部署的模型通常就像它们被训练的数据一样保密。
- 以数据为中心:除了关注模型性能&的改进,MLOps 框架还能够更加关注终端用户如何提高数据质量和广度。
当然,上述原则是对开发运维及软件工程的常规最佳实践的补充,包括代码、文档、单元测试、CI/CD 等基础设施。在探索了 MLOps 的各种解决方案的应用之后(同时考虑到以上几点),我将在这篇博客文章中探索的解决方案是ml flow+Seldon-core的组合——这些的优点是不需要昂贵的订阅。它们大部分都是开源的,这意味着我们可以直接设置和测试它们🙌 ...我将逐一讨论上述要点,看看这个堆栈如何应对每个挑战。这是一个很大的范围,所以也许在阅读之前喝杯咖啡。☕️
PS:我不属于 mlflow 或 Seldon-core 团队。虽然这篇文章包含了这些特定框架的大量代码,但这篇文章来自于一种技术不可知论者的心态,试图了解更多关于上述挑战的知识。
1.发展
有多种工具可以解决数据科学家的 ML 实验管理和协作问题,例如 Neptune.ai 、Weights&bias、 Comet.ml 和 mlflow 。这里我们将重点关注 mlflow,它既有一个开源版本,也有一个托管 D atabricks 解决方案。我们可以将 Databricks 部署为我们云基础架构的一部分(无前期成本,按使用付费),从而为我们提供:
- 数据工程工作流的坚实基础(本文不会涉及)。这些数据可能是高度机密的,并且可能是我们不允许保存在本地计算机上的内容,需要这些数据来训练我们的模型。
- 一个可扩展的协作平台,用于在笔记本电脑上运行实际数据的数据科学实验,非常类似于 jupyter 笔记本电脑。
- 用于训练给定 ML 模型的数据和代码的版本控制,以及与模型训练相关的信息(通过工具 Delta Lake、Jobs API 和 mlflow)
- 用户管理,例如,在 Azure Databricks 的情况下,可以与许多公司使用的 Azure AD 链接。这使我们能够非常精细地控制谁可以看到什么,对我们的模型做什么。
要测试 databricks+mlflow,首先要做的是创建一些基础设施。在这种情况下,我们将使用 terraform 部署到 Azure,terraform 是一个跨不同云提供商轻松配置基础设施的工具。我们将保持简单,只需使用以下脚本在一个文件夹中运行 CLI 命令terraform init && terraform apply
:
用于在 Azure 中设置 Databricks 工作空间和 blob 存储容器的 Terraform 脚本。作者代码。
通过 Terraform 运行上面的脚本会在你的 Azure 帐户上设置一个 Databricks 工作区——如果你在 Azure 门户中导航到已创建的 Databricks 资源,你应该能够点击“启动工作区”,这会将你发送到新创建的 Databricks 工作区;到目前为止一切顺利。👌
现在我们已经建立并运行了数据块,我们需要训练一个 ML 模型并将其登录到 mlflow 中-这可以对任何类型的自定义模型进行,但当我们使用流行的框架时,mlflow 提供了许多方便的函数-在这种情况下,我们将利用 mlflow 的魔力,训练一个经典的 Keras 模型来对 MNIST 数据集中的手写数字进行分类。导航到 Databricks 左侧的“Workspace”选项卡,我们可以创建一个笔记本并运行以下代码片段:
使用 Keras 训练 MNIST 分类器并将结果记录到 mlflow 的 Python 代码。作者代码。
注意:为了能够运行笔记本电脑,您必须将其连接到集群,但这可以使用 UI 轻松创建。
2.模型单元测试
数据块使我们能够定义“作业”,这使我们能够用一组输入参数运行给定的笔记本。我们可以使用它来捆绑我们的训练代码,这样当我们希望重新训练我们的模型时,我们只需要重新运行我们的工作,这可以通过一个简单的 REST 请求来完成,而不是手动进入训练笔记本并重新训练模型。我们的模型训练的这种“可操作化”的一个关键部分是,我们在笔记本中包括检查,以确保模型仍然按照预期在例如测试数据集或合成数据集上工作。例如,可以将以下内容添加到我们之前的笔记本中:
在测试数据集上评估我们的模型的代码片段,如果精度太低,则失败。作者代码
在笔记本中添加了这些检查或“测试”之后,我们可以在 Databricks 中创建一个指向笔记本的“作业”。为了重新训练我们的模型,我们简单地告诉作业用笔记本创建一个“run”(这可以在 UI 中或者通过 REST 调用来完成)。
显示我们 MNIST 工作“运行”的屏幕截图——作者提供的屏幕截图。
这正是我们想要的;例如,如果我们在已部署模型的性能开始下降太多时,自动向 Databricks 发送重新训练 REST 请求,但是由于某种原因,自上次训练以来,新的损坏数据被引入到数据集,从而破坏了模型,我们不希望该模型进入生产。
3.版本控制
一旦我们的模型训练完成,我们可以查看本笔记本附带的 mlflow“实验”,在这里我们可以获得作为本笔记本一部分训练的模型的概述以及每个模型的指标和参数(例如,随时间推移的损耗等)。).我们可以点击“源”按钮(见下面的截图),这将显示我们到底是什么代码被用来训练模型;这意味着我们将能够审计生产中的任何模型,以查看是谁以及如何训练它的。
截图显示了我们的两个训练有素的 MNIST 模型的 mlflow 实验。作者截图。
在上面的屏幕截图中,还有一个“Models”列,对于每次运行,mlflow 都创建一个“mlflow model”对象,它在运行结束时封装模型。单击其中一个,我们将进入一个页面,其中包含有关模型的详细信息,包括有关训练期间的损失和准确性、训练参数的信息,最后是一个包含工件的部分,在这里我们可以看到封装的“mlflow model”,其中包含有关模型所需的conda.yaml
环境、训练的模型权重等信息。通过点击“注册模型”按钮,我们可以将这些模型中的任何一个输入到 mlflow 模型注册表中(当然,这也可以在代码中完成)
特定运行的 mlflow 工件的屏幕截图,特别关注于经过训练的 mlflow 模型。
4.模型注册表
一旦我们将一个或多个模型登录到我们的模型注册中心,我们可以在数据块中单击左侧的“模型”选项卡,以便获得我们的模型注册中心的概览,其中包含所有模型及其当前阶段:
来自 Databricks 的模型注册表显示了每个模型、其最新版本、部署阶段等。
这为我们提供了很多透明度,比如当前部署了什么,之前部署了哪些版本,以及到所有模型对象的链接,允许我们检查他们接受了哪些代码和数据的培训,等等。
5.模型治理
对于注册到我们的模型注册中心的每一个经过训练的模型,我们可以控制许可设置,这意味着我们可以控制谁可以看到模型注册中心中的哪些模型,以及谁可以授权从例如阶段到生产的转换;这正是我们想要的,因为我们希望有一个模型进入生产的控制门;例如,创建给定模型的数据科学家的经理可能需要在给定模型过渡到部署之前对其进行验证和批准,检查如下内容:
- 确保根据已知的测试集或通过交叉验证对模型进行了测试,以确认其有效。
- 确保该模型已针对具有已知“信号”的合成数据集进行了测试如果它没有通过这种类型的测试,可能是引入了错误。
屏幕截图显示了模型注册表中给定模型的权限设置,演示了我们如何给不同的用户不同的权限。作者截图。
6.部署
一旦模型注册中心中的模型已经转换到“生产”阶段,下一个阶段就是将该模型推送到部署服务器,以便该模型的消费者可以使用例如 REST API 来调用它。在本帖中,谢顿核心将处理这些部署。简而言之,Seldon-core 将 ML 模型包装并部署到一个 Kubernetes 集群上,Kubernetes 是一个通用的开源系统,用于自动化部署、扩展和管理容器化的应用程序。为了测试所有这些,首先,我们需要一个 Kubernetes 集群,我们可以通过向 terraform 脚本添加一些配置来设置一个 azure 管理的 Kubernetes 集群:
扩展以前的 terraform 脚本,在 Azure 上创建一个 Kubernetes 集群。作者代码。
将上述内容添加到我们之前的 terraform 脚本并重新运行terraform apply
,应该可以用一个非常简单的 Kubernetes 集群来更新我们的基础设施。既然我们已经启动并运行了一个集群,我们需要安装 Seldon-core +相关的包,这可以通过以下命令来实现(取自官方文档):
在我们新创建的 Kubernetes 集群上安装 Seldon-core 的 Bash 命令
就这样👌 ..现在,我们已经有了一个安装了 Seldon-core 的基本 Kubernetes 集群。作为设置的一部分,上面的命令还安装了 Ambassador ,它控制对我们的 Kubernetes 集群的请求,当您运行上面的edgectl install
时,它应该已经打开了您的浏览器到您新设置的 Ambassador 域,这为我们提供了一个很好的界面来检查我们从我们的 Kubernetes 集群公开了什么,它是如何运行的,等等。
我们新集群的大使界面截图。截图由作者拍摄。
既然我们已经建立了 Seldon-core 的基础版本,我们可以开始探索如何部署我们的 mlflow 模型。可悲的是,我们将不得不做一些充实来实现这一点——即,尽管在 Seldon-core 中支持 mlflow 模型,但它不是以一个漂亮的大按钮的形式自动部署我们的模型。但是,请记住,部署模型所涉及的许多步骤都是可以自动化的——我将在下一篇博客文章中更全面地讨论这一点,可以在下面找到:
好吧。我们希望从 Databricks 模型注册表中获取 mlflow 模型,并将其部署到 Seldon-core 中。Seldon-core 确实提供了一个开箱即用的 mlflow 包装器来部署 mlflow 模型,但对我来说,它总是与有问题的模型发生冲突。相反,我采用了一种更加定制的方法,我们需要创建一个与 Seldon 兼容的 docker 映像,我们可以将它部署到 Seldon-core 上。实际上,我发现这更好,因为它将允许我们在后面与漂移和异常值检测相关的章节中探索 Seldon 的更多边缘应用。首先,我们需要从 Databricks mlflow 服务器下载 mlflow 模型:
获取一个 Azure AD 令牌,并使用它根据您的工作区对 Databricks CLI 进行身份验证。
用于将模型从数据块托管的 mlflow 下载到本地文件夹的脚本
使用上面的脚本,我们可以很容易地从 mlflow 下载一个给定的模型,例如,在我的例子中,我运行了python download_mlflow_model.py --model-name “Digit Classifier" --model_stage Production
。这将把训练好的 mlflow 模型下载到一个model/
文件夹中。从这里开始,我们只需要编写一个小的可重用 python 包装器,它让 Seldon 知道如何加载这个 mlflow 模型,并通过定义load()
和predict()
方法来执行预测。这个MyMlflowModel
python 包装器是我们在 mlflow 和 Seldon 之间拥有的接口的核心部分,在这篇文章中我们会多次提到它。
我们的 mlflow 的 Python 接口将由 Seldon-core 使用。模型是从我们的下载器/模型文件夹中加载的。
有了下载的模型和 python 包装器,我们就可以用 mlflow 模型打包一个合适的 docker 映像了。这可以使用命令行工具s2i
轻松完成,它让我们将代码注入到由 Seldon 维护的 docker 映像中:
将我们的 mlflow 模型捆绑在一个 docker 映像中,该映像被推送到 dockerhub
通读 Seldon-core 文档,有多种方法可以在部署之前本地测试这个 docker 映像,例如,通过启动 docker 映像并向其发送请求,或者使用 Seldon-core 提供的各种命令行工具。一旦确认它在本地工作,我们就必须将我们的映像推送到某个容器存储库——在这种情况下,我只使用公共 dockerhub,但我们必须记住,模型也可以是高度机密的,因此在现实世界的设置中,docker 映像存储库的安全性也必须考虑。最后,我们可以使用一个超级基本的 Kubernetes mlflow.yaml
文件将我们训练好的 mlflow 模型推送到我们的 Kubernetes 集群,这个文件是用kubectl apply -f mlflow.yaml
应用的:
我们在 Kubernetes 上部署 mlflow 模型的配置文件
一旦kubectl apply
命令成功,您应该能够转到您的大使端点(例如,https://YOUR _ URL/seldon/mlflow models-namespace/ml flow-Mn ist/API/v 1.0/doc/)来获取您新部署的模型的 REST API 的文档。该页面还将使您能够通过直接从浏览器向 API 发送请求来快速开始测试 API:
显示我们部署的 mlflow 模型的 Swagger UI 的屏幕截图。作者截图。
或者,我们可以使用 python 通过整个测试数据集来访问我们的 API:
用于将整个测试 MNIST 数据集发送到我们部署的模型端点的 Python 脚本。
7.监视
我们部署的 docker 映像自动设置了许多监控样板文件,这些文件公开了大量的指标,这些指标可以被 Prometheus (一种常见的监控解决方案)抓取。Seldon-core 附带了快速设置所有这些的工具,使我们能够在 Grafana 中可视化这些指标。本质上,我们所要做的就是在我们的 Kubernetes 集群上安装seldon-core-analytics
,这可以通过运行以下命令来完成:
Bash 命令用于安装 Seldon-core-analytics 并将 Prometheus 和 Grafana 端口转发到本地主机
使用这些命令,我们在集群上安装了 Prometheus 和 Grafana,并将其端口转发到我们的本地主机,这样我们就可以转到localhost:3001
查看 Prometheus 界面,该界面允许我们发送对所有记录的指标的查询,或者我们可以转到localhost:3000
查看预先填充的 Grafana 仪表板,该仪表板为我们提供请求率、延迟等的概述。,适用于所有当前部署的型号。本质上,使用 Seldon-core 设置监控非常简单,Grafana 可以根据用户的需求和愿望方便地定制仪表盘。
作者提供的图片,展示了 Grafana dashboard 和我们部署的 mlflow 模型。
8.反馈
您可能已经从 Seldon 公开的 API 文档中注意到,它自动公开了一个/feedback
端点和/predict
端点。此外,默认情况下,Grafana 仪表板还提供了一个图表,显示来自我们模型的“奖励”信号。“反馈”和“奖励”使我们能够在部署模型后对其进行评估,因为我们逐渐开始获得带有已知标签的额外数据。在我们知道真实标签的地方获取新数据,我们可以给/feedback
端点发送一个给定的奖励,记录一个模型是表现得好(高奖励)还是差(低奖励)。例如,我们可以通过循环我们的测试数据来测试端点,并根据它的预测情况将奖励发送回模型:
循环测试集,从模型中获得预测,基于性能向模型反馈奖励。
Grafana 仪表板的屏幕截图,显示我们的模型表现良好,由奖励信号确定。
除了直接发送奖励,值得注意的是,我们还可以在 python 模型包装器上覆盖send_feedback()
方法,使我们能够将数据样本和真实标签发送到/feedback
端点,然后在后端计算“奖励”(例如,在准确性方面)——本质上,在如何跟踪实时模型性能方面有很大的灵活性。
注意,我们可以很容易地在 Python 包装器中实现一个阈值,当平均回报低于给定阈值时,它会自动向 Databricks 发送重新训练请求。🚀
9.A/B 测试
当引入新版本的模型时,您可能希望验证它是否比以前的模型更好。因此,我们可能希望在生产中运行 AB 测试,看看哪个模型的性能更好。Seldon-core 使这一点变得非常容易,因为我们基本上只需要将traffic
关键字添加到我们之前的yaml
文件中,并添加另一个预测器。作为一个例子,让我们尝试添加另一个 MNIST 模型,该模型偶然只被训练了一个时期。在全面更换我们的旧型号之前,我们将 80%的流量导向旧型号,20%导向新型号:
这样,80%的流量流向旧模型(版本 0.1),20%流向新模型(版本 0.2),两者都向我们的 Grafana 仪表板报告,在那里我们可以比较它们接收反馈信号时的表现。
在这种情况下,两个模型实际上表现得差不多,因此仅训练 1 个时期的 MNIST 分类器不会导致模型更差,但也不会显著改善结果。然而,在某些情况下,模型实施或训练数据中的错误可能会通过我们之前的所有检查,因此为任务关键型部署执行这些 AB 测试可能是一个好主意,Seldon-core 使它非常容易做到。
10.漂移检测
在这篇文章中选择 Seldon-core 的原因之一是他们维护并集成了库 Alibi-Detect ,该库为漂移检测、敌对攻击检测和异常检测提供了预实现的算法——预实现这些算法可以节省大量时间,因为没有一种算法适合所有人,并且我们自己实现它们会很痛苦。
Alibi-Detect 中的漂移检测算法支持(2021 年 5 月 4 日)
假设我们希望将一种漂移检测算法应用于我们的 MNIST 分类器。为了以 Seldon-core 推荐的方式完成这项工作,我们必须引入另一个工具,即“ KNative ,它允许我们从 Seldon-core API 中提取有效载荷信息,并异步处理它,见下图:
图片来自 Seldon-Core 文档
设置这个有点麻烦,因为它涉及安装 Knative 并设置它与 Ambassador 一起正常工作,训练 Alibi-Detect 模型并将其推送到 blob 存储,最后为我们的模型设置所需的 Knative 资源。不过,最终,在所有的设置之后,部署漂移检测算法并不比向 Kubernetes 应用另一个yaml
文件更复杂,指向预训练的漂移检测算法。
为了保持这篇文章的简洁,我选择不去经历这个棘手的过程,而是提到在谢顿核心文档中有关于如何继续的例子。作为替代,值得指出的是,我们可以选择直接在 python 模型包装类上实现自定义指标,这意味着我们可以在模型本身中包含预训练的漂移检测模型(基于 Alibi-Detect ),从而让它与每个请求同步评估,并在 Grafana 中实时报告漂移。为此,我们可以回到 Databricks 笔记本,训练一个 Kolmogorov-Smirnov 漂移检测算法(检查数据分布的差异):
为 MNIST 数据集训练 KS 漂移检测器并添加到 mlflow 模型伪影
这样,我们就可以将漂移检测算法训练并添加到我们的 mlflow 模型中,然后我们可以将它重新打包到 Seldon-core docker 映像中,并部署到我们的 Kubernetes 集群中。不过,在此之前,我们也将更新我们的 python 包装器类,以便对每个预测执行漂移检测:
添加了漂移检测器的 mlflow 模型的 Python 包装器。
随着这个模型的部署,漂移现在由普罗米修斯刮出,我们可以很容易地在 Grafana 中创建一个显示漂移的图形。我们甚至可以添加警报阈值,这样,如果数据偏离训练数据太远,相关用户就会收到通知。这里有一个例子,最初我给模型输入了大量正常的 MNIST 图像,突然之间,输入了大量失真的样本,这些样本很容易被检测器检测到:
作者截图来自 Grafana 仪表板
这种特定类型的漂移称为“特征漂移”或数据漂移,即输入数据特征的变化。然而,任何其他类型的漂移检测也可以直接在 python 包装器中实现。
11.离群点检测
与漂移检测类似,Alibi-Detect 采用各种算法来识别输入样本是否为异常值。Seldon-core 中推荐的实现类似于漂移检测,因为它涉及设置 Knative 并异步处理给定样本是否为异常值。为了简洁起见,我将再次跳过这个实现,而是链接到文档示例。
Alibi-Detect 中的异常值检测算法支持(2021 年 5 月 4 日)
除了设置 Knative,值得一提的是,与我们如何在 python 模型包装器上实现自定义指标类似,我们也可以实现在预测时返回的自定义标记——因此,我们可以将异常值检测器与模型捆绑在一起,并同步处理进入异常值检测器中的/predict
端点的每个样本。一种想法是,如果样本是异常值,则返回一个标签,声明该样本与预测一起被认为是异常值。如果我们要尝试这样做,我们首先回到我们的 Databricks 笔记本,在那里我们可以训练异常值检测器并将其与我们的 mlflow 模型捆绑在一起:
用于为 MNIST 数据集训练异常值预测值并将其绑定为 mlflow 模型工件的 Python 脚本。
然后,我们只需要将离群点检测器添加到当前的 python 包装器中:
我们的 mlflow 模型的 Python 包装器,增加了漂移和异常值检测器
这样,我们可以将新的 mlflow 模型捆绑到一个新的 Seldon-core docker 映像中,并将其部署到 Kubernetes。当使用明显是异常值的样本(例如,完全白色的图像)向预测端点发送 REST 请求时,我们现在得到以下响应:
当我们发送白色图像时,来自部署具有漂移和异常值检测器的 mlflow 模型的样本响应。
现在,终端用户将立即能够看到,该预测是相当不确定的,因为与训练数据相比,输入数据被标记为异常值。
12.对抗性攻击检测
机器学习算法可能很脆弱,因为通过非常轻微地改变我们给模型的输入,我们有时可以从根本上改变它的输出——我相信你们都在网上看到过这样的例子,对给定图像的细微改变可以改变其分类,例如从熊猫到长臂猿。在 MLOps 的上下文中,我们需要考虑一个坏演员可能会利用我们部署的一些机器学习模型的这一事实,试图确定如何优化算法的预测。根据不同的用例,这可能或多或少很关键。Alibi-Detect 包再次派上了用场,它采用了一种算法来检测使用敌对自动编码器的“敌对”(被操纵)样本,使我们能够在部署的模型遇到异常数量的敌对数据时获得警报。
与异常值和漂移检测一样,我们可以在模型代码中直接包含对抗性检测器;这样做的一个额外好处是,我们不仅可以使用对抗性检测器来检测我们的 ML 模型的攻击,还可以纠正对抗性示例,从而使攻击变得更加困难,详见论文。这一点的实现将非常简单地遵循异常值和漂移检测器的步骤,因此我选择在这里不包括它。
13.可解释性
除了 Alibi-Detect,Seldon 还维护和集成了一个库 Alibi ,它实现了各种用于模型解释的算法(例如,SHAP、集成梯度、锚点等)。这些都是以这样的方式实现的,它们在我们的 REST API 中提供了一个额外的/explain
端点,这样任何感兴趣的用户都可以很容易地查询给定预测的解释。这太棒了,因为这意味着当最终用户对为什么返回给定的预测有疑问时,他不需要手动执行大量的分析,而只需调用/explain
端点。
让我们尝试向我们的 MNIST 模型添加一个“集成渐变”解释器——不同的解释器有不同的要求,但在这种情况下,解释器需要直接访问我们的 Keras 模型——因此,首先,我们将在我们的 Databricks 笔记本中保存模型,并上传到我们最初用 Terraform 创建的 Azure blob:
将我们的 Keras 模型保存到云中 Azure blob 存储的脚本。
注意:我们从 Azure 的存储帐户中获得的AZURE_CONNECT_STRING
。既然我们已经将解释器上传到 blob 存储器,我们可以扩展我们的 Seldon 部署的yaml
-文件以包含explainer
部分:
有了这个,我们就可以向一个端点发送格式为:https://[URL]/sel don/[space]/[name]-explainer/default/API/v 1.0/explain 的请求,我们会收到一个包含每个像素对分类贡献的响应。对给定的样本进行可视化,我们会得到如下的图,显示哪些像素导致了给定标签的给定阳性分类。
使用测试集中的示例图像调用/explain 端点,并绘制返回的解释
结果图显示了发送到解释终点的样本(左)和像素属性(右)
这种方法非常有效,我们可以看到,该模型将重点放在了敏感像素上,以便进行预测。
14.部署治理
重要的是,并非所有用户都可以访问给定的部署模型——基本上,最小特权原则应该始终适用:允许人们做他们需要做的事情,仅此而已。例如,我们可能不希望财务部门的人在一个模型周围闲逛,这个模型是根据 R&D 部门的高度机密数据训练出来的。幸运的是,Kubernetes 周围有很多工具可以解决这些问题,例如,在我们的例子中,我们使用托管 Azure 集群和 Ambassador 例如,我们可以使用 Azure AD 来认证我们的端点;查看此链接了解更多详情。这些安全方面的细节超出了本文的范围,但是解决方案肯定是有的。
就治理而言,一个有趣的复杂情况是,最终端点上的访问权限应该与 Databricks/mlflow 中的模型注册中心内设置的权限一致,因此需要实现一些额外的工具来紧密同步这些权限。这种工具的细节也不在这篇博文的讨论范围之内。
15.数据中心性
最后但可能是最重要的一点是,我们如何改变 MLOps 的主要焦点,使其远离模型、性能、监控等。,并返回到数据。任何在数据科学领域工作过的人都知道,系统地提高数据质量、一致性和广度(涵盖边缘情况)将比追求更复杂和更花哨的模型带来更好的模型性能。
如何构建以数据为中心的 MLOps 管道是一个有点悬而未决的问题,答案取决于使用情形,但一些观察结果如下:
- 反馈监控、漂移检测和异常值识别的实现已经分别告诉了我们一些关于我们的模型在特定新样本上表现如何、它们与我们已经观察到的有多大不同以及我们是否应该怀疑新样本的准确性的信息。在重新训练我们的模型之前,这些是需要记住的重要指标;例如,如果我们确定某个样本是异常值(例如,传感器损坏),我们就不应该将其包含在我们的重新训练中,对于我们知道旧模型表现不佳的样本,我们可能应该在添加到我们的数据集之前进行更彻底的调查。
- 在一些我们可以选择收集什么数据的应用程序中,可以部署一个适合贝叶斯优化的附加模型;这样,部署的模型可以指导用户收集哪些额外的数据点。
- 类似于根据反馈进行重新训练,我们可以很容易地想象这样一种场景:我们收到了如此多的新数据,以至于重新训练模型实际上会提高性能,即使旧模型的性能并没有衰退。因此,不仅模型性能的变化将决定我们何时重新训练,而且可用训练数据的变化也将决定我们何时重新训练。
结论
我经常被希望引入其最新和最棒的 MLOps 框架的公司接洽,仅基于营销材料来评估每种框架的利弊可能相当困难。正如我希望这篇文章所展示的那样,实现一个全面的 MLOps 框架绝不是一项简单的任务,有许多需要考虑的事项和缺陷需要考虑。
本帖中提出的概念验证解决方案涵盖了本帖中提出的 15 个原则的相当多的方面,除此之外,正在讨论的系统(mlflow + Seldon)支持许多其他概念,这些概念也可能与给定的 MLOps 解决方案相关。然而,mlflow+seldon 的解决方案绝不是完美的,当我在这个框架中调试部署以使它们工作时,我不得不经历许多困难。在理想的场景中,我希望数据科学家能够专注于实现符合一些 python 接口实现方法的 ML 模型,如predict()
、feedback()
、drift()
、outlier()
、transform()
等。,然后能够按下一个绿色的“部署”按钮,启动一个自动化的管道,将接口容器化,并部署具有本文中讨论的所有功能的 ML 模型。要求普通市民数据科学家编写和调试 Kubernetes 部署(以及工件部署以保护 blob 存储等。)不太现实。此外,以这种手动方式进行新模型的每一次部署,对我来说似乎都不可扩展或者非常不容易,如果突然需要多人来将一个模型投入生产,就更不容易了。
一种设想是实现一种工具,将 mlflow 与 Seldon-core 更紧密地联系起来。该工具将负责确保只有符合适当接口的模型才能被推送到 mlflow 模型注册中心中的“生产”阶段,并且一旦模型被提升到生产阶段,该工具将负责确保模型得到部署,权限从 mlflow 传播到 Kubernetes,监控功能正常,等等。这种工具的愿景与我在博文中没有过多提及的最后一个原则联系在一起,那就是自动化的原则。从本质上来说,MLOps 框架要被认为是“完整的”,它应该包含我们在 DevOps 等领域看到的所有最佳实践,并自动化所有可以通过代码自动化的事情。
虽然我不认为 mlflow + Seldon 是一个“无缝”的 MLOps 框架,但我确实认为它代表了一个强有力的组合,并且我认为两者都是非常棒的工具。在一天结束的时候,我没有看到一个全面的 MLOps 系统是微不足道的,因此,在我的书中,所提出的解决方案是开源的这一事实是一个巨大的好处,因为这意味着我们可以很容易地自己填补任何缺失的漏洞。
在本系列的下一部分中,我将介绍如何结合使用 Databricks 和 BentoML 来为最终用户创建一个无缝的设置:
SQL 连接入门
使用示例学习左连接、内连接、自连接
为了执行高级分析处理和数据发现,一个表通常不足以带来有价值的见解,因此将多个表组合在一起是不可避免的。SQL 作为与关系数据库通信的工具,提供了在表之间建立关系的功能。本文介绍了如何使用 SQL 将表链接在一起。如果你想学习更多关于 SQL 的基础知识,我建议你读一读我的第一篇关于用日常语言学习 SQL 的文章。它为绝对初学者提供了全面的 SQL 介绍。
为什么我们需要学习 SQL 连接
也许你还没有意识到,我们也经常遇到加入 Excel。这是通过 VLOOKUP 函数实现的,如下所示。VLOOKUP 函数允许我们执行一列的匹配,并从另一列返回相应的参考值。在这种情况下,我们可以通过将国家代码与国家代码表中的 fips 代码进行匹配,找到与每个标准相关的国家名称。
excel 中的 vlookup(图片由作者提供)
当一个表中的信息不够时,我们可能会遇到许多这样的情况。SQL join 使用完全相同的逻辑,但是它更强大,因为它匹配并合并两个或更多的表,而不是两列。在下一节中,我们将深入探讨如何使用 SQL 来解决这个问题。学习 SQL join 还有一个很实际很现实的原因就是面试!没错,SQL join 几乎是任何一个数据科学家或者数据分析师面试中不可避免的问题。有些问题比较理论化,比较露骨,“能告诉我左连接和内连接的区别吗?”;还有的比较实际含蓄“能不能写一个 SQL 语句,找到这个员工的经理的名字?”所以这给了你另一个理由去学习和区分每一种连接的实现。
如何创建联接
SELECT <attributeName>, <attributeName>, <attributeName>, ...
FROM <TableA>
<LEFT|INNER|FULL OUTER|...> JOIN <TableB>
ON <TableA.commonAttribute> = <TableB.commonAttribute>
SQL join 遵循这个语法,我把它分成三个部分: 1)选择属性和表;2)确定连接条件;3)选择合适的连接类型。
属性和表格
和其他 SQL 语句一样,需要以SELECT <attribute> FROM <table>
的形式指定属性和表名。但是不同之处在于需要连接多个表。如果相同的属性名称存在于多个表中,那么简单地通过名称引用属性将是不明确的,因为数据库不确定您从哪个表中选择该属性。为了解决这个问题,我们需要使用表名作为属性前缀。
例如,如果名称属性同时存在于客户和国家表中,我们只选择客户名称。然后我们将该属性称为“ Customer.name”。
连接条件
表通过至少一个公共属性连接在一起。这个公共属性通常被称为外键。如 excel 示例所示,VLOOKUP 函数也利用了这个共享属性。我们使用这个共享属性(外键)作为匹配点,在这里我们可以找到另一个表中每一行的相应信息。这个公共属性需要作为 SQL 语句中的连接条件显式地表示出来。
国家代码示例(图片由作者提供)
让我们继续这个国家代码的例子。本练习的目的是在“Google_Ads_GeoTargets”表中找到每个标准的国家名称。这些数据集来自谷歌公共数据集。如果有兴趣,可以尝试在 BigQuery 中实现它。
在左侧表格中,我们已经获得了每个标准的国家代码,并且国家代码表格为我们提供了国家名称 fips_code 。因此,逻辑是将 GeoTarget 表中的 country_code 与 Country_Code 表中的 fips_code 进行匹配,找到对应的名称。 country_code 和 fips_code 是建立两个表之间关系的公共属性。
我们写下下面的语句来表示连接条件。注意,最好使用表名作为属性前缀,并且不要忘记关键字“on”:
ON Google_Ads_GeoTargets.country_code = Country_Code.fips_code
连接类型
还有五种主要的连接类型:左连接、内连接、全连接、自连接、和交叉连接。为了与数据库通信,我们需要在语句中显式或隐式地指示连接类型。这是通过使用关键字“左连接”、“内连接”或“全外连接”等实现的。每种类型都有其独特的用例。希望下面的比较能帮助你区分它们的细微差别。
1。左接合
左连接与 excel 中的 VLOOKUP 最相似。右边的表可以被看作是一个参考表或者一个字典,从这里我们扩展了左边表中存储的现有知识。因此,采用左连接来返回左表中的所有记录,并从右表中引用相应的值。左连接还可以让我们更深入地了解为什么有些值找不到匹配项。例如,是因为左表中的记录不正确或打字错误,还是因为右表中的数据不完整?
我们用这个语句生成左连接结果如图所示:
SELECT criteria_id, country_code, country_name, fips_code
FROM Google_Ads_GeoTargets gt
LEFT JOIN Country_Code cc
ON gt.country_code = cc.fips_code;
左连接结果(作者图片)
来自 Google_Ads_Geo_Targets 的所有行都作为结果返回,即使有些行与 Country_Code 表不匹配(因此返回 null)。
你可能想知道为什么大部分时间都没有必要使用右连接。这是因为右连接可以通过交换表的方向和执行左连接来实现。
此外,右表往往被视为一本参考书。在这种情况下,Country_Code 表被视为一个引用或字典。没有必要返回所有 fips_codes 的匹配。想想我们碰到一个新单词的情况。我们会在字典中找到这个单词的意思,而不是在字典中查找每个单词来匹配我们所输入的单词。范围将过于宽泛和模糊。
2。内部连接
当我们对表的交集感兴趣时,内部连接很有用。因为它只显示存在于两个表中的记录,所以内部联接通常返回最少的行数。如下面的结果所示,所有空值都被过滤掉了。我们使用 INNER JOIN 关键字来表示这种连接类型:
SELECT criteria_id, country_code, country_name, fips_code
FROM Google_Ads_GeoTargets gt
INNER JOIN Country_Code cc
ON gt.country_code = cc.fips_code;
内部连接结果(图片由作者提供)
3。完全外部连接
完全外连接覆盖两个表中的每一行,不管是否找到匹配。它用于全面掌握存储在两个表中的信息,并找出任何不匹配的地方。在本例中,第一行对于 country_name 和 fips_code 显示为 null,因为在 Country_Cod e 表中没有匹配的 fips_code = "AZ" 。另一方面,最后一行没有 criteria_id 和 country_code ,因为在 Google_Ads_GeoTargets 表中没有带有 country_code = "ZA" 的标准。
完整的外部连接结果(图片由作者提供)
要写下完整的外部联接语句,请执行以下操作:
SELECT criteria_id, country_code, country_name, fips_code
FROM Google_Ads_GeoTargets gt
FULL OUTER JOIN Country_Code cc
ON gt.country_code = cc.fips_code;
4。自连接
自连接意味着将表链接到自身,我们应用它来处理一元关系。这是强大的创建层次关系,例如,雇员和经理,类别和子类别等。最终,它仍然可以被看作是将两个表连接在一起。
员工示例(图片由作者提供)
我用一个员工的例子来解释自我加入。在这个例子中,如果我们想要找到每个雇员的经理姓名,我们需要使用一个自连接来找到每个雇员的经理的姓名,并且我们使用 managerID 来派生该姓名。在 ERD 图中,manageid 被表示为外键,因为它是从 employeeID 中借用的。
员工示例 ERD(图片由作者提供)
SELECT e.employeeID AS employee ID, e.name AS name, m.name as manager
FROM Employee e
LEFT JOIN Employee m
ON e.managerID = m.employeeID
如 ERD 中所示,我们可以将经理表视为雇员的子集,因此这种自连接相当于将雇员表左连接到其子集经理。连接条件是雇员表中的经理 ID 需要等于经理表中的雇员 ID ,因此 e.managerID = m .雇员 ID 。对于自连接,我们仍然需要考虑什么是连接类型。在这种情况下,我们希望显示所有员工记录,即使他们没有经理(例如,员工 3 和 6),因此需要一个左连接。值得注意的是,需要对表进行重命名,以清楚地表明您引用的是哪个表中的哪些属性。此外,我们可以使用 AS 关键字将属性重命名为可读的内容。
自连接结果(图片由作者提供)
5。交叉连接
我会说交叉连接是最不合理的连接,因为它没有任何连接条件。
SELECT criteria_id, country_code, country_name, fips_code
FROM Google_Ads_GeoTargets gt
CROSS JOIN Country_Code cc;
交叉联接将一个表中的每一行与另一个表中的所有行进行匹配,如下例所示。带有 criteria_id = "1000998" 的地理目标标准与 Country_Code 表中的所有记录匹配。下表并不详尽,但我们可以计算出总共有 42 行(7 行谷歌广告标准 x 6 行国家代码)。当表中有重复的行时,我们可能会意外地创建交叉连接。因此,在预处理数据时,消除重复行是非常重要的。我将在下一篇文章中更详细地解释这一点,如果感兴趣,请继续关注:)
交叉连接的计算成本很高,应尽可能避免。我能想到的唯一用例是在两个表中填充所有记录的组合,例如,size x color。如果您对交叉连接用例有任何建议,请在下面评论。
交叉连接插图(图片由作者提供)
交叉连接结果(图片由作者提供)
带回家的信息
本文的主要内容是将 SQL 连接归结为三个步骤:
- 选择表和属性
- 2.确定连接条件
- 3.从左联接、内联接、自联接和完全联接中选择适当的联接类型
希望这篇文章能帮助你通过结合表格将基本的 SQL 技能提升到更高级的分析。
相关文章
https://www.visual-design.net/post/learn-sql-in-everyday-language https://www.visual-design.net/post/five-data-science-podcasts-to-follow-in-2021
原载于 2021 年 1 月 4 日 https://www.visual-design.net**。
让你的人工智能道德方法论透明化
从道德实践的“为什么”到“如何”
照片由 Anh Vy 在 Unsplash 上拍摄
所以你已经听说了人工智能伦理及其在构建符合社会价值观的人工智能系统中的重要性。你选择踏上将负责任的人工智能原则融入你的设计、开发和部署阶段的旅程,可能有许多原因。但是,我们之前在这里讨论过这些,你会在其他地方找到大量的文献来阐述为什么你应该这样做。
我想花点时间谈谈你应该怎么做。我想专注于其中的一个方面:你的人工智能伦理方法论的透明度。
我认为有一个非常强有力的理由来说明为什么我们需要对我们的人工智能道德方法论保持透明,特别是因为它将帮助你更好地定位自己,以在高度竞争的环境中吸引稀缺的人工智能人才,展示成熟度,提高客户信任,并降低反馈障碍。
因此,让我们深入到这些领域中的每一个,并了解你的人工智能道德过程透明的好处:你会做得更好,你将能够做得更多!
1.在有限人工智能人才的竞争中胜出
正如 ElementAI(现在是 ServiceNow 的一部分)的全球人工智能人才报告中多次提到的那样,人工智能人才继续向世界上的某些地区倾斜。即使在这些地区,人口也高度集中在少数几个地区,人口构成非常有限,导致了多样性问题。进一步加剧所有这些问题的是,那些不是最大的人工智能公司的有限能力,无法吸引和留住能够创造和提供功能良好、高性能人工智能系统的顶级人才。另一个需要考虑的方面是,我们目前对西方伦理方法论的关注要比对伦理框架的考虑更加全球化和多样化。
但是,这不应该成为绝望的理由!
越来越多的证据表明,技术专家正在认识到他们的工作对社会的影响,因此,它可以成为一个区分因素,让你展示你拥有人工智能道德方法论,即使它是新生的,因为它有助于求职者筛选出并专注于与他们的价值观一致的机会。
有时,组织选择保持他们的人工智能道德过程的私密性,通常是因为他们不确定它会被如何看待,以及他们是否会因为它的当前状态而受到惩罚。然而,它可以为求职者提供一个关于你正在做的工作的强烈的市场信号。你计划做的工作可能会帮助你的组织与更大的组织竞争类似的工作,但不同的是,你会思考如何以一种审慎的方式管理你的工作的社会影响。
因此,它可以帮助您用同样多的资源做更多的事情,并通过吸引关心这些问题的顶级人才来帮助您走得更远!
2.展示成熟
阻碍组织的事情之一(除了对法律后果的担忧之外)是他们对他们的过程缺乏信心,并且害怕他们可能被认为是不成熟的,尤其是在过程开发和利用的早期阶段。
使流程公开透明展示了组织的成熟度,也有助于您学习并与您所在行业的同行组织分享最佳实践。这是一项团队运动,我们不会有一个单独的组织能够独自找出所有的答案。对你的过程保持透明,并分享它在哪里工作,在哪里失败,将有助于整个生态系统更快地成熟,帮助你在负责任的人工智能工作中走得更远,更有效。
3.提高客户信任度
当客户四处寻找他们可以雇佣的不同公司为他们工作时,比如说引入外部专业知识来帮助将人工智能能力注入他们现有的产品中,有许多选项可供选择。事实上,这些选择与日俱增!
那么,当顾客在四处观望时,我们如何用我们的产品吸引他们呢?
这些客户中的一些人关心他们的工作对社会的影响,随着他们的用户和客户表现出更强的意识并使用他们的钱来支持他们的信念,越来越多的组织开始关注这一点。
通过对你的人工智能道德方法论保持透明,你向正在寻找合作伙伴的客户发出了一个明确的信号,即你不仅在名义上关心这些想法,而且已经给予足够的思考来将这些想法付诸实践。在过去的几年里,我们已经看到了很多很多的文档出现谈论原则,但是很少关注实施策略,这是生态系统中的参与者注意到并呼吁的事情。
事实上,我即将出版的新书《 可操作的人工智能伦理 》正在帮助人工智能从业者弥合这一鸿沟!
你可以具体地提升客户的信任,这将对你的组织的底线产生直接影响,并利用这一点作为在你的组织中吸收和组织人工智能道德努力的号角。这是一种很好的方式来提高你的工作的影响(从社会的角度来看),并帮助你建立长期的可持续性,因为你的客户信任你做正确的事情,他们可以通过你实施的人工智能道德流程来验证这一点。
4.降低反馈障碍
当你的过程透明时,征求和接受反馈就变得更加容易。
征求反馈变得更加容易,因为人们可以在你的流程中提出他们的反馈,他们可以评估这是否有效。这也清楚地表明,你有反馈渠道,表明你对你的过程有信心,并致力于随着时间的推移改善它。对于那些希望提供反馈的人,他们知道在哪里可以这样做,这是建立用户和客户信任的另一个途径。
正如我们从上面的讨论中看到的,让你的人工智能道德方法论透明化有很多好处:
- 在有限人工智能人才的竞争中胜出
- 展示成熟
- 提高客户信任度
- 降低反馈障碍
我强烈建议你走这条路,把你的人工智能道德反馈透明化!我总是乐于与你进行简短的交谈,就你的过程向你提供建议,并从什么有效和什么无效中学习。不要犹豫,通过蒙特利尔人工智能伦理研究所联系我。
我很乐意听到更多关于你正在做什么来将你的组织的人工智能道德方法论公开化,以及如果这些点是你已经付诸实践的事情。
在这里注册以获得关于可操作的人工智能伦理书的更新!你可以在这里了解更多关于我的作品!
你可以通过订阅人工智能伦理简报从蒙特利尔人工智能伦理研究所了解更多这样的见解!
让您的 Conda 环境在 Jupyter 笔记本电脑上展示——简单的方法
(还有一些其他方式……)
美国宇航局在 Unsplash 拍摄的照片
当我第一次开始使用 Jupyter 笔记本时,我花了比我愿意承认的更长的时间来弄清楚如何让我的 conda 环境内核显示在内核列表中。当我成功时,我并不满意,因为我希望它是自动的。像大多数事情一样,一旦你知道怎么做,两者都很简单。
下面我将展示三种方法,每种方法都最适合特定的场景。
方法 1:“简单的方法”
这是我的首选方法,因为它简单。新环境会自动出现(只要它们安装了ipykernel
。)
在撰写本文时,
nb_conda_kernels
还不支持 Python 3.9。这只会影响我们的基本环境,我们在任何工作中都不会用到它,对吗?😃.您的其他环境可以使用任何 Python 版本,包括 3.9。
最初,您的内核列表(在 Change kernel 下)将只显示您当前的环境。
作者图片
要让您的其他环境内核自动显示:
1.首先,在您的基础环境中安装nb_conda_kernels
。一旦安装完毕,任何从基础环境运行的笔记本都会自动显示任何其他安装了ipykernel
的环境的内核。
(base)$ conda install nb_conda_kernels
2.接下来,创建一个新环境。我会叫我的new-env
。如果您已经有了一个想要在 Jupyter 笔记本上展示的环境,请跳过这一步。
(base)$ conda create --name new-env
3.激活您想要在笔记本中使用的环境,并安装iypkernel
。我的环境叫new-env
。如果您已经有了一个环境,用您的环境名称代替new-env
(base)$ conda activate new-env(new-env)$ conda install ipykernel
4.从您的基本环境重新启动 Jupyter 笔记本电脑,完成。你可以在这里看到我所有安装了 ipykernel 的环境,包括new-env
都显示出来了。我现在可以随意在它们之间切换。极乐世界。
作者图片
方法二:“通常的方式”
单独注册您想要在内核列表中显示的每个环境并不难。如果您有许多环境,这可能更好,因为它允许您注册和取消注册您的环境内核,这有助于保持列表整洁。
- 记下您的环境正在使用的 python 的位置。一些 os/python 版本组合引入了一个路径问题,如果你知道它的存在,这个问题很容易解决。
(new-env)$ which python
/opt/homebrew/Caskroom/miniforge/base/bin/python <- yours may be different.
2.在您的新环境中安装ipykernel
(new-env)$ conda install ipykernel
3.检查您的 python 位置。
(new-env)$which python
/opt/homebrew/Caskroom/miniforge/base/bin/python
如果 python 位置与第一步中的位置不匹配,您需要在继续之前停用并重新激活 conda 环境。
(new-env)$conda deactivate new-env
(base)$conda activate new-env
(new-env)$which python
/opt/homebrew/Caskroom/miniforge/base/bin/python <- this should match step 1
2.使用下面的命令向 Jupyter 注册内核规范。--name=
参数将为这个环境的内核设置您在 Jupyter 笔记本上看到的名称(因此您可以随意命名它,但是使用环境的名称可能是明智的)。
(new-env)$ipython kernel install --user --name=new-env
3.现在new-env
将会显示在你的内核列表中(不需要重启 Jupyter Notebook——只需要在你的浏览器中重新加载页面)。
作者图片
4.当您想要取消注册内核规范(从可用内核列表中删除环境内核)时,使用以下命令:
$jupyter kernelspec uninstall new-env
方法三:“快速肮脏的方法”
这个方法实际上并没有让你的环境在 Jupyter 笔记本上显示出来,但是值得注意。如果你在任何环境中安装jupyter
并从该环境中运行jupyter notebook
,笔记本将使用活动环境中的内核。内核将以默认名称Python 3
显示,但是我们可以通过执行以下操作来验证这一点。
- 激活您的环境,安装
jupyter
,运行jupyer notebook
。
(base)$ conda activate new-env
(new_env)$ conda install jupyter
(new_env)$ jupyter notebook
2.在您的笔记本中运行以下代码,以确认您使用的是正确的内核
import os
print (os.environ['CONDA_DEFAULT_ENV'])
作者图片
结论
最后,你如何选择在 Jupyter Notebook 中与你的内核交互应该基于你的特殊需求,而不是缺乏关于你的选择的信息。希望这篇文章有助于消除后面的。
去做好事吧。
参考资料:
我觉得这个栈溢出答案的评分不够高(去投上一票吧,以示对 lumbric 贴上回答自己问题的答案的一点爱)。这是我对这个主题最初理解的基础。
https://stackoverflow.com/questions/58068818/how-to-use-jupyter-notebooks-in-a-conda-environment
将您的双脚浸入 Power BI
数据科学工具
微软分析工具的实践介绍。
雅各布·鲍曼在 Unsplash 上的照片
作为一名数据科学家,你迟早需要学会适应分析工具。在今天的帖子中,我们将深入学习 Power BI 的基础知识。
请务必点击图片,以便更好地查看一些细节。
数据
我们将在今天的实践教程中使用的数据集可以在https://www . ka ggle . com/c/insta cart-market-basket-analysis/data找到。该数据集是“一组描述客户订单的相关文件。"下载 zip 文件,并将它们解压缩到本地硬盘上的一个文件夹中。
下载 Power BI 台式机
如果你还没有,去 https://powerbi.microsoft.com/desktop点击“免费下载”按钮。
如果你使用的是 Windows 10,它会要求你打开微软商店。
继续并点击“安装”按钮。
让我们点击“启动”按钮开始吧。
一千次点击
出现闪屏时,点击“获取数据”。
截图来自埃德纳林·c·德·迪奥斯
你会看到很多文件格式和来源;让我们选择“文本/CSV”并点击“连接”按钮。
选择“order_products_prior.csv”并点击“打开”按钮。
下图显示了数据的样子。单击“加载”按钮将数据集加载到 Power BI Desktop 中。
通过选择“获取数据”并在下拉菜单中选择“文本/CSV”选项来加载数据集的其余部分。
您应该将这三个文件加载到 Power BI Desktop 中:
- order_products_prior.csv
- orders.csv
- 产品. csv
您应该会在 Power BI Desktop 的“Fields”面板上看到以下表格,如下所示。(注:图像显示的是报表视图中的电量 BI。)
截图来自埃德纳林·c·德·迪奥斯
让我们点击 Power BI 桌面左侧的第二个图标,看看数据视图是什么样子。
现在,让我们看看模型视图,在这里我们将看到不同的表是如何相互关联的。
如果我们将鼠标悬停在某一行上,它会变成黄色,相应的相关字段也会高亮显示。
在这种情况下,Power BI Desktop 很聪明地推断出了这两种关系。然而,大多数时候,我们必须自己创造关系。我们将在以后讨论这个话题。
让我们回到报告视图,仔细检查“可视化”面板。寻找“切片器”图标,它看起来像一个正方形,右下角有一个漏斗。单击它可以向报告添加一个可视化内容。
在“Fields”面板中,找到“department_id”并单击其左侧的复选框。
截图来自埃德纳林·c·德·迪奥斯
这将导致“部门标识”字段出现在“字段”框中的“可视化”面板下。
接下来,将鼠标光标悬停在报告视图的右上角。点击出现在角落的三个点,如下所示。
在出现的下拉菜单中点击“列表”。
当“department_id”视觉对象被选中时,您应该会看到指示该视觉对象为活动视觉对象的角标记。当“department_id”处于活动状态时,按 CTRL+C 复制它,然后按 CTRL+V 粘贴它。将新的视觉效果移到原始视觉效果的右侧。
通过单击第二个视觉对象内部的某个位置来激活它。然后在 Power BI Desktop 右侧的“Fields”面板中查找“aisle_id”字段,如下所示。
尝试在“部门标识”上选择一个值,并观察“通道标识”上的选择如何相应变化。
截图来自埃德纳林·c·德·迪奥斯
截图来自埃德纳林·c·德·迪奥斯
现在,再次检查“可视化”面板,并点击如下所示的表格可视化。
在“字段”面板中,选择“产品标识”和“产品名称”,或者将它们拖到“值”框中。
Power BI Desktop 看起来应该类似于下图。
这一次,尝试从“department_id”和“aisle_id”中选择一个值,观察右边的表格视图会发生什么变化。
让我们通过复制和粘贴表格视图来创建另一个视图。这一次,选择(或拖动)以下字段到可视化的“值”框中。
- 订单 id
- 用户标识
- 订单编号
- 订单时间
- 订单 _dow
- 天数 _ 自 _ 前 _ 顺序
Power BI Desktop 现在看起来应该类似于下图。
尝试单击可视表格中的一个选项(显示“product_id”和“product_name”),并观察右侧表格如何相应变化。
为了仔细观察,通过点击如下所示的图标激活聚焦模式。
截图来自埃德纳林·c·德·迪奥斯
该表显示了订单的详细信息,这些订单包含您在表中选择的带有“产品 id”和“产品名称”的产品
点击“返回报告”退出聚焦模式,如下所示。
让我们通过右键单击页面名称(“第 1 页”)并选择“重命名页面”来重命名此页面或选项卡
键入“产品”并按回车键。
让我们通过再次右键单击页面名称(“产品”)并选择“复制页面”,向报告添加另一个页面或选项卡
将新页面重命名为“TRANSACTIONS ”,并删除(或移除)最右边的包含订单详细信息的表。
更改左上角的视觉效果,并更新字段,如下所示。当左上角的图标被激活时,“Fields”框应该显示“order_dow”。
移动视觉效果,使其看起来与下图相似。
截图来自埃德纳林·c·德·迪奥斯
对下一个画面做同样的事情。这一次,选择“order_hour_of_day ”,您的 Power BI 桌面应该会像下图一样。
截图来自埃德纳林·c·德·迪奥斯
对最后一个表做最后一次同样的操作,现在它应该包含如下所示的字段。
让我们通过单击报告主工作区底部的“+”图标,向报告添加另一个页面或选项卡。
基础探索
在“可视化”面板中,选择“堆积柱形图”
拖动移动手柄来调整图表的大小。
确保“轴”框中分别包含“order_dow”和带有“order_id”的“值”框。Power BI Desktop 应自动计算“order_id”的计数,并将该字段显示为“order_id 计数”,如下所示。
上图很有趣,因为它显示了第 0 天和第 1 天的订单数量较高。
让我们再做一个图表。
我们将遵循添加图表的相同步骤,这一次,我们将在“轴”框中使用“order_hour_of_day”,如下所示。
该图显示了订单数量的峰值时间。
最后一张图!
我们将在“轴”框中添加另一个带有“days_since_prior_order”的图表。
最后一个图是最有趣的,因为再订购的数量在这三个时间段达到峰值:自前一次订购后的 7 天、14 天和 30 天。这意味着人们习惯于每周、每两周、每月补给一次。
就这样,伙计们!
在下一篇文章中,我们将“美化”我们的图表,使它们对其他人更具可读性。
上面的程序已经被拉长了。但是如果你是一个初级的 BI 用户,不要绝望!通过定期练习,本文中演示的概念将很快成为你的第二天性,你很可能在睡梦中也能做到。
感谢您的阅读。如果你想了解更多关于我从懒鬼到数据科学家的旅程,请查看下面的文章:
如果你正在考虑改变方向,进入数据科学领域,现在就开始考虑重塑品牌:
敬请期待!
获得有趣的机器学习项目
机器学习项目会给你更多的技术实践经验
来自 Pexels 的 Jules Amé 的照片
我们现在生活在一个越来越被机器学习、人工智能、物联网等新兴技术主导的时代。
特别是机器学习,它已经影响了我们所有人的生活,并在许多方面比我们想象的更聪明。由于它的人气飙升,我们今天使用的大多数数字服务都以这样或那样的方式依赖于机器学习,这使它成为最好和最有用的技术之一。
如果你也对机器学习的能力印象深刻,并且已经开始了解它,为什么不更进一步,在常规的理论方法之外,还包括一种更实用的方法呢?
在本文中,我们将分享 10 多个机器学习项目,这些项目将让您对该技术有更多的实践经验,从本质上加快您的学习。
机器学习项目
当你在学习技术的过程中,你一定会问自己为什么要从事一个实用的机器学习项目。
答案在于软件开发的本质。任何软件开发人员都必须通过尝试开发现实世界问题的实用解决方案来深入他们正在学习的技术,机器学习也是如此。
尽管实际上有成千上万的应用程序在使用机器学习,但为了帮助你 开始使用技术 ,我们在下面列出了一些对初学者友好的应用程序。
1.鸢尾花分类 ML 项目
凯文·卡斯特尔在 Unsplash 上拍摄的照片
鸢尾花分类是另一个简单的机器学习项目,适合初学者。这个项目通常被视为最古老也是最简单的机器学习项目,现在它已经获得了“Hello World”的称号。军情六处的世界。
鸢尾花分类项目主要处理根据其萼片和花瓣的宽度和高度将鸢尾花分类为该项目使用的三个物种之一,即 Setosa、Versicolor 或 Virginica。
该项目还鼓励 ML 新手掌握构建机器学习应用程序的最基本步骤之一,即加载和处理数据。该项目的数据集也非常轻量级,包含大约 150 个示例,可以帮助您训练分类模型,而不用担心内存限制。
- 你可以从 GitHub 获得源代码。
- Iris 数据集也可以从 UCI ML 资源库下载— Iris Flowers 数据集。
2.使用智能手机数据集的人体活动识别
现代智能手机配备了一系列传感器,可以检测环境光、运动等一系列事情。智能手机、智能手表、平板电脑和智能手环都使用这些传感器来识别用户试图做什么,当与智能软件配合使用时,它们可以非常准确地建议适当的行动。这个有趣且对初学者友好的项目是围绕同样的想法建立的。
在人类活动识别项目中,您将学习如何构建一个分类模型,该模型将尝试预测用户正在进行的身体活动,如跑步、步行、骑自行车以及许多其他活动。
该项目的数据集是从智能手机的加速度计和陀螺仪中捕获的,涵盖了坐、站、走、上楼下楼和躺等活动。它是经过预处理的,所以你不需要在它上面花费任何时间。一旦经过训练,您应该能够更准确地预测用户活动。
你也可以利用这些数据在健身或医疗保健领域建立一个有趣的项目。
3.BigMart 销售预测 ML 项目
Artem Beliaikin 在 Unsplash 上拍摄的照片
机器学习还能够对数据集执行销售预测,这是您将在本项目中学习的内容。这个对初学者友好的项目将教你无监督机器学习算法如何工作,以及你如何使用它们来预测企业的销售。
您将使用 2013 年的 BigMart 销售数据集,其中包含 10 家不同商店的 1500 多种产品的数据。数据集包含所有产品的特定属性,如脂肪含量、MRP、重量、出口尺寸、出口位置等。
就像 BigMart 一样,这个数据集可以帮助你了解他们产品的各种属性,同时还可以指出在提高他们的整体销售额方面发挥关键作用的商店。这里的目标是建立一个回归模型,预测未来几年 10 个销售点的所有 1500 多种产品的销售额。
您可以在此访问销售数据集。
4.了解社交媒体帖子背后的“情绪”
数百万人使用社交媒体分享他们对各种话题的看法,使这些平台成为一个极其庞大和多样化的数据收集宝库。
您可以将所有这些数据用于一个名为情绪分析的有趣的 ML 项目。它本质上分析了社交媒体帖子背后的人们的情绪,并确定他们是积极的还是消极的。
以 Twitter 为例,每秒钟它都会收到成千上万条包含各种数据的推文,比如位置、姓名、想法、标签、用户名等等。
你把所有的数据放在一起,你会有一个数据集,你甚至可以用它来研究一个正在进行的趋势,或者发现人们对任何给定主题的看法。企业可以利用这个项目来改进他们的产品、客户服务,甚至计划他们的下一次产品发布。
关于情感分析的 TEDx 演讲—
5.股票价格预测
我们名单上的下一个最热门的 ML 项目来自金融领域,涉及预测企业的股票价格。
根据一个组织在现实世界中的成功,它的股票价格可能会非常频繁地上涨或下跌。为了更好地预测他们的股票价格,组织总是在寻找可以有效做到这一点的现代工具。
幸运的是,ML 驱动的股票价格预测工具能够轻松地进行股票价格预测。这些工具通过使用数据集来工作,这些数据集考虑了一系列过去的股票相关数据,如开盘价和收盘价、交易量、波动指数和许多其他价格因素。
简而言之,这些股票价格预测工具分析一个组织过去和当前的全部表现来预测他们股票的未来价格,这也使他们能够将任何潜在的风险降至最低。
6.使用 Movielens 数据集的电影推荐
推荐系统已经成为所有主流媒体提供商的最爱,如网飞、亚马逊、Hulu、苹果,甚至更多。
这些推荐系统是使用大量的 ML 算法 构建的,这些算法向用户建议他们接下来可能想看什么。该系统所要做的就是分析你喜欢什么类型的电影,你看了多少,以及一些其他因素。之后,他们会开始向你推荐更多由底层 ML 算法推荐的电影。
有大量的数据集可以用来创建这样的推荐系统,而 MovieLens 数据集 就是其中之一。MovieLens 数据集由超过 2500 万个电影评级和超过 100 万个标签应用组成,涵盖由 16.2 万个用户创建的超过 6.2 万部电影。如果您想尝试创建推荐系统,我们建议您尝试一下 MovieLens 数据集。
另一个好的推荐系统是 Youtube 趋势视频统计。
7. MNIST 手写数字分类
机器学习已经用于一系列涉及语音、图像和文本识别的项目,这个项目也来自类似的类别。
在这个项目中,你将学习如何训练你的机器学习模型识别手写数字。在这个项目中,你将使用一个巨大的手写数字数据库,以及机器学习以简单易懂的方式提供的各种其他学习和模式识别技术。
为了使这个项目更轻便,更适合新手,它使用了一个 MNIST 或修改的 NIST 手写数字数据库,可以轻松地加载和处理,而不用担心任何预处理和格式化。
MNIST 或修正 NIST 数据库在其训练集中包含大约 60000 个手写数字示例,在其测试集中包含大约 10000 个示例,这应该足以让您开始您的第一个模式识别项目。您可以在此访问 MNIST 数据集。
8。假新闻检测
互联网在向数百万人提供各种新闻和有用信息方面发挥着关键作用,但当今互联网上最常见的问题之一是假新闻。
在像 ML 和 AI 这样的技术到来之前,任何一条编造的新闻都会像野火一样在互联网上传播,在人民中间造成大量的恐慌和混乱。
但现代的 ML 和 NLP 解决方案已经变得足够强大,可以筛选大量的新闻,以识别和阻止任何假新闻到达更多的用户。如果所有这些对你来说都很有趣,你绝对会喜欢这个项目。
在这里,您将使用朴素贝叶斯分类器构建一个模型,它将进行文本分类,并将真实的新闻与虚假的新闻分开。对于数据集,你可以从互联网上的真实和虚假的新闻数据集中挑选。
9.乳腺癌预测
近年来机器学习的改进已经允许它广泛用于医疗保健行业,以预测和检测几种疾病,其中之一是癌症。
乳腺癌,特别是,是一种非常常见的癌症,影响了全球许多女性,虽然治疗是可能的,但很大程度上取决于疾病的早期检测。
这就是乳腺癌预测项目的由来。这个 ML 项目旨在教授如何使用像线性支持向量机、高斯朴素贝叶斯、 k 近邻和 C 分类和回归树这样的技术来创建一个基于给定数据的模型,该模型将能够预测症状是否会导致乳腺癌。
数据集中已经提供了半径、纹理、平滑度、对称性、凹度、面积等所有特征,以便您开始使用。
10.房价预测项目
Terrah Holly 在 Unsplash 上拍摄的照片
对任何人来说,买房都是最具挑战性的决定之一,这背后的原因很简单。除了价格本身,还有许多因素要考虑。
你有小巷类型,地段面积,街道类型,土地坡度,屋顶风格,基础类型,屋顶材料,中央空调系统,围栏质量,以及 64 个其他类似的复杂变量,我们大多数人经常忽略。
在这个机器学习项目中,你将使用 ML 中的回归技术建立一个模型,例如随机森林和梯度推进,以准确预测各种房屋的最终价格。您可以从 Kaggle 获得数据集,它将涵盖训练数据和测试数据,以帮助最大化模型的整体准确性。
房价预测项目数据集—
11.葡萄酒质量预测
照片由 Hernán Santarelli 从 Pexels 拍摄
葡萄酒鉴赏家总是在寻找葡萄酒的完美混合,但这听起来很容易,实际上很难。当然,葡萄酒的年份对它的味道影响很大,但这里还有许多其他因素需要考虑。讨论的因素包括固定酸度、密度、pH 值、酒精含量、氯化物等。
在这个项目中,您将构建一个 ML 模型,该模型将使用分类和回归技术,通过分析葡萄酒的化学特性来预测葡萄酒的质量。这个有趣项目的数据集覆盖了 4800 多个实例,共有 12 个属性。
https://medium.datadriveninvestor.com/regression-from-scratch-wine-quality-prediction-d61195cb91c8
结束…
看看 ML 驱动的应用程序在野外越来越受欢迎,现在很明显为什么开发人员急于通过添加少量机器学习来使他们的应用程序更加智能。像世界上大多数开发人员一样,如果你也好奇了解机器学习及其好处,你也应该专注于获得对事物的实际理解以及它们的理论理解。
本文中列出的项目在以适合每个人的方式提供机器学习所有方面的实践经验方面做得非常好。尽管机器学习提供的实际好处非常多,但上面提到的项目应该能够让您开始将 ML 部署到您的应用程序中。
了解你的作者
克莱尔 D 。是 Digitalogy 的内容设计师和战略家,他可以将你的内容想法转化为清晰、引人注目、简洁的文字,与读者建立强有力的联系。
使用 K 个最近邻的分类介绍
一种逐步建立 KNN 分类器的方法
作为机器学习实践者,我们会遇到各种各样的机器学习算法,我们可以利用这些算法来建立特定的预测模型。在本文中,我将重点介绍最复杂的学习算法之一,即 K 近邻算法。该算法可用于处理最大似然法中的回归和分类问题。
在这篇文章中,我将首先尝试给你一个什么是算法的直觉,以及它如何做出预测。然后,我将尝试分解与该算法密切相关的某些重要术语,最后,在本文结束时,我们将使用 KNN 算法设计自己的分类器。
在开始这篇文章之前,我建议你看一下我的以前的文章,我在那里讨论了各种学习算法。此外,如果你喜欢这篇文章,请考虑为这篇文章鼓掌,并确保关注我的更多机器学习食谱。这篇文章的 PDF 副本可以从这里下载,继续你的离线学习。
算法背后的想法
假设你从一个装满金属球的袋子里随机选择一个球,这些金属球要么是金的,要么是碳的。为了区分球是由金还是碳制成,你可以检查它的颜色、导电性、沸点和熔点。这些被称为特征。利用这些特征,我们可以确定球属于哪一类。这类似于 KNN 分类算法的工作原理。
图片由丹尼斯·巴克豪斯拍摄
KNN 算法是一种简单、一致但通用的监督学习算法,可用于解决分类和回归问题。它本质上可以被视为一种算法,该算法基于训练数据集中与其接近的其他数据点的性质来进行预测。
也就是说,简单地说,分类器算法通过计算输入样本和最接近输入样本的 k 个训练实例之间的相似性,输出对象最有可能被分配到的类别。它假设相近的值存在。KNN 经常被认为是一个懒惰的学习者,因为它不学习判别函数。
当很少或没有关于数据分布的信息时,通常使用这种算法。此外,该算法本质上是非参数化的,这意味着它不对数据或其总体分布模式做出任何潜在假设。
图片来自 covartech.github.io
因此,KNN 算法不需要训练时间。然而,无论何时将该算法投入使用,它都需要搜索整个数据集以找到 K 个最近邻。该算法主要用于设计推荐系统和执行分析评估。
KNN 选粉机的引擎盖下
通常,解决分类问题的复杂部分是找到要使用的正确算法。不同的算法适用于不同类型的数据。KNN 算法一般用于小于 100K 标记非文本数据样本的数据集,一般在 LinearSVC 无法投入使用时使用。
如前所述,KNN 是一种监督学习算法,可用于处理回归和分类问题。在这篇文章中,我们将集中在 KNN 分类器。
图片来自 JournalDev
分类器将训练数据作为输入,并输出对象预期所属的类。该对象被分配给其大多数相邻实例所属的类。
KNN 中的 K 分类器
KNN 中的 k 是一个参数,指的是包含在决策过程中的特定数据点的最近邻居的数量。这是核心决定因素,因为分类器输出取决于这些相邻点的大多数所属的类别。
考虑如果 K 的值是 5,那么该算法将考虑五个最近的相邻数据点来确定物体的类别。选择正确的 K 值被称为参数调整。随着 K 值的增加,预测曲线变得更加平滑。
图片来自康奈尔 CS
默认情况下,K 的值为 5。没有找到 K 值的结构化方法,但是 K 的最佳值是数据集中存在的样本总数的平方根。K 的值通常取为奇数值,以避免决策过程中出现平局。误差图或精度图通常用于寻找最合适的 k 值。
KNN 的距离度量
KNN 使用各种不同类型的距离度量来计算距离。为了使算法有效工作,我们需要选择最合适的距离度量。其中一些指标如下所述:
- 欧几里德距离:这是 sklearn KNN 分类器使用的默认度量。它通常被称为 L2 规范。它计算欧几里得空间中两点之间的普通直线距离。
图片来自 Packt 订阅
- 曼哈顿距离:通常被称为城市街区度量,在这种情况下,两点之间的距离是它们的笛卡尔坐标的绝对差,并且在高维度的情况下使用。
- 汉明距离:该指标用于比较两个二进制数据字符串,通常与 OneHotEncoding 一起使用。它查看整个数据集,并发现数据点何时相似或不相似。
既然我们已经讨论了 KNN 分类算法的理论概念,我们将应用我们的学习来使用 K 最近邻算法构建一个分类器。用于构建这个模型的代码和其他资源可以在我的 GitHub 句柄中找到。
步骤 1:导入所需的库和数据集
构建分类器的第一步是导入将用于构建分类模型的所有必需的包。首先,我们将导入 Pandas、Numpy、Seaborn 和 Matplotlib 包。
***#Importing the Required Libraries and Loading the Dataset*** import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt%matplotlib inline
dataset = pd.read_csv("Iris.csv")
在这个例子中,我们将尝试使用各种特征,如花瓣长度、花瓣宽度、萼片长度和萼片宽度,对鸢尾花进行分类。我们在选择模型参数时需要非常小心,因为 KNN 对要使用的参数非常敏感。
图片来自兰卡斯特大学
一旦导入了所有这些库,下一步就是获取数据集。用于建立这个模型的数据可以从这里下载。read_csv()函数用于将数据集加载到笔记本中。用于该模型的数据集可以从这里下载。
第二步:数据分割和标签编码
加载数据集后,下一步是将数据分割为要素和标注。在机器学习中,特征是作为输入提供给系统的独立变量,而标签是我们试图预测的属性。
***#Dividing Data Into Features and Labels*** feature_columns = ['SepalLengthCm', 'SepalWidthCm', 'PetalLengthCm', 'PetalWidthCm']
X = dataset[feature_columns].values
y = dataset['Species'].values***#Label Encoding*** from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
y = le.fit_transform(y)
图片来自 ResearchGate 的 Danilo Bzdok
KNN 分类器不接受字符串标签,因此有必要在对数据建模之前对这些标签进行编码。标签编码器用于将这些标签转换成数值。
步骤 3:可视化数据集
在构建分类模型时,可视化数据集是一个重要的步骤。这使得理解数据和寻找数据中隐藏的模式变得更加容易。Python 有一系列可以用来可视化数据的包。
***#Visualizing Dataset using Pairplot*** plt.figure()
sns.pairplot(dataset.drop("Id", axis=1), hue = "Species", size=3, markers=["o", "s", "D"])
plt.show()***#Visualizing Dataset using Boxplot*** plt.figure()
dataset.drop("Id", axis=1).boxplot(by="Species", figsize=(15, 10))
plt.show()
Matplotlib 是 Python 中静态绘图的基础。Seaborn 是最流行的绘制视觉上吸引人的图形的库之一,它建立在 Matplotlib 之上。Matplotlib 和 Seaborn 就是这样的两个软件包,它们用于在各种不同类型的图表上绘制数据。
图片来自MagratheaGabriela Moreira Mafra
Matplotlib 的网站包含了多个文档、教程和大量的例子,这使得它的使用更加容易。箱线图、Pairplot 和 Andrews 曲线是几种最广泛使用的数据可视化图形,可用于绘制图形以可视化分类问题。
第四步:分割数据集并拟合模型
选择所需的参数并可视化数据集后,下一步是从 sklearn 库中导入 train_test_split,该库用于将数据集拆分为训练和测试数据。我们将把数据集分成 80%的训练数据和 20%的测试数据。
***#Splitting the Data into Training and Testing Dataset*** from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)***#Fitting the Model and Making Predictions*** from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import confusion_matrix, accuracy_score
from sklearn.model_selection import cross_val_score
classifier = KNeighborsClassifier(n_neighbors=3)
classifier.fit(X_train, y_train)
y_pred = classifier.predict(X_test)
在这之后,KNeighborsClassifier 从 sklearn.neighbors 包中导入,并且使用设置为 3 的 k 值实例化分类器。然后将分类器拟合到数据集上,并使用 y _ pred = classifier . predict(X _ test)对测试集进行预测。
图片来自sumunosato . koukodou . or . jp
由于在本例中,要素处于相同的数量级,因此不对数据集执行任何要素缩放。但是,建议在拟合分类器之前对数据集进行归一化和缩放。
第五步:评估预测并交叉验证
评估分类算法预测的最简单和最常用的技术是通过构建混淆矩阵。另一种方法是计算模型的准确度分数。
***#Confusion Matrix*** confusion_matrix = confusion_matrix(y_test, y_pred)
confusion_matrix***#Calculating Model Accuracy*** accuracy = accuracy_score(y_test, y_pred)*100
print('Accuracy of the model:' + str(round(accuracy, 2)) + ' %.')
图片由 Dmytro Nasyrov 从媒体获取
***#Performing 10 fold Cross Validation*** k_list = list(range(1,50,2))
cv_scores = []
for k **in** k_list:
knn = KNeighborsClassifier(n_neighbors=k)
scores = cross_val_score(knn, X_train, y_train, cv=10, scoring='accuracy')
cv_scores.append(scores.mean())***#Finding Best K*** best_k = k_list[MSE.index(min(MSE))]
print("The optimal number of neighbors is **%d**." % best_k)
评估输出预测后,下一步是为参数调整执行多重交叉验证。在这里,我们正在进行十倍交叉验证,以找到 k 的最佳值。
KNN 分类器的优势
KNN 分类器是最复杂和应用最广泛的分类算法之一。使该算法如此流行的一些特征如下所述:
- KNN 没有对这些数据做出任何潜在的假设。
- 与许多分类算法相比,它具有相对较高的精度。
- 随着更多数据点的添加,分类器不断进化,能够快速适应输入数据集中的变化。
- 它为用户提供了选择距离度量标准的灵活性
图片来自 Milliams
KNN 分类器的局限性
虽然分类器有多种优点,但它也有一些严重的局限性。其中一些限制如下所述:
- KNN 对异常值非常敏感。
- 随着数据集的增长,分类速度会变慢
- KNN 没有能力处理缺失的价值观。
- 由于高存储要求,它在计算上是昂贵的。
总结你所学的知识
为了总结我们在本文中学到的东西,首先我们看一下算法背后的思想及其理论概念。然后,我们讨论了参数“K ”,并了解了如何找到 K 的最佳值。之后,我们回顾了各种距离度量指标。
图片来自 Piyush Pathak
然后,我们应用我们的学习来建立 KNN 分类器模型,以对各种植物物种进行分类,然后我们通过浏览分类算法的优点和局限性来支持我们的学习。
至此,我们已经到了这篇文章的结尾。我希望这篇文章能帮助你对 KNN 算法的工作原理有所了解。如果你有任何问题,或者如果你认为我犯了任何错误,请随时与我联系。通过电子邮件或 LinkedIn 与我联系。快乐学习!
让人工智能玩 atari Pong,进行深度强化学习
详细的指导
首先我们统治 pong,接下来,世界…
让一个计算机程序学习如何玩 Atari 游戏似乎是一项非常困难的任务。好吧,我来告诉你…它是什么。但是相信我,如果我能做到,你也能。本页假设你已经通读并稍微理解了深度 RL 的理论(链接在下面)。但是要注意,理论不足以让代理学习雅达利!有了强化学习,一切都在实施中,魔鬼就在细节中!因此,这篇文章的其余部分将集中在一行一行地实现代码,以使我们的代理工作。
实施:
为了实现,我们将使用开放的人工智能健身房环境。对于代理的神经网络,我将使用 Keras 建立一个 CNN。我们将首先处理 Pong,然后在另一篇文章中,我们将让代理玩 breakout(这需要花费更多的时间来训练)。真的要慢慢来,通读我的代码,了解发生了什么。
此外,如果你没有一台功能强大的电脑,我强烈建议你在 google colab 上做这个项目。如果你不知道 google colab 是什么,那就谷歌一下看看吧!他们免费为你提供 GPU 和 CPU 来运行代码。
这里的策略是。我们从 openai 健身房收到当前的游戏画面。来自 4 个最近帧的像素值的张量是我们的当前状态(稍后将详细介绍)。基于ε贪婪策略,我们要么采取随机行动,要么将我们的当前状态输入 CNN 以获得我们的行动。现在我们采取行动,获得奖励,并被带到一个新的状态。我们将(S,A,R,S’)值存储在内存中用于训练。在每个动作之后,我们从我们的代理的内存中随机抽取数据,并使用我们在关于深度 RL 理论的文章中导出的损失函数来训练我们的代理。
一个快速打开的人工智能健身房教程
开放人工智能健身房是一个充满雅达利游戏(在其他游戏中)的图书馆。这个库很容易让我们测试我们的理解,而不必自己构建环境。在你导入健身房后,我们将只使用其中的 4 个功能。这些功能是:gym.make(env)、env.reset()、env.step(a)和 env.render()。
- gym.make(env): 这只是从 open ai gym 中获取我们的环境。我们将调用 env = gym . make(' PongDeterministic-v4 '),这表示我们的 env 是 Pong。
- env.reset(): 这将环境重置回它的第一个状态
- env.step(a): 通过执行动作 a 在环境中前进一步,返回下一帧、奖励、完成标志和信息。如果 done 标志== True,那么游戏结束。
- env.render(): env.render()显示代理在玩游戏。在检查代理的性能时,我们将只使用 env.render()。我不认为这在谷歌 colab 或任何其他笔记本上行得通,尽管我可能是错的。因此,您可能需要保存代理的权重,然后将它们加载到您的本地计算机上,并在那里渲染游戏。
下面是如何实现这些函数的代码示例:
预处理帧
目前,从 openai 接收的帧比我们需要的大得多,分辨率也比我们需要的高得多。见下文:
我们不需要底部的任何空白,也不需要顶部白色条纹上方的任何像素。此外,我们不需要这个是彩色的。
首先,我们裁剪图像,以便只显示重要的区域。接下来,我们将图像转换为灰度。最后,我们使用 cv2 和最近邻插值来调整帧的大小,然后将图像数据类型转换为 np.uint8
生成的图像如下所示:
提供方向信息
站在代理的角度想想,看看下面的框架:
现在,球在朝哪个方向移动…没办法知道。我们只能知道位置,因为我们只有一个时间步长。仅仅在一帧中提供的信息不足以知道方向。如果给定两个时间步长,我们可以知道球的速度,如果给定三个时间步长,我们可以知道加速度,等等。
回想一下,我们的帧是像素值的矩阵。为了将方向信息添加到我们的输入中,我们可以简单地将我们的帧堆叠在一起以形成张量。假设我们的帧的形状是(84,84),如果我们将最近的 4 帧堆叠在一起,我们的状态的形状将是(84,84,4)。所以在游戏中的时间 t,我们当前的状态是 t,t-1,t-2 和 t-3 的帧的堆栈。
代理内存
在我开始实现代理内存之前,我想解释一下最初是什么激发了研究人员使用它。
当我第一次接触这个项目时,我试图使用实时生成的数据来训练代理。所以在时间步长 t,我将使用时间(t-1)的(S,A,R,S’)数据来训练我的代理。
我能解释这个问题的最好方法是回到我大学的早期。在我大二的时候,我连续一年被灌输静力学理论(我学的是机械工程)。然后在我大三的时候,我对静力学一无所知,相反,我被迫接受了机器设计。到了高三,我已经忘记了所有关于静力学的事情。
在我们的环境中,可能有 100 帧球移动到屏幕的左侧。如果我们在完全相同的情况下反复训练我们的代理,那么最终它会过度适应这种情况,它不会推广整个游戏,就像我在学习机器设计时忘记了静力学一样。
所以,我们将所有的经历储存在记忆中,然后从整个记忆列表中随机抽取样本。通过这种方式,代理从学习他在培训时的所有经验,而不仅仅是他的当前情况(为了更好地击败这匹死马,想象一下如果你不能从过去学习,而只能从现在学习)。
好了,现在开始实施。对于内存,我用 4 个独立的 deques 创建了一个独立的类(固定大小的先进先出列表)。列表包含帧、动作、奖励和完成标志(它告诉我们这是否是一个终止状态)。我还添加了一个函数,允许我们添加到这些列表中。
add_experience 中 next_x 的古怪命名稍后会变得清晰
环境
接下来,我们开始实施我们的环境。我通过创建 4 个函数来做到这一点;
- Make_env()
- 初始化 _ 新 _ 游戏()
- take_step() …这是所有奇迹发生的地方
- 播放 _ 剧集()
在深入细节之前,我将展示代码,以便您能够理解。
make_env() 函数是不言自明的。它只是调用 gym.make()函数。
initialize_new_game() 函数重置环境,然后获取开始帧并声明一个虚拟动作、奖励和完成。现在,这个数据被添加到我们的内存 3 次。记住,我们需要 4 帧来完成一个状态,这里添加了 3 帧,最后一帧添加在 take_step()函数的开始处。
take_step() 函数有点复杂。我将在下面列出伪代码:
- 更新代理总时间步长
- 每 50000 步节省重量
- 现在,我们使用代理的动作列表中的最后一个动作调用 env.step。这将返回下一帧、奖励、完成标志和信息
- 调整下一帧的大小,并从最后 4 帧中获取下一个状态。
- 使用下一个状态获取下一个动作。这就是为什么我们能够在步骤 3 中使用代理动作列表中的最后一个动作
- 如果游戏结束,则返回分数和一个终止标志
- 将这段经历加入记忆
- 如果调试,渲染游戏。我们不会使用它,但我发现它在尝试让它工作时很有用。
- 如果代理的内存包含足够的数据,那么让代理从内存中学习。稍后将详细介绍。
- 返回代理分数和一个错误的终端标志
正如您所看到的,这个函数与代理类一起工作了很多。这个类将很快介绍。
play_episode 函数非常简单明了。这个函数只是初始化一个新游戏,调用 take_step 函数,直到返回一个真正的终端标志。然后返回剧集评分。
代理类
这个类有 5 个函数,包括构造函数。这些函数是:init()、_build_model()、get_action()、_index_valid()和 learn()。
build_model() 函数只是为代理构造一个 CNN。请注意,CNN 中没有 max_pooling 图层,因为池化消除了一些所需的空间信息。我使用 Huber 损失和 Adam 初始化器。
get_action() 函数只是 greedy 的一个实现。我们生成一个随机数,如果它小于我们的ε值,我们就采取随机行动。如果没有,那么我们将当前状态传递给 CNN 并返回最大输出。
_index_valid() 函数是学习函数的助手。它只是检查在给定的索引处,在我们的内存的过去 4 帧中是否有一个终止帧。我们不想创造一个介于两个游戏之间的状态。
在我解释 learn 函数之前,您可能已经注意到了该类的 model_target 属性。这是一种用于降低训练噪音的方法。基本上,我们复制我们的 CNN,所以我们现在有了我们的模型,和我们的模型目标。现在,回想一下,在训练时,我们将下一个状态输入到 CNN 中,以帮助生成误差函数的目标。注意,在权重被更新之后,误差函数中的目标将会改变,因为 CNN 被用于生成该目标,并且 CNN 权重刚刚被改变。
下面是我们损失函数的一个提示:
V(t+2)是我们的神经网络的输出。所以如果我们更新一次权重,那么 V(t+2)会有一点变化。这意味着我们的目标在移动,这在实践中被证明是低效的。
有人在谷歌有一个想法,我们可以使用目标模型来生成我们的损失函数的目标,然后我们经常只是设置目标模型的权重到我们的主模型的权重。所以他们尝试了一下,它提高了性能,减少了培训时间(这就是我在这里实现它的原因)。
现在我们来看一下 learn() 函数。我们将用 32 个迷你批次来训练我们的 CNN。
- 我们的第一步是收集 32 个状态、next_states、actions、rewards 和 done 标志。
- 我们通过模型传递状态,通过目标模型传递下一个状态。我们从模型中得到的输出将在下一步中被修改,因此它可以用作我们的 Vtrue。
- 现在,对于迷你批处理中的每个状态,我们首先要弄清楚采取了哪个操作。然后我们计算采取这个动作的真实值,并用这个真实值替换输出值。 not next_done_flags[i] 代码只是确保如果我们处于终止状态,则不考虑下一个奖励。此外,伽玛被称为贴现因子。这只是让当前的奖励比未来的奖励更有分量。Gamma 可以取出来,不用担心弄坏代理。
- 现在,我们使用我们创建的状态和标签来拟合我们的模型。
- 现在更新 epsilon 和代理学习了多少次
- 每 10,000 步将模型权重复制到目标模型
对代理人来说就是这样。学习功能是我第一次尝试这个项目时出错的地方。所以如果你有困难,先检查这里。
main.py
现在是我们最后的文件。我不打算在这里详细介绍,这个文件是不言自明的。只需初始化代理和环境,然后循环调用 play_episode()函数。偶尔打印出一些有用的指标,每 100 集我打印出一个图表,显示得分的移动平均值。在对我的代理人进行培训后,我意识到根据采取的步骤而不是玩的游戏来绘制分数会更有用。如果你正在重新创建这个项目,我建议每 10,000 步左右标一次分数。
总结:
你可以在这里找到完整的、完成的项目。训练持续了大约 24 小时。最后的结果就是这篇帖子顶部 gif 中右边的代理。
我第一次这样做花了几个星期。这确实是一个困难的项目。如果你有困难,真的要花时间去理解理论,通读我的代码。
这种特殊的 RL 算法被称为深度 Q 学习。深度 Q 学习通常被视为深度 RL 的介绍,但它不是最有效的算法。我最喜欢使用的算法是 A2C,我将在以后的文章中介绍它。
但在此之前,让我们证明这个算法有多酷。我曾经把这个展示给一个朋友看,他说,“你就不能硬编码一下球拍,让它跟着球走吗”。尽管他是对的,但这个项目的酷之处不仅仅在于我们用它来玩乒乓球。就是经纪人学会了打 pong。这个算法是迈向通用人工智能的一步。证明我们已经获得某种程度的通用人工智能的一个方法是,看看这个智能体是否可以学习多个游戏。我会在这里留下一个链接,说明如何让这个代理在完成后学习游戏突围。
作者所有图片、gif、代码片段!
感谢您的阅读!如果这篇文章在某种程度上帮助了你,或者你有什么意见或问题,请在下面留下回复,让我知道!此外,如果你注意到我在某个地方犯了错误,或者我可以解释得更清楚一些,那么如果你能通过回复让我知道,我会很感激。
熟悉 Rmarkdown HTML
使用 R 降价
我认为开始做任何事都不晚,除了成为一名芭蕾舞演员。~温迪·利伯曼
简介
R Markdown 最早发布于 2014 年。它是一个工具,为作者提供了一些强大的技术来将报告和分析合并到一个文档中。R Markdown 的官方网站声称这个工具可以用于可复制的文档,以优雅的格式放置叙述性文本和报告元素;使用像 R、Python 和 SQL 这样的语言。它允许作者以 HTML、PDF、Word、演示文稿甚至书籍或仪表板的形式生成组合报告。多年来,许多研究人员、分析师、内容作者、开发人员和软件程序员一直在不懈地发布文章、书籍和帖子,以熟悉研究和分析工作区中的这一强大工具。如果没有这些资源的贡献,从构思将该工具集成到分析表示中,到设置工作站和实际执行任务的过程是不可能的。其中一些将在文章中分享。
R Markdown 被认为在研究和学术领域被学生和教授广泛采用。项目、作业、论文或论文的提交需要在结合数据集、图表、表格、见解、统计结果以及数学方程方面付出大量努力。下图显示了过去 52 周几个关键 R Markdown 包的下载趋势。
图-1 rmakrdown,knitr,tinytex 的 52 周下载趋势。(闪亮 App 来源):链接
虽然通过减价来使用纯文本文档是为互联网用户创建格式良好的文档的关键,但由于多种原因,在企业工作区大规模采用这种做法可能会很麻烦。大多数公司的工作空间严重依赖于幻灯片,多个用户可以编辑和润色内容,而无需花费太多精力进行语法编码。幻灯片或办公工具允许不同类型和大小的内容众包来传达一个共同的信息。然而,如果一个作者主要使用像 R 或 Python 这样的开源编码平台,通过各种复杂的数据源来策划一个讲故事的练习,那么 R Markdown 可以为分析或科学文章提供几个这样的用例。
议程
在这篇文章中,我们将主要关注 R Markdown 用于生成 HTML 文档的一些快速而有用的特性。目标是分享一些可用于生成 HTML 输出格式的基本和扩展元素。我的目标不是出版一本有效的手册或食谱给读者,而是分享我在过去几周收集的快乐和挑战。不过在 RStudio 编辑器中使用 install.packages()函数预装这些包就好了; "rmarkdown "、" tinytex "、" gridExtra "、" kableExtra "、" summarytools "、" sjPlot "、" sjmisc "、" sjlabelled "、" stargazer" 。首先,无论如何,我们都将依赖这些实用程序来完成本文。
R 降价元数据
图-2 R 降价元数据。(图片来源) :图片来自作者
在 RStudio 中,如果我们遵循 File → New file → R Markdown,那么我们将得到一个创建 HTML 文档的选项,该选项是默认选中的。一旦我们单击“OK ”,我们将被定向到一个. rmd 脚本,其中元数据部分是自动填充的(由包含三个破折号的线分隔)。这种结构遵循 YAML 非标记语言(YAML)格式,它通过 R 进行通信,为 HTML 输出提供特定的结构指令。作者可以在引号内键入相关的标题、作者姓名和日期,这将允许 R Markdown 将它们放在文档的顶部。不像标题,在双引号内键入姓名或日期并不是强制性的。标题中的引用需要从文本中屏蔽冒号(😃。
下面的 YAML 元数据为 HTML 文档添加了标题、名称和当前系统日期。
图 3 元数据输出。(图片来源) :图片来自作者
还有更多在 PDF 格式中大量使用的元数据功能。 大多为 HTML 用例;在我们不需要为分页符而烦恼的地方,对自动填充的 YAML 的上述修改就足够了 。
代码块设置
三个连续的反勾号后跟一对以字母“R”开头的花括号,调用环境中的 R 编辑器。这必须以另外三个连续的倒勾结束。在此期间,作者可以编写代码块。setup 部分中声明的任何选项将优先用于流向整个文档的剩余块,除非在单个块中明确更改。设置选项是习惯性的,是文档特有的,是一次性的练习,也是很好的实践。我们不需要为同一个文档重复设置两次。include=FALSE 选项告诉设置不要在输出中包含代码块中的任何内容。warning=FALSE 和 message=FALSE 特别要求设置不要在 HTML 文档中包含来自 R 代码的任何警告消息。打开这些选项意味着作者想要打印代码中的所有内容。许多选项都有详细的记录,可以在这里找到。还有一个 echo=FALSE 选项,请求在输出文档中不包含源代码。我们将暂时在每个块中使用 echo 选项。
哈希和文本
图 4 使用多少个散列值?(图片来源) :图片来自作者
在定义与 R 或 Python 相关的代码块的反斜杠之外,作者可以使用“#”符号后跟一个空格来定义部分。散列越多,意味着章节标题的字体越小。根本不使用散列意味着简单的降价文本。
我遵循的一个非常快速简单的参考是这里的。它快速提醒我如何使用斜体、粗体、项目符号列表或编号列表。
包摘要工具
图 5 使用 dfSummary()在 HTML 中包含数据摘要。(图片来源) :图片来自作者
这个包在一个 HTML 报告 中显示数据集的有用的汇总统计数据。开发这个包的主要目标之一是确保通过 R Markdown 以 HTML 格式轻松呈现数据摘要。对于具有大量分类特征的数据集,通常需要在获得叙述性文本之前显示数据透视表的快照。这个包提供了一些其他的核心功能来满足这个目的。详细的链接是这里,如果渲染 HTML 看起来很有趣,你可以把它加入书签。接下来的几个数字会给你一个基本的外观和感觉,你可以根据自己的兴趣进一步美化。
图 6 使用 descr()在 HTML 中包含数值变量的单变量汇总。(图片来源) :图片来自作者
图 7 使用 freq()处理 HTML 中的分类变量。(图片来源) :图片来自作者
图 8 使用 stby()处理 HTML 中的分组摘要。(图片来源) :图片来自作者
stby()中的 INDICES 参数接受多个分组变量作为列表。
打包 kableExtra
图 9 在 HTML 中使用 kableExtra。(图片来源) :图片来自作者
这个包在使用 R Markdown HTML 时的意义是确保 时尚且格式良好的表格显示在输出 中。这个实用程序产生的结果的外观和感觉与我们通常在 R print()函数中看到的截然不同。这个实用程序的详细指南可以在这里找到,不用说,这个链接可以作为在 R Markdown 中编写语法的圣经。
显示回归表
图 10 在 HTML 中使用 tab_model()。(图片来源) :图片来自作者,(数据来源):链接
tab_model()允许作者在 HTML 文档 中显示格式良好的回归表。虽然无法将此工具用于 PDF 或 Latex,但如果需要,可以通过导入来使用图像。这个函数有更多的参数,你可以使用来检查?R 控制台中的 tab_model() 。请注意,在显示逻辑回归表时, tab_model() 已经自动将β系数转换为优势比,并显示了 95%的置信区间,无需额外的努力。当作者想要展示建模实践中两到三个最重要的迭代或者甚至展示最终的模型时,这个模型就派上了用场。tab_model() 也是线性回归表或其他形式回归的常用工具。这里的链接是在 R Markdown 中工作时的快速参考指南,我希望可以根据具体要求实现进一步的加速。
HTML 标签集
图 11 在 HTML 中使用标签集。(图片来源) :图片来自作者
{.tabset}参数允许在 HTML 文档中创建选项卡。当调整了正确的哈希数后,我们可以看到每个选项卡都可以作为一个单独的页面,在这里可以放置进一步的分析和叙述性文本。当我们想要呈现不同公司的类似分析或者一个特定公司的不同模型时,这个选项卡集布局是有用的。选项卡集布局有助于放置分组的结果或模型输出,以便最终用户阅读和导航。
结论
R Markdown 是一个很好的工具,可以为消费者生成可再现的分析图、表格、见解和图像。本文的目的不是鼓励 Office 套件和开源减价工具之间的任何争论。两者都有其独特的用法,并在提交分析结果时对作者有利。然而,随着 R 中如此强大的扩展的出现,R Markdown 为作者提供了过多令人兴奋的特性来管理分析的外观和感觉。不用说,对于每一个分析,编写语法来美化 HTML 文档中的输出将是有用的和经济有效的,幻灯片或单词仍可能赢得比赛。然而,在使用 R 或 Python 分析数据时,R Markdown 在增强分析师的工具箱方面取得了很大的进步。
除了栈溢出 Q & A forums 之外,本文中提供的超链接是我提到的最常访问的资源。请看一下谢一辉、克里斯托夫·德维约和艾米丽·里德雷尔写的 书 。然而,我还想提一下这篇文章,它是一篇很好的读物,激励我写这篇文章。
谢谢你。
熟悉 Rmarkdown PDF
元数据和引用
塞萨尔·阿布纳·马丁内斯·阿吉拉尔在 Unsplash 上的照片
如果你把一本书掉进马桶里,你可以把它捞出来,擦干,然后读那本书。但是如果你把你的 Kindle 掉到马桶里,你已经做得很好了。~斯蒂芬·金
一个作家的大部分时间花在阅读上,为了写作:一个人会为了写一本书而翻遍半个图书馆。~塞缪尔·约翰逊
简介
为分析表示创建 PDF 报告是学者、业务分析师或现代数据科学家的长期传统。自从 PowerPoint 动画问世以来,最近又引入了 PowerPoint 变形转换或幻灯片缩放功能,作者们一直致力于寻找更有效、更强大的方式来传达信息并获得更好的观众接受度。R Markdown 没有涉足动画领域。然而,在分析领域,复制科学期刊的格式,尤其是美国心理学协会(APA)的格式,对于提交重大项目工作供同行评审并不奇怪。此外,分析师或商业顾问总是希望能够以书籍的形式进行写作,以传达具有强大背景的分析,具有精确的目标,正确的证据碎片和强制性的结论。R Markdown PDF 允许作者将报告和叙述性文本结合起来,并将其放入 PDF 或书籍格式中,这对于在组织的分析功能中工作的非学者来说,确实比漫游癖更强烈。在阿拉伯,他们说“当狮子打喷嚏时,猫就诞生了”。如果假设商业分析师是一只在院士打喷嚏时创造出来的猫,那么对一只坐在牛奶旁边而不舔牛奶的猫的期望就太高了。对于一个分析从业者来说,写降价报告就像喝牛奶一样难,哪怕只有一次。
在上面的文章中,我们打算强调使用 R Markdown HTML 时的几个关键元素。在当前的文章中,我们将关注 R Markdown PDF,首先,我们将在查看 PDF 的主体之前关注元数据和引用。原因是元数据不仅定义了文档的结构,还定义了报告的开始部分。引用出现在文件的末尾,对于任何涉及一些研究工作的科学期刊来说都是强制性的。
注意:如果读者有过一些学术论文的经历,那么这篇文章并不打算区分作者的感知能力和实际能力。随时欢迎您的建议和经验。
议程
目标是分享一些可用于生成 PDF 输出格式的基本和扩展元素。我的目标不是出版一本有效的手册或食谱给读者,而是分享我在过去几周收集的快乐和挑战。不过在 RStudio 编辑器中使用 install.packages()函数预装这些包就好了;“rmarkdown”、“tinytex”、“gridExtra”、“kableExtra”、“stargazer”。首先,无论如何,我们都将依赖这些实用程序来完成本文。
R 降价元数据
LaTex 是学者、研究人员或大学生常用的工具。对于那些不知道的人来说,LaTex 是一个文档编写工具,可以用来编写复杂的数学方程、统计符号和假设。" LaTeX 是科学文献交流和出版的事实标准."(来源:乳胶 网站 )。R Markdown 可以通过“tiny tex”包和 pandoc 与 LaTex 工具通信。要了解更多关于 pandoc 的信息,你也可以访问他们的官方网站。如果一个人熟悉 LaTex 语法,那么 R Markdown 可以作为一个极好的平台来利用研究人员的统计计算、可视化和文档编写能力。然而,即使一个人与研究工作无关,并且处理任何领域的分析工作空间,R Markdown PDF 或 HTML 也可以作为一个很好的附加工具来升级现有的技能组合,以编写格式良好的报告。
图 pdf 输出的上半部分。(图片来源) :图片来自作者
图 pdf 输出的中下部。(图片来源) :图片来自作者
图 1 和图 2 显示了 pdf 输出的第一页。每个编号的框都是第一个代码片段中显示的元数据参数的结果。
第 1 个框是标题(标题:)。
第 2 个框是副标题(副标题:)。
第三个框是作者信息(作者:)。
第四个框是日期(日期:)。
第五个框由分析的摘要(摘要:)和关键字(\ textbf{Keywords:} )组成。
第六个盒子将保存目录( toc )。
第 7 个框保存确认(感谢)消息,最后,我们在第一页的右下角看到页码(编号 _ 部分:)。
管道(“|”)允许在同一参数中键入新的一行。
geometry 参数允许页边距宽度,以便在打印 pdf 时,作者不会因硬装订而丢失任何文本。
当为真时的 keep_tex 参数指示 pandoc 在输出文件中保留 LaTex 转换。
latex_engine 参数指示 pandoc 使用特定的 latex 引擎进行文档转换。像“pdflatex”和“xelatex”这样的引擎是最常用的。使用非英语语言或系统字体的作者更喜欢“ xelatex”。
fig_caption 参数指示 latex 引擎对 pdf 文档中的表格和图像/图表进行自动编号。例如,当插入第一个表格时,标题将从表-1 开始,因此第一个图或图像的标题为图-1。 fontfamily 参数选择文档的字体。
header-includes 下的 \usepackage{} 参数指示 tinytex 确保安装特定的 LaTex 包,用于编写数学方程和放置图形或表格。基本上,以上三个包大部分时间用于基本的 pdf 输出创建。还有一个程序创建一个 。工作目录中的 sty 文件 用于给出显式 LaTex 指令,这些指令可以在下的元数据中使用,包括 _header 参数中的和。
引文
重要的是要提及其作品启发了分析表示的想法和作者。在创建期刊或发表研究论文时,通常会特别注意在同行评审的输出中包含所有必要和正确的引用。事实上,这是审查机构打击剽窃的最重要的评估标准之一。APA 格式的最常见的引用指南和最新版本很容易在公开论坛上通过谷歌搜索获得。R Markdown 可以与 BibTex 格式无缝交互。每一份研究出版物都会附上一个 DOI ( 数字对象标识符),同时在他们的出版物库中发布作者的作品。这个标识符包含一些关于作者和作品种类的独特信息。
上面的网站可以将任何 doi 转换成一个等价的 BibTex 标识符,R Markdown 可以使用 citation_package 参数对其进行翻译和呈现。因此,如果你试图找到一个你已经有的 doi 的相应 BibTex,那么这是一个救命稻草。或者,如果你想获取某个谷歌学术期刊/书籍的 BibTex,你可以点击“双引号符号,然后点击 BibTex 链接。
图 3 如何从谷歌学术获得 BibTex。(图片来源) :图片来自作者
图 4 这是第二个片段的目录。(图片来源) :图片来自作者
图 5 这是第二个代码片段的第二页输出。(图片来源) :图片来自作者
本文所附的第一段和第二段代码的不同之处在于添加了书目:、书目样式:、链接引用:和 natbiboptions: 参数。的例子。当前工作目录中的 bib 文件包含了作者在文档中可能引用或不引用的所有引文。\ n site { * }参数通过 pandoc 明确指示 latex 引擎在 references 部分包含所有引用,而不管它是否在主体中被引用。[@ < id > ]语法允许作者在文档的叙述性文本中明确引用作品。文献目录文件中未明确引用的那些 id(即 bib 文件)将按照\ n site { * }显示在参考部分。如果不需要此功能,那么作者可以简单地删除\ n site { * }参数。
图 6 这是 example.bib 文件在记事本++ 中编辑时的样子。(图片来源) :图片来自作者
函数 write_bib() 在 R 控制台中打印机器中已安装软件包的 BibTex。文档链接在这里是。 wirte_bib()无法从出版网站获取学术文章或期刊的 BibTex。这仅用于获取安装在机器中的 R 包的 BibTex。
最简单的方法是从与分析相关的所有可能来源中逐一收集所有 BibTex 引用,将它们附加到一个单独的 Notepad++文件中,保存该文件,并将该文件及其扩展名重命名为 example.bib. R Markdown 无法识别。txt 文件,除非将其重命名为. bib.
结论
渲染 HTML 和 PDF 文档是两个不同的球赛。呈现 HTML 很简单,相对来说不那么费力,而且有其自身的局限性。另一方面,呈现 PDF 很费力,需要多次迭代才能看到文档是否放在作者想要的地方。在渲染 PDF 输出时,分页符和乳胶浮动对象的概念对初学者来说有很大的作用。然而,正如股市所说的“风险越大,收益越高”,一旦最初的几个项目结束,这种技能组合给分析师带来了很多快乐和满足。不推荐在没有 LaTex 广泛知识的情况下渲染 PDF 输出,但是,R Markdown 并不要求 LaTex 基础的先决条件。R Markdown 的强大功能和它的扩展包使得这种技术对于非学术界人士来说也是触手可及的,而不管它在日常演示中的大规模使用。渲染 PDF 的旅程相对较长,因为它涉及到更多的元素来管理最终输出。我同意,有时搜索数百个 Stackoverflow 问题来学习单个论点及其功能变得很单调。然而,我们的目标不是成为一名 LaTex 开发者,甚至不是 R Markdown 开发者。更大的目的是多花一点功夫来管理这个 husky 工具,以便能够在发送给同行评审时,从常规 Excel 或 PowerPoint 中脱颖而出,释放出一个封装良好的分析流。
在 R Markdown 中有多种方法来构造元数据以呈现 PDF,学习一些的最好方法是迭代不同的版本。虽然这对于学者来说可能不一样,但对于基础从业者来说,熟悉这个大力士的最好方法是熟悉 HTML 过程,然后谨慎地使用 PDF。像“rticles”这样的软件包已经提供了许多不同的模板来呈现 PDF,但是它并不能保证“一个尺寸适合所有人”的目的。我想分享一个来自 Pat Schloss 的视频,这可能会激励更多人。
谢谢你。
熟悉 Rmarkdown Stargazer
R 的 Stargazer 库
ksen ia Samoylenko 在 Unsplash 上拍摄的照片
现在的幸福只会因为与过去的比较而破灭。~道格拉斯·霍顿
简介
回归分析今天不需要单独介绍。事实上,很难找到一个研究领域可以打赌在他们的生命周期中不使用这种技术至少一次就能赢。存在一种关系,等待某人通过某种回归技术的变体来探索。自从数学家阿德里安-玛丽·勒让德(Adrien-Marie Legendre)和卡尔·弗里德里希·高斯(Carl Friedrich Gauss)在 19 世纪初发明了这项技术以来,世界每天都在经历至少一个用例;被活在世上的某个人。想象一下如果人类无法获得这项技术会发生什么是很可怕的。如果这项技术没有公开,世界大战会如何发展?
在过去的十年中,随着开源平台和维护良好的统计估计库的出现,执行回归分析已经成为一项琐碎的任务。然而,比较不同条件和解释统计输出以解释潜在假设的性质的艺术将要求相关从业者通过公平的手段进行探究,直到永恒。人工智能算法旨在复制无错误的高效人类执行,然而,它可以像创建算法的开发人员一样学习表示艺术。
Stargazer 是一个最初为 R 平台开发的库,用于增强 R Markdown 文档中回归表的表示。作为一个用户,我们不能否认 stargazer 的结果在 pdf 文档中使用时非常类似于科学杂志或统计教科书的外观和感觉。
上面的文章试图鼓励读者积极考虑 R Markdown PDF。但是,这里说的是元数据和参考书目部分。stargazer 的使用在元数据之后,书目之前。
注意:如果读者有过一些学术论文的经历,那么本文并不打算区分作者的感知能力和实际能力。欢迎您的建议和经验。
议程
目的是分享一些可用于生成 PDF 输出格式的基本和扩展元素。我的目标不是出版一本有效的手册或食谱给读者,而是分享我在过去几周收集的快乐和挑战。不过在 RStudio 编辑器中使用 install.packages()函数预装这些包就好了;“rmarkdown”、“tinytex”、“gridExtra”、“kableExtra”、“stargazer”。首先,无论如何,我们都将依赖这些实用程序来完成本文。
包观星器
图-1 结构,表示在独立属性上逐一回归的同一响应变量的不同关键迭代。(图片来源) :图片来自作者
图 2 代表不同响应变量的结构,这些变量是在一组共同的独立属性上回归的。(图片来源) :图片来自作者
图 1 显示了线性回归模型的基本结构,其中研究人员或分析人员希望比较最重要的迭代,同时用一组独立属性回归相同的响应变量。然而,在每次迭代中,独立属性都是在考虑一些假设的情况下逐一引入的。这在因果分析和实验中特别有用,因为需要检查每个阶段独立属性的调节效果,以解释关键独立变量之一对响应变量的因果影响。
图-2 表示多元线性回归的基本结构,用于表示独立模型,用于比较数据集的不同响应变量在一组公共独立变量上回归时的结果。这对于比较一项研究中一组常见预测因子或因素对不同反应属性的影响特别有用。这种结构在基于关系的研究中很常见,是记录结论的有用快照。
Stargazer 还可以显示“lm”、“glm”和其他类型模型族的稳健标准误差。它同样有助于显示 logit 家族的β系数和指数标准差的比值比。本文中提到了一些有用的参考资料。如果有人想用 stargazer 做他们的论文或主要项目提交的实验,它们是重要的访问目的地,所以要求将它们放在手边。可以从 这里 和 这里 访问几种 pdf 格式。
需要注意的是,尽管回归的基本本质由于基于树或基于提升的算法迎合大数据的纯粹计算能力而变得成熟,但是涉及不同回归技术的基于关系的研究对于识别重要驱动因素总是有效且必要的。
本文后面的第一个代码片段使用了免费提供的 R datasets 包中的" freeny "数据集。关于……的讨论。bib 文件以及如何为书目创建它们可以在本文开头的链接中找到。使用 stargazer pdf 文档时,必须使用块集中的 results = 'asis '和 stargazer 函数中的 type = "latex"。如果我们处理的因子少于 40 个(在这个数据集中有 4 个),那么 single.row=TRUE 选项会很有帮助。此选项删除两个连续行之间的间距。intercept.bottom=FALSE 选项允许在线性模型中从 intercept 开始(除非我们明确地希望省略 intercept )。pdf 输出文档的快照也显示在代码片段之后。每列代表每次迭代的 beta 值及其相应的稳健标准误差(在括号内)。
图 freeny 数据集上的关键迭代。(图片来源) :图片来自作者
在第二段代码中,我们将处理免费提供的 R datasets 包中的"瑞士 " 数据集。数据帧中每个属性的描述可以在 这里 找到。使用 single.row=FALSE 并从报告中省略 F-statistics(omit . stat = c(" F "))允许在边距内拟合宽表。确保该函数生成的表格适合 PDF 页面的页边距是一项常见任务。与 HTML 不同,HTML 对于作者来说相对容易,并且避免了对边距的详细关注,PDF 输出需要一些额外的努力来遵守边距。
图 4 瑞士数据集上的关键迭代。(图片来源) :图片来自作者
在本文的第三个也是最后一个代码片段中,我们将处理免费提供的 R datasets 包中的" mtcars "数据集。协变量标签选项允许重新标记独立属性。
图 mtcars 数据集上的独立模型。(图片来源) :图片来自作者
结论
使用观星器无疑是很累的,因为需要注意的不仅仅是观星器的功能。作者必须同时考虑页边距、图形宽度、统计模型的整体结构、标题、脚注和字体大小。但是,这是对相关文档的一次性练习。一旦作者创建了一个适合分析的品味和本质的结构,那么为更大的目标修改微小的部分就变得微不足道了。尽管为一个格式良好的 R Markdown PDF 投入了所有的代码编辑、StackOverflow 搜索和自学时间,但结果是短暂而美好的,并且更容易专注于结果的详细解释。虽然不要求必须驻留在这些工具中以生成 PDF 格式的科学文档,但是在旅程结束时,这些亲身经历的记忆并不完全值得删除。这篇文章的意图并不是给人一种作者呼吁读者用半心半意的知识编写代码的印象。这纯粹是为了尊重研究人员、开发人员的辛勤工作,以及 StackOverflow 程序员的贡献,他们让这个 R Markdown 世界变得足够好,足以供基本的论文和报告创作探索和享受。还要注意的是,stargazer 也有一个 python 版本,在这里可以找到,但是到目前为止,如果读者想要估计 R 中的模型,并通过 R Markdown 来表示它们,那么采用 R 版本的 stargazer 将会获得比 Python 多得多的支持文档。原因是它最初是在 R 平台上开发的,随着最新版本的出现;用 Python 来处理数据工程工作,并用 R 来估算它们,变得越来越流行。
谢谢你。
熟悉 Tweepy、NLP 和 Seaborn - Job 招聘
轻松提取、处理、分析和可视化您的推文
Joshua Hoehne 在 Unsplash 上拍摄的照片
Twitter 是向观众分享新闻、信息和情感的最大平台之一。在这个前所未有的时期,许多人失去了工作。在这篇文章中,我们将尝试浏览过去的推文,通过这些推文了解人们对工作的思维过程。我们将从赞和转发的角度来看推文的趋势。我们还将根据它们的位置对它们进行可视化。最后,我们将根据 tweets 中的关键字搜索,根据招聘人员和被招聘人员对他们进行分类。
我们将使用 python 作为我们的编程语言,tweepy 从 Twitter 中提取 tweets。我们将尝试从公司获得一些关于人们工作要求和招聘更新的某些趋势的见解。所以让我们开始导入库。
import csv
import pandas as pd
import csv
import re
import string
import tweepy
import time
import ast
from nltk.corpus import stopwords
from wordcloud import WordCloud
from textblob import TextBlob
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
所有这些库都会在编写代码的某个时候帮助我们。当我们遇到这些细节时,我们会着手处理的。
我们的第二步将是从 Twitter 中提取推文,并将其保存在 CSV 文件中。一个人必须有一个 Twitter 开发者帐户,才能使用 Twitter api 访问推文。下面是创建开发者帐户的链接。
申请接入——Twitter 开发者| Twitter 开发者
def extract_tweets():
auth = tweepy.OAuthHandler(‘xxxxxxxxxx’, ‘xxxxxxxxxx’)
auth.set_access_token(‘xxxxxxx–xxxxxxxx’, ‘xxxxxxxxxx’)
api = tweepy.API(auth)
search_words = “jobs” #enter your words
new_search = search_words + “ -filter:retweets”
csvFile = open(‘jobs1.csv’, ‘a’)
csvWriter = csv.writer(csvFile)
for tweet in tweepy.Cursor(api.search,q=new_search,tweet_mode=’extended’,count=100,
lang=”en”,
since_id=0).items():
csvWriter.writerow([tweet.created_at, tweet.full_text.encode(‘utf-8’),tweet.user.screen_name.encode(‘utf-8’),
tweet.favorite_count,tweet.retweet_count,tweet.truncated,
tweet.user.location.encode(‘utf-8’)])
return
在上面的代码中,我们使用 tweepy 模块初始化 twitter api。在与我们的 twitter 帐户建立连接之后,我们将提取的 twitter 数据添加到 csv 文件中,并开始向其中追加 twitter 数据。我们的数据将包含日期,文本,姓名,喜欢,转发,截断和位置。
注意:提取的推文必须进行编码,因为它们的格式不可读。我们将在接下来的步骤中解码推文。
def read_data():
df=pd.DataFrame()
df=pd.read_csv('jobs1.csv')
df.head()
return df
使用这个函数,我们只需读取我们成功创建的数据。
def pre_processing(df):
df.columns=['Date','Tweet','Name','Likes','Retweet','Truncated','Location']
df['Tweet']=df['Tweet'].apply(lambda x:ast.literal_eval(x).decode('utf-8'))
df['Location']=df['Location'].apply(lambda x:ast.literal_eval(x).decode('utf-8'))
df['Name']=df['Name'].apply(lambda x:ast.literal_eval(x).decode('utf-8'))
df.drop(['Truncated'],inplace=True,axis=1)
return df
现在我们命名这些列,并使用 ast 库将 tweets 解码成可读的格式。
def assorted_tweets(df):
location=['Atlanta, GA','Washington, DC','Los Angeles, CA', 'New York, NY', 'Chicago, IL', 'California, USA', 'Houston, TX',
'San Francisco, CA','New Jersey, USA','Boston, MA','Raleigh, NC','Nashville, TN','Seattle, WA','Pittsburgh, PA',
'Austin, TX','Dallas, TX','California','Portland, OR','Texas', 'Toronto','Phoenix, AZ','New York, USA','Toronto, Ontario', 'Texas, USA','Philadelphia, PA','Denver, CO','New York','Florida, USA','Manchester & San Francisco','Charlotte, NC','Las Vegas, NV','Cleveland, OH','Florida','Pennsylvania, USA','Maryland, USA','Louisville, KY','San Antonio, TX','Brooklyn, NY','Orlando, FL','Washington, D.C.','Miami, FL','Lagos, Nigeria','San Diego, CA',
'Detroit, MI','Colorado, USA','Michigan','Columbus, OH','Los Angeles','Sacramento, CA','New Jersey','Winchester, VA',
'Baltimore, MD','Pennsylvania','Providence, RI','Indianapolis, IN','North Carolina','Virginia, USA','Indiana','Colorado', 'Illinois, USA','St. Paul, MN','Buffalo, NY','North Carolina, USA','Calgary, Alberta']
df_new= df[df['Location'].isin(location)]
df_new.reset_index(inplace=True)
df_new.drop(['index'],inplace=True,axis=1)
return df_new
我们将只考虑美国的数据,因为最多的推文来自该国。这可以通过对数据帧中的“位置”列应用 value_counts 函数来解决。
def view_data():
pd.set_option(‘display.max_rows’, None)
pd.set_option(‘display.max_columns’, None)
pd.set_option(‘display.width’, None)
pd.set_option(‘display.max_colwidth’, None)
return
重要的是,我们能够完整地看到我们的数据,因此我们调用上面的函数,这样可以方便地通过 dataframe 读取 tweets。
def mention_data(df_new):
mention=[]
for i in df_new['Tweet']:
txt=i
x = re.findall("@", txt)
mention.append(x)
df_new['Mentions']=mention
df_new['len']=df_new['Mentions'].map(lambda x: len(x))
mentions['Total']=df_new['len'].groupby(df_new['Location']).sum()
df_new.drop(['Mentions'],inplace=True,axis=1)
return df_new, mentions
我们从统计每条推文的提及次数开始分析。我们还创建了一个提及表,用于将来的广泛分析。
def clean_tweets(df_new):
stop = stopwords.words('english')
df_new['Tweet'] = df_new['Tweet'].apply(lambda x: ' '.join([word for word in x.split() if word not in (stop)]))
df_new['Tweet']=df_new['Tweet'].apply(lambda x: str(x).split('http')[0])
for i in range(len(df_new['Tweet'])):
v = df_new['Tweet'][i]
v = re.sub(r"@[A-Za-z0-9]+", "", v)
df_new['Tweet'][i]=v
return df_new
我们开始使用停用词模块清理我们的推文,并从推文中删除停用词。除此之外,我们删除了标签以及与每条推文相关的“http”链接。我们使用 regex 模块删除 tweets 中的标签和链接。
def create_wordcloud(df_new):
words=''.join(list(df_new['Tweet']))
spam_wc=WordCloud(width=512,height=512).generate(words)
plt.figure(figsize=(8,6),facecolor='k')
plt.imshow(spam_wc)
plt.axis('off')
plt.tight_layout(pad=0)
plt.show()
return
我们创建了一个 tweets 的词云,它给我们提供了所有使用最频繁或不经常出现的词的要点。
def sentiment_analysis(df_new):
sentiment=[]
Type=[]
polarity=0
for i in df_new['Tweet']:
sentiments=TextBlob(i)
sentiment.append(sentiments)
tweet_polarity=sentiments.polarity
if tweet_polarity>0.00:
Type.append('Positive') elif tweet_polarity<0.00:
Type.append('Negative') elif tweet_polarity==0.00:
Type.append('Neutral')
polarity+=tweet_polarity
df_new['Sentiment']=Type
return df_new
我们对我们的推文进行一个非常简单的情感分析。情感是基于极性而被划分的。推文分为正面、负面或中性。我们使用“Textblob”作为我们的 python 模块来帮助我们找到推文的极性。
def recruiter_recruitee(df_new):
df_recruitee = df_new[df_new['Tweet'].str.contains('need')|df_new['Tweet'].str.contains('want work')|
df_new['Tweet'].str.contains('help')|df_new['Tweet'].str.contains('new job')|
df_new['Tweet'].str.contains('looking')|df_new['Tweet'].str.contains('support')]
df_recruitee.drop_duplicates(inplace=True)
df_recruiter = df_new[df_new['Tweet'].str.contains('link bio')|df_new['Tweet'].str.contains('hiring')|
df_new['Tweet'].str.contains('looking')|df_new['Tweet'].str.contains('job opening')|
df_new['Tweet'].str.contains('recommend')]
df_recruitee.drop_duplicates(inplace=True)
return df_recruitee,df_recruiter
我们现在把我们的推文分成 2 个数据帧。我们的第一个数据框架将是招聘人员,第二个将是招聘人员。我们根据单词云中最明显的关键词对它们进行分类。例如,recruitee 中的推文将包含诸如支持、帮助、新工作等词语,而招聘人员的推文包含诸如开放、寻找、推荐等词语。
if __name__ == '__main__':
extract_tweets()
view_data()
df=read_data()
df=pre_processing(df)
df_new=assorted_tweets(df)
mentions=pd.DataFrame()
df_new,mentions=mention_data(df_new)
df_new=clean_tweets(df_new)
df_new=sentiment_analysis(df_new)
df_recruitee,df_recruiter=recruiter_recruitee(df_new)
我们现在可以继续进行可视化。
if __name__ == '__main__':
create_wordcloud(df_new)
我们创建了一个词云来检查我们推文中的常用词。
mentions.reset_index().sort_values(by='Total',ascending=False).head(7)
我们检查在哪个州的人们倾向于在他们的推文中提到其他人。
plt.subplot(121)
df1=df_new[‘Likes’].groupby(df_new[‘Location’]).mean().sort_values(ascending=False).head(7)
df1.plot(kind=’bar’,colormap=’viridis’,figsize=(7,5))
plt.xticks(rotation=45)
plt.subplot(122)
df2=df_new[‘Retweet’].groupby(df_new[‘Location’]).mean().sort_values(ascending=False).head(7)
df2.plot(kind=’bar’,figsize=(12,5))
plt.xticks(rotation=45)
plt.show()
我们创建了一个关于地点的赞和转发的柱状图。我们可以看到,与其他推文相比,来自华盛顿、迈阿密和纽约等大城市的推文产生了更多的影响。
plt.subplot(121)
df1=df_new['Likes'].groupby(df_new['Sentiment']).sum().sort_values(ascending=False).head(7)
df1.plot(kind='bar',colormap='viridis',figsize=(7,5))
plt.xticks(rotation=45)
plt.subplot(122)
df2=df_new['Retweet'].groupby(df_new['Sentiment']).sum().sort_values(ascending=False).head(7)
df2.plot(kind='bar',figsize=(12,5))
plt.xticks(rotation=45)
plt.show()
我们检查哪种类型的情绪获得了最多的喜欢和转发。显然,积极的推文在这方面有优势。
plt.subplot(121)
df1=df_new['Likes'].groupby(df_new['Sentiment']).mean().sort_values(ascending=False).head(7)
df1.plot(kind='bar',colormap='viridis',figsize=(7,5))
plt.xticks(rotation=45)
plt.subplot(122)
df2=df_new['Retweet'].groupby(df_new['Sentiment']).mean().sort_values(ascending=False).head(7)
df2.plot(kind='bar',figsize=(12,5))
plt.xticks(rotation=45)
plt.show()
令人惊讶的是,负面推文平均获得更多的喜欢和转发。
plt.subplot(121)
df1=df_recruitee['Sentiment'].value_counts()
df1.plot(kind='bar',colormap='viridis',figsize=(7,5))
plt.xticks(rotation=45)
plt.subplot(122)
df2=df_recruiter['Sentiment'].value_counts()
df2.plot(kind='bar',figsize=(12,5))
plt.xticks(rotation=45)
plt.show()
我们检查招聘人员和被招聘人员表中的情绪分布。
plt.figure(figsize=(12,5))
plt.subplot(121)
df1=df_recruitee['Likes'].groupby(df_new['Sentiment']).mean()
plt.pie(df1,labels=df1.index,autopct='%1.1f%%',shadow=True)
plt.subplot(122)
df2=df_recruiter['Likes'].groupby(df_new['Sentiment']).mean()
plt.pie(df2,labels=df2.index,autopct='%1.1f%%',shadow=True)
plt.figure(figsize=(12,5))
plt.show()
我们使用饼图来检查喜欢和转发的情绪分布。我们可以看到,中性的推文往往比其他推文产生更多的喜欢。
plt.subplot(131)
a=df_recruitee[df_recruitee['Sentiment']=='Positive']['Location'].value_counts().head(5)
a.plot(kind='bar',colormap='viridis',figsize=(14,6))
plt.xticks(rotation=45)
plt.subplot(132)
b=df_recruitee[df_recruitee['Sentiment']=='Negative']['Location'].value_counts().head(5)
b.plot(kind='bar',colormap='cividis',figsize=(14,6))
plt.xticks(rotation=45)
plt.subplot(133)
b=df_recruitee[df_recruitee['Sentiment']=='Neutral']['Location'].value_counts().head(5)
b.plot(kind='bar',colormap='plasma',figsize=(14,6))
plt.xticks(rotation=45)
plt.show()
与被招聘者表中的位置相关的正面、负面和中性推文。
我们可以看到,与洛杉矶和德克萨斯州的人相比,华盛顿和旧金山的被招聘者更积极。
plt.subplot(131)
a=df_recruiter[df_recruiter['Sentiment']=='Positive']['Location'].value_counts().head(5)
a.plot(kind='bar',colormap='viridis',figsize=(14,6))
plt.xticks(rotation=45)
plt.subplot(132)
b=df_recruiter[df_recruiter['Sentiment']=='Negative']['Location'].value_counts().head(5)
b.plot(kind='bar',colormap='cividis',figsize=(14,6))
plt.xticks(rotation=45)
plt.subplot(133)
b=df_recruiter[df_recruiter['Sentiment']=='Neutral']['Location'].value_counts().head(5)
b.plot(kind='bar',colormap='plasma',figsize=(14,6))
plt.xticks(rotation=45)
plt.show()
关于招聘人员表中位置的正面、负面和中性推文。
同样,我们可以看到,与丹佛和新泽西相比,亚特兰大和芝加哥的招聘人员更加积极。
就这样结束了。我们成功地浏览了我们的推文。我们设法深入了解了不同城市人们对于工作的思维过程。我们还看到了哪些推文在点赞和转发方面更具吸引力。
欢迎留下任何问题或评论!
获得反馈在没有教师的情况下在线学习数据科学
米利安·耶西耶在 Unsplash 上拍摄的照片
当你编码时,你有时会从另一双眼睛那里学到很多东西,那双眼睛会阅读你的工作,捕捉你的错误,并告诉你怎样做得更好。在许多课程中,教师或至少助教会手动阅读你的代码并提供反馈。但是,有些课程是自定进度的课程,您不会从讲师那里获得定制的反馈。即使在这些类型的课程中,你也有向他人学习的方法。
查看相关的问答网站
即使是一个非常有天赋的懂文档的程序员也会经常犯编程错误,尤其是在开始的时候。他们可能不会马上意识到为什么。当我在一个特定的问题上需要帮助时,我的第一站通常是堆栈溢出,有时我会在查看标准文档之前先查看一下。那是一个很受欢迎的问答网站,专注于编程问题的答案。
截图我的。
如果你有一个编程问题,很可能——特别是如果你刚刚开始——许多其他人也有一个非常相似的问题。这些问题和其他人对它们的回答可能已经在网站上分享了。如果你的问题与堆栈溢出略有跑题,同一公司的其他网站 Stack Exchange 涵盖了相关的技术主题。
数据科学不仅是编程,还包括许多其他领域。像 Quora这样的问答网站可以在数据科学的其他领域给你更多的建议,比如分析数据的策略。如果你在某个网站上找不到你的问题,问这个问题,寻求答案,帮助下一个出现的人并不丢人。
开始或加入一个学习小组
你可能还想组织一群人一起学习这门课程。如果你还没有感兴趣的朋友,在社交媒体上发布你对这门课程的兴趣。您还可以加入 Meetup 群组,并将课程作为事件发布在那里。Meetup 是一个为有特殊兴趣的人宣传事件的社交网络。在新冠肺炎登陆之前,它是现场技术活动的主要推广地之一。现在,许多活动都转移到了网上。这可能对你有利,因为你可以在更大的地理范围内吸引同学。
在某些情况下,对你有帮助的事件已经被安排好了。专注于特定技术或更广泛的数据科学的 Meetup 小组可能有办公时间。我所知道的,来自纽约的,可以推荐的团体包括黑客小时、纽约女性编码和纽约 Python Meetup 团体。所有人都至少部分搬到了网上,所以你可以从世界任何地方加入。类似的聚会团体存在于大多数拥有相当规模的技术社区的城市。
如果你经常参加科技活动,你也会接触到一群与你水平相当或略高的人。这个挺有用的。你的朋友可以给你出主意去哪里,如何规划你的职业道路。我在这些活动中遇到的一些朋友已经成为非常成功的技术专家。我仍然和他们保持联系,甚至在他们结婚、有了孩子并搬离纽约多年以后。
寻找你的支持网络
图片来自 nytech.org
一般用途的社交活动大多会吸引那些刚刚开始职业生涯的人。纽约技术联盟组织的纽约技术聚会是吸引更有经验者的一个团体。它的重点是展示崭露头角的纽约科技公司和有趣的项目。它还举办网络会议,让整个技术行业处于职业生涯各个阶段的专业人士和学生能够交流。纽约是世界顶级技术中心之一,即使你在另一个城市,这个团体的在线活动也值得参加。
然而,对你的工作获得个性化反馈的最好方法是多付一点钱,聘请一位行业经验丰富的导师。如果你能找到一个专业数据科学家的好导师,我建议你雇佣他们每周一次或两次,每次一两个小时的指导。这几乎可以像一个现场编码训练营一样教你很多东西,而且价格要低得多。对于美国家教来说,每小时 50-100 美元是合理的。你可以在 Meetup 群和工作论坛上发布你的家教职位,比如说zipcruiter、、Angel.co和。这是一份相当不错的技术职位列表。这里有一些在 Indeed 上辅导工作岗位的例子。
也有可能以更低的价格获得几乎同样质量的教学。如果你有联系大学部门和校友网络的关系,你很可能能够以接近每小时 30-50 美元的价格雇佣一名研究生或高级本科生。这些学生中的一些人在该领域知识渊博,在教学方面很有天赋,他们的辅导质量可以接近专业人士的辅导。或者你可以用更低的价格外包一个家教,可能是外包到国外,使用像 Upwork 这样的平台。尤其是印度是一个讲英语的地方,许多人懂技术,劳动力成本也更低。另一个降低成本的方法是和你的同学分享一个家教的价格。
即使是专业人士也需要知道向哪些专家询问他们专业领域之外的问题。在他们将代码添加到主程序之前,他们通常还会经历一个称为代码审查的过程。在代码评审期间,一个团队成员通读他们的代码。队友经常会有有价值的反馈,即使是世界一流的著名程序员。这类似于写作,另一个强调可读性和优雅的领域。即使是最伟大的作家也有编辑,一个人与编辑一起工作的能力可以增强他的写作能力。我知道——我不仅为专业报纸和杂志写过文章,还在谷歌做过软件工程师。与写作中的编辑过程一样,代码审查是严格的软件开发过程中的关键步骤。
这是我写的另一篇文章,提供了更多关于在自学课程中学习数据科学的技巧。
进入数据科学:自学与训练营
哪种方法更好?
今天的世界允许我们超越学位和地理位置自由思考。互联网让世界各地的人们能够访问相同的数据,相互交流,相互学习。技术的爆炸使一切成为可能,使人们在 30 岁或 40 岁,甚至更晚的时候开始新的职业成为可能;使学生有可能在其他国家上学和学习课程。
虽然,有很多选择通常是一件好事,因为你可以根据自己的能力和情况选择最适合自己的。例如,如果你考虑从事数据科学,你有不止一个选择来实现这个目标。如果你还年轻,还在读高中,或者更年轻,那么获得计算机科学或任何相关领域的学士学位可能是你想要的起步。
但是,如果你年纪大了,已经尝到了工作生活的滋味,并考虑换一份职业,回到学校可能不是你的理想选择——甚至不是一个选择。因此,你通常有两种选择,要么带着一些钱(通常是很多钱)去训练营待几个月,要么系好安全带,打开笔记本电脑,在网上搜索信息。
这两个选项都是有效的,并且通常可以在不考虑您的物理位置的情况下完成。但是,一个比另一个需要更多的钱,这并不总是可行的。那么,你该走哪条路呢?有没有一种方法最终能保证一份工作?哪个更容易?本文将为您解答这些问题。
选项 1:参加训练营
让我们从选择参加训练营开始吧。这适用于您在 COVID 时代前后亲自或在线参加训练营。在过去的十年里,教授任何与技术相关的东西的训练营的数量呈指数级增长。这个数字的增加是对程序员、开发人员和数据科学家需求的增加。
参加训练营是一个非常诱人的选择,前提是你有足够的资金。现在,有数百家公司提供与数据科学相关的训练营,比如,熨斗,旅行车,总装, Thinkful 等等。这些公司的学费从 9500 美元到 17900 美元不等,承诺时间长达 15~20 周。
训练营职业选手
- 参加训练营将为您提供所需的数据科学实用知识。
- 你可以参加专注于一个特定主题或数据科学方面的训练营,如机器学习、人工智能或数据分析。
- 有些训练营的承诺只有 3 个月,这意味着在相对较短的时间内转行是一个很好的选择。
- 参加训练营将有助于你开始建立项目组合,积累实践经验。
- 如果你想有朋友与你分享学习之旅,这是一个很好的选择。
</7-tips-for-data-science-newbies-d95d979add54>
训练营囚犯
- 在我看来,训练营最大的缺点是它会变得多么昂贵。学费高达 18,000 美元,许多人负担不起参加训练营的费用,即使他们想要你。有时,一些公司提供奖学金和学费折扣,但这并不总是可行的。
- 几乎所有的训练营都在他们网站的第一页承诺在短时间内完成工作安排,这导致人们获得一些虚假的希望。因为即使你成功地完成了一次训练营,你也会发现找工作的困难。毕竟,这完全取决于就业市场的要求和你的投资组合。
- 由于大多数训练营专注于一个特定的主题或主题的一个特定方面,他们往往会忽略你在职业生涯中某个时候需要的计算基础。
选项 2:跟随自己的步伐(自学)
本文中我们考虑的另一个选项往往是最常见的选项,也是我个人在学习数据科学时采取的选项,也就是自学选项。自学是互联网的优势之一,也是世界的开放性。如果你今天想自学一些东西——不一定是科技话题——你可以在网上找到无穷无尽的资源。
这很神奇,因为你开始自学所需要的只是一些热情、开始,以及——这是棘手的部分——一个稳定的互联网连接,或者至少是一个体面的连接。在线学习数据科学有许多选择,从像 DataCamp 、 DataQuest 这样的伟大资源,以及像 Coursera 和 edX 这样的一些更普通的教育网站。
自学专家
- 通常,选择自学要比参加训练营便宜得多——如果不是免费的话,这使它成为世界各地许多人的有效选择。
- 当你自己做的时候,你可以完全控制自己的时间。例如,你想什么时候开始,什么时候结束,你想以多快/多慢的速度处理每个方面。
- 当你独立学习时,你可以在任何话题上想多深就多浅。
- 自学数据科学将教会你如何独立,知道如何在正确的地方寻找信息。
- 你将学会如何解决你面临的任何问题。因为你是自己做的,你会发展出一种高效处理和解决问题的技术。
</5-online-data-science-courses-you-can-start-now-748e4a2b5403>
自学的缺点
- 自学最难的是,你不会有一条结构化的道路可走。你需要制定自己的课程,或者在网上找一个,然后坚持下去。如果你参加免费的在线自学课程,情况可能就不一样了。
- 既然你是一个人去,那么有时很容易失去动力,感觉自己是一个人在经历旅程,这可能会让事情花的时间比应该花的时间长。然而,你可以通过加入一个在线社区并在旅途中结交朋友来克服这一点。
- 与训练营不同的是,你需要选择你所从事的项目,并努力让它们变得强大和有效,以便在适当的时候让求职过程变得更加容易。
最后的想法
无论你在生活中想做什么,有很多方法可以达到那个目的。做出选择并坚持到底——或者如果你想改变它——完全取决于你。如果你想转行进入数据科学领域,这同样适用。数据科学是一个充满无限机遇和机会的伟大领域。这是一个适合许多有不同激情的人的领域。
但是,进入这个领域并不总是简单的。进入数据科学有很多方法。例如,你可以去重点学习数据科学的学校,你可以参加许多在线或面对面的训练营,或者你可以浏览网页,自学。
</5-new-data-science-books-that-you-should-consider-reading-c90aec1d5b0d>
所有这些选项都是有效的,你的选择将取决于你作为一个人,你的物理位置,你的目标,以及你想如何实现它。这篇文章向你展示了两个最重要的选择:参加训练营或者按照自己的进度自学。我想告诉你的是,这些选择没有一个能百分百保证找到工作。但是,如果你努力工作,建立一个好的投资组合,你会得到你想要的工作,不管你走的是哪条路。
从熊猫数量中获取更多价值()
有效使用熊猫count()
方法的 5 个技巧
苏珊·霍尔特·辛普森在 Unsplash 上的照片
熊猫图书馆是最受欢迎的数据操作和分析工具之一。数据科学家通常花费大部分时间探索和预处理数据。谈到数据分析和理解数据集,Pandas count()
是了解非 NA 数量的最常用方法之一。
这个方法很快,很快,很容易理解,但是,大多数时候,我们最终使用了带有默认参数的count()
。在本文中,您将了解如何从中获得更多价值。这篇文章的结构如下:
- 对每一列和每一行的非 NA 细胞进行计数
- 在多指数数据框架上计数非钠细胞
- 仅用
numeric_only
计数数字 - 将
count()
应用于groupby()
结果 - 将计数组合回原始数据帧
源代码请查看笔记本。
访问 Github Repo 获取其他教程
1.对每一列和每一行的非 NA 细胞进行计数
Pandas count()
用于计算给定轴上非 NA 细胞的数量。值None
、NaN
、NaT
和可选的numpy.inf
被认为是NA
。
例如,默认情况下,该方法对每一列的非 NA 进行计数
df = pd.DataFrame({
"Person": ["John", "Tom", "Lewis", "John", "Myla"],
"Age": [24., np.nan, 21., 33, 26],
"Single": [False, True, True, None, np.datetime64('NaT')],
"Department": ["Product", "IT", "IT", "IT", "Product"]
})>>> **df.count()**Person 5
Age 4
Single 3
Department 5
dtype: int64
如果我们希望对每行的非 NA 进行计数,我们可以将axis
参数设置为1
或'columns'
:
>>> df.count(**axis = 1**)0 4
1 3
2 4
3 3
4 3
dtype: int64>>> df.count(**axis = 'columns'**)0 4
1 3
2 4
3 3
4 3
dtype: int64
2.在多指数数据框架上计数非钠细胞
一个多索引数据帧允许多个列作为一个行标识符,多个行作为一个标题标识符。例如,让我们用性别和幸存的列作为索引来加载泰坦尼克号数据集。
df = pd.read_csv(
'titanic_train.csv',
**index_col=['Sex', 'Survived']**
)
df.head()
作者图片
例如,我们可以设置参数level
来计算非 NA 以及特定的索引级别
df.count(**level='Sex'**)
熊猫count(level='Sex')
作者图片
df.count(**level='Survived'**)
熊猫count(level='Survived')
作者图片
如果您想了解更多关于 MultiIndex 的信息,请访问:
[## 在熊猫的多索引数据框架中访问数据
towardsdatascience.com](/accessing-data-in-a-multiindex-dataframe-in-pandas-569e8767201d)
3.仅在数字上执行count()
在熊猫count()
中有一个关于numeric_only
只配置数字计数的争论。值 float 、 int 和 boolean 被认为是数字。
参数默认为False
,我们可以将它设置为True
来只计算数值:
>>> df.count(**numeric_only=True**)PassengerId 891
Pclass 891
Age 714
SibSp 891
Parch 891
Fare 891
dtype: int64
4.将 count()应用于 groupby()结果
Pandas [groupby()](/all-pandas-groupby-you-should-know-for-grouping-data-and-performing-operations-2a8ec1327b5)
允许我们将数据分成不同的组来执行计算,以便更好地进行分析。
一个常见的用例是按某一列进行分组,然后获取另一列的计数。例如,让我们按“部门列进行分组,并获得“单个”值的计数。
df = pd.DataFrame({
"Person": ["John", "Tom", "Lewis", "John", "Myla"],
"Age": [24., np.nan, 21., 33, 26],
"Single": [False, True, True, None, np.datetime64('NaT')],
"Department": ["Product", "IT", "IT", "IT", "Product"]
})>>> **df.groupby('Department')['Single'].count()**Department
IT 2
Product 1
Name: Single, dtype: int64
或者,我们也可以使用聚合agg('count')
方法。
>>> df.groupby('Department')['Single']**.agg('count')**Department
IT 2
Product 1
Name: Single, dtype: int64
我们已经对groupby()
结果的特定列执行了count()
。事实证明,我们实际上不必指定像 Single 这样的列。如果没有列,它会将count()
应用于所有列,例如:
>>> df.**groupby('Department').count()**>>> df.**groupby('Department').agg('count')**
如果您想了解更多关于groupby()
的信息,请查看:
5.将计数组合回原始数据帧
在某些情况下,您可能希望将计数写回原始数据帧,例如,我们希望追加一列 department_total_single ,如下所示:
作者图片
这个任务中棘手的部分是,df.groupby()['Single'].cout()
返回只有 2 行的序列(如下所示),它不会匹配原始数据帧中的行数。
>>> df.**groupby('Department')['Single'].count()**Department
IT 2
Product 1
Name: Single, dtype: int64
一种解决方案是将上述结果转换成 DataFrame,并使用merge()
方法组合结果。
>>> temp_df = df.groupby('Department')['Single'].count().**rename('department_total_count').to_frame()** >>> temp_df.**reset_index()**
>>> df_new = pd.**merge(df, temp_df, on='Department', how='left')**
熊猫分组和合并(图片由作者提供)
这当然有助于我们的工作。但是这是一个多步骤的过程,需要额外的代码来获得我们需要的形式的数据。
我们可以使用transform()
函数有效地解决这个问题。一行代码就可以解决应用和合并问题。
>>> df.groupby('Department')['Single']**.transform('count')**0 1
1 2
2 2
3 2
4 1
Name: Single, dtype: int64
我们可以看到transform()
的结果保留了与原始数据集相同的行数。因此,我们可以简单地将结果赋给原始数据帧中的新列:
>>> **df['department_total_single']** = df.groupby('Department')['Single'].transform('count')
熊猫transform('count')
(作者图片)
如果您想了解有关 merge()和 transform()的更多信息,请查看:
结论
在本文中,我们探索了熊猫counts()
的不同用例。它非常方便,是探索性数据分析和数据预处理中最受欢迎的方法之一。
我希望这篇文章能帮助你节省学习熊猫的时间。我建议你查看一下关于counts()
API 的文档,并了解你可以做的其他事情。
感谢阅读。请查看笔记本获取源代码,如果您对机器学习的实用方面感兴趣,请继续关注。
你可能会对我的其他一些熊猫文章感兴趣:
- 9 个熊猫 value_counts()提高数据分析能力的窍门
- 所有熊猫 json_normalize()你应该知道的扁平化 JSON
- 使用熊猫方法链接提高代码可读性
- 如何对熊猫数据帧进行自定义排序
- 数据分析你应该知道的所有熊猫移位()
- 何时使用 Pandas transform()函数
- 你应该知道的熊猫串联()招数
- Pandas 中 apply()和 transform()的区别
- 所有熊猫合并()你应该知道
- 在 Pandas 数据帧中处理日期时间
- 熊猫阅读 _csv()你应该知道的招数
- 用 Pandas read_csv()解析日期列应该知道的 4 个技巧
更多教程可以在 Github 上找到
获得我的 Google Tensorflow 开发者证书
我得到一个的原因,以及帮助我的资源
最近拿到了 Tensorflow 开发者证书,被 Tensorflow 开发者网录取了!这是一个小小的挑战——在 5 个小时的考试中(我已经很久没有这样做了)解决 5 个跨回归、计算机视觉、NLP 和时间序列预测的问题,所有这些都是通过使用 TF 2.0 的深度神经网络完成的。
虽然拿到证书很好,但最有价值的是学习。在这篇文章中,我分享了我旅途中的一些心得和建议。
作者创作的图像
为什么我会考虑买一个?
多年来,我使用 Tensorflow (TF)或 Pytorch 在深度神经网络方面积累了许多不同的项目经验(包括工作和个人经验)。我还非常幸运地成为 ThoughtWorks Australia 活跃的 ML 社区的一员,在这个主题上一起讨论和学习,并得到了 mat kelcey 的指导——他是在 Google Brain 工作时 TF 的早期采用者之一,也是一个分享知识的了不起的人。
尽管如此,我仍然觉得我的知识相当零散。还有一点冒名顶替综合症。我不知道我是否只是触及了表面,可能遗漏了一些关于 TF 框架提供了什么(很有可能)或者它还能提供什么的重要知识。
去考 TF 证书是一个很好的方法来获得关于这个主题的全面的知识覆盖。
一个很好的起点是 TF 的候选人手册。读完技能清单部分后,我被说服了。显然有很多东西要学。它涵盖了从使用传统表格数据、计算机视觉、NLP、数据增强到预测模型的所有主题,所有这些都与深度学习和 TF 有关。和一些数据争论技巧。
最后,自从最近在 NAB 企业数据科学团队担任新角色以来,我获得了一些额外的动力。我们确实有一些令人兴奋的项目,也有许多具有强大研究或行业背景的人。虽然我的角色是技术和人员领导的结合,但我渴望不断更新自己的技术能力,为团队提供有用的技术输入,并帮助指导团队了解 AI/ML 技术雷达的最新动态。
我的学习之路
我不需要在这里重新发明轮子,只需要遵循社区和官方指南的建议。最重要的学习资源是:
- Andrei Neagoie 和 Daniel Bourke 在周日举办的 TF 课程。附带的资源非常好——强烈推荐练习 Github repo 中的所有章节。还有很多关于 TF 和深度学习的技巧。
- Coursera 上的官方推荐课程。虽然这是相当基础的——这是一个 4 周的课程,但是一旦你或多或少精通了 TF——它可以在一天内完成(我确实在一天内完成了)。很高兴有一个好的检查点(和另一个证书收集的乐趣:-)
- 有一个好的 TF 代码记忆肌肉对通过考试真的很有用(这是一个 5 小时的考试)——最好的方法是用你的玩具考试从头开始写东西。只是一遍又一遍的模型定义、model.compile()和 model . fit()😃。我做了一些有趣的工作,建立 MLs 来识别我家里的人(你可以在本地做,所以隐私风险很低)。
- 我意识到我通过练习自己的问题学到了最多的东西。当我没有遵循教科书时,我犯了很多错误——通过这些错误,我更加意识到构建 DNNs 时所有事情的细微差别。例如,对输入要素进行重缩放和不进行重缩放的区别有多大?
一些实用的考试技巧
最后,一些额外的提示:
- 第一个是从所有参加过考试的人那里寻找窍门!例如,这里的就是一个有用的例子。
- 准备好一些助手函数是很好的,这些函数可以帮助做一些事情,例如检查点最好的训练模型、提前停止、tensorboard 回调等等。
- 考试将在 PyCharm 中进行(我是一个 VS 代码人员,但是找到转换并不太难。同样好的老 JetBrains IDE)。确保你在考试前在这种环境下练习得足够好。
- 我发现在开发环境中拥有一个包含所有必需的包和依赖项的本地设置非常有用。不要只是在 Google Colab 中练习东西,重要的是要确保东西可以在你的机器上运行,获得相同的一致结果和性能(比如训练速度——以验证这一切都调整正确)。更具体地说,我使用了:
- Pyenv for Python runtime(将使用 3 . 8 . 0)/poems for dependency management(但考试还要求将特定版本的依赖项直接安装到他们的 PyCharm 插件中,因此请确保您也尝试了这一点)。
- 当您在本地开发时,确保您可以在本地环境中启动 jupyter lab(具有相同的依赖集)也很方便。如果你想快速地/交互地尝试一些事情,并受益于一个活动的有状态会话,这是一个不错的选择。
- 5 小时考试很棘手!确保你已经选择了简单的午餐或晚餐:-)
从这里去哪里?
显然 Mat 说的是 Jax!对我来说,经历这些提醒我把学习当成马拉松,而不是短跑。一个好的学习经历是一个很大的正面强化,可以帮助我走下去。
获取 NYT 文章数据并将其保存到 SQL 数据库中
从纽约时报 API 获取文章数据并保存到 SQLite 数据库
斯蒂芬·瓦伦丁在 Unsplash 上拍摄的照片
介绍
本周,我决定学习更多关于文字处理的知识,从基于报纸数据构建一些文字云开始。同时,我想提高我收集数据并将其保存到数据库中的知识。
我在这里的主要目标是获取并保存一些我可以使用的有趣数据。我认为 2020 年的报纸文章会很有趣,可以看到每个月的新闻主题。
最初,我从不同的报纸档案中寻找文章。有许多很棒的工具,但我能找到的提供 API 的工具并不多。我发现《纽约时报》确实有一个 API,提供与他们的文章相关的数据。
这是一篇记录我的学习历程的文章,从 API 获取数据并保存到 SQLite DB。
关于 API
这些 API 可在 https://developer.nytimes.com/apis获得
我发现 API 的文档(包括https://developer.nytimes.com/faq的常见问题解答)对入门非常有用。
《纽约时报》提供了许多不同的 API,包括 Books API,其中包含有关畅销书列表和书评的信息,Film API,用于电影评论,以及 Community API,其中包含有关用户生成的内容(如评论)的信息。
在本文中,我使用的是归档 API(https://developer . nytimes . com/docs/Archive-product/1/overview)。如果您将年份和月份传递给 API,它将返回该月的文章数据。文章数据告诉我们很多事情,包括 NYT 网站上的全文,发表时间,标题和导语。
获取访问权限
使用 API 的第一步是建立一个帐户并获得访问权限(https://developer.nytimes.com/get-started)
要求
我使用了请求、 sqlite3 和时间。
步伐
我在这里经历三个步骤。我:
- 连接到 API 以浏览可用的数据,并查看我想要保存的数据。
- 基于我要保存的数据建立一个数据库表。
- 获取一年中每个月的数据并保存到数据库中。
探索数据
在这里,我导入我将使用的内容。请求将调用 API, sqlite3 用于与数据库和时间交互,因此脚本可以在调用之间休眠。医生建议两次通话间隔 6 秒,以避免达到极限。
import requests
import sqlite3
import time
在这一行中,我发出一个初始请求来查看数据是什么样子的。您的纽约时报 API 帐户中生成的 API 密钥将放在[您的 API 密钥]占位符中。使用这个 API 进行身份验证非常简单
data_2020_01 = requests.get("[https://api.nytimes.com/svc/archive/v1/2020/1.json?api-key=](https://api.nytimes.com/svc/archive/v1/2020/1.json?api-key=rukHkq9CptpyckwG9qfMpHX7C06rn9zK)[YOUR API KEY]")
归档 API 将数据作为 JSON 响应返回。该信息在 API 网站上给出,但是也可以检查请求响应头,以查看返回的内容类型。是“应用/json”:
知道了这一点,我可以使用 Requests 自己的 JSON 解码器将响应转换成 python 字典:
data_2020_01_json = data_2020_01.json()
打印数据显示这是一本字典。文章本身包含在字典的列表中:
data_2020_01_articles = data_2020_01_json['response']['docs']
该列表的长度为 4480,这意味着它包含以下数量的文章:
为了探究一篇文章,我在列表中取一个数字,直到 4480,来查看它。例如,在位置 10 的文章:
data_2020_01_articles[10]
关于这篇文章有很多信息——比如它的 web_url、lead_paragraph、它在哪个部分(section_name)以及它发表的时间(pub_date)
我想先保存标题、引导段落和出版日期。我认为材料的类型也可能是有趣的,还有字数、主要标题、印刷页、新闻桌和版块名称。
数据库
数据库有许多选项。这里我使用 SQL lite。这样做的一个主要优点是我可以很容易地用 python 创建它并与之交互。我在https://docs.python.org/3/library/sqlite3.html使用文档工作
构建数据库
我想在我们的数据库中保存作为一行返回的每篇文章,并为上面提到的每个字段(即,主标题,打印页面,新闻桌面等)列。,)
我正在创建的特定列:
_id (这将是文章的唯一 id。API 为每篇文章返回一个), web_url , main_headline , pub_date , news_desk , section_name , type_of_material , word_count 。
创建数据库和表
使用 python 直接连接和创建数据库:
connection = sqlite3.connect('nytimes_articles.db')
创建一个游标对象,以便我可以开始执行查询:
cur = connection.cursor()
使用游标的 execute 方法创建表:
cur.execute('''CREATE TABLE articles(_id TEXT, lead_pargraph TEXT, web_url TEXT, main_headline TEXT, pub_date TEXT, news_desk TEXT, section_name TEXT, type_of_material TEXT, word_count INT)''')
保存数据
所以,我想得到一年中每个月的数据。早些时候,我获取了一个月的数据,以探索数据的结构,但现在我需要编写一个函数来获取每个月的数据,然后将每个月的数据保存到刚刚创建的数据库中。
在这里,我编写了一个函数来为我想要获取数据的每个月生成一个 URL。
def generate_urls():
month_range = range(1,13)
api_key = "[YOUR API KEY]"
urls = []
for month in month_range:
url = (f"[https://api.nytimes.com/svc/archive/v1/2020/{month}.json?api-key={api_key](https://api.nytimes.com/svc/archive/v1/2020/{month}.json?api-key={api_key)}")
urls.append(url)
return urls
我将遍历我要访问的 url 列表(由上述函数返回,访问每个 URL,并使用每个月返回的数据,遍历文章列表。然后,我将数据库中每一行的值添加为一个元组,然后将每个元组存储在一个列表中。每个月结束后,我都会把这些写在数据库里。
重要的是,数据以与数据库中的列相同的顺序保存在元组中,即:_id、lead_paragraph、web_url、main_headline、pub_date、news_desk、section_name、type_of_material、word_count
month_urls = generate_urls()for month in month_urls:
data = requests.get(month)
data_json = data.json()
data_articles = data_json['response']['docs']
values_for_db = []for article in data_articles:
row = (article['_id'], article['lead_paragraph'], article['web_url'], article['headline']['main'], article['pub_date'], article['news_desk'], article['section_name'], article['type_of_material'], article['word_count'])
values_for_db.append(row)
cur.executemany('INSERT INTO articles VALUES (?,?,?,?,?,?,?,?,?)', values_for_db)
time.sleep(6)
connection.commit()connection.close()
数据
我使用了 SQLite 的 DB 浏览器来查看文章数据。在这里,我可以很容易地看到保存了什么。55,493 篇文章的数据:
作者图片
我发现使用这个 API 非常简单,它有很多关于纽约时报上文章的有趣信息。虽然 API 没有提供整篇文章的文本,但是 lead_paragraph 字段应该是每篇文章中提到的内容的一个很好的指示器。今年,我计划在文字云可视化之前对文本进行命名实体识别。这也可能是用于情感分析的有趣数据。
介绍图片是斯蒂芬·瓦伦丁在 Unsplash 上的一张照片。其他所有图片均由作者拍摄。本文中使用的代码可以在这里找到:
https://github.com/LiamConnors/Medium-articles
作为一名有抱负的数据科学家受到关注
在竞争激烈的就业市场脱颖而出的秘诀
这篇文章交叉发布在我的网站 https://www.dscrashcourse.com/上,与我们为有抱负的数据科学家策划的其他指南放在一起。
对于任何喜欢与数字和分析打交道的人来说,数据科学家是一个受欢迎的职业选择。曾被《哈佛商业评论》称为“21 世纪最性感的工作”,这一行业的受欢迎程度导致其求职者和新兵训练营饱和。
在如此多的兴趣和竞争下,有抱负的数据科学家越来越难在就业市场上脱颖而出并受到关注。
那么,一个有抱负的数据科学家如何才能脱颖而出呢?
首先,理解数据科学角色的现实很重要,尤其是它对初级和入门级职位的要求。
数据科学职称已经成为所有从事数据工作的人的总称。这些角色中有很多本质上都是分析型的——提取数据、分析数据和分享结果。其他人将更加关注数据质量和可访问性——构建 ETL 管道、监控数据完整性和服务水平协议。很少有初级职位会处理模型构建和机器学习。
这种现实会成为从事数据科学职业的障碍吗?
如果没有,那就太好了。确保你了解你申请的是什么类型的职位,以及哪些技能与这个职位相关。让你的简历符合这些技能。例如,业务分析师可能有从数据中分析和产生洞察力的经验。尽管这不是一次“数据科学经历”,但它仍然与许多数据科学职位密切相关。
这里有一些其他的方法可以让你的个人资料脱颖而出。
有形的项目来展示你可以应用你的知识
我们很幸运能够使用各种工具来简化模型构建和数学计算。有了这个工具,我们可以在评估候选人的理论背景时更加宽松,尤其是那些更初级的候选人。
有抱负的候选人应该把重点放在应用他们的知识来构建在现实世界中有用的数据产品的能力上。
这里有一个好的副业项目的小清单:
我在这个项目中使用了正确的框架吗?它们与当今的行业相关吗?它们对这种特殊的应用有意义吗?
以一个 Python 项目为例:您有诸如 TensorFlow 和 Scikit-learn 之类的去因子库来满足您的大多数建模需求。这些图书馆有充分的理由变得受欢迎。如果你偏离了这些标准,你应该问问自己你的选择是否有意义。这很重要,这样 1)你就不会在不需要的时候重复发明轮子,2)你所展示的技能是相关的。
我是否展示了良好的软件工程实践?我的代码是可测试的、可维护的和可解释的吗?我的作品有多大的可复制性?
始终确保您在编写代码时考虑到了受众——其他人是否容易贡献或审阅您的代码?几周后理解你的代码容易吗?不管他们使用什么机器,安装说明都应该清晰明了。
我表现出很强的解决问题和沟通技巧了吗?我的工作有记录吗?我做这些决定的原因清楚吗?
解决问题和沟通是成为一名成功的数据科学家的两项关键技能。能够交流你的想法(尤其是为什么组件)是一个好科学家和像 AutoML 这样的工具之间的区别因素。
建立强大的在线形象
一旦你有一套要展示的作品,确保它很容易被拿到。强烈建议您通过 GitHub 这样的平台公开共享您的代码。这将使未来的雇主更容易找到并浏览你的工作。
让大家知道你的在线状态。维护一个技术博客,在那里你可以分享想法和知识,这会补充你的简历,让你的工作更容易被发现。考虑建立一个个人网站,进一步展示你的热情和技能。
积极参与社区活动。尽你所能为开源项目做贡献,无论是公开你经历过的问题还是对他们的代码库做一些小的改进。
加入一两个社区
有大量面向数据科学从业者的在线社区。这里有一个数据科学和机器学习松散社区的列表,你可以加入。
也要留意当地的社区,无论是在线的还是面对面的(meetup.com 是一个很好的起点!).这些社区通常会在你附近与当地的专业人士和雇主一起举办活动。这是建立关系网和找工作的绝佳机会。
继续学习并构建您的工具包
数据科学家身兼多职。要想在这个职位上取得成功,你需要掌握多种多样的技能。这个行业变化也非常快,需要大量的学习才能跟上这些变化。
永远不要停止学习,永远不要停止成长。
通过培养学习的倾向来掌握这些变化。承认自己的优势和劣势,制定可行的计划来不断提高自己。
感谢您的阅读!
如果你喜欢这篇文章,可以看看我关于数据科学、数学和编程的其他文章。请通过媒体关注我的最新消息。😃
作为一个业余爱好项目,我还在www.dscrashcourse.com建立了一套全面的免费数据科学课程和练习题。
如果你想支持我的写作,下次你报名参加 Coursera 课程时,可以考虑使用我的会员链接。完全公开—我从每一次注册中获得佣金,但不会对您产生额外费用。
再次感谢您的阅读!📕
AI 为什么这么哑?
为什么自动化知识获取提供了前进的道路。
集体推理主题图(图片由作者提供)
“为什么 AI 这么哑?”是 IEEE Spectrum 十月号封面故事的标题。在一系列文章中,对人工智能的全面分析表明,我们正处于人工智能应用和人工智能研究前进道路的重要转折点。本文的目的是探讨这个问题提出的结论,并提出一个前进的方向。我们正在走向一个新的人工智能冬天,还是有一条承诺持续增长和价值的前进道路?
我度过了第一个人工智能冬天。
作为第一次人工智能 IPO(INAI——intelli corp)的领导者和 1986 年 AAAI 的联合主席,我经历了人工智能浪潮取得巨大成功的喜悦。那些在漫长寒冷的冬天后遗失的故事,包含了前进道路的线索。几乎每一位领先公司的首席执行官都关注并在构建专家系统和其他人工智能应用程序上下了 R&D 赌注。一些非常成功的原型导致了广泛的新应用类别,例如需求预测/定价、配置管理、诊断方法和欺诈检测等等。承诺是巨大的,但成本高于收益。结果,成功的应用程序类别演变成了传统的软件应用程序。人工智能技术提供的生产力是有价值的,但广泛采用也有障碍。
可扩展性的最大障碍之一是知识获取是一个劳动密集型的过程。然而,困难并没有阻止大家。80 年代中期我在道格·勒纳特的办公室。他的既定任务是:建立一个庞大、全面的知识库。近 40 年后,该项目继续进行,并找到了效用。也就是说,手工制作知识库限制了可伸缩性。
在封面故事概述中,有两条引言阐明了当前的事态:
“无论是道格拉斯·莱纳特(Douglas Lenat)的 Cyc 等象征性人工智能项目,还是杰弗里·辛顿(Geoffrey Hinton)、扬·勒昆(Yann Lecun)和约舒阿·本吉奥(Yoshua Bengio)开创的深度学习进展,都还没有产生人类水平的智能。”
“就过去 20 年我们在这项工作上取得的进展而言:我认为我们今天的智力水平还远远没有接近一个 2 岁孩子的水平。但也许我们有相当于低等动物感知的算法。”
第一个评论指出了当前事态带来的限制:手工制作的人工智能系统无法扩展。第二种观点认为,基于从数据中学习数学模式的方法(尽管确实强大有力)不足以捕捉人类智能的本质。最后,朱迪亚·珀尔进一步阐述了这一观点:
“你比你的数据聪明。数据不懂因果;人类会……最可靠的知识是你自己构建的。”
珀尔的评论暗示了一条前进的道路,我们将在后面的段落中继续探讨。
虽然对人工智能局限性的认识越来越突出,但该领域的研究人员也认识到了这些局限性。几年前,我参加了麻省理工学院的一个会议,该会议标志着麻省理工学院智能探索的启动,这是一个促进人类和机器智能研究的广泛倡议。斯坦福和伯克利启动了类似的项目,以深化理解智能(人类和人工智能)本质的跨学科研究。此外,美国国家科学基金会(NSF)和美国国防部高级研究计划局(DARPA)的各种研究计划,都试图为整合人类认知和人工智能模型建立更好的基础。认识到限制和需要,人工智能的实际应用的前进道路是什么?
正如 MIT-IQ 所表明的那样,广义人工智能正在步入基础研究的漫长道路。前进的最佳途径是什么?我们能利用人工智能和集体智慧的发展吗?我相信答案是肯定的。尽管如此,它仍然需要通过找到人类协作学习和深度学习的共同点,深入地重新构建我们如何处理人工智能应用。一种新颖方法的精髓始于 90 年代末。
随着人工智能冬天的到来,我离开人工智能 5 年,并在 1992 年成为苹果公司的 CEO。Connect 成为电子商务平台,于 90 年代末上市。在我接近 Connect 的时候,一个朋友带着他最初称之为“思考游戏”的过程来找我。⁴:这是一个协作学习和融合的人工过程,最初是用索引卡实现的。这一过程和由此产生的模型是受研究科学发现过程的启发。⁵在 90 年代末,我们创建了一个基于网络的协作学习平台,我们将其注册为“适应性对话”宝洁公司和 NBC 是这项技术的早期采用者。我们能够证明,人们可以通过了解消费者喜欢某种产品或观众喜欢(或不喜欢)电视节目的原因来做出预测。
《适应性对话》的工作与《群体的智慧》和《引爆点》的出版同时进行。第一本书指出了什么成为了集体智慧的科学,第二本书涵盖了突现模式如何发展成为更重要的市场现象。集体智慧是关于我们如何一起变得更聪明。正如在《引爆点》中所讨论的,复杂适应系统模拟了导致巨大影响的早期趋势。
结合集体智能和复杂适应系统:人工智能的新框架
人工智能新框架的核心技术是从人类集合中获取知识,并使用我们称为集体推理的过程将这些知识存储在一个活的计算模型中。具体来说,集体推理过程构建了包含参与者集体智慧的概率图形网络。因此,人工智能是一种超级智能的会议主持人,它通过一个平衡发现与优化学习一致性的过程来指导团队,最终产生一种可能性和一种解释。 在嵌入了启发式模型(例如,决策规则或记分卡)的模板的驱动下,系统返回结果的概率估计以及对集体推理的完整解释。
通过与领先的消费品公司(P&G、乐高、NBC、Intuit)合作 12 年,我们了解到从自下而上的消费者对话中学习偏好(例如,你想体验什么?)是可靠的预测。核心自适应学习算法可以产生语句的相关排序。排名准确性通过了 CPG 和媒体领域全球领先的市场情报专业人士的审查。我们还了解到,它引起了高层管理人员的注意,导致技术推动了 Reichheld 的 NPS 书籍《一个问题》中五个案例研究中的两个。它创造了创新的变革案例,乐高就是一个最好的例子。时任乐高 Direct 首席执行官的他利用这项技术与乐高社区共同创新了《星球大战帝国歼星舰》,他从一个简单的问题开始:“当你把你的乐高倒在地板上时,你想体验什么?”
适应性学习奏效了。它将定性对话转化为定量预测结果,但我们只是触及了表面。我们不理解这次演出的根本原因。除了通过服务(例如,没有可靠的 NLP 技术),我们没有任何方法来处理结果,结果是一个报告。我们需要强大的 NLP 技术来释放整合人类和人工智能的新框架的力量。
整合人类和人工智能
集成人类和人工智能的框架在⁶的其他地方有更详细的描述,它由三个可互操作的组件组成:1 .使用隐马尔可夫建模技术基于对等体的学习对齐来学习系统的所有原因的相关性概率的组件,2。NLP 组件,创建推理空间的几何模型;以及 3 .集体推理过程的概率图形模型。⁷
上述框架的技术开发始于 2014 年。目标是确定是否可以获得数据贫乏的资产,如早期创业公司,并预测该创业公司获得后续投资的可能性。生存能力是成功投资回报的最重要的相关因素。预测筹资潜力的基于框架的模型来自天使资本协会赞助的研究。⁸这一预测的“数据”来自一个认知多样化的合作者群体。有些成员有投资经验,有些有行业经验,有些有创业经验,有些有终端用户经验。合作团队是根据每个初创企业所需的领域专业知识挑选出来的,人数从 12 到 30 人不等。四年来分析的数据集大约有 150 家公司。结果是非常积极的,得分超过 73%的 80%在风险投资市场上获得了市场关注。得分最高的公司目前的估值是其价值的 20 倍以上,并获得了两项 CES 大奖。通过这个过程产生的所有模型都被存储为贝叶斯信任网络。知识模型是集体推理过程的持久计算模型。一旦创建,模型就像迷你专家系统一样工作。例如,投资用例的模型是可组合的,有助于学习如何在早期投资中变得更好。⁹
从这些年的经验中,我们了解到我们有一个更通用的知识获取引擎,适用于与决策相关的市场情报或知识发现过程的各个领域。例如,在单盲集体推理过程中学习基于证据的比对,并接受同行评审,本质上是一个知识发现的过程,它与我们如何建立来自科学研究的模型高度一致。
出于这个原因,下一代人工智能技术的一条建议路径是使用协作推理来跨越学科,类似于麻省理工学院 IQ 的跨学科努力。集体推理适用于评估替代模型和技术。在商业层面,集体推理适用于评估技术在创新计划和投资中的影响潜力,这些计划和投资推动了企业转型计划。
集体推理技术的数学和科学基础与深度学习非常相似。深度学习之所以如此有效,是因为它植根于物理学中的合作现象。具体来说,深度学习的核心是一个来自磁行为物理的模型。例如,通过称为重正化群的数学公式,电子自旋标度与宏观磁性的微观排列。深度学习通过实施重正化组过程来衡量数据如何在从微观相互作用(例如,像素到像素)到宏观属性(“它是一只狗”)的模式中对齐。
我们开发的集体推理系统使用类似的数学公式,但将其应用于人类如何整合他们的知识来制定决策或预测。通过利用协作过程,我们学会了协调。具体来说,对齐学习算法智能地对寻求发现对齐区域的其他参与者提交的原因的候选列表进行采样。基于框架的知识获取模板指导系统。
可以将框架简单地看作是关注决策或预测的特定方面的一种方式。例如,早期投资的框架可能简单到“你认为市场机会如何?”以及“你觉得这个团队怎么样?”。集体推理系统将学习对市场机会和团队的集体推理观点。
集体推理算法平衡了发现(允许参与者开放思考,并在看到他人原因的基础上扩展自己的推理)和优化(学习对齐)。⁷类似地,一个团队会议的主持人会从发现走向融合(把所有的想法都提出来,然后进行优先排序)。学习算法具有学习何时将注意力从发现转移到优先化的方法。
自动化集体推理有着巨大的潜力。该系统学习支持任何规模的群体的决策或预测的理由的排序偏好。因此,从组织决策到预测市场智能模型,集体推理具有广泛的适用性。
第一波人工智能专注于模仿人类智能的手工制作系统。我们把人类的思维放在基座上,检查它,并使用逻辑和试探法建立知识和推理模型,试图反映和模拟人类的专业知识。人工智能的第二次浪潮将统计相关性放在了基座上,并在自动模式识别和分类方面取得了巨大成功。
人工智能的第三次浪潮将综合智能置于一个基座上。麻省理工学院对集体智慧的定义说得很清楚:“人和计算机如何连接起来,从而集体地比任何人、团体或计算机更聪明地行动。集体推理提供了一条有望实现这一目标的前进道路。集体推理采用数学上合理的方法来学习深度学习中缩放排列的含义,以可缩放地学习人类的排列,创建集体人类知识的计算模型。
关于决策或结果的共享推理的学习对齐创建了一个知识获取框架,该框架密切反映了科学发现的过程。此外,它基于物理学的一个基本原理,即合作现象,这为未来的研究和开发提供了坚实的基础。
如果你想成为探索集体推理的新倡议的一部分,请给我发电子邮件至 tom@crowdsmart.ai 。对于商业用途,该技术被授权为来自 CrowdSmart.ai 的基于云的服务。如果你的兴趣与研究相关,请在电子邮件中明确说明。
- 伊莱扎·斯特里克兰“人工智能动荡的过去和不确定的未来”IEEE Spectrum 年 10 月
- Yoshua Bengio,米兰-魁北克人工智能研究所创始人兼科学主任
- 朱迪亚珍珠采访为什么基础书籍 2018 年的书
- 布拉德·弗格森
- 托马斯·库恩《科学革命的结构》芝加哥大学出版社 1970 年
- 托马斯·克勒用集体推理改变协作决策
- 专利申请中
- 威尔特班克,罗伯特,和伯克,沃伦,回报天使投资者团体(2007 年 11 月 1 日)。可在 https://ssrn.com/abstract=1028592或 http://dx.doi.org/10.2139/ssrn.1028592或买到
- 托马斯·克勒运用集体推理进行投资
- 亨利·林、马克斯·泰格马克、大卫·罗尔尼克“为什么深度廉价学习效果如此之好?” arXiv:1608.08225
- 基于框架的表征在推理中的作用《CACM》第 28 卷第 9 期
针对数据管道的事件检测和警报
入门指南
如何设置端到端检测和警报,以识别和防止数据中的无声错误。
数据管道断了?仪表盘不靠谱?关键报告中有太多的空值?
要获得可靠准确的数据,测试和断路器只能帮你到此为止。在我们最新的系列中,我们重点介绍了数据团队如何为他们的生产数据管道建立 端到端事件管理工作流 ,包括事件检测、响应、根本原因分析&解决方案(RCA)和无可指责的事后分析。
在这篇客座博文中,蒙特卡洛的 斯科特·奥利里 带我们了解如何开始事件检测和警报,您防御 数据宕机的第一道防线 。
随着公司越来越依赖数据来推动决策,对数据准确性和可靠性的要求也越来越高。随着越来越多的数据进入您的数据生态系统,出错的可能性只会增加,每年会给组织造成超过1200 万美元的损失,更不用说宝贵的时间和利益相关方的信任了。
几十年来,软件工程和 DevOps 团队一直依靠一个 多步骤过程 来识别、分类、解决和防止软件和操作问题影响他们的应用程序。随着数据操作的成熟,是时候我们以同样的勤奋对待 数据停机 了,换句话说,就是数据丢失、不准确或其他错误的时间段,尤其是在构建更可靠、更有弹性的数据系统时。
第一步?事件检测和警报,这是您抵御数据管道中断和管理人员不可避免的清晨 pings 的第一道防线(“为什么数据是错的?”)和利益相关者(“这个仪表板怎么了?”)当管道破裂时。
有了正确的流程、技术和文化,您的数据团队就可以建立一个协作、高效的工作流,用于识别、补救和防止问题消耗太多宝贵的时间和精力,并侵蚀组织其他部门对数据的信任。
第一步。撰写您的数据事件操作手册
在您能够检测到事件之前,您需要建立流程并开发良好的(足够的)文档来传达职责、角色,以及在您确实收到可怕的松弛消息或寻呼责任通知时的清晰前进路径。引用本杰明·富兰克林的一句话,“未能计划就是计划失败”,当涉及到管理数据管道中的 未知的未知 时,这句话当然适用。
无论您为数据管道设置了多少测试,事故都是必然会发生的,当问题出现时,有一个适当的计划将有助于您。就像 站点可靠性工程师(SREs) 在应用程序中断时使用运行手册一样,现代数据工程师也应该为管道中断制定计划。
至少,我建议您使用以下操作手册地址:
- 您的组织认为什么是数据事件? 这可以让你的团队确定这是否是你应该担心的事情。也许数据事件可以通过重新启动 Airflow DAG 来解决,或者也许您需要提交一个票证,以便与数据团队的其他成员一起更深入地研究这个问题。无论哪种方式,确定什么是真正的事件,什么可以不优先考虑或忽略有助于减少噪音和保持您的团队专注。
- 发生数据事件时,谁会收到警报?这因组织而异,所以你需要找出最适合你的团队的方式。一些团队指派一个人负责所有数据事件,作为第一道防线,而其他团队则有一个数据工程团队负责数据的新鲜度和数量,还有一个分析团队负责验证数据。为特定类型的事件甚至某个事件的特定方面分配所有权,将在今后带来回报,提高您的团队合作和识别问题根源的能力。最佳实践是通过 PagerDuty、Slack、Opsgenie 和其他流行渠道将警报集成到数据工程工作流中,因为这可以确保所有数据利益相关方和最终用户在出现问题时收到警报。
- 您将如何向利益相关者和最终用户传达该事件? 一些组织对此采取了直接的方法,向团队特定的渠道发送事件通知(如影响重要营销仪表板的事件的 Slack 渠道)。其他组织在数据工程团队中保持第一道防线,并且只有当问题很明显是“真实的”并且确实影响到下游数据消费者时才提醒风险承担者。无论采用哪种方法,关键是您的第一道防线是技术性的,足以在您的数据环境背景下理解事件,并且足够了解业务背景和问题的影响。选中这两个框非常有帮助,因为它减少了来回沟通问题的技术范围和业务影响所需的时间。
第二步。检测数据事件
图片由蒙特卡洛提供。
当数据管道中断时,第一步是事件检测。
不言而喻,您应该在数据进入生产之前测试您的数据并捕捉已知的未知,换句话说,您可以在特定阈值范围内预测的问题。
然而,测试和其他断路器方法在检测生产中无法预测或解释的事件时会让数据团队失败— 未知的未知 。因此,测试数据并不能提供真正的端到端可观察性,而这对于数据驱动的业务来说是必要的。随着数据管道变得越来越复杂,对于试运行和生产,未知的未知数只会增加。
这就是为什么数据需要测试和 可观测性 来确保端到端的可靠性。现代数据团队必须将数据视为一个动态的、不断变化的实体,不仅要应用于严格的测试,还要应用于持续的数据可观察性。借助数据可观察性,可以通过自动 数据监控和警报 来检测问题,并基于 ML 生成的或自定义设置的阈值来触发问题。
数据可观察性的一个重要方面是异常检测,它允许组织确定数据健康的支柱(即,容量、新鲜度、模式和分布)何时不符合生产中的预期。与仅在数据平台的一两层中实施相比,端到端实施异常检测(例如跨您的仓库、湖泊、ETL 和 BI 工具)对企业来说是有价值的。这样做可以让您的团队全面了解组织的数据健康状况,因此如果出现问题,您的团队会第一个知道并解决。
第三步。为关键数据事件设置警报工作流
如果一条管道破裂,而周围没有人听到,那它真的破裂了吗?
2021 年,当数据驱动着您公司做出的几乎每一个关键决策,并影响到整个组织的团队时,答案是响亮的“是”。
玩笑归玩笑,当出现问题时,你的团队应该得到提醒,而不是花费几个小时甚至几天来手动调查问题。在您设置警报之前,您的团队应该建立考虑事件的基本规则,谁应该接收特定类型的警报,以及接收警报的最佳位置。这些指导方针和流程应该记录在您团队的操作手册中。
写完操作手册后,团队应该考虑实施支持机器学习的解决方案(如数据可观察性平台),以根据历史数据自动生成警报,只需最少的提升即可启动并运行。警报可以直接发送到 Slack、email、PagerDuty、Opsgenie、Mattermost、webhooks 或您的团队用于管理沟通的任何其他渠道。
图片由蒙特卡洛提供。
许多团队选择为重要的表(如财务报告、产品统计、营销支出和运营指标)设置页面责任或 Opsgenie 通知,并为不太重要的表设置 Slack 或电子邮件通知。这样的通知可以让你的团队减少嘈杂的警报。
图片由蒙特卡洛提供。
接下来,选择要发送到此通道的事件。默认情况下,您可以路由所有事件,也可以选择自定义选项,例如,只路由特定表或报告的自定义规则违规。
图片由蒙特卡洛提供。
如果您选择违规,团队可以将所有或部分违规发送至特定渠道:
图片由蒙特卡洛提供。
最后,您可以选择一个客户过滤器来缩小要通知的数据集或表的范围:
图片由蒙特卡洛提供。
虽然数据可观察性有助于基于数据中的历史模式开箱即用的自动端到端异常检测,但一些团队选择基于特定业务需求设置自定义警报。随着贵公司数据战略的成熟,我建议两者都加以利用。
建立数据信任文化
建立一流的事件管理实践不仅需要正确的工具,还需要整体的方法来减少噪音、区分关键资产的优先级、解决隐性错误,最重要的是,促进整个公司内更轻松的协作。
破裂的数据管道可能不会发出声音,但它们的影响可能强大到足以砍倒比喻意义上的树。
在我们的事件管理系列的第二部分,我们将分享我们在响应数据事件方面的最佳实践和经验教训。
有兴趣了解有关使用蒙特卡洛为您的数据团队建立可靠的事故管理流程的更多信息吗?伸出手去 斯科特 和 我们团队的其他人 !
开始学习数据科学意味着首先清理您的数据
入门
用于减少数据混乱的探索性数据分析(EDA)工作流
在阿姆主演的电影 8 Mile 中,歌曲 Lose Yourself 抓住了电影的整体构思。你知道我指的是哪一个。像这样开始的那个…
“他手心出汗,膝盖发软,手臂沉重。
他的毛衣上已经有呕吐物了,妈妈做的意大利面。
他很紧张,但表面上看起来很平静,准备好了”
是的,这就是我在新工作中第一次坐在我的新房间时的感觉。铭牌上贴着令人垂涎的头衔“数据科学家”看起来很自信,但是感觉…嗯…紧张。
有点戏剧性?也许吧。
但是这种感觉和我的经理给我第一个项目任务时的感觉一点也不一样。
“嘿布兰登。欢迎来到公司。您现在会开发我们的企业微细分模型吗?有你加入,每个人都很兴奋。再见了。”
我从紧张到害怕。我的手心不只是出汗,而是湿透了。为什么我会如此紧张?嗯,这里只是几个原因。
第一,我生活在学术界回归模型的世界里。我以前从未用聚类分析对数据建模,聚类分析对于细分是必要的。是的,我知道…完全没有…说真的,我是怎么得到这份工作的?
第二,也是这里最重要的一点,我得到了一个相当于 SELECT * FROM TABLE_A,TABLE_B,TABLE_C 内部连接 blah,blah,blah 的数据集,它包含 300 多万行和 200 多列。
当然,用 200 个变量建立一个有意义的聚类分析?对吗?我会在后面尖叫。
顺便提一句,如果你一直在关注我,你可能也知道我实际上试图一次分析 20 或 30 个东西,但很快发现这很痛苦,而且完全没有意义。
无论如何,如果不是因为下面的 EDA 技术,我可能还在研究那个问题。这个特定用例的主要目标是减少数据中可用的维度数量。
因此,我们希望评估每一列对于像这样的数据科学问题可能具有的潜在信息价值。因为模型是为了模拟数据中的变化而构建的,所以我们的大部分数据减少和清理都围绕着确定变量是否具有良好的变化。
在本文中,我将带您了解一个典型的 EDA 过程,该过程提供了一些常用工具,用于使用 Python 和 Pandas 执行数据简化。最终,这些工作使我们能够在数据科学生命周期的后期为更复杂的数据建模准备数据。我们开始吧!
在这里,我们使用一个常见的表格样式的数据集,包括行和列,来应用一系列重要的任务,帮助我们更深入地理解数据中不同列的潜在价值。
步骤 0:加载数据
这看起来很简单,但是在进行数据分析时需要考虑的一件事是将所需的数据加载到内存中的重要性。因为我们使用的计算机容量有限,所以确保我们的系统大小适合数据分析非常重要。
如果处理的数据对于您的系统内存来说太大了,那么使用向下采样来抽取数据的随机样本或者利用本文这里中详细介绍的其他技术是很重要的。
import pandas as pd
import numpy as nppath = '/path/to/data/'
df = pd.read_csv(path+'data.csv')
下面是我们正在处理的数据的样子:
作者图片
步骤 1:信号
一旦数据在内存中,我们需要元数据信号,使我们能够快速识别变量的信息值。初始清单应该包括检查每一列的数据类型。
我喜欢构建一个包含所有元数据信号的数据框架,让我能够快速识别有意义的变量。
在下面的代码中,我们首先创建一个数据帧,其中每一行都是原始数据帧中的一列。然后,我们的代码继续向这些变量添加不同的元数据信号,例如空值的数量、空值的百分比以及使用 describe()方法的描述性统计数据。以下是我们纳入元数据数据帧的完整信号列表:
-变量名
-空值的数量
-空值百分比
-数据类型
-数数
-卑鄙
-标准偏差
-最小值
- 25%、50%和 75%四分位数
-最大值
-出现频率最高的变量的值
-该变量最频繁值出现的时间百分比
meta_df = df.isna().sum().reset_index()
meta_df['percent'] = meta_df[0]/len(df)
meta_df = pd.concat([meta_df, pd.DataFrame(df.dtypes, columns=['dtypes']).reset_index(drop=True)], axis=1)d = df.describe().T.reset_index()meta_df = meta_df.merge(d, on=['index'], how='left')vcs = [pd.DataFrame(df[x].value_counts(normalize=True)).T for x in
list(df.columns)]vcs= [pd.DataFrame((x.idxmax(axis=1), x.max(axis=1))).T.reset_index() for x in vcs if len(list(x.columns)) > 0]meta_df = meta_df.merge(pd.concat(vcs), on=['index'], how='left') meta_df.columns = ['index', '0_x', 'percent', 'dtypes', 'count', 'mean', 'std', 'min', '25%', '50%', '75%', 'max', 'max_value','max_percent']
一旦我们的元数据 dataframe 构建完成,我们就可以构建一个函数,其中包含一系列规则,用于确定任何变量是否可能是坏的。
第一个规则确保至少有一些可变性,因此我们寻找标准偏差等于 0 的任何列。
第二个规则确保数据的某种分布,因此我们比较四分位数以确保它们不都等于相同的值。
根据这个建议这里,下一个规则标记具有超过 10%空值的变量。类似地,我们也标记那些出现频率超过 80%的单值变量。
最后,如果没有最大值,我们也标记变量,这意味着变量没有值。显然,这些规则可以根据不同的值或信号来定制。
def bad_flag(row):
if row['std'] == 0:
return True
elif (row['25%'] == row['50%']) and (row['50%'] == row['75%']):
return True
elif row['percent'] > .10:
return True
elif row['max_percent'] > .80:
return True
elif pd.isnull(row['max_percent']):
return True
else:
return False
meta_df['bad_var'] = meta_df.apply(lambda r: bad_flag(r), axis=1)
现在我们已经有了自己的标志,下一步是从主数据帧中删除那些变量。为此,我们列出了“bad_var”值设置为 NOT True(!idspnonenote)的列名。=).接下来,我们用一个新的 dataframe 替换我们的 dataframe,该 data frame 此时只包含感兴趣的列。
keep = (meta_df['index'].loc[meta_df['bad_var'] != True]).tolist()df = df[keep]
我们表现如何?我们从 150 个变量开始,现在减少到 113 个,我们已经能够从数据框架中删除 37 列。
第二步:可视化
上面的步骤很快也很容易完成,因为我们依靠数字表示来帮助评估每个变量的可变性程度。对于一些变量,我们可能仍然不确定它们的信息价值。
例如,有些变量在 70%的行中只有一个值。如果只有两个选项,这可能没问题,但是如果有两个以上的选项,则剩余值的可变性可能不足以对模型有用。在这些情况下,使用数据的可视化表示可以帮助我们进一步决定保留什么,去掉什么。
第一步是查看我们的元数据数据帧,检查任何异常或可疑的东西。例如,我们的一个变量有超过 75%的行被标记为“未知”
作者图片
让我们看看这个变量的条形图:
作者图片
根据条形图,变量“Variable_2”有两个值,“未知”和“是”在这种情况下,不清楚“未知”值和“是”值之间的差异意味着什么(一些“未知”可能是“是”),因此我们可以决定消除这个变量。
我们对数据的直观检查揭示的其他观察结果包括“年龄”被默认值“-1”填充,并且相当多的变量具有“未知”的值。虽然对特征工程的正确处理超出了本文的范围,但是这些额外的观察表明需要对特征进行额外的工程处理,以便为模型产生更多有用的数据。
当执行 EDA 以进行数据简化时,查看相关矩阵也可能是有用的,因为一些变量可能高度相关,以至于表明它们本质上是相同的变量,因此可以从分析中移除一个或多个变量。换句话说,变量没有给模型增加任何独特的东西。
快速目视检查将生成热图。要做到这一点,你需要做的就是遵循代码这里。这是我们使用相同代码的热图:
作者图片
例如,在 Variable _ 30-Variable _ 50 范围内似乎有一大块变量具有非常高的相关性,保留这些变量可能没有用。
在下面的代码块中,我们更深入地研究了相关性矩阵,只提取了那些相关性高于. 90 的变量。
high_corrs = corr[corr.iloc[:,:] > .90]
meta_corr = high_corrs.isna().sum().reset_index()
potential_drops = meta_corr.loc[(meta_corr[0] < meta_corr[0].mode()[0])]
从这里开始,由数据科学家来评估这些变量中哪些应该删除,哪些应该保留。
第三步:降维
如果在执行上述步骤后,我们仍然发现自己有太多的变量,EDA 的最后一点是使用探索性因子分析或主成分分析,这对于减少变量的数量同时仍然保持其潜在的信息价值是有用的。这些分析类似于我们在步骤 2 中生成的关联热图,但更进一步,寻找相关变量组,而不是简单的双变量关联。
因子分析帮助我们识别变量是否有足够的方差,我们可以做两件事情中的一件;将它们组合成它们平均值的一个指数(探索性因子分析)或者只关注一个因子中最重要的变量而忽略其余的(主成分分析)。你可以利用因子分析的结果做更多的事情,但这是我在野外处理数据时最常做的两件事。
虽然这些技术通常被认为是“无监督的”,因为我们允许算法识别数据的自然分组,但现实是数据科学家必须在执行分析之前应用一些有意义的框架来分组数据。
我说的有意义的框架是什么意思?
例如,假设一组变量代表健康的不同方面,而其他变量是来自客户满意度调查的项目。寻找跨越这两个独立数据领域的因素并没有多大意义。因此,我经常发现执行聚类分析的多次迭代来识别可能确实有自然分组的数据的自然分组更有用。
在下面的代码中,我们通过对我们一直在使用的演示数据集执行示例因子分析来完成我们的数据缩减。代码是从这个伟大的因子分析教程这里派生出来的,并应用于我们的数据。以下是对相关步骤的简要概述:
首先,我们列出想要包含的特定列。
其次,我们执行充分性测试,以确保因子分析对于给定的数据是可行的。请注意,我们正在寻找小于 0.05 的 p 值,这表明相关矩阵不是单位矩阵。
第三,我们进行因子分析。
第四,我们可视化特征值,并在图中寻找“肘”,以帮助我们决定我们的模型应该包括多少因素。
接下来,我们重新进行因子分析,并根据我们的“肘”图分析设置因子的数量。
最后,我们提取因子负载并查看它们,以确定我们可能希望如何组合我们的变量。
#subset our dataframe to focus only on domain relevant variables
df_fac = df.iloc[:,98:]import pandas as pd
from factor_analyzer import FactorAnalyzer
import matplotlib.pyplot as pltfrom factor_analyzer.factor_analyzer import calculate_bartlett_sphericity#df_fac from optum_data_segmentation.py
df_fac = df_fac.dropna()chi_square_value,p_value=calculate_bartlett_sphericity(df_fac)
chi_square_value, p_value# Create factor analysis object and perform factor analysis
fa = FactorAnalyzer()
fa.fit(df_fac)
# Check Eigenvalues
ev, v = fa.get_eigenvalues()
ev# Create scree plot using matplotlib
plt.scatter(range(1,df_fac.shape[1]+1),ev)
plt.plot(range(1,df_fac.shape[1]+1),ev)
plt.title('Scree Plot')
plt.xlabel('Factors')
plt.ylabel('Eigenvalue')
plt.grid()
plt.show()# Create factor analysis object and perform factor analysis
fa = FactorAnalyzer()
fa.set_params(n_factors=2, rotation="varimax")
fa.fit(df_fac)loads = pd.DataFrame(fa.loadings_)
loads_df = pd.concat([loads, pd.DataFrame(list(df_fac.columns))], axis=1)
loads_df.columns = ['Factor_1','Factor_2','Variable']
以下是“负载 _df”数据帧的样子:
作者图片
在因子负荷的输出中,我们看到大多数变量对因子 1 的负荷比因子 2 重。也就是说,我们看到“变量 _141”和“变量 _143”在因子 2 上的负载更重。
从这一点来看,降维的下一步是通过平均每个因子上加载的变量来为每个因子创建指数。
例如,如果我们想使用“变量 _141”和“变量 _143”为因子 2 创建一个索引,我们首先需要注意“变量 _143”有一个负负载。因此,在对“Variable_141”进行平均之前,我们需要对该变量进行反向编码。
反向编码的一个快速技巧是在平均之前将变量乘以-1。但是,请注意,只有当我们还打算在建模之前对数据进行规范化时,我们才会这样做(对于大多数数据科学模型,这是一个强烈推荐的过程)。
下面是创建因子 2 指数的一些示例代码:
df['Variable_143_R'] = -1*df['Variable_143']df['Factor2'] = df[['Variable_141','Variable_143_R']].mean()
我们的清洁行动现在需要 2 分钟
既然我们已经花时间减少了数据集中的维度数量,我们就准备将数据传递给更复杂的特征工程,并最终进行下游建模。
总共减少了 50%以上的可用数据,现在我的手心出汗少多了。所以我留给你们这个:
“他最好去捕捉这一刻,并希望它不会错过”
前进!
比如参与学习数据科学、职业发展或糟糕的商业决策?加入我。
Bootcamp 数据科学入门
将职业生涯转向数据科学指南
我写这篇博客的目的是与任何正在考虑职业转型、感到不知从何开始、或在致力于他/她的数据科学职业转型时需要一点鼓励的读者分享我最近开始的数据科学之旅的故事。
我的背景
我是 2016 年金融专业毕业,辅修数学的 SF 地区高级销售运营及策略分析师。我在一家小型精品投资银行起步,很快意识到这不是我理想的文化;这是一个竞争激烈的世界,这不符合我的个性。幸运的是(以及后来的数百份申请),我进入了科技领域,在一家小型初创公司做业务运营和战略分析师。尽管我热爱我所做的工作、有趣的环境以及个人和职业发展机会,但在 2020 年 9 月,我开始探索其他领域,寻求新的挑战,以揭开我人生的下一个篇章。当然,更高的工资是另一个激励因素(没有废话)。
探索阶段
基于我的兴趣和愿望,我的潜在选择是软件工程或数据科学。在这之前的一年,我与一位令人印象深刻的同事进行了一次步行会议,他领导了一些有影响力的项目,对公司和行业有着深入的了解。他是数据科学的主管。我了解到他是从一个与金融相关的领域来到这个职位的。他给我的建议是从 SQL 开始,然后如果我对数据科学领域感兴趣,就继续学习 python。按照他的建议,我完成了 SQL,但是没有继续 python,因为公司正在进行收购,这是一个相当紧张的时期。因此,我自然倾向于进一步探索数据科学。
行动和学习
- 安排与数据科学家的会面:那时,我不知道从哪里开始,也不知道数据科学在日常和/或专业化方面需要什么。幸运的是,我利用工作之外和当前公司内部的关系,为数据科学家安排了这些会议,以回答我的迫切问题。最重要的是,他们中的一些人告诉我,甚至在我现在的公司也有一些同事是从训练营开始的,这个消息让我大吃一惊。
- 做研究:我对参加训练营和继续自学方向进行了高层次的成本效益分析。也许因为我是一个怀疑论者,我的大部分在线研究显示,人们对训练营持批评态度,这与我的面对面反馈相反。无论如何,我决定更加重视与我交谈的数据科学家,并继续进行训练营对比。在网上做了一些调查并打电话给他们的招生办公室收集信息后,我选择考虑的前两个是镀锌和熨斗。
作者图片
- 果断点:在评估了最适合我的环境后,我选择了“激励”。即使在那时,我意识到我几乎没有赶上最后一个优质预备班的截止日期,让你为 2 月份的数据科学沉浸式项目开始日期做好准备。如果你有足够的信息来帮助你做决定,我的建议是你赶快行动。
不要和学习
我做了所有这些不该做的事。事后意识到收益递减,我建议避开以下情况。
- 不要在分散注意力的活动上浪费时间:限制你的研究时间。分配的时间结束后,请集中精力学习构建您的数据科学知识的材料。花很多时间在 LinkedIn 上跟踪数据科学家,试图找到一种职业模式,不会让你接近你的职业。
- 不要因为恐惧而放弃追求数据科学:我会认为自己是一名好学生(聪明、学习快、勤奋),但我记得编程的想法让我感到恐惧和不知所措。我当然不想暗示编码/数据科学很容易,当然不是。但我可以向你证明,只要你投入时间、精力和努力,你就能掌握各种看似令人生畏的概念。
持续的训练营体验
作者图片
回顾第一个 python 基础视频几乎让我流泪的时候,我觉得编码是我不明白的事情,这很有趣。但这就是训练营的用武之地…我从 Galvanize 的 premium prep 中获得的一个价值是信息合成。正如其他人提到的,所有入门的必要材料都可以在网上找到,而且很大一部分是免费的。有了像“激励”这样的项目,你可以获得清晰有序的学习材料和视频供你使用。当然还有专家资源供您使用!这帮助我轻松地浏览主题,更快地消化信息。讲师们和蔼可亲,富有思想,简直棒极了,其中一些人我会感激很久。我最喜欢的部分是老师故意给学生留下面包屑,以便更顺利地介绍下一章。
课程是截止日期驱动的;这对培养责任感意义重大。很快,我发现了大多数概念的浩瀚。你可以花无数个小时深入钻研,成为一名主题专家。对于像我这样的初学者来说,我发现花更多的时间去理解基本概念,以及学习正确的时机去学习另一个同样重要的科目来接受全面的教育是非常重要的。考虑到数据科学的广度和深度,如果没有激励,我自己是无法高效完成这项工作的。尊重那些有抱负的数据科学家选择自学的路线来完成自己的事业!
查看到目前为止涵盖的主题
- 简介/中级 Python
- 统计学导论
- Unix 介绍,Git/Github
- 熊猫,熊猫,噢
- 积分学、微分学、线性代数
- 结构化查询语言
离别的思绪
如果你能从我的故事中得到什么(在我下一次更新之前),这些是我希望你留下的:
- 努力做到最好!不后悔。
- 一步一步来!重要的是不要感到不知所措和沮丧。
- 每个人的人生道路都不一样;接受并拥抱你是独一无二的。
感谢您的阅读!
材料信息学入门
如何开始研究材料信息学(数据科学+材料科学)
用数据科学理解材料中的结构-性能-性能-加工关系。来自维基共享。
在这篇文章中,我分享了参与材料信息学研究的资源和建议。随着发现和设计新材料以应对一些最紧迫的全球性挑战(人类健康、食品和水安全、气候等)变得越来越昂贵和耗时。),我们需要拥有科学领域专业知识和数据科学培训的材料科学家。无论你是想在自己的研究中使用数据科学,还是只是想更好地了解该领域的发展状况,这篇文章都会帮助你。
我在 GitHub 上分享了一个资源列表,用于材料信息学入门。该列表包括论文和交互式教程、有用的 Python 库、博客、时事通讯、播客、数据库和学术材料信息学研究小组。
什么是材料信息学?
信息学是转换信息(数据)的科学。从某种意义上说,所有的材料科学都涉及信息学,因为所有的材料科学都是建立在数据和解释数据的理论之上的。“材料信息学”,我们特指被现代数据科学所超越的材料科学。这让我们能够加速材料属性预测,在可能的材料空间中进行系统搜索以发现具有优化属性的化合物,甚至根据我们想要的属性设计新材料。
实验科学家可以使用材料信息学来减少他们在实验室中进行反复试验的时间和精力;而计算科学家和理论家可以提供更好的指导,告诉他们制造什么材料、如何制造,以及如何理解它们的属性。你对数据科学和机器学习了解得越多,就越清楚这些是高效科学的工具,而不是科学家和科学思维的替代品。
先决条件
数据科学先决条件:眼镜、大量显示器、夜间模式文本编辑器。来自 Unsplash。
我假设感兴趣的读者已经在材料科学的某些领域工作:纳米材料、聚合物、冶金、生物材料或量子材料。要进行材料信息学的研究(或培养对材料信息学的欣赏),你需要从数据科学的基础开始:统计学,一种科学计算语言,如 Python 或 Julia,具有相关的数值计算能力和数据结构,机器学习,以及用数据讲故事(可视化)。
好消息是,如果你是一名科学家,你可能有很多必要的背景。更好的消息是,现在是学习数据科学的最佳时机——有大量免费课程、教程和博客可供学习。从某些方面来说,最具挑战性的事情可能是筛选所有这些资源并找到最好的。有大量的数据科学入门指南。
根据你的学习风格,你可能想从自下而上的方法开始,从头开始阅读教科书和实施方法,或者从自上而下的方法开始,在你自己的研究中选择一个有趣的问题或者从 Kaggle 中选择一个简单的问题,然后开始破解,边做边学。
进入兔子洞
如果你想对材料信息学有一个简单的技术介绍,你可以从这里列出的资源开始。从材料信息学的详细定义,到正式的最佳实践、交互式教程和为期三天的研讨会,这些资源将帮助您尽快入门。
如果你对这个领域感兴趣,无论是作为一名从业者还是一名不经意的观察者,这里有一些博客、播客和时事通讯可以帮助你。
图为:用材料信息学加强研究后的你。来自 Unsplash。
行业工具
一旦你准备好开始自己的材料信息学研究,利用许多已经可用的令人惊叹的开源项目会有所帮助。Python 是该领域的编程语言选择,Jupyter 笔记本环境是进行材料信息学的虚拟实验室。以这些工具为基础,有完整的软件生态系统来生成和分析计算的材料数据,建立机器学习管道来预测性能和设计新材料,可视化材料数据,并以机器可读的方式分享您的研究。
努力实现的一个关键原则是确保您的数据是可查找、可访问、可互操作和可重用的(公平)。换句话说,让其他科学家更容易将你的数据用于材料信息学!幸运的是,有一些很棒的框架可以让你的数据清晰可见,并以一种可以通过网络界面和 Python API 探索的方式分享。
一切都是为了数据……
数据科学的第一条戒律是“垃圾进,垃圾出”这一切都归结于获得带有某种信号的巨大数据源,处理它,并应用可用工具的瑞士军刀来提取一些见解。如果缺少第一步:高质量的数据源,任何机器学习方法都无法提供有意义的输出。世界各地的英雄们不辞辛苦地计算和测量了成千上万种材料的特性,并使这些数据在数据库中变得容易获取。
即使是现在,大多数耗费大量人力和资源生成的材料数据都被锁在 pdf 的图形、表格和文本中。有正在努力解析 pdf 并挖掘数据,但是你可以通过将你的数据贡献给数据库并使其公平,在你自己的研究小组和你的领域内产生直接影响。
…还有问题
数据科学的第零条戒律是“问正确的问题”数据科学不能告诉你你的研究方向应该是什么。科学家的主要工作仍然是弄清楚什么是最有趣的问题去询问和研究。希望通过使用这些资源,你能更好地理解材料信息学能做什么和不能做什么。
材料信息员
为了帮助学生、博士后和教师找到所有在这个领域工作的优秀团队,我列出了一个简短的材料信息学团队(排名不分先后)。这些小组专注于完全不同的材料科学领域,共同的主题是他们在某种程度上使用理论、计算和数据科学。如果您在材料信息学小组工作,并且希望被添加到列表中,请告诉我!
欢迎投稿!
我喜欢你的反馈!该资源列表并不全面,相反,它是我在自己的工作中发现的有用的东西的精选集合。我忽略了许多前沿方法(例如,量子机器学习、等变神经网络),因为它们还没有达到日常使用所需的成熟水平,也不太适合“入门”水平。如果有材料信息学资源的某些功能没有包含在列表中,请随意阅读投稿指南并与我分享。我还要感谢 Pat Walters 出色的化学信息学资源列表,它启发了这个列表。
保持联系
如果你喜欢这篇文章或者有任何问题,请随时通过电子邮件联系我,或者通过 LinkedIn 和 Twitter 与我联系。
完整的资源列表可以在 GitHub 的这里找到。
你可以在我的网站上找到更多关于我的项目和出版物的信息,或者只是阅读更多关于我的。
医疗人工智能入门
临床医生在线学习资源指南
随着人工智能(AI)改变医疗实践,所有临床医生都将成为机器学习技术的用户,并将需要学习人工智能和机器学习的基础知识。当你计划升级你的机器学习知识时,你可能会对许多可用的教育选项感到困惑。
我最近完成了为期四个月的休假,在此期间,我调查了越来越多旨在建立人工智能知识和技能的教育课程、视频和书籍。以下是我基于那次经历的想法。
我已经按照职业轨迹组织了我的建议,从放射科医生和其他经验很少的医疗专业人员的基本资源开始,到任何具有强大技术背景和更雄心勃勃的目标的人的高级课程结束。你需要根据你的背景、经验和职业目标来定制你的道路。
放射学家和放射实习生
如果你对人工智能和机器学习完全陌生,那么通过 Coursera 在吴恩达的 deeplearning.ai 项目中提供的 AI for Everyone 课程,强调了为什么人工智能是如此多行业的焦点,而不仅仅是医疗保健。对于医疗保健特定的材料,您可以尝试由北美放射学会 (RSNA,小额费用)、医学成像信息学学会(SIIM) 和美国放射学院(ACR) 提供的网络研讨会,以及由健康人工智能研究中心提供的研究研讨会、期刊俱乐部、小组讨论,包括https://www.youtube.com/c/stanfordaimi医学和成像人工智能中心(AIMI 中心)的 YouTube 频道。
无论你是正在接受培训的放射科医师,还是经过委员会认证的放射科医师,由 RSNA 和 SIIM 赞助的国家影像信息学课程(NIIC) 都清晰地介绍了更广阔的信息学世界——结合录音和现场讲座,以及“翻转课堂”,使信息学名人和同学能够进行小组讨论。任何住院医师项目的受训者都可以参加这一课程,只需象征性的费用,但是住院医师需要说服他们的项目主管提供一个临床时间表的休息时间。训练有素的放射科医生也可以付费参加该课程。
如果你参加 RSNA 年会,我强烈推荐参观 RSNA 的深度学习实验室。在 90 分钟的初级班中,你将使用自己的笔记本电脑来构建和测试一个对医学图像进行分类的深度学习算法。这一简短的经历是对上述教学材料的完美补充,对于理解人工智能算法是如何构建的,包括陷阱是至关重要的。
研究合作者和实践领导者
你们中的一些人有雄心不仅仅成为一个有见识的人工智能用户。例如,你可能渴望成为你临床实践的人工智能领导者——协助决定采用机器学习算法,制定人工智能技术的实施和监控计划,并决定临床实践数据的管理政策。其他人可能会寻求成为领域专家和研究实验室的合作者,或者与行业合作伙伴一起开发机器学习技术。这些目标需要对神经网络和深度学习有更丰富的理解。
机器学习的基本技巧之一是将复杂的计算任务重新转换为一组矩阵运算。作为机器学习命脉的图形处理单元(GPU)通过快速的矩阵数学获得了它们的能力。如果你从来没有学过线性代数,或者像我一样,已经忘记了你所学的大部分内容,我建议你复习一下向量、矩阵、张量以及相关的数学运算。来自 3Blue1Brown 的视觉导向的 YouTube 视频对深度学习和神经网络所必需的矩阵运算给出了清晰的视觉解释。前 10 个视频以正常速度需要 90 分钟左右。
医疗保健专业的人工智能可以作为任何人的健康人工智能教育的基础。这门课程是在我休假快结束时发布的,但已经吸引了成千上万的学习者。专业化从健康经济学家劳伦斯·贝克(Laurence Baker)的医疗保健介绍开始,他介绍了医疗保健系统的基本要素,重点是美国。即使你已经在美国医疗系统工作,本课程也将提供有用的健康政策复习。课程的一些元素与人工智能直接相关,例如对可能来自患者、提供商和中介的不同数据源的讨论。您可以决定本课程中的哪些主题最符合您的需求。
Nigam Shah 教授的第二个专业课程是关于健康数据的。我们如何找到正确的医疗保健数据来回答一个特定的问题?由于数据的收集方式,哪些偏见可能会影响数据?研究人员应该如何处理时态数据、缺失值和文本数据的问题?这些问题是用具体的例子来回答的,这些例子说明了像特征矩阵和知识图这样的概念。第 7 周的道德模块尤其及时。
第三个课程,医疗保健机器学习基础,重点是机器学习方法。讲师 Matt Lungren 和 Serena Yeung 从基本术语和行话的定义开始。然后我们学习损失函数、梯度下降和其他关键概念,接着是过拟合和欠拟合以及其他对算法评估很重要的概念。关于机器学习陷阱的讲座,包括对因果关系、环境、信任和可解释性的讨论,是非常宝贵的。任何计划开始一个大型项目的人都应该密切关注第 6 周关于组建跨学科团队的材料。
第四门课程,由 Tina Hernandez-Boussard 主讲的医疗保健中人工智能应用的评估,讨论了我们如何决定人工智能算法何时工作良好,包括效用和可行性的概念,以及对行动所需的前置时间的实际考虑。强调了实施过程中迭代和部署后监控的重要性。第 4 周提供了可能影响人工智能评估的偏见的广泛目录,并讨论了公平性、校准和透明度。监管的考虑和美国食品和药物管理局包括在内,这是一个全球监管图片的简短讨论。
由所有教师领导的顶级课程将所有材料联系在一起。
机器学习研究人员
任何想成为真正的数据科学家的人都应该学习基本的软件开发技能。python 是一种用于机器学习任务的流行语言,可以在网上的 W3Schools 、 Codecademy 和许多其他地方找到优秀的互动课程。
为了学习医学成像的各种深度学习方法,RSNA 深度学习实验室的全系列实践课程涵盖了图像分割、数据准备和生成对抗网络。当你开始构建实用的深度学习模型时,你可以参考 Brad Erickson 的魔术师之角,这是Radiology:Artificial Intelligence杂志上的一系列文章,与 RSNA 深度学习实验室的课程平行,并提供系统设置的逐步指导。
杰瑞米·霍华德的 fast.ai 课程是我个人最喜欢的课程,对于任何有很强技术背景但懂一点编程的人来说,它都是理想的资源。该课程采用自上而下的方法,从几行计算机代码开始,而不是建立详细的数学符号。第一课将指导你构建和测试你自己的深度学习模型。(我的能以 95%的准确率区分 37 种猫狗。)每一课都使用动手的方法来揭开深度学习的神秘面纱,Jupyter 笔记本中预先编写的代码可供您探索、修改和重用。没有抽象的定理或证明需要努力学习,但在课程结束时,你将知道如何阅读和理解任何深度学习论文的方法部分。
我没有花太多时间做练习,因为我是一个编程老手,现在主要管理项目而不是写代码。但这并没有影响我的学习。对于那些喜欢印刷版的人来说,杰里米刚刚与人合著了一本书,以同样的顺序提供了同样的材料。
吴恩达在 Coursera 上从 deeplearning.ai 推出的开创性和广受欢迎的深度学习专业是对 fast.ai 课程的一个很好的补充。Andrew 采用传统的自下而上的方法,从深度学习的基本概念的理论基础开始。他讲述了许多开创性的人工智能概念的历史和演变,介绍了标准符号,并强调了关键的参考资料。大量的练习提供了你所学的实际经验。我跳过了第三个课程,构造机器学习项目,因为我在这方面有经验,但其他人可能会发现它很有用。该系列的最后一门课程涵盖了序列模型,对于放射科医生和其他处理文本数据的临床医生来说将会特别有意义。它回顾了自然语言处理方法的当前进展,包括来自转换器的双向编码器表示(BERT)和其他转换器方法。像 fast.ai 一样,我发现整个课程很容易跟上,无需完成练习。此课程序列最近已更新。
参考资料
对于真正的核心,一些学术文本为机器学习概念提供了大量的数学基础。古德费勒、本吉奥和库维尔的深度学习在亚马逊有售,在线免费。神经网络和深度学习作者迈克尔·尼尔森,也可以在网上免费获得。这些资源不是为胆小的人准备的,但对于那些想在特定领域更深入研究的人来说,它们是有用的参考文本。
我祝你在机器学习的事业上一切顺利!
Pytest 单元测试入门
入门
没有数据科学家认为他们需要的工具,除非他们知道。
本周,我在一个数据摄取管道上工作,该管道必须处理许多不同的数据场景。我们就说是政府数据,其他的你可以想象。我遇到了一个你可能很熟悉的问题。我开始更新我的函数来处理不同的数据清理场景,这破坏了以前的工作代码。在我的例子中,这些问题大多是在使用正则表达式解析文本时出现的。
此时,我意识到是时候进行单元测试了。为什么?因为单元测试正是为这个问题而设计的。您编写小的独立测试来确保您的代码按预期执行。每当您对代码进行更改时,您都可以轻松地运行这些测试,以确保您没有破坏任何东西,并且您可以继续添加测试,以确保对代码的新更改不会破坏您早已忘记的场景。
我不认为每个数据科学项目都需要单元测试。许多项目都很小,目标明确,因此测试是不必要的。但是一旦你开始编写一个需要维护的包,这是任何生产中使用的包,测试就变成了一个巨大的时间节省器。在这一点上值得注意的是,几乎所有最常见的数据科学包(包括Pandas
、NumPy
、scikit-learn
和matplotlib
都使用pytest
作为他们的测试框架。
pytest
Python 自带unittest
,大多数情况下运行良好;然而,今天大多数开发者都在使用pytest
。值得看一下这两个工具的文档,但是因为这是一个速成课程,我们将只看一下pytest
和它的三个最常用的工具:
- 基本断言测试
- 参数化
- 固定装置
这里使用的所有代码都可以在这个 GitHub 库中找到。
让我们开始吃吧。
安装 pytest
要继续学习,您需要安装 pytest。在大多数系统上,您可以通过在命令行运行以下代码来实现这一点:
pip install pytest
基本断言测试
我们将从头开始。我们的第一个测试将测试一个简单的加法函数。我们将把这段代码放在一个名为project.py
的文件中。
def add(a, b):
return a + b
测试代码放在以test_
为前缀的文件中。当我们运行测试时,pytest
将执行一个发现过程。发现过程将递归扫描当前文件夹及其所有子文件夹,寻找以test_
开头或以_test
结尾的文件。Pytest 将运行位于这些文件中的测试。
现在我们知道我们需要一个前缀为test_
的新文件。我们将在前缀后面添加我们正在编写测试的文件的名称。这给了我们一个文件名test_project.py
。将以下内容添加到您的新测试文件中。
def test_add():
import project # test basic functionality
assert project.add(1,1) == 2 # try a border case
assert project.add(-1,-1) == -2
注意测试函数也带有前缀 **test_**
。当 pytest 扫描我们的文件时,它将运行任何带有test_
前缀的函数。
查看测试函数,我们可以看到实际的测试使用了assert
关键字。如果assert
后的表达式为真,功能将继续。如果assert
后面的表达式为假,则assert
将引发AssertionError
。这将导致测试失败。
为了运行测试,我们进入命令行并键入pytest
。
作者图片
如果我们的测试失败了会发生什么?让我们将第一个断言改为:
def test_add():
import project # 1+1 != 3\. This will rais an AssertionError
assert project.add(1,1) == **3**
作者图片
pytest
不仅清楚地表明我们的测试失败了,而且通过向我们展示函数和测试失败的原因,它还告诉我们确切的位置!从底部开始检查这个结果,我们看到:
- 失败的 test _ project . py::test _ add—assertion error:assert 2 = = 3它告诉我们文件名、测试函数以及导致失败的原因。在这种情况下,我们的表达式(计算结果为 2 == 3)为假。
- 就在那上面,有一个“test_add”部分,以“test _ project . py:10:assertion error”结束。这告诉我们错误的文件和行号。
- 上面的一切给了我们错误的上下文,所以我们可以理解并快速修复我们遇到的任何问题。
注意,虽然有两个 assert 语句,但是 pytest 认为这只是一个测试,因为它们在同一个函数调用中运行。
让我们看看另一个涉及熊猫DataFrame
的例子,它可能更像我们在数据科学工作流中看到的东西。
这是我们想要测试的函数。它向一个DataFrame
添加一列。
def add_col(df, colname, coldata):
# add a column to a DataFrame
df[colname] = coldata
return df
为了测试这一点,我们将:
- 在我们的
test_project.py
文件中创建另一个以test_
开头的函数。 - 定义一个起点
DataFrame
。 - 定义我们的预期结果
DataFrame
。 - 通过调用 DataFrame 的
equals
方法,将使用add_col
函数向起始DataFrame
添加一列的结果与预期结果DataFrame
进行比较。
def test_add_col():
import project # start
df = pd.DataFrame(
[[0, 1], [2, 3]],
index=['cat', 'dog'],
columns=['weight', 'height']) # expected
df_expected = pd.DataFrame(
[[0, 1, 2], [2, 3, 2]],
index=['cat', 'dog'],
columns=['weight', 'height', 'n_ears']) # test the result
assert project.add_col(df, 'n_ears', 2).equals(df_expected)
重新运行 pytest,我们可以看到我们的新测试通过了,但是之前的测试仍然失败。我们可以看到有多少测试失败了,有多少通过了。当其中一个测试失败时,测试不会停止;它运行我们所有的独立测试,并向我们报告每个测试的结果。
让我们通过在我们的test_add
函数中修改这条线来恢复这条漂亮的绿线。
assert project.add(1,1) == 2
作者图片
是啊!
参数化测试
另一个在某些情况下有用的工具是用不同的参数调用测试函数的能力。我们将创建一个新的测试函数,一个减法函数。
def subtract(a, b):
return a - b
在 pytest 中,参数化是通过一个装饰器来完成的,该装饰器定义了我们想要传递给测试函数的参数。让我们为使用不同参数的 subtract 函数定义一个测试。
# test parameterization
[@pytest](http://twitter.com/pytest).mark.parametrize("a,b,expected", [[2,1,1], [-1,1,-2]])
def test_subtract(a, b, expected):
assert project.subtract(a,b) == expected
让我们仔细分析一下。装饰器告诉 pytest 将列表元素作为a
、b
和expected
传递给下面的函数。它将为每个列表重复函数调用。
如果我们重新运行测试,我们会看到现在有 4 个测试,而不是 3 个。因为参数化多次调用测试函数,所以每个函数调用都算作一个单独的测试。
作者图片
固定装置
您可以想象,如果您要在同一个数据帧上测试许多执行不同任务的函数,那么在测试之间回收该起始数据帧会很方便。这就是固定装置的用途。
fixture 是一个带有特殊装饰器的函数,它创建一个资源并返回它。然后我们可以调用我们的测试函数,就像我们传入了那个资源一样。这有点违反直觉,但我认为一旦你看到它的作用,它就会有意义。
这是固定装置。
[@pytest](http://twitter.com/pytest).fixture()
def df():
df = pd.DataFrame([[0, 1], [2, 3]],
index=['wallaby', 'kangaroo'],
columns=['weight', 'height'])return df
当我们调用我们的测试时,我们将在中传递 fixture 函数的名称。Pytest 将调用该函数,并将其返回值传递给我们的测试函数。
def test_add_col2(df): # expected
df_expected = pd.DataFrame(
[[0, 1, 3], [2, 3, 5]],
index=['wallaby', 'kangaroo'],
columns=['weight', 'height', 'hop_height']) assert project.add_col(df,
'hop_height',
[3,5]).equals(df_expected)
注意,我们定义了test_add_col2
来将df
作为参数。因为我们已经定义了一个名为df
的 fixture 函数,pytest 将调用df
fixture 函数并将结果传递给test_add_col2
。
运行我们的测试,我们得到:
作者图片
包起来
显然,使用 pytest 单元测试可以做更多的事情,但是在您了解所有这些东西之前,现在就开始做是值得的。当您看到拥有一套测试的力量时,无论您何时更改您的包,您都可以快速、轻松地运行这些测试,您还将体验到大量的时间节省。即使你还没有看到它的价值,如果你想为任何开源项目做贡献,你可能需要为你的贡献编写测试。
也就是说,不要觉得你需要立即为你所有的代码创建完整的测试套件;在大多数情况下,这是不切实际的。相反,当您开始对代码进行更改时,或者当项目的范围变得足够大而不总是清楚某个函数需要处理的所有情况时,可以考虑编写测试。
向前迈进,测试你的代码,把你的额外时间花在你的家人身上。
资源
- Pytest 文档
- 测试组织从贡献给熊猫
- Aditya Sharma 的 Python 单元测试
- 与 Python 的持续集成:简介
- 维基百科上的单元测试
Pytest 单元测试入门—第 2 部分
制作一个单元测试的模拟器- y。
上周我写了关于开始单元测试的文章。我们讨论了基本的断言测试、参数化、固定装置,最重要的是,测试如何节省您的时间,以便您可以完成更多的工作或花更多的时间与家人在一起——这是您的选择。本文从上一篇文章停止的地方开始,所以如果您需要复习,这里有那篇文章:
单元测试的一个重要原则是它们应该是独立的。在测试环境中,这意味着我们的测试应该只依赖于我们正在测试的功能,而不是任何其他服务或功能。Immagine 你的函数对 goggles.com 进行 API 调用,并使用一些复杂的人工智能返回与你的搜索最相关的泳镜。如果我们不模拟 API 调用,我们的测试将依赖于它。
在我们的测试中,依赖那个 API 调用有几个问题。最常被提起的是时间。一个 API 调用可能需要一两秒钟,我们希望我们的测试很快。我们也想经常测试,如果我们对这些 API 调用收费,测试会变得很昂贵。但是这两个都不是我们不想依赖那个 API 的主要原因。
记住,单元测试的主要目的是节省我们维护项目的时间。如果那个 API 关闭,我们的系统可能会崩溃,但是当我运行我的测试时,我们不希望测试告诉我们问题出在调用 API 的函数上,因为它不是。我们希望我们的测试告诉我们,如果 API 关闭,我们的系统将如何响应,我们也可以通过模拟来模拟。好的测试会告诉我们,我们的代码是否独立于我们所连接的任何其他代码或服务而工作。
测试的主要思想是告诉我们 我们的代码 是否在做我们期望的事情。如果 goggles 的代码坏了,应该不会影响我们的测试。这应该反映在他们的测试中。
好了,解决了这个问题,我们该怎么办呢?
设置
要进行后续操作,您需要安装pytest
和pytest-mock
。
pip install pytest pytest-mock
您也可以在本文的 GitHub 资源库中跟随。
设置场景
首先,我们将假设进行一个 API 调用。
from time import sleepdef fetch_goggles():
# make an api call to goggles.com
# ...
sleep(4) response = {"foo": True}
return response
我们将为它编写一个测试,就像我们在本系列第 1 部分中所做的一样。
def test_fetch_goggles():
import project result = project.fetch_goggles() # test that the value in result['foo'] is True
assert result['foo']
运行测试。
作者图片
太棒了。我们的测试通过了。但是如果 API 调用失败了呢?我们可以通过改变函数的返回值来模拟。如果您遵循 GitHub 存储库中的代码,您可以取消注释新的响应行。
def fetch_goggles():
# make an api call to goggles.com
# ...
sleep(4) # return a 408 (timeout) status code
response = {"status": 408}
return response
作者图片
哦不!我们可以看到我们的测试失败了,因为结果对象没有将foo
作为键。
如果这个 API 调用实际上失败了,它不应该破坏我们的代码。那么,我们如何确保它不会发生呢?
模仿者
这个问题可以通过使用mocker
fixture 和“修补”API 调用来解决。在其最基本的形式中,有两个元素我们必须添加到我们的测试函数中,以便用 mocker 修补。
- 将
mocker
作为夹具添加到我们的测试函数定义中(夹具在第 1 部分的中讨论过,以防你错过)。mocker
夹具由pytest
提供。 - “修补”我们想要规避的功能
新代码如下所示:
def test_fetch_goggles(**mocker**):
import project **mocker.patch('project.fetch_goggles',
return_value={'status':200,"foo": True})**
result = project.fetch_goggles('Hi') assert result['foo']
让我们仔细看看那条mocker.patch
线。第一个元素是一个字符串,它匹配我们希望替换的对象的模块路径。请注意,它与下一行的project.fetch_goggles
相同,但没有()
。我还向我们的project.fetch_goggles
函数传递了一个变量,以说明无论向函数传递什么,返回值都是相同的。一个被模仿的函数会接受你给它的任何东西而不抛出错误。这是很重要的一点,也是你对嘲讽越来越熟悉时需要小心的地方。
运行测试:
砰。测试在 0.02 秒内完成。你可能从图片上感觉不到,但是等待测试完成 4 秒钟感觉是很长的时间。这样好多了。
模仿者提供的另一个我们绝对不想错过的机会是测试 API 调用的失败的能力。毕竟,我们确实想优雅地处理生活和代码中的失败。
def test_fetch_goggles_failure(mocker):
import project mocker.patch('project.fetch_goggles',
return_value={'status':408})
result = project.fetch_goggles() if result['status'] != 200:
# recover gracefully
graceful_recovery = True
# assert that this was not a success
assert graceful_recovery
我们已经将mocker.patch
中的返回值改为{'status':408}
。这模拟了 API 调用超时。现在我们可以测试如何从 API 调用失败中恢复。这使得我们的代码更有弹性,并且仍然不依赖于实际调用 API。
作者图片
现在我们知道我们是优雅的。
嘲笑物品的用途,而不是它的来源
如果你还没听过这个,你会的。你会听到很多次,才会有意义。这不完全是你的错。让我们看看我们是否能分解它。
首先,《去哪儿嘲讽》比较混乱。大家说这话的意思是“如何引用你要嘲讽的对象。”您实际上在测试函数中编写了模拟程序。问题是,您要模仿的对象的路径需要遵循特定的路线。
你可能经历过这些。您导入pandas
并编写一些代码。您决定将一些代码分解到一个单独的helpers.py
文件中。您从helpers.py
将函数导入到您的应用程序中,但是当您第一次运行代码时,您得到一个错误:NameError: name ‘pd’ is not defined
。显然,你忘了在你的新helpers.py
文件中导入熊猫。这是理解如何创建想要模仿的对象的路径的关键。
我们将使用 API 调用函数创建一个helpers.py
文件:
# helpers.pydef fetch_goggles():
# make an api call to goggles.com
# ... response = {'status':200,
"count": 5} return response
我们还将在project.py
中创建一个新函数,在这里我们将使用这个函数。
import helpers
def count_goggles():
result = helpers.fetch_goggles()
return result['count']
最后,我们创建测试函数。
import project
ojectdef test_count_goggles(mocker): mocker.patch('project.helpers.fetch_goggles',
return_value={'status':200, "count": 4}) result = project.count_goggles()
assert result == 4
为了修补我们的函数,我们沿着从我们所在的地方到函数的路径。从测试文件中,我们导入了project
。从project
我们导入了helpers
。fetch_goggles
驻留在helpers
中。因此我们得到project
。helpers
。fetch_goggles
作为我们希望修补的对象的路径。
结论
嘲讽是测试人员工具箱中的一个便捷工具,既然你现在是一名测试人员,你将嘲讽。模仿的价值在于它允许我们保持测试的真正独立性,并给我们一种方法来测试不同类型的返回值,而不需要这些值的所有上下文。当你在学习构建更好的单元测试时,永远记住要考虑单元测试的独立性。
似乎总是有很多关于“嘲笑哪里”的讨论,可能是这个问题的框架造成了混乱。您在您的测试函数中编写 mock,并沿着模块路径找到您正在模仿的对象。我建议不要去想“你在嘲笑哪里”,因为那只会让人困惑。
现在去做你的单元测试。
神经网络入门
使用 Pytorch 的简单 CNN 示例
图片来自 https://pixabay.com/images/id-1201014/的 https://pixabay.com/users/remazteredstudio-1714780/
问题是
在这篇文章中,我们要解决的玩具问题是识别图像中一条线的起点和终点的坐标。图像将是全黑的,即除了代表线的像素之外,所有像素都是 0。
这既不是分类问题(目标是识别线的存在或不存在),也不是对象检测问题(处理识别不是一个而是许多对象,对对象进行分类并通过边界框识别它们的位置)。这在某种程度上介于两者之间,这种选择的基本原理只是为了处理一些与网上数百个现有分类示例略有不同的东西。
基础知识
我们需要做一些事情来设置神经网络的必要组件。
图 1:训练步骤的简单列表(图片由作者提供)
- 数据准备
- 模型定义
- 训练和测试功能:训练功能是图 1 中调用的步骤将驻留的地方
- 损失函数和优化器
1.数据
在我们的练习中,我们将准备自己的自定义数据集。我用 skimage 生成了线坐标。给定起点和终点坐标,这将生成两个数组,表示属于该行的像素的索引。一个代表 x 的列表,另一个代表 y 的列表,把它们放在一起给出了直线经过的坐标。
https://scikit-image.org/docs/dev/api/skimage.draw.html#skimage.draw.line
图 2:生成一行(作者图片)
图 2 显示了一个简单的例子,说明我们将如何实现这一点。首先,我们将创建一个表示全 0 的单通道 10 X 10 图像的张量。然后,我们将随机选择一个起点和终点,以获取表示该行的像素的索引,并在创建的图像张量中将相应的值设为 1。
图 3 是利用该逻辑来创建图像和结果张量的函数。图像数量(dataCount)和图像大小(imgPixelSize)被定义为输入参数。注意:在这个例子中,我使用 128 作为 imgPixelSize。
当我们随机选择一个起点和终点时,我们还会执行一些基本的检查。
首先,我们确保起点总是在终点的左边。这仅仅是基于一种直觉,对于给定的任何一条线,我个人很可能总是将最左边的点指定为“起点”,而将另一个点指定为“终点”。
这使我能够消除“顺序无关紧要”的问题。给定一条从(0,0)到(9,9)的线,虽然从技术上来说将任一点称为起点或终点都是正确的,但训练模型以适应这两种可能性可能需要我编写一个自定义损失函数,而不是简单地与一个单一的基本事实进行比较。我还直觉地感觉到,像这样的约束可能有助于模型训练得更快。
第二个检查相当简单,我们确保随机选择的起点和终点不相同(如果是,那就不是一条线,而只是一个点)。
最后,我们返回图像和相应的结果张量。结果张量只不过是开始和结束坐标的表示,即具有 4 个值的张量。
图 3:创建线条
虽然这创建了我们需要的张量,但是使用它需要我们创建一个自定义数据集和一个相应的数据加载器。自定义数据集应该是实现 len()函数(返回数据集的长度)和 getitem(index)函数(返回给定索引处的样本)的类。我们还将使用 Pytorch 的数据加载器来创建一个可迭代的加载器,它将允许我们批处理和混洗数据。
图 4:定制数据集和数据加载器
2.培训和测试功能
训练函数非常简单,实现了图 1 中的内容。它将数据加载器、模型、损失函数和优化器作为输入,将模型置于训练模式,并为每一批迭代数据加载器。
对于每一批,我们首先将数据移动到可用的设备(gpu vs cpu),然后使用当前模型预测该批的结果,根据预测和基本事实计算损失,将上一轮的梯度归零,使用反向传播计算这一轮的梯度,并让优化器采取一个步骤来更新模型参数。
正如您可能注意到的,这是一个非常通用的函数,不管我们的模型结构如何,也不管我们选择的损失函数或优化器如何,它都能工作。
我们也有通用的测试函数,旨在评估不同于训练数据集的单独测试数据集的损失。测试函数的目的是查看模型对以前没有见过的数据(即没有训练过的数据)的表现。因此,我们将模型置于评估模式,只进行预测并计算损失。
图 5:训练和测试功能
3.模型
通过设计,卷积运算考虑了两个相邻像素之间的空间关系。一段时间以来,卷积神经网络一直是处理图像的事实架构。尽管还很初级,我们的玩具数据集也能处理基本的线条图像。所以让我们从建筑开始。
我从一个接一个的卷积层的随机排列开始。一个简单的谷歌搜索“卷积神经网络”显示,典型的标准似乎减少了高度和宽度,同时增加了这些层上的通道。最后,我们往往会有一个线性层堆栈,将最后一个卷积层展平为输出矢量。
在我们的例子中,输出向量将代表我们想要预测的内容。它将是一个 4 个值的张量,代表线的起点和终点的(x,y)坐标。
图 6:模型 1
上面的图 6 代表了模型本身。在这个例子中,我使用 128 作为 imgPixelSize。因此你所看到的数字都是由此而来的。第一个卷积层表示输入将有 1 层,这是我们在图 3 的 createDate 函数中生成的。它还指示输出将具有 4 层,卷积核的大小将为 3,步长为 2。我们有三个以上的 conv 层堆叠在这上面。然后,我们将输出变平,并在顶部堆叠几个线性层,最后一层产生 4 个值的输出张量。
你可能会注意到,重要的是我们不仅要知道第一层的输入形状,还要知道每一层的输入形状。在 Conv2D 中,我们需要知道输入中的通道数,而在线性中,我们需要知道输入张量的大小。虽然手动推导对于了解这些操作是如何工作的很重要,但是您可以将样本输入传递到一个临时的顺序网络,该网络由模型中使用的一个或多个相同的层组成,并打印结果的大小。请参见下面的图 7,了解如何快速了解添加到模型中的图层末尾的大小。
图 7:快速确定每层末尾尺寸的方法(图片由作者提供)
4.损失函数和优化器
交叉熵损失和 MSE 损失可能是许多例子中两个比较流行的损失函数。交叉熵通常用于分类问题,从公式的核心你可能已经注意到了。它是预测值的对数的函数,在分类问题中,我们感兴趣的是将真实类别的预测值推至 1,当预测值向 1 移动时,对数和损失将向 0 移动(反之亦然)。
图 8:交叉熵损失(图片由作者提供)
然而,我们不是在处理分类问题。我们处理的是预测一个“连续”值——介于 0 和(imgPixelSize-1)之间的任何值。以指示起点和终点的坐标。MSE 或均方误差适用于这类问题。正如下面的核心公式所示,这里我们处理的是实际值和预测值之间的差异,而不是预测值的对数。
图 9: MSE 损失(图片由作者提供)
输出向量预计包含 4 个数字,代表线的两个点——起点和终点。由于不熟悉哪种优化器工作得最好,我选择了 SGD——在 Pytorch 文档的快速入门示例中,它与 MSE 损失一起使用。
结果、观察和改进
请参见下面的图 10,了解我们上面讨论的所有内容是如何组合在一起的。
图 10:将所有这些整合在一起
只是为了测试所有部分是否都按预期工作,我重新创建了一个只有 100 张图像的训练数据集,并用该模型运行了 1 个时期。虽然端到端的过程看似可行,但结果却非常糟糕。对于更大的数据集,我甚至无法完成训练。
图 11:不良结果— 100 个图像训练数据集(作者提供的图像)
图 12:不良结果— 1000 个图像训练数据集(作者提供的图像)
但这是我们想要的初稿。第一稿不是迷失在一个“部分”的完美中,而是意味着首先将整个设置到位。我们可以稍后微调这些部分。
爆炸梯度
在最后一次跑步中,我注意到了一些事情。一是所有结果都是 NaN。当打印来自训练函数的预测时,很明显,在几轮训练后,预测开始呈指数增长,直到它变成 NaN。在打印模型参数(即权重)时,它们也变成了 NaN。
图 13:参数和预测都是 NaN(图片作者提供)
这表明了爆炸梯度问题。这是当导数很大时的情况,因为当我们反向传播时梯度也很大,并且模型权重变化如此剧烈,以至于它们变得太大而无法存储并变成 NaN。在图 14 中,您可以看到权重是如何以指数方式在各个时期更新变大的。
图 14:爆炸渐变(作者图片)
标准化数据
图像处理中的一个基本建议是归一化输入数据和输出,以避免爆炸梯度问题。在我们的数据中,我们没有这样做。
我们有两组数据。一个是图像本身,另一个是结果集。碰巧的是,我们生成图像的方式已经将背景像素标记为 0,将代表线条的像素标记为 1。因此不需要对图像数据进行进一步的归一化。
或者,如果我们处理的是一幅真实世界的图像,其中像素值可能在 0 到 255 之间变化,我们可能必须将它们除以 255 才能得到介于 0 和 1 之间的值。
另一方面,结果集需要一些规范化。目前,我们有绝对坐标,即一对 0 到 127 之间的数字,来代表起点和终点。让我们将它们除以 128,这是我们使用的图像的大小。
图 15:规范化结果集(作者图片)
激活功能
还要注意,我们的任何一层都没有激活功能。一般来说,跨层具有非线性激活函数是很常见的。这在一般意义上有所帮助,因为网络将学习非线性关系,没有这种关系,我们只是将一个线性函数应用于另一个,并创建一个大的线性函数。
尽管有卷积层,但在它们之间缺乏非线性激活函数将导致这样一个线性网络。如果我们把不同的层看作是代表一系列抽象概念的观察者的输入图像,以寻找起点和终点为最终目标,我不得不想象这些层之间的关系的性质将不会简单地是线性的。即使是这样,也可以用非线性激活函数在模型中表示这种关系,而用线性函数表示非线性关系则是不可能的。
所以在图层后添加了 ReLU。如今,在各种中枢神经系统中,标准做法是在卷积函数之后添加 ReLU。
图 16:修改后的模型(作者图片)
减少的层
考虑到我们的问题相对简单,我们还减少了卷积层的总层数。注意:我们现在没有添加任何脱落层(图像处理模型中的另一个常用功能),因为我们处理的是非常初级的图像,而不是具有复杂图案的真实图像。因此,在我们的案例中,辍学实际上可能会伤害学习,而不是帮助学习。
精度度量
为了获得更好的精确度,还添加了一个新的函数,允许在预测开始和结束坐标时有一定的回旋余地。即,如果(20,20)是起点的坐标,则预测(22,22)不一定是错误。因此,为了更好地了解模型是如何运行的,编写了一个新的函数,该函数将基础事实、预测和偏差作为输入参数,任何落在偏差定义的边界内的预测都不被视为错误。
图 17:考虑偏差的准确度指标(作者图片)
学习率
最后,我们必须了解要使用的正确学习率。从 0.1 的学习率开始,我注意到输出要么是 1,要么是 0。在打印线性层末端的中间权重和输出时,我注意到最后一个线性层的输出达到非常高的正值或负值。虽然参数本身没有发生如此剧烈的变化,但无论做了什么改变,都足以导致这种情况。
所以我将速率降低到 0.01,较慢的学习速率意味着参数值的变化较小,然后再次尝试。虽然更新确实更小,并且需要几个额外的时期,但最终结果仍然相同,输出收敛为 0 或 1。但是 0.001 的情况要好得多,我注意到即使经过 5 个时期,这些值并没有真正变成 1 或 0。它们在第一批结束时增加,在下一批减少,表明某种对最优解的搜索正在发生。
因此,在这种学习速度下,我运行了 500 个时期的训练,如图 X 中的度量标准所定义的,准确率飙升至 94%以上,这使得这成为解决我们着手解决的玩具问题的一次相当令人满意的尝试。合并了上述修改后的笔记本最终版本的要点可以在这里找到。
图 18:修改后的结果更好(作者图片)
开始使用蛋白沉积:在 PyTorch 示例中赢得深度学习图像增强技术
Kaggle CV 比赛获奖秘诀?关于如何使用 Albumentation 库进行图像增强的教程
克里斯汀娜面粉在 Unsplash 上拍摄的照片
无论你是安静地参加 Kaggle 比赛,试图学习一种新的酷 Python 技术,还是数据科学/深度学习的新手,或者只是在这里抓取一段你想复制粘贴并立即尝试的代码集,我保证这篇文章将非常有帮助。
在这篇文章中,我将全面介绍最广泛使用的(2021 年和正在进行的)图像增强库之一,albumination,并给出示例 Python 代码和输出。通过这篇文章,你应该能够对 蛋白 有一个基本的了解,并最终在你自己的工作空间中进行尝试。任何没有(或很少)Pytorch 或 Python 经验或接触图像增强技术本身的人也是受欢迎的。
我个人发现这个库在我的日常使用中对任何计算机视觉相关的任务都非常有用,所以我想,‘为什么我不就此发表一篇文章呢?’?
免责声明:这篇文章不是由albumination赞助的,也不隶属于它。
那么,究竟什么是蛋白沉积?使用起来有什么特点和优势?现实世界的应用有哪些?
什么是蛋白沉积?
在你了解白质化有什么帮助之前,理解图像增强在计算机视觉中的意义是至关重要的。
Ryan Allred 的帖子有一个很好的解释。
深度神经网络,尤其是卷积神经网络(CNN),尤其擅长图像分类任务。最先进的 CNN 甚至被证明在图像识别方面超过了人类的表现(……)图像增强是获取已经存在于训练数据集中的图像并对其进行处理以创建同一图像的许多修改版本的过程。这不仅提供了更多的图像进行训练,而且还可以帮助我们的分类器暴露在更广泛的光照和颜色情况下,从而使我们的分类器更加鲁棒
图像增强样本。图片由 https://github.com/aleju/imgaug 的提供
基本上,它向给定的图像/图片中定制添加各种不同的品种,以增加训练数据集的规模,最终帮助提高深度学习模型的准确性。
Albumentation 是一个工具,可以在将图像/图片放入模型之前,对其进行[ 弹性、网格、运动模糊、移位、缩放、旋转、转置、对比度、亮度等] 定制。
官方蛋白网站称自己为
Albumentations 是一个 Python 库,用于快速灵活的图像增强。Albumentations 有效地实现了针对性能而优化的丰富多样的图像变换操作,并且同时为不同的计算机视觉任务(包括对象分类、分割和检测)提供了简洁而强大的图像增强接口。
albuminations 已于 2020 年正式发表在信息杂志上,标题为albuminations:快速灵活的图像增强 ,目前由来自俄罗斯的 5 名核心团队成员维护,功能更新一致。
为什么要用白蛋白?
与其他图像增强相关包不同的是,
是 快
这个包已经被几个基于 OpenCV 的库(包括 NumPy,OpenCV,imgaug)优化了。
现在你有机会面对最终的老板,而不用痛打所有的中层老板
我的深度学习首选 python 框架是 Pytorch,所以我最初接触了 torchvision 原生提供的torch vision . transforms的用法。torch vision . transforms已经给出了相当扎实的定制增强方法和文档,所以我一直坚持它的产品。****
在寻找更好的增强开源库时,我发现了这个 Albumentation 包。我发现它非常快,高度可定制,最重要的是,它只需要 https://github.com/albumentations-team/albumentations
上图是英特尔至强白金 8168 CPU 的测试结果,由 ImageNet 中的 2000 个验证集映像提供。每个单元格中的值表示单个内核中处理的图像数量。你可以看到,在许多转换中,Albumentation 比所有其他库至少快 2 倍。
您可以在albumination 官方 GitHub 中找到有关最新 0.5.0 版本的基准测试的更多信息。
怎么用白蛋白?
教程
对于这个项目的范围,我将介绍白蛋白的主要成分和用途。该代码集主要基于 Albumentations 团队的教程笔记本。我参考了下面的笔记本:
migrating _ from _ torch vision _ to _ albuminations . ipynb
- 在 Google Colab 中安装 Google Drive
我坚持使用 Google Colab 来制作简单/可共享的笔记本原型。他们的 Jupyter 是免费的,你可以使用免费的 GPU!
你可以上传你的照片到你的 Google Drive,然后用下面的代码把 Google Drive 挂载到 Colab。
该单元格将返回以下内容在浏览器中转到该 URL。**点击 URL 后,您可以检索授权码。复制粘贴这段代码,然后按回车键和就可以了!****
**from google.colab import drive
drive.mount("/content/gdrive")**
作者照片。认证后的结果
此外,我将导入本教程所需的所有其他 Python 库
为了演示的目的,我用了一张意大利威尼斯的街景照片,这是我前阵子去欧洲旅行时拍的。
**from PIL import Image
import time
import torch
import torchvision
from torch.utils.data import Dataset
from torchvision import transforms
import albumentations
import albumentations.pytorch
from matplotlib import pyplot as plt
import cv2
import numpy as np**
作者照片。意大利威尼斯的一条街道
原始火炬视觉数据管道
我通常使用 PyTorch 和 Torchvision 创建一个数据加载器来处理图像数据管道。在下面的代码中,它
创建一个简单的 Pytorch 数据集类
- 调用图像并进行转换
- 用 100 个循环测量整个处理时间
- 首先,从 torch.utils.data 中获取 Dataset 抽象类,并创建一个 TorchVision Dataset 类。然后我插入图像,并使用 getitem 方法进行转换。此外,我使用
total_time = (time.time() - start_t
来测量需要多长时间
然后,我们将图像的大小调整为 256x256(高重),并随机裁剪为 224x224。然后以 50%的概率应用水平翻转,转换为张量。输入文件路径应该是你的图片所在的 Google Drive 的路径。*
**class TorchvisionDataset(Dataset):
def __init__(self, file_paths, labels, transform=None):
self.file_paths = file_paths
self.labels = labels
self.transform = transform
def __len__(self):
return len(self.file_paths)
def __getitem__(self, idx):
label = self.labels[idx]
file_path = self.file_paths[idx]
# Read an image with PIL
image = Image.open(file_path)
start_t = time.time()
if self.transform:
image = self.transform(image)
total_time = (time.time() - start_t)
return image, label, total_time**
然后,我们计算从 torchvision_dataset 中提取样本图像并转换它所需的时间,然后运行 100 次循环来检查它所需的平均毫秒数。
**torchvision_transform = transforms.Compose([
transforms.Resize((256, 256)),
transforms.RandomCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
])
torchvision_dataset = TorchvisionDataset(
file_paths=["/content/drive/MyDrive/img5.jpg"],
labels=[1],
transform=torchvision_transform,
)**
在我的 Colab 环境中,Resize+RandomCrop+RandomHorizontalFlip 的一百次循环大约花费了 40 ms,最后一张图像花费了 224x224,如您所见。你也可以看到翻转发生在第 100 张图片上!
**total_time = 0
for i in range(100):
sample, _, transform_time = torchvision_dataset[0]
total_time += transform_time
print("torchvision time/sample: {} ms".format(total_time*10))
plt.figure(figsize=(10, 10))
plt.imshow(transforms.ToPILImage()(sample))
plt.show()**
沉淀数据管道
现在,我将重构从火炬视觉到蛋白质合成的数据管道
类似于 TorchVision,我们创建了一个 Albumentations 数据集类。
现在在蛋白沉积中创造一个转变。在这个例子中,你可以发现一个小小的语法差异,那就是 Torchvision 的 RandomHorizontalFlip() 通过 HorizontalFlip() 在 Albumentation 中产生相同的结果
**class AlbumentationsDataset(Dataset):
"""__init__ and __len__ functions are the same as in TorchvisionDataset"""
def __init__(self, file_paths, labels, transform=None):
self.file_paths = file_paths
self.labels = labels
self.transform = transform
def __len__(self):
return len(self.file_paths)
def __getitem__(self, idx):
label = self.labels[idx]
file_path = self.file_paths[idx]
# Read an image with OpenCV
image = cv2.imread(file_path)
# By default OpenCV uses BGR color space for color images,
# so we need to convert the image to RGB color space.
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
start_t = time.time()
if self.transform:
augmented = self.transform(image=image)
image = augmented['image']
total_time = (time.time() - start_t)
return image, label, total_time**
执行相同的图像转换,获得平均时间,并可视化结果。
**"""
torchvision_transform = transforms.Compose([
transforms.Resize((256, 256)),
transforms.RandomCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
])
"""
# Same transform with torchvision_transform
albumentations_transform = albumentations.Compose([
albumentations.Resize(256, 256),
albumentations.RandomCrop(224, 224),
albumentations.HorizontalFlip(), # Same with transforms.RandomHorizontalFlip()
albumentations.pytorch.transforms.ToTensor()
])**
令人惊讶的是,只用了 1.77ms,比 Torchvision 快了约 23 倍!它甚至比我们从官方基准文档中看到的计算差距更大,而且裁剪区域似乎也略有不同。
**# Same dataset with torchvision_dataset
albumentations_dataset = AlbumentationsDataset(
file_paths=["/content/drive/MyDrive/img5.jpg"],
labels=[1],
transform=albumentations_transform,
)
total_time = 0
for i in range(100):
sample, _, transform_time = albumentations_dataset[0]
total_time += transform_time
print("albumentations time/sample: {} ms".format(total_time*10))
plt.figure(figsize=(10, 10))
plt.imshow(transforms.ToPILImage()(sample))
plt.show()**
白蛋白的应用
如你所见,它非常快,速度很重要。
在代码竞赛中,如果可以减少图像处理中的计算瓶颈,就可以将更多的资源用于其他部分(模型拟合、超参数调优等)。
- 在现实世界的行业中,生产数据库中新图像的流入量可能很大(即每秒 1000 幅图像)。想象开发一个实时深度学习模型。在该模型中,处理图像的快速方法至关重要,这可能会影响用户体验并最终影响收入/利润。
- 对于你的学习目的来说,接触最新的和表现最好的技术技能是有帮助的,这在你建立自己的项目时可能是有用的,也许在找工作(例如简历)时也是有用的
- 更复杂的例子
最后,我将展示如何使用函数中的函数进行增强,我个人认为这是最复杂的,但在蛋白沉积中非常有用
它在调整大小和随机裁剪方面与之前的代码集有相同的代码。 OneOf 在括号内随机选取一个列出的变换。我们甚至可以把发生的概率放在函数本身中。例如,如果其中一个([…],p=0.5),它以 50%的几率跳过整个变换,并以 1/6 的几率随机选取三个变换中的一个。
**albumentations_transform_oneof = albumentations.Compose([
albumentations.Resize(256, 256),
albumentations.RandomCrop(224, 224),
albumentations.OneOf([
albumentations.HorizontalFlip(p=1),
albumentations.RandomRotate90(p=1),
albumentations.VerticalFlip(p=1)
], p=1),
albumentations.OneOf([
albumentations.MotionBlur(p=1),
albumentations.OpticalDistortion(p=1),
albumentations.GaussNoise(p=1)
], p=1),
albumentations.pytorch.ToTensor()
])**
我让它从水平翻转、旋转、垂直翻转中随机选择,又让它从模糊、失真、噪声中随机选择。所以在这种情况下,我们允许 3x3 = 9 种组合。
来自定义的图像变换的五个样本如下:
**albumentations_dataset = AlbumentationsDataset(
file_paths=["/content/gdrive/My Drive/img5.png"],
labels=[1],
transform=albumentations_transform_oneof,
)
num_samples = 5
fig, ax = plt.subplots(1, num_samples, figsize=(25, 5))
for i in range(num_samples):
ax[i].imshow(transforms.ToPILImage()(albumentations_dataset[0][0]))
ax[i].axis('off')**
我们看到旋转 360,水平翻转,垂直翻转被应用,不同的失真被应用到所有遮光罩下的图像。
除了我所解释的,还有许多例子。请参考官方营养强化网站或营养强化 Github 来应用最适合自己需求的强化!
额外资源
注 您还可以找到 Jupyter 笔记本,其中包含了 albumination:ka ggle 竞赛的真实用法
孟加拉语。AI 手写字素分类是一个代码竞赛,给定一个手写孟加拉字素的图像,对图像中的三个组成元素进行分类。这是一个图像分类问题,Albumentation 用于转换最初存在于拼花文件中的数万张图像,大小为 GB。
GitHub: 孟加拉语。AI 手写字素分类大赛
结论
总之,我介绍了图像增强技术,Python 中的 Albumentation 库,教程中有示例代码。为了这个项目,这个实验只使用了一张图像,但是可以发现速度有了很大的提高。白蛋白提供了各种各样的转换,所以我强烈推荐我的读者从今天开始使用它。
有关学习其他数据科学主题的更多详细信息,下面的 Github 存储库也会有所帮助
生产中的 AWS sage maker
展示如何使用 Amazon SageMaker 及其 ML/DL 算法解决业务问题的端到端示例。
- PySpark
函数和实用程序,带有真实世界的数据示例。可以用来构建一个完整的数据建模的 ETL 过程 - 推荐系统
py torch 中推荐系统的生产级实现。克隆 repo 并通过运行“main.py”开始训练 - 自然语言处理(NLP)
Python 中几种自然语言处理方法的完整实现示例。按照学习的复杂程度排序 - 关于作者
贤俊是一名拥有统计学学位的数据极客。他喜欢分享数据科学/分析知识。在 LinkedIn 上给他发消息。
参考: (1)瑞安·奥尔雷德,https://towardsdatascience . com/AWS-glue-and-you-e2e 4322 f 0805
(2)霍亚 012,https://hoya012.github.io/blog/albumentation_tutorial/
(3)蛋白发酵官方文档,https://albumentations.ai/docs/
Reference: (1) Ryan Allred, https://towardsdatascience.com/aws-glue-and-you-e2e4322f0805
(2) Hoya012, https://hoya012.github.io/blog/albumentation_tutorial/
(3) Albumentation Official Docs, https://albumentations.ai/docs/
AWS 入门:保持“免费层”免费
通过监控您的使用情况来防止收费
图片由泰勒·维克(【https://unsplash.com/@tvick】T4)提供
当学习如何使用“云”时,意想不到的费用是通行的权利,即使使用“免费层”。我们自己也经历过这种情况,我们看到它发生在我们大多数学生身上。在这篇文章中,我们将帮助开明的新人避免为他们的错误付出代价。
为什么这是一个问题?
你可能会认为“免费层”意味着你不用付钱。事实并非如此。从设计上来说,云允许你消费你所要求的任何数量的资源。这种做法的负面影响是,如果你要求的数量超过了你的免费配额,你将为此付出代价。只有在 AWS 为您设置的使用限制内,免费层才会保持免费。如果您超出这些限制,将根据他们的计费计划向您收费。
这样做的理由是资本支出与运营支出。云的全部意义在于你可以得到你想要的。如果你想消耗更多免费的资源,你可以这样做,但是你需要付费。
然而,至少应该有一个选项,让你一旦达到免费层的限制,以防止任何收费杀死所有的服务。这是用户十多年来一直要求的功能。
在投入 AWS 之前,您需要理解关键的计费概念并构建一个安全网。
AWS 免费层包括什么?
为了防止被收费,我们首先需要知道免费层包括什么,因为知道是成功的一半。
免费层中最常用的 AWS 服务包括 EC2、S3 和 RDS。以下是这些服务的自由层限制:
AWS 免费层包括更多的服务,可以在这里找到。
监控您的使用情况
如果您注册了 AWS 免费层,您可以通过几种不同的方式来监控您的使用情况。
最直接的方法是查看您的“自由层服务表”此表可在您的“计费和成本管理控制台”中找到
在这里,您可以查看服务、您的当前使用情况以及您的预测使用情况。如果您接近了您的极限,您可以关闭服务(我们将在下一节介绍如何做)。
您还可以在接近免费等级限制时启用电子邮件提醒。这些警报也是从“计费和成本管理控制台”创建的
然后,您将:
- 点击“首选项”
- "帐单首选项"
- 在“成本管理首选项”下
- 选中“接收免费层使用警报”复选框
- 输入您的电子邮件地址
- 保存首选项
当您接近任何免费等级服务的上限时,您将会收到提醒。然而,即使启用了此功能,仍然建议您经常关注您的使用情况,正如 AWS 声明的此警报。
关闭服务
既然您已经了解了如何跟踪您的空闲层使用情况,现在您需要了解战斗的后半部分,即禁用您的服务。
一个很好的方法来检查什么服务正在运行,在什么服务器上,到你的“账单”页面。
选择当前月份以显示正在运行的服务,您将获得该月使用的服务列表。然后,您可以单击接近限制的服务,并查看它在哪个(哪些)区域运行。这一点很重要,因为你需要关闭所有地区的服务,以防止被收费。
不关闭所有地区的服务是一个常见的错误,如果你最终超过了限制,你将被收费。
在这个例子中,我有一个运行在 N. Virginia 和 Ohio 地区的 RDS 实例。因此,要关闭这些,我需要前往 AWS 上的 RDS 页面。
一旦到了那里,你就可以通过查看右上角来知道你在哪个服务器上。
我们可以暂时关闭或永久删除 RDS 实例。
如果你计划在下个月使用同一个数据库,并想关闭它以避免被收费,你可以按照这些步骤来“停止”服务。如果你打算完全删除实例,你可以遵循指南。
注意:当询问您是否要创建快照时,请选择“否”,因为如果超出限额,您可能需要为此付费。
对运行 RDS 的任何其他地区重复此过程。
一旦您关闭了剩余的实例,回头看看您的账单,并找到哪些正在运行的服务需要关闭以防止收费。
关闭其他服务将是一个类似的过程。为了了解如何关闭这些服务,AWS 有一个深入的指南这里。
记住关闭每台服务器的服务。
确认没有运行任何东西
您还可以采取一个额外的步骤来验证没有其他需要付费的东西正在运行,请随时给 AWS 支持发送消息。支持部门的响应相当迅速,这是确保您不会收到任何意外费用的好方法。
如果你被指控,该怎么办
如果你真的收到意外的费用,不要惊慌。我们有学生在忘记完全关闭他们的实例后被指控。有些被收了几百(一个学生,甚至一千多)美元。
所有人都能够联系 AWS,并通知他们,他们不小心让他们的实例运行,因为他们是初学者,不理解这个过程。AWS 确实为他们提供了退款,但你不希望让这成为一种习惯,因为人们会认为,如果你不断要求退款,他们将不会继续这么理解。
结论
AWS 的“免费层”允许你尝试他们提供的许多服务,但是正如你所看到的,“免费”并不总是免费的。
希望本指南能帮助你在学习如何使用 AWS 的过程中避免任何意外的费用。
关注我们了解更多内容
开始使用 Azure Data Explorer 和 Azure Synapse Analytics 进行大数据处理
通过实际例子,了解如何利用这些服务之间的集成,通过 Apache Spark 处理数据
Azure Data Explorer 是一种完全托管的数据分析服务,可以处理来自任何数据源的大量不同数据,如网站、应用程序、物联网设备等。Azure Data Explorer 使获取这些数据变得简单,并使您能够在几秒钟内对数据进行复杂的即席查询。它可以在几分钟内快速扩展到万亿字节的数据,允许快速迭代数据探索,以发现相关的见解。它已经通过数据源和数据接收器连接器与 Apache Spark work 集成,用于为近实时数据处理、数据存档、机器学习等解决方案提供动力。
面向大数据工作负载的 Azure Data Explorer
得益于对该解决方案的扩展,Azure Data Explorer 可作为 Azure Synapse Analytics 中的链接服务,允许 Azure Data Explorer 和 Azure Synapse 中的 Apache Spark 池之间的无缝集成。
Azure Synapse 汇集了企业数据仓库中使用的 SQL 技术、用于大数据的 Spark 技术、用于数据集成和 ETL/ELT 的管道,以及与 Power BI、CosmosDB 和 AzureML 等其他 Azure 服务的深度集成。
这篇博文是一个入门指南,展示了 Azure Data Explorer 和 Azure Synapse 之间的集成。它包括:
- 如何使用 Spark 和 Azure Synapse 处理 Azure Data Explorer 中的现有数据?
- 使用 Spark 处理流和批处理数据,并将其写回 Azure data explore。
笔记本在本次 GitHub repo 中有售—https://GitHub . com/abhirockzz/synapse-azure-data-explorer-101
要学习,你需要的只是一个 Azure 账户(你可以免费获得一个)。一旦你准备好了,就进入下一部分吧!
初始设置和配置
首先创建一个 Azure Synapse workspace 以及一个 Apache Spark pool 。然后,创建一个 Azure Data Explorer 集群和数据库
调整摄取策略
在摄取过程中,Azure Data Explorer 试图通过在等待摄取时将小的入口数据块批处理在一起来优化吞吐量,这由摄取批处理策略控制。默认策略值为:最大延迟时间为 5 分钟,1000 个项目,批处理的总大小为 1G。这意味着从触发数据接收到准备好进行查询之间有一定的延迟。好的一面是,该策略可以根据需要进行微调。
出于演示的目的,我们专注于让我们的数据尽快可供查询。因此,您应该使用30
秒的MaximumBatchingTimeSpan
值来更新策略
.alter database adxdb policy ingestionbatching @'{"MaximumBatchingTimeSpan": "00:00:30"}'
将此策略设置为非常小的值会增加成本并降低性能,这只是为了演示
从 Synapse 连接到 Azure 数据浏览器
在 Azure Synapse Analytics 中,链接服务是您定义与其他服务的连接信息的地方。您可以使用 Azure Synapse 分析工作区为 Azure Data Explorer 创建链接服务。
创建链接服务(按作者分类的图像)
与服务主体相反,托管身份正被用作身份验证方法
创建链接服务后,它将显示在列表中:
Azure Data Explorer 链接服务(图片由作者提供)
好了,你都准备好了!
如果你已经在使用 Azure Data Explorer,很可能你已经有了大量的数据,等待处理!所以让我们从探索这方面开始。
在 Azure Data Explorer 中处理现有数据
数据接收是 Azure Data Explorer 等大数据分析服务的关键组件。难怪,它支持多种方式来从各种来源获取数据。虽然对摄取技术和选项进行了详细的讨论,但是欢迎您在文档中阅读。
为了节省时间,让我们手动摄取数据。不要让“手动”这个词误导你。相当简单快捷!
首先在数据库中创建一个表(姑且称之为StormEvents_1
):
.create table StormEvents_1 (StartTime: datetime, EndTime: datetime, EpisodeId: int, EventId: int, State: string, EventType: string, InjuriesDirect: int, InjuriesIndirect: int, DeathsDirect: int, DeathsIndirect: int, DamageProperty: int, DamageCrops: int, Source: string, BeginLocation: string, EndLocation: string, BeginLat: real, BeginLon: real, EndLat: real, EndLon: real, EpisodeNarrative: string, EventNarrative: string, StormSummary: dynamic)
…并将 CSV 数据接收到表格中(直接从 Blob 存储中):
.ingest into table StormEvents_1 'https://kustosamplefiles.blob.core.windows.net/samplefiles/StormEvents.csv?sv=2019-12-12&ss=b&srt=o&sp=r&se=2022-09-05T02:23:52Z&st=2020-09-04T18:23:52Z&spr=https&sig=VrOfQMT1gUrHltJ8uhjYcCequEcfhjyyMX%2FSc3xsCy4%3D' with (ignoreFirstRecord=true)
如果你觉得这个技术有用,我鼓励你也试试 一键摄取 !
消化可能需要一分钟左右的时间。确认数据是否可用,并执行简单的查询:
.show ingestion failuresStormEvents_1| count
StormEvents_1| take 5 StormEvents_1| take 5 | project StartTime, EndTime, State, EventType, DamageProperty, Source
StormEvents_1
表提供了一些关于美国发生的风暴的信息。看起来是这样的:
Azure Data Explorer table data
(图片作者提供)
对于后续步骤,您可以将代码直接粘贴到 Azure Synapse Analytics 中的 Synapse Studio 笔记本中,或者将该笔记本导入到工作区中。
Azure Synapse 工作空间笔记本(图片由作者提供)
从简单的事情开始:
kustoDf = spark.read \
.format("com.microsoft.kusto.spark.synapse.datasource") \
.option("spark.synapse.linkedService", "adx") \
.option("kustoDatabase", "adxdb") \
.option("kustoQuery", "StormEvents_1 | take 10") \
.load()display(kustoDf)
为了从 Azure Data Explorer 中读取数据,我们需要使用kustoQuery
选项指定查询。在这种情况下,我们只是执行StormEvents_1 | take 10
来验证数据。
这次让我们尝试另一个 Kusto 查询:
filtered_df = spark.read \
.format("com.microsoft.kusto.spark.synapse.datasource") \
.option("spark.synapse.linkedService", "AzureDataExplorer1") \
.option("kustoDatabase", "mydb") \
.option("kustoQuery", "StormEvents_1 | where DamageProperty > 0 and DeathsDirect > 0 | project EventId, State, StartTime, EndTime, EventType, DamageProperty, DeathsDirect, Source") \
.load()filtered_df.createOrReplaceTempView("storm_dataset")
这将把所有记录读入到一个DataFrame
中,选择相关的列并过滤数据。例如,我们排除了没有任何财产损失或死亡的事件。最后,我们创建一个临时视图(storm_dataset
),以便使用 Apache Spark SQL 执行进一步的数据探索。
在此之前,让我们使用Seaborn
(一个 Python 数据可视化库)来绘制一个简单的条形图:
import seaborn as sns
import matplotlib.pyplot as pltfiltered_df = filtered_df.toPandas()ax = sns.barplot(x="DeathsDirect", y="EventType",data=filtered_df)
ax.set_title('deaths per event type')
ax.set_xlabel('Deaths#')
ax.set_ylabel('Event Type')
plt.show()
Seaborn 情节(图片由作者提供)
下面是一个基于临时视图的 Spark SQL 示例。
%%sqlSELECT EventType, AVG(DamageProperty) AS avg_property_damage
FROM storm_dataset
GROUP BY EventType
ORDER BY avg_property_damage DESC
我们计算了每种事件类型(雪崩、冰暴等)造成的平均损失。).下面的输出是柱形图的形式(但也有其他选项):
图表输出(图片由作者提供)
这是上面的一个小变化,我们找出每个州的最大死亡人数。
%%sqlSELECT
State
, MAX(DeathsDirect) AS deaths
FROM storm_dataset
GROUP BY State
ORDER BY deaths DESC
这次还有一个饼状图输出:
饼图输出(图片由作者提供)
现在,您知道了如何通过使用 Azure Synapse 中的 Apache Spark 池进行处理,从 Azure Data Explorer 中的现有数据集中提取见解。
处理数据并将数据写入 Azure Data Explorer
本节将介绍如何使用 Spark(准确地说是 Synapse Spark Pools)处理数据,并将其写入 Azure Data Explorer 以供进一步分析。
首先创建另一个表StormEvents_2
.create table StormEvents_2 (StartTime: datetime, EndTime: datetime, EpisodeId: int, EventId: int, State: string, EventType: string, InjuriesDirect: int, InjuriesIndirect: int, DeathsDirect: int, DeathsIndirect: int, DamageProperty: int, DamageCrops: int, Source: string, BeginLocation: string, EndLocation: string, BeginLat: real, BeginLon: real, EndLat: real, EndLon: real, EpisodeNarrative: string, EventNarrative: string, StormSummary: dynamic)
我们将使用现有的 CSV 数据。这与我们之前在 Azure Data Explorer 中获取的数据相同。但是,这一次,我们将把它下载到我们的本地机器,并上传到与 Azure Synapse workspace 关联的 ADLS Gen2 帐户。
从下载该文件开始:
curl -o StormEvents.csv "https://kustosamplefiles.blob.core.windows.net/samplefiles/StormEvents.csv?sv=2019-12-12&ss=b&srt=o&sp=r&se=2022-09-05T02:23:52Z&st=2020-09-04T18:23:52Z&spr=https&sig=VrOfQMT1gUrHltJ8uhjYcCequEcfhjyyMX%2FSc3xsCy4%3D"
使用工作区将其上传到 ADLS 文件系统:
将文件上传到 Azure 数据湖存储(图片由作者提供)
对于后续步骤,您可以将代码直接粘贴到 Azure Synapse Analytics**中的 Synapse Studio 笔记本中,或者将 该笔记本 导入到工作区中。
将数据集从 ADLS Gen2 加载到一个DataFrame
:
events = (spark.read
.csv("/StormEvents.csv", header=True, inferSchema='true')
)
使用 Apache Spark 应用一些基本的过滤——忽略包含空数据的行,删除我们不需要处理的列,过滤没有任何属性损坏的行。
events_filtered = events.dropna() \
.drop('StormSummary', 'EndLat','EndLon','BeginLat','BeginLon') \
.filter((events.DamageProperty > 0))print(events_filtered.count())
display(events_filtered.take(10))
最后,将DataFrame
写入 Azure 数据浏览器:
events_filtered.write \
.format("com.microsoft.kusto.spark.synapse.datasource") \
.option("spark.synapse.linkedService", "adx") \
.option("kustoDatabase", "adxdb") \
.option("kustoTable", "StormEvents_2") \
.option("tableCreateOptions","FailIfNotExist") \
.mode("Append") \
.save()
请注意,我们使用了
FailIfNotExist
,这意味着如果在请求的集群和数据库中没有找到该表,操作将会失败。
另一个选项是CreateIfNotExist
—如果在请求的集群和数据库中找不到该表,将创建该表,其模式与正在写入的数据帧相匹配。更多信息请参考https://github . com/Azure/Azure-kusto-spark/blob/master/docs/kustosink . MD # supported-options
给它一分钟让数据被写入。然后你就可以随心所欲地执行 Azure Data Explorer 查询了!尝试以下内容:
.show ingestion failuresStormEvents_2| take 10StormEvents_2
| summarize event_count=count() by bin(StartTime, 1d)
| render timechart
时间图输出(图片由作者提供)
您刚刚执行的只是典型的基于批处理的数据处理设置的一瞥。但是情况并不总是这样!
快速回顾
在这篇博文中,你学到了:
- 如何设置和配置 Azure Synapse 和 Azure Data Explorer(包括安全访问)。
- 如何充分利用 Azure Data Explorer 中的现有数据并使用 Azure Synapse 中的 Apache Spark pools 对其进行处理。
- 如何处理来自外部来源的数据并将结果写回 Azure Data Explorer 以供进一步分析。
总结一下!
这些简单的例子可以帮助你开始。但是,Apache Spark SQL、 Python 和 Scala/Java 库的全部功能都可供您使用。如果我不提及 Synapse SQL Pools(有无服务器和专用模式)将是我的失职,它允许通过 T-SQL 进行数据访问,并为广泛的商业智能、专用查询工具和流行的驱动程序提供了可能性。
🙏🏻感谢 Manoj Raheja 和 Adi Polak 的评论和反馈!🙏🏻
BigQuery 脚本入门
揭开 BigQuery 功能强大但可能难以理解的一面,一步一步来
BigQuery 脚本有点像回到过去。照片由 Aaron Burden 在 Unsplash
BigQuery 中的脚本功能非常强大,但语法复杂,尤其是对于习惯于使用简洁、描述性的、大部分是顺序的和人类可读的语言(如 Python)的人来说。
关于脚本的官方文档是一个很好的参考,但我总是发现很难找到一本指南来帮助我一步一步地学习核心概念,从最简单的情况到更复杂的情况。
因为解释概念会让你更深入地学习它们,所以我尽最大努力学得更深一点。
所以让我们从头开始。
什么是 BigQuery 脚本?
BigQuery 中的脚本是做事情的语句序列。它们有基本的控制结构,如变量和循环,并使您能够自动化操作,否则将需要重复,复制/粘贴和潜在的人为错误,这总是伴随着这种方法。
通过在脚本中使用数据定义语言( DDL ),您可以实现大量的自动化任务,而无需离开您可信赖的 BigQuery 控制台。
BigQuery 脚本最有用的方面之一是能够将行为封装到一个过程(本质上是一个函数)中,然后用一组参数调用它来执行一个或一组任务。
程序存在于何处?
BigQuery 中的过程看起来与用户界面左侧资源树中的表或视图完全一样(具有不同的图标),无论您使用的是哪个版本,资源树都在左侧。我不喜欢在新版本中启动额外的标签页,所以我坚持使用以前的功能强大的控制台。
你是如何创造它们的?
在 BigQuery 中定义一个函数(实际上它在技术上是一个过程。或者有时是例行公事。但我要称它们为函数,因为它们是函数),至少你要命名函数,并在开头和结尾之间添加一些 SQL。开始由 BEGIN 语句标记,结束由 end 标记。
到目前为止一切顺利。实际的语法是:
CREATE OR REPLACE PROCEDURE project_id.dataset_name.function_name()
BEGIN
# function body
END;
实际上,在开头和结尾之间会有很多代码,在括号之间是变量定义,但这是代码的高级结构。
但是,上面的代码不会运行,因为函数体中没有要执行的内容。添加一个简单的 select 语句会在右下角给你一个方便的绿色勾号,这意味着你可以开始了。我将在 flowfunction 项目的示例数据集中创建一个真正的函数(注意,如果您的项目名称中没有任何下划线,您不需要用反斜杠将它们括起来,我认为这样更简洁):
CREATE OR REPLACE PROCEDURE
flowfunctions.examples.hello_world()
BEGIN
SELECT TRUE;
END;
太好了!运行后,我现在在示例数据集中有了一个名为 hello_world 的函数。我可以在我的结果窗格中看到对此的确认:
This statement replaced the procedure named flowfunctions.examples.hello_world.
但是我还没有实际运行它,所以我看不到输出。我将在脚本中添加另一行代码,重新定义函数,然后运行它:
CREATE OR REPLACE PROCEDURE
flowfunctions.examples.hello_world()
BEGIN
SELECT TRUE;
END;CALL flowfunctions.examples.hello_world()
现在,我应该在结果窗格中看到两个阶段。如果我第二次点击查看结果,我将看到一个结果为真。现在,由于我调用了函数 hello_world ,我最好更新函数体以与此保持一致。我将把代码改为:
CREATE OR REPLACE PROCEDURE
flowfunctions.examples.hello_world()
BEGIN
SELECT "Hello World!" AS response;
END;CALL flowfunctions.examples.hello_world()
现在我有了一个名为“你好,世界!”的专栏作为单行响应值。太好了!我们现在已经构建了最简单的 BigQuery 函数(与发布的博客文章相比,后者非常有趣,但肯定不是最简单的脚本介绍示例)。
参数呢?
还有一件事,因为您几乎总是会将函数参数传递给 BigQuery 过程,所以我将添加一个名为 name 的输入参数。这将是一个字符串,所以我需要预先定义它,我将把它变成一个新函数:
CREATE OR REPLACE PROCEDURE
flowfunctions.examples.hello_name(name STRING)
BEGIN
SELECT FORMAT("Hello %s!", name) AS response;
END;CALL flowfunctions.examples.hello_name("Dad")
现在,在执行之前,您可能会注意到函数调用带有红色下划线,这表明有问题。不要担心,这是因为在执行 CREATE 或 REPLACE 语句之前,该函数是不存在的。
执行这个脚本将创建函数,然后显示“Hello Dad!”作为单行响应,使用格式的字符串函数将变量注入字符串,这比使用连接更具可读性。
所以我们开始吧,最简单的可能的函数让你开始在 BigQuery 中编写函数。
如果您觉得这(以及其他相关材料)有用和/或有趣,请跟我来!
如果你还不是会员,加入 Medium ,每月只需 5 美元,就能从这个活跃、充满活力和激情的数据人社区获得无限的故事。也有很多其他人,但是如果你对数据感兴趣,那么这里就是你要去的地方…
Python 断点分析入门
数据分析
一个现成的教程,比较 Python 中断点分析的 breakes 和 Jenkspy 库
作者图片
在处理时间序列时,识别断点非常重要。事实上,在执行预测时,数据中断点的存在可能会导致错误和模型不稳定。
断点是数据中的结构变化,如异常或预期事件。
存在许多识别断点的技术。一般来说,这些技术可以分为两类:
- 检测 —检测一个或多个断点
- 测试 —给定一个点,检查它是否是断点。这一类技术包括著名的周试。
在这个简短的教程中,我将重点放在第一类断点上,并比较了两个用于断点分析的 Python 库:ruptures
和jenkspy
。
代码以 Jupyter 笔记本的形式提供,可以从我的 Github 库下载。
加载数据
首先,我加载数据集作为一个pandas
数据帧。作为数据集,我利用了从 2015 年到 2020 年的观众趋势。Giallozafferano 是一个非常著名的意大利美食博客。数据是从一个分析意大利互联网使用的意大利网站 Audiweb 中提取的,然后通过我的一个学生开发的一个名为 LEX 的软件进行加工。LEX 是一个非常有用的软件,它可以将微软 Excel 中的多个文件,按日期划分,转换成一个 CSV 文件。如果你想了解这个软件,请给我留言:)
import pandas as pddf = pd.read_csv('GialloZafferano.csv')
df.head()
作者图片
现在我把数据帧转换成时间序列。这可以分三步完成:
- 将
data
字段转换为日期时间 - 将日期列设置为时间序列的索引
- 将该列值分配给一个名为
ts
的新变量。
df['date'] = pd.to_datetime(df['date'])
df.set_index(df['date'], inplace = True)
ts = df['audience']
我画出了时间序列。我开发了matplotlib
库。
作者图片
看这个图表,我注意到有三个主要的转折点。因此,我决定寻找 3 个突破口。
作者图片
n_breaks = 3
我准备数据作为测试库的输入。我把时间序列转换成数组。
import numpy as npy = np.array(ts.tolist())
断裂
第一个断点检测库是breaks,可以通过命令pip install rupture
安装。
中断提供了六种不同的模式来检测断点:Dynp
、KernelCPD
、Pelt
、Binseg
、BottomUp
、Window
。每个模型都必须被构建、训练(通过fit()
函数),然后用于预测。predict()
功能接收待识别断点的数量(减 1)作为输入。在这个例子中,我利用了Dynp
模型,它对应于动态编程。
import ruptures as rptmodel = rpt.Dynp(model="l1")
model.fit(y)
breaks = model.predict(n_bkps=n_breaks-1)
因为ruptures
返回发生结构变化的索引,所以我从原始时间序列ts
中检索日期。
breaks_rpt = []
for i in breaks:
breaks_rpt.append(ts.index[i-1])
breaks_rpt = pd.to_datetime(breaks_rpt)
breaks_rpt
它产生以下输出:
DatetimeIndex(['2016-03-01', '2018-04-01', '2020-11-01'], dtype='datetime64[ns]', freq=None)
现在我绘制结果。
plt.plot(ts, label='data')
plt.title('Audience')
print_legend = True
for i in breaks_rpt:
if print_legend:
plt.axvline(i, color='red',linestyle='dashed', label='breaks')
print_legend = False
else:
plt.axvline(i, color='red',linestyle='dashed')
plt.grid()
plt.legend()
plt.show()
作者图片
詹克斯比
第二个断点检测库是 Jenkspy ,可以通过以下命令安装:pip install jenkspy
。这个库根据 Fisher-Jenks 算法计算数组中的自然断点。
我导入库(import jenkspy
),然后调用jenks_breaks()
函数,该函数接收值数组和要检测的断点数量作为输入。作为输出,该函数返回与所标识的中断相对应的值。提醒断裂,相反,返回断裂索引。
import jenkspybreaks = jenkspy.jenks_breaks(y, nb_class=n_breaks-1)
我通过循环遍历breaks
数组来计算 breaks 索引。
breaks_jkp = []
for v in breaks:
idx = ts.index[ts == v]
breaks_jkp.append(idx)
breaks_jkp
它产生以下输出:
[DatetimeIndex(['2017-07-01'], dtype='datetime64[ns]', name='date', freq=None),
DatetimeIndex(['2018-04-01'], dtype='datetime64[ns]', name='date', freq=None),
DatetimeIndex(['2020-04-01'], dtype='datetime64[ns]', name='date', freq=None)]
我画出结果。
plt.plot(ts, label='data')
plt.title('Audience')
print_legend = True
for i in breaks_jkp:
if print_legend:
plt.axvline(i, color='red',linestyle='dashed', label='breaks')
print_legend = False
else:
plt.axvline(i, color='red',linestyle='dashed')
plt.grid()
plt.legend()
plt.show()
作者图片
比较结果
最后,我比较了两个库产生的结果。我进行了视觉对比。
我计算了理想情况,两种算法产生相同的结果。
x_ideal = ts.index
y_ideal = x_ideal
我通过散点图来比较这两种算法。理想情况用红色标出。我注意到只有一个普通的断裂(穿过理想情况的那个)。第一个断点很不一样,第三个断点很像。
plt.figure(figsize=(5, 5), dpi=80)
plt.scatter(breaks_rpt,breaks_jkp)
plt.xlabel('Ruptures')
plt.ylabel('Jenkspy')
plt.title('Jenskpy VS Ruptures')
plt.xlim(ts.index[0], ts.index[len(ts)-1])
plt.ylim(ts.index[0], ts.index[len(ts)-1])
plt.plot(x_ideal,y_ideal, color='r', linestyle='dashed')
plt.grid()
plt.show()
作者图片
摘要
在本教程中,我用两个库说明了如何在 Python 中检测断点:ruptures
和jenkspy
。这两个库产生不同的输出。将输出与可视断点进行比较,在这个特定示例中,Jenkspy 算法似乎优于动态编程。
如果你想了解我的研究和其他活动的最新情况,你可以在 Twitter 、 Youtube 和 Github 上关注我。
相关文章
</4-different-approaches-for-time-series-analysis-7e2364fadcb9>
C# DataFrame 和 XPlot 入门。Plotly
探索用 C#在 Jupyter 笔记本上使用数据框和绘制图表的方法
艾萨克·史密斯在 Unsplash 上拍摄的照片
原文可以在路孚特开发者社区上找到。
对于 Python 编程语言来说,Pandas 是一个高效且流行的数据分析工具,尤其是它的 Dataframe,用于操作和显示数据。为了。NET 编程语言,我们可以使用微软的 Deedle 或。Data.Analysis 包在 NuGet 中可用,它还提供了一个 DataFrame 类,用于操作、转换和显示数据。
这个例子主要针对微软。Data.Analysis 包,演示 Jupyter Notebook 中 DataFrame 类的一些基本特性。
它还使用了 XPlot。Plotly 包是 F#数据可视化包,用于绘制数据帧中数据的图表。源代码可在 GitHub 上获得。
先决条件
要运行本文中的示例,请参考此使用。NET Core in Jupyter Notebook 文章,用于设置 Jupyter Notebook 以支持。NET 编程语言。
安装软件包
微软。数据分析包在 NuGet 中可用,因此可以使用 dot net-interactive# r魔法命令从 Nuget 安装该包。
运行下面的命令来安装微软。数据分析包版本 0.4.0。
#r "nuget:Microsoft.Data.Analysis,0.4.0"
引用名称空间
本文使用了以下四个包中的类。因此,它使用 using 语句来引用那些包。
- XPlot。plotly:F #和的跨平台数据可视化包。NET 编程语言
- 微软。Data.Analysis :一个易于使用的高性能数据分析和转换库
- 系统。Linq :支持使用语言集成查询的查询的类和接口
- Microsoft.AspNetCore.Html:操纵 HTML 内容的类型
using XPlot.Plotly;
using Microsoft.Data.Analysis;
using System.Linq;
using Microsoft.AspNetCore.Html;
将数据帧呈现为 HTML 表格
默认情况下,DataFrame 呈现为具有一行和两列(列和行)的 HTML 表格。
这可以通过注册数据帧的自定义格式化程序来覆盖。以下代码为数据帧和数据帧行注册自定义格式化程序,以在 HTML 表格中呈现数据。
它只显示前 100 行。这可以通过修改 take 变量的值来改变。
Formatter<DataFrame>.Register((df, writer) =>
{
var headers = new List<IHtmlContent>();
headers.Add(th(i("index")));
headers.AddRange(df.Columns.Select(c => (IHtmlContent) th(c.Name)));
var rows = new List<List<IHtmlContent>>();
var take = 100;
for (var i = 0; i < Math.Min(take, df.Rows.Count); i++)
{
var cells = new List<IHtmlContent>();
cells.Add(td(i));
foreach (var obj in df.Rows[i])
{
cells.Add(td(obj));
}
rows.Add(cells);
}
var t = table(
thead(
headers),
tbody(
rows.Select(
r => tr(r))));
writer.Write(t);
writer.Write(df.Rows.Count + " x "+df.Columns.Count);
}, "text/html");
Formatter<DataFrameRow>.Register((dataFrameRow, writer) =>
{
var cells = new List<IHtmlContent>();
cells.Add(td(i));
foreach (var obj in dataFrameRow)
{
cells.Add(td(obj));
}
var t = table(
tbody(
cells));
writer.Write(t);
}, "text/html");
创建数据框架
数据帧列
可以通过将 DataFrameColumn 对象的列表传递给 DataFrame 的构造函数来创建 DataFrame。
public data frame(params data frame column[]列);
public data frame(IEnumerable列);
以下代码创建了一个有 200 行 2 列的 DataFrame。第一列包含日期,第二列包含随机整数。它调用PrimitiveDataFrameColumn构造函数来创建 DataFrameColumn 实例。
var start = new DateTime(2009,1,1);
Random rand = new Random();
var numDataPoint = 200;PrimitiveDataFrameColumn<DateTime> date = new PrimitiveDataFrameColumn<DateTime>("Date",
Enumerable.Range(0, numDataPoint)
.Select(offset => start.AddDays(offset))
.ToList());
PrimitiveDataFrameColumn<int> data = new PrimitiveDataFrameColumn<int>("Data",
Enumerable.Range(0, numDataPoint)
.Select(r => rand.Next(100))
.ToList());
var df = new DataFrame(date, data);
df
CSV 文件
也可以通过调用数据帧从 CSV 文件创建数据帧。LoadCsv 静态方法。
下面的代码从 ohcldata.csv 文件创建一个 DataFrame。这个文件是从 5.30 下载的。示例—基本 OHLC(开盘价、最高价、最低价、收盘价)金融阴谋网站。该文件包含每日开盘、盘高、盘低、收盘的财务数据。
var df1 = DataFrame.LoadCsv("ohlcdata.csv");
df1
然后,可以使用 Info 方法生成数据帧中每一列的摘要。
df1.Info()
访问数据框架
通过索引访问数据
行索引和列索引可用于访问数据帧中的特定数据。索引是从零开始的编号。
下面的代码访问第一行和第二列中的数据。
df[0,1]
之后,可以给数据帧分配一个新值。
下面的代码将第一行和第二列的数据增加 10。
df[0,1] = int.Parse(df[0,1].ToString()) + 10;
df.Head(10)
访问行数据
可以使用行索引来访问整行。索引是从零开始的编号。
下面的代码访问数据帧中的第十行。
df1.Rows[9]
列索引也可用于访问行中的特定列。
下面的代码访问第十行的第四列。
df1.Rows[9][5]
然后,新值也可以分配给该列。
下面的代码将 50000000 分配给第六列。
df1.Rows[9][5] = 50000000f;
df1.Head(10)
访问列数据
可以使用列名或索引来访问整列。索引是从零开始的编号。
下面的代码访问 DataFrame 中名为 Data 的列(第二列)。
//df.Columns["Data"] or df.Columns[1]
df.Columns["Data"]
可以使用 DataFrame 的重载运算符来更改列中的数据。
下面的代码将该列中的所有数据增加 10。
df.Columns["Data"]= df.Columns["Data"]+10;
df
插入数据
添加新列
数据帧在数据帧列集合中维护一个数据帧列的列表。可以向 DataFrameColumnCollection 中添加新列。
下面的代码向 DataFrame 添加了一个新的整数列。
df.Columns.Add(new PrimitiveDataFrameColumn<int>("Data1", df.Rows.Count()));
df
新列中的数据被设置为空。
下面的代码用 10 填充新列(Data1)中的空值。
df.Columns["Data1"].FillNulls(10, true);
df
追加新行
Append 方法可用于向数据帧追加新行。
以下代码创建一个 KeyValuePair 实例列表,然后将其添加到 DataFrame 中。
df.Append(new List<KeyValuePair<string, object>>() {
new KeyValuePair<string, object>("Date", DateTime.Now),
new KeyValuePair<string, object>("Data", 12),
new KeyValuePair<string, object>("Data1", 50)
}, true);
df.Tail(10)
操纵数据帧
对数据帧进行排序
OrderBy 或 OrderByDescending 方法可用于按指定列对数据帧进行排序。
以下代码根据名为 Data 的列对 DataFrame 进行排序。
df.OrderBy("Data")
对数据帧进行分组
GroupBy 方法可用于根据列中的唯一值对数据帧的行进行分组。
以下代码按名为 Data 的列对 DataFrame 进行分组,然后计算每组中值的数量。
var groupByData = df.GroupBy("Data");
groupByData.Count().OrderBy("Data")
过滤数据帧
Filter 方法可用于通过行索引或布尔值过滤数据帧。
以下代码通过返回名为 Data 的列中的值大于 50 的行来过滤 DataFrame。
df.Filter(df.Columns["Data"].ElementwiseGreaterThan(50))
合并数据帧
Merge 方法可用于通过数据库风格的连接合并两个数据帧。
以下代码通过使用两个数据帧中包含的日期列来联接两个数据帧。首先,它将 df1 的日期列中的数据类型从字符串类型转换为数据时间类型。然后,它调用合并方法来连接数据帧。
df1.Columns["Date"] = new PrimitiveDataFrameColumn<DateTime>("Date",
df1.Columns["Date"]
.Cast<object>()
.ToList()
.Select(x => DateTime.ParseExact(x.ToString(), "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture))
.Cast<DateTime>());df1.Merge<DateTime>(df, "Date", "Date")
使用 XPlot 绘制图表。普罗蒂
XPlot。Ploty 是用于 F#和的跨平台数据可视化包。NET 编程语言。它基于流行的 JavaScript 图表库 Plotly 。
以下示例演示了如何使用 XPlot。使用数据框中的数据绘制图表。
折线图
下面的代码从 DataFrame 中的打开列绘制了一个折线图。
var chart1 = Chart.Plot(
new Graph.Scatter
{
x = df1.Columns["Date"],
y = df1.Columns["Open"],
mode = "lines+markers"
}
);
var chart1_layout = new Layout.Layout{
title="Open Price",
xaxis =new Graph.Xaxis{
title = "Date"
},
yaxis =new Graph.Yaxis{
title = "Price (USD)"
}
};
chart1.WithLayout(chart1_layout);
chart1
多线折线图
以下代码在折线图中绘制了打开和关闭列。
var chart2_list = new List<Graph.Scatter>
{
new Graph.Scatter
{
x = df1.Columns["Date"],
y = df1.Columns["Open"],
name="Open",
mode = "lines"
},
new Graph.Scatter
{
x = df1.Columns["Date"],
y = df1.Columns["Close"],
name="Close",
mode = "lines"
}
};
var chart2 = Chart.Plot(
chart2_list
);
var chart2_layout = new Layout.Layout{
title="Open and Close Price",
xaxis =new Graph.Xaxis{
title = "Date"
},
yaxis =new Graph.Yaxis{
title = "Price (USD)"
}
};
chart2.WithLayout(chart2_layout);
chart2
条形图
以下代码绘制了 DataFrame 中卷列的条形图。
var chart3 = Chart.Plot(new Graph.Bar
{
x = df1.Columns["Date"],
y = df1.Columns["Volume"],
marker = new Graph.Marker{color = "rgb(0, 0, 109)"}
}
);
var chart3_layout = new Layout.Layout{
title="Volume",
xaxis =new Graph.Xaxis{
title = "Date"
},
yaxis =new Graph.Yaxis{
title = "Unit"
}
};
chart3.WithLayout(chart3_layout);
chart3
蜡烛图
下面的代码从 DataFrame 中的打开、高、低、关闭列绘制一个蜡烛图。
var chart4 = Chart.Candlestick(df1.OrderBy("Date").Rows.Select(row => new Tuple<string, double, double, double, double>(
((DateTime)row[0]).ToString("yyyy-MM-dd"),
double.Parse(row[1].ToString()),
double.Parse(row[2].ToString()),
double.Parse(row[3].ToString()),
double.Parse(row[4].ToString())
)));
chart4.WithLayout(new Layout.Layout{
title="OHLC",
xaxis =new Graph.Xaxis{
title = "Date"
},
yaxis =new Graph.Yaxis{
title = "Price (USD)"
}
});
chart4
结论
Dotnet interactive 允许精通 Dotnet 编程语言的开发人员和数据科学家在 Jupyter Notebook 上运行 C#或 F#应用程序。不可否认的是,Jupyter Notebook 上运行的大部分应用都是使用 Dataframe 来操作数据,使用图表库来可视化数据。这篇文章介绍了微软的。数据分析和 XPlot。Plotly 包为 dotnet interactive 提供 DataFrame 类和图表库。
本文的第一部分演示了 DataFrame 类的基本用法,比如创建和数据操作。虽然与 Pandas python 库相比,DataFrame 类仍然缺少一些基本的特性,例如连接和标准计算,但我希望这在未来的版本中会有所改进。本文的最后一部分展示了如何使用 XPlot。Plotly 软件包为数据框中的数据创建折线图、条形图和蜡烛图。因为这个库是基于流行的 JavaScript 图表库 Plotly 的,所以输出看起来很棒。
参考
- Phplot.sourceforge.net,荷兰国际发展署 5.30。示例-基本 OHLC(开盘、盘高、盘低、收盘)财务图。[在线]见:http://phplot.sourceforge.net/phplotdocs/ex-ohlcbasic.html[2021 年 5 月 6 日访问]。
- blue mountain capital . github . io . n . d . Deedle:用于. NET 的探索性数据库。[在线]可在:https://bluemountaincapital.github.io/Deedle/[2021 年 5 月 6 日访问]。
- Govindarajan,p . 2019。DataFrame |简介。网络博客。【在线】。网络博客。可从以下网址获取:【https://dev blogs . Microsoft . com/dotnet/an-introduction-to-data frame/【2021 年 5 月 6 日获取】。
- 新泽西州塞杰拉,2020 年。dotnet/interactive:魔法命令。[在线] GitHub。可在:https://github . com/dot net/interactive/blob/main/docs/magic-commands . MD【2021 年 5 月 6 日访问】。
- Winnington,e,2019。Eric winning ton——c# Jupyter 笔记本的提示和技巧。[在线]ewin ington . github . io .可在:【https://ewinnington.github.io/posts/jupyter-tips-csharp【2021 年 5 月 6 日访问】。
- Fslab.org . n . d . XPlot—F #数据可视化包。[在线]可在:https://fslab.org/XPlot/index.html[2021 年 5 月 6 日访问]。
- Phuriphanvichai,j .,2021。使用。Jupyter 笔记本中的 NET Core |路孚特开发者。[在线]Developers.refinitiv.com。可从以下网址获取:https://developers . refinitiv . com/en/article-catalog/article/using-net-core-in-jupyter-notebook.html【2021 年 5 月 10 日获取】。
Comet ML 入门
机器学习
机器学习流行实验平台概述,并附有实例。
作者图片
Comet ML 是一个实验平台,它允许测试机器学习项目,从开始到最后的监控。网络上还有很多其他类似的平台,包括 Neptune.ai 、 Guild.ai 、神圣等等。
Comet ML 可以很容易地与最流行的机器学习库集成,包括 scikit-learn、Pytorch、Tensorflow、Keras 等等。实验可以用 Python、Javascript、Java、R、REST APIs 编写。
在本文中,我主要关注 Python。
文章组织如下:
- 彗星 ML 概述
- 使用 Comet ML
- 用法示例
1 彗星 ML 概述
Comet ML 是一个允许跟踪实验的在线平台。Comet ML 的主要优点是我可以轻松地构建一个报告仪表板和一个监控系统。
Comet ML 提供了以下特性:
- 比较实验:我可以很容易地为同一个项目构建不同的实验,并比较结果,在度量、系统度量、参数等方面;
- 监控模型:我可以从早期阶段到生产阶段监控模型。这可以通过警报和调试策略来实现;
- 与其他人协作:我可以与其他人共享我的工作区项目;
- 构建报告和面板:从我的实验结果开始,我可以轻松地构建报告和仪表板;
- 保持我的项目公开或使其公开。
2 使用 Comet ML
一旦我进入 Comet ML Web 站点,我就可以创建一个免费帐户。然后,我登录到平台,并通过单击相对右上角的按钮创建一个新项目。我用需要的信息填写表格:
作者图片
当我单击“创建”按钮时,会出现一个空的控制面板。
作者图片
我可以添加一个新的实验,通过点击页面右上角的按钮(+Add)。我从下拉菜单中选择实验。
作者图片
该平台为实验生成了一个新的 API,可以在我的 Python 代码中使用:
*# import comet_ml at the top of your file*
from comet_ml import Experiment
*# Create an experiment with your api key*
experiment = **Experiment**(
api_key="PUT HERE MY API KEY",
project_name="decisiontree",
workspace="PUT HERE MY ACCOUNT NAME",
)
现在,我需要在我的本地计算机上安装comet_ml
Python 包:
pip3 install comet_ml
然后我就可以像往常一样开始编码了。
2.1 实验课概述
实验类是本地代码与 Comet ML 的接口。它定义了许多方法,这些方法在 Comet 官方文档中有描述。
在这里,我描述一些常见的方法:
log_metric()
和log_metrics()
—向实验注册一个或多个评估度量,例如准确度、精确度和召回率;log_confusion_matrix()
—为实验注册一个混淆矩阵;log_figure()
—将一个图形(如pyplot
)注册到实验中,并保存为 SVG 图像;display()
—在 Jupyter 中创建交互环境,将 Comet ML 仪表盘显示为一个单元格的输出;end()
—如果实验在 Jupyter 中运行,该方法指定实验结束。
2.2 实验仪表板
一旦实验完成,Comet ML 提供了一个仪表板,在这里我可以看到我在代码中跟踪的所有度量、图形、参数等等。
评估指标是自动绘制的。例如,如果一个实验是在多个步骤上运行的,我可以很容易地画出图表,显示度量与步骤数的关系。
作者图片
在实验仪表板的左侧,可以选择许多选项,包括但不限于:
- 面板 —最终仪表板,可用作最终用户的报告;
- 指标 —包含所有指标及其值的表格;
- 系统指标 —所有系统指标的可视化表示,包括内存使用情况、CPU 利用率。
3 用法示例
作为 Comet ML 的一个实际用例,我利用了由 Kaggle 提供的心脏病发作数据集。
首先,我通过指定项目名称和工作空间(我的帐户名称)来设置实验。
from comet_ml import Experiment
experiment = **Experiment**(
api_key="PUT HERE MY API KEY",
project_name="decisiontree",
workspace="PUT HERE MY ACCOUNT NAME",
)
现在我可以照常工作了。我将数据集作为一个pandas
数据帧加载。
import pandas as pddf = pd.read_csv('source/heart.csv')
df.head()
作者图片
我定义特征列。
cols = []
for col in df.columns:
if col != 'output':
cols.append(col)
我定义输入和输出变量:
X = df[cols]
y = df['output']
我通过一个MinMaxScaler
缩放所有的输入特征
from sklearn.preprocessing import MinMaxScalerscaler = MinMaxScaler()
X_scaled = scaler.fit_transform(X)
我在训练集和测试集中设置了数据集。
from sklearn.model_selection import train_test_split
random_state = 42
X_train, X_test, y_train, y_test = train_test_split(X_scaled,y, random_state=random_state)
我利用一个DecisionTreeClassifier
作为模型。我用训练集中包含的渐进数量的样本来拟合它,并预测测试集中所有样本的输出类。我还为每个步骤构建了一个分类报告。
我通过名为log_metrics()
的 Comet 实验函数记录classification_report()
函数返回的指标。我还通过experiment.log_confusion_matrix()
功能记录了混乱矩阵。
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import classification_report
import numpy as npmodel = DecisionTreeClassifier(random_state=random_state, max_depth=2)
min_samples = 5
target_names = ["class 0", "class 1"]for step in range(min_samples, len(X_train)):
model.fit(X_train[0:step], y_train[0:step])
y_pred = model.predict(X_test)
pred_proba = np.max(model.predict_proba(X_test), axis=1)
report = classification_report(y_test, y_pred, target_names=target_names, output_dict=True)
for label, metric in report.items():
try:
experiment.log_metrics(metric, prefix=label, step=step)except:
experiment.log_metric(label, metric,step=i)
experiment.log_confusion_matrix(y_test.tolist(), y_pred.tolist())
我用 Jupyter 展示了实验结果。
experiment.display(tab="confusion-matrices")
下图显示了生成的仪表板的摘录:
作者图片
我结束了实验。
experiment.end()
摘要
恭喜你!您已经学习了如何在机器学习的实验平台 Comet ML 中配置和运行实验。
Comet ML 可以用来运行更复杂的实验。请继续关注更多提示😃
如果你已经走了这么远来阅读,对我来说今天已经很多了。谢谢!你可以在这篇文章中读到更多关于我的信息。
你想了解更多关于彗星的知识吗?
你可以看看我的书 Comet for Data Science ,由 Packt 出版,由 Comet 首席执行官 Gideon Mendels 作序!
相关文章
Cython 入门:如何在 Python 中每秒执行超过 17 亿次计算
结合 Python 的易用性和 C 的速度
Cython 将为你的程序添加一个加力燃烧室(图片由 Oscar Sutton 在 Unsplash 上提供)
Python 的主要优点是对开发人员非常友好,并且易于掌握。然而,这些设计选择有一个主要的缺点;它们导致 Python 的执行速度比其他一些语言慢得多。这篇文章将告诉你如何既吃蛋糕又拥有它。我们将消除 Python 代码中的瓶颈,并使用 Cython 极大地加快速度。在继续弄清楚我们正在试图解决的问题之前,我强烈推荐阅读这篇文章。Cython 将帮助我们:
- 使用类似 Python 的语法编写代码,然后 Cython 将使用这些代码生成 C 代码。我们就不用自己用 C 语言写了
- 编译 C 代码并打包成我们可以导入的 Python 模块(就像
import time
) - 将我们程序的执行速度提高了 70 倍以上
- 向同事吹嘘我们超快的代码
我将这篇文章分成 4 个部分:首先,我们在第一部分中安装依赖项和设置。然后,在B 部分中,我们只关注让 Cython 代码运行 Python。完成后,我们使用一个方便的内置工具来优化 C 部分的 Cython 代码,这个工具会告诉你代码中的瓶颈在哪里。然后,在D 部分中,我们将通过多重处理我们的模块来挤出最后一点速度,导致每秒超过 17 亿次计算!
我们来码!
通过使用 Cython 创建一个 Python 模块并对生成的函数进行多重处理,我们将执行速度从 2.5 万 e/ms 提高到了 175 万 e/ms。速度提高了 70 倍!
在开始之前
创建一个 Cython 包有一些巨大的好处,但是它也比常规的 Python 编程需要更多的努力。在把你的代码的最后一行变成 Cythonizing 之前,想想下面的内容。
- 确保你的代码因为正确的原因而变慢。我们无法编写等待速度更快的代码。我推荐先浏览一下 这篇文章 ,因为它解释了为什么 Python 很慢,它是如何工作的,以及如何绕过某些瓶颈。通过这种方式,你会更加理解 Cython 是如何解决我们速度慢的一个非常好的解决方案。
- 并发性是问题所在吗?
你的问题可以通过 使用线程 (比如等待一个 API)来解决吗?也许 在多个 CPU 上并行运行代码 通过多处理帮助你提高速度? - 你是一个优秀的 C 程序员还是仅仅对 Python 和 C 如何协同工作感兴趣?查看 这篇文章 关于 Python 模块是如何用 C 语言编写的(Python 如何使用 C 代码)。
- 确保使用一个 虚拟环境 。Cython 不要求这样做,但这是最佳实践。
A 部分—安装和设置
安装非常容易。
pip istall Cython
为了展示 Cython 如何加快 CPU 密集型任务的速度,我们将使用一个简单的例子:我们将 Cython 化一个函数,该函数计算给定范围内素数的数量。这方面的 Python 代码如下所示:
请注意,这几乎不是计算素数的最有效的方法,但现在这并不重要。我们只是想要一个计算量很大的函数。
B 部分—创建、打包和导入
首先,我们将创建一个非常简单的 Cython 函数,它与我们用 Python 编写的函数非常相似。本部分的目标是:
- 创建函数
- 在 Python 模块中编译和打包 C 代码
- 导入并使用我们的函数。
接下来,我们将优化函数,以实现令人惊叹的速度。
1.创建 Cython 函数
让我们创建一个名为primecounter.pyx
的新文件:
- 将前一部分的
prime_count_vanilla_range
函数复制到文件中 - 将我们刚刚粘贴的函数重命名为
prime_counter_cy
。
现在,我们将只在 Cython 中运行 Python 代码。这是可能的,因为 Cython 是 Python 的超集;在 Python 中可以做的任何事情,在 Cython 中都可以做。
仅仅复制函数应该已经提供了很好的加速,因为代码现在已经编译好了。然而,在我们检查之前,我们必须使用一个模块将代码放入 Python。
2.编译并打包成 Python 包
下一步是指示 Cython 获取 pyx 文件,将其编译成 C,并将代码填充到 Python 模块中,我们可以导入并在 Python 代码中使用该模块。为此,我们需要一个简单的setup.py
脚本来定义我们想要打包什么以及如何打包。看起来是这样的:
您可能熟悉
*setup.py*
脚本:在创建自己的 Python 包时会用到它。更多关于创建自己的包 这里(公有包) 和 这里(私有包) 。
我们简单地定义一个扩展列表,并将其传递给setup
函数。在Extension
中,我们给我们的模块命名。这样我们可以import primes
然后primes.prime_counter_cy(0, 1000)
晚点。首先,我们将创建并安装模块。下面的代码类似于pip install primes
:
python setup.py build_ext --inplace
您也可以使用 CythonBuilder 来编译、构建和打包您的 Cython 代码;查看 此处 。
故障排除 Cython 会将 pyx 编译成一个 C 文件,我们会将它包含在模块中。对于这个编译过程,它需要一个编译器。如果你收到一条类似Microsoft Visual C++ 14.0 or greater is required
的消息,这意味着你没有编译器。你可以通过安装 C++构建工具来解决这个问题,你可以在这里下载。
3.导入和使用我们的函数
既然我们的模块已经编译、打包和安装,我们就可以轻松地导入和使用它了:
import primes
print(primes.prime_counter_cy(0, 1000))
# >> will correctly print out 168
当我们对 Python 函数和 Cython 函数计时时,我们已经看到了很好的加速效果:
Finding primes between 0 and 1000
Total number of evaluations required = 78 thousand
[py] 2.92ms (25k per ms)
[cy] 1.58ms (42k per ms)
尽管我们只是复制了这个函数,没有花一秒钟去优化它,但它仍然更快,因为代码是编译过的。
请注意,求值次数表示函数需要比较多少个数才能找到该范围内的所有素数。它们由多个计算组成,这使得这种加速更令人印象深刻。点击查看计算方法。
现在有趣的部分开始了:让我们开始优化,看看我们能从我们的机器中挤出多少速度!
我们的代码已经打包好,可以进行调整了(图片由 Jackie Zhao 在 Unsplash 上提供)
C 部分—优化我们的 Cython 功能
我们将调整 pyx 文件中的函数来加速它。我们先看看结果,这样才能过一遍。
我们为变量和函数本身添加了类型。许多这些附加功能使 C 能够编译我们的程序,这样我们就不会被 Python 解释器所困扰。查看 这篇文章 以获得更多关于解释器为什么降低执行速度以及如何提高执行速度的信息(剧透:编写 Cython 模块就是其中之一!)
当 Cython 中的变量没有被类型化时,我们回到 Python 处理变量的方式;用解释器检查它们,并将它们存储在一个 PyObject 中(再次查看文章)。这非常慢,所以通过输入变量,我们让 C 来处理它们,这非常快。
添加类型
在第 1 行中,我们将prime_counter_cy
定义为 cpdef 类型的函数。这意味着 Python 和 C 都可以访问该函数。在第一行我们写下int range_from
。这样编译器就知道 range_from 的数据类型是一个整数。因为我们知道哪些数据值得期待,所以我们避免了许多检查。第 3 行也是如此,我们定义了一个名为 prime_count 的整数。在下面两行中,我们定义了num
和divnum
。这两个整数的特别之处在于它们还没有值,它们的值只在第 7 行和第 8 行被设置。
仅仅是增加类型就大大提高了性能。看看这个:
Finding primes between 0 and 50k
Total number of evaluations required = 121 million
[py] 4539ms ( 27k /ms)
[cy] 2965ms ( 41k /ms)
[cy+types] 265ms (458k /ms)
我们从 4.5 秒多一点到四分之一秒。这只是增加了一些类型,速度提高了 17 倍。
使用注释进一步优化
我们所有的变量都被定义了。如何才能进一步优化?还记得setup.py
吗?在第 8 行(见上),我们用annotate=True
调用了cythonize
函数。这将在 pyx 文件所在的目录下创建一个 HTML 文件。
当我们在浏览器中打开该文件时,我们会看到用黄线标注的代码,黄线表示该代码行与 Python 的接近程度。亮黄色表示它很像 Python(读作:慢),白色表示它更接近 C(快)。这是我们在浏览器中打开primecounter.html
时的样子:
我们在 annotations.html 的两个 Cython 功能(图片由作者提供)
在上图中,你可以看到添加类型对代码的影响。您还可以单击每一行来查看生成的 C 代码。我们点开第 28 行,看看为什么不是全白。
一行代码如何翻译成 C 语言(图片由作者提供)
正如你在上面的图片中看到的,Python 检查了一个 ZeroDivisionError。我不认为这是必要的,因为调用 divnum 的范围从 2 开始。
避免不必要的检查
所以还是进一步优化吧!我们在我们的函数中添加了一个装饰器,告诉编译器避免 ZeroDivisionError-check。只有当你非常确定你的代码时才这样做,因为避免检查意味着你的程序失败的额外风险:
您可以应用许多这种所谓的编译器指令。当涉及到循环时,它们中的许多都很有趣。点击这里阅读更多关于这些编译器指令的内容。
查看我们的注释:
请注意,第 44 行现在完全是白色的(图片由作者提供)
Finding primes between 0 and 50k
Total number of evaluations required = 121 million
[py] 4539ms ( 27k /ms)
[cy] 2965ms ( 41k /ms)
[cy+types] 265ms (458k /ms)
[cy-check] 235ms (517k /ms)
这条小指令进一步缩短了执行时间!
为了提高速度,我们需要更多的工人来完成这项任务
D 部分—更快的速度
所以我们的功能现在已经非常优化了,它几乎完全用机器代码运行。我们怎样才能挤出更多的速度呢?如果你读过这篇文章,你可能会有一个想法。我们的代码仍然在一个 CPU 上运行,而我的笔记本电脑有 12 个 CPU,为什么不用更多呢?
上面的代码创建了一个进程池(同样;阅读 这篇文章 )这将在我所有可用的 CPU 上分配所有任务。在第 3 行中,我们使用一个函数将 start 和 endnumber 除以 workers 的数量。如果我们希望 0 到 100 有 10 个工人,它会产生 0 到 9,10 到 19,20 到 29,等等。
接下来,我们通过将作业提交给 threadpoolexecutor 来创建作业。在最后一条记录中,我们检索每个作业的结果,并对结果求和以获得素数的个数。
值得投资设立吗?
正如 这篇文章 解释的那样,应用多个流程需要一点投资;创建流程需要一段时间。如果用普通函数对我们的新多处理函数进行基准测试,当我们检查前 10k 个数字时,速度甚至更慢:
Finding primes between 0 and 10k
Total number of evaluations required = 5.7 million
[py] 246ms ( 23k /ms)
[cy] 155ms ( 37k /ms)
[cy+types] 14ms (423k /ms)
[cy-check] 12ms (466k /ms)
[cy-mp] 201ms ( 29k /ms)
呀,那一点也不快。让我们看看当我们检查前 50.000 个数字时会发生什么:
finding primes between 0 and 50k
Total number of evaluations required = 121 million
[py] 4761ms ( 25k /ms)
[cy] 3068ms ( 40k /ms)
[cy+types] 304ms (399k /ms)
[cy-check] 239ms (508k /ms)
[cy-mp] 249ms (487k /ms)
请注意,我们并没有通过提高计算速度来弥补设置流程的投资。
最终测试
最后一个测试,我们要找出 0 到 200k 之间的所有素数。注意,我们已经为前两个方法等待了几秒钟。还要注意,增加我们的范围会成倍地增加所需评估的总数。为此,我们只对 Cython 方法进行基准测试:
finding primes between 0 and 200k
Total number of evaluations required = 1.7 billion
[cy+types] 3949ms ( 433k /ms)
[cy-check] 3412ms ( 502k /ms)
[cy-mp] 978ms (1750k /ms)
这里我们看到了我们的结果;我们每毫秒执行175 万次评估。注意实际操作的次数甚至更高!
通过使用 Cython 创建一个 Python 模块并对生成的函数进行多重处理,我们将执行速度从 25k e/ms 提高到了 175 万 e/ms。速度提高了 70 倍!
我们的代码已经从一辆慢车变成了一架高超音速飞机(图片由 NASA 在 Unsplash 上提供)
结论
通过这篇文章,我希望向您展示,您可以用一点 Cython 来扩展您的 Python 代码,以实现令人难以置信的速度提升,将 Python 中编码的简易性与编译 c 的令人难以置信的速度结合起来
我希望一切都像我希望的那样清楚,但如果不是这样,请让我知道我能做些什么来进一步澄清。与此同时,请查看我的其他关于各种编程相关主题的文章,比如:
- Python 为什么这么慢,如何加速
- 自己写 C 扩展加速 Python x100
- Python 中的高级多任务处理:应用线程池和进程池并进行基准测试
- 面向绝对初学者的虚拟环境——什么是虚拟环境,如何创建虚拟环境(+示例)
- 创建并发布自己的 Python 包
- 创建您的定制私有 Python 包,您可以从您的 Git 库 PIP 安装该包
- 使用 FastAPI 用 5 行代码创建一个快速自动记录、可维护且易于使用的 Python API
- 通过简单的升级大大提高您的数据库插入速度
编码快乐!
—迈克
喜欢我正在做的事情吗? 跟我来!
https://mikehuls.medium.com/membership
在不到一小时的时间内开始使用 Twitter API v2 收集数据
使用 Twitter API v2 的搜索查询介绍和使用 Python 的演示。
来源:作者
目录:
简介
社交媒体的无处不在使得各种社交媒体平台作为数据来源越来越受欢迎。随着社交媒体作为数据源的兴起,使用 API 收集数据正在成为许多数据科学角色非常抢手的技能。今天,我们将使用 Twitter API v2 从微博和社交网络服务 Twitter 收集社交媒体帖子。
Twitter 现在每月有近 4 亿活跃用户,这意味着可以收集大量数据,其中大部分是公开的。除此之外,Twitter 开发团队最近从头开始重建了 Twitter API,在 2020 年下半年发布了 Twitter API v2。这个 API 有很好的文档记录,并且易于使用,使得利用这个丰富的数据源比以往任何时候都更容易。
本文介绍了什么是 API,并记录了使用 Twitter API v2 的过程,从获得对 API 的访问,到连接到搜索端点并收集与一些感兴趣的关键字相关的数据。阅读这篇文章不需要熟悉 Twitter API 或任何 API 知识。
什么是 API?
应用程序编程接口(API)是一种软件中介,允许两个应用程序相互通信以访问数据。API 经常用于你在手机上的每一个动作,例如发送私人信息或查看足球比赛的比分。这两者都使用一个 API 来访问和传递信息到您的手机。API 基本上是一个信使,接收你的请求,翻译它们,并返回响应。本质上,开发人员插入 API 来为最终用户访问某些资产。当然,为了确保数据安全,API 只提供应用程序程序员公开的精选数据。API 通常需要 API 密钥来认证请求。API 文档通常包含访问说明和要求的必要信息。很多 API 甚至可以免费使用。通常,开发人员可以遵循现有的 API 文档来构建 URL,以便在浏览器中提取数据。
一个基于 web 的 API,接受客户端的请求并返回数据作为响应。来源:作者
Twitter API
Twitter API 是一个记录良好的 API,它使程序员能够以高级方式访问 Twitter。它可以用来分析,学习,甚至与推文互动。它还允许与直接消息、用户和其他 Twitter 资源进行交互。Twitter 的 API 还允许开发者访问各种用户档案信息,如用户搜索、黑名单、实时推文等等。关于 API 产品、用例以及文档的信息可以在开发者平台上获得。关于 Twitter 开发者政策的细节可以在这里找到。
开发人员可以使用 Twitter 开发的各种 API。这些 API 通过从 Twitter 数据中获取洞察力,使研究人员和公司受益。然而,它也适用于较小规模的项目,如小规模的数据分析,创建机器人,甚至创建可以与 Twitter 交互的全自动系统。在这篇文章中,我们将使用 Twitter API 来提取一些与指定搜索查询相匹配的最近的公共 Tweets。我们将使用的 API 产品跟踪对任何人都是免费的,并且允许每月提取多达 10 万条推文。
访问 Twitter API
在使用 Twitter API 之前,您必须已经拥有一个 Twitter 帐户。然后,它需要申请访问 Twitter API,以便获得凭证。我们将看到的 API 端点是GET/2/tweets/search/recent。这将返回过去七天中与搜索查询相匹配的公共推文,并可供获准将 Twitter API 与标准产品跟踪或任何其他产品跟踪一起使用的用户使用。
出于本文的目的,我们将使用最近的搜索端点,这意味着我们将只需要访问标准产品跟踪。标准产品路线是那些刚刚入门、构建有趣的东西等的默认产品路线。可供选择的产品类别有学术类和商业类,对那些有资格或愿意付费的人来说有更大的能力。
申请标准产品认证并获得必要证书的过程包括首先拥有一个 Twitter 帐户。然后你必须通过填写这个页面上的表格来申请一个开发者账户。请注意,最近搜索端点仅返回最近 7 天内符合搜索条件的 Tweets。一个类似的归档搜索端点 GET /2/tweets/search/all 拥有更强大的功能。它允许用户返回与搜索查询相匹配的公开推文,最早可以追溯到 Twitter 2006 年的第一篇帖子。但是,此端点仅适用于那些已经获得学术研究产品路线批准的用户。学术研究产品跟踪是 Twitter API v2 的一个令人兴奋的新增功能,它允许用户使用最广泛的端点,每个月可以发布多达 1000 万条推文!Twitter API v2 端点的完整列表可在这里获得。可以在这里找到更多关于可用于学术研究的特性的细节。可以在此处检查该产品轨道的合格性。申请学术产品跟踪许可证的过程类似,但申请表更详细,必须经过 Twitter 开发团队的批准。
一旦应用程序被批准,人们最终可以在标准产品跟踪中使用各种 API 端点。要做到这一点,必须打开开发者门户并选择“创建新项目”,填写所需的详细信息,最后给新应用起一个名字。
来源:作者在 Twitter 开发者平台上的应用截图
完成后,您将被导航到密钥和令牌页面。在你命名你的应用程序后,你会收到你的 API 密匙和不记名令牌(隐藏在下面的截图中)。这些是连接到 Twitter API v2 中的端点所必需的。
来源:作者在 Twitter 开发者平台上的应用截图
记下您的 API 密钥、API 密钥和不记名令牌。一旦您离开此页面,您将无法再次看到这些内容。但是,如果您丢失了这些密钥和令牌,仍然可以重新生成它们。这些用于验证使用 Twitter API 的应用程序,并根据端点验证用户。请注意,所有这些密钥都应该像密码一样对待,而不是共享或以明文形式写在您的代码中。
用 Twitter API 发出一个基本请求
现在所有的 API 访问键都应该排序了,剩下的工作就是测试 API 了!这里的第一步是加载您的凭证。一种方法是使用命令提示符(或另一种类似的工具)来传递作为环境变量的不记名令牌和一个 Juptyer 笔记本(可以通过安装 Anaconda 获得)来发出请求和显示响应。首先打开一个命令提示符,将目录更改为您希望保存脚本的位置。在命令提示符下,输入以下命令,传递刚刚由应用程序创建的“不记名令牌”:
set BEARER_TOKEN=YOUR_BEARER_TOKEN
接下来用命令打开 Jupyter 笔记本:
Jupyter Notebook
创建一个新的 Python 3 Jupyter 笔记本文件。接下来,我们需要做的第一件事是导入一些库。
接下来,我们需要建立到 Twitter API 的连接,并访问我们的凭证。为此,我们将创建一个 connect_to_twitter() 函数,从环境变量中检索不记名令牌。在这一步中,我们还传递了用于授权的承载令牌,并返回了将用于访问 API 的头。
现在我们已经准备好使用 API 了!Twitter 最近推出了一个新的#ExtremeWeather 迷你网站【2】。这让我们对 Twitter 上可用的数据洞察有了一个很好的了解。因此,在本例中,我们将提取一些与 Twitter 上的#ExtremeWeather 对话相关的最新推文。为此,我们必须为端点构建适当的 URL 请求以及我们想要传递的参数。
这里 URL 的“最近”部分是端点,查询“ExtremeWeather”是要搜索的关键字。同样,我们可以编写 URL 并分离出查询参数,如下所示:
Twitter API 的响应是以 JavaScript Object Notation (JSON)格式返回的响应数据。响应被有效地读取为 Python 字典,其中的键要么包含数据,要么包含更多的字典。此响应中最上面的两个关键字是“数据”和“元”。推文包含在“数据”中,作为字典列表。Meta 是一个关于相应请求的属性字典,它给出了最老和最新的 tweet ID,结果计数为“next_token”字段,我将在稍后阶段讨论。
{
"data": [
{
"id": "144557134867XXXXXXX",
"text": "Tweet text 1"
},
{
"id": "144557110192XXXXXXX",
"text": "Tweet text 2"
},
...
{
"id": "144555630795XXXXXXX",
"text": "Tweet text 10"
}
],
"meta": {
"newest_id": "144557134867XXXXXXX",
"next_token": "b26v89c19zqg8o3fpds84gm0395pkbbjlh482vwacby4d",
"oldest_id": "144555630795XXXXXXX",
"result_count": 10
}
}
可以使用以下代码将推文制作成数据帧:
如果愿意,我们可以轻松地将其保存为 CSV 格式:
用 Twitter API 修改请求
更改端点提供的查询参数允许我们定制希望发送的请求。端点的 API 参考文档在“查询参数”部分对此进行了详细说明。一组基本的操作符,可以用来修改查询。我们可以修改查询、我们感兴趣的时间窗口的开始和结束时间以及结果的最大数量,我们还可以提取许多附加字段来提供关于 tweet、作者、地点等的更多信息。以下是 15 条包含关键词“ExtremeWeather”的推文,这些推文没有被转发,创建于 2021 年 10 月 12 日(在提出请求的一周内)。
最近的搜索端点可以为每个请求提供最多 max_results=100 条推文,按时间倒序排列。如果匹配的 Tweets 超过“max_results ”,则使用分页标记。通过将先前结果中给出的“下一个 _ 令牌”字段复制并粘贴到“下一个 _ 令牌”字段中来修改请求,而不是如上将其留空,可以检索下一页结果。可以创建一个循环来请求拉推,直到收集了所有匹配的推。请求的数量是有限制的,详情请见这里的。
结论
本文详细介绍了使用 Python 通过最近的搜索端点从 Twitter API v2 收集 Tweets 的一步一步的过程。讨论了从访问 Twitter API、发出基本请求、格式化和保存响应,到最后修改查询参数的各个步骤。这应该使您能够开始使用 Twitter v2 API 进行搜索请求。
如果你觉得这篇文章有帮助,请随意与感兴趣的朋友和同事分享。如果你想联系的话,我在 LinkedIn 和 T2 Twitter 上。
数据收集愉快!
图像来源
所有的图片都是我自己在 diagrams.net制作的或者是我自己在 Twitter 开发者平台上应用的截图。
参考
[1] Statista:截至 2021 年 7 月,全球最受欢迎的社交网络,根据活跃用户数量排名(于 2010 年 4 月 21 日访问)。
[2] 在 Twitter 上可视化全球#ExtremeWeather 对话(访问时间:04–10–21)。
使用 CNN 开始深度学习
实现“Hello World!”卷积神经网络
罗马法师在 Unsplash 上拍摄的照片
近年来在深度学习方面取得的很大一部分进展是由于卷积神经网络或 CNN 的概念。除了图像处理中最琐碎的任务之外,这些网络已经成为事实上的标准。CNN 的基本概念起源于 20 世纪 80 年代,首次应用于图像识别发表于 1989 。像深度学习领域的许多主题一样,巨大的进步伴随着更多的计算能力,一个主要因素是从 2000 年代中期开始使用 GPU 而不是 CPU 进行训练。
我们将查看该领域最重要的论文之一,即 1998 论文“基于梯度的学习应用于文档识别”。由于种种原因,这篇论文在发表 20 多年后仍值得一读。值得注意的是包括 Yann LeCun 和 Joshua Bangio 在内的作者,他们与 Geoffrey Hinton 一起被认为是“深度学习的教父”,并因其在该领域的工作而共同获得了 2018 年图灵奖。
另一个问题是,这篇论文不纯粹是一项研究工作,但那里开发的解决方案已经在商业上应用于 NCR 公司的手写数字识别。由于该论文全面描述了专注于神经网络架构时的工作,我们只需阅读总共 10 节中的第 1 至第 3 节,整篇论文的长度为 46 页,这本身也是值得注意的,远远超过了通常的长度。
这里最相关的问题是,本文中讨论的 LeNet-5 网络通常被认为是 CNN 历史上最相关的网络之一。有时它被称为“你好,世界!”CNN 的。有一些论据支持这一点:
- “LeNet-5 实现”在谷歌上给了你超过 130,000 次点击,其中很多都是相关的。
- 使用当前的库实现基本架构只需几行代码,而不是本文中描述的大量研究工作。
- 你会很快在 MNIST 数据集上得到很好的结果。这还不足以获得当今的最佳论文奖,但可能比从头开始要好得多。
- 根据所使用的超参数,每个时期网络的训练在 CPU 上将花费大约 100 秒,而在 GPU 上将花费仅仅几秒。这给了你合理的时间来试验网络。
另一方面,从论文中紧密地重新实现网络将是非常困难的,因为在实现的时候,作者必须手工做所有的事情。1998 年还没有 GPU,Python 不是人工智能的通用语言,也没有现成的深度学习库。在从头开始做每件事的同时,他们也做了许多优化,这些优化很难用最先进的库来重现。你会发现,使用谷歌的大多数实现只是让网络变得更大,从而在 MNIST 上快速获得类似的好结果。所以这不是简单的“你好,世界!”以获得可比较的结果,但它仍然是一个很好的入门 CNN 的基础。
编码入门
我们甚至不会试图准确地复制这篇论文,但与互联网上的大多数其他实现相反,我们将从一个至少在一些相关参数上遵循这篇论文的版本开始。代码将在 Python 和 Tensorflow 上使用 Keras。使用像 Keras 这样的高级库,网络的代码几乎是微不足道的,这也将使实验变得更容易。
该网络的基本结构在文件第二. b 节中有详细解释。它总共有七层。
- 一个卷积层,有 6 个 5×5 内核,带填充,因此我们实际上有填充的 32×32 图像作为输入,而不是原始的 28×28 MNIST 图像。
- 2x2 池层。这里复制报纸已经开始变得困难,因为你会意识到阅读报纸。为了简单起见,我们使用平均池。
- 具有 16 个 5x5 内核且没有填充的卷积层。这也是本文结构的简化。
- 另一个 2x2 池层使用平均池,再次不是真的。
- 一个有 120 个神经元的全连接层。
- 一个有 84 个神经元的全连接层。
- 一个 softmax 层,最终得到 10 个可能的输出类。虽然这也不同于纸张,但完全连接的层是真实的。
tanh 论文中使用的激活函数和损失函数类似于 MSE 或均方误差。两者都是为论文而优化的,因为它们必须手工编码,而不是像我们一样从高级库中使用它们。对于优化器,我们选择了简单的 SGD 或随机梯度下降。该网络经过 20 个时期的训练,学习率为“前两次为 0.0005,接下来三次为 0.0002,接下来四次为 0.00005,此后为 0.00001”,如论文中明确规定的。
在 Keras 中创建模型只需要几行代码:
model = keras.Sequential(
[
keras.Input(shape=input_shape),
layers.Conv2D(6, kernel_size=(5, 5), padding=’same’, activation=’tanh’),
layers.AveragePooling2D(pool_size=(2, 2)),
layers.Conv2D(16, kernel_size=(5, 5), padding=’valid’, activation=”tanh”),
layers.AveragePooling2D(pool_size=(2, 2)),
layers.Flatten(),
layers.Dense(120, activation=”tanh”),
layers.Dense(84, activation=”tanh”),
layers.Dense(num_classes, activation=”softmax”)
]
)
如果您查看模型摘要并将其与网络的详细描述进行比较,您会发现只有 C1 层、C5 层和 F6 层在可训练参数的数量方面与文章相符。这是因为我们没有尝试复制论文中所做的优化。
Model: “sequential”
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 28, 28, 6) 156
_________________________________________________________________
average_pooling2d (AveragePo (None, 14, 14, 6) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 10, 10, 16) 2416
_________________________________________________________________
average_pooling2d_1 (Average (None, 5, 5, 16) 0
_________________________________________________________________
flatten (Flatten) (None, 400) 0
_________________________________________________________________
dense (Dense) (None, 120) 48120
_________________________________________________________________
dense_1 (Dense) (None, 84) 10164
_________________________________________________________________
dense_2 (Dense) (None, 10) 850
=================================================================
Total params: 61,706
Trainable params: 61,706
Non-trainable params: 0
培训和评分
复制纸张的重大挑战并不仅限于网络架构。下一个要回答的问题是如何构建培训过程。从积极的一面来看,本文中使用的 MNIST 数据集仍然是今天使用的 MNIST 数据集。第三部分有一段有趣而简短的 MNIST 历史。这篇论文很值得一读。
除了损失函数、优化器和学习率之外,我们还必须决定批量大小,以及在训练期间是否以及如何使用交叉验证。如果没有使用批次,即批次大小为 1,则论文中给出的低学习速率结合仅学习 20 个时期才有意义。请注意,只有在使用微批处理的情况下,使用 GPU 才能获得相关的加速,因此训练这些参数需要一些时间。
本文还探讨了训练数据量对网络性能的影响,并明确指出使用了来自 MNIST 的 60,000 幅训练图像。这些都是标准 MNIST 中可用的训练图像。因此,我们不使用交叉验证,即验证分割为 0。
这会产生以下用于训练网络的代码:
lr_list = [0.0005, 0.0005, 0.0002, 0.0002, 0.0002, 0.00005,
0.00005, 0.00005, 0.00005, 0.00001, 0.00001, 0.00001,
0.00001, 0.00001, 0.00001, 0.00001, 0.00001, 0.00001,
0.00001, 0.00001]def calc_lr():
elem = lr_list[0]
del lr_list[0]
return(elem)optimizer = keras.optimizers.SGD(learning_rate=calc_lr)model.compile(loss=”mean_squared_error”, optimizer=optimizer,
metrics=[“accuracy”])model.fit(x_train, y_train, batch_size=1, epochs=20,
validation_split=0.0)
训练网络输出训练集的精度,如果使用交叉验证,则输出验证集的精度。网络的唯一相关度量是测试集上的性能,因为这给出了网络在真实生活数据上如何表现的合理提示。在我的例子中,用这些参数训练网络的结果是训练数据的精度为 0.9257,测试数据的精度为 0.9292。这是一个很好的迹象,表明测试集的准确性更高,并暗示了网络的良好泛化能力。
但是总体来说 93%是一个好的准确率吗?实际上不是。本文在 C 节中比较了 MNIST 分类的几种技术和模型,其中提到的最差的一种具有大约 95%的准确度。本文的一个重要结果是 LeNet-5 在 MNIST 上获得了 99%或更高的准确率。因此,即使在 1998 年,我们要赢得最佳论文奖还有很长的路要走。
获得更好的分数
如前所述,论文中暗示了许多优化,试图复制它们可能至少需要一篇博士论文。所以我们不会走那条路。获得更好结果的更简单的方法是采用 LeNet-5 的基本结构,并在 CNN 中使用当前的最佳实践,而不是 20 多年前。另一个值得考虑的方法是扩大网络,因为使用现有的硬件训练只需要很少的时间。
为了看看什么是可能的,我们采取了一种捷径,使用网络上找到的许多实现方式中的一种,例如,这种方式恰好是我在谷歌搜索中的第一次点击:
https://hackmd.io/@bouteille/S1WvJyqmI
代码比我们的代码稍微复杂一点,可能是因为使用了旧版本的 Keras。我们的选择没有太多不同,实际上网络看起来完全一样。潜在的相关差异有:
- 使用分类交叉熵作为损失函数,而不是均方误差。
- 使用默认的学习率 0.01,而不是纸上的学习率。
- 使用默认批量 32,而不是没有批量,即批量为 1。
- 交叉验证的使用。
在我的例子中,这些简单的调整极大地提高了训练数据和测试数据的准确度,分别为 0.9890 和 0.9870。回到批量大小 1,没有交叉验证,我得到的训练数据精度为 1.0000,这表明过度拟合。但是因为我在测试数据上也得到 0.9888,所以我并不在乎。所以仅仅通过改变损失函数和提高学习率,我们就离最佳论文奖更近了一点,如果我们在 1998 年才交论文的话。
摘要
重新实现LeNet-5 的基本结构很容易,但你不会真的复制论文中的工作。然而,在 MNIST 数据集上,这个有着 20 多年历史的网络的性能仍然令人印象深刻。使用好的超参数至关重要!虽然使用交叉熵进行分类可能被认为是的最佳实践,而不是使用 MSE 进行回归,但是还有更多选择需要决定。在 MNIST 上使用 CNNs】已经做得如此频繁,以至于最大的精确度是众所周知的。
一种替代方案是时尚 MNIST,它可以取代经典 MNIST,而不需要对网络进行任何改变,因为图像分辨率是相同的。它也有 10 个类,但目标是对时尚文章进行分类,而不是手写数字。为了进一步试验“你好,世界!”这是一个更有趣的数据集。
Elasticsearch 查询 DSL 入门
使用 Python Elasticsearch 客户端,用特定领域语言编写 Elasticsearch 查询的实践指南
在这篇文章中,我将介绍弹性搜索中查询的基础知识。我们将看看如何在 Elasticsearch 领域特定语言 (DSL)中构建查询(例如,过滤器与查询上下文,以及相关性评分),并在 Python Elasticsearch 客户端中应用它们。(而且,如果 DSL 让您头晕目眩,请跳到本文的最后一节,在这里我们将介绍针对 es 运行 SQL 查询的基础知识)。这篇博文中使用的所有代码都可以在 this GitHub repo 中找到。
入门指南
对于这篇文章,我假设你熟悉 ES 的基础知识。我还假设您已经提供并部署了自己的 Elasticsearch 集群(要么“从头开始”,要么使用托管服务),并且您已经将数据写入了索引。
要快速了解 ES 的基础知识以及如何使用 Python 提供集群和设置索引的说明,请查看我之前的文章 使用 Python 创建和管理弹性搜索索引 。
对于下面的例子,我将使用我在之前的文章中建立的neflix_movies
索引。这个指数是根据 Kaggle 上的 7787 场网飞演出的数据构建的。原始数据是 CSV 格式的,包含网飞上可用的电影和电视剧的信息,包括元数据,如上映日期、片名和演员。我们的索引的映射定义如下:
这种映射可以进一步改进,并没有针对磁盘使用进行优化,也没有针对搜索速度进行调整。然而,对于我们将在下面运行的查询来说,这已经足够了。
如果你想学习如何创建更好的针对磁盘使用优化的 ES 索引,请查看我之前关于 优化弹性搜索中的磁盘使用 的帖子。
[## 优化弹性搜索中的磁盘使用
towardsdatascience.com](/optimising-disk-usage-in-elasticsearch-d7b4238808f7)
DSL 快速入门
在我们开始这篇博文的实践部分之前,让我们回顾一下从 Elasticsearch 查询数据的一些基础知识。ES search API 接受使用基于 JSON 的 Elasticsearch 领域特定语言(DSL) 的查询。ES 文档将 DSL 描述为查询的抽象语法树(AST ),由两种类型的子句组成:
- 叶查询子句,查找特定字段中的特定值(如
match
或range
);和 - 复合查询子句用于逻辑组合多个查询(如多叶或复合查询)或改变这些查询的行为。
当你运行一个针对你的索引(或多个索引)的查询时,ES 通过一个代表匹配质量的相关性分数(一个浮点值)(_score
字段显示其每次“命中”的值)。一个 ES 查询有一个查询和一个过滤上下文。过滤器上下文——顾名思义——简单地过滤掉不符合语法条件的文档。然而,与 bool 上下文中的匹配不同,它不会影响相关性分数。
让我们来看一个简单的查询示例,它有一个查询和一个过滤器上下文。下面的例子过滤发行年份(使用一个范围查询,并在查询上下文中针对电影类型运行一个匹配查询。
{
"query": {
"bool": {
"must": [
{"match": {"type": "TV Movie"}},
],
"filter": [
{"range": {"release_year": {"gte": 2021}}}
]
}
}
}
我们可以直接使用我们的 ES 控制台(假设您使用的是基于云的平台,如Elastic.co、 Bonsai 或亚马逊 Elasticsearch 服务)或通过 Python Elasticsearch 客户端在我们的索引上运行这个查询。无论您使用客户端还是控制台,查询本身看起来都是一样的。在本文的剩余部分,我的例子将使用 Python ES 客户端和 DSL。
为了开始,我们首先设置 ES 客户端连接(更多细节,请参见我之前的博文和这个 GitHub repo ):
第二步,我们定义并运行针对netflix_movies
索引的查询:
代码末尾的 print 语句将标题和相关的相关性分数打印为元组。输出如下所示:
[
('Bling Empire', 0.96465576),
('Carmen Sandiego', 0.96465576),
('Cobra Kai', 0.96465576),
('Disenchantment', 0.96465576),
('Dream Home Makeover', 0.96465576),
("Gabby's Dollhouse", 0.96465576),
('Headspace Guide to Meditation', 0.96465576),
('Hilda', 0.96465576),
('History of Swear Words', 0.96465576),
('Inside the World’s Toughest Prisons', 0.96465576)
]
在这种情况下,所有条目的相关性分数都是相同的:这是有意义的,因为所有这些条目对于type
(即“电视电影”)都具有完全相同的值。既然我们知道“TV Movie”是该字段可以取的值,我们也可以使用过滤器上下文,因为我们正在寻找那个确切的值。
那么什么时候应该使用过滤器或查询上下文呢?一般来说,过滤器更便宜,应该尽可能在任何时候使用( ES 自动缓存经常使用的过滤器以提高性能)。它们用于搜索二进制案例(答案明确为“是”或“否”)和精确值(例如在搜索数值、特定范围或关键字时)。反过来,当结果可能不明确或用于全文搜索时(即当搜索已分析的文本字段时),应使用查询上下文。
让我们带着何时使用过滤器和查询上下文的信息重新看看上面显示的查询:该查询适用于一系列短字段类型(release_year
)和关键字字段类型(type
)。对于后者,我们知道自己想要的确切价值(“电视剧”)。因此,编写查询的更好方法如下,重用范围过滤器,并对后者应用术语查询(下面将详细介绍这种类型的查询),并将两者放在“过滤器”上下文中:
常见查询
现在我们已经介绍了搜索和 DSL 的基础知识,让我们先来看看几个基本的查询。
比赛
首先是“匹配”查询,这是全文搜索的默认选项。假设我们正在寻找“纸牌屋”系列的元数据。因为 ES 在使用匹配查询时分析文本,所以如果我们使用默认值(DSL 默认为“or”操作符),它将返回标题中有“House”或“Cards”的任何节目。因此,我们将使用“and”运算符:
该查询产生一个匹配项(一个文档):
{
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 15.991642,
"hits": [
{
"_index": "netflix_movies",
"_type": "_doc",
"_id": "rWHgLHgBIp2yHscf16v-",
"_score": 15.991642,
"_source": {
"show_id": "s2833",
"type": "TV Show",
"title": "House of Cards",
"director": null,
"cast": "Kevin Spacey, Robin Wright, Kate Mara, Corey Stoll, Sakina Jaffrey, Kristen Connolly, Constance Zimmer, Sebastian Arcelus, Nathan Darrow, Sandrine Holt, Michel Gill, Elizabeth Norment, Mahershala Ali, Reg E. Cathey, Molly Parker, Derek Cecil, Elizabeth Marvel, Kim Dickens, Lars Mikkelsen, Michael Kelly, Joel Kinnaman, Campbell Scott, Patricia Clarkson, Neve Campbell",
"country": "United States",
"date_added": "November 2, 2018",
"release_year": 2018,
"rating": "TV-MA",
"duration": "6 Seasons",
"listed_in": "TV Dramas, TV Thrillers",
"description": "A ruthless politician will stop at nothing to conquer Washington, D.C., in this Emmy and Golden Globe-winning political drama."
}
}
]
}
这个点击的相关性分数是15.991642
。乍一看,这似乎很奇怪。但是,请记住,相关性分数是没有限制的,它用于评估一个文档相对于匹配查询的所有其他文档的相关性。换句话说:分数表示在相同的搜索中,与相同查询的其他“命中”(文档)相比,文档与查询的相关程度。
术语查询
术语查询用于“查找”字段与精确值匹配的文档。我们的索引中有许多keyword
字段,我们可以对其应用术语查询。下面的例子提取了五个文档,其中type
字段等于TV Show
(注意size
参数控制 ES 返回多少条记录,默认为 10 条):
文本字段应该使用而不是术语查询。ES 在分析过程中改变文本字段,标记文本,去掉标点符号,并将其转换成小写字母。如果type
是一个text
字段而不是一个keyword
字段,上面显示的查询将不会返回结果,因为作为分析的一部分,“TV Show”
的任何实例都将被转换为["tv", "show"]
。
范围
在我们的“常见查询”系列中,最后但同样重要的是“范围查询”。顾名思义,范围查询用于查找特定字段的值落在定义的范围内的任何文档。它可用于date
和数字字段类型。它也可以用于text
和关键字字段,只要您的集群设置允许昂贵的查询(默认)。下面显示的查询对发行年份运行简单的范围查询,搜索 2012 年或更早发行的 100 部电影或电视节目:
(略多)复杂的查询
我倾向于使用几个更复杂的查询。在这一节中,我们将简要了解正则表达式、度量聚合和定制过滤器。
使用正则表达式
regexp 查询设计用于查找特定字段中的术语与正则表达式匹配的文档。下面的示例在我们的netflix_movies
索引中查找任何文档,其中title
字段包含部分由“war”组成的单词(例如 war、warror、war、warm 等)。):
Regexp 查询可以区分大小写(使用case_insensitive
选项,默认设置为false
)。然而,title
是一个文本字段,其分析未被禁用。因此,我们可以预期title
字段中的术语已经被小写化了(除了别的以外,请参考前面的章节以获得更多关于“分析”的细节)。因此,考虑到我们当前的映射,启用或禁用区分大小写没有什么区别。
使用指标聚合检查数据
ES 聚合是探索数据的一种很好的方式,它们有三种风格:度量、桶和管道。在这里,我们将看到一个来自指标,一个来自存储桶类别。
我们首先来看一下 stats 查询(一个度量聚合),当您想要查看数字值的汇总统计信息(min、max、mean、sum)时,这个查询会很方便。例如,如果我们想快速查看release_year
在我们的数据中是如何分布的,我们可以运行以下查询:
对于聚合,我们在查询中将size
参数设置为 0。这意味着搜索 API 不会返回任何文档(如果您忽略这一点,hits
字段将包含文档)。该查询的响应为我们提供了整个文档中release_year
值的简单汇总统计数据(例如,最小值、最大值、平均值):
'{
"release_year_stats": {
"count": 7787,
"min": 1925.0,
"max": 2021.0,
"avg": 2013.932579940927,
"sum": 15682493.0
}
}'
现在让我们转向第二个聚合查询,这一次来自 bucket 聚合家族。术语聚合有助于快速了解不同类别的观察结果的可用性。例如,在我们的netflix_movies
索引中,您可能想要查看在任何给定年份有多少部电影上映,或者每种类型有多少部电影出现在数据集中。在 DSL 中,我们对前者的查询(每个发行年份的电影数量)如下所示:
在这个查询中有两件事值得强调。首先,我们在terms
对象中指定第二个size
参数,它控制返回多少个“术语桶”(在本例中是:5)。第二,我们按关键字(即发行年份)以升序对输出进行排序。该查询的输出应该如下所示:
{
"release_years": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 7775,
"buckets": [
{
"key": 1925,
"doc_count": 1
},
{
"key": 1942,
"doc_count": 2
},
{
"key": 1943,
"doc_count": 3
},
{
"key": 1944,
"doc_count": 3
},
{
"key": 1945,
"doc_count": 3
}
]
}
}
让我们快速回顾一下这个输出。buckets
字段包括五个术语桶中每一个的文档计数(每个关键字一个对象)。反过来,sum_other_doc_count
是从输出中排除的桶的所有计数的总和。最后,doc_count_error_upper_bound
值反映了与桶聚集相关联的误差。此时你可能会想:“错误,什么错误?”。ES 在响应中报告了一个错误,因为术语聚合与近似。这源于这样一个事实,即文档分布在多个分片中,每个分片都有自己的有序术语列表,这些列表在聚合中组合在一起。
协调搜索过程的节点请求等于 [size](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html#_shard_size_3)
的多个术语桶。随后,来自这些碎片的结果被组合以产生最终的响应。因此,如果指定的size
小于唯一项的数量,我们可以预期出现错误的可能性会更大。在上面的例子中,我们有 73 个不同的release_year
值,所以我们可能想要更改size
参数(对于大量的术语桶,shard_size
也是如此,以解决因增加 [size](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html#_shard_size_3)
而产生的一些额外开销)。
使用脚本查询自定义过滤器
我们最后的“复杂”查询:“脚本查询”。如果您想对索引中的文档使用自己设计的过滤器,可以使用脚本查询。过滤器上下文中提供了脚本查询。在下面的例子中,我编写了一个简单的脚本来提取release_year
大于 2018 的文档(我们可以使用范围查询获得相同的结果,见上文)。
source
字段包含脚本,params
字段包含脚本使用的start_year
值。脚本查询的默认语言是“无痛”(在lang
字段中指定),但是其他语言也是可用的,包括 Lucene 的表达式语言和 Mustache 语言。如果您有经常使用的定制脚本,您可以使用端点在集群状态上存储脚本,这样您可以检索它们以备后用。存储脚本加快了搜索速度,因为它通常会减少编译所需的时间。
使用 SQL 语法查询 ES
对于 SQL 爱好者:您可以使用 SQL 语法来查询您的 ES 索引。该功能是 X-Pack 的一部分,您可以使用它在基于云的 es 服务(如 AWS 或Elastic.co)的控制台中直接对您的 ES 索引执行 SQL 查询,或者使用 Python Elasticsearch 客户端。(注意这个不能在 Bonsai 上运行,因为 X-Pack 插件不包括在内,因为它需要一个用于商业目的的许可证。因此,我在Elastic.co上运行了 SQL translate API 的以下 API 调用,它提供了 14 天的免费试用。
将您的 SQL 语法转换成 DSL
如果您在 Elasticsearch 上工作,您可以使用 SQL translate API 来将 SQL 语法翻译成本地的 Elasticsearch 查询。在控制台上,这就像在 JSON 文档中使用带有 SQL 语法的 POST 请求一样简单。例如,获取 2015 年或以后上映的网飞电影的标题列表的查询如下所示:
{"query": "SELECT title FROM netflix_movies WHERE release_year >= 2015"}
如果您在 API 控制台上的翻译端点(POST _sql/translate
)上使用 POST 请求发送该文档,它将返回本地 ES 查询(DSL)中的相应查询。对于我们的示例,产生的 ES 查询是:
{
"sort": [
{
"_doc": {
"order": "asc"
}
}
],
"query": {
"range": {
"release_year": {
"to": null,
"include_upper": false,
"boost": 1,
"from": 2015,
"include_lower": true
}
}
},
"_source": false,
"fields": [
{
"field": "title"
}
],
"size": 1000
}
直接运行 SQL 查询
您也可以直接获得输出,完全跳过“翻译步骤”。如果您使用带有_sql?format=txt
的 JSON 文档发出 POST 请求,API 会以一种格式良好的文本格式返回响应数据(对于 JSON 格式,使用_sql?format=json
):
title
-------------------------------------
Black Crows Black Earth Rising Black Lightning Black Man White Skin Black Mirror Black Mirror: Bandersnatch Black Panther Black Sea Black Site Delta Black Snow
...........
类似地,您可以运行简单的GROUP BY
查询(假设您执行聚合的字段不是text
类型)。例如,以下查询将返回每个发行年份的电影数量(这里我将输出限制为前五年):
POST _sql?format=txt
{"query": "SELECT release_year, COUNT(*) as n_entries FROM netflix_movies GROUP BY release_year LIMIT 5"}
同样,输出的格式也很好:
release_year | n_entries
---------------+---------------
1925 |1
1942 |2
1943 |3
1944 |3
1945 |3
就是这样!我们现在已经回顾了 DSL 的基础知识,并运行了几个基本的和更复杂的查询。
感谢您的阅读!
https://medium.com/@ndgoet/membership
如果你喜欢这篇文章,这里还有一些你可能喜欢的文章:
[## 优化弹性搜索中的磁盘使用
towardsdatascience.com](/optimising-disk-usage-in-elasticsearch-d7b4238808f7)
免责声明:“elastic search”是 Elasticsearch BV 的商标,在美国和其他国家注册。本文中对任何第三方服务和/或商标的描述和/或使用不应被视为对其各自权利持有人的认可。
请仔细阅读 本免责声明 中的任何内容后再依托 我的 Medium.com 文章 。
脸书先知入门
使用脸书的高级预测工具构建您的第一个模型所需了解的一切
在https://amzn.to/373oIcf用脸书预言家预测时间序列数据
这篇文章包含了我的新书《关于脸书先知的一切》的摘录。这本书在亚马逊上有售。这本书的全部内容都列在这个帖子的最后!
如果你觉得这篇文章很有用,并且想用 Prophet 来改善你的预测,请考虑在 https://amzn.to/373oIcf购买整本书。
在 Prophet 中构建简单模型
1958 年 3 月,斯克里普斯海洋研究所的查尔斯·大卫·基林开始了对大气中二氧化碳直接测量的最长记录。基林的基地在加利福尼亚的拉霍亚,但是已经得到了美国国家海洋和大气管理局的许可,可以使用他们位于夏威夷岛上莫纳罗亚火山北坡海拔两英里的设施来收集二氧化碳样本。在那个高度,基林的测量不会受到当地释放的 CO₂的影响,比如附近的工厂。
1961 年,基林发表了他迄今为止收集的数据,确定 CO₂水平有很强的季节性变化,并且在稳步上升,这一趋势后来被称为基林曲线。到 1974 年 5 月,NOAA 开始了他们自己的平行测量,并一直持续到现在。龙骨曲线图如下:
基林曲线显示了大气中二氧化碳的浓度
随着它的季节性和增长趋势,这条曲线是一个很好的候选人来尝试先知。该数据集包含 53 年来超过 19,000 次每日观察。CO₂的测量单位是 PPM 或百万分之一,这是每百万分子空气中 CO₂分子的度量单位。
为了开始我们的模型,我们需要导入必要的库, pandas 和 Matplotlib ,并从 fbprophet 包中导入 Prophet 类。
import pandas as pdimport matplotlib.pyplot as pltfrom fbprophet import Prophet
作为输入,Prophet 总是需要一个包含两列的 pandas 数据框架:
- ds ,对于日戳,应该是熊猫期望格式的日戳或时间戳列。
- y ,包含我们希望预测的测量值的数字列。
在这里,我们使用 pandas 来导入数据,在这种情况下是一个 csv 文件【注意:这个 csv 可以在 https://git.io/JYG6T 的下载】,然后将它加载到一个 DataFrame 中。注意,我们还将 ds 列转换为 pandas datetime 格式,以确保 pandas 正确地将其识别为日期,而不是简单地将其作为字母数字字符串加载。
df = pd.read_csv(‘co2-ppm-daily_csv.csv’)df[‘date’] = pd.to_datetime(df[‘date’])df.columns = [‘ds’, ‘y’]
如果你熟悉 scikit-learn ( sklearn )包,你会觉得在 Prophet 中如鱼得水,因为它是以类似的方式设计的。Prophet 遵循 sklearn 范式,在调用 fit 和 predict 方法之前,首先创建模型类的实例。
model = Prophet()model.fit(df)
在这个单独的 fit 命令中,Prophet 分析了数据并分离出季节性和趋势,而不需要我们指定任何额外的参数。不过,它还没有做出任何未来预测。为此,我们需要首先制作一个未来日期的数据框架,然后调用预测方法。 make_future_dataframe 方法要求我们指定我们打算预测的天数。在这种情况下,我们会选择十年,或 365 天乘以 10 。
future = model.make_future_dataframe(periods=365 * 10)forecast = model.predict(future)
在这一点上,预测数据帧包含了 Prophet 对未来十年 CO₂浓度的预测。我们稍后将探讨该数据框架,但首先让我们使用 Prophet 的 plot 功能绘制数据。 plot 方法建立在 Matplotlib 之上;它需要来自 predict 方法的数据帧输出(本例中是我们的预测数据帧)。
我们用可选的 xlabel 和 ylabel 参数来标记轴,但是只保留可选的 figsize 参数的默认值。注意,我还使用原始 Matplotlib 语法添加了一个标题;因为先知图是基于 Matplotlib 构建的,所以您可以对 Matplotlib 图形做的任何事情也可以在这里执行。另外,不要被带有美元符号的奇怪的 ylabel 文本所迷惑;这只是告诉 Matplotlib 使用自己的类似 TeX 的引擎在 CO₂.中制作下标
fig = model.plot(forecast, xlabel=’Date’, ylabel=r’CO$_2$ PPM’)plt.title(‘Daily Carbon Dioxide Levels Measured at Mauna Loa’)plt.show()
图表如下:
预言家预测
就是这样!在这 12 行代码中,我们得出了我们的十年预测。
解释预测数据框架
现在,让我们通过显示前三行来看看那个预测数据框(我在这里调换了它,以便更好地看到页面上的列名),并了解这些值在上图中是如何使用的:
forecast.head(3).T
运行该命令后,您应该会看到下表:
预测数据框架
以下是对预测数据框架中每一列的描述:
- ‘ds’—该行中的值所属的日期戳或时间戳
- ‘趋势’—单独趋势分量的值
- 'yhat_lower' —最终预测的不确定性区间的下限
- 'yhat_upper' —最终预测的不确定性区间的上限
- 'trend_lower' —趋势分量周围不确定性区间的下限
- 'trend_upper' —趋势分量周围不确定性区间的上限
- 'additive_terms' —所有季节性相加的组合值
- ' additive _ terms _ Lower '—围绕附加季节性的不确定性区间的下限
- ' additive _ terms _ Upper '—围绕附加季节性的不确定性区间的上限
- ‘每周’—每周季节性成分的值
- ‘weekly _ Lower’—周分量不确定性区间的下限
- 'weekly_upper' —周分量不确定性区间的上限
- ‘每年’—每年季节性成分的值
- 'yearly_lower' —围绕年度分量的不确定性区间的下限
- ‘yearly _ Upper’—围绕年度分量的不确定性区间的上限
- '乘法 _ 术语' —所有乘法季节性的组合值
- '乘法 _terms_lower' —围绕乘法季节性的不确定性区间的下限
- '乘法 _terms_upper' —围绕乘法季节性的不确定性区间的上限
- ‘yhat’—最终预测值;‘趋势’、、【乘法 _ 术语】、、【加法 _ 术语】、的组合
如果数据包含每日季节性,则还将包括‘每日’、‘每日 _ 上限’和‘每日 _ 下限’列,遵循由‘每周’和‘每年’列建立的模式。后面的章节将包括加性/乘性季节性和不确定性区间的讨论和例子。
在上面的预测图中,黑点代表我们拟合的实际记录的 y 值(在df[‘y’]列中的值),而实线代表计算的 yhat 值(预测[‘yhat’]列)。请注意,实线超出了我们预测未来的黑点范围。预测区域实线周围的浅色阴影表示不确定性区间,由预测[‘yhat _ lower’]和预测[‘yhat _ upper’]界定。
现在让我们将预测分解成几个部分。
了解组件图
在第 1 章,时间序列预测的历史和发展中,Prophet 作为一个加性回归模型被引入。图 1.4 和 1.5 显示了趋势和不同季节的单个分量曲线是如何相加在一起形成更复杂的曲线的。先知算法本质上是反过来做的;它取一条复杂的曲线,并把它分解成它的组成部分。更好地控制预言家预测的第一步是理解这些组成部分,以便可以单独操作它们。Prophet 提供了一个方法 plot_components 来可视化这些。
继续我们在莫纳罗亚模型上的进展,绘制组件就像运行这些命令一样简单:
fig2 = model.plot_components(forecast)plt.show()
正如你在输出图中看到的,Prophet 在这个数据集中分离了三个部分:趋势、每周季节性和每年季节性:**
莫纳罗亚组件图
随着时间的推移,趋势不断增加,但似乎有一个更陡的斜率——大气中 CO₂浓度的加速。趋势线还显示了预测年份的不确定性区间。从这条曲线中,我们得知 1965 年大气中 CO₂的浓度约为 320 PPM。到 2015 年,这一数字增长到约 430 PPM,我们预计到 2030 年将达到约 430 PPM。然而,由于季节性效应的存在,这些确切的数字将根据一周中的日期和一年中的时间而变化。
每周季节性显示,一周中的每一天,数值会有大约 0.01 PPM 的变化——这是一个微不足道的量,很可能纯粹是由于噪音和随机机会。事实上,直觉告诉我们,二氧化碳水平(当在离人类活动足够远的地方测量时,就像在莫纳罗亚火山的高坡上一样)并不太在乎今天是星期几,也不受它的影响。
我们将在第 4 章,季节性中学习,如何指示 Prophet 不要拟合每周的季节性,因为在这种情况下是谨慎的。在第 10 章,不确定性区间,我们将学习如何绘制季节性的不确定性,并确保像这样的季节性可以忽略。
现在看一下的年度季节性显示,二氧化碳在整个冬季上升,大约在 5 月份达到峰值,而在夏季下降,在 10 月份达到低谷。根据一年中的时间,二氧化碳的测量值可能比趋势预测值高 3 PPM,也可能比趋势预测值低 3 PPM。如果你回头参考原始数据,在基林曲线中,你会被提醒,该曲线有一个非常明显的周期性,这是由每年的季节性决定的。
尽管这个模型很简单,但你通常只需要用 Prophet 就能做出非常准确的预测!除了缺省值,我们没有使用额外的参数,但仍然取得了非常好的结果。
这段摘录摘自用脸书预言家预测时间序列数据的第 2 章,现在可以在亚马逊上买到。这本书有超过 250 页的例子,教训,和先知的每一个方面的描述,并提供了超过 10 个教学数据集,以帮助您了解如何通过演示先知功能,从简单到先进的完整工作代码来完善您的预测。
全书包含以下章节:
- 时间序列预测的历史与发展
- 脸书先知入门
- 非每日数据
- 季节性
- 假日
- 增长模式
- 趋势转折点
- 附加回归量
- 异常值和特殊事件
- 不确定区间
- 交叉验证
- 性能指标
- 生产先知
如果你喜欢这篇文章,请考虑在这里订购:https://amzn.to/373oIcf。如果你真的读了这本书,我会很高兴听到你的想法!
Faiss 入门
行业笔记
了解脸书人工智能相似性搜索的变化—搜索
脸书人工智能的可扩展搜索——关于松果. io 的原创文章——图片由作者提供
F acebook AI 相似性搜索(Faiss)是最流行的高效相似性搜索实现之一,但它是什么——以及我们如何使用它?
是什么让 Faiss 与众不同?我们如何最好地利用这个不可思议的工具?
幸运的是,这是一个非常简单的开始过程。在本文中,我们将探索 Faiss 提供的一些选项,它们是如何工作的,以及最重要的是,Faiss 如何使我们的搜索更快。
点击此处查看视频:
什么是 Faiss?
在我们开始编写任何代码之前,你们中的许多人会问——什么是 Faiss?
Faiss 是一个由脸书·艾开发的库,可以实现高效的相似性搜索。
因此,给定一组向量,我们可以使用 Faiss 对它们进行索引——然后使用另一个向量(查询向量),我们在索引中搜索最相似的向量。
现在,Faiss 不仅允许我们建立一个索引和搜索——而且它还将搜索速度提高到可笑的性能水平——这是我们将在本文中探讨的内容。
构建一些向量
我们首先需要的是数据,我们将连接来自这个语义测试相似性中心报告的几个数据集。我们将下载每个数据集,并将相关的文本列提取到一个列表中。
接下来,我们删除所有重复的句子,留下 14.5 千个独特的句子。最后,我们使用句子-BERT 库构建每个句子的密集向量表示。
现在,构建这些句子嵌入可能需要一些时间——所以可以从这里直接下载它们(您可以使用这个脚本将它们加载到 Python 中)。
当然
我们从简单的开始。首先,我们需要建立 Faiss。现在,如果你使用 Linux——你很幸运——Faiss 为任何支持 CUDA 的 Linux 机器提供了内置的 GPU 优化。
MacOS 还是 Windows?我们没那么幸运。
(别担心,还是快得离谱)
所以,支持 CUDA 的 Linux 用户,输入conda install -c pytorch faiss-**gpu**
。其他人,conda install -c pytorch faiss-**cpu**
。如果你不想使用conda
,这里有替代的安装说明。
一旦我们安装了 Faiss,我们就可以打开 Python,用IndexFlatL2
构建我们的第一个简单明了的索引。
IndexFlatL2
IndexFlatL2
度量的是所有给定点之间的 L2(或欧几里德)距离我们的查询向量,并将这些向量加载到索引中。很简单,非常准确,但是不会太快。
查询向量 xq 和我们的索引向量之间的 L2 距离计算(显示为 y
在 Python 中,我们会用向量维数(768
—句子嵌入的输出大小)初始化IndexFlatL2
索引,如下所示:
通常,我们会使用需要我们在加载数据之前train
它们的索引。我们可以使用is_trained
方法检查某个指数是否需要训练。IndexFlatL2
不是需要训练的指标,应该返回False
。
一旦准备好,我们就像这样加载我们的嵌入和查询:
它返回最接近我们的查询向量xq
的前k
个向量作为7460
、10940
、3781
和5747
。显然,这些都是伟大的比赛——包括人们拿着足球奔跑,或者在足球比赛的背景下。
现在,如果我们想从 Faiss 中提取数值向量,我们也可以这样做。
速度
单独使用IndexFlatL2
索引在计算上是昂贵的,它不能很好地伸缩。
当使用这个索引时,我们正在执行一个穷举搜索——这意味着我们将我们的查询向量xq
与我们索引中的所有其他向量进行比较,在我们的例子中,每次搜索都要计算 14.5K L2 距离。
想象一下我们搜索包含 1M、1B 甚至更多向量的数据集的速度——以及当我们包括几个查询向量时的速度?
返回结果所用的毫秒数(y 轴)/索引中的向量数(x 轴)—仅依赖 IndexFlatL2 会很快变得很慢
我们的索引很快变得太慢而无用,所以我们需要做一些不同的事情。
对索引进行分区
Faiss 允许我们添加多个步骤,使用许多不同的方法优化我们的搜索。一种流行的方法是将索引划分成 Voronoi 单元。
我们可以想象我们的向量都包含在一个 Voronoi 单元中——当我们引入一个新的查询向量时,我们首先测量它在质心之间的距离,然后将我们的搜索范围限制在该质心的单元。
使用这种方法,我们将获取一个查询向量xq
,识别它所属的单元格,然后使用我们的IndexFlatL2
(或另一个度量)在查询向量和属于特定单元格的的所有其他向量之间进行搜索。
所以,我们正在缩小我们的搜索范围,产生一个近似的 答案,而不是精确的(如同通过穷举搜索产生的一样)。
为了实现这一点,我们首先使用IndexFlatL2
初始化我们的索引——但是这一次,我们使用 L2 索引作为量化步骤——我们将其输入到分区IndexIVFFlat
索引中。
这里我们增加了一个新的参数nlist
。我们使用nlist
来指定我们希望我们的索引有多少分区(Voronoi 单元)。
现在,当我们构建之前的仅IndexFlatL2
索引时,我们不需要训练索引,因为构建索引不需要分组/转换。因为我们用IndexIVFFlat
添加了集群,这种情况不再存在。
所以,我们现在要做的是train
我们的数据索引——在添加任何数据到索引之前,我们必须做这件事。
既然我们的索引已经训练好了,我们就像以前一样添加数据。
让我们使用相同的索引句子嵌入和相同的查询向量xq
再次搜索。
搜索时间明显减少,在这种情况下,我们没有发现穷举搜索和近似搜索返回的结果之间有任何差异。但是,通常情况是这样的。
如果使用IndexIVFFlat
的近似搜索返回次优结果,我们可以通过增加搜索范围来提高准确性。我们通过增加nprobe
属性值来做到这一点——它定义了要搜索多少个邻近像元。
当 nprobe == 1 时搜索单个最近的单元(左),当 nprobe == 8 时搜索八个最近的单元(右)
我们可以很容易地实现这种改变。
现在,因为我们通过增加nprobe
值来搜索更大的范围,我们将看到搜索速度也增加了。
使用不同的 nprobe 值(1、5、10 和 20)查询 IVFFlat 索引的时间/向量数
尽管如此,即使有了更大的nprobe
值,我们仍然看到比我们返回的只有IndexFlatL2
的索引更快的响应。
向量重构
如果我们继续并试图再次使用index.reconstruct(<vector_idx>)
,我们将返回一个RuntimeError
,因为由于增加了 IVF 步骤,在原始向量和它们的索引位置之间没有直接映射。
因此,如果我们想要重建向量,我们必须首先使用index.make_direct_map()
创建这些直接映射。
从那里我们可以像以前一样重建我们的向量。
量化
我们还有一个关键的优化要介绍。到目前为止,我们所有的索引都将向量存储为完整的(例如Flat
)向量。现在,在非常大的数据集中,这可能很快成为一个问题。
幸运的是,Faiss 能够使用乘积量化(PQ) 来压缩我们的矢量。
但是,PQ 是什么?嗯,我们可以把它看作是一个额外的近似步骤,其结果类似于我们使用的 IVF 。IVF 允许我们通过缩小我们搜索的范围来近似,而 PQ 近似了距离/相似性计算。
PQ 通过压缩向量本身来实现这种近似的相似性操作,这包括三个步骤。
产品量化的三个步骤
1。我们把原始向量分成几个子向量。
2。对于每个颠覆集,我们执行一个聚类操作——为每个子向量集创建多个质心。
3。在我们的子向量的向量中,我们用每个子向量最近的特定于集合的质心的 ID 来替换它。
为了实现所有这些,我们使用了IndexIVF**PQ**
索引——在添加嵌入之前,我们还需要train
索引。
现在我们准备开始使用新的索引进行搜索。
速度还是准确度?
通过添加 PQ,我们已经将 IVF 搜索时间从大约 7.5 毫秒减少到大约 5 毫秒,对于这种规模的数据集来说,这是一个很小的差异——但当扩大规模时,这一差异会很快变得显著。
但是,我们还应该注意到返回的结果略有不同。之前,通过我们详尽的 L2 搜索,我们返回了7460
、10940
、3781
和5747
。现在,我们看到稍微不同的结果顺序——以及两个不同的 id,5013
和5370
。
我们的两个速度优化操作 IVF 和 PQ ,都是以准确性为代价的。现在,如果我们打印出这些结果,我们仍然会发现每个项目都是相关的:
因此,尽管我们可能得不到完美的结果,但我们仍然很接近——由于这些近似,我们得到了更快的响应。
我们的三个索引的查询时间/向量数量
如上图所示,随着索引大小的增加,查询时间的差异变得越来越重要。
本文到此为止!我们已经介绍了在 Faiss 中为搜索构建高性能索引的基础知识。
显然,使用IndexFlatL2
、IndexIVFFlat
和IndexIVFPQ
可以做很多事情,每一个都有许多参数,可以根据我们特定的精度/速度要求进行微调。如图所示,多亏了 Faiss,我们能以闪电般的速度非常容易地产生一些真正令人印象深刻的结果。
我希望你喜欢这篇文章!如果你有任何问题,请通过 Twitter 或在下面的评论中告诉我。如果你想知道更多类似的内容,我也会在 YouTube 上发布。
感谢阅读!
*所有图片均由作者提供,除非另有说明
功能商店入门
介绍什么是特征库,以及如何使用它们来简化机器学习过程
Artem Gavrysh 在 Unsplash 上拍摄的照片
介绍
创建能够在生产中可靠运行的机器学习模型可能是一个非常困难的过程。事实上,这些模型只能和用来训练它们的数据一样好。因此,能够创建一个能够准确预处理所有传入数据并以最佳方式构建数据以训练模型的流程,对于项目的长期成功至关重要。
数据科学家和数据工程师为了预处理将在机器学习模型中使用的数据而通常使用的技术的一些例子是:
- 特征工程: 修复数据中的不一致,通过合并/分割现有特征来创建新特征。
- 特征提取: 使用 PCA、t-SNE 等技术降低数据集维度
- 特征选择: 通过删除数据集中携带较少信息的特征或在分析中仅添加噪声的特征来减少特征数量。
彻底预处理我们的数据的一些主要好处是:
- 降低过度拟合的风险。
- 加快训练时间。
- 减少执行超参数优化的需求。
- 改进的数据可视化。
因此,在某些情况下,数据预处理可能是一个漫长的过程,以确保我们的数据尽可能采用最佳格式,并考虑所有不同的边缘情况(尤其是在管道中接收新数据时)。
随着越来越多的组织开始在其业务的许多不同领域使用机器学习过程,当涉及到预处理数据时,尝试避免任何形式的重复工作可能非常重要,这些数据随后可由组织内的不同团队和不同模型使用。为了确保消除业务中的任何重复工作,并更好地了解数据在组织中的使用情况,创建了功能库。
ML 的特征存储
特征存储是为机器学习过程设计的数据管理层。因此,特征存储充当公司内的中央存储库,存储所有不同的特征,这些特征被创建用于数据分析和机器学习。
除了存储所有不同的要素之外,要素存储还被设计为完全自动接收新数据(通过自动应用必要的数据预处理步骤)并跟踪其分布中的任何变化。通过这种方式,要素存储可用于存储和转换要素,从而使数据科学家更容易找到他们可能需要的任何要素并使用它们,而不必担心维护问题(要素会自动更新以用于未来预测,如果需要,可以检索任何更改的历史记录)。
最后,为了支持批处理和在线类型的应用程序,已经设计了特性存储。对于批处理应用程序,可能需要存储大量数据(取决于批处理更新的频率),而对于在线应用程序,实现低延迟通常是主要的优先事项。为了实现这一点,特性存储通常被设计成某种形式的双数据库(例如,存储批量数据的 SQL 数据库和快速处理在线数据的键值存储)。
图 1:示例特征库(图片由作者提供)。
因此,利用功能存储可以为组织带来许多不同的好处,例如:
- 自动数据准备:一旦添加了新的原始数据,特征就可以自动更新(例如,如果我们有一个使用线性回归估算缺失值的预处理特征,一旦新数据添加到特征中,就可以应用相同的变换)。
- 改进的模型训练/重新训练:拥有特征如何随时间变化的历史,可以帮助我们在新数据到来时快速重新训练我们的模型,并充分更新我们的测试数据,以反映自我们上次训练以来真实世界环境如何变化。
- 部署后改进的模型监控:随着新数据的存储,可以添加检查,以查看每个特性的分布是否有任何剧烈的变化,并创建警报,然后重新训练我们的模型。
- 加快新模型的上市时间:数据科学团队可以在预处理数据上花费更少的时间,而在试验和创建最佳模型上花费更多的时间。
- 团队间的特性共享:一旦一个特性被创建并归档,它就可以在将来的其他项目中被自动重用。
- 确保使用最佳 MLOps 实践:机器学习操作(MLOps)是一组最佳实践,旨在确保机器学习模型能够尽快创建,同时尽可能易于维护和管理。使用特征库可以极大地帮助我们实现这两个目标。
- 全面管理您的数据:使用功能存储可以更轻松地查看组织在整个过程中是如何处理数据的,并在遇到任何监管问题时快速采取行动。
创建功能存储
在过去的几年中,不同的开源和企业解决方案已经被构思出来,以促进功能商店的采用。两个最常见的开源解决方案是 Feast 和 Hopsworks 。相反,对于企业用户来说,云服务中增加了功能商店功能,如 GCP 顶点人工智能、 AWS Sagemaker 和 Databricks 。
如果您不确定使用哪个平台作为您的功能商店,可以使用不同的工具,例如功能商店比较,以便为您提供不同提供商之间的差异分类。
联系人
如果你想了解我最新的文章和项目,请在媒体上关注我,并订阅我的邮件列表。以下是我的一些联系人详细信息:
SageMaker Studio 实验室地理空间分析入门
SpaceX 在 Unsplash 上拍摄的
实践教程
使用地理数据和地理空间图像来研究气候变化、自然灾害或人类活动的影响。
地理数据包括使用卫星图像和地理延迟系统(GPS)捕获的地理空间数据,以及通常用地理坐标明确描述的其他地理数据。地理空间分析包括使用软件工具、统计方法和机器学习来收集、报告、绘制和分析这些数据。地理空间分析用于 了解气候变化、自然灾害或人类活动 的影响,通常是对特定地理位置的影响。
使用地理空间数据的挑战
使用地理空间数据时存在一些挑战。首先, 地理空间数据可能非常庞大, 如果没有高容量的存储和计算,很难工作,有时甚至无法工作。解决规模复杂性的一个变通办法是缩小你的关注点或研究领域和时间段。这使得检索和分析一小部分数据变得相对容易。
接下来是围绕 不同格式 的复杂性。使用压缩算法以多种格式捕获地理空间数据,使数据传输和存储更加经济。此外,当您在处理地理数据时,您会经常发现自己在处理多个源,而这些源可能会使用的不同投影捕获数据(稍后将详细介绍)。这包括在使用数据进行分析之前对数据进行预处理和重新投影。
最后,随着卫星绕地球运行, 数据在一段时间内 批量捕获。你可能没有足够的数据或足够高质量的数据来研究特定的时间和地点。在这种情况下,您可能需要调整时间窗口或依靠数据处理来清理和扩充这些数据。
先决条件
这篇文章涵盖了在 SageMaker Studio 实验室上开始地理空间数据分析的基础知识。我们探索公开可用的地理数据集,然后探索在 AWS 开放数据注册处可用的 Sentinel-2 地理空间数据集。我们使用地理矢量数据集探索了加利福尼亚州的湖泊和县,然后重点关注加利福尼亚州的沙斯塔湖,以分析 Sentinel-2 地理空间数据并计算光谱指数。
如果您想跟随,您将需要以下先决条件,所有这些都是免费的。
- 一个 SageMaker 工作室实验室 账号
- 一个 自由层 AWS账户**
- 一个 免费试用 的哨兵枢纽账号
亚马逊 SageMaker Studio 实验室提供 CPU 和 GPU 环境,您可以使用 CPU 环境完成这里描述的所有步骤。
设置您的环境
亚马逊 SageMaker Studio Lab 是一个免费的在线 web 应用程序,用于使用 Jupyter 笔记本学习和实验数据科学和机器学习。使用 Amazon SageMaker Studio Lab,您可以保存和恢复您的工作,访问命令行和克隆 git 存储库。点击这里注册一个免费账户。一旦你的账户被批准并登录,你就可以克隆这个库或者手动上传文件。
首先,您需要在 SageMaker Studio 实验室中创建一个环境。在 Studio Lab 中创建环境很容易。转到您的克隆目录,选择environment.yml
文件,右键单击 YAML 文件,并选择 create an environment。您也可以选择在 Studio Lab 中克隆存储库时自动运行 *environment.yml*
。这将创建一个新的 Studio Lab 内核,其中包含所有必需的包。环境创建完成后,您可以打开笔记本并选择新创建的内核。
选择自定义内核—按作者分类的图像
您也可以取消笔记本的包安装部分的注释,手动安装这些包。
下载数据
地理数据通常以shape file、 Geopackage、或 Geojson 格式提供。让我们从下载 shapefiles 开始,其中包括加利福尼亚各县和水体的地理矢量数据。
- ****加州县数据集包含加州州、县和地方的边界,来自美国人口普查局的 2016 年 MAF/老虎数据库此处。
- 加州水体数据集由加州渔猎局发布。海洋资源区,可在此下载。
下载数据集
下载完文件后,我们需要将它们解压缩到您的本地目录中。
带有地理数据的 EDA
一旦我们在本地获得了数据,我们就可以读取和执行探索性的数据分析。在我们的例子中,我们下载了 shapefiles。shapefile 是一种 ESRI 矢量数据存储格式,用于存储地理要素的位置、形状和属性。geopanads
Python 包使得读取这些 shapefiles 和创建一个 Geopanads 数据帧变得很容易。一个geopandas.DataFrame
对象是一个pandas.DataFrame
,它有一个带几何图形的列。除了标准的pandas.DataFrame
属性,它们还有另外两个属性,分别是 CRS 和geometry,都是可选的。CRS 用来指定 坐标参考系统中 的几何数据。几何包含地理数据的实际坐标,并在geopandas.DataFrame
对象中被设置为几何数据类型。
让我们将县形状数据文件读入geopandas.DataFrame
读取县数据
县—按作者分类的图像
像标准数据帧一样,geopandas.DataFrame
有一个方便的plot
方法,可以用来创建地理可视化。
绘制加州各县
绘制加州各县-作者图片
类似地,我们将把 California Lakes shapefile 读入一个geopandas.DataFrame
并绘制它。
读取和绘制湖泊数据集。
绘制加州湖泊——作者图片
数据争论
我们之前简单提到过投影和坐标参考系统。坐标参考系统表示二维数据,即我们的geopandas.DataFrames
中的数据,如何与地球上的真实位置相关联。当您使用不同来源的地理数据时,它们很可能使用不同的投影。
我们希望将 California lakes 数据集与 counties 数据集叠加在一起,并将湖泊与 California counties 一起可视化。在此之前,我们需要检查并确保它们使用相同的坐标参考系统(CRS)进行投影。一个geopandas.DataFrame
对象的crs
属性就是这样做的。如果您使用counties.crs
和lakes.crs
检查坐标参考系统投影,您会注意到加州各县和湖泊的数据具有不同的 CRS。县数据集使用 EPSG:3857,湖泊数据集使用 EPSG:4326 作为各自的 CRS。在我们一起使用这些数据集之前,我们需要重新规划湖泊,使其具有与县相同的 CRS。
重新设计 CRS
一旦在同一个 CRS 投影中有了地理数据集,就可以叠加和绘制它们。
覆盖物
绘制叠加数据-作者提供的图像
地理数据分析中的一项常见任务是缩小研究范围。我们可以选择一个数据子集来创建一个新的geopandas.DataFrame
对象,用于进一步的分析和可视化。对于我们的例子,让我们把重点放在沙斯塔湖。
选择沙斯塔湖
一旦我们选定了感兴趣的领域,就很容易更好地想象和研究它。
绘制沙斯塔湖—作者图片
使用地理空间图像
接下来,我们从地理矢量数据转移到地理空间图像。对于地理空间图像,我们将使用哨兵-2。 Sentinel-2 任务是一个由两颗卫星组成的陆地监测星座,为当前 SPOT 和 Landsat 任务提供高分辨率光学图像和连续性。Sentinel-2 数据集可在 AWS 开放数据注册处公开获取。
python 包使得直接从 AWS 搜索和下载特定于我们关注领域的数据变得容易。以下代码片段显示了如何配置您的凭据。在这个例子中,我使用一个可选的 JSON 文件来存储和检索我的凭证
设置凭据
AWS 上的 Sentinel-2 数据集包含 2017 年 1 月以来的全球数据,并定期添加新数据。在下载之前,我们需要指定要学习的搜索坐标和时间窗口。在我们的例子中,我们关注沙斯塔湖区域,我们将它指定为一个边界框和一个随机时间段。
哨兵搜索
Sentinel-2 数据被捕获并以瓦片的形式分发,这使得它很容易在网络上传输。我们迭代搜索符合搜索标准的可用图块,并选择特定的图块。为了获得最佳效果,我们选择云覆盖最少的图块。
选择特定的单幅图块
Sentinel-2 卫星各携带一台多光谱仪器(MSI ),在可见光/近红外(VNIR)和短波红外光谱范围(SWIR)有 13 个光谱通道。例如,我们将下载八个特定波段,这将有助于我们的分析。你可以在这里阅读更多关于这些乐队的信息。
哨兵数据下载
除了光谱带,Sentinel tiles 还包括预览图像。让我们先检查一下,以确保我们完整清晰地捕捉到了感兴趣的区域。
解析请求以提取波段和其他数据
绘制预览图像-按作者排列的图像
抽查几个额外的波段也是一个很好的做法,以确保我们拥有一切。我们绘制了波段 7——植被红边,波段 8——近红外光谱,波段 8A——窄近红外光谱。
绘制不同波段-按作者分类的图像
使用栅格数据
地理空间数据基本上由栅格数据或矢量数据组成。Sentinel-2 使用 GeoTIFF,这是一种用于卫星图像和地形模型的栅格数据集。地理空间光栅图像类似于数字图像,但也伴随有将数据连接到特定位置的空间信息。这包括栅格的范围和像元大小、行数和列数及其坐标参考系统(或 CRS)。Python 包可用于读取、检查、可视化和写入地理空间栅格数据。这里我们使用rasterio
来读取这些光栅阵列,然后创建一个真彩色图像。
读取栅格数据
我们使用rasterio
来创建一个.tiff
格式的真彩色图像。真彩色图像的文件尺寸较大。在创建之前,请验证您是否有足够的存储空间。
生成真彩色图像
在 Jupyter 中直接可视化 tiff 图像没有太大帮助。您将需要 GIS 软件来打开和查看它。下面沙斯塔湖地区的真彩色图像是在 QGIS 中渲染的。
在 QGIS 中渲染的真彩色图像—作者提供的图像
计算光谱指数
光谱指数是多光谱图像中两个或更多光谱波段的像素值的组合。光谱指数突出显示图像中感兴趣的土地覆盖类型的相对丰富或缺乏的像素。让我们来看几个例子
归一化差异植被指数(NDVI) 是一个简单的图形指标,用于分析观测目标是否包含活的绿色植被。它被计算为NDVI = (NIR — Red) / (NIR + Red)
,其中 NIR 是近红外波段 8,红色是波段 4
计算 NDVI
earthpy
Python 包可用于绘制光谱带。我们在这里使用它来显示沙斯塔湖地区周围的归一化植被指数差异。
策划 NDVI
NDVI 情节——作者形象
你可以看到绿色的植被区域,深色的植被区域。水体通常很少或没有植被,以对比鲜明的橙色显示。
归一化差异水分指数(NDWI) 使用反射的近红外辐射和可见绿光来增强这些特征的存在,同时消除土壤和陆地植被特征的存在。NDWI 对于分析水体很有用。它被计算为NDWI = (GREEEN — NIR) / (GREEN + NIR)
,其中绿色为波段 3,近红外为波段 8。大于 0.5 的值通常对应水体。
计算 NDWI
类似于我们在上一节中绘制 NDVI 的方式,您可以使用earthpy
来绘制被观察区域的 NDWI。
NDWI 图-作者提供的图片
上面的图像向我们展示了沙斯塔湖地区的数值。你可以看到蓝色的湖区。植被通常对应于小得多的值,而建筑面积对应于 0 到 0.2 之间的值,并以绿色阴影显示。
燃烧面积指数(BAI) 通过强调火灾后图像中的木炭信号,在红色到近红外光谱中突出显示燃烧过的土地。该指数是根据从每个像素到参考光谱点的光谱距离计算的,在参考光谱点处,最近燃烧的区域会聚。较亮的像素表示烧伤区域。
在我居住的南加州,野火是经常发生的自然灾害。下面我们举一个例子,白对 2020 年 Silverado 大火的分析。火灾后的图显示了火灾留下的烧伤疤痕。
Silverado Fire BAI —图片由作者提供
包扎
本文介绍了在 SageMaker Studio 实验室中设置地理空间分析环境、地理分析的基础知识、搜索和下载地理空间图像、操作栅格以及计算光谱指数。Studio Lab 是免费的,我们没有创建任何收费的 AWS 资源作为本练习的一部分。但是,您下载的地理和 GIS 数据以及生成的影像可能会占用大量存储空间。请确保检查您的存储利用率,并根据需要删除文件。
GitLab 入门:绝对初学者指南
入门
如何一步一步地使用 GitLab,即使你以前从未听说过 Git
不到一年前,我不知道“Git”这个词是什么意思。对我来说,这是一个相当野蛮的术语,开发团队用一种编码语言相互交流。有了商业背景,我以为自己永远也不会用到它,所以我从来没有真正关注过这个概念。
当我 2020 年开始在一家数据驱动的公司担任数据分析师时,我不得不面对它:处理我本地保存的文件,并使用像“v1”、“v2”等后缀更新它们。是历史。使用 Windows 的 SharePoint 或 Google Drive 等协作工具也不足以确保整个公司使用的代码的质量和统一性。虽然修改和保存你自己的代码可能会奏效一段时间,但不幸的是,这种工作方式从长远来看是不可持续的。您不仅会浪费时间来维护所有文件版本,还会在与他人沟通时遇到困难:
"你实际上指的是文件的哪个版本?"“你能把你最后的修改通过电子邮件发给我吗?”
“在哪里可以找到这个文件的“final-def-latest.sql”版本?”
如果只集中存储一个版本的代码,就可以避免与同事之间许多耗时的交流。比如其他团队和外部工具使用的“官方”版本的代码。例如,我工作的大部分代码都是由 Apache Airflow 每天处理的,并且供我以外的其他部门的同事使用。这正是 Git 和 GitLab 在这里的目的:
- 在一个唯一的地方存储和保存该代码的唯一有效版本
- 让每个人都能同时使用同一个版本
- 历史化公共代码片段中所做的更改
- 讨论要添加到代码主版本中的修改
入门:什么是 GitLab?
Git 的概念
首先也是最重要的:什么是 Git?正如 git 的网站所说,“ Git 是一个免费开源的分布式版本控制系统,旨在快速高效地处理从小型到超大型项目的一切”。该系统传统上用于在软件开发过程中协调合作开发源代码的程序员之间的工作。它允许跟踪任何一组文件中的变化,因此它与任何基于共享版本代码的协作项目高度相关。Git 的目标包括速度、数据完整性和对分布式非线性工作流的支持(在不同系统上运行的数千个并行分支)。
具体来说,这意味着两个不同的人可以在不妨碍彼此进度的情况下处理相同的代码。为了做到这一点,每个人都将在他们自己的分支上工作,分支是位于分支“主”上的主代码的副本。当保存修改时,每个用户提交他们的修改,并在所谓的合并请求中解释修改了什么。下面是一个可视化的例子,可以更好地理解 Git 分支背后的逻辑:
玛丽·勒费夫尔
GitLab:一个基于 Git 并为组织设计的在线平台
虽然 Git 可以直接在每个用户的电脑上使用,例如通过电脑终端或 Sublime Merge 等 Git GUI 客户端使用, GitLab 是一个在线平台,所有操作都可以在浏览器中完成。正如 GitLab 的网站上所描述的,它是“一个在代码上进行合作的开源软件”。创建 GitLab 帐户是免费的,因此如果您在公司环境中使用它,项目管理员会将您添加到公司的相关项目中。这意味着您可以使用相同的帐户在 GitLab 上进行专业项目和个人项目(取决于您用来创建帐户的电子邮件地址)。
在您的计算机上使用 Git 可以完成的大多数操作也可以在 GitLab 中完成。这在这里尤为关键,因为这意味着 GitLab 允许非开发人员(至少是从未学习过如何使用版本控制系统的人,比如一年前的我)在代码中添加修改,而不必接受计算机科学方面的广泛培训(T21)。
此外,GitLab 将自己标榜为“完整的 DevOps 平台”,因为它为组织提供了比简单地跟踪用户在主代码中所做的更改更多的功能。GitLab 还包括测试代码片段的工具,并允许将代码部署到产品中(当代码被依赖于它的外部工具实际应用和使用时)。在这里,我不会深入讨论细节,因为我想向软件开发领域的初学者介绍 GitLab 的主要特性。
入驻:如何在 GitLab 中找到合适的信息?
贮藏室ˌ仓库
GitLab 上的每个项目都对应一个存储库。这是,在这里你可以找到你的项目中包含的所有文件,以及变更的历史和现有分支的状态。当你发现一个新的项目时,这是你应该开始的地方,因为你将理解项目的结构和参与者是如何工作的。
请特别查看以下部分:
- 文件:顶部导航栏允许您找到您正在寻找的确切文件和版本
- 提交:该部分显示了所有最近提交并合并到所选分支中的变更
- 分支:在这里您可以看到项目的所有分支及其当前状态(“主”是主分支,您也可以浏览您或您的同事创建的分支)
投稿:如何将你的个人风格带入项目?
合并请求
现在你已经对你将要工作的项目有了更好的理解,你可以通过对位于“主”分支上的代码进行修改来开始对它做出贡献。为此,请转到“合并请求”(也称为“MR”)部分。
这一部分中最有用的功能包括:
- 合并请求概述:它允许您快速掌握您的团队成员一直在进行的变更,并希望整合到“主”分支中
- 创建一个新的合并请求:当你准备好让你的同事审查、批准你的修改,然后将你的修改合并到“主”分支时,你可以点击“创建一个合并请求”并按照指示操作
新的合并请求(示例
- 合并请求的详细信息:当你点击一个合并请求(应该是你的还是其他人的)时,你可以在四个选项卡中查看它的详细信息——概述、提交、管道和变更
合并请求的详细信息(示例
结论
从零到 GitLab,再从 GitLab 到 Git
正如我刚才介绍的, GitLab 是软件开发领域新手的易用工具。实际上,它的使用不需要高级的编程知识,只要用户熟悉他想要改变的文件的编程语言。
随着您对 GitLab 越来越熟悉,您可能会想在自己的计算机上使用 Git(通过终端或 Git GUI 客户端)。这将允许您节省时间,因为您将在桌面上有一份存储库文件的副本。相信我:我很不情愿从漂亮的 GitLab 界面切换到冰冷的终端窗口。但是在对 Git 的逻辑有了更好的理解,并对我对 master 分支所做的更改有了信心之后,我不得不承认,在浏览和更改我组织的项目时,我节省了大量的时间。
我给你的最后一个建议:慢慢掌握 Git 和 GitLab,剩下的会随着实践而来!
你喜欢读这篇文章吗? 成为 的一员,加入一个不断成长的充满好奇心的社区吧!