原文:Domino Blog
用数据科学对抗儿童剥削
原文:https://www.dominodatalab.com/blog/fighting-child-exploitation-data-science
每天都有 10 万条新的三陪广告发布在网上。这是根据通过技术创新打击儿童性剥削的非营利组织 Thorn T1 的说法。Thorn 对未成年人性交易幸存者的其他研究表明,其中 63%的幸存者曾在网上做过广告。庞大的在线商业色情市场极难对抗,这激发了一年一度的黑客马拉松的开始,将跨行业的专家聚集在一起,致力于儿童安全。
多米诺团队来到了位于门洛帕克的明亮欢快的脸书总部,这是第二届 2017 年儿童安全黑客马拉松的会场,成群的志愿者涌入这里解决一个非常黑暗而真实的话题。工程、数据科学和政策领域最聪明的头脑正在联合力量开发寻找失踪儿童和保护儿童安全的技术解决方案,Domino 是他们的首选工具。
在日常运营中,Thorn 利用科技公司的知识、时间和资源来开发产品,让一线的专业人员能够用来打击儿童性剥削。他们构建的产品的主要组成部分体现了强大的数据科学技术。这就是为什么对于黑客马拉松来说,Thorn 在提供难以获得的儿童剥削数据方面发挥了重要作用。
任何人都可以参加 20 多种不同的挑战,具有工程和数据科学背景的志愿者被 Thorn 的项目所吸引,因为大多数项目需要网络抓取、机器学习、自然语言处理和图像识别专业知识。对于 Thorn 来说,参与这样的挑战并不是黑客马拉松活动独有的。他们依靠志愿者来解决这类问题,每天为执法部门开发真正的工具。
对于许多公司来说,即使拥有一个内部数据科学团队,也很难反复实验,然后为利益相关者和模型获得洞察并投入生产(即,投入下游工具和运营)。
对于 Thorn 来说,这种复杂性被放大了,因为捐款是不稳定的,志愿者来来去去。因此,Thorn 为志愿者提供一个平台,让他们立即开始项目工作,这一点至关重要。志愿者应该很容易从另一个志愿者停止的地方继续现有的工作,并将他们的工作保存在一个中心位置,这样 Thorn 即使在他们离开后也可以将其投入生产。
这也是 Thorn 使用 Domino 平台的原因。它作为一个中心枢纽,容纳了来自内部和志愿者数据科学家的所有工作。
对于 Domino 团队来说,儿童安全黑客马拉松是一次鼓舞人心和令人满意的经历。我们有机会看到 Thorn 如何使用多米诺骨牌来利用惊人的才华,以开发创新的方法来拯救儿童免受性剥削。
这对志愿者来说也是一次很棒的经历。当他们自己选择参加 Thorn 的挑战时,他们可以立即访问项目的数据、环境、模板和信息,因为它们存储在 Domino 中。他们能够立即开始与他们的新团队合作。其他团队的志愿者甚至过来问 Thorn 的团队怎么能这么快上手!
随着团队成员开始试验和编写代码,他们能够在平台内轻松分享算法进展,并与他人并排比较结果。使用 Thorn 专门为黑客马拉松提供的 AWS 实例,团队可以即时访问计算资源,进行快速实验和迭代。
最终,Thorn 带走了硅谷一些顶级技术人才制作的可复制的作品和原型,所有这些都是通过 Domino 的力量捕获和记录的。
混合/多云中的金融服务人工智能:利用混合 MLOps 控制数据重力
原文:https://www.dominodatalab.com/blog/financial-services-ai-in-the-hybrid-cloud
您如何平衡 FSI 的创新和效率需求与合规和善治需求?这是金融服务和保险行业需要回答的一个关键问题,因为人工智能、人工智能和混合/云计算是我们这个时代最重要的技术趋势。
他们已经彻底改变了我们的生活和工作方式,他们的潜力在 FSI 才刚刚开始实现。 根据彭博 最近的一项研究,从 2021 年到 2028 年,全球金融服务和保险市场的人工智能(AI)预计将产生 843 亿美元的收入,CAGR 将增长 21.4%。目前,金融服务公司通过增强人类决策,使其更快、更准确、更高效,来利用人工智能获得竞争优势。
然而,希望利用这两种趋势的公司通常会发现,他们需要在创新的竞争动力与治理和合规性需求之间取得平衡。过多的创新会导致混乱,而过多的治理会扼杀创新。关键是找到正确的平衡,有足够的治理来确保稳定性和问责制,但也有足够的创新来推动模型驱动的竞争优势。
最近的一份 Ventana Research 白皮书, 首席数据的 5 大 AI 考虑事项&分析高管、 注意到类似的挑战。虽然人工智能/人工智能的好处得到了广泛认可,97%的金融服务机构报告称人工智能/人工智能对于检测和防止欺诈非常重要,但各行业中十分之八的机构也指出了治理人工智能/人工智能的重要性,这凸显了数据和分析高管面临的创新与治理之间的艰难平衡。
这不一定非黑即白,因为头条新闻经常报道各自领域的市场领导者未能找到这种平衡。 例如,2017 年,Equifax 的一次数据泄露导致了 7 亿美元的结算 ,最近一次“小故障”导致了消费者的信用评分报告不正确——数据科学行业专家推测,这可能是由人工智能模型“数据漂移”引起的 ,如 VentureBeat 所报道。达美乐的托马斯·罗宾逊说,关键领域非常需要良好的监控
“数据科学的游戏时间结束了。更具体地说,对于那些创建产品模型的组织来说,如果这些模型的决策会影响人们的财务生活、健康结果和隐私,那么现在这些模型不与适当的监控和控制相结合就是不负责任的。”
金融服务公司的数据和分析高管面临着通过证明数据科学计划来从数据中提取价值的挑战,同时还要平衡治理,以确保他们的公司不会因为错误的原因而登上头条。
管理数据科学的卓越分析中心的崛起
为了在混合云环境中更好地治理数据科学,许多金融服务和保险公司正在转向“数据科学卓越中心(CoE)”战略,以推动整个企业中数据科学计划的创新最佳实践和治理。
有效的治理需要所有人工智能/人工智能活动的单一窗口显示,而创造模型驱动的竞争优势的金融服务公司正在实施各种形式的“分析/人工智能/人工智能卓越中心(CoE)”来推动人工智能/人工智能的采用。 DBRS 部署 Domino 作为所有数据项目组的中心平台,包括财务、研究和模型治理。同样, S & P Global 使用 Domino 作为“胶水”支撑程序,对 17,000 名分布在各地的员工进行数据科学教育。
CoE 策略在保险业中也很常见。好事达的 卓越分析中心 帮助他们将模型置于其业务的核心,利用数据作为转型企业资产。 纽约人寿的 数据科学和人工学习中心也完全沉浸在公司的核心业务中,能够在整个公司范围内进行实时的、基于模型的决策。 Topdanmark 的 机器学习卓越中心在欺诈检测、政策批准和风险管理的整个运营过程中注入模型,所有这些都是为了改善客户体验。 SCOR 的 数据科学卓越中心极大地促进了数据科学的采用,并帮助业务部门开发模型,以比以前快 75%的速度满足客户需求。
管理分布式敏感数据的激增
数据是有效机器学习计划的驱动力,跨环境(多种云、混合云和内部部署)的敏感分布式数据为金融服务数据和分析高管在 CoE 战略中集中和管理 AI/ML 带来了独特的挑战。
Ventana Research 最近发布的白皮书《首席数据和分析主管的 5 大人工智能考虑事项》指出,73%的组织报告称,不同的数据源和系统是实施数据科学治理政策时面临的最大挑战,数据科学家需要来自公司防火墙之外的大量数据加剧了这一挑战。
金融服务公司需要来自分支机构、在线和移动设备的数据。收购和合并也扩大了数据足迹,数据通常分布在云区域、提供商和内部数据源之间。根据同一份 Ventana Research 白皮书,32%的组织报告使用 20 个以上的数据源,而 58%的组织自我报告使用“大数据”——Pb 大小的数据库变得越来越普遍。
此外,最近的一篇 《华尔街日报》文章指出,医疗保险公司 Anthem 产生 1.5 到 2 Pb 的合成数据,旨在训练模型以检测欺诈并向会员提供个性化服务,凸显了这种分布式数据的“巨大”。Ventana Research 指出,“到 2025 年,超过四分之三的企业将把数据分散到多个云提供商和内部数据中心,这需要对跨多个位置的数据管理产品进行投资。”
这反映了 Domino 在我们自己的客户端中观察到的类似模式,将数据源与高级机器学习技术相结合,以获得模型驱动的竞争优势。在 Coatue ,替代数据源和新计算技术的激增产生了对识别可告知投资决策的信号的需求。 穆迪分析 通过基于独特的金融数据集创建分析并应用它们来解决客户的业务挑战,建立了竞争优势。
通过混合/多云策略利用数据重力
谈到大数据,尤其是“分布式”大数据,数据引力是需要理解的最重要的概念之一。数据引力是指大数据将其他数据、系统和服务/应用拉向它的趋势。因为人工智能和数据科学需要大量数据,所以制定收集、存储、处理和分析这些数据的策略非常重要。
性能只是一个重要的数据重心考虑因素——通过将数据和计算放在一起,可以减少模型延迟。 虽然托管云数据库在管理这种数据激增方面提供了一些希望,但流入和流出成本会极大地阻碍数据科学的努力——根据 Ventana Research 的数据,提取和分析 1pb 的数据可能需要高达 5 万美元。
除了性能考虑之外,数据驻留和数据主权法规进一步使数据收集和处理复杂化,通常将数据集锁定在单个地理位置、云或云区域。欧盟的数字运营弹性法案(DORA)“旨在确保金融系统中的所有参与者都有必要的安全措施来减轻网络攻击和其他风险”,并对供应商集中和供应商锁定提出了具体要求。更具体地说,对于 AI/ML, GDPR 有关于自动化决策和分析的规定 ,强调了混合和多云配置的重要性,以确保适当的数据管理和地理围栏。根据 Ventana 的研究:
“到 2026 年,几乎所有跨国组织都将投资本地数据处理基础设施和服务,以降低与数据传输相关的风险。”
考虑到数据传输成本、安全性、法规和性能,设计具有灵活性的 AI/ML 平台通常更有意义,它提供了将数据处理背后的计算与数据本身放在一起的选择,而不是跨云或地理位置传输或复制数据集。在分析卓越中心战略要求对治理的数据科学计划有一个整体的、企业范围的看法的背景下,数据和分析高管在构建其数据和分析基础架构时面临困难的决策。
针对混合/多云 MLOps 的数据科学平台考虑事项
寻求采用人工智能平台的金融服务和保险公司应专注于支持其混合企业 IT 战略的平台。这一战略包括平衡开放性、敏捷性和灵活的计算能力,以使业务面向未来。提供这些功能的平台将能够帮助企业快速决策,快速响应市场变化,并快速适应新技术或立法。
随着我们最近的 Nexus 混合云数据科学平台 的发布,Domino 数据实验室处于人工智能工作负载混合支持的前沿。一个真正的混合数据科学平台使数据科学家能够在公司运营的每个环境中以一种安全且管理良好的方式访问数据、计算资源和代码。我们与 NVIDIA 的深度 合作以及对 更广泛的数据和分析生态系统的支持 为数据和分析高管提供了培养 AI/ML 创新所需的信心,同时还提供了企业范围治理所需的灵活性。
Ventana Research 强调开放、灵活的数据科学平台的重要性;“面对不断发展的混合战略和不断变化的数据科学创新,让您的数据科学实践面向未来;以及从专门构建的人工智能基础设施(内部或云中)中实现价值最大化。”
要了解更多关于在企业中扩展人工智能的首要考虑因素,请查看 Domino 和 NVIDIA 委托的新 Ventana Research 白皮书。
金融服务和保险:推动未来的数据科学趋势
上周,多米诺庆祝数据科学创新者推动健康和生命科学的突破。本周,我们在数据科学创新者手册的金融服务和保险版中宣布了一批新的创新者, 现在可以免费下载 。像以前一样,金融服务和保险行业的每位顶级数据科学创新领导者都分享了他们对工作、职业和数据科学专业的见解。剧本包括七个简介,第一个是蒂芙尼·帕金斯-穆恩博士。
会见摩根大通公司的蒂芙尼·帕金斯-穆恩博士
Tiffany Perkins-Munn 博士是摩根大通公司的董事总经理兼营销数据和分析主管。她还是 ANA 教育基金会的董事会成员,是《CDO》杂志评选的 2021 年和 2022 年全球 100 大数据权力女性之一,也是 Data IQ 100 评选的 2022 年最具影响力的数据人物之一。
Perkins-Munn 博士的主要工作是开发金融模型和应用程序,以改善对金融产品和服务的访问和理解。“成本很少是关键驱动因素,”帕金斯-穆恩说。"情感通常是消费者选择中最重要的因素。"她敦促利益相关者将情感作为正在进行的研究的驱动力。“如果我今天对情绪决策的影响进行纵向研究,我认为它会比以往任何时候都高。”
Perkins-Munn 敦促职业生涯早期或中期的数据科学专业人员享受数据揭示几乎任何行业洞察力的能力。“理解数据和数据科学是少数可推断和可替代的技能之一。在许多领域,很难做出改变,但如果你理解数据,无论你是在医疗保健还是金融服务领域,技能都是一样的,并且可以转移和替代。”
对于珀金斯-穆恩来说,成功的一个关键方面是尽最大努力帮助非数据科学家理解数据对讲故事的意义。“众所周知,数据科学家无法消化他们所学到的东西,并将其融入一些小的金块和故事中,以解释为什么他们的工作对他们的业务和其他股东有如此大的影响。”实质上,“你必须能够讲述你的发现,”她说。
创新数据科学领导者的完整名单
下载我们的免费电子书 阅读 Perkins-Munn 和其他创新者、顾问和行业专家在金融服务和保险行业数据科学领域的所有见解。所有人都描述了他们的数据科学部门在团队规模和回答业务关键问题的中心地位方面的巨大增长。知名领袖的完整名单包括:
- 蒂芙尼帕金斯-穆恩博士——董事总经理,营销数据负责人&分析处 摩根大通&公司
- 莫希特贾恩博士——数据科学/机器学习主管 BNY 梅隆财富管理
- 格伦·霍夫曼博士——首席分析官 纽约人寿
- 【安珠古普塔】——西北互助数据科学与分析副总裁
- Meg Walters,——Allstate旗下卓越分析中心(CoE)
- Vincent Walden,注册会计师,CFE——2022 年度注册舞弊审查员,Kona AICEO
- 杰夫·乔纳斯——首席执行官、 森金 创始人兼首席科学家
电子书 还包含了两位行业合作者对这个项目的见解。首先是 NVIDIA 的 Mark J. Bennett ,计算机科学家、金融工程师、技术经理、教育家。Bennett 为我们提供了他在金融前沿技术(如量子计算)方面的丰富经验。加入他的还有 SCOR 首席数据科学官安托万·利和 凯特尔 首席运营官纳撒尼尔·曼宁,他们都提供了对保险行业创新的见解。
结论
我们希望这篇介绍能鼓励您 下载免费电子书 ,并享受我们的特色行业专家分享的其他见解。这些创新领导者的评论可以激发新的研究或想法,促进你自己的职业生涯。这些想法还可以帮助您组织的团队利用 MLOps 平台扩展数据科学,并让您的项目顺利完成。我们邀请您阅读金融服务和保险版的 数据科学创新者行动手册 ,了解如何加速数据科学创新的价值。
炉边谈话:来自托普丹马克的斯蒂格·彼得森
原文:https://www.dominodatalab.com/blog/fireside-chat-stig-pedersen-from-topdanmark
“有了一两个非常成功的算法部署,企业就开始向你寻求帮助。这变成了一种相互交流,每个人都想要价值或储蓄。” —斯蒂格·彼得森
在这个新系列中,我们将与机器学习和数据科学领域的领导者交谈,了解他们是如何开始从事数据科学的,并围绕他们认为领导数据科学团队的关键成功因素提出一系列问题。
我们的第一次炉边谈话是与丹麦领先的保险解决方案提供商 Topdanmark 负责机器学习和数据科学的 Stig pede rsen 进行的。
谈话要点
Stig Pedersen 进入数据科学技术领域,最初是作为其他技术商业化业务部门的一部分工作。在最初致力于在内部部署机器人流程自动化模型之后,Stig 看到了机器学习和数据科学的价值潜力,并着手建立一个数据科学家团队,以构建算法和模型来帮助提高效率,并最终在保险公司内部创造价值。
他是如何在 Topdanmark 内部开始数据科学的。
我来自业务中“我们需要一些东西”的那一方,但我一直以技术为导向。我们从零开始建立这个团队,并与外部咨询公司合作开始
在商业和数据科学家之间培养良好的文化。
如果企业不信任你的数据科学家和他们的算法,你就失去了全部意义。
我们实际做的很简单,但是很管用。我们寻求与业务部门就我们想要做的事情达成一致,然后我们开始开发一种算法,并大致了解我们可以将它推进到什么程度,但我们直到他们接受这一点,并将我们与部门中最重要的主题专家之一联系起来,才开始构建。
创造一个可持续的有趣问题解决渠道。
这是所有先进技术的关键问题。你可以说它以这样或那样的方式取代人类,或者支持他们做决定。
我不认为你能提前三年规划一个管道,但是一旦你证明了你能在特定领域创造价值;例如索赔区,那么经理们会要求你帮助他们解决更多的问题。
你不能总是预测分析需要多长时间,但是展示可以产生的潜在价值是如此巨大,以至于值得投资;每当我们觉得我们的渠道可能开始枯竭,我们就会有新的项目出现,它们的价值与以前的项目相同甚至更高
解决基础设施问题如何让他的团队专注于解决业务问题。
如果没有合适的基础设施,你就会迷失方向。我们真的需要一个机器学习平台。你需要代码运行的版本,谁部署了什么,以及选择他们想要使用什么开源工具的自由
有了多米诺数据实验室 ,他们可以自由地做他们需要做的事情,他们从来不会对技术有任何疑问——因为他们只是继续做下去。比如音乐家弹钢琴,或者拿起小提琴
关于 top land
Topdanmark 是丹麦领先的非寿险和寿险产品提供商之一。
他们在机器人流程自动化和机器学习技术方面进行了大量投资,以提高效率并在组织内部制定更好的决策。
在 Python 中拟合高斯过程模型
原文:https://www.dominodatalab.com/blog/fitting-gaussian-process-models-python
一个常见的应用统计学任务包括建立回归模型来描述变量之间的非线性关系。通过采用特定的非线性函数形式,如正弦函数、指数函数或多项式函数来描述一个变量对另一个变量的变化的响应,来拟合这种模型是可能的。然而,除非这种关系从一开始就很明显,否则它可能涉及大量的模型选择程序,以确保保留最合适的模型。或者,可以通过定义变量空间上的一组结来采用非参数方法,并使用样条或核回归来描述任意非线性关系。然而,结布局程序有些特别,也可能涉及变量选择。第三种选择是采用贝叶斯非参数策略,直接对未知的基础函数建模。为此,我们可以采用高斯过程模型。
将贝叶斯过程描述为“非参数的”有点用词不当。建立贝叶斯模型的第一步是为手头的问题指定一个全概率模型,为每个模型变量分配概率密度。因此,在不使用概率函数的情况下,很难指定一个完整的概率模型,因为概率函数是参数化的!事实上,贝叶斯非参数方法并不意味着没有参数,而是参数的数量随着数据集的大小而增长。相反,贝叶斯非参数模型是无限参数化的。
用高斯模型构建模型
如果我们选择使用高斯分布来模拟我们的数据会怎么样?
$$
p(x \mid \pi,\ sigma)=(2\pi){-k/2}|\sigma|{-1/2} \ exp \ left \ {-\ frac { 1 } { 2 }(x-\mu){\prime}\sigma{-1}(x-\mu)\ right \ }
$ $
这样做似乎没有任何好处,因为正态分布本身并不是特别灵活的分布。然而,采用一组高斯分布(多变量法向向量)有许多优点。首先,多元正态分布中任何元素子集的边际分布也是正态的:
$$
p(x,y)= \ mathcal { n } \ left(\ left[{
\ begin { array } { c }
{ \ mu _ x } \
{ \ mu _ y } \
\ end { array }
} \ right],\ left[{
\ begin { array } { cc }
{ \ sigma _ x }&{ \ sigma _ { xy } } \
{\sigma_{xy}^t}&{ \ sigma _ y }
\ end
KaTeX parse error: Undefined control sequence: \适 at position 44: …thcal{N}(\mu_x,\̲适̲马 _x)
此外,多元正态分布的元素子集的条件分布(取决于剩余元素)也是正态的:
$ $
p(x | y)= \ mathcal { n }(\ mu _ x+\sigma_{xy}\sigma_y^{-1}(y-\mu_y),
\sigma_x-\sigma{xy}\sigma_y{-1}\sigma{xy}t)
$ $
高斯过程将多元常态推广到无限维度。它被定义为随机变量的无限集合,任何边缘子集都具有高斯分布。因此,边缘化属性在其定义中是明确的。另一种思考无限向量的方式是作为一个 T2 函数 T3。当我们编写一个将连续值作为输入的函数时,我们实际上是在暗示一个无限的向量,它只在函数被调用时返回值(由输入索引)。同样,无限维高斯表示为函数的概念允许我们通过计算来处理它们:我们从来不需要存储高斯过程的所有元素,只需要在需要时计算它们。
因此,我们可以将高斯过程描述为函数上的分布。正如多元正态分布完全由均值向量和协方差矩阵指定一样,GP 完全由均值函数和协方差函数指定:
p
(
x
)
∼
G
P
(
m
(
x
)
,
k
(
x
,
x
′
)
)
p(x) \sim \mathcal{GP}(m(x),k(x,x^{\prime}))
p(x)∼GP(m(x),k(x,x′))
正是这种边缘化特性使得使用高斯过程变得可行:我们可以边缘化我们不感兴趣或没有观察到的无限多的变量。
例如,GP 的一个规格可能是:
这里,协方差函数是一个的平方指数,对于它,靠近的[latex]x[/latex]和[latex]x^{\prime}[/latex]的值导致[latex]k[/latex]的值更接近于 1,而远离的值返回更接近于 0 的值。简单地采用零函数来表示高斯过程的均值函数似乎有些奇怪——当然我们可以做得更好!事实证明,GP 中的大部分学习涉及协方差函数及其超参数,因此在指定复杂的均值函数时获得的收益很少。
对于有限数量的点,GP 成为多元正态,均值和协方差分别作为在这些点上评估的均值函数和协方差函数。
从高斯过程中取样
为了使“函数分布”的概念更加具体,让我们快速演示如何从高斯过程中获得实现,这导致对一组点上的函数的评估。我们在这里要做的是来自之前高斯过程的样本,所以在引入任何数据之前。我们首先需要的是我们的协方差函数,它将是指数的平方,以及一个在给定点评估协方差的函数(产生一个协方差矩阵)。
import numpy as np
def exponential_cov(x, y, params):
return params[0] * np.exp( -0.5 * params[1] * np.subtract.outer(x, y)**2)
我们将利用多元高斯分布的可爱的条件属性,逐点依次生成实现。这是有条件的:
$ $
p(x | y)= \ mathcal { n }(\ mu _ x+\sigma_{xy}\sigma_y^{-1}(y-\mu_y),
\sigma_x-\sigma{xy}\sigma_y{-1}\sigma{xy}t)
$ $
这是实现它的函数:
def conditional(x_new, x, y, params):
B = exponential_cov(x_new, x, params)
C = exponential_cov(x, x, params)
A = exponential_cov(x_new, x_new, params)
mu = np.linalg.inv(C).dot(B.T).T.dot(y)
sigma = A - B.dot(np.linalg.inv(C).dot(B.T))
return(mu.squeeze(), sigma.squeeze())
我们将从超参数σ_0=1,σ_1=10 的高斯过程开始。我们还将假设一个零函数作为平均值,因此我们可以绘制一个代表平均值的一个标准差的波段。
import matplotlib.pylab as plt
θ = [1, 10]
σ_0 = exponential_cov(0, 0, θ)
xpts = np.arange(-3, 3, step=0.01)
plt.errorbar(xpts, np.zeros(len(xpts)), yerr=σ_0, capsize=0)
让我们选择一个任意的采样起点,比如 x=1。由于没有先前的点,我们可以从一个无条件的高斯样本:
x = [1.]
y = [np.random.normal(scale=σ_0)]
print(y)
[0.4967141530112327]
我们现在可以更新我们的置信带,给定我们刚刚采样的点,使用协方差函数生成新的逐点区间,条件是值[x_0,y_0]。
σ_1 = exponential_cov(x, x, θ)
def predict(x, data, kernel, params, sigma, t):
k = [kernel(x, y, params) for y in data]
Sinv = np.linalg.inv(sigma)
y_pred = np.dot(k, Sinv).dot(t)
sigma_new = kernel(x, x, params) - np.dot(k, Sinv).dot(k)
return y_pred, sigma_new
x_pred = np.linspace(-3, 3, 1000)
predictions = [predict(i, x, exponential_cov, θ, σ_1, y) for i in x_pred]
y_pred, sigmas = np.transpose(predictions)
plt.errorbar(x_pred, y_pred, yerr=sigmas, capsize=0)
plt.plot(x, y, "ro")
因此,根据这一点,以及我们指定的协方差结构,我们基本上限制了附加点的可能位置。现在让我们来看另一个例子:
m, s = conditional([-0.7], x, y, θ)
y2 = np.random.normal(m, s)
print(y2)
-0.1382640378102619
这个点被添加到实现中,并且可以用于进一步更新下一个点的位置。
x.append(-0.7)
y.append(y2)
σ_2 = exponential_cov(x, x, θ)
predictions = [predict(i, x, exponential_cov, θ, σ_2, y) for i in x_pred]
y_pred, sigmas = np.transpose(predictions)
plt.errorbar(x_pred, y_pred, yerr=sigmas, capsize=0)
plt.plot(x, y, "ro")
当然,顺序采样只是演示协方差结构如何工作的一种启发式方法。我们可以很容易地一次采样几个点:
x_more = [-2.1, -1.5, 0.3, 1.8, 2.5]
mu, s = conditional(x_more, x, y, θ)
y_more = np.random.multivariate_normal(mu, s)
print(y_more)
array([-1.5128756 , 0.52371713, -0.13952425, -0.93665367, -1.29343995])
x += x_more
y += y_more.tolist()
σ_new = exponential_cov(x, x, θ)
predictions = [predict(i, x, exponential_cov, θ, σ_new, y) for i in x_pred]
y_pred, sigmas = np.transpose(predictions)
plt.errorbar(x_pred, y_pred, yerr=sigmas, capsize=0)
plt.plot(x, y, "ro")
因此,随着点的密度变高,它导致了来自先前 GP 的实现(样本函数)。
在 Python 中拟合高斯过程
尽管完全有可能扩展上面的代码来引入数据并手动拟合高斯过程,但是有许多库可用于以更自动化的方式指定和拟合 GP 模型。我将演示和比较三个包含专门为 GP 建模定制的类和函数的包:
特别是,这些软件包中的每一个都包括一组协方差函数,可以灵活地组合以充分描述数据中的非线性模式,以及拟合 GP 参数的方法。
我们将使用一些模拟数据作为测试用例来比较每个包的性能。实际上,我不记得我是在哪里找到这些数据的,所以我不知道这些数据是如何产生的。然而,它清楚地显示了某种类型的非线性过程,受到一定量的观察或测量误差的破坏,因此它应该是高斯过程方法的合理任务。
scikit-learn
scikit-learn
是 Python 的绝世机器学习库。它提供了一套全面的监督和非监督学习算法,在一致、简单的 API 下实施,使您的整个建模管道(从数据准备到输出汇总)尽可能无摩擦。它的工具库中包括一个 Gaussian 流程模块,该模块最近经历了一次完整的修订(从版本 0.18 开始)。
与scikit-learn
中其他机器学习方法的实现一致,使用 GPs 的适当接口取决于它所应用的任务类型。对于回归任务,我们预测一个连续的响应变量,通过指定一个适当的协方差函数应用一个GaussianProcessRegressor
,或核。拟合通过最大化边际似然的对数进行,这是一种高斯过程的便利方法,避免了通常用于选择模型最佳超参数的计算密集型交叉验证策略。GaussianProcessRegressor
不考虑均值函数的规格,总是假设它是零函数,强调了均值函数在计算后验概率中的作用减弱。
对于输出变量为二进制或分类的分类任务,使用GaussianProcessClassifier
。使用正态分布来拟合分类数据,这似乎是不协调的,但通过使用潜在的高斯响应变量,然后将其转换为单位区间(或者更一般地,对于两个以上的结果类,一个单纯形),可以适应这种情况。其结果是一种软的概率分类,而不是机器学习算法中常见的硬分类。与回归设置类似,用户选择适当的核来描述数据集中预期的协方差类型。因为这个 GP 的后验概率是非正态的,所以使用拉普拉斯近似来获得解,而不是最大化边际可能性。
from sklearn import gaussian_process
from sklearn.gaussian_process.kernels import Matern, WhiteKernel, ConstantKernel
scikit-learn
提供了一个大约十几个协方差函数的库,他们称之为核,以供选择。一个灵活的选择是从 Matèrn 协方差开始。
$ $
k _ { m }(x)= \frac{\sigma2}{\Gamma(\nu)2{\nu-1}} \左(\ frac { \ sqrt { 2 \ nu } x}{l}\right)^{\nu} k _ { \ nu } \左(\ frac { \ sqrt { 2 \ nu } x } { l } \右)
$
其中
Γ
\Gamma
Γ是 gamma 函数,
K
K
K是修正的贝塞尔函数。从该函数采样的协方差矩阵的形式由三个参数控制,每个参数控制协方差的一个属性。
- 振幅 ( σ \sigma σ)控制输出沿 y 轴的缩放。该参数只是一个标量乘数,因此通常不包含在 Matèrn 函数的实现中(即设置为 1)
- lengthscale ( l l l)通过缩放 x 轴上的实现来补充振幅。较大的值会将点沿此轴推得更近。
- 粗糙度 ( ν \nu ν)控制协方差函数中脊的锐度,最终影响实现的粗糙度(平滑度)。
虽然一般来说,所有参数都是非负实值的,但是当整数值 p p p的 ν = p + 1 / 2 \nu = p + 1/2 ν=p+1/2时,该函数可以部分地表示为 p p p阶的多项式函数,并且生成 p p p次可微的实现,因此{3/2,5/2} 中的值 中的值 中的值 \ nu \是最常见的。
GP 核可以简单地通过使用 sum 运算符指定为scikit-learn
中的加性分量之和,因此我们可以包括 Matèrn 分量(Matern
)、振幅因子(ConstantKernel
)以及观察噪声(WhiteKernel
):
kernel = ConstantKernel() + Matern(length_scale=2, nu=3/2) + WhiteKernel(noise_level=1)
如前所述,scikit-learn
API 在不同的学习方法中非常一致,因此,所有函数都期望一组表格形式的输入变量,要么是二维数字array
要么是熊猫DataFrame
。由于这里只有一个输入变量,我们可以使用reshape
方法添加第二个维度:
X = x.reshape(-1, 1)
print(X.shape)
(101, 1)
最后,我们用自定义内核实例化一个GaussianProcessRegressor
对象,并调用它的fit
方法,传递输入(X
)和输出(y
)数组。
gp = gaussian_process.GaussianProcessRegressor(kernel=kernel)
gp.fit(X, y)
GaussianProcessRegressor(alpha=1e-10, copy_X_train=True,
kernel=1**2 + Matern(length_scale=2, nu=1.5) + WhiteKernel(noise_level=1),
n_restarts_optimizer=0, normalize_y=False,
optimizer='fmin_l_bfgs_b', random_state=None)
为了方便起见,scikit-learn
在每次实例化拟合算法的一个类时,显示用于拟合算法的配置。这很有用,因为它显示了隐藏的设置,如果用户没有指定,这些设置将被赋予默认值;这些设置通常会强烈影响最终的输出,所以我们理解fit
代表我们假设了什么是很重要的。在这里,例如,我们看到 L-BFGS-B 算法已经被用于优化超参数(optimizer='fmin_l_bfgs_b'
),并且输出变量还没有被标准化(normalize_y=False
)。当在边际可能性中存在找到局部最大值而不是全局最大值的危险时,可以为n_restarts_optimizer
指定一个非零值,它将使用随机选择的起始坐标运行优化算法指定的次数,希望可以发现一个具有全局竞争力的值。
fit
方法赋予返回的模型对象与拟合过程相关的属性;这些属性的名称后面都有一个下划线(_
)。例如,kernel_
属性将返回用于参数化 GP 的内核,以及它们相应的最佳超参数值:
gp.kernel_
0.00316**2 + Matern(length_scale=1.11, nu=1.5) + WhiteKernel(noise_level=0.0912)
除了fit
方法,每个监督学习类都保留一个predict
方法,该方法在给定一组新的预测器(
X
∗
X^{\ast}
X∗)的情况下生成预测结果(
y
∗
y^{\ast}
y∗ ),这些预测器不同于用于拟合模型的预测器。对于高斯过程,这是通过后验预测分布来实现的,后验预测分布是高斯过程,其均值和协方差函数在拟合后更新为后验形式。
p
(
y
∗
∣
y
,
x
,
x
∗
)
=
g
p
(
m
∗
(
x
∗
)
,
k
∗
(
x
∗
)
)
p(y^{\ast}|y,x,x^{\ast})= \mathcal{gp}(m^{\ast}(x^{\ast}),k^{\ast}(x^{\ast}))
p(y∗∣y,x,x∗)=gp(m∗(x∗),k∗(x∗))
其中后验均值和协方差函数计算如下:
$ $
m{\ast}(x{\ast})= k(x{\ast},x)t[k(x,x)+\sigma2i]{-1}y $ $
$ $ k{\ast}(x{\ast})= k(x{\ast},x{\ast})+\sigma2-k(x{\ast},x)t[k(x,x)+\sigma2i]{-1}k(x{\ast},x)
$ $
x_pred = np.linspace(-6, 6).reshape(-1,1)
y_pred, sigma = gp.predict(x_pred, return_std=True)
注意,我们可以计算任意输入
X
∗
X^*
X∗.的预测为了在一系列可能的输入上获得后验形式的感觉,我们可以像上面所做的那样传递一个线性空间给它。predict
可选地返回后验标准差和期望值,因此我们可以使用它来绘制期望函数周围的置信区域。
GPflow
谢菲尔德机器学习小组的 GPy 是早期的项目之一,它提供了一个独立的包来拟合 Python 中的高斯过程。与scikit-learn
的gaussian_process
模块非常相似,GPy 提供了一组用于指定和拟合高斯过程的类,拥有一个大型内核库,可以根据需要进行组合。GPflow 是 GPy 库的重新实现,使用谷歌广受欢迎的 TensorFlow 库作为其计算后端。对于大多数用户来说,这种变化的主要优势在于,它允许使用更现代的方法来拟合更大的 GP 模型,即变分推断和马尔可夫链蒙特卡罗。
让我们通过拟合模拟数据集来演示 GPflow 的使用。API 比scikit-learns
更通用,因为它期望预测器(特征)和结果的表格输入。因此,我们必须将y
重塑为表格格式:
Y = y.reshape(-1,1)
为了反映我们的scikit-learn
模型,我们将再次指定 Matèrn 协方差函数。GPflow 有两个面向用户的子类,一个将粗糙度参数固定为 3/2 ( Matern32
),另一个固定为 5/2 ( Matern52
)。振幅是一个包含的参数(variance
,所以我们不需要包含一个单独的常数内核。
import GPflow
k = GPflow.kernels.Matern32(1, variance=1, lengthscales=1.2)
有六种不同的 GP 类,根据协方差结构(完全与稀疏近似)和模型的似然性(高斯与非高斯)进行选择。GPflow 的主要创新在于,非共轭模型(即具有非正态可能性的模型)可以使用马尔可夫链蒙特卡罗或通过变分推理的近似来拟合。
由于我们的模型涉及一个简单的共轭高斯似然,我们可以使用GPR
(高斯过程回归)类。
m = GPflow.gpr.GPR(X, Y, kern=k)
我们可以简单地通过打印回归模型对象来访问参数值。
print(m)
model.likelihood.[1mvariance[0m transform:+ve prior:None
[ 1.]
model.kern.[1mvariance[0m transform:+ve prior:None
[ 1.]
model.kern.[1mlengthscales[0m transform:+ve prior:None
[ 1.2]
请注意,除了 Matèrn 核的超参数之外,还有一个与正态似然相关的方差参数。我们可以通过直接赋值将其设置为非默认值。
m.likelihood.variance = 0.01
该模型使用optimize
方法拟合,该方法对模型似然性运行梯度上升算法(它使用 SciPy 的minimize
函数作为默认优化器)。
m.optimize()
fun: 54.247759719230544
hess_inv:
jac: array([ 3.09872076e-06, -2.77533999e-06, 2.90014453e-06])
message: b'CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL'
nfev: 16
nit: 15
status: 0
success: True
x: array([-2.3496958, 0.3208171, 0.6063578])
print(m)
名字 | 价值观念 | 在先的;在前的 | 限制 |
---|---|---|---|
模型.可能性.方差 | [ 0.09111893] | 没有人 | +ve |
模型.内核.方差 | [ 0.86636739] | 没有人 | +ve |
型号.内核.长度刻度 | [ 1.04159852] | 没有人 | +ve |
模型对象包含一个predict_y
属性,我们可以用它来获得任意输入值网格上的期望值和方差。
你可能已经注意到,我们在这里所做的没有什么特别的贝叶斯理论。没有指定先验,我们只是执行了最大似然法来获得解决方案。然而,priors 可以被分配为变量属性,适当地使用 GPflow 的一组分布类中的任何一个。
m.kern.variance.prior = GPflow.priors.Gamma(1,0.1)
m.kern.lengthscales.prior = GPflow.priors.Gamma(1,0.1)
除了指定超参数的先验,如果我们有信息证明这样做是正确的,我们也可以固定值。例如,我们可能知道数据采集仪器的测量误差,因此我们可以将该误差值指定为常数。
m.likelihood.variance = 0.1
m.likelihood.variance.fixed = True
m.optimize()
fun: 63.930638821012721
hess_inv:
jac: array([ -3.35442341e-06, 8.13286081e-07])
message: b'CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL'
nfev: 8
nit: 6
status: 0
success: True
x: array([-0.75649791, -0.16326004])
虽然我们可能对自己有一个合适的贝叶斯模型感到满意,但最终结果是一样的。我们所做的只是将先验的对数概率添加到模型中,并再次进行优化。这一次,结果是最大后验 (MAP)估计。
print(m)
model.likelihood.[1mvariance[0m transform:+ve prior:None [FIXED]
[ 0.1]
model.kern.[1mvariance[0m transform:+ve prior:Ga([ 1.],[ 0.1])
[ 0.38479193]
model.kern.[1mlengthscales[0m transform:+ve prior:Ga([ 1.],[ 0.1])
[ 0.6148462]
为了执行“完全贝叶斯”分析,我们可以使用更通用的GPMC
类,它对参数和函数进行联合采样。为此,我们需要指定核参数的似然性和先验性。我们稍微改变一下模型,用一个学生的 T 似然,对极值的影响会更稳健。
l = GPflow.likelihoods.StudentT()
m = GPflow.gpmc.GPMC(X, Y, kern=k, likelihood=l)
m.kern.variance.prior = GPflow.priors.Gamma(1,1)
m.kern.lengthscales.prior = GPflow.priors.Gamma(1,1)
我们使用sample
方法来拟合GPMC
模型,而不是optimize
。这将采用哈密尔顿蒙特卡罗 (HMC),一种有效形式的马尔可夫链蒙特卡罗,利用梯度信息来改善后验采样。TensorFlow 库提供自动微分功能,允许为任意模型计算梯度。HMC 算法需要确定超参数值的规范,这些值决定了采样过程的行为;这些参数是可以调整的。
trace = m.sample(1000, verbose=True, epsilon=0.03, Lmax=15)
Iteration: 100 Acc Rate: 94.0 %
Iteration: 200 Acc Rate: 88.0 %
Iteration: 300 Acc Rate: 96.0 %
Iteration: 400 Acc Rate: 93.0 %
Iteration: 500 Acc Rate: 97.0 %
Iteration: 600 Acc Rate: 94.0 %
Iteration: 700 Acc Rate: 96.0 %
Iteration: 800 Acc Rate: 92.0 %
Iteration: 900 Acc Rate: 96.0 %
Iteration: 1000 Acc Rate: 91.0 %
我们最终得到一个包含来自核参数的采样值的轨迹,在得到数据信息后,可以绘制该轨迹来了解其值的后验不确定性。
parameter_samples = m.get_samples_df(trace)
for col in parameter _ samples . columns . sort _ values()[1:]:
parameter _ samples[col]。hist(label=col.split(’ . '))[-1],alpha=0.4,bin = 15)
[/code]
然后,我们可以回过头来从后验 GP 生成预测,并绘制其中的几个来了解预测的基本函数。
realizations = []
for sample in trace[-100:]:
m.set_state(sample)
realizations.append(m.predict_f_samples(xx, 1).squeeze())
realizations = np.vstack(realizations)
因此,使用 GPflow 代替scikit-learn
可能有利于具有异常似然函数的模型或难以使用梯度上升优化方法拟合的模型的用户。此外,如果关于 GP 超参数的推断是令人感兴趣的,或者如果存在将有助于获得更精确估计的先验信息,则诸如由 GPflow 的模型类提供的完全贝叶斯方法是必要的。
PyMC3
PyMC 项目是一个用于概率编程的非常通用的 Python 包,几乎可以用于任何贝叶斯模型(披露:自从 PyMC 创建以来,我一直是它的开发者)。与 GPflow 类似,当前版本(PyMC3)从早期版本重新设计,以依赖现代计算后端。PyMC3 不是 TensorFlow,而是构建在 Theano 之上,Theano 是一个用于计算根据张量运算定义的表达式的引擎。至少从表面上看,它的工作方式与 TensorFlow 非常相似,提供了自动微分、并行计算和高效编译代码的动态生成。
import pymc3 as pm
import theano.tensor as tt
PyMC3 是一个贝叶斯建模工具包,提供均值函数、协方差函数和概率分布,可以根据需要组合起来构建高斯过程模型。通过声明变量和变量的函数来指定模型,以指定完全贝叶斯模型。声明是在一个Model
上下文中进行的,该上下文自动将它们添加到模型中,为拟合做准备。让我们首先实例化一个模型,并添加一个 Matèrn 协方差函数及其超参数:
with pm.Model() as gp_fit:
ρ = pm.Gamma('ρ', 1, 1)
η = pm.Gamma('η', 1, 1)
K = η * pm.gp.cov.Matern32(1, ρ)
我们可以通过指定均值函数(这在这里是多余的,因为在未指定时假设零函数)和观测噪声变量来继续构建我们的模型,我们将给出半柯西先验:
with gp_fit:
M = pm.gp.mean.Zero()
σ = pm.HalfCauchy('σ', 2.5)
高斯过程模型封装在GP
类中,由上面指定的均值函数、协方差函数和观测误差参数化。由于 GP 的结果已经被观察到,我们将该数据作为字典提供给observed
参数中的GP
的实例。这些被提供给潜在的多元正态似然。
with gp_fit:
y_obs = pm.gp.GP('y_obs', mean_func=M, cov_func=K, sigma=σ, observed={'X':X, 'Y':y})
在Model
上下文中调用的sample
函数符合使用 MCMC 采样的模型。默认情况下,PyMC3 使用 HMC 的自动调整版本,称为无掉头采样器 (NUTS),它为路径长度和步长参数选取适当的值,我们在 GPflow 的sample
调用中看到了这些值。此外,为了将采样器初始化为合理的起始参数值,在 NUTS 之前运行变分推理算法,以产生所有参数的近似后验平均值。
with gp_fit:
trace = pm.sample(2000, n_init=20000)
Auto-assigning NUTS sampler...
Initializing NUTS using advi...
Average ELBO = -61.619: 100%|██████████| 20000/20000 [00:53<00:00, 376.01it/s]
Finished [100%]: Average ELBO = -61.55
100%|██████████| 2000/2000 [00:54<00:00, 36.69it/s]
pm.traceplot(trace[-1000:], varnames=['ρ', 'σ', 'η']);
除了拟合模型,我们还希望能够生成预测。这意味着从后验预测分布中取样,如果你还记得的话,这只是一些线性代数:
\ begin { aligned }
m{\ast}(x{\ast})&= k(x{\ast},x)t[k(x,x)+\sigma2i]{-1}y \
k{\ast}(x{\ast})&= k(x{\ast},x{\ast})+\sigma2-k(x{\ast},x)t[k(x,x)+\sigma2i]{-1}k(x{\ast},x)
\ end { aligned }
PyMC3 允许在模型拟合后进行预测采样,使用模型参数的记录值来生成样本。sample_gp
函数实现上面的预测 GP,用样本轨迹、GP 变量和生成实现的网格点调用:
Z = np.linspace(-6, 6, 100).reshape(-1, 1)
with gp_fit:
gp_samples = pm.gp.sample_gp(trace[1000:], y_obs, Z, samples=50)
100%|██████████| 50/50 [00:06<00:00, 7.91it/s]
对于适合非常大的数据集的模型,人们经常发现 MCMC 拟合非常慢,因为需要在采样算法的每次迭代中评估模型的对数概率。在这些情况下,使用变分推断方法可能是值得的,这种方法用更简单的近似值代替真实的后验概率,并使用优化将近似值参数化,使其尽可能接近目标分布。因此,后验概率只是一个近似值,有时是一个不可接受的粗略值,但对于许多问题来说是一个可行的替代方案。更新的变分推理算法正在出现,它们提高了近似的质量,这些算法最终会进入软件。同时,变分高斯近似和自动微分变分推理现在分别在 GPflow 和 PyMC3 中可用。
结论
Python 用户非常幸运,拥有如此多的选项来构建和拟合非参数回归和分类模型。我展示了使用scikit-learn
将 GP 模型拟合到连续值数据的简单性,以及如何使用 GPflow 或 PyMC3 将这种模型扩展到更一般的形式和更复杂的拟合算法。鉴于在如此多的环境中变量之间普遍存在非线性关系,高斯过程应该出现在任何应用统计学家的工具包中。我经常发现自己,而不是建立独立的 GP 模型,将它们作为一个更大的层次模型中的组件,以充分考虑非线性混杂变量,如生物统计学应用中的年龄效应,或强化学习任务中的函数逼近。
这篇文章远不是对 Python 中拟合高斯过程的软件工具的全面调查。我选择这三个库是因为我自己对它们很熟悉,并且因为它们在自动化和灵活性之间的权衡中占据不同的位置。你可以使用 GPy、 Stan 、 Edward 和 George 来轻松实现这样的模型,这里仅举几个比较流行的包。我鼓励您尝试其中的几种,以了解哪一种最适合您的数据科学工作流程。
基于二次规划的支持向量机拟合
原文:https://www.dominodatalab.com/blog/fitting-support-vector-machines-quadratic-programming
在这篇博文中,我们深入探讨了支持向量机的内部原理。我们导出了一个线性 SVM 分类器,解释了它的优点,并展示了通过 cvx opt(Python 的凸优化包)求解时的拟合过程。
支持向量机(SVM)是一种监督学习模型,在文本分类(Joachims,1998)、图像识别(Decoste 和 schlkopf,2002)、图像分割(Barghout,2015)、异常检测(schlkopf 等人,1999)等领域有着广泛的应用。
Figure 1 - There are infinitely many lines separating the two classes, but a good generalisation is achieved by the one that has the largest distance to the nearest data point of any class.
图 1 显示了 Fisher 虹膜数据集的样本(Fisher,1936)。该示例包含两个类的所有数据点,即鸢尾 (-1)和鸢尾 (+1),并且只使用了四个原始特征中的两个,即花瓣长度和花瓣宽度。这种选择产生了一个明显可线性分离的数据集,并且很容易确认存在无限多的超平面来分离这两个类。然而,选择最佳决策边界并不是一个简单的过程。红色和蓝色虚线将两个类别完全分开。然而,红线距离两个集群太近,这样的决策边界不太可能很好地概括。如果我们添加一个新的“看不见的”观察值(红点),该观察值显然在类+1 的邻域内,则使用红色虚线的分类器会将其错误分类,因为该观察值位于决策边界的负侧。然而,使用蓝色虚线的分类器将没有问题地将新的观察值分配给正确的类。这里的直觉是,在类别之间留有更大间隔的决策边界更具普遍性,这将我们引向支持向量机的关键属性——它们以这样的方式构建超平面,使得两个类别之间的分离间隔最大化(Haykin,2009)。这与感知器形成鲜明对比,在感知器中,我们无法保证感知器将找到哪个分离超平面。
线性 SVM 的推导
我们来看一个二元分类数据集(\ mathcal { d } = \ { \ bold symbol { x } _ I,y_i}_{i=1}^N),其中(\ bold symbol { x _ I } \在\mathbb{R}^2)和(y \in {-1,+1})。注意,我们发展了在二维欧几里得空间中拟合线性 SVM 的过程。这样做是为了简洁,因为推广到更高的维度是微不足道的。
现在,我们可以从分离超平面的一个方程开始,把这个问题正式化:
$ $ \ begin { eq:SVM-hyperplane }
\ mathcal { h } _ { \ bold symbol { w },b } = {\boldsymbol{x}:\boldsymbol{w}^t \ bold symbol { x }+b = 0 } \;;;\text{(1)}
\end{equation}$$
其中(\boldsymbol{x})是输入向量,(\boldsymbol{w})是可调权重向量,(b)是偏差项。我们可以进一步定义以下可用于分配类别标签的决策规则:
$ $ \ begin { equation }
\ begin { aligned }
\boldsymbol{w}^t \ bold symbol { x }&+b \ geq 0 \ text {,for } y _ I =+1 \;;;\ text {(2)} \
\boldsymbol{w}^t \ bold symbol { x }&+b<0 \ text {,for } y _ I =-1
\ end { aligned }
\ end { equation } $ $
我们现在引入边缘的概念——从分离超平面观察的距离。在我们的情况下,从任意数据点到最佳超平面的距离由下式给出
$ $ \ begin { equation }
\ bold symbol { x } _ { I _ p } = \ bold symbol { x } _ I-\ gamma _ I(\ bold symbol { w }/\ | \ bold symbol { w } \ |)
\ end { equation } $ $
其中(\boldsymbol{x}{i_p})是(\boldsymbol{x}_i)到(\mathcal{H})的法线投影,而(\gamma_i)是边缘的代数度量(参见杜达和哈特,1973)。这里的关键思想是连接(\boldsymbol{x}_i)和(\boldsymbol{x}{i_p})的线段平行于(\boldsymbol{w}),并且可以表示为标量(\gamma_i)乘以单位长度矢量(\ bold symbol { w }/\ | \ bold symbol { w } \ | ),指向与(\boldsymbol{w})相同的方向。
因为(\boldsymbol{x}_{i_p})位于(\mathcal{H})上,所以它满足(1)
$ $ \ begin { align } \boldsymbol{w}^t \ bold symbol { x } _ { I _ p }+b = 0 \
\boldsymbol{w}^t(\ bold symbol { x } _ I-\ gamma _ I(\ bold symbol { w }/\ | \ bold symbol { w } \ |)+b = 0 \ end { align } $ $
求解(\γ_ I )得到
$ $ \ begin { align }
\ gamma _ I =(\boldsymbol{w}^t \ bold symbol { x } _ I+b)/\ | \ bold symbol { w } \ | \;;;\text{(3)}
\end{align}$$
我们对(3)应用进一步的修正,以使该度量也能够处理超平面负侧上的数据点:
$ $ \ begin { align } \ label { eq:SVM-margin-final }
\ gamma _ I = y _ I[(\boldsymbol{w}^t \ bold symbol { x } _ I+b)/\ | \ bold symbol { w } \ |]\;;;\text{(4)}
\end{align}$$
这个新的定义对正例和负例都有效,产生的(\gamma)值总是非负的。这很容易看出,因为忽略了(\boldsymbol{w})的范数并参考了我们得到的判定规则(2)
$ $ \ begin { equation }
\ begin { aligned }
y _ I =+1 \;;;&\ gamma _ I =(+1)(\boldsymbol{w}^t \ bold symbol { x } _ I+b \ geq 0)\ \
y _ I =-1 \;;;&\ gamma _ I =(-1)(\boldsymbol{w}^t \ bold symbol { x } _ I+b<0)\ end { aligned }
\ end { equation } $ $
这使得在两种情况下(\gamma_i > 0)。最后,我们将整个数据集的裕度定义为
$ $ \ begin { equation }
\ gamma = \ min _ { I = 1,\dots,N} \gamma_i
\end{equation}$$
我们现在把注意力转向寻找最佳超平面的问题。直观上,我们希望为(\boldsymbol{w})和(b)找到这样的值,使得生成的超平面最大化正样本和负样本之间的分离裕度。如果我们试图直接最大化(\gamma),我们可能会得到一个远离阴性和阳性样本的超平面,但不会将两者分开。因此,我们引入以下约束:
$ $ \ begin { eq:SVM-constraints } \ begin { aligned } \boldsymbol{w}^t \ bold symbol { x }+b \ geq 1 \ text {,for } y _ I =+1 \ \ \boldsymbol{w}^t \ bold symbol { x }+b \ leq-1 \ text {,for } y _ I =-1 \ end { aligned } \ end { equation } $ $
满足上述带有等号的约束条件的特定数据点称为支持向量 -这些数据点位于红色虚线上(图 2),并且最接近最佳超平面。请注意,如果(2)成立,我们总是可以以约束也成立的方式重新调整(\boldsymbol{w})和(b)。换句话说,重新缩放(\boldsymbol{w})和(b)不会影响(\mathcal{H})。
Figure 2 - Two linearly separable classes and an optimal separating hyperplane. The distance between an arbitrary point and the hyperplane is obtained using the normal projection of the point onto the hyperplane. There are also two support vectors present — one on the positive and one on the negative side of the hyperplane.
如果我们现在关注一个支持向量({\boldsymbol{x}_s,y_s}),那么将约束的结果代入等式(4)会发现支持向量和(\mathcal{H})之间的最佳距离为
$ $ \ begin { equation }
\ gamma _ s = y _ s[(\boldsymbol{w}^t \ bold symbol { x } _ s+b)/\ | \ bold symbol { w } \ |]=(\ pm 1)[\ pm 1/\ | \ bold symbol { w } \ |]= 1/\ | \ bold symbol { w } \ |
\ end { equation } $ $
因此,这两个类之间的最佳间隔是
$ $ \ begin { equation }
2 \ gamma _ s = 2/\ | \ bold symbol { w } \ |
\ end { equation } $ $
然而,最大化(1 / |\boldsymbol{w}|)相当于最小化(|\boldsymbol{w}|)。因此,在约束条件下最大化利润相当于
$ $ \ begin { equation }
\ begin { aligned }
\ min _ { \ bold symbol { w },b } \ quad&\ | \ bold symbol { w } \ | \;;;\ text {(5)} \
\ textrm {这样} \ quad&y _ I(\boldsymbol{w}^t \ bold symbol { x } _ I+b)\ geq 1 \ text {,for } \forall {\boldsymbol{x}_i,y _ I \ } \ in \ mathcal { d }
\ end { aligned }
\ end { equation } $
现在的问题是:我们如何解决这个优化问题?
用二次规划学习线性 SVM
二次规划(QP)是一种优化受某些线性约束的二次目标函数的技术。有大量的 QP 求解器可用,例如 GNU Octave 的 qp,MATLAB 的优化工具箱,Python 的 CVXOPT 框架等等。,它们都可以在 Domino 数据科学平台中获得。对于本教程,我们将使用 CVXOPT。为了使用凸优化,我们首先需要构造约束优化问题的拉格朗日函数(5)我们将拉格朗日乘数(\boldsymbol{\alpha})分配给约束,并构造以下函数
$ \ begin { equation } \ begin { aligned } \ t1]j(\ \ boldssymbol { w }、b,\ boldssymbol { alpha })&=-\ alpha _ I[y _ I](符号{ x } _ I+b)-1]
&=(1/2)–\;\;(6)
\ end { align }
\ end { equation } $。
我们现在寻找(J(\boldsymbol{w},b,\boldsymbol{\alpha}))的最小最大点,其中拉格朗日函数相对于(\boldsymbol{w})和(b)最小化,并且相对于(\boldsymbol{\alpha})最大化。这是一个拉格朗日对偶问题的例子,标准方法是从求解最小化目标((\boldsymbol{w})和(b))的原始变量开始。该解决方案提供(\boldsymbol{w})和(b)作为拉格朗日乘数(对偶变量)的函数。下一步是在对偶变量的约束下最大化目标。
假定(J(\boldsymbol{w},b,\boldsymbol{\alpha}))是凸的,最小化问题可以通过对(\boldsymbol{w},b,\boldsymbol{\alpha}))相对于(\boldsymbol{w})和(b)求微分,然后将结果设置为零来解决。
$ $ \ begin { align } \ partial j(\ bold symbol { w },b,\ bold symbol { \ alpha })/\ partial \ bold symbol { w } = 0 \ text {,得出} \ bold symbol { w } = \sum_{i=1}^n \ alpha _ I y _ I \ bold symbol { x } _ I \ label { eq:SVM-dual-const 1 } \ \ \ partial j(\ bold symbol { w },b,\ bold symbol { \ alpha })/\ partial b = 0 \ text {,得出} \sum_{i=1}^N \alpha_i y_i;;\text{(7)}\end{align}$$
扩展(6)和堵塞 w 和 b 产量的解决方案
$ \ begin { align } t0]j(\ \ boldssymbol { w }、b,\ boldssymbol { \ alpha })【T4 =(1/2)\ alpha _ I \ alpha _ j y _ I y _ j } \ boldssymbol { x } _ j-\ alpha _ I \ alpha _ j y _ I y _ j } \ boldssymbol { x } _ j+b \ alpha _ I y _ I+)\;\;\ text {(8)}
\ end { align }
$。
(8)中的第二项因为(7)而为零,这给了我们问题的最终提法。
$ $ \ begin { eq:SVM-qp-min-final }
\ begin { aligned }
\ max _ { \ bold symbol { \ alpha } } \ quad&\sum_{i=1}^n \ alpha _ I-(1/2)\sum_{i=1}^n \sum_{j=1}^n \ alpha _ I \ alpha _ j y _ I y _ j \boldsymbol{x}i^t \ bold symbol { x } _ j \;;;\ text {(9)} \
\ textrm {这样} \ quad&(1)\;\sum{i=1}^n \ alpha _ I y _ I = 0 \
&(2)\;\ alpha _ i \ geq 0 \ for all I
\ end { aligned }
\ end { equation } $ $
现在,让我们看看如何在实践中应用这一点,使用修改后的虹膜数据集。让我们从加载所需的 Python 库开始,加载和采样数据,并对其进行绘图以便进行可视化检查。
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from cvxopt import matrix, solvers
from sklearn.datasets import load_iris
iris = load_iris()
iris_df = pd.DataFrame(data= np.c_[iris["data"], iris["target"]], columns= iris["feature_names"] + ["target"])
# Retain only 2 linearly separable classes
iris_df = iris_df[iris_df["target"].isin([0,1])]
iris_df["target"] = iris_df[["target"]].replace(0,-1)
# Select only 2 attributes
iris_df = iris_df[["petal length (cm)", "petal width (cm)", "target"]]
iris_df.head()
让我们将数据转换成 NumPy 数组,并绘制两个类。
X = iris_df[["petal length (cm)", "petal width (cm)"]].to_numpy()
y = iris_df[["target"]].to_numpy()
plt.figure(figsize=(8, 8))
colors = ["steelblue", "orange"]
plt.scatter(X[:, 0], X[:, 1], c=y.ravel(), alpha=0.5, cmap=matplotlib.colors.ListedColormap(colors), edgecolors="black")
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)
plt.show()
回想一下,为了找到最佳超平面,我们使用(9)中给出的对偶拉格朗日公式。然而,CVXOPT 期望问题以下面的形式表达
$ $
\ begin { equation }
\ begin { aligned }
\ min \ quad&(1/2)\boldsymbol{x}^t p \ bold symbol { x }+\boldsymbol{q}^t\boldsymbol{x}\
\ textrm { subject to } \ quad&a \ bold symbol { x } = b \
\ quad&g \ bold symbol { x } \ precurlyeq \ bold symbol { h }
\ end { aligned }
\ end { equation }
$ $
我们需要重写(9)来匹配上面的格式。让我们定义一个矩阵(\mathcal{H})使得(H_{ij} = y_i y_j x_i \cdot xj)。然后我们可以用向量的形式重写原来的问题。我们还将目标和约束都乘以-1,这就变成了最小化任务。
$ $
\ begin { aligned }
\ min _ { \ alpha } \ quad&(1/2)\boldsymbol{\alpha}^t h \ bold symbol { \ alpha } -1^t \ bold symbol { \ alpha } \
\ textrm {这样} \ quad&\ bold symbol { \ alpha } = 0 \
\ quad&-\ alpha _ I \ leq 0 \;\ for all I
\ end { aligned }
$ $
从那里,我们获取训练样本的数量(n)并构造矩阵(H)。
n = X.shape[0]
H = np.dot(y*X, (y*X).T)
这是目标的第一项。对于第二项,我们只需要一个-1 的列向量。
q = np.repeat([-1.0], n)[..., None]
对于第一个约束,我们将(A)定义为包含标签(\boldsymbol{y})的(1 \乘以 n)矩阵,并将(b)设置为 0。
A = y.reshape(1, -1)
b = 0.0
对于第二个约束,我们构造了一个矩阵(n \u 乘 n \u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\u\( G \\\\\\)在对角线上为负 1,其他地方为 0,以及一个零向量\\\\\\\\
G = np.negative(np.eye(n))
h = np.zeros(n)
最后,我们将所有东西转换成 CVXOPT 对象
P = matrix(H)
q = matrix(q)
G = matrix(G)
h = matrix(h)
A = matrix(A)
b = matrix(b)
打电话给 QP 求解器。
sol = solvers.qp(P, q, G, h, A, b)
alphas = np.array(sol["x"])
pcost dcost gap pres dres
0: -5.8693e+00 -1.1241e+01 3e+02 1e+01 2e+00
1: -5.9277e+00 -3.6988e+00 4e+01 2e+00 3e-01
2: -1.0647e+00 -1.9434e+00 5e+00 2e-01 2e-02
3: -6.5979e-01 -1.1956e+00 6e-01 6e-03 8e-04
4: -8.3813e-01 -1.2988e+00 5e-01 3e-03 4e-04
5: -1.1588e+00 -1.1784e+00 2e-02 8e-05 1e-05
6: -1.1763e+00 -1.1765e+00 2e-04 8e-07 1e-07
7: -1.1765e+00 -1.1765e+00 2e-06 8e-09 1e-09
8: -1.1765e+00 -1.1765e+00 2e-08 8e-11 1e-11
Optimal solution found.
我们现在可以使用(\boldsymbol{w})
$ $ \ begin { equation }
\ bold symbol { w } = \ sum \ alpha _ I y _ I \ bold symbol { x } _ I
\ end { equation }
$ $
w = np.dot((y * alphas).T, X)[0]
接下来,我们确定支持向量,并使用以下公式计算偏差
$ $
\ begin { equation }
b =(1/| s |)\ sum _ { s \ in s }(y _ s-\ sum _ { I \ in s } \ alpha _ I y _ I \boldsymbol{x}_i^t \ bold symbol { x } _ s)
\ end { equation }
$ $
S = (alphas > 1e-5).flatten()
b = np.mean(y[S] - np.dot(X[S], w.reshape(-1,1)))
让我们看看最佳的(\boldsymbol{w})和(b)值。
print("W:", w)
print("b:", b)
W: [1.29411744 0.82352928]
b: [-3.78823471]
接下来,我们绘制分离超平面和支持向量。
该代码基于 scikit-learn 文档中的 SVM 利润示例。
x_min = 0
x_max = 5.5
y_min = 0
y_max = 2
xx = np.linspace(x_min, x_max)
a = -w[0]/w[1]
yy = a*xx - (b)/w[1]
margin = 1 / np.sqrt(np.sum(w**2))
yy_neg = yy - np.sqrt(1 + a**2) * margin
yy_pos = yy + np.sqrt(1 + a**2) * margin
plt.figure(figsize=(8, 8))
plt.plot(xx, yy, "b-")
plt.plot(xx, yy_neg, "m--")
plt.plot(xx, yy_pos, "m--")
colors = ["steelblue", "orange"]
plt.scatter(X[:, 0], X[:, 1], c=y.ravel(), alpha=0.5, cmap=matplotlib.colors.ListedColormap(colors), edgecolors="black")
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)
plt.show()
该图非常令人满意,因为解决方案完美地识别了使分离裕度最大化的支持向量,并且分离超平面正确地位于两者之间。最后,我们还可以通过使用 scikit-learn SVM 实现拟合 SVM 来验证我们解决方案的正确性。
from sklearn import svm
#使用线性内核并将 C 设置为较大的值,以确保硬边界拟合
clf = svm.SVC(kernel="linear", C=10.0)
clf.fit(X, y.ravel())
w = clf.coef_[0]
b = clf.intercept_
print("W:", w)
print("b:", b)
W: [1.29411744 0.82352928]
b: [-3.78823471]
我们得到了相同的(\boldsymbol{w})和(b)(由于具体的实现,在预期的误差范围内),这证实了我们的解决方案是正确的。
摘要
在本文中,我们回顾了支持向量机的数学知识及其相关的学习算法。我们使用 CVXOPT 在 Python 中做了一个“从头开始”的实现,并且我们展示了它产生了与 sklearn.svm.SVC 实现相同的解决方案。
理解支持向量机的内部结构使我们对算法对于各种任务的适用性有了额外的了解,并使我们能够为更复杂的用例编写定制的实现。
参考
- 巴尔古特大学(2015 年)。用于图像分割的迭代模糊决策的空间分类信息颗粒。在 W. Pedrycz 和 s-m . Chen(编辑。)、粒度计算和决策制定:交互式和迭代方法(第 285-318 页)。斯普林格国际出版公司。https://doi.org/10.1007/978-3-319-16829-6_12
- 德科斯特博士和舍尔科夫学士(2002 年)。训练不变支持向量机。机器学习,46(1-3),161–190。
- 杜达,R. O .,,哈特,P. E. (1973)。模式分类和场景分析。约翰·威利父子公司。
- 费希尔(1936 年)。分类问题中多重测量的使用。优生学年鉴,
7(2),179–188。https://doi . org/https://doi . org/10.1111/j . 1469-1809.1936 . TB 02137 . x - Haykin,S. S. (2009 年)。神经网络和学习机(第三)。皮尔森教育。
- t .约阿希姆(1998 年)。用支持向量机进行文本分类:用许多相关特征进行学习。在 C. Nédellec & C. Rouveirol(编辑。),机器学习:Ecml-98(第 137–142 页)。施普林格柏林海德堡。
- 库恩,H. W .,&塔克,A. W. (1951)。非线性规划。第二届伯克利数理统计和概率研讨会会议录,1950 年,481-492。
- schlkopf,b .,Williamson,r .,Smola,a .,Shawe-Taylor,j .,和 Platt,J. (1999 年)。新颖度检测的支持向量方法。第 12 届国际神经信息处理系统会议录,582-588。
建立人工智能卓越中心的五个步骤
原文:https://www.dominodatalab.com/blog/five-steps-to-building-the-ai-center-of-excellence
由战略&创新副总裁林振和 Mark III 系统首席技术官大卫舒尔曼合著,后者是多米诺数据实验室的合作伙伴营销主管。
通过数据科学获得竞争优势的最具创新性的组织正在创建数据科学的卓越中心(CoE)模型。 麦肯锡指出,在高级分析领域,60% 的顶级公司都遵循 CoE 方法。 例如,Bayer Crop Science 将许多优势归功于 CoE 方法,例如跨团队更好地共享知识、提高数据科学计划的效率、更好地协调数据科学和业务战略,以及改善人才获取。
建设欣欣向荣的人工智能卓越中心(CoE)的路径是什么?
在 Mark III,我们在过去几年里有幸与 NVIDIA 和几十个组织一起在工作,以支持他们的 AI CoE 之旅。在 9 月 19 日至 22 日的 NVIDIA GTC 大会上,我们宣布了新的 AI CoE 解决方案,采用了 NVIDIA 和 Domino 数据实验室的最新技术。
尽管每个故事和道路都略有不同,但我们注意到,它们在成熟时大多遵循相同的五个一般步骤或阶段。多米诺数据实验室的企业 MLOps 平台 集成了英伟达的产品线 的基础设施,如英伟达 DGX 系统,来自领先原始设备制造商的英伟达认证系统,以及英伟达 AI 企业软件套件。我们还帮助像【Allstate】【SCOR】Topdanmark这样的组织扩展他们的 Coe。尽管每个故事和道路都略有不同,但我们注意到,它们在成熟时大多遵循相同的五个一般步骤或阶段。
但在我们描述我们观察到的这些步骤是什么之前,我们可能应该定义什么是人工智能卓越中心(至少是我们对人工智能卓越中心的看法)。
什么是人工智能卓越中心?
很简单,人工智能卓越中心是一个集中的数据科学和人工智能/人工智能计算资源,在某一点上由一个团队管理,但可以服务于一个、五个、十个、一百个甚至数千个数据科学家,每个人都有自己独特的关于 ide、框架、工具集、库、模型、应用程序的需求,他们在其中工作的团队,都可以“用脚投票”在哪里构建和运行他们的模型。
简而言之,即使你成功地构建了技术栈来服务于你的数据科学社区,如果你不同时保持对团队、文化、人员、用户体验和教育方面的高度关注,他们也不会喜欢它,他们会转向其他东西(甚至拒绝使用它),你的 AI CoE 也不会成功。
因此,通往人工智能卓越中心的旅程确实一半是技术,一半是非技术(教育/文化/团队)。你会发现这个想法在下面有显著的特征。
构建人工智能 CoE 的五个步骤是什么(根据与几十个机构和组织的合作观察),我们如何合作以确保它的成功?
教育
甚至在关于技术的任何讨论以及关于集中式平台或 MLOps 的任何想法之前,我们已经发现,最成功的组织已经在教育他们的数据科学社区,为将来某一天的集中式 AI CoE 技术堆栈做准备。在任何给定的时间点,我们已经注意到至少 70%的与会者要么开始,要么试图加强基本的 AI/ML 基础,所以持续的实践教育在开始和持续的基础上都是重要的。
Mark III 帮助填补了这一空白,它在早期阶段对组织内的社区进行教育,并通过其 人工智能教育系列 提供所有阶段的继续教育,这是一套为不同地理位置的受众设计的实时虚拟教程/实验室,专为实用的人工智能教育理念而设计。焦点完全集中在术语、实用概念和实验室 — 上,可以被与会者立即“带回家”,让他们插入自己的数字、数据和用例,并立即开始迭代。
Domino 已经在组织中看到了类似的例子,不仅是数据科学家,还有商业领袖。好事达采用教育计划,专注于向业务领导者传授数据科学知识,通过为业务领导者和数据科学家提供“共同语言”来促进跨职能部门的沟通,以解决棘手的业务问题(在 43:00 的 了解更多信息,这是一个点播小组 )。
我们看到的培养这种文化并为 AI CoE“摆好桌子”的其他教育示例包括交互式用户驱动的研讨会、跨职能团队建设以及围绕共同挑战的“快速构建”。
实验
我们通常看到的下一个阶段,通常与“教育”阶段(一旦开始,实际上总是在进行中)重叠,是“实验”阶段,数据科学家和“构建者”从阴影中出现,告诉你他们正在做什么,以及他们如何使用或考虑使用数据科学和人工智能模型在整个组织中做改变游戏规则的事情。
Domino 已经看到组织为数据科学家实验和创新留出有意的时间——,这可能超出了“自上而下”的业务目标。好事达分配了一部分数据科学家的时间来从事任何感兴趣的项目,促进跨团队实验和协作来推动创新。更多详情,请查看 本点播面板 )。
在过去的 5-10 年里,人工智能的开源本质和历史令人难以置信的是,几乎任何人都可以从他们的笔记本电脑或工作站开始,无论是在办公室内还是办公室外。围绕数据科学对社区进行正式教育的官方努力几乎就像是为这些构建者走出来展示他们一直在做的工作开了绿灯。在这一点上,组织有机会鼓励社区在他们各自的组中继续并加速他们的工作,方法是让他们在他们习惯的工作流中访问更好的平台和工具。
评价
有了足够的教育和鼓励,组织将很难跟踪所有正在构建的模型以及所有孤岛和小组中发生的所有数据科学活动。相反,数据科学家开始遇到真正的挑战,例如模型漂移、无法跟踪数据集版本、无法获得模型所需的最佳数据集、模型从训练到生产推理的速度缓慢等等。好的一面是,整个组织有很多活动和讨论,但这些是真正的问题,如果不解决,可能会破坏所有的势头。
这个转折点是“评估”和审视 MLOps 平台的最佳时机,如果操作得当,该平台可以作为人工智能卓越中心向前发展的技术核心,并允许组织在某一点管理 CoE,而不会在组织扩展时侵犯每个数据科学家的独特需求和偏好。
开放性和灵活性是数据科学创新的关键,这就是为什么它是 Domino 平台的核心支柱。数据科学工具和技术的前景是异构的,并且不断发展,处于 CoE 核心的平台必须提供灵活性、敏捷性和可伸缩性。 拜耳 将此视为评估 Domino 的关键因素,数据科学家使用了许多工具,如 RStudio、Jupyter、Flask 等。拜耳数据科学卓越中心负责人 Naveen Signla 指出,“Domino 使全球企业中使用不同工具、具有不同背景和技能的用户更容易相互合作,利用过去的工作,并快速协作。"
我们在这一阶段使用的词是“评估”,因为它不仅需要试验和“推广”由 Domino 的企业 MLOps 平台和 Kubernetes 基金会支持的 MLOps 技术堆栈的能力,还需要确保任何试验中的数据科学家都有培训、部署和运行他们的模型的出色体验。总之是真实的评价。如果你的早期数据科学用户没有很好的体验,你的 AI CoE 可能无法进入下一阶段。
使能够
如果组织取得成功,通往人工智能卓越中心之旅的第四步是“启用”阶段,该阶段的中心是将人工智能卓越中心的成功试点推广到早期生产中,确保数据科学用户的数量增加,并与 IT 运营团队合作,以确保环境保持正常运行。
Mark III 发现,将 AI CoE 几乎像软件即服务产品 — 一样对待和支持,并将管理它的团队视为产品管理团队 — 是构建团队和战略的有效视角。Domino 已经看到了类似的侧重于支持数据科学家和业务的方法,其中 S & P Global 使用 Domino 作为“粘合剂”,支持一项对全球 17,000 名员工进行数据科学教育的计划。SCOR 将数据科学家嵌入业务中,以更好地培养理念、实践、技术和文档,从而推动数据科学的采用。此外,他们的数据科学专家使用 Domino 作为工具来 分享最佳实践和模板 。
Mark III 帮助组织完成了从建立知识库和入门教程到与 IT 运营团队“合作指导”的各种工作,以保持整体 AI CoE 环境的运行和优化。
从事
通往人工智能卓越中心的旅程的第五步也是最后一步是“参与”阶段,这是关于激活数据科学社区的剩余部分来加入人工智能卓越中心的。如果你从技术采用曲线的角度考虑,这将包括早期多数用户和后期多数用户。
到这个时候,组织的 AI CoE 和 MLOps 平台正在运行,大多数组都充分意识到了,并且入职和用户体验应该运行顺利,即使对于非专家用户也是如此。
此时,AI CoE 应该像一台运转良好的机器一样运行。重点是提高大众的参与度,鼓励他们更多地参与 AI CoE。在 Mark III,我们经常在“参与”阶段联合举办黑客马拉松,不仅提高整个组织的意识,还帮助建立与外部组织的合作伙伴关系,包括行业和公共部门。
类似地,Domino 通常是黑客马拉松中使用的 MLOps 平台,提供参与者所需的基础设施、数据和工具。强生公司 举行了一次内部黑客马拉松 来提高视力保健业务的预测能力,利用达美乐的平台让几十个团队提出最佳模式。 BNP Paribas Cardif 举办了一次虚拟数据科学黑客马拉松 ,来自大学和合作公司的 100 多名数据科学家参加,使用 Domino Data Lab 使每个团队能够访问他们需要的基础设施资源。
如何构建人工智能 CoE:英伟达 GTC 发布新解决方案
通往人工智能卓越中心的旅程对每个组织来说都是不同的,但我们认为,如果规划并遵循这五个步骤,它将有可能导致成功,无论确切的路径如何。如上所述,这一旅程基于一半技术、一半文化/团队/教育,并且我们的集体团队可以通过我们的共同学习来提供帮助。
企业 MLOps 在通往人工智能卓越中心的道路上至关重要,因为它构成了卓越中心的技术核心,但请不要忽视这条道路上的其他关键步骤和环节。
毕竟,人工智能卓越中心的成功在于过程,而不是目的地。了解更多关于我们 AI CoE 解决方案的信息,NVIDIA 于 9 月 19 日至 22 日在 GTC 宣布。
将您的数据科学职能引向 MLOps 卓越的五个技巧
编者按:这是分享开发企业数据科学战略的公司最佳实践的系列文章的一部分。一些文章将包含关于他们使用 Domino 的信息。
在我毕业后的 15 年职业生涯中,我有幸为金融和保险行业的公司开发数据科学团队。我最近被要求思考哪些行动有助于使数据科学团队成功融入组织。以下是我提供给任何踏上构建企业数据科学功能之旅的人的五个技巧。
雇佣多样化的技能组合
当我五年前加入纽约人寿时,我的任务是将一个由七名成员组成的数据科学团队发展成为一个企业范围的集中式数据科学中心,并在全公司范围内提供具有新水平的服务、专业知识和效率的人工智能解决方案。
如今,数据科学和人工智能中心(CDSAi)是一个 50 人的团队,拥有在我们的财富 100 强人寿保险公司中成功提供数据科学和人工智能专业知识、解决方案和教育所需的各种技能。CDSAi 不仅包括数据科学家,还包括机器学习工程师、数据工程师、项目和产品经理、运营和变革管理负责人、建立外部合作伙伴关系的开发经理以及数据科学社区负责人。
我们的数据科学家参与模型开发生命周期的每个方面。他们由负责模型部署和我们各种技术平台的项目经理和 ML/Ops 工程师提供支持。我们的变革经理、产品经理和开发经理携手合作,构思和整合新业务合作伙伴的数据科学。
促进透明度和数据科学教育
关于揭开数据科学神秘面纱的重要性已经说了很多,我参与的每个组织都是如此。我们的业务合作伙伴越是见多识广,他们就越会兴奋地将数据科学纳入他们的决策流程。为此,我们为公司创造了多种学习和参与数据科学的方式。
感谢纽约人寿的大力支持,我们已经成功建立了一个包容性的数据科学社区,通过各种计划覆盖所有领域、职业、级别和数据科学经验水平。其中包括:
- 关于项目、方法和数据的每月“午餐和学习”
- 年度数据科学博览会
- 数据科学论坛
- 外部嘉宾扬声器
通过这些活动,我们的内部数据科学家可以继续相互学习,公司内感兴趣的员工可以接触到数据科学在不同业务领域的应用。
此外,通过我们的数据科学学院,我们为纽约人寿的所有员工创造了机会,让他们以最舒适的方式学习数据科学。这包括技术和非技术认证途径以及文章和视频系列。我们举办了一系列研讨会,涵盖的主题从如何开始使用 Python 到我们的高级管理人员如何充分利用我们的数据科学能力。
通过这些活动、学习机会和纽约人寿的内部网,我们提高了对数据科学的理解水平,并强调了它可以提供的巨大价值。这有助于我们与现有业务伙伴、潜在的新业务伙伴以及其他利益相关方的关系。
经常有意义地联系
继续这个主题,您的业务合作伙伴知识越丰富,他们就越愿意将数据科学纳入他们的决策过程,我们非常鼓励 CDSAi 团队经常与我们的业务合作伙伴联系。
对于我们的数据科学家来说,这意味着每周或每两周与利益相关者会面。可能并不总是有重大的更新,但是在这些会议中,我们继续了解业务的细微差别以及棘手问题,他们也了解我们的流程。这对双方都有利,而且从个人层面来说,令人愉快和有益。其他团队成员也参与这些定期安排的会议。项目里程碑一起庆祝。虚拟工作当然也没有阻止我们承认项目中的所有重要时刻。
除了这些会议,我们的团队成员还会定期与公司的其他人进行互动。这有助于了解更多的业务以及我们如何提供帮助,同时,在有意义的层面上了解他人也是工作中令人满意的一部分。找到我们与同事的联系点对于个人参与和确保项目顺利进行都很重要。
与所有利益相关方保持一致
我们认为,确保我们与所有利益相关方有效协调我们的工作至关重要,包括:
- 业务领导 -我们经常与销售、营销、财务、产品、服务和其他业务团队的业务领导交谈,讨论机会并确保我们保持一致。CDSAi 经理与我们所服务的业务部门中的同行非常一致。
- 技术-我们需要在技术方面保持敏捷,特别是当我们迅速将新平台、库和工具引入我们的数据科学生态系统,以帮助我们的团队推动创新时。为此,与我们的技术合作伙伴进行良好的沟通至关重要。对于每一个请求,我们都分享为什么我们需要一种特定的技术,以及它如何从技术和业务的角度推动我们前进。此外,我们的数据工程师积极与技术合作,以确定数据优先级以及数据将如何流入分析开发。然后,CDSAi 团队处理“最后一英里”的数据处理,将数据输入到我们的模型中。
** 【治理团队】- 作为一家公司,我们有广泛的治理流程。对于更大的项目,我们有各种各样的治理团队。因此,在我们所有的项目计划中,我们有流程来确保我们的团队在我们需要决策之前几个月就开始这些对话,这样我们就可以确保我们在开发的早期解决任何需求。*
*### 投资技术基础设施
我们投资于有助于加速模型开发和部署的基础设施。例如,我们已经使用 Python 和 R 栈以及模型开发创建了一个计算环境。最近,我们在 Domino 平台的帮助下创建了模型部署的基础设施。我们使用 Domino 来消除将模型转移到生产环境中的手工工作,这需要大量的质量保证(QA)工作来保证它的正确性。现在,有了 Domino 平台和底层的 Kubernetes 集群,我们消除了数月的重新编码工作,可以直接将 Python 和 R 代码投入生产。我们的模型现在可以通过 API 从公司的任何生产平台访问。实现、运行和管理 Domino 平台以及部署模型在很大程度上是 CDSAi 和我们的技术团队之间的协作。
最终反射
我对 CDSAi 在帮助纽约人寿多元化团队做出模型驱动的决策方面所发挥的影响感到无比自豪。仅举几个例子,销售、营销、核保和代理等职能部门都在利用数据科学来自动化关键流程和改进决策,以便更好地为我们的客户服务。该团队已经建立了一个强大的基础—跨越人员、流程和技术—并在帮助高效和协作地实现这一影响方面发挥了关键作用。
随着我们进一步扩展纽约人寿的数据科学能力,我们将在许多方面继续努力。例如,最近的一项工作是增强我们的数据流,并创建一个特征库,该库记录并制度化了用于特定模型的最佳特征的知识。功能工程是一个耗时的过程,这项工作将使我们的团队能够不断地建立在彼此的知识之上,并更快地解决复杂的业务问题。
以上五个建议来自我的经验,这个旅程当然还会继续。
祝贺我们佛罗伦萨数据科学家抽奖活动的获胜者
原文:https://www.dominodatalab.com/blog/florence-book-sweepstakes-winner
By Domino Data Lab on June 01, 2021 in Company Updates
为了庆祝全国数学意识月,我们在 Domino 数据实验室的团队最近出版了世界上第一本关于数据科学的儿童书籍数据科学家 Florence 和她的神奇移动图书。我们还为这本书的读者提供了赢得一台笔记本电脑和 5000 美元大学学费的机会。我们很兴奋地宣布,威廉·布拉顿,阿肯色州波茨维尔中学的五年级学生,赢得了我们的抽奖!
威廉有幸阅读了这本书,并从他学校的图书管理员梅丽莎·穆迪那里了解了抽奖活动。
威廉的母亲克里斯蒂娜·津内尔说:“这不仅让我的儿子开心,也让他对自己和自己的梦想更有信心。”“他学校的每个人都以他为荣!”
津内尔补充说,虽然威廉喜欢这本书,但他尤其喜欢书中的主角如何利用科学来获得她想要的东西。
数据科学家弗洛伦斯和她的神奇的流动图书车围绕着一个名叫比阿特丽斯的好奇的孩子展开。当一辆神秘的流动图书车在她住的街道上行驶时,比阿特丽斯被这辆车后面的人所吸引。司机叫弗洛伦斯,算是一名图书管理员,他确切地知道哪些书会让附近的每个孩子开心。
随着这本书的展开,比阿特丽斯被迫决定是否有“魔法”这种东西,或者这个“图书管理员”是否知道一些世界上其他人不知道的事情。Beatrice 花了一整天的时间记录和分析她的每个朋友对 Florence 问题的回答,发现并爱上了数据科学的预测能力。
“有些人可能认为她作弊了,但她没有,”威廉说。“她运用自己的技能,观察其他孩子的结果,找到一种模式,这样她就能得到她想要的东西。那不是作弊,那是数据科学。"
此外,威廉说他喜欢书中动物的生活方式。他还认为这本书很好地解释了如何在日常生活中使用数据科学。
“威廉想成为一名兽医,”津内尔说。“他不仅想让动物——家养的和野生的——健康安全,他还想在动物和社区之间架起一座桥梁。”
威廉补充说,拥有数据科学技能可以帮助他开发更好的更持久的解决方案,以改善动物福利。
“我知道波特斯维尔中学也会以他为荣,”齐塞尔说。“尤其是他的图书管理员穆迪女士,她努力帮助她的学生取得成功.”
“我希望我们能提供给威廉的大学基金能帮助他追随他的激情,”莱恩·凯利说,她是《数据科学家弗洛伦斯和她的神奇的移动图书》的作者。“以同样的方式激励他,我希望这本书也能丰富许多其他孩子的梦想,让他们对解决问题充满热情,这样他们就可以继续让这个世界变得更好。”
数据科学家利用过去的数据建立模型,预测未来可能发生的事情。他们用笔记本、表格和图表彻底记录数据,然后用他们的数学和推理技能寻找模式。
想帮助孩子了解记录和分析数据的模式如何有助于预测未来吗?加入比阿特丽斯的行列,她会通过下载一本电子书或者从亚马逊订购一份硬拷贝。
对于物联网来说,东西越多越好
原文:https://www.dominodatalab.com/blog/for-the-internet-of-things-the-more-things-the-merrier
这是德克萨斯州奥斯汀数据科学论坛上众多精彩会议之一。不要错过 2016 年 9 月 14 日在洛杉矶数据科学弹出窗口向世界领先的数据科学家学习的下一次机会。查看演讲者阵容并立即获取门票。
前微软 Azure ML 高管和 Forrester 分析师加入 Domino 数据实验室
克里斯·劳伦(Chris Lauren)和杰尔·卡尔松(Kjell Carlsson)博士 帮助达美乐的客户群战略性地扩展他们对数据科学的使用
Domino Data Lab 自豪地宣布,来自企业技术领域两个最大品牌的 MLOps 专家已加入其团队。Chris Lauren 已经加入 Domino,担任微软产品副总裁,在那里他领导 Azure 机器学习产品团队;前 Forrester 分析师 Kjell Carlsson 博士加入该公司,担任数据科学战略负责人&布道者。
Lauren 将领导 Domino 的产品团队进一步定义和执行 Domino Enterprise MLOps 平台的愿景和战略,以更好地帮助客户利用机器学习的力量加速数字化转型。
在他的新角色中,Carlsson 将为 Domino 客户和潜在客户提供人工智能转型战略方面的建议;就企业如何大规模释放数据科学的商业价值提供战略建议。他还将在提高人们对 Domino 市场领先能力的认识方面发挥重要作用,并在战略和开发方面与 Lauren 的产品团队密切合作。
Domino Data Lab 的首席执行官兼联合创始人 Nick Elprin 表示:“Chris 和 Kjell 拥有广泛的行业知识,这对我们的团队和客户来说是一笔不可思议的财富。“Chris 是云计算和机器学习方面的专家,拥有数十年为企业客户提供产品的经验。随着数据科学和机器学习的成熟,Kjell 有幸为各行各业的数百家组织提供建议。丰富的经验使他非常适合宣传我们释放数据科学的使命。他们的加入让我激动不已。”
“在帮助许多企业大规模采用机器学习的同时,我看到了 MLOps 在加快模型速度以增加业务影响方面的关键作用,”劳伦说。Domino 是唯一一个以开放和灵活的方式满足最苛刻的企业工作负载需求的 MLOps 平台。我希望将 Domino 打造成适用于所有云和内部环境的市场领先企业 MLOps 平台,并在支持医疗保健、保险和金融服务等关键监管行业的客户方面取得成功。"
Carlsson 说:“Domino 是唯一一家真正支持现代专业数据科学家的公司,也是让企业能够扩展并推动其数据科学团队在整个组织中的影响力的最佳选择。与这样伟大的企业合作是一种荣幸,这些企业正在彻底转变自己,并使用 Domino 的 enterprise MLOps 平台实施最新的机器学习创新。”
拥有数十年大规模交付产品经验的真正的云 MLOps 专家
Lauren 在微软工作了 20 多年,利用大数据和机器学习的力量,领导团队交付产品并大规模赢得企业客户。他是云计算领域的专家,有能力与工程、设计、研究、营销、销售、客户和合作伙伴密切合作,推动产品定义和上市战略。
最近,他一直在 Azure Machine Learning 领导一个产品管理团队,以加速企业客户的增长,MAU 和 NPS 主要专注于使 ML 专业人员和工程师能够在云和大规模边缘培训、打包、部署和管理机器学习模型,并集成监控、警报和再培训,以促进完整的 MLOps 生命周期。
推动 Domino 客户迈向模型驱动业务的数据科学社区倡导者
卡尔森撰写了数十份报告,主题涵盖对话智能、MLOps、计算机视觉和 autoML,以及增强智能、下一代人工智能技术和数据科学最佳实践。他在无数的主题演讲、小组讨论和网络研讨会上发表过演讲,并被媒体频繁引用。
在加入 Domino 之前,Carlsson 是专注于 NLU 的初创公司 Stratifyd 的产品和战略副总裁,他在那里领导产品团队并重新设计公司战略。此前,Kjell 是 Forrester Research 的首席分析师,他领导了人工智能、人工智能、数据科学和高级分析方面的研究,就推动业务成果所需的技术、战略、能力和最佳实践向企业和供应商提供建议。卡尔松在哈佛商学院获得商业经济学博士学位。
Forrester TEI 研究:Domino 在 6 个月内实现了 542%的投资回报率和投资回报
Forrester 最近调查了数千名业务和技术决策者,以深入了解他们对数据和分析的使用,以及影响他们购买决策的因素。当被问及他们的组织在使用人工智能(AI)技术时期望获得什么好处时:
- 30%的受访者预计会“增加收入增长”
- 30%的受访者期望“提高运营效率和有效性”
- 30%的人希望“提高内部流程的自动化程度”
- 27%的人希望“提高员工的工作效率”
不幸的是,15%的受访者还表示,“对人工智能的明确投资回报没有统一的信念”是阻碍他们公司采用人工智能技术的最大挑战之一。21%的人最关心“他们人工智能投资的机会成本”。显然,组织对人工智能有很高的期望(他们应该如此),但难以量化人工智能投资对其业务的深远好处。难怪有 17%的人认为“缺乏高管支持来推动人工智能的使用”是他们组织面临的最大挑战之一。
Forrester 就组织如何实现采用人工智能和数据科学的好处提供了许多建议。例如,根据 Forrester Wave:基于笔记本的预测分析和机器学习,2020 年第三季度,“基于笔记本的 PAML 产品通过使个人数据科学家显著提高生产力,特别是通过为团队提供协作能力,将基于笔记本的数据科学推向了一个新的水平。”
我们很早就知道 Domino 使数据科学团队更有生产力。我们记录了他们的许多不可思议的故事,在某些情况下,已经能够衡量令人印象深刻的好处。例如,洛克希德·马丁公司将每年节省的 2000 万美元的成本归功于他们使用我们的平台,这要归功于降低的 IT 成本、提高的入职效率以及 10 倍的数据科学家工作效率。
但有些人看到这样不可思议的数字,自然会产生怀疑。其他人不确定在数据科学和 MLOps 解决方案上投资什么,因为目前市场上存在着混乱的状态,许多供应商推出了针对不同类型用户的截然不同的方法,并有着不同的规模目标。我们认为,购买者必须权衡企业 MLOps 的潜在影响和他们在人员、流程和技术方面的投资,然后衡量投资回报,这一点至关重要。
量化 Domino 的商业价值
为了消除一些疑虑和困惑,我们委托了一项独立的 Forrester Consulting 研究:Domino Enterprise MLOps 平台的总体经济影响(TEI)。Forrester 对几个 Domino 客户进行了详细的采访,以了解他们如何使用我们的平台,并深入了解他们获得的好处。基于这些采访,他们建立了一个由 50 名数据科学家组成的复合组织,预计团队增长与我们的许多客户在使用 Domino 的前三年中的经历一致。
结果不言自明:Forrester 预测,使用 Domino 的组织在三年时间内实现了近 3000 万美元的总经济效益,投资回报率为 542%,T2 为 542%。他们还得出结论,在 T4 投资多米诺不到六个月就收回了成本。
“如果我们没有投资 Domino,首先,我根本不可能建立一个团队,因为如果不为他们提供最先进的工作环境,你就无法雇用高技能的数据科学家。”–保险首席分析官
综合组织在三年内实现的平台预期收益包括:
减少了 980 万美元的计算资源配置时间
根据客户访谈,Domino 通过提供对基础架构和托管环境的自动化访问,允许数据科学家几乎立即开始研究新模型,平均每个实例节省 70 个小时。受访者报告说,以前调配基础架构、创建环境以及安装/维护单个软件包的过程通常需要几天到几周的时间,具体取决于构建的复杂程度。综合组织的净时间节省估计为三年 980 万美元。
对强大计算资源的自助式访问也减少了对工程部门的支持呼叫;管理人员估计,工程师在响应数据科学家的请求上节省了大约 30%的时间。
“在 Domino 出现之前,可能需要两到三周的时间来了解和启动基础架构,然后开始工作。有了 Domino,这需要几周时间,只需点击一下按钮。”–制药行业数据平台和隐私总监
运营效率提高了 850 万美元
数据科学经理报告说,使用 Domino,他们的数据科学团队可以利用更多的工具,花更少的时间等待模型和实验运行,并利用高级协作和可视化功能以新的方式与他人分享他们的工作。
管理人员估计每个数据科学家每年可以节省 200 个小时,对于复合组织来说,三年可以节省 510 万美元。
组织还实现了与新团队成员更快入职、更高效的模型验证、部署和维护相关的好处。对于综合组织而言,这些节省总计增加了 340 万美元。
“我们当然正在实施更精确的模型,甚至是我们以前在更复杂的工作流程中无法实现的模型。这可能比我们可能达到的水平提高了约 20%。”–金融服务首席顾问
520 万美元的增量利润
Domino 客户报告说,能够在开发周期中更有效地协作已经产生了更好地符合业务需求的数据科学解决方案,并且可以直接影响收入。他们能够生产更强大的模型,并受益于更高的模型部署成功率,从而对底线产生重大影响。对于本研究中使用的复合组织,增量利润估计接近 520 万美元。
“我们使用 Domino 对收入产生了巨大的影响,收入高达数百万美元,实际上是数千万美元。”–金融服务首席顾问
了解弗雷斯特·TEI 研究的详细信息
这些数字和报价只是您将在Domino Enterprise MLOps Platform的总体经济影响(TEI)中找到的细节的开始。查看这项研究,了解受访者在实施 Domino 之前面临的挑战,并深入了解 Domino 为他们带来的好处。
**2021 年 6 月 7 日更新:**我刚刚主持了一场网络研讨会,Forrester 首席分析师 Kjell Carlsson 博士和《TEI》的作者 Mary Barton 出席了会议。Kjell 描述了组织在扩展数据科学时面临的一些关键挑战,我们就 TEI 结果本身以及他们的访谈和 Domino 案例研究中的实际例子进行了热烈的讨论。你现在可以观看网上研讨会的重播。
基数:美国、加拿大、英国、法国和德国的 2,456 名数据和分析决策者;来源:Forrester Analytics 商业技术图表数据和分析调查,2020 年。
信号处理基础
原文:https://www.dominodatalab.com/blog/fundamentals-of-signal-processing
数字信号处理基础
信号被定义为任何随时间、空间或任何其他独立变量而变化的物理量。此外,科学和工程中遇到的大多数信号本质上都是模拟信号。也就是说,信号是连续变量的函数,例如时间或空间,并且通常取连续范围内的值。为了以数字方式执行处理,需要模拟信号和数字处理器之间的接口。这个接口被称为模数转换器。
通过以称为采样周期的特定间隔对信号进行采样,将模拟信号转换为数字信号。采样周期的倒数称为采样率(赫兹;秒^(-1) ),并且必须至少两倍于模拟信号中的最大频率,以防止混叠(参考奈奎斯特-香农采样定理)。实际上,采样率要高得多。常见的采样频率有 8kHz、16kHz、32kHz。
特征抽出
音频信号,特别是语音信号,通常在时域、频域和倒谱域进行分析。信号的频域表示由 DFT(离散傅立叶变换)完成。假设信号 X[N]具有范围在 0nN-1 之间的 N 个样本,信号 X[k]的 DFT 由 bey 给出
这里 k 是离散化的频率变量,跨度从 0kN-1。
快速傅立叶变换(FFT)是一种高效的 DFT 计算方法(请参考 cp-algorithms 的文档)。考虑到语音信号的随机特性,FFT 很少一次应用于整个信号,而是以帧为单位。通常,一种称为短时傅立叶变换(STFT)的傅立叶变换被应用于每个单独的帧。
下面示出了对信号 x[n]的样本的 FFT 算法
来源: 维基百科
假设表示语音信号的信号 x[n]和窗口函数 w[n]
人类的语言几乎总是在框架中被分析。语音信号碰巧是非平稳信号,但是在跨度为 20-40 毫秒长的帧中,假设信号是平稳的。原因是在这段时间内,声道特性不会发生太大的变化。这一点很重要,因为只有当信号稳定时,才能假设先验分布。在说话人确认的情况下,分布是高斯分布。
每帧之间有 10ms 的重叠。出现这种重叠是因为三角形窗口被应用于每一帧
(请参考这篇关于信号语音处理的文章)。
窗口可以被认为是索引上的非零值的数组,其中帧的样本在别处是 1 和 0。当该帧的每个帧样本乘以 1 时,它是一个矩形窗口。对于三角形窗口,靠近帧末端的样本被“去加重”(即乘以 0 和 1 之间的数字),而位于中心的样本由于窗口的三角形形状而被加重。执行帧的重叠,以便补偿在每帧结束时样本的去加重。(请参考栈交换提出的问题)
此外,几乎从不使用矩形窗口。在矩形窗口的情况下,信号的样本乘以 1。因为时域中两个信号的相乘等于频域中信号的卷积。矩形窗口的傅立叶变换是正弦函数。该函数在 x=0 处有一个主瓣,在π的整数倍处有旁瓣,随着 x x 的绝对值不断增加,旁瓣值不断减小。
(资料来源: 【维基百科】 )
当这个函数乘以语音信号的傅立叶变换时,在旁瓣处发生频谱泄漏,这是不理想的。当非整数数量的信号周期被发送到 DFT 时,发生频谱泄漏。频谱泄漏使单音信号在 DFT 操作后分散在几个频率上。
(来源: DSP 图文并茂 )
在上图中,我们假设一个目标信号,即左边的三角周期信号乘以红色矩形窗口。这些信号的卷积如上图右侧所示。两个信号卷积由下式给出
简而言之,两个信号的卷积是指其中一个信号反转,另一个信号乘以样本。为了理解信号
正如你所看到的,在上面的蓝色图中,“窗口”信号(卷积的结果)在旁瓣上有频谱泄漏。红色信号是矩形窗口的变换。
为了减少频谱泄漏,使用三角形窗口,如汉宁窗口、汉明窗口和三角形窗口。
(资料来源: 【维基百科】 )
汉宁窗函数由下式给出
三角形窗口由下式给出
语音信号的成帧可以如下图所示:
(来源: 阿尔托大学 )
梅尔频率倒谱系数
MFCCs 顾名思义就是倒谱域的系数和特征。(ceps 反过来是“spec”)这些特性在语音处理和 MIR(音乐信息检索)应用中无处不在。与 DFT 不同,频率是对数标度或 mel 标度。梅尔标度类似于人的听觉标度。低频的毛细胞数量远远高于高频。因此,随着年龄的增长,我们辨别更高频率的能力逐渐减弱。分辨率向更高频率的降低是通过 Mel 标度实现的。
简而言之,在时域信号的帧上,应用 STFT,并且对该信号应用 mel 标度中的重叠三角窗,即,应用一种对数标度。然后应用离散余弦变换,前 13 个系数称为 MFCCS。从每一帧中提取δ系数和双δ系数,一起构成 39 维数组。因此,如果一个音频信号有 100 帧,MFCC 阵列的维数将为(100,39)
mel 标度和线性标度之间的关系由下式给出
其中 f 表示以 Hz 为单位的物理频率,fMel 表示感知频率
Mel 滤波器组看起来像这样
要提取 MFCCs,需要完成以下步骤
- 预加重-这是一个高通滤波器,用于平衡在高频区域有陡峭滚降的浊音频谱。本项目使用的系数为 0.97。该值通常在 0.9 和 1 之间变化
- 框架和窗口——如上所述
- 频谱的 DFT 执行信号帧的帧
Mel 谱-幅度谱 X(k)的 Mel 谱通过将幅度谱乘以每个三角形 Mel 加权滤波器来计算。
其中 M 是三角形 Mel 加权滤波器的总数。
Hm(k)是给予对第 m 个输出频带有贡献的第 k 个^个能谱箱的权重,表示为:
其中 M 的范围从 0 到(M-1)。
- Mel 频谱的离散余弦变换(DCT)用于将 Mel 频率系数的对数变换成一组倒谱系数。
- 动态 MFCC 特征:倒谱系数是静态特征。从这些导出的δ系数是一阶导数,δ-δ系数是二阶导数。这些分别代表语速和语音加速度。
模糊匹配救援
原文:https://www.dominodatalab.com/blog/fuzzy-matching-to-the-rescue
詹妮弗·申是 8 Path Solutions 的创始人&首席数据科学家。Jennifer 是加州大学伯克利分校数据科学研究生项目的教师,纽约城市大学数据分析硕士项目的顾问委员会成员,并在 NYU 大学的研究生项目中教授业务分析和数据可视化。在一次数据科学的弹出式活动中,Jennifer 介绍了近似字符串匹配或模糊匹配。这篇博客文章包括一个会议总结,一个整个会议的视频,和一个演示文稿的视频抄本。如果你有兴趣参加未来的数据科学 Popup,下一个活动将于 11 月 14 日^日在芝加哥举行。
Session Summary
在这个数据科学的弹出式会议中,8 Path Solutions 的创始人兼首席数据科学家 Jennifer Shin 介绍了模糊匹配或近似字符串匹配。
该演示的几个主要亮点包括:
- 通过量化一个字符串与另一个字符串的接近程度,深入研究模糊匹配如何找到几乎相同但不完全相同的字符串。
- 模糊匹配的用例从基于相关性搜索列表到提供替换可能拼错的搜索词的建议。在替代拼写、不一致的格式和拼写错误会限制大型数据集中包含的信息的可用性和价值的情况下,这种方法尤其有用。
- 使用示例来说明模糊匹配如何成为实体和名称匹配的理想选择,但是对于医疗数据却不太理想,因为医疗数据的误差幅度太大。
要了解更多关于本次会议的见解,请观看视频或通读文字记录。
https://fast.wistia.net/embed/iframe/4c1hktg66n
获得对 Domino 实例的 Shell 访问
原文:https://www.dominodatalab.com/blog/gain-shell-access-domino-instances
注意:请注意,对于 4.x 以上的 Domino 版本,不赞成通过 SSH 直接访问容器。通过工作区终端(例如 JupyterLab、VSCode 等)间接访问 SSH。)在所有 Domino 版本中仍然可用。
Domino 提供了一个可管理的、可伸缩的计算环境,为数据科学家提供了方便,无论他们是对探索 Python 笔记本中的数据感兴趣,还是对使用 R 脚本训练模型感兴趣。虽然 Domino 为团队提供了许多定制和共享环境的机会,但是有些问题最好通过 shell 访问来解决。通过 Domino 的最新版本,用户可以做到这一点。
一旦启动了交互式会话,您将能够按照运行细节中的说明使用 SSH 访问正在运行的实例。看看这个短片:
基因组范围:基因组数据使用简介
原文:https://www.dominodatalab.com/blog/genomic-ranges-an-introduction-to-working-with-genomic-data
基因组测序的进步甚至超过了人们对他们的高度期望。我们现在有能力以不到 1000 美元的价格对一个人的整个基因组进行测序——这要归功于 Illumina 的 HiSeq X Ten 测序仪。在这篇文章中,我将介绍 GenomicRanges 软件包,它为表示基因组数据提供了一个方便的结构,并提供了许多操作这些数据的内置函数。
用坐标系统表示基因组
人类基因组由大约 30 亿个碱基对组成,线性排列在 23 对染色体上。因此,表示我们基因组的直观方式是使用坐标系:“染色体 id”和“沿染色体的位置”。像 chr1:129-131 这样的注释代表 1 号染色体上的第 129 到 131 个碱基对。
让我们加载 GenomicRanges 并创建一个示例对象来表示一些基因组片段:
# Installation source("https://bioconductor.org/biocLite.R") biocLite("GenomicRanges") The code below is how to create the an example GRanges object. The code entered here will create 8 segments on either chr1 or chr2, each with defined start and end points. Each read will also have strand information, indicating which direction the sequence is in. seglengths informs us the maximum length of chr1 and chr2. suppressMessages(library(GenomicRanges)) example = GRanges(seqnames=c(rep("chr1", 4), rep("chr2", 4)), ranges = IRanges(start = c(10, 32, 59, 79, 11, 22, 23, 41), end=c(42, 51, 76, 89, 12, 31, 46, 49)), strand = rep(c("+", "-"), 4), seqlengths=c(chr1=120, chr2=70) )
现在让我们来看看 R 控制台表示的例子:
example
## GRanges object with 8 ranges and 0 metadata columns:
## seqnames ranges strand
## <Rle> <IRanges> <Rle>
## [1] chr1 [10, 42] +
## [2] chr1 [32, 51] -
## [3] chr1 [59, 76] +
## [4] chr1 [79, 89] -
## [5] chr2 [11, 12] +
## [6] chr2 [22, 31] -
## [7] chr2 [23, 46] +
## [8] chr2 [41, 49] -
## -------
## seqinfo: 2 sequences from an unspecified genome
现在让我们想象一下这些作品的样子:
格兰奇斯物品估价员
一个 GRanges 对象可以作为一个数组和一个子集来处理,也可以这样修改:
example[1]
## GRanges object with 1 range and 0 metadata columns:
## seqnames ranges strand
## <Rle> <IRanges> <Rle>
## [1] chr1 [10, 42] +
## -------
## seqinfo: 2 sequences from an unspecified genome
该软件包还提供了访问和修改信息的功能:
seqnames(example)
## factor-Rle of length 8 with 2 runs
## Lengths: 4 4
## Values : chr1 chr2
## Levels(2): chr1 chr2
width(example)
## [1] 33 20 18 11 2 10 24 9
end(example)
## [1] 42 51 76 89 12 31 46 49
start(example[1])
## [1] 10
start(example[1]) = 11 example
## GRanges object with 8 ranges and 0 metadata columns:
## seqnames ranges strand
## <Rle> <IRanges> <Rle>
## [1] chr1 [11, 42] +
## [2] chr1 [32, 51] -
## [3] chr1 [59, 76] +
## [4] chr1 [79, 89] -
## [5] chr2 [11, 12] +
## [6] chr2 [22, 31] -
## [7] chr2 [23, 46] +
## [8] chr2 [41, 49] -
## -------
## seqinfo: 2 sequences from an unspecified genome
还可以将每个部分的附加信息存储到 GRanges 对象中:
example$exon_id = 1:8 example
## GRanges object with 8 ranges and 1 metadata column:
## seqnames ranges strand | exon_id
## <Rle> <IRanges> <Rle> | <integer>
## [1] chr1 [11, 42] + | 1
## [2] chr1 [32, 51] - | 2
## [3] chr1 [59, 76] + | 3
## [4] chr1 [79, 89] - | 4
## [5] chr2 [11, 12] + | 5
## [6] chr2 [22, 31] - | 6
## [7] chr2 [23, 46] + | 7
## [8] chr2 [41, 49] - | 8
## -------
## seqinfo: 2 sequences from an unspecified genome
单个范围的操作
GenomicRanges 还提供了许多有用的方法来对范围进行“算术运算”:
移位:
要将所有 10 个碱基对的片段移向染色体末端,可以这样做:
shift(example, 10)
## GRanges object with 8 ranges and 1 metadata column:
## seqnames ranges strand | exon_id
## <Rle> <IRanges> <Rle> | <integer>
## [1] chr1 [21, 52] + | 1
## [2] chr1 [42, 61] - | 2
## [3] chr1 [69, 86] + | 3
## [4] chr1 [89, 99] - | 4
## [5] chr2 [21, 22] + | 5
## [6] chr2 [32, 41] - | 6
## [7] chr2 [33, 56] + | 7
## [8] chr2 [51, 59] - | 8
## -------
## seqinfo: 2 sequences from an unspecified genome
要将所有片段向染色体的起始端移动 5 个碱基对,可以使用:
shift(example, -5)
## GRanges object with 8 ranges and 1 metadata column:
## seqnames ranges strand | exon_id
## <Rle> <IRanges> <Rle> | <integer>
## [1] chr1 [ 6, 37] + | 1
## [2] chr1 [27, 46] - | 2
## [3] chr1 [54, 71] + | 3
## [4] chr1 [74, 84] - | 4
## [5] chr2 [ 6, 7] + | 5
## [6] chr2 [17, 26] - | 6
## [7] chr2 [18, 41] + | 7
## [8] chr2 [36, 44] - | 8
## -------
## seqinfo: 2 sequences from an unspecified genome
要单独移动每一块,可以使用一个矢量:
shift(example, 1:8)
## GRanges object with 8 ranges and 1 metadata column:
## seqnames ranges strand | exon_id
## <Rle> <IRanges> <Rle> | <integer>
## [1] chr1 [12, 43] + | 1
## [2] chr1 [34, 53] - | 2
## [3] chr1 [62, 79] + | 3
## [4] chr1 [83, 93] - | 4
## [5] chr2 [16, 17] + | 5
## [6] chr2 [28, 37] - | 6
## [7] chr2 [30, 53] + | 7
## [8] chr2 [49, 57] - | 8
## -------
## seqinfo: 2 sequences from an unspecified genome
侧面
侧翼用于恢复输入集旁边的区域。对于示例上游的 3 个碱基延伸:
flank(example, 3)
## GRanges object with 8 ranges and 1 metadata column:
## seqnames ranges strand | exon_id
## <Rle> <IRanges> <Rle> | <integer>
## [1] chr1 [ 8, 10] + | 1
## [2] chr1 [52, 54] - | 2
## [3] chr1 [56, 58] + | 3
## [4] chr1 [90, 92] - | 4
## [5] chr2 [ 8, 10] + | 5
## [6] chr2 [32, 34] - | 6
## [7] chr2 [20, 22] + | 7
## [8] chr2 [50, 52] - | 8
## -------
## seqinfo: 2 sequences from an unspecified genome
输入负值表示向下游看,值可以是向量。注意,上游和下游是相对于每个片段的链信息而言的。
调整大小
resize 方法从相对于股方向的最上游位置开始,将片段调整到所需的输入长度:
resize(example, 10)
## GRanges object with 8 ranges and 1 metadata column:
## seqnames ranges strand | exon_id
## <Rle> <IRanges> <Rle> | <integer>
## [1] chr1 [11, 20] + | 1
## [2] chr1 [42, 51] - | 2
## [3] chr1 [59, 68] + | 3
## [4] chr1 [80, 89] - | 4
## [5] chr2 [11, 20] + | 5
## [6] chr2 [22, 31] - | 6
## [7] chr2 [23, 32] + | 7
## [8] chr2 [40, 49] - | 8
## -------
## seqinfo: 2 sequences from an unspecified genome
还有许多其他方法非常有用。看到了吗?格兰奇
对一组范围的操作
GenomicRanges 还包括聚合特定 GRanges 实例中所有片段的信息的方法。以下 3 种方法最有用:
分离
Disjoin 将范围缩减为组成原始集合的唯一的、不重叠的片段的最小集合。默认情况下,它是链特异性的,这意味着第一个和第二个片段不被认为是重叠的,除非另有说明:
disjoin(example)
## GRanges object with 8 ranges and 0 metadata columns:
## seqnames ranges strand
## <Rle> <IRanges> <Rle>
## [1] chr1 [11, 42] +
## [2] chr1 [59, 76] +
## [3] chr1 [32, 51] -
## [4] chr1 [79, 89] -
## [5] chr2 [11, 12] +
## [6] chr2 [23, 46] +
## [7] chr2 [22, 31] -
## [8] chr2 [41, 49] -
## -------
## seqinfo: 2 sequences from an unspecified genome
disjoin(example, ignore.strand=T)
## GRanges object with 11 ranges and 0 metadata columns:
## seqnames ranges strand
## <Rle> <IRanges> <Rle>
## [1] chr1 [11, 31] *
## [2] chr1 [32, 42] *
## [3] chr1 [43, 51] *
## [4] chr1 [59, 76] *
## [5] chr1 [79, 89] *
## [6] chr2 [11, 12] *
## [7] chr2 [22, 22] *
## [8] chr2 [23, 31] *
## [9] chr2 [32, 40] *
## [10] chr2 [41, 46] *
## [11] chr2 [47, 49] *
## -------
## seqinfo: 2 sequences from an unspecified genome
减少
类似地,reduce 创建唯一的、不重叠的片段的最小合并集合,这些片段覆盖了原始集合所覆盖的所有碱基。默认情况下也会考虑线束信息,并且可以将其关闭:
reduce(example)
## GRanges object with 8 ranges and 0 metadata columns:
## seqnames ranges strand
## <Rle> <IRanges> <Rle>
## [1] chr1 [11, 42] +
## [2] chr1 [59, 76] +
## [3] chr1 [32, 51] -
## [4] chr1 [79, 89] -
## [5] chr2 [11, 12] +
## [6] chr2 [23, 46] +
## [7] chr2 [22, 31] -
## [8] chr2 [41, 49] -
## -------
## seqinfo: 2 sequences from an unspecified genome
reduce(example, ignore.strand=T)
## GRanges object with 5 ranges and 0 metadata columns:
## seqnames ranges strand
## <Rle> <IRanges> <Rle>
## [1] chr1 [11, 51] *
## [2] chr1 [59, 76] *
## [3] chr1 [79, 89] *
## [4] chr2 [11, 12] *
## [5] chr2 [22, 49] *
## -------
## seqinfo: 2 sequences from an unspecified genome
新闻报道
如果一个人需要知道每个碱基被一个阅读/片段覆盖了多少次,覆盖函数是非常有用的:
coverage(example)
## RleList of length 2
## $chr1
## integer-Rle of length 120 with 9 runs
## Lengths: 10 21 11 9 7 18 2 11 31
## Values : 0 1 2 1 0 1 0 1 0
##
## $chr2
## integer-Rle of length 70 with 9 runs
## Lengths: 10 2 9 1 9 9 6 3 21
## Values : 0 1 0 1 2 1 2 1 0
coverage(example)$chr1
## integer-Rle of length 120 with 9 runs
## Lengths: 10 21 11 9 7 18 2 11 31
## Values : 0 1 2 1 0 1 0 1 0
范围集合之间的运算
发现重叠
GenomicRanges 还提供了一种有用的方法来查找两组范围之间的重叠。让我们假设我们感兴趣的任何部分与我们感兴趣的目标部分重叠:
target = GRanges(seqnames="chr1", range=IRanges(start=5, 40)) ol = findOverlaps(target, example) ol
## Hits object with 2 hits and 0 metadata columns:
## queryHits subjectHits
## <integer> <integer>
## [1] 1 1
## [2] 1 2
## -------
## queryLength: 1
## subjectLength: 8
为了查看示例中与目标重叠的部分,我们访问了存储在 ol:
example[subjectHits(ol)]
## GRanges object with 2 ranges and 1 metadata column:
## seqnames ranges strand | exon_id
## <Rle> <IRanges> <Rle> | <integer>
## [1] chr1 [11, 42] + | 1
## [2] chr1 [32, 51] - | 2
## -------
## seqinfo: 2 sequences from an unspecified genome
为了查看示例中与目标重叠的部分,我们访问了存储在 ol:
example[subjectHits(ol)]
## GRanges object with 2 ranges and 1 metadata column:
## seqnames ranges strand | exon_id
## <Rle> <IRanges> <Rle> | <integer>
## [1] chr1 [11, 42] + | 1
## [2] chr1 [32, 51] - | 2
## -------
## seqinfo: 2 sequences from an unspecified genome
应用示例-检测基因组缺失
现在,让我们把这篇文章中看到的所有内容汇总起来,看看我们能否在一些更真实的生成数据中检测到删除的存在。
利用现代测序技术,整个基因组并不是一片一片的测序。DNA 通常在随机过程中准备好并切成更小的片段,以便对整个序列进行测序。然后,这些小片段被送入一台机器,从这些片段的随机位置开始产生读数。在最流行的 Illumina 机器的情况下,产生的读数是 100 个碱基对长。这些读数被映射回参考基因组,以找到它们的来源,位置信息可以通过 GenomicRanges 加载到 R 中进行评估。
如果基因组中有一个缺失,人们可能会发现没有来自某个特定区域的读数。让我们看一下 GRanges 对象,它包含来自个人的 2000 次模拟读取的位置信息。这类似于在对参考文献中长度为 1000 个碱基对的虚构染色体 Z 进行测序后可能存储在 GRanges 对象中的内容:
set.seed(1337) # Ensure reproducibility starts = floor(runif(2000)*900)+1 reads = GRanges(seqname="chrZ", ranges=IRanges(start=starts, end=starts+99)) reads
## GRanges object with 2000 ranges and 0 metadata columns:
## seqnames ranges strand
## <Rle> <IRanges> <Rle>
## [1] chrZ [519, 618] *
## [2] chrZ [509, 608] *
## [3] chrZ [ 67, 166] *
## [4] chrZ [409, 508] *
## [5] chrZ [336, 435] *
## ... ... ... ...
## [1996] chrZ [181, 280] *
## [1997] chrZ [224, 323] *
## [1998] chrZ [499, 598] *
## [1999] chrZ [ 63, 162] *
## [2000] chrZ [ 15, 114] *
## -------
## seqinfo: 1 sequence from an unspecified genome; no seqlengths
我们可以使用 reduce 来查看读取覆盖了 chrZ 的哪些部分:
reduce(reads)
## GRanges object with 1 range and 0 metadata columns:
## seqnames ranges strand
## <Rle> <IRanges> <Rle>
## [1] chrZ [1, 999] *
## -------
## seqinfo: 1 sequence from an unspecified genome; no seqlengths
让我们也看看这组读数中每个碱基的覆盖范围
plot(coverage(reads)$chrZ, ty="l", main="Coverage of Reads of ChrZ", xlab="Coordinates along ChrZ", ylab="Coverage")
请注意 chrZ 沿线相对稳定的覆盖范围。这似乎表明沿 chrZ 没有删除。现在让我们看看另一个数据集 reads_2,它来自一个单独的个体:
starts = c(floor(runif(1000)*300), floor(runif(1000)*400)+500)+1 reads_2 = GRanges(seqname="chrZ", ranges=IRanges(start=starts, end = starts+99)) reduce(reads_2)
## GRanges object with 2 ranges and 0 metadata columns:
## seqnames ranges strand
## <Rle> <IRanges> <Rle>
## [1] chrZ [ 1, 399] *
## [2] chrZ [501, 999] *
## -------
## seqinfo: 1 sequence from an unspecified genome; no seqlengths
plot(coverage(reads_2)$chrZ, ty="l", main="Coverage of Reads_2 of ChrZ", xlab="Coordinates along ChrZ", ylab="Coverage")
请注意图中低覆盖到无覆盖的区域以及序列中来自 reduce 的间隙-这似乎表明在第二个受试者中碱基 400 和 500 之间删除了一段 chrZ。现在我们希望发现这种缺失是否与参考基因组中的任何注释区域重叠。这可以使用 findOverlaps 和包含注释信息的 GRanges 对象来实现。已经创建了许多这样的注释,可以加载到 r 中。对于我们的示例,我们可以使用下面的 annotation GRanges 对象注释:
annotation
## GRanges object with 4 ranges and 1 metadata column:
## seqnames ranges strand | Gene_id
## <Rle> <IRanges> <Rle> | <character>
## [1] chrZ [100, 150] * | Gene_1
## [2] chrZ [200, 250] * | Gene_2
## [3] chrZ [400, 550] * | Gene_3
## [4] chrZ [700, 750] * | Gene_4
## -------
## seqinfo: 1 sequence from an unspecified genome; no seqlengths
ol = findOverlaps(GRanges(seqnames="chrZ", ranges=IRanges(start=500, end=600)), annotation) annotation[subjectHits(ol)]
## GRanges object with 1 range and 1 metadata column:
## seqnames ranges strand | Gene_id
## <Rle> <IRanges> <Rle> | <character>
## [1] chrZ [400, 550] * | Gene_3
## -------
## seqinfo: 1 sequence from an unspecified genome; no seqlengths
因此,在第二个受试者中,Gene_3 似乎被删除了——这一信息可以传递给下游的实验室科学家进行验证和一般编目。
祝贺您学习了使用 GenomicRanges 在 R 中处理基因组读取数据的基础知识。在以后的文章中,我将更详细地回顾一些已经报道的需要调整的测序技术工件。例如,基因组产生的读数在整个基因组中并不一致。此外,我们将研究一些更先进的方法来检测基因读取数据中的突变。
用 R 的 ggmap 实现地理可视化
原文:https://www.dominodatalab.com/blog/geographic-visualization-with-rs-ggmaps
你曾经处理过一些涉及空间位置的数据吗?如果答案是否定的,那么男孩,你错过了!要分析的空间数据如此之多,而时间却如此之少。
因为您的时间很宝贵,所以您知道尝试用 Matlab 等语言或 Excel 等应用程序创建空间图可能是一个冗长乏味的过程。令人欣慰的是,有许多新的 R 库正在被创建,以使空间数据可视化成为一项更令人愉快的工作。在这些新选项中,一个有用的包是 ggmap :
ggmap 入门
install.packages("ggmap")
library(ggmap)
就是这样。
最快的方法是使用qmap
类,它代表“快速地图绘制”。使用不同类型的参数调用来渲染不同的绘图类型。
以下是一些例子:
qmap(location = "boston university")
qmap(location = "boston university", zoom = 14)
qmap(location = "boston university", zoom = 14, source = "osm")
它是这样工作的:qmap 是get_map
和 ggmap 的包装器。get_map
是一个智能包装器,它查询您选择的地图服务器——Google Maps、OpenStreetMap 或 Stamen Maps——并返回指定位置的地图。(抱歉,苹果和必应地图的粉丝们,目前还不支持这些 API。)
如上例所示,没有必要添加特定的纬度或经度。创建地图时,ggmap 接受带有“位置”参数的文本搜索输入。
可视化集群
空间绘图功能对于那些在某些精算行业(如医疗或汽车保险)中运行分析的人很有帮助。
例如,让我们直观地调查各州的机动车碰撞数量。首先,我从死亡分析报告系统(FARS)百科全书中找到了 2012 年致命车祸的 Excel 文件。
(一个干净。数据集的 csv 版本可在Domino 的数据科学平台上的这个公共项目中获得。)
加载完 ggmap 库之后,我们需要加载和清理数据。以下代码行加载一个 CSV 文件,将 State 列转换为字符数据类型,并将机动车碰撞量从整数变为双精度。最后,我们删除夏威夷和阿拉斯加,以获得更紧密的地图视图。(抱歉!)
mydata = read.csv("vehicle-accidents.csv")
mydata$State <- as.character(mydata$State)
mydata$MV.Number = as.numeric(mydata$MV.Number)
mydata = mydata[mydata$State != "Alaska", ]
mydata = mydata[mydata$State != "Hawaii", ]
接下来,我们使用 geocode 通过 Google Maps API 查找纬度和经度,只使用mydata$State
中的字符串。
下面是一个简单的 for 循环,它遍历每个州并返回纬度/经度坐标:
for (i in 1:nrow(mydata)) {
latlon = geocode(mydata[i,1])
mydata$lon[i] = as.numeric(latlon[1])
mydata$lat[i] = as.numeric(latlon[2])
}
由于我们不考虑数据的其他方面,如非机动或修复对象碰撞,因此我们可以创建一个新的数据框来简化数据集:
mv_num_collisions = data.frame(mydata$MV.Number, mydata$lon, mydata$lat)
colnames(mv_num_collisions) = c('collisions','lon','lat')
现在让我们用不同大小的圆来画出每个州的碰撞次数,看看最大的机动车碰撞肇事者。
我们获得美国的地理编码,然后创建一个覆盖从东海岸到西海岸的谷歌地图:
usa_center = as.numeric(geocode("United States"))
USAMap = ggmap(get_googlemap(center=usa_center, scale=2, zoom=4), extent="normal")
我们使用+
操作符在地图上添加 ggplot2 几何对象和其他样式选项。
将 ggmap 和 ggplot2 功能相结合的能力对于使用热点图、等值线图或其他空间绘图类型可视化数据来说是一个巨大的优势。这种叠加功能大部分源于 ggplot2 的 geoms 或几何对象,它们决定了所创建的地块的形状。
接下来,我们将 geom_point geom 添加到地图中,并使用 aes 生成美学映射,描述数据中的变量如何映射到 geom 的视觉属性(美学)。
最后,每个圆的大小和比例基于每个状态的碰撞量的最小和最大值范围。
USAMap +
geom_point(aes(x=lon, y=lat), data=mv_num_collisions, col="orange", alpha=0.4, size=mv_num_collisions$collisions*circle_scale_amt) +
scale_size_continuous(range=range(mv_num_collisions$collisions))
运行 ggmap-demo-circles。多米诺骨牌中的 r脚本产生了一张罪犯最多的漂亮地图:加州、佛罗里达州、得克萨斯州和纽约州。
震撼?不好玩吗?是啊!
热图
让我们尝试另一种绘图类型——热图。继续以保险洞察的数据可视化为主题,下一个数据集着眼于一个地区的住宅集中度以及这些住宅的建造时间。
我们可以用get_map
下载底图,然后在上面画一个gg_map
。然后我们加上:
geom_density2d
:使用 kde2d 进行 2D 核密度估计,并用等高线显示结果。stat_density2d
: 2D 密度估计scale_alpha
:设置透明度的 alpha 值。
运行 ggmap-demo-heat。R 脚本给出了结果:
额外资源
- 如果你想了解更多,请参见 ggmap 参考手册并阅读由利兹大学研究人员编写的R 空间数据可视化简介。还可以看到其他令人惊叹的软件包,如 tmap ,它可以创建有用的专题地图。
- Plotly 在 ggplot2 的基础上拥有自己的增强地图功能。
- 2015 年 7 月 14 日,Jack Parmer(plotly 首席执行官)将在波士顿数据挖掘会议上讨论 plotly 的制图能力。
- 最后但同样重要的是,您可以使用 Domino 在大规模数据集上运行这样的分析,而不需要等待缓慢的计算时间,也不需要下载包。
让数据科学迅速进入企业规模:与 CSL Behring 的 John K. Thompson 的对话
随着领先的采用者提高个性化服务和客户体验的标准,数据科学的影响在每个行业都变得越来越明显。IDC 最近对人工智能的调查发现,早期采用者报告说,客户体验提高了 25%,创新速度加快,竞争力增强,还有其他好处。
然而,大多数领导者正在意识到,要将人工智能规模化,他们需要一个包括以下内容的企业战略:
- 为他们如何管理拥抱数据科学所必需的人员和文化变革创建一个规程。
- 在端到端数据科学生命周期中建立可扩展和可重复的流程。
- 确保数据科学团队拥有促进生产力和协作的技术基础。
以全球领先的生物制药公司 CSL Behring 为例,该公司专门治疗罕见疾病,如血友病和免疫疾病。2018 年,公司高管开始将数据科学转化为核心能力,帮助科学家:
- 发现新的救命疗法
- 更快地将产品推向市场,以及
- 帮助减少患者接受准确诊断的时间,这可能需要数年时间,因为患者和护理人员要努力弄清楚各种模糊症状,这些症状往往与其他更常见的疾病重叠。
在构建能力的过程中,高管们希望快速行动,这体现了他们的承诺
“工作吧,就像生活依赖于它一样,因为它们确实如此.”
为了实现他们的愿景,他们聘请了在商业智能和高级分析领域拥有 30 年经验的 John K. Thompson 作为该公司第一位高级分析&人工智能的全球负责人。
在短短两年内,John 在业务的所有领域(从研究和药物安全到制造到供应链到运营)创建了一个蓬勃发展和成功的高级分析和人工智能实践,为患有罕见疾病的患者带来了不可估量的利益以及顶线和底线商业价值。
我们最近采访了约翰,他有能力在相对较短的时间内取得如此大的成就。以下是经过编辑的我们对话的文字记录。
当你加入 CSL Behring 时,你是从哪里开始的?
当我第一次进来时,我建立了一个卓越中心(COE ),雇用了一组数据科学家,并增加了数据可视化专家和开发人员,他们可以到公司的任何地方,为任何感兴趣的业务线或运营领域进行高级分析项目。
一旦我组建了这个团队,我就需要把消息传出去。我们开始通过内部邮件进行宣传,然后安排会议。在第一年,我与从首席执行官到工厂一线工人的所有人举行了 1100 多次会议,讨论高级分析和人工智能以及它可以做什么。
第一年,400 多人注册成为我们邮件列表的一部分,我们联系了 80 名已经在从事数据科学工作的不同业务部门的人员。
从那时起,我们开始寻找定期聚会的方式。我们在瑞士伯尔尼为该公司举办了有史以来第一次数据科学峰会,来自 CSL 各地的人们讨论了他们正在做什么、如何做以及他们想要做什么。
我们还根据收到的反馈创建了特殊兴趣小组(SIG)。我们有从使用人工智能进行药物安全到图像分析到 R 和 Python 的 SIGs。对于这些小组中的每一个,都有一个“所有者”,他们定期开会——通常在每个月到每个季度之间。
现在,这些小组将他们的兴趣反馈给 COE,我们将这些反馈给实践社区,以创建一个生态系统来指导组织中需要发生的事情。这三种结构允许人们进行足够小的、有凝聚力的对话,从而取得进步,以及足够大的、有影响力的社区。
为什么是咖啡?
卓越中心是一个伟大的概念,适用于许多不同类型的组织。
首先,它让组织明确了他们可以在哪里提问。许多高管、运营经理和主题专家来问我:
“哎,我在考虑做 x,我们有这方面的技术吗?我们以前做过吗?我们做过类似的事情吗?”
拥有一个 COE 可以让人们清楚地知道他们可以去哪里问这些问题。
其次,它提供了对技术的关注,以帮助组织了解人工智能的可能和不可能。有些事情人工智能目前可以非常确定地预测,有些事情则不能。所以这是一个专业导航的地方。
最后,COE 提供了一个定位点,有助于将 IT、运营和其他领域的人员聚集在一起,这对完成这项工作至关重要。
业务线员工有时会对集中式团队持怀疑态度。你是如何为你的 COE 赢得支持的?
我们从一开始就非常明确地表示,我们很乐意以顾问的身份帮助他人独立完成项目,但我们也很乐意为那些已经在做数据科学项目的人提供建议和支持。因此,有人来找我们,要求一名数据科学家或数据可视化人员来填补空缺,我们可以从我们的团队中借调一些人给他们。他们向我们寻求专家建议,用最好的技术来解决一个具有挑战性的问题。
招聘总是充满挑战。你是如何白手起家建立起一个团队的?
你需要慢慢来,知道自己在寻找什么。我的观点是,你需要一个由一些资深的、博士级别的数据科学家组成的团队,其余的可以是有才华的后起之秀。所以,我们刚刚开始把它放在那里,我们对前来表示希望与我们合作的人的质量和数量感到非常惊喜。
我们任何时候都有五六名实习生和我们一起工作,因为我们喜欢从本科生或研究生层次招聘人才。我们与许多大学有合作关系:密歇根大学、德克萨斯大学奥斯汀分校、德雷克塞尔大学和俄克拉荷马州立大学等等。在做出招聘决定之前,我们会让实习生回来两三次。我们想让人们长期留在身边,以确保这是一个很好的适应。这是值得的。例如,在我们 2018 年招聘的前六名员工中,有五人今天仍在团队中。
你如何设定你的优先事项?
从用例的角度来看,我们关注业务,以及此时最大的需求是什么,以便为患者和我们的公司带来改变。例如,在新冠肺炎,我们不得不转移我们的重点,以帮助确保我们有足够的血浆捐赠。由于我们所做的一切都来自人类血浆,任何导致人们不离开他们的房子来到捐赠中心的事情都可能给该行业的所有领域带来挑战。因此,在过去的六个月里,我们几乎完全专注于血浆业务,了解捐赠者和他们的担忧以及如何应对。
从流程的角度来看,我们通常专注于构建进入生产环境的系统和容器。一旦新模型投入生产,IT 部门就会接管,处理基础架构、合规性和法规合规性。我们保留对模型本身的权力和责任,监控模型性能,并在需要时重新训练模型。
你会给开始构建 COE 的其他人什么建议?
首先,正如我前面提到的,你必须雇佣好员工。你需要团队中能合作的人。不能与其他团队成员合作的人会削弱团队的凝聚力和生产力。所有人都需要有谦卑感。如果有什么不对劲,我们需要举手纠正。
其次,我认为 COE 是一个适合创意专业人士的环境。它不是一个技术团队,也不是一个 It 团队(考虑到这种差异,我认为 Coe 向 it 部门报告不是一个好主意)。我们不是在构建下一个 ERP 系统或 CRM 系统。我们收集了许多来源的数据,并把它们混合在一起,我们试图围绕可能性提出新的见解。将数据科学视为一种创造性的努力,可以让数据科学家调查他们感兴趣的事情。有时你会一无所获。但是其他时候你改变了企业的运作方式。因此,在我们集团内部,虽然我们不断努力满足业务线用户和高管的需求,但我们有一个非常自由流动、基于实验的方法。
最后,卓越中心必须能够有效地设定主题专家、经理和高管的期望,他们可能不知道高级分析项目涉及哪些内容,也不知道完成项目需要什么。因此,设定期望,让他们得到他们想要的开创性工作是很重要的,但这需要时间。
尽管如此,我们仍然希望成为一个敏捷的组织,帮助主题专家以新的方式尽快了解他们的业务。我想告诉大家,这些事情并不需要花费几周甚至几个月的时间。因此,我们与主题专家一起快速迭代,然后一旦构建了模型,我们就减缓治理和生产流程的周期。我确实相信,使用灵活的方法来构建模型不仅会给数据科学团队带来快乐和兴奋,也会给业务人员带来快乐和兴奋。
了解更多信息
- 阅读约翰的书-分析:如何用智慧取胜和建立分析团队
- 收听 John 与 Domino 首席客户官 Dave Cole 的炉边谈话,话题是建立您最好的数据科学团队。
用美汤获取数据
原文:https://www.dominodatalab.com/blog/getting-data-with-beautiful-soup
数据无处不在,从我们每天分析的电子表格,到我们每天早上依赖的天气预报或我们阅读的网页。很多时候,我们消费的数据只是简单的给了我们,简单的一瞥就足以做出决定。比如,知道今天全天下雨的几率是 75%,就让我带上伞。在许多其他情况下,提供的数据是如此丰富,我们需要卷起袖子,我们可能会使用一些探索性的分析来解决这个问题。我们已经在 的前一篇文章中讨论了一些有用的包来进行这种探索。
然而,我们需要的数据可能并不总是以一种适合于立即操作的格式提供给我们。可能的情况是,数据可以从应用编程接口(API)获得。或者我们可以直接连接到数据库来获取我们需要的信息。
另一个丰富的数据来源是网络,你可能已经从中获得了一些有用的数据。只要访问你最喜欢的维基百科页面,你就会发现每个国家在最近的东京奥运会上获得了多少枚金牌。网页也有丰富的文本内容,虽然你可以复制和粘贴这些信息,甚至输入到你选择的文本编辑器中,网络抓取可能是一种可以考虑的方法。在之前的另一篇文章中,我们谈到了自然语言处理,并从一些网页中提取了文本。在本帖中,我们将使用一个名为 Beautiful Soup 的 Python 模块来简化数据采集过程。
网页抓取
我们可以创建一个程序,使我们能够抓取我们感兴趣的页面并获得我们想要的信息。这就是所谓的网络抓取,我们编写的代码要求我们获取包含信息的网页的源代码。换句话说,我们需要解析组成页面的 HTML 来提取数据。简单地说,我们需要完成以下步骤:
- 用我们需要的信息识别网页
- 下载源代码
- 识别包含我们需要的信息的页面元素
- 提取和清理信息
- 格式化并保存数据以供进一步分析
请注意,并不是所有的页面都让你抓取它们的内容,其他的也不会提供一个清晰的观点。我们建议您检查您正在寻找的页面的条款和条件,并遵守它们。可能有这样一种情况,您可以使用一个 API 来获取数据,使用它而不是直接抓取数据通常会有额外的好处。
HTML 入门
如上所述,我们需要理解 HTML 文件的结构来找到解决方法。网页呈现其内容的方式是通过 HTML(或超文本标记语言)来描述的,HTML 提供了指示页面的格式、样式和结构的详细指令,以便浏览器可以正确地呈现内容。
HTML 使用标签来标记关键结构元素。标签通过使用<
和>
符号来表示。我们还需要指出标记元素的开始和结束位置。对于名为mytag
的标签,我们用<mytag>
表示标签内容的开始,用</mytag>
表示结束。
最基本的 HTML 标签是<html>
标签,它告诉浏览器标签之间的一切都是 HTML。因此,最简单的 HTML 文档被定义为:
<html>
</html>
上面的文件是空的。让我们看一个更有用的例子:
<html>
<head>
<title>My HTML page</title>
</head>
<body>
<p>
This is one paragraph.
</p>
<p>
This is another paragraph. <b>HTML</b> is cool!
</p>
<div>
<a href="https://blog.dominodatalab.com/"
id="dominodatalab">Domino Datalab Blog</a>
</div>
</body>
</html>
我们可以看到之前的 HTML 标签。这一次,我们有其他的标签在里面。我们把另一个标签里面的标签叫做“孩子”,正如你所想象的,标签可以有“父母”。在上面的文档中, <head>
和 <body>
是 <html>
的子节点,依次是兄弟节点。一个美好的家庭!
这里有几个标签:
<head>
包含网页的元数据,例如页面标题<title>
是页面的标题<body>
定义了页面的正文<p>
是一段文字<div>
是页面的一个分部或区域<b>
表示加粗字体-粗细<a>
是一个超链接,在上面的例子中,它包含两个属性href
,表示链接的目的地和一个名为id
的标识符。
好了,现在让我们试着解析这一页。
美味的汤
如果我们保存上面描述的 HTML 文档的内容,并在浏览器中打开它,我们将看到类似这样的内容:
这是一个段落。
这又是一段。HTMLT5【酷炫!
但是,我们有兴趣提取这些信息以供进一步使用。我们可以手动复制和粘贴数据,但幸运的是我们不需要这样做——我们有美丽的汤来帮助我们。
Beautiful Soup 是一个 Python 模块,它能够理解 HTML 和 XML 文档中的标签。你可以在这里看一下 模块的页面。
让我们用 HTML 的内容创建一个字符串。稍后,我们将看到如何从实时网页中读取内容。
my_html = """
<html>
<head>
<title>My HTML page</title>
</head>
<body>
<p>
This is one paragraph.
</p>
<p>
This is another paragraph. <b>HTML</b> is cool!
</p>
<div>
<a href="https://blog.dominodatalab.com/"
id="dominodatalab">Domino Datalab Blog</a>
</div>
</body>
</html>"""
我们现在可以导入美丽的汤,并读取字符串如下:
from bs4 import BeautifulSoup
html_soup = BeautifulSoup(my_html, 'html.parser')
让我们看看html_soup
的内容,正如你所看到的,它看起来很正常:
print(html_soup)
<html>
<head>
<title>My HTML page</title>
</head>
<body>
<p>
This is one paragraph.
</p>
<p>
This is another paragraph. <b>HTML</b> is cool!
</p>
<div>
<a href="https://blog.dominodatalab.com/" id="dominodatalab">Domino Datalab Blog</a>
</div>
</body>
</html>
但是,事情远比你想象的要复杂。看看 html_soup 变量的类型,可以想象,它不再是字符串。相反,它是一个漂亮的组合对象:
type(html_soup)
bs4.BeautifulSoup
正如我们之前提到的,Beautiful Soup 帮助我们理解 HTML 文件中的标签。它解析文档并定位相关的标签。例如,我们可以直接询问网站的标题:
print(html_soup.title)
<title>My HTML page</title>
或者对于 title 标签内的文本:
print(html_soup.title.text)
'My HTML page'
同样,我们可以看看儿童的身体标记:
list(html_soup.body.children)
['\n',
<p>
This is one paragraph.
</p>,
'\n',
<p>
This is another paragraph. <b>HTML</b> is cool!
</p>,
'\n',
<div>
<a href="https://blog.dominodatalab.com/" id="dominodatalab">Domino Datalab Blog</a>
</div>,
'\n']
从这里,我们可以选择第一段的内容。从上面的列表中,我们可以看到它是列表中的第二个元素。记住 Python 从 0 开始计数,所以我们感兴趣的是第 1 个元素:
print(list(html_soup.body.children)[1])
<p>
This is one paragraph.
</p>
这很好,但美丽的汤可以帮助我们更多。例如,我们可以通过参考如下的p
标签找到第一段:
print(html_soup.find('p').text.strip())
'This is one paragraph.'
我们还可以查找所有段落实例:
for paragraph in html_soup.find_all('p'):
print(paragraph.text.strip())
This is one paragraph.
This is another paragraph. HTML is cool!
让我们获得例子 HTML 中引用的超链接。我们可以通过请求所有包含一个href
的a
标签来做到这一点:
links = html_soup.find_all('a', href = True)
print(links)
[<a href="https://blog.dominodatalab.com/" id="dominodatalab">Domino Datalab Blog</a>]
在这种情况下,列表链接的内容就是标签本身。我们的列表包含一个元素,我们可以看到它的类型:
print(type(links[0]))
bs4.element.Tag
因此,我们可以如下请求属性href
和id
:
print(links[0]['href'], links[0]['id'])
('https://blog.dominodatalab.com/', 'dominodatalab')
读取网页的源代码
我们现在准备开始研究从实际的网页中请求信息。我们可以在请求模块的帮助下做到这一点。让我们来看看之前的一篇博文的内容,例如,关于“使用 Pandas Profiler 和 D-Tale 进行数据探索”的那篇
import requests
url = "https://blog.dominodatalab.com/data-exploration-with-pandas-profiler-and-d-tale"
my_page = requests.get(url)
成功的页面请求将返回响应 200:
my_page.status_code
200
用my_page.content
可以看到页面的内容。我不会展示这一点,因为这将是这篇文章的一个混乱的条目,但是你可以在你的环境中继续尝试。
我们真正想要的是将这个信息传递给 Beautiful Soup,这样我们就可以理解文档中的标签:
blog_soup = BeautifulSoup(my_page.content, 'html.parser')
让我们看看包含页面标题的标题标签h1
:
blog_soup.h1
<h1 class="title">
<span class="hs_cos_wrapper hs_cos_wrapper_meta_field hs_cos_wrapper_type_text" data-hs-cos-general-type="meta_field" data-hs-cos-type="text" id="hs_cos_wrapper_name" style="">
Data Exploration with Pandas Profiler and D-Tale
</span>
</h1>
我们可以看到它有几个属性,我们真正想要的是标签内的文本:
heading = blog_soup.h1.text
print(heading)
'Data Exploration with Pandas Profiler and D-Tale'
博文作者在author-link
类的div
中标识,我们来看看:
blog_author = blog_soup.find_all('div', class_="author-link")
print(blog_author)
[<div class="author-link"> by: <a href="//blog.dominodatalab.com/author/jrogel">Dr J Rogel-Salazar </a></div>]
注意,我们需要引用class_
(带下划线)以避免与 Python 保留字class
冲突。从上面的结果中我们可以看到,div
有一个超链接,作者的名字在那个标签的文本中:
blog_author[0].find('a').text
'Dr J Rogel-Salazar '
正如您所看到的,我们需要熟悉我们页面的源代码内容。你可以使用你最喜欢的浏览器提供的工具来检查网站的元素。
假设我们现在有兴趣获得博文中给出的目标列表。信息在一个无序列表的<ul>
标签中,每个条目在一个列表项的<li>
标签中。无序列表没有类或角色(与页面中的其他列表不同):
blog_soup.find('ul', class_=None, role=None)
<ul>
<li>Detecting erroneous data.</li>
<li>Determining how much missing data there is.</li>
<li>Understanding the structure of the data.</li>
<li>Identifying important variables in the data.</li>
<li>Sense-checking the validity of the data.</li>
</ul>
好了,我们现在可以提取 HTML 列表的条目,并将它们放入 Python 列表中:
my_ul = blog_soup.find('ul', class_=None, role=None)
li_goals =my_ul.find_all('li')
goals = []
for li_goal in li_goals:
v goals.append(li_goal. string)
print(goals)
['Detecting erroneous data.',
'Determining how much missing data there is.',
'Understanding the structure of the data.',
'Identifying important variables in the data.',
'Sense-checking the validity of the data.']
如前所述,我们可能对获取博客文章的文本进行一些自然语言处理感兴趣。我们可以用get_text()
方法一次性完成。
blog_text = blog_soup.get_text()
我们现在可以用 spaCy 来使用早先关于自然语言的文章中描述的一些技术。在这种情况下,我们显示每个条目、其词性(POS)、对词性的解释以及该条目是否被视为停用词。为方便起见,我们只展示第一个10 个条目。
import spacy
nlp = spacy.load("en_core_web_sm")
doc = nlp(blog_text)
for entry in doc[:10]:
print(entry.text, entry.pos_,
spacy.explain(entry.pos_),
entry.is_stop)
SPACE space False
Data PROPN proper noun False
Exploration PROPN proper noun False
with ADP adposition True
Pandas PROPN proper noun False
Profiler PROPN proper noun False
and CCONJ coordinating conjunction True
D PROPN proper noun False
- PUNCT punctuation False
Tale PROPN proper noun False
读取表格数据
最后,让我们利用目前所学的知识,得到可以用表格形式显示的数据。我们在这篇文章的开头提到,我们可能希望看到不同国家在东京奥运会上获得的金牌数量。我们可以从维基百科的相关条目中读到这些信息。
url = 'https://en.wikipedia.org/wiki/2020_Summer_Olympics_medal_table'
wiki_page = requests.get(url)
medal_soup = BeautifulSoup(wiki_page.content, 'html.parser')
使用浏览器的 inspect 元素功能,我可以看到数据所在的表有一个类。查看我的浏览器截图:
medal_table = medal_soup.find('table',
class_='wikitable sortable plainrowheaders jquery-tablesorter')
在这种情况下,我们需要遍历每一行(tr
),然后将它的每个元素(td
)赋给一个变量,并将其追加到一个列表中。一个例外是含有th
元素的表格标题。
让我们找到所有的行。我们将挑选出第一个来提取标题,并将奖牌信息存储在一个名为allRows
的变量中:
tmp = medal_table.find_all('tr')
first = tmp[0]
allRows = tmp[1:-1]
让我们来看一个 first
的排:
print(first)
<tr><th scope="col">Rank</th><th scope="col">Team</th><th class="headerSort" scope="col" style="width:4em;background-color:gold">Gold</th><th class="headerSort" scope="col" style="width:4em;background-color:silver">Silver</th><th class="headerSort" scope="col" style="width:4em;background-color:#c96">Bronze</th><th scope="col" style="width:4em">Total</th></tr>
如您所见,我们需要找到所有的 th
标签并获取文本,此外,我们将使用 strip()
方法去掉标题和结尾空格。我们在一个列表理解语法中完成所有这些:
headers = [header.get_text().strip() for
header in first.find_all('th')]
print(headers)
['Rank', 'Team', 'Gold', 'Silver', 'Bronze', 'Total']
酷!我们现在把注意力转向奖牌:
results = [[data.get_text() for
data in row.find_all('td')]
for row in allRows]
print(results[:10])
[['1', '39', '41', '33', '113'],
['2', '38', '32', '18', '88'],
['3', '27', '14', '17', '58'],
['4', '22', '21', '22', '65'],
['5', '20', '28', '23', '71'],
['6', '17', '7', '22', '46'],
['7', '10', '12', '14', '36'],
['8', '10', '12', '11', '33'],
['9', '10', '11', '16', '37'],
['10', '10', '10', '20', '40']]
坚持下去…这看起来很棒,但它没有国名。让我们看看 的内容allRows
:
allRows[0]
<tr><td>1</td><th scope="row" style="background-color:#f8f9fa;text-align:left"><img alt="" class="thumbborder" data-file-height="650" data-file-width="1235" decoding="async" height="12" src="//upload.wikimedia.org/wikipedia/en/thumb/a/a4/Flag_of_the_United_States.svg/22px-Flag_of_the_United_States.svg.png" srcset="//upload.wikimedia.org/wikipedia/en/thumb/a/a4/Flag_of_the_United_States.svg/33px-Flag_of_the_United_States.svg.png 1.5x, //upload.wikimedia.org/wikipedia/en/thumb/a/a4/Flag_of_the_United_States.svg/44px-Flag_of_the_United_States.svg.png 2x" width="22"/> <a href="/wiki/United_States_at_the_2020_Summer_Olympics" title="United States at the 2020 Summer Olympics">United States</a> <span style="font-size:90%;">(USA)</span></th><td>39</td><td>41</td><td>33</td><td>113</td></tr>
啊哈!国家的名称在一个 th
标签中,实际上我们可以从超链接里面的字符串中提取出来:
countries = [[countries.find(text=True) for countries in
row.find_all('a')]
for row in allRows ]
countries[:10]
[['United States'],
['China'],
['Japan'],
['Great Britain'],
['ROC'],
['Australia'],
['Netherlands'],
['France'],
['Germany'],
['Italy']]
你可以从网站的表格中看到,一些国家的金牌、银牌和铜牌数量相同,因此排名相同。例如,见给予希腊和乌干达的第 36 位。这对我们的数据搜集策略有一些影响,让我们看看条目 35 到 44 的结果:
results[33:44]
[['34', '2', '4', '6', '12'],
['35', '2', '2', '9', '13'],
['36', '2', '1', '1', '4'],
['2', '1', '1', '4'],
['38', '2', '1', '0', '3'],
['39', '2', '0', '2', '4'],
['2', '0', '2', '4'],
['41', '2', '0', '1', '3'],
['42', '2', '0', '0', '2'],
['2', '0', '0', '2'],
['44', '1', '6', '12', '19']]
我们的行有五个条目,但是具有相同排名的行实际上有四个条目。这些条目都有一个 rowspan
属性如截图所示为排名36如下:
让我们找到具有 rowspan
属性的条目,并计算具有相同等级的国家的数量。我们将记录条目编号、 td
编号、共享相同等级和等级分配的国家数量:
rowspan = []
for num, tr in enumerate(allRows):
tmp = []
for td_num, data in enumerate(tr.find_all('td')):
if data.has_attr("rowspan"):
rowspan.append((num, td_num, int(data["rowspan"]), data.get_text()))
print(rowspan)
[(35, 0, 2, '36'),
(38, 0, 2, '39'),
(41, 0, 2, '42'),
(45, 0, 2, '46'),
(49, 0, 2, '50'),
(55, 0, 2, '56'),
(58, 0, 4, '59'),
(62, 0, 3, '63'),
(71, 0, 2, '72'),
(73, 0, 3, '74'),
(76, 0, 6, '77'),
(85, 0, 8, '86')]
我们现在可以通过在缺少值的行中插入正确的等级来修复我们的 results
:
for i in rowspan:
# tr value of rowspan is in the 1st place in results
for j in range(1, i[2]):
# Add value in the next tr
results[i[0]+j].insert(i[1], i[3])
让我们检查一下这是否有效:
print(results)[33:44]
[['34', '2', '4', '6', '12'],
['35', '2', '2', '9', '13'],
['36', '2', '1', '1', '4'],
['36', '2', '1', '1', '4'],
['38', '2', '1', '0', '3'],
['39', '2', '0', '2', '4'],
['39', '2', '0', '2', '4'],
['41', '2', '0', '1', '3'],
['42', '2', '0', '0', '2'],
['42', '2', '0', '0', '2'],
['44', '1', '6', '12', '19']]
我们现在也可以插入国名:
for i, country in enumerate(countries):
results[i].insert(1, country[0])
最后,我们可以用我们的数据创建一个熊猫数据框架:
import pandas as pd
df = pd.DataFrame(data = results, columns = headers)
df['Rank'] = df['Rank'].map(lambda x: x.replace('\n',''))
df['Total'] = df['Total'].map(lambda x: x.replace('\n',''))
cols = ['Rank','Gold', 'Silver', 'Bronze', 'Total']
df[cols] = df[cols].apply(pd.to_numeric)
df.head()
军阶 | 组 | 金色的 | 银 | 青铜 | 总数 | |
---|---|---|---|---|---|---|
Zero | one | 美国 | Thirty-nine | Forty-one | Thirty-three | One hundred and thirteen |
one | Two | 中国 | Thirty-eight | Thirty-two | Eighteen | Eighty-eight |
Two | three | 日本 | Twenty-seven | Fourteen | Seventeen | Fifty-eight |
three | four | 大不列颠 | Twenty-two | Twenty-one | Twenty-two | Sixty-five |
four | five | 皇家对空观察队 | Twenty | Twenty-eight | Twenty-three | Seventy-one |
df['Gold'].mean()
3.6559139784946235
df['Total'].mean()
11.612903225806452
摘要
我们已经看到了如何解析一个 HTML 文档,并在 Beautiful Soup 的帮助下理解其中的标签。你可能想用你在这里学到的一些东西来获取一些数据,否则这些数据可能只能在网页上找到。请记住,您应该注意您正在获取的材料的权利。阅读您感兴趣的页面的条款和条件,如果有疑问,最好谨慎行事。最后一句话,网页抓取取决于你正在解析的网页的结构。如果页面发生变化,您的代码很可能会失败。在这种情况下,准备好卷起袖子,重新检查 HTML 标签,并相应地修改代码。