TowardsDataScience 博客中文翻译 2021(七百一十六)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

在数据科学中使用吉拉和用户故事

原文:https://towardsdatascience.com/using-jira-and-user-stories-in-data-science-f1f3f0b1d1ec?source=collection_archive---------21-----------------------

如何在数据领域成功实施吉拉和敏捷项目管理

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

威尔弗里德·桑特在 Unsplash 上的照片

无论你是项目经理还是产品负责人,项目管理工具和一些基本的敏捷技术将极大地帮助你管理你的项目或产品。至少,这些工具会给你、管理层和你的团队一个更好的概述。此外,结果可能是更快的实现、更少的查询、更好的时间估计和更大的动力。在下面的文章中,我想为您提供一些可以帮助您改进项目管理和底层用户故事的要点。

管理工具

在这里,正如标题所示,我推荐吉拉——用于管理目的的标准软件。你可以很容易地从免费 SaaS 解决方案【1】开始。您可以在应用程序中以 Scrum 或看板模式运行您的项目。免费版本为您提供了许多优秀的功能,如积压、报告、工作流等。

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

吉拉·斯普林特——作者图片

如果您有特定的 GDPR 需求,您也可以在本地托管吉拉或现在所谓的数据中心。像 Trello(也是免费的)或开源版本 Wekan(免费,但是你必须建立一个服务器)也存在,但是我更喜欢吉拉。在回答了 toll 问题之后,我想给你六个你在从事数据科学项目时应该注意的主要话题。

Scrum 对看板对瀑布

选择工具后的下一步可能是决定你想使用哪种项目管理方法。当使用 Scrum 时,我会推荐吉拉作为首选工具——因为它提供了你需要的一切。通过使用 Scrum,你将需要设置角色、仪式和工件。此外,Scrum 专注于复杂的软件开发。当在开发新的复杂软件产品或服务的环境中使用时,所描述的项目管理方法可以显示其全部优势。

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

看板板——图片由 Gerd AltmannPixabay 上拍摄

另一方面,由于持续改进的核心原则,看板适合作为可控软件过程中的一种方法。看板经常在支持或维护团队中使用,在这些团队中,要解决的任务很复杂,但通常并不复杂(比如软件推出或维护工作)。看板关注过程效率和生产率的提高。除了 Scrum 和看板,BEAM 方法可能对你也有意义——你可以在这里阅读更多关于它的内容

讨论这些原则,甚至传统的项目管理方法,并决定哪一个最适合你,可能是一个相当困难的过程。在这里,你必须自己做一点研究。这也是有意义的,这样你就理解了理论背景。这个决定也是基于你的组织和人们想要如何一起工作——所以简而言之:你必须自己去发现它。对于我自己,我真的可以推荐吉拉文档[4]。我的观点是,如果你在数据集成、分析、报告等领域工作。由于复杂的任务和不断变化的需求,敏捷工作确实很有意义。

用户故事

在建立了基本的基础设施并决定使用哪种项目管理方法之后,让我们从用户故事开始。用户故事是用日常语言表述的软件需求,并且有意保持简短。为了更深入,我推荐下面的文章: 如何在敏捷软件开发中编写好的用户故事

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

用户故事示例—作者提供的图片

在吉拉,我将用户故事放在描述字段中。通常把其他重要的参考放在那里也是有意义的。如果有必要,你可以使用与故事相关的任务。

积压优化

谈到故事和任务,很好地描述它们非常重要,尤其是在大数据领域。大多数技术细节必须被很好地记录下来,这样来自开发人员的错误和问题就可以保持在较低的水平。在这里,我向 sprint 规划推荐一个反周期的 backlog 精化,在这里产品负责人和团队可以讨论故事以及如何在技术上实现它们。

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

可思考的敏捷过程——作者图片

然后,可以标记好准备好的优先故事,并将其引入下一个 sprint。当不使用 Scrum 时,类似的团队会议和协作也是有用的。

验收准则

验收标准 (AC)是软件产品被用户、客户或其他系统接受所必须满足的条件。它们对于每个用户故事都是独一无二的,并且从最终用户的角度定义了特性行为[5]。

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

AC 示例—作者提供的图像

在吉拉,你也可以把它放在描述字段或为它创建一个新的文本字段。在这里,产品负责人投入一些时间以满足业务需求真的很重要——这取决于他在业务部门和开发团队之间进行调解。

故事点与人工日

我真的会推荐以上两种工具中的一种或两种。故事点是一个用来描述用户故事大小的单位。他们代表了开发工作。

传统的软件团队以基于时间的格式创建评估,例如,天、周和月。然而,许多敏捷团队已经转移到故事点。故事点是估计完全实现产品待办事项或其他任务项所需的总工作量的度量单位。团队根据任务的复杂性、工作量以及风险或不确定性来分配故事点。赋值是为了更好地管理不确定性,以便有效地将任务分成更小的部分[1]。

根据我的经验,我喜欢使用人工来完成 ETL/ELT 管道、建立一些数据库和其他相关工作,这些工作可能也很复杂,但是团队已经很熟悉了。对于更复杂的任务,如开发深度学习算法或建立新的基于云的数据湖——通常是你以前从未做过的事情——使用故事点是有意义的。

谈谈你的工作

最后但同样重要的是,我的建议是,总是谈论你和你的团队取得的成就,以及你的故事如何有助于改善业务和流程,或者至少使它们更容易。我的经验告诉我,公司中像 BI、数据科学或工程这样的新团队通常不太受关注。事实上,同事们可能会问他们在公司里到底在做什么。为了给你的团队留下好印象并获得后续订单,项目营销是必不可少的。此外,通过认可,团队通常会更加团结,积极的情绪会传播开来——至少在我看来是这样。

GIF 由 GIPHY

项目营销被理解为一个项目在其环境和超越。项目营销及其效果在实践中常常被低估,过多的精力被放在应对技术需求上。项目的主动“销售”然后被遗忘:结果是项目团队做了很好的工作,但是这没有被任何人注意和欣赏。因此,在争夺稀缺资源或有价值的注意力方面,该项目往往落后于其他项目,并且在未来将不得不应对比正常项目营销更糟糕的情况[7]。

结论

希望这篇文章能给你一些启发,有所入手。第一步永远是建立一个工具集,当然还有作为产品或项目经理与你的团队取得联系,例如与吉拉取得联系。在我看来,所提供的工具和方法是最重要的因素之一,尤其是在数据领域。我真的推荐使用敏捷过程来更快地部署已开发的系统,以便最小化过程中的风险和不期望的开发。你可以在下面的资源和阅读材料中找到更多的灵感和工具。在数据科学领域,敏捷方法很有前途,因为通常不可能预先评估项目是否可以使用可用数据完成。结果在多大程度上是成功的,只有一旦有了结果才能判断。

资料来源和进一步阅读

[1]吉拉,我们的云产品能够更好地协同工作 (2020 年)

[2]https://trello.com特雷罗 (2020)

[3]韦坎,开源看板 (2020)

[4]吉拉,敏捷宣言还是一样东西吗? (2020 年)

[5] altexsoft,验收标准:目的、格式和最佳实践 (2020)

[6] Quickscrum,产品积压细化 (2020)

[7]项目管理手册,项目营销 (2021)

ML 流水线中的 Schemafull 流数据处理

原文:https://towardsdatascience.com/using-kafka-with-avro-in-python-da85b3e0f966?source=collection_archive---------18-----------------------

使用带有 AVRO 和模式注册的 Kafka,使容器化的 Python 流数据管道利用模式进行数据验证

介绍

在我以前的一篇关于机器学习管道的文章中,消息队列被认为是 HTTP 客户端-服务器架构的一种替代方式,这是现今服务于 ML 模型的最常见的方式。

提醒一下,在 ML 管道中使用像 Apache Kafka 这样的队列有以下优点:

  • 输入数据生产者和数据处理器(Kafka 术语中的消费者)解耦的自然异步处理,即消费数据的 ML 推理/训练服务的失败不会导致 HTTP 超时、数据丢失和数据生产者的失败,而只会导致延迟处理
  • 更好地利用 CPU/GPU 相关任务的计算资源,例如 ML 推断/训练:
    • 批量推断通常效率更高,因为 ML 模型不需要为每个预测预热和拆除
      -如果传入数据不规则到达,队列会平滑负载,而 HTTP 服务器会在负载高峰期间不堪重负,并在安静期间空闲
  • 提高吞吐量。然而,值得一提的是,当推理延迟至关重要时,队列并不完美。在这些情况下,轮询间隔非常短的 Kafka 消费者(这消除了以前的一些优势)或 HTTP ML 模型服务器仍然是可行的选择。

建议读者在阅读本文之前先熟悉 Apache Kafka 和 Docker(包括 docker-compose)。Confluent 有一个不错的介绍卡夫卡的页面Docker docs 也很棒。

为什么要使用模式?

大多数关于如何使用 Kafka,尤其是 Python 的教程都展示了生成和使用无模式 JSON 字符串的例子。尽管运行这些示例很容易,但它们并不太适合生产使用。我们来看看为什么。

无模式方法的缺点

  • 生产者不能强制其发布到主题的数据格式(字段集),这可能导致消费者端的不兼容和运行时错误。当然,它可以在代码中处理,但这会使代码更加复杂,因此容易出错,需要更多的维护。
  • 数据格式演化没有约束,因此生产者可以潜在地切换到新的模式,而不需要消费者期望的字段,这可能再次导致运行时错误(有关详细信息,请参见下一节)
  • JSON 格式的数据包括每个消息的字段名,这使得它在存储空间方面效率很低

Schemafull 消息解决了这些问题,但是,它的代价是更复杂的基础设施,并且需要对模式演化非常小心。

AVRO 图式及其演变

Kafka 支持 AVROProtobufJSON-schema (这仍然存在 JSON 数据格式非二进制且在存储方面不是很高效的缺点)。我们将在文章的代码中使用 AVRO,因为这似乎是卡夫卡最常见的模式格式。

一旦定义,模式通常不能随意更改。提到的一个例子是字段删除或重命名。这个潜在的问题可以通过将字段定义为nullable并使用default值来解决,因此如果字段变得过时,生成器只需停止填充它,同时它仍保留在模式的新更新版本中:

{"name": "value", "type": ["null", "double"], "default": null}

其他模式进化考虑在 AVRO 规范中有描述。

演示设置

这个库有一个 Python AVRO 消费者和生产者的基本例子:

https://github.com/isenilov/python-kafka

让我们回顾一下它所包含的服务,查看docker-compose.yamlservices部分

动物园管理员

Apache ZooKeeper 由 Kafka 用于在一个集中的位置维护配置,并且是 Kafka 集群工作的先决条件。消费者和生产者通常不与它直接交互,所以我们在这里省略了它的详细描述。

图式注册表

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

用于存储和检索模式的汇合模式注册表( 来源 )

汇合模式注册中心是一个用于存储和检索模式的服务。显然,人们可以使用 Kafka,而不仅仅是拥有模式和应用程序代码,但是模式注册中心确保了所有消费者和生产者的版本化模式的单一真实来源,排除了这些消费者和生产者之间模式偏差的可能性。

注册表既有 RESTful API,也有由 confluent-kafka-client 提供的本地支持,这实际上是在 Python 中使用 kafka 的标准。

可以通过 HTTP 请求注册模式,如下所示:

SCHEMA=$(sed 's/"/\\"/g' < ./Message.avsc)

curl -X POST -H "Content-Type: application/vnd.schemaregistry.v1+json" \
  --data "{\"schema\":\"${SCHEMA//$'\n'}\"}" \
  http://<registry_host>:<registry_port>/subjects/<name>/versions

它应该返回模式注册的 id(版本):{“id”:1}

使用 Python 代码中的模式可以通过从前面提到的客户端实例化AvroSerializerAvroDeserializer来完成。

卡夫卡

Apache Kafka 集群本身使用来自汇合的 Docker 映像运行,该映像具有其运行所需的一切。
它有许多配置选项,但我们仅限于基本的工作选项,例如,PLAINTEXT协议不执行任何加密。

init-卡夫卡

这是 Kafka 的一个短暂实例,仅用于创建我们计划在使用kafka-topics CLI 的演示中使用的主题:

kafka-topics --create --if-not-exists --topic Test.Topic --bootstrap-server kafka:29092 --replication-factor 1 --partitions 1

为了简单起见,将replication-factorpartitions选项设置为 1。参考 Kafka 文档了解更多关于这些和更多其他选项的细节。

工人

这是消费和生产应用程序本身。为了简单起见,消费者和生产者都在__main__.py中。代码大部分是不言自明的,所以让我们只看它的一些重要部分。

生产者配置:

"value.serializer": AvroSerializer(schema_str=Message.schema,
schema_registry_client=schema_registry_client, to_dict=todict)

schema_str=Message.schema — producer 需要传递一个模式,这里我们传递包含该模式的生成的 Python 类的属性。模式将在schema_registry_client中上传和注册。

to_dict=todict —这必须是将消息对象转换为 Python 字典的可调用对象。我们使用来自生成代码的helpers.pytodict方法。

消费者配置:

"value.deserializer": AvroDeserializer(schema_str=None, schema_registry_client=schema_registry_client,
from_dict=lambda obj, _: Message(obj))

这里我们不传递模式,所以schema_registry_client将从模式注册中心获取它。
from_dict=lambda obj, _: Message(obj) —将字典转换为消息对象的相反操作。这里我们需要做一点修改,因为反序列化器将 context 作为第二个参数传递给 callable(我们忽略了它),但是生成的类构造函数只接受字典。

"group.id": "test_group"

“group.id”。这允许共享相同消费者组 ID 的多个消费者(读取具有数据处理应用程序的多个容器以进行水平缩放)轮流消费消息,因为他们共享 Kafka 偏移量。同时,如果需要将这些消息用于其他目的,例如,在线测试一个实验性的 ML 模型,可以通过使用新的group.id部署这个实验组来完成,从而避免与主要的产品结构混淆。

运行演示

存储库的README.md有使用docker-compose运行所有服务的指令。执行这些命令应该会在 stdout 中产生类似这样的结果:

worker_1  | Waiting for schema registry to be available
worker_1  | Producing message to topic 'Test.Topic'
worker_1  | Produced message: {'timestamp': 1639304378, 'data': {'count': 10, 'value': 100.0}}
worker_1  | 
worker_1  | Flushing records...
worker_1  | Consumed message: {'timestamp': 1639304378, 'data': {'count': 10, 'value': 100.0}}

这意味着生产和消费是成功执行的。

我们打印消费的消息:

if message is not None:
    print(f"Consumed message: {message.dict()}")

但是,这是推理代码通常随后将结果预测发布到另一个主题、将它们保存到数据库或在下游 API 调用中使用它们的地方。

监视

一般来说,对 Kafka 消费 ML 服务的监控类似于在NLP 任务的完整机器学习管道文章中所描述的。

