TowardsDataScience 博客中文翻译 2020(一千零一十)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

世界 2 模型,从发电机到 R

原文:https://towardsdatascience.com/world2-model-from-dynamo-to-r-2e44fdbd0975?source=collection_archive---------14-----------------------

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

世界动态,如 Forrester (1971)的 World2 模型中所定义。

第一个世界末日计算机模型,基于 Forrester 的系统动力学,用 R 编程语言重新审视

“1972 年,一本名为《》的平装小书大张旗鼓地出版了。这本书警告说,世界正在走向灾难。如果方向没有重大改变,在 50 年或 100 年内,人类将会耗尽食物和自然资源,或者因自身污染而窒息(Hayes,1993)。

杰伊·赖特·福雷斯特(1918–2016)是美国计算机工程师和系统科学家,被誉为系统动力学的“创始人”。虽然比写了《增长的极限》(Meadows et al .,1972)的 Meadows 夫妇更少为人所知,但 Forrester 的世界动力学模型 World2 (Forrester,1971)是所有后续模型的基础预测到 21 世纪中叶我们的社会技术自然系统将崩溃*。本文从编程的角度重新审视了这项开创性的工作,将过时的 DYNAMO 代码重写为 r。它将提供世界动力学模型的全新视角,并可以在以后用作机器学习练习的输入模型。*

《世界动力学》简史

Forrester 于 1989 年在德国斯图加特的系统动力学学会上发表的一次演讲的文字记录为我们提供了媒体对他的世界末日计算机模型的发表的反应的第一手资料:

“《世界动态》于 1971 年 6 月的第一周出版。六月的最后一周,伦敦《观察家报》的头版对此进行了评论。我收到了纽约一位大学教授的来信,要求提供更多的信息,因为他在《新加坡时报》上读到了这本书。8 月份,这本书占据了《基督教科学箴言报》第二版的整个头版,9 月份占据了《财富》的一个半版,10 月份占据了《华尔街日报》的一个专栏。它出现在美国中部报纸的社论栏中,它是欧洲黄金时间纪录片电视的主题,它在环境媒体、人口零增长媒体和反体制的地下学生媒体中被辩论。而且,如果你不喜欢你的文学作品中既有当权派右派也有当权派左派,那么就在政治光谱的中间,在《世界动态》出版九个月后,《增长的极限》在《花花公子》上发表了一篇完整的文章。信息基本上是一样的,尽管做了更多的工作,这本书也更受欢迎……”—杰伊·w·福瑞斯特,1989**

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

继 Sterman (2001)之后,系统动力学学派的现任领袖,两次授予 Jay W. Forrester 系统动力学最佳出版作品奖。来源:维基百科

系统动力学是一种理解复杂系统随时间变化的非线性行为的方法,使用股票、流量、内部反馈回路、表格函数和时间延迟(维基百科)。事实上,它来源于早期的控制论著作。

World2 不是 Forrester 在系统动力学方面的第一个主要工作,因为他已经将该方法应用于“工业动力学”中的工厂规划(Forrester,1961),然后应用于“城市动力学”中的城市规划(Forrester,1969;有趣的是,这后来对电子游戏《模拟城市》的创作产生了影响;Lobo,2007)。Forrester 在城市动力学方面的工作引起了罗马俱乐部的注意,这引发了对全球可持续性的讨论,并在 1971 年出版了《世界动力学》一书,其中提出了 World2 模型。 Meadows 的团队并行开发了模型的扩展,产生了 World3 版本 (Meadows 等人,1972;梅多斯,1974;Meadows 等人在 2004 年更新;另见 Randers,2012 年)。有趣的是,Forrester 在他与瑞士罗马俱乐部的会议结束后,在回家的飞机上草拟了一个模型的初步版本,名为 world 1(Hayes,1993)。

World1 模型的初步结果。2 分 35 秒:“我们来到 2020 年,它真的回来了。当然,更多的人意味着你开始消耗你的自然资源,这是这条曲线,N 曲线,显示了…

重新运行模型 World2 和 World3

“1971 年的‘世界动态’似乎已经具备了保证不引起公众注意的一切必要条件。首先,在书的中间有40 页的方程式,这足以压制公众的兴趣。第二,有趣的信息是以电脑输出图的形式出现的,而大多数公众并不理解这样的演示。” —杰伊·w·福雷斯特,1989 年

在纸上阅读一个模型的特征和输出不足以完全掌握其潜在的机制和假设。由于世界 2 和世界 3 模型在系统动力学中的历史重要性以及随后 50 年的争论,重温源代码是值得的。

虽然我认为很容易找到这些模型的现代版本,但事实上我不得不深入挖掘以找到一些开放源代码,并最终决定在阅读 Forrester (1971)的基础上,用 R 从头开始重做 World2 模型。下面是我通往 Rworld2 项目的旅程总结:

  • 在 R 中找不到代码;
  • 提到了一个法国团队在 2018 年创建的 Python 代码( PDF1PDF2 ),但显然不能直接访问;

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

截图来自 javascript 的 World3 测试版,来自bit-player.org

  • 事情变得越来越具体:存在一个 Javascript 仪表板,允许用户尝试 World3 模型的不同参数化,并绘制结果。然而,的免责声明声明“t 这是一个正在进行的工作,很可能有严重的错误”这与该工具的作者 Brian Hayes 的一篇非常好的文章有关,他在《美国科学家》杂志上写了几篇关于“增长的极限”的文章。2012).下面是这篇文章的一个重要内容:“最初的 World3 模型运行在大型机硬件上——IBM 360 和 370 机器。“迪纳摩计划的其他金块如下,以下是四个要点。
  • Hayes 提到“有几种更通用、更值得信赖的实现方式”,并提供了下面的链接,不幸的是,到 2020 年这个链接已被打破。
  • Scott Fortmann-Roe 通过 Insightmaker (Fortmann-Roe,2014 年)提供了一个值得信赖的 World3 实现——然而,使用一个基于 web 的图形模型构造的通用工具与我最初想到的简单脚本的灵活性不一致。

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

https://insight maker . com/insight/1954/The-World3-Model-A-Detailed-World-predictor对 World 3 模型进行在线模拟。

  • 最可靠和最好记录的开源版本的 World2World3 是由弗朗索瓦·e·塞利耶在 Modelica 中编写的(塞利耶,2007;2008;卡斯特罗等人,2014)。World3 的文档提供了一些有价值的历史信息:“Jay Forrester 在他的书《世界动力学》中列出了他的整个模型,而 Dennis Meadows 只在《增长的极限》中谈到了使用他的模型获得的结果。型号本身没有列出。然而,梅多斯从未试图隐藏自己的模型,以躲避公众的审视。事实上,他写了一份 637 页的 内部报告,描述了他的 模型的方方面面。1974 年,他将这份内部报告作为独立的一本书出版了:《有限世界中的增长动力学》。“Cellier(2008)补充道:“虽然 Forrester 和 Meadows 的著作在 70 年代初首次出版时引起了不小的轰动,但世界建模很快就变得不流行了,因为基本上所有的资金来源都因为政治原因而枯竭了。 只是最近,在石油峰值事件迫在眉睫的背景下,并且因为正在进行的关于全球变暖的讨论,世界建模才再次变得受人尊敬 。这使得 Rworld2 成为一个及时的项目,特别是因为 Modelica 代码虽然可用,但不太可能直接用于任何现代数据科学项目。

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

左图:显示 World2 场景 1 的 OpenModelica OMEdit 平台;右图:Modelica 中 World2 程序的摘录(OpenModelica 库的一部分,可在文件夹/om library/system dynamics 2.1/package . mo 中找到)。

  • 回到起点!既然 Modelica 程序本身是从 Forrester (1971)提供的原始 DYNAMO 代码翻译而来,为什么还要翻译它呢? 迪纳摩(动力学模型) 最初是由 Forrester 的 MIT 团队在 20 世纪 50 年代末开发的,用于系统动力学计算。世界 2 和世界 3 最初都是用 DYNAMO 编写的。自从《增长的极限》出版后,这种语言就不再使用了。 Hayes 描述得很好:“在词汇和句法结构上,DYNAMO 是你对穿孔卡片时代的语言的期望——六个字母的变量名和全部大写——但在其他方面,它是一个有趣的早期实验,其编程风格介于过程式和声明式之间。“这是 Forrester (1971:136)的附录 B‘世界模型的方程式’的摘录,显示了 DYNAMO 中的一些代码行:
*** WORLD DYNAMICS W5
L P.K=P.J+(DT)(BR.JK-DR.JK)
N P=PI
C PI=1.65E9
R BR.KL=(P.K)(CLIP(BRN,BRN1,SWT1,TIME.K))(BRFM.K)(BRMM.K)(BRCM.K)
X (BRPM.K)
C BRN=.04
C BRN1=.04
C SWT1=1970
A BRMM.K=TABHL(BRMMT,MSL.K,0,5,1)
T BRMMT=1.2/1/.85/.75/.7/.7
A MSL.K=ECIR.K/(ECIRN)**

世界 2 从零开始

现在让我们看一下模型的结构,乍一看可能会让人不知所措。我建议先看看世界 3 的结构,使世界 2 的复杂性更加相关(世界 2 中有 43 个控制方程,而世界 3 中有 150 个)。

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

****世界 2 模型的完整图表涉及五个层次的变量——人口、自然资源、资本投资、农业资本投资和污染,摘自 Forrester(1971:20–21,图 2–1)。因此,World2 是一个 5 阶微分方程模型。这个图怎么看?首先,确定 5 个级别(红色),然后是代表流入和流出的比率(蓝色),最后是许多因素(黄色)。水平、比率和因素之间的相互关系(蓝色)在 World2 等式中定义。

