原文:Domino Blog
考虑换工作?以下是 3 位顶级数据科学领导者和创新者的必读建议
如果你正在从事数据科学工作,并且想换一份工作,那么在你寻找新的机会或计划下一步职业发展时,顶级数据科学创新者会给出一些建议。他们的职业建议——以及更多建议——都收录在来自多米诺数据实验室的新书《数据科学创新者行动手册》中。
好消息是,你在一个非常令人向往的领域,所以你的下一份工作有几个选择,无论是在你现在的公司还是在新的雇主。那么,考虑你的数据科学职业的最佳方式是什么呢?
求职和你整个职业生涯的职业建议
谷歌的首席决策科学家凯西·科兹尔科夫(Cassie Kozyrkov)提供了一些职业建议,这些建议不仅适用于剔除可能不适合你的才能和抱负的机会,还适用于设定能让你长期快乐的目标。
她解释道:“我人生中最大的成功就是我希望这个星球上的每一个人都能做到的:花时间充分了解自己,以设计实现自我的目标,而不是追求更适合别人的生活。”。
“这也意味着对你周围每个人都想要的东西说不,”她总结道。“每个人都是独一无二的——我们都有自己的古怪之处,所以真正的成功必须从设计我们自己的生活开始,而不是复制别人的生活。”
不要为混蛋工作——也不要让你的工作把你变成混蛋
John K. Thompson 的职业生涯包括在几家大公司担任数据科学领导,他写了一本关于 建立分析团队 s 的书,并且他在 数据科学创新者行动手册 和 的附带博客 中为数据科学家提供了广泛的职业建议。
对于每个人,在职业生涯的各个阶段,他都提出了以下建议:“不要为混蛋工作。”如果你重视长期的工作满足感和幸福感,也不要做这样的人。
“我的一位 MBA 教授告诉我们,你在工作中成为什么样的人,将对你的个人生活产生直接而巨大的影响,”汤普森说。
“这两者不能分开。他补充道:“如果你在工作中粗鲁无礼,让人无法忍受,你的私人生活也会如此。”
Thompson 还为职业生涯早期、中期和高级数据科学家及其领导者提供了具体建议:
年轻的数据科学家
-
好奇。
-
每天都要学习。
-
抓住机会。
职业生涯中期的专业人士
-
努力应对不断增加的复杂性,不要自满,一遍又一遍地解决同样的问题。
-
帮助年轻员工。
-
帮助你的社区。
-
慷慨地付出你的时间和知识。
经验丰富的数据科学领导者
-
要知道,你知道的并没有你以为的那么多。
-
向年轻员工学习。
-
回馈数据科学社区。
寻找能为职业发展提供必要条件的公司
顶级数据科学领导者 Glenn Hofmann 为希望留住数据科学家的领导者和希望做出改变的数据科学家提供了颇具洞察力的建议。
他建议希望雇佣、培养和留住数据科学人才的数据科学领导者“记住,数据科学家和数据科学团队中的其他每个人——包括 MLOps 工程师、运营和项目经理——都希望看到他们的工作有所作为。确保模型被业务部署和使用将有助于吸引人才到您的团队并留住人才。此外,为了吸引人才,你需要提供合适的资源、职业道路、培训计划和学习津贴。”
寻找新机会的精明的数据科学家知道这一点,并寻找为其团队提供适当资源的组织,为其最优秀的人才提供良好的职业发展道路,赞助有趣的培训计划,并为学习津贴提供充足的预算。
寻找最大限度减少 IT-数据科学家冲突的公司
许多数据科学求职者正在寻找比他们在当前工作中体验到的更具协作性的环境。数据科学越来越不仅仅是数据科学家团队内部的协作;相反,这通常是跨部门的努力,有时有些令人担忧。
例如,数据科学家和 IT 之间的关系令人惊讶地存在问题。DataIQ 调查发现,大约三分之一(33.7%)的受访组织将“数据科学与 IT 之间的冲突”视为最大的挑战之一。就数据和分析的采用水平而言,即使是将自己评为“先进”或“即将成熟”的公司也无法避免冲突。对于这两个群体来说,“数据科学和 IT 之间的冲突”是他们最大的挑战(分别为 52.4%和 50%)。
Thompson 说:“数据科学和 IT 之间的冲突表现在许多方面,它通常是因为它像对待其他软件项目一样对待数据科学模型而开始的。缓解冲突的一部分来自于分析 IT 和数据科学部门面临的不同压力和要求。IT 专家并不总是理解建模与软件开发有多么不同。
“模型需要重新训练,以实验的方式开发,并使用许多不同的软件工具制作。他说:“没有必要‘再培训’软件代码,但(数据科学)生产模型需要经常再培训。”。
这种情况的部分补救措施可能是认识到数据科学和数据科学家并不完全适合现有的结构。出于这个原因,有必要重新思考一系列相关的实践和关于数据科学家做什么和他们如何工作的既定思维方式。
“实现数据科学最大价值的公司明白,模型是一种新型的数字生活,需要不同的人、流程和平台(而不是它通常支持的那些),”汤普森说。
有关 2022 年雇佣和留住数据科学家的更多信息,请查看这个有用的页面“管理数据科学团队”
其他特色创新者也参与了数据科学职业战略
下载免费的 数据科学创新者手册 阅读更多来自 Thompson、Kozyrkov 和 Hofmann 以及其他许多人的职业建议和见解。本书中的顶级创新者完整列表包括:
- 凯西·科济尔科夫——谷歌首席决策科学家,他描述了数据科学家、数据工程师和数据科学生态系统中其他人的工作是如何变化的。
- Andy Nicholls——GSK PLC 统计数据科学部门的高级主管,他描述了数据科学家、MLOps 工程师和其他人简化药物审批和临床试验流程的许多部分的机会。
- Mona g . Flores—NVIDIA 医疗人工智能全球负责人,他谈到了应用人工智能和人工智能来转变医疗和制药业务运营的机会。
- 纳贾特·汗——强生公司让桑制药公司首席数据科学官兼战略部&运营研究&开发全球主管,他谈到了数据科学团队成功的要素。
- 罗伯特·西原——Ray 的联合创始人,Anyscale 的联合创始人&首席执行官,他谈到了随着分布式资源变得更容易使用,科学家将需要的技能。
- John k . Thompson—分析思想领袖,畅销书作家,数据创新者&分析,提供更多关于成长中的创新团队的见解。
- Glenn Hofmann—纽约人寿保险公司首席分析官谈如何建立成功的数据科学团队。
在笔记本电脑上进行数据科学研究的成本
原文:https://www.dominodatalab.com/blog/cost-data-science-laptops
数据科学流程的核心是资源密集型的建模和验证任务。在这些任务中,数据科学家将尝试并丢弃数千个临时模型,以找到最佳配置。即使对于小数据集,这也可能需要几个小时来处理。
因此,依赖笔记本电脑或部门服务器处理能力的数据科学家必须在快速处理时间和模型复杂性之间做出选择。
无论哪种情况,性能和收入都会受到影响:
- 模型复杂性降低会导致模型不太精确,从而影响收入。
- 增加的处理时间意味着运行更少的实验,这限制了创新,因此影响了收入。
不太精确的模型的成本
以流失预测为例,这是几乎所有组织都有的事情。下面的分析表明,即使是 5000 个客户的小数据集,简单模型和复杂模型之间的准确度也有 10%的差异。模型准确性 10%的微小差异会因客户流失而导致 28,750 美元的收入损失。
我们的分析基于来自 UCI 知识库的流失数据集。该数据集包含 5,000 名电信客户的列表,每个客户的属性包括帐户长度和客户服务呼叫次数,以及客户是否有过交易。我们假设干预成本为 50 美元,成功率为 60%,每个客户的损失为 500 美元。
我们训练了 3 个模型来预测 1,000 个帐户的测试集上的客户流失。我们使用笔记本电脑质量的硬件,就像许多组织中的数据科学家一样。
| 模型 | 错过的搅拌 | 不必要的外联 | 费用 |
|---|---|---|---|
| GLMNET | One hundred and twenty | Seventeen | $36,850 |
| 马恩岛 | Thirty-eight | Fourteen | $12,100 |
| H2O 组合体 | Twenty-four | Eighteen | $8,100 |
使用 R’s glm net 的线性模型
这是数据科学家在硬件限制下可能训练的模型类型的代表。
结果:
- 测试集的总体准确率为 86%
- 120 名不明身份的顾客
- 17 例不必要的接触不太可能流失的客户
- 由于车型表现不佳造成 36,850 美元的损失
使用 R 的 GBM 的 GBM 模型
该模型利用了比线性模型更先进的算法,在预测客户流失方面提高了 8%。
结果:
- 总体准确率 94%
- 38 名不明身份的顾客
- 14 次不必要的外联
- 由于车型表现不佳,损失 12,100 美元
尖端堆叠 H2O 系综
这是建模技术的前沿。这是科学家希望做的那种建模数据,但受到硬件条件的限制。
该模型利用梯度提升机器、随机森林和深度学习神经网络来提供集合预测。它提供了最高的性能和最大的成本节约。
结果:
- 总体准确率为 95.8%
- 24 名不明身份的顾客
- 18 次不必要的外联
- 由于车型表现不佳,损失 8100 美元
尖端模型和简单模型之间的差异是 10%的精确度,这相当于 27,850 美元。请记住,这是一个只有 5000 名客户的小数据集,使用的是保守估计。在大型组织中,不太精确的模型的成本很容易达到几十万甚至几百万。
为什么不总是使用最好的模型呢?答案在于训练次数和有限处理能力的成本。
受限处理能力的成本
高性能模型需要更多的处理能力,在标准笔记本电脑上,训练这些模型可能需要小时。以下是我们分析中每个模型的训练时间:
| 模型 | 培训时间(笔记本电脑) | 错过的搅拌 | 不必要的外联 | 费用 |
|---|---|---|---|---|
| GLMNET | 43 秒 | One hundred and twenty | Seventeen | $36,850 |
| 马恩岛 | 828 秒 | Thirty-eight | Fourteen | $12,100 |
| H2O 组合体 | 小时 | Twenty-four | Eighteen | $8,100 |
**在笔记本电脑等受限硬件上工作的数据科学家不太可能尝试高性能模型,因为他们要花半天时间才能得到结果。**这还没有考虑验证每个模型的结果所需的额外时间。
如果他们为了得到更精确的模型而选择等待几个小时,他们就没有时间去做其他可能会得到更好结果的实验了。这种机会成本导致创新缓慢或停滞,并且无法对组织产生重大影响。
这是一组可怕的选择,然而许多数据科学家每天都处于这种境地。
只要数据科学家被迫在受限的机器上工作,如笔记本电脑或自我管理的部门服务器,组织就将继续亏损和失去竞争优势。
另一个选择:云
解决方案是让数据科学家在云硬件上运行实验。
下表显示了在云中运行时,我们的分析中每个模型的训练时间,证明了在不牺牲时间的情况下开发准确的模型是可能的。
| 模型 | 培训时间(笔记本电脑) | 培训时间(云) | 错过的搅拌 | 不必要的外联 | 费用 |
|---|---|---|---|---|---|
| GLMNET | 43 秒 | 9 秒 | One hundred and twenty | Seventeen | $36,850 |
| 马恩岛 | 828 秒 | 27 秒 | Thirty-eight | Fourteen | $12,100 |
| H2O 组合体 | 小时 | 71 秒 | Twenty-four | Eighteen | $8,100 |
尖端的 H2O 模型——在笔记本电脑上需要几个小时——在一台 AWS X1 实例上只需一分多钟,成本约为 39 美分。这为组织节省了 27,850 美元,并让数据科学家有很多时间来尝试其他模型和实验。
结论
让数据科学家在笔记本电脑上工作的成本非常高。即使在处理小型数据集时,数据科学家也必须在开发精确模型和更快开发模型之间做出选择。这两种选择都会导致组织的收入损失。
云是数据科学团队的最佳家园。它使他们能够尝试更大胆的实验并使用尖端技术,从而为组织带来显著且可量化的投资回报。
让数据科学家访问按需和可扩展的云硬件,而不需要供应或维护云服务的最简单、最快速的方法是使用 Domino 等数据科学平台。
在锁定期间创建一个有影响力的数据领导者社区
原文:https://www.dominodatalab.com/blog/creating-a-community-of-impactful-data-leaders-during-a-lockdown
本文最初发表于 LinkedIn 。感谢丹·哈里斯允许我们在这里重新发布它。

今年 3 月,我们精心策划的商务活动、会议日历一夜之间消失了。在意识到虚拟世界将成为新常态之前,有一段短暂的不确定性。
在封锁之前,我的同事尼古拉·曼切夫为数据科学从业者建立了伦敦机器学习会议,当他将会议转移到网上时,出席人数增加了。
我意识到我们需要某种东西来弥合从数据从业者到数据领导者之间的鸿沟。为了取得成功,它需要立即对数据主管有价值。这不是一件容易的事。
重新设想的想法
之前在 Dataiku 任职期间,我成立了一个名为数据和鸡尾酒的团队。我与伊登·史密斯合作,他帮助招募了我们的第一批代表。彼得·杰克森是我们的开场发言人,当时他和卡洛琳·卡鲁泽斯正在完成首席数据官行动手册的终稿,这本书已经成为当前*(以及未来)*首席数据官的必读书目。
我带着十几个问题去参加了那个活动,在演讲结束后开始小组讨论。我不需要它们。也许是鸡尾酒的缘故,但谈话在彼得演讲后立即开始,并在接下来的两个小时里没有停止!
代表们愿意公开分享他们的挑战,尤其是他们在哪些方面遇到困难,这让我大吃一惊。许多人是他们公司雇佣的第一批数据领导者,并且正在为他们的公司建立全新的数据实践。他们得到了高管层的支持,高管们知道他们需要将数据作为数字化转型的核心,但往往缺乏需要交付什么的细节。
那张白纸既是祝福也是诅咒…
显而易见的是,这些数据领导者也有类似的经历,并希望有一个安全的环境,让他们可以与同行社区分享问题和交流想法。也许与我以前在数据库技术方面的角色相比,这是数据科学相对较新的一面,但这种坦诚的交流是我从未见过的。
当时我知道我们正在做一些事情,我知道我想在 2020 年在多米诺骨牌上复制类似的事情。
进入数据领导者行政休息室
我们需要为虚拟世界重新构思*‘数据和鸡尾酒’的概念。我们作为一个团队集思广益,想出了给人们送一份礼物的主意,他们可以用这份礼物在会议期间与专家进行“金钱买不到经验”*。
在我们 EMEA 负责人 Colin Mitchell 的高管支持下,我们推出了一个快速登陆页面、个人邀请函和 RSVP 表格。我们不知道人们是否愿意提供他们的家庭住址,或者他们是否感兴趣。我们不必担心,因为我们在 24 小时内超过了 12 名代表的目标,两周后有 30 人参加了我们的第一次活动。
我永远感谢 Graham Pymm 为我带来了一次独特的品酒体验,一次极具魅力的 Glaswegian 式的转变!
为什么数据领导者选择加入我们,而不是建立团体?
这个问题我已经纠结了一段时间。我想,也许我们是较早将互动礼物理念推向市场的,从那以后,我看到许多其他公司也在这么做。但我认为这不是主要原因。我认为我们所挖掘的,是一种真正的需要,那就是在不同的组织中处理类似挑战的同事之间的人类互动,把他们聚集在一起分享想法和挑战,有时是一个可以哭泣的肩膀!
进一步分析,我认为这些因素也起了作用。
1.排他性
我们让它只接受邀请,在发送之前审查每一份邀请,并在授予访问权限之前仔细检查我们的 RSVP,以确保我们保持小组的完整性,只有数据领导者才能访问。例如,你需要管理一个数据部门、业务或团队才能加入。这样,我们可以保持我们的话题具有战略性,谈话与领导力挑战相关。
这个小组是我曾经参加过的面对面会议的最佳替代方案之一!这里的想法确实帮助我在我的 60 名数据科学家团队中扩展和自动化了模型构建。你做得很好!
2.机密
虽然我们将使用 Zoom 作为交付平台,但我们从一开始就决定不录制会议,甚至不使用跟踪与会者的 Zoom 公司网络研讨会版本。相反,我们在我的个人 Zoom 帐户上运行它,所有需要的就是邀请链接和会议密码。我们宣布会议将按照查塔姆大厦规则举行,目的是鼓励开放讨论,促进信息共享。
**### 3.特异性和相关性
我们为第一个活动创建了一个入口调查,在该调查中,我们询问小组成员他们面临的主要数据挑战是什么,以及他们认为应对这些挑战最有见地的方式是什么。虽然他们很高兴听到来自 Domino 和我们合作伙伴的消息,但他们最感兴趣的是听到来自他们同行的真实世界的谈话,以及我们为讨论和辩论创建一个开放的格式。
我们很喜欢来自数据领导者的演讲,如哈文德·阿特瓦尔和本·迪亚斯,但此后我们也加入了福布斯人工智能专栏作家和风险投资家罗布·托尤斯,作者卡洛琳·卡鲁泽斯和数据人事首席执行官杰斯·克拉克的观点。不过,最精彩的部分是我们放下话筒,向观众敞开心扉。我们从来不缺少生动的辩论!
我们很高兴收到我们的会员主动提供的话题和发言,因为这真的有助于保持事情的相关性,并确保我们的会员有很高的再次出席率。
4.社区和网络
在疫情期间,面对面的联系基本上已经不可能,商业模式已经被打乱,我们很遗憾地看到团队被解雇、裁员,甚至成员失去了自己的职位。Data Leaders 行政酒廊在此期间一直是风暴中的一个港口。与此同时,其他团队也在蓬勃发展并不断招聘,我们已经看到了成员组织之间的一些流动性。
每一版的休息室都扩大了一倍,这种增长很大程度上是由会员推荐他们网络中的同行推动的。
5。乐趣
在开始的时候,我非常注意到 Zoom 电话的增加和个人接触的减少正在导致倦怠。随着几乎所有的面对面会议都转向在线,人们最不需要的就是*‘另一个放大电话’,*不管多么善意。
我个人最喜欢的是 【下班后酒吧锁定】 和令人捧腹的詹姆斯·凯洛,一半的人在会议结束后呆了一个多小时,谈论数据和品尝啤酒!
我们决定通过引入*“精选体验”*来开启每次会议,从而提升活动的档次。这种体验有适当的质量来反映观众的资历,但有一个物理元素,以便他们可以一起玩。我们向人们运送了葡萄酒、杜松子酒、精酿啤酒、巧克力和咖啡,并请来了专家来指导品尝会。这是通向会谈的一个奇妙的破冰方式。
这只是旅程的开始
我的共同主持人戴夫·布洛克和我正在计划下一次的休闲活动。如果你是一名数据领导者,并且认为成为这个小组的成员可能对你有价值,请给我发一条私信,我很乐意告诉你更多。
最初在英国发起的项目已经迅速扩展到欧洲大部分地区,上个月,我们在美国的团队也开始效仿。数据领导者高管休息室正在走向全球!我们希望你能参与其中!**
使用“叶子”创建交互式犯罪地图
原文:https://www.dominodatalab.com/blog/creating-interactive-crime-maps-with-folium
你可以在这里看到这个多米诺骨牌项目。
一张漂亮的地图让我非常兴奋。但是当谈到用 Python 创建地图时,我一直在不断变化的 Python 库中寻找合适的库。经过一些研究,我发现了叶,这使得用 Python 创建叶地图变得很容易。这篇博文概述了我如何使用 fluous 可视化一个关于旧金山犯罪的数据集。然后,我描述了如何使用 Domino 将 Python 代码转换成自助报告工具。
什么是叶?
是一个强大的 Python 库,可以帮助你创建几种类型的传单地图。事实上,follow 结果是交互式的,这使得这个库对于仪表板的构建非常有用。要获得一个想法,只需在下一张地图上缩放/点击即可获得印象。《T2》中的 github 包含了许多其他的例子。
默认情况下,follow 在一个单独的 HTML 文件中创建一个地图。如果你使用 Jupyter(像我一样),你可能更喜欢使用内嵌地图。这个 Jupyter 例子展示了如何内嵌显示地图。
收集数据
对于这个例子,我需要一些包含位置的有趣数据。我决定使用来自 SF OpenData 的 SFPD 事件数据。使用导出功能(选择 csv)下载整个数据集。