然而,推断时间可以(并且可能应该)伴随着消费者滞后,这表明消费者落后于公布的数据多少。如果增长,通常意味着消费者群体必须扩大。当使用基于[librdkafka](https://github.com/edenhill/librdkafka#language-bindings) 客户端时,如本例中使用的confluent-kafka-python,可以使用librdkafka返回的统计数据来获得消费者滞后,如本期所述。

结论

本文展示了为什么在 Kafka 中使用模式可能是一个好主意,以及如何使用 Python(ML 服务的首选语言)来实现它。一如既往,如果您对内容有任何问题或建议,请随时通过 LinkedIn 联系我。

自然语言处理中使用关键词抽取进行无监督文本分类

原文:https://towardsdatascience.com/using-keyword-extraction-for-unsupervised-text-classification-in-nlp-10433a1c0cf9?source=collection_archive---------4-----------------------

自然语言处理的应用

无监督分类任务的混合方法

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

马库斯·斯皮斯克在 Unsplash 上的照片

文本分类是自然语言处理中的一项常见任务。主要的方法倾向于以一种有意义的方式表示文本——无论是通过 TF-IDF、Word2Vec,还是像 BERT 这样更高级的模型——并将表示上的训练模型作为标记输入。然而,有时要么标记数据是不切实际的,要么没有足够的标记数据来建立有效的多分类模型。相反,我们被迫利用无监督的学习方法来完成分类任务。

在本文中,我将概述我为数据科学面试/职业准备网站 Interview Query 的面试问题数据集构建无监督文本分类器的过程。出于几个原因,这将对他们非常有益。面试查询希望能够为用户提供更多关于他们申请的公司的有见地的信息,以及练习特定问题类型的功能。最重要的是,这将使他们能够通过他们提出的问题类型来“描述”不同的公司。

我们的任务是将一个给定的面试问题归类为与机器学习、统计学、概率、Python、产品管理、SQL、A/B 测试、算法或带回家有关的问题。我认为最实用的方法是首先从语料库中提取尽可能多的相关关键词,然后手动将得到的关键词分配到与我们想要的分类相对应的“箱”中。最后,我将遍历数据集中的每个面试问题,并比较每个箱中关键字的总数,以便对它们进行分类。还考虑了使用潜在狄利克雷分配的可能性,以便生成主题模型和检索与每个主题相关的关键词,而不必手动分配它们,以及 K-均值聚类。鉴于我们的分类范围广泛且不同,这些被证明是困难的,并且不如简单地统计关键词有效。

首先,数据必须被清理和预处理。我使用 SpaCy 对文本进行标记化、词汇化、小写化和删除停用词。

import pandas as pd
import nltk
import spacy
from tqdm import tqdnlp = spacy.load("en_core_web_sm")def create_tokens(dataframe):
    tokens = []
    for doc in tqdm(nlp.pipe(dataframe.astype('unicode').values),                  total=dataframe.size):
        if doc.is_parsed:
            tokens.append([n.lemma_.lower() for n in doc if (not n.is_punct and not n.is_space and not n.is_stop)])
        else:
            tokens.append("")
    return tokensraw = pd.read_csv("topics_raw.csv")
tokens = create_tokens(raw)

接下来的问题是选择一种从文本语料库中提取关键词的方法。因为我的语料库由大量小“文档”组成,每个文档都是不同的面试问题,所以我决定从每个文档中单独提取关键词,而不是组合任何数据,并根据频率从结果列表中排序唯一的关键词。

然后,测试开始了。考虑了各种方法,如 TF-IDF、RAKE,以及一些最近的最新方法,如 SGRankYAKETextRank 。我也很好奇,尝试了 Amazon understand,一个自动 ML 解决方案,看看它有多强。不幸的是,结果并不令人满意,因为高层次抽象与 NLP 任务粒度的结合仍然被证明是不切实际的。最后,在比较了每种方法产生的关键词后,我发现 SGRank 产生的结果最好(相关关键词数量最高)。

import textacy
import textacy.ke text = " ".join(raw.tolist())
nlp = spacy.load('en_core_web_sm')
nlp.max_length = len(text)keywords = []
for tokenlist in tqdm(question_tokens):
    doc = nlp(" ".join(tokenlist))
    extract = textacy.ke.sgrank(doc, ngrams=(1), window_size=2, normalize=None, topn = 2, include_pos=['NOUN', 'PROPN'])
    for a, b in extract:
        keywords.append(a)

最后,我按照频率对唯一的关键词进行了排序,以获得最显著的关键词。

res = sorted(set(keywords), key = lambda x: keywords.count(x), reverse=True)

结果是大约 1900 个单词,然后我手动检查并把最相关的 200 个单词分配到我们的垃圾箱。

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

最后,有了最终的分类关键词列表,就可以通过统计关键词在每个问题中的出现次数,将每个面试问题分类为 8 种不同类型中的一种。此外,我们可以为不同的公司生成“个性”档案,并在网站上显示。

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

https://www . interview query . com/interview-experiences/Facebook/data-scientist

总之,我发现对于这个特定的问题,最好是简单地选择一种混合方法来完成无监督分类任务,这种方法既涉及机器学习,也涉及人工工作。

一般来说,在自然语言处理中无监督的上下文中工作,在数据分析和结果的实际应用之间留下了相当大的距离,这迫使人们采用本文中看到的替代方法。在我看来,这是 NLP 的一个明显的缺陷,比其他领域如计算机视觉或生成模型更严重。当然,我预计未来更有洞察力的模型和其他研究的进步将在这方面取得显著的进步。

无论如何,感谢你阅读这篇文章!我希望你学到了一些东西。

使用线性规划来提高你的强化学习算法

原文:https://towardsdatascience.com/using-linear-programming-to-boost-your-reinforcement-learning-algorithms-994977665902?source=collection_archive---------22-----------------------

大而高维的动作空间往往是强化学习的计算瓶颈。将你的决策问题公式化为一个线性规划可以极大地增加你的算法可以处理的问题的范围。

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

照片由穆罕默德·图尔古特·柯克戈兹通过派克斯拍摄

请运筹学研究者解决任何问题——无论是优化你的股票投资组合、安排你的送货路线,还是解决你的婚姻问题——他们很可能会脱口而出“线性规划”作为他们的首选解决方案。线性规划是二战后作为美国陆军航空兵自动化规划程序的一种手段而构想的一种数学方法,此后已发展成为一个成熟的领域,广泛应用于运输、制造、金融、医疗保健和许多其他领域。典型的实现处理具有成千上万个决策变量、无数个约束以及大量成本和回报成分的问题。这些问题不仅仅是学术上的想象;真实世界的实际问题就是这样建模和解决的。事实上,线性编程在如此多的环境中工作得如此之好,有时看到它在强化学习社区中受到的关注如此之少令人惊讶。

线性编程导论

对于那些不熟悉这种方法的人来说,一个非常简短的入门可能是合适的。线性规划本质上是遵循固定结构的方程组,包含(I)必须最小化或最大化的目标函数,(ii)决策空间上的一组约束,以及(iii)具有相应域约束的决策变量的定义。顾名思义,整个系统应该是线性的——这个强大的特性允许利用问题结构的凸性,并显著提高求解方法的速度。求解该系统给出最优解。典型的线性规划方法如下所示:

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

为什么要用这样的公式呢?嗯,没有人比国父乔治·丹齐格本人更能说明线性编程的潜力了[1]:

“考虑一下给 70 个人分配 70 份工作的问题。“活动”包括将第 I 个人分配到第 j 个作业。[……]因此有 2 * 70 或 140 个限制和 70 * 70 或 4900 个活动,有 4900 个相应的 0-1 决策变量。不幸的是,还有 70 种阶乘排列,或者说分配方式。[…]

在这个例子中,70 阶乘是一个非常大的数字。为了了解它有多大,假设我们在 1500 万年前的大爆炸时有一台 IBM 主机。从那时到现在,它能够检查所有可能的解决方案吗?不要![……]即使地球上到处都是纳秒速度的计算机,它们都并行工作,答案仍然是否定的。[……]令人惊奇的是,单纯形法在现代计算机的帮助下可以在瞬间解决这个问题。"

至少可以说,令人印象深刻。这种单纯形法发展于 20 世纪 40 年代末,已经成为许多高级解算器的基础,例如现在使用的 CPLEX 和 Gurobi。结合硬件的不断进步,该领域的进展令人震惊,解决的问题越来越多。请记住,线性规划是一种精确的解决方法:它不会简单地返回一个可行的或“好”的解决方案,而是所有这些数百万、数十亿或数万亿个解决方案中的最佳可能解决方案,很少会在几秒钟内返回!

强化学习中的应用

目前关于线性编程已经说得够多了——我不想给人留下我在推销或试图抬高我的 IBM 股票的印象。现在让我们把注意力转向强化学习。为了方便起见,假设我们试图(近似)求解一个马尔可夫决策模型。当试图这样做时,我们经常遇到所谓的三个维度的诅咒,指的是当问题的规模增长时,状态空间、结果空间和行动空间都爆炸[2]。在著名的贝尔曼方程中,这些计算问题是显而易见的:

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

结果空间*S’*指的是从所选择的状态-动作对可以达到的未来状态的集合。由于每个状态都有自己的价值,因此为每个可行的决策遍历所有这些状态是一项繁琐的任务。我们不是评估所有可能的结果,而是选择一个样本,然后继续前进。通过经常这样做,大数定律预测我们应该收敛到潜在随机变量的真实值。对于状态空间 S ,我们通常定义特征(基本上只是解释变量)来提取预测其值的最显著的属性,而不是显式地观察每个状态。因此,我们不需要观察每个州来评估它有多吸引人;我们可以根据特征做出合理的猜测。这些解决方案被广泛嵌入到许多强化学习算法中。

动作空间 X 的维度受到的关注相对较少。部分地,这可以用这样一个事实来解释,即对于许多问题,完全枚举是可能的。一旦我们生成一个动作,我们只需要计算状态-动作对的值来衡量动作的吸引力,因此对于适度的动作空间枚举工作得非常好。在迷宫中你只能向四个方向移动,即使是超级马里奥也没有那么多锦囊妙计。在棋盘上或在围棋比赛中,事情变得更加复杂,但没有什么是现代计算机不能处理的。除了列举之外,我们当然还有政策梯度定理,它经常被部署在行动者-批评家方法的保护伞下[3]。我们不必列举所有可行的行动,而是可以巧妙地对它们进行采样,并在此过程中调整我们的采样策略。由于没有明确地评估每个动作,我们自然会丢失一些信息,但是只要我们平稳地收敛到好的动作区域,我们通常会认为这是理所当然的。

不幸的是,枚举法和演员批评法并不总是能拯救我们。我们挑一个简单的例子来说明。考虑一个多式联运中心,集装箱可以从这里通过卡车、驳船或火车运输。假设集装箱有 25 个潜在目的地,10 个不同的重量等级,到期日在 1 到 5 之间。然后,我们有 25105=1250 个不同的容器类型,转换成具有 1250 个维度的状态向量,指示当前在中心的每种类型的容器的数量。即使没有正式的证明,也很容易看出可能的排列数量是绝对巨大的——正面处理这些状态和结果空间是不可能的。然而,我们现在感兴趣的是行动空间。每个集装箱可以通过卡车、驳船或火车运输,或者留在中心。如果我们在中心有 n 个集装箱,每个集装箱的这 4 个选项给了我们 4^n 可行的行动;这正是我们不愿意处理的指数行为空间。举例来说:仅仅用 10 个容器,我们就已经面临超过一百万个可行的行动。

这里可以很快排除枚举。我们不想为每一集列举一百万个动作,上帝禁止我们在糟糕的一天遇到 20 个容器。那么是演员兼评论家?我们可以概念化演员网络的各种架构,但它们都面临着同样的挑战。状态向量和动作向量可能很大,但也很稀疏。到目前为止,大多数容器类型在某一天的值都是 0。不幸的是,一个神经网络通过传递一串零是不会学到很多东西的。在高维空间中采样是一项具有挑战性的任务;在这种情况下,大多数演员会在森林里迷路。

集成线性规划和强化学习

尽管面临一个相当干净和直接的问题,但我们无法列举,也无法有效地应用演员-评论家方法。不出所料,这就是线性编程重新登上舞台的地方。还记得这种方法是如何方便地处理大型高维动作问题的吗?真巧。

首先,我们需要将我们的决策问题转换成前面介绍的通用格式。在这种情况下,我们希望以最小化运输成本的方式分配集装箱。知道了我们的模态的成本函数,我们可以全面地将它包装在一个目标函数中。最有可能的是,并不是所有的分配都是允许的:有固定数量的卡车,驳船只能处理一定的重量,显然我们不能分配比我们更多的集装箱…我们的一套约束条件已经成型。决策变量?一组二进制文件似乎可以做到这一点。完成了。自然,并不是每个问题都允许自己如此容易地被这种僵硬的格式所捕获。然而,也不应轻易排除这种可能性。来自许多学科的学者和实践者已经成功地将高度复杂的问题融入到这种格式中。随着整个航空公司的运营被线性程序所控制,你的 RL 问题也有可能被塑造成同样的形状。

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

二维多面体的线性优化,Ylloh 通过 WikiMedia

好了,我们已经为今天的决策问题建模了,但是明天呢?毕竟,向前看是强化学习如此有趣的原因。为此,我们需要添加一些人为变量。这些变量表示捕获处于给定状态的下游值的特征。在这种情况下,我们通常会手动设计这些功能,使用基于状态和动作的线性表达式来计算它们。

假设——作为我们的功能之一——我们跟踪到期日为 5 的集装箱数量。我们现在有六个,我们考虑运输四个:我们剩下两个(即ϕ_f(s,a)=ϕ_f(6,4)=6–4=2).其他的例子可以是卡车的下一个位置、延期后的剩余现金预算等。所有这些特征都是从状态-动作对计算出来的;学习相应的权重θ_f 以将值赋予特征。

要更深入地了解这种情况下的功能设计,以下关于决策后状态的文章可能会有帮助:

[## 什么是后决策状态?他们想从我们这里得到什么?

towardsdatascience.com](/what-are-post-decision-states-and-what-do-they-want-from-us-9e02105b7f40)

上述等式很容易添加到现有的约束集合中。将人工变量ϕ嵌入到目标函数中,我们只需要将它乘以我们学习到的权重θ,就可以评估我们行动的下游价值[2]。

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

总而言之,线性规划值得任何处理大量决策的人考虑。当然,还有本文没有讨论的缺点、限制和挑战,但是有了 70 年的历史记录,这种优化方法还远远算不上时尚。与枚举相比,它提供了令人难以置信的升级,同时保持了评估动作的最优性。当你的笔记本电脑的内存不断被无止境的枚举动作数组填满,当你的演员一直带你无处可去,线性编程可能只是你的 RL 算法需要的推动力,以恢复这些巨大的动作空间的秩序。毕竟,正如乔治·丹齐格几十年前发现的那样:线性程序可以管理军队。

参考

[1]与 George B. Dantzig 的访谈:线性规划之父—大学数学杂志(1986)。http://www.phpsimplex.com/en/Dantzig_interview.htm

[2]鲍威尔(2011 年)。近似动态规划,约翰·威利父子公司,第二版。

[3]萨顿和巴尔托(2018 年)。强化学习:导论,麻省理工学院出版社,第二版。

用线性规划调度司机。

原文:https://towardsdatascience.com/using-linear-programming-to-schedule-drivers-79f02959443c?source=collection_archive---------26-----------------------

使用 Python 中的线性编程库 PuLP 优化工作分配。

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

埃里克·罗瑟梅尔在 Unsplash 上的照片

介绍

对于大型操作,工作分配可能是一项相当大的日常任务。在这篇文章中,我将重点介绍如何使用 PuLP 来创建一个分配工作的模型。可以使用 Excel 中的 VBA 自动完成这一过程,但是,这是一种“贪婪”的方法,为每个单独的驾驶员而不是为整个分配寻找最佳路径,因此效率不高。

Excel 确实有一个可以解决线性和非线性问题的规划求解器,但它仅限于 200 个决策变量,对于大型运算,这种解决方案是可行的。

什么是纸浆?

PuLP 是 Python 中的一个开源库,可以用来解决这类优化问题。

为了使用纸浆解决这个问题,你需要建立一个线性目标函数,然后模型将尝试最大化或最小化这个总价值。典型地,在运输操作中,你会有路线和司机在一天中间隔地开始,所以我希望该模型尝试最小化开始时间的整体偏差。然而,我还想考虑司机的偏好——使其在路线类型上更有利于匹配他们的偏好。

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

目标函数

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

包含路线和驾驶员每种组合的开始时间差异的矩阵。

为了解决这个问题,我们需要为路线和驾驶员的每一个组合创建一个决策变量。

建立纸浆问题并创建二元决策变量。

这将决策变量设置为仅取值 0 或 1 的二进制变量。本质上,如果模型为一个组合返回值 1,这意味着它在最终的解决方案中。

为了避免启动时间差异大于 60 分钟的模型计划驱动程序,我决定使用启发式算法,并最大化以下函数。

根据开始时间的差异,为每个组合设置包含 0 到 1 之间的值的矩阵。

设置目标函数。

我已经为任何开始时间差异大于 60 分钟的组合指定了一个负值(-100)。当我最大化目标函数时,这实质上是一个惩罚,这意味着如果没有可行的路线,模型宁愿让驾驶员不被分配。

为了尝试考虑驾驶员偏好,如果路线类型和驾驶员偏好匹配,则从开始时间的差异返回的分数乘以 2,如果不匹配,则乘以 0.5。这使得具有匹配偏好的路线、驾驶员组合更加有利约 30 分钟,但是,如果模型不能匹配偏好,它仍然会将驾驶员分配到路线,因为该值仍然大于 0。

现在我们需要设置一些约束。

  • 一条路线不能在解决方案中出现多次。
  • 一个驱动程序不能在解决方案中出现多次。

您可以用与设置目标函数相似的方式创建约束,并将一个不等式分配给模型对象。

在纸浆中设置约束

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

纸浆中的约束示例。R1 在最终解决方案中只能出现一次。

现在来解决问题。我已经建立了一个有 10 个司机和 10 条路线的基本例子。

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

解决问题并找到解决方案。

在这个例子中,PuLP 成功地为 9 个司机分配了工作,其中 5 个司机被分配了与他们的偏好相匹配的工作。

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

司机和剩余路线。

纸浆公司无法为驾驶员 D9 分配工作,因为 R2 剩下的唯一一条路线的开始时间相差超过 60 分钟。

使用线性规划可以自动化分配工作的过程,同时找到最有效的方式来规划您的劳动力并考虑员工的偏好。

利用潜在狄利克雷分布分析定性调查数据

原文:https://towardsdatascience.com/using-machine-learning-to-analyse-qualitative-survey-data-1794416e5474?source=collection_archive---------14-----------------------

结合自然语言处理、情感分析、神经网络和主题建模,对开放式数据进行即时分析和可视化

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

照片由像素皮克斯拜拍摄

调查是市场研究和数据收集中最常用的方法之一。虽然主要产出往往是定量数据,但经常会提出开放式问题,以获得广泛的回应。这些一字不差的回答往往有助于回答数字背后的“为什么”。

然而,分析开放式调查数据是一项艰巨的工作。在一个大的调查数据集中,逐字逐句的回答可能需要几个小时甚至几天的时间。不仅如此,它几乎完全是通过人类编码来完成的。因此,定性的回答经常被忽略,或者只是通过抽出一些逐字的引用来补充叙述。

这让我想到了一个问题——有没有更好的方法来揭示定性调查数据中的洞见?

我混合使用自然语言处理、神经网络、情感分析和主题建模,创建了一个可以接受数据集的模型,并自动返回数据中的关键主题。这只花了我 10 个小时的时间。

TL;DR:在十个小时内,我创建了一个模型,它可以在任何大小的数据集中自动提供关键主题。在我的测试数据集上,有‘just’3000 个响应,下面的整个模型(包括可视化)可以在不到 30 秒的时间内生成。

如果你想和我一起出去玩,请继续读下去——我保证这是值得的。

我使用了一个包含 3000 份回复的公开数据集——来自德克萨斯州奥斯汀的一个社区调查。在调查结束时,受访者可以选择提供书面评论来回答以下问题:“如果您能与市长分享一件关于奥斯汀市的事情(任何评论、建议等)。),那会是什么呢?”

我认为这将是一个有趣的数据科学挑战,因为可能会有各种各样的答案。

这是我的机器学习管道-

第一步。潜在狄利克雷分配

潜在狄利克雷分配(LDA)是一种流行的自然语言处理(NLP)工具,可以从语料库中自动识别主题。LDA 假设每个主题由一包具有一定概率的单词组成,每个文档由一包具有一定概率的主题组成。LDA 的目标是学习语料库中的单词和主题分布。Gensim 是一个 NLP 包,特别适合 LDA 和其他单词嵌入机器学习算法,所以我用它来实现我的项目。

# Create Dictionary
id2word = corpora.Dictionary(processed_data)# Create Corpus: Term Document Frequency
corpus = [id2word.doc2bow(text) for text in processed_data]# Build LDA model
lda_model = gensim.models.ldamodel.LdaModel(corpus=corpus,
                                           id2word=id2word,
                                           num_topics=4, 
                                           random_state=42,
                                           update_every=1,
                                           chunksize=10,
                                           per_word_topics=True)

在对数据进行一些预处理以删除常用词之后,我能够从回答者的反馈中获得主题,主要围绕-

1)生活费用

2)公用事业

3)交通

4)其他问题(归类为专题 0)

从“引擎盖下”看,我们可以看到模型识别的每个主题的最具代表性的句子。

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

自然,没有一个词云的定性分析是不完整的:)这里我们可以看到每个主题最有代表性的词。

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

现在变得有点古怪了——我还训练了一个 word2vec 神经网络,并将 LDA 获得的一般主题中的热门单词投影到 word2vec 空间。我们可以使用 t-SNE(t-分布式随机邻居嵌入)算法来可视化 2D 空间中的主题聚类。这让我们可以看到模型是如何将 4 个主题分开的——公用事业问题似乎是最少被提及的。此外,生活费用和公共设施问题之间有一些重叠。

# Getting topic weights
topic_weights = []
for i, row_list in enumerate(lda_model[corpus]):
    topic_weights.append([w for i, w in row_list[0]])# Generating an array of optic weights    
arr = pd.DataFrame(topic_weights).fillna(0).values# Dominant topic in each document
topic_num = np.argmax(arr, axis=1)# tSNE Dimension Reduction
tsne_model = TSNE(n_components=2, verbose=1, random_state=0, angle=.99, init='pca')
tsne_lda = tsne_model.fit_transform(arr)# Plotting the Topic Clusters with Bokeh
output_notebook()
n_topics = 4
mycolors = np.array([color for name, color in mcolors.TABLEAU_COLORS.items()])
plot = figure(title="t-SNE Clustering of {} LDA Topics".format(n_topics), 
              plot_width=900, plot_height=700)
plot.scatter(x=tsne_lda[:,0], y=tsne_lda[:,1], color=mycolors[topic_num])
show(plot)

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

最后,我用 pyLDAVis 创建了这个主题模型的交互式可视化。这可以用来绘制每个主题最突出的单词,以及查看主题的分离程度。

pyLDAvis.enable_notebook()
vis = pyLDAvis.gensim.prepare(lda_model, corpus, dictionary=lda_model.id2word)
vis

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

虽然这个数据集在分割数据方面稍有欠缺,但我们可以看到,不同的议会选区对主题进行了平均分割。在放弃主题 0(杂项)后,有证据表明生活成本、交通和公用事业之间存在显著的等级关系。在 9/10 地区,公共设施是人们谈论最多的改进问题。如果有人口统计数据来观察公民在突出话题上的差异,那将会很有意思。

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

每个议会区的不同主题

第二步。情感分析

我还对分析调查开放式评论的观点感兴趣,并将其与我的主题模型相结合。我使用 VADER 库来分配情感分数,并将一个主题的百分比评级定义为当受访者提到该主题时给出积极评论的百分比。该指标用于为主题分配情感分数。

我使用我的 LDA 模型来确定回复中每个句子的主题构成。如果一个句子有 60%或更多是由一个主题主导的,我认为这个句子属于那个特定的主题。然后,我计算了句子的情绪,或正面或负面,最后统计了每个题目中正面句子的总百分比。

这里快速浏览一下整个数据集中的情绪分布。有了这样一个开放式的问题,受访者很容易抱怨。但是考虑到 70%的回复都是正面的,我们可以推断样本倾向于对他们的家乡城市给予建设性的批评。

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

在这个特定的数据集中,主题之间没有太多的情感差异(如下图所示)。然而,将它应用于商业市场研究环境来观察情绪的差异将会很有趣。

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

总之,我相信这是逐字分析调查有效和可扩展的方法。

一些警告——由于这是一种“快速而肮脏”的方法,不能指望它完全取代人工分析。此外,LDA 还要求我们选择可以限制的主题数量。根据主题,通过更加定制的 NLP,以及 LDA 模型中更好的超参数调整,还有进一步改进的空间。然而,好处是显而易见的-

机器学习有助于减少人为偏见,节省数小时的分析时间,以便从数据中获取主要主题。这种特殊的方法可以轻松处理大型数据集,并在几秒钟内返回可操作的结果。

如果您想了解更多信息,或者有任何改进建议,请联系我们。整个项目都在我的 GitHub 库上(当你在那里的时候,请随意查看我的其他项目!)

使用机器学习将文本分类成主题

原文:https://towardsdatascience.com/using-machine-learning-to-categorize-texts-into-topics-3650f64f663f?source=collection_archive---------25-----------------------

开发一种无监督学习算法来发现主题共性

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

图片来自 Pixabay

读完一篇新闻文章后——无论主题是美国政治、电影评论还是提高生产率的技巧——你可以转向其他人,让他们大致了解文章的内容,对吗?或者,如果你读一本小说,你可以把它分为科幻小说、文学小说或爱情小说。

人类往往很擅长对文本进行分类。现在,电脑也能做到这一点。

在最近的一个机器学习项目中,我从消费者金融保护局(Consumer Financial Protection Bureau)下载了消费者投诉,并开发了模型,将投诉分为五个产品类别之一。我的表现最好的模型在 86%的情况下都是正确的。(你可以在这个媒体博客中读到这个项目。)

我使用了一种监督学习技术,其中模型使用标记的类别,然后预测未标记的类别。在用于训练我的模型的数据集中,产品类别是由消费者自己选择的,考虑到大多数消费者不是金融专家,他们可能不会 100%完美地完成工作,错误会影响模型的性能。

