不要一次剥完洋葱
就有利可图的 Python 采访阿列克谢·格里戈里耶夫
本和阿列克谢正在谈论有利可图的 Python(照片由奥斯汀·迪斯特尔在 Unsplash 上拍摄)
我很高兴能在本的盈利的 Python 播客上与他交谈。在我们的谈话中,本问了许多有趣的问题,这就是为什么我决定在博客中总结我们的谈话。
我们涵盖以下主题:
- 我正在写的书(“机器学习图书营”)
- 通过做项目和在 Kaggle 上竞争来学习
- 成为机器学习专家
- 学习机器学习时保持正确的抽象水平
- 快速原型制作和将模型投入生产
- 和其他东西
开始吧!
欢迎来到 盈利巨蟒 。我是本·麦克尼尔,今天我们采访阿列克谢·格里戈里耶夫。
Alexey 与妻子和儿子住在柏林。他是一名专注于机器学习的软件工程师。他在 OLX 集团担任首席数据科学家。阿列克谢是一位纸牌大师,他写了几本书。其中一个是“ 掌握数据科学的 Java”,现在他正在做另一个——“机器学习书营 ”。那不是错别字,那叫“书营”。
阿列克谢,欢迎你!
嗨,本,很高兴来到这里。
很高兴有你。你能告诉我更多关于你正在写的书的事情吗?
是啊!想法是通过做项目来学习机器学习。每一章都是一个新项目:你得到一个数据集,准备它,建立一个模型。我们也观察每个模型的内部,看它如何做出预测,并试图理解它。这是相当实际的,我们将理论保持在最低限度。完全避免它并不总是可能的,这就是为什么这里那里仍然有公式,但重点是编码。
书中的插图:ML 算法的输入是特征和目标,输出是模型
目标读者是已经会编码的人,比如软件工程师,或者已经有编码经验的学生。当你浏览这本书时,你建立了一个项目组合,最终,你知道了足够多的信息,可以得到一份 ML 工程师的工作,并在工作中继续学习。
这本书仍在进展中,但已经有可能看一看里面,并决定你是否喜欢它。已经有三章一附录了。总共有十章,所以现在已经完成了 30%。
是什么激发了你写这本书的想法?
前段时间我写了另一本书——是关于数据科学的 Java。我真的很喜欢它,但是它变成了一个非常小众的话题:Java 对于 ML 来说并不是那么流行。今天,如果你想做 ML,你用 Python,而不是 Java。所以,我想,我还有想和世界分享的东西,但是世界对 Java 不感兴趣,我们再写一本书吧——这次用 Python。
通过做项目来学习的想法是我从 Kaggle 那里学来的——这是一个举办数据科学竞赛的网站。在 Kaggle,一家公司准备了一个数据集,然后要求社区为他们训练最好的模型。
只有在 Kaggle 上我才真正学到了 ML。我在大学里花了几年时间学习理论,但如果没有适当的实践,这些理论是没有用的。而且,说实话,竞赛并不真的需要这种理论——参与是一种非常需要动手的活动,需要大量的编码:你生成新的功能,将它们放入库中,调整参数,查看结果,并不断重复,直到竞赛结束。
我参加了 10 多次比赛,每一次都非常有用
这让我意识到学习 ML 的最好方法不是研究它,而是做它:每个 Kaggle 比赛都是一个项目,通过做这些项目,我能够真正地学习 ML。对我来说,这比在黑板上看方程如何求解更有帮助。
这就是为什么我认为基于项目的方法是软件工程师和其他编码人员的最佳方式。这就是我决定写这本书的原因。
酷。我很高兴看到这一进展。 能否介绍一下你的背景,以及你是如何成为机器学习专家的?
我来自俄罗斯远东的一个小城市。我所在的城市有一所小大学,我学的东西有点过时了:我在学习使用 Delphi 之类的东西。2006 年,我所在地区的组织需要的就是这些。然而,我们学到了一些基本的东西,如数据库和自动化业务流程。
那很有趣,但是我真正喜欢的科目是数学和统计学。不幸的是,没有办法应用这些技能:每个人都只需要一个数据库。
最终,我搬到了俄罗斯中部的一个更大的城市。那里的公司不需要 Delphi,他们需要 Java 和 web 服务。于是我把工作重心转到了 Java 上,做了一段时间的 Java 开发人员。
2012 年,Coursera 开始流行。其中一门课程是机器学习。我碰巧看了那门课,它改变了我的生活:Java 和数据库很有趣,但 ML 吸引了我,所以我决定走那条路。
吴恩达著名的机器学习教程
大约在那个时候,数据科学职位也开始出现在市场上,尽管数量很少。当时我住在波兰的克拉科夫,有几个职位空缺,但所有的职位都需要博士学位和五年的 Hadoop 经验。这些公司不明白他们想从数据科学中得到什么,他们只是听说了 ML,然后想,“让我们雇佣一个有博士学位的人,让他们弄清楚我们想要什么”。
2013 年数据科学采访(由凡泰传媒在 Unsplash 上拍摄)
从 Java 转向数据科学是一个艰难的时期。这就是为什么我决定接受一些额外的教育并攻读硕士学位。
毕业后,我突然发现公司不再需要博士了。市场想出了他们需要从数据科学家那里得到什么。他们明白拥有博士学位是件好事,但不是必须的。从那以后,对数据科学和 ML 的需求一直在增长。
谷歌趋势:人们对数据科学和机器学习的兴趣正在稳步增长(链接)
当我开始做全职数据科学家时,我发现拥有软件工程背景非常有帮助。仅仅训练一个模型是不够的,你需要走向生产,而这是许多数据科学家纠结的事情。他们知道如何阅读论文,并从这些论文中实现算法,但走向生产是另一回事。这就是为什么接触一些软件工程有助于数据科学家利用他们的模型,更快地解决业务问题。
一名软件工程师正在生产中进行数据科学研究(图片由阿洛拉·格里菲斯在 Unsplash 上拍摄)
我还注意到,许多公司看到了这一点,并开始寻找这类人——了解 ML 的软件工程师,也许不深入,但足以实际训练一个模型,然后产生商业影响。
这很有趣,也有点违反直觉。
是的。我试图深入数学,但最终,并不需要。尽管研究它很有趣,但我和我的许多同事所做的工作是不同的。我们不解数学方程。我们花几个月的时间准备数据集,然后去图书馆,等十分钟训练结束,得到一个模型,然后再花几个月的时间生产这个模型。
训练一个模型并不需要花费太多时间,然而许多大学课程和在线课程的重点是 ML 背后的数学。是的,它仍然是需要的:作为一名数据科学家,你有时需要理解库内部发生了什么——就像软件工程师需要知道 TCP/IP 是如何工作的一样。然而,没有多少软件工程师需要每天深入网络堆栈。也许五年一次,当有问题的时候,但是日常工作通常不需要这样。
OSI 模型。对软件工程师来说非常有用,但在日常工作中可能不需要(来源:https://commons.wikimedia.org/wiki/File:Osi-model.png
所以,你只需要有广泛的知识和良好的接触不同的技术。知道细节是好的,但并不总是必要的。你所需要的只是基础——能够注意到事情是否不对劲。但是当你面对一个问题时,你需要更深入。
我反其道而行之,试图提前了解一切。相反,我应该专注于实践技能,并在需要时深入挖掘。
我注意到你在简历中提到了“快速成型技能”。你如何使用它们?
对于软件工程项目,尤其是 ML,尽快验证想法是很重要的。
通常你甚至不需要编写任何代码就可以验证一个想法。
想象一下,我们想要建立一个系统来确定一幅图像是好是坏:它被恰当地框住,聚焦并且有良好的曝光。我们不需要在模型上花时间,我们自己可以只看图片就决定质量好不好。如果不是,我们就给卖家发邮件,看看他们有什么反应。如果他们的反应是积极的,并且这是他们所需要的,那么我们就投入时间来建立一个实际的模型。
快速原型制作过程中的我(图片:旧苏联卡通https://www.youtube.com/watch?v=_39zAeiNXxo——俄文,英文字幕)
当谈到原型时,你可以快速地构建一些东西,例如一个简单的 Python Flask 应用程序,它最初可能甚至没有遵循最好的工程标准。重点在于速度,因为你想在投入时间之前先验证这个想法。然后你把这个展示给用户,或者公司内部的利益相关者,看看他们是否对这个项目感兴趣。
快速行动也意味着快速失败和快速学习:决策者通常会说“这不是我们的意思,我们不需要这个东西”。尽早了解反馈是非常好的:花了半年时间却发现项目不被需要,这是非常令人沮丧的。
如何成为快速原型制造专家?
给你的任务设定时间框架。比方说,只给它五天时间,然后在这几天里尽可能多的做。动作要快,但不要让它比计划花费更多的时间。
如果你只有一周时间,那么你就开始考虑最重要的事情。然后在一周之内,你就有了一个工作系统并进行演示。
如何不费吹灰之力就说服某人聘用你为机器学习专家?
嗯,首先,买我的书(笑)。
但是,说真的,做项目。
然而,要得到一份工作,你可能也需要得到关注。如果你有一个想法,找到或收集一个数据集,实现这个想法,训练一个模型。不要就此打住。把代码放到 GitHub 上,写一篇关于它的博文,在社交媒体上分享。如果你在十个项目中这样做,你肯定会受到关注。
在互联网上引起注意(图标由 Good Ware 、 Smashicons 、 Pixel perfect 、free pickfromflat icon
机器学习新人应该避免什么?
在开始的时候,尽量避免陷入太深的理论。例如,有一些算法,像 SVM,需要很强的数学基础才能理解它们:两年的微积分,然后是一年的凸优化。这是相当严重的,你可能会想,“我什么都不懂,所以我要辞职”。人们放弃了。不要。不要让这些方程式吓到你。
一个试图理解 SVM 的数据科学新人(照片由汤姆·普姆福德在 Unsplash 上拍摄)
ML 库隐藏了这种复杂性。您可以使用它们,而不用担心里面有什么——就像软件工程师可以在不知道 TCP/IP 如何工作的情况下创建 web 服务一样。当然,知道基础很重要,但作为新人,你应该把重点放在学得快而不是学得深。
Scikit-Learn:一个很棒的机器学习库(【scikit-learn.org】T4)
所以停留在正确的抽象层次——对于初学者来说,这可能是一个你视为黑盒的库。当你需要的时候,再深入。不要试图一次剥掉洋葱皮。
在生产中运行 ML 模型的主要收获是什么?
尽可能快地去。尝试尽快部署一个模型。项目失败最常见的原因之一是在制作完美模型上花费了太多时间。不要。从简单的基线开始,然后尝试部署它——并将其用于生产,看看人们对它的反应。
不要把它弄得过于复杂。例如,如果您想要建立一个价格建议模型,从每个类别的平均价格开始。以汽车为例,它可以简单到每个品牌和型号的平均值。不要从神经网络或者同样复杂的东西开始。
如果你在一个系统上投入了大量的时间,就很难放手。这就是众所周知的宜家效应:如果你自己做了一件东西,你会喜欢它,即使对其他人来说这没什么特别的。想象一下,你在做一把椅子,你花了三个小时做好了,它没有散架,你可以坐在上面。你喜欢这把椅子,但对其他人来说,它可能看起来很丑。同样的事情也发生在软件上:如果人们长时间构建一个东西,他们很难放弃它。
这就是我自己做椅子时发生的事情(照片由威廉·沃比在 Unsplash 上拍摄)
我有这个问题,所以意识到问题已经很有帮助了。在某些时候,继续做一个项目是没有意义的,你只需要停下来。
但是,如果一开始你只花了一周时间,却没有解决问题,你就停止了努力。你从早期的反馈中学习,然后继续前进。
你收到过的最好的建议?
“数学没有你想的那么重要,但解决商业问题比看起来更重要”。如果你的程序只是一堆“如果”语句,但它解决了一个问题——那就很好。所以从简单的启发开始,如果你看到它有帮助,继续做更复杂的事情。
只要能解决业务问题,没人会关心你的服务里面有什么
你如何决定抓住什么样的演讲机会?
我几乎什么都愿意做,因为目前我没有太多的演讲机会。我还在学习如何让我的提议听起来令人兴奋,所以会议组织者接受了它们,让我在他们的活动中发言。
你知道我可以发言的会议吗?请伸出手来(Theofilos Papapanagiotou 拍摄)
怎么和你联系?
在 Twitter ( @Al_Grigor )和 LinkedIn ( agrigorev )上关注我。
Alexey,非常感谢你来参加我们的节目。
谢谢你邀请我。我喜欢和你谈话。
是的,这很有趣。和平了,伙计们。
谢谢你阅读它。如果你喜欢这篇文章,你可以在 profitablepython.fm 上听完整集。这篇博文所涵盖的内容远不止这些!
对于盈利的 Python 的新剧集,在 Twitter 上关注 @PyPodcast ,订阅 YouTube 频道,在 LinkedIn 上关注 Ben 。
Python StdOuts:不要打印,记录!
小窍门
显示状态消息的 pythonic 方式
马库斯·斯皮斯克在 Unsplash 上拍摄的照片
通常在 Python 上,尤其是作为初学者,您可能会打印( )一个变量,以便查看程序中发生了什么。如果你在整个程序中依赖太多的打印语句,你可能会面临不得不在最后注释掉它们的噩梦。查看程序正在做什么的另一种方式是日志记录。然后,您可以将打印内容限制为最终用户希望看到的命令行输出。
为什么要日志?
日志是一种在开发阶段查看程序状态的舒适工具。理想情况是:
- 您希望区分调试输出和程序输出
- 您不希望在最终产品中出现不相关的标准输出
- 您希望在开发和测试后禁用所有标准输出
- 您希望将程序执行历史保存到一个文件中,该文件包含元信息,如时间和更详细的调试信息。
怎么日志?
您可以使用日志模块登录 python。
import logging
日志模块提供了在程序中记录各种状态消息的一些默认状态。默认级别为DEBUG
、INFO
、WARNING
、ERROR
和CRITICAL
。
如果您执行以下程序:
import logging
import os
savepath = ‘path/to/save/at/’if not os.path.exists(savepath):
logging.warning(‘Warning! The savepath provided doesn\’t exist!'
'Saving at current directory ‘)
savepath = os.getcwd()
logging.info(‘savepath reset at %s’,str(savepath))else:
logging.info('Savepath provided is correct,'
'saving at %s’,str(savepath))
示例中的路径不存在。您将看到以下输出:
WARNING:root:warning! The savepath provided doesn’t exist!Saving at current directory
不显示新的当前保存路径信息,即 logging.info。
这是因为输出的默认严重级别是“警告”。严重程度的顺序如下:
DEBUG
INFO
WARNING
(这是默认设置)
ERROR
CRITICAL
如果您想要查看较低严重性级别的输出,您必须在日志记录配置中显式设置它们。在这个设置之后启动一个新的解释器,否则它将无法工作。
logging.basicConfig(level = logging.DEBUG)
现在,一切都将被打印出来,从调试级开始。
输出:
WARNING:root:warning! The savepath provided doesn’t exist! Saving at current directory INFO:root:savepath reset at path/to/current/directory
太棒了。但是对于一个像样的日志,我们可能希望看到更多的信息,并将其放在一个单独的文件中。这可以使用配置中的格式和文件名来设置。在文件开头添加所需的配置:
logging.basicConfig(filename=’logfilename.log’,level =
logging.DEBUG,format=’%(asctime)s %
(message)s’,
datefmt=’%d/%m/%Y %I:%M:%S %p’)
这会将您的信息连同时间戳一起记录到 logfilename.log 中。
13/06/2020 05:14:47 PM warning! The savepath provided doesn’t exist!
Saving at current directory
13/06/2020 05:14:47 PM savepath reset at current/working/directory
下一次运行该文件时,日志会被附加到文本文件中,这样您就可以在一个地方拥有日志的历史记录。您也可以更改它,每次都创建一个新的文本文件,方法是将它添加到您的 logging.basicConfig 中
filemode='w'
您可以通过在脚本中添加以下内容来集中禁用所有日志记录,而不必注释掉每条消息:
logger = logging.getLogger()
logger.disabled = True
或者,您可以选择更改需要写入日志文件的输出级别,以便只向最终用户显示警告和严重错误消息。
这是登录 python 的入门知识。日志记录提供了比上面描述的更大的灵活性(处理程序、过滤器、更改默认日志级别等),但这应该足以开始使用基本的日志记录,并消除打印语句。
不要依靠数据科学和机器学习来招聘(目前)
人工智能系统风靡一时,但它们有严重的内在缺陷
查尔斯在 Unsplash 上的照片
由于时间和预算越来越紧张,公司不得不设计或利用创新的方法来赢得这场人才大战。麦肯锡预测,世界将出现人才短缺——确切地说,4000 万受过大学教育的工人太少。万宝盛华集团最近的人才短缺调查发现,38%的雇主难以填补职位空缺。随着就业市场竞争越来越激烈,公司开始转向技术的最新发展:人工智能系统来寻找、筛选和雇用最佳候选人。
难怪:2020 年的招聘和接下来的几年为公司带来了范式转变。员工不再像以前那样忠诚。拥有这种特质的千禧一代和新生代逐渐在职场中占据更多位置。为了扭转这一趋势,公司正专注于设计令人信服的员工体验。
然而,现任者往往抵制变革。大多数时候,他们太重而不能快速移动,因为他们传统的筒仓工作方式仍然存在。为了改变前进的方式,公司越来越多地转向人力资源技术供应商,推动人力资源技术市场到 2024 年价值至少达到 36 亿美元。
这导致了一个突破性的发展:公司越来越多地使用人工智能和数据科学来决定他们的招聘决定。
最初是有道理的。这些由数据科学家和招聘经理构建的算法旨在消除人类偏见。传统上,人类有偏见和偏好,这使得我们的招聘决定不公平——这就是为什么如果你和面试官有相同的爱好,你会在面试中表现得更好的原因。这会建立融洽的关系,这会影响面试后对他们的评价。
算法消除了这种模糊的判断。毕竟,计算算法常常胜过人类的判断,这意味着我们常常信任它胜过信任自己。
使用数据,算法客观地评估,没有我们所有人都有的认知偏差。筛选候选人的两小时工作可以缩短到几秒钟:对一家公司来说,不浪费时间就是省钱。
不幸的是,节省几个小时可能会导致更多的金钱损失,因为批评家们正在表明算法实际上越来越有偏见。
2003 年,美国国家经济研究局的一组研究人员进行了一项实地实验。他们向波士顿和芝加哥报纸上的招聘广告投去虚假简历,一些简历的名字听起来像非洲裔美国人,另一些简历的名字听起来像白人。
最终,招聘人员压倒性地青睐名字听起来像白人的申请者。
在某种程度上,算法是我们嵌入在代码中的观点。当存在人类的偏见和偏见时,算法就会变得有偏见,导致机器学习错误和误解。如果你在上面的实验中围绕招聘人员的决定创建一个算法,该算法将学习到一个“好”的招聘有一个听起来很白的名字——算法只和它的数据一样好,有偏见的数据导致有偏见的招聘决定。
亚马逊是受害者,也是罪魁祸首。
亚马逊依靠 2014 年创建的内部“秘密”招聘算法,根据候选人相对于公司最佳表现者的特质来评估候选人。三年后,当他们发现压倒性地偏向男性时,该计划被取消了:公司的顶级员工中男性比例过高(这可能是固有的性别偏见的结果)。
这让招聘界感到疑惑:招聘算法真的值得吗?是的,它可能是一个*,*,但前提是企业知道它的内在缺陷以及如何减轻这些缺陷。
永远不要完全相信算法推荐
公司经常陷入依赖算法来做出艰难筛选决定的陷阱。然而,很明显,算法在代码中部分是人类的决定,这意味着在这个过程中会有人类的偏见。当像亚马逊这样的公司创建这样一个算法时,他们对女性的偏见侵犯了法律和道德。
本质上,算法不是中立的。康奈尔大学最近的一项研究显示,招聘算法太不透明,难以判断它们是否公平。
厂商说的公平公正是什么意思?判断候选人是否符合道德标准的标准是什么?他们是否在努力确保它是真正客观的,而不是听之任之?
因此,招聘算法仍然不是公司在人才大战中希望的灵丹妙药。公司需要警惕过度信任这些算法:如果我们依赖它们并一直做出有偏见的决定,我们将来只会做出更有偏见的决定。这一次,他们只会变得更快。
人类必须永远在方向盘后面
特斯拉的自动驾驶功能意味着汽车可以在其车道内自动转向、加速和刹车。它还可以导航和变道。最近的发展也使它能够在复杂、狭窄的道路上行驶。
然而,这并不是完全的自主。
特斯拉明确表示:“当前的自动驾驶功能需要主动的驾驶员监督,并且不能使车辆自动驾驶”。
就像特斯拉的自动驾驶功能一样,招聘算法也是一样的。我们距离完全自动驾驶汽车还有几十年的时间,这同样适用于雇佣算法。好的算法是存在的,但成功不是偶然发生的。公司不应该在早期过度依赖算法,而应该审计和修改算法,以防止不公平现象继续存在。
因此,应该严格审查招聘建议。招聘经理必须将此类算法视为辅助手段,而非万灵药。
用人工审查审计其公正性
对于公司来说,加快招聘时间和简化流程的好处通常会超过无意歧视的风险。
为了应对这种情况并预测潜在的算法歧视,公司可以进行人工审查。例如,他们可以对机器学习的相关性进行人工审查,并有选择地消除任何可能出现偏差的相关性。
公司还可以定期对机器简历决策进行随机抽查:让算法接受广泛的人工审查,以了解算法选择了谁以及为什么选择。目的是发现偏见的潜在原因。
用人工智能审计其公平性
这听起来很讽刺,但算法也可以帮助识别算法中的偏差。
在宾夕法尼亚州立大学和哥伦比亚大学,研究人员开发了一种人工智能工具来检测基于属性的歧视。人力资源科技初创公司 Pymetrics 开源审计人工智能(Audit AI),这种算法还可以确定算法中是否存在系统偏差(尽管它涵盖了更广泛的算法类型)。
公司还可以使用多种算法来帮助限制盲点。通过这种方式,公司可以简单地根据单一指标(算法经常使用,因为它最终只有一个分数)排除合格的候选人。
数据需要有上下文
并非每个算法都是平等的。为了创建一个好的算法,数据科学家必须了解就业环境中的变量。
例如,通勤距离经常被认为是决定工作表现的一个因素。数据显示,这会对工作表现产生负面影响,增加旷工率。然而,通勤距离是由我们的居住地决定的——而居住地是由房价、收入水平甚至种族决定的。在地表层面考虑通勤距离的算法可能对少数民族等受保护群体有偏见。
没有背景,数据将不足以预测一个人在工作中的潜力。为了规避这一点,招聘算法通常会收集更多数据。然而,这可能不会像预期的那样工作:过去的表现可能是潜在的公司特定的,这违背了获得更多数据的目的。
公平会变成一场斗争
去年 12 月发表的一项 T4 VU 大学的研究表明,虽然人工智能不一定会提高或降低道德价值观,但它可以首先塑造我们认为是道德的东西。
在研究中,研究了一个跨国公司使用的人工智能招聘工具。该工具用神经科学游戏和自动化视频分析取代了标准化的在线测试。在 7 个多月的时间里,该工具进行了试点和实施,旨在客观地衡量候选人的 120 多项技能和特质。然后,它向招聘经理推荐候选人,招聘经理会带他们进行面对面的面试,随后进行小组面试。
最终,表现比预期差的候选人试图通过在神经科学游戏中作弊来欺骗系统。
团队经理也对招聘算法持怀疑态度,称他们可能会招聘更多同质员工。他们想要的一些雇员也没有通过人工智能评估,但却通过了人工评估。
人工智能团队也遇到了算法是否可行的阻力。例如,那些在人工智能评估中得分高的人在随后的人类评估中失败了。人力资源经理认为人工智能评估可能会失败——人工智能团队随后认为人类评估员有偏见,因此是不正确的。
算法的力量和做出数据驱动的决策是当今公司必须利用的东西。与麦肯锡的预测一样,人才大战已经爆发——更年轻的劳动力和思维模式的转变加剧了这场战争。为了更快地筛选,更快地招聘,和仍然能提高候选人的质量,招聘经理最终会转向人力资源技术供应商或在内部开发算法(如果他们有时间和资源的话)。
因此,公司在使用算法做出招聘决定时,需要考虑几个因素:
- **对于什么是公平,在全公司范围内达成共识。**阿姆斯特丹自由大学的研究显示,候选人、招聘经理、团队领导和人工智能团队都对什么是公平有不同的看法。没有人愿意承认他们错了,他们很快就指责谁对糟糕的决策负有责任。
- **把算法当作指南,而不是药丸。**算法不是天生中立的。将我们人类的观点编码意味着它本质上是一个数字人,只有一条思路:这个候选人与我的标准有多匹配?如果我们过度依赖算法,我们就有做出错误决策的风险。
- **算法会导致同质化。**假设你的算法确定具有属性 A 和 B 的候选人是很好的雇员。你决定雇佣这样的候选人,这反馈给算法,强化了他们的选择框架。随着时间的推移,你将会雇佣拥有 A 和 B 两种属性的候选人,这意味着公司将会缺乏多样性——不仅仅是种族和性别,还有思想和领导力。
- **投资审计团队和算法。**采用多管齐下的策略。通过使用技术和人工评论来系统地改进算法。从长远来看,投入更多的时间可能会提高招聘的质量。
- 相信自己的判断,质疑一切。不要太全心全意地听人力资源技术供应商的话。尽管他们有一套“成熟”的算法,但你仍然必须在你的团队和公司的背景下思考。质疑算法的训练语料库,并提出正确的问题:他们是在积极地对抗算法中的偏见,还是只是简单地将数据堆积在数据上?
招聘算法最终会被训练成根除人类偏见吗?答案是肯定的,但现在下结论还为时过早。也许有一天,招聘工具会公平公正地雇佣员工,但不幸的是,细节出了问题。或许随着时间的推移,我们可能会看到有一天,一家公司专注于细节,用机器学习解决招聘中的偏见,就像每个人力资源专业人员渴望做的那样。
想要更多这样的文章吗?我是 人+商业 的创始人,一家专注于领导力和人性化的媒体刊物。点击此处阅读更多内容,了解我们如何改变管理员工的方式。
不要在 SQL 上犯这 5 个错误
使用 SQL 进行数据分析非常简单……但事实并非如此!
由 Unsplash 上的 krakenimages 拍摄的照片
SQL 和机器学习有一些共同点。从一个开始很容易,因为它不需要很多编码。此外,代码很少崩溃。
我关于 SQL 和机器学习的推文。
我认为 SQL 查询不会崩溃的事实使得数据分析更加困难。我从数据库中提取了多少数据集,结果发现有错误或丢失的数据?很多!
如果代码只是崩溃,我知道我搞砸了。数据科学家需要在数据验证上花费相当多的时间,因为 SQL 查询总是会返回一些东西。
这是你在编写 SQL 查询时应该避免的 5 个错误。
这里有几个你可能会感兴趣的链接:
- [Complete your Python analyses 10x faster with Mito](https://trymito.io/) [Product]- [Free skill tests for Data Scientists & ML Engineers](https://aigents.co/skills) [Test]- [All New Self-Driving Car Engineer Nanodegree](https://imp.i115008.net/c/2402645/1116216/11298)[Course]
您愿意阅读更多这样的文章吗?如果是这样,你可以点击上面的任何链接来支持我。其中一些是附属链接,但你不需要购买任何东西。
1.不知道查询执行的顺序
SQL 查询执行顺序
SQL 进入门槛低。您开始编写查询——到处使用连接,进行一些分组,您已经是专家了(至少有些人是这样认为的)。
但是所谓的专家甚至不知道 SQL 查询以什么顺序执行吗?
SQL 查询不是以 SELECT 开头的——当我们编写它们时,它们在编辑器中,但是数据库不是以 SELECT 开头的。
数据库开始使用 FROM 和 JOIN 执行查询。这就是为什么我们可以在 WHERE 中使用连接表中的字段。
为什么在 WHERE 中不能过滤 GROUP BY 的结果?因为 GROUP BY 在 WHERE 之后执行。因此我们有理由。
最后,我们来选择。它选择要包含的列,并定义要计算的聚合。此外,窗口函数在这里执行。
这就解释了为什么我们在 WHERE 中尝试使用窗口函数的输出进行过滤时会出现错误。
注意,数据库使用查询优化器来优化查询的执行。优化器可能会更改某些操作的顺序,以便查询运行得更快。此图是幕后发生的事情的高级概述。
2。窗口函数实际上是做什么的?
使用求和窗口函数的变换示例
当我第一次遇到窗口函数时,我觉得它们很神秘。为什么使用窗口函数作为分组依据可以聚集数据?
在设计查询时,窗口函数(WF)简化了许多操作:
- WF 允许访问当前记录之前和之后的记录。请参见超前和滞后函数。
- WF 可以使用 GROUP BY 对已经聚合的数据执行额外的聚合。请看上图中的例子,我用 WF 计算销售额。
- ROW_NUMBER WF 枚举行。我们还可以用它来删除重复的记录。或者随机抽取样本。
- 顾名思义,WF 可以计算给定窗口的统计数据:
sum(sales) OVER (PARTITION BY CustomerID BY ts ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as cumulative_sum
上面的 WF 将计算从第一条记录到当前记录的累积和。
我在哪里做错了窗口函数?
我没有花时间去读一个教程来解释窗口函数的基础和功能。因此,我避免使用它们,查询变得过于复杂。然后虫子爬进来。
运行上面的例子
运行 SQL 中的例子[瞎搞](http://SQL Fiddle)
我收到了许多读者的请求,他们想玩上面的例子。现在,您可以在 SQL Fiddle 中在线运行该示例。
如果您想在本地数据库中尝试一下,下面是代码(它应该可以与 PostgreSQL 9.3 一起使用):
DROP TABLE IF EXISTS sales_table;
CREATE TEMPORARY TABLE sales_table
(
key varchar(6),
customerID varchar(10),
productID varchar(10),
price float
);INSERT INTO sales_table
VALUES ('1', 'Customer1', 'Product1', 100),
('2', 'Customer1', 'Product1', 200),
('3', 'Customer1', 'Product2', 100),
('4', 'Customer2', 'Product2', 200),
('5', 'Customer2', 'Product3', 100);SELECT customerID,
productID,
SUM(price) AS sales,
SUM(SUM(price)) OVER (PARTITION BY customerID) AS sales_all
FROM sales_table
GROUP BY customerID, productID
ORDER BY customerID, productID
3.在下列情况下计算平均值
CASE WHEN 类似于编程语言中的 IF 语句。当我们需要计算某个数据子集的统计数据时,这很有用。
在上图中,我计算了在美国销售的产品的平均价格。我不小心碰到了其他的东西。
在第一个例子中,我对所有非美国产品使用 0,这降低了整体平均价格。如果有许多非美国产品,平均价格可能会接近 0。
SELECT product, AVG(CASE WHEN country = 'US' then price else 0 end) AS avg_price
FROM sales
GROUP BY product
在第二个例子中,我只计算在美国销售的产品的平均价格,这通常是我们想要的。
注意,使用 CASE WHEN 时不需要包含 ELSE,因为它默认为 NULL。
SELECT product, AVG(CASE WHEN country = 'US' then price else null end) AS avg_price
FROM sales
GROUP BY product
关键的要点是,在使用 CASE WHEN 时,应该小心使用“else 0”。它对 SUM 没有任何影响,但对 AVG 有巨大的影响。
4.对缺少值的列进行联接
两个字符串字段的简单内部连接
SQL 中有 4 种不同的连接:内连接、外连接、左连接和右连接。当我们在查询中使用 JOIN 时,它默认为内部连接。
幸运的是,我花时间阅读了一些关于连接的教程。但我还是犯了一个菜鸟的错误。
我编写了一个类似于上图中查询的核心查询。当我执行数据验证时,许多记录丢失了。这怎么可能呢?这是一个如此简单的连接!
结果是,表 1 和表 2 中的许多条目的 string_field 列为空值。我以为 JOIN 会保留空值的记录,因为 NULL 等于 NULL,不是吗?
然后我试着:
SELECT NULL = NULL
它返回 NULL。
获取所有条目的解决方案是在 COALESCE 中包装 string_field,将 NULL 转换为空字符串。
SELECT t1.*,
t2.price
FROM table1 AS t1
JOIN table2 AS t2
ON COALESCE(t1.string_field, '') = COALESCE(t2.string_field, '')
但是要小心,因为这会将表 1 中带有空字符串的每个条目与表 2 中带有空字符串的每个条目连接起来。
消除这些重复的一种方法是使用 ROW_NUMBER()窗口函数:
- 我假设每行都有一个惟一的标识符“some_id”和一个时间戳字段。
- 只需包装查询,并获取每个唯一标识符的第一行以删除重复项。
SELECT *
FROM (
SELECT t1.*,
t2.price,
ROW_NUMBER() OVER(PARTITION by some_id ORDER BY timestamp_field) as row_count
FROM table1 AS t1
JOIN table2 AS t2
ON COALESCE(t1.string_field, '') = COALESCE(t2.string_field, '')
)
WHERE row_count = 1
5.复杂查询不使用临时表
在临时表中包装查询
如果我们能调试查询,SQL 就太好了。如果我告诉你可以调试它们呢!
您可以分解一个复杂的查询并创建多个临时表。然后,您可以对这些表运行“健全性检查”查询,以确保它们包含正确的条目。在设计新的重要查询或报告时,我强烈推荐这种方法。
DROP TABLE IF EXISTS trainset;
CREATE TEMPORARY TABLE trainset AS (
SELECT *
FROM table_1
WHERE field = 1
);
临时表的唯一缺点是数据库中的查询优化器不能优化查询。
当需要性能时,我将使用临时表定义的查询重写为使用 with 语句定义的查询。
WITH helper_table1 AS (
SELECT *
FROM table_1
WHERE field = 1
),helper_table2 AS (
SELECT *
FROM table_2
WHERE field = 1
),helper_table3 AS (
SELECT *
FROM helper_table1 as ht1
JOIN helper_table2 as ht2
ON ht1.field = ht2.field
)SELECT * FROM helper_table3;
在你走之前
在推特上关注我,在那里我定期发关于数据科学和机器学习的推特。
照片由Courtney hedge在 Unsplash 上拍摄
不要给死人寄钱
以及数据行业的其他经验。
图片由 Unsplash 上的 Precondo CA 提供
【2020 年 6 月,有报道称 糟糕的数据 阻碍了美国政府推出其新冠肺炎经济复苏计划的能力。除了其他令人痛心疾首的错误,这次 数据宕机 事件发过来14 亿美元在新冠肺炎刺激支票要死人了。
数据宕机——数据不完整、错误、丢失或不准确的时间段——不仅仅是联邦政府的问题。几乎每个组织都在与之斗争。
在这个由两部分组成的系列文章的第一部分中,我提出了一个解决数据宕机的方法:数据可靠性,这是一个从 站点可靠性工程(SRE) 借用来的概念,已经被业内一些最好的数据团队所采用。
我们如何解决数据宕机问题?
前几天,我在一家受欢迎的上市科技公司采访了一位我非常看重的数据副总裁,他告诉我数据宕机对他的公司的影响,从财务报告和监管报告到营销分析,甚至是客户参与度指标。
他厌倦了用传统的数据质量方法来解决数据问题。
“数据质量检查只能到此为止,”他说(是的,同意匿名引用)。“我想要一种能让我在任何人(包括我的老板)知道之前就知道数据宕机的东西。说真的,让我这么说吧:我认为这是*‘让我们的首席财务官远离监狱’*的首要任务。
他不是一个人。在过去的几年里,我与数百名数据领导者谈论过他们的数据停机问题,从几个空值到完全不准确的数据集。他们的个人问题包罗万象,从浪费时间(一个显而易见的问题)到浪费金钱,甚至是重大的合规风险。
为了解决数据停机问题,我提出了一种方法,它利用了我们的朋友,即“坏软件”的鼓吹者的一些最佳实践: 站点可靠性工程师 。
SRE 的崛起
自 21 世纪初以来,谷歌(该术语的来源)和其他公司的站点可靠性工程 (SRE)团队不仅在修复中断方面至关重要,而且通过构建可扩展和高度可用的系统从一开始就防止了中断。然而,随着软件系统变得越来越复杂,工程师们开发了新的自动化方法来扩展和操作他们的技术堆栈,以平衡他们对可靠性和创新的双重需求。
站点可靠性工程师(sre)通常被描述为勇敢的消防员,他们在晚上的所有时间都被呼叫来解决隐藏的错误、滞后的应用程序和系统中断。除此之外,SRE 团队通过自动化解决方案帮助自动化流程,从而促进无缝软件部署、配置管理、监控和度量,首先消除辛劳并最大限度地减少应用停机时间。
在软件工程中,每个团队都有类似于 New Relic 、 DataDog 或page duty的 SRE 解决方案来衡量应用程序的健康状况并确保可靠性。数据团队怎么会盲目飞行?
数据团队的可靠性
在现场可靠性工程中,“希望不是策略”这句话很流行。它告诉 SRE 精神,系统不会自己运行,每一个软件的背后都有一个工程师,他可以尽自己最大的能力确保某种程度的可靠性。
希望不会使你的公司免于因错误的数字而做出决策。数据可靠性会。
正如 SRE 团队最先知道应用程序崩溃或性能问题一样,数据工程和运营团队也应该最先知道坏管道和数据停机问题。仅在六年前,数据停机每年给公司造成的损失累计达 1.7 万亿美元;在一个数据无处不在的时代,数据管理工具还没有跟上时代的步伐,这些数字可能会变得更糟。
然而,为了使数据完全可用、可信和自助,数据团队必须专注于通过实现完全可靠性来减少数据停机时间。
毫无疑问,这种新方法是行业的游戏规则改变者,我很高兴看到公司加入数据可靠性运动。毕竟:当你可以信任你的数据时,谁还需要希望?
如果你想了解更多, 伸出手 给巴尔摩西。
不要停留在集合上——针对表格数据的非常规深度学习技术
使用深度学习学习表格数据的降维、去噪和合成数据生成
由 Unsplash 上的 chuttersnap 拍摄
近年来,深度学习在计算机视觉和自然语言处理领域取得了巨大进展。因此,深度学习技术通常局限于图像数据或序列(文本)数据。表格数据呢?对于业务用例来说,许多组织中传统的信息存储和检索方法无疑是最重要的。但我们表格/数据框架中的数据似乎满足于在深度学习领域使用简单的多层前馈网络。虽然有人认为递归神经网络(RNNs)通常用于表格时间序列数据,但这些方法在没有时间序列成分的数据上的应用非常有限。在这篇博客文章中,我们将看看一些深度学习技术的应用,通常用于图像或文本数据,在非时间序列表格数据上,在传统的递减水平上。
用于降维的自动编码器
传统上,自动编码器已经被用于非线性维度减少。假设我们有一个数据集,其中的要素数量远远超过我们的期望,我们可以使用自动编码器通过复杂的非线性函数将要素集调整到所需的要素大小,我们不必担心!与线性降维方法如 PCA(主成分分析)或其他传统的非线性技术如 LLE(局部线性嵌入)相比,这是一种更有效的技术。
自动编码器结构(来源)
自动编码器在没有任何标签的训练特征集上被训练,即,无论输入是什么,它们都试图预测输出。如果隐藏层足够宽,可以捕获所有的输入数据,这将是一个简单的任务。因此,对于作为自动编码器的神经网络的要求是,至少有一层,即瓶颈层,具有比输入或输出维度更低的维度。这通常是我们想要使用的嵌入层或缩减的特性集。训练网络时的度量可以是通常的均方误差或平均绝对误差。如果原始数据是 x 并且自动编码器生成的重构输出是 *x_hat,*我们试图最小化
L(x,x_hat) = |x — x_hat|
在一起训练网络的编码器和解码器部分之后,我们仅使用模型的编码器部分作为我们的维度减少/特征提取算法。Keras 中的示例代码如下:
from keras.layers import Dense, Dropout
from keras.models import Sequential, Model
from keras import metrics, InputMETRICS = [
metrics.RootMeanSquaredError(name='rms'),
metrics.MeanAbsoluteError(name='mae')
]ENCODING_DIM = 16 #Desired Dimension
BATCH_SIZE = 64
EPOCHS = 100def make_and_train_autoencoder(X_train, metrics=METRICS):
len_input_output = X_train.shape[-1]
input_ = Input(shape=(len_input_output,))
encoded = Dense(units=ENCODING_DIM*2, activation="relu")(input_)
bottleneck = Dense(units=ENCODING_DIM,
activation="relu")(encoded)
decoded = Dense(units=ENCODING_DIM*2,
activation="relu")(bottleneck)
output = Dense(units=len_input_output,
activation="linear")(decoded)
#Training is performed on the entire autoencoder
autoencoder = Model(inputs=input_, outputs=output)
autoencoder.compile(optimizer='adam', loss='mean_squared_error',
metrics=[metrics])
autoencoder.fit(X_train, X_train,
batch_size=BATCH_SIZE,
epochs=EPOCHS)
#Use only the encoder part for dimensionality reduction
encoder = Model(inputs=input_, outputs=bottleneck)
return autoencoder, encoder
用于降噪的去噪自动编码器
MNIST 上的去噪自动编码器示例(来源
去噪自动编码器的灵感来自计算机视觉领域。如上所述,它们可用于消除输入数据中的噪声。去噪自动编码器(DAE)可以类似地用于表格数据,因为大多数数据收集过程固有地具有一些噪声。这项技术已被证明是许多 Kaggle 比赛获胜解决方案的关键( Porto Seguro 的安全驾驶员预测)。与自动编码器不同,DAE 不需要满足将编码和解码部分连接到网络的要求。换句话说,不存在瓶颈,也就是说,它只是一个被训练用来消除噪声的神经网络。那么问题来了,我们如何训练网络?
去噪自动编码器的工作(来源
如上图所示,我们首先破坏输入数据 x 。被破坏的数据𝑥̃通常是通过添加高斯噪声或者通过将一些输入特征值设置为零而获得的。这是我们试图模仿数据集中噪音的方式。然后,我们让𝑥̃通过我们设计的 DAE,以获得重构的输出 x_hat ,其尺寸与输入 *x 相同。*损失函数类似于常见的自动编码器。DAE 试图最小化输出 x_hat 和原始数据 *x,*之间的差异,从而使其能够消除噪声的影响并从损坏的数据中提取特征。示例代码如下:
#Change mean and scale of the noise according to your data
noise = np.random.normal(loc=0, scale=0.5, size=X_train.shape)
X_train_noisy = X_train + noiselen_input_output = X_train.shape[-1]def make_dae(metrics=METRICS):
dae = Sequential([
Dense(units=len_input_output*2,
activation="relu", input_shape=(len_input_output,)),
Dropout(0.5), #Add dropout layers if required
Dense(units=len_input_output*2, activation="relu"),
Dense(units=len_input_output*2, activation="relu"),
Dense(units=len_input_output, activation="linear"),
])
dae.compile(
optimizer='adam',
loss='mean_squared_error',
metrics=[metrics]
)
return daedae = make_dae()
history = dae.fit(
X_train_noisy,
X_train,
batch_size = BATCH_SIZE,
epochs = EPOCHS
)
我们通常只在训练集上训练去噪自动编码器。一旦模型被训练,我们可以通过 DAE 传递原始数据 x 和测试集,比如说 x` ,以获得数据集的去噪版本。
使用语言模型的合成数据生成
我们很多人可能都遇到过著名的字符级语言模型,用于生成类似莎士比亚的文本。如果我们在训练数据(CSV/txt 格式)上训练一个语言模型会怎么样?首要问题是,我们为什么要这么做?简单的答案是——数据不平衡。大多数真实数据集在每个类/标签的训练样本数量上有很大差异。以欺诈检测为例。只有大约 0.05%的交易是欺诈性的。因此,我们可能希望生成更多的少数类训练示例来解决不平衡问题。
通过在我们的少数民族类数据(仅特征值)上训练字符级语言模型,我们可以生成类似于少数民族类的记录,就像我们通过在一组诗歌上训练模型来生成文本一样。我不会深入研究角色级语言模型的训练和采样细节,但我鼓励你浏览一下安德烈·卡帕西的博客(或者 Coursera 上的 T2 序列模型课程的第一周)。
谢天谢地,有像 gretel-synthetics 这样的库为我们做上述工作!Gretel 的图书馆也有其他选择,如在生成的合成数据集中启用差分隐私。他们的博客文章是了解和学习他们图书馆的好方法。以下示例代码可用于生成合成数据帧:
!pip install gretel-synthetics --upgradefrom pathlib import Path
from gretel_synthetics.batch import DataFrameBatch
import pandas as pdsource_df = pd.read_csv("diabetic_data.csv") #File Pathconfig_template = {
"max_lines": 20000, # maximum lines of training data. Set to ``0`` to train on entire dataframe
"max_line_len": 2048, # the max line length for input training data
"epochs": 15, # Gretel recommends 15-50 epochs with GPU for best performance
"vocab_size": 20000, # tokenizer model vocabulary size
"gen_lines": 100, # the number of generated text lines
"dp": True, # train with differential privacy enabled (privacy assurances, but reduced accuracy)
"field_delimiter": ",", # Must be specified
"overwrite": True,
"checkpoint_dir": str(Path.cwd() / "checkpoints")
}batcher = DataFrameBatch(df=source_df, config=config_template)
batcher.create_training_data()
batcher.train_all_batches()
status = batcher.generate_all_batch_lines()
synthetic_df = batcher.batches_to_df()
synthetic_df.head(10)
上面讨论的所有深度学习技术都属于自我监督或无监督学习的范畴。在为我们的分类或回归任务训练实际模型之前,这些通常被用作预处理步骤。这些步骤的有效性将取决于您手头的数据和参数,如您希望对语言模型进行多长时间的训练,或者您希望在您的特征集中进行多大程度的压缩。
恭喜你坚持到了文章的最后!希望这篇文章能够为您提供处理表格数据的创新方法。所以,下次你认为 XGBoost 或 LightGBM 就是表格数据的全部时,请三思!
请继续关注类似的另一篇帖子,在那里我将讨论像生成对抗网络(GANs) 和潜在狄利克雷分配(LDA) 这样的算法在表格数据上的应用。和我一起让表格数据再次变得伟大!
欢迎对帖子发表评论或在 LinkedIn 上与我联系。期待大家的反馈和建议。
参考文献:
[1] F. Chollet,Keras 博客,【https://blog.keras.io/building-autoencoders-in-keras.html 。
[2] A .沃森,j .迈尔斯,a .斯泰尔,格雷特尔.艾在培养基上,https://medium.com/gretel-ai。
[3] M. Jahrer,Kaggle,https://www . ka ggle . com/c/Porto-seguro-safe-driver-prediction/discussion/44629。
不要相信数据科学家会设定性能指标
如何将机器学习产品与业务结合起来
图片由 Free-Photos 来自 Pixabay
选择正确指标的重要性
你是一家销售自行车和自行车配件的电子商务初创企业的创始人。你的网站现在对所有用户都是一样的,但是你想引入个性化功能,在页面顶部显示最相关的 3 个产品。
你走向数据科学团队的办公桌,向他们解释问题。“我应该如何决定展示哪些产品?”,他们问。“那些与用户更相关的”,你解释道。“在什么意义上相关?”“嗯,用户更有可能点击的网站”,你回答,因为这对你来说似乎很简单。
但是在新功能上线几周后,你的报告显示它产生了很多额外的点击,但是销量很少。显然,许多“点击诱饵”产品已经得到推广!它们可能是一个别致的自行车头盔,广告上打着大折扣,但是已经脱销了。这可不好。
所以你向你的数据科学团队抱怨,要求他们改变相关性的概念。“当然,推广不转化的产品是没有意义的。我们只需要用户最终会购买的产品!”你解释。
图片由 Evanscycles 提供
很好,所以你的数据科学家回去工作,这一次他们的算法最大限度地增加了售出商品的数量。但是你会发现很多 3.99 美元的踏板就像这些被卖掉了!
你现在清楚地知道总收入需要最大化,因为出售大量廉价商品不会对你的底线有太大帮助。但是,等等,你想最大化的是物品的总价还是你的毛利?如果一般是毛利,但你仍然想销售某些低利润的产品,因为它们往往会带来高价值和更忠诚的客户,那该怎么办?
底线是,机器学习产品和你给它的目标一样好,这是一个商业驱动的决定,通常不是直截了当的。
但是你能控制的杠杆是什么呢?
在三维空间工作
每一款 ML 产品都需要决定三个关键因素:
- 设置适当的绩效指标来衡量成功
- 当建立模型时,为模型选择合适的优化(损失)函数
- 当模型被部署到生产中时,着眼于产品如何帮助业务整体的更大图景
我们一个一个来看。
设定绩效指标,即定义成功
机器学习模型的性能度量可以表示业务变量,但不一定如此。当模型缺乏可解释性时,业务焦点特别有用,这可以通过更加用户友好的性能度量来弥补。
为预测模型设置指标和目标时,要考虑的一个关键方面是为业务犯错误的成本。让我们以分类引擎为例来看看这一点。
犯错的代价
一个在线酒店预订平台希望预测可能会取消预订的客户。
机器学习模型工作流程如下图所示,将每个客户标记为“可能取消”或“不太可能取消”。
数据科学团队推出了一个准确率为 90%的模型,即 90%的客户预测正确。你应该祝贺你的数据科学团队吗?
让我们更详细地看看结果。有 1000 个客户,其中 900 个预测正确。
但是当我们更仔细地观察时,我们意识到并非所有的错误都是生来平等的。犯了一个错误,一个客户预计会取消,但最终没有取消,与一个客户预计不会取消,但最终传播,这是有区别的。
我们特别想问两个问题:
- 当模型显示预订将会取消时,我能有多自信?这被定义为精度
- 被取消的预订中有多大比例被正确识别?这叫做灵敏度或回忆
在这种情况下,当模型预测客户将取消时,只有 25%的可能性是正确的。而在最终会取消的客户中,它只抓住了其中的 5%!很难说是一个好的分类器,尽管它有 90%的准确率。还要考虑一个虚拟分类器,简单地对所有客户预测“否”,在这种情况下准确率为 91 %( 895+15 的正确预测/1000)。这是一个典型的不平衡类问题,众所周知,例如那些设计医学测试以识别罕见疾病的人。
那么,最好的度量标准是什么呢?
- 衡量预测模型的“正确”指标完全取决于您的业务流程和您想要实现的目标
- 通常,您需要考虑至少两个指标,并在它们之间寻找合适的平衡。查看精确回忆曲线,找到正确的平衡
现在让我们来看一下这个模型的几个业务应用程序,它们具有不同的业务优先级,因此需要优化不同的指标。
超额预订用例的酒店取消预测
优化团队希望对那些取消可能性非常高的客户进行超额预订。他们犯错误的代价很大(客户将没有地方睡觉!)但是不一定需要标记大量的客户列表。我们应该为了什么而优化这个模型?
这个模型将被优化为精确的,所以会标记很少的预订,但对那些人来说,它会超级自信。
酒店客服提醒电话取消预测
现在,考虑一下客户服务部门使用的相同模型,为更有可能取消的客户安排提醒电话,以便尝试与他们接触,防止他们取消电话。
在这种情况下,打电话的成本可能相当低,而犯错的成本(例如,打电话给甚至没有考虑取消的人)也不会太高。因此,您可能希望标记更大份额的具有不同置信度的客户,最终您将得到一个精度较低但召回率/灵敏度较高的分类器。
选择正确的优化函数
在这个阶段,您可能已经选择了一组理想的性能指标来事后测量您的机器学习模型,但您可能也希望模型在构建时就针对这些指标进行优化。
这是通过所谓的损失函数实现的,即模型在训练时(即在从过去的数据中学习时)试图最小化的误差函数,也可以被视为优化函数的逆函数。
这一步跨越了相当多的技术和数学方面的考虑,尽管许多预先构建的算法对于某些默认函数来说效果最好。例如,如果你正在运行一个线性回归,你很少想要偏离最小二乘作为损失函数。
但情况并非总是如此,在某些情况下,这也可能成为商业决策。
例如,如果您试图对彼此相似的商店进行聚类,您需要考虑“类别”维度(商店的类型)和地理成分(其位置)。
聚类模型将尝试基于距离 标准来定义聚类,但是没有一种单一的方法来定义这样的距离:例如,根据您的业务用例,您可能希望使用更广泛的类别定义(例如,所有的食品商店在一起)与更广泛的聚类地理区域(例如,城市中的所有商店,而不是邻居)。
可能出现的一个问题是:
为什么我们需要根据性能指标单独定义一个损失函数,而不是简单地使用同一个函数?
这有两个原因:
- 一个模型只能有一个损失函数,而你可以有几个性能指标。例如,正如我们所看到的,您可能希望衡量算法对毛利润和收入的影响,但算法无法同时最大化这两者
- 模型是用代码实现的,并且需要考虑操作效率。当模型需要按比例运行时尤其如此。例如,在预测房价时,您可能希望最后通过百分比误差中值来评估您的算法。但是在实践中对中值进行优化可能会很棘手,所以您可能会选择另一个度量作为损失函数。
不过,一般来说,损失函数应该与评估指标保持一致。在一天结束时,模型在训练时只能看到它的损失函数,但您将在结束时使用评估指标来评估它。如果两者开始背离,那就不好了。
纵观全局
衡量机器学习产品的性能只是故事的一部分,因为最终目标通常是改善整体业务。业务和产品目标的不同可能有多种原因,但这里有两个常见的例子,一个是负面的,一个是正面的:
- 你的产品正在蚕食其他渠道的收入
- 你的产品正在推动其他渠道的交叉销售
让我们考虑一个个性化时事通讯的例子。当用户点击时事通讯并购买产品时,你也许能够通过归因于额外的销售来准确地测量特定于产品的指标,例如增加的收入、转换率等。
但是,如果客户在时事通讯中看到一个产品,没有点击它,但后来又记得它并直接在网站上购买它,该怎么办呢?在大多数归因模型中,这将被视为“直接渠道”购买,因此不归因于时事通讯。
另一方面,你的时事通讯可能会推动其他渠道可能已经发生的销售。
尝试衡量这些更广泛的影响的一种方法是根据客户整体来衡量提升性能,而不考虑渠道。在本例中,如果您要比较简讯中的治疗顾客和对照顾客,您需要衡量他们在整个平台上的活动(例如,他们当天是否在所有渠道购买了产品)
然而,这说起来容易做起来难,主要有两个原因:
- 从技术角度来看,全球属性可能需要更深层次的数据集成,而这在公司内部不一定能实现
- 更微妙的是,其他内部产品可能会运行类似的实验,以不同的方式对待相同的客户(例如,向相同的客户显示个性化的移动应用程序页面)
在任何情况下,即使不可能解释所有这些变量,重要的是至少从定性的角度记住它们,即使不可能量化它们。
关键要点
设置正确的性能指标可能是一项棘手的任务,需要成为一项业务决策。如果您来自业务部门,请让您的数据科学家参与进来,但请记住,最终这是您的决定,并且需要基于业务优先级。如果您是一名数据科学家,请确保您完全与业务保持一致,并在做出这些决定之前尝试设身处地地为他们着想。
关键要点总结:
- 考虑价值链不同层次的度量:一个 CTR 可能更容易衡量,但通常缺乏端到端的关注
- 一个单一的性能指标通常是不够的:您需要考虑多个指标,并经常评估它们之间的平衡和折衷
- 在设置指标时,请始终牢记做出错误预测的代价。通常,同一个预测模型可以很容易地调整,使其在预测结果时或多或少地保守(就像我们的酒店取消模型)
- 不管你看多少评价指标,记住一个机器学习模型只能对单一的优化(损失)函数起作用。您需要确保这与您的其他指标和目标保持一致
- 始终从业务的角度看全局,即使这需要考虑不可量化的方面,如客户保留、跨渠道互动或长期参与。
不要小看这些 Python dunder 方法!
有大量关于使用 Python 进行面向对象编程的文章、书籍和视频,其中许多都涉及到了 dunder (也称为 magic )方法。在本文的最后,我会提供一些我认为对自己有用的资源的链接。
不过,请原谅我。
我现在要表明我的观点:在我看到它们有多有用之前,下面列出的这些方法似乎与我毫不相干。
来源:https://docs.python.org/3/reference/datamodel.html
这些被称为 富比较 的方法。现在,事后看来,它们似乎有点多余,甚至毫无用处,因为 python 本身也提供了比较对象的函数。
事情是这样的,当你构建一个类时,你可能希望它以某种特定的方式运行。现在,行为在许多方面不同于功能。
让我们看看它如何应用于数据科学的问题。
假设你正在为一个分类问题测试不同的监督学习 技术 。为简单起见,我假设您熟悉这些术语。
通常,您会有一组原始要素用作训练算法的输入变量。然而,重要的转换,比如填充缺失值、标准化变量等等,几乎肯定会发生。
就像在 scikit-learn 的管道 *,*中一样,你可以为 , , 逻辑回归构建不同的变形金刚。
请注意,即使这些步骤是相同的,并且具有相同的名称,也不可能说它们与 Python 中的常规比较是相等的。
>>> from sklearn.preprocessing import StandardScaler, MinMaxScaler
>>> from sklearn.impute import SimpleImputer
>>> from sklearn.pipeline import Pipeline
>>>
>>> mean_transformer_1 = Pipeline(steps=[
... ('imputer', SimpleImputer(strategy='mean')),
... ('scaler', StandardScaler())])
>>>
>>> mean_transformer_2 = Pipeline(steps=[
... ('imputer', SimpleImputer(strategy='mean')),
... ('scaler', StandardScaler())])
>>>
>>> mean_transformer_1==mean_transformer_2
False
这就对了。在应用不同的管道之前和之后比较模型可能相当麻烦。
比较它们的一种方法是比较每个步骤的类,看它们是否相同:
>>> class_1 = mean_transformer_1.steps[0][1].__class__
>>> class_2 = mean_transformer_2.steps[0][1].__class__
>>> class_1 == class_2
True
现在,除了难看和冗长,如果你有一个更大的管道,这可能是相当冗长的。老实说,这么小的管道在现实生活中很少投入生产。
**警告:**为了注意广度,我只保留了类别的比较。但是传递的参数比如
'mean'
如果真的要深究比较的话也要比较一下。
正如雷蒙德的名言所说:一定有更好的方法!确实有。
让我们制作一个类来比较这些:
>>> class SmartCompare:
... def __init__(self, pipeline):
... self.pipeline = pipeline
...
... def __eq__(self, other):
... return [m1.__class__ for m1 in self.pipeline]==[m2.__class__ for m2 in other.pipeline]
...
>>> mean_transformer_1_c = SmartCompare(mean_transformer_1)
>>> mean_transformer_2_c = SmartCompare(mean_transformer_2)
>>> mean_transformer_1_c==mean_transformer_2_c
True
当然,这并没有好到哪里去,但是这说明了一个问题!
您也可以继承Pipeline
类,而不是让它成为您的类的一个属性。或者甚至使用其他方法进行比较。
在任何情况下,dunder 方法都超越了常规的比较方法,使您的代码更具可读性和愉悦性。
感谢您的耐心!!!欢迎批评,请随意发表评论。
一些有用的资源:
[## 用 Dunder(神奇的,特殊的)方法丰富你的 Python 类——dbader.org
Python 的“神奇方法”是什么,以及如何使用它们使一个简单的 account 类更加 Python 化。在 Python 中…
dbader.org](https://dbader.org/blog/python-dunder-methods) [## 欢迎来到 Python,认识一下邓德尔一家
python 中几种 magic 方法的快速介绍
medium.com](https://medium.com/swlh/welcome-to-python-meet-the-dunders-41026b2a7e36)
不要浪费时间寻找学习数据科学的最佳方法
一旦你开始,道路将会变得光明。
数据科学列车正在以不断加速的速度前进,并通过增加新的车厢来增加其长度。企业希望搭上数据科学的列车,以跟上不断发展的技术并改善他们的运营。因此,在数据科学领域有大量的工作岗位。越来越多的人想搭上火车,开始在这个领域工作,因为:
- 这些工作既刺激又有趣
- 这些工作报酬很高
- 在可预见的未来,需求不会减少
这就像一个连锁反应。采用数据科学的企业创造就业机会,推动人们在这一领域工作。这些人需要接受教育,这促使其他一些人创造学习资源。在这篇文章中,我们将关注故事中的“学习资源”部分。
学习数据科学的资源多得令人应接不暇。造成这种情况的主要原因有两个:
- 数据科学是一个非常广阔的领域,是数学、统计学和编程的混合体。因此,要学的东西太多了。
- 与传统教育相比,人们倾向于更灵活、更快捷、更便宜的学习方式。因此,有各种教授数据科学的 MOOC 课程、youtube 视频、博客和训练营。
在这么多不同的平台上有这么多东西要学。这可能是优势,也可能是劣势,取决于我们如何处理。
当我开始学习数据科学时,我有一些问题让我失去了动力。我想在这里列出其中的一些问题:
- 我应该学 Python 还是 R?(我之前没有任何编程经验)
- 我需要一个硕士学位还是几个证书?
- 我需要学多少统计学?
- 我有工程学士学位,所以我有足够的数学知识,但是“我需要学多少数学”对于没有技术背景的人来说是一个重要的问题。
- TensorFlow 还是 PyTorch?
- 我应该学习自然语言处理(NLP)技术吗?
- 时间序列分析怎么样?
- 数据可视化要学什么?Matplotlib,Seaborn,Plotly 或其他什么?
- NumPy 和熊猫够数据分析吗?
还有更多的问题。你可能会有类似的问题,并犹豫开始。我没有这些问题的答案。但是我的建议是不要再浪费时间去寻找答案了。
刚开始学!
一旦你开始并迈出第一步,你就会发现一些答案。你也会看到有些问题没有明确的答案。然而,这不应该停止你的学习过程。
另一个要记住的非常重要的事情是你不能什么都学。例如,NLP 本身就是一个完整的领域,需要深入的训练和实践。如果你想专攻 NLP,你可能会更关注 NLP 专用的工具和框架。
选择总是不止一个!
当你开始倾向于数据科学的特定子领域时,一些工具和框架变得突出,但我们通常有不止一个选择。例如,R 可能比 Python 更适合于统计分析。不过 Python 也有强大的第三方统计包,比如 statsmodels 。我不想引起更多的矛盾。我只想指出,学数据科学有很多选择。
我还想提一下不同类型的资源。拥有压倒性的资源其实是件好事。我们有选择不同选项的自由。youtube 上有几乎任何与数据科学相关主题的视频。ArXiv 包含大量关于数据科学的学术文章。许多平台提供数据科学证书,如 Coursera、Udemy 和 edX。当然,博客对于学习特定主题非常有效。例如,我们可以在媒体上找到几乎任何主题的文章。
我首先完成了一个证书,IBM 数据科学专业。从主题的组织和结构来看,这是非常有帮助的。它还提供了数据科学领域的概述。我建议从这样一个基本的、全面的资源开始。然后你就会很容易地建立起自己的学习路径。你不需要收集任何主题的证书。
最后但并非最不重要的,也许是最重要的,是做项目。它们让你为工作做好准备。项目将不同的技能整合为一种。它们也是展示你技能的橱窗。
基础学完了再做项目。
数据科学在不同行业有很多应用。企业的目标是从数据中创造价值。因此,学习分析数据的算法或工具不足以获得一份工作。你应该开始做与你想工作的领域相关的项目。做项目不仅会帮助你获得更全面的知识,还会给你带来更好的工具和框架。根据项目的不同,某些工具会优于其他工具,更适合您的风格。以下是我做项目的 5 个理由:
把手弄脏来学习。
towardsdatascience.com](/5-reasons-why-you-should-do-projects-instead-of-collecting-data-science-certificates-9023accda6b4)
综上所述,怎么学其实并不重要。如果你对学习数据科学充满热情,你遵循的道路并没有什么不同。任何适合你的学习方式都可以。最重要的是开始你的旅程,当然,在你完成基础知识之后做项目。
感谢您的阅读。如果您有任何反馈,请告诉我。
别担心,Excel 出奇的有效
作为一名数据科学家,为什么不应该羞于使用 Excel
米卡·鲍梅斯特在 Unsplash 上的照片
数据科学家看不起微软 Excel 是常有的事。与 Python 这样的编程语言相比,它看起来像是石器时代的工具。它不能很好地扩展,很难重现结果,而且一旦你开始编写 VBA 宏,你还不如使用 Python。
尽管如此,Excel 还是存活了下来。我甚至想不出有哪家企业不使用某种电子表格软件来帮助分析数据。正如乔·里斯所说:
Excel 也仍然是商业世界的中流砥柱。第三次世界大战后,蟑螂和 Excel 将继续存在。
幸存者
你可能想知道,为什么 Excel 能在大数据和 Spark、Snowflake 等性感工具的世界里生存下来?不起眼的电子表格怎么可能没有被完全打乱?
我相信这是因为 Excel 是查看和分析数据的最用户友好的方式之一。Excel 是一个所见即所得(WYSIWYG)类型的产品。进入 Excel 时,您会看到数据的表格视图,您可以开始编辑、添加公式以及创建数据透视表。当您进行这些更改时,您看到的内容会自动更新。这是难以置信的强大,它使 Excel 更加平易近人。
此外,Excel 使基本分析变得非常简单和直观。想取一列的平均值?就用平均公式吧。想要数据的散点图吗?只需突出显示您的数据,然后单击“散点图”。这种易用性是一个难以置信的好处。它允许公司利用非程序员来分析和可视化数据。在我看来,Excel 是帮助公司建立数据驱动文化的最佳工具之一。
数据科学家该不该用 Excel?
以上几点我想大家都能认同。Excel 是一个有用的工具,可以帮助人们简单直观地进行基本的数据处理和分析。
但是——它应该成为数据科学家的工具吗?
或者——我们是不是太超前了?对 Excel 这样的软件来说太复杂了?所有问题应该通过 Python 还是 R 来运行?
我认为,每个数据科学家都应该对 Excel 有基本的熟悉,并觉得把它作为工具使用并不可耻。
我提到羞耻是因为我发现数据科学家很容易讨厌 Excel。它肯定不是解决所有问题的工具。甚至可能不是大多数数据科学问题。但这并不意味着它没有自己的位置。我发现 Excel 在以下情况下非常有用:
- 我有少量的表格数据,我想对其进行一些快速计算。例如,也许你在一个电子表格中有几百个 YouTube 视频的视图。只需打开它并计算一些基本的统计数据,就会简单快捷得多。
- 我需要与非数据科学家分享结果,同时让他们能够轻松地进行自己的分析。
- 我想快速绘制一些干净的表格数据。
注意:在上述所有示例中,这些都是临时请求,不会重复出现。一旦你开始必须创建一个可重复的过程,我会转向编程语言,即使分析很简单。如果有必要,这样做将更容易复制和扩展您的分析过程。再现性和可伸缩性是 Excel 的两个主要缺点。
去学吧
希望这篇短文已经让您相信 Excel 在您的数据科学工具箱中有一席之地。如果您还没有使用过 Excel,我建议您在 Excel 中打开一个 CSV 文件并探索其功能。这很容易开始。
如果你想要一些入门帮助,微软有一些非常好的免费教程。
最后,还要记住 Excel 对于许多数据科学项目来说并不是一个好工具。如果您发现自己有更大的数据集、更高级的分析/机器学习需求,或者需要创建可重复的流程,请不要使用 Excel。回到你选择的编程语言。
如果你需要一个资源来帮助你开始使用 Python 进行分析和可视化,你可以看看我创建的课程来做这件事。
现在,去为你的数据科学工具箱添加另一个工具吧(如果你还没有的话)!
这篇文章也可以在这里找到。
使用 Python 实现数据科学线性代数中的点积
建立对矩阵如何帮助解决线性方程组以及回归问题的直觉
在这里你可以一步一步跟着我
在您很好地掌握了向量、矩阵和张量之后,是时候向您介绍线性代数的一个非常重要的基本概念了— 点积(矩阵乘法)以及它如何与求解线性方程组相关联。我说它很重要,因为它被广泛应用于几乎所有主要的机器学习和深度学习算法中。
这为学习数据科学的数学提供了一个很好的案例。
因此,在这篇文章中,我们将使用 NumPy 来涵盖以下概念及其代码:
- 矩阵和向量的点积
- 两个矩阵的点积
- 矩阵乘法的性质
- 线性方程组
- 线性回归预测模型方程
让我们开始吧…
矩阵和向量的点积
与加法或减法不同,两个矩阵的乘积不是通过将一个矩阵的每个单元与另一个矩阵的相应单元相乘来计算的,而是我们计算一个矩阵的行与另一个矩阵的列的乘积之和,如下图所示:
矩阵和向量的点积
这种矩阵乘法也叫点积。
下面是该方法的形式化描述:
矩阵乘法数学形式化
**重要规则:**只有第一个矩阵的列数等于第二个矩阵的行数,才能将两个矩阵相乘。
如果一个矩阵的形状是(m×n),而另一个矩阵的形状应该是(n×t)(t ≥ 1),那么得到的乘积矩阵将具有如下所示的形状(m×t):
如果我将矩阵 A (3×2)与向量 B(2×1)相乘,下面是矩阵和向量之间的点积的更全面的符号形式:
生成的矩阵将是一个 3×1 向量,计算如下:
[数]矩阵
让我们看一个例子:
将第一个 3×2 矩阵乘以一个向量
按照上述规则计算的结果矩阵
代码:
让我们使用 Numpy 对它们进行编码:
Colab 笔记本截图,可以在这里查看:https://colab . research . Google . com/drive/1 jrqnk 5 pjlwbycvjf 2 jhjdu-dRvMXjXkD?usp =分享
首先,在您的工作区中导入 NumPy 包,然后创建一个上面例子中讨论过的 2D 矩阵或任何其他您想尝试的矩阵结构,然后创建一个向量,确保矩阵中的行数和列数相等。
然后可以使用 numpy 包中的dot()
方法,将矩阵和向量传递给它。它将为您返回合成向量,如图所示。
您可以查看整个笔记本,并使用以下代码进行试验:
colab.research.google.com](https://colab.research.google.com/drive/1jrQnk5pjLWbYCvjF2JHjDu-dRvMXjXkD?usp=sharing)
两个矩阵的点积。
然后,我们可以将 2 个矩阵相乘,下面是一个 4×3 矩阵 A 乘以 3×2 矩阵 B 的示例:
遵循如下所示的方法:
代码:
就像我们编写上一个示例一样,这里您将创建两个 2D 数组,然后使用数组的点方法,您可以计算点积:
Colab 笔记本截图,可以在这里查看:https://colab . research . Google . com/drive/1 jrqnk 5 pjlwbycvjf 2 jhjdu-dRvMXjXkD?usp =共享
矩阵乘法的性质
现在矩阵乘法都清楚了,让我们看看下图中解释的矩阵乘法的一些属性:
这里有一个任务给你:你可以根据你的想象创建矩阵(A、B 或 C ),然后通过首先计算 lhs 来检查每个规则,然后用它来评估 R.H.S。如果它们成立。
我将在这里检查点积的变换规则:
大家可以看到,我首先创建了两个矩阵 A 和 B ,然后首先通过计算两个矩阵的点积来求解 L.H.S .然后使用**T**
方法转置它们,并根据 R.H.S .对其进行评估,其中矩阵的位置互换,它们首先被转置,然后使用dot()
方法相乘。
线性方程组
在线性代数中起着至关重要的作用,以帮助解决各种各样的问题,方程系统基本上被定义为多个方程的集合。它们可以用矩阵进一步描述,让我们看看如何描述。
含有两个未知数的两个方程组。图表绘制使用:https://mathisfun.com
因此,方程组有两个主要部分:
- 方程式的数量
- 未知数的数量
未知数的数量是手头问题的维数,方程的数量是(2D)或 n 维平面中的线的数量。
这是一个由 4 个方程和 4 个未知数组成的系统:
含有 4 个未知数 x1,x2,x3,x4 的 4 个方程组。
线性方程组的矩阵表示
现在,我们可以使用矩阵来描述线性方程组,其形式为 Ax = b. 考虑这个线性方程组:
这里,我们有从 x₁到 xₙ的**n**
个未知数,我们有**m**
个行数(这里是方程)。我们可以推断出变量(从 x₁到 xₙ)可以概括为一个向量 x.
并且我们可以将作为(每个变量的系数(权重)】放在另一个矩阵 A 中:
然后,可以使用下面的符号来描述系统的 lhs:
A 和矢量 x 的点积将给我们所需的输出矢量 b
下面是一个两个方程的系统如何发生这种情况的例子:
线性回归
我们今天所学的一个实际例子可以在线性回归模型预测方程的实现中看到,如下所示:
这里,
- ŷ 是预测值。
- n 是特征的数量。
- xi 是第 i 个特征值。
- θj 是第 j 个模型参数(包括偏置项 θ 0 和特征权重 θ 1、 θ 2、⋯、 θn )。
它可以进一步写成矢量化的形式,如:
yˇ= hθ(x)=θx
- θ 是带有特征权重的模型的参数向量。
- x 是实例的特征向量,包含 x 0 到 xn ,其中 x 0 始终等于 1。
- θ x 是矢量 θ 和 x 的点积,等于上式中的相对高度。
- h θ 为假设函数,使用模型参数 θ 。
结论:
因此,你可以意识到点积和矩阵&向量在机器学习中的重要性,因为高层的每个操作都是由这些基础知识执行的。
Harshit 的数据科学
通过这个渠道,我计划推出几个涵盖整个数据科学领域的系列。以下是你应该订阅频道的原因:
- 该系列将涵盖每个主题和子主题的所有必需/要求的高质量教程,如 Python 数据科学基础。
- 解释了为什么我们在 ML 和深度学习中做这些事情的数学和推导。
- 与谷歌、微软、亚马逊等公司的数据科学家和工程师以及大数据驱动型公司的首席执行官的播客。
- 项目和说明实施目前所学的课题。
你可以在 Twitter 、 LinkedIn 或 Instagram 上与我联系(在那里我谈论健康和福祉。)
双盲随机研究:如何正确证明治疗有效
自从新冠肺炎病毒传播以来,我们已经听到各种各样的人在争论某些医学研究将某种药物作为治疗手段的有效性。在本帖中,我将展示一种最值得信赖的科学方法来证明一个事件对另一个事件的影响,例如,一种疗法对一种医疗状况的影响。
由 Unsplash 上的 Taras Chernus 拍摄的照片
用实验研究证明因果关系
证明因果关系的挑战,即一个事件(或特征)对另一个事件的影响,是数据科学家面临的一个著名挑战。很容易获得一个历史数据集,绘制数据点,并找到两个变量之间的相关性。然而,相关性并不意味着因果关系:
- 可能无法知道哪一个变量是另一个的原因,哪一个是结果;
- 相关可能是纯粹的巧合;
- 第三个未知变量可能是两个研究变量的原因。
人们在冲进苹果商店时会摔下楼梯吗?还是人口增长解释了这两个系列?也许这只是纯粹的巧合?更多好玩的例子看【tylervigen.com/spurious-correlations】
为了解决这些问题,研究人员设计了实验研究。与研究历史数据的观察性研究不同,实验性研究是通过重复一个具有受控变量的实验来创建我们自己的数据:在两次实验之间只有一个变量发生变化,这就是我们想要研究的变量对目标变量的影响。如果目标值随着变量的变化而不断变化,那么就存在因果关系。
定义双盲研究
现在,假设我们想证明一种新药治疗特定疾病的效率。典型的设置包括将患病患者分成两组,只给一组患者用药,并比较每组中治愈患者的数量。但是为了避免任何可能影响结果的偏差,我们将增加额外的步骤:
- 为了消除反应偏差,我们会给未治疗组的患者服用安慰剂,他们显然对治疗分配是不知情的;
- 为了消除统计偏差,我们将随机分组;
- 为了消除确认和观察者的偏见,研究者和医务人员也将对治疗分配视而不见。
该配置定义了一个双盲随机研究。
实验结果分析
为了简单起见,我们的两个组被认为具有相同的大小,但是对于不同大小的组,分析是非常相似的。**
简化实验的观察结果
现在我们可以制定两个假设:
- 无效假设:药物无效,两组治愈率相近;
- 替代假设:该药物是有效的,并且在提供药物的组中治愈率明显更高。
在零假设下,理论结果会是这样的:
在零假设下的结果:组间无差异。
我们现在将执行 卡方检验 。这种广泛使用的测试检查两个变量之间的统计联系(相关性)。这里,我们的两个二元变量是:
- 药物的使用(表格各栏)
- 病人的治疗(表格的行)
对于表中的每个像元,卡方统计是观测像元值与零假设下的像元值之间的平方差之和除以零假设下的值:
我们简化案例研究的卡方统计公式
最后要做的是将该值与参考表进行比较,以接受或拒绝零假设。在我们的示例中,我们有 1 个自由度:一个变量的值的数量减 1 乘以另一个变量的值的数量减 1 等于 1。
来自维基百科的卡方值表
让我们以下面的例子为例,计算卡方值。起初,我们可能认为这种药物是有效的:
如果我们想要 95%的置信度(这是医学中的常见情况),因为我们的卡方值是 4.8,4.8>3.84,我们可以拒绝零假设,认为药物与安慰剂相比有效果。
****就是这样!不要忘记寻找效果的类型(积极或消极)。
注意:为了使卡方检验有效,建议在零假设下,表中每个单元格的 E≥5。
高级分析:数字目标变量
有时候,目标变量不是二元的,而是一个连续的数值变量:治愈天数、血糖水平、血压……这种情况下,建立一个结果表就无关紧要了。我们将使用不同的方法。
首先,我们将为每组中的每个患者注册目标变量的值。绘制每组的值分布图是评估药物是否对目标变量(此处为患者治愈的天数)有影响的第一条线索。
如果我们的结果看起来像例 A,我们是否应该认为药物有效果?例子 B 呢?
比较这两组的严格方法是比较它们分布的期望值。然而,我们只知道我们研究的病人的样本均值。所以我们要用学生的 t 分布的一个性质来估计两个分布的期望值(一个先决条件显然是检查分布是否正态)。此属性根据样本平均值定义分布期望值的置信区间:
期望值置信区间的学生定律
α是置信水平。 n 是样本量(患者数)。 t 是学生因素。我们可以在参考表中找到它的值:
来自维基百科的学生因子值表
例如,假设我们有 2 组 100 人( n=100 ),我们想要 95%的置信度,我们研究前面看到的例子 B:
示例 B 的置信区间
期望值的置信区间不重叠,因此分布也不相同:我们可以认为,与安慰剂相比,药物在治愈天数上是有效的。
一个结论
双盲随机研究是证明药物有效的最可靠的方法之一,但它的用途远远超出了医学研究。例如,你可能知道广告、UX 设计甚至机器学习中经常使用的 A/B 测试:哲学是相同的。这种研究可以在我们想知道一个变量是否对另一个变量有影响的任何时候使用。在 Wavestone Consulting,我们使用类似的方法为我们的一个客户评估储罐特性对酒精蒸发的影响。
然而,当进行双盲研究是可能的时候(并不总是如此——你如何为外科手术提供安慰剂?),一个主要的缺点出现了:如果测试的药物是有效的,这意味着“安慰剂”组没有从中受益,当然会后悔。给患有不治之症的病人服用安慰剂是否道德?也许有一天,在 A/B 测试的背景下,一些旨在解决这个遗憾问题的新方法,例如基于强化学习的网飞艺术品个性化系统,将有益于医学研究。
使用一小段代码在 10 秒钟内将你的 Google Colab 内存翻倍
“我需要更多内存!”(图片鸣谢:布莱克·帕特森)
oogle Colab 是一个不可思议的工具。可以用三个字来形容:云中的 Python。好吧,四个字。但是重要的是,您不需要担心 Python 版本(Colab 既有 Python 2 又有 Python 3),也不需要担心下载模块(最流行的已经安装了)、备份、文件系统和所有那些有时会导致您因堆栈溢出而浪费时间的管理工作。最好把多余的精力留给编码。
Google Colab 很棒,因为它很简单。这对于学习 Python,对于小型玩具项目,以及一些严肃的机器学习实践来说都是非常棒的。谷歌让你免费使用他们的 GPU 或 TPU!我发现它在大学环境中非常有用:我要求学生通过分享他们的 Google Colab 笔记本的链接来提交他们的作业。再也没有“我的笔记本电脑因为内存不足而死机”的借口了。
2020 年 5 月 20 日更新:一位读者报告说在免费的 Colab 运行时上加倍 RAM 的选项不再有效。胡乱猜测:这与谷歌最近以 9.99 美元/月的价格推出的 Colab Pro 有关,它提供了两倍的内存…
Colab 是 100%免费的,因此自然会有一些资源限制。正如你在下面的截图中看到的,Colab 的每个实例都有 12 GB 的 RAM(实际上是 12.7 GB,但是已经占用了 0.8 GB)。这已经足够了,尤其是考虑到你不需要为此付钱。但有时你需要更多的内存。
默认运行时间有 12 GB 的内存
幸运的是,谷歌很慷慨。非常慷慨。您可以将 RAM 增加一倍,达到 25 GB。你是怎么做到的?不幸的是,没有复选框或菜单选项来做到这一点。要让 25 GB 选项生效,首先需要用完所有会话内存。全部 12 GB。一旦您这样做,会话将崩溃,Colab 将在屏幕底部显示以下内容:
你耗尽了所有的内存!
单击“获取更多内存”将弹出一个对话框,允许您切换到“高内存”运行时:
是的,我有!
就是这样!一旦您批准,您的机器 RAM 现在将显示新的容量:25.5 GB。
双倍的内存!
有一个问题:在 25 GB 升级之后,您当前运行时的状态将会丢失,包括本地文件。你需要从头开始重新运行你的程序。也许再次上传文件等等。因此,如果你知道你肯定需要那块额外的 RAM,先分配它,然后再发现,否则就太晚了。
那么怎么分配这么多 RAM 呢?我在网上找到了一些解决方案,但是(1)它们需要大约 60 秒(2)它们需要多行代码。
所以我想出了一个更简单的解决方案:一行代码,由 10 个字符组成,就可以完成这个任务。此外,它非常快:仅在 10 秒钟内就消耗完了所有 12 GB 或 RAM。这是:
[1]*10**10
就是这样。这就是代码。它是如何工作的?Python 将尝试创建一个由 10 个⁰=10,000,000,000 整数组成的列表。然而,这样的列表需要超过 12 GB。事实上,存储这个列表需要大约 80 GB 的 RAM。因此,会话将崩溃,升级将很快可用。所以:如果你确定你的程序需要双 RAM,在暂存单元(Ctrl/⌘+Alt+N)中运行[1]*10**10
,接受 ram 升级,就这样。你完了。
希望你喜欢这篇文章!现在,让我们开始 10x10 编码挑战:)
10x10 编码挑战
你能找到一段“更好”的代码来用完所有的内存吗?短一点的(少于 10 个字符),还是快一点的(少于 10 秒)?或者最好两者都有!欢迎在评论区发表您的代码或任何其他反馈。谢谢大家!
更新(2020 年 5 月 3 日): Sumit Yadav 回应挑战,发布了一段更短的代码,只有 9 个字符:[1]*9**10
(9 ⁰约为 3.5 10⁹,足以触发内存升级)。恭喜你 Sumit!
用凯利标准和贝叶斯统计让你的钱翻倍
投资组合优化
如何确定赌注并获胜
彼得罗·马蒂亚在 Unsplash 上拍摄的照片
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
不久前,当我住在阿德莱德时,有客户找到我,他们想弄清楚如何分配赛马中的赌注,特别是一些奇特的赌注,如 trinella(以任何顺序挑选前三匹马)和 quinella(以任何顺序挑选前四匹马)。
他们想让我找出一种计算凯利标准(见下文)的方法,通过重复下注来成倍增加他们的资金池。一个巨大的复杂问题是,这是一个同注分彩投注系统,所以赛马的赔率甚至就在比赛开始前更新!
我可以说我解决了这个问题,但是我不能在我的咨询合同中透露这个解决方案。
然而,在这篇文章中,我将讨论凯利标准,以及如何将贝叶斯统计与它结合起来。
单次与重复下注
假设你想通过抛硬币和一个朋友打一次赌。假设你有一笔资金池 M ,那么,为了使你的赢款最大化,最佳策略是你应该下注 M 的全部股份。对于一枚公平的硬币,预期的回报是 M/2。
但是如果你和你的朋友多次打赌呢?
我们可以很容易地看到,在一次性赌注中使用的策略在这里并不适用。如果我们每一轮都下全额赌注,存活足够长时间以复合初始资金池的机会将非常渺茫,因此随着赌注数量的增加,我们的预期奖励将趋向于 0 。我们可以看到,最起码,重复下注的游戏主名是生存,而欣欣向荣。
那么,在这种情况下,什么是最佳策略呢?
输入凯利标准
凯利标准是由贝尔实验室的 John L. Kelly Jr .在其开创性的论文中提出的,是一种在重复下注的情况下优化下注规模的策略。凯利本人是一个有趣的人物:一个烟不离手的得克萨斯人,二战期间曾是海军的战斗机飞行员,也是一名出色的研究员。他发展了这个标准,作为他杰出的同事克劳德·香农对信息熵的另一种解释。你可以从《财富的公式》这本书里了解它的历史。
给定一个初始的财富池,目标是在下注时最大化财富的翻倍率。凯利论文中对赛马案例的最初分析假设投注者将她的投资组合完全投资于所有期权;后来出现了一些变化,赌者可以扣留一部分财富。有趣的是,可以从数学上证明(几乎可以肯定),从长期来看,没有其他策略能在更高的财富方面胜过凯利标准。
简而言之,凯利标准的目标是通过在每次下注时进行智能分配,最大化财富翻倍的速度。即使你知道胜算很大,全押也不是个好主意,因为有亏损的可能。
让我们考虑一下掷硬币场景中的重复下注。在这种情况下,凯利标准很简单(例子取自维基百科)
- f* 是当前财富要下注的分数(用分数表示),
- b 是在赌注上收到的净赔率(例如,下注 10 美元,赢了,奖励 14 美元,包括赌注;然后 b =0.4),并且
- p 是获胜的概率。如果我们让q= 1p,那么有趣的是,凯利准则建议,如果下注者有一条边,即b>q/p(注意,如果b<,则 f* 可以是负数它还说如果b*=q/p就不要赌任何东西。*
为了得到下面的好东西,我不打算过多地钻研这个案例的公式。你可以在像托马斯和盖的经典文本这样的标准教科书中找到推导。
现在我们已经建立了对凯利标准的直觉,通过对比单次下注情况和重复下注情况,我们可以看到明显的差异:
- 如果赔率对你不利,就不要下注!这相当于在扑克游戏中经常弃牌,只对对你有利的赌注分配较大的份额,
- 对于一次性下注,我们最大化您赢款的平均值(或期望值),但对于重复下注,我们最大化您赢款的 几何平均值。
这些共同帮助我们最大化我们的钱每一次翻一番的速度(或 T42 翻一番的速度)。
这已被应用于各种游戏,包括赛马,甚至股市投资。在后一种情况下,有人说沃伦·巴菲特本人就是凯利·bettor⁴(尽管我认为查理·芒格比巴菲特更像)。
一个主要的警告
然而,应用该标准的主要困难在于,它假定事件发生的真实概率对于下注者来说是已知的。在上面掷硬币的例子中,下注者知道 p 的值是多少,她可以相应地确定赌注的大小。
实际上,这些通常是未知的,概率必须由下注者来估计。不幸的是,根据定义,任何估计都可能是错误的,因为这只是猜测。该标准对估计概率敏感,并且由于该标准使财富翻倍指数最大化,所以随着时间的推移,估计概率中的错误很容易毁掉投注者。
请注意,在我的咨询工作中,我的客户有一个系统来估计马匹获胜的概率,这使得我的工作简单了很多。
如果你没有这样的系统,这就是贝叶斯更新的用武之地。目标很简单:我们希望根据所有可用信息估算事件发生的概率。我们根据新的信息不断更新概率,然后用这些信息来决定我们的赌注。随着时间的推移,随着评估的适应,我们希望我们的分配表现得更好。
例子:赛马!
具体来说,让我们把问题归结为在赛马场赌马的具体问题。
让我们假设有 K 匹马。在每一轮中,我们都想赌一匹获胜的马,一旦这一轮结束,获胜者就是这 K 匹马中的一匹。基于这些信息,我们想要更新一组概率 p ₁, p ₂,⋯, pₖ ,其中 pᵢ 是那匹马我的概率,随着时间的推移越来越接近真相。
点击链接这里运行一个他们如何一起工作的模拟!假设你的机器上已经安装了 Docker ,只需在命令行上通过提供的脚本run.sh
运行笔记本即可。笔记本在docker/Kelly Multiarm Portfolio Simulation.ipynb
找到。
我们假设马独立地执行。基于这个假设,我们可以用狄利克雷分布来模拟马获胜的概率。这样做的理由如下:****
- 每匹马获胜都可以被视为一个分类随机变量,所以如果马 k 获胜,那么实现的随机变量就是 k ,那么
- 作为伯努利过程的一般情况,分类分布的共轭先验是狄利克雷分布,因此选择了狄利克雷分布。这在朱庇特笔记本上会更清楚。
贝叶斯更新投资组合与最优凯利配置投资组合
**我们将看到,在模拟中,在重复下注的情况下,由于估计概率中的误差,分配通常是不完美的,并且不接近最优分配,即,如果下注者知道潜在的马获胜概率。我们可以在下图中看到这一点,其中最优投资组合和贝叶斯投资组合的初始财富都是从 1 美元开始的。但是结果是不可否认的:随着评估变得更好,最终的分配也会变得更好!
最后一个音符
当然,现实要复杂得多:
- 我们假设马的表现是相互独立的:这在现实中可能不是真的,****
- 潜在的真实概率在整个模拟过程中保持静态:同样,概率在现实生活中会更加动态,更多地来自未知过程,****
- 目标函数假设在估计的概率中没有错误:考虑估计中的不确定性可以改善分配,并且
- 在整个模拟过程中,赔率保持不变:这在同注分彩投注系统中显然是不正确的,因此在赔率变化的情况下不断更新概率会很有趣。
我还没有探索的一个途径是转换到非参数模型(也称为神经网络)来估计概率。这是令人兴奋的,因为人们可能会使用每匹马的更多上下文信息,例如它的骑师、过去在不同赛道上的表现等。来推导获胜的概率,而不是像上面那样附加一个经典的共轭先验。
另一个原因是,将它应用于股票市场更复杂,因为股票价格的范围更广,基本上可以用连续分布来建模。也就是说,可以想象的是,蒙特卡洛模拟的某种组合可能有助于估算。
我想总结的一个主要观点是,概率的建模和赌注的大小本质上分别是估计和决策任务。这与强化学习和控制系统有很强的联系,因此结合这些领域的知识将是一个令人兴奋的探索领域!****
原载 此处 稍加编辑。
参考
[1]约翰·l·凯利,“信息率的新解释”,贝尔系统技术杂志。第 35 卷第 4 期:第 917–926 页,1956 年链接
[2]威廉·庞德斯通,“财富的公式:击败赌场和华尔街的科学赌博系统的不为人知的故事”,2006 年链接
[3]托马斯·m·盖和乔伊·a·托马斯,“信息理论的要素”,第 2 版。,2006 年链接
[4] Mohnish Pabrai,“The Dhandho Investor:The Low-Risk Value Method to High return”,Wiley,2007 年链接
上下:用 D3.js 说明的谜题
在面试中解决一个脑筋急转弯可能会令人害怕,但通常简单的视觉效果——就像这篇文章中的那些——会帮助你找到答案。
由 Walimai.photo 拍摄的照片由作者裁剪并调整大小。
在最近的一次度假中,我和丈夫偶然发现了一家娱乐商店,里面有很多棋盘游戏、骰子、扑克牌等。我们很快找到了一件我们都绝对是书呆子的东西,被认为是必不可少的:Boris A. Kordemsky 写的一本书,书名是The Moscow Puzzles:359 Mathematical Recreations。不,我们没有花整个假期来解决所有 359 个问题,但我们确实把书带回家,并继续研究它们——通常在晚上喝一杯酒。
出于几个原因,最近有一个特别的谜题引起了我的注意。我一会儿会回到那些原因,但是现在,这个问题叫做“上下波动”,它是这样的:
假设你有两支铅笔压在一起并垂直握着。从铅笔的下端量起,左边有一英寸被涂上了油漆。右铅笔保持稳定,同时将左铅笔向下滑动 1 英寸,继续将两支铅笔压在一起。然后,将左边的铅笔向上移动,回到原来的位置,同时保持两支铅笔接触。你继续这些动作,直到你把左边的铅笔上下移动 5 次。假设油漆在此过程中不会干燥或耗尽。在你最后的动作之后,每支铅笔有多少英寸被涂上了颜料?
如果你愿意,在继续之前花一分钟解决这个问题——剧透在前面!
最初的想法
当我第一次听到这个问题时,我最初认为,也许油漆根本没有涂抹到右铅笔上,也许在整个过程中,只有一英寸的油漆出现在左铅笔上。(这也是你预料到的吗?)但是当我第二次阅读这个问题时,我开始想象可能会发生什么。一旦我在脑海中勾勒出这个过程,解决方案就变得清晰多了。因为我丈夫正在和我一起解决这个问题,所以我给他画了这个草图来分享我的想法:
我设法清晰地设想了情况,找到了解决方案,并用这个简单的草图表达了我的想法。对于许多数学难题来说,一张粗略的图片就能满足你寻找答案的所有需要,但是如果我粗糙的图画还没有完全传达给你答案,不要担心。让我们用一个更好的例子来更有条理地深入一下。
颜料立即从左边的铅笔转移到右边。
问题设置
从问题的方向,我们知道,最初只有左边的铅笔涂上了油漆。回想一下,左边的铅笔直接压在右边。这意味着当它们挤压在一起时,颜料立即转移到正确的铅笔上。所以两支铅笔在上下运动之前都涂了一英寸的颜料。
解决和说明整个问题
随着左铅笔上下移动,问题变得有点复杂,但是再次回到视觉解释非常有帮助。也可以随时重读问题陈述,重新找到你的方向。
两支铅笔目前都被涂上了一英寸厚的油漆。然后左边的铅笔向下移动一英寸,同时两支铅笔继续压在一起。你能想象当左边的铅笔向下移动时会发生什么吗?是啊!左铅笔的干净部分与右铅笔的底部接触;因此,另一英寸的油漆转移到左侧。
左边的铅笔现在比右边的低一英寸。右铅笔的一英寸被涂上了颜料,但是颜料覆盖了左铅笔的两英寸。左边的铅笔在问题的下一步向上移动,回到原来的位置。两支铅笔重新对齐,但是颜料会发生什么变化呢?由于左铅笔不断与右铅笔接触,在第一次上下循环结束时,油漆会涂抹到右铅笔上,并覆盖两个铅笔的两英寸。
其余四个循环过程类似,颜料先转移到左边的铅笔,然后转移到右边。最后,在五轮运动之后,两支铅笔都被涂上了总共六英寸的颜料:最初的一英寸加上另外五英寸,每一个上下循环一次。
这个问题最终取决于将问题陈述转化为解释性视觉效果的能力。为了进一步将这个解决方案放到上下文中,我用 D3.js 创建了一个交互式图形,展示在下面的 gif 中。下面两支铅笔都从一英寸的油漆开始,如问题设置中所述。
在每次上下移动的过程中,额外的颜料会涂抹到左边的铅笔上,然后是右边的。
注:你可以在我的网站上 与这个视觉 互动或者在 GitHub 上 看一下我的 D3 代码 。
背景故事和问题扩展
之前我提到的这个问题引起了我的注意,原因有几个。第一个原因正是我们一直在讨论的。我惊讶于这个问题一开始听起来是多么棘手,而一旦你在脑海中构建了一个适当的情景,它就变得多么简单。
这个谜题激起我兴趣的第二个原因是它的历史。正如 Kordemsky 在书中解释的那样,生活在 20 世纪早期的苏联数学家 Leonid Mikhailovich Rybakov 创造了这个“上下”问题。我非常欣赏贯穿许多时间和地域的数学问题。解决这样的难题让我感觉与过去和世界上其他数学家有了更多的联系。
最后,这个问题引发了我的好奇心,因为 Rybakov 第一次想到这个问题是在一次成功的猎鸭回家的时候。Kordemsky 鼓励读者思考为什么会这样,但在他的“答案”部分继续解释。摘自莫斯科谜题一书:
看着他的靴子,Leonid Mikhailovich [Rybakov]注意到他走路时,他们通常互相摩擦的地方整个长度都是泥。
“真奇怪,”他想,“我没有在很深的泥里走,但我的靴子却泥到膝盖了。”
现在你明白谜题的由来了。
就像油漆涂抹了两支铅笔的整个长度一样,Rybakov 的靴子从头到脚都是,因为当他走路时,泥浆从一只靴子转移到了另一只靴子。
我继续思考这个概念如何适用于其他情况,我想到了一个有趣但有点令人不快的例子。考虑两行魂斗罗舞者,其中第一行中的第一个舞者不幸感到不适。如果这位舞蹈演员的疾病具有高度传染性,她当然会将她的疾病传染给她对面的舞伴。有时在对舞中,参与者通过横向移动两条线来交换舞伴。令人遗憾的是,当这种情况发生时,新感染的舞蹈演员会将疾病传回到线上,最终整个舞蹈演员群体都会生病。
疾病从一个舞者传播到另一个舞者,就像颜料在铅笔之间转移一样。
注:你可以在我的网站上 与这个视觉 互动或者在 GitHub 上 看一下我的 D3 代码 。
结论
我希望你喜欢这个关于我最喜欢的数学智力题之一的讨论,以及这些说明性的 D3 图片。在脑海中形成一个数学难题的图像并不总是容易的,但是在解决这样的问题时,它是无价的——尤其是如果你像我一样是一个视觉学习者。下一次,当你在面试中遇到问题时,看看画草图或想象问题的物理结构是否有帮助。对我来说经常是这样。
我也希望你喜欢了解这个谜题背后的背景故事。一些世界上最好的数学智力题是在很久以前创造的,所以我相信当试图提高我们的思维时,回顾过去对我们大有好处。此外,将这类问题扩展到新的应用程序,就像我对魂斗罗舞者所做的那样,有助于巩固核心概念,并为未来的脑筋急转弯建立直觉。它也使数学问题变得更有趣,因为你把它们和你自己的生活联系起来。现在轮到你了——你能想到其他“上下”的场景吗?
原载于 2020 年 1 月 5 日 http://kimberlyfessel.com。
参考
[1] B. A. Kordemsky,莫斯科难题:359 种数学娱乐 (1992),多佛。
下载一个 Flask 模板,准备插入您的业务逻辑
照片由 Fotis Fotopoulos 在 Unsplash 上拍摄
可用于日志记录、配置设置、URL 参数验证的预配置设置
让我们假设,经过大量艰苦的工作,你已经有了你的机器学习模型,它应该运行的方式。这种模型可以响应用户的请求,对推文情感进行分类,或识别图像中的对象,或推荐产品或其他符合您需求的算法。您现在想要快速部署这个模型。下面这篇文章解释了我创建的模板,它可以让你快速上手。
Flask micro 服务是一种部署应用程序的简单方法。然而,人们很快意识到,你不希望创建一个大的单片单文件程序。该计划应该是模块化的,以支持未来的增强,它应该是可配置的帮助下配置文件。这些配置参数不仅适用于 Flask,也适用于您的业务应用程序(还记得您创建的 tweet 分类应用程序)。理想情况下,服务器应该适当地记录一切。大多数应用程序还需要连接到数据库,最后,在调用模型 api(或返回错误)之前,需要验证入站请求参数。
听起来很多,对吧?这实际上是相当多的,人们可以很容易地花相当多的时间来构建一个提供这些特性的健壮框架。在这里,我提供了一个到 github 的链接,它在一个模块化的应用程序中提供了所有上面提到的特性。
您应该能够克隆这个 Flask 服务器模板,并简单地运行它。一旦你让它运行起来,你就可以开始调整它来满足你的特定需求。
[## alsm 6169/flask _ 服务器 _ 模板
Flask 服务器模板准备插入业务逻辑。该模板的特点是:烧瓶配置模块…
github.com](https://github.com/alsm6169/flask_server_template)
**在本文中, 我将只解释为您的项目定制这个烧瓶模板可能需要更改的部分。**我的基本假设是对 Flask、SQLAlchemy、Marshmallow 有一定程度的熟悉。只要足够熟悉,如果某些部分没有意义,可以谷歌一下。请在评论中自由提问,我可以回答/更新文章以涵盖要点。
如果您希望先安装并运行服务器,那么请跳过中间的解释部分,按照下面的命令顺序操作。
让我们从代码组织开始
Flask 服务器模板代码结构
现在解释代码文件
下面我将解释每个文件的用途以及你可能需要根据你的要求修改的相关代码部分(如果有的话)。
base _ dir/flask _ server _ template→主模板目录
flask _ server _ template/main . py
这是服务器的入口点。它读取应用程序配置文件(run_params.json),初始化记录器,初始化 flask 服务器并运行服务器。
**### flask_server_template/main.py ###***To use the template no changes are needed in this file.*
flask _ server _ template/main _ config . py
这个模块有两个作用。
1.读取应用程序配置文件,并创建一个可由应用程序的另一部分使用的字典。
2.创建数据库连接字符串。这个连接字符串利用了配置文件中的参数。该连接字符串因基础数据库而异。用于创建连接字符串的 SQLAlchemy 文档在这里是。
**### flask_server_template/main_config.py ###** def get_db_con_str():
pwd = os.getenv(**'DB_PWD'**) *# get password from environment variable DB_PWD* db_con_str = **f'postgresql://'** \
**f'**{run_conf_data[**"DB_USER"**]}**:'** \
**f'**{pwd}**@'** \
**f'**{run_conf_data[**"DB_SERVER"**]}**:'** \
**f'**{run_conf_data[**"DB_PORT"**]}**/'** \
**f'**{run_conf_data[**"DB_NAME"**]}**'** os.environ[**'SQLALCHEMY_DATABASE_URI'**] = db_con_str
return db_con_str
flask _ server _ template/config→以下是记录器和业务逻辑应用程序的配置文件
config/logger.conf
有两个日志处理程序。“handler_consoleHandler”记录到屏幕,而“handler_fileHandler”记录到文件 run_log.log 中。每次服务器运行时,该文件都会被覆盖。但是,如果您想更改这一点并创建带有时间戳的新文件,您可以取消对第二行的注释,并对第一行进行注释
**### config/logger.conf ###** ...
...
[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=simpleFormatter
args=('logs/run_log.log','w')
*#args=('../logs/' + time.strftime('%%Y%%m%%d_%%HH%%MM') +'.log','a')*[handler_consoleHandler]
class=StreamHandler
level=INFO
formatter=simpleFormatter
args=(sys.stdout,)
...
...
config/run_params.json
“run_params”具有应用程序级配置,包含数据库服务器、用户名、运行 flask 的模式(开发/生产)等信息
**### config/run_params.json ###** {
"LOGGER_CONFIG": "config/logger.conf",
"FLASK_CONFIG": "flask_config.DevelopmentConfig",
"DB_SERVER": "localhost",
"DB_PORT": "5432",
"DB_NAME": "dvdrental",
"DB_USER": "dvdrental"
}
flask _ server _ template/logs→创建运行日志的目录
要使用该模板,不需要对该目录进行任何更改。
flask _ server _ template/test→您的测试脚本
test/flask_client.py
这个模板是一个工作模板,理想情况下,人们应该能够简单地下载和运行。测试客户端将测试这些功能。
**### test/flask_client.py ###***To use the template no changes are needed in this file. New additional test cases can be written in this file or new test file created in this test folder.*
flask _ server _ template/flask _ server _ template→包含 flask 初始化代码、配置设置以及适当功能的路径重定向的主 flask 目录。
flask _ server _ template/_ _ init _ _。py
init。py 包含 flask_server_template 包的初始化函数。它有一个主要功能“create_app”,创建 Flask 对象,设置 Flask 配置,初始化数据库并注册路线(其功能的 URL)
***### flask_server_template/__init__.py ###***To use the template no changes are needed in this file.**
flask _ server _ template/flask _ config . py
’ flask_config.py '包含 flask 的配置设置。它提供了开发和生产环境的一般配置。
大部分常用参数都已经设置好了。如需更多设置选项,请查看官方文档。
***### flask_server_template/flask_config.py ###***To use the template no changes are needed in this file.However, for quick reference, the default configurations*class Config(object):
DEBUG = False
TESTING = False
CSRF_ENABLED = True
SECRET_KEY = **'this-really-needs-to-be-changed'** SQLALCHEMY_DATABASE_URI = os.getenv(**'SQLALCHEMY_DATABASE_URI'**)
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ECHO = False
class ProductionConfig(Config):
DEBUG = False
class DevelopmentConfig(Config):
DEVELOPMENT = True
DEBUG = True*
flask _ server _ template/flask _ routes . py
“flask_routes.py”包含 URL 到其相应实现的映射。
***注意:*有一个调用对数据库进行适当的设置。@ routes . before _ app _ first _ request。如果我们希望使用 SQLAlchemy ORM 特性,这是必需的。在下面对 flask_server_template/db 的描述中有更多的细节。
对于每个需要迎合的 REST API,都需要有一个到函数的映射。这里描述了映射到 URL 的单个函数的示例。
***### flask_server_template/flask_routes.py ###** ...
...
@routes.route('/module/v01/functions/film_info_orm', methods=['GET']) ***#TODO:*** *change URL*
def get_film_info_orm(): ***#TODO****: change function name*
try:
log.debug('inside get_film_info_orm') ***#TODO:*** *change logging*
film_df = bm.get_film_info_orm(request) ***#TODO:*** *change business logic function here*
response_code = 200
response_msg = film_df.to_json(orient='records') ***#TODO:*** *change response*
except RuntimeError as err:
response_code = 700 response_msg = jsonify(str(err))
return make_response(response_msg, response_code)
...
...*
flask _ server _ template/model→业务逻辑代码驻留在这里**
model/business _ model . py
在模块“business_model.py”中添加了所需的业务逻辑。一般流程如下:验证输入参数,从数据库获取数据,执行所需的业务逻辑应用程序并返回结果。
PS: 目前,我没有任何业务逻辑。我只是从数据库返回熊猫数据帧格式的数据。
****### model/business_model.py ###** ...
...def get_film_info_orm(in_request): ***#TODO****: appropriate function name*
try:
*# validate the URL parameters* title_schema_obj = TitleValidator() ***#TODO****: appropriate validation object*
title_schema_obj.load(in_request.args)
*# verification passed, hence flask_server_template comes here else it would have gone to exception* title = in_request.args[**'title'**]
log.debug(**'title: '** + title)
*# get your data in pandas data frame format* df = queries_orm.get_film_info(title) ***#TODO****: appropriate function call here*
*# apply business logic (if any)* return df
except ValidationError as error:
log.error(**f'get_all_film_df:** {error}**'**)
raise RuntimeError(**'Invalid Request Parameter: '** + str(error))
...
...**
model/request _ validator . py
模块’ business_model.py '使用棉花糖来验证 URL 参数。与手动编写 if then else 语句来验证 URL 参数的每个组成部分相比,这是一种首选的验证方式。验证包括数据类型检查(整数、字符串)、数值范围或特定列表和/或一些完全定制的检查。
****### model/request_validator.py ###** ...
...
def some_custom_check(data): ***#TODO****: common checks*
*'''can be replaced with customised check'''* if not data:
raise ValidationError(**'some_custom_check for title failed'**)class TitleValidator(Schema): ***#TODO****: appropriate class name*
***# URL should have title of type string between length 1 and 50\. After that call your custom check***title = fields.Str(required=True, validate=[validate.Length(min=1, max=50), some_custom_check])...
...**
*****flask _ server _ template/db→*数据库的查询和操作都在这个文件夹里
在我详细介绍之前,我必须澄清几件事:
- 我使用了来自postgresql 教程的 PostgreSQL 教程数据库
- 出于演示目的,这里只有三个相关的表 a .电影 b .演员 c .电影 _ 演员
数据库模式
- 由于不需要用户进行额外的安装就无法发布 postgresql db,所以我在 sqlite 中创建了这 3 个表,并将其与该模板一起发布(在目录 flask _ server _ template/db/dvdrental . db 中)。
- 虽然上面我强调了 postgresql 连接,但是在 Github 上也有 sqlite 连接字符串,有了这个连接字符串,整个模板就可以开箱即用了。(简而言之,如果你从他们的网站上安装了 postgresql 和数据库,你可以使用 postgresql,否则你可以简单地使用 sqlite)。
- 由于大多数数据科学家使用表格,查询返回熊猫数据框。
- 我有两种格式的所有查询 a .使用 SQLAlchemy 核心,即原始 SQL(select * from…)b . SQLAlchemy ORM 将表反映到 python 对象中,并以 python 方式执行查询。这让人们可以根据自己的喜好自由选择。
唷!现在我解释代码文件
db/dvdrental.db
这是包含三个表的 sqlite 数据库
- 电影:存储电影数据,如标题,发行年份,长度,评级等。
- actor:存储 actor 数据,包括名字和姓氏。
- film_actor:存储电影和演员之间的关系。
*****### db/dvdrental.db ###***To use the template no changes are needed in this file.****
数据库/数据库 _ 扩展. py
模块“db_extensions.py”具有数据库连接对象、数据库元数据、包含数据库反射(即数据库表到 python 对象的转换)的对象以及初始化对象关系映射的代码。
*****### db/db_extensions.py ###***To use the template no changes are needed in this file.*def orm_init():
...
Base.prepare(db_obj.engine, reflect=True) #IMPORTANT for reflecting database into python objects***
db/query s _ ORM . py
模块“queries_orm.py”包含使用 SQLAlchemy ORM 的查询,即访问数据库的 pythonic 方式。
*****### db/queries_orm.py ###**def get_film_info(title):
film_orm = Base.classes.film ***#TODO****: refer to correct table*
qry = db_obj.session.query(film_orm).\
filter(film_orm.title == title) ***#TODO****: your query*
film_df = pd.read_sql(qry.statement, db_obj.session.bind)
return film_df***#TODO****: Another sample query below with multiple joins and filter*
def get_film_actors(title):
film_orm = Base.classes.film
actor_orm = Base.classes.actor
film_actor_orm = Base.classes.film_actor
qry = db_obj.session.query(actor_orm).\
join(film_actor_orm,film_orm).\
filter(film_orm.title == title)
actor_df = pd.read_sql(qry.statement, db_obj.session.bind)
return actor_df***
db/queries_rawsql.py
模块“queries_rawsql.py”包含原始 sql 查询。
免责声明:在 queries_rawsql.py 中有示例参数化查询(where 子句带有参数)。但是,这种格式不适用于 sqlite。它在 postgresql 和 oracle 上都能很好地工作。
*****### db/queries_rawsql.py ###**def get_all_films():
query = **'''
SELECT * FROM film
''' *#TODO****: your query* film_df = pd.read_sql(query, db_obj.session.bind)
return film_dfdef get_film_actors(title):
query = **'''
SELECT a.first_name, a.last_name FROM actor a
INNER JOIN film_actor fa on fa.actor_id = a.actor_id
INNER JOIN film f on f.film_id = fa.film_id
WHERE f.title = %(title)s
''' *#TODO****: your query* actor_df = pd.read_sql(sql=query, params={**'title'**: title}, con=db_obj.session.bind)
return actor_df***
安装和运行
我认为快速启动并运行的最好方法是执行以下步骤
- 克隆存储库
- 创建虚拟环境
- 激活虚拟环境
- 在需求文本中安装库
- 运行服务器
*****### Terminal ###**$mkdir base
$cd base
$git clone [https://github.com/alsm6169/flask_server_template.git](https://github.com/alsm6169/flask_server_template.git)
$cd flask_server_template/
$conda create --name ptest
$conda activate ptest
$conda install --file requirements.txt
$python main.py***
- 在另一个 shell 中运行测试文件。或者可选地,
- 打开浏览器运行请求
*****### Browser ###**http://127.0.0.1:5000*http://127.0.0.1:5000/module/v01/functions/film_list_orm**http://127.0.0.1:5000/module/v01/functions/film_actors_orm?title=Alaska Phantom****
这就把我带到了这篇文章的结尾。希望你会发现它很容易理解和使用。如果您有任何反馈/改进,请告诉我。
使用 Python 从 Springer 下载所有免费教材
一个重要的 PYTHON 技巧
使用 Python 下载多个文件的分步指南
插图作者:金彩云
所有数据科学家和研究人员的好消息🎉🎉斯普林格宣布在新冠肺炎封锁期间提供数百本价值数千美元的昂贵科技书籍供免费下载。超过 500 本教科书可供选择!
如果你只对其中的一些书感兴趣,你可以一本书一本书地下载。但是这种机会不会经常出现,那把他们都弄到手呢?😊自己手动下载会很无聊。为什么不让 Python 来做这个工作呢?🤔根据这个帖子,这些春季教材只能买到七月底。根据疫情的情况,黄金时间可能会延长…
这篇文章将通过一步一步的指导向你展示如何使用 Python 从列表中自动下载所有的 Springer 教材。所以,如果你是编程或 Python 的新手,不用担心。
证明:
从 Springer 下载教材的简单 Python 脚本(使用 VSCode 运行)
Python 脚本的示例输出
如你所见,只有 11 行 Python 脚本可以在几分钟内为你下载所有这些教材。在你读完这篇文章之后,你将能够自己完成这个过程,并且将来也能够应用这个技术来下载任何项目或文件的列表。✌
为什么斯普林格现在给我们免费访问?
冠状病毒的爆发对教育产生了前所未有的影响,给学者和他们的学生带来了特别的压力。在诸多不确定性和快速变化的信息中,我们知道许多教育工作者正在努力向虚拟课堂环境过渡,寻找与学生在线互动的方法,并确保他们拥有继续学业所需的资源。为了缓解学术界目前面临的巨大压力, Springer Nature 制作了一套 所有学科的基本教材,免费提供 以帮助支持世界各地的学生和教师。[1]
斯普林格自然图书公司董事总经理尼尔斯·彼得·托马斯说:“随着危机的全球影响加剧,远程访问教育资源变得至关重要。在这个充满挑战的时期,我们希望为讲师、教师和学生提供支持,并希望这一举措(将有 500 多本关键教科书在网上免费提供)能够有所帮助。”[2]
我们开始吧
现在,让我们看看如何使用 Python 来完成这项工作!
首先,让我们准备好你的 python 的所有需求。如果你的电脑里还没有 Python,你可以在官方网站这里下载。
请打开命令行并使用以下命令,使用pip
准备 Python 库:
**$ pip install pandas
$ pip install wget
$ pip install requests
$ pip install xlrd**
安装完成后,创建一个项目文件夹,从 Springer(Free+English+textbooks . xlsx)这里下载可用免费教材的 excel 列表。
从这里获取免费英语教材标题表。
链接 URL 可能会随着时间的推移而改变,您可以在此页面找到此 excel 表格的更新版本,并点击链接“免费英语教科书标题”,如下图所示。
然后,创建一个 Python 文件download_textbooks.py
,并在项目文件夹中准备名为download
的文件夹。在我们的项目文件夹中会是这样的:
项目文件夹示例
然后,使用您喜欢的编辑器编辑download_textbook.py
,添加以下代码行以导入 Python 模块并将 Springer 教科书 excel 加载到pandas dataframe
中。让我们使用df.head(10)
命令来检查数据帧的前 10 行。
**import requests
import wget
import pandas as pd**
**df = pd.read_excel("Free+English+textbooks.xlsx")
print(df.head(10))**
斯普林格公司教科书清单数据框
在这个数据框架中,我们目前需要的主要列是用于形成文件名的“书名和“版本”,以及用于获得下载链接的“ OpenURL ”。所以我们现在的计划是使用for loop
遍历 excel 列表的每一行。
我们应该为每个循环做什么:
- 通过“书名”和“版本”列为每本书创建一个
filename
变量。请注意,我们可以使用任意混合的列来生成文件名。 - 使用
wget
命令下载一本书,并用filename
变量命名。
所以我们可以将这个计划转换成 Python 脚本:
**for index, row in df.iterrows():
file_name = f"{row.loc['Book Title']}_{row.loc['Edition']}"
url = f"{row.loc['OpenURL']}"
wget.download(download_url, f"./download/{file_name}.pdf")**
看起来不错,对吧?然而,这种方法是行不通的,因为“OpenURL”列并不直接代表下载 PDF 文件的最终 URL。因此,我们需要将这个 OpenURL 更改为正确的端点 URL。
例如,如果我们在网络浏览器的“OpenURL”栏中打开一本教科书的链接:
**1.**[**http://link.springer.com/openurl?genre=book&isbn=978-0-306-48048-5**](http://link.springer.com/openurl?genre=book&isbn=978-0-306-48048-5)
哦,它被重定向了!🤨它会自动重定向到
**2.**[**https://link.springer.com/book/10.1007%2Fb100747**](https://link.springer.com/book/10.1007%2Fb100747)
然后,如果我们单击网站中的下载 PDF 按钮,真正的端点 PDF 文件将是:
**3.**[**https://link.springer.com/content/pdf/10.1007%2F0-387-36274-6.pdf**](https://link.springer.com/content/pdf/10.1007%2F0-387-36274-6.pdf)
这意味着我们应该从 1。敬 3。每个循环的第一个!因此,我们在for loop
中应该做的额外步骤是
- 从“OpenURL”列打开链接。
- 获得重定向的 URL:我发现最简单的方法是使用
request
模块。 - 将 URL 字符串的结构重新格式化为下载 PDF 文件的端点 URL。我们可以用
str.replace(old,new)
来做。 - 按计划用
wget
下载一本书。
然后,整个 Python 代码将如下所示:
download_textbooks.py
在用python download_textbooks.py
运行 Python 脚本后,您会在download
文件夹中获得所有的教科书。
下载的施普林格教材
所以,大概就是这样。我希望你喜欢这篇文章,并且能够在将来应用这个想法来自动化你的一些工作流程。请注意,使用 Python 有几种方法可以做到这一点,因为几个模块可以完成这项工作。如果您有任何问题、意见或建议,请随时与我分享。
安全健康健康**!**
感谢您的阅读。👋😄
参考
[1]露西·弗里希,以下是在冠状病毒封锁期间如何免费获取教科书的方法(2020 年 4 月 16 日),斯普林格自然杂志
[2] Felicitas Behrendt,施普林格自然集团,施普林格自然向受冠状病毒封锁影响的教育工作者、学生和学者免费提供关键教科书 (2020 年),施普林格自然
下载并分析您的 Facebook Messenger 数据
其他社交媒体应用程序如何影响您在 Facebook Messenger 上的使用?你和谁聊得最多?
蒂姆·班尼特在 Unsplash拍摄的照片
拥有超过 20 亿用户的脸书是当今最受欢迎的平台。大多数 facebook 用户使用 Facebook Messenger 应用程序相互交流,包括我。我真的很好奇我在这个平台上的行为,以及 Instagram、微信和 SnapChat 等其他社交媒体应用的兴起如何影响我在脸书的使用。
今天,我将向你展示如何下载你的脸书信息数据,以及如何分析它。
下载您的脸书数据
- 打开你的脸书,进入设置&隐私 > 设置
- 前往您的脸书信息 > 下载您的信息
- 选择数据范围“我的所有数据”、格式“ JSON ”和媒体质量“高”(随意更改媒体质量,因为高媒体质量会消耗更多存储空间)
- 仅选择消息*(在这种情况下,我只对我的消息数据感兴趣,您也可以尝试其他数据)*
- 点击创建文件
脸书将在他们的服务器上创建一个 zip 文件,并在文件可以下载时通知您。我花了一天时间才拿到压缩文件。
预处理您的脸书消息数据
在进行任何分析之前,我们要做的第一件事是预处理数据。这些是我们解压缩下载文件后,邮件数据中的文件夹。
邮件数据中的文件夹
我们只对收件箱感兴趣。
Folder Structure of Inbox:
📂 inbox
┣ 📂 alex
┃ ┗ 📜 message_1.json
┃ ┗ 📂 photos
┗ 📂 brian
┗ 📜 message_1.json
┗ 📜 message_2.json
┗ 📜 message_3.json
┗ 📂 photos
这是收件箱中的常规文件夹结构。如果你和某人有很多文本消息,你可能有多个消息 JSON 文件。
现在,我们必须编写一个 Python 脚本来提取所有这些 JSON 文件中我们需要的信息。
我将遍历收件箱中的所有子文件夹,读取文件名以“message”开头的所有 JSON 文件。
folders.remove(".DS_Store")
此处用于删除 macOS 中的系统文件。这是为了防止以后循环中的错误。 (Windows 用户可以忽略这个)
datetime.fromtimestamp(message[“timestamp_ms”] / 1000).strftime(“%Y-%m-%d %H:%M:%S”)
在这里用于将时间戳转换成人类可读的东西。我还把它转换成字符串,这样我就可以毫无问题地把它写入输出文件。
这是您将通过上面的 Python 脚本获得的示例输出文件。现在你可以用任何可视化工具分析你的脸书信息数据。
output.csv
"2016-03-20 13:48:46",Brian,Okay
"2016-03-20 13:48:10",June,See you
"2016-03-20 13:48:01",Matthew,We are at ....
分析我的脸书消息行为
我的 Facebook Messenger 活动趋势
- Messenger 与脸书应用的分离确实增加了我在 Facebook Messenger 上的使用。起初,我真的很讨厌它,因为它迫使我使用 2 个不同的应用程序。但我发现它实际上减少了我被脸书分散的注意力,使我能够专注于发信息(发信息时不再不停地滚动脸书!).
- 有一段时间我迷上了 SnapChat,因为它花哨的面部过滤器和 24 小时故事功能。使用率的下降是由 SnapChat 开始的,但这不是持续下降的主要原因,因为 Instagram 也引入了 Stories 功能!
- 当 Instagram 开始引入 DM(直接消息)功能时,它没有成功吸引我,因为它没有我正在寻找的功能,如通话、特殊交互(贴纸、gif 等)。当 Instagram 也发布 Stories 功能时,它立即将我引入了该平台,因为我已经有很多朋友在使用 Instagram(我相信这也是 Instagram 能够战胜 SnapChat 的主要原因之一,Instagram 与 SnapChat 相比已经拥有庞大的用户群)。
- 2017 年后,my 被多元化为微信、WhatsApp、Telegram 等更多 App。这导致自 2017 年以来使用率持续下降。
除了这种分析,我们还可以进行一些分析,如
- 工作日与周末的使用情况
- 白天和晚上的使用情况
- 你最常用的短语/单词是什么?
现在你已经学会了如何下载你的脸书信息数据并分析它。希望这篇文章对你有用。如果我犯了任何错误或错别字,请给我留言。
可以在我的 Github 中查看完整的脚本。干杯!
如果你喜欢读这篇文章,你可能也会喜欢这些:
使用命令行参数创建自己的 Python 脚本的简单指南
towardsdatascience.com](/how-to-master-python-command-line-arguments-5d5ad4bcf985) [## 如何用 Python 设计你的数据框架
如何使用 Python 高亮显示、格式化或着色您的数据框
towardsdatascience.com](/how-to-style-your-dataframe-with-python-eabf376d1efd)
你可以在 Medium 上找到我其他作品的链接,关注我这里的。感谢阅读!
如何下载和解析 TREC-柯维德数据
你改进 cord19 搜索应用的第一步。
这是一系列博客文章中的第一篇,将向您展示如何改进文本搜索应用程序,从下载数据到微调 BERT 模型。
您也可以从 Google Colab 运行这里包含的步骤。
vespa.ai 背后的团队已经构建并开源了一个 CORD-19 搜索引擎。得益于先进的 Vespa 功能,如近似最近邻搜索和转换器支持 ONNX ,它采用了目前可用的最先进的 NLP 搜索方法。
我们的第一步是下载相关性判断,以便能够评估应用程序中部署的当前查询模型,并训练更好的模型来替换已经存在的模型。
下载数据
本节使用的文件可以在https://ir.nist.gov/covidSubmit/data.html.找到。我们将下载主题和相关性判断数据。不要担心它们是什么,我们很快就会探索它们。
!wget https://ir.nist.gov/covidSubmit/data/topics-rnd5.xml
!wget [https://ir.nist.gov/covidSubmit/data/qrels-covid_d5_j0.5-5.txt](https://ir.nist.gov/covidSubmit/data/qrels-covid_d5_j0.5-5.txt)
解析数据
主题
主题文件是 XML 格式的。我们可以解析它并存储在一个名为topics
的字典中。我们希望从每个主题中提取一个query
、一个question
和一个narrative
。
import xml.etree.ElementTree as ET
topics = {}
root = ET.parse("topics-rnd5.xml").getroot()
for topic in root.findall("topic"):
topic_number = topic.attrib["number"]
topics[topic_number] = {}
for query in topic.findall("query"):
topics[topic_number]["query"] = query.text
for question in topic.findall("question"):
topics[topic_number]["question"] = question.text
for narrative in topic.findall("narrative"):
topics[topic_number]["narrative"] = narrative.text
总共有 50 个话题。例如,我们可以看到下面的第一个主题:
topics["1"]{'query': 'coronavirus origin',
'question': 'what is the origin of COVID-19',
'narrative': "seeking range of information about the SARS-CoV-2 virus's origin, including its evolution, animal source, and first transmission into humans"}
每个主题都有许多相关的相关性判断。
相关性判断
我们可以将相关性判断数据直接加载到熊猫DataFrame
中。
import pandas as pd
relevance_data = pd.read_csv("qrels-covid_d5_j0.5-5.txt", sep=" ", header=None)
relevance_data.columns = ["topic_id", "round_id", "cord_uid", "relevancy"]
相关性数据包含在 5 轮比赛中做出的所有相关性判断。relevancy
等于 0 不相关,1 相关,2 高度相关。
relevance_data.head()
我们将删除关联度等于-1 的两行,我假设这是一个错误。
relevance_data[relevance_data.relevancy == -1]
relevance_data = relevance_data[relevance_data.relevancy >= 0]
下面的图表显示,每个主题有相当多的相关性判断,相关文档的数量在不同的主题之间变化很大。
import plotly.express as px
fig = px.histogram(relevance_data, x="topic_id", color = "relevancy")
fig.show()
接下来我们将讨论如何利用这些数据来评估和改进 cord19 搜索应用程序。
自动从 Microsoft Exchange Web 服务下载电子邮件附件
用 Python 自动化枯燥的程序
学习使用 Python 库 Exchangelib 处理电子邮件附件
Webaroo.com.au在 Unsplash 上拍照
介绍
您需要定期下载电子邮件附件吗?你想让这个无聊的过程自动化吗?我知道那种感觉,兄弟。刚来工作的时候,我被分配了一个日常任务:每天从发给我们团队的邮件里下载附呈的报告。这不是一个困难的任务,但它非常无聊,我经常忘记这样做。
我怎样才能摆脱这个虚拟任务:定期下载电子邮件附件。
在研究了互联网之后,我发现一个小小的 Python 脚本可以接管我的工作。让我们来探索一下 Python 能帮到我们什么。
Exchangelib
Exchangelib 是一个 Python 库,它提供了一个简单的接口,允许 Python 脚本与 Microsoft Exchange 或 Exchange Web 服务(EWS)进行交互
该模块提供了一个性能良好、行为良好、独立于平台的简单接口,用于通信…
github.com](https://github.com/nylas/exchangelib)
您可以从 PyPI 安装这个包:
pip install exchangelib
然后按照官方网站的说明导入包。你可能不会全部用到,
#import pytzfrom exchangelib import DELEGATE, IMPERSONATION, Account, Credentials, ServiceAccount, EWSDateTime, EWSTimeZone, Configuration, NTLM, GSSAPI, CalendarItem, Message, Mailbox, Attendee, Q, ExtendedProperty, FileAttachment, ItemAttachment, HTMLBody, Build, Version, FolderCollection
下一步是指定您的凭证,即登录用户名和密码
credentials = Credentials([username='john@example.com](mailto:username='john@example.com)', password='topsecret')
邮件服务器配置
当然,您必须配置邮件服务器。Exchangelib 应该能够识别您的电子邮件服务器使用的身份验证类型,但是在我的例子中,它失败了,我将身份验证类型指定为 NTLM。
ews_url = 'mail.example.com'
ews_auth_type = 'NTLM'
primary_smtp_address = 'john@example.com'config = Configuration(service_endpoint=ews_url, credentials=credentials, auth_type=ews_auth_type)# An Account is the account on the Exchange server that you want to connect to.account = Account(
primary_smtp_address=primary_smtp_address,
config=config, autodiscover=False,
access_type=DELEGATE)
从文件夹下载附件
现在您有了一个 Account 对象,您可以在其中导航。它只是遵循你的电子邮件帐户文件夹结构。比如你想对收件箱文件夹进行操作,就用这个简单的语法:account.inbox
。要操作收件箱里面的一个文件夹,只需要像这样放一个反斜杠和单引号:account.inbox / 'some_folder'
。
如果您只想下载一个文件夹中的所有附件,这个短代码会有所帮助。您可能需要os
包来处理本地目录。
some_folder = account.inbox / 'some_folder'for item in some_folder.all():
for attachment in item.attachments:
if isinstance(attachment, FileAttachment):
local_path = os.path.join(local_path, attachment.name)
with open(local_path, 'wb') as f:
f.write(attachment.content)
就是这样!
奖金部分
如果我只想下载我以前没有下载过的文件,我可以进一步做什么?我需要一种机制来检查附件是否存在于本地。
我们的团队使用 FTP 服务器来存储所有附加的报告。因此,在我的 Python 脚本中,首先,我登录到 FTP 服务器并列出所有带有指定前缀的文件。在脚本中添加了一项检查,以确定该文件是否存在于当前文件列表中。
为此,我使用了 ftplib,这是一个 FTP 协议客户端库。
[## ftplib — FTP 协议客户端— Python 3.8.1 文档
源代码:Lib/ftplib.py 这个模块定义了类和一些相关的项。该类实现了客户端…
docs.python.org](https://docs.python.org/3/library/ftplib.html)
以下代码登录到 FTP 服务器(ftp.login()
),导航到目标文件夹(ftp.cwd()
)并列出所有匹配指定前缀(file.startswith()
)的文件(ftp.nlst()
)
from ftplib import FTPftp_server_ip = FTP_SERVER_IP
username = 'username'
password = 'password'
remote_path = 'remote_path'
local_path = 'local_path'with FTP(ftp_server_ip) as ftp:
ftp.login(user=username, passwd=password)
ftp.cwd(remote_path + '/copied data')
filelist = [file for file in ftp.nlst() if file.startswith('YOUR_FILE_PREFIX')]
在本地下载附件后,我将文件上传到 FTP 服务器。我用storbinary
向 STOR 发送上传附件的命令。
if attachment.name not in filelist:
# Check if the attachment downloaded before
local_path = os.path.join(local_path, attachment.name)
with open(local_path, 'wb') as f:
f.write(attachment.content)with FTP(ftp_server_ip) as ftp:
ftp.login(user=username, passwd=password)
ftp.cwd(remote_path)
file = open(local_path, 'rb')
ftp.storbinary('STOR {}'.format(attachment.name), file)
file.close()
结论
我使用一个简单的 Python 脚本自动完成了这个日常工作,该脚本可以定期运行。该脚本自动化了从邮件服务器下载丢失的附件并将它们上传到 FTP 服务器的工作流。