构建树叶地图
安装好数据后,我们可以开始编写脚本来可视化我们的数据。要开始设置,您需要在您的终端中运行pip install folium来安装 lyum。
Jupyter 笔记本只有几行代码。它将事件文件加载到 pandas 数据帧中,选择前 1000 条记录以加快速度,并创建一个包含交互式地图的内嵌地图,该地图带有基于结果数据集的标记。
import folium
import pandas as pd
SF_COORDINATES = (37.76, -122.45)
crimedata = pd.read_csv("SFPD_Incidents_2015.csv")
# for speed purposes
MAX_RECORDS = 1000
# create empty map zoomed in on San Francisco
_map = folium.Map(location=SF_COORDINATES, zoom_start=12)
# add a marker for every record in the filtered data, use a clustered view
for each in crimedata[0:MAX_RECORDS].iterrows():
_map.simple_marker(
location = [each[1]["Y"],each[1]["X"]],
clustered_marker = True)
display(_map)
当运行这个程序时,它会创建一个带有位置标记的地图,如果位置标记靠得很近,就会聚集在一起(clustered_marker = True)。这里使用的 tileset 是 OpenStreetMap(这是默认设置)。leav 也可以和其他 tilesets 一起使用,比如 Mapbox 或者 Cloudmade。

通过使用map.create_map(path='map.html')而不是display(map)将地图保存为 html 文件
等值区域图
嗯,那很有趣!但是这可能不是比较地图的理想可视化方式。幸运的是,多亏了叶,还有一种创建 choropleth 地图的方法。
维基百科:
choropleth 地图(源自希腊语χώρο(“区域/地区”)+ πλήθος(“大众”))是一种专题地图,其中区域按照地图上显示的统计变量(如人口密度或人均收入)的度量值成比例地进行着色或图案化。
要创建 choropleth,我们需要一个 geojson 文件来创建与数据文件中的旧金山警区相匹配的区域/边界。在谷歌上搜索“旧金山警察局地区地理信息”,我找到了一个政府开放数据网站,它的 Shapefile 几乎符合我的需求。
下一步是将 Shapefile 转换为 geojson 文件。最简单的方法是使用一个 ogr2ogr web 客户端。选择下载的 zip 文件,并将crs:84放入目标 SRS 字段。将结果保存为 sfpd zones . geo JSON,并将文件上传到 Domino 项目。
创建 choropleth 的额外 Python 代码如下。注意,我使用了整个数据集,而不是前面使用的 1000 条记录。因为 choropleth 基于聚合计数,所以速度不会受到大型数据集的影响。
# definition of the boundaries in the map
district_geo = r"sfpddistricts.geojson"
# calculating total number of incidents per district
crimedata2 = pd.DataFrame(crimedata["PdDistrict"].value_counts().astype(float))
crimedata2.to_json("crimeagg.json")
crimedata2 = crimedata2.reset_index()
crimedata2.columns = ["District", "Number"]
# creation of the choropleth
map1 = folium.Map(location=SF_COORDINATES, zoom_start=12)
map1.geo_json(geo_path = district_geo,
data_out = "crimeagg.json",
data = crimedata2,
columns = ["District", "Number"],
key_on = "feature.properties.DISTRICT",
fill_color = "YlOrRd",
fill_opacity = 0.7,
line_opacity = 0.2,
legend_name = "Number of incidents per district"
它创建了一个如下的 choropleth 地图,在右上角有一个图例。颜色调配器颜色方案是内置的,可以像fill_color = 'YlOrRd'一样添加。聚合计数存储在一个单独的 json 文件(crimedata2.to_json('crimeagg.json'))中,该文件稍后将在地图创建过程中用作数据源。

构建自助报告工具
犯罪事件数据不仅仅是地点和地区,而是更加丰富。它还包含类别、日期和时间等变量。例如,这为更好地了解特定类型的事件创造了机会。为了避免为所有的变量组合创建地图,我使用了 Domino 的“Launcher”特性,让其他人根据他们的参数创建他们自己的地图。

Domino 中的启动器是一个自助式 web 表单,允许非技术用户运行您的脚本。要创建一个,我们只需要指定通过 web 表单公开什么参数。
我的启动器将有两个参数:
1。“Dayofweek”是一个多选列表,包含一周中的所有日子。
2。“类别”是一个选择菜单,包含数据中的所有事件类别。
出于懒惰,我决定创建一个小脚本来创建数据中出现的类别列表。

我将第二个单元格的结果复制粘贴到新创建的启动器中的 Allowed Values 字段。
处理启动器请求的脚本是 main.py 。下一段代码处理用户输入,并使用它来过滤数据集:
args = sys.argv
dayselect = args[1].split(",")
crimeselect = args[2]
daycond = crimedata["DayOfWeek"].isin(dayselect)
crimecond = crimedata["Category"] == (crimeselect)
filtered_crimedata = crimedata[crimecond & daycond]
既然我们有了类别和描述信息,为什么不用它作为标记的弹出窗口呢?只需将popup=each[1]['Category'] + ": " + each[1]['Descript']添加到标记放置功能的参数中。Main.py 包含标记映射代码和 choropleth 代码。
现在我们可以使用启动器创建地图。以下(静态)地图显示了周末(周六和周日)的毒品和麻醉品相关事件。放大创建的地图将使集群分裂。蓝色标记代表个别事件。看到大多数与毒品有关的事件发生在嫩腰区及其附近,可能并不奇怪。

它还创建了一个像这样的 choropleth 地图,讲述了一个类似于带有标记的地图的故事。

奖励:比较地图
现在我们已经创建了这样的代码和启动器,我们可以使用 Domino 比较特性将多个地图并排放置。
我有两次不同的经历,一次是在周末,一次是在工作日。两次运行都成功了。下一步是选择两个运行,并点击顶部的比较。

将打开一个页面,其中包含两次运行的比较。好的一面是它会把地图放在一起。这样我们可以很容易地看到,在我们的例子中,盗窃似乎在周末比在工作日更均匀地分布在旧金山。

这就是我们要做的,一个非常简单的创建和比较地图的方法。我还没有发现非常令人震惊的犯罪事件趋势。所以请在评论中分享你最感兴趣的发现。
使用 Apache Spark 创建多语言管道或避免将 spaCy 重写为 Java
在这篇客座博文中, Holden Karau , Apache Spark Committer ,提供了关于如何使用 Apache Spark 创建多语言管道以及避免将 spaCy 重写为 Java 的见解。她已经写了一篇关于使用 spaCy 为 Domino 处理文本数据的补充博客文章。 Karau 是谷歌的开发者拥护者,也是高性能火花和学习火花的合著者。她在 Twitch 和 Youtube 上也有一个关于她的演讲、代码评审和代码会议的知识库。
介绍
作为一名 Scala/Java data/ML 工程师,您是否发现自己需要使用一些现有的 PySpark 代码,但不想重写所有使用过的库?或者您只是厌倦了 JVM 中的 NLP 选项,想尝试一下 spaCy?Apache Spark 新的基于 Apache Arrow 的 UDF 不仅提供了性能改进,还可以与实验特性相结合,以允许跨语言管道的开发。这篇博文关注的是 spaCy 的使用,我还有另外一篇关于 NLTK 的文章,我将会发布在我的博客上。如果您希望在单语言管道中使用 spaCy 和 PySpark,那么我之前的文章《让 PySpark 与 spaCy 一起工作:克服序列化错误》会对您有所帮助
如果您选择在生产中使用这些技术,请预先注意在 Spark 中调试多语言管道会增加额外的层次和复杂性。你应该看看霍尔登的调试 Spark 视频,如果你有公司费用账户,还有一个在 Safari 上提供的关于调试 Apache Spark 的深度潜水。
从 Scala / Java 调用和注册 Python UDFs
我们的第一步需要为 JVM 设置一种方法来调用 Python,并让 Python 将 UDF 注册到 Java 中。
在 startup.py 中,我们可以创建一个入口点,这样我们的 Java 代码就可以调用 Py4J。这个连接 Python 和 Scala 的样板有点烦人。如果你想看细节(或者破坏魔法),你可以看看 Initialize.scala 和 startup.py 。其中的关键部分是一个注册提供者,它在 Scala & Python:
# This class is used to allow the Scala process to call into Python
# It may not run in the same Python process as your regular Python
# shell if you are running PySpark normally.
class PythonRegistrationProvider(object):
"""Provide an entry point for Scala to call to register functions."""
def __init__(self, gateway):
self.gateway = gateway
self._sc = None
self._session = None
self._count = 0
def registerFunction(self, ssc, jsession, function_name, params):
jvm = self.gateway.jvm
# If we don't have a reference to a running SparkContext
# Get the SparkContext from the provided SparkSession.
if not self._sc:
master = ssc.master()
jsc = jvm.org.apache.spark.api.java.JavaSparkContext(ssc)
jsparkConf = ssc.conf()
sparkConf = SparkConf(_jconf=jsparkConf)
self._sc = SparkContext(
master=master,
conf=sparkConf,
gateway=self.gateway,
jsc=jsc)
self._session = SparkSession.builder.getOrCreate()
if function_name in functions_info:
function_info = functions_info[function_name]
if params:
evaledParams = ast.literal_eval(params)
else:
evaledParams = []
func = function_info.func(*evaledParams)
ret_type = function_info.returnType()
self._count = self._count + 1
registration_name = function_name + str(self._count)
udf = UserDefinedFunction(func, ret_type, registration_name)
# Configure non-standard evaluation types (e.g. Arrow)
udf.evalType = function_info.evalType()
judf = udf._judf
return judf
else:
return None
class Java:
package = "com.sparklingpandas.sparklingml.util.python"
className = "PythonRegisterationProvider"
implements = [package + "." + className]
在 Scala 方面,它看起来像这样:
/**
* Abstract trait to implement in Python to allow Scala to call in to perform
* registration.
*/
trait PythonRegisterationProvider {
// Takes a SparkContext, SparkSession, String, and String
// Returns UserDefinedPythonFunction but types + py4j :(
def registerFunction(
sc: SparkContext, session: Object,
functionName: Object, params: Object): Object
}
构建用户定义的函数是在基类 PythonTransformer 中完成的。主调用通过以下方式完成:
// Call the registration provider from startup.py to get a Python UDF back.
val pythonUdf = Option(registrationProvider.registerFunction(
session.sparkContext,
session,
pythonFunctionName,
miniSerializeParams()))
val castUdf = pythonUdf.map(_.asInstanceOf[UserDefinedPythonFunction])
因为我们现在需要在 JVM 和 python 之间传递一个参数(例如,我们正在使用的语言),所以包装器必须有逻辑来指向所需的 Python 函数和用于配置它的参数:
final val lang = new Param[String](this, "lang", "language for tokenization")
/** @group getParam */
final def getLang: String = $(lang)
final def setLang(value: String): this.type = set(this.lang, value)
def this() = this(Identifiable.randomUID("SpacyTokenizePython"))
override val pythonFunctionName = "spaCytokenize"
override protected def outputDataType = ArrayType(StringType)
override protected def validateInputType(inputType: DataType): Unit = {
if (inputType != StringType) {
throw new IllegalArgumentException(
s"Expected input type StringType instead found ${inputType}")
}
}
override def copy(extra: ParamMap) = {
defaultCopy(extra)
}
def miniSerializeParams() = {
"[\"" + $(lang) + "\"]"
}
}
然后我们需要重构我们的 Python 代码,以便 Scala 代码可以很容易地调用这些参数。在 SparklingML 内部,我们有一个可以使用的基类,scalarvectorizedtransformation function,来处理一些样板文件,看起来像是:
class SpacyTokenize(ScalarVectorizedTransformationFunction):
@classmethod
def setup(cls, sc, session, *args):
pass
@classmethod
def func(cls, *args):
lang = args[0]
def inner(inputSeries):
"""Tokenize the inputString using spaCy for the provided language."""
nlp = SpacyMagic.get(lang) # Optimization for spacy.load
def tokenizeElem(elem):
result_itr = [token.text for token in nlp(elem)]
return list(result_itr)
return inputSeries.apply(tokenizeElem)
return inner
@classmethod
def returnType(cls, *args):
return ArrayType(StringType())
functions_info["spacytokenize"] = SpacyTokenize
SpaCyMagic:处处超越` spacy.load()’
PySpark 面临的一大挑战是序列化问题,对于多语言管道,这一挑战几乎加倍。
# Spacy isn't serializable but loading it is semi-expensive
@ignore_unicode_prefix
class SpacyMagic(object):
"""
Simple Spacy Magic to minimize loading time.
>>> SpacyMagic.get("en")
<spacy.lang.en.English ...
"""
_spacys = {}
@classmethod
def get(cls, lang):
if lang not in cls._spacys:
import spacy
try:
try:
cls._spacys[lang] = spacy.load(lang)
except Exception:
spacy.cli.download(lang)
cls._spacys[lang] = spacy.load(lang)
except Exception as e:
raise Exception("Failed to find or download language {0}: {1}"
.format(lang, e))
return cls._spacys[lang]
然后在我们的代码中,我们通过我们的朋友 SpacyMagic 访问 spaCy。
spaCy load pre-fork 在 Spark 2.4 中有一些有趣的新技巧,但这是另一篇博客文章的主题。(再一次,请关注我的博客,我将在那里分享它。)
用跨语言字数统计把它们联系在一起
如果我们不把重点放在字数上,这看起来就不像是一篇真正的大数据博客文章,但我们将通过使用 Scala 和 Python 的不同方式来完成它。在 Scala 中,我们可以使用我们创建的转换器对单词计数进行标记:
val data = session.load(...)
val transformer = new SpacyTokenizePython()
transformer.setLang("en")
transformer.setInputCol("input")
transformer.setOutputCol("tokens")
val tokens = transformer.transform(data)
val counts = tokens.groupBy("tokens").count()
counts.write.format("json").save("...")
包扎
虽然这些技术对于像 WordCount 这样的简单跨语言管道已经足够好了,但是在构建更复杂的管道时,我们还必须考虑一些其他方面。例如,即使在我们的简单示例中,spaCy 除了标记之外还有更多信息,并且当前在我们的 Panda 的 UDF 中缺少复合类型的数组,这使得返回复杂的结果很困难。
如果你觉得这很有趣,希望你能加入我们,为闪亮的 ML 项目、Apache Arrow 或 Apache Spark Python 和 Arrow 集成做出贡献。
进一步阅读
如果你有兴趣看到这篇文章的幕后,你可以看看这个现场编码会议和相应的闪闪发光的 ml 回购。如果你有兴趣向孩子们介绍分布式系统的神奇世界,请注册了解我的下一本书“分布式计算 4 孩子”。如果一切都着火了,这些调试资源( free talk 和subscription Safari deep-dive)至少应该能帮到你一点点。
使用 XGBoost、SMOTE 和阈值移动的信用卡欺诈检测
在本文中,我们将讨论组织在欺诈检测方面面临的挑战,以及如何使用机器学习来识别和发现人眼可能无法发现的异常情况。我们将通过 XGBoost 使用梯度增强技术来创建一个模型,我将向您介绍可以采取的步骤,以避免过度拟合,并构建一个适合目的并准备用于生产的模型。如果你想亲自尝试这个项目,你可以点击这里 注册一个 免费账户。
信用卡欺诈是金融机构面临的一个重大问题,可靠的欺诈检测通常具有挑战性。在这里,我们展示了如何在现实世界的信用卡欺诈数据集上训练机器学习模型,以及如何采用过采样和阈值移动等技术来解决类别不平衡问题。
从历史上看,欺诈检测是由负责识别和跟踪数据中的可疑模式的分析师执行的。在线交易的快速增长,通常与在线购物、移动支付等相关联。,使得这种方法不可行。现代交易数据集有数百个维度、数百万条记录,并且以在线方式不断更新。像依靠持卡人报告欺诈交易这样的辅助技术不幸被证明是无效的[1]。

Rules-based fraud detection (top) vs. classification decision tree-based detection (bottom): The risk scoring in the former model is calculated using policy-based, manually crafted rules and their corresponding weights. In contrast, the decision tree classifies observations based on attribute splits learned from the statistical properties of the training data.
自动信用卡欺诈检测通常使用以下方法之一来实现:
基于规则的检测 -基于硬编码的规则,这种方法需要大量的人工工作来定义大多数可能的欺诈条件,并制定触发警报或阻止可疑交易的规则。这种方法的一个优点是,它的决策本身是可以解释的——很容易识别将特定交易标记为欺诈的规则。缺点是基于规则的检测是计算密集型的,并且通常被实现为批量(或离线)评分。从维护的角度来看,保持规则更新并不断扫描漏网的假阴性也是一个挑战。
基于机器学习的检测 -使用统计学习是另一种越来越受欢迎的方法,主要是因为它不太费力。它可以实现为无监督(例如异常检测)或监督模型(分类),并且需要较少的维护,因为模型可以自动重新训练以保持其关联最新。它也适用于在线应用,因为评分功能通常非常轻量级。ML 方法的一个缺点是,对于某些算法(例如深度学习),没有保证的可解释性。
在这篇博文中,我们将展示一个基于 XGBoost 的基于 ML 的异常检测的实现。我们将经历一个典型的 ML 管道,在那里我们进行数据摄取、探索性数据分析、特征工程、模型训练和评估。
数据接收和探索性数据分析
我们从导入管道所需的 Python 库开始。然后,我们读取并检查样本数据集。该数据集包含匿名的信用卡交易数据,可从 Kaggle 免费获取。这些数据是 Worldline 和布鲁塞尔自由大学的机器学习小组合作研究的一部分。该数据集包含欧洲信用卡持有人在 2013 年 9 月进行的交易,并已被匿名化-功能 V1,V2,…、V28 是对原始数据应用 PCA 的结果。唯一完整的特征是时间和数量。类别标签的标题为 class,其中 0 表示真实交易,1 表示欺诈。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import random
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import GridSearchCV
from imblearn.over_sampling import SMOTE
from xgboost import XGBClassifier
from xgboost import Booster
from xgboost import DMatrix
from sklearn import metrics
from datetime import datetime
dataDF = pd.read_csv("dataset/creditcard.csv")
dataDF.head()

如果我们查看数据帧的维度,我们会注意到数据集总共包含 284,807 个样本。似乎也没有丢失值,但是,由于卡交易数据集通常包含大部分正常交易,只有一小部分欺诈交易,我们的预期是数据集将非常不平衡。我们可以通过检查目标类的分布来确认这一点。
value_counts = dataDF["Class"].value_counts()
value_counts.plot(kind="bar", title="Class distribution of the target variable")

欺诈交易占整个数据集的 0.17%。正如所料,大多数样本都是合法交易。只有 0.17%的交易被标记为欺诈。让我们看看所有属性的基本描述性统计数据。
pd.set_option("display.float_format", lambda x: "%.3f" % x)
dataDF.describe()

检查上面的统计数据可以发现,V1-V28 属性是以零为中心的,但是其他两个输入属性时间和数量却不是这样。
dataDF[["Amount", "Time"]].describe()

我们还可以绘制所有输入属性的直方图,并确保没有任何异常突出。
ax = dataDF.drop("Class", axis=1).hist(figsize=(10,12),bins=100)
# We hide the axes' labels to make the plot neater and more compact
for axis in ax.flatten():
axis.set_xticklabels([])
axis.set_yticklabels([])

对于主成分我们无能为力,但是看起来数量和时间属性需要更详细的检查。
首先,时间的基本统计数据表明这个属性是以时间戳(秒)的形式给出的。我们可以将其转换为当地日期并提取小时数,以尝试确定交易的小时数是否与交易欺诈的可能性相关。
dataDF["Hour"] = dataDF["Time"].apply(datetime.fromtimestamp).dt.hour
fig, ax = plt.subplots(2, figsize=(10,7))
for a in ax:
a.set_xticks(range(24))
dataDF.loc[dataDF["Class"] == 0]["Hour"].hist(bins=np.arange(24)-0.5, ax=ax[0], grid=False)
dataDF.loc[dataDF["Class"] == 1]["Hour"].hist(bins=np.arange(24)-0.5, ax=ax[1], grid=False)
ax[0].title.set_text("Legitimate Transactions")
ax[1].title.set_text("Fraudulent Transactions")
plt.subplots_adjust(hspace=0.3)

似乎合法交易在夜间急剧下降,随着工作日的开始,其比率增加。相比之下,凌晨 2 点左右是欺诈交易的高峰,这看起来很不寻常。此外,欺诈交易的数据看起来分布更加均匀。让我们编写一个简单的函数,它将允许我们在欺诈/非欺诈类之间比较单个属性的基本统计数据。
def compare_leg_fraud(attribute):
leg_trS = dataDF.loc[dataDF["Class"] == 0][attribute].rename("Legitimate").describe()
frd_trS = dataDF.loc[dataDF["Class"] == 1][attribute].rename("Fraudulent").describe()
tr_hourDF = leg_trS.to_frame().join(frd_trS.to_frame())
return tr_hourDF
compare_leg_fraud("Hour")

欺诈交易无疑具有较高的标准差,但鉴于其相对较低的数量,我们无法确定这是真实的模式还是只是统计上的巧合。
我们现在将注意力转移到交易金额上。让我们通过直方图直观显示欺诈交易与合法交易的分布。
fig, ax = plt.subplots(2, figsize=(9,7))
dataDF.loc[dataDF["Class"] == 0]["Amount"].hist(bins=30, ax=ax[0])
dataDF.loc[dataDF["Class"] == 1]["Amount"].hist(bins=30, ax=ax[1])
ax[0].title.set_text("Legitimate Transactions")
ax[1].title.set_text("Fraudulent Transactions")
plt.subplots_adjust(hspace=0.3)

让我们看看 Amount 属性的基本统计信息。
compare_leg_fraud("Amount")

看起来欺诈交易的平均交易金额较高,尽管总交易金额的绝对值明显较低。我们还可以看看前 5 个最频繁的合法交易。
(dataDF.loc[dataDF["Class"] == 0]["Amount"].value_counts(normalize=True)*100).head()
1.000 4.775
1.980 2.126
0.890 1.714
9.990 1.669
15.000 1.154
对比前 5 大欺诈交易
(dataDF.loc[dataDF["Class"] == 1]["Amount"].value_counts(normalize=True)*100).head()
1.000 22.967
0.000 5.488
99.990 5.488
0.760 3.455
0.770 2.033
我们看到,所有欺诈交易中有近 23%的交易金额为 1.0,而合法交易中相同交易金额的百分比接近 5%。我们还看到大量的 0 值交易,这很可能是持卡人详细信息验证交易的结果。
特征工程
在尝试任何功能工程之前,我们要做的第一件事是创建一个维持集。这是为了防止任何信息泄露到我们的测试集中。
trainDF, testDF = train_test_split(dataDF, test_size=0.2, random_state=1234, stratify=dataDF[["Class"]])
trainDF_norm["Amount"] = trainDF["Amount"].subtract(trainDF["Amount"].mean())
trainDF_norm["Hour"] = trainDF["Hour"].subtract(trainDF["Hour"].mean())
testDF_norm = testDF.copy()
testDF_norm["Amount"] = testDF["Amount"].subtract(testDF["Amount"].mean())
testDF_norm["Hour"] = testDF["Hour"].subtract(testDF["Hour"].mean())
trainDF = trainDF_norm
testDF = testDF_norm
tr_value_counts = trainDF["Class"].value_counts()
print("Fraudulent transactions are %.2f%% of the training set." % (tr_value_counts[1] * 100 / len(trainDF)))
tst_value_counts = testDF["Class"].value_counts()
print("Fraudulent transactions are %.2f%% of the test set." % (tst_value_counts[1] * 100 / len(testDF)))
Fraudulent transactions are 0.17% of the training set.
Fraudulent transactions are 0.17% of the test set.
我们在探索性分析中注意到,Amount 列不是零均值居中的。让我们来解决这个问题,并且将小时属性居中,我们将使用它来代替时间。
trainDF_norm = trainDF.copy()
trainDF_norm["Amount"] = trainDF["Amount"].subtract(trainDF["Amount"].mean())
trainDF_norm["Hour"] = trainDF["Hour"].subtract(trainDF["Hour"].mean())
testDF_norm = testDF.copy()
testDF_norm["Amount"] = testDF["Amount"].subtract(testDF["Amount"].mean())
testDF_norm["Hour"] = testDF["Hour"].subtract(testDF["Hour"].mean())
trainDF = trainDF_norm
testDF = testDF_norm
接下来,我们删除时间属性,因为我们将使用小时。
trainDF = trainDF.drop(["Time"], axis=1)
testDF = testDF.drop(["Time"], axis=1)
现在,让我们将自变量和类变量分割到单独的数据框中。
X_train = trainDF.iloc[:, trainDF.columns != "Class"]
y_train = trainDF.iloc[:, trainDF.columns == "Class"]
X_test = testDF.iloc[:, testDF.columns != "Class"]
y_test = testDF.iloc[:, testDF.columns == "Class"]
X_train.head()

过采样
我们已经确定原始数据集是高度不平衡的。这通常是有问题的,因为基于这种数据训练的模型将很难识别少数类。当我们不只是对预测结果感兴趣时(我们知道如果我们假设交易不是欺诈性的,我们在 99.83%的时间里都是正确的),而是检测少数类的实例(例如欺诈),这就变成了一个更大的问题。
在实践中,有两种解决类不平衡的常用技术,这两种技术都会在数据集中引入偏差,以均衡所有类的表示。
欠采样 -欠采样技术从优势阶层中移除观察值,以减少代表过多/代表不足的差距。例如,随机欠采样随机地移除样本(替换或不替换),经常直到多数类中的观察值的数量变得与少数类中的观察值的数量相同。
过采样 -过采样也旨在减少类计数差异,但与欠采样不同,它通过增加少数类中的实例数量来实现这一点。这种策略有不同的方法,最常用的两种是随机过采样和 SMOTE。随机过采样是一个相当简单的解决方案,它简单地制作现有少数类观测值的多个副本,从而增加来自少数类的总观测值的数量。另一方面,合成少数过采样技术(SMOTE) 通过创建合成样本对少数类进行过采样。已经证明 SMOTE 优于简单的欠采样[2]
使用 SMOTE 来纠正我们数据集中的不平衡是相当容易的,这要感谢不平衡学习,这是一个 Python 包,提供了许多重采样技术,包括 SMOTE。
X_train_smote, y_train_smote = SMOTE(random_state=1234).fit_resample(X_train, y_train)
smote_value_counts = y_train_smote["Class"].value_counts()
print("Fraudulent transactions are %.2f%% of the test set." % (smote_value_counts[0] * 100 / len(y_train_smote)))
Fraudulent transactions are 50.00% of the test set.
现在,班级失衡问题已经解决,我们可以继续进行实际的模型培训了。
模特培训
我们现在将使用过采样训练集来训练 XGBoost 分类器。首先,我们定义一个函数,该函数将对分类器的最佳超参数执行网格搜索。该功能的亮点如下:
我们对 params 中给出的超参数进行参数搜索
- 每个模型的交叉验证策略在分层折叠中使用 3 个折叠
- 评估搜索中模型的度量是受试者工作特征曲线下的面积(ROC AUC)
- 该函数打印产生最高 AUC 分数的参数,并返回最佳估计值的参数作为其输出
def xgboost_search(X, y, search_verbose=1):
params = {
"gamma":[0.5, 1, 1.5, 2, 5],
"max_depth":[3,4,5,6],
"min_child_weight": [100],
"subsample": [0.6, 0.8, 1.0],
"colsample_bytree": [0.6, 0.8, 1.0],
"learning_rate": [0.1, 0.01, 0.001]
}
xgb = XGBClassifier(objective="binary:logistic", eval_metric="auc", use_label_encoder=False)
skf = StratifiedKFold(n_splits=3, shuffle=True, random_state=1234)
grid_search = GridSearchCV(estimator=xgb, param_grid=params, scoring="roc_auc", n_jobs=1, cv=skf.split(X,y), verbose=search_verbose)
grid_search.fit(X, y)
print("Best estimator: ")
print(grid_search.best_estimator_)
print("Parameters: ", grid_search.best_params_)
print("Highest AUC: %.2f" % grid_search.best_score_)
return grid_search.best_params_
由于训练集相当大,我们将网格搜索限制为 5000 个观察值的样本。在xgboost_search检查完所有可能的评估器后,它将打印出用于最佳执行评估器的参数,并将返回一个 XGBClassifier 对象,我们可以用它来检查模型的泛化能力。
请注意,尽管我们使用了相对较小的训练数据子集,但搜索仍需要训练超过 1,600 个模型,这将需要一段时间。
rows = random.sample(np.arange(0,len(X_train_smote.index)).tolist(), 5000)
model_params = xgboost_search(X_train_smote.iloc[rows,], y_train_smote.iloc[rows,])
Fitting 3 folds for each of 540 candidates, totalling 1620 fits
Best estimator:
XGBClassifier(base_score=0.5, booster='gbtree', colsample_bylevel=1,
colsample_bynode=1, colsample_bytree=0.6, eval_metric='auc',
gamma=1, gpu_id=-1, importance_type='gain',
interaction_constraints='', learning_rate=0.1, max_delta_step=0,
max_depth=4, min_child_weight=100, missing=nan,
monotone_constraints='()', n_estimators=100, n_jobs=8,
num_parallel_tree=1, random_state=0, reg_alpha=0, reg_lambda=1,
scale_pos_weight=1, subsample=1.0, tree_method='exact',
use_label_encoder=False, validate_parameters=1, verbosity=None)
Parameters: {'colsample_bytree': 0.6, 'gamma': 1, 'learning_rate': 0.1, 'max_depth': 4, 'min_child_weight': 100, 'subsample': 1.0}
Highest AUC: 0.98
现在我们有了产生最高分数的参数集,我们可以使用它们在完整的过采样训练集上训练模型。
model = XGBClassifier(objective="binary:logistic", eval_metric="auc", use_label_encoder=False)
model.set_params(**model_params)
model.fit(X_train_smote, y_train_smote)
XGBClassifier(base_score=0.5, booster='gbtree', colsample_bylevel=1,
colsample_bynode=1, colsample_bytree=0.6, eval_metric='auc',
gamma=1, gpu_id=-1, importance_type='gain',
interaction_constraints='', learning_rate=0.1, max_delta_step=0,
max_depth=4, min_child_weight=100, missing=nan,
monotone_constraints='()', n_estimators=100, n_jobs=8,
num_parallel_tree=1, random_state=0, reg_alpha=0, reg_lambda=1,
scale_pos_weight=1, subsample=1.0, tree_method='exact',
use_label_encoder=False, validate_parameters=1, verbosity=None)
模型评估
我们将使用 ROC AUC 曲线来评估我们的模型在维持集(X_test,y_test)上的表现。为了生成 ROC 曲线,我们计算了不同阈值水平下维持集的真阳性(TP)和假阳性(FP)率。
对维持集调用predict_proba(X_test)[:,1]将给出样本[latex]{ Y _ I }[/latex]\ text { X \ _ test } _ I[/latex]属于第 1 类(欺诈)的估计概率。给定一个特定的阈值[latex]T[/latex],如果[latex]T>\ hat { Y _ I }[/latex],我们可以将[latex]\ text { X \ _ test } _ I[/latex]归类为欺诈。很明显,改变[latex]T[/latex]会影响 TP/FP 率,这就是 ROC 曲线所代表的。
我们还在图上显示了曲线下的面积(AUC ),因为它等于模型将均匀绘制的随机阳性排序高于均匀绘制的随机阴性的概率。
y_pred = model.predict_proba(X_test)[:,1]
fp_r, tp_r, t = metrics.roc_curve(y_test, y_pred)
auc = metrics.auc(fp_r, tp_r)
plt.figure(figsize=(8, 6))
plt.plot(fp_r, tp_r, label="AUC = %.2f" % auc)
plt.plot([0,1],[0,1],"r--")
plt.ylabel("TP rate")
plt.xlabel("FP rate")
plt.legend(loc=4)
plt.title("ROC Curve")
plt.show()

二元分类问题的标准方法是查看模型产生的概率,如果概率小于 0.5,则将观察值分类为 0 类,如果概率等于或大于 0.5,则将观察值分类为 1 类。在高度不平衡的数据集中,这种解释可能会导致糟糕的预测。偏移阈值(阈值移动)是一种标准技术,用于通过找到分类器产生的概率的最佳解释来改进预测。
欺诈检测中还有一个额外的因素,即一种错误分类的成本远远高于另一种。换句话说,将合法交易归类为欺诈最多是不方便的,但让欺诈交易溜走会带来更可怕的后果。在这种情况下,以减少假阳性为代价来抵消阈值成为一种可行的策略。
可以用多种方式来选择最佳阈值。查看 ROC 曲线,我们可以直观地看到,最佳性能(不考虑错误分类成本)将由位于曲线左上部分的阈值产生(即 TP 率高,FP 率低)。记住这个标准,我们可以定义一个到曲线左上角的距离度量,并找到一个最小化它的阈值。
[latex]T _ { optimal } = \ text { arg max } _ { T } \ sqrt { TP _ r-FP _ r }[/latex]
t_opt_idx = np.argmax(tp_r - fp_r)
t_opt = t[t_opt_idx]
print("Threshold value is: %.2f" % t_opt)
Threshold value is: 0.80
我们也可以手动检查不同阈值的混淆矩阵。
y_pred = model.predict_proba(X_test)[:,1]
fig, axes = plt.subplots(3,3, figsize=(10,10))
for t, ax in enumerate(axes.flat):
threshold = (t+1)/10
y_pred_int = (y_pred > threshold).astype(int)
c_matrix = metrics.confusion_matrix(y_test, y_pred_int)
sns.heatmap(c_matrix, annot=True, cmap="Blues", fmt="d", ax=ax, cbar=False)
ax.title.set_text("T=%.1f" % threshold)
plt.subplots_adjust(hspace=0.5, wspace=0.5)
plt.suptitle("Impact of threshold adjustment on the error matrix")

看上面的图,我们确实可以确认 T=0.8 给出了最好的解释。假阴性和假阳性都很低。提高阈值会导致遗漏更多欺诈交易,降低阈值会使误报数量翻倍。
既然我们对模型的表现感到满意,我们可以将它持久化,并从其他笔记本/评分脚本中使用它。
model.save_model("smote_fraud.xgb")
摘要
在这篇博文中,我们查看了真实世界的信用卡交易数据集,并展示了如何使用机器学习来自动检测欺诈交易。随着新数据的到来,该模型可以自动更新,重新训练过程不需要人工干预。
数据集中的不平衡可以通过使用欠采样/过采样技术来解决,并且可以对概率的解释进行微调,以在错误警报和遗漏的欺诈交易之间产生更好的平衡。关于不平衡学习的含义和技巧的更正式的概述,你可以看[3]。
这篇博文中使用的完整数据集和代码可以在try.dominodatalab.com、获得,这里显示的所有结果都是完全可再现的,这要感谢 Domino reproducibility engine,它是 Domino 数据科学平台的一部分。同样,如果你想自己实现,你可以点击这里注册一个免费账户。
参考
[1] Jose M. Pavía,Ernesto J. Veres-Ferrer,Gabriel Foix-Escura,信用卡事件和控制系统,《国际信息管理杂志》,第 32 卷,2012 年第 6 期,第 501-503 页,ISSN 0268-4012
[2]尼泰什诉舒拉、凯文·鲍耶、劳伦斯·霍尔和菲利普·凯格尔迈耶。2002. SMOTE:合成少数过采样技术。j .阿提夫。里面的第 16 号决议,第 1 段(2002 年 1 月),第 321-357 段。
[3]何和加西亚(2009 年)。从不平衡数据中学习。知识与数据工程,IEEE 汇刊,21,1263-1284。doi: 10.1109/TKDE.2008.239
使用 Python 进行 Crunchbase 网络分析
原文:https://www.dominodatalab.com/blog/crunchbase-network-analysis-with-python
Crunchbase 最近将其后端数据库转换为一个 Neo4j 图形数据库。这将在未来给它带来很大的灵活性,但目前,数据的公开方式与以往类似:在进行任何图形分析之前,必须检索各个实体并使用属性数据来形成它们之间的边。除了在网页上手动遍历链接之外,没有提供图形分析。
为了能够对这些数据进行更强大的操作,我在 Zipfian Academy 工作期间,创建了我的“可视连接”项目。“可视化连接”促进了 Crunchbase 数据的构建和网络分析,并额外提供了可在 NetworkX 或 Gephi 中使用的数据。
下面,我将对 Crunchbase 数据中的收购进行分析,并描述我所使用的技术。软件本身的技术细节记录在公共项目中。
现有数据
代表公司、金融机构和个人的整个数据库数据都存储在项目中。大多数人希望使用 NetworkX gpickle 文件来访问每种节点类型的数据。GraphML 文件也可以直接导入到 Gephi。
所提供的数据包含 24,000 多家金融机构、200,000 人和 200,000 家公司。其中,只有 9861 家公司参与了收购。
构建图表
Visibly Connected 是用 Python 编写的,依赖于 NetworkX 库进行网络存储和图形分析。使用 GraphBuilder 类构建图是最简单的,它是 NetworkX 的有向图的超类。实例化 graph 对象和读取节点相对容易,如下面的代码片段所示。完整的程序见src/graph/build_acquisition_digraph.py。完整的程序包含了一些从图表中删除不必要数据的技术。
COMPANIES_COMPLETE = r'./data/company_complete.pkl'
x = gb.GraphBuilder()
x.read_gpickle(COMPANIES_COMPLETE)
使用每个节点的属性数据构建关系或边。您提供节点类型和关系列表。关系仅限于 Crunchbase 中定义的关系,目前还仅限于收购(被收购)、收购(收购他人)和投资(向公司提供资金)。请记住开源数据的一个重要偏见:如果有人不想公开信息,他们可以删除它。
.add_relations_from_nodes('company', ['acquisitions', 'acquisition'])
x.summary()
恭喜你,你有人脉了。对于大多数分析来说,你会想要清理一下。不连接任何东西的节点往往对网络分析不感兴趣(个人判断。)小集群可能感兴趣,也可能不感兴趣。下面的行删除未连接的节点,然后是少于四个节点的子图。技术文档中解释的过滤可用于根据任意复杂的条件保留或删除节点。
x.remove_nodes_from(x.isolates())
x.remove_small_components(min_size=4)
x.summary()
最后,如果你想保存或导出你的图表,这是一个单行的事情。GraphML 文件格式可以直接读入 Gephi。可以使用 GraphBuilder 类或 NetworkX 读取 gpickle 文件。
ACQUISITIONS_GPICKLE = r'./data/full_acquisitions_digraph.pkl.gz'
x.write_gpickle(ACQUISITIONS_GPICKLE)
full_acquisitions_digraph_file 和相应的 GraphML 文件可以在项目数据目录以及其他一些目录中找到。
收购图表的结果
上面提到的 python 脚本的第二部分用于为图表生成多个网络和数据。可视化是在 Gephi 中生成的,尽管也可以使用 Matplotlib。在所提供的数据中,有 4640 个子图彼此之间没有联系。它们的大小从 1 到 242 个节点不等,直径从 1 到 14。直径是网络中从任何节点到任何其它节点的最长路径。下图显示了占采集子图 70%的两个图结构。

是的,没错:根据 Crunchbase 的数据,至少有 15 家公司收购了自己,从而产生了单节点 0 直径图。有两个节点的 3276 个图表示一家公司恰好收购了另一家公司。下图显示了每个子图中节点的数量以及它们与子图直径的关系。

显然,涉及少数公司的收购是最常见的。当公司开始吞并一直在吞并其他公司的公司时,事情变得更有趣了。谷歌和它的一些收购就是一个很好的例子。

然而,这张图并不是谷歌收购的所有公司。请注意,将 Mobility Solutions 和 Hellman Friedman 链接到谷歌的节点表明它们被两家公司收购。是的,只是时间不同。
直径为 14 的最大收购子图由两家主要公司组成。从社区的角度来看,他们只有一个脆弱的联系。想知道吗?试用这个软件。
讨论
在我看来,这些收购并不是 Crunchbase 中最有趣的数据。我鼓励你看看剩下的数据,并考虑利用各种基于图形的社区措施。有很多有趣的东西与风险投资、启动资金和人们从一家公司到另一家公司的转移有关。两个简单的想法:
- 哪些风投或天使投资人会先投资好公司?谁总是跟着别人?
- 哪些金融组织基于所资助的公司或参与的融资轮而彼此联系紧密?
请记住,存在明显的偏差。Jamie Davidson 和在 GitHub 上有相关软件的 Benn Stancil 已经写了关于生存偏差的文章,并且在更传统的表格中有一组备用的 Crunchbase 数据。
在项目 README.md 中有更多关于软件、数据和文件的详细信息。如果您有任何问题,请随时与我联系。
Dask 并行计算:一步一步的教程
原文:https://www.dominodatalab.com/blog/dask-step-by-step-tutorial
现在,随着时间的推移,计算能力不断提高是正常的。每月,有时甚至每周,新的设备被创造出来,具有更好的特性和更强的处理能力。然而,这些增强需要大量的硬件资源。接下来的问题是,你能使用一个设备提供的所有计算资源吗?在大多数情况下,答案是否定的,你会得到一个 out of memory 错误。但是,如何在不改变项目底层架构的情况下利用所有的计算资源呢?
这就是达斯克的用武之地。
在许多 ML 用例中,您必须处理巨大的数据集,如果不使用并行计算,您就无法处理这些数据集,因为整个数据集无法在一次迭代中处理。Dask 帮助您加载大型数据集,用于数据预处理和模型构建。在本文中,您将了解更多关于 Dask 的知识,以及它如何帮助并行化。
Dask 是什么?
当开发人员处理小型数据集时,他们可以执行任何任务。然而,随着数据的增加,它有时不再适合内存。
Dask 是一个开源库,在 ML 和数据分析中提供高效的并行化。在 Dask 的帮助下,您可以轻松扩展各种 ML 解决方案,并配置您的项目以利用大部分可用的计算能力。
Dask 帮助开发人员扩展他们的整个 Python 生态系统,它可以与您的笔记本电脑或容器集群一起工作。Dask 是针对大于内存的数据集的一站式解决方案,因为它提供了多核和分布式并行执行。它还为编程中的不同概念提供了一个通用实现。
在 Python 中,像 pandas、NumPy 和 scikit-learn 这样的库经常被用来读取数据集和创建模型。所有这些库都有相同的问题:它们不能管理大于内存的数据集,这就是 Dask 的用武之地。
与 Apache Hadoop 或 Apache Spark 不同,在 Apache Hadoop 或 Apache Spark 中,您需要改变整个生态系统来加载数据集和训练 ML 模型,Dask 可以轻松地与这些库集成,并使它们能够利用并行计算。
最好的部分是你不需要重写你的整个代码库,你只需要根据你的用例进行最小的修改就可以实现并行计算。
Dask 数据帧和 pandas 数据帧之间的差异
数据帧是数据的表格表示,其中信息存储在行和列中。pandas 和 Dask 是用来读取这些数据帧的两个库。
pandas 是一个 Python 库,用于将不同文件(例如 CSV、TSV 和 Excel)中的数据读入数据帧。它最适合处理相对少量的数据。如果你有大量的数据,你会收到一个 out of memory (OOM)错误。
为了解决 OOM 错误并实现并行执行,可以使用 Dask 库来读取 pandas 无法处理的大型数据集。Dask 数据帧是不同熊猫数据帧的集合,这些数据帧沿着一个索引分割:

当您使用 Dask 数据帧读取数据时,会创建多个小熊猫数据帧,沿索引拆分,然后存储在磁盘上(如果内存有限)。当您在 Dask 数据帧上应用任何操作时,存储在磁盘上的所有数据帧都会触发该操作。
Dask 的使用案例
Dask 数据帧可用于各种用例,包括:
- 并行化数据科学应用: 要在任何数据科学和 ML 解决方案中实现并行化,Dask 是首选,因为并行化不限于单个应用。您还可以在同一硬件/集群上并行处理多个应用。因为 Dask 使应用程序能够利用整个可用的硬件,所以不同的应用程序可以并行运行,而不会出现资源争用导致的问题。
- 图像处理: 这需要大量的硬件资源。如果你在 pandas 或 NumPy 上使用传统的方法,你可能会中止这个项目,因为这些库/工具不能执行多重处理。Dask 帮助您在多个内核上读取数据,并允许通过并行方式进行处理。
有关不同真实世界用例的更多信息,请查看 Dask Stories 文档中的 Dask 用例页面。
Dask 实现
要实现 Dask,您需要确保您的系统中安装了 Python。如果没有,现在就下载并安装它。确保您安装的版本高于 3.7。(3.10 最新)。
软件包安装
如前所述,Dask 是一个 Python 库,可以像其他 Python 库一样安装。要在您的系统中安装软件包,您可以使用 Python 软件包管理器 pip 并编写以下命令:
## install dask with command prompt
pip install dask
## install dask with jupyter notebook
! pip install dask
配置
当您安装完 Dask 后,您就可以使用默认配置(在大多数情况下都有效)来使用它了。在本教程中,您不需要显式地更改或配置任何东西,但是如果您想要配置 Dask,您可以查看这个配置文档。
并行化准备
首先,看一个计算两个数平方和的简单代码。为此,您需要创建两个不同的函数:一个用于计算数字的平方,另一个用于计算数字的平方和:
## import dependencies
from time import sleep
## calculate square of a number
def calculate_square(x):
sleep(1)
x= x**2
return x
## calculate sum of two numbers
def get_sum(a,b):
sleep(1)
return a+b
calculate_square() 函数将一个数字作为输入,并返回该数字的平方。 get_sum() 函数接受两个数字作为输入,并返回这两个数字的和。故意增加一秒钟的延迟,因为这有助于您注意到使用和不使用 Dask 时执行时间的显著差异。现在,在不使用 Dask 的情况下,看看这个逻辑的执行时间:
%%time
## call functions sequentially, one after the other
## calculate square of first number
x = calculate_square(10)
## calculate square of second number
y = calculate_square(20)
## calculate sum of two numbers
z = get_sum(x,y)
print(z)
前面的代码计算数字的平方,并将它们存储在变量 x 和 y中。然后计算并打印 x 和 y 之和。 %%time 命令用于计算函数执行所花费的 CPU 时间和 wall 时间。现在,您应该有这样的输出:

您可能会注意到,即使在故意延迟三秒钟之后,整个代码也花了 3.1 秒运行。
现在是时候看看 Dask 如何帮助并行化这段代码了(计算平方和的初始函数保持不变)。
首先,您需要导入一个名为 delayed 的 Python Dask 依赖项,用于实现并行化:
## import dask dependencies
import dask
from dask import delayed
导入 Dask 依赖项后,就可以使用它一次执行多个作业了:
%%time
## Wrapping the function calls using dask.delayed
x = delayed(calculate_square)(10)
y = delayed(calculate_square)(20)
z = delayed(get_sum)(x, y)
print(z)
在这个代码片段中,您使用 Dask delayed 函数将您的普通 Python 函数/方法包装成延迟函数,现在您应该得到如下所示的输出:

你可能会注意到 z 并没有给你答案。这是由于在这个实例中, z 被认为是延迟函数的懒惰对象。它包含了计算最终结果所需的一切,包括不同的函数及其各自的输入。要得到结果,必须调用 compute() 方法。
然而,在调用 compute() 方法之前,先检查一下使用 visualize() 方法的并行执行会是什么样子:
%%time
## visualize the task graph
z.visualize()
请注意: 如果您在可视化图形时遇到任何错误,可能会有依赖性问题。你必须安装 Graphviz 来可视化任何图形。用
pip install graphviz可以做到这一点。
执行图表应该如下所示:

%%time
## get the result using compute method
z.compute()
要查看输出,需要调用 compute() 方法:
)
您可能会注意到结果中有一秒钟的时间差。这是因为 calculate_square() 方法是并行化的(在前面的图中形象化了)。Dask 的一个好处是,您不需要定义不同方法的执行顺序,也不需要定义要并行化哪些方法。达斯克会为你做的。
为了进一步理解并行化,看看如何将 delayed() 方法扩展到 Python 循环:
## Call above functions in a for loop
output = []
## iterate over values and calculate the sum
for i in range(5):
a = delayed(calculate_square)(i)
b = delayed(calculate_square)(i+10)
c = delayed(get_sum)(a, b)
output.append(c)
total = dask.delayed(sum)(output)
## Visualizing the graph
total.visualize()
这里,代码迭代一个 for 循环,并使用 delayed 方法计算两个值的平方和: a 和 b。这段代码的输出将是一个有多个分支的图形,看起来像这样:

到目前为止,您已经了解了 pandas 数据帧和 Dask 数据帧之间的差异。然而,当你从事并行化工作时,理论是不够的。现在您需要回顾技术实现,Dask 数据帧在实践中如何工作,以及它们与 pandas 数据帧相比如何。
这里使用的样本数据集可以从这个 GitHub repo 下载。
技术实现
要开始测试 Dask 数据帧的技术实现,请运行以下代码:
## import dependencies
import pandas as pd
import dask.dataframe as dd
## read the dataframe
pandas_dataframe = pd.read_csv('Sunspots.csv')
dask_dataframe = dd.read_csv('Sunspots.csv')
## calculate mean of a column
print(pandas_dataframe['Monthly Mean Total Sunspot Number'].mean())
print(dask_dataframe['Monthly Mean Total Sunspot Number'].mean().compute())
这段代码应该对 pandas 和 Dask 数据帧产生相同的结果;但是内部处理就大不一样了。熊猫数据帧将被加载到内存中,只有当它适合内存时,你才能对它进行操作。如果不适合,就会抛出错误。
相比之下,Dask 创建多个 pandas 数据帧,并在可用内存不足时将它们存储在磁盘上。当您在 Dask 数据帧上调用任何操作时,它将应用于构成 Dask 数据帧的所有数据帧。
除了延迟方法之外,Dask 还提供了其他一些特性,比如并行和分布式执行、高效的数据存储和延迟执行。你可以在 Dask 的官方文档中读到它。
使用 Dask 的最佳实践
每一种使开发更容易的工具或技术都有一些自己定义的规则和最佳实践,包括 Dask。这些最佳实践可以帮助您提高效率,让您专注于发展。Dask 最著名的一些最佳实践包括:
从基础开始
您不需要总是使用并行执行或分布式计算来找到问题的解决方案。最好从正常的执行开始,如果这不起作用,您可以继续使用其他解决方案。
仪表板是关键
当你在研究多重处理或多线程概念时,你知道事情正在发生,但是你不知道如何发生。Dask 仪表板通过提供清晰的可视化效果,帮助您查看员工的状态,并允许您采取适当的执行措施。
高效使用存储
尽管 Dask 支持并行执行,但您不应该将所有数据存储在大文件中。您必须根据可用内存空间来管理您的操作;否则,你会耗尽内存,或者在这个过程中会有一个滞后。
这些只是帮助您简化开发过程的一些最佳实践。其他建议包括:
- 避免非常大的分区: 这样它们就能放入一个工作者的可用内存中。
- 避免非常大的图: 因为那会造成任务开销。
- 学习定制的技巧: 为了提高你的流程效率。
- **不再需要时停止使用 Dask:**比如当你迭代一个小得多的数据量时。
- **能坚持就坚持分布式 RAM:**这样做,访问 RAM 内存会更快。
- 进程和线程: 注意将数字工作与文本数据分开,以保持效率。
- **用 Dask 加载数据:**例如,如果你需要处理大型 Python 对象,让 Dask 创建它们(而不是在 Dask 之外创建它们,然后交给框架)。
- 避免重复调用 compute:,因为这样会降低性能。
有关更多信息,请查看 Dask 最佳实践 文章。
通过 Domino 使用 Dask
Domino Data Lab 帮助您在 Domino 实例的基础设施上动态地提供和编排 Dask 集群。这使得 Domino 用户能够快速访问 Dask,而不需要依赖他们的 IT 团队来为他们设置和管理集群。
当您启动 Domino workspace 进行交互式工作或启动 Domino job 进行批处理时,Domino 会创建、管理并提供一个容器化的 Dask 集群供您执行。
要了解更多关于在 Domino 上使用 Dask 的信息,请查看我们的 GitHub 页面。
Dask:解决并行性、硬件浪费和内存问题的一站式解决方案
早期的程序员、开发人员和数据科学家没有强大的系统来开发 ML 或数据科学解决方案。但是现在,随着强大的硬件和定期的改进,这些解决方案变得越来越受欢迎。然而,这带来了一个问题:数据库不是为利用这些解决方案而设计的,因为它们没有内存容量或者不能利用计算能力。
有了 Dask,您不必担心并行性、硬件浪费或内存问题。Dask 是所有这些问题的一站式解决方案。
当您开始构建一个解决方案(记住内存问题或计算能力)时,您需要将解决方案部署到目标受众可以访问的地方。Domino Enterprise MLOps 平台通过提供机器学习工具、基础设施和工作材料来加速数据科学工作的开发和部署,使团队能够轻松协调和构建解决方案。
Domino 5.0:共享和重用可信数据源以提高模型质量
Domino 5.0 中的数据源介绍
数据科学家浪费时间去弄清楚在哪里可以找到他们需要的数据,访问这些数据,并配置正确的工具来连接这些数据。 Domino 5.0 通过数据连接器简化了整个流程,让数据科学团队安全地共享和重用通用数据访问模式。
Domino 数据源提供了一种机制来创建和管理受支持的外部数据服务的连接属性。连接属性被安全地存储,并且不需要安装特定于数据源的驱动程序或库。紧密耦合的库为基于表格和基于文件的数据提供了一致的访问模式。
使用 Domino 5.0,数据科学家团队可以注册和配置对外部数据源的访问,比如 Amazon Redshift、Amazon S3 和 Snowflake。一旦在 Domino 中注册了数据源,团队就可以开始利用数据访问 Python 库来列出和获取注册的外部数据源中的对象,甚至可以直接在 Pandas dataframes 中查询表格数据!
Domino 中的数据源通过消除与驱动程序安装、特定库等相关的 DevOps 障碍,使数据访问民主化。 通过与同事共享数据源连接器来增强团队协作。IT 团队将会很高兴地看到, 支持每个用户和服务帐户凭证的功能,以最大限度地提高灵活性,同时保持最高级别的数据安全性。
它是如何工作的

从 Domino 数据科学家的角度来看,只需点击几下鼠标,就可以为数据源配置一个新的连接器。在 Domino 中,导航到左侧导航栏上的“Data”部分,并选择“Connect to External Data”。

模式窗口出现后,从下拉菜单中选择数据存储的类型。出于演示的目的,我们将使用亚马逊 S3。
首先,您需要添加一些关于您将要连接的亚马逊 S3 桶的基本信息。

接下来,您需要将您的 AWS 凭证添加到 Domino。这个过程是完全安全的,只有您可以查看凭证。即使是 Domino 管理员也不能查看您的凭证。
您可以通过单击“测试凭据”来快速验证凭据是否有效。验证之后,您可以保存新的数据连接器,并开始在 Domino 中使用它。

现在导航到 Domino 中的一个项目,并单击“Data”部分。您将看到您有权访问的数据连接器列表。在我们的例子中,选择您之前配置的亚马逊 S3 连接器。

选择数据源的连接器后,单击“添加到项目”,然后启动一个工作区开始使用它。
正如你将在下面的截图和上面的演示视频中看到的,你可以通过 Domino SDK 直接在亚马逊 S3 处理文件。
在这个例子中,我创建了一个到亚马逊 S3 的连接,然后使用 JupyterLab 下载销售数据 CSV 文件,该文件在我的 S3 存储桶中,以便在 Domino 中使用。

现在数据已经在 Domino 工作区中,我们可以继续编写代码来提取和使用这些数据!
幕后强大的技术
既然我们已经介绍了这在实践中是如何工作的,那么让我们来探索技术细节。

虽然在上面的截图中有很多东西需要解开,但我们可以开始将其分成几个部分。从用户在 Domino 中启动他们的工作空间并开始使用 Python 库 建立到外部数据源的连接开始,我们有许多组件来帮助用户实现这种连接。
当用户从其工作空间或作业中启动查询时,最初会从运行的工作空间容器连接到数据源服务,数据源服务负责管理数据源元数据并促进与下游服务的连接。该服务将在 MongoDB 中执行查找,以收集关于数据源的元数据。MongoDB 不包含任何关于凭证的信息,而是包含关于数据源的元数据,这些元数据将帮助下游服务建立连接。
当您为数据源添加凭证时,它们作为访问密钥和秘密密钥存储在与 Domino 一起部署的 Hashicorp Vault 的实例中。我们通过数据凭证服务安全地检索这些凭证,并将它们传递给数据源代理服务,这是一种无状态的微服务,充当上游服务和用户希望访问的数据源(如雪花、亚马逊 S3 或红移)之间的中间人。既然请求有了适当的元数据和凭证,它就被路由到高可用性数据源代理服务,以连接到亚马逊 S3(在我们的示例中)。
Domino 生产的各种连接器利用特定于供应商的 Go SDK,这有助于满足连接到各种数据源所需的先决条件,比如数据库驱动程序。这将连接数据源的复杂性从 Domino 中的数据科学家那里抽象出来,以便他们每次都可以使用熟悉的方式连接到他们的数据。
结论
访问适当的数据是任何数据科学项目的关键部分。过去,在 Domino 和其他平台上,用户或数据科学家团队很难设置、配置和维护连接到各种数据源所需的凭证和驱动程序。对于非超级用户来说尤其如此。有了 Domino 数据源,启动和运行数据的困难就减轻了。
Domino 是 企业 MLOps 平台,它无缝集成了代码驱动的模型开发、部署和监控,以支持快速迭代和最佳模型性能,因此公司可以确保从其数据科学模型中实现最大价值。

图像分类器的数据漂移检测
原文:https://www.dominodatalab.com/blog/data-drift-detection-for-image-classifiers
本文介绍了如何检测将图像数据作为输入的模型的数据漂移,以防止它们在生产中无声地退化。在一个补充的 Domino 项目中运行这个例子。
防止生产中的静默模型退化
在现实世界中,数据是由不同的系统记录的,并且是不断变化的。数据的收集、处理和转换方式会影响数据。由于物理系统的机械磨损而引入噪音,或者如果基础生产过程发生根本变化(例如,监管机构的利率变化、自然灾害、市场中引入新的竞争对手或业务战略/流程的变化等),可能会发生变化。).这种变化会影响预测的准确性,并且需要检查在模型开发期间做出的假设在模型投入生产时是否仍然有效。
在机器学习的背景下,我们认为数据漂移¹ 是导致模型性能下降的模型输入数据的变化。在本文的剩余部分,我们将讨论如何检测将图像数据作为输入的模型的数据漂移,以防止它们在生产中无声地退化。
检测图像漂移
鉴于企业中对深度学习的兴趣激增,将非传统形式的数据(如非结构化文本和图像)吸收到生产中的模型正在增加。在这种情况下,主要依赖数字数据的统计过程控制和运筹学方法很难采用,因此需要一种新的方法来监控生产中的模型。本文探索了一种方法,可用于检测对图像数据进行分类/评分的模型的数据漂移。
模型监控:方法
我们的方法不对已经部署的模型做出任何假设,但是它需要访问用于构建模型的训练数据和用于评分的预测数据。检测图像数据的数据漂移的直观方法是构建训练数据集的机器学习表示,并使用该表示来重建呈现给模型的数据。如果重建误差较高,则呈现给模型的数据与其被训练的数据不同。操作顺序如下:
- 学习训练数据集的低维表示(编码器)
- 使用步骤 1(解码器)中的表示重建验证数据集,并将重建损失存储为基线重建损失
- 使用步骤 1 和 2 中的编码器和解码器重建正在发送的用于预测的一批数据;商店重建损失
如果用于预测的数据集的重建损失超过基线重建损失一个预定义的阈值,则发出警报。
图像数据漂移检测正在发挥作用
下面的步骤显示了涵盖上面详述的方法的相关代码片段。该项目的完整代码是可用的,可以从https://try.dominodatalab.com上的 图像 _ 漂移 _ 检测项目中分叉。


在Image _ Drift _ Detection项目可用的笔记本(Convolutional _ auto encoder . ipynb)布局如下:
- 在 MNIST 数据集² 上训练卷积自动编码器;使用验证损失作为基线来比较新数据集的漂移。
- 向 MNIST 数据集添加噪声,并尝试重建有噪声的 MNIST 数据集;注意重建损失。(如有需要,用作替代基线)。
- 使用步骤 1 中构建的卷积自动编码器重建 nonMNIST3 数据集,并将重建损失与 MNIST 数据集的验证损失或含噪 MNIST 数据集的重建损失进行比较。

我们现在深入相关的代码片段来检测图像数据的漂移。
步骤 1 :通过将以下内容添加到 docker 文件中来安装项目所需的依赖项。你也可以在https://try.dominodatalab.com中使用 Image_Drift_Keras_TF 环境,因为它已经预装了所有的库/依赖项。
RUN pip install numpy==1.13.1
RUN pip install tensorflow==1.2.1
RUN pip install Keras==2.0.6
第二步: 启动 Jupyter 笔记本工作区,加载所需的库。
#Load libraries
from keras.layers import Input, Dense, Conv2D, MaxPool2D, UpSampling2D, MaxPooling2D
from keras.models import Model
from keras import backend as K
from keras import regularizers
from keras.callbacks import ModelCheckpoint
from keras.datasets import mnist
import numpy as np
import matplotlib.pyplot as plt
第三步: 为 autoencoder 指定架构。
#Specify the architecture for the auto encoder
input_img = Input(shape=(28, 28, 1))
# Encoder
x = Conv2D(32, (3, 3), activation='relu', padding='same')(input_img)
x = MaxPooling2D((2, 2), padding='same')(x)
x = Conv2D(32, (3, 3), activation='relu', padding='same')(x)
encoded = MaxPooling2D((2, 2), padding='same')(x)
# Decoder
x = Conv2D(32, (3, 3), activation='relu', padding='same')(encoded)
x = UpSampling2D((2, 2))(x)
x = Conv2D(32, (3, 3), activation='relu', padding='same')(x)
x = UpSampling2D((2, 2))(x)
decoded = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(x)
autoencoder = Model(input_img, decoded)
autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy')
第四步: 生成测试、训练和嘈杂的 MNIST 数据集。
# Generate the train and test sets
(x_train, _), (x_test, _) = mnist.load_data()
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
x_train = np.reshape(x_train, (len(x_train), 28, 28, 1))
x_test = np.reshape(x_test, (len(x_test), 28, 28, 1))
# Generate some noisy data
noise_factor = 0.5
x_train_noisy = x_train + noise_factor * np.random.normal(loc=0.0, scale=1.0, size=x_train.shape)
x_test_noisy = x_test + noise_factor * np.random.normal(loc=0.0, scale=1.0, size=x_test.shape)
x_train_noisy = np.clip(x_train_noisy, 0., 1.)
x_test_noisy = np.clip(x_test_noisy, 0., 1.)
第五步: 训练卷积自动编码器。
# Checkpoint the model to retrieve it later
cp = ModelCheckpoint(filepath="autoencoder_img_drift.h5",
save_best_only=True,
verbose=0)
# Store training history
history = autoencoder.fit(x_train_noisy, x_train,epochs=10,
batch_size=128,
shuffle=True,
validation_data=(x_test_noisy, x_test),
callbacks = [cp, plot_losses]).history
我们得到的验证损失是 0.1011。
第六步: 得到含噪 MNIST 数据集的重建损失。
x_test_noisy_loss = autoencoder.evaluate(x_test_noisy,decoded_imgs)
Sample of noisy input data (top row) and reconstructed images (bottom row)
我们在有噪声的 MNIST 数据集上获得的重建误差为 0.1024 。与验证数据集的基线重建误差相比,误差增加了 1.3% 。
第七步: 获取 nonMNIST 数据集的重建损失;比较 MNIST 数据集和噪声 MNIST 的验证损失。
non_mnist_data_loss = autoencoder.evaluate(non_mnist_data,non_mnist_pred)
Sample of nonMNIST data (top row) and its corresponding reconstruction (bottom row)
我们在 nonMNIST 数据集上获得的重建误差为 0.1458 。与验证数据集上的基线重建误差相比,误差增加了 44.2% 。
从这个例子中可以清楚地看出,当卷积编码器重建不同于用于训练模型的数据集时,重建损失中存在尖峰。作为检测结果的下一步是用新数据重新训练模型,或者调查导致数据变化的原因。
结论
在本例中,我们看到卷积自动编码器能够根据重建误差量化图像数据集中的差异。使用这种比较重建误差的方法,我们可以检测呈现给图像分类器的输入的变化。但是,将来可以对这种方法进行改进。首先,虽然我们使用试错法来确定卷积自动编码器的架构,但通过使用神经架构搜索算法,我们可以获得更精确的自动编码器模型。另一个改进可以是在训练数据集上使用数据扩充策略,以使自动编码器对于噪声数据以及图像的旋转和平移的变化更加鲁棒。
如果您想了解更多关于如何使用 Domino 监控您的生产模型的信息,您可以观看我们关于“监控大规模模型”的在线研讨会。它将包括对数据漂移和模型质量的持续监控。
参考
- 伽马、若昂;Zliobait,Indre 艾伯特·比费特;佩赫尼茨基、米科拉;阿卜杜勒哈米德·布恰基亚。“概念漂移适应调查” ACM 计算调查第 1 卷,第 1 篇(2013 年 1 月)
- 乐村,Yann 科琳娜·科尔特斯;克里斯托弗 J.C 伯吉斯。MNIST 手写数字数据库。
- notMNIST 数据集
数据伦理:质疑真理和重新安排权力
原文:https://www.dominodatalab.com/blog/data-ethics-contesting-truth-and-rearranging-power
这份多米诺数据科学领域笔记涵盖了克里斯·维金斯最近在柏克莱举办的数据伦理研讨会。本文重点关注 1)定义和设计伦理的拟议框架,以及理解鼓励行业实施伦理的力量的拟议框架,以及 2)数据科学家在开发数据支持产品时应考虑的拟议伦理原则。非常感谢克里斯在这篇文章发表前提供反馈,并允许摘录他的幻灯片。
数据科学家、权衡和数据伦理
随着越来越多的公司成为模型驱动的,数据科学家在推动创新和帮助他们的公司保持经济实力方面处于独特的地位。构建和使用模型时生成的知识产权、工件和见解(即模型上下文)使数据科学家能够直接影响业务问题。数据科学家在其模型的整个生命周期中不断做出权衡决策。
最近关于公司是否将数据伦理纳入考虑的问题引发了公众讨论,来自知名研究人员(特别是模型可解释性)、主流技术出版社,以及知名全球机构的数据科学领导者都发表了意见。克里斯·维金斯,《纽约时报》的首席数据科学家,同时也是哥伦比亚大学的教授最近举办了研讨会“未来的统计学家、首席执行官和参议员应该了解数据的历史和伦理?”在伯克利。在他的演讲中,克里斯提出了一个框架,原则和建议,以帮助在历史背景下操作伦理。他还鼓励数据科学家了解新的数据科学算法如何重新安排权力,以及数据的历史是如何讲述真理和权力的故事。这个演讲提出,为了理解未来,我们需要理解真理和力量是如何一直被争夺的。甚至自 19 世纪以来,当人们收集数据以建立能力时,他们经常“用它们来捍卫自己的权力,而不是赋予手无寸铁的人权力”。
我刚刚看过克里斯在纽约的演讲,他在纽约时报上讲述了他建立团队开发和部署数据科学中的机器学习的工作,我也参加了他最近的数据伦理演讲。虽然数据伦理演示涵盖了构建和部署一个将技术和关键数据方法相结合的课程,但这篇博客文章重点关注一个提议的伦理框架、现代数据伦理问题的示例(例如,偏见、伤害和重新识别)、要考虑的原则和建议。如果对更多的细节感兴趣,可以获得的资料以及一段早期演讲的视频。课堂讲稿和 Jupyter 笔记本也通过 GitHub 分发。非常感谢 Chris 在这篇文章发表前提供反馈,并允许摘录他的幻灯片。
理解数据伦理的分析框架:作为重新安排权力的能力的数据科学
克里斯提出,历史为“思考将要做出的决定”提供了一个框架。他建议查看之前的问题,“历史上的垃圾箱火灾”,或之前确立的有争议的“真相”。通过回顾这些真理是如何被争论的,历史为工业提供了一种“我们可能创造的不同的未来”的感觉对于工业界来说,推断概率结果的想法是很常见的。然而,人们可能不太熟悉的是,创造一种新的数据算法会重新安排权力。Chris 认为,在构建一项能力时有意图,只有这项能力——而不是意图——才能“以某种技术的形式移植给其他人”。它对人们如何能够‘对谁做什么’产生影响,从而影响权力的动态变化。”克里斯表示,他之所以会有这种顿悟,是因为本·雷希特寄给他菲利普·罗加威的论文“密码作品的道德品质”,并建议克里斯在阅读时将“密码学”一词替换为“数据科学”。的论文摘要以“密码术重组权力”为开篇。它配置谁可以从什么地方做什么。这使得加密成为一种固有的政治工具”。

然后,克里斯主张数据伦理应该成为公共话语的一部分,特别是当存在现代问题的影响时,包括人才不愿意为特定公司工作或者当一名工程师因“通过实施专门设计的软件来欺骗排放测试,从而欺骗美国监管机构和大众汽车客户”而被判入狱

克里斯鼓励人们讨论各种历史问题,他让人们回答“新能力如何重新安排权力?”以及考虑权利、伤害和正义的作用。

克里斯还谈到了现代文学是如何指出“互联网出了问题”,引用了凯茜·奥尼尔、T2、萨菲娅·诺布尔、T4、维吉纳·尤班克斯和肖莎娜·祖博夫的分析。Chris 主张,来自研究人员的质疑先入为主的“真理”的现代分析正在影响和塑造行业对数据伦理的认识。(当一名观众提到“所有女性!”在伯克利的演讲中,关于他的引用,他的回答是“没错。对此,我可以添加 Zeynep Tufekci、Hanna Wallach 和许多其他人的论文。这不是一个完整的列表”)。

数据伦理:重新识别和质疑真理(昂首阔步)
Chris 在他的研讨会上指出了许多消费者保护抗议的例子,以及行业如何争论和解决这些问题。然而,他在演讲中提到的两个重新识别的例子可能会引起数据科学家的特别共鸣,尤其是在寻找具有商业意义的例子时。2010 年,网飞取消了他们的第二次推荐竞赛,因为提起了隐私诉讼。相关论文“大型稀疏数据集的稳健去匿名化”,作者阿夫林德·纳拉亚南和维塔利·什马蒂科夫
“证明对单个订户知之甚少的对手可以很容易地在数据集中识别出该订户的记录。使用互联网电影数据库作为背景知识的来源,我们成功地确定了已知用户的网飞记录,揭示了他们明显的政治偏好和其他潜在的敏感信息。”
Chris 提到的一个更早的重新鉴定的例子来自 Latanya Sweeney ,在她的论文中“只有你、你的医生和许多其他人可能知道”。Latanya 指出,虽然一个数据集可能被认为是匿名的,因为一个人的“姓名”不包含在人口统计属性中,但其他数据列可能存在于与该人的姓名配对的列中具有相同人口统计属性的某处。相似的列变成了一个连接键并发生重新识别。克里斯还提到,1997 年,拉坦雅通过电子邮件向马萨诸塞州州长发送了自己的健康记录,当时她还是麻省理工学院计算机系的研究生。


数据伦理:考虑采用贝尔蒙特原则
在他的研讨会上,克里斯指出,伦理不是一个简单的话题。具体来说,实施数据伦理包括技术、哲学和社会学组成部分的结合。这并不奇怪,因为数据科学需要关键素养(例如,对主观设计选择的认识)以及功能性技术素养(例如,数据管理、构建模型等)。).此外,数据科学工作本质上是实验性和概率性的。因此,应用确定性的伦理规则可能会挑战执行力。

Chris 建议行业考虑将道德规范阐述为一套原则,并理解将清楚地传达和考虑出现的紧张点。然后,他主张设计一个适应新社区或新公司的工作系统,以实施这些原则。克里斯在他的演讲中谈到了不同的原则,供人们思考。然而,这篇文章关注的是贝尔蒙特原则。

克里斯借鉴了贝尔蒙特原则,这些原则是为了回应 T2·塔斯基吉的研究而制定的。贝尔蒙特原则经久耐用,并且自 20 世纪 70 年代以来就经过了“压力测试”。人们继续将它们用于交互设计,并作为审核决策的一种手段(在你做出决策之前和之后)。然而,克里斯建议根据公司如何使用数据和我们所处的时代来更新。

例如,在 70 年代,强调“知情同意”是达到“尊重人格”的一种手段。然而,今天,克里斯指出
“知情同意是一个模糊的概念,特别是在与私营公司打交道时,正如 Eben Moglen 所说,他们对我们的数据所做的一切,以及我们使用他们的免费服务来换取免费监视我们的所有方式”。
克里斯建议在“自主性”后面加上知情同意,或者用肯定回答这个问题:“用户有机会自主决定如何使用他们的数据吗?”克里斯还建议重新考虑“不伤害”,最大化利益,因为一个人“永远不和你说话或和你交往也不会伤害你”。第三个原则是“公正”。克里斯建议用“公平”代替“合法”,比如“建立一个系统,让你乐意成为任何参与者,任何利益相关者。”例如,在拼车系统中,乘客、司机和公司都同样快乐吗?无论答案是“是”还是“否”,它都提供了一个在审计期间和开发机器学习算法时要考虑的框架。
Checks and balances on corporate, state, and people power
在一个社区——包括一家公司——定义和设计道德规范之前,他们必须首先意识到这是一个好主意。克里斯还提出了一个框架来理解推动行业首先考虑道德的力量,将制衡描述为国家权力、企业权力和人民权力之间的“三人不稳定游戏”。他简要回顾了当前国家权力围绕消费者保护和反垄断法规重新参与的方式,以及人民权力如何以集体机构的形式在包括数据科学家和软件工程师在内的员工中出现。
摘要
Chris 在他的演讲“未来的统计学家、首席执行官和参议员应该了解数据的历史和伦理吗?”中涉及了与数据伦理相关的广泛话题虽然这篇文章提供了他的研讨会的精华摘录,包括一个提议的框架,行业争议真理的具体例子,以及供数据科学家考虑的建议原则,但更多见解可在他演讲的早期版本的甲板或视频中获得。再次感谢 Chris 允许摘录的幻灯片以及他在发表前对这篇文章的反馈。
使用 Pandas Profiler 和 D-Tale 进行数据探索
原文:https://www.dominodatalab.com/blog/data-exploration-with-pandas-profiler-and-d-tale
我们都听说过数据是新的石油。我总是说,如果是这样的话,我们需要经过一些精炼过程,才能将原油转化为有用的产品。对于数据,这种细化包括进行一些清理和操作,以便更好地理解我们正在处理的信息。
在之前的一篇博文中,我们已经报道了 Pandas Profiling 如何能够加速将我们的数据带入预测建模阶段所需的数据探索。我们讨论了探索性分析的重要性,包括观察缺失数据的频率和计算所有特征的交互作用。
在这篇博客中,我们将继续讨论使用 Pandas Profiler 进行数据探索,并包括另一个工具,对于我们这些更倾向于使用视觉线索的人来说,它可能会很方便。
数据探索的目的
在跳上机器学习马车之前,数据探索是非常重要的一步。它使我们能够围绕手头的数据构建上下文,并让我们开发适当的模型,然后可以正确地解释这些模型。此外,最初的探索还可以为机器学习管道中可能需要包含的一些转换的自动化铺平道路。
始终考虑数据所有者可以提供的关于数据的信息也很重要。例如,我们看到的数字实际上是指类别还是以特定格式提供的日期?探索的类型可能取决于其中一些问题的答案。
在项目的探索阶段,我们希望实现的一些典型目标包括:
- 检测错误数据。
- 确定有多少丢失的数据。
- 理解数据的结构。
- 识别数据中的重要变量。
- 检测数据的有效性。
Python 和熊猫剖析
我们在之前的文章中已经介绍了熊猫烧香,在这篇文章中,我们想强调这个工具使我们能够做到的一些方面。然后,我们将工作流程与另一个:D 故事进行对比。
首先让我们来看看我们将要处理的数据:来自 UCI 机器学习知识库的乳房 x 线照相海量数据集。关于这个数据集的信息可以在这里获得。
该数据集包含用于乳腺癌诊断的诊断性乳房 x 线照片的相关信息。乳房 x 光片实际上是乳房的 x 射线,用于检查或筛查可能没有疾病症状的人的癌症。在检测到异常的情况下,可能需要进一步的乳房 x 光检查来确定异常是否是良性的。
让我们将数据加载到 pandas 中,先在没有 Pandas Profiler 的情况下看一看,看看我们能告诉我们什么。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
根据 UCI 网站提供的描述,我们知道总共有 6 个属性:
- BI-RADS 评估
- 年龄
- 形状
- 边缘
- 严重
我们可以用它来为数据框架中的列提供有用的名称。
url = "http://archive.ics.uci.edu/ml/machine-learning-databases/mammographic-masses/mammographic_masses.data"
names = ['BI-RADS', 'Age', 'Shape', 'Margin', 'Density', 'Severity']
df = pd.read_csv(url, names=names)
masses = df.copy()
请注意,我已经创建了原始数据集(df)的副本,并将其命名为masses。万一我们实现的一些操作最终在我们的数据集中产生了意想不到的变化,我们总是可以回到最初的状态。在这种情况下,我们总是可以从 UCI 网站下载数据,但在许多情况下这可能是不可能的。
好,让我们先来看看我们的数据集:
masses.head()

此外,我们可以检查数据是否具有预期的行数。根据我们掌握的信息,共有 961 个条目,其中 516 个为良性,445 个为恶性。利用Severity栏告诉我们肿块是良性还是恶性,我们可以检测数据是否符合预期:
masses.shape
(961, 6)
masses['Severity'].groupby(df['Severity']).size()
Severity
0 516
1 445
Name: Severity, dtype: int64
在这种情况下,我们使用了 pandas 的功能,根据列Severity中的值对数据进行分组,并查看组的大小。让我们继续看我们的数据。
我们可以检查每一列包含的信息类型,我们可以用.dtypes来完成:
masses.dtypes
BI-RADS object
Age object
Shape object
Margin object
Density object
Severity int64
dtype: object
我们可以看到,除了Severity之外,所有的列都有object类型。这是 pandas 告诉我们类型要么是字符串,要么是数值和非数值的混合。Severity由整数组成。
仔细查看数据,您会注意到一些列带有问号?。对于该数据集,这是数据收集表示缺失数据的方式。当通过read_csv用na_values参数加载数据集时,我们可以使用这些信息。让我们看看数据集中的一些数据示例:
masses.iloc[[20, 456, 512],:]

我们现在可以使用replace函数来转换nan的缺失值。同时,我们可以利用这个机会将我们的列转换成数值,而不是将它们保留为object。
masses = masses.replace('?', np.NAN)
masses.loc[:,names[:-1]] = masses.loc[:,names[:-1]].apply(pd.to_numeric)
masses.dtypes
BI-RADS float64
Age float64
Shape float64
Margin float64
Density float64
Severity int64
dtype: object
正如我们看到的,现在列的类型是float。请注意,虽然原始数据看起来像整数,但我们在列中引入了nan值,这意味着 pandas 要求列至少是float。让我们来看一些缺失值已被替换的示例行:
masses[masses['BI-RADS'].isna()]

很好,让我们来看看数据集的描述性统计数据。我们只需使用pandas.describe()功能,就可以一次看到所有信息:

我们可以看到,我们有年龄在 18 至 96 岁之间、平均年龄为 55 岁半的患者的数据。但是我们如何计算其他列的值呢?有一个 2.72 的Shape意味着什么?这有意义吗?这就是语境产生影响的时候了。
我们还可以通过替换平均值或中值的缺失值来开始处理缺失数据,或者甚至开始使用一些奇特的插补,例如使用最近邻算法。然而,对数据进行转换而不考虑所考虑的值的含义是完全错误的。
上下文中的数据
我们知道我们可以获得大量的数据,事实上我们可以盲目地获取像上面这样的数据集,并将其投入到机器学习管道中,以达到分类的目的。尽管如此,这样做的危险在于,我们可能会错过显而易见的东西,做出不符合目的的决定。处理这个问题的一个方法是停下来考虑数据的上下文。
在我们的工作示例中,我们可能能够安全地假设Age变量是以年为单位的患者年龄,但是我们能告诉其他变量什么呢?根据 UCI 页面中的信息,属性如下:
BI-RADS评估:1 到 5(依次)Age:患者的年龄(整数)Shape:肿块形状:圆形=1 椭圆形=2 小叶形=3 不规则形=4(标称)Margin:质量余量:限定=1 微叶状=2 模糊=3 模糊=4 针状=5(标称)Density:质量密度高=1 iso=2 低=3 含脂=4(序数)Severity:良性=0 或恶性=1(二项式)
让我们也考虑一下乳房 x 光检查后会发生什么。我们可以预期,这些结果将由一名合格的放射科医师进行检查,该放射科医师接受过寻找组织中异常肿块的培训。大多数情况下可能是良性的,对于那些不是良性的,有一些迹象表明可能是癌症。在放射科医生查看病例后,他们会写一份报告,描述所发现的异常情况。医生描述结果的一种标准方法是双 rad。它通常从 0 到 6,但根据 UCI 的页面,我们可以看到他们认为他们只有 1-5 的范围。
除了 BI-RADS 评分,医生还使用其他属性,例如形状(圆形、椭圆形、小叶形或不规则形)、肿块中存在的脂肪细胞的数量以及可疑细胞的数量,即密度,以及肿块边缘的外观,即边缘。所有这些属性实际上都是绝对的,事实上其中一些是有序的。这意味着对这些值取平均值或标准偏差实际上没有意义。
现在让我们利用这些信息对数据进行更好的了解。
我们可以从寻找异常值开始。例如,我们不期望找到 1-5 范围之外的任何BI-RADS值。
masses[(masses.loc[:,'BI-RADS']<1) | (masses.loc[:,'BI-RADS']>5)]

啊哦!看来我们有一些惊喜。首先,数据中存在明显的异常值,因为行 340 的 BI-RADS 为 55!我们也有一些 0 和 6 的行。在这一点上,我们可以回到我们的放射科团队,并验证异常值是(或不是)打字错误,期望值实际上是 5。
对于其他人,我们可以尝试证实他们正在使用完整的 BI-RADS 分类,其中包括用于不完整读数的0和用于已知活检且已证实为恶性肿瘤的6。
在这种情况下,由于我们是从网上获得这些数据的,所以让我们考虑以下假设:
- 55 实际上是 5
- 0 必须更改为 1,6 必须更改为 5
请注意,这可能不是数据集原作者的真实意图。然而,它为我们提供了一些可以在这个练习中执行的清洁步骤。
masses.loc[:,'BI-RADS'][masses.loc[:,'BI-RADS']==55] = 5
masses.loc[:,'BI-RADS'][masses.loc[:,'BI-RADS']==0] = 1
masses.loc[:,'BI-RADS'][masses.loc[:,'BI-RADS']==6] = 5
masses[(masses.loc[:,'BI-RADS']<1) | (masses.loc[:,'BI-RADS']>5)]

熊猫侧写师
from pandas_profiling import ProfileReport
profile = ProfileReport(masses, title="Mammographic Mass Dataset Profiling Report")
profile.to_notebook_iframe()
其结果是一个交互式报告,提供了一个非常有用的数据集概述,包括一些总体统计数据。例如,我们可以看到配置文件认为我们有一个数字变量和 5 个分类变量。此外,它认为有 2.8%的丢失细胞。

然后,我们可以查看数据集中的每个变量,例如,让我们查看前两个变量的内容,即BI-RADS和Age:

在BI-RADS的例子中,我们可以看到最普遍的值是类别 4,超过 56%的数据,而类别 1 只有 0.5%。如果我们要在模型中使用这个列,我们现在意识到我们有一个不平衡的数据集。
对于Age,我们看到一个看起来正常的直方图,峰度为-0.31。请记住,这里使用的是 Fisher 的峰度定义,即正态分布的峰度为零。在这两种情况下,我们都有许多其他信息统计数据可以指导我们的探索。
我们可以查看变量之间的相关性,并能够在不同的相关性度量之间进行选择。我们甚至得到了所选相关性度量的描述。

我们还以不同的可视化格式获得关于缺失值的信息,例如如下所示的零矩阵:

我们可以从熊猫的角度来看这个问题,寻找缺失条目的数量:
for name in names:
missing = masses[masses[name].isna()].shape[0]
print('{0} missing: {1}'.format(name, missing))
BI-RADS missing: 2
Age missing: 5
Shape missing: 31
Margin missing: 48
Density missing: 76
Severity missing: 0
我们可以将报告保存为 HTML 文件以供将来参考:
profile.to_file("mammographic_mass_report.html")
好的,看起来很棒!如果你是一个更加视觉化的人,并且愿意以那种方式去探索呢?嗯,D-Tale 对你来说可能是个不错的选择。我们来看看吧!
使用 D-Tale 进行数据探索
D-Tale 是一个可以帮助我们以可视化的方式获得数据集详细信息的模块。它支持代码导出。这意味着,如果您想要记录、复制或实际学习您的分析的某些部分,您可以获得由该工具创建的代码的导出,并从那里开始。
该模块生成一个报告,涵盖了数据集的概况,它让您应用通用和自定义过滤器,运行可视化,突出显示值等。
让我们试着做一些我们在博客第一部分做的步骤,但是现在使用 D-Tale。让我们导入模块并创建原始数据帧df的新副本。
import dtale
masses2 = df.copy()
我们现在可以在笔记本中运行一个报告,我们将看看如何执行以下步骤:
- 转换’?'至
NaN - 移除异常值表单
BI-RADS - 获取预期范围内的
BI-RADS值 - 检查变量的数据类型
- 浏览报告
- 导出清理后的数据
准备好了吗?
dt = dtale.show(masses2, notebook=True)
该报告看起来非常像一个电子表格,当您将鼠标悬停在表格上时,您可以看到您可以采取的一些行动。

让我们把问号转换成nan。对于每一列,我们选择“替换”菜单并填写表格,告诉 D-Tale 进行更改变成了‘南’。请注意,您需要通过单击加号来添加操作。正如您在下面的动画中看到的,该工具生成的代码是可见的。我已经为一个单独的列做了这些,我们将需要对其他列应用相同的更改。

D-Tale 让我们直接修改表中的值,让我们对BI-RADS列中的异常值进行修改。

此列的其他替换可能更适合使用替换功能。请注意,您可以将各种步骤添加到上下文菜单中,如下所示:

我们可以使用提供的菜单来更改列中的数据类型。例如,我们可以将Severity列从int更改为分类。在这种情况下,我们需要告诉 D-Tale 先将值更改为字符串,然后再更改为类别:

我们可以像以前一样探索缺失的数据。在这种情况下,只需选择“缺失分析”菜单:

D-Tale 让我们可以做更多的事情,如查看相关性、创建图表或突出显示值。

我们可以通过从菜单中选择“代码导出”来导出生成的代码:

您还可以看到一个“导出”菜单,让我们将数据保存到 csv 或 tsv 文件中。
摘要
在这篇文章中,我们已经讨论了数据探索的重要性,并看到了上下文如何提供下一步的线索。我们不仅能够创建更好、更合适的转换,而且能够更好地解释我们的变量。
我们看到了如何用三个工具做到这一点:Pandas、Pandas Profiler 和 D-Tale。这些工具可以帮助我们用几行代码获得关于数据集的信息,对于 D-Tale,只需点击几下鼠标。我们探索的结果可以重复,并进一步用于构建适合目的的机器学习模型。
《数据为善》创刊会:DrivenData 的彼得·布尔
原文:https://www.dominodatalab.com/blog/data-for-good-peter-bull-drivendata-meetup
最近,Domino 举办了一次超过 40 名数据科学家的会议,他们来看了来自 DrivenData 的 Peter Bull 发表了一个精彩的演讲,题为为好而众包数据。
Peter 的演讲阐述了如何将统计学、计算机科学和机器学习应用于应对社会领域的挑战。他给出了良好运动数据的大背景,以及各种背景的人如何参与其中的建议。他还谈到了两个新的 DrivenData 竞赛。第一场比赛的目标是利用机器学习来识别鱼类物种,以帮助保护新英格兰的底栖鱼,以及如何利用视频数据进行深度学习是一个令人信服的问题。第二个是,一种新的竞争,向开源项目贡献拉请求可以为竞争者赢得 10 万美元奖金池的积分。这项挑战的目的是:将深度学习置于放射科医生的指尖。
数据质量分析
原文:https://www.dominodatalab.com/blog/data-quality-analytics
HealthJoy 的数据科学总监 Scott Murdoch 博士介绍了数据科学家如何使用分布和建模技术来了解数据中的陷阱,并避免根据脏数据做出决策。
会话摘要
在最近于芝加哥举行的 Data Science PopUp 上,Scott Murdoch 讨论了数据科学家如何理解他们的数据,实施数据质量分析,然后与 IT 合作。默多克主张“信息技术和数据科学实际上应该很好地整合……这是我在任期内学到的一件事。”
会议亮点
- 数据质量分析的定义和脏数据的成本。
- 识别关键字段(唯一键、关键字段等。)来解决问题。
- 涵盖 OLS 回归、K 均值聚类和神经网络建模技术作为跟踪质量的高级方法。
- 实用技巧包括在创建预测时为将来保留系数(种子和权重)。
- 与 IT 集成,为基准指标(百分比 0、频率分布等)创建边际误差范围。),构建脚本,并自动化这些过程

演示文稿
好的,首先,我要感谢团队今天邀请我。我很兴奋能和你说话。我要和你们谈谈数据质量分析,我相信你们中的一些人会对此感到厌烦,因为谁想谈论数据质量。但如果有人知道,那就是这个小组,对吗?
虽然对某些人来说,这可能不是最吸引人的话题,但却是一个非常重要的话题。什么是数据质量分析?这是重要的一点。我们为什么需要它?脏数据的成本是多少?我们将了解您如何理解您的数据、实施数据质量分析,然后与数据集成。这是非常重要的一部分。脏数据会让公司损失很多东西。这可能会降低生产率。为什么?我可能不需要告诉你这些,但我在这里,所以我会的。
如果你做错了什么,你正在做分析,突然你在你的数据中发现了一些东西-一种缺失的感觉,一部分数据缺失了,你做了所有这些分析,你去给你的老板看。糟透了,对吧?他们得往上走。你可能不得不改变结果。
如果你是一家更大的公司,我已经工作了两年,你推出它,它会影响你的品牌认知,如果你用这些数据来驱动决策,这就是你这么做的原因。最重要的是,它会影响收入。
那么,事不宜迟,什么是数据质量分析?基本上,它使用分布和建模技术来理解数据中的陷阱。与节省的费用相比,成本相当低。代价是你的时间,在大公司里,这就是所谓的 FTE(全职员工),或者你的身体时间。如果你自己在做某件事,原谅我的语言,我是经济学家,但是你时间的机会成本。也就是说,如果你不这样做的话,你能做的最好的事情就是。这种节省可能会让你免于尴尬、名誉受损,并获得一定比例的收入。
那么,我们为什么又要在乎呢?当我发现这个数字时,我并没有感到震惊,但当我亲眼看到它时,我觉得有点奇怪。所以,肮脏的数据决策,我应该澄清一下。在美国,根据脏数据或未正确编码的数据做出决策的成本每年约为 3 万亿美元。
我来自医疗保健行业。对我们来说,这大约是每年 3400 亿美元。这是一大笔钱。当你看这三个步骤时,你的目光可能会有点呆滞,因为它们看起来很简单。但是我要告诫大家不要轻举妄动。
当你开始看你的数据时,我想让你想想你在试图解决什么问题。我知道每个人都喜欢,嗯,当然。这就是我们这么做的原因,对吗?
但是我想让你想想你使用的领域。然后我想你有什么类型的数据。更具体地说,我想让你想想你没有哪些数据。好吗?然后,你真正了解你的数据。我的意思是,你的数据里有什么?数据是从哪里来的?来源是什么?在你之前有多少人摸过?它是为它而来的吗?它是从网上来的吗?对于创业公司的人来说,这可能是一个相当简单的问题。对于来自大公司的人来说,你会惊讶地发现,在你接触这些数据之前,有多少人会去接触它们。
在接下来的几张幻灯片中,我希望大家回想一下自己做的最后一个项目。我想让你想想你对这些数据有什么倾向。你对数据做了什么假设?你检查过了吗?你验证了那些假设吗?如果你没有,我不怪你。有时候是时间的问题。但是如果你做了,你的处置是正确的吗?
那么,仅仅通过举手表决,这个房间里有多少人,当他们得到一个新的数据源时,知道他们的数据的唯一键是什么?有点?我看到有人举手。这是一个 It 问题,许多数据科学家并不总是关注它,至少在我看来是这样。唯一键是唯一的行。我会谈到医疗保健数据,但你可以将它应用于任何事情。
我非常熟悉的一件事是索赔数据。如果你从未见过索赔数据,你去医院,对不对?如果因为某种原因,不幸的事情发生了。你骨折了。我也经历过一次。你得去急诊室,对吗?他们有所有这些不同的程序称为 CPT 代码,当你进入急诊室,一个是 x 光。一个是医生的时间。一个是护士的时间。一个是他们给你的药,对吗?所以,你有这些不同的行。
当我向某人提供索赔数据时,他们会说,“好的,这是索赔级别的数据”。再问一次,这到底意味着什么,对吗?这是索赔数据,人们会拿走它,好吧,这是在索赔水平。一般来说,它的意思是它是一个成员,它是一个独特的行是成员,数据服务,索赔号码,因为他们可以对一次访问进行多次索赔,以及索赔行。
这是我在金融数据和健康数据中看到的。这种说法是——对于 IT 部门或组织中的任何人来说,您可能以前见过这种说法。它基本上就像一个更新序列。你会有 10 行相同的硬币。他们甚至可能有相同的允许量。基本上就是某人在这个手术上花费的金额。除了其中的九个,它会有相同的数量,然后第十个可能会不同。事情是这样的,每次供应商提出索赔时,他们都会更新索赔。但他们不会删除旧记录,对吧?所以,你要选最后一个。如果你不知道那个唯一的键,如果你只是假设它在声明级别,你按列做一个求和,你会得到大约 10 倍于你应该得到的。
接下来的事情是理解关键字段。在我将要展示的几个例子中,我将尝试模拟一个人为一个给定的手术支付多少钱。这就是他们所说的允许支付,或允许金额。它基本上意味着保险公司允许参与者支付多少费用。其余由个人负担。然后是提供者,也称为 MPI。然后是承保金额,即员工承保的金额。他们称之为 CPT 代码,这是实际的程序。
我之前也是这么说的。x 光片,一个医生给你检查,他们叫它什么来着,他们给你止痛药,那是在另一个目录下。然后是提供商的专业,这将与提供商和会员的邮政编码相关联。他们还会有一些其他领域,对于任何从事医疗保健的人来说,他们称之为 PHI。会员护理 ID、姓氏、名字。好的。所以,无论何时你在看数据,并且你在系统地做这件事,你应该考虑一套你想要看数据的标准。我倾向于看这里的前三名。我知道很多人都是从后两个开始的。
举手表决,有多少人在使用数据之前创建了一个分布?好的,相当多。有多少人看到少了多少?甚至更多的人。印象深刻。有多少人在零度看到?有多少人看到了价值的比例?那么,前 20 个最常见的值是什么呢?人少了,好吧。
一个月大概有 300 场演出。所以,要抽查的数据太多了吧?他们假设数据是从数据源正确提交的,但是他们没有办法验证这一点。他们所做的就是他们所谓的模式检查。它有正确的列名吗?它有正确的编码吗?是字符串还是 varchar 之类的?但是,他们实际上不会进入该领域,并说,根据我们过去所做的,这是我们期望看到的吗?这就是我今天想告诉你的,好吗?
总之,我在做这个分析。我是在允许的范围内做的。想象一下,你有大约 5 亿个索赔,我做了这个频率。有一个数字——有人对 5 亿张唱片的 5.14%的时间收费。你觉得这合理吗?想想整个美国的所有供应商。一家供应商对 5 亿份索赔中的 5%收取相同的费用。这是一个很大的数字,对不对?巧合的有点过了。嗯,没错。但如果我不调查的话,我是不会知道的。
人们去一个非常大的,我不能说,但是遍布美国的非常大的药检机构进行药检。但这是对的,一开始看起来是错的。然后我确实发现了一些数据有问题的地方。数据不是-我们过去称之为胖手指。这不是人为错误,但它是从提交的一个地方编码错误。所以这就是我们这么做的原因。
对于你正在做的事情,模仿最后两个——直方图,最大值和最小值——是非常有效的,很好的方法。如果您每月或每天、每周都在提交非常大的数据,并且您希望围绕它构建一个流程,因此您有一些基准测试的基础,我会做所有这些以及您能想到的任何其他事情。因为你们中的任何一个都能得到更好的。
好了,这里有一些先进的数据质量技术,我相信这个房间里的每个人都以某种形式或方式做过建模。但是我在这里要讲的是用这些技术来检查你的数据质量。好吗?接下来我要讲两个例子,回归和聚类。神经网络更多地假设回归。
这里有多少人用过神经网络?那很好。大约八年前,我读完了研究生,我无法让我的导师让我使用神经网络。我终于让他们让我用了。但是现在,似乎每个人都在使用它。但那时候很难推销。这让我听起来很老。
好的,对于回归,我要做的是尝试预测允许的金额,也就是某人为一个特定的程序支付的金额,对吗?我想使用的所有字段都在这里。是什么样的医生?医生在哪里?是什么类型的手术?个人负担了多少?是的,这与允许的数量有关。
我想在此基础上建立一个模型,你会得到一组系数,就像你得到的其他回归一样,对吗?你可以得到每个变量的系数。记住这一点。我可以对 k 均值聚类做同样的事情。但是这里的不同之处在于——为了简单起见,我在这里使用了相同的字段——但是假设您想要一个实际提供者上的集群,其中您不一定有您试图预测的明确依赖项,但是您想要对事物进行分组。那就是你用这个的时候。同样的事情,无论你使用聚类,回归,神经网络,任何你能想到的。
最重要的是保留系数,种子,权重。基本上,你要做的是,试着设置这些系数,基本上是为未来做一些预测。我将在下一步展示这一点。
现在我们到了与它集成的部分。举手表决——因为我还是来自一家大公司——数据科学团队中有多少人每月至少与他们的信息技术组织举行一次例会?好的,我明白了-继续。在这里的 100 个人中,我只看到了 10 个人。这很正常,但不应该。IT 和数据科学实际上应该非常好地集成。这是我任职期间学到的一件事。
您可以使用它来基本上采用您在两张幻灯片中找到的那些基准。百分之零点,频率分布。您可以编写一个 Perl 脚本或 Python 脚本,无论您想做什么,来自动化这个过程。基本上,你所做的是——就像许多数据科学家做的其他事情一样——你观察一个分布。您可以创建 1,000 个样本的随机样本。找出均值、中值、标准差,然后你就可以在你觉得合适的地方切掉。所以假设正负 2 个标准差。如果一个特定的-让我们说允许的数量。如果平均赔偿金额从 0 美元到–让我们看看,索赔金额是多少?我认为我见过的最高索赔是一次 10 万美元左右。所以,假设是 0 到 10 万美元,好吗?但那是尾端,对吗?大部分可能在 100 美元到 1000 美元之间,对吗?大概 1500 美元。所以,取这两个范围之间的任意值。当你的新数据进来的时候,你运行均值,你运行标准差,然后比较它们。如果没有阈值,你就会触发警报。然后发送给它。突然间,你可以自动检查你的数据。你做分析的时候少了一个步骤。你可以对建模做同样的事情,这就是我所说的第二步。这是更高级的东西。
基本上,你所做的就是做模型。你保存系数。你运行新的数据就像一个样本。然后你看你的预测率是多少。同样,你可以运行一个新的模型,看看系数之间的差值是多少。他们基本上得到同样的东西。基本上,您希望了解我显示的允许数量与所有新数据和旧数据的不同提供商信息之间的关系。我得到了很多。我可以举更多的例子。但是人们有什么疑问吗?
好吧,我们有几个。如果你还需要我解释什么的话,我说得有点快,因为我以为我已经迟到了,所以。
SCOR 的数据科学:用实例而不是法令来管理数据科学
编者按:这是分享开发企业数据科学战略的公司最佳实践的系列文章的一部分。一些文章将包含关于他们使用 Domino 的信息。
在过去的一年半时间里,我们的数据科学卓越中心(CoE) 极大地推动了数据科学在 SCOR 的应用,并帮助我们的业务部门开发模型来满足客户需求,所需时间比以前缩短了四分之一。
虽然有许多因素促成了我们的成功,从强大的管理层支持到顶尖人才,但有一个因素尤为突出:
牢牢植根于知识共享的理念和实践。
为什么要分享知识?
强调知识共享并不是 SCOR 数据科学学院独有的。这在我们的公司文化中根深蒂固。作为全球第四大再保险公司,我们采用模型驱动的方法来帮助客户控制和管理风险,包括自然风险、气候风险、健康风险、地缘政治风险、网络风险等。我们帮助人们在逆境中重建家园。我们的成功深深植根于我们理解问题并与他人合作解决问题的能力。
- 新冠肺炎患者的长期健康风险是什么?
- 再保险人如何帮助促进可持续发展实践和应对气候变化的行动?
- 组织如何降低成为勒索软件受害者的风险?
为此,我们实施了一个多云策略以及 Domino 的 Enterprise MLOps 平台,以提高我们的模型速度,这样我们就可以在过去四分之一的时间内满足客户需求。
近年来,SCOR 的研发部门更名为知识团队,并成立了专门针对特定专业群体的分会,以反映这一重点。我们的数据科学 CoE 就是这些社区之一。(例如,其他包括敏捷性、生物特征风险建模和行为科学。)
特别是对于数据科学,我认为这种知识共享的哲学至关重要。在加入 SCOR 之前,我是一名顾问,看到过无数这样的例子:商业领袖因为狭隘的思维和怀疑态度而抵制全球团队的努力。采取支持员工而不是强加实践的方法使我们能够与欧洲、亚洲和美洲的数据科学和业务同事建立牢固的合作伙伴关系,并避免许多 Coe 面临的阻力。
那么我们如何将知识共享付诸实践呢?
以下是我们使用的五种策略。
- 在当地发生的事情和全球发生的事情之间架起一座桥梁。这包括在业务中安插员工,以促进思想、实践、技术和文档的交流。例如,虽然我们是一个全球团队,但团队成员分散在不同的地点,并对全球团队及其区域市场保持虚线报告结构。这种方法确保我们的数据科学家贴近业务,了解特定市场的具体情况,同时促进思想交流。因此,我们可以将全球实践带到不同的市场,并提升可能有利于其他市场的本地实践。
- **秀,不告诉。**我们不提倡严格的项目流程。我们的数据科学专家分享了他们发现的长期有用的最佳实践和模板,并推荐它们作为节省当地团队时间的起点。有时,这是通过文档发生的。例如,假设您已经准备好部署一个应用程序或 API。在这种情况下,我们可以提供说明从概念验证到生产的 IT 要求的文档,以帮助团队更快地前进。有时,它通过工作本身发生,在我们进行的过程中讨论什么在不同的市场有效,以及它是否可能在这里也有效。我们在构建时也考虑到了可重用性,但我们对此始终保持透明。如果你告诉一个业务部门,我们需要建立一个全球通用的特定标准,他们会立即认为这需要更多的时间。通过使它成为我们日常工作的一部分,我们可以快速地移动,同时仍然创建可重用的资产(无论是一段代码还是整个应用程序)。例如,去年,我们以这种方式完成了大约 25 个项目,这是一个可观的数字,显示了我们可以达到的规模。
- 让每个人都参与进来。例如,我们召集了各个地区最优秀的技术专家来开发使用 Python 和 R(我们数据科学团队中最常用的两种工具)的模板和策略。我们让他们查看所有不同的项目,开发一个强大的框架,我们可以从一个项目重用到另一个项目,并在开始创建应用程序或 API 时引入这种系统化的方法。我们还寻求业务负责人对他们建议的反馈——在给定项目中哪些做得好,哪些可以改进——我们不断学习和重新审视我们管理项目的方式。
- 共享工具和基础设施。为了共享知识、实践和代码,我们必须共享工具。为此,我们在 Domino 平台上实现了一个多云策略。例如,我们在 Domino 上启动了 dashboarding 计划。我们正在扩展一些现有的仪表板,以监控数据和控制一些不同的模型,以便其他市场可以利用它们。我们已经向欧洲和美国市场推出了一款在澳大利亚开发的产品。我们还使用 Domino 扩展了在欧洲开发的 API 的使用,使其在世界范围内可用。
- 保持联系。我们每月两次与每个市场的高层领导进行电话会议,讨论正在进行的项目和新的挑战。这些电话确保我们能够快速响应不断变化的业务需求,并提供必要的支持。例如,这些电话帮助我们很快确定并交付了一些与新冠肺炎相关的项目。许多企业领导人对我们在如此短的时间内取得的成就印象深刻,并开始围绕数据科学展开更多对话。通常,组织将业务构思与技术开发分开。但是,通过从一开始就让技术专家参与进来,我们可以帮助向更有效的业务解决方案发展。
最终,通过专注于知识共享,我们发现我们可以将数据科学从一种功能转变为一种思维模式,并将新思想从一个市场传播到另一个市场。

关于全球一级再保险公司 SCOR
SCOR 是全球第四大再保险公司,为客户提供多元化和创新的解决方案和服务,以控制和管理风险。应用“风险的艺术和科学”,SCOR 利用其行业公认的专业知识和尖端的金融解决方案来服务其客户,并为社会的福利和弹性做出贡献。
SCOR 为其客户提供了最佳的安全级别,标准普尔、穆迪、惠誉和 AM Best 的 AA-评级或同等评级。该集团在 2020 年创造了超过 160 亿欧元的保费,并通过其全球 36 个办事处为 160 多个国家的客户提供服务。
欲了解更多信息,请访问:www.scor.com。
纽约时报的数据科学
原文:https://www.dominodatalab.com/blog/data-science-at-the-new-york-times
克里斯 《纽约时报》首席数据科学家威金斯在 Rev. Wiggins 上发表《纽约时报的数据科学》主张数据科学家发现影响业务的问题;将问题重新框架为机器学习(ML)任务;执行 ML 任务;并以有效的方式将结果反馈给业务部门。他讲述了他的团队如何用描述性、预测性和规范性的 ML 解决方案解决业务问题的例子。这篇文章提供了会议的精华、文字记录和视频。非常感谢克里斯·维金斯在这篇文章发表前提供的反馈。
会话摘要
在 Rev 会议“纽约时报的数据科学”中,克里斯·维金斯提供了关于纽约时报的数据科学小组如何通过开发和部署 ML 解决方案来帮助新闻编辑室和业务在经济上变得强大的见解。Wiggins 建议数据科学家吸收业务问题,将它们重新组织为 ML 任务,执行 ML 任务,然后清晰简明地将结果反馈给组织。他主张,一个有效的 ML 解决方案不会以 Google Slides 结束,而是成为“一个托管的工作 API 或 GUI 或一些人们可以投入工作的工作代码”。Wiggins 还深入研究了应用非监督、监督和强化学习来解决业务问题的例子。Wiggins 还指出,数据科学、数据工程和数据分析是 T4 和纽约时报 T5 的不同团队。特别是数据科学组,包括来自“各种各样的智力训练”的人,包括认知科学、物理、金融、应用数学等。Wiggins 在会议结束时表示,他期待着从更加多样化的工作申请中进行招聘。
本次会议的一些亮点包括
- 在历史背景下定义数据科学家的思维模式和工具集
- 将数据科学视为数据科学家将 ML 应用于现实世界问题的一门手艺
- 数据科学家必须具备分析技术技能,并能够与非技术利益相关方进行清晰简洁的沟通。
- 评估业务利益相关者是否试图解决描述性、预测性或规范性的问题,然后将问题分别重新组织为监督学习、非监督学习或强化学习。
- 在*《纽约时报》*中深入探讨构建和部署 ML 模型的示例,包括面向描述性主题建模的 Readerscope(受众洞察引擎),关于谁可能订阅/取消订阅的预测模型,以及通过高度策划的编辑内容推荐的说明性示例。
要了解更多关于本次会议的见解,请观看视频或通读文字记录。
录像

副本
克里斯·维金斯:
我和你有大约 30 分钟的时间。我将在《纽约时报》上告诉你们所有关于数据科学的内容,如果时间不够,我的电子邮件地址和我的 Twitter 都在这里。随时给我发电子邮件。如果你不记得其他事情,只要记住我们在招人。不,我只是在开玩笑。我们在招人,但是…我的演讲有点像皮特·斯科莫罗奇的演讲和帕科·内森的演讲,有点像是塞进了应用程序。我今天要讲的很多东西,希望能引起你们今天早些时候在 Paco Nathan 或 Pete 的演讲中听到的共鸣。
正如广告所说,我在哥伦比亚大学和《纽约时报》之间来回奔波,在《纽约时报》我领导着一个数据科学小组。哦,顺便说一句,如果你发微博给我,我现在应该警告你,我和 Twitter 有一种“黑暗森林”的关系,这意味着我阅读,但我不写,所以如果你要发微博给我,告诉我你的电子邮件地址,这样我可以通过其他渠道联系你。数据科学。数据科学在纽约时报。
首先,我必须告诉你我们是做什么的…当我们在纽约时报做“数据科学”的时候。不同的公司对“数据科学”的理解是不同的。例如,脸书几年前刚刚将他们所有的“数据分析师”重新标记为“数据科学家”。当有人说他们“做数据科学”时,这可能意味着许多不同的事情。下面是我们如何看待*《纽约时报》*的数据科学思维和工具集。因为我是一个学者,我喜欢看原始的创始文件。这是一份关于数据科学的古老文档,特别是 Jeff Hammerbacher 的一篇文章。这里有多少人认识杰夫·汉默巴克?只有几个人听说过他?有多少人听说过杰夫·哈默巴赫尔?好吧。杰夫·哈默巴赫尔在脸书创立了数据科学或数据基础设施。有多少人听说过脸书?很好。他和一个叫马克·扎克伯格的人一起上大学。他做了一年金融,然后就超级无聊了。他打电话给马克说:“马克,你有什么事吗?”马克说,“是的,我们有很多数据。请帮助我们理解它。”他去了脸书大约四年,然后退休了。2009 年退休时,他有些空闲时间。他收集了这本可爱的散文集。他在书中说,
“在脸书,我们觉得不同的职位头衔,比如研究科学家、商业分析师,不太适合我团队中的多样化工作。“数据科学家”可能用 Python 构建多级处理管道,设计假设测试,用 R 对数据样本执行回归分析,用 Hadoop 设计和实现算法,或者以清晰简洁的方式将我们的分析结果传达给组织的其他成员。为了抓住这一点,我们想出了“数据科学家”这个头衔"
我真的很喜欢这一段。
十年后再来看,这确实是一个有趣的段落。Python 已经有了足够的武器等级,我们不会再堕落到 R 级了。抱歉,各位。我曾经是你们中的一员,但我们不再陷入 r。Hadoop 肯定正在发生,但这是谷歌的问题,因为现在在 iron 解决方案上构建了我们自己的 Hadoop 后,在处理了一段时间的红移后,我们现在只是将其全部交给 BigQuery。后台有一个分布式 MapReduce,但我们不需要知道。据我们所知,我们感觉像是在输入 SQL。但是,以清晰简洁的方式将结果传达给其他人,这绝对是我对数据科学团队员工的要求。我想要数据科学家,我可以和来自产品或营销部门的人或不会说微积分的人一起呆在一个房间里,这说明了皮特说过的很多事情。我不希望产品经理成为研究和开发有用产品的人和最终用户之间的信息瓶颈。我们希望人们能够以清晰简洁的方式与组织中的其他人交流。
另一个试图向我上面的人解释我们在数据科学组做什么的古老而规范的文档是这个。有多少人看过这个维恩图?很好,好的。这是一个非常数据科学的人群。你甚至可能认识德鲁·康威,那时他还只是个研究生。他试图解释他在一次阶层规划会议上听到的内容,当时人们正在谈论数据科学。
我仍然相信数据科学是试图将机器学习应用于一些现实世界问题的工艺。
同样,营销或产品部门的人不会来对你说,“请用多项式核来最小化这个铰链损耗。”一个真正的活生生的人有一个现实生活中的问题,比如“我想知道如何让更多的人订阅我的产品”或者“我想让人们不要离开我的产品”。他们带着一些现实世界的问题来找你。作为数据科学家,你的工作是找出如何将现实生活中的问题重新构建为机器学习任务,执行机器学习任务,并以对他们有用的方式向他们传达结果。如果你是 Eric Colson 所说的“全栈”数据科学家,并且你是 prod 的成员,那就更好了,这意味着你实际上是在推送代码,产生一个实时 API、一个实时 GUI,一些其他人可以投入工作的东西,这就是数据科学家如何真正增加我的经验价值。我们可能会觉得这些是数据科学的古老文档。
正如 Paco 今天早上介绍的那样,在思维模式中有一些甚至更早的古代文档,甚至带有“数据科学”这个短语。一份文件来自异端统计学家比尔·克利夫兰。像他那个时代的许多异端统计学家一样,他在贝尔实验室。贝尔实验室确实证明了约翰·图基的心态,正如帕科今天早上向你们介绍的那样,现在我有几双图基 swag 袜子可以送给我的朋友。比尔·克里夫兰和贝尔实验室的许多其他统计学家确实生活在当时的谷歌和脸书时代。他们是政府容忍的垄断企业。他们有所有的书呆子,所有的计算机,以及所有关于你们所有人一直在互相说什么的数据。我们学到了很多关于如何利用数据耗尽的经验——这是一个常见的短语,Pete 暗示了一个产品产生大量有用数据的方式——他们是对的。他们拥有这个国家所有的电信,这意味着大量的其他数据,但这是另一个话题。总之。贝尔实验室基本上是当时的“数据科学”。2001 年,比尔·克利夫兰写了一篇文章说,“你做错了。”当然,他与之交谈的人不是业内的其他人。他在与学者交谈时,回到了 Paco 之前的观点,即数据科学实际上是由行业发明的思维模式。这是几篇类似文章中的一篇,但那是另一篇了。
我们还试图帮助我们的高管理解可互换使用的单词之间的区别。人们交替使用 AI、ML 和“深度”这三个词。我们试图以不同的方式使用它们。没有 ML 当然也可以有 AI 吧?如果你写一个像伊莱扎一样的聊天机器人,这里有很多人工智能。“艾”是志向。我想做一个模仿真实智能的东西。但这不一定是要从数据中学习的东西。如果你对这种历史感兴趣,并且希望 Paco 激起你对其中一些历史的兴趣,我鼓励你看看其他的基础文献,比如 Herb Simon 的这篇伟大的文章。赫伯·西蒙在 1983 年写了这篇文章,他说,“是谁在阻碍我的人工智能,并把他们的 ML 放在我的人工智能里?”赫伯·西蒙当然不是傻瓜。他是少数几个获得诺贝尔奖和图灵奖的人之一,他的想法是,“你们所有人都很懒,你们应该给它编程。不要试图让计算机为你编程。”任何人。AI 和 ML 不一定一样。AI 是一种渴望,ML 是一种试图让你得到一些“我”的方法。
让我们回到数据科学。现在,我已经告诉了你一些我对数据科学的看法,以及我们在纽约时报、对数据科学的看法,你可能想知道这些与纽约时报有什么关系?这是一个合理的问题,尤其是当你想到《纽约时报》时,你会想到这个问题。这是一张纽约时报在 1851 年生日的照片,在它生命的绝大部分时间里,这就是用户与纽约时报互动的体验。你可能想知道你会把一个数据科学小组放在纽约时报的什么地方。
为了向你解释我们小组的位置,我必须给你看一下《纽约时报》的组织结构图。这是《T2》和《纽约时报》的组织结构图。
教堂。教会是拥有并捍卫新闻业的人。国家就是一切。
我在州政府。
我想说明的是,我领导的团队并不制作那些令人敬畏的信息图。那些人很棒。我们是朋友,我们是兄弟。道具。不是我的人。我们不做数据新闻。我们咨询记者,当我们能帮上忙的时候,我们尽力帮忙,但是那些人有截止日期,我已经向 NeurIPS 和其他公司提交了论文。我这辈子已经有够多的截止日期了。我不想写新闻。相反,我们在做你看不到的事情。
我们正在努力帮助企业在经济上变得强大。我们在状态上是稳固的,特别是,我们在一个叫做数据的子群中。当我出现的时候,我正在向 BI 的负责人汇报,他向 CTO 汇报,CTO 向 CIO 汇报,CIO 向数字产品的 EVP 汇报,EVP 向 CEO 汇报。在这一点上,数据是一个直接向 CEO 报告的功能。我在纽约时报工作的五年里…六、五年半,数据变得更接近一等公民,事实上向首席执行官报告。
数据科学小组的部分目标是对整个教会和国家都有用,因为数据尤其可以对编辑、广告人和各种不同的项目有用。我将向你们展示一些我们将数据科学付诸实践的项目示例。该组织的口号是“开发和部署机器学习解决方案,以解决新闻编辑室和业务问题。”我的意思是,除了在 scikit-learn 中找到的方法之外,您可能需要稍微扩展一下机器学习方法。足够深入地了解机器学习是有用的,以至于你知道如何超越 scikit 中的内容,并且你可能会部署它。希望你能部署它,对吧?
我们时不时会制作一些以谷歌幻灯片结尾的东西,但我们的目标是制作一些可以托管的工作 API,或者 GUI,或者一些人们可以投入工作的工作代码。这就是我在与团队外的人交谈时对标语的想法。当我与团队之外的人交谈时,我也会尝试解释我的团队做什么,以及更大的数据分析师团队做什么。我提出的一种方式是,“你在寻找建立一个预测模型吗?还是一个规定性的模型?还是描述性的模型?”今天我将向你们展示的不同问题…我用不同的方式思考。我发现,当我与团队以外的人交谈时,一个有用的框架是,来自产品、营销或编辑部的人,“你在寻找描述吗?预测在没有治疗的情况下会发生什么?或者你是在找我帮你决定什么是最佳治疗,以获得你想要的结果?”在我的团队里我说。“实际上,这些是无监督学习、监督学习和强化学习,但不要告诉团队以外的任何人,因为那样会让他们的眼睛变得呆滞,会认为我们在说某种星际语言。”但这是人们可以理解的。
思考这些问题的另一种方式是在某种功能、营销活动或其他东西的生命周期中。有时人们会找到我,他们会给我一个数据集,他们说,“给我找纳斯卡妈妈或其他细分市场。”我会说,“好吧。你真的是在让我向你描述这个数据集,但你为什么想找到纳斯卡妈妈们呢?”“嗯,我真的很想知道哪些会流失,哪些会订阅。”“好吧,那你真的不想要描述。你真的想要一个预言。你真的很想知道这些人中哪一个会成为订户。”他们说,“嗯,不。我想知道我应该给哪些人这个提议,我应该给哪些人显示蓝色按钮。”我说,“好吧。你真正想要的是一个规定性的模型。你真的想…你真的已经知道你想采取什么行动,你想让我帮你找出最佳治疗方案,而不是在没有治疗的情况下会发生什么。”让人们经历和思考这些事情通常与商业伙伴对他们真正想做的事情考虑得有多深有关。
当然,这看起来很像科学。
如果你在科学上花些时间,你会知道同样的规则也适用,那就是你建造一些东西,你建造一个预测,然后你把它放到野外。它不起作用,然后这有助于你重新理解你对数据的心理模型出了什么问题,或者你对人的心理模型出了什么问题。很好。描述的例子有哪些?让我给你们看一些问题的例子,在这些问题中,我们已经能够建立对有用数据的描述。
一个是这个叫做 Readerscope 的工作 GUI。Readerscope 是一个告诉你谁在哪里读了什么的工具。“什么”是一个主题模型。“谁”涉及第三方数据,声称此人可能是决策者或纳斯卡妈妈之类的人。“哪里”是地理定位。对我们来说,你知道,这开始就像一个科学项目,有一些花哨的主题建模,然后我们把它展示给我们在广告业的朋友,他们说,“太棒了。我们可以将其货币化。”突然间,我们有了两个项目经理,两个前端开发人员和一个后端开发人员,这就变成了一件美好的事情,看起来不再像一个科学项目。相反,我们把它展示给其他公司的营销部门的人看,这些人正在考虑为《纽约时报》的像素付费,他们会问,“你的读者是谁,他们到底在看什么?”我们说,“我们可以展示给你看。
这里有一个工具可以帮助你了解谁是人,他们过度索引的主题是什么。您可以将鼠标悬停在这些不同的主题上,查看与这些主题相关的单词。“这有助于人们了解谁是我们的读者。同样,举例来说,这只是一种描述,而不是对将要发生的事情的预测。
然后,我们可以深入研究,并指出哪些文章对该组或该主题进行了过度索引。我们看到你可以通过“谁”、“什么”或“在哪里”来理解人们。好吧。这是一个描述工具的例子。
预测工具的一个例子是什么?嗯,如果你使用任何数字订阅服务,你能想象的第一件事就是建立一个模型,预测你的哪些用户将成为订阅者,哪些订阅者将取消订阅。事实上,我的第一天——我结束了在纽约时报的休假——我在那里的第一天…我仍然保留着那天下午 3:00 发给我当时老板的电子邮件,邮件中说,“我们真的需要一个模型来预测我们的哪个订户将会取消,”就像 table stakes 需要一个模型来预测哪个订户将会取消一样。当然,如果你得到的东西有很高的预测能力,那很好。作为一名数据科学家,你可以晚上睡觉,你知道你不是在构建一个随机数生成器,但是产品部的人,他们不想知道你可以预测谁会有风险。他们想知道什么是危险的行为。当然,我们努力建立不仅可预测而且可解释的模型。
向上帝发誓,我今天在 Paco 演讲之前有这张幻灯片,但是这是 Leo Breiman 提出的一个很好的观点。如果你不知道 Leo Breiman,他已经不在了,但 Leo 是另一个异端统计学家的好例子,一个西海岸异端统计学家,他显示了他作为一个适当的数学概率学家的真诚,写了一本有趣的书,然后离开了在加州大学洛杉矶分校的终身职位,在地球上行走了一段时间,为各种客户做咨询,包括全新的 EPA 和其他一群试图找出不同外国潜艇之间的差异的人。在途中,他建造了随机森林和其他一些东西。在他和我们在一起的时间快结束时,他回到了伯克利的学术界,试图向他的统计学家同事解释,“你做错了。”这是他的一篇关于“你做错了”的论文,其中他谈到了他在机器学习社区中观察到的算法文化,以及在统计学中更传统的生成模型社区。他还知道,因为他在现实世界中工作过,所以有时人们想知道哪些客户有风险,有些人想知道他们的风险行为是什么。有时人们想要一个预测,有时他们想要一个解释。正如他在奥卡姆困境这一节中所说,“森林是 A+预测因子”。但他接着说,“他们的可解释性被评为 F 级。”早在最近对可解释的机器学习的兴趣复苏之前,Leo 和其他理解预测和人们想要的之间的平衡的人就在研究它。然而,在可解释性方面,决策树的得分是 A+。这是一个很好的例子,当客户希望预测,但也希望一些可解释性。
与许多数字媒体公司不同,纽约时报仍然以枯树的形式发布新闻。我们把枯树运送到不同的商店,必须有人决定明天早上应该把多少棵枯树送到 1066 号商店、137 号星巴克或者类似的地方。有很多方法可以做到这一点。假设,您可以在 20 世纪 90 年代的 AS400 机器上使用大约 10,000 行用 COBOL 编码的启发式代码。或者你可以用科学。我们现在用科学来做这件事。具体来说,我们有机器学习模型来推断不同商店的可能需求分布。一旦你知道了分布,这就是一个老问题,有时被称为报童问题。如果你参加第一年的研究生运筹学课程,在给定需求分布的情况下获得最有利可图的分配被称为报童问题。我们是一个报摊,所以我们有这个问题。此外,我们可以在仔细的 A/B 测试中使用科学,我们可以显示不同的商店,不同算法的分配,然后我可以向首席执行官科学地证明,通过使用科学,我每年节省了多少数据科学家的工资。在部署端,有人将一堆枯树扔进了商店,但在 BQ 之外,还有 scikit-learn。在上面的某个地方,Python 正在分配一定数量的文件,这些文件最终会以某人扔枯树的形式作为产品部署。很好。其他花式预测题。
《纽约时报》的另一个问题是…与枯树有关…把墨水涂在枯树上。当一名摄影记者拍下一张照片,然后发送给*《纽约时报》的编辑时,这种事情每天都会发生数千次,其中一些照片最终会成为印刷品。文件是从相机、手机或其他内置在墙上的无电池监控设备中获取的。谁知道呢?然后,一个非常仔细和耐心的编辑必须检查并重新平衡所有的颜色直方图,所有的 CMYK,直到它完全达到正确的照片平衡,因为否则当它最终变成墨水并进入印刷机时,你只会得到一个黑色的方块。*
在排气的过程中,我们有一个很棒的前后数据集,是一个耐心的编辑做的,现在我们基本上可以给他们一个温暖的开始。我们可以说,“看。这是照片…这是摄影记者相机里的文件。下面是我们对一个无限耐心的编辑如何去做的建议。”使用深度学习,我们甚至可以超越这一点,我们可以说,“这是 12 号编辑可能会重新平衡它,”而不是,“这是……”如果你有足够的数据集,你实际上可以学习不同的编辑器风格。做这件事的令人敬畏的天体物理学家最近已经离开并加入了谷歌的人工智能小组,对我来说很不幸,但他在使用谷歌的工具将这件事付诸实施方面做得很好。这很有效。这是一个视觉问题,所以它既适用于我们的 MSE,也适用于你的眼球。但是这里有另一个可行的方法。
我们建立的另一个项目是这个项目,这是一个夏季实习生项目,有一个本科生和我一起在哥伦比亚大学工作,然后她作为数据科学实习生和我一起工作,我们建立了这个项目,有点像一个科学项目,看看你能不能实际预测人们在阅读纽约时报的不同报道时会有什么感觉。最初的想法是,如果你不仅知道故事的部分,而且知道“这是一个严肃的故事,或者这是一个非常快乐的故事”之类的话,也许你可以建立一个更好的推荐引擎,或者也许你可以进行更复杂的分析起初我在想,“好吧,我用我拥有的数据,而不是我想要的数据来战斗,所以拥有这些数据是很好的,但我不会让编辑坐下来给故事贴标签,谁感觉快乐,悲伤或诸如此类的。”但后来我意识到我可以众包它。我们众包了它。我们实际上让人们给一堆故事贴上标签,并说他们感受到不同的感觉,然后我们使用一些深度学习模型,这些模型实际上可以预测人们会有什么样的感觉。对于这样一个故事,“雪儿从来不是一个超级粉丝,但她喜欢做雪儿,”你可以说,“嗯,这是,你知道的,‘受鼓舞的’、‘快乐的’、‘被逗乐的’和一堆其他的感觉。然后,这是一个有趣的暑期项目,你知道,就像一个实习生的暑期实习项目,她已经在 Chartbeat 有一份全职工作等着她,所以这只是一种玩笑,看看我们是否能做到这一点。然后我把它给我的广告朋友看,他们说,“太棒了。我们可以把它货币化。"
突然之间,我们有了一个完整的后端团队,他们将攻击我们的 API,然后将其转化为广告策略,现在你可以根据一篇文章给你的感觉来销售优质广告。其逻辑是,不要说,“我希望我的品牌出现在一篇文章的旁边,你知道,旅游,”它可能是你希望你的品牌出现在一篇文章的旁边,这篇文章让人感觉“有灵感”、“有希望”或“有冒险精神”或类似的东西。我们可以做到。
当我说“它起作用了,它起作用了,它起作用了”时,我的意思是它起作用了,因为我们在测试数据上得到了准确的预测,所以我晚上可以睡觉了。它的工作原理是人们为此付费。这实际上是一种商业行为,我们通过做这件事来赚取数据科学家的薪水。从某种意义上说,当广告客户更有策略地瞄准目标时,他们实际上看到了更多的提升。比如,你有一张与某种特殊好奇心相关的图片,你应该把它放在会让人感到“好奇”的文章旁边。
另一件很酷的事情是,它不涉及任何人。这里不涉及 PII。我没有做任何关于人的分析,并声称某人是纳斯卡妈妈或对天知道什么感兴趣的商业决策者。我只是在对文本进行分析。这是更好的语境相关性广告。它成功了,成功了,成功了。挺好玩的。我以前没有众包,但你会得到有趣的效果,就像人们真的会给你发电子邮件,告诉你他们对这个实验的感受。通过弄清楚,你知道,不同的感觉如何相互联系,有一些有趣的计算社会科学要做。另一件让我感到奇怪的事情是,你知道,在我在哥伦比亚的研究中,没有人在事后为这个项目制作了一个沥青平台,但是现在人们实际上…在《纽约时报》中,有一个团队制作了这个演示平台,展示事情实际上是如何运作的。上周我们刚刚在一个广告集团获得了一个奖项。我在哥伦比亚大学写的论文中,没有一篇是有人为我做了一个像这样的移动平台。
这是一个人们…我们也谈论我们如何运送东西,所以我会说一点我们如何运送东西。当我在 2013 年出现的时候…有痛苦。如果你想要数据,这意味着你要编写 Java MapReduce,你要坐在 S3 打一桶桶 JSON。然后,当事情变得真正文明时,你可以说蜂巢或猪。然后最终你可以和维护亚马逊红移星团的人战斗。然后有人决定,一个好主意是让我们购买自己的机器,并在这些机器上安装 Hadoop,这种方法会悄无声息地失败,并且需要您更接近金属并理解 Java 错误日志。在这一点上,所有的都是谷歌的问题,都在 GCP。小组中的开发人员,他们用 Python 编写;他们利用 sci kit-大量学习。我们有持续集成解决方案。为了可视化,我们没有构建自己的仪表板。我们用的是 Chartio。每个人都很满意。然后,最终调度的作业由 Airflow 和 Cloud Composer 管理。作为一个例子,在这个项目中,当我们预测感受时,我们也使用张量流…并充分利用 scikit-learn 作为我们的解决方案。这种感觉在某种意义上起作用,你可以去看看,然后说,“嗯,明尼苏达州的家庭故事让人们感到快乐;医生误诊的事情让人感到难过。”这是一套合理的解决方案。所有东西都从 GitHub 中管理的代码库通过 Docker 转移到 GCP,然后这就成了 GCP 的问题——谷歌的问题——就像我们不会在这个问题上超过谷歌一样。太好了。
这些是描述和预测的例子。处方的例子是什么?很多时候,人们并不想知道在没有治疗的情况下会发生什么。他们想知道最佳治疗方案是什么。一个很好的例子就是观众发展挑战。受众发展意味着当你是一名编辑并点击发布时,你与故事的关系并没有结束,因为仍然有机会确保人们了解故事。同样,在大约 150 年的时间里,用户体验是一棵摊开在桌子上的枯树,而现在人们正在体验手掌中的新闻。关于我们如何在社交渠道上推广这些东西,有一些策略需要考虑。我们建立了一些奇特的机器学习,根据你是否在不同的社交渠道上推广,来预测不同的参与度水平——对于不同的参与度定义。这很好,但是我怎么把它交到编辑手里呢?好吧,结果是编辑器不会启动 Python。我们花了一段时间思考我们可以构建什么样的 web 应用程序,但是根据以前的经验,尽管我们在 Flask 中拥有出色的开发技能,编辑们不会停止他们正在做的事情,并打开一个新的 web 应用程序。
然而,在 2014 年,2015 年编辑们爱上了 Slack。Slack 的 Josh [Willis]昨天向你介绍了 Slack。然后我们这些除了命令行之外不特别擅长界面的人就可以了,因为我们只需要考虑如何让我们的机器学习可读,也就是说易读。编辑可以和这个机器人互动。软件工程师变成了一个产品人,来到新闻室,看着他们做他们做的事情,做所有这类的产品研究,然后建造这个人们可以与之互动的机器人。你可以问它一些问题,比如“我应该在脸书上发布什么?”或者你可以让它打断你,说,“说真的,你应该把这个贴在脸书上。”
另一个说明性问题的例子是对于有个性化的部分内容,我们如何做到这一点?嗯,我们可能不希望我们的编辑为每一个选举报道做决定,例如,这个选举报道只对俄亥俄州有兴趣,还是对俄亥俄州和阿拉巴马州都有兴趣?我们宁愿放手让数据…我们为一小部分内容构建了一个上下文相关的 bandit 解决方案:被编辑认为与选举相关的内容;内容将被放入一个受控的小部件,就像一个选举箱,然后我们可以放手,让上下文强盗。出于时间的考虑,我不打算教你语境强盗。这就像做 A/B 测试,只不过之后你再也不用开会了。如此语境化…就像刚刚想到的土匪一样,多武装的土匪就是会议杀手。不要在会后开会说,“哦,我喜欢 B,但另一个人喜欢 C,然后 CEO 喜欢选项 D,”你只需放手让强盗去做,你永远不需要再开会,因为代码会动态地为你感兴趣的 KPI 赢得胜利。
做土匪有很多种方法。出于时间的考虑,我不会告诉你太多,除了我们最喜欢的是最古老的。最古老的是 1933 年的一项技术,这非常有趣,当时一群人在为他们最新的 PAC 界限和算法捶胸顿足,然后获胜的是 1933 年的东西。顺便说一下,这是雅虎的一些研究人员在 2011 年写的一篇论文,他们将自己的花哨算法与 1933 年的算法和 1933 年的算法进行了比较,这非常酷。如果你们中的一些人是学者,你的论文没有被引用,不要担心。这是这篇发表于 1933 年的论文的引用次数。直到 2011 年才有人注意到这一点。突然就像“砰!这才是 biddy!”只是,你只需要等 80 年然后你的论文就会被大量引用。是的,现在你可以把这个东西作为一种服务。我不会告诉你我们为了扩展它而做的奇特的数学。相反,我只会说一点点,试图呼应 Paco 和 Pete 所说的关于我们已经了解到的关于完成事情的事情。我们学到的要把事情做好的主要东西是,如果你想改变文化,你需要按照“人”、“想法”和“事情”的顺序来做,这是从军队里学来的。这是美国空军飞行员约翰·伯伊德的一句话,我们真的…我们无法完成任何事情,除非我们从合适的人那里买进,他们愿意让我们进行试验和尝试。我们所有人都对各种各样的“事情”感到非常兴奋。
我在皮特今天下午的演讲之前放了这个,但是皮特提到了莫妮卡·罗加蒂的需求层次理论。你知道,当你出现时,你是第一个数据科学家,你可以通过做一些花哨的人工智能和 ML 来进行一些挑衅,但如果你没有正确的数据基础设施,那么就很难真正影响流程。一开始,五年前,我们在做一些挑衅的事情,构建我们自己的 Flask 应用程序,但实际上整合到其他人的流程中需要公司真正提升其所有数据基础架构,他们已经做到了。
出于时间的考虑,我不会谈论太多,除了回到我之前关于脸书的笑话的另一件事是,在学术界,我们倾向于将所有这些工作混为一谈,数据治理,数据分析师,数据科学家,数据工程师,但是纽约时报看到了不同的头衔,不同的群体。我们努力与各方合作,包括 Paco 提到的数据治理。我们有一个非常好的数据治理团队。我们这样做的一部分是从各种各样的智力培训中雇佣人员。目前团队中的人来自物理、金融、应用数学、双 E、cog sci,这在众包和其他方面非常有用,我们还在招聘。我们期待着从更加多样化的工作申请中招聘人才。就这样,我有两秒钟的时间来提问。
谢谢您们。
【编者按:为了可读性,本文经过了编辑。]



5940

被折叠的 条评论
为什么被折叠?