或者考虑一个不同的数据集,其中的文本没有预先标记。为了训练有监督的自然语言处理(NLP)模型,人类这样做将是乏味的。这些缺点是监督模型所固有的。

作为该项目的后续工作,我想开发一个无监督学习 NLP 模型,看看会出现什么类别。这个模型会忽略预先标记的类别,而是辨别共性,以便将文本分组到自己设计的主题中。

我还想到了一个商业案例。无人监管的模型可能对消费者金融保护局有用,因为它不必依赖消费者对其提交的信息进行分类,而且它可能会将收到的信息处理为新的、不可预见的类别。本质上,无监督的 LDA 模型可以为任何从消费者或客户那里接收信息并帮助分类文本的机构工作。

创建新主题

我已经处理了对监督学习模型的投诉,对文本进行了记号化,删除了停用词,并对单词进行了词条化。(更多细节见前述博客)。对于非监督建模过程,我使用了 Gensim 的潜在狄利克雷分配(LDA)模块。

我让它将 160,000 个投诉分成五个主题,然后使用 pyLDAvis 模块创建一个可视化:

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

点击 这里 可以看到这些主题可视化的互动页面。

可视化用图表显示了五个主题中最常见的单词:

主题 1

本主题包括一般的金融词汇,如账户银行信用,还包括电子邮件电话信件收到等词汇。这个话题的一个共同点是与沟通有关。

话题 2

有了征信举报举报查询这样的热门词汇,这个话题就是关于征信

主题 3

付款贷款抵押到期利息余额告诉我这个题目关注的是抵押和贷款的相关问题。

主题 4

本话题热门词汇有债务催收法律违规举证法律。这个话题似乎与法律事务有关。

主题 5

在这里,一些关键词是信息消费者身份盗窃侦查诈骗公正受害者。我想说这个话题是关于身份盗窃或者对欺诈活动的调查。

在我进一步讨论这些分组之前,我想指出我可以选择多于或少于五个主题。事实上,Genism 也有衡量模型主题“连贯性”的模块。我用不同数量的主题制作了模型,并将它们与 u-mass 一致性度量进行了比较。这个度量产生一个负数,这个数越接近零,它就越连贯。

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

正如你所看到的,有五个主题的模型有最高的一致性分数。与此同时,在我将 coherence 作为给我的模型评分的一种方法之后,似乎许多专注于 NLP 的数据科学家并没有在它上面投入太多的精力。LDA 毕竟是一种无人监管的技术,因此有限的测量不一定能取代人类对结果的细微解释。

无监督模型有多大用处?

让我们比较一下监督学习模型的五个产品类别和我的非监督学习模型的五个主题类别。

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

两对主题重叠,但六个主题不同。这些发现如何具有洞察力或有用性?

我可以想象在消费者金融保护局有一个区域处理通信和消费者服务问题,一个处理法律事务,另一个处理身份盗窃和欺诈。如果是这样,LDA 模型发现属于这些相应主题之一的投诉可以被路由到适当的区域。

总之,一个无人监管的模型确实能够将收到的信息归类到新的、不可预见的类别中。这五个类别是基于我对热门关键词的直觉解读,当然还需要更深入的分析和解释。然而,更重要的一点是,有监督和无监督的 NLP 模型对于任何希望处理大量日常传入邮件的组织都是有用的。

使用机器学习对服务器事件进行分类

原文:https://towardsdatascience.com/using-machine-learning-to-classify-server-incidents-36f837c107a?source=collection_archive---------37-----------------------

如何使用机器学习对服务器事件进行分类的分步介绍

介绍

当我们谈到事件管理时,自动化事件解决是每个公司的必备条件,但要让自动化在正确的事件中发挥作用并提供正确的信息,有必要自动从服务器事件中检索信息,其中大部分内容都基于文本,即事件描述,然后分类(我们称之为“匹配”)哪些已经可用的自动化可能会解决事件。

从不需要深入编程技能的事件中检索信息的常用方法是使用正则表达式,但是如果您已经使用过它,您就会知道它有多糟糕,对事件内容的最小修改就可能导致正则表达式失败。

在这篇文章中,我们描述了我们如何使用机器学习技术来改善这种匹配。

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

克里斯蒂娜@ wocintechchat.com 在 Unsplash 上的照片

数据准备

用于训练模型的数据基于在过去六个月中由可用自动化之一解决的事件,即来自 9 个不同国家/地区的 180 多个客户的大约 10 万起事件。我们将数据限制为仅 6 个月,因为我们不断部署新的自动化并修复一些正则表达式问题,所以为了防止使用错误/旧的数据,更小的间隔应该足够了。

我们从数据湖中检索的原始数据集有 14 列,但是我们将只关注创建模型所必需的列。

  • **自动化 _ 名称:**在此事件中执行的自动化的名称(我们分类的目标)
  • **组件:**事件中受问题影响的组件的高级名称
  • **子组件:**事件中受问题影响的组件的特定名称
  • **摘要:**事件的快速描述

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

数据集中包含的数据示例

在这种特殊情况下,由于组件子组件是对摘要信息的补充,我们决定连接这三个字段,创建一个“特征字段,这一过程将使接下来的步骤更容易,除此之外,我们将所有内容设置为小写。

在一些国家,我们有不止一种语言的事件,例如英语和西班牙语,为了解决这个问题,我们使用了两个 libslangdetect 来检查事件的语言,我们采用英语作为我们的主要语言,并在必要时使用 googletrans 将事件翻译成英语。这一过程可能需要几个小时,取决于您的数据集大小,我们试图只过滤必要的文本翻译成英语。

为了完成这一步,我们将数据分为特征,其中自动化名称是我们想要预测的,而特征是我们上面处理的结果。

建模

准备好这两个字段后,我们终于可以开始机器学习阶段了。为了使运行我们的模型变得简单,我们创建了一个管道,这个管道有三个主要组件:

from sklearn.pipeline import Pipelinepipeline = Pipeline(steps=[
     ('bow', CountVectorizer(analyzer=proc_text)),
     ('tfidf', TfidfTransformer()),
     ('classifier', model)
])
  • CountVectorizer: 这个函数将标记我们的数据,结果将是每个单词计数的稀疏表示

这一阶段的一个重要步骤是删除停用词和标点符号,这两个组件可能会造成我们的情况不必要的复杂性,所以使用 nltk 库和下面附加到 CountVectorizer 的函数,我们把它们去掉。

import string
import nltk
# Necessary to install stopwords, only in the first time
#nltk.download()
from nltk.corpus import stopwords
sw = set(stopwords.words('english'))def proc_text(text):
 string_w_no_punc = [char for char in text if char not in string.punctuation]

 string_w_no_punc = ‘’.join(string_w_no_punc)

 return [word for word in string_w_no_punc.split() if word.lower() not in sw]
  • TfidfTransformer:CountVectorizer 返回的稀疏矩阵中,该函数将对其应用 TF-IDF(词频-逆文档频率)表示。TF-IDF 的目标是衡量一个单词在一个文档(TF)和所有文档(IDF)中的影响。
  • 模型:流水线的最后一个组件是应用分类器。

管道完成后,一切如常,我们将数据分为训练和测试,并将评估每个分类器的结果。

估价

在这种特殊的情况下,我们需要一个精确和召回的平衡指标,因为在这一点上,它们都不会比另一个带来更多的麻烦。考虑到这一点,我们选择评估 F1 分数和宏观平均值,我们尝试了一些分类器,您可以查看以下结果:

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

测试分类器的结果

最适合我们的数据的模型是 XGBoost,但是您可以做更多的事情来改善这些数字,例如超参数优化、**对少数类进行上采样、**以及其他一些方法,但是我会让您自己尝试这些方法。😃

为了在生产中使用它,我们需要有一些保证,即分类器预测自动化的概率高于某个阈值,为此我们使用了来自 sklearn lib 的 predict_proba ,这个函数返回分类器为每个类返回的概率,有了这个和阈值(我们设置为 97%),我们就能够在生产中无忧无虑地实现和监控分类器。这是我们使用的片段:

pred_proba = pipeline.predict_proba(X)
pred = pipeline.predict(X)confidence = []
for item in pred_proba:
    confidence.append(item.max())df["predicted_automation"] = pred
df["confidence"] = confidence
df["applicable"] = df_test["confidence"].apply(lambda x: "OK" if x > 0.97 else "NOK")

希望这篇文章能帮助你理解如何使用机器学习来处理文本数据,以及我们如何找到机会并在日常工作中应用它来提高我们客户的满意度。

使用机器学习生成图像字幕

原文:https://towardsdatascience.com/using-machine-learning-to-generate-captions-for-images-f9a5797f31d6?source=collection_archive---------6-----------------------

在本文中,我们将通过 Python 使用机器学习来为各种图像生成标题

图像字幕是给图像加上适当标题的过程。作为一个人,这似乎是一个简单的任务,甚至一个五岁的孩子都可以轻松完成,但我们如何编写一个计算机程序,将输入作为图像,并生成标题作为输出?

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

照片来自 Unsplash

在深度神经网络最近发展之前,这个问题对于业内最聪明的人来说是不可思议的,但在深度神经网络出现之后,如果我们有所需的数据集,这是完全可能的。

例如,网络可以生成与下面的图片 I 相关的以下任何标题,即“”草地上的白狗“ 带褐色斑点的白狗 ”或者甚至“ 草地上的狗和一些粉红色的花 ”。

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

来自开源 Flikr8k 数据集的图像

数据集

我们选择的数据集是’ Flickr 8k '。我们选择了这个数据,因为它很容易访问,并且具有完美的大小,可以在普通的 PC 上训练,也足以公平地训练网络来生成适当的字幕。数据分为三组,主要是包含 6k 图像的训练组、包含 1k 图像的 dev 组和包含 1k 图像的测试组。每个图像包含 5 个标题。其中一个例子如下:

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

来自开源 Flikr8k 数据集的图像

  1. 一个穿着粉色连衣裙的孩子正在入口通道爬上一组楼梯。
  2. 一个女孩走进一栋木制建筑。
  3. 一个小女孩爬进木制玩具屋。
  4. 一个小女孩爬楼梯去她的玩具屋。
  5. 一个穿着粉色连衣裙的小女孩走进了一个小木屋。

数据清理:

任何机器学习程序的第一步也是最重要的一步是清理数据,去掉任何不需要的数据。当我们处理字幕中的文本数据时,我们将执行基本的清理步骤,如将所有字母转换为小写字母,因为对于计算机来说,‘嘿’‘嘿’是两个完全不同的单词,删除特殊符号和标点符号,如、(、$、%,并删除任何包含数字的单词。*

我们首先为我们的数据集中的所有唯一图片创建一个词汇表,即 8000(图片数量) 5(每张图片的标题)= 40000 个标题。我们发现它等于 8763。但是这些单词中的大多数只出现一两次,我们不希望它们出现在我们的模型中,因为它不会使我们的模型对异常值具有鲁棒性。因此,我们设置了一个阈值,即一个单词在我们的词汇表中最少出现 10 次,这相当于 1652 个独特的单词。*

我们做的另一件事是给每个描述添加两个标记,以指示标题的开始和结束。这两个标记是‘start seq’‘end seq’,分别代表字幕的开始和结束。

让我们从导入所有需要的库开始:

让我们定义一些助手函数:

让我们逐一解释:

  • load_doc:获取文件的路径并返回该文件中的内容
  • load_descriptions:获取包含描述的文件内容,并生成一个字典,以图像 id 作为关键字,以描述作为值列表
  • clean_descriptions:通过使所有字母小写,忽略数字和标点符号字符,以及只有一个字符的单词来清除描述
  • save_descriptions:将描述词典作为文本文件保存到内存中
  • loads_set:从文本文件中加载图像的所有唯一标识符
  • load_clean_descriptions:使用上面提取的唯一标识符加载所有清理后的描述

数据预处理:

接下来,我们对图像和字幕进行一些数据预处理。图像基本上是我们的特征向量,即我们对网络的输入。这就是为什么我们需要在将它们传递到神经网络之前,将它们转换为固定大小的向量。为此,我们使用由 Google Research【3】创建的 Inception V3 模型(卷积神经网络)的迁移学习。该模型在’ ImageNet’ 数据集【4】上进行训练,以对 1000 幅图像执行图像分类,但我们的目标不是执行分类,因此我们移除了最后一个 softmax 层,并为每幅图像提取了 2048 固定矢量,如下图所示:

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

概念网的体系结构

字幕是我们模型的输出,也就是我们必须预测的东西。但是这种预测不会一下子发生,我们会一个字一个字地预测我们的字幕。为此,我们需要将每个单词编码成一个固定大小的向量(这将在下一节中完成)。为此,我们首先需要创建两个字典,即’单词到索引’,它将每个单词映射到一个索引,在我们的例子中是从 1 到 1652,以及’单词索引’,它将每个索引映射到它对应的单词。我们要做的最后一件事是计算数据集中具有最大长度的描述的长度,以便我们可以填充所有其他描述,从而保持固定的长度。在我们的例子中,这个长度等于 34。

单词嵌入:

如前所述,我们将把每个单词映射到一个固定大小的向量(即 200),我们将使用一个预先训练的手套模型。最后,我们为词汇表中的所有 1652 个单词创建一个嵌入矩阵,其中包含词汇表中每个单词的固定大小的向量。

让我们仔细分析这段代码:

  • 第 1–5 行:将所有训练图像的所有描述提取到一个列表中
  • 第 9-18 行:只选择那些在词汇表中出现超过 10 次的单词
  • 第 21–30 行:创建一个单词索引和一个单词字典索引。
  • 第 33–42 行:将手套嵌入加载到字典中,以单词作为关键字,嵌入向量作为值
  • 第 44–52 行:使用上面加载的嵌入为我们的词汇表中的单词创建一个嵌入矩阵

数据准备:

这是这个项目最重要的方面之一。对于图像,我们需要使用前面描述的 Inception V3 模型将它们转换成一个固定大小的向量。

  • 第 1–22 行:将训练和测试图像的路径加载到单独的列表中
  • 第 25–53 行:遍历训练集和测试集中的每个图像,将它们加载到固定大小,对它们进行预处理,使用 InceptionV3 模型提取特征,最后对它们进行整形。
  • 第 56–63 行:将提取的特征保存到磁盘

现在我们不会一下子预测我们的标题,也就是说,我们不会只是给计算机图像,然后让它为图像生成标题。我们要做的是给它图像的特征向量和标题的第一个单词,让它预测第二个单词。然后我们给它前两个字,让它预测第三个字。让我们考虑数据集部分中给出的图像和标题‘一个女孩走进一座木制建筑’*。在这种情况下,在添加标记’ startseq’'endseq '之后,下面将是我们在每种情况下的输入(Xi)和输出(Yi)。*

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

*在这之后,我们将使用我们创建的字典’ *word to index '来改变输入和输出中的每个单词以映射索引。因为我们要进行批处理,所以我们希望所有的序列长度相等,这就是为什么我们要在每个序列后面加上 0,直到它们达到最大长度(如上计算的 34)。可以看到,这是一个巨大的数据量,一次性将其加载到内存中根本不可行,为此,我们将使用一个数据生成器,将其加载到小块中,即只加载需要的数据,而不消耗所有内存。

上面的代码遍历所有的图像和描述,并生成类似于表中的数据项。将让函数从同一行再次运行,因此,让我们批量加载数据

模型架构和培训:

如前所述,我们的模型在每个点都有两个输入,一个是特征图像向量,另一个是部分字幕。我们首先对图像向量应用 0.5 的下降,然后将其与 256 个神经元的层连接。对于部分字幕,我们首先用如上所述预训练的手套中的嵌入矩阵的权重将其连接到嵌入层。然后,我们应用 0.5 的辍学和 LSTM(长短期记忆)。最后,我们将这两者结合起来,并将它们连接到一个由 256 个神经元组成的层,最后连接到一个 softmax 层,该层预测我们词汇表中每个单词的概率。可以使用下图总结高级架构:

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

问题的定制架构

*以下是在训练期间选择的超参数:损失被选择为’*分类损失熵’,优化器是’ Adam '。模型总共训练了 30 个时期,但前 20 个时期的批量和学习率分别为 0.001 和 3,而后 10 个时期的批量和学习率分别为 0.0001 和 6。

让我们稍微解释一下代码:

  • 第 1- 11 行:定义模型架构
  • 第 13–14 行:将嵌入层的权重设置为上面创建的嵌入矩阵,并设置trainable=False,这样,该层不再被进一步训练
  • 第 16–33 行:用上面提到的超参数在两个不同的区间训练模型

推论:

前 20 个时期和接下来的 10 个时期的训练损失如下所示:

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

培训损失

为了进行推理,我们编写了一个函数,根据我们的模型预测下一个单词是具有最大概率的单词(即,greedy)

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

来自开源 Flikr8k 数据集的图像

你能做什么:

因此,总之,我们的模型在没有任何广泛的超参数调整的情况下,在为测试数据集中的图像生成标题方面表现得相当好。我们能想到的一些改进可以被使用

  • 更大的数据集
  • 进行更多的超参数调整
  • 改变模型架构。

如果你尝试了这些方法并得到了更好的结果,请告诉我。该项目的代码可以在这里找到

如果您觉得以上内容对您有用,请分享并随时支持我–>

  • https://www.buymeacoffee.com/nouman10

使用机器学习来生成实际可行的食谱

原文:https://towardsdatascience.com/using-machine-learning-to-generate-recipes-that-actually-works-b2331c85ab72?source=collection_archive---------2-----------------------

用数据科学烹饪

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

当我尝试了一个星期的水果减肥法时,我吃的食物的照片。使用艺术家 Yury Malkov 的风格,通过神经风格转换生成。作者图片

近年来,生成模型领域在面部生成方面取得了巨大的成功,或者说从图画中创造出有趣的风景。

然而,为一道人类真正喜欢吃的菜制作食谱似乎超出了我们目前的能力。结果往往非常糟糕,实际尝试一下会很有意思,例如:

我开始尝试一些不同的食谱制作方法,烹饪它们,找出它们的缺点,也许还能加以改进。

资料组

对于数据集,我将使用来自 https://www.koket.se/和 https://www.tasteline.com/的食谱。其原因是:

  • 我已经使用它们很多年了,我知道这些食谱质量很高,通常能做出美味的食物。
  • 食谱有点“国际化”。尽管这些网站是瑞典的,但大多数食谱反映了现代瑞典观众对其他文化食物的渴望。因此,尽管你会发现传统食物,如肉丸,你也会发现汤姆凯盖肉馅卷饼、scaloppine al limone di vitello、和超过 100 种配方的鹰嘴豆沙。一些更“奇特”的食谱已经被篡改,例如,高良姜有时代替生姜,但并不总是如此。

TextGenRNN

TextGenRNN 是一个使用递归神经网络(RNN)的文本生成 python 库。RNN 是处理顺序数据问题的一种解决方案。由于文本数据是可变长度的(不同数量的单词或字母),我们不能使用普通类型的神经网络,例如,每个字母进入输入层中的一个感知器,因此,我们将一个接一个地输入字母作为序列。我们希望我们的神经网络能够记住输入的所有内容,而不仅仅是序列中最新的元素。为了实现这一点,我们要将每个字母的隐藏状态反馈到感知器中。隐藏状态是 RNN 的内部记忆。

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

来自维基百科

普通 RNNs 的一个问题是,对于每一步,更远的一步的影响变得越来越小,因为它已经通过神经元馈送了很多次。因此,一个 RNN 人可能在保持一个长句的上下文方面有问题,有时会忘记它是在谈论一个人、一个比萨饼还是天气。减轻这种情况的一种方法是使用一种特殊类型的感知机,称为 LSTM 或 GRU,结果会更好,但不是恒星。

无论如何,这是我得到的:

  • 与橄榄油、sambal oelek 混合在一起,放在盘子上
  • 黄瓜切丁,切成楔形
  • 根据包装上的说明煮意大利面
  • 加入洋葱、大蒜、油和熏制三文鱼片的两面,放入烤箱烤 10 分钟左右,或者烤至金黄色
  • 将西红柿洗净并切成两半

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

作者图片

**评价:**这顿饭还可以。用 sambal oelek 和橄榄油制作简单的调味酱是个不错的主意。我不得不反复阅读许多食谱,然后才能找到我可以真正烹饪的东西。大多数食谱语无伦次,难以理解。

TableGAN

一些最著名的生成模型是生成对抗网络(GANs)。他们通过让两个神经网络竞争来工作。生成器试图生成类似于训练集的数据,鉴别器试图找出哪个是假的,哪个来自训练集。通过这次比赛,他们都变得更好。

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

作者图片

虽然大多数 GAN 专门用于图像生成, TableGAN 是一个 python 库,它使用 GAN 技术来生成表格数据。在这个例子中,输入数据是期望值为 200、标准差为 100 的随机数。TableGAN 生成了以下代码,我认为看起来相当不错。

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

作者图片

这似乎是一个很好的配料表。我使用 scikit-learn 的 CountVectorizer 将菜谱转换成向量。结果是:

[‘茄子’,‘小菠菜’,‘培根’,‘叶菠菜’,’ bulgur ',‘蘑菇’,‘辣椒片’,‘辣椒酱’,‘柠檬汁’,‘科涅克’,‘龙’,‘固体土豆’,‘鱼酱’,‘液体人造黄油’,‘新鲜百里香’,‘新鲜香草’,‘希腊酸奶’,‘青椒’,‘黄瓜’,‘日本酱油’,‘日本大米’,‘刺山柑’,‘椰奶’,‘浓缩小牛肉原汤’,‘肉末’,‘酸橙’,‘淡啤酒’,‘牛排’,‘玉米淀粉’,‘油’,‘奶酪’,‘牡蛎片’,‘胡椒(调味’,‘松子’,‘韭菜’,'迷迭香 '黄油(用来油炸) ',‘大豆’,‘标准牛奶’,‘黑胡椒’,‘甜辣椒酱’,‘红薯’,‘百里香干’,‘鳕鱼背’,‘核桃’,‘酸奶’,‘西葫芦’,‘鸡蛋’,‘苹果醋’]

**定论:**这款简直成分太多,我就不试了。

GPT-2

创成式预训练变形金刚 2 (GPT-2)就是所谓的变形金刚。他们从训练数据中学习一个单词出现的可能性,这取决于全文中的其他单词,但不同的单词被赋予不同的权重,这一过程被称为注意力。这样,它就可以无限期地保持理论上的语境。使用 GPT-2 的方法是写几个词作为开始,让转换器填写哪个词最有可能跟随,然后查看新字符串,并重复这个过程。GPT-2 在互联网的大部分区域接受训练,见过许多食谱。

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

作者图片

我用过 https://app.inferkit.com/demo 的,这是一个可以免费试用 GPT 2 的网站。

开头的句子是粗体的。

切洋葱。磨碎孜然和肉豆蔻。炒洋葱。从煎锅中取出洋葱、孜然芹、肉豆蔻、盐和胡椒,在另一个容器中磨碎洋葱。重新加热。加入鹰嘴豆、大蒜、生姜、香茅、鸡汤、酸橙汁、酱油和葡萄酒。把液体煨一下,然后关小火,盖上锅盖。煮大约 30 分钟,偶尔搅拌。一旦液体完全沸腾,加入浓奶油搅拌。再次降低温度,盖上盖子,然后

结论:这似乎是一道美味的炖鹰嘴豆。我最终没有做它。

在一个大碗中混合西红柿、芫荽叶、番茄酱、酸奶油、酸橙汁、盐、黑胡椒、孜然、辣椒粉和辣椒粉。腌制 30 分钟。用中火加热一个 12 英寸的不粘锅。加入熏肉、洋葱和胡椒片。烹饪并搅拌 3 分钟或直到培根变脆。搅拌酸奶油混合物。加入绞碎的牛肉,烹饪,用木勺打碎牛肉,大约 3 到 4 分钟,或者直到牛肉不再呈粉红色。将切碎的生菜、洋葱和西红柿混合;投掷

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

作者图片

结论:这味道真好。只是可能有点太普通了。

勒苟拉斯切碎洋葱,并把它们与面包屑、一些橄榄油和鸡汤混合在一起。当他们搅拌的时候,阿拉贡把千层面的面团擀开,切成八等份。“我不知道这是不是有史以来最好吃的千层面,”他说,“但至少比昨天好吃。”“你还没吃呢。”阿拉贡站起来,开始把所有东西放在一起。“在这一点上你必须相信我。”“很好。”“不如我的好。不过话说回来,我的就是我的专长。”他们做好了饭

**结论:**GPT 2 号的一个有趣之处在于,你可以给它喂任何你喜欢的东西,它会连贯地完成任务。我特别喜欢 GPT 知道阿拉贡在品尝食物之前就评论它有多好吃,并且写了勒苟拉斯是如何召唤他的。

我没有做这种难吃的饭。

分析数据集

上面的食谱已经足够好了,但是我不得不重复了好几次才得到它们。不过,我觉得最大的问题是他们的缘分很低。 Serendipity 是推荐系统中常用的一个指标,高分意味着用户感到惊喜。所以,例如,如果我推荐食物,我可以通过推荐牛奶或香蕉来获得高准确率,因为这是人们经常购买的东西。但是这样的推荐并不是很好,因为顾客无论如何都会买的。相反,我们会向客户推荐他们会喜欢的东西,但他们自己可能不会想到。这是很高的意外收获。它可以被视为人工智能生成的食谱的最重要的衡量标准。我们已经有人类在制作食谱,我们希望从人工智能那里得到的是一个令人震惊的不同但仍然美味的食谱,摆脱人类先入为主的什么一起吃味道好的观念。

需要注意的一点是,当一个人制作一份食谱时,他会从不同的配料的味道、气味和外观中汲取经验。所有这些信息对算法来说都是不可用的,算法只能看到不同的成分是如何一起使用的。这是机器学习中的一个常见问题,顺便说一下,模型继承了训练数据的偏差。这排除了一些由于地理意外而不常见的可行成分组合。例如,生姜和奶油放在一起是不常见的,因为生姜生长在世界上有很大一部分人对乳糖不耐受的地方。然而,我看不出他们为什么不能一起工作,因为生姜和椰子汁是常见的。

我决定在配料中添加一些特性并进行调查。我使用的功能有:

  • 淀粉 _1
  • 淀粉 _2
  • 蛋白质 _1
  • 蛋白质 _2
  • Fat_1
  • 脂肪 _2
  • 甜甜 _1
  • 甜甜 _2
  • 酸味 _1
  • 酸味 _2
  • 鲜味 _1
  • 鲜味 _2
  • 苦的
  • 柔软的
  • 中等
  • 易碎的
  • 红色
  • 黄色
  • 格林(姓氏);绿色的
  • 褐色的
  • 怀特(姓氏)
  • 香料

1 表示“一些”,2 表示“大部分”。例如,牛奶有 sweet_1,而蜂蜜有 sweet_2。柔软、适中、松脆是指质地。

现在,这有点主观,也容易出错,因为某些成分有不同的特点,取决于它们是如何准备的。这可以通过例如将“土豆”和“土豆泥”作为不同的配料来稍微缓解。

计算频率揭示了一些有趣的事情。

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

作者图片

计数是这样完成的:每当一个食谱至少有 1 个特征,我们就增加那个特征。我们对所有的食谱都这样做,然后除以食谱的总量。每当一个食谱包含一种我在我的配料清单中没有的配料时,“未命名”标记。这意味着如果我有时间和精力记录更多的成分,这个数字可能会更高。

这似乎表明:

  • 除了苦味,大多数菜肴至少有一些所有的味道。
  • 许多食谱由许多不同的质地和颜色组成。
  • 几乎所有的菜都有某种香料。

我还是不确定关于苦能得出什么结论。它在那里是因为我们喜欢它,还是仅仅因为一种苦味的成分有一些其他令人满意的品质,例如,罗马沙拉,它是苦的,但也非常脆。我最大的猜测是,有时它是偶然出现的,而其他时候它是有意识地添加进来,让菜肴变得更有趣,就像使用香料一样。它在功能上似乎不同于其他四种味道,甜、盐、鲜味和酸味。

我发现将这些与我得到的甜点进行对比很有趣:

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

作者图片

多点甜少点鲜味,果然不出所料。我怀疑鲜味 1 的流行主要是由于各种各样的鸡蛋和坚果。在本文中,我将重点介绍非甜点食谱。

看看非甜点食谱中最常见的成分:

  • 洋葱(黄色、红色、葱等):0.90
  • 奶酪:0.55
  • 番茄:0.45
  • 大蒜:0.31
  • 柠檬:0.30

不知道为什么会这样。可能很早就在许多地方种植了洋葱(5500 年前的埃及、5000 年前的印度和中国、4500 年前的苏美尔)。此外,洋葱富含硫,油炸时产生的一些化学化合物有点像肉。奶酪的流行很可能是因为食谱来自西方烹饪网站。

根据特征生成配方

既然我们已经有了根据它们的特点而不是成分来描述的食谱,也许我们可以用它作为训练数据?但是,我们希望生成一个由配料而不是功能描述的食谱。为实现这一目标,我们将:

  • 训练一个一级 SVM 根据其特征识别什么是有效的食谱。
  • 生成成分的随机组合,计算特征,并让 SVM 确定它是否是一个有效的食谱,如果不是重复的。这意味着在我们找到可以使用的东西之前,我们将不得不经历几百种随机组合。尽管这种生成东西的方法有点间接,但已经足够快了。
no_of_tries = 1000
generated_recipe = ''for x in range(no_of_tries):
    sample = df_ingredients.sample(12)
    sample_sum = sample.sum()[feature_names]
    pred = clf.predict([sample_sum.values])
    if pred[0] == 1:
        print(sample_sum[feature_names].values)
        generated_recipe = sample.sort_values(['Starch_2', 'Protein_2'], ascending=False)
        break

generated_recipe['Nudles', 'Chickpeas', 'Shrimps', 'Melon', 'Asparagus',
       'Thai Basil', 'Cabbage', 'Sesame seeds', 'Orange','Tamarind',
       'Butter', 'Cinnamon']

另一种方法可能是查看上述特性的频率,并得出结论,我们希望每种特性都有一个。因此,代替我们的 SVM,我们硬编码这个规则,像这样:

no_of_tries = 10000
generated_recipe = ''for x in range(no_of_tries):
    sample = df_ingredients.sample(16)
    sample_sum = sample.sum()[feature_names]

    if sample_sum['Starch_2'] == 1 and sample_sum['Protein_2'] == 1 and all([x > 0 for x in sample_sum]):
        generated_recipe = sample.sort_values(['Starch_2', 'Protein_2'], ascending=False)
        break['Polenta', 'Chicken', 'Pear', 'Star Anise', 'Lime juice', 'Radish', 'Mayonnaise', 'Tomato', 'Mushrooms', 'Artichoke', 'Vanilla', 'Eggs', 'Orange Zest', 'Oyster sauce', 'Sugar', 'Fennel']

由于我们只有配料,我不得不自己决定如何处理它们。这是我想到的:

  • 盐水鸡。
  • 用茴香和蚝油做玉米粥。
  • 烤鸡和玉米粥。
  • 煎烤蘑菇和西红柿。
  • 用梨、萝卜、朝鲜蓟和酸橙汁做沙拉。
  • 用蚝油、糖、酸橙汁、水、橙皮、香草、八角、茴香和蛋黄酱做调味汁。

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

作者图片

评价:味道不错,更重要的是,有点不寻常(很高的意外收获)。糖、香草、八角和茴香使调味汁尝起来有点像甘草糖,但蚝油使它美味可口,从而避免了它尝起来像甜点。

填充配料

我突然想到,如果一开始就给它一些成分,这个发生器将有助于填补缺失的成分。由于鹰嘴豆泥有数百种配方,我决定看看该算法是否能产生一种新的配方。所以我从面包鹰嘴豆开始,食谱变成了:

['Bread', 'Chickpeas', 'Stock', 'Dried tomatoes', 'Sunflower oil', 'Coca cola', 'Almonds', 'Dill', 'Pickles', 'Smoked paprika', 'Lemon juice', 'Beer']

我决定用切碎的杏仁作为配菜,泡菜作为配菜。然后我必须决定可口可乐和啤酒中的哪一种应该加入鹰嘴豆泥中,哪一种我应该喝。我决定往鹰嘴豆泥里倒几汤匙可口可乐。

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

作者图片

结论:味道不错,和通常的鹰嘴豆泥食谱有点不同。

熟读烹饪知识

此时,我认为自己没有足够的背景知识来继续学习,所以我订购了几本书:

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

作者图片

我还在 YouTube 上找到了一个不错的系列讲座:

读完和听完之后,我准备对这一切意味着什么做出一些有根据的猜测。

洞察力

以下是我自己的想法。我已经尝试过了,但样本量太小,无法得出任何一般性的结论。尽管如此,我还是会把它们呈现在这里,但要有所保留。

美食的要素

  • 平衡。只有盐味的东西不好吃。对甜味或其他任何味道也是一样。做一顿好饭需要的是甜、盐、鲜味和酸味之间的平衡。
  • 变异。一顿饭需要变化多样,刺激许多不同的感官,因此最好是包含不同的颜色、质地、香味和温度。
  • 新奇。反复吃同样的东西会令人厌烦。我们喜欢体验新的感觉组合。我认为这是许多现代餐厅的主要特征之一,这些餐厅提供味道、质地、颜色等不同寻常的食物组合。
  • 熟悉度。作为孩子,我们从我们的文化中学习什么是可食用的,什么是不可食用的。这对于我们的生存至关重要,这样每一代人就不必通过尝试来找出哪些浆果是有毒的。这也导致在烹饪时,我们不能偏离前人设定的界限太远。至少不是一蹴而就的,通过循序渐进,有可能学会欣赏与你习惯的食物非常不同的新型食物。

我觉得有趣的是,人类的饮食习惯似乎有一个特定的人类元素。做一顿好饭的主要挑战之一当然是做出一些大脑认为有营养的食物,而不是像草或泥土这样的随机植物。但是,这还不够。它也需要刺激和惊喜我们。它的工作方式似乎与许多其他人类休闲活动的工作方式惊人地相似。例如,有人可能会说上面的列表也可以作为如何制作音乐的指南。

为什么我们喜欢自己喜欢的东西?

**纹理:**说到人类,我有一个猜测,为什么我们会如此痴迷于纹理。在许多烹饪书中,有整整一章,有时几章,致力于获得正确的肉的质地(我更喜欢用 sous vide 或 reverse sear 处理嫩切肉,用高压锅处理切肉,将胶原蛋白转化为明胶。提前几个小时在盐或盐水中摩擦)。同时,大多数动物乐意吃所有的肉,不管有多硬。我的猜测是,这与我们有一个非常高的喉头(因为讲话)和小下巴肌肉(为我们的大大脑腾出空间)有关。这使得人类特别容易因窒息而死,所以鲜肉不仅仅是味道的问题,也是生存的问题。较软的肉也可能是肉已经被煮熟的标志,因为这使我们更容易吸收营养,所以我们更喜欢这样的肉是有道理的。

味道:我们喜欢甜食,这一点应该不会让任何人感到惊讶,因为糖是高能量的,因此我们的祖先会给它定价。鲜味有点复杂,因为它不是一般的蛋白质,而是一种特殊的氨基酸。我猜谷氨酸盐通常与其他蛋白质一起被发现,我们用它来代表高蛋白食物。酸味更加棘手。这可能表明维生素 C 的含量,也可能是它让我们的祖先更喜欢未成熟的水果,因此让他们在比赛前吃它。盐对于正常的生理机能是必不可少的。

辣椒:现在,这有点神秘,因为吃辣椒会触发痛觉感受器。关于这一点似乎没有共识,但一个很好的理论是,它模拟了一种我们可以控制的危险情况,并且知道它是不危险的,类似于过山车。

香料的作用

在我看来,香料主要是为了让食物变得更有趣,没有哪种香料能和某种配料搭配得更好。配对似乎主要是文化上的。

你应该从建立你的食谱开始,让它包含适量的甜、酸、盐和鲜味。这样你的大脑会把它识别为食物。之后,你可以添加任何你觉得愉快的气味。

如果你喜欢香料的味道,你可以用它搭配任何东西。

  • 喜欢肉桂的味道?它不仅仅是甜点,还可以用在炖鸡里,这是印度人的做法。
  • 比如松木的味道?在你的冰淇淋里放一些磨碎的杜松子。
  • 你觉得川菜的刺痒感有趣吗?在你炖的奶油蘑菇里放一些四川胡椒。

此外,香料大多与气味有关(除了少数像辣椒、黑胡椒、花椒),大脑处理气味的部分和处理记忆的假设之间可能有密切的联系。这意味着香料可以用来唤起某些记忆。普鲁斯特在《寻找逝去的时光》中的一个著名场景中对此进行了精彩的描述,主角吃了一个玛德琳蛋糕,喝了一些莱姆花茶,香味引发了生动的不由自主的记忆。

音响工程师类比

将食物的所有复杂性简化为几个特征,如甜、酸或脆,这似乎很荒谬。某些成分搭配在一起比其他成分更好,以及某些食物如何相互补充和增强,这种想法怎么了?

我认为用声音工程来类比是恰当的。因此,在声音工程的早期,捕捉正确的声音似乎是一项不可完成的任务。声学是一个非常复杂的领域,移动一根柱子或缩小一堵墙,或者改变材料,声波传播和相互干扰的方式就会完全改变。

然而,人们很快认识到,这个问题可以通过理解这样一个事实来简化,即在如此复杂的情况下,人类仍然只有两只耳朵。

同理,人类舌头上只有 5 种味蕾,大约 400 个嗅觉感受器。我们并不像人们常说的那样,在调味汁中加入柠檬来“提亮它”。我们这样做是因为大多数人喜欢特定的 pH 值以及柠檬醛和柠檬烯的气味。也增加了几分甜味。我们可以自由地用任何满足酸、甜和气味标准的东西来代替它。考虑到你喜欢酒石酸、琥珀酸、苹果酸和葡萄酯的味道,香醋可能是一个不错的选择。葡萄酒也是很好的替代品。

说到葡萄,它们和蓝纹奶酪很配,因为它们含有甜味和酸味,但含盐量低,蓝纹奶酪中富含鲜味。牛肉干也含有这些部分,不出所料,和葡萄一起吃味道很好,前提是你喜欢烟熏味。

音乐世界的另一个有趣的类比是对声音进行分类。在过去,人们通常会根据乐器的演奏方式、外观或使用的材料来分类。随着合成器的出现,我们现在可以制造任何声音,而无需参考现实世界中的材料,如木材或黄铜。这不得不导致许多虚拟仪器技术转而根据其功能对仪器进行分类。因此,我们有创造背景,领导的旋律,和低音的,嗯,低音。同样的,我倾向于考虑成分,而不是它们是叶、根还是果实,而是它们是松脆的、咸的、红色的,还是含有芳樟醇。

老方法也用于将酱料分类为法国母酱料:贝沙梅尔酱、西班牙酱、番茄酱、维露特酱和荷兰酱。它们是根据烹饪时使用的配料和技术来分类的,而不是根据它们的味道和它们在食物中的作用。

了解富含鲜味成分的作用

我曾经对某些配料的味道感到惊讶,如鱼露、伍斯特郡酱、蚝油等。当我用勺子品尝它们时,我不喜欢它们,那么我为什么要在食物中使用它们呢?甚至像帕尔玛意大利干酪这样的东西也有点神秘,它放在三明治上味道很好,但伯爵酒味道更好,所以为什么不用它来代替呢?

现在我明白了,很多这些味道更“古怪”的配料实际上是古代寻找鲜味的一部分。古罗马人已经有了他们的 garum,据说味道很差,塞内卡写道:

你难道没有意识到,腐败的鱼,那昂贵的血淋淋的块,用它的咸腐来消耗胃吗?

但是,鲜味在自然界中供应不足,我们渴望它,并准备在任何可能的地方获得它。现在,每当我做饭时,我通常会在旁边放一瓶鱼露,鱼腥味在完成的菜肴中并不明显,许多食物用一些鱼露会变得更好。不仅仅是亚洲食物,注意,在肉酱面里放一些会更好吃。

此外,显然有两种类型的化学物质触发鲜味受体,谷氨酸盐肌苷酸二钠并且两者一起似乎产生强烈的反应,因此串联使用不同类型的鲜味 _2 型成分可能是有益的。

品味与特色

当我开始做这类实验时,有一件事让我感到惊讶,那就是大脑并没有真正把不同的特征看成是独立的,而是根据一些不同的感觉拼凑成一幅统一的画面。因此,举例来说,对一些人来说,在美味的菜肴中加入甜味,就像在棕色酱汁中加入糖一样,听起来可能令人反感。是的,如果你加的太多,你会尝到你不想要的甜味。但是,如果酱汁完全没有甜味,尝起来就好像缺少了什么。向菜肴中添加一些糖不会使它变甜,而是大脑会将其记录为“味道不错”(如果你不想直接添加糖,可以在制作调味汁时使用胡萝卜甚至洋葱)。质地也是如此,有时我根本没有注意到它的质地,只是觉得它很好吃。

比例和酸味

算法并没有给出确切的比例,所以我通常用我内置的化学分析仪来做。也就是说,我品尝它,并根据需要添加配料,通常是一些缺少的特征高度集中的东西。所以如果没有酸味,我会拿一个酸橙,如果没有鲜味,我会用鱼露等。

我想有可能采取更科学的方法,我通过测量我做的酱的 pH 值来尝试酸味。

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

作者图片

酱汁似乎是 6,相比之下,另一端与水是 7。

将菜肴分类

虽然有许多许多不同类型的菜肴和烹饪方法,但在我看来,其中一些在世界各地都极为常见。

  • :将所有材料放入水中,加热至沸腾。让它煨到合适的质地和味道。
    Ex:土豆韭菜汤,Tom Kha Gai,Sopa Azteca,Bouillabaisse,蛤蜊杂烩,拉面汤,Pho,酸辣汤,Mulligatawny 汤。
  • :作为汤,但去除淀粉成分,单独烹制。
    例如:Chili con carne、Dal、Massaman curry、Gumbo、Sega wat、Domoda、麻婆豆腐。
  • 自行:自行准备淀粉、蛋白质、蔬菜,配以酱汁食用。肉和土豆,香肠和土豆泥,西班牙小吃,北京烤鸭,黛安牛排。
  • 自行混合:自行准备淀粉、蛋白质、蔬菜和酱料,并在上菜前混合。
    例如:肉酱面、泰伯香浓、意大利面沙拉、泰伯勒、普克碗。
  • 三明治:准备好蛋白质和蔬菜,放在面包上食用。
    例如:汉堡、热狗、朗格士、法式长棍面包、烤肉串、玉米煎饼、牛排三明治、Skagen 吐司、smrrebrd。
  • 馅饼:在面团上或里面烘焙蛋白质和蔬菜。
    例如:肉饼、Pierogi、披萨、饺子、Bö rek、Kiymali pide、Empanadas、Bobotie。

化学反应

烹饪不仅仅是找到合适的原料并把它们组合在一起,它也是一种化学反应。例如:

  • 美拉德反应。从 19 世纪开始,就有一个有弹性的神话,说我们把肉烤焦来密封肉汁。这已被证明是错误的,但仍有理由烤焦。原因是美拉德反应,这是氨基酸和还原糖之间的化学反应,产生褐色,酥脆的质地和美好的香味。
  • 烫漂。当我们切蔬菜时,我们切断了细胞壁,使不同的化学物质混合在一起。这有时会导致不希望的化学反应。例如,当切罗勒做香蒜酱时,一种化学反应开始了,使鲜绿色变成褐色。阻止这种反应发生的一种方法是通过加热来破坏引起这种反应的化学物质。这可以通过预先热烫罗勒来实现。另一个例子是洋葱,洋葱在切开之前没有太多气味,随后化学物质的混合产生了一些非常强烈的富含硫的化学物质,当它们与水接触时会变成硫酸,使我们的眼睛灼伤。这些反应可以通过在煎锅里加热洋葱来停止。
  • 炭化。谁会想到部分燃烧一些植物会让它们味道更好?但这是真的,尤其是对非常有用的甘蓝类蔬菜来说。它是那些被培育了很长时间的物种之一,并被选择采取许多不同的有用的形式。例如:
    顶芽选择:甘蓝
    侧芽选择:抱子甘蓝
    茎选择:大头菜
    叶选择:羽衣甘蓝
    茎花选择:西兰花
    花束选择:花椰菜
    Btw,它所属的属还包含芥菜和油菜。

越南牛肉沙拉

我喜欢这道菜,因为很明显所有的配料是如何搭配在一起的。调料是:

  • 酸橙
  • 棕榈糖(甜)
  • 鱼露(鲜味,盐)
  • 大蒜、辣椒、生姜(香料)
  • 芝麻油(脂肪、香料)

现在所有的口味都考虑到了,真正的沙拉主要是增加质地、颜色和营养。

  • 米粉(淀粉,白色,柔软)
  • 胡萝卜(淀粉、橙、脆)
  • 黄瓜(淀粉,绿色,酥脆)
  • 莴苣(苦的、绿色的、脆的)
  • 牛肉(蛋白质,中等质地)

当然,其中一些成分还有一些其他的特点,例如,胡萝卜是甜的,有点像香料(事实上,这是波斯人驯化它的原因,用种子和叶子作为香料),肉有鲜味。但是调料里有更多。

为了让这道菜更加有趣,可以加入新鲜的香草:

  • 铸造
  • 芫荽叶
  • 泰国罗勒

意大利面条

这是我做了一辈子的菜,从来没想过改进,直到现在。用我的新知识武装起来,我注意到酸和甜不见了,所以有一天我加了少量的香醋,它确实改善了这道菜。现在,我确信传统上人们会吃酸的配菜来平衡它,但我仍然认为我的加入是一种改进。

集束香料和香草

有许多香料,很难知道用哪一种。为了获得一个概观,我决定将他们分组。我在谷歌上搜索了常见的替代品,并通过绘制 spice 与其替代品之间的关系图对其进行了建模。这是在图形工具 Gephi 中完成的:

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

作者图片

似乎有几个集群:

  • 圣诞串(丁香、肉豆蔻、多香果、肉桂、小豆蔻、姜粉、姜黄)。对我来说,这是姜饼和圣诞节的味道。我猜美国人会把它与感恩节和南瓜派联系在一起。此外,这种味道在印度和印度尼西亚菜肴以及牙买加小吃中也很常见。这个簇的一个特征化学物质是丁香酚
  • 甘草串(八角、八角、茴香、龙蒿)。对我来说,这是甘草、面包、盐和地中海的味道。这一串的特征味道是由于茴香脑或其异构体蒿脑的缘故。
  • 麻辣串(辣椒、黑胡椒、花椒、辣椒粉)。这些香料不同于其他香料,因为它们主要是关于口腔中的感觉(辛辣、火辣、刺痒),而不是香味。
  • 鲜串(香茅、柠檬皮、漆树)。这些气味如柠檬醛、芳樟醇和柠檬烯,通常与清新联系在一起,这也是它们常见于肥皂和洗涤剂中的原因。
  • 果味集群(罗望子、酸橙)。这些是各种醛类的花香和水果味。
  • 踢中窦丛(辣根、芥菜、胡芦巴)。这些和辣串差不多,只是痛在鼻子而不是嘴。葫芦巴没有这种品质。
  • 地中海草本植物群(牛至、罗勒、月桂、百里香、鼠尾草):闻起来像披萨和地中海草甸。
  • 麝香串(孜然、芫荽、香菜、莳萝):闻起来像中东美食。
  • 松树丛(刺柏浆果、迷迭香):这是针叶林的气味,多半源于α-蒎烯
  • 牙膏簇(薄荷、欧芹、香菜)。对我来说,这是牙膏和漱口水的清新味道。
  • (烟熏味、香草味、巧克力味、藏红花味):这些香料实际上不属于任何其他类别。

顺便说一句,在许多情况下,让我们如此渴望香草和香料的好气味是化学战。看,草药无法逃离它们的敌人(如真菌和昆虫),所以相反,它们产生有毒的化学物质杀死任何入侵者。这些化学物质使得香料闻起来有味道。显然,一生中被害虫侵袭过的草药比那些喷洒过杀虫剂的草药味道更好。至于人类为什么喜欢这些化学物质,有几种理论。一是有毒化学物质有助于我们的免疫系统。

然而,这并不是故事的全部,罗望子和其他水果闻起来很香,因为它们想被吃掉,这样它们里面的种子就会被传播,辣椒是辣的,以阻止哺乳动物吃它们,这样它们的种子反而被尝不到热量的鸟类传播。

关于香料,另一件要注意的事情是,在使用前将它们整体储存并磨碎是一个好主意。这是因为平方立方定律。通过减小香料颗粒的尺寸,体积随着尺寸减小,而面积仅仅随着尺寸减小,因此小颗粒具有大得多的面积-体积比,气味分子将消散得更快。同理,小动物通常很难保暖,而大动物则很难不过热。

利用机器学习识别高价值足球转会目标

原文:https://towardsdatascience.com/using-machine-learning-to-identify-high-value-football-transfer-targets-d4151a7ffcac?source=collection_archive---------17-----------------------

xgboost 和 FIFA 20 数据集的冒险

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

斯文·库契尼奇在 Unsplash 上的照片

如果你想复制本文中描述的分析,你可以在 GitHub 的 这里 找到所有的代码

马后炮是一个善变的东西。

回顾过去,我们很容易想到我们应该预见到它们的到来。当然,我们认为,我们应该知道比特币会成为一个东西,特朗普会在 2016 年获胜,iPod touch 意味着带按钮的手机的终结

足球转会也是如此。很难不回顾像安迪卡罗尔到利物浦,费尔南多托雷斯到切尔西,阿莱克西斯·桑切斯到曼联,安德烈舍甫琴科到切尔西这样的转会,并认为他们从一开始就注定要失败。

但现实很少如此简单。

我们举个例子。

在 2016 年和 2017 年的夏天,两名 25 岁的边锋以俱乐部创纪录的费用转会到了冠军联赛的顶级球队。两人在他们的老东家都表现出色;两者的估价都在 2000 万到 3000 万英镑之间;两人在国际足联的总体评分都在 80%左右。在前一个赛季,一名球员每两场比赛进一球,另一名每三场进一球。他们甚至都曾在英超前四名的俱乐部度过了一段糟糕的时光,然后去了国外以获得更多的比赛时间。

你觉得怎么样?这些玩家各自的命运应该是显而易见的吗?如果你知道他们的名字,你认为你的答案会不同吗?

其中一个是德国国脚安德烈·舒尔勒。他在 2016 年转会到多特蒙德,转会费约为 3000 万€。对他来说不幸的是,事情并没有在威斯特法伦斯坦迪翁解决。舒尔勒在托马斯·图切尔的第一个赛季打了 15 场比赛,只进了两次球。在接下来的 12 个月里,他的市场价值直线下降,在他大笔转会三年后,他被租借到了莫斯科斯巴达。他在那个赛季结束后退役了。

另一个呢?嗯,另一个是穆罕默德·萨拉赫

机器学习和偏见问题

虽然这些可能看起来像无关紧要的轶事,但后见之明偏见的影响可能比你想象的更大。如果我们总是回过头来想,在那个时候区分一个犹太人和一个萨拉赫人应该很容易,我们就会低估在未来做同样的事情有多难。下一次我们看到一个 25 岁的边锋在欧洲踢球得分,他看起来是下一个大人物,我们会认为很明显他们是一个伟大的转会目标。我们可能会在不经意间让 Schürrles 比 Salahs 多。

那么,我们能做些什么呢?

我们可以做的一件事是将我们的评估建立在更加客观的数据基础上。如果我们可以设计和验证系统来学习与随后的高绩效可靠相关的模式,并证明它们在现实世界中有效,我们就可以开始做出更好的决策,并消除人类偏见。

当然,机器也不会对偏见免疫——远非如此。过去几年中有太多有偏见的算法的例子,这几乎已经成为数据科学领域的陈词滥调。特别是,机器学习算法经常会无意中放大人类的偏见,尤其是在根据人类判断生成的数据进行训练的情况下。不过这通常是可以避免的:如果你知道偏见来自哪里,你就可以想出如何从你的训练过程中消除它们,从而获得更好的结果。

但是听着,我知道你不需要我告诉你这些。你已经看过了钱球。你在这里是为了了解我们实际上是如何做到的。

所以让我们继续吧。

接下来

在这篇文章的剩余部分,我们将使用一个玩具示例来演示如何使用 R、xgboostFIFA 20 数据集来构建一个足球转会推荐系统。我们的目标是训练一种算法来识别在即将到来的赛季中表现出色的球员。此外,我们真正想知道的是:如果我们签下他们,哪些球员可能会在我们支持的俱乐部表现出色。

我们将把这个问题构建成一个 监督机器学习问题 ,其中有一个与未来玩家表现相关的连续目标变量,我们的目标是提前预测。

我们将采取的步骤是:

  1. 获取数据,设计特征并定义目标变量
  2. 探索性可视化
  3. 训练和验证一个简单的 xgboost 模型
  4. 根据最新数据创建预测并探索结果

(如果您对代码不感兴趣,只想听一些有趣的传输八卦,您可以直接跳到第 4 部分)

步骤 1:加载数据和工程特征

首先,我们将加载所有的数据文件并做一些基本的清理。我们还将从国际足联的数据中提取非常详细的“位置”特征,并将其转化为稍微更广泛的类别(守门员、中后卫、边后卫、中场、攻击型中场、边锋、前锋)。

我们还在这里定义了我们的目标变量。在每个赛季开始时,我们希望预测每个球员在该赛季的表现如何。总的来说,在下一个版本的游戏中,拥有一个好赛季的玩家将会被开发者提高他们的总评分。那些赛季表现不佳的人将会看到他们的总体评分下降。因此,我们的目标变量将是改进栏,代表从一个赛季到下一个赛季总体评分的变化。

特征工程

接下来,我们将设计一些我们认为我们的机器学习算法将从中受益的功能。当然,并不是所有的算法都需要这一步。如果我们走深度学习的路线,那么我们可以在理论上指定一个足够复杂的模型来设计它自己的底层功能,并从中学习。问题是,那种方法需要大量数据——可能比我们这里得到的还要多。记住:越复杂并不总是越好。编码重要领域专业知识的高质量工程特征可以极大地改善大多数机器学习模型,作为足球迷,我们可能有惊人数量的有用知识可以编码到我们的模型中。

比如我们知道足球是团队游戏。这意味着一个球员进步(或失败)的程度不仅取决于他们自己的技能和特点,也取决于他们队友的技能和特点。

这些关系远非简单。一方面,你可能听过专家们谈论一个球员如何从身边有一个更好的球队中受益。如果没有维吉尔·范·迪克和阿利松·贝克尔在他身边,乔·戈麦斯会打得像 19/20 那样好吗?

但另一方面,团队中有太多其他优秀球员——特别是如果他们打同一个位置——从发展的角度来看可能不是那么好,因为这意味着你不太可能获得比赛时间。举例来说,如果加布里埃尔·赫苏斯不是一直充当塞尔吉奥·阿奎罗的副手,他在曼城会有更大的进步。

使用像 xgboost 这样的基于树的模型可以帮助我们捕捉其中的一些非线性。为了让它有所作为,我们将为每个玩家创建一些列来表示:

  • 球员在俱乐部的平均综合评分
  • 球员在俱乐部的平均潜在得分
  • 首发/首选选手的平均综合评分
  • 首发进攻者、中场、防守者和守门员的平均综合评分(作为单独的特征)
  • 俱乐部中与目标球员踢相同位置的其他球员的平均综合评分
  • 同上,但使用潜力而不是总体评分
  • 如上,但是是最大等级而不是平均等级
  • 玩家在各自职位中的“排位”(按总体评分排序)

注意,我们还对我们的分类变量进行了一次性编码。

第二步。探索性可视化

接下来,我们可以检查数据集的一些有趣的特性。我们发现我们的目标变量有一个稍微偏斜的正态分布,平均值大约为+1:

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

作者图片

我们可以画出一个赛季中最大的 5 个赢家和输家:

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

作者图片

该数据集中最大的进步是由当时 16 岁的波兰门将 Drągowski 实现的,他的排名在 2015 年和 2016 年之间惊人地上升了 21 分,从 50 分上升到 71 分。另一方面,最大的输家是可怜的老约娜·托伊维奥。芬兰中后卫的整体评分在 2018/19 赛季期间下降了 8 分,从 71 分降至 63 分。我不知道他做错了什么,但这不可能是好事。

凭直觉,我们可能会认为年轻球员更有可能从一个赛季提高到下一个赛季,而老球员则下降。也可能是这样的情况,在某些职位上的改进往往比其他职位快,甚至两者之间可能存在相互作用。让我们快速浏览一下年龄和职位与进步的关系图,看看是否有什么特别之处。(注意,我们在每个位置随机抽取 500 名球员,以便于绘图)。

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

作者图片

不出所料,年龄和进步之间存在关联——但平均水平也有很大差异。有很多年轻球员一年比一年差,也有很多稍老的球员变得更好。也许有更多的年轻攻击中场球员在这个数据中有所提高,守门员的关系可能比其他位置稍浅,但除此之外,这种模式在所有组中都相当稳定。

最后,让我们生成一些经典的蜘蛛图来看看那些工程团队级的特性。

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

作者图片

创建这些图的完整代码如下。

步骤 3:建模和评估

既然我们已经获得了数据并设计了我们的功能,预测建模的实际代码就相当简单了。当然,调整、调整和改进模型需要时间,但是为了这个实验的目的,一些简单的默认参数就可以了。我们所要做的就是将我们的数据分成训练集和测试集,将它们转换成 xgb 数据矩阵,并通过xgb.cv函数运行它们。这将在我们的训练集中进行 k 倍交叉验证,这将为我们提供估计,我们可能期望该模型在样本外的表现如何。顺便说一下,本节假设您对 xgboost 非常熟悉。如果你不是,这里有一篇优美温和的介绍你可以看看。

这里需要注意的一件重要事情是,我们是而不是随机划分我们的训练集和测试集。如果我们这样做了,那么我们将在整个时间段的训练集中包括案例。这意味着我们的一些训练数据会比测试数据来得晚。但是测试集应该代表“看不见的”数据,在你训练完你的模型之前,你在现实世界中是无法访问这些数据的。

因此,我们复制更真实的条件,并按时间分割我们的数据。这意味着我们将总是使用过去的数据来预测未来,不需要时间旅行。

我们还在最后添加了一些代码来计算最佳迭代的一些不同的性能指标,包括 RMSE 和 R 平方。我们可能对它作为基本的改进/未改进分类器的表现感兴趣,因此我们添加了一些分类指标(灵敏度、特异性、阳性预测率和阴性预测率)作为良好的度量。

# A tibble: 1 x 8
model    rmse  r_square  sens   spec  pos_pred_rate neg_pred_rate
xgboost  2.15     0.339  0.332 0.915          0.651         0.741

我们得到的结果看起来相当合理,因为这只是开箱即用的 xgboost。(注意,在 GitHub repo 中,我们还运行了一个简单的线性模型作为基线,这总是一个好主意,但为了节省空间,这里省略了它)。RMSE 分数或多或少表明,该模型的预测正确率平均在+/- 2 点以内,R 平方表明我们解释了目标变量中约 34%的方差。

对于分类指标,该模型正确地识别了大约三分之一将要改进的玩家,并正确地排除了大约 90%没有改进的玩家。总的来说,如果你用它来选择一组预测在即将到来的赛季会变得更好的球员,大约 65%的人会这样做。

另一个重要的意义检查是查看模型使用哪些变量来进行这些预测。如果它过于依赖一个特性,或者一组我们不认为特别重要的变量,那么这可能是一个奇怪的迹象。我们可以使用下面的变量重要性图来检查这一点(只画出了 20 个最重要的特征)。

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

作者图片

在预测一个球员未来的进步时,看起来最重要的特征是他们当前的总体评分。这从直觉上讲是有道理的:已经非常优秀的玩家更有可能接近他们游戏的巅峰,并且没有更小的“空间”来提高。

同样有希望的是,该模型正在对年龄以及与球员俱乐部相关的各种特征(我们之前添加的那些额外列)产生影响,包括平均总体评级、平均首发评级、位置排名(“啄食顺序”)等等。

最后,我们来看几个玩家级预测的例子。这是从交叉验证的训练数据中随机选择的预测。

请注意,我们的男孩 Mo Salah 和 André Schürrle 都在那里,该模型正确地将 Mo 标记为良好前景(预计会改善),而 Schürrle 标记为不佳前景(预计会变得更糟)。

因为这个模型看起来很合理(并且因为这只是一个玩具例子),我们将把我们的评估留在那里,并接受它作为我们的最终模型。然后,我们在保留数据上测试它的性能,看看它在样本外的表现如何。

# Predict on test set
preds <- predict(xgb_model, newdata = test_xgb)# Add to data
test <- test %>%
  mutate(pred_improvement = preds,
         residual = improvement - pred_improvement) %>%
  select(1:improvement, pred_improvement, residual, everything())# Metrics
test %>%
  filter(season == 19) %>%
  mutate(pred = pred_improvement, obs = improvement) %>%
  mutate(pred_category = ifelse(pred > 0, "improve", "decline/same"),
         obs_category = ifelse(obs > 0, "improve", "decline/same")) %>%
  filter(!is.na(pred), !is.na(obs)) %>%
  summarise(rmse = RMSE(pred, obs),
            r_square = R2(pred, obs),
            mae = MAE(pred, obs),
            sens = sensitivity(factor(pred_category), reference = factor(obs_category)),
            spec = specificity(factor(pred_category), reference = factor(obs_category)),
            pos_pred_rate = mean(obs_category[pred_category == "improve"] == "improve"),
            neg_pred_rate = mean(obs_category[pred_category != "improve"] != "improve"),
            num = n()) %>%
  mutate(model = "xgboost") %>%
  select(model, everything())## Resultsmodel    rmse r_square   mae  sens  spec pos_pred_rate neg_pred_rate
xgboost  1.82    0.119  1.43 0.410 0.784         0.359         0.818

该模型在测试数据上的表现也相当不错——在一些指标上优于交叉验证(RMSE、灵敏度、阴性预测率),而在其他指标上则较差(R 平方、特异性、阳性预测率)。这里没有任何过度拟合的主要证据,所以我们很清楚要真正尝试这个模型,并开始在最新数据中识别转移目标。

第四步:确定转移目标

现在我们有了我们的模型,我们准备对最新的数据进行预测,并确定一些转移目标!

为此,我们将建立一个函数,对于任何给定的俱乐部:

  1. 计算俱乐部在最近一个赛季的团队级别属性
  2. 按位置为该俱乐部的球员创建球员评级矩阵。这使得转会前景可以很容易地与俱乐部中相同位置的其他球员进行比较,从而创建一些预测功能
  3. 采用最新的国际足联数据中的所有球员,并设置他们的属性,以便“看起来”他们在新的俱乐部
  4. 通过这些新功能预测他们的改进分数
  5. 将此与原始预测(使用旧俱乐部的特征生成)进行比较

所以本质上我们在这里做的是说:对于数据集中的每个球员,如果他们的俱乐部级别属性改变了,他们的预测会如何改变?

(我们还增加了一个选项来获得最差的转会,即我们应该避免的转会目标,我们认为球员在我们的俱乐部会比留在他们原来的俱乐部做得更差)。

如果我们为利物浦俱乐部运行这个程序,并保留前 100 个目标,我们会得到下面的结果。一些特殊字符的格式有点…不寻常,所以你必须原谅那些。

(注意:当这个帖子被创建时,最新的可用数据是 FIFA 20 数据集——所以这些预测是针对 19/20 赛季的,有点过时了。加入 FIFA 21 的数据将是一个很好的项目扩展!)

这里有一些有趣的事情:

  • 所有十大目标都是进攻型中场,包括像凯文·德布劳内(我们可以做梦)保罗·迪巴拉布鲁诺·费尔南德斯。解释模型的具体选择是我们可能会保存到未来的帖子中的事情——但看起来模型可能会发现尤尔根·克洛普在 CAM 部门相对缺乏可用的选项
  • 其中几名球员实际上是利物浦最近几个赛季的转会目标——最引人注目的是纳比尔·费基尔。所以看起来模型至少做出了一些合理的决定!
  • De Bruyne 是排在首位的一个特别有趣的内含物。虽然转会不太可能发生,但该模型预测,如果他留在曼城,KDB 的总体评分在不久的将来可能会略有下降——但如果他转会到安菲尔德,他实际上会有所改善。精神食粮。
  • 鉴于默西塞德郡目前的防守伤病危机,选择有前途的莱比锡中后卫易卜拉希马·科纳特是一个有趣的选择。事实上,这位 25 岁的球员在最近几个月与转会到利物浦的联系在一起,我们的模型预测,在克洛普的领导下,他的进步速度将比现在的俱乐部快 60%以上。在这个世界上,他排在范迪克、戈麦斯和马蒂普之后,排在第四位——随着更多的一线队出场,他可能会进步得更快。

我们可能会花一整天的时间来研究这些结果——事实上,这种人工检查通常是机器学习项目中的一个重要步骤。

在下面的附录中,你可以看到 19/20 赛季在英超踢球的每个俱乐部的前 50 名转会目标。你同意你的俱乐部的哪些选择?你认为哪个模型出错了?为什么会这样?回答这类问题通常可以帮助您确定要包含的新数据源、要设计的新功能、要编码的更多领域专业知识,这些可能会改进您对未来的预测。

结论

当然,我们在这里采用的方法有很多限制。虽然国际足联的评分系统令人印象深刻的彻底,它自然是不完美的。任何讨论单个玩家评级的留言板都会有很多粉丝抱怨感知的不准确性,而为视频游戏设计的系统永远不会完全捕捉到专业水平所需的所有细微差别。因此,出于类似的原因,我们的“改善”目标有点粗糙。我们也有很多更复杂的方法来模拟这个问题——例如,使用图形卷积网络来更全面地捕捉不同类型的球员在同一个俱乐部中产生的复杂互动效应。

然而,我们在这里展示的只是冰山一角。我们已经探索了一些简单、容易获得的数据,用几行代码构建了一个模型,并且已经获得了直观的结果。甚至这个简单的概念证明也能引发一些有趣的转让讨论。但顶级俱乐部可以获得比这更丰富、更广泛的数据来源。想象一下,如果你有资源将机器学习技术应用于类似于 Wyscout 数据库的东西,你会做些什么。

所以这个故事的寓意是:当谈到机器学习时,从简单的东西开始,在你感兴趣的主题上找到一些容易获得的数据,不要害怕陷入其中并进行实验。你可能会对你的发现感到惊讶。

附录:所有英超转会目标

下表是通过运行 19/20 赛季英超各队的get_best_transfers()函数生成的。对于每支球队,我们都使用一些粗略的启发式方法来筛选更“现实”的转会目标(没有必要只向每个人推荐莱昂内尔·梅西)。

首先,根据国际足联的比赛,我们筛选出那些被记录为市场价值等于或低于目标俱乐部最昂贵球员+ 20%的球员。第二,我们也通过总体评分进行过滤,只显示那些目前在“总体”评分上比首发俱乐部前 11 名中最差球员最多差几分的球员。因此,如果你的球队最差的首发球员总评分为 80,而你最贵的球员价值 5000 万,你会看到当前总评分为 78 或更高的转会目标,当前市值为 6000 万或更少。

在“新俱乐部”栏中搜索你支持的球队,并在探索预测中获得乐趣!

使用机器学习预测信贷损失:为什么当前的方法有缺陷

原文:https://towardsdatascience.com/using-machine-learning-to-predict-credit-losses-why-current-methods-are-falling-short-e18ac0a191b3?source=collection_archive---------54-----------------------

“所有模型都是错的,但有些是有用的”

乔治·博克斯 1976 年论文中的上述引文在 45 年后的今天仍然适用。)在很多方面。过去十年中,机器学习的进步带来了很多希望(和大量宣传),有助于解决商业中最棘手的挑战:在事情发生之前知道将会发生什么。我们提出,即使所有的模型都是错误的,一些模型比其他模型的错误少*。*

