TowardsDataScience-博客中文翻译-2021-五十二-

TowardsDataScience 博客中文翻译 2021(五十二)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

如何使用带 spaCy 3 的 BERT 变换器训练联合实体和关系提取分类器

原文:https://towardsdatascience.com/how-to-train-a-joint-entities-and-relation-extraction-classifier-using-bert-transformer-with-spacy-49eb08d91b5c?source=collection_archive---------2-----------------------

如何使用 Transformer 和 spaCy3 训练关系提取分类器的分步指南

照片由 JJ 英Unsplash

简介

NLP 技术最有用的应用之一是从非结构化文本中提取信息,如合同、财务文档、医疗记录等。—使自动数据查询能够获得新的见解。传统上,命名实体识别被广泛用于识别文本中的实体,并存储数据以进行高级查询和过滤。然而,如果我们想从语义上理解非结构化的文本,仅仅 NER 是不够的,因为我们不知道实体是如何相互关联的。执行联合 NER 和关系提取将通过知识图开辟一种全新的信息检索方式,在知识图中,您可以浏览不同的节点以发现隐藏的关系。因此,联合执行这些任务将是有益的。

在我的上一篇文章中,我们使用 spaCy3 对 NER 的 BERT 模型进行了微调,现在我们将使用 spaCy 的新 Thinc 库向管道添加关系提取。我们按照 spaCy 的文档中概述的步骤训练关系提取模型。我们将比较使用 transformers 和 tok2vec 算法的关系分类器的性能。最后,我们将在网上找到的职位描述上测试该模型。

关系分类:

在其核心,关系提取模型是一个分类器,它为给定的实体对 {e1,e2} 预测关系 r 。在变压器的情况下,该分类器被添加到输出隐藏状态的顶部。有关关系提取的更多信息,请阅读这篇出色的文章概述了关系分类的微调变压器模型的理论。

我们要微调的预训练模型是 roberta-base 模型,但是您可以使用 huggingface 库中可用的任何预训练模型,只需在配置文件中输入名称即可(见下文)。

在本教程中,我们将提取两个实体{经验,技能}之间的关系作为中的经验,以及{文凭,文凭 _ 专业}之间的关系作为中的学位。目标是提取特定技能和与所需文凭相关的文凭专业所需的经验年限。当然,您可以为自己的用例训练自己的关系分类器,例如在健康记录中查找症状的原因/结果,或者在财务文档中查找公司收购。可能性是无限的…

在本教程中,我们将只涵盖实体关系提取部分。对于使用 spaCy 3 微调伯特 NER,请参考我的以前的文章

数据标注:

正如在我的上一篇文章中,我们使用 UBIAI 文本注释工具来执行联合实体和关系注释,因为它的通用接口允许我们在实体和关系注释之间轻松切换(见下文):

UBIAI 的联合实体和关系注释接口

对于本教程,我只注释了大约 100 个包含实体和关系的文档。对于生产,我们当然需要更多的带注释的数据。

数据准备:

在训练模型之前,我们需要将带注释的数据转换成二进制空间文件。我们首先将 UBIAI 生成的注释拆分到 training/dev/test 中,并分别保存它们。我们修改 spaCy 的教程 repo 中提供的[代码](https://github.com/explosion/projects/blob/v3/tutorials/rel_component/scripts/parse_data.py),为我们自己的注释创建二进制文件(转换代码)。

我们对训练、开发和测试数据集重复这一步骤,以生成三个二进制空间文件(github 中提供的文件)。

关系抽取模型训练:

为了训练,我们将从我们的黄金语料库中提供实体,并在这些实体上训练分类器。

  • 打开一个新的 Google Colab 项目,确保在笔记本设置中选择 GPU 作为硬件加速器。确保通过运行以下命令启用 GPU:!英伟达-smi
  • 每晚安装空间:
!pip install -U spacy-nightly --pre
  • 安装轮包并克隆空间的关系提取报告:
!pip install -U pip setuptools wheel
!python -m spacy project clone tutorials/rel_component
  • 安装变压器管道和空间变压器库:
!python -m spacy download en_core_web_trf
!pip install -U spacy transformers
  • 将目录更改为 rel_component 文件夹:cd rel_component
  • 在 rel_component 中创建一个名为“data”的文件夹,并将培训、开发和测试二进制文件上传到其中:

培训文件夹

  • 打开 project.yml 文件并更新培训、开发和测试路径:
train_file: "data/relations_training.spacy"dev_file: "data/relations_dev.spacy"test_file: "data/relations_test.spacy"
  • 您可以通过转到 configs/rel_trf.cfg 并输入模型的名称来更改预训练的转换器模型(例如,如果您想要使用不同的语言):
[components.transformer.model]@architectures = "spacy-transformers.TransformerModel.v1"name = "roberta-base" # Transformer model from huggingfacetokenizer_config = {"use_fast": true}
  • 在开始训练之前,我们将把 configs/rel_trf.cfg 中的 max_length 从默认的 100 令牌减少到 20,以提高模型的效率。max_length 对应于两个实体之间的最大距离,超过该距离的实体将不被考虑进行关系分类。结果,来自同一文档的两个实体将被分类,只要它们在彼此的最大距离(在标记数量上)内。
[components.relation_extractor.model.create_instance_tensor.get_instances]@misc = "rel_instance_generator.v1"max_length = 20
  • 我们最终准备好训练和评估关系提取模型;只需运行以下命令:
!spacy project run train_gpu # command to train train transformers
!spacy project run evaluate # command to evaluate on test dataset

您应该开始看到 P、R 和 F 分数开始更新:

模型培训正在进行中

模型完成训练后,对测试数据集的评估将立即开始,并显示预测与黄金标签。该模型将与我们模型的分数一起保存在名为“training”的文件夹中。

要训练非变压器模型 tok2vec,请改为运行以下命令:

!spacy project run train_cpu # command to train train tok2vec
!spacy project run evaluate

我们可以比较这两种模型的性能:

# Transformer model
"performance":{"rel_micro_p":0.8476190476,"rel_micro_r":0.9468085106,"rel_micro_f":0.8944723618,}
# Tok2vec model
  "performance":{"rel_micro_p":0.8604651163,"rel_micro_r":0.7872340426,"rel_micro_f":0.8222222222,}

基于 transformer 的模型的精度和召回分数明显优于 tok2vec,并证明了 transformer 在处理少量注释数据时的有效性。

联合实体和关系提取管道:

假设我们已经在我的上一篇文章中训练了一个 transformer NER 模型,我们将从网上找到的工作描述中提取实体(这不是训练的一部分,也不是开发集的一部分),并将它们提供给关系提取模型以对关系进行分类。

  • 安装空间变压器和变压器管道
  • 加载 NER 模型并提取实体:
import spacynlp = spacy.load("NER Model Repo/model-best")Text=['''2+ years of non-internship professional software development experience
Programming experience with at least one modern language such as Java, C++, or C# including object-oriented design.1+ years of experience contributing to the architecture and design (architecture, design patterns, reliability and scaling) of new and current systems.Bachelor / MS Degree in Computer Science. Preferably a PhD in data science.8+ years of professional experience in software development. 2+ years of experience in project management.Experience in mentoring junior software engineers to improve their skills, and make them more effective, product software engineers.Experience in data structures, algorithm design, complexity analysis, object-oriented design.3+ years experience in at least one modern programming language such as Java, Scala, Python, C++, C#Experience in professional software engineering practices & best practices for the full software development life cycle, including coding standards, code reviews, source control management, build processes, testing, and operationsExperience in communicating with users, other technical teams, and management to collect requirements, describe software product features, and technical designs.Experience with building complex software systems that have been successfully delivered to customersProven ability to take a project from scoping requirements through actual launch of the project, with experience in the subsequent operation of the system in production''']for doc in nlp.pipe(text, disable=["tagger"]): print(f"spans: {[(e.start, e.text, e.label_) for e in doc.ents]}")
  • 我们打印提取的实体:
spans: [(0, '2+ years', 'EXPERIENCE'), (7, 'professional software development', 'SKILLS'), (12, 'Programming', 'SKILLS'), (22, 'Java', 'SKILLS'), (24, 'C++', 'SKILLS'), (27, 'C#', 'SKILLS'), (30, 'object-oriented design', 'SKILLS'), (36, '1+ years', 'EXPERIENCE'), (41, 'contributing to the', 'SKILLS'), (46, 'design', 'SKILLS'), (48, 'architecture', 'SKILLS'), (50, 'design patterns', 'SKILLS'), (55, 'scaling', 'SKILLS'), (60, 'current systems', 'SKILLS'), (64, 'Bachelor', 'DIPLOMA'), (68, 'Computer Science', 'DIPLOMA_MAJOR'), (75, '8+ years', 'EXPERIENCE'), (82, 'software development', 'SKILLS'), (88, 'mentoring junior software engineers', 'SKILLS'), (103, 'product software engineers', 'SKILLS'), (110, 'data structures', 'SKILLS'), (113, 'algorithm design', 'SKILLS'), (116, 'complexity analysis', 'SKILLS'), (119, 'object-oriented design', 'SKILLS'), (135, 'Java', 'SKILLS'), (137, 'Scala', 'SKILLS'), (139, 'Python', 'SKILLS'), (141, 'C++', 'SKILLS'), (143, 'C#', 'SKILLS'), (148, 'professional software engineering', 'SKILLS'), (151, 'practices', 'SKILLS'), (153, 'best practices', 'SKILLS'), (158, 'software development', 'SKILLS'), (164, 'coding', 'SKILLS'), (167, 'code reviews', 'SKILLS'), (170, 'source control management', 'SKILLS'), (174, 'build processes', 'SKILLS'), (177, 'testing', 'SKILLS'), (180, 'operations', 'SKILLS'), (184, 'communicating', 'SKILLS'), (193, 'management', 'SKILLS'), (199, 'software product', 'SKILLS'), (204, 'technical designs', 'SKILLS'), (210, 'building complex software systems', 'SKILLS'), (229, 'scoping requirements', 'SKILLS')]

我们已经成功地从文本中提取了所有的技能、工作年限、文凭和文凭专业!接下来,我们加载关系提取模型,并对实体之间的关系进行分类。

注意:确保将 rel_pipe 和 rel_model 从脚本文件夹复制到主文件夹中:

脚本文件夹

import randomimport typerfrom pathlib import Pathimport spacyfrom spacy.tokens import DocBin, Docfrom spacy.training.example import Examplefrom rel_pipe import make_relation_extractor, score_relationsfrom rel_model import create_relation_model, create_classification_layer, create_instances, create_tensors# We load the relation extraction (REL) modelnlp2 = spacy.load("training/model-best")# We take the entities generated from the NER pipeline and input them to the REL pipelinefor name, proc in nlp2.pipeline:
          doc = proc(doc)# Here, we split the paragraph into sentences and apply the relation extraction for each pair of entities found in each sentence.for value, rel_dict in doc._.rel.items():
        for sent in doc.sents:
          for e in sent.ents:
            for b in sent.ents:
              if e.start == value[0] and b.start == value[1]:
                if rel_dict['EXPERIENCE_IN'] >=0.9 :
                  print(f" entities: {e.text, b.text} --> predicted relation: {rel_dict}")

在这里,我们显示了所有具有关系 Experience_in 且置信度得分高于 90%的实体:

"entities":("2+ years", "professional software development"") --> **predicted relation**":
{"DEGREE_IN":1.2778723e-07,"EXPERIENCE_IN":0.9694631}"entities":"(""1+ years", "contributing to the"") -->
**predicted relation**":
{"DEGREE_IN":1.4581254e-07,"EXPERIENCE_IN":0.9205434}"entities":"(""1+ years","design"") --> 
**predicted relation**":
{"DEGREE_IN":1.8895419e-07,"EXPERIENCE_IN":0.94121873}"entities":"(""1+ years","architecture"") --> 
**predicted relation**":
{"DEGREE_IN":1.9635708e-07,"EXPERIENCE_IN":0.9399484}"entities":"(""1+ years","design patterns"") --> 
**predicted relation**":
{"DEGREE_IN":1.9823732e-07,"EXPERIENCE_IN":0.9423302}"entities":"(""1+ years", "scaling"") --> 
**predicted relation**":
{"DEGREE_IN":1.892173e-07,"EXPERIENCE_IN":0.96628445}entities: ('2+ years', 'project management') --> 
**predicted relation**:
{'DEGREE_IN': 5.175297e-07, 'EXPERIENCE_IN': 0.9911635}"entities":"(""8+ years","software development"") -->
**predicted relation**":
{"DEGREE_IN":4.914319e-08,"EXPERIENCE_IN":0.994812}"entities":"(""3+ years","Java"") -->
**predicted relation**":
{"DEGREE_IN":9.288566e-08,"EXPERIENCE_IN":0.99975795}"entities":"(""3+ years","Scala"") --> 
**predicted relation**":
{"DEGREE_IN":2.8477e-07,"EXPERIENCE_IN":0.99982494}"entities":"(""3+ years","Python"") -->
**predicted relation**":
{"DEGREE_IN":3.3149718e-07,"EXPERIENCE_IN":0.9998517}"entities":"(""3+ years","C++"") -->
**predicted relation**":
{"DEGREE_IN":2.2569053e-07,"EXPERIENCE_IN":0.99986637}

值得注意的是,我们能够正确地提取几乎所有年的经验以及他们各自的技能,而没有假阳性或假阴性!

让我们看看具有关系 Degree_in: 的实体

entities: ('Bachelor / MS', 'Computer Science') -->
predicted relation: 
{'DEGREE_IN': 0.9943974, 'EXPERIENCE_IN':1.8361954e-09} entities: ('PhD', 'data science') --> predicted relation: {'DEGREE_IN': 0.98883855, 'EXPERIENCE_IN': 5.2092592e-09}

再次,我们成功提取了文凭和文凭专业的所有关系!

这再次证明了,无论是对于 NER 还是关系提取,使用少量的注释数据就可以很容易地将 transformer 模型调整到您自己的领域特定情况。

只有一百个带注释的文档,我们能够训练一个性能良好的关系分类器。此外,我们可以使用这个初始模型来自动注释数百个未标记的数据,并进行最小的校正。这可以显著加快标注过程并提高模型性能。

结论:

变形金刚真正改变了自然语言处理的领域,我对它们在信息提取方面的应用感到特别兴奋。我想对 explosion AI(spaCy developers)和 huggingface 提供开源解决方案以促进变压器的采用表示感谢。

如果您的项目需要数据注释,请不要犹豫尝试 UBIAI 注释工具。我们提供了许多可编程的标注解决方案(如 ML 自动标注、正则表达式、字典等),以最大限度地减少手工标注。

最后,查看这篇文章,了解如何利用 NER 和关系提取模型来构建知识图表并提取新的见解。

如果您有任何意见,请在下方留言或发送电子邮件至 admin@ubiai.tools!

在 Twitter 上关注我们

如何使用 Google BigQuery ML 训练一个模型来预测第二天的降雨

原文:https://towardsdatascience.com/how-to-train-a-model-to-predict-next-day-rain-with-google-bigquery-ml-d2231c05dcd8?source=collection_archive---------46-----------------------

用大家都非常熟悉的 SQL 语法预测未来,速度快得惊人,而且简单。

照片由 安娜·阿特金斯Unsplash

预计会下雨。只有两个简单的词,但有时赌注可能比明天出门前拿一把伞要高得多。雨水可能会破坏野餐计划,也可能会给急于拯救遭受旱灾的农作物的农民带来巨大的快乐。

学习如何预测第二天的降雨是用 Google BigQuery 探索机器学习的一种简单实用的方法。所以,让我们来看看如何让它发生。

在这篇文章中,你会发现:

  1. 为什么机器学习要用 BigQuery ML?
  2. 如何将数据集摄取并拆分成训练集和测试集?
  3. 如何训练和评估一个分类模型?
  4. 如何预测第二天的降雨?

为什么机器学习要用 BigQuery ML?

想象一下,作为一名生活在 SQL 中的数据分析师,您了解 BigQuery 数据仓库中存储了哪些数据。你可能最近学习了一些关于机器学习的基础知识,但绝不是一个可以闭着眼睛写 Python 代码的狂热的 ML 专家。

然而,你想要用 BigQuery 数据集建立一个机器学习模型,来预测某些可能对你的业务有价值的行为。你需要尽快得到它,因为在商界,时间不等人。

如果你不太了解复杂的 ML 框架,比如 TensorFlow 或 Keras,你应该如何在短时间内实现它呢?在不疯狂使用 Python 或 Java 编程的情况下,如何编写完整的 ML 解决方案呢?

这也是 BigQuery ML 真正能够大放异彩的地方。简而言之,它允许你使用标准的 SQL 查询在 BigQuery 中创建和训练机器学习模型。这种方法有 3 个主要好处。

  • 你不需要花费太多的时间去尝试用各种各样的新工具从你的 BigQuery 数据仓库中导出数据
  • 如果有法律限制或合规性要求严格控制如何导出数据并将其转移到进行分析和机器学习,您就不必寻求大量批准(当然,遵守访问控制政策和常识在这里仍然适用。)
  • 你不需要把自己逼疯去用 Python/ Java 创建一个 ML 解决方案,也不需要加入长长的等待名单去麻烦别人(甚至整个团队)来帮你。

那么,这对企业到底意味着什么呢?这意味着一种更简单、更快速的方式来利用机器学习来预测未来可能发生的事情,以及企业应该如何应对,以有效抓住机遇或减轻风险。

提醒一句,目前 BigQuery ML on 支持一系列特定的模型。它们包括线性回归、逻辑回归、K 均值聚类、张量流、矩阵分解、XGBoost、深度神经网络和基于 ARIMA 的时间序列模型。

我个人认为可用的选项足以为常见的 ML 用例快速构建基线模型。但是请务必查看 BigQuery 文档以获得最新的产品列表。

开始之前

我们的目标和游戏计划

在进入 BigQuery 之前,这里是我们想要实现的:给定今天关于风向、降雨量、最低温度、最高温度、云量等等的观测数据,我们能预测明天是否会下雨吗?

我们拥有的是一个 Kaggle 数据集,包含了 2007 年至 2017 年间澳大利亚选定地点的 10 年天气观测数据。下面是我们关于如何将数据集转化为分类模型的游戏计划,我们可以用它来预测 2021 年的第二天降雨。

作者图片

诚然,我们正试图创建一个非常简化的降雨预报,它无处不在,以至于人们很容易忽视它的巨大价值:从大量数据中预测未来的能力。但是,不要被它的简单性所迷惑,因为预测能力是唯一重要的东西,而不是花哨的 ML 算法或脑筋急转弯技术!

初始设置

在我们为那些令人兴奋的机器学习的东西疯狂之前,这里有 3 件你需要设置的事情。

  1. 在谷歌云平台上创建一个项目
  2. 在 BigQuery 上创建数据集
  3. 从我的 GitHub 下载以下 2 个 CSV 文件,然后将它们上传到 Google 云存储
  • weatherAUS.csv:可以从 Kaggle 下载。我们用它来训练和测试 ML 模型
  • apr10_predict.csv:可从我的 GitHub &下载,包含 2021 年 4 月 10 日的天气观测。我们用它来预测 4 月 11 日是否会下雨

新项目“澳大利亚铁路”&数据集“降雨预测”已创建(图片由作者提供)

上传到云存储的 2 个 CSV 文件(图片由作者提供)

摄取和分割数据集

摄取数据集

第一步。将云存储中的 2 个 CSV 文件加载到 BigQuery

由于 weatherAUS 数据集将空值写成“NA”字符串,所以我将使用 bq load 命令通过 null_marker 选项直接将“NA”字符串作为空值导入。下面是怎么做的。

在 GCP 控制台上,单击页面顶部的激活云外壳按钮来配置您的 Google 云外壳计算机。给它一分钟左右的加载时间。

作者图片

要加载 weatherAUS 数据集,请输入下面的命令 ,但要记住更新云存储 URI(以 gs://开头,以。因为您的 csv 文件将位于不同的位置

*bq load --autodetect --null_marker="NA" --source_format=CSV rainprediction.weatherAUS gs://australia_rain_input/weatherAUS.csv*

作者图片

当看到要求授权云壳的弹出窗口时,点击授权

作者图片

等到看到当前状态:DONE,然后输入下一个命令来加载 apr10_predict 数据集。 但是也别忘了更新云存储 URI。

*bq load --autodetect --source_format=CSV rainprediction.apr10_predict gs://australia_rain_input/apr10_predict.csv*

看到当前状态:完成此加载作业后,刷新您的浏览器。

作者图片

仔细检查是否可以在 BigQuery 中新创建的数据集下看到两个名为 weatherAUS 和 apr10_predict 的新表。

作者图片

步骤二。查看加载到 BigQuery 中的数据

weatherAUS 表的快速预览显示有 145,460 行数据。标签(即我们试图预测的)是 RainTomorrow,所有其他列是预测器(即我们可能用来预测第二天是否下雨的变量)。

作者图片

不要忘记查看模式来验证数据类型。在 BigQuery ML 中,确保每一列的数据类型正确总是有好处的。

为什么这样因为不同的数据类型会导致非常不同的数据预处理处理,这些处理是由 BigQuery ML 自动执行的。简而言之,混合数据类型可能导致次优的数据处理,最终阻碍 ML 模型的准确性。

作者图片

在我们的例子中,MinTemp、MaxTemp、rainbow、Sunshine 等数值使用字符串类型似乎有点奇怪。请记住这一点,因为我们将在下一节中解决它。

将数据集分成训练集和测试集

接下来,我们将把数据集分成训练集和测试集。

  • 训练集:训练一个分类模型,把给定的天气观测映射到规定的标签(即 RainTomorrow)。
  • 测试集:严格用于评估最大似然模型是否可以用该模型以前没有见过的新数据进行预测

第一步。创建一个假的唯一 ID 列,并更正数值的数据类型

作者图片

第二步。基于伪唯一 ID 列(UUID)分割数据集

为了获得我的训练和测试集的可重复数据采样,我使用了下面由 Christy Bergman 编写的 BigQuery 代码。

训练集(图片由作者提供)

测试集(图片由作者提供)

训练和评估分类模型

使用创建模型训练 ML 模型

训练一个简单的逻辑回归模型

现在最激动人心的部分来了!让我们创建一个逻辑回归模型,这是分类问题的最简单的模型类型。大伙儿,击鼓吧!

作者图片

在 BigQuery 中运行上述语句后,我们将获得第一个分类模型,该模型将天气观测结果映射为明天下雨是或否。哒哒!

作者图片

定制逻辑回归模型

众所周知,许多精明的 ML 工程师在优化他们的模型时喜欢自由选择。但另一方面,如果你是一名 ML 新手或在关键时刻,必须做出如此多的选择(例如,学习速度,如何以及以什么比例将输入数据分成训练集和评估集等等)可能会令人生畏。

幸运的是, BigQuery ML 已经将某些设置作为默认设置。从上面的例子可以看出,不需要处理无数的选择,只需要几行代码就可以相对容易地建立并运行一个像样的 ML 模型。

但是如果我们想要定制某些设置来满足我们的需求呢?让我们尝试定制我们的逻辑回归模型来反映 3 个变化。

  1. 随机抽取 20%的训练数据用于评估(目前 BigQuery ML 仅使用 10,000 行进行评估,因为我们的数据集超过 50,000 行。)
  2. 纠正不平衡的训练数据集(默认选项是不平衡权重。)
  3. 应用 L2 正则化来惩罚复杂性,从而控制过度拟合(默认选项是没有 L2 正则化。)

作者图片

哦,等等!是不是意味着我们可以定制任何东西,任何东西?没有。至少现在不会,但是可以随时查看 BigQuery 文档来了解您不能定制的内容,并尝试您可以定制的内容。

用 ML 评估分类模型。评价

是时候使用测试数据集来验证我们第一个简单的逻辑回归模型的性能了。让我们看看这样一个简单的模型(没有任何花哨的微调)能够用前所未见的新数据预测明天的降雨。

这个查询再简单不过了。

作者图片

由于测试集的 ROC _ AUC(0.878)与训练集的 ROC _ AUC(0.880)几乎相同,因此我们的模型没有过拟合。0.85 的精度看起来也还过得去。当然,可以用转换条款做更多的功能工程来提高 F1_score,但是现在,让我们坚持现有的。

用分类模型预测第二天的降雨

在 apr10_predict 表中,我收集了 2021 年 4 月 10 日澳大利亚几个地方的每日天气观测。接下来,我们将使用逻辑回归模型来预测 2021 年 4 月 11 日是否会下雨。

作者图片

让我解释一下上面的截图是怎么回事。

  1. predicted _ rain tomorrow根据我选择的 0.6 阈值显示 4 月 11 日是否可能下雨。只要“下雨”的概率超过 0.6,模型就会预测第二天“明天下雨”。
  2. 接下来的两列predicted _ rain tomorrow _ probs . labelpredicted _ rain tomorrow _ probs . prob显示了 BigQuery 如何得出预测。在第一行中,模型计算出悉尼“不下雨”的概率是 0.75,而“下雨”的概率只有 0.25。因为“下雨”的概率低于阈值 0.6,所以对第二天下雨的预测是“不”。
  3. 红色的最后一栏是我添加到截图中的,这样你可以很容易地比较预测和 4 月 11 日的实际降雨。这不是模型在执行查询时会给你的。

如果你仍然想知道阈值在分类模型中意味着什么,看看这个简单的解释。但是就预测而言,我们只对达尔文的预测是错误的。我会说这并不坏,因为我们只花很少的时间在 Google BigQuery 中编写简单的查询。

当时间是最重要的,并且您的数据在 BigQuery 中随时可用时,就是这样了——big query ML 是您的最佳选择!

包扎

现在,您可以快速浏览如何训练和评估分类模型,以及如何使用 BigQuery ML 预测第二天的降雨量!BigQuery ML 能否取代其他类似 Tensorflow、Keras 等行业标准的机器学习框架?可能不是因为让 ML 在现实生活中发挥作用是一系列相互竞争的目标之间的权衡,如速度、简单性和准确性。

如果你是一个精明的 ML 工程师,更喜欢大量的自由来试验各种 ML 模型和不同的数据预处理技术,以实现极其精确的预测,你可能最好去别处看看。这是因为 BigQuery ML 目前提供的选择有限,因为它保留了它的简单性和速度。

然而,作为一个欣赏快速测试一个新想法或者创建一个足够好的 ML 基线模型的人,我确实看到了 BigQuery ML 的价值。我不必为尝试从数据仓库导出数据而烦恼,因为我正在 BigQuery(数据仓库本身)中训练和部署 ML 模型。此外,没有必要使用 Python 或 Java 构建一个完整的 ML 管道,因为我可以使用 SQL 用几行代码创建一个模型。有什么不喜欢的?

感谢您的阅读。对我如何能做得更好有反馈,或者只是想聊天?在评论里告诉我或者在 LinkedIn 上找到我。祝大家这周过得愉快!

原载于 2021 年 4 月 12 日 http://thedigitalskye.com*http://thedigitalskye.com/2021/04/13/how-to-train-a-classification-model-to-predict-next-day-rain-with-google-bigquery-ml/。***

如何从零开始训练一个神经网络

原文:https://towardsdatascience.com/how-to-train-a-neural-network-from-scratch-952bbcdae729?source=collection_archive---------31-----------------------

寻找神经网络权重背后的直觉,并附有示例。

在这篇文章中,我将继续我们关于人工神经网络的讨论,并给出一个用 python 编写的非常简单的神经网络的例子。我正在写的这一系列文章的目的是从头开始对 ANN 的作一个完整的解释,而不是躲在特殊的库后面。Tensorflow 非常适合原型制作和生产,但对于教育来说,唯一的学习方法是拿起铅笔和纸,开始学习数学。

在上一篇文章中,我回顾了人工神经网络背后的灵感以及如何对人脑进行数学建模(你可以在这里找到这篇文章)。我们的下一步是为我们的模型找到正确的权重。

将输入映射到输出

假设我们有一个输入和输出的列表。这些可以是任何东西,股票特征和价格,财产特征和销售价格,学生行为和平均考试分数,它们可以是任何东西;但是让我们保持一般的东西,说我们有一些输入和输出。

图片作者

我们的目标是预测最后一次输入的输出。为此,我们必须找到将这些输入映射到其输出的关系(函数)。现在为了学习,我把这个关系做成了线性。这告诉我们可以用身份激活函数代替 sigmoid,而且只有 1 层(输出层)。

如果你看不出为什么一个线性关系只给我们一层具有身份激活功能;请容忍我。在我解释之前,让我给你看一下我们的神经网络,并向你展示它所代表的功能。

注意我们如何通过应用点积来清理事物。它的代码效率也更高。请记住,这个神经网络也会有偏差,我们可以通过手动输入 1 作为输入之一,然后对这个 1 应用一个权重来给出偏差。现在,忽略偏见。*****图片作者***

如果我们有更多的层使用相同的功能,那么我们总是可以简化到上面的方程。自己尝试一下,添加一个中间层,每个中间层有 2 个神经元,每个神经元都有身份激活函数,然后写出对应于网络的方程,并将其简化。

你可以用许多不同的方法很容易地解决这里的重量。毕竟只是一个线性方程组。但是,让我们试着在一般情况下解决这个问题,我们没有线性关系。

用误差函数来衡量我们的错误程度

所以,让我们找点乐子吧。如果不把它看作一个线性方程组,我们怎么能算出重量呢?好吧,你必须从某个地方开始,所以让我们先瞎猜一下它们可能是什么。我猜 W1 = .2,W2 = 1.4,W3 = 30。

现在让我们看看我们的猜测有多好,并在其中一个输入上进行测试(使用上表中的相同数据)。

图片作者

回想一下,根据我们的数据,正确的输出(或预期输出)应该是 13.5;我们太离谱了!让我们用一个误差函数来量化我们到底错了多少。当神经网络输出正确的值时,我们希望误差为 0。先说;误差=正确输出-我们的 ANN 的输出(例如;0 = 13.5–13.5,如果我们的权重正确)。

我们快到了。实际地想,我们的错误是我们想要最小化的。那么,我们当前误差函数的最小值是多少?没有最低!实际上,我们可能会有-∞误差。我们通过对函数求平方来解决这个问题,所以它不能是负的,误差=(正确的输出-我们的人工神经网络的输出)。注意这个误差函数的形状是一个以 0 为中心的抛物线。这是单个输出神经元的误差。如果我们有多个输出,那么我们只取所有输出的平均误差。所以,我们有;

这被称为均方误差函数。这是有 N 个输出的一般情况。总误差是每个输出的平均误差。在我们的例子中,N = 1。*****图片作者***

最小化我们的错误(最小化我们的错误)

当你把一个砝码改变很小的量时(∂W),你会得到一个误差和变化(∂E).)因此,如果我们想知道这个权重的变化对误差的影响有多大,我们可以取 2,∂E/∂W.的比值,这可以看作是误差函数对这个权重的偏导数,或者这个权重的微小变化如何改变误差。

这对我们有什么帮助?好吧,如果你擅长微积分,你可能知道这是什么方向。但是,如果你不是,看看下面的图表。

回想一下,导数只是一个斜率。*****图片作者***

这只是一个任意的函数。取这条线上的任何一点,把你的手指放在上面。现在,大声说出这一点的斜率是正还是负。如果斜率为正,沿+X 方向移动手指一点点。如果是负数,在-X 方向移动它。如果斜率为 0…选择另一个点。为了几个点这样做。注意到什么了吗?

不管怎样,你总是朝着线上更高的值移动手指。

导数的方向总是上升的方向。

如果导数为负,X 的减少将增加 y。如果导数为正,X 的增加将增加 y。

回到我们和∂E/∂W.的神经网络,我们想减少误差,所以我们想把重心移向下降的方向。我们可以通过计算这个导数,然后求负来做到这一点。现在,我们将重心向这个负导数的方向移动一小步。或者;

α确保我们朝着这个方向迈出很小的一步。它被称为学习率,是另一个超参数。图片作者

这只是我们网络中的一个重量。我们可以把这个表达式写成矩阵形式,记住梯度只是一个包含所有∂E/∂Wi.导数的向量矩阵形式如下所示;

记住坡度就是最陡的上坡方向。我们想下降,所以我们去负梯度的方向。图片作者

现在,上述等式可以重复应用于权重,直到它们收敛到正确的值。如果我们的网络更大,找到这个梯度有点痛苦,但只要我们使用可微分的激活函数,它总是可能的。这个等式的重复应用被称为梯度下降算法。

快速小结

让我总结一下过去的 2 页。我们有数据和一些输出。我们知道这些数据和输出之间有某种关系。受人脑的启发,我们可以构建一个人工神经网络。我们用随机权重初始化这个神经网络,然后开始在我们拥有的数据和输出上测试它。当我们测试时,我们通过使用误差函数来量化我们的网络有多错误,然后使用梯度下降来最小化这个误差函数。

例子

既然我们对训练神经网络背后的理论有了一个想法,我们需要专注于如何实现这个理论。早些时候,我给出了一些输入和输出的例子,并为找到它们的关系制定了游戏计划。

手动找到正确的权重是困难的,几乎是不可能的(不把它当作一个线性方程组)。但是通过使用梯度下降算法和我们之前推导出的误差函数,我们可以用正确的方法来计算这些权重。

寻找我们函数的梯度

现在,这是我们从输入到错误的神经网络。记住,为了学习,我们忽略了偏见。我们将在下一个项目中添加它。

图片作者

我们希望找到误差相对于每个重量的导数(每个重量的微小变化对误差的影响),然后将该重量向求反导数的方向(或最陡下降的方向)移动一点点。我们可以使用如下所示的链式法则来做到这一点;

链式法则看起来吓人,其实就是简单的除法。注意,你可以取消∂Z's,就像处理分数一样(你基本上就是这样)。另一种思考方式是。如果你想知道权重的变化对误差的影响有多大,你首先需要知道它对 Z 的影响有多大,然后你需要知道 Z 对误差的影响有多大。此外,掠夺者 3 点符号意味着“因此”。*****图片作者***

就这样,我们找到了我们的梯度!现在我们只需要迭代地应用梯度下降更新来使我们的权重收敛。下面是执行此操作的代码:

坡度下降的提示。*****图片作者***

更新权重 2000 次通常就足够了,如果你猜测荒谬的权重在数万或更高,可能需要更多。看看你运行这段代码后得到的权重,是不是得到了[.5,. 9,1.2]?这就是我用来生成这些数据的确切重量。

这难道不可思议吗?!通过使用微积分和数据,我们可以近似任何两个相关事物之间的关系!你可能会说,“这是一个简单的例子,我可以在 2 分钟内解决它,把它当作一个线性方程组”。嗯,你完全正确。但是,如果有 5 或 6 层,每层有 1000 多个神经元,每层都使用 sigmoid 激活功能,会怎么样呢?以任何方式手工解决都是不可能的。我们需要的是一个系统的算法,可以找到我们网络中权重的梯度,我在这里过了

感谢您的阅读!如果这篇文章在某种程度上帮助了你,或者你有什么意见或问题,请在下面留下回复,让我知道!此外,如果你注意到我在某个地方犯了错误,或者我可以解释得更清楚一些,那么如果你能通过回复让我知道,我会很感激。

这是一系列文章的继续,这些文章从头开始对神经网络进行了直观的解释。其他文章请参见下面的链接:

第 1 部分:什么是人工神经网络

第 2 部分:如何从头开始训练神经网络

第 3 部分:梯度下降的全面实施

第 4 部分:梯度下降的实现(示例)

第五部分:如何在 python 中对手写数字进行分类

如何用简单的变形金刚训练一个 mT5 翻译模型

原文:https://towardsdatascience.com/how-to-train-an-mt5-model-for-translation-with-simple-transformers-30ba5fa66c5f?source=collection_archive---------8-----------------------

mT5 模型在一百多种不同的语言上进行了预训练。让我们看看如何利用这一点来训练一种低资源语言——僧伽罗语的双语翻译模型。

亚历山大·巴甫洛夫·波德瓦尼在 Unsplash 拍摄的照片

mT5 是一个多语言 Transformer 模型,在包含来自 101 种不同语言的文本的数据集(mC4)上进行了预训练。mT5 模型的体系结构(基于 T5)被设计成支持任何自然语言处理任务(分类、NER、问题回答等)。)通过将所需的任务重新架构为序列到序列的任务。

换句话说,文本进去,文本出来。例如,在分类任务中,模型的输入可以是要分类的文本序列,模型的输出将是该序列的类标签。对于翻译来说,这就更简单了。进去的文本是一种语言,出来的文本是另一种语言。

考虑到 mT5 的多语言能力和序列到序列格式对语言翻译的适用性,让我们看看如何为机器翻译微调 mT5 模型。在本文中,我们将训练一个翻译模型在僧伽罗语(我的母语!)和英语。为像僧伽罗语这样的低资源语言训练好的翻译模型是相当具有挑战性的,因为资源(训练数据)的低可用性。希望在一个巨大的数据集(包括僧伽罗语,尽管不是很多)上的多语言预训练将有助于 mT5 模型以直接僧伽罗语-英语(反之亦然)序列的形式补偿不充分的训练数据。

我们将使用简单的变形金刚库(基于 Huggingface 变形金刚库构建)来训练 mT5 模型。训练和测试数据将从Tatoeba 翻译挑战赛中获得。图形和图表由权重&偏差生成,这在用于实验跟踪和超参数优化的简单变压器中得到本地支持。

注:在简单变形金刚 Github repo 的 *examples/t5/mt5_translation* 目录( 链接 )中可以找到本文的所有代码。

概述

  1. 安装简单的变压器
  2. 下载数据集进行翻译
  3. 训练模型
  4. 评估模型—计算 BLEU 分数
  5. 包裹

设置

您可以在简易变形金刚 文档 中找到最新的安装说明。

1.从这里安装 Anaconda 或 Miniconda 包管理器。

2.创建新的虚拟环境并安装软件包。

conda create -n st python pandas tqdm sacrebleu
conda activate st

3.如果使用 CUDA:

conda install pytorch>=1.6 cudatoolkit=10.2 -c pytorch

否则:

conda install pytorch cpuonly -c pytorch

4.安装简单的变压器。

pip install simpletransformers

数据准备

培训和测试可从 Tatoeba 翻译挑战数据页面获得。你还可以在那里找到大量其他语言的数据集(包括《指环王》中精灵使用的语言辛达林语😀).

如果您想尝试为另一种语言训练翻译模型,可以下载该语言的数据集,而不是僧伽罗语。本文中的所有其他步骤适用于任何语言数据集。

如果你懒得搜索数据集,这里有 直接链接 😜

  1. 下载(压缩的)翻译数据集并解压缩存档。
  2. 提取train.trg.gztrain.src.gz档案(是的,训练数据在档案里面的档案里)。
  3. 检查data/eng-sin/目录下是否有train.trg, train.src, test.trg, test.src文件。(如果没有,将文件移动到这个位置可能是最容易的,因为代码示例将假设这些文件可以在这里找到)

现在,让我们构建tsv文件,我们将使用它来训练和测试我们的 mT5 模型。

运行上面的代码会将两个文件train.tsveval.tsv写入data/目录。

模特培训

一旦我们有了数据文件,我们就可以开始训练模型了。

首先,我们将导入必要的东西并设置日志记录。

接下来,我们设置我们的培训和评估数据。

这里,我们从数据集中删除了prefix值,因为我们希望模型根据输入来推断所需的任务。如果输入是英语,那么它应该被翻译成僧伽罗语。如果是僧伽罗语,那就要翻译成英语。模型应该不需要一个前缀就能在训练后搞清楚这一点!

您可以使用前缀值来告诉 mT5(或 T5)执行特定的任务。这对于训练一个可以执行多项任务的模型非常有用,如下文所示。

GPU 内存使用侧记

训练转换器模型所需的 GPU 内存量取决于许多不同的因素(最大序列长度、层数、注意力头数、隐藏维度的大小、词汇表的大小等)。).其中,模型的最大序列长度是最重要的。

对于 mT5 模型中使用的自注意机制,存储器需求随着输入序列长度的平方增长( O(n)空间复杂度)。也就是说,当序列长度加倍时,所需的内存增加了四倍。

此外,mT5 的词汇量比 T5 大得多(大约 250,000 个令牌到大约 32,000 个令牌),这导致 mT5 在所需的 GPU 内存方面相当糟糕。

从所有这些中得出的结论是,我们可以输入到模型中的令牌数(最大序列长度)是以巨大的溢价而来的。基于这一点,如果模型不需要前缀,那么在前缀上使用少量的标记也是一种浪费。

现在,让我们回到训练模型!

这里,我们指定我们希望如何设置模型,并根据model_args初始化预训练的 mT5 模型。

我使用的最大序列长度(max_seq_length)为 96,训练/评估批量为 20。通常,批量越大意味着 GPU 利用率越高,因此训练时间越短。如前所述,更长的序列需要更多的 GPU 内存,这意味着更小的批量和更长的训练时间。最大序列长度为 96,这使得该模型可以处理相当长的文本(通常是几个句子),同时保持训练时间的实用性。

请注意,您可能需要调整这些值,以便在您自己的 GPU 上训练模型。如果 GPU 内存不足(CUDA 内存错误),请尝试减少批处理大小和/或最大序列长度。

如果你想尝试微调的模型,你可以在 Huggingface 模型 hub 上找到 这里

现在,要运行训练,我们只需要调用train_model()方法。

就这么简单!经过微调的模型将在培训结束时保存到outputs目录中(有关模型保存的更多信息,请参见文档)。

通过这些设置,该模型在 RTX 3090 (24 GB VRAM)上完成培训需要 10 个多小时。

培训花费的时间—按作者

我可能已经得到了稍微大一点的批量(正如你在下面看到的),但是我不想冒训练崩溃的风险,因为我整夜都在运行它!

培训期间的 GPU 内存使用情况—按作者

安全起见,批处理大小为 20 意味着 GPU 没有得到充分利用,但是,80%左右也不错!

GPU 利用率(核心数)—按作者

可视化培训进度

model_args中设置wandb_project值告诉简单的变压器自动记录重量&偏差的训练进度。你可以在这里找到这个实验的所有记录数据。

培训损失

培训损失图表—按作者

评估损失

评估损失图表—按作者

这里的实际损失值并没有告诉我们太多,但是它们正在减少的事实确实意味着模型正在学习!

事实上,由于评估损失仍在减少,该模型似乎尚未收敛。再训练一两个纪元可能会很好地提高模型的性能,但是,这将需要另外 10 或 20 个小时!

使用终端命令 *simple-viewer* ,在基于网络的图形用户界面(Streamlit app)中尝试微调后的模型。

评估模型

用于评估和比较机器翻译模型的标准度量是 BLEU 分数,特别是机器翻译年会(WMT)使用的 BLEU 方案。SacreBLEU 库可以用来计算这个分数。

关于 BLEU 评分的更多信息,请参考 Matt Post 的这篇 论文

由于 Tatoeba Challenge 还提供了基准翻译模型的 BLEU 分数,因此我们可以轻松地将我们的模型与基准模型进行比较。

现在,让我们加载我们的微调模型,看看它是如何叠加的!

我们导入必要的东西(注意sacrebleu库)并初始化模型,就像我们为训练所做的一样,除了我们从outputs/加载微调的模型,而不是预训练的模型。

我们还为使用模型生成文本(解码)设置了一些参数。这里,max_length是模型输出而不是输入的最大长度。

如果您想进一步了解解码过程,请参考本 文章 中的 解码算法 部分以及本优 笔记本 by Huggingface。

接下来,我们将准备用于评估的数据。

在这里,我们加载评估数据,并准备单独的输入和真实翻译列表(从英语到僧伽罗语,反之亦然)。

加载并准备好模型和评估数据后,我们就可以开始翻译了。对于简单的变压器,我们只需用输入数据调用model.predict()。然后,我们使用sacrebleu工具来计算 BLEU 分数。

如果您按照安装说明进行操作,那么 *sacrebleu* 库应该安装在您的虚拟环境中。如果没有,可以用 *pip install sacrebleu* 安装。

运行该程序会得到以下分数(四舍五入):

  • 英语到僧伽罗语:10.3
  • 僧伽罗语对英语:24.4

这两个分数都比翻译模型在 Tatoeba 挑战赛中发布的分数有所提高!

包扎

尽管训练数据有限,但 mT5 模型在僧伽罗语和英语之间的翻译方面做得很好。

mT5 超过了 Tatoeba 挑战赛公布的分数。但是,应该注意的是,除了僧伽罗语和英语之外,挑战赛中的基准模型还针对其他几种语言进行了训练。此外,mT5 模型需要更多的计算资源来培训和使用。另一方面,mT5 模型有潜力通过更多的训练来提高当前的分数。

最后,你可以在 Huggingface 模型中心这里找到微调过的模型。可以直接用简单的变压器使用,如下图。

from simpletransformers.t5 import T5Model model = T5Model("mt5", "thilina/mt5-sinhalese-english")print(model.predict(["Let's translate!"]))

如何在 Google 云平台上用 Vaex 训练和部署一个机器学习模型

原文:https://towardsdatascience.com/how-to-train-and-deploy-a-vaex-model-pipeline-on-google-cloud-platform-d5023ef46322?source=collection_archive---------19-----------------------

股票图片来自pixabay.com

介绍

T 训练机器学习(ML)模型通常是一项相当漫长且计算密集型的任务,尤其是在使用大量数据时。

无论您使用的是您最喜欢的深度学习框架、可信的梯度增强机器还是定制的系综,模型训练阶段都可以轻松消耗您笔记本电脑或本地服务器上的大部分(如果不是全部)可用资源,从而有效地“冻结”您的机器,并阻止您执行其他任务。或者,你手头可能甚至没有足够的资源来训练一个复杂的模型来处理你辛辛苦苦收集的所有数据,或者使用你精心设计的所有功能。

最重要的是,管理 ML 模型是一个持续的过程:人们可能需要相对频繁地重新训练模型,以考虑新数据、概念漂移、领域中的变化,或者只是通过调整输入特征、架构或超参数来改进模型。

因此,如果没有必要,将 ML 模型创建的繁重阶段外包给由公认的云提供商管理的服务会非常方便。使用这种方法,计算资源将不是问题。如今,人们可以“租用”连接了数百个 vCPUs 和数 TB RAM 的计算实例,或者提供定制的集群配置。此外,用户可以提交多个独立运行的培训作业,这些作业不会相互竞争资源。所有这些意味着您可以将更多的时间花在创建最佳模型上,而几乎没有时间管理、维护和配置您的计算资源。值得注意的是,随着时间的推移,这些服务变得越来越便宜,越来越容易获得。

谷歌云平台和 Vaex

通过谷歌云控制台看到的谷歌云 AI 平台(作者截屏)

那么 Vaex 如何适应这一切呢?即使在云环境中,使用 Vaex 作为构建 ML 解决方案的核心技术也有很多好处。首先,您可以将数据托管在谷歌云存储(GCS)或亚马逊网络服务(AWS) S3 存储桶上,并根据“需要”将其缓慢地传输到您的计算实例。这意味着只下载您的模型需要的特定列,而不是全部文件。甚至可以选择只下载一小部分数据,这对测试和持续集成特别有用。

所有 Vaex 转换都是通过完全并行的高效核外算法完成的。这意味着您总是可以充分利用出租的计算实例,而无需任何额外的设置。无内存复制策略使您可以更轻松地选择所需的机器类型,同时在不牺牲性能的情况下最大限度地降低成本。

整篇文章将重点介绍更多的好处。因此,事不宜迟,让我们看看如何使用 Vaex 来构建 ML 解决方案,然后如何使用 GCP 来实现它。

在开始之前

本文假设了 GCP 的一些基本知识,以及如何通过谷歌云控制台、和通过gcloud 命令行工具与它交互。如果你想跟随这个教程,你需要一个经过认证的谷歌账户,一个 GCP 项目,和一个已经设置好的 GCS 桶。如果你不确定如何做,有许多有用的指南。如果有疑问,GCP 官方文档总是一个好的起点。

本文中的所有材料都可以在这里 以及各种其他 Vaex 示例中找到。

使用 Vaex 创建自定义 ML 管道

这个例子使用了公共的异构活动识别(HAR) 数据集。它包含了从一组志愿者身上获取的几组测量数据,这些志愿者正在进行六种活动中的一种:行走、上下楼梯、坐着、站着和骑自行车。测量结果通过流行的智能手机和智能手表设备获取,包括分别从板载加速度计和陀螺仪采样的三轴加速度和角速度。数据集还包含“创建时间”和“到达时间”列,它们是分别由操作系统和移动应用程序附加到每个测量样本的时间戳。目标是仅使用单个测量样本来检测佩戴者进行的特定活动。活动本身在“ gt ”栏中指定,该栏代表“地面实况”。

以下示例使用通过智能手机设备获得的加速度计数据。它包含了超过 1300 万个样本。为了简洁起见,我们不会对数据进行任何探索性分析,而是直接构建一个生产就绪的解决方案。

让我们从创建一个 Python 脚本开始,该脚本将获取数据,设计相关的特性,并训练和验证一个模型。因为我们使用的是 Vaex,所以获取数据很简单。如果数据是 HDF5 文件格式,并托管在 GCS(或亚马逊的 S3)上,Vaex 将缓慢地传输分析所需的部分。因为我们已经知道需要哪些数据列,所以可以立即预取它们:

下一步是将数据随机分成 3 组:训练、验证和测试。验证集将在训练阶段用作质量控制,而测试集将是已训练模型的最终独立性能指标。

此时,我们可以开始创建一些有用的功能。让我们从做几个坐标变换开始。我们将把三轴加速度测量值从笛卡尔坐标转换到球坐标,以及通过 PCA 变换转换到它们的“自然”坐标系:

即使上面的一些转换并不太复杂,我们仍然可以选择通过 numba 使用即时编译来加速它们。请注意,我们还使用了在 vaex-ml 版本 0.11 中可用的新 API,而不是更传统的 scikit-learn“fit&transform”方法。

为了捕捉数据中的一些非线性,我们可以在 PCA 组件之间创建一些特征交互:

现在,我们将变得更有创造性。首先,让我们计算每个活动类别的每个主成分的平均值和标准偏差。然后,我们将计算每个主成分的值与每个组的平均值之间的差异,并按该组的标准偏差进行缩放:

请注意我们是如何结合使用 Vaex 和 Pandas 来创建这些功能的。虽然不会存储df_summary数据帧,但它的值会被“记住”,作为在for循环中定义的表达式的一部分,该循环遵循groupby聚合。上面的代码块是一个例子,展示了如何快速清晰地创建新特性,而不需要创建定制的Transformer类。

特征工程的另一个有趣的方法是对已经定义的特征子集应用聚类算法,并将得到的聚类标签用作附加特征。 vaex-ml 包直接实现了KMeans聚类算法,所以保证了非常快速和内存高效。使用KMeans算法,我们创建 3 组聚类标签:一组通过对 PCA 组件进行聚类,另一组通过对 PCA 交互组件进行聚类:

在 Vaex 中,任何模型都被视为一个转换器,因此它的输出很容易用作下游计算图中的任何其他功能。

最后,我们还可以利用时间戳特性,计算"到达时间"和"创建时间"列之间的差异,我们对其应用标准缩放:

定义完所有特性后,为了方便起见,我们可以将它们收集到一个列表中:

数据准备的最后一部分是将目标列" gt" 编码成数字格式。在编码之后,我们还将定义一个逆映射字典,稍后我们将使用它将预测的类翻译成它们真正的标签。

至此,我们终于准备好开始训练模型了。您可能已经注意到,我们没有费心去显式地创建一个管道来允许所有的数据转换被传播到验证和测试集。这是因为 Vaex 数据帧隐式记录了对数据进行的所有转换和修改。过滤器、分类编码、缩放,甚至 ML 模型的输出都被认为是数据转换,并且是数据帧的状态的一部分。因此,为了加快验证设置,以便我们可以在模型训练期间将其用作参考点,我们只需获取df_train状态并将其应用于df_val:

现在我们准备实例化和训练模型,我们已经选择它作为一个 LightGBM 分类器:

当与 Vaex 配合使用时,ML 型号也是变压器。这意味着可以将预测添加到数据帧中,就像应用另一种变换一样。这在构建集成时非常有用,对于执行模型诊断也是如此。在我们的例子中,LightGBM 模型的输出是概率数组。为了使输出对模型的最终用户更有意义,我们将找到最可能的类,并对其应用逆转换,这样我们就可以获得最可能的活动的名称——这是一系列转换中的又一个!

一旦模型被训练,我们可以通过计算验证集和测试集上的两个度量来了解它的性能,到目前为止,后者在这个过程中完全没有使用过。同样,要获得预测,我们需要做的就是从df_train获得状态,现在包括模型预测,并将其应用于df_valdf_test数据帧:

注意上面和前面代码块中log函数的用法,它是标准 Python 日志记录系统的一个实例。当这段代码在 AI 平台上运行时,日志将被自动捕获,并在 GCP 的集中云日志部分提供。整洁!

我们结束了。最后一步是将最终的状态文件保存在 Google 云存储(GCS)桶中,以便以后部署。Vaex 可以将状态文件直接保存到 GCS 或 S3 桶中;

在 GCP 训练定制的 Vaex 管道

现在,我们的训练脚本已经准备好了,它需要被制作成一个 Python 包,以便可以在 AI 平台上安装和执行。让我们称我们的训练模块为“har_model”。其组成文件应按照以下树形结构组织:

作者制作的训练目录树。

请注意,我们还包含了一个空的“init”。py ”,因此 Python 将“har_model”目录视为一个包。“setup.py”脚本安装软件包以及所需的依赖项:

人工智能平台的好处在于,在向 GCP 提交作业之前,我们可以在本地运行我们的包。这对于调试和测试非常有用。以下 shell 命令将以与云中相同的方式在本地执行培训脚本:

由于当前解决方案中的核心技术是 Vaex,人们可以很容易地限制它使用一小部分数据来使测试运行得更快。一旦我们确定培训模块按预期运行,我们就可以通过以下命令向 GCP 提交培训作业:

给定大量的参数,将上面的命令作为 shell 脚本的一部分来执行会非常方便。这样,它可以被版本控制,或者作为 CI/CD 管道的一部分。

一旦上述命令被执行,人工智能平台培训工作将开始,你可以在 GCP 的日志记录部分监控其进展。使用我们在上面的例子中选择的机器类型( n1-highcpu-32,32 vcpu,28GB RAM),整个培训工作需要大约 20 分钟。工作完成后,我们可以检查日志,看看模型在测试集上的表现如何:

GCP 日志查看器的屏幕截图,显示了上面文本中描述的培训作业的日志输出。

就是这样——通过最少的设置,我们成功地在 GCP 训练了一条完全定制的 Vaex 管道!管道本身包含完整的特征工程和数据处理步骤、分类算法和后处理操作,具有 Vaex 状态文件的形式,并保存到指定的 GCS 存储桶中,以备部署。

在 GCP 铺设 Vaex 管道

AI 平台是部署 ML 模型的一种相当方便的方式。它确保了预测服务的高可用性,并使部署和查询多个模型版本变得容易,这对于进行 A/B 测试是很有用的。

部署 Vaex 管道非常简单——预测服务器需要做的就是将传入的批次或数据样本转换为 Vaex 数据帧,并对其应用状态文件。

为了部署定制的 Vaex 管道,我们必须指导 AI 平台如何处理特定于我们问题的请求。我们可以通过编写一个实现预测器接口的小类来做到这一点:

上面的VaexPredictor类有两个关键方法:from_path方法只是从 GCS 桶中读取状态文件,而predict方法将数据转换为 Vaex 数据帧格式,对其应用状态文件,并返回预测。注意,predict方法可以方便地截取以 Python listdict类型传递的数据。

下一步是将VaexPredictor类打包成一个.tar.gz源代码发行版 Python 包。该包需要包括获得预测所需的所有依赖项。创建这样的包需要一个“setup.py”文件:

通过运行以下 shell 命令来创建软件包:

最后,我们需要将预测包移动到 GCS,这样 AI 平台就可以拾取并部署它:

为了方便起见,将上述两个命令捆绑在一个 bash 脚本中可能会很方便,尤其是在创建预测包时需要迭代几次的情况下。

作为参考,该示例项目的部署部分的目录树应该如下所示:

我们现在准备好部署预测包了。首先在 shell 中定义一些环境变量会非常方便:

模型部署是通过以下两个命令完成的。首先,我们需要在 AI 平台上创建一个“模型”资源,如下所示:

然后,我们创建模型的“版本”资源,它指向模型制品,即状态文件,以及预测器类:

执行上述命令可能需要一两分钟的时间。就是这样!我们的 Vaex 模型现在已经部署完毕,可以响应传入的预测请求了!

我们现在准备好查询我们的模型。发送到 AI 平台的批量数据需要采用 JSON 格式。如果输入是列表的形式,文件的每一行都应该是包含单个样本特征的列表。应注意的是,要素的顺序与预测器类的预期一致。这种文件的示例如下所示:

一个列表格式的输入文件的例子,input_list.json,用于查询“har_model”。

然后使用以下命令发送预测请求:

输入数据也可以格式化为 JSON 对象。这里可以更加灵活—一行可以是单个或多个样本:

一个 dict 格式的输入文件的例子,input_dict.json,用于查询“har_model”。

下面是使用上面的文件查询我们的“har_model”的简短屏幕截图:

就这么简单!

ML 模型的寿命不是无限的。当取消部署模型时,需要首先删除版本资源,然后删除模型资源:

最后,值得注意的是,尽管我们在本例中在 GCP 上训练了模型,但这根本不是部署需求。所有需要做的就是让状态文件驻留在一个 GCS 桶中,以便预测模块可以拾取它。人们可以训练模型并在本地创建状态文件,或者使用任何其他可用的服务。

摘要

我希望这篇文章证明了 Vaex 是构建 ML 解决方案的优秀工具。它的表达系统和自动管道对这项任务特别有用,而它高效的核外算法确保了速度并保持低计算成本。

将 Vaex 与 GCP 结合使用会带来可观的价值。Vaex 能够直接从 GCS 传输数据,并且只传输那些对模型绝对必要的部分。在 Google Clouds 的 AI 平台上训练 ML 模型也相当方便,尤其是对于要求更高、运行时间更长的模型。由于 Vaex 模型的整个转换管道都包含在一个单独的状态文件中,用 AI 平台部署它是很简单的。

数据科学快乐!

附录:AI 平台统一

2020 年 11 月中旬,谷歌推出了人工智能平台的下一个迭代,称为人工智能平台统一。顾名思义,这个版本统一了 GCP 提供的所有 ML 相关服务:autoML,随时可以使用的 API 以及培训和部署定制模型的选项都可以在同一个地方找到。

新的人工智能平台带来的一个重大改进是可以选择使用定制的 Docker 容器来训练和部署模型。与“经典”人工智能平台相比,这带来了额外的灵活性,在“经典”人工智能平台中,只有特定的环境可用,安装或修改其内容的选项有限。

让我们看看如何使用统一的 AI 平台来训练和部署我们在本文前面构建的 Vaex 解决方案,现在使用定制的 Docker 容器。

训练模型相当简单:我们需要做的就是创建一个 Docker 映像,当它启动时将执行我们之前准备的训练脚本。我们首先创建一个docker file:

在上面的 Dockerfile、 " env.yml 中,我们需要的所有依赖项都可以通过 condamambapip 安装。“setup.py”和“har_model”组成了我们前面定义的模型训练包。然后,我们安装所需的依赖项和模型训练包,最后设置一个 入口点 ,以便在容器运行时开始训练过程。提示:如果你想建造非常小的码头集装箱,看看 Uwe Korn 的指南。

现在,我们可以在本地构建 Docker 映像,并将其推送到 Google 的容器注册表,但是简单地使用云构建并在 GCP 构建映像要方便得多:

然后,我们可以启动容器,并通过执行以下命令开始培训工作:

可以通过云日志记录来监控培训进度,云日志记录可以捕获来自自定义 Docker 容器的任何日志。大约 20 分钟后,作业应该完成,我们可以通过 Google Cloud 控制台对其进行检查:

现在,让我们在统一的 AI 平台上部署我们刚刚使用自定义 Docker 容器训练的模型。启动时,容器应该运行一个 web 应用程序,该应用程序将使用预测来响应请求。web 应用程序应该至少实现两种方法:一种是人工智能平台将用来进行“健康检查”的方法,即确保 web 应用程序按预期运行,另一种方法将接受传入的预测请求并使用答案进行响应。有关容器要求和所有可用定制选项的更多信息,您可以查看官方文档

我们不会详细讨论如何构建这样一个 web 应用程序,因为 web 上有大量的相关资源。作为参考,您可以在这里看到我们为这个示例准备的 web 应用程序。

在构建和测试 web 应用程序之后,我们需要创建一个 Docker 容器,在启动时运行它。按照与创建模型训练容器相同的步骤,很容易做到这一点。

一旦 Docker 映像在 Container Registry 中可用,我们需要通过下面的gcloud命令将它变成一个模型资源:

下一步是创建用于访问模型的模型端点:

我们现在可以像这样将模型资源部署到端点:

这一步可能需要几分钟才能完成。请注意,您可以将几个模型资源部署到一个端点,也可以将一个模型部署到多个端点。

模型现在终于部署好了,可以接受请求了。请求应采用 JSON 格式,并具有以下结构:

在这里你可以看到对于这个特殊的例子,这样一个文件看起来会是什么样子。Google Cloud 控制台还会给你一个如何查询模型端点的例子。它看起来会像这样:

就是这样!当您的模型超过其生存期时,不要忘记取消部署它并删除端点和模型资源,以避免不必要的成本。可以这样做:

最后,我们可以将培训和部署视为两个独立的、完全独立的过程。这意味着可以使用“经典的”人工智能平台进行训练,使用统一的人工智能平台部署模型,反之亦然。当然,人们总是可以“在内部”或者使用任何可用的资源来创建模型,并且只使用 GCP 来服务。

如何训练伯特

原文:https://towardsdatascience.com/how-to-train-bert-aaad00533168?source=collection_archive---------0-----------------------

训练变形金刚的速射指南

像这样的形式需要预先训练——由作者生成图像。

transformer 模型的成功在很大程度上要归功于它能够采用 Google 和 OpenAI 等公司在巨大数据集上预先训练的模型,并将它们应用到我们自己的用例中。

有时,这就是我们所需要的——我们采用模型并按原样滚动。

但在其他时候,我们发现我们确实需要对模型进行微调。我们需要在我们的特定用例上对它进行更多的培训。

每个变压器模型都是不同的,针对不同用例的微调也是不同的——因此我们将重点关注核心 BERT 模型的微调。并附有一些脚注,说明我们如何为几个最常见的应用程序修改它。

你可以在这里观看文章的视频版本:

它是如何工作的

首先,这些是如何工作的?我假设你对变形金刚和伯特有一定的了解,如果你不知道我在说什么——先看看这篇文章

《变形金刚》的威力源自谷歌和 OpenAI 等大公司将变形金刚模型预先训练到非常高的标准。

现在,当我说按照非常高的标准进行预培训时,OpenAI 的 GPT-3 的估计培训成本在 460 万美元到 1200 万美元之间[1][2]。

我没有多余的 1200 万美元来训练模特,你呢?

通常,原始的预训练模型对于我们的需求来说已经足够了,我们不需要担心进一步的训练。

但有时,我们可能需要——幸运的是,变形金刚在制造时就考虑到了这一点。对于 BERT,我们可以将进一步培训的可能性分为两类。

首先,我们对核心 BERT 模型本身进行了微调。这种方法包括使用 Google 在训练原始模型时使用的相同训练方法——我们稍后将更深入地讨论这一点。

(左)带分类头的 BERT,(右)带问答头的 BERT。

第二,我们可以添加不同的到我们的模型中,这给了伯特新的能力。这些是我们模型末尾的额外层,为不同的用例修改输出。例如,我们会使用不同的标题来回答问题或进行分类。

在本文中,我们将重点关注对核心 BERT 模型的微调——这允许我们对 BERT 进行微调,以更好地理解我们的用例中特定的语言风格。

微调内核

使用两种方法训练 BERT 的核心,下一句预测(NSP)和屏蔽语言建模(MLM)。

1。 下一个句子预测包括将句子对作为模型的输入,这些对中的一些对将是真的,其他的将不是。

两个连续的句子形成一个“真对”,其他的都不是真对。

BERTs 在这里的任务是准确地识别哪些对是真正的对,哪些不是。

还记得我说过我们可以用不同的头来训练伯特吗?NSP(和 MLM)也用特殊的头。这里使用的 head 将来自分类器令牌的输出处理到一个密集的 NN 中,输出两个

我们的分类头密集层消耗来自分类任务中使用的[CLS](分类器)标记位置的输出。

这个[CLS]令牌的输出是一个 768 维的向量,它被传递给我们具有两个节点的密集 NN 层——我们的IsNextSentenceNotNextSentence类。

BERT 中 NSP 任务的高级视图。

这两个输出是我们对 BERT 是否相信句子 B 在句子 a 之后的真/假预测。索引 0 告诉我们 BERT 相信句子 B 在句子 a 之后。

训练后,NSP 头被丢弃——我们保留的只是许多 BERT 层中经过微调的权重。

2。 屏蔽语言建模包括获取一大块文本,屏蔽给定数量的标记,并要求 BERT 预测被屏蔽的单词是什么。

通过屏蔽操作处理原始文本,用【屏蔽】标记替换随机标记。

每个序列中有 15%的单词被[MASK]标记屏蔽。

一个分类头被附加到该模型上,并且每个标记将被馈送到一个前馈神经网络中,随后是一个 softmax 函数。每个令牌的输出维数等于 vocab 的大小。

MLM 进程的高级视图。

这意味着从每个记号位置,我们将得到最高概率记号的输出预测。我们用我们的词汇把它翻译成一个特定的单词。

在训练期间,当计算损失函数时,对未被屏蔽的记号的预测被忽略。

同样,与 NSP 一样,MLM 头部在训练后被丢弃——留给我们优化的模型权重。

用代码

我们知道 NSP 和 MLM 的微调是如何工作的,但是我们如何在代码中应用它呢?

好了,我们可以从导入变形金刚PyTorch ,以及我们的训练数据— 冥想(在这里找到训练数据的副本)开始。

现在我们在text中有一个段落列表——一些,但不是全部,包含多个句子。这是我们在构建 NSP 培训数据时需要的。

为 NSP 做准备

为了准备 NSP 的数据,我们需要创建一个非随机句子(两个句子最初在一起)和随机句子的混合。

为此,我们将创建一个从text中提取的句子包,然后我们可以在创建随机NotNextSentence对时从中随机选择一个句子。

我们的包含与文本相同的数据,但是按句子分割——通过使用句点字符来标识。

在创建我们的bag之后,我们可以继续创建我们的 50/50 随机/非随机 NSP 训练数据。为此,我们将创建一个句子 As、句子 Bs 以及它们各自的IsNextSentenceNotNextSentence标签的列表。

我们可以在控制台输出中看到,标签 1 表示随机句子(NotNextSentence),标签 0 表示非随机句子(IsNextSentence)。

标记化

我们现在可以标记我们的数据。如同典型的 BERT 模型一样,我们将序列截断/填充到长度为 512 的记号。

这里有几件事我们应该注意。因为我们标记了两个句子,所以我们的标记器在 token_type_ids 张量中自动将 0 值应用于句子 A,将 1 值应用于句子 B。尾随零与填充标记对齐。

其次,在 input_ids 张量中,记号赋予器自动在这两个句子之间放置一个 SEP 记号(102)——标记两者之间的边界。

伯特在表演 NSP 的时候需要看到这两者。

NSP 标签

我们的 NSP 标签必须放在一个叫做 next_sentence_label 的张量中。我们通过获取我们的label变量,并将其转换为torch.LongTensor——也必须使用.T进行转置,从而轻松地创建它:

MLM 的屏蔽

对于 MLM,我们需要clone我们当前的 input_ids 张量来创建一个 MLM 标签张量——然后我们移动到屏蔽 input_ids 张量中大约 15%的记号。

现在我们克隆了我们的标签,我们屏蔽了 input_ids 中的令牌。

请注意,我们在这里添加了一些规则,通过在创建mask_arr时添加额外的逻辑,我们确保不屏蔽任何特殊的令牌,例如 CLS (101)、 SEP (102)和 PAD (0)令牌。

数据加载器

我们所有的输入和标签张量都准备好了——我们现在需要做的就是将它们格式化为 PyTorch dataset 对象,以便可以将它们加载到 PyTorch Dataloader 中——这将在训练期间向我们的模型提供批量数据。

数据加载器期望使用__len__方法检查数据集中的样本总数,使用__getitem__方法提取样本。

培训设置

进入训练循环之前的最后一步是准备模型训练设置。

我们首先检查我们是否有可用的 GPU,如果有,我们将模型移到它上面进行训练。然后,我们激活模型中的训练参数,并用加权衰减初始化 Adam 优化器。

培养

最后,我们开始训练我们的模型。我们训练两个纪元,并使用tqdm为我们的训练循环创建一个进度条。

在循环中,我们:

  • 初始化渐变,这样我们就不会从上一步计算的渐变开始。
  • 将所有批量张量移动到选中的device (GPU 或 CPU)。
  • 将一切输入模型,提取损失。
  • 使用loss.backward()计算每个参数的损失。
  • 基于计算的损失更新参数权重。
  • 将相关信息打印到进度条(loop)。

就这样,我们用 MLM 和 NSP 对我们的模型进行了微调!

关于使用屏蔽语言建模和下一个句子预测微调 BERT 的文章到此结束。我们已经介绍了什么是 MLM 和 NSP,它们是如何工作的,以及我们如何用它们来微调我们的模型。

有很多地方可以对 BERT 进行微调,但是概念和实现并不太复杂——同时功能非常强大。

使用我们在这里学到的知识,我们可以采用 NLP 中最好的模型,并对它们进行微调以适应我们更特定于领域的语言用例——只需要未标记的文本——通常是很容易找到的数据源。

我希望你喜欢这篇文章!如果你有任何问题,请通过 Twitter 或在下面的评论中告诉我。如果你想要更多这样的内容,我也会在 YouTube 上发布。

感谢阅读!

参考

[1] B. Dickson,《GPT 3 号未披露的故事》是 OpenAI 的转变 (2020),TechTalks

[2] K. Wiggers, OpenAI 巨大的 GPT-3 模型令人印象深刻,但大小并不代表一切 (2020),VentureBeat

朱庇特笔记本

如果你有兴趣了解更多关于 MLM 和 NSP 背后的逻辑,以及一般的变形金刚,请查看我的 NLP 变形金刚课程:

🤖《变形金刚》NLP 课程 70%的折扣

*所有图片均由作者提供,除非另有说明

如何训练 Bert 进行任何语言的问答

原文:https://towardsdatascience.com/how-to-train-bert-for-q-a-in-any-language-63b62c780014?source=collection_archive---------2-----------------------

从零开始的多语言问答简单指南

杰里米·贝赞格在 Unsplash 上的照片

问答(Q&A)变压器应用广泛,是现代自然语言处理的非常酷的应用。

乍一看,我们大多数人会认为建造这样的东西是一个非常困难的壮举。幸运的是,我们大多数人都错了。

尽管变形金刚有着令人难以置信的性能,但训练或微调它们来完成特定任务却异常简单。

再加上网上可用的许多大规模语言数据集,我们就拥有了构建一些令人难以置信的工具所需的一切。

我们将解释从头开始训练 Bert transformer 模型所需的关键步骤,以及我们如何针对 Q & A 微调该模型。这里的一个关键因素是数据集,我们也将在整篇文章中概述它。

从零开始问答

第一,变形金刚训练流程是什么样子的?虽然这些模型非常强大,但训练过程却出奇的简单。

我们首先需要明白的是,有一个核心 Bert 模型。这个核心模型充当了中央转换引擎——正是这个引擎构建了对语言的理解。

这个中央模块的输出本身并不是特别有用。它只是一个语言理解引擎,它不能告诉你一个句子是快乐还是悲伤,识别实体,或者回答我们的问题。

对于所有这些任务以及更多的任务,我们需要一个训练有素的变压器头。

变压器的头部连接到核心引擎。核心引擎消耗一些文本,并将其处理成有意义的数字向量。这些向量是我们变压器头的丰富信息输入。

每个 transformer 头的结构都是为特定任务而构建的,许多只不过是由几个前馈神经网络层组成,其组织方式是,一旦训练了头,我们就可以产生有意义的功能。

因此,要从头构建问答 Bert 模型,我们必须:

  • 训练一个核心 Bert 引擎。
  • 培养一个问答 Bert 问答头。

有时可能没有使用您的语言的现有 Bert 模型。如果是这种情况,您还必须训练一个 Bert 单词片段标记器。我已经在这里写了这个

为了简洁起见,这里我们将只关注两个模型训练任务。让我们进入核心的 Bert 训练过程。

训练核心

伯特最初是用两个并行的过程训练的。掩蔽语言建模(MLM)和下一句预测(NSP)。两者都需要大量的训练数据,这些数据必须是非结构化文本的形式。

幸运的是,如果说我们在互联网上有很多东西的话,那就是非结构化文本。

MLM 和 NSP 的数据集

对于 MLM 和 NSP,我们只需要一个大型的非结构化文本数据集。在多语言非结构化文本方面,没有比 OSCAR 语料库更好的来源了。

OSCAR 目前涵盖 166 种语言,从英语到纳瓦特尔语。完整列表可在此处找到

从 OSCAR 下载数据最简单的方法是通过 HuggingFace 的datasets库。我个人会 100%推荐采取这种方式。我们可以非常快速地下载——例如——奥斯卡的英文子集,如下所示:

还有大量其他可用的数据集,我们可以在 HuggingFace 的数据集查看器上找到。

当下载较小的数据集时,我们可以毫无问题地使用上面的代码——但是较大的数据集(特别是来自 OSCAR 的数据集)可能会非常大——OSCAR 的意大利子集有 69GB 的数据,而英国只有 1.8TB。

在这种情况下,我们可以通过将streaming=True参数添加到load_datasets流式传输数据。

然后,要么用streaming=True构建完整的输入管道,要么只遍历数据集的较小部分并将它们存储在内存中(通常streaming=True会导致代码问题,在这种情况下,后一种选择是最好的)。

如果你需要通过 HF 数据集下载数据的细节方面的帮助,我会在这段视频中一一介绍:

一旦数据下载完毕,我们就开始用 MLM ( NSP,如果愿意的话)训练核心模型。

屏蔽语言建模

MLM 包括向伯特提供一个句子,其中几个单词(或记号)已经使用掩码记号隐藏起来。这个掩码标记无非是隐藏原始单词。

**ORIGINAL**: "flying fish flew by the space station"**MASKED**: "*[MASK]* fish flew by the *[MASK]* station"

然后,原始句子作为核心 Bert 模型的目标输出传递。通过这样做,Bert 被迫阅读句子中的其他单词,并试图理解上下文以正确预测被屏蔽的单词。

下一句预测

除了 MLM 之外,还发现一种叫做 NSP 的额外训练过程提高了 Bert 在下游任务(那些需要特定变压器头的任务)中的性能。

当 Bert 试图猜测掩码标记背后的真实单词时,它还负责识别作为输入提供的两个句子是否属于一起。

这意味着,给定两个句子——AB。句子B是句子A的逻辑延续吗?

**Logical continuation (*IsNext*)**
A: "Alia went to the shop to buy pasta"
B: "The shop was closed"**Not logical continuation (NotNext)**
A: "Alia went to the shop to buy pasta"
B: "The armadillo was not very happy with the lion"

MLM 和 NSP 是否都被用于训练核心的伯特模型——或者仅仅是 MLM,取决于你的偏好。只训练 MLM 更简单,通常能达到 MLM NSP 可能表现的 90%左右。

在下面的视频中,我们介绍了 MLM 的训练过程(如果你想用 MLM NSP,在这里找到)。

问答负责人

我们有一个经过全面训练的核心 Bert 模型,我们可以采用该核心并添加几个头部,从而允许我们使用该模型执行不同的任务。但是,这些负责人最初是未经培训的,因此我们必须对他们进行培训!

如果您喜欢视频,我们在这里也涵盖一切:

对于问答,最受欢迎的数据集是斯坦福问答数据集(SQuAD)。除了最初的英文版本,现在还有其他几种语言版本。

**Language options *(on HF datasets at the time of writing)***Spanish: **squad_es** Portuguese: **squad_v1_pt** Italian: **squad_it** Korean: [**squad_kor_v1**, **squad_kor_v2**]Thai: [**iapp_wiki_qa_squad**, **thaiqa_squad**]English: [**squad**, **squad_v2**, **squadshifts**, **squad_adversarial**]

为了下载英国队的数据,我们使用:

**Language options *(at the time of writing)***Spanish: **squad_es** Portuguese: **squad_v1_pt** Italian: **squad_it** Korean: [**squad_kor_v1**, **squad_kor_v2**]Thai: [**iapp_wiki_qa_squad**, **thaiqa_squad**]English: [**squad**, **squad_v2**, **squadshifts**, **squad_adversarial**]

对于每个样本,我们的数据可以分为三个部分:

  • 问题 —包含我们将向 Bert 提出的问题的字符串。
  • 上下文 —包含我们问题答案的更大的序列(段落)。
  • 回答 —回答我们问题的一段上下文。

给定一个问题上下文,我们的 Q & A 模型必须读取两者并返回上下文中预测答案的标记位置。

我们的问题、上下文和答案输入的示例,以及来自模型的(希望的)正确预测。请注意,这些跨度值并不精确,而是假设一个单词=一个标记。

格式化答案

在我们开始标记化、训练等之前,我们需要将我们的answers特性重新格式化为正确的训练格式。目前看起来像是:

{'text': ['the answer is here'], 'answer_start': [71]}

71代表我们的context字符串中答案开始的字符位置。我们可以通过简单地将text的长度加到answer_start来得到答案范围,我们首先这样做:

数据格式现在可以进行标记化了。

标记化

我们需要对阵容数据进行记号化,以便它可以被我们的 Bert 模型读取。对于contextquestion特征,我们可以使用标准的tokenizer()函数:

它将我们的contextquestion字符串编码成单个令牌数组。这将作为我们 Q & A 培训的输入,但是我们还没有目标。

我们的目标是答案的开始和结束位置,这是我们之前使用context字符串中的字符开始和结束位置构建的。然而,我们将把令牌输入到 Bert 中,所以我们需要提供令牌的开始和结束位置。

为此,我们需要将字符的开始和结束位置转换成记号的开始和结束位置——使用我们的add_token_positions函数很容易做到:

这个函数给我们的Encoding对象增加了两个张量(我们将它们输入到 Bert 中)—start_positionsend_positions

我们的张量现在准备好训练 Bert Q&A 头了。

培养

我们将使用 PyTorch 进行训练,这意味着我们需要将我们构建的张量转换成 PyTorch Dataset对象。

我们将使用一个Dataloader对象把我们的Dataset输入到我们的 Q & A 训练循环中,我们用:

最后,我们设置模型参数并开始训练循环。

训练完我们的模型后,我们需要做的就是保存它!

我们完成了,我们从零开始训练了一个问答模型。

这就是本文的全部内容,我们已经介绍了训练用于问答的 Bert transformer 模型的核心和头部背后的要点,并探索了一些我们可以用于这两者的最佳数据集。

我希望你喜欢它!如果你有任何问题,请通过 Twitter 或在下面的评论中告诉我。如果你想要更多这样的内容,我也会在 YouTube 上发布。

感谢阅读!

🤖《变形金刚》课程 NLP 的 70%折扣

*所有图片均由作者提供,除非另有说明

如何在数据流上训练深度神经网络

原文:https://towardsdatascience.com/how-to-train-deep-neural-networks-over-data-streams-fdab15704e66?source=collection_archive---------10-----------------------

来源

历史上,已经开发了许多机器学习算法来处理和学习传入的数据流。例如,支持向量机和逻辑回归机等模型已被推广到学习者无法获得整个数据集的情况,训练必须在输入的连续数据流上进行[1,2]。类似地,许多聚类算法已经被提出用于数据流的学习[3]。这些方法迫使底层模型从一个连续的数据流中学习,该数据流一次只提供一个示例,从而消除了立即提供整个数据集的需要。有趣的是,尽管已经为更传统的机器学习算法开发了流学习的方法,但是流学习并没有被广泛地用于深度神经网络,其中离线训练(即,在整个数据集上执行若干循环/时期)占主导地位。

为了缩小这一差距,深度学习社区最近的工作探索了通过流式传输训练深度网络的可能性。在深度学习领域中,流可以被描述为一种学习设置,其中 (i) 数据集一次学习一个示例(即,数据集被呈现为传入的数据流) (ii) 数据集中的每个唯一示例仅出现一次, (iii) 流中数据的排序是任意的, (iv) 正在训练的模型可以在数据流中的任何点进行评估。与训练神经网络的典型离线方法相比,这种设置可能看起来相当苛刻,这解释了为什么在流设置中实现高性能通常很困难。尽管如此,流式学习反映了工业中的许多应用,并且如果正确使用,为深度学习实践者提供了强大的工具。

在这篇文章中,我将概述深度学习中的流。我将从激励使用流学习开始,重点关注流学习在实际应用中的效用。然后,我将概述在流设置中训练深度神经网络的现有方法,强调在实践中最有用的方法。通过这篇文章,我的目标是 i) 说明流学习和深度学习之间的关系,以及 ii) 概述在实际应用中利用流学习的力量的有用发现。

为什么选择流式学习?

分流与其他培训模式有何关系?在提出流学习[4]之前,研究了许多训练设置,这些训练设置探索了不同的策略,这些策略将部分不相交的数据子集顺序暴露给模型,而不是以离线方式对整个数据集进行训练。在这篇文章中,我将把所有这样的方法(包括流学习)统称为“在线”学习设置。通常,在线学习将数据集分成几个不相交的“批”数据,模型一次只暴露一批。一旦学习了一批数据,该模型就不能在以后的训练过程中返回到该批数据(即,只有“当前”数据可以被直接访问以训练该模型)。

已经提出了在线学习的许多不同变体(例如,终身学习、持续学习、批量/班级增量学习、流学习等)。).这些不同的变体中的每一个都涉及上述在线学习的相同概念,通常对实验设置有微小的改变。例如,终身学习倾向于按顺序学习不同的任务(即,每个任务可以被认为是来自包含所有任务的数据集中的数据的子集/批次),而类增量学习针对每个批次内的总体分类问题学习严格的类子集(例如,CIFAR100 的前 20 个类)。值得注意的是,在线学习过程中的每一批数据都可能非常大。例如,类增量学习实验经常在 ImageNet 上进行,其中每批包含完整数据集的 100 个类子集(即~130K 数据示例)。

流式学习也可以被解释为上述在线学习描述的变体,其中每个“批”数据只是来自数据集的单个示例。然而,流学习似乎比其他相关的方法更偏离通常的在线学习设置。也就是说,流式学习,因为它被限制为一次学习一个实例的数据集,所以不能在每次有新的一批数据可用时执行任意数量的离线训练。这是因为一次只有一个数据示例可供模型使用,而按顺序对同一数据执行多次更新会迅速降低模型性能。因此,流式学习方法倾向于在新数据可用时执行简短的实时模型更新,而其他在线学习方法通常执行昂贵的离线培训程序来学习每一批新数据。

为什么在线学习很难?当一个人第一次遇到在线学习的话题时,他们可能会认为解决这个问题很容易。为什么不在新数据可用时对模型进行微调呢?这种幼稚的方法在某些情况下是有效的。特别是,如果传入数据流是 i.i.d. ,它将工作,这意味着每一段传入数据都是从所有可能的数据示例中均匀采样的。在这种情况下,从数据流中学习等同于为每个训练迭代从数据集中均匀地采样一个例子(即,这只是随机梯度下降!),而且幼稚的微调也挺管用的。然而,我们不能总是确保传入的数据是独立身份的。事实上,许多值得注意的实际应用的特征在于非独立身份的数据流(例如,视频流、个性化行为跟踪、对象跟踪等。).

虽然当输入数据是独立身份数据时,在线学习很容易解决,但当数据是非独立身份数据时,会出现一个有趣的现象-模型从新数据中学习,但很快就会忘记之前学习的所有内容。例如,在类增量学习的情况下,模型可能开始学习如何对马进行分类(即,它以前没有遇到过的某个类),但是完全忘记了如何对狗、猫、松鼠以及过去已经学会分类的所有其他动物进行分类。这个问题——通常被称为灾难性遗忘[5,6]——是所有在线学习技术面临的基本问题。也就是说,因为数据流通常是非独立的,以在线方式学习的模型通常会遭受灾难性的遗忘,这极大地影响了它们的性能(尤其是在最近没有观察到的数据上)。

流学习更实用。现在,我们对流式学习、一般的在线学习以及二者所面临的问题有了更好的理解,有人可能会问这样一个问题:为什么要特别关注流式学习?主要原因是流学习 i) 实时发生, ii) 更好地反映了实践中出现的常见学习范式。

因为学习在流内一次发生一个示例,所以模型更新往往是简短的(即,每个示例一次或几次向前/向后传递)。因此,在新数据示例到达和底层模型适应该数据示例之间存在最小的延迟— 当新数据可用时,模型会实时更新。相比之下,当 i) 等待足够大批量的新数据积累,或者 ii) 在新一批数据可用之后更新模型时,其他通常研究的在线学习设置可能会遭受延迟——必须执行许多向前/向后传递,以更新大批量数据的模型,特别是如果对数据执行了几次循环。虽然从研究的角度来看,这种在线学习的替代实验设置很有趣,但是当他们有能力在每个新样本到来后更新模型时,为什么任何从业者都要等待数据积累呢?

流学习使模型实时适应数据流的能力在工业中也有广泛的应用。例如,考虑一个推荐系统,该系统在用户每次与网站交互时(例如,购买、点击或者甚至鼠标的移动)执行动态更新。或者,可以利用深度网络来执行视频插值(例如,在给定前几帧的情况下,预测人在下一帧中的位置),并利用流学习来基于其在每一帧中所犯的错误在视频流上更新该模型。流式学习的可能性几乎是无限的,因为它适用于深度网络应该立即从输入数据中学习的任何情况。因此,它(在我看来)是一个值得深度学习从业者关注的话题。

深度流学习的方法

现在,流学习已经被定义和激励,是时候学习如何在数据流上实际训练神经网络,而不会严重降低它们的性能。最近,在深度学习社区中提出了几种以流方式训练深度神经网络的算法[4,7,8]。对于每个算法,我将概述该方法的主要组件和细节,并强调在实践中实现该算法的主要实际考虑。在这一节中,我将重点介绍每种方法的主要细节,这些细节可以让实践者更好地理解哪种方法最适合给定的应用程序。

ExStream [4]

ExStream 于 2019 年 2 月提出,是一种基于重放的流式学习方法。这里,“重放”(也称为预演)用于描述将来自传入数据流的先前遇到的数据存储在缓冲区中的方法。然后,当新数据变得可用时,基于重放的方法将新数据与来自重放缓冲区的数据样本混合,并使用这种新旧数据的混合来更新模型,从而确保先前的知识得以保留。简而言之,这些方法用新旧数据的混合来训练网络,以确保网络暴露于来自数据流的一组平衡的示例。重播是在线学习中广泛使用的一种方法,既简单又有效,但它需要存储以前的数据,这会产生不可忽略的内存占用。

虽然 ExStream 证明了“完全”重放(即,将所有传入数据存储在重放缓冲区中,并在每次遇到新数据时循环通过重放缓冲区中的所有示例)消除了灾难性遗忘,但是还探索了不需要存储整个数据流的更节省存储器的重放机制。使用 ResNet50 [9]来执行图像分类,ExStream 预训练并固定底层模型的卷积层(即,在流式传输过程中不会更新任何卷积层参数),并专注于以流式传输方式学习最终的全连接层。因此,存储在重放缓冲器中的所有例子都是简单的向量(即,ResNet 的特征提取器/主干的输出)。使用这些特征向量作为输入,ExStream 为每类数据维护一个单独的固定大小的重放缓冲区(即,每类只能存储c个向量),并旨在发现一种算法,该算法使 i) 最大限度地减少必须存储以供重放的向量数量(即,这限制了内存开销) ii) 保持最先进的分类性能(即,可与完全重放相比)。

为了实现这些目标,ExStream 利用以下规则集在流式传输期间维护其重放缓冲区:

  • 保持c簇质心(即,只是向量!)每个类,每个类都有一个与之相关联的“计数”。
  • 在数据流中遇到一个类的c示例之前,只需将每个向量添加到重放缓冲区,计数为 1。
  • 一旦给定类的缓冲区已满,并且该类的新示例到达,找到两个最近的聚类质心(基于欧几里德距离),并通过基于它们各自的计数对向量进行加权平均来将它们合并在一起。将结果质心的计数设置为前两个质心的计数之和。
  • 一旦两个质心合并(从而为新的质心腾出空间),将新的数据示例添加到缓冲区中,计数为 1。

使用如上所述维护的重放缓冲区,ExStream 然后通过采样和混合来自不同类的聚类质心与传入数据来执行重放,以对模型参数执行更新。与用于在重放缓冲区内维护聚类质心的几种其他算法(例如,在线 k-means、CluStream [10]、HPStream [11]等)相比,),ExStream 表现出最佳性能。此外,通过调整重放缓冲区内每个类所允许的质心数量,可以很容易地调整算法的内存占用量(尽管重放缓冲区太小可能会导致较差的性能)。ExStream 在 Core50 和 iCUB 数据集上表现良好,但在后来的工作发表之前,没有应用于大规模分类问题(如 ImageNet)。

深沉的 SLDA [7]

深度流线性判别分析(SLDA)于 2020 年 4 月提出,是深度流学习的另一种方法,它脱离了基于重放的方法(即,它不保持任何重放缓冲)。因此,与需要重放缓冲区的 ExStream 等方法相比,它的内存效率非常高,从而(潜在地)使其适合内存受限的学习场景(例如,设备上学习)。SLDA 是一个已经建立的算法[12],已经用于数据挖掘社区中的数据流分类。在深度 SLDA 中,通过使用固定的 ResNet18 [9]主干的 i) 将 SLDA 算法与深度神经网络相结合,以获得每个数据示例的特征向量,并通过使用 SLDA 的【T2 ii)以流的方式对这些特征向量进行增量分类。同样,除了最终分类模块(即,SLDA 组件),所有网络层在深度 SLDA 的流式传输过程中是固定的。

用 SLDA 以递增的方式对特征向量进行分类的细节超出了本文的范围——这种算法很复杂,可能需要一篇完整的博文来真正理解它。然而,在高层次上,SLDA 通过 i) 用相关计数维护每个类的单个平均向量,以及 ii) 构建表征类表示之间关系的共享协方差矩阵来操作。当新数据变得可用时,为每个类更新均值向量,而协方差矩阵可以保持固定(在训练数据子集上的一些基础初始化之后)或者在流式传输过程中递增地更新。在测试时,可以使用平均类向量与协方差矩阵的逆矩阵的封闭形式的矩阵乘法来推断新数据示例的类输出。

与 ExStream 等基于重放的方法相比,SLDA 具有优势,因为它显著降低了内存需求,只需存储每个类的一个向量和一个共享协方差矩阵。此外,即使在 ImageNet 这样的大规模数据集上,SLDA 也能产生令人印象深刻的分类性能,优于 ExStream [4]、iCarl [13]和端到端增量学习[14]等流行方法;参见[8]中的表 1。此外,与大规模数据集上的正常离线神经网络训练相比,深层 SLDA 的挂钟训练时间几乎可以忽略不计。总的来说,该方法在规模上令人惊讶地有效,因为它的计算和内存需求最小

提醒[8]

REMIND 于 2020 年 7 月发布,是最近提出的一种基于重放的深度流学习方法。REMIND 不像 ExStream 那样在重放缓冲区中维护簇质心,而是为传入流中遇到的每个数据示例存储单独的缓冲区条目。在以前的工作中,这是通过在重放缓冲器[13,14]中存储原始图像来完成的。然而,在 REMIND 中,作者提出,神经网络中的中间激活(即,这些激活不仅仅是一个向量——它们可能具有空间维度)应该存储在重放缓冲区中,而不是原始图像中,这 i) 极大地减少了每样本的内存需求,而 ii) 模拟了海马索引理论概述的大脑中压缩记忆的重放。

为了使上述策略成为可能,REMIND 采用了 ResNet18 [9]架构,并冻结了网络的初始层,使得这些层的参数在流式传输过程中不会改变。类似于深度 SLDA,这些冻结参数的值是使用某个基础初始化阶段在训练数据的子集上设置的。然后,对于在流式传输期间遇到的每个示例,REMIND i) 通过网络的冻结层传递示例以提取中间激活, ii) 使用乘积量化(PQ)策略压缩激活张量[15],并且 iii) 将量化的向量存储在重放缓冲器中。然后,使用新数据(在它已经被量化之后)和来自重放缓冲器的采样激活的组合作为输入,在最终网络层(即,那些没有被冻结的网络层)上执行在线更新。在实践中,REMIND 对从重放缓冲区采样的激活执行随机裁剪和混合,这提供了正则化的好处,并产生适度的性能改进。

由于 REMIND 的内存高效的重放方法,它可以用有限的开销维护非常大的重放缓冲区。例如,在 ImageNet 数据集上,REMIND 可以维护大约 1M 样本的缓冲区,其内存占用与 10K 原始图像的重放缓冲区相同。因此,REMIND 在许多在线学习的常见基准测试中明显优于 ExStream 和 Deep SLDA;参见[8]中的表 1。在大规模数据集(例如 Imagenet)上,REMIND 的性能优势尤其明显,在这种情况下,REMIND 能够在有限的内存中存储许多重放示例,这使得它真正脱颖而出。目前,REMIND 是在流领域训练深度网络的最佳方法。

与一般在线学习的联系

现在已经概述了深度流学习的现有方法,人们可能会开始问这些方法如何与为其他在线学习设置(例如,批量增量学习或终身学习)提出的方法相关联。为了更全面地描述在线学习的所有方法,我推荐我之前关于这个话题的文章。然而,我试图在下面的高层次上概述这些方法。

  • Replay: 广泛用于流学习和在线学习。
  • 知识蒸馏:广泛应用于在线学习技术中,但还没有探索用于流学习。虽然知识提炼可以为流式学习技术提供一些好处,但最近的几篇论文认为,当与重放结合时,知识提炼提供的好处很少[16,17]。
  • 偏差修正:未在流设置内测试,但对增量学习非常有益。

在线学习的若干其他方法还没有在流设置中探索过(例如,架构修改或基于正则化的方法)。然而,这些方法中的许多在当前的在线学习研究中不太受欢迎,因为它们在应用于大规模问题时表现不佳。因此,这些方法不太可能胜过大规模流式学习的成熟方法,如 REMIND。

实践中用什么最好?

尽管这篇文章中概述的深度流学习的所有方法都是有用的,但从业者可能想知道哪种方法最适合他们的应用。在性能方面,REMIND 是迄今为止为深度流学习提出的性能最好的方法。这可以从 REMIND [8]论文的表 1 中看出,REMIND 的表现明显优于 ExStream 和 Deep SLDA。此外,REMIND 甚至已经扩展到问题领域,如对象检测[16],从而展示了它在图像分类以外的应用中的效用。

ExStream 和 REMIND 都需要存储一个重放缓冲区,并且具有相似的计算效率,因此 REMIND 是两者之间显而易见的选择。然而,深度 SLDA 不需要维护这样的重放缓冲器,并且可以非常快速地被训练。因此,即使 REMIND 实现了更好的性能,深度 SLDA 在内存或计算资源有限的情况下可能是有利的。否则,REMIND 在实践中是深度流学习的最佳选择,因为它可以实现令人印象深刻的性能,并通过量化最小化重放缓冲区的内存占用。

对于那些感兴趣的人来说,REMIND [17]和 Deep SLDA [18]的实现都可以通过 github 公开获得。

结论

在这篇文章中,我概述了数据流上深度神经网络的训练,包括讨论为什么这样的训练范式实际上是相关的,并描述了以这种方式训练深度网络的现有方法。在深度流学习的相关方法中,REMIND 实现了最佳性能,而深度 SLDA 等方法可能在内存或计算资源有限的情况下有用。

非常感谢你阅读这篇文章。如果你有任何反馈或总体上喜欢这篇文章,并希望了解我未来的工作,请随时在 twitter 上关注我或访问我的网站。这项工作是我在 Alegion 做研究科学家和在莱斯大学做博士生工作的一部分。如果你喜欢这篇文章中的内容,我鼓励你去看看 Alegion 的空缺职位,或者联系我的研究实验室

引文

[1]https://arxiv.org/abs/1412.2485

[2]https://ieeexplore.ieee.org/abstract/document/8622392

[3]https://epubs.siam.org/doi/abs/10.1137/1.9781611974317.7

[4]https://arxiv.org/abs/1809.05922

[5]https://www . science direct . com/science/article/ABS/pii/s 0079742108605368

https://arxiv.org/abs/1708.02072

https://arxiv.org/abs/1909.01520

https://arxiv.org/abs/1910.02509

https://arxiv.org/abs/1512.03385

https://www.vldb.org/conf/2003/papers/S04P02.pdf

[11]https://www . semantic scholar . org/paper/A-Framework-for-Projected-Clustering-of-High-Data-Aggarwal-Han/317 c 0 F3 A 829 ee 8 f 0 B3 d 7 E5 A 915 A 93 c 52 baa 7 a9 e 8

https://ieeexplore.ieee.org/document/1510767

https://arxiv.org/abs/1611.07725

https://arxiv.org/abs/1807.09536

[15]https://lear . inrialpes . fr/pubs/2011/JD S11/jegou _ searching _ with _ quantization . pdf

https://arxiv.org/abs/2008.06439

https://github.com/tyler-hayes/REMIND

https://github.com/tyler-hayes/Deep_SLDA

如何用 PyGAD 遗传算法训练 Keras 模型

原文:https://towardsdatascience.com/how-to-train-keras-models-using-the-genetic-algorithm-with-pygad-9d9d626782d1?source=collection_archive---------19-----------------------

PyGAD 是一个开源的 Python 库,用于构建遗传算法和训练机器学习算法。它提供了广泛的参数来定制遗传算法,以处理不同类型的问题。

PyGAD 拥有自己的模块,支持构建和训练神经网络(NNs)和卷积神经网络(CNN)。尽管这些模块运行良好,但它们是在 Python 中实现的,没有任何额外的优化措施。这导致即使是简单的问题也需要相对较长的计算时间。

PyGAD2 . 8 . 0(2020 年 9 月 20 日发布)开始,一个名为kerasga的新模块支持训练 Keras 模型。尽管 Keras 是用 Python 构建的,但速度很快。原因是 Keras 使用 TensorFlow 作为后端,TensorFlow 高度优化。

本教程讨论如何使用 PyGAD 训练 Keras 模型。讨论内容包括使用顺序模型或函数式 API 构建 Keras 模型、构建 Keras 模型参数的初始群体、创建合适的适应度函数等等。

您也可以跟随本教程中的代码,并在来自 ML Showcase 的渐变社区笔记本上免费运行它。

完整的教程大纲如下:

  • 开始使用 PyGAD
  • pygad.kerasga模块
  • 使用 PyGAD 训练 Keras 模型的步骤
  • 确定问题类型
  • 创建一个 Keras 模型
  • 实例化pygad.kerasga.KerasGA
  • 准备培训数据
  • 损失函数
  • 适应度函数
  • 生成回调函数(可选)
  • 创建一个pygad.GA类的实例
  • 运行遗传算法
  • 健身与世代图
  • 有关已定型模型的统计信息
  • 回归的完整代码
  • 使用 CNN 分类的完整代码

让我们开始吧。

图片来自 Unsplash:https://unsplash.com/photos/zz_3tCcrk7o

PyGAD 入门

要开始本教程,安装 PyGAD 是必不可少的。如果您已经安装了 PyGAD,检查__version__属性以确保根据下一个代码至少安装了 PyGAD 2.8.0。

import pygadprint(pygad.__version__)

可以从 PyPI (Python 包索引)获得,然后可以使用pip安装程序进行安装。确保安装 PyGAD 2.8.0 或更高版本。

pip install pygad>=2.8.0

PyGAD 标志

安装完成后,您就可以开始了。阅读文档阅读文档:pygad . readthedocs . io。该文档包括一些示例。

下一段代码解决了一个简单的优化线性模型参数的问题。

import pygad
import numpyfunction_inputs = [4,-2,3.5,5,-11,-4.7] # Function inputs.
desired_output = 44 # Function output.def fitness_func(solution, solution_idx):
    output = numpy.sum(solution*function_inputs)
    fitness = 1.0 / (numpy.abs(output - desired_output) + 0.000001)
    return fitnessnum_generations = 100
num_parents_mating = 10
sol_per_pop = 20
num_genes = len(function_inputs)ga_instance = pygad.GA(num_generations=num_generations,
                       num_parents_mating=num_parents_mating,
                       fitness_func=fitness_func,
                       sol_per_pop=sol_per_pop,
                       num_genes=num_genes)ga_instance.run()ga_instance.plot_result()

pygad.kerasga模块

从 PyGAD 2.8.0 开始,引入了一个名为kerasga的新模块。它的名字是 KerasGgenicA算法的简称。该模块提供以下功能:

  • 使用KerasGA类构建解决方案的初始群体。每个解决方案都包含 Keras 模型中的所有参数。
  • 使用model_weights_as_vector()功能将 Keras 模型的参数表示为染色体(即 1D 向量)。
  • 使用model_weights_as_matrix()功能从染色体中恢复 Keras 模型的参数。

pygad.kerasga模块有一个名为KerasGA的类。这个类的构造函数接受两个参数:

  1. model:Keras 车型。
  2. num_solutions:群体中解的数量。

基于这两个参数,pygad.kerasga.KerasGA类创建了 3 个实例属性:

  1. model:对 Keras 模型的引用。
  2. num_solutions:群体中解的数量。
  3. population_weights:保存模型参数的嵌套列表。该列表在每一代之后更新。

假设 Keras 模型保存在model变量中,下一段代码创建一个KerasGA类的实例,并将其保存在keras_ga变量中。num_solutions参数被赋值为 10,这意味着群体有 10 个解。

构造函数创建一个长度等于num_solutions参数值的列表。列表中的每个元素在使用model_weights_as_vector()函数转换成 1D 向量后,为模型的参数保存不同的值。

基于KerasGA类的实例,初始群体可以从population_weights属性返回。假设模型有 60 个参数,有 10 个解,那么初始种群的形状就是10x60

import pygad.kerasgakeras_ga = pygad.kerasga.KerasGA(model=model,
                                 num_solutions=10)initial_population = keras_ga.population_weights

下一节总结了使用 PyGAD 训练 Keras 模型的步骤。每一个步骤都将在单独的章节中讨论。

使用 PyGAD 训练 Keras 模型的步骤

使用 PyGAD 训练 Keras 模型的步骤总结如下:

  • 确定问题类型
  • 创建一个 Keras 模型
  • 实例化pygad.kerasga.KerasGA
  • 准备培训数据
  • 损失函数
  • 适应度函数
  • 生成回调函数(可选)
  • 创建一个pygad.GA类的实例
  • 运行遗传算法

接下来的小节将讨论这些步骤。

确定问题类型

问题类型(分类或回归)有助于准备以下内容:

  1. 损失函数(用于构建适应度函数)。
  2. Keras 模型中的输出图层。
  3. 训练数据。

对于回归问题,损失函数可以是平均绝对误差、均方误差或本页中列出的另一个函数,该页总结了回归的 Keras 损失函数:keras.io/api/losses/regression_losses

对于分类问题,损失函数可以是二进制交叉熵(对于二进制分类)、分类交叉熵(对于多类问题),或者在本页中列出的另一个函数,其总结了 Keras 分类损失函数:keras.io/api/losses/probabilistic_losses

输出层中的激活函数根据问题是分类还是回归而不同。对于分类问题,与回归的线性相比,它可能是 softmax

如果问题是回归,那么每个样本的输出相对于分类问题中的类标签是一个连续的数。

总之,确定问题的类型以便正确选择训练数据和损失函数是至关重要的。

创建一个 Keras 模型

构建 Keras 模型有 3 种方式:

  1. 时序模型
  2. 功能 API
  3. 模型子类化

PyGAD 支持使用顺序模型和函数式 API 构建 Keras 模型。

顺序模型

对于顺序模型,这里有一个构建 Keras 模型的例子。简单地说,使用tensorflow.keras.layers模块创建每一层。然后,创建一个tensorflow.keras.Sequential类的实例。最后,使用add()方法将图层添加到模型中。

import tensorflow.kerasinput_layer  = tensorflow.keras.layers.Input(3)
dense_layer1 = tensorflow.keras.layers.Dense(5, activation="relu")
output_layer = tensorflow.keras.layers.Dense(1, activation="linear")model = tensorflow.keras.Sequential()
model.add(input_layer)
model.add(dense_layer1)
model.add(output_layer)

请注意,输出层的激活函数是linear,这意味着问题是回归。对于一个分类问题,函数可以是softmax。在下一行中,输出层有 2 个神经元(每个类 1 个),它使用softmax激活函数。

output_layer = tensorflow.keras.layers.Dense(2, activation="linear")

功能 API

对于功能性 API 案例,每一层通常都是作为顺序模型案例创建的。每一层,或者输入层,都被用作一个接受前一层作为参数的函数。最后,创建了一个tensorflow.keras.Model类的实例,它接受输入和输出层作为参数。

input_layer  = tensorflow.keras.layers.Input(3)
dense_layer1 = tensorflow.keras.layers.Dense(5, activation="relu")(input_layer)
output_layer = tensorflow.keras.layers.Dense(1, activation="linear")(dense_layer1)model = tensorflow.keras.Model(inputs=input_layer, outputs=output_layer)

创建 Keras 模型后,下一步是使用KerasGA类创建 Keras 模型参数的初始群体。

实例化pygad.kerasga.KerasGA

通过创建一个pygad.kerasga.KerasGA类的实例,就创建了一个 Keras 模型参数的初始群体。下一段代码将前一节中创建的 Keras 模型传递给KerasGA类构造函数的model参数。

import pygad.kerasgakeras_ga = pygad.kerasga.KerasGA(model=model,
                                 num_solutions=10)

下一节将创建用于训练 Keras 模型的训练数据。

准备培训数据

基于问题的类型(分类或回归),准备训练数据。

对于有 1 个输出的回归问题,这里有一个随机生成的训练数据,其中每个样本有 3 个输入。

import numpy
​
# Data inputs
data_inputs = numpy.array([[0.02, 0.1, 0.15],
                           [0.7, 0.6, 0.8],
                           [1.5, 1.2, 1.7],
                           [3.2, 2.9, 3.1]])
​
# Data outputs
data_outputs = numpy.array([[0.1],
                            [0.6],
                            [1.3],
                            [2.5]])

对于 XOR 这样的二元分类问题,下面是它的训练数据。每个样本有 2 个输入。准备输出,以便输出层有 2 个神经元,每个类一个。

import numpy
​
# XOR problem inputs
data_inputs = numpy.array([[0, 0],
                           [0, 1],
                           [1, 0],
                           [1, 1]])
​
# XOR problem outputs
data_outputs = numpy.array([[1, 0],
                            [0, 1],
                            [0, 1],
                            [1, 0]])

下一节讨论回归和分类问题的损失函数。

损失函数

损失函数因问题类型而异。本节讨论 Keras 的tensorflow.keras.losses模块中用于回归和分类问题的一些损失函数。

回归

对于回归问题,损失函数包括:

  • tensorflow.keras.losses.MeanAbsoluteError()
  • tensorflow.keras.losses.MeanSquaredError()

查看本页了解更多信息。

下面是一个计算平均绝对误差的例子,其中y_truey_pred代表真实输出和预测输出。

mae = tensorflow.keras.losses.MeanAbsoluteError()
loss = mae(y_true, y_pred).numpy()

分类

对于分类问题,损失函数包括:

  • tensorflow.keras.losses.BinaryCrossentropy():二元分类。
  • tensorflow.keras.losses.CategoricalCrossentropy():多级分类。

查看本页了解更多信息。

下面是一个计算二元类熵的例子:

bce = tensorflow.keras.losses.BinaryCrossentropy()
loss = bce(y_true, y_pred).numpy()

基于损失函数,根据下一部分准备适应度函数。

适应度函数

分类或回归问题的损失函数都是最小化函数。遗传算法的适应度函数是最大化函数。因此,适应值是作为损失值的倒数来计算的。

fitness_value = 1.0 / loss

用于计算模型的适应值的步骤如下:

  1. 从 1D 向量恢复模型参数。
  2. 设置模型参数。
  3. 做预测。
  4. 计算损失值。
  5. 计算适应值。
  6. 返回适应值。

回归适合度

下一段代码构建了完整的适应度函数,它与 PyGAD 一起处理回归问题。PyGAD 中的 fitness 函数是一个常规的 Python 函数,它必须接受两个参数。第一个表示要计算适应值的解。另一个参数是群体内解的指数,这在某些情况下可能是有用的。

传递给适应度函数的解是 1D 向量。为了从这个向量恢复 Keras 模型的参数,使用了pygad.kerasga.model_weights_as_matrix()

model_weights_matrix = pygad.kerasga.model_weights_as_matrix(model=model, weights_vector=solution)

一旦参数被恢复,那么它们就被set_weights()方法用作模型的当前参数。

model.set_weights(weights=model_weights_matrix)

基于当前参数,模型使用predict()方法预测输出。

predictions = model.predict(data_inputs)

预测输出用于计算损失值。平均绝对误差被用作损失函数。

mae = tensorflow.keras.losses.MeanAbsoluteError()

因为损失值可能是 0.0 ,那么最好像0.00000001一样给它加上一个小值,避免在计算适应值时跳水归零。

solution_fitness = 1.0 / (mae(data_outputs, predictions).numpy() + 0.00000001)

最后,返回适应值。

def fitness_func(solution, sol_idx):
    global data_inputs, data_outputs, keras_ga, model
​
    model_weights_matrix = pygad.kerasga.model_weights_as_matrix(model=model,
                                                                 weights_vector=solution)
​
    model.set_weights(weights=model_weights_matrix)
​
    predictions = model.predict(data_inputs)

    mae = tensorflow.keras.losses.MeanAbsoluteError()
    solution_fitness = 1.0 / (mae(data_outputs, predictions).numpy() + 0.00000001)
​
    return solution_fitness

二元分类的适合度

对于二进制分类问题,这里有一个适用于 PyGAD 的适应度函数。假设分类问题是二元的,它计算二元交叉熵。

def fitness_func(solution, sol_idx):
    global data_inputs, data_outputs, keras_ga, model
​
    model_weights_matrix = pygad.kerasga.model_weights_as_matrix(model=model,
                                                                 weights_vector=solution)
​
    model.set_weights(weights=model_weights_matrix)
​
    predictions = model.predict(data_inputs)

    bce = tensorflow.keras.losses.BinaryCrossentropy()
    solution_fitness = 1.0 / (bce(data_outputs, predictions).numpy() + 0.00000001)
​
    return solution_fitness

下一节将构建一个在每代结束时执行的回调函数。

生成回调函数(可选)

对于每一代,遗传算法对解进行改变。在每一次生成完成后,可以调用一个回调函数来计算一些关于最新达到的参数的统计数据。

这一步是可选的,仅用于调试目的。

生成回调函数实现如下。在 PyGAD 中,这个回调函数必须接受一个引用遗传算法实例的参数,通过该参数可以使用population属性获取当前群体。

在这个函数中,一些信息被打印出来,比如当前的代数和最佳解的适应值。这种信息使用户能够通过遗传算法的进展来更新。

def callback_generation(ga_instance):
    print("Generation = {generation}".format(generation=ga_instance.generations_completed))
    print("Fitness    = {fitness}".format(fitness=ga_instance.best_solution()[1]))

创建一个pygad.GA类的实例

使用 PyGAD 训练 Keras 模型的下一步是创建一个pygad.GA类的实例。这个类的构造函数接受许多参数,这些参数可以在文档中找到。

下一段代码通过使用该应用程序中最少的参数传递来实例化pygad.GA类,这些参数是:

  • num_generations:世代数。
  • num_parents_mating:要交配的亲本数量。
  • initial_population:Keras 模型参数的初始群体。
  • fitness_func:健身功能。
  • on_generation:生成回调函数。

请注意,在KerasGA类的构造函数中,群体中的解的数量先前被设置为 10。因此,要交配的亲本数量必须少于 10 个。

num_generations = 250
num_parents_mating = 5
initial_population = keras_ga.population_weights
​
ga_instance = pygad.GA(num_generations=num_generations, 
                       num_parents_mating=num_parents_mating, 
                       initial_population=initial_population,
                       fitness_func=fitness_func,
                       on_generation=callback_generation)

下一部分运行遗传算法来开始训练 Keras 模型。

运行遗传算法

pygad.GA类的实例通过调用run()方法来运行。

ga_instance.run()

通过执行这个方法,PyGAD 的生命周期按照下图开始。

PyGAD 生命周期。版权归作者所有。

下一节讨论如何对训练好的模型得出一些结论。

健身与世代图

使用pygad.GA类中的plot_result()方法,PyGAD 创建了一个图形,显示了适应值是如何逐代变化的。

ga_instance.plot_result(title="PyGAD & Keras - Iteration vs. Fitness", linewidth=4)

有关已定型模型的统计信息

pygad.GA类有一个名为best_solution()的方法,它返回 3 个输出:

  1. 找到最佳解决方案。
  2. 最佳解决方案的适应值。
  3. 群体中最佳解决方案的索引。

下一段代码调用best_solution()方法并输出最佳解决方案的信息。

solution, solution_fitness, solution_idx = ga_instance.best_solution()
print("Fitness value of the best solution = {solution_fitness}".format(solution_fitness=solution_fitness))
print("Index of the best solution : {solution_idx}".format(solution_idx=solution_idx))

下一段代码从最佳解决方案中恢复 Keras 模型的权重。基于恢复的权重,该模型预测训练样本的输出。您还可以预测新样本的输出。

# Fetch the parameters of the best solution.
best_solution_weights = pygad.kerasga.model_weights_as_matrix(model=model,
                                                              weights_vector=solution)
model.set_weights(best_solution_weights)
predictions = model.predict(data_inputs)
print("Predictions : \n", predictions)

假设使用的损失函数是平均绝对误差,下一个代码计算它。

mae = tensorflow.keras.losses.MeanAbsoluteError()
abs_error = mae(data_outputs, predictions).numpy()
print("Absolute Error : ", abs_error)

接下来的部分列出了使用 PyGAD 构建和训练 Keras 模型的完整代码。

回归的完整代码

对于一个使用平均绝对误差作为损失函数的回归问题,这里是它的完整代码。

import tensorflow.keras
import pygad.kerasga
import numpy
import pygad
​
def fitness_func(solution, sol_idx):
    global data_inputs, data_outputs, keras_ga, model
​
    model_weights_matrix = pygad.kerasga.model_weights_as_matrix(model=model,
                                                                 weights_vector=solution)
​
    model.set_weights(weights=model_weights_matrix)
​
    predictions = model.predict(data_inputs)
​
    mae = tensorflow.keras.losses.MeanAbsoluteError()
    abs_error = mae(data_outputs, predictions).numpy() + 0.00000001
    solution_fitness = 1.0 / abs_error
​
    return solution_fitness
​
def callback_generation(ga_instance):
    print("Generation = {generation}".format(generation=ga_instance.generations_completed))
    print("Fitness    = {fitness}".format(fitness=ga_instance.best_solution()[1]))
​
input_layer  = tensorflow.keras.layers.Input(3)
dense_layer1 = tensorflow.keras.layers.Dense(5, activation="relu")(input_layer)
output_layer = tensorflow.keras.layers.Dense(1, activation="linear")(dense_layer1)
​
model = tensorflow.keras.Model(inputs=input_layer, outputs=output_layer)
​
weights_vector = pygad.kerasga.model_weights_as_vector(model=model)
​
keras_ga = pygad.kerasga.KerasGA(model=model,
                                 num_solutions=10)
​
# Data inputs
data_inputs = numpy.array([[0.02, 0.1, 0.15],
                           [0.7, 0.6, 0.8],
                           [1.5, 1.2, 1.7],
                           [3.2, 2.9, 3.1]])
​
# Data outputs
data_outputs = numpy.array([[0.1],
                            [0.6],
                            [1.3],
                            [2.5]])
​
num_generations = 250
num_parents_mating = 5
initial_population = keras_ga.population_weights
​
ga_instance = pygad.GA(num_generations=num_generations, 
                       num_parents_mating=num_parents_mating, 
                       initial_population=initial_population,
                       fitness_func=fitness_func,
                       on_generation=callback_generation)
ga_instance.run()
​
# After the generations complete, some plots are showed that summarize how the outputs/fitness values evolve over generations.
ga_instance.plot_result(title="PyGAD & Keras - Iteration vs. Fitness", linewidth=4)
​
# Returning the details of the best solution.
solution, solution_fitness, solution_idx = ga_instance.best_solution()
print("Fitness value of the best solution = {solution_fitness}".format(solution_fitness=solution_fitness))
print("Index of the best solution : {solution_idx}".format(solution_idx=solution_idx))
​
# Fetch the parameters of the best solution.
best_solution_weights = pygad.kerasga.model_weights_as_matrix(model=model,
                                                              weights_vector=solution)
model.set_weights(best_solution_weights)
predictions = model.predict(data_inputs)
print("Predictions : \n", predictions)
​
mae = tensorflow.keras.losses.MeanAbsoluteError()
abs_error = mae(data_outputs, predictions).numpy()
print("Absolute Error : ", abs_error)

代码完成后,下一张图显示适应值在增加,这是一个好迹象,因为 Keras 模型正在正确学习。

图片来自 PyGAD 文档。

以下是关于训练模型的更多细节。请注意,预测值接近正确值。平均相对误差为 0.018。

Fitness value of the best solution = 54.79189095217631
Index of the best solution : 0
Predictions : 
[[0.11471477]
 [0.6034051 ]
 [1.3416876 ]
 [2.486804  ]]
Absolute Error :  0.018250866

使用 CNN 分类的完整代码

下一个代码使用 Keras 构建一个卷积神经网络,用于对 80 幅图像的数据集进行分类,其中每幅图像的大小为100x100x3。注意,使用分类交叉熵是因为数据集有 4 个类。

可以从以下链接下载培训数据:

  1. dataset _ inputs . npy:https://github . com/ahmedfgad/NumPyCNN/blob/master/dataset _ inputs . npy
  2. dataset _ outputs . npy:https://github . com/ahmedfgad/NumPyCNN/blob/master/dataset _ outputs . npy
import tensorflow.keras
import pygad.kerasga
import numpy
import pygad
​
def fitness_func(solution, sol_idx):
    global data_inputs, data_outputs, keras_ga, model
​
    model_weights_matrix = pygad.kerasga.model_weights_as_matrix(model=model,
                                                                 weights_vector=solution)
​
    model.set_weights(weights=model_weights_matrix)
​
    predictions = model.predict(data_inputs)
​
    cce = tensorflow.keras.losses.CategoricalCrossentropy()
    solution_fitness = 1.0 / (cce(data_outputs, predictions).numpy() + 0.00000001)
​
    return solution_fitness
​
def callback_generation(ga_instance):
    print("Generation = {generation}".format(generation=ga_instance.generations_completed))
    print("Fitness    = {fitness}".format(fitness=ga_instance.best_solution()[1]))
​
# Build the keras model using the functional API.
input_layer = tensorflow.keras.layers.Input(shape=(100, 100, 3))
conv_layer1 = tensorflow.keras.layers.Conv2D(filters=5,
                                             kernel_size=7,
                                             activation="relu")(input_layer)
max_pool1 = tensorflow.keras.layers.MaxPooling2D(pool_size=(5,5),
                                                 strides=5)(conv_layer1)
conv_layer2 = tensorflow.keras.layers.Conv2D(filters=3,
                                             kernel_size=3,
                                             activation="relu")(max_pool1)
flatten_layer  = tensorflow.keras.layers.Flatten()(conv_layer2)
dense_layer = tensorflow.keras.layers.Dense(15, activation="relu")(flatten_layer)
output_layer = tensorflow.keras.layers.Dense(4, activation="softmax")(dense_layer)
​
model = tensorflow.keras.Model(inputs=input_layer, outputs=output_layer)
​
keras_ga = pygad.kerasga.KerasGA(model=model,
                                 num_solutions=10)
​
# Data inputs
data_inputs = numpy.load("dataset_inputs.npy")
​
# Data outputs
data_outputs = numpy.load("dataset_outputs.npy")
data_outputs = tensorflow.keras.utils.to_categorical(data_outputs)
​
num_generations = 200
num_parents_mating = 5
initial_population = keras_ga.population_weights
​
ga_instance = pygad.GA(num_generations=num_generations, 
                       num_parents_mating=num_parents_mating, 
                       initial_population=initial_population,
                       fitness_func=fitness_func,
                       on_generation=callback_generation)
​
ga_instance.run()
​
ga_instance.plot_result(title="PyGAD & Keras - Iteration vs. Fitness", linewidth=4)
​
# Returning the details of the best solution.
solution, solution_fitness, solution_idx = ga_instance.best_solution()
print("Fitness value of the best solution = {solution_fitness}".format(solution_fitness=solution_fitness))
print("Index of the best solution : {solution_idx}".format(solution_idx=solution_idx))
​
# Fetch the parameters of the best solution.
best_solution_weights = pygad.kerasga.model_weights_as_matrix(model=model,
                                                              weights_vector=solution)
model.set_weights(best_solution_weights)
predictions = model.predict(data_inputs)
# print("Predictions : \n", predictions)
​
# Calculate the categorical crossentropy for the trained model.
cce = tensorflow.keras.losses.CategoricalCrossentropy()
print("Categorical Crossentropy : ", cce(data_outputs, predictions).numpy())
​
# Calculate the classification accuracy for the trained model.
ca = tensorflow.keras.metrics.CategoricalAccuracy()
ca.update_state(data_outputs, predictions)
accuracy = ca.result().numpy()
print("Accuracy : ", accuracy)

下图显示了适应值是如何逐代演变的。只要适应度值增加,那么就增加代数,以达到更好的精度。

图片来自 PyGAD 文档。

以下是有关已训练模型的一些信息。

Fitness value of the best solution = 2.7462310258668805
Categorical Crossentropy :  0.3641354
Accuracy :  0.75

本文原载于 Paperspace 博客 。你可以在渐变 上免费运行我的教程的代码

结论

本教程讨论了如何使用名为 PyGAD 的 Python 3 库,使用遗传算法来训练 Keras 模型。Keras 模型可以使用顺序模型或函数式 API 来创建。

使用pygad.kerasga模块,创建 Keras 模型权重的初始群体,其中每个解决方案为模型保存一组不同的权重。这个种群随后按照 PyGAD 的生命周期进化,直到所有世代完成。

由于 Keras 后端 TensorFlow 的高速特性, PyGAD 可以在合理的时间内训练复杂的架构。

如何像专业人士一样训练神经网络!

原文:https://towardsdatascience.com/how-to-train-neural-networks-like-a-pro-1d2362768c1?source=collection_archive---------13-----------------------

用于处理神经网络训练问题的完整包,如过拟合/欠拟合、消失梯度、局部最小值、学习率策略等。

梅根·霍尔姆斯在 Unsplash 上的照片

在步入深度学习的世界时,许多开发人员试图建立神经网络,但结果令人失望。他们可能最终发现训练过程不能更新网络的权重,或者模型不能找到成本函数的最小值。这些是我们在训练神经网络时面临的非常常见的问题,因此,需要有一个好的策略来解决它们。

本博客将帮助读者在训练神经网络时理解和解决以下问题:

  1. 过度拟合 vs 欠拟合
  2. 消失渐变
  3. 局部最小值
  4. 设定正确的学习率策略
  5. 挑选迷你批次大小

我鼓励读者在继续下一步之前,查看以下博客,深入了解神经网络如何工作以及如何为不同的机器学习问题构建神经网络:

  1. 【了解神经网络基础知识(适用于初学者)
  2. 神经网络的激活函数和损失函数——如何选择合适的?

问题:过拟合与欠拟合

作者图片

当模型学习训练数据中的细节和噪声达到对新数据的模型性能产生负面影响的程度时,就会发生过度拟合。这意味着训练数据中的噪声或随机波动被模型拾取并学习为概念。问题是这些概念不适用于新数据,并对模型的概括能力产生负面影响。非参数和非线性模型在优化损失函数时更具灵活性,因此更有可能出现过度拟合。

另一方面,欠拟合指的是既不能对训练数据建模也不能推广到新数据的模型。

过拟合/欠拟合的概念与方差/偏差权衡问题密切相关。方差是如果使用不同的训练数据,损失函数的估计将改变的量。

  • 低方差:建议随着训练数据集的改变,对目标函数的估计进行小的改变。
  • 高方差:表示目标函数的估计值随着训练数据集的变化而发生较大变化。

另一方面,偏差是指模型做出的简化假设,以使损失函数更容易学习。

  • 低偏差:暗示对损失函数形式的假设较少。
  • 高偏差:暗示关于损失函数形式的更多假设

为了识别模型的正确拟合,我们可以查看机器学习算法在训练迭代/时期的数量上对训练和测试数据集的性能。

作者图片

随着算法的学习,模型在训练和测试数据上的误差下降。但是在某个点之后,训练数据集上的性能持续下降,但是模型也开始学习训练数据中的噪声。这可以从测试集中上升的误差看出来。最佳点是测试数据的误差开始上升之前的点(如上图所示)。

过拟合/欠拟合问题与历元数一起,是决定隐藏神经元数和隐藏层数的关键因素。它们决定了模型理解数据中复杂关系的能力。但是类似于纪元的数量,太多会导致过度拟合,太少会导致欠拟合。

解决办法

有三种流行的方法来克服这个问题:

  1. 提前停止:提前停止(也称为“提前终止”)是一种方法,它允许我们指定大量的训练时期,一旦模型性能在测试数据集上停止改善,就停止训练。它监视训练的进度,但在满足某些条件时也会停止训练。TensorFlow 包中有两个预定义的停止监视器:a .StopAtStepHook:训练在一定步数后停止
    b. NanTensorHook:监视丢失,如果遇到 NaN 丢失则停止训练
  2. 正则化:这是一种回归形式,它要么消除(L1 正则化)系数,要么将(L2 正则化)系数估计值缩小到零。因此,它不鼓励拟合复杂的模型以避免过度拟合的风险
  3. Dropout: Dropout 基于在不同架构上并行训练多个神经网络的思想。基本思想是,在训练期间,某些层输出被随机丢弃。因此,在每次迭代之后,输出基于神经网络中神经元的不同组合。

除了这些选项,我们还可以尝试以下关于隐藏层数的启发式建议:

“在实践中,通常情况是 3 层神经网络将优于 2 层网络,但是甚至更深(4、5、6 层)也很少有帮助。这与卷积网络形成鲜明对比,在卷积网络中,深度被认为是一个好的识别系统的极其重要的组成部分(例如,大约 10 个可学习层)。”~安德烈·卡帕西

最后,为了选择隐藏层中神经元的数量,我们可以遵循以下规则:

  1. 隐藏神经元的数量应该介于输入层和输出层的大小之间。
  2. 最常见的隐藏神经元数目是
    sqrt(输入层节点输出层节点)*
  3. 在随后的层中,隐藏神经元的数量应该不断减少,以越来越接近输出层的结构。

值得注意的是,所有这些都是启发式规则,应该根据问题陈述进行调整。

问题:消失渐变

一些激活函数,如 sigmoid 函数,具有非常小的导数,尤其是当输入值远离函数中心时。这意味着神经网络权重的更新速率非常小。这个问题随着我们添加更多的隐藏层而变得更糟,因为来自不同层的导数相乘,因此,大量小数字相乘,导致最终变化接近于零。这意味着模型不能做出足够的反应来找到最优值。

解决方案:

处理消失渐变的最好方法是用 ReLU 或 Tanh 等其他函数替换隐藏层中的 sigmoid 激活函数。请参考我的博客中可用的激活功能列表以及在哪里使用它们。

问题:局部最小值

作者图片

损失函数有许多波峰和波谷是很常见的。局部极小值是指在其邻域内但不在损失函数上的最小值。如上图所示,一旦我们的模型遇到局部最小值,简单的梯度下降算法无法找到任何方向来进一步最小化邻域中的损失函数,并将卡在那里。因此,我们将无法找到神经网络的最佳权重。

解决方案:

我们有两种选择来处理局部最小值问题:

  1. 随机重启:基本意思是我们可以从损失函数的不同点出发,从所有的点进行梯度下降。这种方法大大增加了我们找到全局最小值的机会。
  2. 动量:这种方法的灵感来自于一个物体在不平坦的表面上快速移动的想法,这样它的动量就会推动它越过小驼峰。基本思想是,在局部最小值处的梯度是零,但是在先前时段中的梯度将具有非零值,并且取它们的平均值将帮助我们在局部最小值处走出驼峰。形式上,动量是过去梯度的加权平均值,并且较大的权重被应用于最近的梯度,导致梯度的指数衰减平均值。权重通常称为速度,在 0 和 1 之间变化。找到速度值的最好方法是使用交叉验证。

问题:迷你批次大小

小批量梯度下降是梯度下降算法的一种变体,该算法将训练数据集分成小批量,用于计算模型误差和更新模型系数。这是梯度下降算法最常见的形式(其他选项是批处理和随机梯度下降)。批量大小由最小批量大小参数决定,我们选择它的方式会影响资源需求以及神经网络的训练速度。太少会导致训练进度缓慢,但有助于收敛到全局最小值。

选择高的迷你批次大小将导致更快的训练,但是需要更多的存储器和计算资源。它也有陷入局部最小值的风险。

解决方案:

32 的小批量是一个很好的开始,如果不行,我们也可以尝试 64、128 和 256。大多数问题最常用的一组值是:1、2、4、16、32、64、128 和 256。

问题:如何设置学习率

学习率是指在机器学习模型的训练过程中权重更新的量(也称为步长)。它是用于训练神经网络的重要超参数之一,通常的可疑值是 0.1、0.01、0.001、0.0001、0.00001、0.000001 和 0.000001。设置一个非常低的学习率,会使我们的模型在识别成本函数上的最小点方面非常慢,而选择一个高值会使我们错过最佳点,因为模型将继续大步前进。看看这种情况的极端版本,高学习率会导致模型的性能在训练时期之间振荡,这表明权重偏离了最佳值。在另一个极端,一个非常小的值可能会阻止模型收敛或陷入局部最小值。我们通常会面临三种情况:

  1. 训练期间验证误差快速下降:表示学习率选择良好
  2. 训练过程中验证误差下降非常缓慢:表示学习率需要提高
  3. 训练过程中验证误差缓慢增加:表示学习率需要降低

解决方案:

一些现代版本的随机梯度下降算法(如 Adam)允许自适应学习率,其中模型在训练数据集上的性能由算法监控,并且学习率作为响应进行调整。如果错误率开始下降,则学习率逐渐降低,如果错误率在多个时期内没有改善,则学习率增加。如果这不起作用,那么我们可以尝试其他优化器,如 AdaGrad 或 RMSProp(它们也有自适应学习速率机制)。在另一篇博客中,我将讨论可用于训练神经网络的各种优化器及其优缺点。

如果我们想要手动设置参数值,那么我们应该通过创建训练时期的损失线图来检查模型的学习动态,然后我们可以检查以下内容:

  • 学习的速度是快还是慢?
  • 指示低学习率值的错误率是否有非常小的变化?
  • 我们是否看到损失的振荡表明高学习率值?

我们也可以手动设置学习率计划,其中学习率在一定数量的时期后从最大值线性/指数地降低到最小值。

结论

我要感谢读者阅读了我的神经网络系列博客的最后一部分。这个博客的目的是帮助读者有效地训练他们的神经网络。我们了解到以下情况:

  1. 什么是欠拟合/过拟合和方差/偏差权衡,你如何处理它们?
  2. 哪个激活函数面临消失梯度问题?
  3. 随机重启和动量如何帮助我们避免局部极小问题?
  4. 如何设置迷你批次大小?
  5. 设定学习率的稳健策略是什么?

我将撰写一个单独的博客系列,介绍如何用 Python 实现这些解决方案(使用 Keras 和 Pytorch 库)。所以请保持关注!

你对这个博客有什么问题或建议吗?请随时留言。

感谢您的阅读!

如果你和我一样,对人工智能、数据科学或经济学充满热情,请随时添加/关注我的 LinkedInGithubMedium

马特·博茨福德在 Unsplash 上拍摄的照片

如何使用自定义数据集训练 StyleGAN2-ADA

原文:https://towardsdatascience.com/how-to-train-stylegan2-ada-with-custom-dataset-dc268ff70544?source=collection_archive---------6-----------------------

了解如何训练人工智能生成任何你想要的图像

生成的自行车插值[图片由作者提供]

你一直想知道如何训练自己的生成模型吗?第一次发现像这个人脸生成网站这样的 GAN 应用,一直在想怎么在其他东西上训练 GAN。幸运的是,作为我研究的一部分,我最近有机会训练一个自行车发电模型。在本文中,我将记录我在如何根据自己的图像训练 StyleGAN2-ADA 方面的经验。

StyleGAN 是 NVIDIA 最受欢迎的生成模型之一。StlyeGAN 的多个版本已经发布,我们将使用最新版本 StyleGAN2-ADA。为了避免重复,我不会解释 StyleGAN,因为有很多文章已经很好地解释了它。

https://jonathan-hui.medium.com/gan-stylegan-stylegan2-479bdf256299

训练 StyleGAN 的计算量很大。因此,如果你没有一个像样的 GPU,你可能想在云上训练。如果你决定在 Google Colab 上训练(这是免费的),有人为此制作了一个不错的笔记本

在教程中,我将使用自行车数据集 BIKED 。请随意使用您自己的数据集。只要确保所有的训练图像都是正方形的,并将它们放在同一个文件夹中。

在本文中,我将使用 StyleGAN2-ADA 的 Tensorflow 实现。确保使用 Tensorflow 版本 1,因为代码与 Tensorflow 版本 2 不兼容。或者,如果你喜欢 PyTorch,你可以使用最近发布的 PyTorch 版本。PyTorch 代码在性能上似乎稍快一些。如果您使用 PyTorch,您仍然可以遵循本教程,只是在数据集准备方面稍有不同。

要求

  • 64 位 Python 3.6 或 3.7。建议使用带有 numpy 1.14.3 或更新版本的 Anaconda3。
  • 建议使用 TensorFlow 1.14,但 Linux 上也支持 TensorFlow 1.15。不支持 TensorFlow 2.x。
  • 在 Windows 上,您需要使用 TensorFlow 1.14,因为标准的 1.15 安装不包括必要的 C++头文件。
  • 1-8 个高端 NVIDIA GPUs,至少 12 GB GPU 内存,NVIDIA 驱动程序,CUDA 10.0 工具包和 cuDNN 7.5

步伐

  1. 克隆 StyleGAN2-ADA 存储库并进入目录
git clone [https://github.com/NVlabs/stylegan2-ada.git](https://github.com/NVlabs/stylegan2-ada.git)
cd styelgan2-ada

2.下载或创建自己的数据集。我将使用我已经预处理过的 BIKED 数据集。你可以从 dropbox 下载我的预处理版本。

BIKED 数据集 [ CreativeGAN 的样本图像

# Dowload dataset
wget "https://www.dropbox.com/s/0ybsudabqscstf7/biked_dataset.tar.gz" -q -O biked_dataset.tar.gz# extract dataset
tar -zxvf biked_dataset.tar.gz# Delete the tar.gz file
rm biked_dataset.tar.gz

提取内容后,您将拥有一个名为 BIKED 的文件夹,其中包含 4510 个自行车设计的正方形图像。

注意 :如果使用自己的数据集,创建一个文件夹,将所有训练图像放入文件夹中。确保所有的图像都是正方形的,大小相同。

3.正在准备数据集

因为代码需要数据集。tfrecords 格式。我们首先需要将数据集转换成这种格式。StyleGAN2-ADA 已经编写了一个脚本来简化这种转换。

# first argument is output and second arg is path to dataset
python dataset_tool.py create_from_images ./datasets/biked biked

这将创建一个多分辨率。/datasets/biked/文件夹中的 tfrecord 文件。

4.培训风格 GAN2-ADA

# snap is how often you want to save the model and sample results
# res is what image resolution you want to train on
# augpipe is augmentation pipes, such as 'blit', 'geom', 'color', 'filter', 'noise', 'cutout' or combination of thesepython train.py --outdir ./results --snap=10 --data=./datasets/biked --augpipe=bgcfnc --res=512

您还可以修改许多其他参数,请随意查看 train.py 代码以了解关于这些参数的更多信息。

一旦您运行该命令,它将开始训练并定期保存结果和模型文件(。pkl),基于您提供的快照参数(在本例中,每 10kimg)。一旦你认为结果足够好或者 FID 开始平台期,你可以停止训练,使用最后保存的。pkl 文件。

一旦你有了模型文件,你就可以使用这个命令生成图像。

python generate.py --outdir=out --trunc=0.5 --seeds=600-605 --network={path_to_pkl_model_file}

您可以为种子提供一个范围或逗号分隔值。trunc 是截断技巧的值。截断值越高,输出越多样化或极端,但可能会降低图像质量。该值越低,图像质量越高,但多样性可能会降低。最大值为 1。

但是,如果你想生成插值视频或图像网格。可以参考我之前的文章。

5.转移学习或恢复培训

如果你的训练因为某种原因停止或崩溃。您仍然可以从上次保存的进度继续训练。您只需要添加— resume 参数和模型的路径(。pkl)文件。

此外,你也可以把这个论点用于迁移学习。与其从头开始训练,通常最好从一个预先训练好的模型开始,即使数据集本身并不相似。只需更换。由 StyleGAN-ADA 提供的预训练模型之一的 pkl 路径。

在这个例子中,我将在 biked 数据集上从我的预训练模型恢复训练。

python train.py --outdir ./results --snap=10 --data=./datasets/biked --augpipe=bgcfnc --res=512 --resume=full-bike-network-snapshot-004096.pkl

培训结果

这是一个经过一天的训练后,在特斯拉 P100 GPU 上 256x256 分辨率的训练结果的动画。

1 天的 StyleGAN2-ADA 训练进度。[图片由作者提供]

如果你喜欢我的作品,看看我的其他文章!

参考

[1] Regenwetter,l .,Curry,b .,和 Ahmed,F. (2021 年)。BIKED:数据驱动自行车设计的数据集和机器学习基准。

[2]诺巴里,A. H .,拉沙德,M. F .,,艾哈迈德,F. (2021)。CreativeGAN:编辑用于创造性设计综合的生成性对抗网络

[3]t . Karras,m . Aittala,j . hells ten,Laine,s .,Lehtinen,j .,& Aila,T. (2020 年)。用有限数据训练生成性对抗网络

如何使用 Python 和 docTR 训练用于车辆识别号(VIN)提取的文本检测和识别模型

原文:https://towardsdatascience.com/how-to-train-text-detection-recognition-models-for-vehicle-identification-number-vin-extraction-76857d1c2927?source=collection_archive---------19-----------------------

VIN(车辆识别号)是一个由数字和大写字母组成的 17 位字符串,作为汽车的指纹。它可以帮助识别任何汽车在其生命周期内,并获得有关它的具体信息。这个唯一的标识符在制造过程中被印在车辆的某个地方,以便人们在某些过程中需要时可以读取它,例如汽车租赁或销售。

几个月前,我们来自 Monk 的朋友联系了我们:这是一家人工智能公司,为汽车、保险和移动市场提供最先进的计算机视觉解决方案。他们正在开发一种视觉智能技术,能够在汽车生命周期的每个阶段检查世界上的任何汽车。

他们唯一关注的是建立最好的技术来检测、分类和评估车辆的损坏。能够自动读取 vin 对他们来说很重要,但不是核心业务,这是 Mindee 的优势所在。

VIN 使用案例

请注意,本文中车辆识别号的任何照片要么是故意伪造的,要么是模糊的。

问题的定义很简单:

  • 输入是写在汽车上的 VIN 的照片
  • 输出是一个 17 个字符长的字符串:VIN

端到端 VIN 提取

高精度地自动执行这项任务比看起来要难。主要困难是:

  • 输入的照片大多是在户外拍摄的,有很多噪声(亮度、水渍、阴影……),这使得检测和识别 VIN 变得困难
  • 虽然 VIN 是以非常标准的格式书写的,但是使用的字体并不标准,也不总是一样的,字母间距也有很大不同。
  • 校验和验证方法可以验证 vin,但并不适用于所有车辆。我们拒绝了这种后处理解决方案。
  • 最后但同样重要的是,VIN 并不总是照片中唯一的文字,使用传统的 OCR 方法是不够的,因为我们需要添加一层后处理来过滤掉不想要的字符。

噪声图像的几个例子:

噪声车辆识别号图像

我们做的第一件事是从开源库和基于云的 API 运行现成的 ocr。由于问题的性质,在文本检测和识别上的结果不够好。vin 是写在汽车上的,而不是写在文档上的,这也不是字符识别技术的常见用例。我们必须找到另一种使用 Python 和 docTR 的方法。

为什么要用 docTR?

DocTR 是为数据科学家和开发人员提供的一个 PythonOopticalCcharacterRecognition 库。端到端 OCR 是使用两阶段方法实现的:文本检测(本地化单词),然后是文本识别(识别单词中的所有字符)。

端到端 OCR 体系结构

DocTR 包括用于检测和识别任务的预训练模型。任何人都可以用它从图像或 pdf 中提取单词。您可以非常容易地测试它(更多信息见 docTR 文档)

1.装置

pip install python-doctr

2.Python hello world

from doctr.io import DocumentFile
from doctr.models import ocr_predictormodel = ocr_predictor(pretrained=True)
# PDF
doc = DocumentFile.from_pdf("path/to/your/doc.pdf").as_images()
# Analyze
result = model(doc)

但是正如我们前面提到的,没有一个 OCR 能很好地解决我们的 VIN 问题。通用 ocr 不是此用例的好解决方案,因为:

  • ocr 应该是通用的,当涉及到像 vin 照片这样的“野生”数据时,文本检测和文本识别的问题非常困难。
  • 通用 ocr 的输出列出了图像中书写的字符,即使它们都被准确地检测到,你如何从中重建 VIN 字符串?

为了摆脱这些限制,我们决定在检测和识别任务中对 VIN 数据的 docTR 模型进行微调,以获得更好的性能。这样,检测将只提取 VIN 字符(而不是周围的字符),我们将有一个用于读取它们的微调模型。该库包括基于预训练模型的用于检测和识别阶段的那些训练能力。由于这些预训练的模型,可以非常容易地根据 VIN 数据微调我们的模型:我们应该获得高精度,因为它们是根据数百万种数据预训练的。

我们的贡献者经常将最先进的模型添加到库中。以下是截至今日的可用型号列表:

文本检测

文本识别

这就是我们如何与尼古拉斯·舒尔(Nicolas Schuhl)一起解决车辆识别号提取案的。

我们的数据集

我们有 5000 张不同设备拍摄的车辆识别号照片,都来自不同的车辆。这是一个好的开始!Nicolas 告诉我们,他们的移动应用程序中有一个用于照片拍摄的布局模板,强制用户以正确的方向拍照。这使得问题变得简单,因为我们可以假设输入图像的方向是正确的。这也有助于我们确保 vin 不会过于偏斜:我们可以考虑大约 5°的最大绝对偏斜角度。

VIN 图像

我们的数据集包含方向错误的照片和角度超过 5°的倾斜 vin。我们从我们的数据集中删除了超过 5 加上一个小增量(不是 5,以保留训练集中的一些困难情况)的倾斜照片,并改变了方向,以使每张照片都是直的。

我们将 75%的数据用于训练,15%用于验证,10%用于测试集,我们小心地将它们放在一边。

注释文本检测数据集

DocTR 文本检测模型输出图像的分割热图,以及相对坐标中的插值多边形列表。

VIN 文本检测

为了训练这个模型,我们需要为每个图像提供对应于我们正在寻找的文本位置的多边形集。你可以在 docTR 参考文献上找到更多信息。

在我们的例子中,每个图像的标签是一个多边形,代表 VIN 在图像中的位置。

训练集和验证集必须以这种方式在文件夹中构建:

├── images
│   ├── sample_img_01.png
│   ├── sample_img_02.png
│   ├── sample_img_03.png
│   └── ...
└── labels.json

labels.json 文件将输入文件名映射到其多边形标签:

{
    "sample_img_01.png" = {
        'img_dimensions': (900, 600),
        'img_hash': "theimagedumpmyhash",
        'polygons': [[[x1, y1], [x2, y2], [x3, y3], [x4, y4]],...]
     },
     "sample_img_02.png" = {
        'img_dimensions': (900, 600),
        'img_hash': "thisisahash",
        'polygons': [[[x1, y1], [x2, y2], [x3, y3], [x4, y4]],...]
     }
     ...
}

我们使用我们的内部工具来注释这些数据,但是你可以找到许多很棒的商业软件(如 V7Kili )或开源软件(一个很好的基准这里是)来做这件事。

注释文本识别数据集

在 docTR 端到端管道中,文本识别模型将在第一文本检测阶段检测到的输入图像的裁剪作为输入。然后,该算法将对这些作物执行“读取”任务,以获得机器编码的字符串。

VIN 文本识别

注释识别数据集比检测要繁琐一些。我们再次使用我们的内部工具,它包括一个使用通用文本识别算法的预注释功能,以使它更容易。纠正几个字符确实比从头开始手动键入所有字符容易。你可以在很多商业注释软件上找到这个特性。

对于文本识别任务,docTR 要求数据集文件夹的结构与文本检测相同,并且labels.json文件应该用唯一的关联字符串映射每个输入文件名:

├── images
    ├── img_1.jpg
    ├── img_2.jpg
    ├── img_3.jpg
    └── ...
├── labels.json

labels.json文件将输入文件名映射到它们的输出字符串:

{
    labels = {
    'img_1.jpg': 'I',
    'img_2.jpg': 'am',
    'img_3.jpg': 'a',
    'img_4.jpg': 'Jedi',
    'img_5.jpg': '!',
    ...
}

训练模型

现在让我们跳到有趣的东西!正如您可能想象的那样,真实的过程实际上是在训练实验和数据清理之间来回多次以提高性能。但是出于本文的考虑,让我们考虑数据集第一次被完美地注释了。

我们将使用 TensorFlow 2 (TF)后端来训练我们的模型:这也可以使用 PyTorch 后端来实现,因为步骤非常相似。您可以通过以下方式使用 TF 或 PyTorch 后端安装 docTR:

张量流

pip install python-doctr[tf]

PyTorch

pip install python-doctr[torch]

确保您有 4 个必需的带注释数据的文件夹,例如:

├── detection_train
    ├── images
	├── train_det_img_1.jpg
	└── ...
	└── labels.json
├── detection_val
    ├── images
	├── val_det_img_1.jpg
	└── ...
	└── labels.json
├── recognition_train
    ├── images
	├── train_rec_img_1.jpg
	└── ...
	└── labels.json
├── recognition_val
    ├── images
	├── val_rec_img_1.jpg
	└── ...
	└── labels.json

文本识别模型训练

先说文本识别算法。

1.安装 docTR

pip install python-doctr[tf]

2.在您的笔记本电脑上克隆存储库

git clone [https://github.com/mindee/doctr](https://github.com/mindee/doctr)

3.导航到您刚刚克隆的 docTR repo,并进入识别参考文件夹。references/recognition 文件夹包含 TensorFlow 和 PyTorch 的培训脚本。

cd /path/to/doctr/references/recognition

4.使用 sar_resnet31 启动培训(此型号使用 resnet31 主干)

python train_tensorflow.py model=sar_resnet31  train_path=/path/to/your/train/recognition/dataset val_path=/path/to/your/val/recognition/dataset --vocab legacy_french --pretrained --wb --epochs 50

—预训练:将使用 Resnet31 主干训练模型的检查点从 docTR — SAR 开始训练模型。
— wb: 将启动一项关于权重&偏差的实验。如果你想使用 TensorBoard,你也可以使用
— tb:

根据您的机器规格,如果您没有足够的内存,您可能会得到一个内存不足(OOM)错误。如果出现此错误,请使用-b 参数减小批处理大小:

python train_tensorflow.py model=sar_resnet31 train_path=/path/to/your/train/recognition/dataset
val_path=/path/to/your/val/recognition/dataset --vocab legacy_french --pretrained --wb --epochs 50 -b 16

-b: 批量

验证步骤发生在每个时期之后,如果验证损失是所有时期中最低的,则检查点将保存在 references 文件夹中。

VIN 文本识别培训

该模型收敛非常快,并且能够在验证集上实现 80%的精确匹配。这可能看起来没那么多,但这是因为我们决定将倾斜的数据放在训练集中。我们将很快计算端到端指标,因为这是最重要的一项指标,然后看看进展如何。

文本检测模型训练

对于文本检测模型,步骤如下:

  1. 导航到/references/detection 文件夹
cd /path/to/doctr/references/detection

2.使用 db_resnet50 启动培训(此型号使用 resnet50 主干)

python train_tensorflow.py model=db_resnet50 train_path=/path/to/your/train/detection/dataset val_path=/path/to/your/val/detection/dataset --pretrained --wb

检测模型比识别模型更重要:在这个模型中,更有可能出现 OOM 错误。同样,如果发生这种情况,考虑减少批量大小。

使用预先训练好的模型来完成这项任务是非常重要的。docTR 模型被训练来检测图像中的任何单词,而我们只寻找 vin。通过只在 vin 上重新训练这个模型,我们对模型进行了微调,只检测 vin 并过滤掉任何周围的文本。

VIN 文本检测培训

检测指标比识别指标更难分析。虽然精度看起来非常高,但由于 IoU 不容易操作,我们将通过测试端到端管道来计算模型的性能。

测试训练好的模型

我们的模型保存在克隆的 docTR 存储库的 reference 文件夹中。

要查看模型的运行情况,代码非常简单:

from doctr.io import DocumentFile
from doctr.models import ocr_predictorDET_CKPT = "file:///path/to/detection/model/db_resnet50_XXXX/weights"
REC_CKPT = "file://path/to/recognition/model/sar_resnet31_XXXX/weights"model = ocr_predictor(det_arch='db_resnet50', reco_arch='sar_resnet31',pretrained=True)
model.det_predictor.model.load_weights(DET_CKPT)
model.det_predictor.model.postprocessor.unclip_ratio = 2
model.reco_predictor.model.load_weights(REC_CKPT)if __name__ == "__main__":
    # Image loading
    doc = DocumentFile.from_images("./path/to/image")
    # Models inference
    result = model(doc)
    # Max proba post processing rule for selecting the right VIN value among docTR results
    vin = ""
    for word in result.pages[0].blocks[0].lines[0].words:
        if word.confidence > confidence:
	     vin = word.value
	     confidence = word.confidence
    # Display the detection and recognition results on the image
    result.show(doc)

没有理由说文本检测算法完全适合优化文本识别算法的框的大小。为了找到最佳的参数,我们根据验证集微调了 invoke _ ratio 参数。这是用于扩展来自检测模型的输出多边形的因子,以便生成可以输入到文本识别模型中的方形框。由于这两个模型是分别训练的,因此默认参数没有理由是优化文本识别性能的最佳参数。

在我们的测试集上测试了经过训练的模型之后,我们实现了 90%的端到端精确匹配,考虑到数据数量少和用例的复杂性,这是非常好的。如果我们愿意,我们可以花更多的时间用一些想法来优化模型:

  • 检测模型在方形盒子上训练。DocTR 将很快支持旋转框,这将使我们对倾斜的照片有更好的鲁棒性。
  • 超参数微调:我们没有在这上面花太多时间。例如,我们注意到学习衰退对训练有很大的影响。我们手动测试了一些值,但是我们可以花更多的时间来运行这些参数的网格搜索。输入大小也很重要,我们使用了默认的 docTR 参数。
  • 仅用于算法主干部分的文本识别预训练模型:虽然拥有预训练模型非常好,但我们在使用它们时不能随意使用我们想要的词汇。我们询问 docTR 团队是否可以只为文本识别算法的主干部分获得预训练的模型,这样我们就可以用我们特定的词汇表训练分类头。一个问题被打开,他们将很快解决这个问题。
  • 当然,更多的数据…

结论

这个案例是端到端文本提取问题的一个很好的例子,它需要重新训练检测和识别层以获得更好的性能。使用通用 OCR 并试图提取您想要的关键信息可能会非常繁琐。您需要在原始 OCR 结果的基础上建立大量的后处理,它不太可能在简单的文本检测和识别任务中表现良好。

如果你有类似的用例,可以随时加入 Mindee 的 slack 社区 ,或者试用docTR并给我们你的反馈:)

如何用 Ray v1 更快的训练时间序列预测?第二部分,共三部分。

原文:https://towardsdatascience.com/how-to-train-time-series-forecasting-faster-using-ray-part-2-of-2-aacba89ca49a?source=collection_archive---------13-----------------------

时间序列预测使用谷歌的时间融合变压器 LSTM 版的 RNN 与 PyTorch 预测和火炬闪电

显示纽约市黄色出租车的乘坐量,以及 1 周每小时的预测。根据验证数据集,蓝色=观察到的,橙色=预测到的。由 Pytorch forecasting 实现的使用 Google 的时间融合转换器算法生成的预测,并由 Ray 并行化以实现更快的运行时间,无论是在笔记本电脑上还是在任何云上。图片作者。

在第 1 部分中,我的前一篇博客解释了当每个模型都被独立训练时,如何应用令人尴尬的并行模式来加速预测,例如使用传统的预测算法 ARIMA、预言者和神经预言者。数据、训练和推理由 Ray 引擎分布在本地笔记本电脑内核上。这个概念类似于多处理池,除了 Ray 可以处理分布更复杂的类和函数。与多处理不同,完全相同的代码也可以在任何云中的任何集群上并行运行。

这篇文章将解释当训练一个大型全球模型以预测许多目标时间序列时,如何使用 Ray 来加速深度学习预测。为什么要这么做?嗯,通常情况下,一个公司想要预测的东西是相互关联的,比如体育用品、相同品牌和颜色的洗衣机和烘干机、经常一起购买的超市物品等等。然后,每个目标时间序列都被用作同一个模型的输入,每个目标时间序列都得到不同的输出。

为全局深度学习模型的分布式运行时并行化代码需要分布式数据并行和模型并行。这需要分布式计算工作者之间的协作来分割数据,在每个具有其自己的数据片的工作者之间共享梯度,并将梯度组合到单个全局模型中。Ray 处理数据和模型并行性,同时为开发人员保留一个简单的 API。此外,Ray 可以并行训练和推断深度学习模型,分布在单个笔记本电脑的内核或任何云中的计算节点上。

本博客分为以下几个主题:

  • 介绍用于预测的深度学习人工智能算法
  • 在 Pytorch 预测中使用 Google 的时态融合转换器(使用 py torch Lightning API)
  • 如何使用 Ray 加速模型训练和推理
  • 如何使用 Anyscale 加速任何云中的模型训练和推理

介绍用于预测的深度学习人工智能算法

向左。RNN 的高级视图和展开的时间步骤。图片来源。中间。典型的 ANN 构造块,由 1 个输入层、2 个隐藏的密集层和 1 个输出层组成。图片来源。没错。示例 GRN 由 2 个致密层组成,具有 2 个激活函数(ELU 指数线性单位和 GLU 门控线性单位),以及脱落。图片来自时间融合转换器论文

递归神经网络 ( RNN )是一种常用于时间序列的神经网络,因为它按顺序处理数据。RNN 由一系列 ANN(人工神经网络)组成,通常每个时间步一个 ANN。RNN 架构允许顺序输入和顺序输出。每个 ANN 构件本身是一组神经元,分为输入层、隐藏层和输出层,其中每个神经元与其他神经元相连,每个连接具有可训练的权重。rnn 首先用于文本翻译。

以下是一些相关的概念术语。

LSTM(长短期记忆)是一种递归神经网络架构,旨在克服消失梯度问题(过去的事情可能接近 0 值权重)。LSTM 有 3 个记忆门,它们一起允许一个网络记住和忘记。

GRN 或门控剩余网络可以代替基本的 ANN 构建模块。具体包括:2 个致密层和 2 个激活函数(ELU 指数线性单元和谷氨酸门控线性单元)。这使得网络能够理解哪些输入转换是简单的,哪些需要更复杂的建模,以及哪些需要完全跳过。

编码器-解码器模型是一种 RNN,其中数据(训练数据)的输入序列可以与输出序列(验证或测试数据,也称为预测范围)具有不同的长度。位置编码被添加到输入嵌入中,以指示输入相对于整个时间序列的位置。

自我注意机制是为解决 LSTMs 的远程依赖问题(由于 LSTM 的遗忘门,重要信息可能丢失)而开发的一种进化。通过增加一个变压器,某些输入可以得到更多的“关注”,通过 RNN 网络进行前馈。在每个时间步,可学习的权重被计算为 Q 查询(具有特定的输入向量 w.r.t .其他输入)、 K ey(也包含该查询的输入嵌入)和 V 值(通常通过 Q,K 学习的权重的点积计算的输出向量)的函数。输出通过 RNN 网络进行前馈。由于 Q、K 都是从相同的输入中计算出来的,而这些输入又被应用于相同的输入,这个过程被称为“自我注意”。

多头注意力在每个时间步使用多个 Q,K 变换。纯自我关注使用每个时间步的所有历史数据。例如,如果 h=4 个注意头,则输入数据被分成 4 个块,然后使用 Q,K 矩阵将自我注意应用于每个块,以获得 4 个不同的 V 得分向量。这意味着单个输入被投射到 4 个不同的“表示子空间”上,并且通过 RNN 网络进行前馈。结果是更加细致入微的自我关注。从分布式计算的角度来看,这是理想的,因为来自多头注意力的每个块 h 可以在单独的处理器或工作器上异步运行。

回测。训练和验证数据被分割成滑动窗口的批次(每一批次是在未来移动 1 个值的前一批次)。这种技术被称为“回溯测试”,因为你不能像往常一样随机抽取 80/20 的训练/测试样本。顺序数据顺序必须保持不变。时间序列通常采用 context_length 大小的数据窗口进行训练,然后采用不同的 prediction_length 大小的窗口进行验证。

在 Pytorch 预测中使用 Google 的时态融合转换器实现的示例

本教程中使用的数据集是 8 个月的历史纽约市黄色出租车乘坐量。

我们的数据编码对象将是一个使用回溯测试技术重复折叠顺序数据的生成器。为了处理去趋势化,我们将使用 PyTorch Forecasting 的组规格化器,或每个 item_id 的批量规格化。每批分为 63 小时的训练输入和 168 小时或 1 周的预测目标。也就是说,使用 63/168 窗口长度对数据进行训练/有效采样,以保持数据的顺序完整。

网络设计将是 LSTM 版的 RNN,具有 GRN 构建块、编码器-解码器和多头注意力。我们将使用 PyTorch Forecasting 对谷歌的时间融合转换器的实现。PyTorch Forecasting 是为 PyTorch Lightning 开发的一套方便的 API。PyTorch Lightning 又是一套基于 PyTorch 之上的便利 API。这与 Keras 是 TensorFlow 之上的一组便利 API 的概念类似。

演示的代码是 github 上的

示例如何使用 Ray 加速模型训练和推理

Ray 是加州大学伯克利分校 RISELab 开发的开源库,该校还开发了 Apache Spark。Ray 使得并行化和分发 Python 代码变得很容易。代码可以在任何类型的内核上运行:a)你自己的笔记本电脑内核,AWS、GCP 或任何公共云中的集群。

这篇文章的其余部分假设你已经定义了一个 PyTorch 闪电模型,无论是通过普通的 PyTorch 闪电还是通过 PyTorch 预测。下面用粗体显示了您需要修改的代码部分,以使它能够在 Ray 上运行。

第一步。安装并导入RayRay 插件 为 PyTorch Lightning,以及any scale。确保您的 PyTorch Lightning 版本为 1.4。****

# Install these libraries in your conda environment  
conda install pytorch  
**pip install pytorch_lightning==1.4**   #required version for ray  
**pip install git+https://github.com/jdb78/pytorch-forecasting@maintenance/pip-install**  #used at time of writing this blog, check for updates  
**pip install ray  
pip install anyscale**  
**pip install ray_lightning**# Import these libraries in your .py or .ipynb code     
import torch   
import pytorch_lightning as pl    
import pytorch_forecasting as ptf   
**import ray**  
**from ray_lightning import RayPlugin**# PyTorch visualization uses Tensorboard
import tensorflow as tf #Tensorflow
import tensorboard as tb  #Tensorboard
#compatibility for PyTorch
tf.io.gfile = tb.compat.tensorflow_stub.io.gfile

第二步。根据笔记本电脑上的内核数量初始化 Ray (这是默认行为)。我的有 8 个内核。

# initialize ray, detects and uses all available CPU by default
**ray.init()**

****第三步。初始化 Ray Lightning 插件,也是为了你笔记本电脑上的内核数量。

# initialize the Ray Lightning plugin **plugin = \      
   RayPlugin(           
      num_workers=8,  #fixed num CPU        
      num_cpus_per_worker=1,           
      use_gpu=False,  #True or False    
      find_unused_parameters=False, #skip warnings    
   )**

步骤四。像往常一样,将您的数据转换为 PyTorch 张量,并定义 PyTorch 预测数据加载器。PyTorch 预测数据加载器 API 方便地将张量自动折叠到训练/测试回溯测试窗口中。

接下来,修改 PyTorch 闪电训练器来使用射线插件。在下面添加**plugins=[ray_plugin]**参数。

注意:示例数据与代码位于同一个 github repo 中。数据已经汇总到纽约每个地点的每小时出租车乘坐次数中。

# read data into pandas dataframe
filename = "data/clean_taxi_hourly.parquet"
df = pd.read_parquet(filename)# keep only certain columns
df = df[["time_idx", "pulocationid", "day_hour",
         "trip_quantity", "mean_item_loc_weekday",
         "binned_max_item"]].copy()# convert data to PyTorch tensors and PyTorch Forecasting loaders 
# PyTorch Forecasting folds tensors into backtest windows
train_dataset, train_loader, val_loader = \
     convert_pandas_pytorch_timeseriesdata(df)# define the pytorch lightning trainer
trainer = pl.Trainer(      
     max_epochs=EPOCHS,      
     gpus=NUM_GPU,      
     gradient_clip_val=0.1,        
     limit_train_batches=30,       
     callbacks=[lr_logger, 
                early_stop_callback],      
     # how often to log, default=50      
     logger=logger,      
     # To go back to regular python - just comment out below      
     # Plugin allows Ray engine to distribute objects     
     plugins=[**ray_plugin**] 
     )

最后,像往常一样定义一个 PyTorch 闪电(或预测)模型。并像往常一样拟合模型。

# define a pytorch forecasting model
model = ptf.models.TemporalFusionTransformer.from_dataset(   
             train_dataset,      
             learning_rate=LR,      
             hidden_size=HIDDEN_SIZE,      
             attention_head_size=ATTENTION_HEAD_SIZE,      
             dropout=DROPOUT,    
             hidden_continuous_size=HIDDEN_CONTINUOUS_SIZE,   
             loss=ptf.metrics.QuantileLoss(),      
             log_interval=10,      
             reduce_on_plateau_patience=4, 
             )# fit the model on training data
trainer.fit(
     model,      
     train_dataloaders=train_loader,         
     val_dataloaders=val_loader, 
)# get best model from the trainer
best_model_path = trainer.checkpoint_callback.best_model_path
best_model = \
ptf.models.TemporalFusionTransformer.load_from_checkpoint(
     best_model_path
)

就是这样!现在您的 PyTorch Lightning 模型将分布式运行。在幕后,Ray Lightning 插件 API 和 Ray 一起自动分发数据和模型。输入数据被自动完全分片,数据分片和训练函数被放置在每个并行工作器上,在工作器之间共享梯度,产生一个全局模型,并且结果模型作为请求的类型(PyTorch Lightning 或 PyTorch Forecasting 模型类型)被返回。

Ray 在幕后将全局模型的学习分布到 N 个计算节点上。输入数据被完全分片,每个节点上的每个工人得到相同的训练函数,梯度在并行工人之间共享,并且产生一个全局模型。图片作者。

以前,我试图在我的笔记本电脑上训练这个模型,但几个小时后中断了运行,因为第一个时期还没有结束。用 Ray 分发代码后,同样的代码运行大约 1 小时。

这些小的调整使得在一个相当小的计算资源(我的笔记本电脑)上在大约 1 小时内训练一个非常精确的 DL 全球预测模型成为可能。

Ray 的另一个好处是,现在代码可以在我的笔记本电脑上并行运行,我可以使用 Anyscale 在任何云上运行相同的代码,接下来我将展示这一点。

在 8 核笔记本电脑上运行的模型训练输出。iPython %% time 输出显示,训练一个非常准确的预测大约需要 1 个小时。

在 8 核笔记本电脑上运行的模型训练输出。使用对 1 周延迟验证数据的预测计算精确度。

如何使用 Anyscale 在任何云中加速模型训练和推理

接下来,为了更快地训练或进行推理,您可能希望在更大的实例或更大的集群上的云上运行相同的代码。为了在云上使用完全相同的射线代码,(AWS,GCP,…),你需要使用射线开源集群Anyscale 来简化任何云设置。

使用 Anyscale,您可以选择 a)在集群配置上进行 pip 安装和 github 克隆,或者 b)在运行时进行。更多信息见集群或运行时环境。首先使用集群配置,然后运行时配置(如果指定)将覆盖集群配置。

使用 Anyscale 在任何云上运行 Ray 代码的步骤如下:

第一步。 报名 参加 Anyscale 和 建立自己的账户

****第二步。创建集群配置。我这样做是为了方便,因为我有许多非典型的、较新的 ML 库要安装,并带有依赖项。打开浏览器到 Anyscale 控制台,在Configurations左侧菜单下,点击Create new environment按钮。见下面 Anyscale 控制台的图片。

  1. Cluster environment name。给你的环境配置起一个名字。
  2. 选择 Python 版本。
  3. 选择一个基本 docker 图像。我选择了anyscale/ray-ml:1.9.0-python38-gpu
  4. Pip packages下,见下图了解要安装的软件包和顺序。
  5. Post build commands下,如果您想自动安装该演示代码和数据,请参见下图。
  6. 点击Create按钮。

记下您的cluster-config-name:version_number。在下面的截图中,我的名字是christy-forecast-pytorch:13。下一步你会需要这个。

Anyscale 控制台,显示配置左侧菜单。主屏幕显示了一个示例配置,在基本 docker 映像上安装了额外的 pip 和 github clone。

****第三步。用云集群的名称和集群配置初始化光线

import anyscale # initialize ray on Anyscale to run on any cloud 
# name your cluster on the fly 
# set cluster_env parameter = your preconfigured cluster config name
ray.init(      
     **anyscale://my-cool-cluster**, #give your cluster any name   
     **cluster_env=christy-forecast-pytorch:13**, 
)

****第四步。用 num_workers=N 初始化 Ray Lightning 插件,其中 N > num cpu 在你的云集群的头节点上。如果指定任意数字< = N,Anyscale 将不会向外扩展。对于任意数量的 N,Anyscale 自动缩放将自动触发,直到您的帐户中配置的限制。如果您可以访问 GPU,请设置 GPU。

plugin = \
     RayPlugin(
          num_workers=**10**,              
          num_cpus_per_worker=1,              
          use_gpu=**True**,                  
     )

现在,像平常一样运行 python 代码(或笔记本)。它会自动在任何云中并行运行!当您的应用程序运行时,您可以在Clusters下的 Anyscale 控制台中监控您的云集群使用情况。

结论

这篇博客展示了为用于时间序列预测的 PyTorch Lightning 模型启用数据和模型并行性是多么容易。只需要最少的代码更改。一旦针对 Ray 进行了修改,相同的代码可以在您的笔记本电脑上并行运行,或者通过 Anyscale 在任何云上并行运行。

演示的完整代码在 github 上的

感谢 Jan Beitner, PyTorch Forecasting 的作者,接受我的拉动请求并创建了一个维护版本,用于本演示。

资源

  1. 雷 doc 页数:https://docs.ray.io/en/latest/using-ray.html
  2. PyTorch 闪电雷外挂:https://github.com/ray-project/ray_lightning
  3. PyTorch 预测:https://pytorch-forecasting.readthedocs.io/en/stable/
  4. Anyscale doc 页数:https://docs.anyscale.com/get-started
  5. 时态融合变换算法论文:https://arxiv.org/pdf/1912.09363.pdf
  6. 用于预测的 RNN 背景资料:https://assets . Amazon . science/0b/93/4117 a 5014 a F5 DD 487d 7 ffd 74 ab/deep-state-space-models-for-time-series-Forecasting . pdf
  7. 时间序列预测算法背景介绍:https://towards data science . com/the-best-deep-learning-models-for-Time-Series-Forecasting-690767 bc63f 0
  8. 数据和模型并行性背景介绍:https://arxiv.org/abs/1404.5997

最初发表于https://www.anyscale.com**

如何在自定义数据集上训练 YOLOX

原文:https://towardsdatascience.com/how-to-train-yolox-on-a-custom-dataset-bb2f94cdb038?source=collection_archive---------7-----------------------

(引用)

YOLO 家族继续发展下一款产品:YOLOX。在本帖中,我们将介绍如何训练 YOLOX 识别自定义用例的对象检测数据。

出于本教程的目的,我们使用公共血细胞对象检测数据集。但是,您可以将自己的数据导入到 Roboflow 中,并将其导出以训练该模型来满足自己的需求。本教程使用的 YOLOX 笔记本 可以在 这里 下载。

感谢旷视科技团队发布了 底层知识库 ,这构成了我们笔记本的基础。

在本指南中,我们采取了以下步骤:

  • 安装 YOLOX 依赖项
  • 通过 Roboflow 下载自定义 YOLOX 对象检测数据
  • 下载 YOLOX 的预训练重量
  • 运行 YOLOX 训练
  • 评估 YOLOX 性能
  • 对测试图像运行 YOLOX 推理
  • 导出保存的 YOLOX 重量以供将来推断

更喜欢 YouTube?

YOLOX 有什么新功能?

YOLOX 是 YOLO 模型的最新版本,在速度和准确性方面都达到了极限。YOLOX 最近赢得了流媒体感知挑战(CVPR 2021 自动驾驶研讨会)。

相对于其他 YOLO 检测网络的 YOLOX 评估

最大的建模变化包括移除盒锚(提高模型到边缘设备的可移植性)和将 YOLO 检测头解耦到用于盒分类和盒回归的单独特征通道(提高训练收敛时间和模型准确性)。

YOLOX 中的分离头

通过YOLOX中的历元加快训练时间。我们认为yolov 5时代更快(我们还没有运行任何直接的面对面测试)

许多其他令人兴奋的训练和推理考虑都包括在论文中。你可以在 YOLOX 论文或这个视频中更深入地探究。

安装 YOLOX 依赖项

为了设置我们的开发环境,我们将首先克隆基本的 YOLOX 库并下载必要的需求:

!git clone https://github.com/roboflow-ai/YOLOX.git %cd YOLOX !pip3 install -U pip && pip3 install -r requirements.txt !pip3 install -v -e . !pip uninstall -y torch torchvision torchaudio # May need to change in the future if Colab no longer uses CUDA 11.0 !pip install torch==1.7.1+cu110 torchvision==0.8.2+cu110 torchaudio==0.7.2 -f [https://download.pytorch.org/whl/torch_stable.html](https://download.pytorch.org/whl/torch_stable.html)

我们还将安装 NVIDIA Apex 和 PyCocoTools,以使该存储库按预期工作:

%cd /content/ !git clone https://github.com/NVIDIA/apex %cd apex !pip install -v --disable-pip-version-check --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" ./ !pip3 install cython; pip3 install 'git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI'

下载自定义 YOLOX 对象检测数据

在我们开始之前,您需要创建一个 Roboflow 帐户。我们将使用这个血细胞数据集,但是欢迎您使用任何数据集,无论是您自己加载到 Roboflow 的数据集还是其他公共数据集。

对于这个笔记本,我们将需要应用一些预处理步骤来确保数据能够与 YOLOX 一起工作。首先,创建一个 Roboflow 帐户(如果您还没有),然后派生数据集:

在分叉数据集之后,您将需要添加一个预处理步骤,将所有图像的大小调整为 640 x 640:

然后简单地生成数据集的新版本,用“ Pascal VOC ”导出。您将收到一个类似于以下内容的 Jupyter 笔记本命令:

复制该命令,并用 Roboflow 提供的命令替换笔记本中的下面一行:

!curl -L "[YOUR LINK HERE]" > roboflow.zip; unzip roboflow.zip; rm roboflow.zip

标注您的数据

如果你有自己的数据集,你可以在 Roboflow 中标注你的图像。

下载 YOLOX 的预训练重量

YOLOX 带有一些预训练的权重,以允许模型更快地训练并实现更高的精度。砝码有多种尺寸,但我们使用的砝码尺寸将基于小型 YOLOX 型号(YOLOX_S)。我们可以按如下方式下载:

%cd /content/ !wget https://github.com/Megvii-BaseDetection/storage/releases/download/0.0.1/yolox_s.pth %cd /content/YOLOX/

运行 YOLOX 训练

为了训练模型,我们可以运行tools/train.py文件:

!python tools/train.py -f exps/example/yolox_voc/yolox_voc_s.py -d 1 -b 16 --fp16 -o -c /content/yolox_s.pth

运行该命令的参数包括:

  • 经验文件:该文件允许我们在培训时更改基础模型的某些方面
  • 设备:我们的模型将训练的 GPU 数量— 1 是 Colab 提供的值 1
  • 批量大小:每批图像的数量
  • 预训练权重:指定您想要使用的权重的路径-这可以是我们下载的权重或您的模型的早期检查点

经过大约 90 个时代的训练,我们得到了以下 AP。

评估 YOLOX 性能

要评估 YOLOX 的性能,我们可以使用以下命令:

MODEL_PATH = "/content/YOLOX/YOLOX_outputs/yolox_voc_s/latest_ckpt.pth.tar" !python3 tools/eval.py -n yolox-s -c {MODEL_PATH} -b 64 -d 1 --conf 0.001 -f exps/example/yolox_voc/yolox_voc_s.py

运行评估后,我们得到以下结果:

YOLOX 模型的评估

性能看起来不错!

对测试图像运行 YOLOX 推理

我们现在可以在测试图像上运行 YOLOX 并可视化预测。要在测试映像上运行 YOLOX:

TEST_IMAGE_PATH = "/content/valid/BloodImage_00057_jpg.rf.1ee93e9ec4d76cfaddaa7df70456c376.jpg" !python tools/demo.py image -f /content/YOLOX/exps/example/yolox_voc/yolox_voc_s.py -c {MODEL_PATH} --path {TEST_IMAGE_PATH} --conf 0.25 --nms 0.45 --tsize 640 --save_result --device gpu

要在图像上可视化预测:

from PIL import Image OUTPUT_IMAGE_PATH = "/content/YOLOX/YOLOX_outputs/yolox_voc_s/vis_res/2021_07_31_00_31_01/BloodImage_00057_jpg.rf.1ee93e9ec4d76cfaddaa7df70456c376.jpg" Image.open(OUTPUT_IMAGE_PATH)

看起来模型像预期的那样工作!

导出保存的 YOLOX 重量以供将来推断

最后,我们可以将模型导出到我们的 Google Drive,如下所示:

from google.colab import drive drive.mount('/content/gdrive') %cp {MODEL_PATH} /content/gdrive/My\ Drive

结论

YOLOX 是一个令人难以置信的强大,最先进的对象检测模型。在本教程中,您可以学习如何:

  • 准备 YOLOX 环境
  • 使用 Roboflow 下载自定义对象检测数据
  • 运行 YOLOX 培训流程
  • 使用你训练过的 YOLOX 模型进行推理
  • 将您的模型导出到 Google Drive

快乐训练!

原载于 2021 年 8 月 2 日【https://blog.roboflow.com】

如何以分布式方式训练你的深度学习模型?

原文:https://towardsdatascience.com/how-to-train-your-deep-learning-models-in-a-distributed-fashion-43a6f53f0484?source=collection_archive---------8-----------------------

基于 Horovod 的 Azure ML 分布式训练实用方法

凯文·Ku 在 Unsplash 上的照片

深度学习算法非常适合大数据集,并且训练深度学习网络需要大的计算能力。由于 GPU/TPU 很容易按使用付费或免费获得(如 Google collab),今天有可能在类似云的 ImageNet 数据库上训练大型神经网络,例如 Resnet 152 (152 层),ImageNet 数据库有大约 1400 万张图像。但是一台支持多核 GPU 的机器是否足以训练庞大的模型呢?从技术上来说是的,但是训练这个模型可能需要几个星期。那么我们如何减少训练时间呢?任何可扩展性问题都可以使用两种方法来解决—纵向扩展或横向扩展。我们都知道,如果我们选择纵向扩展,容量会在某个时候达到极限,因此更好的替代方案是横向扩展。但是,你如何进行分布式训练,如果我使用 Jupyter 笔记本进行模型训练,我从哪里开始,我可以对任何深度学习模型进行分布式训练吗?这个博客旨在用一种实用的方法来回答这些问题。

在这篇博客中,我们将学习如何在云上应用横向扩展或者说分布式机器学习技术。我们将了解如何从 Jupyter 笔记本阶段(构建 ML 模型的最敏捷方式)过渡到可以在使用 Azure ML 和 Horovod 的 GPU 集群上运行的生产就绪型培训脚本。

如果你是分布式机器学习的新手,这里有一些概念/术语是你在继续学习之前应该知道的。

数据并行和模型并行

在数据并行方法中,整个模型被部署到一个集群的多个节点上,数据被分片(水平分割)。模型的每个实例都处理一部分数据。

数据并行训练。

在模型并行方法中,模型的一个层(或一组层)被部署在集群的一个节点上,并且整个数据被复制到该节点,每个节点在完整的数据集上训练。

模型平行训练。

最常见也最容易实现的是数据并行,我们将在接下来的章节中看到一种实用的方法。直观理解数据并行如何工作的一种方式是,在每个 GPU 节点中为一小批数据(比如一次 30 个图像)计算梯度,并且在网络的一轮前后传递结束时,更新的权重被发送回发起节点。来自每个节点的权重的加权平均值被应用于模型参数。更新的模型参数被发送回节点用于下一轮迭代。

这几乎类似于你以非分布式方式分批训练时发生的情况。然而,这里的关键问题是如何在数据并行方法中存储和更新模型参数。这就把我们带到了下一个话题,集中和去中心化的培训。

集中和分散培训。

在模型并行或数据并行训练中,关键是节点之间的通信,定义参数如何初始化、权重/偏差如何更新很重要。

有两种类型的沟通方式。这适用于数据并行和模型并行方法。在集中式通信模式中,存在负责同步模型参数的节点或节点组,该节点被称为参数服务器。这种方法的优点是很容易同步模型参数,另一方面,参数服务器本身可能成为大型集群的瓶颈。这也是一个单点故障。当然,通过引入多个并行服务器并确保应用适当的存储冗余,可以在一定程度上减少瓶颈问题。

在去中心化的通信模式中,每个节点与每个其他节点通信以更新参数。这种方法的优点是对等更新更快,稀疏更新可以通过仅交换已更改的内容来进行,并且没有单点故障。

集中培训与分散培训。

同步和异步更新。

如果你熟悉深度学习并知道如何训练权重(如果不是,你可以在这里阅读我的文章),一旦损失函数的梯度可用,就计算更新的权重。在使用数据并行方法的分布式训练中,可以用两种方式更新模型参数,即权重和偏差。

1.同步地:假设我们正在处理 10k 图像和 10 个节点,每个节点被给予 1k 图像的子集,一旦它们完成第一次迭代,更新的模型参数被发送到参数服务器。这种方法大大提高了模型的准确性,但这种方法的缺点当然是服务器必须等待所有节点完成迭代,如果有一个非常慢的服务器,它可能会降低整个训练的速度。

2.异步:在这种情况下,不是等待所有节点发送权重更新,而是一旦它们可用就发送,这增加了集群利用率并提高了训练速度,但是当然导致了陈旧梯度问题。大多数实现异步更新的框架都应用了一些策略来降低影响,以利于更高的集群利用率。

请记住,同步或异步更新适用于集中式和分散式培训方法。类似地,同步和异步更新可以应用于权重和对权重的更新,即,根据等式权重(新)=权重(旧)LR *梯度损失,在每次迭代之后,仅可以发送关于权重的梯度损失。为了更好地理解这一点,让我们想象一下,我们建立了一个具有同步更新和集中训练的集群,这意味着还有一个单独的参数服务,每个节点发送更新,一旦参数服务器上接收到所有更新,就计算新的权重,然后在所有节点上复制该权重,用于下一次迭代。

在讨论了如何存储和更新模型参数的优点和缺点之后,选择最佳参数总是取决于问题、数据集、聚类大小和各种因素。没有一个解决所有问题的正确方法。

实现分布式机器学习的框架

Map/Reduce、Apache Spark、百度 All Reduce、Horovod、Caffe2、微软认知工具包(CNTK)、dist faith、Tensorflow、DIANNE、MXNet、Petumm 是分布式机器学习可用的顶级框架。在这里可以找到每一项的简要介绍。

其中,以下是 Azure today 在工作区(PaaS)模型中支持的——Apache Spark、Horovod(它在 Databricks 和 Azure ML 上都可用)、TensorFlow 分布式培训,当然还有 CNTK。

Horovod 和天蓝色 ML。

分布式训练可以在 Azure ML 上使用 PyTorch、TensorFlow 这样的框架来完成。Tensorflow 的分布式训练支持集中式和分散式训练方法(更多信息这里),如果你已经有一个使用分布式 TF 的笔记本,你可以很容易地将其导入 Azure ML。在这篇文章中,我们将了解霍洛佛德。

Horovod 是一个开源的分布式深度学习框架,适用于 TF、Keras、PyTorch 和 Apache MXNet,它通过减少对并行运行在多个 GPU 节点上的训练脚本所做的更改数量,简化了分布式训练。你可以在这里了解更多关于霍洛佛德的信息。

使用 Horovod 设置环境时,您不必担心太多,Azure ML 提供了精选的培训环境,可以使用各种框架轻松设置培训,其中一个框架预装了 TensorFlow 和 Horovod。如果需要,这些策划的框架还允许定制。

注意:你也可以在 Azure ML 上使用上面解释的集中式或分散式训练方法运行原生分布式 TensorFlow。

从笔记本阶段到分布式 ML 的训练过程。

在这个例子中,我试图使用 CNN 对两类图像进行分类。这些图像属于胸部 X 射线,一类图像包含检测到积液的图像,另一类不包含。有关学习过程、预处理、消融实验等的更多信息。我推荐你参观这里的代码。

下图解释了从笔记本阶段到以分布式方式在集群上运行训练实验的过程。

下面是我在一个支持 Horovod 的 4 节点分布式训练集群上运行单个 GPU 训练脚本的代码片段。

import osfrom azureml.core import ScriptRunConfigimport shutilfrom azureml.core import Experimentfrom azureml.core import Environmentfrom azureml.core.conda_dependencies import CondaDependenciesfrom azureml.widgets import RunDetailsfrom azureml.core.runconfig import MpiConfiguration## The training script capable of running in distributed environment is extracted to effusion_detector_distributed.pyproject_folder = './effusion_detector-distributed'os.makedirs(project_folder, exist_ok=True)shutil.copy('effusion_detector_distributed.py', project_folder)## choosing an experiment nameexperiment_name = 'tf-distributed-effusion-detector'experiment = Experiment(ws, name=experiment_name)# loading the env dependencies from conda configurationos.makedirs('./envs', exist_ok=True)tf_env = Environment.from_conda_specification(name="imageclassification", file_path="envs/distributed-tensorflow-with-horovod/conda_dependencies.yml")# Specify a GPU base imagetf_env.docker.enabled = Truetf_env.docker.base_image = 'mcr.microsoft.com/azureml/openmpi3.1.2-cuda10.1-cudnn7-ubuntu18.04'# using a cluster which can autoscale uptp 4 nodes.cluster_name = "gpus"compute_target = ComputeTarget(workspace=ws, name=cluster_name)# running the scriptargs = ['--data-folder', dataset.as_mount(), '--epochs', 20]src = ScriptRunConfig(source_directory=project_folder,script='effusion_detector_distributed.py',arguments=args,compute_target=compute_target,environment=tf_env, distributed_job_config=MpiConfiguration(node_count=4))run = experiment.submit(src)print(run)run.get_details()

这里有一个图像显示了培训的结果,第一个实验是使用分布式培训(4 个节点,每个节点 6 个 GPU 核心)完成的,第二个实验是使用一台具有 6 个 GPU 核心的机器完成的。用于单机和集群的处理单元 GPU — 1 个 NVIDIA Tesla K80

分布式训练和单机训练的实验结果。

我在分布式培训中没有发现什么明显的不同。

  1. 训练时间从 7.5 分钟减少到 5 分钟。
  2. 为运行配置了 20 个时期,每个节点运行 5 个时期。(注意:这也意味着不能应用最小容差设置为 5 个时期的提前停止,在单机训练中,由于提前停止规则,训练最终停止)

该图显示了运行 5 个时期的工作进程 0。

3.每个工作进程都有一个私有 IP,日志显示它们都是相互连接的。

该图显示了给定私有 IP 的每个进程。

显示工作进程 0 连接到工作进程 3 的图像。

https://github.com/sriksmachi/octopus

附加阅读

-https://stack overflow . com/questions/53498952/tensor flow-horo VOD-nccl-and-MPI #:~:text = MPI % 20 is % 20 used % 20 for % 20 CPU,used % 20 for % 20g pu % 2d GPU % 20 communication

如何训练自己的张量流模型,并在任何平台上运行它们

原文:https://towardsdatascience.com/how-to-train-your-own-tensorflow-models-and-run-them-on-any-platform-6a1303d4c2d6?source=collection_archive---------20-----------------------

探索全球芯片短缺危机的解决方案。

训练自己的 TensorFlow Lite 模型为您提供了一个创建自己的定制 AI 应用程序的机会。此外,使用像 WasmEdge 这样的运行时,您就有机会在许多不同的平台上运行您的定制 TensorFlow 应用程序。包括共享硬件。稍后将详细介绍共享硬件…

照片由杰瑞米·零Unsplash 上拍摄

什么是 WasmEdge?

WasmEdge 是一个轻量级和高性能的 WebAssembly (WASM)虚拟机(VM ),针对边缘计算进行了优化。它广泛用于云无服务器功能(FaaS)、软件即服务(SaaS)、区块链智能合约和物联网以及实时汽车应用等场景。

CNCF 主办,WasmEdge 旨在成为 Wasm 及其 Edge 相关扩展的开源“参考实现”。

本文主要关注 WasmEdge 的 TensorFlow 扩展。可以通过 GitHub 了解更多 WasmEdge 如果您想为 WasmEdge 投稿,请参见该投稿人文档

我们为什么要使用 Wasm?

Wasm 生态系统仍处于早期阶段。然而,Wasm 相对于传统的执行环境有一些非常重要和独特的优势。

除了它的性能…

"在其超前(AOT)编译模式下,WasmEdge 是目前市场上速度最快的 Wasm 虚拟机."[1]

…一个独特的主张是 Wasm 可执行文件在独立的、基于堆栈的 Wasm 虚拟机中运行。这意味着任何不受信任的 Wasm 程序都可以在共享硬件上与其他 Wasm 程序一起运行;没有副作用。

您为什么想要共享硬件?

就制造业的未来而言,这是一件大事。例如,丰田最近宣布,他们将“因全球芯片短缺而削减 40%的汽车产量”[2]。

所有领域的消费电子产品,不管是什么类型,都有不断满足消费者需求的动力。这些需求包括不同种类的娱乐、信息娱乐、安全、反垃圾邮件、语音识别、物体检测等等。

能够在共享硬件上训练和运行复杂的人工智能应用程序(可以帮助满足这些消费者需求)对生产来说至关重要。以下是全球制造商的一些报价,它们证明了这一点。

大众

“德国大众汽车表示,它可能还需要进一步减产,并预计第三季度的芯片供应将‘非常不稳定和紧张’。”

福特

“福特汽车表示,由于半导体相关零件短缺,将暂时关闭其制造最畅销的 F-150 皮卡的堪萨斯城组装厂”

学习人工智能模型和数据

开始学习如何训练 TensorFlow 的最好方法是查看一些现成的 TensorFlow 训练数据。

我们的第一个例子是专门针对自然语言情感分析的。我们要检查一些训练数据。一旦您理解了这个特定的数据集,您就可以继续创建自己的训练数据,然后为特定的用例(无论是什么)训练和运行自然语言模型。

在我们的第二个例子中,我们也将从查看一些现成的数据开始;深入到关于边界框坐标等等的细节。

一旦我们了解了单发探测器(SSD)边界框的工作原理,我们就可以创建自己的训练数据,然后针对特定用例训练和运行 SSD 模型。

让我们从一些动手演示开始;请继续阅读,即使你不是编码。有许多图表和解释将使这容易理解。

第一个例子—自然语言、情感分析

亚历山大·辛恩在 Unsplash 上拍摄的照片

在开始之前,让我们运行几个命令来准备好我们的系统。我们安装了 TensorFlow、TensorFlow 模型制作工具、Numpy 和熊猫。

pip3 install tensorflow
pip3 install tflite-model-maker
pip3 install numpy~=1.19.2
pip3 install pandas

然后我们打开一个python3解释器,运行下面的代码。

import os
import numpy as np
import pandas as pd
import tensorflow as tf
from tflite_model_maker import model_spec
from tflite_model_maker import text_classifier
from tflite_model_maker.config import ExportFormat
from tflite_model_maker.text_classifier import AverageWordVecSpec
from tflite_model_maker.text_classifier import DataLoader
# Get the data
data_dir = tf.keras.utils.get_file(
      fname='SST-2.zip',
      origin='[https://dl.fbaipublicfiles.com/glue/data/SST-2.zip'](https://dl.fbaipublicfiles.com/glue/data/SST-2.zip'),
      extract=True)
data_dir = os.path.join(os.path.dirname(data_dir), 'SST-2')

您可以在这里看到,作为该设置的一部分,我们正在从fbaipublicfiles.com下载一个公共数据集。我们需要去看看那些公共数据,因为它是我们理解如何创建我们自己的数据的关键。

如果我们打印data_dir,我们可以看到数据已经保存到我们的主目录中(在一个隐藏的.keras文件夹中)。

print(data_dir)
/Users/tpmccallum/.keras/datasets/SST-2

如果我们查看这些数据,我们可以看到数据集的格式不适合 TensorFlow Lite …还不适合!

我们可以解决这个问题:)

为了使该数据与 TensorFlow Lite 兼容,我们执行以下任务。

首先,我们将制表符分隔的数据文件dev.tsv转换为逗号分隔的文件,并替换标签(将0转换为单词negative,将1转换为单词positive,如下图所示)。

df = pd.read_csv('/Users/tpmccallum/.keras/datasets/SST-2/dev.tsv', sep='\t')
label_map = {0: 'negative', 1: 'positive'}
df.replace({'label': label_map}, inplace=True)
df.to_csv('/Users/tpmccallum/.keras/datasets/SST-2/dev.csv')
replace_label(os.path.join(os.path.join(data_dir, 'dev.tsv')), 'dev.csv')

我们也对train.tsv文件这样做

df = pd.read_csv('/Users/tpmccallum/.keras/datasets/SST-2/train.tsv', sep='\t')
label_map = {0: 'negative', 1: 'positive'}
df.replace({'label': label_map}, inplace=True)
df.to_csv('/Users/tpmccallum/.keras/datasets/SST-2/train.csv')
replace_label(os.path.join(os.path.join(data_dir, 'train.tsv')), 'train.csv')

最后,我们再次对test.tsv文件执行此操作。

df = pd.read_csv('/Users/tpmccallum/.keras/datasets/SST-2/test.tsv', sep='\t')
label_map = {0: 'negative', 1: 'positive'}
df.replace({'label': label_map}, inplace=True)
df.to_csv('/Users/tpmccallum/.keras/datasets/SST-2/test.csv')
replace_label(os.path.join(os.path.join(data_dir, 'test.tsv')), 'test.csv')

好的,太好了!现在我们有了一些有意义的 TensorFlow Lite 兼容数据,可以使用和复制(使用我们自己的句子和标签)。

3 个电子表格(dev.csvtrain.csvtest.csv)各有两列(句子和标签)。

这个句子不是肯定的就是否定的。例如,句子“坚定地黯淡和绝望”被正确地标注为否定的。

理解了这个大纲,你就可以开始创建你自己的训练和测试数据。你只需简单地添加句子,然后正确/准确地标记它们(然后存储你的定制文件来代替这些原始文件)。

培养

我们现在可以加载这些csv文件,然后执行训练。

spec = model_spec.get('average_word_vec')
train_data = DataLoader.from_csv(filename='train.csv', text_column='sentence', label_column='label', model_spec=spec, is_training=True)
test_data = DataLoader.from_csv(filename='dev.csv', text_column='sentence', label_column='label', model_spec=spec, is_training=False)
# Train
model = text_classifier.create(train_data, model_spec=spec, epochs=10)

培训过程将生成如下所示的输出。

Epoch 1/101/2104 [..............................]
2104/2104 [==============================] - 3s 1ms/step - loss: 0.6841 - accuracy: 0.5570// snip //Epoch 10/10
2104/2104 [==============================] - 2s 1ms/step - loss: 0.3340 - accuracy: 0.8647

我们现在可以对训练好的模型进行测试

# Test
loss, acc = model.evaluate(test_data)

培训的结果如下

28/28 [==============================] - 0s 1ms/step - loss: 0.5160 - accuracy: 0.8303

如果我们对这些结果满意,那么我们可以将训练好的模型导出为一个.tflite文件;然后我们可以在我们的应用程序中使用它(稍后将详细介绍如何创建应用程序)。

model.export(export_dir='average_word_vec')

如果我们在 netron app 中打开新创建的 TensorFlow Lite 兼容文件(model.tflite,可以看到输入输出规范。这些规范将帮助我们编写应用程序。

模型设定

正如我们所见,输入称为input_1,输出称为Identity

输入(称为 input_1)

模型属性中的描述描述了输入的数据格式。具体来说…

嵌入表示要分类的输入文本的向量。输入需要从原始文本转换为嵌入向量使用附加的字典文件。

本质上,这个输入希望文本(用户提供的)被转换成一个单独的 i32 整数数组,即[5043, 201023, ... , 29361, 3499]。因此,我们需要了解模型的创建者希望我们如何将单词映射到数字。

通过调查数据,我们了解到该模型的创建者使用了一个字典文件,该文件将单词/短语映射到数字。字典文件每行有一个唯一的整数(对应于文本)。

例如,在第 85,155 行,我们有单词“awesome”和整数 29361(如下所示)。

awesome|29361

因此,在我们的应用程序中,如果用户键入单词“awesome ”,我们需要将整数29361发送给模型(作为模型期望的i32数组中的许多元素之一)。

这取决于您是在客户端还是在服务器端这样做。编程语言是你自己的个人喜好;我在下面创建了一些 Rust 代码,展示了如何从本地文件系统中读取字典,然后从数据中创建一个 HashMap。然而,我们也可以通过网络阅读这个文件,而不是;请允许我在下一节解释。

从本地磁盘读取并解析字典文件

 // Create HashMap which stores String and Integer pairs
    let mut map_name: HashMap<String, i32> = HashMap::new();
    // Read the dictionary file 
    let filename = "src/dictionary.txt";
    let file = File::open(filename).unwrap();
    let reader = BufReader::new(file);
    // Process each line
    for (index, line) in reader.lines().enumerate() {
        let line = line.unwrap();
        // Create vector to store each line as split data
        let v: Vec<&str> = line.split(|c| c == '|').collect();
        // Place the split data into the HashMap
        map_name.insert(v[0].to_string(), v[1].parse::<i32>().unwrap());
    }
    // Create another vector to hold the input data
    let size = 256;
    let mut vecForModel: Vec<i32> = Vec::with_capacity(size);
    // Split this functions input by space
    let vInputString: Vec<&str> = input_string.split(|c| c == ' ').collect();
    // See if any words are in the HashMap
    for word in vInputString {
        if map_name.contains_key(word){
            // If so, add the appropriate integer
            vecForModel.push(*map_name.get(word).unwrap());
        }

通过网络读取和解析字典文件

为了向您展示如何为 web 创建 AI 应用,让我们远程解析这个字典文件。

WasmEdge 的 RESTful API 其实可以远程为我们取这个字典文件;类似于使用内容交付网络(CDN ),而不是在本地存储文件。这有几个好处。

首先,应用程序开发人员可以更新字典文件(在其远程位置),而用户无需做任何事情。

其次,文件的获取和读取现在 100%在服务器端完成(客户机不需要做任何这种高带宽的工作)。我们的 AI 应用程序的用户(在客户端)只上传他们的句子和指向字典文件的 URL 指针。我们必须记住,这个字典文件超过 20 万行(239,232),并且可能随着新单词/语言的添加而增长。

上面屏幕截图显示这只是一个文本文件。

远程获取这种大型文本文件要快得多,繁重的工作更适合服务器端。下图说明了远程获取是如何工作的。

Web 表单

让这个 AI 应用程序可用的最好方法是使用表单数据(即 web 表单)。让我们看看 web 表单会是什么样子。

除了几个输入框(在 HTML 中),我们将有一个 Javascript 函数,它接受输入,然后调用 WasmEdge 的 RESTful API。

这是 Javascript。本质上只是一个 AJAX 请求。

function callService() {
          setTimeout(function() {
            $('#process').prop('disabled', true);
          }, 0); var formData = new FormData();
          formData.append('input_1', $('#input_1').val());
          formData.append('fetch_input_2', $('#input_2').val());
          console.log("Running ...");
          $.ajax({
            url: "[https://rpc.ssvm.secondstate.io:8081/api/multipart/run/392/classify](https://rpc.ssvm.secondstate.io:8081/api/multipart/run/392/classify)",
            type: "post",
            cache: false,
            data: formData,
            contentType: false,
            processData: false,
            xhrFields: {
              responseType: "" // defaults to text
            },
            success: function(r_data) {
              console.log("Successfully ran the ajax");
              document.getElementById("result_box").innerHTML = r_data;
              $('#process').prop('disabled', false);
            },
            error: function(r_error) {
              console.log("Error running the ajax: " + r_error);
              alert("Rate limit exceeded");
              $('#process').prop('disabled', false);
            }
          });
          console.log("END");
          return false;
        }

只是提醒一下,WasmEdge 几乎可以在任何设备上运行。为了这篇文章,我们将使用网络,以便您可以看到它的行动。

从上面的 Javascript 代码可以看出,WasmEdge 有一个 API 端点,任何能够发出安全 HTTP 请求的设备都可以调用它。显然,对于汽车应用来说,这些程序将在本地硬件上运行,而不是通过网络。

然而,仅仅为了演示 WasmEdge 的多功能性,让我们仔细看看 WasmEdge 的 API 端点结构。

您会注意到这个 URL 以一个函数名结尾,在本例中是classify。这实际上是执行所有逻辑(执行张量流模型)的 Rust 函数的名称。出于演示的目的,Rust 函数已经被编写、编译成 Wasm 并部署在 wasm_id 392(如上面的 URL 所示)。不要担心,我们很快就会深入研究 Rust/Wasm。现在,让我们只关注应用程序的前端(客户端)。

以下简单的 curl 命令可用于执行我们预先编写的 Wasm 二进制文件。注意我们如何添加两个--form参数(让 curl 模拟一个填充的表单)。注意,第二个输入实际上是我们前面提到的大字典文件的远程获取。

提示:执行远程获取时,使用不经过重定向的 URL,即如果在 GitHub 中存储数据,则使用如下所示的raw.githubusercontent风格的 URL。

curl --location --request POST 'https://rpc.ssvm.secondstate.io:8081/api/multipart/run/392/classify' --form 'input_1="Awesome movie"' --form 'fetch_input_2="[https://**raw.githubusercontent**.com/tpmccallum/Tim2/main/dictionary_testing.txt](https://raw.githubusercontent.com/tpmccallum/Tim2/main/dictionary_testing.txt)"'

一旦 curl 工作了,我们就可以为我们的应用程序创建一个 HTML 表单了。我们之前准备的那个看起来像下图,你可以在这里访问 HTML 源代码

同样的页面也可以通过 GitHub pages 进行现场演示。

现在我们已经介绍了 HTML 和 Javascript,让我们看看我们实际上通过 WasmEdge API 调用的可执行代码。

这整个应用程序是由 Rust 函数驱动的,这里是我们之前准备的 Rust 源代码的链接。注意,这个函数叫做classify,它与上面的 API URL 相匹配。

我们使用一个命令将 Rust 源代码编译成 WebAssembly (Wasm)。

rustwasmc build

如上所述,WasmEdge 能够在多种模式下运行,即通过 NodeJS、在嵌入式设备上等等。然而,我们将继续使用 WasmEdge 的 API 进行演示,以便您可以试用。

让我们看看如何解释输出。

输出——“身份”

正如我们在模型的属性中看到的,输出被称为“身份”。Identity 是一个包含两个元素的数组(数据类型都是 float 32)。第一个是与负面情绪相关的指数0-1。例如,0.25 意味着它有 1/4 的负面含义,1 意味着它是一个完全负面的评论。

第二个因素代表积极的情绪。

数组中的 2 个元素的总和总是 1。例如,中性将是 0.5 负和 0.5 正。

让我们尝试一些句子,看看我们得到了什么。

…的句子

“绝顶的平淡,痛苦的缓慢。”

导致了:

  • 高负指数1
  • 0的低正指数

相比之下……的句子

这部电影棒极了。伟大的演员,好的情节和娱乐性。

导致了:

  • 0.09839419的低负指数
  • 0.9016058的积极指数较高

为了更深入一点,在我们结束自然语言示例之前,我冒昧地粘贴了 WasmEdge 服务器端日志的输出。下面的输出显示了 Rust 源代码中所有的println!语句;本质上展示了我们如何远程获取字典,获取用户的输入,然后为模型创建一个 256 元素的数组,该数组包含任何单词/整数匹配的数字表示(在输入与字典文件的交叉引用期间)。

Input string: "This film was excellent. Great actors, good plot and entertaining"Processing word: "this"Processing word: "film"Processing word: "was"Processing word: "excellent."Processing word: "great"Processing word: "actors,"Processing word: "good"Processing word: "plot"Processing word: "and"Processing word: "entertaining"Processing loading the modelFinal Vec For Model: [2838, 976, 3070, 6874, 1092, 9754, 408, 6224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]Adding outputRunning sessionThe words you provided have a negative connotation index of 0.09839419, and a positive connotation index of 0.9016058.

第一个例子到此结束,现在我们来看另一个例子。物体检测。你可能在无人驾驶汽车演示中见过这种人工智能。物体检测有着广泛的用途,尤其是在工程和制造业。

目标检测

科学高清照片Unsplash

单发探测器(SSD)示例

和上面的自然语言例子一样,我们将首先安装一些依赖项

pip3 install testresources
pip3 install pycocotools
pip install grpcio==1.32
pip3 install tflite-model-maker

然后输入python3进入 Python 解释器。

import numpy as np
import os

from tflite_model_maker.config import ExportFormat
from tflite_model_maker import model_spec
from tflite_model_maker import object_detector

import tensorflow as tf
assert tf.__version__.startswith('2')

tf.get_logger().setLevel('ERROR')
from absl import logging
logging.set_verbosity(logging.ERROR)

对于这个特定的对象检测,我们将使用 GS://cloud-ml-data/img/open image/CSV/Salads _ ml _ use . CSV 中的沙拉数据集

前述的salads_ml_use.csv遵循特定的约定。以下是为培训目的创建自己的csv文件的条件。

目标是理解这个模型,这样你就可以在你喜欢的任何图像/物体上训练它;不仅仅是沙拉😊

数据格式

csv文件:

  • 必须是 UTF 8 编码的
  • 必须以.csv扩展名结尾
  • 集合中的每个边界框都有一行
  • 每行包含一幅图像;具有多个边界框的图像将在与边界框一样多的行上重复

标签

每个标签必须以字母开头,并且只能包含字母、数字和下划线。

边界框

图像中特定对象的每个边界框(在csv文件的那一行)可以用两种方式之一来表示。

  1. 只有两个顶点(由一组 x,y 坐标组成),如果它们是矩形的对角点。

例如:

(x_relative_min,
    y_relative_min,
    ,
    ,
    x_relative_max,
    y_relative_max,
    ,
)

2.所有 4 个顶点

例如

(x_relative_min,
    y_relative_min,
    x_relative_max,
    y_relative_min,
    x_relative_max,
    y_relative_max,
    x_relative_min,
y_relative_max)

从示例中可以看出,这些坐标必须是 0 到 1 范围内的浮点数,其中 0 表示最小的 x 或 y 值,1 表示最大的 x 或 y 值。

正如我们在本文开头提到的,理解数据非常重要,这样我们才能创建自己的训练数据。这些坐标可能会有点混乱,所以让我们来看一张图,这将使这一点更清楚。首先,正如你所看到的,最小值和最大值是从左上到右下排序的。因此,不要感到困惑,或者尝试将这与传统的数据绘图练习联系起来(这是不同的)。

下图增加了一些细节;演示边界框的坐标位置。

例如,x_min = 0,x_max = 1,y_min = 0,y_max = 1

创建您自己的数据集

我们马上就要使用一个现成的数据集,但是现在我们已经了解了这个数据是如何工作的,让我们来看看如何从头开始创建我们自己的数据集。

有许多应用程序允许你在自己的图像上手动创建带标签的边界框。其中一个应用叫做 labelImg

我们在本文中使用的另一个应用程序叫做 MakeML

下图显示了我们如何拍摄桌子的照片,然后识别笔记本电脑(通过绘制黄色边框并创建名为“laptop”的标签)。

然后我们识别笔记本电脑的键盘(通过画一个紫色的方框并创建一个名为“keyboard”的标签)。

在每张图片上画出一个边界框(越多越好),然后点击左下角的“导出数据集”链接。

有几种不同的数据格式可供选择。我们来对比一下。

Turicreate

Turicreate 兼容数据如下。

[{'label':'keyboard','type':'rectangle','coordinates':{'x':298,'y':301,'width':397,'height':69}},{'label':'laptop','type':'rectangle','coordinates':{'x':294,'y':225,'width':508,'height':407}}]

椰子树

这个通用对象上下文(COCO)兼容数据集是一个 JSON 文件(如下所示)。

{
  "categories" : [
    {
      "id" : 1629415338,
      "name" : "laptop"
    },
    {
      "name" : "keyboard",
      "id" : 1629415413
    }
  ],
  "images" : [
    {
      "file_name" : "ssd10.png",
      "height" : 450,
      "id" : 0,
      "width" : 600
    }
  ],
  "annotations" : [
    {
      "id" : 0,
      "category_id" : 1629415413,
      "iscrowd" : 0,
      "bbox" : [
        101,
        268,
        498,
        114
      ],
      "segmentation" : [],
      "image_id" : 0,
      "area" : 27456
    },
    {
      "iscrowd" : 0,
      "id" : 1,
      "bbox" : [
        40,
        22,
        549,
        21
      ],
      "segmentation" : [],
      "area" : 207401,
      "image_id" : 0,
      "category_id" : 1629415338
    }
  ]
}

帕斯卡 VOC

Pascal VOC 数据集格式是一个 XML 文件(如下所示)

<annotation>
    <folder>images</folder>
    <filename>ssd10.png</filename>
    <size>
        <width>600</width>
        <height>450</height>
        <depth>3</depth>
    </size>
    <segmented>0</segmented>
    <object>
        <name>keyboard</name>
        <pose>Unspecified</pose>
        <truncated>0</truncated>
        <occluded>0</occluded>
        <difficult>0</difficult>
        <bndbox>
            <xmin>101</xmin>
            <ymin>268</ymin>
            <xmax>498</xmax>
            <ymax>337</ymax>
        </bndbox>
    </object>
    <object>
        <name>laptop</name>
        <pose>Unspecified</pose>
        <truncated>0</truncated>
        <occluded>0</occluded>
        <difficult>0</difficult>
        <bndbox>
            <xmin>40</xmin>
            <ymin>22</ymin>
            <xmax>549</xmax>
            <ymax>430</ymax>
        </bndbox>
    </object>
</annotation>

您可能还记得上面的内容,我们需要以特定的方式格式化数据,即电子表格的每一行都需要如下所示:

链接到图像、标签、边界框坐标,即

gs://folder/ssd10.png,笔记本电脑,x_min,y_min,x_max,y_min,x_max,y_max,x_min,y_max

gs://folder/ssd10.png,键盘,x_min,y_min,x_max,y_min,x_max,y_max,x_min,y_max

为了符合上面讨论的格式,我们需要将图像形状和框坐标转换为 0–1 值(作为 600 px x450 px 格式中的并列像素坐标)。

如果宽度(x 轴)是 600 像素,高度(y 轴)是 450 像素,那么我们将对笔记本电脑的边界框坐标执行以下转换。

40px(最小)/ 600px(宽度)= 0.06

549 像素(最大值)/600 像素(宽度)= 0.91

22px(最小)/ 450px(高度)= 0.04

430(最大)/450 像素(高度)= 0.95

因此,膝上型电脑边界框的单行条目如下

gs://folder/ssd10.png,笔记本电脑,0.06,0.04,0.91,0.04,0.91,0.95,0.06,0.95

用数据训练

准备好电子表格行和图像后,您可以继续运行以下命令。

spec = model_spec.get('efficientdet_lite0')train_data, validation_data, test_data = object_detector.DataLoader.from_csv('gs://cloud-ml-data/img/openimage/csv/salads_ml_use.csv')model = object_detector.create(train_data, model_spec=spec, batch_size=8, train_whole_model=**True**, validation_data=validation_data)model.evaluate(test_data)model.export(export_dir='.')

编写应用程序来执行对象检测

使用经过训练的模型来执行对象检测的应用程序需要提供正确的输入(数据类型),并且还知道如何解释模型的输出。

如果我们检查model.tflite文件(使用 netron 这样的应用程序。app),我们看到以下内容

投入

这个模型很好地描述了输入和输出(我们可以看到输入在 RGB 中是 320 x 320 像素)

我们确保 Rust 源代码以 320x320 数组格式提供图像;平面阵列。

let mut resized = image::imageops::thumbnail(&img, 320, 320);
let mut flat_img: Vec<u8> = Vec::new();
for rgb in resized.pixels() {
    flat_img.push(rgb[0]);
    flat_img.push(rgb[1]);
    flat_img.push(rgb[2]);
}

输出

输出在模型规格中有详细说明,如下图所示。

让我们看一个使用前面提到的沙拉数据集的例子。

弗兰霍根,CC BY-SA 4.0<https://creativecommons.org/licenses/by-sa/4.0>,通过维基共享

该模型本质上是采用它以前从未见过的新图像,然后以与我们在生成训练数据时手动创建边界框坐标几乎相同的方式返回边界框坐标。

有趣的是,这个模型以相同的0–1格式返回给我们边界框,并且与缩小的 320x320 图像尺寸相关。

当我们将原始图像返回给用户时,我们需要确保根据原始图像的大小来转换对象边界框。

这里有一个包围盒坐标的例子,我们称这个数据为res0

[0.8125, 0.72265625, 0.5859375, 0.45703125, 
...
0.4296875, 0.36328125, 0.36328125, 0.3203125]

处理盒子的逻辑如下(基于我们在每个盒子 4 个坐标的集合中工作的事实)

let mut iter = 0;
while (iter * 4) < res0.len() {
    // bounding box logic
    iter += 1;
}

边界框逻辑的具体实现(假定原始图像是 512 像素乘 512 像素)如下。

let image_height: f32 = img.height() as f32; //512
let image_width: f32 = img.width() as f32; //512
let x1 = res0[4 * iter + 1] * image_width;
let y1 = res0[4 * iter] * image_height;
let x2 = res0[4 * iter + 3] * image_width;
let y2 = res0[4 * iter + 2]  * image_height;

为训练和测试创建自己的数据集

我想用一个额外的工具来结束这篇文章,它可能有助于使这个数据训练过程更快和更健壮。

我们在上面提到了标签图像标签应用程序。这是一个开源产品,以 PASCAL VOC 格式的 XML 文件构建训练集。这是 ImageNet 使用的格式。

ImageNet 是一项正在进行的研究工作,旨在为世界各地的研究人员提供用于训练大规模对象识别模型的图像数据。

令人欣慰的是,labelImg 似乎有一个免费的转换工具,可以在GitHub 仓库获得,它可以将你的 XML 文件从 PASCAL VOC 格式转换成 TensorFlow 兼容格式,我们在本文中已经解包了这种格式;正式描述在谷歌的官方文档中。labelImg 还支持 YOLO 和 CreateML 格式。

使用 labelImg 将允许您创建自己的自定义图像和自定义标签。额外的转换工具将使您不必编写自己的转换工具。

一旦你的数据集被训练并导出为tflite文件,你就可以使用 WasmEdge 创建你自己的 AI 应用程序。

你会创造什么?

如果你有任何问题,请在下面留下评论。

此外,如果您想为 WasmEdge 做贡献,请访问官方 WasmEdge GitHub 页面。

https://www.secondstate.io/

SecondState 团队是 WasmEdge 的最初创建者和当前维护者,所以请随时查看 SecondState 的网站、博客GitHub 库。

感谢阅读!

参考

[1]https://github.com/WasmEdge/WasmEdge#introduction

[2]https://www . ABC . net . au/news/2021-08-20/Toyota-slash-car-production-over-chip-short/100392630

如何训练你的连体神经网络

原文:https://towardsdatascience.com/how-to-train-your-siamese-neural-network-4c6da3259463?source=collection_archive---------2-----------------------

实践教程

训练时看不到的类的简单工作方式

Sereja RisUnsplash 上拍摄的照片

当你第一次开始机器学习时,从偏移中可以清楚地看到,精确而稳健的模型训练需要大量的数据。虽然这是事实,但当为了需要自定义数据集的目的而训练模型时,您通常需要在模型看到的数据级别上做出妥协。

这是我自己的情况;在 conservation tech 工作时,我们部署到一个区域的任何模型都是使用前几年调查中收集的数据构建的,这些数据在某些情况下可能是稀疏的(当然远不及 ImageNet [1]等基准数据集的水平)。更糟糕的是,在保护技术领域工作意味着使用开放的数据集。因为我们处理的动物是自由漫游的,所以不能保证我们用于模型训练的数据集将包含模型将在野外看到的所有事物的示例。

当试图使用传统的机器学习方法部署模型时,这导致了一场艰难的战斗。如果每门课都需要成千上万个例子,并且每年随着课程的变化都需要重新训练模型,那么建立一个守恒模型是没有用的。但是这个问题不仅限于保护,基准测试之外的许多领域都有类似的数据量和变化率问题。

在这篇文章中,我将讨论一种被称为连体神经网络的模型。希望在阅读之后,您将更好地理解这种架构不仅可以在保护方面有所帮助,而且可以在数据量有限且类别变化速度快的任何领域中有所帮助。

先决条件

在开始之前,你可能应该对机器学习有所了解,特别是卷积神经网络。如果你不知道,我发现 Sumit Saha 的帖子 是卷积神经网络的综合指南 ELI5 方式 是代替该领域正规教育的一个很好的起点。你应该先看看这个。

您还应该熟悉 Python、Keras 和 TensorFlow。在本文中,我们将学习代码示例,因为我发现这样做比自由格式文本本身更容易理解。本指南中的所有代码都是在 TensorFlow 1.14 中编写的,但没有理由认为这些代码不能在新版本中工作(可能需要一些修改),或者移植到其他深度学习框架,如 PyTorch。

什么是连体神经网络?

简而言之,连体神经网络是包含至少两个平行的、相同的卷积神经网络的任何模型结构。从现在开始我们称这些为 SNNs 和 CNN。这种并行 CNN 架构允许模型学习相似度,可以用来代替直接分类。snn 主要用于图像数据,如面部识别,尽管它们在这个领域之外也有用途。例如,赛仑·乌古罗格鲁在 NeurIPS 2020 上做了一个关于网飞如何利用社交网络根据电影元数据生成用户推荐的精彩演讲。在本指南中,我们将重点介绍图像数据。

构成 SNN 一部分的每个并行 CNN 被设计成产生输入的嵌入或缩减维度的表示。例如,如果我们指定嵌入大小为 10,我们可以输入大小为宽度 * 高度 * 通道的高维图像,并接收大小为 10 的浮点值向量作为输出,该向量直接表示图像。

然后,这些嵌入可用于优化排名损失,并在测试时用于生成相似性得分。理论上,并行 CNN 可以采取任何形式。然而,重要的一点是它们必须完全相同;它们必须共享相同的架构,共享相同的初始和更新权重,并具有相同的超参数。这种一致性允许模型比较它接收的输入,通常每个 CNN 分支一个。来自 Dey 等人【2】的图章纸对此提供了一个极好的可视化,可以在下面看到。

图章建筑。图片来自 Dey 等人。

SigNet 的目标是确定给定的签名是真实的还是伪造的。这可以通过使用两个平行的 CNN 来实现,这两个 CNN 在真实和伪造的签名对上进行训练。每个签名通过 SNN 的一个分支输入,该分支为图像生成一个 d- 维嵌入。正是这些嵌入被用来优化损失函数,而不是图像本身。更近版本的 SNNs 将很可能利用三分支甚至四分支,分别包含三个或四个平行的 CNN。

SNNs 有什么意义?

既然我们了解了 SNN 的构成,我们就可以强调它们的价值了。使用生成的 d- 维嵌入,我们可以创建一些 d- 维多维空间,允许绘制嵌入来创建集群。然后,可以使用主成分分析(PCA)将这个多维空间投影到二维空间进行绘图。

100 个训练时期后嵌入超空间的图,使用 PCA 投影到 2 维。使用基于笔记本的代码生成的图像。

该图显示了 MNIST 测试数据子集的嵌入位置[3]。这里,已经训练了一个模型来生成 10 个独特类别的图像嵌入(0 到 9 之间的手写数字的图像)。请注意,即使只经过 100 个训练时期,该模型也开始为同一类别的图像生成类似的嵌入。这可以从上图中相同颜色的点的聚类中看出——图中的一些聚类相互叠加,这是由于通过 PCA 降低到二维。在这种情况下,其他的观想,比如 t-SNE 图,或者降低到更高的维度,会有所帮助。

正是这种嵌入聚类使得 SNNs 成为如此强大的工具。如果我们突然决定要向数据中添加另一个类,那么就没有必要重新训练模型。新的类嵌入应该以这样一种方式生成,即当绘制到多维空间中时,它们远离现有的聚类,但是当它们被添加时,与新类的其他示例聚集在一起。通过使用这种嵌入的相似性,我们可以开始使用很少的数据为可见和不可见的类产生可能的分类。

模特培训

之前,我提到过 SNNs 由至少两个并行 CNN 分支组成,但现代实现往往依赖于更多分支。SNN 分店的数量对你的模特训练有很大的影响。您不仅需要确保您的数据以这样一种方式输入到 SNN,即每个分支都接收到训练样本,而且您选择的损失函数还必须考虑分支的数量。不管选择了多少个分支,损失函数的类型将可能保持一致。

排序损失,也称为对比损失,旨在预测投影到超空间时模型输入之间的相对距离。这与旨在预测一些类别标签集的更传统的损失相比。排序损失在 SNNs 中起着重要的作用,尽管它们对于诸如自然语言处理的其他任务也是有用的。有许多不同类型的排名损失,但它们都以相同的方式工作。

假设我们有两个输入,我们想知道它们有多相似。使用排名损失,我们将执行以下步骤:

  1. 从输入中提取特征。
  2. 将提取的特征嵌入到一个 d- 维的多维空间中。
  3. 计算嵌入之间的距离(例如使用欧几里德距离)以用作相似性的度量。

这里需要注意的是,我们通常并不特别关心嵌入的值,只关心它们之间的距离。以前面显示的嵌入图为例,注意所有点都位于 x 轴上大约-1.5,2.0 和 y 轴上大约-2.0,2.0 之间。嵌入在这个范围内的模型本身没有好坏之分,重要的是这些点在它们各自的类中聚集。

三重排序损失

用于 SNNs 的更常见的排序损失类型之一是三元组排序损失。你会经常看到 snn 使用这种称为三联体网络的损失函数,就好像它们是自己的东西一样(事实上这就是霍夫尔 e t al 对它们的定义。在最初构思它们的论文中,但实际上它们只是一个有三个分支的 SNN。因为三重态损失现在是如此普遍,这是我们将在本文后面使用的损失函数,所以理解它的工作原理很重要。

这个例子展示了三元组排序损失是如何将相同类别的嵌入图像拉近,而将不同类别的嵌入图像拉远的。图片作者。

顾名思义,三元组排序损失需要三个输入,我们称之为三元组。三元组中的每个数据点都有自己的工作。是某个 C 类的数据,它定义了三元组将在哪个类上训练模型。是 c 类的另一个例子。是某个类的数据点,它不是c。在训练时间,我们的每个三元组组件都被馈送到它自己的 CNN 分支进行嵌入。这些嵌入被传递给三元组损失函数,其定义为:

其中 D(A,P) 为锚点与正片的嵌入距离, D(A,N) 为锚点与负片的嵌入距离。我们还定义了一些边距——一个常用的初始值是 0.2,这是 FaceNet [5]中使用的边距。

该函数的目的是最小化锚和正片之间的距离,同时最大化锚和负片之间的距离。要更深入地了解三胞胎排名的损失,我建议这篇来自劳尔·戈麦斯的精彩文章

半坚硬三重开采

由于三胞胎成分的重要性,当务之急是我们的 SNN 只提供三胞胎,这将使它能够学习。更具体地说,我们希望提供否定,以便我们的三元组允许模型学习,但不要太难以至于学习需要太长时间。

一个简单的方法是通过一个被称为半硬三重开采的过程。为此,我们首先定义三个三元组类别:

  • 易三元组是那些其中 D(A,P) + margin < D(A,N) ,从而 L = 0 的。
  • 硬三元组是那些 D(A,N) < D(A,P)的。
  • 半硬三联体是那些 D(A,P) < D(A,N) < D(A,P) + margin 的。

目标是找到尽可能多的半硬三胞胎。这些三元组具有正损失,但是正嵌入距离比负嵌入距离更接近锚嵌入。这允许快速训练,但是对于模型来说,在训练期间实际学习某些东西仍然是足够困难的。

有两种方法可以找到这些半硬的三元组。在离线挖掘中,整个数据集在训练前被转换成三元组。在在线挖掘中,成批的数据被输入,随机生成三个一组。

作为一般的经验法则,在线挖掘应该尽可能地执行,因为它允许更快的训练,因为它能够随着训练的进行不断地更新我们的半硬三元组的阈值定义。这可以用数据扩充来补充,数据扩充也可以以在线方式进行。

推理时使用 SNNs

既然我们已经了解了 snn 是如何被训练的,我们接下来需要了解如何在推理时使用它们。在训练期间,我们使用 SNN 的所有分支,而推理可以使用单个 CNN 分支来执行。

在推理时,未知类别的输入图像由 CNN 分支处理并嵌入其特征。这种嵌入然后被绘制到超空间上,并与其他集群进行比较。这为我们提供了相似性分数的列表,或者未知类别的图像和所有现有聚类之间的相对距离。我们用来比较输入图像的聚类被称为支持集。让我们看一个例子来帮助理解这一点。

根据 Vetrova 等人[6]的数据,为测试图像蛾寻找最可能的家族类别。图像使用基于本笔记本的代码生成。

上面的图是我为了确定蛾的科学家族而创建的 SNN 的输出。数据集中的每张图片改编自 Vetrova 等人的【6】,被贴上了四个科学家族名称中的一个,或者被贴上了“幼虫”的标签,总共给出了五个类别。为了易于可视化(尽管事后看来不一定易于理解),每个已知标记的类别都显示在支持集中,如上面图的中间所示,使用来自每个类别的随机示例图像。在图的左边是一个测试图像;这是一张 SNN 没有看到的蛾的照片,它现在的任务是确定科学家族。

首先,SNN 使用在训练期间学习的嵌入函数嵌入测试图像。接下来,将该嵌入与支持集嵌入进行比较,支持集嵌入为测试图像提供了最可能的蛾类。在图的右边,我们可以看到支持集中的第一个图像已经被再次打印。

上面用于生成绘图的代码被告知首先显示测试图像族的相应示例(绘图代码知道正确的类,但 SNN 不知道)。因为第一个支持集图像再次显示在图的右侧,这告诉我们,SNN 在确定测试图像蛾的科学家族方面是正确的!如果这个图对您来说有点混乱,不要担心,因为我们稍后将在不同的、更简单的数据上创建相同的图。

如果嵌入被放置在超空间的一个新的区域中,并且超过了某个预定义的类距离阈值,则该代码可以被进一步扩展以警告用户。这可能表明 SNN 第一次看到了一个新的蛾类家族。

我们从哪里开始测量?

为了确定测试图像和支持集中的类之间的距离,我们需要每个类的测量位置。乍一看,从每个支持集类中随机选择一个嵌入似乎没问题;毕竟,如果所有的嵌入都完美地聚集在一起,那么我们使用哪一个并不重要?

虽然这个假设肯定成立如果我们的类嵌入是完美的集群,在一个真实的世界系统中不会是这种情况。让我们看看下面的玩具例子。

一个嵌入空间的例子,有两个类,十字和正方形,还有一个未定类的嵌入用三角形表示。图片作者。

在这个例子中,我们有两个类嵌入空间,一个用于十字,一个用于正方形。所有的方形类嵌入都聚集在图的右侧,但是交叉类有一个嵌入没有与左上方的其他嵌入聚集在一起。这个错误的十字被嵌入到方块通常聚集的空间中。在右上角还绘制了一个三角形,这是当前的测试图像,嵌入到空间中,但尚未根据其与其他聚类的距离分配到某个类别。

为了确定三角形实际上应该是十字形还是正方形,我们为每个类随机选择一个要测量的嵌入;错误的十字和左下角的方块被选中(都被圈起来)。如果我们比较这些嵌入的距离,选择的十字是最接近的,因此三角形将被标记为十字。

然而,从整体上来看,很明显,三角形可能应该被标记为正方形,而十字是一个异常值。通过选择随机嵌入来度量,我们冒着离群值扭曲距离度量的风险,从而扭曲最终结果。

这可以通过使用原型来解决,这是一个优雅且易于理解的问题解决方案。原型本质上是每个类的一般化嵌入,减少了离群值对距离测量的影响。这些可以用多种方法计算,但是简单的技术,比如取中间值,效果很好。让我们更新玩具的例子…

与之前相同的嵌入空间,但是包含了原型。图片作者。

现在,每个类都被赋予了一个靠近其类中心的原型(例如,Pₓ是交叉类的原型)。如果我们在测量相似性时选择了原型,我们的三角形就被正确地标记为正方形。这个简单的解决方案可以大大减少计算相似性时离群值的影响。

确定如何计算原型是很困难的,使用中位数等解决方案可能会在某些数据集上失效。例如,如果我们的所有交叉类示例围绕原点形成半径为 1 的圆,而方形类示例形成半径为 2 的圆,则原型现在都将在原点形成,从而产生相等的距离测量值。我们需要找到另一种方法来计算数据集的原型。

建立一个连体神经网络

既然我们已经掌握了 SNNs 的基本理论,以及为什么它们是一个重要的工具,那么让我们来看看如何构建一个 SNNs。如前所述,我们将为此使用 Python、Keras 和 TensorFlow 1.14,尽管实际上没有什么可以阻止这些代码被转换用于另一个框架,如 PyTorch 我使用 TensorFlow 是出于个人偏好,而不是因为它更适合制作 snn。为了一致性和便于训练,我们还将坚持使用 MNIST 作为我们的数据集。

这里的代码是基于各种来源的,我会在我们进行的过程中进行链接,但底层的构造是基于 Amit Yadav 的 Coursera,中描述的方法,它本身是基于 FaceNet [5]。

如果你喜欢完整的代码而不是片段,这可以从我的 Github 获得。

步骤 1:导入包

首先,我们需要导入所需的包。如需在虚拟机上运行该代码所使用的软件包版本的完整列表,请参见此处的。我用 Python 3.6.7 测试了这段代码。

步骤 2:导入数据

接下来,我们需要为 SNN 导入一个数据集。如前所述,我们将使用 MNIST,它可以通过 TensorFlow 的mnist.load_data()加载。

数据加载后,将被重新整形和展平。这使得将数据读入 SNN 更加容易。

注意,我们这里只有高度和宽度,因为 MNIST 是灰度的,所以只有一个颜色通道。如果我们有一个包含多个颜色通道的数据集,我们需要修改我们的代码,例如使用x_train_w_h_c来代替。

第三步:创建三胞胎

现在我们需要创造我们的 MNIST 三胞胎。为此需要两种方法。

第一个是create_batch(),通过随机选择两个类标签生成三元组,一个用于锚/正,一个用于负,然后为每个随机选择一个类示例。

第二个,create_hard_batch(),使用create_batch()创建一批随机的三元组,并使用当前的 SNN 嵌入它们。这允许我们确定该批中的哪些三胞胎是半硬的;如果是,我们保留其中的num_hard,用其他随机的三元组填充其余的批次。通过填充随机三元组,我们允许开始训练,并确保我们的批次大小一致。

步骤 4:定义 SNN

SNN 由两部分定义。首先,我们必须创建嵌入模型。该模型接收一个输入图像并生成一个维嵌入。我们在这里创建一个非常浅的嵌入模型,但是可以创建更复杂的模型。

接下来,我们创建一个模型,该模型接收一个三元组,将其顺序传递给嵌入模型进行嵌入,然后将结果嵌入传递给三元组损失函数。

步骤 5:定义三重损失函数

为了让 SNN 使用三元组进行训练,我们需要定义三元组损失函数。这反映了前面所示的三重态损失函数方程。

步骤 6:定义数据生成器

为了将我们的三元组传递到网络,我们需要创建一个数据生成器函数。TensorFlow 需要一个xy,但是我们不需要一个y值,所以我们传递一个填充符。

步骤 7:为培训和评估做准备

现在,我们已经定义了 SNN 的基础知识,我们可以设置培训模型了。首先,我们定义超参数。接下来,我们创建并编译模型。我指定这是使用 CPU 执行的,但是根据您的设置,这可能不是必需的。

一旦模型被编译,我们存储测试图像嵌入的子集。这个模型还没有被训练,所以这给了我们一个很好的基线来显示嵌入是如何在训练过程中变化的。通过 PCA 嵌入可视化是基于阿德里安农的这本笔记本

可以在我们的 SNN 上进行进一步的评估。这一步中使用的代码受 Eric Craeymeersch 的 One Shot Learning、Siamese Networks 以及 Keras 的 Triplet Loss 的影响很大。

我们来看看未经过训练的模特的评价。从图中,我们可以看到我们的模型无法区分相似和不相似的图像。这在第三个图中最为明显,突出显示了测试图像及其最可能的类别,它们的分数之间几乎没有差异。

使用基于本笔记本的代码生成的图像。

现在我们已经编译了模型,我们也可以生成示例随机和半硬三元组。这段代码基于 Ruochi Zang 的博客文章。

这会产生以下结果:

使用基于这篇博文的代码生成的图像。

我们的示例随机三元组包含锚和类别 4 的正,以及类别 6 的负。我们的半硬三联体包含一个锚和一个 8 类的阳离子,和一个 6 类的阴离子,但是请注意它们在组成上是多么的相似。

步骤 8:记录我们模型训练的输出

在训练我们的模型之前,让我们设置一些日志记录和自定义回调,如果我们需要在以后的某个日期再回来的话,可以帮助我们。Tensorboard logging callback 改编自 erenon 的有用的堆栈溢出答案,而基于验证损失的最佳模型的保存改编自另一个 OverLordGoldDragon 的堆栈溢出答案

第九步:训练 SNN

现在我们所有的设置已经完成,是时候开始训练了!我首先从选择可用的 GPU 总数开始,并对它们进行并行模型训练。如果您没有访问多个 GPU 的权限,您可能需要对此进行修改。

注意,在运行model.fit()时,我们提供训练和测试数据生成器,而不是直接提供训练和测试数据。这允许在线三元组挖掘发生。

步骤 10:评估训练好的模型

一旦模型训练完毕,我们就可以评估它并比较它的嵌入。首先,我们加载训练好的模型。我通过重新加载保存的日志文件来实现这一点,但是如果您只是在一个笔记本中作为一个封闭的系统运行这一切,那么一旦模型被训练,就没有必要重新加载。

一旦加载了模型,我们执行与未训练模型相同的 PCA 分解,以可视化嵌入是如何变化的。

在上述代码块的末尾,我们再次运行evaluate(),这产生了下图:

使用基于本笔记本的代码生成的图像。

请注意第一个图现在如何显示 AUC 为 0.985,以及我们类别之间的距离增加。有趣的是,当查看测试图像及其最可能的类别时,我们可以看到,对于第二和第三测试图像,已经正确地实现了相应的类别(例如,以类别 0 的第二测试图像为例,我们可以看到所有支持集类别的最低分数也在类别 0),然而,查看第一测试图像,支持集类别的所有分数都非常接近,这表明训练的模型难以对该图像进行分类。

为了确认我们的模型已经正确训练,并且现在正在形成类簇,让我们绘制我们先前存储的 PCA 分解嵌入。

该代码产生以下输出:

使用基于本本的代码生成的图像。

左图显示了训练前的嵌入位置,使用 PCA 将其分解为二维以进行可视化,每种颜色代表一个不同的类别,如图例所示。请注意嵌入是如何混在一起的,没有清晰的聚类结构,这是有意义的,因为模型还没有学会将类分离出来。这与右图形成对比,右图显示了由经过训练的 SNN 嵌入的相同数据点。我们可以在地块的外围看到清晰的集群,但是中间看起来还是有点乱。我们的图表明,该模型已经很好地学习了对例如类别 1 的嵌入图像进行聚类(左下方的聚类),但是仍然与类别 5 的嵌入图像进行斗争,类别 5 的嵌入图像仍然主要位于中心。这一点得到了我们之前的图的支持,图中显示了模型在努力确定 5 类测试图像的最可能匹配。

量化我们的模型表现有多好将是一件好事。这可以通过利用我们之前讨论过的原型,使用 n 向准确度得分来实现。在 n 向精度中,val_steps个随机选择的测试图像与大小为 n. 的支持集进行比较。当 n 与下面代码中的类总数num_classes相同时,这提供了模型精度的指示。MNIST 有 10 个等级,给出 10 个方向的精确度。

当我们运行上面的代码时,SNN 实现了 97.4% 的 10 向准确率,这是一个值得称赞的分数。由于测试图像选择的随机性,如果您愿意,可以在这里进行交叉验证。

最后,让我们看看如何生成一个支持集图像,类似于上一个 moths 示例中显示的图像,只是这次是使用 MNIST 生成的。同样,我们将使用 10 类支持集。

这会产生以下情节:

使用基于本笔记本的代码生成的图像。

如果本文前面讨论的蛾的例子令人困惑,希望使用 MNIST 的相同情节更加清晰。代码随机选择了一个 2 类测试图像进行分类,并将其与支持集中所有其他类的原型进行比较。同样,绘图代码知道测试图像属于类别 2,因此首先显示支持集 2。在右侧,再次显示了相同的支持集 2,表明 SNN 已经正确地为测试图像确定了最可能的类别 2,这应该在大约 97.4%的时间内为其他测试图像完成!

结论

在本文中,我们已经了解了什么是连体神经网络,如何训练它们,以及如何在推理时利用它们。尽管我们通过使用 MNIST 使用了一个玩具示例,但我希望能够清楚地看到,当处理开放式数据集时,SNNs 的功能有多强大,在数据集创建时,您可能没有所有可用的类,以及模型将如何处理新的训练时未看到的类。

我希望我已经为您提供了理论知识和实际应用的良好平衡,我要感谢我自始至终提到的所有人提供了开源代码和堆栈溢出答案。没有这篇文章,事实上我自己在保护技术方面的工作也不可能完成。

当我刚开始写作时,我担心没有足够的内容值得去写。现在一切都结束了,我意识到我错了!希望如果你已经做到这一步(而不是跳到最后),这篇文章已经教会了你一些东西,如果是这样,请让我在 TwitterLinkedIn 上知道。

参考

[1]邓军,董,魏,苏,李,李,李,,李,2009 年 6 月.Imagenet:一个大规模分层图像数据库。在 2009 年 IEEE 计算机视觉和模式识别会议(第 248–255 页)。IEEE。

[2] Dey,s .,Dutta,a .,Toledo,J.I .,Ghosh,S.K .,Lladós,j .和 Pal,u .,2017 年。Signet:用于独立于书写者的离线签名验证的卷积暹罗网络。 arXiv 预印本 arXiv:1707.02131

[3] LeCun,y .,Bottou,l .,Bengio,y .和 Haffner,p .,1998 年。基于梯度的学习在文档识别中的应用。IEEE 会议录86 (11),第 2278–2324 页。

[4]霍弗,e .和艾伦,n .,2015 年 10 月。使用三元组网络的深度度量学习。在基于相似性的模式识别国际研讨会(第 84–92 页)。斯普林格,查姆。

[5]施罗夫、弗洛里安、德米特里·卡列尼琴科和詹姆斯·菲尔宾。Facenet:人脸识别和聚类的统一嵌入。在IEEE 计算机视觉和模式识别会议记录中,第 815–823 页。2015.

[6]维特罗娃,v .,政变,s .,弗兰克,e .和克里,M.J .,2018,11 月。隐藏特征:细粒度多类和单类图像分类的特征转移实验。在 2018 新西兰图像与视觉计算国际会议(IVCNZ) (第 1–6 页)。IEEE。

如何将从维基百科提取的数据转换成 Python 中的地图

原文:https://towardsdatascience.com/how-to-transform-data-extracted-from-wikipedia-into-a-map-in-python-8325dce0710b?source=collection_archive---------12-----------------------

数据可视化

一个现成的代码,可以通过 Selenium、GeoPy 和 leav 在从维基百科提取的条目列表上创建一个地图

作者图片

在本教程中,我描述了一个从维基百科中提取地理条目的策略,这些条目被组织成列表,然后显示在地理地图上。我利用了以下 Python 库:

例如,我利用了 5 个维基百科页面,与意大利犹太人社区相关:

所有被考虑的维基百科页面都包含一个条目列表,每个条目代表一个地理实体,即一个意大利城市。因此,我们的想法是用从维基百科中提取的所有地点构建一个地理地图。该过程分为三个步骤:

  • 数据析取
  • 数据清理
  • 数据丰富
  • 数据可视化

1 数据提取

所有被考虑的维基百科页面中的所有位置都被表示为无序列表的项目符号。因此,它们可以很容易地通过一个公共过程提取出来,通过selenium库来实现。为了让你的代码工作,你应该为你的浏览器安装正确的selenium驱动程序,如本视频中的所述。

现在,我已经准备好编写代码了。

首先,我导入驱动程序:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

然后,我定义了一个名为extract_list的函数,它接收维基百科页面的 URL 作为输入,还接收用于从该页面提取数据的 XPath 表达式。该函数提取与该 XPath 关联的所有文本,按行拆分提取的文本,并返回项目列表作为结果:

def **extract_list**(url, xpath):
    options = Options()  
    options.add_argument("--headless") 
    options.add_argument("--lang=it");
    driver = webdriver.Chrome(options=options) driver.get(url)
    table = [] # get the list of terms
    words = driver.find_element_by_xpath(xpath).text
    table.extend(words.split('\n'))
    driver.close()
    return table

现在,我可以为每个被考虑的维基百科页面调用该函数,为此我定义了一个列表:

pages = ['Comunit%C3%A0_ebraiche_italiane', 'Cimiteri_ebraici_in_Italia', 'Musei_ebraici_in_Italia','Ghetti_ebraici_in_Italia','Sinagoghe_in_Italia']

然后,我在创建的页面列表上构建一个循环,并调用extract_list函数。我还将提取的表格转换成一个pandas数据帧,并将每个提取的条目与一个类别相关联,对应于所考虑的页面(有一些风格上的变化):

import pandas as pddf_dict = {}
xpath = '//*[[@id](http://twitter.com/id)="mw-content-text"]'
table = {}
base_url = '[https://it.wikipedia.org/wiki/'](https://it.wikipedia.org/wiki/')**for page in pages**:
    name = page.replace('_', ' ').title().replace('%C3%A0', 'à')
    print(name)
    url = base_url + page table[page] = extract_list(url,xpath)
    df_dict[page] = pd.DataFrame(table[page], columns=['value'])
    df_dict[page]['category'] = name

最后,我通过连接前面构建的数据帧来构建数据帧:

df = pd.DataFrame(df_dict[pages[0]])
for i in range(1,len(pages)):
    df = pd.concat([df, df_dict[pages[i]]])

作者图片

提取的数据包含许多错误,需要纠正。但是,我可以将第一个原始数据集存储为 CSV 文件:

df.to_csv('data/raw_data.csv')

费尔南多·雷耶斯在 Unsplash 上拍摄的照片

2 数据清理

电子社区页面中提取的地点可以进一步分为两类:活跃社区和不再活跃社区。查看保存的 CSV 文件,可以轻松提取这些信息。指数低于 83 的地区是指活跃社区,其他地区是指不再活跃的社区。

我定义了一个函数来提取这些信息。请注意,仅当考虑的类别为 Comunitàebra ICA Italiana(意大利犹太社区)时,此信息才有用:

df = pd.read_csv('data/raw_data.csv')
index_na = 83def **is_active**(x, index_na):
    if x < index_na:
        return True
    return False

我在数据帧中创建了一个新字段,指定一个社区是否活动:

df['is_active'] = df['Unnamed: 0'].apply(**lambda x**: is_active(x, index_na))

作者图片

现在我需要清理value字段,以便提取位置。该操作分两步完成:

  • 删除不包含地点的记录
  • 确定文本中的分隔符以提取准确的位置。

2.1 删除不包含地点的记录

看数据,对应于地点的记录很容易识别,因为它们包含一些特殊的关键字。因此,我定义了一个单词包,它只能用于选择地点:

bag_words = ['Comunità ebraica di', '(Provinc', '(Region', ' Provinc', 'ex circondario', 'Cimitero ebraico di', 'Museo ebraico di', 'Ghetto di', 'Sinagoga di', 'Cimitero israelitico di', 'Cimitero monumentale ebraico di']

现在,我定义一个函数来检查记录是否是一个位置:

def **is_locality**(x):
    for bag in bag_words:
        if bag in x:
            return True
    return False

我利用已定义的函数来构建数据帧的新列:

df['is_locality'] = df['value'].**apply**(lambda x : is_locality(x))

最后,我只选择具有is_locality属性True的记录:

df = **df[df['is_locality'] == True]**
df.reset_index(inplace = True)

作者图片

2.2 识别文本中的分隔符以提取准确的位置

查看记录,特别是在value列,每个地点的名称在两个偏移量之间标识:(start,end)。起始偏移量可以是 0,也可以等于以下单词包的长度:

**start_bag** = ['Comunità ebraica di','Sinagoga di', 'Cimitero ebraico di','Sinagoghe del Ghetto di','. Getto di','Ghetto di','Cimitero monumentale ebraico di','Cimitero israelitico di', 'Museo ebraico di']

然后我定义一个函数,它提取起始偏移量:

def **get_start_index**(x):
    start_index = 0
    for bag in start_bag:
        if bag in x:
            return len(bag)
    return start_index

关于结束偏移量,我定义了一个停止字符包,可以用来标识停止偏移量:

**stop_bag** = ['oratorio', '[', ',', 'aperta', 'viale', 'presso', '-', 'di rito','(']

然后,我定义一个函数,来确定止损点偏移量的最小指数:

def **get_min_index**(x):
    min_index = len(x)
    for stop in stop_bag:
        try:
            curr_index = x.index(stop)
            if curr_index < min_index:
                min_index = curr_index
        except ValueError:
            continue
    return min_index

以及提取位置的函数:

def **get_locality**(x):
    if 'Fiuggi' in x:
        return 'Anticoli'
    if x == 'Cimitero ebraico di viale Ippolito Nievo a Livorno (dismesso)':
        return 'Livorno'
    if x == 'Sinagoga di via dei Ramaglianti (Firenze), scomparsa':
        return 'Firenze'
    start_index = get_start_index(x)
    stop_index = get_stop_index(x)  
    return x[start_index:stop_index].strip()

前一项职能还考虑了三种特殊情况(Fiuggi、Cimitero ebraico di viale Ippolito Nievo a Livorno(dismesso)和 Sinagoga di via Ramaglianti(费伦泽)、scomparsa),这些情况不属于一般情况。

现在,我在数据帧中创建了一个新列,其中包含每个地区的名称:

df['locality'] = df['value'].**apply**(lambda x: get_locality(x))

最后,我将结果导出为 CSV 文件:

df.**to_csv**('data/data_locality.csv')

安妮·斯普拉特在 Unsplash 上的照片

3 数据丰富

为了将提取的地点表示到地图中,我必须提取它们的地理坐标。这可以通过geopy库来完成,它不是一个地理编码服务,而是一个面向外部地理编码服务的接口。

在本教程中,我利用了Nominatim服务,并定义了一个提取坐标的函数:

from geopy.geocoders import Nominatimdef **get_coordinates**(city_list):
    geolocator = Nominatim(user_agent="location script")
    dicto = {}

    for city in city_list:
        try:
            location = geolocator.geocode(city, country_codes='it')
        except:
            raise Exception("There was a problem with the getCoordinates function")
        coordinate_values = (location.longitude, location.latitude)  
        dicto[city] = coordinate_values 
    return dicto

为了使地理编码服务更加精确,我将 country_code 设置为 Italy,因此该服务只在意大利境内。该函数返回一个字典,其中包含每个地区的经度和纬度。

city_coords_dict = **get_coordinates**(df['locality'].values)

我定义了一个中间函数,它只返回纬度或经度,给定一个位置:

def **get_coords**(x, city_coords_dict, coord = 0):
    coords = city_coords_dict[x]
    return coords[coord]

我利用它向我的数据帧添加了两个新列:

df['longitude'] = df['locality'].**apply**(lambda x : get_coords(x, city_coords_dict))
df['latitude'] = df['locality'].**apply**(lambda x : get_coords(x, city_coords_dict, coord = 1))

我将结果导出为 CSV 文件,以避免多次执行地理编码:

df.to_csv('data/geo_data.csv')

4 地图上的数据可视化

提取的地点可以显示在地图上。我利用folium库来构建地图。

首先,我将维基百科的页面名称转换成人类可读的类别:

categories = []
for page in pages:
    category = page.replace('_', ' ').title().replace('%C3%A0', 'à')
    categories.append(category)
categories

然后,我构建基本地图,聚焦于意大利,从缩放级别等于 6 开始:

import foliummy_map = folium.Map(tiles='cartodb positron',location=[41.8719, 12.5674],zoom_start=6)

至于地图布局,我选择的是cartodb positron地图。其他地图布局可以在官方folium 文档中找到。

然后,我定义一个函数,为数据帧中的每个位置添加一个标记:

def **add_markers_to_the_map**(the_map, df, icon, category, color):      group = folium.FeatureGroup(name=category).add_to(the_map) for i in range(0, df.shape[0]):    
            popup_text = df.iloc[i]['value']
            city = df.iloc[i]['locality']
            long = df.iloc[i]['longitude']
            lat = df.iloc[i]['latitude']

            popup = folium.Popup(popup_text, autopan='False', parse_html=True)

            marker = folium.Marker(location=[lat, long], 
                                   popup=popup, 
                                   icon = folium.Icon(icon_size=(25, 25), color=color, icon=icon, prefix='fa'))

            group.add_child(marker)

    return the_map

对于每个类别,我通过前面函数中的FeatureGroup()类定义了一个新层,一个图标和一种颜色。然后,我为每个类别调用函数:

colors = ['green', 'blue', 'orange', 'brown', 'pink']
color = 0for category in categories:
    df_selected = df[df['category'] == category] if category == 'Comunità Ebraiche Italiane':
        add_markers_to_the_map(my_map, df_selected[df['is_active'] == True], 'flag', category + ' Attive', 'green')        add_markers_to_the_map(my_map, df_selected[df['is_active'] == False], 'flag', category + ' Non più Attive', 'red') else:
        add_markers_to_the_map(my_map, df_selected, 'flag', category, colors[color]) color = color + 1

在前面的函数中,以意大利电子社区为例,我创建了两个层,分别用于活跃社区和不再活跃社区。

为了使图层可选,我在地图上添加了一个LayerControl():

folium.LayerControl().add_to(my_map)

最后,我将地图导出为 html 格式:

my_map.save('mappa.html')

作者图片

摘要

在本教程中,我描述了一种从维基百科页面中提取地点的策略,通过地理编码服务丰富这些地点,最后将它们表示到地理地图中。

对于这篇文章,我要感谢 Alberta Odamea Anim-Ayeko ,他写了一篇精彩的文章,题为用 Geopy 和 leavy制作酷炫的地图,这启发了我做这篇教程:)

还有你,你用哪些库来实现 Python 中的地图?给我留言吧!我很乐意听听你的意见!

如果你已经走了这么远来阅读,对我来说今天已经很多了。谢谢!你可以在这篇文章中读到更多关于我的信息。

你愿意支持我的研究吗?

你可以每月订阅几美元,并解锁无限的文章。

对于那些选择支持我的人(不仅仅是他们)来说,额外的奖励是一个在 leav 中实现鼠标悬停/鼠标释放工具提示的提示。

由于 leav 不支持 mouseover/mouseout,我可以直接修改 HTML 文件来支持它:

import re
import fileinputwith open("mappa.html") as inf:
    txt = inf.read()#Find all the markers names given by folium
markers = re.findall(r'\bmarker_\w+', txt)
markers = list(set(markers))for marker in markers:
    for linenum,line in enumerate( fileinput.FileInput("mappa.html",inplace=1) ):
        pattern = marker + ".bindPopup"
        pattern2 = marker + ".on('mouseover', function (e) {this.openPopup();});"
        pattern3 = marker + ".on('mouseout', function (e) {this.closePopup();});"if pattern in line:
            print(line.rstrip())
            print(pattern2)
            print(pattern3)
        else:
            print(line.rstrip())

离开前最后说一句:你可以从我的 Github 库:)下载本教程的完整代码

相关文章

参考

https://fontawesome.com/v5.15/icons/flag?style=regular https://stackoverflow.com/questions/41095716/hover-in-popup-in-folium https://stackoverflow.com/questions/55344513/add-menu-bar-on-folium-map-to-select-or-deselect-particular-object-marker https://stackoverflow.com/questions/51486454/convert-geopandas-shapely-polygon-to-geojson

从社会公正的角度看如何用 NLP 创建标签

原文:https://towardsdatascience.com/how-to-transform-technical-jargon-into-simple-bi-tri-grams-with-nlp-on-a-public-dataset-2081f5609c1f?source=collection_archive---------16-----------------------

粘土银行Unsplash 拍摄的照片

那么,互联网是一种人工制品,既是正式教育过程的延伸,也是“非正式文化”,因此它是一种“主体性的发挥”。这一想法提供了另一个有利的角度,可以理解媒体中的代表性(和虚假陈述)是权力关系的一种表达方式——Safiya Umoja Noble(压迫的算法:搜索引擎如何强化种族主义,2018 年)

屏幕另一边的人工智能对谦逊声音的压制正在扩大。我最近遇到一个小企业主。她的商业吸引力减少了,因为她的网站不再符合最近更新的搜索引擎优化算法。她的问题的解决方案比用于故障排除的标准技术更复杂。与谷歌自然语言或“搜索引擎”算法合作的最佳方式是什么?人类可以“学习人工智能来设计他们的方式来提高谷歌搜索的排名吗?

谷歌使用复杂的语料库和单词包算法来绘制现有网站,每秒钟可以理解 40,000 次搜索。让少数民族、残疾人、退伍军人和女性拥有的企业等不太为人所知的声音发出来的方法是,让这些社区拥有一个能够理解并向 SEO 算法提供微调参数(词)的人工智能。有一种方法可以借鉴 Google NLP 算法,优化并动态更新自报能力。在本文结束时,您将会实现以下目标:

  • 将句子转换成有意义的二元模型和三元模型。
  • 轻松添加和更改数据框和数据类型。
  • 对公开报道的利基数据应用 PMI、单词包、n-grams 和非结构化数据清理,以生成标签。
  • 文本摘要、模型偏差和改进后端数据集的方法。

我们会从这里学习如何处理事情-

到这里-

让我们直接进入解决方案-

照片由Christian WiedLet ' s sonUnsplash

数据集

纽约州在州属企业数据库中维护Disabled/Women/MBbusinessEE。审计官办公室托管主数据库,帝国审计官根据具体情况授予企业认证,并将其纳入法律登记处。纽约市为特定城市的公司维护另一个数据库。接下来的部分将介绍我们如何合并这些数据库和数据可视化。

州数据库可能很难导航。应该与自我报告功能相对应的 Google 搜索可能不会映射州数据库,因为它具有受保护的性质。在定义了问题之后,让我们更深入地研究数据库的核心。对于这个问题,我将使用的数据库是SDVOB——截至 2022 年 1 月 27 日,数据库中有 932 家认证的伤残退伍军人所有的企业。您可以通过按下搜索按钮下载 excel 文件。

乔希·阿佩尔在 Unsplash 上拍摄的照片

配方的模块

import numpy as np
import pandas as pd
from pandas import DataFrame, Series  # for convenience
import re
import glob
import copy
import os
import xlrd
import nltk
import unicodedata
import re
from collections import Counter
from nltk.collocations import *
bigram_measures = nltk.collocations.BigramAssocMeasures()
trigram_measures = nltk.collocations.TrigramAssocMeasures()
from nltk.tokenize import word_tokenize
from nltk.tag import pos_tag
import spacy
#!pip install -U pip setuptools wheel
#!pip install -U spacy
#!python -m spacy download en_core_web_sm
nlp = spacy.load("en_core_web_sm")
import en_core_web_sm
nlp = en_core_web_sm.load()
from bs4 import BeautifulSoup
from html import unescape

探索数据集

数据集包含 936 行× 21 列,其中一列包含自我报告功能-

-以及关键字和关于列。由于每一列都包含关键信息,这些信息可以让我们深入了解企业在做什么,因此我们需要训练一个模型,该模型使用这些信息的组合作为之前的,而没有任何嵌入的分类(或偏差)。这意味着我们的模型没有考虑信息是否来自关键字或关于列;该模型假设自我报告的信息与公共记录认证和验证的信息一样有价值

因此,下一步是将信息组合成一个列表;列表的索引对应于企业在数据库中的位置。正如你可能看到的,特征数据是不干净的,有几个不需要的 ASCII 字符,但是如果你仔细观察,这些字符是分隔关键字的,例如:

string1 = "Marijuana Dispensary, Online Retail Sales"
string2 = "Environmental remediation services; Fire and or Water Damage Restoration Services"print(string1.split(sep =', '))
>>['Environmental remediation services',  'Fire and or Water Damage Restoration Services']#try - string2.split(sep='; ')

因此,要在没有 NLP 的情况下提取所需的二元模型和三元模型,我们可以使用分隔符,分隔符的选择取决于我们!这里有一些我可以观察到的分隔符&, --,: etc.,所以在我们下一步清理数据之前,让我们列出一个可以循环的列表。

数据集分离

下面是我如何制作一个总数据的列表

在我们进入清理和提取 hashtags 的循环之前,我将定义关键函数来清理、提取和整理数据。

基本功能

  1. Basic clean 是最重要的函数,它使用 NLP 并返回一个没有 Unicode、ASCII 和停用词的字符串列表!通过使用 Beautifulsoup 来清理 HTML 语法或定义停用词,您可以将它提升到一个更高的水平。当我们在将成为数据框单元一部分的字符串列表中获得重复的时,该函数获取一组列表并将它们转换成一个字符串。

现在我们有了基本的清理,我们可以创建这个整洁的函数来大写单词-

  1. 下面的函数将帮助我们删除位于数据框单元格内的字符串列表中的重复项,并吐出组合了这些单词的字符串。

比如说—

`s = “ Hello Hello Sir”
strsetoflist(s.split())
>>'Hello Sir'

2.不幸的是, np nan 一直是我所有数据方的客人,我不得不使用这个函数将其从字符串列表中移除——

3.如果你没有字符串列表,那么在字符串中删除重复项就有点复杂了,所以为了安全起见,这里是第一个函数的扩展。

4.移除非类型是我们需要考虑的另一个麻烦。

标签生成

欢迎使用机器!这里有几个移动部分——选择和调整参数。其中第一个是字数(len(q))第二个是三元组和二元组第三个是PMI(点态互信息)。我们使用 PMI 来识别“搭配的单词。首先,让我们解开双循环,走向 if-else。****

因为数据列表的长度等于行数,所以让我们在原始数据框中创建一个单独的列来开始操作。我们可以通过更改列表本身并将其附加到数据框来实现相同的目标。

  1. 首先,我们将对数据中的每个字符串元素使用split()函数来创建一个双列表。然后我们将basic_cleanandcapitalize()这些单词,并开始一个接一个地删除和操作双列表中的每个单词/字符串。

2.我们将分割字符串(总数据中的单词)并创建一个我们想要检查的虚拟列表‘q’。

3.正如您可能看到的,我们希望将单词限制在长度 2–4 之间,所以我们想要一个长度在(1,5) 之间的字符串。然后,我们将列表放回字符串中,并将其与原始数据框连接起来。

4.否则——我们使用列表中的三元模型查找器,并应用过滤器 apply_freq_filter ( 移除频率小于 min_freq 的候选元模型)。— 1 表示单词至少出现一次,这是另一个可以考虑的值。这里你也可以使用一个 bigram_measures 和bigram collocation finder**

5.我们还使用 finder 和 nbest 来测量 PMI 以检查单词一起是否有意义,并从该元组([0:1]) 中选择前两个候选项,这里的机制是位扭曲的,试错法将比 PMI 的数学解释得更多。

6.最后,我们将元组转换成字符串,并在将临时变量合并到数据帧之前使用 tidy 函数。我们可以通过制作标签来总结:

**df1['Hashtags'] = df1['Data_total_grams'].apply(nonetype_remove )**

结论

上述过程解释了如何将句子转换成有意义的两个或三个单词的组合,并选择适合应用的单词。这篇文章的总体目标是解释简单的人工智能算法如何帮助和授权资源有限的社区进行“标记”和“标注”。关于人工智能的社会挑战组织人工智能伦理的定性文章阐明了这个问题。这篇文章是将事情付诸行动的一个小小尝试。我们可以在 https://toughleaf.com找到算法的应用

在没有任何 Web 开发经验的情况下,如何将您的数据见解转化为网站

原文:https://towardsdatascience.com/how-to-transform-your-data-insights-into-websites-without-any-web-development-experience-44fde2d72648?source=collection_archive---------19-----------------------

使用 WordPress 和 SQL 以视觉上引人注目的方式展示您的 Python 见解

通过使用 WordPress 和 SQL 让您的数据见解变得可访问——作者插图(官方示例图表/表格由 wpDataTables 提供)

当用 Python 完成一个漂亮的分析时,有没有感觉被切断了?我也是——我没有提交另一个 Jupyter 笔记本,里面有一些沉重的机器学习材料,充满了 seaborn 主题的情节,而是花了一整夜的时间研究如何让公众更容易获得这种分析,并以更专业的方式呈现见解。

结果呢?在 WordPress 上运行的网站以清晰的方式展示见解,并允许最终用户与数据交互。该网站通过使用简化的 Python 文件填充的数据库来访问分析数据。棘手?绝对不是,使用 WordPress 不需要大量的网页编码,并且允许通过拖拽来建立一个网站。

使用 WordPress 和 SQL 将您的数据见解发送到一个简单的 web 应用程序中——作者插图

因此,让我们把它分成小块,用一个简单的例子一步一步地完成整个过程。

#0 获取一些数据

重要提示: 下面讨论的所有代码片段也可以在 GitHub 上我的 资源库 中的一个完整的 Jupyter 笔记本文件中找到。

第一步从 python 文件(或 Jupyter 笔记本)开始,我们在其中执行分析任务,并加入额外的代码来与数据库交互:

通过 Python 与数据库交互的元素—作者插图

为了简化,我们将使用通过雅虎的金融 API 获得的一些股票数据,并创建一个简单的数据框架。

安装 Yahoo API 连接器库以下载历史市场数据:

$ pip install yfinance

获取特斯拉股票信息:

特斯拉上市前 100 天的股票信息——作者配图

#1 创建一个数据库

对于数据库系统,我们的目标是 PostgreSQL。这是最成熟的方法之一,可以完美地与 WordPress 网站配合使用。其他流行的 SQL 数据库有 MySQL 和 MS SQL。

有各种各样的提供商为在云中运行数据库提供负担得起的托管计划。除了现有的平台,如亚马逊 AWS 或微软 Azure,我建议你注册一个平台,免费为你提供(1)个基本计划,或者如果你只是想为自己复制展示,提供(2)个试用版本。

注意:你也可以在本地运行数据库设置和 WordPress 网站,这不需要任何托管。然而,由于我们对制作一个公共网站感兴趣,我们将致力于在云中部署。

在我的例子中,我使用的是elephantsql.com,它提供了一个免费版本,但没有提供任何支付细节。数据库的启动和设置都在短时间内完成:

  1. 去 elephantsql.com
  2. 创建一个帐户
  3. 选择免费计划(“小乌龟”)并完成配置过程(托管区域无关紧要)
  4. 转到控制台(customer.elephantsql.com ),单击刚刚创建的数据库
  5. 参见详细信息部分中的数据库凭证

连接到数据库所需的凭据详细信息–作者插图

注意:如果数据的持久性至关重要,我建议使用具有额外安全保护(SSL、IP 范围等)的方案。)和用于快速恢复的高可用性,这也是行业标准。

#2 连接到数据库

我们使用pg8000作为 PostgreSQL Python 连接器,这需要 pip 安装。

注意:这个库是专门为 PostgreSQL 数据库设计的。对于 MySQL 或其他数据库,可能需要不同的连接器。

$ pip install pg8000

#3 创建模式和表

接下来,我们创建一个模式和表,将数据正确地存储在数据库中。PostgreSQL 中支持的常见数据类型有:

  • boolean
  • date
  • timestamp
  • decimal
  • float
  • varchar(n)
  • numeric

注意:数据类型因数据库系统而异。

为了简化,我们只检索DateClose列,以便稍后创建一个简单的折线图。当我们想要发送查询来与数据库交互时,我们使用 SQL 语言(参见代码片段中的字符串)。

注意:[IF NOT EXISTS]是可选的,它检查具有该名称的表/模式是否已经存在。这有助于避免在常规测试中覆盖数据。

#4 向数据库发送数据

我们通过使用一个list of lists(“obj”)将数据发送到数据库,其中每个列表代表数据帧中的一行。变量s用 SQL 语法表示查询。我们引用希望填充到数据库中的列,并为它们的值提供“占位符”%s。确保obj的顺序必须符合查询中定义的顺序。

注意:游标方法允许遍历整个列表,这将只需要一个查询。

快速完整性检查,查看数据是否发送到数据库:

PostgreSQL 数据库中的前 5 行数据—作者插图

#5 WordPress 基础

背景 WordPress 是最强大的开源内容管理系统之一。最初是作为一个博客系统创建的,它已经发展到支持其他相关领域,如电子商务、报纸或企业网站。你使用模板来构建网站,这意味着你可以通过拖放来添加内容,而不必关心后端本身。您可以访问一个第三方插件池来构建非标准特性,在我们的案例中我们也会这样做。根据 w3techs.com,大约。排名前 1000 万的网站中有 41%运行在 WordPress 上,这充分说明了这个网站建设者的便利性和安全性。

WordPress 内容管理系统的技术架构——作者举例说明

这篇文章不包括 WordPress 网站的设置。已经有大量的文章对此进行了解释。如果你是一个完全的初学者,我建议你遵循下面列出的资源:

由于我们的目标是部署一个在线网站,我们需要一个网站托管计划(包括一个域)。下面是一些提供特殊 WordPress 托管计划的提供商,在这些计划中,WordPress 可以立即配置(通常只需几次点击) :

托管计划(2021 年 5 月)-作者插图(维基媒体图片用于公司标志)

注意:WordPress 也需要一个数据库(与 MySQL 或 MariaDB 数据库配对)。理论上,也可以使用集成的。在某些提供商处,默认情况下并不总是提供对它的访问,这就是我们使用独立数据库的原因。

新手的动力
不要一开始就被 WordPress 冲昏了头脑,把下面的插图看做一点动力:

到达临界点——作者插图

开始的时候,这看起来像是一个失望的山谷,但是一旦你理解了基本原理,由于 WordPress 的低代码模板方法,你就能够在很短的时间内构建几乎所有的东西(例如,仅在一天内建立一个电子商务商店)。代码密集型 web 框架,如 Bootstrap 或 Python Django,对于初学者来说实际上是一场真正的斗争,并且对于每一个新的案例都需要额外的上下文知识。

#6 通过 WordPress 插件连接到数据库并创建可视化

一旦你有了一个运行在 WordPress 上的网站,我们就会寻找一个允许连接到 PostgreSQL 数据库的插件。

到目前为止,我用过的最好的与 SQL 数据库接口的 WordPress 插件叫做 wpDataTables 。它有一个免费的限量版和一个收费版,起价为 42 美元/年。它自动将 SQL 查询转换成可用于网站的表格,这些表格可以使用 JavaScript 或其他流行的图表呈现引擎进一步转换成图表。除了 PostgreSQL 连接,您还可以访问 MySQL 和 MS SQL 数据库,以及加载平面文件。

wpDataTables 官方提供的样表和图表

我建议使用付费版本(15 天退款保证),因为数据库连接只涵盖在付费版本。

关于如何安装这个插件的详细指南可以在他们的官方网站上找到。

一旦安装了插件,我们只需要建立一个连接并编写一个 SQL 查询来创建我们选择的可视化:

通过插件访问数据库的步骤——作者举例说明

连接数据库

在 WordPress 控制台中:

  1. 转到 WP 数据表一节
  2. 点击设置
  3. 选择独立数据库连接
  4. 插入您的数据库凭证(对于字段端口驱动程序,分别填写 5432 和 ODBC。端口信息最初不会显示在 elephantsql.com 的控制台上)
  5. 点击保存更改创建连接

创建图表或表格

为了简化,我们选择股票表,并创建一个简单的图表。

注意:使用图表时,我们总是要先创建一个表格。

在 WordPress 控制台中:

  1. 转到第节 WP 数据表
  2. 点击创建表格
  3. 选择您的连接,然后选择创建一个链接到现有数据源的数据表
  4. 选择 SQL 查询作为输入数据源类型,并分配一个名称
  5. 编写 SQL 查询:

6.点击保存更改运行查询(如果查询成功,现在已经创建了表格)

7.转到创建图表

8.分配一个名称并选择一个图表渲染引擎(我推荐使用 chart.js )

在这一步之后,您将转到格式化和预览部分:

格式部分—作者插图

9.点击保存更改创建图表并获取短代码

快速实施的简码—作者举例说明

WordPress 中的 shortcode 是一小段代码,用方括号表示,指的是一个功能(这个图表,一个图库,等等)。) .现在,您只需要将这个短代码实现到您想要的页面中。不需要转换,在编辑页面时,只需将收到的短代码粘贴到文本元素中。

这是最后一步。您已经构建了第一个准备发布的小数据产品!

现在,您拥有了从 python 文件到网站的无缝连接,这意味着您可以更新 Python 文件,并且可视化效果将由于 SQL 查询而自动更新。

进一步的例子

我最近在一个大学项目中也使用了 WordPress。你可以在这里查看,或许还能获得一些设计网站的灵感。注意,这个项目的焦点不是分析本身,而是它的数据管道。

subway.christopherkindl.com 快照-作者插图

GitHub 知识库

https://github.com/christopherkindl/python-data-to-sql-database

参考文献:

[1]W3techs.com。(2021).内容管理系统使用统计https://w3techs . com/technologies/overview/content _ management。检索于 2021 年 5 月 29 日。

[2]Websitebuilderexpert.com。(2021).7 最便宜的 WordPress 托管https://www . websitebuilderexpert . com/we B- Hosting/Cheap-WordPress/。检索于 2021 年 5 月 29 日。

[3]Themeisle.com。(2021).WordPress 中的短码是什么?https://theme isle . com/blog/what-are-short codes-in-WordPress/。检索于 2021 年 5 月 29 日。

从学术界到数据科学

原文:https://towardsdatascience.com/how-to-transition-from-academia-to-data-science-5821ebe598a?source=collection_archive---------30-----------------------

实用指南

图片来源: Unspash

哦,天啊,又一篇关于从学术界过渡到数据科学的博文。好吧,在这篇文章中,我会试着在一些更传统的建议之外,加入一些对通常建议的稍微不同的看法。这不是一步一步的指导,因为我不认为在这种情况下有这样的事情存在。相反,这篇文章将是我对如何从学术界平稳过渡到数据科学的个人观点。此外,这篇文章不是关于“如何获得数据科学工作”。我不会谈论你的简历,或者为面试做准备之类的事情。这篇文章是关于如何成为一名数据科学家的。

首先,我应该注意到,虽然我在这篇文章中涉及的许多事情可能是通用的,并适用于许多不同的情况,但我将首先提出一些假设。

  1. 你已经进入了一个技术领域(数学、统计、物理、化学、生物等)。
  2. 你有一定的编程知识(任何语言都可以)。
  3. 你打算从事的数据科学职业是应用型,而不是研究型的。
  4. 如果你正在攻读博士学位,所有这些可能会更适用,但对学士学位仍然适用。

好了,让我们开始吧。

数据科学到底是什么?

如果你偶然看到这个博客,你可能对数据科学有所了解,或者你认为你知道它是什么。数据科学可能意味着你整天管理数据库和编写 SQL 代码。这可能意味着您使用“大数据”工作,并使用 Hadoop(这可能还是一件事吗……)、Spark 和其他大数据工具做事。但愿不会,这可能意味着你在 Excel 中做的大部分工作都是制作线性回归模型。

但根据我的经验,当大多数人说数据科学时,他们真正的意思是“机器学习工程师”,即开发和应用 ML 模型到真实数据并部署它们以用于真实世界场景的人。当然,还有更多的内容,但这是要点,也是我在这篇文章的剩余部分中想到的那种数据科学家。

学术界是如何让我为这个角色做好准备的?

我知道当我还是研究生的时候,我以为我这辈子只准备做一件事——成为一名(天文)物理学教授/研究员(在一段漫长的博士后生涯之后)。在我读物理研究生的时候(2009 年至 2014 年),几乎没有人提到过任何其他职业轨迹。假设这是每个人都会走的路,这基本上意味着只有一种操作模式:写论文

但是,在你的学术生涯中(无论是本科还是研究生)仍然会学到很多对你的数据科学(咳咳…机器学习工程师)生涯非常有用的东西。

学习斗争

有些技巧是教不来的。他们只能通过斗争来学习。如果你在你的学术领域做过任何种类的原创性研究,那么你就会知道其中的艰难。你必须学会自己解决问题,因为没有“正确的答案”可以在书的后面找到。如果你曾经编写过任何重要的代码库,那么你也知道其中的挣扎。你必须弄清楚如何将所有的东西放在一起,并调试不可避免会出现的错误。

在数据科学中,你的大部分时间都在挣扎,你需要能够对在特定时刻不知道该做什么感到舒服。你需要能够尝试,并且有可能失败。在许多情况下,利益相关者(想要某种 ML 产品/功能的个人/实体的花哨语言)并不太了解 ML,他们所知道的只是他们想要的最终产品是什么样子。事实上,在某些情况下,他们甚至不知道自己想要的最终产品是什么样子。更常见的情况是,他们拥有大量数据(当然是非常干净的),并且他们希望从这些数据中获得“洞察力”。作为机器学习工程师,你需要做好准备,努力找到他们问题的解决方案。

即使你将在基于 ML 的问题中经历的斗争可能与你在学术界经历的不同,但对不确定性感到舒适将为你作为机器学习工程师的职业生涯做好准备。

在下一节中,我将提供一些建议来更好地熟悉基于 ML 的斗争。

学习如何学习

与“奋斗”密切相关的是学会如何学习。每个人都以不同的方式学习,在你的学术生涯中,很有可能你已经发现了自己的方法。在很多情况下,尤其是在我的课堂上,你会意识到你并没有从课堂上学到很多东西。当然,你可能在考试中表现很好,但你会在一周内忘记一切。你通过做来学习。没有实践,所有的理论都是毫无价值的。你会相信一个花了几年时间研究最新外科技术,但从未真正实施过外科手术的医生吗?你会招募一个了解所有音乐理论但从未真正弹过吉他的“吉他手”吗?

稍后我将在这方面提供一些建议,但知道如何自主学习是数据科学或生活中最重要的技能之一。

“软技能”

总的来说,软技能是人际技能和沟通技能的结合。这一点很大程度上取决于你是否必须向技术和非技术观众展示你的作品。这也取决于你是否参与了一个大型合作项目。

也就是说,能够以清晰简洁的方式向非技术受众展示技术信息是一项技能,它将帮助你获得一份好的数据科学工作。正如我上面提到的,我专注于应用数据科学的工作,而不是研究数据科学家的职位。这意味着你需要能够与利益相关者以及你的队友沟通。

如果你有幸参与了一个大型协作项目,并与许多需要合作的不同团队合作,那么你将获得宝贵的技能,这些技能将真正在数据科学领域对你有所帮助。能够在不同群体之间进行翻译是一项非常有用的技能。例如,当我还是研究生时,我是数据分析小组的一员,我们主要使用贝叶斯技术。还有另一组人主要使用 T2 常客技术。从表面上看,这些事情可能非常不同,但两者之间有一些有用的翻译,我会说两种语言,这使得事情进展得更顺利。

同样,在下一节,我会给出一些关于如何练习沟通技巧的建议。

实用(而且非常固执己见)的建议

如题,这个建议很固执,但是这些方法对我来说效果很好。在给出实际建议之前,让我解释一下我对数据科学家候选人的要求:

  1. 一个容易相处并有良好的个人/沟通技巧的人。对于一个技术角色来说,这可能看起来不太重要,但对我来说却至关重要。大多数数据科学家在团队中工作,因此能够相处和沟通至关重要。
  2. 一个在过去表现出主动性并且相当自我激励的人。这不需要与 ML/数据科学相关,它可以应用于你的学术研究领域,但也可以应用于你向数据科学过渡的准备。
  3. 对“真实”数据有经验的人。我说的真实数据是指杂乱的数据。我想看到你已经学会了奋斗并接受了它。同样,这也适用于你的学术经历或数据科学准备。
  4. 能够谈论许多不同的 ML 技术的人。这并不意味着您需要非常深入地了解任何细节,但是您应该对现有的技术及其应用有所了解。

就这样,让我们得到建议

1.学习 Python

Python 是机器学习的语言。它非常容易使用,并且它主要包装了用更高性能的语言编写的库,比如 c。

python 的成长(来源: KDnuggets )

它在所有领域都在增长,不仅仅是 ML,但在这篇文章中,我将重点关注 ML。Python 在 ML 中非常强大,因为有几个专门构建的 ML 库,比如熊猫tensorflowpytorchscikit-learnspacy变形金刚等等。

如果你已经知道 Python,那太好了。如果你没有,还有很多资源可以学习。我不建议用一本书来学习 Python,因为已经有这么多好的资源了。从 Matlab 转到 Python 之后,我学习了 Python,这些年来,我通过查看如上所述的设计良好的代码库,以及观看各种 YouTube 教程和其他在线资源,磨练了自己的技能。事实上,我从来没有读过关于 Python 编程的书(关于机器学习或深度学习或统计学,但我稍后会深入讨论)。

2.学习软件设计原则

好,那么你已经学了 Python。准备好了吗?不完全是,在我真正学会如何设计软件之前,我已经知道如何使用 Python 很长时间了。我总是用盖房子来比喻。你可能真的很擅长使用所有的工具,但是如果你没有蓝图,不知道各种各样的代码和标准,或者不知道从哪里以及如何获得所有的材料,那么你就不走运了。虽然了解 Python 语言非常重要,但实际上了解软件设计原则(主要是语言不可知的)将真正让你脱颖而出。

这一部分本身可以作为几篇博客文章,但我在这里只提到主要的亮点:

  1. 面向对象编程(OOP) :虽然函数式编程没有任何问题,但你确实会在日常生活中混合使用 OOP 和函数式编程。ML 生态系统(也就是上面提到的包,尤其是 PyTorch 和 scikit-learn)大部分在 OOP 阵营。能够理解基于 OOP 的包并能够编写自己的基于 OOP 的代码是非常重要的。
  2. 单元测试持续集成(CI) :这两者通常是并行的。单元测试是指对你的代码“单元”进行特定的测试。这是为了检查您的代码是否正确,也是为了在您进行更改时防止代码被破坏。CI 基本上包括自动化这个测试过程,也可以包括单元测试之外的其他类型的测试。掌握这一点将会给你带来巨大的优势。
  3. 设计模式:这些是解决特定问题的可重复使用的模式。这些模式大多与语言无关。现在,您不需要知道所有不同的模式,也不需要总是使用它们;然而,对他们的所作所为有一个基本的了解(以及他们的存在)会让你处于一个很好的位置。
  4. 文档:在你的学术生涯中,你可能编写了适合你的代码。你知道如何使用它,而且它有效。作为数据科学团队的一员,其他人需要能够使用和理解您的代码。代码文档至关重要,了解最佳实践也非常重要。

上面的列表只是从细节上触及了表面。我为每一个提供了一个基本的教程链接,但是还有很多其他非常好的资源来学习正确的编码实践和工具。这里有几个:

在结束这一部分时,我要指出,根据我的经验,大多数数据科学家(尤其是机器学习工程师)对这些东西的了解非常有限。所以,这不是你在竞争中所缺少的东西。然而,如果你确实知道这些事情,并花时间去学习它们,那么它会让你在竞争中脱颖而出。更重要的是,它会让你成为更好的数据科学家。

3.做一些项目(并分享)

好了,这就是标准建议的来源,但它是标准的是有原因的。如果你来自学术背景,而不是数据科学背景,你必须做一些项目来填补你缺乏的在职经验。从某些方面来说,这是一个额外的收获,尤其是如果你的竞争对手是那些上过数据科学或类似领域的学校的人。记住我说过的自我激励。对于那些从事数据科学或分析项目的人来说,他们的大部分经历都是通过他们“不得不”做的课程获得的。对于你这个自学成才的数据科学家来说,你通过展示你已经完成的数据科学项目来表明你是自我激励的。

现在你可以做很多不同种类的项目。我将按照重要性的大致顺序列出三个:

  1. 数据讲故事项目:在我看来,这种项目是你能做的最有用的。基本上就是选择一个你感兴趣的领域,找数据,分析,讲故事。你甚至不需要做任何 ML。这些项目展示了你使用未经过滤的原始数据的技能,(尽量不要使用经过筛选的数据集),还可以让你在数据科学的斗争中获得一些经验。在我的案例中,我查看了警察枪杀平民,并从一些数据库中提取数据,包括人口普查数据、联邦调查局犯罪统计数据和当地警察局数据。在这个过程中,我花了很大的力气将所有这些资源整合在一起,并了解了大量关于熊猫和各种 python 地图包的知识。
  2. 完整的端到端 ML 应用:这种项目会给人留下非常深刻的印象,并显示出你有实际 ML 部署的经验,这是许多候选人和实际数据科学家(包括我自己)所缺乏的。
  3. 你可以通过做一些 Kaggle 比赛和查看公共笔记本来了解很多关于 ML 的事情。这些都在列表中,因为它们对你获得一些将 ML 应用于数据的经验很重要,但它们是最后的,因为这种工作现在无处不在,所以它不会让你与众不同。

一旦你做了一些项目,并通过大量的努力获得了一些 ML 和数据辩论技巧,现在你可以提高你的沟通技巧了。

首先,一定要把你做的任何事情放到 GitHub 上,这将公开你的工作,如果你还不知道的话,还会教你版本控制。请确保用项目自述文件记录您的项目。这只是最低级的分享你的作品。

接下来,你可能想在个人博客或媒体上分享这个作品。这是另一个磨练你的沟通技巧和确保你真正理解你的项目的好方法。测试你的知识的最好方法是试着向别人解释你的项目。然而,写博客仍然有些被动,这些技能不是成为一名成功的数据科学家所需的主要沟通技能。

最后,你可以通过演讲来展示你的作品。这种事情大概有很多论坛。就我而言,我在 Meetup 上寻找任何本地数据科学相关的团体。先参加一些聚会,并向组织者介绍自己,这可能是个好主意。他们通常在寻找任何想演讲的人。如果有机会,主动提出就你的一个项目做一个演示。

因此,这听起来很多,你未来的公司可能甚至不会看你做的所有工作,但即使他们不会看,你做了所有这些并发展和磨练了所有这些技能的事实将极大地帮助你作为数据科学家的整体职业生涯。

4.学习行话(假装直到你成功)

当我还是大学生的时候,我的一位物理学教授给了我一些很好的建议。他告诉我们,就你的职业生涯而言,最重要的事情之一是你“学习行话”,也就是说,你学习你正在从事或想要从事的领域的语言。例如,如果有人对你说他们“使用了一个变压器模型进行情感分析”,你需要从这句话中得到什么?你肯定不需要知道变压器模型是什么或如何实现它的任何细节,但你应该知道情感分析是指测量一段文本的“积极”或“消极”程度,而“变压器”模型是一种深度学习模型,现在在自然语言处理中非常流行。

换句话说,对许多概念有广泛但浅薄的理解要比对几个概念有非常深刻的理解好得多。这在很多情况下几乎与学术研究背道而驰。在学术界,一个人非常需要对自己的领域有非常深刻的理解,代价是对该领域以外的知识了解不多。作为一名数据科学家,情况正好相反,对许多概念及其用途有一个基本的了解要比知道精确的算法细节好得多。

这又回到了我早先提出的关于学会如何学习的观点。如果你对许多事情有肤浅的理解,那么这将允许你快速评估一个给定的问题,并提出一个潜在的解决方案;然而,要真正实现这个解决方案,你可能需要学习更多你目前所知道的东西。因此,你需要能够脚踏实地地学习。作为一名学者,似乎你总是需要提出新的东西,但在数据科学中,没有人真正关心你是否提出了新的东西,他们只关心你是否解决了问题。这意味着,在互联网上搜索与你类似的问题的解决方案,并对其进行调整以解决你的问题,这并不可耻。

所有这些似乎都是错误的,但这是我收到的最好的建议,我认为它对我帮助很大。现在,这一切听起来不错,但你怎么做呢?这是最难的部分。我认为发展这种技能的最好方法是允许自己探索许多领域,但也要控制自己不要挖得太深,至少在你还在学习的开始阶段。参加介绍性的在线课程,跟随教程,做一些简单的项目,但是不要认为你需要知道所有的细节。

5.在线学习

好了,现在来谈谈另一个有争议的建议。不要看书来学习你的数据科学/ML 技能。至少,不要把书作为主要的信息来源。我唯一会推荐的书籍是学习基本的编程语言基础知识,(尽管在线学习可能更好)。

我从未读过关于编程、机器学习、深度学习、统计学或通信的书籍,但在我的学术生涯中,我发表过几篇论文,并领导过大型工作组。在学术界之外,我进步相当快,并领导了几个人工智能领域的项目,所有这些都是严格通过在线学习实现的。

现在,在线学习并不意味着你被动地坐下来看一些 YouTube 视频。这意味着你看一些 YouTube 视频或在线课程或阅读博客帖子或 arXiv 论文,然后自己尝试这些东西。你挣扎。你多看多读。再奋斗一些。在你的工作或项目中应用这些技术。再奋斗一些。在这个阶段结束的时候,你会意识到你已经学会了很多,不是通过一些基础的方法,而是通过一个更随机的试错过程,最终导致对材料更深刻的理解。

这听起来可能很疯狂,可能对你无效,但对我有效,对许多其他伟大的数据科学家和机器学习工程师也有效。我有一个非常简单的学习方法,我涉猎了许多不同的东西,但是除了我已经在这篇文章中提供的资源之外,我还可以在这里提供一些好的资源。

  1. Coursera :这里有很多很棒的课程,可以给你很好的介绍很多话题,尤其是机器学习深度学习。参加 Coursera 课程后,不要期望成为任何方面的专家,但他们可以给你一个良好的基础。
  2. fast.ai :我会说这是学习前沿深度学习技术的最佳资源。不幸的是,它是由一个软件库支持的,在我看来,这个库结合了所有最糟糕的编码实践,并把它们都放在一个地方。即便如此,还有两个很棒的深度学习课程和一个更不为人知的机器学习 ( github 此处)和线性代数课程。
  3. YouTube:你几乎可以在 YouTube 上找到任何你想要的关于数据科学/ML/编程的东西。问题是质量参差不齐。我不会推荐特定的频道或视频,(其中一些我已经在上面提到过了)我只会说,对我来说,在许多情况下最有用的视频是实时演练,他们在实时编码(这是 fast.ai 很棒的原因之一)。然而,有时你只是对一个概念感兴趣,所以编码并不重要。不管怎样,YouTube 是一个每个人都可以使用的神奇资源。
  4. 博客帖子:走向数据科学可能有一些非常好的帖子,但里程数各不相同。这主要是说,看看随机的博客帖子来学习东西可能不是一个坏主意。即使帖子本身不是很好,通常也有其他参考资料可以引导你找到你想要的东西。
  5. 代码文档和源代码:许多大型代码库都有大量的文档和教程。浏览这些教程是一次很好的学习经历。在其他一些情况下,查看源代码本身可以向您展示一些良好的编程实践,(在某些情况下,您会惊讶于各种项目的源代码有多糟糕)。对于组织良好且文档记录良好的代码,我推荐初学者使用 PyTorchscikit-learn
  6. Twitter:可以是垃圾箱,但也可以是学习新事物和建立新联系的好工具。我实际上是通过一个 twitter 朋友找到我现在的工作的。这里不胜枚举,但搜索数据科学或机器学习,关注一些更受欢迎的帐户。最终,你会发展这个网络,并把它作为一种信息过滤器。

包裹

如果你能走到这一步,恭喜你!这篇文章比我最初计划的要长得多。我已经在这里介绍了很多东西,这可能看起来令人望而生畏。当我第一次开始这个旅程时,我一直在想,我不可能学会所有这些东西,也许留在学术界会更好。如果你对你的学术领域充满热情,那么无论如何不要放弃,但是如果你只是因为你认为没有其他选择而呆在那里,那么这是一个完全错误的假设。

我在这篇文章中提到的所有事情都是我在过去 3.5 年的数据科学家生涯中学到的。一开始我并没有做所有这些事情,从那以后我学到了很多。

最后,如果你正处于这种转变中,并且感到有压力,请记住,一旦你获得了这些技能,你将成为抢手货,几乎可以在任何地方找到一份令人满意的工作。

原载于 2021 年 1 月 3 日https://jellis 18 . github . io

AI 配音过 Subs?用人工智能翻译和配音视频

原文:https://towardsdatascience.com/how-to-translate-and-dub-videos-with-machine-learning-55204e55a960?source=collection_archive---------43-----------------------

unsplash.com

除了为自己做饭和绕着房子走几圈,日本卡通(或者孩子们称之为“动画”)是我在隔离期间学会喜欢的东西。

不过,看动漫的问题是,如果不学习日语,你就要依赖人类翻译和配音员把内容翻译成你的语言。有时你得到了字幕(“subs”),但没有配音(“dubs”)。其他时候,整季的节目根本没有被翻译,你只能坐在座位的边缘,只有维基百科的摘要和 90 年代的网络论坛带你穿越黑暗。

那你该怎么办?答案显然不是让计算机将一部电视节目的全部片段从日语转录、翻译和配音成英语。翻译是一门精细的艺术,不能自动化,需要人手的爱心触摸。此外,即使你确实使用机器学习来翻译视频,你也不能使用计算机来配音……我的意思是,谁会愿意听一整季的机器声音呢?那会很糟糕。只有真正的神经病才会想要那个。

因此,在这篇文章中,我将向你展示如何使用机器学习来转录、翻译视频,并将视频从一种语言转换为另一种语言,即“人工智能视频配音”它可能不会给你带来网飞质量的结果,但必要时你可以用它来本地化在线对话和 YouTube 视频。我们将从使用谷歌云的语音转文本 API 将音频转换成文本开始。接下来,我们将使用翻译 API 翻译该文本。最后,我们将使用文本到语音转换 API 为翻译“配音”,根据文档,它产生的声音“像人一样”。

(顺便说一句,在你在评论中炮轰我之前,我应该告诉你,YouTube 将自动免费为你转录和翻译你的视频。所以你可以把这个项目当成你从头开始烘焙酸面团的新爱好:这是对 30 个小时的低效利用。)

人工智能配音的视频:它们通常听起来很棒吗?

在你开始这段旅程之前,你可能想知道你有什么期待。我们现实地期望从 ML 视频配音管道中达到什么质量?

这里有一个从英语自动翻译成西班牙语的例子(字幕也是自动生成的英语)。我没有对它进行任何调整或调节:

正如你所看到的,转录是体面的,但并不完美,同样的翻译。(忽略说话者有时语速太快的事实——稍后再谈。)总的来说,你可以很容易地从这个配音视频中了解事情的要点,但它并不完全接近人类的质量。

让这个项目比大多数项目更棘手(更有趣)的是,至少有三个可能的失败点:

  1. 语音转文本 API 可能会错误地将视频从音频转录为文本
  2. 翻译 API 可能会错误或笨拙地翻译该文本
  3. 这些翻译可能会被文本到语音转换 API 读错

以我的经验来看,最成功的配音视频是那些在清晰的音频流中有一个人说话,并从英语配音成另一种语言的视频。这主要是因为英语的转录质量(语音到文本)比其他源语言高得多。

事实证明,从非英语语言配音更具挑战性。这是我最喜欢的节目之一《死亡笔记》的一段特别平淡无奇的日语到英语的配音:

死亡笔记的原始视频

如果你想把翻译/配音留给人类,好吧——我不能怪你。如果没有,请继续阅读!

构建人工智能翻译配音员

和往常一样,你可以在用机器学习 Github repo 制作的中找到这个项目的所有代码。要自己运行代码,请按照自述文件配置您的凭证并启用 API。在这篇文章中,我将简单介绍一下我的发现。

首先,我们将遵循以下步骤:

  1. 从视频文件中提取音频
  2. 使用语音转文本 API 将音频转换为文本
  3. 将转录文本分割成句子/片段进行翻译
  4. 翻译文本
  5. 生成翻译文本的语音音频版本
  6. 加速生成的音频,使其与视频中的原说话者一致
  7. 将新音频缝合到折叠音频/视频的顶部

我承认,当我第一次着手构建这个配音器时,我充满了傲慢——我所要做的就是将几个 API 插在一起,还有什么比这更简单的呢?但是作为一个程序员,所有的傲慢都必须受到惩罚,好家伙,我也受到了惩罚。

具有挑战性的部分是我上面加粗的部分,主要来自于必须将翻译与视频对齐。但一会儿我们会详细讨论这个问题。

使用谷歌云语音转文本 API

翻译视频的第一步是将音频转换成文字。为此,我使用了谷歌云的语音转文本 API 。这个工具可以识别 125 种语言的音频,但正如我上面提到的,英语的质量最高。对于我们的用例,我们希望启用一些特殊功能,比如:

  • 增强型。这些是经过特定数据类型(“视频”、“电话呼叫”)训练的语音到文本模型,通常质量更高。当然,我们将使用“视频”模型。
  • 脏话过滤器。这个标志防止 API 返回任何不良单词。
  • 字时间偏移。这个标志告诉 API 我们希望转录的单词和说话者说这些单词的时间一起返回。我们将使用这些时间戳来帮助我们的字幕和配音与源视频对齐。
  • 语音适配。通常,语音到文本转换最难处理的是不常用的单词或短语。如果您知道某些单词或短语可能会出现在您的视频中(即“梯度下降”、“支持向量机”),您可以将它们以数组的形式传递给 API,这将使它们更有可能被转录:
client = speech.SpeechClient()  
# Audio must be uploaded to a GCS bucket if it's > 5 min
audio = speech.RecognitionAudio(uri="gs://path/to/my/audio.wav")

config = speech.RecognitionConfig(
  language_code="en-US"
  # Automatically transcribe punctuation 
  enable_automatic_punctuation=True,
  enable_word_time_offsets=True,
  speech_contexts=[
    # Boost the likelihood of recognizing these words:
    {"phrases": ["gradient descent", "support vector machine"], 
     "boost": **15**}
  ],
  profanity_filter=True,
  use_enhanced="video",
  model="video")

res = client.long_running_recognize(config=config, audio=audio).result()

API 将转录的文本连同单词级时间戳作为 JSON 返回。举个例子,我转录了这个视频。你可以在这个 gist 里看到 API 返回的 JSON。输出还让我们进行快速的质量健全性检查:

我实际说的:

“软件开发者。我们的摇滚风格并不出名,对吧?或者说我们?今天,我将向你展示我如何利用 ML 让自己变得更时尚,从有影响力的人那里获取灵感。”

API 以为我说了什么:

“软件开发者。我们的摇滚和风格并不出名。我们还是今天的我们吗?我将向你展示我是如何利用 ml 从有影响力的人那里获取灵感来打造新的时尚潮流的。”

根据我的经验,这是你在转录高质量英语音频时可以期待的质量。注意标点有点偏。如果你对观众理解视频的要点感到满意,这可能已经足够好了,尽管如果你说的是源语言,你可以很容易地自己手动修改脚本。

此时,我们可以使用 API 输出来生成(未翻译的)字幕。事实上,如果您用`-srt '标志运行我的脚本,它会为您做到这一点( [srt](https://blog.hubspot.com/marketing/srt-file#:~:text=An SRT file (otherwise known,the sequential number of subtitles.) 是隐藏字幕的一种文件类型):

python dubber.py my_movie_file.mp4 "en" outputDirectory **--srt** **--targetLangs** ["es"]

机器翻译

现在我们有了视频抄本,我们可以使用翻译 API 来…嗯…翻译它们。

这是事情开始变得有点🤪。

我们的目标是这样的:我们希望能够翻译原始视频中的单词,然后在大致相同的时间点播放它们,以便我的“配音”声音与我的真实声音保持一致。

然而,问题是翻译不是逐字逐句的。从英语翻译成日语的句子可能语序混乱。它可能包含更少的词,更多的词,不同的词,或(如成语)完全不同的措辞。

解决这个问题的一个方法是翻译整个句子,然后试着调整这些句子的时间界限。但是即使这样也变得复杂了,因为你如何表示一个句子呢?在英语中,我们可以用标点符号来拆分单词,例如:

"Hi! My name is Dale. What's up?" --> ["Hi", "My name is Dale", "What's up"]

但标点符号因语言而异(英语中没有),有些语言根本不用标点符号分隔句子。

另外,在现实生活中,我们通常不会用完整的句子说话。你知道吗?

另一个让翻译抄本变得困难的问题是,一般来说,你输入到翻译模型中的越多上下文,你就能期待更高质量的翻译。举个例子,如果我把下面的句子翻译成法语:

"我感到忧郁,但我也喜欢粉红色。"

我去拿翻译过来的:

"我喜欢蓝色,但我也喜欢玫瑰."

这是准确的。但是,如果我把这句话分成两部分(“我感到忧郁”和“但是我也喜欢粉红色”),并分别翻译每一部分,我会得到:

“Je me sens triste,mais j'aime aussi le rose”,即“我感到悲伤,但我也喜欢粉红色。”

这就是说,我们在将文本发送到翻译 API 之前分割得越多,翻译的质量就越差(尽管在时间上与视频保持一致会更容易)。

最终,我选择的策略是,每当说话者停顿时间超过一秒钟时,就把所说的话分开。这是一个看起来像什么的例子:

{
        "en": "Software developers.",
        "start_time": **0.2**,
        "end_time": **1.5**,
    },
    {
        "en": "We're not known for our Rock and style. Are we",
        "start_time": **1.6**,
        "end_time": **4.4**,
    },
    {
        "en": "or are we",
        "start_time": **5**,
        "end_time": **6.2**,
    },

这自然导致了一些尴尬的翻译(即“或者我们”是一个奇怪的翻译片段),但我发现它足够好。这里是代码中的逻辑。

侧栏:我还注意到,对于非英语语言,语音到文本 API 返回的时间戳的准确性明显较低,这进一步降低了非英语到英语配音的质量。

最后一件事。如果您已经知道希望如何翻译某些单词(例如,我的名字“Dale”应该总是简单地翻译为“Dale”),您可以利用高级翻译 API 的“词汇表”功能来提高翻译质量。我在这里写了一篇关于那个的博文

碰巧的是,Google Cloud 正在开发一个新的 API 来处理翻译口语的问题。它被称为媒体翻译 API ,它直接在音频上运行翻译(即没有转录的文本中介)。我不能在这个项目中使用这个 API,因为它还没有返回时间戳(这个工具目前处于测试阶段),但是我认为在未来的迭代中使用它会很棒!

文本到语音转换

现在开始有趣的部分——挑选电脑声音!如果你读过我的 PDF 到有声读物转换器,你就会知道我喜欢听起来滑稽的电脑声音。为了生成配音音频,我使用了谷歌云文本到语音转换 API 。TTS API 可以用不同口音的不同语言生成许多不同的声音,你可以在这里找到并使用来弹奏。“标准”声音可能听起来有点,呃,微小,如果你知道我的意思,但是由高质量神经网络生成的 WaveNet 声音听起来很像人类。

在这里,我遇到了另一个我没有预见到的问题:如果计算机的声音比视频的原始扬声器慢得多,从而导致生成的音频文件太长,该怎么办?那么配音将不可能与源视频对齐。或者,如果译文比原文更加冗长,导致同样的问题,怎么办?

为了解决这个问题,我尝试了文本到语音转换 API 中的参数speakingRate。这允许您加快或减慢电脑声音:

# Instantiates a client
    client = texttospeech.TextToSpeechClient()

    # Set the text input to be synthesized
    synthesis_input = texttospeech.SynthesisInput(text="Hello World")

    voice = texttospeech.VoiceSelectionParams(
        language_code=languageCode, name=voiceName
    )

    # Select the type of audio file you want returned
    audio_config = texttospeech.AudioConfig(
        audio_encoding=texttospeech.AudioEncoding.MP3,
        # Speed up or slow down speaking
        speaking_rate=speakingRate 
    )

    # Perform the text-to-speech request on the text input with the selected
    # voice parameters and audio file type
    response = client.synthesize_speech(
        input=synthesis_input,
        voice=voice,
        audio_config=audio_config
    )

所以,如果电脑说一句话的时间比视频原声说话人说一句话的时间长,我就提高说话速度,直到电脑和人类花的时间差不多。

听起来有点复杂?代码如下所示:

**def** **speakUnderDuration**(text, languageCode, durationSecs, voiceName=None):
    """Speak text within a certain time limit.
    If audio already fits within duratinSecs, no changes will be made.

    Args:
        text (String): Text to be spoken
        languageCode (String): language code, i.e. "en"
        durationSecs (int): Time limit in seconds
        voiceName (String, optional): See https://cloud.google.com/text-to-speech/docs/voices

    Returns:
        bytes : Audio in wav format
    """
    # First, generate audio with speakingRate = 1
    baseAudio = speak(text, languageCode, voiceName=voiceName)

    # Save audio to a temporary file
    f = tempfile.NamedTemporaryFile(mode="w+b")
    f.write(baseAudio)
    f.flush()

    # Get the sample's duration
    baseDuration = AudioSegment.from_mp3(f.name).duration_seconds
    f.close()

    # How fast was the generated audio compared to the original?
    ratio = baseDuration / durationSecs

    # if the audio fits, return it
    **if** ratio <= **1**:
        **return** baseAudio

    # If the base audio is too long to fit in the segment, increase
    # the speaking rate
    ratio = round(ratio, **1**)
    # speakingRate must be <= 4
    **if** ratio > **4**:
        ratio = **4**
    **return** speak(text, languageCode, voiceName=voiceName, speakingRate=ratio)

这解决了音频与视频对齐的问题,但有时这意味着我配音中的电脑扬声器有点笨拙地快。但是这对 V2 来说是个问题。

值得吗?

你知道这句话吗,“玩愚蠢的游戏,赢得愚蠢的奖品?”感觉我在这里建立的每一个 ML 项目都是一种爱的劳动,但这一次,我喜欢我的愚蠢的奖励:能够生成无限数量的怪异,机器人,笨拙的动画配音,有时还有点像样。

点击这里查看我的结果:

遵循dale quark为万物 ML。最初发表于 2021 年 2 月 2 日 https://daleonai.com**

如何将数据转化为可操作的见解

原文:https://towardsdatascience.com/how-to-translate-data-into-actionable-insights-83982eba7675?source=collection_archive---------14-----------------------

使用这个过程来发展一个无价的分析技能

照片由 迈克尔·布隆维斯特 发自 派克斯

在最近的一次数据演示中,我的利益相关者对我说“我不知道如何处理这些信息”。这句话萦绕在我的脑海中,因为我意识到我们不能总是假设我们的利益相关者能够将数据和可操作的见解联系起来。作为数据分析师,我们的工作就是帮助弥补这一缺失环节。今天,我将讨论我用来将数据转化为见解的流程,以及如何在您的工作中应用这一流程。

学习公司的商业模式

我首先回答关于公司业务的三个基本问题。

  1. 公司如何获得潜在客户? —根据商业模式,潜在客户可以是网站的访问者、销售团队的负责人或产品或服务的用户。营销通常负责通过各种数字渠道带来潜在客户,如有机搜索、付费营销、电子邮件等。了解公司如何获得客户非常重要,因为这有助于您了解业务影响,以及当与客户获得相关的 KPI 发生变化时,在哪里进行调查。
  2. 是什么影响了潜在客户的购买行为? —同样,根据业务模式,不同的因素会影响潜在客户的购买可能性。销售服务或产品的公司可以在购买前提供免费试用,或者电子商务公司可以在客户首次购买时提供折扣。关键是要知道影响你的公司的因素,以了解变化将如何影响业务。比如产品公司把他们的免费试用去掉了怎么办?这可能意味着更少的人会购买,因为他们不能免费试用,公司将赚更少的钱。
  3. 公司如何留住客户? —留住客户是保持收入的关键。电子商务公司有忠诚度计划,给顾客购买奖励积分,积分可以兑换成折扣。产品公司发布新功能,并不断改善产品体验,以吸引用户。了解影响客户保留率的因素对于查明与保留率 KPI 相关的问题非常重要。

使用漏斗分析绘制 KPI

在我了解公司的商业模式后,我使用漏斗分析将相关 KPI 映射到客户获取漏斗的每个部分。这有助于我识别 KPI 变化的业务影响。

让我们使用下面的电子商务收购漏斗示例来绘制一些电子商务KPI并讨论 KPI 的变化如何影响业务。

作者创建的电子商务收购漏斗图

  1. 访问者来到网站。 —总访客和营销渠道访客。访客越少,意味着购买量越少,收入越低。
  2. 参观者浏览商品。 —平均产品页面浏览量。产品页面浏览量减少可能意味着营销没有为网站带来合适的访客。
  3. 游客将感兴趣的产品添加到购物车。—添加到购物车的平均商品数。添加到购物车的平均商品数量的增加可以转化为更高的平均订单价值和更高的收入。
  4. 访客开始结账流程。 —弃车率。更低的购物车放弃率意味着更多的购买和更高的收入。
  5. 访客完成购买。 —采购总额、平均订单价值和转换率。更高的转换率意味着更多的访问者购买和更高的收入。

请注意,有些 KPI 跨越了漏斗的多个部分,因为数字本身可能没有意义。例如,购物车放弃率转换率是使用漏斗不同部分的数据计算的重要 KPI。找出贵公司的关键 KPI,并将它们映射到客户获取漏斗的相关区域。

将数据转化为见解

现在,我们将回顾一些假设的 KPI 变化、业务影响,以及它们如何转化为可操作的见解。

  1. 与历史日平均水平相比,日购买量开始下降。—由于购买是客户获取漏斗的最后一个阶段,我们需要观察漏斗的不同部分,以找到下降的原因。购买是由游客推动的。从每日总访问量来看,我们发现网站的访问量没有变化。我们检查了产品页面浏览量和添加到购物车的商品的平均值,没有变化,但我们确实看到购物车放弃率有所增加。在与 product 交谈后,您发现有一个针对结帐流程的 A/B 测试正在运行,并且测试变体的表现比控制差。影响是测试运行时收入暂时减少。可操作的见解是,如果 A/B 测试达到了统计显著性,则关闭该测试;如果没有达到,则与产品部门讨论是否值得继续运行该测试,如果它影响了收入的话。
  2. 与历史平均水平相比,转换率下降。 —转化率通过购买量除以访客来计算。这意味着要么游客增加了,但他们的购买率不如以前,要么购买数量下降了。按渠道细分转化率,我们看到下降来自付费搜索。在与营销人员交谈后,我们发现他们推出了新的付费活动,与现有活动相比,转换率较低。业务影响是降低收入,可操作的见解是现在关闭新的活动,并找出为什么访客转换率比现有活动低。

最后的想法

了解贵公司的商业模式和客户获取渠道是学习如何将数据转化为可操作的见解的关键。我希望学习我的过程有助于你尽快发展这种无价的分析技能。感谢阅读和快乐的数据翻译!

你可能也会喜欢…

https://medium.datadriveninvestor.com/how-data-scientists-can-develop-business-acumen-870eb55866e6

如何对异常 KPI 变化进行故障排除

原文:https://towardsdatascience.com/how-to-troubleshoot-an-abnormal-kpi-change-b9eb0c3d46a1?source=collection_archive---------29-----------------------

调查 DAU 下降的案例研究

来自 Pexels 的 Andrea Piacquadio 的照片

如果你从事数据分析工作,有时你会被要求调查公司 KPI 的异常变化。根本原因可能有很多种,但是如何进行故障诊断可能会占用您一天的大量时间,或者根本没有时间。作为一名数据分析师,我有过许多类似的问题,我想介绍一下我研究问题的步骤和最常见的原因,以帮助您更快地找到答案。

方案

让我们假设一个常见的 KPI,如贵公司仪表盘中的 DAU ,与之前的历史趋势相比,在 3 月 15 日出现了异常下降。

1.数据管道

使用此排除过程来确认 DAU 下降是否是由数据管道问题引起的。

  • 找到生成仪表板使用的数据的 ETL 过程,并确定用于计算 DAU 的数据源。在这种情况下,DAU 由注册帐户的新用户和今天登录该帐户的现有用户组成。
  • 确认 3 月 15 日新增和现有用户数据已成功加载到数据库中。
  • 检查新的和现有的用户原始数据文件的记录计数是否与数据库匹配。如果某个 KPI 有多个数据源,则可能缺少一部分数据。新的用户数据加载可能不完整,这导致了 DAU 的下降。重新运行 ETL 来处理所有新的用户数据将会修复 DAU 下降。
  • 如果原始数据和数据库之间的记录计数匹配,则按小时检查数据,以确认所有 24 小时都在 3 月 15 日完成。如果文件不是按小时划分的,可以找到一个时间戳字段,比如注册时间或登录时间。有时这是问题的根源,发送登录事件的服务在几个小时内失败,并且当天有部分数据。如果没有办法恢复数据,你能做的最好的事情就是通知利益相关者 DAU 下跌不是真的。
  • 如果到目前为止所有检查都是好的,请检查仪表板是否使用了来自数据库的计划提取,并确认提取成功运行。我遇到过提取失败的情况,这导致仪表板上有错误的数据。

2.数据

如果数据管道没有问题,下一步就是检查数据本身。虽然数据可以成功加载到数据库中,但这并不意味着数据值是好的。

  • 校验表字段已填充,并且没有不应该缺少的值。例如,DAU 应该填充用户 ID 和日期。如果 SQL 代码按日期计算用户 ID 和分组,则缺少的值将影响查询结果。
  • 检查表格字段的值是否正确。运行按降序排序的每个字段分组的计数,以检查是否有任何包含大量记录的意外值。我曾经有一个包含错误值的表,该表打乱了用于计算 KPI 的 SQL 逻辑。运行频率检查发现了这个问题。
  • 检查控制面板中的筛选器和计算字段,以确认没有需要包含的新值。我曾经让一个供应商在没有任何通知的情况下添加新的事件值来替换现有的事件值,并且不得不更改仪表板逻辑来获得正确的数字。

3.外部因素

如果不是数据管道或数据问题,第三项检查是寻找任何可能导致 DAU 下降的外部因素。

  • 检查 3 月 15 日是否有用户无法登录或注册账户的技术问题。
  • 向产品经理核实是否有任何 3 月 15 日开始的实验会影响 DAU。我们曾经做过一个实验,导致应用程序在打开时立即崩溃,一旦产品团队意识到这个问题,他们就会恢复控制。崩溃导致 DAU 下降,因为用户几个小时内无法登录。
  • 3 月 15 日,确认将用户导向网站的电子邮件或发送用户进入应用程序的推送通知已成功发出。我曾经看到 DAU 下降时,推送通知提醒打破,用户停止进入应用程序。
  • 3 月 15 日,与工程部门确认网站是否有任何更改或应用程序是否有新版本。可能是网站或应用程序发布导致事件停止发送到后端,工程人员修复了它,但在此期间导致 DAU 数据下降。

对异常 KPI 变化进行故障排除可能是一个耗时的过程。我发现以上三个原因占了我调查的大部分案例。你的公司会有特定的边缘案例,但是现在你知道去哪里找了,我希望你尽快找到答案。

你可能也会喜欢…

数据科学家如何像数据工程师一样解决 ETL 问题

原文:https://towardsdatascience.com/how-to-troubleshoot-etl-issues-like-a-data-engineer-d761f7d361d4?source=collection_archive---------21-----------------------

常见原因及其处理方法

图片来自 Pixabayerikawittleb

如果你是一名数据科学家,在你职业生涯的某个阶段,你必须解决 ETL 问题。如果您是 ETL 故障排除的新手,并且不清楚从哪里开始,这些是我作为数据工程师遇到的问题的常见原因以及如何处理它们。

1.所有的源数据都可用吗?

典型的 ETL 作业要么从原始文件加载源数据,要么从另一个系统将数据提取到临时表中。在下面的 ETL 管道示例中,三个数据文件被转换、加载到一个临时表中,并最终聚合到一个最终表中。ETL 失败的一个常见问题是缺少最近一天运行的数据文件。

如何处理:

如果数据来自外部来源,请与提供商核实并确认文件是否运行延迟。如果数据是内部数据,如应用程序事件或公司网站活动,请与负责团队确认是否存在可能导致数据延迟或丢失的问题。一旦您获得了丢失的数据,您的 ETL 问题就解决了。如果数据被延迟,一旦数据可用,您可能需要手动重新运行 ETL。

作者创建的示例 ETL 管道

2.上游 ETL 依赖项运行完毕了吗?

当数据库表缺少最近一天的数据时,您可能会收到 ETL 问题的警告。如果这是一个聚合表,则在更新该表之前,您很可能需要完成多个作业。

如何处理:

找到负责更新表的 ETL 管道。使用上面显示的示例 ETL 管道,从聚集表向后工作到暂存表,并确认每个步骤都成功完成。如果在第一步中没有验证,请检查最近一天的数据文件是否可用。一旦您确定了失败的阶段,从该点重新运行以确认表在下游被更新。

3.数据文件是否完全加载到数据库中?

有时候,由于我无法理解的原因,数据没有完全加载到数据库中😫。

如何处理:

在这些情况下,将原始文件的记录计数与暂存表进行比较,以验证数据是否不完整。当昨天和今天的数据之间的行数变化超过历史平均百分比时,我通常运行这个检查。从头重新运行 ETL 管道来重新加载原始文件应该可以解决这个问题。

4.数据文件是否包含意外值?

如果 ETL 的重新运行继续失败,就应该检查日志,以验证它是与最初的失败相同的错误消息还是新的错误消息。如果幸运的话,日志文件可能会指出文件中的哪个行号或字段导致了数据库加载错误。

如何处理:

我遇到的最常见的意外值是数值字段中的字符、非 ASCII 字符以及超出表模式中定义的字段长度的字段值。如何处理坏数据取决于您的数据库和可用的工具,但这只是几个选项。

对于非 ASCII 字符,您可以删除原始文件中的坏行,或者使用终端命令将它们从文件中删除,然后重新运行 ETL 作业。

对于超过字段长度的数据,如果您有数据库管理员权限,可以改变表模式来增加字段长度。

对于数值字段中的字符,您可以增加因错误数据而跳过的最大行数,或者创建一个新的临时表,使用字符而不是数值字段在加载前清除或过滤错误数据。

5.数据文件不完整吗?

检查数据文件的行数是否与过去的文件相似。如果低于预期,当天的数据可能不完整。这可能是由于事件停止发送到后端或计划的系统维护造成的。

如何处理:

请与数据提供商联系,确认数据是否确实丢失,或者是否需要发送包含所有数据的新文件。如果需要发送新文件,请在数据更新后重新运行 ETL。

6.数据文件包含预期的格式吗?

数据格式可能会发生意外变化,尤其是外部数据。将 ETL 代码期望的分隔符和字段顺序与最新的文件格式进行比较。

如何处理:

如果格式已更改,请向数据提供商确认。如果没有,等待更新的文件并重新运行现有的 ETL。如果是,请自己修改生产代码或创建一个数据工程票证来处理新的格式更改。

7.有重复的吗?

这种情况并不经常发生,但是重复数据可能会进入您的数据中,并引起很大的麻烦。

如何处理:

使用上面的同一个 ETL 管道示例,向后工作,检查聚合表、临时表和数据文件中的重复项。删除重复项,并从该点重新运行 ETL。

最后的想法

当我第一次成为数据工程师时,我不知道如何解决 ETL 问题。经过反复试验,我想出了一个常见原因的清单,以便在进入更不寻常的原因之前进行检查。这个列表解释了我过去的大部分问题,现在你知道该找什么了,我希望你的许多问题也能得到解决。

你可能也会喜欢…

</6-best-practices-i-learned-as-a-data-engineer-9d3ad512f5aa> </6-bad-data-engineering-practices-you-shouldnt-apply-as-a-data-scientist-58de5eca14c3> https://medium.com/swlh/how-i-used-a-machine-learning-model-to-generate-actionable-insights-3aa1dfe2ddfd

如何解决 Python 中的内存问题

原文:https://towardsdatascience.com/how-to-troubleshoot-memory-problems-in-python-93ea0f62296d?source=collection_archive---------27-----------------------

行业笔记

一个在生产环境中使用开源工具修复泄漏程序的真实例子。

致谢:哈里森·布罗德本特Unsplash

发现应用程序内存不足是开发人员可能遇到的最糟糕的情况之一。一般来说,内存问题很难诊断和修复,但我认为在 Python 中更难。Python 的自动垃圾收集功能使得使用这种语言变得很容易,但是它太擅长于置身事外了,以至于当它不像预期的那样工作时,开发人员会不知如何识别和修复问题。

在这篇文章中,我将展示我们如何诊断和修复由 Alteryx 创新实验室开发的开源 AutoML 库 EvalML 中的内存问题。没有解决内存问题的神奇秘方,但是我希望开发人员,尤其是 Python 开发人员,能够了解在将来遇到这类问题时可以利用的工具和最佳实践。

读完这篇博文后,你应该会有如下收获:

  1. 为什么发现并修复程序中的内存问题很重要,
  2. 什么是循环引用,为什么它们会导致 Python 中的内存泄漏,以及
  3. Python 内存分析工具的知识,以及您可以用来识别内存问题原因的一些步骤。

设置舞台

在发布新版本的包之前,EvalML 团队运行了一套性能测试,以捕捉任何性能退化。这些性能测试包括在各种数据集上运行我们的 AutoML 算法,测量我们的算法获得的分数以及运行时间,并将这些指标与我们之前发布的版本进行比较。

一天,我正在运行测试,突然应用程序崩溃了。发生了什么事?

步骤 0 —什么是内存,什么是泄漏?

任何编程语言最重要的功能之一是它在计算机内存中存储信息的能力。每次你的程序创建一个新的变量,它会分配一些内存来存储变量的内容。

内核为程序定义了一个接口来访问计算机的 CPU、内存、磁盘存储等等。每种编程语言都提供了要求内核分配和释放内存块的方法,以供正在运行的程序使用。

当一个程序要求内核留出一块内存来使用时,就会发生内存泄漏,但由于一个错误或崩溃,程序永远不会告诉内核它何时用完了那块内存。在这种情况下,内核将继续认为正在运行的程序仍在使用被遗忘的内存块,其他程序将无法访问这些内存块。

如果在运行程序时重复出现相同的泄漏,被遗忘内存的总大小会变得很大,以至于它会消耗计算机内存的很大一部分!在这种情况下,如果一个程序试图请求更多的内存,内核将引发“内存不足”错误,程序将停止运行,或者换句话说,“崩溃”

因此,在您编写的程序中找到并修复内存泄漏是非常重要的,因为如果您不这样做,您的程序最终可能会耗尽内存并崩溃,或者会导致其他程序崩溃。

步骤 1:确定是内存问题

应用程序崩溃的原因有很多——可能是运行代码的服务器崩溃了,也可能是代码本身有逻辑错误——所以确定眼前的问题是内存问题非常重要。

EvalML 性能测试以一种异常安静的方式崩溃了。突然,服务器停止记录进度,作业悄悄地完成了。服务器日志会显示由编码错误引起的任何堆栈跟踪,所以我有预感这个无声的崩溃是由使用所有可用内存的作业引起的。

我再次运行了性能测试,但是这次启用了 Python 的内存分析器来获得一段时间内的内存使用情况。测试再次崩溃,当我查看内存图时,我看到了这个:

EvalML 性能测试的内存配置文件。作者创建的图像。

随着时间的推移,我们的内存使用量保持稳定,但后来达到了 8gb!我知道我们的应用服务器有 8g 的 RAM,所以这个配置文件证实了我们的内存不足。此外,当内存稳定时,我们使用大约 4 GB 的内存,但我们以前版本的 EvalML 使用大约 2 GB 的内存。因此,出于某种原因,当前版本使用的内存是正常情况下的两倍。

现在我需要找出原因。

第二步:用一个最小的例子在本地重现内存问题

查明内存问题的原因需要大量的实验和反复,因为答案通常不是显而易见的。如果是,你可能就不会把它写进代码了!出于这个原因,我认为用尽可能少的代码行重现问题是很重要的。这个最小的例子使您可以在修改代码时,在一个分析器下快速运行它,以查看您是否取得了进展。

在我的例子中,我从经验中得知,我们的应用程序在我看到峰值的时候运行了一个有 150 万行的出租车数据集。我把我们的应用程序精简到只有运行这个数据集的部分。我看到了一个类似于我上面描述的尖峰,但这一次,内存使用量达到了 10gb!

看到这个之后,我知道有一个足够好的最小的例子来深入研究。

出租车数据集中本地再现器的内存占用。作者创建的图像。

第三步:找到分配最多内存的代码行

一旦我们将问题隔离到尽可能小的代码块中,我们就可以看到程序在哪里分配了最多的内存。这可能是你需要重构代码和修复问题的确凿证据。

我认为 filprofiler 是一个很好的 Python 工具。它显示应用程序中每行代码在内存使用峰值点的内存分配。这是我的本地示例的输出:

fil-profile 输出。作者创建的图像。

filprofiler 根据内存分配对应用程序中的代码行(以及依赖项的代码)进行排序。线越长越红,分配的内存就越多。

分配最多内存的行正在创建 pandas 数据帧(pandas/core/algorithms.py 和 pandas/core/internal/managers . py ),数据量达到 4gb!我在这里截断了 filprofiler 的输出,但是它能够在创建 pandas 数据帧的 EvalML 中跟踪 pandas 代码。

看到这个有点令人费解。是的,EvalML 创建了 pandas 数据帧,但是这些数据帧在整个 AutoML 算法中是短暂的,一旦不再使用就应该被释放。因为事实并非如此,而且这些数据帧仍然在内存中存在足够长的时间,所以我认为最新版本引入了内存泄漏

步骤 4:识别泄漏物体

在 Python 的上下文中,泄漏对象是指在使用完之后不会被 Python 的垃圾收集器释放的对象。由于 Python 使用引用计数作为其主要的垃圾收集算法之一,这些泄漏的对象通常是由于对象持有对它们的引用的时间超过了它们应该持有的时间。

这些类型的对象很难找到,但是有一些 Python 工具可以让搜索变得容易处理。第一个工具是 gc。垃圾收集器的 DEBUG_SAVEALL 标志。通过设置这个标志,垃圾收集器将在 gc.garbage 列表中存储不可到达的对象。这将让您进一步研究这些对象。

第二个工具是 objgraph 库。一旦对象出现在 gc.garbage 列表中,我们就可以将这个列表过滤为 pandas 数据帧,并使用 objgraph 查看还有哪些对象正在引用这些数据帧并将它们保存在内存中。通过阅读这篇奥赖利的博客文章,我得到了这个方法的灵感。

这是我在可视化其中一个数据帧时看到的对象图的子集:

pandas 数据帧使用的内存图,显示了导致内存泄漏的循环引用。作者创建的图像。

这就是我一直在寻找的确凿证据!dataframe 通过一个叫 PandasTableAccessor 的东西对自己进行引用,这就创建了一个循环引用,所以这将把对象保存在内存中,直到 Python 的垃圾收集器运行并能够释放它。(可以通过 dict、PandasTableAccessor、dict、_dataframe 来追踪循环。)这对 EvalML 来说是个问题,因为垃圾收集器将这些数据帧保存在内存中的时间太长了,以至于我们耗尽了内存!

我能够追踪 PandasTableAccessor 到木工库,并把这个问题提交给维护人员。他们能够在新版本中修复它,并向 pandas 知识库提交相关的问题——这是开源生态系统中可能的合作的一个很好的例子。

木工更新发布后,我可视化了同一个数据帧的对象图,循环消失了!

木制品升级后的熊猫数据框对象图。不再有周期!作者创建的图像。

步骤 5 —验证修复是否有效

当我在 EvalML 中升级了木制品版本后,我测量了我们的应用程序的内存占用,我很高兴地报告说,现在的内存使用不到以前的一半!

修复后性能测试的记忆。作者创建的图像。

结束语

正如我在本文开头所说的,没有解决内存问题的神奇方法,但是这个案例研究提供了一个通用的框架和一套工具,如果您将来遇到这种情况,您可以利用这些工具。我发现 memory-profiler 和 filprofiler 是调试 Python 中内存泄漏的有用工具。

我还想强调的是,Python 中的循环引用会增加应用程序的内存占用。垃圾收集器最终会释放内存,但是,正如我们在本例中所看到的,也许直到为时已晚!

在 Python 中,循环引用非常容易被无意引入。我能够在 EvalML 中找到一个无意的一个scikit-optimizescipy 。我鼓励你擦亮你的眼睛,如果你在野外看到一个循环引用,开始一个对话,看看它是否真的需要!

原贴于 Alteryx 创新实验室 博客

如何尝试 CLIP: OpenAI 的零拍图像分类器

原文:https://towardsdatascience.com/how-to-try-clip-openais-zero-shot-image-classifier-439d75a34d6b?source=collection_archive---------29-----------------------

本周早些时候,OpenAI 向计算机视觉世界投下了一颗炸弹——你现在可以在不需要培训的情况下进行图像分类。

(引用)

本周早些时候,OpenAI 向计算机视觉世界投下了一颗炸弹:两个新的突破性模型暗示了大规模 GPT3 式变形金刚模型侵占视觉领域的未来。虽然 DALL-E (一种可以从文本提示中生成图像的模型)在本周获得了很多关注,但这篇文章主要关注的是剪辑:一种可以说更加重要的零镜头分类器。

到目前为止,对图像进行分类涉及收集数百、数千甚至数百万张标记图像的自定义数据集,这些图像适当地代表了您的目标类别,并使用它来训练监督分类模型(通常是卷积神经网络)。这种方法(以及像物体检测这样的扩展)导致了计算机视觉在过去十年中的快速发展(为从无人驾驶汽车增强现实的一切提供动力)。

监督训练的缺点是,结果模型不能很好地概括。如果你给他们看一张不同领域的图片,他们通常不会比随机猜测做得更好。这意味着您需要收集各种各样的数据,这些数据足以代表您的模型将在野外执行的确切任务。

输入 OpenAI 剪辑

最近推出的剪辑(对比语言-图像预训练)打破了这一范式。这是一个零射击模型,这意味着它可以识别前所未见的大量事物。

剪辑就像最好的 AI 字幕写手。它能够从 32,768 个样本字幕中说出图像中的内容。图片来源: OpenAI

在传统的分类器中,标签的意义被忽略了(事实上,它们经常被简单地丢弃,并在内部用整数替换)。相比之下,CLIP 创建其类的编码,并在超过 4 亿个文本到图像对上进行预训练。这使得它能够利用 transformer 模型从文本中提取语义的能力,在不根据自定义数据进行微调的情况下,对图像进行开箱即用的分类。

你所需要做的就是定义一个可能的类别列表,或者描述,CLIP 会根据它的先验知识来预测一个给定的图像最有可能属于哪个类别。把它想象成问模型“这些标题中哪一个最匹配这张图片?”

在本帖中,我们将演示如何在您自己的图像上测试 CLIP 的性能,这样您就可以获得一些硬数字,并直观地了解 CLIP 在各种用例中的实际表现。我们发现 CLIP 在一个 花分类 任务上比 我们定制训练的 ResNet 分类模型 它在一系列更模糊和更具挑战性的任务中也表现得令人惊讶(包括从我们的相机胶卷中识别蘑菇品种,以及识别狗和猫的品种)。

本教程中的资源:

公共花卉分类数据集

组装数据集

要试用 CLIP,您需要带一组您想要分类的图像,并将其划分到您想要查看的类别中。

如果你还没有数据集,想尝试一下新技术,看看 Roboflow 的公共计算机视觉数据集

在本帖中,我们将对公开的花卉分类数据集进行基准测试。如果使用你自己的数据,将你的数据上传到 Roboflow 很容易,而且是免费的(最多 1000 张图片),然后你可以在这个博客中遵循同样的流程。

一旦你组装好你的数据集,它就会被放到 CLIP benchmarking Colab 笔记本上。

本文中使用的示例花卉分类数据集

安装剪辑依赖关系

要尝试裁剪自己的数据,请在驱动器中复制一份笔记本,并确保在运行时下选择了 GPU(Google Colab 会给你一个免费的 GPU 供你使用)。然后,我们在克隆 CLIP Repo 的同时进行一些安装。

将数据集下载到 Colab

下一步是将分类数据集下载到 Colab 中。

下载分类数据到本帖笔记本

如果你在 Roboflow 中创建了一个数据集,这可以通过点击Generate,然后点击OpenAI CLIP Classification格式的Download来实现。这将把所有的测试图像放在一个名为test的文件夹中,并为数据集中的每个类提供单独的图像子目录,并为您提供一个_tokenization.txt文件,让您尝试“快速工程”,这可以极大地提高或降低模型的性能。

我们还为对象检测数据集创建了一个转换器,它将从现有的边界框创建文本描述。我们得到了不同的结果,但是玩起来肯定很有趣。

此外,我们已经将所有的开源数据集以剪辑格式免费下载。

用剪辑推断类别标签

最后一步是通过预测步骤传递您的测试图像。

CLIP 接受一个图像和一个可能的类标题列表作为输入。您可以在_tokenization.txt文件中定义您认为合适的类别标题。请确保它们与按字母顺序排序的class_names(由文件夹结构定义)保持相同的顺序。

notebook包含迭代测试集中每个类文件夹的代码,并通过预测步骤传递相关图像。

实验本体和结果

当您使用 CLIP 执行分类任务时,为您的分类本体尝试不同的类标题是很有用的,请记住,CLIP 被训练来区分图像标题。

在 flowers 数据集上,我们尝试了以下本体并看到了这些结果:

  • "daisy" vs "dandelion"] - > 46%的准确率(比猜测差)
  • "daisy flower" vs "dandelion flower" - > 64%的准确率
  • "picture of a daisy flower" vs "picture of a dandelion flower" - >准确率 97%

97%的准确率高于我们在这个数据集上训练的任何 其他分类模型

这些结果显示了提供正确的类描述来剪辑和表达预处理过程的丰富性的重要性,这是在传统的二进制分类中完全丢失的特征。OpenAI 将这一过程称为“提示工程”。

翻转脚本

CLIP 可能有许多额外的用例,包括根据目标查询字符串对图像进行排序,或者根据图像的独特性对图像进行排序。

在笔记本中,你会看到定义两个变量image_featurestext_features的代码。任何一对特征之间的余弦相似性代表了它们的语义距离——从我们目前的经验来看,这是非常准确的。这只是早期...

结论

如果您发现 CLIP 的性能没有您希望的那么高,您可能仍然希望考虑在监督下训练一个自定义图像分类模型

关于剪辑研究的更多信息,可以考虑阅读论文和查看 OpenAI 的博客文章。如果你在玩模型的时候发现了什么有趣的东西,我们很乐意听到!请务必在推特上给我们留言。

一如既往,推理快乐!

雅各布·索拉维茨

原载于 2021 年 1 月 8 日 https://blog.roboflow.com**的

如何调整机器学习的超参数

原文:https://towardsdatascience.com/how-to-tune-hyperparameters-for-machine-learning-aa23c25a662f?source=collection_archive---------30-----------------------

调整超参数是机器学习过程中的关键部分。继续读下去,学习一些有效而直观的方法。

尼克·希利尔在 Unsplash 上的照片

在机器学习算法中,有两种参数——模型参数和超参数。通过训练过程学习模型参数,例如神经网络的权重。超参数用于控制训练过程;因此,必须在训练开始前进行设置。深度学习中超参数的一些例子是学习速率和批量大小。许多机器学习实践者忽略的一个问题就是如何设置这些超参数。未能进行良好的超参数调整可能会抵消您构建模型的所有努力。幸运的是,有一种通用的启发式方法来挑选超参数。对于更复杂的情况,也有自动超参数选择方法。在本文中,我们将讨论这两个问题。

挑选超参数的一般方法

考虑超参数选择的一个好方法是在模型容量的背景下考虑。从广义上讲,我们所说的模型容量指的是我们的模型能够表现的功能的数量。理想情况下,我们希望选择超参数,以便我们的模型的容量正好适合手头的问题。换句话说,我们想要避免欠拟合或过拟合的超参数。从视觉上很容易看出这一点。如果您要绘制一个图,y 轴为测试误差,x 轴为一个超参数值,大多数情况下您会得到如下结果:

作者图片

太小或太大的超参数对应于太大或太小的模型容量,导致高测试误差。因此,为了最佳地设置超参数,我们需要推理该超参数的特定值对模型容量有什么影响。

让我们看一个这种推理的例子。一个常见的超参数是神经网络中的节点数。节点数量和模型容量之间的关系非常明显——更多的节点意味着更多的模型容量,反之亦然。如果我们怀疑我们的模型过度拟合,例如,如果我们注意到一个非常低的训练误差,但一个相当大的测试误差,我们知道模型容量可能太大了。因此,我们需要减少神经网络中的节点数量。如果我们看到拟合不足(可能是如果训练集和测试集都有很高的错误),我们知道模型容量太小,我们应该增加节点的数量。

现在让我们考虑另一个常见的超参数——重量衰减系数。权重衰减是神经网络的一种正则化形式,顾名思义,它使权重变小。权重衰减系数的影响也非常明显——衰减系数越高,权重越小,模型容量也就越小。因此,如果我们怀疑过度拟合,我们应该增加衰减系数,如果我们怀疑不足拟合,我们应该减少它。

然而,在某些情况下,超参数如何影响模型容量尚不清楚。深度学习中的学习率就是这样一个例子。在这些情况下,我们可以使用自动超参数调整方法。

两种自动方法:网格搜索和随机搜索

这些自动方法背后的基本原理很简单。让我们从一个简单的例子开始,我们的模型只有一个超参数。让我们假设我们知道这个参数的合理值在 0 和 1 之间(例如,强化学习问题中的ε)。我们想尝试一些值,看看哪个是最好的。最明显的做法是尝试类似[0,0.2,0.4,0.6,0.8,1]或[0,0.33,0.66,1]的东西。这种以均匀间隔尝试数值的想法被称为网格搜索。如果我们有多个超参数,我们会尝试每个均匀分布的单个参数的组合。例如,我们可能有两个参数,并想尝试每个参数的值[0,1,2]。那么我们的网格搜索将需要尝试(0,0)、(0,1)、(0,2)、(1,0)、(1,1)、(1,2)、(2,0)、(2,1)、(2,2)。网格搜索也可以在对数而不是线性标度上运行,例如[0,10(-3),10(-2),10^(-1),1]。

网格搜索的一个问题是,我们需要尝试的组合数量是超参数数量的指数级。因此,如果我们有多个超参数,网格搜索将需要很长时间来运行。也有可能不是所有的超参数都会影响模型。如果是这样的话,那么网格搜索不仅要花很长时间,而且还要浪费大量时间去寻找不影响性能的超参数的变化。

随机搜索解决了这两个问题。随机搜索分两步进行。首先,我们为每个超参数定义一个边际分布。然后,我们从组合分布中抽取随机值,并选择最佳值。随机搜索避免了指数运行时间问题——它凭借其随机性探索相同的空间。它还避免了时间浪费问题——由于其随机性,随机搜索不会在特定超参数的相同值上花费时间(这可能根本不会影响模型)。

从经验上看,这些改进似乎使 随机搜索比 网格搜索更有优势。因此,如果你想用一种自动的方法来选择你的超参数,我建议用随机搜索代替网格搜索。

我希望这篇文章让您对如何调优超参数有了更多的了解。许多超参数可以通过思考超参数如何影响模型容量来进行调整。对模型容量(例如学习率)有复杂影响的超参数,或者超参数的大量组合,可以用上述自动方法进行调整。对于这些情况,我的建议是随机搜索。

请随时留下任何问题/评论。感谢阅读!

如何调整机器学习模型的超参数

原文:https://towardsdatascience.com/how-to-tune-hyperparameters-of-machine-learning-models-a82589d48fc8?source=collection_archive---------17-----------------------

使用来自 envato 元素BoykoPictures 的图像创建(经许可)。

数据科学 | 机器学习

使用 Scikit-learn 的分步教程

通常情况下,您会使用默认参数来构建机器学习模型。只需几段代码,您就可以为您的机器学习模型搜索最佳超参数。为什么?因为最佳的超参数集可以大大提高模型的性能。

在本文中,您将学习如何使用 scikit-learn 库在 Python 中执行随机森林模型的超参数调优。

注: 本文灵感来源于我前段时间做的一个 YouTube 视频(Python 中机器学习模型的超参数调优 )。

1.超参数

在应用机器学习中,调整机器学习模型的超参数代表了尽可能实现最佳性能的有利可图的机会。

1.1.参数与超参数

现在让我们定义什么是超参数,但在此之前,让我们考虑一下参数超参数之间的区别。

参数可以被认为是模型固有的或内部的,并且可以在模型从数据中学习之后获得。参数的例子是线性回归中的回归系数、支持向量机中的支持向量和神经网络中的权重。

超参数可以被认为是模型的外在或外部参数,可以由从业者任意设置。超参数的例子包括 k-最近邻中的 k、随机森林中的树的数量和特征的最大数量、神经网络中的学习速率和动量、支持向量机中的 C 和 gamma 参数。

1.2.超参数调谐

由于没有通用的最佳超参数可用于任何给定的问题,超参数通常被设置为默认值。然而,超参数的最佳集合可以从手动经验(试错法)超参数搜索中获得,或者通过使用优化算法来最大化适应度函数以自动方式获得。

两种常见的超参数调谐方法包括网格搜索随机搜索。顾名思义, 网格搜索 需要创建可能的超参数值的网格,从而以强力方式为所有这些超参数组合迭代构建模型。在 随机搜索 中,不是所有的超参数组合都被使用,而是每次迭代使用一个随机超参数组合。

比较两种常用超参数调整方法的示意图:(1)网格搜索与(2)随机搜索。作者绘制的图像。

此外,随机优化方法也可用于超参数调整,其将以算法方式自动导航超参数空间,作为损失函数(即性能度量)的函数,以便监控模型性能。

在本教程中,我们将使用网格搜索方法。

2.资料组

今天,我们既不使用虹膜数据集,也不使用企鹅数据集,而是要生成我们自己的合成数据集。但是,如果您想继续使用您自己的数据集进行替换,那就太好了!

2.1.生成合成数据集

2.2.检查数据集维度

现在让我们检查数据集的维度

这将给出以下输出:

((200, 10), (200,))

其中(200, 10)是 X 变量的维度,这里我们可以看到有 200 行和 10 列。至于(200,),这是 Y 变量的维度,表示有 200 行和 1 列(没有显示数值)。

3.数据分割

3.1.检验训练集的维数

现在让我们检查一下训练集(80%子集)的维度。

这将给出以下输出:

((160, 10), (160,))

其中(160, 10)是 X 变量的维数,这里我们可以看到有 160 行和 10 列。至于(160,),这是 Y 变量的维度,表示有 200 行 1 列(没有显示数值)。

3.2.检验训练集的维数

现在让我们检查一下测试集的维度(20%子集)。

这将给出以下输出:

((40, 10), (40,))

其中(40, 10)是 X 变量的维数,这里我们可以看到有 40 行 10 列。至于(40,),这是 Y 变量的维度,表示有 40 行 1 列(没有显示数值)。

4.构建基线随机森林模型

这里,我们将首先构建一个基线随机森林模型,该模型将用作基线,以便与使用最佳超参数集的模型进行比较。

对于基线模型,我们将为 2 个超参数(例如n_estimatorsmax_features)设置一个任意数字,我们也将在下一节中使用该数字进行超参数调整。

4.1.实例化随机森林模型

我们首先导入必要的库,并将随机森林分类器分配给 rf 变量。

4.2.训练随机森林模型

现在,我们将应用随机森林分类器,使用训练数据上的rf.fit()函数(例如X_trainY_train)来构建分类模型。

模型定型后,会出现以下输出:

之后,我们可以应用训练好的模型(rf)进行预测。在上面的示例代码中,我们应用模型来预测训练集(X_test),并将预测的 Y 值赋给Y_pred变量。

4.3.评估模型性能

现在让我们来评估模型性能。这里,我们计算 3 个性能指标,包括准确性、马修斯相关系数(MCC)和受试者工作特征曲线下面积(ROC AUC)。

5.超参数调谐

现在,我们将对随机森林模型的超参数进行调整。我们将调整的两个超参数包括max_featuresn_estimators

5.1.代码

应该注意的是,下面显示的一些代码改编自 scikit-learn

5.2.代码解释

首先,我们将导入必要的库。

scikit-learn 的GridSearchCV()功能将用于执行超参数调谐。特别需要注意的是,GridSearchCV()功能可以执行分类器的典型功能,如fitscorepredict以及predict_probadecision_functiontransforminverse_transform

其次,我们定义了作为GridSearchCV()函数必要输入的变量,这包括 2 个超参数(max_features_rangen_estimators_range)的范围值,然后将其作为字典分配给param_grid变量。

最后,打印出最佳参数(grid.best_params_)及其对应的度量(grid.best_score_)。

5.3.性能指标

GridSearchCV()的默认性能指标是准确性,在本例中,我们将使用 ROC AUC。

为了以防万一,您想知道可以使用哪些其他性能指标,运行以下命令来找出答案:

这将打印以下受支持的性能指标:

因此,在本例中,我们将使用 ROC AUC,并在GridSearchCV()函数中设置输入参数scoring = 'roc_auc'

5.4.超参数调整的结果

第 5.1 节代码的第 14–15 行打印了性能指标,如下所示:

其表明最优或最佳超参数集具有 3 的max_features和 60 的n_estimators,ROC AUC 分数为 0.93。

6.调谐超参数的数据可视化

让我们首先来看看底层数据,稍后我们将使用它进行数据可视化。超参数调整的结果已被写出到grid.cv_results_,其内容显示为如下所示的字典数据类型。

***grid.cv_results_***.内容截图

6.1.准备数据帧

现在,我们将有选择地从grid.cv_results_中提取一些数据,以创建一个包含 2 个超参数组合及其相应性能指标的数据框架,在本例中是 ROC AUC。特别地,下面的代码块允许组合 2 个超参数(params)和性能度量(mean_test_score)。

输出为以下数据帧,其中 3 列由max_featuresn_estimatorsROC_AUC组成。

包含超参数组合及其相应性能度量值的串联数据帧的输出屏幕截图。

6.2.重塑数据框架

6 . 2 . 1分组列

为了将上述数据框可视化为等高线图(即 2D 或 3D 版本),我们首先需要重塑数据结构。

在上面的代码中,我们使用来自pandas库的groupby()函数根据两列(max_featuresn_estimators)对数据帧进行分组,从而合并第一列(max_features)的内容。

6 . 2 . 2。旋转数据

通过将数据旋转到 m ⨯ n 矩阵中,数据被重新整形,其中行和列分别对应于max_featuresn_estimators

上面的代码块产生了下面的整形数据帧。

已准备好绘制等值线图的整形数据框的屏幕截图。

最后,我们将整形后的数据分配给各自的xyz变量,这些变量将用于绘制等高线图。

6.3.制作 2D 等高线图

现在,有趣的部分来了,我们将通过使用 Plotly 绘制 2D 等高线图,可视化我们正在调整的 2 个超参数的景观及其对 ROC AUC 分数的影响。前述xyz变量用作输入数据。

上述代码块生成以下 2D 等高线图。

6.4.制作 3D 等高线图

这里,我们将使用 Plotly 创建一个交互式 3D 等高线图,使用xyz变量作为输入数据。

上述代码块生成以下 3D 等高线图。

2 个超参数相对于性能指标 ROC AUC 的 3D 等高线图的屏幕截图。

结论

恭喜你!您刚刚执行了超参数调优,并创建了数据可视化。希望您能够提高您的模型性能,与默认值相比。

下一步是什么?在本教程中,您已经研究了两个超参数的调优,但这还不是全部。对于随机森林模型,您还可以调整其他几个超参数。您可以查看来自scikit-learn的 API,获得一个可以尝试的超参数列表。

https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html

或者,您可以使用本文中描述的代码作为起始模板,尝试为其他机器学习算法调整超参数。

在评论里让我知道,你在做什么好玩的项目!

订阅我的邮件列表,获取我在数据科学方面的最佳更新(偶尔还有免费赠品)!

关于我

我是泰国一所研究型大学的生物信息学副教授和数据挖掘和生物医学信息学负责人。在我下班后的时间里,我是一名 YouTuber(又名数据教授)制作关于数据科学的在线视频。在我制作的所有教程视频中,我也在 GitHub 上分享 Jupyter 笔记本(数据教授 GitHub page )。

https://www.youtube.com/dataprofessor

在社交网络上与我联系

✅YouTube:http://youtube.com/dataprofessor/
♇网站:http://dataprofessor.org/(在建)
♇LinkedIn:https://www.linkedin.com/company/dataprofessor/
♇Twitter:https://twitter.com/thedataprof/
♇Facebook:http://facebook.com/dataprofessor/
♇github:https://github.com/dataprofessor/
♇Instagram:)

如何用 GridSearchCV 一次调优多个 ML 模型?

原文:https://towardsdatascience.com/how-to-tune-multiple-ml-models-with-gridsearchcv-at-once-9fcebfcc6c23?source=collection_archive---------4-----------------------

加快您的型号选择工作流程

图片由 LTD EHU 发自 Pixabay

模型选择是数据科学模型开发流程的重要组成部分。在执行特征工程之后,数据科学家需要选择具有最佳超参数集的模型,该模型对于训练数据集表现最佳。有各种自动化模型选择组件的 Auto-ML 库。

网格搜索是一种交叉验证技术,可用于调整机器学习模型的超参数。为了从 ML 模型列表中选择稳健模型,需要对每个模型进行多次交叉验证。在本文中,我们将讨论使用网格搜索和随机搜索交叉验证同时调优多个模型的技巧。

什么是网格搜索和随机搜索交叉验证?

GridSearchCV 或 RandomizedSearchCV 是交叉验证技术,用于执行超参数调整,以确定机器学习模型的最佳值。理想情况下,GridSearchCV 会尝试所有可能的参数值,而 RandomizedSearchCV 会随机选取参数并加速交叉验证工作流。

(作者代码),GridSearchCV 实现

上述代码片段可用于为随机森林分类器模型选择最佳超参数集。

理想情况下,GridSearchCV 或 RandomizedSearchCV 需要为多个机器学习模型运行多个管道,以挑选具有最佳超参数值集的最佳模型。数据科学家可能会花很多时间来开发代码并研究它。

通过创建多个参数字典并为每个字典指定模型,可以使用 GridSearchCV 或 RandomizedSearchCV 同时调整多个机器学习模型。一次调优多个模型的逐步方法是:

  1. 初始化多分类器估计器
  2. 准备第一个分类器的管道。
  3. 准备每个估计量的超参数字典,每个估计量都有一个作为“分类器”的关键字和作为估计量对象的值。超参数键应该以分类器的单词开始,用“__”分隔(双下划线)。
  4. 列出超参数字典。
  5. 使用管道和参数字典列表训练 GridSearchCV 模型。

实施:

(作者代码)

我使用了一个包含大约 5000 个实例和 29 个独立特征的样本二元分类数据集。为了训练一个健壮的机器学习模型,我已经初始化了 7 个机器学习估计器,包括:

  • 随机森林
  • 支持向量分类器
  • 逻辑回归
  • 决策图表
  • k-最近邻
  • 朴素贝叶斯
  • 梯度推进

并进一步用变量名**param_i**准备了它们对应的超参数字典。

Scikit-learn 包附带了 GridSearchCV 实现。我已经将带有管道和参数字典列表的第一个估计器传递给 GridSearchCV 模型。

GridSearchCV 需要 120 秒来训练 7 个估计器的 176 个模型。具有**C=10****class_weight=None**的支持向量分类器表现最好,交叉验证 ROC AUC 得分为 0.984,测试 ROC AUC 得分为 0.979。

RandomizedSearchCV 模型需要 9 秒来训练同一组模型。相同的支持向量分类器产生执行最好的结果。

结论:

在本文中,我们讨论了 GridSearchCV 和 RandomizedSearchCV 如何用于同时调优多个机器学习模型。这是一种非常方便的技术,可以加快模型选择工作流程。

参考资料:

[1] Scikit-learn 文档:https://sci kit-learn . org/stable/modules/generated/sk learn . model _ selection。GridSearchCV.html

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一小部分会员费,不需要你额外付费。

https://satyam-kumar.medium.com/membership

感谢您的阅读

如何把茱莉亚变成 Python!

原文:https://towardsdatascience.com/how-to-turn-julia-into-python-6ab13dafb84?source=collection_archive---------33-----------------------

如何在 Julia 编程语言中使用面向对象编程范式?

介绍

Julia 是一门相当新的编程语言,科学界的大多数人可能都很熟悉,或者想要熟悉它。Julia 编程语言有许多优点,这使它成为一门非常好的语言。虽然 Julia 传统上被认为是一种更函数式的编程语言,但使用一些 Julia 的酷技巧——如外部构造函数和令人难以置信的动态类型语法,我们实际上可以使编程语言非常快速和非常有效地成为面向对象的语言!

为什么要让 Julia 成为面向对象的编程语言?鉴于面向对象编程语言的流行,很容易理解为什么程序员可能最终想要使用支持这种范式的语言。子类型输入是很棒的,而且课程让很多事情变得轻而易举。虽然我们可能需要改变 Julia 中的一些东西,因为我们只是简单地使用内部和外部构造函数,并将我们的方法类型传递到一个结构中,但高级语法最终将保持不变。这意味着除了使用 Julia 之外,您还可以使用这种方法用这种语言重新创建您喜欢的 Python 包!

构造器

当然,为了让内部和外部构造函数更有意义,我们还需要看看我们通常认为的 Julia 语言中的构造函数。这当然是一种被构造成包含其他数据类型的类型。您可以将任何构造的类型视为保存数据类型的容器。在 Julia 中,我们为此使用 struct:

struct exampleend

正如人们可能想象的那样,数据被定义为带有回车的变量名:

struct example
    x
    y
end

我们刚刚创建的是一个外部构造函数。这是一种很好的方法,可以使构造的类型只需要保存将来可能通过方法传递的数据。然而,通常当我们想要一个类型返回时,我们不希望该类型只包含我们提供的数据,而是为我们获取它。考虑下面的例子,它是一个正态分布:

struct NormalDistribution
    mu
    sigmaend

当然,最终用户总是可以在其他地方计算他们的均值和标准差,然后输入:

using Lathe.stats: mean, stdstruct NormalDistribution
    mu
    sigmaendnorm = NormalDistribution(mean(x), std(x))

但是我们也可以通过简单地添加一个内部构造函数来更好地完成这项工作。为了添加内部构造函数,我们需要在这个结构中定义一个新函数。我们将使用 new()方法从这个内部构造函数返回新构造的类型。我们的构造函数将获取一个数组并从中返回一个正态分布:

struct NormalDistribution
    mu::Float64
    sigma::Float64
    function NormalDistribution(x::Array)
        return new(mean(x), std(x))
    endend

现在,如果我们调用我们的正态分布,并为它提供一个位置参数,这个位置参数恰好是一个数组,我们将得到一个正态分布的返回,其中包含该数组的平均值和标准差。这可能开始看起来像一个类,因为我们有一个下面有函数的构造函数,但是这不是我们将要调用的函数。

面向对象的程序设计(Object Oriented Programming)

我们将使用一种新的方法来应用这个分布的概率函数,简称 pdf。正态分布的 pdf 非常简单,只需要我们减去平均值,然后除以数组中每个值的标准差。我们可以在 Julia 中用一行 for 循环来实现,就像这样:

**pdf(xt) = [i = (i-μ) / σ for i in xt]**

现在我们可以将它添加到之前的内部构造函数中:

struct NormalDistribution
    mu::Float64
    sigma::Float64
    function NormalDistribution(x::Array)
        **pdf(xt) = [i = (i-μ) / σ for i in xt]**
        return new(mean(x), std(x))
    endend

这将在这个函数的私有范围内定义 pdf()方法(将来,这个类型。)然而,问题是该类型现在对这个新的 pdf()方法一无所知,我们希望它成为它的子方法。第一步是设置变量类型。我们可以使用{}语法做到这一点。然后,我们将把一个新的数据类型 pdf 转换为该变量类型:

struct NormalDistribution{P}
    mu::Float64
    sigma::Float64
    pdf::P

现在,我们需要做的就是在内部构造函数的返回中更改 new()方法调用,以包含 pdf()方法的类型,并向外部构造函数提供 pdf()方法:

function NormalDistribution(x::Array)
        pdf(xt::Array) = [i = (i-μ) / σ for i in xt]
        return new**{typeof(pdf)}**(mean(x), std(x), **pdf**)
end

现在,我们可以使用正态分布获得正态分布数据,就像我们在 Python 之类的东西中处理类似的对象一样!

x = [5, 10, 15, 20]
dist = NormalDistribution(x)
scaled_data = dist.pdf(x)

结论

我真的希望您喜欢这篇关于如何使用内部和外部构造函数使 Julia 编程像 Python 一样面向对象的概述!Julia 语言的伟大之处在于,这仅仅是一种选择,就方法论而言,它是选项海洋中的一条鱼。这不仅完全改变了范式,而且实际上非常有效!感谢您的阅读,祝您有美好的一天!

如何将你无聊的图表变成电子游戏

原文:https://towardsdatascience.com/how-to-turn-your-boring-graphs-into-a-video-game-e02810bf3ec2?source=collection_archive---------38-----------------------

轻松将 R 图转换成游戏关卡的教程。高管们再也不会在你演讲的时候睡觉了。我保证。

图片作者。这是数据科学人,我们即将打造的游戏的主角。

有些英雄穿斗篷。其他英雄可能有活塞,剑,火箭发射器,或重力枪。

但不是我们的英雄。

不,我们的英雄 dual 挥舞着他传奇的笔记本电脑和 TI-83 计算器。我们的英雄用事实、数字和机器学习模型武装起来,将在 4 年内将利润率提高 1.2%。

这是数据科学人。

数据科学人在这里拯救你的图表,使其免于在你的观众心目中被归档为“无聊且易被遗忘”的可怕命运。

在本教程中,我们将使用 R 的 ggplot2 库绘制一家公司的股票价格,然后在 Unity 中将它轻松转换为实际的视频游戏。你将控制数据科学的人,因为他跌倒,跌跌撞撞的山下降的利润。

只是想玩游戏?滚动到文章底部的游戏网页链接,玩得开心!

是时候提升您的数据科学技能了!我们开始吧!

游戏计划

数据科学人总是有计划的,你也应该有!这是我们将要做的,按照我们将要做的顺序。

  • 获取 Unity Systems Inc (U)去年的股价数据。这也恰好是制作 Unity 3D 的公司,我们将使用该软件制作游戏。
  • 创建该股票价格数据的 ggplot2 折线图。这将有标签,日期,轴等。这将是游戏的‘水平’。
  • 创建该股票价格的 ggplot2 面积图。这将是一个没有标签的透明背景上的黑色图表。它将成为数据科学人行走的无形地面。
  • 将两个图表和上面的数据科学人绘图添加到一个新的 Unity 项目中。我们将添加一些代码使他移动。这看起来就像一个小人在你的星盘上奔跑。会很棒的。
  • 你将说服你的老板,这是仪表板的未来,并获得制作视频游戏的报酬。

在 R 中建立关卡

获取一家公司的股价数据很容易,所以我们不要在这上面花太多时间。我们想要 Unity 系统公司去年的股票价格。我喜欢使用 Pythons 的 yfinance 库,因为它易于使用并且有很好的文档记录。这里有一个链接 到提取数据的 python 代码。你也可以从数百个免费提供股票数据的网站中下载。这里有一个链接到我们将要使用的数据

首先创建一个新的 R 项目和 R 脚本,并将股票数据 csv 放入同一个文件夹。r 项目允许我们使用相对路径,这对于教程来说非常好。顺便说一下,我的整个 R 项目可以在 GitHub 上找到,以防你觉得懒。

让我们从数据的主图表开始。这将是我们游戏的“水平”:

图片作者。

我们的第一个图表有标题、标签和日期。我们使用 tidyverse 库来选择我们想要的数据(时间和价格),然后使用 ggplot2 来制作线图。我们手动将 y 轴限制设置为 0–180。我们为两个图形手动执行此操作,因此它们的大小大致相同。

不幸的是,我们不能把这个图表导入到像 Unity 这样的游戏引擎中,让它作为一个关卡来使用。对 Unity 来说,这只是另一个图像,引擎不知道图表的线应该是地板,或者这个图像应该以任何特殊的方式进行交互。

在 Unity 中,游戏的边界被称为碰撞器。数据科学人的脚上会有一个对撞机,这个会和地板上的对撞机相互作用,给人一种在地上行走的感觉。

Unity 可能无法区分我们的图形中的线条和图像中的任何其他特征,但它确实有能力轻松地用仅由一个特征组成的整个图像制作碰撞器!我们所需要的是我们的图形在透明背景上的完全黑色版本,然后 Unity 将能够检测我们的图形的边界,并通过单击 1 个按钮创建一个地板!

幸运的是,ggplot2 非常棒,允许我们对任何图形做任何我们想做的事情。数据科学家对您的 n00b 友好开箱即用的仪表板解决方案嗤之以鼻!

这与之前的折线图相同,但使用了面积。我们还使用一些主题参数来删除图表中的所有内容(标签、刻度、背景颜色等)。).我们剩下的只是透明背景上的面积图,这意味着背景可能看起来是白色的,但实际上什么都没有。酷毙了。

图片作者。现在这是一个楼团结可以承认!

请注意,该形状与我们的折线图的形状相同。我们需要做的就是把面积图变成 Unity 中的碰撞器,把它和我们原来的折线图对齐,然后让它隐形!烟雾和镜子。

最后,我们将这两个图形保存到 images 文件夹中。

从静止到统一。把我们的图表变成一个水平。

首先,您需要在电脑上安装 Unity 3D。Unity 是免费的,你可以在这里下载。完成后,启动 Unity 并点击“新建”,然后创建一个名为“数据科学人”的项目。选择“2D”作为模板。

图片作者。

一旦你点击“创建”,你应该在统一编辑器内。如果这是你第一次使用 Unity,不要感到害怕。如果你按照我的步骤,你会得到游戏的工作。如果你觉得你需要学习更多,也有数百个针对初学者的 Unity 教程!

在主窗口的右下角,你会看到一个名为“资产”的文件夹。让我们把所有需要的图片都拖到这个文件夹里。您可以一次将多个文件从电脑直接拖到“资源”文件夹。

图片作者。

我们将使用的所有图片都位于GitHub 文件夹中。只需将它们全部下载到您的计算机上,然后放入 Unity。它们包括:

  • 我们在 R 中做的折线图
  • 我们在 R 中制作的面积图
  • 数据科学人
  • 一个叫做“地板”的红色方块
  • 一个玩家动作脚本。这是让数据科学人心动的代码!

图片作者。将文件从电脑上的“图像”文件夹拖到 Unity 中的“资产”文件夹。

将白色“股价线”图拖到场景窗口。

图片作者。将白色折线图拖到场景中。

将黑色的“StockPriceArea”图像拖到场景窗口中。

图片作者。将黑色区域图拖到场景视图中。

现在,如果黑色面积图在白色折线图的上面,就像上面的截图一样,那就很好。如果黑色图表位于白色图表下方,只需点击场景视图中的黑色区域图表,并查看 Unity 右侧的检查器选项卡。找到“位置”并将 Z 值更改为-1。

图片作者。只有当黑色图表位于白色图表下方时,您才需要修改此设置。

接下来,您需要将面积图与折线图对齐。为此,您可以结合使用屏幕左上角的“缩放”和“移动”工具。不一定要精确,但你希望波峰和波谷尽可能排成一行。

图片作者。首先单击您的面积图,然后使用这两个工具来对齐它们。

图片作者。这些是要拖动的手柄。不一定要完美,足够接近就好。

现在是魔法酱的时候了。这是我们在 R 中所做的一切的目的,也是让我们能够将你们自己公司的数据转化为视频游戏水平的原因。点击场景视图中的黑色区域图,回到右边的检查器窗口。在底部,点击“添加组件”并输入“多边形”。选择“多边形碰撞 2D”。

图片作者。选择多边形碰撞器 2D。

嘣!!看看吧!

图片作者。

因为 ggplot2 允许我们自定义图表,我们认为合适,并把清晰的黑色形状放在透明的背景上,Unity 能够检测图表的边界,以创建多边形!这意味着这现在是我们视频游戏中的工作层。

这和你以前玩过的任何 2D 平台游戏中的山没有什么不同。但是你想一想……在二维空间里,一座山除了一系列间隔不一、坡度上下不一的数据点还能是什么?归根结底都是数学,伙计。自然界的一切都只是信息,从山坡到你细胞中的原子。我是不是陷入了二维空间?悖论!

哲学够了!

将数据科学人带入生活

现在我们有了一个关卡,是时候把数据科学家放进去,让他动起来了!

图片作者。把数据科学家拖到图表上!

现在数据科学家已经到了我们的水平,让我们在他的脚下添加一个物体,这样他就可以在地上行走了。在左侧的层次视图中右键单击“DataScienceMan ”,然后单击“创建空”。这就创建了一个空的游戏对象,它附属于我们的主角。

图片作者。右键单击数据科学人,然后单击创建空

将此对象重命名为“Origin”。然后使用移动工具,并调整它,使我们的新对象在我们的英雄的脚下。这将与我们的 R 图发生冲突,并使他看起来像是在我们的数据上行走(和跌倒)!

图片作者。

为了让我们的英雄移动,我们需要给他添加一个移动脚本。这个脚本在我们的 images 文件夹中,所以您应该已经把它拖到项目中了。我们需要做的就是将这个脚本从我们的 assets 文件夹拖到层次视图中的 DataScienceMan:

图片作者。将 Move.cs 拖动到“DataScienceMan”中。

现在是时候给数据科学人添加一些组件了。我们快完成了!点击层次视图中的 DataScienceMan,查看检查器。单击“添加组件”并键入“刚性”。从下拉菜单中选择“刚体 2D ”:

图片作者。添加刚体 2D 组件。

在 unity 中,给像 Data Science Man 这样的游戏对象添加新的组件会赋予它新的属性。刚体 2D 组件允许我们的角色受物理影响!不相信我?点击顶部的 play,看着他直接从地板上摔下来。

图片作者。这是播放按钮,它播放游戏。谁能想到呢?

地心引力正在把他往下拉!但是为了让他击中我们的图表并坚持下去,我们需要添加最后一个组件。点击“添加组件”并键入“box”,然后选择 BoxCollider2D:

图片作者。向 DataScienceMan 添加一个箱式碰撞器 2D 组件。

现在,如果你点击 play,我们的角色就会移动并站在我们的图上。只有一个问题,数据科学家是巨大的!让我们把他缩小一点,让他看起来像站在一座山上,而不是一个小山丘。

图片作者。数据科学人太大了。

再次点击“数据科学人”并返回到检查员。将他的 x 和 y 比例值设置为 0.5。现在他只有以前的一半了!

图片作者。缩放 x 和 y 改变他的尺寸。如果 DataScienceMan 出现在游戏中的物体后面,降低他的 z 位置会让他出现在前面。

数据科学家还有最后一件事要做。将我们创建的“原点”对象拖动到他的移动脚本的“光线原点”参数上。这是告诉我们的脚本,我们想用它作为他的脚!

图片作者。像这样拖动原点到移动脚本上。

你现在有一个工作的视频游戏!单击顶部的播放按钮查看。“A”键左移,“D”键右移,空格键跳跃!如果他掉下关卡,“R”键会重置游戏。

现在,当你跳跃的时候,数据科学人就像是发射到了外太空。我们可以做一些清理工作,让我们的游戏更有趣一点。

清理美学

首先,让我们摆脱面积图。这意味着是他的看不见的地面,我们希望他看起来像是在有标签的线图上走来走去。只需点击场景或层次视图中的黑色区域图,进入检查器并取消选中“精灵渲染器”。

图片作者。取消选中面积图的 sprite 渲染器。

这意味着图像不再被绘制,但是物体(以及碰撞器)仍然在那里。

好了,还有最后两件事要做。抓住红色的“地板”图像,并将其拖动到图表上方。使用缩放和移动工具将其拉伸到图表上方。在该对象的检查器中,单击“添加组件”,然后像我们处理数据科学人对象一样,在它上面放置一个 2D 碰撞器。

图片作者。将地板图像添加到游戏中,并在上面设置一个 2D 碰撞器。

这个对撞机将阻止数据科学人跳跃到达轨道。最后一步是调整相机,使其恰到好处。你可以点击“游戏”视图(它就在我们一直使用的“场景”视图旁边)来查看相机视窗。点击层次视图中的“主摄像机”并查看其检查器。

图片作者。游戏视图将向您展示摄像机看到的内容。使用此视图调整摄像机。

图片作者。点击“主摄像头”并调整它的“大小”来移动摄像头。位置 x 和 y 将上下左右移动它。滴管会将背景设置为与您的图表相同(先点按滴管,然后点按您的图表)。

选择了“游戏”视图(不是“场景”!)调整“大小”字段,直到图表刚好在视图中。确保我们的红色天花板不可见。最后,单击“背景”右边的滴管,并单击图表中的某个位置,使背景与我们的图表相匹配。

就是这样!你现在可以在我们的 R ggplot2 图表上行走、跳跃和翻滚了。当他从屏幕上掉下来时,只要按“R”就可以让他复活!

可能性是无限的

这是游戏能做到的最简单的事情了。但是停下来想象一下所有的可能性。我们每天使用的许多图表将会成为可爱的视频游戏。

旋转甜甜圈图作为刀片,条形图作为跳转的壁架,在树状图中滑行,在气泡图中浮动,甚至不要让我开始使用径向条形图和重力!

我保证我们会在以后的文章中做到这些。数据科学人的冒险才刚刚开始!

如果你时间紧迫,只想玩这个游戏,我已经在这里上传了它的网页版。尽情享受吧!

这个项目的所有代码包括 R 项目,制作游戏所需的图像,以及 Unity 项目都可以在 GitHub 上获得。

数据科学人永远遵循规律。这就是大数定律。你知道吗,在一篇文章中,你最多可以点击鼓掌按钮 50 次!

如何将您的数据科学想法转化为受资助的项目

原文:https://towardsdatascience.com/how-to-turn-your-data-science-idea-into-a-funded-project-f919dbaff104?source=collection_archive---------30-----------------------

技术、数据科学、学习

为你的数据科学想法和项目寻找资金的一些建议。

作者图片

所有的数据科学家心里至少隐藏着一点数据科学的想法。然而,由于时间限制或缺乏资金,他们不会将想法转化为项目。

在这篇文章中,我提出了一个将你的想法转化为数据科学项目的策略。所采用的方法基于以下步骤:

  • 写一份项目建议书的草稿
  • 搜索合作伙伴和协作者(可选)
  • 寻找资金
  • 根据出资方模板修改项目草案并提交

1 .撰写项目建议书草稿

资助项目的第一步包括撰写项目初稿。在写完整的草稿时,尝试回答以下问题:

  • 我的项目涵盖哪个主题?
  • 我的项目解决了哪个问题?

通常,一个项目建议书,由以下几项组成:

  • 摘要
  • 项目目标
  • 类似项目
  • 项目架构
  • 工作计划
  • 对社会的影响
  • 项目参与者的描述
  • 甘特图

1.1 摘要

摘要是对项目的概述。如果你的项目涉及数据科学,总结应该包含与数据科学相关的最重要的关键词,比如机器学习数据分析数据可视化人工智能等等。

为了构建一个成功的提案,该项目还应该处理至少一个与数据科学相关的热门话题,例如由 ODSC -开放数据科学撰写的有趣文章中描述的那些话题。

总结应恢复项目的所有部分,包括背景描述、目标、对社会的影响等。

1.2 项目目标

你的项目至少要解决一个问题,否则不会资助。例如,作为一名数据科学家,你可以提出一种新的机器学习算法,实现一个新的有趣的仪表板来讲故事,或者建立一个数据新闻故事。无论如何,你的项目目标应该非常明确。

一般来说,在撰写本节时,您应该关注两种目标:

  • 总体目标,例如提供一个用于讲故事的仪表板
  • 具体目标,比如利用拟议中的仪表板来了解蚂蚁随时间推移的行为。

这一部分应该非常清楚,不应该出现歧义。

1.3 类似项目

到目前为止,你已经描述了你的想法。但是,你应该看看你的周围,看看你的想法是否已经被其他人实施了。如果你的答案是肯定的,那就不要浪费时间去写你的提议,相反,要努力为你的想法增加附加值。

您可以通过在搜索引擎上搜索您的总体/具体目标来搜索类似的项目。如果你没有找到任何东西,这并不意味着没有类似的项目,你的想法。很有可能你在以错误的方式寻找。搜索,再搜索,直到你找到至少 2-3 个类似的项目。

为了执行你的搜索,你也可以看看社交网络。例如,你可以利用 Twitter 作为扩展你知识的地方。此外,你可以在谷歌学术搜索,正如我在之前关于如何从数据科学项目撰写科学论文的文章中所描述的。

一旦建立了类似的项目,你可以阅读它们,以获得一些额外的想法,这些想法可以用来丰富你的提案。无论如何,你应该写一段话,描述相关的项目。

1.4 项目架构

现在你可以详细描述你的想法了。尝试建立一个图表,描述它。例如,您可以将项目的每个元素表示为一个组件。在机器学习管道的情况下,您可以为管道的每个元素添加一个组件(数据清理、数据分析、数据测试、数据生产等等)。

这一部分不应该描述用来实现你的项目所采用的技术,比如 Python 或者 R 软件,而是描述一般的概念,元素是如何连接的。

1.5 工作计划

工作计划部分应该描述项目将如何组织。通常项目被组织在工作包中,如下所示:

  • 项目管理——与项目管理相关的所有方面,包括如何管理资金的分析
  • 建筑设计
  • 架构的每个元素一个工作包
  • 传播和利用——如何推广项目

1.6 对社会的影响

对社会的影响常常被低估,这是项目建议书最重要的部分之一。事实上,如果一个项目不能为社区带来任何好处,它就是无用的。

在这一部分,你应该描述为什么一般的社会或特定的社区可能会利用你的项目。

例如,在新的在线新闻分类系统的情况下,对社会的影响可能是根据每个用户的兴趣为他们提供更好的新闻建议。

1.7 行为者的描述

一个好的项目建议书应该描述谁来实施它。在这里,你应该包括一份 10 行的简历摘要,重点是实施项目所需的技能。

此外,该部分应包括项目所有其他合作伙伴(参与者)的简短简历(如果有)。你可以在这篇文章中进一步了解如何为你的项目寻找合作伙伴。

1.8 甘特图

甘特图代表您的项目时间表,包括期限。换句话说,它描述了在项目生命周期中如何实施工作计划。

有许多工具可以实现甘特图,比如本文中描述的那些工具。

丹尼尔·麦卡洛Unsplash 上拍照

2 搜索合作伙伴和协作者

到目前为止,你已经写了一份项目草稿,可能有 5-10 页。现在是时候寻找合作伙伴了。首先,你应该确定你要找的伴侣的类型。例如,你可以搜索具有文本分析或数据可视化技能的人。无论如何,试着为每个期望的个人资料和他们在项目中的相关角色写 3-4 个句子。

下一步是在你的同事中或通过你喜欢的社交网络传播这种声音。例如,你可以探索 Twitter 话题,找到一些符合你要求的人,采用我在之前的文章中描述的策略,用 Twitter 扩展你的知识。

或者,您可以利用特定的网站进行合作伙伴搜索,例如欧盟委员会提供的合作伙伴搜索网站,以及本文中描述的网站

一旦确定了一些潜在的合作伙伴,你可以通过解释你的想法来联系他们。你不必分享项目的完整草稿,只需分享摘要即可。然后,如果合作伙伴同意加入您的项目,您可以与他们分享完整的草案。

您可以决定不向您的项目添加合作伙伴。提醒一些项目电话需要至少三个合作伙伴,来自三个不同的国家,因此我强烈建议寻找合作伙伴。

3 寻找资金

寻找资金是最困难的部分,因为它需要不同参与者之间的激烈竞争。无论如何,你可以通过很多渠道获得资助:

  • 国家或国际层面的呼吁:几乎所有国家都会定期发布项目呼吁。例如,欧盟委员会有一个名为融资&招标机会的门户网站,专门用于项目融资。一般来说,在这种类型的招标中很难找到资金,因为竞争非常激烈,而且拟议的项目应该对社会产生很大影响。所以,我建议甚至不要尝试这条路,除非你有一个非常好的想法和一个强大的合作伙伴。
  • 基金会的呼吁:基金会也定期发出项目呼吁。通常这类电话是指满足基础要求的小型项目。基金会的例子有大众基金会和与银行有关联的基金会。
  • 筹款:最后,但同样重要的是,你可以尝试筹款选项,通过普通人的自愿捐款来筹集资金。有很多平台是为了筹款而存在的,比如 GoFundme

你可以尝试所有建议的渠道,注意为每个选择的渠道修改项目建议书的标题。

4 根据出资方模板修改项目草案并提交

一旦选择了适合您的合适渠道,您应该下载与通话相关的所有文档。你应该仔细阅读它。阅读时,尽量突出最重要的关键词和句子,比如人工智能、机器学习等的新视角。

至少读两遍电话,试着理解电话需要什么。现在你可以修改你的提议草案了,为了包含所有高亮句子的释义。

让你的合作者参与撰写项目建议书的最终版本。

再次阅读您的建议,并最终在截止日期前提交给电话!

米妮·迪法在 Unsplash 上的照片

摘要

在本文中,我描述了一个简单的策略,将您的数据科学想法转化为一个受资助的项目。

最困难的部分是寻找正确的渠道来获得资助,但有了一点经验,你会找到适合你的方式!

感谢您的阅读!你可以在这篇文章中读到更多关于我的信息。

相关文章

https://betterhumans.pub/6-tips-for-extending-your-knowledge-with-twitter-af2bc8c16bdb https://alod83.medium.com/the-death-of-semantic-web-or-new-challenges-e7e8860d9b06

离开前再说一句…

你可能有兴趣阅读我在第集的新故事,名为小女孩和小丑:

卡特琳娜·奥尔米 第一次被带到马戏团的时候才七岁。她有两只蓝眼睛,大如天空,深如大海。金色卷发披在她的肩上。她看起来几乎像一个公主。卡特琳娜·奥尔米是个非常漂亮的小女孩。很好,很好。可能有点太敏感了。 但她有一颗宽大的心 每个母亲都喜欢的女儿。

那天晚上,她和父母一起去看马戏,继续阅读

新到中?您可以每月订阅几美元,并解锁无限的文章— 单击此处

如何理解具有集成梯度的深度时间序列分类器

原文:https://towardsdatascience.com/how-to-understand-the-deep-time-series-classifier-with-integrated-gradients-f4f58af48c05?source=collection_archive---------7-----------------------

作者图片:电机数据的两个实例

时间序列分类是一个常见的问题,可以在许多领域和环境中看到,例如,对于金融产品的给定时间序列,预测客户是否会购买。

然而,由于特殊的时间维度,理解分类器为什么做出决定并不总是一件容易的事情:决定标签的不是时间线上的单个点,而是整个时间线。但是所有的时刻都重要吗?它们的重要性相同吗?对于预测来说,今天比昨天更重要还是星期二比星期天更重要?

在本文中,我试图给出我的解决方案来解释时间序列分类器。本文主要由两部分组成:

  1. 在第一部分中,我将为一个经典的时间序列分类问题建立一个 CNN 模型。
  2. 在文章的第二部分和主要部分,我将使用综合梯度来解释模型的预测。

请在这里查看笔记本中我所有的代码。

CNN 模型作为时间序列分类器

我建立的模型考虑了来自本教程的一个例子。

数据集

给定的数据集由电机数据组成,其中每个实例都是电机传感器捕获的发动机噪声测量值的时间序列。该任务的目标是预测发动机是否有特定问题。关于数据集的更多细节,你可以看看这篇的论文

本文开头的图显示了这个时间序列中的两个实例:类 0 表示不存在问题,而类 1 表示存在问题。此外,我给出了下图:所有三条曲线都属于同一个 0 类(没有问题的类),因此您可以看到,要想知道时间序列可以被标记的原因并不简单:

图片作者:同一类的三个时间序列 0

CNN 模型

时间序列与其他正常特征的一个重要区别是时间线上的每个点都不是独立于预测的。一个时刻一个点不仅应该包含该时刻的信息,还应该包含过去的一部分信息。这需要提取时间序列的特征(平均值、标准差、最大值等)。在观察窗口内)。我们将使用以下代码构建一个 1D CNN 模型来进行分类,而不是进行特征提取:

from keras import models
from keras import layersinput_layer = layers.Input(shape=(x_train.shape[1],1))
conv1 = layers.Conv1D(filters=64, kernel_size=3, padding="same")(input_layer)
conv1 = layers.BatchNormalization()(conv1)
conv1 = layers.ReLU()(conv1)
conv2 = layers.Conv1D(filters=64, kernel_size=3, padding="same")(conv1)
conv2 =layers.BatchNormalization()(conv2)
conv2 = layers.ReLU()(conv2)
conv3 = layers.Conv1D(filters=64, kernel_size=3, padding="same")(conv2)
conv3 = layers.BatchNormalization()(conv3)
conv3 = layers.ReLU()(conv3)
gap = layers.GlobalAveragePooling1D()(conv3)
output_layer = layers.Dense(1, activation="sigmoid")(gap)
model=models.Model(inputs=input_layer, outputs=output_layer)

下面我给出一个情节作为模型的总结。可以看到,模型中有三个 1D 卷积层。

作者图片:CNN 模型摘要

在 3601 个实例上训练并在另外 1320 个实例上测试,该模型在具有早期停止的 220 个训练时期之后达到 0.9697 的 val_binary_accuracy。

IG 解释的时间序列预测

作为解释者的 IG

现在让我们深入一点。如何才能理解模型?为了解释 CNN 分类器,我将使用综合梯度作为工具。我想你对 IG 很熟悉。如果没有,请查看我的上一篇博客,在这篇博客中,我简要介绍了 IG,并展示了一个关于它的实现和限制的例子。

简而言之,IG 将系数概化为线性表达式,其输入要素的值用于测量该要素如何使模型的输出不同于基线输出。在这个例子中,基线被简单地选择为一个时间序列,所有的点都是 0。下面是 IG 的定义。

图片 bu 作者:IG 的定义

根据上述定义,IG 是通过沿着从基线到输入的直线路径累积梯度而获得的。实际上,借助于张量流的自动微分,梯度的计算可以很容易地用下面的代码得到:

def compute_gradients(series):
   with tf.GradientTape() as tape:
     tape.watch(series)
     logits = model(series)
    return tape.gradient(logits, series)

结果

为了说明 IG 如何帮助我们理解我们在上一章中建立的模型,我在测试数据集中选择了两个时间序列,它们分别被预测为 1 类和 0 类。图中的曲线显示时间序列,而颜色显示 IG 值的绝对值:颜色越深,IG 值越大。换句话说,曲线上的深色部分对预测的贡献更大。

作者图片:具有 IG 值的类 1 中的时间序列

作者提供的图片:具有 IG 值的 0 类时间序列

结论

我们可以从这两幅图中观察到一些有趣的事情:

  1. 一个单独的点不能导致预测。在时间线上总是存在一个点的邻域,其中所有点对预测具有相似的贡献值。
  2. 对于预测来说,时间线上的一些点(间隔)远不如时间线上的其他点重要。
  3. 即使我们没有导致预测的提取特征的量化值,我们仍然可以对 CNN 分类器的输出有很好的视觉直觉。例如,该值的局部最小值或最大值对预测没有大的影响。

如何卸载 PostgreSQL 13.3 并通过 Brew 重新安装

原文:https://towardsdatascience.com/how-to-uninstall-postgresql-13-3-and-reinstall-via-brew-6c1e7047f349?source=collection_archive---------7-----------------------

关于删除通过安装程序安装的 PostgresSQL 并通过 brew for macOS Catalina 重新安装它的分步指南

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

这是给谁的?

对于任何需要完全卸载 PostgresSQL 13.3 的人,该版本是通过安装程序安装的。

本文将涵盖三个主题:

  • 如何卸载 PostgreSQL 13.3
  • 如何通过 brew 重新安装 PostgreSQL
  • 测试它是否工作:创建数据库、用户和授予特权
  1. 如何卸载 PostgreSQL 13.3

第一步:打开你的终端。检查安装的版本和位置。在我的例子中,它安装在/Library/PostgreSQL/13/bin/psql

# check version
$ postgres --version
postgres (PostgreSQL) 13.3# locate where it is installed
$ which psql
/Library/PostgreSQL/13/bin/psql

第二步:根据uninstall-postgres.app是否安装,我们有两种解决方案。

解 2A:

改变目录运行uninstall-postgres.app这个应用程序位于bin文件夹的上层目录,在我的例子中是/Library/PostgreSQL/13

# change directory$ cd /Library/PostgreSQL/13
$ open uninstall-postgres.app

如果卸载窗口提示,您可以按照本指南上的【在 Mac 上卸载 PostgreSQL】一节进行操作。

然而,这个解决方案对我不起作用。我收到一条错误消息:

$ open uninstall-postgres.appThe file /Library/PostgreSQL/13/uninstall-postgres.app does not exist.

在网上尝试了许多其他方法后,虽然似乎都没有结果,但我注意到一个有趣的模式,即→对于同一功能,有些人会使用 **postgres** ,而其他人会使用 **postgresql**。出于绝望,我意外地发现了解 2B。

解 2B :

改变就好→

$ open uninstall-postgres.app

$ open uninstall-postgresql.app

这是一个很小的变化,但它的工作!🤩

# change directory$ cd /Library/PostgreSQL/13
$ open uninstall-postgresql.app

卸载窗口提示!如果这也适用于你,你可以遵循本指南中的【在 Mac 上卸载 PostgreSQL】一节,直到图 8。

重要提示:在你按照上面的指南,一直到图 8,我们还没有完成!为了删除所有 Postgres 相关文件,您需要执行步骤 3。

步骤 3:删除 Postgres 相关文件

# change to home directory
$ cd ~
$ sudo rm -rf /Library/PostgreSQL
$ sudo rm /etc/postgres-reg.ini# some people also suggested to remove sysctl.conf
# but I don't seem to have this file in my environment
# so I ignored it. You can try if you'd like
$ sudo rm /etc/sysctl.confrm: /etc/sysctl.conf: No such file or directory

🎉🎉🎉万岁!我们成功卸载了 PostgreSQL 13.3!!

2。如何通过 brew 重新安装 PostgreSQL】🍺

我需要卸载 PostgreSQL 的原因是,当我需要创建一个测试数据库时,我不能使用我的同事正在使用的代码。我们怀疑通过安装程序安装的 PostgreSQL 和通过 brew 安装的 PostgreSQL 是有区别的。长话短说,这是真的至少在我的情况下,它解决了问题。

通过 brew 安装 PostgreSQL 非常简单,它有两个步骤:

# 1\. update brew
$ brew update# optional: run brew doctor (I did this.)
$ brew doctor# 2\. install postgresql
$ brew install postgresql

至此,我们可以通过运行下面的命令来启动 PostgreSQL。

$ brew services start postgresql

运行之后,它告诉我们已经成功启动了postgresql

==> **Successfully started `postgresql` (label: homebrew.mxcl.postgresql)**

现在,让我们测试一下它是否工作。

3。测试:执行三项任务—创建数据库、用户和授予特权。

第一步:启动 Postgres

# 1\. launch postgres
$ psql postgrespsql (13.3)
Type "help" for help.postgres=# ls
postgres-# help
Use \? for help or press control-C to clear the input buffer.
postgres-# \q

您可以使用命令\l查看所有可用的数据库。比如这是我能看到的。

# note: postgres=# is a prompt, not part of the command
# the command is \l, which lists all databasespostgres=# \l

第二步:我创建了一个名为discovery_db的数据库,你可以根据自己的目的命名这个数据库。

postgres=# create database discovery_db;# use \l to check again
postgres=# \l

现在我们有 4 排,discovery_db列在最上面。整洁!

第三步:创建一个带密码的用户。

postgres=# create user discovery_db_user with encrypted password 'discovery_db_pass';

第四步:将所有权限授予我们刚刚创建的用户。

postgres=# grant all privileges on database discovery_db to discovery_db_user;

现在,我们再检查一遍→

在输出Access privileges中,我们可以看到discovery_db_users拥有与所有者wen(我)相同的特权😊).

最后,我们可以用内容退出 postgres \q

postgres=# \q

关键要点:

  1. 如果您遇到 Postgres 问题,并且您在网上找到的博客帖子似乎对您不起作用,请尝试修改命令postgrespostgresql,反之亦然。
  2. Postgres 有许多不同的版本。如果你不能运行其他人的代码,完全卸载 Postgres 并重新安装可能比调试几天更容易。
  3. 我意识到一旦有了新版本的 Postgres,这篇文章可能会过时,但我认为它至少可以作为 PostgreSQL 13.3 + MacOS Catalina 系统的定时解决方案。

如何通过添加 NLP 的味道来解锁强大的计算机视觉应用

原文:https://towardsdatascience.com/how-to-unlock-powerful-computer-vision-applications-by-adding-a-flavor-of-nlp-d125ef81559d?source=collection_archive---------35-----------------------

结合 NLP 和计算机视觉的深度学习模型

图片来自 Pixabay

什么是剪辑?

计算机视觉中的自监督学习在学习图像的不同表示方面显示出巨大的潜力。

这是一种神经网络可以学习表示的方法,这些表示可以在以后用于不同的任务,如图像分类和对象检测。

从数据集学习表示的另一种方法称为 剪辑 ,由 OpenAI 开发。

这种方法使用(图像,文本)配对来学习图像编码器和文本编码器。这意味着它结合了自然语言处理和计算机视觉。

我觉得这很酷!

一旦学习了这些编码器,它们就可以在零射击设置中用于完成不同的计算机视觉任务。

剪辑工作原理的高级概述

在下图(左侧)中,我们看到了如何使用(图像,文本)配对来学习两个编码器。一个是文本编码器,另一个是图像编码器。这就好像我们试图将语言映射到视觉,反之亦然。

然后,这两个编码器可以用于一次性设置,以预测图像包含的内容,例如,如下图右侧所示。

剪辑高级概览图(来自原纸[1])

为什么剪辑令人印象深刻?

ResNet-50 在来自 ImageNet 的 128 万个人群标记的训练样本上进行训练。它通过纯监督达到了很高的 top-1 精度。

CLIP 通过不使用这 128 万张图像中的任何一张图像达到了相当的准确性!

CLIP 也达到了与 InceptionV4 相当的前 5 名精度。后者是在一个纯粹的监督环境中接受培训的。

仔细想想,这太不可思议了!

我测试了 CLIP 深度学习模型

使用 OpenAI 提供的开源代码,我给 CLIP 了下面这张图片,是我从股票图片网站 Unsplash 得到的。

WALL-E(来自 Unsplash)

这张图片是一个名叫瓦力的机器人,它曾出现在同名电影中。

我通过给 CLIP 一个包含句子“a robot”的句子字典来测试它。

作者制作的图像

标签问题:[[5.436 e-04 3.622 e-04 4.041 e-04 9.985 e-01]]

夹子答对了!它给了这个标签最高的概率。

然后我给它除了“一个机器人”还加了“瓦力”这个词。

作者制作的图像

标签问题:[[1.329 e-05 8.881 e-06 9.756 e-01 2.443 e-02]]

瞧,它也做对了!

事实上,我保留了两个句子:“一个机器人”和“瓦力”,它给了后一个标签最高的概率!

还记得吗,CLIP 在纯监督环境下既没有被训练识别机器人,也没有被训练识别瓦力。但它仍然能够一次性识别出它们。这太不可思议了!

不仅仅是这样!通过给这个模型贴上“瓦力”和“机器人”的标签,我试图了解 CLIP 对这个图像到底了解多少。我认为“wall-e”这个标签太具体了,但显然这个模型非常强大!

如果要我在其他具体案例上测试,请告诉我!

结论

在本文中,我们了解了自然语言处理和计算机视觉的结合是如何产生一些令人难以置信的结果的。CLIP 是一个深度学习模型,展示了这一点。我们看到了 CLIP 如何在一次性设置中使用,并且仍然做出正确的预测。这是深度学习的未来吗?

参考

[1]亚历克·拉德福德等.从自然语言监督中学习可转移视觉模型

作者制作的图像

我是一名机器学习工程师,致力于解决具有挑战性的计算机视觉问题。我想帮助你学习应用于计算机视觉问题的机器学习。以下是方法。

  1. 通过帮助您了解该领域的最新动态。我几乎每天都在 LinkedInTwitter上分享一些小帖子。那就跟我去吧!
  2. 给你一份我的https://nourislam.ck.page/dc3e8b7e12时事通讯上那些琐碎帖子的每周摘要。所以订阅吧!****
  3. 通过在 Medium 上写关于机器学习不同主题的文章。所以跟我来吧!
  4. 给你一份免费的机器学习工作清单,帮助你检查你需要学习的所有要点,如果你计划在 ML,特别是在计算机视觉方面的职业生涯。你可以在这里 得到核对表

5.最后但同样重要的是,通过与你分享我的 免费入门张量流课程 ,它有超过 4 小时的视频内容,你可以在那里问我任何问题。

此外,如果您有任何问题或者您只是想聊聊 ML,请随时在 LinkedIn 或 Twitter 上联系我!

如何上传广告数据到谷歌大查询

原文:https://towardsdatascience.com/how-to-upload-ads-data-to-google-bigquery-5ebdf1a2cf90?source=collection_archive---------27-----------------------

来源: Unsplash

了解如何在一个集中的数据仓库中比较和分析您所有营销渠道的广告表现,以及如何轻松地将您的广告数据上传到 GBQ。

如果你像许多营销人员一样,你可能会使用各种数字营销渠道开展活动——不仅包括谷歌广告,还包括脸书、Instagram、Twitter、LinkedIn 等等。没有钱可以浪费,你的目标是从每项营销投资中获得最大收益。为此,您需要清晰、全面地了解客户在所有渠道和设备上的旅程。

在这篇文章中,我们将探讨如何将所有的东西放在一起,并将所有的营销数据上传到一个数据存储中(例如 Google BigQuery ),从而描绘出一幅广告活动绩效的美好画面,并提高所有多个广告渠道的投资回报率。

全渠道营销分析已经成为任何规模和行业的组织的关键工具。然而,大多数营销人员将时间浪费在日常活动上,比如手动组织数据。 OWOX BI 为您耗时的营销常规提供解决方案。有了 OWOX BI,来自付费活动的广告数据将被自动拉入 Google BigQuery。您可以根据自己的需要存储多长时间,根据需要创建详细的报告,了解付费营销计划的真正价值,并更好地利用您的广告支出。

当今数字营销的挑战

今天的客户旅程比以往任何时候都更加复杂。数字说明了一切:根据 Salesforce 的《2020 年关联客户状况报告,72%的消费者使用多种沟通方式来开始并完成一笔交易。从 Z 世代到沉默一代,63%的消费者使用多种设备开始并完成一笔交易。最重要的是,62%的消费者表示,他们更喜欢个性化的产品或服务,而不是标准的“一刀切”的报价。

图片由作者提供

单个客户的旅程可能需要几分钟到几个月的时间。它可能发生在一个渠道中,也可能跨越多个接触点和设备。举个例子:用户可以首先通过智能手机上的脸书广告访问你的网站,然后在初次互动几天后,通过笔记本电脑上的搜索广告注册并购买。在当今多渠道、多设备的环境下,消费者只需点击一下鼠标,就能离开你的品牌,转向竞争对手。

如果你像大多数营销人员一样,你可能正在努力与你的客户保持联系,并让他们通过互联网参与进来。你需要数据——这不用说。像大多数营销人员一样,你可能已经在筛选无数的活动报告,努力发现客户行为的趋势和模式,确定制胜策略,并优化你的营销策略。你留意一些选择的指标,其余的只是堆积在广告平台上,从未真正被分析或使用。

但是这里有一个警告:如果你不关注价值,你就会落后于

Gartner 称,大多数营销分析团队仍然将大部分时间花在组织数据、运行即席查询和生成报告上,而不是实际使用他们的数据来为他们的营销决策提供信息。结果呢?Gartner 报告称,超过一半的高级营销领导对其分析投资的结果感到失望。

自动化日常活动将使您能够专注于对您的组织真正重要的事情,例如提取隐藏的见解并利用它们做出更好、更明智的营销决策。

尽管如此,在你的数据中寻找洞察力之前,你必须在一个地方收集和合并它。最广泛使用的解决方案是 Google BigQuery,这是一个完全托管的无服务器数据仓库,是 Google 基础设施的一部分。

BigQuery 有什么特别之处?

全渠道营销的主要障碍之一是数据存储在彼此不容易沟通的孤岛中。如果你使用许多不同的平台开展付费营销活动,你就会知道密切关注每个活动并试图将所有营销活动的数据整合在一起是多么困难。

这就是 Google BigQuery 的用武之地。

Google BigQuery 是一个无服务器的、可扩展的数据仓库,具有内置的查询服务。它为营销人员提供了一个集中的位置来进行高级数据驱动的营销,而不需要广泛的技术技能、对 It 的依赖或大量的资金投资。

然而,BigQuery 有一个很大的问题——它不能与非谷歌服务集成。

您需要第三方连接器来整合来自非 Google 数据源的接触点。也就是说,如果你想从你的网站、CRM、ESP 或广告平台如脸书广告到 BigQuery 获取数据,你需要一个像 OWOX BI 这样的服务来帮你完成繁重的工作。

图片由作者提供

接受挑战:6 种自动上传常规数据的方法

您可以通过多种方式将您的广告数据上传到 Google BigQuery。主要任务是找到一种适合您的业务的方法,需要最少的努力,节省最多的时间,并提供可靠和准确的结果。

让我们来看看将数据上传到 Google BigQuery 的方法:

  1. 从 CSV 或 JSON 文件上传数据。您可以手动将包含广告数据的 CSV 或 JSON 文件直接从 Google 云存储、Google Drive 或您的计算机上传到 Google BigQuery。
  2. 用 Google Sheets 上传数据(OWOX BI BigQuery Reports 插件)。你可以使用免费的 OWOX BI BigQuery Reports 插件从 Google Sheets 上传数据。你可以直接从 Google Sheets 或者从 Chrome 网上商店安装这个插件。
  3. 从谷歌云存储上传数据。 谷歌云存储让你安全地在线存储和传输数据。你可以在谷歌云帮助中心了解数据下载限制云存储权限
  4. 从谷歌广告和谷歌广告管理器等其他谷歌服务上传数据。要从各种 Google 服务上传数据,首先需要配置 BigQuery 数据传输服务。在您可以使用它之前,您必须选择或创建一个数据项目,并且在大多数情况下,为它启用计费。
  5. big query API下载数据。有了云客户端库,你可以使用你最喜欢的编程语言来使用 Google BigQuery API。
  6. 使用第三方工具上传数据。例如,通过 OWOX BI Pipeline ,您可以自动从广告服务以及呼叫跟踪和 CRM 系统中收集数据。这使您能够快速、轻松地从您选择的源中获得现成的完整数据集。

这些方法各有利弊,以及它们最适用的业务挑战。然而,为了跟上现代世界的步伐,最好通过尽可能自动化和简化流程,为你不能委派的任务节省时间和精力。

对于大多数企业来说,最佳决策是选择一个以最快、最简单的方式满足其需求的单一服务。那么,让我们来看看将你的广告数据上传到 Google BigQuery 的最佳方式之一。

BigQuery 和 OWOX BI:释放数据价值的正确组合

OWOX BI 是一个全面的商业智能系统,旨在促进营销分析和决策。借助 OWOX BI,营销人员可以自动集中各种来源的不同数据,并使用这些整合数据来:

  • 分析他们的营销努力
  • 创建自动化报告
  • 揭示客户与组织互动的新见解
  • 优化您的营销投资以获得更好的投资回报。

您不必编写一行代码,不必四处寻找连接器,也不必手动准备数据。OWOX BI 会处理好一切。

现在,OWOX BI 和 Google BigQuery 到底能帮你做什么?

汇集来自多个系统的数据

只有在将数据整合到一个集中的位置后,它才变得可操作。您需要做的第一件事是有效地整合您的数据,以便您可以轻松地处理、分析和提取来自所有这些众多客户接触点的见解。你需要知道你信任你的数据,并且你在比较苹果和苹果。

图片由作者提供

OWOX BI 提供了一套连接器,可以自动将你所有营销平台的原始数据,包括 LinkedInTwitterInstagram脸书拉至 BigQuery。结果是一个随时可用的数据集,每天自动更新。此外,您将能够将这些数据与来自其他接触点的数据联系起来,包括来自您网站的原始实时数据以及来自您的 CRM、呼叫跟踪和电子邮件营销系统的数据。你唯一要做的事情就是全力以赴,专注于将数据付诸行动。

处理海量数据

BigQuery 是谷歌云平台的一部分,这意味着你可以获得谷歌的云计算和存储能力。您可以在这里存储万亿字节的数据,包括所有的历史数据,并在几秒钟内对数十亿行进行查询。

减少重复性的工作

在传统场景中,营销人员必须手动在广告服务之间来回切换,以提取数据快照并将其组织到报告和仪表板中。通过 OWOX BI 和 BigQuery 实现这些过程的自动化消除了执行常规数据更新的麻烦,并确保您可以随时获得最新的数据。如果您的广告账户发生变化,OWOX BI 还会追溯性地刷新 Google BigQuery 中的成本数据。

永远不要失去对历史数据的控制

大多数营销平台都对你可以存储多少数据或可以访问这些数据多长时间有限制。有了 Google BigQuery,你可以将来自所有营销平台的数据保存任意长的时间,并对其进行分析,以捕捉不太明显的趋势,这些趋势只有在很长一段时间后才会变得可见。OWOX BI 可以用您的 ad 帐户中的历史数据填充您的 BigQuery 数据集,因此您可以立即开始工作。

进行全面的数据分析

使用 BigQuery 中的数据,您将能够创建原始数据中没有的定制指标和维度,创建任意参数组合,将定制过滤器应用于您的报告。

如果您不喜欢编写 SQL 查询,OWOX BI 可以满足您的需求。您可以使用 OWOX BI Smart Data 中的报告构建器,用自然英语询问您的数据问题,并根据您的数据以组织有序的报告形式获得答案,其中包含您需要的具体指标。

图片由作者提供

可视化数据

通过将 BigQuery 连接到您最喜欢的可视化工具,或者将您的报告导出到数据可视化服务,如 Google Data Studio ,来创建可操作的数据可视化。为此,您不必使用多个数据源:一个 BigQuery 连接器就足够了。

如何用 OWOX BI Pipeline 将广告数据上传到 Google BigQuery

要设置数据收集,您必须在要收集数据的项目中拥有 BigQuery 数据编辑器BigQuery 用户角色。一旦这些角色出现在您的项目中,请按照以下步骤将您的广告数据上传到 Google BigQuery:

  1. 在 OWOX BI 仪表板中,单击创建管道

图片由作者提供

2.选择要连接的数据源。

图片由作者提供

3.选择 Google BigQuery 作为目的地。

图片由作者提供

4.提供您广告帐户的访问权限。

5.提供对您想要存储导出数据的 Google BigQuery 帐户的访问。

6.选择一个 Google BigQuery 项目并创建一个想要上传数据的数据集(或者选择一个现有的数据集)。

7.指定标记要上载成本数据的期间的开始日期,并选择要将成本数据转换为的货币。

8.点击创建管道

搞定了。Google BigQuery 会自动收集数据,你可以从你选择的来源获得现成的完整数据。

最后的想法

在数据产生价值之前,需要对其进行收集、处理、分析并付诸行动。借助 Google BigQuery 和 OWOX BI,营销人员可以轻松摆脱手动任务和分散的电子表格,转向成熟的商业智能系统,在该系统中,您可以自动聚合来自多个接触点的数据,并将其转化为有价值的见解。

毕竟,您收集的数据的价值完全取决于您驾驭这些数据并从中做出决策的能力。

如何上传和嵌入交互式绘图可视化

原文:https://towardsdatascience.com/how-to-upload-and-embed-interactive-plotly-visualizations-f819d4ffecfb?source=collection_archive---------15-----------------------

Plotly 是一个很好的交互式数据可视化工具,但是它的 Chart-Studio 服务仅限于 500KB 的上传。

由作者创建

今年我分享了很多我用 Plotly 制作的互动情节。有一段时间,Plotly 的 chart-studio 服务对我来说是一个很好的解决方案,我可以上传我的绘图,以便我可以将它们嵌入到文章或演示文稿中。然而,Chart-Studio 在他们的自由层上有一个相当激进的 500KB 大小限制。除了昂贵的商业计划之外,chart-studio 没有一个透明的选项来支付更大的上传量。

我想一定有更好的方法来分享我制作的交互式网络地图,果然有!在这篇文章中,我将向你展示如何上传一个交互式 Plotly 地图到 Datapane,并将其嵌入到任何网站上。

图表工作室

看看下面描绘阿拉斯加积雪变化的图。我用 Matplotlib 和 Cartopy 创建了它,它们可以很好地将数据投影到底图上。然而,静态地图不允许查看者查看数据值或缩小以获取位置的上下文。此外,虽然像这样的动画地图很有趣,但我认为网络地图上的滑块可以让读者更好地了解随着时间的推移而发生的变化。

由作者创建

制作一个互动版本将意味着我不必在数据可见和观众了解我们在地球上的位置之间做出选择。当我为博客帖子等设置创建地图时,我喜欢使用交互式地图,因为我不会在那里解释背景信息。我倾向于用静态地图来展示,因为我可以向观众提供任何需要的背景。

我们可以很容易地使用 Plotly 重新创建这个交互的情节。但是,有很多数据点,远远超过了 500KB 的 Chart-Studio 限制。但是我们马上会处理这个问题。首先,下面是我用 Plotly 翻拍剧情的代码:

由作者创建

Plotly 剧情截图(作者创作)

下面是这段代码创建的一个屏幕截图。看起来很好!然而,当我使用 chart-studio 上传它时,我得到了以下错误:

import chart_studio.plotly as pypy.plot(fig, filename = 'swe_map_test', auto_open=True)

Plotly 图表工作室大小限制(由作者创建)

如果你有一个只有很少数据点的图,你也许可以摆脱 500KB 的限制。为了让我写的几篇文章的图表符合我的要求,我会随机挑选一些数据。然而,我最近发现了另一个工具 Datapane,它的空闲层有一个更高的大小限制。

数据面板

Datapane 是一种用于创建由数据帧、绘图和文件组成的报告的服务。您可以在 Python 中创建它们并将它们发布到 Datapane。他们还提供了一个免费层,比 Chart-Studio 有更高的上传大小限制。太棒了。

用 Datapane 创建报告非常有用,但是在这篇文章中,我们将重点介绍如何使用 Datapane 来嵌入用 Plotly 和 Altair 制作的交互式绘图。创建一个报告只需要几行代码。

首先,使用 pip 安装 Datapane:

pip3 install datapane

现在您可以创建一个 Datapane 帐户,并通过终端/命令提示符登录:

datapane login --token=[your_token]

现在我们都设置好了,我们可以继续发布我们的数字!

import datapane as dp report = dp.Report(dp.Plot(fig))
report.publish(name="SWE Study Area", open=True)

一旦您运行这个代码,一个新的窗口将会打开,您的绘图将会上传到 Datapane。我们可以通过粘贴“分享”按钮中的 URL 将情节直接嵌入到这篇文章中:

由作者创建

您可能需要进入设置,并将图“可见性”更改为“公共”。由于某些原因,在最新版本的 Datapane 上,在 Python 中设置可见性给我抛出了一个错误。

现在我们有了一个用 Plotly 构建的交互式网络地图,我们可以把它嵌入到任何地方。最棒的是,这个图比我能够通过 Chart-Studio 上传的要大得多,这意味着我可以开始上传更多的网络地图,而无需支付昂贵的订阅费。

在 GitHub 页面上托管

我尝试的 Chart-Studio 的第一个替代方案是用我的情节创建一个 GitHub Pages repo,并通过 iFrame 嵌入它。我在几个地方读到过这种方法,我真的很喜欢它,因为 GitHub Pages 的限制很少。然而,许多网站,比如我们目前所在的网站,不支持手动插入 iFrames。这意味着在 GitHub 页面上托管情节对我的用例不起作用,因为我不能将它们插入到我的文章中。不过,我将向您展示如何做到这一点,因为这是在您自己的网站上嵌入的一个很好的解决方案。

创建 HTML 文件

首先,我们需要使用 Plotly 来导出我们绘图的 HTML 文件。

import plotly.io as pio
pio.write_html(fig, file='index.html', auto_open=True)

这将使用生成的 HTML 文件在浏览器中打开绘图。

设置 GitHub 页面

使用 GitHub 页面托管您的绘图有三个步骤:

  1. 使用自述文件创建新的存储库
  2. 上传新的 HTML 文件
  3. 转到“设置”选项卡,向下导航到“页面”,在“源”下选择您的主/主分支

由作者创建

现在你可以去https://wino6687.github.io/swe_viz_1/看剧情,但是我不能把它放在这里。

包扎

希望这能帮助你找到一个免费的 Chart-Studio 的替代品,它没有 500KB 的上传限制。Datapane 使嵌入图变得非常简单,并且它们与许多网站接口良好。

资源

如何从脸书上传数据到谷歌大查询

原文:https://towardsdatascience.com/how-to-upload-data-from-facebook-to-google-bigquery-fd4640957fe5?source=collection_archive---------33-----------------------

来源:沉积照片

在脸书广告档案和网络分析系统中,你可以分析广告表现的基础。对于广告渠道少的小企业来说,这就足够了。

脸书是全球最受欢迎的社交网络,每月活跃用户超过 26 亿。毫不奇怪,它已经成为许多商家的强制性促销渠道。超过 700 万的广告客户在这个平台上推广他们的服务。此外,脸书拥有另外三个最大的社交媒体平台 : Instagram、WhatsApp 和 Facebook Messenger。

脸书和 Instagram 在广告商中受欢迎的另一个原因是接触受众的低价格和准确锁定受众的能力。

脸书收集什么数据

脸书为企业和营销人员提供广告宣传工具:脸书广告经理、脸书像素和脸书分析。

默认情况下,广告管理器提供关于覆盖范围、浏览量、点击量、广告成本等信息。如果你在网站上安装了脸书 pixel,并设置了事件跟踪功能,你就可以通过点击广告来了解用户的行为。

你可以在任何设备上跟踪你的广告给你的网站带来的所有类型的转换,并查看你想要的行为花费了多少。脸书报告显示你所有的点击,注册,订单,购买等。

存储在脸书广告档案中的数据只能告诉你一个来源的有效性。但是,如果一个用户从有机流量中找到你,然后回到你的网站,点击脸书上的链接,并在收到电子邮件后进行购买,会怎么样呢?在这种情况下,你如何评价脸书渠道的有效性?在整合数据之前,您不会知道它如何与其他营销来源交互,以及它们如何影响整体业务。

在大公司,营销不仅限于脸书,销售可以在线上和线下进行。因此,有必要将脸书广告管理器的数据与您的网站、其他广告服务和您的 CRM 的数据结合起来,这样您就可以看到全貌:在广告上花了多少钱,哪些广告渠道更有效,以及财务结果。

为什么要在谷歌大查询中收集脸书的数据?

通过将广告服务的成本数据上传到 Google BigQuery,您可以将成本与网站上的用户活动、呼叫中心的呼叫、电子邮件以及 CRM 系统中的购买订单相关联。这有助于您建立高级分析并评估所有在线和离线营销活动对业务绩效的影响。

上传到谷歌 BigQuery 的营销服务数据可以用于计算你的归因模型,然后 BigQuery 可以将结果传递给系统进行自动投标管理。此外,在谷歌大查询中,你可以根据综合数据和属性计算的结果创建用户受众,然后自动将这些受众发送给广告服务。最后,您可以使用 BigQuery 中收集的数据来构建任何您需要的报告而不受限制。

为什么谷歌大查询而不是其他云存储?

最受欢迎的云平台是亚马逊红移、谷歌 BigQuery 和微软 Azure。与传统的数据仓库相比,它们具有共同的优势:

  • 当负载增加时,您不需要维护服务器和连接新的服务器。云存储会自动扩展。
  • 云平台比传统存储更快,并自动重新分配负载。
  • 进入云存储不需要在电脑上安装服务器。只需打开浏览器,登录云端。

我们选择 Google BigQuery 并推荐给我们的客户,原因如下:

  • 谷歌是营销人员数据来源数量的领导者:广告、分析、搜索控制台、YouTube。所有这些服务都与 BigQuery 无缝集成。
  • 它能快速处理大量数据。
  • 不需要数据库管理员的帮助,很容易上手 BigQuery。只需创建一个谷歌云帐户。
  • 您只需为您使用的服务付费。
  • 有现成的服务和解决方案可以在不需要开发者帮助的情况下将数据上传到 Google BigQuery。

如何将脸书的数据导入 Google BigQuery

谷歌 BigQuery 没有内置的从脸书广告管理器导入数据的工具。有几种方法可以解决这个问题:手动上传数据,编写自己的脚本,或者使用 OWOX BI 之类的专门服务。让我们仔细看看这些选项。

手动导入数据或使用您自己的解决方案

您可以将脸书广告资料中的成本数据上传到单独的文件中,并通过 BigQuery 界面手动上传。这种方法的缺点是显而易见的:大量不必要的工作,没有自动化。

您还可以编写脚本,从营销服务中上传您需要的数据。然而,您需要不断地监控和支持这些脚本。你还必须花费开发人员的资源来组合来自不同账户和不同日期的数据,检查数据质量,并快速响应广告服务 API 的可能变化。此外,如果脸书广告中的数据发生变化,您需要追溯更新数据,将所有广告来源的成本转换为单一货币,等等。如果你不做这些事情,低质量的数据会导致次优的解决方案,让你的企业损失惨重。

使用谷歌分析将成本数据收集到谷歌 BigQuery 中

使用 OWOX BI,您可以设置从不同广告服务向 Google Analytics 自动导入成本数据,并将成本数据上传到云存储中。如果你使用这种方法,考虑一下谷歌分析的限制:

  • 每天最多可将 90 MB 加载到单个数据集中。
  • 每个资源每天最多可以下载 50 个文件。
  • Google Analytics 可能需要 24 小时来处理上传的数据,并使其在报告中可用。
  • 当上传大量数据时,Google Analytics API 可能会出现问题。
  • 您上传的参数不能超过 Google Analytics 的成本数据集模式所能包含的参数。

将广告服务的费用直接导入 Google BigQuery

OWOX BI 拥有来自脸书InstagramLinkedIn 的直接数据流,你可以通过它将所有活动的原始数据上传到 BigQuery。这些数据方案包含 80 到 200 个参数,这确保了您报告的高粒度数据。

脸书与谷歌 BigQuery 的直接整合有什么好处?

OWOX BI 提供了开箱即用的完整解决方案,您不需要手动做任何事情。该服务以方便的格式收集您需要的所有数据,并监控其质量和相关性。

如果脸书广告中的历史数据发生变化,OWOX BI 会自动更新上传到 BigQuery 的数据。此外,如果有必要,您可以上传您最近六个月的历史数据。这将有助于您评估活动动态。

由于成本数据的导入没有 Google Analytics 的参与:

  1. 你可以更快地获得数据:费用被直接上传到 BigQuery,你不必再等 24 小时让 Google Analytics 来处理。
  2. 数据下载没有谷歌分析限制 90 MB 和每天 50 次下载
  3. 创建流时,只需指定相同的数据集,就可以将多个 ad 帐户的统计数据下载到单个 BigQuery 表中。
  4. 来自广告源的数据被编译成 Google BigQuery 中的一方表。这极大地简化了查询的编译和下载数据的分析。
  5. 成本数据以两种货币上传到 BigQuery。一个字段存储广告服务的原始货币成本。创建流程时,您可以指定将成本数据转换为的另一种货币。转换成本对于必须将不同来源的数据转换为单一货币的报表很有帮助。

如何使用 OWOX BI 设置从脸书广告到 Google BigQuery 的成本数据导入

  1. 确保你的广告链接有 UTM 标签。
  2. OWOX BI 主页上,点击创建管道:

图片由作者提供

3.作为来源,选择脸书广告:

图片由作者提供

4.作为目的地,选择 Google BigQuery :

图片由作者提供

如果你在 Google BigQuery 中没有项目, 学习如何开始使用云存储并创建数据集

5.选择要从中导出广告费用数据的脸书帐户(或授予对新脸书帐户的访问权限):

图片由作者提供

在任何情况下,OWOX BI 都不会更改您的帐户设置或广告活动!

对于大多数广告平台,OWOX BI 仅请求访问以读取数据。这个访问级别足以让我们获得广告中链接标记的统计数据和信息。但并不是所有的广告服务都有我们期望的这种访问或工作水平。比如使用 OWOX BI 将脸书的原始数据导入 Google BigQuery,需要 ads_management 权限

图片由作者提供

6.选择一个已连接的帐户或授予对您要存储导出数据的 Google BigQuery 帐户的访问权限:

图片由作者提供

7.选择一个 Google BigQuery 项目和一个要上传数据的数据集(或创建一个新的数据集):

图片由作者提供

注意! 要设置数据收集,您的 Google 帐户必须被授予目标项目的 BigQuery 数据编辑 BigQuery 用户 角色。否则,BigQuery 不会让您上传数据。

图片由作者提供

要检查/授予这些权限,请转到您的 Google 云平台项目中的 身份和访问管理 页面。更多阅读 谷歌文档

8.指定管道的设置:

图片由作者提供

  • 选择要上传成本数据的起始日期。您可以设置未来或过去的日期。如果您选择过去的日期,请了解历史数据导入的限制。
  • 选择默认情况下要应用于导入数据的源/媒体。只有当 OWOX BI 没有接收到实际的 UTM 参数值时,您为 UTM 源/通道指定的默认值才会被写入成本数据表。关于为什么要在管道设置中为 UTM 源/通道指定默认值的更多信息,参见帮助

重要!您可以随时将 pipeline 页面上的源/介质设置更改为除 google/organic 之外的任何值。指定的值将应用于修改后导入的新数据和更新窗口内的历史数据。

图片由作者提供

9.点击创建管道

搞定了。前一天的数据将在每天 00:00 (UTC)出现在指定数据集中的表中。根据数据量和广告服务 API 的功能,导入数据可能需要 24 小时。表的结构见本条

如果广告服务中的信息发生追溯性变化,OWOX BI 将在已建立的更新窗口内更新上传到 BigQuery 的所有数据。

关键要点

在脸书广告档案和网络分析系统中,你可以分析广告表现的基础。例如,您可以分析 CTR、CPC、CPA、CR、会话、观看深度、跳出率、RPC 和 ROAS。对于广告渠道少的小企业来说,这就足够了。

然而,如果您与客户有许多接触点,有线下商店,并希望看到完整的购买路径,那么您应该考虑设置高级分析并创建一个自动更新的仪表板,其中包含您感兴趣的所有指标。这将使您随时掌握最新信息,对广告效果进行全面评估,并更快地做出重要决策。

如何使用 Python 向 Google BigQuery 上传数据:3 个步骤

原文:https://towardsdatascience.com/how-to-upload-data-to-google-bigquery-using-python-in-3-steps-7138ae625fe3?source=collection_archive---------2-----------------------

在 Google 的云数据仓库中自动更新 API 数据

图片由像素上的 Anete Lusina 拍摄

Google BigQuery 是一个快速、可扩展的数据存储解决方案,可以轻松地与 Power BI 和 Tableau 等一些顶级数据科学应用程序集成。如果你以前用过 BigQuery,你可能知道它有很多特性。比如,很多功能。这对于新用户来说肯定是令人生畏的,但是如果你坚持下去,你会从这个平台中得到很多有用的东西!

我经常使用 BigQuery 的一个功能是上传数据,以便与其他应用程序共享和集成。与反复编辑和上传 CSV 文件相比,您会发现将一个功能链接到所有应用程序要容易得多!在本文中,我将向您展示如何从 API 中获取数据,并使其易于在各种平台和应用程序之间共享和访问。这应该适用于任何 API,只要您能够输出 pandas 数据帧。

第一步:创建云函数

登录您的帐户后,您要做的第一件事就是转到右上角的“控制台”部分。如果你还没有一个项目,那就按照你的喜好来设置吧。进入控制台后,进入右上角的导航菜单,向下滚动到“云功能”

作者谷歌大查询截图

您需要启用计费来使用此功能,但根据您需要的数据量,此功能不会很贵。云函数可以使用各种语言来做几乎任何事情,从简单的 API 调用到机器学习,所以非常值得!

一旦你进入云函数,点击“创建函数”按钮。名称和区域可以是您喜欢的任何名称,对于触发器类型,我通常将它保存在 HTTP。然后,对于运行时设置,我更喜欢将我的超时设置为最大值 540 秒,内存分配和最大实例数由您决定,但这是我通常使用的:

作者 Google BigQuery 截图

然后点击“保存”和“下一步”,你就可以添加你的自定义 API 了。在您将代码复制并粘贴到 Google 的 IDE 之前,您必须添加一些特定于 BigQuery 的函数。幸运的是,我已经得到了你在第二步中需要的一切!

第二步:添加 BigQuery 特定函数

这些 BigQuery 函数的结构看起来有点复杂,但简单来说,它看起来像这样:

  • 功能 1:验证 HTTP 响应
  • 功能 2:您的自定义 API 拉
  • 功能 3:将数据帧加载到 BigQuery 表中

那么在 python 中这看起来像什么呢?大概是这样的:

如果您已经编写了一个 API 拉脚本,那么您可以将它粘贴到 get_all_data()函数中,然后将整个脚本复制并粘贴到您的 BigQuery 云函数中。就这么简单!在尝试在云中运行 API 调用之前,只需确保它在本地运行即可。

在部署函数之前,要做的最后几件事是确保“入口点”是第一个函数 validate_http,并确保您拥有正在使用的任何库的所有正确的依赖项。这个例子看起来是这样的:

作者提供的谷歌大查询截图

最后,您可以部署您的功能!在您点击部署后,它将运行几秒钟,如果您看到一个绿色的勾号,这意味着您做得对。

第三步:测试并刷新你的表

有很多方法可以让你的新表显示数据,我认为最简单的方法是点击你的云函数,点击“测试”,然后“测试函数”。这将创建一个 BigQuery 表,其中应该包含来自 API pull 的所有数据!要查看该表,只需进入左上角的主菜单,向下滚动到“BigQuery”

作者提供的谷歌大查询截图

在这里,您可以查看数据的模式,查看数据的更新时间,并预览数据集的外观。就这样,您将数据存储在 BigQuery 中!现在你可以将这些数据链接到 Tableau、Google Data Studio、Power BI 或任何最适合你的应用程序。能够从任何地方访问这些数据并将其链接到多个应用程序是非常值得的,您甚至可以通过使用 BigQuery 的“云调度程序”来自动化这个过程。这也可以在主菜单中找到,向下滚动直到看到以下内容:

作者谷歌大查询截图

在这里,您可以决定您希望数据刷新的频率,BigQuery 将自动处理测试过程。这就让你少担心一步了!

最终想法

如果你曾经考虑过使用云数据存储解决方案,我肯定会推荐你使用 Google BigQuery!一开始可能会有很多,但是我认为如果你按照本文中的步骤去做,你应该能够适应它的一些特性。我希望这篇文章能够帮助您更好地理解 BigQuery 以及如何将您的数据上传到云中。非常感谢你的阅读,我希望你有一个伟大的一天!

跟我来!——【https://bench-5.medium.com/】T2

通过使用此链接升级您的中级会员来支持我:https://bench-5.medium.com/membership

如何使用 Airflow 将文件上传到 Google Drive

原文:https://towardsdatascience.com/how-to-upload-files-to-google-drive-using-airflow-73d961bbd22?source=collection_archive---------10-----------------------

开发自定义 GoogleDriveOperator

一个可以自动化的常见有用操作是将文档定期上传到 Google Drive 文件夹。例如,这可以是每月上传一次销售数据的 Excel 分析,以便与团队共享。

Airflow provider package apache-airflow-providers-google提供了允许与 GCP 上的谷歌服务轻松集成的组件。但是,它没有直接提供一个操作者直接上传一个本地文件到 Google Drive。这就是为什么在本文中,我们将学习如何构建我们自己的气流操作符来实现这一点。

我们将分四个连续的步骤来完成这项工作:

  1. 在 GCP 上配置 Google Drive API 和创建服务帐户
  2. 在我们的 Google Workspace 上配置全域委托
  3. 为我们的自定义 GoogleDriveOperator 编写代码
  4. 测试一个最小的 DAG 上传一个文本文件到我们的 Google Drive 账户

按照这些步骤,我们需要:

  • 一个对 GCP 和它所属的谷歌工作区有管理权限的谷歌帐户
  • 气流 2.0.x 安装

我在 Docker 上创建了一个公共 GitHub repo 和一个 Airflow 安装以及本文中的所有代码。克隆项目并用docker-compose run启动它。

1.在 GCP 上配置 Google Drive API 和创建服务帐户

Airflow 通过 Google 云平台上的 Google Drive API 将文件上传到 Google Drive。

转到https://cloud.google.com/并点击控制台。接受条件。迎接我们的是下面的仪表板(可能会因您的组织而有所不同)。

创建新的 GCP 项目

我们将创建一个新的 GCP 项目致力于这一功能。点击选择一个项目,然后点击新建项目。姑且称之为“气流驱动”。选择项目,使名称显示在顶部栏中。

启用 Google Drive API

既然项目已经设置好了,我们可以启用 Google Drive API 了。在页面顶部的搜索栏中搜索“Google Drive API”并选择第一个搜索结果。

点击启用启用 Google Drive API。

创建服务帐户

Airflow 将使用一个 Google 服务帐户来验证 Google Drive API。服务帐户是一种特殊类型的 Google 帐户,代表非人类用户。

从菜单进入API&服务并选择服务账户

目前此项目中没有服务帐户。点击创建服务账户创建一个。

让我们将服务帐户命名为与项目“气流驱动”相同的名称。

授予服务帐户此项目的所有者角色。

点击完成。服务帐户现在可见。

现在我们有了服务帐户,我们创建一个包含其凭证的 keyfile JSON。Airflow 将使用这些凭证来验证 Google Drive API。转到选项卡,点击添加键。选择创建新密钥并选择 JSON 格式。

如果您正在使用提供的 GitHub repo ,请将 JSON 密钥文件保存在docker/目录中。确保将它的路径添加到。gitignore 这样你就不会不小心把你的 keyfile 推给 GitHub 了。不要与任何人共享此密钥!

启用全域性委派

全域委托允许一个服务帐户在 Google Workspace 内代表另一个用户执行操作。这很重要,因为由服务帐户创建或上传的文件对于其他用户来说是不可见的。通过为我们的服务帐户启用域范围的委托,我们将能够以我们自己的 Google 帐户的名义上传文件,以便可以直接访问上传的文件。

转到菜单中的服务账户并点击服务账户的电子邮件。这将打开一个页面,显示服务帐户的唯一 ID。请记下这个数字,因为我们在配置 Google Workspace 时会用到它。

展开“全域委托”下的部分。选中显示启用 G Suite 全域委托的复选框。我们可以输入“airflow.to.drive”作为同意屏幕的产品名称。这个名称并不重要,因为我们不会使用这个特性。点击保存

GCP 配置现在完成了!

2.在我们的 Google Workspace 上配置全域委托

接下来,我们必须通过我们的 Google Workspace 为服务帐户授权域范围的委托。前往https://myaccount.google.com/。点击右上角的管理控制台

转到安全,然后转到设置

在列表底部,打开 API 控件部分。

找到关于全域授权的部分,并点击管理全域授权

目前,没有条目。点击添加新的

填写我们在上一部分中记录的服务帐户的唯一客户端 ID,并添加以下范围:https://www.googleapis.com/auth/drive。这将授予具有该特定客户端 ID 的服务帐户对 Google Drive 的完全访问权限。点击授权

服务帐户现在被授权以 Google Workspace 中任何用户的名义将文件上传到 Google Drive。

Google Workspace 现在已经配置好了!

3.为我们的自定义 GoogleDriveOperator 编写代码

在这一部分中,我们将查看自定义气流操作符的 Python 代码。

像所有气流操作符一样,我们的 GoogleDriveOperator 继承自气流 BaseOperator 类。上传本身是由apache-airflow-providers-google包提供的 GoogleDriveHook 执行的。操作符接受我们想要上传的本地文件的路径、Google Drive 上的目标文件夹以及 GoogleDriveHook 所需的一些参数。如果参数delete设置为True,上传成功后本地文件被删除。将该文件放在plugins/文件夹中,以便它可以很容易地导入 DAG 模块。

示例 DAG

现在一切都设置好了,我们可以测试 GoogleDriveOperator 并将一些文件上传到我们的个人 Google Drive。

让我们编写一个包含两个任务的最小每日 DAG:

  1. 使用 BashOperator 在$AIRFLOW_HOMEtmp/文件夹中创建一个包含当前日期的文本文件
  2. 使用 GoogleDriveOperator 将此文件上传到 Google Drive 上的指定文件夹

此 DAG 将从 2021 年 2 月 10 日到 2021 年 2 月 13 日每天执行。每天都用内容file created on 2021-02-10创建一个文件,例如my_file_2021-02-10.txt。然后,这个文件被上传到我们谷歌账户的根目录下的文件夹google-drive-operator。请注意,delegate_to参数指定了服务帐户将上传委托给的电子邮件地址。该 Google 帐户将成为上传文件的所有者。

创建气流连接

还有最后一件事要做:我们必须创建由任务upload_file中的gcp_conn_id指定的气流连接。启动 Airflow 网络服务器,并转到管理选项卡。打开连接,用以下字段创建一个新连接:

  • 连接标识:gcp_conn_id
  • 连接类型:谷歌云
  • Keyfile 路径: /opt/airflow/ < <您的 JSON keyfile 名称> > >。json ( 或者,我们可以将这个 JSON keyfile 的内容粘贴到 Keyfile JSON 字段中)
  • 项目 Id:驱动气流
  • 范围:https://www.googleapis.com/auth/drive

运行 DAG

返回到DAG部分并激活 DAG。

执行之后,可以在我们的 Google Drive 文件夹中看到文本文件。

注意,由于域范围的委托,文件的所有者是“我”。如果google-drive-operator是一个共享文件夹,任何被授权的人都可以访问这些文件。

我希望你喜欢我这篇关于气流和 Google Drive 的文章。欢迎在评论中分享任何有趣的用例或问题!

米海·苏尔杜Unsplash 上的照片

如何将 Python 包上传到 PyPI

原文:https://towardsdatascience.com/how-to-upload-your-python-package-to-pypi-de1b363a1b3?source=collection_archive---------2-----------------------

让您的 Python 包在 pip 上可用的分步指南

凯利·西克玛Unsplash 上拍摄

您编写了一个新的 Python 包,解决了一个特定的问题,现在是时候与更广泛的 Python 社区分享它了。为此,您需要将包上传到一个中央存储库,全球的开发人员都可以访问这个存储库。

在今天的文章中,我们将讨论 PyPI 如何让开发人员与其他希望在自己的应用程序中使用特定功能的人共享包。此外,我们将介绍一个分步指南,帮助您在 PyPi 上上传 Python 包,以便每个 Python 用户都可以使用它。我将使用一个真实的端到端示例,这样所有步骤都非常清楚。

什么是 PyPI

Python 包索引 缩写为 PyPI,是 Python 编程语言的官方软件库。默认情况下,pip——最流行的 Python 包管理器——使用 PyPI 作为检索包依赖关系的源。

PyPI 允许您查找、安装甚至发布您的 Python 包,以便公众可以广泛使用它们。超过 300,000 个不同的软件包目前发布在索引中,超过 2,500,000 个版本分发给用户。

如何让您的 Python 包在 PyPi 上可用

在下一节中,我们将探索在 PyPI 上发布 Python 包并使其在pip可用所需遵循的步骤。

步骤 1:确保您已经安装了 pip

如果你使用的是 Python 2 ≥ 2.7.9 或者 Python 3 ≥ 3.4 pip应该已经安装了。但是,如果出于任何原因您可能需要安装它,只需运行下面的命令(说明适用于 Unix):

curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py

就是这样!您可以确保pip现在安装如下。

**$** python -m pip --version
pip X.Y.Z from .../site-packages/pip (python X.Y)

步骤 3:打包您的 Python 代码

我在 GitHub 上创建了一个示例项目,这样可以更容易地演示如何在 PyPI 上发布自己的包。这个项目可以在这个链接上找到——通常你至少需要创建以下文件:

  • **README.rst**:强烈推荐包含一个 README 文件,您应该在其中概述您的软件包所提供的基本功能。此外,您还可以附上安装说明或使用指南。

  • **LICENSE.txt**:最好在您打算广泛使用的包中包含一个许可证。有关更多选项和细节,请参考 GitHub 文档的许可存储库部分。

  • **setup.py** : 这个文件应该放在你的项目结构的顶层目录中。在该文件中,您可以为 Python 项目指定配置。更多详情可参考官方文档。我们的示例项目的setup.py文件可以在 GitHub 上找到,并且与下面显示的文件相同。

  • **setup.cfg**:该文件包含setup.py命令的默认选项。

我们的示例项目的整体结构如下所示

.
├── LICENSE.txt
├── README.rst
├── setup.cfg
├── setup.py
├── src
│   ├── example_publish_pypi_medium
│   │   ├── __init__.py
│   │   └── example
│   │       ├── __init__.py
│   │       └── custom_sklearn.py
├── tests
│   ├── __init__.py
│   └── example
│       ├── __init__.py
│       └── test_custom_sklearn.py

现在我们只需要在 PyPI 上发布我们的包,这样其他用户就可以在他们的本地机器上安装它。注意,我们的示例包依赖于scikit-learn,这种依赖性在setup.py文件中被明确指定。因此,当用户使用pip安装您的包时,指定的依赖项也将被安装。

步骤 3:创建包的源代码发行版

既然我们的源代码是结构化的,并且包含了打包所需的所有文件,我们就可以继续创建源代码发行版了。

源代码发行版—通常称为 sdist —是包含setup.py文件以及源代码和数据文件(如setup.py和/或setup.cfg中所指定)的发行版

您可以通过运行下面给出的命令来创建包的源代码分发:

python setup.py sdist

如果一切按计划进行,应该在新创建的目录dist下创建一个.tar.gz文件。在我的例子中setuptools也增加了一个MANIFEST文件。

注意:如果您碰巧收到类似于以下内容的警告

Unknown distribution option: 'install_requires'

你可以暂时忽略它。

步骤 4:安装麻绳

[twine](https://pypi.org/project/twine/#:~:text=Twine%20is%20a%20utility%20for,and%20links%20to%20additional%20resources.)是一个实用程序包,用于在 PyPI 上发布 Python 包。

pip install twine

步骤 5:创建一个 PyPI 帐户

为了在 PyPI 上发布一个包,你必须创建一个帐户。你可以通过访问这个链接来实现。这是完全免费的,注册时你只需要提供你的电子邮件地址、用户名和密码。

步骤 6:在 PyPI 上上传源代码发行版

最后,我们现在将使用twine来上传在 PyPI 上创建的源代码发行版。

twine upload dist/*

系统将提示您输入用户名和密码,您的包将最终在 PyPI 上可用:

twine upload dist/*
Uploading distributions to [https://upload.pypi.org/legacy/](https://upload.pypi.org/legacy/)
Enter your username: YOUR_USER_NAME
Enter your password: YOUR_PASSWORD
Uploading example_publish_pypi_medium-0.6.tar.gz
100%|██████████████████████████████████████████████████████████████| 3.49k/3.49k [00:01<00:00, 2.17kB/s]View at:
[https://pypi.org/project/example-publish-pypi-medium/0.6/](https://pypi.org/project/example-publish-pypi/0.1/)

瞧啊。我们的示例包现在可以在 PyPI 上获得。

使用 pip 安装已发布的包

现在让我们验证我们的包是否如预期的那样工作。

我们的示例项目现在可以在 PyPi 上获得,并且可以通过 pip 安装

正如我们已经提到的,pip的默认源索引是 PyPI。所以我们的包可以直接从pip安装。为此,请运行

pip install example-publish-pypi-medium==0.6

该软件包应该成功安装在您的本地计算机上。如果您检查输出,您还会看到scikit-learn也被安装,因为它是一个依赖项,我们在打包源代码时也指定了它。

最后,我们可以验证该包是否按预期工作:

$ python3
>>> from example_publish_pypi_medium.example import custom_sklearn>>> custom_sklearn.get_sklearn_version()
'0.24.1'

最后的想法

了解如何分发 Python 包并使其广泛可用是很重要的。在今天的文章中,我们讨论了 PyPI 如何被用作包含 Python 包的中央存储库。此外,我们还看到了如何将您自己的 Python 包打包并发布到 PyPI,以便它可以被广泛使用。

但是请注意,强烈建议使用 TestPyPI ,它是原始索引的一个单独的测试实例,允许用户在不影响实际索引的情况下尝试分发工具和流程。一旦您验证了所有的行为都符合预期,那么您就可以使用我们之前研究过的命令将它发布到真正的 PyPI。

你可能也喜欢

https://betterprogramming.pub/11-python-one-liners-for-everyday-programming-f346a0a73f39

如何在量子贝叶斯网络中使用多元分布

原文:https://towardsdatascience.com/how-to-use-a-multinoulli-distribution-in-a-quantum-bayesian-network-d13807841d23?source=collection_archive---------40-----------------------

量子机器学习实用指南

量子机器学习要不要入门?看看 动手量子机器学习用 Python

今天,我们将阐明一个重要的宏观经济问题。“备考会带来更高的就业率吗?”

上学的时候,我一直宁愿打文明也不愿意备考。所以,我会说不。但是我们为什么不更严谨地看待我的信仰呢?让我们来模拟我的信念。完成这项工作的最佳工具是贝叶斯网络。

但是我们为什么不给这个任务增加一点乐趣呢?我们为什么不建立一个量子贝叶斯网络 (QBN)?

“又来了!”你喊?好吧,很公平。我看到你看了我以前的帖子,你已经熟悉 QBNs 了。所以,我们来增加一个挑战。在上周的帖子中,我们了解了量子多内核分布。所以,如果我们把它作为我们 QBN 的一部分不是很好吗?

那么,我们开始吧。

下图描绘了我们今天要建造的 QBN 的结构和 CPT。CPT(条件概率表)包含了 QBN 中变量之间的所有条件依赖关系。因为这些数字都是我编的,所以它们代表了我的信仰。我不是说过我们要塑造我的信仰吗?

作者图片

我们在这里看到了什么?我相信 80%的学生都在准备考试。所以,我是剩下的 20%没有准备的人之一。这个概率分布构成了我们称之为“准备”的变量这是一个有两种可能结果的变量。因此,CPT 有两行。此外,因为 preparation 没有任何父变量,所以我们只有一列值。

这没什么大不了的。我们已经研究过这样的伯努利分布。所以,让我们继续下面的变量——“等级”这是一个有四种可能结果的变量。因此,它在 CPT 中有四行。因为我们有两个可能的输入,所以有两列。这些是从“A”(最好)到“D”(最差)的等级。

我相信,准备考试的学生比那些没有准备的学生取得不同的(更好的)成绩——很可能。但是,当然,你总会看到准备充分的学生不及格(得了个“D”)。你会看到这些幸运儿取得了好成绩,尽管他们没有花下午的时间学习。有时候,我是那些幸运儿之一。

对于“准备”的每一个可能的结果,CPT 告诉我们得到特定分数的可能性。因为我们有四个等级,我们需要八个概率。

最后,我相信成绩影响一个人是否找到工作。不过,我在这里没有提到薪水。但是,让我们假设 90%的 A 级学生找到了工作,80%的 B 级学生找到了工作,只有 30%的 D 级学生找到了工作。

因为这个变量有两种可能的结果,CPT 有两行。但是为了说明其父变量(等级)的四种可能结果,我们需要四列。所以,这张表也需要八个概率。

现在简单的问题是:“这个人群的就业率是多少?

我们从导入将要使用的库开始。我们定义了一个便利函数,它将给定的概率转换成一个量子位旋转角度。详情请看这篇文章

下一步,我们定义 CPT 的值。对于那些只有两种可能结果(准备和就业)的变量,我们只需要存储一个概率,因为相应的另一个结果的概率是 1。

注释,如 00,表示我们打算分配这些概率的量子态。我们很快就会看到这一点。事先,我们定义了一个量子电路,它有一个量子寄存器和四个量子位。

创建 QBN 时,从父变量开始总是一个好主意。在我们的情况下,这是准备。我们使用 prob_to_angle 函数来指定旋转角度,该角度表示准备就绪的边际概率。R_Y 门相应地旋转量子位,以 0.8 的概率将该量子位测量为 1。

接下来,正如我们在上一篇关于多元分布的文章中了解到的,我们计算了做好准备并获得“C”或“D”等级的概率。

我们将相应的旋转应用于位置 2 的量子位(第三个量子位)。因此,如果学生的等级为 C 或 d,我们说这个量子位为 1。当你再次查找概率的定义时,你会看到这些等级在第一个位置共享值 1(10 或 1 1)。在我们的QuantumRegister中,我们保留了位置 1 和 2(范围从 0 到 3!)为 Multinoulli 变量。所以,只有当位置 0 代表准备的量子位是 1 时,我们将位置 2 的量子位旋转一个角度,这个角度定义了等级 C 或 d 的概率。

接下来,我们要把这个概率分成 C 和 D 两个值。为此,我们将位置 1 处的量子位旋转一个角度,该角度代表给定 C 或 D 的可能性的等级 C 的概率。但是,我们仅在位置 0(准备)和位置 2 (C 或 D)处的量子位为 1 时旋转量子位。

mcry(多控\(R_Y\) gate)为我们完成了这个任务。我们使用位置 0 和 2 的量子位作为控制量子位(它必须是 1 ),以便 gate 应用。我们使用位置 1 的量子位作为目标量子位。

如果学生有所准备,我们对 A 和 B 年级也做类似的事情。主要的区别是,我们将这部分封装到\(NOT\) ( qc.x)门,我们在位置 2 应用量子位。这实质上“选择”了学生成绩不是 C 或 D 的情况。因此,它必须是 A 或 B。而且,由于我们已经将 C 和 D 与 A 和 B 分开,我们不必在这里再次这样做。

这就是我们为那些备考的同学所做的一切。现在,让我们转向那些没有的人。这一次,我们使用非门来“选择”没有准备好的学生。代码的其余部分与我们为准备好的学生所做的类似。我们先把 C 和 D 的成绩从 A 和 b 中分离出来,然后,我们把 C 从 D 中分离出来,A 从 b 中分离出来,最后,我们再次取消选择没有准备好的学生。

最后,我们必须具体说明在给定特定分数的情况下被雇用的概率。在这一点上,我们不再关心学生是否准备好了。这是因为,在我们 QBN,准备对就业没有直接影响。

我们分别选择每个等级,并旋转代表就业的量子位(位置 3 的量子位)。由于如果学生有 D 级,两个控制量子位(位置 1 和 2)都是 1,默认选择这个状态,我们可以直接应用多控\(R_Y\) gate。

为了选择 C 级,我们必须将\(NOT\) gate 应用于量子位 1,因为这个量子位的值区分了学生是得到 C 还是 d。

相应地,我们将\(NOT\) gate 应用于量子位 2 来选择 B 级。最后,我们对量子位 1 和 2 应用\(NOT\) gates 来选择 A 等级。

这就完成了我们的 QBN。我们准备好运行它了。首先,我们使用 statevector_simulator 后端来计算所有状态的概率。

我们可以看到每个状态的概率。例如,状态 1011 具有 0.256 的最高概率。在这种状态下,学生是有准备的,因为位置 0 的量子位是 1 (101 1 )。并且,如位置 1 和 2 的量子位所示(1 01 1),该学生得到了 B 的成绩。这些学生也得到一份工作,如位置 4 的量子位所示( 1 011)。

作者图片

我们可以很容易地计算出被雇用的总概率,方法是将位置 4 的值为 1 的所有状态相加。但是相反,我们用量子电路凭经验完成这项工作。

我们使用只考虑我们测量的量子位的qasm_simulator。因此,我们必须添加一个包含常规位的ClassicalRegister。一位就足以衡量就业情况。

当我们按照 shots 参数中的指定运行电路 1000 次时,我们将得到以下结果。

作者图片

如果 80%的学生准备考试,70%的学生会找到工作。如果只有 20%的学生准备怎么办?

我们可以为变量指定相应的值,然后重新运行电路。

结果显示,尽管只有 20%的学生为考试做了准备,但仍有 58%的学生找到了工作。

作者图片

那么,我们从这一切中学到了什么?最重要的教训是,我不是职业顾问。所以,请完全忽略你可能从结果中得出的关于准备考试是否值得努力的任何结论。

其次,我们学习了如何在我们的 QBN 中使用多内核分布。尽管它只有四个可能的值,但构建它比使用伯努利分布要花费更多的精力。当然,我们可以稍微简化一下代码。准备网络并不太复杂。实际上,主要的问题将是在你的 QBN 中得到你需要的所有概率。

但这是贝叶斯网络成为如此伟大工具的一个方面。它们明确了你对某个特定领域的所有信念。因此,每当你面临生活中的重要决定时,你可以创建一个(Q)BN 来验证你的信念并观察结果。只要记住结果代表你的信念。这些可能是错误的。

量子机器学习要不要入门?看看 动手量子机器学习用 Python

免费获取前三章这里

如何在 Tensorflow 2.x 中使用已保存的模型

原文:https://towardsdatascience.com/how-to-use-a-saved-model-in-tensorflow-2-x-1fd76d491e69?source=collection_archive---------16-----------------------

关于保存和重用 Tensorflow 训练模型的教程

作者使用 wordart.com 生成的图像

在我之前的文章中,我写了关于使用 TensorFlow 2.x 的模型验证、正则化和回调。在机器学习管道中,创建一个经过训练的模型是不够的。一旦我们完成了训练、验证和测试,并保留了一部分数据,我们将如何处理训练好的模型呢?在实践中,我们希望导入这样一个经过训练的模型,以便它可以在一些实际应用中有用。例如,假设我在相机图像上训练了一个模型来识别行人。最终,我想使用训练好的模型,通过安装在自动驾驶汽车上的摄像头,对检测行人进行实时预测。此外,训练模型还需要将模型保存为检查点,特别是当您在非常大的数据集上训练模型或者训练时间大约为几个小时时。如果您的训练由于某些原因而中断,比如您的编程逻辑中的缺陷、您的笔记本电脑的电池没电、存在 I/O 错误等等,模型保存也是有用的。

https://medium.com/analytics-vidhya/tensorflow-2-model-validation-regularization-and-callbacks-49c5ace1e8b

最终,我想使用训练好的模型,通过安装在自动驾驶汽车上的摄像头,对检测行人进行实时预测。

保存和加载模型

在保存模型时,我们可以做几件事情。我们希望在每次迭代(历元)中保存模型权重和训练参数,每隔一段时间保存一次,还是在训练完成后保存?我们可以使用内置回调,就像我们在我之前的文章中看到的那样,在训练过程中自动保存模型权重。或者,一旦训练完成,我们也可以保存模型权重和其他必要的信息。

保存的模型有两种主要格式:一种是原生 TensorFlow 格式,另一种是 HDF5 格式,因为我们通过 Keras API 使用 TensorFlow。

在训练过程中保存模型的例子:

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.losses import BinaryCrossentropy
from tensorflow.keras.callbacks import ModelCheckpointmodel = Sequential( [
Dense(128, activation='sigmoid', input_shape = (10, )),
Dense(1)])model.compile(optimizer = 'sgd', loss = BinaryCrossentropy(from_logits  = True))checkpoint = ModelCheckpoint('saved_modelname', save_weights_only=True)model.fit(X_train, y_train, epochs = 10, callbacks = [checkpoint])

你可以看到,我使用ModelCheckpoint类创建了一个对象checkpoint,它接受一个参数,该参数将被用作保存模型的文件名。由于使用了save_weights_only=True,所以只会节省权重,不会节省网络架构。最后,我们将callback = [checkpoint]传递给 fit 函数。

如果我们提供‘saved_modelname.h5而不是‘saved_modelname’,那么模型将以 HDF5 格式保存。

为了加载先前保存的权重,我们调用load_weights函数。

model = Sequential( [
Dense(128, activation='sigmoid', input_shape = (10, )),
Dense(1)])
model.load_weights('saved_modelname')

手动保存模型权重,无需回调

我们也可以通过在培训结束时调用save_weights来手动保存模型

model = Sequential( [
Dense(128, activation='sigmoid', input_shape = (10, )),
Dense(1)])model.compile(optimizer = 'sgd', loss = BinaryCrossentropy(from_logits  = True))model.fit(X_train, y_train, epochs = 10)
**model.save_weights("saved_modelname")**

您还可以分析保存模型的目录:

total 184K
-rw-r--r-- 1 ivory ivory   61 Jan 12 01:08 saved_modelname
-rw-r--r-- 1 ivory ivory 174K Jan 12 01:08 saved_modelname.data-00000-of-00001
-rw-r--r-- 1 ivory ivory 2.0K Jan 12 01:08 saved_modelname.index

在这里,您可以看到保存的实际模型是saved_modelname.data-00000-of-00001,文件的其余部分包含元数据。

保存整个模型

到目前为止,我们看到我们只保存了模型权重。然而,保存整个模型是非常容易的。在实例化ModelCheckpoint 类时只需传递save_weights_only=False

checkpoint_dir = 'saved_model'
checkpoint = ModelCheckpoint(filepath=checkpoint_dir, 
                            frequency = "epoch",
                            save_weights_only = False,
                             verbose= True)model.fit(X_train, y_train, callbacks=[checkpoint])

在这种情况下,将创建一个包含以下内容的新目录:

total 128
drwxr-xr-x 2 ivory ivory   4096 Jan 12 01:14 assets
-rw-r--r-- 1 ivory ivory 122124 Jan 12 01:14 saved_model.pb
drwxr-xr-x 2 ivory ivory   4096 Jan 12 01:14 variables

在这种情况下,主模型保存在文件saved_model.pb中,其他文件是元数据。

最后,我们可以如下使用保存的模型:

from tensorflow.keras.models import load_model
model = load_model(checkpoint_dir)

如果我们想在训练程序完成后保存模型,我们可以如下调用save函数:

model.save("mysavedmodel")

如果使用model.save(“mysavedmodel.h5”),那么模型将被保存为一个单独的文件mysavedmodel.h5

保存的模型可用于使用全新的数据集进行预测。

model.predict(X_test)

我的 GitHub repo 在https://GitHub . com/rahulbhadani/medium . com/blob/master/01 _ 12 _ 2021/Saving _ Model _ tf2 . ipynb中给出了一个更具描述性的例子。

确认

这篇文章的动机是作者从 TensorFlow2 Coursera 课程https://www . Coursera . org/learn/getting-started-with-tensor-flow 2/。读者可能会发现这个例子与 Coursera 课程中的例子有相似之处。教师允许使用 Coursera 课程中的代码示例(以其原始形式或经过一些修改)。

如何在 Python 中使用抽象类

原文:https://towardsdatascience.com/how-to-use-abstract-classes-in-python-d4d2ddc02e90?source=collection_archive---------2-----------------------

Jr KorpaUnsplash 上拍摄的照片

什么是抽象类?

抽象类是一个类,但不是可以直接从中创建对象的类。它的目的是定义其他类应该是什么样子,也就是说,它们应该有什么样的方法和属性。

在抽象类中定义(但未实现)的方法和属性被称为抽象方法抽象属性。所有抽象方法和属性都需要在子类中实现,以便能够从中创建对象。

我们可以通过继承属于[abc](https://docs.python.org/3/library/abc.html) 模块ABC类来创建一个抽象类。

from abc import (
  ABC,
  abstractmethod,
) class BasicPokemon(**ABC**):
  def __init__(self, name):
    self.name = name
    self._level = 1 **@abstractmethod**
  def main_attack(self):
    ...

在上面的代码中,我们创建了一个名为BasicPokemon的新抽象类。我们通过使用装饰器abstractmethod指出方法main_attack是一个抽象方法,这意味着我们期望在BasicPokemon的每个子类中实现它。

如果你尝试直接从BasicPokemon创建一个对象会发生什么?TypeError

试图从抽象类创建一个新对象,但由于 main_attack 未实现而失败。图片由作者提供。

现在,你会注意到BasicPokemon__init__方法需要一个name参数,因此上面的代码无论如何都不会起作用。这里需要注意的是,它甚至没有使用__init__方法来检查这一点。事实上,它有一个尚未实现的抽象方法,因此它失败了!

这就是如何使用BasicPokemon类。

from collections import namedtuple Attack = namedtuple('Attack', ('name', 'damage')) **class Pikachu(BasicPokemon):**
  def main_attack(self):
    return Attack('Thunder Shock', 5) **class Charmander(BasicPokemon):**
  def main_attack(self):
    return Attack('Flame Thrower', 5)

现在我们可以毫无问题地从这些类中创建对象。

创造了一个新的皮卡丘,名叫…乔治。图片由作者提供。

注意,您也可以使用相同的abstractmethod装饰器创建抽象属性。

from abc import (
  ABC,
  abstractmethod,
) class BasicPokemon(**ABC**):
  def __init__(self, name):
    self.name = name **@property
  @abstractmethod**
  def level(self):
    ... **@abstractmethod**
  def main_attack(self):
    ... 

现在,我们需要在子类中实现属性levelmain_attack方法。

class Pikachu(BasicPokemon):
  **@property**
  def level(self):
    return 1 def main_attack(self):
    return Attack('Thunder Shock', 5)

我们可以只使用 NotImplementError…对吗?

你们中的一些人可能想知道为什么我们不能使用一个普通的类(即不从ABC继承)并为还没有实现的方法产生一个NotImplementerError,就像下面的例子。

class NotAbstractBasicPokemon:
  def __init__(self, name):
    self.name = name
    self._level = 1 def main_attack(self):
    **raise NotImplementedError()**

上面的代码将让你从NotAbstractBasicPokemon创建对象,只有当你试图使用main_attack时才会失败。这通常是不可取的行为。

从 NotAbstractBasicPokemon 创建对象,并在尝试调用 main_attack()时出错。图片由作者提供。

相反,试图从BasicPokemon创建一个对象会立即导致错误,正如我们前面看到的。

什么时候应该使用抽象类?

在我们在这篇文章中使用的例子中,BasicPokemon的目的是作为一个的蓝图,为特定种类的口袋妖怪创建其他类。拥有一个每个人都需要继承的抽象类来创建一个新的口袋妖怪有几个明显的好处:

  • 避免代码重复。
  • 确保其他人实现子类方式的一致性。
  • 确保没有人忘记在子类中实现关键的方法和属性。

当你在一个团队中工作,并且你希望其他人重用/扩展代码时,以上几点尤其重要。

结论

在这篇文章中,我们看了 Python 的抽象类,以及它们如何给我们一种方法来描述我们期望子类如何被实现,以及当关键部分没有被定义时如何警告用户(即其他程序员或我们未来的自己)。

https://eminik355.medium.com/subscribe

参考文献

[1]https://docs.python.org/3/library/abc.html

https://realpython.com/python-interface/

更多来自同一作者。

https://medium.com/analytics-vidhya/multi-armed-bandits-part-1-epsilon-greedy-algorithm-with-python-code-534b9e2abc9 https://medium.com/analytics-vidhya/calculating-using-monte-carlo-simulations-337cff638ac5

如何使用亚马逊 Textract 读取发票和收据

原文:https://towardsdatascience.com/how-to-use-amazon-textract-to-read-invoices-and-receipts-143b661b0c49?source=collection_archive---------7-----------------------

自然语言处理

AWS 和 Amazon Textract 入门。

Unsplash 上由 Atakan Narman 拍摄的照片

今天,我们将冒险进入 AWS 世界,用 Amazon Textract 玩一玩。我们将拍摄一张发票的扫描图像,并从中提取信息。主要是,我们将:

  1. 创建 AWS 用户
  2. 安装 AWS CLI
  3. 安装和配置 AWS SDK
  4. 上传到 S3
  5. 代码!

使用的大部分代码来自 Amazon Textract 开发人员指南。它可以在这里找到:

如果你想跟随我使用的相同文件,请在我的 Github 上查看项目回购。

让我们开始吧!

1.创建 AWS 用户

首先,进入https://aws.amazon.com/console/,点击屏幕右上角的橙色按钮登录。

接下来,使用“Root 用户”选项登录。

输入您的密码。

如果您已经激活了 MFA,请输入它。

您将进入 AWS 管理控制台主页,在这里您将看到最近访问过的服务。

找到屏幕顶部的搜索栏,键入“IAM”以显示可用 AWS 服务的下拉列表。点击写着“IAM”的那个。

然后,您的浏览器将显示 IAM 仪表板。在页面左侧找到“用户”并点击它。

点击屏幕右上角的蓝色按钮“添加用户”。

填写用户名,勾选“编程访问”和“AWS 管理控制台访问”并设置密码。然后,单击“下一步:权限”。

单击“直接附加现有策略”框。

你的屏幕应该看起来像下面的截图。点击“下一步”。

找到屏幕中间的搜索框,输入“textract”。

找到“AmazonTextractFullAccess”并点击左边的复选框。

接下来,在搜索栏中键入“s3”。

找到“AmazonS3FullAccess”并点击左边的复选框。然后,点击“下一步:标签”。

添加标签是可选的。点击“下一步:回顾”。

点击页面底部的“创建用户”按钮。

您应该会看到类似下面的内容:

非常重要!!! 点击“下载。csv”并将文件保存在安全的地方。一定要记下你把它保存在哪里。以后哪里会需要里面的资料。

瞧啊。您应该会看到一个屏幕,确认已经创建了一个新用户。

在屏幕的右上方,找到您的帐户别名(我的是 ecdedios ),点击它会显示一个下拉菜单。最后,点击“退出”。

点击“重新登录”。

这一次,点击“IAM 用户”而不是“根用户”。

键入您的帐户别名,然后单击“下一步”按钮。

键入您刚刚创建的 IAM 用户名,并填写密码。点击“登录”。

如果出现提示,请更改密码。否则,我们就完成了这一步。

2.安装 AWS CLI

要下载 AWS 的命令行界面,请访问https://docs . AWS . Amazon . com/CLI/latest/user guide/CLI-chap-install . html

在这个练习中,我使用了 AWS CLI 版本 2。

在下一页中,找到您的操作系统并点击它。比如,我点击了“视窗”。

找到能让你下载最新版本的链接,然后点击它。

然后应该会打开一个“另存为”对话框。把文件保存在某个地方。

找到您刚刚下载的文件,双击它启动安装程序。在弹出的窗口中单击下一步。

您应该会在下面看到类似的内容。

完成后,您会在安装窗口上看到确认信息。接下来,单击“完成”按钮。

接下来,让我们确保它安装正确。

启动您的终端,键入以下内容:

aws --version

这一步就到此为止。

3.为 Python 安装和配置 AWS SDK(boto 3)

对于这一步,我们将为 Python 安装和配置 AWS SDK。

如果您想了解更多 Boto3,请查看它的文档:

启动一个终端,键入下面一行:

pip install boto3

让脚本完成它的任务。

完成后,让我们通过键入以下行来进行配置:

aws configure

它会提示您输入凭据。首先,找到您在步骤 1(创建一个 AWS 用户)中下载的文件。

出现提示时,复制并粘贴“访问密钥 ID”,然后复制并粘贴“秘密访问密钥”。粘贴完每一张后,你必须按回车键。接下来,当提示输入“默认区域名称”时,在您的首选区域中键入

当提示输入“默认输出格式”时,不要输入任何内容。再次按回车键。

就是这样!我们现在已经准备好用 Python 与 AWS 通信了。

4.上传到 S3

对于这一步,我们将上传一个图像文件到 S3 桶。我们将使用这张图片作为我们的输入文档,并要求 Amazon Textract 阅读它。

让我们重新登录 AWS 控制台。

单击 IAM 用户。

键入您的帐户别名。

单击“下一步”继续。

键入您在步骤 1 中创建的用户(非 root)凭据。

此时,您应该会看到 AWS 管理控制台。

找到页面顶部的搜索栏,输入“S3”。接下来,选择服务下的“S3 ”,如下所示。

找到橙色按钮“创建桶”。水桶就像一个文件夹。我们将在里面保存(上传)文件。

填写“Bucket name ”,并选择一个与您在步骤 3 中输入的区域相同的 AWS 区域。接下来,向下滚动页面,您会发现页面右下角有一个橙色按钮。点击它“创建桶”。

您应该会看到一条确认消息,表明已经创建了一个新的存储桶。接下来,单击我们刚刚创建的存储桶名称。

找到橙色的“上传”按钮并点击它。

点击“添加文件”。

从您的计算机中选择一个图像。扫描的发票或收据就可以了。

向下滚动到下一页,找到橙色的“上传”按钮。点击它。

点击“关闭”。

您应该会看到该文件列在“对象”下。

好吧!现在,该编码了。

5.密码

这是我们将要阅读的文件:

现在,让我们启动 Jupyter 笔记本,导入一些项目,并设置笔记本显示设置。

然后,复制并粘贴下面的代码。 重要!!! 不要忘记再次检查第 42 行,确保它与您一直使用的区域相同。

也重要!!! 注意你的文件夹结构,以匹配第 79 行

下面是代码的作用:

首先,它连接到 S3 并获取我们将输入到 Textract 的对象(图像文件)(第 30–33 行)。然后,它将文件加载到内存中,并将其送入 image(第 35–39 行)。接下来,我们调用 Amazon Textract API(第 41–42 行)。最后,我们调用analyze_expense来分析图像,并将结果存储在response中(第 45 行)。

第 48–76 行解析response,并在图像文件上绘制边界框。第 79 行在本地保存图像。最后,第 81 行返回response的内容。

对于下一个单元格,复制、粘贴并定制下面的代码,以匹配您的存储桶名称和对象(文件)。

现在我们准备调用上面的函数。

让我们来看看输出:

漂亮!

现在,让我们考虑下面的代码:

我们在上面所做的是过滤响应,以便它只给我们那些置信度值小于 90%的元素。

我们可以说,工作和销售人员是标签,而“技术技能(点)忍者”不是。不出所料,这个元素的置信度只有 39%。

很酷,不是吗?

就这样,伙计们!我们已经成功地进入了 AWS 的世界,并与 Amazon Textract 进行了合作。

谢谢你过来看我的帖子。我希望你学到了新的东西!在我随后的文章中,我们将深入探讨 AWS 及其提供的大量服务。

敬请期待!

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

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

你可以通过推特LinkedIn 联系我。

如何使用自回归(AR)模型进行时间序列分析

原文:https://towardsdatascience.com/how-to-use-an-autoregressive-ar-model-for-time-series-analysis-bb12b7831024?source=collection_archive---------2-----------------------

python 中使用自回归模型进行预测的初学者指南

阿格巴洛斯Unsplash 上拍摄的照片

在处理时间序列数据时,可以使用自回归模型来预测未来值。预测背后的概念是使用以前的数据点来计算未来的数据点。

在这个简短的初学者友好指南中,你将学习如何创建一个自回归模型,并用它来预测未来的价值。

例子

举个简单的例子,可以让你知道它是如何工作的:
现在是下午 2 点,我们想预测下午 3 点的值。为了做到这一点,我们可以使用已知的 2pm 和 1pm 的值。从数学上讲,它可能如下所示:

x(t) = b0 + b1x(t-1) + b2x(t-2)

是我们希望对其进行预测的时间。 t-1 是前一个时间点,而 t-2 是向后两个时间点。

b 值是通过拟合数据集的自回归模型得到的权重。

术语

滞后:处理时间序列数据时,每个跨时间的数据点称为一个滞后。

偏差或权重:上例中的 b 值为权重。它们是描述输入变量和我们预测的变量之间的相关性的值。如果权重为正,也称为正相关,这意味着输入变量与预测变量的移动方向相同。相反,如果权重为负,那么它会向预测变量的相反方向移动。

例如,值为 10 (正值)的输入变量上的权重 -0,7 会将 -7 加到输出值上,从而对其产生负面影响。

如果权重值非常接近 0 ,则表明变量的先前值和未来值之间可能没有相关性,因此无法进行预测。高于 0.5 或低于- 0.5 的值表示强相关。

自相关:当输出变量本身与其早期变量之间计算相关性时,预测变量与输入变量之间的关系或相关性称为自相关。

数据集

在本指南中,我们将使用澳大利亚墨尔本的数据集,其中包含了 10 年间的最低日温度。该数据集是由澳大利亚气象局创建的。

如果你想按照这个指南编码,那么你可以在这里找到数据

寻找自相关

为了找出哪些滞后与预测值有很强的相关性,我们可以使用 statstmodels 模块中的plot_acf()函数。这将创建一个图表,显示每个先前的滞后对未来滞后的影响程度。

如上所述,高于 0.5 或低于 -0.5 的值被认为具有高相关性,因此在查看曲线图时,我们可以使用这些值作为阈值来决定是包括还是忽略特定的滞后。

下面的代码块创建了这个图,我在
y = 0.5 处添加了一条垂直线,以便于查看哪些滞后符合 0.5 阈值。

请注意,我将 y 轴限制在 0 到 1 的范围内。您通常不应该这样做,因为相关性也可能是负的。我这样做是为了提高图的可读性,只是因为我已经知道所有的滞后都是正相关的。

import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.graphics.tsaplots import plot_acf
import numpy as npdf = pd.read_csv('australia_temp_data.csv')fig, ax = plt.subplots(figsize=(16,8))
plot_acf(df['Temp'], lags=50, ax=ax)
plt.ylim([0,1])
plt.yticks(np.arange(0.1, 1.1, 0.1))
plt.xticks(np.arange(1, 51, 1))
plt.axhline(y=0.5, color="green")
plt.show()

作者创建的 acf 图

在分析剧情的时候,我们可以看到第一个滞后对我们未来的价值有非常强的相关性。滞后 22 是明显高于绿色阈值线的最后一个滞后。因此,我们现在知道使用 22 个滞后来创建我们的自回归模型。

将数据分成训练和测试数据集

为了能够评估我们的模型,一旦我们训练了它,我们需要一些数据来测试它。因此,我们将使用数据集中的一些最新值作为测试数据。

从上面代码块中的代码继续,我们可以按如下方式分割数据:

df_train = df['Temp'].iloc[:-5]
df_test = df['Temp'].iloc[-5:]

这使得训练集由整个数据集的最后 5 个值组成,并且训练集是直到最后 5 的所有值。

创建和拟合模型

既然我们已经将训练和测试数据分开,并且我们知道在我们的模型中要考虑多少滞后,我们就拥有了创建模型所需的一切。

我们使用 statsmodels 模块(版本 0.13.1)中的AutoReg类。

如果您使用的是 Google Colab 笔记本,那么您可能没有安装最新版本的 statsmodels。您很可能安装了 0.10.2 版本,而我将使用 0.13.1。要得到这个版本,你可以调用pip install statsmodels==0.13.1,然后重启笔记本的运行时间。

from statsmodels.tsa.ar_model import AutoReg
model = AutoReg(df_train, lags=22).fit()

现在已经创建了模型,并对训练数据进行了拟合。接下来,是时候进行一些预测,并通过与测试值进行比较来评估准确性。

预测和评估

forecasts = model.forecast(5).tolist()
test_values = df_test.tolist()
for index in range(len(forecasts)):
  difference = forecasts[index] - test_values[index]
  print(forecasts[index], test_values[index], difference)

为了进行预测,我们简单地调用模型上的forecast()函数,并向它传递我们想要预测的滞后量。这将返回一个熊猫系列对象,我们可以使用它的tolist()函数将它转换成一个列表。

在循环中,我们在测试数据集中的实际值旁边打印预测,以及它们之间的差异。打印结果如下所示。

作者创建的预测值、测试值以及它们之间的差异

为了获得可用于评估模型性能的单个数字指标,我们可以计算两个值列表之间的均方误差。这可以通过使用 scikit-learn 模块中的mean_squared_error()功能来完成,如下所示。

from sklearn.metrics import mean_squared_error
print(mean_squared_error(test_values, forecasts))>> 1.181958471550279

结果显示,我们的预测平均误差约 1.2 摄氏度。为了直观地了解预测的准确性,我们还可以在同一个图中绘制预测和测试数据。

fig = plt.subplots(figsize=(12,8))
plt.plot(forecasts, color="green")
plt.plot(test_values,color="blue")
plt.xticks(np.arange(0,6,1))
plt.yticks(np.arange(12.5, 17, 0.5))
plt.show()

作者创建的预测和测试数据图

这里我们可以清楚地看到,在滞后 4 时(x 轴上的 3),距离很远。然而,其他预测实际上相当不错。

摘要

在这篇简短的指南中,您学习了自回归背后的重要背景理论,包括一些数学知识和术语。您学习了使用 acf 图来查找用于创建模型的滞后量。接下来,您将数据集分为训练和测试数据子集。最后,您了解了如何进行预测以及评估其性能的一些方法。

我希望你喜欢这个指南,并学到一些有用的东西!

感谢阅读。

学分

1——Jason Brownlee,用 Python 进行时间序列预测的自回归模型,机器学习掌握,可从https://Machine Learning Mastery . com/auto regression-Models-Time-Series-Forecasting-Python/获取,2021 年 12 月 20 日。

如何在 R 中使用和可视化 K-Means 聚类

原文:https://towardsdatascience.com/how-to-use-and-visualize-k-means-clustering-in-r-19264374a53c?source=collection_archive---------1-----------------------

通过美国传统基金会的 2020 年经济自由指数数据,学习使用和可视化 R 中的 K 均值聚类分析

作者用 K-Means 和 R |图像制作的聚类图图像

目标

  1. 在 R 中使用 K-均值聚类算法
  2. 确定正确的集群数量
  3. 创建集群的表格和可视化
  4. 从网上下载、提取复杂的 Excel 文件并加载到 R
  5. 高效地清理、争论和过滤数据

介绍

K-Means 聚类是一种无监督的机器学习技术,对于根据数据集中存在的独立变量的中心将独特的数据分组为几个相似的组非常有用[1]。几个经典的例子是在公司忠诚度计划中对不同类型的客户进行聚类,并将医疗患者分为低、中、高和极端风险类别[1]。

在本文中,我们将使用美国传统基金会免费提供的 2020 年经济自由指数数据集 [2]。我们还将使用一个 R Markdown 文件(。RMD)可通过此链接在我的 GitHub 上下载。我将假设您可以在您选择的机器上下载并安装 R 和 RStudio。

这篇文章的结构是:

  1. 加载所需的库
  2. 导入数据
  3. 清理数据并修复格式问题
  4. 展示创建 K 均值聚类的几种不同方法
  5. 展示几种有用的可视化效果,您可以根据需要将它们应用到您的项目中

让我们投入进去吧!

代码

加载库

首先,我们需要将 tidyverse、FactoMineR、factoextra、readxl 加载到我们的 R 环境中。如果您得到一个关于软件包未被识别的错误,请在您需要的 install.packages() 行之前取消注释(删除#)。

# Install if needed by removing the #
# install.packages("tidyverse")
# install.packages("readxl")
# install.packages("FactoMineR")
# install.packages("factoextra")# Load Libraries
library(tidyverse)
library(readxl)
library(FactoMineR)
library(factoextra)

将您的工作目录设置到包含您的文件并有空间下载. xls 文件的文件夹中也会对您有所帮助。这可以通过 setwd() 命令或使用 RStudio 导航文件菜单到文件夹位置,并使用更多下拉菜单设置工作目录来完成,如下所示:

在 RStudio 中设置工作目录

下载数据

现在我们需要下载数据。网页的链接可以在这里找到,或者如果你想在传统基金会的网站上了解更多的数据,可以在我的 GitHub 的 T2 RMD 文件中找到。单击页面顶部的“下载原始数据”按钮,您应该会得到一个名为 index2020_data.xls 的文件,我们将在项目的其余部分使用该文件。

导入数据

最简单的做法就是导航到有数据的文件夹,点击它,自动调出 readxl 图形界面。为了简单明了,我继续将我的数据重命名为 EFI_data 。这些截图应该有所帮助:

在 RStudio 中导入数据集

RStudio 中的 readxl GUI

更改名称并点击导入按钮后,RStudio 会自动生成一些代码到您的控制台。最好将没有“>”的第一行复制/粘贴到文件中,以便稍后能够快速加载数据。看起来是这样的:

RStudio 中的 EFI_data 控制台输出

代码应该如下所示:

# Import Data
EFI_data <- read_excel("index2020_data.xls")

用代码将数据导入 RStudio

初步查看数据

如果可能的话,在我们做有趣的事情之前,快速浏览一下数据,看看是否有任何明显的问题需要解决,这总是一个好主意。

下面是中间部分数据的截图。让我们看看有什么突出的。

初步看看 RStudio 中的一些 EFI 数据

我想到的是,丢失的数据被标记为“N/A ”,我知道 R 不会喜欢。这些数字看起来也很奇怪,有些又短又甜,而有些则有太多的小数位。此外,我们中的热心人注意到,在数据导入阶段,所有应该是数字的列实际上都是字符。我们还必须解决数据类型问题。

清理数据

首先,让我们摆脱“不适用”的问题。有很多方法可以做到这一点,但我将依靠一个技巧 R 和“相信魔术”一点点。为了避免下面的步骤变得复杂,请相信我,在继续之前,我们应该从 EFI_data 中获取原始的列名。让我们使用这个代码:

# Get original column names
EFI_data_col_names <- names(EFI_data)

接下来,我们将使用 lapply() 函数,并将 gsub() 函数放入自定义函数()中,以查找字符串 "N/A" 的任何出现,并将其替换为 nothing。当我们像这样构造函数时,我们依靠 lapply() 的速度来执行调整,这比使用 for 循环要快得多,因为 R [1]是单线程的。在下一步中,我们将依靠 R 将空数据强制转换成正确的 NA 格式。浏览数据,亲自查看结果。

代码如下:

# Fix "N/A" in the data set
EFI_data <- data.frame(lapply(EFI_data, function(x) {
  gsub("N/A", "", x)
}))

虽然这个函数在数据本身中做了我们希望它做的事情,但 R 认为自动更改列名是个好主意。又烦又乱,就用这段代码把原来的名字放回去吧:

# Put the right column names back
names(EFI_data) <- EFI_data_col_names

自定义函数的时间到了!

让我们做一个,把所有的字符列都变成数字,并四舍五入到两位小数。我们将在下一步中插入这个自定义函数。

代码如下:

# Create custom function to fix data types and round
to_numeric_and_round_func <- function(x){
  round(as.numeric(as.character(x)),2)
}

创建了自定义函数后,我们将使用 mutate_at() 函数来更改除了应该保留文本的四列之外的所有列。

代码如下:

# Mutate the columns to proper data type
EFI_data <- EFI_data %>%
  mutate_at(vars(-one_of("Country Name", "WEBNAME", "Region", "Country")), to_numeric_and_round_func)

实际上,我们不需要 CountryWEBNAME 来进行实际分析,所以我们现在将通过使用以下代码使它们为空来删除它们:

# Remove Country and WEBNAME
EFI_data$Country <- NULL
EFI_data$WEBNAME <- NULL

k 均值聚类

有两种主要的方法来做 K-Means 分析——基本方法和花式方法。

基本 K 均值

在基本的方法中,我们将做一个简单的 kmeans() 函数,猜测一些集群(5 通常是一个好的起点),然后有效地将集群编号粘贴到每一行数据中,然后就结束了。我们必须首先删除任何丢失的数据,这可以用下面的代码来完成:

# create clean data with no NA
clean_data <- EFI_data %>%
  drop_na()

我们还想设置种子,以确保代码的可重复性:

# Set seed
set.seed(1234)

下面是基本 K 均值方法的代码:

# Cluster Analysis - kmeans
kmeans_basic <- kmeans(clean_data[,7:32], centers = 5)
kmeans_basic_table <- data.frame(kmeans_basic$size, kmeans_basic$centers)
kmeans_basic_df <- data.frame(Cluster = kmeans_basic$cluster, clean_data)# head of df
head(kmeans_basic_df)

以下是输出结果:

基本 K 均值聚类方法的前六行

这显示了添加到每一行数据中的簇号。

我们还可以在这里使用 kmeans_basic_table 查看每个集群的属性(中心、大小):

基本 K 均值聚类方法的大小和中心

我们还可以像下面这样浏览在 kmeans_basic_df 对象中带有集群号的每一行数据:

每个国家的基本 K 均值数据和聚类的大视图

对许多人来说,基本的方法将带你到你需要去的地方。从这里,您可以按区域、每个集群的数据或您想要的任何内容绘制图表。

我创建了一个快速的 ggplot() 例子,按区域分解每个集群的计数。我们可以做几十个不同的情节,但这是一个很好的,简单的演示。

代码如下:

# Example ggplot
ggplot(data = kmeans_basic_df, aes(y = Cluster)) +
  geom_bar(aes(fill = Region)) +
  ggtitle("Count of Clusters by Region") +
  theme(plot.title = element_text(hjust = 0.5))

以下是输出结果:

使用 ggplot 按区域绘制聚类计数图

花式 K 均值

第一项任务是计算出正确的集群数量。这是用碎石图完成的。本质上,目标是找到曲线开始明显变平的地方[1]。因为 K-Means 算法有效地最小化了聚类中心和每个数据点之间的差异,所以创建了这种曲线形状,其开始是陡峭的,然后渐进地接近某一水平的平坦线[1]。虽然这不是一个完整的要求,但在使用 scale() 函数或其他归一化技术生成聚类时缩放数据通常是一个好主意,这样可以获得更准确的结果[1]。

我们将使用 fviz_nbclust() 函数创建一个 scree 图,代码如下:

# Fancy K-Means
fviz_nbclust(scale(clean_data[,7:32]), kmeans, nstart=100, method = "wss") + 
  geom_vline(xintercept = 5, linetype = 1)

以下是输出结果:

确定 K 均值最佳聚类数的 Scree 图

实际上,创建奇特的 K 均值聚类函数与基本的非常相似。我们将只缩放数据,创建 5 个集群(我们的最佳数量),为了简单起见,将 nstart 设置为 100。

代码如下:

# Fancy kmeans
kmeans_fancy <- kmeans(scale(clean_data[,7:32]), 5, nstart = 100)# plot the clusters
fviz_cluster(kmeans_fancy, data = scale(clean_data[,7:32]), geom = c("point"),ellipse.type = "euclid")

以下是输出结果:

K-均值聚类的可视化

这最后一个图确实有助于形象化地显示出这些集群实际上是彼此相似的。有趣的是,用很少的代码就能得到一些非常有趣的结果。

结论

这个项目是为了展示如何使用和可视化 K-均值聚类。这样做的方法不止一种,可以做出无数的情节。像数据科学中的大多数任务一样,大多数时间实际上都花在了查找数据和清理数据上,以便用这些数据做一些有用的事情。希望到目前为止,您对使用 K-Means 聚类有了更好的感觉,并且可以看到我们在这里使用的技术的不同应用。

参考

[1] R .卡巴科夫, R 在行动(第 2 版。) (2015),纽约州谢尔特岛:曼宁出版公司。

[2]美国传统基金会, 2020 年经济自由度指数 (2020),https://www.heritage.org/index/download

如何使用 AWS Amplify 部署 React 应用程序

原文:https://towardsdatascience.com/how-to-use-aws-amplify-to-deploy-a-react-application-ae93cd6e4525?source=collection_archive---------9-----------------------

使用 AWS Amplify 部署 React 应用程序的指南

我的作品集网站

自从我作为一名软件工程师开始从事咨询工作以来,我就想建立一个作品集网站,展示我参与的个人项目和专业项目。今年寒假,我花时间设计、开发和部署了我的 portfolio 站点,在本文中,我将向您介绍我是如何使用 AWS Amplify 部署它的。你可以在dan-murphy.com查看网站,在 GitHub 查看代码。

简要背景

我的大部分专业工作需要构建数据驱动的应用程序和简化数据管道。为了完成这些任务,我经常使用 Python 和 Ruby,并在任何前端工作中加入 JavaScript。为了更好地使用 React,我决定使用这个框架来构建我的作品集网站。

设置应用程序

我采取的第一步是决定如何构建应用程序。我利用create-react-app作为我的目录的基本模板,然后用一些额外的文件夹重新构建了应用程序。最终的设置如下所示:

src
├── components
│   ├── archives
│   └── extras
│       ├── data
│       └── imgs
├── pages
│   ├── contents
│   └── data
├── styles
└── tests
    └── fixtures

一些显著的变化是**components****pages****styles**目录。

  • **components**:这是我存储应用程序所有组件的地方。通过将组件存储在一个集中的文件夹中,可以更容易地重用和重构我的代码,并且让其他人更直观地理解。组成我的作品集网站的一些组件是[Header](https://github.com/danmurphy1217/website/blob/main/src/components/Header.js)[Footer](https://github.com/danmurphy1217/website/blob/main/src/components/Footer.js)[ProjectSidebar](https://github.com/danmurphy1217/website/blob/main/src/components/ProjectSidebar.js)
  • 这是我为应用程序构建不同页面的地方。我从**components**文件夹中导入所需的组件,然后将它们集合起来设计页面。下面是我如何为主页这样做的一个例子:

Home.js

  • **styles**:这是我为应用程序定义全局 CSS 样式的地方。我喜欢将styled-components用于单个组件,但我也发现它有助于构建适用于每个页面的全局样式。

最后,为了将请求映射到正确的页面,我们使用了react-router-dom。路径在App.js文件中定义,如下所示:

App.js

这将把/请求映射到HomePage,把/projects请求映射到ProjectsPage,把/about请求映射到AboutPage,把/bookshelf请求映射到BookPage。既然应用程序的开发已经完成,我们需要部署它以便其他人可以使用它!

使用 AWS Amplify 部署

概观

部署 React 网站有几种方法,但我发现最简单的方法之一是使用 AWS Amplify 。Amplify 被描述为“构建可扩展的移动和网络应用的最快和最简单的方式。”为了实现这一点,AWS 推断出设置服务器、安装依赖项和创建网站生产版本的所有复杂性,允许您专注于构建直观的 UX。要了解更多关于 AWS Amplify 为数据驱动的应用提供了什么(具体来说,有前端后端的网站),请查看他们的文档

连接存储库

要在 AWS Amplify 上托管您的 web 应用程序,您首先需要连接包含您的源代码的存储库。为此,您可以导航至 AWS Amplify 入门 页面,滚动至托管我的 Web App ,点击连接 App 回购

AWS Amplify 入门页面

然后,您将被重定向到一个单独的页面,在那里您可以连接包含您的源代码的存储库。对于这个例子,我将选择 GitHub,但 AWS Amplify 也支持 BitBucket、GitLab、AWS CodeCommit,甚至在没有 Git 提供者的情况下进行部署。

将存储库连接到 AWS Amplify

成功授权后,您可以选择想要部署的存储库,并选择 AWS Amplify 应该用于生产构建的分支。

选择存储库和分支

之后,点击下一步,AWS 将要求您配置您的构建测试设置。AWS 提供的基本模板如下所示。

version: 1
frontend:
  phases:
    preBuild:
      commands:
        - npm install build:
      commands:
        - npm run build
  artifacts:
    baseDirectory: build
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*

此外,在高级设置开关下,您可以设置环境变量和自定义构建容器。

最后,在检查完应用程序的设置后,单击 Save and Deploy 和AWS 将开始配置和部署应用程序。当 AWS 完成部署后,您可以导航到 Amplify 主页并查看您新部署的应用程序。

现在,让我们使用 AWS Amplify 域管理定制 URL。

添加自定义域

要开始添加自定义域,导航到左侧边栏并选择域管理

AWS Amplify 主页,在域管理设置周围有一个红框。

然后,选择添加域名输入您的域名(如下图所示),点击配置域名

配置您的自定义域

之后,您可以设置您的域所需的任何重定向。例如,在下面的例子中,我创建了一个从https://dan-murphy.comhttps://www.dan-murphy.com的重定向。

AWS 放大器域管理设置页面

最后,在您的自定义域被正确配置后,AWS 将为您提供一个验证证书。您也可以在 AWS 证书管理器控制台中查看该证书。

添加 CNAME 记录

配置自定义域的最后一步是添加 CNAME 记录。在下面的例子中,我使用了 Google Domains ,但是不同的域名注册商的基本概念是一样的。

首先,向下滚动到谷歌域名中的自定义资源记录。创建一个 CNAME 记录,将所有子域指向 AWS 放大器域:

  1. 名称:输入子域名称。如果子域为www.domain.com输入 www 。如果是app.domain.com,进入 app
  2. 数据:在域管理页面,点击动作,然后选择查看 DNS 记录。然后,在配置 DNS 提供商下输入可用的 AWS Amplify 域。

域管理页面中,选择操作查看 DNS 记录

总之,自定义资源记录将如下所示:

在 Google 域中创建自定义资源记录。第一个 CNAME 记录突出显示在一个红框中。

接下来,再添加一个指向 AWS 证书管理器验证服务器的 CNAME 记录。经验证的 AWS 证书管理器为您的应用程序处理 TLS:

  1. 名称:输入验证服务器的子域。如果验证您的域名所有权的 DNS 记录是 _1234.example.com ,只需输入 _1234
  2. 数据:输入 ACM 验证证书。如果验证服务器是_ 1234 . abcdefg . ACM-validations . AWS .,输入_ 1234 . abcdefg . ACM-validations . AWS .

您的验证证书的所有信息可在 AWS 证书管理器控制台中找到。添加第二个 CNAME 后,您的自定义记录应该如下所示:

在 Google 域中创建自定义资源记录。第二个 CNAME 记录在一个红框中突出显示。

最后,让我们添加一个合成记录来建立一个子域 forward:

  1. 子域:输入 @
  2. 域名网址 : 输入你要转发到的子域。在这个例子中,子域是 www

在谷歌域名创建一个子域转发。

包扎

总之,在本文中,我们学习了如何构建 React 应用程序并使用 AWS Amplify 部署它们。首先,我们讨论了如何将 react 应用程序模块化到组件页面文件夹中。然后,我们了解了 AWS Amplify 以及如何使用它部署静态和数据驱动的应用程序。最后,我们学习了如何使用 AWS Amplify 域管理Google 域来定制我们应用程序的域。

如果你对这篇文章或我的作品集网站有任何问题、顾虑或反馈,请随时评论或发邮件给我,地址是danielmurph8@gmail.com。感谢阅读!

如何使用 AWS Secrets Manager 管理凭据

原文:https://towardsdatascience.com/how-to-use-aws-secrets-manager-for-managing-credentials-abf57ab7344c?source=collection_archive---------11-----------------------

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

在很多情况下,您需要使用凭证、令牌、API 密钥等。访问某些服务。例如,您需要使用 SQL server 凭据来访问应用程序的特定数据库。但是,将它们以纯文本文件的形式存储在代码库中并不是最好的主意。这是一个安全漏洞。任何有权访问您的代码库的人都可以读取这些机密,未经授权访问您的服务并执行恶意操作。您可以对秘密进行加密,并将密钥作为配置文件在应用程序外部共享,以允许解密。但是管理这样的秘密会变得很复杂。AWS 有一个秘密管理器,顾名思义,它是一个允许你管理秘密的服务。在本文中,我将讨论如何以编程方式存储和检索秘密。

AWS 机密管理器[1]

此服务允许您保护访问您的应用程序、服务和 IT 资源所需的机密。人们可以在数据库凭证、API 密钥和其他秘密的整个生命周期中轻松地轮换、管理和检索它们。用户和应用程序通过调用 Secrets Manager APIs 来检索机密,无需以纯文本方式硬编码敏感信息。该服务可扩展到其他类型的秘密,包括 API 密钥和 OAuth 令牌。此外,您可以使用细粒度的权限控制对机密的访问,并对 AWS 云中的资源、第三方服务和内部资源集中审计机密轮换。这些秘密可以很容易地复制到其他区域,以支持多区域应用。现在我们将看看创建一个秘密并以编程方式检索它所需的步骤。

步骤 1:创建和存储秘密

您可以使用 AWS Secrets manager 控制台或 AWS CLI 来创建机密。

机密管理器控制台

  1. 登录控制台:【https://console.aws.amazon.com/secretsmanager/

2.在“机密列表”页面上,单击“存储新机密”。

来源:作者

3.在“存储新密码”页面上,选择“其他密码类型”。(这种类型允许您存储键值对或纯文本。)然后,您可以在这个页面上将机密指定为键值对。例如,您的密钥可以是“用户名”和值“secrets@aws.com”

来源:作者

4.对于选择加密密钥,请选择 DefaultEncryptionKey。当您选择此选项时,Secrets Manager 将始终加密机密,无需额外费用。

5.选择下一步

6.在“机密名称”下,键入机密的名称。它只能是字母数字和/_+=。@-.可以用的例子:tutorial/firstkey。等级制度允许你将你的秘密分组并更好地维护它们。如果你愿意,你可以在这里添加描述和标签。

7.按下一步。

8.查看最终细节。此外,该页面还为您提供了不同语言的非常好的示例代码,您可以在您的应用程序中直接使用它们。你可以得到 Python,Java,JavaV2,JavaScript,C#,Ruby 和 Go 语言片段。相当整洁!出版社商店。这将创建一个名为 tutorial/firstkey 的秘密,其中包含 testkey:testvalue 对作为秘密。

机密管理器 CLI

  1. 打开命令提示符运行 AWS CLI。(安装 AWS 命令行界面
  2. 要创建密码,请运行以下命令:$ aws secretsmanager create-secret --name tutorial/firstkey *2* --description "Basic Create Secret" --secret-string '{"testkey":"testvalue"}'

步骤 2:从机密管理器中检索机密

在 AWS 机密管理器控制台中检索您的机密

  1. 登录秘密管理员控制台:https://console.aws.amazon.com/secretsmanager/
  2. 在“机密列表”页面上,选择您创建的机密。
  3. 在“机密值”部分,选择“检索机密值”
  4. 您可以将这个秘密视为键值对,或者 JSON 文本结构。

使用 AWS Secrets Manager CLI 检索

  1. 打开命令提示符。
  2. 输入以下命令:

使用 boto3 Python 代码检索

您也可以使用 boto3 库检索秘密。需要配置您的 AWS CLI。

该函数将给出以下结果:

来源:作者

结论

最后,我们将 AWS Secrets Manager 视为存储数据库凭证、API 密钥等的一种方式。我们看到了如何使用控制台和 AWS CLI 创建密码。最后,我们看了如何使用控制台、AWS CLI 和 boto3 Python 库获得密钥。我希望你喜欢这篇文章,并学到一些有用的东西。感谢您的阅读。关注我更多有趣的文章。

参考

[1]https://aws.amazon.com/secrets-manager/

[2] 快速入门— Boto3 文档 1.17.96 文档

[3]AWS Secrets Manager—boto 3 Docs 1 . 17 . 97 文档

[4] 教程:创建和检索秘密— AWS 秘密管理器

如何使用 Bash 来自动化数据科学的枯燥工作

原文:https://towardsdatascience.com/how-to-use-bash-to-automate-the-boring-stuff-for-data-science-d447cd23fffe?source=collection_archive---------7-----------------------

使用命令行为您的数据科学项目编写一些可重用代码的指南

伊莲娜·科伊切娃在 Unsplash 上的照片

作为一名数据科学家,您倾向于通过终端反复使用一些命令。这些可能是命令为一个项目创建一个新目录启动一个新的虚拟环境激活它,安装一些标准库等等。

当你开始一个项目的工作时,你自己的标准工作流程可能每次都不一样。

例如,我总是为一个新项目创建一个新文件夹,并通过以下方式将其移入:

mkdir newproject
cd newproject

然后我通过以下方式创建了一个新的虚拟环境:

pipenv shell # orpython -m venv newenv

最后,我还做了 numpypandas 作为项目的样板安装。为了形象化的目的,我也经常使用 matplotlibplotly

事实上,我也喜欢为我的机器学习应用程序快速开发 web 应用程序,所以我也倾向于安装 streamlit,因为它是最好的库。如果你不太了解它,这里有一个我写的快速介绍,让你开始使用它。

因此,到目前为止我们需要执行的命令是:

pip install numpy pandas matplotlib plotly streamlit

如果您忘记添加库,您必须返回并通过终端重新安装它们。现在来看,通过一个命令来自动完成这一切不是一个好主意吗?

你可以使用一个脚本,每次执行时自动执行一些重复的命令,这样可以提前一点,节省一些宝贵的时间。

在本文中,我将演示一个简单的命令行过程,您可以很容易地习惯于有效地自动化枯燥的东西,这是我经常使用的一种方法。

我们开始吧!👇

检查系统上的 bash

了解 bash 在系统中的位置的一个简单方法是使用:

$ which bash

输出将类似于:

**/bin/bash**

检查 bash 版本:

bash --version

输出应该如下所示:

例如,Mac 上的 bash 版本

太好了,现在我们有了一点信息,让我们看看我们可以用它来构建什么。

制作新的 bash 脚本

我们将创建一个包含所有要执行的样板命令的文件。这将被称为我们的 bash 脚本,它将具有的扩展。sh 就一般惯例而言。

首先,创建一个新文件。

touch createmlapp.sh

接下来,让我们在文件的顶部添加一行代码,以确保系统知道使用默认的 bash shell 来运行我们的脚本。

#!/bin/bash

现在,让我们明白我们在这里想要做什么。我们的流程如下:

  1. 为我们的项目创建一个新目录
  2. 创建和激活虚拟环境
  3. 安装我们需要的任何软件包
  4. 打开项目目录中的 VSCode。

让我们现在过一遍。

写我们的剧本

我们所有的命令都将类似于我们在终端中正常运行的命令。

只有一个区别——为了使我们的项目成功,我们需要一个名字,我们将通过一个参数传递这个名字。

APP_NAME="$1"

执行脚本时输入的第一个参数将是我们的 $1

现在,剩下的代码将是熟悉的:

cd
cd Desktop/ # use whatever directory you wish here 
mkdir $APP_NAME
cd $APP_NAME

现在进入虚拟环境:

python -m venv newenv
source newenv/bin/activate

最后,我们安装我们需要的任何软件包:

pip install --upgrade pip
pip install numpy pandas matplotlib streamlit

最后,作为奖励,让我们打开我们最喜欢的代码编辑器 VSCode 开始我们的项目。

code .

我们完事了。😄。您的脚本现在应该是这样的:

#!/bin/bashAPP_NAME="$1"
cd
cd Desktop/
mkdir $APP_NAME
cd $APP_NAME
python -m venv newenv
source newenv/bin/activate
pip install --upgrade pip
pip install numpy pandas matplotlib streamlit
code .

运行我们的脚本

首先,我们做chmod +x(在我们的脚本上)使它可执行。

chmod +x createmlapp.sh

厉害!这太棒了。剩下的唯一一件事就是将这个脚本移动到我们的主目录中,这样我们就可以运行它,而不用每次都将 cd — ing 放入任何其他文件夹中。

首先,找出您的主目录——在终端中键入 cd 。无论您要去哪里,您都需要将脚本移动到那里,以便使它可以从那里执行。

现在,只需输入:

./createmlapp.sh yourmlappname

来看看实际的脚本!

结束…

恭喜你。在这个小指南之后,你现在应该能够自动化类似的工作流程,以便在开始一个新项目时节省一些时间!

我现在能给你的建议就是探索更多,尝试创建更多的脚本,也可能执行更复杂的任务,比如运行新的应用自动、T21【将代码推送到 GitHub 等等。

你可以在这里找到代码库

如果您喜欢这篇文章,我每周都会在这里分享一些来自数据科学世界的有用工具和技术。跟随我永远不会错过他们!

最后,这里有几篇我的类似文章,你可能也会觉得有用:

</26-datasets-for-your-data-science-projects-658601590a4c>

如何使用来自拥抱脸变压器库的伯特

原文:https://towardsdatascience.com/how-to-use-bert-from-the-hugging-face-transformer-library-d373a22b0209?source=collection_archive---------2-----------------------

如何使用来自拥抱脸变形库的 BERT 完成四项重要任务

eberhard grossgasteiger 在 Unsplash 上的照片

在这篇文章中,我将演示如何使用 BERT 的拥抱面部变形库来完成四个重要的任务。我还将向您展示如何配置 BERT 来执行您可能希望使用它的任何任务,除了它旨在解决的标准任务之外。

请注意,本文写于 2021 年 1 月,因此拥抱脸库的早期/未来版本可能会略有不同,本文中的代码可能不一定有效。

伯特建筑的快速回顾

BERT 是一个双向转换器,使用屏蔽语言建模和下一句预测的组合进行预训练。BERT 的核心部分是来自 transformer 模型的堆叠双向编码器,但在预训练期间,在 BERT 上添加了屏蔽语言建模和下一句预测头。当我说“头”时,我的意思是在 BERT 上添加几个额外的层,可以用来生成特定的输出。BERT 的原始输出是来自堆叠双向编码器的输出。这个事实特别重要,因为它允许您使用 BERT 做任何事情,您将在本文后面看到这样的例子。

BERT 可以解决拥抱脸提供的许多任务,但我将在本文中讨论的是掩蔽语言建模、下一句预测、语言建模和问题回答。我还将演示如何配置 BERT 来完成除上述任务和拥抱脸提供的任务之外的任何任务。

在讨论这些任务之前,我将描述如何使用 BERT 记号赋予器。

伯特记号赋予器

BERT 记号赋予器是一个与 BERT 一起工作的记号赋予器。对于任何类型的令牌化任务,它都有许多功能。您可以使用这行代码下载令牌化器:

from transformers import BertTokenizertokenizer = BertTokenizer.from_pretrained('bert-base-uncased')

与 BERT 模型不同,您不必为每个不同类型的模型下载不同的标记器。您可以对 hugging face 提供的各种 BERT 模型使用相同的标记器。

给定一个文本输入,下面是我在项目中通常如何标记它:

encoding = tokenizer.encode_plus(text, add_special_tokens = True,    truncation = True, padding = "max_length", return_attention_mask = True, return_tensors = "pt")

由于 BERT 一次只能接受 512 个令牌作为输入,因此我们必须将截断参数指定为 True。add special tokens 参数只是让 BERT 添加标记,如开始、结束、[SEP]和[CLS]标记。Return_tensors = "pt "只是让 tokenizer 返回 PyTorch 张量。如果您不希望这种情况发生(也许您希望它返回一个列表),那么您可以移除该参数,它将返回列表。

在下面的代码中,你会看到我没有添加上面列出的所有参数,这主要是因为这是不必要的,因为我没有对真实项目的文本进行标记。在一个真实的机器学习/NLP 项目中,您会想要添加这些参数,尤其是截断和填充,因为我们必须在一个真实的项目中对数据集中的每个批次进行此操作。

tokenizer.encode_plus()专门返回值的字典,而不仅仅是值的列表。因为 tokenizer.encode_plus()可以返回许多不同类型的信息,如 attention_masks 和令牌类型 id,所以所有内容都以字典格式返回,如果您想检索编码的特定部分,可以这样做:

input = encoding["input_ids"][0]
attention_mask = encoding["attention_mask"][0]

此外,因为记号赋予器返回一个不同值的字典,而不是像上面显示的那样找到这些值,并分别将它们传递到模型中,我们可以像这样传递整个编码

output = model(**encoding) 

关于记号赋予器,需要知道的另一件非常重要的事情是,如果需要,您可以指定检索特定的记号。例如,如果您正在进行掩码语言建模,并且您想要在模型解码的位置插入一个掩码,那么您可以像这样简单地检索掩码标记

mask_token = tokenizer.mask_token

您可以通过将它与您的输入文本连接起来,简单地将其插入到您的输入中。

您还可以用同样的方式检索许多其他标记,比如[SEP]标记。

我通常使用 tokenizer.encode_plus()函数来标记我的输入,但是还有另一个函数可以用来标记输入,这个函数就是 tokenizer.encode()。这是一个例子:

encoding = tokenizer.encode(text, return_tensors = "pt")

tokenizer.encode_plus()和 tokenizer.encode()的主要区别在于 tokenizer.encode_plus()返回更多信息。具体来说,它返回实际的输入 id、注意掩码和令牌类型 id,并在一个字典中返回所有这些内容。tokenizer.encode()只返回输入 id,并根据参数 return_tensors = "pt "以列表或张量的形式返回。

掩蔽语言建模

屏蔽语言建模是对句子中的屏蔽标记进行解码的任务。简单来说就是填空的任务。

我将演示如何获取掩码标记的前 10 个替换单词,而不是仅获取最佳候选单词来替换掩码标记,下面是您可以如何做:

from transformers import BertTokenizer, BertForMaskedLM
from torch.nn import functional as F
import torchtokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertForMaskedLM.from_pretrained('bert-base-uncased',    return_dict = True)text = "The capital of France, " + tokenizer.mask_token + ", contains the Eiffel Tower."input = tokenizer.encode_plus(text, return_tensors = "pt")
mask_index = torch.where(input["input_ids"][0] == tokenizer.mask_token_id)
output = model(**input)
logits = output.logits
softmax = F.softmax(logits, dim = -1)
mask_word = softmax[0, mask_index, :]
top_10 = torch.topk(mask_word, 10, dim = 1)[1][0]
for token in top_10:
   word = tokenizer.decode([token])
   new_sentence = text.replace(tokenizer.mask_token, word)
   print(new_sentence)

拥抱脸是这样设置的,对于它有预训练模型的任务,你必须下载/导入那个特定的模型。在这种情况下,我们必须下载用于屏蔽语言建模模型的 Bert,而正如我在上一节中所说的,标记器对于所有不同的模型都是相同的。

屏蔽语言建模的工作方式是,在您希望预测最佳候选单词的位置插入一个屏蔽标记。您可以简单地插入掩码标记,就像我上面所做的那样,将它连接到输入中所需的位置。用于屏蔽语言建模的 Bert 模型预测其词汇表中替换该单词的最佳单词/记号。在 softmax 激活函数应用于 BERT 的输出之前,logits 是 BERT 模型的输出。为了获得 logits,我们必须在初始化模型时在参数中指定 return_dict = True,否则,上面的代码将导致编译错误。在我们将输入编码传递到 BERT 模型中之后,我们可以通过指定 output.logits 来获得 logit,这将返回一个张量,然后我们可以最终将 softmax 激活函数应用到 logit。通过对 BERT 的输出应用 softmax,我们得到了 BERT 词汇表中每个单词的概率分布。具有较高概率值的单词将是掩码标记的更好的候选替换单词。为了获得 BERT 词汇表中所有单词的 softmax 值的张量以替换屏蔽令牌,我们可以指定屏蔽令牌索引,这是使用 torch.where()获得的。因为在这个特定的例子中,我正在检索掩码标记的前 10 个候选替换单词(通过相应地调整参数,可以得到 10 个以上),所以我使用了 torch.topk()函数,它允许您检索给定张量中的前 k 个值,并且它返回包含这些前 k 个值的张量。在此之后,过程变得相对简单,因为我们所要做的就是迭代张量,并用候选标记替换句子中的掩码标记。下面是上面代码编译的输出:

The capital of France, paris, contains the Eiffel Tower. 
The capital of France, lyon, contains the Eiffel Tower. 
The capital of France, lille, contains the Eiffel Tower. 
The capital of France, toulouse, contains the Eiffel Tower. 
The capital of France, marseille, contains the Eiffel Tower. 
The capital of France, orleans, contains the Eiffel Tower. 
The capital of France, strasbourg, contains the Eiffel Tower. 
The capital of France, nice, contains the Eiffel Tower. 
The capital of France, cannes, contains the Eiffel Tower. 
The capital of France, versailles, contains the Eiffel Tower.

您可以看到 Paris 确实是 mask token 的首选替换单词。

如果您只想获得第一个候选单词,可以这样做:

from transformers import BertTokenizer, BertForMaskedLM
from torch.nn import functional as F
import torch
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertForMaskedLM.from_pretrained('bert-base-uncased',    return_dict = True)
text = "The capital of France, " + tokenizer.mask_token + ",
contains the Eiffel Tower."
input = tokenizer.encode_plus(text, return_tensors = "pt")
mask_index = torch.where(input["input_ids"][0] == tokenizer.mask_token_id)
logits = model(**input)
logits = logits.logits
softmax = F.softmax(logits, dim = -1)
mask_word = softmax[0, mask_index, :]
top_word = torch.argmax(mask_word, dim=1)
print(tokenizer.decode(top_word))

我们不使用 torch.topk()来检索前 10 个值,而是使用 torch.argmax(),它返回张量中最大值的索引。代码的其余部分与原始代码基本相同。

语言建模

语言建模的任务是在给定句子中所有单词的情况下,预测跟随或继续句子的最佳单词。

import transformersfrom transformers import BertTokenizer, BertLMHeadModel
import torch
from torch.nn import functional as F
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertLMHeadModel.from_pretrained('bert-base-uncased',
return_dict=True, is_decoder = True)
text = "A knife is very "
input = tokenizer.encode_plus(text, return_tensors = "pt")
output = model(**input).logits[:, -1, :]
softmax = F.softmax(output, -1)
index = torch.argmax(softmax, dim = -1)
x = tokenizer.decode(index)
print(x)

语言建模的工作方式与屏蔽语言建模非常相似。首先,我们必须下载特定的 BERT 语言模型 Head Model,它本质上是一个 Bert 模型,上面有一个语言建模 Head。在实例化该模型时,我们必须指定的一个额外参数是 is_decoder = True 参数。如果我们想要使用这个模型作为预测序列中下一个最佳单词的独立模型,我们必须指定这个参数。代码的其余部分与屏蔽语言建模中的代码相对相同:我们必须检索模型的逻辑,但我们不必指定屏蔽标记的索引,我们只需获取模型最后一个隐藏状态的逻辑(使用-1 索引),计算这些逻辑的 softmax,找到词汇表中的最大概率值,解码并打印这个标记。

下一句预测

下一句预测是预测一个句子是否跟随另一个句子的任务。这是我的代码:

from transformers import BertTokenizer, BertForNextSentencePrediction
import torch
from torch.nn import functional as Ftokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertForNextSentencePrediction.from_pretrained('bert-base-uncased')prompt = "The child came home from school."next_sentence = "He played soccer after school."encoding = tokenizer.encode_plus(prompt, next_sentence, return_tensors='pt')
outputs = model(**encoding)[0]
softmax = F.softmax(outputs, dim = 1)
print(softmax)

下一句预测是预测一个句子对给定句子的下一句有多好的任务。在这种情况下,“孩子放学回家。”是给定的句子,我们试图预测“他放学后是否踢足球。”就是下一句。为此,BERT tokenizer 自动在句子之间插入一个[SEP]标记,表示两个句子之间的分隔,特定的 BERT For Next sense 预测模型预测该句子是否为下一句的两个值。Bert 在一个张量中返回两个值:第一个值表示第二个句子是否是第一个句子的延续,第二个值表示第二个句子是否是随机序列或者不是第一个句子的良好延续。与语言建模不同,我们不检索任何逻辑,因为我们不试图在 BERT 的词汇表上计算 softmax 我们只是试图计算下一句预测的 BERT 返回的两个值的 softmax,这样我们就可以看到哪个值具有最高的概率值,这将代表第二句话是否是第一句话的下一句话。一旦我们得到了 softmax 值,我们就可以简单地通过打印出来来查看张量。以下是我得到的值:

tensor([[0.9953, 0.0047]])

因为第一个值大大高于第二个指数,所以 BERT 认为第二句话跟在第一句话后面,这就是正确答案。

抽取式问题回答

抽取式问题回答是在给定一些上下文文本的情况下,通过输出答案在上下文中所处位置的开始和结束索引来回答问题的任务。以下是我回答问题的代码:

from transformers import BertTokenizer, BertForQuestionAnswering
import torch
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertForQuestionAnswering.from_pretrained('bert-base-
uncased')
question = "What is the capital of France?"
text = "The capital of France is Paris."
inputs = tokenizer.encode_plus(question, text, return_tensors='pt')
start, end = model(**inputs)
start_max = torch.argmax(F.softmax(start, dim = -1))
end_max = torch.argmax(F.softmax(end, dim = -1)) + 1 ## add one ##because of python list indexing
answer = tokenizer.decode(inputs["input_ids"][0][start_max : end_max])
print(answer)

与其他三个任务类似,我们从下载特定的用于问题回答的 BERT 模型开始,我们将两个输入标记化:问题和上下文。与其他模型不同,该模型的过程相对简单,因为它输出标记化输入中每个单词的值。正如我之前提到的,抽取式问题回答的工作方式是通过计算答案在上下文中所处位置的最佳开始和结束索引。该模型返回上下文/输入中所有单词的值,这些值对应于它们对于给定问题的起始值和结束值有多好;换句话说,输入中的每个单词接收表示它们是答案的好的开始单词还是答案的好的结束单词的开始和结束索引分数/值。这个过程的其余部分与我们在其他三个程序中所做的非常相似;我们计算这些分数的 softmax 以找到值的概率分布,使用 torch.argmax()检索开始和结束张量的最高值,并在输入中找到对应于这个 start : end 范围的实际记号,解码它们并打印出来。

使用 BERT 完成您想要的任何任务

尽管文本摘要、问题回答和基本语言模型特别重要,但人们通常希望使用 BERT 来完成其他不确定的任务,尤其是在研究中。他们的方法是获取 BERT 堆叠编码器的原始输出,并附加自己的特定模型,通常是一个线性层,然后在特定数据集上微调该模型。当在 Pytorch 中使用 Hugging Face transformer 库执行此操作时,最好将其设置为 Pytorch 深度学习模型,如下所示:

from transformers import BertModel
class Bert_Model(nn.Module):
   def __init__(self, class):
       super(Bert_Model, self).__init__()
       self.bert = BertModel.from_pretrained('bert-base-uncased')
       self.out = nn.Linear(self.bert.config.hidden_size, classes)
   def forward(self, input):
       _, output = self.bert(**input)
       out = self.out(output)
       return out

如您所见,我没有下载已经为特定任务(如问答)设计的特定 BERT 模型,而是下载了原始的预训练 BERT Model,它没有附带任何头部。

要获得原始 BERT 输出的大小,只需使用 self.bert.config.hidden_size,并将它附加到您希望线性图层输出的类的数量。

要使用上面的代码进行情感分析,这是一个令人惊讶的任务,没有下载/已经在拥抱脸变压器库中完成,您可以简单地在线性层的末尾添加一个 sigmoid 激活函数,并将类指定为等于 1。

from transformers import BertModel
class Bert_Model(nn.Module):
   def __init__(self, class):
       super(Bert_Model, self).__init__()
       self.bert = BertModel.from_pretrained('bert-base-uncased')
       self.out = nn.Linear(self.bert.config.hidden_size, classes)
       self.sigmoid = nn.Sigmoid() def forward(self, input, attention_mask):
       _, output = self.bert(input, attention_mask = attention_mask)
       out = self.sigmoid(self.out(output))
       return out

我希望您觉得这些内容很容易理解。如果你认为我需要进一步阐述或澄清什么,请在下面留言。

参考

拥抱变脸库

如何在 Python 中有效地使用注释

原文:https://towardsdatascience.com/how-to-use-comments-effectively-in-python-2a793014307f?source=collection_archive---------18-----------------------

如果使用得当,注释是一个很有价值的工具——这就是你应该如何最有效地使用它们。

(src =https://unsplash.com/photos/5KKglNl852A

介绍

软件工程师或数据科学家可能会使用许多工具来为他们的代码提供更多的表达。有很多原因可以让你这么做。例如,在需要教授的循序渐进的过程中,注释可能是宝贵的资产。注释还可以提供有价值的信息,这些信息对于处理某些代码是必不可少的。

我回想起一个例子,我不得不挖掘一些 Julia 代码,因为没有它的文档。我不知道某个东西的输入应该是如何构造的,但是我发现一些奇怪的注释存储在一边,解释了我需要的数据结构是如何呈现的,然后我的代码开始了比赛。虽然这绝对不是注释的最佳应用,但它确实坚定地证明了注释对于阐明某些观点是多么重要。我们不能指望文档包含开发人员可能想从最初的程序员那里了解的所有内部信息,这正是注释派上用场的地方。

然而,我想谈一点关于使用注释的原因是,虽然它们很简单,但实际上使用它们是一门艺术。也就是说,我发现在较新的程序员代码中发现一些相当可怕的注释是很常见的。很多时候,有些评论要么是矛盾的,要么是直接解释的…例如,我不需要一个评论告诉我你在做这个算术:

# divide x by 5
new = x / 5

如果对此有任何评论,它应该高于所有的算术,而仅仅是一个公式,例如:

# z = 3 * 2 + x / 5

然而,在这种特殊情况下,这仍然没有太大意义——因为这个表达式中只有一个独立变量。有那么多正确的地方可以评论,但结果也有那么多错误的地方和事情可以评论。所以事不宜迟,我想提供一些有效注释代码的个人技巧,以及 Python 编程语言的 PEP8 代码注释惯例。

PEP8 要说的话

首先,PEP8 指出代码需要与软件保持同步。随着给定注释集周围的代码发生变化,这些注释也应该重写。不适用于给定代码的注释比没有注释更糟糕。PEP8 还指出,注释应该用完整的句子。这当然是有适当的语法和标点的,比如一个句子以大写开头,以句号结尾。

# This would be a proper comment.
#this one isn't

当然,这有一个例外,如果我们有一个已存在的别名,我们应该在代码中遵守那个别名的大小写,比如这个例子:

# g is Jimmy's height
g = jimmys_height

# G is Jimmy's height
g = jimmys_height

在多句注释中,除了在最后一句之后,你应该在句末句号之后使用两个空格。当然,这些评论也应该具有可读性,并且易于理解。PEP8 的另一个奇怪的惯例是注释应该是英文的……“除非你 120%确定只有说你的语言的人会查看代码……”(直接引用)。)我发现这很有趣,因为我在一些非常流行的 Python 软件中看到过许多西班牙语或其他语言的评论。

还有一点,PEP8 说行内注释应该很少使用。明确地说,行内注释就是代码后面的注释。

我要说的是

首先,我想说的是,如果有一种负面的注释类型,我宁愿看到空白,那就是

多余的评论。

评论可以被过度使用,这绝对不是你想做的事情。因为你在解释你正在做的每件事而重复你的代码行不是一个好的编码实践。不要做这样的工程师:

# Multiply z and x to get b.
b = z * x
# Add five to b
b += 5
# Multiply slope by x and add b:
y = m * x + b

我们可以看到你在做什么!这不需要注释,只要看一下这个例子,您就能看出注释使代码更难阅读——而不是更容易?这一部分的一个更好的例子是用这个算法实际做了什么来标记它下面的整个代码,而不是用它所需要的操作来标记。

# Calculate the line.
b = z * x
b += 5
y = m * x + b

另外,在你的磅后面加一个空格也是程序员之间的约定。这绝对是一个可以遵循的好规则:

# Comment this.
#Not this.

我认为这类似于将操作符挤在数据旁边,这只是让东西难以阅读。另一件事是当描述一个短语时,要理解评论实际上属于哪里。想想之前的台词。我们不希望在任何地方添加内嵌评论,尤其是在这之后!

# This is correct.
b = z * x
b += 5    # This is not correct.
y = m * x + b
# Please do not do this.

您可以非常有效地使用注释来描述功能区域的目标,而不是描述单独的行。虽然有时这些确实是一个好主意,但请考虑我的 OddFrames.jl 包中的以下代码:

function OddFrame(file_path::String)# Create labels/columns from file.extensions = Dict("csv" => read_csv)extension = split(file_path, '.')[2]labels, columns = extensions[extension](file_path)length_check(columns)name_check(labels)types, columns = read_types(columns)# Get our coldata.coldata = generate_coldata(columns, types)# dead function."""dox"""head(x::Int64) = _head(labels, columns, coldata, x)head() = _head(labels, columns, coldata, 5)# drop function.drop(x) = _drop(x, columns)drop(x::Symbol) = _drop(x, labels, columns, coldata)drop(x::String) = _drop(Symbol(x), labels, columns, coldata)
# dropna function.dropna() = _dropna(columns)dtype(x::Symbol) = typeof(coldata[findall(x->x == x,labels)[1]][1])
# dtype function.dtype(x::Symbol, y::Type) = _dtype(columns[findall(x->x == x,labels)[1]], y)# Create the type.self = new(labels, columns, coldata, head, drop, dropna, dtype);select!(self)return(self);end

这些评论是针对 Julia 包的,但实际上这两个包在评论时应该没有太大区别。在这个例子中,我使用注释来解释我正在创建的数据——这些数据都包含在我们的类型中。我正在描述我想要的输出,您可以让代码解释我是如何到达那里的。我认为这是使用注释的一个很好的方式,因为它使得找出函数的特定区域变得不那么困难。

结论

老实说,评论是一个完整的主题,我认为从教育的角度来看,应该更加关注它。这是因为它们非常强大,但只有在正确使用的情况下。当然,这在很大程度上取决于程序员个人认为需要评论什么,这是非常主观的。关于什么该评论,什么不该评论,确实没有指南。

然而,使用这些建议来避免重复,从一个更广泛的角度来看问题,肯定会使你的评论比过去更有价值。我认为我们都可以不断改进这一点,我知道我肯定不会总是写评论,当我写评论时,它们可能非常模糊,也不是非常全面。在很多方面,我觉得好的代码不应该需要注释。如果你的代码很棒,那么它应该像读英语或其他什么一样可读。然而,话虽如此,我仍然发现如果使用得当,注释会有很大的好处,而且我肯定能看到它们在某些方面是如何有效的。我希望这个关于我们都可能犯过无数次的错误的小概述,特别是当涉及到 PEP8 方面的事情时,有助于使我们未来的代码看起来更好,并且通过准确、无冗余的注释更容易理解。感谢您阅读我的文章。

如何在机器学习模型中使用置信度得分

原文:https://towardsdatascience.com/how-to-use-confidence-scores-in-machine-learning-models-abe9773306fa?source=collection_archive---------0-----------------------

入门

从二进制分类教科书案例到现实世界的 OCR 应用。

与人类一样,机器学习模型有时会在根据输入数据点预测值时出错。但是也像人类一样,大多数模型能够提供关于这些预测可靠性的信息。当你说“我确信……”或“也许是……”时,你实际上是在给你对自己所说的话的自信程度赋予一个相对的资格。在数学中,该信息可以被建模为例如百分比,即 0 和 1 之间的数字,并且大多数 ML 技术提供这种类型的信息。

该置信水平的人机等价可以是:

“我确信……”<=>100%

“我认为是……”<=>70%

“我不知道,但我会说……”<=><50%

The main issue with this confidence level is that you sometimes say “I’m sure” even though you’re effectively wrong, or “I have no clue but I’d say…” even if you happen to be right. Obviously in a human conversation you can ask more questions and try to get a more precise qualification of the reliability of the confidence level expressed by the person in front of you. But when you’re using a machine learning model and you only get a number between 0 and 1, how should you deal with it?

Most common ML confidence scores

There is no standard definition of the term “confidence score” and you can find many different flavors of it depending on the technology you’re using. But in general, it’s an ordered set of values that you can easily compare to one another.

The three main confidence score types you are likely to encounter are:

一个介于 0 和 1 之间的十进制数字,可以解释为信心的百分比。

  • 优点:人类容易理解
  • 缺点:分数“1”或“100%”令人困惑。这很矛盾,但 100%并不意味着预测是正确的。

0 与+,或-与+

  • 优势:你几乎总是可以比较两个置信度得分
  • 弱点:对一个人来说没什么意义

一组表达式,如{ "低"、"中"、"高" }

  • 优点:非常容易操作和理解
  • 缺点:缺乏粒度,无法在数学函数中使用

重要技术说明:你可以使用任何双射函数转换[0,+[0,1 中的点],例如使用 sigmoid 函数,轻松地从选项#1 跳到选项#2,或者从选项#2 跳到选项#1(广泛使用的技术)。请记住,由于浮点精度的原因,从 2 切换到 1 或从 1 切换到 2 可能会丢失两个值之间的顺序。试着计算一下 sigmoid(10000)和 sigmoid(100000),都可以给你 1。

理解问题的一些指标

大多数情况下,决策是基于输入做出的。例如,如果你正在开车,收到“红灯”数据点,你(希望)会停下来。

当您使用 ML 模型做出导致决策的预测时,您必须让算法做出反应,如果它是错误的,将导致不太危险的决策,因为根据定义,预测永远不会 100%正确。

为了更好地理解这一点,让我们深入研究用于分类问题的三个主要指标:准确度、召回率和精确度。我们可以将这些度量扩展到分类以外的其他问题。

真阳性、真阴性、假阳性和假阴性

这些定义对计算指标非常有帮助。一般来说,它们指的是一个二元分类问题,在这个问题中,对一个拥有真值“是”或“否”的数据进行预测(要么是“是”,要么是“否”)。

  • 真阳性:预测“是”且正确
  • 真正的否定:预测“不”和正确
  • 误报:预测“是”和错误(正确答案实际上是“否”)
  • 假阴性:预测“否”和错误(正确答案实际上是“是”)

在接下来的部分中,我们将使用缩写 tp、tn、fp 和 fn。

准确(性)

准确性是最容易理解的指标。它只是数据集上正确预测的数量。例如,给定一个包含 1,000 幅图像的测试数据集,为了计算准确性,您只需对每幅图像进行预测,然后计算整个数据集中正确答案的比例。

假设你从这 1000 个例子中做出了 970 个好的预测:这意味着你的算法准确率是 97%。

当在假阳性和假阴性预测之间没有令人感兴趣的折衷时,使用该度量。

但是有时候,根据你的目标和你的决策的重要性,你可能想用其他的指标来平衡你的算法的工作方式,比如召回率和精确度。

精度公式:(tp + tn ) / ( tp + tn + fp + fn)

回忆(也称为敏感性)

为了计算算法的召回率,你只需要考虑测试数据集中真正“真实”的标签数据,然后计算正确预测的百分比。这是一个有助于回答以下问题的指标:“在所有真正的正值中,我的算法实际预测为真的百分比是多少?”

如果一个 ML 模型必须预测一个交通信号灯是否是红色的,以便你知道你是否必须开车,你更喜欢一个错误的预测:

  1. 虽然不是红色,但上面写着“红色”
  2. 虽然它是红色的,但上面写着“不是红色的”

让我们来看看在这两种情况下会发生什么:

  1. 你的车停下来了,尽管它不应该停下来。这只是轻微的危险,因为后面的其他司机可能会感到惊讶,这可能会导致一场小型车祸。
  2. 你的车不会在红灯时停下来。这是非常危险的,因为过马路的司机可能看不到你,造成全速撞车,造成严重的损害或伤害..

每个人都会同意情况(b)比情况(a)糟糕得多。在这种情况下,我们因此希望我们的算法永远不要说灯不是红色的:我们需要一个最大的回忆值,只有当灯是红色时算法总是预测“红色”,即使这是以灯实际上是绿色时预测“红色”为代价的,才能实现。

可以通过在测试数据集上测试该算法来测量召回率。它是一个百分比,除以算法预测为“是”的数据点数,再除以实际上为“是”值的数据点数。

例如,假设我们有 1000 幅图像,其中 650 幅是红灯,350 幅是绿灯。为了计算我们算法的召回率,我们将对我们的 650 个红灯图像进行预测。如果算法对这 650 张图片中的 602 张说“红色”,召回率将是 602 / 650 = 92.6%。这还不够!7%的情况下,存在全速车祸的风险。我们将在后面看到如何使用我们算法的置信度来防止这种情况,而不改变模型中的任何东西。

召回公式:tp / ( tp + fn)

精确度(也称为“阳性预测值”)

你的算法的精度让你知道当你的算法预测“正确”时,你可以信任它多少。它是正确猜测为“真实”的预测与所有猜测为“真实”的预测(其中一些实际上是“错误的”)的比例。

让我们现在想象一下,有另一个算法正在查看一条两车道的道路,并回答以下问题:“我可以超过我前面的车吗?”

再一次,让我们弄清楚一个错误的预测会导致什么。错误的预测意味着算法说:

  1. “你能超过那辆车”尽管你不能
  2. “不,你不能超过那辆车”尽管你可以

让我们看看在这两种情况下会发生什么:

  1. 你提高车速以超越你前面的车,然后你移动到你左边的车道(向相反的方向行驶)。然而,可能会有另一辆车在相反的方向全速驶来,导致全速撞车。结果:你们都受了重伤。
  2. 你可以超越你前面的车,但你会轻轻地跟在慢的司机后面。结果:什么也没发生,你只是损失了几分钟。

同样,每个人都会同意(b)比(a)更好。我们希望我们的算法只在“你可以超车”是真的时候才预测它:我们需要一个最大的精度,当它实际上是“不”的时候,永远不要说“是”。

为了测量测试集上的算法精度,我们计算所有“是”预测中真正“是”的百分比。

为此,假设我们有 1000 张超车情况的图像,其中 400 张代表安全超车情况,600 张代表不安全超车情况。我们想知道在我们的算法做出的所有“安全”预测中,真正“安全”的百分比是多少。

假设在我们的“安全”预测图像中:

  • 其中 382 个是安全超车情况:真=是
  • 其中 44 个是不安全超车情况:真相=否

计算精度的公式为:382/(382+44) = 89.7%。

意思是:89.7%的时候,当你的算法说你可以超车的时候,你实际上是可以的。但这也意味着 10.3%的时候,你的算法说你可以超越这辆车,尽管它不安全。精确度不够好,我们将看到如何通过置信度得分来提高精确度。

精度公式:tp / ( tp + fp)

度量摘要

您可以使用测试数据集(越大越好)估计以下三个指标,并计算:

  • 准确率:正确预测的比例— ( tp + tn ) / ( tp + tn + fp + fn)
  • 回忆:所有真实“是”数据中“是”预测的比例— tp / ( tp + fn)
  • Precision:所有“是”预测中真实“是”数据的比例— tp / ( tp + fp)

置信度阈值

在所有之前的例子中,我们认为我们的算法只能预测“是”或“否”。但是这些预测从来不会被输出为“是”或“否”,它总是一个数字分数的解释。实际上,机器总是以 0 到 1 之间的概率预测“是”:这是我们的置信度得分。

作为一个人,在给定 0 到 1 之间的置信分数的情况下,将预测解释为“是”的最自然的方式是检查该值是否高于 0.5。这个 0.5 是我们的阈值,换句话说,它是最小的置信度,超过这个值我们就认为预测是“是”。如果低于,我们认为预测为“否”。

然而,正如我们在前面的例子中看到的,犯错误的代价根据我们的用例而不同。

幸运的是,我们可以改变这个阈值,使算法更好地符合我们的要求。例如,让我们想象一下,我们正在使用一个返回 0 到 1 之间的置信度得分的算法。将阈值设置为 0.7 意味着您将拒绝(即在我们的示例中将预测视为“否”)所有置信度低于 0.7 的预测(包括在内)。这样做,我们可以微调不同的指标。

总的来说:

  • 提高阈值会降低召回率,提高准确率
  • 降低阈值会产生相反的效果

现在需要指出的重要一点是,上面的三个指标都是相关的。一个简单的例子是:

  • threshold = 0 意味着您的算法总是说“是”,因为所有的置信度得分都在 0 以上。你得到最小的精确度(你在每一个真正的“否”数据上都是错的)和最大的回忆(当它是一个真正的“是”时,你总是预测“是”)
  • threshold = 1 意味着您拒绝所有预测,因为所有置信度得分都低于 1(包括 1)。你有 100%的准确性(你说“是”永远不会错,因为你从来不会说“是”..),0%回忆(……因为你从来不说“是”)

试图设置最佳分数阈值无非是在精确度和召回率之间进行权衡。

精确召回曲线(PR 曲线)

要选择应用程序中要设置的最佳阈值,最常用的方法是绘制精确召回曲线(PR 曲线)。

为此,您将在一个测试数据集上,针对许多不同的阈值,计算算法的精度和召回率。一旦你有了所有的情侣(pr,re),你就可以把它们画在一张图上,如下所示:

PR 曲线总是以一个点开始(r = 0;p=1)按照惯例。

一旦你有了这条曲线,你可以很容易地看到蓝色曲线上的哪一点最适合你的用例。然后,您可以找出这个点的阈值,并在您的应用程序中设置它。

如何绘制你的 PR 曲线?

所有之前的例子都是二元分类问题,我们的算法只能预测“真”或“假”。在现实世界中,用例稍微复杂一点,但是所有之前的度量都可以通用化。

让我们举一个新的例子:我们有一个基于 ML 的 OCR,它对发票执行数据提取。这个 OCR 提取一堆不同的数据(总金额、发票号、发票日期……)以及这些预测的可信度分数。

我们应该为发票日期预测设置哪个阈值?

这个问题不是二元分类问题,要回答这个问题,绘制我们的 PR 曲线,需要定义什么是真预测值,什么是假预测值。

这里所有的复杂性是做出正确的假设,这将允许我们符合我们的二元分类度量:fp,tp,fn,tp

以下是我们的假设:

  1. 我们数据集中的每张发票都包含一个发票日期
  2. 我们的 OCR 可以返回一个日期,或者一个空的预测

如果与#1 不同,您的测试数据集包含没有任何发票日期的发票,我强烈建议您将它们从数据集中删除,并在增加更多复杂性之前完成第一个指南。这个假设在现实世界中显然不成立,但是如果没有这个假设,下面的框架描述和理解起来会复杂得多。

现在,让我们定义我们的指标:

  • true positive:OCR 正确提取了发票日期
  • 误报:OCR 提取了错误的日期
  • 正误:这种情况是不可能的,因为我们的发票上总是有日期
  • 假阴性:OCR 没有提取发票日期(即空预测)

在开始绘制我们的 PR 曲线之前,让我们考虑一下我们的模型和二元分类问题之间的区别。

在我们的 OCR 用例中,将阈值设置为 0 意味着什么?这意味着我们不会拒绝任何预测,但与二元分类问题不同,这并不意味着我们会正确预测所有的正值。事实上,我们的 OCR 可以预测错误的日期。

这意味着我们可能永远不会到达回忆为 1 的曲线点。将阈值设置为 0 时,通常会达到这一点。在我们的例子中,这个阈值将给出我们整个数据集中正确预测的比例(记住没有发票日期就没有发票)。

我们预计最终会有这样的曲线:

我们现在准备绘制我们的公关曲线。

步骤 1:对测试数据集的每张发票运行 OCR,并为每张发票存储以下三个数据点:

  • 这个预测正确吗?
  • 预测的置信度是多少?
  • 预测是否填充了日期(与“空”相对)?

第一步的输出可以是一个简单的 csv 文件,如下所示:

步骤 2:计算阈值= 0 的召回率和精确度

我们现在需要计算 threshold = 0 的精度和召回率。

这是最简单的部分。我们只需要将我们的每个预测限定为 fp、tp 或 fn,因为根据我们的模型化,不可能有任何真正的否定。

让我们算一下。在上面的例子中,我们有:

  • 8 个真阳性
  • 5 次误报
  • 3 个假阴性

在阈值为 0 的第一个例子中。,我们就有了:

  • 精度= 8 / (8+5) = 61%
  • 召回率= 8 / (8+3) = 72%

我们有了 PR 曲线的第一个点:(r=0.72,p=0.61)

步骤 3:对不同的阈值重复此步骤

我们刚刚计算了第一个点,现在让我们对不同的阈值进行计算。我们以阈值= 0.9 为例。

正如我们上面提到的,设置 0.9 的阈值意味着我们认为任何低于 0.9 的预测都是空的。换句话说,我们需要把它们都限定为假负值(记住,不可能有任何真负值)。

为此,您可以在我们的 csv 文件中添加一列:

在上面的 csv 文件中:

  • 灰线对应于低于我们阈值的预测
  • 蓝色单元格对应于我们必须将资格从 FP 或 TP 更改为 FN 的预测

让我们再算一次。

我们有:

  • 6 个真阳性
  • 3 次误报
  • 7 个假阴性

在阈值为 0 的第一个例子中。,我们就有了:

  • 精度= 6/ (6+3) = 66%
  • 召回率= 6 / (6+7) = 46%

这导致了我们的 PR 曲线的一个新点:(r=0.46,p=0.67)

对一组不同的阈值重复这一步,存储每个数据点,就大功告成了!

解读你的公关曲线

在理想情况下,您的测试集中有大量数据,并且您使用的 ML 模型非常适合数据分布。在这种情况下,随着回忆的增加,你会得到一条向下的公关曲线。

但是你可能没有很多数据,或者你可能没有使用正确的算法。在这种情况下,你得到的 PR 曲线可能是不成形的,是可利用的。

这是我们在 Mindee 绘制的真实世界 PR 曲线的一个例子,它与我们在日期字段上的收据 OCR 非常相似。

我们的测试集中有来自大约 20 个国家的 10k 个带注释的数据。日期字段的 PR 曲线如下所示:

任务完成了。现在,您可以选择曲线上对您的用例最感兴趣的点,并在您的应用程序中设置相应的阈值。

无论您的用例是什么,您几乎总能找到一个代理来定义适合二元分类问题的度量。这样,即使你不是数据科学专家,你也可以谈论你的模型的精度召回:两个清晰而有用的指标来衡量算法有多适合你的业务需求。

如何在 Matplotlib 中使用自定义字体——在 5 分钟或更短时间内

原文:https://towardsdatascience.com/how-to-use-custom-fonts-with-matplotlib-in-5-minutes-or-less-57c63ece2a11?source=collection_archive---------12-----------------------

使用自定义字体(包括 TTF)使您的可视化效果更加引人注目

默认情况下,Matplotlib 可视化效果会很难看。对你来说,幸运的是,几行代码就可以做很多调整。今天,我们将看看改变字体,并解释为什么它通常是一个好主意。

这篇文章的结构如下:

  • 自定义字体—为什么?
  • 使用内置字体
  • 使用 TTF 文件中的自定义字体
  • 结论

自定义字体—为什么?

为什么不呢?默认的不会让你走远。如果你的公司有一个独特的品牌,为什么不尽可能使用它呢?

让我们来看看默认样式是什么样子的。没有数据就没有数据可视化,所以让我们先声明一个简单的数据集。它包含一家虚构公司的虚拟季度销售额:

以下是数据集的外观:

图 1-虚拟可视化数据集(作者提供的图片)

让我们用折线图和散点图来展示这些数据。我们将保留大多数默认样式,只移除顶部和右侧的脊线:

这是视觉效果:

图 2 —使用默认字体的可视化效果(作者提供的图片)

正如你所看到的,字体看起来不错,但我不知道有哪个品牌使用 DejaVu Sans 作为他们的首选字体。接下来看看怎么改。

使用内置字体

Matplotlib 使得使用安装在机器上的字体变得容易。您可以使用以下代码片段列出前十种可用字体:

结果如下:

图 3-预装字体(作者图片)

如果您想要整个列表,请移除[:10]。您可以指定参数font的值,以便在标题或轴标签中使用感兴趣的字体。

以下代码片段向您展示了如何在标题中使用 Courier 新字体:

这是可视化效果的样子:

图 4 —预装系统字体的可视化效果(图片由作者提供)

但是你知道在使用之前不需要安装字体吗?你所需要的只是一个 TTF 文件。接下来让我们探索一下它是如何工作的。

使用 TTF 文件中的自定义字体

要跟进,请从这里(或任何其他地方)下载梅里韦瑟字体。解压缩文件,并将路径复制到文件夹。

从这里,我们可以使用 Matplotlib 中的font_manager从文件中添加字体。你需要在循环中一个接一个地添加字体。

添加后,我们将把整个 Matplotlib 字体系列设置为 Merriweather,这样我们就不必到处手动指定字体。

完成后,您可以像往常一样进行可视化:

结果如下图所示:

图 5 —使用自定义 TTF 字体的可视化效果(图片由作者提供)

这就是在 Matplotlib 中添加自定义字体有多简单!接下来让我们总结一下。

结论

今天的文章很短,但很中肯。你已经学会了如何将你的品牌融入到数据可视化中,如果你想在所有媒体上传递一致的信息,这是一项基本技能。

如果你喜欢这篇文章,请继续关注博客——更多类似的文章即将发表。

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@radecicdario/membership

了解更多信息

保持联系

原载于 2021 年 4 月 1 日 https://betterdatascience.com**

如何利用数据(和心理学)获得更多数据

原文:https://towardsdatascience.com/how-to-use-data-and-psychology-to-get-more-data-1749996ea704?source=collection_archive---------37-----------------------

约书亚·索蒂诺在 Unsplash 上拍摄的照片

在进行研究调查时,使用这些技巧平均能让我多得到 70%的回答

不幸的是,让人们填写调查问卷是一件复杂的事情。没有什么灵丹妙药能让每个人都一直填写。然而,我已经将一些技术组合在一起,当它们相互结合使用时,会有很大的帮助。

众所周知,好的数据和大量的数据对于构建任何工作模型都是必不可少的。因此,当你试图从公众那里收集数据时,这篇文章将帮助你增加你收集的数据量。

  • 首先,我将讨论杠杆突出理论及其对让个人填写调查的影响。
  • 其次,我将讨论使用机器学习(K-means)将个人分组到同类偏好的组中来对个人进行聚类。
  • 最后,我将讨论行为经济学和心理学揭示的人类内部的系统性非理性,以及如何将它们纳入您的调查邀请以提高接受度。

一份好的调查邀请函要阐明个人认为有吸引力的调查属性。

调查参与最突出的理论之一是杠杆突出理论。这个理论是由密歇根大学的格罗夫斯、辛格和康宁在 2000 年创立的。顾名思义,该理论利用调查特征的显著性来影响个人参加调查的概率。

下图将有助于解释这一点。一开始可能会让人觉得有点困惑和费解,但我会尽力解释。

https://www.jstor.org/stable/3078721?seq=1

该图显示了两个人面对两个独立的调查—一个在左边,一个在右边。成功概率(进行调查)是调查属性的系数加权和。

图表上圆圈的大小代表了勘测设计者对勘测各个方面的重视程度。例如,左侧调查中的“5 美元现金奖励”圆圈较大,因此在本次调查的调查介绍中更为突出。这可能是在标题中而不是副标题中提到的。支点(铅笔尖)代表个体的一个无关紧要的点,与支点的距离代表个体对属性的重视程度。球挂得越靠右,个人对这个属性的评价就越积极。以同样的现金激励为例,右边的人比左边的人更看重现金。这意味着现金激励比左边的人更有可能说服他填写调查。

因此,可以看出,面对两个独立调查的两个人之间的主要区别是一个向左倾斜,一个向右倾斜。图表越向右倾斜,个人回答调查的可能性就越大。

简而言之,人们重视不同的东西,我们需要设计调查邀请来说明这一点——突出好的,隐藏坏的。

不同的人对不同的东西有不同的价值——所以让我们把他们分成具有相同偏好的群体。

我相信你能发现,这其中的主要问题是人们对不同事物的重视程度不同。那么,我们如何着手设计一份调查邀请函来说明这一点呢?我们没有——我们设计了一些不同的。我们将个人聚集到具有相似偏好的群体中,然后针对这些群体定制邀请。还有一些所有人都重视的属性,这些属性几乎总是会产生积极的影响,但我将在下一节谈到这一点。

因此,你可能明白我的意思了。我们可以使用机器学习算法将个人分成我们认为具有相似偏好的群体。我们可以使用许多算法,但最常用的技术是 K-means 。K-means(经常与它的监督学习堂兄 KNN 混淆)使用最近的均值将数据划分到聚类中。我不会在这里深入 K-means 的细节,因为这不是这篇文章的内容。维基百科页面在这里是,Scikit-learn 文档在这里是我假设从现在开始,大多数人都知道 K-means 是如何工作的,如果你不知道,那么你真正需要知道的是,该算法根据个人的特征将他们分组。

K 表示行动中的(维基百科)

如果你想进一步了解如何用 K-means 对你的客户/参与者进行细分,请阅读这篇伟大的文章。我还必须指出,你最终选择的集群越多,你需要写的邀请函就越多,所以我从来不倾向于超过 k = 5。

标准 K 均值算法演示(维基百科)

好了,现在我们把所有的潜在参与者分组。然后,我们可以分析这些群体,并尝试辨别这些群体中的个人可能重视什么。这完全取决于你有什么数据。例如,如果您发现一个群体的平均年龄为 20 岁,平均收入为 10,000 英镑,而另一个群体的平均年龄为 50 岁,平均收入为 50,000 英镑,那么假设前一个群体可能更看重金钱并不是一个大胆的假设。在 Python/Pandas 中使用描述性统计的完整指南可以在这里找到。

我们星团平均年龄的一个例子。

然后,利用你愿意提供的任何金融服务来完成你的调查可能是明智的。在您的调查中直接提供资金并不总是一个好主意,因为这有各种各样的问题,我稍后会谈到。不过,为调查未来产品提供较大折扣将是一个好主意。

个人也看重同样的东西——来自行为经济学和心理学的见解

奇怪的是,尽管人们的偏好范围很广,但他们也倾向于同一方向。

个体就是我们行为经济学家所说的“系统性非理性”。因此,除了个体对激励的反应千差万别之外,某些事物也会吸引所有的个体。我们可以整合并利用这些有利于我们的偏见来增加调查的参与度,而不管我们是否已经聚集了个人。

下面我将重点介绍一些最常见的偏见,这些偏见被用来鼓励个人采取某些行动,以及如何在您的调查邀请中使用这些偏见。

互惠

1974 年,杨百翰大学的社会学家菲利普·昆兹向 600 名陌生人发出了手写的圣诞卡。他在验证一个理论,即如果你为某人做了好事,他们会回报你。他是对的。尽管没有一个人见过他,他还是收到了数百个回复。有些信长达 3 页,人们经常把家庭照片发给陌生人。在行为经济学中,我们称之为互惠准则——如果别人为我们做了积极的事情,我们会因为没有回报而感到非常不舒服。

因此,要求某人为你做某事的最佳时机是在你已经为他们做了某事之后。然而,这并不是双向的。只有在你已经为个人做了一些事情的情况下,这种方法似乎才有效。承诺以后做事就是不切实际。

因此,如果你刚刚提供了一些令人难以置信的客户服务,为什么不在你发送最后一封电子邮件时,请个人在调查中给你一些反馈。在这一点上,个人会比其他任何人更有责任感。这在业内开始变得相当普遍,如果你以前没有注意到这一点,我会感到惊讶。另一个常见的方法是预先给某人一些东西(比如他们下一个订单的 20%),然后立即让他们填写一份关于“他们如何能进一步帮助你”的调查。

让它社交

个人喜欢从众,他们喜欢做别人做的事。通常情况下,做决定是复杂且耗费精力的,因此个人只能求助于默认选项——其他人都在做的事情。因此,我们可以反过来使用这些知识。告诉人们‘嘿,其他人都在这么做,你也应该这么做’效果非常好。

英国政府正是通过这样做收回了数百万未缴税款一句话可以拯救百万。

因此,如果很多人在做你想让他们做的事情,那么告诉其他人,这部分人很可能会越来越多。

告诉你的客户 80%的人会留下一些反馈,这可能会鼓励其他人也这样做。这也带来了越来越多的回报——随着越来越多的人留下反馈,百分比会变得更高,球会继续滚动。

使之容易

这是最基本的常识,但是经常被忽视。人类很懒,我们不想使用不必要的努力——尤其是脑力。因此,请使调查(和介绍)简短,易于理解,并尽可能简单易用。大多数时候,在调查时,你想要的是个人首先想到的。让他们尽可能容易地提供它。不要让调查变得复杂,因为信息太多。

在信息可能有用的前提下抛出问题不是一个好策略。你应该事先有一个清晰简明的计划,知道你需要什么信息。这将有助于消除多余的问题,并消除参与者在完成一页而进度条几乎没有移动时的恐惧。

你为什么不直接付钱给他们?

在经济学中,我们有一个术语叫做挤出。该理论认为,在一个经济体中,公共部门的过度支出会压低或消除(挤出)私人部门的支出。奇怪的是,也有证据表明排挤与个人的道德意图有关。例如,Richard Titmuss 的一项著名实验表明,当个人有偿献血时,最终献血的人会减少。

因此,支付激励挤出了良好的意图(或自我感觉良好的激励)。就 LS 模型而言,这意味着调查的某些属性不兼容。正如这个例子所示,当个人收到现金激励时,他们就失去了向慈善事业捐款的激励。人们努力让自己感觉良好,做一些道德的事情,同时还能获得报酬。

当然,如果你付给某人 1000 英镑来完成一个 5 分钟的调查,你将很难在这个国家找到一个不这样做的人。但是,如果您可以选择为个人 1 提供一份 20 分钟的调查(例如癌症研究),那么向个人付费可能不是一个好主意。由于个人的良好天性,你可能会得到同样多的回应,如果不是更多的话。

结论:

因此,总结一下,下面是我在调查个人时的过程总结。

  • 个体差异很大,所以使用 K-means 等算法根据他们的偏好对他们进行聚类。使用描述性统计从这些群体中进行推断,并为他们定制调查邀请。
  • 在某些领域,个人会受到系统性的影响——诸如互惠、社会规范和从众倾向等偏见会显著提高回应的可能性。
  • 结合使用上述两种技巧,设计出量身定制且具有心理吸引力的调查邀请函。

我在针对标准调查邀请的 A/B 测试中多次测试了这种方法,正如所述,平均回报是回复率增加了 70%。

我希望这能有所帮助,如果你喜欢阅读,请不要犹豫跟随。以下是我的一些类似的文章。

干杯,

詹姆斯

如何在工业生产环境中使用数据科学

原文:https://towardsdatascience.com/how-to-use-data-science-in-industrial-production-environments-6accf24afeb2?source=collection_archive---------21-----------------------

关于如何在工业生产环境中使用数据科学的方法源于我的学士论文

Unsplash 上拍摄的 ThisisEngineering RAEng

这篇文章来源于我的工业工程学士论文“用数据科学技术进行生产数据分析”。我的论文来自真实的工业世界,所以我可以使用真实的工业数据,创建一个对我的论文有用的案例研究。

介绍

我研究了一个分三个阶段制造的特定对象:两个组装阶段和一个系统运行测试阶段。该系统已经批量生产了三年,因此操作员对他们的工作非常有信心。我的分析集中在装配线的流程交付时间(*)和两个装配阶段的周期时间(**)。在我的分析中,我还没有考虑操作测试周期时间,因为在过去的几个月中发生了一些变化,数据仍然有点脏。

这项研究的统计基础

在这个案例研究中,我使用回归模型来研究数据集;特别是:线性回归、多项式回归和样条回归。这个想法是细分每个操作员在两个装配阶段的周期时间;这样回归方法可以帮助我找到:

  • 每个装配阶段最快的操作员
  • 每个装配阶段的常量运算符

如何理解一个操作者在工作中是否恒常?从数学上讲,当一个变量在图表中是一条垂直线或水平线时,我们可以说它是常数;这就是回归,尤其是线性回归,帮助我的地方。

数据分析

现在来说说数据,看看数据分析是怎么做出来的。但是在继续之前,我必须说整个数据分析都是用 r。

流程提前期分析

首先,我研究了装配线流程提前期。我已经使用 r 中的“read excel”库导入了数据。绘制了一个散点图,其中“观察值”在“x”轴上,“流程交付时间”在“y”轴上,结果如下:

流程提前期分析。图片由作者提供。

正如我们所看到的,有很大的数据分散;事实上,我不得不使用双对数标度,以便图表可以在特定的维度上绘制。所以,我在这项研究中首先要面对的是数据清洗。我问自己:流程提前期的哪些值太小了?哪些数值过高?我可以用什么标准来排除过高和过低的值?

我决定使用高斯正态函数对数据集进行归一化,结果如下:

通过标准化数据绘制的图。图片由作者提供。

我们可以看到,这是一条右偏的高斯曲线;此时,我已经计算了平均值(m)和标准偏差(s ),并清理了(m-s;m+s)范围。数据清理后,我用线性回归线绘制了流程交付时间的散点图,结果如下:

清理流程交付周期数据:线性回归散点图。图片由作者提供。

我发现了一条负斜率线;这是什么意思?这意味着随着观察的增加,过程交付时间减少;但是为什么会这样呢?有两个答案:

  • 操作员已经在该系统上工作过多次,他们获得了专业知识
  • 外部修改已经使流程交付周期缩短

由于该系统已经制造了三年,正如我在本文开始时所说,流程交付周期缩短的正确答案是第二个。

正如我之前所说的,在过去的几个月中,一些变化使我避免研究功能测试周期时间;这些变化也会影响流程交付时间,从而缩短交付时间。

这是第一个结果:使用线性回归方法,流程交付时间随着负斜率线的减少而减少。

第一个装配阶段:周期时间分析

首先,我得说这个组装阶段是一个“标准阶段”。我所说的标准装配阶段是什么意思?我的意思是,所涉及的操作是典型的工业装配线;例如,在一个标准的,我们可以找到像螺丝,机械和物理装配等操作。为了更好地理解它,请考虑这样一个事实,即周期时间取决于操作员对该阶段的信心(他们做了数百次),而不是他们的手工技能。在第二个组装阶段,我们将了解什么是非标准的组装阶段,这样在本文的后面会更加清楚。

我已经确定了至少贡献了 400 次观察的操作员;操作符有四个:操作符 A、D、N、o。然后,我已经使用我们在流程交付周期分析中看到的相同方法清理了数据,所以我不再重复了。那么,让我们来看看第一个装配阶段的数据分析。

线性回归模型

我做的第一件事是对四个运算符进行线性回归,结果如下:

周期时间:四个操作员的线性回归散点图。图片由作者提供。

从图中我们可以看出,除了运算符 A,线性回归看起来是水平线;对于这个算符,直线有一点正斜率。当然,这种分析不足以得出任何结论。事实上——这也是这项研究的重点——统计学中的水平回归线有明确的含义:两个变量之间没有回归;换句话说,观察值和周期时间之间没有联系。

从数学上来说,我们可以在这里停下来说:“没有回归”,也许会中断研究。但是我们在一个工程领域,所以我问自己:“如果观察值和周期时间之间没有联系,这意味着什么?”。答案非常简单:对于任何观察,平均周期时间都是相同的;换句话说,操作者的周期时间是一致的;这是一个伟大的成果!

无论如何,这项研究还没有完成。我想深入回归方法,以表明那些水平线是真正水平的。怎么做呢?首先我做了一个残差分析。从残差分析来看,“多重 R 平方”值都接近于零。这发生在两种情况下:

1)线性回归模型不是描述数据的最佳方法

2)回归线真的是水平的

此外,通过残差分析,我可以找到每个操作员的周期时间;事实上,R 给了我们截距的值,由于这条线是水平的,这个值就是实际的周期时间。因此,在这一点上,我决定更深入地尝试用多项式回归模型来分析数据。

多项式回归模型

我问自己的第一个问题是:完美拟合数据的最佳多项式次数是多少?我怎么找到它?

回答这些问题有不同的方法:

  • 随着多项式次数的增加进行残差分析迭代
  • 随着多项式次数的增加进行图形迭代

选择这种方式或那种方式没有对错:无论如何,这是一个迭代的问题,决定何时停止迭代;但是我们什么时候停止?

对于残差分析,我们可以参考“调整后的 R 平方”值;一个好的方法是研究每次迭代的值;我们应该看到它在每次迭代中增加,在某一点上它应该减少;当它下降时,尤其是接近零时,这是一个好迹象,表明这与最符合数据的多项式次数有关。

相反,对于图形迭代,我们只是实现一个多项式回归,每次迭代的次数增加,我们可以用图形方式看到哪条曲线最符合数据;在一定程度上,这些曲线应该看起来都是相同的:我们只选择与“所有相似曲线”相关的最小程度。

在这个案例研究中,我使用了这两种方法,只是为了进行一些实践。

在下图中,我们可以看到四个运算符的迭代结果:

周期时间:四个操作员的多项式回归散点图。图片由作者提供。

通过分析图形,我可以说,对于算子 N 和 O,曲线实际上是一条线,呈现非常小的波动,但这些波动在域的边界上。与算子 D 相关的曲线似乎是可疑的,但在这种情况下,波动也在域的边界。相反,对于 operator A 曲线,毫无疑问:数据的最佳近似值是一条曲线(7 次曲线)。

总结:拟合操作员 A 数据的最佳曲线似乎是 7 次多项式。拟合运算符 N 和 O 数据的最佳曲线似乎是一条水平线。对于算子 D,曲线有些疑问:它甚至可能是一条水平线。为了更加确定这些结果,我使用了样条回归方法。

样条回归模型

为了简单起见,我使用了一个三次样条来研究数据。我已经决定沿着 x 轴在每个域的 25%、50%和 75%的位置上施加样条线结,这是一个相当标准的选择。

这是运算符 A 样条:

周期时间:操作员 A 样条散点图

相反,对于其他三个运算符,当尝试进行样条回归时,R 给了我一个错误,这是一个好结果;事实上,这意味着没有样条可以插值数据。因此,最符合数据的曲线实际上是一条(水平)线。

这一结论是对这一装配阶段研究的自然完成,因为对于这三个操作符,多项式回归方法对最符合数据的曲线留下了一些疑问。相反,样条消除了任何疑虑:因为没有样条,所以曲线实际上是每个操作符的一条线。

第二装配阶段:周期时间分析

应用于第二组装阶段的研究的方法论与之前相同,所以我只是直奔结果;但在此之前,有几件事要说。

这个装配阶段是非标准的。事实上,在这一阶段,操作者手动将垫圈施加到产品的整个外表面上。可以理解这一阶段与操作员的手工技能的关系。

因此,记住第一阶段的研究,这里的期望是发现大多数运营商显示周期时间振荡。

这意味着,对它们中的大多数来说,描述数据的最佳模型是样条模型。

因此,我发现四个操作者中有两个在周期时间中出现振荡,这些是他们的样条:

周期时间:操作员 A 样条散点图

周期时间:带操作员 D 样条的散点图

对于另外两个操作者,最好地描述数据的方法当然是一条水平线,这意味着它们在其周期时间内保持不变。

结论

最后,我想强调本研究中使用的方法的重要性,并谈谈本研究的一些可能的应用。

方法:对流程进行异常检测

这个案例研究的重要性依赖于方法,它是对流程的异常检测。事实上,对于每个操作者,我都进行了线性回归研究——首先找到了周期时间;然后,我通过多项式回归和样条回归来验证插值曲线是直线还是 n 次曲线。如果曲线是一条水平线,我们可以接受——就像我们在工程领域中一样——残差分析结果接近 0,这意味着该线在一定范围内是水平的(可能有一个小的正斜率或负斜率)。

因此,这种方法使我能够找到速度最快的操作员和/或在工作中最稳定的操作员,也就是那些在周期时间内呈现水平线的操作员。

这项研究的可能应用

该方法与操作员技能矩阵相结合,可用于:

1)根据数据,为每种产品找到最快和最稳定的运算符

2)拥有基于数据的替身操作员

3)在不参与生产环境的情况下研究生产时间,有几个好处:

3a)访问全部可用的历史数据,而不是对一小部分数据(在实际参与生产环境时注册的数据)做出假设。

3b)在生产环境中参与时,注册的数据不可能 100%干净。我的意思是,操作人员可能会有某种情绪上的参与,在他们的工作中感觉有点“被监督”。

因此,生产环境中唯一可用的注册数据只能为我们提供真实情况的一部分,此外,由于脏数据,这甚至可能是错误的。

— — — -

我想公开感谢卡洛·德拉戈教授对这项研究的指导

— — — -

(*)对于流程交付周期,我指的是完全制造某种产品所需的总时间。它从产品“进入”装配线开始计算,直到产品“离开”装配线

(**)周期时间是指完全完成一个制造阶段所需的时间。

我们一起连线吧!

中型

LINKEDIN (向我发送连接请求)

如果你愿意,你可以 订阅我的邮件列表 这样你就可以一直保持更新了!

考虑成为会员:你可以免费支持我和其他像我一样的作家。点击 这里 成为会员。

如何在 PyTorch 中为自定义文本数据使用数据集和数据加载器

原文:https://towardsdatascience.com/how-to-use-datasets-and-dataloader-in-pytorch-for-custom-text-data-270eed7f7c00?source=collection_archive---------2-----------------------

在本教程中,您将学习如何使用 PyTorch 中的 DataLoader 创建自定义数据集并管理它。

来源:https://thenounproject . com/term/natural-language-processing/2985136/

创建 PyTorch 数据集并使用 Dataloader 管理它可以保持数据的可管理性,并有助于简化您的机器学习管道。数据集存储所有数据,Dataloader 可用于迭代数据、管理批处理、转换数据等等。

导入库

import pandas as pd
import torch
from torch.utils.data import Dataset, DataLoader

熊猫对于创建数据集对象来说并不重要。然而,它是管理数据的强大工具,所以我打算使用它。

torch.utils.data 导入创建和使用数据集和数据加载器所需的函数。

创建自定义数据集类

class CustomTextDataset(Dataset):
    def __init__(self, txt, labels):
        self.labels = labels
        self.text = textdef __len__(self):
        return len(self.labels)def __getitem__(self, idx):
        label = self.labels[idx]
        text = self.text[idx]
        sample = {"Text": text, "Class": label}
        return sample

类 custom text Dataset(Dataset):创建一个名为‘custom text Dataset’的类,你可以随意调用这个类。传递给该类的是我们之前导入的数据集模块。

def init(self,text,labels): 初始化类时需要导入两个变量。在这种情况下,变量被称为“文本”和“标签”,以匹配将要添加的数据。

self.labels = labels&self.text = text:导入的变量现在可以通过 self . text 或 self . labels 在类内的函数中使用

def _ _ len _ _(self):这个函数被调用时只返回标签的长度。例如,如果数据集有 5 个标签,那么将返回整数 5。

def getitem(self,idx): 这个函数被 Pytorch 的 Dataset 模块用来获取一个样本,构造数据集。初始化时,它将循环通过这个函数,从数据集中的每个实例创建一个样本。

  • 【idx】传递给函数的是一个数字,这个数字就是数据集将要循环的数据实例。我们使用前面提到的 self.labelsself.text 变量与传入的' idx '变量来获取当前实例的数据。然后,这些当前实例被保存在名为“标签”和“数据”的变量中。
  • 接下来,声明一个名为' sample '的变量,它包含一个存储数据的字典。这存储在由数据集中所有数据组成的另一个字典中。在用数据初始化这个类之后,它将包含许多标记为“文本”和“类”的数据实例。你可以把“文本”和“类”命名为任何东西。

初始化 CustomTextDataset 类

# define data and class labels
text = ['Happy', 'Amazing', 'Sad', 'Unhapy', 'Glum']
labels = ['Positive', 'Positive', 'Negative', 'Negative', 'Negative']# create Pandas DataFrame
text_labels_df = pd.DataFrame({'Text': text, 'Labels': labels})# define data set object
TD = CustomTextDataset(text_labels_df['Text'],                               text_labels_df['Labels'])

首先,我们创建两个名为 【文本】和【标签】 的列表作为例子。

text_labels_df = pd。DataFrame({'Text': text,' Labels': labels}): 这不是必需的,但是 Pandas 是一个用于数据管理和预处理的有用工具,可能会在 PyTorch 管道中使用。在本节中,包含数据的列表“文本”和“标签”保存在 Pandas 数据帧中。

TD = custom text dataset(Text _ labels _ df[' Text '],Text _ Labels _ df[' Labels ']):这将使用传入的' Text '和' Labels '数据初始化我们之前创建的类。这些数据将成为该类中的“self.text”和“self.labels”。数据集保存在名为 TD 的变量下。

数据集现已初始化,可以使用了!

一些代码向你展示数据集内部发生了什么

这将向您展示数据是如何存储在数据集中的。

# Display text and label.
print('\nFirst iteration of data set: ', next(iter(TD)), '\n')# Print how many items are in the data set
print('Length of data set: ', len(TD), '\n')# Print entire data set
print('Entire data set: ', list(DataLoader(TD)), '\n')

输出:

数据集的第一次迭代:{'Text': 'Happy ',' Class': 'Positive'}

数据集长度:5

整个数据集:[{'Text': ['Happy'],' Class': ['Positive']},{'Text': ['Amazing'],' Class': ['Positive'],{'Text': ['Sad'],' Class': ['Negative']},{ ' Text ':[' unhappy '],' Class': ['Negative']},{'Text': ['Glum'],' Class ':[' Negative ']]}]]]]]

如何使用' collate_fn' 对数据进行预处理

在机器学习或深度学习中,需要在训练之前清理文本并将其转化为向量。DataLoader 有一个方便的参数叫做 collate_fn。 该参数允许您创建单独的数据处理函数,并在数据输出前将该函数内的处理应用于数据。

def collate_batch(batch): word_tensor = torch.tensor([[1.], [0.], [45.]])
    label_tensor = torch.tensor([[1.]])

    text_list, classes = [], [] for (_text, _class) in batch:
        text_list.append(word_tensor)
        classes.append(label_tensor) text = torch.cat(text_list)
     classes = torch.tensor(classes) return text, classesDL_DS = DataLoader(TD, batch_size=2, collate_fn=collate_batch)

例如,创建两个张量来表示单词和类。实际上,这些可能是通过另一个函数传入的单词向量。然后这个批处理被解包,然后我们将单词和标签 tensors 添加到列表中。

然后,单词张量被连接起来,类别张量的列表,在本例中为 1,被组合成单个张量。该函数现在将返回已处理的文本数据,准备用于训练。

要激活此功能,只需在初始化 DataLoader 对象时添加参数collate _ fn = Your _ Function _ name

训练模型时如何循环访问数据集

我们将在不使用 collate_fn 的情况下遍历数据集,因为这样更容易看到 DataLoader 是如何输出单词和类的。如果上述函数与 collate_fn 一起使用,那么输出将是张量。

DL_DS = DataLoader(TD, batch_size=2, shuffle=True)for (idx, batch) in enumerate(DL_DS): # Print the 'text' data of the batch
    print(idx, 'Text data: ', batch['Text']) # Print the 'class' data of batch
    print(idx, 'Class data: ', batch['Class'], '\n')

DL_DS = DataLoader(TD,batch_size=2,shuffle=True) : 这用我们刚刚创建的 Dataset 对象“TD”初始化 DataLoader。在本例中,批量大小设置为 2。这意味着当您遍历数据集时,DataLoader 将输出 2 个数据实例,而不是一个。有关批次的更多信息,请参见本文。Shuffle 将在每个时期重新排列数据,这将阻止模型学习训练数据的顺序。

for (idx,batch)in enumerate(DL _ DS):遍历我们刚刚创建的 DataLoader 对象中的数据。【DL _ DS】返回批次的索引号以及由两个数据实例组成的批次。

输出:

如您所见,我们创建的 5 个数据实例以 2 个为一批输出。因为我们有奇数个训练样本,所以最后一个样本在自己的批次中输出。每个数字— 0、1 或 2 代表一个批次。

完整代码

如何对时间序列数据使用深度学习

原文:https://towardsdatascience.com/how-to-use-deep-learning-for-time-series-data-f641b1b41a96?source=collection_archive---------3-----------------------

实践教程

了解时间序列深度学习的可用选项

埃里克·维特索Unsplash 上拍摄的照片

关于机器学习和数据科学,ime 系列数据通常被单独归为一类。然而,由于分布随着时间和顺序测试而变化,数据科学的这一领域可能很难管理。

本文将介绍三种不同的深度学习模型,用于基于时序数据创建预测模型。第一个将是 LSTM,随后是两个具有一维卷积和二维卷积的 CNN。

我包含了代码块,这样您可以通过简单地更新正在使用的数据和调整参数来复制和重用这些代码。

请随意将本页加入书签,以供将来参考。

请注意,这些模型可能比时间序列预测所需的要多得多。然而,从简单的模型和 2D 表格数据开始,您可以对您可能期望的性能进行基准测试。

要将时间序列数据转换为 2D 数据,请在整个可用时间段或时间段的子集内进行聚合。这里不讨论其他选择,其中最常见的是自回归(AR)模型。

数据,数据,数据

任何精通数据的科学家都知道,数据争论、操作和全面的数据工程是数据科学家最耗时的任务。特别是有了机器学习和深度学习,这个任务就更复杂了。例如,与使用表格数据(基本熊猫数据框架或 2D 数字阵列中的数据)的模型相比,时间序列数据需要额外的维度才能使模型正常运行。

将数据处理成三维或四维的直接方法是一次考虑一个实例。这样,您可以一次查看一个实例的数据,以在进一步转换之前确认正确的信息(如标准时间间隔)。

X = []for i in instances:
    # ‘df’ is a 2D pandas dataframe or numpy array
    df = generate_instance(i) # Produce a single instance here
    X.append(df)X_3D = np.array(X)
X_4D = X_3D.reshape((X_3D.shape[0], X_3D.shape[1], X_3D.shape[2], 1))

对于每个实例,创建一个 2D 数据帧或 numpy 数组。该数据帧的列将包含特征,行代表单个实例的不同时间步长。

一次创建一个实例,并将它们添加到列表中。一旦每个数据帧都在一个列表中,就转换成一个 numpy 数组,然后轻松地将信息输入到下面的模型中。

请注意,每个实例必须具有相同的尺寸。如果它们不同,你会得到一些令人兴奋的错误。

对于二维卷积,数据必须有一个额外的维度。对于多元时间序列数据,这意味着使用 reshape 函数添加另一个维度。

模型的结构

这些模型使用“relu”或 sigmoid 激活函数以及最终输出的 sigmoid 激活。

对于这些模型,您可以调整卷积层数、内核大小、过滤器数量、学习速率、密集层中的节点数量、LSTM 单元数量、批量大小和池大小。

这里的模型被建立来处理使用多元时间序列数据的分类问题,并使用二元交叉熵作为它们的损失函数。此外,这些模型包括根据其发生率的比例类加权。最后用 Adam 优化对整个网络进行优化。

T-CNN 模型:

两个 CNN 模型的结构遵循相似的格式:

  1. 数据经过一系列一维或二维的卷积层。
  2. 汇集层。合并后,输出被展平并连接到完全连接的图层。
  3. 在完全连接的层之后,产生预测的概率。

LSTM 模式:

  1. 数据通过具有可变数量单元的 LSTM 单元。
  2. 输出被展平并连接到完全连接的图层。
  3. 在完全连接的层之后,产生预测的概率。

结构故意保持相似。因此,很容易只交换 CNN 和 LSTM 模型之间不同的第一层。

超参数和导入

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Flatten, Conv1D, Conv2D, MaxPooling1D, MaxPooling2D
from tensorflow.keras.optimizers import Adam, schedules, SGDKERNEL_SIZE = 2
POOL_SIZE = 2
N_FILTERS = 24
BATCH_SIZE = 128
LEARNING_RATE = 0.00001
DENSE_UNITS = 50
LSTM_UNITS = 50
EPOCHS = 100N_STEPS = X.shape[1]
N_FEATURES = X.shape[2]
class_weight = {0: 1., 1: 1/np.mean(y_train)}ACTIVATION_FUNC = ‘relu’
FINAL_ACTIVATION = ‘sigmoid’LOSS_FUNC = ‘binary_crossentropy’
METRIC = ‘accuracy’
OPTIMIZER = Adam(learning_rate=LEARNING_RATE)# Split you own data from X_3D or X_4D, and a target
X_train, y_train, X_val, y_val = None
X_test, y_test = None

这里有几件事需要注意。我认为数据的第一个维度是实例的数量,第二个维度是时间步长的数量,第三个维度是特征的数量。对于 2D 卷积模型的四维数据,第四维是“虚拟”维度,以便进行适当的处理。然而,其余的维度保持相同的解释。

根据您为这些 Keras 型号使用的后端,了解订购很重要。不幸的是,约定并不一致,这可能是您错误的来源。如果是这种情况,请考虑调整数据的形状,以更改维度的顺序。

我还特意将训练、校准和测试数据设置为“无”,以便您可以根据自己的喜好调整数据分割。在拟合期间,校准集用于评估模型。

关于如何为不同类型的问题和训练模型分离数据的更多细节,你可以阅读这篇文章:

长短期记忆模型

长短期记忆模型(LSTM)是递归神经网络(RNN)的一种变体。这些模型由多个通道组成,数据可以通过这些通道来维护以前步骤中的信息,以便在将来的步骤中使用。

此处显示的预测模型中使用的 LSTM 单元遵循相同的结构。乍一看,它们看起来很复杂,但通过一些观察可以直观地解释。

穿过 LSTM 单元有两条主要路径;这些大致可以解释为短时记忆和长时记忆。短期是通过单元的底部路径,长期是通过单元的顶部路径。

LSTM 细胞(作者照片)

对于短期记忆,注意输入是如何被引导到这条路径的。正如人们对短期记忆的预期,模型与新数据 Xt 和上一步的输出相互作用。然后,该数据在单元中有几个可能的路径。

长期记忆是沿着细胞顶部的路径。这条路径有来自先前长期记忆输出的输入。然后通过细胞,基于来自几个不同通道的更新来更新长期记忆。

从短期到长期,LSTM 细胞的不同路径通过所使用的激活函数和中间输出的组合来最清楚地区分。

请务必注意,sigmoid 函数用于某些路径,双曲正切函数用于其他路径。这个选择是有意义的。这里的重要观察结果是,sigmoid 函数的输出为 0 到 1。相比之下,双曲正切函数的输出是-1 比 1。

现在,为什么会有区别呢?

在短期和长期记忆路径之间的第一个通道中,激活是 sigmoid 函数,这意味着输出在 0 和 1 之间。因此,这条路径决定了当前步骤的输入是否对长期记忆更重要。如果这个输出是零,那么这个输出和前一个长期记忆输出之间的最终乘积为 0。另一方面,如果这个输出更接近于 1,那么先前的长期记忆会持续。

第二和第三通道分别使用 sigmoid 和双曲线正切激活。这种组合作为一个两步过程,根据双曲正切函数的-1 到 1 输出来确定当前信息是否相关,以及它的贡献是正还是负。细胞的这一部分基本上回答了这两个问题。然后将当前时间步长对长期记忆的贡献添加到长期记忆中。

最终路径结合了当前时间步长和包含在长期记忆路径中的当前理解。这条通路的输出成为下一个 LSTM 细胞的输出。

LSTM 模型的设置

model = Sequential()model.add(
    LSTM(LSTM_UNITS, activation=ACTIVATION_FUNC, 
         input_shape=(N_STEPS, N_FEATURES) 
))
model.add(Flatten())
model.add(Dense(DENSE_UNITS, activation=ACTIVATION_FUNC))
model.add(Dense(1, activation=FINAL_ACTIVATION))model.compile(
    optimizer=OPTIMIZER,
    loss=LOSS_FUNC,
    metrics=[tf.keras.metrics.AUC(), METRIC]
)

卷积神经网络

卷积网络是深度学习中最复杂的模型之一;它们通常由许多不同的层组成,并且这些层可以有不同的行为。

与具有全连接层的标准神经网络相比,卷积神经网络使用卷积层、汇集层和全连接层。一些先进的模型甚至使用了这些层越来越复杂的变化。

卷积神经网络 CNN 通常与图像和视频机器学习应用相关联,因为它们能够有效地捕捉像素之间的关系,并建立开放的这些关系以模拟日益复杂的结构。

在其核心,这些网络依靠其卷积层来有效地捕捉邻近像素之间的关系。然而,这种架构不限于多维图像。例如,很容易将时间序列数据转换成与 CNN 一致的格式。

您还可以使用卷积来模拟时间序列中不同步骤之间的交互。与图像相反,一维卷积可以模拟先前和未来时间步骤的行为,以从系列中捕捉复杂的关系。

一些一维卷积非常常见,你可能在不知道的情况下使用过它们。例如,移动平均是一种卷积类型,其中每一步的权重相等。所以,粗略地说,你可以把一维卷积看作不同长度的移动平均。周期中的每个时间步长的权重不同。

卷积比较(作者供图)

1D 卷积—时间序列 CNN

model = Sequential()
# Add one or more convolutional layers
model.add(Conv1D(filters=N_FILTERS, kernel_size=10, activation=ACTIVATION_FUNC))model.add(MaxPooling1D(pool_size=2))
model.add(Flatten())
model.add(Dense(DENSE_UNITS, activation=ACTIVATION_FUNC))
model.add(Dense(1, activation=FINAL_ACTIVATION))
model.compile(
    optimizer=OPTIMIZER, 
    loss=LOSS_FUNC,
    metrics=[tf.keras.metrics.AUC(), METRIC]
)

当你有多个时间序列时,一维卷积仍然是可能的;但是,使用二维卷积组合不同的序列可以捕获更复杂的关系。

这些高维卷积捕捉不同时间序列之间的关系。

2D 卷积——时间序列 CNN

model = Sequential()
# Add one or more convolutional layers
model.add(Conv2D(
    filters=N_FILTERS,
    padding=”same”,
    kernel_size=(2,2),
    activation=ACTIVATION_FUNC,
    input_shape=(N_STEPS, N_FEATURES, 1)),
)model.add(MaxPooling2D(pool_size=2))
model.add(Flatten())
model.add(Dense(DENSE_UNITS, activation=ACTIVATION_FUNC))
model.add(Dense(1, activation=FINAL_ACTIVATION))model.compile(
    optimizer=OPTIMIZER,
    loss=LOSS_FUNC,
    metrics=[tf.keras.metrics.AUC(), METRIC]
)

拟合模型

为了训练每个模型,您可以使用以下相同的代码块。因为模型被假定为分类器,所以拟合包括类别权重。在大多数情况下,职业并不是完全平衡的,所以这个增加考虑到了这一点。

model.fit(
    X_train, y_train, epochs=EPOCHS,
    verbose=1, class_weight=class_weight,
    batch_size=BATCH_SIZE,
    validation_data=(X_val, y_val),
)

结论

时间序列问题有许多活动部分。然而,许多其他简单得多的模型也可以用于合理程度的性能。

当从多变量时间序列数据中创建分类器(或回归器)时,我还忽略了一些更多涉及时间的部分。两个最重要的是:

  • 当时间步长不一致时会发生什么,以及如何标准化数据和处理差距。
  • 深度学习模型架构如何优化,不是所有的模型都是生而平等的。虽然您可能不需要 100 层的网络,但您仍然可以从一些调整中受益。

然而,使用多元时间序列数据构建模型可能是一项令人愉快的任务。它迫使您不要将所有数据都视为可用于 scikit-learn 模型的表格数据。这些模型非常灵活,可以捕捉复杂的时间相关关系。你应该将它们添加到你现有的车型库中。

如果你有兴趣阅读关于新颖的数据科学工具和理解机器学习算法的文章,可以考虑在 Medium 上关注我。

如果你对我的写作感兴趣,想直接支持我,请通过以下链接订阅。这个链接确保我会收到你的会员费的一部分。

https://zjwarnes.medium.com/membership

如何对任意 GLM 使用弹性网正则化

原文:https://towardsdatascience.com/how-to-use-elastic-net-regularization-with-any-glm-6eab524bbcc6?source=collection_archive---------11-----------------------

思想和理论

斯坦福研究人员开发的新算法及其在 r。

广义线性模型(GLMs)是使用最广泛的推理建模技术之一。它们的简单性使它们易于解释,因此当向利益相关者传达因果推理时,它们是非常有效的工具。

弹性网正则化是一种广泛使用的正则化方法,是与 GLMs 的逻辑配对-它删除了不重要和高度相关的特征,这些特征会损害准确性和推断性。这两种方法是任何数据科学工具包的有用部分。

JESHOOTS.COMUnsplash 上拍照

在 2021 年 3 月之前,GLMs 和弹性网正则化的组合相当复杂。然而,斯坦福大学的研究人员发表了一篇论文,利用循环坐标下降允许有效计算任何链接函数的模型系数,而不仅仅是简单的链接函数。他们还在著名的 R 包 glmnet 中实现了这个模型。

在这篇文章中,我们将讨论 GLMs 的基本原理,弹性网络正则化,并了解这两者如何协同工作。让我们开始吧…

技术 TLDR

在 R 中, glmnet 包现在支持所有的链接函数族。如果您的链接是规范的,将一个字符串传递给family参数。如果没有,则传递一个家族函数。请注意,您可以查看文档以获得受支持的规范函数的列表。

在后端,这个包有两个主要的变化…

  1. 用 OLS 求解器替代最大似然法。注意,这仅适用于非规范链接函数——规范链接仍使用 OLS 求解。
  2. 用迭代加权最小二乘法(IRLS)求解。需要 IRLS(也称为费希尔评分),因为不保证最大似然是凹的。

好的,我想我明白了。但是这种新方法实际上是如何工作的呢?

让我们慢一点,从 GLM 实际工作方式开始。

什么是广义线性模型(GLM)?

GLM 是一个相当简单的概念,从 20 世纪 70 年代就有了。随着大数据的兴起,它们已经成为开发推理模型的宝贵工具,即,为我们的数据提供统计有效结论的模型。

为什么你会问?

嗯,GLM 的只是带有额外技巧的线性回归:链接函数。链接函数的目的是转换我们的因变量,以便线性模型能够更好地拟合。

让我们看一个简单的例子。

图 1:使用日志链接功能的 OLS 对 GLM。图片作者。

在图 1 的顶部,我们有一条由 GLM 拟合的指数曲线,没有连接函数。是的,这只是简单的线性回归。不是很合适,对吧?

因为我们知道数据大致遵循指数分布,所以我们使用带有对数链接函数的 GLM,并观察到更好的拟合(下图)。

从推理的角度来看,使用 GLM 拟合数据的主要好处是我们可以像线性回归一样解释系数。因此,在我们的例子中,X 的一个单位的变化导致 y自然对数的 1.007 的变化。如果您想更进一步,查看给定的 xy 的原始单位,我们可以取对数的倒数 exp(1.007 * x) ,以获得 x 的任意值的拟合 y

很有用吧?

现在,GLM 链接函数的选择取决于因变量的结构。在上面的例子中,我们的数据是连续的,看起来是指数型的,所以我们使用了对数分布。如果是整数数据,我们会使用泊松分布。如果它是连续的并且大致呈正态分布,我们将使用高斯(又名正态)分布。个人最喜欢的是 Tweedie 分布,它本质上是一种泊松分布,允许许多 0 值。

什么是弹性网正规化?

现在我们已经了解了 GLM 的,让我们看看这篇文章的主人公,弹性网正规化。

任何类型的正则化的目的是去除无用预测值的影响。此外,弹性网络正则化也不例外— 它移除了高度相关且不会提高我们模型准确性的预测因子。

因此,让我们假设我们正在寻找一个 GLM 来模拟股票价格(顺便说一下,这可能不是一个好主意)。我们的因变量是能源行业 ETFXLE的价格。我们的独立预测变量是:

  • 星期几
  • 前一天 XLE 的价格
  • 前两天 XLE 的价格
  • 前两天你衬衫的颜色

如果你用这些预测值来拟合价格,我们会认为一周中的天,昨天的 XLE 价格,两天前的 XLE 价格会高度预测今天的价格。遗憾的是,你的衬衫颜色对价格没有影响,因此弹性网会将我们的系数缩小到 0。

但是,我们有一个问题。如果我们观察昨天和两天前的价格之间的相关性,我们会注意到高共线性。共线性会阻止模型收敛并降低我们系数的可解释性,因此 elasitc net 发现了这一点,并降低了两天前的价格的系数。

第一种方法是通过将系数缩小到零来去除不重要的系数,这种方法称为拉索(或 L1)正则化。第二种方法是减少与其他预测因子相关的预测因子的系数大小,称为岭回归(或 L2 正则化)。

这两个组件协同工作被称为弹性净回归。

弹性网正则化的数学

随着一些直觉的发展,让我们看看 OLS 线性回归的弹性网的数学定义。

图 2:弹性网正则化公式。图片作者。

在图 2 中,我们可以看到,我们正在寻找能够最大限度降低方括号中值的模型系数。左边是 OLS 项,它计算误差平方和。在右边,我们有我们的弹性网正则化项。让我们快速定义一下这些变量…

稍微研究一下这个方程后,我们会注意到α是一个非常重要的参数。实际上,我们只允许 alpha 取 0 到 1 之间的值。因此,如果α= 0,L1 项抵消,我们最终得到岭回归。相反,如果α= 1,L2 项抵消,我们得到套索。

通常,我们希望获得岭和套索的好处,因此α-大约 0.5 既可以将系数缩小到零,又可以利用岭回归的系数缩减能力。

很酷,对吧?

最后一点:lambda 不是用户指定的参数。相反,用户指定一个 lambdas 范围,而弹性网试图确定最佳的一个。这里,lambda 完全控制偏差-方差权衡。如果 lambda 很大,我们会进行更多的正则化,从而创建一个低偏差/高方差模型。如果 lambda 为 0,我们将减少正则化并专注于准确性,从而创建高偏差/低方差模型。

这就是你要的——简而言之,弹性网络正则化。

为什么弹性网对所有的链接功能都不起作用?

正如您可能想象的那样,能够将弹性网络正则化应用于许多不同类型的链接函数是非常有用的。然而,直到最近,还有一些复杂的解决方法来让弹性网络与某些链接功能一起工作。但是斯坦福大学的研究人员取得了突破,他们一直在 R(编程语言)中率先使用 GLMs,他们开发了一种新方法,允许弹性网络为所有链接函数工作。

简而言之,OLS 最小化适用于规范的链接函数。在这种情况下,锥形意味着链接函数具有某些保证其形状为凹形的性质(想想抛物线,如 x )。其他更复杂的链接函数不一定有常数二阶导数,因此它们的形状可能会不规则,这使得找到全局最小值更加困难。

解决方案

新方法巧妙地避开了 OLS,而是利用了最大似然估计(MLE),这是另一种流行的拟合标准。最大似然法的缺点是它需要一个分步求解器——我们必须迭代地测试值,直到我们达到一个足够最优的解。最重要的是,MLE 并不总是保证全局最小值,所以从技术上讲,我们可能会错过一组更好的系数。

但是,在实践中,MLE 产生了稳健的结果。

R 中的解

如前所述,研究人员致力于提高 R 处理所有类型链接函数的能力。著名的 glmnet 包已经更新,支持规范和非规范链接函数。

但是,你怎么知道你的链接函数是否规范呢?

好吧,如果你的链接函数是高斯,二项式,泊松,多项式,考克斯,或者高斯,它是正则的。现在这不是一个完整的列表,但是这些是目前由 glmnet 支持的规范链接。

在编码方面,如果你的函数在那个列表中,你可以把链接函数族作为一个字符串传递。如果不是,你需要传递一个家族函数。参见下面的例子:

library(glmnet)# canonical exmaple - pass gaussian string
fit <- glm(y ~ x, family = **"gaussian"**)# non-canonical exmaple - pass quasi-poisson function
fit <- glm(y ~ x, family = **quasipoisson()**)

有了这次更新,我们现在可以选择任何最能代表我们数据的分布,不管它有多复杂。如果我们觉得有创意,我们甚至可以创造一些新的链接功能。

但是这个解决方案实际上是如何工作的呢?

新的优化算法使用了一种叫做循环坐标下降的方法。与基于梯度的优化不同,基于梯度的优化通过模型的导数(如随机梯度下降)来计算“山”,坐标下降使用原始数据。从那里,它沿着这些坐标移动,寻找全局最小值。

概念化这两者之间的区别的一个方法是通过思考旧金山这个城市。它有许多山丘,代表我们的特征空间。山的高度是我们的模型拟合的估计值,纬度和经度是正在优化的两个特征。

循环坐标下降使用旧金山的道路来寻找最低点,其中每条道路代表我们变量的不同组合。另一方面,梯度下降完全忽略了道路,只是以最陡的坡度下山。

图 3:循环坐标下降与随机梯度下降。图片作者。

循环坐标下降的好处是你不需要根据模型的导数计算一个完整的梯度,这对于某些链接函数是不可能的。

为了完整起见,我们将在这里讨论优化算法。这将是技术性的,所以请随意跳到实现说明和注释。

本文中标记为算法 1 的主要算法如下:

这里面有很多,但是让我们快速总结一下。在初始化了一组可能的λ值后,我们遍历每个值,并尝试最小化该值的损失,搜索最佳的λ值。然而,因为我们使用最大似然法而不是 OLS,我们需要使用循环坐标下降法。然后,我们希望在最后一步中最小化加权最小二乘(WLS)表达式,这涉及到另一个类似的算法。

我发现只盯着算法是有帮助的,但是如果你对细节感兴趣,可以看看论文的第 2.3 节。

实施说明

  • 当运行弹性网正则化时,通常我们要同时使用套索和脊。所以,最好尝试不同的α值,看看保留了哪些变量。如果你想要优化,使用交叉验证来找到 alpha 的最佳值是一个好主意。
  • 选择一个好的连接函数对于模型的准确性和稳定性至关重要。
  • 选择更“高级”的链接功能可以节省时间。一个例子是使用特威迪分布而不是零膨胀泊松分布——如果我知道特威迪分布,我可以在论文上节省很多时间。
  • 通常最好将预测值标准化,这样它们的范围就不会影响您的变量选择。z 分数也非常容易解释,如果需要,可以转换回原始单位。
  • R 中的 glmnet 包为 GLMs 的易用性铺平了道路。大多数其他语言落后于这个包几个发布版本,但是希望很快会有一个支持所有链接功能的 python 库。

感谢阅读!我将再写 44 篇文章,将“学术”研究引入 DS 行业。查看我关于使用 GLMs 进行推理建模的链接/想法的评论。

如何使用 fastai 评估 DICOM 医学文件

原文:https://towardsdatascience.com/how-to-use-fastai-to-evaluate-dicom-medical-files-738d7f7bc14d?source=collection_archive---------25-----------------------

开始 Kaggle 医学竞赛

机器学习意味着你可以像放射科医生一样看东西——📸疾控

Kaggle 竞赛可能会非常激烈,仅仅获得领域知识就需要做大量的前期工作。

我有相当多使用 fastai 的经验,现在,这并不意味着我总是在最后的比赛中使用它,但它是一个快速原型化和学习数据集的伟大工具。

本文将向您展示一些有用的技巧,帮助您快速了解 DICOM 医学文件及其相关数据。这篇文章不会包含所有的代码,这些代码在 Kaggle 上与大家分享。所以我会在这里添加一些片段,但会把你指向 Kaggle 上的完整笔记本。还用了惊艳 fastai 医学影像教程学习

你可能会问自己的第一个问题(或者如果你在谷歌搜索“fastai dicom 文件”就不会问):什么是 dicom 文件?

什么是 DICOMs?

DICOM 代表(DIImaging 和COcommunications inMedicine)并且是事实上的标准,其建立了允许医学图像(X 射线、MRI、CT)和相关信息在来自不同供应商、计算机和医院的成像设备之间交换的规则。DICOM 格式提供了一种合适的方法,该方法符合医疗信息交换(HIE)标准和 HL7 标准,HIE 标准用于在医疗机构之间传输与健康相关的数据,HL7 标准是使临床应用能够交换数据的消息标准

DICOM 通常与一个.dcm扩展名相关联。DICOM 文件真正令人惊奇的地方在于,它们提供了一种以单独的“标签”存储数据的方式,例如患者信息以及图像/像素数据。DICOM 文件由打包成一个文件的标题和图像数据集组成。

这是我们了解 fastai 如何让您快速查看存储在.dcm文件中的信息的好机会。如果你习惯使用 fastai,你会熟悉一些导入,但是要注意医疗导入。这对处理 DICOM 文件很重要。

from fastai.basics import *****
from fastai.callback.all import *****
from fastai.vision.all import *****
from fastai.medical.imaging import *****

import pydicom

import pandas **as** pd

我使用的数据集在 Kaggle 上: VinBigData 胸部 x 光异常检测。这是一场有趣的比赛;你可以阅读 Kaggle 上的信息了解更多。作为一个简单的教程,您将在下面看到我访问该文件的代码。该结构非常简单,有一个父文件夹“vinbigdata-胸部-x 射线-异常-检测”,以及包含 DICOM 图像的训练路径:

path = Path('../input/vinbigdata-chest-xray-abnormalities-detection')
train_imgs = path/'train'

接下来,您可以设置您的图像,以便可以阅读。

items = get_dicom_files(train_imgs)

Pydicom 是一个 python 包,用于解析 dicom 文件,使访问 DICOM 文件头以及将原始 pixel_data 转换为 python 结构变得更加容易。fastai.medical.imaging 使用 pydicom.dcmread 加载 dicom 文件。

要绘制 X 射线,我们可以在项目列表中选择一个条目,并用 dcmread 加载 DICOM 文件。在这里,我们可以编写一行简单的代码来查看与 dcm 文件相关的有趣的、有潜在价值的数据。

#add any number here to pick one single patient 
patient = 3xray_sample = items[patient].dcmread()

现在我们可以在 dicom 文件中查看标题元数据。

xray_sampleOutput:Dataset.file_meta -------------------------------
(0002, 0000) File Meta Information Group Length  UL: 160
(0002, 0001) File Meta Information Version       OB: b'\x00\x01'
(0002, 0002) Media Storage SOP Class UID         UI: Digital X-Ray Image Storage - For Presentation
(0002, 0003) Media Storage SOP Instance UID      UI: 7ecd6f67f649f26c05805c8359f9e528
(0002, 0010) Transfer Syntax UID                 UI: JPEG 2000 Image Compression (Lossless Only)
(0002, 0012) Implementation Class UID            UI: 1.2.3.4
(0002, 0013) Implementation Version Name         SH: 'OFFIS_DCMTK_360'
-------------------------------------------------
(0010, 0040) Patient's Sex                       CS: 'M'
(0010, 1010) Patient's Age                       AS: '061Y'
(0028, 0002) Samples per Pixel                   US: 1
(0028, 0004) Photometric Interpretation          CS: 'MONOCHROME2'
(0028, 0010) Rows                                US: 2952
(0028, 0011) Columns                             US: 2744
(0028, 0030) Pixel Spacing                       DS: [0.127, 0.127]
(0028, 0100) Bits Allocated                      US: 16
(0028, 0101) Bits Stored                         US: 14
(0028, 0102) High Bit                            US: 13
(0028, 0103) Pixel Representation                US: 0
(0028, 1050) Window Center                       DS: "8190.0"
(0028, 1051) Window Width                        DS: "7259.0"
(0028, 1052) Rescale Intercept                   DS: "0.0"
(0028, 1053) Rescale Slope                       DS: "1.0"
(0028, 2110) Lossy Image Compression             CS: '00'
(0028, 2112) Lossy Image Compression Ratio       DS: "2.0"
(7fe0, 0010) Pixel Data                          OB: Array of 5827210 elements

这里有很多信息,好消息是有一个很好的资源可以了解更多信息:

http://DICOM . NEMA . org/medical/DICOM/current/output/chtml/part 03/Sect _ c . 7 . 6 . 3 . html # Sect _ c . 7 . 6 . 3 . 1 . 4

最后,你可以看到一张真正的 x 光片。

xray_sample.show()

还记得上面那些看起来很有趣的元数据吗?你可能想知道如何让它变得有用?好消息是,你可以把这些数据放到一个数据框架中。

作为一个小提示。我将在下面添加两个版本的代码。一个用于 Google Colab 和点击链接查看更复杂的 Kaggle 版本。任何使用过 Kaggle 的人都知道,有时候你必须做一些改变才能让事情正常进行。

以下是将元数据放入数据帧的简单方法:

dicom_dataframe = pd.DataFrame.from_dicoms(items)dicom_dataframe[:5]

我将在下面添加一个截图,因为数据是 29 列,将离开页面。

希望这能对你们中的一些人有所帮助。接下来,我将设置边界框来检测 x 射线中的各种疾病。

如果有人在 fastai 和/或医学数据方面做了什么了不起的事情,我想听听!请在下面的回复中让每个人都知道你创造了什么,或者随时在 LinkedIn 上联系。

如何用第一性原理思维解决数据科学问题?

原文:https://towardsdatascience.com/how-to-use-first-principle-thinking-to-solve-data-science-problems-db94bc5af21?source=collection_archive---------11-----------------------

埃隆·马斯克解决问题的方式

莫尔·蒂亚姆在 Unsplash 上的照片

大约 2000 年前,亚里斯多德将【第一原理】定义为【认识事物的第一基础】。这个概念仍然非常相关,可以帮助您为复杂的数据科学问题提出创新的解决方案。第一原理思维背后的思想是将一个复杂的问题分解成它的基本部分,然后使用自下而上的方法来构建一个以前没有概念化的独特解决方案。

在本文中,我将向您解释如何应用第一原理思维来解决数据科学问题。为了简单明了,让我们考虑一下“客户流失问题”。为了帮助你理解第一原理思维的好处,我将首先展示如何使用传统方法解决这个问题,然后使用第一原理思维方法。

问题陈述:零售能源领域的客户流失

让我们假设“XYZ”是一家试图解决客户流失问题的零售能源公司。每年大约有 10%的客户流失,“XYZ”公司正在寻找减少客户流失的方法。

传统方法

解决问题的传统方法或最常用的方法是主观思维。也就是说,我们大多受已有假设或观点的影响。这种方法涉及的一般步骤是,

  1. 从现有的假设开始
  2. 根据假设确定需要逐步改进的领域
  3. 探索选项并选择最佳解决方案

现在,让我们考虑一下能源零售行业的客户流失情况,看看如何使用传统方法解决这个问题。如前所述,传统方法的第一步是从假设开始,

假设:

  • 与客户代理的糟糕经历会导致客户流失
  • 可以通过折扣/优惠来防止流失

基于上述假设,我们现在提出了可以帮助我们解决问题的解决方案。

  • 向不满意的客户提供折扣—我们可以通过检查投诉登记簿来识别不满意的客户
  • 专注于获得更多客户
  • 确定导致最多投诉的投诉类别,并使用表现最佳的代理来处理这些问题——这有助于避免给客户带来不好的体验
  • 确定高能耗消费者,并主动向他们提供折扣

以上是一些基于假设的解决方案。这里的优点是,

  • 这里确定的解决方案易于实现,不需要太多的努力。
  • 增量改进可以很快实现

但另一方面,缺点是,

  • 客户流失的主要原因没有得到解决
  • 无法作为长期战略持续下去

第一原理思维方法

现在,我将向您展示如何通过使用第一原理方法来解决客户流失问题。这种方法背后的主要思想是花尽可能多的时间去理解问题,然后试图解决它。就像爱因斯坦说的,

“如果我有一个小时来解决一个问题,我会花 55 分钟思考问题,花 5 分钟思考解决方案。”——阿尔伯特·爱因斯坦

理解问题

更好地理解问题的一个最好方法是尽可能多地提问。不要认为任何假设都是理所当然的。一直问问题,直到没有进一步的问题!

有助于更好地理解问题的一些问题是,

  • 每月有多少客户流失?
  • 客户流失的行业平均水平是多少?
  • 你的客户是什么样的?
  • 搅动的客户是什么样的?
  • 不同配置文件给客户带来的收入/利润是多少?
  • 客户流失的原因都是什么?
  • 客户什么时候会流失?有什么趋势吗?

所有这些问题有助于更好地理解问题,量化问题,也有助于确定当前的重点领域。如果你试图解决一个不同的问题,试着用下面的问题来理解它,

  • 有什么问题?
  • 问题有多大?(可以用美元或受影响的客户来量化)
  • 为什么会发生?
  • 谁面临这个问题?
  • 它什么时候发生?

将它分解

一旦对问题有了很好的理解,下一步就是开始分解问题。对于客户流失这个问题,我们先根据客户流失的原因来分解一下。这有助于区分可解段和不可解段。假设客户流失可以分为以下几类:

  1. 客户离开了我们不提供能源零售商服务的国家/州?
  2. 因业务关闭而流失
  3. 前 3 个月内的流失
  4. 成为常客超过 3 个月,然后流失的客户

以上原因,很少是可解的,其他都是不可解的。第 1 类和第 2 类是无法解决的,因为在第一类中,客户正在转移到能源零售商不提供服务的地方,而在第二类中,客户由于他们的业务关闭而搅动,从能源零售商的角度来看,没有什么可以做的。

第三类是客户在 3 个月内流失,这是一个问题,但这应被视为入职问题,而不是流失问题。由于这些客户没有花足够的时间来正式成为客户,他们几乎没有花任何时间。

所以,现在我们只剩下第四类了。这一类别的客户可以进一步划分成组,

  • 根据客户的终身价值、在平台上的年龄等将客户进一步细分。

这种细分实际上有助于识别需要立即关注的细分市场和可以忽略的细分市场。继续细分类别,直到单个组/类别变得更小

数据怎么说?

根据上述细分,确定需要立即关注的细分市场/类别。对于所有这些客户,探索他们跨不同业务部门的数据。就像在我们的客户流失问题中,需要做的分析是,

  • 客户的能源使用模式是怎样的?
  • 这些顾客抱怨过吗?解决这些投诉需要多长时间?谁处理这些投诉?
  • 最近 2 个月内是否与客户有过互动?
  • 是否有客户的能源账单出现峰值?
  • 这些客户中有谁收到过营销信息吗?

使用自下而上的方法求解

根据上述数据分析,找出导致客户流失的前 10-15 个场景。深入研究这些已确定的场景,假设我们有这样一个场景,客户就账单问题联系支持中心时,大多数情况下都是不了了之。我们需要确切了解导致这些客户流失的原因。原因可能是,

  • 这些类别的合规性需要更长的时间来解决?为什么它们需要更长的时间来解决?
  • 修改账单所需的时间要长得多。为什么他们需要更多的时间?

像上面一样,问尽可能多的问题,直到没有进一步的问题。这样,问题就一清二楚了,因此可以主动解决。

是什么阻止了许多数据科学家使用第一原理思维?

而我们可以清楚地看到,第一原理思维才是解决问题的方法。但是为什么数据科学家不在他们解决的所有用例中使用它们呢?

原因是时间。是的,“时间”是一项非常重要的资源,数据科学团队通常会处理具有不同重要程度的多项任务,因此可能会有一些问题不值得使用绝对没问题的第一原理思维方法来解决。

但是,当有一个对业务有更大影响的业务问题时,最好使用第一原则思维方法来解决,而不是采用增量增强。

结束语

有许多数据科学项目时不时会失败。虽然技术挑战仍然是许多失败的关键因素,但也有失败是由于缺乏对业务问题的理解。没有很好地理解问题的首要原因是因为组织试图关注太多的问题,并且经常面临过快交付结果的压力。在这个视频中,我分享了一些使用第一原理思维解决数据科学问题的技巧

保持联系

如何在报告中使用 GETDATE()

原文:https://towardsdatascience.com/how-to-use-getdate-for-reports-d8cdc504a261?source=collection_archive---------33-----------------------

不再需要手动调节!

照片由 Manavita S via Unsplash 拍摄

只需复制并粘贴这个查询,转到 WHERE 子句,将其更改为上周,然后运行它。这很简单!”—一些你可能认识的人

每天/每周/每月手动更改查询中的值可能会非常痛苦。这也为人为错误打开了大门。我们将回顾 SQL 的 GETDATE()函数的强大功能,如何将它包含在查询中(例如,也许您有一个总是上周数据的报告),以及非常重要的是,如何避免日期/周范围的一些问题。

这东西到底有什么用?

和所有工具一样,理解一个函数的作用是非常有帮助的。今天的日期是 2021 年 8 月 27 日。让我们看看运行一个 GETDATE 会给我们带来什么(格式为' yyyy-MM-dd '):

作者照片

它会得到执行的日期。当你在《第六感》中发现布鲁斯·威利斯一直都死了的时候,你可能不会有那种惊天动地的震惊……但也很接近了。

自动化上周的报告

因此,假设您每周一都有需要提取的数据。该报告只包括前一周的数据。不包括上周或部分当前周之前的周。

为此,你需要一些日历表。在其中,理想情况下,您将拥有一个一年一周的组合列。请在年和周之间包含某种分隔符。如果你的公司还没有这个,我假设你正在你自己的电脑/手机上阅读这篇文章,因为你的公司可能还没有电脑。

现在,很明显,查看今天的日期不会给出我们所说的上周的信息。让我们来看一个表格,其中包含本周和上周的“日历日期”和“年份周”列。

作者照片

GETDATE() — 7?

您可能习惯于使用 DATEADD 函数,其中一个参数是数字,另一个参数是间隔类型(年、日等)。).当使用 GETDATE 时,你可以简单地说“-7”来获得一周前的日期。现在让我们看看当我们从“calendar_table”中选择 GETDATE()和 GETDATE( ) — 7 时会得到什么。

作者照片

假设我们在星期一运行它。在本例中,我们可以选择 2021–08–16 作为上周的星期一,并提取“year_week”等于“calendar_table”中的值的所有数据,在本例中也是“2021–33”。如果我们在周日运行,上周周日的“year_week”将是我们要使用的变量,仍然是“2021–33”。周六也可以。你明白了。事情正在好转。

我们在赚钱,恰恰,恰,恰。我们在赚钱,恰恰,恰,恰。我们在赚钱,恰恰,恰,恰。恰恰,恰,恰,恰,恰,恰,恰,正!—帕梅拉·普金

齐心协力

有多种方法可以做到这一点。我们可以使用子查询来选择“year_week ”,并将该子查询放在 WHERE 子句中。我们可以将需要的日期内联。我们甚至可以创建一个变量来存放这个值。

对于这个例子,我推荐使用变量 route,因为当您开始进入更多的临时表、CTE 或子查询以引入多个表时,命名一个变量并将其包含在每个表的 WHERE 子句中可以节省时间。从长远来看,它还减少了代码行数。

现在我们有了“daily_sales”表,我们只想提取上周的行。下面是结果,后面是代码,最后是使用“year_flag”列的有用信息。

作者照片

注意,例如,如果我们想要包含一个滚动的 6 周期间,我们可以创建两个变量。另一个变量可以设置为 GETDATE 之前的不同天数。然后,我们可以在两个“year_week”值之间提取行。

为什么前导零很重要?

当创建这个“year_week”列时,非常需要使用一个前导 0 来表示一位数的周。本质上,这些值将像字母一样被读取,0 =A,1 = B,等等。按字母顺序思考这个问题,我们可以看到如果没有前导 0,拉取和排序结果会是什么样子。在本例中,我们提取了“2021–1”和“2021–3”之间的值。

请注意,第 10 周、第 105 周(只是为了展示)、第 11 周和第 12 周都包括在内。在我们的“日历表”中,我们只有第 1–12 周(加上 105 周)。不包括 13 周以上。如果是这样的话,10 到 29 之间的所有星期都会出现。第 30 周不会出现,因为那是 D 后面的 DA。

作者照片

在本例中,我们可以看到,如果我们按“year_week”或“year_week_alpha”排序,我们会得到相同的结果。

天空是无限的!

我们不仅限于按天或按周划分范围。我们可以发挥创意,使用季度或年度。我们可以设置像年初至今这样的事情。

我们甚至可以使用一些规则,比如“总是在输出中包括至少 10 周(如果需要的话,返回到上一年),但是在新的一年的第 10 周之后,然后包括本年度的所有周并删除去年的周”。当新的一年开始,人们不希望在 Power BI 报告中看到可视化的一周的数据时,类似这样的东西会很有帮助。

关于连接和联合的更多信息,请查看这篇更详细的文章。一如既往,有趣的可视化和超级爸爸笑话包括在内。

最后的想法

SQL 是一个强大的工具,它让生活变得更加简单。如果使用得当,它可以节省大量时间。当使用常规查询时,GETDATE()函数是一个包裹在温暖的小狗模糊闪光云中的祝福。

这是我们今天的课。一如既往,继续学习!

如何在 SQL 中使用 Group By 和 Partition By

原文:https://towardsdatascience.com/how-to-use-group-by-and-partition-by-in-sql-f3d241846e3e?source=collection_archive---------3-----------------------

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

简介

当我第一次学习 SQL 时,我有一个问题,就是如何区分通过划分的和通过分组的,因为它们都有一个用于分组的函数。相信很多开始接触 SQL 的人可能都会遇到同样的问题。因此,在这篇文章中我想和你分享一些使用 PARTITION BY 的例子,以及它和 GROUP BY 在 select 语句中的区别。

探测

抽样资料

首先,我创建了一个包含 4 列的简单数据集。下面的 df 表格描述了不同职能部门的每位员工在公司旅行中会携带的金额和水果种类。

图 1: 测向表

图 2:测向信息

分区由 vs 组由

下面是 Partition By: 的语法

SELECT expression 1, expression 2, ...
aggregate function () 
OVER (PARTITION BY expression 1 order_clause frame_clause)
FROM table

当我们想要在特定的列上进行聚合时,我们可以应用带有 OVER 子句的 PARTITION BY 子句。让我们看看下面的例子,看看数据集是如何转换的。

图 Partition By 子句的输出

在示例中,我想计算每个函数为旅行带来的总收入和平均收入。截图中可以看到的是我通过查询分区的结果。

现在,如果我在上面的例子中使用 GROUP BY 而不是 PARTITION BY ,结果会是什么样子?

首先, GROUP BY 的语法可以写成:

SELECT expression 1, expression 2
aggregate function ()
FROM tables
WHERE conditions
GROUP BY expression 1, expression 2

当我将它应用到查询中以查找每个函数中的总金额和平均金额时,聚合输出类似于由子句划分的分区。然而,正如您所注意到的,图 3 的和图 4 的结果有所不同。

图 Group By 子句的输出

  • GROUP BY 给出公司中每个职能的结果(图 4)。同时,由于我们在 df 表中有 7 条记录,PARTITION BY 检索所有 7 行,每行有 total_amount 和 average _ amount(图 3)。因此,总之, PARTITION BY 检索表中的所有记录,而 GROUP BY 只返回有限的数量。
  • 还有一点就是 GROUP BY 不允许在 select 语句中添加不属于 GROUP BY 子句的列。但是,使用分区 BY 子句,我们可以添加所需的列。

按行号进行分区

我们可以通过和行号组合分区,使行号按特定值排序。例如,如果我想看看每个函数中的哪个人带来的钱最多,我可以很容易地通过将 ROW_NUMBER 函数应用于每个团队,并获得每个人的钱数(按降序排列)。

图 5:行号函数示例

用累积值进行分区

分区由+行无界前置

为了更容易想象,我将从一个例子开始解释这一部分的思想。

我创建了一个新表,命名为 df8

图 6:新数据帧(df8)

通过应用 ROW_NUMBER ,我得到了按每个函数中每个雇员的金额排序的行号值。基本上直到这一步,在图 7 中可以看到,一切都和上面的例子差不多。

图 7:输出

但是,由于我想再计算一列,这是当前行的平均金额和分区中当前行之前的较高值金额。例如在图 8 中,我们可以看到:

  • 在技术团队中,仅萨姆一人就有平均 40 万的累积金额。
  • 但是,在技术小组的第 2 行,平均累计金额是 340050,等于(Hoang 的金额+ Sam 的金额)的平均值。
  • 在第 3 行中,Dung 的钱数低于 Hoang 和 Sam,所以他的平均累计金额是(Hoang、Sam 和 Dung 的金额)的平均值

= >这是关于 ROWS UNBOUNDED PRECEDING 和 PARTITION BY 子句如何一起使用的一般概念。

图 8:使用前面无界的行的累积平均量

当前行和 1 之间按+行划分

这种组合的用途是计算分区中当前行和下一行的聚合值(平均值、总和等)。让我们继续使用【df9】数据来看看这是如何实现的。

图 9:当前行和 1 个 之间使用 行的累计平均金额

图 9 中,我们可以得出:

  • 在技术功能第 1 行中,Sam 的平均累计金额为 340050,等于她和她在第 2 行中的跟随者(Hoang)的平均金额。
  • 然后,Hoang 的平均累积量是第 3 行中 Hoang 的量和 Dung 的量的平均值。

结论

在本文中,我提供了我对由划分分区和由划分组的理解,以及使用分区的一些不同情况。希望以上信息对你有所帮助。****

参考

https://www.sqlshack.com/sql-partition-by-clause-overview/

如何使用 Horovod 的大批量模拟来优化(高度)分布式训练的超参数调整

原文:https://towardsdatascience.com/how-to-use-horovods-large-batch-simulation-to-optimize-hyperparameter-tuning-for-highly-a815c4ab1d34?source=collection_archive---------20-----------------------

理解大数据

一个简单的技术可以帮你省下一大笔钱,以及如何将它与混合精确学习相结合

杰瑞米·托马斯Unsplash 上拍照

加快学习速度的愿望激励,今天深度学习领域的一个常见做法是将培训活动分配给多个工作人员(例如 GPU)。在数据分布式训练中,每个工人并行地对训练数据的不同子集(本地批次)执行训练步骤,向所有其他工人广播其结果梯度,并基于所有工人计算的梯度更新其模型权重。

在之前的帖子中,我们扩展了数据分布式培训的一些复杂性和潜在挑战。在本帖中,我们将重点关注在数据分布式训练环境中执行超参数调整的挑战。

我要感谢 Dennis Kreinovich 对分布式训练和混合精度的贡献。

介绍

任何深度学习项目必不可少的一部分就是超参数调优。模型超参数是我们在运行训练算法之前修复的所有控制设置。它们不同于在训练期间学习的模型参数。常见超参数的示例包括:

  • 优化器设置:优化器的选择和控制它的设置,例如学习率
  • 模型架构:模型层的选择,它们是如何组合在一起的,以及它们是如何配置的。这包括每层的通道数、卷积核的大小、正则化设置、辍学率、批量归一化设置、激活函数的选择等设置。
  • 损失函数:损失函数的选择及其各自的配置设置。

不用说,超参数的选择对我们训练算法的成功有决定性的影响。超参数整定 (HPT)指的是为这些超参数寻找最优值的艺术,也就是寻找最终会导致最优训练结果的值。应当注意,对超参数的所有可行组合进行完全搜索实际上是不可能的。在实践中,大多数团队会修正大量的超参数,并将 HPT 限制到训练控制的子集。它们可以通过限制剩余超参数的搜索空间来进一步简化问题。

每一个成功的深度学习项目都包括某种形式的 HPT,即使在名称上没有明确地这样称呼。当你尝试使用额外的卷积层或信道,或者使用不同的学习率、正则化值、退出率或激活层来训练你的模型,只是为了看看它如何影响你的结果的质量时,你正在执行 HPT。当然,你在 HPT 战略上投入的越多,你成功的可能性就越大。以下是影响 HPT 战略优势的一些方面。

1。高级参数搜索算法
给定一个参数搜索空间,有多种方法可以进行搜索。琐碎的算法有随机搜索网格搜索。在随机搜索中,我们随机选择参数组合。在网格搜索中,我们将搜索空间分成一个网格,并在网格的交叉点上测试组合。然而,有许多基于贝叶斯优化的更高级的算法,已经被证明比随机搜索网格搜索执行得好得多(例如,参见这里的)。在撰写本文时,深度学习的 HPT 搜索算法仍然是一个活跃的研究领域。

2.实验并行化

显然,并行运行实验将加速 HPT 阶段,使您能够更快地得出关于最佳超参数的结论。然而,由于并行运行 N 个实验,潜在的好处可能比线性(乘以 N)加速要大得多。这是因为并行化增加了实验提前终止的可能性。让我们通过一个简单的例子来证明这一点。假设我们将 HPT 算法定义如下:

  • 每个实验最多训练 8 个时期(或固定步数),并在每个时期后评估准确度。
  • 在每个时期之后,我们将每个实验的准确度与达到相同步骤的所有其他实验的准确度结果进行比较。任何精度比最高计算精度差 10%以上的实验都将被终止。当一个实验提前停止时,它的相关资源可以用于后续的实验。
  • 如果一个实验是唯一剩下的实验,或者如果它以最高的准确度完成了 8 个时期,则该实验被宣布为获胜者。

现在,假设在我们的 HPT 中的给定阶段,我们正在运行 4 个实验,这些实验将产生下表所示的精度:

样本精确度

如果我们并行运行所有四个试验,我们将在 1 个时期后终止试验 3,在 2 个时期后终止试验 2,在 4 个时期后终止试验 1 和试验 4,此时试验 4 将被宣布为获胜者。给定阶段将总共运行 11 个时期。另一方面,如果我们在实验中选择随机顺序并按顺序运行它们,通过应用简单的概率论定律,我们会发现总时期数的期望值将是 19.6。在这种情况下,并行化带来了 44%的预期节省。虽然这个例子是人为设计的,但是节省这么多钱的可能性并不遥远。节省的潜力只会随着并行化程度的增加而增加。

3.自动化

可以想象,人们可以定义参数搜索空间,选择 HPT 算法,手动实例化所有实验,并监控它们的进展。然而,HPT 算法的手动实现可能缓慢、乏味,并且极易出错。更好的建议是将 HPT 自动化。有许多工具和库支持 HPT 自动化。这些不同之处在于它们为不同的训练环境、搜索算法、并行化、早期停止等提供的支持。最流行的库之一(在撰写本文时)是 Ray Tune ,它支持各种各样的训练框架、前沿搜索算法和实验并行化。我希望在以后的文章中扩展 HPT 框架。

这篇博文的重点是实验并行化,或者更具体地说,是在分布式训练环境中运行并行实验的挑战。我们将在下一节介绍这一挑战。

挑战——分布式培训环境中的 HPT

一个强有力的 HPT 战略对于一般培训同样重要,对于分布式培训更是如此。这是由于以下两个因素:

  1. 调优的复杂性:数据分布式训练的净效应是训练批量的显著增加。用 k 表示工人数量,用 b 表示本地批量,对 k 工人进行分布式训练的结果是,在每一个训练步骤中,模型在一个全局批量 kb* 样本上进行训练。正如我们在上一篇文章中所讨论的,随着批量的增加,HPT 会变得更加困难。可能需要更高级的优化器(如 LAMBLARS ),以及更精细的优化器设置调整。此外,最佳超参数可能高度依赖于全局批次的大小。大小为 X 的全局批次的调整结果可能与大小为 y 的全局批次的调整结果非常不同。
  2. 调整成本:在高度分散的环境中,培训的成本可能相当高。在单个 GPU 设置中可以容忍的 HPT 策略(例如使用原始搜索算法)的低效率在高成本的分布式设置中是不可原谅的。我们在这里和本文的其余部分提到的成本可以是使用基于云的培训服务的价格,也可以是过度使用公司内部培训资源的机会成本。

正如我们在上面看到的,强 HPT 策略的技术之一是并行化调优实验。并行化既可以加快整个过程,又可以通过提前终止实验来节省成本。在多员工环境中,这种成本节约非常显著。然而,当尝试并行化高度分布式的训练实验时,您可能会发现自己面临一个重大挑战,我们将通过下面的简单示例来演示这个挑战:

假设,如本文中的所示,您已经选择在 256 个 GPU 上进行训练,并且您的 HPT 算法的给定阶段需要并行运行 8 个实验。通过简单的计算,我们发现您将需要 2048 个 GPU 来并行运行您的 HPT!!您可能没有这个数量的 GPU,即使您有,运行您的 HPT 每小时的成本可能会非常高。例如,云中的 2048 个 GPU 可以轻松地花费数千美元/小时。

循环实验

您可以考虑的一个替代实验并行化的选项是以循环方式一次一个时期地执行每个实验。例如,在上面的例子中,我们将在 256 个 GPU 上运行第一个实验一个时期,然后第二个,然后第三个,直到第八个实验。此时,我们将比较中间结果,决定终止哪些实验,然后继续运行第二个时期的剩余实验,然后是第三个时期,依此类推。虽然这种方法花费的时间是完全并行化的 8 倍,但它能够实现相同类型的实验提前终止,并导致运行相同总数的时期。这种方法的问题是,实验之间的上下文切换(包括捕获和保存模型状态以及重建计算图)可能会引入大量开销,尤其是在分布式训练设置中。因此,早期终止实验的能力所带来的总体成本节约将低于并行化的情况。

我们在这篇文章中提出的解决方案是通过使用大批量模拟在更少的工人身上运行平行实验。

大批量模拟

大批量模拟 (LBS)中,我们仅使用 Y ( < X) 工人来模拟对 X 工人的培训,其中 YX 的除数,通过在 Y 工人上运行与我们在 X 工人上相同的全局批量。例如,假设在上一节中看到的示例中,本地(每个工作线程)批处理大小为 32,全局批处理大小为 8192 (32x256)。使用 LBS,我们可以在 32 个 GPU(而不是 256 个)上并行运行 8 个 HPT 实验中的每一个,这样每次运行都将使用大小为 256(而不是 32)的本地批处理。全局批处理的结果大小将是 8192,与我们在 256 个 GPU 上运行时的大小相同。这样,当并行运行 8 个实验(每个实验使用 32 个 GPU)时,我们在 HPT 期间将使用与培训期间相同的 256 个 GPU。这里的 8 个实验也比完全并行化花费更多的时间(超过 2048 个 GPU)。然而,提前终止实验所节省的成本将等同于完全并行化所节省的成本。(事实上,由于梯度共享消息数量的减少,它甚至可能会更好一点。)

如果有可能随意增加培训工人的本地批量,实施 BTS 将是微不足道的。然而,在现实中,批量的大小受到培训工作者的可用内存的限制。为了克服这一点,我们将使用一种叫做梯度聚合的技术。

梯度聚合

在典型的训练步骤中,我们执行向前传递以计算本地批次的损失,执行向后传递以计算梯度,将结果传播给其他工人,然后根据所有工人计算的梯度更新模型权重。当我们执行梯度聚合时,我们不是立即共享和应用梯度,而是在预定义数量的步骤中收集它们,然后才广播它们的平均值并更新权重。用 B 表示本地批量大小,在 N 步上执行梯度累加的效果将与用本地批量大小 N x B 进行训练相同。并且在具有规模为 B 的本地批次和具有 Y 的工人的 N 个步骤上运行梯度聚合,将与具有规模为 B 的本地批次和具有X=NXY个工人的培训具有相同的效果。

这种用于模拟大批量的技术依赖于梯度计算的线性,即依赖于批量大小K=NxB的梯度与批量大小NBB的梯度平均值之间的等价性。

总之,我们提出的解决方案是使用 Y 工人模拟一个有 N x Y 工人的培训课程,通过对每个工人的 N 步执行梯度聚合。

使用 Horovod 的大批量模拟

Horovod 是一个流行的库,用于执行分布式培训,广泛支持 TensorFlow、Keras、PyTorch 和 Apache MXNet。Horovod 的工作方式是将梯度共享引入梯度计算步骤。虽然有各种方法来实例化 Horovod,但一种常见的方法是使用distributed optimizerAPI 将您的训练优化器与 Horovod 优化器包装在一起,如下面的 TensorFlow 代码片段所示。更多详情参见 Horovod 文档

import horovod.tensorflow.keras as hvd
*# Initialize Horovod*
hvd.init()
*# Pin GPU, build model, and configure optimizer*
opt = ...
*# Wrap optimizer with Horovod Distributed Optimizer*
opt = hvd.DistributedOptimizer(opt)

从 0.21 版本开始, DistributedOptimizer API 新增了两个用于编程梯度聚合的标志: backward_passes_per_stepaverage _ aggregated _ gradients。当 backward_passes_per_step 设置为大于 1 的值时,Horovod 将在后台使用一个梯度聚合器,该聚合器将在选择的步数上累积梯度,然后共享它们并使用它们将更新应用于模型权重。average _ aggregated _ gradients决定是否在共享累积的梯度之前对其进行平均。在下面的代码块中,我们展示了如何修改 Horovod 设置代码,以便将有效的全局批处理大小增加 8 倍:

import horovod.tensorflow.keras as hvd
*# Initialize Horovod*
hvd.init()
*# Pin GPU, build model, and configure optimizer*
opt = ...
*# Wrap optimizer with Horovod Distributed Optimizer*
opt = hvd.DistributedOptimizer(
                      opt, 
                      *backward_passes_per_step=8,                 
                      average_aggregated_gradients=True*)

小心使用

虽然现代深度学习框架为您可能想要做的几乎所有事情提供了高级 API,但深入了解正在发生的事情总是一个好主意,例如,模型层如何工作,您选择的优化器正在运行什么操作,以及在训练步骤中实际发生了什么。当你试图做一些与众不同的事情时,比如 LBS,尤其如此。否则,你可能会发现你的程序失败了,却不知道为什么。以下是一些需要注意的例子:

定期更新超参数:当使用 Y 工人模拟具有X=NXY的培训环境时,需要注意的是, X 工人环境中的每一步都相当于 Y 工人环境中的 N 步。一些训练算法要求对优化器超参数进行定期更新。例如,通常的做法是使用学习率调度器以固定的迭代步骤调整优化器学习率。为了使模拟正常工作,我们需要通过将更新的预定步骤乘以系数 N 来修改超参数变化的时间表。

对梯度的非线性运算:我们所描述的 LBS 技术依赖于梯度计算的线性,也就是说,依赖于一批大小为 N x B 的梯度与一批大小为NB 的梯度的平均值之间的等价性。一些训练算法可能要求对梯度执行非线性操作。非线性操作的一个例子是梯度裁剪。只要这种非线性仅在完全累积的梯度上执行(即,仅在应用梯度时在台阶上执行),就不会有问题。请注意,TensorFlow 2.5 中的默认行为是对聚集的梯度执行裁剪(参见此处的)。

在正向传递过程中对模型参数的更新:我们已经描述的梯度聚集技术通过反向传递每一步步骤来延迟梯度更新对模型权重的应用。然而,除了梯度更新,我们还需要考虑模型参数的其他更新。在正向传递期间发生的模型参数更新的一个例子是在批标准化层中移动统计的重新计算。假设这些统计数据是在主要(0 级)工作人员上计算的(例如,我们不同步跨工作人员的批处理标准化统计数据),我们需要考虑到在模拟环境中,0 级工作人员将看到的数据量将是backward _ passes _ per _ step乘以 0 级工作人员在原始环境中看到的数据量。尽管批处理规范化统计数据往往会很快被整理出来,但是这种差异可能会导致评估指标的差异。

在这篇文章的附录中,我们描述了如何将 LBS 与混合精度训练结合起来,这个用例进一步证明了谨慎的必要性。

在下一节中,我们将在一些简单的实验中演示 LBS 的使用。

实验

以下实验是在 Amazon EC2 G4 实例上运行的。对于单个 GPU 实验,我们使用 g4dn.2xlarge 实例,对于四个 GPU 实验,我们使用 g4dn.12xlarge 实例。实验在 TensorFlow 版本 2.4.1 和 Horovod 版本 0.21.0 上运行。对于所有实验,我们运行了官方的 Horovod tf.keras mnist 示例,并做了以下更改:

  • 我们应用了附录中描述的必要更改来支持混合精度的 LBS。
  • 对于混合精度测试,我们对模型进行了以下突出显示的调整(参见混合精度文档以了解变化):
**policy = tf.keras.mixed_precision.Policy('mixed_float16')
tf.keras.mixed_precision.set_global_policy(policy)**mnist_model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(32, [3, 3], activation='relu'),
    tf.keras.layers.Conv2D(64, [3, 3], activation='relu'),
    tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),
    tf.keras.layers.Dropout(0.25),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Dense(10),
    tf.keras.layers.Activation('softmax', 
                               **dtype='float32'**, 
                               name='predictions')
])
  • 为了运行 LBS,我们将 backward_passes_per_step 设置为 4,并相应地更新了学习率。

在下面的图表中,我们绘制了四个实验的精度与历元数的函数关系图:在有和没有混合精度设置的情况下在 4 个 GPU 上进行分布式训练,以及在单个 GPU 上运行相应的大批量模拟。

每个历元的精度

在所有情况下,我们看到精度遵循类似的收敛模式。虽然这是在一个简单的模型上演示的,但我们可以看到使用混合精度训练和大批量模拟的潜力。

结束语

在本帖中,我们重点讨论了如何使用 LBS 来解决在高度分散的训练环境中进行 HPT 的挑战。LBS 还可以在许多其他场景中发挥作用。这里有一些例子。

批量调整

在整篇文章中,我们假设培训工人的数量和全局批量大小都是固定的,并相应地解决了调整其他超参数的挑战。当然,在现实中,两者都可以被视为需要调整的超参数。我们讨论的 LBS 技术提供了一种调整批量大小和评估工人数量的选择如何影响培训质量的创造性方法。这可以通过在多台机器上运行平行实验来完成,每台机器的向后 _ 走刀 _ 每步设置值不同。

增加单个实例的批量大小

可能存在这样的情况,其中以大批量运行可能不是数据分布式训练的强制副作用,而是用于提高训练性能的期望工具。在这种情况下,可以使用 LBS 来解决内存约束带来的批量限制,并在我们想要的批量上运行训练。

动态 GPU 编排

现代人工智能公司面临的挑战之一是如何在多个团队和项目中最有效地分配培训资源。培训资源非常昂贵,而且有强烈的经济动机来最大限度地利用这些资源。一种常见的策略是根据团队的需求和项目优先级在团队之间动态分配 GPU。这种策略的效果是,在培训的不同阶段,你可以接触到不同数量的工人。

如果您依赖低成本的“现场”实例进行培训,也会出现类似的情况。许多云服务提供商为多余的计算实例提供大幅折扣。在 AWS 中这些被称为 亚马逊 EC2 Spot 实例 ,在 Google Cloud 中它们被称为 可抢占 VM 实例 ,在微软 Azure 中它们被称为 低优先级 VM。代价是,如果对它们的需求增加,这样的实例可以在使用过程中终止。你会再次发现,在培训过程中,分配的员工数量在不断变化。

考虑到资源分配中这种变化的可能性,明智的做法是在设计培训时考虑到这种可能性。具体来说,在任何给定的时间,您都希望利用尽可能多的可用工作人员,但也不希望重新分配其中的一部分。一个策略可能是天真地培训任何数量的可用工人。然而,全球批量将根据工人数量而变化,正如我们已经看到的,在每种情况下成功的培训并不总是简单的调整学习率。基于 LBS 的另一种策略是在各种情况下保持相同的有效批量。下面是这种工作方式的一个例子:

假设您设计您的模型来培训最多 256 名工人,本地批量为 B 。然而,当你开始培训时,你发现只有 128 名工人可用。使用伦敦商学院,你可以开始对 128 名工人进行培训,有效的本地批次规模为 2 x B 。现在假设培训开始一小时后,分配给你的员工数量下降到 128 人以下。同样,使用 LBS,您可以重新设置您对 64 名工人的培训,进行有效的本地批量 4 x B 培训。稍后,资源可能会开始释放,并且可能会重新设置您的培训,以便在 256 名员工上运行。

理论上,我们甚至可以通过使用 Elastic Horovod 来实施这一策略,而无需停止和重新开始训练,这是 Horovod 的一个引人注目的功能,即使在分配的资源数量发生变化的情况下,也可以进行不间断的训练。然而,在撰写本文时,Horovod APIs 不支持对backward _ passes _ per _ step设置的动态更新。想了解更多关于弹性按摩棒好处的信息,请看这篇最近的文章

摘要

数据分布式培训带来了许多独特的挑战。幸运的是,这些挑战也是创新和创造力的机会。在这篇文章中,我们接受了在高度分散的训练环境中超参数调整的挑战。我们已经展示了如何使用 Horovod 的梯度聚合支持来实现并行实验以及随之而来的潜在成本效益。高度分散的培训可能很昂贵,应该充分探索任何降低成本的机会。

附录:结合大批量模拟和混合精度学习

混合精度训练中,我们在训练期间混合了 16 位和 32 位浮点类型,而不是仅使用 32 位浮点类型。这个特性可以显著节省运行时间和内存使用。

在这篇文章中,我们将重点关注 TensorFlow 提供的混合精度支持,尽管我们要说的大部分内容也适用于其他框架。关于混合精度的 TensorFlow 指南很好地概述了混合精度如何工作以及如何配置。我们将提到与我们的讨论相关的一些混合精度训练的元素。

  • 使用 16 位浮点编程时,主要关注的是由于较低的位精度导致的数值下溢或上溢。实际上,当执行混合精度训练时,最关心的是梯度计算期间下溢的可能性。
  • TensorFlow 支持两种 16 位精度浮点类型,float16 和 bfloat16 。bfloat16 类型的指数位数与 float32 一样多,并且能够表示相同范围的数字。因此,bfloat16 型不存在下溢问题。虽然有许多处理器支持 bfloat16,但在撰写本文时,TensorFlow 的正式版本只支持 Google TPUs 上的 bfloat16。查看这篇文章中关于浮点表示如何工作的有趣概述。
  • 使用 float16 时,克服下溢可能性的方法是执行损失缩放。当我们使用损失缩放时,我们在计算梯度之前将损失乘以一个缩放因子,然后在将它们应用于模型权重之前将结果梯度除以相同的因子。通过选择适当的比例因子,我们可以降低下溢的可能性。在 TensorFlow 中,该过程在losscale optimizer中实现。执行的步骤有:
    1。衡量损失
    2。计算梯度
    3。取消渐变比例
    4。如果所有梯度都是有限的,则将它们应用于权重
    5。如果需要,根据当前梯度的统计数据更新比例因子

既然分布式训练和混合精确训练都有加速训练的共同目标,我们自然会对两者的结合感兴趣。特别是,我们需要基于 LBS 的解决方案来执行混合精度的 HPT。遗憾的是,Horovod 中 LBS 的当前默认实现与 TensorFlow 中的losscale optimizer的默认实现不兼容。然而,幸运的是,通过对每个特性进行小的修改,这些特性可以通过编程和谐地工作。以下是将 LBS 与混合精度相结合时需要解决的问题:

  1. 处理梯度中的 Nan 值:损失缩放的副作用之一是,由于数值溢出,我们可能偶尔会在梯度中得到 Nan 或 Inf 值。如果 LossScaleOptimizer 遇到这样的值,它简单地丢弃梯度并继续下一步。然而,目前 Horovod 中的梯度聚合代码没有考虑 Nan 值的可能性。这个问题的细节以及建议的修改可以在这里找到,但是需要覆盖默认的 Horovod 行为。希望这将在 Horovod 的未来版本中得到解决。
  2. 何时更新缩放系数:如上所述,losscale optimizer基于梯度统计对缩放系数进行周期性更新。在上一节中,我们建议在 LBS 期间应用超参数的定期更新时要谨慎。在这种情况下,如果我们不能将缩放系数的更新与我们应用(和重置)聚集梯度的步骤对齐,我们不仅会在大批量模拟中失败,而且还可能会完全无法训练。如果梯度在其缩放状态下累积(例如 TensorFlow 2.3),并且我们在累积期间重置缩放,则聚集的梯度将具有不匹配的缩放系数。因此,得到的未缩放梯度将是不正确的。即使梯度在其未缩放的状态下被累积(例如 TensorFlow 2.4 和 2.5),也有可能losscale optimizer将无法找到合适的缩放因子。
    为了解决这个问题,您需要覆盖由lossscaleproptimizer调用的损失比例更新函数,以便损失比例更新仅应用于梯度聚合器被重置的步骤。见这里有一种方法可以解决这个问题。
  3. 梯度量化的非线性:需要记住的一点是,使用低精度时固有的量化构成了对梯度的非线性操作。事实上,你很可能会发现一批尺寸为 N x B 的梯度和 N 批尺寸为 B 的梯度的平均值之间存在很小的数字差异。当然,即使使用 32 位浮点数,量化也是存在的,但是数量上的影响远没有那么明显。尽管如此,我们还没有发现由于非线性而影响训练的数值差异,但是知道这一点是有好处的。

请注意,根据您使用的 TensorFlow 版本,可能需要进行一些额外的更改,以便将这两种功能结合起来。更多详情见此处

如何使用 LightGBM 和 boosted 决策树预测销售

原文:https://towardsdatascience.com/how-to-use-lightgbm-and-boosted-decision-trees-forecast-sales-cf65ce8ab645?source=collection_archive---------13-----------------------

使用机器学习构建数据以预测未来销售的广泛指南。它介绍了如何使用 python 创建滞后变量、滚动方法和基于时间的功能。它涵盖了如何执行目标编码,训练测试分裂的时间相关模型,并建立一个梯度推进树模型预测下个月的零售商的销售。

Photo by 褚 天成 on Unsplash

问题陈述

大多数公司对了解他们未来的业绩感兴趣。上市公司必须向投资者提供指导,说明他们认为下一季度或下一年的财务表现会如何。

为了能够回答公司在未来时期的表现,许多公司雇佣分析师来构建预测业务表现的分析解决方案。这种分析往往侧重于平均历史表现,并将其外推至未来结果。移动平均线和滚动窗口是一种常见的做法,也是长期以来的标准做法。

随着数据科学的最新发展,这些模型可以使用更复杂的技术(如梯度推进三)得到显著改善。

在本指南中,我们将使用 ML 为一家俄罗斯零售商预测下个月的销售额。我们将预测每个商店售出的每件商品的销售量。

通过将数据组织为月度预测,我们可以利用我们拥有的关于商店和产品的非常精细的数据。我们将使用在 t-n 时刻获取的历史销售数据来预测 t+n 时刻的未来销售。

作者图片

数据

该数据集来源于 kaggle 的预测未来销售竞赛,包括几个数据文件,我们必须将它们结合在一起。对于那些了解数据库建模的人来说,sales_train 文件或训练集可以被认为是星型模式中的事实表,其中 items、item_ categories 和 shops 是我们可以用主键连接的维度表。

测试文件是具有类似关系的另一个事实。sales_train 文件和测试文件的关键区别在于,销售文件是每日,测试文件是每月。通常在实践中,我们可能希望预测月销售额,以便最终消费者更容易理解。这意味着我们还必须将每日数据汇总到每月数据,以便将其输入到我们的模型中。

数据集包含以下文件:

  • sales_train.csv —培训集。2013 年 1 月至 2015 年 10 月的每日历史数据。
  • test.csv —测试集。你需要预测这些商店和产品在 2015 年 11 月的销售额。
  • sample_submission.csv —格式正确的示例提交文件。
  • items.csv —物品/产品的补充信息。
  • item_categories.csv —关于物品类别的补充信息。
  • shop . CSV-店铺补充信息。
## Import lots of libraries to use
import pandas as pd
import numpy as np
from google_trans_new import google_translator
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error
%matplotlib inline
from itertools import product
import time
from sklearn.model_selection import KFold
from sklearn import base
import lightgbm as lgb
from lightgbm import LGBMRegressor
from sklearn.preprocessing import LabelEncoder, OneHotEncoder, RobustScaler
from sklearn.model_selection import GridSearchCV, cross_val_score, StratifiedKFold, learning_curve, KFold, train_test_split
import calendar
from datetime import datetime

让我们读入数据。

## allows us to pick up the european formatting of the dates in the trainset
dateparse = lambda x: pd.datetime.strptime(x, ‘%d.%m.%Y’) # importing the trainset with dates correctly formatted
sales = pd.read_csv(‘sales_train.csv’, parse_dates = [‘date’], date_parser = dateparse)#import the rest of the files
test = pd.read_csv(‘test.csv’)
items = pd.read_csv(‘items.csv’)
item_categories = pd.read_csv(‘item_categories.csv’)
shops = pd.read_csv(‘shops.csv’)

现在我们已经读入了所有的文件,我们开始一个一个地分析文件。从项目类别开始。

项目类别文件

不幸的是,文件是俄文的。为了更好地理解数据,我们可以将单个类别转换成对非俄语使用者有意义的数据点。为此,我们可以使用 googletrans 将类别名称翻译成英语。我们将把翻译后的值存储在一个名为 Category_type 的列中。

item_categories.head()

作者图片

不会说俄语可能是一个劣势,但我们可以看到,似乎我们有一个模式,其中有一个单词后面跟着 PS2、PS3、PS4 和 PSP。这看起来很像它与各种索尼 playstation 平台有关。也许第一个可以帮助我们将这些物品归类在一起。我们来翻译一下单词,看看。

# Starting with translating the column item_category name from Russian to English. We will then append that to the original dataframe.
translator = google_translator()  
list_a = []
for word in item_categories['item_category_name']:
    try:
        a = translator.translate(word)
        list_a.append(a)
    except:
        list_a.append(word)
item_categories['English_Name'] = list(list_a)
print(list_a)

作者图片

这个翻译并不完美,因为它漏掉了一些术语。我们可以手动搜索单词,并用我们资助的最佳翻译替换它们,以便我们的类别更容易使用。

## Программы means Programs
item_categories[‘English_Name’]= item_categories[‘English_Name’].str.replace(“Программы”, “Programs”)## Книги means Books
item_categories[‘English_Name’]= item_categories[‘English_Name’].str.replace(“Книги”, “Books”)item_categories.head()

作者图片

啊哈!看起来每个项目类别的第一部分都有类别类型。在我们的例子中,类别类型是附件。让我们把它提取出来,存储在一个名为 Category_type 的新特性中。

## Create a feature called Variable type by splitting the English_Name strings where they either have a paranthesis or a dash.
list_a = []
for row in item_categories['English_Name']:
        a = row.replace('(','-').split(' -')[0] ## replacing the opening parantheses with dash so we can use str.split function to split on it.
        list_a.append(a)
item_categories['Category_type'] = list(list_a)
## Lets check out the categories we have
pd.DataFrame((item_categories['Category_type'].unique()))

看起来几个类别有相似的名称和含义。比如游戏 主机游戏主机实际上是同一类型的品类。让我们清理一下,让这个新特性更加统一。

## Let's clean up some of this output in the categories:## Game Consoles are really the same thing as Gaming Consoles
item_categories['Category_type']= item_categories['Category_type'].str.replace("Gaming Consoles", "Game Consoles")## Payment cards with a lowercase c is the same as Payment Cards with upper case C
item_categories['Category_type']= item_categories['Category_type'].str.replace("Payment cards", "Payment Cards")## Cinema and movie tends to be synomomous. Let's change "The Movie" category type to Cinema
item_categories['Category_type']= item_categories['Category_type'].str.replace("The Movie", "Cinema")## Pure and Clean Media Seem Similar. Let's combine into Pure/Clean Media
item_categories['Category_type']= item_categories['Category_type'].str.replace("Clean media", "Pure/Clean Media")
item_categories['Category_type']= item_categories['Category_type'].str.replace("Pure Media", "Pure/Clean Media")

因为这个数据集比较大(对于笔记本电脑来说,无论如何都要处理),所以让我们删除不打算使用的列。这将允许我们在笔记本电脑上使用更少的内存。我们去掉英文名称 categories_name,只留下类别类型。

item_categories = item_categories.drop([‘item_category_name’,’English_Name’],axis =1)

商店

这个文件包含了商店的名称。它可以用作获取销售文件中商店 Id 名称的关键字。因为这个文件也是俄语的,我们将再次把单词翻译成英语。一旦我们有了英文名称,我们将提取这些商店所在的城市,并将其作为一个特征。

shops.head()

作者图片

尽管我学习了如何用俄语拼写配饰,但我担心我的俄语还不够好,看不清商店的名字。让我们把它们翻译成英语,看看这些单词是什么意思。

## Let’s translate this into English
translator = google_translator() 
list_a = []
for word in shops[‘shop_name’]:
 a = translator.translate(word)
 list_a.append(a)
shops[‘English_Shop_Name’] = list_a
shops

作者图片

貌似城市是第一个词,后面是购物中心,TC 或者,SEC 之类的。让我们试着从这里提取城市。一些谷歌化的词让我觉得所有我检查过的地方,不管是 TC 还是 SEC 都是在购物中心。因此,我们没有创建一个突出的店铺名称的一部分。

我们将创建一个仅包含城市名称(第一个单词)的城市变量,并通过按空格分割 English _ Shops _ Name 字符串来创建一个名为城市类型的特性。

因为像圣彼得堡这样的城市名称中有一个空格,所以我们去掉了句号后面的空格和感叹号后面的空格。

list_a = []
for row in shops[‘English_Shop_Name’]:
 a = row.replace(‘. ‘,’’).replace(‘! ‘,’’).split(‘ ‘)[0] ## remove spaces follwing period or exclaimation point and split based on spaces. First word is city
 list_a.append(a)
shops[‘City’] = list(list_a)
## Lets check out the categories we have
pd.DataFrame((shops[‘City’].unique()))

作者图片

因为我们已经从中提取了城市信息,所以我们删除了商店名称,英文商店名称。

shops = shops.drop([‘shop_name’,’English_Shop_Name’],axis = 1)
shops.head()

作者图片

汇总数据

因为任务是进行每月预测,所以在进行任何编码之前,我们需要将数据聚集到每月级别。下面的代码单元正是为了这个目的。它还将 item_cnt_day 变量重命名为 Target(一旦我们将它设为每月聚合)。

gb = sales.groupby(index_cols,as_index=False).agg({'item_cnt_day':{target = 'sum'}})temp['total'] = pd.DataFrame(project_data.groupby(col1)[col2].agg({'total':'count'})).reset_index()['total']index_cols = [‘shop_id’, ‘item_id’, ‘date_block_num’]# For every month we create a grid from all shops/items combinations from that month
grid = [] 
for block_num in sales[‘date_block_num’].unique():
 cur_shops = sales[sales[‘date_block_num’]==block_num][‘shop_id’].unique()
 cur_items = sales[sales[‘date_block_num’]==block_num][‘item_id’].unique()
 grid.append(np.array(list(product(*[cur_shops, cur_items, [block_num]])),dtype=’int32'))#turn the grid into pandas dataframe
grid = pd.DataFrame(np.vstack(grid), columns = index_cols,dtype=np.int32)#get aggregated values for (shop_id, item_id, month)
gb = sales.groupby(index_cols,as_index=False).agg({‘item_cnt_day’: ‘sum’})gb.columns = [‘shop_id’, ‘item_id’, ‘date_block_num’, ‘target’]
# gb = sales.groupby(index_cols,as_index=False).agg({‘item_cnt_day’:{‘target’:’sum’}})#fix column names
# gb.columns = [col[0] if col[-1]==’’ else col[-1] for col in gb.columns.values]
#join aggregated data to the grid
all_data = pd.merge(grid,gb,how=’left’,on=index_cols).fillna(0)
#sort the data
all_data.sort_values([‘date_block_num’,’shop_id’,’item_id’],inplace=True)

有时我们的训练数据中会有异常值。在这个特定的数据集中,我们知道如果我们的目标值为 20 或更大。这意味着,如果我们看到一个大于 20 的值,我们会自动将其称为 20。这对我们的 RMSE 分数有重大的积极影响。这可能并不总是适用于所有的预测模型。

all_data[‘target’]=all_data[‘target’].clip(0,20)

合并数据集

接下来,我们用训练集和测试集创建一个数据帧。我们将用 item_categories、items 和 shops 来加入它。我们将使用这个数据框架来创建我们的许多特征,并尽可能减少将它们应用于多个数据框架的需要。例如,当我们创建滞后变量时,我们需要为训练集、验证集和测试集创建它们。通过将所有数据合并到一个数据帧中,我们只需这样做一次。

在现实世界中,我们将构建一个预处理管道,将训练中使用的相同特征工程应用于未标记数据。那是另一天的话题。

我们将联合训练和测试设备。正如我们从上面的代码中看到的,我们在测试集中缺少了两列。这些是日期块编号和目标。现在,我们将把目标设定为零。我们还会将数字 34 分配给日期块编号。date_block_num 对应于数据集中的月份,因此由于我们需要预测下个月的 item_counts,我们将简单地查找训练集的最大值并加 1。(最大值为 33)

## Assign 34 to date_block_num and 0.0 to target
test[‘date_block_num’] = 34
test[‘target’] = 0.0TEST_ID = test[‘ID’] ## in case we need this later## Then we need to union them and save that back as our all_data dataframe
all_data = pd.concat([all_data,test], axis =0, sort=True)
all_data = all_data.drop(columns = [‘ID’])

接下来,我们将 all_data 数据框架与 items、item_categories 和 shops 数据框架合并。因为我们希望避免创建重复的行,所以我们将添加一些行计数检查器,以确保我们不会添加任何新行或删除任何行。

## Calculate number of rows prior to merge
prior_rows = all_data.shape[0]## Merge the sales train data with the items, item categoris and shops datasets to get the names of items, their categories and the shop names
all_data = pd.merge(all_data, items, on = “item_id”)
all_data = pd.merge(all_data, item_categories, on = “item_category_id”)
all_data = pd.merge(all_data, shops, on = “shop_id”)## Calcualte number and print of rows dropped (should be zero)
print(“Dropped {} rows”.format(prior_rows — all_data.shape[0]))

作者图片

特征工程

因为我们有大量可能具有预测性的数据,所以我们需要将其预处理成我们的模型可以使用的格式。这通常被称为特征工程。

处理日期、季节和日期

日期可以告诉我们很多关于销售的事情。例如,二月份的销售额可能低于一月份,仅仅是因为二月份的天数比其他月份少。日子的类型也很重要。更多的周末可能意味着更多的人经常光顾商店。季节也很重要,六月的销售可能与十二月不同。我们将创建与所有这些项目相关的功能。

首先,我们需要提取每个日期块的月份和日期,并将其存储在一个数据帧中。

## Pull out the last date of each dateblock and append it to the 
from datetime import datetime
list_a = []
for dateblock in sales[‘date_block_num’].unique():
 a = sales[sales[‘date_block_num’] == dateblock]
 a = max(a[‘date’])
 list_a.append(a)

list_a.append(datetime.strptime(‘2015–11–30’,’%Y-%m-%d’)) ## Manually adding the month for the test set
## Transform it to dataframe so we can merge with all_data
list_a = pd.DataFrame(list_a)
## Give the data a descriptive column header
list_a.columns = [‘Month_End_Date’]

现在已经提取了月份和日期,我们可以计算每个月中有多少个星期一、星期二等。

## Let’s calculate the number of specific days are in each month.
import calendar
## Create the empty lists
mon_list = []
tue_list = []
wed_list = []
thu_list = []
fri_list = []
sat_list = []
sun_list = []## Calculate the number of a specific day in a given month (for example, number of mondays in March of 2015)
for date in list_a[‘Month_End_Date’]:
 mon_list.append((len([1 for i in calendar.monthcalendar(date.year,date.month) if i[0] != 0])))
 tue_list.append((len([1 for i in calendar.monthcalendar(date.year,date.month) if i[1] != 0])))
 wed_list.append((len([1 for i in calendar.monthcalendar(date.year,date.month) if i[2] != 0])))
 thu_list.append((len([1 for i in calendar.monthcalendar(date.year,date.month) if i[3] != 0])))
 fri_list.append((len([1 for i in calendar.monthcalendar(date.year,date.month) if i[4] != 0])))
 sat_list.append((len([1 for i in calendar.monthcalendar(date.year,date.month) if i[5] != 0])))
 sun_list.append((len([1 for i in calendar.monthcalendar(date.year,date.month) if i[6] != 0])))## Add these to our list we created with the dates
list_a[‘Number_of_Mondays’] = mon_list
list_a[‘Number_of_Tuesdays’] = tue_list
list_a[‘Number_of_Wednesdays’] = wed_list
list_a[‘Number_of_Thursdays’] = thu_list
list_a[‘Number_of_Fridays’] = fri_list
list_a[‘Number_of_Saturdays’] = sat_list
list_a[‘Number_of_Sundays’] = sun_list

我们还可以提取与年、月和月中天数相关的特征。

## Create the empty listsyear_list = []
month_list = []
day_list = []## Next lets calculate strip out the number of days in a month, the number of the month and the number of the year
for date in list_a['Month_End_Date']:
    year_list.append(date.year)
    month_list.append(date.month)
    day_list.append(date.day)## Add to our dataframe
list_a['Year'] = year_list
list_a['Month'] = month_list
list_a['Days_in_Month'] = day_list

list_a 数据帧可以与 all_data 数据帧合并,我们还添加了一些日期特性。

## Merge the new dataframe with the all_data, using the index and the date_block_num as keys
all_data = pd.merge(all_data, list_a, left_on = ‘date_block_num’, right_index = True)

价格变量

我们最初的方法是添加交易的计数,我们没有对项目的价格做任何事情。让我们计算每月价格的平均值,并将该特性与我们的 all_data 数据框架合并。

## adding the average monthly price within a monthly block for each item at each store to the dataset
a = sales.groupby([‘date_block_num’,’shop_id’,’item_id’])[‘item_price’].mean()
a = pd.DataFrame(a)
all_data = pd.merge(all_data,a,how = “left”, left_on = [‘date_block_num’,’shop_id’,’item_id’], right_on = [‘date_block_num’,’shop_id’,’item_id’])

物品首次售出后的月数&物品上次售出后的月数

这些特征显示了自第一次出售该物品和最后一次出售该物品以来的日期块(月)的数量。这将有助于我们了解该商品有多新,并可能告诉我们该商品已不再销售。

我们将计算每个项目的最小值。这将给出它售出的第一个月。然后,我们将计算该数字与当前日期块之间的差值,以查看该项目的“旧”程度。

a = all_data.groupby(‘item_id’)[‘date_block_num’].min()
a = pd.DataFrame(a)
a = a.reset_index()
a.columns = [‘item_id’,’min_item_sale_date_block_num’]
all_data = pd.merge(all_data,a, left_on = ‘item_id’, right_on = ‘item_id’)
all_data[‘Months_Since_Item_First_Sold’] = all_data[‘date_block_num’]- all_data[‘min_item_sale_date_block_num’]

测试集中的一些数据是针对我们从未见过的产品的。让我们创建一个特性,只计算特定商品在第一个月的平均月销售额。我们会让其余的人归零。

我们还将把相同的逻辑应用于商品类别和商店 id 的组合。我们可以按类别计算第一个月的平均销售额

a = all_data[all_data[‘Months_Since_Item_First_Sold’] == 0].groupby([‘item_category_id’,’Months_Since_Item_First_Sold’])[‘target’].mean()
a = pd.DataFrame(a)
a = a.reset_index()
a.columns = [‘item_category_id’,’Months_Since_Item_First_Sold’,’avg_first_months_sales_by_item_category_id’]
all_data = pd.merge(all_data,a, left_on = [‘item_category_id’,’Months_Since_Item_First_Sold’], right_on = [‘item_category_id’,’Months_Since_Item_First_Sold’], how = ‘left’)
all_data[‘avg_first_months_sales_by_item_category_id’] = all_data[‘avg_first_months_sales_by_item_category_id’].fillna(0)

按类别和店铺 ID 计算第一个月的平均销售额。

a = all_data[all_data[‘Months_Since_Item_First_Sold’] == 0].groupby([‘item_category_id’, ‘Months_Since_Item_First_Sold’,’shop_id’])[‘target’].mean()
a = pd.DataFrame(a)
a = a.reset_index()
a.columns = [‘item_category_id’,’Months_Since_Item_First_Sold’,’shop_id’,’avg_first_months_sales_by_item_category_and_shop’]
all_data = pd.merge(all_data,a, left_on = [‘item_category_id’,’Months_Since_Item_First_Sold’,’shop_id’], right_on = [‘item_category_id’,’Months_Since_Item_First_Sold’, ‘shop_id’], how = ‘left’)
all_data[‘avg_first_months_sales_by_item_category_and_shop’] = all_data[‘avg_first_months_sales_by_item_category_and_shop’].fillna(0)

滞后变量

如果只允许我用一个数据点来预测下个月的销售额,我可能会用这个月的销售额。这个月的销售额是一个滞后变量。在时间序列分析中,目标变量的滞后是很常见的。我们将创建几个滞后变量(上个月的销售额)。我们将重复这一过程几个月。

为了创建一个滞后函数,熊猫图书馆有一个非常有用的函数叫做 shift。我们将它包裹在一个循环中,以产生几个月的多重滞后。我们还使用内置的填充值函数使 na 值为零。

## With pandas shift function
for each in [1,2,3,4,5,6,12]:
    all_data[str("target_lag_"+str(each))] = all_data.groupby(['date_block_num','shop_id','item_id'])['target'].shift(each, fill_value = 0)

更多!滞后很有趣。让我们使用每个月的平均值以及类别、城市、商店或商品来创建特征。我们可以在模型中使用这些特征的滞后。

## Average number of sales by month and by item
all_data[‘avg_monthly_by_item’] = all_data.groupby([‘item_id’, ‘date_block_num’])[‘target’].transform(‘mean’)## Average number of sales by month and by shop
all_data[‘avg_monthly_by_shop’] = all_data.groupby([‘shop_id’, ‘date_block_num’])[‘target’].transform(‘mean’)## Average number of sales by month and by category
all_data[‘avg_monthly_by_category’] = all_data.groupby([‘Category_type’, ‘date_block_num’])[‘target’].transform(‘mean’)## Average number of sales by month and by city
all_data[‘avg_monthly_by_city’] = all_data.groupby([‘City’, ‘date_block_num’])[‘target’].transform(‘mean’)

移动平均线

另一种为数据添加更多特征的方法是创建滚动或移动平均值。滚动平均具有很强的预测性,有助于确定目标的历史水平。让我们创建两个滚动平均值,3 个月和 6 个月。

## 3-months rolling average
all_data[‘target_3_month_avg’] = (all_data[‘target_lag_1’] + all_data[‘target_lag_2’] +all_data[‘target_lag_3’]) /3## 6-months rolling average
all_data[‘target_6_month_avg’] = (all_data[‘target_lag_1’] + all_data[‘target_lag_2’] +all_data[‘target_lag_3’] + all_data[‘target_lag_4’] + all_data[‘target_lag_5’] +all_data[‘target_lag_6’]) /6

请注意我们是如何明确计算这些平均值的。这也可以通过熊猫滚动和平均功能来实现。

## 3-months rolling average
all_data['target_3_month_avg'] = all_data.groupby(['date_block_num','shop_id','item_id'])['target'].rolling(3, fill_value = 0).mean()## 6-months rolling average
all_data['target_6_month_avg'] = all_data.groupby(['date_block_num','shop_id','item_id'])['target'].rolling(3, fill_value = 0).mean()

提高内存使用率

哇,我们创造了很多功能。因为我们只使用一台笔记本电脑,所以我们应该确保将它存储在尽可能小的数据帧中。让我们检查内存使用情况和数据帧的数据类型。

all_data.info(memory_usage = “deep”)

运行 info 时,在输出的底部,您会看到数据框中不同数据类型的数量以及它们的总内存使用情况。

由于其中许多被列为 int64 或 float64,我们可能会将它们减少到更小的空间数据类型,如 int16 或 float8。向下转换意味着我们将每个特性的数据类型减少到最低可能的类型。

for column in all_data:
 if all_data[column].dtype == ‘float64’:
 all_data[column]=pd.to_numeric(all_data[column], downcast=’float’)
 if all_data[column].dtype == ‘int64’:
 all_data[column]=pd.to_numeric(all_data[column], downcast=’integer’)
## Dropping Item name to free up memory
all_data = all_data.drop(‘item_name’,axis =1)
## Let’s check the size
all_data.info(memory_usage = “deep”)

作者图片

使用向下转换,我们能够将数据集的大小减少到一半。

列车测试拆分

在更传统的最大似然模型中,我们会随机地将观测值分配给训练集、测试集和验证集。在预测情况下,我们需要考虑时间对数据集的影响,并相应地构建我们的训练和测试验证。既然我们的数据集已经向下转换,我们可以开始将数据分为训练(前 32 个月)、验证(第 33 个月)和返回到我们的测试集(第 34 个月)。

X_train = all_data[all_data.date_block_num < 33]
Y_train = all_data[all_data.date_block_num < 33][‘target’]
X_valid = all_data[all_data.date_block_num == 33]
Y_valid = all_data[all_data.date_block_num == 33][‘target’]
X_test = all_data[all_data.date_block_num == 34]

更多功能工程—目标编码

我们为什么以编码为目标?

XGBoost 和 LightGBM 等梯度增强的基于树的模型很难处理高基数的分类变量。目标编码通过用平均结果替换字符串或文本值,帮助将分类变量转换为数值。例如,如果一个【PS3】的平均销售量是 300,PS2 是 200,我们将用 300 替换【PS3】的字符串,用 200 替换 PS2。事实上,一个模特现在可以知道我们应该期待 PS3 的销量超过 PS2 的销量。这种类型的特征工程有助于提高模型性能。

为什么要正规化?

简单地计算目标变量的平均值会导致过度拟合,并且通常会降低模型推广到新数据的能力。所以我们需要规范

正则化技术:

  • 培训数据中的交叉验证循环
  • 缓和
  • 添加随机噪声
  • 排序和计算扩展平均值

我们将只在训练数据中进行交叉验证循环。首先,我们将定义两个助手函数,这是我从https://medium . com/@ pouryayria/k-fold-target-encoding-dfe 9a 594874 b中获得的

## Helpder Function to KFold Mean encoding
class KFoldTargetEncoderTrain(base.BaseEstimator,
                               base.TransformerMixin):
    def __init__(self,colnames,targetName,
                  n_fold=5, verbosity=True,
                  discardOriginal_col=False):
        self.colnames = colnames
        self.targetName = targetName
        self.n_fold = n_fold
        self.verbosity = verbosity
        self.discardOriginal_col = discardOriginal_col
    def fit(self, X, y=None):
        return self
    def transform(self,X):
        assert(type(self.targetName) == str)
        assert(type(self.colnames) == str)
        assert(self.colnames in X.columns)
        assert(self.targetName in X.columns)
        mean_of_target = X[self.targetName].mean()
        kf = KFold(n_splits = self.n_fold,
                   shuffle = False, random_state=2019)
        col_mean_name = self.colnames + '_' + 'Kfold_Target_Enc'
        X[col_mean_name] = np.nan
        for tr_ind, val_ind in kf.split(X):
            X_tr, X_val = X.iloc[tr_ind], X.iloc[val_ind]
            X.loc[X.index[val_ind], col_mean_name] = X_val[self.colnames].map(X_tr.groupby(self.colnames)[self.targetName].mean())
            X[col_mean_name].fillna(mean_of_target, inplace = True)
        if self.verbosity:
            encoded_feature = X[col_mean_name].values
            print('Correlation between the new feature, {} and, {} is {}.'.format(col_mean_name,self.targetName,                    
                   np.corrcoef(X[self.targetName].values,
                               encoded_feature)[0][1]))
        if self.discardOriginal_col:
            X = X.drop(self.targetName, axis=1)
        return X## Helper function to get the Kfold Mean encoded on the test setclass KFoldTargetEncoderTest(base.BaseEstimator, base.TransformerMixin):

    def __init__(self,train,colNames,encodedName):

        self.train = train
        self.colNames = colNames
        self.encodedName = encodedName

    def fit(self, X, y=None):
        return self
    def transform(self,X):
        mean =  self.train[[self.colNames,
                self.encodedName]].groupby(
                                self.colNames).mean().reset_index() 

        dd = {}
        for index, row in mean.iterrows():
            dd[row[self.colNames]] = row[self.encodedName]
        X[self.encodedName] = X[self.colNames]
        X = X.replace({self.encodedName: dd})
        return X

现在我们已经定义了两个助手函数,让我们用它们开始对变量进行均值编码:

  • 项目标识
  • 商店标识
  • 城市
  • 类别 _ 类型
  • 项目 _ 类别 _ 标识
## item_id mean encoding
targetc = KFoldTargetEncoderTrain(‘item_id’,’target’,n_fold=5)
X_train = targetc.fit_transform(X_train)## shop_id mean encoding
targetc = KFoldTargetEncoderTrain(‘shop_id’,’target’,n_fold=5)
X_train = targetc.fit_transform(X_train)## City mean encoding
targetc = KFoldTargetEncoderTrain(‘City’,’target’,n_fold=5)
X_train = targetc.fit_transform(X_train)## Category_type mean encoding
targetc = KFoldTargetEncoderTrain(‘Category_type’,’target’,n_fold=5)
X_train = targetc.fit_transform(X_train)## Item_category_id mean encoding
targetc = KFoldTargetEncoderTrain(‘item_category_id’,’target’,n_fold=5)
X_train = targetc.fit_transform(X_train)

作者图片

对测试集应用类似的转换。

## Transform validation & test set## Apply item id mean encoding to test set
test_targetc = KFoldTargetEncoderTest(X_train,’item_id’,’item_id_Kfold_Target_Enc’)
X_valid = test_targetc.fit_transform(X_valid)
X_test = test_targetc.fit_transform(X_test)## Apply shop id mean encoding to test set
test_targetc = KFoldTargetEncoderTest(X_train,’shop_id’,’shop_id_Kfold_Target_Enc’)
X_valid = test_targetc.fit_transform(X_valid)
X_test = test_targetc.fit_transform(X_test)## Apply city mean encoding to test set
test_targetc = KFoldTargetEncoderTest(X_train,’City’,’City_Kfold_Target_Enc’)
X_valid = test_targetc.fit_transform(X_valid)
X_test = test_targetc.fit_transform(X_test)## Apply Category_type mean encoding to test set
test_targetc = KFoldTargetEncoderTest(X_train,’Category_type’,’Category_type_Kfold_Target_Enc’)
X_valid = test_targetc.fit_transform(X_valid)
X_test = test_targetc.fit_transform(X_test)## Apply item_category_id mean encoding to test set
test_targetc = KFoldTargetEncoderTest(X_train,’item_category_id’,’item_category_id_Kfold_Target_Enc’)
X_valid = test_targetc.fit_transform(X_valid)
X_test = test_targetc.fit_transform(X_test)

最终数据集

我们正在接近。我们的特写完成了。让我们做一些检查,以确保我们只有我们将使用的功能。

## drop first 12 months since we have lagged variables
X_train = X_train[X_train.date_block_num > 12]## Assign target variables to seperate variables
y= X_train[‘target’]
Y_valid = X_valid[‘target’]## Drop Categorical Variables that we mean encoded, the target and the item codes.
columns_to_drop = [‘target’, ‘Category_type’,’City’,’Month_End_Date’, ‘item_category_id’]
X_train= X_train.drop(columns_to_drop, axis = 1)
X_valid = X_valid.drop(columns_to_drop, axis = 1)
X_test = X_test.drop(columns_to_drop, axis = 1)

使用 LightGBM 建模

LightGBM 是一个梯度推进框架,使用基于树的学习算法。它被设计为分布式和高效的,具有以下优点:

  • 训练速度更快,效率更高。
  • 更低的内存使用率。
  • 精确度更高。
  • 支持并行和 GPU 学习。
  • 能够处理大规模数据。

LightGBM 非常擅长处理大于 100K 记录的数据集,并且与 XGBoost 相比速度相对较快。

我们需要将训练和验证转换成建模所需的 lgb 数据集结构。

lgb_train = lgb.Dataset(X_train, y)
lgb_eval = lgb.Dataset(X_valid, Y_valid, reference=lgb_train)

像大多数增强模型一样,我们需要调整我们的超参数。这些是我最成功的,但这并不意味着它们是“终极”的。一般来说,当我调整参数时,我倾向于遵循文档提供的指导。

LightGBM 使用逐叶树生长算法,而许多其他流行的工具使用逐深度树生长算法。与深度增长相比,叶子增长算法可以更快地收敛。然而,如果不使用合适的参数,叶向生长可能会过度拟合。

为了使用逐叶树获得良好的结果,以下是一些重要的参数:

叶子数。这是控制树形模型复杂度的主要参数。理论上,我们可以设置 num_leaves = 2^(max_depth)来获得与深度方向树相同数量的叶子。然而,这种简单的转换在实践中并不好。原因是,对于固定数量的叶子,按叶排序的树通常比按深度排序的树更深。不受约束的深度会导致过度拟合。因此,在尝试调整 num_leaves 时,我们应该让它小于 2^(max_depth).例如,当 max_depth=7 时,深度方向的树可以获得良好的准确性,但是将 num_leaves 设置为 127 可能会导致过度拟合,而将其设置为 70 或 80 可能会获得比深度方向更好的准确性。

叶中最小数据。这是一个非常重要的参数,可以防止逐叶树中的过度拟合。它的最佳值取决于训练样本的数量和 num_leaves。将其设置为较大的值可以避免树长得太深,但可能会导致欠拟合。实际上,对于大型数据集,将其设置为数百或数千就足够了。最大深度。您还可以使用 max_depth 来显式限制树深度。

# specify the configurations as a dict
params = {
 ‘boosting_type’: ‘gbdt’,
 ‘objective’: ‘regression’,
 ‘metric’: ‘rmse’,
 ‘num_leaves’: 31,
 ‘learning_rate’: 0.05,
 ‘feature_fraction’: 0.9,
 ‘bagging_fraction’: 0.8,
 ‘bagging_freq’: 5,
 ‘verbose’: 0,
 ‘num_threads’ : 4
}print(‘Starting training…’)
# train
gbm = lgb.train(params,
 lgb_train,
 num_boost_round=10000,
 valid_sets=lgb_eval,
 early_stopping_rounds=100)print(‘Saving model…’)
# save model to file
gbm.save_model(‘model.txt’)print(‘Starting predicting…’)
# predict
y_pred = gbm.predict(X_valid, num_iteration=gbm.best_iteration)
# eval
print(‘The rmse of prediction is:’, mean_squared_error(Y_valid, y_pred) ** 0.5)

让我们来看看特征重要性图。

num_features = 50
indxs = np.argsort(gbm.feature_importance())[:num_features]

feature_imp = pd.DataFrame(sorted(zip(gbm.feature_importance()[indxs],X_train.columns[indxs])), columns=[‘Value’,’Feature’])plt.figure(figsize=(20, 20))
sns.barplot(x=”Value”, y=”Feature”, data=feature_imp.sort_values(by=”Value”, ascending=False))
plt.title(‘Top {} LightGBM Features accorss folds’.format(num_features))
plt.tight_layout()
plt.show()

作者图片

就是这样,我们成功地训练了一个 LightGBM 模型来预测下个月的销售额。

如果你觉得这很有用,请为这个故事鼓掌。

如何使用 loc 和 iloc 在 Pandas 中选择数据

原文:https://towardsdatascience.com/how-to-use-loc-and-iloc-for-selecting-data-in-pandas-bd09cb4c3d79?source=collection_archive---------0-----------------------

熊猫帮助你开始数据分析的提示和技巧

克莱班克斯Unsplash 上拍摄的照片

当选择数据帧上的数据时,熊猫lociloc是两个最受欢迎的。它们快捷、快速、易读,有时还可以互换。

在本文中,我们将探索lociloc之间的差异,看看它们的相似之处,并检查如何用它们执行数据选择。我们将讨论以下主题:

  1. lociloc的区别
  2. 通过单个值进行选择
  3. 通过值列表进行选择
  4. 通过切片选择数据范围
  5. 通过条件选择并可调用
  6. 当标签是从 0 开始的整数时,lociloc可以互换

源代码请查看笔记本

1.lociloc的区别

lociloc的主要区别在于:

  • loc是基于标签的,这意味着您必须根据行和列的标签来指定行和列。
  • iloc是基于整数位置的,所以你必须通过它们的整数位置值(基于 0 的整数位置)来指定行和列。

以下是lociloc的一些区别和相似之处:

loc 和 iloc 的异同(图片由作者提供)

为了进行演示,我们创建了一个 DataFrame,并使用 Day 列作为索引来加载它。

df = pd.read_csv('data/data.csv', **index_col=['Day']**)

作者图片

2.通过单个值进行选择

lociloc都允许输入单个值。我们可以使用以下数据选择语法:

  • loc[row_label, column_label]
  • iloc[row_position, column_position]

例如,假设我们想要检索星期五的温度值。

使用loc,我们可以传递行标签'Fri'和列标签'Temperature'

# To get Friday's temperature
>>> df.**loc['Fri', 'Temperature']**10.51

等效的iloc语句应该采用行号4和列号1

# The equivalent `iloc` statement
>>> df.**iloc[4, 1]**10.51

我们也可以使用:返回所有数据。例如,要获取所有行:

# To get all rows
>>> df.loc**[:, 'Temperature']**Day
Mon    12.79
Tue    19.67
Wed    17.51
Thu    14.44
Fri    10.51
Sat    11.07
Sun    17.50
Name: Temperature, dtype: float64# The equivalent `iloc` statement
>>> df**.iloc[:, 1]**

要获取所有列:

# To get all columns
>>> df**.loc['Fri', :]**Weather        Shower
Temperature     10.51
Wind               26
Humidity           79
Name: Fri, dtype: object# The equivalent `iloc` statement
>>> df**.iloc[4, :]**

注意以上 2 个输出为系列lociloc当结果为一维数据时,将返回一个系列

3.通过值列表进行选择

我们可以将标签列表传递给loc来选择多行或多列:

# Multiple rows
>>> df.**loc[['Thu', 'Fri'], 'Temperature']**Day
Thu    14.44
Fri    10.51
Name: Temperature, dtype: float64# Multiple columns
>>> df.**loc['Fri', ['Temperature', 'Wind']]**Temperature    10.51
Wind              26
Name: Fri, dtype: object

类似地,可以将整数值列表传递给iloc来选择多行或多列。下面是使用iloc的等价语句:

>>> df**.iloc[[3, 4], 1]**Day
Thu    14.44
Fri    10.51
Name: Temperature, dtype: float64>>> df**.iloc[4, [1, 2]]**Temperature    10.51
Wind              26
Name: Fri, dtype: object

以上所有输出都是系列,因为它们的结果都是一维数据。

例如,当结果是二维数据时,输出将是一个数据帧,以访问多个行和列

# Multiple rows and columns
rows = ['Thu', 'Fri']
cols=['Temperature','Wind']df.**loc[rows, cols]**

等效的iloc语句是:

rows = [3, 4]
cols = [1, 2]df.**iloc[rows, cols]**

4.通过切片选择数据范围

Slice(写为start:stop:step)是一种强大的技术,允许选择一系列数据。当我们想要选择两个项目之间的所有内容时,这非常有用。

loc带切片

使用loc,我们可以使用语法A:B从标签 A 到标签 B 中选择数据(包括 AB ):

# Slicing column labels
rows=['Thu', 'Fri']df.loc[rows, **'Temperature':'Humidity'** ]

作者图片

# Slicing row labels
cols = ['Temperature', 'Wind']df.loc[**'Mon':'Thu'**, cols]

作者图片

我们可以使用语法A:B:S从标签 A 中选择数据,以步长 S 标记 B (包括 AB ):

# Slicing with step
df.loc[**'Mon':'Fri':2** , :]

作者图片

iloc带切片

使用iloc,我们也可以使用语法n:m来选择从位置 n (包含)到位置 m (不包含)的数据。然而,这里的主要区别是端点( m )被排除在iloc结果之外。

例如,选择从位置 0 到 3 的列(不包括):

df.iloc[[1, 2], **0 : 3**]

作者图片

同样,我们可以使用语法n:m:s选择从位置 n (包含)到位置 m (不包含)的数据,步长为 s 。注意端点 m 被排除。

df.iloc[0:4:2, :]

作者图片

5.通过条件选择并可调用

情况

**loc** 带条件

我们通常希望根据条件过滤数据。例如,我们可能需要找到湿度大于 50 的行。

使用loc,我们只需要将条件传递给loc语句。

# One condition
df.loc[**df.Humidity > 50**, :]

作者图片

有时,我们可能需要使用多个条件来过滤数据。例如,查找湿度大于 50 且天气为阵雨的所有行:

## multiple conditions
df.loc[
    **(df.Humidity > 50) & (df.Weather == 'Shower')**, 
    ['Temperature','Wind'],
]

作者图片

**iloc** 同条件

对于iloc,如果将条件直接传递到语句中,我们将得到一个值错误:

# Getting ValueError
df.**iloc[df.Humidity > 50, :]**

作者图片

我们得到这个错误是因为iloc不能接受布尔序列。它只接受布尔列表。我们可以使用list()函数将一个系列转换成一个布尔列表。

# Single condition
df.iloc[**list(df.Humidity > 50)**]

类似地,我们可以使用list()将多个条件的输出转换成一个布尔列表:

## multiple conditions
df.iloc[
    **list((df.Humidity > 50) & (df.Weather == 'Shower'))**, 
    :,
]

可调用函数

**loc** 带有可调用的

loc接受一个可调用的作为索引器。callable 必须是具有一个参数的函数,该函数返回有效的索引输出。

例如选择列

# Selecting columns
df.loc[:, **lambda df: ['Humidity', 'Wind']**]

并使用可调用的过滤数据:

# With condition
df.loc[**lambda df: df.Humidity > 50**, :]

作者图片

**iloc** 带有可调用的

iloc也可以带一个可调用的作为索引器。

df.iloc[**lambda df: [0,1]**, :]

作者图片

为了用 callable 过滤数据,iloc需要list()将条件的输出转换成一个布尔列表:

df.iloc[**lambda df: list(df.Humidity > 50)**, :]

作者图片

6.当标签是从 0 开始的整数时,lociloc可以互换

为了演示,让我们创建一个数据帧,用从 0 开始的整数作为标题和索引标签。

df = pd.read_csv(
    'data/data.csv', 
    **header=None,** 
    **skiprows=[0],**
)

使用header=None,熊猫将生成以 0 为基的整数值作为头。有了skiprows=[0],我们一直在用的那些头天气温度、等都将被跳过。

作者图片

现在,loc,一个基于标签的数据选择器,可以接受单个整数和一个整数值列表。例如:

>>> df**.loc[1, 2]** 19.67 >>> df**.loc[1, [1, 2]]** 1    Sunny
2    19.67
Name: 1, dtype: object

他们工作的原因是那些整数值(12)被解释为指数的 标签 。这种用法是而不是一个带有索引的整数位置,有点混乱。

在这种情况下,通过单个值或值列表进行选择时,lociloc可以互换。

>>> df.**loc[1, 2]** == df.**iloc[1, 2]**
True>>> df.**loc[1, [1, 2]]** == **df.iloc[1, [1, 2]]**
1    True
2    True
Name: 1, dtype: bool

请注意,通过切片和条件选择时,lociloc将返回不同的结果。它们本质上是不同的,因为:

  • 切片:端点从iloc结果中排除,但包含在loc
  • 条件:loc接受布尔序列,但iloc只能接受布尔列表。

结论

最后,这里是一个总结

loc基于标签,允许的输入有:

  • 单个标签'A'2(注意2被解释为索引的标签。)
  • 标签列表['A', 'B', 'C'][1, 2, 3](注意1, 2, 3解释为索引的标签。)
  • 带标签的切片'A':'C'(两者都包含)
  • 条件、布尔序列或布尔数组
  • 一个只有一个参数的callable函数

iloc基于整数位置,允许的输入有:

  • 整数,例如2
  • 整数列表或数组[1, 2, 3]
  • 整数切片1:7(端点7除外)
  • 条件,但只接受布尔数组
  • 一个有一个参数的函数

当熊猫数据帧的标签是从 0 开始的整数时,lociloc可以互换

希望这篇文章能帮助你节省学习熊猫数据选择的时间。我建议你查看一下文档来了解你可以做的其他事情。

感谢阅读。请查看笔记本获取源代码,如果你对机器学习的实用方面感兴趣,请继续关注。

你可能会对我的其他一些熊猫文章感兴趣:

更多教程可以在我的 Github 上找到

如何在熊猫身上使用 loc

原文:https://towardsdatascience.com/how-to-use-loc-in-pandas-49ed348a4117?source=collection_archive---------3-----------------------

了解如何使用 pandas Python 库中的 loc 方法

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

为熊猫的数据帧建立索引是一项非常重要的技能。索引仅仅意味着在数据帧或系列中选择特定的行和/或列。

在本教程中,我们将学习 loc 方法,这是最简单的和最通用的方法来索引 pandas 中的数据帧。

制作数据框

我们将使用 jupyter 笔记本中的这里找到的 ufo 目击数据集。让我们将数据读入数据帧,看看 ufo 数据帧的前 5 行:

我们 ufo 数据帧的前 5 行

让我们看看关于我们的数据框架的其他一些信息:

我们使用了 shapecolumns dataframe 属性来分别获取数据帧的形状(行数、列数)和列名。

锁定方法

索引数据帧最通用的方法可能是loc方法。loc 既是 dataframe 又是 series 方法,这意味着我们可以对这些 pandas 对象中的任何一个调用 loc 方法。当在数据帧上使用 loc 方法时,我们通过使用以下格式指定我们想要的行和列:

data frame . loc[指定的行:指定的列]

种不同的方式来指定我们想要选择的行和列。例如,我们可以传入一个单个标签、一个标签列表或数组、一个带标签的切片对象或一个布尔数组

让我们来看一下这些方法!

使用单一标签

我们可以指定哪些行和/或哪些列的一种方法是使用标签。对于行,标签是该行的索引值,对于列,列名是标签。例如,在我们的 ufo 数据帧中,如果我们只想要第五行以及所有的列,我们将使用如下:

ufo.loc[4, :]

单一标签

我们传入的标签永远被解释为标签。它永远不会被解释为沿着索引的整数位置。所以我们通过使用特定行的标签来指定我们想要的行,这是 4,因为我们想要所有的列,我们将只使用冒号。

注意:我们可以省略冒号,我们会得到相同的输出,但是,为了代码可读性,最好保留冒号,以明确显示我们需要所有列。

标签的列表或数组

假设我们想要多个行和/或列。我们如何指定它?嗯,使用标签,我们可以输入一个标签列表,或者使用你可能熟悉的类似于切片符号的东西。

让我们从标签列表开始:

标签列表

注意我们如何用标签列表指定行和列标签。

切片对象

我们也可以使用以下格式的切片符号:

开始标签:停止标签

然而,与使用列表或字符串的切片符号相反,开始和停止标签都包含在我们的输出中:

带标签的切片对象

请注意行标签 3、4 和 5 是如何包含在我们的输出数据帧中的。还要注意 City、Colors Reported 和 Shape Reported 列是如何包含在内的,即使我们使用 slice 对象停止在 Shape Reported。记住,ufo.columns 返回了一个列表,其顺序为城市、报告的颜色、报告的形状、州和时间。我们包括从城市标签到形状报告标签的所有内容,其中还包括颜色报告标签。

布尔数组

最后,我们可以使用布尔值数组。然而,这个布尔值数组的长度必须与我们正在使用的轴的长度相同。例如,根据我们上面使用的 shape 属性,我们的 ufo dataframe 的形状为 (18241,5) ,意味着它有 18241 行 5 列。

所以如果我们想用一个布尔数组来指定我们的行,那么它也需要有 18241 个元素的长度。如果我们想使用一个布尔数组来指定列,它需要有 5 个元素的长度。创建这个布尔数组最常见的方法是使用一个 条件,它创建一个可对齐的布尔序列

例如,假设我们只想选择包含 Abilene 的行作为 ufo 目击事件发生的城市。我们可以从以下情况开始:

ufo.City == ‘Abilene’

注意这是如何返回长度为 18241 并且由布尔值(真或假)组成的熊猫序列(或类似数组的对象)的。这是我们需要能够使用这个布尔数组使用 loc 方法指定我们的行的值的确切数目!

想象我们将这一系列真值和假值覆盖在 ufo 数据帧的索引上。只要这个序列中有一个真的布尔值,这个特定的行将被选中并显示在我们的数据帧中。

我们可以在上面看到,第一个真值出现在第 4 行,标签为 3,这意味着一旦我们用 loc 方法使用这个布尔值数组,我们将看到的第一行是标签为 3 的行(或 ufo 数据帧中的第 4 行)

ufo.loc[ufo.City == ‘Abilene’, :]

阿比林的不明飞行物目击事件

这正是我们所看到的!我们已经使用长度等于原始数据帧中的行数的布尔值数组指定了我们想要的行。

可调用函数

我们还可以向 loc 方法传递一个可调用的函数来指定行和/或列。该函数将接受一个参数,该参数将是调用序列或数据帧,并且必须返回一个用于索引的有效输出,该输出可以是上面我们讨论过的任何方法(比如布尔数组)。****

例如,我们可以使用 lambda 函数获得与上面相同的数据帧,其中包括所有以 Abilene 为城市的行:

ufo.loc[lambda df: df.City == ‘Abilene’, :]

我们使用带有一个参数的 lambda 函数来指定行。传递给 lambda 函数的参数是 ufo 数据帧(被索引的数据帧)。lambda 函数返回一个布尔数组,然后用于指定行。

** **

结合这些方法

记住,我们可以组合这些不同的指定行和列的方式,这意味着我们可以对行使用一种索引方式,对列使用不同的方式。例如:

ufo.loc[ufo.City == ‘Abilene’, ‘City’:’State’]

请注意我们如何使用返回布尔值数组的条件来指定行,以及如何使用标签来指定列的切片对象。

如果你喜欢阅读这样的故事,并想支持我成为一名作家,考虑注册成为一名媒体成员。每月 5 美元,你可以无限制地阅读媒体上的故事。如果你注册使用我的 链接 ,我会赚一小笔佣金。

**https://lmatalka90.medium.com/membership **

结论

在本教程中,我们学习了如何使用 loc 方法索引熊猫数据帧。我们了解了 loc 方法是如何既是 series 方法又是 dataframe 方法,并可用于在索引 dataframe 时指定行和列。我们研究了指定行和列的不同方法,包括标签的单个或列表、带标签的切片对象、通常使用条件创建的布尔数组,以及返回任何上述内容的可调用函数。最后,我们学习了如何将这些不同的方法结合起来,同时用于索引熊猫的数据帧。

如何用 R 在 Power BI 中使用机器学习

原文:https://towardsdatascience.com/how-to-use-machine-learning-in-power-bi-with-r-6b6a930f0310?source=collection_archive---------32-----------------------

用人工智能赋能您的仪表盘

微软最近一直在大力调整开源技术,并将人工智能技术融入其产品中,Power BI 也包括在这一计划中。Power BI 是当今构建仪表板的主要工具之一,微软每天都在增加其开发能力和灵活性。

为了使仪表板的开发可行,Power BI 有几个用于数据处理的功能,其中最重要的一个是与 R 的集成工具,以及最近与 Python 的集成。使用 R 和 Python 开发语言的选项在 BI 工具中开辟了大量的可能性,其中一个可能性是使用机器学习工具并直接在 Power BI 中构建模型。

在本文中,我将从以下主题开始,逐步讲解如何使用 R 语言在 PowerBI 中直接使用机器学习模型进行训练和预测:

  1. 安装依赖项
  2. 分析数据
  3. 动手——代码
  4. 结果
  5. 结论

1.安装依赖项

第一步是在您的机器上安装 R Studio,因为开发将使用 R 语言。尽管 PowerBI 与 R 语言有着本机集成,但它要求用户在机器上安装 R 包。

可以通过这个链接下载:https://www.rstudio.com/products/rstudio/download/

安装完成后,您必须打开 R studio 并安装依赖库。

  • 脱字号
  • 数据集
  • monomvn

要在 R 中安装软件包,R-bloggers 网站有一个很棒的教程,教你如何在 R Studio 中安装和加载软件包。链接:https://www . r-bloggers . com/2013/01/how-to-install-packages-on-r-screens/

分析数据

该数据集是从 kaggle.com 网站获得的,包括圣保罗一所大学的啤酒消费数据,以及每天的最低、最高和平均温度以及体积降雨量。

为了添加另一个重要的功能,我创建了一个名为“周末”的列,指示当天是周六还是周日,因为周末的消费量较高,所以我可以考虑周五,但对于这一时刻,我决定更保守一些。

数据集—作者

3-实践-代码

对于测试,我使用 monomvn 包(Bayesian Ridge Regression)建立了一个贝叶斯线性回归模型,以预测每天的啤酒消费数据(升),并通过 10 倍的交叉验证进行验证。

在本文中,我不会深入讨论这个模型及其结果,因为我们的目标是更多地关注与 Power BI 的集成,而不是建模。

代码的第一部分导入库

library(caret)
library(datasets)
library(monomvn)

在我们将 Power BI 数据作为数据集导入后,在 R

mydata <- dataset
mydata <- data.frame(mydata)

有了它,我们就可以创建模型并进行预测。在这种情况下,我没有定义测试数据集,我只是使用带有 CV10 验证的训练数据集来简要分析训练指标。

fitControl <- trainControl(
  method = "repeatedcv",
  number = 10,
  repeats = 10)

lmFit <- train(mydata[1:365, 2:6],mydata[1:365,7], method ='bridge',trControl = fitControl)

predictedValues <- predict(lmFit,newdata = mydata[, 2:6])

最后,我们用模型预测生成的值在 PowerBI 数据集中创建了一个新列。

mydata$PredictedValues <- predictedValues

完整代码

library(caret)
library(datasets)
library(monomvn)

mydata <- dataset
mydata <- data.frame(mydata)

fitControl <- trainControl(
  method = "repeatedcv",
  number = 10,
  repeats = 10)

lmFit <- train(mydata[1:365, 2:6],mydata[1:365,7], method ='bridge',trControl = fitControl)

predictedValues <- predict(lmFit,newdata = mydata[, 2:6])

mydata$PredictedValues <- predictedValues

4 —结果

下面是包含真实值、预测值和误差(%)的完整数据集。训练的平均误差为 7.82% ,最大 20.23%,最小 0.03%

预测—作者

下面是一个图表,黑色表示真实数据,红色表示预测数据,蓝色表示整个测试期间的误差。

真实 x 预测—作者

4.1-与温度的相关性

当绘制啤酒消费量(黑色/红色)与温度(蓝色)的关系图时,我们看到消费量很好地遵循了月份之间的温度变化,包括温度变化的“微观”(每日)变化和“宏观”(趋势)。我们看到温度的上升导致了更大的消费,例如在一年的岁末年初,这是夏天,而冬天较低的温度导致了啤酒消费的减少。

预测和温度—作者

4.2.真实数据和预测之间的相关性

在实际值和模型预测值之间应用相关性,我们会得到集中在黑色虚线(下图)中的理想数据,在这种情况下,预测数据将等于实际数据。通过制作这个相关图,我们可以看到模型预测的分散程度,以及预测的集中程度是被低估还是被高估。

当分析相关图时,我们看到初始模型的离差没有那么高,平均变化为 7.8%,如前所述。当分析数据的集中度时,我们看到模型在预测值大于或小于真实值之间变化,但在大多数情况下,模型略微高估了消费数据,预测的消费高于真实值。

预测 x 真实数据相关性—作者

4.3 测试— 2018 年数据

在用 2015 年的数据训练模型之后,我试图获得用于推断的数据,并获得了 2018 年圣保罗市的温度和降雨量数据的数据集。

下面要注意的是,2018 年数据中的推断值显示了与真实数据相同的模式,随着温度的降低,年中的消费量减少,周末出现峰值。

2018 年测试数据预测—作者

4.3.1 温度相关性

然后用蓝色标出的数值和温度一起证明了消费和温度之间的相关性,并在推断数据中展示了其全年的动态。

2018 年温度测试数据预测—作者

4.3.2 周末的季节性

解释季节性周期的一种方式是周末啤酒消费量的增加,我们可以在平均温度的消费量图表下方看到,黑色条代表周末、周六和周日。

与周末的相关性(测试)—作者

这种季节性也发生在实际数据中,当我们绘制 2015 年的实际消费时,高消费模式在周末重复出现,这表明该模型尽管简单,但却很好地适应了数据动态。

与周末的相关性(火车)—作者

5.结论

Power BI 作为一种图形工具,除了能够同时呈现数据库本身的探索性视图之外,还提供了从机器学习模型输出开发分析可视化的巨大多功能性和速度。对于在分析领域工作的开发人员来说,将机器学习模型的功能整合到 BI 工具中无疑是一项重大进步,PowerBI 以简单实用的方式带来了这一功能。

最后,关于这篇文章或机器学习、PowerBI、R、Python 等话题的任何问题或建议,请随时在 LinkedIn 上联系我:https://www.linkedin.com/in/octavio-b-santiago/

如何使用 Matplotlib 绘制对象检测数据集中的样本

原文:https://towardsdatascience.com/how-to-use-matplotlib-for-plotting-samples-from-an-object-detection-dataset-5877fe76496d?source=collection_archive---------11-----------------------

为目标检测绘图

关于如何使用 Matplotlib 为对象检测任务绘制图形的简短教程

帕特里克·托马索在 Unsplash 上的照片

可视化数据集中的样本对于有效探索机器学习任务至关重要。它提供了关键的见解,帮助您从模型架构、数据扩充等几个可用选项中缩小选择范围。与分类或回归任务相比,绘制来自对象检测数据集的样本更加棘手。

下面是一个简短的教程,介绍如何使用 Matplotlib 库为对象检测样本创建高质量的绘图。

下载数据集和其他文件

我们将使用 Yolov5 PyTorch 版本的国际象棋数据集,你可以从 https://public.roboflow.com/object-detection/chess-full/23下载。我们还将使用上一篇文章“使用对象检测数据集在 PyTorch 中创建数据集管道的一般方法”中的数据帧。

如果你还没有这样做,请读一读。以下是数据框的链接。

  1. https://raw . githubusercontent . com/varun 9213/Blog _ machine _ learing/main/Data _ Blog _ 1/train _ FD . CSV
  2. https://raw . githubusercontent . com/varun 9213/Blog _ machine _ learing/main/Data _ Blog _ 1/valid _ FD . CSV
  3. https://raw . githubusercontent . com/varun 9213/Blog _ machine _ learing/main/Data _ Blog _ 1/test _ FD . CSV

你可以从这里下载完整的笔记本教程。

现在,让我们开始编码吧!!

首先,导入教程所需的所有库和文件

!pip install fastai --upgrade

from fastai import *
from fastai.vision.all import *
from fastai.imports import *
import cv2, os
from matplotlib import patches, text, patheffectsroot = Path("/content/data")!curl -L "https://public.roboflow.com/ds/pK9BobmV9A?key=G9IUWXkCZA" > roboflow.zip; unzip roboflow.zip; rm roboflow.ziptrain_df = pd.read_csv
("[https://raw.githubusercontent.com/Varun9213/Blog_machine_learing/main/Data_blog_1/train_fd.csv](https://raw.githubusercontent.com/Varun9213/Blog_machine_learing/main/Data_blog_1/train_fd.csv)")valid_df = pd.read_csv
("[https://raw.githubusercontent.com/Varun9213/Blog_machine_learing/main/Data_blog_1/valid_fd.csv](https://raw.githubusercontent.com/Varun9213/Blog_machine_learing/main/Data_blog_1/valid_fd.csv)")test_df = pd.read_csv
("[https://raw.githubusercontent.com/Varun9213/Blog_machine_learing/main/Data_blog_1/test_fd.csv](https://raw.githubusercontent.com/Varun9213/Blog_machine_learing/main/Data_blog_1/test_fd.csv)")train_df.head()

作者图片

履行

让我们先来看看我们希望最终的剧情是怎样的。

作者图片

好了,现在我们心中有了一个明确的目标,让我们看看实现。

如果你读过我以前的帖子,我喜欢把一个问题分解成更小的部分,所以,让我们从绘制数据集的图像开始,只为图像中的一个对象绘制一个边界框。

train_images = get_image_files(root/"train")fig, ax = plt.subplots()
path_img = train_images[0]img = cv2.imread(str(path_img))
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)ax.xaxis.tick_top()
ax.imshow(img)

作者图片

get _ image _ files()是一个 fastai 函数,返回父目录下所有图片的路径列表,可以访问https://docs.fast.ai/进一步探索库。

def get_target_ds(name, df):
  rows = df[df["name"] == name[:-4]]
  return rows["class"].values, rows[bboxes_cols].valuesbboxes_cols = ["center_x", "center_y", "width", "height"]
labels, boxes = get_target_ds(path_img.name, train_df)x = (boxes[0][0] - boxes[0][2]*0.5)*img.shape[1]
y = (boxes[0][1] - boxes[0][3]*0.5)*img.shape[0]
w = boxes[0][2] * img.shape[1]
h = boxes[0][3] * img.shape[0]fig, ax = plt.subplots(figsize = (6,9))ax.xaxis.tick_top()
ax.imshow(img)
ax.add_patch(patches.Rectangle((x,y),w,h, fill=False, edgecolor='red', lw=2))

作者图片

好了,现在让我们来分解这个代码块,看看这个盒子到底是如何出现在图像中的。

ax.add_patch()是一个 Matplotlib 方法,用于在绘图上绘制一个图形或一个补丁,我们在这里使用它来绘制一个由边界框坐标给出的矩形。

补丁。Rectangle()是我们传递给 add_patch()方法的参数,该方法随后将矩形绘制到图像上。注意,需要传递给函数的边界框的格式是 ((x_min,y_min),width,height) 然而,数据集为边界框提供的格式是不同的,必须转换成所需的格式。

当我们选择数据集的 Yolo 版本时,边界框的格式是【x _ center,y_center,width,height】。N 注意,这里的坐标已经标准化,必须根据图像的分辨率按比例缩小。

来源:物体检测的白蛋白文档

注意您可以在此处找到的相册文档中的图像向您展示了坐标系在大多数绘图和增强库中是如何工作的。与我们通常使用的坐标系相比,它是上下颠倒的。它还向您展示了边界框的坐标是如何以各种格式表示的。

最后,让我们给盒子加上相应的标签。

fig, ax = plt.subplots(figsize = (6,9))
ax.xaxis.tick_top()
ax.imshow(img)ax.add_patch(patches.Rectangle((x,y),w,h, fill=False, edgecolor='red', lw=2))**ax.text(x,(y-50),str(labels[0]),verticalalignment='top',
color='white',fontsize=10,weight='bold')**

作者图片

这个图中似乎还缺少一些东西,我们的目标图比我们刚刚创建的要干净得多。

不同之处在于我们的目标图缺少轮廓,让我们添加轮廓以获得更清晰的图。

fig, ax = plt.subplots(figsize = (6,9))
ax.xaxis.tick_top()
ax.imshow(img)ax.add_patch(patches.Rectangle((x,y),w,h, fill=False, edgecolor='red', lw=2))**.set_path_effects([patheffects.Stroke(linewidth=4, foreground='black'), patheffects.Normal()])**ax.text(x,(y-50),str(labels[0]),verticalalignment='top',
color='white',fontsize=10,weight='bold')**.set_path_effects([patheffects.Stroke(linewidth=4, foreground='black'), patheffects.Normal()])**

作者图片

是啊!这个看起来好多了。最后,总结一下,让我们为每一步创建函数,并在图像中用相应的标签画出所有的方框。同样,让我们创建一个函数来为多个样本生成图。

def get_bb(bboxes, img): boxes = bboxes.copy()
  boxes[:,0] = (boxes[:,0] - boxes[:,2]*0.5)*img.shape[1]
  boxes[:,1] = (boxes[:,1] - boxes[:,3]*0.5)*img.shape[0]
  boxes[:,2] = boxes[:,2] * img.shape[1]
  boxes[:,3] = boxes[:,3] * img.shape[0] if boxes.shape[0] == 1 : return boxes
  return np.squeeze(boxes)def img_show(img, ax = None, figsize=(7,11)):
  if ax is None: fig, ax = plt.subplots(figsize=figsize)
  ax.xaxis.tick_top()
  ax.imshow(img) return axdef draw_outline(obj):
  obj.set_path_effects([patheffects.Stroke(linewidth=4,  foreground='black'), patheffects.Normal()])def draw_box(img, ax, bb):
  patch = ax.add_patch(patches.Rectangle((bb[0],bb[1]), bb[2], bb[3], fill=False, edgecolor='red', lw=2))
  draw_outline(patch)def draw_text(ax, bb, txt, disp):
  text = ax.text(bb[0],(bb[1]-disp),txt,verticalalignment='top'
  ,color='white',fontsize=10,weight='bold')
  draw_outline(text)def plot_sample(img, bboxes, labels, ax=None, figsize=(7,11)):
  bb = get_bb(bboxes, img)
  ax = img_show(img, ax=ax)
  for i in range(len(bboxes)):
    draw_box(img,ax,bb[i])
    draw_text(ax, bb[i], str(labels[i]), img.shape[0]*0.05)def multiplot(dim:tuple, df, images, idxs = None, figsize=(18,10)):
  if idxs is None: idxs = np.random.randint(0, len(images)-1,          dim[0]*dim[1])
  fig, ax = plt.subplots(dim[0],dim[1], figsize=figsize)
  plt.subplots_adjust(wspace=0.1, hspace=0)
  fig.tight_layout()
  for i in range(dim[0]):
    for j in range(dim[1]):
      img = images[idxs[(i+1)*j]]
      labels, bboxes = get_target_ds(img.name, df)
      img = cv2.imread(str(img), cv2.IMREAD_UNCHANGED)
      img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
      plot_sample(img, bboxes, labels, ax=ax[i][j]) plot_sample(img, boxes, labels)

作者图片

multiplot((2,4), train_df, train_images, figsize=(20,8))

作者图片

结论

在完成一个机器学习项目后,你意识到你的大部分编码时间都花在了预处理、EDA、绘制样本、增强和构建管道上。从长远来看,熟悉打印库可以节省大量时间。

我希望这篇文章能帮助你更有效地使用这些绘图功能。我将在下一篇文章中讨论数据增强,在我看来,如果使用得当,它会给你带来最佳的性能。

敬请关注,谢谢!!

如何使用元数据让您的数据堆栈面向未来

原文:https://towardsdatascience.com/how-to-use-metadata-to-future-proof-your-data-stack-97c4885f97f6?source=collection_archive---------12-----------------------

消除元数据孤岛、分散的专业知识和长期的数据管理复杂性。

当构建或重新思考他们的数据堆栈时,组织通常以工具优先的心态来完成任务。我们最近查看了流行的工具,如 Fivetran、dbt、Airflow 和 Looker on Snowflake,并注意到许多参考架构和实施计划都过于复杂。不一定要这样。

我们推荐了一个简化概念框架来考虑构建数据堆栈。我们相信,让元数据驱动堆栈提供了清晰的关注点分离,并鼓励简单性。此外,它还帮助数据团队进行战略性思考,并使用正确的工具来满足他们的数据战略需求。

我们的三层框架如下所示:

  • 第 1 层:数据流
  • 第 2 层:元数据
  • 第 3 层:开发运维工具

图片由 Datacoral 提供。

让我们更深入地了解为什么元数据对于构建可伸缩和可维护的数据堆栈如此重要;为什么元数据是大多数公司事后才想到的;以及如何采用整体平台方法来满足数据目标。

缺少元数据

全球各地的公司都在构建数据堆栈,并在数据团队上投入巨资,这导致了用于管理数据处理、状态管理和配置的工具激增。这些工具非常适合构建接收和转换数据的管道,但是它们最终会产生元数据孤岛。这些孤岛导致不同工具之间的阻抗不匹配,从而导致缺乏内聚智能。通过将元数据从一个工具转换到另一个工具,需要大量粘合代码来集成工具。

为什么?在很大程度上,数据堆栈是基于普遍的业务需求零碎构建的。当您是一家拥有少量数据的小公司时,很难证明采用平台方法来构建数据架构是正确的。但是,随着公司的发展,工具越来越多,导致数据堆栈的视图支离破碎,复杂性呈指数级增长。

业务领导需要有价值的见解,而数据团队需要稳定的基础设施,以支持处理数百万条记录的数据管道。业务领导希望根据最新数据做出最新决策,而数据团队则担心模式更改对转型工作的连锁影响。我们可以看到数据堆栈的目标会有多快出现分歧。

当业务洞察力、稳定的基础设施和干净的元数据结合在一起时,有意义的价值可以在数据堆栈中快速轻松地获得。提供的图像是一个库存图像。

有一种元数据优先的方法来解决更广泛的行业开始看到的问题,但还不能完全解决。最近几个月,我们已经看到几个以元数据为中心的产品上市,这非常令人鼓舞。但是,这些产品中的大多数解决了更简单的短期问题,如数据源、仪表板、机器学习作业和电子表格的编目,以支持搜索、审计和合规性。这些元数据搜索工具真的很有用,但是它们并没有解决公司真正需要有一个一致堆栈的平台方法。

今天的元数据工具集中了来自不同系统的元数据,并试图提供一个单一窗口来显示整个堆栈中发生的事情。但是,不同工具之间的元数据并不一致,因为每个工具的构建方式不同,这意味着需要做更多的工作来标准化元数据。用元数据标准化玩打地鼠很快就会过时。数据从业者经常发现遗留的元数据系统并不总是最新的,所以工具本身随着对元数据的关注而变得陈旧。然后,元数据系统的主要用例变成了审计和遵从,只有当审计和遵从需求实际出现时才这样做。

如果你在构建完你的数据栈的其余部分后,还在考虑元数据系统,从某种意义上来说,你还没有选择构建整体数据栈的道路。

当前的元数据解决方案最终强化了工具优先的思想。我们认为数据团队应该以一种非常不同的方式考虑元数据——使元数据成为数据管道关键路径的一部分。

我们认为元数据需要驱动整个系统。元数据层是关键,但通常是在实际数据堆栈本身之后添加的。元数据不是设计数据管道的关键路径的一部分,因此缺乏数据堆栈内的长期可预测性。

为什么是元数据?

我们今天所知的数据工程主要由复杂的集成和由各种工具驱动的定制代码组成。正如我们刚刚讨论的,有利的一面是数据连接器和转换工具的可用性和商品化。它们使得统一原始数据集和计算 KPIs 指标变得前所未有的简单。缺点是缺乏集成和端到端的智能。更重要的是,这些缺点增加了为应用程序、AI/ML 模型和业务领导者提供有意义的见解的难度。

数据堆栈最终会提供数据,但不能保证数据的质量。

如果工具是分散的,元数据是孤立的,团队最终会拥有分散的专业知识。少数人成为了 Fivetran 专家,一些人成为了 dbt 奇才,还有一些人成为了气流大师。很快,数据堆栈就产生了“一个工具导致另一个工具”的思维模式。如果没有工具之间的本机集成,就没有显示数据管道健康状况的统一端到端视图,也没有对模式依赖关系的整体理解。当出现数据问题时会发生什么?正如我们在数据框架文章中所探讨的,在这种情况下,调试流程相当复杂——在分析师、分析工程师和数据工程师之间,他们需要找到正确的工具,然后才能排除错误。

这些是关键的日常问题,增加了从数据堆栈中获取价值的摩擦。如果没有将数据堆栈作为一个平台的长期战略观点,可能会出现更深层次的问题。

数据调试流程。摘自《走向数据科学》文章 构建现代数据堆栈时要牢记的 3 件事。图片由 Datacoral 提供。

高价值的平台不是偶然建立起来的——它们需要一些前瞻性思维和前期投资架构的意愿。如果开局良好,该平台将允许在有意义的约束下实现有机增长。我们的主张是,首先投资于元数据对于建立一个可持续的数据平台至关重要。了解和规划元数据使得编排高效且可伸缩。DevOps 创作工具开发变得更加容易。预防性地解决了数据和代码冲突。转换变更和编排逻辑保持同步。

我们如何培养一种元数据思维模式?我们从数据管道开始。

数据管道给数据堆栈带来了活力

数据管道没有得到太多的爱(尽管有相反的努力),但是它们给数据栈带来了生命。从表面上看,它们似乎足够简单,甚至非技术人员也能理解它们的工作。在转换数据以生成洞察之前,数据从源移动到数据仓库,管道的效用立即为人所知。

如果一个管道给栈带来了生命,那么管道元数据就是栈的脉冲。我们将它视为需要管理并始终保持“干净”的命脉。保持整洁的唯一方法是将元数据层放在数据堆栈成功的关键路径上。因此,我们必须将元数据定位为管道的主要驱动力,否则它将成为另一个信息源。

通过跟踪和理解元数据,我们保持数据干净。清洁度允许系统无问题运行,并提供自我记录和可观察性。其他工具可以更轻松地使用干净的元数据。如果没有干净的元数据,很难理解数据的质量和新鲜度。

管道元数据是关于管道本身的所有信息,如配置、运行时状态。图片由阿帕奇气流公司提供。

今天的数据管道是使用 ETL 系统构建的,ETL 系统通常是工作流管理器。这些系统可以运行相互依赖的作业,并允许工程师将这些作业和依赖关系手工编码到管道中。

换句话说,数据管道由移动和转换数据的作业组成。一个作业的输出数据被用作另一个作业的输入数据,使得这些作业相互依赖。数据管道本质上变成了图,更具体地说,是 Dag(有向无环图),其中节点是作业,边表示作业之间的依赖关系。当执行数据管道时,我们必须确保作业以正确的依赖顺序运行。这种基于依赖性的执行是编排系统的工作。

工作流程管理

通常,ETL 工具是围绕编排系统构建的;气流就是一个很好的例子。数据工程师在工作流管理器中编写定义这些作业及其依赖关系的管道代码。工作流管理器解释该管道代码,以正确的顺序执行作业。数据工程师负责确保所有的数据依赖关系都正确地转换为工作流管理器要解释的作业依赖关系。

这些工作流管理器被提供关于作业及其依赖性的配置,并生成关于作业执行的元数据。但是对于一个分析师来说,数据依赖比工作依赖更重要。数据管道的元数据由以下内容组成:

  1. 连接器配置:如何从源中检索数据(以增量方式或快照方式),定期获取更改的行还是连续读取更改日志。
  2. 批处理配置:获取数据或刷新转换的频率
  3. 沿袭:不同的转换如何依赖来自连接器和其他转换的数据。此外,出版商如何依赖底层数据
  4. 管道运行时元数据:成功处理步骤、失败、新鲜度检查结果、用作管道中任务障碍的数据质量度量、历史同步的历史以及重新处理动作的日志
  5. 模式变化:输入数据和相应转换的模式如何随时间变化的历史。

通常,这些信息的大部分隐藏在作业定义本身或 ETL 系统或工作流管理器管理的元数据中,因此这些信息不会清楚地暴露给其他应用程序。通常需要集成到不同的系统中,然后该系统将这些元数据用于其他应用程序。

孤立管道元数据的挑战

在我们的简化概念框架文章中,我们回顾了一个示例数据堆栈,包括:

谱系图显示了可能受数据转换作业影响的模式依赖关系。图片由 Datacoral 提供。

  • 用于摄取的五川
  • 用于转换的 dbt
  • 视觉化的观察者
  • 存储用雪花
  • 用于编排的气流

在这个例子中,气流是工作流管理器。触发 dbt 运行的任务被调度为在隐含理解 Fivetran 通常何时引入数据的情况下运行。

我们将使用一个常见的场景,Fivetran 每天从 Salesforce 和 MySQL 提取数据,并将其加载到 Snowflake。dbt 模型将来自这两个来源的数据结合起来,计算出每日报告。通常,Fivetran 在每天凌晨 1 点左右引入数据,因此为了安全起见,Airflow 可以将 dbt 安排在凌晨 3 点运行。大多数时候,这是有效的。

但是有一天,由于 MySQL 超载,从 MySQL 中提取数据有延迟,所以 Fivetran 被延迟了,直到凌晨 3:05 才导入数据。到那时,Airflow 已经触发了 dbt 运行,这意味着 Salesforce 数据是最新的,而 MySQL 数据不是,因此模型刷新会导致不正确的数据。

现在想象一下,Fivetran 每小时递增地接收 MySQL 数据,但是每天接收一次 Salesforce 数据。您马上会遇到一个问题,那就是必须等待全天 24 小时的 MySQL 更新和 Salesforce 的每日更新。这个问题通过在气流中编写几个传感器来解决,这些传感器等待 24 次 MySQL 摄取和一天的 Salesforce 摄取。当传感器满意时,一个任务触发 dbt 运行。

这种类型的设置会带来一些挑战。我们称之为围绕元数据的“裂脑”:

  1. dbt 为转换构建自己的 DAG,该 DAG 的操作复杂度与 Airflow 不同,air flow 是一个复杂的工作流管理器。dbt 更像是一个数据建模工具,而不是像 Airflow 一样的成熟的工作流管理器,因此很难找出如何在不重新计算整个 DAG 的情况下进行有效的再处理。
  2. Airflow 没有任何关于数据依赖性的信息,因为这些信息封装在 dbt 中。这意味着当 dbt 中的查询发生变化时,比如当 dbt 中的查询连接三个表而不是两个表时,作业依赖关系不会自动更新。因此,当三个表中只有两个被更新时,Airflow 可能会触发 dbt 运行,从而导致信息丢失。
  3. Airflow 没有关于 Fivetran 的数据加载器的信息。当 Fivetran 加载出现延迟时,或者如果从 Fivetran 加载的数据不完整,Airflow 不会察觉,它只会触发 dbt 运行。
  4. 要将每天的数据获取更改为每小时的数据获取,团队必须更改 Airflow 中的代码,以适当地处理下游的作业依赖性。

这些问题没有一个是不可解决的,但是它们需要在 Airflow 中实现大量的代码,以便理解数据依赖性并添加传感器来保证数据质量,等等。但是,即使在气流中设置了代码,数据管道的持续维护也需要昂贵的工程时间。对查询的每次更改都会导致更新气流管道的工作。而且涉及多个系统的事实意味着调试问题要花很长时间。

孤岛式管道元数据系统中出现的典型问题包括:

  • 元数据被孤立在不同的系统中,导致了“大脑分裂”的问题此外,不同系统之间的编排不一致,如 fivetran 和 dbt。
  • 重要的责任在于一个外部的工作流管理器,如气流来协调过程。这需要大量的编码来正确设置。
  • 像模式更改、历史同步和重新处理这样的持续操作很难在不同的系统之间进行协调。
  • 创作越来越困难,因为很难预见变化的影响
  • 调试堆栈中的问题很困难,因为必须在多个系统之间跳转。

元数据优先设计的蓝图

我们提出了一种架构,其中我们首先定义元数据本身。我们首先对可能存在的元数据进行建模,而不是担心数据管道功能的不同部分是如何工作的(比如如何从不同的源接收数据,如何转换数据本身,以及如何编排整个管道)。

一旦我们定义了元数据本身,我们就可以构建由元数据驱动的编排。这个管道元数据从 ETL 系统的外部开始。ETL 系统使用这些元数据进行操作,它自己的元数据非常少。然后,其余的用例可以依赖元数据来执行它们的操作。

元数据层本身可以被认为有四个组成部分:

  1. 用于审计和可观察性的纯元数据应用程序
  2. 用于访问控制的增强元数据
  3. 模式、沿袭和统计的管道元数据
  4. 管弦乐编曲

从元数据开始,围绕它构建一切。图片由 Datacoral 提供。

当确定编排和堆栈的每个其他部分都依赖于元数据时,可以用一致的方式设计数据堆栈的所有组件。使用孤立的方法,只需生成元数据并将其捕获到元数据系统中。这使得元数据成为数据堆栈中的二等公民,元数据工具只对审计和合规性问题有用,并且只在需要时有用。

元数据优先的思想意味着编排可以自动协调模式更改、历史同步和重新处理如何在数据流的不同步骤中传播。正如我们在上面的例子中所展示的,孤立的元数据给编排和转换工作带来了许多不必要的挑战,而这些挑战本来可以通过提前规划元数据来解决。

Datacoral 的元数据方法

Datacoral 的数据管道平台采用元数据优先的方法构建。我们的优势显而易见,因为我们的平台帮助我们只见树木不见森林。我们只需监控元数据,就可以完全透明地输入和输出数据。事实上,我们提供了自动模式发现和变更传播。工程师和分析师可以轻松地为转换编写 SQL 查询,并为视图设置数据间隔,而不用担心冲突和数据完整性问题。一旦我们开始合作,我们就帮助我们的客户变得重视元数据。

【Datacoral 干净元数据的下一级可观察性提供了自动谱系捕获,可全面洞察数据管道的每一步。图片由 Datacoral 提供。

我们不仅捕获数据沿袭,而且我们的编排实际上利用数据沿袭来确保仅当上游数据更新时才执行转换。我们的连接器在从任何来源接收每一条新数据时都会发布元数据。我们的编排检查谱系图,以根据所接收的每一条新数据来判断哪些转换可以运行。当转换所依赖的所有数据都被更新时,编排触发转换。并且,当转换运行时,它再次触发编排系统更新沿袭图中的依赖关系。不仅如此,甚至模式变化也通过谱系图传播。我们的客户不会遇到数据错误,因为我们的平台带有内置的数据质量检查,当每条新数据进入数据堆栈时都会触发该检查。Datacoral 能够确保仓库中的所有数据都是一致的。

如果没有干净的元数据,或者没有将元数据放在数据管道的关键路径中,所有这些都是不可能的。我们的平台自动理解数据依赖。我们自动进行数据质量检查,并提供内置的可观察性,因为所有的元数据都已经可用。我们的平台和连接器可以扩展到任何规模,这要归功于我们屡获殊荣的无服务器架构,它提供了简单性和有机增长的能力。

我们的平台不是构建数据堆栈的零敲碎打的方法。因为我们对元数据和现代公司的数据期望有一个整体的理解,所以我们不会面临许多团队在按需工具集合方面遇到的问题。集成和一致的设计从第一天起就可用,我们的客户不需要大量的定制代码来集成不同的系统。

我们在行业中看到的最大挑战是涉及的系统数量。我们提供了一个模型,在这个模型中,我们从配置和状态管理元数据的清晰定义开始,然后构建数据处理和编排。我们的服务受到管理,因此我们的客户不必成为工具和开发专家。Datacoral 的管道将接收、转换、模型构建和发布服务与堆栈中每个变更的端到端视图连接起来。

结论

由工具组合构建的数据堆栈不可避免地会导致孤立的元数据、分散的专业知识和长期的数据管理复杂性。我们不仅在与新客户的日常交往中看到这一点,而且解决这些问题的新工具也在不断涌现。工具优先的思想需要大量的定制代码,并且不能保证数据管道和元数据的端到端可见性。即使像 Airflow 这样可靠的工作流管理解决方案也需要持续的代码维护和大量的工程投资。

当元数据作为数据管道的关键路径的一部分进行管理时,可以实现显著的短期和长期优势。像 Datacoral 这样的工具利用干净的元数据来实现自动的沿袭捕获和模式更改传播。借助级联数据依赖关系的现成可视化,可以快速轻松地更改转换作业。团队能够更快地行动,他们可以花更多的时间处理数据,而不是被迫从事管道工作。

在 Datacoral,我们针对数据堆栈的简化概念框架并没有停留在元数据层。关于数据流和 devops 工具层,我们将在以后的文章中分享更多内容。干净的元数据为可扩展、可持续、可管理和低成本的数据堆栈打开了新的大门。在我们的下一篇文章中,我们将强调其中的一些优势。

我们希望这篇文章强调了在数据行业内围绕元数据首先需要什么,以及它在现代数据堆栈的所有级别上提供的好处进行对话的必要性。如果你对我们的元数据第一的论文有任何想法,给我们在 hello@datacoral.co 写信。

如何使用度量学习:嵌入是你所需要的

原文:https://towardsdatascience.com/how-to-use-metric-learning-embedding-is-all-you-need-f26e01597375?source=collection_archive---------9-----------------------

实践教程

找出常规分类和度量学习之间的区别,并通过我在 PyTorch 中实现的监督对比损失亲自尝试一下

Boitumelo Phetla 通过 unsplash

机器学习中最简单、最常见的任务之一就是分类。例如,在计算机视觉中,你希望能够微调普通卷积神经网络(CNN)的最后几层,以正确地将样本分类到某些类别(类)。然而,有几种根本不同的方法来实现这一点。

公制学习就是其中之一,今天我想和大家分享一下如何正确使用它。为了让事情变得实际,我们将看看监督的对比学习 (SupCon),这是对比学习的一部分,而对比学习又是度量学习的一部分,但稍后会有更多的介绍。

完整代码可以在 GitHub repo 中找到。

分类通常是如何完成的

在我们深入度量学习之前,首先了解分类任务通常是如何解决的,这实际上是一个好主意。今天实用计算机视觉最重要的想法之一是卷积神经网络,它们由两部分组成:编码器和头部(在这种情况下是分类器)。

哈桑通过神经蜂巢

首先,你拍摄一幅图像,并计算出一组能够捕捉该图像重要品质的特征。这是使用卷积和池操作完成的(这就是为什么它被称为卷积神经网络)。之后,您将这些特征分解到单个向量中,并使用常规的全连接神经网络来执行分类。在实践中,您采用一些在大型数据集(如 ImageNet)上预先训练的模型(例如 ResNet、DenseNet、EfficientNet 等),并在您的任务中对其进行微调(或者只是最后几层,或者是整个模型)。

然而,这里有几件事需要注意。首先,通常你只关心网络 FC 部分的输出。也就是说,您获取其输出,并将其提供给损失函数,以便保持模型学习。换句话说,您并不真正关心网络中间发生了什么(例如,编码器的功能)。其次,(再次,通常)你用一些基本的损失函数,比如交叉熵,来训练这整件事。

Kolluru via 媒介

为了对这个两步过程(编码器+ FC)有更好的直觉,你可以这样想:编码器将图像映射到一些高维空间(例如,在 ResNet18 的情况下,我们谈论的是 512 维,而对于 resnet 101–2048)。之后,FC 的目标是在这些代表样本的点之间画一条线,以便将它们映射到类。这两样东西是同时训练的。所以你试图优化特性,同时“在高维空间中画线”。

这种方法有什么问题?嗯,没什么,真的。它实际上工作得很好。但这并不意味着没有其他方法。

度量学习

现代机器学习中最有趣的想法之一(至少对我个人来说)被称为度量学习(或深度度量学习)。简而言之:如果我们不去研究 FC 层的输出,而是更仔细地研究编码器生成的特征,会怎么样呢?如果我们设法用一些损失函数来优化这些特征,而不是网络末端的逻辑,会怎么样?这实际上就是度量学习的内容:用编码器生成好的特征(嵌入)。

但是“好”是什么意思呢?如果你仔细想想,在计算机视觉中,你希望相似的图像有相似的特征,而不相似的图像有截然不同的特征。

监督对比学习

Prannay Khosla via arxiv

好吧,假设在度量学习中,我们只关心好的特征。但是有监督的对比学习是怎么回事呢?老实说,这种特定的方法没有什么特别的。这只是最近的一篇论文,提出了一些不错的技巧和一个有趣的两步方法:

  1. 训练一个好的编码器,能够为图像生成好的特征。
  2. 冻结编码器,添加一个 FC 层,然后就这样训练。

你可能想知道常规分类器训练有什么不同。不同的是,在常规训练中,你同时训练编码器和 FC。另一方面,在这里,你先训练一个像样的编码器,然后冻结(不再训练),只训练 FC。这种逻辑背后的直觉是,如果我们设法首先为图像生成真正好的特征,那么优化 FC 应该很容易(正如我们前面提到的,它的目标是优化分隔样本的线)。

培训过程的细节

下面我们来深挖一下中控实现的细节。

Prannay Khosla via arxiv

在检查训练回路之前,关于中控有一点你要了解的是正在训练的是什么模型。这很简单:编码器(如 ResNet、DenseNet、EffNet 等),但没有用于分类的常规 FC 层。

代替分类头,这里我们有一个投影头。投影头是 2 个 FC 层的序列,将编码器功能映射到一个更低的维度空间(通常为 128 维,您甚至可以在上图中看到该值)。使用投影头的原因是,模型学习 128 个精心选择的特征比学习来自编码器的所有几千个特征更容易。

好了,是时候最后检查一下训练循环了。

  1. 构建一批 N 个图像。与其他度量学习方法不同,您不需要太在意那些样本的选择。能拿多少就拿多少,剩下的由损耗来处理。
  2. 将这些图像通过网络成对转发,其中一对被构造为[ 增强(image_i)增强(image_i) ],得到嵌入。将它们正常化。
  3. 拿某个形象做锚。在批中查找同一类别的所有图像。把它们作为阳性样本。找出所有不同类别的图像。用它们做阴性样本。
  4. 将 SupCon 损失应用于标准化嵌入,使正样本彼此更接近,同时远离负样本。
  5. 训练完成后,删除投影头,并在编码器上添加 FC(就像在常规分类训练中一样)。冻结编码器,并微调 FC。

这里需要记住几件事。第一,训练完成后,去掉投影头更有利可图,在它之前使用特性。作者解释这一事实是由于头部信息的损失,因为我们降低了嵌入的大小。第二,扩充的选择很重要。作者提出了裁剪和颜色抖动的组合。第三,Supcon 一次处理批中的所有图像(因此,不需要构造成对或三元组)。并且批量中的图像越多,model 就越容易学习(因为中控有一个隐式正反硬挖掘的质量)。第四,实际上可以停在第四步。这意味着可以仅使用嵌入进行分类,而无需任何 FC 层。为此,计算所有训练样本的嵌入。然后,在验证时,为每个样本计算一个嵌入,将其与每个训练嵌入进行比较(比较=余弦距离),取最相似的,取其类。

PyTorch 实现

PyTorch 中实际上有一个中控的半官方实现。不幸的是,它包含非常恼人的隐藏错误。其中最严重的一个:回购的创建者使用了自己的 ResNets 实现,由于其中的一些 bug,批量大小比常规 torchvision 模型低两倍。最重要的是,回购没有验证或可视化,所以你不知道什么时候停止训练。在我的报告中,我修正了所有这些问题,并为稳定的训练增加了更多的技巧。

更准确地说,在我的实现中,您可以访问:

  1. 白蛋白增强
  2. Yaml 配置
  3. t-SNE 可视化
  4. 使用 AMI、NMI、mAP、precision_at_1 等指标进行两步验证(针对投影头前后的特征) PyTorch 指标学习
  5. 指数移动平均线用于更稳定的训练,随机移动平均线用于更好的概括和公正的整体表现。
  6. 自动混合精确训练,以便能够以更大的批量(大约 2 倍)进行训练。
  7. 标签平滑丢失,以及第二阶段训练的lr finder(FC)。
  8. 支持 timm 模型jettify 优化器
  9. 固定种子以便使训练具有确定性。
  10. 基于验证、日志保存重量—到常规。txt 文件,以及 TensorBoard 日志,以备将来检查。

从包装盒上看,repo 支持 Cifar10 和 Cifar100。然而,添加自己的数据集是非常简单的。为了运行整个管道,请执行以下操作:

python train.py --config_name configs/train/train_supcon_resnet18_cifar10_stage1.ymlpython swa.py --config_name configs/train/swa_supcon_resnet18_cifar100_stage1.ymlpython train.py --config_name configs/train/train_supcon_resnet18_cifar10_stage2.ymlpython swa.py --config_name configs/train/swa_supcon_resnet18_cifar100_stage2.yml

在那之后,你可以在相应的朱庇特笔记本中检查 t-SNE 可视化。例如,对于 Cifar10 和 Cifar100,您可能会看到如下内容:

Cifar10 与 t-SNE,验证和培训(中控),图片由作者提供

具有 t-SNE 的 Cifar10,验证和训练(交叉熵),图片由作者提供

带有 t-SNE 的 Cifar100,验证和培训(中控),图片由作者提供

带有 t-SNE 的 Cifar100,验证和训练(交叉熵),图片由作者提供

最后的想法

度量学习是一件非常强大的事情。然而,我很难达到普通 CE/LabelSmoothing 所能提供的准确度。此外,它还可能在训练期间计算量大且不稳定。我在各种任务(分类、超出分布预测、推广到新类别等)上测试了中控和其他度量损失,使用中控这样的东西的优势还不清楚。

等等,那有什么意义?我个人认为这里有两点。首先,中控(和其他度量学习方法)仍然可以提供比 CE 更结构化的集群,因为它直接优化了该属性。第二——多一项技能/工具让你尝试一下还是很有好处的。因此,有可能使用一组更好的扩充或不同的数据集(可能使用更细粒度的类),SupCon 可以产生更好的结果,而不仅仅是与常规分类训练相当。

所以我们必须尝试和实验。没有免费的午餐,对吗?

如何在 AWS 上使用 MLflow 来更好地跟踪你的机器学习实验

原文:https://towardsdatascience.com/how-to-use-mlflow-on-aws-to-better-track-machine-learning-experiments-bbcb8acded65?source=collection_archive---------17-----------------------

再现性的一步

尼古拉斯·托马斯在 Unsplash 上拍摄的照片

我们都知道跟踪你的机器学习实验有多痛苦。

你训练了一堆不同风格的模型:随机森林,XGBoost,神经网络…

对于每个模型,您将探索一个范围的超参数。然后计算一些测试数据的性能指标

有时,您通过添加或删除特征并再次重新训练您的模型来更改训练数据

其他时候,你必须在团队中工作,并与其他数据科学家比较你的结果。

你如何管理这些实验,使它们易于追踪和重现?你如何比较你的结果?

MLflow 非常适合这些任务。我们将在这篇文章中看到如何在本地使用它,以及如何在 AWS 上设置它。

让我们来看看!

PS:想更深入的现场使用 MLflow,看看我的视频教程:*

PS**:你可以在我的 Github 上找到代码 回购

什么是 MLflow

“ML flow 是一个开源平台,用来管理包括 实验 再现性 部署 ,以及一个 中央模型注册表。”—mlflow.org**

简而言之,MLflow 是一个包,您可以将其安装到 python 环境中,以便:

  • 执行实验跟踪(本文主题)
  • 以可复制的方式打包数据科学代码
  • 部署模型
  • 从开发到生产管理模型

MLflow 可与任何机器学习或深度学习框架集成,如 Scikit-learn、TensorFlow、PyTorch、h2o.ai、XGBoost 等。

此外,它也是云不可知的。你可以在任何地方运行:AWS,谷歌云平台或者 Azure 机器学习。我们将在这篇文章中看到如何在 AWS 上设置它。等到最后看看是怎么做的😉。

使用 MLFlow 跟踪的快速入门

MLflow tracking 是一个组件,可以帮助您非常轻松地记录您的机器学习实验。

它被组织成个实验并且每个实验被分成次运行。****

作者图片— MLflow 术语

实验的一个例子可以是“训练二元分类器”。在这种情况下,每次运行对应一个模型拟合。

在不同的运行中拟合不同的模型时,您可以使用 MLflow 来跟踪大量数据:**

  • 参数:您使用什么来调整您的模型(例如,n_estimators、max_depth、epochs、kernel_size、dropout、batch_size 等。)
  • 您的模型的指标(损失、AUC、MAE、MSEF1 分数,准确性,R 平方(r2))**
  • 数据:你的模型在每次运行中使用的不同版本的数据。
  • 保存的模型:与每次运行相关的二进制输出(想想 pickle 文件)
  • 代码产生的其他输出,如图像、CSV、文本、HTML
  • :负责运行的脚本/笔记本文件名 git 提交
  • 标签和注释:个人或团队注释

如何在我的代码中使用 MLflow?

相当容易。

  • 首先使用pip安装 mlflow:
*****pip install mlflow*****
  • 导入mlflow并使用set_tracking_uri方法设置 MLflow 存储每次运行结果的路径
  • 用适当的名称调用create_experiment方法

为了能够在每次运行时记录您的参数、指标并保存您的模型,您必须通过将experiment_id指定为参数,将您的代码包装在mlflow.start_run上下文中。

在这个上下文中,MLflow 创建一个具有唯一 id (run_id)的运行。本次运行将等待任何要跟踪的信息。

  • 使用mlflow.log_param方法可以保存参数
  • 可以使用mlflow.log_metric方法保存指标
  • 将(scikit-learn)模型保存为 artifcat 可以通过调用mlflow.sklearn.log_model以简单的方式完成

作者图片

好了,现在发生了什么?成绩在哪里?

MLflow 提供了一个很好的用户界面来可视化每次运行的结果,以及相互比较运行结果。

要启动 UI,在mlruns目录的相同位置运行以下命令:

*****mlflow ui*****

这将在端口 5000 启动一个本地服务器。

在左边,你会看到实验。在右边,你会看到跑道。该表是交互式的,您可以对运行进行排序,通过指定查询进行搜索,甚至进行比较(在第二个视图中)。

作者图片— MLflow UI(运行)

点击一次跑步后,您将被重定向到另一个包含更多详细信息的页面。

度量、参数、持续时间、状态、git 提交:

作者图片— MLflow UI(运行详情)

以及模型输出和工件:

作者提供的图片— MLflow UI(运行输出)

在 AWS 上设置跟踪服务器

到目前为止,我们在本地使用 MLflow。如果我们想与其他同事合作并在团队中跟踪实验,这并不理想。

幸运的是,设置远程 MLflow 跟踪服务器非常容易。让我们看看这是怎么做到的。

在本节中,我将使用 AWS,因此,如果您想要重现这些步骤,请确保您拥有一个帐户。

1 —使用 MLflow 设置远程 EC2 机器

  • 创建一个 IAM 用户。拿起Access key IDSecret access key凭证,将它们存放在安全的地方。我们以后会需要它们。
  • 对于同一个用户,创建一个 s3 存储桶来存储未来的工件:给这个存储桶命名。我的是mlflow-artifact-store-demo,但是你不能摘。注意,您不需要为您的 bucket 定制配置(例如,它不需要是公共的)
  • 启动一个 EC2 实例:它不必很大。一个t2.micro有资格自由层做得很好
  • 将此实例的安全组配置为接受端口 5000 和任何 IP 地址上的入站 HTTP 流量,以便可以从外部访问 MLflow 服务器
  • 使用 SSH 连接到您的实例,并运行以下命令来安装 pip、pipenv 和 mlflow
***# install pip
sudo apt update
sudo apt install python3-pip# install 
sudo pip3 install pipenv
sudo pip3 install virtualenv

export PATH=$PATH:/home/[your_user]/.local/bin/# install mlflow, awscli and boto3
pipenv install mlflow
pipenv install awscli
pipenv install boto3***
  • 在 EC2 机器上,使用用户凭证配置 AWS,以便跟踪服务器可以访问 s3 并在 UI 上显示工件。
    输入aws configure,然后按照提示输入凭证
  • 通过将主机定义为0.0.0.0并将--default-artifact-root定义为 S3 桶,在 EC2 实例上启动一个 MLflow 服务器
*****mlflow server -h 0.0.0.0 --default-artifact-root s3://mlflow-artifact-store-demo*****

现在您的 EC2 机器已经正确配置好了。

2 —设置您的环境

要允许 MLflow 将运行从您的本地环境推送到 EC2 和 S3,您必须:

  • 通过pip install boto3在本地安装 boto3
  • 将 AWS 凭证设置为环境变量,以便 MLflow 拥有 S3 读写访问的适当权限
*****export AWS_ACCESS_KEY_ID=<your-aws-access-key-id>
export AWS_SECRET_ACCESS_KEY = <your-aws-secret-access-key>*****
  • 将代码中的跟踪 URI 更改为HTTP://:5000****

现在一切都应该设置正确。

如果再次执行代码,运行将不再保存在本地,而是保存在远程跟踪服务器上,您可以通过访问 URL 来检查远程跟踪服务器。

作者提供的图片— MLflow UI(在远程服务器上)

快速笔记

  • 像我们这样设置 MLflow 对于相对较小的团队中的小项目来说是很好的。然而,它还不能投入生产。事实上,您必须保护对 MLflow UI 的访问,并在 EC2 上创建一个服务,以便在启动时在后台启动 MLflow
  • 你可以在 数据块 上使用 MLFlow 的托管版本
  • MLflow 跟踪与您正在进行的工作类型无关,无论是 NLP、计算机视觉还是无监督学习。只要您有指标和参数要跟踪,MLFlow 是一个很好的选择。

感谢阅读!所有代码都可以在我的 Github repo 上获得。

如何使用蒙特卡罗模拟帮助决策

原文:https://towardsdatascience.com/how-to-use-monte-carlo-simulation-to-help-decision-making-a0a164bc8619?source=collection_archive---------6-----------------------

使用蒙特卡罗模拟来做出现实生活中的决策

来源:https://unsplash.com/photos/vBWsG91aR_U

最近,我面临着一个非常困难的决定。出于不同的原因,我不得不在各种有趣的工作机会中做出选择。几个不眠之夜之后,我意识到一件事:为什么不用我所掌握的工具来帮我做决定呢?

本文将向您展示如何构建蒙特卡洛模拟来帮助您在生活中做出任何类型的决定。我将比较三个不同的工作机会,类似于我面临的问题。很明显,所有呈现的信息都是 100%虚构的,并不代表我所面对的现实。换句话说,它只是一个例子!

我们开始吧!

什么是蒙特卡洛模拟?

蒙特卡洛模拟是一种数学技术,用于在处理上述结果的不确定性时估计所有可能的结果。这个想法很简单。

假设你需要在回家的两条路上做出选择。第一个平均需要 20 分钟。它的灯很少,车也很少。很有可能你总是会在你期望的时间到达。第二个平均需要 15 分钟。然而,经常有更多的交通,灯等。有很多不确定性,你可能要花 10 到 45 分钟。

蒙特卡洛模拟通过利用概率分布建立可能结果的模型。通过模拟实验,比如说 10,000 次,你可以很好地了解各种选择的风险有多大。然后你可以决定哪条路更适合你。

设置模拟

假设你正在处理各种各样的工作机会。做决定的挑战在于总有一些不确定性。例如,你并不总是确切地知道你将做什么,谁将是你的同事,这份工作将如何帮助你的职业发展,等等。

这就是蒙特卡洛的用武之地。下面是设置实验要遵循的三个步骤。

  1. 定义做出决策的所有变量(工资、条件、地点、工作生活平衡等)。)
  2. 定义每个变量的重要性(权重)。换句话说,什么对你最重要?
  3. 对于每个选项,为每个变量定义一个您认为合适的可能性范围(本例中为 10 分)。当然,范围越大,就意味着你对这个变量的评分越不确定!范围代表变量的概率分布。

当然,第 2 部分和第 3 部分需要更定性方法。分数是基于你对事物的感知,你的观点。有人定义的 10/10 工作环境因人而异,没有简单通用的方法来量化。

然而,这种方法的有趣之处在于,它可以帮助你找出你潜意识中对各种选项的偏见。事实上,通过对所有变量本身进行分级,你可能会意识到一个选项在大多数方面都处于领先地位。

代码

这是我用来创建蒙特卡洛模拟的 Python 代码。

  • 在第 6 行,我定义了所有要考虑的变量。
  • 第 10 行是将所有权重分配给不同变量的地方。
  • 第 14 行非常重要。它是根据您为此变量提供的范围生成随机值的地方。
  • 第 20-22 行包含列表的列表,每个变量的等级范围。例如,对于 A,第一个列表[4,9]意味着work 变量可以在模拟中的等级 4 和 9 之间的任何地方找到自己。

结果

这是经过 10,000 次迭代后得到的分布。

我们看到似乎有两个最爱,作业 A 和作业 C。有趣的是,作业 A 的分布更广,而作业 C 似乎更安全,可能是因为不确定性更少。

模拟允许我们在多次迭代中比较各种选项,以确定这些选项的实际风险有多大。然后,用户的任务是决定与期权相关的额外风险是否值得回报。

结论

当存在不确定性时,蒙特卡罗模拟可以帮助做出决策,因为我们事先不知道变量的确切结果。这是一个非常简单而强大的技术。对于任何给定的实际问题,可以随意重用和修改代码。

非常感谢你的阅读!

如何像知道自己在做什么一样使用正态分布

原文:https://towardsdatascience.com/how-to-use-normal-distribution-like-you-know-what-you-are-doing-1cf4c55241e3?source=collection_archive---------23-----------------------

变得非常擅长正态分布

照片由 伊娃 像素

介绍

你在半夜叫醒一个统计学家,问他们关于正态分布的公式。半睡半醒时,他们会不折不扣地背诵这个公式:

正态分布是我们宇宙中最基本的东西之一。它几乎无处不在,自然,科学,数学。即使是最疯狂的现象,如质子相互碰撞,人群的行动等。可以用正态分布来模拟。

当我们绘制正态分布数据时,通常会形成一个钟形模式:

这就是为什么你也会听到它被称为钟形曲线高斯分布(以发现它的德国数学家卡尔·高斯命名)。

这在商业领域也有许多含义。它无处不在,以至于数据科学家和统计学家从正态假设开始分析许多新数据。此外,由于我们将在后面讨论的中心极限定理,即使基础分布不正态,您也可以导出正态分布。

在这篇文章中,您将学习如何在您的日常工作流程中使用这种发行版,方法是建立理论上的理解,并通过代码应用这些思想。

https://ibexorigin.medium.com/membership

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

https://alphasignal.ai/?referrer=Bex

正态分布预告

正态分布是你在分析过程中能想到的最好的东西。它有许多“好”的属性,使得它很容易使用和获得结果。

之前我们看了 ND 的钟形曲线。曲线的高度由标准偏差值决定。较小的标准差意味着更多的数据点聚集在平均值周围,而较大的值表示分布更加分散。这也可以解释为曲线的密度(稍后将详细介绍)是由标准偏差决定的。

ND 的平均值围绕 x 轴移动中心:

如你所见,理论上完美的 ND 有一个单峰,它也是对称线穿过分布的地方。此外,这些陈述可以是关于完美的 ND:

  • 平均值、中值和众数都相等。
  • 正好一半的值在对称线的左边,一半在右边。
  • 曲线下的总面积始终等于 1。

当然,真实数据很少遵循完美的钟形模式。然而,估计完美 ND 和基础分布之间的相似性是值得的,以查看我们是否可以安全地将其视为正态分布。我们将在接下来的几节中看到如何生成这个相似性过程。

PDF 到底是什么?

到目前为止,我们一直在看 NDs 的图,但我们没有问是什么函数产生这些图。要回答这个问题,你需要理解什么是连续概率分布。

根据描述性统计,有两种类型的数据:离散的和连续的。通过计数记录的任何数据都是离散的(整数值),如考试成绩、每天吃的苹果数量、遇到红灯停下来的次数等。相反,连续数据是通过测量记录的任何数据,如身高、体重、距离等。时间本身也被认为是连续的数据。

连续数据的一个定义方面是相同的数据可以用不同的度量单位表示。例如,距离可以用英里、公里、米、厘米、毫米来度量,列表 继续 。无论多小,对于连续数据都可以找到更小的度量单位。这也意味着一次测量可以有无限多的小数点。

在概率上,如果一个随机实验产生了连续的结果,那么它就会有一个连续的概率分布。例如,假设随机变量 X 以英寸为单位存储每天的降雨量。现在,降雨量几乎不可能是一个整数值,因为我们不能说今天的降雨量是 2 英寸,而不是一个水分子的多或少。发生这种情况的概率很小,我们可以有把握地说是零。

其他值也是如此,例如 2.1 或 2.0000091 或 2.000000001。下雨的几率总是 0。这就是为什么对于连续分布,我们有不同的函数,叫做概率密度函数。如果你正在阅读我最近的帖子,概率密度函数会计算离散事件的概率,比如掷骰子、掷硬币或任何其他的伯努利试验

概率质量函数将结果的概率编码为高度。以下是单个骰子滚动的 PMF 图示例:

如您所见,每个条形的高度代表单一结果的概率,如 1、3 或 5。它们都处于相同的高度,因为模具辊具有不连续的均匀分布。

现在,概率密度函数使用一个面积来表示某个概率。在我解释为什么之前,想想如果他们也在高度上编码概率会发生什么。如我所说,连续数据取某个值的概率很小,以至于高度都下降到 0,如下所示:

还记得统计学家最喜欢的公式吗?

这是正态分布的概率密度函数的公式。仅凭一己之力,它做不了多少事情。对于已知平均值和标准偏差的 ND,您可以在函数中输入任何 x 值。它输出 x 轴上该点处曲线的高度。注意,我不是说概率,而是说曲线的高度。我说过,对于连续分布,面积代表了一定的概率。图上的细线没有面积,所以我们需要重新定义我们最初的问题。

对于我们观察每天降雨量的随机实验,我们将不再问诸如降雨量为 3 英寸或 2.5 英寸的概率是多少之类的问题,因为答案总是 0。相反,我们现在问的是降雨量在 1.6 到 1.9 英寸之间的概率是多少。这相当于问这两条线之间的曲线下的面积是多少:

对于那些做过微积分作业的人来说,它是用这个积分公式计算的:

等等等等。先别走。我们在这里不会手工计算,甚至不会使用代码。稍后我会向你展示一个更简单的计算方法。

上面的公式得出了一个 0 到 1 之间的数字,即降雨量在 1.6 到 1.9 英寸之间的概率。现在,一个显而易见的问题是,既然没有给出概率,我们如何解释亚轴。嗯,我根本没有资格回答这个问题,所以我建议你看看 StackExchange 的这个帖子,看看 3Blue3Brown 的这个超赞的视频

接下来,我们将讨论累积分布函数,它为我们提供了一个更好的工具来计算面积下的概率,也许是 NDs 的一个改进的可视化。

累积分布函数

在这一点上,我想我们已经同意正态分布图有一条曲线。我们已经看到了钟形的,现在,是时候看看乙状结肠了:

在解释这个之前,我们先了解一下什么是累积分布函数(CDF)。我们最好从一个简单的例子开始:

Cdf.from_seq([1, 2, 3, 4, 5, 6])

如果我们从任何分布中取一个随机数并输入到 CDF 中,结果告诉我们得到一个小于或等于该随机数的值的概率。以上是单个模辊的 CDF。模具辊具有 1、2、3、4、5、6 的分布。假设我们随机选择了 4 个。

从我们的分布中观察到小于或等于 4 的值的概率是多少?根据上面的 CDF,是 0.6666。同样,有 100%的机会观察到小于或等于 6 的值,因为在我们的分布中所有的值都小于或等于 6。

在符号中,这看起来像这样:

因此,要计算 CDF,第一步是计算每个结果的个体概率。然后,任何值 x 的累积概率将是我们分布中所有有序个体概率的总和,直到 x

现在,回到正态分布的 CDF,我们可以很容易地解释它:

这条曲线也被称为 s 形曲线。ND 的平均值是曲线的中心:

使用 CDF,你不必使用 ND 的公式。例如,要找到 X 落在 1.6 和 1.9 之间的概率,您将找到上限的 CDF 并减去下限的 CDF:

这么简单!

最后,Python 正常的东西

最后,我将揭示我是如何绘制所有这些钟形曲线和 CDF 的。首先,任何分布的钟形曲线都可以用 Seaborn 的kdeplot函数生成。

为了绘制这个分布图,我们需要创建分布图本身。这可以通过使用numpy.random.normal来完成:

这里,我们从平均值为 5、标准差为 2 的正态分布中抽取 10k 个样本。接下来,我们将使用kdeplot来制作曲线:

kdeplot将任意值序列作为分布。它的bw_adjust参数控制曲线的平滑度。有关该功能的更多信息,请访问文档

现在,创建 CDF 还需要做一些工作。我们可以手工生成它,但是我们将使用empiricaldist库的Cdf功能:

from empiricaldist import Cdf

Cdf有一个from_seq方法可以计算任何分布的 CDF:

接下来,我们将用pyplot绘制这个分布图:

正如所料,我们在图上看到平滑的 s 形曲线。

最后,我们将看一个实际的用例。我们将使用 CDF 图来找出给定的分布是否正态。例如,我将从 Seaborn 加载 Iris 数据集:

在前面的章节中,许多自然现象遵循正态分布,因此我们可以假设鸢尾花物种的测量值遵循正态分布。让我们看看我们有多正确:

从一个眼球估计就已经可以看出,我们的假设是不正确的。不过,为了确保绘制完美的正常 ND 进行比较会更好。你问哪一个?当然,NDs 有无限多种,那么我们如何选择一种呢?

好吧,明智的做法是画出与基础分布具有相同均值和标准差的 ND,这样两个分布会很接近:

现在,更清楚的是,这两种分布是完全不同的。然而,在许多情况下,这两种分布彼此非常接近,但又不完全相同,即不是正态分布。对人眼来说,比较接近的钟形曲线不是一件容易的事情。所以我们需要用更好的视觉来比较这样的分布。我想你已经猜到了,但是我们将使用 CDF。

我们将使用与上面相同的技术,但是将 PDF 替换为 CDF:

像往常一样,我们生成萼片长度的 CDF 并绘制成一条线。接下来,我们取萼片长度的平均值和标准差,并用这些参数生成一个完美的正态分布。然后,我们也为其生成 CDF,并将它们绘制在彼此之上。为了清楚起见,我用点作为标记,省略了线条样式。这个视图提供了比逐行比较更好的视觉比较。

现在,解释这个,我们可以看到分布并没有很大的不同。我们还必须考虑到样本量非常小(150)。

简而言之,如果你想模拟一个正态分布,使用np.random.normal。尝试增加样本量以获得更好的准确性。如果你想知道一个分布是否是正态分布,试着用基本分布的参数画出它的 CDF 和一个完美 nd 的 CDF。

结论

我们已经谈了这么多了。尽管如此,关于正态分布还有很多东西要学。也就是说,我们没有涵盖中心极限定理或经验法则,或许多其他主题。我留下了一些帮助我理解这个主题的资源链接:

如何使用成对相关性进行鲁棒的特征选择

原文:https://towardsdatascience.com/how-to-use-pairwise-correlation-for-robust-feature-selection-20a60ef7d10?source=collection_archive---------3-----------------------

将久经考验的方法添加到您的武器库中

照片由 Pixabay 像素

相关系数是多少?

在我上一篇关于特性选择的文章中,我们关注了一种基于特性的移除技术。在本帖中,我们将探讨一种更可靠、更稳健的方法,让我们看到特性之间的联系,并决定它们是否值得保留。正如你从标题中所看到的,这种方法使用成对相关。

首先,让我们简单的接触一下皮尔逊相关系数——通常表示为 r 。该系数可用于量化单个指标中两个分布(或特征)之间的线性关系。它的范围从-1 到 1,-1 是完全负相关,+1 是完全正相关。

作者图片

例如,身体测量通常有很强的正相关性。你可以预期高个子会有更长的胳膊和腿,或者宽肩膀的人会更重。还有,冰淇淋的销量和温度负相关,或者跑得越远越慢等等。

关于如何使用、解释和理解相关系数的深入指导,请参考我的另一篇文章

但是相关系数和机器学习或者特征选择有什么关系呢?嗯,假设两个特征之间的相关系数是 0.85。这意味着在 85%的情况下,您可以仅使用特性 1 的值来预测特性 2。换句话说,如果数据集中有要素 1,则要素 2 不会带来太多新信息。这就是为什么保留特征 2 没有意义,因为它只会在训练模型时增加复杂性。

使用成对相关进行要素选择就是这么回事-识别高度相关的要素组并仅保留其中一个要素,以便您的模型可以使用尽可能少的要素获得尽可能大的预测能力。

https://ibexorigin.medium.com/membership

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

https://alphasignal.ai/?referrer=Bex

绘制完美的相关矩阵

识别高度相关特征的最快且通常是最好的方法是使用相关矩阵。该矩阵显示了数据集中每一对数值要素之间的相关性。

让我们来看一个使用墨尔本住房数据集的例子,该数据集包含 13 个数字特征:

计算矩阵很容易通过调用 DataFrame 上的.corr()方法来完成。接下来,我们将它传递给 Seaborn 的热图函数,通常这样做是为了生成漂亮的视觉效果:

是的,默认热图没有那么好。让我们给它补个妆:

首先,我们创建一个定制的发散调色板(蓝色->白色->红色)。然后,我们将颜色条以 0 为中心,使注释能够看到每个相关性,并使用 2 个小数点。

如您所见,矩阵将每对之间的相关性显示两次,因为 A 和 B 之间的相关性与 B 和 A 之间的相关性相同。此外,对角线由 1 组成,表示特征与其自身的相关性。所有这些额外的信息会让人分心。这就是为什么我们要去掉矩阵的上半部分:

在上面代码片段的第 4 行,我们创建了一个 2D 布尔掩码。首先,np.ones_like创建一个 2D numpy 数组,其形状与填充了True值的相关矩阵相同。然后,将这个数组传递给np.triu,将它转换成适合我们需要的布尔掩码。我们只是将这个面具传递给heatmapmask论证,这给了我们上面美丽的情节。

下面是一个绘制这些完美相关矩阵的小函数:

即使我们可以通过编程找到所有高度相关的特性,我们仍然应该直观地探索它们。因为像上面这样的热图有助于我们了解相关性是否有意义。例如,新生婴儿的数量可能与附近鹳的数量高度相关,尽管这没有任何意义。这就是为什么要进行视觉探索,以查看各组特征是否实际上相互关联,以及寻找它们之间的联系是否有意义。

如何移除高度相关的特征

现在,让我们看看我们如何实际删除高度相关的功能。这次我们将使用不同的数据集— Ansur 数据集。它包含了 6000 名美国陆军人员的所有可以想象的身体尺寸,还包含了 98 个数字特征。这是一个练习要素选择技能的绝佳数据集,因为该数据集中有许多相关的要素:

我们将只处理数字特征,因此,我们将隔离它们:

顺便说一句,试图用这么多特征来绘制数据集的相关矩阵是没有用的。

我们的目标是消除强烈的相关性,无论是负面的还是正面的。因此,我们这次将通过在.corr()上链接.abs()方法来构建具有相关性绝对值的矩阵:

接下来,我们再次创建一个布尔掩码,用于矩阵的子集化:

使用熊猫数据帧的mask方法(相关矩阵是一个数据帧)将 NaN 值放在矩阵的上半部分和对角线上:

>>> reduced_matrix.iloc[:5, :5]

接下来,我们需要设置一个阈值来决定是否删除某个特性。应该仔细选择这个阈值,并且只有在彻底了解数据集的情况下才能选择。对于我们的例子,我们将选择阈值 0.9:

上面的列表理解找到了满足阈值 0.9 的所有其他列。使用any可以让我们不使用嵌套的 for 循环,就像这样:

列表理解无疑是一个更好的解决方案。注意,如果我们没有将NaN放在矩阵的上半部分和对角线上,我们将丢失所有相关的特征,而不是保留其中的一个。

下面是一个函数,它对任意阈值执行上述操作,并返回要删除的列的列表:

现在,让我们实际删除这些列:

现在,让我们看看放弃这么多特性是否是正确的选择。我们将通过训练两个RandomForestRegressor来检查这一点:一个在完整数据集上,一个在缩减的、特征选择的数据集上。目标重量以磅为单位- Weightlbs:

我们得到了一个非常好的结果,即使有这么多的功能。现在,让我们在特征选择的数据帧上重复上述内容:

我们的测试分数只降低了 2%,而运行时间却减少了两倍。

结论

总之,使用成对相关允许我们检测高度相关的特征,这些特征不会给数据集带来新的信息。因为这些特性只会增加模型的复杂性,增加过度拟合的机会,并且需要更多的计算,所以应该去掉它们。

然而,在使用这种技术之前,通过做适当的 EDA 来彻底理解你的数据集。总是寻找没有意义的相关性,例如,没有联系的随机相关特征。

如果你不知道接下来要读什么,这里我为你挑选了一些:

</11-times-faster-hyperparameter-tuning-with-halvinggridsearch-232ed0160155> https://towardsdev.com/intro-to-object-oriented-programming-for-data-scientists-9308e6b726a2

如何使用排列测试

原文:https://towardsdatascience.com/how-to-use-permutation-tests-bacc79f45749?source=collection_archive---------1-----------------------

排列测试及其如何应用于时序数据的演练。

排列检验是非参数检验,只需要很少的假设。所以,当你不太了解你的数据生成机制(总体)时,排列测试是确定统计显著性的有效方法。

图 1:排列测试分布的例子。红色垂直线是我们的观测数据测试统计。这里,98.2%的排列分布在红线以下,表明 p 值为 0.018。图片作者。

斯坦福大学研究人员最近发表的一篇论文将排列测试框架扩展到了时间序列数据,这是一个排列测试通常无效的领域。这个方法非常数学化,而且是全新的,所以几乎没有支持,也没有 python/R 库。然而,它非常高效,可以大规模实施。

在本帖中,我们将讨论排列测试的基础,并简要概述时间序列方法。

让我们开始吧。

技术 TLDR

置换检验是非参数检验,只依赖于可交换性的假设。

为了得到 p 值,我们随机抽样(没有替换)我们感兴趣的变量的可能排列。p 值是检验统计量大于观测数据的样本比例。

时间序列数据很少可以交换。考虑到缺乏可交换性,我们将检验统计量除以标准误差的估计值,从而将检验统计量转换为 t 统计量。这个“学生化”过程允许我们对不可交换的数据进行自相关测试。

但是,排列测试实际上是如何工作的呢?

让我们慢一点,真正理解排列测试…

排列测试 101

排列测试非常简单,但是惊人的强大。

排列检验的目的是估计总体分布我们的观察值来自的分布。从那里,我们可以确定我们的观察值相对于总体是多么稀少。

在图 2 中,我们看到了排列测试的图形表示。有 5 个观察值,由每一行和两个感兴趣的列表示,风险死亡

图 2:排列测试的框架。图片作者。

首先,我们开发了我们感兴趣的变量的许多排列,标记为 P1,P2,…,P120。在这一步的最后,我们将从我们的总体中获得大量的理论数据。然后将这些图结合起来估计人口分布。

请注意,我们永远不会看到重复的排列— 排列测试对所有可能的排列进行采样,而不进行替换。

其次,我们可以计算我们的 p 值。使用中位数作为我们的测试统计量(尽管它可以是从我们的数据中得到的任何统计量),我们将遵循以下步骤:

  1. 计算观察数据的中位数(死亡数列)。
  2. 对于每个排列,计算中间值。
  3. 确定比我们观察到的中位数更极端的排列中位数的比例。这个比例就是我们的 p 值。

如果你喜欢代码,这里有一些计算 p 值的 pythonic 伪代码:

permutations = permute(data, P=120)observed_median = median(data)
p_medians = [median(p) for p in permutations]p_val = sum(p > observed_median for p in p_medians) / len(p_medians)

既然我们理解了这个方法,让我们决定什么时候使用它。

排列检验的假设

排列测试之所以吸引人,是因为它们是非参数的,并且只需要假设可交换性。让我们依次讨论这两个概念。

参数方法假设了一个潜在的分布。非参数方法不会。就这么简单。

图 3:参数化和非参数化可视化。图片作者。

现在使用参数方法要求我们对数据的分布有信心。例如,在 A/B 测试中,我们可以利用中心极限定理得出结论,观察到的数据将呈现正态分布。从那里我们可以运行 t 检验,并获得 p 值。

然而,在其他情况下,我们无法知道分布,所以我们必须利用非参数方法。

出于测试目的,参数和非参数方法都估计总体分布。主要区别在于参数测试利用假设来创建分布,而非参数测试利用重采样。

太好了。让我们继续讨论可交换性。

可交换性指的是一系列随机变量。从形式上讲,如果一个序列的任意排列具有与原序列相同的联合概率分布,则该序列是可交换的。

图 4:一枚有偏见的硬币的形象化。图片作者。

因此,在图 4 中我们可以看到两枚硬币。左边的硬币是公平的,有 50%的正面(H)和 50%的反面(T)。正确的硬币有 60%的机会正面朝上。

如果我们多次抛硬币,我们会有一个可交换的序列。同样,如果我们多次投掷不公平的硬币,我们会有一个可交换的序列。然而,如果我们在公平和不公平硬币之间交替,我们将没有一个可交换的序列。

如果我们的数据生成机制(硬币)的分布发生变化,我们的序列不再可交换。

图 5:互换性的定义。图片作者。

在数学上,我们定义可交换性,如图 5 所示。左边的序列是原始数据,右边的序列是原始数据的排列。如果它们具有相同的分布,它们是可交换的。

时间序列相关性的排列检验

通常,时间序列数据是不可交换的——以前的值可能是未来值的决定因素。如果你有强有力的证据证明你的时间序列数据确实是可交换的,那么你可以运行一个常规的排列测试,但是如果没有,你需要利用下面的方法。

论文讨论了在时间序列数据集上运行自相关测试的方法,但是概念可以推广到其他测试。还要注意,对于所有值,自相关只是一个值和它的前一个值之间的相关性。

我们将简单地介绍一下这个方法,因为它非常非常复杂。但是,方法如下:

  1. 估计我们的自相关值的标准误差。
  2. 通过除以标准误差,将我们的统计转换为 t 统计。
  3. 做个 t 检验。

第 2 节概述了标准误差的计算,特别是等式 2.9 和 2.12。不幸的是,我们不打算在这里讨论它们,因为它们实在太长了。

摘要和实施说明

现在,您已经了解了置换测试的步骤,以及如何将它们应用于不可交换的时间序列数据的一些信息。

总而言之,排列测试很棒,因为它们是非参数的,并且只需要可交换性的假设。排列测试对我们的数据进行多种排列,以估计我们人口的分布。从那里,我们可以给我们观察到的数据分配一个 p 值。对于不可交换的时间序列数据,本文概述了一种方法。

最后,这里有一些关于实现的注意事项:

  • 当有许多行时,您不能开发所有可能的排列。取而代之的是,对那些没有替换的排列进行抽样,以估计分布。
  • 当样本量很小或者参数假设不满足时,排列检验是有效的。因为我们只要求可交换性,所以它们非常健壮。
  • 排列检验往往比参数检验给出更大的 p 值。
  • 如果你的数据在实验中是随机的,你可以使用一个简单的随机测试。
  • 时间序列自相关方法需要平稳数据。如果您的数据不稳定,请查看差异

感谢阅读!我会再写 34 篇文章,把学术研究带到 DS 行业。查看我的评论,链接到这篇文章的主要来源和一些有用的资源。

如何在 React 中使用 Plotly.js 来可视化您的数据并与之交互

原文:https://towardsdatascience.com/how-to-use-plotly-js-in-react-to-visualize-and-interact-with-your-data-ab4c2c67e8f6?source=collection_archive---------13-----------------------

简单易懂的教程

在 React 中使用 Plotly.js 的简短教程

卢卡斯·布拉塞克在 Unsplash 上的照片

几个月前,我写了一篇关于如何用 Python Plotly 可视化交互式 3D 网络(或数据)的教程,我想为 Plotly.js 再写一篇可能是个好主意

有人可能更喜欢 Plotly.js 而不是 Python Plotly 的原因之一可能是因为加载速度——我曾经编写过一个 React + Flask 应用程序(其中数据集和 Plotly 图形都在 Flask 上),当我将其与我的 React + Plotly.js 应用程序进行比较时,Plotly.js 的交互性和加载速度要好得多。

所以这里有一个快速教程,教你如何用 React 来使用 Plotly.js!ʕ•́ᴥ•̀ʔっ♡

本教程的最终代码可以在这个 GitHub 资源库中找到:https://GitHub . com/reine 0017/mini-Tutorials/tree/master/React-Tutorials/visualize-data-plot ly

让我们从一个基本的 React 应用程序开始。在所需的项目目录中,运行:

npx create-react-app .

然后运行:

npm start

来打开网页。

接下来,我们要安装 Plotly.js 库。您可以参考此链接获取安装说明。但是基本上,你只需要运行(从上面链接的 npm 包页面):

npm install react-plotly.js plotly.js

好了,现在安装已经完成,让我们开始写一些代码吧!

有大量不同的情节,地图和图表,你可以玩 Plotly。在本教程中,我们将了解如何使用 Plotly.js 创建一个简单的螺旋形交互式 3D 散点图。

让我们首先创建 Plotly 组件,然后导入 react-plotly 库。之后,只需像这样键入组件:

一旦我们将其导入到 App.js 文件中,

这是它带来的结果:

只是一个没有数据的空图(因为我们没有输入任何数据)

现在,让我们用一些数据填充图表。你可以去他们的官方网站看看你能用 Plotly 创建什么样的可视化效果。

由于我们想在本教程中创建一个螺旋 3D 图形,我们将首先获得该 3D 图形的 x、y 和 z 数据坐标:

接下来,让我们用这些数据填充我们的组件。

对于您想要的图表,您可以使用更多的参数。但在这种情况下,我只对它做了一些小的修改。下面是最终结果:

这个 3D 散点图是完全交互式的,当用户点击它时,您也可以配置某些动作。出于演示的目的,我将只让它在控制台记录它的坐标 onClick。

要注册用户的点击(在图中的坐标点上),我们可以写如下内容:

onClick={(data) => { console.log(data.points[0])}}

组件内部。

下面是最终结果:

今天的教程到此为止!希望这是有帮助的,如果你有任何问题,请随时评论或给我发信息。谢谢你们读了这篇文章,很高兴

阴谋诡计!ʕ•́ᴥ•̀ʔっ♡

我真的不喜欢无耻的插头,但如果你已经在考虑每月 5 美元获得中等会员资格,如果你能使用我的推荐链接来注册,我会非常感激——https://reine-ran.medium.com/membership😃

如何在工业环境中使用 PointNet 实现 3D 计算机视觉

原文:https://towardsdatascience.com/how-to-use-pointnet-for-3d-computer-vision-in-an-industrial-context-3568ba37327e?source=collection_archive---------18-----------------------

我们如何使用来自工业 3D 传感器的数据测试 PointNet

来自 revopoint3d 的图像

三维计算机视觉

3D 计算机视觉是一个迷人的领域!

我们可以用多种形式在 3D 中表示 2D 的场景,而不是用一组像素值。

一些著名的形式:

  • 深度图像,也称为 RGBD,其中 D 代表深度。
  • 3D 点云,其中有一组在 3D 参考框架中表示的点。
  • 体素,我们将 3D 场景表示为一组立方体。
  • 网格,我们对 3D 点云进行三角剖分,以获得连接 3D 点的平滑三角形。

有很多经典算法使用 3D 图像来做各种很酷的应用,如增强现实。

但是深度学习已经在这个领域掀起了风暴(就像它在许多其他领域一样!).现在,我们有了神经网络,它正在取代经典算法,并大幅超越其性能。

3D 计算机视觉的深度学习

已经有几种方法将深度学习应用于 3D 图像。

一种著名的方法是名为 PointNet 的神经网络,它将 3D 点云作为输入。

这个网络可以用于几个任务:分类,语义分割和部分分割,如下图所示。

图片来自 PointNet paper [1]

网络的架构出奇的简单!

它将 N 个点作为一组无序的 3D 点。

它应用一些变换来确保点的顺序无关紧要。

然后,这些点通过一系列 MLP(多层感知器)和 max pooling 层,最终获得全局特征。

为了分类,这些特征然后被馈送到另一个 MLP,以获得代表 K 个类别的 K 个输出。

对于分割,添加另一个子神经网络以获得逐点分类。

图片来自原始纸张[1]

工业背景下的点网

PointNet 可以处理原始格式的 3D 点云。

这意味着许多行业可以将它与 3D 传感器结合使用。

我们和一些前同事一起对此进行了实验,并发表了一篇论文[2]概述了我们所做的一些实验。

实验的目标是尝试和分类 4 种不同类型的“工业支持”。这些“工业支架”可以在飞机底盘内找到。下图显示了 4 种类型的支架。

图片来自我们的论文[2]

我们学到了什么

我们做了几次实验来实现我们对这些点云进行分类的目标。我们没有太多的数据,所以我们必须找到允许我们利用有限数据集进行深度学习的方法。下文提到了一些重要的调查结果。

1.具有不完美三维点云的点网

我们发现,即使点云远非完美,也可以对使用工业 3D 传感器获得的点云应用 PointNet。例如,在下图中,您可以在左侧看到某个场景的 2D 图像,在右侧看到表示同一场景的 3D 点云,这些点云是使用 3D 工业传感器获取的。正如你可以清楚地看到,收购远非完美。但即使是这样的收购,我们也能得到一些非常有趣的结果。

图片来自我们的论文[2]

2.迁移学习可以用在 3D 点云上,就像在 2D 图像上一样

由于我们的数据量有限,我们尝试对 3D 点云使用迁移学习,就像对 2D 图像一样。

我们使用了一个名为 ModelNet40 的数据集,它由 12000 多个 CAD 模型组成,分为 40 个类。我们首先在这个数据集上训练 PointNet,然后在我们的小数据集上对它进行微调。下表显示了我们利用迁移学习获得的一些结果。我们实现了一些非常高的精度!

图片来自我们的论文[2]

3.影响点网性能的重要因素

当涉及到性能时,输入点云中包含的点数可能是一个重要因素。由于我们可以控制输入点云的大小,我们用几个值进行了实验,我们发现根据这个数字,精度可以变得非常高或非常低。这是有意义的,因为我们的点云已经不完美,所以当我们对它们进行缩减采样时,我们会丢失更多信息,而这些信息对于通过点网学习良好的特征可能是有价值的。

我们发现另一个非常重要的因素是用于获得 PointNet 最终输入的采样算法的类型。

从点的数量来看,来自 3D 传感器的原始点云可能非常大,因此我们总是需要对它们进行下采样。为此,我们使用了 2 种不同的算法:随机采样和 f 最优点采样(FPS)。后一种算法擅长保留对结果产生积极影响的有意义的云结构。

结论

在本文中,我们介绍了 PointNet,一种用于 3D 点云的深度神经网络,如何用于来自工业传感器的 3D 数据。我们看到了它是如何用于将点云分成 4 个不同的类别,即使它们是不完美的。我们还看到了一些因素,如输入点的数量和采样算法的类型如何影响结果。

参考

[1]查尔斯·r·齐,,凯春莫,列奥尼达·j·吉巴斯." PointNet:用于三维分类和分割的点集深度学习"

[2]伊万·米哈伊洛夫、伊戈尔·约万切维奇、努尔·伊斯拉姆·莫赫塔里、让-何塞·奥尔特乌。"在结构化工业环境中使用三维传感器进行分类"

作者制作的图像

我是一名机器学习工程师,致力于解决具有挑战性的计算机视觉问题。我想帮助你学习应用于计算机视觉问题的机器学习。以下是方法。

  1. 通过帮助您了解该领域的最新动态。我几乎每天都在 、LinkedIn、Twitter****上分享小型博客帖子。那就跟我去吧!
  2. 每周给你一份我的 时事通讯 上那些琐碎帖子的摘要。所以订阅吧!
  3. 通过在 Medium 上写关于机器学习不同主题的文章。所以跟我来吧!
  4. 给你一份免费的机器学习工作清单,帮助你检查你需要学习的所有要点,如果你计划在 ML,特别是在计算机视觉方面的职业生涯。你可以在这里 获得核对表

5.最后但同样重要的是,通过与你分享我的 免费入门张量流课程 ,它有超过 4 小时的视频内容,你可以在那里问我任何问题。

此外,如果您有任何问题或者您只是想聊聊 ML,请随时在 LinkedIn 或 Twitter 上联系我!

如何使用泊松分布像你知道你在做什么

原文:https://towardsdatascience.com/how-to-use-poisson-distribution-like-you-know-what-you-are-doing-c095c1e477c1?source=collection_archive---------15-----------------------

幸运的是,这些情况下有泊松分布

照片由 安德里亚·皮亚卡迪奥 发自 像素

故事

你从事自由职业已经 10 年了。到目前为止,你的平均年收入大约是 80,000 美元。今年,你觉得自己停滞不前,决定达到 6 位数。为了做到这一点,你想从计算这个令人兴奋的成就发生的概率开始,但你不知道如何去做。

事实证明,你并不孤单。在这个世界上,有许多情况下,某个随机事件的发生率是已知的,而企业希望找到该事件在未来发生的几率是高于还是低于这个发生率。

例如,已经知道自己平均销售额的零售商会试图猜测他们在黑色星期五或网络星期一等特殊日子会多赚多少钱。这将帮助他们储存更多的产品,并相应地管理他们的员工。

在本帖中,我们将讨论泊松分布背后的直觉,泊松分布用于模拟上述情况,如何理解和使用它的公式,以及如何使用 Python 代码模拟它。

https://ibexorigin.medium.com/membership

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

https://alphasignal.ai/?referrer=Bex

离散概率分布

这篇文章假设你对概率有基本的了解。如果没有,请查看这篇伟大的文章。

在我们开始这篇文章的真正内容之前,我们将对离散概率分布有所了解。

首先,让我们定义什么是离散的。在描述统计学中,离散数据是通过计数记录或收集的任何数据,即整数。例如考试成绩、停车场的汽车数量、医院的分娩数量等。

然后,有随机实验,有离散的结果。例如,掷硬币有两种结果:正面和反面(1 和 0),滚动骰子有 6 种不连续的结果,等等。如果一个随机变量 X 被用来存储一个离散实验的可能结果,它将有一个离散的概率分布。

概率分布记录了随机实验的所有可能结果。

举一个简单的例子,让我们建立一次抛硬币的分布:

那很容易。如果我们想以编程的方式记录分布,它应该是 Python 列表或 Numpy 数组的形式:

然而,你可以想象,对于有许多可能结果的大型实验来说,以这种方式构建分布并找到概率变得不可能。值得庆幸的是,每一个发明的概率分布都有自己的公式来计算任何结果的概率。对于离散概率分布,这些函数被称为概率质量函数(PMF)。更详细的解释,请阅读我在上一篇关于离散分布的文章

泊松分布

我们将通过案例研究开始理解泊松分布。说你真的很喜欢在医院里看新生儿。根据您的观察和报告,您知道医院平均每小时观察 6 名新生儿。

照片由米哈尔·巴尔·哈伊姆Unsplash 拍摄

你发现你明天要出差,所以在去机场之前,你想最后一次去医院。因为你要离开几个月,你想看到尽可能多的新生儿,所以你想知道在飞机起飞前一小时看到 10 个或更多婴儿的可能性。

如果我们将观察新生婴儿视为随机实验,结果将遵循经典的泊松分布。原因是它满足泊松分布所需的所有条件:

  • 有一个已知的事件发生率:平均每小时 6 个新生儿
  • 事件独立发生:一个婴儿的出生不影响下一个的时间
  • 已知的比率是不变的:每小时婴儿的平均数量不会随着时间而改变
  • 两件事不会在完全相同的时刻发生
  • (提醒:每个结果都是独立的)

泊松分布有许多重要的商业含义。企业通常使用它来预测特定一天的销售额或客户数量,因为他们知道平均日费率。做出这样的预测有助于企业在生产、调度或人员配备方面做出更好的决策。例如,库存过多意味着低销售活动的损失,或者没有足够的货物意味着失去商业机会。

简而言之,泊松分布有助于发现事件在固定时间间隔内发生的概率大于或小于已经记录的比率(通常表示为 λ (lambda) )。

其概率质量函数由以下公式给出:

在哪里

  • k 是成功的次数(期望事件发生的次数)
  • λ是给定的速率
  • e 是欧拉数:e = 2.71828…
  • k!k 的阶乘

如果你仍然对 PMFs 感到不舒服,请阅读我的上一篇文章

使用这个公式,我们可以发现看到 10 个新生婴儿的概率,知道平均比率是 6:

不幸的是,只有 4%的机会看到 10 个婴儿。

我们不会详细讨论这个公式是如何推导出来的,但是如果你好奇,可以看看汗学院的这个视频。

仍然有一些要点你必须记住。尽管有一个已知的比率,但它只是一个平均值,所以事件发生的时间完全是随机的。例如,你可以连续观察两个婴儿的出生,或者你可能要等半个小时才能看到下一个。

此外,在实践中,速率λ可能不总是恒定的。这甚至可以适用于我们的新生儿实验。即使这个条件不成立,我们仍然可以将分布视为泊松分布,因为泊松分布足够接近来模拟情况的行为。

模拟泊松分布

使用numpy从泊松分布中模拟或抽取样本非常容易。我们首先导入它并使用它的random模块进行模拟:

import numpy as np

为了从泊松分布中抽取样本,我们只需要速率参数 λ 。我们将它插入np.random.poisson函数,并指定样本数:

poisson = np.random.poisson(lam=10, size=10000)

这里,我们模拟一个比率为 10 的分布,有 10k 个数据点。为了看到这种分布,我们将绘制其 PMF 的结果。虽然我们可以手工完成,但是已经有一个非常好的库叫做empiricaldist,作者是 Allen B. Downey,他是著名书籍的作者,比如 ThinkPythonThinkStats 。我们将在我们的环境中安装并导入它的Pmf函数:

from empiricaldist import Pmf  # pip install empiricaldist

Pmf有一个名为from_seq的函数,它接受任意分布并计算 PMF:

poisson = np.random.poisson(lam=10, size=10000)pmf_poisson = Pmf.from_seq(poisson)
pmf_poisson

回想一下,PMF 显示了每个独特结果的概率,所以在上面的结果中,结果在probs下作为指数和概率给出。让我们使用matplotlib来绘制它:

正如所料,最高概率是平均值(速率参数,λ)。

现在,让我们假设我们忘记了泊松分布的 PMF 公式。如果我们正在做观察新生儿的实验,我们将如何发现看到 10 个新生儿的概率为 6?

首先,我们用给定的利率作为参数来模拟完美的泊松分布。此外,我们确保抽取大量样本以提高准确性:

我们正在对一个比率为 6、长度为 100 万的分布进行抽样。接下来,我们发现他们中有多少人生了 10 个孩子:

所以,我们在 41114 次试验中观察了 10 个婴儿(每个小时可以认为有一次试验)。然后,我们将这个数字除以样本总数:

>>> births_10 / 1e60.041114

如果你记得,使用 PMF 公式,结果是 0.0413,我们可以看到,我们的手动编码解决方案是一个非常接近的匹配。

结论

关于泊松分布还有很多要说的。我们讨论了基本用法及其在商业世界中的含义。泊松分布仍然有有趣的部分,例如它如何与二项式分布相关。为了全面理解,我建议阅读这些高质量的文章,它们也有助于我对该主题的理解:

如何使用 py caret——低代码 ML 的库

原文:https://towardsdatascience.com/how-to-use-pycaret-the-library-for-lazy-data-scientists-91343f960bd2?source=collection_archive---------3-----------------------

入门

用最少的代码训练、可视化、评估、解释和部署模型

Armando ArauzUnsplash 上拍摄的照片

当我们处理有监督的机器学习问题时,很容易看到随机森林或梯度推进模型的表现,如果我们对结果满意,就停止实验。如果只用一行代码就能比较许多不同的模型,会怎么样?如果您可以将数据科学过程中从功能工程到模型部署的每一步都减少到只有几行代码,那会怎么样?

这正是 PyCaret 发挥作用的地方。PyCaret 是一个高级的低代码 Python 库,只需几行代码就可以轻松比较、训练、评估、调优和部署机器学习模型。在其核心,PyCaret 基本上只是许多数据科学库的大型包装器,如 Scikit-learn、Yellowbrick、SHAP、Optuna 和 Spacy。是的,您可以使用这些库来完成相同的任务,但是如果您不想编写大量代码,PyCaret 可以为您节省大量时间。

在本文中,我将演示如何使用 PyCaret 快速轻松地构建一个机器学习项目,并为部署准备最终模型。

正在安装 PyCaret

PyCaret 是一个有很多依赖项的大型库。我建议使用 Conda 专门为 PyCaret 创建一个虚拟环境,这样安装不会影响任何现有的库。要在 Conda 中创建和激活虚拟环境,请运行以下命令:

conda create --name pycaret_env python=3.6
conda activate pycaret_env

要安装默认的较小版本的 PyCaret,并且只安装所需的依赖项,可以运行以下命令。

pip install pycaret

要安装 PyCaret 的完整版本,您应该改为运行以下命令。

pip install pycaret[full]

安装 PyCaret 后,停用虚拟环境,然后使用以下命令将其添加到 Jupyter。

conda deactivate
python -m ipykernel install --user --name pycaret_env --display-name "pycaret_env"

现在,在您的浏览器中启动 Jupyter 笔记本后,您应该能够看到将您的环境更改为您刚刚创建的环境的选项。

改变 Jupyter 中的 Conda 虚拟环境。

导入库

您可以在这个 GitHub 资源库中找到本文的完整代码。在下面的代码中,我简单地导入了 Numpy 和 Pandas 来处理这个演示的数据。

import numpy as np
import pandas as pd

读取数据

对于这个例子,我使用了 Kaggle 上的加州房价数据集。在下面的代码中,我将这个数据集读入一个数据帧,并显示该数据帧的前十行。

housing_data = pd.read_csv('./data/housing.csv')
housing_data.head(10)

住房数据集的前十行。

上面的输出让我们了解了数据的样子。数据主要包含数字特征,其中一个分类特征表示每栋房屋与海洋的距离。我们试图预测的目标列是 median_house_value 列。整个数据集总共包含 20,640 个观察值。

初始化实验

现在我们有了数据,我们可以初始化一个 PyCaret 实验,它将预处理数据并为我们将在这个数据集上训练的所有模型启用日志记录。

from pycaret.regression import *reg_experiment = setup(housing_data, 
                       target = 'median_house_value', 
                       session_id=123, 
                       log_experiment=True, 
                       experiment_name='ca_housing')

如下面的 GIF 所示,运行上面的代码预处理数据,然后生成一个带有实验选项的数据帧。

Pycaret 设置函数输出。

比较基线模型

我们可以一次比较不同的基线模型,用下面的代码所示的 compare_models 函数找到实现最佳 K 倍交叉验证性能的模型。出于演示的目的,我在下面的例子中排除了 XGBoost。

best_model = compare_models(exclude=['xgboost'], fold=5)

不同模型的比较结果。

该函数生成一个数据框,其中包含每个模型的性能统计数据,并突出显示性能最佳的模型的指标,在本例中是 CatBoost 回归器。

创建模型

我们也可以用 PyCaret 只用一行代码训练一个模型。create_model 函数只需要一个与您想要训练的模型类型相对应的字符串。您可以在这个函数的 PyCaret 文档页面上找到可接受字符串和相应回归模型的完整列表。

catboost = create_model('catboost')

c reate_model 函数生成上面的数据帧,其中包含已训练的 CatBoost 模型的交叉验证指标。

超参数调谐

现在我们有了一个训练好的模型,我们可以通过超参数调整进一步优化它。只需一行代码,我们就可以调整这个模型的超参数,如下所示。

tuned_catboost = tune_model(catboost, n_iter=50, optimize = 'MAE')

10 倍交叉验证的超参数调整结果。

最重要的结果,在本例中是平均指标,用黄色突出显示。

可视化模型的性能

我们可以使用 PyCaret 创建许多图表来可视化模型的性能。PyCaret 使用另一个名为 Yellowbrick 的高级库来构建这些可视化。

残差图

默认情况下, plot_model 函数将为回归模型生成残差图,如下所示。

plot_model(tuned_catboost)

调整后的 CatBoost 模型的残差图。

预计误差

我们还可以通过创建预测误差图,将预测值与实际目标值进行对比。

plot_model(tuned_catboost, plot = 'error')

调整后的 CatBoost 回归器的预测误差图。

上面的图特别有用,因为它为我们提供了 CatBoost 模型的 R 系数的可视化表示。在理想情况下(R = 1),预测值与实际目标值完全匹配,该图将只包含沿单位虚线的点。

特征重要性

我们还可以可视化模型的特征重要性,如下所示。

plot_model(tuned_catboost, plot = 'feature')

CatBoost 回归器的特征重要性图。

根据上面的图,我们可以看到中值收入特征是预测房价时最重要的特征。由于这一特征对应于房屋所在区域的中值收入,因此这一评估非常合理。建造在高收入地区的房子可能比低收入地区的房子更贵。

使用所有地块评估模型

我们还可以用 evaluate_model 函数创建多个图来评估一个模型。

evaluate_model(tuned_catboost)

使用 evaluate_model 函数创建的接口。

解释模型

解释模型函数是解释模型预测的有用工具。这个函数使用一个名为 SHAP 的可解释机器学习库,我在下面的文章中提到过。

只用一行代码,我们就可以为模型创建一个 SHAP 蜂群图

interpret_model(tuned_catboost)

通过调用解释模型函数生成的 SHAP 图。

根据上图,我们可以看到中值收入字段对预测的房价影响最大。

AutoML

PyCaret 还有一个运行自动机器学习(AutoML)的函数。我们可以指定想要优化的损失函数或度量,然后让库接管,如下所示。

automl_model = automl(optimize = 'MAE')

在这个例子中,AutoML 模型碰巧也是一个 CatBoost 回归器,我们可以通过打印出模型来确认这一点。

print(automl_model)

运行上面的 print 语句会产生以下输出:

<catboost.core.CatBoostRegressor at 0x7f9f05f4aad0>

生成预测

predict_model 函数允许我们通过使用来自实验的数据或新的未知数据来生成预测。

pred_holdouts = predict_model(automl_model)
pred_holdouts.head()

上面的 predict_model 函数为用于在交叉验证期间验证模型的维持数据集生成预测。该代码还为我们提供了一个数据框架,其中包含由 AutoML 模型生成的预测的性能统计数据。

AutoML 模型生成的预测。

在上面的输出中,标签列表示 AutoML 模型生成的预测。我们还可以对整个数据集进行预测,如下面的代码所示。

new_data = housing_data.copy()
new_data.drop(['median_house_value'], axis=1, inplace=True)
predictions = predict_model(automl_model, data=new_data)
predictions.head()

保存模型

PyCaret 还允许我们用 save_model 函数保存训练好的模型。该函数将模型的转换管道保存到 pickle 文件中。

save_model(automl_model, model_name='automl-model')

我们也可以用 load_model 函数加载保存的 AutoML 模型。

loaded_model = load_model('automl-model')
print(loaded_model)

打印加载的模型会产生以下输出:

Pipeline(memory=None,
         steps=[('dtypes',
                 DataTypes_Auto_infer(categorical_features=[],
                                      display_types=True, features_todrop=[],
                                      id_columns=[], ml_usecase='regression',
                                      numerical_features=[],
                                      target='median_house_value',
                                      time_features=[])),
                ('imputer',
                 Simple_Imputer(categorical_strategy='not_available',
                                fill_value_categorical=None,
                                fill_value_numerical=None,
                                numer...
                ('cluster_all', 'passthrough'),
                ('dummy', Dummify(target='median_house_value')),
                ('fix_perfect', Remove_100(target='median_house_value')),
                ('clean_names', Clean_Colum_Names()),
                ('feature_select', 'passthrough'), ('fix_multi', 'passthrough'),
                ('dfs', 'passthrough'), ('pca', 'passthrough'),
                ['trained_model',
                 <catboost.core.CatBoostRegressor object at 0x7fb750a0aad0>]],
         verbose=False)

从上面的输出中我们可以看到,PyCaret 不仅在管道的末端保存了训练好的模型,还在管道的开始保存了特征工程和数据预处理步骤。现在,我们在单个文件中有一个生产就绪的机器学习管道,我们不必担心将管道的各个部分放在一起。

模型部署

既然我们已经有了准备生产的模型管道,我们也可以使用 deploy_model 函数将模型部署到云平台,比如 AWS。在运行此功能之前,如果您计划将模型部署到 S3 存储桶,则必须运行以下命令来配置 AWS 命令行界面:

aws configure

运行上面的代码将触发一系列信息提示,比如您需要提供的 AWS Secret Access Key。一旦这个过程完成,您就可以使用 deploy_model 函数部署模型了。

deploy_model(automl_model, model_name = 'automl-model-aws', 
             platform='aws',
             authentication = {'bucket' : 'pycaret-ca-housing-model'})

在上面的代码中,我将 AutoML 模型部署到 AWS 中名为py caret-ca-housing-model的 S3 桶中。从这里,您可以编写一个 AWS Lambda 函数,从 S3 获取模型并在云中运行。PyCaret 还允许您使用 load_model 函数从 S3 加载模型。

MLflow UI

PyCaret 的另一个很好的特性是,它可以用一个名为 MLfLow 的机器学习生命周期工具来记录和跟踪你的机器学习实验。运行以下命令将从本地主机在您的浏览器中启动 MLflow 用户界面。

!mlflow ui

MLFlow 仪表板。

在上面的仪表板中,我们可以看到 MLflow 为您的 PyCaret 实验跟踪不同模型的运行。您可以查看性能指标以及实验中每次运行的运行时间。

使用 PyCaret 的利弊

如果您已经读到这里,那么您现在已经对如何使用 PyCaret 有了基本的了解。虽然 PyCaret 是一个很棒的工具,但是如果您计划将它用于您的数据科学项目,您应该了解它的优缺点。

赞成的意见

  • 低代码库。
  • 非常适合简单的标准任务和通用机器学习。
  • 为回归、分类、自然语言处理、聚类、异常检测和关联规则挖掘提供支持。
  • 使得为模型创建和保存复杂的转换管道变得容易。
  • 使可视化模型的性能变得容易。

骗局

  • 到目前为止,PyCaret 对于文本分类并不理想,因为 NLP 实用程序仅限于主题建模算法。
  • PyCaret 对于深度学习并不理想,并且不使用 Keras 或 PyTorch 模型。
  • 你不能用 PyCaret(至少在 2.2.0 版本下)执行更复杂的机器学习任务,比如图像分类和文本生成。
  • 通过使用 PyCaret,您为简单和高级代码牺牲了一定程度的控制。

摘要

在本文中,我演示了如何使用 PyCaret 来完成机器学习项目中的所有步骤,从数据预处理到模型部署。虽然 PyCaret 是一个有用的工具,但是如果您计划将它用于您的数据科学项目,您应该了解它的优缺点。PyCaret 非常适合使用表格数据的通用机器学习,但从 2.2.0 版本开始,它不是为更复杂的自然语言处理、深度学习和计算机视觉任务而设计的。但它仍然是一个节省时间的工具,谁知道呢,也许开发者将来会增加对更复杂任务的支持?

正如我之前提到的,你可以在 GitHub 上找到这篇文章的完整代码

加入我的邮件列表

你想在数据科学和机器学习方面变得更好吗?您想了解数据科学和机器学习社区的最新图书馆、开发和研究吗?

加入我的邮件列表,获取我的数据科学内容的更新。当你注册时,你还会得到我免费的解决机器学习问题的逐步指南

来源

  1. 米(meter 的缩写))Ali, PyCaret:一个用 Python 编写的开源低代码机器学习库,(2020),PyCaret.org。
  2. 南 M. Lundberg,S. Lee,解释模型预测的统一方法,(2017),神经信息处理系统进展 30 (NIPS 2017)。

如何使用 Python 和 Tableau 分析数码照片元数据

原文:https://towardsdatascience.com/how-to-use-python-and-tableau-to-analyze-digital-photo-metadata-e4d4a744b6a4?source=collection_archive---------26-----------------------

本文分享了一个 Python 程序,它使用 exifread 模块读取数字图像文件中的元数据,并使用 Tableau Public 分析细节

成熟的秃鹰。图片由作者提供。

介绍

假设你是一名专门拍摄猛禽的野生动物摄影师,比如老鹰、老鹰和猎鹰。你更喜欢捕捉飞行中的鸟的图像(BIF),尤其是当它们捕获猎物的时候。今天,你站在密西西比河明尼苏达州一侧的河岸上,在佩平湖的下游,紧接着穿过 T2 奇普瓦河口的海峡,在那里流入浩瀚的密西西比河。当秃鹰在水下捕鱼时,你的超长焦镜头对准了它们。

现在,假设您想要分析您在过去十年中拍摄的鸟类照片。不久以前,当被摄对象用胶片拍照时,关于每张照片的信息都是以模拟的形式被记录在胶片上,记录在摄影师的头脑中,也许还被摄影师记录在纸上。相比之下,今天,专用数码相机或智能手机相机记录丰富详细的数字化图像和关于它们的各种元数据。

本文向您展示了如何编写一个 Python 程序,从数码照片文件中提取元数据。然后,它会查找每张照片拍摄日期的日出和日落时间。最后,它将数据写入 CSV 文件,每张照片一条记录。本文还描述了一个 Tableau 公共工作簿,它使用 CSV 文件来组织、查看和分析其中包含的照片元数据。

数码照片元数据

当你点击数码相机或智能手机上的快门按钮时,该设备会将来自照片传感器的图像的详细数据写入数字媒体上的文件,如相机的 SD 卡或智能手机的内存。该文件包含在显示器上重建图像所需的数据和元数据,元数据是关于图像的数据。照片编辑软件,如 Adobe Lightroom 和 Photoshop、Microsoft Photos 或 Google Photos,使用图像数据和元数据。用 Python 和其他语言编写的自定义程序也可以读取这些类型的数据。

数码照片元数据以一种标准格式存储,这种格式称为可交换图像文件格式,通常称为 Exif。有关 Exif 结构中包含的字段列表,请参阅由 CIPA 相机和成像产品协会出版的 Exif 标准的第 42 页。

存储在每个照片文件中的元数据包括与图像相关的值,如日期和时间、相机的品牌和型号以及镜头的品牌和型号。它还包括曝光信息,包括快门速度、感光度(ISO)和光圈(F 档)。

大白鹭。图片由作者提供。

本文的案例

当我想象这篇文章时,我想象它将描述一个数据分析项目,它将帮助我确定一天中拍摄鸟类的最佳时间。但它变得更多了。它帮助我理解和反思我的鸟类摄影习惯、技巧和偏好。这可能会支持我拍摄更好的鸟类照片并经常拍摄的目标。

照片

为了获得 1,000 多张鸟类照片供该程序处理并与 Tableau Public 一起分析,我在 Adobe Lightroom 中搜索了超过 30,000 张照片的目录,以找到符合这些标准的图像文件:

  • 星级 2/5—每次拍照后,我会将相机 SD 卡上的照片导入 Lightroom。下一步是后处理,包括检查照片,删除那些模糊、构图不佳或其他不理想的照片,编辑其余的照片,并给每张照片打分。评级是主观的,基于我对照片的喜欢程度,从 1 星到 5 星,其中 1 是可接受的,5 是优秀的。对于这个项目,我选择了评分为 2 或更高的照片。
  • RAW 的图像类型——用我的 DSLR 或无反光镜相机,我以 RAW 模式拍摄所有照片,这从传感器捕捉了尽可能多的图像细节。另一种方法是将图像捕获为 JPEG 文件。JPEG 文件是可以接受的,但就其性质而言,相机已经处理并试图优化每张照片,并将其压缩为 JPEG 格式。
  • 鸟的关键词 —在一张鸟的照片之后,我的意图是给每张饲养员的照片加上关键词“鸟”。如果时间允许,我会添加其他关键词,如物种、性别和颜色。这些关键字将帮助我以后搜索和找到鸟类图片。

在这个项目中,我排除了那些我认为是在离家很远的地方拍摄的照片。因为我的相机中设置的日期和时间是当地时区(在我的情况下是美国中部时间),该时区的日期和时间值被写入每个图像文件。包含我所在时区以外的图片可能会扭曲数据分析的结果。

过滤要从 Lightroom 导出的鸟类照片图像文件。图片由作者提供。

本项目中使用的软件

我为这个项目使用了下面列出的软件。

  • Windows 10 操作系统——我在大部分专业和个人电脑工作中使用 Windows。
  • Adobe Lightroom —我的照片存储在 Adobe Lightroom 的云中(Creative Cloud 版本)。图像 JPEG (*。jpg)文件从 Lightroom 导出,由稍后描述的 Python 程序进行处理。你使用的任何照片编辑软件都可以正常工作。
  • Python 3.9.2 编程语言—Python 3 的任何最新版本都应该可以工作。
  • Visual Studio 社区 —我用过很多版本的微软 Visual Studio。社区版免费。
  • Tableau Public —我在 Tableau Public 工作簿的两个仪表板中创建了这个项目中显示的图表。Tableau Public 是流行且强大的 Tableau 商业智能和数据可视化工具的免费版本。公共版本在这个项目中运行良好。但是它的主要限制是只能从有限的文件类型中读取数据,并且只能将工作簿保存到 Tableau 公共服务器。这意味着世界上的任何人都可以查看您使用 Tableau Public 创建的可视化效果。
  • Windows 记事本 —我用记事本查看 Python 程序创建的 CSV 文件。任何文本或代码编辑器都可以。

关于软件和操作系统的说明:

Python 语言应该可以在任何现代操作系统上工作,包括 Mac OS、Linux 和 Windows。Lightroom 和 Tableau Public 版本适用于 Mac OS 和 Windows。虽然微软发布了一个版本的 Visual Studio for Mac OS,但它不支持 Python。但是几乎任何代码编辑器或集成开发环境(IDE)都可以工作。记事本是特定于 Windows 的,但每个操作系统都支持工具来读取文本文件,如程序创建的 CSV 文件。

沙丘鹤。图片由作者提供。

程序中使用的 Python 模块

以下是程序中使用的 Python 模块的列表,以及如何使用它们的描述:

  • 星体 —获取日期和时区的日出和日落。
  • csv—从每个图像文件的 Exif 数据结构中选择元数据写入 CSV 文件。
  • 日期时间 —从日期时间值中提取日期。
  • Exif Read—从保存为 JPEG 格式的图像中读取 Exif 数据(。JPG)文件。****
  • os —获取一个目录下的镜像文件的名称。
  • pytz—将日出和日落日期时间值从协调世界时(UTC)转换为美国中部时区。这允许相对于拍摄每张照片的日期和时间来确定日出和日落的日期时间值。

代码

该程序的代码分为两个模块。控制器模块运行程序,一个名为 c_photo_exif 的类完成这项工作。这些模块将在以下章节中介绍和显示。

控制器模块

用 C 语言编写的程序有一个 main()函数作为它们的入口点。在 Python 中,我喜欢把入口点称为控制器。这是因为它控制着程序的整体流程。photo_exif_controller.py 文件作为这个程序的入口点和控制器。

为了读取图像文件,控制器使用以下值调用 c_photo_exif 类的构造函数(init()):

  • 包含要读取的图像文件的目录的名称。
  • 程序将为每个图像文件写入记录元数据的 CSV 文件的名称。
  • 离照片拍摄地最近的城市。
  • 照片拍摄地的时区。

编写这个程序时假设输入目录中的所有照片都是在大致相同的位置拍摄的。稍后将描述克服这一限制的潜在增强。

c_photo_exif Python 类

文件 c_photo_exif.py 中的 c_photo_exif Python 类是程序的引擎。它执行以下任务:

  1. 创建一个 CSV 输出文件,并写入其列名。
  2. 遍历指定目录中的图像文件。
  3. 从每个文件的 Exif 结构中获取图像元数据。
  4. 获取每张照片拍摄当天的日出和日落日期时间值。
  5. 将数据写入 CSV 文件。

注意: 由于 c_photo_exif 类的内容大约有 150 行长,所以显示在下面的附录 a 中。

CSV 文件中的照片 Exif 数据。图片由作者提供。

潜在的计划改进和增强

潜在的改进

与大多数概念验证(POC)程序一样,这个程序只执行满足特定需求所需的基本任务。在本例中,它从一组图像文件中读取 Exif 数据,获取与每张照片拍摄日期相关的日出和日落日期时间值,并将数据写入 CSV 文件供以后使用。以下是可对程序进行的潜在改进,以使其为生产做好准备:

  • 添加错误处理,这样当出现严重错误(如磁盘故障)时,程序可以正常关闭或重试。
  • 将消息写入日志文件以捕获重要事件,如程序开始时间、结束时间、错误消息和处理的图像文件数量。

潜在的改进

虽然该程序执行其预期的功能,但它可以被增强以服务于额外的用途。以下是一些想法:

  • 将输出数据写入关系数据库表,而不是 CSV 文件。根据需要,将数据写入数据库而不是 CSV 文件可以提供一些优势,例如性能和消除创建重复记录的可能性。
  • 从图像文件中获取附加数据。在本例中,写入输出 CSV 文件的所有内容都是从操作系统(文件名)、每个图像文件中的 Exif 数据结构以及 Astral Python 模块中的日出和日落数据时间值中捕获的。其他有用的数据,如关键字、评级、标题和说明,可能存在于每个图像文件中。我打算学习如何获得这些数据,并在下一篇文章中介绍它们。
  • 将输出数据写入 Tableau 超文件。在这个项目中,Tabeau Pulic 工作簿从 CSV 文件中读取图像元数据,而 Tableau Creator 桌面工作簿可以直接从以 Tableau 专有的 hyperfile 格式编写的文件中获取数据。
  • 为上下文添加其他数据。例如,如果每个鸟类图像文件在标题或关键字字段中包含物种的名称,则可以从单独的数据存储库中获得物种的描述,并将其写入 CSV 文件。

Tableau 公共工作簿

我在这个项目的数据分析部分使用了 Tableau Public。Python 程序编写的 CSV 文件充当 Tableau 工作簿的数据源。使用 Tableau 创建工作表、视觉效果和仪表板的说明超出了本文的范围。但是这两个仪表盘被公布在 Tableau 公共网站上的一个名为鸟类摄影数据分析的工作簿中。请随意下载工作簿,修改它,并将其与您的数码照片的元数据集成在一起。

鸟类照片概览仪表板

这个仪表盘显示了我自 2012 年以来拍摄鸟类的相机的使用数据。它还按镜头长度、快门速度、光圈和 ISO 显示照片数据。

Tableau 公共照片图表。图片由作者提供。

按月份和小时显示的鸟类照片

这显示了相机在这些时间段拍摄的照片数量:

  • 一年中的月份
  • 一天中的某个时刻
  • 相对于日出的拍摄时间
  • 相对于日落的拍摄时间

Tableau 公共照片图表。图片由作者提供。

我学到了什么教训?

摄影和拍摄好照片是我生活中重要的组成部分。和大多数追求一样,我希望随着时间的推移提高自己的技能和成果。以下是我从这个项目中学到的一些经验,或者直接通过观察数据,或者间接地作为催化剂来反思我多年来的鸟类摄影经历。我想提高我的技术来增加我的守门员比例和图像质量。

  • 在相机中设置当地时间 —因为当我离家旅行时,我已经将相机中的日期和时间重置为当地时间,所以我不能总是可靠地确定特定照片是何时拍摄的。从现在起,每当我离开我的时区时,我打算将相机的时间设置为当地时间。幸运的是,有了智能手机,时间会自动改变。
  • 在 Lightroom 中或通过智能手机应用程序为每张照片添加位置信息——直到我进行了这项分析,我才意识到时间和位置数据可以如此紧密地联系在一起。从现在开始,我会在导入后立即将位置信息记录到 Lighroom 中的 keeper photos。我还会尝试使用智能手机上的尼康 SnapBridge 应用程序来自动捕捉每张照片的拍摄位置。
  • 为更多的守护者使用最高合理的快门速度 —摄影的一个经验法则是将快门速度设置为镜头焦距的倒数或更高。使用这个规则,700 毫米的焦距保证了 1/700 秒的快门速度。但是设置快门速度涉及到许多变量。例如,相机或镜头可能具有图像稳定功能,这有助于在较低的快门速度下捕捉清晰的图像。另一方面,在鸟类摄影中,拍摄对象通常很远且在移动,因此可能需要更快的快门速度来获得清晰的图像。为了获得更清晰的鸟类照片,我会尝试将快门速度提高到经验法则的倒数以上,无论是使用图像稳定、三脚架还是单脚架。

雌性红翅乌鸫。图片由作者提供。

下一步是什么?

也许,通过这篇文章,您已经想到了将摄影元数据用于个人或商业项目的方法。以下是我可能会探索的想法:

  • 使用 Exif 数据研究其他类型或主题的摄影模式,如昆虫、哺乳动物、风景和建筑。或者,我可能会按鸟类研究数据。
  • 了解如何以编程方式从照片文件中获取不是以 Exif 格式存储的额外数据。例如,也许我对 Lightroom 目录中的许多照片应用的星级和标题可以在应用程序导出的每个 JPEG 文件中找到。有了这些数据点,照片的特征就可以在不同的评级中进行比较和对比。
  • 使用存储在每个图像文件中的日期和时间、关键字和潜在位置(GPS) 来确定每年何时何地返回特定地点,以便有机会拍摄特定种类的鸟类。

结论

到目前为止,您可能对每个数码照片文件的 Exif 文件中存储的元数据有所了解。您还应该了解如何编写 Python 程序来获取元数据并在数据分析项目中使用它。像我一样,也许你可以使用图像元数据来了解你的摄影习惯和技术,并尝试在未来拍出更好的照片。

关于作者

Randy Runtsch 是一名数据分析师、软件开发人员、作家、摄影师、自行车手和冒险家。他和妻子住在美国明尼苏达州东南部。

关注 Randy 即将发表的关于公共数据集的文章,以推动数据分析解决方案、编程、数据分析、摄影、自行车旅行、啤酒等。你可以在 shootproof.com和 shutterstock.com看到他的一些照片。

附录 A — Python c_photo_exif 类

c_photo_exif 类在文章的正文中有描述。

**"""
Name:           c_photo_exif.py
Author:         Randy Runtsch
Date:           March 20, 2021
Description:    The c_photo_exif class opens all image files in the specified 
                folder, reads the Exif data from each file. It then gets the sunrise
                and sunset times of the day the photo was taken. It then writes a subset
                of the Exif data, and the sunrise and sunset times, as a row in a CSV file.
"""import csv
import exifread
import os
import datetime
from pytz import timezone
from astral.geocoder import lookup, database
from astral.sun import sunclass c_photo_exif:def __init__(self, input_photo_folder, output_csv_file_nm, city, time_zone):# Create the output CSV file with headers and process all of the 
        # photo files.# Set astral location as Minneapolis and time zone as US/Central.
        astral_db = database() 
        self._astral_city = lookup(city, astral_db)
        self._time_zone = time_zoneself._rows_processed = 0csv_writer = self.init_csv_file(output_csv_file_nm)self.process_photos(input_photo_folder, csv_writer)def process_photos(self, input_photo_folder, csv_writer):# Process all of the image files contained in the input folder.rows = 0for subdirs, dirs, files in os.walk(input_photo_folder):

            for photo_file_nm in files:# Process only files with a .jpg extension.if photo_file_nm[-4:] == '.jpg':self._rows_processed += 1photo_file_nm_full = input_photo_folder + '/' + photo_file_nm
                    self.process_photo(photo_file_nm, photo_file_nm_full, csv_writer)def process_photo(self, photo_file_nm, photo_file_nm_full, csv_writer):# Get a subset of EXIF values from the photo file. Call function write_csv_file_row()
        # to write the values as a row to a CSV file.photo_file = open(photo_file_nm_full, 'rb')tags = exifread.process_file(photo_file)camera_make     = tags['Image Make']
        camera_model    = tags['Image Model']
        photo_date_time = tags['EXIF DateTimeOriginal']
        focal_length    = tags['EXIF FocalLength']
        shutter_speed   = tags['EXIF ExposureTime']
        f_stop          = tags['EXIF FNumber']
        exposure_bias   = tags['EXIF ExposureBiasValue']
        white_balance   = tags['EXIF WhiteBalance']
        iso             = tags['EXIF ISOSpeedRatings']# Exif date-time values contain colons in the date part (for example, 2021:01:20). Replace
        # the first two colons with hyphens (-) so that they will be treated as date-time values
        # in other programs, such as Tableau. This will leave the colons in place in the time portion
        # of the value.photo_date_time = photo_date_time.values.replace(':', '-', 2)# Get sunrise and sunset date-time values.sunrise_date_time   = self.get_sun_date_time(photo_date_time, 'sunrise')
        sunset_date_time    = self.get_sun_date_time(photo_date_time, 'sunset')self.write_csv_file_row(csv_writer, photo_file_nm, photo_date_time, sunrise_date_time, sunset_date_time, \
            camera_make, camera_model, focal_length, shutter_speed, f_stop, exposure_bias, iso, white_balance)def init_csv_file(self, output_csv_file_nm):# Open the CSV output file for write (create a new file and overwrite
        # the existing file), write its header, and return its handle.headers = ['File Name', 'Photo Date Time', 'Sunrise Date Time', 'Sunset Date Time', 'Camera Make', 'Camera Model', \
            'Focal Length', 'Shutter Speed', 'F Stop', 'Exposure Bias', 'ISO', 'White Balance']csv_file = open(output_csv_file_nm, 'w', encoding='utf-8', newline='')csv_writer = csv.DictWriter(csv_file, headers)
        csv_writer.writeheader()return csv_writerdef write_csv_file_row(self, csv_writer, file_name, photo_date_time, sunrise_date_time, sunset_date_time, \
        camera_make, camera_model, focal_length, shutter_speed, f_stop, exposure_bias, iso, white_balance):# Assemble the record of Exif values by column and write it to the CSV file.row = {'File Name' : file_name, 'Photo Date Time' : photo_date_time, 'Sunrise Date Time' : sunrise_date_time, \
                  'Sunset Date Time' : sunset_date_time, 'Camera Make' : camera_make, 'Camera Model' : camera_model, \
                  'Focal Length' : focal_length, 'Shutter Speed' : shutter_speed, \
                  'F Stop' : f_stop, "Exposure Bias": exposure_bias, 'ISO' : iso, 'White Balance' : white_balance}csv_writer.writerow(row)def get_sun_date_time(self, date_time_in, date_time_type):# Get the sunrise or sunset date and time in UTC, convert it to the local
        # timezone, and return it as a string in this format: YYYY-MM-DD HH:MM:SS.date_in = datetime.datetime(int(date_time_in[0:4]), int(date_time_in[5:7]), int(date_time_in[8:10]))astral_sun = sun(self._astral_city.observer, date_in)
        astral_date_time = astral_sun[date_time_type]astral_date_time_local = astral_date_time.astimezone(timezone(self._time_zone))
        date_time_out = astral_date_time_local.strftime('%Y-%m-%d %X')return date_time_outdef print_exif_values(self, photo_file_nm):# Print most of the human-readable Exif values for the specified photo file.file = open(photo_file_nm, 'rb')# Return Exif tags
        exif_tags = exifread.process_file(file)for exif_tag in exif_tags.keys():
            if exif_tag not in ('JPEGThumbnail', 'TIFFThumbnail', 'Filename', 'EXIF MakerNote'):
                print("Key: %s, value %s" % (exif_tag, exif_tags[exif_tag]))def get_rows_processed(self):return self._rows_processed**

如何使用 Python 的新匹配语句

原文:https://towardsdatascience.com/how-to-use-pythons-new-match-statement-d81981f8adc4?source=collection_archive---------16-----------------------

快速浏览 Python 的新匹配语句以及如何使用它。

(src =https://pixabay.com/images/id-20237/

介绍

Python 3.10 已经发布了一段时间,并带来了一些新的额外特性。与许多版本一样,语言的许多变化并不太显著,也没有中断。要明确的是,这不是传统意义上的破坏,旧代码将被破坏,但这是说,未来使用该语法的代码不能使用旧版本的 Python。

然而,Python 的一个新变化是全新的,意义重大。这种变化就是匹配语句。这个语句肯定是 Python 早期版本中所缺少的,它确实可以帮助语言的控制流。今天,我想讨论一下这句话的用法,并更详细地介绍一下。

匹配语句是什么?

如果你是一个 C 或 C++程序员,很可能你使用过或者至少听说过使用 match 语句,只是它被重命名为 switch 语句。该语句用于控制代码执行的流程。该语句可以接受一个值,并将其与多个可能条件中的一个完美匹配。这也被称为模式匹配,这是 Rust 程序员可能熟悉的一个术语。该语句可以像条件语句一样使用,并且基本上遵循与以下语句非常相似的语法:

**from** **enum** **import** **Enum**
**class** **Command**(**Enum**):
    QUIT = 0
    RESET = 1

match command:
    **case** **Command**.QUIT:
        quit()
    **case** **Command**.RESET:
        reset()

我们可以匹配任何条件,并快速将控制流移入或移出块。虽然使用简单的条件语句当然可以做到这一点,但 match/case 方法要漂亮得多,甚至优于使用传统的条件语句。虽然这是一个简单的特性,但是对于 Python 程序员来说,这是一个非常受欢迎并且非常酷的特性。

重要注意事项

现在我们已经使用了 match 语句,让我们再多谈一点。您可能已经意识到,当我们将 match 语句与其他具有相似表达式类型的编程语言进行比较时,它们都是系统/低级、命令式编程语言。match 语句本身属于一个非常必要的计算领域。这就提出了一个非常有趣的问题,为什么它现在出现在所有语言的 Python 中?

我们应该考虑到很多 Python 程序员也可能写 C++或 C,这可能是来回切换的一个有效原因,在某些情况下可能会被忽略。但是我想提出的问题是,这是否意味着 Python 在未来会变得更加必要。当然,我们可以预期 Python 将保持相当高的声明性和高级别,但是推测 Python 在未来是否会更适用于较低级别的事物将会很有趣。当然,没有办法知道,但是我希望看到更多类似这样的迭代特性在未来实现,因为我认为它真的可以使语言更加通用。

一些人可能会担心的一个问题是命名。Python 3 中编写的许多遗留函数都使用 match 和 case 作为变量名,那么这两者的增加是否是对代码的重大改变呢?简单的回答是肯定的,你仍然可以使用 match 和 case 作为变量名。匹配和大小写已经成为所谓的软关键字。这意味着大多数时候,它们没有特殊的含义,但是当在某些应用程序中使用时,比如 a case 块,它们就成为 Python 解释器使用的关键字。

关于匹配和大小写需要注意的另一件奇怪的事情是它不能处理下划线。下划线是 Python 中通配符变量的另一个软关键字,但在这种情况下,我们可以通过 case/match 语句传递它,但它不会改变匹配的值。

最后一个问题也许是最重要的,这是一个范围问题。Python 中的代码块有自己的作用域是很常见的,那么如果我们在匹配块中使用一个变量,那么它是在什么作用域中声明的呢?Python 中的 Case 块没有自己的作用域。这意味着变量将被应用到最近的可用局部作用域。换句话说,我们可以在没有初始化的情况下在这些块中定义变量,并在函数周围使用它们,这可能是您所不希望的,因为在大多数其他情况下不会发生这种情况。

结论

match 语句无疑是 Python 编程语言中一个很酷的新特性。至于这是否暗示了这种方法可能会带来更多的特性,我真的很期待看到结果。该语句当然是一个受欢迎的补充,尽管它不一定提供那么多新功能。我们可以做的另一个假设是,一旦 Python 4 准备好做出突破性的改变,这可能会成为 Python 4 中的一个常规关键字。不管怎样,我认为这是一个有趣的附加功能,我将来会不时地使用它。感谢您的阅读,我希望您对 Python 的最新特性有所了解!

如何使用 Pytorch 作为通用优化器

原文:https://towardsdatascience.com/how-to-use-pytorch-as-a-general-optimizer-a91cbf72a7fb?source=collection_archive---------4-----------------------

图片作者。

Pytorch 真的很有趣,如果你正在寻找一个框架来开始学习神经网络,我强烈推荐它——在 Pytorch 这里可以看到我关于如何使用基本神经网络的简短教程。

然而,许多人没有意识到 Pytorch 可以用于一般的梯度优化。换句话说,您可以使用 Pytorch 找到任意复杂优化目标的最小值或最大值。但是,你为什么要这样做呢?我能想到的理由至少有三个(还有很多)。

  1. 您已经熟悉 Pytorch,不想再学习另一个优化框架
  2. 您希望对 Pytorch 模型的结果进行优化,即,您希望对 Pytorch 神经网络的预测进行优化(例如,第一阶段神经网络可能会预测客户参与特定高价值活动的倾向,优化器用于确定在给定一些约束条件(如营销预算)的情况下哪个活动是最佳的)。
  3. 您希望使用 Pytorch 中定义的高级优化器,比如 Adam。

实现通用优化器

嗯……你实际上不需要实现任何东西,如果你已经熟悉 Pytorch,你只需要简单地写一个 Pytorch 自定义模块,就像你写神经网络一样,Pytorch 会处理好所有其他的事情。让我们看一个成功的例子。

为了演示,我们将定义一个简单的函数——指数衰减函数。让我们定义数据——标量浮点值a, k, b是函数的未知参数,优化的目标是估计这些参数。

import numpy as np
import torch
import matplotlib.pyplot as plt
from torch import nn
from torch.functional import F
from copy import copyimport seaborn as snssns.set_style("whitegrid")n = 1000
noise = torch.Tensor(np.random.normal(0, 0.02, size=n))
x = torch.arange(n)
a, k, b = 0.7, .01, 0.2
y = a * np.exp(-k * x) + b + noiseplt.figure(figsize=(14, 7))
plt.scatter(x, y, alpha=0.4)

指数衰减函数——作者图片。

接下来,让我们定义模型和训练循环:

class Model(nn.Module):
    """Custom Pytorch model for gradient optimization.
    """
    def __init__(self):

        super().__init__()
        # initialize weights with random numbers
        weights = torch.distributions.Uniform(0, 0.1).sample((3,))
        # make weights torch parameters
        self.weights = nn.Parameter(weights)        

    def forward(self, X):
        """Implement function to be optimised. In this case, an exponential decay
        function (a + exp(-k * X) + b),
        """
        a, k, b = self.weights
        return a * torch.exp(-k * X) + b

def training_loop(model, optimizer, n=1000):
    "Training loop for torch model."
    losses = []
    for i in range(n):
        preds = model(x)
        loss = F.mse_loss(preds, y).sqrt()
        loss.backward()
        optimizer.step()
        optimizer.zero_grad()
        losses.append(loss)  
    return losses

如果你熟悉 Pytorch,这里没有什么特别的东西。我们在这里要做的关键事情是定义我们自己的权重,并手动将它们注册为 Pytorch 参数,这就是这些行要做的事情:

weights = torch.distributions.Uniform(0, 0.1).sample((3,))
# make weights torch parameters
self.weights = nn.Parameter(weights)

下面几行确定了要优化的功能。你可以用你想要最小化的函数的定义来代替它们。

a, k, b = self.weights
return a * torch.exp(-k * X) + b

通过调用nn.Parameter,我们定义的权重将以与标准 Pytorch 参数相同的方式运行——即,它们可以计算梯度并根据损失函数进行更新。训练循环简单地在n历元上迭代,每次估计均方误差并更新梯度。

运行模型的时间到了,我们将使用 Adam 进行优化。

# instantiate model
m = Model()
# Instantiate optimizer
opt = torch.optim.Adam(m.parameters(), lr=0.001)losses = training_loop(m, opt)
plt.figure(figsize=(14, 7))
plt.plot(losses)
print(m.weights)

超过 1000 个时代的损失—作者图片..

上面的图显示了超过 1000 个时期的损失函数——你可以看到,在大约 600 年后,它没有显示出进一步改善的迹象。a、k、b 的估计权重为 0.697、0.0099、0.1996,非常接近定义函数的参数,我们可以使用训练好的模型来估计函数:

preds = m(x)
plt.figure(figsize=(14, 7))
plt.scatter(x, preds.detach().numpy())
plt.scatter(x, y, alpha=.3)

蓝线是估计的指数衰减曲线——图片由作者提供。

您可以看到,通过优化参数,我们现在可以拟合数据的指数衰减。虽然你可以用来自scipycurve_fit做同样的事情,但是我认为 Pytorch 更大的灵活性来适应更复杂的功能是值得花时间去学习的。

总结

虽然大多数人会使用 Pytorch 来构建神经网络,但该框架的灵活性使它非常通用。在这篇文章中,我们拟合了一条由指数衰减函数定义的简单曲线,但是没有理由为什么相同的构建块不能扩展到任意复杂的优化函数。

希望这是有帮助的,如果你有任何想法,评论或问题,请告诉我。

感谢阅读!

如何使用 Q-Q 图检查数据的分布

原文:https://towardsdatascience.com/how-to-use-q-q-plot-for-checking-the-distribution-of-our-data-c798d0577369?source=collection_archive---------28-----------------------

作者图片

数据科学家通常需要检查他们的数据集的统计数据,特别是针对已知的分布或与其他数据集进行比较。我们可以为此目标运行几个假设测试,但我通常更喜欢使用简单的图形表示。我说的是 Q-Q 情节。

什么是 Q-Q 情节?

Q-Q 图通常被称为分位数图。这是一个 2D 图,我们在其中将分布的理论分位数与数据集的样本分位数进行比较。如果数据集是根据该分布生成的,我们预计该图表将接近 45 度线,因为样本分位数将与理论分位数相似。如果样本是从不同的分布中生成的,我们就不会得到 45 线。

通过这种方式,我们可以很容易地想象数据集是否类似于理论分布。我们甚至可以使用 Q-Q 图来比较两个数据集,只要它们具有相同的点数。

Python 中的一个例子

现在让我们看看 Python 中的 Q-Q plot 是如何工作的。你可以在我的 GitHub repo 上找到完整的代码。

首先,让我们导入一些库,并设置随机数种子,以使我们的模拟可重复。

from statsmodels.graphics.gofplots import qqplot 
from matplotlib import pyplot as plt plt.rcParams['figure.figsize'] = [10, 7] 
plt.rc('font', size=14) 
from scipy.stats import norm, uniform 
import numpy as np 
np.random.seed(0)

现在,让我们模拟 0 和 1 之间的 1000 个均匀分布的点,并将该数据集与具有相同均值和方差的正态分布进行比较。我们期望得到一个与 45 度线非常不同的 Q-Q 图,因为这两个分布非常不同。

x = np.random.uniform(1,2,1000)

为了根据最佳拟合正态分布绘制该数据集的 Q-Q 图,我们可以编写以下代码:

qqplot(x,norm,fit=True,line="45") 
plt.show()

作者图片

fit=True 参数试图根据最大似然来拟合数据集的正态分布。正如我们所见,样本分位数与理论分位数有很大不同,因为蓝点离红线非常远,红线是 45 度线。

现在让我们尝试使用正态分布的数据集。

x = np.random.normal(1,2,1000) 
qqplot(x,norm,fit=True,line="45") 
plt.show()

作者图片

现在结果大不一样了。样本分位数与理论分位数非常相似(即蓝色点靠近红线)。有一些异常值会在此图表的下限和上限产生一些噪音,但这不是一个大问题,因为样本分布的最大部分与理论值非常吻合。

当然,改变 qqplot 函数的第二个参数,我们可以将我们的样本数据集与另一个分布进行比较。例如,我们可以将正态分布的数据集与均匀分布的数据集进行比较。

qqplot(x,uniform,fit=True,line="45") 
plt.show()

作者图片

正如预期的那样,结果不太好,因为生成数据集的分布与最佳拟合的均匀分布非常不同。

两个数据集的 Q-Q 图

Q-Q 图甚至可以用于 2 个数据集,只要它们具有相同的点数。为了获得两个数据集的样本分位数,我们只需对它们进行升序排序并绘制它们。

让我们从两个正态分布生成两个正态分布数据集,具有相同的均值和相同的方差。

x1 = np.random.normal(1,2,1000) 
x2 = np.random.normal(1,2,1000)

现在我们可以对数据进行排序:

x1.sort() 
x2.sort()

然后我们可以画出来:

plt.scatter(x1,x2) 
plt.plot([min(x1),max(x1)],[min(x1),max(x1)],color="red") 
plt.xlabel("1st dataset's quantiles") 
plt.ylabel("2nd dataset's quantiles") 
plt.show()

作者图片

如我们所见,尾部仍有一些噪声,但分布的中心部分匹配得相当好。

结论

在本文中,我展示了如何使用 Q-Q 图来检查样本分布和理论分布之间或两个样本之间的相似性。尽管可以执行一些假设检验来实现这一目标(例如 Kolmogorov-Smirnov 检验),但我更喜欢使用数据可视化,以便对我们的数据集中的现象进行可视化表示。这样,我们的解释不会受到任何假设检验的影响,甚至对非技术人员来说也更加清晰。

原载于 2021 年 6 月 21 日【https://www.yourdatateacher.com】

如何通过 python 脚本使用 QGIS 空间算法

原文:https://towardsdatascience.com/how-to-use-qgis-spatial-algorithms-with-python-scripts-4bf980e39898?source=collection_archive---------7-----------------------

显示土地价格的日本东京地图。作者照片

QGIS 是您学习 GIS 和空间分析时最先接触到的工具之一。使用这个开源软件包,您可以处理空间数据及其处理的几乎所有方面。尽管它有大量的 GUI 特性可以使用,但有时有一种处理脚本的方法是很重要的。尤其是对于构建工作流的数据科学家和数据工程师来说,他们非常需要可扩展的自动化脚本。QGIS 为此提供了一个名为 PyQGIS 的 Python API。您可以通过 python 脚本自动执行大多数与 QGIS 相关的操作和空间算法。让我们深入了解这个 Python API,并了解如何在 Python 上使用 QGIS 空间算法。

如果你想了解更多关于位置(地理空间)数据如何变得越来越重要,以及它是数据分析的前进方向,请查看我关于这个主题的文章。

https://www.samashti.space/articles/why-geospatial-data-is-the-way-forward-in-data-analytics https://www.samashti.space/articles/why-you-need-to-use-geopackage-files-instead-of-shapefile-or-geojson

作为其 python API 的一部分,QGIS 在其软件上提供了一个 python 控制台。您可以使用它来访问几乎所有内容,从 QGIS 菜单和图层到在数据图层上运行一些算法。控制台很好地处理了一些小规模的功能执行。但是,如果目标是处理复杂的工作流和更大的数据集,这个控制台就失去了光泽。它具有基本的功能,但缺乏复杂工作流程所需的复杂性。

不能从默认 python 环境中导入 QGIS 库。QGIS 安装了 python 版本来处理运行软件所需的所有模块。因此,如果您需要从 python 控制台/jupyter 笔记本中使用 QGIS 库,您需要确保您的 python 可以找到 QGIS 库路径。或者,您可以在 python 环境中安装 QGIS 库。让我们更详细地看看这些选项。

使用 Conda 安装 QGIS 库

如果您使用 Anaconda 来管理 python 库,并从事数据科学项目,那么您将主要了解 conda 。类似于 pip ,conda 是一个 Python 和其他一些语言的包管理系统。使用 conda,您可以像在 Python 上安装任何其他库一样安装 QGIS 包。你可以直接在你默认的 python 环境中安装这个包。但是由于 QGIS 通常对依赖模块有其特定的要求。因此它可能会升级或降级关键包,这可能会为您的其他项目创建依赖模块版本冲突。

理想情况下,如果您将 Python 用于不同的项目,请为每个项目设置一个环境,或者至少为数据科学工作流设置一个环境。通过将这些从全局 python 环境中分离出来,您将使您的系统避免与包依赖相关的错误。因此,安装 QGIS 库的最佳选择是在虚拟环境中进行。它有助于将 QGIS 包与全球 Python 环境隔离开来。

要在活动 Python 虚拟环境中从 conda 安装 QGIS,请在活动 Python 虚拟环境中的终端上运行以下命令。该命令安装必要的 QGIS 库。

conda install -c conda-forge qgis

从虚拟 Python 环境映射 QGIS 桌面软件库。

上述方法可能会安装几个核心 QGIS 库,用于 python 脚本。但这仍无法让您访问桌面软件包中使用的所有 QGIS 空间算法。例如,如果您想要使用 QGIS 的处理工具箱中提供的 GRASS 或 SAGA 处理算法,仅安装 QGIS 核心库是不可能的。如果您经常使用桌面软件,您可能会发现安装工作量很大,而且占用大量存储空间。每次创建项目环境时,安装这么大的包会占用很多存储空间。

相反,您可以使用更简单的解决方案。通过从默认虚拟 Python 环境映射系统环境路径,可以使用 QGIS Desktop 及其库的现有安装(甚至是使用 QGIS 插件安装的 GRASS、SAGA 和其他算法)。您可以将一个现有的 QGIS 安装用于多个 Python 环境,而不存在依赖包的问题,同时不仅仅使用 QGIS 的核心库。

在这种情况下,我将在 Mac OS 上演示这个过程。但是对于 Linux 和 windows,您可以遵循类似的步骤,只需稍加修改。

步骤 1:从 QGIS Python 控制台获取和导出系统路径和操作系统环境变量

打开 QGIS 桌面 app ,打开 Python 控制台。然后首先运行下面几行,将系统路径导出到 CSV 文件。

import sys
import pandas as pd
paths = sys.path
df = pd.DataFrame({'paths':paths})
df.to_csv('./qgis_sys_paths.csv', index=False)

一旦导出了系统路径,就需要导出 QGIS 中的环境变量。

import os
import json
env = dict(os.environ)
rem = ['SECURITYSESSIONID', 'LaunchInstanceID', 'TMPDIR']
_ = [env.pop(r, None) for r in rem]with open('./qgis_env.json', 'w') as f:
    json.dump(env, f, ensure_ascii=False, indent=4)

理想情况下,您使用的 python 版本应该与 QGIS 安装中使用的版本相同或更早。要查找随 QGIS 一起安装的 python 版本及其路径,请运行以下代码,并在 Mac OS 的路径/Applications/Qgis.app/Contents/MacOS/bin/中查找相应的 Python 可执行文件。

from platform import python_version
print(python_version())

步骤 2:在使用算法之前,用 Python 脚本初始化 QGIS 库

在 python 脚本中使用 QGIS 库及其空间算法之前,我们需要设置刚刚导出的环境变量和路径。此外,我们需要初始化 QGIS 的处理模块。

首先,我们导入一些必要的 python 库来处理环境的设置。

# necessary imports
import os
import sys
import json
import pandas as pd

导入这些库后,我们需要设置环境变量和系统路径。

# set up system paths
qspath = './qgis_sys_paths.csv' 
# provide the path where you saved this file.
paths = pd.read_csv(qspath).paths.tolist()
sys.path += paths# set up environment variables
qepath = './qgis_env.json'
js = json.loads(open(qepath, 'r').read())
for k, v in js.items():
    os.environ[k] = v# In special cases, we might also need to map the PROJ_LIB to handle the projections
# for mac OS
os.environ['PROJ_LIB'] = '/Applications/Qgis.app/Contents/Resources/proj'

然后,我们实际上可以从 python 导入 QGIS 库。

# qgis library imports
import PyQt5.QtCore
import gdal
import qgis.PyQt.QtCore
from qgis.core import (QgsApplication,
                       QgsProcessingFeedback,
                       QgsProcessingRegistry)
from qgis.analysis import QgsNativeAlgorithms

在下一步中,我们通过将 QGIS 的本地算法添加到处理注册表来初始化处理模块及其算法。

feedback = QgsProcessingFeedback()# initializing processing module
QgsApplication.setPrefixPath(js['HOME'], True)
qgs = QgsApplication([], False)
qgs.initQgis() # use qgs.exitQgis() to exit the processing module at the end of the script.# initialize processing algorithms
from processing.core.Processing import Processing
Processing.initialize()
import processingQgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms())

通过这一步,您可以从 python 访问所有 QGIS 库及其空间算法。您可以通过运行以下代码来检查您有权访问的所有算法。

algs = dict()
for alg in QgsApplication.processingRegistry().algorithms():
    algs[alg.displayName()] = alg.id()
print(algs)

目前,这些步骤解决了从 QGIS native algorithms & GRASS 等提供商处导入算法的问题。我仍在致力于启用佐贺和其他插件,如 Orfeo 工具箱等。,用于 Python。继续查看这个博客的更新,或者如果你知道如何更新,请告诉我。

运行算法

你可以从图书馆找到很多算法。您可以运行算法来帮助查看每个算法的描述。提供给算法的参数也显示在帮助输出中。要查看帮助,只需通过提供算法 id 来运行以下代码:

processing.algorithmHelp("native:centroids")# which would print this on the console.
"""
Centroids (native:centroids)This algorithm creates a new point layer, with points representing the centroid of the geometries in an input layer.The attributes associated to each point in the output layer are the same ones associated to the original features.----------------
Input parameters
----------------INPUT: Input layer Parameter type:	QgsProcessingParameterFeatureSource Accepted data types:
		- str: layer ID
		- str: layer name
		- str: layer source
		- QgsProcessingFeatureSourceDefinition
		- QgsProperty
		- QgsVectorLayerALL_PARTS: Create centroid for each part Parameter type:	QgsProcessingParameterBoolean Accepted data types:
		- bool
		- int
		- str
		- QgsPropertyOUTPUT: Centroids Parameter type:	QgsProcessingParameterFeatureSink Accepted data types:
		- str: destination vector file, e.g. 'd:/test.shp'
		- str: 'memory:' to store result in temporary memory layer
		- str: using vector provider ID prefix and destination URI, e.g. 'postgres:…' to store result in PostGIS table
		- QgsProcessingOutputLayerDefinition
		- QgsProperty----------------
Outputs
----------------OUTPUT:  <QgsProcessingOutputVectorLayer>
	Centroids
"""

因此,我们知道,对于在任何矢量层上运行质心算法的情况,我们知道我们必须提供 3 个参数及其可接受的数据类型。让我们对包含几个多边形的矢量文件运行一个简单的质心算法。

包含洛杉矶市网格多边形的矢量文件示例。作者照片。

对于算法,我们需要创建一个参数字典,一旦完成,我们运行质心算法。

parameters = {
    'ALL_PARTS': 1,
    'INPUT': './grid-polygons.geojson',
    'OUTPUT': './grid-centroids.geojson'
}
processing.run("native:centroids", parameters)# this would print out the output, once the algorithm is run.
"""
{'OUTPUT': './grid-centroids.geojson'}
"""

我们可以在 QGIS 桌面应用程序上看到网格质心的最终输出。

为洛杉矶市上空的每个网格多边形创建一个质心。作者照片。

需要注意的事项

  • 理想的做法是让虚拟环境的 Python 版本与 QGIS 安装的版本或更早版本保持一致。否则,这可能会给为早期版本的 Python 构建的一些模块带来问题。
  • 不要忘记通过运行qgs.exitQgis()退出您初始化的 QGIS 模块,其中 qgs 是您用来初始化模块的变量。
  • 对于 windows 用户,由于有一个 OSgeo4W shell,整个过程的处理方式略有不同,这里不做介绍。
  • 对于使用 M1 macbook 的用户,QGIS 使用 Rosetta 安装在英特尔架构中。而全球安装的 python 是建立在 arm64 架构上的。即使你使用 Anaconda Python 和 intel 架构,仍然有库(esp。数据科学&空间数据科学)。匹配模块安装的架构非常重要,这样您就可以在 python 中使用 QGIS 和其他库。
  • 如果您发现您的全局 python 安装与 QGIS 上的不匹配,esp。在 M1 macbook 中,您可以将 QGIS python 本身用于数据科学工作流。因为它是为空间数据科学需求而构建的,所以没有太多东西可以添加到项目中。您可以按照上面的步骤 1 获得这个 python 路径。
    macOS: /Applications/Qgis.app/Contents/MacOS/bin/python[version] Linux: /usr/share/qgis/python
  • 如上所述,您可以使用 QGIS Python 安装 spyder & jupyter 笔记本,使用 pip 在日常工作流程中使用。

我希望这有助于在日常 python 工作流中设置和使用 QGIS 库。当我找到更多的信息时,我会继续更新这部分,我很高兴收到任何进一步改进的建议。

如果你喜欢这篇文章,请订阅我的博客,并获得关于未来博客文章的通知。如有任何疑问或讨论,您可以在 LinkedInTwitter 上找到我。看看我以前的博客,关于如何免费对地址进行地理编码。

https://www.samashti.space/articles/how-to-geocode-addresses-for-free https://www.samashti.space/articles/how-alternative-data-helping-companies-invest-big

如何利用强化学习推荐内容

原文:https://towardsdatascience.com/how-to-use-reinforcement-learning-to-recommend-content-6d7f9171b956?source=collection_archive---------9-----------------------

谷歌的研究人员开发了一个新的 RL 框架。

强化学习理论上是最有效的深度学习方法之一。然而,实际上它并不处理复杂的问题。谷歌开发的 RL 框架 RecSim ,允许优化复杂的推荐系统。

图 1:强化学习框架。图片作者。

谷歌和 UT 奥斯汀的研究人员创建了一个更强大的 RL 框架,允许动态用户功能,并处理一些 RL 的技术问题。虽然这种方法计算量很大,但它提供了一个允许优化或推荐引擎的离线开发环境。

让我们深入了解一下这种方法是如何工作的…

技术 TLDR

RecSim 是一个利用强化学习(RL)的模拟环境构建器。该方法由“模拟器”模块控制,该模块负责对用户/文档进行采样,并迭代地训练推荐代理。该方法支持与用户的顺序交互,并允许工程师对环境进行大量定制。

这篇论文和其他一些有用的资源在评论中有链接。

好的,很多了。它实际上是如何工作的?

让我们慢一点,真正理解这个方法是如何工作的。

强化学习的背景

强化学习(RL)是一个框架,它涉及通过重复模拟来训练代理人做出决策。简而言之,代理做出决定,从模拟器获得反馈,调整其决定,然后再次尝试。重复这个过程,直到损失函数被优化。

图 2:雅达利突围:2013 年第一款 RL 游戏。图片作者——src

现代 RL 算法首次应用于雅达利游戏《突围》(图 2)。代理人控制底部的桨,并通过用球打破障碍来最大化得分。仅仅通过大量的尝试,RL 就可以成为一个近乎完美的玩家。从那以后,由于 RL 能够掌握定义良好的任务,如游戏和 NLP,因此受到了很多关注。

但是,与任何机器学习算法一样,它也有其局限性:

  • RL 不好概括。如果引入了新的功能或决策,it 部门通常很难适应。
  • RL 在组合决策空间上不能很好地扩展。因此,如果我们有很多可能的决定,比如在网飞的主屏幕上推荐很多电影,RL 会努力处理大量可能的配置。
  • RL 不处理低信噪比数据。 RL 是一个非常强大的模型,可以从数据中学习错综复杂的规则和关系——如果有噪声特征,RL 将拟合噪声。
  • RL 不处理长时间范围。与上面的要点类似,如果我们想要优化一个长期决策,有很多机会去适应噪声,所以如果给 RL 一个复杂的优化任务,它可能会过度适应。

所以,RL 在明确定义的问题空间中确实很强大,但是我们如何让它推广到更复杂的问题呢?

RecSim 框架

由谷歌和 UT 奥斯汀的研究人员开发的 RecSim 可能会解决我们在推荐引擎方面的问题。在这里,推荐包括向用户提供内容——想想 Spotify、网飞、YouTube 等。

图 3:简化的 RecSim 框架。图片作者——src

如图 3 所示,RecSim 中有两种类型的组件:模型(蓝色)和数据(黑色)。从第一个代理-环境周期开始,我们…

  1. 创建用户和文档样本(内容)。这些样本来自工程师指定的分布。
  2. 获得代理的推荐。推荐代理从前面的步骤中获取用户和文档,并且产生一个 策略 —一个例子是向给定用户显示一组电影。
  3. 模拟用户的决策。用户选择模型接受来自代理的推荐,并基于先前的例子,将估计用户的行为——假设 45%的用户开始看电影。
  4. 向代理和用户传递反馈。在确定了用户的行为之后,我们将这些信息传递给代理,这样它就可以改进它的预测。我们还将信息传递给用户数据,这样我们就可以更新长期的用户偏好,比如最喜欢的流派。
  5. 重复步骤 1-4,直到停止标准。常见的停止标准是固定的迭代次数或最低精度。

注意,推荐代理用户选择模型都可以是复杂的神经网络。对于文中的例子,推荐代理是一个深度神经网络,用户选择模型是一个多项式逻辑。

个案研究

RecSim 在各种使用案例中都取得了成功,但本文中引用了三个核心示例。

第一个是使用 RecSim 为用户发现潜在的(隐藏的)状态,并优化长期点击率(CTR)。潜在状态的一个例子是电影类型偏好。

这是一个典型的探索与利用的权衡。我们需要获得一些关于用户的数据来提供建议,但我们也希望尽快做出明智的决定来帮助我们的用户。对于有强烈内容偏好的用户,RecSim 能够显示出比贪婪算法提高 51%的点击率。

图 4:单一文档与候选文档推荐。图片作者。

研究人员解决的第二个问题是处理候选推荐,即组合决策空间(图 4)。

虽然没有给出准确性分数,但通过使用一些基本假设,作者能够证明 RecSim 框架的有效性。他们还注意到,“最优”算法的计算量非常大,并且大部分增益可以通过使用时间差异学习来获得,而不是完全成熟的 RL 算法。

因此,虽然我们没有解决组合决策空间的问题,但 RecSim 提供了一些比普通 RL 计算效率更高的解决方案。

最后,在第三个案例研究中,研究人员试图解决长时间跨度的问题。为了解决这个问题,作者反复向一组用户给出相同的建议,并观察他们偏好的变化。通过隔离单个建议的影响,该模型甚至能够在低信噪比的环境中估计功能的真实影响。

摘要

现在你知道了!

总之,RecSim 创建了一个模拟框架来优化推荐代理。它允许组合决策空间和长时间的视野。

如果您从事为用户生成推荐的业务,并且有足够的数据和计算资源,RecSim 可能是 RL 最健壮的推荐框架。

实施说明

  • RecSim 框架被封装在 OpenAI gym 中,以利用当前的 RL 库。
  • 该方法是有效的,但仍可从未来的开发中受益。
  • RecSim 附带了几个默认的学习环境,但是因为这些环境可能是特定于领域的,所以鼓励开发人员构建自己的环境。
  • RecSim 允许可配置的用户状态,比如主题关联性。
  • 虽然这不是 RecSim 的直接贡献,但该库支持动态用户特性,这是 RL 的一个相对较新的特性

感谢阅读!我会再写 38 篇文章,把学术研究带到 DS 行业。查看我的评论,链接到这篇文章的主要来源以及一些有用的资源。

如何使用 Roboflow 和 Streamlit 可视化对象检测输出

原文:https://towardsdatascience.com/how-to-use-roboflow-and-streamlit-to-visualize-object-detection-output-672ba11b2f7c?source=collection_archive---------24-----------------------

构建用于血细胞计数检测的应用程序

正在运行的应用程序。(图片由 RoboflowStreamlit 提供;授权使用。)

大多数技术都是为了让你的生活或工作更轻松。如果您的工作涉及将计算机视觉构建到您的应用中,使用 Roboflow 平台可以满足您的一切需求。

Streamlit 是一个开源平台,使您能够将 Python 脚本转换为应用程序,并立即部署它们。Streamlit 和 Roboflow 可以携手合作,让您处理计算机视觉问题并可视化您的输出,以便您可以更快地做出更好的决定。

在本帖中,我们将带您了解如何使用 Roboflow 并简化它,向您展示如何:

  1. 在 Roboflow 中拟合对象检测模型
  2. 使用 API 访问模型及其预测
  3. 创建和部署 Streamlit 应用程序

具体来说,我们将使用一个通用的血细胞计数和检测数据集。如果你想直接玩它,这里有一个互动应用这是代码

红细胞、白细胞和血小板。(图片由 RoboflowStreamlit 拍摄;授权使用。)

我们将构建一个检测血小板、白细胞和红细胞的对象检测模型。然后,我们共同开发的应用程序将允许您使用您的对象检测模型进行预测,以给定的置信度可视化这些预测,并根据您首选的置信度编辑这些预测,并提供即时视觉反馈。

如何在 Roboflow 中拟合对象检测模型

您以前是否拟合过对象检测模型?

即使你没有,Roboflow 也可以帮助你完成计算机视觉的所有方面,从上传、注释和组织你的图像到训练和部署计算机视觉模型。

我们认为,你不需要成为一名数据科学家,或者需要丰富的编码背景才能使用计算机视觉。你现在已经拥有了你需要的一切。

计算机视觉工作流程。(图片由 RoboflowStreamlit 提供;授权使用。)

如果你还没有一个 Roboflow 账户,你需要前往 Roboflow 并创建一个。如果你想从公共数据集开始训练你的模型,Roboflow 有一个很棒的教程,描述了如何更快地改进你的模型。(或者,可以上传自己的数据集!)

一旦你有了一个账户,就去我们的计算机视觉数据集页面。我们已经公开了 30 多个不同类型的数据集,并且还在继续增加。

我们今天要介绍的是血细胞计数和检测数据集。

在您决定使用哪个数据集之后,就可以开始使用它了。这将创建您现在可以使用的数据集的副本。

派生公共数据集。(图片由 RoboflowStreamlit 拍摄;授权使用。)

此时,可以直接拟合一个模型。但是,我们建议您预处理和增强您的图像。

  • 图像预处理。在将图像输入模型之前,对所有图像执行确定性步骤。例如,你可以调整你的图像的大小,使它们都一样大,或者将你的图像转换成灰度
  • 图像增强。通过扭曲您的输入图像来创建更多的训练示例,以便您的模型不会过度适应特定的训练示例。例如,您可以翻转旋转模糊,或者为您的图像添加噪声。目标是在您部署模型时,让您的模型更好地概括“真实世界”。

对于我正在使用的血细胞计数数据集,我选择了以下预处理和增强选项:

图像预处理图像增强技术。(图片由 RoboflowStreamlit 拍摄;授权使用。)

当决定是否使用特定的增强选项时,我问自己一个问题“对于我的模型来说,增强图像是一个合理的图像吗?”在这种情况下,我给我的图像添加了 90 度、180 度和 270 度的旋转,因为细胞幻灯片可以合理地旋转 90 度,并且仍然有意义。

它对所有应用程序都没有意义。例如,我可能不包括自动驾驶汽车的那种旋转,因为停车标志应该用伸入地面的杆子来看。将图像旋转 180 度会使停车标志颠倒,而地面应该是天空——这对我的模型来说可能不是一件非常有用的事情。

培训、验证、测试拆分 (图片由 RoboflowStreamlit 拍摄;授权使用。)

我对数据进行了拆分,70%的数据在训练集中,20%在验证集中,10%在测试集中。正如你可能知道的,将你的数据分成个训练、验证和测试集真的可以帮助避免过度拟合。

我决定创建三个增强版。这意味着,对于每个训练图像,我们将创建该图像的三个副本,每个副本都应用了随机增强技术。这将为我提供总共 874 张生成的图像:

  • 765 个增强的训练图像(765 = 255 * 3)
  • 加上 73 张验证图像
  • 加上 36 张测试图片。

一旦你完成了你的预处理和增强,点击右上角的“生成”。有用的提示:确保给你的数据集起一个令人难忘的名字!

现在您已经准备好构建一个模型了

要建立一个模型,就像点击“使用 Roboflow Train”一样简单

两次点击来训练一个计算机视觉模型。(图片由 RoboflowStreamlit 提供;授权使用。)

一般来说,你需要一个 Roboflow Train 信用来做到这一点。联系我们,我们会帮您设置好

你可以选择从头开始训练或者从一个关卡开始。

从零开始建立模型或者使用 迁移学习 (图片由 RoboflowStreamlit 拍摄;授权使用。)

  • 从零开始培养。这是更容易的选择。只需点击并运行!您的模型将从零开始构建,仅使用您提供给它的数据。
  • 从一个关卡开始。这个选项稍微复杂一点,需要一个相关的现有模型。如果您已经构建了一个适合相关数据的模型(或者有一个公共模型),那么从一个检查点开始允许您使用现有的模型作为起点。模型还会根据您的图像进行额外训练。这样做的两个好处是你的模型将会训练得更快,而且你会经常看到性能的提高!这就是所谓的迁移学习。然而,这确实需要一个相关的现有模型,而我们并不总是有这样的模型。

在我的例子中,我从零开始构建我的模型,因为我还没有一个相关的模型。

这就是在 Roboflow 中适合一个模型所需要的一切。说到底,如果你的数据已经被注释,并且你没有对增强做很多改变,那么只需要点击几下鼠标,就可以从你的图像转到一个训练有素的计算机视觉模型。我们还将注释图像变成了一个非常快速的过程——特别是有了模型辅助标签

如何使用 API 访问模型和预测

我们模型性能的总体结果,包括 平均精度 (图片由 RoboflowStreamlit 拍摄;授权使用。)

在深入研究这个问题之前,您需要确保您的模型运行良好。

我们的模型似乎表现得很好。通常,我们使用平均精度 (mAP)来评估目标检测模型。你的地图越接近 100%越好!按类别查看您的模型的性能也是有帮助的,以确保您的对象检测模型对于一个对象子集的性能不会明显更差。

看着 模特逐班表演 (图片由 RoboflowStreamlit 拍摄;授权使用。)

如果您的模型没有按照您想要的方式执行,您可能希望在继续之前对其进行改进。当人们采取以下两种行动中的一种(或两种)时,我们通常会看到模型的显著改进:

  1. 完善自己的标注 围绕整个对象放置边界框,但尽可能靠近对象的边缘,可以提高模型的性能。
  2. https://blog.roboflow.com/handling-unbalanced-classes/为不平衡的阶级进行矫正。有一个或多个严重代表不足的类会使您的模型更难正确识别那些代表不足的类。一个基本的例子是,如果你给一个孩子看 5 张狗的图片和 100 张猫的图片,这个孩子可能不能很好地识别狗。

现在我们已经拟合了一个模型,我们可以使用该模型对新图像进行预测。Roboflow 推断 API 是进行推断的几种方法之一,这就是我们将要使用的。

  • 型号名称:这个要以rf开头。
  • 访问令牌/API 密钥:这应该是一个 12+字母的代码。

为了使用这个 API,我们需要来自 Roboflow 的一些信息。确保这些都是私人的。这些都是针对你的!

这些信息可以在很多地方找到。我喜欢从示例 Web 应用程序中检索这些,因为我还可以轻松地上传一张图片,并从那里测试我的模型。一旦你有了这些信息,你会想要储存它们——你会随时需要它们。

如何创建和部署 Streamlit 应用程序

部署 Streamlit 应用程序非常简单。即使你以前没有花很多时间专注于部署应用程序。(这里是我写的构建 app 的代码。)

紧紧跟随 Streamlit 的 API 文档,我能够构建一个应用程序:

  • 从我的电脑导入了一个图像文件
  • 允许用户调整我们的计算机视觉模型的参数
  • 显示了用模型的预测注释覆盖的导入图像
  • 计算并显示有关图像和预测的汇总统计数据
  • 为边界框生成了一个置信度直方图

我选择将它分为两个物理组件:侧边栏和主区域。

  • ****边栏。在侧边栏中,用户可以选择从本地计算机导入文件。在这里,用户可以选择一幅图像放入应用程序,并编辑为图像生成预测边界框时使用的置信度和重叠阈值。

应用侧边栏,让你能够快速改变你的预测参数。(图片由 RoboflowStreamlit 拍摄;授权使用。)

  • ****主要区域。在主区域,我们有我提到的所有其他东西。包含预测的图像、关于图像和预测本身的一些统计数据、显示所有边界框置信度的直方图,以及存储边界框注释的 JSON 的打印输出。

主应用区域,可视化预测输出、汇总统计和边界框置信度。(图片由 RoboflowStreamlit 拍摄;授权使用。)

如果你想看完整的代码,你可以在这里找到。最有帮助的三个工具是:

  • 如果我想在我的屏幕上打印任何东西,st.write()让我可以轻松做到。它支持 Markdown ,所以我可以用##来控制标题的大小。在显示汇总统计数据时,我还使用了 f 字符串,以便更好地控制这些数据的呈现方式。例如,在小数点后四位四舍五入平均置信水平,而不是一长串尾随小数。
  • 我绝对不是一个网络开发人员。定义侧边栏就像st.sidebar()一样简单,而不是花费我的时间去计算如何为用户留出屏幕的左侧和争论尺寸。想在侧边栏上添加一些东西,比如滑块或者上传文件的方式?试试st.sidebar.slider()或者st.sidebar.file_uploader()。Streamlit API 的设置使您的组件停留在您想要的位置。
  • st.image()st.pyplot() : Streamlit 的 API 很直观。如果你想在你的应用程序中插入图像,你可以使用st.image()功能。来自 pyplot 的剧情?st.pyplot()。如果你想把一张图片放到侧边栏,你可以把它从st.image()改成st.sidebar.image()

你明白了。如果你想做某件事,你可能只需要输入st.that_thing_you_want_to_do()!如果你想让那个东西出现在你的侧边栏里,把它改成st.sidebar.that_thing_you_want_to_do()

在编写完我的 Python 脚本并推送到 Github 之后,我按照 Streamlit 的指示部署了我的应用——点击这里查看应用

想了解更多关于开发人员使用 Streamlit 开发的令人惊叹的应用程序吗?查看他们的应用程序库社区论坛,为你的下一个项目寻找一些灵感。

原载于 2021 年 2 月 23 日https://blog . streamlit . io**

如何使用 Seaborn 进行数据可视化

原文:https://towardsdatascience.com/how-to-use-seaborn-for-data-visualization-4c61fc488ec1?source=collection_archive---------34-----------------------

数据可视化是以图形的形式表示数据的艺术。对于处理数据的专业人员,例如金融分析师、业务分析师、数据分析师、数据科学家等,这是一个非常有用的工具。在本教程中,我们将使用 Python 库 Seaborn。

卢克·切瑟在 Unsplash 上的照片

目录

  1. 介绍
  2. 先决条件
  3. 安装 Seaborn
  4. 导入 Seaborn 并加载数据集
  5. 不同类型的图表
  6. 可视化口袋妖怪数据集
  7. 结论

介绍

Seaborn 是一个基于 matplotlib 构建的开源 Python 库。它用于数据可视化和探索性数据分析。Seaborn 很容易使用 dataframes 和 Pandas 库。创建的图表也可以轻松定制。下面是数据可视化的一些好处。

图表可以帮助我们找到在任何机器学习或预测项目中有用的数据趋势。

  • 图表使得向非技术人员解释数据变得更加容易。
  • 视觉上吸引人的图表可以使演示和报告更吸引读者。

本教程可以分为三个主要部分。第一部分将讨论安装 seaborn 和加载我们的数据集。在第二部分中,我们将讨论 Seaborn 中的一些常见图形。最后,我们将使用 seaborn 和口袋妖怪数据来创建一些很酷的图表。

我将把我所有的代码写在一个 Google colab 文件中。你可以在这里找到。

先决条件

  • 很好的理解 Python。
  • 在熊猫图书馆工作的一些经验。
  • 使用 Matplotlib 库的一些经验。
  • 对数据分析的基本理解

安装 Seaborn

如果您正在使用 Google Colab,您可以跳过安装步骤。但是,如果您在本地机器上工作,您将需要安装 Seaborn。我强烈建议创建一个虚拟环境来更好地管理您的包。

python -m venv venv
venv/Scripts/activate
pip install pandas, matplotlib, seaborn

导入 Seaborn 并加载数据集

import seaborn as sns
import pandas
import matplotlib.pyplot as plt

Seaborn 有 18 个内置数据集,可以使用以下命令找到它们。

sns.get_dataset_names()

我们将在本教程中使用泰坦尼克号数据集。

df = sns.load_dataset('titanic')
df.head()

不同类型的图表

计数图

在处理分类值时,计数图很有帮助。它用于绘制不同类别的频率。性别列包含泰坦尼克号数据中的分类数据,即男性和女性。

sns.countplot(x='sex',data=df)

计数图 1

  • 数据 —数据帧。
  • x —列的名称。

我们可以从图表中观察到,男性乘客的数量明显高于女性乘客的数量。

我们可以根据另一个分类变量进一步分解计数图中的条形。也可以自定义绘图的调色板。

sns.countplot(x='sex', hue = 'survived', data = df,
palette = 'Set1')

计数图 2

  • 色调 —拆分条形的分类列的名称。
  • 调色板 —要使用的调色板。要获得调色板列表,请点击查看 matplotlib 的文档

KDE 图

核密度估计(KDE)图用于绘制连续数据的分布。

sns.kdeplot(x = 'age' , data = df , color = 'black')

KDE 图

  • 数据 —数据帧。
  • x —列的名称。
  • 颜色 —图形的颜色。你可以在这里找到颜色列表

上图的峰值在 20 到 40 岁之间,因此我们可以得出结论,大多数乘客的年龄在 20 到 40 岁之间。

分布图

分布图类似于 KDE 图。它用于绘制连续数据的分布。

sns.displot(x = 'age',kde=True,bins = 5 , data =df)

分布图 1

  • kde —默认设置为假。但是,如果您希望在条形图顶部绘制 KDE 图,可以将其设置为 True。
  • —箱/条的数量。数字越小,条形越宽,间隔越宽。

上面的情节告诉我们,泰坦尼克号上的大多数人都是 25 岁左右。

sns.displot(x ='age',kde=True,bins = 5 ,
hue = df['survived'] , palette = 'Set3', data=df)

分布图 2

您还可以将色调和调色板作为参数传递来定制图形。

大多数幸存的乘客都是二十多岁。

散点图

对于这个图和下面的图,我们将使用 iris 数据集。虹膜数据集包含与花的花瓣大小(花瓣长度和花瓣宽度)和萼片大小(萼片长度和萼片宽度)相关的数据。

这些特征用于分类鸢尾的类型(刚毛鸢尾、杂色鸢尾和海滨鸢尾)。下面我们将尝试研究这些特征之间的关系。

首先,我们需要加载虹膜数据集。

df = sns.load_dataset('iris')
df.head()

散点图有助于理解数据之间的相互关系,

sns.scatterplot(x='sepal_length', y ='petal_length' ,
data = df , hue = 'species')

散点图

散点图需要 x 轴和 y 轴的数据。我们还可以为 hue 参数传递一个值,根据分类列给点着色。

在上图中,我们可以观察到萼片长度< 6cm and petal length >2 厘米的鸢尾花最有可能是刚毛鸢尾。虽然在杂色点和海滨点之间没有明显的界限,花瓣长度在 2 厘米和 5 厘米之间的鸢尾花最有可能是杂色类型,而花瓣长度大于 5 厘米的鸢尾花最有可能是海滨类型。

联合地块

联合图也用于绘制数据之间的相关性。

sns.jointplot(x='sepal_length' , y ='petal_length',
data = df , kind = 'reg')

联合地块

  • 种类 —要绘制的地块的种类。它可以是下列之一。

'scatter', 'hist', 'hex', 'kde', 'reg', 'resid'

配对图

Seaborn 让我们绘制多个散点图。当您想快速浏览数据时,这是一个不错的选择。

sns.pairplot(df)

配对图

它将所有连续数据配对,并绘制它们的相关性。它还绘制了数据的分布。

如果不希望将所有列配对,可以再传入两个参数 x_vars 和 y_vars。

热图

热图可用于可视化混乱、矩阵和关联。

corr = df.corr()
sns.heatmap(corr)

热图 1

我们可以自定义配色方案、最小/最大值和注释。

根据热图,我们可以得出结论,萼片长度与花瓣长度和花瓣宽度高度正相关,而萼片宽度与花瓣长度和花瓣宽度负相关。

sns.heatmap(corr, cmap=['red','green','blue'],
vmin = -.5 , vmax = 0.6,annot = True)

热图 2

可视化口袋妖怪数据集

你可以从这里下载口袋妖怪数据集。

将文件上传到 google drive。

from google.colab import files
files.upload()

如果您在本地机器上工作,可以跳过上述步骤。确保下载的文件与 Python 文件位于同一个文件夹中。

pokemon_df = pd.read_csv('pokemon.csv')
pokemon_df.head()

口袋妖怪类型分布

plt.figure(figsize=(15,8))
sns.countplot(x = 'type1' , data = pokemon_df,
hue = 'is_legendary')

口袋妖怪剧情 1

因为 Seaborn 是建立在 matplotlib 之上的,所以我们可以使用 matplotlib 的函数来增加图形的大小。查看图表,我们可以得出结论,水和正常是主要的口袋妖怪类型。我们还可以得出结论,传奇口袋妖怪的主导类型是精神。

进攻和防守的关系

sns.pairplot(x_vars=['attack' , 'defense','sp_attack','sp_defense'] ,
y_vars=['attack' , 'defense','sp_attack','sp_defense'] ,
data = pokemon_df)

口袋妖怪剧情 2

你也可以选择传递色调参数来获得更多的洞察力。

身高和体重的关系

sns.jointplot(x = 'weight_kg', y = 'height_m',
data = pokemon_df,hue = 'is_legendary')

口袋妖怪剧情 3

根据上面的图表,我们可以得出结论,口袋妖怪的身高和体重没有任何相关性。

你可以尝试一些其他的情节。

  • 身高/体重分布。
  • 传奇口袋妖怪 vs 非传奇口袋妖怪的数量。
  • 特攻特防回归图。
  • 显示功能之间相关性的热图。

结论

数据可视化是呈现数据的好方法,Seaborn 是您工具箱中的有用工具。因为它是建立在 matplotlib 之上的,所以您可以像使用 matplotlib 自定义绘图一样自定义您的绘图。

编码快乐!

我最近用 WordPress 创建了一个博客,如果你能看看的话,我会很高兴的😃

在 LinkedIn 上与我联系

https://www.linkedin.com/in/rahulbanerjee2699/

原载于 。2021 年 1 月 29 日木卫一

如何使用模拟进行假设检验

原文:https://towardsdatascience.com/how-to-use-simulations-for-hypothesis-tests-6f0ac53a9c8f?source=collection_archive---------17-----------------------

实践教程

如何用 Python 中的例子使用两种不同的模拟技术进行假设检验

照片由 ChuttersnapUnsplash 上拍摄

假设检验是统计学的重要组成部分。它们帮助我们在医疗保健、商业、伦理和许多其他领域做出重要决策。有许多很棒的资源解释了如何进行这些测试,以及如何使用像正态分布和 t 分布这样的分布来获得这些测试的结果。

本文将关注如何使用模拟为假设检验生成我们自己的分布。模拟允许我们用很少的假设来进行假设检验,并且有一个直观的结果,可以很容易地解释。

我们要看的第一个模拟技术是使用一个已知概率分布的随机变量随机生成数据。当您知道您有兴趣进行统计分析的事件结果的潜在概率分布时,这是一个非常有用的概念。

我们将使用的第二种模拟技术被称为置换假设检验。当您试图测试变量之间的相关性时,这是一个特别有用的工具。

对于这两种技术,我们将使用一个示例来计算在六面骰子上滚动的 1 的数量。我们以此为基础来描述这些模拟是如何工作的。到本文结束时,您应该了解如何将模拟应用到您感兴趣的更高级的假设测试中。

假设检验简介

在我们开始模拟之前,让我们快速回顾一下假设检验。如果您已经对此感到满意,请随意跳到下一部分。

假设检验的基本目标是了解某种治疗对结果变量的影响。例如,如果一家制药公司在一项研究中给一些参与者一种他们正在测试的新药,而另一些人收到一种安慰剂,该公司将有兴趣了解实际药物的表现是否比安慰剂更好。举个例子,这是一种减肥药,服用这种药的人比服用安慰剂的人平均多减了 10 磅。

你首先假设一个无效假设,即你在研究中观察到的结果是由于偶然。这相当于假设整个人群(除了参与研究的样本之外)的真实体重减轻了 0 磅。然后,我们需要收集足够的证据来否定这个假说,支持另一个药物有效的假说。

然后,我们将观察到的结果与 t 分布(如果我们不知道标准偏差,并且人口较少)或正态分布进行比较。我们会考虑在假设的分布下,我们多久会观察到一个和我们在实验中观察到的一样大的结果;观察到极值或比观察值更极值的概率称为 p 值。如果该概率足够低(通常为 5%),我们可以拒绝我们的零假设,即我们观察到的结果仅仅是由于机会(因为零分布不太可能代表基于我们实验的真实总体反应)。

方法 1:已知概率分布的模拟

我们将使用 Python 编写所有的代码,但是这些概念在没有 Python 知识的情况下应该很容易理解。让我们从导入一些库开始。

import numpy as np
import pandas as pd
import random
import seaborn as sns

对于第一个例子,我们想进行一个假设检验,看看一个六面骰子的权重是否相等(如果所有 6 个数字的概率相等)。我们对这个测试的零假设是所有的数字被掷出的可能性是相等的。

我们假设一个骰子有 20%的未知概率掷出 1,有 16%的概率掷出其他 5 个数字。

random.seed(100)
pop = [1, 2, 3, 4, 5, 6]
weights = [.2, .16, .16, .16, .16, .16]
skewed = random.choices(pop, weights=weights, k=200)

在观察了 200 次掷骰子(由上面的代码生成)之后,我们使用下面的函数来计算每个被掷出的数字的个数:

def count_occurences(data, minimum=1, maximum=6):
    counter = {num: 0 for num in range(minimum, maximum + 1)}
    for roll in data:
        counter[roll] += 1
    return counter

我们观察每个数字出现的次数如下:

skewed_dist = count_occurences(skewed)Out: {1: 46, 2: 29, 3: 27, 4: 39, 5: 29, 6: 30}

如果骰子的重量相等,那么当我们掷骰子 200 次时,我们预计每次掷骰子的数字约为 32,每个数字出现的概率为 16.67% (1/6)。我们注意到 1 的数量特别大,想测试一下这是否是偶然的。

由于我们已经知道每个数字在公平骰子中出现的潜在概率,我们可以模拟成千上万次掷骰子,看看在一组 200 次掷骰子中观察到 46 个 1 的可能性有多大。

我们可以使用下面的代码生成 100 次 200 个公平骰子滚动的试验:

rolls_dist_100 = [[random.randint(1, 6) for rolls in range(200)] for num_trials in range(100)]

我们应该模拟多少次试验?100 次试验够吗?这是一件需要考虑的重要事情。让我们看看在不同次数的试验中,我们看到的 1 的数量分布。

正如我们所看到的,更多的试验似乎能更好地去除我们结果中的随机噪声。运行更多试验的时间成本很小。因此,你应该进行的试验次数取决于你试图探索的问题。一般来说,试验越多越好。

我们将使用 100,000 次试验来获得我们的统计结果。这是我们在零假设下观察到的一的数量分布,假设每个数字的概率相等。

现在,让我们将实际观察到的 46 个结果与 100,000 组 200 个骰子滚动的结果进行比较。

# Create a list of dictionaries for the counts
roll_counts_100000 = list(map(count_occurences, rolls_dist_100000))# Store results in dataframe
counts_df_100000 = pd.DataFrame(roll_counts_100000)# Find the times where we observe a larger value
counts_df_100000['bigger'] = counts_df_100000[1] > skewed_dist[1]# Get the probability
sum(counts_df_100000['bigger']) / 100000Out: 0.0082

我们看到观察到我们所做的结果的概率大约是 0.0082(我们的 p 值)。这是非常低的,所以我们将拒绝我们的零假设,即骰子在所有 6 个面上着陆的可能性相等。我们已经知道这是预期的结果,因为我们知道倾斜骰子的真实概率分布。

方法 2:排列假设检验

现在我们将讨论排列测试。这里有一个很棒的可视化,如果你想了解更多关于这个过程的信息,你应该去看看。排列测试背后的想法是,我们给变量赋值,我们想看看这些赋值是否有意义。为了测试这一点,我们多次随机打乱赋值的顺序,看看旧的赋值与新的赋值分布相比如何。

让我们假设一个有 1000 名参与者的锦标赛正在进行,每个参与者互相掷骰子 200 次,最低的数字获胜。玩家 0 赢得锦标赛,与其他玩家相比,他有大量的零。我们想知道他是否作弊了。

我们使用以下代码生成数据:

pop = [1, 2, 3, 4, 5, 6]
weights_skewed = [.2, .16, .16, .16, .16, .16]
random.seed(100)
rolls_vs = [random.choices(pop, k=200) if person != 0 else random.choices(pop, weights=weights_skewed, k=200) for person in range(1000)]

我们使用下面的代码为每个玩家的所有掷骰子创建一个数据框。

df_vs = pd.DataFrame(list(map(count_occurences, rolls_vs)))

我们注意到参与人 0 掷出了 46 个 1,远远超过了预期的 200 个 1 的数量。我们在 200 掷的锦标赛中生成 100,000 个千位玩家的 1 的排列分布,并查看该玩家的 1 是否明显多于排列分布。

perms = [np.random.permutation(df_vs[1])[0] for i in range(100000)]

每个排列中玩家 0 的 1 的数量(来源:作者)

在给定分布的情况下,我们发现观察值的 p 值为 46 或更高。

sum([1 if 46 <= x else 0 for x in perms]) / 100000Out: 0.01746

我们得到 p 值为 0.017。这是一个相当低的概率,但并非完全不可信。我们期望看到这种类型的表演大约是 100 次中的 1 次。我们应该对这种表现持怀疑态度,并可能认为该球员可能在这场比赛中作弊。如果这是研究环境中的另一个测试,我们将有足够的证据来拒绝零假设,即我们观察到的结果是由于机会而支持我们的替代假设,即玩家使用倾斜的骰子。

结论

作为数据科学家,我们现在又多了两个工具来进行假设检验。只需几行代码,我们就可以用很少的假设来测试这些假设。我们不需要假设检验中经常需要的关于数据正态性的典型假设。

除了分析掷骰子之外,这些工具还有一些有趣的应用。我们现在有了分析这些问题的基本构件。这些类型的测试已经被应用到一些有趣的问题中,比如评估奥运会跳水比赛中的裁判偏差,以及评估篮球比赛中的“T2”是否存在。

感谢您阅读本文,祝您下次假设检验顺利。

Python 中如何使用奇异值分解进行图像分类

原文:https://towardsdatascience.com/how-to-use-singular-value-decomposition-svd-for-image-classification-in-python-20b1b2ac4990?source=collection_archive---------3-----------------------

用一个简单的例子揭开 SVD 背后的线性代数概念

Marcel strau 在 Unsplash 上拍摄的照片

线性代数中最难理解的主题之一是奇异值分解 (SVD)方法。它也是最基本的技术之一,因为它为理解主成分分析(PCA)、潜在狄利克雷分配(LDA)和一般矩阵分解的概念铺平了道路。

奇异值分解之所以难以捉摸,是因为虽然这种方法需要大量的数学和线性代数知识才能掌握,但实际应用却常常被忽视。有很多人以为自己掌握了 SVD 的概念,其实不然。这不仅仅是一种降维技术:本质上,SVD 的神奇之处在于任何矩阵 A 都可以写成秩 1 矩阵的和!这一点以后会变得明显。

本文的目的是通过将 SVD 应用于一个众所周知的例子:手写数字分类,展示 SVD 的用途和基本机制。

快速提醒(高级可选)

奇异值分解的基本关系是

其中:
U 和 V 是正交矩阵,
S 是对角矩阵

更具体地说:

其中显示了前述的权利要求,任何矩阵 A 都可以写成秩 1 矩阵的和

奇异值分解的一些有用特性:

  1. u 矩阵和 v 矩阵分别由aᵀa的特征向量构成。
  2. 任何矩阵都有 SVD 分解。这是因为 AAᵀAᵀA 矩阵有一个特殊的性质(以及其他性质):它们至少是半正定的(这意味着它们的特征值要么是正的,要么是零)。
  3. S 矩阵包含正特征值的平方根。这些也被称为奇异值。
  4. 在包括 Python 在内的大多数编程语言中,U 和 V 的列的排列方式是特征值较高的列在特征值较小的列之前。
  5. u,u …向量也被称为左奇异向量,它们形成了一个正交基*。相应的, v,v …向量称为右奇异向量。*
  6. 矩阵 A 的秩是 S 矩阵的非零奇异值的个数。
  7. 埃克哈特-杨-米尔斯基定理 : 一个秩的最佳 k 秩逼近 k < r 一个矩阵在 2-范数和 F-范数下是:

换句话说:

如果你想用一个较低秩的 k 来逼近任何矩阵 A,最佳的方法是对 A 应用 SVD,只取前 k 个具有最高 k 个奇异值的基向量。

Python 中的 SVD

对于这个例子,我们将使用手写数字 USPS(美国邮政服务)数据集。该数据集包含 7291 个训练和 2007 个[0–9]之间的手写数字测试图像。图像是 1616 灰度像素。首先,我们加载数据:*

*import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.linalg import svd, norm
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
import h5py
import os# define class labels
labels = {
    0: "0", 
    1: "1", 
    2: "2", 
    3: "3", 
    4: "4", 
    5: "5", 
    6: "6", 
    7: "7", 
    8: "8",
    9: "9"
}# load the dataset
with h5py.File(os.path.join(os.getcwd(), 'usps.h5'), 'r') as hf:
        train = hf.get('train')
        test = hf.get('test') x_train = pd.DataFrame(train.get('data')[:]).T
        y_train = pd.DataFrame(train.get('target')[:]).T
        x_test = pd.DataFrame(test.get('data')[:]).T
        y_test = pd.DataFrame(test.get('target')[:]).Tprint(x_train.shape)
print(y_train.shape)
print(x_test.shape)
print(y_test.shape)#Output:
#(256, 7291)
#(1, 7291)
#(256, 2007)
#(1, 2007)*

数据的加载方式与上面快速提醒部分的尺寸相匹配。 x_trainx_test 的列包含作为向量的数字,这些数字被展平成大小等于 256 的数组(因为每个数字的大小都是 16x16)。另一方面, y_trainy_test 是行向量,分别包含训练和测试数据集的每个数字(0 到 9 之间的值)的实际类。

图 1 显示了训练数据集中的第一幅图像:

*digit_image=x_train[0]
plt.imshow(digit_image.to_numpy().reshape(16,16),cmap='binary')*

图 1:来自训练数据集的图像

数字分类的方法由以下步骤组成:

  1. 我们将 x_train 数据帧分成 10 个矩阵(按列),每个矩阵对应一个数字[0–9]。这些是之前提到的 A 的矩阵。目标是将 SVD 分别应用于它们中的每一个。例如,A0 矩阵仅包含数字 0 的图像,其形状为(256,1194),因为数据集中有 1194 个 0。
  2. 接下来,我们将 SVD 应用于[A0,A1..A9]矩阵。对于每个 A 矩阵,我们存储相应的 U、S 和 V 矩阵。我们将主要使用 U 矩阵。
  3. 用一个数字表示的每个数据矩阵 A 都有一个“独特的特征”。这种区别反映在前几个左奇异向量 (u,u …)。由于这些特征向量本质上是基向量,如果一个未知数字可以用另一个数字(例如数字 3)的基更好地近似,那么我们可以假设该未知数字被分类为那个数字(如 3)。这将在后面的编程示例中变得更加明显。

第一步

这相当容易。我们只是创建了[A0,A1..A9]矩阵,并将它们存储在名为 alpha _ matrices 的字典中:

*alpha_matrices={}for i in range(10):
    alpha_matrices.update({"A"+str(i):x_train.loc[:,list(y_train.loc[0,:]==i)]})print(alpha_matrices['A0'].shape)
#(256, 1194)*

第二步

这一步也很简单。我们将 U、S 和 V 矩阵分别存储在左奇异奇异 _ 矩阵右奇异字典中:

*left_singular={}
singular_matix={}
right_singular={}for i in range(10):
    u, s, v_t = svd(alpha_matrices['A'+str(i)], full_matrices=False)
    left_singular.update({"u"+str(i):u})
    singular_matix.update({"s"+str(i):s})
    right_singular.update({"v_t"+str(i):v_t})print(left_singular['u0'].shape)
#(256, 256)*

让我们展示一下这些矩阵中包含了哪些信息。我们将使用数字 3 的 U、S 和 V 矩阵作为示例,在我们的示例中,它们对应于以下变量:

*#left_singular[‘u3’]
#right_singular[‘s3]
#singular_matix[‘v_t3]plt.figure(figsize=(20,10))
columns = 5
for i in range(10):
   plt.subplot(10/ columns + 1, columns, i + 1)
   plt.imshow(left_singular["u3"][:,i].reshape(16,16),cmap='binary')*

图 2:U3 矩阵的前 10 个奇异向量

图 2 显示了前 10 个左奇异向量[u,u … u ⁰](共 256 个)。它们都描绘了数字 3,其中第一个(u1 向量)最为清晰。

图 3 以对数标度显示了 S 矩阵中数字 3 的奇异值:

*plt.figure(figsize = (9, 6))
plt.plot(singular_matix[‘s3’], color=’coral’, marker=’o’)
plt.title(‘Singular values for digit $3$’,fontsize=15,weight=”bold”,pad=20)
plt.ylabel(‘Singular values’ ,fontsize=15)
plt.yscale(“log”)
plt.show()*

图 3:数字 3 的所有奇异值

给定奇异值排序,前几个是最高的(就值而言),并遵循“陡峭的曲线模式”。

通过考虑图 2图 3 ,我们可以图形化地确认 3 位 SVD 的矩阵逼近性质(记住 Eckart-Young-Mirsky 定理):第一个左边的奇异向量代表矩阵 A3 的固有属性值。事实上,在图 2 的中,第一个奇异向量 u1 看起来像数字 3,随后的左奇异向量代表 u1 周围的训练集的最重要的变化。

问题是我们是否可以只使用第一个 k 个奇异向量,并且仍然有一个很好的近似基。我们可以通过实验来验证。

第三步

给定一个由(1256)个向量表示的未知数字称为 z ,给定左奇异向量的集合 u1,u2… uk ,其中每个集合表示对应的数字矩阵/A 矩阵,那么 z 的目标值是多少?注意我们的索引是 k (第一主奇异特征向量)而不是 n (全部)。要解决这个问题,我们要做的就是以下几点:

目标是计算测试集中的一个数字在 10 个不同的标准正交基中的表现程度。

这可以通过计算以下类型的最小二乘问题中的剩余向量来实现:

最小二乘问题的解是

记住 U 矩阵是正交的。剩余范数向量变成:

就是这样!现在我们需要的东西都有了。使用最后一个公式,我们继续计算不同 k 值的测试精度:

*I = np.eye(x_test.shape[0])
kappas=np.arange(5,21)
len_test=x_test.shape[1]predictions=np.empty((y_test.shape[1],0), dtype = int)for t in list(kappas):
    prediction = []
    for i in range(len_test):
        residuals = []
        for j in range(10):
            u=left_singular["u"+str(j)][:,0:t]
            res=norm( np.dot(I-np.dot(u,u.T), x_test[i]  ))
            residuals.append(res)
        index_min = np.argmin(residuals)
        prediction.append(index_min)

    prediction=np.array(prediction)
    predictions=np.hstack((predictions,prediction.reshape(-1,1)))scores=[]for i in range(len(kappas)):
    score=accuracy_score(y_test.loc[0,:],predictions[:,i])
    scores.append(score)data={"Number of basis vectors":list(thresholds), "accuracy_score":scores}
df=pd.DataFrame(data).set_index("Number of basis vectors")*

表 1:不同 k 值的测试准确度得分

我们也可以用图形显示这个结果:

图 4:不同 k 值的测试准确度分数

表 1图 4* 都显示了不同数量的基向量的准确度分数。使用 k=12 可以获得最好的分数。*

接下来,显示混淆矩阵:

*pd.set_option(‘display.max_colwidth’,12)
confusion_matrix_df = pd.DataFrame( confusion_matrix(y_test.loc[0,:],predictions[:,7]) )confusion_matrix_df = confusion_matrix_df.rename(columns = labels, index = labels)
confusion_matrix_df*

f1 分数(宏观平均值和每节课的分数) :

*print(classification_report(y_test.loc[0,:],predictions[:,7]))*

*点评: *数字 0、1、6、7 在 f1-score 方面表现最好。
数字 5 和 3 在 f1 得分方面表现最差。

让我们来看一些分类错误的图片的例子:

*misclassified = np.where(y_test.loc[0,:] != predictions[:,7])plt.figure(figsize=(20,10))
columns = 5
for i in range(2,12):
    misclassified_id=misclassified[0][i]
    image=x_test[misclassified_id]

    plt.subplot(10/ columns + 1, columns, i-1)
    plt.imshow(image.to_numpy().reshape(16,16),cmap='binary')
    plt.title("True label:"+str(y_test.loc[0,misclassified_id]) + '\n'+ "Predicted label:"+str(predictions[misclassified_id,12]))*

显然,其中一些数字写得非常糟糕。

结论

实际上,A 数据矩阵本质上是一个低秩矩阵加噪声:A = A' + N。通过应用 Eckart-Young-Mirsk 定理,我们用一个正确秩为 k 的矩阵来逼近数据矩阵 A。这具有保持矩阵固有属性完整的效果,同时去除了额外的噪声。但是我们如何找到正确的秩 k 呢?

在我们的案例中,我们通过对第一个主要奇异值进行实验,根据测试精度经验地找到了 k。然而,应该注意的是,当然还有其他算法优于这种技术。然而,本案例研究的重点是通过调整一种众所周知的矩阵分解技术来展示手写数字分类的另一种方法。有关这个例子的理论技术和原理的更多信息,请查阅本

如何在数据质量改进中使用六适马

原文:https://towardsdatascience.com/how-to-use-six-sigma-in-data-quality-improvements-f6d4d49838d9?source=collection_archive---------41-----------------------

DMAIC 可以成为数据治理计划中一个有用的框架

我们到处都能听到数据的高度重要性。我们甚至称之为新石油。由于我们生活在一个数据驱动的时代,我们需要知道如何跟上数据趋势,并保持允许使用它的某种质量。一旦你理解了目的,你就可以开始在数据质量改进计划中采取行动。

@钳工Unsplash 上的照片

在组织中拥有高质量数据的关键是意识和防弹过程。这里我们来关注第二个。当考虑过程时,DMAIC 循环非常方便,这个六适马框架确实是为过程改进而设计的。

DMAIC 是一个数据驱动的改进周期,旨在应用于业务流程。在您的组织中实施将让您发现缺陷或低效——尤其是导致输出缺陷的缺陷——并与之斗争。目标是改进、优化或稳定现有流程。

这听起来非常适合帮助提高数据质量,事实也确实如此。它可以帮助改进数据管理过程,并发现数据条目中的“缺陷”。该框架本身符合 5 个步骤,将引导您获得值得信赖的数据:

图片由丹尼尔·彭菲尔德

1.定义— 从挑战业务需求开始。寻找受数据质量影响的主要利益相关者——他们可以是职能、部门、项目等。(示例—销售营销、人力资源、法律)

建立联系,与他们交谈,了解他们在流程中使用了哪些数据元素。创建调查并安排采访。你的目标是找出什么是相关的,这样你就不会最终创建一堆没人关心的指标和报告。识别数据管理流程和数据流—将它们放到地图上。

使用设计思维方法,如强调和构思,寻找要解决的问题和高效的改进机会。发出调查问卷并安排面试。

输出:确定的机会

2。测量- 尝试用数字描述流程,收集数据并执行数据分析活动,使其与数据质量维度保持一致。获得成效(取决于您组织的成熟度,但首先要关注数据合规性、一致性和唯一性)。用数字,而不只是空洞的论文。你可以阅读如何设置数据质量仪表板

例如:

  • 10 %的顾客是重复的。
  • 20%的客户邮政编码具有有效的格式

尝试绘制数字并显示相关性,在此建立一个业务案例,并显示可以带来的好处—可以是报告准确性、减少浪费或法规遵从性。估计差的数据质量会在维护或罚款上花费多少。

输出:过程性能测量

3。分析— 数据管理流程应该能够产生满足最低数据质量要求的结果。这是你应该评估结果的地方。使用流程图、数据流、来源、确定的入口点,并在此基础上执行根本原因分析以下是一些有用的技术:

  • 5 个为什么

这是一个非常简单的入门技巧。基本概念是问“为什么?”五次深入挖掘问题的根源。其背后的逻辑是,在前几个问题中,您将找到问题的原因之一,到第 5 个问题时,您将看到问题背后的流程失败。这个来自维基百科的例子很好地解释了这个问题:

  1. 为什么?—电池没电了。(第一个为什么)
  2. 为什么?—交流发电机不起作用。(第二个为什么)
  3. 为什么?—交流发电机皮带断裂。(第三个为什么)
  4. 为什么?—交流发电机皮带远远超过其使用寿命,且未更换。(第四个为什么)
  5. 为什么?—车辆没有按照推荐的维修 计划进行维护。(第五个为什么是根本原因)
  • 鱼骨图—石川图

它显示了比 5whys 更全面的情况。这是一个高度可视化和头脑风暴的技术,引发了根本原因的进一步的例子。问题显示为右侧的鱼头,原因延伸到左侧的鱼骨。

  • 帕累托图

帕累托原理广为人知。这个练习的目的是发现哪些变化对我们的输出影响最大。这种技术更多的是对变量进行加权,而不是寻找潜在的根本原因,帕累托图允许我们对根本原因本身进行优先排序。它显示了您应该首先处理哪些变化才能产生最大的影响,以及哪些变化不值得花费精力。

Pareto 的目标不是找到 x,而是找到正确的 x。它代表了最常见的缺陷来源、发生率最高的缺陷类型或客户投诉最常见的原因。

问自己一个问题,变异的可能来源是什么。查看历史数据,找出决定性因素,确定哪些进程或供给系统正在创建大部分垃圾记录。

输出:问题陈述和确定的关键变量

4。改进 —一旦你发现流程中的薄弱环节,调查它们如何影响结果,并找出如何修复它们。尝试用价值比努力的方法去获得唾手可得的成果和快速的胜利。根据组织的成熟度,可以通过简单的调整(如用户界面应用程序中的数据输入验证)来修复流程。更复杂的可以使用弹性搜索或重复数据删除,甚至是实施新的主数据工具和流程的项目。

主要步骤是:

  • 头脑风暴和设计解决方案-
  • 确定预期结果
  • 规划和实施解决方案

输出:实施的解决方案。预测和测试结果

5。控制 —解决问题这不是最后一步。持续监控您的数据,以确保改进得以实施和保持。

创建数据质量指标,定期监控您的数据,并对任何相关变化做出反应。控制并信任这个过程,以确认你的改变是可持续的。

  • 验证因问题陈述而导致的故障减少
  • 确定是否需要其他改进
  • 吸取的教训

输出:性能监控、稳定性计划

现在相信这个过程,你可以通过寻找下一个改进的机会重新开始这个循环。如果您迷失在数据质量度量中,遵循 DMAIC 步骤可以帮助组织您的项目并协调组织中数据清理计划的工作。这是一个坚实的框架,可以为您指明正确的方向,并让您了解数据质量之旅中的高层次计划。

原载于 2021 年 4 月 13 日 https://www.solution-tailor.comhttps://www.solution-tailor.com/post/how-to-use-six-sigma-in-data-quality-improvements

如何将 Sklearn 管道用于极其简洁的代码

原文:https://towardsdatascience.com/how-to-use-sklearn-pipelines-for-ridiculously-neat-code-a61ab66ca90d?source=collection_archive---------2-----------------------

我喜欢的关于 Scikit-Learn 的一切,都在一个地方

照片由https://www.pexels.com/@abhiram2244?utm_content=attributionCopyText&utm_medium=referral&utm_source=pexels像素 组成

为什么需要管道?

数据清理和准备很容易成为机器学习中最耗时、最无聊的任务。所有的 ML 算法都很繁琐,有些想要标准化或规范化的特征,有些想要编码的变量,有些则两者都想要。然后,还有一个总是存在的缺失值的问题。

处理它们一点都不好玩,更不用说在所有的训练、验证和测试集上重复相同的清理操作所带来的额外好处了。幸运的是,Scikit-learn 的Pipeline是促进这一过程的主要生产力工具,它清理代码并将所有预处理和建模步骤压缩到一行代码中。来,看看这个:

上图中,pipe_lasso是这种管道的一个实例,它填充了X_train中缺失的值,并通过拟合套索回归对数字列和一次性编码分类变量进行了特征缩放。当你调用.predict时,同样的步骤也适用于X_test,这真是太棒了。

管道结合了我喜欢的 Scikit-learn 的一切:简洁、一致和易于使用。所以,事不宜迟,让我在几分钟内展示如何构建自己的管道。

从这个链接下载笔记本或者在 Kaggle 这里运行。

****https://ibexorigin.medium.com/membership

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

https://alphasignal.ai/?referrer=Bex

Scikit 简介-学习管道

在本部分和接下来的部分中,我们将为 Ames Housing 数据集一起构建上述pipe_lasso管道,该数据集用于 Kaggle 上的班级竞赛。该数据集包含 81 个变量,几乎涉及房子的每个方面,利用这些变量,你必须预测房子的价格。让我们加载训练集和测试集:

除了最后一列— SalePrice之外的所有内容都用作特征。在我们做任何事情之前,让我们将训练数据分成训练集和验证集。我们将使用最终的X_test集进行预测。

现在,让我们对训练集做一个基本的探索:

19 个特征有 NaNs。

现在,开始预处理。对于数字列,我们首先使用平均值用SimpleImputer填充缺失值,使用MinMaxScaler填充特征比例。对于类别,我们将再次使用SimpleImputer用每一列的模式来填充缺失的值。最重要的是,我们在一个管道中完成所有这些工作。让我们导入所有内容:

我们为数字和分类特征创建了两个小管道:

handle_unknown设置为ignore以跳过之前未看到的标签。否则,如果测试集中有不在训练集中的标签,则OneHotEncoder抛出错误。

[sklearn.pipeline.Pipeline](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html)类接受一组转换器作为它的steps参数。每个元组应该具有以下模式:

('name_of_transformer`, transformer)

然后,每个元组被称为一个步骤,包含一个类似SimpleImputer的转换器和一个任意的名称。每个步骤都将被链接起来,并以给定的顺序应用于传递的数据帧。

但是,如果我们不知道它们应该应用于哪些列,这两条管道就没有用。为此,我们将使用另一个变压器— ColumnTransformer

柱式变压器

默认情况下,所有的Pipeline对象都有fittransform方法,可以用来转换输入数组,如下所示:

上面,我们在使用fit_transformX_train上使用了新的数字预处理器。我们用select_dtypes指定列。但是,以这种方式使用管道意味着我们必须在选定的列上分别调用每个管道,这不是我们想要的。我们希望有一个单一的预处理器,它能够在一行代码中执行数值和分类转换,如下所示:

full_processor.fit_transform(X_train)

为了实现这一点,我们将使用ColumnTransformer类:

记住numerical_featurescategorical_features包含了X_train中各个列的名称。

类似于Pipeline类,ColumnTransformer取一个变形金刚元组。每个元组应该包含一个任意的步骤名、转换器本身和应该应用转换器的列名列表。在这里,我们使用数值和分类预处理管道创建了一个包含 2 个步骤的列转换器。现在,我们可以用它来完全改造X_train:

注意,大多数转换器返回numpy数组,这意味着索引和列名将被删除。

最后,我们设法将所有预处理步骤压缩成一行代码。然而,我们可以走得更远。我们可以将预处理和建模结合起来,得到更整洁的代码。

具有估计器的最终流水线

向管道中添加一个估计器(模型)就像创建一个包含上面的列转换器和模型本身的新管道一样简单。让我们导入并实例化LassoRegression,并用full_processor将其添加到新管道中:

警告!步骤的顺序很重要!估计器应该总是管道正确工作的最后一步。

就是这样!我们现在可以像调用任何其他模型一样调用lasso_pipeline。当我们调用.fit时,管道在拟合估计器之前应用所有转换:

_ = lasso_pipeline.fit(X_train, y_train)

让我们在验证集上评估我们的基本模型(记住,我们有一个单独的测试集,到目前为止我们还没有接触过):

太好了,我们的基地管道工程。管道的另一个优点是,它们可以被视为任何其他模型。换句话说,我们可以把它插入任何我们会使用 Scikit-learn 估计器的地方。因此,我们将在下一节中使用网格搜索中的管道来寻找最佳超参数。

到处使用你的管道

Lasso的主要超参数是α,范围从 0 到无穷大。为简单起见,我们将仅以 0.05 为步长对 0 和 1 之间的值进行交叉验证:

现在,我们打印出Lasso的最佳分数和参数:

如你所见,best alpha是 0.95,这是我们给定区间的终点,即步长为 0.05 的[0,1]。我们需要再次搜索,以防最佳参数位于更大的区间:

使用最好的超参数,我们得到了 MAE 的显著下降(这是好的)。让我们用Lasso(alpha=76)重新定义我们的管道:

将其安装到X_train,在X_valid进行验证,并使用X_test提交比赛预测:

结论

总之,管道为您的日常工作流程带来了几个优势,例如代码简洁快速、易于使用以及多个步骤的就地修改。在示例中,我们使用简单的套索回归,但是我们创建的管道可以用于几乎任何模型。去用它来建造一些令人敬畏的东西吧!****

如何利用空间数据识别 CPG 需求热点

原文:https://towardsdatascience.com/how-to-use-spatial-data-to-identify-cpg-demand-hotspots-c7ad6dfafd55?source=collection_archive---------58-----------------------

实践教程

使用空间分析检测包装消费品的需求热点。

近年来,属于有机/天然/本地类别的产品的消费和促销急剧增加。这些是特定类型的产品,没有经过任何工业加工或缺乏某些食品添加剂和防腐剂。在美国,有机产品的营销显著增长,吸引了寻找健康产品和植物性食品的新一代消费者。根据有机贸易协会【1】,有机食品是美国食品工业中增长最快的部门:

有机食品是美国食品工业中增长最快的部分。有机食品的销售额以每年两位数的速度增长,远远超过了整个食品市场的增长率。现在,一项前所未有的结论性研究将经济健康与有机农业联系起来。

对有机产品需求的增长与文化、社会经济和健康因素密切相关。在本案例研究中,我们对这些因素进行了空间分析,以了解哪些特征和城市区域可能有助于 CPG 数据和营销专业人员确定在纽约和费城这两个美国大城市推广分销和确定某些有机食品的 POS(销售点)时的优先顺序。

数据

为了做到这一点,我们从 CARTO 的数据观测站【2】中选择了不同的数据源,这些数据源可以帮助我们确定城市中的哪些区域更适合有机产品的分销。我们用于此分析的数据集如下:

  • 万事达卡地理洞察:提供一个地点基于销售的动态数据,这些数据衡量信用卡消费、交易数量、平均门票等的变化。随着时间的推移在零售领域发生的;
  • Spatial.ai地理社交细分:基于分析带有位置信息的社交媒体馈送的行为细分;
  • d stilley行为受众:来源于网络行为的受众;
  • Pitney Bowes兴趣点:具有按类别和行业组分类的企业和其他兴趣点的位置的数据库;
  • AGS社会人口统计:当前年度和未来 5 年的基本社会人口统计和社会经济属性。

方法学

我们的分析遵循三个主要步骤:

  1. 确定有机产品成功推广的高潜力目标领域。
  2. 分析表征和驱动目标区域选择的不同因素
  3. 根据在纽约和费城选择的区域来识别旧金山的孪生区域。

确定分销有机产品的目标区域

一般来说,有机产品或“生物”产品被认为是优质产品,通常价格较高。例如,在底特律,有机牛奶比普通牛奶贵 88%。这意味着最好将这些产品放在消费者愿意支付额外费用的商店里,无论是他们生活、工作还是休闲的地方。

因此,为了确定推广此类产品的潜在领域,我们遵循以下 3 个步骤:

  1. 基于万事达卡数据识别杂货店中平均票价较高的区域;
  2. 通过探索社交媒体帖子(使用 Spatial.ai 地理社会细分)和互联网搜索行为(使用 Dstillery 的受众数据),确定有机食品潜在需求较高的领域;
  3. 上述两个步骤中确定的区域的交集;这些将是案例研究剩余部分的最终选定目标区域。

请注意,我们在此阶段使用的所有三个来源都提供了在人口普查区块组级别聚合的特征。

步骤 1 考虑了基于杂货店中每个人口普查区块组的信用卡交易的月平均票据的指数,并查看票据大小较高的区域。这背后的基本原理是基于这样一个事实,即有机产品被认为是“优质的”,正如本节开始时所提到的。因此,购物者必须有能力和意愿花额外的钱购买有机产品。

首先,我们检查这个变量是否是空间相关的(计算它在两个城市中的莫兰 I 测度),评估表达的模式是聚集的、分散的还是随机的。结果显示了某个位置的值受附近位置的值影响的空间模式。因此,作为下一步,我们将空间滞后计算为某个位置及其邻近区域的平均门票指数的平均值;这基本上就像一个平滑的空间。

然后,基于 FisherJenks 算法 [4]将平均标签的空间滞后量化为 5 个不同的 quants,以努力最小化每个类与类均值的平均偏差,同时最大化每个类与其他组均值的偏差。从结果中,我们选择了前 2 组作为普查区块组,从信用卡消费的角度来看,它们更有可能“盈利”。

下一步是根据行为数据确定对有机产品更感兴趣的领域。为此,使用 Spatial.ai 和 Dstillery 的数据集。前者有一个有机食品的亲和力指数,我们按照与万事达卡指数相同的程序进行分析。由于 Spatial.ai 索引的值范围是从 0 到 100,因此使用的量化方法是分位数。

从 Dstillery 数据集中,我们选择名为“有机和本地食物”的兴趣类型,并遵循用于 Mastercard 和 Spatial.ai 索引的类似分析。同样,观察到了空间相关性,并发现其具有统计学意义。但是,在这种情况下,相关性比 Spatial.ai 中的先前数据集中的相关性低得多。

基于每个数据源,我们已经确定了销售有机产品的最相关区域,我们选择最后一组目标区域作为后两个区域(来自行为数据)与第一个区域(来自信用卡交易数据)的外部合并的交集:

{选定区域} = { master card ∩{ spatial . ai∪d stillery } }

下图说明了每个城市的选择过程。在每个图中,显示了 4 个子图,每个子图分别显示了使用 Mastercard、Spatial.ai、Dstillery 和最终选择选择的区域。

纽约市选定的人口普查区块组

费城选定的人口普查区块组

表征所选区域

已经确定了感兴趣的区域,我们现在想进一步了解哪些因素是它们的特征,并检查使一个区域吸引放置有机产品的驱动属性。为此,我们分析了 AGS 提供的所选区域的社会人口统计和社会经济因素、Pitney Bowes(现在准确地说是)数据库中按业务组汇总的兴趣点(POI)数量,以及 Spatial.ai 中的地理社会细分。我们将比较这些因素在所选区域和未选区域之间的表现。请注意,就社会人口统计和社会经济属性而言,我们选择了数据集中可用的属性作为 5 年预测。

为了识别驱动因素,首先我们计算并比较选择区域和非选择区域的每个特征的分布。为了对它们进行比较,我们执行了一个 t 检验,以评估两组面积的平均值是否存在显著差异。我们丢弃那些在选定区域和非选定区域中具有相同分布的特征。

此外,对于空间地理社会片段,为了减少特征的维度,遵循额外的过程,以便识别在选择区域和非选择区域之间存在较大差异的片段。为此,选择区域和非选择区域内的平均值以及这些平均值的比率被用作特征。下表显示了整个城市和选定地区的平均指数以及这两个值之间的比率。这些计算出来的特征被进一步聚类,我们选择了两个反直径边中的地理社会段。这种选择的基本原理是,在中心,特征在选定区域和非选定区域之间显示相似的行为,而在侧边,观察到高或低值,使得它们之间的区别很明显。

在上述过程之后,忽略了常数和相关特征。对于相关特征,使用 80%阈值。

这些表格显示了前 5 名和后 5 名特性的值,这些值基于城市平均值与各自城市中所选区域平均值之间的比率。有趣的是,地理社交细分市场"ED06 _ ingredient _ attention"出现在费城,而" ED03_trendy_eats "出现在纽约。

选择驱动因素

在形成和清理了特征之后,我们然后构建一个分类器,以便导出每个所选特征的最终影响。但首先,我们需要解决数据不平衡的问题,因为与其他地区相比,选定地区的数量要少得多:纽约选定了 5389 个地区,而费城选定了 623 个地区,1043 个地区,而费城选定了 35 个地区。

为了实现这一点,使用了一种上采样技术【5】来生成人工数据。对训练集进行上采样,生成“新”数据。这样做的原因是为每个类别创建足够的样本,以便分类器可以识别和纠正,同时不会被主要类别、不同的驱动因素及其影响淹没。

上采样过程之后是分类过程,其中使用随机森林分类器。执行超参数调整,试图最小化错误识别的“选择”区域,并保持良好的准确性。作为分类的性能指标,混淆矩阵和接收到的操作曲线在下图中报告。

对于这两个城市,我们可以看到分类方法的性能是好的。有些人可能会认为过度拟合已经发生,但是因为成功地识别了所选区域,所以在不平衡数据集之上的适当分类器的置信度增加了。

查看每个城市前 20 个特征的重要性,使用 Shapley 值 [6],可以提取关于主要驱动因素重要性的信息。此外,可以观察到两个城市的驱动因素之间的相似性。从前 20 个特征中,可以找出城市之间的 10 个共同特征。

纽约市的 20 大特色

费城的 20 大特色

看看纽约最重要的特征,我们可以看到,收入较高的地区,存在“LGTB 文化”和“艺术欣赏”地理社会细分市场,以及与优质食品和饮料相关的细分市场,最适合有机产品的分销。我们在费城看到了类似的趋势,这两个城市的大多数驾驶特征都是相同的。

识别不同城市中的孪生区域

在分析了纽约和费城地区选择背后的驱动因素后,我们在以前的一篇文章 [7]中描述的双地区方法可以应用于在美国其他地区确定有机产品分销的目标地区。作为这个练习的例子,我们选择了旧金山。

现在,我们假设已经在纽约市建立了有机产品的分销策略,并发现了在产品销售方面产生最佳结果的人口普查区块组。双区法的目的是帮助我们利用上一节中确定的驱动因素(即特征)来确定不同城市中的相似区域。

作为表现最好的地区,我们选择了曼哈顿的人口普查区块组:

纽约市的人口普查区块组,我们将在旧金山寻找两个地区

将用作双区方法标准的特征是上一节中确定的纽约和费城的共同特征:

  • 人均收入(预计,五年)',
  • 平均家庭收入(预计,五年)',
  • ' EB03_lgbtq_culture ',
  • ED09 _ 啤酒花和啤酒,
  • ED08 _ 葡萄酒 _ 爱好者',
  • ED04 _ 威士忌 _ 商务',
  • 家庭收入中位数(预计,五年)',
  • ED02 _ 咖啡 _ 鉴赏家',
  • 法律服务,
  • “ED01_sweet_treats”

下面的地图展示了双区域方法的结果,显示了旧金山相似性得分大于 0 的人口普查区块组。我们可以使用直方图小部件过滤区域,根据上面列出的特征识别最相似的双胞胎。

旧金山地点的相似性得分(SS)。仅显示具有正 SS 的位置。

结论

在本案例研究中,我们展示了如何利用新型空间数据,如聚合信用卡交易和社交媒体行为,以定义一种方法来选择和描述在纽约市和费城推广有机产品的最佳区域,使 CPG 公司能够看到他们的 POS 网络中可能存在的差距。最后,我们还应用了双区域法,以便根据在其他两个城市确定的驱动因素来确定旧金山的最佳区域,这两个城市与高收入区域、不同类型零售店的更大集中度以及与优质食品相关的地理社会细分密切相关。

新的位置数据流和空间数据科学技术的结合开辟了一系列新的机会,为消费品的分配确定更优化的策略;允许更好地了解基于消费者细分的不同零售区域,因此 CPG 公司可以将产品尽可能放在潜在需求最大的区域,以确保 CPG 品牌的销售额和投资回报增加。

参考

[1]https://ota.com/hotspots

[2]http://www.carto.com/data

[3]https://www . market watch . com/story/heres-why-of-organic-food-is-dropping-2019-01-24 #:~:text = Last % 20 year % 2C % 20 organic % 20 food % 20 and,percent % 20more % 2C %据%20to%20Nielsen。&text = % 20a 的% 20 平均% 20 价格% 20,a % 20gallon % 20of %普通% 20 牛奶

[4]https://en . Wikipedia . org/wiki/Jenks _ natural _ breaks _ optimization

[5]https://en . Wikipedia . org/wiki/over sampling _ and _ under sampling _ in _ data _ analysis # SMOTE

https://en.wikipedia.org/wiki/Shapley_value

https://carto.com/blog/spatial-data-science-site-planning/

原载于 2021 年 1 月 12 日 https://carto.comhttps://carto.com/blog/how-to-use-spatial-data-to-identify-cpg-demand-hotspots/

如何使用 SQL 交叉连接

原文:https://towardsdatascience.com/how-to-use-sql-cross-joins-5653fe7d353?source=collection_archive---------8-----------------------

您从来不知道存在的 SQL 连接

惠普科赫在 Unsplash 上的照片

我一直在通读旧代码,并试图以更有效的方式重写它。我遇到过很多奇怪的逻辑,但对我来说最陌生的是交叉连接。

我使用过左连接、右连接和内连接,但从未使用过交叉连接。我总是把成为 SQL 忍者作为我的目标,所以很自然,我很好奇为什么我以前从来没有听说过这个。

当我谷歌它是什么时,我发现它是“一种连接,从连接的表中返回行的笛卡尔乘积”。

交叉连接的结果最好用图片来解释。当您交叉连接表 1 和表 2 时,会得到如下所示的结果。

作者图片

这里,第一个表中的第一列与第二个表中的每一列连接,产生三个新行,其组合如下:

  • 1 和 1
  • 1 和 2
  • 1 和 3

因此,对于表 2 中的每一行,该值都与表 1 中的每个值相结合。

当我想到这个输出时,我想到了统计课上的经典组合问题。如果度假只允许带两双,有三种不同颜色的可能性,你能做出多少种不同的袜子组合?

作者图片

对于每一双红色的鞋,你都可以搭配一双蓝色或绿色的。对于每一对绿色的,你可以把它和一对蓝色或红色的配对。对于每一双蓝色的,你可以把它和一双红色或绿色的配对。这类似于交叉连接的输出!

让我们看一个实际的 SQL 查询。假设我们有两个不同的表,代表教室里孩子的名字。一个写着女生名字,一个写着男生名字。

作者图片

SELECT
   girls.name,
   boys.name
FROM girls 
CROSS JOIN boys

当交叉连接女孩表和男孩表并从两个表中选择姓名时,您将得到如下所示的输出。

作者图片

你可以看到每个女孩的名字都与每个男孩的名字配对。您实际上是在两个表之间创建了一个很大的可能组合列表。

对于交叉连接,您还可以包含一个指定某种连接条件的where子句。这在处理数字列时最为常见。

SELECT
   schedule.event,
   calendar.number_of_days
FROM schedule
CROSS JOIN calendar
WHERE schedule.total_number < calendar.number_of_days

这里,查询将只连接schedule表中的行和calendar表中满足指定条件的行。

当您添加where子句时,交叉连接的行为类似于inner join,除了您没有在任何指定的列上连接它。交叉连接查询中不需要 on 语句!

现在,这种连接似乎是低效的。然而,它实际上比解决我们在这里试图做的事情的大多数其他逻辑运行得更快。我决心找到一个更好的交叉连接的解决方案,但我找不到。

所以,也就是说,如果你知道一个运行更快的技巧,请在下面的评论中留下你的建议。

如果你有兴趣学习更多关于 SQL 的知识,可以看看我写的关于窗口函数排名面试问题的文章。

如何使用 SQL 超前和滞后函数

原文:https://towardsdatascience.com/how-to-use-sql-lead-and-lag-functions-35c0db633c5e?source=collection_archive---------2-----------------------

使用窗口函数简化 SQL 解决方案的教程

(本·斯特恩在 Unsplash 上拍照)

如果你一直在虔诚地练习你的 SQL,就像我在的顶级技巧中建议的那样,去面对每一个 SQL 面试问题,那么你可能会遇到使用窗口函数的问题。或者你已经在 Leetcode 上的讨论或解决方案页面中遇到了他们。

窗口函数可能很复杂,但它们使许多问题更容易解决。一旦你学会了最常用的窗口函数,你就可以轻而易举地将它们应用到你的解决方案中。

今天,我将讨论两个有助于简化解决方案的函数——领先和滞后。虽然这些函数以相同的方式使用,但它们会给你相反的结果。一个会找到上一条记录,另一个会找到下一条记录。但是哪个做哪个呢?

他们做什么

超前和滞后将显示与您正在查看的当前行相比的前一个值或后一个值。与其他窗口函数一样,您必须指定运行该函数的列,还可以指定作为分区依据的列和作为排序依据的列。但是,在使用这些函数时,您很可能希望使用 ORDER BY。

例如,假设您有马拉松比赛中运动员的终点订单。你想找到在你之前和之后完成的人。您可以使用这些函数来查找这些人的名字,方法是在跑步者姓名上运行这些函数,并按完成位置排序。

如何使用它们

这两个函数都使用 OVER()子句以及 PARTITION BY 和 ORDER BY。部分函数的划分是可选的,但是 ORDER BY 几乎总是必需的。唯一不希望使用它的情况是在表中查找目标行之前/之后的行。

SELECT runner_name, place, LEAD(runner_name) OVER(ORDER BY place ASC) AS runner_after FROM race_results

作者图片

这里需要注意的是表最后一行的空值。因为 Ellen 之后没有 runner,所以 LEAD 函数将返回 NULL。

ORDER BY 指定表格中行的排序依据列。在这种情况下,我们按位置排序,从第一个位置开始,到最后一个位置结束。根据您想要的结果,在这里选择 ASC 还是 DESC 订单也很重要。请记住,ASC 表示当您向下滚动表格的行时,数字会变大,而 DESC 表示数字会从最高值开始变小。

划分充当分组逻辑。它将只查看在指定列中具有相同值的行。例如,如果我们按性别划分比赛结果,领先和落后只会给我们之前和之后的赛跑者与讨论中的那一排相同的性别。

SELECT runner_name, place, gender, LEAD(runner_name) OVER(PARTITION BY gender ORDER BY place ASC) AS same_gender_runner_after

作者图片

这里我们可以看到,same_gender_runner_after 列给出了与目标行性别类别相同的下一个跑步者的姓名。还可以注意到,John 和 Ellen 在该列中具有空值,因为他们之后没有与其性别相同的跑步者。

超前和滞后的区别

LEAD 将给出您正在查找其值的行之后的行。LAG 将给出您要查找其值的行之前的行。

考虑这些术语与您的目标行的关系。使用 lead 函数时,目标行位于返回行的开头。使用 LAG 函数时,目标行落后于返回的行。

请记住,如果使用 PARTITION BY 语句,它可能不会返回目标行之前或之后的确切行。它将返回在该语句指定的列中具有相同值的行之前或之后的行。

让我们先在不分区的情况下比较超前和滞后的结果。

作者图片

当我们不使用 PARTITION BY 时,我们得到的是在目标行之前/之后的真实行,只要在这种情况下它们是按位置排序的。此外,当使用 LEAD 函数时,最后一行为 NULL,而当使用 LAG 函数时,第一行为 NULL。查看滞后列,Madison 在这里的值为空,因为没有人在她之前完成。

现在我们来比较一下按性别分区时的两个函数。

作者图片

在这里,我们可以看到 LEAD 和 LAG 为我们提供了相同性别的之前/之后的行,如果性别与目标行的性别不匹配,则跳过“真实”的下一行。同样,我们可以看到最后两行 LEAD 为空,前两行 LAG 为空。由于按性别划分,这里是前/后两行。

如果你正在为 SQL 面试而学习,一定要看看我的文章获得每一个 SQL 面试问题的顶级技巧以及如何使用 SQL RANK 和 DENSE_RANK 函数,以便更仔细地了解 SQL 的排名函数。

查询愉快!

如何使用 SQL RANK 和 DENSE_RANK 函数

原文:https://towardsdatascience.com/how-to-use-sql-rank-and-dense-rank-functions-7c3ebf84b4e8?source=collection_archive---------0-----------------------

一个关于你为什么想要使用它们以及它们的主要区别的教程

乔舒亚·戈德Unsplash 上拍摄的照片

如果你一直在虔诚地练习你的 SQL,就像我在顶级技巧中建议的那样,去面对每一个 SQL 面试问题,那么你可能会遇到使用窗口函数的问题。或者你已经在 Leetcode 上的讨论或解决方案页面中遇到了他们。

窗口函数可能很复杂,但它们使许多问题更容易解决。一旦你学会了最常用的窗口函数,你就可以轻而易举地将它们应用到你的解决方案中。

今天我要讲两个对任何类型的排名问题都有帮助的函数——RANK 和 DENSE_RANK。虽然这些功能相似,但它们确实有所不同。在很多情况下,两者都可以解决你的问题。然而,当你确实需要一个特殊的解决方案时,知道其中的区别仍然是很重要的。

他们做什么

RANK 和 DENSE_RANK 用于对值进行排序,并根据它们相对于彼此的位置为它们分配编号。

例如,假设你有三个学生,他们有三个不同的考试分数——一个学生得了 100 分,另一个得了 85 分,最后一个得了 72 分。这些函数将根据您希望的排名顺序为每个学生分配 1、2 或 3。

如何使用它们

这两个函数都使用 OVER()子句以及 PARTITION BY 和 ORDER BY。函数的 part BY 是可选的,但是 ORDER BY 总是必需的。

SELECT student_name, RANK() OVER(ORDER BY grades DESC) AS grade_ranking

作者图片

在这里,您可以看到最高等级的等级为 1,最低等级为 5,因为它们是按降序排列的。

ORDER BY 指定要对其值进行排序的列。在前面的示例中,等级是在 ORDER BY 之后指定的。您可以按降序或升序排列值。

在上面的代码片段中,我们从最高等级到最低等级排序(DESC),下面我们从最低等级到最高等级排序(ASC)。

SELECT student_name, RANK() OVER(ORDER BY grades ASC) AS grade_ranking

作者图片

在这里,您可以看到最低等级的等级为 1,最高等级的等级为 5,因为等级是按升序排列的。

分区由组排名。当此处指定的列的值发生变化时,排名会重新开始。假设我们在学生的考试成绩中增加了科目。如果你把数据按主题分类,它会给你每个分数的排名,按主题分组。

SELECT student_name, DENSE_RANK() OVER(PARTITION BY subject ORDER BY grades DESC) AS grade_ranking

作者图片

正如你所看到的,每门课的最高分被定为 1 分,其余的分数也根据他们在这门课中的位置进行排名。

秩和 DENSE_RANK 的区别

这两个函数的区别在于它们如何处理相同的值。假设我们有两个成绩相同的学生。两人的数学考试都得了 90 分。

RANK 和 DENSE_RANK 将根据等级与其他值相比的排名情况为等级分配相同的排名。然而,RANK 将跳过下一个可用的排名值,而 DENSE_RANK 将仍然使用下一个按时间顺序排列的排名值。

因此,对于等级,如果两个 90 的等级为 2,下一个最低值将被分配为 4,跳过 3。使用 DENSE_RANK,下一个最低的值将被分配等级 3,而不会跳过任何值。

让我们比较一下这两个函数的结果。

SELECT student_name, RANK() OVER(ORDER BY grades DESC) AS rank_w_rank, DENSE_RANK() OVER(ORDER BY grades DESC) AS rank_w_dense_rank

作者图片

同样,您可以看到使用 rank 的列中没有 rank 2,而 DENSE_RANK 列包含 rank 2 并以 rank 4 结尾,尽管表中有 5 行。

希望你现在明白如何使用 RANK 和 DENSE_RANK 以及何时使用它们。通常,我使用 DENSE_RANK 作为我在 SQL 中的默认排名函数。我发现更多的问题希望你按照时间顺序排列,不要跳过一个数字。但是,请确保您仔细阅读了问题,并考虑了您试图实现的输出。

如果你正在准备 SQL 面试,一定要看看我的文章每一个 SQL 面试问题的顶级技巧

查询愉快!

通过订阅我的电子邮件列表,了解更多关于 SQL 和分析工程师使用的其他工具的信息。

如何使用 SQL 窗口函数

原文:https://towardsdatascience.com/how-to-use-sql-window-functions-5d297d29f810?source=collection_archive---------26-----------------------

最常见的例子有代码示例

范妮·拉斯科在 Unsplash 上的照片

无论您是在解决一个复杂的问题,还是正在面试一个需要高级 SQL 知识的技术职位,了解如何使用 SQL 窗口函数都很重要。

虽然在工作面试过程中并不总是必要的,但知道如何使用它们肯定会给面试官留下深刻印象,并在解决编码问题时节省你的时间。这些功能通常会将非常复杂的解决方案简化为更快、更容易理解的解决方案。

什么是窗口函数?

窗口函数是在各种表格行中执行的函数。这些函数不是像“正常”函数那样单独查看每一行,而是通常查看前面和/或后面的行,以便计算目标行。

最流行的窗口函数

  1. 总和
  2. 最大
  3. 行号
  4. 军阶
  5. 超前/滞后

让我们分别来看看它们的作用以及在 SQL 代码中使用它们的最佳方式。

总和

Sum 就像它听起来的那样。它把你指定给它的任何东西加起来,或者取总和。sum window 函数与典型 sum 函数的主要区别在于,它对每一行进行累计求和,而不是对所有行进行累计求和。

例如,假设您想要创建一周内花费的累计总额。你希望看到你在一周的每一天都花了多少钱,而不是一周结束时的总数。你可以使用求和窗函数。

SELECT
   employee_name,
   day_of_week,
   amount_spent,
   SUM(amount_spent) OVER (ORDER BY date) AS total
FROM personal_finances 

这将产生如下所示的输出:

作者图片

如果我们是一家公司,正在查看我们的员工花费了多少钱,那么在报表中添加一个分区可能会有所帮助。

SELECT
   employee_name,
   day_of_week,
   amount_spent,
   SUM(amount_spent) OVER (ORDER BY date PARTITION BY employee_name) AS total
FROM personal_finances

该查询的输出如下所示:

作者图片

最大

就像 sum 一样,max 的工作方式类似于“普通”SQL max 函数。它采用您指定的列的最大值,并取决于您对 ORDER BY 和 PARTITION BY 使用的条件。但是,请记住,这些函数是可选的。

以下是如何从每个部门中找出在公司卡上花费最多的员工:

SELECT
   employee_name,
   department,
   MAX(total_spent) OVER(ORDER BY total_spent PARTITION BY   department) as max_spent
FROM personal_finances

结果将如下所示:

作者图片

行号

行号和等级非常相似,经常互换使用。就我个人而言,我更多地使用排名方式,因为我认为它更适用于我正在解决的问题。行号用于根据行在表中的顺序为行分配编号。您不必在括号中使用列名,因为您只是返回订单。

这里,我们按照雇员 id 对雇员进行排序,并根据雇员在表中的顺序为每一行分配一个行号。

SELECT
    ROW_NUMBER() OVER(ORDER BY employee_id),
    employee_id,
    employee_name
FROM org_chart

这将产生如下所示的输出:

作者图片

军阶

Rank 用于根据某个列值对行进行排序。这对于任何类型的排序问题都非常有用,并且由于 ORDER BY 和 PARTITION BY 子句的缘故,非常有用。Rank 可能是所有窗口函数中我最喜欢和最常用的!

在这里,我们可以用它来找出公司里花钱最多的人:

SELECT
    employee_name,
    employee_id,
    amount_spent,
    RANK(amount_spent) OVER(ORDER BY amount_spent DESC) AS spend_rank
FROM employees

请注意,我在 ORDER BY 子句后包含了 DESC。这在使用 rank 时极其重要。必须指定是按列 ASC(值变大)还是按列 DESC(值变小)排序。如果不指定这一点,查询可能会返回与预期相反的结果。

作者图片

让我们看看同一个例子,但是使用 PARTITION BY。

SELECT
    employee_name,
    employee_id,
    department_id,
    RANK(amount_spent) OVER(ORDER BY amount_spent DESC PARTITION BY department_id) AS spend_rank
FROM employees

现在,我们正在对每个部门的最高支出者进行排名。每次检测到不同的 department_id 时,排名将从停止的排名号继续。输出将如下所示:

请注意,它并不一定要对行进行分组或重新排序,但是排名是由 department_id 和每个员工在其部门内的支出金额顺序决定的。

如果您有兴趣深入研究 rank 窗口函数,甚至了解 rank 和 dense rank 之间的区别,请查看我的文章如何使用 SQL RANK 和 DENSE_RANK 函数

超前/滞后

当你第一次了解它们的时候,理解起来会很困惑。实际上,我写了一整篇文章来解释它们的不同之处,以及记住它们的含义的技巧。查看如何使用 SQL 超前和滞后函数了解更多信息。

第一次使用窗口函数时,尽量不要沮丧。你能做的最好的事情就是练习、练习、练习,然后将你的输出与你期望你的代码产生的结果进行比较。这是了解代码如何工作的最好方法。

请务必查看我的另一篇关于 SQL 窗口函数的文章,以消除您可能有的任何困惑。查询愉快!

如何使用 Streamlit 和 Python 构建数据科学应用程序

原文:https://towardsdatascience.com/how-to-use-streamlit-and-python-to-build-a-data-science-app-d74b0d28ca8?source=collection_archive---------13-----------------------

用几行代码部署您的数据科学解决方案

照片由来自佩克斯克里斯蒂娜·莫里洛拍摄

Web 应用仍然是数据科学家向用户展示其数据科学项目的有用工具。由于我们可能没有 web 开发技能,我们可以使用 Streamlit 这样的开源 python 库,在短时间内轻松开发 web apps。

目录

  1. Streamlit 简介
  2. 安装和设置
  3. 开发 Web 应用程序
  4. 测试 Web 应用程序
  5. 结论

1.Streamlit 简介

Streamlit 是一个开源 python 库,用于为数据科学和机器学习项目创建和共享 web 应用程序。该库可以帮助您用几行代码在几分钟内创建和部署您的数据科学解决方案。

Streamlit 可以与数据科学中使用的其他流行 python 库无缝集成,如 NumPy、Pandas、Matplotlib、Scikit-learn 等等。

注意:Streamlit 使用 React 作为前端框架在屏幕上呈现数据。

2.安装和设置

Streamlit 要求您的计算机中的 python >= 3.7 版本。

要安装 streamlit,您需要在终端中运行以下命令。

pip install streamlit

您还可以使用以下命令检查您的计算机上安装的版本。

streamlit --version

streamlit,版本 1.1.0

成功安装 streamlit 后,您可以通过在终端中运行以下命令来测试该库。

streamlit hello

Streamlit 的 Hello 应用程序将出现在 web 浏览器的新选项卡中。

这表明一切都运行良好,我们可以继续使用 Streamlit 创建我们的第一个 web 应用程序。

3.开发 Web 应用程序

在这一部分中,我们将使用经过训练的 NLP 模型来预测电影评论的情绪(正面或负面)。你可以在这里访问源代码和数据集

数据科学 web 应用程序将显示一个文本字段来添加电影的评论,以及一个简单的按钮来提交评论并进行预测。

导入重要包

第一步是创建一个名为 app.py 的 python 文件,然后为 streamlit 和经过训练的 NLP 模型导入所需的 python 包。

# import packages
import streamlit as st
import os
import numpy as np

from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer

# text preprocessing modules
from string import punctuation

# text preprocessing modules
from nltk.tokenize import word_tokenize

import nltk
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
import re  # regular expression
import joblib

import warnings

warnings.filterwarnings("ignore")
# seeding
np.random.seed(123)

# load stop words
stop_words = stopwords.words("english")

功能清理审查

评论可能会有我们在做预测时不需要的不必要的单词和字符。

我们将通过删除停用词、数字和标点来清理评论。然后我们将使用 NLTK 包中的词汇化过程将每个单词转换成它的基本形式。

在做出预测之前, text_cleaning() 函数将处理所有必要的步骤来清理我们的评论。

# function to clean the text
@st.cache
def text_cleaning(text, remove_stop_words=True, lemmatize_words=True):
    # Clean the text, with the option to remove stop_words and to lemmatize word

    # Clean the text
    text = re.sub(r"[^A-Za-z0-9]", " ", text)
    text = re.sub(r"\'s", " ", text)
    text = re.sub(r"http\S+", " link ", text)
    text = re.sub(r"\b\d+(?:\.\d+)?\s+", "", text)  # remove numbers

    # Remove punctuation from text
    text = "".join([c for c in text if c not in punctuation])

    # Optionally, remove stop words
    if remove_stop_words:
        text = text.split()
        text = [w for w in text if not w in stop_words]
        text = " ".join(text)

    # Optionally, shorten words to their stems
    if lemmatize_words:
        text = text.split()
        lemmatizer = WordNetLemmatizer()
        lemmatized_words = [lemmatizer.lemmatize(word) for word in text]
        text = " ".join(lemmatized_words)

    # Return a list of words
    return text

功能进行预测

名为 make_prediction() 的 python 函数将完成以下任务。

  1. 收到评论并清理。
  2. 加载训练好的 NLP 模型。
  3. 做个预测。
  4. 估计预测的概率。
  5. 最后,它将返回预测的类及其概率。
# functon to make prediction
@st.cache
def make_prediction(review):

    # clearn the data
    clean_review = text_cleaning(review)

    # load the model and make prediction
    model = joblib.load("sentiment_model_pipeline.pkl")

    # make prection
    result = model.predict([clean_review])

    # check probabilities
    probas = model.predict_proba([clean_review])
    probability = "{:.2f}".format(float(probas[:, result]))

    return result, probability

注:如果训练好的 NLP 模型预测 1,表示正,预测 0,表示负。

创建应用标题和描述

您可以使用 streamlit 中的 title()和 write()方法创建 web 应用程序的标题及其描述。

# Set the app title
st.title("Sentiment Analyisis App")
st.write(
    "A simple machine laerning app to predict the sentiment of a movie's review"
)

要显示 web 应用程序,您需要在终端中运行以下命令。

streamlit run app.py

然后,您将看到 web 应用程序在您的 web 浏览器中自动弹出,或者您可以使用创建的本地 URLhttp://localhost:8501。

创建一个接收电影评论的表单

下一步是使用 streamlit 创建一个简单的表单。该表单将显示一个文本字段来添加您的评论,在文本字段下方,将显示一个简单的按钮来提交添加的评论,然后进行预测。

# Declare a form to receive a movie's review
form = st.form(key="my_form")
review = form.text_input(label="Enter the text of your movie review")
submit = form.form_submit_button(label="Make Prediction")

现在,您可以在 web 应用程序上看到该表单。

进行预测并显示结果

我们的最后一段代码是,每当用户添加一部电影的评论并单击表单部分的“make prediction”按钮时,就进行预测并显示结果。

点击按钮后,web app 将运行 make_prediction() 函数,并在浏览器中的 web app 上显示结果。

if submit:
    # make prediction from the input text
    result, probability = make_prediction(review)

    # Display results of the NLP task
    st.header("Results")

    if int(result) == 1:
        st.write("This is a positive review with a probabiliy of ", probability)
    else:
        st.write("This is a negative review with a probabiliy of ", probability)

4.测试 Web 应用程序

通过几行代码,我们创建了一个简单的数据科学 web 应用程序,它可以接收电影评论,并预测它是正面评论还是负面评论。

要测试 web 应用程序,请通过添加您选择的电影评论来填充文本字段。我补充了以下关于 2021 年上映的扎克·施奈德版正义联盟电影的影评。

“我从头到尾都很喜欢这部电影。就像雷·费舍说的,我希望这部电影不会结束。乞讨的场景令人激动,我非常喜欢那个场景。不像《正义联盟》这部电影展示了每个英雄最擅长自己的事情,让我们热爱每一个角色。谢谢扎克和整个团队。”

然后单击进行预测按钮并查看结果。

正如你在我们创建的 web 应用程序上看到的,经过训练的 NLP 模型预测添加的评论是正面的概率为 0.64。

我建议您在我们创建的数据科学 web 应用程序上添加另一个电影评论,并再次测试它。

5.结论

Streamlit 提供了许多功能和组件,您可以使用这些功能和组件按照自己的方式开发数据科学 web 应用程序。您在这里学到的是 streamlit 的一些常见元素。

要了解更多信息,您可以访问他们设计精美的文档页面这里。

如果你学到了新的东西或者喜欢阅读这篇文章,请分享给其他人看。在那之前,下一篇文章再见!。

你也可以在推特上找到我 @Davis_McDavid

最后一件事:在以下链接中阅读更多类似的文章

https://python.plainenglish.io/how-to-use-google-trends-api-with-python-d00837349369 https://medium.datadriveninvestor.com/nlp-datasets-from-huggingface-how-to-access-and-train-them-8852c2aca74 https://medium.datadriveninvestor.com/pycaret-a-faster-way-to-build-machine-learning-models-d4cbce6a6633

本文首发 此处

如何在 react.js 中使用 tensorflow.js 对象检测

原文:https://towardsdatascience.com/how-to-use-tensorflow-js-in-react-js-object-detection-98b3782f08c2?source=collection_archive---------3-----------------------

与 Tensorflow.js 反应

使用 COCO-SSD 模型定位和识别单个图像中的多个对象

来自 PexelsAnna Shvets 的原始照片

本文是我的 tensorflow.js + react.js 系列的第 3 部分,旨在促进 tensorflow.js 在 react 中的使用。作为对新阅读器的介绍, Tensorflow.js 或 TF.js 是 Javascript 中的机器学习库,它使 ML 模型可以直接在浏览器或 Node.js 中使用

TF.js 释放了前端开发人员的无限潜力,他们可以利用机器学习的力量,如对象检测、人脸检测、图像分类和情感分析,而无需依赖后端服务器。

本教程的最终产品是通过 COCO-SSD 模型创建一个对象检测,该模型在桌面网络摄像头中工作,可检测 80 种类型的对象。

图 1:来自最终项目的图像

*在这里尝试演示,在这里尝试完整代码

*演示尚未针对移动相机(人像)进行优化

1.0 理论和了解您的模型

什么是物体检测?

目标检测是一项计算机视觉任务,包括两个主要任务:

  1. 定位图像中的一个或多个对象,以及
  2. 对图像中的每个对象进行分类

图 2:图像分类与目标检测(分类和定位)。来自佩克斯的克里斯滕·梅里曼和来自佩克斯莎伦·麦卡琴的原始照片

与图像分类(图 2)相反,对象检测的目标是通过边界框和所定位对象的类别来预测对象在图像中的位置,输出可以多于一个类别。

基于区域的卷积神经网络和目标检测

CNN 传统上用于图像分类,然而,当图像中有多个对象时,由于输出层的长度不是恒定的,并且将有大量的区域/包围盒用于分类,CNN 不可能对图像中的多个对象进行分类。

Ross gir shick提出了一种更好的方法,其中通过选择性搜索约 2000 个区域(称为区域建议),现在神经网络只对区域建议进行分类,而不是对大量区域进行分类(图 3)。这种方法被称为 R-CNN,它极大地提高了图像中对象检测的性能,并使自动驾驶汽车技术成为可能。它是 CNN 中目标检测的基础。

图三。来自[5]的 R-CNN 图像的插图

COCO-SSD 是什么?

COCO-SSD 模型或上下文中的常见对象—单次多盒检测模型检测 COCO 数据集中定义的对象,该数据集中包含大规模对象检测、分割和字幕数据。

该模型能够检测 80 类对象,是移植到 tensorflow.js 的官方对象检测模型之一。它可以将输入作为任何基于浏览器的图像元素(例如,<img><video><canvas>元素),并返回带有类名和置信度的边界框数组(图 4)。

图 4。返回预测结果

2.0 设置您的创建-反应-应用程序

通过终端中的以下命令创建一个 Create-React-App :

npx create-react-app tfjs-sentiment
cd tfjs-sentiment

安装 tensorflow.js 和 COCO-SSD 型号如下:

npm install @tensorflow/tfjs
npm install @tensorflow-models/coco-ssd

安装 react-网络摄像头,如下所示:

npm install react-webcam

并启动应用程序

npm start

3.0 编码

所有代码只会发生在 App.js 中,我只会显示重要的代码,完整代码可以参考我的 GitHub repo

步骤 1:从导入所需的包开始

import React, { useEffect, useState, useRef } from "react";
import * as cocoSsd from "@tensorflow-models/coco-ssd";
import * as tf from "@tensorflow/tfjs";
import Webcam from "react-webcam";

步骤 2:加载模型

使用 useEffect()在初始化时加载模型,当模型加载时,您将获得“set loaded Model”的控制台日志。它通常看起来大约 1-2 秒,取决于你的 CPU 速度

确保在触发模型加载功能之前,TF 模块已准备就绪

const [model, setModel] = useState();async function loadModel() {
try {
const model = await cocoSsd.load();
setModel(model);
console.log("set loaded Model");
} catch (err) {
console.log(err);
console.log("failed load model");
}
}useEffect(() => {
tf.ready().then(() => {
loadModel();
});
}, []);

步骤 3:构建用户界面

该项目的用户界面包括:

  • 按钮—用于启动检测
  • 画布-用于绘制边界框,以及
  • 网络摄像头—用于输入图像/视频
Button:
//Trigger a predictionFunction() on Click<Button
variant={"contained"}
style={{
color: "white",
backgroundColor: "blueviolet",
width: "50%",
maxWidth: "250px",
}}
onClick={() => {
predictionFunction();
}}
>
Start Detect
</Button>Webcam:
const webcamRef = React.useRef(null);
const [videoWidth, setVideoWidth] = useState(960);
const [videoHeight, setVideoHeight] = useState(640);const videoConstraints = {
height: 1080,
width: 1920,
facingMode: "environment",
};<div style={{ position: "absolute", top: "400px" }}>
<Webcam
audio={false}
id="img"
ref={webcamRef}
screenshotQuality={1}
screenshotFormat="image/jpeg"
videoConstraints={videoConstraints}
/>
</div>Canvas:
<div style={{ position: "absolute", top: "400px", zIndex: "9999" }}>
<canvas
id="myCanvas"
width={videoWidth}
height={videoHeight}
style={{ backgroundColor: "transparent" }}
/>
</div>

注意:画布和网络摄像头的大小和位置必须相同,才能在 HTML 画布中进行绘制。

步骤 4:设置预测函数

要使用模型进行预测,代码很简单:

const predictions = await model.detect(document.getElementById("img"));
console.log(predictions);
*Do not copy

然而,当预测的类必须显示在照片中时,事情就变得复杂了,这就是使用 HTML canvas 的原因。整个预测函数如下所示:

async function predictionFunction() {//Clear the canvas for each prediction
var cnvs = document.getElementById("myCanvas");
var ctx = cnvs.getContext("2d");
ctx.clearRect(0,0, webcamRef.current.video.videoWidth,webcamRef.current.video.videoHeight);//Start prediction
const predictions = await model.detect(document.getElementById("img"));if (predictions.length > 0) {
console.log(predictions);for (let n = 0; n < predictions.length; n++) {
console.log(n);
if (predictions[n].score > 0.8) {
//Threshold is 0.8 or 80%//Extracting the coordinate and the bounding box information
let bboxLeft = predictions[n].bbox[0];
let bboxTop = predictions[n].bbox[1];
let bboxWidth = predictions[n].bbox[2];
let bboxHeight = predictions[n].bbox[3] - bboxTop;
console.log("bboxLeft: " + bboxLeft);
console.log("bboxTop: " + bboxTop);
console.log("bboxWidth: " + bboxWidth);
console.log("bboxHeight: " + bboxHeight);//Drawing begin
ctx.beginPath();
ctx.font = "28px Arial";
ctx.fillStyle = "red";
ctx.fillText(
predictions[n].class +": " + Math.round(parseFloat(predictions[n].score) * 100) +
"%", bboxLeft,bboxTop);ctx.rect(bboxLeft, bboxTop, bboxWidth, bboxHeight);
ctx.strokeStyle = "#FF0000";
ctx.lineWidth = 3;
ctx.stroke();console.log("detected");
}
}
}
//Rerun prediction by timeout
setTimeout(() => predictionFunction(), 500);
}

这个函数包括 4 个部分,第一部分是清除绘制的 HTML 画布,然后开始对象的模型检测。

如果模型检测到对象,则模型将返回如图 4 所示的预测数据。通过使用边界框数据,我们可以使用 HTML 画布绘制来绘制边界框。

然后使用 500 毫秒的超时重新运行整个功能。

最后,祝贺你!您获得了第一个基于 react 的网络摄像头对象检测。

一些问题:

  • 除了视频,这个模型也接受 tf。tensor 3d | ImageData | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement。更多信息请参考我的 github 中的评论部分
  • 您可以更改基于 CNN 的模型,如 mobilenet_v1、mobilenet_v2,以在 ModelConfig 中获得更好的性能。默认型号是 lite_mobilenet_v2
  • 要检测定制对象,这种解决方案并不可行,因为定制模型训练需要经历许多过程

4.0 最后的话:

在我看来,react 使得使用 TF.js 的整个过程比官方推荐的 HTML+javascript 的演示更简单。与官方演示中令人困惑的演示相比,只需要不到 100 行代码就可以对基于网络摄像头的检测进行编码。

基于前端的供电 TF 模型可以具有成本效益,因为与服务器供电的 TensorFlow 解决方案相比,大多数前端托管更便宜,此外,它可以保护用户的隐私。这里有一些谷歌关于 TF.js 用例的演示,关注 TF youtube 频道以获得更多社区分享!

最后,

感谢您的阅读。

希望这篇文章对你有所帮助

我的 TF.js + React.js 文章:

参考资料:

  1. TensorFlow.js 物体检测变得简单
  2. https://github . com/tensor flow/models/blob/master/research/object _ detection/readme . MD
  3. https://cocodataset.org/#home
  4. 视觉系统的深度学习
  5. 丰富的特征层次,通过 Ross Girshick 实现精确的对象检测和语义分割

如何在数据分析项目中使用束方法

原文:https://towardsdatascience.com/how-to-use-the-beam-approach-in-data-analytic-projects-8a1604015cfd?source=collection_archive---------14-----------------------

问正确的问题,在你的敏捷项目和产品中取得成功

照片由 Unsplash 上的 Gautier Salles 拍摄

business Event Analysis & modeling(BEAM)是一个针对数据仓库的敏捷需求收集工具,其目标是将需求分析与业务流程而不仅仅是报告结合起来。它源于 Lawrence Corr 和 Jim Stagnitto 的敏捷数据仓库设计[1]。

原则

这一概念的主要原则是[1][2]:

  • 个人和互动:商业智能是由用户对其业务的提问所驱动的。技术设置是次要的。
  • 业务驱动的:需要数年时间部署的文档完备的数据仓库总是会过时。商业用户会将目光投向别处。我在业务部门的经验:我现在就需要它,否则我宁愿坚持使用 Excel 解决方案…
  • 客户协作:最终用户对其业务的了解是您最大的资源。
  • 应对变化:如果你采取了以上所有的行动,变化会自然而然地出现,并导致每周的交付周期。

这是关于问正确的问题

BEAM 的作者 Lawrence Corr 描述了一种用于构建“数据故事”的设计模式。
举例:业务事件——客户购买产品[3]

  • 订单日期是什么时候?
  • 在哪里购买的,会送到哪里?
  • 怎么买了多少?
  • 被购买的原因是什么?
  • 哪个哪个渠道购买的?

通过这些重要的问题,业务流程变得清晰可见,因此可以推导出技术条件。

图片来自 Pixabay 上的 Gerd Altmann

梁和用户故事

问了正确的问题后,你现在可以很容易地定义用户故事。例如,在回答哪里:客户从网上商店订购产品时,您可以在您的数据仓库中导出一个累积快照事实表的需求,我需要什么属性以及进一步的需求,如相应的 ETL/ELT 过程的模式。

吉拉的数据故事-作者图片

摘要

我现在说到哪里了?对我来说,BEAM 遵循的原则是有意义的,并且非常适合敏捷模式。我也发现提问方式很重要。提出正确的问题并确定业务流程。这揭示了很多被蒙在鼓里的东西。

“启发我们的不是答案,而是问题。”—欧仁·尤内斯库

然而,对我来说,我说我并不严格按照 BEAM 来工作,但是我发现这种描述用户故事的方法很有趣。为此,了解业务流程是必不可少的。当然,这种方法不仅适用于数据仓库设计,也适用于数据领域。例如,如果我想在您的数据湖中提供新的 ML 服务或报告,这总是与 ETL 过程的构造、数据仓库中的模式以及报告或服务的实现有关。

资料来源和进一步阅读

[1]optimalbi.com、阿吉利比 vs BEAM✲ vs 模特风暴 (2015)

[2] Lawrence Corr,Jim Stagnitto,敏捷数据仓库设计:协作维度建模,从白板到星形模式(2011)

[3] Raphael Branger,BI-Excellence durch agilitt und Automatisierung(2017)

如何使用费曼技术成为数据科学中最复杂概念的专家

原文:https://towardsdatascience.com/how-to-use-the-feynman-technique-to-become-an-expert-in-the-most-complicated-concepts-in-data-cecf33d7d518?source=collection_archive---------3-----------------------

来自“伟大的解释者”的教导将帮助你掌握数据科学

莱纳斯·米米耶茨在 Unsplash 上的照片

业内人士都认同的一点是,数据科学很难学。

就像学习打高尔夫球一样,你可以每天都在数据科学高尔夫球场上学习编程、数学和行业知识,但是到你死的时候仍然没有掌握这项运动。

不仅如此,一些最复杂的数据科学概念甚至足以让我们当中的勇者回头。

幸运的是,那些在我们之前的人给我们留下了一个方法宝库,我们可以用它来处理最复杂的问题,以至于我们可以成为这些问题的专家。其中最好的方法是什么?

费曼技术。

什么是费曼技术?

费曼技术是由诺贝尔奖得主物理学家理查德·费曼开发的,他是量子计算和纳米技术领域的先驱,由于他在康乃尔和加州理工学院发表的令人难以置信的演讲,他被称为【伟大的解释者】

尽管被英国杂志 物理世界 评为有史以来十大物理学家之一,但费曼认为自己是“一个努力学习的普通人。”

使理查德·费曼成为杰出人物的是他发现自己不知道的事情,然后全身心投入去理解它们的方式。多年来,费曼提供了关于他如何打破他的领域最复杂的主题,并将其提炼为任何人都可以理解的简单知识的见解。这些见解被收集并提炼到我们现在所知的“费曼技术”中。

费曼技巧是理解任何主题的四个步骤。

费曼技术不依赖于通过死记硬背获得的基本记忆,而是倾向于通过主动学习发展对主题的真正理解。

费曼技术可以分解为四个步骤:

  1. 选择一个概念来学习。
  2. 教给自己或者别人。
  3. 找出你的知识缺口,回到原始材料。
  4. 简化你的解释。

费曼技术是如何工作的。

在学习数据科学的复杂主题时,很有可能你认为自己理解了一些东西,直到有人要求你向他们解释或者有人要求你将它应用到分析中。

费曼技巧解决了这个问题,因为当你只是一个业余爱好者时,它不会给你机会去相信你是一门学科的大师。相反,它迫使你在过程的每一步评估你的知识,找出任何知识缺口,直接接触材料来填补这些缺口,然后澄清和提炼你对知识的理解。

为什么要使用费曼技术?

费曼技术是用来学习数据科学复杂概念的完美方法,因为它迫使你面对你不知道的东西,然后引导你进入一个你对它了如指掌的领域。

学习数据科学的复杂主题是一项艰巨的任务。如果你在阅读了一篇关于你正在努力学习的主题的文章后,认为你的学习经历是完整的,这就更复杂了。记住: 读书不是理解

相反,通过使用费曼技巧,你可以确保你对一个概念的理解是牢固的。

费曼技术之所以如此有效,关键在于简化步骤。众所周知,在准备即将到来的加州理工大学本科生讲座时,费曼意识到他无法在本科生水平上解释这个话题。那一刻,费曼意识到,如果他不能向满教室的新生解释,他就没有完全理解这个话题。这让他彻底重写了这个话题,直到他简化了自己的解释,并创造了适合本科生的类比,从而让他对这个话题有了更深的理解。

使用费曼技术来学习数据科学中最复杂的概念,将会使您的主题不再可怕或复杂,因为您已经简化了对它们的理解,使它们变得清晰易懂。

如何使用费曼技术学习数据科学中最复杂的概念?

第一步:选择一个要学习的概念。

选择一个课题去研究,迫使你去面对你不知道的东西,去直面它。一旦你选择了一个主题,拿出一张白纸或打开一个新的 Word 文档。用题目的名字给它加标题。

然后,写下你想知道/需要知道的关于这个话题的一切。这可能包括理解它是如何工作的,如何将它应用于分析,以及何时应该将其应用于分析。

此时,试着写下你已经知道的关于这个话题的一切。不要在网上寻找开始。运用你自己的脑力是创造有效学习体验的关键。这也是你要尽量利用已有知识去理解新概念的点。

记下你必须用一个大而复杂的词来解释某事的任何地方,然后问自己是否理解这个词的意思。如果你有,那太好了!如果没有,分解这个词的意思,然后尝试用简单的语言来描述这个过程。

第二步:教给自己或别人。

这是关键的一步,它会告诉你对这个概念的理解程度。把它教给你自己,或者,理想情况下,教给别人,会让你很难欺骗自己相信你是这方面的专家。

把这个概念教给你自己或其他人会迫使你精炼和简化你的解释,以至于一个 10 岁的孩子也能理解。

教学还会启动一个反馈循环,在这个循环中,问题和评论会帮助你加深对主题的理解。欢迎提问,自己不知道答案就写下来。这是帮助你进一步发现知识缺口的好方法。

向自己或其他人教授这个话题的好处是它会建立你的信心。当这种情况发生时,你会更倾向于接受更难的话题,并且你会有信心在前进中应用你所学到的东西。

第三步:找出你的知识缺口,回到原始材料。

这一步是的一部分,与第二步循环重复。

通常,在你第一次尝试向自己或他人教授一个概念后,你会发现知识缺口。当这种情况发生时,你必须回到原始材料来回答问题,提炼你的理解,巩固你所学到的东西。请记住,在第一步开始的那张纸上写下你的理解,并在添加新的要点时使用简单的语言。

一旦你对这个概念有了新的或更深的理解,你可以回头再教这个概念。这个循环应该根据需要重复多次,直到你完全理解这个主题。

第四步:简化你的解释。

最后一步是简化你对概念的解释或理解,使你可以不用行话来解释。

当人们不明白自己在说什么时,通常会使用行话,要么是因为这是一种不用花太多力气就能解释一个话题的简单方法,要么是因为他们只想表现得好像他们知道自己在说什么。

正因为如此,这一步才是过程中最重要的。强迫自己用简单的语言解释这个概念并不允许你藏在华丽的词汇后面。相反,它迫使你真正地将概念分解成每个人都能理解的小块。

此外,现在是对概念进行简单类比的好时机,这在将来更容易回忆和解释。

这也是你在处理一个概念时应该简化你所写的任何代码的时候。当我们第一次理解一个新概念时,通常会编写极其复杂的代码。现在是时候编写尽可能简单、干净的代码了,这些代码易于理解,但仍能完成工作。

外卖。

学习数据科学很难。句号。

费曼技术是学习数据科学复杂主题的完美方法,因为它有利于通过主动学习来发展对主题的真正理解。这种学习方法可以确保您能够在现实生活中的数据科学工作中应用这一概念。

以下是你需要记住的费曼技巧的四个步骤:

  1. 选择一个概念来学习。
  2. 教给自己或者别人。
  3. 找出你的知识缺口,重新阅读原始材料。
  4. 简化你的解释。

如何使用 Google Places API 进行位置分析等等

原文:https://towardsdatascience.com/how-to-use-the-google-places-api-for-location-analysis-and-more-17e48f8f25b1?source=collection_archive---------0-----------------------

从谷歌地图获取任何信息的分步指南

我感兴趣的一个分析主题是位置分析,并思考如何将更多数据驱动的方法引入位置搜索,特别是对于没有塔吉特(Target)或星巴克(Starbucks)资源的较小公司。我写了几篇文章(这里这里这里)讨论我们可以采取的不同方法以及如何将它们付诸实践的例子。

作为最近一些研究的一部分,我发现自己在搜索兴趣点数据的不同选项。

在这个搜索过程中,我发现了 Google Places API。假设你想找一家附近的咖啡店。你在谷歌地图上自由搜索咖啡。几个大头针弹出与您的搜索匹配的本地结果。

当你点击其中一个时,它会显示一些关于该位置的有用信息,如谷歌评论评级、评论数量、价格类别(评论旁边的单个$号)、地址等等。

搜索北卡罗来纳州罗利市中心附近的一家咖啡店和一个输出示例;作者图片

Google Places API 在指定的参数范围内有效地执行搜索,并返回搜索中出现的每个位置的结果。这使我们能够在谷歌地图运营的任何地方(根据谷歌的说法,包括 200 多个国家和 99%的全球覆盖面)获取谷歌地图搜索中出现的任何商业类型的信息。

作为一个没有编程背景的人,我发现第一次尝试和解释如何使用 API 以及理解定价是如何工作的有点困难(它不是免费的,但他们有每月循环的积分,在你开始付费之前给你大量的访问权)。

下面,我将展示如何访问 API 以将数据用于您自己的项目和目的的简单步骤。作为一个例子,我将介绍用 Python 构建搜索 URL 的过程。

入门指南

首先要做的是注册一个谷歌云账户。注册后,除了每月 200 美元的免费积分外,您还可以获得 300 美元的积分。

一旦你创建了一个帐户,并在谷歌云平台上,你会想去使用左上方的下拉导航,并选择 API &服务>凭证。一旦到了那里,你需要点击顶部的创建凭证,然后点击 API 键。这将生成一个字母数字字符串,在您调用 API 时标识您的 Google Cloud 帐户。

如何创建 API 凭据的示例;作者图片

我们将在稍后调用 Places API 时使用该凭证,但是现在,这就是您需要做的全部工作!

如何使用 Google Places API

一旦您有了 API 证书,就可以用您选择的编程语言来完成该过程的下一部分。我使用过 Python,但是如果你是一个 R 用户,你可以很容易地用 R 代码修改这个过程的最后步骤。

虽然一开始有点吓人,但是放置了 API 文档,其中包含了使用指定参数执行 API 调用所需的所有信息。

由于我们将执行一个“不明确的文本字符串”(即不搜索特定的位置,而是搜索一般的咖啡店),我将介绍如何在 Places 文档/API 中使用文本搜索请求。

API 文档中文本搜索请求的使用示例;作者图片

为了调用 API,我们需要构造一个 URL 字符串。我们要使用的每个必需和可选参数都需要包含在字符串中。我们可以在文档的可选参数部分找到每个参数选项、它们是什么以及如何使用它们。

文本搜索 API 的可选参数示例;图片作者。

为了构造字符串,让我们一步一步来看看实际发生了什么以及如何使用它。这些参数中的大部分都是可选的,您可以根据您的使用情况进行切换,但是如何在文档中使用任何参数的本质是相同的。

[**https://maps.googleapis.com/maps/api/place/textsearch/**](https://maps.googleapis.com/maps/api/place/textsearch/)

上面连接到 Google Maps API(maps.googleapis.com/maps/api)并建立了我们想要使用的地点API(/地点)和地点 API 的文本搜索(/文本搜索)组件。

[https://maps.googleapis.com/maps/api/place/textsearch/**output_type?**](https://maps.googleapis.com/maps/api/place/textsearch/output_type?)

输出 _ 类型?定义了我们希望如何创建输出。选项是 json 或 xml,您只需替换 output_type?json 哪个?还是 xml?取决于你的选择。

[https://maps.googleapis.com/maps/api/place/textsearch/output_type?**query=your_query**](https://maps.googleapis.com/maps/api/place/textsearch/output_type?query=your_query)

查询参数定义了我们的“模糊”搜索词。我们用加号来分隔任何单词。因此,为了搜索咖啡店,我们将把 your_query 替换为 coffee+shop

[https://maps.googleapis.com/maps/api/place/textsearch/output_type?query=your_query**&location=latitude,longitude**](https://maps.googleapis.com/maps/api/place/textsearch/output_type?query=your_query&location=latitude,longitude)

我们用&符号分隔参数。我们可以通过提供纬度和经度坐标来定义我们想要的位置。这将是搜索的中心点。你也可以在搜索词中输入一个地点,跳过纬度/经度,比如“咖啡+商店+罗利+北卡罗来纳州”。

[https://maps.googleapis.com/maps/api/place/textsearch/output_type?query=your_query&location=latitude,longitude**&radius=number_of_meters**](https://maps.googleapis.com/maps/api/place/textsearch/output_type?query=your_query&location=latitude,longitude&radius=number_of_meters)

半径参数定义了搜索的范围。要在经纬度坐标 1000 米范围内搜索,我们可以用 1000 代替米数(字符串中不要用逗号)。更大的半径将覆盖更广的区域。也就是说,它也容易受到丢失位置的影响。

想想当你缩小谷歌地图搜索时,你会得到更大范围的位置,但实际弹出的并不多。看看下面的图片——在右边,我们有一个更大的搜索缩放半径。我们得到了更多的结果,但是左边图像中的一些没有显示出来,尽管它们仍然在搜索区域中。测试几个不同的半径,看看什么最适合您的用例。半径越小,结果越准确,但是运行时间越长,调用 API 的次数越多,成本也越高。

请注意,右侧有更多的位置,但不包括左侧的所有结果。在半径参数和我们是否能够捕获某个地理区域的所有相关结果之间存在权衡。图片作者。

[https://maps.googleapis.com/maps/api/place/textsearch/output_type?query=your_query&location=latitude,longitude&radius=number_of_meters&**region=region_code**](https://maps.googleapis.com/maps/api/place/textsearch/output_type?query=your_query&location=latitude,longitude&radius=number_of_meters&region=region_code&)

区域代码是您要搜索的国家的 2 位数代码。例如,与一家英国公司合作,我使用代码英国,而在美国,我们可以使用区域代码美国

[https://maps.googleapis.com/maps/api/place/textsearch/output_type?query=your_query&location=latitude,longitude&radius=number_of_meters&region=region_code&**type=establishment_type**](https://maps.googleapis.com/maps/api/place/textsearch/output_type?query=your_query&location=latitude,longitude&radius=number_of_meters&region=region_code&type=establishment_type&)

type 参数允许我们指定 Google 数据中标记的机构类型。对于咖啡店,我们可以提供 bakery 和 café作为类型,以确保我们不会得到不相关的结果。类型的完整列表可以在这里找到。我们用逗号分隔类型,不加空格。对于面包店和咖啡馆,类型参数将是面包店,咖啡馆

[https://maps.googleapis.com/maps/api/place/textsearch/output_type?query=your_query&location=latitude,longitude&radius=number_of_meters&region=region_code&type=establishment_type&**key=YOUR_API_KEY**](https://maps.googleapis.com/maps/api/place/textsearch/output_type?query=your_query&location=latitude,longitude&radius=number_of_meters&region=region_code&type=establishment_type&key=YOUR_API_KEY)

最后但同样重要的是输入 API 密钥。使用之前在该参数中创建的 API 键。

把所有这些放在一起,你就会得到这个项目所用的类似这样的东西:

"https://maps.googleapis.com/maps/api/place/textsearch/json?query=coffee+shop&location=35.792491,-78.653009&radius=2000&region=us&type=cafe,bakery&key=MY_API_KEY"

其中许多是可选参数,可能与您的使用相关,也可能不相关,但是 API 的本质是选择您的相关参数,输入所需的值,并用&符号分隔您的参数。所有必需和可选参数可在文档页面的文本搜索标题下找到。

从 API 收集数据

一旦我们构建了我们的 URL 字符串,我们就使用基本编码和 web 抓取的组合来访问和解析信息。下面是我如何接近它,但可能有更有效的方法拉它。您将需要请求、json 和时间包。

在下面的代码中,我首先建立一个空列表来放置结果和一个空字典用于将来的参数,然后建立我们刚刚创建的 URL 作为它自己的变量。

我使用 requests.get 发送一个 URL 请求,然后,因为我使用了一个 json 输出,所以在结果上使用 json.loads 将 URL 输出转换成一个可用的 json 输出。我将结果添加到我创建的空列表中,然后在使用 time.sleep(2) 进行下一个调用之前暂停一下。

对 API 的每次调用每页最多返回 20 个结果,总共 3 页,总共 60 个结果。time.sleep 参数是必需的,因为如果您尝试一次不间断地发送所有请求,API 将不会返回结果

import requests
import json
import time

endpoint_url = "https://maps.googleapis.com/maps/api/place/textsearch/json?query=coffee+shop&location=35.7790905,-78.642413&radius=2000&region=us&type=cafe,bakery&key=MY_API_KEY"

res = requests.get(endpoint_url, params = params)
results =  json.loads(res.content)

输出是一个字典列表,其中每个字典包含一家咖啡店的信息。

如果您使用 R 或另一种编程语言,您将创建相同的 URL 字符串,然后调整代码来执行 URL 请求,设置与列表相反的空向量,等等。

定价和成本

Places API 是 Google Maps API 中比较贵的一个,但是在你不得不自掏腰包之前,有足够的工作可以做。当我注册时,有 300 美元的信用额度,必须在 3 个月内使用。谷歌还提供每月 200 美元的免费信用点数。这不会延续下去,所以你每个月有 200 美元可以使用,然后重置。

API 的大致经验是,每 1000 个 API 请求将花费大约 40 美元。请记住,每个请求最多可以获得 20 个位置,因此您可以花费 40 美元获得 20,000 个位置。每月 200 美元的信用,这相当于在你开始付费之前有大约 5000 个免费请求。

完整的定价细节可在此处获得,但以下是文本搜索 API 的示例。我们无法控制返回哪些数据点;每个 API 调用都会返回地点、基本数据、联系人数据和氛围数据。

关于定价的最后一个注意事项是,我起初不明白的是,每次你提交一个 URL 字符串来拉取信息,它总共可以达到 3 个请求。我在上面提到过,每个 URL 调用在 3 个页面上提供多达 20 个结果。访问每一个额外的页面都是对 API 的新请求。因此,获得所有 60 个结果将被认为是对 API 的总共 3 个请求。

赞成、反对和结论

通过理解如何访问和使用来自该 API 的数据,我对所释放的可能性感到兴奋。

该 API 的优点是高数据可用性和跨类别和位置的全面覆盖,但缺点主要是许可限制,您必须在使用前仔细阅读这些限制,以确保数据使用方式的合规性。

有兴趣了解更多信息或建立联系吗?通过 LinkedIn 或电子邮件在 jordan@jordanbean.com 联系我

如何在 Python 中使用多重处理包

原文:https://towardsdatascience.com/how-to-use-the-multiprocessing-package-in-python3-a1c808415ec2?source=collection_archive---------0-----------------------

用不到 6 分钟的时间了解多重处理

朱莉安娜·罗蒙Unsplash 上拍摄的照片

当一个长时间运行的进程必须加速或者多个进程必须并行执行时,多重处理是最重要的。在单核上执行一个进程会限制它的能力,否则它会将触角伸向多个内核。如果耗时的任务有并行运行的范围,并且底层系统有多个处理器/内核,Python 提供了一个易于使用的接口来嵌入多处理。

本文将区分多处理和线程,引导您了解用于实现多处理的两种技术——进程和池,并探索进程的交互和共享内存的概念。

多重处理与多线程

多重处理利用全部 CPU 内核(多个进程),而多线程将多个线程映射到每个进程。在多重处理中,每个进程都与自己的内存相关联,这不会导致数据损坏或死锁。线程利用共享内存,因此加强了线程锁定机制。对于与 CPU 相关的任务,多处理是更好的选择,然而,对于与 I/O 相关的任务( IO 绑定与 CPU 绑定的任务),多线程执行得更好。

在 Python 中,全局解释器锁(GIL)是一种只允许单线程控制 Python 解释器的锁。在多线程的情况下,它主要用于 IO 绑定的作业,GIL 没有太大的影响,因为锁是在线程之间共享的,而它们正在等待 I/O

另一方面,多处理为每个进程分配一个 Python 解释器和 GIL。

在下一节中,让我们看看多处理包的一个重要概念——Process 类。

使用过程

多处理中的Process类一次性分配内存中的所有任务。使用Process类创建的每个任务都必须分配一个单独的内存。

设想一个场景,其中要创建十个并行进程,每个进程都必须是一个单独的系统进程。

下面是一个例子(输出的顺序是不确定的):

https://replit.com/@allasamhita/Process-Class?lite=true

Process类为从 0 到 10 的数字启动了一个进程。target指定要调用的函数,args确定要传递的参数。start()方法开始流程。所有的进程都循环等待,直到每个进程执行完毕,这是使用join()方法检测到的。join()有助于确保程序的其余部分仅在多重处理完成后运行。

***sleep()*** 方法有助于理解进程的并发程度!

在下一节中,让我们看看各种进程通信技术。

如何实现管道

如果两个进程需要通信,管道是最好的选择。一个管道可以有两个端点,每个端点都有send()recv()方法。如果两个进程(线程)同时读取或写入同一个端点,管道中的数据可能会损坏。

cube_sendercube_receiver是使用管道相互通信的两个进程。

  • 数字 19 的立方从管道的一端送到另一端(x_conny_conn)。x_conn是流程p1的输入。当在x_conn上调用send()时,输出被发送到y_conn
  • y_conn是流程p2的输入,该流程接收输出并打印结果立方体。

如何实现队列

要在共享通信通道中存储多个进程的输出,可以使用队列。例如,假设任务是找出前十个自然数的立方,然后给每个数加 1。

定义两个功能sum()cube()。然后定义一个队列(q),调用cube()函数,然后调用add()函数。

https://replit.com/@allasamhita/Queue-Communication?lite=true

代码解释了两个进程之间对象的通信,在我们的例子中是q。方法empty()是确定队列是否为空,get()返回存储在队列中的值。

结果的顺序是不确定的。

如何实现共享内存

受队列的启发,共享内存无缝地存储进程间的共享数据。它可以有两种类型:数组

价值

单个值可以在多个流程之间共享,如下所示:

https://replit.com/@allasamhita/Shared-Memory-Value?lite=true

数字 19 作为参数传递给函数cube()value属性取Valuenum的实际值。修改后的数字随后被发送到cube()功能。最终的双立方数反映在打印语句中。

排列

值列表可以在多个流程之间共享,如下所示:

https://replit.com/@allasamhita/Shared-Memory-Array?lite=true

Array()初始化拥有长度为 3 的int数据类型的空数组。通过给数组中的每个元素加 1 来循环数组。

你可以在不同的过程中使用arr,就像一样。这本质上就是共享内存的概念。

:‘d’表示双精度浮点数,‘I’(在数组中(" I ",3))表示有符号整数。

如何实现服务器进程

服务器进程是在 Python 程序开始时触发的主进程。其他进程可以利用它的对象进行操作。类别Manager()的管理器对象控制服务器进程。Manager() 支持多种数据类型,如 list、dict、Lock、RLock、Semaphore、BoundedSemaphore、Namespace、Condition、Event、Queue、Value、Array

为了更好地理解这个概念,请看这个例子:

https://replit.com/@allasamhita/Server-Process?lite=true

这里使用 manager 对象初始化和操作字典和列表类型。

共享内存与服务器进程:

  1. Manager()与共享内存相比,支持多种数据类型
  2. 通过网络,不同计算机上的进程可以共享一个管理器
  3. 服务器进程比共享内存慢

使用游泳池

多重处理中的Pool类可以处理大量的进程。它允许您在每个进程中运行多个作业(因为它能够对作业进行排队)。内存只分配给正在执行的进程,不像Process类,它把内存分配给所有的进程。Pool类获取存在于池中的工作进程的数量,并生成进程。

使用Process类启动许多进程实际上是不可行的,因为它可能会破坏操作系统。因此,出现了一个池,它将在存在最少数量的工作进程的情况下,处理向所有产生的进程分配作业和从所有产生的进程收集结果(最优选地,工作进程的数量等于 CPU 核心的数量)。

*Pool* 在交互式解释器和 Python 类中不起作用。它要求 main 模块可由子模块导入。

Pool类自带六个有价值的方法:

apply()方法阻塞主进程,直到所有进程完成。它接受多个参数,保持结果的顺序,并且 不是并发的

https://replit.com/@allasamhita/Pool-apply?lite=true

如果要计算前十个自然数的立方,必须循环这些数字,一次发送一个给apply()方法。这里的进程数设置为 4;然而,cube()只在一个池工作线程中执行。

close()方法终止池,join()等待工作进程终止。

地图

map()方法支持 并发不接受多个参数,阻塞主程序,直到所有进程完成。它还保持结果的顺序或(尽管计算顺序可能不同!).

https://replit.com/@allasamhita/Pool-map?lite=true

apply()不同,map()接受迭代器作为参数传递给函数cube()

应用 _ 异步

apply_async()中的回调函数可用于在其执行完成后立即返回值。这个方法维护结果的顺序,而支持并发

https://replit.com/@allasamhita/Pool-applyasync?lite=true

注意:您可以使用wait()来阻止异步调用。

map_async

map()不同,map_async()非阻塞(并维持结果的顺序)

https://replit.com/@allasamhita/Pool-mapasync?lite=true

map_async()运行时,“这里”和“再次这里”被写入控制台,展示了它的非阻塞特性。但是,您可以使用wait()来阻止异步调用。

星图

与 map()不同,starmap()接受多个参数。它维持结果的顺序,是并发的,阻塞主进程

https://replit.com/@allasamhita/Pool-starmap?lite=true

星图 _ 异步

starmap()不同,starmap_async()非阻塞的(并且维持结果的顺序)

https://replit.com/@allasamhita/Pool-starmapasync?lite=true

交互邮件访问协议

map()不同的是,imap()不会等待所有的结果,而是返回一个迭代器(不是一个列表)。

https://replit.com/@allasamhita/Pool-imap?lite=true

imap_unordered

imap()不同,结果的顺序并不总是保持

https://replit.com/@allasamhita/Pool-imapunordered?lite=true

结论

在本教程中,您学习了如何使用 Python 中的多重处理实用程序。您学习了进程的不同之处,并且您创建了一个cube()函数来理解所有的概念。您了解了进程通信、共享内存、服务器进程以及同步和异步池。

我希望你喜欢阅读这篇文章。

参考:【https://docs.python.org/3/library/multiprocessing.html】T42

如何使用渐进超负荷方法在 6 周内大幅提高您的数据科学技能

原文:https://towardsdatascience.com/how-to-use-the-progressive-overload-method-to-aggressively-improve-your-data-science-skills-in-6-da7e932de68e?source=collection_archive---------34-----------------------

这个值得信赖的负重训练原则也可以用来有效地训练你的大脑

Unsplash 上的 Karsten Winegeart 拍摄

数据科学家可以从举重运动员身上学到很多东西。

当然,远离电脑,过上健康的生活是一件很重要的事情,但是从这个不太可能的信息来源中也可以获得一些更重要的东西。

举重运动员可以教数据科学家如何学习。

通过借鉴举重运动员的训练计划,数据科学家可以使用这种值得信赖的训练方法,在 6 周内有效并持续地提高他们的技能。

什么是渐进过载法?

渐进超负荷是一种屡试不爽的重量训练方法,用于在预定的训练时段内持续增加力量。目标是在日常训练中增加重量、频率或重复次数。这个过程会让你的身体不断变得强壮,并避免在某个强度上停滞不前的风险。

渐进超负荷法是由生活在公元前 6 世纪的六届奥运会冠军——巴豆的米洛(Milo of Croton)首先发明的。米洛成为冠军是因为他每天用肩膀扛着一头小牛,直到小牛长成公牛。随着小牛越长越大,米洛的力气也越来越大。

渐进超负荷疗法也在现代史上留下了印记,当时一位名叫托马斯·l·德洛姆的美国军医开始用它来恢复受伤士兵的健康。在第二次世界大战期间,遭受骨科创伤的士兵人数超过了医院能够使他们康复的速度。看到这个问题的第一手资料,德洛恩博士开始使用渐进超负荷格式的力量训练,以快速加强和恢复士兵。因此,渐进超负荷的现代概念诞生了,现在已经成为任何寻求持续有效提高技能的人的普遍做法。

当谈到提高你的数据科学技能时,渐进式超载可以以与力量训练相同的方式使用。通过逐步增加所学或应用的概念的难度、规模或范围,您对数据科学概念的了解将随着时间的推移而有规律地增加和提高。

谁应该使用渐进过载方法?

在使用渐进重载方法研究数据科学时,有一点需要注意。

渐进过载方法最适合已经具备数据科学基础的人使用。为什么?因为如果你不能成功地执行基本动作,渐进式超载对你不起作用。

让我们从举重的角度来看这个问题。如果一个人没有先学会安全举起一个重量所需的正确形式,那么开始一个渐进的超负荷计划是很危险的。他们可能会受伤,因为他们不知道如何举重,然而杠铃的重量却在不断增加。

同样的原则也适用于使用渐进式超载方法来提高您的数据科学技能。虽然你的健康和安全不会受到威胁,但你发展和应用新技能的能力会受到威胁。例如,如果你要开发一个渐进超负荷程序,在这个程序中,你要对一个月内逐渐增大的数据集进行数据分析,但你甚至不知道如何进行数据分析,你就不知道从哪里开始,整个过程就是浪费时间。

因此,强烈建议您在开发渐进式超负荷学习计划之前,首先在数据科学的绝对基础方面打下坚实的基础。绝对初学者最适合使用微学习超学习20 小时法则来学习数据科学的基础知识。

渐进式过载方法对数据科学学习体验有何益处?

渐进式超载方法通过提供一个明确的框架来确保技能的持续提高,从而有利于数据科学学习体验。

对于未来和当前的数据科学家来说,关键是确保他们不断提升技能,以保持在行业中的相关性。通过制定计划来不断提高这些技能,数据科学家可以对自己为工作带来积极影响的能力保持信心。

通过不断地计划更难掌握的概念、要完成的分析或要学习的技能,你可以确保你在鞭策自己,这样你的技能就会随着你训练计划的继续而提高。关键是要设计一个合适的培训计划,缓慢但肯定地引入新的或更困难的话题。

如何使用渐进式过载方法来提高您的数据科学技能。

渐进超负荷训练成功的关键在于准备。通过提前准备你的“训练计划”,你可以确信在你的“训练分割”结束时,你已经显著地提高了你的技能。

如何规划您的数据科学渐进超负荷培训计划:

  1. 留出几个小时的专用时间来计划你的训练计划:最好的运动员花时间与他们的教练一起准备完美的训练计划,这将产生更好的结果。关键是要留出几个小时来决定你想学什么,以及你打算如何设计你的培训计划。
  2. 决定你想学习哪种技能/概念,并确定你的最终目标:决定你想学习哪种技能将为你的培训计划定下基调,确定你的最终目标将设定你希望在计划结束时看到的改进速度。例如,假设您想学习如何完成一个数据分析,您的最终目标是完成一个包含 500 个条目的数据集的分析。创建这个大纲有助于你确定你需要从哪里开始,以及你想从哪里结束。
  3. 为你的训练计划设定一个时间表:我最喜欢的渐进超负荷训练拆分为 6 周。为什么?因为在 6 周的时间里,你给自己三个两周增量的部分,你可以专注于不同的方面,这将帮助你达到最终目标。此外,6 周通常是你开始看到结果的时间框架。真的,你可以选择任何你想要的时间尺度。然而,6 周提供了一个完美的平衡,既给自己足够的时间舒适地完成目标,又足够短,让你不断地鞭策自己。
  4. 确定你希望在你所选技能的某个特定方面专注多少周:在你培训计划的时间范围内,有几周时间可以用来学习或完善你所选技能的较小方面。例如,如果我的目标是完成对具有 500 个条目的数据集的分析,我的前两周(6 周训练计划)可能会花在完成对具有 100 个条目的数据集的分析上,接下来的两周会花在完成对具有 300 个条目的数据集的分析上,最后两周会花在完成对具有 500 个条目的数据集的分析上。诀窍是计划好你的周数,这样会有持续的进步。这里需要注意的是,你不需要以两周为增量来工作,你可以选择最适合你的增量。
  5. 确保你的计划让你每周都能提高技能:渐进式超负荷的问题在于,要想让它发挥作用,你需要能够确定自己是否在进步。当谈到举重时,这很容易,因为你可以走到深蹲架前,试着深蹲一个比你之前举起的重量更重的重量。对于数据科学,能力测试可能是确保持续改进的最佳方式。通过每周测试你自己,你可以确保你的程序持续提高你的技能。
  6. 别忘了休息:在持续进步的过程中很容易陷入困境,但如果举重运动员能教会我们一件事,那就是休息和工作一样重要。不要忘记在你的“训练课”之间休息几天。这种休息可以让你的大脑恢复活力,并可能保留比你想象中更多的东西。
  7. 衡量你的进步:一旦你的训练计划结束,是时候衡量你的进步了。现在是检验你一直努力获得的技能的时候了。如果你成功了,你的计划就成功了!如果没有,是时候重新开始了。举重和数据科学的进步都不是线性的,所以在项目结束时没有达到目标是完全正常的。相反,花点时间反思一下什么可行,什么不可行。从那里,你可以开始填补你的知识空白,并设计一个新的训练计划,这将有助于你达到你的目标。

最后的想法。

关键要点:

  • 渐进式超负荷是一种流行的重量训练方法,可以追溯到公元前 6 世纪。这种方法背后的想法是,随着持续更困难的训练,你的技能将随着时间的推移而提高。
  • 渐进式超载可用于提高和学习数据科学概念,方法是从基础开始,不断提高难度,直到实现目标。
  • 你的渐进超负荷训练计划应该有明确的难度增加,这将拓展你作为数据科学家的能力。正如他们所说:没有付出就没有收获。
  • 举重和数据科学的进步都不是线性的,所以有可能在你的训练计划结束时,你还没有完全实现你的目标。这是完全正常的,这让你可以重新开始尝试新的训练计划。不管怎样,在你花时间训练的过程中,你仍然会提高你的技能。

当谈到学习或提高数据科学技能时,有时从其他地方寻找学习方法的典型资源是值得的。通过渐进式超负荷训练,你可以将常规训练与创造自己的训练计划的能力完美结合,并取得切实的成果。

通过探索不同的学习方法,你将有最好的机会在一个众所周知的困难领域提高和发展你的技能。

如何使用 SQL GROUP BY 子句和聚合函数

原文:https://towardsdatascience.com/how-to-use-the-sql-group-by-clause-and-aggregate-functions-cbaef410be91?source=collection_archive---------3-----------------------

让它回到基础

照片由杜凡Unsplash 上拍摄

请务必 订阅此处 千万不要错过另一篇关于数据科学指南、诀窍和技巧、生活经验等的文章!

在本文中,我们将重点关注 SQL 的基础知识,尤其是聚合函数。

SQL 中的聚合函数是什么?

聚合函数是对一个或多个值执行并返回单个值的函数。当聚合函数与 GROUP BY 子句一起使用时,它可以返回一个或多个值。通过本文中的几个例子,您将对此有更好的理解。

对于 SQL 编码来说,有五种主要类型的聚合函数是必不可少的:

  1. 计数()
  2. COUNTIF()
  3. 最小值()/最大值()
  4. 总和()
  5. AVG()

对于这篇文章,我们将继续讨论我们想象中的公司 Sandy Shores(如果你参加了我们关于运营分析各个阶段的网络研讨会,你一定很了解这家公司),它出租沙滩椅。

说了这么多,让我们开始吧!

1.计数()

COUNT 返回一列中的行数,不包括空值。如果只想计算一列中值的不同数目,可以使用 COUNT(DISTINCT)。

让我们看看 Sandy Shores 如何使用这些功能。假设 Sandy Shores 有一个名为 transactions 的表,它跟踪椅子租赁的交易。

  • 日期代表交易的日期
  • customer_id 代表每个不同客户的唯一 id
  • 如果客户使用了折扣,则为真,否则为假
  • 椅子代表租赁的椅子数量
  • 金额代表交易的总金额

假设 Sandy 想要获得从 7 月 1 日到 7 月 8 日的交易总数。她可以运行以下查询:

SELECT COUNT(customer_id) FROM transactions

这将返回等于 8 的行数。

简单吧?如果 Sandy 想要获得独立客户的总数,该怎么办?

SELECT COUNT(DISTINCT customer_id) FROM transactions

这将返回 7,因为 id 为 894458 的客户进行了两次交易,一次在 4 号,一次在 8 号。

我们可以用下面的函数进一步扩展 COUNT:

务必 订阅此处 千万不要错过另一篇关于数据科学指南、诀窍和技巧、生活经验等的文章!

2.COUNTIF()

COUNTIF 是 COUNT 的扩展,它返回满足条件的行数。

让我们回到我们的表,事务。假设 Sandy 想要计算使用折扣的交易数量和不使用折扣的交易数量。这是使用 COUNTIF 函数的最佳时机:

SELECT COUNTIF(discount_used = TRUE) as num_discount
     , COUNTIF(discoun_used = FALSE) as num_normal
FROM transactions

这将返回以下输出:

现在您已经知道如何使用 COUNT 和 COUNTIF,让我们深入研究一个相似但不同的函数:

3.总和()

SUM 返回非空值的总和,换句话说,它将一列中的所有值相加。不要把这个和计数混淆了。COUNT 返回一列中的行数,而 SUM 将一列中的所有值相加。

使用 SUM 时,您应该了解以下几种特殊情况:

  • 如果列只有空值,SUM()返回 NULL
  • 如果列没有行,SUM()返回 NULL
  • 如果列包含 Inf/-Inf,SUM()返回 Inf/-Inf
  • 如果列包含 NaN,SUM()返回 NaN
  • 如果列有 Inf 和-Inf 的组合,SUM()返回 NaN

当你想知道任何事物的总数时,SUM()是非常有价值的。让我们看看 Sandy Shores 如何使用 SUM()来更好地了解她的业务。

假设桑迪想得到她从 7 月 1 日到 7 月 8 日的总收入。她可以简单地运行以下查询:

SELECT SUM(amount)
FROM transactions

这将总共返回 149 美元。如果她想在有折扣和没有折扣的情况下合计总金额,该怎么办?

SELECT discount_used, SUM(amount) as total_amount
FROM transactions
GROUP BY discount_used

这将返回以下内容:

如果我们把这两个数字加起来,也是 149 美元!太棒了!

4.AVG()

AVG 只返回非空值列的平均值。从数学上来说,AVG 对给定列的值求和,然后除以相应的行数。

AVG 计算了一个叫做平均值的集中趋势。当您想知道特定指标的平均表现时,这是非常有用的。例如,在商业环境中,您可能希望了解以下信息:

  • 你想知道每笔交易的平均 T21 金额是否随着时间的推移而增长
  • 您希望了解呼叫中心的平均响应时间是否在减少
  • 你想知道生产的平均错误率是否在下降

让我们看看桑迪·肖尔斯如何利用 AVG 来推动她的商业决策。

假设 Sandy 想要获得每笔交易的平均椅子数量,以及每笔交易的平均金额。她可以运行以下查询:

SELECT AVG(chairs) as avg_chairs
     , AVG(amount) as avg_amount
FROM transactions

这太棒了。但是为了进一步扩展这个分析,让我们来看看我们可以在 AVG 中使用的另外两个函数:

务必 订阅此处 千万不要错过另一篇关于数据科学指南、诀窍和技巧、生活经验等的文章!

5.最小值()/最大值()

MIN 和 MAX 只是分别返回列的最小值和最大值。

我们之前讨论了 AVG 以及它如何提供给定列的中心趋势。MIN 和 MAX 是补充 AVG 的非常有用的函数,因为它们提供了给定列的范围,允许您理解方差和均值。

现在,让我们获取椅子和数量的最小值和最大值,这样,除了她已经计算出的平均值之外,Sandy 还可以得到每个值的范围:

SELECT MIN(chairs) as min_chairs
     , MAX(chairs) as max_chairs
     , MIN(amount) as min_amount
     , MAX(amount) as max_amount
FROM transactions

这将导致以下结果:

现在,Sandy 知道她预计每位顾客平均会有 2 把椅子,最少 1 把,最多 4 把。同样,她可以期望平均金额为 18.63 美元,最少 10 美元,最多 40 美元。

感谢阅读!

一定要 订阅这里 千万不要错过另一篇关于数据科学的指南、诀窍和技巧、生活经验等文章!

不确定接下来要读什么?我为你挑选了另一篇文章:

</22-new-data-science-interview-questions-for-2022-964c687f735b>

还有一个:

-特伦斯·申

如何使用 STAPLE 算法合并多个图像分割

原文:https://towardsdatascience.com/how-to-use-the-staple-algorithm-to-combine-multiple-image-segmentations-ce91ebeb451e?source=collection_archive---------15-----------------------

此代码示例显示了如何对医学图像数据集使用 STAPLE 算法

例如,Lutz(公共领域)

医学图像包含丰富的信息,有助于我们了解患者的健康状况。为了解开这些信息,第一步通常是分割,或者追踪重要结构。

分割是医学图像分析中最重要的步骤,但却经常被忽视。有关分割过程的更多信息,请查看我的胰腺分割简介

定义地面真相

医学成像和数据科学领域的研究人员面临的最大挑战之一是,我们如何定义什么是“真正的”分割?

从表面上看,这似乎是一个简单的问题。我们要求房间里最聪明的人(通常是放射科医生)尽最大努力分割胰腺,这是我们的基本原则,对吗?

这种方法有几个问题。首先,医生非常忙。让一名放射科专家完成几百次(甚至几十次)扫描是一项艰巨的任务。其次,如果同一个项目有多个放射科医生,我们怎么说哪个是最“专家”的呢?一名放射科专家在结束一天的工作时真的比一名拿着一壶咖啡的医科学生更准确吗?

顺便说一下,这是人工智能(AI)可以改善放射学的方法之一。研究表明,虽然人工智能模型可能不总是比人类专家更准确,但在大多数情况下,它们更精确,这意味着人工智能每次都会给出相同的预测,而人类专家往往会在他们为一个项目投入的时间和精力上有所不同。

要是有一种民主的方式来创造我们的基本事实分割就好了。如果多个示踪剂分割相同的扫描,可能会有个人之间的小错误或差异,但这些错误平均起来会成为比任何单个人的工作更好的决定。

输入 STAPLE 算法,这是我最喜欢的算法之一,也可能是医学成像领域中最有用的代码。

在这篇文章中,我将简要描述 STAPLE,并展示一个如何在 Python 中使用它的例子。

装订算法

STAPLE 代表“同步事实和性能水平评估”,由 Warwick 等人于 2004 年出版。STAPLE 因其完善的理论和易用性而在医学成像领域被广泛接受。

让我们以我们的 CT 胰腺分割任务为例。提醒一下,这是通过癌症成像档案馆公开的数据集。假设我们有一个腹部 CT 扫描,其中胰腺被三位不同的放射科医生分割了三次。胰腺的每个像素都被标记为“1”(胰腺)或“0”(无胰腺)。图 1 显示了一个放射科医师的分割示例。

图一。三位放射科医生在腹部 CT 中对胰腺进行分割的示例。蓝色标记为“1”(“胰腺”)。背景(透明)标记为“0”。图片作者。

乍一看,所有三个细分可能看起来差不多。但是如果你仔细观察,就会发现它们是不同的。左下的放射科医师有点渴望在整个腹部上绘画(甚至在黑色脂肪组织上绘画),而右下的放射科医师可能缺少胰腺体的一部分。STAPLE 将帮助我们将这些合并成一个跟踪。

装订工作原理

STAPLE 是一种加权投票算法。作为第一步,该算法将通过对每个像素的简单投票,将所有三个组合成一个测试分割。STAPLE 将对 3 名放射科医生的准确性进行评级,并与初始测试分段进行比较。然后,它将根据 3 名放射科医生的准确性对他们的投票进行加权,从而重新绘制新的第二次测试分割。如果发现放射科医师 3 的准确率为 90%,而放射科医师 1 和 2 的准确率仅为 30%和 40%,则放射科医师 3 的权重将远远高于其他人。

订书钉是一个迭代的过程;这个估计准确度和重新绘制测试分段的循环将会重复,直到测试分段收敛(停止变化)。STAPLE 保证在合理的时间长度内收敛,通常运行不超过几秒钟。STAPLE 将返回这个最终的测试分段作为“基础事实”。

这些权重是在每个图像的基础上重新计算的。因此,举例来说,如果一个放射科医师倾向于更准确,但碰巧有一个糟糕的病例,该病例不一定会基于先前的准确性被评级为更高。

正如你所料,越多的评分者被用来投票,STAPLE 就变得越准确。在 10 个或 12 个评价者的情况下,钉书钉产生的分割可以被认为是独立于个人贡献的,这使得它成为估计任何给定评价者的准确性的伟大工具。

STAPLE 适用于两个评定者,但我建议你至少使用三个,因为两个评定者不足以评估评定者的准确性,而准确性是使用 STAPLE 的核心优势。

算法的缺点

STAPLE 是一个优秀的算法,也是该领域的黄金标准,但也有一些局限性。首先,因为 STAPLE 依赖于多数投票,它可能会倾向于低估你试图追踪的结构的边缘。这可能会夸大“假阳性”率的示踪剂相比,主食结合地面真相。

其次,STAPLE 是一种简单的投票算法,它没有考虑图像的语义或潜在属性。如果多个示踪剂标记了某个东西,它将在最终版本中显示出来,而不管实际的解剖。当多个追踪器发现随机变化或错误时,这可能会导致小的像素错误(相信我,这种情况会发生)。

当使用 STAPLE 进行多标记分割时,这些问题往往是一致的。在我同事的一个标记大脑解剖的出版物中,STAPLE 倾向于在相邻结构之间留下小间隙,没有考虑到大脑是连续的这一事实。这导致了订书钉分割,虽然在技术上是准确的,但看起来与用于生成它的分割非常不同。

因此,对你的基本事实进行一些后处理可能是合适的。例如,您可以选择只保留给定类的最大的单个结构,排除小的像素错误。或者,您可以选择定义一个“背景”类来填补任何空白。例如,在腹部器官分割中,我们将“脂肪”定义为背景,因此器官中的任何间隙都将被填充(这通常与实际情况非常接近)。

只是一定要在你的期末论文中报告这样的后处理步骤,这样其他人就可以从你的共享知识中学习了!

使用装订的例子

在 Python 中,STAPLE 可以通过 SimpleITK 获得。下面的代码片段说明了如何使用 STAPLE 来组合三个分段。我用的是 SimpleITK 版本 2.1.0 和 Python 3.7.8。

例 1。使用 STAPLE 将三个分段合并成一个单一的基本事实

在我们继续之前,对这个简单的 ITK 实现做一些快速的注释,它可能很挑剔。

  1. SimpleITK 要求输入数组是整数,可以是 int16、int32 或 int64。这些数组必须都转换为相同的类型
  2. STAPLE 一次只能在一个类上运行。类别标签被定义为“前景值”(第二个运算符),所有其他像素被视为背景。
  3. 对于多类分段,您必须对每个类单独运行 STAPLE,然后将它们重新组合成一个数组,这是包的一个限制。

现在我们已经生成了我们的主要部分,我们可以使用 matplotlib 与我们的三位评分者并排绘制它:

例 2。使用 matplotlib 绘制我们的主食分割

图二。使用 STAPLE 将 3 个胰腺分段合并为一个单一的基本事实的示例(最左侧)。作者图片

如果你眯着眼睛,你可以分辨出我们的示踪剂和主要的地面事实之间的差异,但是很难看到。让我们强调一下每个评分者和订书钉之间的区别:

例 3。绘制每位评定者与主要评定者之间的差异

图 3。每个评分者和订书钉之间的重叠(真阳性)以红色显示。差异用浅蓝色表示。作者图片

在这里,差异非常明显。在胰腺的边缘有一点变化,但最大的不同是 STAPLE 能够纠正评分员 2 在分割胰腺体时犯的一个错误。

总结

在本教程中,我介绍了 STAPLE 算法,并展示了如何将来自多个跟踪器的简单分段组合成一个单一的基本事实。

本教程展示了一个简单的例子,但是 STAPLE 也适用于大型任务。在一个项目中,我们在一个由 35 个器官组成的数据集上使用了它,涉及 17 个评分者。除了评分者之间的可靠性,这也是我结合集合预测的首选方法,我用它结合了多达 10 个模型的输出。

希望这篇文章有所帮助!如有问题,欢迎评论,我会尽力解答。

其他链接

https://nipy.org/nibabel/】T4—链接到 Nibabel 包,用于读/写 NIFTI 文件

https://simpleitk.org/—链接到 STAPLE 的 SimpleITK 实现

Pypi.org/project/staple——我在研究本文时发现的另一个 STAPLE 实现

关于使用 SimpleITK 进行分段的更深入的教程—

链接到我其他一些关于医学成像的文章—

如何使用这 6 个不寻常的 SQL 函数

原文:https://towardsdatascience.com/how-to-use-these-6-unusual-sql-functions-b912e454afb0?source=collection_archive---------19-----------------------

把这些放在你的工具箱里,你会准备好解决最困难的问题

照片由 Joni LudlowUnsplash 上拍摄

无论您是数据分析师、数据工程师还是分析工程师,您都需要了解您的 SQL。在数据世界中,这是一门必须掌握的语言。我们一直在使用它!

作为一名分析工程师,我经常为我的 dbt 数据模型编写 SQL。我一直在努力扩大我所知道的函数的数量,并改进我如何使用我已经知道的函数。

这里有一些不同寻常但很有帮助的 SQL 函数,可以帮助你了解你是一个 SQL 忍者还是仅仅在学习这门语言。

符号()

SIGN()函数根据给定的列是正数还是负数返回值。如果一个数字是> 0,则返回 1。如果一个数字是< 0,则返回-1。如果数字= 0,则返回 0。此函数仅适用于数字数据类型的列。

这个函数对于在CASE语句和WHERE子句中使用很有帮助。这使得按符号筛选列变得更加容易。

假设我们是一家银行,我们需要查看客户的月结单。我们希望标记所有帐户中有 0 美元或负金额的客户。

我们可以这样做:

SELECT
   customer_name,
   amount
FROM bank_statements 
WHERE SIGN(amount) IN (-1, 0)

这将为帐户中有负美元或零美元的客户生成一个带有customer_nameamount的表。

地板()

这个函数是在 SQL 查询中进行数学计算时常用的函数。它返回等于或小于所提供数字的最大整数。

请注意,它返回的数字等于或小于所提供的数字。这意味着当你对一个负数使用FLOOR()时,会产生一个更大的负数。

SELECT FLOOR(-15.5) FROM numbers

这将返回-16 作为您的答案,因为这是大于-15.5 的最大整数。

天花板()

这个函数是FLOOR()函数的姊妹函数。它不是返回最大的整数,而是返回大于或等于所提供数字的最小整数。

让我们看看上面的例子,但是现在使用 CEILING()函数。

SELECT CEILING(-15.5) FROM numbers

不是像FLOOR()函数那样返回-16,而是返回-15。-15 是大于或等于-15.5 的最小整数。

你有没有去过杂货店,收银员问你是否想凑够你的钱,把多余的零钱捐给当地的慈善机构?这个函数在杂货店数据库的后台会很有帮助。使用CEILING将为收银员提供向客户收费的新金额以及他们将捐赠的金额。

SELECT 
   transaction_id,
   transaction_amount,
   CEILING(transaction_amount) AS transaction_with_donation,
   CEILING(transaction_amount) - transaction_amount AS donation_amount 
FROM grocery_db

使用此功能,您可以获得您需要的关于交易的所有信息!

铅()

如果不包含至少一个窗口函数,这就不是一篇合格的 SQL 文章。我总是被教导说他们没有必要学习,但是我不确定是谁说的。窗口函数是 SQL 中最有用的函数之一。

LEAD()函数使您不必再对另一个表进行混乱的连接。它允许您访问当前正在查看的行之后的行中的值。这让比较变得超级容易。

让我们继续杂货店的例子。在一家杂货店中,有多个不同的结账通道 1-10。然后,在每一个收银台里都有不同的顾客。谁先到,谁就排在第一位,谁最后到,谁就排在最后。

作者图片

我们想找到排在每个顾客后面的人。为了做到这一点,我们将在customer_name列上使用LEAD()函数,这样我们就可以得到下一个客户的名字。然后,我们通过line_number对其进行划分,因为只有同一行中的客户才能排在彼此之前/之后。最后,我们在arrived_at时间前订购,这样我们就可以准确地了解每一行的客户顺序。

SELECT 
   customer_name,
   LEAD(customer_name) OVER(PARTITION BY line_number ORDER BY arrived_at ASC) AS next_in_line
FROM grocery_customers

这将导致如下所示的结果:

请注意,排在最后的客户在 next_in_line 列中有一个NULL值。只要当前行之后没有满足指定条件的行,LEAD()就会返回一个NULL值。由于 Fred 和 Haley 在他们的队列中排在最后,所以他们的next_in_line列有一个NULL值。因为 Sebastian 是第 2 行中的唯一一个人,所以他在该列中也有一个NULL值。

滞后()

LEAD()功能相反,LAG()允许您将当前行与其之前的行进行比较,而不是与其之后的行进行比较。它仍然用于比较,它只是服务于一个不同的目的。

类似地,使用 LEAD(),您可以根据希望如何分隔列,从当前行和分区之前的行中选择希望输出的列。然后,最重要的部分是ORDER BY。这将决定你是否得到你想要的价值。如果你选择ASCDESC值,那会改变你的整个查询。只要确保它符合你的问题和你要解决的问题的背景。

SELECT 
   customer_name,
   LAG(Name) OVER(PARTITION BY line_number ORDER BY arrived_at ASC)    AS ahead_in_line
FROM grocery_customers

这里,我们有相同的查询,只是现在我使用了LAG()函数。该功能将使客户排在我之前而不是之后。

作者图片

请注意,NULL值现在与使用LEAD()函数时相反。现在,那些排在第一位的人有了NULL值。Sebastian 仍然有一个NULL值,因为他是唯一排队的人。

在我的深入文章这里中可以看到更多关于如何使用这些函数的例子。

IFF()

我个人从来没有使用过这个函数,但是我现在需要开始使用它,因为我知道它有多有用。它本质上是一个更简单的CASE语句。IFF()函数测试一个条件,如果条件为真,则返回一个指定值,如果条件为假,则返回另一个指定值。

IFF(条件,真值,假值)

当使用一个列创建布尔列时,这很有帮助。假设您想要检查数据库中的哪些客户是老年人,或者超过 65 岁。您可以编写如下所示的查询:

SELECT 
   customer_name, 
   IFF(age >= 65, TRUE, FALSE) AS is_elderly 
FROM grocery_customers 

现在,我们可以简单地使用布尔型is_elderly列来过滤我们的客户,而不是查看年龄列并基于此添加过滤器。

结论

我不经常使用这些 SQL 函数,但是当我使用它们时,我的查询的速度和复杂度会有很大的不同。在您的工具箱中拥有这些函数对于在出现需要这些函数的问题时拥有最佳解决方案是至关重要的。

在面试中完成 SQL 测试时,它们也非常有用。有时你一时想不出简单的解决方案,知道这些奇特的功能会救你一命。相信我,我也经历过。事实上,面试官会对你的这些知识印象更加深刻。

通过订阅我的电子邮件列表,了解有关 SQL 和分析工程师使用的其他工具的更多信息

如何使用基于变压器的 NLP 模型

原文:https://towardsdatascience.com/how-to-use-transformer-based-nlp-models-a42adbc292e5?source=collection_archive---------7-----------------------

由 Julia Nikulski 创建的图形显示了初学者指南中关于如何使用基于 transformer 的 NLP 模型的主题。由 Flaticon 制作的 BecrisFreepikultimatearmmonkeucalype图标。

实践教程

理解和实现伯特、GPT-2 和其他用于下游任务的 NLP 模型的初学者指南

几个月前,我开始从事一个涉及文本分类的项目。我以前只使用基本的 NLP 技术来准备文本数据和应用简单的 ML 算法进行分类。然而,我知道基于变压器的 NLP 模型(如 BERT、GPT-3、T5 和 RoBERTa)可以实现最先进的(SOTA)结果。

实际上,让我重新表述这一部分,以准确描述我当时的知识状态:我知道围绕 GPT-3 的发布和这种模型如何能够很好地自行生成文本有着重大的轰动。有人告诉我这个模型可以用于文本分类。我该如何“使用这个模型”并让它预测我的数据标签呢?我不知道。

有很多很棒的博客文章解释了变形金刚的技术复杂性,T2 对比了目前可用的许多语言理解和语言生成模型,并提供了 T4 的教程和代码来实现特定的自然语言处理任务。然而,我缺乏基本的信息来理解如何使用这些 NLP 模型。

因此,本文为提供了一个高层次的概述,传达了围绕的基础知识,这些模型如何工作,在哪里可以访问它们,以及如何将它们应用到您自己的数据集和 NLP 任务。它面向熟悉 NLP 基础知识,但不熟悉更复杂的语言模型和迁移学习的人。为了获得基础知识之外的更多细节,我提供了学术论文、博客文章和代码演练的链接和参考。

劳伦·里奇蒙在 Unsplash 上的照片

1。什么是变压器?

变压器是 Vaswani 等人在 2017 年【1】开发的一种神经网络架构。不涉及太多细节,这个模型架构由一个多头自关注机制结合一个编码器-解码器结构组成。它可以实现在评估分数( BLEU 分数)和训练时间方面都优于利用递归( RNN )或卷积神经网络( CNN )的各种其他模型的 SOTA 结果。

与其他神经网络(NN)结构相比,转换器的一个关键优势是,单词周围的更长距离的上下文以更高效的计算方式被考虑【12】。“使……更加困难”这一短语可以在“使登记或投票过程更加困难”这句话中找到,尽管“更加困难”是“使……更加困难”的一个相当遥远的从属词【1】。围绕单词的相关上下文的计算可以并行进行,节省了大量的训练资源。

最初,Transformer 是为 NLP 任务开发的,并由 Vaswani 等人应用于机器翻译【1】。然而,它也适用于图像识别和其他领域。关于变压器的确切机制和功能的更多细节,请看这些深入解释:

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

2.NLP 模型如何利用 Transformer 架构,它们的不同之处是什么?

Transformer 模型结构已经在很大程度上取代了其他 NLP 模型实现,比如 RNNs【3】。当前的 SOTA NLP 模型部分或整体使用变压器架构。GPT 模型只使用了变换器结构(单向)【2】的解码器,而 BERT 是基于变换器编码器(双向)【4】。T5 采用了与原始实现【3】非常相似的编码器-解码器转换器结构。这些通用架构在组成编码器或解码器的元素的数量和维度方面也有所不同(即,层数、隐藏大小以及它们采用的自关注头的数量【4】)。

除了模型结构的这些变化外,语言模型在用于预训练的数据和任务方面也有差异,这将在下面的段落中进一步阐述。有关确切模型架构及其预培训设计的更多详细信息,您可以参考介绍这些模型的学术论文:

  • 【2】:GPT
  • 3:T5
  • [ 4 ]:伯特
  • 【5】:各种 NLP 模型及其差异的详尽概述

照片由蒂姆·莫斯霍尔德Unsplash 上拍摄

3.什么是迁移学习、预培训和微调?

许多基于 Transformer 的 NLP 模型是专门为迁移学习而创建的[ 34】迁移学习描述了一种方法,其中首先使用自我监督学习【5】在大型无标签文本语料库上对模型进行预训练。然后在对特定 NLP(下游)任务【3】进行微调的过程中对其进行最小程度的调整。特定 NLP 任务的标注数据集通常相对较小。与预训练版本【2】相比,仅在如此小的数据集上训练模型而不进行预训练会降低结果。相同的预训练模型可以用于微调各种 NLP 下游任务,包括文本分类、摘要或问题回答。

各种未标记的数据源可用于预训练。只要数据集足够大,它们在微调期间可以与数据或任务完全无关。使用 40 GB 的文本[ 6 ]对 GPT-2 进行预训练。因此,预训练非常耗费时间和资源,通常需要使用多个 GPU,耗时数小时甚至数天。在预培训期间实施的数据集和学习目标在不同的模型之间有很大的不同。GPT 使用标准语言建模目标【2】,预测句子中的下一个单词,而伯特则接受掩蔽语言建模(MLM)和下一句预测(NSP)【4】的训练。RoBERTa 模型复制了 BERT 模型架构,但使用更多数据改变了预训练,训练时间更长,并删除了 NSP 目标【7】

预训练模型的模型检查点作为微调的起点。特定下游任务的标记数据集用作训练数据。有几种不同的微调方法,包括以下几种:

  1. 根据标记的数据训练整个模型。
  2. 只训练较高层,冻结较低层。
  3. 冻结整个模型并训练一个或多个添加在顶部的附加层。

【3】中解释了另外两种类型的微调(适配器层和逐渐解冻)。无论采用哪种方法,特定于任务的输出层通常需要附加到模型上。如果您仅在新的文本数据集上微调模型,但学习目标保持不变,则不需要这一层。如果在特定的文本数据集上使用 GPT-2 进行语言生成,就会出现这种情况。

几篇介绍预训练的基于变压器的模型的研究论文也进行了微调实验,以展示它们的迁移学习性能。例如,BERT 接受了 11 个 NLP 任务的训练,微调整个模型中的所有参数,并将输出提供给特定任务的输出层

杰斯·贝利在 Unsplash 上拍摄的照片

4.除了迁移学习还有其他方法吗?

多任务学习旨在提高跨任务和领域的模型泛化能力 8 。同一个模型可以执行各种下游 NLP 任务,而不需要微调或改变模型参数或架构。GPT-2 仅使用语言建模目标在大型和多样化的文本数据集上进行训练。对于各种 NLP 任务,它达到了 SOTA 结果,而没有对这些任务进行微调。在推理期间只提供了几个例子来帮助模型理解所请求的任务。

元学习特别适用于特定任务数据集只有少量样本的情况(低资源任务)。它使模型能够开发良好的初始化和广泛的技能,在推理过程中快速适应新的或以前看到的任务[ 910 ]。多任务学习和元学习之间的一个关键区别是,多任务学习的性能偏向于具有大数据集的任务。元学习能很好地适应任何任务。类似于多任务学习,元学习模型不需要微调。

零触发、一次触发和少量触发学习有时被称为元学习。这些规格指的是在推理时提供给模型[ 9 ]的演示次数。

照片由 Jazmin QuaynorUnsplash 拍摄

5.在哪里可以获得这些模型?

研究人员开发的大多数基于变压器的模型都是开源的(目前除了 GPT-3)。你可以在 GitHub 上找到他们的模型实现(例如, BERT )。然而,如果您想要将模型应用到您自己的 NLP 任务中,您需要模型检查点。你可以通过 抱脸 提供的 变形金刚库 来访问这些。这个图书馆给你超过 32 个预先训练的 SOTA 模型。它提供了一个 API,允许您使用 PyTorch 或 TensorFlow 轻松地将模型集成到代码中。

拥抱脸被谷歌、微软和脸书等组织使用。然而,它的变形金刚库对初学者来说也很棒。它有大量的文档和各种 Google Colab 笔记本,提供了使用 DistilBERT 进行文本分类的示例实现。他们还会带你通过更一般的例子了解如何训练和微调一个模型。

有了管道对象,你只需要写几行代码就可以对各种不同的任务做推理。这些管道利用已经微调过的模型,并且文档解释了哪些模型与哪些特定于任务的管道一起工作。抱抱脸甚至创造了一个 零拍分类流水线 。它接受任何文本输入和标签数量,并返回每个标签的概率。在微调过程中,没有必要看到这些标签中的任何一个(因此称为零触发)。

照片由丹尼尔·麦金尼斯Unsplash 上拍摄

6.如何将这些模型应用到 NLP 任务中?

如果你知道你想要执行什么 NLP 任务,你将需要决定哪个基于 Transformer 的模型最适合这个目的。例如,GPT-2 通过其单向架构为语言生成进行了预训练和设计,使其对语言生成任务最有用。但是,也可以对序列分类进行微调。

你可以查阅这些模型的原始学术论文,以了解它们针对哪些任务进行了微调,以及它们在哪些方面表现得特别好。你也可以查看拥抱脸变形金刚文档,里面详细介绍了各种模型及其应用领域。

选择型号后,您可以对其进行微调。或者,你可以选择一个已经调好的模型、多任务或元学习者,然后马上开始推理(见管道拥抱脸的对象)。抛开拥抱脸提供的 32+预训练模型,其社区提供了超过9000 种模型规格

你将必须熟悉神经网络(NN)和深度学习至少一点点才能在大多数情况下微调模型。请记住,您通常会在预训练的模型中添加一个特定于任务的 NN 层,并实施一个训练过程。此外,您需要将数据集转换成正确的数据结构,以便与您的训练过程兼容。如果你还没有和 NNs 合作过,我建议你在这里阅读一下:

为了开始一个特定的任务并微调你的模型,看一下这些用于各种下游 NLP 任务的示例实现:

照片由缺口缺口缺口处拍摄

结论

起初,利用基于 Transformer 的 NLP 模型似乎令人望而生畏。已经发表了许多文章,非常详细地解释了与这些模型相关的概念。然而,在我深入这些细节之前,我想先有一个更广泛的概述。这是对与模型、训练过程以及将其应用于您自己的 NLP 用例相关的最重要元素的高级概述,希望能阐明如何使用它们。对于我的文本分类任务,我最终使用了 Longformer 模型,并使用 PyTorch Lightning 对其进行了微调。

你想在媒体上阅读更多高质量的故事吗?考虑注册一个支持我和其他媒体作者的会员。

https://medium.com/@julia.nikulski/membership

你想开始使用基于 Transformer 的 NLP 模型,但是你还没有一个具体的项目想法吗?为什么不看看我的关于如何提出独特的数据科学项目想法的 5 步指南:

</5-steps-to-develop-unique-data-science-project-ideas-6c2b3a0014b>

学术论文参考文献

[1] Vaswani,a .,Shazeer,n .,Parmar,n .,Uszkoreit,j .,Jones,l .,Gomez,A. N .,Kaiser,l .,& Polosukhin,I. (2017)。你需要的只是关注。ArXiv:1706.03762 [Cs]。http://arxiv.org/abs/1706.03762

[2]拉德福德、纳拉辛汉、萨利曼斯和苏茨基弗(2018 年)。通过生成性预训练提高语言理解https://cdn . open ai . com/research-covers/language-unsupervised/language _ understanding _ paper . pdf

[3] Raffel,c .,Shazeer,n .,Roberts,a .,Lee,k .,Narang,s .,Matena,m .,周,y .,Li,w .,,刘,P. J. (2020)。用统一的文本到文本转换器探索迁移学习的局限性。ArXiv:1910.10683 [Cs,Stat]。http://arxiv.org/abs/1910.10683

[4] Devlin,j .,Chang,m-w .,Lee,k .,& Toutanova,K. (2019 年)。BERT:用于语言理解的深度双向转换器的预训练。ArXiv:1810.04805 [Cs]。http://arxiv.org/abs/1810.04805

[5]阿恩马赫,m .,,霍伊曼,C. (2020 年)。预训练语言模型的可比性。 ArXiv:2001.00781 [Cs,Stat]http://arxiv.org/abs/2001.00781

[6]a .、吴 j .、蔡尔德 r .、栾 d .、阿莫代伊 d .、&苏茨基弗 I. (2019)。语言模型是无人监督的多任务学习者。 OpenAI 博客1 (8),9。https://cdn . open ai . com/better-language-models/language _ models _ are _ unsupervised _ 多任务 _ 学习者. pdf

[7]刘,y .,奥特,m .,戈亚尔,n .,杜,j .,乔希,m .,陈,d .,利维,o .,刘易斯,m .,泽特勒莫耶,l .,&斯托扬诺夫,V. (2019)。RoBERTa:稳健优化的 BERT 预训练方法。ArXiv:1907.11692 [Cs]。http://arxiv.org/abs/1907.11692

[8] Worsham,j .,& Kalita,J. (2020 年)。面向 21 世纪 20 年代自然语言处理的多任务学习:我们要去哪里?模式识别字母136 ,120–126。https://doi.org/10.1016/j.patrec.2020.05.031

[9] Brown,T. B .,Mann,b .,Ryder,n .,Subbiah,m .,Kaplan,j .,Dhariwal,p .,Neelakantan,a .,Shyam,p .,Sastry,g .,Askell,a .,Agarwal,s .,Herbert-Voss,a .,Krueger,g .,Henighan,t .,Child,r .,Ramesh,a .,Ziegler,D. M .,Wu,j .,Winter,c .,Amodei,D. (2020 年)。语言模型是一次性学习者。ArXiv:2005.14165 [Cs] 。http://arxiv.org/abs/2005.14165

[10]窦,张志勇,于,k .,,阿纳斯塔西索普洛斯,A. (2019).低资源自然语言理解任务的元学习算法研究。ArXiv:1908.10423【Cs】http://arxiv.org/abs/1908.10423

如何使用变压器网络建立预测模型

原文:https://towardsdatascience.com/how-to-use-transformer-networks-to-build-a-forecasting-model-297f9270e630?source=collection_archive---------3-----------------------

实践教程

使用变压器和 PyTorch 训练预测模型

安东尼·斯克里瓦科斯Unsplash 上拍摄的照片

我最近读了一篇非常有趣的论文,叫做 时间序列预测的深度转换模型:流感流行案例 我认为这可能是一个有趣的项目,从头实现类似的东西,以了解更多关于时间序列预测的信息。

预测任务:

在时间序列预测中,目标是在给定历史值的情况下预测时间序列的未来值。时间序列预测任务的一些示例如下:

例如,我们可以存储一个城市几个月的能源消耗指标,然后训练一个模型,该模型将能够预测该城市未来的能源消耗。这可以用于估计能源需求,因此能源公司可以使用该模型来估计在任何给定时间需要生产的能源的最佳值。

时间序列预测示例

型号:

我们将使用的模型是编码器-解码器转换器,其中编码器部分将时间序列的历史作为输入,而解码器部分以自回归方式预测未来值。

解码器使用注意机制与编码器链接。通过这种方式,解码器可以在进行预测之前学会“关注”时间序列历史值中最有用的部分。

解码器使用掩蔽的自我关注,使得网络不能通过向前看并使用未来值来预测过去值而在训练期间作弊。

编码器子网:

作者提供的编码器/图像

解码器子网络:

作者的解码器/图像

完整模型:

自回归编码器-解码器转换器/作者提供的图像

可以使用 PyTorch 通过以下方式构建该架构:

encoder_layer = nn.TransformerEncoderLayer(
    d_model=channels,
    nhead=8,
    dropout=self.dropout,
    dim_feedforward=4 * channels,
)
decoder_layer = nn.TransformerDecoderLayer(
    d_model=channels,
    nhead=8,
    dropout=self.dropout,
    dim_feedforward=4 * channels,
)

self.encoder = torch.nn.TransformerEncoder(encoder_layer, num_layers=8)
self.decoder = torch.nn.TransformerDecoder(decoder_layer, num_layers=8)

数据:

每次我实现一种新方法,我都喜欢先在合成数据上尝试,这样更容易理解和调试。这降低了数据的复杂性,并且更加关注实现/算法。

我编写了一个小脚本,可以生成具有不同周期、偏移量和模式的非平凡时间序列。

def generate_time_series(dataframe):

    clip_val = random.uniform(0.3, 1)

    period = random.choice(periods)

    phase = random.randint(-1000, 1000)

    dataframe["views"] = dataframe.apply(
        lambda x: np.clip(
            np.cos(x["index"] * 2 * np.pi / period + phase), -clip_val, clip_val
        )
        * x["amplitude"]
        + x["offset"],
        axis=1,
    ) + np.random.normal(
        0, dataframe["amplitude"].abs().max() / 10, size=(dataframe.shape[0],)
    )

    return dataframe

作者生成的时间序列/图像示例

然后在对模型进行训练,所有这些时间序列同时进行:

作者培训损失/图像

结果:

我们现在使用该模型对这些时间序列的未来值进行预测。结果有些复杂:

坏消息:

作者的错误预测/图片示例

优点:

作者的优秀预测/图像示例

结果没有我预期的那么好,特别是考虑到对合成数据做出好的预测通常很容易,但它们仍然令人鼓舞。

该模型的预测有些异相,在一些糟糕的例子中略微高估了振幅。在好的例子中,预测与地面真实情况非常吻合,排除了噪声。

我可能需要对我的代码进行更多的调试,并对超参数进行优化,然后才能期望获得更好的结果。

结论:

变压器目前是众多机器学习应用中非常受欢迎的模型,因此它们将用于时间序列预测是很自然的。

在处理时间序列时,Transformers 可能不是您的首选方法,因为它们可能很笨重且需要大量数据,但考虑到它们的多功能性和广泛的应用范围,它们很适合放在您的机器学习工具包中,从它们在 NLP 中的首次引入到音频处理、计算机视觉和时间序列。

如果您有任何问题或建议,请随时发表评论。

https://github.com/CVxTz/time_series_forecasting

如何使用 Twitter 高级搜索 API 来挖掘推文

原文:https://towardsdatascience.com/how-to-use-twitter-premium-search-apis-for-mining-tweets-2705bbaddca?source=collection_archive---------15-----------------------

一步一步地展示 Twitter 的高级搜索 API,挖掘历史推文数据用于学术研究

亚历山大·沙托夫在 Unsplash 上的照片

介绍

自然语言处理(NLP)对来自 Twitter 等社交媒体平台的高频数据的重要性正在飞速增长。公司正在与他们的客户进行实时反馈。它被用来收集有关新产品发布的情报,监控客户投诉,并分析营销活动的有效性。它还可以用来衡量人们对政府机构所作政策决定的看法/反应。

Twitter 提供不同的 API 来挖掘推文。有三个级别的访问其 API 来挖掘数据——基本、高级和学术。有了基本和提升的访问权限,人们可以挖掘出一周前的推文。然而,它的学术许可证带有两个高级搜索 API—search_30_daysearch_full_archive,允许搜索日期长达 30 天及以上的推文。此外,学术访问允许使用高级搜索运算符进行查询。我们将在这个博客中了解更多。

对于一个学术研究者来说,没有足够的例子可以让他立即开始他的项目。主要问题是 tweet 返回的 json 的结构根据 tweet 的类型而不同。第二个问题是,如果 tweet 超过 140 个字符的限制,搜索结果中的 tweet 文本通常会被截断。第三,twitter 不会一次获取全部数据,而是通过将数据分散到多个页面来优化其有效负载,默认情况下每个页面包含 100 条推文。悬停在这些页面上构成新的请求,并由 twitter 监控。免费学术访问每月仅提供 250 个请求。

Twitter 开发者资源[1]可以被证明是非常详尽的,但同时也是非常耗时的。该博客旨在通过展示一个简单的 python 片段,帮助研究人员通过高级搜索操作符筛选出历史推文的全文,从而节省他们浏览文档和试验 twitter APIs 的时间、精力和精力,从而为研究人员提供一个良好的开端。

在我们继续之前,我假设读者已经可以使用学术访问权限访问 twitter 开发者帐户。在这个演示中,我将使用Tweepy库,它是 Twitter API 的包装器。它减少了我们需要编写的代码行数,从而使我们的工作变得更加容易。我们开始吧。

2.工作流程

Twitter APIs 被聪明地设计来减少其服务器上的负载,即请求期间的数据传输。在大多数标准 API 中,默认情况下文本会被截断,因此必须使用extended模式来提取 API 的完整文本。然而,在 Twitter V2 高级搜索 API 中,full_text属性给出了未删节的原始推文,这通常是研究人员想要的,但它深深嵌入了推文的 json 字典中,该字典在所有推文中不遵循一致的模式。使用这些 API 的第二个问题是搜索结果显示在页面上,就像 Google web search 一样。默认情况下,每个页面提供 100 条推文。为了从后续页面访问更多的 tweets,我们需要执行分页。第三,Twitter 允许在其查询中使用搜索操作符来过滤结果,但是,原始 Twitter APIs 和 Tweepy APIs 的查询格式略有不同。我们将看到如何指定使用逻辑(和/或)操作符来微调搜索结果的查询。总而言之,工作流程如下:

  • 如何构建 twitter 搜索 API 来提取所有的推文
  • 如何避免截断并获得推文的全文
  • 如何进行分页
  • 如何在查询中指定逻辑和/或参数

3.如何构建 Twitter 搜索 API 来提取所有推文

我们将设置 API 构造函数,并使用作为学术许可一部分的证书进行授权。Twitter 沙盒环境将速率限制为每分钟 30 个请求和每秒 10 个请求。Tweepy API 构造函数提供了提及wait_on_rate_limit参数的灵活性,当达到 twitter 速率限制时,该参数会在发送新请求之前等待。

现在可以调用高级搜索 API,但它需要首先在 twitter 开发者帐户中创建沙盒环境。我已经将我的沙盒环境标记为research。搜索功能强制要求环境标签和查询参数。可选地,还可以提供fromDatetoDate字段来按时间过滤搜索结果。请注意,日期字段的格式是“YYYYMMDDHHMM”。推文按时间降序排列,即最新的推文排在最前面。对于沙盒开发环境,查询字段的最大长度限制为 256 个字符。默认情况下,构造函数将获取由 100 条 tweet 组成的第一页结果,如前所述,但是可以通过在非沙盒环境中指定 maxResults 参数来增加它,每页最多 500 条 tweet。

tweet_results = api.search_30_day(label='research', query="RBI", fromDate="202111100000", toDate="202111300000")

如果你尝试打印tweet_results,乍一看会显得胡言乱语。它本质上是 100 个状态对象的列表,每个 tweet 数据被打包成一个状态对象。您还可以使用索引来访问每个 tweet 数据,就像数组和列表一样。它会揭示每条推文的 json 结构。尝试用下面的代码打印第一个 tweet 对象。

print(json.dumps(tweet_results[0]._json, indent=4, sort_keys=True))

4.如何避免截断并获得推文的全文

tweet 的核心结构可以在开发者门户找到[2]。如前所述,搜索查询返回的有效载荷结构根据 tweet 的类型而不同。有四种不同类型的推文,即原始推文、转发推文、回复推文和引用推文[3]。我们将根据 tweets 的 json 结构改变我们的挖掘标准。首先,我们编写一个函数来确定 tweet 的类型。

下一步,我们将编写一个解析函数,从 json 列表中提取其他相关属性,并制作我们自己的定制词典。下面提供了示例代码。

5.如何用 Tweepy 分页

Tweepy 使分页变得非常简单。所有需要做的就是用pages()方法将 api 搜索封装到 Tweepy 的 Cursor 对象中,该方法将结果分成页面[5]。下一步是遍历所有页面,解析每个页面中的 tweets。在测试您的代码时,建议输入一个小数字作为 pages 的参数,因为它将请求的数量限制在这个数字之内。当需要完整的结果时,可以省略该参数。

或者,也可以使用光标对象通过使用items()方法获得状态对象列表,然后可以迭代该列表以提取每个 tweet 的单个元素。在测试您的代码时,建议输入一个小数字作为 items 的参数,因为它将 tweets 的数量限制在这个数字以内。当需要完整的结果时,可以省略该参数。需要注意的是,在这两种方法中,使用仪表板中反映的请求数量将是相同的,因为 twitter 将 100 条推文计算为 1 个请求。

6.如何在查询中指定逻辑和/或参数

Twitter 搜索 API 还允许在本质上是字符串对象的查询中嵌入逻辑操作符。在这个字符串中,我们可以使用 AND/OR 操作符连接我们的关键字。这里唯一的问题是 twitter API 搜索规则要以 json 格式放置[6,7]。下面是一些说明性的例子:

  1. query = ""RBI article\ " ",搜索 API 将呈现与短语RBI article完全匹配的推文
  2. query = " " RBI article "或" RBI Bulletin "将呈现包含精确短语RBI articleRBI Bulletin的推文。
  3. query = ""RBI" "Governor\ " "将呈现包含关键字RBIGovernor的推文,而不考虑它们出现的顺序。

7.结论

在这篇博客中,我讨论了研究人员在使用 twitter 高级搜索 API 时遇到的困难。稀缺的文档将这些问题变成了一场耗时的考验,从而将焦点从最初的研究问题转移到如何使用 twitter APIs 以所需的格式获取有关相关 tweets 的所需信息。我们解决了截断、分页和在查询中使用逻辑运算符的困难,并编写了一个代码,研究人员可以在各自的用例中直接部署该代码。

在我们结束之前,

我邀请你和我一起参与这个激动人心的数据科学旅程。关注我的媒体页,探索更多关于数据科学的精彩内容。

如何用 Python 对测井数据进行无监督聚类

原文:https://towardsdatascience.com/how-to-use-unsupervised-learning-to-cluster-well-log-data-using-python-a552713748b5?source=collection_archive---------6-----------------------

使用 Python 细分地下

对测井数据进行无监督聚类分析,以识别岩相(图片由作者提供)

了解地下岩性是地球科学和岩石物理学中的一项重要任务。使用由测井技术产生的各种电测量,我们能够推断出下面的地质情况,例如岩性、岩相、孔隙度和渗透率。

机器学习算法通常被用来将测井记录测量值分成不同的岩性组,称为岩相。这个过程可以使用无监督学习或监督学习算法来实现。

监督学习是最常见和最实用的机器学习任务,它旨在使用已映射到“正确”输出的输入数据从示例中学习。或者,我们可以使用无监督学习运行建模,让算法识别数据中的潜在模式,这些模式在数据探索过程中可能不容易看到。

在本教程中,我们将使用两种聚类方法(K 均值聚类和高斯混合建模)进行无监督学习分类,并将结果与已建立的岩相曲线进行比较。

什么是聚类/聚类分析?

数据聚类是探索性数据分析(EDA)的一种常见形式,用于根据共享的特征或属性将数据分成不同的组。彼此相似的数据点被分组在同一个群集中,而不同的数据点被放在另一个群集中。

k 均值聚类

K-Means 聚类是一种非常常用的无监督机器学习算法。它用于通过最小化数据点和质心之间的距离来将数据分组为 K 个簇。

质心在数据空间中的 k 个随机点处被初始化,并且基于到质心的距离,其周围的所有点被分配给相关的聚类。然后将质心调整到群集的中心点,并重新分配其周围的点。这种情况一直持续到质心没有变化或者这些点保持在同一个簇中,或者直到达到最大迭代次数。

K-Means 是一种硬聚类方法,其中数据点要么属于某个聚类,要么不属于某个聚类。它还通过对数据应用圆(或多维数据集中的超球)来执行聚类。

高斯混合模型

GMM 方法也允许对数据点进行聚类,只是它考虑了数据差异,导致了更软的分类,并且它不是基于距离而是基于分布。

此外,被分类的数据点有可能是一个或另一个聚类。

虽然 K-Means 聚类在数据聚类是圆形的情况下效果很好,但是,在岩石物理和地质情况下,数据很少形成良好的圆形模式。GMM 模型使用椭圆形的聚类/决策边界,因此更加灵活。

一篇关于这两种方法之间差异的优秀文章可以在https://www . analyticsvidhya . com/blog/2019/10/Gaussian-mixture-models-clustering/找到

资料组

我们在本教程中使用的数据集构成了由 Xeek 和 FORCE 2020 举办的机器学习竞赛的一部分。竞赛的目的是从现有的标记数据中预测岩性。该数据集由挪威海的 118 口井组成。

本文的数据和笔记本可以在我位于 https://github.com/andymcdgeo/Petrophysics-Python-Series的 GitHub 仓库中找到。

导入库和数据加载

项目的第一步是导入我们需要的库。对于这个例子,我们将使用 NumPy 处理数组, pandas 存储数据, seabornmatplotlib 显示数据。

然后我们将使用pd.read_csv读入数据,然后使用describe()方法查看数据细节。

的数据描述

由于这是一个相当大的表,我们可以通过调用df.columns来查看列。

这将返回 dataframe 中的列数组:

Index(['WELL', 'DEPTH_MD', 'X_LOC', 'Y_LOC', 'Z_LOC', 'GROUP', 'FORMATION', 'CALI', 'RSHA', 'RMED', 'RDEP', 'RHOB', 'GR', 'SGR', 'NPHI', 'PEF', 'DTC', 'SP', 'BS', 'ROP', 'DTS', 'DCAL', 'DRHO', 'MUDWEIGHT', 'RMIC', 'ROPA', 'RXO', 'FORCE_2020_LITHOFACIES_LITHOLOGY', 'FORCE_2020_LITHOFACIES_CONFIDENCE'], dtype='object')

在这个例子中,我们不需要所有的列,所以我们将复制一个包含所需测井测量值的数据帧,包括井名和深度曲线。

我们还将把FORCE_2020_LITHOFACIES_LITHOLOGY列重命名为更简单的名称,如FACIES

当我们调用 dataframe 时,我们要处理的列数量要少得多。

列重新映射/重命名

为了简化绘图,并理解数据中提供的岩性数字的含义,我们可以创建两个字典并将FACIES列映射到两个新列。

第一个是为数字的字符串表示创建一个字典。

第二本字典将岩性数字简化为 1 到 12 的范围,而不是原始数据中使用的大范围数字。这将有助于绘制对数图。

为了在我们的数据框架中创建新的列,我们首先定义列名workingdf['LITH'],然后使用.map()方法分配映射值。

我们对相的字符串和简单数字表示都这样做。

当我们查看数据帧时,我们可以看到现在在末尾有两个新列。

将数据可视化

由于已经有一个包含该数据的相列,我们可以快速查看数据在每个岩相中的分布情况。

为了做到这一点,我们可以使用 Seaborn 的FacetGrid方法为每种岩性绘制单独的密度-中子交会图(散点图)。

FacetGrid 用于创建地块的基础结构。在这个例子中,FacetGrid 已经被传递了我们正在处理的 data frame(workingdf)、我们想要用来拆分图的列(col)以及我们想要换行到新行的点(col_wrap)。在这种情况下,一旦有 4 列,数据就会换行。

然后我们可以在FacetGrid的顶部绘制一个密度中子交会图。

FORCE 2020 XEEK 机器学习数据集内岩性的 FacetGrid。

创建绘图功能

在绘制任何数据之前,我们需要创建一些函数。第一个是 create plot 函数,它将接受一些参数和我们的相曲线,并将生成一个常规的测井曲线。

按井函数拆分数据

我们将创建的第二种方法将用于按井分割我们的数据帧。这是使用groupby函数完成的,它将允许我们将每个数据帧存储在一个列表中,以便于以后访问。

然后,我们可以调用该函数:

这将返回一个索引位置和相关井名的列表

index  wellname
0      15/9-13
1      15/9-15
2      15/9-17
3      16/1-2
4      16/1-6 A
5      16/10-1
6      16/10-2
7      16/10-3
8      16/10-5
9      16/11-1 ST3
10      16/2-11 A
11      16/2-16

无监督聚类

在本节中,我们将建立聚类模型,并在数据集上运行它们。

首先,我们将从 sklearn 库中导入我们的集群模型。

寻找最佳聚类数

为了确保 K 均值和高斯混合建模模型有效工作,我们需要为它们提供一个初始的聚类数。如果聚类数选择不正确,算法可能无法很好地执行,或者可能需要更长的时间来解决问题(尤其是当聚类数过高时)。

我们可以尝试使用肘形图来确定最佳聚类数,目标是根据结果中形成的“肘形”或拐点来选择聚类数。还有其他方法,例如用于挑选集群数量的剪影方法。

对于这个例子,我们将使用肘图。为此,我们在给定的聚类范围内评估模型性能,然后从图中确定最合适的数字。

为了进行聚类,我们需要删除任何丢失的值。这是通过使用dropna()功能实现的。

然后,我们可以使用describe()函数来确保在删除丢失的数据值后,我们的数据仍然是好的。在这个例子中,我们已经从 133,198 到 82,732 个深度级别。

为了使我们的模型简单,我们将使用四个测井测量值(列):伽马射线(GR)、体积密度(RHOB)、中子孔隙度(NPHI)和声波压缩慢度(DTC)。

用于选择最佳聚类数的肘形图(图片由作者提供)

在上面的图中,我们可以看到,随着聚类数量的增加,惯性(到最近的聚类中心的平方距离之和)减小。在该数据集中没有明确定义的间断,但是,我们可以看到斜率从大约 5 个聚类开始变化。该值的选取将取决于解释器,范围可以从 4 到 10。

因此,在本例中,我们将 5 作为最佳聚类数。

拟合聚类模型

为了使比较简单,我们将在高斯混合模型中使用相同数量的聚类。对于该模型,簇数参数被称为 n_components。

绘制结果

现在已经使用克均值和 GMM 方法计算了聚类,我们可以绘制数据以查看预测与标记岩性的关系。请注意,这些方法是无监督的,并且不使用标记的数据进行训练。我们在这里比较无监督方法在测井数据中的表现。

正如我们在主workingdf数据框架中预测的那样,我们需要将数据再次拆分到各个油井中。我们可以通过调用前面创建的简单函数来做到这一点。

index  wellname
0      15/9-13
1      15/9-15
2      15/9-17
3      16/1-6 A
4      16/10-1
5      16/10-2
6      16/10-3
7      16/10-5
8      16/2-11 A
9      16/2-16

我们要看的第一个图是对数图。我们将传递原始岩相(LITH_SI)列和新计算的 KMeans 和 GMM 结果。

用 Python 生成的测井图显示了不同的无监督学习聚类方法(图片由作者提供)

在上面的图中,我们有原始的岩性,我们计算的 k 均值和 GMM 聚类结果在最后三个子图中。

首先要注意的是,颜色不一定意味着数据来自每种方法的同一组。有很多方法可以映射它们,使得颜色一致,但是为了本教程的目的,我们不会深入讨论这个。

查看 16/10–1 井(索引 4),我们显示了 10 个独立的相/组,我们可以看到这些主要与测井测量的变化有关。例如,伽马射线(GR)从大约 2300 米下降到大约 2775 米,这与蓝色和浅蓝色组很好地联系在一起。在 KMeans 和 GMM 模型中,这一部分也在两种方法中被突出显示为位于同一聚类中,但是,这一部分没有变化。由于这两种方法都被设置为最多 5 个集群,我们将无法捕获相同程度的变化。

为了解决这个问题,我们可以增加集群的数量。

查看散点图/交会图上的结果

查看聚类性能的另一种方式是通过散点图。我们可以使用常见的密度-中子散点图/交会图和 matplotlib 来实现这一点。

无监督学习结果与提供的岩性的交会图(图片由作者提供)

尽管在每种方法中都有聚类的混合,但在测井曲线部分讨论的区间可以在曲线的左下方识别,这里我们有较高的密度值和较低的中子孔隙度值。

在 KMeans 分组中,该聚类显示为一个完整的聚类,然而,在 GMM 方法中,我们可以看到它更接近于所提供的岩性。

查看配对图上的结果

因为我们在模型中使用了四条输入曲线,所以我们应该查看所有这些曲线,以了解聚类是如何变化的。最好的方法是使用 seaborn 库中优秀的 pairplot。此图在网格上显示数据集中数据之间的关系。这提供了一种快速简单的方法来识别和可视化数据。沿着对角线,还绘制了按聚类划分的数据分布。

当我们查看 4 号井时,我们需要将该数据帧传递给 pairplot (dfs_wells[4])。

说明每个输入测量的各种聚类的 PairPlot(图片由作者提供)

说明每个输入测量的各种聚类的 PairPlot(图片由作者提供)

这为我们提供了一个更好的图形,也让我们看到数据是如何聚集在其他测井曲线中的。我们可以看到,GMM 模型在定义集群方面提供了一些改进,尤其是在 DTC 与 RHOB 图中。

摘要

在本文中,我们介绍了使用两种流行的算法(KMeans 聚类和高斯混合建模)进行无监督聚类分析的基础知识。使用优化方法,我们通过目测确定了最佳聚类数为 5,但是,值得用更多的聚类进行实验,以查看这是否提供了更好的匹配。

一旦聚类完成,我们看到了多种可视化结果的方法:标准对数图设置、散点图和 seaborn 的 pairplot。

由于 K-均值聚类利用球形聚类,它可能并不总是适用于测井数据和地下。然而,高斯混合模型似乎确实在聚类方面提供了一点改进。

感谢阅读!

如果你觉得这篇文章有用,请随时查看我的其他文章,这些文章从不同的角度研究了 Python 和测井数据。你也可以在 GitHub 找到我在这篇文章和其他文章中使用的代码。

如果你想联系我,你可以在LinkedIn或者我的 网站 找到我。

有兴趣了解更多关于 python 和测井数据或岩石物理学的知识吗?跟我上

如果你喜欢这篇文章或任何其他文章,并想表达你的谢意,欢迎你来给我买杯咖啡

参考

博尔曼,彼得,奥桑德,彼得,迪里布,法哈德,曼拉尔,投降,&迪辛顿,彼得。(2020).机器学习竞赛 FORCE 2020 井测井和岩相数据集[数据集]。芝诺多。http://doi.org/10.5281/zenodo.4351156

你需要的最全面的 K-Means 聚类指南https://www . analyticsvidhya . com/blog/2019/08/Comprehensive-Guide-K-Means-Clustering/

posted @ 2024-10-18 09:27  绝不原创的飞龙  阅读(258)  评论(0)    收藏  举报