TowardsDataScience 博客中文翻译 2019(二百八十二)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

自动化对经济的影响

原文:https://towardsdatascience.com/impact-of-automation-on-the-economy-33ef17352f5b?source=collection_archive---------14-----------------------

这篇文章是为 Darakhshan Mir 博士在巴克内尔大学的计算机和社会课程写的。我们讨论技术中的问题,并用伦理框架来分析它们。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Rock’n Roll Monkey on Unsplash

在一个自动驾驶汽车、智能语音助手和网飞推荐的世界里,有必要就人工智能如何影响社会进行对话。

最近一段时间,我们看到人工智能(AI)出现了巨大的增长。人工智能系统正变得越来越普遍。通常,关于人工智能的讨论围绕着自动化如何影响就业市场。在这篇文章中,我试图回答这个问题,主要是引用弗曼等人的观点。下面,我将讨论就业市场的趋势,以及自动化影响总体经济格局的几种方式。

—就业市场的趋势

1942 年,经济学家约瑟夫·熊彼特创造了短语创造性破坏,指的是一个过程,通过这个过程,一个现有的生产系统被一个更具创新性的系统所取代,从而提高劳动生产率【2】。这样的过程产生了“经济失败者”,他们注定会在变革中遭受损失。一些人可能会被减薪,而另一些人可能会完全失业。凯恩斯将后者描述为,

“由于我们发现节约使用劳动力的方法的速度超过了我们发现劳动力新用途的速度而导致的失业”

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 1: A look at which jobs are more likely to be automated based on the skills required for those jobs [6]. If you’re curious about the probability of computerization for a specific job, check out https://willrobotstakemyjob.com/. The estimates are based on US data.

历史证据表明,虽然某些工作可能面临迫在眉睫的风险,但从长远来看,新的工作通常会出现在互补行业[4]。虽然说起来容易做起来难,但重要的是人们要适应这个不断变化的市场。不幸的是,我们已经看到了劳动力参与率的“长期下降”,因为个人无法跟上工作场所所需的技能。这提出了一个关键问题。

谁该为缺乏劳动力参与负责?

使用一组(例如工程师)作为建立系统的手段,将另一组人(例如低技能劳动者)排除在工作之外,技术部门应该受到指责吗?这种排斥在资本主义经济中似乎很难避免,因为企业总是竞相(通过创新)实现利润最大化。那么,是我们的教育制度不能使个人为新的工作做好准备吗?还是政府对人工智能的发展监管过于宽松?

这些都是很难回答的问题,也没有放之四海而皆准的解决方案。即使一个有自动化的社会与没有自动化的社会产生相同或更大的经济产出,忽视(尽管是无意的)最脆弱的利益相关者(即低技能工人)的需求也是不公平的。在这种情况下,我们能希望做的最好的事情就是投资再培训工人,以促进公共利益。

—AI 成长的副作用

初创企业的进入壁垒

自本世纪初以来,人工智能相关的初创企业每天都在获得更多的资金[7]。然而,像谷歌和百度这样的科技巨头主导了大部分投资,而其他公司(科技或其他)则被留下来追赶。这给创造“成熟的人工智能经济”带来了一些挑战,在某种程度上,这为现有者和进入者提供了公平的竞争环境。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 2: Top 35 high tech companies invest a whopping $18-27 bn in AI. Here, M&A refers to mergers and acquisitions and PE refers to Private Equity. To learn more, check the full MGI report.

随着互联网的成熟,我们观察到客户停止使用现有平台并转向新平台的“转换成本”越来越高。像谷歌搜索这样的平台享有先发优势,能够收集他们的用户数据以进一步巩固他们的市场优势。大多数人工智能应用依赖于机器学习[7],因此大数据集的不可用性对人工智能初创公司来说是一个重大障碍。

一些人认为,那些花费资源精心制作一个好数据集的公司应该有权根据需要分发它。另一方面,有理由相信数据本身属于用户。为了解决这些对立的利益相关者利益,[1]提出了数据可移植性的概念,它“允许客户将他们的数据从一个提供商带到另一个提供商。”虽然这是朝着正确方向迈出的一步,但作者也承认,需要进一步的工作来确定大型数据集如何影响市场。

关于数据的可移植性,有关于数据安全性的问题,以及客户是否应该能够“拥有”基于人工智能的应用程序对其行为做出的推断[8]。因此,任何未来的监管第三方机构的作用是确保公司遵守道德数据实践标准,并将用户的福祉(身体、社会或情感)放在首位。

收入不平等

自动化的怀疑者担心人工智能会导致收入水平的巨大差异。弗曼等人写道,

“替代非熟练工人和补充熟练工人的技术将导致非熟练工人的相对工资下降”

这种担忧导致人们重新审视诸如普遍基本收入(UBI)、工资补贴和就业保障等提议。可以理解的是,这些提议没有一个是万无一失的,否则早就付诸实施了。尤其是 UBI,它看起来雄心勃勃,因为除了每年 1 万亿美元的融资之外,它还需要增加近 50%的税收[1]。

正如我们一次又一次看到的那样,收入不平等会导致已经处于不利地位的社会阶层陷入恶性反馈循环。在人工智能取代低技能劳动力的背景下,缩小贫富差距的最佳政策是什么?

—最终想法

我们的社会离“人工智能接管”(一般的人工智能)还很远,我们还没有看到该领域的突破,尽管机器学习中特定任务的进步已经吸引了所有人。然而,这不应该成为我们不去思考如何监管人工智能的借口。

低技能工人尤其容易受到自动化的影响,其中一些人甚至无法从失业中恢复过来。此外,作为一家初创企业,由于缺乏竞争和无法获得“标准化数据集,进入该领域变得越来越困难所有这些都引发了一系列伦理讨论,比如谁应该为工作岗位的流失指责以及谁拥有用户数据的权利,这是每个人工智能应用程序所依赖的关键。

世界各地的政策制定者都试图设计出监管人工智能的框架。然而,正如[9]所指出的,他们都没有讨论他们对未来社会的愿景。这项研究的作者认为,只有了解我们未来的优先事项,我们才能全面解决这篇文章中提出的问题。

参考

[1]弗曼,杰森和罗伯特·西曼。“人工智能与经济。”创新政策与经济 (2019)。

[2]熊彼特,约瑟夫。“创造性破坏。”资本主义、社会主义和民主 825 (1942)。

[3]凯恩斯,约翰·梅纳德。1930.“我们子孙后代的经济可能性。”劝导随笔 (2010)。

[4]戴维·h·奥特尔,“为什么仍然有这么多工作?工作场所自动化的历史和未来。”《经济透视杂志》 (2015)。

5 经济顾问委员会。总裁经济报告 (2016)。

[6]弗雷、卡尔·贝内迪克特和迈克尔·奥斯本。"就业的未来:工作对计算机化有多敏感?"技术预测与社会变革 (2017)。

[7]布欣,雅克等人。艾尔。“人工智能:下一个数字前沿?” MGI 报告,麦肯锡全球研究院(2017 年 6 月)。链接

[8]塔克,凯瑟琳。“隐私和创新。”载于创新政策与经济,第 11 卷(2012)。芝加哥:芝加哥大学出版社。

[9] Cath,Corinne 等人,“人工智能和‘好社会’:美国、欧盟和英国的方法。”科学与工程伦理 (2018)。

[10]史蒂文·n·德劳夫,“持久收入不平等理论”经济增长杂志 1.1 (1996)。

如果你喜欢这个,请看看我的其他媒体文章和我的个人博客。请在下面评论我该如何改进。

自然语言处理中使用迁移学习的影响

原文:https://towardsdatascience.com/impact-of-using-transfer-learning-in-nlp-59ffc4ffb806?source=collection_archive---------30-----------------------

我们分析了基于从零开始训练的语言模型或使用语料库 wikitext-103 的预训练模型对电影评论情感进行分类的影响

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Riccardo Annandale on Unsplash

背景

在 NLP 的不同分类工作中,我们使用了 ULMFiT 。我们可以在用于推文姿态分类的NLP 迁移学习和用于文本分类的通用语言模型微调-ULMFiT 中找到两篇关于这种方法的优秀文章。

ULMFiT 已经在 fastai 库的版本 1 中实现了,他们开发了一些技术,使得迁移学习变得非常方便。

原始文件中,ULMFiT 包括三个阶段:

  • 使用通用领域数据集在捕获高级自然语言特征的语料库上训练语言模型。
  • 调整和微调第一阶段创建的语言模型,并使用迁移学习在目标数据集上创建新的模型语言。
  • 使用在第二阶段调整的模型语言学习来创建和微调分类器。

本文的主要目的是衡量从第三阶段(分类器)、从预先训练的语言模型(第二阶段)或直接从零开始之间的差异和影响。

换句话说,第二阶段模型是在有和没有迁移学习的情况下创建的,比较初始结果。

在本文的第一部分,我们将导入数据集并执行必要的数据转换操作。

然后,我们将测量使用从另一个已经训练好的模型接收迁移学习的语言模型的影响,或者直接从数据集创建语言模型的影响,并比较两种结果。

最后,我们将使用上一节中创建的最好的语言模型来开发 NLP 上的情感分类器。

数据集

用于二元情感分类的数据集由 Andrew Maas 等人管理,包含 IMDB 上总共 100,000 条评论。其中 25,000 个标记为阳性和阴性用于训练;另外 25,000 个被标记用于测试。

还有另外 50,000 个未标记的数据,我们将用于创建我们的模型语言学习。

df = pd.read_csv(path/'texts.csv')
df.head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第 1 部分-导入数据集和要素工程

“由于文本是由单词组成的,不能直接对它们应用数学函数,我们首先必须将它们转换成数字。在 fastai 中,这是通过两个不同的步骤完成的:标记化和数值化。在 fastai API 中,TextDataBunch 为我们做了这些*。”

%reload_ext autoreload
%autoreload 2
%matplotlib inline
from fastai.text import *
path = untar_data(URLs.IMDB_SAMPLE)
data_lm = TextDataBunch.from_csv(path, 'texts.csv')

标记化

data = TextClasDataBunch.from_csv(path, 'texts.csv')
data.show_batch()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数字化

一旦我们从文本中获得了标记,TextDataBunch 就会通过创建一个包含所有使用过的单词的列表来转换成整数。默认情况下,最大词汇量为 60,000,并替换那些没有被未知令牌 UNK 切断的词汇。

从 id 到令牌的对应关系存储在一个名为 itos 的字典中的 vocab 属性中。

data.vocab.itos[:10]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在,如果我们查看数据集,我们会看到标记化的文本如下:

data.train_ds[0][0]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果我们看所有的火车,都是数字:

data.train_ds[0][0].data[:10]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第 2 部分—创建语言模型学习

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Conor Luddy on Unsplash

语言建模

“一个语言模型试图通过层次化的表征来学习自然语言的结构,因而既包含低级特征(词的表征),也包含高级特征(语义)。语言建模的一个关键特征是它是生成性的,这意味着它的目标是在给定一个单词序列的情况下预测下一个单词。它能够做到这一点,因为语言模型通常是以无监督的方式在非常大的数据集上训练的,因此该模型可以以比单词嵌入更深入的方式“学习”语言的句法特征。

在他的文章中,Sebastian Ruder 做了一个非常优雅的工作,强调了为什么语言建模对于广泛的自然语言处理任务如此强大。未标记的语言数据相对容易获得(它可以以大型文本语料库的形式免费获得),因此通过向语言模型提供足够大的数据集,现在可以对数十亿个单词进行无监督的预训练,同时融入更深入的语言语法知识。"⁴

我们将使用 fastai 的 API 中的 language_model_learner,这是一种学习者⁵,它采用一组配置,从数据集中假设一个语言模型。

Language_model_learner 承认属性“pre-trained (Bool)”,其默认选项为 True,并假设每种语言都有一个迁移学习模型。

从头开始创建我们的语言模型学习

这种技术已经被用来为不同的习语创建一个语言模型,这里是一篇文章在 Vietnamese⁶.有一个极好的例子

path = untar_data(URLs.IMDB)
data_lm = (TextList.from_folder(path)
.filter_by_folder(include=['train', 'test', 'unsup'])
.split_by_rand_pct(0.1)
.label_for_lm()
.databunch(bs=bs))data_lm.save('data_lm.pkl')

“我们必须为语言模型使用一种特殊的TextDataBunch,它会忽略标签(这就是为什么我们在任何地方都放 0 ),在将它们连接在一起之前,会在每个时期对文本进行洗牌(仅用于训练,我们不会对验证集进行洗牌),并且会发送按顺序读取该文本的批处理,目标是句子中的下一个单词。*"

data_lm = load_data(path, 'data_lm.pkl', bs=bs)
data_lm.show_batch()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这里,我们向 API 表明,我们希望“学习”模型不采用预训练迁移学习的默认权重,而是在不假设预训练的情况下开始:

learn = language_model_learner(data_lm, AWD_LSTM, **pretrained=False**, drop_mult=0.3)

在调整学习率和训练之后,我们获得了 0.284114 的准确度

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用预训练模型进行迁移学习

在 fastai 中使用的更大数据集上预先训练的模型是维基百科的一个清理过的子集,名为 wikitext-103

“我们将使用英语语言的‘知识’来构建我们的分类器,但首先,像计算机视觉一样,我们需要根据我们的特定数据集微调预训练模型。因为人们在 IMDB 上留下的评论的英文和维基百科的英文不一样,我们需要稍微调整一下模型的参数。此外,可能有一些词在评论数据集中非常常见,但在维基百科中几乎不存在,因此可能不是模型训练的词汇表的一部分。*"

learn = language_model_learner(data_lm, AWD_LSTM, drop_mult=0.3)
learn.lr_find()
learn.recorder.plot(skip_end=15)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

准备要在分类器中使用的模型

不仅要为下一个零件保存模型,还要保存它的编码器。这一部分非常重要,因为要重用这个模型,单词列表和它们的 id 必须相同。

**learn.save_encoder('fine_tuned_enc')**

第 3 部分—电影评论情感分类器:采用模型

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Georgia Vagim on Unsplash

path = untar_data(URLs.IMDB)
data_clas = (TextList.from_folder(path, vocab=data_lm.vocab)
.split_by_folder(valid='test')
.label_from_folder(classes=['neg', 'pos'])
.databunch(bs=bs))data_clas.save('data_clas.pkl')
data_clas = load_data(path, 'data_clas.pkl', bs=bs)

我们创建分类器,并将其指定为前一阶段的编码器。

learn = text_classifier_learner(data_clas, AWD_LSTM, drop_mult=0.5)
**learn.load_encoder('fine_tuned_enc')**

结果……

左边,模型语言从零开始,右边,模型用迁移学习:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后,在调整学习率和一些额外的训练之后,我们在电影评论数据集上获得了一个准确率为 0.943960 的情感分类器。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

摘要

我们已经试验了来自先前数据体的预训练语言模型和从头开始的语言模型的应用,在使用迁移学习时获得了更好的结果。

使用 fastai 和 UMLFiT 的工具,我们可以通过维基百科的数据语料库来应用这一点,以任何语言进行预训练,这在 NLP 中是一个很大的优势,因为工具和数据集的偏见是英语。

最后,记住在语言模型和文本分类器之间保持编码器是非常重要的。这个练习的基础是来自 [fastai 课程](https://fast.ai course/)第 3 和第 4 课的 token,在那里你可以找到完整的代码和对数据集的访问。

我希望这篇文章有助于看到在 NLP 中使用迁移学习的积极影响,类似于在计算机视觉中使用的迁移学习。欢迎任何更正、评论或想法。

参考

[1]https://course.fast.ai/

[2]http://ai.stanford.edu/~amaas/

[3]https://www.imdb.com/

[4]https://towards data science . com/transfer-learning-in-NLP-for-tweet-stance-class ification-8ab 014 da 8d de

[5]https://docs.fast.ai/basic_train.html#Learner

[6]https://towards data science . com/pre-trained-language-model-in-any-language-7531 ea 7217d 4

[*]本文中的许多概念都直接来自于第 3 课和第 4 课 fast.ai 课程

不完美的信息,不完美的超人人工智能

原文:https://towardsdatascience.com/imperfect-information-imperfect-superhuman-ai-58eaba48fe3?source=collection_archive---------29-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

[1]

应该允许 AI 参与我们的赌博吗?卡耐基梅隆大学的脸书人工智能研究人员刚刚创造了一种可以在扑克中击败人的人工智能。这是一项巨大的成就。在扑克游戏中,没有最佳答案,也没有要寻找的一系列赢棋。相反,最大化回报和最小化风险是最好的赌博。但是,我们能负责任地运用训练有素的代理人在不完全信息的情况下取得成功吗?这些类型的超人人工智能会在哪些方面下错赌注,我们如何围绕它们设计系统以造福社会?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

[2]

我们来看一个思维实验。医疗诊断和治疗是机器学习研究中最发达和最多产的领域之一。诊断在很大程度上是一个分类问题。你有大量来自患者的输入数据,比如症状数据、环境数据等。机器学习算法用于在大量数据中寻找模式,以诊断患者。通常算法发现的模式是如此错综复杂,以至于专业人士并不总是能理解它们。诊断是一个经典的机器学习应用,伴随着它的伦理问题。为了实验起见,我们假设医生非常敏锐或者一个 ML 算法准确地给出了正确的诊断。

然而,推荐治疗并不是一个标准的分类问题。这是一个不完全信息的游戏。你必须根据个人情况和诊断结果来选择最佳的治疗方案。算法的工作是观察治疗、诊断和个人的各种成功机会,并推荐最佳的治疗方案来挽救他们的生命。他们可能没有时间接受更多的治疗,所以每一个建议都必须是高质量的。这个问题是脸书和 CMU 的研究可能被应用的地方。毕竟,如果每个人都得到正确的诊断,并给予尽可能最好的治疗,那难道不是一个值得建设的世界吗?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

[3]

可悲的是,这可能是不可能的。如果我们让一个人工智能代理来推荐治疗,我们可能会发现和医生一样的盲点。推荐治疗方法的代理人可能不得不考虑各种疗法的成功率,作为要分析的许多数据特征的一部分。成功率可能会被 p-hacked,或者不诚实地操纵统计数据,使其高于实际水平。例如,立普妥,一种宣称有 36%成功率而实际只有 1%成功率的药物。人工智能代理推荐治疗方法并查看成功率等指标可能会下错赌注。

医生也可能成为错误成功率的牺牲品。这个弱点就是问题所在。医生和超人 AI 都有同样的缺陷:腐败或有偏见的数据。但是医生可以为他们的诊断提供理由。尽你所能去寻找,但是在 50,000 个矩阵中找出以不同的顺序方式相乘的确切模式并正确识别其原因是不现实的。也许你可以制造一个人工智能来理解并把人工智能的见解翻译成人类的理解,但是你会再次遇到同样的问题。

即使我们能够在信息不完善的领域超越人类,我们仍然依赖于手头问题的准确和无偏见的数据。赌一赌这是否可能是人工智能未来的一个关键问题。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

[4]

图片来源:【1】【2】【3】【4】

使用 Python Pandas 数据帧与最小堆数据结构

原文:https://towardsdatascience.com/implement-a-min-heap-to-solve-performance-issue-with-data-processing-1f7f891a4ec0?source=collection_archive---------17-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Marian Kroell on Unsplash

介绍

最近我花了很多时间研究基本的数据结构,包括栈、队列、堆和树。它教会了我用以下不同的方式解决问题(代码):

  • 总是寻找最简单、最有效、最优雅的方式(可读性是金)
  • 审查,审查和审查,以提高代码的效率(是否有重复的部分?我能换一种方式做吗?有些步骤是多余的吗?)
  • 在选择你可以使用的工具(框架、数据结构、算法)时,要实际考虑

阅读理论只是一个开始,在我看来,巩固所学知识的最好方法是将其应用到现实世界的问题中。幸运的是,我参与的一个项目中有一部分可以利用Min Heap的实现,也就是通常所说的Priority Queue

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

An example of a Binary Min Heap, visualised in a tree structure.

我在下面几节中概述了实现:

  • 问题是
  • 在最小堆实现之前
  • 在最小堆实现之后
  • 参考

问题是

任务很简单:从所有满足包含依赖规则的输入表中找到所有列对。规则是,对于每个列对,一列的所有值都必须存在于它的列对中。下面是为了更容易理解的例子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

In Example 1, there were 2 checks performed: 1) column A in column B and 2) column B in column A. The valid column pair in this example is 2) column B in column A, because all values in column B exists in column A (inclusion dependency rule satisfied). In Example 2, both checks 1) column C in column D and 2) column D in column C are invalid, because the value LL300 only exists in column D.