背景

为了提供机器学习如何解决分类问题的一些基本背景,下面的视觉表示显示了如何通过算法将由具有已知结果的案例组成的数据集(即,数据集中的每一行代表一笔独特的贷款,每一列中有关于该贷款的属性,最后一列代表该贷款是否违约)馈送给训练*(即,创建模型😗

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

(图片由作者提供)

一旦模型已经根据已知的历史案例和结果(违约与非违约)进行了训练*,就可以输入结果未知的新案例;该模型根据从训练数据集中获得的信息,预测每种新情况的预期结果:*

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

(图片由作者提供)

现在我们有了机器学习如何工作的基本知识。这在理论上听起来很棒,但让我们探索一下为什么像我们上面训练的模型在实践中不适合许多应用,包括大多数信用损失建模。

一个重要的区别

在我们的数据仓库中,我们可能存储代表事务的数据。例如,对于每笔贷款,我们可能有多行数据:如果贷款按月偿还,则新的一行表示每个月的未偿余额。这与我们需要训练模型的数据集的结构形成对比;我们训练数据集中的每一行都应该是一个独特的案例,我们稍后将要求它对其进行预测。如果我们正在构建一个模型来预测香蕉是成熟还是腐烂,我们的训练数据集中的每一行都必须表示关于一个独特香蕉的信息,而不是每天对多余香蕉的观察。

亏空

首先,回想一下,我们的训练数据集由违约或未违约的案例组成。考虑一个贷款组合,我们的数据仓库中有一些历史数据,包含违约或按期全额偿还的贷款(让我们暂时忽略提前还款的想法,我们可以改天再讨论)。然而,我们数据的很大一部分可能代表了仍在账面上的贷款,这些贷款没有违约,但也没有达到贷款期限的末尾(其结果是未知的 T2)。这提出了几个重要的问题:

如果我们不将这些“活跃的”案例包含在我们的训练数据集中,我们是不是遗漏了许多本应该告诉我们的模型的重要信息?毕竟,如果他们还在账面上,他们还没有违约…

此外,我们知道训练数据集中的每一行都必须代表一笔唯一的贷款:

如果我们的训练数据集中的一个案例具有“违约”的已知结果,那么知道该贷款是在 1 个月后还是在 1 年后违约难道不重要吗?

毫无疑问,我们希望我们的模型能够评估这样一位客户,他在 28 年内按时偿还了 30 年期抵押贷款,然后违约,与在最初几个月后破产的客户不同。

考虑一个不同的问题,比如访问者是否会点击我们网页上的广告。在这个例子中,可能没有太多的“寿命”要考虑。他们上了我们的网站,在几秒钟内,要么点击了广告,要么继续前进——仅此而已。我们可以快速创建一个训练数据集,该数据集可以输入到一个算法中,并生成一个模型,如我们之前在背景部分中所述。

相反,客户拖欠贷款不是一个在几秒钟内发生的过程;几乎可以肯定,这是导致违约的几个月或几年内发生的一系列事件的结果。

我们可以把前面提到的两个问题归结为一个一般性问题,这个问题包含了我们想要得到的核心内容:

我们如何将关于案例(贷款)的“生命周期”的更多信息整合到我们的模型中?

让我们来看三种不同的方法来实现这一点:

  1. 生存分析
  2. IPCW(逆概率截尾加权)
  3. 贝叶斯推理

生存分析

生存分析是一种回归方法,旨在预测事件发生的时间。它还允许我们引入“事件”尚未发生的情况。当训练生存模型时,我们的训练数据集中的每一行都是唯一的贷款,并且列被指定如下:

  • ***‘时间(月)’*代表我们观察贷款的时间
  • ***‘事件’*表示事件(默认)是否在观察期间发生;默认值= 1,无默认值= 0
  • 【属性 1】【属性 2】**代表贷款的一些其他信息(即自变量);这些变量可以是分类独立变量*,如与贷款相关的客户所在地区,或连续独立变量,如观察期间客户的平均债务覆盖率;你可以引入尽可能多的独立变量*来帮助解释你的模型中的方差**

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

(图片由作者提供)

*生存模型的输出不同于传统机器学习模型的输出。生存模型输出新贷款案例“存活”(不违约)超过特定月数的概率,而不是输出它对新贷款案例属于哪一类(违约或非违约)的猜测。更具体地说,当输入新病例时,该模型返回在训练数据集中的“**时间(月)】*列中找到的每个唯一时间值之后存活的概率。

在我们上面的模拟数据集中——忽略属性 1&2——我们的生存模型会告诉我们,一笔新贷款有 67%的概率存活过去 13 个月(因为 2/3 的贷款是在过去 13 个月观察到的),有 33%的概率存活过去 27 个月(因为 3 笔贷款中有 1 笔“存活”过去 27 个月)。当然,更复杂的模型会考虑我们额外的独立变量(如’属性 1 '和’属性 2 ')并改变这些概率。

生存分析是对传统机器学习的改进,因为它允许我们将嵌入在我们尚不知道结果的案例中的所有信息纳入我们的模型。它还允许我们回答一些非常有力的问题,例如,“在我们投资组合的这一部分中,哪些贷款在 12 个月内违约的可能性大于 50%?24 个月怎么样?”。然而,生存模型假设事件*(在我们的例子中是违约)将最终在未来的某个时刻发生。这并不完全符合我们的业务问题,因为许多贷款不会出现违约(它们将被全额偿付)。也许有一种方法可以将生存分析中的一些方法论融合到传统的机器学习模型中…*

IPCW(截尾加权的逆概率)

在生存分析中,未知结果的病例被称为“已审查”。在 Vock 等人撰写的 2016 年题为“ 使机器学习技术适应审查的时间-事件健康记录数据:使用审查权重的逆概率的通用方法 的论文中,作者讨论了一种将生存方法引入任何机器学习分类模型的方法。

他们提出的方法要求在训练数据集中只使用结果已知的案例,但是使用一种叫做审查加权的逆概率(IPCW) 的技术对这些案例中的每一个单独进行加权*。这些权重是基于整个数据集计算的(结果已知的病例和结果未知的病例)。不是推导事件在时间 t 之前发生的概率,而是通过取该推导的逆来计算 IPCW 权重,或者在时间 t 之后结果仍然未知的概率。*

使用 IPCW 加权的训练数据集来开发一个模型,使我们能够利用所有最新和最棒的机器学习算法,同时还可以对我们所有关于未知结果贷款的数据进行编码。特别是,它有助于我们的模型理解在生命中不久违约的贷款和违约但几乎还清的贷款之间的差异。

贝叶斯推理

如果您已经做到了这一步,您应该看到我们正在以不同的方式稍微改变估计信用损失的业务问题,以符合适当的建模方法。

我们认为,最后一种适合信用损失建模的方法是贝叶斯推理。对于那些不熟悉的人来说,这些模型要求可能的结果和相关概率的先验分布,然后添加已经收集的数据(下图中的证据),以创建最终的后验分布。它的工作很像我们的大脑工作——我们通常对可能的结果及其可能性有一些预先的信念,我们随着时间的推移收集更多的证据,更新和完善我们的理解。

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

https://data insights . de/introduction-to-Bayes-inference-with-pystan-part-ii/

在信用损失建模的背景下,贝叶斯推理为我们提供了两个独特的优势:

  1. 我们通常不需要像训练频繁模型那样多的数据来训练一个统计上健壮的贝叶斯模型;这对于没有大量历史损失数据的组织尤其有用
  2. 这些模型输出可能结果的分布,而不是单点估计。这使得我们可以得出这样的结论,“我们有 90%的信心,信贷损失将少于 500 万美元,我们有 95%的信心,信贷损失将少于 1000 万美元”。这通常比传统的频率主义模型更有用,后者仅限于得出结论,“我们预测明年的信贷损失总额将达到 600 万美元”

Kwon 在 2012 年的论文 “三篇关于信用风险模型及其贝叶斯估计的论文” 中最好地概述了使用贝叶斯方法对信用损失进行建模。

包扎

尽管使用机器学习来帮助改善信用损失预测的承诺是合理的,但这样做需要确保您正确地设置数据和模型。将你的数据直接插入机器学习算法可能会很快,所以考虑使用生存分析的一些方法——包括 IPCW——或贝叶斯推理,以确保你正在用你拥有的信息建立最好的模型。

如果你想了解更多关于如何改善你的信用损失评估模型,不要犹豫,与我们联系在凯奇布鲁克分析

使用机器学习预测客户流失

原文:https://towardsdatascience.com/using-machine-learning-to-predict-customer-churn-cd499cb230db?source=collection_archive---------14-----------------------

监督机器学习

使用逻辑回归、决策树、随机森林和梯度推进预测客户流失

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

Gert RDA valasevi it 在 Unsplash 上拍摄的照片

简介

在本文中,我将带您了解机器学习的一个真实的业务用例。通常,企业需要采取主动措施来减少客户流失(流失)。在大数据和机器学习时代,预测客户流失从未如此容易。

我使用四种机器学习方法,并根据性能推荐最佳方法。我用过的四个模型是:逻辑回归、决策树、随机森林分类器和梯度推进机器分类器。

基于两个标准评估模型性能:训练时间和预测能力。AUC 是用于衡量预测能力的指标,因为它提供了一种很好的衡量模型区分流失客户和未流失客户的能力的方法。

数据

模型根据客户数据集进行训练(每个客户都由唯一的客户 id 标识)。特征是与业务相关的客户属性。它们包括以下内容:

性别——注册时指定的客户性别

加入日期——客户加入的日期

联系倾向——客户联系客户服务部的可能性

Country ID——可以连接到 Country 表以获取客户当前居住国家名称的标识符。国家表也可用于分析。

目标(或标签)是客户流失标记,它识别客户停止处理业务的情况。

数据准备

这是机器学习管道的第一步,在这里进行一些初始探索、数据源合并和数据清理。

合并数据:客户属性和国家数据在国家 ID 上合并,带入当前居住国家的名称。

重复:在客户数据的上下文中,重复的观察可能意味着错误的数据管理,因为数据中应该只有一个客户的实例。没有发现重复的观察结果。

初始特征工程:加入日期是一个日期时间特征,已经被拆分为加入月份和加入年份。这种拆分为模型提供了捕捉客户流失的潜在季节性影响的机会。

测试&训练:客户数据被分成测试和训练数据集。具有丢失流失标记的客户被分配到测试集,所有其他客户在训练集中。测试和训练数据集中唯一客户的数量分别为 5,622 和 50,598。

从这一点开始,测试和训练数据被分开处理,以防止两者之间的数据泄漏,这种泄漏会对机器学习的有效性产生不利影响。

缺失数据:大量缺失数据会影响下游建模。对 N/A 或空值进行简单检查,以确保测试或训练中没有。没有意外丢失的值。

探索性数据分析

最初的数据探索揭示了一些有趣的怪癖。

性别:在培训和测试中,有三个独特的性别类别。男,女,U(未知)。未知案例大约占测试和训练集所有案例的 5%。

对于未知的情况有两种可能的解释。1)选择不透露性别的客户。2)数据输入或数据质量问题导致信息丢失。

