不是另一个新冠肺炎数据分析!
意见
不,实际上不是。这就是我不打算发表新冠肺炎数据分析/预测的原因…
新冠肺炎确实是眼下的热门话题;新闻上到处都是,这可能是大多数谈话的主题。媒体上涌现出许多数据分析和数据分析文章,展示了一些非常酷的疾病可视化和预测。你可能很高兴知道,这真的不是那些帖子中的另一个,我将解释为什么…
我是一名婴儿数据科学家,即使这样也有点夸大事实。当然,我对能利用新冠肺炎的数据做些什么很感兴趣,但我也非常清楚自己能力的有限性。我只是最近才开始涉足数据科学,尽管我已经编程 7-8 年了。
我们也处在一个非常有趣和动荡的时代——我毫不怀疑,在未来的几年里,这段时间将成为学校历史课的一部分!然而,这也是我们需要注意身体和精神健康的时候。有这么多关于新冠肺炎的信息,但哪些是准确的呢?我们应该相信什么?所有这些黯淡的预测都是真的吗?
结合这两件事:我缺乏数据科学经验和我们生活中新冠肺炎(错误)信息的饱和,我决定不发表一篇预测死亡人数或传播速度的文章。
不要误解我,我相信数据科学将在社会克服这种以及未来的疾病中发挥重要作用,但是,我不会为此做出重大贡献。
如果这真的是我的目标的话,还有很多其他数据集可以让我练习我的技能。但是发表一篇关于我对新冠肺炎数据分析的文章,我觉得只会产生负面影响。思考两种不同的场景…
- 在初步分析中,我没有发现什么新的东西,所以我只是对新冠肺炎已经饱和的黯淡前景做出了贡献,从而影响了心理健康。
- 我预测了别人没有的东西(对于我可能生产的简单模型来说,可能性很小),但我不能完全证明这一点,我也不知道这是因为我做错了什么,还是因为我的模型不够好。因此,传播虚假信息或“假新闻”。
是的,新冠肺炎是一个热门话题。
是的,数据科学很可能有助于克服这一点。
但是,这并不是说发表一篇展示婴儿数据科学家研究成果的文章是一件好事。
我的目标是实践我的技能,并有效地交流我的发现,就像许多数据科学家一样。但是,我也觉得我们都对彼此负有责任。我可以使用大量其他数据集来练习这些非常相同的技能,这些数据集对人们来说不太感兴趣,但也不会对他们产生太大的负面影响。或者,如果我积累了足够多的技能,也许我可以产生一些真正的影响,关注世界上其他重要的事情,这些事情正在被忽视或遗忘,而关注的焦点是新冠肺炎。
这就是为什么我要把这项工作的数据预测和公共交流留给那些真正知道自己在做什么的人。
让我们想一想,我们是否真的需要发表更多关于新冠肺炎的文章,或许应该关注世界上其他被遗忘的重要事情。
与 NumPy 一起生成矩阵
Python 技巧
创建 2d 阵列的 NumPy 函数的综合列表
Anton Vietrov 在 Unsplash 上拍摄的照片
NumPy 位于最初与数据科学相关联的 Python 库中。但是,很明显,它是一种处理高维数组、矩阵和表的通用工具。虽然应用程序的数量太大,无法在一篇文章中描述,但我想关注一个非常有用的特性:2d 数组生成。你可能会想,我们为什么要为此烦恼呢?因此,我会提醒我们在每个项目中产生的数百个微小的操作,而没有注意到它们:默认变量的值生成、单元测试的数据创建、中间结果的准备、转换矩阵、“哑”值,等等…准备这些值需要一些时间,在项目开发结束之前,你会意识到它们的必要性。
1.顺序
你可能会感到惊讶,因为我已经把二维数组作为本文的主题。虽然数组到矩阵的转换非常普遍,所以这是有意义的。让我们来探索一对 NumPy 原生的把戏。
例如,对于序列:
重塑它:
增加维度:
由于我们有将数组转换为矩阵的工具,我们可以将其应用于传统的np.arange()
序列发生器,例如:
np.arange(1, 12, 2).reshape(2, 3)
2.随机数
当然,我们不能忽略随机序列,因为它们在测试中被过度使用。Numpy 基于不同的公式提供了大量不同的随机分布。虽然我们将回顾创建随机矩阵的最常见的方法,但所有其他方法也可以类似地使用:
np.random.random([3,3])
—样本来自均匀[0,1)
分布的 3x3 矩阵
np.random.randn(3, 3)
—3×3 矩阵,样本来自均值为 0、方差为 1 的单变量“正态”(高斯)分布
np.random.randint(0, 2, size=(3, 3))
—3×3 矩阵,随机整数来自[0,2]
区间。
3.分布
我们再次使用数组,但是我们不能错过这样重要的函数,它在指定的时间间隔内产生连续的数据分布。
-
np.linspace()
—线性分布(等步长) -
np. logspace()
—对数分布 -
np.geomspace()
—几何分布(有相等因子)
4.阵列复制
这是填充函数的一个很好的例子,它接受一个数组,并将其复制几次以获得一个矩阵。我们必须设置行数和一行中的重复次数(按照这个顺序)。
5.对角矩阵
对于矩阵的中间运算,我们可能需要对角运算。也是线性代数中的基本元素之一。不足为奇的是,NumPy 为它们的创建提供了几个函数。
-
来自数组
-
带 1 的方阵
-
具有自定义对角线的自定义大小的 1s 矩阵
6.np.zeros()
它创建了一个完全由 0 填充的矩阵。它是变量默认值或哑返回值的完美候选。
您也可以使用np.zeros_like()
创建一个自定义大小的 0 矩阵。
7.np.ones()
默认值矩阵的另一个例子,这次用 1 填充。
同样,你可以使用另一个数组作为np.ones_like()
的模板。
8.np.full()
前面的函数使用定义的填充值创建矩阵。但是 NumPy 还提供了一个自定义填充的功能。
9.三角形矩阵
线性代数运算的另一个重要元素:矩阵 a 的一半用 0 填充。NumPy 对三角形矩阵有三个主要函数:
np.tri()
—创建一个下部填充的三角形 1s 矩阵np.tril()
—从自定义数组创建一个三角形矩阵,其下半部分被填充np.triu()
—从一个自定义数组创建一个三角形矩阵,填充上半部分
10 完全自定义矩阵
NumPy 函数山的顶峰是 np.fromfunction()。它根据用户定义的函数创建一个自定义大小的矩阵。函数应该接受与矩阵维数相等的参数个数,如果需要,还可以接受其他值。生成将从索引(0,0)
开始,每个坐标的步长为 1。
你可以在我的 GitHub 上找到一个完整的带有示例的笔记本:
permalink dissolve GitHub 是 4000 多万开发人员的家园,他们一起工作来托管和审查代码,管理…
github.com](https://github.com/Midvel/medium_jupyter_notes/blob/master/matrices_generation/generate-matrices.ipynb)
NumPy 库是任何线性代数运算的完美工具。它充满了有趣的功能,可以创造性地使用。你可以自由分享你最喜欢的 NumPy 技巧。
不是千与千寻:在分散注意力的工作环境中记笔记
尤利娅·卢卡希娜
数据科学家在动荡的工作环境中保持高效的一些生活窍门。不包括辞职。主要基于 Jupyter,但也支持其他数据科学工具。
我想总结一下我做笔记、写待办事项清单、写工作日记来对抗分心的实验。
我的第一份正经工作发生在一家重视时间追踪的公司。它使用了一个基于 Confluence 的工具——我现在已经忘了它的名字——将项目分解成一系列任务。
在接下来的工作中,我采用了一些方法。他们证明了他们的必要性,因为我们的伞式项目接近最后阶段,整体压力增加。在上线前的最后几天,我们有很多自发的会议。他们让我在进程中离开我的任务,从我被打断的同一点开始并不容易。
没有那么明显的办公室干扰
为什么要费心记笔记,这不是迂腐吗?它与效率和生产力有什么关系,难道不需要更多的时间吗?
让我们想象一个典型的办公室日…
我只想喝杯咖啡。但是因为我们有一个厨房给很多人用,所以总是以不可避免的闲聊结束。我通常是一个内向的人。每一次社交活动都吸引了我并不丰富的社交能力。因此,我花了一些时间来降低我的情绪投入,重新开始工作。
此外,我们有一个非常方便游客的数据科学办公室。门一整天都开着。很多人过来打招呼,谈论晴朗的天气。如此高水平的办公室社交是有代价的。这个代价就是我们的专注。
“恢复”持续了 10 到 15 分钟,然后我才能再次完全集中注意力。一天之内会有很多会谈。
事实上,我们开了很多会。当你知道一个会议将在半小时后召开时,你不可能开始任何需要你全力投入的大事。
朱皮特
因为这些挑战,Jupyter 笔记本成了我的最爱。如果我不得不站起来离开,我会留下完整的数据记录,包括成功的和失败的。我想给你一些见解。
在从我的 Mac 电脑迁移到 iPadPro 后,我暂时从 Jupyter 笔记本转向了谷歌合作研究。它有一个相似的界面。我在 Jupyter 只使用了基本的按钮,它们似乎在 Colab 的同一个地方。
实际上,我想使用 Juno,但是在我阅读了一些操作指南之后,我就不再那么有热情了。我偶然发现了 Colab,现在我在浏览器中使用它。我只需要警告那些处理大量数据的人。你应该检查一下,Colab 处理大量数据的速度有多快。目前,我不会为此做广告。
Microsoft OneNote
由于代码中的注释不是用于进度跟踪的,所以我将笔记保存在不同的工具中。
我没有尝试过很多记笔记的应用程序,但在开始使用 OneNote 后,我不想寻找替代方法。它允许我将笔记组织到文件夹中,并且它提供了许多附件格式。
因为我负责检查在混合迁移期间并行运行的两个平台之间的数据一致性,所以我经常需要在手边准备大量的。CSV 或 Excel 文件。在 OneNote 中,我可以将它们直接插入笔记本。
桌面版也有一种格式样式,可以突出显示我经常直接保存到 OneNote 中的代码块。我最后喜欢的功能是时间戳。我可以看到我什么时候开始任务,什么时候完成任务。可以快速估计每项任务的持续时间。对我和项目经理都有好处。
我的工作日记曾经是这样的:
Microsoft OneNote 屏幕截图
我也滥用 OneNote 作为备份工具。我用我的中间结果保存了多个文件。我总是可以通过访问我的日记回到旧版本。
大量的图标选择,尤其是待办事项图标,有助于在笔记变得过大时突出显示重要内容。
我用来写这篇文章的 iOS 版本错过了时间戳(只有日期)和插入代码块。然而,我喜欢再次使用它,我只能推荐它。
一个用例
把你的一天分成几个任务,然后完成它们!
我想从 OneNote 开始。记笔记训练了我,让我在前一天结束时计划我的一天。这让我在第二天早上节省了时间。白天,我会添加一些临时任务。
那么,让我们从一个例子开始。对于一些说明性的部分——比如代码块——我选择了非常简化的部分,以便为每个读者提供一个共同点。
想象一下,我需要可视化谷歌地理定位位置的实际覆盖范围。它是 Google 定位工具支持的位置及其邮政编码的集合。如果未包含邮政编码,则您无法定制您的活动,也无法将它定位于特定位置。
因此,前一天晚上,我在 OneNote 中记下了以下任务:
您可能已经注意到,我正在数据科学笔记本上工作。我也可以有其他的笔记本。我在工作日记的每个条目的标题前放了一个日历周数。在我们敏捷工作的日子里,这很方便,我们的工作量被分成了两周的 scrum 冲刺。
除了分心,你还可能在任务中遇到问题。如果你记录下你一天中所做的所有工作,你就不会有太大的麻烦去回忆你为什么停止做某事,转而去做其他的事情。
我们无法下载地理定位位置。我将在下一节展示更多的细节。
让我们把一个失败通知放在我们最初想做的任务旁边,并把它删除掉,而不是把它标记为完成。
然后,我们仔细考虑情况,并添加一些我们需要的待办事项,以获得我们想要的数据。第一个做完之后,我们有了一些结果。我们把它们写下来。简而言之,数据的原始路径似乎已经过时,我们必须找到新的路径。由于数据会时不时地被更新,我们必须找到一种通用的方法来获取我们每次需要的相关数据。
我们转到第一个子任务,完成它并在这里放一些中间结果。午餐后,我们可能会思考这些 HTML 片段,并开始 BeautifulSoup 任务来自动化获取实际数据路径的过程。
让我们看看在“后端”发生了什么
在 Jupyter / Google 联合实验室中保持跟踪
从技术角度来看,我的任务是从一个 URL 下载数据。该 URL 以“.”结尾。csv”,这是一个好迹象。尽管如此,当我添加一个简单的检查——一个列表长度——结果看起来有点可笑。整个地球上只有 1713 个邮政编码?那不可能是真的!
因此,我们打印应该包含列名的零线。它抛出了一些在这种情况下毫无意义的东西。如果我们打印下一行,它看起来也没有意义。
我们尝试通过导入 IPython 包,让 Colab notebook 显示完整的输出,但是没有效果。我们把它往下移几格。将输出复制粘贴到 iOS Notes 中,再看一遍。仍然没有线索。
我们发送一个简单的请求并检查响应,结果是一个 404 错误。该页面不存在。
我们可以直接从 BeautifulSoup 包开始,自动解析正确的 URL。但是相反,我们做了一个简单的步骤,缩短网址并打开它。
我们看到的页面在层次结构中比目标页面高一级。我们发现它有不止一条路径。CSV 文件:一个包含退役的位置,一个包含仍在工作的位置。
谷歌地理目标(用户视图)
Google 地理目标(HTML 视图)
因此,我们不仅需要从父网页中解析一个 URL,还需要解析正确的 URL。
我们请求父页面,打印前 1000 个符号,以确保我们得到一些可以开始的数据。输出看起来不错。
找到页面上的所有链接也很好。
然后,我们尝试只获取包含“,”的链接。CSV”部分,但它不工作。我们试验了不同的语法,并把它们都放在那里。如果在这个过程中宣布开会,那么回来就更容易了,而不是开始我们已经拒绝的方法。
例如,一个输出表明我们使用了不可迭代的数据类型。我们检查它是否为真,类型是否为 NoneType。我们得到 yes,并试图把它转换成字符串。它工作了。
我们调整 if 条件,它抛出两个相关的链接。尽管如此,我们只需要一个。因此,我们检查链接文本——这也是按钮标签——并添加一个 if 条件,以便只选择指向最新位置的链接。我们现在可以保存它,并开始今天最初计划的任务:可视化数据。
我们在 OneNote 中将待办事项框标记为已完成!
结论:我们让代码逐渐地、有机地增长,备份每个阶段。
我希望你已经了解了我的进度跟踪方法。在下一节中,我将在更抽象的层次上总结它们。
伟大的八人组
如果你与 Jupyter、Juno、Google 联合实验室研究、Kaggle 或 R Studio 合作,你可以使用这些技巧。对于最后一个,你必须激活降价。
如果你经常在办公室分心,如何避免丢失重要信息?
#1.
我没有把整个代码放在一个单元格中。这些数据块帮助你记录你对数据的操作。在每个块之后是输出部分,您可以在那里显示您的初步结果。
会议一结束,您就可以通过查看输出来快速编写代码并刷新您的记忆。
#2.
我做了很多复制粘贴。如果一部分代码不能正常工作,我不会完全删除它,而是将有问题的部分复制到下一个单元中。然后我一步一步改,一次一改。每次修改后都要复制粘贴。我可以随时回到任何代码单元,制作一个新的副本,调整另一个参数或使用另一个函数,等等。
#3.
我保留那些被证明无效的副本,以便以后能够访问它们的错误信息。为了防止自己忘记已经尝试过的事情。
#4.
我保留了所有的工作副本,以便能够从中选择最好的。
#5.
我在每台笔记本电脑的顶部预留了一个单元格,用于打包导入。对于动态加载到笔记本中的每个新包,我稍后会在顶部添加 import 语句。
如果你只运行其中的一小部分,这有助于保持其他部分的工作。例如,您开始用 pyplot 绘图,然后过一会儿您添加了 seaborn,但是您的 import 语句很快就在笔记本中间的某个地方丢失了。第二天,您回到它那里,只想运行使用这些包的代码行,但是它抛出了一个错误,您不得不寻找一个 import 语句或者专门编写它。最终,你的笔记本中会出现大量重复的语句。
除了 import 语句之外,您在试验过程中不会接触到的所有东西也出现在顶部,例如,禁止科学符号的命令行。
#6.
对于每一个新的试验,我都重新命名用于相同结果的对象。如果我将一些外部数据放入数据帧,每次放入不同的数据,我不会为所有数据帧指定相同的“df”名称。这可能会引起混乱。涉及一个对象的每个新命令,一般命名为,将覆盖前一个对相似对象做了一些转换的命令。如果您以某种方式回到笔记本开头的代码块,您会得到意想不到的结果,因为笔记本会调用最后保存的“df”数据帧。
它仅不适用于图形对象,因为 pyplot show 命令将覆盖当前存储在内存中的任何其他图形。
#7.
在一行的开头加上#进行评论,并留下有意义的注释,将会在将来节省你的宝贵时间。不要再写日记了——只写下简短解释某个函数或方法用法的信息。
如果您完成了代码构建,并希望保存它以供几周后的应用,那么添加散列标记的注释是必不可少的。您可能不乐意在 OneNote 中寻找使用一个包而不使用另一个包的解释。
#8.
在我的笔记本的最终版本中,我将大块与标题分开,以便让它们抓住我的注意力,即使我很紧张,向下滚动得太快而无法阅读代码本身。
一个完美的例子
由于我在上面的例子中没有完全遵循我自己的最佳实践,这里是我用来为另一篇 TDS 文章构建 viz 的笔记本截图:
当然,如果你不能在办公室集中注意力,和你的老板谈谈也是值得的。数据科学家每天应该有几个小时不受干扰地工作。
人工智能世界的显著进步和发展(11 月 9 日)
你应该知道的人工智能世界中相关事件的基本信息。
人工智能的世界发展迅速,新技术每天都在发展,更多专注于人工智能的公司正在涌现。
跟上与机器学习从业者相关的发展和进步可能具有挑战性。
因此,我写了一篇文章,提供了机器学习从业者将特别感兴趣的人工智能领域的事件细节。
Palantir 正在商谈向英国提供援助,以处理其联系和追踪系统
Palantir 是一家在过去一个月一直处于商业新闻头条的公司,这主要是由于曾经的私营公司申请首次公开募股,它已经在美国股票市场成功上市。
对于那些不知道的人,Palantir 是一家美国公司,专注于创建高效和有效的数据分析软件和工具。
该公司的创始人之一是彼得·泰尔,他是贝宝和许多其他成功的科技企业的联合创始人。
有报道称,Palantir 和英国政府官员一直在进行谈判,以确定 Palantir 如何帮助英国政府围绕其测试和跟踪计划创建一个更有效的分析系统。
Palantir 对于从以数据为中心的角度与各国合作处理新冠肺炎疫情并不陌生。这家数据分析公司已经与全球多个国家和美国疾病控制和预防中心合作。
可能值得注意的是,英国公共医疗保健系统 NHS(国家医疗服务)已经通过利用其一些数据分析软件获得了 Palantir 的帮助。
点击以下链接了解更多信息。
[## 英国正与 Palantir 就测试和追踪计划进行谈判
英国政府已与美国数据分析公司 Palantir 举行会谈,试图支持其苦苦挣扎的…
www.ft.com](https://www.ft.com/content/6f6575a8-799f-42a4-b1cc-3f7452b2166f) [## 英国正与 Palantir 就新冠肺炎测试与跟踪计划进行谈判
(路透社)-英国政府正在与美国数据分析公司 Palantir Technologies Inc .进行谈判,试图…
uk.reuters.com](https://uk.reuters.com/article/us-health-coronavirus-britain-palantir-idUKKBN27J2HL)
人工智能通过听到你的咳嗽来执行新冠肺炎检测
麻省理工学院的研究人员开发了一种利用人工智能的新冠肺炎探测方法。
开发的人工智能模型可以从通过手机和网络浏览器捕获的咳嗽音频样本中检测到新冠肺炎。
研究人员报告说,人工智能模型可以拾取指标的微小变化,然后用于检测个体中的新冠肺炎。
在研究论文中,这些指标被称为生物标志物。生物标记是肌肉退化、声带变化、情绪变化以及肺部和呼吸系统内的变化。
人工智能模型是神经网络和设计算法的结合,可以拾取生物标志物的微小变化,并从咳嗽样本中准确检测新冠肺炎。
该模型从可用的咳嗽样本中检测新冠肺炎的准确率达到了令人印象深刻的 98.5%。
研究人员希望人工智能模型可以集成到移动应用程序中。在移动应用程序中工作的人工智能模型可以促进在人群中对新冠肺炎的日常监控。
以下资源提供了更多信息:
[## 仅使用咳嗽记录的新冠肺炎人工智能诊断
IEEE Xplore,提供对世界上最高质量的工程和…
ieeexplore.ieee.org](https://ieeexplore.ieee.org/document/9208795) [## 人工智能模型通过手机记录检测无症状新冠肺炎感染…
根据定义,感染新冠肺炎病毒的无症状患者没有可辨别的身体症状
news.mit.edu](https://news.mit.edu/2020/covid-19-cough-cellphone-detection-1029)
英特尔正在通过更多的收购来加强其人工智能部门
英特尔最近收购了两家专注于机器学习的公司,以推动芯片制造公司进入人工智能领域。
英特尔最新收购的两家公司包括 Cnvrg.io 和 SigOpt 。
Cnvrg.io 是一家开发软件和工具来帮助数据科学家构建和部署机器学习模型的公司。
SigOpt 专注于通过自动模型优化和开发来优化机器学习模型。
这两家公司似乎互补,无疑将使英特尔成为全球企业人工智能市场份额争夺战中的一支强大力量。
更多信息请点击以下链接:
[## 英特尔将收购 SigOpt 以提升人工智能的生产力和性能|英特尔新闻编辑室
最新消息:今天,英特尔宣布将收购 SigOpt,这是一家总部位于旧金山的领先平台提供商
newsroom.intel.com](https://newsroom.intel.com/news/intel-to-acquire-sigopt-to-scale-ai-productivity-and-performance/#gs.kyc4eu) [## 英特尔已经收购了 Cnvrg.io,这是一个管理、构建和自动化机器学习的平台
英特尔继续收购初创公司,以建立其机器学习和人工智能运营。在最近的行动中,TechCrunch…
techcrunch.com](https://techcrunch.com/2020/11/03/intel-has-acquired-cnvrg-io-a-platform-to-manage-build-and-automate-machine-learning/)
IBM 和辉瑞合作开发可以预测阿尔茨海默病的人工智能模型
IBM 和辉瑞研究部门的合作开发了一种人工智能模型,该模型可以在临床诊断实施之前或个体出现症状之前预测个体阿尔茨海默病的早期发作。
人工智能模型的性能得分为 70%,并通过分析一到两分钟长的口头语音样本来工作。利用自然语言处理技术来分析转录的语音样本。
语音样本数据是通过弗雷明汉心脏研究提供的,该研究包含了超过 5000 个人的健康数据点。
在未来,人工智能模型可以用来帮助降低个体早期患阿尔茨海默病的风险。
更多信息请点击下面的链接。
[## 人工智能能帮助临床医生在阿尔茨海默病发展之前预测它吗?IBM 研究博客
由 IBM 和辉瑞公司开发的人工智能模型已经使用语音测试来帮助预测阿尔茨海默氏症的最终发作…
www.ibm.com](https://www.ibm.com/blogs/research/2020/10/ai-predict-alzheimers/) [## IBM 和辉瑞声称人工智能可以预测阿尔茨海默病的发作,准确率为 71%
辉瑞和 IBM 的研究人员声称已经开发出一种可以预测阿尔茨海默病的机器学习技术…
venturebeat.com](https://venturebeat.com/2020/10/22/ibm-and-pfizer-claim-ai-can-predict-alzheimers-onset-with-71-accuracy/)
结论
随着时间的推移,利用人工智能检测几种疾病正在成为现实。
很快,我们就可以期待临床医生使用人工智能嵌入式软件和硬件来改善威胁生命的疾病的早期检测。
大型科技公司在收购有前途的初创公司方面没有放缓,研究团队之间的合作越来越多,以进一步开发新技术来解决现实世界的问题,特别是关于健康的问题。
下周会有什么发展和进展,我们只能拭目以待。
我希望这篇文章对你有用。
要联系我或找到更多类似本文的内容,请执行以下操作:
关于使用 Spark 3.0 保存数据的注意事项
使用 Spark SQL 以文件格式存储数据的不同选项。
Apache Spark 是一个计算引擎,经常在大数据环境中用于数据处理,但它不提供存储,因此在典型情况下,数据处理的输出必须存储在外部存储系统中。Spark SQL 为文件格式(CSV、JSON、text、Parquet、ORC)或 JDBC 等数据源提供了一些连接器。从 2.4 开始也支持 Apache Avro,从 3.0 开始也支持二进制文件。此外,还有几个库允许连接到其他数据源,例如 MongoDB、ElasticSearch 或 DynamoDB 等等。
在本文中,我们将讨论将数据保存为 Apache Parquet 等文件格式时的一些可能性,因为 Spark 和 Parquet 的结合提供了非常好的体验,尤其是对于分析查询。我们将首先解释为什么 Parquet 是 Hadoop 生态系统中如此受欢迎的数据存储格式,然后我们将描述如何使用 Spark 保存数据的不同方法,同时特别关注官方文档中缺少或难以找到的功能。我们要研究的一个重要特性是如何以预先排序的状态保存数据,以便可以利用适当的过滤器跳过数据。
所提供的代码片段使用 Python API,并对照 Spark 3.0 和 2.4 进行了检查。
阿帕奇拼花地板
Apache Parquet 是一种开源文件格式,最初由 Twitter 和 Cloudera 开发。它是一种自描述格式,这意味着它包含带有模式信息的元数据(以及其他信息)。它使用混合模型在磁盘上存储数据,所谓混合,我们的意思是它不是严格面向行的(如 JSON 或 CSV ),也不是严格的列,而是首先将数据垂直划分为所谓的行组,然后将每个行组存储在列表示中。这些行组允许将数据集分成多个文件(每个文件可以有一个或多个行组),这样我们就不会以一个巨大的文件结束,这在大数据环境中尤其重要。
每个行组的列表示也是一个非常重要的特征,因为它允许所谓的列修剪。在分析查询中,我们通常对数据集的所有列都不感兴趣,而是选择几列并对其进行聚合。这种列删减让我们可以跳过所有其他列,只扫描那些在查询中选择的列,因此与必须扫描所有列的面向行的格式相比,它使读取更加高效。列格式的另一个优点是压缩——列中的每个值都具有相同的数据类型,并且这些值甚至可能重复,这可以用于使用各种编码和压缩技术(Parquet 支持的技术)更有效地存储数据。
Parquet 文件支持不同级别的数据跳过,即分区级别和行组级别。因此,数据集可以通过某个(通常是低基数的)键进行分区,这意味着对于该字段的每个不同值,根目录中都会有一个子文件夹,其中包含具有该特定键值的所有记录(每个分区仍可以被划分为多个文件)。分区的用例是在读取时减少数据量,因为当在过滤器中使用分区键时,Spark 将应用分区修剪,它将跳过所有与查询无关的分区(这也支持其他文件格式,如 JSON 或 CSV)。
行-组级别的数据跳过是基于 parquet 元数据的,因为每个 parquet 文件都有一个页脚,该页脚包含关于每个行-组的元数据,并且该元数据包含统计信息,例如行-组中每个列的最小值和最大值值。当读取 parquet 文件时,Spark 将首先读取页脚,并使用这些统计信息来检查给定的行组是否可能包含与查询相关的数据。这将非常有用,特别是如果 parquet 文件是按照我们用于过滤的列排序的话。因为,如果文件没有被排序,那么大小值可能分散在所有行组中,因此每个行组都必须被扫描,因为它可能包含一些过滤器满足的行。这里的排序是至关重要的,正如我们将在后面看到的,以排序后的状态保存数据是很重要的。
1.救人()
将 Spark 中的计算输出保存为文件格式的选项之一是使用 save 方法
(
df.write
.mode('overwrite') # or append
.partitionBy(col_name) # this is optional
.format('parquet') # this is optional, parquet is default
.option('path', output_path)
.save()
)
如您所见,如果您希望在保存数据的文件系统中对数据进行分区,它允许您指定分区列。默认格式是 parquet,所以如果您不指定它,它将被假定。
2.保存表()
如果您使用保存表方法保存数据,将使用数据的数据分析师可能会更加感激,因为这将允许他/她使用
df = spark.table(table_name)
保存表功能也允许使用分桶,其中每个桶也可以(可选地)排序:
(
df.write
.mode('overwrite') # or append
.partitionBy(col_name) # this is optional
.bucketBy(n, col_name) # n is number of buckets
.sortBy(col_name)
.format('parquet') # this is optional, parquet is default
.option('path', output_path)
.saveAsTable(table_name)
)
我们不会在这里深入探讨分桶,但一般来说,这是一种关于如何预混洗数据并将其保存在这种状态下的技术,以便后续查询可以利用它来避免混洗。如果使用 Spark 正确设置了 metastore,这将会起作用,因为关于分桶的信息将保存在这里。这种方法还有其他好处,因为当您稍后调用 ANALYZE TABLE 命令时,metastore 还可以保存关于数据集的其他信息,比如统计数据。 sortBy 只能在 bucketsBy 之后使用,因为要排序的是创建的 bucket。即使表还不存在,两种模式覆盖和追加在这里都有效,因为函数会简单地创建它。
3.插入()
如何保存数据的另一种可能性是使用 insertInto 功能。与前一种情况不同,该表必须首先存在,因为如果不存在,您将得到一个错误:analysis exception:Table not found。使用这个函数的语法相当简单
(
df.write
.insertInto(table_name)
)
但是有一些需要注意的警告:
- 您不必指定输出路径。Spark 将在 metastore 中找到该信息。如果您仍然指定路径,它将被忽略。
- 默认模式是 append ,所以它会简单地将您的数据添加到现有的表中。
- 数据框架的模式必须与表的模式相匹配。如果数据帧中的列顺序不同于表中的顺序,Spark 将在数据类型不同且无法安全转换时抛出异常。但是如果数据类型没有不匹配,Spark 会以这种错误的顺序将数据插入到表中。因此这是非常危险的,最好确保模式是相同的,例如:
(
df.select(spark.table(table_name).columns)
.write
.insertInto(table_name)
)
- 如果您的表是分区的或分桶的,您不需要指定这一点(您会得到一个错误),因为 Spark 将从 metastore 中选取该信息。
函数 insertInto 比 saveAsTable 有一个很大的优势,因为它允许所谓的动态覆盖。此功能允许您覆盖分区表中的特定分区。例如,如果您的表按 year 进行分区,并且您只想更新一个 year,,那么使用 saveAsTable 您将不得不覆盖整个表,但是使用 *insertInto,*您可以只覆盖这一个分区,因此这将是一个非常便宜的操作,尤其是在有许多大分区的情况下。要使用此功能,您必须设置相应的配置设置:
spark.conf.set("spark.sql.sources.partitionOverwriteMode", "dynamic")(
df # having data only for specific partitions
.write
.insertInto(table_name, overwrite=True)
)
在这里,还是要小心,因为如果将 partitionOverwriteMode 设置为 static (这是默认值),它将覆盖整个表,因此所有其他分区都将变空。动态值确保 Spark 只覆盖数据帧中有数据的分区。
以排序状态保存数据
正如我们上面提到的,有时希望根据某一列以排序状态保存数据,以便在使用该列作为过滤器的分析查询中跳过数据。在 Spark SQL 中,有三个函数用于排序。有 orderBy (或等价的 sort )、 *sortWithinPartitions、*和 sortBy。让我们看看它们之间有什么区别,以及如何使用它们:
- orderBy —这是一个将调用全局排序的数据帧转换。这将首先运行一个单独的作业,该作业将对数据进行采样,以检查排序列中值的分布。然后,该分布用于创建分区的边界,数据集将被混洗以创建这些分区。这是一个非常昂贵的操作,如果您将数据保存到一个分区表中,并且如果集群上的数据分布与文件系统中的表的最终分布非常不同,则可能会创建许多小文件(例如,如果您按日期排序,并且您的表按国家分区,则 Spark 作业最后阶段的每个任务都可能携带每个国家的数据,因此每个任务都会向每个文件系统分区中写入一个新文件)。
- sort within partitions—这也是一个数据帧转换,与前面的情况不同,Spark 不会尝试实现全局排序,而是将每个分区分别排序。所以在这里,您可以使用 repartition() 函数(这也将创建一个 shuffle)在 Spark 集群上分发您所需要的数据,然后调用 sortWithinPartitions 对每个分区进行排序。与前一种方法相比,这种方法的优点是您可以避免拥有大量小文件,并且仍然可以对输出进行排序。
- sortBy —如果我们也调用 bucketBy 并使用 saveAsTable 方法进行保存,则可以在data frame writer上调用该函数(在调用 df.write 之后)。它将确保每个存储桶都被排序(一个存储桶可以是一个文件,也可以是多个文件,这取决于写本文时 Spark 集群上的数据分布)。
使用前两个函数有一个大问题,你在文档中找不到(写于 2020 年 10 月)。让我们看一个简单的例子。为了简单起见,我们希望按照年对数据进行分区,并按照 user_id 对每个分区进行排序,为了保存,我们使用 saveAsTable() 。如果你只是打电话
(
df.repartition('year')
.sortWithinPartitions('user_id')
.write
.mode('overwrite')
.partitionBy('year')
.option('path', output_path)
.saveAsTable(table_name)
)
这是行不通的!不会产生任何错误,会保存数据,但订单不会被保留!重点是,当将数据写入文件格式时,Spark 要求这种排序:
(partitionColumns + bucketIdExpression + sortColumns
)
这里的 partitionColumns 是我们将数据分区到文件系统所依据的列,bucketingiexpression是从 bucketing 列派生而来的(与我们的查询无关,因为我们在这里没有使用 bucketing),而 sortColumns 是在带有 bucketing 的 sortBy 中使用的列(同样与我们的查询无关)。如果数据是按照这些列(可能还有更多)排序的,那么这个要求将会得到满足,Spark 将会保持这个顺序。但是,如果不满足这个要求,Spark 将会忘记之前的顺序,并在写入数据时根据这个要求再次对数据进行排序。在我们的示例中,所需的排序是( year ),这是分区列,我们在这里没有任何存储桶。然而,这一要求并没有得到满足,因为实际的排序是( user_id ),这是我们对数据进行排序的列,这就是为什么 Spark 不会保留我们的顺序,而是按照 year 列再次对数据进行排序。
required_orering = (year)
actual_ordering = (user_id) ... this doesn't satisfy the requirement
为了实现我们的目标并保存按 user_id 排序的数据(每个分区),我们可以这样做:
(
df.repartition('year')
**.sortWithinPartitions('year', 'user_id')**
.write
.mode('overwrite')
.partitionBy('year')
.option('path', output_path)
.saveAsTable(table_name)
)
注意现在的区别,我们按照年和用户 id 对每个分区进行显式排序,但是由于数据将按照年进行分区,因此按照该列进行排序并不重要。重要的是,现在 Spark 的要求将得到满足,因此 Spark 将保留我们的顺序并保存按年和 user_id 排序的数据,由于我们按年分区,这基本上意味着每个分区将按 user_id 排序,这正是我们想要的。
required_orering = (year)
actual_ordering = (year, user_id) ... this satisfies the requirement
在每个分区排序的位置保存分区数据,将允许使用过滤器进行高效的分析查询,该过滤器将跳过两个级别上的数据—分区级别和行组级别。想象这样一个查询:
(
spark.table(table_name)
.filter(col('year') == 2020)
.filter(col('user_id') == 1)
.collect()
)
这将首先使用分区过滤器来修剪分区,并且在该单个分区 2020 内,它将检查来自每个行组的镶木地板脚的元数据。基于元数据中的统计数据,Spark 将挑选最小小于等于 1 且最大大于等于 1 的行组,并且只扫描这些行组,因此这将加快查询速度,尤其是在有许多行组可以跳过的情况下。
结论
在本文中,我们描述了如何使用 Spark 将数据保存为文件格式(特别是 Apache Parquet)的三种不同方式,还解释了为什么 Parquet 是如此流行的数据格式,尤其是在分析查询中。我们还指出了一些不太明显的 Spark 特性,比如 insertInto 函数的行为或者如何在排序状态下保存数据。
图论的注记——中心性测度
关于不同中心性度量的注记:定义和权衡
作者图片
介绍
中心性测量是分析网络的重要工具,无论是国家道路网络还是电力网络,您都希望确定主要城市,并确定需要维护的关键节点,以消除未来对网络的干扰。所有这些分析都可以使用一些简单的拓扑测量来完成,这些测量根据节点作为大网络的一部分的重要性来评分。
图论:导论
首先,我将通过给出图形抽象的定义和数学表示来介绍图形抽象,因为我们以后会用到它。
图形定义
图表无处不在,它是一个非常适合的工具来呈现数据,其中连接和链接对于我们理解它很重要。就像分子结构呈现出基本原子的集合,这些原子相互连接,形成复杂的结构,在这个集合中每个原子的连接意味着这个分子的用法或特征,事实上,改变其中一个连接可以给你一个完全不同的分子。
这个例子将帮助我们理解一个图的基本结构,这个图是由一堆通过边连接的节点生成的。基础解剖学?是的,但是继续添加这些节点和边,你可以创建一些曾经存在的复杂网络。以脸书为例,节点是用户,边是友谊或追随者。
一个有 5 个节点和 5 条边的图的例子(图片由作者提供)
图形数学演示
如前所述,图表可以发展成为复杂的结构,以脸书社交网络为例。因此,仅仅通过视觉观察很难研究它,因此,我们需要建立数学工具来帮助我们理解或分析我们的图形结构。
我们从作为数学对象的图形定义开始。一个图是由它的一组节点和一组边定义的,所以一个图 G 被定义为:
图表的数学表示(作者提供的图片)
n 表示图中的节点集,E 是边集。我们还将图的范数定义为节点数
邻接矩阵
正如我之前所说的,我们不能仅仅使用图形的几何形状来分析它们,但是我们需要某种工具来封装我们图形中的信息,并且容易对其进行数学分析。
为此,我们将邻接矩阵定义为二进制 2d 数组 n*n,其中 n 表示节点的数量。如果两个节点链接,则每个值可以是 1,否则将是 0。正如你在例子中看到的,无向图(一种图形结构)的邻接矩阵是对称的,我们将在接下来的故事中看到更多。
邻接矩阵示例(图片由作者提供)
图论:中心性测量
现在我们已经建立了关于图的基本概念,我们准备通过给出它们的定义和用法来发现中心性度量。我还将尝试以一种您可以轻松看到何时使用每种措施的方式对它们进行排序。
中心性度量是给予图中每个节点的标量值,以基于假设量化其重要性。
节点度
- 定义
节点度是基本的中心性度量之一。等于节点邻居的数量。因此,一个节点的邻居越多,它就越是中心的和高度连通的,因此对图有影响。
节点 Ni 的节点度为 1 /节点 Nj 的节点度为 4(图片由作者提供)
- 节点度是局部的,不是全局的
虽然节点度给了我们一个关于每个节点连通性的概念,但是它是一个局部的度量,并不能展示全局。让我给你举个例子:
这两个节点具有相同的度数(图片由作者提供)
如您所见,这两个节点具有相同数量的邻居,这意味着它们具有相同的节点度,但看看它们的邻居,节点 1 连接到度数较高的节点,因此如果我们基于连通性进行选择,我们肯定会选择它,因此节点度作为一种度量没有考虑邻居连通性这就是为什么我们称之为局部度量。
特征中心性
- 定义
特征向量中心性测量节点的重要性,同时考虑其邻居,换句话说,它测量节点的度,但更进一步,通过计算其连接(邻居)有多少条链路。它使用邻接矩阵的分解。因此每个节点 I 的特征中心性是具有最大特征值的矩阵特征向量的第 I 个条目。
特征中心性定义(图片由作者提供)
- 轮毂偏置
我们已经看到,特征中心性是全局的,因为它奖励具有高的和重要的连通性(在数量和质量方面的连接)的节点。但是想象一下添加一个新节点并将其连接到一个 hub 节点。该节点将具有较低的度数,但是具有较高的特征中心性,因为它的邻居是集线器(度数较高的节点)。为了澄清这一点,想象一下你刚到脸书,你开始关注巴拉克·奥巴马或一个受欢迎的人,这并不意味着你在网络中是那么重要。
作者图片
PageRank 中心性
以减少假的或有偏差的中心节点的危险。谷歌创始人拉里·佩奇(Larry Page)和谢尔盖·布林(Sergei Brin)发明了一种新的中心性衡量标准( PageRank ),这种衡量标准使用一种阻尼因子来平抑/减弱中枢连接的影响。
页面等级中心性测量使用阻尼因子来控制邻居对您的节点的影响,同时测量其重要性。(图片由作者提供)
接近中心性
这种类型的中心性根据与其他节点的连接来衡量节点效率。当尝试使用较少的链路向其他节点发送信号时,哪个节点效率更高?为了更好地理解这一点,让我再举一个例子。
想象一下,我们有一个道路网络,城市是你的节点,道路是边。你拥有一家服装公司,你想安装一个新的仓储设施,为所有城市的客户供货。一般来说,你会选择把它放在一个离所有其他城市都近的城市,以减少你的运输成本。
对于这个用例,接近中心性将是选择您的位置的一个很好的度量,因为它测量平均路径长度**。**因此,你的亲密度中心值越高,你的节点离你网络中的其他节点就越近。
亲近中心性公式(作者图片)
中间中心性
在强调最短路径方面,接近接近中心性的度量是中间中心性。它测量我们研究的节点所在的最短路径的百分比**。因此,具有高介数中心性的节点可能对其他节点之间传递的信息具有相当大的影响。因此它们代表了网络的关键部分,因为移除它们会破坏图中顶点(节点)之间的链接。**
外卖点
正如您所看到的,中心性度量为节点提供了一个易于解释的标量分数,还可以帮助您根据重要性和关键程度比较网络中的节点。
另一个要点是,每个中心性度量都有一个背景假设,例如,紧密度和介数中心性将重要性定义为图中信息流的节点效率。其他如特征中心性或度中心性奖励高度连接的节点。所以我给你的建议是,使用一个基于你的研究案例的中心性测量,如果你想更进一步,你可以把它们结合成一个适合你问题需要的一般中心性测量。
最后,如果你正在使用 python,我建议你使用已经实现了这些中心化措施的 Networkx 库,所以花些时间来使用它们。不久我们将看到另一个关于图论的故事。
资源:
没什么特别的——但是 16 个必要的操作让你开始接触熊猫
使用 Pandas 的基本数据处理技能概述
Python 已经成为许多数据科学家和机器学习研究人员的首选编程语言。熊猫图书馆是他们做出这一选择的一个重要的数据处理工具。当然,pandas 库是如此通用,以至于它可以用于几乎所有的初始数据操作,以便为进行统计分析或建立机器学习模型准备好数据。
然而,对于同样的多功能性,开始舒适地使用它可能会令人不知所措。如果你正在纠结如何开始,这篇文章很适合你。本文的目的不是介绍太多而失去要点,而是概述您希望在日常数据处理任务中使用的关键操作。每个关键操作都有一些需要考虑的重要参数。
当然,第一步是安装熊猫,你可以按照这里的说明使用pip
或conda
。在编码环境方面,我推荐 Visual Studio Code,JupyterLab,或者 Google Colab,所有这些都需要很少的努力就可以设置好。当安装完成后,在您首选的编码环境中,您应该能够将 pandas 导入到您的项目中。
import pandas as pd
如果您运行上面的代码没有遇到任何错误,您就可以开始了。
1.读取外部数据
在大多数情况下,我们从外部来源读取数据。如果我们的数据是类似电子表格的格式,下面的函数应该可以满足目的。
*# Read a comma-separated file* df = pd.read_csv(**"the_data.csv"**)*# Read an Excel spreadsheet* df = pd.read_excel(**"the_data.xlsx"**)
- 应该正确处理标题。默认情况下,读数将假定第一行数据是列名。如果它们没有标题,你必须指定它(如
header=None
)。 - 如果你正在读取一个制表符分隔的文件,你可以通过指定制表符作为分隔符来使用
read_csv
(例如sep=“\t”
)。 - 当你读一个大文件时,读一小部分数据是一个好主意。在这种情况下,您可以设置要读取的行数(例如
nrows=1000
)。 - 如果您的数据涉及日期,您可以考虑设置参数使日期正确,例如
parse_dates
和infer_datetime_format
。
2.创建系列
在清理数据的过程中,您可能需要自己创建系列。在大多数情况下,您只需传递一个 iterable 来创建一个系列对象。
*# Create a Series from an iterable* integers_s = pd.Series(range(10))# Create a Series from a dictionary object
squares = {x: x*x for x in range(1, 5)}
squares_s = pd.Series(squares)
- 您可以通过设置
name
参数为系列对象指定一个名称。如果该名称成为 DataFrame 对象的一部分,它将成为该名称。 - 如果您发现索引比默认的基于 0 的索引更有用,您也可以将索引分配给系列(例如,设置
index
参数)。请注意,索引的长度应该与数据的长度相匹配。 - 如果你从一个字典创建一个系列对象,这些键将成为索引。
3.构建数据框架
通常,您需要使用 Python 内置对象创建 DataFrame 对象,比如列表和字典。下面的代码片段突出了两个常见的使用场景。
*# Create a DataFrame from a dictionary of lists as values* data_dict = {**'a'**: [1, 2, 3], **'b'**: [4, 5, 6], **'c'**: [7, 8, 9]}
data_df0 = pd.DataFrame(data_dict)
*# Create a DataFrame from a list* data_list = [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
data_df1 = pd.DataFrame(data_list, columns=tuple(**'abc'**))
- 第一个使用了一个字典对象。它的键将成为列名,而它的值将成为相应列的值。
- 第二个使用了一个列表对象。与前面的方法不同,构造的数据帧将按行使用数据,这意味着每个内部列表将成为创建的数据帧对象的一行。
4.数据帧概述
当我们有了要处理的数据框架时,我们可能想看看 30,000 英尺高度的数据集。您可以使用几种常见的方法,如下所示。
*# Find out how many rows and columns the DataFrame has* df.shape
*# Take a quick peak at the beginning and the end of the data* df.head()
df.tail()*# Get a random sample* df.sample(5)*# Get the information of the dataset* df.info()*# Get the descriptive stats of the numeric values* df.describe()
- 检查头部和尾部非常重要,尤其是在处理大量数据时,因为您希望确保所有数据都已被完整读取。
info()
函数将根据数据类型和项目计数给出列的概述。- 获取数据的随机样本来检查数据的完整性也很有趣(即
sample()
函数)。
5.重命名列
您注意到数据的某些列没有太多意义,或者名称太长而无法使用,您想要重命名这些列。
*# Rename columns using mapping* df.rename({**'old_col0'**: **'col0'**, **'old_col1'**: **'col1'**}, axis=1)
*# Rename columns by specifying columns directly* df.rename(columns={**'old_col0'**: **'col0'**, **'old_col1'**: **'col1'**})
- 如果您只是提供一个映射对象(例如, dict ),那么您需要指定
axis=1
来重命名列。 - 或者,您可以显式地将映射对象指定给
columns
参数。 - 默认情况下,
rename
函数将创建一个新的数据帧。如果你想就地重命名数据帧,你需要指定inplace=True
。
6.排序数据
为了使你的数据更加结构化,你需要对 DataFrame 对象进行排序。
*# Sort data* df.sort_values(by=[**'col0'**, **'col1'**])
- 默认情况下,
sort_values
函数将对您的行进行排序(axis=0
)。在大多数情况下,我们使用列作为排序关键字。 - 默认情况下,
sort_values
函数将创建一个排序后的数据帧对象。要改变它,使用inplace=True
。 - 默认情况下,所有排序关键字的排序都基于升序。如果要使用降序,请指定
ascending=False
。如果您想要混合排序(例如,一些键是升序,一些键是降序),您可以创建一个布尔值列表来匹配键的数量,比如by=[‘col0’, ‘col1’, ‘col2’], ascending=[True, False, True]
。 - 原始索引将包含它们的旧数据行。在许多情况下,您需要重新索引。不用直接调用 rese
t
_index 函数,可以指定ignore_index
为True
,排序完成后会为你重置索引。
7.处理重复
在现实生活的数据集中,包含重复记录是很常见的情况,要么是人为错误,要么是数据库故障。我们希望删除这些重复项,因为它们会在以后导致意想不到的问题。
*# To examine whether there are duplicates using all columns* df.duplicated().any()
*# To examine whether there are duplicates using particular columns* df.duplicated([**'col0'**, **'col1'**]).any()
上述函数将返回一个布尔值,告诉您数据集中是否存在任何重复的记录。要找出重复记录的确切数量,您可以使用sum()
函数,利用从duplicated()
函数返回的布尔值系列对象(Python 将True
视为值 1),如下所示。另外需要注意的是,当参数keep
被设置为False
时,它会将任何重复标记为True
。假设有三条重复记录,当keep=False
时,两条记录都会被标记为True
(即正在重复)。当keep= “first”
或keep=“last”
时,只有第一条或最后一条记录标记为True
。
*# To find out the number of duplicates* df.duplicated().sum()
df.duplicated(keep=False).sum()
为了实际查看复制的记录,您需要使用生成的复制的系列对象从原始数据集中选择数据,如下所示。
*# Get the duplicate records* duplicated_indices = df.duplicated([**'col0'**, **'col1'**], keep=False)duplicates = df.loc[duplicated_indices, :].sort_values(by=[**'col0'**, **'col1'**], ignore_index=True)
- 我们通过将
keep
参数设置为False
来获得所有重复的记录。 - 为了更好地查看重复记录,您可能希望使用相同的一组键对生成的数据帧进行排序。
一旦您对数据集的重复记录有了一个好的想法,您可以像下面这样删除它们。
*# Drop the duplicate records* df.drop_duplicates([**'col0'**, **'col1'**], keep=**"first"**, inplace=True, ignore_index=True)
- 默认情况下,保存的记录将是第一个副本。
- 如果您想就地更新数据帧,您需要指定
inplace=True
。BTW:许多其他函数都有这个选项,即使不是全部,大多数时候也不会讨论这个问题。 - 与
sort_values()
函数一样,您可能希望通过指定ignore_index
参数来重置索引(熊猫 1.0 中的一个新特性)。
8.处理丢失的数据
缺失数据在现实生活的数据集中很常见,这可能是由于测量值不可用或只是人为数据输入错误导致无意义的数据被视为缺失。为了对您的数据集有多少缺失值有一个总体的概念,您已经看到 info()函数告诉我们每一列有多少非空值。我们可以通过更结构化的方式获得关于数据缺失的信息,如下所示。
*# Find out how many missing values for each column* df.isnull().sum()
*# Find out how many missing values for the entire dataset* df.isnull().sum().sum()
isnull()
函数创建一个与原始数据帧形状相同的数据帧,每个值表示原始值缺失(True
)或不缺失(False
)。相关的注意事项是,如果您想生成一个指示非空值的数据帧,您可以使用notnull()
函数。- 如前所述,Python 中的
True
值在算术上等于 1。sum()
函数将为每一列计算这些布尔值的总和(默认情况下,它按列计算总和),这反映了缺失值的数量。
通过对数据集的缺失有所了解,我们通常想要处理它们。可能的解决方案包括删除带有任何缺失值的记录,或者用适用的值填充它们。
*# Drop the rows with any missing values* df.dropna(axis=0, how=**"any"**)
*# Drop the rows without 2 or more non-null values* df.dropna(thresh=2)
*# Drop the columns with all values missing* df.dropna(axis=1, how=**"all"**)
- 默认情况下,
dropna()
函数按列工作(即axis=0
)。如果指定how=“any”
,将会删除任何缺少值的行。 - 当您设置
thresh
参数时,它要求行(或当axis=1
时的列)具有非缺失值的数量。 - 与许多其他功能一样,当您设置
axis=1
时,您正在按列执行操作。在这种情况下,上面的函数调用将删除那些所有值都丢失的列。
除了删除带有缺失值的数据行或列的操作之外,还可以用一些值来填充缺失值,如下所示。
*# Fill missing values with 0 or any other value is applicable* df.fillna(value=0)*# Fill the missing values with customized mapping for columns* df.fillna(value={**"col0"**: 0, **"col1"**: 999})*# Fill missing values with the next valid observation* df.fillna(method=**"bfill"**)
*# Fill missing values with the last valid observation* df.fillna(method=**"ffill"**)
- 要用指定的值填充缺失的值,您可以将 value 参数设置为所有值的固定值,也可以设置一个 dict 对象,该对象将指示基于每列的填充。
- 或者,您可以通过使用缺失孔周围的现有观测值来填充缺失值,回填或向前填充。
9.分组描述性统计
当您进行机器学习研究或数据分析时,通常需要对一些分组变量执行特定操作。在这种情况下,我们需要使用groupby()
函数。下面的代码片段向您展示了一些适用的常见场景。
*# Get the count by group, a 2 by 2 example* df.groupby([**'col0'**, **'col1'**]).size()
*# Get the mean of all applicable columns by group* df.groupby([**'col0'**]).mean()
*# Get the mean for a particular column* df.groupby([**'col0'**])[**'col1'**].mean()
*# Request multiple descriptive stats* df.groupby([**'col0'**, **'col1'**]).agg({
**'col2'**: [**'min'**, **'max'**, **'mean'**],
**'col3'**: [**'nunique'**, **'mean'**]
})
- 默认情况下,
groupby()
函数将返回一个 GroupBy 对象。如果你想把它转换成一个数据帧,你可以调用对象上的reset_index()
。或者,您可以在groupby()
函数调用中指定as_index=False
来直接创建一个数据帧。 - 如果您想知道每组的频率,则
size()
很有用。 agg()
功能允许您生成多个描述性统计数据。您可以简单地传递一组函数名,这将应用于所有列。或者,您可以传递一个带有函数的 dict 对象来应用于特定的列。
10.宽到长格式转换
根据数据的收集方式,原始数据集可能是“宽”格式,每一行代表一个具有多个测量值的数据记录(例如,研究中某个主题的不同时间点)。如果我们想要将“宽”格式转换为“长”格式(例如,每个时间点变成一个数据行,因此一个主题有多行),我们可以使用melt()
函数,如下所示。
从宽到长的转换
melt()
函数本质上是“取消透视”一个数据表(我们接下来将讨论透视)。您将id_vars
指定为在原始数据集中用作标识符的列。- 使用包含值的列设置
value_vars
参数。默认情况下,这些列将成为融合数据集中var_name
列的值。
11.长到宽格式转换
与melt()
功能相反的操作叫做旋转,我们可以用pivot()
功能来实现。假设创建的“宽”格式数据帧被称为df_long
。下面的函数向您展示了如何将宽格式转换为长格式——基本上与我们在上一节中所做的过程相反。
从长到宽的转变
除了pivot()
函数之外,一个密切相关的函数是pivot_table()
函数,它比pivot()
函数更通用,允许重复的索引或列(更详细的讨论见此处的)。
12.选择数据
当我们处理一个复杂的数据集时,我们需要根据一些标准为特定的操作选择数据集的一个子集。如果您选择一些列,下面的代码将向您展示如何操作。所选数据将包括所有行。
*# Select a column* df_wide[**'subject'**]
*# Select multiple columns* df_wide[[**'subject'**, **'before_meds'**]]
如果要选择包含所有列的特定行,请执行下列操作。
*# Select rows with a specific condition* df_wide[df_wide[**'subject'**] == 100]
如果你想选择某些行和列,我们应该考虑使用iloc
或loc
方法。这些方法的主要区别在于iloc
方法使用基于 0 的索引,而loc
方法使用标签。
数据选择
- 以上几对调用创建了相同的输出。为了清楚起见,只列出了一个输出。
- 当您将 slice 对象与
iloc
一起使用时,不包括停止索引,就像常规的 Python slice 对象一样。然而,切片对象在loc
方法中包含停止索引。请参见第 15–17 行。 - 如第 22 行所示,当您使用布尔数组时,您需要使用实际值(使用 values 方法,这将返回底层 numpy 数组)。如果不这样做,您可能会遇到下面的错误:
NotImplementedError: iLocation based boolean indexing on an integer type is not available
。 - 在选择行方面,
loc
方法中标签的使用恰好与索引相同,因为索引与索引标签同名。换句话说,iloc
将始终根据位置使用基于 0 的索引,而不管索引的数值。
13.使用现有数据的新列(映射和应用)
现有列并不总是以我们想要的格式显示数据。因此,我们经常需要使用现有数据生成新列。这种情况下有两个函数特别有用:map()
和apply()
。我们有太多的方法可以使用它们来创建新的列。例如,apply()
函数可以有一个更复杂的映射函数,它可以创建多个列。我将向您展示两个最常用的案例,并遵循以下经验法则。让我们的目标保持简单——只需用任一用例创建一个列。
- 如果您的数据转换只涉及一列,只需对该列使用
map()
函数(本质上,它是一个系列对象)。 - 如果您的数据转换涉及多列,请使用
apply()
功能。
映射并应用
- 在这两种情况下,我都使用了 lambda 函数。但是,您可以使用常规函数。还可以为
map()
函数提供一个 dict 对象,它将基于键-值对将旧值映射到新值,其中键是旧值,值是新值。 - 对于
apply()
函数,当我们创建一个新列时,我们需要指定axis=1
,因为我们是按行访问数据的。 - 对于 apply()函数,所示的例子是为了演示的目的,因为我可以使用原来的列做一个更简单的算术减法,如下所示:
df_wide[‘change’] = df_wide[‘before_meds’] —df_wide[‘after_meds’]
。
14.连接和合并
当我们有多个数据集时,有必要不时地将它们放在一起。有两种常见的情况。第一种情况是当您有相似形状的数据集,或者共享相同的索引或者相同的列时,您可以考虑直接连接它们。下面的代码向您展示了一些可能的连接。
*# When the data have the same columns, concatenate them vertically* dfs_a = [df0a, df1a, df2a]
pd.concat(dfs_a, axis=0)
*# When the data have the same index, concatenate them horizontally* dfs_b = [df0b, df1b, df2b]
pd.concat(dfs_b, axis=1)
- 默认情况下,串联执行“外部”连接,这意味着如果有任何不重叠的索引或列,它们都将被保留。换句话说,这就像创建两个集合的并集。
- 另一件要记住的事情是,如果您需要连接多个数据帧对象,建议您创建一个列表来存储这些对象,并且如果您按顺序执行连接,通过避免生成中间数据帧对象,只执行一次连接。
- 如果您想重置串联数据帧的索引,您可以设置
ignore_index=True
参数。
另一种情况是合并具有一个或两个重叠标识符的数据集。例如,一个数据帧有身份证号、姓名和性别,另一个有身份证号和交易记录。您可以使用 id 号列合并它们。下面的代码向您展示了如何合并它们。
*# Merge DataFrames that have the same merging keys* df_a0 = pd.DataFrame(dict(), columns=[**'id'**, **'name'**, **'gender'**])
df_b0 = pd.DataFrame(dict(), columns=[**'id'**, **'name'**, **'transaction'**])
merged0 = df_a0.merge(df_b0, how=**"inner"**, on=[**"id"**, **"name"**])
*# Merge DataFrames that have different merging keys* df_a1 = pd.DataFrame(dict(), columns=[**'id_a'**, **'name'**, **'gender'**])
df_b1 = pd.DataFrame(dict(), columns=[**'id_b'**, **'transaction'**])
merged1 = df_a1.merge(df_b1, how=**"outer"**, left_on=**"id_a"**, right_on=**"id_b"**)
- 当两个 DataFrame 对象共享相同的一个或多个键时,可以使用
on
参数简单地指定它们(一个或多个都可以)。 - 当它们有不同的名称时,您可以指定哪个用于左数据帧和哪个用于右数据帧。
- 默认情况下,合并将使用内部联接方法。当您希望有其他连接方法(例如,left、right、outer)时,您可以为
how
参数设置适当的值。
15.删除列
虽然您可以通过重命名数据帧中的所有列而不产生任何冲突,但有时您可能希望删除一些列以保持数据集的整洁。在这种情况下,你应该使用drop()
功能。
*# Drop the unneeded columns* df.drop([**'col0'**, **'col1'**], axis=1)
- 默认情况下,
drop()
函数使用标签来引用列或索引,因此您可能希望确保标签包含在 DataFrame 对象中。 - 要删除索引,您可以使用
axis=0
。如果您删除列,我发现它们更常见,您可以使用axis=1
。 - 同样,该操作创建了一个数据帧对象,如果您喜欢更改原始的数据帧,您可以指定
inplace=True
。
16.写入外部文件
当您希望与合作者或队友交流数据时,您需要将 DataFrame 对象写入外部文件。在大多数情况下,逗号分隔的文件应该可以满足要求。
*# Write to a csv file, which will keep the index* df.to_csv(**"filename.csv"**)
*# Write to a csv file without the index* df.to_csv(**"filename.csv"**, index=False)
*# Write to a csv file without the header* df.to_csv(**"filename.csv"**, header=False)
- 默认情况下,生成的文件将保留索引。您需要指定
index=False
来从输出中删除索引。 - 默认情况下,生成的文件将保留标题(例如,列名)。您需要指定
header=False
来移除标题。
结论
在本文中,我们回顾了一些基本操作,您会发现它们对您开始使用 pandas 库很有用。正如文章标题所示,这些技术并不打算以一种奇特的方式处理数据。相反,它们都是允许你以你想要的方式处理数据的基本技术。稍后,您可能会找到更好的方法来完成一些操作。
用 Python 通知
使用 Python 构建的电子邮件通知让生活更轻松
西蒙·米加杰在 Unsplash上的照片
在 Python 中工作,我经常运行数据处理、传输和模型训练脚本。现在,对于任何合理程度的复杂性和/或大数据,这都需要一些时间。
虽然在等待这些处理过程完成的时候,我们经常都有一些其他的工作要做,但有时我们并没有。
为此,我整理了一组专门为这个问题构建的 Python 脚本。我使用这些脚本向我的手机发送流程更新、可视化和完成通知。
所以,当我们偶尔有自由的时候。我们可以享受它们,而不用担心模型的进展。
我们需要什么
好的,我们需要问的第一件事是— 我们需要知道什么?
当然,这取决于你正在做的工作。对我来说,我有三个主要的处理任务可能会占用时间:
- 模型训练
- 数据处理和/或传输
- 财务建模
对于其中的每一个,当然都有不同的信息需要我们了解。让我们来看一个例子。
模特培训
每 n 个时期更新**,必须包括关键指标。例如,训练集和验证集的损失和准确性。**
完成通知(当然)。为此,我喜欢包括:
- 预测输出,用于文本生成,生成的文本(或其样本)——用于图像生成,一个(希望)酷的可视化。
- 培训期间关键指标的可视化(同样,培训和验证集的损失和准确性)
- 其他不太重要但仍然有用的信息,如本地模型目录、培训时间、模型架构等
让我们以训练神经网络来再现给定的艺术风格为例。
对于这一点,我们希望看到;从模型生成的图像、损失和精度图、当前训练时间和模型名称。
在这种情况下,每隔 100 个时期,就会发送一封包含上述所有内容的电子邮件。这是其中一封电子邮件:
数据处理和传输
这一个稍微不那么迷人,但是就消耗的时间而言,遥遥领先。
我们将使用 Python 向 SQL Server 批量上传数据的例子(对于我们这些没有BULK INSERT
的人)。
在上传脚本的末尾,我们包含了一条简单的消息,通知我们上传完成。
如果偶尔抛出错误,我们还可以添加一个 try-except 子句来捕获错误,并将其添加到一个列表中,以包含在我们的更新和/或完成电子邮件中。
金融建模
在金融建模的情况下,我运行的一切实际上都相当快,所以我只能在这里给你提供一个“示例”用例。
我们将使用现金流建模工具的例子。实际上,这个过程不超过 10-20 秒,但是现在让我们假设我们是华尔街的热门 quants,处理几百万(而不是几百)贷款。
在这封电子邮件中,我们可能希望包含对所分析的投资组合的高层次总结。我们可以随机选择一些贷款并可视化给定时间段内的关键价值——给我们一个小样本来交叉检查模型性能是意料之中的。
代码
上述所有功能都来自一个名为notify.py
的脚本。
我们将在示例代码中使用 Outlook。然而,将它翻译给其他提供者是非常容易的,我们将在最后快速介绍这一点。
这里我们需要两个 Python 库,email
和smtplib
。
[**email**](https://docs.python.org/3/library/email.html)
—用于管理电子邮件信息。这样,我们将设置电子邮件本身,包括主题、正文和附件。[**smtplib**](https://docs.python.org/3/library/smtplib.html)
—处理 SMTP 连接。简单邮件传输协议(SMTP)是大多数电子邮件系统使用的协议,允许通过互联网发送邮件。’
哑剧
消息本身是使用来自email
模块的MIMEMultipart
对象构建的。我们还使用了三个 MIME 子类,我们将它们attach
到MIMEMultipart
对象:
MIMEText
—这将包含电子邮件“有效载荷”,即电子邮件正文中的文本。MIMEImage
—很容易猜到,这是用来在我们的电子邮件中包含图像的。MIMEApplication
—用于 MIME 消息应用对象。对我们来说,这些是文件附件。
除了这些子类,还有其他参数,比如MimeMultipart
中的Subject
值。所有这些一起给了我们下面的结构。
让我们看看如何将这些放在一起。
这个脚本在很大程度上相当简单。在顶部,我们有我们的导入——这是我们之前讨论过的 MIME 部分,以及 Python 的os
库。
接下来定义一个名为message
的函数。这允许我们用不同的参数调用函数,并轻松地构建电子邮件消息对象。例如,我们可以编写一封包含多个图像和附件的电子邮件,如下所示:
email_msg = message(
text="Model processing complete, please see attached data.",
img=['accuracy.png', 'loss.png'],
attachments=['data_in.csv', 'data_out.csv']
)
首先我们初始化MIMEMultipart
对象,将其赋给msg
。
然后我们使用'Subject'
键设置邮件主题。
attach
方法允许我们向MIMEMultipart
对象添加不同的 MIME 子类。这样我们就可以使用MIMEText
子类来添加邮件正文。
对于图像img
和附件attachment
,我们可以什么都不传递,传递一个文件路径,或者传递一个文件路径列表。
这是通过首先检查参数是否是None
来处理的,如果是,我们通过。否则,我们检查给定的数据类型,如果它不是一个list
,我们把它变成一个——这允许我们使用下面的for
循环来迭代我们的项目。
此时,我们使用MIMEImage
和MIMEApplication
子类来分别附加我们的图像和文件。对于这两种情况,我们都使用os.basename
从给定的文件路径中检索文件名,我们将其作为附件名。
简单邮件传输协议
现在我们已经建立了电子邮件对象,我们需要发送它。
这就是smtplib
模块的用武之地。代码也很简单,除了一个例外。
因为我们直接与不同的电子邮件提供商及其各自的服务器打交道,所以我们需要不同的 SMTP 地址。幸运的是,这个真的很好找。
在谷歌中输入*“outlook SMTP”*。甚至不用点击页面,我们就能得到服务器地址smtp-mail.outlook.com
和端口号587
。
当用smtplib.SMTP
初始化SMTP
对象时,我们使用这两种方法——在send
函数的开头附近。
smtp.ehlo()
和smtp.starttls()
都是 SMTP 命令。ehlo
(扩展 Hello)本质上是问候服务器。starttls
通知服务器我们将使用加密传输级安全(TLS)连接进行通信。你可以在这里了解更多关于 SMTP 命令的信息。
之后,我们只需从文件中读取我们的电子邮件和密码,分别存储在email
和pwd
中。
然后我们用smtp.login
登录 SMTP 服务器,用smtp.sendmail
发送邮件。
我总是将通知发送给自己,但在自动报告的情况下(或出于任何其他原因),您可能希望将电子邮件发送到其他地方。为此,更改destination_address
: smtp.sendmail(email, ***destination_address***, msg.as_string)
。
最后,我们终止会话并关闭与smtp.quit
的连接。
所有这些都放在一个 try-except 语句中。在网络连接暂时中断的情况下,我们将无法连接到服务器。导致了socket.gaierror
。
实现这个 try-except 语句可以防止程序在网络连接中断时中断。你如何处理这种情况可能会有所不同,这取决于这封邮件的重要性。
对我来说,我用它来更新 ML 模型训练和完成数据传输。如果一封电子邮件没有被发送出去,那也没关系。因此,这种简单、被动的连接丢失处理是合适的。
把它放在一起
现在我们已经编写了代码的两个部分,我们可以发送电子邮件,只需:
# build a message object
msg = message(text="See attached!", img='important.png',
attachment='data.csv')send(msg) # send the email (defaults to Outlook)
杰森·法莱特 指出,使用 Gmail 的人可能需要“允许访问不太安全的应用程序”。这样做的步骤可以在 这个堆栈溢出问题中找到 。
这就是使用 Python 实现电子邮件通知和/或自动化的全部内容。感谢email
和smptlib
库,这是一个非常简单的设置过程。
通用电子邮件提供商服务器地址和 TLS 端口。如果你有什么要补充的,请告诉我!
对于任何耗费大量时间的处理或培训任务,进度更新和完成通知通常是真正的解放。
我希望这篇文章对你们中的一些人有用,一如既往,如果你有任何问题或建议,请告诉我!
感谢阅读!
我还写了其他“快速修复”文章,让我们的 Python 生活变得更简单,看看这篇关于 Excel 和 Python 集成的文章:
为 Python 工具构建前端 Excel 工作簿
towardsdatascience.com](/excel-to-python-79b01638f2d9)
网络容量规划的新方法
介绍
一种增强网络容量测量的方法,该方法基于客户在网络上的数据使用与使用近实时大数据架构的客户的位置变化之间的相关性。
在此分析中,我将使用一个模拟热流的模型,并以类似的方式用数学方法表示网络。
此外,我们将通过在偏微分方程和不同来源之间的概率统计相关性建模。
最后,我们将浏览大数据堆栈,在那里我们可以实施该模型并将其可视化。
为什么/好处
很难主动检测网络流量,也很难将其映射到消费者行为。
因此,在这个模型中,我们需要克服 3 个问题:
主动减少网络上的数据流量拥塞,这将改善客户体验和网络的净推广分数。
通过主动检测故障,减少因数据网络问题导致的客户流失,因为这始终是客户退出网络的主要原因之一。
我们需要有一个不同的视角,从商业消费者的角度来规划网络整改。
用例模拟
在这种情况下,我将通过一个非常简单的网络快照模拟,让一群客户使用数据。
网络的一部分看起来会像这样
图 1:在第一个例子中,在时间 T 5,小区 1 有 70MBPs 带宽的活跃用户,而小区 2 完全免费。
在一个时间增量之后,一些用户将移动到其他邻居节点,占用一部分带宽
图 2:在第二个例子中,在时间 T++时,一些活跃用户已经移动到小区 2,带走了一部分带宽
因此,添加一个新的邻居节点并使用部分带宽移动一些客户的模拟将是这样的。
图 3:然后在下一步中,这些用户的一部分移动到其他新的小区,占用部分带宽。
因此,一般来说,在时间 T 有许多节点,我们需要对具有最大流量的小区采取行动,这是总客户和已用带宽的一个因素。
一般来说,通量是单位时间单位面积的能量流的表示,在我们的情况下,通量是单位时间内用户数量和带宽的函数。
所以,我们要经历的最后一个等式。推导过程看起来像这样:一个偏微分方程,对于具有表中定义的最大差分电势“U”的单元,在时间 t 得到建议 R。
所以,这就是汞金属的扩散方式,它在液态移动中扩散,网络数据就像水银一样珍贵。
这里我们开始进行方程推导。
方法总结:
每个客户进行数据 CDR(呼叫详细记录)并离开该小区到另一个相邻小区的概率方法。
概率基于客户使用的历史频率,如语音、短信和移动到相邻小区。
定义网络流量和决定容量建议的模型是基于传热模型的模拟计算的
基于类比的小区流量计算是小区的最小利用率,加上所有来自其他小区的传入数据流量,减去任何到其他小区的传出数据流量。
为了模型的准确性,模型中使用的一些属性可能会被丢弃
在这一步,我们必须回到热流在两个表面之间的工作原理。
然后,当网络流在单元之间移动时,我们将其与网络上的情况进行类比
因此,我们在这里有一些符号和变量,我们需要映射的类比,将有以下定义。
然后流动的偏微分方程将在这些步骤中完成
一般的定义会是这样的
然后,我将 V 定义为包 P 和顾客 C 的函数
然后,通过替换交通流量方程中的所有变量,得到三维距离 d
这里的面积是两个小区之间的两个覆盖区域的最小值,常数 K 将是在小区 1 和 2 之间随时间移动的用户数量对小区 1 上出现的最小用户数量的积分
最后,两个细胞之间的流动看起来像这样
类似地映射到小区之间的距离 x,y 的第三维的 M 变量是健康监控检查,其示出了网络节点相对于时间的健康,将时间 t 处的 M 变量作为小区 1 监控和小区 2 监控之间的差的梯度。
这就是我们如何在两个单元之间映射等式,那么如果我们有多个节点,那么成本函数将像这样分布。
符号为 21 的 u 表示从 cell2 到 cell1 的流量,依此类推。
现在,一般来说,我们可以得到如下 3 个像元之间的等式,其中 Q 为网络常数,它映射到变量定义表中定义的整个网络的成本函数的最小值。
现在扩展到 N 个单元格,我们可以将流量求和如下。
那么问答在这里,我们需要对哪个细胞采取行动,它就是通量(流量)最大的细胞。
所以最终方程会是这样的。
那么,构建该模型所需的网络资源和流量设计示例是什么呢?我们需要一些网络资源和网络核心数据上的客户行为样本,这些样本将被移动到基础设施的不同逻辑层,如下所示:
我们如何在没有关联的来源之间进行事件关联?
现在让我们来看看如何在两个未链接的源之间进行事件关联
我们将使用 DAG(有向无环图)概率方法。
更详细地说,概率计算可以用这个例子的公式来完成
并深入研究开发集群如何实现该模型。
这是 4 个节点,每个节点将提供以下详细服务。
最后,这是大数据开发集群存储体系结构
结论
因此,在这种方法中,我们设计了一个数学模型,它几乎是线性的,可以使用非链接源之间的相关性来主动分析网络行为,并且我们依赖于一个大数据堆栈。
热传递模型的类比是使用相同方法的入口,以使用相同的方法设计其他成本函数。
实现中的所有微分方程都可以在微批处理中的窗口功能方法中进行,或者以流的方式在移动窗口中进行。
关于我
我是一名独立的分析工程师,在该领域拥有丰富的经验。你可以在这里查看我的 LinkedIn,了解更多关于我和我的证书的信息。https://www.linkedin.com/in/ahmedshaaban90
具有局部异常因子的新奇检测
检测新数据是否是异常值
兰迪·法特在 Unsplash 上的照片
与异常检测相比,新奇检测可能是一些人更难听到的术语。如果离群点检测旨在发现数据集中的异常或显著不同的数据,则新颖性检测旨在确定新的或未知的数据是否是离群点。
新颖性检测是一种半监督分析,因为我们将训练未被异常值污染的训练数据,并且我们感兴趣的是通过使用训练的模型来检测新观察值是否是异常值。在这种情况下,离群值也称为新奇值。
在这篇文章中,我将解释如何使用局部异常因子(LOF)进行新颖性检测。让我们开始吧。不过,如果你想跳过所有的理论,只是想接触编码部分,就跳过下一节吧。
本地异常因素(LOF)
局部异常因子或 LOF 是由 Breunig 等人提出的一种算法。(2000 年)。概念很简单;该算法试图通过测量给定数据点相对于其邻居的局部偏差来发现异常数据点。在这个算法中,LOF 会给出一个分数,告诉我们的数据是否是异常值。
LOF(k)~1 意味着作为邻居的相似密度。
LOF(k) < 1 means 密度高于邻居(内/非外值)。
LOF(k) > 1 意味着密度低于邻居(离群值)
在上式中,我已经给你介绍了一个 k 参数。在 LOF 算法中,局部性由 k 个最近邻给出,其距离用于估计局部密度。然后,该距离将用于测量局部偏差并查明异常。
k 参数是我们为获取一个 k 距离而设置的参数。k 距离是一个点到它的第 k 个邻居的距离。如果 k 为 4,k-距离将是一个点到第四个最近点的距离。距离本身是我们可以选择的距离计算的度量。通常它是“欧几里得”,但你可以选择其他距离。
k = 4,该点到达第四个最近的点(由作者创建的图像)
如果您想知道,我们的数据集中的每个数据点都将被测量 k 距离,以便测量下一步。
距离现在被用来定义我们所说的可达性距离。这个距离度量是两点距离的最大值或第二点的 k 距离。形式上,可达性距离的度量如下。
可达性距离 k(A,B)= max { k-距离(B),d(A,B)}
其中 A 和 B 是数据点,A 和 B 之间的可达性距离要么是 k-距离 B 的最大值,要么是 A 和 B 之间的距离。如果 A 点在 B 点的 k-邻居内,那么可达性距离 k(A,B)将是 B 的 k-距离。否则,它将是 A 和 B 之间的距离*。*
接下来,我们将通过使用可达性距离来测量局部可达性密度 (lrd)。测量 lrd 的公式估计如下。
lrd(A) = 1/(sum(可到达距离(A,i))/k)
其中 I 是点 A 的邻居(从其邻居可以“到达A**的点),为了获得点 A 的 lrd,我们计算 A 到其所有 k 个最近邻居的可达性距离之和,并取其平均值。lrd 是平均值的倒数。LOF 概念完全是关于密度的,因此,如果到下一个邻居的距离较长,则特定点位于较稀疏的区域。因此,密度越低——反之亦然。
这里,lrd 表示该点要移动多远才能到达下一个点或点簇。lrd 越低意味着点必须走得越长,并且组越不密集。
中心点的 lrd 是到其最近邻居的平均可达性距离,这些最近邻居是除(1,1)点之外的左下角的点。但是,这些邻居有其他 lrd,因为它们的最近邻居不包括中心点。(图片由作者创建)
然后,使用以下公式将本地可达性密度与其他邻居的可达性密度进行比较。
将每个点的 lrd 与其 k 个邻居的 lrd 进行比较。LOF 是 A 的相邻点的 lrd 与 A 的 lrd 的平均比率。如果该比率大于 1,则点 A 的密度小于其相邻点的密度。这意味着,从点 A 到下一个点或点簇需要比从 A 的邻居到下一个邻居的距离长得多的距离。
LOF 表示该点相对于其相邻点的密度。如果一个点的密度小于其相邻点的密度(LOF 大于 1),则该点被视为异常值,因为该点比密集区域更远。
LOF 算法的优点是,即使在异常样本具有不同基础密度的数据集上,它也能很好地执行。这是因为 LOF 不是样本有多孤立,而是样本与周围邻居相比有多孤立。
通过 LOF 进行新颖性检测
我们将使用由 scikit-learn 提供的 LOF 来帮助我们训练我们的模型。
#Importing the moduleimport pandas as pd
import seaborn as sns
from sklearn.neighbors import LocalOutlierFactor#Importing the dataset. Here I use the mpg dataset as an example
mpg = sns.load_dataset('mpg')
作为介绍,在使用模型进行新颖性检测之前,让我们尝试使用 LOF 作为离群点检测模型。
#Setting up the model. K is set by passing the n_neighbors parameter with integer. 20 is often considered good already to detect an outlier. By default the distance metric is Euclidean distance.lof = LocalOutlierFactor(n_neighbors = 20)#Training the model, I drop few columns that was not a continuous variablempg['lof'] = lof.fit_predict(mpg.drop(['cylinders', 'model_year', 'origin', 'name'], axis = 1))#Getting the negative LOF scorempg['negative_outlier_factor'] = lof.negative_outlier_factor_mpg
下面是结果,我们得到了 LOF 分类和负 LOF 分数。如果 lof 等于 1,那么它被认为是一个 inlier 如果它是-1,那么它是一个离群值。让我们试着得到所有的离群数据。
mpg[mpg['lof'] == -1]
污染或异常值取决于 LOF 分数。默认情况下,如果 negative_outlier_score 的分数小于-1.5,它将被视为异常值。
现在,让我们尝试使用模型进行新颖性检测。我们需要再次训练模型,因为我们需要传递一个额外的参数。
#For novelty detection, we need to pass novelty parameter as Truelof = LocalOutlierFactor(n_neighbors = 20, novelty = True)
lof.fit(mpg.drop(['cylinders', 'model_year', 'origin', 'name'], axis = 1))
我们只训练模型,我们根本不会使用训练数据来预测数据。在这里,我们将尝试预测新的看不见的数据。
#Predict a new random unseen data, the dimension must match the training datalof.predict(np.array([109, 310, 190, 3411, 15]).reshape(1,-1))Out: array([1])
输出可能是 1 或-1,这取决于它是否是一个异常值。如果你想得到负的 LOF 分数,我们也可以用下面的代码来实现。
lof.score_samples(np.array([109, 310, 190, 3411, 15]).reshape(1,-1))Out: array([-1.34887042])
输出将是数组形式的分数。就是这样,我已经向你们展示了如何用 LOF 做一个简单的新奇感检测。
结论
新奇性检测是检测新的看不见的数据是否是异常值的活动。局部异常因子是一种用于异常检测和新奇检测的算法。这取决于我们传递的 k 参数。通常情况下,k = 20 是可行的,但是如果您觉得数据中有大量的异常值,您可以增加这个数值。
希望有帮助。
如果你喜欢我的内容,并想获得更多关于数据或作为数据科学家的日常生活的深入知识,请考虑在这里订阅我的时事通讯。
如果您没有订阅为中等会员,请考虑通过我的推荐订阅。
11 月版:深度学习的力量
月刊
构建受生物启发的算法
当我刚刚开始研究数据科学时,我从未想过我需要解决深度学习问题。深度学习不是新手才有的概念!我天真的以为可以避免。突然,在我的旅程开始几个月后,我试图通过构建一个推荐系统来优化一项任务,并需要了解哪种 NLP 模型适合我的问题以及原因。是时候面对现实了。
当我开始深入主题时,我意识到建立深度学习模型很像是在不看盒子上的图片的情况下将拼图拼在一起。首先,我们根据形状挑选出我们认为是边缘的部分。接下来,我们按颜色将剩余的拼图块分开。根据边缘块的颜色,我们也许能够猜出每个颜色组的大概位置。之后,我们从一组颜色中挑选出我们容易识别的相关部分,并开始将它们放在一起。一点一点,我们意识到这是梵高的夜店。
就像这个类比一样,深度学习模型是由许多更简单的概念和函数组成的杰作。这种想法使得深度学习成为一种强大而广泛使用的技术。无论你是新手、科技领域的博士还是任何关心社会的人,你都会比你想象的更快地遇到深度学习的话题。为了帮助你了解更多,我们在这个话题上收集了一些我们最喜欢的精选,从介绍性的想法到最先进的技术。我们希望它们能让你对当前的理解有新的认识,并帮助你在这个旅程中导航。
《走向数据科学》的编辑琳达·陈。
深度学习的数学路线图
从头开始理解神经网络的内部运作
由蒂瓦达·卡丹 — 19 分钟阅读
用 CIFAR-10 进行深度学习
基于 CNN 的图像分类
由阿雅婆罗门 — 10 分钟阅读
利用深度学习&人工智能解决现实世界的问题
不是你通常的物体检测博客
通过 Vaishnavi Dwivedi — 6 分钟读取
深度学习真的需要 GPU 吗?
获得一个 GPU 是深度学习的必备条件吗?了解 GPU 及其优势,并探索替代方案
通过bharat K—7 分钟读取
我的 3 年历程:从零 Python 到深度学习竞赛高手
自从 2017 年开始学习 Python 以来,我一直遵循的道路是在 2019 年年中成为一名 Kaggle 竞赛大师,并获得一枚单人金牌。一个激励你追求目标,永不放弃的故事。
由米格尔·平托 — 6 分钟读完
图形深度学习:成功、挑战和后续步骤
这是系列帖子中的第一篇,在这里我将讨论图形深度学习领域的演变和未来趋势。
迈克尔·布朗斯坦——7 分钟阅读
深度学习不再困难
至少,用深度学习构建软件不是
由凯泽 — 6 分钟阅读
用于深度学习的 MacBook Pro?让我们试试。
它与英伟达 GPU 驱动的笔记本电脑相比如何?
由达里奥·拉德契奇 — 4 分钟阅读
新播客
- Edouard Harris——机器学习中出现的问题:让 AI“变好”
- Tim rocktschel—深度强化学习、符号学习和 AGI 之路
- Rohin Shah — 有效的利他主义、人工智能安全以及从世界状态中学习人类偏好
我们也感谢最近加入我们的所有伟大的新作家费德里科·乌雷纳、贾森·吴永林、瓦伊什纳维·德维迪、尼古拉斯·路易斯、安佳丽·巴德瓦吉、克里斯·麦考密克、阿米尔·阿菲安、胡希德·加福尔、应元(瓦莱丽)张。 提莫·博恩施泰特,亚历山大·科尔科维洛斯,薇琪·于,达斯·维耶桑德拉,泰勒·哈里斯,加布里埃尔·卢西亚诺·彼得拉费萨,艾琳·p,阿里雷扎·库查里,米黑尔-尤利安·pleșa, 我们邀请你看看他们的简介,看看他们的工作。
“现在,我该怎么做呢?”
你已经有了伟大的项目想法,现在做什么?
Med Badr Chemmaoui 在 Unsplash 上拍摄的照片
在我的上一篇文章中,我谈到了我是如何为我的类似的针织图案探测器想出一个项目创意的。这个星期,我将谈论在你有了一个可靠的项目想法后的下一步。
太好了,你现在有了你的项目想法!对很多人来说,这可能是一个非常艰难的步骤,所以要鼓励自己。现在,你必须考虑你将如何回答你的问题或者构建你的程序。
研究
第一步是研究。你没有必要去重新发明轮子。如果有人已经写了一篇关于如何做一件具体事情的文章,你最好现在就找到它,而不是花几个星期做你的项目,只是发现有人写了一篇你可以直接跟随的漂亮、整洁的教程。就我而言,我从阅读协作式和基于内容的推荐系统以及它们是如何工作的开始。我还开始查看 Ravelry API 文档,看看我可以通过 API 访问哪些数据。
说了这么多,我需要指出一点:
不要在这一步花太多时间
我们都去过维基百科虫洞,浪费时间阅读语言学中所有未解决的问题。虽然你肯定不想盲目地一头扎进去,但是你也不想躲在你的研究后面,所以你从来没有真正开始编码。理想情况下,您希望处于可以完成下一步的位置:
创建路线图
在您提出项目想法后,您的项目路线图可能看起来像这样:
- 查找数据
- 干净的数据
- 尝试模型
- ???
- 利润
如果那是你开始的地方,那是可以的,但是如果你真的想越过想法阶段,你肯定需要做得更好。当你在研究阶段,你的目标应该是找出如何使这些步骤更加具体。例如,这个步骤可能会变成“发出这些 API 请求”,或者“从这些网站收集数据”,而不是“查找数据”你每一步做得越具体,你的情况就越好。
也就是说,你不需要想清楚一路上的每一步。如果您在收集数据的同时还在考虑如何清理数据,那也没关系。只要你对接下来的步骤有一个具体的想法,对你想要的结果有一个清晰的画面,你就有足够的东西可以开始工作了。路线图的目标是集中你的工作(这样你就不会花两周的时间在你最终扔掉的东西上),并使一个潜在的令人生畏的任务变得不那么令人生畏。
虽然有一个项目路线图很重要,但是步骤列表不能是一个僵化、不灵活的列表。出现了意想不到的错误,当您开始收集数据时,有一些您不知道的奇怪的数据特性,您正在收集的数据没有您最初想要的所有特性,项目有太多的方式可以偏离轨道并可能脱轨。对于你完成的每一步,肯定会有至少三个你必须解决的问题。这就是为什么你必须有一个适应性强的路线图。即使出现了这些问题,你仍然需要有这样的地图,这样你才不会迷失在细节中,看不到你的项目目标。
我已经有了路线图,现在做什么?
现在您已经有了项目路线图,并且至少对如何完成项目有了一个大致的想法,您必须做最难的事情之一:
实际跟进并完成你的项目
在我们的回购协议中,我们都有被放弃的附带项目,下周我将谈论我如何确保这个项目不会成为其中之一。
在欧洲,现在是成为数据科学家或数据管家的最佳时机
为什么欧盟计划培训 50 多万数据科学家和数据管理员
【Pexels.com 的 皮沙贝拍摄的照片
内容
- 简介
- 什么是公平数据?
- 在科学和研究领域,对数据科学家的期望是什么?
- 数据管家是做什么的?
- 两个角色如何比较和交集?
- 结论
介绍
2016 年,一组欧盟高级专家估计,欧洲将需要在十年内使开放科学成为可能 超过 50 万“核心数据专家” 。
在他们看来,这些“核心数据专家”将在整个研究生命周期中支持 170 万研究人员和 7000 万科学技术专业人员,确保良好的数据管理,帮助数据捕获(格式、元数据、标准、出处、发布),以及数据分析。
两年后,在 2018 年,这一想法得到了加强,并且“核心数据专家”被确定为数据科学家和数据管家 ( 将公平变为现实最终报告和行动计划),他们除了技术专业知识外,还需要拥有他们将从事的研究和创新领域的领域知识。
在研究的背景下,这两种技能组合定义如下:
- 数据科学 — “处理、加工和分析数据,从中得出真知灼见的能力”;所需技能包括:计算机科学、软件开发、统计学、数据可视化、机器学习以及计算基础设施。
- 数据管理 — “一套确保数据在整个研究生命周期和长期保存过程中得到正确管理、共享和保存的技能”。提到的技能的一些例子是:信息管理、数据清理、数据管理。
鉴于这些确定的需求,该报告呼吁制定新的正式或不太正式的教育和培训计划,帮助培养实现公平数据所需的大量数据科学家和数据管理员。
有趣的是,该报告还呼吁研究人员精通数据,以便他们能够更好地利用现有的数据和技术。
什么是公平数据?
从哲学的角度来看,公平数据的原则,以及整个开放科学运动,都与科学和研究数据一样可以被视为全球公共产品的理念有关。尤其是当它们是由公共资金资助的时候。
关于开放数据作为公共产品的更多信息,以及关于免费开放数据来源的信息可以在我之前的文章中找到:
类型、优势以及在哪里可以找到它们
towardsdatascience.com](/data-science-for-social-good-best-sources-for-free-open-data-5120070caf02)
每年,科学和其他领域产生的数据量都呈指数级增长。这为我们如何在科学中使用这些数据、制定商业决策或制定基于证据的政策带来了巨大的机遇。但在利用产生的数据方面也存在巨大挑战,比如数据的质量及其长期保存。
按照这种逻辑,我们必须能够将数据转化为知识,然后付诸行动。
那么,公平代表什么?(公平数据原则
- 可查找的 —人类和计算机都应该能够很容易地找到数据及其元数据。为此,元数据应该是机器可读的,允许自动发现数据集和服务。
- 可访问 —数据应该带有关于如何访问的明确信息,即使这涉及认证或授权。此外,即使数据不再可用,也应该可以访问相应的元数据。
- 可互操作 —数据需要与应用程序(如 API)或工作流互操作,以便进行分析、存储和处理。
- 可重用 —该原则指的是 FAIR 的主要目标,即优化和促进数据的重用。为此,元数据和数据需要被很好地描述,以包括关于使用许可的信息,以及出处。
公平数据不等于开放数据。例如,从可访问性原则中可以注意到,有时它可能涉及授权或认证。
据欧盟委员会公平数据专家组主席西蒙·哈德森(Simon Hudson)称,没有“数据科学和数据管理技能的显著和广泛提高”,公平就不可能实现。在数字技能方面,欧洲并不是真正的最佳实践范例,平均 42%的人口缺乏这方面的技能。
数字经济与社会指数 2 0 2 0
在科学和研究领域,对数据科学家的期望是什么?
与数据管家一起,数据科学家将被要求在整个研究生命周期中支持研究人员,并将被嵌入机构层面的研究项目或每个领域的专业服务中。
在许多情况下,数据科学职位由已经有研究背景或受过信息专业培训的人担任。前者尤其重要,因为数据科学家在这一领域的大部分工作都是特定学科的,需要对监管和研究有深刻的理解。
在查看了一些由研究执行组织提供的数据科学家的工作描述后,我注意到,除了与机器学习、统计学、Python、数据可视化、有时高性能计算或云计算相关的常见要求之外,一些未来的员工还应该了解与研究学科相关的软件工具,为科学期刊文章和博客撰写内容,或者参加国家和国际会议并在会上发言。在教育方面,该领域的数据科学家需要拥有天文学、物理学、统计学或计算机科学等领域的硕士或博士学位(根据研究学科的不同而不同)。
对于那些来自计算机科学或其他相关学科,而不是来自特定研究领域的人来说,一个潜在的缺点是要求至少是第一阶段的研究人员(R1)。在这种情况下,最好先成为该领域的研究人员,然后再学习数据科学技能。然而,并非在所有情况下都是如此。
另一方面,在研究执行组织中担任数据科学家的一个优势可能是,它可能会对社会影响做出贡献。例如,该领域的一些工作需要将数据科学应用于社会技术主题,如流行病、假新闻、公民参与或可再生能源。
超越我们想看什么类型的电影,到我们想生活在什么类型的世界。资源、示例和…
towardsdatascience.com](/data-science-for-social-good-a88838bc8ed0)
数据管家是做什么的?
在业务领域,数据管理与提高数据质量、处理敏感和机密数据、数据清理、定义政策和监控系统、定义标准、添加元数据以及数据生命周期中的整个数据管理流程(从监管到废弃)相关联。
Adobe 的数据治理角色
在 Adobe,数据管理员特别负责解释法规、任何合同限制和政策,并将其应用于数据。因此,他们的职责包括:创建数据策略并将其应用于数据集;审查数据、数据集和数据样本,以应用和管理元数据使用标记等。
从 Adobe 的例子和其他例子中我们可以看出,在某些情况下,数据管理更多地与数据策略和处理敏感和机密数据相关。接下来我们将会看到,在欧洲开放科学的背景下,数据管理是如何围绕实施公平原则展开的。
在研究的背景下,数据管理员可以负责数据清理、消除不一致、组织和构建数据、处理元数据、确保数据的可重用性、可访问性和长期保存(即使在技术发生变化时),以及其他数据管理操作。根据他们的经验和专业水平,在某些情况下,数据管理员可能还需要处理定义标准、最佳实践和互操作性框架。
然而,无论是公共部门还是私营部门,数据管理不仅仅是数据管理,因为它还包括数据收集或捕获、处理、长期保存及其再利用。
在代尔夫特理工大学 关于 数据管理的演示中,提到数据管理人员应该能够回答特定研究领域中所有与数据相关的问题。一些问题可能涉及数据存储、数据恢复和备份、如何处理机密和敏感数据、在申请专利的情况下共享数据、帮助制定数据管理计划和跟踪数据、确保数据的长期保存。
此外,在代尔夫特大学,数据管理员的工作规范包括数据管理员预期工作的研究领域的核心要求知识。
数据管理员与工作相关的职责示例(摘自 EURAXESS )包括:在整个研究生命周期中支持研究人员和管理人员,开发研究数据管理工作流程和最佳实践,研究项目的数据管理规划,研究数据监管,为研究人员开发和举办培训和研讨会,数据管理,确保数据有效性、保护和安全性,确保符合有关格式、元数据的国际标准,监控数据管理,维护词汇表,实施公平数据原则,开发特定领域的词汇、本体和元数据模式,参与研究活动和编写出版物。
这两个角色是如何相互比较和交叉的?
2020 年美国平均年薪:
- 数据管家—**$**67982(Payscale.com)
- 数据科学家—**$**96101(Payscale.com)
热门技能(按此顺序,在 Payscale.com 上):
- 数据管家:数据分析、数据管理、数据质量、Microsoft Excel、SQL
- 数据科学家:机器学习,Python,数据分析,统计分析,R
欧洲研究人员专用平台EURAXESS上的工作列表数量:
- 数据管家:只有 3 个,在荷兰、德国和卢森堡
- 数据科学家:488 人,但这个数字并不完全准确,因为这个名单还包括其他类型的工作,比如 UI/UX 设计师、软件开发员
当谈到研究执行组织的工作职责时,两者在一定程度上是重叠的。数据科学家角色还包括与数据管理或处理公平数据原则相关的任务。
将公平变为现实报告的作者认为,数据科学和数据管理通常可以在同一个人身上结合,但最好是在这两个领域推动更大的专业化。在某些情况下,这可能取决于可用的预算和研究机构的数据导向程度。对于许多这样的组织来说,在这方面可能很难有两种不同的立场。
下面是一个与欧洲开放科学云相关的试点项目如何详细描述数据管理技能和能力框架的示例。在这种情况下,数据科学是更大的数据管理概念的一部分。整个框架请见报告。
其他定义数据科学和数据管理的欧洲计划可在以下页面查阅:
- 爱迪生计划 —数据科学专业的加速和创造
- 数字策展的课程框架
结论
鉴于目前数据管事没有太多的职位空缺,这似乎可能不是最好的职业。然而,空缺数量少也可能是因为该角色有时被整合在数据科学家的角色中,因为后者还涉及处理研究数据管理和数据的公平原则(至少在欧洲)。
当这两个角色分开时,数据管家对于数据的重用可能是极其重要的,即使它与私有或公共部门有关。数据具有更大的价值,当它可以被重用和构建时,可以产生更好的结果和影响。为了完成他们的工作,数据科学家需要获得良好、可靠的数据,并且,随着时间的推移,数据管理员可以在这方面提供帮助。
数据管理可以解决数据科学中的垃圾入、垃圾出(GIGO)问题。如果你一开始就没有高质量的数据,那么一个数据科学家再好也没用。正如我的一个朋友曾经说过的,我们需要从如何和收集什么类型的数据开始,然后转移到处理和从中提取洞察力。
无论如何,欧洲对数据专家的需求很高,预计还会增加,因为欧盟机构希望在创新和技术竞赛中赶上美国和中国。如果不拥抱新技术,不在人力资源方面加强竞争,这是不可能的。
如果您希望尝试开放的研究数据集,请查看以下存储库:
2020 年 8 月 12 日(1.0 版)数据集开放存取 Bardi,Alessia 库奇马、伊里纳;波波罗夫、叶夫根尼;伊万娜·特鲁科洛;蒙泰罗…
zenodo.org](https://zenodo.org/) [## 领域知识在数据科学中到底有多重要?
看看来自美国的招聘信息,不仅仅是。
towardsdatascience.com](/how-important-domain-knowledge-really-is-in-data-science-19d833d98698)
现在,使用惰性计算在一秒钟内加载巨大的数据集😴用 Python?
厌倦了用 pandas 加载数据集…了解 Vaex 如何通过 Python 实现在几秒钟内加载大量数据。
来源:https://vaex.readthedocs.io/en/latest/tutorial.html
本文简要介绍了如何使用 Vaex 将大数据集加载到 Python 内核中,并给出了实际的实现。让我们开始吧。在深入真正的实现之前,让我们了解一下什么是 Vaex。
Vaex 是什么?
- Vaex 是一个高性能的 Python 库,用于懒惰的核外数据帧(类似于 Pandas),以可视化和探索大型表格数据集。
- 它在一个 n 维网格上每秒计算超过 10 亿(10⁹)个样本/行的统计数据,如平均值、总和、计数、标准偏差等。
- 可视化是使用直方图、密度图和 3d 体绘制完成的,允许对大数据进行交互式探索。Vaex 使用内存映射、零内存复制策略和惰性计算来获得最佳性能(不浪费内存)。
看完这篇文章,我建议你去这里 看看 VaexT3 的文档
下载和安装包
第一步是使用任何包管理器如 pip 或 conda 下载并安装 vaex 库。
pip install vaex
或者
conda install -c conda-forge vaex
记得用“!”如果您直接将它输入到 iPython 环境中,请在命令之前。
导入包
现在,我们需要使用下面的命令将这个库导入到我们的工作环境中。我们将导入 pandas 来计算两个库的执行时间。
import vaex
import pandas as pd
资料组
现在,在本演示中,让我们创建一个包含 100 万行 100 列的大型数据集,这确实是一个大型数据集。
n_rows = 100000
n_cols = 10
df = pd.DataFrame(np.random.randint(0, 100, size=(n_rows, n_cols)), columns=['c**%d**' % i **for** i **in** range(n_cols)])
现在,让我们检查一些关于加载的数据集的信息。
df.info(memory_usage='deep')
创造。csv 文件
我们将把上面创建的演示数据帧保存为的形式。csv 文件实现加载。
file_path = 'main_dataset.csv'
df.to_csv(file_path, index=**False**)
创建 Hdf5 文件
我们需要以 hdf5 格式存储数据集,作为 vaex 负载的输入。
请注意,所有这些过程只是为了创建演示数据集,用于演示目的,在实际项目中,我们会有一些数据,而实现基于 vaex 的数据加载只是一行代码。
vaex_df = vaex.from_csv(file_path,
convert=**True**,
chunk_size=5_000_000)
在检查我们得到的这个数据帧的类型时,
type(vaex_df)
使用 Vaex 库读取 Hdf5 文件
现在,我们终于到了演示中最重要的一步,所以请注意。使用 Vaex 加载 Hdf5 格式的数据集。
vaex_df = vaex.open('main_dataset.csv.hdf5')
vaex_df.head()
表达系统
现在让我们看看 Vaex 的计算速度有多快。我们实现了两列的乘法,并将它们存储在数据帧中的一个新列中,并估计了这个过程所花费的时间。结果可以忽略不计。
%%time
vaex_df['multiplication_col13']=vaex_df.c1*vaex_df.c3
看到这一列中的内容,我们得到一个 vaex 定义的表达式类似于熊猫数据框中的一列。
vaex_df['multiplication_col13']
核外数据帧
坚持 Vaex 开发背后的主要概念,我们需要记住以下注意事项,
"筛选和计算表达式不会因为复制而浪费内存;数据在磁盘上保持不变,仅在需要时进行流式传输。在需要集群之前延迟时间。”
比如…
vaex_df[vaex_df.c2>70]
所有的算法都在内核之外工作,极限是你的硬盘驱动器的大小
比如…
dff.c2.minmax(progress='widget')
Vaex 实现了并行、高性能的 groupby 操作,尤其是在使用类别(> 10 亿/秒)时。
实现为…
%%time
vaex_df_group = vaex_df.groupby(vaex_df.c1,
agg = vaex.agg.mean(vaex_df.c4))
vaex_df_group
%%time
vaex_df.groupby(vaex_df.c1,agg='count')
参考
【https://vaex.readthedocs.io/en/latest 号
关于这次演示的完整代码,请从我的 Github 中获取 Jupyter 笔记本。
谢谢!
Numba: JIT 编译,但是用于 Python
快速浏览一下 2020 年让 Python 变得更好的神奇工具。
介绍
对于程序员和计算机科学家来说,统计计算一直是一个非常困难的学科。程序员不仅在统计编程语言中寻找某些属性和特征,在通用编程语言中也是如此。随着机器学习和数据科学应用的普及,统计计算的兴起也加剧了“完美语言”发展中的这些关键问题。
回到十年前,没有人能预料到 Python 中机器学习的兴起会是什么样子。大多数科学家使用 R 编程语言进行统计分析和类似的事情。MATLAB 当然也是统计计算领域非常流行的选择,Scala 也是如此。Python 最近在这方面变得非常流行,因为它具有强大的统计能力
当然,Python 是用 c 解释的,这意味着 Python 没有它的竞争对手那么快,也不适合大数据解决方案。Python 本质上并不是一种为满足现代科学计算需求而构建的编译器语言。虽然 Python 对于大多数统计应用程序来说是一个很好的应用程序,但 Python 的主要缺点通常是在处理大量数据和递归训练机器学习模型时的速度。
为什么要用 Python?
如果 Python 在处理大量数据方面有问题,并且本质上是一种解释型的高级语言,那么为什么今天许多科学家喜欢这种语言呢?答案很简单,目前,Python 是最好的解决方案。虽然 Python 与许多其他语言相比相对较慢,但与其他语言相比,它也是非常高级的语言,并且在过去几年中一直在变得更快和更优化。
除此之外,Python 拥有当今最强大的统计计算生态系统之一。这些包中的大部分也是用 C 语言编写的,这使得 Python 经常成为非常快速的代码的简单接口。然而,无论生态系统有多强大,它都无法帮助处理海量数据和编写 Pythonic 算法来清理和编辑数据。
吉特舞乐
除非你一直生活在编程的龟壳下,否则你可能熟悉——或者至少听说过一个叫做 JIT 的编译器概念。JIT 或即时编译是一种编译器特性,它允许在运行时而不是在执行时解释和编译语言。这意味着 JIT 编译器在编译代码之前执行逻辑,而不是准备所有的代码来工作,决定代码要做什么,然后再去做。
这种编译器的好处当然是速度。花费在初始编译上的时间更少意味着代码可以更快地被解释。打个比方,假设你有一份晚餐要做的东西的清单。你可以采取一种多任务的方法,在同一时间做多件事情,而不是单独做所有的事情。
数字概述
Numba JIT 编译器类似于 Julia JIT 编译器,使用标准的 LLVM 编译器库。虽然它在这方面确实有一些缺点,因为 LLVM 的重点不一定是 JIT,但它确实意味着编译器非常快和精确。Numba 编译的 Pythonic 算法可以达到 c 等低级语言中常见的速度。
这听起来可能很复杂,确实如此——但这并不意味着 Numba 很难使用。事实上,Numba 非常容易使用!为了试用它,你当然需要用 Python 的包管理器 PIP 来添加它。
sudo pip3 install numba
安装 Numba 后,您可以通过 jit 函数访问它:
from numba import jit
import random
@jit(nopython=True)
def monte_carlo_pi(nsamples):
acc = 0
for i in range(nsamples):
x = random.random()
y = random.random()
if (x ** 2 + y ** 2) < 1.0:
acc += 1
return 4.0 * acc / nsamples
对于大多数代码,Numba 在优化 Python 代码方面做得非常出色。然而,正如 Julia 开发者在 JuliaCon 上讨论的那样,在当前版本中,Numba 仍有很长的路要走,并存在[某些代码的问题。一些问题无法通过简单的 Python 调用来解决,尽管 Numba 在创建可以轻松导入的 Python 优化编译器方面做得很好,但仍有一些改进需要做。
结论
不管 Python 是否会一直成为科学目的和统计计算的首选编程语言,很明显 Python 现在肯定是这样。虽然 Python 不是最快的编程语言,并且在科学计算方面也有一些小问题,但对于那些希望进行统计或机器学习的人来说,它仍然是一个很好的选择。这主要是由于它的生态系统和整体受欢迎程度。
幸运的是,Python 的许多缺陷正被有才华、有干劲的开发人员直接瞄准。随着时间的推移,这项技术很有可能会发展到当使用 Python 进行数据科学时,这些问题中的许多可能都不会再被感觉到。
Python 最大的问题之一是速度。Numba 是一系列令人敬畏的工具之一,有助于解决这个问题,并使 Python 达到对抗其他统计语言的标准,特别是像 Julia 这样的新语言。Numba 令人兴奋的地方在于它使用起来非常简单,就像一个电灯开关,可以让你的代码运行得更快。反过来,这可以用来为应用程序注入新的活力,否则这些应用程序甚至可能无法运行。
Numba:“大规模优化的武器”
Numba 如何节省您的时间并加速您的代码
Numba 是一个 Python 编译器,专门针对数字函数,允许您使用直接用 Python 编写的高性能函数来加速应用程序。
Numba 使用 LLVM 生成从纯 Python 代码优化的机器码。通过几处简单的修改,我们的 Python 代码(面向函数的)可以“实时”优化,获得类似于 C、C++的性能,而不必改变语言。
你可以在我的 GitHub 中找到完整的代码!😃
索引
- 什么是 Numba?
- 第一步:为 CPU 编译
- GPU 的 Numba
- 结论
什么是 Numba?
Numba 是一个编译器,允许您为 CPU 和 GPU 加速 Python 代码(数值函数):
- 函数编译器: Numba 编译 Python 函数,而不是整个应用或部分应用。基本上,Numba 是另一个提高函数性能的 Python 模块。
- Just-in-time: (动态翻译)Numba 将字节码(比机器码更抽象的中间代码)在其执行前立即翻译成机器码,以提高执行速度。
- 数值型: Numba 关注的是数值型数据,比如
int
、float
、complex
。目前,对字符串数据使用它有一些限制。
Numba 不是 CUDA 唯一的编程方式,通常是直接用 C/C ++为它编程。但是 Numba 允许你直接用 Python 编程,并对 CPU 和 GPU 进行优化,只需对我们的代码做很少的修改。关于 Python,还有其他替代方案,如 pyCUDA,下面是它们之间的比较:
CUDA C/C++:
- 这是 CUDA 中最常见和最灵活的编程方式
- 加速 C、C ++中的应用程序。
pyCUDA
- 这是 Python 最有效的 CUDA 形式
- 它需要用我们的 Python 代码进行 C 编程,一般来说,还需要许多代码修改。
PyCUDA 示例
数字巴
- 效率不如 pyCUDA
- 它允许您用 Python 编写代码,并通过少量修改对其进行优化
- 它还为 CPU 优化了 Python 代码
目标
本次会谈的目标如下:
- 使用 Numba 在 CPU 上编译函数
- 了解 Numba 是如何工作的
- 在 GPU 中加速 Numpy ufuncs
- 使用 Numba 编写内核*(下一个教程)*
第一步:为 CPU 编译
Numba 除了能够加速 GPU 中的函数之外,还可以用来优化 CPU 中的函数。为此,使用了 Python decorators(函数修饰符)。
首先我们要开始评估函数hypot
来试试 Numba 是怎么工作的。我们需要在函数中使用装饰器@jit
。
>>> # Numba function
>>> hypot(3.0, 4.0)
**5.0**>>> # Python function
>>> hypot.py_func(3.0, 4.0)
**5.0**
Numba 中的结果与 Python 函数中的结果相同,因为 Numba 将函数的原始实现保存在.py_func
中。
标杆管理
自然,测量我们代码的性能,检查 Numba 是否真的工作良好,并观察 Python 实现和 Numba 实现之间的差异是很重要的。此外,库math
已经包含了hypot
函数,我们也可以对其进行评估。
>>> # Python function
>>> %timeit hypot.py_func(3.0, 4.0)**The slowest run took 17.62 times longer than the fastest. This could mean that an intermediate result is being cached. 1000000 loops, best of 3: 260 ns per loop**>>> # Numba function
>>> %timeit hypot(3.0, 4.0)**The slowest run took 33.89 times longer than the fastest. This could mean that an intermediate result is being cached. 1000000 loops, best of 3: 216 ns per loop**>>> # math function
>>> %timeit math.hypot(3.0, 4.0)**The slowest run took 105.55 times longer than the fastest. This could mean that an intermediate result is being cached. 10000000 loops, best of 3: 133 ns per loop**
**math.hypot
**功能甚至比 Numba 还快!!这是因为 Numba 为每个函数调用引入了一定的开销,这比 Python 函数调用的开销要大,非常快的函数(就像上一个)会受此影响。
(但是,如果从另一个函数调用 Numba 函数,开销很小,如果编译器将该函数集成到另一个函数中,开销有时甚至为零。总之用 Numba 检查一下功能是不是真的在加速)。
**[## 1.14.性能提示-Numba 0 . 48 . 0 . dev 0+134 . g 709967 b-py 3.7-Linux-x86 _ 64 . egg 文档
这是一个简短的指南,介绍 Numba 中的一些特性,这些特性有助于从代码中获得最佳性能。二…
numba.pydata.org](https://numba.pydata.org/numba-doc/dev/user/performance-tips.html#performance-tips)**
Numba 是如何工作的?
当我们初始化hypot
函数时:
Numba 如何工作
- 中间表示法
- ****字节码分析中间代码比机器码更抽象
- LLVM 低级虚拟机,开发编译器的基础设施
- NVVM 是一个基于 LLVM 的 IR 编译器,它被设计用来表示 GPU 内核
python 的每一行前面都有几行 Numba IR 代码。最有用的是查看向我们展示 Numba 如何处理变量的类型注释,例如,在“pyobject”中,它表明 Numba 不知道np.sin
函数,他应该从 Python 中调用它。我们可以使用.inspect_types()
检查hypot
的过程。
>>> @jit
>>> def foo_np(x):
>>> return np.sin(x)>>> foo_np(2)
>>> foo_np.inspect_types()**foo_np (int64,)
----------------------------
# File: <ipython-input-18-02574ac7ba04>
# --- LINE 1 ---
# label 0** **@jit** **# --- LINE 2 ---
def foo_np(x):
# --- LINE 3 ---
# x = arg(0, name=x) :: int64
# $0.1 = global(np: <module 'numpy' from '/usr/local/lib/python3.6/dist-packages/numpy/__init__.py'>) :: Module(<module 'numpy' from '/usr/local/lib/python3.6/dist-packages/numpy/__init__.py'>)
# $0.2 = getattr(value=$0.1, attr=sin) :: Function(<ufunc 'sin'>) # del $0.1
# $0.4 = call $0.2(x, func=$0.2, args=[Var(x, <ipython-input-18-02574ac7ba04> (3))], kws=(), vararg=None) :: (int64,) -> float64** **# del x
# del $0.2
# $0.5 = cast(value=$0.4) :: float64
# del $0.4
# return $0.5 return np.sin(x) ==============================================**
示例:创建分形
我们将使用 Mandelbrot 集合来测量创建分形的性能,我们将看到 Numba 如何帮助我们提高性能。
**1 loop, best of 3: 4.62 s per loop
<matplotlib.image.AxesImage at 0x7f986ce23780>**
使用 Mandelbrot 集合生成一个分形大约需要 4.62 秒,现在我们将使用 Numba 来提高性能,我们只需添加@jit
装饰器。
**The slowest run took 4.17 times longer than the fastest. This could mean that an intermediate result is being cached. 1 loop, best of 3: 52.4 ms per loop**
我们可以观察到我们是如何实现将构建分形的时间从 4.62 秒减少到 52.4 毫秒… 并且这是通过添加装饰器实现的!!****
一些常见错误
我们说过 Numba 只对数字函数有效,虽然 Numba 可以编译和运行任何 Python 代码,但是有些类型的数据它还不能编译(比如字典),而且编译它们也没有意义。
>>> @jit
>>> def dictionary(dict_test):
>>> return dict_test['house']dictionary({'house': 2, 'car': 35})
**2**
****但它并没有失败!!我们说过 Numba 不编译字典…这里的重点是 Numba 创建了两个函数,一个用 Python,另一个用 Numba。这里我们看到的是 python 解决方案,我们可以通过做nopython = True
来验证这一点。
*jit(nopython = True)*
相当于njit
>>> @jit(nopython = True)
>>> def dictionary(dict_test):
>>> return dict_test['house']dictionary({'house': 2, 'car': 35})**-----------------------------------------
TypingError Traceback (most recent call last)****<ipython-input-31-14d1c8683c01> in <module>()
3 return dict_test['house']
4
----> 5 dictionary({'house': 245, 'car': 350})2 frames****/usr/local/lib/python3.6/dist-packages/numba/six.py in reraise(tp, value, tb)
656 value = tp()
657 if value.__traceback__ is not tb:
--> 658 raise value.with_traceback(tb)
659 raise value
660****TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Internal error at <numba.typeinfer.ArgConstraint object at 0x7f986c1bed68>:
--%<-----------------------------------------**
GPU 的 Numba
使用 Numba 在 GPU 中编程有两种方式:
1。 ufuncs/gufuncs__
2。 CUDA Python 内核(下一个教程)**
函数 ufunc
GPU 的主要设计特性之一是并行处理数据的能力,因此 numpy (ufunc)的通用函数是在 GPU 编程中实现它们的理想候选。
注 : ufunc 是对 numpy 数组的每个元素执行相同操作的函数。例如:
实践:为 GPU 创建函数
正如我们之前说过的,ufunc 函数是将它们与 GPU 一起使用的理想选择,因为它们具有并行性。因此,Numba 有能力在不使用 c 的情况下创建编译的 ufunc 函数,要做到这一点,我们必须使用 decorator @vectorize
。
让我们从一个使用@vectorize
编译和优化 CPU ufunc 的例子开始。
**array([ 24, 343, 15, 9])**
我们将在 GPU 中使用 CUDA,而不是使用 CPU 来编译和执行前面的函数,为此我们必须使用“目标属性”。我们将指出每个变量的类型(参数和返回值)。
return_value_type(argument1_value_type, argument2_value_type, ...)
为此,我们将使用前面的函数,该函数需要 2 个 int64 值并返回另一个 int64 值。我们将指定target = 'cuda'
能够在 GPU 中执行它。
**array([ 24, 343, 15, 9])**
我们可以检查它在 CPU 或 GPU 上运行的速度:
>>> %timeit np.add(a, b) # Numpy en CPU**The slowest run took 38.66 times longer than the fastest. This could mean that an intermediate result is being cached. 1000000 loops, best of 3: 511 ns per loop**>>> %timeit add_ufunc_gpu(a, b) # Numpy en GPU**The slowest run took 4.01 times longer than the fastest. This could mean that an intermediate result is being cached. 1000 loops, best of 3: 755 µs per loop**
GPU 比 CPU 慢!!!安静,这有一个解释…但是首先让我们看看当我们调用那个函数时会发生什么…
当我们执行这个函数时,Numba 产生:
- 编译 CUDA 内核,对输入数组 的所有元素并行执行 ufunc 函数
- 将输入和输出分配给 GPU 内存
- 将输入复制到 GPU
- 运行 CUDA 内核
- 将结果从 GPU 复制回 CPU
- 以 numpy 数组的形式返回结果
与 C 中的实现相比,Numba 允许您以更简洁的方式执行这些类型的任务。
为什么 GPU 比 CPU 慢?
- 我们的输入太小:GPU 使用并行性一次对数千个值进行操作来实现更好的性能。我们的输入是 4 或 64 维,我们需要更大的阵列来保持 GPU 被占用。
- 非常简单的计算:与调用 CPU 函数相比,将计算结果发送到 GPU 需要很多“努力”。如果我们的函数不需要过多的数学计算(这通常被称为算术强度),那么 GPU 可能会比 CPU 花费更长的时间。
- Numba 将数据复制到 GPU。
- 我们输入的变量类型比需要的大:我们的例子使用 int64,我们可能不需要它们。实际上,在 CPU 中,32 位和 64 位具有相同的计算速度,但在 GPU 中,64 位的计算速度略有增加(它可以分别比 32 位慢 24 倍)。因此,在 GPU 中执行函数时,记住这一点非常重要。
****考虑到这一点,我们将尝试应用前面几点学到的东西,看看在 GPU 上运行是否真的比 CPU 快。我们将计算一个密度函数,对于较大的数组,这是一个稍微复杂一点的操作。
给定平均值和 sigma,让我们计算x
中高斯密度函数的值:
>>> %timeit norm_pdf.pdf(x, loc=mean, scale=sigma) # CPU function
**10 loops, best of 3: 60.8 ms per loop**>>> %timeit gaussian_dens_gpu(x, mean, sigma) # GPU function
**100 loops, best of 3: 6.88 ms per loop**
耶啊!
我们甚至可以使用 Numba 定义在 CPU 中执行的函数。
>>> %timeit gaussian_dens_cpu(x, mean, sigma) # CPU
**10 loops, best of 3: 23.6 ms per loop**
它甚至比用 Python 编写的函数还要快,但比在 GPU 中执行的函数要慢。
不幸的是,有几个函数不在 ufunc 的定义范围内,因此,为了在 GPU 中执行不满足该要求的函数,我们使用cuda.jit
。我们可以使用运行在 GPU 上的“设备功能”。
注 :“设备函数”是只能从内核或另一个“设备”函数调用的函数。
>>> %timeit polar_distance(rho1, theta1, rho2, theta2)
**The slowest run took 23.16 times longer than the fastest. This could mean that an intermediate result is being cached. 1 loop, best of 3: 10.2 ms per loop**
结论
总而言之,Numba 是一个 Python 编译器,专门针对数值函数,允许您使用直接用 Python 编写的高性能函数来加速应用程序。
它是一个稳定的工具,允许您优化面向数组操作的代码。感谢它的易用性(只是一个装修工!!)为我们提供了一个非常强大的工具来提高我们代码的性能。
欢迎建议和评论。关注我,感谢你的阅读!😃
前馈神经网络中的参数数量
手动计算前馈神经网络中可训练参数的总数
今天,机器学习正在解决如此大量的复杂问题,看起来就像魔术一样。但是机器学习没有任何魔力,相反它有很强的数学和统计基础。
在试图理解机器学习的重要且有些困难的概念时,我们有时甚至不会考虑一些琐碎的概念。也许你会想到这些,但是我知道我经常忽略很多简单的事情。原因是令人惊叹的机器学习和深度学习库,它们具有为我们快速做到这一点的功能和方法。😍
一个这样的小问题是手动找出前馈神经网络中可训练参数的总数。我在一次考试中遇到的一个问题,它让我对所提供的选项感到困惑。这个问题也被很多机器学习的从业者在很多不同的论坛上问过。🙋🏻
本帖讨论的问题是:
如何求一个前馈神经网络中可训练参数的总数?
你一定想知道为什么这是一个需要讨论的重要问题。的确是!训练一个模型所需的时间取决于要训练的参数的数量,因此这些知识有时真的可以帮助我们。
通过查看一个简单的网络,您可以很容易地计算并说出参数的数量。最坏的情况,你可以画出图,说出参数个数。但是当你遇到一个问题,一个神经网络有 7 层,每层的神经元数量不同,比如说 8,10,12,15,15,12,6,会怎么样呢?你怎么知道总共有多少个参数?
让我们一起找到一个数学公式来得到计数。但是在开始计算之前,让我们先了解一下什么是前馈神经网络,它具有什么特征。这将帮助我们找到参数的总数。
前馈神经网络是最简单的人工神经网络,其中感知机之间的连接不形成循环。
尽管是最简单的神经网络,但它们对机器学习实践者来说极其重要,因为它们构成了当今使用的许多重要和高级应用的基础。🤘
前馈神经网络的特性;
- 感知器是分层排列的。第一层接收输入,最后一层给出输出。中间层被称为隐藏层,因为它们对外部世界是隐藏的。
- 一层中的每个感知器都连接到下一层的每个感知器。这就是信息不断从一层流向下一层的原因,因此得名前馈神经网络。
- 同一层的感知器之间没有联系。
- 从当前层到前一层没有向后连接(称为反馈连接)。
注: 感知器是计算输入值加权和的神经网络的基本单元。
数学上,前馈神经网络定义了映射y = f(x;θ) 并学习有助于找到最佳函数近似的参数 θ 的值。
注: 前馈神经网络中除输出层外的所有层中也有一个偏置单元。通过将激活功能向左或向右移动,偏差对成功学习非常有帮助。迷茫?🤔简单来说,bias 类似于直线的线性方程 y = mx + c 中的截距(常数),有助于预测线更好地拟合数据,而不是一条总是经过原点(0,0)的线(y = mx 的情况)。
现在让我们利用这一知识来找出参数的个数。
场景一: 一个只有一个隐层的前馈神经网络。输入层、隐藏层和输出层中的单元数分别为 3、4 和 2。
一个前馈神经网络(图片由作者提供)
假设:
i =输入层的神经元数量
h =隐含层神经元的数量
o =输出层神经元数
从图中,我们有 i = 3, h = 4, o = 2。请注意,红色神经元是该层的偏差。一层的每一个偏置都连接到下一层除了下一层偏置以外的所有神经元。
数学上:
- 第一层和第二层的连接数:3 × 4 = 12,无非是 i 和 h 的乘积。
- 第二层和第三层的连接数:4 × 2 = 8,无非是 h 和 o 的乘积。
- 层与层之间也有通过偏置的连接。第一层的 bias 和第二层的神经元之间的连接数(第二层的 bias 除外):1 × 4,无非就是 h 。
- 第二层偏置与第三层神经元的连接个数:1 × 2,无非是 o 。
总结所有:
3 × 4 + 4 × 2 + 1 × 4 + 1 × 2
= 12 + 8 + 4 + 2
= 26
因此,这个前馈神经网络总共有 26 个连接,因此将有 26 个可训练参数。
让我们试着用这个等式来概括,找出一个公式。
3 × 4 + 4 × 2 + 1 × 4 + 1 × 2
= 3 × 4 + 4 × 2 + 4 + 2
=I×h+h×o+h+o
因此,具有一个隐藏层的前馈神经网络中的参数总数由下式给出:
(I×h+h×o)+h+o
由于该网络是一个小型网络,因此也可以通过计算图中的连接数来得出总数。但是,如果层数更多呢?让我们再研究一个场景,看看这个公式是否有效,或者我们需要对它进行扩展。
场景一: 一个具有三个隐层的前馈神经网络。输入层、第一隐藏层、第二隐藏层、第三隐藏层和输出层中的单元数分别为 3、5、6、4 和 2。
假设:
i =输入层的神经元数
h1 =第一个隐藏层的神经元数量
h2 =第二个隐藏层的神经元数量
h3 =第三隐藏层的神经元数量
o =输出层的神经元数量
- 第一层和第二层的连接数:3 × 5 = 15,无非是 i 和 h1 的乘积。
- 第二层和第三层的连接数:5 × 6 = 30,无非是 h1 和 h2 的乘积。
- 第三层和第四层的连接数:6 × 4 = 24,无非是 h2 和 h3 的乘积。
- 第四层和第五层的连接数:4 × 2= 8,无非是 h3 和 o 的乘积。
- 第一层的 bias 和第二层的神经元(第二层的 bias 除外)的连接个数:1 × 5 = 5,无非就是 h1 。
- 第二层偏置与第三层神经元的连接个数:1 × 6 = 6,无非是 h2 。
- 第三层偏置与第四层神经元的连接个数:1 × 4 = 4,无非是 h3 。
- 第四层偏置与第五层神经元的连接个数:1 × 2 = 2,无非是 o 。
总结所有:
3 × 5 + 5 × 6 + 6 × 4 + 4 × 2 + 1 × 5 + 1 × 6 + 1 × 4 + 1 × 2
= 15 + 30 + 24 + 8 + 5 + 6 + 4 + 2
= 94
因此,这个前馈神经网络总共有 94 个连接,因此有 94 个可训练参数。
让我们试着用这个等式来概括,找出一个公式。
3 × 5 + 5 × 6 + 6 × 4 + 4 × 2 + 1 × 5 + 1 × 6 + 1 × 4 + 1 × 2
= 3 × 5 + 5 × 6 + 6 × 4 + 4 × 2 + 5 + 6 + 4 + 2
= I×h1+h1×H2+H2×H3+H3×o+h1+H2+H3+o
因此,具有三个隐藏层的前馈神经网络中的参数总数由下式给出:
(I×h1+h1×H2+H2×H3*+H3×o+h1+H2+H3+o***
T 因此,找到具有 n 个隐藏层的前馈神经网络中可训练参数总数的公式由下式给出:
计算前馈神经网络中参数总数的公式(图片由作者提供)
如果这个公式听起来有点让人不知所措😳,别担心,没必要背这个公式🙅。请记住,为了找到参数的总数,我们需要总结以下内容:
- 输入层和第一个隐藏层中神经元数量的乘积
- 两个连续隐藏层之间神经元数量的乘积之和
- 最后一个隐藏层和输出层中神经元数量的乘积
- 所有隐藏层和输出层中神经元数量的总和
现在,我希望你可以应用这种方法,即使不使用库,也可以找到具有任意数量的隐藏层和神经元的前馈神经网络中的参数总数。🙃
参考:
谢谢大家!如果你对这篇文章有任何反馈或建议,请留下你的评论!