现在,您可能会想,为什么要让事情变得复杂呢?您可以通过检查每一对,一列中的所有值是否都包含在另一列中,来应用强力方法。问题是大约有 900 个表,每个表都有不同数量的列。简而言之,当使用暴力方法时,要花很长时间来完成检查。

在最小堆实现之前

我最初的方法比暴力方法稍微好一点,但是,它仍然需要很长时间来运行。本质上,应用了Single Pass算法。这意味着在找出列对时,所有数据(或值)将只被读取一次,而不是多次(想想暴力方法,您将多次读取相同的列/值)。

为此,我使用pandas库构建了一个单独的data frame,存储所有表中的所有列,包括它们的值。最后的data frame看起来是这样的。

A       B     C
index
0        nan     0.0   0.0
1        1.0     nan   1.0
2        2.0     nan   2.0
3        nan     3.0   3.0

让我通过这些步骤来了解上面的data frame:

  • 对于每个表中的每一列,将其唯一值存储在一个list中,按升序排序
  • 从所有列中获取所有唯一值,将它们存储在一个list中,按升序排序,例如按照上述data frame[0, 1, 2, 3]
  • 构造一个data frame并将其index设置为包含来自步骤 2 的所有唯一值的list
  • 通过index上的left join合并从步骤 1步骤 3 的所有列表(当一列没有特定值时,会在最后的data frame中产生一个nan条目),例如,列A没有[0, 3]

注意,由于*nan*值的形成,*data frame*中的列类型不是*float64*。那些列的原始值实际上是*int64*

在迭代data frame中的每一行之前,我们需要初始化一个包含初始包含依赖列列表的dictionary。等等,什么?让我给你展示一下dictionary的样子,让你明白这一点。

inclusion_dict = {'A': ['B', 'C'],
                  'B': ['A', 'C'],
                  'C': ['A', 'B']}

现在更有意义了?因此,基本上,我们初始化所有可能的列对(例如,列 B 中的列 A,列 C 中的列 A,表示为字典条目'A': ['B', 'C'],等等。)作为我们迭代前的起点。当我们迭代data frame中的每一行时,inclusion_dict将会相应地更新(更多信息见下文)。

好了,让我们来谈谈迭代。下面是执行迭代的代码。

def sp_algorithm(dataframe, inclusion_dict): # for each value, get all columns that contains it
    for val in dataframe.index: cols_list = dataframe.columns[dataframe.isin([val]).any()] # for each column in inclusion_dict.keys(), intersect its values with cols_list to get the remaining column pairs candidates
        for key_col in inclusion_dict.keys(): column_val = dataframe.loc[val, key_col]# if the current column value is null, then do nothing
            if (column_val == column_val) & (column_val != ''):
                col_dict[key_col] = list(set(col_dict[key_col]).intersection(cols_list))

提醒一下,这是data frame

A       B     C
index
0        nan     0.0   0.0
1        1.0     nan   1.0
2        2.0     nan   2.0
3        nan     3.0   3.0

data frame行的每次迭代中,会发生以下情况:

  • cols_list:获取包含当前索引值的所有列(只是它们的名称)val
  • 对于inclusion_dict中的每一列(字典的key),根据位置.locdata frame中获取其值
  • 检查第二步的值是否为nan和/或'',如果不是,通过与cols_list相交更新inclusion_dict。例如,在上面的data frame的第一次迭代中,cols_list将是['B', 'C'],因为它们包含值0。当我们查找inclusion_dict时,key_col = 'A'将被跳过,因为它在if statement中返回False,因为它是nan(参见data frame中索引0处的A列)。对于key_col = 'B',我们将把它当前的inclusion_dict值与cols_list相交,这样我们就有了['C']。这是因为['A', 'C'] ['B', 'C']相交的就是['C']。对于key_col = 'C',其inclusion_dict剩余值将为['B']

嗯,上面的一系列代码实际上工作并产生了我想要的结果,但是,运行时间非常慢!所以,我开始问自己一个问题,如果数据库大得多,如果有更多的表和列要处理怎么办?

此外,每次在sp_algorithm运行时代码中出现错误,我都必须从头重新运行整个程序,这花费了我很长时间。代码看起来也不可读,难以理解,并且可能不可持续。

在最小堆实现之后

多亏了Min Heap数据结构,我能够将运行时间提高 10 到 60 倍,这取决于数据库(大小、表计数、列计数、唯一值计数等。)!

无论如何,这是一个巨大的进步!我不必整夜运行我的代码,希望没有任何东西会中断,并在早上第一件事就是检查它。现在,我可以随时运行代码,并在几分钟内得到结果,而不是几个小时。

事不宜迟,下面是实现代码。

# inclusion_dict from above
inclusion_dict = {'A': ['B', 'C'],
                  'B': ['A', 'C'],
                  'C': ['A', 'B']}# instead of a data frame, a dictionary is used to store columns from all tables
# column_dict stores sorted (ascending order) unique values from all columns from all tables
column_dict = {'A': [1, 2], 
               'B': [0, 3],
               'C': [0, 1, 2, 3]}def sp_algorithm(column_dict):
    # initialise min heap
    min_heap = [] for column in column_dict:
        vals = column_dict[column] for val in vals:
            tup = (val, column)
            heapq.heappush(min_heap, tup) while min_heap: # get the smallest value in the heap
        att = [] current_smallest, var = heapq.heappop(min_heap)
        att.append(var) # pop all elements where values are equal to current smallest and put them in att list
        while min_heap and min_heap[0][0] == current_smallest:
            next_var = heapq.heappop(min_heap)[-1]
            att.append(next_var) # update inclusion_dict
        for a in att:
            if a in inclusion_dict:
                inclusion_dict[a] = list(set(inclusion_dict[a]).intersection(att))# final inclusion_dict should look like
inclusion_dict = {'A': ['C'],
                  'B': ['C'],
                  'C': []}

inclusion_dict最后的结果基本上说:

  • 列 A 可能依赖于列 C,因为它的所有值都在列 C 中
  • 列 B 可能依赖于列 C,因为它的所有值都在列 C 中
  • 列 C 在此上下文中没有依赖关系,因为列 A 和列 B 都不包含列 C 中的所有值

我希望这能给你一个在项目中实现*Min Heap*的潜在好处的想法。正如我前面提到的,思考并重新思考你可以使用哪些工具,并明智地选择。

Min Heap背后的理论不在本文讨论范围之内。本文的主要目的是向您展示一个真实世界中的Min Heap实现。别担心,只要在谷歌上搜索一下,你就会在Min Heap上找到大量的资源。

参考

上面描述的技术来自一篇讨论单程包含依赖识别(SPIDER) 算法的论文。你可以在这里了解更多信息

前往章节 2.2.22.2.3 了解蜘蛛算法的更多细节。

Heap理论而言,你可以在谷歌上找到很多参考资料。这里有一本你可以读。

最后的话

这是我写的第一篇有点冗长的文章,所以,如果你觉得有用,请留下你的反馈、评论或给我鼓掌或加书签。

欢迎提出任何问题或在下面留下建议。

干杯!🙂

使用 Python 在不到 3 分钟的时间内实现人脸检测

原文:https://towardsdatascience.com/implement-face-detection-in-less-than-3-minutes-using-python-9f6b43bb3160?source=collection_archive---------5-----------------------

使用这个简单的代码将人脸检测功能添加到您的应用程序中

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Face detection (Image by teguhjati pras from Pixabay)

人脸检测是人工智能最常见的应用之一。从智能手机中的相机应用到脸书的标签建议,人脸检测在应用程序中的使用每天都在增加。

人脸检测是计算机程序在数字图像中识别和定位人脸的能力。

随着应用程序中对人脸检测功能的需求不断增加,每个人都希望在自己的应用程序中使用人脸检测,这样他们就不会在竞争中落后。

在这篇文章中,我将教你如何在不到 3 分钟的时间内为自己建立一个人脸检测程序。

如果尚未安装以下 python 库,则需要进行安装:

opencv-python
cvlib

下面是导入所需 python 库、从存储中读取图像并显示它的代码。

# import libraries
import cv2
import matplotlib.pyplot as plt
import cvlib as cvimage_path = 'couple-4445670_640.jpg'
im = cv2.imread(image_path)
plt.imshow(im)
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Couple Photo (Image by Sonam Prajapati from Pixabay)

在加载的图像中检测人脸,在检测到的人脸周围绘制一个边界框,并显示带有检测到的人脸的最终图像的代码如下。

faces, confidences = cv.detect_face(im)# loop through detected faces and add bounding box
for face in faces: (startX,startY) = face[0],face[1]
    (endX,endY) = face[2],face[3] # draw rectangle over face
    cv2.rectangle(im, (startX,startY), (endX,endY), (0,255,0), 2)# display output        
plt.imshow(im)
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Result of Face Detection on couple image

你已经准备好了面部检测程序。就这么简单!

觉得这个帖子有帮助? 在下面留下你的想法作为评论。

点击这里 阅读我其他关于 AI/机器学习的帖子。

要了解更多关于 cvlib 库的信息,可以访问下面的链接。

[## cvlib

用于 Python 的高级易用开源计算机视觉库。它的开发重点是实现简单的…

www.cvlib.net](https://www.cvlib.net/)

为了理解人脸检测是如何工作的,这里有一些进一步的阅读:

[## FaceNet:人脸识别和聚类的统一嵌入

尽管最近在人脸识别领域取得了重大进展,但实现人脸验证和识别…

arxiv.org](https://arxiv.org/abs/1503.03832) [## 卷积神经网络| Coursera

从 deeplearning.ai 学习卷积神经网络。本课程将教你如何构建卷积神经网络…

www.coursera.org](https://www.coursera.org/learn/convolutional-neural-networks) [## 深度学习计算机视觉 CNN、OpenCV、YOLO、SSD 和 GANs

深度学习计算机视觉使用 Python & Keras 实现 CNN、YOLO、TFOD、R-CNN、SSD & GANs+A 免费…

www.udemy.com](https://www.udemy.com/master-deep-learning-computer-visiontm-cnn-ssd-yolo-gans/)

用 Q-Learning 实现网格世界

原文:https://towardsdatascience.com/implement-grid-world-with-q-learning-51151747b455?source=collection_archive---------3-----------------------

强化学习在网格游戏中的应用

之前的故事中,我们谈到了如何使用值迭代实现一个确定性的网格世界游戏。这一次,让我们进入一种更普遍的强化学习形式——Q 学习。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

提高一个档次

鉴于 V(s) 是从状态到该状态的估计值的映射,Q 函数— Q(s,a) 只是与 V 函数不同的一个分量。当你处于特定的状态时,不要认为你得到了一个值,向前想一步,你处于一种状态,通过采取特定的行动,你得到了相应的值。本质上,这两种功能没有区别,只是通过将状态与行动绑定在一起方便了我们的生活。例如,回想一下使用值迭代的 grid world 的结果,我们得到了每个状态的估计值,但是为了拥有我们的策略 π(s,a) ,这是从状态到动作的映射,我们需要更进一步,选择可以达到下一个状态的最大值的动作。然而,在 Q 函数中,状态和动作首先是成对的,这意味着当一个人拥有最佳 Q 函数时,他就拥有该状态的最佳动作。

除了 Q-function,我们还将为我们的游戏增添更多乐趣:

  • 代理操作是不确定的
  • 报酬随比率γ衰减

非确定性意味着代理将不能去它想要去的地方。当它采取一个动作时,它将有可能在不同的动作中崩溃。

衰变率γ在 0 和 1 之间。它表示代理人对未来奖励的关心程度,1 表示奖励永不衰减,代理人同样关心未来的所有奖励,0 表示代理人只关心当前状态的奖励。这个因素有助于调整代理人的长期愿景——想象一下像围棋这样的战略游戏,有时在当前状态下看似愚蠢的行动在长期利益和胜利方面是值得的。

就是这样!让我们着手实施。[ 完整代码

电路板设置

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Board

董事会设置与之前讨论的基本相同,唯一的区别是代理采取行动。当它采取行动时,它将有 0.8 的概率进入期望的状态,并有相等的概率处于垂直状态。也就是说,如果代理人选择向上,那么它有 0.8 的概率向上,0.1 的概率向左和向右。

在确定代理的下一个位置时,我们将采取返回chooseActionProb()的操作,并利用我们已经定义的nxtPosition()函数。

nxtPosition()函数接受一个动作,验证该动作的合法性并返回该动作的状态。

代理人

让我们跳到主课程——如何通过迭代计算和更新 Q 值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Q-value update

首先,在每一步,代理采取行动a,收集相应的奖励r,并从状态s移动到s'。所以每一步都要考虑一整对(s, a, s',r)

其次,我们给出当前 Q 值的估计,它等于当前奖励加上下一状态的最大 Q 值乘以一个衰减率γ。值得注意的一点是,我们将所有中间奖励设置为 0,因此代理在结束状态之前无法收集任何非零奖励,无论是 1 还是-1。(这不是强制性的,你可以尝试其他奖励,看看代理如何行动)

最后,我们通过将α乘以一个时间差(新的估计值和当前值之间的差)来更新当前 Q 值的估计值。

q 值初始化

整个更新与值迭代非常相似,尽管 Q value 认为动作和状态是一对。当初始化 Q 值时,我们需要将每个状态和每个动作设置为 0,并将它们存储在字典中作为Q_value[state][action]=0

行动

就采取行动而言,仍将基于我们在勘探&开采中讨论的勘探率。当代理利用状态时,它将根据当前估计的 Q 值采取最大化 Q 值的行动。

更新 Q 值

类似于数值迭代, Q 数值更新也是以相反的方式进行,每次更新将在游戏结束时进行。

在游戏结束时,我们显式地将最后一个状态的所有行为设置为当前奖励,即 1 或-1,但这部分是可选的,它有助于更快地收敛。以下部分与值迭代相同,只是我们在这里加了一个decay_gamma(注:self.decay_gamma * reward应该是self.decay_gamma * reward + 0作为我们设置为 0 的当前状态的奖励)。

玩游戏

我们开球吧!玩了 50 轮之后,我们有了下面的状态-动作对的更新。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

result after 50 rounds

我们从(2, 0)开始,最大行动应该是值为0.209up,然后到达(1, 0),从那里最佳行动仍然是值为0.339up,以此类推……最后我们得到我们的策略up -> up -> right -> right -> right。我们可以看到,通过传播和更新,我们的代理足够聪明,可以在每个状态下产生最佳行动。Q-learning 的一个好处是,与基本值迭代相比,我们可以直接获得每个状态下的最佳行动。

请在这里查看完整代码,如果您发现任何警告,欢迎评论或投稿!

在 R 中实现随机森林

原文:https://towardsdatascience.com/implement-random-forest-in-r-b00b69eb8501?source=collection_archive---------13-----------------------

随机森林在乳腺癌患者分类中的实际应用

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Rural Explorer on Unsplash

什么是随机森林(RF)?

为了理解 RF,我们需要首先理解决策树。 Rajesh S. Brid写了一篇关于决策树的详细文章。我们不会过多地讨论决策树的定义,因为这不是本文的目的。我只想快速总结几点。决策树是一系列是/否问题。对于树的每一级,如果你的答案是肯定的,你就属于一个类别,否则,你就属于另一个类别。你将回答这一系列是/否的问题,直到你到达最后一类。你将被归入那一组。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Taken from here

对于我们用来训练的数据,树工作得很好,但是当涉及到新的数据样本时,它们的表现并不好。幸运的是,我们有随机森林,它是许多具有灵活性的决策树的组合,因此导致了准确性的提高。

在这里,我不会过多地讨论 RF 的细节,因为我们可以从外部的各种来源了解它背后的数学原理。这里的就是其中之一。

本文更多的是关于 RF 在癌症患者分类中的实际应用,所以我将直接进入编码部分。现在让我们打开 Rstudio,动手干一场:)

在 R 中实现 RF

首先,我们需要加载以下包。如果您不能加载它们,很可能您还没有安装它们。所以请在加载下面的包之前先这样做。

library(ggplot2)
library(corrplot)
library(reshape2)
library(ggthemes)
library(dplyr)
library(randomForest)
Wisconsin = read.table(url(paste0("[https://archive.ics.uci.edu/ml/machine-learning-databases/](https://archive.ics.uci.edu/ml/machine-learning-databases/)",
"breast-cancer-wisconsin/wdbc.data")),header=FALSE,sep=",",nrows=570)

我直接从 web 链接中读取数据,并将数据集命名为 Wisconsin。让我们稍微检查一下数据

head(Wisconsin)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

V1 是 ID,所以它与我们这里的分析无关。V2 是分类结果,“M”代表“恶性”,“B”代表“良性”。剩下的只是关于癌症诊断信息的变量。

现在我想把 M 和 B 改成真和假,以便于解释。

Wisconsin$V2 <- Wisconsin$V2 == “M”

预处理数据

首先,我们将数据混洗并分成训练和测试。我们决定七三分成。

set.seed(2019)test_size = floor(0.3 * nrow(Wisconsin))
samp = sample(nrow(Wisconsin), test_size,replace = FALSE)y_train = Wisconsin[-samp,2]
x_train = Wisconsin[-samp,-c(1,2)] #since the first column is just ID
y_test= Wisconsin[samp,2]
x_test = Wisconsin[samp,-c(1,2)] #since the first column is just ID**#convert labels to categorical**
y_train = factor(y_train)
y_test = factor(y_test)

我们应该注意,RF 只在响应变量是一个 因子 时才起作用。刚才我们把‘M’和‘B’转换成 TRUE 和 FALSE 的时候,这个变量的类型是逻辑的。因此,我们需要使用 factor()函数将其转换为 factor。

现在让我们将 x 和 y 组合起来,形成训练集和测试集。

#Create training set and testing set
train = cbind(y_train,x_train)
test = cbind(y_test,x_test)

训练集将用于训练 RF 模型,测试集将用于测试模型的性能。现在让我们给我们的响应变量命名。在这里,我把它命名为“标签”

colnames(train)[1] = ‘label’
colnames(test)[1] = ‘label’

它现在看起来像这样

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

拟合随机森林模型

现在一切准备就绪。我们可以开始拟合模型了。这一步很容易。

包中的“randomForest()”函数使随机森林模型适合数据。除了包括数据集和指定公式和标签之外,该函数的一些关键参数包括:

  1. ntree :要种植的树木数量。默认值为 500。

  2. mtry :每次分割随机选择的变量个数。在这个例子中,我们使用 p 的平方根(p 表示预测值的数量)。请注意,对于回归分析,一般规则是使用 mtry = p/3,这也是该参数在回归中的默认值。

3.重要性:如果为真,模型将计算特征的重要性,以供进一步分析。(默认值=假)

4.邻近度:如果为真,模型将包含一个 N*N 矩阵,代表邻近度。

  1. maxnodes :树可以拥有的最大终端节点数。

6.动作:指定如何处理缺失数据的功能。

由于有 30 个独立变量,我们将 mtry 设为 30 的平方根,然后拟合模型

mtry = sqrt(30)
model_1 = randomForest(label~., data = train, importance = TRUE)

就是这样。简单不是吗?现在我们已经有了一个射频模型

print(model_1)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

出袋 OOB 误差估计率为 3%,这是非常好的,即 97%的准确度。如果我们看混淆矩阵,我们可以看到分类误差相当低。这表明我们的 RF 模型在分类训练集方面表现良好。

让我们用测试集来测试这个模型。

pred_1 = predict(model_1, x_test)
table(y_test, pred_1)accuracy_m1 = mean(y_test == pred_1)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

看起来我们的模型在测试集上表现也很好,准确率达到 95%。

可变重要性

varImpPlot(model_1)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Importance of variables in the model. The higher the rank, the more important the variables

我们可视化绘图的另一种方法是使用 **ggplot 包。**请注意,下面的代码是为了可视化“平均降低准确度”。要得到“平均下降基尼系数”,只需将下面的粗体字改为“MeanDecreaseAccuracy”(无间距)。

importance = importance(model_1)
varImportance = data.frame(Variables = row.names(importance),
 Importance =round(importance[, “**MeanDecreaseAccuracy**”],2))rankImportance=varImportance%>%mutate(Rank=paste(‘#’,dense_rank(desc(Importance))))ggplot(rankImportance,aes(x=reorder(Variables,Importance),
 y=Importance,fill=Importance))+ 
 geom_bar(stat=’identity’) + 
 geom_text(aes(x = Variables, y = 0.5, label = Rank),
 hjust=0, vjust=0.55, size = 4, colour = ‘white’) +
 labs(x = ‘Variables’) +
 coord_flip() + 
 theme_classic()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Mean Decrease Accuracy

结果和我们之前得到的图类似。结果显示变量 V25、V30、V26 和 V23 是最重要的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Mean Decrease Gini

使用平均下降基尼系数,我们得到 V25、V23 和 V26 作为最重要的变量。

结论

本文展示了如何实现一个简单的随机森林模型来解决分类问题。我没有深入研究如何调整参数以优化模型,因为分类的准确度如此之高,我认为简单的模型就足够了。然而,在现实生活中,还有其他更复杂的分类问题需要我们调整参数以获得最佳模型,我将在下一次单独撰写一篇文章。但重要的是要记住总是从简单的模型开始,然后从那里建立模型以获得更好的预测。

谢谢你的时间。我希望这篇文章能帮助你们,尤其是那些以前从未尝试过在 R 中实现 RF 的人,更好地了解如何实现。如果您有任何意见或问题,请告诉我。

祝您愉快,编程愉快:)