对于未知的情况,很难说清楚这两种情况之间的区别。因此,我做了一个简化的假设,即未知病例是那些选择不透露性别的人。在此基础上,有理由相信这群人的行为可能与那些选择认同的人不同。这就是我在训练数据中留下未知案例的理由。

未知案例在流失客户和固定客户中的分布比例与男性和女性客户相似。

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

跨流失标志的性别分布

缺失&未知国家:在训练数据中,共有 12 名客户的当前居住国缺失或未知。这个相对较小的训练集子集可能是由于数据输入或收集错误造成的。客户不明确说明自己的居住国就注册这项服务似乎不太可能。正因为如此,我将从训练数据中省略这些观察值。

注意:如果当前居民所在的国家不断更新,将缺失的数据作为其自己的类别保留下来可能是值得的。

异常加入日期:在培训数据中,一些客户的加入日期为 1901,这表明存在一些数据质量问题。这些观察结果在分析中被忽略了。

非常老的客户:测试数据中的一位客户年龄为 150 岁。这几乎肯定是数据输入错误,因为目前世界上最长寿的人是 117 岁。荒谬的年龄观察已被纠正,将年龄大于 117 岁的观察替换为客户在其居住国的平均年龄。

注:117 岁是写作时最长寿的人的年龄。这可能需要重新考虑。

**训练&测试数据:**训练和测试的分割基于丢失的流失标记。这是有意义的,因为目标是推断丢失的流失标记。但是,检查测试人群是否是训练人群的代表性样本是明智的。

我们可以通过绘制我们特征的分布图,并在测试和训练中进行比较来实现这一点。通过肉眼观察分布,测试集看起来确实是训练集的子集,这是我们进行有效机器学习所需要的。

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

加入年度分布

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

加入月份分布

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

目前居住分布的国家

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

性别分布

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

年龄分布

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

接触倾向分布

一个热编码

机器学习模型解释数字而不是单词。我们的客户数据具有必须转换的分类变量,以便机器学习模型能够处理它们。这是通过一个热编码完成的。

造型

四个机器学习模型已经按照标准建模管道进行了训练。选择一个模型,并结合网格搜索和 5 重交叉验证仔细调整超参数。

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

作者图片:ML 培训管道

下面是 Python 中培训管道的样子。这个简单的功能涵盖了结果评估阶段的所有内容。

用于训练和调整 Scikit Learn 机器学习模型的管道

时间和计算的约束限制了我在优化超参数方面的搜索空间。但是,可以通过以下启发式调整来获得最佳预测性能:

逻辑回归:模型已经用 L2 正则化初始化,这稍微降低了模型的复杂性,以防止过度拟合。超参数 C 是正则化参数的倒数,它被调整以找到最佳拟合。[1]

运行逻辑回归管道的 Python 代码

决策树:决策树容易过度拟合,调整最大树深度和最大特征可以避免这种情况。

运行决策树管道的 Python 代码

随机森林:要调整的重要超级参数是树的数量和每次分割时要考虑的特征子集的大小[2]。自举样本用于构建树,以使模型对过拟合具有鲁棒性。

运行随机森林管道的 Python 代码

梯度推进机:树的数量、学习速率和树的深度是需要调整的重要超参数[2]。

