接下来去哪里旅游?兴趣点推荐系统构建指南
在的上一篇文章中,我写了如何制作你自己的电影和书籍推荐系统。在下文中,我将一步一步地描述如何构建一个推荐系统,该系统基于用户偏好、地理影响和社会影响来建议新的游览地点。
推荐方法在文章 iGSLR:个性化地理社交位置推荐:一种核密度估计方法】中介绍,张和周,SIGSPATIAL’13。
我将使用 Surprise Library 一步一步地介绍他们方法的实现。
加载数据集和预处理
我使用的数据集是从社交媒体 Gowalla 收集的。它由 2,724,891 个兴趣点中的 407,533 个用户的 36,001,959 次签到组成。
它包括用户签到信息、用户朋友信息、位置信息和用户信息的数据集。
为了减少计算时间,我只选择了拥有 5 次以上 50 次以下签到的用户,但是你当然可以处理所有的数据。
最终的训练数据集应包含所有兴趣点信息和用户信息,没有冗余信息,为此:
- 我使用地点 id 连接了签到数据框和位置数据框
2.我从获得的数据帧 df_checkins_location 中计算了被访问位置的频率,以去除冗余的行
3.我连接了测向频率和测向位置,以获得最终的训练数据集
然后,整个数据集被意外加载
这篇文章的作者设计了一个推荐系统,利用社会和地理影响来表达用户的偏好。
社会影响
作者观察到,用户通常会向朋友寻求书籍、电影或兴趣点的推荐。他们通常更喜欢去朋友们强烈推荐的景点,而不是随便去一个地方。
他们建议使用以下步骤来计算用户的社会影响力:
(1)测量她/他与她/他的每个朋友的相似性。
两个用户之间的社会相似性
- F(u)是用户 u 的朋友的集合
实现
首先,我创建了一个数据框,将每个用户与她/他的朋友联系起来。
数据集中每个用户的朋友列表
(2)在协同过滤公式中使用这种相似性
社交协同过滤评级预测
- r_vi 是用户 v 访问 POI i 的频率
为了获得 r_vi,我们需要使用下面的函数:
使用以下函数计算预测评级的实施情况:
(3)将 POI 的预测转换成概率得分
在哪里
- l 是所有 POI 的列表
位置的地理影响
作者建议利用同一用户访问的每对位置之间的距离。例如,曾经在世界各地旅行的用户希望得到国外的兴趣点的建议,相反,经常访问其生活区域周围的兴趣点的用户希望得到附近兴趣点的建议。
随着距离分布从一个用户到另一个用户的变化,其计算如下:
距离分布估计
在哪里
-
d_ij 是要推荐的 POI 和用户已经访问过的 POI 之间的距离
-
D_u 是用户 u 访问的所有 POI 对的距离列表
-
k(。)是一个普通的核函数
正常核函数
- h 是作为最佳带宽的平滑参数。
最佳带宽
用户访问新 POI 的最终概率计算如下:
用户访问新位置的地理概率(POI)
最终公式
将社会影响和地理影响概率相加,以为用户 u 估计 POI 的相关性分数。
结论
就是这样!这个推荐系统可以帮助你决定你的下一次旅行,以防你认为离 POI 的距离和你朋友的推荐是选择的重要因素。你可以通过 LinkedIn 给我发消息获取完整的代码。请继续关注推荐系统的更多代码。
由吉菲演出
沃尔多在哪?
实践教程
物理世界中的搜索算法
想象你想读(或重读)你的《无限玩笑》。你家里的书架上摆放着成千上万本书。你如何找到那本特别的书?
蛮力
你可以在房子里走来走去,浏览每一个书架上的每一本书,直到你发现无限的笑话。这是可行的,但会相当令人厌倦和费时。这样的策略在计算机科学中被称为蛮力 算法。它确定了解决方案的存在以及最坏的情况是什么。除了放弃暴力策略,别无选择。
这种算法显然很麻烦,但到底有多麻烦呢?在最好的情况下,《无限的玩笑》碰巧在你浏览的前几本书里,你会很快找到它。在最坏的情况下,你只有在看完所有其他的书之后才会碰到它。当你在生活中反复使用蛮力搜索时,你会发现平均来说你必须翻完一半的书才能找到一本特定的书。用计算机科学的说法,这个算法的运行时间是 N ,其中 N 是图书总数。粗略地说,这意味着平均来说,找到一本书需要的时间与书的数量成正比。如果你把书的数量增加一倍,你就要花两倍的时间去找一本具体的。
你怎么能比蛮力搜索做得更好呢?通过整理书籍!在计算机科学中,解决问题的数据组织被称为使用数据结构。
二进位检索
让我们从一个常见且熟悉的组织策略开始:a 按照书名的字母升序排列书籍。
按字母顺序排列的书籍(图片由作者提供)
显然,你将能够比必须检查每一本书更快地找到 Infinite Jest。你知道如何在一个按字母顺序排列的列表中找到一些东西,甚至不用考虑你正在使用的算法。您隐式使用的关键属性是,如果您检查一本书,并且它的标题按字母顺序比您要查找的书大(小),那么您想要的书必须在该书之前(之后)。通过这种方式,您可以利用图书的排序来反复缩小目标图书的范围。
算法到底是什么?它叫做二分搜索法。事情是这样的。你在一套排列好的书中间粗略地检查了一本书,你发现它是莫比·迪克。《无限的玩笑》按字母顺序排在莫比·迪克之前,所以你知道它一定在第一本书和莫比·迪克之间。您刚刚将要搜索的帐套减少了一半。然后,在新范围的中间位置(第一本书和莫比·迪克之间)检查这本书。原来青蛙和蟾蜍是朋友。所以你知道,青蛙和蟾蜍是朋友,莫比·迪克之间肯定是无限的玩笑。你又一次将书籍的范围缩小了一半。继续这样下去,你最终会发现无限的玩笑。
无限玩笑的二分搜索法(图片由作者提供)
二分搜索法比强力全扫描搜索快多少?如果有 N 本书要搜索,在第一次比较之后,要搜索的书的数量减少到 N/2。在下一次比较之后,该集合的大小是 N/4,然后是 N/8,以此类推,直到只剩下一本书:《无限的玩笑》。如果 k 是查找一本书所需的比较次数,那么 2^K = N。换句话说,二分搜索法的运行时间是 log N 。所以如果你把书的数量增加一倍,你只需要做一次额外的比较就可以找到特定的一本。这确实比随着书籍数量线性增长的蛮力运行时间要好得多。
带有二分搜索法的排序数组似乎是一个好的解决方案,但是它有两个严重的问题:
- 对大量的书籍进行分类是很困难的。有一些聪明的排序算法可以帮助你做到这一点,但是有一个事实是无法回避的,那就是你必须进行大量的图书交换才能正确排序。
- 很难在已分类的藏书中添加或删除书籍。例如,如果你买了一本新书,根据书名排序,它属于书架上的特定位置,如果书架上没有空间,你必须将许多/所有的书移到那个位置之后,为它腾出空间。
二叉查找树
这里有一种不同的方式来组织书籍,以解决排序和添加/删除书籍的问题。把书按书架上的顺序放好。在每本书里插入一张索引卡。每个索引卡将包含一些对数据结构进行编码的信息。
索引卡上的第一条信息是书的位置。第一本书的索引卡将把它的位置记为 1,下一本书记为 2,依此类推。
每个索引卡还将包含右子和左子的位置。这个指针的结构定义了一个二叉树。第一本书是二叉树的根。第二本书是根的左边或右边的孩子,这取决于它的标题在字母顺序上是低还是高。诸如此类。右边的子树只包含字母顺序大的标题,左边的子树只包含字母顺序小的标题,这种排序特性使得二叉树成为一个二叉查找树。
要添加新书,从第一本书(根)开始,根据新书的标题是在根的标题之前还是之后,跟踪左边或右边的孩子,沿着树不断重复遍历,最后当要跟踪的孩子不存在时,使新书成为孩子。请注意,为了简单起见,我们在书名中包含了任何主要文章(the,a,an)。下图中的一个示例概括了这一点:
在二叉查找树中添加图书(图片由作者提供)
要查找一本书,从第一本书(根目录)开始,沿着相应的子目录(取决于书名的顺序)直到找到所需的书。以下是如何在我们上面构建的二叉查找树中找到无限玩笑的示例:
在二叉查找树找到无限的玩笑(作者图片)
使用这种二叉搜索树算法查找一本书的运行时间是多少?因为我们沿着树向下遍历,要么选择左边的孩子,要么选择右边的孩子,所以在每一步之后,我们基本上将搜索空间减少了一半,类似于二分搜索法算法。所以,就像前面的结果一样,需要 log N comparisons 才能找到一本书。
我们忽略了几个细节:
- 为了在每次比较后将搜索空间减少一半,树应该是平衡的,即右边和左边的子树应该是大致相同高度的子树。通常,当标题以随机顺序插入树中时,树应该足够平衡。如果做不到这一点,还有算法技术(比如树旋转)来平衡一棵树(但这超出了本文的范围)。
- 要在特定的位置找到孩子,你必须依靠按位置分类的书籍,并使用二分搜索法在指定的位置找到孩子。因此,沿着树向下的每一个 log N 跳本身都需要对索引卡上的位置进行 log N 次比较来找到这本书。这导致运行时间为(log N)。
二叉查找树解决方案是正确的、可行的和有效的。但这是矫枉过正。它引导我们跟踪索引卡中的元数据,以便可以使用搜索树数据结构将书名按排序顺序链接在一起。如果我们真的需要把书按顺序排列,那就好了。但是不需要仅仅为了搜索而排序。有没有更简单的方法至少同样有效?
散列法
如果我们放弃对书籍进行分类的努力(无论是直接分类,还是通过搜索树间接分类),我们确实可以提出一个更简单、更有效的解决方案。它涉及到一种被称为哈希的计算机科学技术。
哈希是什么?你将架子分成数百个更小的桶,并将桶标为 0、1、2、3 等等。通过以可重复的方式从标题计算桶号,将每本书散列到一个桶中。例如,使用手机键盘上的 T9 系统从书名的最后 4 个字母生成一个 4 位数,用 4 位数除以桶数,将余数作为书的桶数。所以,《无限 Jest》对应的是 T9 编号 5378。如果有 101 个存储桶,它散列到存储桶 25(因为 5378 = 25 + 101*53)。
通过将每本书放入它所指向的桶中来组织书籍。假设数千本书大致平均分布在数百个桶中(如果您的哈希方案足够健壮,就会出现这种情况),每个桶应该只包含几十本书。
通过哈希组织图书(作者图片)
你如何发现无限的玩笑?您将标题散列到它的桶中(使用与组织书籍完全相同的散列方案),进入那个桶,从那里的几十本书中挑选出一本书。
通过哈希找到无限的笑话(作者图片)
通过哈希查找一本书有多快?速度极快。它本质上只需要一个步骤,不管书的总数是多少!你所要做的就是计算你要找的书名的哈希值,这就把你的搜索范围缩小到一桶书中的几本书。这就是所谓的常数时间算法。如果你把书的总数增加一倍,你最终会发现每个桶里的书的数量也增加了一倍。但是,如果有足够多的桶,每个桶应该只包含几十本书,所以在恒定的时间内找到特定的书仍然很容易。
对于在一大堆书中寻找一本书来说,散列似乎是一个很好的解决方案。尽管它并不完美。它有一些相对较小的缺点,包括以下几点:
- 假设你的藏书越来越多,书架空间开始不够用了。你买更多的架子。但是现在你的散列方案有了更多的桶,你必须将每本书重新散列到新的桶中。多痛苦啊!如果改变搁置是一个罕见的事件,也许你可以忍受。但如果不是呢,或者你做不到呢?
- 如果您希望存储桶的大小不相等,也就是说,将更多的书散列到更大的存储桶中,将更少的书散列到更小的存储桶中,该怎么办?例如,每个搁板可以是一个桶,不同尺寸的搁板上有不同的书柜。这里介绍的散列算法似乎不能适应不同大小的桶。
这两个问题都可以解决。但这需要使用更复杂的基于哈希的算法,如一致哈希或会合哈希。我将让这篇文章立足于基础,避免讨论这些迷人的技术。如果你有兴趣了解他们,请留下评论,我会写一篇后续文章。
哪些科技工作是 AI 无法替代的?
试图预测即使人工智能变得越来越普遍,仍然以人类为中心的领域
扩展我的先前预测的灵感来自于我最近听到的一句话,“任何可以自动化的都将被自动化”。有了这些明显的金钱激励,组织自动化,百万美元的问题是,技术专业人员应该如何最好地为未来做准备。为了回答这个问题,我们需要深入了解哪些流程可以自动化,这对技术专业人员意味着什么。
什么可以自动化?
机器人流程自动化的领导者 UiPath 概述了五套标准来决定一个流程是否应该自动化。虽然他们的标准侧重于 RPA,但这些概念也适用于可以自动化的其他领域。
标准#1:员工参与
耗时或严重依赖人工。手动操作会导致流程出错。
标准 2:复杂性
在考虑自动化时,复杂性可能是一件好事,也可能是一件坏事。评估复杂性可以基于所涉及的应用程序/系统的数量、人工干预的频率以及完成该过程所需的步骤数量。更复杂的流程可能更希望自动化,但也可能更难以自动化。
标准 3:数量
高容量的活动需要更多考虑自动化,因为它们会带来更高的 ROI。
标准#4:标准化和稳定性
人工智能应用主要集中在狭义人工智能上。因此,自动化要求过程依赖于基于规则的决策,而不需要计算机做出主观选择。在可预见的未来,主观选择是人类的事情。
标准 5:外包的难度
需要更多控制和自主权的流程不能外包。如果准确性和控制是重中之重,内部自动化策略可能是合适的。
摘要
一般来说,自动化非常适合可重复、高容量、耗时、基于规则的流程,并且将证明设置和维护自动化的费用是合理的。
自动化将如何发生?
人工智能一点也不像电影。我们还没有接近这样一个时代,你可以和 Siri 对话,让她即时创建一个“类似优步”的移动应用。人工智能和智能自动化的浪潮将增加计算机与计算机之间的交互数量,而不是人与计算机之间的交互。一个滑稽的例子是谷歌 Android 操作系统的自动来电过滤。当我收到一个烦人的机器人电话时,Android 会为我屏蔽电话并接听。结果是两个软件机器人进行了对话。听起来像是瑞克&莫蒂剧集中的一个笑话。
在商业意义上,这通常以脚本的形式调用应用程序接口(API) 来执行动作。脚本是一组指令,告诉一台计算机联系另一台计算机来执行所需的操作。常见的 API 包括 Twlio 的 SendGrid 和 Okta,前者根据特定规则发送电子邮件,后者在登录 web 应用程序时实现用户身份验证。API 变得如此重要,以至于它们支持着数十亿美元的公司(例如 Twilio、Okta、Stripe)。
谈到数据科学,谷歌发布了机器学习算法,比如他们的图像分类器,可以很容易地集成到软件中。微软有Azure Machine Learning Studio,这是 Azure 中的一个无代码工具,可以构建简单的机器学习模型。
说到无代码工具,这些工具到处都是。如果您想构建一个简单的 web 应用程序,您不再需要成为一名程序员。像 Adobe XD 这样的工具让任何人都可以很容易地为数据产品或 web 应用程序创建快速 MVP。
来源:南方公园推特
哪些工作职责是安全的?
RPA 和 API 将接管大量可重复的流程,这就引出了一个问题,技术专业人员将承担哪些工作职责?在未来 5 到 10 年内,有三种主要的工作职责看起来不会受到自动化的影响。这些预测的一个重要前提是假设我们仍然处于企业向云迁移的早期阶段。
流#1:自动化创建者和支持团队
自动化不是瞬间产生的,也不是免费的。所有自动化都是由大量数据和技术专业人员创建和维护的,不管你是否看到他们*。如前所述,API 优先的公司雇佣了数千名数据和技术专业人员。随着对这些接口的依赖越来越大,我预计对这些职位的需求只会增加。看看 Stripe 的职位空缺,你会看到数百个软件工程师的职位(如后端工程师、fullstack 等。).需要软件工程师来构建、维护开源算法和 API,并将其集成到数据产品或 web 应用程序中。
如果机器人过程自动化起飞,对 RPA 专家的需求将激增。生产一个 UiPath 工作流需要需求收集、开发自动化过程和生产自动化过程方面的专家。UiPath 列出了他们在 UiPath 学院的几条不同的职业道路。几年后,人们可以看到 UiPath 在招聘信息中的应用会像现在的 Tableau 或 PowerBI 一样无处不在。
对于这个群体来说,一个很好的经验法则是,任何头衔中带有“工程师”或“开发人员”的人都更安全,不会受到自动化的威胁,因为他们是构建者。除了建筑工人,你还需要专业人员来支持和促进他们的工作。我们将它们称为使能因素。我们将需要以下的建设者和推动者:
- 建筑商
- 构建和维护支持构建或自动化流程的工具(如 UiPath、API 等)。)
- 将 API 和开源算法集成到 web 应用程序/数据产品中
- 构建、生产 RPA 工作流并为其提供支持
- 使能器
- 自动化需求的需求收集
- 自动化用例的决策者和预算决策
- 自动化开发的项目和产品经理
- 数据质量和数据治理专家确保数据(和自动化触发器)准确可靠
流程#2:不符合自动化标准的流程
并不是每一个过程都符合设置和维护自动化版本的标准。对于数量少、定义模糊、需要主观决策和/或不容易标准化的流程,自动化不值得花费成本。以下是一些难以自动化的工作职责和潜在的职称:
作者图片
流程#3:数字化转型团队
因为我们正处于向云转变的早期阶段,所以可以预期对实现这种数字化转型的专业人员或自动化的需求会很高。数字转换可以分为三层:
- 云基础设施
- 数据工程
- 数据科学
行业向云的转移将需要能够建立云基础设施、支持持续维护并保持其安全性的技术专业人员。这将要求对云专业知识、开发运维以及网络安全的需求水平不断提高。
基础设施之上的下一层是数据工程。随着数据量呈指数级增长,对获取、清理、存储和移动这些数据的专业技能的需求将会持续增长。在保持质量的同时,快速移动大量数据将是组织多年来的一项需求。这方面的职位头衔通常包括数据工程师、分析工程师、BI 工程师、分析经理和数据经理。
一旦你有了值得信赖的数据,你将需要熟练操作、分析、可视化和建模数据的人。如果不全面了解可以从数据和数据之外的得出什么样的见解,你就无法做出数据驱动的决策。
虽然数字化转型团队的工作职责至少在未来五年内仍将是必要的,但人们可以很容易地想象自动化会减少需求。软件很可能会减少在这个流程中执行许多过程所需的人工劳动的总时间。例子包括如下:
- 加速探索性数据分析的软件
- 通过无代码工具(如 H2O、数据机器人)运行 ML 模型
- 人工智能算法使一些数据清理/工程过程自动化(例如,完美)
- 软件可以自动创建数据可视化
- 监控和检测软件可以实现云工程和网络安全的自动化
这个流程的工作职责是(三个中)最容易被自动化替代的。
谁来负责?
在思考未来的时候,考虑工作职责比考虑职称更有益。职称变动频繁,而工作职责更稳定。后者有更多的信号。这类似于在做出长期投资决策时,只关注股票的市场价格,而非其背后的基本面。
五年前,一个称职的数据分析师只需要是 Excel 和/或 SQL 方面的专家。如今,最好的数据分析师应该能够胜任一套技术和方法。这个列表通常包括 Python、R、SQL、Tableau、PowerBI 和机器学习概念。
数据科学家的职位发布终于开始找到一些稳定性。正如我在上一篇文章中提到的,将工作职责分为决策科学家/分析师和软件工程师的趋势仍在继续。
普通的“商业”角色将变得更加技术化。我注意到我的许多没有传统 STEM 背景(或职称)的朋友正在承担更多以数据为中心的责任。由于对理解数据的压倒性需求,典型的“商业”专业人员将被要求学习更多关于软件开发和数据科学的概念和工具。对于商科本科生来说,仅仅胜任基本的 Excel 和描述性统计已经不够了。数据分析、数据科学和信息技术课程变得更加基础。
来源:百事可乐 Linkedin
最后的想法
引导我对未来技术专业人员角色进行预测的两个主要驱动因素是向云的长期转变,以及组织希望通过尽可能自动化来减少劳动力支出。在接下来的十年里,我设想这样一个世界:自动化带来的最安全的工作职责将是那些从这两项技术变革中受益的人。主要受益者将是那些构建和维护自动化的人,那些支持数字化转型的人,以及那些角色需要主观决策的人。将这些流转化为职称,我认为以下技术专业人员的职业道路是自动化最安全的。
- 软件工程师
- 软件销售工程师/其他销售角色
- 技术项目/产品经理
-
在投资界,讨论一家公司是否有护城河是很常见的,护城河是指他们相对于竞争对手保持竞争优势的能力。数据和技术专业人员拥有的最大护城河是他们对继续学习和提高技能的强烈渴望。如果你想避免 AI 取代你,我建议你
让学习成为你生活中的一个常数。
-
数据通才
数据分析职业顾问
*在 IT 群体中有一个流传已久的笑话,即没有人认识或看到 IT 团队。这是因为他们的办公室在地下室。
- *公民开发人员是新一波专业人员的一部分,他们可以在软件的帮助下履行技术职责(例如 RPA 公民开发人员、Alteryx 上的公民数据科学家、不用代码工具构建 MVP 等)。)
你希望提升哪种数据科学技能?
在数据科学和机器学习等快速变化的领域,向你的工具包添加新技能有时可能会让人感到不知所措:你如何选择下一步?你是专注于一些实际的和工作相关的东西,还是通过最新的研究拓展你的视野?你探索一个全新的领域,还是建立在现有的兴趣上?
虽然我们不能为你回答这些问题,但由于我们的作者社区,我们可以提供令人兴奋的、多样的、通常意想不到的选择。以下是我们本周想要强调的几个。
- 了解模型优化不同方法的好处 。 Bradley Stephen Shaw 的实践教程从新的角度涵盖了模型优化这个始终重要的话题。他将使用贝叶斯方法在 LightGBM 模型中调整超参数的结果与他从仔细的特征工程中获得的结果进行了比较,并得出了一个令人惊讶的结论。
安妮·斯普拉特在 Unsplash 上的照片
- 让你的图表更引人注目 **。**我们都已经内化了视觉叙事在数据科学中的重要性,但即使你的图表和图形已经很清晰,也总会有更多东西需要探索。Parul Pandey 向我们展示了如何给可视化注入额外的个性,创建看起来像手绘的 xkcd 风格的图表(而不牺牲可读性)。
- 确保所有利益相关者都能理解你的回复 **。**如果没有人能找到完成给定任务所需的资料,即使是最聪明、最努力的数据团队也会浪费数百个小时。露西·罗斯韦尔前来救援。她介绍了一种快捷的捷径,可以为任何回购建立一个通用的结构,让团队中的同事能够自助获取他们需要的数据和代码。
- 找到更有效的方法掌握 Python 。我们只能第一次学到一样东西一次,但是我们在这个过程中犯的错误对我们自己和他人的成长都是有价值的。 Nicholas 回顾了他早期与 Python 的斗争,并分享了他所学到的经验,以便刚刚起步的数据科学家可能会有比他更顺利的体验。
- 填补你时间序列预测知识的空白 。迟早,大多数数据科学家的任务是获取历史数据,并用它来预测未来的情景。马特·索斯纳对 ARIMA(自回归综合移动平均线)模型的深入研究首先奠定了必要的基础,然后耐心地带领我们了解几种常见的实际应用。
- 从一个整洁的作物测绘项目中获得灵感 。即使你的兴趣不在农业、农作物或劳工问题上,从一个结合了技术知识和创造力来解决复杂问题的端到端项目中,你总能学到很多东西。典型的例子: Madeline Lisaius 在洛克菲勒基金会的工作,利用卫星数据绘制手工收割的作物,以更好地检测产量的变化。
我们希望你本周能抽出时间来学习一些新的东西,或者在你感兴趣的领域扩展你的知识;如果你想教 TDS 社区一些你和擅长的东西,你真的应该——我们很乐意听到你的意见。
直到下一个变量,
TDS 编辑器
我们策划主题的最新内容:
入门
实践教程
- 由 Tirthajyoti Sarkar 用 Python 创建带有异常特征的合成时间序列
- 如何交付 AI 管道作者 Fernando Tadao Ito
- 多项式回归导论作者张希楚
深潜
- 我们可以在线性回归模型上使用随机梯度下降(SGD)吗?由魏毅
- 加速 Python 程序的 7 种令人尴尬的简单方法作者 Joseph Robinson 博士
- 使用 pgfplots 在 LaTeX 中制作经济图表 Arnav Bandekar
思想和理论
在 2021 年,哪些数据科学技能是最重要的?
市场在找什么技能,新的一年该拿什么?
(图片由作者提供)
介绍
对于像数据科学这样不断发展变化的领域来说,很容易理解为什么有时在任何给定的时间很难获得最受欢迎的工具。成为一名数据科学家的一个关键部分是研究并熟悉在任何给定时刻可供您使用的现代技术。你永远不知道什么时候你可能需要一个你以前从未使用过的工具、函数或模块,因此需要首先学会如何使用它。这就是为什么我们大多数人读数据科学!
数据科学学科的最大障碍是它在过去几年中的巨大增长。近年来,数据科学已经从一个相对不太知名的领域变成了未来十年最热门的工作。也就是说,生态系统也在快速发展。这意味着,如果你没有站稳脚跟,很难不被超越。
雇主可能会在数据科学家身上寻找几个关键属性,但最重要的一个是你熟悉的技术。也就是说,熟悉模仿《摩登原始人》中的脚车的技术可能远不如 TensorFlow 这样的东西有价值。
因为这个市场和生态系统在不断发展,所以很难确定雇主实际上希望在自己的解决方案中利用的最新技术到底是什么。幸运的是,由于我们是数据科学家,我们可以继续在互联网上寻找关于这个主题的数据,并找到比我们可能需要知道的更多的关于特定语言、软件包和软件的数据科学技能的最新工作需求。
找到一个完美的“数据科学技术”数据集并不完全可行,所以下面的概述来自我的经验。也就是说,这些也是全面列出的工作要求,对数据科学来说本质上很重要。另一件需要记住的重要事情是,数据科学领域也是一个发展非常迅速的领域。这意味着,尽管这些技术在第一季度、第三季度或第四季度可能非常受欢迎,但它们可能不会再被使用。因此,考虑到这一点,我也想就技术在这方面的地位提供我个人的见解。
受欢迎的技能
有许多行业标准工具是任何有抱负的数据科学家都希望熟悉的。使用这些工具的经验几乎总是作为工作列表的一项要求,因为它们很可能是你将在内部使用的工具。至少,在您有机会体验这些工具之前,熟悉这些工具提供的概念会使它们更容易使用。
计算机编程语言
首先,如果你还不知道 Python,我建议你学习它。尽管在数据分析领域肯定有 R,SAS,甚至 Julia 的工作,但大多数工作将会寻找那些精通 Python 的人。这并不是说没有其他语言是有用的,因为不同用途的工具集合总是最佳的。如果我要建造一个花园,我想用的不仅仅是铲子——尽管做更多的工作,我还是能完成它。
Python 是科学计算的当前行业标准。这是有充分理由的,因为几乎任何事物的 Python 生态系统都是无与伦比的。另一件很棒的事情是 Python 的采用使得它非常容易掌握。对于那些门外汉,我当然会说拿起 Python,因为它会对你有很大帮助!
分析学
至于分析方面,技术通常不会直接列出。然而,这仅仅是因为当涉及到制作具体的可视化时,任何包都是可行的——这取决于您想要做什么。因此记住这一点,最好是获得一组不同的库用于数据可视化。分析过程的另一个重要步骤当然也是统计。
我想说的是,特别是熟悉 Python 的 SciPy 将会对你被录用非常有帮助。在分析方面,雇主正在寻找真正的量化结果。统计测试是执行测试的最简单方法,可以获得真正的定量结果。此外,这些统计技能将发展成为你的机器学习技能。
数据
至于数据,无论使用哪种编程语言,对数据有一个复杂的理解是很重要的。也就是说:虽然大多数语言都有相似的数据类型,但是用你喜欢的语言使用它们很可能会完全不同。掌握如何实际处理观测数据的复杂基础知识,对于清理数据和实际制作有效的管道来说,将会很方便。
也就是说,对于 Python 来说,像 NumPy 和 Pandas 这样的包对于处理数据是绝对必要的。如果您想要处理复杂的观察集并训练大型模型,那么首先非常好地学习如何用您最喜欢的编程语言管理数据可能更为重要。虽然数据科学的一个重要部分是机器学习,但职位名称中不包含机器学习是有原因的。首先,数据科学家处理数据,然后进行科学研究。考虑到这一点,如果没有对数据操作的正确理解,甚至很难建立并运行一个模型。处理数据也是擅长机器学习最重要的一步。
在数据方面,另一件重要的事情是理解数据是如何处理和存储的。在了解了数据湖、库和表之后,您还应该知道如何查询这些数据,并将其放入代码中进行测试。能够用数据进行算术运算是很棒的,但是当你没有数据时,它就变得非常无用。
此外,无论是来自记录的数据、生成的数据还是最常请求的数据,数据聚合算法都很重要。使用 API 并能够以许多非传统的方式检索数据对于任何数据科学家来说都是必不可少的。
机器学习
在机器学习方面,虽然像构建神经网络这样的一些更高级的概念可能很酷,但在许多情况下,使用典型的、更多的黑盒模型可能是最佳的。我认为这意味着一个数据科学家至少应该具备这两方面的知识。虽然我不认为这些技能是有价值的,因为大多数时候它们是建立在其他技能之上的(尤其是在行业中),但大多数工作可能会要求 Python 开发人员至少有类似 Sklearn 的经验。
开发运营
开发运营是一项经常被忽视的数据科学技能。所有的模型都有一个目的,通常这个目的是为了部署那些相应的模型。因此,虚拟环境管理往往会成为您的数据科学团队的重要组成部分。这些至关重要的基本技能可能也有助于编程,但主要是经验将有助于构建更复杂的数据解决方案。
如果你不知道任何一部分是如何组合在一起的,那么使用已经在使用的开发-运营实现可能会很困难。至少,知道如何使用终端和熟悉 CLI 对于许多数据科学来说是绝对必要的。实际上,我在一年前写了一篇关于为什么这如此重要的文章,你可以在这里查看:
在你的生态系统中
很难接触到大量的数据科学家,因为他们经常使用不同的语言。也就是说,对于你的特定语言,如果你还没有的话,可能有一些工具是你想在 2021 年学会的。根据我放在工作列表上的内容,以及我在工作列表上看到的内容,我会说这些是对他们各自的语言来说最重要的学习包。
计算机编程语言
- NumPy
- 数学
- 科学情报
- 熊猫
- 张量流
- Sklearn
- Matplotlib/Seaborn
- Plot.ly
- 克拉斯
- Pytorch
- PySpark
朱莉娅
- 情节
- Makie
- 数据帧
- 牛虻
- MLJ
- 车床
- GLM
- 流量
- Knet
稀有
- 发光的
- ggplot2
- 数据表
- dplyr
- tidyr
- 针织工
C++
- Xtensor
- OpenCV
- 将军
- 张量流
当然,这不是一个学习如何使用的模块列表,而是给出了一个人们可能期望使用的生态系统的概念。例如,Seaborn 和 Matplotlib 有很多相同的功能,所以你可能不需要知道这两者,但知道如何制作统计图表是绝对必要的。
未来
预测像数据科学这样快速变化的领域的未来可能相当困难。然而,我们每天都可以看到技术发展的迹象。对于这个列表中的大多数行业标准工具——tensor flow、Python、Pandas——它们很可能会存在并使用很长时间。我怀疑我们工作的整个生态系统会走向何方,而且肯定不会很快。
也就是说,新的编程语言 Julia 拥有许多有趣的前景,可能暗示着数据科学的未来。需要明确的是,这对 Python 的地位没有任何意义,但对 Python 旁边的其他语言的角色来说可能有意义。
我认为在数据科学的世界里,每天都有很多有趣的事情发生。对于像我这样喜欢不断学习新事物的人来说,这是一件很棒的事情,但它也可能令人担忧,因为为了跟上行业的步伐,很难知道在任何给定的时间点你应该做什么。
2021 年开发者对哪些数据库环境感兴趣?
2021 年开发人员对数据库环境的预期使用分析
2021 年数据库管理系统使用统计的词云—作者图片
介绍
近年来,世界上人工智能在工业和研究中的使用都有所增加。毫无疑问,人工智能日益增长的相关性导致了对不同人工智能应用领域专家的需求。这些专家需求领域包括软件开发人员、机器学习工程师、数据科学家和数据库管理员。此外,上述专业领域的工作需要计算机编程、数据库管理系统、统计学和矩阵代数等领域的技术知识,这是必不可少的。在本文中,我只关注数据库管理系统的使用。更准确地说,我让人们知道了预计在 2021 年将在软件开发者中流行的数据库环境。
在揭示数据库环境将如何流行时,我使用了 2020 年的 Stack Overflow 年度开发者调查数据集。我使用这些数据集的原因是,在过去的十年中,Stack Overflow 年度开发者调查已经成为世界上最大、最值得信赖的专业软件开发人员社区。因此,有必要了解这些软件开发人员对 2021 年软件开发人员中流行的数据库环境的看法。
进行的调查有来自 182 个国家和地区的 64,461 名受访者。调查问题分为以下几个部分:基本信息、教育、工作和职业、技术和技术文化、堆栈溢出使用以及社区和人口统计。调查中提出了 61 个问题。一些问题包括:
你住在哪里?
在过去的一年中,您在哪些协作工具上做了大量的开发工作,在接下来的一年中,您希望在哪些工具上工作?(如果您已经使用了该工具,并希望继续使用,请选中该行中的两个框。)
但是我最感兴趣的问题是
在过去的一年中,您在哪些数据库环境中做了大量的开发工作,接下来的一年您希望在哪些环境中工作?(如果你们都使用过数据库,并且希望继续使用,请勾选该行的两个框。)
按国家和大洲分列的调查对象分布情况
在回答兴趣问题之前,我想了解一下
调查中回答者的分布如何与其国家相对应(分别为。以及这种分布是否很好地代表了这些国家的人口。大洲)?
在第一小节(调查对象在各国的分布情况),我根据调查对象所在的国家介绍了我的调查结果。第二小节(按国家分列的调查对象分布情况)给出了与调查对象所在大洲相对应的调查结果。
按国家分列的调查对象分布情况
在这一小节中,我将对下面的问题提出我的发现。
调查对象的分布如何与其国家相对应?
用来回答这个问题的数据集部分是国家列,询问受访者他们住在哪里?
下图 1 显示了按居住国降序排列的调查受访者的百分比。人们可以看到,美国记录的最高调查受访者人数为 19.46%。接下来的四个国家依次是印度、英国、德国和加拿大,分别为 13.11%、6.08 %、6.07%和 3.42%。
图 1:根据国家的调查受访者数量和百分比(仅显示至少 1%的受访者的国家)—按作者分类的图片
提出了一个后续问题,以了解调查对象的分布如何与其居住国相对应。这是通过了解
答卷人数最多的国家在多大程度上代表了各自国家的人口?
为了回答上述问题,我引入了一个新的量,称为受访者密度,它衡量的是给定各自国家人口后受访者的密度。准确地说,它由下面的公式给出:
图 2:回答者密度公式——作者图片
我使用由 Tanu N Prabhu 提供的 2020 年人口数据集来获得 Stack Overflow 年度调查数据集中所代表的国家的人口。
下面的图 3 显示了我的分析结果。从中可以看出,有趣的是,瑞典、荷兰、以色列、加拿大和英国是受访者密度排名前五的国家。因此,可以说来自这些国家的调查答卷人的数量很好地代表了他们国家的人口。
图 3:调查受访者在受访国家的百分比和受访者密度(仅显示受访者至少占 1%的国家)——按作者分类的图片
另一方面,美国虽然记录了 19.46%的调查受访者,但根据受访者的密度衡量,排名第八位。印度占调查受访者的 13.11%,按受访者密度衡量排在第 16 位。在这两个国家,人们可以假设那里的软件开发人员对调查不感兴趣。也可以说,从这两个国家的结果来看,在本次调查中,没有多少软件开发商能够很好地代表他们各自的国家。虽然这些可能是明智的猜测,但我想知道我得出这个结果的简明原因。或许在进行进一步的研究以获得一个具体的答案,为什么这是一个明显的例子,我将是出路。
调查对象在各大洲的分布情况
在这一小节中,我将呈现我对上一小节中讨论的可能的后续问题的分析结果。即,
哪个洲的受访者人数最多?
我使用了由柴坦尼亚·戈卡莱创建的国家大陆数据集,将调查受访者所在的国家按照各自的大陆进行分组。
调查结果见下图 4。
图 4:各大洲的调查受访者数量和百分比——按作者分类的图片
从上面的图 4 中可以看出,接受调查人数最多的是欧洲大陆,占 38.5%,其次是美洲、亚洲、非洲和大洋洲,分别占 29.08%、25.59%、4.21%和 2.44%。
与上一小节中提出的第二个问题一样,我引入了受访者密度度量,将其限制为调查受访者在各大洲的人口。这里感兴趣的问题如下:
前一个问题的结果在多大程度上代表了调查对象所在的大陆?
从下图 5 可以看出,大洋洲的答卷密度最高。因此,来自该大陆的受访者比来自其他被调查大陆的受访者对调查更感兴趣。
图 5:各大洲的调查受访者百分比和受访者密度——按作者分类的图片
调查受访者对数据库环境的使用情况
在本节中,我将介绍我对以下主要问题的调查结果:
在过去的一年中,您在哪些数据库环境中做了大量的开发工作,接下来的一年您希望在哪些环境中工作?(如果你们都使用过数据库,并且希望继续使用,请勾选该行的两个框。)
在调查数据集中,对于标有 DatabaseWorkedWith 和*databasedesinerextyear 的列,也提出了同样的问题。*调查受访者的回答显示,在全球范围内,有 14 种不同的数据库管理系统(DBMS)受到软件开发人员的欢迎。其中包括:
Cassandra
couch base
DynamoDB
elastic search
Firebase
IBM DB2 Maria db
微软 SQL Server MongoDB
MySQL
Oracle
本节的其余部分分为两个小节。在第一小节(2020 年调查受访者对数据库环境的使用情况)中,我介绍了我对 2020 年之前感兴趣的问题的调查结果,第二小节重点介绍了 2021 年的调查结果。
2020 年受访者对数据库环境的使用情况
在这一节中,我将展示我对标有 *DatabaseWorkedWith 的专栏中感兴趣的问题的发现。*在这一栏中,调查受访者被要求指出他们在 2020 年之前进行了大量开发工作的数据库环境。换句话说,我对下面这个问题感兴趣。
调查对象中最受欢迎的数据库环境是什么?
下面的图 6 显示了截至 2020 年底所有调查对象对各种数据库管理系统的使用情况。
图 6:截至 2020 年底,调查受访者使用数据库环境的百分比—按作者分类的图片
从上面的图 6 中可以看出,受访者在过去一年(即 2020 年底前)进行了大量开发工作的五大流行数据库环境是
MySQL—20.07%
PostgreSQL—13.03% 微软 SQL Server—11.90%
SQLite**—11.24**********
有趣的是,尽管 MongoDB 与其他数据库环境(如 Oracle DBMS )相比,是最近数据库社区的新产物之一,但在调查受访者中,它已经上升到前五名 DBMS。在下一小节中,我将探究一下 2021 年 MongoDB 可能会有多流行。
在下面的图 7 中,我们可以看到这五大数据库管理系统在最具代表性的国家中的排名。
图 7:2020 年排名前五位的国家/地区的数据库管理系统使用百分比——按作者分类的图片
从上面的图 7 可以看出, MySQL 仍然是排名靠前的国家中使用最广泛的数据库环境,除了俄罗斯联邦,在俄罗斯联邦 PostgreSQL 排名第一,其竞争对手 MySQL 排名第二。人们还可以看到,MySQL 在巴基斯坦、印度和意大利被广泛使用。
在所有这些国家,五大数据库管理系统中至少有两个存在竞争。波兰是 MySQL 有竞争对手的唯一国家。它的竞争对手是 PostgreSQL 。在美国、印度、荷兰、澳大利亚和意大利, PostgreSQL 和微软 SQL Server 的使用存在竞争。 MongoDB 在以色列排名第二,在加拿大和法国与 SQLite 竞争。
2021 年受访者对数据库环境的使用情况
最后,我根据调查对象在数据集中标为 DatabaseDesireNextYear 的一栏中给出的答案展示了我的发现。这里有趣的问题是
明年,也就是 2021 年,受访者希望在哪些数据库环境中工作?
下图 8 显示了 2021 年数据库管理系统使用情况的预期排名。
图 8:截至 2021 年底,调查受访者使用数据库环境的百分比—按作者分类的图片
从上面的图 8 可以看出,2021 年最受软件开发人员欢迎的五大数据库环境是:
PostgreSQL—14.30%
MongoDB—12.96% MySQL—12.73%
Redis—9.69%********
将此处看到的 2021 年的结果与上一小节中显示的 2020 年的数据进行比较,可以看出 PostgreSQL 很有可能在 2021 年受到来自世界各地的受访者的欢迎。得出这一结论的原因是,其使用量预计将增长 1.27%。从而以 14.30%的排名从 2020 年的 13.03%的第二名上升至第一名。
接下来是 MongoDB ,令人印象深刻地从 2020 年的第五位上升到 2021 年的第二位,上升幅度为 3.43%。这是一个很好的进步。考虑到 MongoDB在 2020 年和 2021 年之间仅上升了三位,一个可能要探讨的问题是,MongoDB 在未来几年是否会成为全球受访者中最受欢迎的数据库环境。
MySQL 从 2020 年的第一位下降到 2021 年的第三位,降幅为 7.36%。因此,在世界范围内,MySQL 很有可能在 2021 年变得不那么受欢迎。
接下来是 2020 年受访者中排名第六的 Redis 。它以 3.09%的增幅排名第四,预计将于 2021 年在全球范围内受到软件开发商的欢迎。它在 MongoBD 之后排名第二,预计在 2021 年也会大受欢迎。
最后, SQLite 下降了 2.41%,从 2020 年的第四位跌至 2021 年的第五位。调查对象也认为数据库管理系统在世界范围内失去了受欢迎的程度。
从调查结果可以明显看出,在全球范围内, Microsoft SQL Server 很有可能不受调查对象的欢迎。我之所以得出这个结论,是因为微软 SQL Server 以 3.91%的差距从 2020 年的第三位跌落到 2021 年的第七位。
图 9 显示了调查中代表性最强的国家对同一问题的调查结果。
图 9:2021 年排名前五位的国家/地区的数据库管理系统使用百分比——按作者分类的图片
将上面的图 9 与图 7 相比较,我们可以观察到 PostgreSQL 在 2021 年仍然会在俄罗斯流行。对于美国、英国、德国、加拿大、法国、巴西、荷兰、波兰、澳大利亚、瑞典和土耳其,也可以预测 PostgreSQL 的受欢迎程度。也就是说, PostgreSQL 很有可能在 2021 年在这些国家的受访者中流行起来。
在印度、西班牙、巴基斯坦和以色列的受访者中,MongoDB 预计将成为 2021 年最受欢迎的 DBMS。在土耳其、巴西、西班牙和意大利, MongoBD 与 PostgreSQL 竞争。印度和巴基斯坦是个例外,在那里你可以看到 MongoDB 正在与 MySQL 竞争。
有趣的是,意大利是唯一一个预计 MySQL 在 2021 年保持流行的国家。比较 2020 年和 2021 年的 MySQL 和 PostgreSQL 以及 MySQL 和 MongoDB 之间的差异,可以说,在意大利, MySQL 的密切竞争对手,即 PostgreSQL 和 MongoDB 可能会在 2021 年接管。
结论
这项调查的大多数受访者居住在以下国家之一:美国、印度、英国、德国和加拿大。
使用受访者密度测量,我发现来自以下国家的受访者对调查最感兴趣:瑞典、荷兰、以色列、加拿大和英国。也就是说,他们很好地代表了他们的人口。尽管美国和印度有更多的受访者,但其受访者的密度值表明,他们没有像预期的那样很好地代表其人口。
在洲一级,欧洲成为接受调查人数最多的洲。另一方面,根据答复者密度衡量,大洋洲是唯一得到充分代表的大陆。
在全球范围内, MySQL 在 2020 年底之前一直是受访者中最受欢迎的数据库环境。尽管 2020 年有这个记录,但是 PostgreSQL 很有可能在 2021 年超过 MySQL 。此外,人们对 2021 年的 MongoDB 和 Redis 的兴趣预计会上升。这项研究中没有探究产生这种兴趣的原因。尽管如此,了解这个原因还是很有趣的。我的调查结果还显示,预计 2021 年微软 SQL Server 将不再受调查对象的欢迎。
值得注意的是,这项研究的发现是观察性的,而不是彻底的正式研究。然而,它们引出了有趣的面向商业的研究问题,这些问题不仅指向软件开发者,而且指向生产这些数据库管理系统的公司。无论您属于哪一类,是软件开发人员还是数据库管理系统的生产者,问题仍然存在:
你认为什么样的数据库管理系统会在 2021 年流行起来?
关于这些分析和更多的技术细节,请点击这里查看我的 Github 链接。
哪种编码器最适合随机森林精度?浮点数还是序数?
基尼指数随机森林分类器上分类编码器的比较。
(src =https://unsplash.com/photos/50bzI1F6urA
介绍
O 处理分类数据和问题的最常见模型类型之一是随机森林分类器。这是有充分理由的,因为它相对容易使用,不需要太多努力就可以产生一些非常惊人的结果。随机森林分类器使用一种称为基尼指数的统计指标来种植节点,以分析数据和结果之间的某些一致性。
处理这类数据时,需要处理连续的要素是很常见的,但在不是这种情况的情况下,我们需要将分类值转换成某种数字形式,以便计算机可以实际分析它。为此,通常使用编码器。编码器获取典型的文本或分类数据,并将其转换成一种新的形式,有时具有惊人的准确性性能,这取决于用什么模型对什么数据处理什么类别。也就是说,我真的想尝试一下,了解一下哪些不同类型的编码器可以更好地处理基尼指数,以便在我们的随机森林分类模型中获得最高的准确性。
我的预测是,顺序编码器的性能将超过浮点和标签编码器。我之所以估计这个案例,部分是因为我在这个课题上的经验。以我的经验来看,顺序编码对于基于基尼指数的预测非常有效,而在许多其他分类模型中,一种热编码可能是最合适的解决方案。我估计这是因为一个热点将创建更多的特征来作为我们节点的基础,这将把我们的胡萝卜放入几个基于布尔的篮子中,而不是只保留一个集合编码的特征。另一方面,float 编码器只是简单地将字符转换成数字,所以本质上它要做的事情和 ordinal 编码器一样,对每个类别应用唯一的值。我认为序数编码器在这方面仍将领先的原因是,序数编码器不会有可能具有高方差且本质上是任意的高数字,它不会浪费任何连续的空间,使我们的评估者更容易跟踪我们总体中的数字。如果你想了解更多关于这三种编码器的信息,你可以在这里查阅我写的这篇关于这三种编码器的文章,甚至是如何用 Julia 编写它们:
依赖性和数据
对于这个项目,我们将使用模型和编码器的 Lathe.jl 实现。这将有助于降低依赖性,并为我们将要使用的每个工具提供一致的方法。此外,我们将使用 DataFrames.jl 和 CSV.jl 来读入我们要处理的数据。
这个过程的第一步是读入我们的数据。为此,我们将使用 sink 参数和 CSV.read()方法。如果你想了解更多关于水槽的论点,我也有一篇关于它的文章,你可以在这里找到:
我为这个项目选择的数据是 2008 年发生在亚特兰大的犯罪数据集。让我们继续往下读:
using CSV
using DataFrames; df = CSV.read("atlcrime.csv", DataFrame)
现在我们已经有了数据,我删除了缺失的值,然后继续使用我为此项目选择的两个要素创建了一个新的数据框:
df = dropmissing(df)
df = DataFrame(:crime => df[!, :crime], :neighborhood => df[!, :neighborhood])
现在,为了了解我们将在这里处理多少个类别,我将集合类型转换为数组。然后,我打印了这些内容的长度,给出了一些类别,因为我们可能不希望我们的目标有比我们的功能更多的类别:
println(length(Set(df[!, :crime])))
犯罪特写最终有 11 个不同的类别。
println(length(Set(df[!, :neighborhood])))
邻域要素最终有 243 个不同的类别,因此对于我的目标,我最终选择了犯罪要素。现在,我们可以使用 Lathe.preprocess 中的 TrainTestSplit()方法将我们的特征分成两个不同的集合,以便使用以下内容进行训练和测试:
using Lathe.preprocess: TrainTestSplit
train, test = TrainTestSplit(df)
现在,我要让我们的火车和测试 x 和 y 的数据框架,并进入一维数组:
target = :neighborhood
feature = :crime
trainX = train[!, feature]
trainy = train[!, target]
testX = test[!, feature]
testy = test[!, target]
请注意,在 DataFrames.jl 的新版本中,这些调用将返回 PooledDataArray 类型。Lathe 专门处理 Julian 数组类型,而不是抽象数组类型,所以这意味着我们肯定需要改变这一点。当然,我们可以通过简单地将数组类型转换成它们来实现:
trainX = Array(trainX)
浮点/标签编码器
现在我们将使用 Lathe.preprocess 的 FloatEncoder 对这个新数组中的标签进行编码。
using Lathe.preprocess: FloatEncoder
FloatEncoder 是车床内部的一种类型,是编码器类型的子类型。更进一步,我们也可以说这是一个车床预处理器。这意味着我们可以期望从这个调用中返回一个类型,而不是结果编码数组。为了获得数组,我们需要从类型内部调用 predict()函数:
fetX = FloatEncoder().predict(trainX)
现在我们有了我们的特性,我们还需要将数组类型转换到我们的目标上:
trainy = Array(trainy)
最后,我们将使用来自 Lathe.models 的 RandomForestClassifier 类型。与编码器一样,我们将使用新类型调用 predict 方法。当然,我们也想对我们的测试 X 进行编码:
using Lathe.models: RandomForestClassifier
model = RandomForestClassifier(fetX, trainy)feteX = FloatEncoder().predict(Array(testX))
y_hat = model.predict(feteX)
现在,我们可以使用 Lathe.stats 中的 catacc 方法以基于百分比的精度验证该模型:
using Lathe.stats: catacc
catacc(y_hat, testy)
低得可笑(图片由作者提供)
顺序编码器
与 float 编码器一样,这个过程的第一步是初始化编码器,并在我们的数组上调用 predict()函数。唯一的区别是,这一次我们需要提供数组作为参数来创建类型。这将创建查找字典,稍后用于对结果进行编号。
using Lathe.preprocess: OrdinalEncoder
ordenc = OrdinalEncoder(trainX)
oetX = ordenc.predict(trainX)
和以前一样,我们将使用这些数据来拟合 RandomForestClassifier:
model = RandomForestClassifier(oetX, trainy)
然后在使用相同的序号编码器对特征进行编码后调用预测函数:
oeteX = ordenc.predict(testX)
y_hat = model.predict(oeteX)
现在我们将像以前一样使用 Lathe.stats.catacc 验证结果:
catacc(testy, y_hat)
作者图片
结论
虽然我们用顺序编码器得到了基本的精度提升,但这还在误差范围内。也就是说,这不应该是一个巨大的惊喜。这两种编码器做的事情基本相同,但方式不同。我最初的意图是将这些预测与来自一键编码器的结果进行比较,但是在这方面仍然有一些问题需要解决。谢谢你看我的文章!
OpenCV 和 TensorFlow 哪个更适合你的机器学习任务?
其中一个真的比另一个好吗?一位同时使用这两种框架的 ML 工程师的解释。
由作者制作
背景
我每天上网寻找机器学习和计算机视觉的内容。我喜欢了解 ML 领域的最新动态,因为这是一个几乎每天都能给你带来惊喜的领域!
我遇到过几次的一个问题是:
OpenCV 和 Tensorflow 哪个好?
对一些人来说,这不是一个合理的问题。
对其他人来说,这是一个值得思考的问题。
最简单的回答就是 Tensorflow 比 OpenCV 好,OpenCV 比 Tensorflow 好!
希望没有让你困惑!如果我知道,请继续读下去!
事实是,这些框架中的每一个都注定要用于机器学习和计算机视觉的特定领域。所以,直接说一个比一个好,就是没有意义。
但是我们可以说,在某些方面,一个比另一个好,反之亦然。
其实 Tensorflow 是一个机器学习框架,帮助你建立机器学习模型。它更出名的是建立神经网络,这是机器学习中的一种算法和方法,称为深度学习。
因此,Tensorflow 已经发布,以服务于一个主要目的,即建立机器学习模型。在这里,我说机器学习而不仅仅是深度学习,因为已经有一些努力让 Tensorflow 能够训练非深度机器学习模型,如决策森林。
另一方面,OpenCV 是一个计算机视觉框架,可以帮助你对图像和视频进行各种处理。自发布以来,它一直是图像处理任务中广泛使用的工具。它使您能够轻松地操作像素,因此如果您愿意,您可以构建自己的图像和视频处理算法。
随着深度学习的兴起,OpenCV 通过引入一个名为https://docs.opencv.org/4.5.2/d2/d58/tutorial_table_of_content_dnn.html(深度神经网络)的新模块,开始集成更多支持基于深度学习的任务的功能。
这个 DNN 模块旨在使其易于集成已经训练过的深度学习模型。这就是为什么你会在 OpenCV 中找到如何整合深度学习模型的例子:图像分类、图像对象检测和图像分割。
现在,正如你所看到的,所有这些例子都是专注于计算机视觉任务的深度学习模型。
据我所知,没有对语言模型的支持,例如(如 BERT )。
现在,这两个框架在特定情况下可以有一些相似之处。例如,使用 Tensorflow,您可以操作图像,并为训练您的机器学习模型做准备。
OpenCV 也可以用来做一些机器学习的任务。例如,您可以在 OpenCV 中训练 SVM 模型、逻辑回归模型或视觉单词包模型。
何时使用哪个
来源:pexels.com
现在,来看看这两个广泛使用的框架的用例。
如果你正在为一些特定的任务和自定义数据集建立一个新的深度学习模型,那么 Tensorflow 应该是你的选择。
如果你已经完成了为计算机视觉任务训练深度学习模型,特别是:图像分类,物体检测和图像分割,并且你正在寻找部署你的模型,那么 OpenCV 可能是一个不错的选择。
Tensorflow 和 OpenCV 都有 C++和 Python APIs。
在 Tensorflow 中,机器学习工程师使用 Python API 进行训练,他们使用 C++ API 在 C++应用程序/API/SDK 中部署他们的模型。
但是正如我之前提到的,OpenCV 可能 是一个很好甚至更好的部署选择,原因如下。
现在很多公司已经用 OpenCV 很久了。这些公司正在开发计算机视觉产品。他们非常习惯于框架,他们不想在他们的产品代码中添加另一个第三方库(另一个依赖)。在这种情况下,他们可能会选择使用 OpenCV 来部署他们的计算机视觉深度学习模型。
OpenCV 成为生产部署的更好选择的另一个非常重要的方面是 性能 。事实上,对于一些深度学习模型来说,在 OpenCV 中运行它们可以比在 Tensorflow 中运行它们快一个数量级(即使使用 Tensorflow 的 C++ API)。
对于某些行业来说,这可能是一个关键点。
另外,关于这两个框架的 c++ API 的另一件事是 文档 。OpenCV 的文档比 Tensorflow 的 C++ API 的文档要好得多(即使我们这里只是说 DNN 模块)。
使用 OpenCV 而不是 Tensorflow 的最后一点是,使用 OpenCV,您可以用 C++训练 SVM 模型。这意味着在相同的生产代码中,您可以训练一个模型并部署它。
结论
总结一下:
- Tensorflow 在某些用例上优于 OpenCV,OpenCV 在其他一些用例上优于 Tensorflow。
- Tensorflow 的强项在训练方面。如果您将模型作为 C++应用程序/API/SDK 的一部分进行部署,OpenCV 的优势在于部署方面。
- 这两个框架的主要重叠点发生在计算机视觉任务中。
作者制作的图像
我是一名机器学习工程师,致力于解决具有挑战性的计算机视觉问题。我想帮助你学习应用于计算机视觉问题的机器学习。以下是方法。
- **通过帮助您了解该领域的最新动态。我几乎每天都在 、LinkedIn 和 、Twitter**上分享小型博客帖子。那就跟我去吧!
- 每周给你一份我的 时事通讯 上那些琐碎帖子的摘要。所以订阅吧!
- 通过在 Medium 上写关于机器学习不同主题的文章。所以跟我来吧!
- 给你一份免费的机器学习工作清单,帮助你检查你需要学习的所有要点,如果你计划在 ML,特别是在计算机视觉方面的职业生涯。你可以在这里 获得核对表 。
5.最后但同样重要的是,通过与你分享我的 免费入门张量流课程 ,它有超过 4 小时的视频内容,你可以在那里问我任何问题。
此外,如果您有任何问题或者您只是想聊聊 ML,请随时在 LinkedIn 或 Twitter 上联系我!
Python 线程和进程哪个更快?一些有见地的例子
理解大数据
一系列的例子解释了线程和进程的优缺点。用 Dask 代码做你自己的实验。
乔纳森·肯珀在 Unsplash 上的照片
如果你正在阅读这篇文章,你可能已经在试图找出 Python 中线程和进程之间的区别,以及何时应该使用它们。为了解释一些关键差异,我将展示一些示例函数,并分析使用线程和进程运行它们需要多长时间。重要的是,我将讨论为什么线程和进程在每种情况下有不同的计时。
我将使用 Dask 来运行使用线程和进程的示例函数。关于如何用 Dask 做到这一点的更多细节在文章的底部。现在,我将把重点放在线程和进程的区别上。
1。激活 GIL 的功能
让我们从一个简单的函数开始,只是一个 Python for-loop 。它采用一个参数n
,该参数是循环中重复次数的整数。
def basic_python_loop(n):
"""Runs simple native Python loop which is memory light
and involves no data input or output."""
mydict = {}
for i in range(n):
mydict[i%10] = i
return None
这个函数只创建一个 10 个条目的字典,所以使用很少的内存,并且对 CPU 的要求不高。你的计算机实际上会花大部分时间解释 Python 代码,而不是运行它。
下图显示了执行功能basic_python_loop(n=10_000_000)
16 次所需的时间。相比之下,运行这个函数只需要 0.8 秒。
作者图片
在图中,对该函数的 16 次调用中的每一次调用都被分配了一个任务编号 1-16。橙色阴影条显示了每个函数调用开始和结束的时间。例如,左边面板中的task 8
开始计算后开始~5 秒,并一直运行到 5.6 秒。顶部的蓝条显示了完成所有 16 个函数调用所需的全部时间。
图中的三个面板使用简单的循环、多线程和并行处理对函数进行计时。
完整的 16 部分计算使用线程花费的时间与使用循环花费的时间相同。有趣的是,使用线程时,每个单独的任务都要花费更长的时间。这是因为全局解释器锁(GIL) 。在 Python 中,一次只有一个线程可以读取代码。这是 Python 语言的核心特性,但大多数其他编程语言没有这种限制。这意味着你读到的关于多线程的其他文章可能不适用于 Python。
在 Python 中,线程的工作就像一组厨师共享一本食谱。假设他们要准备 3 道菜(3 个线程),有 3 个厨师(你电脑上的 3 个内核)。厨师会从食谱中读出一行,然后去完成它。一旦他们完成了这一步,他们就排队阅读下一步。如果食谱中的步骤很短(就像在一个基本的 Python for-loop 中一样),厨师会很快完成它们,因此会花费大部分时间等待轮到他们阅读食谱。因此,每一份食谱的制作时间都比厨师单独阅读这本书的时间要长。
上面显示的 16 个任务使用 3 个线程运行,这意味着同时处理 3 个函数调用(3 个配方)。由于步骤很简单(就像访问字典一样),线程花费大部分时间等待读取 Python 代码。因此,尽管我们同时运行 3 个函数调用,但每个调用都要花 3 倍的时间来完成。所以这里使用多线程没有任何好处!
在图中,您可以看到在完成所有 16 个任务时,进程比使用循环或多线程快了大约 3 倍。当使用进程运行时,每个单独的任务花费的时间与使用循环运行时一样长。这是因为每个进程都有自己的 GIL,所以进程不会像线程一样互相锁定。
在 Python 中,并行处理就像一个厨师团队,但是每个厨师都有自己的厨房和食谱。
2.从 CSV 加载数据
在这个函数中,我们从一个目录中加载一个随机选择的 CSV。目录中的所有 CSV 大小相同。
def load_csv():
"""Load, but do not return, a CSV file."""
# Choose a random CSV from the directory
file = np.random.choice(glob.glob(f"{temp_dir}/*.csv"))
df = pd.read_csv(file)
return None
作者图片
线程和进程花费的时间差不多,而且都比使用循环要快。在这个函数中,与前一个不同,线程完成的每个任务与循环完成的任务花费的时间相同。但是为什么线程不会因为 GIL 而变慢呢?
在这个函数中,大部分时间花在运行行pd.read_csv(file)
上。这个函数使 Python 运行一大块 C 代码来从文件中加载数据。当运行这个 C 代码时,一个线程释放 Python 解释器,以便其他线程可以读取 Python 代码,并且它在完成加载之前不需要再次读取 Python 代码。这意味着线程不会像上一个例子那样互相锁定。他们并不都在努力一次读懂代码。
NumPy、scipy 和 pandas 中的大多数函数都是用 C 语言编写的,因此它们也会导致线程释放 GIL,避免相互锁定。
在食谱-烹饪的类比中,这就像食谱中有一个步骤说“揉面团 5 分钟”。这个指令读起来很快,但要花很长时间才能完成。
3.使用大量 CPU 的数字函数
下一个函数使用 NumPy 创建一个随机数组,并求它的逆。基本上,这只是一个计算量很大的计算。
def numpy_cpu_heavy_function(n):
"""Runs a CPU intensive calculation, but involves
no data input or output."""
x = np.linalg.inv(np.random.normal(0, 1, (n,n)))
return None
这个函数的时序如下所示,使用n=2000
使得数组的形状为 2000x2000。
作者图片
奇怪的是,无论是使用线程还是进程,我们都没有获得很大的加速。但是为什么呢?在前面的例子中,我们获得了 3 倍的加速,因为所用的计算机有 3 个内核。这是因为 **NumPy 本身使用多线程,使用多核。**这意味着当你试图使用线程或进程并行运行这些 NumPy 函数时,你会受到计算能力的限制。每个内核都试图招募额外的内核来运行其 NumPy 计算。因此,一旦所有内核都以 100%的速度运行,就没有办法从它们那里获得更多的计算能力。
4.具有大量输入或输出的功能
到目前为止,我们使用的函数要么没有输入参数,要么输入参数只是一个整数。当我们有大量的输入或输出时,进程和线程之间的一个关键区别就显现出来了。
def transfer_data(x):
"""Transfer data into and out of a function."""
return x*2
在上面的函数中,我们将传入一个数组x
,并返回一个 doubled 数组。在下面显示的结果中x
是一个 10,000x1000 大小的数组,内存为 80 MB。
作者图片
在这种情况下,线程完成任务用了 0.36 秒,循环用了 0.51 秒,但是进程用了 14 倍多的时间。这是因为进程都有自己独立的内存池。当我们将数组x
传递到函数中,并使用进程运行它时,x
必须从主 Python 会话复制到每个进程中。这花了大约 3.5 秒。一旦复制了数组,进程可以非常快速地将数组翻倍,但是将翻倍的数组复制回主会话又需要 3.5 秒。与此相反,线程与主 Python 会话共享相同的内存空间,因此不需要再来回复制数组。
在厨师类比中,过程就像三个厨师,每个人都有自己的食谱和自己的厨房。厨房在不同的地方,所以如果我们想让厨师运行一些食谱,我们需要把配料带给他们,然后他们可以烹饪这道菜,我们需要去收集这些菜。有时,使用线程并让它们在同一个厨房烹饪菜肴会更容易,即使这意味着它们必须阅读同一本食谱。
线程与进程——简要总结
让我们总结一下:
- GIL 意味着一次只有一个线程可以读取 Python 代码。这意味着多个线程可能会相互锁定。
- 像在 NumPy、SciPy 和 pandas 函数中一样,使用对 C 代码的外部调用意味着线程在运行这些函数时将释放 GIL。这意味着线程不太需要等待机会来读取代码。
- 每个进程都有自己的内存池。这意味着将大量数据复制进或复制出它们的速度很慢。例如在大型输入数组或数据帧上运行函数时。
- 线程与主 Python 会话共享相同的内存,因此不需要在它们之间来回复制数据。
这些导致了一些加速计算的经验法则。
- 首先,关于数据传输。如果你的函数接收或返回大量数据,使用线程;否则你会浪费太多时间传输数据。然而,问问你自己,你真的需要数据作为参数吗,你能在函数中加载数据吗?如果是这样,那么您仍然可以使用进程。
- 接下来是 Python 循环。如果您的函数必须使用简单的本地 Python 循环,那么使用进程。然而,问问你自己,这些循环可以用 NumPy 数组操作代替吗?如果是这样,您仍然可以使用线程。
- 如果您正在使用计算开销很大的 NumPy/etc 操作,那么您可能不会从使用线程或进程中获得太多好处。
使用线程运行函数,使用 Dask 运行进程
在这篇文章中彻底覆盖 Dask 会让它太长,所以相反,我会覆盖必要的部分,并将 链接到一个笔记本 ,这样这些情节就可以重现了。
如果你感兴趣,我在 DataCamp 上还有一个 Dask 课程 在那里我会用互动视频和练习更全面地介绍 Dask。该课程的第一章是免费的,大约需要 30 分钟,涵盖了下面和笔记本中使用的所有 Dask。
我们可以使用 Dask 来运行使用线程或进程的计算。首先,我们导入 Dask,并使用dask.delayed
函数创建一个延迟评估结果的列表。
import daskn = 10_000_000lazy_results= []
for i in range(16):
lazy_results.append(dask.delayed(basic_python_loop)(n))
请注意,函数basic_python_loop
实际上还没有运行,因为它是延迟求值的。相反,只存储了运行它的指令。
我们可以使用多线程来运行计算,例如:
results = dask.compute(lazy_results, scheduler='threads')
或者可以使用多重处理来运行计算,例如:
results = dask.compute(lazy_results, scheduler='processes')
这些是最简单的方法,但是在本文的实验中,我希望对使用的线程和进程的数量有更多的控制。为此,您可以创建一个客户机,它设置了一个进程和/或线程池,您可以用它来完成计算。
例如,要创建和使用 3 个进程的池,可以使用:
process_client = Client(
processes=True,
n_workers=3,
threads_per_worker=1
)results = process_client.compute(lazy_results)
一些类似的故事和进一步的阅读
我从 Brendan Fortuner 几年前的文章中获得了很多灵感。事实上,我在这里所做的很多都是重现他的例子,但我想比他写的原始文章更深入一点。
https://medium.com/@bfortuner/python-multithreading-vs-multiprocessing-73072ce5600b
如果你在代码中大量使用原生 Python 循环,那么你绝对应该使用 Numba 。它可以将这些循环加速到接近 c 的速度。最好的是,如果你正确使用 Numba(见笔记本)你可以设置它,这样你的循环函数就不会锁定 GIL。这意味着你可以使用你的 Numba 循环函数,它已经快得多了,并与多线程并行运行。
最后,我们在本文中得出的使用线程和进程的经验法则与这里描述的 Dask 最佳实践非常相似。
哪些 NBA 新秀会成为全明星?
使用随机森林模型来预测哪些新秀有一天会进入全明星队
在 2010/11 NBA 赛季中,有两名球员打出了同样稳定但不起眼的新秀赛季。埃文·特纳,2010 年 NBA 选秀的第二顺位球员,在每场 23 分钟的比赛中得到 7.2 分。与此同时,在同一选秀中第 10 顺位的保罗·乔治,每场比赛 21 分钟,得到 7.8 分。然而,从那时起,他们的职业生涯走上了截然不同的道路。保罗·乔治参加了 7 场(还在继续)全明星赛,同时成为 NBA 最危险的双向球员之一。虽然特纳在 NBA 又打了 9 年,但他大部分时间都是作为一名平庸的替补球员度过的。
我打算回答的问题很简单:我能建立一个统计模型,把这两个球员和他们的新秀赛季区分开来吗?
数据和代码
数据取自篮球参考。从“三分时代”(1979/80 赛季起)开始,我总共训练了 1300 个新秀赛季的模型。赛季至少有 30 场比赛,每场比赛 7 分钟。我使用的最后一个新秀赛季是 2010/11 赛季,因为从那时起出道的新秀可能仍然有机会成为全明星,如果他们还没有成为全明星的话。在这 1300 名球员中,有 197 人最终在职业生涯中至少入选了一支全明星队。
数据和代码可在 my GitHub 上获得。我使用 randomForest 和 ROCR 软件包在 R 中执行所有分析。
模型
我将使用随机森林分类器。随机森林是一种灵活的学习方法,它使用许多决策树来对观察值进行分类。每个决策树包含随机选择的 mₜᵣᵧ预测特征。决策树的模式结论成为模型的分类。
总的来说,该模型被训练有 13 个特征:
- 每场比赛的时间
- 每场比赛得分
- 场均进攻篮板
- 场均防守篮板
- 每场比赛的块数
- 每场抢断
- 场均助攻数
- 有效投篮命中率(根据相应赛季的平均水平进行标准化)
- 罚球命中率
- 年龄
- 进攻方加减(OBPM)
- 防守方加减(DBPM)
- 使用率
- 周转率
拟合和调整模型
在最初用 750 个决策树拟合模型之后,可以对其进行一些调整以提高模型性能。我要优化的超参数是 mₜᵣᵧ,即每棵树的特征数量。我将 mₜᵣᵧ设置为最小化袋外(OOB)误差。正如你在下面看到的,4 是我的数据的神奇数字。
既然模型适合 mₜᵣᵧ=4,让我们来看看结果。
该模型的 OOB 估计误差率为 12.54%。简而言之,我预计这个模型有 12.54%的时间猜错。
我们还可以查看随着树数量的增加,误差如何变化:
起初,增加树的数量减少了 OOB 误差。然而,它很快稳定在略高于 12%的水平。750 棵树足以最大限度地发挥这种模式的潜力。
该混淆矩阵显示了该模型如何根据真实结果对玩家进行分类:
毫不奇怪,这个模型的猜测有相当大的误差。在真实世界的全明星中,模型有三分之二的时间会错过他们。
下面的图表显示了每个特征对于分类的重要性。左边的图表显示,如果删除任何一个特征,精度就会下降。右边的图表显示了基尼系数(衡量节点杂质的指标)的下降。在这两个图表中,顶部的特征最重要,而底部的特征最不重要。
最重要的指标是每场比赛的上场时间和得分。防守篮板(DRB)比我想象的要重要得多。令人惊讶的是,有效投篮命中率和罚球命中率都可以从模型中移除,而精确度几乎没有损失。由于这两个变量高度相关,因此任何一个变量的损失对模型的影响都很小。然而,这两个特征的损失使得模型的准确性大大降低。
由于 OBPM 在两个排行榜上都高于 DBPM,这似乎也证实了在全明星赛中进攻比防守更重要。然而,框加减度量可以是对性能的粗略度量。虽然得分等统计数据也可以衡量进攻,但防守价值更难以量化。最近的高级统计在使用更高级的追踪来测量防御方面取得了很大的进步,但是这些统计在这里没有足够大的样本可用。最终,很难说防守是否对全明星赛没有什么影响,或者我们只是没有很好地衡量防守。
评估该模型的一种方法是使用下图所示的受试者工作特征(ROC)曲线。该图显示了在不同的辨别阈值下假阳性率如何变化。在默认函数下(在此模型中使用),阈值为 0.5。虽然这是可以修改的,但我对默认设置很满意。
ROC 曲线下的面积(AUC)可用于查看模型的有用程度。AUC 可以在 0.5 和 1 之间。AUC 为 0.5(曲线遵循上面的灰色虚线)表示该模型根本无法区分所有恒星和非所有恒星。AUC 为 1 表示模型可以完全区分。该模型的 AUC 为 0.818,这是令人尊敬的。
改进模型的一个选择是加入来自高级玩家跟踪技术的统计数据。然而,由于该数据仅从 2013/14 赛季开始收集,因此这还不是训练模型的现实选择。
另一个考虑可以是增加一个特征来说明他们球队的实力,因为与弱的重建队相比,好的前景可能在竞争的球队中发挥得更少。
有趣的数据点
在这篇文章的开始,我想知道一个模型是否能区分埃文·特纳和保罗·乔治的新秀赛季。最终,该模型认为保罗·乔治有 33%的机会成为全明星,埃文·特纳有 7.5%的机会成为全明星。虽然它仍然将两人归类为非全明星球员,但我很满意它能够确定两人是有意义的不同。
在训练样本的球员中,模型给了蒂姆·邓肯最高的赔率——超过 96%的机会成为全明星。这并不奇怪;邓肯在新秀赛季是全明星。这个模型也给了沙奎尔·奥尼尔(94.3%)和加索尔(93.3%)很高的赔率。
最大的假阳性是克拉克·凯洛格,该模型给出了几乎 90%的机会成为全明星。凯洛格在新秀赛季场均得分超过 20 分,但膝伤很快阻碍了他。他的职业生涯在仅仅五个赛季后就结束了,而且他从未超过他新秀赛季的平均得分。在光谱的另一端,该模型给贾森·威廉姆斯和里基·皮尔斯 0%的赔率,但这两名球员继续出现在一个单一的全明星赛。
最后,下面是这个模型如何处理几个年度最佳新人的:
对 2020 年选秀班的预测
最后,我们可以使用模型对未来进行一些预测。如果这个模型负责重新起草 2020 年的职业,它会这样做(排除一些小样本玩家):
虽然该模型没有发现任何全垒打的前景,但它准确地预测了两名全明星球员(泰瑞斯·哈利伯顿和拉梅洛·鲍尔)将从这一组中产生。混乱矩阵的结果表明,很可能还有其他人潜伏在狼群中。
结论
评估前景是篮球运动中最困难的任务之一。那么你能根据新秀赛季预测所有的球星吗?答案是有些。虽然新秀赛季可以给我们一个体面的想法,职业生涯仍然可以采取一些非常不可能的路径。很可能有更多的优秀球员(甚至是全明星球员)潜伏在这个平庸的新秀池中,这个模型还无法区分。
更好的数据可能会有所帮助。2013/14 赛季开始使用的球员跟踪技术为我们提供了比以往任何时候都更详细的 NBA 球员数据。这有可能使我们做出比以前更准确的预测。然而,我们还没有足够大的样本来充分利用这些数据。
哪些 NBA 球队最擅长选秀?
一项数据驱动的分析对每个 NBA 球队的选秀成功进行了排名
注:这里有一个 新仪表板 可以查看数据。这篇文章在 2022 年 6 月 14 日更新了新的数据和数字,以及方法的改进。
选秀是一个成功的 NBA 球队最困难也是最关键的因素之一。从 1998 年到 2019 年,圣安东尼奥马刺队创纪录地连续 22 次季后赛出场,并在此过程中赢得了五个冠军。这种不可思议的运行是由一系列强有力的选秀权推动的,其中许多是在彩票之外。
在光谱的另一端,萨克拉门托国王队现在已经连续 16 个赛季错过了季后赛——这是 NBA 的记录。不出所料,这个分析显示了国王队一贯糟糕的选秀记录。
在这个分析中,我创建了一个衡量标准,通过将他们与之后选中的球员进行比较来对每个选中的球员进行评分(完整的方法在文章结尾提供)。每个球员的分数不仅取决于他们自己的表现,还取决于球队放弃了什么来选择他们。在对过去 12 次 NBA 选秀(从 2009 年到 2020 年)进行分析后,持续选秀的球队与不选秀的球队之间出现了明显的差异。
结果
在被分析的 849 名球员中,尼古拉·约基奇脱颖而出。在被选中之前,乔基奇已经被传了四十多次,在他的前七年里,他已经连续获得了 MVP。另一方面,马文·巴格利的排名比所有其他选秀状元都要差。
总的来说,选秀分数以零为中心——这是一个相当典型的既不差也不好的选秀分数。这些选秀权中有许多是第二轮选秀权,期望值低,相应的价值也低。
五大选秀状元:
正如所料,顶级选秀是中后期选择的一些顶级球员。同样值得注意的是弗雷德·范弗利特(多伦多猛龙),得分 3.7,第 7 高,排名第一的未选秀球员。
另一方面,底部的五个选择主要是没有成功的高选择。
当巴格利还年轻的时候,萨克拉门托放弃了卢卡·东契奇、小贾伦·杰克逊和特雷·杨。选择巴格利的巨大机会成本是他得分低的原因。
詹姆斯·怀斯曼是一个异数——他的 NBA 生涯才开始两年,他就因伤错过了整个第二个赛季。他的排名很低,主要是因为勇士队没有选中拉梅洛·鲍尔(在他的第二个赛季已经是全明星了)。虽然怀斯曼有足够的时间来恢复他的选秀分数,但他的选择已经被设定得很高了。
多伦多猛龙队仍然是 NBA 中遥遥领先的最佳选秀球队,而萨克拉门托国王队和克利夫兰骑士队则排名垫底。
不出所料,圣安东尼奥马刺队排名第二,其他一些长期竞争者也接近榜首。
如果排除未选秀的球员,多伦多仍然是第一,尽管差距较小。
在活跃的总经理中,孟菲斯灰熊队的扎克克雷曼拥有迄今为止最好的选秀记录(尽管迄今为止只有 6 个选秀权)。在样本量较大的人当中,马赛乌吉里(多伦多猛龙)高居榜首。
大多数至少有 5 个选秀权的活跃高管在起草方面至少比平均水平好一点。这可能是因为不擅长起草的高管被解雇了,而更擅长起草的高管却被保留了下来。
包括至少有五个选秀权的非活跃高管,拉里·伯德(印第安纳步行者队)排在克雷曼和乌吉里之后,弗拉德·迪瓦茨和克里斯·格兰特垫底。
方法学
这里有一个完整的仪表盘,你可以自己查看和探索完整的数据集(按团队、球员或负责起草的高管)。
总结
该指标的目标是衡量团队和高管识别人才的能力。
这种方法背后的中心思想相对简单:为了评估选秀选择,球员应该与可供选择的球员进行比较。如果有更好的球员,那么选秀会被认为是糟糕的。如果更好的球员没有可用——或者被选得太早以至于在那个选秀位置没有被现实地考虑——那么选秀选择是一个好的选择。
在那个位置被选中的球员通常表现如何并不重要——事实上,你会发现这种方法有时会将被认为令人失望的球员评为体面的选秀权,因为接下来被选中的球员甚至更差。例如,安德鲁·威金斯实际上得到了一个正的选秀分数,因为克里夫兰避免了选贾巴里·帕克(第二顺位),他比克里夫兰差得多。
因此,每个被选中的球员的表现都要与之后被选中的球员的加权平均值进行比较。距离较近的球员比距离较远的球员被赋予更高的权重,因为他们更有可能被认为是那个位置的替代者。
彩票选择(#1 到#14)也根据选择的“明显”程度而打折扣。如果一名球员是一致同意的第一选择,那么这个选择既不好也不坏,因为任何球队都会做出同样的选择。
球员包括
所有被选中的球员(从第 1 名到第 60 名)都包括在内。未选秀的球员也包括在内,如果他们在符合条件的一年后的第一个赛季就进入了花名册。如果它们是后来签署的,则不包括在内。
一旦两个完整的季节过去,就会增加新的征兵年份。
团队归属
一些调整是围绕哪些球队的选秀权来进行的。虽然一名球员被正式列在了他们被选中的球队名下,但如果他们在选秀之夜或下一个赛季开始前的任何时候被交易,我会把选秀权归于他们被交易到的球队。此后的任何交易都不会影响归属。
未选秀的球员归属于他们签约的第一支球队。
衡量玩家表现
虽然该模型的最后一次迭代使用获胜份额来衡量球员的表现,但现在使用 BBall Index 中的 LEBRON Wins Added (WA)指标来衡量球员的表现。这个指标比传统的高级统计数据更全面,应该能更准确地捕捉 NBA 球员的价值。然而,这一指标只适用于 2009 赛季至今,限制了对 2009 年选秀的分析。
任何低于零的 WA 值都将被替换为零。一个打得很差的球员不应该被认为比一个从来不打比赛的球员更差。
用于比较的加权平均值
为了形成权重,我使用了布朗简单指数平滑模型的稍微修改版本:
其中 V 代表 y 年 d 拔模位置的反事实( C )值( V )。α代表在 d 的平滑因子,它必须在零和一之间。一个高的 alpha 值会将更多的重量分配给靠得更近的玩家,而一个低的 alpha 值会将重量更平均地分配给许多玩家。alpha 乘以玩家在 y 年 d + 1(紧接其后)拍摄的实际值( V )。
但是,alpha 在任何一年内的草稿选择中并不一致(尽管它在不同年份的同一草稿位置中是一致的)。在选秀中,通常只有很少一部分球员可以被选中。在以后的选秀位置上,有大量的球员可以考虑。通过比较实际的选秀位置和 ESPN 对最佳选秀前景的排名可以很容易地看出这一点。在早期选秀位置中,ESPN 排名与实际选秀位置非常接近。到了第二轮,两者之间往往会有巨大的差异。
在统计学中,这种现象被称为异方差,当可变性在值的范围内变化时,就会出现异方差。在这种情况下,在较后的拔模位置可变性增加。
因此,每个拔模位置都有一个唯一的平滑因子。首先,我确定了同一名球员在 2014 年至 2020 年期间每次选秀的实际选秀位置和 ESPN 最佳球员排名之间的绝对差异。在极少数情况下,没有被 ESPN 排名的球员被选中,他们的排名被记录为 101。然后,我找到了每个草稿位置的平均值,并将其回归到实际草稿位置,如下所示:
β系数为 0.317,然后将其输入以下等式,以确定每个吃水位置的α:
这样产生的阿尔法值在以后的选秀位置会下降。与之前的分析版本相比,这种方法为第一轮选秀权提供了相当高的 alpha,但为第二轮选秀权提供了相当低的 alpha。最终的结果是,顶尖选秀权的得分严重依赖于直接被选中的球员的表现,而后面的选秀权的得分则更加平均地与许多球员进行比较。
计算原始选秀分数
alpha 用于计算每个玩家的反事实表现。通过从反事实值中减去实际值,确定每个玩家的净等级。
净评级可以被视为草案选择相对于可能的可用备选方案产生的“超额价值”。虽然该值可以与一年内的其他草案选择进行比较,但不能在年份之间进行比较,因为较旧的草案年份有更多的时间来累积 WA。
为了使选秀分数可以跨选秀年份进行比较,我使用 z 评分法,将每年每个球员的净评分除以该年内净评分的标准偏差来计算原始选秀分数(RDS):
概率得分
最后,彩票选秀权会根据选择的明显程度而“打折扣”。例如,一个一致的第一次整体选秀权(普遍同意该球员应该先去)会被打折扣接近 100%——这意味着无论该球员表现如何,选秀分数都接近于零。不太确定的选秀权(可能有多名球员被选中)会因为积极或消极的结果而受到表扬。
对于分析的这一部分,我欠 Chris Feller 一份感激之情,因为他在这里创造了他的原创分析,这是我的灵感来源,也因为他花时间和我谈论这个项目。
为了估计一个球员在选秀中被选中的概率,我收集了一些专家和作家的选秀板和模拟草稿。
使用 R 中的 PlackettLuce 包,模拟选秀选择符合 Plackett-Luce 排名模型。然后,生成的模型用于为每个草稿创建 10,000 个模拟。
使用模拟,Kaplan-Meier 估计值(一种生存分析的常用方法)用于计算每个彩票选择在他们的实际位置被选中的概率(P ),条件是他们在该点之前没有被选中。
然后,通过条件概率§对 RDS 进行贴现,计算出最终草案得分(FDS):
由于数据限制,这一过程仅针对彩票选择(前 14 名)完成,尽管无论如何对以后的选择影响不大。
所有个人草案分数的平均值构成了每个团队和高管的草案分数。
针对高管的贝叶斯估计
每个团队的高管都来自篮球参考。虽然样本量对于团队来说相对较大,但对于高管个人来说通常很小。所以除了正常的选秀分数,我还计算了每位高管的贝叶斯估计。贝叶斯估计将每个分数向平均草案分数收缩。随着每位高管的选秀权数量的增加,他们的贝叶斯估计越来越接近他们的实际选秀得分。当您感兴趣的高管的样本量非常小时,这种估计非常有用。
贝叶斯估计的计算方法如下:
每位高管(e)的贝叶斯选秀得分(B)的计算方法是,将每位高管的缩水权重(W)乘以他们的正常选秀得分(S ),并将其与所有选秀的平均选秀得分(DS)相加,再乘以 1 减去权重。
每位高管的权重计算如下:
其中,高管选秀得分的方差(在那些至少有八个选择的人中)除以方差加(所有选秀得分的平均值除以该高管的选秀次数)。
(我还要感谢我的女朋友玛丽娜,帮我收集和输入草稿板。这是一个耗时的过程,在她的帮助下变得容易了。)
你的哪些特征是过度拟合的?
提示和技巧
发现“ParShap”:一种高级方法,用于检测哪些列使您的模型在新数据上表现不佳
[图片由作者提供]
W 机器学习中最重要的是对新数据做出正确的预测。
当训练数据上的预测很好,但测试数据上的预测很差时,就说模型“过拟合”。这意味着该模型从训练数据中学习了太多的噪声模式,因此它无法很好地推广到它以前没有见过的数据。
过度拟合该怪谁?换句话说,
哪些特性(数据集的列)会妨碍模型对新数据进行良好的概括?
在本文中,借助真实世界的数据集,我们将看到一种高级方法来回答这个问题。
功能重要性这次救不了你了!
如果你对上述问题的回答是“我会考虑特性的重要性”,那就再努力一点。
要素重要性并没有说明要素在新数据上的表现。
事实上,它只是模型在训练阶段所学内容的代理。如果模型已经学习了许多关于特征“年龄”的模式,那么该特征将在特征重要性中排名较高。这并没有说明这些模式是否正确(所谓“正确”,我指的是一种足够通用的模式,对新数据也适用)。
因此,我们需要一种不同的方法来解决这个问题。
“曾经有一家德国医院…”
为了解释这种方法,我将使用一个包含从 1984 年到 1988 年德国健康注册记录的数据集(该数据集可以从库 Pydataset 访问,使用 MIT 许可证)。
下载数据非常简单:
import pydatasetX = pydataset.data('rwm5yr')
y = (X['hospvis'] > 1).astype(int)
X = X.drop('hospvis', axis = 1)
该数据集由 19,609 行组成,其中每行包含给定年份的某个患者的一些信息。请注意,对患者的观察跨越不同的年份,因此同一患者可能出现在数据帧的不同行中。
目标变量是:
**hospvis**
:患者在相应年度内住院时间是否超过 1 天。
我们处理了 16 列:
**id**
:患者 ID(1-7028);**docvis**
:一年中看医生的次数(0-121);**年**
:年(1984-1988);**edlevel**
:教育程度(1-4);**年龄**
:年龄(25-64);**outwork**
: 1 如果失业,0 否则;**女**
: 1 如果女,0 否则;**已婚**
: 1 如果已婚,0 否则;**kids**
: 1 如果有孩子,0 否则;**hhninc**
:家庭年收入,单位为马克(马克);**educ**
:正规教育年限(7-18 年);**自营**
: 1 如果自营,0 否则;**edlevel1**
: 1 如果不到高中毕业,否则为 0;**edlevel2**
: 1 如果高中毕业,0 否则;**edlevel3**
: 1 如果大学/学院,0 否则;- edlevel4 `: 1 如果读研,0 其他。
让我们将数据分为训练集和测试集。有更复杂的方法可以做到这一点,如交叉验证,但让我们保持简单。由于这是一个实验,我们将(天真地)把所有的列当作数字特征。
from sklearn.model_selection import train_test_split
from catboost import CatBoostClassifierX_train, X_test, y_train, y_test = train_test_split(
X, y, test_size = .2, stratify = y)cat = CatBoostClassifier(silent = True).fit(X_train, y_train)
一旦模型被训练,让我们看看特征重要性:
import pandas as pdfimpo = pd.Series(cat.feature_importances_, index = X_train.columns)
训练模型的特征重要性。[图片由作者提供]
不足为奇的是,“docvis”——看医生的次数——对于预测患者是否住院超过 1 天非常重要。“年龄”和“收入”也有些明显。但是病人的 id 在重要性上排名第二的事实应该让我们怀疑,特别是因为我们已经把它当作一个数字特征。
现在,让我们在训练集和测试集上计算模型性能(ROC 下的面积)。
from sklearn.metrics import roc_auc_scoreroc_train = roc_auc_score(y_train, cat.predict_proba(X_train)[:, 1])
roc_test = roc_auc_score(y_test, cat.predict_proba(X_test)[:, 1])
在训练集和测试集上模拟性能。[图片由作者提供]
差别太大了!这是严重过度拟合的迹象。但是哪些特征对此“负责”呢?
听说过 SHAP 价值观吗?
我们有许多指标来衡量一个模型在一些数据上的表现。但是我们如何衡量一个特性在一些数据上的表现呢?
做到这一点的最有力的工具叫做“SHAP 价值观”。
一般来说,要高效地计算任何预测模型的 SHAP 值,可以使用专用的 Python 库。然而,在本例中,我们将利用 Catboost 的本机方法:
from catboost import Poolshap_train = pd.DataFrame(
data = cat.get_feature_importance(
data = Pool(X_train),
type = 'ShapValues')[:, :-1],
index = X_train.index,
columns = X_train.columns
)shap_test = pd.DataFrame(
data = cat.get_feature_importance(
data = Pool(X_test),
type = 'ShapValues')[:, :-1],
index = X_test.index,
columns = X_test.columns
)
如果你看一下shap_train
和shap_test
,你会注意到它们是各自数据集的相同形状。
数据帧的形状。[图片由作者提供]
如果你想更多地了解 SHAP 价值观及其运作方式,你可以从这里的和这里的开始。但是——为了我们的目的——你需要知道的是,SHAP 值让你了解每个单一特征对模型在一次或多次观察中做出的最终预测的影响。
让我们看几个例子:
原始数据与相应的 SHAP 值。[图片由作者提供]
第 12071 排的患者已 0 次就诊。相应的 SHAP 值(-0.753)告诉我们,这条信息将他住院超过 1 天的概率(实际上是对数优势)降低了-0.753。相反,排 18650 的患者已经去看过 4 次医生,这将她住院超过 1 天的对数比提高了 0.918。
会见 ParShap
直观地说,数据集上要素性能的一个很好的代理是要素的 SHAP 值和目标变量之间的相关性。事实上,如果模型在一个特征上发现了好的模式,那么该特征的 SHAP 值必须与目标变量高度正相关。
例如,如果我们希望计算特征“docvis”和测试集中包含的观测值上的目标变量之间的相关性:
np.corrcoef(shap_test['docvis'], y_test)
但是,SHAP 值是相加的,这意味着最终预测是所有要素形状的总和。因此,如果我们在计算相关性之前去除其他特征的影响,这将更有意义。这正是“ 偏相关 ”的定义。Python 库 Pingouin 中包含了部分相关的一个方便实现:
import pingouinpingouin.partial_corr(
data = pd.concat([shap_test, y_test], axis = 1).astype(float),
x = 'docvis',
y = y_test.name,
x_covar = [feature for feature in shap_test.columns if feature != 'docvis']
)
这段代码意味着“在去除所有其他特征的影响之后,计算特征‘doc vis’的 SHAP 值和测试集的观测值上的目标变量之间的相关性”。
既然每个人都需要一个名字,我就把这个公式叫做**【ParShap】**(来自“Shap 值的偏相关”)。
我们可以在训练集和测试集上对每个特征重复这个过程:
parshap_train = partial_correlation(shap_train, y_train)
parshap_test = partial_correlation(shap_test, y_test)
注意:你可以在本文末尾找到函数
partial_correlation
的定义。
现在,让我们在 x 轴上绘制parshap_train
,在 y 轴上绘制parshap_test
。
plt.scatter(parshap_train, parshap_test)
在训练集和测试集上,SHAP 值和目标变量之间的部分相关。注意:颜色条代表特征的重要性。[图片由作者提供]
如果一个特征位于等分线上,这意味着它在训练集和测试集上的表现完全相同。这是最理想的情况,既不过度配合也不欠配合。相反,如果一个特征位于等分线以下,这意味着它在测试集上的表现比在训练集上的表现差。这是过度拟合区域。
从视觉上看,哪些特性表现不佳是显而易见的:我用蓝色圈出了它们。
蓝色圆圈中的要素最容易过度拟合当前模型。[图片由作者提供]
因此,parshap_test
和parshap_train
之间的算术差(等于每个特征和平分线之间的垂直距离)为我们的模型提供了特征过度拟合程度的度量。
parshap_diff = parshap_test — parshap_train
parshap_test 和 parshap_train 之间的算术差异。[图片由作者提供]
我们应该如何解读这个输出?基于我们上面所说的,这个分数越负,特征带来的过度拟合就越多。
“我不相信你”
没关系:你不必!你能想出一个方法来检查这篇文章背后的直觉是否正确吗?
在逻辑上,如果我们从数据集中删除“过拟合特征”,我们应该能够减少过拟合(即roc_train
和roc_test
之间的距离)。
因此,让我们尝试一次删除一个特性,看看 ROC 下的区域如何变化。
在训练集和测试集上的性能,一次删除一个特征,按特征重要性(左)或 ParShap(右)排序。[图片由作者提供]
在左侧,我们一次移除一个特征,按照特征重要性排序。因此,首先删除最不重要的(edlevel4
),然后删除两个最不重要的( edlevel4 '和
edlevel1 `),依此类推。
在右侧的上,我们遵循相同的过程,但是移除的顺序由 ParShap 给出。因此,首先删除最负的 ParShap (id
),然后删除两个最负的 ParShap (id '和
year `),依此类推。
正如我们所希望的那样,删除具有最大负 ParShap 的特性导致过度拟合的大幅减少。事实上,roc_train
离roc_test
越来越近了。
请注意这只是一个测试,用来检查我们推理路线的正确性。一般来说,ParShap 不应该作为特征选择的方法。的确,一些特征容易过度拟合的事实并不意味着这些特征根本没有携带有用的信息!(例如,本例中的收入和年龄)。
然而,ParShap 在给我们提示如何调试我们的模型方面非常有帮助。事实上,它允许我们将注意力集中在那些需要更多特性工程或规则的特性上。
本文使用的完整代码(由于随机种子,您可能会获得略有不同的结果):
# Import libraries
import pandas as pd
import pydataset
from sklearn.model_selection import train_test_split
from catboost import CatBoostClassifier, Pool
from sklearn.metrics import roc_auc_score
from pingouin import partial_corr
import matplotlib.pyplot as plt# Print documentation and read data
print('################# Print docs')
pydataset.data('rwm5yr', show_doc = True)X = pydataset.data('rwm5yr')
y = (X['hospvis'] > 1).astype(int)
X = X.drop('hospvis', axis = 1)# Split data in train + test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = .2, stratify = y)# Fit model
cat = CatBoostClassifier(silent = True).fit(X_train, y_train)# Show feature importance
fimpo = pd.Series(cat.feature_importances_, index = X_train.columns)
fig, ax = plt.subplots()
fimpo.sort_values().plot.barh(ax = ax)
fig.savefig('fimpo.png', dpi = 200, bbox_inches="tight")
fig.show()# Compute metrics
roc_train = roc_auc_score(y_train, cat.predict_proba(X_train)[:, 1])
roc_test = roc_auc_score(y_test, cat.predict_proba(X_test)[:, 1])print('\n################# Print roc')
print('roc_auc train: {:.2f}'.format(roc_train))
print('roc_auc test: {:.2f}'.format(roc_test))# Compute SHAP values
shap_train = pd.DataFrame(
data = cat.get_feature_importance(data = Pool(X_train), type = 'ShapValues')[:, :-1],
index = X_train.index,
columns = X_train.columns
)
shap_test = pd.DataFrame(
data = cat.get_feature_importance(data = Pool(X_test), type = 'ShapValues')[:, :-1],
index = X_test.index,
columns = X_test.columns
)print('\n################# Print df shapes')
print(f'X_train.shape: {X_train.shape}')
print(f'X_test.shape: {X_test.shape}\n')
print(f'shap_train.shape: {shap_train.shape}')
print(f'shap_test.shape: {shap_test.shape}')print('\n################# Print data and SHAP')
print('Original data:')
display(X_test.head(3))
print('\nCorresponding SHAP values:')
display(shap_test.head(3).round(3))# Define function for partial correlation
def partial_correlation(X, y):
out = pd.Series(index = X.columns, dtype = float)
for feature_name in X.columns:
out[feature_name] = partial_corr(
data = pd.concat([X, y], axis = 1).astype(float),
x = feature_name,
y = y.name,
x_covar = [f for f in X.columns if f != feature_name]
).loc['pearson', 'r']
return out# Compute ParShap
parshap_train = partial_correlation(shap_train, y_train)
parshap_test = partial_correlation(shap_test, y_test)
parshap_diff = pd.Series(parshap_test - parshap_train, name = 'parshap_diff')print('\n################# Print parshap_diff')
print(parshap_diff.sort_values())
# Plot parshap
plotmin, plotmax = min(parshap_train.min(), parshap_test.min()), max(parshap_train.max(), parshap_test.max())
plotbuffer = .05 * (plotmax - plotmin)
fig, ax = plt.subplots()
if plotmin < 0:
ax.vlines(0, plotmin - plotbuffer, plotmax + plotbuffer, color = 'darkgrey', zorder = 0)
ax.hlines(0, plotmin - plotbuffer, plotmax + plotbuffer, color = 'darkgrey', zorder = 0)
ax.plot(
[plotmin - plotbuffer, plotmax + plotbuffer], [plotmin - plotbuffer, plotmax + plotbuffer],
color = 'darkgrey', zorder = 0
)
sc = ax.scatter(
parshap_train, parshap_test,
edgecolor = 'grey', c = fimpo, s = 50, cmap = plt.cm.get_cmap('Reds'), vmin = 0, vmax = fimpo.max())
ax.set(title = 'Partial correlation bw SHAP and target...', xlabel = '... on Train data', ylabel = '... on Test data')
cbar = fig.colorbar(sc)
cbar.set_ticks([])
for txt in parshap_train.index:
ax.annotate(txt, (parshap_train[txt], parshap_test[txt] + plotbuffer / 2), ha = 'center', va = 'bottom')
fig.savefig('parshap.png', dpi = 300, bbox_inches="tight")
fig.show()# Feature selection
n_drop_max = 5
iterations = 4features = {'parshap': parshap_diff, 'fimpo': fimpo}
features_dropped = {}
roc_auc_scores = {
'fimpo': {'train': pd.DataFrame(), 'test': pd.DataFrame()},
'parshap': {'train': pd.DataFrame(), 'test': pd.DataFrame()}
}for type_ in ['parshap', 'fimpo']:
for n_drop in range(n_drop_max + 1):
features_drop = features[type_].sort_values().head(n_drop).index.to_list()
features_dropped[type_] = features_drop
X_drop = X.drop(features_drop, axis = 1)
for i in range(iterations):
X_train, X_test, y_train, y_test = train_test_split(X_drop, y, test_size = .2, stratify = y)
cat = CatBoostClassifier(silent = True).fit(X_train, y_train)
roc_auc_scores[type_]['train'].loc[n_drop, i] = roc_auc_score(y_train, cat.predict_proba(X_train)[:, 1])
roc_auc_scores[type_]['test'].loc[n_drop, i] = roc_auc_score(y_test, cat.predict_proba(X_test)[:, 1])
# Plot feature selection
fig, axs = plt.subplots(1, 2, sharey = True, figsize = (8, 3))
plt.subplots_adjust(wspace = .1)
axs[0].plot(roc_auc_scores['fimpo']['train'].index, roc_auc_scores['fimpo']['train'].mean(axis = 1), lw = 3, label = 'Train')
axs[0].plot(roc_auc_scores['fimpo']['test'].index, roc_auc_scores['fimpo']['test'].mean(axis = 1), lw = 3, label = 'Test')
axs[0].set_xticks(roc_auc_scores['fimpo']['train'].index)
axs[0].set_xticklabels([''] + features_dropped['fimpo'], rotation = 90)
axs[0].set_title('Feature Importance')
axs[0].set_xlabel('Feature dropped')
axs[0].grid()
axs[0].legend(loc = 'center left')
axs[0].set(ylabel = 'ROC-AUC score')
axs[1].plot(roc_auc_scores['parshap']['train'].index, roc_auc_scores['parshap']['train'].mean(axis = 1), lw = 3, label = 'Train')
axs[1].plot(roc_auc_scores['parshap']['test'].index, roc_auc_scores['parshap']['test'].mean(axis = 1), lw = 3, label = 'Test')
axs[1].set_xticks(roc_auc_scores['parshap']['train'].index)
axs[1].set_xticklabels([''] + features_dropped['parshap'], rotation = 90)
axs[1].set_title('ParShap')
axs[1].set_xlabel('Feature dropped')
axs[1].grid()
axs[1].legend(loc = 'center left')
fig.savefig('feature_selection.png', dpi = 300, bbox_inches="tight")
fig.show()
感谢您的阅读!我希望你喜欢这篇文章。如果你愿意,在 Linkedin 上加我!
哪支英超球队的主场球迷最有冲击力?
内森·罗杰斯在 Unsplash 上拍摄的照片。
主场优势一直是足球界被广泛研究的现象。据说好处主要来自减少旅行和主场球迷的出现。主场球迷为他们帮助球队获胜的影响力而自豪。然而,在过去很难确定有多少影响来自球迷。
2020-21 英超赛季的大部分时间都没有球迷。有几场比赛的上座率较低,但没有接近前几个赛季的水平。这给了一个绝佳的机会来确定主场球迷真正有多大的影响力,以及对哪支球队的影响最大。
在这篇文章中,我分析了过去十个赛季的英超历史数据,即从 2012-13 赛季到当前赛季(2021-22)。首先,我会试着回答这个问题:球迷在整个联盟中增加了主场优势吗?然后,我会具体看每支球队,确定哪些球迷对自己球队主场成绩的影响最大。
摘要为那些赶时间的人陈述了关键发现,而细节部分为那些想要更多信息的人提供了关于这些发现的进一步细节。
摘要
2020-21 赛季见证了主场胜率的大幅下降和客场胜率的上升。近十个赛季唯一一次客场胜率超过主场胜率。这表明,总的来说,在整个联赛中,主场球迷对结果有影响。随着粉丝的回归,本赛季的收视率多少回到了疫情之前的水平。
图片作者。
每支球队都计算了主场球迷因素,这是基于 2020-21 赛季英超联赛球队在 2020-21 赛季主场比赛中的分数与之前 8 个赛季的分数相比的比例。
富勒姆被证明有最大的主场球迷因素,这意味着富勒姆球迷的存在对联盟中任何球队的结果都有最大的积极影响。另一方面,南安普顿的得分最低,这意味着南安普顿在没有球迷在场的情况下主场表现更好。图 4 的细节部分显示了所有团队的因素。
图片作者。
主场球迷的出现被证明对比赛结果有积极的影响,对主队有利。然而,体育场容量对主场球迷因素没有影响。这说明粉丝的存在很重要,但数量并不重要。
细节
第一部分:总体
首先,在过去的十个赛季中,主场球迷的影响是跨整个联盟来看的。图 1 显示了本赛季主客场球队的胜率。在疫情之前的八个赛季中,主场胜率从未低于 40%,客场胜率从未超过 35%。事实上,这两个比率从来不会相差 10%以内。
图 1:按赛季划分的主场/客场胜率。图片作者。
对于 2020-21 赛季,客场胜率超过主场胜率,这证明了主场球迷在整个联盟中平均发挥着重要作用。事实上,它甚至可能表明大多数(如果不是全部)主场优势来自球迷,因为旅行因素仍然存在。有趣的是,2019–20 赛季的最后三分之一是在没有球迷的情况下进行的,但主场胜率与往年一致。然而,总体平均上座率并没有明显低于前几个赛季(见附录中的表 1)。
对于 2021-22 赛季,主场率再次提高,但差异没有以前那么极端。随着平均上座率回到疫情之前的水平,这表明了平局的趋势。事实上,提取率(29%)是所有季节中最高的。然而,由于赛季不完整,这可能只是统计上的波动,随着赛季的进行,差异可能会增加。
查看影响的另一种方式是查看自 2012-13 赛季以来的滚动胜率,如图 2 所示。红线表示没有球迷出现在体育场的时间。在此期间,滚动率明显下降。考虑到这一比率是由之前的八个赛季加权得出的,这一下降是相当惊人的。
图 2:最近十个赛季的滚动胜率(%)。图片作者。
所以,下一个问题是:在 2020-21 赛季,这些额外的客场胜利来自哪里?观察主客场进球总数(图 3)可以发现,这两个类别的进球数量多年来一直保持相对稳定。然而,对于 2020-21 赛季,我们看到了最剧烈的变化。虽然仍然有更多的主场进球,但差距现在已经小得多了。事实上,只有四个主场进球。因此,不出所料,客场胜率增加了,因为客场球队得分更多,主场球队得分更少。
图 3:按赛季划分的主客场进球数量。图片作者。
对每个赛季的平均出勤率(如附录中的表 1 所示)和客场赢球率进行学生 t 检验,结果显示出–0.72 的显著相关性(p 值为 0.02 <0.05), suggesting that higher fan attendance leads to a lower away win rate. Hence, we can conclude that the attendance of fans has a statistically significant effect on the away win rate.
第 2 部分:特定团队
在这里,我试图调查每支球队的球迷对他们表现的具体影响。为此,我将把 2020-21 赛季之前的八个赛季直接与 2020-21 赛季进行比较。我不会包括当前的赛季,因为这个赛季是不完整的。我会把疫情之前的赛季分组。这种比较只使用了 2020-21 赛季的球队,不包括利兹联队和谢菲尔德联队,因为他们在疫情之前的赛季中不在英超联赛中。
为了量化球迷的影响,我们可以看看每支球队在疫情之前和 2020-21 赛季之间主场胜率的差异。然而,一个队可能有较低/较高的胜率,仅仅是因为那个赛季的形式不同。相反,我会看一个赛季中主场比赛占总积分的比例。这样,球队的整体形式是不相关的,而是主场形式被认为是相对于客场形式的。我将比较疫情之前赛季和 2020-21 赛季球队主场总得分的比例。两者之间的差异将被称为主场球迷因素(HFF) ,定义为:
图 4 显示了每个团队的 HFF。正值表示该队在 2020-21 赛季主场比赛中的得分比例有所下降,这表明主场球迷通常会产生积极的影响。负值表示相反的情况。当球迷不在场时,整个联盟的主场胜率都下降了,所以 HFF 对大多数球队来说是积极的也就不足为奇了。水晶宫和南安普顿是例外。这两支球队似乎更喜欢在空无一人的体育场里比赛——也许他们也没有处理好球迷的压力。富勒姆和埃弗顿的 HFF 最大。这表明这两家俱乐部的球迷对主场比赛的结果有着最大的影响。
图 4:每支球队的主场球迷因素(HFF)。图片作者。
最后一点,比较 HFF 和每个队的体育场容量,发现没有显著的相关性,如图 5 所示。这表明体育场的大小并不影响主队的表现。事实上,HFF 最大的球队(富勒姆)容量也最低。尽管富勒姆并不以其特别喧闹的氛围而闻名,但与安菲尔德这样的地方相比,球队可能会在压力稍小的情况下比赛。所以,也许在家里最好的表演来自于更温和的氛围。
图 5:体育场容量与每支球队主场得分率的差异。图片作者。
总之,主场球迷的出现降低了整个联盟的平均客场胜率。富勒姆被证明拥有最具影响力的球迷。然而,体育场的容量与 HFF 没有相关性。这表明,虽然球迷的存在很重要,但实际人数相对来说并不重要。
来源:
资料:【https://www.football-data.co.uk/englandm.php
使用的软件:R
延伸阅读:
https://www.sciencedirect.com/science/article/pii/S146902922100131X
附录:
表 1:每季平均上座率。
应该使用哪种 Python 数据结构?
列表、元组、集合、字典…什么时候使用哪种内置数据结构?
照片由维多利亚诺·伊斯基耶多在 Unsplash 拍摄
Python 是一种面向对象的编程(OOP)语言。类和对象用于结构化和模块化代码,以便可重用和易于修改。OOP 要求使用数据结构来组织和存储数据,以一种可以被有效访问的方式。
Python 有原语(或基本)数据结构,如浮点、整数、字符串和布尔。Python 还有非原语数据结构,比如列表、元组、字典和集合。非原始数据结构存储各种格式的值的集合,而不是单个值。有些可以在数据结构中保存数据结构,从而增加了数据存储能力的深度和复杂性。
作者照片
在本文中,我们将研究每种内置数据结构,以决定何时使用一种结构优于另一种结构。
什么是可变性?
可变性意味着数据结构中的数据在创建后可以被修改(添加、删除或更改)。可变性是选择数据结构时要考虑的一个重要因素。如果你知道你不需要改变内部状态,考虑使用一个不可变的对象来确保它是线程安全的,并且没有任何东西可以覆盖你的数据。
列表
为了表示按整数位置索引的项目序列,可以使用的一种数据结构是列表。列表包含零个或多个元素,并且可以包含不同类型的元素(甚至是对象!).这使得列表非常强大,因为它们允许您创建深度和复杂的数据结构。
列表是可变的,这意味着您可以灵活地添加、删除或更改元素。另一种顺序数据结构是一个元组;这两者的区别在于元组是不可变的。
因为列表有一个顺序元素:如果你只想跟踪唯一的值而不关心顺序,使用 Python set 。
使用[]
或list()
创建列表。使用list()
进行类型转换。
一些值得注意的方法和技巧
获取列表项: my_list[0]
通过偏移获取列表项。像字符串一样,负索引可以用来从末尾向后计数。
my_list[0] = ‘new item'
通过偏移改变列表项。
my_list[0:2]
通过偏移切片来提取项目。该示例返回my_list
的前两个元素。
添加列表项: append()
在列表末尾添加一项。
extend()
或+=
将一个列表合并到另一个列表中。
insert()
在任何偏移前添加一项。
删除列表项目:
remove()
从列表中删除项目值。
pop()
删除最后一个(或指定的)元素,同时返回值。
del
根据项目在列表中的位置删除项目。del
是 Python 语句,不是 list 方法。
join()
返回组合列表项的字符串。join()
的参数是一个字符串或任何可迭代的字符串序列。
len()
返回列表中的项数。count()
返回指定值出现的次数。
元组
元组也是一种有序的数据结构,就像列表一样。但是,元组是*不可变的;*创建元组后,不能添加、删除或更改项目。元组不同于列表,它的函数要少得多,因为它们在定义后不能修改。元组包含零个或多个元素,并且可以包含不同的不可变类型的元素。
元组相对于列表的优势:
- 元组使用更少的空间
- 不变性防止错误地更改元组项
- 元组可以用作字典键
- 函数参数作为元组传递
使用()
或没有括号的逗号分隔的元素列表创建元组。使用tuple()
进行类型转换。
一些值得注意的方法和技巧
count()
返回一个元素在元组中被找到的次数
index()
返回一个元素的索引位置
字典
字典不使用偏移量,而是使用键来关联每个值。这意味着顺序是不可跟踪的,如果你打算使用字典的话,这并不重要。字典键是不可变的和唯一的,然而,字典是可变的。可以添加、删除或更改键值元素。简而言之,字典非常类似于散列表。
使用{}
创建字典。使用dict()
进行类型转换。
一些值得注意的方法和技巧
my_dict[‘key’]
通过键获取一个项目
my_dict['key'] = ‘value'
使用一个键添加(或改变,如果它已经存在)一个值。
update()
将一个字典的键和值合并到另一个字典中。
del
按提供的键删除项目。del
是 Python 语句,不是字典方法。
keys()
返回所有字典键。values()
返回字典中的所有值。items()
返回所有字典键值对。
设置
集合就像一本字典,只有关键字,没有值。这意味着集合是唯一的,而不是连续的(无序存储)。集合也是可变的。集合包含零个或多个元素,并且可以包含不同的不可变类型的元素。
本质上,当你想知道某样东西是否存在,而对它一无所知时,就要用到集合。如果跟踪值的顺序或存储相同值的倍数很重要,考虑使用空间友好的元组来代替。
使用set()
创建器械包。使用set()
进行类型转换。
一些值得注意的方法和技巧
add()
向集合中添加不存在的项目
clear()
从集合中删除所有项目
intersect()
返回两个集合的交集
union()
返回两个集合的并集
概括起来
- 如果需要跟踪排序,使用列表或元组
- 如果你只想跟踪唯一的值,而不关心顺序,使用 Python set
- 如果一旦定义了对象就不需要修改,那么使用一个元组来节省空间并确保没有东西会覆盖你的数据
- 如果你需要跟踪和修改键值对结构的数据,使用字典
哪个 Python 库最适合数据可视化?
大蟒
Matplotlib、Seaborn、Plotly Express 和 Altair。哪一个是最好的数据可视化库?
图片由 Jason Coudriet 提供。来源: Unsplash
数据可视化是任何探索性数据分析或报告的关键步骤。它通常易于阅读,并且可以让我们一眼就能洞察数据集。有几十个很棒的商业智能工具,比如 Tableau、Google Data Studio 和 PowerBI,它们让我们可以轻松地创建图表。数据分析师或数据科学家通常会使用 Python 在 Jupyter 笔记本上创建可视化效果。幸运的是,有几十个很棒的 Python 库可以创建很棒的图形。然而,百万美元的问题是:哪一个是最好的?
无论你是学生还是专业人士,你都应该知道一些选择。没有完美的图书馆。因此,您应该知道每种数据可视化的优缺点。我将介绍四个最流行的用于数据可视化的 Python 库:Matplotlib、Seaborn、Plotly Express 和 Altair。为此,我将创建一个简单的条形图,并分析使用每个库有多容易。对于这个博客,我将使用一个城市数据集。你可以在这里找到笔记本。
类别
这篇博客将分析建立一个柱状图有多容易,定制图表使其最少呈现有多容易,以及库文档。
设置数据集
首先,让我们导入所有重要的库。很有可能你的电脑上已经安装了 Matplotlib 和 Seaborn。但是,你可能没有 Plotly Express 和 Altair。您可以使用pip install plotly==4.14.3
和pip install altair vega_datasets
轻松安装它们。
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import altair as alt
import plotly.express as px
现在我们将导入数据集。出于演示目的,我们仅创建一个包含美国人口最多的前 15 个城市的数据框。我还将修改城市名称的大写字母。当我们创建可视化时,这将有助于编辑过程。
df = pd.read_csv('worldcitiespop.csv')us = df[df['Country'] == 'us']us['City'] = us['City'].str.title()cities = us[['City', 'Population']].nlargest(15, ['Population'], keep=’first’)
现在我们应该准备好分析每个库了。你准备好了吗?
类别:设置难度和初步结果
赢家: Plotly Express
输家: Matplotlib、Altair、Seaborn
在这个类别中,所有的库都表现良好。它们都很容易设置,基本编辑的结果对于大多数分析来说已经足够好了,但我们需要有赢家和输家,对吗?
Matplotlib 非常容易设置和记忆代码。然而,图表并不好看。它可能会做数据分析的工作,但它对于商务会议的结果不是很好。
作者图片
Seaborn 创造了一个更好的图表。它会自动添加 x 轴和 y 轴标签。x 记号可能看起来更好,但对于基本图表来说,这比 Matplotlib 好得多。
作者图片
Plotly Express 表演得很精彩。用很少的代码就可以创建一个好看且专业的条形图。没有必要设置图形或字体大小。它甚至旋转 x 轴标签。所有这些都只需要一行代码。印象非常深刻!
作者图片
牛郎星图表现不错。它提供了一个好看的图形,但是它需要更多的代码,并且出于某种原因,要按照字母顺序组织容器。那不可怕,很多情况下也能有帮助,但我感觉这应该是用户自己决定的事情。
作者图片
类别:编辑和定制
赢家: Plotly Express,Seaborn,Matplotlib
输家: Altair
我相信这四个图书馆都有成为赢家的潜力。在它们中的每一个中定制图表是不同的,但是我认为如果你学得足够多,你将学会如何创建漂亮的可视化。然而,我正在考虑编辑和在互联网上找到关于编辑它们的信息有多容易。我确实有使用这些库的经验,但是我把自己想象成一个新用户。
Matplotlib 和 Seaborn 非常容易定制,它们的文档非常惊人。即使你没有在他们的文档中找到你要找的信息,你也可以很容易地在 Stack Overflow 中找到它。他们还有一起工作的优势。Seaborn 基于 Matplotlib。因此,如果你知道如何编辑一个,你就会知道如何编辑另一个,这将非常方便。如果使用sns.set_style('darkgrid')
设置 Seaborn 主题,会影响 Matplotlib。这可能就是为什么 Matplotlib 和 Seaborn 是两个更受欢迎的数据可视化库。
作者图片
作者图片
例如,Plotly Express 从一开始就提供了漂亮的图表,比 Matplotlib 需要更少的编辑,以获得最低限度的会议可视化。它的文档简单易懂,他们通过Shift + Tab
提供文档,非常方便。在我尝试过的所有库中,它还提供了最多的定制选项。您可以编辑任何内容,包括字体、标签颜色等。最棒的是这不费吹灰之力。它的文档中有很多例子。
作者图片
我发现 Altair 的文档非常混乱。与其他库不同,Altair 没有Shift + Tab
快捷键。这对初学者来说是非常有问题和困惑的。我可以做一些编辑,但是寻找相关信息很有压力。与我花在编辑 Matplotlib 和 Plotly Express 上的时间相比,我要说 Altair 对于初学者来说并不是一个很好的选择。
作者图片
类别:附加功能
赢家: Plotly Express 和牛郎星
输家: Matplolib 和 Seaborn
对于这一类别,我将考虑除了那些我们可以通过代码实现的特性之外的附加特性。Matplotlib 和 Seaborn 在这一类中是非常基础的。除了代码所提供的,它们不提供任何额外的编辑或交互选项。然而,Plotly Express 在这一类别中大放异彩。首先,图表是交互式的。你只需要将鼠标悬停在图表上,就会看到相关信息。
作者图片
Altair 提供了一些选项来保存文件或通过 Vega Editor 打开 JSON 文件。咩!
作者图片
类别:文档和网站
赢家: Plotly Express,Altair,Seaborn,Matplotlib
所有这些库的文档都很好。Plotly Express 有一个漂亮的网站,上面有代码和可视化演示。非常容易阅读和查找相关信息。我喜欢他们的网站看起来如此复杂和精心设计。你甚至可以与图表互动。
作者图片
Altair 也把他们的网站做得很好。他们的定制文档不是最好的,但网站看起来很好,很容易找到代码示例。我不会说这是惊人的,但它确实起了作用。
作者图片
Seaborn 的网站还可以。有些人说他们有最好的文档。我觉得还可以。它完成了任务。它包含代码示例。如果您正在寻找定制选项,这可能会变得棘手,但除此之外,这是一个干净的网站,其文档非常完整。
作者图片
Matplotlib 有完整的网站。在我看来,它有太多的文本,找到一些信息可能有点棘手。然而,信息就在那里的某个地方。他们还提供 PDF 格式的文档,我计划在将来的某个时候阅读这些文档。
作者图片
最终交付
我在这篇博客中分析的四个库都是很棒的库,有无限的可能性。我只检查了几个因素。基于这个原因,不要认为这个博客是理所当然的。所有的库都有优点和缺点,我是作为一个初学者写这篇博客的。我最喜欢的是 Plotly Express,因为它在所有类别中都表现良好。然而,Matplotlib 和 Seaborn 更受欢迎,大多数人会在他们的计算机上安装它们。在这些库中,Altair 是我最不喜欢的,但它值得我在未来给予一些关注。让我知道你最喜欢的数据可视化库是什么。
你是谁,数据工程师?
在这篇文章中,我将解释当今存在的数据角色,特别是谁是数据工程师?其中包含的角色定义、职责和挑战是什么?
克里斯蒂娜@ wocintechchat.com 在 Unsplash 上的照片
在过去的几年里,我一直在做一名大数据工程师,虽然这听起来像是当前的流行语,但我已经知道,我在软件世界的许多同事不一定理解这个角色的内容。
有些人会将其与 DevOps、数据分析或数据科学相混淆。有些人会认为这是数据库架构师(DBA)这个神话角色的新品牌。
因此,在发现自己向许多不同的人解释了几次我做什么,以及为什么它与我之前提到的那些不同之后,我意识到可能会有更多的人乐于知道数据工程是怎么回事。
但是首先:目前存在哪些数据角色?
老实说,这种困惑是可以理解的-今天,许多公司已经意识到数据对组织的重要性,在这个世界上,每一个基本操作都被转换为数据并由某人使用,几乎每个公司都有一个数据组,其中的角色定义略有不同。
有时数据组将作为整个公司的一个组,通常是在具有特定领域的小公司中,但是随着公司以这种方式发展,对于具有特定领域的每个部门来说,将有一个专用的数据组来保存数据处理。
这些是数据组中的关键角色:
- 数据分析师 —数据分析师的工作是将信息转化为知识,识别趋势,并将分析后的数据用作制定更好的基于数据的业务决策的战略引擎。它的主要工具将是数据库、SQL 和 HIVE 查询,以及用于数据可视化的图形仪表板。
- 数据科学家 —使用数据驱动的算法、机器学习来解决业务问题,通常具有丰富的统计和数学知识,在数据中寻找趋势和模式,以将公司的利益带到下一个级别。
- 数据工程师— 构建和维护数据基础设施,如数据管道,负责将来自不同来源的数据传输到其他角色使用的地方,为数据科学家的模型构建准备数据。
作者图片
数据工程师的类型
数据工程师不仅“获取”数据,还允许您方便地访问数据,随时甚至实时收集最新数据。
“经典”数据工程师——数据管道工程师
大部分工作是基于将数据从不同的数据源传输到单个目标,在许多情况下,他们将主要使用 ETL ( ETL 代表 E xtract,Ttransform,以及 L oad,指的是从多个数据源提取数据并根据业务需求将其转换并加载到目标数据库的过程)或者构建和维护这样的数据库。
这种类型的数据工程师需要对关系数据库和 SQL 查询有很高的理解。
机器学习数据工程师
这些工具的主要作用是将模型(由数据科学家开发)部署到真实的生产环境中,并完成所有必要的工作—构建包括自动化、测试、监控和日志的生产基础架构。
机器学习工程师将参与编写用于训练和准备模型的代码(大数据解决方案中的数据准备和训练层),在这种情况下,Python、Spark 和云环境方面的强大背景是必须的。
数据工程师的主要技能
虽然数据科学家通常在数学和统计学方面有很强的背景,但数据工程师通常是有几年经验的软件开发人员,他们了解云基础设施和开发语言,如 Python 或 Java、Scala 等。
由于我们处于一个大数据世界,它通常是在云中管理的,因此了解其中一个提供商将是有用的——如谷歌云服务、Azure 或 AWS。
此外,数据库的知识是工作所需的知识之一——理解关系和非关系数据库,运行复杂的数据获取查询,所有这些都不会影响用于生产环境的数据。
在某些情况下,根据工程师从事的项目,需要对机器学习算法、统计模型和各种数学函数有基本的理解。
作者图片
作为数据工程师的挑战
可靠性
数据世界中最重要的事情是数据的可靠性——在数据损坏的情况下,任何复杂的模型都无法提供帮助。因为数据工程师负责收集数据(有时来自不同的来源)并将它们移动到一个目标,转换和处理它们以创建一致性,等等,所以人们担心数据的可靠性会在这个过程中受到损害。
这是一个巨大的挑战,要确保一路上我们没有改变数据的本质,我们收到的和我们传递的是一样的。
为了提供高度确定的数据,我们必须全程采取行动,例如:
- 数据一致性 —意味着数据中的每个变量都只有一个含义。为了确保数据的可靠性,我们必须验证模式的一致性——对于特定的模式,每个记录都以相同的方式处理。
- 元数据存储库 —通过有序保存元数据的来源和处理方式,为数据提供上下文。
- 数据修改权限 —只有被授权的人才能修改数据——人和流程都一样。这将确保不会发生意外的变化。
可扩展性和性能分析
有时,传入数据的数量和速度是不可预测的,该角色面临的挑战之一是构建一个知道如何轻松快速地处理增加的负载的系统。
重要的是要明白 Scale 没有神奇的解决方案,但是会根据问题给出解决方案——如何处理负载?
例如,如果您的系统是一个 web API,负载可能会影响响应时间,因此解决方案应该在这个级别。
再现性
数据是一切的基础。因此,我们应该做好准备,以防由于各种原因导致某些数据丢失。因此,高效、快速地恢复并保持数据随时间推移而可用的能力,是数据工程师面临的一项重要挑战。
结论
综上所述,关于谁是数据工程师,他们的职责是什么的困惑是理解的。这确实是一个有趣而多样化的角色,包括代码编写以及云基础设施的维护和建立,数据库的复杂工作,在某些情况下还包括统计和机器学习。
数据基础架构用户相信您能为他们提供一个数据可靠的系统,能够快速处理突发负载而不丢失关键数据,并且能够在意外情况下恢复信息。
工作中的许多挑战增加了人们的兴趣和令人印象深刻的学习曲线——数据世界正在快速发展,为了保持一致,我们必须跟上我们作为解决方案所面临的变化和技术。此外,这一角色还伴随着许多责任,例如,数据可靠性是一个真正的挑战,至少在“最坏的情况”下意味着大量的金钱损失,在其他情况下,可能会因为不正确的数据或错误的决策而产生法律后果,从而导致人员伤亡(例如,安装在煤气罐上的传感器和实时泄漏报告,如果数据在此过程中被不同地翻译,则可能会错过实时灾难警报)。
这个数据库是谁设计的?
塞巴斯蒂安·赫尔曼在 Unsplash 上的照片
一个设计良好的数据库和最新的文档是最理想的,但是如果不是这样,并且您无法改进数据库设计,那么有什么解决方法呢?
考虑以下场景
你是一名自由职业的数据科学家,受雇对一家公司的数据进行分析。这似乎很简单,您知道如何使用 SQL 和 Python,以及如何进行假设检验,并且您会被告知您将获得一个数据库模式。
该公司一直在向一些客户提供不同程度的折扣。作为您的第一项任务,您需要弄清楚提供产品折扣是否有助于增加订单中的商品数量,如果有,它是否特定于某个或某些折扣?
看一下这个模式
您要做的第一件事是查看提供给您的数据库模式,并提出一个收集数据的计划。
提供的数据库模式
您会看到订单明细表中列出了产品折扣。您已经看到了这个数据库设计的一个问题,这个表的标题中有一个空格,这不是一个好现象,但是您可以通过引用表名来解决它。
订单细节表数据看起来像什么?
您将使用 Python 的 sqlite3 包来查询数据库,并计划将查询到的数据存储在 Pandas Dataframe 中。
首先,您需要查看表中的几个条目。
import sqlite3
import pandas as pdquery = """SELECT * FROM 'Order Details' LIMIT 10"""df = pd.DataFrame(cur.execute(query).fetchall(), columns = [description[0] for description in cur.description])df.head(10)
您收到的不是数据,而是以下错误:
OperationalError Traceback (most recent call last)
<ipython-input-5-8791be329a46> in <module>
----> 1 cur.execute(query).fetchall()
OperationalError: no such table: Order Details
嗯。在仔细检查模式中的拼写错误后,很明显没有名为 Order Details 的表。
如果模式是错误的,那么表名是什么?
不幸的是,如何做到这一点取决于您正在使用的关系数据库实现,但是在我们的例子 sqlite 中,您可以使用下面的查询。
query = """
SELECT name FROM sqlite_master
WHERE type='table'
ORDER BY name;
"""
cur.execute(query).fetchall()
返回的表名是:
[('Category',),
('Customer',),
('CustomerCustomerDemo',),
('CustomerDemographic',),
('Employee',),
('EmployeeTerritory',),
('Order',),
('OrderDetail',),
('Product',),
('Region',),
('Shipper',),
('Supplier',),
('Territory',)]
什么?没有一个表名与模式匹配。此时,您不能信任该模式,但是希望即使表名不匹配,每个表之间的关系仍然存在。
现在您知道了正确的表名,您可以再次尝试检索一些数据。
query = """SELECT * FROM 'OrderDetail' LIMIT 10"""df = pd.DataFrame(cur.execute(query).fetchall(), columns = [description[0] for description in cur.description])df.head(10)
这次你得到一些数据!
OrderDetail 表的输出
您会发现模式和当前数据库实现之间存在更多的不一致。有一个 Id 列未在架构中显示,并且 OrderId 列和 ProductId 的大小写与架构不匹配。虽然大写在 SQL 中并不重要,但是一旦你将数据放入 Pandas 数据框架中,大写就很重要了。您需要记下这一点,以便将来进行查询和分析。
你现在可以使用这个表进行假设检验了,我不会在这篇文章中详细介绍这个表,但是如果你需要其他表中的数据呢?
订单表呢?
你可能已经注意到上面有一个叫做 Order 的表。如果您熟悉 SQL,您会知道顺序是一个保留字。您应该怀疑从订单表中查询数据会有问题,但是为什么会这样呢?
举个简单的例子,您可以尝试从那个表中查询几行数据。
query = """SELECT * FROM Order LIMIT 5"""df = pd.DataFrame(cur.execute(query).fetchall(), columns = [description[0] for description in cur.description])df.head()
正如所料,您会收到一个错误
---------------------------------------------------------------------------
OperationalError Traceback (most recent call last)
<ipython-input-31-dc8e46beab2b> in <module>
**1** query = """SELECT * FROM Order LIMIT 5"""
**2**
----> 3 df = pd.DataFrame(cur.execute(query).fetchall(), columns = [description[0] for description in cur.description])
**4** df.head()
OperationalError: near "Order": syntax error
对此你能做些什么?SQL 怎么知道 Order 是表名不是保留字?不幸的是,该解决方案依赖于数据库实现。我将向您展示如何在 sqlite 的情况下处理它。您需要用反斜杠将表名括起来。
query = """SELECT * FROM `Order` LIMIT 5"""df = pd.DataFrame(cur.execute(query).fetchall(), columns = [description[0] for description in cur.description])df.head()
这次检索了一些数据。
订单表中的数据
如果您参考上面的有问题的模式,您会注意到被指定为 OrderID 的内容实际上被称为 ID,并且需要注意。
如果您需要引用订单表中的一列,该怎么办?你还在用反勾号。下面是一个更复杂的查询示例。
query = """
SELECT `Order`.Id AS OrderId,
SUM(OrderDetail.Quantity) AS TotalQty
FROM `Order` JOIN OrderDetail
ON `Order`.Id = OrderDetail.OrderId
GROUP By `Order`.Id
"""
您可以看到,在任何使用 Order 的地方,都需要用反勾括起来。如果您需要将它用作子查询,重命名顺序。Id 到 OrderId 将有助于保持查询的其余部分“干净”。
感谢你花时间阅读这篇文章。当您遇到设计和/或文档不良的数据库时,我希望我详述的解决方法会有所帮助。
谁是自然语言处理领域的“维基百科名人”?
变更数据
尽管维基百科的简历中存在众所周知的偏见,但拥有维基百科的简历通常被视为衡量知名度的一个标准
作为一名研究人员,拥有一篇维基百科文章是衡量一名研究人员有多著名的众多标准之一。然而,维基百科因其性别偏见而受到严厉批评,这是一个如此突出的问题——你可能已经猜到了——有一个关于这个话题的专门的维基百科页面。此外,研究发现,在维基百科上有一篇传记文章实际上与传统的影响指标如引用计数没有关联。鉴于我在自然语言处理(NLP) 研究领域参与了多样性&包容计划,以及对性别偏见检测和学术数据的兴趣,我对我们领域的现状感到好奇,具体来说:1) 有多少研究人员拥有维基百科传记,2) 是否存在显著的性别差异,3) 拥有一篇维基百科文章与拥有, 4)谁有维基百科的文章中有任何可观察到的国家或机构偏见?
注意事项:我先分享一些数据准备的注意事项,然后是数据分析和讨论。尽管我尽了最大努力,但还是有可能无意中排除了一些维基百科页面。还要注意的是,NLP 研究人员可能因为他们的 NLP 研究之外的原因而出名。此外,有许多不同的影响指标可以比较,我选定了一个将研究人员发表的 NLP 论文数量与这些论文吸引的引用数量相结合的指标。最后,除了性别之外,还有更多偏见——我也将分享一些关于这方面的笔记。如果你只是想要外卖,跳到 TL;博士总结在最后。
数据准备
这种分析需要两种类型的数据:关于自然语言处理研究人员的维基百科文章列表,以及这些研究人员的出版数据,以衡量他们对该领域的相对影响。
收集维基百科的简历
有几种方法可以识别维基百科文章的主题,最直接的方法是出现在文章底部的类别标签。虽然有用,但不幸的是它们也很稀少。因此,我浏览了大约 1000 篇链接到自然语言处理页面的文章,如果它们代表了相关研究人员的传记,就将它们标记为自然语言处理和/或计算语言学研究人员。正如你从(现在更新的)类别列表以及这个电子表格、中看到的,总共有 138 名 NLP 研究人员拥有维基百科简介。
附注:术语“自然语言处理”和“计算语言学”之间有一些语义上的差异,但由于它们经常被混为一谈,因此出于分析的目的,我将它们视为同一个术语,并通篇使用当今更常见的术语“自然语言处理”。
此外,我只考虑了英文维基百科的 NLP 页面作为起点。因此,我可能错过了只有维基百科非英文版页面的 NLP 研究人员。
收集学术资料
为了评估这些研究人员对该领域的影响,我使用了 NLP 学者数据集,它包含了 ACL 选集中的所有论文(反过来,它索引了在著名的 NLP 会议、研讨会和期刊上发表的论文)。除了论文列表,它还包含截至 2020 年 6 月谷歌学术论文的引用计数。请注意,相关研究人员不必拥有谷歌学术帐户;只有论文需要被谷歌学术索引。
衡量研究影响
衡量研究影响的一个常用指标是研究人员的 h 指数。然而,这个衡量标准考虑了所有研究者的论文,而不仅仅是某个特定学科的论文,正如我在这里想要捕捉的。为了衡量 NLP 中的研究影响,我选择了一个不同的指标,即研究人员发表了多少篇论文,以及这些论文被引用的情况,这两个指标也是常见的研究影响指标。不仅仅是测量引用的原因是,基于NLP 的哪个子领域是关于、第一作者的性别是什么、和更多,关于什么论文获得多少引用存在偏见。
此外,我采用了一个相对宽泛的“突出”场所的定义,因为这些偏见也会影响同行评审,从而影响作者希望在多有声望的场所发表他们的工作——例如,介绍新数据集的论文虽然对社区非常有价值,但很少在 NLP 内排名最高的场所发表,因为介绍新模型的论文通常被评审员认为更值得发表。
请进一步注意,这些研究人员可能在其他领域发表过论文,或者他们可能因为他们的研究论文以外的原因而更加引人注目。此外,维基百科页面的长度,它们被编辑的频率或其他更细粒度的统计数据可能有助于衡量,正如Samoilenko&Yasseri(2013)所调查的那样。由于我对维基百科上高影响力的 NLP 研究人员的代表性感兴趣,我只考虑了他们的 NLP 出版物(如上所述,我在这里使用的 NLP 学者数据集只包含由 ACL 选集索引的论文,这些论文都是关于 NLP 的论文)。此外,我没有对他们的维基百科简历进行更细致的统计。
此外,测量研究影响是非常复杂的,当然不仅仅是研究人员的出版物,例如,参见关于替代指标的讨论。出版物的数量也受到研究小组规模的限制,而研究小组的规模本身又受到研究经费等资源的限制。给研究人员排名甚至会对科学本身有害,因此除非必要,否则应该避免。在这里,衡量研究影响应被视为达到目的的必要手段,而不是目的本身。我想积极劝阻读者试图过多地解读下面某个研究人员的特定影响排名,因此不会发布与他们的 NLP 影响度量配对的研究人员的完整列表。
事不宜迟,这是我选定的衡量标准。根据 NLP 学者数据集,我首先计算了每位研究人员的论文数量和引用数量。然后,我对结果列表进行降序排列,以获得两个等级: r_p ,一个研究人员的等级,表示他们相对于其他研究人员发表了多少篇论文,以及 r_c,一个研究人员的等级,表示他们相对于其他研究人员获得了多少引用。然后,我线性组合了两个等级,即 r_p + r_c ,并对结果等级进行归一化,这样每个位置之间的增量为 1。
数据分析
回想起来,我主要对两件事感到好奇:维基百科上 NLP 研究人员的代表性是否存在性别差异,以及拥有维基百科简历本身是否与 NLP 的科学影响力相关。总共有 138 名研究人员拥有维基百科的简历,因此很难从中得出任何结论性的发现(如果我将这篇博文作为论文提交,审稿人 2 可能会反对我这样做)。然而,这是我的发现。
定性分析
我知道你们中的一些人来这里是为了一些容易理解的情节/图表/例子,所以下面是根据我之前定义的研究影响排名以及赛义德和性别(手动标记,见下文)列出的拥有维基百科页面的前 20 名研究人员。显而易见,并非所有有影响力的 NLP 研究人员都有维基百科的简历。此外,有很有影响力的男性和女性 NLP 研究人员都有维基百科的简历。
前 20 名最有影响力的 NLP 研究人员,他们的维基百科页面和手动标记的性别。影响排名是根据他们的 NLP 论文及其引用来确定的。
性别代表性
我根据维基百科简历中描述他们的代词,在维基百科页面上手动标记了每个研究人员的性别。没有一个研究者被称为“他们”,51 个被称为“她”,86 个被称为“他”。请注意,维基百科页面不是自传性的,因此,尽管不太可能,但有可能有人无意中弄错了性别。此外,一些非二元的人使用代词“她”或“他”,而不是“他们”或其他代词,这意味着性别不能仅从代词中推断出来。尽管如此,我得出的结论是,极不可能存在拥有维基百科页面的非二进制 NLP 研究人员,拥有维基百科简历的女性研究人员比例为 37.2%。作为比较, Mohammad (2020) 估计 NLP 中 29%的第一作者和 25%的最后作者是女性, Schluter (2018) 估计 NLP 中女性占所有研究人员的比例为 33.5%。鉴于此,似乎拥有维基百科简历的女性 NLP 研究人员的比例明显低于男性 NLP 研究人员的比例。然而,这也略高于妇女在该领域的代表性。
影响分析
回想一下,我感兴趣的是拥有维基百科简历的研究人员是否也倾向于对该领域产生重大影响。总的来说,在 NLP Scholar 数据集中有 45041 个唯一作者条目。其中一些可能是重复的,例如,如果一名研究人员以不同的名字发表了论文——出于这种粗略分析的目的,没有努力将这些联系起来。
研究这个问题的一个简单方法是计算拥有维基百科简历的研究人员的平均排名(回想一下,有 138 个这样的排名——你可以在这里看到所有的排名)。拥有维基百科简历的 NLP 研究人员的平均排名是 8152,而数据集里 NLP 研究人员的平均排名是 22521。此外,拥有维基百科简历的研究人员中有 37%属于 NLP 影响排名最高的前 1%的 NLP 研究人员。为了说明这一点,下面是具有维基百科简历的 NLP 研究人员的绝对影响排名(x 轴)与具有维基百科简历的所有 NLP 研究人员的相对影响排名(y 轴)的曲线图。
拥有维基百科简历的 NLP 研究人员的绝对影响排名(x 轴)与拥有维基百科简历的所有 NLP 研究人员的相对影响排名(y 轴)
正如你可以再次看到的,这些研究人员中约有 2/3 的影响力排名为 5000 或更低,只有少数离群值在远端,没有被 ACL 选集索引的 NLP 研究论文。因此,他们被分配了一个虚拟级别(可能的最高级别)。观察一些离群值,他们要么是在不被 ACL 选集索引的本地期刊上发表文章的 NLP 研究人员,要么主要不是 NLP 研究人员(但其他领域的研究人员,现在在行业中的前研究人员,或者根本不是主要研究人员的人)。
总体而言,由此可以得出结论,拥有 bios 的 NLP 研究人员在该领域的影响力远远高于没有拥有 BIOS 的研究人员,这与Samoilenko&Yasseri(2013)的发现相反。
国家和机构分析
最后,我很好奇,想知道谁有维基百科的简历是否存在国家或机构偏见。在最近的 ACL(NLP 中排名最高的会议)上,记录了每篇论文联系作者的国家或地区,会议组织者发现大多数研究论文来自美国(39%),其次是中国(24%),英国(6%),德国(6%)和日本(3%)。
注意,因为国家和地区在 ACL 调查中被合并,所以左图中的地区“大不列颠”和“爱尔兰”不能直接映射到其他图表中的国家“英国”和“爱尔兰”。“香港”和“中国”也是如此,它们在 ACL 调查中被视为独立的地区,但在维基百科中却不是独立的国家。
为了与维基百科上的研究人员进行比较,我考虑了一个人出生的国家,他们获得博士学位的机构和它位于哪个国家,以及最近的机构隶属关系和它位于哪个国家。所有这些都是从研究人员的维基百科页面手动获得的。在没有现成可用的地方,我在研究人员的机构网站上搜索这些信息,并相应地更新他们的维基百科页面。结果可以在下面看到。
左图:基于联系作者的 ACL 2020 论文的国家或地区分布;共有 779 篇论文被接受。右图:在维基百科上有简历的 NLP 研究人员最近被雇佣的国家。只有拥有最多两篇论文/维基百科简历的国家被明确命名。
显而易见,ACL 作者所在的国家(左)和拥有维基百科简历的 NLP 研究人员目前受雇的国家(右)之间存在明显的差异。有 57%的美国 NLP 研究人员拥有维基百科的简历,只有 39%的 ACL 2020 论文是由美国提交的。此外,在 ACL 2020 上发表的所有论文中,有 24%是由中国提交的,而只有 2%的维基百科关于 NLP 研究人员的简历是关于目前在中国的研究人员的。以色列、新加坡和加拿大各占 ACL 2020 认可的论文主要作者居住国的 3%,但在维基百科关于 NLP 研究人员的简历中却一个都没有。
左图:拥有维基百科简历的国家自然语言处理研究人员在。右图:拥有维基百科简历的 NLP 研究人员出生的国家。只有拥有最多两个维基百科传记的国家才被明确命名。
将 NLP 研究人员目前所在的国家与他们获得博士学位的国家和出生的国家进行比较,很明显,随着时间的推移,分布越来越倾向于以英语为主要语言的国家,在某种程度上是英国和加拿大,但特别是美国(34%出生于,52%获得博士学位,57%最近就业的国家)。
作为补充,这并不令人惊讶,这里是拥有维基百科简历的 NLP 研究人员获得博士学位的最著名的机构。
左图:拥有维基百科简历的 NLP 研究人员最近加入的机构。右图:NLP 研究人员获得博士学位的机构。
在这两种情况下,分布都是由美国的机构主导的,这些机构在 CSRankings 等排名中也名列前茅。虽然可以看出,并不是所有排名靠前的机构都在维基百科上的 NLP 简历中有大量出现,这意味着这可能部分是大学公关努力的结果。
总的来说,在每个国家发表的研究论文数量和被引用的程度上已经存在差异。当谈到维基百科上 NLP 学者的代表性时,这些问题进一步加剧,这使他们处于进一步的劣势。所以总的来说,在英文版的维基百科中,NLP 学者有很强的国家和机构偏见**。
这些偏见可能是由多种因素造成的,文化和资源可能是社会偏见的一部分。**
行动呼吁
总体而言,存在明显的国家和机构偏见,以及女性 NLP 学者在维基百科上的代表性不足。尽管性别偏见并不像我预期的那样明显有利于男性研究人员,但在 NLP 和更广泛的社会中,还有许多其他传统上代表性不足的群体。首先,性别不仅仅是二元性别,偏见也不仅仅是性别和制度偏见,例如种族、宗教、阶级、性别、残疾等方面的偏见。交叉性,即一个人身份的不同方面如何相互作用,也应予以考虑——研究人员可能面临不止一种类型的偏见,例如性别和种族偏见。我帮助发起的拓宽 NLP 倡议,旨在提高所有传统上在 NLP 中代表性不足的群体的代表性。作为这项计划的一部分,我维护着 NLP 中代表性不足的群体的大目录。如果你有兴趣支持这项倡议,并且有几个小时的空闲时间,为什么不为这个目录中的一个人创建一个维基百科个人资料呢?
如何开始
第一件要做的事当然是挑选一个值得维基百科关注的人。维基百科社区整理了一些关于这个的指南,不遵循这些指南的文章通常会被标记为删除。还要注意的是,文章应该从中立的角度来写,所以强烈反对写一篇关于你自己的维基百科文章。为了让你更容易理解,我将大目录与 NLP 学者数据集中有影响力的研究人员列表进行了交叉引用,你可以在这里找到结果。如果您为这些研究人员之一添加维基百科页面,请将维基百科页面链接添加到相应的栏中。具有高影响力指标的研究人员很可能通过显著性标准,但是没有高影响力指标并不意味着他们不显著,因为人们可能因为不同的原因而显著(也参见进一步的讨论)。
TL;博士;医生
一开始,我提出了以下研究问题:
1)有多少研究人员拥有维基百科传记,2)是否存在显著的性别差异,3)拥有一篇维基百科文章与对自然语言处理领域产生影响之间是否存在关联?以及 4)在谁拥有维基百科文章的问题上,是否存在任何可观察到的国家或机构偏见?
答案是:
- 138 名 NLP 研究人员拥有维基百科传记,而 ACL 选集有 45041 名独特的作者,该选集索引了所有著名的 NLP 期刊、会议和研讨会的会议记录。
2)拥有维基百科简历的自然语言处理作者中,37.2%为女性,明显低于男性。然而,ACL 选集中女性论文作者的比例估计在 25%到 33.5%之间,这意味着,相对于女性在 NLP 领域的代表性,女性在维基百科上的代表性更突出。 - 37%拥有维基百科简历的研究人员属于 NLP 研究人员中影响力排名最高的前 1%,仅根据他们的出版物计算。因此,可以得出结论,在拥有一篇维基百科文章和对 NLP 领域产生影响之间有很强的相关性。
4)美国有 57%的自然语言处理研究人员拥有维基百科的简历,只有 39%的 ACL 2020 论文是由美国提交的。此外,在 ACL 2020 上发表的所有论文中,有 24%是由中国提交的,而只有 2%的维基百科关于 NLP 研究人员的简历是关于目前在中国的研究人员的。拥有大量拥有维基百科资料的 NLP 学者的机构不一定在诸如 CSRankings 这样的排名中排名靠前。因此,可以得出结论,在自然语言处理学者的维基百科简历中,存在非常明显的国家和机构偏见。
遗言&致谢
谢谢你能走到这一步。如果你喜欢阅读这篇文章,并有评论或建议,请在下面留下。
感谢 Saif Mohammad 的有用和详细的反馈,以及分享 NLP 学者数据集。还要感谢巴里·诺顿、拉达·米哈尔恰、莫娜·迪亚卜、佩帕·阿塔纳索娃、瑞安·科特雷尔、嵇和塔马尔·索洛里奥分享了他们对本文的看法。也感谢 Pascale Fung 和 Smaranda Muresan 鼓励我写这篇文章。