作为社会科学程序员处理不同的数字数据
照片由 @gemasaputera 拍摄
文本、声音、数字、代码、图像、视频等等
昨天我和一个社会数据科学的同学进行了讨论,我们问自己为什么社会科学家经常处理数字或文本数据。我没有量化社会科学家的数量。然而,这是我目前所看到的印象。如果你是一名经济学家,处理数字数据似乎更直接,而且有可能通过合作来处理法律,特别是在涉及政治利益和政治政策考虑的情况下(可能是这种情况)。例如,如果考虑税收政策。
就我所见,音频、图像和视频数据减少的原因可能很容易解释。在社会科学家经历的教育经历中,他们经常被教导通过文本交流。我想不出有哪种社会科学教育会在很大程度上利用图像、视频或音频中的训练。这些无疑是表达的媒介,是交流或传播研究的场所。因此,也许奇怪的是,他们没有在更大程度上考虑研究和教育。
出现了几个与这次讨论有关的问题。按出现的顺序:
- 有可能量化社会科学家在传播研究、记录和处理中使用的数据吗?
- 如果你尝试,你会如何分类研究论文?
- 社会科学领域总共有多少篇研究论文?
- 哪些学科可以被认为是社会科学的一部分?
- 如果研究是以一种形式进行的,它可能被用于其他形式的交流,人们如何能够发现这是否可能是事实呢?
- 为什么这会有价值?
当这些问题出现在我的脑海中时,我将试图简要地回答这些问题,当然是临时性的,以引发可能的讨论。
为什么这会有价值?
我觉得最后一个问题可能先回答比较容易。研究进行的方式和涉及的方法——材料研究是研究团体感兴趣的。它还可以说明某一科学学科的整体研究方法或途径。
如果研究是以一种形式进行的,它可能被用于其他形式的交流,人们如何能够发现这是否可能是事实呢?
这似乎几乎不可能。如果一个人要这样做,那么他可能必须首先这样做。成功分类数百万份文档,然后尝试跟踪介质中的部分文档。如果一个研究项目以某种方式保留了它被设计的格式,并且从未传播到其他格式,这是非常值得怀疑的。这就变成了一个问题,是应该只考虑收集的材料还是研究交流的形式。大多数已经完成的研究是否会列出其他类型的工作表现/文档/表达?这是一个不同的问题,很难回答。
哪些学科可以被认为是社会科学的一部分?
根据《大英百科全书》:“社会科学包括文化(或社会)人类学、社会学、社会心理学、政治学和经济学。还经常包括社会和经济地理以及那些处理学习的社会背景和学校与社会秩序的关系的教育领域如果要进行这样的研究(如果可能的话),那么就有可能考察这些学科或其中的几个学科。在这一过程中,必须认识到,其他人可能对社会科学的范围有不同的定义。
社会科学领域总共有多少篇研究论文?
这似乎很难回答。这似乎也不是一个富有成效的问题。一方面,为什么一个人要试图从一段时间里收集该领域所有可能的知识。另一方面,如果将这一数据限制在过去五年内每个领域中最大的五种期刊上,就会出现问题。这可能是一个开始,而且似乎更有可能,如果一个人应该决定。在这种情况下,作为一种思想出现的是数据类型的差异,甚至是数据的基本概念。
如果你尝试,你会如何分类研究论文?
政治学家、经济学家和人类学家对数据有什么不同的看法。这种理解可能并不普遍,但简单地将其归类为文本、图像、视频等可能会令人困惑/无益。如果要找到专门处理*【数字】数据的文章,研究每个领域中什么被认为是【数字】*可以是一种分类方式。来自研究的数据可能在不同的领域中遵循一定的标准,至少在最常见的叙述中。从某种程度上来说,收集大量信息并进行分类只会强化叙述或偏见。也许更有建设性的做法是,问问对数字方法更感兴趣的社会科学家如何处理不同类型的数据。此外,这些类型的探索性研究如何与该领域现有的方法或从业者相结合。分类是否足够有用,以至于需要收集大量的研究来尝试分类?
有可能量化社会科学家在传播研究、记录和处理中使用的数据吗?
是的,这是可能的。我认为这是可以做到的。研究研究人员如何研究很有趣。另一个方面是通过搜索模式——引用模式——引导或管理的整体知识生产的治理变化。搜索模式似乎已经发生了变化,研究的管理方式也值得考虑。我之前写过这个问题,因为研究的方式正在发生变化,在某种程度上不可避免地会受到一系列不同算法的影响。
人工智能正在改变研究的方式
medium.com](https://medium.com/dataseries/ai-academic-search-engines-acf971717fbf)
当我与我的同学交谈时,我的第一个想法是,更多地分析视频数据可能会很有趣,然后一个大的隐约出现的问题击中了我。如何切实可行地做到这一点?通过将视频数据与其他来源相结合,可以更好地探索哪些社会科学主题?会出现哪些伦理问题?
你怎么想呢?
PS:当我提到社会科学程序员时,它涉及到将 编程作为社会科学 的讨论。越来越多的社会科学家不仅在研究编程人员,还在学习编程语言并将其融入他们的方法中。
这里是#500daysofAI,您正在阅读的是第 459 条。500 天来,我每天都在写一篇关于或与人工智能相关的新文章。
用 Python 多线程处理大型数据文件
在左侧车道加速行驶。
2020 年 zapalote.com
我们花费大量时间等待一些数据准备任务完成——你可能会说,这是数据科学家的命运。我们可以加快速度。这里有两种技术会派上用场:内存映射文件和多线程。
数据
最近,我不得不从 Google Books Ngram corpus中提取术语和术语频率,我发现自己在想是否有办法加快这项任务。语料库由 26 个文件组成,总数据量为 24GB。我感兴趣的每个文件都包含一个术语和其他元数据,用制表符分隔。将这些文件作为熊猫数据帧读取的暴力方法非常慢。因为我们只需要唯一的术语和它们的匹配计数,所以我想我会尽量让它更快:-)
内存映射文件
这种技术并不新鲜。由来已久,起源于 Unix(Linux 之前!).简而言之,mmap
通过将文件内容加载到内存页面中来绕过通常的 I/O 缓冲。这对于内存占用量大的计算机非常适用。对于今天的台式机和笔记本电脑来说,这基本上没问题,因为 32GB 的内存不再是一个深奥的问题。Python 库模仿了大多数 Unix 功能,并提供了一个方便的readline()
函数来一次提取一行字节。
# map the entire file into memory
mm = mmap.mmap(fp.fileno(), 0)# iterate over the block, until next newline
for line in iter(mm.readline, b""):
# convert the bytes to a utf-8 string and split the fields
term = line.decode("utf-8").split("\t")
fp
是一个文件指针,之前用r+b
访问属性打开过。这就对了,通过这个简单的调整,你已经使文件读取速度提高了一倍(好吧,确切的改进将取决于许多因素,如磁盘硬件等)。
多线程操作
下一个总是有助于提高速度的技术是增加并行性。在我们的例子中,任务是 I/O 绑定的。这非常适合于扩展— 即添加线程。你会发现关于什么时候在搜索引擎上横向扩展(多处理)更好的讨论。
Python3 有一个很棒的标准库,用于管理线程池并动态地给它们分配任务。所有这一切都通过一个极其简单的 API 实现。
# use as many threads as possible, default: os.cpu_count()+4
with ThreadPoolExecutor() as threads:
t_res = threads.map(process_file, files)
ThreadPoolExecutor
的max_workers
默认值是每个 CPU 内核 5 个线程(从 Python v3.8 开始)。map()
API 将接收一个应用于列表中每个成员的函数,并在线程可用时自动运行该函数。哇哦。就这么简单。在不到 50 分钟的时间里,我已经将 24GB 的输入转换成了一个方便的 75MB 的数据集,可以用 pandas 来分析——瞧。
完整的代码在 GitHub 上。随时欢迎评论和意见。
PS:我给每个线程加了一个带tqdm
的进度条。我真的不知道他们是如何设法避免屏幕上的线条混乱的…它非常有效。
更新:两年后,这个上来了:-)
在 Python 中用 Unicode 处理文本
数据科学家的最佳实践
照片由 Kayla Kozlowski 在 Unsplash 上拍摄
我们能够阅读这些文本行,因为我们熟悉英语中使用的 26 个字符的拉丁字母。其他语言有他们自己的字符,他们都需要被编码,这样他们就可以被我们的计算机所代表。几十年来,计算机能够根据 ASCII 码表来表示字符。
ASCII 表
ASCII 是一种在 8 位代码的 256 个可用位中分配字母、数字和其他字符的标准。对于不使用拉丁字母的语言,如汉语、希腊语、日语,ASCII 无法表示这些文本,我们需要一个新的字符集。它们是 Unicode。
Unicode 表
Python 中的文本可以用 unicode 字符串或字节表示。
编码 unicode 字符串
让我们在 Python 中定义一个string
,看看它的类型。
它确实是一个str
类型的对象或者一个字符串。如果我们定义一个字节。(我们可以用 *bytes*
函数将字符串转换成字节对象)。
我们尝试定义一个包含非 ASCII 字符的 byte 对象(中文*“Hello,World】*)。
我们可以用前缀 b 定义一个字节
它显示了一个错误,告诉我们需要先将包含非 ASCII 字符的字符串转换成 bytes 对象。
我们将需要提供和编码来做到这一点如下。
这部分代码的结果如下图所示。
处理编码的一个更好的方法是使用encode()
函数。
正如你所看到的,我们得到了和以前一样的结果。
请记住,默认情况下,Python 3 使用 utf-8 编码。
因为 Python 3 默认使用utf-8
,所以我们应该如何使用不同的编码,我们简单地把它传递给函数。例如,我们可以如下编码utf-16
中的‘hello world’
字符串。
解码字节
Unicode 字符串可以用一些预定义的编码方式编码成字节,比如utf-8
、utf-16
等。字节可以解码为 unicode 字符串,但这可能会失败,因为在特定的编码中,并非所有的字节序列都是有效的字符串。
没有简单的方法来确定在字节串中使用什么类型的编码。
unicode 和字节之间的转换通过encode()
和decode()
函数完成。我们尝试做相反的操作,解码字节对象,如下所示。
没有简单的方法来确定在字节串中使用什么类型的编码。
因此,我们需要提供正确的编码(utf-8、utf-16 等。)到解码方法
正则表达式模式
请记住,正则表达式模式也适用于非拉丁字符。在这里,我们如何删除 US-ASCII 字符范围之外的字符?
这部分代码的结果如下图所示。
从 csv 文件中读取 UTF 8 编码的数据
下面的例子演示了如何用 Python 从 csv 文件中读取“utf-8”
编码的数据。
很简单,对吧?这完全是关于用 Python 中 Unicode 处理文本。
参考
机器学习中未标记数据的处理
构建机器学习概念
引入混合处理,并将其与主动学习和直推式和归纳式半监督学习结合起来
在专栏“构建机器学习概念”中,我试图从机器学习(ML)空间中提取概念,并将它们投射到新的、可能不寻常的框架中,以提供新的视角。该内容面向数据科学社区的人们,以及对 ML 领域感兴趣的精通技术的个人。
由作者创建。包括由 Vectra AI 和 taviphoto 通过 iStock 制作的图形。
介绍
T 他在“构建机器学习概念”的最后一部分中致力于提出一个新的框架来映射监督、自我监督、非监督和强化学习。我认为这些才是我们在 ML 中应该考虑的真正“纯粹”的学习风格。
写这篇文章的触发点是我的公司在现实世界场景中自动化人类标签任务的工作。我总是渴望将我们正在尝试做的事情与研究的行话相匹配,但从未真正对那里提出的概念感到满意。让我们详述一下。
混合处理、主动学习以及直推式和归纳式半监督学习
混合处理的概念
当我谈到人工标记任务时,我指的是人工完成 SL 问题的业务流程。这可以是对媒体公司中的图像进行内容审核(例如,在“可安全发布”和“不可安全发布”之间做出决定),通过组织路由传入的电子邮件和文档(“部门 1”、“部门 2”、…),或者从传入的 PDF 订单中提取信息(“name”、“IBAN”,…).对于其中的许多人来说,现在通常只有人工流程,这可以从自动化中受益。
理想情况下,你不要试图实现 1 比 1 的替换,而是开始使用算法将明显的情况自动化,并将剩下的工作留给人类。在我的公司 Luminovo ,我们一直在思考如何构建一个 ML 系统,当用于一步一步地自动化纯人工智能过程时,它真正实现了持续学习的承诺。我们称之为混合处理,因为我们正在使用人类-人工智能混合来实现处理数据的目标。
我们通常要么从零知识开始,要么从预先训练好的基础模型开始。一开始,我们的模型没有足够的信心来自动化任何事情,所以所有传入的数据点都由人来标记。因此,她不仅完成了任务,还以新的输入输出对的形式向模型提供了反馈,该反馈可用于重新训练。
两个数据集的故事&人在回路中
当向 ML 社区的朋友解释这个概念时,它经常被比作主动学习 (AL)。抛开大多数自动化任务的“在线性质”(相对于在正常的人工智能设置中批量消耗数据),我从来没有完全热衷于这种比较,因为人工智能的首要目标是用“尽可能少的数据”创建“尽可能好的模型”。另一方面,混合处理不关心模型的质量,至少不是它的主要目标。相反,我们的目标是给尽可能多的数据点贴上自己的标签,只把不确定的数据点发送给人类。
当试图概括这一点时,我意识到在“结构化机器学习概念”系列的最后一部分中解释的半监督学习 (SemiSL)的整个概念非常符合这些考虑。请记住,在 SemiSL 中,我们试图在训练期间将少量(通常很少)已标记的数据与大量未标记的数据结合起来。这类似于我们想要在人工智能和混合处理中实现的目标,但是,我们缺少一个重要的元素:人在回路中。对于 SemiSL,我们无法访问“oracle ”,而是被给定的带标签的数据所困。此外,这个过程不是“在线”的,这意味着时间的概念不是一个关键的驱动因素。
当研究 SemiSL 理论时,我确实找到了我一直在寻找的分裂:SemiSL 可以是直推式的,也可以是归纳式的。对于直推 SemiSL,目标是为未标记的数据推断正确的标记;对于归纳 SemiSL,我们希望推断出从 X 到 Y 的正确映射,或者换句话说:尽可能构建最佳模型。
轻量级定义
- **混合处理:**ML 模型根据人类获得的数据,按照他们正常的标记程序,不断地进行训练。随着模型的每一个改进版本,其置信阈值都被重新校准,允许随着时间的推移自动处理越来越多的数据点。
- **艾尔:**我们正试图通过不断地决定我们应该如何使用我们的“标签预算”来改善一个潜在的 ML 模型,例如,支付一名受过训练的医生来诊断/分类一些 x 射线扫描。有各种形式的人工智能,区分在给定时间我们可以访问未标记数据的哪些部分(场景)以及我们如何决定标记哪些实例(查询策略)。
- 直推 SemiSL: 我们的目标是在第一个数据集中的少量标签的帮助下,为未标记的数据集提供标签。此外,我们期望三个假设中的至少一个成立:连续性(接近的点共享一个标签)、聚类(聚集的点共享一个标签)和流形(位于低维平面上的点共享一个标签)。
- 归纳 SemiSL: 我刚刚解释的 SemiSL 的一般假设仍然成立,但我们现在试图推断数据和标签的真实输入输出关系,而不关心将标签分配给特定的、潜在的噪声数据点。因此,我们的模型不仅关心手边未标记的例子,还关心即将到来的新例子。
2x2 矩阵
2x2 矩阵,用于混合处理、AL 以及直推式和感应式半固态。由作者创建。
再一次,我提出一个简单的 2x2 矩阵,具有以下维度:
目标:处理数据还是改进模型?
处理数据
改进模型 还是我们只关心改进模型,即找到从输入到输出的真实映射?
有没有人在回路中?
是的 我们能接触到能给我们提供标签的“神谕”吗?
还是我们只剩下已经收集到的信息?
关于所有这些象限,尤其是关于 AL 及其场景和查询策略,您可以写得更多。我将把这个留给另一篇博文。
关闭
在这篇文章中,我终于找到了关于人工智能如何转化为现实世界场景的个人结论。我介绍了混合处理作为一种新的范式,我们的目标是尽可能高效地解决人类标记任务。结合已知的 AL 和直推式&感应式 SemiSL 概念,我们能够建立一个 2x2 矩阵,询问我们是否旨在改进基础模型,以及我们是否能够接触到人在回路中。
如果你有任何其他非常规的映射,对此事的想法,或者对我们在 Luminovo 的工作感兴趣,我很乐意收到你的来信。你可以在 Linkedin 上留言或联系我。
构建机器学习概念的第三部分是关于迁移学习的新观点。请随意查看。
产品直觉和数据叙事
苹果 | 谷歌 | SPOTIFY | 其他
内特·尼科尔斯在 TDS 播客
编者按:迈向数据科学播客的“攀登数据科学阶梯”系列由 Jeremie Harris、Edouard Harris 和 Russell Pollari 主持。他们一起经营一家名为sharpes minds的数据科学导师创业公司。可以听下面的播客:
如果说有一个趋势是,在进入 2020 年之前,似乎没有足够多的数据科学家关注,那就是:数据科学家正在成为产品人。
五年前,情况完全不是这样:数据科学和机器学习风靡一时,经理们对花哨的分析和过度设计的预测模型印象深刻。今天,一剂健康的现实已经到来,大多数公司都将数据科学视为达到目的的手段:它是改善真实用户和真实付费客户体验的方式,而不是一种冷静自圆其说的神奇工具。
与此同时,随着越来越多的工具不断让非数据科学家的人构建和使用预测模型变得越来越容易,数据科学家将不得不擅长新事物。这意味着两件事:产品本能和数据故事。
这就是为什么我们想与 Nate Nichols 聊天,他是一名数据科学家,后来成为叙事科学公司(Narrative Science)的产品架构副总裁,该公司致力于简化数据通信。内特也是《让你的人成为人》的合著者,这是一本关于数据故事的(免费)书。他有很多很棒的见解要分享,以下是几个重要的亮点:
- 大学不是学习如何解决产品问题的地方,因为学术研究倾向于强调工具而不是理解用例。你可能从硕士毕业时就有了预测建模的坚实基础,但是根本不知道如何决定你应该首先做什么样的。
- 数据叙事是一项至关重要的技能。你可以对你的数据进行出色的分析,但是如果你不能向你的经理解释你的结果,你就不能为公司增加价值。
- 例如,招聘经理注重讲故事,通常看重你描述自己思维过程的能力,以及用高于之前工作附加值的客观指标的数据进行论证的能力。这很重要。
- 好的讲故事能力不是任何人与生俱来的;这需要练习。写博客,在当地会议上做报告,或者在 youtube 上录制一段讲解视频——然后,寻求反馈。训练和验证不仅仅针对机器学习模型😉
- 你不能把交流和解释分开。如果你发现你很难向其他人解释你的最新项目,注意他们在哪里感到困惑:很有可能,你自己的想法中也有需要填补的漏洞。
你可以在 Twitter 这里关注内特,或者在 LinkedIn 这里关注他。
夹子
我们正在寻找能与我们的观众分享有价值的东西的客人。如果你碰巧知道谁是合适的人选,请在这里告诉我们:publication@towardsdatascience.com。
基于关联规则学习的产品布局、定价和促销策略
实体店中的产品植入在购买量中起着重要的作用
使用 Apriori 算法提供产品推荐、产品放置、定价和捆绑策略
想象一下,如果我们能够了解客户的下一次购买会是什么!想象一下,如果我们能够发现购买行为的模式,并将其用于我们的优势!未来的钥匙在历史中!
市场购物篮分析有助于零售商根据大量交易确定目录中各种产品之间的关联。这些信息可用于推动产品定价、捆绑和投放。
想象一下,你有一家超市,你想增加产品的销量。您希望根据顾客购物车中的商品或他们之前购买的商品,为顾客提供购买商品的建议。你甚至可能想推荐随产品一起购买的最受欢迎的商品。
交易数据可能是洞察的金矿
分析的第一步是收集数据。所以你在你的商店里找出了过去一年的大量交易记录。每笔交易的兴趣点是购买的物品。
有些交易可能非常罕见。例如,有多少人会在一次交易中购买面包和一把剪刀?我敢说没几个人值得麻烦。另一方面,一起购买面包和黄油的交易数量肯定是一个非常大的数字,因为人们很有可能会购买黄油和面包一起吃。因此,我们可以这样把面包和黄油联系起来:
如果一个人买面包、,那么一个人可能会买黄油。
在交易历史中可能会出现许多这样的产品组合。
然而,要使产品之间有很强的关联,这些组合必须经常被购买。为了不在罕见的组合上浪费时间,可以设置截止频率、 、f 、。算法中不考虑出现次数少于 f 的任何项目组合。这个最小频率 f 叫做 支持 。
支持=项目组合在所有交易中出现的次数/交易总数
在根据项目组合的频率过滤事务之后,我们剩下的是具有更高频率的事务。在这些交易中,如果你想在两个项目之间建立一个关联规则,比如说面包和黄油*、,你还想确定在所有面包和黄油的组合中、*至少出现了一定的次数。这个频率叫做 信心 。
置信度= i1 和 i2 在所有事务中出现的次数/i1 出现的事务数
注意:如果两个项目同时出现的置信度很低,那么任何包含这两个项目的组合的置信度也会很低。
如果面包和剪刀不是很频繁的一起买,那么直觉上剪刀、面包和鞋子也不会买的那么频繁。这是根据子集频率消除许多组合的基础。
现在,您有了一组事务,其中只有那些具有足够大的支持度和置信度的项目组合才会出现。
让我们看看这在实践中是如何工作的。让我们看看下面的 12 笔交易:
交易清单样本
从上面的列表中,我们看到蔬菜和葡萄,以及意大利面和肉丸被频繁购买(分别是 12 次中的 4 次和 12 次中的 3 次)。
让我们通过 Apriori 算法找出这样的产品关联。
首先要设置的是支撑。假设只考虑那些在交易中至少出现 3 次的项目。让我们用 S(item)来表示对一个项目的支持。
S(虾)= 4
S(杏仁)= 2
S(牛油果)= 4
S(蔬菜)= 7
S(葡萄)= 4
S(汉堡)= 4
S(肉丸)= 4
S(意大利面)= 6
这就排除了杏仁,因为杏仁的支持度只有 2。
让我们试着在意大利面和肉丸之间建立一种联系。为此我们需要树立信心。让我们把它设为 0.35。这意味着至少 35%有意大利面的交易必须有肉丸。让我们定义两个项目 C(项目 1,项目 2)的置信度。
我们知道 C(item1,item2) = S(item1,item2)/Support(item1)
C(意大利面、蔬菜)= 3/6 = 0.5
C(意大利面、汉堡)= 2/6 = 0.33
C(意大利面、牛油果)= 3/6 = 0.5
C(意大利面、葡萄)= 2/6 = 0.33
C(意大利面、肉丸)= 3/6 = 0.5
C(意大利面、虾)= 2/6 = 0.33
基于我们选择的信心,意大利面似乎与蔬菜、鳄梨和肉丸有很强的联系。
但是我们能说置信度越高,产品之间的关联就越强吗?
置信度可能是一个有偏差的度量,因为它只考虑一个组成项目的支持度。为了解释膨胀的信心,我们使用 Lift。升力是指物品组合的支撑与组合中单个物品支撑的乘积之比。
升力=支撑(i1,i2)/((支撑(i1)*支撑(i2))
很自然,项目组合的提升越高,项目之间的关联就越高。
现在让我们重新考虑意大利面与其他项目的关系。让我们将两个项目的提升表示为提升(项目 1、项目 2)。
L(意大利面、蔬菜)= 3/(76) = 0.071
L(意大利面、汉堡)= 2/(46) = 0.083
L(意大利面、牛油果)= 3/(46) = 0.125
L(意大利面、葡萄)= 2/(46) = 0.083
L(意大利面、肉丸)= 3/(46) = 0.125
L(意大利面、虾)= 2/(46)
基于 Lift,我们看到意大利面和蔬菜之间的关系并不像信心所显示的那样紧密。意大利面和鳄梨、意大利面和肉丸之间的联系最为紧密。
类似地,可以在任意数量的项目之间建立关联。
根据我们的计算,我们如何改进我们的营销工作?
- **植入式广告:**植入式广告有两种方式。放置相关产品的一种方法是将这些产品放在彼此靠近的位置,这样顾客就不需要看其他地方了。
如果你想让顾客在拿到想要的商品之前冲动购物,那么就让这两件商品在商店里尽量远离。
比如尽量保留意大利面和肉丸,让顾客穿过所有其他过道从意大利面过道走到肉丸过道。当他们经过不同的通道时,顾客可能想要购买他们以前没有计划购买的物品。 - **产品促销和定价:**从上面的练习中,我们发现意大利面与肉丸和鳄梨有着密切的联系。为了推广这种组合,可以提供意大利面和肉丸/意大利面和鳄梨组合的促销优惠。可以对相关联的商品进行捆绑定价,这样客户就会有兴趣购买产品捆绑包,而不是单个商品。
摘要
Apriori 算法用于确定在多次交易中购买的商品之间的潜在关系。用于建立项目-项目关联的三个关键指标是:
1 .支撑
2。信心
3。电梯
举例来说,已经使用了 2 项组合,但是如果它们通过了最低支持和置信水平,也可以建立更大的组合(3 项及以上)。
参考文献:
阿格拉瓦尔河和斯里坎特河(1994 年 9 月)。挖掘关联规则的快速算法。在过程中。第 20 国际。糖膏剂超大型数据库,VLDB (第 1215 卷,第 487–499 页)。
机器学习模型的生产和部署——III
为执行端到端预测而实施的架构框架。
为了建立一个不折不扣的机器学习系统,在这里我们获取数据,训练我们的模型,然后部署模型为客户服务,我们需要一个适当设计的架构。我们应该直接探索一些重要的设计架构。
我们将触及所有的结构,并详细阐述我工作的那个。但首先我想直观地解释一下这个操作。
假设总的来说,人们现在已经对模型构建过程有了一个公平的理解。我假设我们已经训练和测试了我们的模型,结果是模型(M)。这是我们将坚持的模式。
你说的模型持久性是什么意思?
模型持久性意味着将模型保存到磁盘上。
简单地说,模型持久化意味着将你的模型保存到磁盘上。
技术定义:模型持久性是保存和加载机器学习模型的能力。希望有一种方法来保持模型以供将来使用,而不必重新训练。
Pickle 和 Joblib 是您在模型持久化过程中经常会听到的术语。
您可以将您的模型称为持久 python 对象。您可以将此文件存储到硬盘或固态驱动器中。
此时,模型保存在磁盘上。下一步是部署模型。
简单来说,部署的意思是您的模型如何与公司或组织架构中的其余系统进行交互,这听起来很模糊!坚持住…
绿色的大圆圈是公司已经实施的系统架构。两个深灰色圆圈代表该架构中的对象。这些对象可以是运行不同服务的单独的盒子,其中一个特定的盒子是存储我们的模型的地方,用红色表示。
没有什么比一个例子更能让人们参与到这个主题中来了。
今天,你厌倦了那些恼人的自助餐厅谈话(他们总是关于谁在做什么,左对右和上帝!人们确实有自己的看法,坦白地说,我对几乎所有事情都不感兴趣。你回到家,坐在床边舒适的椅子上休息,几分钟后,你决定去看电影。你打开浏览器,输入网飞。当它打开你想看的电影时,你会在底部看到 5-6 部类似电影的推荐。页面除了推荐你的电影还有很多东西。
我不能使用实际的网飞页面来举例说明。但我会尽力给你足够的见解,让你开始明白这一切。
你打开浏览器,输入了网飞的地址。当网飞打开你选择的电影时,页面也有其他细节(它有一个加入和订阅,它在侧边栏上有另一个菜单和一些更多的选项。这是当你点击网站时发生的事情,网站连接到它的服务器,服务器上运行着许多服务,这些服务对页面有贡献。服务器将连接到一种服务类型的数据库,加入和订阅将通过不同类型的服务来执行,类似地,您将在底部获得的类似电影(作为推荐)将通过连接到**服务器的 ML 服务盒来执行。**所有这些服务同时运行,为您提供结果。
在上图中,你可以认为一个星形或三角形是不同的服务,在页面底部也是相似的电影,尽管系统上运行着 ML 服务。一个页面有许多部分,对于每个部分,它将调用不同的服务并获取数据。web 服务器将从各种服务中提取数据,并对其进行整理以生成页面。在我们的例子中,将有一个 m1 的这样的服务,它是推荐相似电影的服务(推荐系统)。
这个服务像其他服务一样运行在不同的机器上,它不会在实际的服务器上。它将位于运行模型“M”的系统中。服务器从盒子中调用类似的电影服务。它将向该服务发送一个请求(向它所在的框发送,考虑图中的蓝色框),该服务将使用类似的电影进行响应,以占据页面上的特定空间。这更像是面向服务的架构。
设计方法
这是一种方式,我们部署我们的模型。该模型在一个盒子上运行,我们将带有数据的请求(我们称之为特征化数据的数据,前面讨论过)推送到盒子,它将响应一个结果(可能是类似产品、电影、预测价格等的推荐)。).
对于请求,服务器;发送请求的服务器和给出输出的 ML 服务器就数据的格式达成一致(格式对流程至关重要)。
这就是所发生的事情,目的是给你直觉,我将在后面详述这些部分。
我讨论的方法是一个 Web API 方法。在这种方法中,模型被离线训练和持久化,然后被上传到一个 web 应用程序中,当客户端将关于给定电影的细节发布到 rest API 时,该应用程序可以给出类似电影的实时预测。这是一种类型的架构,它需要更多的细节,但目前重要的是理解这个想法。
一种方法是离线训练你的模型,然后作为一个请求,例如,客户将上传一个包含输入细节的电影 CSV 文件,然后等待一段时间,等待一封电子邮件或一条消息告诉他们检查网站的结果。这个应用程序将使用异步任务队列执行批量预测,这些结果将保存到一个共享数据库中,然后 web 应用程序可以访问该数据库来显示结果。
您也可以创建自己的示例,尝试使用 amazon 页面,该页面有如此多的服务,从订单详细信息按钮到产品详细信息,再到购买此产品的人也购买了这些产品,并尝试围绕它构建部署理念,我相信您能够理解。
请在评论中给出一些有价值的反馈,以便我改进。谢谢你。
生产级 R 闪亮假人:原型制作
使用假人软件包从头开始制作一个健身应用程序
本教程结束时您的仪表板|作者图片
这是一个激动人心的时代,成为一名开发者——R Shiny 正被越来越多地采用,让数据科学家制作快速、漂亮的 web 应用程序来共享数据,甚至提供面向公众的数据产品和仪表板访问。R Shiny 让非 web 开发人员快速启动并运行应用程序,但也让数据科学家和数据分析师在依赖性管理、可再现性、测试和部署责任方面成为 web 开发人员或软件工程师。随着 R Shiny 在各个领域的采用,一个全新的 production Shiny 工具已经开发出来,以帮助应对开发由数据科学家和非 web 开发人员创建和维护的健壮、可持续和可复制的 R Shiny 应用程序的挑战。事实上,我认为即使你不认为你的应用程序是真正的产品或软件,你也可以从在你的开发工作流程中使用闪亮的产品工具中获益。
在本教程中,我将介绍使用一个名为假人的新包在开发中启动并运行 R Shiny 应用程序的基础知识,该包是专门为开发生产就绪的 R Shiny 应用程序而设计的自以为是的框架。出于本教程的目的,我们的客户是我,我们将专注于构建一个举重应用程序的原型。
在本教程中,您将学习:
- 用户访谈和原型制作的基本思想
- 基本线框绘图
- 如何使用 shinipsum 包让 R 中的工作原型充满填充文本和演示图形
第 1 部分:需求收集和线框图
用户访谈
您可能想知道为什么这个部分在这里——来吧,看看代码!好吧,在我们开始在 R 中混日子之前,我们可能应该花点时间弄清楚我们要做什么!这可能是所有开发步骤中最被低估的一步:实际定义我们想要构建什么。幸运的是,假设这个应用程序的用户是我(或我们),这应该是一个非常简单的用户访谈!
核心功能
- 从 Fitbod 上传更新的导出数据(我在那里生成并跟踪我的锻炼)
- 记录我在一段时间内提升了多少重量,让我有成就感
- 跟踪我在不同锻炼中每次锻炼的总运动量
- 追踪我在不同训练中预计的 1 次重复最大值
- 追踪我每个肌肉群举起了多少
线框
在我们开始编码之前的最后一步,我保证。我们将快速(手动)勾画出我们要建造的东西,这样我们就知道我们要做什么了。如果你愿意的话,有很多很酷的交互模型工具,但是我们现在要保持简单,只是把它画出来。我在平板电脑上画出了这个,但是笔和纸也可以。
首先,让我们画出我们想要的主仪表板页面和数据上传的样子:
带有数据上传弹出框以及仪表板页面上的图表和列表的仪表板的绘图。作者照片。
我们还可以绘制另外两个选项卡,以包含在我们的用户访谈中概述的特定运动统计数据和肌肉群统计数据的内容。
(**顶部)**一个选项卡的绘图,允许选择一个练习,最大投影 1 个重复和两个图形。| ( **底部)**允许用图形和表格选择肌肉群的标签的绘图。作者照片。
第 2 部分:假人入门
创建和设置应用程序
与假人一起启动一个项目看似简单。首先,确保你已经用你的老朋友install.packages('golem')
安装了它。
安装 golem 后,你应该可以在 RStudio 菜单中进入“文件”->“新目录”->“使用 golem 打包闪亮的应用程序”。
您也可以通过在 RStudio 控制台中键入golem::create_golem("projectName")
在命令行上创建您的项目。
从这里,假人将打开大量的文件,让你去!让我们从编号为 1.1 的评论处的dev/01_start.R
开始。继续操作,在golem::fill_desc()
函数中填写您的姓名、包名等。我更喜欢提前设置我的回购,所以我将在 GitHub 上创建一个空的回购,并在这里输入 URL。
现在让我们打电话给golem::set_golem_options()
来安排这一切。我们还将保留注释“1.2-设置公共文件”中的所有内容,就像现在一样。
我们现在将运行golem::use_recommended_tests()
来为单元测试添加一个文件夹,稍后我们可以使用 testthat 来添加。测试允许您自动化您用来确保您的代码正确工作的过程。为什么应该使用单元测试?嗯,这个说的很好:
我开始使用自动化测试,因为我发现我花了太多的时间重新修复我以前已经修复过的 bug。在编写代码或修复错误时,我会执行交互式测试以确保代码正常工作。但是我从来没有一个系统可以存储这些测试,这样我就可以在需要的时候重新运行它们。我认为这是 R 程序员的普遍做法。不是你不测试你的代码,而是你不自动化你的测试。
由哈德利·韦翰和詹妮弗·布莱恩创作
现在我们运行golem::use_recommended_deps()
来添加假人推荐的依赖项。这些是您在开发过程中几乎肯定会用到的包。
我还将运行golem::use_utils_ui()
和golem::use_utils_server()
,因为我从来不会拒绝一些我以后可能需要的很好的预写函数。这些并不是绝对必要的,但是它们为一些常见的任务增加了一些功能,可能会帮到我们。
这样,我们就可以开始原型制作了!
使用 shinipsum 构建 UI 原型
还记得我们想画的画吗?好了,现在是时候看看当我们实际上试图使它闪闪发光时,它是否看起来很好!
原型是一种很好的方式,可以在你完成构建之前检查你的用户需求。当人们可以看到一个应用程序的样子并玩它时,即使它还没有最终的信息,他们也会澄清他们想要什么,因为他们意识到应用程序缺少一些东西,或者他们不喜欢或不想要他们认为必不可少的功能。
我们将尝试傀儡世界的一个有趣的新部分来做我们的原型:{shinipsum}
像往常一样,我们将开始安装它:install.packages('shinipsum')
,我们会让傀儡知道我们将使用它与usethis::use_package("shinipsum")
。
让我们开始原型制作吧!
如果我们回头看看我们的图表,我们会看到我们实际上有三个选项卡(我没有计算让我们的用户上传数据的初始弹出窗口)。
这意味着有三个模块,每个页面一个,可能是一个好的开始。
让我们使用 golem 创建我们的第一个模块!在您的 R 终端中,您可以使用 golem 的功能直接添加模块基础设施:
golem::add_module(name = 'Home')
现在让我们添加其他模块:
golem::add_module(name = 'Exercises')
golem::add_module(name = 'MuscleGroup')
酷-我们有两个模块!让我们按照新创建的模块中所说的那样做,并在主 UI 和主服务器中添加对这些模块的引用,这样应用程序就知道要调用它们。一旦你将这些块粘贴到了R/app_ui.R
和R/app_server.R
文件中的正确位置,就可以随意删除模块文件底部的注释块。
现在让我们回头看看第一页的绘图,开始制作我们的模块。
显示占位符文本、图形和表格的仪表板线框。|作者图片
嘿,导航部分看起来很重要,所以让我们先关注它。我们希望这看起来很漂亮,所以我们要拿出华丽闪亮的 UI 设计的大枪:
install.packages("shinydashboard")
install.packages("shinydashboardPlus")
usethis::use_package("shinydashboard")
usethis::use_package("shinydashboardPlus")
我们将把侧边栏放在我们的主R/app_ui.R
文件中,因为我们希望它在我们所有的页面上都可见。现在请听我说,因为这将会是一段疯狂的 UI 代码之旅。
app_ui <- function() {
tagList(
# Leave this function for adding external resources
golem_add_external_resources(), # Define this page as a dashboard page to signal we're using the dashboard page format
shinydashboardPlus::dashboardPagePlus(
header = shinydashboardPlus::dashboardHeaderPlus(
title = "Fitbod Tracking Dashboard",
enable_rightsidebar = FALSE
), # Create our navigation menu that links to each of the tabs we defined
sidebar = shinydashboard::dashboardSidebar(
shinydashboard::sidebarMenu(
# Setting id makes input$tabs give the tabName of currently-selected tab
id = "tabs",
shinydashboard::menuItem("Dashboard", tabName = "dashboard", icon = icon("dashboard")),
shinydashboard::menuItem("Muscle Group View", icon = icon("th"), tabName = "mg"),
shinydashboard::menuItem("Exercise View", icon = icon("bar-chart-o"), tabName = "ev"
))
),# Show the appropriate tab's content in the main body of our dashboard when we select it
body = shinydashboard::dashboardBody(
shinydashboard::tabItems(
shinydashboard::tabItem("dashboard", mod_Home_ui("Home_ui_1")),
shinydashboard::tabItem("mg", mod_MuscleGroup_ui("MuscleGroup_ui_1")),
shinydashboard::tabItem("ev", mod_Exercises_ui("Exercises_ui_1")
)
)
),
rightsidebar = NULL,
title = "FitBod App Monitoring Dashboard"
)
)
}
只是为了好玩,让我们也添加一些东西到我们的每个模块页面,这样我们就可以知道我们的导航是否正常工作。
在每个R/mod_TABNAME_ui.R
文件中,添加一条线来表示哪个标签显示在tagList(
之后
例如:
mod_Home_ui <- function(id){
ns <- NS(id)
tagList(
h1("Welcome HOME!")
)
}
现在让我们看看这是否可行!如果你是一个更有经验的 Shiny 开发者,你可能已经注意到我们没有在任何地方采购我们的模块,并且在我们的任何脚本上都没有“运行应用”按钮。这些部分都集成到了假人的基础设施中!那么,我们如何运行我们的应用程序呢?让我们导航到dev/run_dev.R
脚本。
哎,那个run_app()
命令好眼熟啊!因为我们在 golem 中将我们的应用构建为一个包,所以我们在自己的包之外运行run_app()
函数。让我们继续运行这个脚本吧!
假设一切正常,我们应该会看到这样的内容出现:
带有侧边栏和文本“嗨,我是肌肉群标签”的仪表板|作者照片
太棒了。让我们现在开始充实这些页面。
所以让我们使用{shinipsum}
,这样我们现在就不用担心数据了。我们将需要好的旧的{ggplot2}
,所以如果你没有安装它,请安装它,并记住在你的 R 终端使用命令usethis::use_package("ggplot2")
,这样 golem 知道当它运行我们的应用程序时加载这个包。
在我们的R/mod_Home.R
文件中,我们可以改变占位符文本,使其看起来更像我们期望看到的,并添加占位符图形和表格。
一些注意事项:
- 当你在 golem 应用程序中调用函数时,你需要确保使用
::
符号附加包。这无论如何都是一个好的实践,因为它确保了当函数名称冲突时,您使用的是正确包中的正确函数。 - 我们使用了
shinydashboard::box()
函数以最少的工作给我们提供了漂亮的格式化盒子——这是这些包的一大优点! - Shinipsum 为我们提供了自动的假数据来绘制图表,因此我们还不必担心我们的数据。
- 我们正在使用模块,所以我们需要在输出标签周围使用
ns()
,这样我们的命名空间才能正常工作。
mod_Home_ui <- function(id){
ns <- NS(id)
tagList(
fluidPage(
fluidRow(
column(width = 5,
h2("Welcome!")),
br(),br(),br()
),
fluidRow(
column(width = 10,
shinydashboard::box(
background = "blue",
h2("You lifted XYZ xx times!"),
title = "Congrats!"),
br(), br(), br(), br()
)),
fluidRow(
shinydashboard::box(
title = "Top Exercises",
width = 6,
DT::dataTableOutput(ns('data_table'))),
shinydashboard::box(
title = "Total Weight Lifted",
width = 6,
plotOutput(ns("plot"))
)
)
)
)
}mod_Home_server <- function(input, output, session){
ns <- session$ns
output$data_table <- DT::renderDT({
shinipsum::random_DT(5, 3, "numeric")
})
output$plot <- renderPlot({
shinipsum::random_ggplot(type = "line")
})
}
现在,如果您再次运行您的应用程序(记住,我们现在从dev/run_dev.R
脚本中执行此操作),它应该看起来像这样:
一个仪表板,带有一个包含占位符文本的框、一个包含随机数据的占位符表格和一个包含随机数据的占位符图形。|作者照片
那看起来好多了!是时候完成另外两个标签的原型了。记住,我们的运动和肌肉群选项卡应该是这样的(根据我们的线框):
显示占位符文本、图形和表格的“锻炼”选项卡和“肌肉群”选项卡的仪表板线框。|作者图片
幸运的是,我们可以重用仪表板页面中的大量代码。所以在R/mod_Exercises.R
我们将充实这个演示界面!
一些注意事项:
- 我们现在已经对输入框中的选项进行了硬编码,但是稍后我们会用我们的数据填充它!
- 你会注意到我们再次使用了框,以及一个闪亮的功能,为我们的用户创建一个基于他们想看什么练习的过滤点。
mod_Exercises_ui <- function(id){
ns <- NS(id)
tagList(
fluidPage(
fluidRow(
h2("Exercise Progress for "),
selectizeInput(
inputId = ns("exercises"),
label = "",
# Hard coded for now, but we'll deal with this later!
choices = c("Dumbell Bicep Curl", "Deadlift"),
selected = "Dumbell Bicep Curl",
width = '50%',
multiple = FALSE)
),
fluidRow(
column(width = 10,
shinydashboard::box(
background = "blue",
h2("Your current projected 1 rep max is x!"),
title = "Congrats!")
)),
fluidRow(
shinydashboard::box(
title = "Total Weight Per Workout",
width = 6,
plotOutput(ns("plot2"))),
shinydashboard::box(
title = "Max Weight Per Workout",
width = 6,
plotOutput(ns("plot3"))
)
)
)
)
}mod_Exercises_server <- function(input, output, session){
ns <- session$ns
output$plot2 <- renderPlot({
shinipsum::random_ggplot(type = "line")
})
output$plot3 <- renderPlot({
shinipsum::random_ggplot(type = "line")
})
}
太好了!如果您运行您的应用程序,您的“练习”选项卡现在应该是这样的:
带有占位符选择输入框、占位符文本和两个占位符图形的仪表板。|作者图片
我打赌你能猜到我们要在肌肉群选项卡上做什么!试着根据我们已经写好的东西自己做一个,但是如果你需要帮助,我的代码在下面。
在R/mod_MuscleGroup.R
中:
mod_MuscleGroup_ui <- function(id){
ns <- NS(id)
tagList(
fluidPage(
fluidRow(
h2("Muscle Group Progress for "),
selectizeInput(
inputId = ns("muscles"),
label = "",
choices = c("Back", "Hamstrings"),
selected = "Back",
width = '50%',
multiple = FALSE)
),
fluidRow(
shinydashboard::box(
title = "Max Weight Over Time",
width = 6,
plotOutput(ns("plot4"))),
shinydashboard::box(
title = "Top Exercises",
width = 6,
DT::dataTableOutput(ns('data_table2'))
)
)
)
)
}mod_MuscleGroup_server <- function(input, output, session){
ns <- session$ns
output$plot4 <- renderPlot({
shinipsum::random_ggplot(type = "line")
})
output$data_table2 <- DT::renderDT({
shinipsum::random_DT(5, 3, "numeric")
})
}
最终结果应该是这样的:
带有占位符选择输入框、占位符图形和占位符表格|按作者排序的图像的仪表板
现在我们已经有了一个功能完整的原型,可以展示给我们理论上的用户(在这里是我们)了!我们可以使用原型图更容易地根据用户的反馈进行修改,而不是处理我们所有的数据争论,当我们不必在用户看到任何东西之前让整个应用程序工作时,我们可以更快地向用户提供原型。一旦我们的用户批准了最终的线框,我们将准备好以正常的方式构建我们闪亮的应用程序的其余部分,我们都设置好了使用假人基础设施的自动化测试和基于 Docker 的部署。
如果你有任何问题,本教程的所有代码都在我的 Github 库里。
使用 Google BigQuery 和 PySpark 生产 ML 项目:预测酒店取消
数据科学家经常陷入数据科学的探索阶段,即在特定数据集上运行多个模型并优化准确性。
机器学习的探索阶段无疑是重要的。在生产过程中投入大量时间和资源之前,确保模型正确运行并具有预测能力是必要的。
然而,总是有在这个阶段花费太多时间而在生产上花费不够的风险。也就是说,整理来自多个来源的数据,并确保基础设施适合处理大型数据流。
这是一个使用梯度推进分类器预测酒店取消的 ML 管道示例。在这个例子中,为两个不同的酒店(H1 和 H2)构建并运行了两个模型。
管道
具体来说,管道设置如下:
- 从酒店取消表中选择的列从 Google BigQuery 数据库下载到带有 pythonbq 的 Jupyter 笔记本中,Python bq 是 BigQuery 的 Python 客户端。
- 使用 pyspark 初始化 Spark 会话。进行相关的数据转换是为了让 GBTClassifier 能够处理相关的数据。
- 进行 80/20 训练测试分割,以允许模型评估训练集的不可见部分的性能。
- 模型预测从 Spark 转换为 pandas 数据框架,然后导出为 CSV。然后,这些预测被读回 Jupyter 笔记本,并生成一个混淆矩阵来评估模型的准确性。
谷歌大查询
首先,H1 的相关 CSV 文件可以上传到 Google BigQuery 并存储为表格。
来源:谷歌大查询
在这种情况下,选择了模式的“自动检测”选项,并生成了表。
下面是 Google BigQuery 中显示的表格:
来源:谷歌大查询
与 PySpark 的相互作用
Spark 专为处理“大数据”而设计。虽然本例中数据集的大小仍然适合使用 Python 本身固有的模型运行,但是我们假设随着更多的数据添加到数据库中,最终将需要使用 Spark 来高效地处理这些大数据批次。此外,Spark 更适合处理不断流动和更新的数据。
Spark 会话用 pyspark 初始化,pythonbq 用于从 BigQuery 加载数据:
import pyspark
conf = pyspark.SparkConf()conf.set('spark.local.dir', 'path')
sc = pyspark.SparkContext(conf=conf)from pythonbq import pythonbqmyProject=pythonbq(
bq_key_path='json_file',
project_id='project_id'
)
以下是 Jupyter 笔记本中所选功能的表格显示:
加载相关特征和输出标签:
from pyspark.ml import Pipeline
from pyspark.ml.feature import OneHotEncoderEstimator, StringIndexer, VectorAssembler
categoricalColumns = ["Country", "MarketSegment", "ArrivalDateMonth", "DepositType", "CustomerType"]stages = []
for categoricalCol in categoricalColumns:
stringIndexer = StringIndexer(inputCol=categoricalCol, outputCol=categoricalCol + "Index")
encoder = OneHotEncoderEstimator(inputCols=[stringIndexer.getOutputCol()], outputCols=[categoricalCol + "classVec"])
stages += [stringIndexer, encoder]label_stringIdx = StringIndexer(inputCol="IsCanceled", outputCol="label")
stages += [label_stringIdx]numericCols = ["LeadTime", "ArrivalDateYear", "ArrivalDateWeekNumber", "ArrivalDateDayOfMonth", "RequiredCarParkingSpaces"]
assemblerInputs = [c + "classVec" for c in categoricalColumns] + numericCols
assembler = VectorAssembler(inputCols=assemblerInputs, outputCol="features")
stages += [assembler]
gbt 分类器
现在可以加载 gbt 分类器(或梯度增强分类器)来用相关数据进行训练。
from pyspark.ml.classification import GBTClassifier
partialPipeline = Pipeline().setStages(stages)
pipelineModel = partialPipeline.fit(dataset)
preppedDataDF = pipelineModel.transform(dataset)gbtClassifier = GBTClassifier()
trainedModel = gbtClassifier.fit(preppedDataDF)
在将数据分成 80%训练和 20%测试时,可以训练分类器。
gbtModel = gbtClassifier.fit(trainingData)
predictions = gbtModel.transform(testData)
selected = predictions.select("label", "prediction", "probability")
我们来评价一下模型。
from pyspark.ml.evaluation import BinaryClassificationEvaluator
evaluator = BinaryClassificationEvaluator(rawPredictionCol="rawPrediction")
evaluator.evaluate(predictions)
该模型返回的评估值为 0.9131。
预测现在可以转换成熊猫数据帧并导出到 CSV:
selected.toPandas().to_csv('h1predictions.csv')
再次导入预测时,这里有一个包含结果的混淆矩阵。
f1 得分的总体准确率为 84%,而召回率为 66%表明该模型正确识别了 66%取消酒店预订的客户。
对 H2 表运行相同的程序——下面是混淆矩阵结果。
f1 分数的准确率为 94%,而回忆率为 79%。
结论
在本例中,我们看到:
- 如何在 Google BigQuery 中填充表格
- 将 Jupyter 笔记本与 BigQuery 数据库进行交互
- 使用 pyspark.ml 实现梯度增强分类器
非常感谢您的时间——非常感谢您的任何想法或反馈!
这个例子的相关 GitHub 库可以在这里找到,你也可以在 michael-grogan.com找到更多我的数据科学内容。
免责声明:本文是在“原样”的基础上编写的,没有担保。本文旨在提供数据科学概念的概述,不应以任何方式解释为专业建议。
使用 Pytorch Lightning 和 Torchtext 对 Python 进行高效的自然语言处理实验
如何使用 Pytorch Lightning 和 Torchtext
Pytorch 是我主要的深度学习框架。然而,有些部分我觉得可以改进。Pytorch Lightning 已经回答了这个问题[1]。
William Falcon 展示了 Pytorch Lightning [2]中的一些核心功能。这些功能包括构建您的代码以准备数据、进行训练、验证和测试,以及使用 Tensorboard 进行日志记录。
他对 Pytorch Lightning、Pytorch Ignite、fast.ai 做了客观的比较[4]。他强调指出,Ignite 并不是每个模型都有一个标准的接口,需要更多的代码来训练模型,并不直接与 Tensorboard 集成,也不像 Lightning 那样具有额外的高性能计算。而 fast.ai 比其他两个有更高的学习曲线,用例可能与 Pytorch Lightning 和 Pytorch Ignite 不同。
在本文中,我想强调 Pytorch Lightning 提高我的工作效率的一些特性,以及如何将 Pytorch Lightning 与 Torchtext 集成。
照片由🏴·廷德尔在 Unsplash 上拍摄
为什么使用 Pytorch 闪电
减少样板文件
除非万不得已,不要再进行写作训练。您可以将您的培训定义为
from pytorch_lightning import Trainertrainer = Trainer(
gpus=1,
logger=[logger],
max_epochs=5
)
trainer.fit(model)
一个Trainer
的工作是做你的日常训练。
- **不再有写循环。**正如你所看到的,不再有通常在 pytorch 教程中看到的循环。
- **不要将你的模型转换成 gpu。**您不必担心忘记将您的型号转换为
cuda
。 - **没有定制打印对您造成的损失。**你看到
logger
那里的变量了吗?你可以使用 Tensorboard 来管理你的日志,我推荐你使用它。在本地使用之前,请执行pip install tensorboard
。
Pytorch 闪电产生的张量板样本
在这个截图中,我将logger
变量定义为
from pytorch_lightning.loggers import TensorBoardLoggerlogger = TensorBoardLogger('tb_logs', name='my_model')
Pytorch Lightning 会创建一个名为tb_logs
的日志目录,你可以参考你的 Tensorboard 的日志目录(如果你在 Jupyter notebook 之外单独运行你的 Tensorboard)。
tensorboard --logdir tb_logs/
组织代码
除了构造函数和forward
之外,你还可以定义更多的函数
configure_optimizer
。期望从torch.optim
包中返回 Pytorch 优化器。
def configure_optimizers(self):
return Adam(self.parameters(), lr=0.01)
train_step
。给定一个批次和批次号,定义我们将如何输入到模型中。
def training_step(self, batch, batch_idx):
x, y = batch.text[0].T, batch.label
y_hat = self(x)
loss = self.loss_function(y_hat, y)
return dict(
loss=loss,
log=dict(
train_loss=loss
)
)
在这个例子中,注意我用转置做了一点变换。在输入到模型中之前,可以进行各种转换,但是我建议您在这个函数之外进行大量的转换,这样会比较干净。
我还将loss_function
定义为模型的一部分,并使用交叉熵对其进行“硬编码”。如果你不想这样,你可以使用torch.functional as F
然后调用你的功能损失函数,比如F.log_softmax()
。你可以做的另一件事是让模型构造器接受损失函数作为参数。
train_dataloader
。定义希望如何加载培训数据加载器。
Pytorch Dataloader 是一个 API,可以帮助你批处理输入。不过,据我所知,Pytorch Lightning 将运行for batch_idx, batch in enumerate(train_dataloader)
(不完全是这样,但类似)。这意味着你可以自由定义任何可迭代的东西。
test_step
。给定一个批次和批号,定义我们如何将输入馈送到模型进行测试。值得注意的是,在这一步中,我们不需要输入损失函数,因为我们是在没有梯度的情况下运行的。test_dataloader
。定义您希望如何加载您的测试数据加载器test_epoch_end
。给定所有的测试输出,定义您想要对测试输出做的一些动作。如果您不想定义它,那么您可以定义,但是当您定义了test_step
和test_dataloader
之后,它会显示警告,因为这样您基本上对您的测试数据没有做任何事情。
使用 Pytorch Lightning 和 Torchtext
之前,我已经描述了我对使用 torchtext 的探索[4]。现在,我想在实验部分进一步提高我的生产力,包括培训、测试、验证、度量记录。所有这些都可以通过 Pytorch 闪电来实现。
我将采用 IMDB 情感分类数据集,它已经在 Torchtext 包中可用。
正在加载数据集
IMDB 情感分类数据集是文本分类任务,给定评论文本预测它是正面评论还是负面评论。有一个来自torch text【5】的官方简短教程,然而那个教程并没有涵盖训练部分。我将使用一些教程代码,并使用 Pytorch Lightning 将它们与培训联系起来。
该数据集包含 3 个类别:未知、阳性(标记为“阳性”)、阴性(标记为“阴性”)。因此,我们知道我们将需要定义一个可以预测 3 个类的输出。这是一个分类任务,所以我将使用交叉熵损失。
现在加载数据你可以做什么
from torchtext.data import Field
from torchtext.datasets import IMDBtext_field = Field(sequential=True, include_lengths=True, fix_length=200)
label_field = Field(sequential=False)train, test = IMDB.splits(text_field, label_field)
由于 IMDB 审查的长度不一致,使用固定长度参数将有助于填充/修剪序列数据。
您可以使用train.examples[i]
访问您的样本数据,以查看训练和测试变量中的内容。
构建词汇
预训练单词嵌入通常针对我们使用的不同数据进行训练。因此,它将使用不同的“编码”从令牌到整数,我们目前有。build_vocab
将使用预先训练的编码重新映射来自当前数据集(在本例中为 IMDB 数据集)的当前整数编码。例如,如果我们词汇表中的标记2
是eat
,但是eat
是预训练单词嵌入中的标记号15
,那么它将被自动映射到正确的标记号。
from torchtext.vocab import FastTexttext_field.build_vocab(train, vectors=FastText('simple'))
label_field.build_vocab(train)
IMDB 数据集中的标签字段将采用pos
、neg
和<unk>
的形式,因此它仍然需要构建自己的 vocab,但不嵌入单词。
拆分并生成迭代器
迭代器的工作方式有点像数据加载器,它有助于在一个时期内批处理和迭代数据。我们可以使用 BucketIterator 来帮助我们迭代特定数量的批处理,并将所有这些向量转换成一个设备,其中设备可以是cpu
或cuda
。
from torchtext.data import BucketIteratordevice = 'cuda' if torch.cuda.is_available() else 'cpu'
batch_size = 32train_iter, test_iter = BucketIterator.splits(
(train, test),
batch_size=batch_size,
device=device
)
现在我们准备定义我们的模型。
模型定义
用 Pytorch Lightning 定义模型就像 William 解释的那样简单[2]。
- 从
LightningModule
而不是 Pytorch 的模块加载。 - 定义构造函数并转发。
- 现在添加上一节提到的属性
在进行完整的训练之前,最好确保您的模型可以正确地接受传递的输入,就像这样。
sample_batch = next(iter(train_iter))
model(sample_batch.text[0].T)
让我解释一下我为什么要做这些转换。
迭代器中的每个批处理对象都有text
和label
字段。text
字段实际上是一个评论的真实单词向量和实际长度向量的元组。真实字向量的大小为固定长度 x 批量大小,而实际长度向量的大小为批量大小。为了给模型输入单词 vector,我需要:取第一个元组并旋转它,这样它将产生batch _ size x fixed _ length。
我们现在准备训练我们的模型!
from pytorch_lightning import Trainer
from pytorch_lightning.loggers import TensorBoardLoggermodel = MyModel(text_field.vocab.vectors)
logger = TensorBoardLogger('tb_logs', name='my_model')
trainer = Trainer(
gpus=1,
logger=logger,
max_epochs=3
)
trainer.fit(model)
完成了!它会自动显示进度条,这样你就不用再做 tqdm 了。
for batch_idx, batch in tqdm(enumerate(train_loader)):
经过培训,您可以通过 1 行进行测试
trainer.test()
如果你在想为什么这个测试方法只返回一个对象?那么你可能会想到 scikit-learn 的训练和测试分离。在 Pytorch 中,“测试”部分通常被定义为“验证”。所以你可能想定义
validation_step
和val_dataloader
,而不是test_*
。
结论
在我看来,使用 Pytorch lightning 和 Torchtext 确实提高了我试验 NLP 深度学习模型的生产率。我认为这个库非常吸引人的一些方面是向后兼容 Pytorch,Torchtext 友好,以及利用 Tensorboard。
向后兼容 Pytorch
如果你犹豫不决,因为你认为使用一个新的库会是一个开销,那么不要担心!你可以先安装,用LightningModule
代替nn.Module
并编写普通的 Pytorch 代码。它仍然可以工作,因为这个库不会引起任何额外的麻烦。
友好的火炬文本
与 Pytorch Lightning 一起使用 Torchtext 相当容易。这两个库都运行在 Pytorch 上,并且与本机 Pytorch 有很高的兼容性。两者都有额外的特征,这些特征并不相交,而是互补的。例如,Torchtext 具有加载数据集的简单接口,如 IMDB 或 YelpReview。然后,您可以使用 Pytorch Lightning 来训练您想要定义的任何模型,并登录到 Tensorboard 或 MLFlow。
利用 Tensorboard 的使用
使用 Tensorboard 代替手动打印你的损失和其他指标,帮助我消除了在训练循环中打印损失时不必要的错误。它还将消除在培训结束时可视化损失与时期图的需要。
你最好现在就在 google colab 中进行实验,这是链接
参考
[1] Pytorch Lightning 文档。https://py torch-lightning . readthedocs . io/en/stable/introduction _ guide . html
[2] Falcon,w .从 PyTorch 到 py torch Lightning——一个温和的介绍。https://towards data science . com/from-py torch-to-py torch-lightning-a-gentle-introduction-b 371 b 7 caaf 09
[3] Falcon,w . py torch Lightning vs py torch Ignite vs fast . ai .https://towards data science . com/py torch-Lightning-vs-py torch-Ignite-vs-fast-ai-61dc 7480 ad8a
[4] Sutiono,Arie P .用 PyTorch 和 Torchtext 进行 NLP 的深度学习。https://towardsdatascience . com/deep-learning-for-NLP-with-py torch-and-torch text-4f92d 69052 f
[5] Torchtext 数据集文档。https://pytorch.org/text/datasets.html
生产力助推器:复合估算器和管道的交互式可视化
内部 AI
Scikit-Learn 0.23 版本中的前处理步骤的可视化是生产力的助推器。
管道和估计器可视化——文章中讨论的代码的输出
根据我的经验,在现实生活中的机器学习项目中,最大的工作份额是数据预处理。使用适当的预处理数据训练模型是稍后获得准确预测的先决条件。
通常,由于连续的预处理和转换,它变得非常复杂,以至于解开它变得非常繁琐和耗时。如果您的同事已经完成了部分预处理逻辑,而您需要完成剩余的部分,这将变得更具挑战性。
Scikit-Learn 在 2020 年 5 月的 0.23 版本中引入了丰富的复合估值器和管道结构的交互式可视化。
在本文中,我将说明如何使用这个主要的新特性来改进我们对复杂的顺序预处理步骤的理解,并在出现任何问题时指出错误的步骤。
在本文中,我们将使用 Seaborn 包中著名的“Titanic”数据集。现实世界中大多数收集的数据都有缺失值。这里,我们将使用 SimpleImputer,KNNImputer 来填充样本 Titanic 数据集中缺失的值。我们需要 ColumnTransformer 对不同的列执行一组不同的转换。
**import seaborn as sns
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer ,KNNImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.decomposition import PCA
from sklearn.ensemble import RandomForestClassifier**
首先,我们将下载样本 titanic 数据集,并从完整的可用要素集中选择一些要素作为自变量。
如下面的代码所示,大写的“X”通常用于表示自变量,小写的“y”表示因变量。
**TitanicDataset=sns.load_dataset("titanic")****X=TitanicDataset[["sex","age","fare","embarked","who","pclass",
"sibsp"]].copy()
y=TitanicDataset[["survived"]].copy()**
因为特性“fare”没有任何记录的空白值,所以我们不需要估算器。在下面的代码中,根据要应用的一组预处理和变换对功能进行了分组。
**numeric_independent_variables1= ['fare']
numeric_independent_variables2= [ 'age', 'pclass','sibsp']****categorical_independent_variables=["who","embarked","sex"]**
我们为三组特征定义了三种不同的管线。第一个管道只涉及缩放,而在第二个管道中依次提到输入和缩放。对于分类特征,使用最频繁策略填充缺失值,然后使用 OneHotEncoder 将分类值转换为数值。
**numeric_pipeline1=Pipeline([('scaler', StandardScaler())])****numeric_pipeline2=Pipeline([('imputer', KNNImputer(n_neighbors=7)),('scaler', StandardScaler())])****categorical_pipeline=Pipeline([('imputer',SimpleImputer(strategy='most_frequent')),('onehot', OneHotEncoder(handle_unknown='error'))])**
我们将使用 column transformer,因为我们将对不同的列组使用一组不同的预处理和转换。
**consolidated_pipeline= ColumnTransformer([('num1', numeric_pipeline1, numeric_independent_variables1),('num2', numeric_pipeline2, numeric_independent_variables2),('cat', categorical_pipeline, categorical_independent_variables)])**
在前面的步骤中,在一个列变压器中,提到了三条管线。
最后,我们有一个嵌套的管道,将更早的“合并 _ 管道**”、“** pca **”、**和“分类器”放入新的管道“clf”。
**clf = Pipeline([('consolidated_pipeline', consolidated_pipeline),('pca',PCA(n_components=5)),('classifier',RandomForestClassifier(max_depth=5))])**
解释转换的顺序已经变得相当复杂,即使与实际项目相比,预处理和转换顺序相对简单
在 0.19 版本中,Scikit-Learn 引入了 set_config 包。在 2020 年 5 月发布的 0.23 版本中,添加了“显示”参数,以实现复合估算器和管道的交互式可视化。
**from sklearn import set_config
from sklearn.utils import estimator_html_repr****set_config(display='diagram')
diaplay(clf) # for** **Jupyter Notebook and Google Collab**
管道和估计器可视化——文章中讨论的代码的输出
如果你正在运行 Jupyter 笔记本和 Google Collab 中的代码,那么上面的代码将带来管道的结构和其他复合估算器。点击各个方框显示参数。
如果你正在使用 IDLE,那么你可以用下面的代码在你的本地机器上下载完整的结构。由于我们没有在下面的代码中提供任何文件夹路径,因此 HTML 文件将保存在与主 python 程序相同的位置。
**with open('estimator.html', 'w') as f:
f.write(estimator_html_repr(clf)) # for saving the HTML file**
我们不需要浏览所有的预处理和转换编码,只需看一眼,就可以通过这种树形结构的可视化来了解管道和转换序列。对于冗长复杂的嵌套管道和预处理步骤,它有助于我们快速确定问题区域,是真正的生产力助推器。
用 PyTorch 编写一个简单的图形网
几何机器学习简介
费迪南·斯托尔在 Unsplash 拍摄的照片
介绍
机器学习中一个非常新且快速发展的领域是图神经网络。顾名思义,它们能够学习任何网络中节点之间的关系。这在很多领域都很有用,例如预测分子结构的有用性,了解社交网络中的人,或者构建购物推荐系统。在这篇短文中,我将解释图网背后的理论,并用 PyTorch 实现一个简单的理论。
概观
在深入图网之前,让我们首先回答一个重要的问题:图究竟是什么?基本上,图是由两个元素组成的结构:
- 节点:通常具有一组特定属性的实体
- 边:连接两个节点。边可以是单向的,也可以是双向的
图形数据和我们在其他机器学习任务中遇到的“正常”数据之间的主要区别在于,我们可以从两个来源获得知识:
- 就像在其他机器学习应用中一样,每个节点都有一组特征。例如,当我们看一个社交网络时,每个节点都可以是具有特定年龄、性别、兴趣、政治观点等的人。
- 信息也编码在图的结构中。通过观察一个人的朋友,通常可以对这个人有所了解。
那么,所有这些是如何组成一个神经网络的呢?让我们继续我们的社交圈的例子。我们可以首先只看一个人本身。然后我们可以收集一个人的朋友的信息。然后是朋友的朋友的信息等等。这基本上是一个图形网络的想法:我们聚集邻居的信息,邻居的邻居,等等。一个节点。让我们看一个简单的例子,让事情更清楚。下图显示了一个小型朋友组,其中两个节点之间的边表示这两个人是彼此的朋友。
图 1:一个简单的图表
我们现在将关注人物 a。首先,我们只看一下深度为 0 的朋友圈,例如,只有人物本身
图 2:深度为 0 的朋友圈
那不太有意思。我们只能从这个人的特征来推断。现在看看深度 1(图 3)。
图 3:深度为 1 的朋友圈
现在我们还可以分析朋友们的特征。最后,深度为 2 的网(图 4):
图 4:深度 2 的朋友圈
哇,最后一张图看起来已经很像神经网络了!这就是我们在这些神秘的灰色盒子中所做的事情:我们以某种方式聚集相邻节点的所有特征,将它们乘以权重,并应用激活函数。注意:我们称聚集的特性为嵌入
让我们仔细看看这些盒子里发生了什么。看看下面的两个等式(图 5)。
图 5:图形网络的基本方程
我们定义没有前趋的节点在第 0 层。这些节点的嵌入只是它们的特征。为了计算层 k 的嵌入,我们对层 k-1 的平均嵌入进行加权,并将其放入激活函数中。注意这里的两件重要事情:首先,所有相邻节点的权重是相同的,它们没有单独的权重。第二,当我们计算一个节点 v 的嵌入时,我们也想包括这个节点的特征,所以我们给每个节点添加自循环。这在直觉上也是有意义的:当描述一个节点的特征时,邻居确实扮演了一个重要的角色,但是节点本身也很重要。
到目前为止,我们已经了解了普通图网络是如何工作的。在我们开始实现之前,我想介绍一个轻微的修改,它已经显示出经常优于正常的图网。这种邻域聚合被称为图卷积网络 (GCN,看这里有很好的介绍)。有两个主要区别(图 6):
- 每层只有一组权重,所以 W 和 B 不再不同。因此,节点本身的特征乘以与其所有邻居相同的权重。
- 所有节点的归一化因子并不相同,而是取决于它们各自的邻居数量。
图 6:差分正态和 GCN 邻域聚合
履行
好在 PyTorch 已经有了一个惊人的几何深度学习库,它叫 PyTorch 几何。务必仔细通读安装说明,因为我在这里搞砸了。这里的陷阱是 PyTorch 几何需要不同版本的库,这取决于您是否有 GPU。
首先,我们要定义我们的 GCN 层(清单 1)。
清单 1: GCN 层
让我们一行一行地看一下:
add_self_loops 函数(清单 2)是 PyTorch Geometric 提供的一个方便的函数。如上所述,在每一层中,我们都希望聚合所有的相邻节点以及节点本身。为了确保包含节点本身,我们在这里添加了自循环。
清单 2:添加自循环
接下来我们要做的是用我们的权重乘以嵌入值(清单 3)。
清单 3:乘以权重
最后,我们计算归一化因子(清单 4)。
清单 4:计算规范化
重要:不要惊讶我们这里没有激活功能,我们会在网本身添加。
接下来我们可以使用我们的层定义创建一个图形网(清单 5)。这里没有太多特别需要注意的地方。我们创建了一个香草火炬网使用我们的 GCN 层。注意:从数据中我们可以得到节点(x)和它们之间的边(edge_index)。
清单 5:整个图形网
当然,我们想测试我们的网络在一些真实数据上的表现。上面实现的网络是一个非常简单的网络,所以它在大数据集上表现不好。一个不错的选择是 21 世纪初收集的 Cora 数据集。这里我们有来自七个不同领域的机器学习论文,并希望对哪篇论文属于哪篇进行分类。每篇论文的特点是经常出现的单词。两个节点之间的边表示一篇论文引用了另一篇论文。通过查看数据集(图 7 ),我们已经可以看到同一区域的论文形成了一个集群。
图 7: Cora 数据集可视化
在这里,我将省略我们为了训练模型而需要的常见 PyTorch 样板代码。完整的代码可以在我的 GitHub(链接)中找到。仅仅几个时期之后,我们就获得了 100%的训练准确率和大约 80%的验证准确率。
图 8:简单图形网络的性能
结论
这是我第一次涉足图形神经网络领域,总体来说是一次非常有趣的经历。图网的想法是几年前的事了,所以直到今天,就像在快速发展的机器学习世界的其他领域一样,无数的修改和改进已经出现了。所以有很多要发现的!
全部代码都在我的 GitHub 里。
来源
[1] PyTorch 几何文档https://py torch-Geometric . readthedocs . io/en/latest/index . html
[2]斯坦福教程http://snap . Stanford . edu/proj/embeddings-www/files/nrl tutorial-part 2-gnns . pdf
像 1970 年一样编程!
有点回到人工智能过去的样子
洛伦佐·埃雷拉在 Unsplash 上的照片
机器学习现在风靡一时!CNN、GANs 和 LSTMs 是所有酷孩子现在都在做的事情。很多人忘记了人工智能!= Machnine learning,在 2010 年深度学习热潮之前,人工智能已经存在了很长时间。我想带你回去,用一个简单的例子来说明过去的人工智能方法。
地图着色
“地图着色”是制图学中一个著名的玩具问题,我们希望以两个相邻国家总是有不同颜色的方式给地图着色(图 1)。
图 1:解决地图着色问题
为了便于说明,我们将在下面的部分中尝试给澳大利亚的州着色(因为只有八个州)。
有趣的是,在很长一段时间里,人们“知道”解决这个问题至少需要四种颜色。但是直到 90 年代末,还没有一个关于 T4 的数学证明。
约束满足问题
地图着色问题属于一类特殊的问题,简称为“约束满足问题”。这些类型的问题由三个不同的部分组成:
- 变量:我们要查找其值的占位符。在我们的案例中,这些是澳大利亚的州和地区:新南威尔士州、昆士兰州、维多利亚州、西澳大利亚州、南澳大利亚州、北部地区、澳大利亚首都直辖区和塔斯马尼亚州
- 域:这些是变量的可能值。在这种情况下,所有变量的定义域都是相同的。每种状态都可以用红、绿、蓝、黄四种颜色中的一种来着色。
- 约束:变量不能违反这些约束。例如,维多利亚和新南威尔士的颜色必须不同,因为这是两个相邻的州。
一般来说,解决 CSP 有两种不同的策略:
- 推理
- 搜索
重要的是,CSP 通常只能通过推理部分解决,因此需要搜索。简而言之,如果我们不需要进行某种随机猜测来寻找答案,那么 CSP 就是完全可以通过推理来求解的。一个典型的例子是数独游戏。我们有自己的变量(空字段)、域(1 到 9 之间的数字)和几个不能违反的约束(在一行、一列或一个正方形中不能有相同的数字)。在这里,我们不必随机选择一些数字,但我们可以通过以正确的顺序应用约束来解决整个难题。不幸的是,对于我们的地图着色问题,我们没有那么幸运:为了找到一个合适的解决方案,我们不可避免地要做一些猜测。
通常的方法:回溯
解决类似 CSP 的常见方法是使用回溯算法。这是用 Python 实现的算法:
回溯算法
我们现在将逐行检查代码,以确保我们理解这里发生了什么:
如上所述,我们的 CSP 由变量、域值和约束组成。重要的是要注意,如果可能的话,约束通常被转换成二元约束,以使事情变得更容易。二元约束描述了两个变量之间的关系。在我们的 Python 实现中,它们的形式是[(‘NSW ‘,’ V ‘),(’ NSW ‘,’ Q ‘),(’ NSW ‘,’ SA ‘),…,(’ T ‘,’ V’)]。
如果我们有和变量一样多的赋值,那就意味着我们已经给每个变量赋值了,从而解决了问题!
我们现在必须选择一个仍然未赋值的变量,我们现在想找到它的值。如何选择这个值将在下面进一步讨论。
在选择了一个未赋值的变量后,我们还必须选择一个顺序来测试这个变量的值。
如果我们为变量选择的值与我们的二元约束一致,我们就把它添加到我们所有赋值的列表中。现在真正酷的部分是:我们再次调用回溯函数,所以这是一个递归函数。我们找到了一个变量的有效赋值,所以现在是时候为下一个变量找到一个值了。
可能发生的情况是,递归调用的结果是‘None’。这意味着我们赋给变量的值在这个时候是局部一致的,但是不可能用这个值找到一个整体一致的解。所以我们把这个值从赋值列表中去掉了。如果我们不能找到一个单一的一致的解决方案,我们返回 None 给上面的递归函数。如果所有的递归调用都没有返回 None,这意味着问题是不可解决的。
哦,这个理论说够了。让我们看看这个算法如何执行,如果我们让它运行在我们的地图着色问题:
图 2:天真的回溯
嗯…我们的算法似乎没有任何进展。剧透:它最终会找到一个解决方案,但这需要很长时间,这在上面的 gif 中没有显示。这是为什么呢?因为我们仍然没有回答上面的一个重要问题:我们如何选择下一个变量来赋值?在上图中,算法只是随机选择一个未赋值的值。显然这不是最好的方法。要选择一个变量,我们应该选择一个更好的启发式。我们实现了最小剩余值试探法或者 MRV 试探法。这一点是不言自明的:我们选择的下一个变量总是剩下最少有效值的变量。这在直觉上也是有道理的。例如,如果我们只能将新南威尔士州涂成红色,但我们仍然可以将西澳大利亚州涂成红、绿和蓝色,那么我们应该首先将新南威尔士州涂成红色,因为如果我们将另一个州涂成红色,可能就不会再有任何有效的颜色留给新南威尔士州了。所以让我们用这个启发法再试一次:
图 3:MRV 的原路返回
哇,这个好用多了!
比较随机选择和 MRV 启发式(图 3 ),我们可以看到后者通常更省时。
图 4: MRV(左)与随机(右)选择下一个变量
但是说实话,给澳大利亚涂色并不有趣,因为澳大利亚只有 8 块领土。所以,为了好玩,让我们试着给德国涂上颜色,这个国家有两倍多的州:
图 5:给德国上色
这个也很管用!
捷径:序言
因此,到目前为止,整个过程都相当繁琐:我们需要编写所有这些回溯代码(递归函数有时会很棘手!)甚至想出一个好的启发式。没有更好的解决办法吗?介绍:序言。
很可能,作为一个普通的程序员(就像我一样),你已经接触过相当多的编程语言:Java、Python、C、C#、JavaScript 等等。它们可能完全不同,但它们都属于同一类编程语言:命令式编程。然而,Prolog 属于声明性编程语言,或者更确切地说,属于逻辑编程语言。那么有什么区别呢?在“普通”编程语言中,你指定事情应该如何完成。在 Prolog 中,你指定应该做什么。看看下面的例子:
简单的序言示例
Prolog 中最重要的两个构造是事实和规则。在节目的开始,我们陈述了一些事实,例如,亨利是男性,玛丽是迈克尔的父母。再往下我们有一些规则。例如,我们声明,如果 Y 是男性,Y 是 X 的父,重要的是:所有变量都必须以大写字母开头。小写名称是固定的常数。
当我们进入 Prolog 控制台时,我们可以问我们的 Prolog 程序一些问题。我们可以找出迈克尔的母亲是谁:
?- mother(michael, X).
X = mary.
或者谁是迈克尔的祖父:
?- grandfather(michael, X).
X = henry ;
现在让我们写一个程序给澳大利亚上色:
这真是直截了当!首先,我们定义哪些状态应该用不同的颜色。Diffx 只是一个帮助函数,它帮助我们定义如果颜色 A 不同于 B,那么 B 也不同于 A。最后,我们只是声明所有的颜色都彼此不同(显然)。就是这样!15 行代码,我们只需要陈述规则和事实,不需要算法。
让我们加载这个程序,要求变量赋值:
?- map_coloring(WA, NT, SA, NSW, V, Q, T, ACT).
WA = NSW, NSW = T, T = blue,
NT = V, V = ACT, ACT = red,
SA = green,
Q = yellow
将这些值放入地图如下所示:
图 6:由 Prolog 程序确定的颜色
的确,我们得到了一个有效的解!
结论
当我通常处理人工智能时,它必须用神经网络做一些事情,所以对我来说,看看几十年前人们对“人工智能”这个术语的理解是非常有趣的。尤其是用 Prolog 编程对我来说非常独特。解决 CSP 和类似的问题显然是非常容易的。我对这种语言的主要问题是,我从来不知道到底发生了什么。我只是陈述一些事实和规则,但从不明确告诉程序该做什么。因此,如果任务失败,跟踪错误和调试问题几乎是不可能的。
掌握正则表达式 1 的唯一指南
清晰、简明、循序渐进的指南
了解语言类比
照片由 Fotis Fotopoulos 在 Unsplash 上拍摄
正则表达式(Regex)是最强大、最灵活、最有效的文本处理方法之一。Regex 有自己的术语、条件和语法;从某种意义上说,它是一种迷你编程语言。Regex 可用于添加、删除、隔离和操作所有类型的文本和数据。它可以用作简单的文本编辑器命令,例如搜索和替换,或者作为它自己强大的文本处理语言。正因为如此,Regex 在今天的技术中有如此多的应用,例如:用网络爬虫提取有用的信息、数据抓取和网络抓取、数据争论和机器学习——即自然语言处理和语音识别。
Regex 不是特定于编程语言的应用程序;事实上,它可以用在今天所有的编程语言中。编程语言支持正则表达式的使用,但是所有的魔力和力量都来自正则表达式本身。
使用正则表达式可以为程序员节省宝贵的时间,这些时间可能会浪费在平凡的任务上。任务,如在文件夹中查找电子邮件,从一堆文本文件中删除重复内容,分析特定语言的语法,突出显示文件中的某些上下文,等等。对于那些以前从未使用过 Regex 的人来说,这听起来很神奇,但也很吓人!第一次阅读正则表达式可能——不,可能,肯定——会感到困惑和复杂。我是说,看看这个例子:
我向您保证,在本文结束时,您将很快理解您遇到的任何正则表达式,包括上面的这个。
然而,第一次看到一门新的语言总是令人困惑。然而,当你开始学习形成语言的小块时,它看起来就不再复杂或令人困惑了。
所以,让我们开始破译正则表达式…
正则表达式语言类比
完整的正则表达式通常由两种基本类型的字符组成:元字符和文字。元字符是赋予正则表达式权力的特殊字符,而文字是所有其他标准文本字符。Regex 与文件名模式的不同之处在于,文件名模式为有限的应用程序提供了有限的选项。相比之下,Regex 提供了丰富的元字符,允许更高级的应用程序。
作者使用 Canva
考虑元字符和文字的一种方式是,因为 Regex 是它自己的语言,我们可以说文字是该语言的单词,而元字符是它的语法。单词和语法可以在一套特定的规则下结合在一起,形成无数的表达式,能够表达你能想到的任何可能的模式。
你意识到正则表达式的力量了吗?
没有吗?只要继续读下去…
首先,我们将涵盖正则表达式的基本概念,然后我们将举一些例子,我们将看到如何构造一个正则表达式,以及我们如何使用 Python 来提取匹配。
元字符
元字符有三种基本类型,每一种都用来表示我们正在搜索的模式的一个方面。这三种类型是元字符类、量词和位置元字符。
元字符类
这些类型的元字符用于匹配单个字符,它们都以\开头,以区别于文字。下面是六种可能的元字符类的表格:
量词
这些类型的元字符用于指示我们试图匹配的模式中某个字符出现的次数。假设我们希望匹配“鞠波”和“杰西”,我们将使用其中一个量词来表示这两个选项都是可接受的。量词有四种类型:
位置元字符
位置元字符用于指示我们正在寻找的字符的位置。是在正文的开头,行尾,还是一个词?为了实现这一点,我们使用位置元字符。
超级演员
这只是我对他们的称呼——绝对不是正式的名字😄—这些是一些额外的元字符,用于连接其他元字符和文字。
文字
文字是所有不是元字符的单词和字符。例如,“从”,“到”,“你好:”所有这些都是文字。如果我想匹配一个元字符,例如,我想匹配*
或^
字符,我应该怎么做呢?
在这种情况下,我们使用转义字符来正则表达式,以明确表示我们想要匹配该字符。所以我们输入\^
或\*
,而不仅仅是^
和*
。
Python 中的正则表达式
要在 Python 中使用 Regex,我们需要使用一个名为***re***
的库。这个库是 Python 内置库的一部分,这意味着您不需要为了使用它而安装它。你只需导入它并得到匹配。这个库包含许多函数,允许我们有效地使用 Regex。在本文中,我们将讨论基本的五个功能:*compile*
、*search*
、*match*
、*findall*
和*sub*
。
编制
正则表达式基本上是我们定义并要求代码寻找的模式。在 Python 中,这些表达式是作为字符串或原始字符串的句柄。普通字符串和原始字符串之间的区别在于,在原始字符串中,转义字符不被处理,即它们将按原样打印。例如:
usual_str = "Hello\nWorld!" #This will print Hello and World! in different linesraw_str = r'Hello\nWorld!' #Will print the string as it is Hello\nWorld!
在 Python 中,可以使用字符串来表示表达式,也可以使用compile
函数将正则表达式模式计算成正则表达式对象。如果您计划在代码中多次使用相同的模式,最好将它作为编译对象;因为将模式存储为正则表达式对象以便重用比将其保存为字符串更有效。
比赛
我们可以使用match
函数在给定的字符串中搜索模式。如果搜索成功,该方法将返回一个 match 对象。如果不是,则返回None
。
搜索
search
函数在扫描字符串时寻找给定模式的第一次出现。如果找到匹配,将作为 match 对象返回,否则返回None
。
**search()**
VS **match()**
match
函数只在字符串的开头检查匹配,而search
函数在字符串的任何位置检查匹配。
芬达尔
findall
函数搜索一个字符串,找到所有可能的匹配,并将它们作为一个字符串列表返回。每个返回的字符串代表一个匹配。
潜水艇
sub
是替代功能。它接受一个原始字符串和一个模式,并返回通过用替换 repl 替换该字符串中最左边的非重叠模式获得的字符串。如果找不到模式,则返回字符串,不做任何更改。
subn
类似于sub
。但是,它返回一个包含新字符串值和对原始字符串执行的替换次数的元组。
注意所有这些方法都有一个额外的属性叫做flag
?
该属性用于微调模式的搜索和匹配,这些标志是:
- IGNORECASE or (I): 允许不区分大小写的匹配。
- DOTALL or (S): 允许。匹配任何字符,包括换行符。
- 多行 or (M): 允许插入符号(^)和美元($)元字符匹配换行符。
- VERBOSE or (X): 允许您在表达式中写入空白和注释,使其更具可读性和易于理解。
好了,这已经很多了,让我们举一些例子来帮助我们阐明不同元字符的用法。
我们将从小处着手,然后逐步构建更复杂的示例。😉
例子一
创建一个正则表达式,匹配以大写字母开头的任意长度的单词。例如,在句子中:
侧栏包括备忘单、完整参考和帮助。您还可以保存与社区的共享,并在我的模式中查看您创建或喜爱的模式。
我们希望匹配所有以大写字母开头的单词。
步骤:
- 匹配单词中的第一个字符(在[A-Z]大写字母中)。
- 匹配下列任意数量的字母。
匹配模式的 Python 代码:
执行这段代码将打印[‘The’, ‘Cheatsheet’, ‘Reference’, ‘Help’, ‘You’, ‘Share’, ‘Community’, ‘My’, ‘Patterns’]
例子二
创建一个正则表达式来匹配 xxxx-xxxx-xxx 格式的电话号码。例如,在这句话中:
昨天在办公室聚会上,我遇到了东海岸分公司的经理,她的电话号码是 202-555-0180。我还和招聘人员交换了我的电话号码 202-555-0195。
我们将匹配202–555–0180 和 202–555–0195。
步骤:
- 匹配 4 个数字,后跟一个连字符。
- 重复步骤 1。
- 匹配三位数。
匹配模式的 Python 代码:
执行代码打印[‘202–555–0180’, ‘202–555–0195’]
例子三
让我们加大难度吧!
我们想创建一个正则表达式来匹配 DD 格式的任何日期。年月日或年月日或年月日。此外,我们希望年份只在 19s 或 20s 之间。
Python 3.0 于 2008 年 3 月 12 日发布。这是对该语言的一次重大修改,它并不完全向后兼容。它的许多主要特性都被移植到了 Python 2.6。以及分别于 2008 年 10 月 3 日和 2010 年 7 月 3 日发布的 2.7 版本。
我们希望匹配该句子中的所有三个日期。
步骤:
- 匹配天。我们可以将日正则表达式分为三部分。0[1–9],表示从 01 到 09 的日期。接下来,我们有【12】【0–9】;这个表示 1 或 2,后面跟一个 0~9 之间的数。最后,3【01】,这是针对 3 后面跟着 bt 0 或者 1。所以,30 或者 31。
- 匹配分隔符()。|-|/).这符合-或/或。注意,在点之前我们添加了一个\来告诉 Python 我们想要匹配一个点,我们不是指点元字符。
- 匹配月份。月份可以分为两部分:小于 10 的月份和小于 10、11 和 12 的月份。第一部分可以用**0[1–9],**匹配,第二部分是 1[012] 。
- 最后,我们需要匹配年份。对于年份,我们希望它以 19 或 20 开始,然后后面跟着另外两个数字。
匹配模式的 Python 代码:
执行代码打印[‘03–12–2008’, ‘03.10.2008’, ‘03/07/2010’]
唷…
那很有趣——我希望如此!。
Regex 是一个很大的话题,我们可以花很多时间来讨论它,这就是为什么我决定把这篇文章分成两篇。在这一篇中,我介绍了基础知识,在下一篇中——下周开始——我将进入更高级的形式,我们将讨论如何在 Python 中创建高效的正则表达式以及更多的re
方法…
参考和工具
[1] Tonkin,e .,& Tourte,G. J. L. (2007 年)。掌握正则表达式。阿里阿德涅, 53 。
[2]练习正则表达式的一个有用工具是 regexr.com。
给量子计算机编程
奇点研究
量子逻辑门软件
一个普遍的误解是,量子计算机还没有为应用做好准备,这项技术还需要很多年才能变得有用。在这篇文章中,我们将看看量子计算机编程的一些基本原则,并解决这个误解。我们将关注免费的开源软件,如 IBM 的 QISKit ,以及量子机器学习软件 PennyLane 。我们还将解释如何在 IBM 云中的实际量子计算机上运行你的程序。在后续文章中,我们将讨论机器学习中的一些应用,这些应用目前可供任何有一点好奇心的人使用。
什么是量子计算机?
首先,让我们谈一谈量子计算,以及你可以从这项技术中期待什么。你可以在手机、笔记本电脑或平板电脑中找到的当前计算机芯片架构是由硅制成的。最常见的技术之一是使用一种特殊的基于光的光刻技术在硅片上蚀刻出微小的图案。这些微小的图案使我们能够制造出硅芯片,以可控的方式在芯片中传输电子(电流)。目前,我们已经达到了这些微小图案可以有多小的物理极限。它们可以有效地大量制造,具有纳米级的精度,典型的结构大约为 10 纳米,直径在 20 到 50 个原子之间。
更精确的技术已经存在,可以操纵单个原子,我们目前可以创造出比你通常在电脑或电话中看到的还要小的结构。这种制造过程有点慢,因此大规模生产这些更小、原子级精确的芯片有点困难。在构造具有如此小特征的计算机芯片时,我们遇到的一个困难是电子和原子的量子行为。电子有一种叫做波粒二象性的东西。这意味着,在某些情况下,电子的行为像波而不是粒子,因此当蚀刻图案太小时,将它限制在硅片上的微小蚀刻图案变得更加困难。电子“扩散”并发生电子泄漏,导致电流流经硅片中的这些微小通道时出现问题。这种泄漏意味着芯片不能按预期运行,电子的波动行为成为一个问题。这通常被称为“摩尔定律的死亡”,代表着过去几十年来我们所期待的计算机性能增长的停止。如果你押注于一个建立在持续不断增长的假设之上的市场,这将是一个大问题,因为你能制造的电脑芯片有多小多高效,实际上是有物理限制的。
量子计算旨在将量子力学行为的这一“问题”作为一种计算优势,通过使用它以一种与我们手机和笔记本电脑中常见的二进制 1 和 0 完全不同的方式处理信息。一种有用的方式认为量子计算机是一个专用集成电路。不完全是这样,但这是个不错的类比。可以把它想象成一种特殊的计算机芯片,设计用来执行特定种类的计算,比标准的硅芯片更有效。我们来看看 QISKit 中的基本计算单位是如何表示的。
QISKit 中的量子比特态
首先,你需要下载一个免费分发版的 Anacond,这样你就可以使用 Jupyter Lab 了。下载 Anaconda 之后,打开 Anaconda navigator 并打开 Jupyter Lab 的一个实例。如果你想从 Github 下载笔记本,你可以在这里找到。如果你想看活页夹上的互动版本,你可以在这里找到。要安装 QISKit,只需使用 Jupyter 笔记本或 Jupyter Lab 中的 pip 即可。
接下来,您需要导入 qiskit 和 matplotlib。
现在,如果您想在 Bloch 球体上绘制“自旋”状态,您可以键入以下命令。
我们可以用下面的命令画出量子位的“自旋下降”状态。
总的来说,量子位状态不再像经典的二进制信息位那样局限于简单的 0 或 1。量子位可以有无限多种状态。每个状态被表示为布洛赫球面上的一个点。自旋向上对应于状态 0,自旋向下对应于状态 1,但是量子位也可以是这两种状态的组合。布洛赫球上的每一个点,就像地球表面的坐标一样,代表一个独特的量子位元状态。一个量子位可以处于无限多种不同状态的这种能力,与量子物理中的“叠加”概念有关。例如,布洛赫球面上的以下状态是状态 0 和状态 1 的均匀混合,因此它是这两个状态的叠加。
这个“右旋”位置被表示为“叠加”,
或者 0 状态和 1 状态的“线性组合”。如果你不懂线性代数参考,没关系。现在,如果我们想对自旋向上状态(或状态 0)的单个量子位进行操作,并将其翻转到自旋向下状态(或状态 1),我们可以使用非门。非门或“泡利 X 门”是一个量子逻辑门。量子逻辑门在概念上类似于经典逻辑门,但又不完全相同。它们对量子比特进行操作,就像经典逻辑门对比特进行操作一样,但是它们总是可逆的,并且用(酉)矩阵乘法来表示。我们可以在 QISKit 中创建一个量子电路,如下所示:
现在,如果我们想使用非门对单个量子位进行操作,我们可以在 QISKit 中使用下面的代码来完成。
这向我们表明,我们已经翻转了量子位状态,使其自旋向下。这是量子算法背后的基本思想。在下一篇文章中,我们将看看这些量子逻辑门是如何在实际硬件上使用超导量子位实现的。这也可以用 IBM 软件来完成,相当于对应用于量子计算机芯片的微波脉冲进行编程。如果你想看一些介绍量子算法背后的数学的教程,可以看看我的 Github 知识库,里面有用 Python 实现的量子计算背后的数学。如果你有问题或评论,或者想讨论量子计算及其应用,请随时联系。
算法中的编程公平性
理解和解决监督学习中的公平问题。
“做好事容易,难的是做公正。” ― 维克多雨果
“我们需要捍卫那些我们从未谋面、也永远不会谋面的人的利益。” ― 杰弗里·萨克斯
**注:**本文旨在让普通读者尝试并阐明机器学习算法中不公平性的复杂本质。因此,我试图用简单易懂的方式解释概念,尽量少用数学,希望每个人都能从阅读中有所收获。
有监督的机器学习算法天生具有歧视性。它们是歧视性的,因为它们使用嵌入在数据特征中的信息将实例分成不同的类别——事实上,这是它们生活中的指定目的。这反映在这些算法的名称中,这些算法通常被称为判别算法(将数据分成类别),与生成算法(从给定类别生成数据)相反。当我们使用监督机器学习时,这种“区分”被用来帮助我们将数据分类到数据分布中的不同类别,如下图所示。
判别式与生成式算法的图解。请注意,生成算法从限制于特定类别的概率分布(例如,蓝色分布)中提取数据,而判别算法旨在辨别这些分布之间的最佳边界。来源: 堆栈溢出
虽然当我们对任何数据集应用判别算法(如支持向量机、各种形式的参数回归(如香草线性回归)和非参数回归(如随机森林、神经网络、boosting))时会出现这种情况,但结果不一定有任何道德含义。例如,使用上周的天气数据来尝试预测明天的天气,这并不具有道德价值。然而,当我们的数据集基于直接或间接描述人(个体)的信息时,这可能会无意中导致基于群体关系的歧视。
显然,监督学习是一种两用技术。它可以为我们带来好处,例如用于信息(例如预测天气)和保护(例如分析计算机网络以检测攻击和恶意软件)。另一方面,它有可能被武器化,以便在几乎任何层面上进行歧视。这并不是说算法这样做是邪恶的,它们只是在学习数据中存在的表示,这些表示本身可能已经嵌入了历史不公正的表现,以及个人的偏见和倾向。数据科学中的一个常见格言是“垃圾输入=垃圾输出”,指的是高度依赖于提供给它们的数据质量的模型。这可以在算法公平性的上下文中类似地表述为“偏入=偏出”。
数据原教旨主义
有些支持者信奉 数据原教旨主义 ,也就是说,数据通过经验观察反映了世界的客观真相。
“有了足够的数据,数字就能说明一切。” —前《连线》主编克里斯·安德森(数据原教旨主义者)
数据和数据集不客观;它们是人类设计的产物。我们赋予数字它们的声音,从中得出推论,并通过我们的解释来定义它们的意义。收集和分析阶段的隐藏偏差带来了相当大的风险,对于大数据等式来说,这与数字本身一样重要。 —凯特·克劳福德,微软研究社交媒体集体 首席研究员
表面上看,这似乎是一个合理的假设,但凯特·克劳福德在《哈佛商业评论》的一篇文章中提供了一个很好的反驳:
波士顿有坑洞的问题,每年修补大约 20,000 个。为了帮助有效地分配资源,波士顿市发布了优秀的 StreetBump 智能手机应用程序,它利用加速度计和 GPS 数据来帮助被动检测坑洞,并立即向城市报告。虽然这无疑是一个聪明的方法,但 StreetBump 有一个信号问题。在美国,低收入群体不太可能拥有智能手机,尤其是老年居民,他们的智能手机普及率只有 16%。对于像波士顿这样的城市来说,这意味着智能手机数据集缺失了相当一部分人口的输入——通常是那些资源最少的人。——微软研究院首席研究员凯特·克劳福德
本质上,StreetBump 应用程序从富裕社区获得了大量数据,而从贫困社区获得的数据相对较少。很自然,你可能从中得出的第一个结论是,较富裕的社区有更多的坑洞,但实际上,贫穷社区的数据很少,因为这些人不太可能有智能手机,因此下载了 SmartBump 应用程序。通常,我们的数据集中没有的数据会对我们的结果产生最大的影响。这个例子说明了一种微妙的收入歧视形式。因此,当从可能遭受“信号问题”的数据中得出这样的结论时,我们应该谨慎。这种信号问题通常被表征为 采样偏差 。
另一个值得注意的例子是“替代性制裁的惩教罪犯管理概况”算法,简称 COMPAS。美国许多州都使用这种算法来预测累犯率,即前罪犯再次犯罪的可能性。调查性新闻机构 ProPublica 对该算法的分析引发了争议,因为它似乎表明该算法是基于种族的歧视——种族在美国是一个受保护的阶层。为了让我们更好地了解正在发生的事情,用于预测累犯的算法看起来像这样:
累犯风险评分 =(年龄w) +(首次被捕年龄w) +(暴力史* w)+(职业教育* w)+(违规史* w)
应该清楚的是,种族不是用作预测的变量之一。然而,根据美国历史上的不公正以及人口统计、社会和执法统计数据(这通常是另一个批评的目标,因为他们经常使用算法来确定哪些街区需要巡逻),对于这些变量中的一些变量,如“暴力历史”和“职业教育”因素,两个给定种族之间的数据分布可能有很大不同。这些数据分布之间的不匹配可以被算法利用,导致种族之间的差异,从而在某种程度上导致适度偏向或反对某些种族的结果。这些根深蒂固的偏见将被算法操作化,并因此继续存在,导致进一步的不公正。这个循环本质上是一个自我实现的预言。
历史不公→训练数据→生产中的算法偏差
这导致了一些困难的问题——我们去除这些有问题的变量了吗?我们如何确定一个特征是否会导致歧视性的结果?我们需要设计一个度量标准来提供“歧视”的阈值吗?人们可以将这种方法发挥到极致,去掉几乎所有的变量,但这样算法就没用了。这描绘了一幅暗淡的画面,但是幸运的是,有一些方法可以解决这些问题,这些问题将在本文的后面讨论。
这些例子不是孤立的事件。甚至乳腺癌预测算法也显示出一定程度的不公平歧视。从乳房 x 光片预测乳腺癌的深度学习算法对黑人女性的准确性远远低于白人女性。这部分是因为用于训练这些算法的数据集主要基于白人女性的乳房 x 光片,但也因为黑人女性和白人女性之间的乳腺癌数据分布可能有很大差异。根据疾病控制中心(CDC)黑人女性和白人女性患乳腺癌的几率差不多,但是黑人女性死于乳腺癌的几率比白人女性高**。**
动机
这些问题引发了关于算法开发人员动机的问题——设计这些模型的人是故意这样做的吗?他们是否有一个他们试图推动的议程,并试图将其隐藏在灰色盒子机器学习模型中?
虽然这些问题不可能有把握地回答,但在问这类问题时,考虑一下汉隆剃刀是有用的:
永远不要把可以用愚蠢来充分解释的事情归咎于恶意——罗伯特·j·汉伦 T3
换句话说,世界上没有那么多邪恶的人(谢天谢地),世界上邪恶的人肯定比无能的人少。一般来说,我们应该假设当事情出错时,更可能是因为无能、幼稚或疏忽,而不是纯粹的恶意。虽然可能有一些恶意的行为者想要推动歧视性议程,但这些可能是少数。
基于这种假设,可能会出现什么问题呢?有人可能会说,统计学家、机器学习从业者、数据科学家和计算机科学家没有被充分地教授如何开发监督学习算法来控制和纠正偏见倾向。
为什么会这样呢?
事实上,实现这一点的技术并不存在。机器学习公平性是机器学习的一个年轻的子领域,在过去几年中,随着机器学习与社会领域的快速融合,它越来越受欢迎。与医生不同,计算机科学家不一定受过考虑其行为的道德含义的训练。直到最近(可以说是社交媒体出现以来),计算机科学家的设计或发明才具备了伦理维度。
这表现在大多数计算机科学期刊不要求对提交的稿件进行伦理陈述或考虑。如果你有一个包含数百万真实人物图像的图像数据库,这无疑会有伦理上的影响。由于物理距离和数据集的大小,计算机科学家与数据主体相距甚远,以至于对任何一个人的影响都可能被认为是微不足道的,从而被忽视。相比之下,如果社会学家或心理学家对一小群人进行测试,就会成立一个完整的伦理审查委员会来审查和批准实验,以确保实验不会超越任何伦理界限。
从好的方面来看,这种情况正在慢慢开始改变。越来越多的数据科学和计算机科学项目开始要求学生参加数据伦理和批判性思维的课程,期刊也开始认识到通过 IRB 和手稿中的伦理陈述进行伦理审查可能是同行评审过程的必要补充。对机器学习公平性话题的兴趣不断上升,只是在强化这一立场。
机器学习中的公平性
在过去的几年里,机器学习的公平性已经成为一个热门话题。图片来源: CS 294:机器学习中的公平性 加州大学伯克利分校教授的课程。
如前所述,监督机器学习算法的广泛采用引发了对算法公平性的担忧。这些算法被采用得越多,它们对我们生活的控制力越大,只会加剧这些担忧。机器学习社区很清楚这些挑战,算法公平现在是机器学习的一个快速发展的子领域,有许多优秀的研究人员,如 Moritz Hardt,Cynthia Dwork,Solon Barocas 和 Michael Feldman。
尽管如此,在我们能够实现真正公平的算法之前,仍有一些重大障碍需要克服。在算法中防止不同的处理是相当容易的——一个群体对另一个群体的显式区别对待,例如通过从数据集中删除对应于这些属性的变量(例如种族、性别)。然而,要防止不同的影响**——一个群体相对于另一个群体的隐性差别待遇,通常是由数据中被称为冗余编码的东西引起的,要容易得多。**
不同影响的图示-在此图中,两组的数据分布非常不同,这导致了算法输出的差异,而没有任何组的显式关联。来源: KdNuggets
一个冗余编码告诉我们关于一个受保护属性的信息,比如种族或性别,基于我们数据集中与这些属性相关的特征。例如,在线购买某些产品(如化妆品)可能与性别高度相关,某些邮政编码可能具有不同的种族人口统计数据,算法可能会发现这些数据。
尽管算法并不试图沿着这些路线进行区分,但不可避免的是,在模式识别任务中取代人类表现的数据驱动算法可能会发现这些嵌入数据中的关联,无论它们可能有多小。此外,如果这些关联是非信息性的(即,它们不会增加算法的准确性),则算法将忽略它们,这意味着一些信息显然嵌入在这些受保护的属性中。这对研究人员提出了许多挑战,例如:
- 公平和准确之间是否存在根本性的权衡?我们是否能够从受保护的特征中提取相关信息,而不会以歧视的方式使用它们?
- 在算法中嵌入“公平”概念的最佳统计方法是什么?
- 我们如何确保政府和公司产生保护个人公平的算法?
- 我们的训练数据中有哪些偏见,我们如何减轻它们的影响?
我们将在文章的剩余部分触及其中的一些问题。
数据的问题
在上一节中,提到了冗余编码会导致与受保护属性相关的特性。随着我们的数据集规模的扩大,这些相关性出现的可能性也相应扩大。在大数据时代,这提出了一个大问题:我们访问的数据越多,我们可用于辨别的信息就越多。这种歧视不一定是纯粹基于种族或性别的,它可以表现为对粉发者、网络开发者、星巴克咖啡饮用者或所有这些群体的组合的歧视。在本节中,将介绍训练数据和算法中存在的几种偏差,这些偏差使公平算法的创建变得复杂。
多数偏向
算法对任何特定的群体都没有亲和力,然而,由于它们的统计基础,它们确实倾向于大多数群体。正如 Moritz Hardt 教授在 Medium 的文章中所概述的,分类器通常会随着用于训练它们的数据点的数量而提高,因为误差与样本数量的平方根成反比,如下所示。
分类器的误差通常随着样本大小的平方根的倒数而减小。四倍的样本意味着误差率减半。
这导致了一个令人不安的现实,因为根据定义,关于少数群体的可用数据总是较少,我们的模型在这些群体中的表现往往比在多数群体中的表现差。只有当多数群体和少数群体来自不同的分布时,这个假设才是正确的,如果他们来自单一的分布,那么增加样本量对两个群体都同样有利。
这方面的一个例子是我们之前讨论过的乳腺癌检测算法。对于这个由麻省理工学院研究人员开发的深度学习模型,在用于训练神经网络的数据集中的 6 万张乳房 x 光照片中,只有 5%是黑人女性的乳房 x 光照片,她们死于乳腺癌的可能性增加了 43%。因此,在对黑人女性和少数族裔群体进行测试时,该算法的表现更差。这可能部分是因为乳腺癌通常在有色人种妇女中较早出现,这表明了不同的影响,因为有色人种妇女的概率分布未被充分代表。
这也提出了另一个重要的问题。准确性是公平的合适代表吗?在上面的例子中,我们假设少数群体的较低分类准确度对应于不公平。然而,由于公平的定义差异很大,性质有些模糊,有时很难确保我们衡量的变量是公平的良好代表。例如,我们的算法对于黑人和白人女性可能都有 50%的准确性,但是如果对于白人女性有 30%的假阳性,对于黑人女性有 30%的假阴性,这也将指示不同的影响。
从这个例子中,几乎可以直观地看出这是一种歧视形式,因为存在基于群体隶属关系的差别待遇。然而,有时这种群体关系对我们的预测是有益的。例如,对于一个试图决定向用户展示什么内容的电子商务网站来说,了解个人的性别、年龄或社会经济地位非常有帮助。这意味着,如果我们仅仅从数据中删除受保护的字段,我们将降低模型的准确性(或其他一些性能指标)。类似地,如果我们有足够的黑人和白人女性的乳腺癌模型数据,我们可以开发一种算法,将种族作为输入之一。由于种族间数据分布的差异,很可能两组的准确性都有所提高。
因此,理想的情况是拥有一个包含这些受保护特征的算法,并使用它们来进行算法概括,但受到公平性度量的约束,以防止算法进行区分。
这是由莫里茨·哈特和埃里克·普莱斯在“监督学习中的机会均等”中提出的想法。与其他指标相比,这有几个优点,如统计奇偶和均等优势,但我们将在下一节讨论所有这三种方法。
公平的定义
在这一节中,我们分析了机器学习公平研究人员提出的一些公平概念。即统计上的均等,然后是统计上的均等的细微差别,如机会均等和机会均等。
统计平价
统计均等是最古老也是最简单的实施公平的方法。在 arXiv 文章 " 算法决策和公平成本 " 中对此进行了详细阐述。统计奇偶校验的公式如下所示。
统计奇偶性公式。换句话说,这说明结果 y 独立于参数 p——它对结果概率没有影响。
对于统计奇偶校验,结果将独立于我的团体从属关系。这直观上意味着什么?这意味着每组的相同比例将被归类为积极或消极。出于这个原因,我们也可以将统计上的均等描述为人口上的均等**。对于包含在 p 内的所有人口统计群体,将实施统计均等。**
对于尚未应用统计奇偶校验的数据集,我们可以通过计算如下所示的统计奇偶校验距离来衡量我们的预测与统计奇偶校验的偏差程度。
统计奇偶距离可用于量化预测偏离统计奇偶的程度。
这个距离可以为我们提供一个度量标准,来衡量一个给定的数据集基于群体关系的公平或不公平程度
使用统计奇偶校验的利弊是什么?
统计上的均等并不能确保公平。
你可能已经注意到了,统计奇偶性并没有说明这些预测的准确性。一个组可能比另一个组更有可能被预测为阳性,因此我们可能获得每个组的假阳性率和真阳性率之间的巨大差异。这本身会造成完全不同的影响,因为一个组的合格人员( p=0 ) 可能会被另一个组的不合格人员( p=1 )漏掉。从这个意义上说,统计上的均等更类似于结果的均等。
下图很好地说明了这一点。如果我们有两个组,一个有 10 个人(A 组=1),一个有 5 个人(A 组=0),我们确定 A 组=1 中的 8 个人(80%)获得了 Y=1 的分数,那么 A 组=0 中的 4 个人(80%)也必须获得 Y=1 的分数,而不考虑其他因素。
统计奇偶性图解。来源:杜克大学隐私&数据科学中的公平讲义
统计奇偶性降低算法准确性
统计奇偶性的第二个问题是,受保护的类可能提供一些对预测有用的信息,但是由于统计奇偶性强加的严格规则,我们无法利用这些信息。性别对于预测人们可能购买的物品可能非常有用,但如果我们被阻止使用它,我们的模型就会变得更弱,准确性也会受到影响。一种更好的方法将允许我们考虑这些组之间的差异,而不会产生完全不同的影响。显然,统计奇偶校验与机器学习的基本目标不一致——完美的分类器可能无法确保人口统计奇偶校验。
由于这些原因,一些机器学习公平性研究人员不再认为统计奇偶性是一个可信的选择。然而,统计上的均等是一个简单而有用的起点,公平的其他定义都建立在这个起点上。
统计奇偶性有稍微更细微的版本,例如真正奇偶性、假正奇偶性和正比率奇偶性。
真正的正均等(机会均等)
这仅适用于二元预测,并对真值执行统计奇偶校验(预测输出为 1,而真值输出也为 1)。
机会均等与均等几率相同,但重点在于 y=1 的标签。
这确保了在两组中,在所有合格的人(Y=1)中,相同比例的个人将被归类为合格(C=1)。当我们只对正面结果的均等感兴趣时,这是有用的。
真实正宇称的图解。注意,在第一组中,所有 Y=1(蓝框)的都被归类为阳性(C=1)。类似地,在第二组中,所有被分类为 Y=1 的人也被分类为阳性,但有一个额外的假阳性。在统计奇偶性的定义中没有考虑这种假阳性。来源:杜克大学隐私&数据科学中的公平讲义
假阳性奇偶校验
这也仅适用于二进制预测,并侧重于误报(预测输出为 1,但真实输出为 0)。这类似于真阳性率,但是提供了跨假阳性结果的奇偶性。
正比率平价(均等赔率)
这是同时针对真阳性和假阳性的统计奇偶性的组合,也称为均衡赔率*。***
正比率平价图解(均等的赔率)。注意,在第一组中,所有 Y=1(蓝框)的都被归类为阳性(C=1)。类似地,在第二组中,所有归类为 Y=1 的也归类为阳性。在获得 Y=0 的 A=1 的群体中,其中一个被分类为 C=1,给出 50%的假阳性率。类似地,在第二组中,这些个体中的两个被给予 C=1,对应于 50%的假阳性率。来源:杜克大学隐私&数据科学中的公平讲义
请注意,对于机会均等,我们放宽了均等赔率的条件,即在 Y=0 的情况下赔率必须相等。均等机会和均等机会也更加灵活,能够纳入受保护变量的一些信息,而不会产生完全不同的影响。
请注意,虽然所有这些都提供了某种形式的解决方案,可以说是公平的,但没有一个是特别令人满意的。其中一个原因是,对于公平的内涵有许多相互冲突的定义,很难用算法的形式来捕捉它们。这些都是很好的起点,但仍有很大的改进空间。
增加公平性的其他方法
统计均等、均等的机会和机会均等都是很好的起点,但我们还可以做其他事情来确保算法不会被用来过度歧视个人。已经提出的两种这样的解决方案是人在回路中和算法透明。
人在回路中
这听起来像某种过山车,但它只是指一种人类监督算法过程的范式。人在回路通常在算法出错的高风险情况下实施。例如,当检测到导弹时通知军方的导弹检测系统允许个人审查情况并决定如何做出反应——如果没有人类的互动,算法不会做出反应。想象一下,当 AI 检测到威胁时,允许它开火,运行核武器系统的灾难性后果——一个假阳性,整个世界都将毁灭。
另一个例子是针对累犯的 COMPAS 系统——该系统不会将你归类为累犯并做出法律判决。取而代之的是,法官审查 COMPAS 的分数,并将此作为他们评估情况的一个因素。这提出了新的问题,例如人类如何与算法系统交互。使用亚马逊 Mechanical Turk 的研究表明,一些人会全心全意地遵循算法的判断,因为他们认为它比人类可能拥有的知识更多,其他人则对其输出持保留态度,有些人则完全忽视它。对人在回路中的研究相对来说比较新颖,但随着机器学习在我们的社会中变得更加普遍,我们可能会看到更多这样的研究。
另一个重要且相似的概念是人在回路中。这类似于人在回路中,但不是人主动参与过程,而是被动参与算法的监督。例如,数据分析师可能负责监控石油和天然气管道的各个部分,以确保所有传感器和流程正常运行,并且没有相关信号或错误。该分析师处于监督位置,但不积极参与流程。“人在回路”比“人在回路”本质上更具可扩展性,因为它需要更少的人力,但在某些情况下它可能站不住脚——例如照看那些核导弹!
算法透明性
公平在法律文献中的主导地位是通过算法的可解释性和通过透明度的可解释性。论点是,如果一个算法能够被公开查看和仔细分析,那么它就可以在很大程度上确保模型中没有完全不同的影响。虽然这在许多层面上显然是可取的,但算法透明也有一些缺点。
专有算法根据定义不能是透明的。
从商业角度来看,这种想法在大多数情况下是站不住脚的——如果算法和业务流程被提供给所有人看,商业秘密或专有信息可能会被泄露。想象一下,脸书或 Twitter 被要求向世界发布他们的算法,以便他们可以被仔细检查,以确保没有偏见问题。最有可能的是,我可以下载他们的代码,然后很容易地开始我自己版本的 Twitter 或脸书。完全透明只是公共服务中使用的算法的一个选项,例如政府(在某种程度上)、医疗保健、法律系统等。由于法律学者主要关心的是法律制度,这在目前仍然是共识是有道理的。
在未来,对私人公司来说,对算法公平性的监管可能是一个比算法透明度更站得住脚的解决方案,因为私人公司有既得利益让他们的算法远离公众的视线。Andrew Tutt 在他的论文“a FDA For Algorithms”中讨论了这一想法,该论文专注于开发一个类似于 FDA 的监管机构来监管算法。可以将算法提交给监管机构,或者第三方审计服务,并对其进行分析,以确保它们适合使用而不会产生完全不同的影响。
显然,这样的想法需要大量的讨论、资金和专业知识来实现,但从我的角度来看,这似乎是一个潜在可行的解决方案。要确保我们的算法不受不同的对待和不同的影响,还有很长的路要走。通过将法规、透明度、人在回路、人在回路以及新的和改进的统计奇偶性变化结合起来,我们是实现这一目标的一部分,但这一领域仍然年轻,还有许多工作要做——请关注这一领域。
最终意见
在本文中,我们详细讨论了由于收集和分析数据的方式而导致的训练数据中存在的多重偏差。我们还讨论了几种方法来减轻这些偏见的影响,并帮助确保算法对少数群体和受保护的阶层保持不歧视。
虽然机器学习就其本质而言总是一种统计歧视,但当它将某些特权群体置于系统优势而将某些非特权群体置于系统劣势时,这种歧视就会变得令人反感。由于标签中的偏见或欠采样/过采样,训练数据中的偏差会产生带有不需要的偏差的模型。
有些人可能会说,这些决定是由人在较少的信息下做出的,这可能会有许多隐含的和认知的偏见影响他们的决定。自动化这些决策提供了更准确的结果,并在很大程度上限制了这些偏差的程度。算法不需要完美,只要比以前存在的算法更好就行。历史的弧线朝着正义弯曲。
有些人可能会说,算法被赋予了自由,允许不平等被系统地实例化,或者数据本身存在固有的偏见。应该从数据中删除与受保护属性相关的变量,以帮助缓解这些问题,并且删除或限制与变量相关的任何变量。
这两组都是部分正确的。但是,我们不应该满足于不公平的算法,还有改进的空间。类似地,我们不应该浪费我们拥有的所有数据并删除所有变量,因为这将使系统性能更差,并使它们变得不那么有用。话虽如此,归根结底,这些算法和监督机构的创造者以及负责收集数据的人有责任确保这些偏见得到妥善处理。
数据收集和抽样程序在统计学课堂上经常被掩盖,并且不被公众所理解。在监管机构出现之前,机器学习工程师、统计学家和数据科学家有责任确保机会平等嵌入到我们的机器学习实践中。我们必须注意我们的数据来自哪里,我们用它做什么。谁知道我们的决定将来会影响到谁?
“世界是不公平的,卡尔文。”“我知道爸爸,但是为什么从来没有对我有利的时候呢?”
― 【比尔·沃特森】, 加尔文与霍布斯:一个加尔文与霍布斯的国库
时事通讯
关于新博客文章和额外内容的更新,请注册我的时事通讯。
丰富您的学术之旅,加入一个由科学家,研究人员和行业专业人士组成的社区,以获得…
mailchi.mp](https://mailchi.mp/6304809e49e7/matthew-stewart)
进一步阅读
【1】大数据:关于算法系统、机会和公民权利的报告。白宫。2016.
【2】计算机系统中的偏差。巴特娅·弗里德曼,海伦·尼森鲍姆。1996
【3】大数据中隐藏的偏见。凯特·克劳福德。2013.
【4】大数据的不同影响。索隆·巴罗卡斯,安德鲁·塞尔伯特。2014.
**【5】**博文:大数据有多不公平。莫里茨·哈特。2014
【6】从语言语料库中自动导出的语义包含类人偏见。艾林·卡利斯坎,乔安娜·j·布赖森,阿尔温德·纳拉亚南
研究生招生中的性别偏见:来自伯克利的数据。比克尔,哈默尔,奥康内尔。1975.
****【8】辛普森悖论。珍珠(第六章)。技术报告
****【9】验证并移除不同的影响。迈克尔·费尔德曼,索雷尔·弗雷德勒,约翰·默勒,卡洛斯·沙伊德格,苏雷什·文卡塔萨布拉曼尼安
****【10】监督学习中的机会均等。莫里茨·哈特,埃里克·普莱斯,内森·斯雷布罗。2016.
****【11】博文:接近机器学习中的公平。莫里茨·哈特。2016.
****【12】机器偏差。Julia Angwin,Jeff Larson,Surya Mattu 和 Lauren Kirchner,ProPublica。代码审查:github.com/probublica/compas-analysis,github.com/adebayoj/fairml
****【13】COMPAS 风险等级:展示准确性、公平性和预测性平价。诺斯波因特公司。
刑事司法风险评估中的公平性:最新技术
Richard Berk,Hoda Heidari,Shahin Jabbari,Michael Kearns,Aaron Roth。2017.
****【15】法院和预测算法。安格尔·克里斯汀、亚历克斯·罗森布拉特和丹娜·博伊德。2015.讨论稿
****【16】用机器学习减轻司法偏见的局限性。克里斯蒂安.卢姆。2017.
****【17】支持向量机的概率输出以及与正则化似然方法的比较。约翰·c·普拉特。1999.
****【18】公平确定风险分值的内在权衡。乔恩·克莱因伯格,森迪尔·穆莱纳坦,马尼什·拉加万。2016.
****【19】影响迥异的公平预测:累犯预测工具偏差研究。亚历山德拉·乔尔德乔娃。2016.
****【20】用更智能的机器学习攻击歧视。Martin Wattenberg,Fernanda Viégas 和 Moritz Hardt 的交互式可视化。2016.
****【21】算法决策与公平成本。山姆科比特-戴维斯,艾玛·皮尔森,阿维费勒,沙拉德戈埃尔,阿齐兹胡克。2017.
****【22】歧视性结果检验中的次边际问题。卡米莉亚·西莫伊,萨姆·科比特·戴维斯,沙拉德·戈埃尔。2017.
****【23】监督学习中的机会均等。莫里茨·哈特,埃里克·普莱斯,内森·斯雷布罗。2016.
因果推论的要素。彼得斯、扬金、舍尔科夫
****【25】关于调整混杂和中介变量的回归中种族的因果解释。泰勒·j·范德威尔和惠特尼·r·罗宾逊。2014.
【反事实公平】。马特 j .库斯纳,约书亚 r .洛夫特斯,克里斯拉塞尔,里卡多席尔瓦。2017.
【27】通过因果推理避免歧视。尼基·基尔伯图斯、马特奥·罗哈斯-卡鲁拉、詹巴蒂斯塔·帕拉斯坎多罗、莫里茨·哈特、张秀坤·扬金、伯恩哈德·舍尔科夫。2017.
【28】对结果的公平推断。伊利亚·施皮泽尔·拉齐埃·纳比
【29】通过认知实现公平。辛西娅·德沃克,莫里茨·哈特,托尼安·皮塔西,奥马尔·莱因戈尔德,里奇·泽梅尔。2012.
【30】论公平的可能性。Sorelle A. Friedler,Carlos Scheidegger,Suresh Venkatasubramanian。2016.
【31】为什么不应该使用倾向评分。理查德·尼尔森·Gary King。2016.
【32】原始数据是一种矛盾修饰法。莉萨·吉特曼编辑。2013.
****【33】博文:统计中最重要的有哪些是课本上没有的。安德鲁·吉尔曼。2015.
【34】解构统计问题。大卫. j .汉德。1994.
【35】统计学和计量理论。大卫. j .汉德。1996.
【36】计量理论与实践:通过量化看世界。大卫. j .汉德。2010
【调查方法论】第二版。罗伯特·格罗夫斯、小弗洛伊德·j·福勒、米克·p·库帕、詹姆斯·m·莱普考斯基、埃莉诺·辛格、罗杰·图兰盖。2009
男人对于电脑程序员就像女人对于家庭主妇一样?去偏置词嵌入。托尔加·博卢克巴斯、张开伟、詹姆斯·邹、文卡特什·萨利格拉玛、亚当·卡莱。2016.
【39】男性也喜欢购物:利用语料库级约束减少性别偏见放大。、王天禄、马克·亚茨卡、维森特·奥多涅斯、张开伟。2017.
【40】大数据的不同影响。索隆·巴罗卡斯,安德鲁·塞尔伯特。2014.
【41】这不是隐私,也不公平。辛西娅·德沃克迪尔德丽·k·穆里根。2013.
【42】算法决策的麻烦。塔尔·扎斯基。2016.
【43】版权法如何修复人工智能的隐性偏见问题。阿曼达·莱文多夫斯基。2017.
【44】FDA 对算法的。安德鲁·塔特。2016***
每个数据工程师都应该知道的 ML 编程技巧——第 1 部分
现实世界中的 DS
数据科学家和机器学习从业者的更广泛的备忘单。
纳赫尔·阿卜杜勒·哈迪在 Unsplash 上的照片
让我们马上开始。
1.省略号对象(…):
它是 Python 中的一个对象,可以用于 Numpy 包中的矩阵切片,也可以用于一般的列表切片。这个对象的主要目的是使多维数组处理更容易。Numpy 数组中的多个索引可以替换为…(省略号对象)。
同样,它也可以用来代替 Python 中的 pass 命令,在定义空函数时实现“无操作”。
>>> import numpy as np
>>> a = np.array([[[i + 2*j + 8*k for i in range(3)] for j in range(3)] for k in range(3)])
>>> arr = np.array(a)
>>> arr
array([[[ 0, 1, 2], [ 2, 3, 4], [ 4, 5, 6]],
[[ 8, 9, 10], [10, 11, 12], [12, 13, 14]],
[[16, 17, 18], [18, 19, 20], [20, 21, 22]]])
>>> **arr[1,...]** array([[ 8, 9, 10], [10, 11, 12], [12, 13, 14]])
>>> **arr[...,1]** array([[ 1, 3, 5], [ 9, 11, 13], [17, 19, 21]])
2.* & @速记运算符:
两个主要的 numpy 矩阵运算是 np.multiply(A,B) 和 np.matmul(A,B) ,它们分别计算元素乘法和矩阵乘法。np.multiply(A,B)可以实现为 A*B ,np.matmul(A,B)可以实现为 A@B 。
>>> import numpy as np
>>> A = np.random.rand(2,2)
>>> B = np.random.rand(2,2)
**>>> np.multiply(A,B)**
array([[0.69938897, 0.08791922], [0.23572921, 0.04930693]])
**>>> A*B**
array([[0.69938897, 0.08791922], [0.23572921, 0.04930693]])
**>>> np.matmul(A,B)**
array([[0.75990246, 0.74811588], [0.49980481, 0.39179465]])
**>>> A@B**
array([[0.75990246, 0.74811588], [0.49980481, 0.39179465]])
3.样本/混洗数据集:
熊猫数据帧对象可以用一只熊猫随机洗牌。DataFrame.sample()函数。
>>> import pandas as pd
>>> df = pd.DataFrame({'num_legs': [2, 4, 8, 0],
'num_specimen_seen': [10, 2, 1, 8]},
index=['falcon', 'dog', 'spider', 'fish'])
>>> df
num_legs num_specimen_seen
falcon 2 10
dog 4 2
spider 8 1
fish 0 8
>>> df.sample(frac=1, random_state=2)
num_legs num_specimen_seen
spider 8 1
fish 0 8
dog 4 2
falcon 2 10
4.LP 规范:
范数是从复数或实数上的向量空间到正实数的一种度量。LP 范数是有限维 p 范数的推广形式。p-范数定义为向量的和的幂 *p,*进一步幂为 *p 的倒数,*公式如下:
当 p=1 时,其 L1 范数(也称为曼哈顿距离)和用于 Lasso 回归的绝对值范数(称为 L1 损失(MAE))。
当 p=2 时,其 L2 范数,也称为欧氏距离,在岭回归中用作 L2 损失(MSE)。
类似地,p=3,4,…可用于计算不同水平的范数,并可在不同的机器学习算法中用作损失函数。
5.处理等级不平衡:
在所有 scikit learn 的机器学习算法实现中,有一个名为“class_weight”的参数,需要设置为“balanced”或 Python 字典对象,其中包含所有样本的权重。
>>> rfc = RandomForestClassifier(class_weight='balanced')
>>> rfc.fit(df_train_pca,y_train)
6.正在加载 ARFF 数据集:
大多数情况下,当我们使用数据集时,我们被提供了。csv 或。xls 文件,可以用 pandas.read_csv() 或 pandas.read_excel() 函数直接读取。但是,有些时候**。arff 文件**也用于分析,也用于记录一组属性的实例,如。但是对性能和内存使用更敏感。我们可以使用熊猫数据帧中的 arff 库在熊猫中阅读它,如下所示:
>>> import arff
>>> df = pd.DataFrame(arff.loadarff('./Training Dataset.arff')[0])
>>> df = df.select_dtypes([np.object])
>>> df = df.stack().str.decode('utf-8').unstack()
7.PIL 图像:
PIL 是 Python 图像库,它提供了使用 Python 解释器操作和显示图像的能力。
# importing Image class from PIL package
>>> from PIL import Image
# creating a image object
>>> im = Image.open(r"/Users/killerHack/Desktop/Hackint.jpg")
>>> im.show()
8.用熊猫制图。Series.map():
当操作 pandas 数据框架中的列值时,例如将分类值转换为数值。熊猫。Series.map()函数可用于 Series 或 DataFrame 列,将不同的值替换为另一组值,如下所示:
>>> s = pd.Series(['cat', 'dog', np.nan, 'rabbit'])
>>> s.map({'cat': 'kitten', 'dog': 'puppy'})
0 kitten
1 puppy
2 NaN
3 NaN
dtype: object
9.数据透视表:
大多数人都有在 Excel 中使用数据透视表的经验,并且可以在 Python 中使用相同的 pandas.pivot_table()函数。数据透视表用于汇总大型扩展表中的一些列的数据。
>>> import pandas as pd
>>> df = pd.DataFrame({"A": ["foo", "foo", "foo", "foo", "foo",
... "bar", "bar", "bar", "bar"],
... "B": ["one", "one", "one", "two", "two",
... "one", "one", "two", "two"],
... "C": ["small", "large", "large", "small",
... "small", "large", "small", "small", "large"],
... "D": [1, 2, 2, 3, 3, 4, 5, 6, 7]})
>>> df
A B C D
0 foo one small 1
1 foo one large 2
2 foo one large 2
3 foo two small 3
4 foo two small 3
5 bar one large 4
6 bar one small 5
7 bar two small 6
8 bar two large 7
>>> table = pd.pivot_table(df, values='D', index=['A', 'B'],
... columns=['C'], aggfunc=np.sum)
>>> table
C large small
A B
bar one 4.0 5.0
two 7.0 6.0
foo one 4.0 1.0
two NaN 6.0
10.Matplotlib 样式参数:
matplotlib 是用于在 Python 中创建静态和动态可视化的绘图库。使用 matplotlib 绘图时,可以根据绘图要求使用 matplotlib.rcParams 对象更改样式的一些重要参数。
**import** **matplotlib.pyplot** **as** **plt**
%**matplotlib** inline
plt.style.use('ggplot')
plt.rcParams['font.family'] = 'sans-serif'
plt.rcParams['font.serif'] = 'Ubuntu'
plt.rcParams['font.monospace'] = 'Ubuntu Mono'
plt.rcParams['font.size'] = 10
plt.rcParams['axes.labelsize'] = 12
plt.rcParams['axes.titlesize'] = 12
plt.rcParams['xtick.labelsize'] = 8
plt.rcParams['ytick.labelsize'] = 8
plt.rcParams['legend.fontsize'] = 12
plt.rcParams['figure.titlesize'] = 14
plt.rcParams['figure.figsize'] = (12, 8)
目前就这些。在接下来的几部分中,我将介绍更多这些每个数据工程师都应该了解的重要技巧/功能。敬请关注。
【更新】
下面继续下一部分…
[## 每个数据工程师都应该知道的 ML 编程技巧——第 2 部分
数据科学家和机器学习从业者的更广泛的备忘单。
towardsdatascience.com](/ml-programming-hacks-that-every-data-engineer-should-know-part-2-61c0df0f215c) [## 机器学习中最常见的损失函数
每个机器学习工程师都应该了解机器学习中这些常见的损失函数,以及何时使用…
towardsdatascience.com](/most-common-loss-functions-in-machine-learning-c7212a99dae0)
感谢阅读。你可以在这里找到我的其他机器学习相关的帖子。
希望这篇帖子有用。我感谢反馈和建设性的批评。如果你想谈论这篇文章或其他相关话题,你可以在这里或在 LinkedIn 给我发短信。
四个数据集欺骗了线性回归模型。
towardsdatascience.com](/importance-of-data-visualization-anscombes-quartet-way-a325148b9fd2)
没有技术术语的逻辑回归+与树模型的比较
没有术语的机器学习
如果你喜欢披萨,你就会明白逻辑回归和随机森林的区别!
尼克·欧文斯在 Unsplash 上的照片
概述
- 什么是逻辑回归,它有什么好处
- 理解这个算法和随机森林(我们上周提到的那个)的区别,用一个意大利辣香肠披萨来说明使用哪个更好!
- 本周我这边的更新
逻辑回归非常常用于告诉我们一个事件是 T 还是 F,例如,这个客户会留下还是离开,这是垃圾邮件还是非垃圾邮件,有人会不会得这种病,等等。我几次看到人们声称这是最常用的算法。所以就来说说吧。
假设我们的漏斗中有 1000 名新客户作为潜在客户。我们知道有些客户比其他人更有可能和我们在一起。换句话说,一些客户更符合我们的特征,或者需要我们付出更少的精力来达成交易。我们想确认他们是谁。
图片 1
由于这是一个相互排斥的事件,客户越有可能留在我们这里,客户就越不可能离开我们。那么让我们在这里陈述我们的目标:我们想要一个模型,这样如果客户 A 可能会和我们呆在一起,它会告诉我们“呆”的概率很高,或者“不呆”(1-呆)的概率很低,反之亦然。(记住这一点,我们以后再来讲这个!)
图片 2
我们有三个变量,它们是合同的大小(价值),客户的类型(B2C 对 B2C),以及他们了解我们的渠道。我们非常直观地开始思考,我们需要看看我们以前的客户,看看这三个变量与结果之间有什么关系。这是正确的方向,除了我们这里有一个问题。
在我们初中或高中学过的传统线性方程中,它不代表概率;它给了我们一个明确的答案。为了向您展示我的意思,在图 3 等式 1)中,我们可以使用一些以前的数据,并有一个函数来计算 A、B 或 C 的“停留”百分比……我们将需要另一个函数来计算 A、B 或 C 的“未停留”百分比。这两个百分比不一定相加为 1,因为它们不代表概率。
因此,一些聪明的家伙开始思考,如果,我升级 Y,使它直接产生一个比较事件“停留”的概率和事件“不停留”的概率的结果,换句话说,它告诉我哪个事件比另一个更可能发生*(图 4)* 。这就是我们如何从功能 1)到功能 2)!函数 2)直接给我们“停留”的概率和“不停留”的概率之比
图 3
图 4
那么木头为什么会在哪里出现呢?现在就不能解决关系吗?
原因很简单。这是因为当我们在比较 A 比 B 多多少时间时,这个数字可以从 0 到无穷大。你想想,你比你不喜欢的人牛逼 100 倍、1000 倍、10000 倍……牛逼。“时代”可以有多大是没有限制的(当然!).另一方面,如果我们想表达更少的可能性,我们没有办法做到,因为我们的等式 2)的分子的最小值,事件 A 的概率是 0。不存在负概率。
为了解决这个问题,我们通过记录 y 从等式 2)移至等式 3)。如果您需要一些关于对数如何工作的提示,我在下面附上了基于 10 的对数标度与线性标度的图像。简而言之,这只是一种不同的测量方式,比如从英尺到厘米。现在,我们准备使用我们的数据,并解决这些系数!
图 5
我相信学校里没有多少人喜欢解这些系数的作业。**这就是为什么我们要使用算法!!**没什么花哨的。在逻辑回归中,当你输入数据后,你的计算机会告诉你系数,而不是一个神奇的答案。
我们的计算机将通过尝试一系列不同的线来为我们获得最佳系数!我们如何定义最好的一个?记得我们的目标是什么吗?
我们需要一个模型,这样如果客户 A 很有可能和我们呆在一起,它会告诉我们“呆”的概率很高,或者“不呆”(1-呆)的概率很低,反之亦然。
因此,最佳系数的定义是使最大数量的情况能够满足我们定义的目标。
现在,计算机已经给了我们系数。我们已经解决了三个变量和结果之间的关系!现在我们想从我们的函数中获得洞察力。然而,记住我们改变了我们的 Y,所以解释起来有点棘手。让我们编造一些准确的数字来说明这一过程。
图 6
第一个系数是指 x1 增加 1 个单位(其他一切不变),将增加概率 x 与概率(1-x) 的比值在对数标度上增加 0.005;另一方面,x2 增加 1 个单位,将会使在对数标度上使比率降低 0.65。
既然在生活中,我们用的是线性标度而不是对数标度,那么我们可以用 e 将其转换回线性标度,在 x2 的例子中,之前,事件“停留”发生的可能性是事件“不停留”发生的可能性的 1.17 倍。然而,在 x2 发生 1 个单位的变化后,尽管“停留”仍然更有可能发生,但该比率现在降低到只有 0.52 倍的可能性。
图 7
图 8
嘿,我知道这不是最简单的事情,但是如果你能接受这个,你知道有什么好处吗?
你不仅知道谁有可能留下来,你应该把精力放在哪里,而且在那些有可能留下来的人中,你甚至知道谁最有可能留下来!所以现在,您可以对您的客户进行排名,或者为不同的客户制定不同的预期时间表!!
例如,对于不太可能的客户,预留更多的时间,因为这将是一场漫长的战斗,如果你没有在第一次尝试中获得它,不要觉得自己不好:)对于那些已经获得的客户来说,更有可能是“不留下来”,然后留下来,我们现在甚至不需要麻烦!!
你如何整合你发现的例子
好吧,但是上周的帖子显示,随机森林也可以告诉我们一个客户是否会留下来或离开,为什么要用另一种方法呢?
我们可以(或许应该)用很多角度来解决这个问题,但我只想在这里给出最直观的答案。
想象一下,你的室友让你把比萨饼平均分成两份,因为你喜欢意大利辣香肠,所以你正在考虑如何切它,以便最大限度地获得意大利辣香肠。在逻辑回归中,你只能选择一条线来切断,尽管你仍然有很多选择,然而,在决策树中,没有这样的规则。
这种差异的原因是,在树模型中,我们使用一组逻辑陈述(是或否问题)来得出我们的结论,而对于逻辑回归,我们定义一组数字关系。当我们用一组数字来表达一种关系时,我们已经预先确定了一个等式,一个预先确定的结构来表达这种关系。例如,我们有等式 1)、2)和 3),我们只想找到系数。当我们使用一组逻辑语句时,我们不会指定这种关系是什么样的结构。
所以你可能会问,哪个更好?
谨记“如果一个模型是好的?”或者“应该使用哪个模型?”可以扩展成一个巨大的主题模型评估,我打算写一个单独的博客。对于每个人来说,了解我们应该或者能够如何评估一个模型是至关重要的,因为很多时候,在生产中使用哪个模型不仅仅是由具有坚实技术背景的人决定的。现在,让我们只讨论基础知识。
继续披萨的类比,第一个方法是计算哪一个给我们的辣香肠最多。然而,大多数时候事情并不那么清楚。如果你仔细观察比萨饼,通过使用逻辑回归划分,我们可以得到 7–7.5 个意大利辣香肠,而树模型给我们 8 个意大利辣香肠。没有明显的区别。考虑到每块披萨上意大利香肠的位置略有不同,逻辑回归有时可能会优于树形模型。这就是为什么你看到一个数据科学家有时使用 2 或 3 个模型,看看哪一个做得最好。
思考这个问题的另一种方法是问:除了模型的准确性,什么样的信息将最有助于解决您的业务问题?正如我在以前的文章中提到的,树模型(包括随机森林)最好的部分是它告诉你哪个逻辑语句最重要。在我们的比萨饼例子中,如果每个矩形都是一个逻辑陈述,那么它应该是最左边的那个,因为它给了我们三个意大利香肠。对于逻辑回归来说,最好的部分是它不仅给了我们意大利辣香肠,还告诉我们哪个意大利辣香肠最大,并为我们排序。
因此,在商业环境中,如果我正在开发一个产品并希望改进功能,树模型将帮助我们确定哪个功能是最重要的,因为该功能将为我们带来最多的客户,但如果我希望在月底前尽可能多地签订合同,逻辑回归将告诉我们首先瞄准哪些客户,因为他们最有可能从一开始就与我们合作。
每周更新!!上周不是最有成效的一周。
从周一到周二,在我周一晚上发布了我的上一篇文章后,我经历了一场几乎是恐慌的袭击,因为我意识到了我在文章中犯的一些错误(已经修复)。虽然我知道这是一个学习的过程,我知道作为一个新作家,可能没有人会仔细阅读这篇文章,但我仍然感到非常尴尬。因此,我花了两天时间来确保我对这个模型了如指掌。
周三和周四,我在准备两份工作申请,周四我有一个第一轮面试。不幸的是,我的推荐人告诉我,虽然面试的人力资源给了我一个通过,但我未来的老板让我失望了,因为我在☹之前没有任何相关的工作经验
在经历了这些情绪紧张的日子后,我开始感到有点疲惫,我觉得这一周我没有完成任何事情。我也开始质疑自己在数据领域找工作的能力(我看了一段时间不同的工作岗位)。所以我放慢了自己的节奏,出去散步,做一些烘焙,花一些时间读一本名为《商业数据科学》的书。阅读是我的自理活动之一。此外,这是一本令人惊叹的书,我打算在读完之后分享一些见解。
除此之外,我还在以下方面取得了一些进步:
- 模型选择和正则化:像所有的降维方法一样,ROC,AUC
- 关于树模型算法的更多信息:Ada 增强、梯度增强和 XGboost
- 总结所有监督模型并了解如何使用它们。为了准备这篇文章,我比以前更深入地理解了逻辑回归、LDA 和朴素贝叶斯。
- 我确实开始了一个项目,但我决定做一个预测客户流失的项目,而不是客户细分。我没有取得多大进展,但我计划下周完成它。我的目标是同时使用随机森林和逻辑回归。
仅此而已。我想用一句令人愉快的话来结束这篇文章,来提醒我自己和其他所有感觉有点精疲力尽的人。
“生活中的大事只有在你花时间做一些照顾自己的小事时才有可能实现。”—香奈儿·米勒
下周见!