使用非最大抑制(NMS)实现平均精度(mAP)

原文:https://towardsdatascience.com/implementation-of-mean-average-precision-map-with-non-maximum-suppression-f9311eb92522?source=collection_archive---------10-----------------------

实现对象检测的度量

写完你的 CNN 物体检测模型后,你可能会认为最艰难的部分已经过去了。衡量你的物体探测器表现如何的标准呢?衡量异议检测的标准是映射。为了实现 mAP 计算,工作从来自 CNN 对象检测模型的预测开始。

非最大抑制

诸如 Yolov3 或更快的 RCNN 的 CNN 对象检测模型产生比实际需要更多的边界框(bbox)预测。第一步是通过非最大值抑制来清理预测。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ground truth bbox (Blue), predicted bbox (light pink), averaged predicted bbox (red)

上图显示了一个图像,其中蓝色矩形是基本事实边界框。浅粉色矩形是预测的边界框,其具有超过 0.5 的客观性,即边界框中存在对象的置信度得分。红色边界框是由浅粉色边界框平均得到的最终预测边界框。浅粉色包围盒到红色包围盒的平均称为非最大值抑制。

https://github.com/eriklindernoren/PyTorch-YOLOv3提供了 Yolov3 预测后的非最大值抑制和 mAP 计算的详细实现,如本文所述。每个 Yolov3 的预测由右上边界框坐标(x1,y1)、左下边界框坐标(x2,y2)、对象置信度(Objectness)和每个类的分类置信度(C1,…C60,如果边界框内容可以被分类为 60 个类别)。对于每个图像,假设预测了 10654 个初始边界框,仅保留 6 个具有高于 0.5 的客观置信度的预测。在 6 个边界框中,彼此具有高重叠(高 IOU)并且预测相同类别的边界框被一起平均。这些步骤的详细说明解释如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

真阳性检测

一旦最终预测被确定,预测的边界框可以相对于地面真实接地框被测量,以产生 mAP 来查看对象检测器做得有多好。为此,需要确定真正阳性的数量。如果预测的边界以 IOU 阈值(0.5)与基本真实边界框重叠,则认为是成功的检测,并且预测的边界框是真的正的。如果预测的边界框与基本事实的重叠小于阈值,则认为是不成功的检测,并且预测的边界框是假阳性。精确度和召回率可以通过真阳性和假阳性来计算,如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

详细的实现如下所示。对于一批中的每个图像,对于图像中的每个预测边界框,如果边界框的预测类别不是图像中的目标类别之一,则将边界框记录为假阳性,否则,检查预测边界框与图像中的所有目标框,并获得与目标框的最高重叠。如果最高重叠大于 IOU 阈值,则认为目标框被成功检测到,并且预测的边界框被记录为真阳性。否则边界框被记录为假阳性。隐藏成功检测到的目标框,并继续循环以检查其他预测的边界框。返回每个预测的对象、其预测的类别以及它是否为真阳性。这些步骤的详细说明如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

地图计算

上述步骤的输出用于计算 mAP。按照反对程度的降序对预测进行排序。从具有最高客观性的预测开始,在每次增量预测之后,测量召回率(真阳性的计数/全局所有目标框的计数)和精确度(真阳性的计数/到目前为止的预测计数),并绘制召回率对精确度曲线。曲线下的区域就是地图。计算的面积为矩形,因此图形的三角化部分被忽略。可以为每一类预测计算 mAP,然后对所有类进行平均。感谢https://medium . com/@ Jonathan _ hui/mAP-mean-average-precision-for-object-detection-45c 121 a 31173对地图的详细讲解。召回率对精确度曲线的绘制如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

dataframe for Recall-Precision graph (left), Recall-Precision graph (right)

详细的实现如下所示。按照客观性降序排列真阳性记录、客观性记录和类别记录。对于每个类,按照排序顺序,在每次增量预测后,从真阳性记录中找出累积的真阳性和假阳性。通过将累积的真阳性分别除以基础真值和预测的数量(真阳性+假阳性),找到相应的召回率和精确度值。计算每一类的曲线下面积。这些步骤的详细说明如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

https://github.com/eriklindernoren/PyTorch-YOLOv3 中的 test.py 和 utils/utils.py 可以参考 NMS 和 mAP 的完整实现。

RNN、LSTM 和 GRU 的实施情况

原文:https://towardsdatascience.com/implementation-of-rnn-lstm-and-gru-a4250bf6c090?source=collection_archive---------4-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Recurrent Neural Network

递归神经网络是一类人工神经网络,其中节点之间的连接沿着时间序列形成有向图。与前馈神经网络不同,递归神经网络使用其内部状态存储器来处理序列。递归神经网络的这种动态行为使得它们非常有用,并且可应用于音频分析、手写识别和一些这样的应用。

Keras 中简单的 RNN 实现。

数学上,简单的 RNN 可以用公式表示如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其中 x(t)和 y(t)是输入和输出向量,Wᵢₕ、Wₕₕ和 Wₕₒ是权重矩阵,fₕ和 fₒ是隐藏和输出单元激活函数。

具有 2 个简单 RNN 层的 RNN 的实现可以如下所示,每个层具有 32 个 RNN 单元,随后是用于 10 个类别分类的时间分布密集层:

def get_model(_rnn_nb, _fc_nb):spec_start = Input((256,256))
 spec_x = spec_start
 for _r in _rnn_nb:
 spec_x = SimpleRNN(_r, activation=’tanh’, dropout=dropout_rate, recurrent_dropout=dropout_rate, return_sequences=True)(spec_x)for _f in _fc_nb:
 spec_x = TimeDistributed(Dense(_f))(spec_x)
 spec_x = Dropout(dropout_rate)(spec_x)spec_x = TimeDistributed(Dense(10))(spec_x)
 out = Activation(‘sigmoid’, name=’strong_out’)(spec_x)_model = Model(inputs=spec_start, outputs=out)
 _model.compile(optimizer=’Adam’, loss=’binary_crossentropy’,metrics = [‘accuracy’])
 _model.summary()
 return _model

参数:

rnn_nb = [32, 32] # Number of RNN nodes. Length of rnn_nb = number of RNN layers
fc_nb = [32] # Number of FC nodes. Length of fc_nb = number of FC layers
dropout_rate = 0.5 # Dropout after each layer

模型总结如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Summary.

LSTM 在喀拉斯的实施。

LSTM,也被称为长短期记忆,是一种具有反馈连接的 RNN 架构,这使得它能够执行或计算图灵机可以执行的任何事情。

单个 LSTM 单元由一个单元、一个输入门、一个输出门和一个遗忘门组成,这有助于单元记忆任意时间的值。这些门控制着进出 LSTM 细胞的信息流。

LSTM 单元的隐藏状态 hₜ可以计算如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里, *i,*f,o分别称为输入、遗忘和输出门。注意,它们具有完全相同的方程,只是具有不同的参数矩阵( W 是在前一隐藏层和当前隐藏层的递归连接, U 是将输入连接到当前隐藏层的权重矩阵)。

LSTM 的 Keras 实现具有 2 层 32 个 LSTM 单元,每层用于上述 10 个类别分类的任务,可以说明如下:

def get_model(_rnn_nb, _fc_nb):spec_start = Input((256,256))
 spec_x = spec_start
 for _r in _rnn_nb:
 spec_x = LSTM(_r, activation=’tanh’, dropout=dropout_rate, recurrent_dropout=dropout_rate, return_sequences=True)(spec_x)for _f in _fc_nb:
 spec_x = TimeDistributed(Dense(_f))(spec_x)
 spec_x = Dropout(dropout_rate)(spec_x)spec_x = TimeDistributed(Dense(10))(spec_x)
 out = Activation(‘sigmoid’, name=’strong_out’)(spec_x)_model = Model(inputs=spec_start, outputs=out)
 _model.compile(optimizer=’Adam’, loss=’binary_crossentropy’,metrics = [‘accuracy’])
 _model.summary()
 return _model

参数:

rnn_nb = [32, 32] # Number of RNN nodes. Length of rnn_nb = number of RNN layers
fc_nb = [32] # Number of FC nodes. Length of fc_nb = number of FC layers
dropout_rate = 0.5 # Dropout after each layer

模型总结如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Summary.

GRU 在喀拉斯的实施。

GRU 被称为门控循环单元,是一种 RNN 建筑,类似于 LSTM 单元。GRU 由复位门和更新门组成,而不是 LSTM 的输入、输出和遗忘门。

复位门决定如何将新的输入与先前的存储器相结合,而更新门定义要保留多少先前的存储器。如果我们将 reset 设置为全 1,将 update gate 设置为全 0,我们又会得到简单的 RNN 模型。

对于 GRU,隐藏状态 hₜ可以计算如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里 r 是复位门, z 是更新门。

GRU 的实施情况可以说明如下:

def get_model(_rnn_nb, _fc_nb):spec_start = Input((256,256))
 spec_x = spec_start
 for _r in _rnn_nb:
 spec_x = GRU(_r, activation=’tanh’, dropout=dropout_rate, recurrent_dropout=dropout_rate, return_sequences=True)(spec_x)for _f in _fc_nb:
 spec_x = TimeDistributed(Dense(_f))(spec_x)
 spec_x = Dropout(dropout_rate)(spec_x)spec_x = TimeDistributed(Dense(10))(spec_x)
 out = Activation(‘sigmoid’, name=’strong_out’)(spec_x)_model = Model(inputs=spec_start, outputs=out)
 _model.compile(optimizer=’Adam’, loss=’binary_crossentropy’,metrics = [‘accuracy’])
 _model.summary()
 return _model

参数:

rnn_nb = [32, 32] # Number of RNN nodes. Length of rnn_nb = number of RNN layers
fc_nb = [32] # Number of FC nodes. Length of fc_nb = number of FC layers
dropout_rate = 0.5 # Dropout after each layer

模型摘要:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Summary.

网络的比较。

  • 从我的经验来看,如果你在做语言建模(不确定其他任务),GRUs 在较少的训练数据上比 LSTMs 训练得更快和表现更好。
  • gru 更简单,因此更容易修改,例如在网络有额外输入的情况下增加新的门。一般来说代码更少。
  • 理论上,lstm 应该比 GRUs 记住更长的序列,并且在需要模拟远距离关系的任务中胜过它们。
  • 从上面的模型总结中可以看出,gru的参数复杂度也比 LSTM 低。
  • 简单的 rnn 只有简单的循环操作,没有任何门来控制信元之间的信息流。

如何使用合适的批量获得 4 倍的加速和更好的泛化能力

原文:https://towardsdatascience.com/implementing-a-batch-size-finder-in-fastai-how-to-get-a-4x-speedup-with-better-generalization-813d686f6bdf?source=collection_archive---------7-----------------------

有一次在推特上,我看到了杰瑞米·霍华德引用 Yann LeCun 关于批量的对话:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Batch size discussion on Twitter

自从我遇到 Fastai 的非常好的学习率查找器以来,这个主题一直在我脑海中的某个部分,我一直想知道是否有一个有用的批量大小查找器,人们可以使用它快速开始训练他们的模型具有良好的批量大小。

作为一个提醒,Fastai 中使用的学习率查找器通过测试不同的学习率来找到正确的学习率,以找到哪一个能最大程度地减少损失。更详细的解释可以在这里找到:https://sgu gger . github . io/how-do-you-find-a-good-learning-rate . html

拥有一个批量查找器的想法在我脑海中已经存在了很长时间,在从 Jeremy 那里获得了动力之后,我已经决定开始实现用于训练神经网络的批量查找器的旅程。

今天我想分享实现一篇论文的旅程和目的地,因为它们在我看来都很有趣,也许会激励你去尝试更多的东西!

一、大小故事

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

OC meme about batch size

一个普遍的看法是,您不应该使用大批量,因为这只会导致模型过拟合,并且您可能会耗尽内存。虽然后者显然是正确的,但前者比后者更复杂,为了回答这个问题,我们将稍微深入一点 OpenAI 论文“大批量训练的经验模型”

这篇我推荐阅读的文章解释了许多简单的想法,值得记忆。

首先,我们的目标是通过随机梯度下降法来最小化损失,并且有一个真正的基础景观,在此基础上我们将最小化损失。尽管如此,我们无法获得整个数据集的真实梯度(或者更准确地说,是整个分布的梯度),因此,我们必须用有限的批量来近似梯度。

因为我们对一批进行平均,如果我们的批量很小,就会有很多噪声,我们可能只训练噪声模型。尽管如此,应用几个连续的更新将朝着正确的方向推进,但我们还不如直接使用更大的批处理大小,这在计算上更有效,并直接平均掉噪声。尽管如此,在达到一定规模后,如果您的梯度已经很精确,那么再增加批量规模就没有意义了,因为这只是一种计算上的浪费,精度上的收益很小。

此外,通过使用更大的批量(达到 GPU 允许的合理数量),我们可以加快训练速度,因为这相当于迈出几大步,而不是迈出许多小步。因此,对于更大的批量,对于相同数量的历元,我们有时可以获得 2 倍的计算时间!

第二,有一个统计称为“简单噪声标度,它帮助我们确定什么是好的批量,它被定义为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Simple Noise Scale equation

其中 G 是在 n 个参数上我们损失 L 的真实梯度。

在不深入研究这篇论文的详细内容的情况下,我们的想法是,如果我们使用小于简单噪声标度的批量大小,我们可以通过增加批量大小来加快训练速度,相反,如果我们使用大于简单噪声标度的过大批量大小,我们只会浪费计算能力。

为了更好地理解这一统计数据的含义,让我们来研究一下每个术语:

  • 分子是梯度中每个变量的方差之和。这是对梯度中存在的噪声的测量。
  • 分母是梯度的平方范数,我们称之为标度,给出了梯度接近于零的局部最小值的接近程度的度量。

因此,梯度越大,我们想要的批量就越大,这很自然,因为我们想要在正确的方向上采取梯度步骤。相反,如果梯度没有噪声,我们将从较小的步长中受益更多,因为我们不需要平均大量的观察值并分别使用它们。

另一方面,我们越接近最小值,批量越大,因为我们越接近局部最小值,我们希望采取更谨慎的步骤,因为我们不希望超过它而错过正确的方向。

最后,简单的噪声标度为我们提供了一个工具来回答“较大的批量会使我们过度适应,而较小的批量有助于调整”这个问题:

不一定!如果您的任务已经很复杂,并且近似梯度会有噪声,那么您可能会有兴趣使用更大的批量,以确保您的模型不会在太多的噪声上进行训练。不是说较大的批量会使你过度拟合,而是较小的批量会通过噪声注入增加更多的正则化,但是如果你连拟合都不合适,你还要增加正则化吗?

二。实施文件

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

OC meme of my journey

现在,我们已经了解了为什么选择正确的批量大小很重要,以及我们如何通过简单的噪声比例统计找到合适的批量大小,现在是时候实施了!好吃!

记住,简单的噪声比例公式是:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Simple Noise Scale equation

问题是,我们不仅需要知道真实的梯度,还需要知道这个梯度的方差,这就更加困难了。为了解决这个问题,作者提出了两种不同的统计方法来逼近简单噪声标度的分子和分母。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Estimator for the scale

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Estimator for the noise

这里,我们使用两个不同的批量大小, B 大和 B 小 ,使用以下公式计算实际梯度的两个不同估计值:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Approximate gradient for a given batch size

一旦有了这两个近似值,我们就可以用下面的公式来计算简单的噪声比例:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Approximation of the Simple Noise Scale

为了确保该估计量具有低方差,作者在整个训练过程中计算了几个简单的噪声尺度估计量,并对其进行了平均。

正如论文中所解释的,一种自然的方法是利用几个 GPU 来计算每个 GPU 的局部梯度,这将是小梯度,然后将其与不同 GPU 之间的平均梯度进行比较,这将是大梯度。尽管如此,这种方法假设我们有一个多 GPU,但对我们大多数人来说并不是这样。

因此,必须找到一种有效的方法来为单个 GPU 实现这一点,而这在原始论文中没有描述。这就是我开始的地方,现在我将与你分享我如何解决这个问题的理由!

文章其余部分使用的代码可以在这里找到:https://colab . research . Google . com/drive/15 ltg _ r 03 yqswshz 0 jo 4xaowixlmxmemv

在第一行代码中,我设置了一个 Fastai 环境来在 MNIST 上运行一个模型,因为这个数据集已经在论文中进行了测试,他们得到了平均 900 的简单噪声标度。

我不会详细解释代码,因为我要花一整篇文章来解释 Fastai 如何将所有东西与他们的 API 放在一起,但是代码应该是一个好的开始。如果你想进一步了解代码,请在评论中告诉我,我可以解释它,甚至可以写一篇关于编码部分的文章。

A .使用指数移动平均线的第一种方法

由于我没有多 GPU 设置,所以我发现论文中提出的统计数据并没有真正的帮助,我想我可以跳过它,通过进行近似,直接计算方差的总和:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

首先,我用给定批次的估计梯度来近似真实梯度。

然后,由于协方差矩阵的计算可以被视为两个平均值,我试图用指数移动平均值来近似它,因为我不想在训练中存储许多梯度。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Running average of noise, scale, and Simple Noise Scale over batches computed

正如您在这里看到的,结果很奇怪,简单噪声标度太不稳定,噪声比噪声大得多,这给出了一个非常负的简单噪声标度,没有意义。

B .存储梯度

我们看到,使用指数移动平均并不是逼近协方差矩阵的好主意。

解决这个问题的另一种方法是简单地预先设置若干个***【N】***梯度来保持,然后我们将简单地计算 N 不同的梯度,并使用那些 N 梯度来近似协方差矩阵。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

它开始显示结果,但是它的计算方式很复杂:x 轴是我存储的批次数量,以这种方式计算简单的噪声范围。虽然它似乎提供了某种结果,但实际上并不可用,因为我已经存储了数百个渐变!

C .进行两次培训

又一次失败后,我决定按照论文的思路,计算他们的两个统计量。尽管如此,当我只有一个 GPU 时,我需要有一种方法在训练期间获得两个不同大小的批次。

然后我想,当我可以用两种不同的批量大小运行两个训练时期,然后再计算它时,为什么要运行一个训练时期呢?

于是我带着这个想法去做了,用 B 大 = 2 * B 小 ,这将允许我计算它们各自的梯度,并使用它们来计算 GS 如文中所述以指数移动平均的方式。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

哎哟!与第一种方法一样,它产生了奇怪的结果!此外,当我想到这一点时,我得到的批次可能在两次运行之间并不相同,因为没有什么会强制将小批次包含在大批次中。此外,我需要运行两个训练时期来计算这一点,所以它不是很好。

D .连续批次

最后,我意识到最好的方法似乎是第二种,但有些东西必须修改,因为我不想保留大量的梯度来计算统计数据。

然后,一个非常简单但有效的想法出现在脑海中:如果我不是像论文中那样以平行的方式对几个批次进行平均,而是以连续的方式对连续的批次进行平均,会怎么样?

这仅仅意味着我只需要设置一个参数,我调用***【n _ batch】***这是在计算大梯度和小梯度之前我必须存储的批次号,然后我将能够以连续的方式计算论文的统计数据!

以这种方式实现后,我得到了以下结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

她真是个美人!在论文中,他们描述了增长趋势是可以预期的,因为噪声更可能保持不变,而梯度的规模将随着我们越来越接近最小值而减小,这将导致简单噪声规模的增长。

因为我们很可能没有相同的设置,我也没有访问他们的代码,所以我们的结果略有不同,但在论文中,作者提到了一个简单的噪声标度,从大约 50 开始,到 900,这才是重要的。考虑到理论和实践中的许多近似值,结果可能会有所不同,但正如论文中所解释的那样,差异不应超过一个数量级。

因此,在这个漫长的旅程之后,似乎有一个实现正在工作,尽管本文对此没有提供什么帮助,最好的部分是,要在实践中使用它,您只需要一行代码!

这里的参数对应于:

  • 学习:快速学习者。
  • lr:完成一个训练循环的学习率,可以使用 lr_find()找到
  • num_it:您想要处理的批次数量,可以设置为 【无】 ,它会在一个时期内自动训练。
  • n_batch:在计算简单噪声标度之前要存储的批次数量。20 似乎可以很好地完成不同的任务。
  • beta:指数移动平均的 beta 参数,用于计算方差和以及渐变的比例。如果绘图太不规则,如果需要,尝试增加到 0.999 或更大,或者增加 n_batch 参数。

三世。在不同任务上测试批量查找器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Time to take big steps !

现在我们有了一个工作的实现,看看它在实践中如何帮助找到一个好的批量大小会很有意思。

首先,我们将研究罗斯曼数据集。这个数据集已经在 Fastai courses v3 中进行了探索,您可以在这里找到:https://github . com/Fastai/course-v3/blob/master/nbs/dl1/lesson 6-rossmann . ipynb

在这里,我将简单地运行我的批量大小查找器,并进行与原来完全相同的训练,但是批量大小考虑了简单的噪声标度。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在如何解读这一点?这意味着,对于给定的学习速率,训练似乎收敛到大约 500 的简单噪声标度,即噪声和标度在训练的后期稳定。因此,计算时间和效率之间的最佳权衡似乎是批处理大小为 512。

在使用批量大小 512 和 64 运行相同的训练后,我们可以观察到一些情况。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

First one-cycle training with batch size 512

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

First one-cycle training with batch size 64

批量大小为 512 时,培训速度比批量大小为 64 时快近 4 倍!此外,即使批量大小 512 采取更少的步骤,最终它具有更好的训练损失和稍差的验证损失。

然后,如果我们查看每个批量的第二个训练周期损失:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Second one-cycle training losses with batch size 512

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Second one-cycle training losses with batch size 64

我们可以看到,与批量大小为 512 的情况相比,批量大小为 64 的情况下,训练更加不稳定,因为验证损失继续减少。

最后,我们可以观察到最后一个培训周期的以下结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Last one-cycle training losses with batch size 512

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Last one-cycle training losses with batch size 64

所以最后,如果我们总结 Rossmann 的结果,使用 512 而不是 64 的批量

  • 减少 4 的训练时间
  • 提供了更好的训练和验证损失,以及感兴趣的度量,这里是 exp_rmse

我研究过文本和图像数据,但考虑到它们要重得多,尤其是具有巨大身体的预训练模型,当我尝试以批量大小运行训练时,我遇到了 CUDA 内存不足,所以我不会在这里显示结果,但你可以在 Colab 笔记本上看看。

结论

贯穿这篇文章我们看到了很多东西!我希望你喜欢这次旅行,如果有什么事情你必须记住的话,那就是:

  • 没有神奇的批量大小数字,例如 32,它取决于您的数据的复杂性,以及您的 GPU 约束。我们看到,小批量可以通过噪声注入帮助调整,但如果你想学习的任务很难,这可能是有害的。而且,跑很多小步会花更多的时间。相反,大批量确实可以加快你的训练,甚至有更好的泛化性能。
  • 一个很好的方法是使用“大批量培训的经验模型”中介绍的简单噪音等级度量。我在这里提供了第一个快速的实现:【https://github.com/DanyWind/fastai_bs_finder】。您可以在自己的数据集上尝试它,特别是在推荐系统或表格模型上,在那里您不太可能遇到 CUDA 内存不足的问题。
  • 不要犹豫去尝试一些事情,一个小小的推动有时可以推动你做好事!我大概在 6 个月前看到了这篇论文,但我并没有真正注意到它,直到我真正尝试(并且失败了很多次)去实现它。但是现在,我不仅可以与大型社区分享这些结果,它还帮助我更好地理解批量大小是如何工作的,以及它的常见概念可能是错误的。所以不要犹豫,现在就实施酷的东西,即使它不直接工作也没关系,旅程比目的地更有价值!

所以,我希望你喜欢读这篇文章,如果能得到你的反馈,那就太好了,我会在未来试着发布更多的文章。

如果您有任何问题,请不要犹豫,通过 Linkedin 联系我,您也可以通过 Twitter 找到我!

实施企业人工智能战略

原文:https://towardsdatascience.com/implementing-a-corporate-ai-strategy-a64e641384c8?source=collection_archive---------6-----------------------

行动太慢会有代价——几乎和行动太快一样

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

随着这一代人的数字化转型,机器学习和人工智能的更大承诺在人们的脑海中创造了奇迹,并在组织内部产生了活力。这个领域的吸引力是有道理的:每天都有大量的流程改进被公布,每个新的科技创业公司都有一部人工智能剧,甚至政府也在宣布他们独特的战略来跟上。

未来财富的承诺足以让最脚踏实地的领导人眩晕。人工智能创新的惊人速度意味着新的软件创意可以在几天内提交、检查、测试、检验和部署。新特性随着持续的开发周期一步一步来;突发商机的新想法。

(对于那些仍然怀疑这个行业发展速度的人,这里有一个故事:我们曾经在 一个半小时 设计、创建、验证和部署了一个用于海上监控的概念验证预测模型——我们所要做的就是花两周时间告诉客户回去再清理一些他们的数据。)

网飞时代的大片

业务活动和流程来来去去;它们旨在反映一天的心情,或者及时捕捉机会。然而,战略往往进展缓慢且无处不在。他们不再受欢迎后还会留下来,因为“这是我们一贯的做事方式。”

企业战略和企业文化之间有明显的重叠:创新可以被视为信口开河,就像精心策划可以被描述为陈旧和繁琐。有一个深思熟虑的方法来定义你的组织的问题,允许人们独立地做决定,避免灾难。

企业战略包含什么?

在最基本的层面上,战略是在不确定的条件下实现一个或多个目标的高层次计划。“它是一系列启发和信念,旨在提供针对对手(如竞争对手)或情况(如市场)的优势(进攻性或防御性)。

在你的组织内有一个战略的意义就像在隧道里有一个手电筒:你不能看到全貌,但你可以对你的下两步,也许是三步相当有信心。这就是你继续前进所需要的。

通常,公司战略可以用一两句话来概括,对外界来说有些显而易见——正是这种战略的实施经验是专有的,并使公司取得成功。与毕马威保守的程序和可靠的立场相比,德勤具有探索性和灵活性。IBM 正在失去其经典的政府和财富 500 强优势,因为 AWS 和 Azure 等新的云玩家在定价策略和谈判策略上不采取行动。

公司战略基础

早在 1996 年,迈克·E·波特写了一篇内容广泛的文章来帮助定义公司战略的“是什么”和“为什么”。他的要点如下:

  • 仅仅优化您的流程不会带来更多利润;你的竞争对手也在这么做。所以你所在行业的所有公司都会收敛到同一个最优点。
  • 为了避免这种趋同和随后的后果,你可以通过做不同的事情、做不同的事情来获得优势。
  • 然而,选择接下来做什么事情的行为在逻辑上意味着你选择不做其他事情。因此,从选项列表中选择正确的事情突然变得非常重要。

当情况不明朗,或者必须在两个不理想的结果之间做出选择时,一个好的策略将有助于支持和证明你的决定。一个糟糕的策略会让你喘不过气来,并强迫你根据呈现给你的信息做出逻辑上的错误选择。

企业环境中的人工智能策略

对于大多数企业来说,人工智能的实现是面向内部的。这意味着一个好的商业策略将是独一无二的,并与你的竞争对手区分开来,但你的 AI 策略可以和其他所有人的一样。你的数据与他们的不同,因此你的结果也会不同。启动这一内部驱动战略的一个简单问题如下:

我们可以或应该用机器学习来加速、增强或取代哪些业务活动或流程,从而影响感兴趣的结果?

要回答这个问题,需要一些输入:

  • 流程映射。对于所执行的每项活动,是否有一系列明确的步骤来产生结果?如果没有写下来,你的团队成员有能力写下这些过程吗?
  • 功力。你的团队拥有实现机器学习项目的全部技能吗?如果不是,外部团队的重点角色应该是什么?
  • **衡量成功的标准。**流程或活动增加或替换后,预期会发生什么变化?
  • **持续支持。**未来几年将如何支持这一新安装?组织内部会有所有者吗?
  • **范围。**需要实施的仅仅是一项产品功能,还是需要对整个部门进行彻底改革?

你的 AI 战略的执行和实施,需要和开辟一个新部门一样的关注和专注。在我们的参与下,成功的公司实施并雇佣了数据科学团队,并为其提供了与其 it、HR 或销售部门相同的条件:有预算和授权。

人工智能策略建议

围绕在您的组织内采用人工智能,还有其他一些考虑因素。

首先,来自首席执行官的法令是好的,但各级领导的认同更好。我们看到的典型阻力是团队成员对替换或淘汰的恐惧,掩饰为犬儒主义。必须让整个组织的领导人意识到重点是增加工作人员,而不是替换。甚至有人因为机器学习的声势而根本不相信它——然而一个影响组织底线的清醒的过程改进通常会很快说服他们。

此外,比拥有人工智能能力更重要的是拥有数据和分析文化。如果没有结果和结果的集合,那么就不能得到预测或解释模型。机器学习需要从数据中学习,数据来自记录,记录来自流程。

在员工层面,有许多考虑要支持参与的每个人。一个人工智能项目框架将有助于帮助经理提供一个去/不去的决定。内部创业文化将允许人们探索解决棘手问题的不同方法。持续的学习环境让每个人都跟上时代。如果只有一个冠军离开,会对士气造成不利影响,所以要通过展示和讲解来确保团队内部的知识转移。

第一次做对

在我们咨询过的大型组织中,他们让我们加入是有明确原因的。他们知道自己有资源雇佣数据科学家团队,让他们横行无忌,就像鬣狗嗅出受伤的瞪羚一样;他们没有的是第二次机会来建立正确的团队而不是建立正确的团队*。*

我们给他们的建议和随后的项目实施遵循以下几点:

  • AI 应该没意思。如果它是外来的,很有可能会被误解,甚至误用。你要的是厨师刀,不是搅拌机。当有一个明确的问题,有一个已知的解决方案,使用它。谈到流程优化,好已经足够好了。完美永远不会实现,因为不管怎样,明天会有更好的研究论文。
  • ***它直接影响 KPI。*每一项努力都应该为你的公司赚更多的钱,为你的公司省钱,或者为你的员工节省工作和时间。聪明的计划失败了。回到你的组织的基本原则。
  • ***实施起来需要时间。*需要像马拉松一样实施,而不是短跑。记住,人们花了大约 15 年的时间才意识到电动机可以被移到它改进制造的地方,而不是被插入它的蒸汽对应物的位置。保持耐心,专注于获得动力而不是一夜成名。
  • 从小处着手。大多数大的努力都会失败。(在加拿大,我们仍然受到联邦政府支付系统改革失败的影响。)如果你不确定自己是否会游泳,尝试一下比从深水区跳下去更安全。选择一个项目,把它分解成关键活动,自动化其中一个,然后是另一个,等等。

最终注释

在他 2011 年的书《适应:为什么成功总是始于失败》中,蒂姆·哈福德讨论了人们容易犯的三种错误:失误、违规和错误。滑倒是按错了按钮,违规是有人故意骗你。至于第三类,作者解释得最好。“错误是你故意做的事情,但会产生意想不到的后果,因为你对世界的心理模型是错误的。”

在这个数字能力的新时代,正确的心理模型将机器学习技术与商业问题结合起来,并准备在明天被重新发明。利用这种速度成为你的优势,而不是让它成为你的劣势。

如果您对本文或我们的 AI 咨询框架有其他问题,请随时通过LinkedIn或通过 电子邮件 联系。

你可能喜欢的其他文章

我的首席技术官丹尼尔·夏皮罗(Daniel Shapiro)的其他文章您可能会喜欢:

用 Django 实现数据仓库

原文:https://towardsdatascience.com/implementing-a-data-warehouse-with-django-e4856c92f146?source=collection_archive---------2-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在本文中,我们将介绍如何利用 Django 及其 rest 框架来实现数据仓库。我们将特别关注来自外部 API 的数据源,但是同样的原则也适用于任何其他类型的数据源:平面文件或直接 ODBC 连接。

使用 Django 实现数据仓库的一个主要好处是,您将能够使用 Python 处理任何组件或任务:ETL、查询、数据操作、报告、web 应用程序应用程序…

请注意,Django 可能不适合您的用例,但是同样的原则也适用。

本文使用的所有代码都可以在 GitHub 上找到。

什么是数据仓库?

数据仓库的实现通常是为了整合整个公司的不同数据源。在我们的案例中,我们使用不同的外部和内部 API 来整合所有这些信息,以便进行分析、报告和预测建模。

主要挑战是将不同来源的数据提取、转换和加载为一种通用格式,并能够跟踪数据随时间的变化。

我们将在下面的章节中详细介绍这些挑战。

Django 和 rest 框架

Django 是开源的 web 框架模板;并遵循模型、视图、模板(MVT)设计模式。

在本文中,我们将主要关注 Django 架构的模型组件。为了能够与数据库交互,Django 使用了对象关系映射器;这意味着它们将被表示为 Python 类,而不是使用 SQL 表。这意味着我们可以使用 Python 执行任何 CRUD 操作,而无需直接与 SQL 或数据库本身进行交互。
这将是我们数据仓库实现的关键,因为我们将利用这个 ORM 来执行插入和更新。