运行梯度提升机器管道的 Python 代码

**不平衡的阶层:**从我们的探索性数据分析中,我们看到流失客户和坚持客户之间的阶层不平衡。所有模型都使用类别加权来解决这个问题。

车型评测

预测能力

使用 AUC 评估预测性能。在预测性能方面,梯度增强优于所有其他模型,平均 AUC 为 0.994。逻辑回归表现不佳,平均 AUC 为 0.7246。

决策树在最佳运行时表现良好。然而,在所有模型中,其最佳运行和整个搜索空间内的方差是最高的,这意味着有些倾向于过度拟合训练数据,这是不容易控制的。

就预测能力而言,随机森林是表现第二好的模型,平均 AUC 为 0.993。然而,它对过度拟合最稳健,交叉验证折叠之间的方差为 0.000287。

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

跨 5 倍 CV 的最佳超参数空间的模型性能

下面是用于生成所有最佳模型得分表的 Python 代码。

为每个模型生成最佳得分表的 Python 代码

下面是用来生成上面图表的代码。

为每个模型绘制最佳分数的 Python 代码

训练速度

尽管梯度增强在预测能力方面表现最好,但训练速度很慢,仅用了半个多小时。相比之下,随机森林花了大约一半的时间进行训练。逻辑回归和决策树都在不到 10 秒的时间内完成训练。然而,易过拟合和预测性能差使得这些选项不适合商业使用。

最佳模特

随着计算能力的提高,我会推荐梯度推进。然而,随机森林提供了出色的预测性能和对过度拟合的鲁棒性,这对于生产模型是很重要的。

生产模型

最终,这种模型不仅仅会出现在你的笔记本电脑上,还会被客户大规模使用,因此需要进行生产。因此,我建议我们应考虑以下几点:

1) 这将使测试脚本和调试代码(如果需要的话)变得更加容易。

2) 客户数据监控:我们需要能够预测模型性能何时会受到影响。一种简单的方法是监控我们当前的客户群,并评估它是否与过去的客户群有显著差异。

**3)模型重新评估&重新培训:**我们应该定期根据新数据评估模型的性能。这可能是当我们检测到数据偏差(见第 2 点)或在一个设定的时间框架。如果新数据的模型性能低于我们的阈值,我们将需要重新训练模型。拥有灵活的建模管道将使重新训练模型变得容易。

4) 考虑袋外评分:如果使用随机森林模型,考虑使用袋外验证来加速训练。不是 K-fold 交叉验证,而是在袋外样本上验证随机森林(假设引导样本用于构建树)。

5)

6) 扩展训练数据:通过在数据中包含一些附加特征,可以进一步提高预测性能。其中一些是最常见的走廊和定价、每月交易、转介和平均交易金额。

代码和数据

这个分析背后的完整 python 代码可以在这里运行。数据可在我的流失建模 GitHub repo 中获得。

https://www.linkedin.com/in/john-adeojo/

使用机器学习来预测客户的下一个购买日

原文:https://towardsdatascience.com/using-machine-learning-to-predict-customers-next-purchase-day-7895ad49b4db?source=collection_archive---------0-----------------------

机器学习模型来预测客户是否会在一段时间后进行下一次购买。

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

图片由 Mediamodifier 制作,可以在这里访问。

介绍

如果说零售业的人从新型冠状病毒疫情那里学到了一个重要的教训,那就是要求他们转向通过互联网做生意,即电子商务。电子商务的理念有助于管理人员为公司的发展做出决策。毫无疑问,这些决策中的大多数都会受到数据分析、数据科学和机器学习专家对在线客户购买行为数据的研究结果的影响。

假设一家在线零售店的管理团队带着数据集来找你,你是一名数据科学家,你想知道顾客是否会在最后一次购物后的 90 天内进行下一次购物。您对他们询问的回答将有助于他们确定他们的营销团队在推出下一次促销活动时需要关注哪些客户。

在本文中,作为一名数据科学家,我的目标是构建一个模型,为公司经理提出的问题提供合适的答案。更准确地说,使用给定的数据集,我建立了一个机器学习模型,预测零售店的在线客户是否会在他们最后一次购买的 90 天后进行下一次购买。

值得一提的是巴尔·卡拉曼已经做了一个类似的工作回答了一个不同的问题,而不是我们想要先发制人的这个问题的准确预测。

关于数据集的一些信息

在开始回答感兴趣的问题之前,我将首先介绍一些关于数据集的一般有用信息。

该数据集记录了来自 43 个不同国家的 5942 名在线客户。在零售店的在线客户中,90.8%的人生活在英国。

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

图 1:以百分比表示的客户国家计数—图片由作者提供

英国有如此庞大的客户群,公司 83%的收入来自英国也就不足为奇了。

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

图 2:各国收入百分比——图片由作者提供

下面的图 3 给出了在线零售公司每月收入的直观表示。

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

图 3:2009 年 12 月至 2011 年 12 月的月收入——图片由作者提供。

在这里,我们可以观察到该公司在 2010 年 11 月的收入最高,其次是 2011 年 11 月。此外,8 月份以后每月收入有所上升。

根据本节所做的分析,我们可以向经理们提出一些建议供他们考虑。在该公司努力增加除英国以外的其他国家的客户群的过程中,数据科学家可以向管理团队提出什么建议?在回答这个问题时,我会说…

由于该公司在英国拥有坚实的客户基础,它可以利用这一点推出“双赢促销”。具体来说,对于现有客户购买的任何产品,他/她都有机会通过网络链接邀请英国以外的新客户。如果新客户使用他/她从现有客户那里收到的网络链接从在线商店购买了一些东西,公司将向现有客户和新客户提供一张现金券,双方可以在下次购买时使用该现金券。通过这样做,我们看到公司、现有或以前的客户以及新客户在交易中都获得了一定程度的满意度。

预测顾客的下一次购买

在这一节中,我将重点介绍我为解决感兴趣的问题而部署的方法。也就是说,建立一个机器学习模型,该模型将预测零售店的在线客户是否会在他们最后一次购买的 90 天后进行下一次购买。

主要步骤包括如下:

  • 数据角力
  • 特征工程
  • 建立机器学习模型
  • 选择型号

我首先导入必要的 Python 包,下载数据集,然后将其加载到我的 Python 环境中。下面的代码片段总结了这个步骤。

数据争论

然后,我与数据集争论,让它进入良好的状态,以便引入新的X特性。

给定数据集的CustomerID列有243007缺失数据。这代表了所有在线客户的22.77%。此外,Description列有4382缺失数据。我如何处理这些丢失的数据?在与公司领导交谈后,他们建议应该放弃任何缺少CustomerID的项目。

数据帧df_data被分成两个熊猫数据帧。即,

  • 第一个子数据框架ctm_bhvr_dt包含客户在 2009 年 1 月 12 日至 2011 年 8 月 30 日期间的购买情况。从这个数据集中,我得到了所有在线客户的最后购买日期。

  • 第二个子数据帧ctm_next_quarter用于获取客户从 2011 年 01 月 09 日到 2011 年 11 月 30 日的首次购买日期。

接下来,我创建一个 pandas 数据框架,其中包含每个客户的一组特征,以便我们构建预测模型。我首先创建一个数据集,它包含数据帧ctm_bhvr_dt中的不同客户。

然后,我向数据帧ctm_dt添加一个新标签**NextPurchaseDay**。这个新标签将是数据帧中某个客户的最后一次购买日期之间的天数,该客户拥有最频繁购买的商品,并且缺少 CustomerID 下面的过程处理 CustomerID 列中缺少的值。结果是数据框ctm_next_quarter中的ctm_bhvr_dt和他/她的首次购买日期。

下面的图 5 是上面代码片段的输出。它显示了 dataframe 对象的前 5 个条目ctm_dt

图 5:客户的下一个购买日数据

在下一节中,我将介绍一些功能,并将它们添加到数据框架ctm_dt中,以构建我们的机器学习模型。

特征工程

我在我们的数据框架ctm_dt中引入了一些特性,这些特性根据客户对公司的价值将他们分成不同的组。在执行这个过程中,我使用了 RFM 分割法。RFM 代表

  • 最近度:表示顾客购买的时间有多近。
  • 频率:顾客购买的频率或次数。
  • 货币价值/收入:客户在某一时间点购买时所花费的金额。

利用这三个特征,即新近性、频率和货币价值/收入,我创建了一个 RFM 评分系统来对客户进行分组。从本质上讲,RFM 得分有助于洞察客户在未来可能会做出什么样的购买决定。

在计算出 RFM 分数后,我接着应用无监督机器学习为每个分数识别不同的组(群)并将它们添加到数据框架ct_dt。最后,我将 pandas 数据框架方法get_dummies应用到ctm_dt来处理数据框架中的分类特征。我现在开始编写代码,找出 RFM 分数和聚类的计算方法。

新近度

在了解谁有可能进行当前购买的过程中,我使用最近特征来解决这个问题。考虑到顾客在最后一次购买后离开的时间长度,最近特征在这里就派上用场了。我使用这个特性来了解哪个客户将进行交易。还需要注意的是,最近购买的客户的销售交易远比有一段时间没有购买的客户更有价值。

让我们进入下面的编码。

下面的图 6 给出了在线客户的最近数据的可视化表示。

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

图 6:客户最近数据的直方图—图片由作者提供。

用于生成上面图 6 的代码可以在 Jupyter 笔记本这里访问。

接下来,我需要为最近值分配一个最近分数。这可以通过应用 *K 均值聚类算法来实现。*但是,在使用算法之前,我们需要知道聚类的数量。应用 肘法 ,可以确定给定数据所需的聚类数。在我们的例子中,给定最近值作为我们的数据,计算的聚类数是 4。用于计算星团数量的代码可在 Jupyter 笔记本这里获得。

我现在可以使用数据帧ctm_dt中的**Recency**列构建 4 个聚类,并在ctm_dt中创建一个新列**RecencyCluster**,其值是由无监督机器学习算法kmeans预测的聚类值。使用用户定义的 Python 函数order_cluster可访问这里是,我按照**RecencyCluster**中值的降序对数据帧ctm_dt进行排序。下面的代码片段输出了图 7。

图 7:客户最近聚类数据

让我们根据标有**RecencyCluster**的列中的聚类值对数据帧ctm_dt进行分组,并取出每个聚类的**Recency**数据的统计描述

图 RecencyCluster 的最近数据的统计摘要

从上面的图 8 中可以看出,聚类值 3 包含最近的客户,而 0 包含最不活跃的客户。

在接下来的小节中,我将我们在这一小节中讨论的方法应用于频率和收入特性。

频率

如前所述,在特定的时间段内,如果我们考虑客户参与购买交易的次数,频率就会发挥作用。现在,这种频率特征有助于我们了解特定公司或贸易品牌的客户联盟。考虑到这一点,它使公司能够洞察营销策略,以及在什么时间点进行传递,以便特别触及这些客户。

在这里,我进行了与上一小节相似的分析过程(新近度)。

图 9:带有频率的主数据集的前 5 个条目

下面的图 10 展示了购买频率低于 1200 的客户的直方图。

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

图 10:购买频率低于 1200 的客户直方图—图片由作者提供。

下面的代码片段为每个客户的购买频率分配一个分类值,并按降序对分类值进行排序。

图 11:带有 FrequencyCluster 的主数据集的前五个条目

下面的代码片段根据记录在标签为**FrequencyCluster**的列中的聚类值对数据帧ctm_dt进行分组,并提取每个**FrequencyCluster**值的**Frequency**数据的统计描述。

图 12:针对 FrequencyCluster 的频率数据统计摘要

就像最近的情况一样,具有较高频率聚类值的客户是更好的客户。换句话说,他们经常光顾零售店的产品,而不是那些频率聚类值较低的产品。

货币价值/收入

为了更详细地描述货币价值或收入,它更侧重于客户在任何时间点购买时所花的钱。因此,这有助于确定顾客在购物时可能会放出多少钱。尽管收入的这一特征并不能让人们预测顾客下一次购买的时间,但知道当顾客完成交易时会有多少收入是值得的。

我再次遵循类似的过程来获得每个客户的收入分数,并根据他们的收入分数为每个客户分配聚类值。

图 13:带有收入的主数据集的前五个条目

下图直观地展示了收入低于 10,000 英镑的客户。

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

图 14:货币价值低于 10000 的客户直方图—图片由作者提供。

下面的代码片段为每个客户的收入分配一个分类值,并按升序对分类值进行排序。

图 RevenueCluster 的收入数据统计摘要

总分

在下面的代码片段中,我向 dataframe ctm_dt添加了一个新列**OverallScore**,其值是最近、频率和收入的聚类值之和。

图 16:根据整体核心价值分组的近期、频率和收入的平均值

上面的评分清楚地告诉我们,总体得分为 8 分的客户是非常优秀的客户,他们为公司带来了很多价值,而那些得分为 3 分的客户被认为是不可靠的,仅仅是徘徊不定。

作为跟进,我根据总体得分将客户分为以下几类:

  • 3 到 4:低值
  • 5 到 6:中间值
  • 7 到 8:高价值

代码片段如下:

图 17:带有 Segment 列的主数据集的前五个条目

然后,我创建数据集ctm_dt的副本,并对其应用方法get_dummies,以便将所有分类列**Segment**转换为指示变量。

为了实现估计客户是否会在下个季度购买的目标,我创建了一个值为 1 或 0 的新列**NextPurchaseDayRange**,定义如下:

  • 如果值为 1,则表明客户将在下一季度购买某样东西,即从他或她最后一次购买起 90 天。
  • 值 0 表示客户将在自上次购买后的 90 天内购买商品。

我通过计算我们的特征和标签之间的相关性来结束这一部分。我通过对数据帧ctm_class应用corr方法来实现这一点。

图 18:最小和最大相关系数

从上面的图 18 可以看出,**OverallScore****RecencyCluster**的正相关性最高,为 0.97,**Segment_Low-Value****Segment_Mid-Value**的负相关性最高,为-0.99。

在下面的图 19 中,我展示了一个很好的系数矩阵的可视化。代码片段如下。

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

图 19:相关矩阵—图片由作者提供。

构建机器学习模型

在本节中,我将介绍构建机器学习模型所需的必要先决条件。下面的代码片段将数据帧ctm_class分成**X**特征和目标变量**y**。之后,我将**X****y**分开,以获得训练和测试数据集,然后测量不同模型的准确度、F₁-score、召回率和精确度。

图 20:所有模型的度量

从上面图 20 的结果中,我们看到LogisticRegression模型在度量准确性和 F₁-score.方面是最好的

让我们看看如何通过找到合适的参数来控制模型的学习过程,从而对现有模型XGB Classifier进行改进,该模型在上面的图 20 中排名第四。这个过程称为超参数调整。然后我用下面的计算来验证改进的XGB Classifier模型是否优于LogisticRegression模型。

图 21: XGB 分类器模型——超参数调整

图 22:改进的 XGB 分类器准确度分数

选择模型

比较上面图 20 中的LogisticsRegression和上面图 22 中的精确XGB classifier的精度,很明显精确XGB classifier 模型比LogisticRegression模型精确0.1。其他指标呢?

图 23:XGB 和 LogisticRegression 分类器的度量分数

从上面图 23 中的输出可以明显看出,对于每个指标、accuracyF₁-scorerecallprecision,改进的XGB classifier模型优于LogisticRegression模型。

在预测客户在最后一次购买 90 天后在网上零售店再次购买的预期时,我们的提交需要准确。因此,我感兴趣的是在进行这种先发制人时尽可能给出最高精确度的模型。因此,最好选择使用改进的XGB classifier型号,而不是LogisticRegression型号。

结论

从数据集中,我强调了一个事实,即以英国为中心的网上商店的强大客户群是公司从英国作为一个地区获得高收入的主要原因。

我还详细演示了如何建立一个机器学习模型来预测零售商店的在线客户是否会在他们最后一次购买的 90 天后进行下一次购买。在我使用的模型中,我必须通过超参数调整过程进一步改进XGB classifier模型,以胜过LogisticRegression模型。XGB classifier模型max_depthmin_child_weight的超参数调整后的初始指标都设置为 3,并没有超过LogisticRegression的指标。所以我不得不进一步试探性地调整这些值,以便让XGB classifier模型的性能优于LogisticRegression模型。

尽管如此,进一步研究如何再次提高模型的准确性和 F₁-score 度量将是有趣的。我建议通过引入“正确的”X特性来改进数据集,从而避免使用超参数调整过程。所以我现在的问题是

在不调整超参数的情况下,将哪些X-特征引入数据集以达到或提高模型的高精度和 F₁-score 指标是合适的?

本文使用的 Jupyter 笔记本可从这里获得。

参考

[1] 巴尔斯卡拉曼。(2021 年 4 月 28 日访问)预测下一个购买日

使用 MapQuest API 获取地理数据

原文:https://towardsdatascience.com/using-mapquest-api-to-get-geo-data-a0b4375145e3?source=collection_archive---------22-----------------------

数据科学技巧

一个友好的关于从街道地址获取邮政编码和其他地理数据的教程。

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

Jasmin Sessler 在 Unsplash 上拍摄的照片

知道如何处理地理数据是一个数据科学家的必备技能。在这篇文章中,我们将使用 MapQuest Search API 从街道地址中获取邮政编码以及相应的经度和纬度。

场景

2019 年,我和朋友参加了 CivTechSA Datathon。在比赛中,我们希望将数据点可视化并覆盖在圣安东尼奥的地图上。问题是,我们的数据不完整。惊喜!我们有的只是一个街道号码和一个街道名称——没有邮政编码,没有纬度,也没有经度。然后,我们转向互联网寻求帮助。

我们在 MapQuest 上找到了一个很棒的 API,它能给我们所需要的东西。只需少量的 Python 代码,我们就能实现我们的目标。

今天,我们将完成这一过程。

数据

为了跟进,你可以从这里下载数据。只需向下滚动到底部选项卡,转到 2019 年数据目录。寻找 saw(圣安东尼奥水系统),如下所示。

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

截图作者edn alin c . De Dios

通过点击 Excel 文件的链接下载文件。

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

截图作者edn alin c . De Dios

或者,你可以点击这个

MapQuest API 密钥

前往https://developer.mapquest.com/并创建一个账户以获得一个免费的 API 密匙。

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

截图来自edn alin c . De Dios

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

截图来自edn alin c . De Dios

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

截图来自edn alin c . De Dios

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

截图来自埃德纳林·c·德·迪奥斯

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

截图来自埃德纳林·c·德·迪奥斯

复制“消费者密钥”并将其保存在安全的地方。我们以后会需要它。

Jupyter 笔记本

现在,让我们打开 Jupyter 笔记本,开始编码吧!

首先,让我们通过几个导入来设置环境。

不要忘记用上面您自己的密钥替换 API_KEY(第 12 行)。

现在。我们用一个简单的df = pd.read_excel()来读取 Excel 文件。

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

截图来自埃德纳林·c·德·迪奥斯

接下来,我们将合并街道编号和街道名称列。

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

截图作者edn alin c . De Dios

所有的大写字母刺痛了我的眼睛。让我们做点什么:

df['street_address'] = df.street_address.str.title() .

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

截图作者edn alin c . De Dios

下面是两个调用 API 并返回地理数据的函数。

我们可以用下面这条线手动调用它。不要忘记用您自己的 API 键替换’ ##### '。您可以使用任何想要的地址(用+字符替换空格)。

get_zip('[https://www.mapquestapi.com/geocoding/v1/address?key=####################&inFormat=kvp&outFormat=json&location=](https://www.mapquestapi.com/geocoding/v1/address?key=Zd5jr3WZm1PbGobgPDHzLz9LEFDaco1V&inFormat=kvp&outFormat=json&location=3403+Kildare+Ave&thumbMaps=false&delimiter=%2C')100+ Military+Plaza[&thumbMaps=false&delimiter=%2C'](https://www.mapquestapi.com/geocoding/v1/address?key=Zd5jr3WZm1PbGobgPDHzLz9LEFDaco1V&inFormat=kvp&outFormat=json&location=3403+Kildare+Ave&thumbMaps=false&delimiter=%2C'))

但是我们有很多地址,所以我们将使用一个循环来重复调用 API。

让我们看看结果是什么样的:

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

截图来自edn alin c . De Dios

最后,让我们创建一个包含街道地址的数据帧——包括邮政编码、纬度和经度。

瞧啊。我们有自己的地理数据。

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

截图来自edn alin c . De Dios

为了额外加分,让我们将数据导入 Tableau 并获得一个漂亮的视觉效果:

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

截图来自edn alin c . De Dios

就这样,伙计们!

你可以在这里找到 jupyter 笔记本。

谢谢你过来看我的帖子。希望对你有用:-)