我发现 Forrester (1971)第 3 章中提供的 DYNAMO 脚本比附录 b 中给出的完整代码更容易理解。我通过遵循书中相同的编号系统来识别不同的“方程”(即赋值语句)以进行直接匹配。类似地,我保留了相同的变量和函数名。在 DYNAMO 中顺序并不重要,所以 R 中最繁琐的步骤是对 World2 的 43 个等式和所谓的乘数(见下文)进行重新排序,以便正确定义和更新所有变量(因此我手动完成了 DYNAMO 编译器的工作。将 R 中的 World2 编码为一个图,然后应用拓扑排序,这将是一个挑战,尽管很诱人。

等式的一个例子在下面的 R 中给出:

**# logical function used as time switch to change parameter value
CLIP <- function(FUNCT1, FUNCT2, THRESH.K, VAL) if(THRESH.K >= VAL) return(FUNCT1) else return(FUNCT2)DT <- .2
TIME <- seq(1900, 2100, DT)   # CALENDAR TIME (YEARS)
n <- length(TIME)# (...)## (2) Birth rate BR ##
# BR.KL = P.K CLIP(BRN, BRN1, SWT1, TIME.K) BRFM.K BRMM.K BRCM.K BRPM.K
# BRFM = BIRTH-RATE-FROM-FOOD MULTIPLIER ()
# BRMM = BIRTH-RATE-FROM-MATERIAL MULTIPLIER ()
# BRCM = BIRTH-RATE-FROM-CROWDING MULTIPLIER ()
# BRPM = BIRTH-RATE-FROM-POLLUTION MULTIPLIER ()
BR <- numeric(n)    # BIRTH RATE (PEOPLE/YEAR)
BRN <- .04          # BIRTH RATE NORMAL (FRACTION/YEAR)
BRN1 <- .04         # BIRTH RATE NORMAL no. 1 (FRACTION/YEAR)
SWT1 <- 1970        # SWITCH TIME no. 1 FOR BRN (YEARS)# (...)for(K in 2:n){
  J <- K - 1 # (...) BR[K] <- P[J] * CLIP(BRN, BRN1, SWT1, TIME[J]) * BRMM(MSL[J]) * BRCM(CR[J]) * BRFM(FR[J]) * BRPM(POLR[J])  # (2-3,16-18) # (...)**

BR 是出生率,是人口 P、MSL 物质生活水平、拥挤 CR、食物 FR 和污染 POL (POLR 是污染比率)的函数。BR 与 P 成比例增长,并通过称为乘数的单值函数依赖于其他变量(BR .variable. M)。现在是一个乘数示例,基于 Forrester 定义的查找表:

**library(signal)  # interp1()## (3) Birth-rate-from-material multiplier BRMM ##
BRMM = function(MSL.K){
  # MSL   = MATERIAL STANDARD OF LIVING ()
  # BRMMT = BIRTH-RATE-FROM-MATERIAL MULTIPLIER TABLE
  lookup.table <- data.frame(MSL = seq(0, 5, 1), 
                             BRMMT = c(1.2, 1., .85, .75, .7, .7))
  return(interp1(lookup.table$MSL, lookup.table$BRMMT, MSL.K))
}**

为了清晰地解释 Forrester 构建 World2 的方法,我推荐 Castro 和 Cellier 的这个 2016 演示文稿。由于 Rworld2 代码大约有 500 行长(包括许多与 Forrester,1971 年的第 3 章直接匹配的注释),所以这里没有给出它的全文,但是可以在我的 GitHub repohist _ GC _ sys dyn(History _ global distoriates _ system dynamics 的简称)中找到。最后,让我们画出结果。

**# basic plots with same y-range as in Fig. 4-1 of Forrester (1971)plot(TIME, P, type = 'l', ylim = c(0, 8e9))
plot(TIME, POLR, type = 'l', ylim = c(0, 40))
plot(TIME, CI, type = 'l', ylim = c(0, 20e9))
plot(TIME, QL, type = 'l', ylim = c(0, 2))
plot(TIME, NR, type = 'l', ylim = c(0, 1000e9))**

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

****Rworld2人口 P、污染率 POLR、资本投资 CI、生活质量 QL 和自然资源 NR 的原始结果。

通过将结果与 Forrester (1971 年)的图 4–1 进行比较,很容易验证 R 代码是否正确— 参见 GitHub 上的图。《Rworld2》很粗糙,但我想保留弗雷斯特原著中 20 世纪 70 年代的精髓。未来的工作将包括一个交互式仪表板,正如 javascript 和 Insight Maker 已经提供的那样。另一个步骤是用 R 写 World3(如果 Rworld2 花了我一整天的工作,Rworld3 应该花了大约半个星期)。一个长期的项目是将模型定义为一个图。

最终注释

这篇中型文章的目的是从编程的角度展示 World2 模型,并提供一个 R 版本,这是以前所缺乏的。围绕各种世界末日场景的争论不是本文的主题,但读者可能会问,在 2020 年运行 World2 是否有任何用处。因此,让我引用 Cellier (2008)关于这种过时模型的有用性的话:“事实证明,Forrester 和 Meadows 的评估基本上是正确的,尽管他们的模型与现实世界的动态相比非常粗糙。“这些“简单”模型的有效性已经在最近的研究中得到证实,这些研究将过去的预测与观察结果进行了比较(Turner,2008;2014).

参考

Castro R,Fritzson P,Cellier F,Motesharrei S,Rivas J (2014),【Modelica 世界建模中的人与自然互动。 Proc。第十届国际 Modelica 会议,瑞典隆德,477–488。
Cellier FE (2007),生态足迹,能源消耗,以及即将到来的崩溃油桶
Cellier FE (2008),Modelica 中的 World3:在 Modelica 框架中创建系统动力学模型过程。2008 年 modelica,2393400 英镑。
福瑞斯特·JW(1961 年)产业动态。麻省理工学院出版社,剑桥,464 页
福瑞斯特·JW(1969)城市动力学。飞马通信公司,沃尔瑟姆,285 页。
福瑞斯特·JW(1971),《世界动态》。Wright-Allen Press,Inc .,Cambridge,144 页。
Fortmann-Roe S (2014), Insight Maker:基于 web 的建模通用工具&模拟模拟建模实践与理论,47,28–45。
海斯 B(1993)计算科学:在铅笔尖上保持平衡美国科学家,81(6),510–516。
Hayes B (2012),计算科学:计算和人类困境,增长的极限和计算机建模的极限美国科学家,100(3),186–191。
Lobo DG (2007),玩转都市生活。在 von Borries 等人(编辑)的文章中,时空玩电脑游戏,建筑和城市化:下一个层次。伯克豪泽,495 页。
梅多斯 DH,梅多斯 DL,兰德斯 J,伯伦斯三世 WW(1972)增长的极限 。宇宙图书,纽约,205 页。
梅多斯 DL(1974)有限世界中的增长动力学。赖特艾伦出版社,剑桥,637 页
梅多斯 D,梅多斯 D,兰德斯 J(1992)超越极限。切尔西格林出版社,300 页。
梅多斯 D,兰德斯 J,梅多斯 D (2004),增长的极限:30 年更新。切尔西格林出版社,338 页。
兰德斯 J (2012), 2052:未来四十年全球预测。切尔西格林出版社,416 页。
斯特曼法学博士(2001),系统动力学建模:复杂世界中的学习工具加州管理评论,43(4),8–25
特纳通用汽车(2008),增长的极限与 30 年现实的比较。全球环境变化,18,397–411。
特纳通用汽车(2014),全球崩溃是否迫在眉睫?增长的极限与历史数据的最新比较。MSSI 研究论文№4,墨尔本可持续社会研究所,墨尔本大学,共 21 页

你更愿意做数据分析师还是数据科学家?

原文:https://towardsdatascience.com/would-you-rather-be-a-data-analyst-or-data-scientist-a107c84cd09e?source=collection_archive---------10-----------------------

扮演其中一个角色是什么感觉?在这里找到答案。

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

照片由克里斯蒂娜@ wocintechchat.com 拍摄。

目录

  1. 介绍
  2. 数据分析师
  3. 数据科学家
  4. 摘要
  5. 参考

介绍

作为一名专业数据分析师和数据科学家,我认为强调每个职位的经历以及他们日常感受的一些关键差异是有见地的。最终,我希望我的文章能帮助你决定哪个角色最适合你。如果你已经处于其中一个位置,也许你想换到另一个位置。一些人从数据分析师开始,然后成为数据科学家,然而,作为一个不太受欢迎但仍然有点突出的途径,是从非高级数据科学家职位到高级数据分析师。对于每一个职位,在你进行下一次重大职业变动时,有几个概念和总体经验是很重要的。

下面,我将强调作为数据分析师和数据科学家的感受。我将提出关于每个角色的常见问题,并根据我的经历做出相应的回答——此外还有每个领域的一些亲密同行。

数据分析师

如果你想描述过去或当前的数据,同时展示关键的发现、变化和趋势,并最终将数据可视化给利益相关者,那么数据分析师的职位最适合你。虽然这两个职位之间有一些重叠,我在另一篇文章(链接在本文的末尾)中强调了这两个职位技能之间的差异和相似之处,但我现在想花一些时间来回顾一下作为数据分析师和数据科学家的感受。重要的是要知道在这个领域你每天会期待什么。你可以期望与不同的人一起工作,以不同的方式沟通(更多),并且比典型的数据科学家行动更快。

因此,你对每个角色的感受可能会大相径庭。

下面,我将提出一些常见的问题及其相应的回答,以阐明数据分析师的体验。

  • 你和谁一起工作?

—您将主要与公司中要求提取数据、可视化见解和报告的利益相关方合作。通过使用电子邮件、Slack 和吉拉等工具,可以预期沟通将是口头和数字的。你将专注于业务的人员和分析方面,而不是公司的工程和产品部分(根据我的经验*)。*

  • 你与谁分享你的发现?

—你将与上面的人分享你的发现。然而,如果你有一个经理,有时,你会向他们报告,他们会转达和分享你的发现给适当的利益相关者。您可能还有一个收集需求、开发报告并将其传达给利益相关者的过程。您可以使用 Tableau、Google Data Studio、Power BI 和 Salesforce 等工具进行报告。这些工具通常可以连接到容易访问的数据源,如 CSV 文件,而有些工具需要更多的技术工作,通过 SQL 对数据库进行高级查询。

  • 你需要以多快的速度完成一个项目?

—您从事项目的速度将比数据科学家快得多。你可以每天有几个数据拉取(查询)或报告,每周有更大的可视化和洞察力。因为你不是在建立模型和预测(通常是),你会更快地得到结果,因为它们更具描述性和针对性。

数据科学家

数据科学家与数据分析师大相径庭。虽然一些工具和语言可以在这两个角色之间重叠,但你可以预期与不同的人一起工作,并花更多时间研究更大的项目,如机器学习模型的创建和部署。数据分析师可能倾向于独立完成他们的项目;例如,使用 Tableau 仪表板来呈现结果可能需要一个人,但数据科学家可以整合其他几个工程师和产品经理来确保模型解决了业务问题,并且代码是正确的、强大的和高效的。

  • 你和谁一起工作?

—与数据分析师不同,在项目的某些方面,您将与利益相关者合作,但在模型及其结果的其他方面,您将求助于数据工程师、软件工程师和产品经理。

  • 你与谁分享你的发现?

—您可以与利益相关者分享您的发现,但也可以与一些工程师分享,他们需要知道最终产品是什么,以便他们可以围绕您的预测构建 UI(用户界面)。

  • 你需要多快完成一个项目?

—也许这些角色感觉和操作的最大区别是你分配给每个项目的时间。尽管数据分析的节奏更快,但数据科学家可能需要几周或几个月才能完成一个项目。由于存在数据收集、探索性数据分析、基础模型创建、迭代、模型调整和结果输出等过程,数据科学模型和项目可能需要更长时间。

摘要

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

马库斯·温克勒在Unsplash【2】上的照片。

作为一名数据分析师和数据科学家,您可以共享 Tableau、SQL 甚至 Python 等常用工具,但每个角色的体验可能会大不相同。数据分析师的日常工作包括更多的会议、更多的面对面互动、软技能和更快的项目周转。数据科学家的工作可能涉及更长的流程、与工程师和产品经理的互动,以及总体而言,预测模型着眼于及时分类新的观察结果或事件,而数据分析则侧重于过去和当前的状态。

我已经写了一篇关于这些角色细节的更深入的文章。你可以在这里找到这篇文章[2]:

* [## 数据科学与数据分析。区别就在这里。

数据科学家和数据分析师的主要区别和相同点是什么?阅读下面的概述…

towardsdatascience.com](/data-science-vs-data-analysis-heres-the-difference-4d3da0a90f4)

我希望你觉得这篇文章有趣并且有用。感谢您的阅读!

参考

[1]照片由克里斯蒂娜@ wocintechchat.com(2019)拍摄

[2]马库斯·温克勒在 Unsplash 上拍摄的照片,(2020)

[3] M.Przybyla. 数据科学 vs 数据分析。区别就在这里。,(2020 年)*

你更愿意成为 NLP 还是计算机视觉数据科学家?

原文:https://towardsdatascience.com/would-you-rather-be-an-nlp-or-computer-vision-data-scientist-5b1d45e1c601?source=collection_archive---------14-----------------------

意见

深入了解这些受欢迎的数据科学家角色。

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

JESHOOTS.COMUnsplash【1】上的照片。

目录

  1. 介绍
  2. 数据科学
  3. 自然语言处理
  4. 计算机视觉
  5. 摘要
  6. 参考

介绍

在申请数据科学家的职位时,您可能会在职位描述部分看到各种所需的技能。向下滚动,你会发现不同职位所要求的教育程度也是不同的。最重要的是,您会看到一个概述,概述了该角色,尽管职位的标题是相同的,但部分却有很大的不同。这种变化是由于不同类型的数据科学职位。然而,我注意到,随着公司了解他们在数据科学方面的专长,这些角色有了新的名称。数据科学的这两个热门分支是自然语言处理(NLP)和计算机视觉。根据你最终将为之工作的公司,或者目前为之工作的公司,一些职位仍将被称为数据科学,但重点是 NLP 或计算机视觉,而一些职位将是全面的数据科学。我将重点介绍 NLP 和计算机视觉,以便您可以找到更多信息,了解这两者的含义,以及各自的预期工资,以及哪个角色最终更适合您。

数据科学

数据科学是一个非常宽泛的术语,经常在人们中间引起争议,尤其是在技术领域。当前的数据科学家可能会根据他们在第一份工作中的经历,对他们认为数据科学真正是什么有一些偏见,但后来会意识到数据科学实际上是几个学科的总称。这些学科包括或围绕自然语言处理、计算机视觉、机器学习、统计学、数学、编程、数据分析、产品管理和商业智能。这真的取决于你和你工作的公司来决定你想要走什么样的道路,或者成为所有这些方面的多面手。专攻 NLP 或计算机视觉的一个好处是,你将知道你将进入什么领域,并可以专注于学习和提高每个职位所需的特定技能。

自然语言处理

有时,专门从事 NLP 的数据科学家也被称为 NLP 工程师。这种专业化专注于人类的自然语言,以及计算机如何参与消化这种非结构化的输入,然后输出结构化的、有用的意义。虽然这种类型的数据科学有无数的定义和例子,但我想给出我个人在 NLP 方面的专业经验。我主要参与过三种类型的 NLP 项目。这三个项目包括:

  • 情感分析
  • 主题建模
  • 文本分类

这些项目有主要的概念,这些概念也可以应用于其他形式的 NLP。他们都共享相似的工具和代码来创建有益的输出。具体来说,我在 Python 编程语言中使用 NLP 最多。

情感分析 —这种形式的自然语言处理关注给定文本的情绪或情感、极性和主观性。情感分析的典型工作流程是收集数据,对其进行预处理,然后对其进行表征。本质上,在这一点上,你将有你正在分析的每一个词,清理,并剥离,以便这些词可以被标记。下一部分通常被称为词性标注。一旦你确定了你所拥有的词的类型,比如形容词、名词和动词,你就可以很容易地应用一个库的功能,为每个文本分配一个极性分数。一些流行的情感 NLP 库是 TextBlob 和 Vader perspection。我在这里不会讲得太深入,但是如果你想写一篇关于 NLP 和这两个流行的库的文章,我很乐意这样做(请在下面评论)。情感分析可以被大多数企业广泛使用。这里有一些可以应用情感分析的例子:

—客户评论

—客户细分

—异常检测

—产品改进

下面是情感分析的总结流程:

gather datapreprocesstokenizePOS tagscoring

主题建模 —这种形式的自然语言处理属于无监督学习的一个分支,帮助你找到由文本组成的文档的主题。在文档中查找主题最流行的方法之一是利用 LDA 或潜在 Dirichlet 分配。这是一种技术,最终输出的主题总结了流行的和重要的,关键短语从你的文本。这里有一些可以应用主题建模的例子:

—从课文中提出新的话题

—使用这些主题来分配新的监督学习标签

—通过手动搜索很难找到的见解

文本分类 —这种形式的 NLP 是一种监督学习技术,有助于对新的数据实例进行分类,这些数据实例不一定只包含文本,也可以包含数值。比这两种 NLP 形式更广泛的是,您可以将文本分类视为一种典型的分类算法,其中标签是文本,一些特征也是文本。您将使用上述相同的技术对文本进行预处理、清理和提取含义。这里有一些可以应用文本分类的例子:

—对特殊动物进行分类

—将假新闻分类

—对银行交易进行分类

最流行的 Python 包是nltk【2】,它代表自然语言工具包。它包含了几个库,这些库对于你用 NLP 技术解决问题是必不可少的。

[## 自然语言工具包- NLTK 3.5 文档

NLTK 是构建 Python 程序来处理人类语言数据的领先平台。它提供了易于使用的…

www.nltk.org](https://www.nltk.org/)

一个 NLP 工程师挣多少钱?

根据glass door【3】统计,美国一名 NLP 工程师的平均工资为 114121 美元/年。

计算机视觉

我相信这个数据科学领域甚至比 NLP 更专业。计算机视觉关注图像和视频数据,而不是数字或文本数据。对我来说,计算机视觉的风险更大,因为它可以用于更多不一定依赖于洞察力,但需要安全措施到位的行业。想想 NLP 和情感分析如何分析某人评论的快乐,这种洞察力是有用和强大的,但不如计算机视觉那样有影响力或有害。下面我将重点介绍一些类型的计算机视觉。

面部识别 —当你拿起手机时,你很可能会有一个安全功能,它会分析你的面部,看看是否真的是你试图访问你的手机。一个有益于面部识别项目的流行 Python 库被恰当地命名为 face_recognition 。您处理的由面组成的图像被编码为一个特征。基于面部的共同特征,您可以将()个别面部与相同或不同的面部进行匹配,以便最终“识别”面部。

物体检测 —使用来自物体的信息,这种形式的计算机视觉可以帮助检测物体。OpenCV 是程序员和数据科学家使用的流行工具,他们希望专注于对象检测。

你可以期待在中找到计算机视觉的例子

—图像检测

— iPhone Face ID

—脸书照片标签

—特斯拉行人和汽车检测

一个计算机视觉工程师挣多少钱?

glass door【4】报道,美国一名 NLP 工程师的平均工资为 99619 美元/年。

虽然这两个工资都很高,但我个人从招聘信息中看到,不仅计算机视觉工程师的工资高于报道的平均工资,NLP 工程师也是如此。因为数据科学中的这两个角色越来越专业化,我相信这就是为什么你可以期望有更高的工资。

摘要

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

安妮·斯普拉特在Unsplash【5】上的照片。

大多数数据科学家可能研究过某种形式的 NLP 或计算机视觉,无论是来自大学还是在线教程。数据科学中的这两个专业角色都非常受尊重,可以让无数行业受益。在回答“你更愿意做 NLP 工程师还是计算机视觉工程师”这个问题时,最终取决于你的偏好和职业目标。’。想一想你想从事什么类型的项目,想为哪个行业工作,想和哪个公司合作。数据科学领域的这两个职位都能给你的工作带来巨大的影响,所以这两个职位都会给你一次激励的经历。

我希望你觉得这篇文章有趣并且有用。请随意在下面评论您作为一名普通数据科学家、NLP 工程师或计算机视觉工程师的经历。

感谢您的阅读!

参考

[1]照片由JESHOOTS.COMUnsplash(2018)拍摄

[2] NLTK 项目,自然语言工具包,(2020)

[3] Glassdoor,Inc .,NLP 工程师工资 T25,(2008-2020 年)

[4] Glassdoor,Inc .,计算机视觉工程师工资,(2008–2020)

【5】安妮·斯普拉特在Unsplash(2020)上拍摄的照片

你会在泰坦尼克号上幸存吗?——对 Kaggle 的经典挑战

原文:https://towardsdatascience.com/would-you-survive-the-titanic-a-classic-challenge-on-kaggle-3efaa22bfb5e?source=collection_archive---------34-----------------------

关于如何开始 Kaggle 之旅的 7 步指南

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

安东尼·梅特卡夫在 Unsplash 上的照片

卡格尔

Kaggle 是数据科学家共享数据、交流思想和在预测分析问题上竞争的平台。人们经常认为 Kaggle 不适合初学者,或者它有一个非常陡峭的学习曲线

他们没有错。但是它们确实给像你我一样刚刚起步的人带来了挑战。作为一名(初级)数据科学家,我无法抗拒搜索有趣的数据集来开始我的 Kaggle 之旅。 和我撞上了泰坦尼克号。

Kaggle 是数据科学家的 Airbnb 这是他们度过夜晚和周末的地方。齐尚·哈桑·乌斯马尼

泰坦尼克号

该数据集包含泰坦尼克号上乘客的信息。

我使用了 Python 来可视化和理解更多关于数据集的内容。我训练了一个分类器的集合,使用 scikit-learn 来预测一个人的生存几率**。然后,我使用 pickle 保存这个模型,并使用 Flask 将它作为 Web App 部署在本地主机上。最后,我利用 AWS 来云托管它。**

该代码可在 GitHub 上获得。

坐稳了,我们走!

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

和 hika SorengUnsplash 上的照片

1.数据检查

首先要做的事。我把数据导入到一个熊猫 数据框 中。它包括乘客 ID、幸存者、机票等级、姓名、性别、年龄、船上兄弟姐妹和配偶的数量、船上父母和子女的数量、机票号、乘客票价、客舱号和出发港。

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

前 5 行数据

我立即想到的是:

  • PassengerId是每个条目唯一的
  • Survived是我们要用推断的目标,
  • Name可能没有帮助,但是他们的头衔可能有帮助,
  • Ticket是一团,而且
  • 缺失数据标注为NaN

为了简单起见,我决定暂时去掉变量Ticket。它可能包含有用的信息,但提取这些信息需要大量的特征工程。我们应该从最容易的开始,并从那里着手。

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

缺失数据的比率

另一方面,让我们仔细看看缺失的数据。变量EmbarkedFare中有几项缺失。另一方面,大约 20%的乘客年龄没有被记录**。这可能会给我们带来一个问题,因为Age可能是数据集中的关键预测值之一。“妇女和儿童优先”在当时是一种行为准则,报告表明他们确实是首先被拯救的。Cabin中有 > 77%的漏项,不太可能有太大帮助,暂且不提。**

2.数据可视化

Pair plot (下面未显示)通常是我在数据可视化任务开始时的首选,因为它通常很有帮助,并且它具有很高的信息与代码行数比率。一条单线seaborn.pairplot()给你 n 个图(技术上是 n(n+1)/2 个不同的图),其中 n 代表变量的数量。它让你对每一对变量之间的关系,以及每个变量本身的分布有一个基本的了解。让我们深入研究不同的变量。

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

我们首先逐个检查目标变量Survived与每个预测值的关系。到了seaborn.countplot(),我们发现大多数人属于第三类,这并不奇怪;总的来说,他们存活的概率较低。即使有这个单一的预测因素, 考虑到其他一切未知的 ,我们可以推断一个头等舱乘客更有可能幸存,而这对于一个三等舱乘客来说不太可能。

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

同时,妇女和儿童更有可能幸存,这与前面提到的 【妇女和儿童优先】 理论相一致。如果我们只考察三个变量PclassSexAge,头等舱的年轻女性乘客现在将是最有可能生还的人。

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

然而,解释乘客票价密度图可能会更难。对于“幸存”和“未幸存”两类,它们的跨度很大,其中“未幸存”类的均值和方差较小。请注意,在“幸存”等级的分布中有一个有趣的尾巴**,它对应于三个人每人获得 512 美元的头等舱机票。他们都是在瑟堡港上船的,所有人都活了下来。**

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

另一方面,出发港似乎也在决定谁将幸存的问题上扮演了一个角色。大多数人在南安普顿港上船——旅程的第一站,他们的存活率最低。也许他们被分配到离出口更远的船舱,或者在游轮上花更多的时间会让人放松或疲惫。或者,这可能只是由第三个变量间接导致的——比如说,在第一个港口上船的妇女/儿童/头等舱乘客可能更少。需要进一步调查。

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

如果你喜欢表格而不是图表,我们也可以通过pandas.DataFrame.groupby()将数据可视化,并取每一类的平均值。但是,我觉得下面的Parch的表格中并没有一个清晰的模式显示出来。

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

****由seaborn.heatmap()生成的相关矩阵说明了任意两个变量之间的相关强度。如您所见,SexSurvived的相关性最高,而FarePclass的相关性最高。SibSpParch似乎在预测一个人的生存机会方面没有太大作用,尽管我们的本能表明情况并非如此。

3.缺失数据插补

我们之前在数据检查中发现有很多缺失数据条目**。例如,我们似乎不知道一位 60 岁的托马斯·斯托里买票花了多少钱。直觉告诉我们,机票价格在很大程度上取决于机票等级和出发港口,我们可以用上面的相关矩阵进行交叉检查。因此,我们将只取南安普敦三等舱票价的平均值。这只是一个有根据的猜测,可能是错误的,但已经足够好了。请记住,不可能有无噪声的数据,机器学习模型应该对噪声具有鲁棒性。**

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

还有两个女人,我们不知道她们是从哪里上船的。这应该与机票等级和票价密切相关。因为他们都花了 80 美元买了一张头等舱的票,所以我把我的钱押在瑟堡(图中的 C)。

如果某个特定变量中只有几个缺失条目,我们可以使用上面的技巧,通过基本上采用 最大似然 值来进行有根据的猜测。尽管如此,如果我们有更多丢失的数据,做同样的事情真的很危险,就像在Age中,大约有 20%的数据丢失。

我们再也不能通过观察做出有根据的猜测了。因为我们丢弃了变量Cabin,并且所有其他缺失的条目都被填充,所以我们可以利用所有其他变量通过随机森林回归来推断缺失的Age。有 80%的‘训练’数据来推断剩下的 20%。

4.特征工程

虽然大多数人都有“先生”、“夫人”和“小姐”的头衔,但也有不少不太常见的头衔——“博士”、“牧师”、“上校”等。有些只出现一次,如“Lady”、“DOA”、“Captain”等…他们罕见的出现对模特训练没什么帮助。为了用数据科学找到模式**,你需要数据。一个基准点没有任何模式。让我们把所有那些相对罕见的标题归类为“罕见”。**

分类数据在模型训练之前需要格外小心。分类器无法处理字符串输入,如“Mr”、“Southampton”等…虽然我们可以把它们映射成整数,比如说(‘先生’,‘小姐’,‘夫人’,‘稀有’)→ (1,2,3,4),但是头衔之间不应该有排序的概念。 成为博士并不能让你高人一等 。为了不误导机器,不小心构建了一个性别歧视的人工智能,我们应该对它们进行一次性编码**。它们变成了:**

( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) )

另一方面,我决定再添加两个变量— FamilySizeIsAlone。加上FamilySize = SibSp + Parch + 1更有意义,因为全家人会一起待在游轮上。你不想和你的伴侣在一起,但却抛弃你的父母,是吗?此外,独处可能是关键因素之一。你可能更容易做出鲁莽的决定,或者你可能更灵活,不需要照顾家庭。通过一次添加一个变量,我发现它们在模型中的出现提高了整体的可预测性。

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

Alex Siale 在 Unsplash 上拍摄的照片

5.模型评估

我尝试了我所知道的最流行的分类器——随机森林、SVM、KNN、AdaBoost 等等。XGBoost 最终以 87%的测试准确率脱颖而出。为了增加我们的分类器的鲁棒性,训练具有不同性质的分类器的集成,并且通过多数投票获得最终结果。

最后,我提交给 Kaggle,并取得了 80% 的准确率。还不错。总有改进的余地。

例如,在CabinTicket中肯定有一些有用的信息隐藏在中,但是为了简单起见,我们省略了它们。我们还可以创建更多的特征,例如一个二进制类Underage,如果Age < 18为 1,否则为 0。

但是我现在要继续前进了。

6.作为 Web 应用程序部署

Flask 是 Python 中一个易于使用的 web 框架。

from flask import Flask
app = Flask(__name__)[@app](http://twitter.com/app).route("/")
def hello():
    return "<h1>Write something here.</h1>"app.run(host='0.0.0.0', port=60000)

瞧!您可以在本地主机中浏览它。

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

安德鲁·弗尔兰在 Unsplash 上拍摄的照片

我们还需要什么?我们希望人们填写表格来收集所需的数据,并将其传递给机器学习模型。该模型将有一个输出,我们将用户重定向到该页面。

我们将使用 WTForms 在 Python 中构建一个表单,单个表单由一个类定义,如下图所示:

from wtforms import Form, TextField, validators, SubmitField,  DecimalField, IntegerField, SelectFieldclass ReusableForm(Form):sex = SelectField('Sex:',choices=[('1', 'Male'), ('0', 'Female') ],
                   validators=[validators.InputRequired()])fare = DecimalField('Passenger Fare:',default=33,places=1,
                     validators=[validators.InputRequired(),
                                 validators.NumberRange(min=0,
                                                        max=512,

                         message='Fare must be between 0 and 512')])submit = SubmitField('Predict')

我从 Will Koehrsen 那里找到了一个 HTML 模板,并在它的基础上构建。

你看看那些在你之前的人,那些以前处理过这个问题的人,那些建立了意大利面条代码的人,你非常感谢他们使它开源,你给他们荣誉,你把他们做的东西放进你的程序里,你永远不会再看它。—汤姆·斯科特

7.云托管

现在可以通过我的本地主机查看网页了,一切正常。最后一步是把它放在网上。现在有 3 个主要的云托管服务——AWS、GCP 和 Azure。AWS 是目前最受欢迎的,所以我选择了它的 12 个月免费版。

我用我的私钥连接到 Linux 服务器实例,将我的存储库迁移到服务器,运行我的脚本,它工作了!

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

嗯…那对我来说不太好…

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

相关文章

感谢您的阅读。你可以注册我的时事通讯来接收我的新文章的更新。如果您对数据科学感兴趣,以下文章可能会有用:

** [## 我希望我能早点知道的 5 个 Python 特性

超越 lambda、map 和 filter 的 Python 技巧

towardsdatascience.com](/5-python-features-i-wish-i-had-known-earlier-bc16e4a13bf4) [## Python 3.8 中针对 Python 新手的 6 项新特性

请做好准备,因为 Python 2 不再受支持

towardsdatascience.com](/6-new-features-in-python-3-8-for-python-newbies-dc2e7b804acc) [## Python 初学者应该避免的 4 个常见错误

我很艰难地学会了,但你不需要

towardsdatascience.com](/4-common-mistakes-python-beginners-should-avoid-89bcebd2c628)

最初发布于edenau . github . io**

把你的头缠在梯度下降上(有漫画!)

原文:https://towardsdatascience.com/wrapping-your-head-around-gradient-descent-with-pictures-3fbd810235f5?source=collection_archive---------20-----------------------

为什么我们需要另一篇关于梯度下降的文章?

因为数学很难,我们中的一些人需要更慢、更直观的方法。

TL;dr —没有 TL;博士我们在预测未来。描述细节而不使你愤怒退出需要几句话。

理解这篇文章的唯一前提是知道什么是线性函数。我们看到线性函数有许多不同的表述方式,但今天我将坚持使用“y = MX+b”,因为它可能是应用最广泛的。

如果我问“函数 y = mx + b 的变量是什么?”,你可能会说“ x ”。

通常,你是对的,但是梯度下降的第一个“问题”是它是反向的。

不是“给定这个线性函数,找到这些数据点”,而是说“给定这些数据点,找到线性函数

让它深入人心,因为它超级怪异。

xy 更像是一堆常数。我们需要找到符合这些点的“ m ”和“ b ”的值。然后,我们可以用这条线来预测新的点。

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

如果看手相的人教会了我们什么的话,预测未来并不是一门精确的科学。一般来说,没有一条线能完美地穿过这些点,所以我们想找出哪条线最接近到达这些点。

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

什么是“紧密”配合?

这似乎是一个愚蠢的问题。看起来你应该能够测量每个点离直线有多远,然后除以点的数量来计算出直线离每个点有多近。

然而,考虑下面两行,问问自己哪一行更好地代表了这两个数据点:

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

第一条线向底部倾斜。第二条线直接在数据点之间分开。第二行感觉更准确地表示了数据,但平均误差是一样的:

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

由于这个原因和其他原因,我们通常用距离直线的平方来衡量一个数据点的“接近度”。这也确保了只有一个“最佳”位置。

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

通过使用平均平方误差,我们可以看到,将线放在中间比放在顶部更好。

太好了,我怎么找到平均平方误差最小的地方?

这有几种方法。最简单的方法叫做普通最小二乘法,但是在复杂问题上表现不佳。为了解决复杂的问题,我们经常使用一种叫做“梯度下降”的方法。很多机器学习都建立在这个概念上。

首先,让我们假设等式中没有" mx “,而只是试图为” b "找到好的值。这更简单,因为你只有一个变量需要求解。

y = b

这听起来可能很荒谬。这意味着“ m ”锁定在零(一条水平线)。不管你得到什么输入,你总是要猜测同样的输出。

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

照片来自 Oleg Magnipxhere

稍等一下。很快就会变得疯狂。

为简单起见,假设我们只有两个数据点。这些数据点代表了最近的房屋销售。我们知道每栋房子的面积和售价。

我准备把这些数据点称为“东方先生的房子”和“西方先生的房子”(因为一个更靠近图形的东侧,另一个更靠近西侧)。

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

我们试图找到一条线 y = b ,使 East 先生的房子和 West 先生的房子的平均平方误差最小。

我知道你在想什么。“哦……就拿平均销售价”。

b = 7.5

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

你说得对。这种方法是可行的,它可以最小化平方误差。然而,这不是梯度下降。这个可爱的“平均”小技巧不适用于更复杂的问题,所以让我们用梯度下降法来求这个值。

在梯度下降中,我们首先将线放在一个随机的点上。我要把它放在这里:

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

我们希望这条线尽可能靠近所有的房子。所以我们对附近进行了调查。我们敲开每一扇门,并问“我们应该把线移到哪个方向?”。我将称之为移动调查:

移动调查#1

叩叩叩

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

左图由 Brett Saylespexels 上拍摄。右图来自 pixnio

移动调查后,投票是一致的,所以我们把线向上移动。假设我们将其移动到 7.1

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

现在我们进行另一项运动调查:

移动调查#2

叩叩叩

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

现在越来越有趣了。韦斯特先生想把线下移,而伊斯特先生想把线上移。想象一下这些邻居在拔河(每个人都希望线离他们的财产更近)。

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

照片来自 pxhere

那么我们如何决定把线移到哪里呢?

站在房主的角度想想这个问题:

  • 如果你的属性正好在线上,你就没有平方误差。
  • 现在,如果我们把线从你的财产上拉开 1 格,你的平方误差是 1 (1)。
  • 如果我们将线拉离你的财产另一个空间,你的平方误差是 4 (2)。
  • 如果我们把线拉离你的财产另一个空间,你的平方误差是 9 (3)。

如此处所示,每次搬家都比上一次更贵。

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

错误在近距离非常便宜,在远距离就变得非常昂贵。

看着这两栋房子:

  • 韦斯特先生接近错误是廉价的那条线。
  • 伊斯特先生远离错误代价高昂的前线。

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

当你考虑权衡的时候,给 West 先生加上一些便宜的误差是值得的,这样我们就可以从 East 先生身上减去昂贵的误差。

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

东方先生对变化非常敏感。我的意思是,把线从 East 先生那里移开会让我们花费很多,而把线移到离 East 先生更近的地方会让我们节省很多。

相比之下,韦斯特先生对变化不敏感。将战线移向韦斯特先生,我们并没有得到多少好处。将生产线从韦斯特先生那里移开也花费较少。

我们的调查没有考虑“敏感性”。我们应该修改调查。我们需要问的不仅仅是"我们应该把线往什么方向移动?“但是”你对线条运动有多敏感?

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

我们将结果写在我们的移动调查中:

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

一旦我们调查了所有居民,我们将总敏感度除以居民人数,得出“平均敏感度”:

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

这里的正平均敏感度意味着,如果我们把线上移,利大于弊。平均灵敏度(0.4)告诉我们上下权衡的强度。

我们从这个数字中抽取一小部分(比如说 25%)。我们把这个百分比叫做“学习率”。

*0.4 .25 = 0.1

然后我们把线移动那么多。

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

回到拔河的类比,你可以想象东方先生和西方先生在往相反的方向拉,但是东方先生远比西方先生强(因为他更敏感)。

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

来自用户 falcopixabay 上的照片

线现在是 7.2,我们做另一个调查,再次问:

  • 我们应该向什么方向移动这条线?
  • "你对线条运动有多敏感?

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

我们可以看到,西先生比以前敏感了,东先生比以前不敏感了。

伊斯特先生的敏感性仍然超过韦斯特先生,但没有以前那么多了。

让我们用这个数字的 25%来更新这一行:

.3 * .25 = .075

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

该线现在位于 7.275。移动的幅度比以前更小了。

如果我们继续进行多轮调查,你会发现韦斯特先生越来越敏感,而伊斯特先生越来越不敏感。动作也越来越小。

随着更多回合的到来,拉锯战变得更加势均力敌。伊斯特先生希望这条线向上延伸,就像韦斯特先生希望这条线向下延伸一样。此时,“平均灵敏度”非常小(两个灵敏度实际上相互抵消)。

随着平均灵敏度接近零(平衡),线停止移动,因为线更新是基于平均灵敏度的。

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

我将向您展示 3 个不同的动画,它们都显示了直线从第一次测量(7.1)移动到平衡(7.5)时的梯度下降。这三个视图应该可以帮助你理解这个过程。

视图#1:生产线移动视图

以下动画展示了每次测量后的直线移动。当线接近 7.5(最小误差点)时,你可以看到波动越来越小。

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

视图#2:单个错误视图

这个动画展示了东方先生和西方先生的错误。你可以看到,我们继续用昂贵的错误换取便宜的错误,直到双方都不便宜。

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

仔细想想,这是有道理的。只有当你得到的比放弃的多的时候,你才想要移动这条线。当平均灵敏度为零时,向任一方向移动直线都没有好处(因为两边的灵敏度相同)。

视图#3:梯度下降视图

当谈到梯度下降时,你会看到最后一种类型的图表被多次引用。这一点可能很难理解。

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

该图与前面的图具有相同的形状,但不要被欺骗,它是非常不同的。在上图中,X 轴是误差(每个误差是一个单独的点),Y 轴是误差的平方。

在这张新图表中:

  • X 轴显示了’ b 的不同值。
  • 当’ b '设置为该值时,Y 轴是平均平方误差

我们可以看到,理想的’ b '值为 7.5,产生 0.25 的平均平方误差。

我们在梯度下降中的任务是找到这条曲线底部的点(最小平方误差)。

当我们开始(在 7.1),并继续做移动调查,我们在几轮后接近底部。点击此处观看动画:

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

在我们开始梯度下降之前,我们知道曲线会这样形成(它总是这样),但是我们不知道最小值在哪里。

在第一次移动调查后,我们发现猜测值为 7.1 会导致平均平方误差为 0.41。起初,这似乎是我们所知道的全部:

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

然而,我们实际上知道的更多。我们知道平均灵敏度是 0.4,这告诉我们两件事:

  1. 居民希望这条线上移(这样我们就知道我们在曲线的左侧)。
  2. 平均灵敏度很高,所以我们离中心很远。

我将标记一条蓝线,显示我们对自己所处位置的了解。

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

然后,我们做一个移动调查,我们发现 7.2 的猜测导致 0.34 的平均平方误差。

由于平均敏感度(. 3),我们知道我们仍然在图表的左侧,但我们越来越接近中心。我将画另一条线来表示这一点,但这条线不会太陡,因为我们更接近底部。

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

随着我们继续做移动调查,我们的步伐越来越小,越来越接近曲线的底部。

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

蓝线的“陡度”代表平均灵敏度。当’ b 值远离最小值时,斜率很陡。

随着’ b '值接近最小值,平均灵敏度(也称为斜率)接近零。

“G radient ”只是“斜率”的另一种说法。随着我们向图表的底部移动,梯度变得越来越小。这就是为什么我们称这种方法为“梯度下降”。

无论你有两个数据点(如此处所示),还是 1000 个数据点。梯度下降的逻辑是相同的:

  • 调查每个点,询问“*您希望我向哪个方向移动?”*和“你有多敏感?
  • 取所有灵敏度(梯度)的平均值。
  • 乘以“学习率”
  • 更新该行。
  • 重复直到我们找到平衡。

实际上,你永远不会完全达到平衡,因为当它接近底部时,更新变得越来越小,但是在足够多的回合之后,差异将变得微不足道。

好的,我们可以解出 b。“m”呢?

现在我们已经发现了如何找到最小的“b”值,让我们暂时忽略“b ”,想想如何找到最小的“m”值。

y = mx

这意味着“ b ”实际上被固定在常数 0。我们可以使用“ m ”值来改变函数的斜率,但是直线将总是通过(0,0)

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

让我们再来看看 East 先生和 West 先生,猜一猜这条线可能在哪里:

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

m=1 处,我们看到 West 先生在线上 2 个单位*,East 先生在线下2 个单位。平均平方误差为 4。*

直觉上,我们似乎处于平衡状态,无法在此基础上有所提高。然而,事实并非如此。

下面的动画显示了如果我们将“ m ”值从 1 更改为 0.9 会发生什么

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

请注意,我们是如何在离 East 先生更近的地方得到 1 个完整的空间,而在离 West 先生更远的地方只得到 1/2 的空间。总平方误差减少到 3.625

当你认为等式 y = mx 是有意义的

将“*m”*值乘以“ x ”。因为东先生( x=10 )的距离是西先生( x=5 )的两倍,所以东先生受“ m 变化的影响也是西先生的两倍。

一般来说,越往东,对坡度变化越敏感。

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

既然我们向 East 先生移动可以得到两倍的收益,为什么不把线一直移动到 East 先生呢?我们可以向东方先生移动整整 2 个单位,而向西方先生只移动 1 个单位。

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

因为我们离韦斯特先生有 3 个空间,新的平均平方误差是(4.5)。这比我们开始的时候更糟…怎么回事?

记住:当我们把线从 West 先生移开时,每个误差都比上一个更昂贵(由于平方误差)。在某些时候,韦斯特先生对运动非常敏感,以至于不值得做出权衡,尽管你可以通过移动线来获得两倍于伊斯特先生的距离。

虽然上面的线有最小的原始误差,但它没有最小的平方误差。

因此,东先生和西先生都很敏感,但原因不同。事实证明,点对斜率变化的敏感度由两个因素决定:

  • 点离线有多远?
  • 这个点向东有多远?

当我们计算灵敏度时,我们需要考虑这两个因素。

灵敏度= {与直线的距离} * {x 值}

让我们把这条线放回( m = 0.9)

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

本帖第一次,你很可能无法通过简单的看一眼就判断出线条应该往哪个方向移动。

我们来做个移动调查,计算一下敏感度,就知道了。

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

我们可以看到,尽管 West 先生只有“ x ”值的一半,但由于他与生产线的距离,他更加敏感。

我们知道斜率需要向上移动,但是增加 1.25 比 T21 大得多,会把线放在两点之上。这就是为什么我们只移动它的一个百分比(我之前描述的“学习率”)。这里我用 1%的学习率。

1.25 * .01 = .0125

新的“m”= . 9+. 0125

新线在. 9125。在另一次移动调查后,我们可以看到平方误差有所下降。

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

乘以学习率以获得更新值:

0.46875 * .01 = .0046875

新的“m”值= .9125 + .0046875

更新后线路在. 917。如果我们继续一轮又一轮的移动调查,这条线会越来越接近它的平衡点(. 92)。

这是 0.92 时的移动调查结果

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

梯度下降过程看起来非常类似于我们看到的“ m ”的梯度下降。

梯度下降视图

让我们看看坡度变化的梯度体面视图:

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

我们可以看到,当“ m ”值为 0.9 时,平方误差最小。

关于“ m ”曲线需要注意的一点是,它比我们看到的“ b ”的曲线要陡得多。这是因为" m “值乘以我们的每个” x “值,所以即使对” m "的小更新也会导致大的变化(更好或更坏)。这就是为什么保持小的学习率很重要。

把所有的放在一起

首先,我们想出了当“ m ”保持不变时,如何求解“ b ”。然后,我们想出了当“ b ”保持不变时,如何求解“ m ”。我们如何移动“ m ”和“ b ”来找到最佳的整体匹配?

当“ m 和“ b 都可以移动时:

  1. 假设“ m ”不变。进行移动调查,询问所有居民他们希望“ b ”值向哪个方向移动。
  2. 假设“ b ”不变。进行移动调查,询问所有居民他们希望“ m ”值移动到哪个方向。
  3. 根据“ b ”移动调查的平均灵敏度更新“ b ”值。
  4. 根据“ m ”移动测量的平均灵敏度更新“ m ”值。
  5. 只有一个地方“ m ”和“ b ”的灵敏度都为零。这条线将会聚在那一点。

完整的例子

让我们来看一下当水平线位于( *y = 0x + 7.5”),*并进行全梯度下降时会发生什么。

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

第一轮:

  1. 在“ b ”移动调查中,我们发现 East 先生和 West 先生对“ b ”的变化同样敏感(他们都相距 0.5)。“ b 的平均灵敏度为零。
  2. 在“ m ”移动调查中,我们发现虽然两人距离相同,但 East 先生对“ m ”变化的敏感度是他的两倍,因为他有两倍的“ x ”值。
  3. b ”值没有更新,因为没有平均“ b ”灵敏度。
  4. 我们将“ m ”值更新为平均“ m ”灵敏度的 1%。

该线现在为" y = 0.0125x + 7.5"

第二轮:

  1. 这一次,韦斯特先生比伊斯特先生离这条线更远。这意味着他对“ b ”的变化更加敏感。韦斯特先生比较强势,想把“ b ”值拉下来。
  2. 在“ m ”移动调查后,我们发现 East 先生仍然对“m”的变化更敏感,并希望将“ m ”的值拉高。
  3. 我们将“b”值向下移动平均“ b ”灵敏度的 25%。
  4. 我们将“ m ”值向上移动平均“ m ”灵敏度的 1%。

随着我们继续将“ m ”和“ b ”移向平衡,我们接近“ m ”和“ b ”都为零(最小值)的唯一地方。

让我们从两个角度来总结一下。

直线运动视图

以下动画显示了梯度下降的重复循环,更新了“ b 和“ m ”。观察“ b ”值如何下降,以及“ m ”值如何增加。

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

梯度下降视图

让我们从“梯度下降”的角度来看正在发生的事情。到目前为止,我们已经展示了两张“梯度下降”图。

  1. " b "值与均方差。
  2. m 值与均方差。

为了显示" m " "和 " b "与均方误差的关系,我们需要图表上的第三个轴。

两个水平轴将代表“ m 和“ b ”的值。纵轴代表这些点的平方误差。

3 轴梯度下降图通常看起来像这样。这个图表不是基于我们的数据,而是帮助你理解这个概念。

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

该图有助于显示“ m ”和“ b ”都处于平衡状态的地方只有一个(底部)。

这是基于我们实际数据的梯度下降图。看起来有点困难,但是它有相同的“下坡到最小值”属性:

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

如果您仔细观察这个图表,您可以看到最小点的" m “值为 6,而” b "值为 0.2。

直线" y = 0.2x + 6 "实际上是理想的函数,结果是零误差(它穿过两点)。

该图与之前的图有所不同,原因如下:

  • m ”侧的变化比“ b ”侧的变化要敏感得多,使图形呈现出这种独特的“taco”形状。
  • 对于“ b ”的每个值,最小可能的“ m ”值会有一点变化。这就是为什么你看到的浅槽同时向“ m ”和“ b ”方向移动。

关于作者

我是约翰尼·伯恩斯,FlyteHub.org 的创始人,这是一个免费开源工作流程库,可以在没有编码的情况下执行机器学习。我相信在人工智能上的合作会带来更好的产品。

如果你对数学如何支持我们的“敏感度”公式感兴趣,我会写一篇后续文章来解释。

用这 10 个技巧写出更好的 Python 代码

原文:https://towardsdatascience.com/write-better-python-code-with-these-10-tricks-30b7018e247a?source=collection_archive---------3-----------------------

提高您的 Python 技能

学习如何用 Pythonic 的方式编码

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

克里斯托弗·高尔Unsplash 上拍摄的照片

编码很有趣,用 Python 编码更有趣,因为有许多不同的方法来完成相同的功能。然而,大多数时候,都有首选的实现,有些人称之为 Pythonic。这些 Pythonic 实现的一个共同特点是代码简洁明了。

用 Python 或任何编码语言编程都不是火箭科学,它主要是关于制作技能。如果您有意尝试 Pythonic 编码,这些技术将很快成为您的工具包的一部分,并且您会发现在您的项目中使用它们会越来越自然。因此,让我们来探索一些简单的技巧,希望对你有所帮助。

1.负索引

人们喜欢使用序列,因为我们知道元素的顺序,并且我们可以按顺序操作这些元素。在 Python 中,字符串、元组和列表是最常见的序列数据类型。我们可以使用索引来访问单个项目。像其他主流编程语言一样,Python 支持基于 0 的索引,其中我们使用一对方括号中的 0 来访问第一个元素。此外,我们还可以使用 slice 对象来检索序列中的特定元素,如下面的代码示例所示。

>>> # Positive Indexing
... numbers = [1, 2, 3, 4, 5, 6, 7, 8]
... print("First Number:", numbers[0])
... print("First Four Numbers:", numbers[:4])
... print("Odd Numbers:", numbers[::2])
... 
First Number: 1
First Four Numbers: [1, 2, 3, 4]
Odd Numbers: [1, 3, 5, 7]

然而,Python 更进了一步,支持负索引。具体来说,我们可以使用-1 来引用序列中的最后一个元素,并对项目进行反向计数。例如,倒数第二个元素的索引为-2,依此类推。重要的是,负索引也可以与切片对象中的正索引一起工作。

>>> # Negative Indexing
... data_shape = (100, 50, 4)
... names = ["John", "Aaron", "Mike", "Danny"]
... hello = "Hello World!"
... 
... print(data_shape[-1])
... print(names[-3:-1])
... print(hello[1:-1:2])
... 
4
['Aaron', 'Mike']
el ol

2.检查容器的空度

容器是指那些可以存储其他数据的容器数据类型。一些常用的内置容器是元组、列表、字典和集合。当我们处理这些容器时,我们经常需要在执行附加操作之前检查它们是否包含任何元素。事实上,我们可以检查这些容器的长度,它对应于存储项目的数量。当长度为零时,容器为空。下面给你看一个简单的例子。

if len(some_list) > 0:
    # do something here when the list is not empty
else:
    # do something else when the list is empty

然而,这并不是最有效的方法。相反,我们可以简单地检查容器本身,它将在包含元素时计算True。虽然下面的代码向您展示了主要的容器数据类型,但是这种用法也适用于字符串(即任何非空字符串都是True)。

>>> def check_container_empty(container):
...     if container:
...         print(f"{container} has elements.")
...     else:
...         print(f"{container} doesn't have elements.")
... 
... check_container_empty([1, 2, 3])
... check_container_empty(set())
... check_container_empty({"zero": 0, "one": 1})
... check_container_empty(tuple())
... 
[1, 2, 3] has elements.
set() doesn't have elements.
{'zero': 0, 'one': 1} has elements.
() doesn't have elements.

3.用 Split()创建字符串列表

我们经常使用字符串作为特定对象的标识符。例如,我们可以使用字符串作为字典中的关键字。在数据科学项目中,字符串通常是数据的列名。当我们选择多个列时,我们不可避免地需要创建一个字符串列表。事实上,我们可以在列表中使用文字创建字符串。然而,我们必须用引号将每个字符串括起来,这对于我们这些“懒人”来说有点乏味。因此,我更喜欢利用字符串的split()方法创建一个字符串列表,如下面的代码片段所示。

>>> # List of strings
... # The typical way
... columns = ['name', 'age', 'gender', 'address', 'account_type']
... print("* Literals:", columns)
... 
... # Do this instead
... columns = 'name age gender address account_type'.split()
... print("* Split with spaces:", columns)
... 
... # If the strings contain spaces, you can use commas instead
... columns = 'name, age, gender, address, account type'.split(', ')
... print("* Split with commas:", columns)
... 
* Literals: ['name', 'age', 'gender', 'address', 'account_type']
* Split with spaces: ['name', 'age', 'gender', 'address', 'account_type']
* Split with commas: ['name', 'age', 'gender', 'address', 'account type']

如上所示,split()方法默认使用空格作为分隔符,并从字符串创建一个字符串列表。值得注意的是,当您创建一个包含一些包含空格的元素的字符串列表时,您可以选择使用不同类型的分隔符(例如,逗号)。

这种用法受到一些内置功能的启发。例如,当你创建一个命名的元组类时,我们可以这样做:Student = namedtuple(“Student”, [“name”, “gender”, “age”])。字符串列表指定了元组的“属性”然而,通过这样定义该类,它本身也得到支持:Student = namedtuple(“Student”, “name gender age”)。再举一个例子,创建一个枚举类支持相同的替代解决方案。

4.三元表达式

在许多用例中,我们需要根据条件定义具有特定值的变量,我们可以简单地使用 if…else 语句来检查条件。然而,它需要几行代码。如果我们只处理一个变量的赋值,我们可能想要使用三元表达式,它只需要一行代码就可以检查条件并完成赋值。此外,它的形式更短,这使得代码更加简洁。考虑下面的例子。

# The typical way
if score > 90:
    reward = "1000 dollars"
else:
    reward = "500 dollars"# Do this instead
reward = "1000 dollars" if score > 90 else "500 dollars"

有时候,我们可以从一个已定义的函数中获取一些数据,我们可以利用这一点,写一个三元表达式的速记运算,如下所示。

# Another possible scenario
# You got a reward amount from somewhere else, but don't know if None/0 or not
reward = reward_known or "500 dollars"
# The above line of code is equivalent to below
reward = reward_known if reward_known else "500 dollars"

5.文件对象的 With 语句

我们经常需要从文件中读取数据,并向文件中写入数据。最常见的方法是简单地使用内置的open()函数打开一个文件,它创建了一个我们可以操作的文件对象。您以前遇到过以下问题吗?

>>> # Create a text file that has the text: Hello World!
... 
... # Open the file and append some new data
... text_file0 = open("hello_world.txt", "a")
... text_file0.write("Hello Python!")
... 
... # Open the file again for something else
... text_file1 = open("hello_world.txt")
... print(text_file1.read())
... 
Hello World!

在前面的代码片段中,我们从一个文本文件开始,该文件包含文本“Hello World!”然后,我们将一些新数据添加到文件中。然而,过了一会儿,我们又想在文件上工作了;当我们读取文本文件时,它仍然有旧的数据。换句话说,附加的文本不包括在文本文件中。为什么会这样?

这是因为我们没有首先关闭文件对象。如果不关闭文件,将无法保存更改。事实上,我们可以在 file 对象上显式调用close()方法。但是,我们可以使用“with”语句来实现这一点,它会自动为我们关闭 file 对象,如下所示。当我们完成对文件的操作时,我们可以通过访问 file 对象的closed属性来验证文件是否被关闭。

>>> with open("hello_world.txt", "a") as file:
...     file.write("Hello Python!")
... 
... with open("hello_world.txt") as file:
...     print(file.read())
... 
... print("Is file close?", file.closed)
... 
Hello World!Hello Python!Hello Python!
Is file close? True

更一般地说, with 语句是在 Python 中使用上下文管理器的语法。前面的例子涉及文件操作,因为文件是共享资源,我们负责释放这些资源。上下文管理器可以帮助我们完成工作。如前所示,文件操作结束后,通过使用带有语句的自动关闭文件。你可以在我的上一篇文章中了解更多关于上下文管理的内容。

6.评估多个条件

我们经常需要评估多种情况。有几种可能的情况。对于数值,我们可以对同一个变量进行多次比较。在这种情况下,我们可以将这些比较链接起来。

# Multiple Comparisons
# The typical way
if a < 4 and a > 1:
    # do something here# Do this instead
if 1 < a < 4:
    # do somerthing here

在其他一些场景中,我们可以进行多重等式比较,并且我们可以利用下面的技术,使用关键字中的进行成员测试。

# The typical way
if b == "Mon" or b == "Wed" or b == "Fri" or b == "Sun":
    # do something here# Do this instead, you can also specify a tuple ("Mon", "Wed", "Fri", "Sun")
if b in "Mon Wed Fri Sun".split():
    # do something here

另一种技术是使用内置的all()any()函数来评估多个条件。具体来说,当 iterable 中的元素都是True时,all()函数的计算结果将是True,因此该函数适合代替一系列的 and 逻辑比较。另一方面,当 iterable 中的任何元素为True时,any()函数将计算为True,因此适合替换一系列 OR 逻辑运算。相关的例子如下。

# The typical ways
if a < 10 and b > 5 and c == 4:
    # do somethingif a < 10 or b > 5 or c == 4:
    # do something# Do these instead
if all([a < 10, b > 5, c == 4]):
    # do somethingif any([a < 10, b > 5, c == 4]):
    # do something

7.在函数声明中使用默认值

在几乎所有的 Python 项目中,大部分代码都涉及到创建和调用函数。换句话说,我们不断地处理函数声明和重构。在许多情况下,我们需要多次调用一个函数。根据不同的参数集,该函数的运行方式会略有不同。然而,有时一组参数可能比其他参数更常用,在这种情况下,我们应该考虑在声明函数时设置默认值。考虑下面这个微不足道的例子。

# The original form:
def generate_plot(data, image_name):
    """This function creates a scatter plot for the data"""
    # create the plot based on the data
    ...
    if image_name:
        # save the image
        ...# In many cases, we don't need to save the image
generate_plot(data, None)# The one with a default value
def generate_plot(data, image_name=None):
    pass# Now, we can omit the second parameter
generate_plot(data)

需要注意的一点是,如果在设置默认值时处理可变数据类型(例如,列表、集合),请确保使用None而不是构造函数(例如,arg_name=[])。因为 Python 在定义函数对象的地方创建函数对象,所以提供空列表会被函数对象“卡住”。换句话说,函数对象不会在你调用它的时候被创建。相反,您将在内存中处理同一个函数对象,包括它最初创建的默认可变对象,这可能会导致意想不到的行为(更多讨论见

8.使用计数器进行元素计数

当我们在一个列表、元组或字符串中有多个项目时(例如,多个字符),我们经常想要计算每个项目有多少个。要做到这一点,可以为该功能编写一些乏味的代码。

>>> words = ['an', 'boy', 'girl', 'an', 'boy', 'dog', 'cat', 'Dog', 'CAT', 'an','GIRL', 'AN', 'dog', 'cat', 'cat', 'bag', 'BAG', 'BOY', 'boy', 'an']
... unique_words = {x.lower() for x in set(words)}
... for word in unique_words:
...     print(f"* Count of {word}: {words.count(word)}")
... 
* Count of cat: 3
* Count of bag: 1
* Count of boy: 3
* Count of dog: 2
* Count of an: 5
* Count of girl: 1

如上所示,我们首先必须创建一个只包含唯一单词的集合。然后我们迭代单词集,并使用count()方法找出每个单词的出现次数。然而,有一个更好的方法——使用Counter类,它是为完成这个计数任务而设计的。

>>> from collections import Counter
... 
... word_counter = Counter(x.lower() for x in words)
... print("Word Counts:", word_counter)
... 
Word Counts: Counter({'an': 5, 'boy': 4, 'cat': 4, 'dog': 3, 'girl': 2, 'bag': 2})

collections模块中提供了计数器类。为了使用该类,我们简单地创建了一个生成器:x.lower() for x in words,并且每一项都会被计数。如你所见,计数器对象是一个类似 dict 的映射对象,每个键对应于单词列表的唯一项,而值是这些项的计数。很简洁,对吧?

此外,如果您对找出单词列表中最频繁出现的条目感兴趣,我们可以利用 Counter 对象的most_common()方法。下面的代码向您展示了这种用法。你只需要指定一个整数(N),它会从列表中找出最频繁出现的 N 个条目。顺便提一下,Counter对象也可以处理其他序列数据,比如字符串和元组。

>>> # Find out the most common item
... print("Most Frequent:", word_counter.most_common(1))
Most Frequent: [('an', 5)]
>>> # Find out the most common 2 items
... print("Most Frequent:", word_counter.most_common(2))
Most Frequent: [('an', 5), ('boy', 4)]

9.不同订单要求的排序

在许多项目中,对列表中的项进行排序是一项普遍的任务。最基本的排序是基于数字或者字母顺序,我们可以使用内置的sorted()函数。默认情况下,sorted()函数将按升序对列表(实际上,它可以是任何可迭代的)进行排序。如果我们将reverse参数指定为True,我们可以得到降序排列的条目。下面显示了一些简单的用法。

>>> # A list of numbers and strings
... numbers = [1, 3, 7, 2, 5, 4]
... words = ['yay', 'bill', 'zen', 'del']
... # Sort them
... print(sorted(numbers))
... print(sorted(words))
... 
[1, 2, 3, 4, 5, 7]
['bill', 'del', 'yay', 'zen']
>>> # Sort them in descending order
... print(sorted(numbers, reverse=True))
... print(sorted(words, reverse=True))
... 
[7, 5, 4, 3, 2, 1]
['zen', 'yay', 'del', 'bill']

除了这些基本用法,我们还可以指定key参数,以便对复杂的项目进行排序,比如元组列表。考虑以下这种情况的例子。

>>> # Create a list of tuples
... grades = [('John', 95), ('Aaron', 99), ('Zack', 97), ('Don', 92), ('Jennifer', 100), ('Abby', 94), ('Zoe', 99), ('Dee', 93)]
>>> # Sort by the grades, descending
... sorted(grades, key=lambda x: x[1], reverse=True)
[('Jennifer', 100), ('Aaron', 99), ('Zoe', 99), ('Zack', 97), ('John', 95), ('Abby', 94), ('Dee', 93), ('Don', 92)]
>>> # Sort by the name's initial letter, ascending
... sorted(grades, key=lambda x: x[0][0])
[('Aaron', 99), ('Abby', 94), ('Don', 92), ('Dee', 93), ('John', 95), ('Jennifer', 100), ('Zack', 97), ('Zoe', 99)]

上面的代码通过利用 lambda 函数向您展示了两个高级排序示例,该函数被传递给key参数。第一个是使用降序对项目进行排序,而第二个是使用默认的升序。如果我们想把这两个要求结合起来呢?如果你考虑使用reverse参数,你可能找错了对象,因为如果你试图按多个标准排序,相反的参数将适用于所有标准。那有什么诀窍呢?请参见下面的代码片段。

>>> # Requirement: sort by name initial ascending, and by grades, descending
... # Both won't work
... sorted(grades, key=lambda x: (x[0][0], x[1]), reverse=True)
[('Zoe', 99), ('Zack', 97), ('Jennifer', 100), ('John', 95), ('Dee', 93), ('Don', 92), ('Aaron', 99), ('Abby', 94)]
>>> sorted(grades, key=lambda x: (x[0][0], x[1]), reverse=False)
[('Abby', 94), ('Aaron', 99), ('Don', 92), ('Dee', 93), ('John', 95), ('Jennifer', 100), ('Zack', 97), ('Zoe', 99)]
>>> # This will do the trick
... sorted(grades, key=lambda x: (x[0][0], -x[1]))
[('Aaron', 99), ('Abby', 94), ('Dee', 93), ('Don', 92), ('Jennifer', 100), ('John', 95), ('Zoe', 99), ('Zack', 97)]

如您所见,通过将reverse参数设置为TrueFalse,两者都不起作用。相反,诀窍是否定等级,因此当您按默认升序排序时,分数将因为这些值的否定而反向排序。但是,对于这种方法有一个警告,因为求反只能处理数值,而不能处理字符串。

10.不要忘记 defaultdict

字典是一种有效的数据类型,它允许我们以键值对的形式存储数据。要求所有的键都是可散列的,这样在幕后,存储这些数据可能涉及到使用散列表。这种实现允许数据检索和插入的 O(1)效率。然而,应该注意的是,除了内置的 dict 类型之外,我们还可以使用其他的字典。其中,我想讨论一下 defaultdict 类型。与内置的 dict 类型不同, defaultdict 允许我们设置一个默认的工厂函数,当键不存在时创建一个元素。您可能对以下错误并不陌生。

>>> student = {'name': "John", 'age': 18}
... student['gender']
... 
Traceback (most recent call last):
  File "<input>", line 2, in <module>
KeyError: 'gender'

假设我们在处理单词,我们想将相同的字符组成一个列表,这些列表与作为键的字符相关联。这里有一个使用内置字典类型的简单实现。值得注意的是,检查 dict 对象是否有letter键至关重要,因为如果键不存在,调用append()方法会引发KeyError异常。

>>> letters = ["a", "a", "c", "d", "d", "c", "a", "b"]
... final_dict = {}
... for letter in letters:
...     if letter not in final_dict:
...         final_dict[letter] = []
...     final_dict[letter].append(letter)
... 
... print("Final Dict:", final_dict)
... 
Final Dict: {'a': ['a', 'a', 'a'], 'c': ['c', 'c'], 'd': ['d', 'd'], 'b': ['b']}

让我们看看如何使用 defaultdict 来编写更简洁的代码。虽然这个例子很简单,但它只是给了你一些关于 defaultdict 类的想法,这样我们就不用处理字典对象中不存在的键了。

>>> from collections import defaultdict
... 
... final_defaultdict = defaultdict(list)
... for letter in letters:
...     final_defaultdict[letter].append(letter)
... 
... print("Final Default Dict:", final_defaultdict)
... 
Final Default Dict: defaultdict(<class 'list'>, {'a': ['a', 'a', 'a'], 'c': ['c', 'c'], 'd': ['d', 'd'], 'b': ['b']})

结论

在阅读本文之前,您可能已经知道了其中的一些技巧,但是我希望您仍然能够很好地掌握这些技巧。在您的项目中实践这些习惯用法将使您的 Python 代码更具可读性和性能。

这件作品到此为止。感谢阅读。

使用这个 Python 工具编写更好的故事

原文:https://towardsdatascience.com/write-better-stories-with-this-python-tool-ad1371158822?source=collection_archive---------5-----------------------

利用编程的力量写得更好,提高可读性。

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

héizel vázquez 的插图

如果你经常给老板写文章、博客或报告,那么你要确保人们理解你说的话。在这篇文章中,我将展示如何使用一个名为 textstat 的 Python 库来确定你的文本的可读性、复杂性、等级级别以及更多相关信息。

装置

您可以通过 Python 包索引(PyPI)轻松安装 textstat:

pip install textstat

您也可以从 GitHub 安装最新版本:

git clone [https://github.com/shivam5992/textstat.git](https://github.com/shivam5992/textstat.git)
cd textstat
pip install .

使用

该库中有许多有用的函数来:

  • 数音节
  • 执行词典计数
  • 计算句子
  • 运行 Flesch 阅读难易程度评分来评估文档的可读性。
  • 运行弗莱施-金凯等级。这是一个评分公式,9.3 分意味着九年级学生能够阅读该文档。
  • 返回雾标度。雾指数为 12 需要美国高中毕业生(大约 18 岁)的阅读水平。
  • 返回雾霾指数。这是一种可读性的衡量标准,估计了理解一篇文章所需的教育年限。
  • 返回自动可读性索引。它产生了理解文本所需的美国等级水平的近似表示。
  • 返回科尔曼-廖指数。
  • 返回 Linsear 编写的公式。
  • 获得 Dale-Chall 可读性分数。
  • 基于以上所有测试,获得可读性共识。

这个库的基本思想是让你写一篇文章,然后运行不同的测试和索引,看看你的文章有多好。我将在下面的例子中解释如何做。

例子

我将从我写的一篇旧文章中选取一段,然后对它进行不同的测试。文章是:

[## 关于数据和科学

第一部分:将科学引入讨论的重要性。

towardsdatascience.com](/https-towardsdatascience-com-on-data-and-science-e96849b5f363)

我要用的文字是这样的:

数据科学是目前大多数科学和研究的主要焦点,它需要许多东西,如人工智能、编程、统计、商业理解、有效的演示技巧等等。所以才不容易理解,也不容易学习。但是我们能做到,我们正在做。

数据科学已经成为学术界和工业界解决问题的标准框架,而且这种情况还会持续一段时间。但是我们需要记住我们从哪里来,我们是谁,我们要去哪里。

在这个 GitHub repo 中,您将找到运行库的下一个笔记本:

[## FavioVazquez/改进-写作

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/FavioVazquez/improve-writing)

在创建这段代码的过程中,我还发现了一些有趣的事情。如何在 Python 中运行类的每个方法?我没有在网上找到它,所以这里是这个库的例子:

*# Run all at once*
**import** **inspect**
funcs = ["textstat." + inspect.getmembers(textstat, predicate=inspect.ismethod)[i][0] **for** i **in** range(1,28)]**for** elem **in** funcs:
    method = eval(elem)
    textstat.set_lang("en")
    print(elem.split(".")[1])
    print(method(text))
    print(" ")

相当酷。但是缺少了一些东西,拼写呢?Python 中有很好的库,但是自动更正是最容易使用的:

# Here I'm misspelling :
# presentation as presentatio
# focus as focsu
# framework as framwork 
text = """
Data science is the main focsu of most sciences and studies right now, 
it needs a lot of things like AI, programming, statistics, 
business understanding, effective presentatio skills and much more. 
That's why it's not easy to understand or study. But we can do it, we are doing it.
Data science has become the standard solving problem framwork for academia and 
the industry and it's going to be like that for a while. But we need to remember 
where we are coming from, who we are and where we are going.
"""

正如你所看到的,我故意拼错了单词演示、焦点和框架,,我可以用这段简单的代码来修复它:

from autocorrect import Spellercheck = Speller(lang='en')check(text)

结果是:

"\ndata science is the main focus of most sciences and studies right now, \nit needs a lot of things like AI, programming, statistics, \nbusiness understanding, effective presentation skills and much more. \nThat's why it's not easy to understand or study. But we can do it, we are doing it.\ndata science has become the standard solving problem framework for academia and \nthe industry and it's going to be like that for a while. But we need to remember \nwhere we are coming from, who we are and where we are going.\n"

已经修好了。

如果你是一个 Python 用户,希望你可以用它来写更好的文章、报告等等。请在下面告诉我你的想法:)

你也可以通过 Instagram/Twitter 联系我:

[## 法维奥·巴斯克斯

Favio Vázquez 的最新推文(@FavioVaz)。数据科学家。物理学家和计算工程师。我有一个…

twitter.com](https://twitter.com/faviovaz)

写清楚你的简历,增加你找到第一份编码工作的机会

原文:https://towardsdatascience.com/write-clear-readmes-to-increase-your-chances-to-find-your-first-coding-job-c2408786b27a?source=collection_archive---------59-----------------------

为什么开发人员应该花时间为他们的公共存储库写一个清晰的自述文件

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

Unsplash 上的 Oxa Roxa 拍摄的照片

在这篇文章中,我想和你分享我的一点观察,关于有多少的初级开发人员没有把自述文件放到他们的存储库中,没能说服我雇佣他们。

在文章末尾有一些关于如何撰写精彩自述的有用链接。

什么是 README?

通常,README 是软件/项目存储库中的一个文件,它简要地解释了它。

自述文件是用来推销你的作品的。

自述文件不是您的文档(除非它能被压缩到一页纸中)。

为什么要做呢?

如果你公开你的知识库,你很可能会被它评判。尤其是你在简历中用 GitHub/GitLab 账号申请新工作的时候。

在我的职业生涯中,我曾几次参与招聘实习生/初级软件工程职位。平均而言,我看到 7 个候选人中只有 1 个提到他们在 GitHub/GitLab 上的简介。这些候选者中很少有人会将自述文件附加到他们的存储库中。

我假设那些附上 GitHub 简介的候选人认为招聘人员/招聘工程师会钻研代码,弄清楚那里发生了什么。这种情况不会发生。其主要原因是:

  1. 他们没有时间做那件事
  2. 它们不是技术性的
  3. 即使他们是技术人员,他们也可能不知道你写的代码的语言/结构

因此,你可能有很强的编码技能,并且在你的投资组合中有一个不错的项目,但是如果没有一个自述文件来解释会发生什么,没有人会知道。

根本没有自述文件的缺点

当人们申请实习/初级职位时,他们通常没有什么可以证明他们是好的候选人。他们获得了教育背景。通常情况下,就是这样。所以,你的 Github 账号是你简历中最有价值的东西

作为一名技术人员,当我看到没有自述文件的求职者信息库时,我会质疑他们的软技能水平。至少,我会认为你可以让你的作品不被记录。显然,它不会帮助您进入下一个处理级别。

糟糕的自述文件的缺点

你试图在自述文件中解释这一切,但(对我来说)很难理解。如果你申请初级职位,我会给你一分,但如果你想成为高级职位,这将是一个问题。

软技能对于高级工程师来说至关重要。传达任务,解释你的工作可能比你的编码技能更重要。

高级工程师必须能够清楚地解释他们构建了什么。

有一个清晰的自述文件的好处(对于你的简历)

  1. 你看起来很专业
  2. 招聘圈里的任何人都可以评估你的努力
  3. 你能够清楚地解释你建造了什么

如何做好自述?

0.创建一个简单明了的存储库名称

是的,我想仅仅通过名字就能猜出里面是什么。

通常,仅仅用存储库名称来解释您所做的一切是不可能的。相反,您应该只选择一个特性,并尝试使用它作为存储库名称。

1.简洁的一行程序

俏皮话很难。它必须吸引读者的注意力。

尝试用 60 个字符打动你的读者。

你的任务是让我思考:

“有意思,她是怎么做到的?我想进一步调查她的储存库”

2.演示一下

给我看看它是干什么的。有截图或者 GIF 就好了。

3.解释它的用途

哦是的。我们不仅仅是为了编码而编码。我们编码来解决问题。我们编码是为了给公司带来价值。所以,即使你只是因为喜欢才这么做的。我想让你解释它给特定类型的人/公司带来的价值。

4.推广它

现在,当你有一个清晰的自述时,试着引起某人的注意。获得一些反馈。弄些星星。

试着在黑客新闻或一些子网站上分享。

自述文件中最好包含的其他内容:

  1. 如何安装
  2. 快速启动
  3. 提及你用来创作作品的图书馆

结论

在有精心制作的自述文件的知识库中搜索你的第一份编码工作会增加你收到招聘人员回电的机会。

尽管如此,这篇文章是关于给你的简历加分的,仅仅有一份好的自述并不会让你成为一个好的候选人。

如何做一个别人想看的自述

  1. 一个了不起的自述文件模板,帮助您快速启动项目!
  2. 您的开源项目的 README.md 模板
  3. 令人敬畏的读物精选列表
About meMy name is Artem, I build [newscatcherapi.com](https://newscatcherapi.com/) - ultra-fast API to find news articles by any topic, country, language, website, or keyword.I write about Python, cloud architecture, elasticsearch, data engineering, and entrepreneurship.

学习如何在 Jupyter 笔记本上写下降价和乳胶

原文:https://towardsdatascience.com/write-markdown-latex-in-the-jupyter-notebook-10985edb91fd?source=collection_archive---------1-----------------------

不仅是朱庇特。Google Colab、R Markdown 等等。

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

背景由JESHOOTS.COMUnsplash

交互式笔记本越来越受欢迎。为什么? 仅仅是因为它是一个很棒的教学环境,功能强大,可共享,并提供了在相同环境中执行数据可视化的能力。*应该用哪些互动笔记本?*我推荐:

  • Jupyter Notebook是一个开源的 web 应用程序,允许您创建和共享包含实时代码、公式、可视化和叙述性文本的文档。
  • Colaboratory 是一个免费的 Jupyter 笔记本环境,不需要设置,完全在云中运行。

他们两个都支持

  1. Markdown 是一种标记语言,是 HTML 的超集。
  2. 乳胶 渲染数学和科学的写法。

降价

这是一种非常简单的语言,它允许你以一种简化的方式编写 HTML。它可以用在一些网站上,比如 Stack Overflow,或者用来写文档(基本上是在 GitHub 上)。

Markdown 文件扩展名是。钔

当你在 Markdown 中写的时候,你使用缩短的符号,这些符号被相应的 HTML 标签所取代。每次,我都会告诉你相当于 Markdown 符号的 HTML,向你展示 Markdown 是如何使我们的生活比以往任何时候都更容易。

现在,甚至网络开发者也使用 Markdown,然后通过一些网站将其转换成 HTML。

标题

你用标签#制作标题。一个标签给你一个标题(h1),两个标签给你一个副标题(h2),依此类推,如下所示:

# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6

HTML 等效:

输出结果: Colab 笔记本

段落

HTML 中的段落由<p>标签表示。在 Markdown 中,它们由一个或多个空行分隔。像 HTML 一样,空白被忽略。所以如果你增加 10 个空行,你仍然只有一个段落。

This is a paragraph of text.This is another paragraph of text.

HTML 等效:

输出结果: Colab 笔记本

换行

只需用两个或更多空格结束一行,然后键入 return。或者留一个空行。

This is a text.     <!-- spaces -->
This is another text.

HTML 等效:

输出结果: Colab 笔记本

标出重点

您可以通过将文本加粗或倾斜来强调。

Emphasis, aka italics, with ***asterisks*** or **_underscores_**.Strong emphasis, aka bold, with ****asterisks**** or **__underscores__**.Combined emphasis with ****asterisks and _underscores_****.Strikethrough uses two tildes ~ . **~~Scratch this.~~**

HTML 等效:

输出结果: Colab 笔记本

列表

在 Markdown 中创建列表是一种真正的乐趣,你会发现没有什么比这更简单的了!

1\. Item 1
2\. Item 2 ( we can type 1\. and the markdown will automatically numerate them) 
* First Item
  * Nested item 1
  * Nested item 2
    1\. Keep going
    1\. Yes

* Second Item
- First Item
- Second Item

HTML 等效:

输出结果: Colab 笔记本

链接和图像

要创建链接,必须将链接文本放在方括号中,后面是圆括号中的 URL。图像的插入方式几乎和链接一样,添加一个感叹号(!,后面是括号中的 alt 文本,括号中是图像资产的路径或 URL。

<!-- [Text](link) -->
[Link Text]([https://medium.com/@ahmedazizkhelifi](https://medium.com/@ahmedazizkhelifi) "Optional Title")<!-- ![Alt Text](image path "title") -->
![Alt Text]([https://miro.medium.com/max/80/0*PRNVc7bjff0Jj1pm.png](https://miro.medium.com/max/80/0*PRNVc7bjff0Jj1pm.png) "Optional Title")**<!-- Linking Image -->**
<!-- [![Alt Text](image path "title")](link) -->[![Alt Text]([https://miro.medium.com/max/80/0*PRNVc7bjff0Jj1pm.png](https://miro.medium.com/max/80/0*PRNVc7bjff0Jj1pm.png) "Optional Title")]([https://medium.com/@ahmedazizkhelifi](https://medium.com/@ahmedazizkhelifi))

HTML 等效:

输出结果: Colab 笔记本

水平标尺

要创建水平线,请在一行中单独使用三个或三个以上的星号(***)、破折号(---)或下划线(___)。

Reading articles on Medium is awesome.
---
Sure !!

HTML 等效:

输出结果: Colab 笔记本

桌子

太简单了。而且你可以使用这个网站来生成它们。
在笔记本上的美元符号$前使用\,否则将进入数学显示模式(在 LaTeX 面查看)。

| Id | Label    | Price |
|--- |----------| ------|
| 01 | Markdown |\$1600 |
| 02 | is       |  \$12 |
| 03 | AWESOME  | \$999 |

HTML 等效:

输出结果: Colab 笔记本

代码和语法突出显示

```python
def staySafe(Coronavirus)
  if not home:
    return home

**HTML** 等效:

输出结果: [Colab 笔记本](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=MQrtBJ3KH1Nj&line=7&uniqifier=1)

## 大宗报价

块引号的工作方式类似于对电子邮件的回复:您必须在引号前面加上一个`>`。

This is a blockquote.

This is part of the same blockquote.Quote break> This is a new blockquote.


**HTML** 等效:

输出结果: [Colab 笔记本](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=52zLR8keH1A4&line=6&uniqifier=1)

# 乳液

> 你有没有问过自己,他们是如何用计算机写出复杂的数学和物理方程的?嗯,都是关于乳胶的。

Jupyter 笔记本使用 [MathJax](http://www.mathjax.org/) 在 HTML / Markdown 中渲染 LaTeX。把你的 LaTeX math 放在`$ $`里面就行了。或者通过在`$$ $$`之间书写进入*显示*数学模式。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/8cc47df284a94714ea72a5a8a2176f20.png)

输出结果: [Colab 笔记本](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=fiZwHP0czJyT)

[**重要提示**](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=1v3l2nNmNN7_) **:**

1.  使用`\,`在数学模式中添加**小间距**
2.  在数学模式下使用`\\`添加**新行**
3.  使用`\frac{arg 1}{arg 2}`显示**分数**
4.  对于**电源**(上标文本)使用`^{}`
5.  对于**索引**(下标)使用`_{}`
6.  对于**根**,使用`\sqrt[n]{arg}` `[n]`是可选的。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/2e52d8b60d42978e870aa23872ca1bf6.png)

输出示例: [Colab 笔记本](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=1v3l2nNmNN7_&line=7&uniqifier=1)

> *LaTeX 文件的扩展名是。特克斯*

## 希腊字母

要写希腊字母,输入`\`和字母名称:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/8962e3c6e44595531801d821b2777c18.png)

输出结果: [Colab 笔记本](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=go3imAWqE9au)

[**重要注意事项**](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=VFaCoSXvS-_H&line=6&uniqifier=1) :
要写**大写希腊字母**,键入反斜杠`\`后的第一个大写,例如:

\delta >>> δ
\Delta >>> Δ\omega >>> ω
\Omega >>> Ω


![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/8b24aa39e8abd697e83b90f932edce94.png)

输出示例: [Colab 笔记本](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=VFaCoSXvS-_H)

如下图所示:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/67815d908f3e38d8dcebf0441106c496.png)

完整的希腊字母列表。[来源](http://tug.ctan.org/)

## 罗马名称:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/ea970ef7614f8408c27e85d37e5372da.png)

输出结果: [Colab 笔记本](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=3aD-y9kO523a)

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/7cdb556311ccf4ba14d7ed49c657f440.png)

[来源](http://tug.ctan.org/)

## 其他符号

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/288bfdf9549275f62243b50a971f551d.png)

输出结果: [Colab 笔记本](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=-888LBso8HS1)

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/563813daa5dca8174f7d399530526544.png)

集合与逻辑:[来源](http://tug.ctan.org/)

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/764487534cf2adf88218da975cef5495.png)

箭头:[来源](http://tug.ctan.org/)

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/beac2c59fee2cded281a7f4e0df2138b.png)

其他符号:[来源](http://tug.ctan.org/)

## 垂直花括号:

为了定义左垂直花括号,我们使用属性

\left{


为了关闭它,我们使用

\right}


![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/f44a7d14ce084ea38630d077d9ef1134.png)

输出结果: [Colab 笔记本](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=XPXiLu3IE9gO)

## 水平花括号

对于水平花括号,我们使用:

\underbrace{…}
\overbrace{…}


![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/886853d4e83cb601fe14ea9d5e238d24.png)

输出结果: [Colab 笔记本](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=xzu2CyGLE9iy)

## 衍生产品

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/ddd9a9a69cedc1f5876259558ca41d3b.png)

输出结果: [Colab 笔记本](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=S06VqebHE9mE)

## 极限

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/a0477415fba017de9f150f1ab41f0ffd.png)

输出结果: [Colab 笔记本](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=9eGgqyQ4E9oC)

## 总和

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/a8924ac4168f6f97f054f4c43effb3f3.png)

输出结果: [Colab 笔记本](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=m6Q0JcCYE9qm)

## 产品

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/18e16797ffe5c1bd5f81d274b86d5cec.png)

输出结果: [Colab 笔记本](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=twn8CTHSE9tH)

## 积分

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/a7130c9f4b80ceb24a24cc63542a5a61.png)

输出结果: [Colab 笔记本](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=aYWkttHLE9vs)

## 矩阵

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/49baa18f98111ff6e2d07b0182e6b37b.png)

输出结果: [Colab 笔记本](https://colab.research.google.com/drive/18_2yFdH8G-6NXY_7fTcshMoScgJ-SYac#scrollTo=z3qGgxul048v)

**资源:**

*   [https://www . datasciencecentral . com/profiles/blogs/all-about-using-jupyter-notebooks-and-Google-colab](https://www.datasciencecentral.com/profiles/blogs/all-about-using-jupyter-notebooks-and-google-colab)
*   [https://oeis.org/wiki/List_of_LaTeX_mathematical_symbols](https://oeis.org/wiki/List_of_LaTeX_mathematical_symbols)
*   [https://jupyter.org/](https://jupyter.org/)
*   [https://en.wikipedia.org/wiki/Project_Jupyter](https://en.wikipedia.org/wiki/Project_Jupyter)
*   [https://en.wikipedia.org/wiki/Markdown](https://en.wikipedia.org/wiki/Markdown)
*   [http://tug.ctan.org/info/undergradmath/](http://tug.ctan.org/info/undergradmath/)
*   [https://open classrooms . com/en/courses/1304236-redi gez-en-markdown](https://openclassrooms.com/en/courses/1304236-redigez-en-markdown)

**感谢阅读!😄**

[![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/37f8cb5ef38701ddec87b02b1435a150.png)](https://medium.com/@ahmedazizkhelifi)

查看**我的其他文章**并关注我的 [**中的**](https://medium.com/@ahmedazizkhelifi)

哈利菲·艾哈迈德·阿齐兹

# 用 pandas 编写 5 个常见的 SQL 查询

> 原文:<https://towardsdatascience.com/writing-5-common-sql-queries-in-pandas-90b52f17ad76?source=collection_archive---------32----------------------->

## 利用您的 SQL 数据操作技能来学习熊猫

能够熟练地使用 SQL 和 pandas(Python 中的一个数据分析库)操作数据,对于数据分析师、数据科学家和任何处理数据的人来说都是一项很有价值的技能。在本帖中,我们将并排比较 SQL 查询和它们在 pandas 中的对应项。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/162c038d5988634c0fbe215743044418.png)

作者图片

通常有许多方法可以达到相同的输出。因此,对于一些 SQL 查询,我们将在 pandas 中选择一些对应的查询。

# 0.资料组📦

*如果你还没有,确保你已经安装了* [*熊猫*](https://pandas.pydata.org/pandas-docs/stable/getting_started/install.html) *和* [*海兽*](https://seaborn.pydata.org/installing.html) *。*

我们将使用 seaborn 的餐馆小费数据集作为样本数据集。关于这个数据集的细节可以在这里找到[(这个源实际上是 R 的,但是它看起来是指同一个底层数据集)。为了便于快速查阅,我在下面引用了他们的数据描述:](https://vincentarelbundock.github.io/Rdatasets/doc/reshape2/tips.html)

> “一个服务员记录了他在一家餐馆工作几个月期间收到的每一笔小费的信息。”

Import packages

import pandas as pd
import seaborn as sns# Import data
tips = sns.load_dataset(‘tips’)


# 📍 1.查看数据提取

让我们简单地从数据集中的前 5 条记录开始:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/76866b63e112b32b2825e7eb14531a38.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/aa9c7bf762bb8eae6bed9f3b011a9a9f.png)

在`head()`方法中,我们可以像这样指定 parantheses 中的行数:`tips.head(5)`。然而,在这个例子中我们可以不用`tips.head()`,因为默认的行数被设置为 5。

我们不查看所有列,而是查看包含选定列的前 3 行:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/7bb77ddbd780e4f78f99bf56447c48ff.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/346850f60732a80b7e264b8abba914fc.png)

在本例中,更改行选择和列选择的顺序不会影响结果。因此,图像显示了两种变化。在第一个版本中,我们首先选择列,然后指定行选择,而在第二个版本中,我们反过来做。现在,让我们看看如何过滤数据。

# 📍 2.过滤数据

让我们来看看周四前五名的记录:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/1cabbe3d7abeb829c1e2d4470f33a47e.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/0a8fd0ca6cdd5c44845c45cf26fa0134.png)

我们可以用三种方法中的一种在熊猫身上达到同样的效果。第一种是我最喜欢的在 pandas 中过滤数据的方法,因为它更简洁,尤其是当有多个条件要过滤时。在另外两种方法中,我们用代码的`tips['day']=='Thur'`部分表示的*布尔掩码*过滤数据。该布尔掩码将为每个记录创建一个布尔值,如果记录来自星期四,则为`True`,否则为`False`。因为后两种方法除了`.loc`部分是相同的,我将只展示后者的例子,因为前者可以很容易地从另一个中推断出来。你注意到我们用`==`表示平等吗?那是因为`=`在 Python 中是为赋值保留的。然而,`>`、`>=`、`<`和`<=`在两者中的工作方式是一样的。现在,让我们看看其他一些运算符:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/2800077879bd83a94a6bb249c7b04e66.png)

如你所见,两者在关键词上有相似之处。需要记住的一点是 Python 是区分大小写的。这意味着`match(r'S.')`和`match(r's.')`将给出不同的输出,而 SQL 中的`LIKE 'S%'`或`LIKE 's%'`将返回相同的输出。如果我们想过滤任何以' s '开头的日期,而不考虑大小写,一种方法是使用`match(r'[Ss]')`。如果对于某些记录,我们有一个名为“S”的工作日,`WHERE day LIKE ‘S%'`和`.str.startswith(‘S')`将选择这些案例,而`.str.match(r'S.')`不会。如果我们想迎合这种情况,那么我们将修改脚本为`.str.match(r'S.?')`。现在,让我们来看看否定:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/df19d63158b139b3b0a1eac029c491d0.png)

您可能已经注意到,SQL 中的`NOT`对应于 pandas 中的`-`或`~`。现在,让我们看看如何使用`AND`或`OR`进行多条件过滤:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/23d8f0b66ffa9ac87f02214814bba8bc.png)

> *💡*在 Python 中,`and`或`or`被称为布尔运算符,而`&`或`|`被认为是位运算符。

如你所见,用`query`过滤比布尔掩码更简洁。它也更灵活,因为我们可以使用布尔或按位运算符。另一方面,当使用布尔掩码过滤时,只支持按位运算符。那就是`tips[(tips['tip']>=9) or (tips['size']==6)]`会给出一个错误。如果你想知道为什么,看看 StackOverFlow 上的这个帖子。

但是,当根据您的熊猫版本使用`query()`时,您可能会遇到此处 : `TypeError: ‘Series’ objects are mutable, thus they cannot be hashed`描述的[问题。如果发生这种情况,请使用使用布尔掩码的替代方法来过滤数据。](https://github.com/pandas-dev/pandas/issues/34251)

# 📍 3.排序数据

现在让我们看看如何按一列升序对数据进行排序:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/4ea000e359c6cf337b642b1569abab70.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/0bfc0235374989e2e8c1eb3c12d75b54.png)

就像我们可以在 SQL 中使用`ORDER BY tip ASC`一样,我们也可以在 pandas 中使用`tips.sort_values(tip’, ascending=True)`。然而,我觉得这些多余的赘言是多余的。如果我们要按降序排序,我们使用:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/6c7ba07d35a41be6992224a8caf2a2cc.png)

看看布尔值如何也可以用整数来表示?让我们看看如何按多列排序:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/0a96b7f408e796c4a43a2f16870d3b5a.png)

排序到此为止!

# 📍 4.汇总数据

通常,我们希望汇总数据并检查汇总指标,让我们从最基本的指标开始。这是检查行数的方法:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/9bb2b7c9fdaf95418473c451fc2db272.png)

在 pandas 中,如果我们运行`tips.shape`,它将以如下格式显示行数和列数:(#rows,#columns)。这里,我们只是通过添加`[0]`来过滤行数。另一种常见的聚合是查找汇总统计数据。让我们检查所有数字列的平均值:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/ad2be4eb55397585cf046c8b9da5a8a6.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/6add926501a505ac7161740e691db4e6.png)

在 pandas 中使用这两个选项中的任何一个,如果数据在正确的[类型](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.dtypes.html)中,所有的数字列都将被自动选取。因此,我们不必键入所有的列名。

值得注意的是,`agg`其实是`aggregate`的别名。因此,所示的第二个选项是`tips.aggregate('mean')`的简称。

现在让我们检查列的最小值和最大值:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/12f26a4b055528f7034d5daf554aa18d.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/afe3b89746638761342da62d4768de23.png)

同样,这两种选择都可行。让我们进一步扩展查询:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/a717ea151c3c95f0deb3e13580b42846.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/6bae9458d5e67cbdf9d6948121e9435a.png)

尽管 SQL 和 pandas 中的输出并不完全相同,但我们得到的是相同的汇总统计数据,只是格式略有不同。这就是我们如何为两列提取相同的汇总统计信息:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/90fdcc88eec05cd71c4db3d3d78ba0e0.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/bf37dbf6975249dec467ed698bcef6e6.png)

另一个常见的查询是检查列的唯一值:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/70ba791aba669ec137ac6248ab39a989.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/80265142024f660e8377e7800f7b9382.png)

如果我们想查看唯一值的数量,那么它会变成:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/a9b0fd6b8fa30bc33ea6f3ec8528738c.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/a88eb485a2bf77f6539a50cee9b95bd3.png)

在熊猫中,我们还可以使用`describe()`获得汇总统计数据。如果我们运行`tips.describe()`,我们将看到一个漂亮的所有数字列的汇总统计表。

# 📍 5.按组聚集数据

让我们先看一个简单的组聚合示例:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/a915fe2be53e565af58b204cbab190e6.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/2c315b8361997d8dc46b38a581dc61d8.png)

另一个例子:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/537d7e0187cc818bf4bdfa987ae315b2.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/e02dda03dc68bbc4698b214cc4a5d953.png)

熊猫的数据透视表看起来更简单吗?也许吧?👀我们也可以将我们在聚合部分学到的知识用于组聚合。

Voila❕:这些是对 5 种查询的比较。这里有一个额外的例子,我们结合了一些查询:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/add487ad7a9ee3583140d6eb0bddf960.png)

*您想访问更多这样的内容吗?媒体会员可以无限制地访问媒体上的任何文章。如果您使用* [*我的推荐链接*](https://zluvsand.medium.com/membership)*成为会员,您的一部分会费将直接用于支持我。*

谢谢你看我的帖子。希望这些比较对你有用,✂️,并对熊猫有更多的了解。

如果你有兴趣了解更多关于熊猫的知识,这里有我的一些帖子的链接:
◼️️ [给熊猫用户的 5 个建议](/5-tips-for-pandas-users-e73681d16d17)
◼️️ [如何在熊猫数据框架中转换变量](/transforming-variables-in-a-pandas-dataframe-bce2c6ef91a1)

再见🏃💨

# 撰写数据科学博客

> 原文:<https://towardsdatascience.com/writing-a-data-science-blog-5595bf542107?source=collection_archive---------58----------------------->

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/34bfbd976970c914715e3c7f7adf4980.png)

照片由 Unsplash 上的思想目录

## [我如何写数据科学博客](/how-i-write-a-data-science-blog-62e4108fe478)

由[丽贝卡·维克里](https://medium.com/u/8b7aca3e5b1c?source=post_page-----5595bf542107--------------------------------)——5 分钟阅读

两年来,我几乎一直在媒体上专门写关于数据科学的文章。我最初打算只是偶尔写点东西来帮助其他人学习数据科学,并作为我自己发展的学习工具(我是费曼技术的超级粉丝)。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/acd88cdf006610c0a570af814c380a4d.png)

照片由 Pexels 的 Pixabay 拍摄

## [欢迎加入数据团队!请解决一切。](/welcome-to-the-data-team-please-solve-everything-part-i-the-problem-13a157551804)

到[贾鲁斯·辛格](https://medium.com/u/413ac87ff804?source=post_page-----5595bf542107--------------------------------) — 11 分钟读取

先说一个常见的情况。不管是勇敢的 MBA 市场实习生还是首席执行官,至少拥有一点权力的人都会面临一个难题。他们安排了一个项目启动会议,与不同的人一起集思广益,想出一个解决方案,并且知道如果它有任何机会被他们的上级批准,它将需要数据的支持。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/ebbbb9844abc3651850d54e58003b381.png)

照片由 Alva Pratt 在 Unsplash 上拍摄

## [哪位翻译?](/which-translator-870bae18f3bf)

史蒂文·麦克唐纳 — 12 分钟阅读

作为一个狂热的小说读者,我经常想知道译者的风格对翻译小说的影响。尤其是,我一直对村上春树的作品很好奇。他用日语写作,有三个主要的英语翻译:阿尔弗雷德·伯恩鲍姆、杰伊·鲁宾和菲利普·加布里埃尔。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/11a60eec4010b815dbc3d3f9d1e7386c.png)

阿莱西奥·达马托,米哈伊尔·梁赞诺夫/CC BY-SA([http://creativecommons.org/licenses/by-sa/3.0/](http://creativecommons.org/licenses/by-sa/3.0/))

## [钟形曲线的魔力](/the-magic-of-the-bell-curve-60caa40bf182)

由曼努埃尔·布伦纳 — 7 分钟读完

这个世界令人难以置信地混乱,所以我们甚至需要一定的勇气去试图在其中找到永恒的结构。统计学家是这群大胆的人中的一员,他们总是在寻找规律性。但是规律性很难找到,关于这个世界的强有力的陈述通常只有在长期盲目徘徊的代价下才会出现。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/2407032e8bc8295326960c681f50ec73.png)

## [自己解释!利用语言模型进行常识推理](/explain-yourself-leveraging-language-models-for-common-sense-reasoning-1c988b8b24cd)

作者 naz neen Rajani——25 分钟

深度学习模型在需要常识推理的任务上表现不佳,这通常需要某种形式的世界知识或对输入中不立即存在的信息进行推理。我们以自然语言序列的形式收集人类对常识推理的解释,并在一个名为常识解释(CoS-E)的新数据集中突出标注。

# 编写带有用户认证的多文件上传 Python-web 应用程序

> 原文:<https://towardsdatascience.com/writing-a-multi-file-upload-python-web-app-with-user-authentication-8f75064b819a?source=collection_archive---------7----------------------->

## 为合作者提供了一种简单的方法来上传文件到文件存储,而不需要他们理解任何代码

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/762bf24b85588b510b8c39164dfb4d67.png)

你好,我是尼克🎞 on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

当构建一个 web 服务器时,我们经常希望提出一个想法或主题。在静态网站的情况下,这可以通过在源文件中包含相关信息来实现。在更动态的例子中,在将信息返回给用户之前,可以使用 API(应用编程接口)来预处理信息。

在这个例子中,我们设计了一个简单的 flask 应用程序,它只需要一个用户密钥和一个 web 浏览器就可以工作。这背后的想法是,任何人都可以使用它,它是一个设备(和操作系统),独立的。

# 创建烧瓶应用程序

像往常一样,我们首先为服务器安装相关的库。最简单的方法是使用 pip(python 包管理器)。

pip install flask, werkzeug


## 上传页面模板

接下来,为登录页面创建 HTML 模板。为此,我们从应用程序目录开始,创建一个名为`templates`的新文件。在这里,我们创建一个名为`upload.html`的文件,并将下面的代码粘贴到其中。

本质上,我们有一个`form`,其中包含我们的密码`input`,一个文件上传`input`和一个提交按钮。工作时,这将看起来如下

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2020/raw/master/docs/img/646e03bd46f4aa4e2761f15a0fc0589e.png)

upload_simple.html 的输出

## 设置上传选项

接下来,我们为上传选项定义一个配置文件。为此,在主应用程序文件夹中创建一个名为`config.py`的文件。在此范围内,我们可以指定可接受的最大文件大小、上传目的地以及我们可以选择接受的文件扩展名。将下面的代码复制到`config.py`中,并进行相应的调整。

*关于文件类型的注意事项:文件扩展名不保证文件类型,我们应该避免执行任何上传的文件。这就是我们后来引入密码的原因——只有经过批准的用户才能上传。*

## 烧瓶模板

我们从一个基本的 flask 模板开始,它导入我们的信息,并在导航到`[http://127.0.0.1:4000/upload](http://127.0.0.1:4000/upload)`时服务于`upload.html`页面

## 上传文件检查

现在我们有了我们的应用程序,我们可以添加一些功能来确保我们有正确的目录,如果没有创建它。

if not os.path.isdir(upload_dest):
os.mkdir(upload_dest)


我们可以设置最大文件上传大小(使用来自`config.py`的值)

app.config[‘MAX_CONTENT_LENGTH’] = file_mb_max * 1024 * 1024


并检查文件扩展名(再次在`config.py`中定义)

def allowed_file(filename):
return ‘.’ in filename and filename.rsplit(‘.’, 1)[1].lower() in extensions


就我个人而言,我在代码中的`app.secret`和`@app.route`部分之间添加了这些。

## 上传时要做什么

最后,我们还没有告诉程序在上传时做什么。我们通过解析来自上传页面的 post 请求来做到这一点。有关这意味着什么的信息,请阅读:

[](/talking-to-python-from-javascript-flask-and-the-fetch-api-e0ef3573c451) [## 从 Javascript: Flask 和 fetch API 与 Python 对话

### 使用 Python 处理动态 web 界面或可视化所需的数据。

towardsdatascience.com](/talking-to-python-from-javascript-flask-and-the-fetch-api-e0ef3573c451) 

这里我们检查`request.method`是否是一个帖子,如果是,处理任何附加的文件。第一部分处理一个空请求,而第二部分遍历每个文件,检查它们是否有正确的文件扩展名,如果有,将它们保存到我们想要的位置(`upload_dest`)。

@app.route(‘/upload’, methods=[‘POST’])
def upload_file():
if request.method == ‘POST’: if ‘files[]’ not in request.files:
flash(‘No files found, try again.’)
return redirect(request.url) files = request.files.getlist(‘files[]’) for file in files:
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join( upload_dest, filename)) flash(‘File(s) uploaded’)
return redirect(‘/upload’)


## 测试用例

最后,在继续添加密码之前,我们要确保上传功能正常。为此,我们运行 python 脚本,导航到[http://127 . 0 . 0 . 1:4000/upload](http://127.0.0.1:4000/upload),选择几个文件,然后单击 upload。如果这已经成功,并且您正在使用上面的配置,那么您的文件现在应该位于与您的应用程序嵌套在同一文件夹中的`uploads_folder`目录中。

# 添加用于用户身份验证的加密数据库

到目前为止,我们已经创建了一个 Flask 应用程序,可以用来上传文件。接下来,我们想添加一个基本的安全层,这样我们就可以跟踪哪些文件被上传了,是谁上传的。此外,这允许我们拒绝任何未经授权向目录提交数据的人。

## 安装 **pysqlcipher3**

我们从安装数据库工具开始。这有时会给人们带来问题,所以下面包含了 Mac 和 Linux 的安装说明。

**MAC**

brew install SQLCipher
pip install pysqlcipher3


**LINUX**

sudo apt install sqlcipher libsqlcipher0 libsqlcipher-dev
sudo -H pip3 install pysqlcipher3python3 -c ‘import pysqlcipher3; print(pysqlcipher3.path)’


## 连接到数据库

我们从连接数据库开始。如果您以前使用过数据库,pysqlcipher 语法与 sqlite 或任何 postgresql 库非常相似。我们从导入库开始

from pysqlcipher3 import dbapi2 as sqlite3
from config import app_key, db_loc


然后连接到数据库:

conn = sqlite3.connect(db_loc)# where this is /path/test.db
cursor = conn.cursor()


最后,我们需要为数据库指定一个加密密钥,以便能够访问数据。

cursor.execute(“PRAGMA key=‘%s’”%app_key)


如果不这样做,或者使用不同的键,您将收到以下错误:`DatabaseError: file is not a database`当试图从数据库模式中读取信息时。

## 创建数据库

打开我们的数据库,输入我们的密钥,我们现在可以创建一个表来存储我们的值。我们通过使用`cursor execute`函数执行一个`create table` SQL 命令来实现这一点。最简单的用例需要一个**名称**和一个**上传密钥。**

cursor.execute(
‘’’
CREATE TABLE IF NOT EXISTS upload (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
upload_key TEXT UNIQUE
);
‘’’
)


*此外,我设置了一个条件,即每个密钥必须是唯一的,因为我们不使用用户名登录。*

最后,我们必须将新表提交给数据库并关闭它。

conn.commit()

conn.close()

close only when we have finished everything, otherwise we have to reopen the database each time


## 添加用户

我们需要用户能够使用上传工具,所以我们可以使用`insert`命令添加一些。

cursor.execute(
‘’’
INSERT INTO upload (name, dir, uploadcode)
VALUES (“bob”, “bobs top secret upload key”)
‘’’
conn.commit()


## 读取数据库

作为检查,我们想看看是否有一个名字与 upload_key 相关联。这可以通过`select`函数和`where`条件来实现。

user_code = 'bobs top secret upload key’cursor.execute(‘select * from upload where uploadcode=“%s”’%user_code)result = cursor.fetchall() # get all the results e.g. [(“bob”,)]


# 把它们串在一起

现在我们有了一个数据库和一个上传脚本,我们可以将两者结合起来。

## 打开数据库

首先,我们添加所需的库

from pysqlcipher3 import dbapi2 as sqlite3

from config import app_key, db_loc # already imported


在`from config_simple import *`线下。

## 读取密码

如果您使用的是之前的 HTML 代码,我们已经有了一个密码输入字段:`<p> upload_key: <input name=”psw” type=”password” /></p>`

因为这在提交表单中,所以我们可以在`@app.route`包装器中将它作为 POST 请求的一部分来阅读。

user_code = str(request.form.get(‘psw’))


我们将此与我们数据库阅读器结合起来,形成一个条件检查,看看是否有人拥有访问密钥/密码。

cursor.execute(‘select * from upload where uploadcode=“%s”’%user_code)
result = cursor.fetchall()if len(result)==0:
flash(‘Not a valid Code’)
return redirect(request.url)


然而,由于数据库只能从与我们需要放置的网站相同的计算线程中打开和读取

conn = sqlite3.connect(db_loc)
cursor = conn.cursor()
cursor.execute(“PRAGMA key=‘%s’”%app_key)


在`cursor.execute`块之前,以及在`result =`线之后的`conn.close()`。(见最后 GitHub repo 中的 app.py)

# 结论

这就是我们要做的——最基本的提交框,允许预先批准的用户上传文件。但是,您可能希望进行一些改进(这些都在下面 GitHub 资源库中显示的附加文件中)。

*   检查扩展名的文件名字符串可能会导致问题。文件可能命名不正确,甚至没有扩展名(我的许多文件就是这种情况)。相反,我们可以过滤`file.mimetype`值。这些是格式`image/png`等。
*   拖放上传。手动选择文件通常很麻烦,尤其是当它们位于不同的位置时。从文件浏览器中拖动它们让用户的生活变得简单多了。
*   自动上传。另一个常见的错误是选择一个文件,但忘记点击提交。在你放入一个文件后,拥有一个可以立即工作的窗口有助于提高工作效率和用户满意度
*   文件预览。如果用户正在上传图像,提供微缩预览总是很有帮助的。这样可以进行最后一分钟的检查,这样就不会重复提交相同的文件。
*   文件失败指示器。虽然有一条消息通知我们上传状态,但一个视觉提示(即一个更亮的预览图像)让我们更容易看到是否有什么东西没有工作。
*   独特的下载空间——如果你有很多用户,你可能会弄不清哪个文件属于谁(更不用说覆盖问题了)。相反,我们可以为每个用户添加一个指定的空间,并将路径保存在数据库中。

添加以上所有附加建议,我们得到以下输出。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2020%2Fraw%2Fmaster%2Fdocs%2Fimg%2F7046836748f9937fe22a220ec0dcf5f5.png&pos_id=img-BKFKgt24-1727714412026)

这里我们看到,两个文件都失败了,中间有一个成功了。在这种情况下,这是由于无效的用户凭据和故意无效的文件类型。

免责声明:这不是最安全的凭证检查方法,但是对于许多任务来说,这是一个非常合适的解决方案。

# 代码库

本教程的所有示例代码都被转储到了 Github 存储库中。

[](https://github.com/wolfiex/FlaskPython_FileUpload) [## wolfiex/FlaskPython_FileUpload

### 一个简单的烧瓶上传程序,用于需要凭据的多个文件

github.com](https://github.com/wolfiex/FlaskPython_FileUpload) 

如果您有任何改进,请随时提交拉取请求。

# 编写生产级机器学习框架:经验教训

> 原文:<https://towardsdatascience.com/writing-a-production-level-machine-learning-framework-lessons-learned-195ce21dd437?source=collection_archive---------23----------------------->

## 我们从开发 PyTorch 框架来训练和运行深度学习模型中获得的一些见解…

我和我在 [Atomwise](https://www.atomwise.com/) 的优秀同事们已经为训练和运行深度学习模型编写了一个生产级 PyTorch 框架。我们的应用集中在药物发现上——预测一个分子是否会通过结合一个口袋来抑制蛋白质的活性。我们的目标是拥有一个稳定而灵活的平台,以支持机器科学家进行培训和实验,并支持药物化学家将它们应用到生产流程中。

迭代改进和[“持续重构”](https://www.codit.eu/blog/continuous-refactoring/)在软件开发中无处不在,我们也不例外。第一个版本远非完美;但是看看用例、反馈和扩展功能,我们已经经历了几轮细化。我们的设计目标是提供一种无需编写代码就能进行简单实验的工具,以及在自动化管道中使用的工具。这意味着我们必须在允许足够的旋钮进行有意义的研究,同时限制无意的错误配置和混乱的可能性之间取得平衡。我们还针对云环境中的性能和成本效益进行了优化。在这篇文章中,我想回顾一下我们在这个过程中学到的一些通用的、独立于领域的经验。

## **1。不要重新发明轮子**

当我们第一次尝试时,我们从头开始设计了一个应用程序;使用火炬。张量运算,但是其他的很少提供实用类。这被证明是一个错误:我们遇到了多处理和数据排队的问题,这是我们没有预料到的,而且`[torch.utils.data.DataLoader](https://pytorch.org/docs/stable/data.html#torch.utils.data.DataLoader)`已经解决了。虽然这个 Python 类表面上看起来似乎没做什么,但实际上它是相当复杂的!并且它足够灵活,因此在大多数用例中无需修改即可采用。通过继承轻量级的`torch.utils.data.DataSet`和`torch.utils.data.Sampler`来使用定制要简单得多。对于后者,请参见我之前关于我们复古`[TreeSampler](/flexible-declarative-dataset-sampling-in-pytorch-613c6d5db10c)`设计的帖子。

我们的大部分架构都遵循通用标准——请看下面的概要。训练和评分循环被封装到一个`Engine`类中。训练通过小批数据迭代;在每个时期之后,来自单独测试集的固定数量的小批用于估计学习曲线并检测可能的过拟合。每当我们改进(最近的平滑平均值)测试指标时,我们会写出一个检查点作为当前的最佳模型,可以用来模拟早期停止。此外,在(可能不同的)可配置的时间间隔,我们编写检查点,将学习统计记录到度量记录器(例如,`[Tensorboard](https://www.tensorflow.org/tensorboard)`或`[MLFlow](https://mlflow.org/)`)中,并将消息打印到日志文件和控制台。我在这里描述了辅助`Meter`级[。](/pytorch-tidbits-measuring-streams-and-times-de0c7bae85da)

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2020%2Fraw%2Fmaster%2Fdocs%2Fimg%2F368b24bea3478fdf0687bc5aceb352a8.png&pos_id=img-dnKF80KL-1727714412026)

我们发现引擎代码的很大一部分与初始化训练运行所需的所有对象(模型、数据集、优化器、调度器、损失函数等等)有关,所以我们后来分解出一个只在启动时使用的`LaunchManager`类。

转换管道通常是指一系列数据预处理步骤,如选择、格式转换和随机扩充。最常见的建议是在`DataSet.`的`__getitem__()`方法中调用它们,我们通过将转换管道作为整理阶段的一部分,将一系列示例连接到一个迷你批处理`Tensor`中。为此,`DataLoader`允许传入一个可选的`collate_fn`参数。因此,张量运算可以在整个 minibatch 上进行矢量化,与在单个示例上循环相比,可以显著提高速度。

## **2。使用配置文件**

如果 shell 命令有很多可能的选项,那么它们就成了记忆和输入的负担。在实践中,用户通常会复制/粘贴本质上作为配置的包装外壳脚本。更好的解决方案是从一开始就使用配置文件来区分设置和代码。这带来了几个额外的好处:它们允许在部分、注释、管理缺省值的清晰方式和自动验证工具中进行分层组织。

虽然像 Python 这样的解释语言使得用 Python 本身编写配置变得很容易,但我更喜欢通过使用像`yaml`或`json`这样的格式来保持与代码的明显区别。在我们的例子中,我们选择了使用`[ConfigObj](https://pypi.org/project/configobj/)`包进行验证的`yaml`格式。也有替代的配置包,比如 are schema,或者脸书最近推出的`[hydra.](https://engineering.fb.com/open-source/hydra/)` `ConfigObj`管理一个单独的规范文件,包含每个参数的类型和值约束。在这里指定默认值很方便,这样配置就可以省略某些选项。例如,在得分模式下运行时,我们可以将培训部分留空,反之亦然。在验证过程中,记住还要检查额外的参数——那些由用户指定,但在规范中没有提到的参数。在许多情况下,这些都是打字错误,否则很容易被忽视。

我们将整个配置约束到一个文件中。虽然在运行实验时,文件包含、覆盖机制或拥有多个子配置可能更容易管理,但我们认为这不会服务于一致性和可再现性的长期目标。

我们发现为配置文件实现智能的类似 diff 的功能是很有用的。该函数分解添加、删除和更改的选项。这有助于快速了解新模型与以前训练的模型有何不同,以及在微调运行中发生了什么变化。与基于行的(unix) `diff`相反,它考虑了排序中的非实质性变化、隐含的默认值,并且可以被告知忽略某些差异,比如在日志记录中。

关于配置和定义模型架构的正确方法很容易引起激烈的争论——我们也有我们的一份。第一个问题:规范粒度的适当水平是什么?`[Caffe](https://caffe.berkeleyvision.org/)`框架以声明的方式指定了完整的模型,作为所有层及其设置的列表。另一方面,PyTorch 通常采用更程序化的方法——我们可以将模型定义为`torch.nn.Module`的子类,并写出包含计算步骤序列的正向方法。这两种方法在灵活性、对无意的错误设定的敏感性、代码量以及跨实验跟踪和比较方面都有优点和缺点。我们希望避免仅在细微方面有所不同的模型文件的扩散,所以我们选择了一个折衷的解决方案:我们为每个模型族写出一个文件,但是允许一些由选项控制的变化(例如,层的深度和宽度)。通过提供一个公共构建模块库,例如具有不同激活的多层感知器以及可选的丢弃层和归一化层,可以进一步促进这一点。

下一个问题:我们如何通过名称在配置中检索这些模型(当然我们不想引用文件路径)?为此,我们设计了一个轻量级的模型注册中心(也可以称之为工厂)。当模型代码用一个`@register`标签修饰时,它将被识别,并随后在配置中通过它的类名或一个定制的名字被访问。每个模型文件都有一个相关的参数规范。在训练开始时创建实例之前,注册中心会读取并验证这些参数。

我们使用的一些模型由其他模型组成——多任务、连体和系综网络。对于这些,在配置中允许多个命名的模型被证明是有用的,其中一些可能是当前未使用的。例如,系综网络可以具有如下结构:

换句话说,我们正在使用软件工程的[基本定理。我们也开始在配置的其他部分使用命名组件。例如,不同的模型类型可能需要不同的转换管道。因此,如果用户切换模型,他们将需要相应地修改转换部分,这可能是乏味且容易出错的(在实践中,用户很可能倾向于保留注释和取消注释部分)。因此,我们也用名称来指代转换管道和微型批次采样设置。](https://en.wikipedia.org/wiki/Indirection)

总的来说,我们当前的配置文件已经增长到大约 500 行。它分为以下几个顶级部分:

*   *型号:*如上所述
*   数据:位置、格式和缓存选项。在大多数情况下,原始数据太大,无法完全存储在内存中。我们假设一个单独的索引文件;每一行都包含训练标签和其他有用的元数据,以及对数据描述符的引用(通常是文件路径,尽管也可以使用其他数据源和协议)。我们不仅允许单个输入,还允许内部连接的列表。这对于配置交叉验证运行或处理多种不同的输入格式非常方便
*   *损失函数:*训练可以有一个损失函数,定期测试可以有零到多个辅助损失函数。对于多任务目标,我们用原子子损失列表定义一个复合`WeightedSumLoss`,每个子损失与输入数据中的一个权重和一个列名相关联。
*   *变换管道*
*   *小批量取样:*见[早先的帖子](/flexible-declarative-dataset-sampling-in-pytorch-613c6d5db10c)
*   *训练:*优化器、调度器、迭代次数、测试迭代的频率和次数、提前停止的平滑迭代、检查点
*   *评分:*测试时间增加和聚集,检查点的频率
*   *日志记录:*我们在这一小节中加入了 Python `[logging.config](https://docs.python.org/3/library/logging.config.html)`。顺便提一下:为了捕获和合并来自`Dataloader`工作者的日志记录,必须使用带有`[logging.handlers.QueueListener](https://docs.python.org/3/library/logging.handlers.html#queuelistener)`的 torch.multiprocessing.Queue。
*   *常规和操作参数:* CPU 和 GPU 模式、工作线程数量、随机种子、写入内容和写入频率`Tensorboard`

> “计算机科学中的所有问题都可以通过另一个间接层次来解决……除了间接层次太多的问题。”
> 
> —大卫·惠勒

## **3。共同归档和封装所有模型工件**

机器学习科学家的实践涉及不断训练和评估大量模型,以便找出最佳的模型架构、超参数、数据和采样配置。在评估之后,他们保留模型文件以便比较,并能够在将来做更多的分析。如果需要的话,你总是希望能够回到过去,并且很好地理解你到底是如何得出一个实验结果的;你今天并不确切知道明天、一个月或一年后你会问哪个问题。

归档不仅适用于原始模型文件,还适用于实验运行可能产生的所有工件:`Logging`和`Tensorboard`输出、检查点、可视化等等。保持实验有组织的一种方式是系统化的目录结构,例如使用路径名,该路径名便于记忆所研究的参数差异,与基本模型相比。虽然许多机器学习科学家自然倾向于这样的组织,但为什么不为他们做并强制执行呢?

因此,我们将所有与训练相关的工件保存在一个专用于特定运行的目录中:

*   *模型检查点:*每隔一段时间,加上早期停止的当前最佳检查点,每个测试指标一个
*   训练、测试和性能(时间和记忆)*统计*以 Tensorboard(或 MLFlow,…)格式
*   原始*配置文件*的副本,根据规范输入或不输入默认值
*   输出*日志文件*
*   检查点的副本,如果我们从一个*预训练模型*开始

对于新的训练运行,将创建一个空目录。它应该只能由我们的命令行界面脚本修改,而不能由用户直接修改。这减少了可能的错误,并简化了引擎代码,因为我们可以假设一个具有预定义名称和结构的布局。我们的礼仪是将模型目录视为黑盒档案。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2020%2Fraw%2Fmaster%2Fdocs%2Fimg%2F2d328b2dcf8367d25533a0fa663408c2.png&pos_id=img-UrOBgjKC-1727714412026)

照片由[蒂姆·莫斯霍尔德](https://unsplash.com/@timmossholder?utm_source=medium&utm_medium=referral)在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄

## **4。围绕典型工作流程进行设计**

我们如何设计命令行界面,使其既能被进行实验的机器学习科学家使用,又能作为领域专家标准工作流程的一部分,而领域专家不一定是程序员(比如我们案例中的药物化学家)?我在上面讨论了使用配置文件以声明方式控制程序行为的目标。相反,为了避免混淆,我们希望尽量减少命令行选项。本质上,脚本只需要知道三件事:

*   *到模型目录的路径*
*   *配置文件:*总是创建包含单个文件的新目录会给用户带来不必要的负担。我们允许将配置从任何原始位置复制到模型目录中。
*   *执行方式:* `train`或`score`。在评分过程中,会指定一个输出目录来包含带有模型预测的文件。某些输入列是从输入文件中复制的。我们集成了测试集扩充——该模型可以从单个输入行生成多个输出分数。该配置可以指定列来定义聚合组,这样我们就可以得到一个单独的行,但也可能是这个集合的多个统计数据(例如,分数的平均值和标准差——想想`[pandas.DataFrame.groupby](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.groupby.html)`)。

有时,我们希望从现有模型中初始化模型权重,而不是随机初始化。这对于微调来说是正确的,但如果我们只是想通过额外的迭代来继续训练,也是如此。我们应该在现有的模型目录中跟踪这个过程,还是创建一个新的?或者,行为是否应该取决于配置变更的重要性(例如,允许用户在相同的目录中添加更多的迭代,而不改变配置)?这个问题让人想起忒修斯的[船。我们的讨论最终决定总是需要一个新的目录。供参考,复制旧模型检查点;但是在初始化之后,训练运行被视为与任何其他运行完全相同。](https://en.wikipedia.org/wiki/Ship_of_Theseus)

我们还必须考虑到培训和评分大多是在云环境中进行的。我们经常为成本折扣提供现场实例,但这意味着我们必须随时准备好中断。显然,训练不应该从头开始,而应该从中断的地方重新开始。我们称这种单独的场景为自动重启。它应该对用户尽可能无摩擦和透明;因此,它应该通过重新发出原始命令自动工作,无需任何更改。

在固定的时间间隔,我们保存由模型、优化器和调度器状态组成的检查点;请注意,出于采样目的,还需要保存所有随机数发生器的状态。请记住,只有在成功写入当前检查点后,才能删除旧的检查点,以应对损坏。在自动重启时,我们会检查最新的有效版本。

如上所述,我们希望防止用户意外覆盖之前的实验。那么我们如何区分这种情况和自动重启呢?同时,模型目录之外的配置文件可能已经被修改,并且模型甚至可能在不同的绝对路径中继续。这就是比较配置的函数再次派上用场的地方。如果命令行上指定的配置文件的内容与模型目录中归档的内容一致,则该脚本假定它已经自动重启;否则,我们会警告用户并中止。

自动重启不仅适用于培训;有时我们需要对有几千万或几行的大文件进行评分。为此,计分器创建一个以输出文件命名的临时目录,并定期保存分数批次。最后,所有这些部分结果在被写回到单个输出文件之前被重新读取、连接、聚合并适当地格式化。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2020%2Fraw%2Fmaster%2Fdocs%2Fimg%2F4f8ed123e9ee4899006536c3e7d1e7fd.png&pos_id=img-TYiW9jIx-1727714412027)

Aneta Foubíková 在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄的照片

## **5。设计尽可能多的再现性(但不是更多)**

在一个专用的目录中捕获所有与模型相关的工件是实现可再现性的第一步,但仅仅是第一步。

**软件版本跟踪**

对于以后的参考,将重要的元数据打印到日志文件是很有帮助的。我们使用`[versioneer](https://github.com/warner/python-versioneer)`包来跟踪软件版本;它检索最新的 git 标签和散列字符串,并将其作为 Python 字符串提供。我们相应地设置我们的包`__VERSION__`字符串,用它来标记我们的内部 `PyPI`发布,并在每次运行时将其打印到日志输出中。我们还打印重要包的版本号,比如`torch`。

**确定性执行**

众所周知 [GPU 计算天生就是不确定的](https://pytorch.org/docs/stable/notes/randomness.html)。即使特殊的`CUDA`执行标志也不能在所有情况下消除并行执行的这些影响。然而,尽可能使训练具有可重复性也是值得的。为此,我们提供了种子随机数生成器的选项:Python 随机包、`numpy`、CPU 操作和每个 GPU 实例。注意 PyTorch `Dataloader`产生多个进程,每个进程都有自己独立的随机数生成器。正如在之前的[帖子](/flexible-declarative-dataset-sampling-in-pytorch-613c6d5db10c)中更详细描述的,我们可以通过在专用于采样的单个主线程中预先生成所有需要的随机数,并将它们附加到每个示例数据上来有效地控制这一点。

**测试**

测试驱动开发是一种有效的、普遍适用的软件开发指南。因此,我们努力用适当的单元测试覆盖我们的大部分代码库。我们还需要几个集成步骤来模拟完整工作流的不同设想情况:从头开始训练,自动重启,评分,以及重新调整,使用空的或现有的模型目录。机器学习的特殊之处在于,引入一个微妙的错误非常容易,但在一段时间内没有意识到它:只要它不会导致灾难性的崩溃,模型训练就可以在某种程度上弥补任何数据缺陷。因此,我们发现自动化每晚的训练回归工作非常有用,用我们最新的提交和典型的模型架构运行十万次迭代。基于以前的运行,我们在指定的迭代中为各种度量设置期望和容差,以提醒我们行为的任何变化,无论是积极的还是消极的。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2020%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fe5470065747690d3935be8e5b82ccab8.png&pos_id=img-8rXbv7X0-1727714412027)

照片由[卡洛斯·穆扎](https://unsplash.com/@kmuza?utm_source=medium&utm_medium=referral)在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄

## 6.最后:不要让完美成为好的敌人

一个常见的、众所周知的缺陷是过早的优化,或者优化软件的一部分,而这部分在功能或性能方面并不重要。概要分析和选择性简化(例如,用简单的模型或简单的数据运行)可以暗示什么是全局中最重要的。相反,有时不显眼的作品却能产生超大的效果。例如,分析显示,训练循环中的以下代码行由于不必要的 GPU 同步而导致速度变慢:

在我们的旅途中,我们走过了几条小路,在后面变成了兔子洞。仅举一个例子:如上所述,我们在试图保护现有模型目录不被意外覆盖方面走得太远了。我们有一个写保护文件的方案,但我们不希望用户必须明确地改变权限,同时,它必须在一个自动化框架内工作,其中状态存储在无权限的`S3`文件中。这需要大量的逻辑来涵盖不同的用例,但是总会有你没有预料到的新情况。这种设计既复杂又脆弱,最终并不值得追求所谓的利益。

如果软件变得太复杂而无法管理,用户会感到沮丧——但是如果它不能提供至少一个他们最想要的功能的基本版本,他们也会感到沮丧。这是一个连续的过程,对请求进行过滤和优先级排序,将它们捆绑到一个通用的最小化界面中。

随着软件的成长和成熟,在健壮性和便利性与新特性和灵活性之间总会有一个微妙的平衡。尽管开发人员努力让尽可能多的用户满意,但我们永远不可能让每个人都非常满意。

## 承认

感谢布兰登·安德森、巴斯蒂亚安·伯格曼、杰瑞德·汤普森和格雷格·弗里德兰!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值