Rest-Framework 是 Django 生态系统的一部分,是创建 web APIs 的有用工具包。
我们将使用的框架组件称为序列化器;它允许将复杂的数据结构序列化为一个呈现的 JSON(典型的 GET 请求),还允许在首先验证传入的数据(也称为反序列化)之后解析要转换回复杂类型的数据。
这在我们的情况下将非常有用,因为我们可以利用反序列化来确保信息以正确的格式出现,并且我们可以将每个元素映射到数据仓库中的正确字段。
-https://www.djangoproject.com/
-https://www.django-rest-framework.org/

基本模型

一旦我们创建了 Django 项目和应用程序(https://docs.djangoproject.com/en/2.1/intro/tutorial01/);我们现在可以创建我们的模型了。

Models.py 将包含所有允许 Django ORM 与数据库交互的逻辑; models.py 中的每个类都是数据库中的一个物理表。

在这个例子中,我们将创建 3 个表:
-Person;通过名字和姓氏

  • 车辆唯一识别的自然人的实例;通过其注册号
  • 人员车辆唯一识别的车辆;一个人拥有车辆的例子
from **django.db** import **models**class **Person**(models.Model):
 *“”” Person class identifies a unique physical person by its first name, last name and email “””*created_at = models.DateTimeField(auto_now_add=True)
 updated_at = models.DateTimeField(auto_now=True)
 first_name = models.CharField(max_length=100)
 last_name = models.CharField(max_length=100)
 email = models.CharField(max_length=100)def __str__(self):
 return “{} {}”.format(self.first_name, self.last_name)class **Vehicle**(models.Model):
 *“”” Vehicle class uniquely with the registration plate number “””*created_at = models.DateTimeField(auto_now_add=True)
 updated_at = models.DateTimeField(auto_now=True)
 registration_plate = models.CharField(max_length=100)def __str__(self):
 return self.registration_plateclass **PersonVehicle**(models.Model):
 *“”” PersonVehicle register the relationship between a vehicle in a person,
 in other words, the owner of the vehicle at a given point in time “””*created_at = models.DateTimeField(auto_now_add=True)
 updated_at = models.DateTimeField(auto_now=True)
 vehicle = models.ForeignKey(Vehicle, on_delete=models.PROTECT)
 person = models.ForeignKey(Person, on_delete=models.PROTECT)def __str__(self):
 return “{} {}”.format(self.vehicle, self.person)

created_atupdated_at 是两个自动生成的字段,将记录创建或更新记录的日期时间。

保护将禁止删除任何与其他表有关系的记录。如果您希望删除与该记录相关的所有记录,也可以使用级联

现在我们已经创建了我们的模型,我们可以通过 Django shell ( )插入信息。/manage.py shell ):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

跟踪更改

为了能够跟踪随时间的变化,我们将使用简单历史;它允许在每次创建/更新/删除时存储 Django 模型状态:https://django-simple-history.readthedocs.io/en/2.7.0/

from django.db import models
from **simple_history.models** import **HistoricalRecords**class Person(models.Model):
 *“”” Person class identifies a unique physical person by its first name, last name and email “””*created_at = models.DateTimeField(auto_now_add=True)
 updated_at = models.DateTimeField(auto_now=True)
 first_name = models.CharField(max_length=100)
 last_name = models.CharField(max_length=100)
 email = models.CharField(max_length=100)
 **history = HistoricalRecords()**class Meta:
 **unique_together = ((“first_name”, “last_name”),)**def __str__(self):
 return “{} {}”.format(self.first_name, self.last_name)class Vehicle(models.Model):
 *“”” Vehicle class uniquely with the registration plate number “””*created_at = models.DateTimeField(auto_now_add=True)
 updated_at = models.DateTimeField(auto_now=True)
 registration_plate = models.CharField(max_length=100)def __str__(self):
 return self.registration_plateclass PersonVehicle(models.Model):
 *“”” PersonVehicle register the relationship between a vehicle in a person,
 in other words, the owner of the vehicle at a given point in time “””*created_at = models.DateTimeField(auto_now_add=True)
 updated_at = models.DateTimeField(auto_now=True)
 vehicle = models.ForeignKey(Vehicle, on_delete=models.PROTECT)
 person = models.ForeignKey(Person, on_delete=models.PROTECT)
 **history = HistoricalRecords()**class Meta:
 **unique_together = ((“vehicle”),)**def __str__(self):
 return “{} {}”.format(self.vehicle, self.person)

请注意,我们在每个模型中添加了字段 *history* ,以便跟踪随时间的变化。这些更改将存储在前缀为*历史*的镜像表中。

为了能够跟踪变更,我们还需要定义*代理键,*这些键是记录唯一性的业务定义。例如,在 *Person* 表中,我们将 *first_name* 和 *last_name* 定义为 *unique_together* ,这意味着这些字段将不可更新,但是 *email* 是可更新的。

现在让我们尝试修改我们之前记录的记录:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2019/raw/master/docs/img/6420586a70a064efc40fbc444421d155.png)

现在让我们看一下历史表,看看这些变化是如何记录的:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2019/raw/master/docs/img/239413297e8cc6c571a7bd09325c87d5.png)

## 序列化程序

如前所述,在将输入数据插入相关的 SQL 表之前,将使用序列化程序来解析和验证输入数据。

现在让我们假设一个外部源通过 REST API 以下面的 JSON 格式向我们提供信息:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2019/raw/master/docs/img/b3ab2ba89f8c86e04fc1340481ccc5ea.png)

JSON 提供了此人的身份和当前属于此人的车辆列表,以下是将用于解析此 JSON 的序列化程序:

from rest_framework import serializersfrom dwh_app_simple_history.models import Person, PersonVehicle, Vehicleclass VehicleSerializer(serializers.Serializer):
*“””
Nested serializer within the JSON source; in this example all vehicles that belong to the
person nested in the JON as a list of all active vehicles.
“””*registration_plate = serializers.CharField(max_length=100)class PersonVehicleSerializer(serializers.Serializer):
*“””
Serializer that will be used to deserialize the json to be then imported in the datawarehouse
“””*first_name = serializers.CharField(max_length=100)
last_name = serializers.CharField(max_length=100)
email = serializers.CharField(max_length=100)
vehicles = VehicleSerializer(many=True)def save(self):
“””
Overwrite the save function on the serializer to be able to control how we want to
insert/update the data provided by the source in our datawarehouse.
“””
# First update or create the person
person_obj, created = Person.objects.update_or_create(
first_name=self.validated_data[“first_name”],
last_name=self.validated_data[“last_name”],
defaults={“email”: self.validated_data[“email”]},
)# Then create each Vehicle and link it to the person created before
for vehicle in self.validated_data[“vehicles”]:
vehicle_obj, created = Vehicle.objects.get_or_create(registration_plate=vehicle[“registration_plate”])

personvehicle_obj, created = PersonVehicle.objects.update_or_create(
vehicle=vehicle_obj, defaults={“person”: person_obj}
)


首先,我们创建了一个嵌套的序列化器 *VehicleSerializer* 来解析一辆车的实例,然后在父序列化器 *PersonVehicleSerializer* 中,我们可以使用参数 *many=True* 来告诉 Django 它们可以是多辆车。

为了正确保存所有信息,我们重写了 *save()* 方法,首先我们创建或更新 *Person* ,然后为嵌套字典中的每辆车创建一个 *Vehicle* ,然后将它链接到 *PersonVehicle* 中的 *Person* 。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2019/raw/master/docs/img/063bb3146129677fb2d03f18eb6c0fc7.png)

请注意,如果需要,可以通过添加验证或转换规则来丰富序列化程序,就像在传统的 ETL 实现中一样。

## 视图

在前面的例子中,我们使用 JSON 文件和 Django shell 将数据插入到我们的数据仓库中。

现在让我们假设信息不是由外部提供者提供的,而是公司架构的源系统向数据仓库发送信息。这可以通过添加一个允许通过一个 *POST* API 请求插入数据的*视图*来实现。

from django.shortcuts import render
from rest_framework.decorators import api_view
from rest_framework.response import Responsefrom dwh_app_simple_history.serializers import PersonVehicleSerializer@api_view([“POST”])
def PersonVehicle(request):
“””
This view will be called through a POST request to add or update the information provided in
the request
“””
# Deserialize the information provided in the request
ser = PersonVehicleSerializer(data=request.data)# Validate the information provided
ser.is_valid(raise_exception=True)# Save the information in the datawarehouse
ser.save()return Response({“All good, everything has been saved”})


正如你所看到的,我们使用了与 Django shell 中相同的序列,但是使用了 *api_view* decorator 将这个端点暴露给另一个系统或用户。这意味着我们现在可以从任何系统与我们的数据仓库通信(您需要确保您的 Django 服务器正在运行)。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2019/raw/master/docs/img/1f26deafa49d2b639a639842329c5bd0.png)

## 结论

在本文中,我们已经介绍了使用 Django 构建数据仓库的所有步骤和组件:
——使用 Django ORM 创建第三范式数据模型;
-使用简单的历史记录来跟踪随时间的变化;
-使用 serializer rest 框架对来自外部提供者或内部系统的信息进行反序列化,并将结果保存在数据仓库中;和
——使用来自 rest 框架的视图,允许源系统通过 POST 请求发送信息。

以上所有内容应该为构建您的数据仓库提供了足够的信息,当然,您必须浏览所有不同的来源,了解数据将如何在下游以最有效的方式建模数据,并在您的 ETL 中添加所有转换/验证规则。

# 在 PyTorch 中实现线性链条件随机场

> 原文:<https://towardsdatascience.com/implementing-a-linear-chain-conditional-random-field-crf-in-pytorch-16b0b9c4b4ea?source=collection_archive---------4----------------------->

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2019/raw/master/docs/img/68f4266c815001ecb9b8798bb60aaede.png)