如果你想了解更多关于我从懒鬼到数据科学家的旅程,请查看下面的文章:

如果你正在考虑改变方向,进入数据科学领域,现在就开始考虑重塑品牌:

敬请期待!

你可以通过 TwitterLinkedIn 联系我。

运用数学思维寻找完美公寓

原文:https://towardsdatascience.com/using-mathematical-thinking-to-find-the-perfect-apartment-e421c6e621fb?source=collection_archive---------8-----------------------

面对铺天盖地的选择,我用数学思维来增强我的决策能力,并在一周内找到了完美的公寓。

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

照片由 PexelsChait Goli 拍摄

经过几个月紧张的面试,我在一家令人兴奋的公司获得了一个优秀的数据科学职位。2020 年,我回到学校攻读数据科学硕士学位,并准备安顿下来,现在我正在寻找一个令人敬畏的公寓。为了帮助我在最短的时间内找到最好的地方,我为我要看的公寓创建了一个简洁的测量工具,然后计划用它来找到最好的一个。此外,作为一个数据呆子,我做了一点额外的分析只是为了好玩。运用这种方法的很多灵感来自于阅读《思考,快与慢》,并试图在我的思考中避免走捷径。本文中使用的所有数据都来自我在查看每套公寓时进行的一项简短调查。

这篇短文介绍了一种将数据带入决策过程的简单方法,希望这里的想法对你更有用,而不只是在你下次必须做出重大决定时列出利弊清单。它没有描述一种寻找完美地点的复杂方法,但强调了一种为原本可能是情绪主导的决定增加定量思考的方式。它还展示了如何使用数据科学工具包中的两个工具来可视化自己收集的数据,以解决他们自己的个人问题。

如何比较属性?

一开始,我想知道房地产对我来说有哪些重要特征。考虑到这一点,并考虑到我看到的第一批房产后的轻微调整,我决定列出对我来说最重要的九个因素。然后,我通过一项调查,从 1 到 10 对每个特征进行评分。值得注意的是,并不是所有的功能都是平等的。我需要将它们分为“保健”因素和“激励因素”。这种思维方式基于工业心理学中的一种理论,叫做“双因素理论”。要点是,在卫生项目上得分很低可能会对我的日常生活产生更大的负面影响,而在激励因素上得分较高则不会产生明显的影响。我也倾向于从公寓广告中了解公寓的激励因素,所以它们的变化小于卫生因素,而卫生因素只有在我看公寓时才能观察到。我用字母(H)表示健康因素,用字母(M)表示激励因素

  • 负担能力(百万)
  • 停车(H)
  • 安全(H)
  • 安静(H)
  • 尺寸(米)
  • 街区(H)
  • 面积(H)
  • 美学(M)
  • 视图(M)

现在,这里有一些事情需要考虑。很多这些都是主观的衡量,例如,“美学”或“观点”,然而这些东西对我来说非常重要,我需要一些方法来比较这些属性。其次,这些数据中的一部分可能是通过更复杂的手段收集的。例如,“安全”可能包含该区域的犯罪统计数据,以及一些与安全警卫和安全级别(如围栏)相关的分类变量。我不认为这种详细程度对于帮助我做出更好的决策是必要的——将它添加到模型中的 ROI 会非常低。最后,在计算每套公寓的得分时,我将卫生因素的权重定为 2,将激励因素的权重定为 1,因为它们对我认为它们会带来的幸福水平的影响是不平衡的。

使用可靠的旧谷歌表,我把一组简单的加权分数放在一起,取平均值。对我来说有趣的是,我真的被困在 H. Park (G)和 HL (GP)公寓之间,但结果显然倾向于 H. Park。我设法在最后一分钟多看了一次,FH (G)显然是赢家,也是我最终选择的。

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

每个公寓的每个特征的分数,其中每个特征被从 1 到 10 评级,然后乘以其相关的卫生或激励因素权重;作者图片

变得更专业一点

作为一个书呆子,数据科学家,我决定看看数据中的两件事。首先,我对不同因素之间的相关性感兴趣。这里有一个非常基础的笔记本,如果你想亲自查看或使用代码,你可以去看看。

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

特征相关矩阵;作者图片

不出所料,负担能力与其他一切都呈负相关;花更多的钱可以买到更好的公寓。最好的公寓楼有最差的停车位。更好的地区也往往更吵,有更小的公寓,也更安全——尽管肯定更贵。停车似乎也与良好的视野负相关。

我还想对数据进行一点主成分分析,看看公寓是否自然地聚集在一起。我没有得到我期望看到的结果,然而有趣的是,通常得分低(平均)的公寓在图表的底部。鉴于我对公寓的记忆,我不认为它们能在这个二维空间中形成有意义的集群。然而,看看非线性降维方法会产生什么是有趣的。

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

公寓的主要组成部分;作者图片

我通过查看因子权重进一步研究了 PCA 的减少情况。显而易见,安全性和面积高度相关。就公寓的定位而言,图表下半部分的街区更实惠,但在其他功能上的权重较低;考虑到上面的相关图,这并不奇怪。

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

主成分和因子权重;作者图片

这里值得注意的是,我故意没有缩放数据,尽管我确实把它放在了中间。我没有对数据进行缩放,因为保健和激励变量的缩放差异很大,我不想从数据中删除这种差异。

结论

这项研究最有价值的方面是,它有助于用数字显示我特别感兴趣的公寓之间的差异,并有助于决策过程。对我来说,能够运用一种定量的方法来解决一个主要由直觉驱动的问题也很有趣。有趣的是,一些我在看过之后不会真正考虑的公寓实际上得分并不太差,但仍然不在得分的前一半。我认为可以对流程进行更多的改进,但我认为这是一个迭代过程,我将来肯定会对我做出的决策应用类似的方法。

使用 MATLAB 的深度学习工具箱|第 2 部分

原文:https://towardsdatascience.com/using-matlabs-deep-learning-toolbox-part-2-b461d7457eb5?source=collection_archive---------16-----------------------

使用乳腺癌成像数据训练深度前馈神经网络

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

艾莉娜·格鲁布尼亚克在 Unsplash 上的照片

概述

在这个 3 篇文章系列的第一部分中,我们介绍了 MATLAB 的深度学习工具箱 (DLT),用于训练关于乳腺癌恶性肿瘤数据的浅层神经网络分类器。

如果您想回顾第 1 部分,这里有该文章的链接:

在本文中,我们将在 MATLAB 内置的同一个乳腺癌威斯康星州(诊断)数据集上训练一个深度前馈神经网络。

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

照片由凯蒂·罗德里格斯Unsplash 上拍摄

为什么要用 MATLAB 和深度学习工具箱?

MATLAB 不会付钱让我(叫我 MathWorks)去检查他们的工具箱。但是,我认为更多的初学者应该使用 MATLAB 入门深度学习的原因并不是最终构建一个将要大规模部署的 AI 应用。

相反,这篇文章旨在展示训练神经网络所必需的一些实际考虑,而不会陷入每个组件的细节

通过这种方式,我的希望是在你的人工智能项目中快速起步并边走边学。

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

弗兰基·查马基在 Unsplash 上拍摄的照片

如果你想知道为什么我认为 MATLAB 是从非编程背景开始学习数据科学的编程语言,你可以阅读我写的这篇文章:

[## 为什么我选择 MATLAB 学习数据科学

towardsdatascience.com](/why-i-chose-matlab-for-learning-data-science-4f5e4650dce9)

乳腺癌数据集的描述

首先,我将简要描述数据集,它是从 699 个活检中获得的。 cancerInputs 变量中的每个特征描述了细胞属性(粘附、大小、形状)。

cancerTargets 变量被编码成 0 和 1,描述细胞是良性的(0)还是恶性的(1)。我们需要确保输出的数据类型是分类变量。

与浅层神经网络函数相比,没有内置的方法可以自动将数据分为训练集、测试集和验证集,MATLAB 也没有自动完成这一任务的函数。

我写了一个模仿 scikit-learn 的train _ test _ split**()**函数的函数,叫它……嗯,trainttestsplit()。该功能概述如下:

我们将首先使用这个**trainttestsplit()**函数分割训练和测试数据。

注意特征应横跨行,样本应横跨列。此外,数据类型需要转换为分类类型。最后,对于我们的二元分类任务,我们将只使用其中一个目标标签。

设置网络架构

我们将使用以下神经网络架构训练一个 5 层深度前馈神经网络:

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

我们将要训练的 5 层神经网络结构的示意图。请注意,输出图层是一个包含布尔值的单一矢量,表示我们预测的两种癌症状态(良性/恶性)。这个塑像是由斯科特·坎皮特设计的。

与我们的浅层神经网络分类器相比,我们需要在该网络架构中指定 4 个组件,如下所述:

  1. **输入数据层:**在输入数据集中调用管道的函数因输入的数据类型(如 2D 数值、张量等)而异。).对于我们的数据集,需要使用 sequenceInputLayer() 函数,需要将要素的数量作为参数。
  2. 隐层:设计一个全连接的前馈神经网络,我们需要调用 fullyConnectedLayer() 函数,该函数需要将激活节点数作为第一个参数。 WeightsInitializer()BiasInitializer() 参数解释了如何初始化权重和偏差参数。在下面的代码中,我们指定使用正态分布的小随机数来打破对称。
  3. **激活函数:**每个隐藏层之间是激活函数。虽然我们可以使用交叉熵层进行二元分类,但是我们也可以使用 softmaxLayer() 函数,该函数可以推广到多类分类问题。
  4. 分类层😗*分类层()**将概率解码成它们预测的标签。

我们将这些组件存储到变量中:

对于 MATLAB 中可用的不同层对象的描述,您可以查看文档

网络架构的健全性检查和调试

从这里,我们应该停下来,看看我们是否有正确的架构,以及是否有任何潜在的警告或问题会导致培训阶段失败。

我们可以使用analyze network**()**函数,该函数接受我们刚刚设置的 layers 变量并可视化网络架构。

该函数输出一个表格,显示我们刚刚指定的层的概要以及网络中的参数数量。

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

analyzeNetwork()函数的汇总表,显示了层类型、每层中的节点数量以及模型正在学习的参数数量。

指定训练和超参数

接下来,我们必须指定模型超参数。 训练选项 () 函数创建一个模型对象,让您将超参数输入神经网络函数。

我们将使用的具体参数如下所示。

用于模型训练的附加超参数选项可在这里找到。

训练 DNN

最后,让我们使用train network**()**函数来训练神经网络,该函数允许我们训练其他深度神经网络架构。

有关使用此功能训练的其他神经网络的更多信息,您可以阅读文档

该函数还输出一个图形,显示模型实时训练时的精度和成本曲线。该图如下所示。

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

trainNetwork()函数输出的训练记录。该图显示了作为时期函数的精确度(顶部)和成本(底部)曲线。这个图形用户界面在模型训练期间弹出。

从该图中可以得出的主要结论是,成本在 200 个历元时收敛到最小值。如果我们增加历元的数量,有证据表明模型开始过度拟合。

用深度神经网络做预测

为了使用深度神经网络模型进行预测,我们可以使用内置的classify**()**函数,该函数返回给定验证集的目标标签。

针对浅层神经网络的基准模型结果

在第 1 部分中,我们训练了一个浅层神经网络,并根据验证集评估了它的性能。

让我们通过并排绘制混淆矩阵来看看我们更深层次的神经网络是否比浅层次的更好。

在 MATLAB 中生成混淆矩阵的代码如下所示:

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

将浅层神经网络(准确率:96.7%)与 5 层神经网络(准确率:97.3%)进行基准测试。

5 层神经网络稍微增加了我们的乳腺癌分类任务的准确性。

在这种情况下,我们正在观察深度神经网络的一个普遍趋势:增加神经网络的深度和节点数量往往会提高精度。

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

粘土堤Unsplash 上拍照

超参数调优呢?

MATLAB 中有对深度神经网络进行贝叶斯超参数整定的方法。然而,这个过程更复杂,将在以后的文章中更深入地讨论。

摘要

我们将深度前馈神经网络添加到我们的深度学习工具中,并发现它提高了我们对患者是否患有良性或恶性肿瘤进行分类的能力。

但是,您可能已经注意到,我们一直在使用数值数据对肿瘤成像数据进行分类。如果我们想使用原始图像本身呢?

在下一篇文章中,我们将在图像上训练一个卷积神经网络来预测肿瘤致病性。

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

克里斯汀·休姆在 Unsplash 上拍摄的照片

我们谈谈吧!

如果你想分享你是如何在你的项目中实现深度神经网络的,或者只是想打个招呼,请在下面的评论中留下你的回复。

此外,请随时通过 LinkedIn联系我——我很乐意与你联系并讨论所有书呆子的事情!

使用微服务构建和扩展数据功能

原文:https://towardsdatascience.com/using-microservices-to-build-and-scale-data-functions-28d47f400419?source=collection_archive---------13-----------------------

行业笔记

微服务是我构建灵活有效的数据功能的首选框架。以下是我学到的方法和内容。

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

来源:Unsplash,照片由米赛尔·莫雷诺拍摄

数据团队是一个专业的业务职能部门,在决策中利用数据和见解。

在我的职业生涯中,到目前为止,我已经建立了两个数据团队。首先是在 Instagram 上建立决策科学功能。这是一个职责广泛的重要角色。我们支持世界各地的业务团队。我们实施了一系列工具,如仪表盘和机器学习程序。我们还支持预算规划,为全球战略提供信息,并提出产品建议。

现在,我回到 fin-tech 初创公司spacex建立数据和分析业务。两家截然不同的公司,两种截然不同的资源。

在这两个例子中,我发现使用微服务架构作为我的框架来编写数据功能计划和扩展团队是成功的。

我想分享一下我是如何在构建数据团队中部署微服务方法的,以及在此过程中的一些收获。

微服务架构快速介绍

如果你已经知道这个东西,请跳过它。

微服务架构是一种应用于服务或应用的架构以及代码编写的方法。

微服务架构背后的基本前提是——将大型复杂的业务问题(如应用程序或服务)分解成较小的、很大程度上独立的组件。

这些组件通过共享功能**“松散耦合”在一起**,例如表格、定义或公式。但是,在大多数情况下,组件是独立运行的。这意味着一个组件的问题或中断不会影响其他组件,一个小问题也不会影响整个服务。

这与整体架构正好相反,在整体架构中,所有的东西都在一个地方并且相互关联。相反,微服务是独立的,但仍然一起工作来完成相同的任务。例如,在线商店搜索栏可能是一个组件,而“由他人推荐”可能是另一个组件。

关于微服务架构的更多信息,我发现这个来自软件服务公司 Red Hat 的概述很容易理解。

循序渐进的方法

这些是我根据微服务方法创建数据功能计划和策略时遵循的主要步骤。

第一步——了解业务。

我从深入了解业务开始。

我试图理解广泛的商业动态,商业和产品的经济学。

我观察了广泛的用户行为和用户旅程,从认知到获得再到使用再到流失的漏斗(有漏斗吗?)以及更广泛的市场动态(竞争对手、市场变化、人口采用等)。

这些见解是我接下来工作的基础。

第 2 步—概述微服务组。

然后我概述了微服务组。这些组将成为单个组件度量和洞察的集合(参见步骤 3)。我将这些组与业务设置紧密关联。

以宇宙飞船为例。我们有一个线性漏斗。人们了解了宇宙飞船。如果他们感兴趣,他们就签约,他们存一些钱用于投资,并通过存款和经常性投资来增加这些钱。最后,一些人关闭了账户。

所以我的微服务团队很简单:

  1. 市场洞察
  2. 收购和增长
  3. 产品使用和参与
  4. 搅拌

第三步——定义组件。

接下来,我概述了新数据功能将在每个微服务组中提供的组件指标,以支持业务领导者。

“市场洞察”组中的示例组件包括:行业趋势、品牌(和竞争对手)认知度、品牌考量、意向和品牌情感。

“获取和增长”微服务组的示例组件包括:归因、归因模型、媒体优化、媒体渠道基准(CPM、CPC 等)和漏斗转换百分比。

你会注意到有很多成分。一些复杂的需要专家工作或建模,一些更简单。因此,每个组件都有自己的开发计划和改进清单。

步骤 4——定义共享工具。

快速回顾—此时,我列出了我的微服务组和组件。接下来,我概述了许多组件会使用的共享工具。定义这些共享工具有助于减少工作量,简化 SQL 代码并防止数据管道重复。他们还帮助企业中的每个人分享对某些指标和数据类别的共同理解。

共享数据工具包括标准化定义、标准化公式和标准化类别。

一些示例包括:客户平衡的标准化范围、年龄范围和性别等关键人口统计标签、增长会计范围、软流失与硬流失的定义以及一些产品级别的定义。

第 5 步——盘点和起草。

此时,我已经为我的新数据功能建立了微服务组、组件指标和共享工具/功能。

接下来,我对我的微服务进行了盘点,以查看已经可用的微服务,并为每个组件起草了开发步骤。

具体来说,我在看:

  • 我可以重新利用企业中其他地方的资源,
  • 每个组件所需的开发和改进水平,
  • 眼前的业务优先级(确定交付什么组件和优先级顺序)

例如,在 Spaceship,表格中已经有了“参与”客户的定义。但是客户流失的定义不可用。所以客户流失的定义是我们建立的。

在 Instagram,人口分组和细分工作已经完成,并由中央数据科学团队提供。所以我们不需要建造这些。但是本地化分析不可用,所以这是我们建立的东西。

第六步——敲定计划。

在流程的这一点上,我有了我的微服务组、组件指标、共享工具,以及对业务和开发步骤中已经可用的东西的理解。

我收集了所有这些信息,并最终确定了我的发展计划。

我用两张幻灯片写了这个计划。一张幻灯片显示了微服务组、组件和组件进度。第二张幻灯片显示了 1 年、2 年和 3 年的计划进度,突出了将通过数据团队交付给企业的广泛关注领域和数据功能。

以下是我总结计划的一个例子:

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

作者提供的图片—仅作为示例

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

作者提供的图片—仅作为示例

注意——这些幻灯片仅供说明之用,已经过编辑,删除了敏感信息,并经过简化以适应本媒体。

除了上面显示的这些概述幻灯片之外,该计划还得到包含更多详细信息的项目管理表、用于管理“待办事项”列表项目进度和人员/角色规划的 JIRA 委员会的支持。

第七步——回顾、重复、改进、再回顾。

接下来,我制定了一个时间表,每半年回顾一次计划。当业务发生重大变化时,我还会审查该计划。在评估过程中,我重点关注:

  • 需要升级的组件,因为工作已经完成,组件已准备好进入下一阶段。
  • 本可以更高效的组件或增长过大的组件需要拆分成新的组件。
  • 我的数据功能不再需要或不再需要支持的组件或微服务。

我还利用评审时间向业务部门展示更新的计划,并提醒领导层计划和交付时间表。

使用微服务架构构建数据团队的优势

乍一看,可能很容易将微服务的前提过于简单化。“只是把东西分解成小块?就这样?”但是事情远不止如此。

对数据功能采用微服务方法带来了许多好处,我总结如下:

  1. 结构化、层次化的思维方法——从业务理解到微服务组再到组件指标——让整个功能构建过程感觉可管理、结构化且清晰
  2. 事实上,每个组件、每个开发步骤和每个微服务组都与一个业务功能联系在一起,这意味着这些计划得到了整个业务的广泛支持,并被广泛理解。每个业务领导都可以看到他们将获得的具体指标以及如何使用每个指标。
  3. 在业务中寻找共享的定义和共享的工具(比如公式)确保了数据功能不会重复工作,并且工作与业务中的其他领域保持一致。
  4. 微服务方法鼓励交付思维*——也就是说,它鼓励向业务交付组件指标,逐步向业务领导推出工具和见解,并关注持续的指标改进以支持业务。*
  5. 与此相关的是,它为每个组件和每个微服务组提供了一种勾勒清晰开发计划的方式。从那时起,这就是一个简单地执行计划并推动每个团队改进的案例。
  6. 微服务范围带来了独立的数据管道、特定于组的代码库、独特的表格和专用的仪表板,从而提高了商业智能的连续性,更快地发现故障和问题,确保表格故障仅影响一小部分组件,并加快了开发速度。
  7. 最后,我发现微服务方法非常灵活,并成功地将其用于较小规模的项目(如活动测量),直到构建本文中概述的完整数据团队。

考虑到工作的艰巨性,两次建立数据函数的任务既令人畏惧又令人兴奋。然而,我发现使用微服务方法有很多好处。

微服务架构帮助我组织工作,使任务变得非常容易管理。它给了我一个灵活的框架,一个集中我的计划的方法和一个建立有效数据功能的过程。

我鼓励任何管理复杂数据项目或组建数据团队的人将微服务概念视为潜在的辅助手段。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值