Random fields 😝. Photo by [Matthew Miles](https://unsplash.com/@matthewmiles?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

嗨伙计们!这是我在 Medium 上的第一篇帖子。我希望你喜欢它!

在过去的日子里,我使用 PyTorch 从头开始实现了一个 CRF 模型。我这样做的想法是为了更好地理解 CRF 模型是如何工作的。我在网上找到了很多关于 CRFs 的内容,包括博客帖子、教程和书籍。我还看了 Hugo Larochelle 的关于 CRF 模型的系列视频讲座,发现它们非常直观。

看完之后,我决定用 PyTorch 从头开始实现这些数学方程(不用担心梯度!).所以,这就是这篇帖子的目的!与您分享一个关于如何实施(*线性链* ) CRF 模型的简单易懂的指南!

*免责声明:CRF 是任何无向图结构的概括,例如序列、树或图。在这篇文章中,我将重点关注顺序结构,这意味着我们的模型将只以先前的转换为条件。这种参数化被称为线性链 CRF。在这篇文章的其余部分,我将使用缩写 CRF 来命名一般的 CRF 和它的线性链对应物*互换*。*

在这篇文章中,我不会描述使用 CRFs 的原因和它的应用。我想如果你正在读这篇文章,是因为你已经知道了所有这些,而且你只对技术部分感兴趣。也就是说,我将介绍它背后的一些基本理论,并介绍用于编写代码的符号。

总之,在这篇文章中,你会看到:

1.  通用报告格式背后的基本理论;
2.  给定一系列观察值,如何找到最可能的标签序列;
3.  如何在给定标签的情况下计算一系列观察值的分数;
4.  如何计算配分函数来归一化这个分数;
5.  如何在对数空间中实现它们(数值稳定)。

**在下一篇文章中:**如何向量化 *for 循环*以使并行计算机单元的计算更容易(比如说 GPU🙌).在这里先睹为快矢量化代码。

# 幕后的基本理论

最初的条件随机场论文发表于本世纪初[【1】](https://repository.upenn.edu/cgi/viewcontent.cgi?referer=https://en.wikipedia.org/&httpsredir=1&article=1162&context=cis_papers)。从那以后,机器学习社区一直在到处应用 CRF,从计算生物学和计算机视觉到自然语言处理。在 google scholar 上用“使用 CRF”和“使用条件随机场”这样的关键词快速搜索,会得到大约 20000 个答案。

在过去的几年中,CRFs 模型与 LSTMs 相结合以获得最先进的结果。在 NLP 社区中,在 BiLSTM 上堆叠 CRF 层被认为是在序列标记问题上实现更高准确性的经验法则。你可以看到一些例子[在这里](https://github.com/sebastianruder/NLP-progress/blob/master/english/part-of-speech_tagging.md)和[在这里](https://github.com/sebastianruder/NLP-progress/blob/master/english/semantic_role_labeling.md)。

在序列分类问题中,我们的主要目标是在给定一个序列向量( **X** )作为输入的情况下,找到一个标签序列( ***y*** )的概率。这表示为条件概率*P*(**y***|**X**)。*

*首先,让我们定义一些改编自 Larochelle 的类的符号:*

*   *训练集:输入和目标序列对 *{(* **X** *i,* **y** *i)}**
*   *向量的第 *i-* 个输入序列:**x***I =[***x***1、…、***x**ℓ*
*   **标签的第 *i-* 个目标序列:**y**t46】I =【y1,…,y ℓ】**
*   **ℓ是序列长度。**

**假设时间独立,对于一个样本( ***X*** *,* ***y*** ),在一个常规的分类问题中,我们通过乘以每个项目在 *k-t* 处的概率来计算*P*(**y***|***X******

**![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2019/raw/master/docs/img/43add53fb7fdfd09794e594bf297d59a.png)**

**请注意,我们正在使用标准化的指数对*P(yk |***x***k)*进行建模。这类似于神经网络中广泛使用的 *softmax* 变换。这是使用 *exp* 函数 *:* 的一些直觉**

1.  ****下溢:**当我们将非常小的数相乘时,我们得到的是一个更小的数,它可能会发生*下溢*。**
2.  ****非负输出:**所有值都映射在 0 和+inf 之间。**
3.  ****单调递增:**将高值向上推,低值向下推。这与 *argmax* 操作有相似的效果。更多[此处](https://datascience.stackexchange.com/questions/23159/in-softmax-classifier-why-use-exp-function-to-do-normalization)。**

**我们从帽子里拿出两个符号: *U 和 z。*让我们看看它们是什么。**

***U* ( *x,y* ) 被称为我们的**排放量**或**一元分数** *。*这只是给定我们在第 *k* 时间步的 **x** 向量的标签 *y* 的分数。你可以把它看作是 BiLSTM 的第 k 个输出。其实理论上我们的 **x** 向量可以是你想要的任何东西。实际上,我们的 **x** 向量通常是周围元素的串联,就像滑动窗口中的单词嵌入。在我们的模型中,每个*一元*因子由一个可学习的权重加权。如果我们把它们看作 LSTM 输出,这就很容易理解了。**

***Z*(*x*)*俗称**分区函数**。我们可以把它看作一个归一化因子,因为我们想得到最终的概率。这类似于 *softmax* 函数的分母。***

**到目前为止,我们描述了一个带有“最终 softmax 激活”的常规分类模型,以便获得概率。现在我们将添加新的可学习权重来模拟标签 *yk* 被 *yk+1 跟随的几率。*通过建模,我们在连续的标签之间创建了一个依赖关系。因此,名为*直链 CRF!*为了做到这一点,我们将之前的概率乘以 *P(yk+1 | yk),*我们可以使用指数属性将其重写为一元分数*U*(***x****,y* )加上可学习的**转换分数** *T* ( *y,y* )**

**![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2019/raw/master/docs/img/6b4fc75883532aa73b78027935ce15ba.png)**

**在代码中, *T* ( *y,y* ) 可以看作一个具有形状 *(nb_labels* ,*nb _ labels)*的矩阵,其中每个条目都是一个可学习的参数,表示从第*个*标签到第*个*标签的过渡。让我们回顾一下我们所有的新变量:**

*   ****排放或一元分数** *(U):* 分数代表在给定输入的情况下*yk*x*k .***
*   ****过渡分数** *(T):* 代表可能性的分数 *yk* 后跟 *yk+1***
*   *****分区函数****【Z】:*归一化因子为了得到序列上的概率分布。**

**唯一需要正确定义的是配分函数 *Z:***

**![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2019/raw/master/docs/img/02c8008b94d23cdd7f134827835b0783.png)**

**结果是计算 *Z* (X)并不简单,因为我们有太多的嵌套循环😖。它是在每个时间步*标签集上所有可能组合的总和。*更准确地说,我们在标签集上进行ℓ计算。这给了我们一个时间复杂度 *O(|y|^* ℓ *)。***

**幸运的是,我们可以利用循环依赖,并使用动态编程来有效地计算它!完成这项工作的算法被称为**正向算法**或**反向算法—** ,这取决于你在序列上迭代的顺序。不要与神经网络中使用的前向和反向传播混淆。**

**这就是我们开始实施之旅所需了解的全部内容!如果你在我的解释中迷失了,有很好的资源可以更详细地解释 CRF。比如埃德温·陈的这篇精彩的教程,或者萨顿和麦卡勒姆的这篇内容丰富的教程,或者迈克尔·柯林斯的这篇直截了当的笔记。**

# **密码**

**让我们通过创建一个从 PyTorch 的 *nn 继承而来的名为 CRF 的类来开始我们的代码。模块*以便自动跟踪我们的坡度。此外,我为句子的开头/结尾添加了特殊的标记,并添加了一个特殊的标志来通知我们是否正在传递批量优先维度的张量。**

**我们还可以为 pad id 添加一个特殊的令牌。如果我们这样做,我们必须确保强制约束以防止从填充的过渡*和从*填充到*填充的过渡——除非我们已经处于填充位置。我们可以看到,我们的转换分数 *T* 被表示为矩阵 *self.transitions* ,并使用 *torch.parameter.* 进行编码。这样,PyTorch 将通过 autodiff 学习这些权重!太好了!***

# *定义损失函数*

*在监督分类问题中,我们的目标是在训练期间最小化期望误差。我们可以通过定义一个损失函数 *L* 来做到这一点,该函数将我们的预测和我们的真实标签作为输入,如果它们相等,则返回零分,如果它们不同,则返回正分——指示错误。*

*注意,我们正在计算*P*(**y***|**|*X***),这是我们想要最大化的东西。为了将这作为一个最小化问题,我们取这个概率的负对数。这也被称为*负对数似然损失(NLL-Loss)。*在我们的例子中,我们得到:*L =*-*log*(*P*(**y***|***X***)。应用 log-properties,如*log(a*/*b)= log(a)-log(b)*,我们得到:***

**![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2019/raw/master/docs/img/7eddb20ff93c6955b893e5832c951d83.png)**

**其中 *Z_log* 表示我们在计算配分函数时取 *log* 。当我们应用向前算法时,这将使事情变得更容易。因此,让我们检查一下这部分的代码:**

**我们的*正向*传递仅仅是 *NLL 损失*(不要与计算 Z(X)的正向算法混淆),其中我们在常规的 *log_likelihood* 方法前面插入了减号。 *log_likelihood* 通过首先计算分数和对数分割方法,然后彼此相减来计算。此外,我们向这些方法传递一个掩码矩阵,以便它们可以忽略与填充符号相关的计算。为了完整起见,掩码矩阵如下所示:**

input = [[‘lorem’, 'ipsum ‘dolor’, ‘sit’, ‘amet’],
[‘another’, ‘sentence’, ‘here’, ‘’, ‘’]]mask = [[1, 1, 1, 1, 1],
[1, 1, 1, 0, 0]]


# **计算分子:分数**

**由于我们将 *log* 应用于 *exp* 函数,分子就是我们在每个时间步长的发射和跃迁分数的总和。在代码中:**

**为了理解这段代码,您必须认为批处理中的每个句子的所有操作都是相同的。因此,我们首先通过调用`tags[:, 0]`来获取每批中第一个单词的标签。类似地,我们对时间步长维度上的掩码求和,以获得一个长度列表,对于上一个示例来说是`[5, 3]`。在实践中,它返回了一个*火炬。长型*带外形`(batch_size,)`。例如,让我们看看第 28 行:**

emissions[:, 0].gather(1, first_tags.unsqueeze(1)).squeeze(1)


1.  **首先,我们从第一个时间步长`emissions[:, 0]`中选择所有批次,它返回一个形状为`(batch_size, nb_labels)`的张量。**
2.  **然后,我们希望只从形状为`(batch_size,)`的*long tenser*`first_tags`中的列( *dim=1* )中选择值。由于`emissions`是一个 2D 矩阵,我们*取消`first_tags`的最后一个维度*得到形状`(batch_size, 1)` : `first_tags.unsqueeze(1)`**
3.  **现在它们有了相同的形状,我们可以使用*聚集*函数在`emissions` : `emissions[:, 0].gather(1, first_tags.unsqueeze(1))`的指定维度中选择`first_tags`内的值**
4.  **最后,这将产生一个形状为`(batch_size, 1)`的矩阵,所以我们*将*压缩回去,得到一个 1D *长传感器。***

**整个代码都使用这个简单的过程来选择指定维度内的一组标签。**

**关于这段代码,我想说的最后一件事是我们如何忽略与填充符号相关的分数。解决这一问题的思路非常简单:我们在两个向量(分数和掩码向量)之间执行逐元素乘法,以在与填充位置相关联的时间步长中将分数清零。**

# **计算配分函数:正向算法**

**既然我们已经计算了分数,让我们把注意力集中在分母上。为了有效地计算配分函数,我们使用了向前算法。我将简要描述它,并展示我们如何在对数空间中计算它。**

**正向算法的伪代码如下:**

**1)初始化*y’2:*的所有值**

**![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2019/raw/master/docs/img/b8ca21ef03dad2fcec13bf07647227d3.png)**

**2)对于 *k=2 到* ℓ-1,对于*y’k+1*(对数空间) *:* 的所有值**

**![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2019/raw/master/docs/img/aa11aee12b4d0ced9b0a7abdead7d29a.png)**

**3)最后:**

**![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2019/raw/master/docs/img/d22fe40241e7c31826a3940fb994ef3e.png)**

**请注意,在第二步中,我们记录了 exp 的总和。这可能会有问题:如果一个给定标签的分数太大,那么指数将很快增长到一个非常大的数字。因此,在我们最终获取日志之前,我们可能会发现一个*溢出*。幸运的是,有一个技巧可以使这个操作稳定:**

**![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2019/raw/master/docs/img/fcee87c5aa9e598eb7bc3983dbb29138.png)**

**左边等于右边的证明看起来是这样的:**

_ = log sum(exp(zk))
= log sum(exp(zk-c) * exp©)
= log exp© + log sum(exp(zk-c))
= c + log sum(exp(zk-c))


**设置 *c* 为 *max* ( *z* )我们就完成了。此外,PyTorch 已经在`torch.logsumexp`中为我们提供了这个稳定的实现。现在让我们使用 PyTorch 对上面的算法进行编码:**

**上面的代码与我们在分子中计算分数的方式非常相似。其实我们是在计算分数!但是现在我们通过查看以前的迭代来积累它们。我添加了关于形状的注释,这样你就能明白发生了什么。**

**这里只有一件事我们以前没有看到(*种*):**

*   **在这一行中,如果我们没有到达填充位置,我们就用新的值来改变 alpha 的当前值,否则就保持相同的值。要了解这是如何工作的,请看这个例子,当我们在时间步长 *i=1* 时:**

**>>> mask
tensor([[1., 0., 0.],
[1., 1., 0.],
[1., 1., 1.]])

alphas
tensor([[-0.7389, -0.6433, -0.0571, -0.3587, -2.1117],
[ 1.0372, 1.8366, -0.9350, -1.2656, -0.5815],
[ 0.1011, 0.7373, 0.0929, -0.8695, 0.7016]])>>> new_alphas
tensor([[11.1889, 10.6471, 11.0028, 11.0248, 11.0909],
[10.3975, 11.0104, 8.5674, 10.2359, 13.9150],
[10.1440, 9.9298, 11.3141, 10.1534, 10.3397]])>>> is_valid = mask[:, 1].unsqueeze(-1)
is_valid
tensor([[0.],
[1.],
[1.]])>>> is_valid * new_alphas + (1 — is_valid) * alphas
tensor([[-0.7389, -0.6433, -0.0571, -0.3587, -2.1117],
[10.3975, 11.0104, 8.5674, 10.2359, 13.9150],
[10.1440, 9.9298, 11.3141, 10.1534, 10.3397]])**


**我们已经更新了第二和第三序列,但没有更新第一序列,因为在时间步 *i=1* 我们到达了填充位置。**

**作为一个很好的观察,你可以看到一旦我们取了 *logsumexp* 我们就已经在日志空间中了!所以,我们可以把α的值加到我们的分数上。最后,我们在最后的时间步再进行一次 *logsumexp* 操作,返回到达句子末尾的最终值——所以我们仍然在 log-space 中。**

**这个算法的时间复杂度是 O(𝓁| *y* |),这比我们用朴素方法得到的指数界限低得多。**

# **寻找标签的*最佳*序列**

**现在我们已经计算了配分函数,我们几乎完成了所有的工作。如果我们也计算向后算法——它只是向后遍历序列——我们可以找到在每个时间步长最大化*P*(**y***k*|**X**)的标签 *k.* 有趣的是,如果我们假设 CRF 是真实分布,这个将是最优解。它可以这样表述:**

**![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fdf09c2f6f1146f54ea21341cb1090664.png&pos_id=img-1kT2Db1G-1727458261997)**

**其中 *α* 分数来自正向算法,而 *β* 分数来自反向算法。为了找到标签 **y** *的最佳序列,我们可以在每个时间步长取 *argmax* :**

**![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F0b3018c6a86653d9fb7d8dceb9bad740.png&pos_id=img-VW3poHmJ-1727458261997)**

## **维特比算法**

**但是,事实证明我们不需要计算反向算法来找到最可能的标签序列。取而代之的是,我们可以在向前算法期间简单地跟踪每个时间步长的最大分数。一旦我们完成了,我们就可以沿着 max 运算( *argmax* )的反向轨迹,以便**解码**使分数最大化的序列。这正是下面的代码所做的:**

**这种算法被称为维特比算法。这与我们在 log_partition 函数中使用的前向算法几乎相同,但我们没有对整个序列使用常规分数,而是使用最大分数和使这些分数最大化的标签*。*换句话说,我们用 *torch.max* 代替了 *torch.logsumexp* 操作,它一起返回 *max* 和 *argmax* 。**

**所以,我们现在需要做的一切就是挑选这些最终的标签,并沿着向后的轨迹找到" *argmax"* 标签的整个序列。上面代码的延续如下:**

**请注意,对于每个样本,我们都在对该样本的回溯进行迭代,并且在每个时间步长中,我们都在`best_path`的开头插入了使分数最大化的标签。因此,在最后,我们有一个列表,其中第一个元素对应于序列的第一个标签,最后一个元素对应于最后一个标签有效标签(*见第 15 行*)。还要注意。python 中的 insert(0,)是 O(n),所以更快的方法是使用。append()并在以后反转列表。**

**就是这样!当我们为批次中的所有样本计算 *find_best_path* 操作时,我们就完成了!**

# **把所有的放在一起**

**完整的代码可以在这里找到:[https://github.com/mtreviso/linear-chain-crf](https://github.com/mtreviso/linear-chain-crf)。看看`main.py`和`bilstm_crf.py`看看实践中的 CRF!**

# **结论**

**这个帖子比我预想的要长😛。请随意让这段代码更有效率,并留下评论告诉我们你是如何做到的🙂。**

**最后,我认为值得一提的是,如果你想在生产中使用 CRF 模型,我强烈建议你使用一个经过充分测试的高效实现,比如[这个伟大的 pytorch 包](https://github.com/kmkurn/pytorch-crf),或者由 [allennlp 库](https://github.com/allenai/allennlp)提供的那个。**

**在下一篇文章中,我们将看到如何对循环*进行矢量化,以计算配分函数和维特比算法。***

# **更多信息**

**通用报告格式只是众多连续模型中的一种。我强烈推荐你看一看[诺亚·史密斯关于序列模型的演讲](http://lxmls.it.pt/2016/sequencemodels.smith.7-23-16.pdf)或者[安德烈·马丁斯的演讲](https://andre-martins.github.io/docs/dsl2018/lecture_05.pdf)来看看这篇文章中提出的算法的一些可视化例子。或者更好的是,你可以参加下一届 [Lisbon 机器学习暑期学校](http://lxmls.it.pt/2019/),它将涵盖序列模型和许多关于机器学习和自然语言处理的有趣主题!**

# **参考**

*   **Hugo Larochelle 关于 CRFs 的讲座:[http://www . DMI . usherb . ca/~ la rochelle/neural _ networks/content . html](http://www.dmi.usherb.ca/~larocheh/neural_networks/content.html)**
*   **Pytorch 教程—高级:制定动态决策和 Bi-LSTM 通用报告格式:[https://py torch . org/tutorials/初学者/nlp/advanced_tutorial.html](https://pytorch.org/tutorials/beginner/nlp/advanced_tutorial.html)**
*   **Michael Collins 关于对数线性模型、MEMMs 和 CRF 的注释:[http://www.cs.columbia.edu/%7Emcollins/crf.pdf](http://www.cs.columbia.edu/%7Emcollins/crf.pdf)**
*   **迈克尔·科林斯关于向前向后算法的笔记:[http://www.cs.columbia.edu/~mcollins/fb.pdf](http://www.cs.columbia.edu/~mcollins/fb.pdf)**
*   **Sutton 和 McCallum 的教程—条件随机字段介绍:[https://home pages . INF . ed . AC . uk/csutton/publications/crftutv 2 . pdf](https://homepages.inf.ed.ac.uk/csutton/publications/crftutv2.pdf)**
*   **Edwin Chen 博文:[http://blog . echen . me/2012/01/03/introduction-to-conditional-random-fields/](http://blog.echen.me/2012/01/03/introduction-to-conditional-random-fields/)**
*   **Ravish Chawla 的条件随机字段概述:[https://medium . com/ml 2 vec/Overview-of-Conditional-Random-Fields-68 a2a 20 fa 541](https://medium.com/ml2vec/overview-of-conditional-random-fields-68a2a20fa541)**

**🔍*特别感谢@flassantos31、@erickrfonseca 和@thales.bertaglia 对本帖的审核。***

**🔮回顾后感谢: [André Luís Macêdo Farias](https://medium.com/u/a800706492c5?source=post_page-----16b0b9c4b4ea--------------------------------) 指出了使用朴素方法计算 *Z* 的正确时间复杂度。**

# 用五个步骤实现用于文本分类的朴素贝叶斯分类器

> 原文:<https://towardsdatascience.com/implementing-a-naive-bayes-classifier-for-text-categorization-in-five-steps-f9192cdd54c3?source=collection_archive---------2----------------------->

## 我希望我以前有朴素贝叶斯分类器指南

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fb286e95adf75c6dea9c5a1368d367d6f.png&pos_id=img-1hcS3RsO-1727458261997)

Thomas Bayes (1701–1761) author of the Bayes’ theorem

> 朴素贝叶斯是一种常用于文本分类的学习算法。

朴素贝叶斯分类器的一些应用是:

*   **(自动)对文件夹**中的电子邮件进行分类,因此收到的电子邮件信息会进入**:**“家人”、“朋友”、“更新”、“促销”等文件夹。
*   **(自动)工作列表的标记。给定一个原始文本格式的工作列表,我们可以给它分配标签,如:“软件开发”、“设计”、“营销”等。**
*   **(自动)产品分类。给定一个产品描述,我们可以将其分类,如:“书籍”、“电子产品”、“服装”等。**

本文的其余部分将提供必要的背景知识和直觉,通过五个步骤从头构建一个朴素贝叶斯分类器。

# 第一步。确定训练朴素贝叶斯分类器的先决条件

如前所述,贝叶斯分类器在文本分类中的应用是无止境的。唯一的先决条件是,对于我们希望将文本片段进行分类的每个类别( *class)* ,都有一组现有的*示例*。

例如,对于工作列表分类示例,我们需要一组已知针对“软件开发人员”的工作列表,一组已知针对“设计人员”的工作列表,以及一组针对“营销人员”的工作列表。

在这种情况下,有三个类(“软件开发”、“设计”和“营销”)。利用每个类别中的工作列表样本,我们可以训练一个朴素贝叶斯分类器,以便自动对*新的*工作列表进行分类。

我们将在本文剩余部分探讨的示例是**垃圾邮件/垃圾邮件分类,**因此,有两个类别:“垃圾邮件”和“垃圾邮件”(即非垃圾邮件)。如前所述,唯一的先决条件是拥有已知为垃圾邮件的现有*训练集*和已知为垃圾邮件的训练集*。*

为了说明清楚,我们的训练集将由三封垃圾邮件和三封垃圾邮件组成(下面的图片是可点击的,因此您可以放大并阅读每封邮件):

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fd6bea97abb6f54cb2ca1fd7e2d7740f7.png&pos_id=img-hReRhYFD-1727458261997)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F4a9f493486c24bc3660d8c462616c5c5.png&pos_id=img-FnPIPU3E-1727458261997)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F2b6bd46992a03ad03362d7859539e3d6.png&pos_id=img-kjzUyK1H-1727458261998)

Examples of HAM emails.

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F2b86f712d37afd14f04f2ec07ca2f34a.png&pos_id=img-KMXvNzLN-1727458261998)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F010ee4a290d36304b60b1e2b02814c37.png&pos_id=img-XLNwshis-1727458261998)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Ff07446d42cc48c483efe53b94448d8f1.png&pos_id=img-xJEY6arz-1727458261998)

Examples of SPAM emails.

请注意,在生产级垃圾邮件过滤器中,训练集的大小(即,已知垃圾邮件和 Ham 电子邮件的数量)通常要大得多,然而,我们将在此开发的概念和直觉确实适用。

# **步骤二。计算每个类别的术语文档矩阵(TDM)**

术语-文档矩阵(TDM)由出现在一组文档中的词频列表组成。

TDM 矩阵是由 *n* 个字和 *m* 个文档组成的稀疏矩形矩阵。之所以说它稀疏,是因为它包含的大部分都是零。TDM 矩阵的条目( *i,j* )表示单词“*I”*在文档“*j”*中的出现频率。

对于考虑英语中所有单词的英语垃圾邮件分类器,单词的数量( *n* )大约为 170k。至于每节课的例题数量,一般规律是越多越好:-)。然而,实际上,几千条信息给出了合理的预测。对于垃圾邮件检测任务,垃圾邮件标记数据的实际来源是 [SpamAssassin](https://spamassassin.apache.org/) 。

以下图片摘自垃圾邮件和垃圾邮件类别的 TDM 矩阵:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Faa76766b660c6b03012f7ec4f7af83b4.png&pos_id=img-PsVlDTUl-1727458261999)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fe9a0817c07c5e8fcc7e4b83493c94bdf.png&pos_id=img-gezsaf6P-1727458261999)

Term document matrix excerpts for the HAM and SPAM emails.

# 九月三日。计算频率

一旦为每个类别计算了 TDM 矩阵,下一步就是计算每个术语的频率和出现次数:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fe833114811c71d74b0b08b056920869e.png&pos_id=img-Y0MdHIPb-1727458261999)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fcaaa13cd3339892be9ae788ffdf6569c.png&pos_id=img-5SoK2epH-1727458261999)

Top 10 terms sorted by frequency for the HAM and SPAM classes.

根据原始频率计数,您可以推断垃圾邮件包含高频术语,如“免费”,而垃圾邮件包含高频术语,如“考试”。这就是分类器将能够区分一个类和另一个类的方式。

“频率”列是每个术语在所有文档中出现的次数,即 TDM 矩阵各列的总和。“出现”列是每个术语在所有文档中出现的时间百分比。

“频率”和“出现”列都可以用于计算概率估计,但是,“出现”列是优选的,因为它被限制在 0 和 1 之间。

# **第四步。回想一下朴素贝叶斯法则**

根据基本概率,假设另一个事件 **B** 也发生了,那么一个事件 **A** 发生的概率是多少?按顺序的话,**A**给 B 的概率是多少?

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fc2ac916bb20192a95310e4394e8ab40c.png&pos_id=img-BmktNBwl-1727458262000)

Probability of A given B.

从下面的文氏图中

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F3d9329f29079ce89f2f1f858cd05d6d4.png&pos_id=img-gb5625vf-1727458262000)

我们可以看到,给定 B 的概率是 A 和 B (交集)发生的**概率除以 B** 发生的**概率**,**即:**

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F900fe7404c0a0b8811907d4d91c22d39.png&pos_id=img-GadDnz1R-1727458262000)

Eq. 1

现在,假设 A 也发生了,那么 B 发生的概率呢?根据前面的公式,我们得到:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F1cbf5f4f09ce52ff0b386f6285aa8000.png&pos_id=img-yIdmumRy-1727458262000)

Eq. 2

从文氏图中可以看出

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F7d3e92b1e8f98064609c9aef8c983af0.png&pos_id=img-Xk8d4bte-1727458262000)

因此,通过等式。1 和 Eq。2 我们得到贝叶斯定理:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fcf33ed06385068bc5c1a9e00a32d1580.png&pos_id=img-u7KJHH8y-1727458262001)

**Bayes theorem**

鉴于贝叶斯定理在概率论中的重要性,每个术语都有一个名称:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F625045fae7ca9f542a0b68f390f72acc.png&pos_id=img-ZbSB9lkb-1727458262001)

Naming terms in Bayes theorem

简单来说,“**先验**”*P(A)*、“**证据**”*P(B)*是指相互独立地观察到 A 和 B 的概率,而“**后验**”和“**似然**是观察到给定 B 的**条件** **概率**,反之亦然。

回到我们在垃圾邮件或 Ham 中的电子邮件分类示例,我们要计算的概率是:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F99fc6599097094139c81e5b96889d5bc.png&pos_id=img-ssDwMwnu-1727458262001)

其中 **x** 是包含来自垃圾邮件的单词的特征向量:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fb22e2702a79fb290e5ff8adb2bb00912.png&pos_id=img-x37YitRx-1727458262002)

Feature vector **x** composed of **n** words coming from spam emails.

*朴素贝叶斯*结果是“**可能性**”是在一组垃圾邮件或业余电子邮件中看到每个单词的个体概率的乘积。我们在步骤 3 中计算了这些概率,并将它们存储在“发生”列中。形式上:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F40971eab4758062380b5b9b846cd0926.png&pos_id=img-S1oGMmIJ-1727458262002)

注意“**证据**”是一个仅取决于特征的常数因子,因此在前面的等式中为“**可能性**”计算引入了比例符号。

此外,由于我们的数据集有 3 封垃圾邮件和 3 封垃圾邮件,我们知道“**优先于**”*P(垃圾邮件)*是 50%。

总之,由于我们在贝叶斯定理中有所有必要的术语(“**可能性**”、“**先验**”和“**证据**”),我们可以继续计算“**后验**”概率。回答这个等式的概率是,给定的(看不见的)电子邮件是垃圾邮件的概率是多少?

> 回想一下,朴素贝叶斯分类器的主要假设是每个特征(单词)彼此独立。

# **第五步。计算收到垃圾邮件的概率**

假设我们计算了垃圾邮件或业余爱好者电子邮件中出现的术语的概率数据库,我们可以继续进行*朴素贝叶斯分类器*的最后一步,即分类。

正式的决策规则是:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F73f4c073f3cf4ed1915d95179ca04673.png&pos_id=img-I25en4Vz-1727458262003)

Decision rule: pick the most probable hypothesis.

这意味着,对于每个传入的电子邮件,我们必须计算此类电子邮件是垃圾邮件和垃圾邮件的概率(即,对于每个类),并且我们的最终验证将由最大概率给出。

以下面的电子邮件为例:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F58d8b477af52ed92f973d066a10035c9.png&pos_id=img-np3qq0Tq-1727458262003)

Test HAM email.

假设不在我们的训练集中的单词的任意小概率为 1e-2,则每个类别的概率为:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F6eb01dde7dc38970b057512d6b04a27d.png&pos_id=img-UsAdcxlO-1727458262003)

表明该电子邮件是垃圾邮件。

关于小数字的链乘的注释(感谢 [jgrahamc](https://news.ycombinator.com/user?id=jgrahamc) ):

【http://getpopfile.org/docs/faq:bayesandlogs】
参考:“实际上,取概率的 log()是有用的,这样你就可以处理对数的和,而不是乘以小的浮点数”

## 参考资料和源代码:

[![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F5cd71e827eea520f79696a3f5ab61aca.png&pos_id=img-dXTbAzuW-1727458262003)](https://amzn.to/2Xjkuqa)

文件处理、TDM 矩阵计算、频率、最终分类和示例电子邮件的源代码可以在这个存储库中找到:[**https://github . com/gchave z2/code _ machine _ learning _ algorithms**](https://github.com/gchavez2/code_machine_learning_algorithms)。

该代码大量借鉴了 O'Reilly Media 出版的[Conway&Myles Machine Learning for Hackers 一书第 3 章](https://amzn.to/2Xjkuqa),该书还提供了一个更大的垃圾邮件和业余邮件数据库,以及估计不在训练集词汇中的单词概率的策略。

*我是劳伦斯伯克利国家实验室的博士后,在那里从事机器学习和高性能计算的交叉工作。*

*如果你觉得这篇文章很有趣,请随意打个招呼,联系 LinkedIn* *,我总是很乐意与该领域的其他专业人士交流。*

*一如既往:非常感谢评论、问题和分享!❤️*

[![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Ffc9812283b6ecba784677161ec8ba4ef.png&pos_id=img-JwBbVDxo-1727458262004)](http://eepurl.com/giSKB9)

No Spam, ever.

# 用机器学习实现星巴克的盈利促销策略(上)

> 原文:<https://towardsdatascience.com/implementing-a-profitable-promotional-strategy-for-starbucks-with-machine-learning-part-1-2f25ec9ae00c?source=collection_archive---------11----------------------->

在这个系列中,我们将为星巴克设计一个促销策略,并介绍从数据预处理到建模的整个过程。这是我为 Udacity 数据科学家 Nanodegree Capstone 项目设计的解决方案。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fb7f216b2994797da58853fc3d5a78e71.png&pos_id=img-hMy4Up6u-1727458262004)

*在本系列的第一部分,我们将介绍项目介绍、数据集描述、可用促销类型、缺失值输入、数据预处理和探索性数据分析。*

[*链接*](https://medium.com/@joshxinjielee/implementing-a-profitable-promotional-strategy-for-starbucks-with-machine-learning-part-2-8dd82b21577c) *到本文第二部分。*

*本文附带的代码可以在* [*这里*](https://github.com/joshxinjie/Data_Scientist_Nanodegree/tree/master/capstone) *找到。*

# 一.导言

在这一系列文章中,我们将探索星巴克奖励移动应用程序的数据,并利用机器学习来设计促销策略。我们还将浏览整个数据预处理工作流程,并设计一个指标来测试我们的促销策略。

我们希望在本文结尾回答的问题是:

我们能通过采取更具选择性的促销策略来增加星巴克的利润吗?

作为 Udacity 数据科学家 Nanodegree Capstone 项目的一部分,星巴克友好地提供了一个模拟数据集,模拟客户在他们的奖励移动应用程序上的行为。数据集也可以在我的 [GitHub](https://github.com/joshxinjie/Data_Scientist_Nanodegree/tree/master/capstone) 仓库中找到。

情况是这样的:每隔几天,星巴克就会在手机 app 上向顾客发出促销信息。这些可以是折扣优惠、买一送一优惠(BOGO)或信息优惠。

促销通常需要一定的成本。在我们的例子中,买一送一或打折促销会导致公司的“利润损失”,因为公司牺牲了一些利润来给予顾客金钱激励(免费产品或折扣)。

如果顾客已经愿意在没有任何促销的情况下购买星巴克的产品,那么我们应该放弃给这部分顾客任何促销。

此外,还有一群人被称为“睡狗”。“睡狗”是购买你的产品的人,但如果他们被包括在你的营销活动中,他们会停止这样做。

因此,向每个人发送促销信息并不是一个合理的商业策略。理想情况下,我们希望将促销信息发送给那些只有在收到优惠信息时才会购买的人,同时我们也希望避免将促销信息发送给“睡觉的狗”。

我们的目标是制定一个促销策略,该策略可以确定我们应该向哪些人进行促销,以实现公司利润的最大化。

为了帮助我们解决这个问题,我们将利用抬升模型。提升模型允许我们对治疗(在我们的案例中是促销)对客户购买行为的增量影响进行建模。

如果您有兴趣了解关于提升模型的更多信息,请查看这篇[文章](https://medium.com/datadriveninvestor/simple-machine-learning-techniques-to-improve-your-marketing-strategy-demystifying-uplift-models-dc4fb3f927a2)。

虽然提升模型确实非常有益,但它们有时很难实现。值得注意的是,最大的挑战是找到最佳方法来模拟促销对个人反应的增量影响。

尽管如此,这些模型为我们提供了提高促销效果的最佳机会。所以,我们应该试一试!

# 二。资料组

Starbucks 为此项目提供了 3 个数据文件。下面列出了数据文件及其模式:

## 作品集. json

1.  id(字符串)—优惠 id
2.  offer_type (string) —优惠的类型,如 BOGO、折扣、信息
3.  难度(int)——完成报价所需的最低花费
4.  奖励(int) —为完成一项提议而给予的奖励
5.  duration (int) —报价的有效期
6.  渠道(字符串列表)—发送要约的媒介

投资组合数据集包含有关 10 种可通过应用程序获得的促销活动的信息。

有三种主要的促销方式:信息促销、折扣促销和买一送一(BOGO)促销。

在数据集中,术语“优惠类型”用于指代类似促销的集合。例如,它可以指一系列的折扣促销。

我发现这个术语令人困惑,所以我将把类似的促销统称为简单的家庭型优惠。我将使用术语“优惠类型”或“促销类型”来指代 10 种促销类型中的每一种。

信息提供没有附加的金钱奖励。这些促销活动主要是饮料广告。

折扣优惠通常提供少量的金钱奖励,前提是顾客在优惠期限内消费了一定数量的钱。

解锁奖励所需花费的金额将被称为提供的难度。

BOGO 类似于折扣优惠,除了他们提供相当于优惠难度的金钱奖励。

优惠详情可在下面查看:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F45b2628f3fb3ff4d83aca8611ed2c0da.png&pos_id=img-tdnbuQmj-1727458262004)

Portfolio dataset with offer id re-encoded

请注意,为了简化工作过程,我将原始报价 id 从它们的原始哈希值重新编码为整数(0–9)。

## profile.json

1.  年龄(整数)—客户的年龄
2.  变成 _ 成员 _ 开(整数)—客户创建应用帐户时的数据
3.  性别(str) —客户的性别
4.  id (str) —客户 id
5.  收入(浮动)—客户的收入

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F6e5453ea1a919685d2528307aba64e91.png&pos_id=img-eA3mvAP9-1727458262005)

Snapshot of original profile dataset

简档数据集包含关于客户的人口统计信息。

只有 4 个人口统计属性,我们可以工作:年龄,收入,性别和会员开始日期。一部分配置文件数据集有缺失值,这些问题将在本文后面讨论。

## 抄本. json

1.  事件(str) —记录描述(即交易、收到的报价、查看的报价等)
2.  人员(字符串)—客户 id
3.  time (int) —以小时为单位的时间。数据开始于时间 t=0
4.  value(字符串字典)—根据记录,可以是报价 id,也可以是交易金额。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F9322ecff174e8ef229c6a9e63fc5592c.png&pos_id=img-oQ03rQkV-1727458262005)

Snapshot of original transcript dataset

副本数据集记录了在应用程序上进行购买的时间戳,以及收到、查看或完成报价的时间戳。

在我们继续之前,有几个关于数据集的细节需要强调。

1.  客户不需要在一次交易中花光所有的钱来激活优惠。只要他们在要约的持续时间内达到要求的金额,无论他们进行了多少次交易,他们都将获得要约的奖励。
2.  即使用户实际上没有查看报价而是花费了所需的金额,报价也可以被记录为已完成。
3.  即使优惠已过期,也可以将优惠记录为已完成。例如,让我们考虑在时间 7 到期的报价。如果客户在稍后的时间(可能是时间 20)花费了所需的金额,该报价仍将被记录为已完成。实际上,这一优惠并未“完成”,客户也不会享受到促销的回报。因此,在处理数据时,我们需要考虑这种情况。
4.  每个报价、人员和时间组合都没有唯一的序列号。这可能会导致关于转录数据集的解释的混乱。例如,客户可能在时间 7 收到 10 美元的 BOGO 折扣,在时间 31 收到另一个相同的报价。该应用然后可以在时间 52 记录要约完成。但是,我们不知道哪个是在时间 52 完成的相关报价,因为问题编号为 3。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Faa450f2a06229b29d8abcc0a322be1b1.png&pos_id=img-C9mmEMaF-1727458262007)

An example illustrating problems 3 and 4\. Note the events at time 0, 6, 132\. This offer has a validity of 7 days and should have been expired at time 7\. Nonetheless, it was “completed” 132 days after it was sent.

这些特性意味着,尽管我们应该能够恢复其中的大部分,但重新获得每个报价的确切结果可能是不可能的。

# 三。可用优惠

以下是通过该应用程序提供的优惠:

***优惠 id 号:优惠家庭类型、有效期、难度、奖励***

1.  优惠 id 0:折扣 10/20/5
2.  优惠 id 1:折扣 7/7/3
3.  优惠 id 2:折扣 7/10/2
4.  报价 id 3:信息 4/0/0
5.  优惠 id 4:BOGO 2010 年 10 月 5 日
6.  报价 id 5:信息 3/0/0
7.  报价 id 6: BOGO 7 月 5 日
8.  优惠 id 7:BOGO 2010 年 7 月 10 日
9.  报价 id 8: BOGO 5 月 5 日
10.  优惠 id 9:折扣 10/10/2

我将在整篇文章中使用相同的报价参考系统。

注意:我将使用 Offer id 10 来表示非 Offer 情况。这一点过一会儿就清楚了。

# 四。预测缺失值

大约 12.8%的个人资料数据集包含性别和收入的缺失值。巧合的是,个人要么缺少年龄和收入数据,要么一个都没有。此外,性别和收入信息缺失的个人都有相同的 118 岁。

很可能这些人实际上并没有 118 岁。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fd733df020cd2ba79fdbe7f3f1e59eb95.png&pos_id=img-bVm7vZQs-1727458262007)

Distribution of Age. Note the outlier group at age 118.

合理的解释是,在处理缺失的人口统计数据时,118 是应用程序的默认输入年龄。

由于年龄、收入和性别是唯一可用的人口统计数据(除了会员开始日期),因此解决这些缺失数据非常重要。

一种解决方案是删除丢失数据的个人。然而,这也将意味着丢失很大一部分数据。

由于该群体的规模,这些人可能具有不同的人口统计属性。因此,我决定使用基于机器学习的方法来预测缺失值,而不是用单个值(如平均值)来输入缺失值。

## 特征工程

由于会员开始日期是唯一可以用于我们的机器学习模型的人口统计信息,我希望不同性别、收入水平和年龄组的个人之间存在交易行为的差异。

交易行为的统计数据将在单个基础上进行汇总。对于每个人,我都记录了:

1.  收到的报价数量
2.  成功完成的出价数
3.  已尝试但未完成的聘用数量
4.  成功完成的出价百分比
5.  尝试出价的百分比
6.  报价总支出
7.  为报价进行的交易总数
8.  报价的平均每笔交易支出

这些数字是在累积的基础上(所有报价加无报价)、每种报价类型(id0–9 加 id 10 代表无报价)和每种报价系列类型(BOGO、折扣、信息)汇总的。

*注:成功/尝试报价的定义可在第五节定义成功/尝试/失败报价小节中找到。数据预处理:生成月度数据*

还计算了其他比率,例如:

1.  优惠类型和优惠系列类型的支出占总支出的比率
2.  优惠类型和优惠系列类型的交易数量占交易总数的比率
3.  收到的优惠类型和优惠系列类型的数量与收到的优惠总数的比率

由于创建了大量的特性,所以我不会在本文中一一列出。要了解更多细节,请参考我的 [GitHub](https://github.com/joshxinjie/Data_Scientist_Nanodegree/tree/master/capstone) 存储库中的文件 *input_missing_data.ipynb* 中的代码。

任何空值都将被替换为 0,因为空值通常表示没有收到/查看/完成报价或没有支出。

为了区分 1)收到一份工作邀请但没有回应的情况和 2)根本没有收到工作邀请的情况,跟踪了每个人收到的工作邀请的数量。

模型的输入特征将是新设计的特征和成员资格开始日期。

由于特征的高度稀疏性,很大程度上由于低完成率和报价的低支出,对这些输入特征进行了降维。

为了防止具有较大值的特征支配其他特征,对特征进行了归一化。标准缩放用于将这些特征减少到平均值 0 和标准偏差 1。

## 模型

创建了 3 个独立的模型,每个模型对应一个缺失的属性:年龄、收入和性别。没有缺失值的概况数据集部分将用于训练模型(约占概况数据的 87.2%)。

年龄和收入模型都是回归问题,而性别模型是多类分类问题。在网格搜索过程中使用具有 5 个折叠的 k 折叠交叉验证来优化模型。

XGBRegressor 和 XGBClassifier 分别是为回归和分类任务选择的模型。这些是相对快速和准确的基于树的非线性模型。

这些模型唯一的主要缺点是它们不能天生地提取特征交互。

例如,如果我们的数据集只跟踪每种优惠类型的总支出(例如,BOGO 5/5/5 为 10 美元,BOGO 7/10/10 为 30 美元,等等。),但并非针对每种家庭类型(例如,所有 BOGO 优惠均为 40 美元),XGBoost 模型将仅基于每种优惠类型的支出做出建模决策。它无法提取任何关于 BOGO 优惠等级总支出的信息,也无法在建模过程中使用这些信息。

因此,如果我们想要我们的模型利用它们,我们将需要手工设计这些特性交互。

## 韵律学

均方根误差(RMSE)被选为年龄和收入模型的优化指标,因为我想优先考虑预测的准确性。

请注意,最小化 RMSE 等同于最小化均方误差(MSE),因为 RMSE 是 MSE 的平方根(线性变换)。

RMSE 是这样计算的:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fd08780a38f1e0250b815318415b668c3.png&pos_id=img-afifSbff-1727458262007)

In our case, Pi is the predicted age/gender and Oi is the actual age/gender for each sample i.

另一方面,微观平均 F1 分数被用作性别模型的优化指标。微观平均 F1 分数将按以下方式计算:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F84b6974143d687ad7f8d4c791391d5c9.png&pos_id=img-dpyBVGoh-1727458262008)

在哪里

*   TP —真阳性。预测属于性别 *g* ,实际属于性别 *g* 的样本数。
*   FP —误报。预测属于性别 *g* 但实际不属于性别 *g* 的样本数。
*   TN——真正的否定。预测不属于性别 *g* ,实际不属于性别 *g* 的样本数。
*   FN —假阴性。预测不属于性别 *g* 但实际属于性别 *g* 的样本数。

f、M、O 分别代表“女性”、“男性”和“其他”性别。

## 结果

预测个人年龄的模型实现了大约 16.5 的 RMSE,而预测个人收入的模型实现了大约 13,500 的 RMSE。这些数字意味着,平均而言,年龄预测误差 16.5 岁,而收入预测误差 13500 美元。

另一方面,在性别预测模型的测试集上记录了 0.6 的 F1 分数(1 是最佳可能模型的分数)。一个有趣的观察是,性别的预测值似乎由男性主导。如果时间允许,可以进行更多的调查,以查明为什么会出现这种情况。

这些模型指标远非理想。然而,考虑到可用的信息量有限,这些结果是可以接受的。尽管如此,这些估算的数字应该比用常数填充缺失值的替代方法更好地为我们服务。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Ff8565051ac17b1ffbc511671b45b4a77.png&pos_id=img-zzzBsXFp-1727458262008)

Left: Original Distribution of Age, Middle: Distribution of Predicted Age for Missing Data, Right: Final Combined Distribution of Age

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F93595545da01c26ff9bbfc0075796dc0.png&pos_id=img-UgHgSfml-1727458262008)

Left: Original Distribution of Income, Middle: Distribution of Predicted Income for Missing Data, Right: Final Combined Distribution of Income

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F478bbb59d060df501092649332e866d7.png&pos_id=img-ncFm6Ktu-1727458262008)

Left: Original Distribution of Gender, Middle: Distribution of Predicted Gender for Missing Data, Right: Final Combined Distribution of Gender

# 动词 (verb 的缩写)数据预处理:生成每月数据

为了将数据集转换成有用的东西,我们必须执行大量的数据清理和预处理。

在本节的最后,我们将生成一个数据集,如下所示:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F25f8ea49cd163693d694cbbadf96ae44.png&pos_id=img-StLWWL8m-1727458262009)

Snapshot of Monthly Data After Data Preprocessing

主要任务是确定与没有收到报价相比,收到报价时可能会花更多钱的人。因此,我们需要一个数据集来反映用户在促销和非促销情况下的反应。

我们还对顾客的行为是否会随着时间的推移而改变感兴趣。

因此,我选择每月汇总客户的反馈。由于没有给出实际的日期,我将估计一个月为 30 天,并将第 0 天视为第 0 个月的开始。

从上面的快照中,我们知道“人员 id 2”在第 0 个月收到了促销“优惠 id 2”。这个人在这个月里没有在这个提议上花任何钱。同样,“人物标识 2”也没有在非促销场合花任何钱。

请注意,为简单起见,我将使用“优惠 id 10”来表示非促销支出。

每个月,数据集应该跟踪:

1.  如果客户收到优惠,他们在优惠有效期内消费了多少。如果他们不花钱,这个数字可能是 0。
2.  顾客在没有优惠的时候花了多少钱。如果他们不花钱,这个数字也可能是 0。

对随机选择的个人交易的检查表明,客户通常一个月不会收到超过 1 个报价。因此,与每月的促销日相比,消费者暴露于更多的非促销日。

每月汇总数据比每天/每周汇总数据更受欢迎,因为大多数客户每隔几个月就会收到一次报价。如果每天/每周汇总数据,将会有太多天/周没有任何促销活动。

我现在将讨论生成每月数据集的过程。这是一个冗长的讨论,最好遵循代码。因此,如果您想跳过这一部分,请继续阅读第六部分。本页末尾附近的“探索性数据分析”。

## 定义成功/尝试/失败的报价

在我们跟踪顾客在促销有效期内花了多少钱之前,我们需要根据可能的结果对优惠进行分类。有三种可能性:成功、尝试和失败。

要将要约归类为成功,必须在要约到期前收到、查看并完成要约。这意味着客户知道促销活动,并因此进行交易。

如果客户在查看报价之前完成了报价,则报价不会被分类为成功,因为客户在进行交易时不受报价的影响。

如果顾客在查看报价之前进行了一些交易,但是没有花足够的钱来完成报价。如果他/她在要约仍然有效时查看了要约,并在要约到期前花了更多的钱来完成要约,那么要约也将被归类为成功。

因此,成功报价的事件流程是:

*   已收到报价-> *可选:已成交* - >已查看报价- >已成交- >已完成报价- >已到期报价

“尝试过的优惠”是指顾客在优惠到期前查看了优惠,花了一些钱,但没有完成它。因此,客户没有花足够的钱来完成要约的要求。

由于信息性要约没有要约完成事件,如果客户在要约有效期内查看了要约并花费了一些钱,则它们将被视为尝试性要约。

尝试报价的事件流程如下:

*   报价已收到-> *可选:成交- >* 报价已查看- >成交- >报价已到期- > *可选:报价已完成*

失败的报价将不属于前面提到的两个类别。

例如,如果收到并查看了要约,但在要约到期之前没有进行交易,则该要约将是失败的要约。

如果要约在到期前收到但未被查看,也将被归类为失败的要约,即使在要约的有效期内花了钱。这是因为顾客在消费时不受优惠的影响。

跟踪促销期间花费的金额相当于找到成功和尝试过的优惠花费的金额。

## 分割抄本数据集

预处理的第一步包括将原始转录物分成 4 个更小的子集:

1.  *抄本 _ 报价 _ 已收*:跟踪客户何时收到报价以及他们收到了何种报价
2.  *文字记录 _ 报价 _* 已查看:跟踪客户查看报价的时间以及他们查看的报价类型
3.  *抄本 _ 报价 _ 已完成*:跟踪客户何时完成报价以及他们完成了何种报价
4.  *transcript_trans* :跟踪客户进行的所有交易

## 生成带标签的月度交易数据

首先,我们将确定成功或尝试过的产品。我们首先将*抄本 _ 报价 _ 接收、抄本 _ 报价 _ 查看*和*抄本 _ 报价 _ 完成*合并在一起*。*生成的数据帧将如下所示。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F7e897a8774b95eeda9124a0581c1f459.png&pos_id=img-mXL9oQCh-1727458262009)

在这个阶段,合并过程中产生的许多报价将是无意义的。

我们可以通过保留符合以下条件的产品来消除大量虚假产品:

1.  完成的报价时间>查看的报价时间>收到的报价时间
2.  (查看的报价时间>收到的报价时间)和(完成的报价时间为空)
3.  查看的时间报价和完成的时间报价均为空

现阶段虚假要约依然存在,需要进一步处理。

我们可以通过将要约的持续时间与要约的接收时间相加来计算所有要约的到期时间。

接下来,我们可以将这些提议分为可能的结果:成功、尝试或失败/错误。请注意,在这个阶段的分类并不一定意味着要约是真正成功的或尝试。我们稍后将需要交易信息来找出答案。

满足以下条件的报价将被归类为可能成功的报价:

1.  (收到的优惠时间≤查看的优惠时间)和(查看的优惠时间≤完成的优惠时间)以及(完成的优惠时间≤优惠到期时间)

满足以下条件的要约被归类为可能尝试的要约:

1.  (收到报价时间≤查看报价时间)和(查看报价时间≤报价到期时间)以及(报价到期时间
2.  (收到的时间报价≤查看的时间报价)和(查看的时间报价≤时间报价到期)以及完成的时间报价为空

不满足这些条件的其余提议或者是失败的或者是错误的提议,并且将被丢弃。

除了第一次出现的情况之外,任何具有重复的“接收时间”、“人员标识”和“报价标识”值的报价都将被删除。一个人不太可能一次收到同一种聘用不止一次,这些重复的条目是在合并过程中生成的错误条目。

我们将调用结果数据帧*succ _ tryed _ offers*。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F718964ede2d6ed93646ccd153e3691e2.png&pos_id=img-9ifv3ogj-1727458262009)

A snapshot of succ_tried_offers at this stage of processing

接下来,我们可以将*的抄本 _ 交易*与*的成功 _ 尝试 _ 报价*合并,以获得成功/尝试报价和交易之间所有可能的交叉积。

我们可以标记每笔交易,看看它们是否发生在报价有效期内。换句话说,我们将检查消费是否发生在收到报价之后和报价过期之前。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fde48e97c142378aee999429331a4b239.png&pos_id=img-tGDUk7mT-1727458262009)

在有效期内发生交易的*succ _ tryed _ offers*中的任何报价都可能是实际成功或已尝试的报价。

然后,我们可以将带标签的事务执行左合并,返回到原始的事务副本,以避免任何潜在的事务重复计算。这也将使我们能够确定哪些交易发生在非促销期间。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F70ecb28b48e1c01d8499504a7b6b3f07.png&pos_id=img-2WjiJuIR-1727458262010)

The labelled transactions

接下来,我们可以分配交易发生的月份,并根据月份号、人员 id 和优惠 id 聚合数据。这将每月生成一份客户在促销和非促销期间消费金额的汇总。我们将该数据帧称为*月度交易*。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F941053c3b12248d8c9b4113c12cce416.png&pos_id=img-phGDVxFQ-1727458262010)

A snapshot of monthly_transactions

## 寻找没有每月交易的优惠

从*succ _ tryed _ offers*中,我们知道哪些报价是成功的或尝试过的。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F96340907a5a4482f7e529b0f188582b0.png&pos_id=img-T8yB7BOY-1727458262010)

Offers that were successful or tried

我们可以从*抄本 _received 中获得星巴克发出的所有报价的列表。*

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F152df4effb3d54ed0944db2d9e357d11.png&pos_id=img-uvRDAEuN-1727458262011)

Snapshot of all offers sent

两者之间的差异可以告诉我们哪些提议失败了。这些要约在有效期内没有引发任何货币交易。

接下来,我们可以指定收到这些失败报价的月份号,并将结果数据帧命名为 *monthly_failed_offers。*

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fe8ecec191bdc7941337ba9aa78258291.png&pos_id=img-oIMPq6V5-1727458262011)

Snapshot of *monthly_failed_offers*

## 找出个人没有进行非要约交易的月份

请注意 *monthly_transactions* 已经跟踪了客户在非促销期间的花费。我们的目标是找出哪些月份的顾客在非促销期间没有花钱。

首先,我们生成月份号、人员 id 和报价 id 10(非促销曝光)的所有可能组合。我们把这个数据帧称为 *non_offer_trans* 。

然后,我们可以将 *monthly_transactions* 数据框架合并到 *non_offer_trans* 中,以找出哪些月份-个人组合在非促销期间没有货币交易。

因此,我们将获得客户在非促销情况下不花钱的月度账户。我们姑且称这个数据帧 *no_offer_no_trans* 。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F6883b0fc3a150bed6c14a0fb3bb916c0.png&pos_id=img-WXQSlXay-1727458262011)

Snapshot of no_offer_no_trans

## 将它们聚集在一起

最后,我们可以将 *monthly_transactions* 、 *monthly_failed_offers* 和 *no_offer_no_trans* 串联在一起*,生成 *monthly_data* 。*产生的数据集每月追踪每个人在发送给他们的不同促销活动上花了多少钱,以及他们花了多少非促销费用。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fd170fac52ca9554bf6d7c0de1b1e7a76.png&pos_id=img-pkg2Cdl8-1727458262011)

Snapshot of monthly data at this stage

## 计算利润并生成标签

接下来,我们必须计算数据集的每个实例产生的利润。我们首先需要计算每个人每月收到的报价数量。这使我们能够计算与报价相关的成本。

一个简单的方法是检查个人是否在一个月内接触到每种类型的一个以上的报价。通过检查*抄本 _ 已接收*,我们注意到以下内容:

1.  没有人在同一个月内多次收到相同的报价类型。
2.  如果个人收到下个月到期的要约,他/她在下个月将不会收到类似的要约。例如,如果个人在第 16 个月收到“要约 id 2 ”,而要约在第 17 个月到期。他/她不会在第 17 个月收到另一个“要约 id 2”。

因此,我们可以得出结论,客户每月最多只能接触到一次优惠类型。

这意味着 *monthly_data* 中的成本只是完成促销的奖励。

我们可以通过以下 3 条规则来计算每个人每个月为每种优惠类型创造的利润:

1.  如果要约成功,利润将是每月收入减去要约的成本。请注意,提供信息是没有成本的。
2.  如果要约不成功,利润将是在该实例中产生的收入。
3.  如果交易不是要约的一部分,利润就是收入,因为不涉及成本。

我们将使用的提升模型涉及在两种情况下对给定人员和月份的利润概率进行建模:

1.  如果这个人收到一份工作邀请。
2.  如果这个人没有收到聘书。

因为我们想要预测利润的概率,我们的标签( *has_profit)* 将只是一个指示变量,指示该实例是否有利润。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F25f8ea49cd163693d694cbbadf96ae44.png&pos_id=img-O4VE4fRD-1727458262012)

Resulting monthly_data obtained at the end of the process

# 不及物动词探索性数据分析

## 大多数优惠都没有被顾客尝试过

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F6fe7a66f033279fb913e3d2dbb74a009.png&pos_id=img-2BpYPad1-1727458262012)

从上面的图表中,我们注意到绝大多数的优惠都没有被顾客尝试过。

一个普遍的观察是,具有更长有效期、更高回报和更低难度的报价往往具有更高的成功/尝试率。

请注意,信息性报价无法完成,因为它们缺乏难度。因此,他们要么尝试或失败。

## 只有少数客户成功完成或尝试了一次以上的优惠

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fb6a2c8a6299e60adb392b9faf2d9b368.png&pos_id=img-6ZTsmKwF-1727458262012)

在研究期间,大多数客户收到了 3 到 6 份报价。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fe942d3ac2effd6c8754f7e46e039265d.png&pos_id=img-7q3dYOQg-1727458262012)

然而,绝大多数客户没有成功完成任何优惠。他们中只有一小部分人完成了 1 次报价,更少的人完成了 2 次或更多次报价。

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fbb0c58190a49c9c6258371c77bf1ae16.png&pos_id=img-F67r08y7-1727458262013)

对于尝试过(但未成功完成)的要约也是如此。面对优惠,很少有顾客做出反应(花钱)。对两个或两个以上的提议做出回应的情况极为罕见。

总的来说,优惠似乎效力有限。

## 月度利润趋势

左边的图表显示了每月获得晋升的人数。此外,图表将显示这些人中有多少人每月产生促销利润和非促销利润。盈利实例也可以定义为来自 *monthly_data* 数据集的数据点,其 *has_profit* 标签为 1。

右边的图表显示了接受促销的个人每月产生的总利润,以及他们的促销和非促销支出的总利润。

从这些图表中,我们可以衡量促销的有效性,并评估这些促销的有效性是否随时间而变化。

**折扣 10/20/5(优惠 ID 0)**

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F395c7ebe9a9506ee274bb4829e4a5737.png&pos_id=img-3vVp3OjI-1727458262013)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F9bcc150fa55f40d5f5c750e5c90c1cf1.png&pos_id=img-XxeGVIq9-1727458262013)

Plotted from individuals who received Discount 10/20/5 offers each month

**折扣 7/7/3(优惠 ID 1)**

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fbfd8219b698cfc2c26f0fc69f7ac3058.png&pos_id=img-TY8GDFJP-1727458262014)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F482fe431d626de1b9cfedfd3200a5d4e.png&pos_id=img-Zo3919lF-1727458262014)

Plotted from individuals who received Discount 7/7/3 offers each month

**折扣 7/10/2(优惠 ID 2)**

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F4ad9ef84471c874b2204e4bbb281cba2.png&pos_id=img-VbUQPult-1727458262014)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fd03ef833ebb67794d0742ed1b3b754ca.png&pos_id=img-Cr2UJaJJ-1727458262014)

Plotted from individuals who received Discount 7/10/2 offers each month

**信息 4/0/0(报价 ID 3)**

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F3d95bd7eafd44060994907818ad68845.png&pos_id=img-T2XO8tDM-1727458262015)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F632ce69af4bed4459aaee9b44361e0cc.png&pos_id=img-OiSz3vaL-1727458262015)

Plotted from individuals who received Informational 4/0/0 offers each month

**BOGO 2010 年 5 月 10 日(报价 ID 4)**

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F9bf27e6ee6144156e7e47eddf32b52e2.png&pos_id=img-li8Ph6ID-1727458262015)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fc60d2d62aa3a1176bc26a3a3d52c4199.png&pos_id=img-omroBzfg-1727458262016)

Plotted from individuals who received BOGO 5/10/10 offers each month

**信息 3/0/0(报价 ID 5)**

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fa2715416b178a33a34b1d0fb585b7b5e.png&pos_id=img-tJjFjqYX-1727458262016)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F173ffc509db5d9461f5f5c56ad082f86.png&pos_id=img-IyhXStmU-1727458262016)

Plotted from individuals who received Informational 3/0/0 offers each month

**BOGO 5 月 7 日(报价 ID 6)**

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fa2348560d3bb6daa856b1f8aeb27ae53.png&pos_id=img-PwHJGpFk-1727458262016)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F85f2f9d05fd7329037b5749b198ebba6.png&pos_id=img-j1aLxWgu-1727458262016)

Plotted from individuals who received BOGO 7/5/5 offers each month

**BOGO 2010 年 7 月 10 日(报价 ID 7)**

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Ff67a2def9267f342299b38628d928198.png&pos_id=img-fdfryMXL-1727458262017)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F3bbfb1158b682c24e7457ba2e17af05b.png&pos_id=img-RYHkPADu-1727458262017)

Plotted from individuals who received BOGO 7/10/10 offers each month

**BOGO 5/5/5(报价 ID 8)**

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2F20931b89629403dcf2c195e2333ccc18.png&pos_id=img-v4CAolpJ-1727458262017)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Faf9e8bcefaa50baca664c23579816b42.png&pos_id=img-DplFRbkb-1727458262017)

Plotted from individuals who received BOGO 5/5/5 offers each month

**折扣 10/10/2(优惠 ID 9)**

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fbf448290fbd653aead0cdb7efd7061ae.png&pos_id=img-wRu24G1A-1727458262017)![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2019%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fbc2473944acc40b85455a1bf7a3700f6.png&pos_id=img-FpP91Lgx-1727458262018)

Plotted from individuals who received Discount 10/10/2 offers each month

一个反复出现的观察结果是,在每月接受促销的人中,他们更有可能在没有任何促销活动的日子里购物,而不是在有促销活动的日子里。因此,非促销利润实例的数量通常超过促销利润实例的数量。

在促销和非促销期间产生的利润总额中也观察到类似的情况,非促销利润经常超过促销利润。

当然,一个人接受要约的天数通常低于一个人没有接受任何要约的天数。

每个月,个人受要约影响的天数受到要约有效期的限制,该有效期可以是 3 至 10 天。请注意,没有人在一个月内收到相同的报价超过一次。

然而,即使我们考虑了暴露期之间的差异,在大多数情况下,非促销利润仍然会超过促销利润。

因此,这表明促销在诱导顾客比平时多花钱方面的效果有限。

如果顾客普遍愿意购买星巴克的产品,而没有得到任何促销,那么发送更多的促销信息将不符合星巴克的最佳利益,因为这样做可能会由于促销成本而侵蚀公司的盈利能力。

我们的希望是,我们将能够识别出那些只有在获得促销时才消费的人。限制向这些人发送促销信息将有助于最小化成本和最大化利润。

在本系列的第 2 部分中,我们将介绍特征工程、提升模型的实现、对模型和数据的额外调整、结果以及项目的结论。[将](https://medium.com/@joshxinjielee/implementing-a-profitable-promotional-strategy-for-starbucks-with-machine-learning-part-2-8dd82b21577c)链接到文章的第 2 部分。

*本文附带的代码可以在这里*[](https://github.com/joshxinjie/Data_Scientist_Nanodegree/tree/master/capstone)**找到。**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值