TowardsDataScience-博客中文翻译-2022-二十七-

TowardsDataScience 博客中文翻译 2022(二十七)

原文:TowardsDataScience

协议:CC BY-NC-SA 4.0

如何在 R 中创建自定义数据集

原文:https://towardsdatascience.com/how-to-create-a-custom-dataset-in-r-cf045e286656

制作您自己的合成数据集,用于分析您的投资组合

斯科特·格雷厄姆Unsplash 上拍照

在你的数据科学之旅中,你可能会遇到合成数据集,有时也被称为玩具虚拟数据集。这些对于实践数据争论、可视化和建模技术非常有用。与真实世界的数据相比,它们通常是清晰易懂的。这使得使用合成数据对初学者来说是一个很有吸引力的想法。今天,我将带你了解如何制作你自己的合成数据。阅读完本文后,您将能够创建自己的大数据,其中包含您喜欢的任意数量的变量。

本教程将介绍我如何创建这个人力资源数据集。它包含了 300 名数据科学家在一家假设公司的招聘考试中表现如何,以及他们在该公司工作 1 年后的绩效评估分数。

为什么要创建自己的数据集?

除了易于分析之外,合成数据集还提供了优于真实世界数据的额外优势。这里有一些场景来说明:

您正在寻找的数据是高度小众、特定或机密的

起初,我试图在脑海中为我的项目寻找数据集。找了几个小时后,我两手空空。我意识到网上可能根本没有,因为公司不会到处公布申请人的数据。

你想创建自己的教程

假设你想写一个关于执行线性回归的教程(就像我一样!).你需要保证一些预测因子与你的自变量线性相关,而一些则不是。如果你寻找你自己的数据集,你将不得不对它们中的每一个进行测试。另一方面,如果你创建了你自己的,你可以设计它来保证这个假设成立。

您希望拥有您数据的所有权利

再也不用担心版权、数据隐私或使用条款,因为数据完全是你的。

你的目标是练习你的数据可视化和沟通技巧

就我而言,我的目的是展示我在人力资源分析方面的知识。具体来说,我想展示我在执行统计测试和将结果传达给业务经理方面的知识。

你需要什么

  • 你的数据集将描述什么
  • 关于数据性质的知识
  • 关于常见概率分布的一些知识
  • R 的工作知识

制作数据集

r 有几个函数可以让你即时生成随机数据。以下步骤将指导您选择正确的函数、组织其输出并导出完成的数据集。

第一步:列出所有你想包含的变量

记下你需要多少单位或多少行数据。对于这个项目,我想要总共 320 个申请人/行的数据。

第二步:描述每个变量的要求

这就是背景和你的现场经验发挥作用的地方。例如,面试分数可能在 0 到 10 之间。但是作为招聘人员,你知道从 0 到 3 的分数是不现实的,所以你把 4 和 10 设为这个变量的最小值和最大值。同时,对于机器学习考试的分数,现实的最低和最高分数是 40 和 100。然而,你也知道平均分数是 80 分,大多数申请人的分数接近 80 分,所以你也希望你的数据能够反映这一趋势。如果你想让一些变量相互关联,也指出哪些变量。

第三步:为你的变量确定一个合适的分布

这是最棘手的部分,因为这是你要运用你的普通概率分布知识的地方。如果您只是使用数据集来练习争论或可视化,您可能只需要知道均匀和正态分布就可以了。但是在我的例子中,我希望我的数据有各种各样的关系和特性,所以我使用了一大堆。

我对面试分数使用了离散均匀分布,因为我希望申请人获得 4 分的概率等于获得 4.1 分或 4.2 分,一直到 10 分。同时,我对我的编码考试分数和性能分数使用了多元正态分布,因为我希望它们都是正态分布的,并且以不同的强度相互关联。

请注意,每个分布都有自己的一组参数,这就是我们在步骤 2 中的需求。你可以在这里阅读更多关于常见概率分布

步骤 4:编写代码

当然,这部分说起来容易做起来难。所以让我们一次解决一个变量(或一组变量)。

套餐

library(MASS)
library(tidyverse)
library(writexl)

首先,让我们装载所有我们需要的包。Tidyverse 用于数据操作,MASS 用于生成我们的多元正态分布,writexl 用于将我们的工作保存为 excel 文件。

申请人身份证号

id <- paste0("Applicant #", 1:320)

生成唯一 ID 号的最简单方法是创建一个整数序列。这里,我们还在“申请人#”后面追加了paste0()

管理

# Assign Management Experience Randomly
set.seed(0717)
management_random <- rbinom(320, 1, 0.5)
management <- ifelse(management_random == 0, "manager", "non-manager")

随机生成分类变量的一种方法是首先随机抽取一组数字,然后给每个数字分配一个类别。这里,我们使用rbinom随机选择 0 和 1,然后将男性分配给 0,女性分配给 1

情境判断考试成绩、缺课人数和数据可视化考试成绩

# Situational Judgment Test Scores
set.seed(0717)
situational <- round(runif(320, 60, 100))# Number of Absences
set.seed(0717)
absences <- rpois(320, lambda = 1)# Data Viz Exam Scores
set.seed(0717)
coding_viz <- rnorm(320, 85, 5) %>%
  cap_score(., 100) %>% 
  round(2)

由于我们已经为这些变量指定了我们想要使用的分布和参数,我们现在需要做的就是将它们插入到它们各自的函数中:均匀分布的runif 、泊松分布的rpois和单变量正态分布的rnorm 。我们还将使用我们之前创建的函数cap_score,将数据可视化考试分数的最高分设为 100。

相关变量

cor_var_means <- c(6.8, 7.2, 8.4, 77, 84, 80)
cor_var_matrix <- matrix(
  c(
    0.87, 0.6, 0.7, 0.36, 1.55, 0.57,
    0.6, 1.2, 0.52, 0.5, 1.2, 2.34,
    0.7, 0.52, 0.68, 0.45, 0.89, 0.75,
    0.36, 0.5, 0.45, 15.2, 1.09, 1.64,
    1.55, 1.2, 0.89, 1.09, 17.2, 1.88,
    0.57, 2.34, 0.75, 1.64, 1.88, 9.3
  ), byrow = T, nrow = 6
)set.seed(0717)
correlated_vars_df <- as.data.frame(mvrnorm(n = 320, mu = cor_var_means, Sigma = cor_var_matrix))

我们需要一个均值向量和一个方差-协方差矩阵来生成多元正态分布。我们已经在前面的步骤中确定了均值,但是现在,我们必须用下面的公式计算协方差。您可能会发现在 Excel 中执行这一步更容易。

correlated_vars_df_cols <- c("interview_p1", "interview_p2", "interview_p3", "coding_cleaning", "coding_ml", "performance")
colnames(correlated_vars_df) <- correlated_vars_df_colscorrelated_vars_df <- correlated_vars_df %>%
  mutate(interview_p1 = round(cap_score(interview_p1, 10), 1),
         interview_p2 = round(cap_score(interview_p2, 10), 1),
         interview_p3 = round(cap_score(interview_p3, 10), 1),
         coding_cleaning = round(cap_score(coding_cleaning, 100), 2),
         coding_ml = round(cap_score(coding_ml, 100), 2),
         performance = round(cap_score(performance, 100))
         )

现在,我们有了随机生成的面试、编码考试和性能分数。让我们稍微清理一下。首先,我们给它们分配了所有的列名。接下来,让我们将面试分数四舍五入到小数点后一位,最高分为 10 分。为此,我创建了自己的函数cap_score。它将列和最大分数作为其参数。编码考试成绩,小数点后两位,最高 100 分。为了提高性能,我们也将它们设为最大值为 100 的整数。

第五步:收集并保存你的数据

applicant_scores <- cbind(
  id, management, situational, coding_viz, correlated_vars_df, absences)applicant_final <- applicant_scores[1:300, ]write_xlsx(applicant_final, "Employee Selection Scores.xlsx")

我们可以很容易地收集使用cbind生成的变量和数据集。我只保存前 300 行数据,因为我计划将它用作训练集。准备就绪后,您可以将最终数据集保存为您想要的格式。我选择了 Excel .xlsx

(可选)第六步:分享!

您创建这个数据集可能是因为您没有任何替代方法。这意味着你的数据分析师同事可能也不知道。通过分享来回馈社区!这也是一个展示你的 R 技能和领域知识的机会。

你可以在这里访问我的数据集。

https://github.com/MartinaGiron/R-Portfolio/tree/main/Employee-Selection

一些最后的话

今天,我们讨论了如何使用 320 个数据点和变量创建自己的数据集,这些数据点和变量遵循正态、泊松和离散均匀概率分布。现在,您可以分析这些数据,并将其添加到您的投资组合中。下一次,尝试添加更多的数据点(你可以有几十万,甚至几百万行!).您也可以通过让变量遵循不同的分布来进行试验,例如 beta 或几何分布。

如何在 VDK 创建一个数据格式插件

原文:https://towardsdatascience.com/how-to-create-a-data-formatting-plugin-in-vdk-dc5f1c7d206d

数据工程,数据湖

关于如何通过编写 VDK 自定义插件来操作数据湖中的表的分步教程

活动创建者Unsplash 上的照片

通用数据工具包 (VDK)是一个框架,用于将不同的数据源接收和操作到一个数据湖中。我已经在我的上一篇文章中讨论过 VDK,所以关于它的介绍,你可以参考那里。

在这篇文章中,我将讨论如何在 VDK 中实现一个自定义插件。作为一个用例,我将实现一个简单的插件,它从现有的表中获取输入,并在其上执行数据格式化。为了展示插件是如何工作的,我将只实现一个简单的任务,从一个表的一列中取出一些字符串,并用另一个字符串替换它们。下图显示了我将要实现的数据格式化作业:

作者图片

在左边的表中,同一个国家意大利出现了两个不同的名称,因此我将执行数据格式化,以得到一个同质的国家值,如右边的表所示。

为了执行前面描述的任务,我将实现一个 VDK 插件,您可以如下调用:

**vdk format-column** -t my-table -c country -o "Italie,Italia" -d Italy

其中:

  • -t选项指定要操作的表格
  • -c选项指定要操作的列
  • -o选项指定要替换的事件列表
  • -d选项指定目标值。

为了在 VDK 实现这个自定义插件,我将遵循下面描述的步骤:

  1. 创建骨架
  2. 配置插件
  3. 配置作业
  4. 测试和安装插件。

1.创建骨架

为了创建插件的框架,我使用如下的cookiecutter:

**cookiecutter** https://github.com/tozka/cookiecutter-vdk-plugin

当我运行前面的命令时,我需要回答一些问题:

作者图片

该过程完成后,将创建一个新目录。下图显示了所创建目录的树:

作者图片

包含两个主目录:srctests,以及三个文件:README.mdrequirements.txtsetup.py

首先,我编辑README.md文件。我可以让requirements.txt保持原样,因为我不会添加任何特定的库。

我现在把重点放在插件配置上。

2 配置插件

我用编辑器打开了setup.py文件。在这个文件中,您可以指定插件的版本、名称、所需的包以及插件的入口点目录:

__version__ = "0.1.0"setuptools.setup(
 **name="vdk-preprocessing",**
 version=__version__,
 url="https://github.com/vmware/versatile-data-kit",
 description="Versatile Data Kit SDK Preprocessing plugin to manipulate an already ingested table.", long_description=pathlib.Path("README.md").read_text(),
 long_description_content_type="text/markdown",
 install_requires=["vdk-core"],
 package_dir={"": "src"}, packages=setuptools.find_namespace_packages(where="src"), **entry_points={"vdk.plugin.run": ["vdk-preprocessing =  vdk.plugin.preprocessing.preprocessing_plugin"]},** classifiers=[ "Development Status :: 4 - Beta",
 "License :: OSI Approved :: Apache Software License",
 "Programming Language :: Python :: 3.7",
 "Programming Language :: Python :: 3.8",
 "Programming Language :: Python :: 3.9",
 "Programming Language :: Python :: 3.10",
 ],)

现在我可以重命名目录的名称来反映我的项目的语义。最终的目录树应该如下所示:

我已经将plugin_entry.py重命名为preprocessing_plugin.py,然后我在preprocessing中添加了一个preprocessing_formatting_job目录,在那里我放了一个format_column_step.py脚本。

现在我正在写剧本preprocessing_plugin.py。这个脚本定义了插件接口。在我的例子中,我将实现一个命令行插件,所以这里我必须定义插件的命令名,以及传递给命令的选项。在我的例子中,该命令将接收 4 个参数作为输入:

**@click.command**(
  name="format-column",
  help="Execute a SQL query against a configured database and format the table.",
  no_args_is_help=True,
)**@click.option**(
  "-t",
  "--table",
  help="The name of the table.",
  default="my_table",
  type=click.STRING,
)**@click.option**(
  "-c",
  "--column",
  help="The column to format.",
  default="my_column",
  type=click.STRING,
)**@click.option**(
  "-o",
  "--occurrences",
  help="The list of occurrences to modify separated by comma.",
  default="",
  type=click.STRING,
)**@click.option**(
  "-d",
  "--destination",
  help="The target value.",
  default="",
  type=click.STRING,
)**@click.pass_context**

您可以注意到,我需要将上下文传递给我的命令函数。

VDK 使用hookimpl decorators 实现了一个插件,所以你可以参考 VDK 官方文档了解更多细节。

一旦定义了选项,我就可以定义format_column()函数,它将接收它们:

**def format_column(ctx: click.Context, table: str, column: str, occurrences : str, destination : str):**
  args = dict(table=table, column=column, occurrences=occurrences, destination=destination)
  ctx.invoke(
    run,
    data_job_directory=os.path.dirname(format_column_step.__file__),
    arguments=json.dumps(args),
)

前面的函数只是调用运行任务的特定作业。

最后,我给 VDK 加上命令:

@hookimpl
**def vdk_command_line(root_command: click.Group) -> None:**
   root_command.add_command(format_column)

3 配置作业

现在是配置格式化作业的时候了。这个作业只包含一个名为 format_column.py 的步骤。

我定义了一个名为 ColumnFormatter 的新类来执行该任务。在我的例子中,它搜索作为参数传递的表的列中的所有匹配项,并用目标值替换它:

class **ColumnFormatter**:
  def __init__(self, job_input: IJobInput):
     self.__job_input = job_input def format_column(self, table: str, column: str, occurrences: list, destination : str):
     for value in occurrences:
        query = f"UPDATE {table} SET {column} = '{destination}' WHERE {column} = '{value}'; "
       self.__job_input.execute_query(query)

ColumnFormatter类必须包含一个IJobInput实例对象。

现在我实现了run()函数,向 VDK 表明这是一个步骤:

def **run(job_input: IJobInput) -> None:** table = job_input.get_arguments().get("table")
   column = job_input.get_arguments().get("column") 
   occurrences = job_input.get_arguments().get("occurrences").split(",")
   destination = job_input.get_arguments().get("destination") formatter = ColumnFormatter(job_input)
   formatter.format_column(table, column, occurrences,destination)

run()函数只是检索命令行参数,并将它们传递给 ColumnFormatter 方法format_column()

4 测试和安装插件

插件准备好了。最后一步包括编写测试和安装插件。我更改了tests目录的默认结构,因为我将实现一个简单的测试。

我将测试编写为包含在测试目录中的脚本,如下图所示:

作者图片

您可以编写任意多的测试。在这个例子中,我只编写了一个测试来展示它们是如何工作的。VDK 使用pytest来执行测试。

我编写了下面的测试:

  • 我使用sqlite-query插件创建了一个表格。我还用本文顶部显示的表中的值填充了该表(列 town 和 country)
runner = **CliEntryBasedTestRunner**(sqlite_plugin, preprocessing_plugin)runner.invoke(
[
 "sqlite-query",
 "--query",
 "CREATE TABLE test_table (city TEXT, country TEXT)",
]
)mock_sqlite_conf = mock.MagicMock(SQLiteConfiguration)
sqlite_ingest = IngestToSQLite(mock_sqlite_conf)
payload = [
{"city": "Pisa", "country": "Italie"},
{"city": "Milano", "country": "Italia"},
{"city": "Paris", "country": "France"},
]sqlite_ingest.ingest_payload(
 payload=payload,
 destination_table="test_table",
 target=db_dir,
)

我使用了 VDK 提供的CliEntryBasedTestRunner()类来调用 sqlite-query 插件。

  • 我调用 vdk 预处理插件,用值“意大利”替换国家列中出现的“意大利,意大利”
result = runner.invoke(["**format-column**", "--table", "test_table", "--column", "country", "--occurrences", "Italie,Italia", "--destination", "Italy"])
  • 我检查输出。
result = runner.invoke([
 "sqlite-query",
 "--query",
 "SELECT country FROM test_table",
]
)output = result.stdout
assert output == (
  "country\n"
  "---------\n"
  "Italy\n"
  "Italy\n"
  "France\n")

现在你可以运行测试。首先,我安装软件包:

pip install -e /path/to/vdk-preprocessing/

然后从vdk-preprocessing目录中:

pytest

如果一切正常,你的测试应该是PASSED

摘要

恭喜你!你刚刚学会了如何在 VDK 建立一个自定义插件!你可以在 VDK 官方知识库中找到更多关于 VDK 插件的信息。你也可以使用 VDK 已经有的插件!

你可以在我的 GitHub 库中找到这篇文章中描述的例子的代码。

相关文章

如何创建数据质量框架

原文:https://towardsdatascience.com/how-to-create-a-data-quality-framework-6887dea268ae

关于确定重点关注领域的逐步说明

照片由 Unsplash 上的clément del Andrea拍摄

当您的数据比预期晚到达时会发生什么?或者一列中应该填充的值都是 NULL?像这样的数据质量问题通常是数据管道中出现问题的滞后指标。当它们发生时,损害已经造成,您需要找到一个解决方案来防止这些问题再次进入生产。

以下是一些常见的数据质量问题及其潜在原因:

作者图片

关注数据质量计划对于生成业务可依赖的数据至关重要。如果没有特定的工具和流程,您的数据将很难被信任。没有人会确切知道这些数据是否能带来准确的见解。如果你不能相信数据,你还能相信什么?

实施质量检查还将允许您减少花费在解决突然出现的问题上的时间。相反,你可以积极主动,在问题发生并扰乱工作流程之前预见任何问题。强调数据质量的最佳方式是创建一个数据质量框架,供您的团队遵循。

什么是数据质量框架?

数据质量框架是组织和数据团队定义不同数据质量特征的工具,以便他们能够致力于开发有助于改善这些特征的系统和过程。该框架关注数据质量的七个关键领域——准确性、完整性、及时性、唯一性、治理、沿袭和一致性。

准确性是指数据的实际值与其真实值的接近程度。与真实值相比,实际值的特征有意义吗?例如,信用卡号列是否像它应该的那样是 16 位数字?

完整性查看数据表中是否有缺失值。是否有缺少值的列或行?如果是,这是意料之中的吗?

时效性看你数据的新鲜程度。接收新数据的频率如何?当您的团队需要数据时,数据是否可用?

唯一性检查重复数据行。是否有两行具有相同的主键?他们的其他价值观相比如何?

治理指的是谁有权访问您的数据以及数据的安全性。每个人都应该拥有完成工作所需的最低访问权限。PII 数据应该对用户隐藏。您还希望确保您的数据符合您所在行业的法规。

沿袭跟踪数据从接收到编排的移动。理想情况下,您应该能够看到模型之间的依赖关系,以及源列是如何向下游转换的。

最后,一致性查看数据中的模式。您的数据每天都在同一时间被摄取和转换吗?或者这是变量?每周摄取的数据量相似吗?

为什么我应该创建一个数据质量框架?

数据质量框架允许您精确定位将对业务产生最大影响的质量领域。它遵循“80%的结果来自 20%的努力”的理念。当你花时间关注那些引起最多问题的领域时,你将对你的组织产生最大的影响。

框架让你更好地了解你所缺乏的领域。这也有助于您在投资数据质量方面获得支持,因为您将能够清晰、简明地向利益相关者展示您正在做的事情。一个框架允许你提出一个问题和一个解决方案,它可以帮助防止这个问题再次发生。

如何创建数据质量框架

那么,如何创建一个框架,让所有的数据质量计划都基于这个框架呢?让我们走一遍这些步骤。

  1. 记录您过去遇到的或怀疑将来会遇到的所有已知数据质量问题。

想想你过去处理过的事件或遇到的问题。例如,如果您的数据管道在 3 周前出现故障,这将是您希望立即解决的问题。如果某一天某个表中的数据丢失了,您可能也想记录下来。

2。将每一个分类为 7 个类别之一——准确性、完整性、及时性、唯一性、治理、沿袭和一致性。

现在,您可能想重温一下我前面列出的不同数据质量支柱的描述。您列出的每个问题属于哪一类?管道故障属于及时性范畴,因为当天的数据交付较晚。表中缺失的数据属于完整性范畴。

3。列出每一类,并把相应的项目放在下面。

你要确保这些问题得到妥善组织。如果组织中的利益相关者或领导询问数据质量计划,这将为您提供一些演示材料。

4。计算哪 3-4 个类别的商品数量最多。

你需要将你的框架集中在拥有最多条目的类别上。这些是您的组织最头疼的问题。你 80%的进步将来自于关注这些。一旦你确定了这些,我建议你创建一个简单的图形来提醒自己什么是重要的。

作者图片

5。在相应的类别下列出这些问题的潜在解决方案。

这将帮助您为每个数据质量支柱定义一个总体目标。例如,测试可能对提高数据表的完整性和准确性很重要。我推荐头脑风暴潜在的工具,比如你想要实现的 Datafoldre_data 来帮助每个支柱,并考虑不同类型的测试,比如 dbt 测试dbt 期望,甚至是定制的测试。

在创建解决方案时,系统与工具和测试同样重要。想想你的团队需要做什么来使这些计划成功。当出现问题时,您是否需要创建待命时间表或警报行动计划?

6。细化每种解决方案,并列出每种解决方案成功所需完成的具体任务

我建议在吉拉上创建这些特定的任务作为标签,这样它们就可以直接添加到 sprint 中。你希望它们足够详细,你可以指出它们,并立即开始实施。

7。与利益相关者分享基本框架,让他们了解你在做什么以及为什么。

最后,分享你做了什么!您这样做是为了产生每个人都可以依赖的高质量数据。请务必注意这一点!以利益相关者会感到兴奋的方式设计计划。例如,向我们的数据模型中添加测试将在某些东西损坏时提醒我们,允许我们在损坏之前修复您最喜欢的仪表板

推荐工具

作者图片

结论

在创建数据质量框架时,您希望关注准确性、完整性、及时性、一致性、唯一性、治理和沿袭。牢记这些支柱的框架将有助于组织您的流程,并确保您正在执行的任务能够带来最佳结果。

幸运的是,有许多令人惊奇的工具使得产生高质量的数据变得更加容易。最大的障碍通常是弄清楚你需要做什么,以及哪些任务将对业务产生最大的影响。实现这种类型的框架永远不会太晚,即使您正在进行数据质量工作。

重组,重新组织,看你的数据质量飙升到新的高度!

更多关于产生高质量数据的信息,请查看我的免费每周简讯关于分析工程。

看看我的第一本电子书,分析工程基础知识,一本全方位的分析工程入门指南。

如何通过 5 个重要步骤创建数据仓库

原文:https://towardsdatascience.com/how-to-create-a-data-warehouse-in-5-important-steps-95a8f893a3fd

任何数据仓库项目中需要的 5 个重要步骤

万花筒Unsplash 上拍摄的照片

H 作为众多复杂数据转换项目的一部分,我可以确认 85%的数据项目失败的统计数据。

这些失败的原因是:

  1. 更改数据堆栈
  2. 缺乏准备
  3. 没有合适的团队
  4. 不耐烦的利益相关者
  5. 过分热情的管理
  6. 缺乏对文化变革的投资等。

项目以良好的意图开始;很快,面对以上问题,导致挫败感和一种压倒性的感觉。这些项目要么被不择手段拖到终点线,要么被放弃,去寻找下一个闪亮的目标。

那么,我们如何避免这种情况呢?今天,我们将学习一个成功的数据仓库项目的蓝图。

不,这不是火箭科学。

第 1 步—了解核心业务需求

请不要追逐下一个闪亮的物体。

你真的需要一个数据仓库(DWH)吗?除非你是一个全新的企业,你可能已经有了最后的 DWH 项目的残余。需求需要创建一个新的DWH 吗?如果答案是肯定的,请确保您了解核心业务需求。

通常,它是为了解决一个重大问题,即如何产生更多的收入,减轻监管风险,改善董事会层面的报告等。

记住;解决问题>用于解决问题的技术

明确你的要求——创造迫使你思考最终结果的报道故事。

一个报道故事的例子:

作为一名营销经理,我需要了解去年购买产品的客户 数量,以便向他们提供追加销售。**

从上面的故事中,我可以确定我们将需要根据前一年的销售额合计每位顾客的产品数量。创建一个完整的报告故事目录,帮助您推动业务及其数据需求。

创建概念模型

现在,您已经有了一个报告故事的列表,是时候创建简单的概念模型来验证它们了。概念模型是实体及其关系的抽象视图。

用简单的英语,他们像五年级学生一样解释你的业务流程。

作者图片:抽象概念模型

概念模型还可以稍微详细一些,实体关系可以解释为一对多、一对一或多对多,称为 基数。

作者图片:显示基数的模型

  1. 客户必须是独一无二的,即同一客户不应重复计算。
  2. 他们可以有零个或多个订单,也就是说,他们可能在数据库中,以前从未订购过。
  3. 订单必须包含一种或多种产品,即没有产品就不能下订单。
  4. 一个产品可能出现在零个或多个订单中,即一个产品可能在库存中,但从未销售过或销售过多次。

你有一个报道故事的目录,你从中挑选出所需的数据。您还有一个简单的概念模型,它解释了这些关系。

这必须与业务最终用户共同创建和验证。

步骤#2 —创建物理数据模型

我们可以从早期的概念数据模型中为骨骼添加肉。作为一个实体,客户现在可以被细化为属性,如客户姓名、电话号码、地址、唯一标识符等。

作者图片:简单的物理数据模型,只有很少的关键属性

物理模型引入了字符串、整数等数据类型。、主键和外键。如果我们回到最初的报告故事,我们在物理数据模型中有足够的信息来回答这个问题吗?

作为一名营销经理,我需要知道客户去年购买的产品数量,以便向他们提供追加销售。****

我不这么认为!此时,我们需要决定如何在 DWH 创建这些数据。我们可以使用一些不同的方法,例如星型模式中的维度建模或雪花模型中的第三范式标准化。

如果这些概念对你来说是陌生的——考虑阅读这篇文章:

****https://medium.com/geekculture/50-data-engineering-jargon-d94d07596a5a

对于我们的例子,我们将创建一个简单的维度模型,包含事实(定量)和维度(定性)。

作者图片:我们报道故事的星形模式

现在,我们在事实表中有了足够的信息,可以聚合任意日期(去年、最近五年)每个客户的产品数量及其总销售额。该模型还允许我们以多种方式“切割”数据。

分析已知的数据属性

当这项活动正在进行时,您必须开始分析已知的源数据。

我已经记不清有多少 DWH 项目因为数据质量差和缺乏真实数据测试而失败。提前做好这项工作——在设计数据管道之前,分析数据,了解数据质量问题,并尝试解决这些问题。如果某个问题无法解决,您必须在您的数据管道中处理它。****

第 3 步—展示最终结果的解决方案线框

根据团队的规模和需求的复杂程度,这可能与第二步同时发生。商业终端用户不关心你的 DWH 或者你的星形模式维度模型。他们希望问题得到解决。

记住;解决问题>用于解决问题的技术!

在此阶段,根据客户的要求创建一些最终报告的线框/原型。你将很快学会并塑造最终产品的外观。业务最终用户可能有一个愿景,但他们在需求阶段无法清晰地表达出来。线框不需要使用真实世界的数据或在报告工具中。它可以简单地在幻灯片中创建。

步骤# 4——构建、测试和迭代

希望到这时候,我们已经做出了一些设计和环境决策。包括物理数据模型、历史要求、批准的线框图以及环境供应和设置。

现在—我们创建 ETL(提取、转换和加载)作业或数据管道。数据需要从源系统转移到我们的物理 DWH。

在移动这些数据时,我们需要考虑#2(数据类型)的分析输出,如果需要转换,还需要考虑需要提取的历史记录的数量。我们还需要迭代地对管道的单个组件进行单元测试。

一旦构建了足够大的管道,就应该进行端到端的系统集成测试,以确保集成点按预期运行。

整合通常决定交付的成败。

如果渠道足够成熟,可以给出一个结果,即报告指标、总销售额、产品数量等。,谨慎的做法是与业务最终用户一起验证这些数字。同样,让最终用户参与到整个过程中来帮助迭代解决方案将会在项目的后期节省大量的痛苦。

第五步——不是上线——而是走向成熟

我们喜欢对现场约会感到兴奋。一个 DWH 需要成熟;因此,上线并不重要。

如果被现实生活中的数据证明是错误的,一些设计决策可能必须在成熟阶段重新考虑。如果变更很耗时,并且影响到许多组件,这就特别痛苦。因此,我建议提前广泛地分析数据。

如果创建最终报告所需的时间比预期的长,则必须持续进行性能调整。

数据库管理员可能需要收集数据统计信息、创建索引、在重复的日期应用压缩等。在 DWH 可以完全依赖之前。

再说一次,从经验来说,期望 DWH 在代码生产的第一天就能工作是天真的。

随着 DWH 的成熟,使用它的团队将需要接受如何使用它的培训,数据治理原则将得到应用,数据质量和清理流程将正式化。将围绕这个 DWH 创建一个完整的运营模型,以确保它符合目的。

结论

这不是一份详尽的活动清单;在这篇文章中,我可能忽略了一些我认为不太必要的步骤。希望这里能为你和你的 DWH 项目提供一些经验。

如果你觉得这篇文章有帮助,请在下面留言告诉我。查看我在 Medium 上的其他帖子:

****https://medium.com/geekculture/25-terms-to-help-you-in-your-career-in-data-science-14ca681b0699

如果您没有订阅 Medium,请考虑使用我的推荐链接订阅。它比网飞便宜,而且客观上能更好地利用你的时间。如果你使用我的链接,我会获得一小笔佣金,而你可以在 Medium 上获得无限的故事。

我也定期在推特上写东西;跟着我这里。****

如何创建 dbt 包

原文:https://towardsdatascience.com/how-to-create-a-dbt-package-ca795d1dbe12

钳工Unsplash 上拍照

我过去常常复制和粘贴几乎相同的 SQL 查询,认为这是使用 SQL 的唯一方法。

幸运的是,我接受了一个分析工程师的新职位,并发现了 dbt ,这是一个用动态查询和模型依赖来构建数据模型的神奇工具。

有了 dbt,我们可以使用宏,而不用两次重写相同的 SQL。我很快意识到,即使我们试图在项目中使用可重用的代码,我们也经常在不同的项目中使用相同的代码。

为了避免跨项目的代码冗余,我创建了我的第一个 dbt 包。这个包现在由共享一些模型和宏的几个项目导入。

以下是如何快速创建第一个 dbt 包并跨项目重用代码的方法!

创建项目

dbt 包只不过是一个常规的 dbt 项目。让我们通过调用 dbt init 来创建一个包。选择您想要的名称和配置,这并不重要,因为我们不会单独使用这个项目。

我们将把这个项目称为,而这个包被导入的项目称为主项目

导入模型

现在,在 models/example 文件夹中,让我们使用以下查询创建一个名为 hello_world.sql,的文件:

{{config(
materialized = 'table'
)}}SELECT "Hello World!" AS field

并将绝对路径复制到 dbt 项目。

打开您的主项目,并编辑 packages.yml 以添加以下行:

- local: <absolute_path>

然后在您的终端中,运行:

dbt deps
dbt run -m example

检查您的配置文件中指定的数据集。您现在应该会看到一个新的表格 hello_world,如下所示:

作者截图

定制您的模型

项目变量

这很好,但是您可能不希望在所有项目中使用完全相同的查询。好消息是,你可以使用项目变量来定制你的模型。

让我们编辑我们的查询:

{{config(materialized = 'table')}}SELECT "Hello {{ var('first_name') }}!" AS field

在我们主项目的 dbt_project.yml 文件中,我们可以像这样添加一个项目变量:

vars: first_name: Marie

作者截图

然后一旦你运行 dbt run -m example,你的查询将使用为该变量定义的值运行!

源文件

这只是一个没有 FROM 子句的简单查询;在实际项目中,您还会希望使用源文件来查询不同的表。

让我们创建一个使用源表的模型 hello_world_2

{{config(materialized = 'table')}}SELECT *, 2 AS versionFROM {{ source("hello_source", "hello_world")}}

这里,我们告诉 dbt 在 source hello_source 中查找表 hello_world

但是我们必须在项目中配置源代码。让我们在项目的 sources 文件夹中创建一个名为 hello.yml 的配置文件。

version: 2sources: - name: hello_sourceproject: "<your_project>" dataset: "<your_dataset>" tables: - name: hello_world

现在,当我们运行我们的模型时,我们看到的是:

作者截图

导入宏

导入模型有一些主要的缺点:

  • 如果我们需要模型中的变量,我们必须在项目文件中定义它们,这个文件很快就会被重载
  • 项目变量的类型不被保留,所以列表被转换成字符串
  • 从包中选择包括哪些型号并不容易

宏解决了这些问题,尽管还需要做更多的配置。

在我们包的 macros 文件夹中,让我们创建一个名为 hello_everyone.sql 的文件。

{% macro hello_everyone(names) -%}{{config(materialized = 'table')}}SELECT{% for name in names -%}"Hello {{name}}" AS greeting_{{name}},{%- endfor %}{%- endmacro %}

现在,让我们告诉主项目通过编辑项目文件来查找该宏:

macro-paths: ["macros", "dbt_packages/<package_name>/macros"]

最后,让我们在模型/示例中创建一个模型文件来调用我们的宏:

{% set names = ["nina", "chloe", "marie"] %}{{ hello_everyone(names) }}

作者截图

发布您的包

要发布您的包,您只需将它推送到 git 存储库,然后您将能够使用以下语法导入它:

packages:
  - git: "https://github.com/<git_url>" 
    revision: <version_tag>

感谢您的阅读,希望这篇教程对您有所帮助!您可以在 dbt 文档中找到关于该主题的更多信息。

如果您喜欢这篇文章,请关注我,了解更多关于 SQL、dbt 和分析的内容!

如何用 Python 从 Matplotlib 图创建 GIF

原文:https://towardsdatascience.com/how-to-create-a-gif-from-matplotlib-plots-in-python-6bec6c0c952c

基于 imageio 的二维时间序列数据可视化技术

用 Matplotlib 和 imageio 创建的 GIF(图片由作者提供)

我们都知道线图是可视化时间序列的最直观的方式。但是,如何可视化具有两个有关系的特征的时间序列,比如 x 和 y 坐标或经度和纬度?gif 是可视化二维时间序列数据的好方法。

gif 是可视化二维时间序列数据的好方法。

让我们看看下面的例子。

x = [1, 2, 3, 4, 4, 4, 4, 3, 2, 1, 1, 1, 1]
y = [1, 1, 1, 1, 2, 3, 4, 4, 4, 4, 3, 2, 1]
time = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12

您可以首先用线图绘制一段时间内的每个要素。但是对于这种数据可视化,这两个特征之间的关系并不清楚。

两个独立时间序列的折线图(图片由作者提供)

接下来,你可以在 y 上绘制 x,这揭示了两个特征之间的关系。但是现在你错过了时间。

x 在 y 之上(图片由作者提供)

为了形象化两个特征和时间之间的关系,我们可以使用 GIF。

本教程将向你展示如何用 Python 通过三个简单的步骤快速创建 GIF。

如何用 Python 创建 GIF

你可以使用库 Matplotlibimageio 通过三个简单的步骤用 Python 创建 GIF:

  1. 创建一个函数,用 Matplotlib 绘制时间相关帧
  2. 绘制 GIF 的所有帧
  3. 图像将这些帧组合成 GIF

对于本教程,我们将使用 Matplotlib 来绘制 GIF 的单个帧,并使用 imageio 将单个帧组合成一个 GIF。

import matplotlib.pyplot as plt
import imageio

1.创建一个绘制时间相关帧的函数

首先,您将创建一个函数create_frame(t),它在一个特定的时间戳绘制 GIF 的单个帧,并用一个惟一的名称保存它。

我建议设置参数transparent = Falsefacecolor = 'white',以避免由于单个透明帧重叠而在 gif 中产生奇怪的效果。

def create_frame(t):
    fig = plt.figure(figsize=(6, 6)) plt.plot(x[:(t+1)], y[:(t+1)], color = 'grey' )
    plt.plot(x[t], y[t], color = 'black', marker = 'o' ) plt.xlim([0,5])
    plt.xlabel('x', fontsize = 14)
    plt.ylim([0,5])
    plt.ylabel('y', fontsize = 14)
    plt.title(f'Relationship between x and y at step {t}',
              fontsize=14) **plt.savefig(f'./img/img_{t}.png', 
                transparent = False,  
                facecolor = 'white'
               )** plt.close()

2.绘制 GIF 的所有框架

接下来,你要做的就是绘制 GIF 的所有帧。

for t in time:
    create_frame(t)

用 Matplotlib 绘制的 GIF 的所有单帧(图片由作者提供)

并将所有的单帧保存到一个名为frames的数组中。

frames = []for t in time:
    image = imageio.v2.imread(f'./img/img_{t}.png')
    frames.append(image)

3.将这些帧组合成一个 GIF

最后,您所要做的就是用mimsave方法将这些帧保存到 GIF 文件中。您可以使用fps参数调整 GIF 的每秒帧数(fps)。

imageio.mimsave('./example.gif', # output gif
                frames,          # array of input frames
                fps = 5)         # optional: frames per second

生成的 GIF 如下所示。

用 Matplotlib 和 imageio 创建的 GIF(图片由作者提供)

如果你想让 GIF 在最后一帧后停止,给mimsave方法添加参数loop = 1

imageio.mimsave('./example.gif', 
                frames, 
                fps = 5, 
                **loop = 1**)

使用 Matplotlib 和 imageio 创建的 GIF,在最后一帧循环一次后停止(图片由作者提供)

结论

用线图可视化二维时间序列数据可能是无效的,因为它不能显示两个特征之间的关系。对于经度和纬度或 x 和 y 坐标这样的二维时间序列数据,使用 gif 是更好的数据可视化替代方法。

在这个简短的教程中,您学习了如何使用 Python 中的 Matplotlibimageio 创建 GIF,只需三个简单的步骤:

  1. 创建一个函数,用 Matplotlib 绘制时间相关帧
  2. 绘制 GIF 的所有帧
  3. 图像将这些帧组合成 GIF

喜欢这个故事吗?

这里收集了我的其他时间序列分析和预测文章:

Leonie Monigatti

莉奥妮·莫尼加蒂

时间序列分析和预测

View list6 storiesHierarchical time series forecastingGIF created with Matplotlib and imageioA time series with lines indicating trend and variance for time series analysis. The last three data points are in a contrast color to indicate that they are predicted values from the time series forecasting model

如果你想把我的新故事直接发到你的收件箱,请务必订阅https://medium.com/subscribe/@iamleonie

成为媒介会员,阅读更多来自我和其他作家的故事。报名时可以用我的 推荐链接 支持我。我将收取佣金,不需要你额外付费。

*https://medium.com/@iamleonie/membership

TwitterLinkedInKaggle***

如何用 Python 创建图形神经网络

原文:https://towardsdatascience.com/how-to-create-a-graph-neural-network-in-python-61fd9b83b54e

用 Pytorch 几何图形和 OGB 创建 GNN

照片由 JJ 英Unsplash

深度学习为在非结构化数据上进行预测开辟了一个全新的可能性世界。今天,通常对图像数据使用卷积神经网络(CNN ),对文本使用递归神经网络(RNNs ),等等。

在过去的几年中,出现了一类新的令人兴奋的神经网络:图神经网络(GNNs)。顾名思义,这个网络类侧重于处理图形数据。

在这篇文章中,你将学习图形神经网络如何工作的基础知识,以及如何使用 Pytorch 几何(PyG)库和开放图形基准(OGB)库在 Python 中实现它。

我的 GithubKaggle 上有这篇文章的代码。

一个普通的 GNN 是如何工作的

随着图形卷积网络(GCN) [1]的引入,GNNs 开始变得流行起来,它从 CNN 借用了一些概念到图形世界。这种网络的主要思想,也称为消息传递框架,多年来成为该领域的黄金标准,这就是我们将在这里探讨的概念。

消息传递框架声明,对于图中的每个节点,我们将做两件事:

  • 聚集来自其邻居的信息
  • 用来自其先前层及其邻居聚集的信息来更新节点信息

消息传递框架。来源:维基百科

图 1 展示了这个通用框架是如何工作的。GCN 之后开发的许多架构都专注于定义聚集和更新数据的最佳方式。

关于派格和 OGB

PyG 是 Pytorch 库的扩展,它允许我们使用研究中已经建立的层快速实现新的 GNNs 架构。

OGB [2]是作为一种提高该领域研究质量的方法而开发的,因为它提供了可供使用的精选图表,也是评估给定架构结果的标准方法,从而使方案之间的比较更加公平。

一起使用这两个库的想法是,人们可以更容易地提出一个体系结构,而不必担心数据获取和评估机制。

实施 GNN

首先,让我们安装所需的库。请注意,您必须安装 PyTorch:

pip install ogb
pip install torch_geometric

现在,让我们导入所需的方法和库:

import os
import torch
import torch.nn.functional as Ffrom tqdm import tqdm
from torch_geometric.loader import NeighborLoader
from torch.optim.lr_scheduler import ReduceLROnPlateau
from torch_geometric.nn import MessagePassing, SAGEConv
from ogb.nodeproppred import Evaluator, PygNodePropPredDataset

第一步是从 OGB 下载数据集。我们将使用 ogbn-arxiv 网络,其中每个节点是 arxiv 上的一篇计算机科学论文,每个有向边代表一篇论文引用了另一篇论文。任务是将每个节点分类到一个纸类中。

下载它非常简单:

target_dataset = 'ogbn-arxiv'# This will download the ogbn-arxiv to the 'networks' folder
dataset = PygNodePropPredDataset(name=target_dataset, root='networks')

数据集变量是一个名为 PygNodePropPredDataset()的类的实例,该类特定于 OGB。要将数据集作为可在 Pytorch 几何图形上使用的数据类进行访问,我们只需:

data = dataset[0]

如果我们看一下这个变量,我们会看到这样的情况:

Data(num_nodes=169343, edge_index=[2, 1166243], x=[169343, 128], node_year=[169343, 1], y=[169343, 1])

我们有节点数、邻接表、网络的特征向量、每个节点的年份和目标标签。

这个网络已经有了一个用于训练、验证和测试的分离集。这是由 OGB 提供的,旨在提高该网络研究的可重复性和质量。我们可以通过以下方式提取:

split_idx = dataset.get_idx_split() 

train_idx = split_idx['train']
valid_idx = split_idx['valid']
test_idx = split_idx['test']

现在,我们将定义两个数据加载器,在我们的培训中使用。第一个将只加载训练集中的节点,第二个将加载网络上的所有节点。

我们将使用 Pytorch 几何图形中的邻居加载器。该数据加载器对每个节点的给定数量的邻居进行采样。这是一种避免具有数千个节点的节点的 RAM 和计算时间爆炸的方法。对于本教程,我们将在训练加载器上对每个节点使用 30 个邻居。

train_loader = NeighborLoader(data, input_nodes=train_idx,
                              shuffle=True, num_workers=os.cpu_count() - 2,
                              batch_size=1024, num_neighbors=[30] * 2)total_loader = NeighborLoader(data, input_nodes=None, num_neighbors=[-1],
                               batch_size=4096, shuffle=False,
                               num_workers=os.cpu_count() - 2)

请注意,我们打乱了训练数据加载器,而不是整个加载器。此外,训练加载器的邻居数量被定义为网络每层的数量。因为我们这里要使用两层网络,所以我们用两个值 30 将其设置到列表中。

现在是时候创造我们的 GNN 建筑了。对于任何熟悉 Pytorch 的人来说,这应该不会太可怕。

我们将使用鼠尾草层。这些层在一篇非常好的论文[3]中进行了定义,该论文介绍了邻域采样的概念。Pytorch 几何库已经为我们实现了这一层。

因此,与每一个 PyTorch 架构一样,我们必须用我们将要使用的层定义一个类:

class SAGE(torch.nn.Module):
    def __init__(self, in_channels,
                 hidden_channels, out_channels,
                 n_layers=2):

        super(SAGE, self).__init__()
        self.n_layers = n_layers self.layers = torch.nn.ModuleList()
        self.layers_bn = torch.nn.ModuleList() if n_layers == 1:
            self.layers.append(SAGEConv(in_channels, out_channels,   normalize=False))
        elif n_layers == 2:
            self.layers.append(SAGEConv(in_channels, hidden_channels, normalize=False))
             self.layers_bn.append(torch.nn.BatchNorm1d(hidden_channels))
            self.layers.append(SAGEConv(hidden_channels, out_channels, normalize=False))
        else:
           self.layers.append(SAGEConv(in_channels, hidden_channels, normalize=False))
              self.layers_bn.append(torch.nn.BatchNorm1d(hidden_channels)) for _ in range(n_layers - 2):
                self.layers.append(SAGEConv(hidden_channels,  hidden_channels, normalize=False))
                 self.layers_bn.append(torch.nn.BatchNorm1d(hidden_channels))

            self.layers.append(SAGEConv(hidden_channels, out_channels, normalize=False))

        for layer in self.layers:
            layer.reset_parameters() def forward(self, x, edge_index):
        if len(self.layers) > 1:
            looper = self.layers[:-1]
        else:
            looper = self.layers

        for i, layer in enumerate(looper):
            x = layer(x, edge_index)
            try:
                x = self.layers_bn[i](x)
            except Exception as e:
                abs(1)
            finally:
                x = F.relu(x)
                x = F.dropout(x, p=0.5, training=self.training)

        if len(self.layers) > 1:
            x = self.layers[-1](x, edge_index) return F.log_softmax(x, dim=-1), torch.var(x)

    def inference(self, total_loader, device):
        xs = []
        var_ = []
        for batch in total_loader:
            out, var = self.forward(batch.x.to(device), batch.edge_index.to(device))
            out = out[:batch.batch_size]
            xs.append(out.cpu())
            var_.append(var.item())

        out_all = torch.cat(xs, dim=0)

        return out_all, var_

让我们一步一步地分解它:

  • 我们必须定义网络的输入通道数,这将是数据集中的要素数。out_channels 将是我们试图预测的类的数量。隐藏通道参数是一个我们可以自己定义的值,代表隐藏单元的数量。
  • 我们可以设置网络的层数。对于每个隐藏层,我们添加一个批量标准化层,然后我们重置每个层的参数。
  • forward 方法运行正向传递的单次迭代。它将获取特征向量和邻接表,并将其传递给 SAGE 层,然后将结果传递给批量规范化层。我们还应用了一个 ReLU 非线性和一个用于正则化目的的漏失层。
  • 最后,推理方法将为数据集中的每个节点生成一个预测。我们将使用它进行验证。

现在,让我们定义模型的一些参数:

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')model = SAGE(data.x.shape[1], 256, dataset.num_classes, n_layers=2)
model.to(device)
epochs = 100
optimizer = torch.optim.Adam(model.parameters(), lr=0.03)
scheduler = ReduceLROnPlateau(optimizer, 'max', patience=7)

现在,我们将创建测试函数来验证我们所有的预测:

def test(model, device):
    evaluator = Evaluator(name=target_dataset)
    model.eval()
    out, var = model.inference(total_loader, device) y_true = data.y.cpu()
        y_pred = out.argmax(dim=-1, keepdim=True) train_acc = evaluator.eval({
        'y_true': y_true[split_idx['train']],
        'y_pred': y_pred[split_idx['train']],
    })['acc']
    val_acc = evaluator.eval({
        'y_true': y_true[split_idx['valid']],
        'y_pred': y_pred[split_idx['valid']],
    })['acc']
    test_acc = evaluator.eval({
        'y_true': y_true[split_idx['test']],
        'y_pred': y_pred[split_idx['test']],
    })['acc']return train_acc, val_acc, test_acc, torch.mean(torch.Tensor(var))

在这个函数中,我们从 OGB 实例化了一个验证器类。这个类将负责对我们之前检索到的每个分割进行模型验证。这样,我们将看到每个时期的训练、验证和测试集的分数。

最后,让我们创建我们的培训循环:

for epoch in range(1, epochs):
    model.train() pbar = tqdm(total=train_idx.size(0))
    pbar.set_description(f'Epoch {epoch:02d}') total_loss = total_correct = 0 for batch in train_loader:
        batch_size = batch.batch_size
        optimizer.zero_grad() out, _ = model(batch.x.to(device), batch.edge_index.to(device))
        out = out[:batch_size] batch_y = batch.y[:batch_size].to(device)
        batch_y = torch.reshape(batch_y, (-1,)) loss = F.nll_loss(out, batch_y)
        loss.backward()
        optimizer.step() total_loss += float(loss)
        total_correct += int(out.argmax(dim=-1).eq(batch_y).sum())
        pbar.update(batch.batch_size) pbar.close() loss = total_loss / len(train_loader)
    approx_acc = total_correct / train_idx.size(0) train_acc, val_acc, test_acc, var = test(model, device)

    print(f'Train: {train_acc:.4f}, Val: {val_acc:.4f}, Test: {test_acc:.4f}, Var: {var:.4f}')

这个循环将训练我们的 GNN 100 个代,并且如果我们的验证分数连续七个代没有增长,将提前停止它。

结论

gnn 是一类令人着迷的神经网络。今天,我们已经有几个工具来帮助我们开发这种解决方案。正如你所看到的,使用 Pytorch 几何和 OGB 可以很容易地实现一些图形的 GNN。

[1]基普夫,托马斯&韦林,马克斯。(2016).基于图卷积网络的半监督分类。

[2]胡,魏,费伊,米,齐特尼克,米,董,y,任,刘,b,卡塔斯塔,米和莱斯科维奇(2020)。开放图基准:图的机器学习数据集。arXiv 预印本 arXiv:2005.00687

[3]汉密尔顿,威廉&英,雷克斯&莱斯科维奇,Jure。(2017).大型图上的归纳表示学习。

如何在 Streamlit 中创建网格布局

原文:https://towardsdatascience.com/how-to-create-a-grid-layout-in-streamlit-7aff16b94508

我们介绍了一种在 Streamlit 中使用世界人口数据演示应用程序以编程方式创建网格布局的方法

Piet Mondrian,公共领域,通过维基共享媒体

Streamlit 的优秀人员为我们提供了许多显示数据和图表的方法,也为设计数据科学应用程序提供了几种方法。

但是没有原生网格布局。

幸运的是,这很容易解决,我们将看到如何使用标准的 Streamlit 布局函数构建网格,然后创建一个简单的函数来创建任意维度的网格。

网格让我们以行和列的形式整齐一致地布置文本、数据和图表。例如,我用 2022 年联合国世界人口展望报告中的数据创建了一个 Streamlit 应用程序。其中,这份报告着眼于未来几十年世界人口将如何增长。这款应用基于《我们的世界》杂志的一篇文章(见注 1),外观如下:

作者图片

你可以在这里运行的应用

构建网格布局

稍后我们将查看该应用程序,但首先,我们将了解如何在 Streamlit 中构建网格布局。

当然,Streamlit 有内置的标准列。但是排呢?

实际上,是的,那些也是。如果我们将一堆 Streamlit 容器一个接一个地堆叠起来,我们就有了行。如果我们把这些容器分成相同数量的列,我们就有了一个网格。

看一下这段代码:

*# a 2x2 grid the long way*with st.container():
    col1, col2 = st.columns(2)
    with col1:
        st.write('Caption for first chart')
    with col2:
        st.line_chart((0,1), height=100)with st.container():
    col1, col2 = st.columns(2)
    with col1:
        st.write('Caption for second chart')
    with col2:
        st.line_chart((1,0), height=100)

清单 1

它通过堆叠两个容器并将每个容器分成两列来创建一个 2 x 2 的网格。每一行在右栏中有一个图表,在左栏中有一个标题。代码很容易理解并且运行良好。结果看起来像这样:

作者图片

对于这个简单的应用程序来说,这样做很好,但是如果我们要创建一个 10 x 10 的网格,代码可能会非常麻烦。

创建一个可以作为二维数组访问的网格不是更容易吗?因此,我们可以编写类似下面这样的代码,而不是我们上面看到的显式代码:

mygrid[0][0].write('Caption for first chart')
mygrid[0][1].line_chart((1,0), height=100)
mygrid[1][0].write('Caption for second chart')
mygrid[1][1].line_chart((0,1), height=100)

清单 2

我想你可能会同意,这是一种更简洁的方式来实现同样的事情,对于一个更大的网格将更容易管理。

因此,下一步可能是这样的:

*# 2x2 grid using an array*mygrid = [[],[]]with st.container():
    mygrid[0] = st.columns(2)
with st.container():
    mygrid[1] = st.columns(2)

清单 3

这里我们创建一个空的二维数组,然后在每个数组中,我们使用一个容器,并为每个数组元素分配两列。这给了我们一个二维数组,这使我们能够完全按照清单 2 中的方式编写代码。

同样,虽然这样做很好,但是将其扩展到更大的网格会导致更麻烦的代码。

通用解决方案

那么,我们写一个函数来创建一个任意维度的二维数组怎么样,2 x 2,3 x 2,10 x 10——随便什么。

这是:

*# make any grid with a function*def make_grid(cols,rows):
    grid = [0]*cols
    for i in range(cols):
        with st.container():
            grid[i] = st.columns(rows)
    return grid

清单 4

清单 4 中的函数将行数和列数作为参数。接下来,它创建一个一维数组,该数组是列的大小。(列表用零初始化——一个将被覆盖的任意值。)

然后,对于该数组的每个元素,我们创建一个 Streamlit 容器,并在该容器中创建所需数量的行(一个行列表)并将其分配给一维数组的每个元素,从而创建一个由函数返回的行和列组成的二维数组。

我们现在可以编写如下所示的代码:

mygrid = make_grid(5,5)mygrid[0][0].write('00')
mygrid[1][1].write('11')
mygrid[2][2].write('22')
mygrid[3][3].write('33')
mygrid[4][4].write('44')

清单 5

会产生这样的结果:

作者图片

当然,我们可以对这些网格元素使用任何适当的 Streamlit 函数,因此在清单 5 中的代码之后执行它

mygrid[2][2].line_chart((0,1), height=100)

清单 6

会给你这个:

作者图片

这里我们有一个创建任意大小和形状的网格布局的通用方法。让我们看看我是如何在世界人口应用程序中实际使用它的。

示例应用程序

该应用程序显示了联合国《2022 年世界人口展望》中的三个关键发现。它在数据中使用了我们世界中的两个数据文件,文本基于相同的来源(参见注释 1)。

每个调查结果有三行,每行包含三列:第一列是标题,第二列是简要描述,最后一列是图表。使用上述函数构建网格,使用 _ py plot _ frommatplotlib从数据文件构建图表。使用st.write()st.markdown()在适当的栏中显示文本。如果你遵循了上面的代码,你会发现代码很容易理解(代码的要点包含在最后)。

关于这个应用程序需要注意的一点是,它对各列的权重不同,因此标题列比其他两列窄一点。我们通过向make_grid()传递一个元组作为它的cols值来做到这一点。这被传递给产生我们想要的效果的st.columns()函数。

第一个发现是,世界人口增长率现在低于 1%,不到 20 世纪 60 年代的一半。

这一结果反映在第二个发现中,即尽管世界人口继续增长,但将在 2086 年达到 104 亿的峰值。

第三个发现是,虽然中国长期以来一直是地球上人口最多的国家——目前有 14 亿人——但自 20 世纪 70 年代和 80 年代以来,其增长率一直在下降。因此,印度的人口很可能在 2023 年超过中国,因为尽管其人口增长也在下降,但速度比中国慢。

结论

也许 Streamlit 将来会增加网格布局。但在此之前,我希望你会发现这是有用的。

你可以在我的 Github 网页上找到这里使用的所有代码和应用程序的完整列表,在文章的最后还有应用程序代码的要点。

感谢阅读。

笔记

  1. 数据和编辑文本由提供,数据中的我们的世界,根据知识共享署名 4.0 国际( CC BY 4 )转载

示例应用程序清单

如何在科技公司创造学习文化

原文:https://towardsdatascience.com/how-to-create-a-learning-culture-in-a-technology-company-801093837d50

这里有三种建立学习型组织的有效方法

蒂姆·莫斯霍尔德在 Unsplash 上的照片

HBR 强调科技和医疗保健行业的辞职率最高,因为这些行业的员工在疫情期间经历了需求的极度增长,这可能会导致工作量增加和倦怠。

作为一个在过去 20 年里一直在科技行业工作的人,我当然可以看到近几个月来工作量、倦怠和辞职的趋势。另一方面,我看到许多员工调查强调,员工参与度和幸福感的提高与他们对自己职业发展的感受直接相关。

忘掉免费食物、乒乓球桌甚至在家工作的预算吧,你的员工真正想要的是他们的职业发展。因此,对于技术领导者和管理者来说,在他们的技术公司创造一种学习文化比以往任何时候都更加重要。在这篇文章中,我想和你分享三种建立学习型组织的有效方法:

  1. 为经理提供工具和资源,帮助他们为直接下属制定个人发展计划
  2. 在常规活动中整合学习机会,如冲刺规划、演示和一对一
  3. 使用数据在整个公司范围内建立明确的投资和责任

1.为经理提供工具和资源,帮助他们为直接下属制定个人发展计划

虽然我非常相信个人要对自己的职业发展负责,但当他们的经理指导他们并支持他们的职业发展时,这总是有帮助的。这在个人和经理之间建立了信任关系,并增加了保留率。从我的职业规划测试中,我知道一个事实,大多数软件工程师属于变色龙群体——那些不知道他们在职业生涯中想要什么的人。如果没有一个好的经理在职业生涯中辅导和指导他们,这些软件工程师最终只会因为对目前的工作感到厌倦和不满而跳槽。

职业规划初学者工具包是工程经理可以得到的东西,以便开始采取行动,为他们的软件工程师提供职业发展机会。

如果您是一名工程经理,我希望您问问自己——在免费食物和乒乓球桌等办公室津贴不复存在的远程环境中,您如何让您的软件开发团队参与进来并保持高绩效?

嗯,答案很简单!投资于他们的职业发展。

如果你不确定从哪里开始,看看我为经理们制作的职业规划入门工具包。该入门套件包括—职业规划研讨会资料(如果您想为您的团队举办职业规划研讨会,还可提供额外的研讨会模板)和个人发展计划模板。

有了个人成长计划,每个员工都会知道他们需要获得什么技能,需要学习什么知识,需要进行什么活动。这反过来创造了一个学习型组织,因为每一个员工都在采取行动改善自己,造福公司。

2.在常规活动中整合学习机会,如冲刺规划、演示和一对一

我目睹的一个误解是,公司认为提供学习预算是创建学习型组织的解决方案。这与事实相去甚远,让我来解释一下原因。以我的经验,光靠学习预算是非常无效的。首先,一些人不知道它,因为这些信息没有被清楚地交流或重复共享。其次,许多人不使用它,因为他们不知道该学什么,或者他们在日常工作之外抽不出时间参加课程或培训。第三,那些利用学习预算来学习的人最终并没有为组织利用他们所学的东西。

那么,这里的解决方案是什么呢?公司停止提供学习预算了吗?绝对不行!解决方法是培养学习的应用。

作为一名工程经理,你可以通过在日常活动中整合学习机会来实现这一点,如冲刺规划、团队演示和一对一。让我们看一个实际的例子。在一家技术公司,有许多软件工程师,从毕业生到架构师都有。高级软件工程师和初级软件工程师的区别在于他们的影响力,更高的能力与更大的影响力相关。

常见的能力(按初级->高级的期望顺序排列)有:

  • 专门技能
  • 计划工作技能
  • 评估技能
  • 沟通技巧
  • 利益相关者管理技能
  • 影响技能
  • 指导技能

让我们选择评估技能作为工程团队中少数软件工程师需要改进的技能。工程经理不应该要求软件工程师接受评估技能培训,而应该鼓励他们使用不同的评估技术。然后,在 sprint 回顾中,整个团队将对估计和实际花费的时间进行回顾,讨论如果它们相差很大,为什么会有差异,下次如何估计得更好,等等。每个人都在学习,但他们可能没有意识到,因为学习机会已经很好地融入了团队的常规活动中。

3.使用数据在整个公司范围内建立明确的投资和责任

一个组织要成为学习型组织,支持和承诺应该来自高层。为此,整个公司应该有明确的投资和责任。

对于一个学习型组织来说,有两种方法可以证明这种投资。首先,通过正式任命一个人或一组人来管理学习和发展计划,协调计划,并作为其角色的一部分拥有明确的责任和成功标准。

其次,围绕学习和发展设定 S.M.A.R.T(具体的、可衡量的、可实现的、现实的、有时限的)目标,并跟踪这些目标。实施与学习相关的部门级 OKRs(目标和关键结果)是跟踪进展的一个好方法。主要结果的几个例子是:

  • 一年运送的实验数量
  • 按年度使用的学习预算百分比
  • 关于学习的季度调查问题的员工满意度得分。一个示例陈述可以是“我在上个季度学到了一些与我的职业目标一致的新东西”,并要求员工在 1-5 的范围内进行评分;1 是最不有利的,而 5 是最有利的。

基于数据的方法将确保对鼓励学习和发展的全公司计划进行投资,因为只有正确的计划才能帮助指标朝着正确的方向发展。

每个科技公司都应该体现一种学习文化

知识工作者,尤其是软件工程师,不仅仅是为了得到薪水而工作。他们来工作是为了很好地运用他们的技能,并接受智力挑战。对于软件工程师来说,没有比给他们有趣的问题来解决更好的智力挑战的方式了,通过与擅长他们工作的人一起工作来激励他们,最后但同样重要的是,给他们足够的机会来学习和发展他们的技能。

学习文化不仅会对员工的参与度和满意度产生积极影响,还会确保公司能够创新,并在这个不断变化和不断发展的技术环境中保持相关性。

首席技术官工具包——技术领导者的必备工具和资源

首席技术官工具包

你是一家科技公司的高级工程主管吗?你可能会对的首席技术官工具包感兴趣。它包含面向以下领域的高级技术领导者的资源和工具:

📝技术战略
💡卓越工程
⛳️组织设计
👍招聘
☑️职业发展
🚀对准&交付

看看这个,我保证你会更有能力在你的科技公司建立学习文化。

如何使用 Python 从地理空间数据创建地图

原文:https://towardsdatascience.com/how-to-create-a-map-from-geospatial-data-in-python-f4bb7d11ddad

使用 Folium 将印度尼西亚火山的位置数据绘制成地图

印度尼西亚爪哇岛的火山地图,用蟒蛇皮和树叶制成。图片作者。

我最近才学会如何用 Python 使用叶子实际创建一个地图来显示地理位置数据。我想我最好写下来,这样我就不会忘记怎么做了。在我接触到 leav 之前,我已经尝试过使用 Matplotlib 或 Plotly 等常用的可视化库。它们仍然工作,但不是我想象的那样。一旦我使用了叶,它就开始有意义了。所以我们开始吧。

作为一个例子,我将使用在印度尼西亚发现的火山的地理数据。请注意,全国至少有 127 座火山,从几个月前有喷发历史的活火山到没有已知喷发历史的火山。基本上,印度尼西亚是世界上活火山数量最多的国家。这听起来是可怕还是迷人,取决于你。

印度尼西亚博约拉里的默巴布山令人惊叹的景色。丹·吉尔摩在 Unsplash 上拍摄的照片。

收集数据

我从一个名为 MAGMA Indonesia 的政府网站上收集了火山数据,并将它们存储到一个 CSV 文件中。您可以将以上页面中的数据复制并粘贴到您选择的任何电子表格应用程序的表格中。或者你可以在这个 GitHub 库页面下载我准备好并格式化的文件。

我不是火山方面的专家,我只是碰巧一辈子都住在火山附近,所以我就按照数据和官方网站上说的去做。根据网站介绍,印度尼西亚有 3 种火山。

  • A 型共有 76 座,是自 16 世纪以来就有喷发历史的火山。
  • B 型,共 30 座,为 1600 年前有喷发史的火山。
  • C 型,共 21 座,是没有已知喷发历史,但仍有火山活动痕迹的火山,如索尔法塔拉或喷气孔。

加载和准备数据

因为我将数据保存为 CSV 格式,所以我可以使用 Pandas 加载它。

import pandas as pddf = pd.read_csv("Indonesian_volcanoes.csv")
df.head()

本文中使用的数据摘录。作者图片

然后,作为开始,我导入了 leav 库。

在这里找到我们地图的位置中心也很重要,它是数据中所有位置的平均经纬度。由于有火山横跨全国,这些经度和纬度基本上是在印度尼西亚的中心。我们将使用这个位置中心作为地图的中心。

手动输入定位中心也可以,但我更喜欢下面这种方式。

import foliumloc_center = [df['Latitude'].mean(), df['Longitude'].mean()]

蓝点中的火山

我们将把这张地图保存到一个名为 map1 的变量中。然后,我们可以开始使用叶创建地图。我使用 loc_center 中的位置作为地图的中心,并为 zoom_start 设置 5(完成后可以放大或缩小地图)。

地图图块有许多选项可用, OpenstreetmapMapboxStamenCartoDB 等等。我将使用最常见的一个,所以我使用 Openstreetmap 中的图块。

然后,我遍历了数据中的每座山,并为每座山的位置画了一个圈。弹出的是火山名称,所以当你在地图上点击它,它会显示山的名称。

map1 = folium.Map(location = loc_center, tiles='Openstreetmap', zoom_start = 5, control_scale=True)for index, loc in df.iterrows():
    folium.CircleMarker([loc['Latitude'], loc['Longitude']],     radius=2, weight=5, popup=loc['Volcano']).add_to(map1)folium.LayerControl().add_to(map1)map1

印度尼西亚的火山用蓝点表示。图片作者。

地图放大了。它展示了默拉皮火山,世界上最活跃的火山之一。图片作者。

你可以放大地图,点击每一个蓝点,就会显示出这座山的名字。总的来说,我已经对这张地图感到满意了。在这里你可以看到整个印度尼西亚和每个地区的山脉。

婆罗洲(加里曼丹)和巴布亚是印度尼西亚仅有的两个没有火山的大岛。那里有山,但是没有探测到火山活动。

现在,我想做更多的实验,比如我们把它们做成三角形,而不是圆点,怎么样?毕竟,山看起来确实像三角形,对吗?或者,如果我们根据火山活动的类型给山脉上色,就像我前面解释的那样,会怎么样呢?

根据火山的类型给它们上色

对于第二张地图,我将使用雄蕊地形作为地图的图块。我也用有三条边的正多边形标记器来做一个三角形来标记每座山。

对于 A 型火山(最活跃的火山),我把它们涂成红色。对于 B 型,我把它们涂成黄色,对于 C 型,它们是绿色。

map2 = folium.Map(location = loc_center, tiles='Stamen Terrain', zoom_start = 5, control_scale=True)for index, loc in df.iterrows(): if loc['Type']=='A':
        color = 'red'
    elif loc['Type']=='B':
        color = "yellow"
    elif loc['Type']=='C':
        color = 'green'
    else:
        color = 'black' folium.RegularPolygonMarker([loc['Latitude'],    loc['Longitude']], popup = loc['Volcano'], fill_color=color, number_of_sides=3, radius=6, rotation=30).add_to(map2)folium.LayerControl().add_to(map2)map2

根据火山活动用不同的颜色来表示火山。图片作者。

使用上一张地图中的不同贴图,你会得到一个稍微不同的外观。用不同的颜色表示每座山的火山活动,你可以很容易地分辨出哪些火山更活跃(红色),哪些火山不太活跃(黄色和绿色)。

您可以通过查看我将在参考资料部分链接的 Folium 文档来尝试不同的图块或不同的对象形状。

我希望你觉得这篇文章有用而且有趣。感谢阅读!

我在本文中使用的整个笔记本和数据都在下面我的 Github 存储库中。

https://github.com/catris25/Indonesian-Volcanoes-in-Folium

参考文献:

https://magma.esdm.go.id/v1/edukasi/tipe-gunung-api-di-indonesia-a-b-dan-c

如何使用 Python 创建蒙特卡洛模拟

原文:https://towardsdatascience.com/how-to-create-a-monte-carlo-simulation-using-python-c24634a0978a

演练一个示例,了解什么是蒙特卡罗模拟以及如何使用它来预测概率

马库斯·温克勒在 Unsplash 上的照片

什么是蒙特卡洛模拟?

蒙特卡罗模拟是一种计算算法,它估计由于涉及随机变量而导致的不可确定事件的发生概率。该算法依靠重复的随机抽样来确定概率。这意味着用随机输入模拟一个事件很多次,以获得你的估计。您也可以确定其他因素,我们将在示例中看到。蒙特卡罗模拟可以应用于广泛的领域,从经济、赌博、工程、能源到任何介于两者之间的领域。所以,无论你在哪个职业领域,这都是一件非常值得了解的事情。

当学习如何建立蒙特卡洛模拟时,最好从一个基本模型开始,以了解基本原理。最简单也是最常见的方法是简单的游戏,所以我们将在本文中使用一个骰子游戏。你可能听说过这样一句话,“赌场总是赢家”,所以在这个例子中,赌场(通常是赌场)将有优势,我们将展示这对玩家可能的收入意味着什么。

骰子游戏

我们的简单游戏包括两个六面骰子。为了赢,玩家需要在两个骰子上掷出相同的数字。六面骰子有六种可能的结果(1、2、3、4、5 和 6)。用两个骰子,现在有 36 种可能的结果(1 和 1,1 和 2,1 和 3,等等。,或 6×6 = 36 种可能性)。在这场游戏中,庄家有更多的机会获胜(30 个结果对玩家的 6 个结果),这意味着庄家有相当的优势。

假设我们的玩家开始时有 1000 美元的余额,并准备全部输掉,所以他们在每一次掷骰子时都下注 1 美元(意味着两个骰子都掷了),并决定玩 1000 次。因为赌场如此慷慨,当玩家赢的时候,他们提供玩家赌注的 4 倍。例如,如果玩家赢了第一轮,他们的余额增加 4 美元,他们结束这一轮的余额为 1004 美元。如果他们奇迹般地连胜 1000 场,他们可以带着 5000 美元回家。如果他们每轮都输了,他们可能会一无所有地回家。风险回报比并不差…或者可能是这样。

导入 Python 包

让我们模拟我们的游戏,看看玩家是否做出了正确的选择。我们通过导入必要的 Python 包开始我们的代码:py plotMatplotlibrandom 。我们将使用 Pyplot 来可视化我们的结果,并使用 random 来模拟普通的六面骰子滚动。

# Importing Packages
import matplotlib.pyplot as plt
import random

骰子滚动功能

接下来,我们可以定义一个函数,该函数将为两个骰子随机化一个从 1 到 6 的整数(模拟掷骰子)。该函数还将比较两个骰子,看它们是否相同。该函数将返回一个布尔变量 same_num ,用于存储卷是否相同。我们稍后将使用该值来确定代码中的操作。

# Creating Roll Dice Function
def roll_dice():
    die_1 = random.randint(1, 6)
    die_2 = random.randint(1, 6)

    # Determining if the dice are the same number
    if die_1 == die_2:
        same_num = True
    else:
        same_num = False
    return same_num

输入和跟踪变量

每一次蒙特卡洛模拟都需要你知道你的输入是什么,你希望获得什么信息。当我们描述这个游戏的时候,我们已经定义了我们的输入是什么。我们说过每场游戏的掷骰数是 1,000,玩家每掷的下注金额是 1 美元。除了我们的输入变量,我们还需要定义我们想要模拟游戏的次数。我们可以使用 num_simulations 变量作为我们的蒙特卡罗模拟计数。这个数字越大,预测的概率就越接近真实值。

我们可以跟踪的变量数量通常与项目的复杂程度成比例,所以明确你想要的信息是很重要的。在本例中,我们将跟踪每场模拟(或游戏)的获胜概率(每场游戏的获胜数除以总掷骰数)和期末余额。这些被初始化为列表,并将在每场游戏结束时更新。

# Inputs
num_simulations = 10000
max_num_rolls = 1000
bet = 1

# Tracking
win_probability = []
end_balance = []

设置图形

下一步是在运行模拟之前设置我们的图形。通过在模拟之前这样做,它允许我们在每次游戏后给我们的图形添加线条。然后,一旦我们运行了所有的模拟,我们就可以显示图表来显示我们的结果。

# Creating Figure for Simulation Balances
fig = plt.figure()
plt.title("Monte Carlo Dice Game [" + str(num_simulations) + "   
          simulations]")
plt.xlabel("Roll Number")
plt.ylabel("Balance [$]")
plt.xlim([0, max_num_rolls])

蒙特 卡罗模拟

在下面的代码中,我们有一个外部的 for 循环,它遍历我们预定义数量的模拟(10,000 次模拟)和一个嵌套的 while 循环,它运行每个游戏(1,000 次掷骰)。在我们开始每个 while 循环之前,我们将玩家的余额初始化为$1,000(作为用于绘图目的的列表)以及掷骰子和赢数。

我们的 while 循环将模拟游戏进行 1000 次掷骰。在这个循环中,我们掷骰子并使用从 roll_dice() 返回的布尔变量来决定结果。如果骰子是相同的数字,我们将 4 倍赌注加到余额列表中,并将一次胜利加到胜利计数中。如果骰子不同,我们从余额列表中减去赌注。在每一次掷骰子结束时,我们会在我们的 num_rolls 列表中添加一个计数。

一旦掷骰数达到 1000,我们就可以计算出玩家的获胜概率,即获胜数除以掷骰总数。我们还可以在跟踪变量 end_balance 中存储已完成游戏的结束余额。最后,我们可以绘制 num_rollsbalance 变量,为我们之前定义的数字添加一条线。

# For loop to run for the number of simulations desired
for i in range(num_simulations):
    balance = [1000]
    num_rolls = [0]
    num_wins = 0 # Run until the player has rolled 1,000 times
    while num_rolls[-1] < max_num_rolls:
        same = roll_dice() # Result if the dice are the same number
        if same:
            balance.append(balance[-1] + 4 * bet)
            num_wins += 1
        # Result if the dice are different numbers
        else:
            balance.append(balance[-1] - bet)

        num_rolls.append(num_rolls[-1] + 1)# Store tracking variables and add line to figure
    win_probability.append(num_wins/num_rolls[-1])
    end_balance.append(balance[-1])
    plt.plot(num_rolls, balance)

获得结果

最后一步是显示来自跟踪变量的有意义的数据。我们可以显示我们在 for 循环中创建的图形(如下所示)。此外,我们可以通过平均我们的 win_probabilityend_balance 列表来计算和显示(如下所示)我们的总体获胜概率和期末余额。

# Showing the plot after the simulations are finished
plt.show()

# Averaging win probability and end balance
overall_win_probability = sum(win_probability)/len(win_probability)
overall_end_balance = sum(end_balance)/len(end_balance)# Displaying the averages
print("Average win probability after " + str(num_simulations) + "   
       runs: " + str(overall_win_probability))
print("Average ending balance after " + str(num_simulations) + " 
       runs: $" + str(overall_end_balance))

骰子游戏模拟[由作者创建]

Average win probability after 10000 simulations: 0.1667325999999987
Average ending balance after 10000 simulations: $833.663

分析结果

任何蒙特卡罗模拟(或任何这方面的分析)最重要的部分是从结果中得出结论。从我们的图中可以确定玩家很少在 1000 掷后盈利。事实上,我们 10,000 次模拟的平均期末余额为 833.66 美元(由于随机化,您的结果可能略有不同)。因此,即使玩家赢了,庄家“慷慨”地支付了 4 倍于我们赌注的钱,但庄家还是赢了。

我们还注意到我们获胜概率大约是 0.1667,或者大约是 1/6。让我们想想为什么会这样。回到前面的一段,我们注意到玩家有 6 种可能获胜的结果。我们还注意到有 36 种可能的掷骰子。使用这两个数字,我们预计玩家将在 36 次掷骰中赢得 6 次,或者 1/6 次,这与我们的蒙特卡洛预测相匹配。相当酷!

结论

你可以用这个例子来发挥你的创造力,尝试不同的赌注,不同的掷骰子等等。如果你愿意,你也可以跟踪一些其他的变量。使用这个例子来熟悉蒙特卡洛模拟,并真正使它成为你自己的。更有趣的是,如果庄家支付 5 倍的赌注,玩家平均会与庄家持平。此外,如果他们支付的金额超过赌注的 5 倍,房子很可能最终会破产。如果你想看那些结果,请在评论中告诉我!这个简单的例子说明了为什么蒙特卡罗模拟和概率如此重要。

感谢您阅读文章!我希望这有助于你创建一个可靠的蒙特卡洛模拟!请关注我更多的 Python 相关文章,并查看我写的其他文章!

如何在 Python 中为您的数据分析创建 PDF 报告

原文:https://towardsdatascience.com/how-to-create-a-pdf-report-for-your-data-analysis-in-python-2bea81133b

作为数据分析的一部分,使用 FPDF 图书馆自动生成 PDF

使用 Python 和 FPDF 自动生成数据分析报告的 PDF(图片由作者提供)

一旦你完成了数据分析,你需要考虑如何传达结果。沟通一部分是决定您将以何种文件格式提供您的数据分析报告。我确信大多数利益相关者更喜欢 PDF 文件而不是 iPython 笔记本。

本文将讨论如何在数据分析工作流程中自动生成 PDF,包括:

对于本教程,我们将使用fpdf库[1]。

from fpdf import FPDF

虽然库没有被积极维护,并且自 2012 年 [1]以来没有更新过,但是它对于大多数用例来说都是简单易用的。如果您对 PDF 生成有更复杂的需求,您可以查看类似于 PyPDF2ReportLabWeasyPrint 的替代方案。

如何创建 PDF 文件

用 Python 中的fpdf库[1]生成 PDF 非常简单。要创建一个空的 PDF 文档,您需要创建一个类FPDF的实例,添加一个空白页,并用下面三行代码保存它。

pdf = FPDF()
pdf.add_page()
pdf.output(f'./example.pdf', 'F')

用 Python FPDF 中的三行代码创建的空 PDF 文档(图片由作者提供)

默认页面为纵向模式的 A4 格式,页边距为 1cm。您可以使用add_page()方法的参数定义自定义页面配置。

布局和放置文本

接下来,让我们了解文档的布局。

您可以使用cell()方法添加文本单元格。为了展示最终的布局,我们将设置参数border = 1,它显示单元格的边框。当您实现所需的设计时,您可以将参数值设置回 0。

使用wh参数,您可以定义文本单元格的宽度和高度。一个w = 0将产生一个横跨整个页面宽度的文本单元格。

ln参数定义了该单元格之后的位置:

  • 0:在当前单元格的右侧
  • 1:到下一行的开头
  • 2:在当前单元格下方

要在单元格之间创建空间,可以使用set_xy()方法为下一个元素指定一个特定的位置,或者使用ln()方法创建垂直空间。

下面你可以看到一些单元格及其布局的例子。您可以通过单元格名称找到相应的代码。

# Margin
m = 10 
# Page width: Width of A4 is 210mm
pw = 210 - 2*MARGIN 
# Cell height
ch = 50pdf = FPDF()
pdf.add_page()
pdf.set_font('Arial', '', 12)pdf.cell(w=0, h=ch, txt=**"Cell 1"**, border=1, ln=1)pdf.cell(w=(pw/2), h=ch, txt=**"Cell 2a"**, border=1, ln=0)
pdf.cell(w=(pw/2), h=ch, txt=**"Cell 2b**", border=1, ln=1)pdf.cell(w=(pw/3), h=ch, txt=**"Cell 3a"**, border=1, ln=0)
pdf.cell(w=(pw/3), h=ch, txt=**"Cell 3b**", border=1, ln=0)
pdf.cell(w=(pw/3), h=ch, txt=**"Cell 3c"**, border=1, ln=1)pdf.cell(w=(pw/3), h=ch, txt=**"Cell 4a"**, border=1, ln=0)
pdf.cell(w=(pw/3)*2, h=ch, txt=**"Cell 4b"**, border=1, ln=1)pdf.set_xy(x=10, y= 220) # or use pdf.ln(50)
pdf.cell(w=0, h=ch, txt=**"Cell 5**", border=1, ln=1)pdf.output(f'./example.pdf', 'F')

创建包含单元格的 PDF 布局(图片由作者提供)

页眉和页脚

您还可以指定 PDF 文档中每页显示的页眉和页脚。为此,您需要在自定义类中覆盖header()footer()方法。不要忘记使用自定义类的实例,而不是FPDF类。

# Custom class to overwrite the header and footer methods **class PDF(FPDF):**
    def __init__(self):
        super().__init__()
    **def header(self):**
        self.set_font('Arial', '', 12)
        self.cell(0, 10, 'Header', 1, 1, 'C')
    **def footer(self):**
        self.set_y(-15)
        self.set_font('Arial', '', 12)
        self.cell(0, 10, 'Footer', 1, 0, 'C')pdf = **PDF()** # Instance of custom class
pdf.add_page()
pdf.set_font('Arial', '', 12)
pdf.cell(w=0, h=255, txt = "Body", border = 1, ln = 1, align = 'C')pdf.output(f'./example.pdf', 'F')

用 Python 生成的 PDF 文档的页眉、正文和页脚(图片由作者提供)

如何向 PDF 文件添加文本

现在您已经了解了如何布局 PDF 文档,让我们用一些内容填充单元格。

样式文本

fpdf库为你提供了基本的文本样式:

  • 使用set_font()方法,您可以设置字体、字体大小和强调(常规、粗体、斜体)。
  • cell方法中,您可以用align参数定义文本对齐。
  • 要填充单元格的背景,您需要用set_fill_color()方法定义一种颜色,并在cell()方法中定义fill = True
  • 要改变单元格文本的颜色,可以用set_text_color()方法定义一种颜色。
pdf = FPDF()
pdf.add_page()pdf.set_font('Arial', **''**, 16)
pdf.cell(w=0, h=10, txt="This is **regular** text.", ln=1)pdf.set_font('Arial', **'B'**, 16)
pdf.cell(w=0, h=10, txt="This is **bold** text.", ln=1)pdf.set_font('Arial', **'I'**, 16)
pdf.cell(w=0, h=10, txt="This is **italic** text.", ln=1)pdf.set_font('Arial', '', 16) # Reset text back to regularpdf.cell(w=0, h=10, txt="This is **left** aligned text.", ln=1,   
         **align='L'**)
pdf.cell(w=0, h=10, txt="This is **center** aligned text.", ln=1,
         **align='C'**)
pdf.cell(w=0, h=10, txt="This is **right** aligned text.", ln=1,
         **align='R'**)pdf.**set_fill_color**(r= 0, g= 128, b = 0)
pdf.cell(w=0, h=10, txt="This is text with **filled** background.", ln=1,
         **fill=True**)pdf.**set_text_color**(r= 0, g= 128, b = 0)
pdf.cell(w=0, h=10, txt="This is **colored** text.", ln=1)pdf.output(f'./example.pdf', 'F')

生成的 PDF 中不同样式的文本:左对齐、居中对齐、右对齐、粗体和斜体文本、字体和背景颜色(图片由作者提供)

分行符和分页符

如果你需要一段更长的文本,cell()方法是不够的,因为它不允许换行或分页,正如你在下面看到的。

为此,您应该使用multi_cell()方法,它可以处理换行符和分页符。

import lorem # Use this package to showcase long textspdf = FPDF()
pdf.add_page()
pdf.set_font('Arial', '', 16)pdf.cell(w=0, h=50, txt="This and the below cells are regular cells." , border=1, ln=1)pdf.cell(w=0, h=50, txt="Example: " + lorem.text(), border=1, ln=1)pdf.**multi_cell**(w=0, h=50, txt="This and the below cells are multi cells.", border=1, )pdf.**multi_cell**(w=0, h=5, txt="Example: " + lorem.text(), border=1, )pdf.output(f'./example.pdf', 'F')

对于带有换行符和分页符的较长文本,使用 multi_cells,而不是常规单元格(图片由作者提供)

模板

根据到目前为止您所学的一切,您现在可以创建一个简单的模板,如下所示。我们将在下面的例子中使用它。

# cell height
ch = 8class PDF(FPDF):
    def __init__(self):
        super().__init__()
    def header(self):
        self.set_font('Arial', '', 12)
        self.cell(0, 8, 'Header', 0, 1, 'C')
    def footer(self):
        self.set_y(-15)
        self.set_font('Arial', '', 12)
        self.cell(0, 8, f'Page {self.page_no()}', 0, 0, 'C')pdf = PDF()
pdf.add_page()
pdf.set_font('Arial', 'B', 24)
pdf.cell(w=0, h=20, txt="Title", ln=1)pdf.set_font('Arial', '', 16)
pdf.cell(w=30, h=ch, txt="Date: ", ln=0)
pdf.cell(w=30, h=ch, txt="01/01/2022", ln=1)
pdf.cell(w=30, h=ch, txt="Author: ", ln=0)
pdf.cell(w=30, h=ch, txt="Max Mustermann", ln=1)pdf.ln(ch)
pdf.multi_cell(w=0, h=5, txt=lorem.paragraph())pdf.ln(ch)
pdf.multi_cell(w=0, h=5, txt=lorem.paragraph())pdf.output(f'./example.pdf', 'F')

用 Python 生成的 PDF 模板(图片由作者提供)

对于下面的例子,我们将使用一个小的虚构数据集。

import pandas as pddf = pd.DataFrame(
          {'feature 1' : ['cat 1', 'cat 2', 'cat 3', 'cat 4'],
           'feature 2' : [400, 300, 200, 100]
          })

虚构数据集导入为熊猫数据帧(图片由作者提供)

如何将 Matplotlib 图作为图像添加到 PDF 文件中

除了文本,您可能需要在 PDF 报告中添加绘图。

要将图添加到 PDF 报告中,首先需要将 Matplotlib 图保存为图像(例如,PNG 文件)。

import matplotlib.pyplot as plt
import seaborn as snsfig, ax = plt.subplots(1,1, figsize = (6, 4))sns.barplot(data =  df, x = 'feature 1', y = 'feature 2')
plt.title("Chart")plt.**savefig**('./example_chart.png', 
           transparent=False,  
           facecolor='white', 
           bbox_inches="tight")

Matplotlib 绘图保存为 PNG 文件(图片由作者提供)

一旦您的 Matplotlib 绘图被保存为图像,您就可以使用image()方法将其添加到报告中。

pdf = PDF()
pdf.add_page()
pdf.set_font('Arial', 'B', 24)
pdf.cell(w=0, h=20, txt="Title", ln=1)pdf.set_font('Arial', '', 16)
pdf.cell(w=30, h=ch, txt="Date: ", ln=0)
pdf.cell(w=30, h=ch, txt="01/01/2022", ln=1)
pdf.cell(w=30, h=ch, txt="Author: ", ln=0)
pdf.cell(w=30, h=ch, txt="Max Mustermann", ln=1)pdf.ln(ch)
pdf.multi_cell(w=0, h=5, txt=lorem.paragraph())**pdf.image('./example_chart.png', 
          x = 10, y = None, w = 100, h = 0, type = 'PNG')**pdf.ln(ch)
pdf.multi_cell(w=0, h=5, txt=lorem.paragraph())pdf.output(f'./example.pdf', 'F')

用 Python 将 Matplotlib 绘图添加到 PDF 报告中(图片由作者提供)

如何将熊猫数据帧作为表格添加到 PDF 文件中

不幸的是,没有简单的方法可以用FPDF库将熊猫数据帧添加到 PDF 报告中。尽管将 pandas 数据帧作为表格添加到 PDF 报告需要一些简单的编码,但这也并不困难:通过使用带有border=1cell()方法并有效利用ln参数,您可以迭代数据帧来创建表格。

pdf = PDF()
pdf.add_page()
pdf.set_font('Arial', 'B', 24)
pdf.cell(w=0, h=20, txt="Title", ln=1)pdf.set_font('Arial', '', 16)
pdf.cell(w=30, h=ch, txt="Date: ", ln=0)
pdf.cell(w=30, h=ch, txt="01/01/2022", ln=1)
pdf.cell(w=30, h=ch, txt="Author: ", ln=0)
pdf.cell(w=30, h=ch, txt="Max Mustermann", ln=1)pdf.ln(ch)
pdf.multi_cell(w=0, h=5, txt=lorem.paragraph())pdf.image('./example_chart.png', x = 10, y = None, w = 100, h = 0, type = 'PNG', link = '')pdf.ln(ch)
pdf.multi_cell(w=0, h=5, txt=lorem.paragraph())pdf.ln(ch)**# Table Header
pdf.set_font('Arial', 'B', 16)
pdf.cell(w=40, h=ch, txt='Feature 1', border=1, ln=0, align='C')
pdf.cell(w=40, h=ch, txt='Feature 2', border=1, ln=1, align='C')****# Table contents
pdf.set_font('Arial', '', 16)
for i in range(0, len(df)):
    pdf.cell(w=40, h=ch, 
             txt=df['feature 1'].iloc[i], 
             border=1, ln=0, align='C')
    pdf.cell(w=40, h=ch, 
             txt=df['feature 2'].iloc[i].astype(str), 
             border=1, ln=1, align='C')**pdf.output(f'./example.pdf', 'F')

熊猫数据框架作为 Python 中的表格添加到 PDF 报告中(图片由作者提供)

从技术上讲,你也可以将你的 pandas DataFrame 转换成 Matplotlib 表格,将其保存为图像,并将该表格作为图像插入 PDF 。但我试过了,所以你不必这样做:它不是很漂亮。

结论

尽管批评家说有比fpdf库更好的选择,但它使用起来很简单。

本文向您展示了:

下面您可以复制生成以下 PDF 的模板代码,并根据您的需要进行调整。

喜欢这个故事吗?

如果你想把我的新故事直接发到你的收件箱, 订阅

成为媒介会员,阅读更多其他作家和我的故事。报名时可以用我的 推荐链接 支持我。我将收取佣金,不需要你额外付费。

https://medium.com/@iamleonie/membership

上找我LinkedInka ggle**

参考

[1]“Python 的 FPDF”,“PyFPDFhttps://pyfpdf.readthedocs.io/en/latest/(2022 年 10 月 22 日访问)

如何在 GitHub 上创建专业作品集,帮助你在数据科学领域找到第一份工作

原文:https://towardsdatascience.com/how-to-create-a-professional-portfolio-on-github-that-will-help-land-your-first-job-in-data-science-e1fc8bd7a797

你的投资组合在告诉雇主为什么他们应该雇用你方面起着至关重要的作用。

叶振宇Unsplash 上拍照

你参考的每一条关于在数据科学领域找到工作的建议都会谈到拥有一个展示你的工作的专业作品集的重要性,并让雇主有机会深入了解你的个人项目。

作品集不仅能让雇主看到你的代码的质量和思维过程,还能让他们有机会看到你是否有主动性去着手自己的项目,以及是否有能力创建个人项目来产生影响或解决现实世界的问题。

GitHub 是行业标准,这使它成为托管和维护您的专业投资组合的理想场所。此外,它的其他功能,如提交历史或贡献日历,为雇主提供了一个你如何定期添加和维护你的投资组合的想法。

特别是对于自学成才的数据科学家来说,投资组合在决定雇主是否邀请你参加面试方面可以发挥关键作用,并可以提供关于你如何融入公司的背景信息。虽然它可能在你获得第一份数据科学家工作的过程中发挥较小的作用,但不能低估可靠、专业的数据科学组合的价值。

你的投资组合中应该包括什么

个人项目

个人项目是你在数据科学投资组合中最常发现的,可以包括从泰坦尼克号分析(尽管你可能不想包括这个过度的主题)到气候建模的一切。

为个人项目创意茫然?查看 Kaggle 上的数百个数据集以获取灵感,看看其他人在 Youtube 上建立了什么,或者与您所在地区的小企业交谈,看看您是否可以帮助他们使用数据解决问题。

虽然个人项目不一定要与你申请的行业完全相关,但向雇主展示你处理过相关数据,并能够得出实际的见解是有益的。不仅如此,它还能帮助你了解在一个给定的行业中需要解决什么样的问题,以及解决这些问题的不同方法,从而让你在竞争中占据优势。

作业或课堂项目

作业和课堂项目是一个很好的想法,尤其是对于即将到来的本科生或硕士生或通过训练营或在线学习项目自学的数据科学家来说。

它们可能不是最令人兴奋的项目,但它们确实增加了内容,可以让雇主了解你作为数据科学家的进展。这也可能引起雇主的兴趣,看看他们现在在学校教什么。

出于上下文的原因,包括作业的描述、你试图达到的目标,甚至你的分数和指导老师的评论(如果有的话)也是有益的。

黑客马拉松或竞赛参赛作品

没有什么能像黑客马拉松或参赛作品那样向雇主展示你能够在紧张的条件下按时完成工作。

完成比赛后,在将代码添加到作品集之前,清理代码是个好主意。在代码文档中包括竞赛名称、日期、竞赛持续时间、竞赛描述和您试图解决的问题、竞赛环境信息(例如,团队或个人、会议厅或家中等)。),你如何解决问题的细节,甚至可能是竞赛的结果。

黑客马拉松或竞赛参赛作品不一定要与你申请的工作相关,因为雇主会用它们来确定你在压力下如何工作,你在短时间内能完成的工作质量,以及你是否能在问题交给你后不久解决问题。

博客帖子、文章、社交媒体帖子等。

作为一名 STEM 交流者,我知道能够向他人传授一些东西或者能够指导他人完成你所经历的重要过程的价值。

例如,我利用我的教育和技术背景帮助其他人实现他们的目标,学习新的编程语言,自学困难的概念,并获得该领域的第一份工作。我通过博客、文章和社交媒体来做这些事情。这些媒介能够向雇主展示我的软技能,比如我沟通、教学、写作、展示和讲故事的能力。

把博客文章、文章、社交媒体文章等放入你的文件夹中,这不仅是展示你的软技能的好方法,正如我之前提到的,而且也让雇主知道你将如何融入一家公司,以及你是否能够在以后的日子里获得提升。此外,这些关键部分向雇主展示了你的能力范围,甚至是你日常工作之外的兴趣。

创建您的投资组合

  1. 选择一个模板:谷歌“github 页面的 html 模板”(或类似的东西),你会发现几个预先制作的模板,其中将包括 HTML、CSS 和 JavaScript 文件,这些文件都可以在 GitHub 页面上托管。这些模板是现成的,只需要一些调整就可以根据您的需求进行定制。自述文件通常包括您需要了解的关于安装模板的所有内容、包含的文件、其他有用的资源和许可信息。
  2. 修改模板以满足您的需求:这一部分将需要一点 HTML 知识,可能还需要 CSS(尽管,如果您已经经历了学习数据科学的过程,学习足够的 HTML 以修改您的作品集将是小菜一碟)。这一部分将包括添加您的所有个人信息。
  3. 在 GitHub 上托管作品集,并填充项目:这是你的作品集上线的地方,免费!我不能改进在这里找到的的教程,它可以完全遵循在 GitHub 上托管文件夹。

如何开发专业的投资组合,帮助你获得数据科学领域的第一份工作

自述文件中应包含哪些内容

  • 写一份介绍,告诉雇主他们能从你的投资组合中找到什么:如果你已经让雇主看了你的投资组合,那么恭喜你!你已经通过了招聘人员给每份简历的 7.4 秒的关键窗口,并且已经吸引了他们足够长的时间来引导他们关注你的简历。雇主应该看到的第一件事是一份简明扼要的描述,描述他们希望在你的投资组合中找到什么。信息丰富,切中要点,明确你所包含的项目,以及它们所属的类别(个人项目,课堂作业,黑客马拉松参赛作品,文章等等。)
  • 使用带有导航链接的目录:如果你像我们大多数人一样,你的自述文件更像是一部包含大量相关信息的短篇小说。不管你写得多短多甜,你可能会开始写几千字而不是几百字。在这种情况下,通过创建一个包含导航链接的描述性目录来帮助雇主,帮助他们准确地跳转到他们正在寻找的内容(此外,您需要在每个部分的末尾包含返回目录的导航链接,以方便快速轻松地阅读)。
  • 添加对每个项目的简短描述,以及在存储库中找到的每个项目中的每个文件:正如我之前所描述的,你需要描述雇主可以在你的文件夹中找到的每个项目。该描述可以包括子描述,这些子描述描述了他们可以在项目文件夹中找到的每个文件。这需要你做一些额外的工作,但是雇主会对你在浏览作品集时的细节和想法印象深刻。
  • 使用标题和下拉框等格式选项,让你的自述文件更具可读性:阅读本文时,你会注意到它的可浏览性——也就是说,你可以轻松地浏览文章并收集相关细节,而不必逐行阅读。我通过使用清晰的格式和标题做到了这一点,这也是你在自述文件中应该努力做到的。自述文件具有巨大的自定义潜力,这意味着您可以使用标题、分栏线、项目符号、下拉列表、表格等来组织您的文件。雇主只有很短的时间浏览候选人的作品集,所以你必须让他们尽可能容易地找到他们想要的。

如何在将代码推送到存储库之前清理代码

  • 将你的导入放在顶部:一个古老的软件工程最佳实践,当雇主开始筛选文件中的代码时,将你所有的导入放在顶部是为他们定下基调的一个好方法。导入允许他们立即看到你在使用什么工具。不仅如此,这对您来说也是一个很好的实践,因为它提高了可读性和代码优化。
  • 遵循语言惯例:不管你用什么语言写数据分析,确保你使用了正确的语言惯例。每种编码语言都有自己的一套约定,应该遵循这些约定来确保任何阅读您的代码的人都能理解它在做什么。
  • 在代码中维护代码文档,并在项目存储库中提供支持文档:代码文档是帮助雇主理解你的代码应该做什么,为什么你要这样写,以及它如何与其他代码一起工作的最佳方式。内联代码文档(又名注释)提供了对您的逻辑、思维过程的清晰一瞥,并且还提供了您的代码所说内容的英文版本。此外,它有助于将变量和函数结合成一个易于理解的故事,任何第一次看代码的人都可以理解。
  • 使用准确的变量和函数名帮助别人理解你的代码:在个人项目中,很容易陷入用模糊的名字称呼变量和使用只有你自己能理解的函数名的陷阱。这在你独自做一个项目的时候很好(虽然我不建议继续这个习惯),但是在你把它放入你的文件夹之前,你应该确保你的变量名和函数名是清晰的,并且尽可能具有描述性。这有助于雇主第一次看到你的代码,并确切地知道你想要完成什么。

最后的想法

专业数据科学投资组合的价值不可低估,尤其是当你正在寻找该领域的第一份工作时。因为你几乎没有适用的工作经验,雇主会用你的投资组合来衡量你是否适合公司,以及你的技术技能和软技能。令人印象深刻的投资组合是一种很好的陈述方式,也是从其他候选人中脱颖而出的一种方式,因此,使用这里提供的提示投入一些时间和精力,可以在你获得数据科学领域的第一份工作时产生有价值的结果。

订阅让我的故事直接发到你的收件箱:故事订阅

请成为会员,使用我的推荐链接获得无限制的媒体访问权限(我将免费向您收取少量佣金):媒体会员

通过捐赠来支持我的写作,以资助更多像这样的故事的创作:捐赠

如何创建可重现的数据科学项目

原文:https://towardsdatascience.com/how-to-create-a-reproducible-data-science-project-682d3a1b98ed

Anaconda 项目初学者指南

索菲娅·杨艾伯特·德弗斯科拍摄

照片由克里斯·巴尔巴利斯Unsplash 上拍摄

创建可重复的数据科学项目非常重要。数据科学家需要能够与其他人共享项目,并确保其他人能够产生相同的结果。在我们看来,可再生数据科学集中在三个领域— 可再生代码(例如使用 Git )、可再生代码行为(例如编写测试)和可再生环境

在创建数据科学可复制环境方面,大多数数据科学家都熟悉 conda (针对 conda 用户)或 venv (针对 Pip 用户)。一个不太为人所知但强烈推荐的选择是 Anaconda 项目。它是一个 YAML 文本文件,有助于创建一个可再现的数据科学项目,并且不限于可再现的环境。Anaconda 项目具有以下特性:

  • 它指定了 Conda 和 Pip 包来创建可复制的环境。
  • 它将数据下载到项目中。
  • 它会跟踪您想要执行的命令。
  • 它允许您设置环境变量。
  • 它易于共享,并提供了上传到 Anaconda Cloud 的选项。
  • 它用一个简单的 CLI 命令构建 docker 映像。

一个例子

下面是 anaconda-project.yml 的样子。在本例中,我们已经定义了包/依赖项、可执行命令和环境变量。

如何安装 Anaconda 项目?

如果您还没有安装 Anaconda 或 Miniconda,请先安装它们。那么您应该可以在您的终端中访问conda。然后在命令行中,键入conda install anaconda-project来安装 Anaconda 项目。

如何创建项目?

  • 要从头开始创建项目,请运行
anaconda-project init

然后,您将看到在您的目录中创建了一个“anaconda-project.yml”文件。

  • 要从现有的 Conda 环境中创建一个项目,运行
conda env export –from-history environment-name > anaconda-project.yml

如何添加包?

要添加包(例如,本例中的 pandas 和 numpy),您可以运行anaconda-project add-packages pandas numpy来添加 Conda 包,或者运行anaconda-project add-packages --pip pandas numpy来添加 Pip 包。然后,您应该会看到这些包出现在您的 anaconda-project.yml 文件中。

如何添加环境变量?

Anaconda 项目允许用户通过运行

anaconda-project add-variable --default=default_value VARIABLE

如何添加可执行命令?

例如,如果您的目录中有一个 Python 文件“hello.py ”,那么您可能想要运行python hello.py来运行这个代码。使用 Anaconda Project,您可以通过运行anaconda-project add-command hello “python hello.py"在 anaconda-project.yml 文件中添加这个可执行命令。然后,我们可以简单地运行anaconda-project run hello,而不是激活您的环境然后运行python hello.py,这将在您在 anaconda-project.yml 文件中定义的环境中自动运行这段代码。多简单啊!

类似地,您可以添加一个命令来启动 Jupyter 笔记本或 Python 应用程序。例如,这里我们添加了一个名为“notebook”的命令来启动笔记本,另一个名为“app”的命令来启动应用程序

anaconda-project add-command notebook notebook.ipynbanaconda-project add-command app “panel serve notebook.ipynb”

然后我们可以运行anaconda-project run notebookanaconda-project run app来启动笔记本和应用程序。

如何分享一个项目?

共享项目有三种方式:

  • 我们可以直接在您的中创建一个归档文件:
anaconda-project archive filename.zip

然后,您将看到您的项目文件保存为 filename.zip。

  • 我们还可以将我们的项目上传到 Anaconda Cloud:
anaconda-project upload
  • 我们还可以创建一个 Docker 图像:
anaconda-project dockerize

其他的

如果您对 yaml 文件进行了大量的修改,您可以使用anaconda-project prepare --refresh从头构建环境。

要锁定项目,请运行anaconda-project lock。您可以使用anaconda-project add-packages添加包。但是如果直接编辑anaconda-project.yml,可以运行anaconda-project update更新anaconda-project-lock.yml来匹配。

通过使用 Anaconda Project,您不仅可以创建可再现的环境,还可以在您的数据科学项目上创建可再现的可运行命令和配置。试一试,让我们知道你的想法。

参考资料:

https://anaconda . cloud/webinars/making-reproducible-conda-based-projects?UTM _ medium = web&UTM _ source = Anaconda-com&UTM _ campaign = Webinar

https://anaconda-project . readthedocs . io/en/latest/index . html

https://towards data science . com/testing-for-data-scientists-1223 fcad 4 AC 2?sk = bde 5487 Fe 3 ad 11 a 06 AE 3a 92 ed 80d 451 b

https://towardsdatascience . com/git-workflow-for-data-scientists-c 75445 f 23 f 44?sk = 579671 f 9 FCC 2000 BFF 07 BDC ba 4777 BCD

https://docs . conda . io/projects/conda/en/latest/user-guide/tasks/manage-environments . html

索菲亚·杨阿尔伯特·德福斯科于 2022 年 3 月 15 日

如何为您的数据项目创建抽样计划

原文:https://towardsdatascience.com/how-to-create-a-sampling-plan-for-your-data-project-3b14bfd81f3a

当简单的随机抽样不是那么简单的时候

第一部分中,我们看到简单随机抽样(SRS)在实践中并不总是简单。当你处理现实世界时,数据设计可能是一个怪物。

故事到此为止

假设你是一名数据科学家,受雇估算下图森林中松树的平均高度,并描述分布。你负责计划和分析,所以当一个狂热的徒步旅行者执行你的指示去测量森林中的树木时,你可以在你舒适的巢穴中幕后操纵。

你绝对不会做的是指示徒步旅行者 “完全随机地选择 20 棵树。” (如果你动心了,请回到第一部分。)

这片森林里的树有多高?照片由丹·奥蒂斯Unsplash 拍摄

相反,总是努力给出万无一失的指示,因为你永远不知道一个野傻子什么时候会出现。

永远努力给出万无一失的指令,因为你永远不知道一个野傻子什么时候会出现。

简单明了的说明

当我要求我的学生为数据收集代理(徒步旅行者)给出更好的——更简单的——指示时,团队通常会给出一个古老的经典建议:

用一个唯一的数字来标识每棵树,然后随机抽取这些 id

这更好了——至少它不再包括“仅仅”这个词——但这仍然不是专业统计学家级别的答案。专业的统计学家心碎了很多次,他们知道细节决定成败。

塞巴斯蒂安·赫尔曼在 Unsplash 上拍摄的照片

魔鬼在(现实世界)细节中

在专业统计学家的头脑中,这一看似无辜的指令会迅速滚雪球般变成一大堆细节:

“亲爱的徒步旅行者,让我提前道歉,但你必须穿过整个森林一次,用唯一的 id 给所有的树编号…这就是你喜欢徒步旅行的原因!”

甚至在我们说完之前,我们的大脑就已经在飞速运转:

用什么颜料?(写下来!等等,我们可能需要多少桶油漆?(写下来!)
如果油漆用完了我们怎么办(因为我们不知道森林里有多少棵树)。(写下来!)
我们在哪里可以买到更多桶的油漆?最近的城镇在哪里?(写下来!)
我们工作的时候,把桶放在哪里会更有效率?(写下来!)
我们如何确保合理地标记这些树,以便在抽中它们的号码时能够有效地再次找到它们?(写下来!我们需要一辆手推车吗?或者一些助手?(写下来!)
我们如何确保没有漏掉一棵树?(写下来!我们预计这一切需要多长时间?(写下来!)
如果徒步旅行者中途退出项目怎么办?(写下来!)
下雨掉漆怎么办?(写下来!这些总共要花多少钱?(写下来!)
如果计划比预期的更昂贵,我们的旋转计划是什么?(写下来!)
我们的预算是多少?(写下来!)

https://kozyrkov.medium.com/the-obscure-art-of-data-design-397ffb230596

替代抽样方案

啊,预算。当你开始详述你的计划时,你可能会发现你的理想方法是不可行的。在这种情况下,你有两个选择。

  1. 选择不同的采样程序。 SRS 并不是您唯一可用的方法,它甚至不一定是满足您需求的统计优势方法。它的主要优点是允许你使用初学者的技术,但是如果你发现在现实世界中完成 SRS 比雇佣懂得高级方法的人更昂贵,那么这是一个很好的选择。请记住,使用其他采样程序意味着您 必须 以不同于 STAT101 教您的标准方式分析数据(除非您选择下面的选项 2)。
  2. 假设 带走问题。这是绝望中的经典捷径,你会在科学中发现它。它本质上可以归结为这样一句话:即使你知道某些事情不是真的,你也会像它们是真的一样进行你的分析。这是一个哲学上站不住脚的领域,唯一有权批准继续进行的人是决策者,他可能愿意接受一个低质量的决策程序来节约资源。如果你不是负责做出数据驱动决策的人,你就没有资格做这个决定。

但是,让我们想象一下,你的徒步旅行者是如此渴望尽可能长时间地在森林里闲逛(哇哦),以至于他们为你提供了这个项目的统一价格。现在你可以让这位户外狂热者为你粉刷所有的树木了。是时候开始计划下一步了:随机选择 20 棵树。

我们如何“仅仅”选择其中的 20 个呢?一个非常简单的方法是等到所有的树都被涂上唯一的 id,然后将所有的树 id 放入电子表格的一列中,拖动=RAND()函数通过相邻的列,并按照随机数列的顺序排序,然后选择混排的表格顶部的前 20 个 id。

现在我们担心更多的细节:

标签应该是整数还是别的?(写下来!)
如果它们很难读懂怎么办?(写下来!)
我们确定随机数生成器是随机的吗?(写下来!)
如果我们忘记只粘贴特殊值怎么办?(写下来!我们打算带笔记本电脑去森林吗?哪一个?(写下来!)
没有 Wi-Fi 软件还能用吗?(写下来!)
笔记本电池够用吗?(写下来!)
我们需要备用笔记本电脑吗?(写下来!)

一旦我们有了 20 个随机选择的树 id——保存在哪里?(写下来!是时候为可能不得不再次徒步穿越森林向徒步者道歉了。希望我们已经想出了一个有效的徒步旅行策略来节省时间,因为这个可怜的徒步旅行者已经筋疲力尽了。但是还有更多!

维基百科上关于使用高度计测量海拔的图片:https://en.wikipedia.org/wiki/Hypsometer

徒步旅行者将如何进行测量?(写下来!我们应该使用哪种仪器?一个 高度计 ?(写下来!)
我们如何确保徒步旅行者经过适当培训,能够正确使用设备?(写下来!)
如果树在斜坡上
或者被遮挡 怎么办?(写下来!我们可能需要什么额外的设备?(写下来!)
将在哪里记录测量值?纸?笔记本电脑?电话?我们有没有计划好如何搬运它,如果它出现故障该怎么办?(写下来!)
徒步旅行者是否明白测量值应记录在树 ID 旁边?树的高度是徒步旅行者唯一需要测量和记录的吗?当然,还有一些额外的信息可能是有用的,而且获取起来相对便宜,包括一天中的时间、树木的物理特征、离徒步旅行者出发点的距离、与阳光和土壤养分竞争相关的半径内其他树木的数量(半径是多少?),树的周长,还有很多。(写下来!但是如果你和我一样,对树木知之甚少,先和领域专家谈谈。)
如果我们为每个 ID 记录一堆附加属性,应该如何记录它们?徒步旅行者应该使用什么样的数据模式?(写下来!)
我们如何检查错误?徒步旅行者应该进行额外的检查吗?(写下来!我们如何验证徒步旅行者正确地遵循了指示?(写下来!)
对于我们正在记录的每个属性,徒步旅行者应该使用哪个
单位或类别 ?(写下来!)

在今天结束之前,我们将仔细检查我们的文件,充实更多的细节。如果你在编写详细说明方面做得很差,你最终会因为数据收集代理带来的混乱而憎恨他们(因为这不会是你认为你要求的)。你的数据收集代理理所当然地会讨厌你给他们愚蠢的指令,并期望他们能读懂你的想法。

总有一天,数据收集代理会成为你,然后你会恨你。

抽样计划涵盖了数据收集的实际方面。

这就是我们如何在工作中艰难地学习的。我多年来养成的成熟的数据卫生习惯是由对我以前的糟糕规划的愤怒所推动的。年轻的我最关心的是数学。时间浸泡过的我对真实世界的细节更感兴趣。我希望你能从我的错误中吸取教训,这样你就不必再犯同样的错误了。

请向我保证,你不会再指示别人“随便”取一个简单的随机样本。

布雷特·乔丹在 Unsplash 上的照片

抽样检验方法

在你担心了很多细节之后(写下来!),你面前的这份文件叫做抽样计划

抽样计划涵盖了现实世界中数据收集的实际方面,在没有抽样计划的情况下从现实世界中记录数据是非常业余的。如果你试图跳过计划,你最终会为即将到来的重来做一次非常昂贵的彩排。

抽样方案

现在你已经写下了理论部分(抽样程序)和实践部分(抽样计划),你已经准备好将它们合并成一个叫做抽样方案的文件。

抽样计划+抽样程序=抽样方案

顺便说一句,当你从供应商那里购买数据时,你应该总是要求完整的抽样方案(计划,而不仅仅是程序),以确保你理解你的数据实际上意味着什么。要了解更多关于使用次级(继承)数据的技巧,包括购买的数据,请参见我的指南这里

一个真正的专业人士在建立一个完整的抽样方案之前不会想到收集数据。不幸的是,数据学院的课程教授方式——理论多,实践少——往往需要一段时间,刚毕业的小鸭才开始像真正的专业人士。我们这些已经在游戏中有一段时间的人可以通过啦啦队关注实际方面来尽自己的一份力量。毕竟,如果细节令人生厌,那么所有花哨的数学又有什么意义呢?

感谢阅读!人工智能课程怎么样?

如果你在这里玩得开心,并且你正在寻找一个为初学者和专家设计的有趣的应用人工智能课程,这里有一个我为你制作的娱乐课程:

在这里欣赏整个课程播放列表:bit.ly/machinefriend

https://kozyrkov.medium.com/membership

附:你有没有试过在 Medium 上不止一次地点击拍手按钮,看看会发生什么? ❤️

了解更多关于数据设计的重要性

https://kozyrkov.medium.com/the-obscure-art-of-data-design-397ffb230596

喜欢作者?与凯西·科兹尔科夫联系

让我们做朋友吧!你可以在 TwitterYouTubeSubstackLinkedIn 上找到我。有兴趣让我在你的活动上发言吗?使用表格取得联系。

如何用 Python 创建一个简单的神经网络模型

原文:https://towardsdatascience.com/how-to-create-a-simple-neural-network-model-in-python-70697967738f

用 Scikit 建立一个简单的神经网络——学习预测测井测量

图片由皮克斯拜的 Gerd Altmann 提供

神经网络是一种流行的(大部分)监督机器学习算法。它们可以用于模拟各种复杂的任务,如图像处理、欺诈检测、语音处理等。这些算法可以应用于基于回归的问题以及基于分类的问题。

在岩石物理学和地球科学中,我们可以使用神经网络来预测缺失的测井测量值,创建合成曲线或从离散采样数据创建连续曲线。

在本文中,我将向您展示如何使用scit kit-learn创建一个简单的 人工神经网络模型 。我们将把该模型应用于预测测井测量值的任务中,而测井测量值通常在油井测量值中不存在。

什么是人工神经网络?

神经网络,或有时被称为人工神经网络(ANN ),是由一系列功能形成的,这些功能是受人脑解决问题的方式的启发。

给定一个已知的目标变量和一系列已知的输入,它们“学习”,或者更确切地说,被训练来识别数据中的模式。人工神经网络由包含节点的多层组成。

通常有:

  • 单个输入图层,其中包含模型接受训练和应用的要素
  • 存在于输入层和输出层之间的多个隐藏层,可以是单层或多层
  • 单一输出层,包含我们的目标变量

一种单层神经网络模型,采用多个测井测量值并预测单个连续目标变量。图片作者——麦克唐纳(2022)。

如果你想更多地了解人工神经网络是如何工作的,我建议你阅读下面的文章。

https://www.ibm.com/cloud/learn/neural-networks

使用 Scikit-Learn 在 Python 中实现人工神经网络

导入 Python 库

在我们开始我们的人工神经网络 python 教程之前,我们首先需要导入我们将要需要的库和模块。

  • 熊猫 :用于从 CSV 文件加载数据
  • matplotlib :用于创建数据的图形

然后,从 Scikit-Learn我们将导入以下模块:

加载测井数据

数据源

本教程中使用的数据是 Equinor 在 2018 年发布的 Volve 数据集的子集。数据集的全部细节,包括许可证可以在下面的链接中找到。

**https://www.equinor.com/energy/volve-data-sharing

Volve 数据许可证基于 CC BY 4.0 许可证。许可协议的全部细节可以在这里找到:

https://cdn . sanity . io/files/h 61 q 9 gi 9/global/de 6532 f 6134 b 9 a 953 f 6 c 41 BAC 47 a 0 c 055 a 3712d 3 . pdf?equinor-hrs-许可-数据-volve 的条款和条件. pdf

使用 Pandas 加载测井数据

一旦库被导入,我们可以继续导入我们的数据。这是通过调用pd.read_csv()并传入原始数据文件的位置来完成的。

由于 CSV 文件包含许多列,我们可以将一个名称列表传递给usecols参数,因为我们只想在本教程中使用一小部分内容。

数据预处理

在通过机器学习算法运行数据之前,对数据进行预处理的工作流程会有所不同。在本教程中,我们将:

  • 删除丢失的值
  • 将数据分成训练、验证和测试数据集
  • 标准化每次测量的数值范围

删除丢失的值

缺失数据是我们在处理真实世界数据时面临的最常见问题之一。它可能由于各种原因而丢失,包括:

  • 传感器误差
  • 人为误差
  • 处理错误

有关识别和处理缺失数据的更多信息,您应该阅读以下文章:

对于本教程,我们将删除包含缺失值的行。这被称为列表式删除,是处理缺失值的最快方法。然而,这样做减少了可用数据集的大小,并且在进行机器学习模型之前,应该完全理解丢失值的原因和程度。

为了删除丢失的值,我们可以使用 pandas dropna()函数,并将其赋回给df (dataframe)变量。

将数据分为训练、测试和验证数据集

在进行机器学习时,我们经常将数据分成多个子集进行训练、验证和测试。

需要注意的一点是,测试和验证数据集的术语可能因文章、网站和视频而异。这里使用的定义说明如下:

将数据分为训练、验证和测试的示例。图片由作者提供,来自麦当劳,2021。

训练数据集:用于训练模型的数据

验证数据集:用于验证模型和调整参数的数据。

测试数据集:留出的数据,用于在看不见的数据上测试最终模型。这个子集使我们能够了解我们的模型能够多好地概括新数据。

对于本教程,我们的数据集包含 3 个独立的井。因此,我们将分离出一个(15/9-F-1 B)作为我们的测试数据集。这通常被称为盲试井。另外两口井将用于训练、验证和调整我们的模型。

一旦创建了这些列表,我们就可以为子集创建两个新的数据帧。这通过检查列表中的井是否在主数据框(df)内来实现。

一旦我们运行了上面的代码,我们就可以使用describe()方法查看子集的统计数据。

train_val_df.describe()

训练和验证子集的数据框架统计,包含来自 Volve 油田的两个井的数据。图片由作者提供。

我们可以看到,我们有 21,6888 行数据来训练和验证我们的模型。

我们可以用测试数据集重复这一过程:

test_df.describe()

包含 Volve 油田一口井数据的测试子集的数据框架统计。图片由作者提供。

创建训练和验证子集

下一步是将我们的train_val_df进一步细分为训练和验证子集。

为了做到这一点,我们首先将我们的数据分成我们将用于训练(X) 和我们的目标特征(y)的特征。然后我们调用train_test_split()函数来分割我们的数据。

在这个函数中,我们传递 X 和 y 变量,以及用于指示我们想要多大的测试数据集的参数。这是作为十进制值输入的,范围在 0 和 1 之间。

在这种情况下,我们使用 0.2,这意味着我们的测试数据集将是原始数据的 20%,我们的训练数据集将是原始数据的 80%。

标准化价值观

当使用不同比例和范围的测量时,标准化它们是很重要的。这有助于减少模型训练时间,并减少对依赖基于距离的计算的模型的影响。

标准化数据本质上包括计算特征的平均值,从每个数据点中减去它,然后除以特征的标准偏差。

scikit-learn中,我们可以使用standard scaler类来转换我们的数据。

首先,我们使用训练数据来拟合模型,然后使用fit_transform函数对其进行转换。

当涉及到验证数据时,我们不想让 StandardScaler 适应这些数据,因为我们已经这样做了。相反,我们只是想应用它。这是使用transform方法完成的。

建立神经网络模型

训练模型

为了开始神经网络训练过程,我们首先必须创建一个我们在开始时导入的MLPRegressor的实例。

当我们调用MLPRegressor时,我们可以指定许多参数。你可以在这里 了解更多关于这些 的信息。但是,在本教程中,我们将使用:

  • hidden_layer_sizes :控制网络的架构。
  • ****激活:隐藏层激活功能。
  • random_state :当使用整数时,这允许模型创建可重复的结果,并控制权重和偏差的随机数生成。
  • max_iter :控制如果事先不满足收敛性,模型将进行的最大迭代次数。

初始化模型后,我们可以使用fit()用训练数据训练我们的模型,然后使用predict方法进行预测

验证模型结果

既然我们的模型已经被训练,我们可以开始在我们的验证数据集上评估模型的性能。

在这个阶段,我们可以调整和优化我们的模型。

我们可以使用多种统计方法来衡量模型的表现。在本教程中,我们将使用以下三个指标:

平均绝对误差(MAE): 提供预测值和实际值之间绝对差异的测量。

均方根误差(RMSE): 表示预测误差的大小。

要使用 scikit-learn 计算 RMSE,我们首先需要计算均方误差,然后求它的平方根,这可以通过将mse提高到 0.5 的幂来实现。

相关系数(R2): 表示自变量和因变量之间的关系强度。值越接近 1,关系越强。

我们可以按如下方式计算上述指标:

当我们执行上面的代码时,我们得到下面的结果。根据这些数字,我们可以确定我们的模型是否表现良好,或者是否需要调整,

验证数据预测的度量值。图片由作者提供。

超越度量标准

像上面这样的简单指标是查看模型表现的好方法,但是您应该总是检查实际数据。

一种方法是使用散点图,x 轴表示验证数据,y 轴表示预测数据。为了帮助观想,我们可以添加一条一对一的关系线。

完成这项工作的代码如下。

当我们运行上面的代码时,我们得到了下面的图,它显示了我们在实际测量和预测结果之间有一个相当好的趋势。

Volve 数据集的实际声波压缩慢度值与预测值。图片由作者提供。

在看不见的数据上测试模型

一旦我们最终确定了我们的模型,我们就可以用我们为盲测留出的数据来测试它了。

首先,我们将创建用于应用模型的特征。然后,我们将应用我们之前创建的 StandardScaler 模型来标准化我们的价值观。

接下来,我们将为预测数据的数据框架分配一个新列。

预测完成后,我们可以查看与上面相同的散点图。

在岩石物理学和地球科学中,我们经常查看测井图上的数据,其中测量值是相对于深度绘制的。我们可以创建一个简单的预测结果和测试井内实际测量值的对数图,如下所示。

这将返回以下图。

我们可以看到,我们的模型在看不见的数据上表现很好,但是,有几个方面的结果与真实测量值不匹配。特别是在 3100 米和 3250 米之间

这告诉我们,我们的模型可能没有足够的涵盖这些区间的训练数据,因此,如果数据可用,我们可能需要获取更多的数据。

预测测量值与实际测量值的线图(对数图)。图片由作者提供。

如果您想了解该模型与随机森林模型的结果相比如何,请查看下面的文章:

**

摘要

人工神经网络是一种流行的机器学习技术。在本教程中,我们介绍了一种非常快速简单的方法来实现预测声波压缩慢度的模型,从而产生合理的结果。我们还看到了如何验证和测试我们的模型,这是这个过程的一个重要部分。

在 Python 中建立神经网络还有许多其他方法,例如 Tensorflow 和 Keras,然而,Scitkit-learn 提供了一个快速且易于使用的工具来立即开始。**

感谢阅读。在你走之前,你一定要订阅我的内容,把我的文章放到你的收件箱里。 你可以在这里做!或者,您也可以* 注册我的简讯 免费将更多内容直接发送到您的收件箱。***

其次,你可以通过注册成为会员来获得完整的媒介体验,并支持我和成千上万的其他作家。每月只需花费你 5 美元,你就可以接触到所有精彩的媒体文章,也有机会通过写作赚钱。如果你用 我的链接 报名,你直接用你的一部分费用支持我,不会多花你多少钱。如果你这样做了,非常感谢你的支持!

参考

McDonald,A. (2021)“岩石物理机器学习模型的数据质量考虑。”岩石物理学62(2021):585–613。https://doi.org/10.30632/PJV62N6-2021a1**

McDonald,A. (2022)“缺失数据对基于岩石物理回归的机器学习模型性能的影响。”论文发表于 SPWLA 第 63 届年度测井研讨会,挪威斯塔万格,2022 年 6 月。https://doi.org/10.30632/SPWLA-2022-0125**

如何用 Python 创建 SQL 实践数据库

原文:https://towardsdatascience.com/how-to-create-a-sql-practice-database-with-python-d320908e1faf

亲自动手

最后,开始用您自己的数据库练习 SQL

人物插图由故事集

编写 SQL 很重要。作为一名有抱负的数据分析师/科学家,高效查询数据库的能力通常被认为是最重要的技能之一。

SQL 不仅重要,而且非常常用。根据 2021 年 Stackoverflow 开发者调查,SQL 位列使用的五大编程语言之一。

所以,我们或许应该投入一些时间来学习 SQL。

但只有一个问题:首先,在没有数据库的情况下,如何练习查询数据库?

在接下来的几节中,我们将解决这个基本问题,并学习如何从头开始创建我们自己的 MySQL 数据库。在 Python 和一些外部库的帮助下,我们将创建一个简单的脚本,自动创建并使用随机生成的数据填充我们的表。

但是在深入实现细节之前,我们必须先了解一些先决条件。

注意:当然还有其他方法可以获得 SQL 数据库用于实践目的(例如,简单地通过下载)。然而,使用 Python 和一些外部库为我们提供了额外的、有价值的实践机会。

先决条件

让我们从基础开始。

首先我们需要安装 MySQL 工作台并设置一个连接。一旦我们有了一个可以用来建立数据库的连接:

CREATE DATABASE IF NOT EXISTS your_database_name;

现在,我们只需要安装必要的 python 库,基本设置已经完成。我们将要使用的库如下,可以通过终端轻松安装。

  1. 数字pip install numpy
  2. sqlalchemy pip install sqlalchemy
  3. 骗子pip install faker

创建脚本

完成基本设置后,我们终于可以开始编写 python 脚本了。

让我们先用一些样板代码创建一个类,为我们提供一个蓝图,指导我们完成其余的实现。

目前为止没什么特别的。

我们基本上只是创建了一个类,存储了供以后使用的数据库凭证,导入了库,并定义了一些方法。

建立连接

我们必须完成的第一件事是创建一个数据库连接。

幸运的是,我们可以利用 python 库 sqlalchemy 来完成大部分工作。

该方法创建并存储 3 个对象作为实例属性。

首先,我们创建一个引擎,作为任何 sqlalchemy 应用程序的起点,描述如何与特定种类的数据库/ DBAPI 组合进行对话。

在我们的例子中,我们指定一个 MySQL 数据库并传递我们的凭证。

接下来,我们创建一个连接,它只允许我们执行 SQL 语句和一个元数据对象,元数据对象是一个容器,它将数据库的不同特性保存在一起,允许我们关联和访问数据库表。

创建表格

现在,我们需要创建我们的数据库表。

我们创建了 3 个表,并将它们存储在一个字典中,供以后参考。

在 sqlalchemy 中创建一个表也非常简单。我们简单地实例化一个新的表类,提供一个表名、元数据对象,并指定不同的列。

在我们的例子中,我们创建了一个职务、一个公司和一个人员表。person 表还通过外键引用其他表,这使得数据库在实践 SQL 连接方面更加有趣。

一旦我们定义了表,我们只需要调用元数据对象的create_all()方法。

生成一些随机数据

我们创建了数据库表,但是我们仍然没有任何数据可以使用。因此,我们需要生成一些随机数据并插入到我们的表中。

现在,我们利用 Faker 库来生成随机数据。

我们只是在一个 for 循环中用随机生成的数据创建一个新记录,用一个字典表示。然后将单个记录追加到可用于(多个)insert 语句的列表中。

接下来,我们从 connection 对象中调用execute()方法,并将字典列表作为参数传递。

这就是了!我们完成了我们的类实现——我们只需要实例化这个类并调用它的方法来创建我们的数据库。

进行查询

唯一剩下的事情—我们需要验证我们的数据库已经启动并正在运行,并且确实包含了一些数据。

从一个基本查询开始:

SELECT *
FROM jobs
LIMIT 10;

基本查询结果[图片由作者提供]

看起来我们的脚本成功了,我们有了一个包含实际数据的数据库。

现在,让我们尝试一个更复杂的 SQL 语句:

SELECT
  p.first_name,
  p.last_name,
  p.salary,
  j.description
FROM
  persons AS p
JOIN
  jobs AS j ON
  p.job_id = j.job_id
WHERE 
  p.salary > 130000
ORDER BY
  p.salary DESC;

更多相关查询结果[图片由作者提供]

这看起来也很有希望——我们的数据库还活着,而且运行良好。

结论

在本文中,我们学习了如何利用 Python 和一些外部库,用随机生成的数据创建我们自己的练习数据库。

尽管人们可以很容易地下载一个现有的数据库来开始练习 SQL,但是使用 Python 从头开始创建我们自己的数据库提供了额外的学习机会。因为 SQL 和 Python 经常是紧密联系在一起的,所以这些学习机会会被证明是特别有用的。

你可以在我的 GitHub 上找到完整的代码。

随意调整代码,创建一个更大、更好、更复杂的数据库。

Marvin Lanhenke

马文·兰亨克

# 30 日

View list30 stories

喜欢这篇文章吗?成为 中等会员 继续无限学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@marvinlanhenke/membership

如何免费创建强大的数据科学产品组合

原文:https://towardsdatascience.com/how-to-create-a-strong-data-science-portfolio-for-free-142588a0d754

一个有效总结你的技能、数据科学项目和过去经验的网站

kike vegaUnsplash 拍摄的照片

有没有想过建立自己的作品集网站?LinkedIn、Github 和标准简历似乎足以概括你的能力和过去的经历,但它们同时也是间接和分散的,因为它们不包含关于你的所有信息,因此,你会放很多链接来弥补这一点。相反,个人投资组合可以让你脱颖而出,而不是消失。

这很重要,因为它能让你把所有你需要的内容展示给面试官,并间接展示其他重要的技能,如创造力和批判性思维。这些品质让你从其他相同专业的人中脱颖而出,同时对自己更有信心。

如果你决定建立投资组合,不要因为你遇到的第一个困难而气馁。起初,我认为这项任务对我来说太有挑战性,我需要事先了解,但过了一段时间,我发现自己的力量,我发现它并不像我想象的那么难。毅力和耐心是解决任何问题的关键。

创建投资组合的步骤

建立你的作品集网站需要遵循一些步骤。首先,你需要一点 HTML 和 CSS 的知识。如果没有,可以看看我前段时间写的这个帖子,有必要的基础就够了。

这些是基本步骤:

  1. 下载作品集模板
  2. 修改您选中的模板
  3. 建议要点补充
  4. 创建一个包含所有代码的 Github 库

1。下载作品集模板

作者插图。来自 HTML5P 的免费模板

你不需要从头开始编写所有的 HTML 和 CSS 代码。有几个网站可以让你避免它,并提供了很多模板。这里有一个网站列表,如果你有兴趣有一个更完整的看法。在我的例子中,我使用了 HTML5P ,它允许下载免费的 HTML5 网站模板。

你有很多选择,因为有大量不同的模板。试着想一想你的网站需要什么样的结构,然后点击现场演示来大致了解一下网站模板。它非常有效,因为它显示了模板在你的电脑、平板电脑或手机上的外观。

2.修改您选择的模板

作者插图。Visual Studio 代码中网站模板的结构。

一旦你下载了模板,解压文件并放入你喜欢的路径。我想指出的是,有一种简单有效的方法可以修改这个模板。最好的解决方案是使用一个众所周知的名为 Visual Studio Code 的 IDE。它通过添加扩展为任何编程语言提供支持。当你下载它的时候,选择“用代码打开”选项,比如在这个溢出回答,它会让你直接用 Visual Studio 打开一个文件夹。

作者插图。用 Live Server 打开。

在你右键点击“打开代码”之后,你应该可以看到你的项目文件夹,如上图所示。因为有很多文件,所以看起来可能有点乱,但是你可以直接关注 index.html 的文件。为了可视化这个项目如何出现在你的浏览器上,你只需要右击 HTML 文件选项“用 Live Server 打开”。

记得在 Visual Studio 上添加“Live Server”这个扩展,否则,你无法在浏览器上对网站有一个概览

您应该能够在浏览器中可视化网页,如下例所示:

作者插图。模板在浏览器上的可视化

我建议你每次修改模板上的一些文字时点击“用 Live Server 打开”来熟悉这个工具。

您还应该尝试检查网页的特定元素。例如,检查标题,右键单击该元素并选择“检查”。

这样,您就清楚地知道在哪里可以找到该元素,并最终可以对其进行修改。在这种情况下,短语“我的数据科学组合”包含在标签

中。

3。补充要点建议

我建议你在网站上写下一些要点:

  • 你的照片和主页上关于你自己的简介
  • 你的数据科学项目。你不需要把所有的项目都放进去,把最相关的和对应的 Github 链接放进去更有效
  • 在 LinkedIn 和 Github 等网站上放上你个人资料的链接
  • 你也可以把你的教育路径和经历部分做出来

没有要遵守的精确规则,跟着你的直觉走,看看一些投资组合的例子。你可以看看我的网站寻找灵感。我还受到了朱莉娅·尼库尔斯基、布兰登·沃克和库蒂斯·派克斯创作的作品集的启发。还有一个 10 分钟的 Youtube 视频,由 Joshua Fluke 拍摄,展示了如何用 Github 创建一个文件夹。

4.创建 Github 存储库

作者插图。创建名为**username.github.io**的 Github 存储库

当您完成了对您的投资组合模板的修改后,您就可以在 Github 中创建一个存储库了,其名称需要采用以下格式:username.github.io。你只需要用你的 Github 用户名替换用户名,然后点击“创建资源库”按钮。

一旦创建完成,你上传模板中包含的所有文件,等待几秒钟,然后在浏览器上写https://username.github.io。例如,在我的例子中,链接将是https://eugeniaring.github.io

现在,你的作品集的网站已经可以被看到了!

最终想法:

我希望这篇文章鼓励你开始建立你的数据科学投资组合。我相信开始的时候可能会有所畏惧,但是你的努力会得到满足感的补偿。这样,你会吸引更多的工作机会,扩大你在 LinkedIn 上的人脉。不错,你不觉得吗?感谢阅读!祝你有愉快的一天。

你喜欢我的文章吗? 成为会员 每天无限获取数据科学新帖!这是一种间接的支持我的方式,不会给你带来任何额外的费用。如果您已经是会员, 订阅 每当我发布新的数据科学和 python 指南时,您都可以收到电子邮件!

如何创建虚拟环境并在 Jupyter 笔记本上使用

原文:https://towardsdatascience.com/how-to-create-a-virtual-environment-and-use-it-on-jupyter-notebook-6c0b7b1cfca0

使用 Jupyter 笔记本中的虚拟环境

动机

创建虚拟环境是一个很好的实践。它将特定项目的依赖项与操作系统上全局安装的其他包隔离开来。作为一名数据科学家,在处理通常需要不同依赖关系的不同项目时,这可能是有益的。

在本概念性博客结束时,您将能够:

(1)使用virtualenvconda创建虚拟环境

(2)将虚拟环境连接到 Jupyter 笔记本电脑。

创建您的虚拟环境

每个工具都用于管理 python 包和环境。两者的主要区别在于,virtualenv用于管理单个项目的 Python 包,而conda是一个更通用的包管理工具,可以用于多个项目和 Java、R、Python 等语言。

首先,你需要在你的电脑上安装 Python 。一旦完成,我们就可以使用 Python 包管理器pip继续创建环境。

使用 virtualenv 创建环境

virtualenv可通过命令行界面或提示命令进行安装,如下所示:

pip3 install virtualenv

成功安装后,您可以使用以下语法继续创建虚拟环境:

virtualenv virtual_env_1

根据前面的语法,virtual_env_1对应于您的虚拟环境的名称。

下一步是激活它,以便能够使用它。激活取决于您的操作系统:

# On Mac
source virtual_env_1/bin/activate
# On Windows
virtual_env_1\Scripts\activate

运行前面的命令之一应该会显示虚拟环境括号的名称,如下所示:

来自 virtualenv 的第一个虚拟环境(图片由作者提供)

**(virtual_env_1)**表示virtual_env_1被认为是当前环境。现在,您可以继续安装软件包,并在环境中管理它们。这里有一个例子:

pip install pandas # to install pandas library

使用 conda

创建虚拟环境的第一步是在您的系统上安装conda。如果没有,你可以下载并安装已经包含了condaAnaconda 或者 Miniconda

在创建环境之前,让我们用deactivate命令停用之前创建的环境:

deactivate

现在,您可以通过运行以下命令,用condaPython 3.8创建您的新环境virtual_env_2:

conda create --name virtual_env_2 python=3.8

最后,您可以激活环境,如下所示。无论您使用何种操作系统,激活过程都是一样的:

conda activate virtual_env_2

该命令激活virtual_env_2,并使其成为当前环境。下面是预期的输出。

来自 conda 的第二个虚拟环境(图片由作者提供)

我们可以使用以下语法停用环境:

conda deactivate

将您的虚拟环境连接到 Jupyter 笔记本电脑。

作为数据科学家,我们的大部分分析和模型训练主要是在 Jupyter 笔记本上完成的。

从笔记本电脑上就能创建我们的虚拟环境不是很好吗?

这是本节的主要目标。它解释了如何将以前的环境连接到 jupyter 笔记本电脑。

第一步,安装ipykernel。这个包允许我们管理来自不同环境的内核。使用pip完成安装:

pip3 install --user ipykernel

使用ipykernel我们可以使用以下通用语法添加任何虚拟环境:

python -m ipykernel install --user --name=[my_virtual_env]
  • [my_virtual_env]是现有虚拟环境的名称。

因此,让我们添加我们的虚拟环境virtual_env_1virtual_env_2:

# Add the first virtual environment
python -m ipykernel install --user --name=virtual_env_1
# Add the second virtual environment
python -m ipykernel install --user --name=virtual_env_2

前面的命令添加了您的环境!现在,如果您运行 Jupyter notebook,您应该能够在创建新笔记本时看到这两种环境。

# Run your notebook 
jupyter notebook

从笔记本中,我们应该看到如下所示的内核,我们可以决定使用哪一个:

Jupyter 笔记本中添加的环境(图片由作者提供)

结论

恭喜你!🎉你已经学会了如何使用condavirtualenv创建虚拟环境。此外,您还了解了如何将您的环境连接到 Jupyter 笔记本电脑。

如果你喜欢阅读我的故事,并希望支持我的写作,考虑成为一个媒体成员。每月支付 5 美元,你就可以无限制地阅读媒体上的故事。

欢迎在媒体推特YouTube 上关注我,或者在 LinkedIn 上打招呼。讨论人工智能、人工智能、数据科学、自然语言处理和人工智能是一种乐趣!

如何为管道测试创建 LDAP 沙箱

原文:https://towardsdatascience.com/how-to-create-an-ldap-sandbox-for-pipeline-testing-644b01478dd

在本地或云中使用 Docker 容器

劳拉·奥克尔在 Unsplash 上的照片

许多公司使用 LDAP 或轻量级目录访问协议来存储有关员工的信息,并允许员工根据他们各自的角色访问组织资源。微软的 Active Directory (AD)是使用这种协议的最著名的数据库。

在最近的一个数据工程项目中,一个客户需要创建一个管道,以便向其内部 AD 批量添加新员工,并根据各种独特的因素为这些新员工分配角色、用户名和其他属性。在进行项目时,我需要一些方法来测试我正在进行的工作。但是由于安全原因,客户端不允许访问 AD 服务器,即使他们可以,服务器也在使用中,不是一个好的测试平台。

为了创建这个管道的测试沙箱,我使用了:

  • Docker 和云服务,在我的例子中是 T4 Azure T5。除了云服务,我还可以对我的本地机器使用隧道服务。
  • 与服务器交互的界面
  • 一个管道集成平台,在我的例子中是 SnapLogic

下面是我创建沙箱的步骤,显示了几个不同的选项。

从 Docker 映像创建 LDAP 服务器

OpenLDAP 是 LDAP 的开源实现,我使用 osixia/openldap docker 映像运行它。(查看文档的链接。)

选项 1:将其作为 Azure 容器实例运行

我首先需要一个 Azure 帐户,并在我的计算机上安装 Azure CLI。然后,我在终端中运行以下命令:

当创建容器时,它出现在资源组的容器实例中的 Azure 门户中。注意右栏中 Azure 是如何给容器分配一个公共 IP 地址的。

选项 2:在本地机器上运行容器

你可能没有订阅 Azure 或其他云服务,或者你可能更喜欢在本地运行容器。在我的 Mac 上安装了 docker 之后,我创建了一个 docker 容器,其中的命令与上面 Azure 的命令相同。

LDAP 服务器使用端口 389,因此需要包含在-p标志中。有时也使用端口 636。

将接口连接到 LDAP 服务器

选项 1:在 docker 容器中启动接口

根据其主页,“phpLDAPadmin 是一个基于 web 的 LDAP 客户端。它为您的 LDAP 服务器提供了简单、随处可访问的多语言管理。”和 OpenLDAP 服务器一样,这个客户机作为 docker 映像存在;它位于 osixia/phpldapadmin

有了这个映像,我将在本地创建容器,但是我将把它连接到服务器的 Azure 实例。注意我是如何在环境变量中包含 Azure 为 LDAP 服务器容器创建的 IP 地址的。

客户机容器使用端口 443,映像文档说要将其映射到端口 6443。当它启动并运行时,我可以通过localhost:6443访问客户端。我看到一个登录页面。

我使用在 Azure 上为登录凭证创建服务器时定义的环境变量。然而,请注意,登录用户名不仅仅是admin。我需要管理员的识别名,在本例中是cn=admin,dc=example,dc=com,在一个环境变量中,我将密码定义为pass_word

登录后,我可以创建示例用户帐户、组织单位和其他对象。

选项 2:创建一个到本地主机的隧道

如果我选择执行上面的选项 2,在本地机器上创建容器,我可以将本地服务器连接到本地客户机接口容器,但是请记住,最终我希望将 LDAP 服务器连接到数据集成平台,而该平台位于云中。为了让从云到我的本地机器上的服务器的连接工作,我必须弄清楚如何绕过防火墙,处理可能改变的 IP 地址,以及其他令人头痛的问题。

创建隧道更容易,一个名为 ngrok 的服务允许我这样做。当我注册时,我获得了一个免费的活动隧道,一旦 ngrok 代理安装到我的计算机上,我就可以运行:

ngrok tcp 389

这告诉 ngrok 创建一个到端口 389 的 TCP 连接,该连接在本地主机上映射到服务器容器。(你需要使用 TCP 协议而不是 HTTP,因为 LDAP 使用 TCP。)Ngrok 会在终端中生成一个类似这样的页面。

注意转发行,其中一个 URL 被转发到我的 localhost:389。该 URL 将在下一步中使用。

另一行需要注意的是 web 界面在 http://127.0.0.1:4040 。Ngrok 允许您监视该地址的隧道,但是要使它工作,您还需要在创建容器时发布端口 4040。

同样,我需要一个接口来与 LDAP 服务器交互。我可以再次使用 phpLDAPadmin,但这一次为了展示另一种可能性,我将使用Apache Directory StudioLDAP 浏览器,它可以免费下载用于 Windows、Mac 和 Linux。

安装后,我可以转到“连接”窗格并创建一个新连接。在网络参数面板中,我输入由 ngrok 创建的 URL 及其相关的 ngrok 端口号(而不是端口 389)。

在 Authentication 面板中,我将输入与上面第一个选项相同的识别名和密码。当连接通过身份验证后,我可以开始向服务器添加条目。

将管道连接到 LDAP 服务器

如前所述,我将 SnapLogic 用于我的管道。为了与服务器交互,我必须在平台中使用正确的凭证添加我的帐户。

如果我使用运行在 Azure 容器上的服务器执行选项 1,我需要添加由 Azure 创建的 URL 以及标准 LDAP 端口 389 和管理员的识别名和密码。

如果我使用在我的机器上本地运行的服务器执行选项 2,我需要添加 ngrok 隧道的 URL、它的端口以及管理员的识别名和密码。

这应该可以了。我提供了几种不同的选择。无论我选择哪一个,我的沙盒都准备好了。

额外收获:添加自定义模式

OpenLDAP 带有标准的对象类,但是如果您需要带有自定义属性的对象类,您将不得不添加您自己的模式。

在这种情况下,我将展示如何在本地服务器上实现这一点。

首先,我创建一个扩展名为.schema的文本文件。在这里,我将其保存为cs.schema。以下是该文件的内容:

在这个文件中,我只在基于 inetOrgPerson 的名为“personnel”的新对象类中创建了两个新属性:“sAMAccountType”和“myadditionnalAttr”。第一个属性是 LDAP 的现有属性,第二个属性是该模式的虚构属性。有关 LDAP 模式结构、属性和代码的更多信息,请查看其他文档,如 LDAP wiki

下面是我用来创建一个新容器的 docker 命令,它与上面的类似,只是做了一些修改:

使用--volume标志,我将模式文件挂载到容器中的特定目录。此外,为了正确工作,我需要使用图像的--copy-service命令。

当容器启动并运行时,我可以再次使用 ngrok 创建一个到它的隧道,并继续执行上面的选项 2 步骤。

摘要

选项 1

  • 在诸如 Azure 的云平台上创建一个服务器容器
  • 在本地创建一个接口容器,并将其链接到云中的服务器
  • 将管道链接到云中的服务器

选项 2

  • 在本地创建服务器容器
  • 创建到服务器的隧道
  • 通过隧道将接口链接到服务器
  • 通过隧道将管道连接到服务器

如何使用 AWS 和 Python 创建对象检测解决方案

原文:https://towardsdatascience.com/how-to-create-an-object-detection-solution-with-aws-and-python-8b20690686c5

从头开始部署无服务器、事件驱动的对象检测解决方案的端到端教程

图片作者。

目录

  1. 简介
  2. 实现
    2.1 S3 木桶
    2.2 角色和策略
    2.3λ函数
    2.4 我们来试试
  3. 结论
  4. 参考文献

1。简介

对象检测是一种计算机视觉技术,允许识别和定位图像或视频中的对象。

在本帖中,我们将开发一个基于 AWS 的无服务器、事件驱动的对象检测解决方案,AWS 是一个流行的云提供商。

我们可以将解决方案描述如下:

  1. 一张图片将被加载到亚马逊 S3 的一个对象存储服务中。
  2. 将图片加载到 S3 的事件将触发使用 AWS Lambda 实现的功能的执行。AWS Lambda 是一个无服务器事件驱动的计算服务。它支持在不提供或管理底层基础设施的情况下运行我们的代码。
  3. 该功能将调用人工智能(AI)服务 Amazon Rekognition ,以分析图像并返回已识别的标签。
  4. 我们的代码会将日志写到 Amazon CloudWatch 进行监控。
  5. 该功能将把分析的输出作为 JSON 文件保存回 S3 以备将来使用。

本教程的唯一先决条件是一个活跃的 AWS 账户。由于 AWS 提供了免费层,我们可以零成本地学习本教程。

2.履行

接下来的段落将分享构建解决方案的详细、逐步的过程。

2.1 S3 吊桶

桶是存放在 S3 的物品的容器。对于本教程,我们想要创建两个不同的存储桶,分别存储输入图像和分析输出。

我们按如下方式创建输入存储桶:

  • 打开 AWS 控制台。
  • 在页面顶部的搜索栏中输入“ S3 ”。
  • 打开“亚马逊 S3 ,然后点击“创建桶”。
  • 在“时段创建”页中,提供时段名称和 AWS 区域。
  • 对于输入桶,我们选择名称input-img-dev-032022

输入桶的创建。图片作者。

我们重复相同的步骤来创建输出桶,将其命名为output-img-dev-032022

输入和输出桶。图片作者。

我们可以选择其他的存储桶名称,假设在接下来的步骤中应该一致地使用它们。

2.2 角色和政策

我们需要我们的 Lambda 函数有权限:

  • S3 读取图像。
  • 发送图像到识别检测标签。
  • 结果回 S3
  • 日志写入 CloudWatch

在 AWS 中,这样的权限被称为 策略 。我们需要定义所需的策略,并将它们附加到一个身份上,比如一个 角色 。稍后,我们可以向服务授予身份,以定义与该服务相关联的权限。

在我们的例子中,我们将创建策略并将它们附加到角色。然后,我们将把角色与 Lambda 函数关联起来。

创建策略

  • 单击 AWS 控制台顶部的帐户名称。

  • 选择安全凭证

  • 从左侧菜单中选择“策略,然后选择“创建策略”。

  • 在下一页中,点击 JSON

  • 在文本框中,添加以下代码:

  • 点击“下一步:标签”,然后点击“下一步:查看”。

  • 最后,将策略命名为obj-detect-policy-dev-032022,并单击创建策略

政策详情

  • 我们的策略被定义为Statement属性中的 JSON 对象。
  • 每个策略对象由
    • Effect组成:指定语句的结果是Allow还是Deny
    • Action:所需权限列表。例如,S3:GetObject将让我们从 S3 读取对象,而S3:PutObject将允许我们将它们保存到一个桶中。
    • Resource:策略适用的资源。AWS 要求通过他们的亚马逊资源名称(ARN) 来识别资源。
  • 在复制代码时,我们应该用创建服务的 AWS 区域替换:
    • <REGION>
    • <AWS ACCOUNT ID>具有唯一标识 AWS 账户的 12 位数字。
  • 要了解更多关于 ARN 和政策的信息,我们应该查阅官方文件。例如,资源arn:aws:s3:::*没有指定帐户 ID 的区域。这是因为在 S3,存储段名称在所有帐户和地区中都是唯一的。
  • 通配符符号*用于标识所有资源。例如,resource: arn:aws:s3:::*标识所有的桶/对象。
  • 尽管这超出了本文的范围,但我们应该记住最小特权原则:任何参与者都应该只拥有完成任务所需的最小权限。

创建角色

  • 单击 AWS 控制台顶部的帐户名称。
  • 选择安全凭证
  • 从左侧菜单中选择“角色,然后选择“创建角色”。
  • 选择可信实体页面:
    -对于可信实体类型,点击 AWS 服务
    -对于用例,选择λ
  • 点击下一个

选择可信实体。图片作者。

  • 从“权限策略菜单中,选择之前创建的策略obj-detect-policy-dev-032022,并将其添加到角色中。
  • 点击下一个
  • 给角色命名为obj-detect-role-dev-032022,点击创建角色

我们已经定义了一组所需的权限(策略),并将它们附加到一个身份(角色)上。我们可以继续创建 Lambda 函数。

2.3λ函数

  • 从 AWS 控制台,在页面顶部的搜索栏上键入“ lambda ”。
  • 选择“λ”服务。
  • lambda 函数的 AWS 区域应该与 S3 输入桶的区域相同。可以通过 AWS 控制台右上角的下拉菜单来更改区域。
  • 点击创建功能,然后:
    ——从头选择作者
    -对于函数名,键入:obj-detect-dev-032022
    -对于运行时,选择 Python 3.7
    -对于执行角色,选择使用现有角色,并提供之前创建的角色名称。
  • 点击创建功能

Lambda 函数创建页面。图片作者。

  • 在功能页面中,选择“ +添加触发器”。我们希望配置该函数来运行,以响应亚马逊 S3 上传。

图片作者。

  • 添加触发页面:
    -选择 S3 作为输入。
    -提供桶名:input-img-dev-032022。这是最初加载图像的桶。
    -事件类型:
  • 勾选信息框,点击添加

触发配置。图片作者。

功能页面现在如下所示:

图片作者。

就是这样!

我们终于可以用 Python 写应用程序逻辑了。在功能页面的“代码”选项卡下,让我们将它粘贴到文本框中:

关于代码

  • Boto3 是 Python 的 AWS SDK。我们用它与其他 AWS 服务进行交互:S3 ( boto3.client("s3"))和 Rekognition ( boto3.client("rekognition"))。
  • Label类存储 Rekognition 检测到的标签(名称和置信度)。
  • Response类存储被分析的对象、完整的元数据和一个列表LabelsResponse类通过rekognition.detect_labels()方法实现对 Rekognition 的调用。
  • rekognition.detect_labels()方法接受以下参数:
    • MaxLabels:我们希望 Rekognition 返回的标签的最大数量。
    • MinConfidence:最小置信度阈值。Rekognition 不会返回置信度低于此值(默认值:55%)的标签。
  • save_analysis()函数将一个对象作为输入,并将其存储在输出 S3 桶中。它利用了s3.put_object()方法。
  • 调用 Lambda 函数时运行lambda_handler(event, context)方法。它传递触发执行的事件对象。

2.4 我们来试试吧!

我们可以添加任何图片到输入桶(AWS 控制台>亚马逊 S3 >桶>输入桶> "上传")。一个例子:

意大利佛罗伦萨韦基奥桥。图片作者。

标签检测过程由上传自动触发。我们可以通过 AWS CloudWatch 日志来查看。要检查它们,我们应该进入 Lamba 功能页面,打开“监视器选项卡,然后“查看 CloudWatch 中的日志”:

图片作者。

识别出的标签很好的描述了图片:urbanoutdoorswaterwaterfrontarchitecture等。

亚马逊 Rekognition 可以返回的标签包括在一张图片中找到的 物体场景动作概念 。产品文档中提供了更多信息。

让我们检查分析是否也保存在输出桶中:

输出桶。图片作者。

我们可以下载并检查该文件:

保存的文件。图片作者。

3.结论

在这篇文章中,我们利用 AWS 快速部署了一个无服务器和事件驱动的图像分析解决方案。

如今,像 S3 这样的对象存储服务是图片等非结构化数据最流行的存储目标。为此,类似的方法可以很容易地从大量图像文件中提取有用的信息。随着分析被保存回 S3,它可用于进一步的服务。搜索引擎和商业报告工具可能会产生吸引人的和可消化的见解。

在非功能性要点中,我们提醒:

  • 采用托管服务,这样我们就不必处理复杂耗时的基础设施设置。
  • 成本效益:有了 AWS Lambda,我们只需为我们有效使用的资源付费。代码不运行时不收费。此外,使用亚马逊 Rekognition 等人工智能服务可以消除开发复杂机器学习模型的相关成本。
  • 通过设计实现自动化和可伸缩性:该过程是事件驱动的,并且在新映像可用时立即开始。此外,AWS Lambda 会自动缩放代码。

4.参考

如何创建和训练多任务转换器模型

原文:https://towardsdatascience.com/how-to-create-and-train-a-multi-task-transformer-model-18c54a146240

关于如何使用 Huggingface Transformers 创建和训练多任务 transformer 模型的分步教程。

弗拉德·扎伊采夫在 Unsplash 上拍摄的照片

当我在做一个人工智能聊天机器人项目时,我对提供 NLP 模型服务的公司做了一个简短的回顾。我对一些提供商对基本意图分类模型收取的费用感到惊讶,甚至对那些既提供意图分类又提供令牌分类任务(例如部分速度标记)的提供商收取的费用更高。

在我看来,这些服务的唯一附加值就是部署和维护。因为开源的 Huggingface Transformer 库(训练这种模型的当前标准)已经成熟,并且可以被任何没有广泛的 Transformer 模型知识的人使用。

我知道部署和维护是任何生产应用程序的关键方面(知道维护平均占任何软件成本的 70%)。然而,走这条路也有一些缺点:

  • 你对引擎盖下使用的模型控制较少。您将模型视为通过 API 访问的黑盒。此外,您总是受到发布周期的约束,以获得最新的模型架构(如果它们被添加的话)。
  • 对于纯云服务,您需要将您的数据发送给该第三方。
  • 您受到任何服务限制。比如 API 访问方法(REST vs. gRPC)、延迟、特性等。

因此,如果您可以构建和训练您的模型,您只需要支付成本更低的部署服务,尤其是从建模的角度来看没有任何优势,因为数据的质量决定了您的模型的性能。

这篇文章是关于构建和训练多任务模型的分步教程,该模型执行序列分类(即意图分类)和标记分类(即命名实体识别)。然而,对于任何使用 Huggingface Transformer 库的 MTL 模型来说,这也是一个很好的起点。最后,如果您必须为您的 NLP 服务选择一个外部提供者,至少您可以使用这个例子创建一个基线来比较不同提供者的性能。

多任务数据集

首先,我们将创建一个多任务数据集,它结合了来自两个任务的样本(即序列和标记分类)。

对于序列分类,我们将使用公开可用的 MRPC 数据集和 Conll2013 数据集来完成令牌分类任务。然而,在实际的用例中,您可能会将相同的数据标记为令牌和序列分类。

要创建多任务数据集,我们需要:

  • 下载或加载每个数据集。
  • 将每个数据集标记化。
  • 组合标记化的集合。

令牌分类数据集

以下是加载令牌分类数据集的代码片段。这个片段的灵感来自 Huggingface 中的 run_ner.py 示例,并做了一些修改以处理多任务设置:

  • 我们添加了一个名为task_ids的新列,包含每个样本的任务 id(第 59 行)。模型将使用任务 id 来正确处理来自每个任务的样本。
  • 在标记化之后删除不使用的列,只保留模型(第 70 行)使用的特性。

我们使用了 Huggingface 数据集load_dataset函数(第 79 行)。但是,如果您有数据,您仍然可以使用相同的函数并提供文件路径而不是数据集名称。

Task数据类是一个助手,用来记录 MTL 模型所需的关于特定任务的所有信息。

  • id:唯一的任务 id。
  • name:任务名称。用于打印日志消息。
  • type:任务类型(seq_classificationtoken_classification)。
  • num_labels:标签的数量(如二进制分类为 2)。

序列分类数据集

以下是加载序列分类数据集的代码片段。它受 Huggingface 的 run_glue.py 示例的启发,并做了一些修改以处理多任务设置:

  • 我们添加了类似于令牌分类数据集(第 30 行)task_ids列。
  • label列重命名为labels,以匹配令牌分类数据集(第 29 行)
  • 仅为训练数据集填充标签(第 36 行)

为了理解我们为什么需要填充标签,让我们以下面的例子为例:“我想开一个账户。”

  • 标签将是序列分类任务的类 id(单个整数)。
  • 标签将是用于令牌分类任务的每个单词的标签列表,

因为我们需要在同一批中包装两种样品,所以标签的形状应该相同。我们只需要稍后为序列分类样本去除填充。

合并数据集

既然我们可以分别加载每个数据集,那么最后一步就是创建一个单独的数据集来提供给培训师。

  • load_seq_classification_datasetload_token_classification_dataset是我们之前定义的函数。
  • 为了合并训练数据集,我们使用 pandas 格式的原始数据来避免处理数据集库中的一些检查,因为这些数据集格式最初是不兼容的(我们添加的填充)(第 14 行)
  • 训练数据集被混洗,以便单个批次包含来自多个任务(第 18 行)的样本。
  • 因为我们分别评估每个任务(第 21 行),所以验证数据集被附加到一个列表中。

您可能会问自己,为什么验证集没有像训练集一样合并。由于计算性能指标和避免改变默认训练者的不同方式,在验证期间单独处理每个数据集(一个接一个)要容易得多。

多任务模型

概观

我们将使用硬参数共享多任务模型[1],因为这是最广泛使用的技术,也是最容易实现的。在硬参数共享中,所有的任务共享一组隐藏层,每个任务都有其输出层,通常称为输出头,如下图所示。在这种设置中,模型学习对所有任务建模的共享特征表示。

图片由作者提供。灵感来源于[1]。

多任务模型

对于我们的用例,共享层将是一个转换器(例如,BERT、RoBERTa 等。),输出头将是线性层,有落差,如下图所示。

图片由作者提供。

创建多任务模型时有两个主要考虑事项:

  • 模型应该是 Pytorch 模块。意味着一个从torch.nn.Model继承并实现forward方法的类。
  • forward方法应该处理输入参数并返回类似于任何 Huggingface 模型的输出。

init 方法

下面的代码片段为每个任务创建了编码器和输出头。

  • 使用AutoModel创建编码器,以使用任何变压器(第 5 行)
  • torch.nn.ModuleDict中的输出标题帮助我们使用任务 id (第 7–11 行)访问每个标题。

前进前进方法

下图显示了 forward 方法的高级流程。如前所述,批次首先通过编码器。然后,使用任务 id 将每个样本重定向到适当的输出头。最后,我们计算平均损失。

图片由作者提供。

下面的代码片段是forward方法的实现。

  • **kwargs 参数用于避免声明未使用的参数(第 23 行)
  • 使用每个样本的任务 id 对编码器输出进行过滤,然后馈送到适当的解码器(第 29–37 行)
  • 总损失是批次中每个任务损失的平均值(第 48 行)
  • 与其他 huggingface 模型(第 56–60 行)类似,返回损耗、逻辑和编码器输出。

令牌分类头

正如上面概述中所讨论的,令牌分类是一个简单的线性层,与BERTForTokenClassification类似。

下面是这个输出头的代码片段。

序列分类头

序列分类头类似于令牌分类头,但有以下区别:

  • 使用pooled_output代替sequence_output (第 11 行)
  • 在标记化过程中添加的填充被删除(第 18 行)

韵律学

我们需要为每种任务类型定义指标。这里,我们使用 seqeval 进行标记分类,使用 accuracy 进行序列分类。

为了区分每个任务,我们在预测中使用维度的数量。

  • 序列分类任务的维数是 2,因为整个序列只有一个标签(第 4 行)
  • 对于令牌分类任务,维数是 3,因为每个令牌都有一个标签(第 8 行)

一起

下面的代码片段显示了一个训练循环的工作示例。

model_argsdata_argstraining_args是类似于 huggingface run_glue.py 示例中定义的数据类,只是model_name_or_path被重命名为encoder_name_or_path

进一步的考虑

这篇文章的目的不是为你的用例提供一个现成的代码。它旨在通过一个简单的例子向您展示构建和训练 MTL 模型是多么容易。但是,如果您想要扩展这项工作,以下是您需要考虑的一些事项。

采样

为了简化,我们对训练数据集进行了洗牌,以确保每一批都包含来自不同任务的样本。然而,如果数据集的大小不一致,低资源任务可能会饿死,这可能会导致灾难性的遗忘。你可能想检查其他 MTL 抽样技术,如 MTL 主动学习抽样[2]。

损失

在这个例子中,我们选择平均每个任务的损失。如果损失不在同一个范围内,那么在这种情况下,一个单一的任务可以控制梯度下降。

结论

在这篇文章中,我用 huggingface Transformers 库演示了一个创建和训练多任务模型的例子。

尽管我简化了这个例子以便于理解,但它仍然是一个很好的开始例子。

在你走之前

推特上关注我,在那里我定期发关于软件开发和机器学习的推特。

参考

  • [1]深度神经网络中的多任务学习概述,“CoRR,vol. abs/1706.05098,2017。【在线】。可用:http://arxiv.org/abs/1706.05098
  • [2] J. Pilault,A. E. hattami,C. Pal,“条件自适应多任务学习利用较少的参数和较少的数据改善 NLP 中的迁移学习”,2019,arXiv:2009.09139。【在线】。可用:https://arxiv.org/abs/2009.09139

如何为汇流纵断面创建和使用等值线

原文:https://towardsdatascience.com/how-to-create-and-use-isolines-to-understand-catchment-profiles-e8847bbdff68

引入等值线-基于交通网络和行程时间的流域。

在 CARTO 中创建等值线——继续阅读,了解如何创建这些等值线!资料来源:CARTO

等值线对于数据科学家来说是一个非常强大的工具,它显示了可以轻松访问给定位置的区域。您可能也听说过这些被称为等时线、贸易区或行程时间集水区。不管他们的名字是什么,概念都是一样的——他们根据设定的距离或时间(如 1 英里或 20 分钟)来衡量一个站点可访问的区域。这些计算基于实际交通网络,包括高速公路和自行车道和人行道(如适用)。

在本指南中,我们将解释等值线和固定距离缓冲区之间的区别,分享如何轻松计算等值线,并最终分享如何从中获得见解。

这篇文章由 Helen McKenzie 撰写,她是 CARTO 的地理空间倡导者。

固定距离缓冲区与等值线

说明了等值线和固定距离缓冲区之间的差异。资料来源:CARTO。

固定距离缓冲区正是它听起来的样子。这些方法根据从某个位置到每个方向的固定距离来计算该位置的集水区。它没有考虑到是否有可能在所有这些方向上旅行。

您可以在上面的可视化图中看到这个概念——蓝色圆圈是固定距离的缓冲区。它没有考虑交通网络,并表明跨水旅行是可能的。

与几何形状更复杂的等值线相比,固定距离缓冲区具有计算速度更快、存储成本更低的优势。但是,固定距离缓冲区可能会被误解,因为它们假设该距离内的所有区域都可以被个人轻松访问。由于多种原因,情况可能并非如此,例如:

  • 海岸线、河流或湖泊等自然屏障可能会阻碍旅行。
  • 人为障碍,如私有土地,可能会阻止人们进入某些地区。
  • 组成一个区域的街道网络和人行道(如果考虑活动出行模式)可能不允许集水区周围的无干扰出行。例如,街道可能是单行道或死胡同。

考虑到这一点,在任何情况下都应该使用固定距离缓冲区而不是等值线吗?绝对的!

其中一个例子是,如果您正在考虑为某个位置创建集水区,而您知道该位置周围的交通基础设施将经历重大改造。这方面的一个例子是计算新购物中心商店的销售区域(零售/房地产行业数据科学家的常见用例)。新购物中心周围的高速公路网络很可能会完全重新配置,基于当前网络的评估将完全不真实。在这种情况下,更具“指示性”的固定距离集水区更为合适。

其次,正如我们前面提到的,等值线的计算和存储成本比固定距离缓冲区更高。此外,等值线计算还利用了位置数据服务。

创建集水区:您首先需要了解的内容

在开始创建集水区之前(在本例中是使用 CARTO 创建),您需要确定几个参数。

旅行方式

分析工具箱允许你选择两种交通方式中的一种;汽车或行人。

选择“汽车”时,您的分析将仅限于允许车辆通行的运输网络部分。为了最好地模拟实际驾驶条件,集水区还将受每条街道的交通条件和限制(如单行道)的影响。

相反,在创建行人聚集区时,更多的交通网络将被开放,如人行道、自行车道和小路。这种分析也不会受到道路速度或限制的影响,但会避开被认为对行人不可用的主要高速公路,如州际公路和高速公路。

由于行人和骑自行车的人通常使用相同的基础设施,您可以将此转化为骑自行车的人的分析。骑自行车的人通常比行人行驶速度快 3.75 倍,该数字可用于适当缩放等值线,例如,30 分钟周期等时线可根据大约 2 小时的步行计算。

在下面的例子中,您可以看到源自纽约市中央公园东南角的汽车集水区和行人集水区之间的差异(白色圆盘)。绿色的 5 分钟步行集水区在各个方向都行驶了相同的距离,包括穿过中央公园。与之形成对比的是紫色的 3 分钟步行等时线,它既不能穿越公园,也不能违反单向限制,例如沿着南行的第五大道行驶。

驾驶时间与步行时间等时线。资料来源:CARTO

等时线与等值线

创建集水区时,有两种主要类型可供选择;等时线(基于行程时间的集水区,例如,我在 10 分钟内可以走多远?)或等值线(基于行程距离,例如,在 1 公里内,我可以沿交通网络行驶多远?).

当分析主动出行模式(即步行和骑自行车)时,选择哪种并不重要,因为旅行者通常会以相当恒定的速度移动。然而,如果你考虑的是车辆模式,这就很重要了,因为等时线会受到道路速度和交通状况的影响,而等值线则不会。

创建等值线:指南

现在我们准备等时线!这些功能目前在连接到 Google BigQuery雪花数据仓库时可用,我们将从 SQL 控制台运行该分析。

带 SQL 的等值线

首先,确保您使用的是点表;如有必要,ST_CENTROID()可用于从线和面创建中心点。

对于 BigQuery 用户,基本语法如下。用户应该选择模式是汽车还是步行,以及他们是否想根据时间或距离来测量他们的贸易区。对于时间,使用的数字(整数格式)应该以秒为单位,对于距离,应该以米为单位。您需要引用位置数据服务(LDS) API URL 和令牌。这些都可以在 CARTO 工作区的 Developer 标签中找到。

CALL ‘carto-un’.carto.CREATE_ISOLINES(
 ‘input-query’,
 ‘my-schema.my-output-table’,
 ‘my_geom_column’,
 ‘car/walk’, number, ‘time/distance’,
 ‘my_lds_api_url’, ‘my_lds_token’
);

如果你是雪花用户,你可以点击这里查看我们的数据仓库等值线运行指南

如果您的数据仓库不在美国地区,请确保用适当的前缀替换“carto-un”。

看看我们的例子!下面的地图显示了从佛罗里达州奥兰多的麦当劳步行 15 到 30 分钟范围内的区域。这个位置是通过我们的数据合作伙伴 Safegraph 的 Places 数据集获得的。

15 分钟和 30 分钟步行等时线,源自奥兰多的麦当劳店。资料来源:CARTO。

等值线和空间洞察力

有时,创建贸易区可能是您分析的最终目标。然而,总的来说,这只是从您的分析中获得进一步见解的关键一步。

以下是通过创建等值线可以获得的洞察力类型的三个示例。

洞察力 1:贸易区人口统计

能够理解在一个贸易区内生活或工作的人的数量和特征是无价的。例如,零售分析师可以根据谁会真正光顾他们的商店来评估每个商店的潜在市场规模。他们可以更进一步,计算出有多少人可能步行、骑自行车或开车去他们的商店,并以此来规划停车设施或集中营销活动投资。

理解这一点的一个好方法是使用浓缩工具。这些工具允许用户根据另一个数据集的属性快速、轻松地计算出某个区域的特征——无论是他们自己的数据集还是来自第三方数据源

扩展我们在奥兰多的麦当劳的例子,我们已经丰富了我们的 30 分钟步行等值线与总人口(可通过美国社区调查这里免费获得)以及“快速休闲亲和力”指数。该指数可通过 Spatial.ai 的 Geosocial Segments 数据集获得。它根据人们在社交媒体平台上分享的经历、个性和感受,根据 72 个指数给人们打分。

使用等时线了解商店集水区的人口统计资料。资料来源:CARTO。

洞察力 2:反向贸易区人口统计

在许多情况下,实际上你最感兴趣的并不是那些能够访问服务的人;是那些不知道的人。能够找出人们不容易进入商店或服务的地方是制定未来扩张战略的基础。在这些情况下,最感兴趣的是每个集水区之外的区域。

例如,在下面的地图中,浅蓝色区域突出显示了我们的研究区域(由佛罗里达州的奥兰治县、奥西奥拉县和塞米诺尔县组成)中距离麦当劳步行 30 分钟以上的所有地方。再次使用我们的丰富工具,我们可以计算出有 1,783,500 名居民居住在该地区,约占总人口的 84%!

这一数字有助于战略家决定该研究区域是否是增加额外地点的有力候选,因为它有如此大的未开发市场。下一步将是进一步探索研究区域内的哪个位置是新位置的最佳位置。

反向集水区-使用等时线来了解无法访问设施点的区域。资料来源:CARTO。

洞察力 3:可访问的服务评估

我们的最后一个 insight 示例是使用等值线来评估附近的配套或竞争设施。新住宅开发背后的规划者可能需要了解有多少相关服务(如学校、公交车站和诊所)可在其开发的旅行时间阈值内到达。物流公司可能希望将车队管理决策或配送中心位置建立在与供应链元素的实际接近程度上。

基于我们的示例用例,下面的地图显示了每家餐厅 30 分钟步行范围内的其他快速服务餐厅(qsr)的数量,以帮助评估当地的竞争。探索互动版这里

使用等值线了解竞争对手的分布。来源(CARTO)。

使用空间连接(关于这个的更多细节,请点击)我们可以评估每个 30 分钟步行范围内的竞争对手品牌,还可以确定哪个位置有最多的竞争对手。这些信息对于推动市场营销和招聘等策略非常重要。

感谢阅读我们关于等值线的帖子!我们希望我们不仅向您展示了它们在帮助您理解网站的地理环境方面有多么强大,而且展示了它们是多么容易创建。

如何创建和可视化复杂的雷达图

原文:https://towardsdatascience.com/how-to-create-and-visualize-complex-radar-charts-f7764d0f3652

使用 Matplotlib 中的多种刻度和标签调整创建高级且高度灵活的极坐标图

图片作者。

adar 图表,也称为极坐标图、蜘蛛图或网状图,是在一张图片中清晰地可视化大量维度或特征(如聚类结果)的好方法。

用 Python 编写雷达图可能非常棘手。幸运的是,已经有关于它们的全面的操作指南教程文章然而,细节决定成败。想象你的数据有不同的小数位数或者你的变量名很长。现有的解决方案将无法可视化这些情况。这就是我写这篇文章的原因。

TL;博士;医生

  • 当前的解决方案不支持多尺度,并且缺乏对标签的正确可视化
  • 所提出的解决方案在彼此的顶部创建了几个轴,以提供多个刻度
  • 如何使用这个解决方案的几个代码示例可以在这里找到

你将从这篇文章中学到什么

  • 当前解决方案失败的案例
  • 如何创建具有多种比例和更好的标签格式的高级雷达图
  • 这种方法背后的概念以及针对高级用户的简单解决方案
  • 一个(初学者友好的)扩展版本,有几个例子

每个解决方案都有一个代码片段。本文中使用的示例数据是由 scikit-learn 包提供的葡萄酒数据集 (CC BY 4.0 参见来源)。

当现有解决方案失败时

如开头所述,我们可以找到经典雷达图绘制情况的现有解决方案。然而,有些情况下这些解决方案会失败。在我们讨论可能的解决方案之前,我会告诉你为什么这些解决方案会失败。

我们使用的示例数据集

以下代码片段加载葡萄酒数据集,应用经典聚类( k-means )方法,并将聚类数作为新列( cluster )添加回数据框。在最后一行中,我们通过聚类列对数据进行分组,并通过每个聚类计算每个特征平均值

代码片段 1。创建示例数据。

现在我们可以使用这两个数据框了(图 1)。数据数据框(表 1)包含每行的相关聚类,而结果数据框(表 2)是聚类特征的汇总(每个聚类的每个特征的平均值)。通过查看不同的值,我们可以看到,该数据集具有不同的标度(例如,灰分值与脯氨酸值的比较)。

图一。表格摘录(图片由作者提供)。

Plotly

交互式图形库 Plotly 提供了用极坐标图可视化数据的选项。以下代码片段基于他们的文档

代码片段 2。用 Plotly 创建雷达图。

代码的结果如下面的图 2 所示。

图二。Plotly 的问题(图片由作者提供)。

正如我们所见,不同的集群破坏了剧情(我们看不到它们的结尾)。这个问题的解决方案是改变第 15 行中的范围参数。

然而,我们的例子数据有不同的尺度**。列灰分(图 1 表 2)的平均值约为 2.3,而脯氨酸的平均值约为 1.100。所以即使我们增加范围,脯氨酸的值仍然会破坏曲线。如果我们将整个图放在脯氨酸的适当范围内,其他变量(因为它们的尺度小得多)将不会清晰地可视化,因为它们的尺度小得多(见图 3)。**

图 3。Plotly 的问题(脯氨酸的调整范围)(图片由作者提供)。

plot ly意识到当数据具有不同比例时,绘图崩溃的问题,但实现需要赞助。除了这个缺点之外,Plotly 的优点是,围绕圆的特征标签清晰可见。

Matplotlib

Matplotlib 还提供了极坐标图解决方案。然而,他们的例子也只支持一种尺度。下面的代码片段利用了它们定义的类。

代码片段 3。用 Matplotlib 创建雷达图。

如果我们运行代码片段,我们可以看到他们的解决方案(图 4)没有正确定位标签而没有重叠,只有脯氨酸值(因为比例)清晰可见。

图 4。Matplotlib 提供的极坐标图解决方案的问题(图片由作者提供)。

解决方案

这个解决方案的核心灵感来源于 stackexchange 上的一个答案。主要思想是为每个变量创建一个 axes 对象。每个轴对象通过提供的最小-最大值获取并绘制其比例。为了确保图表的正确可视化,除了第一个对象及其副本之外,所有轴对象都被设置为不可见,以便只有它们的绘制刻度值保持可见。

第一个轴对象负责绘制网格,其副本绘制图表线并填充区域。为了确保rgrid、标签以及绘制的线条和区域的正确定位,必须采取这种解决方法。

简单的解决方案

下面的代码片段展示了一个简单的解决方案。它可用于绘制雷达图,无需任何附加格式。高级 Matplotlib 用户可以轻松地修改/扩展代码,以格式化特定的部分,如网格。

代码片段 4。简单的解决方案。

下面的代码片段展示了如何将上面的代码用于我们的示例数据。

代码片段 5。对示例数据应用简单的解决方案。

我们的 ComplexRadar 类需要每个变量的范围作为元组(min,max)。当然,我们可以手动为每个变量创建一个元组,但我也想向您展示如何更加自动化地完成这项工作。第3–5行通过使用。describe()函数并把它们放在一个列表中(line 8)。结果如下所示(图 5)。

图 5。普通解决方案结果(图片由作者提供)。

正如您所看到的,雷达图可以处理几个轴(每个轴对应一个变量),并负责清楚地放置变量的标签(多亏了 textwrap 模块)。

如果你的每个变量都有一个相似的范围,你可以用一个(最小,最大)元组乘以变量的个数。例子:ranges =[(1,10)]*len(df.columns)

扩展版本

基于上面的普通版本,我还创建了一个扩展版本。扩展版本使用字典来配置/样式化图中的每个对象,以在可视化方面提供更大的灵活性。这个版本也是在本文的特色图片中创建不同可视化效果的版本。

代码片段 6。扩展解决方案。

下面的代码片段显示了如何使用扩展版本。

代码片段 7。对示例数据应用扩展解决方案。

主要的变化是引入了一个可选的 format_cfg 字典。这一个可以被用来样式化和格式化极坐标图的不同部分。上面的示例代码在第10–16行显示了如何设置不同的参数。要了解哪些选项可用,可以查看源文件,我将链接放在该文件的相关部分。

上面代码的结果可以在下面的图 6 中看到。

图 6。使用扩展代码片段的结果(图片由作者提供)。

如果你对进一步的例子感兴趣(例如,如何在特色图片中创建图表),请查看我的 colab 笔记本

结论

创建雷达图可能相当具有挑战性。现有的解决方案可能有助于简单的任务。但是,当您必须处理不同的比例和标签格式时,需要进行大量的调整和变通。本文希望通过提供管理复杂需求的解决方案,为您节省大量时间(和精力)。

来源

UCI 机器学习知识库:葡萄酒数据集知识共享署名 4.0 国际 (CC BY 4.0)许可”。

https://data science . stack exchange . com/questions/6084/how-do-I-create-a-complex-radar-chart

如何创建定制的 Streamlit 组件

原文:https://towardsdatascience.com/how-to-create-custom-streamlit-components-de6a00a7d5ab

如何使用 Streamlit 构建一切

背景由法库里安设计Unsplash 上,由作者编辑。

Streamlit 作为构建 web 应用程序的纯 Python 解决方案广受欢迎。它使得构建动态的、以数据为中心的应用程序变得异常简单。学习曲线实际上是不存在的。

Streamlit 应用程序的屏幕截图(左)和创建它所需的代码(右)。

只需几行代码,我们就可以通过简单地实现预构建的 Streamlit 组件来组装干净的交互式应用。

Streamlit 设计了大量预构建组件。如果你找不到你需要的,甚至还有社区构建的组件。

将这些几乎像“乐高”积木一样的组件放在一起很容易,这使得 Streamlit 成为 ML 工程师的理想选择。让我们专注于 ML,同时仍然能够与世界分享我们的应用和工具。

然而,有时我们会陷入困境,根本没有涵盖我们所需要的组件。如果需要,我们仍然可以构建自己的定制组件。

要做到这一点,我们需要从底层的网络技术着手,让 Streamlit 自己发挥作用。所以这不像使用预构建组件那么简单。然而,由于预制的模板,创建一个新组件并不太难。

在本文中,我们将确切地了解如何创建定制组件。我们将关注于使用材料 UI 设计元素设计一个交互式卡片组件。

设置和安装

我们将使用 Node.jsNPM 来开发我们的卡组件。它们可以从这里安装在 Windows/Mac/Linux 上,或者在 Mac 上使用自制软件:

**brew install node**

安装后,我们可以确认两个包都安装了:

**node -v***AND***npm -v**

确保您的 Python 环境中安装了 Streamlit。如果没有,就**pip install streamlit**

从模板开始

自定义组件的 React 模板设置

我们将从克隆streamlit/组件模板 repo 开始:

我们可以从 Streamlit 中克隆出组件模板。

在这里,我们将找到一个/template目录,其中包含:

模板组件目录结构概述。

突出显示最重要的文件和目录。其余的我们可以完全忽略。

模板组织

在我们开始构建任何东西之前,让我们组织我们的模板。首先,我们将所有默认的MyComponent引用更新为更具描述性的CardComponent

  • /my_component更名为/st_card_component
  • index.tsx中的MyComponent替换为CardComponent,将__init__.py中的my_component替换为CardComponent
  • 重命名MyComponent.tsx并替换代码中的MyComponent引用

最后一次更新是对package.json中的"name"参数,我们将其命名为streamlit_card_component

节点包

接下来,我们在终端窗口中导航到/frontend目录,并使用npm install安装package.json中指定的必要节点包。

npm install 安装 package.json

并安装材料 UI 卡所需的其他依赖项:

npm install @mui/material @mui/icons-material @emotion/react @emotion/styled

如果您看到一个上游依赖冲突错误,通过在 install 命令中添加--legacy-peer-deps来强制安装。

运行组件

现在,我们可以通过在终端窗口中输入npm start来运行组件的当前状态。

localhost:3001 上托管组件

前往http://localhost:3001我们将什么也看不到,因为我们托管的是组件,而不是Streamlit 应用。在开发过程中,我们需要两者都运行。组件正在运行,所以我们通过导航到/card_component目录(在一个新的终端窗口中)并键入streamlit run __init__.py来初始化我们的应用程序。

默认组件模板。

这将打开一个新的浏览器窗口,看起来像上面的默认 Streamlit 组件模板。

构建组件

创建 MUI 卡组件

我们现在需要修改这个模板来创建卡片格式。这大部分是在CardComponent.tsx文件中完成的。如果我们现在看,那里有很多。我们不需要大部分,所以让我们先把它拆了。

这些基本要素就是我们所需要的,CardComponent类,我们从render中的类返回的 HTML,以及我们的组件返回到我们的 Streamlit 实例的export

我们可以修改它来创建我们的卡组件。首先,让我们设置组件的绝对核心。基本信息的简单显示。

卡片元素的高级细分。

每张卡片将显示一个标题、副标题、段落和超链接,显示为材料图标。

我们在CardComponent.tsx__init__.py中的card_component函数中向组件添加可通过的参数。

CardComponent.tsx中,我们通过this.props.args引入参数。

card_component函数充当 React 组件的初始化,通常从前端 Streamlit 脚本调用。如果我们看一下我们的 Streamlit 窗口,我们会看到一个错误:

TypeError 由现在过时的代码引发。

这是因为调用我们的card_component的代码仍然只传递一个值"World",而新组件需要四个参数;titlesubtitlebodylink

在开发过程中,前端脚本临时存储在__init__.py中,所以我们在调用card_component的地方更新这个脚本以反映这些变化。

现在我们可以看到我们的卡组件的第一个版本。

“卡”的简单实现,没有任何格式或结构。

它并不漂亮,但组件的核心在那里。我们有标题、副标题、正文和链接。我们开始做造型吧。

材质用户界面样式

我们将使用 MUI 来设计和实现卡的功能。幸运的是,我们几乎可以通过在 MUI 组件页面中找到符合我们要求的卡来复制和粘贴所需的代码。

MUI 组件页面中的卡组件。我们点击 < > 图标查看代码示例。

我们需要在我们的CardComponent.tsx文件的顶部添加几个导入。

在组件本身中,我们添加了各种卡片和按钮标签。

这样,我们就可以刷新页面,看到新的卡片格式页面。

还缺少最后一个细节。使用的字体与 MUI 示例不一致。为此,我们需要安装并导入 Roboto 字体。从/frontend目录,我们在终端窗口中输入npm install @fontsource/roboto。然后将字体添加到CardComponent.tsx导入:

现在,我们的组件与 MUI 示例相匹配。

很好,现在让我们清理一下__init__.py,从我们的 cards 组件中删除任何不需要的东西,并将它作为一个单独的组件在 Streamlit 项目中实现。

发布组件

Streamlit 组件通常通过pip installimport集成到单个项目中。我们将发布我们的卡组件来遵循相同的示例。

将 Streamlit 组件发布到 PyPI

首先,我们通过设置_RELEASE = True告诉__init__.py使用脚本的版本版本。这告诉 Streamlit 从/frontend/build目录中提取组件。目前,这个目录不存在。我们必须通过 NPM 创造它。

为此,我们在终端中导航到/frontend并输入npm run build。该命令创建/frontend/build目录,其中包含组件发布版本中使用的编译代码。

执行 npm run build 构建编译后的组件代码。

接下来,我们导航到顶层目录并创建一个 Python /dist文件夹,其中将包含 pip 包轮。

在构建 dist 文件夹之前,我们需要修改一些东西。首先将setup.py中的name参数改为name="st_card_component"

为了将编译后的代码包含在构建目录中,我们必须将目录从MANIFEST.in更新到recursive-include **st_card_component**/frontend/build *

最后,我们必须将__init__.py中的组件名称更新为"st_card_component":

我们现在准备创建发行版。使用终端,我们执行python setup.py sdist bdist_wheel,在/dist文件夹中我们会看到:

  • st_card_component-0.0.1.tar.gz
  • ST _ card _ component-0 . 0 . 1 . py3-none-any . whl

现在我们继续上传到 PyPi ,在那里pip install包被下载。首先,我们用pip install twine安装 twine,然后用python -m twine upload --repository pypi dist/*上传我们的包(都来自组件的顶层目录— /st-card-component)。

当发布我们组件的新版本时,我们必须更新 *setup.py* 文件中的版本号。

使用组件

我们终于可以像使用其他组件一样使用我们的 Streamlit 组件了。组件包安装有pip install st-card-component

让我们创建一个“测试”脚本。

还有我们定制的 Streamlit 卡组件!

这就是为 Streamlit 构建定制和可共享组件的指南。我们已经介绍了很多,从默认模板到在 React 中构建组件,甚至在 PyPi 上发布组件。

当然,这是一个极其简单的组件。我们可以在这里做更多的事情。我把那个留给你。

您可以通过此链接了解最新的 ML 文章。我还在 YouTube 上上传每周的 ML 和 NLP 视频。

感谢阅读!

🎁面向语义搜索的 NLP 免费课程

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

文章笔记本脚本

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

如何在 Windows 10/11 上用 WSL2 创建一个完美的机器学习开发环境

原文:https://towardsdatascience.com/how-to-create-perfect-machine-learning-development-environment-with-wsl2-on-windows-10-11-2c80f8ea1f31

一切包括:终端,Docker,Anaconda,Git,Jupyter 实验室,GPU 支持,…

来自 PexelsLina Mamone 的照片

什么是 WSL,为什么需要它?

就是这样。我已经受够了。失败的安装,错误信息,取笑 Windows 的迷因,人们认为他们更酷,因为他们使用 Linux…

今天,在使用 Windows Subsystem For Linux 2 (WSL2)的所谓愚蠢的 Windows (10/11)之上,安装一个成熟的 Linux 开发环境就结束了。

WSL2 使您能够在 Windows 中运行完整的 Linux 环境。它有一个专用的文件系统和 Linux 终端,同时允许文件和服务与 Windows 代码编辑器和应用程序无缝共享。

作为机器学习工程师或数据科学家,您将从 Linux 环境中受益匪浅。您会发现安装和使用 TensorFlow、PyTorch 或 Docker 等技术要容易得多,因为 Linux 可以更顺畅地利用系统资源,尤其是 GPU。

在本教程结束时,您将拥有一个完全成熟的 Linux 环境,包括以下内容:

  • 定制终端
  • VSCode 和 PyCharm 配置为使用 Windows 设置的 IDE
  • 安装 Git、Anaconda、Python 和 Docker
  • Jupyter 实验室配置了最好的扩展
  • 适用于 CUDA 和 cuDNN 的 NVIDIA GPU 驱动程序,因此您可以通过一条pip语句安装 GPU 库。

让我们开始吧!

https://ibexorigin.medium.com/membership

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

https://alphasignal.ai/?referrer=Bex

1.卸载现有安装(可选)

即使您安装了 WSL,我也建议从头开始,因为您可能已经破坏了您的环境,这可能会阻止我们实现接下来的一些步骤。

作者图片

你的发行版可能会有不同的名字(Debian,Kali 等)。)

2.如果你还没有安装 Docker 桌面

请通过运行docker --version检查您是否在 Windows 上安装了 Docker Desktop。如果没有打印版本,请转到此 Docker 安装页面并下载/运行可执行文件。

Docker 下载页面的屏幕截图

3.检查先决条件

WSL2 需要 Windows 10、OS build 19041 或更高版本或 Windows 11。请转到“设置”>“系统”>“关于”,然后向下滚动到“Windows 规格”,进行检查。

作者图片

4.如何安装 WSL2

如果满足先决条件,您需要一个命令来安装 WSL2:

wsl --install -d Ubuntu

请在以管理员权限打开的命令行(CMD)上运行上述命令(右键单击并选择“以管理员身份运行”)。

wsl命令的-d标签指定了 Ubuntu 发行版,这是最简单的开始。要检查安装是否成功,运行wsl -l -v命令查看版本。

$ wsl -l -v
  NAME                   STATE           VERSION
* Ubuntu                 Running         2

5.设置用户名和帐户

安装完成后,你会在开始菜单中看到一个 Ubuntu 应用程序。

当你第一次打开它时,它会要求你设置用户名和密码。我把我的用户名设为bexgboost,这和我的 Windows 用户名不同,以免混淆。

终端提到sudo命令,相当于以管理员身份运行应用。当您开始使用 Linux 终端时,您会发现在命令之前添加sudo命令可以解决许多错误。

在本教程的剩余部分,我们将同时使用 Windows 和 WSL2 终端。对于 Windows,我将它们称为“CMD ”,对于 WSL2,我将它们称为“终端”。

6.如何在 WSL2 上更新和升级软件包

在新的库安装或版本更改后,您应该定期更新 Linux 包。以下是执行此操作的命令:

sudo apt update && sudo apt upgrade

这些命令类似于 Windows Update,但速度更快。update命令下载新的库/包更改,而upgrade命令执行它们。

如果您对 Linux 完全陌生,请查看这些最常用的终端命令以便更有效地理解本文的其余部分。

7.了解 WSL2 中的文件系统

操作系统由文件/应用程序和与之交互的图形用户界面组成。在 Windows 中,您同时使用了 CMD 和文件浏览器。在 WSL2 中,您将主要使用终端来与一切进行交互。

WSL2 不自带 GUI (Windows 11 现在自带 GUI,点此查看)。起初这似乎是一个限制,但是通过终端工作要快得多,提供了灵活性,并且使你看起来像一个黑客。

WSL2 可以被认为是安装在 Windows 之上的 Linux 文件系统。它的安装文件夹可以在网络路径\\wsl$\Ubuntu中找到。要在终端中打开它,请键入cd /。当你运行列出目录的ls时,你会看到很多目录。

我们只对其中两个感兴趣:homemnthome包含您的用户账户信息。现在,只有一个目录以你的 UNIX 用户名命名(我的是/home/bexgboost)。每次启动新的终端会话时,路径都设置为该文件夹。这就是为什么/home/username被称为主目录。

开头的正斜杠/很重要。

当你改变目录时,你可以不带参数地调用cd或者用~引用它。

/mnt文件夹包含 Windows 盘和 D 盘的链接。在 WSL 之前,我习惯于在桌面上存储我的项目和代码。下面是将它们复制到 home 中的命令:

cp /mnt/users/bex/Desktop/* .

cp代表“复制”。bex是我的 windows 用户名。

尽管 WSL2 是一个 Linux 文件系统,但是您可以使用 Windows 资源管理器打开它的目录。在任何目录中,运行explorer.exe .命令。下面,我们正在打开主目录:

作者 GIF

8.如何为 WSL2 安装 Visual Studio 代码

如果您在 Windows 上安装了 VSCode,则可以使用它打开任何 WSL2 文件夹。你只需要安装远程扩展开发包扩展。

作者图片

然后,转到终端,更新/升级包。然后,切换到任意目录并运行code .打开该文件夹的 VSCode 项目。

作者 GIF

使用 Windows VSCode for WSL2 项目可以共享 VSCode 设置和主题。

9.如何为 WSL2 安装和设置 Git

git已经预装在 WSL2 中(如果没有,运行sudo apt-get install git)。

通过运行以下命令设置您的git凭证:

然后,在 CMD 上运行git update-git-for-windows。然后,在 Ubuntu 终端上,运行以下命令:

git config --global credential.helper "/mnt/c/Program\ Files/Git/mingw64/bin/git-credential-manager-core.exe"

这将设置 Git 凭证管理器(GCM ),以便您可以将提交无错误地推送到远程 repos。

10.如何为 WSL2 安装 Docker

这一步很简单,因为我们已经在一开始安装了 Docker。要将 Docker Desktop 链接到 WSL2,请进入 Docker Desktop >设置>资源> WSL 集成,并将 Ubuntu 按钮切换到“开”。然后,按应用并重新启动终端以使更改生效。

作者图片

之后,您应该可以在 WSL2 终端上成功运行docker --version

https://ibexorigin.medium.com/membership

11.如何在 WSL2 上安装 Anaconda

对于 Python 版本和管理包,我更喜欢 Anaconda。(转到这一步的末尾,查看不带 Anaconda 的常规 Python 安装)。

第一步是进入https://www.anaconda.com/products/distribution页面。

作者图片

Linux 文件不像 Windows .exe可执行文件。如果你点击下载链接,你会发现它们的扩展名是.sh

因为我们说过 Linux 没有 GUI 来安装应用程序,所以我们将使用终端来下载并安装适用于 Linux 的 Anaconda 可执行文件。首先复制下载链接,到终端。

键入wget并将下载链接粘贴到它旁边(在主目录中执行此步骤)。下面是我复制的下载链接的样子:

$ wget https://repo.anaconda.com/archive/Anaconda3-2022.10-Linux-x86_64.sh

是一款优秀的 CLI 工具,可以下载任何带有 URL 的文件。上面的命令将下载一个名为Anaconda3-2022.10-Linux-x86_64.sh的文件。

要安装该文件,请使用带有文件名的bash命令,并按照说明操作:

$ bash Anaconda3-2022.10-Linux-x86_64.sh

要检查安装,您可以运行conda --versionwhich python:

$ conda --version
conda 22.9.0

$ which python
/home/bexgboost/anaconda3/bin/python

输出显示 Anaconda 安装在主目录的anaconda3目录下。所有未来的环境和包都将存储在那里。

安装完成后,删除 Anaconda 可执行文件:

$ rm -rf Anaconda3-2022.10-Linux-x86_64.sh

如果您不想使用 Anaconda,下面是如何安装 Python、pip 和 venv:

$ sudo apt update && upgrade
$ sudo apt install python3 python3-pip python3-venv ipython3

12.如何在 WSL2 上安装 Jupyter Lab

现在,最好的部分——安装 Jupyter 实验室,它是数据科学家 ide 皇冠上的宝石。在基础环境中,运行pip install jupyterlab

在基础环境中安装 Jupyter Lab 及其扩展将使其可用于所有未来的 conda 环境,并且不需要单独的设置。

要打开 Jupyter 实验室会话,请在所需目录中运行jupyter lab --no-browser。要在浏览器中打开会话,您必须复制底部带有令牌的会话链接。

作者图片

当您启动 Jupyter Lab 时,您将会看到您的 conda 环境在启动程序中是不可用的。要将现有的(或新的)conda envs 添加到 Jupyter Lab,请使用以下命令:

# Create a new env
$ conda create -n new_env -y

# Install ipykernel and add the env
$ pip install ipykernel
$ ipython kernel install --user --name=new_env

一旦您重新启动 Jupyter 实验室会话,env 将出现在启动器中。

作者图片

要从 Jupyter Lab 中删除 conda 环境,您可以运行以下命令:

$ jupyter kernelspec uninstall env_name

13.如何为 Jupyter Lab 安装拼写检查器和代码格式化程序(可选)

我最喜欢的两个 Jupyter 实验室扩展是拼写检查器和代码格式化器。要安装它们,请在基本环境中运行以下命令:

pip install jupyterlab-spellchecker
pip install jupyterlab-code-formatter
pip install black isort

安装后,Markdown 单元格中拼写错误的单词将被标记为红色,一个新图标将格式化代码。您可以在高级设置编辑器中将这两个扩展配置为每次保存时运行。

作者 GIF

14.如何格式化 WSL2 终端(可选)

现在,Ubuntu 终端看起来很丑:

作者图片

你的可能比我的更糟,因为我已经做了一些修补。要格式化终端提示符,通过键入code ~打开带有 VSCode 的主目录,并打开名为.bashrc的文件。

作者图片

向下滚动到文件的末尾,粘贴这个要点中的代码。在第 1 行,用你想要的窗口标题替换WSL2 Bash,在第 4 行,用你的用户名替换bexgboost

保存/关闭文件并关闭 VSCode。要应用更改,运行根目录中的source .bashrc:

作者图片

如您所见,新的提示符看起来更好。它用不同的颜色显示路径、提示名和 git 分支名,并且总是以新的一行开始提示。

在要点的末尾,您会看到我为最常用的命令添加了几个别名。例如,ggit的简称,jljupyter lab --no-browsergcb创建一个新的分支并将其检出,等等。您可以随时编辑.bashrc文件来添加您自己的别名。

要改变提示的格式或理解其背后的代码,可以阅读这本优秀指南。

15.如何将 WSL2 Linux 终端添加为 PyCharm 内置终端(可选)

我心爱的 IDE 在 Jupyter Lab 之后就是 PyCharm Professional。由于 PyCharm 只安装在 Windows 上,所以它的内置终端链接到 CMD 或 Git Bash。

要使用 WSL2 Ubuntu 终端,进入设置>工具>终端>外壳路径并粘贴wsl.exe --distribution Ubuntu。然后,关闭所有终端标签并重新打开它们,使 Ubuntu 终端链接到 PyCharm。

然后,要将任何 WSL2 文件夹作为 PyCharm 项目打开,使用explorer.exe .打开该文件夹,并从上下文菜单中选择“将文件夹作为 PyCharm 项目打开”选项。PyCharm 默认支持 Windows 上的 WSL2,并将识别其文件夹。

作者 GIF

16.如何在 WSL2 上安装 NVIDIA CUDA 和 cuDNN 驱动程序(100%有效)

最后也是最具挑战性的一步是为 WSL2 安装 GPU 支持。要完成这一步,您应该已经为您的 NVIDIA GPU 安装了 CUDA 和 cuDNN 驱动程序,并且应该能够在 GPU 支持下运行 TensorFlow 等库,而不会出现任何错误。

如果你不能在 Windows 上运行带 GPU 的 TensorFlow,首先,按照我写的这篇文章安装带 GPU 支持的 TensorFlow:

该指南将教您在 Windows 系统上安装 CUDA 11.2 和 cuDNN 8.1 驱动程序/库。我们为 CUDA 和 cuDNN 选择 11.2 和 8.1 版本,因为 TensorFlow v. 2.6+需要这些版本。按照教程操作后,打开 Ubuntu 终端并更新/升级:

$ sudo apt update && sudo apt upgrade

然后,极其小心地在根路径中一个接一个地运行下面的命令,因为如果你弄乱了它们,它可能会破坏你的整个 WSL2 安装,你可能不得不从头开始。

这些命令需要一些时间来安装 CUDA 驱动程序。现在,关于 cuDNN 车手:

$ sudo apt-get install libcudnn8
$ sudo apt-get install libcudnn8-dev
$ sudo apt-get update && sudo apt-get upgrade

最后,运行以下命令来清理根目录,因为我们下载了一些文件:

$ rm -rf cuda-keyring_1.0-1_all.deb
$ rm -rf cuda-repo-wsl-ubuntu-11-2-local_11.2.0-1_amd64.deb
$ rm -rf cuda_11.2.0_460.27.04_linux.run

要检查 GPU 支持是否正常工作,请在新的 conda env 中安装 TensorFlow 2.10。以下是命令:

$ conda create -n tf python=3.9 -y
$ conda activate tf
$ pip install tensorflow==2.10
$ python -c "import tensorflow as tf; print(tf.config.list_physical_devices('GPU'))"

如果你得到了[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')],输出,恭喜你!您拥有一个有 GPU 支持的成熟的 Linux 环境!

结论

如果你过去想在 Windows 中运行 Linux,你必须使用复杂的技术,如 VirtualMachine 或 vagger,这会让你讨厌 Linux 和 Windows,并最终迫使你购买昂贵的 Mac 电脑(他们说,这可能是值得的)。现在,您可以使用 Windows 子系统 Linux (WSL2)的一个命令获得 Windows 和 Linux 的双重优势。

感谢您的阅读!

https://ibexorigin.medium.com/membership

有用的资源:

我的更多故事

💔-step-feature-selection-guide-in-sklearn-to-superchage-your-models-e994aa50c6d2>

如何在《铁锈》中创造情节

原文:https://towardsdatascience.com/how-to-create-plot-in-rust-fdc6c024461c

铁锈绘图仪简介

克劳迪奥·施瓦茨在 Unsplash 上的照片

O'Reilly Data & AI 简讯报道,2021 年,数据/AI 专业人士中收入最高的编程语言之一是 Rust。随着 Rust 的出现,数据科学项目最近变得更加普遍。数据可视化无疑是这些项目中的一个领域。在这篇文章中,我将分享如何在 Rust 中使用一个名为 Plotters 的库创建绘图。

什么是密谋者?

Plotters 是一个绘图库,旨在加快 Rust 中高质量数据可视化的生产。它在 Github 上有超过 1.8k 的星星,是绘制数据的库之一。

plotters 没有直接解决绘图问题,而是采用了一种非常不同的方法,它提供了一种方便的绘图 API,使绘制绘图更加简单。在绘图仪中编写 Rust 代码可能比在 ggplot2 或 Matplotlib 中编写花费更多的时间。

绘图仪入门

由于这不是一个 Rust 博客帖子,而不是每一行代码的含义,我将更多地关注于获取数据以开发绘图仪中的绘图。

让我们首先创建名为 rust_viz 的项目

cargo new rust_viz --bin

创建 rust 项目后,还会创建一个名为“Cargo.toml”的清单。我们可以在这个清单中添加三个库供以后使用: csv、绘图仪和快速浮点。

[dependencies]
csv = "1.1"
plotters = "0.3"
fast-float = "0.2"

你现在应该准备好创建 Rust 中的第一个情节了!

在 Rust 中创建绘图仪图形的基本逻辑可以描述如下:

  • 根据需要转换数据集
  • 使用BitMapBackend绘制位图
  • 创建图表上下文,用于高级图形绘制
  • 绘制一个数据序列,它被抽象为绘图仪中元素的迭代器

按作者在 Rust | Image 中创建情节的步骤

散点图

散点图|作者图片

我们将创建的第一个地块基于 Top Genres 文件,它是名为“ House Sales in King County,USA ”的 Kaggle 数据集的一部分。我们将首先使用它的价格sqft_living 列来创建一个散点图。这是数据集的样子

id,date,price,bedrooms,bathrooms,sqft_living,sqft_lot,floors,waterfront,view,condition,grade,sqft_above,sqft_basement,yr_built,yr_renovated,zipcode,lat,long,sqft_living15,sqft_lot15"7129300520","20141013T000000",221900,3,1,1180,5650,"1",0,0,3,7,1180,0,1955,0,"98178",47.5112,-122.257,1340,5650"6414100192","20141209T000000",538000,3,2.25,2570,7242,"2",0,0,3,7,2170,400,1951,1991,"98125",47.721,-122.319,1690,7639

美国金县房屋销售 许可 CC0:公共领域

下面是在 Rust 中读取 CSV 文件的代码行:

let mut rdr = csv::Reader::from_path("~/Downloads/kc_house_data.csv")?;

由于 Plotters 需要一个迭代器来绘制序列,我们需要将 Price 和 Sqft Living 字段读入两个向量,并为它们执行从 string 到 float 的数据转换。这里需要注意的一点是,当我们使用f64时,cartesian_2d 也将使用浮点数而不是整数。否则,错误将显示"预期浮点数,找到整数 rustc(E0308)。“我们把价格的数字除以 1000.0 来归一化数据,这样结合 sqft live 更容易观察。这里使用快速浮点库来解析价格字段中的科学概念。

for result in rdr.records() {
        // The iterator yields Result<StringRecord, Error>, so we check the
        // error here..
        let record = result?;
        match record.get(2) {
            Some(i) => {
                let tmp: f64 = parse(i).unwrap();
                price.push(tmp/1000.0)
            },
            _ => ()
        }
        match record.get(5) {
            Some(i) => {
                sqft_living.push(parse(i).unwrap())
            },
            _ => ()
        }
    }

然后,我们可以执行 zip 函数,将两个向量拼接成一个元组向量。

let price_sqft_living: Vec<(f64, f64)>= price.iter().cloned().zip(sqft_living.iter().cloned()).collect();

我们现在可以使用矢量并在绘图仪中创建散点图。首先,我们需要使用输出图像路径及其大小(本例中宽度:600px,高度:400px)绘制位图(就像在 Photoshop 中创建画布一样)。我们也可以指定颜色作为背景。Rust 提供以下预定义的颜色:白色、黑色、红色、绿色、蓝色、黄色、青色、洋红色、透明。

let root_area = BitMapBackend::new("/Users/chengzhizhao/Downloads/test.png", (600, 400)).into_drawing_area();
root_area.fill(&WHITE).unwrap();

一旦创建了位图。我们可以构建图表上下文,为显示图表提供更多的元数据。set_label_area_size是增加一些空间来显示标签。它是可选的,如果没有设置左或底部位置,它不会显示 x 轴或 y 轴标签。如果你也相应地设置顶部和正确的位置,它看起来会更好,因为它会给用户一种图没有正确显示的印象。

let mut ctx = ChartBuilder::on(&root_area)
        .set_label_area_size(LabelAreaPosition::Left, 40.0)
        .set_label_area_size(LabelAreaPosition::Bottom, 40.0)
        .set_label_area_size(LabelAreaPosition::Right, 40.0)
        .set_label_area_size(LabelAreaPosition::Top, 40.0)
        .caption("House Sales in King County", ("sans-serif", 40.0))
        .build_cartesian_2d(0.0..6000.0, 0.0..10000.0)
        .unwrap();

在上面提到的所有设置之后,我们终于要创建散点图了。是时候把 price_sqft_living 的向量映射到元素上了。该库有许多内置形状。可以参考他们的 base_shape 。在这种情况下,我们将使用大小为四的红色圆作为轮廓。

// Draw Scatter Plot
    ctx.draw_series(
        price_sqft_living.iter().map(|point| Circle::new(*point, 4.0_f64, &BLUE)),
    ).unwrap();

面积图

面积图|作者提供的图像

因为我们已经有了散点图,所有的东西都将为额外的图就位。这里我们需要做的就是在现有的位图上draw_series并更新上下文值。

为了更好地展示 sqft 实时数据的面积图,我们将指定一个从 0 开始的增量整数作为 x 轴,sqft 实时数据作为 y 轴。并且只显示前 10 所房子。

它还将 x 轴的范围和数据类型从 float 更改为 int,我们可以在散点图中指定的图表上下文中执行以下更改:

.build_cartesian_2d(0.0..6000.0, 0..10000)–> .build_cartesian_2d(0..9, 0..10000)

然后我们就可以很容易地画出这个图了

// Draw Area Plot
ctx.draw_series(
        AreaSeries::new((0..).zip(sqft_living[..10].iter().map(|x| *x)), 0 ,&RED.mix(0.2)).border_style(&RED)
    ).unwrap();

条形图

条形图|作者图片

条形图给用户一种图表正在绘制的感觉。特别是我们必须定义Rectangle::new,它定义了矩形的 4 个点。为了简化,我们仍然将增量虚拟值作为 x 轴,将居住平方英尺数作为 y 轴。我们需要将 x 值映射到 x0,将 x+1 映射到 x1,这定义了矩形的宽度,然后将 0 和 y 值作为矩形的高度。最终,绘图仪将使用该映射来构建条形图(x0, 0), (x1, y0)

此外,我们需要更改图表上下文。它将当前范围值转换成分段坐标:.build_cartesian_2d((0..9).into_segmented(), 0..40)

// Draw Bar Plot
ctx.draw_series((0..).zip(sqft_living[..10].iter()).map(|(x, y)| {
    let x0 = SegmentValue::Exact(x);
    let x1 = SegmentValue::Exact(x + 1);
    let mut bar = Rectangle::new([(x0, 0), (x1, *y)], BLUE.filled());
    bar.set_margin(0, 0, 5, 5);
    bar
})).unwrap();

线形图

线图|作者图片

线形图类似于前面所示的图。

// Draw Line Chart
ctx.draw_series(
    LineSeries::new((0..).zip(sqft_living[..10].iter()).map(|(idx, y)| {(idx, *y)}),&BLUE)
).unwrap();

综上所述:

最后的想法

Rust 中的 Plotters 是数据科学在 Rust 上尝试数据可视化的一个极好的开始。虽然 Plotters 还为时尚早,但用户需要做大量繁重的工作来绘制情节。和 ggplot2 或者 Plotly 这样的成熟库相比是不公平的。我希望这篇文章向您展示了数据科学@Rust 的潜力,并期待 Rust 中有更多令人兴奋的数据相关项目。

希望这个故事对你有帮助。本文是我的工程&数据科学故事系列的部分,目前包括以下内容:

Chengzhi Zhao

赵承志

数据工程和数据科学故事

View list47 stories

你也可以 订阅我的新文章 或者成为 推荐媒体会员 也可以完全访问媒体上的故事。

如果有问题/评论,请不要犹豫,写下这个故事的评论或者通过 LinkedinTwitter 直接联系我

如何为 SageMaker 作业创建可重用的 R 容器

原文:https://towardsdatascience.com/how-to-create-reusable-r-containers-for-sagemaker-jobs-a3d481daf5cd

为 R 开发人员在 SageMaker 上创建可重用容器的指南

图片来源于 unsplash.com

SageMaker 非常棒,它给了您充分的灵活性,让您可以使用自己的运行时和语言来使用它的服务。如果没有可用的运行时或语言适合您的代码,您首先需要克服最初的障碍,创建一个兼容的 docker 容器(T2),SageMaker 可以使用。

在这篇博客中,我们深入探讨了如何在 SageMaker 中创建这样的 R-containers ,并试图更深入地理解 SageMaker 的工作方式。这使我们在容器构建阶段做出的一些决策更加清晰。要获得利用这些 R 容器的 ML 管道的端到端示例,请查看这个 GitHub 示例。

码头集装箱简而言之

您可能已经阅读了这篇文章,但是不知道 docker 容器是什么。我不会试图解释 docker 或 containers 是什么,因为已经有大约一百万篇这样的文章写得比我更好。

简而言之,容器是一个标准的软件单元,它将代码及其所有依赖项打包在一个“对象”中,可以跨不同的系统安全可靠地执行。

对于这个博客,你需要广泛地熟悉一些概念,即什么是 docker 文件、图像、容器注册表和容器。如果你对容器很好奇,想了解更多,可以从这里开始了解更多。

为什么是容器+ SageMaker?

SageMaker 是以模块化的方式构建的,允许我们使用自己的容器来提供服务。这给了我们使用我们选择的库、编程语言和/或运行时的灵活性,同时仍然利用使用其服务的全部好处。

用于 SageMaker 处理的 r 容器

为处理作业创建一个 R 容器可能是我们在 SageMaker 上可能需要的所有容器中最简单的。
docker 文件可以如下所示:

当容器被创建并注册到 ECR,Amazon Elastic Container Registry时,我们可以运行一个处理作业。这类似于我们通常运行处理作业的方式,我们只需将参数 image_uri 即新创建的图像的 uri 传递给作业。这种处理作业运行的例子(也作为流水线的一部分)可以在流水线的第 33 行中找到。上面分享的例子中的 R 。当处理作业运行时,SageMaker 使用以下命令运行容器:

docker run [AppSpecification.ImageUri]

因此,将运行入口点命令,并且将运行传递到 ScriptProcessor代码参数中的脚本。在这种情况下,我们的入口点是命令 Rscript ,因此这个容器可以被所有需要执行任意代码的处理作业重用,当然假设必要的包依赖关系对它可用。

进一步的定制是可能的,如果你有兴趣更深入地了解 SageMaker 容器是如何具体处理作业的,请随意阅读相关文档页面。

用于 SageMaker 培训和部署的容器

与上面这个简单明了的例子相比,为训练作业创建一个 R 容器(也可以在部署模型时重用)需要更多的步骤。

模板 Dockerfile 文件可以如下所示:

您会注意到,一旦我们安装了模型/代码所需的必要包,我们还复制了一个 run.sh 和一个 entrypoint。r 文件。让我们看看这些文件是什么,为什么需要它们。

#!/bin/bash
echo "ready to execute"
Rscript /opt/ml/entrypoint.R $1

run.sh 脚本非常简单,它所做的只是运行入口点。R 脚本在$1 下传递命令行参数。我们这样做是因为 SageMaker 使用以下命令运行 docker 容器进行培训和服务:

docker run image train

或者

docker run image serve

这取决于我们称之为培训还是部署方法。基于参数$1,即“train”或“serve ”,我们想区分下一步。这里需要 bash 脚本将这个参数传递给 Rscript 执行,因为没有直接的方法从 R 代码中读取 docker run 参数。如果你知道更好/更简单的方法,请在评论中告诉我!

现在让我们看看入口点。r 脚本:

这现在变得更加 SageMaker 具体的方式,让我们打开它!SageMaker 有一个定义非常好的文件结构,它保存文件并期望在/opt/ml/下找到文件。具体来说,我们在这里使用的是:

/opt/ml/
    - input/config/hyperparameters.json
    - code/
    - model/
        - <model artifacts>
        - code/

hyperparameters.json 文件
当创建一个训练评估器时,我们将希望传入一些自定义代码来定义和训练我们的模型。通过之后,SageMaker 会将这些文件(可能是您需要通过培训的文件的整个目录)压缩到一个名为“source dir . tar . gz”的文件中,并将它上传到 S3 的一个位置。一旦我们开始一个训练作业,SageMaker 将在/opt/ml/input/config/位置创建 hyperparameters.json 文件,该文件包含任何传递的 hyper 参数,但也包含关键字"sage maker _ submit _ directory ",其值为" sourcedir.tar.gz" 文件上载到的 S3 位置。
在训练模式下,我们需要下载并解压缩我们的训练代码。这正是上面 if 语句的第一部分所做的。

代码目录
遵循 SageMaker 如何在内置算法和托管框架容器上下载和解包训练代码的约定,我们正在提取/opt/ml/code/目录中的训练代码。然而,这不是一个要求,而是遵循服务标准的一个好的实践。

模型目录
这是 SageMaker 自动下载模型工件和与推理相关的代码的目录。
上面代码片段中 if 语句的第二部分利用了这一点,来获取 deploy。R 脚本。这里需要注意的是,这个 Dockerfile &代码示例假设我们的推理代码将包含一个部署。R 文件,该文件将为部署而运行。如果您遵循不同的命名习惯,请随意重命名该文件。
在这个代码示例中,在训练过程中,一旦创建了模型,模型的工件就保存在/opt/ml/model 文件夹下。我们还将推理代码保存在同一目录下的子文件夹 code/中。这样,当 SageMaker 压缩文件以创建 model.tar.gz 文件时,这个文件也将包含部署代码所必需的内容。

以上是一个架构/设计决策,用来将推理代码与模型本身捆绑在一起。对于您的用例来说,想要分离这两者并保持推理代码独立于模型工件是完全合理的。这当然是可能的,由你来决定采用哪种方法。

还请注意,模型工件保存在 S3 上的一个单独的model.tar.gz文件中,然而,在部署期间,SageMaker 会自动下载并解压缩这个文件,所以我们不必在部署期间自己手动这么做。

Pro 提示:您可能希望有不同的容器用于训练和部署,在这种情况下,可以简化上述步骤,跳过 run.sh 脚本的使用。

进一步的定制是可能的,如果你有兴趣深入了解 SageMaker 容器如何专门用于训练和推理工作,请随意阅读相关文档页面

建造集装箱

如果你熟悉构建容器,你会意识到下面的过程没有什么本质上的特别。我们所需要做的就是根据提供的 docker 文件构建容器,并向 ECR 注册图像,SageMaker 作业将在运行时提取图像。如果你已经知道如何建立和注册一个图像到 ECR,请随意跳过这篇文章的这个部分。

对于 SageMaker 上 RStudio 的用户或者任何不能或不愿意让 docker 守护进程在他们的开发环境上运行的人,我建议将容器的实际构建外包给另一个 AWS 服务,即 AWS CodeBuild 。幸运的是,我们不需要主动与该服务交互,这要感谢有用的实用程序 SageMaker Docker Build ,它对我们隐藏了所有这些复杂性。
使用如下命令安装该实用程序:

py_install("sagemaker-studio-image-build", pip=TRUE)

我们准备好了。构建容器只需要一个命令:

sm-docker build . --file {Dockerfile-Name} --repository {ECR-Repository-Name:Optional-Tag}

结论

SageMaker 的处理、培训和托管功能非常全面,通过自带容器,我们可以按照自己的方式构建模型和应用程序。

在这篇博客中,我们探索了如何创建我们自己的、可重用的、支持 R 的 docker 容器,我们可以用它来满足我们的处理、培训和部署需求。

本文中使用的完整代码示例可以在这个 Github 资源库中找到。

如果您正在 SageMaker 上为 R 构建自己的容器,请在评论中联系我,或者在 LinkedIn 中与我联系,SageMaker 愿意就此进行讨论!

如何用 Python 创建像 3Blue1Brown 这样流畅的数学动画

原文:https://towardsdatascience.com/how-to-create-slick-math-animations-like-3blue1brown-in-python-457f74701f68

学习将你对数学和编程的热爱结合起来的最佳方式

除特别注明外,所有图片均为作者所有。

你知道创建 3Blue1Brown 的线性代数系列的本质用了多少行代码吗?

这个系列有 16 个视频,频道总共有+100 个视频,这些数字充分说明了数学界对格兰特·桑德森的感激之情。

尽管这个频道看似专注于数学,但它是他为了练习编程技巧而创建的图形库的副产品。他称之为 Manim,,它成为了将一些最复杂的数学和计算机科学主题可视化和动画化的先驱工具。

目前,他关于神经网络、微积分、拓扑学和纯数学的视频被认为是 YouTube 上的瑰宝。

如果你能创造出与他的作品有一点相似的东西,那不是很酷吗?本 Manim 教程结束时,你不仅能够创建自己的精彩动画,还能了解格兰特·桑德森在视频中使用的一些签名转换的秘密。

https://ibexorigin.medium.com/membership

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

https://alphasignal.ai/?referrer=Bex

什么是曼尼姆?

Manim 代表数学动画引擎,由 Grant Sanderson 创建,用于制作高精度的数学动画视频。3B1B 频道和这个 Python 库的主要目标是用视觉直觉来补充传统的基于教科书的数学学习。

目前,Manim 有两个版本:Grant 创建的原始库Manim 社区维护的分叉版本。我们将在本帖中使用社区版本,因为它得到了更好的维护、测试,最重要的是,得到了适当的记录。

有许多安装选项,我认为使用 Docker 镜像是与库交互的最省事的方式。请参考本页中的文档化安装说明,或本页中的其他选项,以便您可以遵循。

或者,你可以留下来享受内容,因为会有一些很棒的动画!

请注意,这篇文章包含几个动画,如 gif 和视频,这可能会降低它们的显示速度。你可以从 my GitHub repo 下载文章的源代码。这篇文章还提到了几个可能会让初学者感到困惑的 Python OOP 概念。如果在任何时候你发现自己在挣扎,看看我的 OOP 系列。

对 Manim 如何工作的更高层次的概述

Manim 是作为 FFmpeg 视频编码引擎和 Python 之间的桥梁而创建的。由于不能将内置的 Python 数据结构传递给 FFmpeg,Manim 实现了几个数学对象表示和动画类。

这些类一般分为三类:SceneMobjectAnimation。为了更清楚地解释这些概念,让我们创建我们的第一个动画:

在安装了 Manim 并将上面的代码保存在类似scenes.py的脚本中之后,运行下面的命令:

manim -pqh scenes.py MyFirstAnimation

您应该得到这样的输出:

恭喜你!你刚刚制作了你的第一部动画!

下面是这个 CLI 命令的分解——将-p添加到manim将使您能够在视频编译后立即播放。和qh结合起来就是高质量渲染。随着渲染时间的增加,有四种分辨率-低(l)、中(m)、高(h)和 4k ( k)。

如果想要 GIF 版本的动画,在-pqh后面加上-i。这里是 manim CLI 命令的完整列表。

分解基本的 Manim API

让我们通过逐行分析代码来理解上面的动画。

在第一行中导入所有 manim 内容后,我们用一个 construct 方法定义一个场景类:

class MyFirstAnimation(Scene):
    def construct(self):
        ...

这是创建单个动画的通用公式——您定义一个从[Scene](https://docs.manim.community/en/stable/reference/manim.scene.scene.Scene.html)类继承并具有construct方法的自定义类。Scene类是 Manim 的更高级的构建块,它将所有相关的动画和对象连接成一个单一的结构。

接下来,我们创建两个属于Mobject类(数学对象)的对象(一个星形和一个圆形)。这个[Mobject](https://docs.manim.community/en/stable/reference_index/mobjects.html)类是许多内置移动对象的基础数据结构,如几何形状、向量、坐标系等。基本上所有不是场景和动画的都是一个Mobject

然后,我们有了[Animation](https://docs.manim.community/en/stable/reference_index/animations.html)类。在上面的例子中,我们使用了其中的 3 个- FadeInTransformFadeOut。manim 中所有内置的Animation类都接受 mobjects 作为参数,并对它们应用各种效果。例如,Transform接受两个移动对象,并播放一个平滑的动画,将第一个对象转换为另一个对象。

每次你创建一个动画,你都必须把它包装在play函数中,这样它们才能在屏幕上呈现。

最后,我们有类似于REDBLUEYELLOWPITAU等的常量。这些是 Manim 的[constants](https://docs.manim.community/en/stable/reference/manim.constants.html)模块的一部分,将常用值编码为变量,并在代码片段的第一行导入:

控制移动对象及其位置

默认情况下,所有添加到屏幕上的移动对象都会显示在ORIGIN中:

>>> ORIGINarray([0., 0., 0.])

Manim 使用 numpy 数组在xyz坐标中表示屏幕。z只要您在 2D 空间中制作动画,就会保持 0。要将对象向xy方向移动一个单位,可以使用常量LEFTRIGHTUPDOWN:

例如,我们将在屏幕上的不同位置绘制四个移动对象,并在原点放置一个点作为参考:

LEFTRIGHT等。变量是 Numpy 数组,它们允许数值运算,允许像上面那样缩放它们。还有其他内置的位置变量,如UL(向上+向左)、DR(向下+向右)等。:

在上面的代码片段中,我们通过传递移动对象的新坐标位置来使用移动对象的shift方法。由于shift只是一个函数,实际的换档并没有动画效果。为了显示没有动画的移动对象,我们使用了add方法。

如果我们想制作移动的动画会怎么样?嗯,你可以像这样在animate函数后链接shift:

事实上,使用animate方法,您可以将几乎任何类型的变化制作成动画。例如,mobjects 有几个以set_*开头的方法可以改变它们的属性。这里有一个例子:

动画功能

让我们更认真一点,学习如何绘制函数并制作动画。从现在开始,我将使用 JupyterLab 和它的%%manim细胞魔术来渲染 manim 输出。语法与 CLI 界面相同。

要像在 Matplotlib 中一样绘制 2D 轴,调用带有所需参数的[Axes](https://docs.manim.community/en/stable/reference/manim.mobject.coordinate_systems.Axes.html)类。

接下来,我们使用[get_graph](https://docs.manim.community/en/stable/reference/manim.mobject.coordinate_systems.CoordinateSystem.html#manim.mobject.coordinate_systems.CoordinateSystem.get_graph)方法,传递我们想要绘制的函数。这个内置方法只接受返回xy之间一对一映射的单变量函数。在上面的例子中,我们画出了 sin(1/x) 的图形。

或者,您可以使用get_graph_label将函数的标签放置在特定位置:

最后,我们正在使用[VGroup](https://docs.manim.community/en/stable/reference/manim.mobject.types.vectorized_mobject.VGroup.html?highlight=vgroup)类创建一组移动对象。它允许在多个移动对象上同时进行动画和变换。

另外,不要忘记画出你创建的每个对象。要么用Create / Write之类的动画功能,要么用self.add

更多很酷的例子

你不会以为我不放几个 3B1B 的招牌动画就走了吧?

我是从他的《线性代数的本质》系列中了解到 3B1B 的,看到一个空间的线性变换完全让我意乱情迷。疯狂的是,用 Manim 制作动画非常简单:

类似地,看到用 3D 绘制的函数令人大开眼界,因为我们都习惯于在 XY 平面上绘制函数。当你看到下面的函数时,你会意识到数学是多么美好:

嘿,那些非线性变换怎么样?

还有比这更好的吗?当然可以!

虽然已经很酷了,但是你今天学到的只是 manim 所能做的很小一部分。以上动画只是格兰特·桑德森在他简单的开场场景中使用的。

当您想要超越内置的移动对象和动画类时,该库有一个陡峭的学习曲线。实现自定义类可能会非常冗长,对于较长的视频,通常需要数千行代码。

然而,如果你真的热爱数学,并以新颖和创造性的方式向他人解释它,这不应该阻止你。

离别赠言

我很抱歉把这篇文章变成了一篇“如何做”的帖子。这只是我根深蒂固的过度解释事情的倾向。

然而,我觉得适当的解释是必要的,因为互联网上充满了过时的教程和视频。除此之外,当您不小心在一个项目中使用了不同版本的 manim 时,就会产生混淆。

如果你想成为一名铁杆 manim 动画师,我强烈建议你仔细阅读社区版的文档的每一页。我也建议你去看看像这种使用 Manim 的频道,并阅读他们的源代码。

https://ibexorigin.medium.com/membership https://ibexorigin.medium.com/subscribe

我的更多故事:

https://ibexorigin.medium.com/yes-these-unbelievable-masterpieces-are-created-with-matplotlib-b62e0ff2d1a8 https://ibexorigin.medium.com/how-to-use-matplotlib-annotations-like-you-know-what-you-are-doing-da61e397cce3

如何用 Python 在 d3js 中创建讲故事移动气泡图

原文:https://towardsdatascience.com/how-to-create-storytelling-moving-bubbles-charts-in-d3js-with-python-b31cec7b8226

移动气泡图是值得一看的令人兴奋的图表之一。这是从概念上更好地理解单个项目如何跨状态分布和跨时间移动的好方法。了解如何使用 Python 和您自己的数据集创建它们。

移动气泡图。(图片由作者提供)

移动气泡图是一种看起来令人兴奋的图表。这是一个很好的方式来讲故事,并从概念上更好地理解单个项目是如何跨州分布和跨时间移动的。尽管它们的外观很吸引人,但这样的图表并不常见,因为创建一个单独的图表需要付出巨大的努力。这里出现了 D3Blocks 库,因为移动气泡图是 D3Blocks 的一部分。它是开源的,不需要安装除 Python 之外的任何东西来创建一个移动气泡图表。输出是交互式的和独立的,除了浏览器,你不需要任何其他技术。因此,在网站上分享、发布和整合图表变得非常容易。 在这篇博客中,我将用一个实际操作的例子来介绍移动气泡图。

如果你觉得这篇文章很有帮助,可以使用我的 推荐链接 继续无限制学习,并注册成为中级会员。另外, 关注我 关注我的最新内容!

移动气泡 图是 D3Blocks 的一部分。

D3 blocks是一个包含各种图表的库,其可视化部分基于(d3) javascript 构建,但可使用 Python 进行配置。以这种方式, D3Blocks 库结合了 d3 javascript 的优点,如速度、可伸缩性、灵活性和无限的创造力,以及 Python 的快速和简单使用。关于 D3Blocks 库的更多信息可以在这个博客【1】中找到。

**移动气泡图是 D3Blocks 的一部分,由两部分组成;Python 部分和 d3js 部分。Python 部分包含数据管理、预处理、标准化、颜色处理、标签等功能,而不用担心任何 d3 javascript 模块。可以加载该模块,指定参数,然后根据您的输入数据集创建移动气泡图表。 在幕后,Python 模块会整合 d3js 部分的信息,比如数据集,颜色,调整位置,为状态数设置标签,包含用户自定义的参数。最后,所有的文件被连接并合并成一个单一的工作 HTML 文件。这样,移动气泡图表将根据您的特定数据集和参数自动调整。

输入数据集、参数和输出。

**移动气泡图在视觉上令人满意地显示了力导向和碰撞节点。有助于理解是否何时出现样本簇在特定的时间点和状态。在我们浏览移动泡泡的功能之前,我们首先需要安装 D3Blocks 库:

*pip install d3blocks*

输入数据框。

在制作图表之前,我们需要构建输入数据集,以便 MovingBubbles 函数可以使用它。输入数据是一个包含以下三列的数据帧:

  • 日期时间 :描述事件发生的日期时间。
  • 状态 :描述 sample_id 在日期的具体状态。**
  • sample _ id:样本可以是在不同时间点具有不同状态的个体/实体。它可以 而不是 在同一时间点有两个或多个状态。

输入数据帧的示例如下所示。在本例中,有 10.000 行,包括 3 列和索引列。唯一的sample _ id代表具有某种生活方式的个人(美国)。例如,第一行(索引 0)包含标识符为 61 的个体,并且在时间点 00:10:36 状态为正在进食。* 不多一会儿这个个体就要进入 睡眠状态 (时间点 00:11:30)。 第二天我们再次看到这个特定的个体(以 id 61 )在时间点 23:57:54 ,以状态 【家】 。总结一下,id 为61的个体确实经历了三种状态: 吃饭>睡觉>回家。 注意,个体将停留在特定状态,直到下一个状态被调用。*

*print(df)#                ** datetime sample_id     state**
**# 0    2000-01-01 00:10:36        61    Eating** # 1    2000-01-01 00:10:51        83      Sick
**# 2    2000-01-01 00:11:30        61  Sleeping** # 3    2000-01-01 00:11:37        66  Sleeping
# 4    2000-01-01 00:11:57        94  Sleeping
#                  ...       ...       ...
# 9995 2000-01-02 23:57:12         6      Home
# 9996 2000-01-02 23:57:23        48      Sick
**# 9997 2000-01-02 23:57:54        61      Home** # 9998 2000-01-02 23:58:22         4  Sleeping
# 9999 2000-01-02 23:59:34        88  Sleeping# [10000 rows x 3 columns]*

输入参数。

移动气泡块包含各种输入参数,在代码段 1* 中有描述。这些状态将自动定位在一个圆圈中。*

代码部分 1。输入参数(图片由作者提供)

输出文件。

输出是存储在指定文件路径的单个 HTML 文件。HTML 包含一个可以共享和发布的全功能图表。

数据如何转化为动作的实践示例。

让我们从一个小例子开始,演示输入数据帧是如何转换成运动的。我们将创建三个独特的样本,它们将跨越六个状态:家>学校>工作>吃>咖啡>睡觉,每个样本间隔 5 分钟。为了清楚起见,让我们将三个样本或个体的运动存储在三个独立的数据帧中; df1df2,df3。 最终数据帧 df 是三个数据帧的组合集。通过打印数据帧 df ,如代码第 2 节所示,可以看到日期时间有 5 分钟的间隔,每个样本在六个状态之间移动。

代码部分 2。演示数据如何转化为运动。

有三列的数据框 df 是你创建移动气泡图所需要的。可以指定其他输入参数,例如标准化。在本例中,使用了 samplewise 标准化,并且指定了将在左侧面板上弹出的 time_notes (可选)。其他参数设置为默认值,以尽可能保持整洁。

代码第三部分。创建移动气泡图的示例。

运行这几行代码后,下面的图表就创建好了。每个点代表一个个体,颜色代表状态,当有人改变状态时,点会相应移动。一天中的时间显示在左上面板中,而时间注释显示在左中面板中。

演示 3 个人穿越 6 个预先定义的状态的移动。速度设置为慢、中和快。就等着吧。(图片由作者提供)

不同配置和更多样本的示例。

在本例中,我们将生成一个数据集,其中包含样本在不同州之间的随机移动。这个想法和前面的例子是一样的,但是现在我们将使用d3.import_example(graph='random_time')。输入数据集打印在代码段 4* 中,应包含三列。设置以下参数:speed设置为自定义center设置为表示无状态显示在图表中间。没有应用标准化(见下一节关于标准化的更多细节)。*

代码第 4 部分。随机状态作为 movingbubbles 函数输入的示例。

展示跨越 6 个州的数百个样本的移动。速度设置为慢、中和快。就等着吧。(图片由作者提供)

我们现在也可以很容易地设置center=’work’,这将自动改变状态的顺序和位置。

以一个中心州为例,演示数百个样本在 6 个州之间的移动。速度在慢、中和快之间变化。就等着吧。(图片由作者提供)

样本时间标准化。

标准化功能允许以 方式方式对时间点进行转换。这意味着每个样品 id 的时间是标准化的,并且独立于其他样品 id。或者换句话说,每个样本的起始点是对齐的,因此起始日期时间将是相同的。为了演示 samplewise 标准化的效果,我将加载在代码部分 1* 中创建的小数据帧。如果我们仔细观察数据,我们可以看到 sample_id 1sample_id 2 具有相同的开始日期时间,而 sample_id 3 几乎在 1 年后开始:*

  • sample _ id 的日期时间# 1:2000–01–01**00:00:00
  • sample _ id# 2:日期时间 2000–01–01**00:00:00
  • Datetimeofsample _ id# 3:2000–12–12**00:00:00

当我们现在应用样本方式标准化时,在数据帧中添加了两个新列。列 datetime_norm(代码段 5) 包含对齐的日期时间点,其中 sample_id 3 中的一年差异是对齐的。delta 列描述了在原始数据中看到的时差。

没有标准化。

如果我们不应用标准化,则时间按原样建模。一年之差(确切地说是 345 天,第 67 行代码第 5 段)可以从时差( delta )中看出。现在您可能需要等待很长时间,然后 sample_id 3 才会移动。但是可以使用speed参数改变时间的速度(参见代码第 1 节)。

代码第 5 部分:标准化的差异。

最后的话。

我演示了如何使用 Python 创建自己的移动气泡图表。图表的开发方式可以处理各种状态、时间范围和颜色。移动气泡图表是 D3Blocks 中的一个模块,d3js 的使用显示了它的力量和优势,例如速度、灵活性和将你所有的创造力添加到图表中的可能性。随意摆弄库!**

注意安全。保持冷静。

干杯,E.

如果您觉得这篇文章很有帮助,请使用我的 推荐链接 继续无限制学习,并注册成为中级会员。另外, 关注我 关注我的最新内容!

软件

我们连线吧!

参考

  1. **Taskesen,E,D3 blocks:Python 库,用于创建交互式和独立的 D3js 图表。 中等,2022 年 9 月

如何用雪花的 GENERATOR()函数创建合成行

原文:https://towardsdatascience.com/how-to-create-synthetic-rows-with-snowflakes-generator-function-8f947d40d9b3

当 SQL 变得比你想象的更好时…

图片由弗朗斯·范·海登像素上拍摄

建议的点播课程:

努力工作 推进事业*数据行业 ?如果是这样的话,我强烈建议您查看以下课程:*

雪花的生成器功能是什么?

你有过无中生有创造数据的需求吗?

如果您看过,您可能已经转到了关于如何用 Python、JAVA 和其他编程语言创建假数据的教程。

然而,事实证明,SQL 不仅是查询(DQL)和操作数据(DML)的伟大语言,还可以用来创建 合成行

在雪花中,这可以通过利用GENERATOR()函数来实现,如文档所述,该函数的语法为:

***GENERATOR(** ROWCOUNT => *<count>* [ , TIMELIMIT => *<sec>* ] **)**

**GENERATOR(** [ TIMELIMIT => *<sec>* ] **)***

这意味着您可以通过以下方式生成数据集:

  • 指定输出表应该包括的确切的ROWCOUNT
  • 以秒为单位指定一个TIMELIMIT(生成周期),在此之后行创建将停止。

请记住,第二个选项既强大又危险,因为 SQL 查询甚至可以在几秒钟内生成大量合成行。

下面的例子可以更好地解释这一点:

  • 第一个SELECT语句使用GENERATOR(ROWCOUNT(=>10))语法输出一个数据集,其中正好有 10 ( 相同的)行显示字符串Let's learn about Snowflake GENERATOR()。使用ROWCOUNT,使您的语句结果具有确定性,因为它涉及到输出中的行数:

  • 第二个SELECT语句使用了GENERATOR(TIMELIMIT(=>3))语法。这意味着,在执行时,查询将在 3 秒钟内持续生成行。这似乎不是很长的时间,但仍然足以让雪花产生大约 310 亿行:

请注意GENERATOR()函数本身是如何包装在TABLE()子句中的。这样做的原因是,GENERATOR()实际上用于创建所谓的虚拟表 " "具有 0 列,但可能有许多行 "。

反过来,每当查询完全由数据生成函数组成时,语法中就需要虚拟表。

什么时候应该使用发电机?

每当您没有或不希望使用物理数据来执行特定任务时,您应该考虑使用GENERATOR()功能,例如:

  • 构建数据管道的本地或分级版本
  • 生成由与您部署的输出的形状和格式相似的列组成的非常大的数据集,以测试生产数据管道的未来性能**
  • 创建虚拟数据对象这在写教程的时候也特别有用。**
  • 用与原始数据保持相同结构的数据替换个人敏感信息(PII)
  • ****创建日期模板表用于生产,同时在给定的时间范围内转换数据。

生成器可以创建什么类型的数据?

通过GENERATOR功能可以创建的不同合成数据的类型是无穷无尽的——您的创造力在这里是极限——而且当与雪花提供的其他 数据生成功能 结合使用时,该功能会大放异彩。

然而,在下面的三个常见用例中,GENERATOR函数变得非常方便。

#1 生成顺序 id

有时,您可能需要生成合成的序列(唯一的)id。这可能只是为了模拟包含物理 id 的生产表,或者为了能够对不同的行进行计数。

以下是用GENERATOR创建连续 id 的 4 种方法:

输出:

这里有两个亮点:

  • ROW_NUMBER() OVER()这样的窗口函数在与GENERATOR结合使用时可以用来产生连续的 id。我发现让合成行更动态是一个聪明的把戏。
  • 使用数据生成功能T5 生成唯一的 UUID。在很多情况下,这个功能在生产中有直接的应用,所以值得你在这里查看一下

#2 生成字符串属性

在某些情况下,您可能希望通过生成包含随机字符串属性的行来复制表的结构,比如PLATFORMPRODUCTCUSTOMER_NAME等等。

在雪花中,这可以通过结合使用GENERATORUNIFORMRANDOM功能来实现。例如:

输出:

如你所见,RANDOM函数用于随机选择一个通过UNIFORM函数在指定间隔内生成的整数。然后,注意整数是如何:

  • 传递给分配字符串属性的CASE WHEN语句;
  • 传递给一个ARRAY_CONSTRUCT作为索引,在组中选择一个随机的字符串。这个解决方案是一行程序,我觉得它非常优雅。

还有,你能说出哪个客户不应该在那里吗? 😄

#3 生成日期和时间戳

GENERATOR功能最常见的用例之一是创建合成日期时间戳

例如,下面的查询返回 2022 年每个月的STARTEND日期😗***

输出:

  • 请注意ROW_NUMBER()是如何再次被用来产生从 1 到 12 的连续数字的,这些数字已经通过DATEADD函数作为月份添加到开始日期** ( 2021-12-01)中。**
  • 还要注意如何利用LAST_DAY函数来获取当月的最后一天。

要随机生成时间戳,您可以再次利用数据生成函数,并将它们作为DATEADD的参数传递,如下所示:

输出:

最后一个例子:生成一个日期模板表

一个日期模板表(也称为日期脚手架)是一个包括一组日期以及直接导出的参数的表,从过去的某一天开始,一直到未来。

这些类型的表通常由数据团队创建,用作辅助数据集,而执行与事实表的连接:

  • 验证给定时间范围内记录的存在与否;
  • 当需要与前期进行比较时,计算 KPIs
  • 对数据集的季节性进行建模。

如果您想知道如何在GENERATOR函数的帮助下创建它们,您可以在下面找到一个为 2022 年创建此类辅助日期模板表的脚本:

输出:

结论

当第一次介绍雪花的GENERATOR功能时,我被它的多功能性惊呆了,这提醒我,即使在“大数据时代,SQL 仍然可以用来解决大量的数据任务。

事实上,有很多实际的用例,其中GENERATOR可以方便地大规模生成合成行,而无需掌握任何其他编程语言。

在本教程中,您学习了函数语法,并探索了一些实际应用。希望你和我一样对GENERATOR功能强大印象深刻。

来源

如何使用 Apache ECharts 和 Python 创建网络友好的图表

原文:https://towardsdatascience.com/how-to-create-web-friendly-charts-with-apache-echarts-and-python-402fa7f79791

教程-PYTHON-pye charts

使用 PYECHARTS 通过 Python 和 JavaScript 创建 Apache ECharts 的分步教程

戴维·克洛德在 Unsplash 上的照片

介绍

大家好,我是 Gregor,一名顾问和技术书呆子,对数据可视化和数据科学非常感兴趣。我一直在寻找新的更快的方法来显示隐藏在数据中的信息。我经常用 Python(熊猫)或者 R (Tidyverse) 处理数据。

通常,这种练习的结果是将图形保存为图像,最终以 PowerPoint 文档的形式呈现给客户。由于这些是静态图像,附加信息以文本形式作为 PowerPoint 文档的一部分提供。

最近我发现了 Apache ECharts,这是一个使用 JavaScript 在 web 上可视化数据的开源工具。使用 Apache ECharts 而不是 Python 的 matplotlib 会给您带来以下好处:

  1. 内置的交互和自动生成的图表描述
  2. 网络友好,即在桌面和移动设备上工作
  3. 开箱即用的优雅

Apache ECharts 条形图示例;作者视频

由于 Apache ECharts 需要我编写 JavaScript,所以我研究了可用的 Python APIs。pyecharts 是一个 Python API,使用 Python 创建必要的 HTML 和 JavaScript 代码。

本文将向您介绍 Apache ECharts 和 pyecharts,这是一个用于创建 Apache ECharts 的 Python 库。我还将向您展示如何设置您的设置,并通过两个示例向您展示。

Apache Echarts & PYECHARTS

阿帕奇·埃查尔兹

Apache EChartsTM 是一个开源的 JavaScript 可视化工具,可以在 PC 和移动设备上流畅地运行。它兼容大多数现代网络浏览器,如 IE9/10/11、Chrome、Firefox、Safari 等。

Apache EChart 特性— 链接

换句话说,您可以直接在 HTML 页面上使用 JavaScript 对数据可视化进行编程。Apache ECharts 提供了必要的库,因此任何访问者的网站浏览器都可以呈现可视化效果。结果是一个动态和交互式的图形(参见上面的视频)。

Apache ECharts 提供了常用的图表类型作为数据可视化库,包括折线图、条形图、地图和树形图。

Apache EChart 图表类型— 链接

肾盂造影图

如果您习惯于用 R、Python 或 Julia 以编程方式创建可视化,那么用 JavaScript 编程可能会让您感到害怕。 Pyecharts 是一个 Python 库,允许您为数据可视化创建与 Apache EChart 兼容的 JavaScript 文件。这让你不用学习 JavaScript,不用呆在你的编程环境里。在 pyecharts 旁边,有可用于 RJulia 的包装器。

设置

在我们开始之前,您需要使用 pip 安装 pyecharts。

pip install pyecharts

对于本教程,我还使用了漂亮的 Gapminder 数据集。Gapminder 的数据是在知识共享署名 3.0 未授权许可下发布的。我很乐意参考这些文章来了解更多信息: 7 个不到 5 分钟的数据辩论 Python 函数如何为您的数据可视化使用调色板

辅导的

接下来,我们需要导入必要的库。

在下面的部分中,我用 pyechart 创建了两个不同的图:条形图和箱线图。

条形图

对于柱状图,我使用熊猫按洲对 Gapminder 数据进行分组。如果你想知道我是如何构建我的代码的,它被称为方法链或管道(在 R 社区中)。我在我的另一篇文章中解释了基础知识。

最后,让我们使用创建的数据集创建一个基本的条形图。我们从调用 Bar 函数开始。我将一些选项传递给了 Bar 函数,比如宽度和高度。add_xaxis 和 add_yaxis 接收 x 轴和 y 轴所需的数据列。在本例中,我在 x 轴上传递洲信息,在 y 轴上传递平均人口。Set_global_options 设置此图表的标题和副标题。set_series_opts 允许添加附加信息。在这种情况下,我为最小和最大平均人口添加标记。最后,render()优雅地呈现必要的 JavaScript 和相应的 HTML 文件。如果您使用的是 Jupyter 笔记本或实验室,请使用函数 render_notebook()。这将直接在您的笔记本中渲染情节。

各大洲平均人口;作者图片

请注意,不可能将熊猫系列直接传递给 pyecharts。相反,您需要将系列转换成列表。这对我有用。如果你知道如何不同地做它,请联系我。

箱线图

对于箱线图,我想比较 1952 年和 2007 年各大洲的人口。首先,我创建了一个包含所有五大洲的列表。这将作为 x 轴,并创建包含 1952 年和 2007 年人口的列表。

创建所有列表后,我使用 Boxplot()函数初始化绘图。使用 add_xaxis,我传递大陆列表。接下来,我对每个人口列表使用 add_yaxis 两次。

按洲和年份分列的人口分布;作者图片

结论

本文将向您介绍 Apache ECharts 和 pyecharts,这是一个用于创建 Apache ECharts 的 Python 库。我还向您展示了如何设置您的系统,并通过两个例子向您展示了这一点。请注意,我只能触及表面。Apache ECharts 和 pyecharts 还有更多的可能性。但是这篇文章可以让你开始。

Apache ECharts 是一个强大的数据可视化库。它的目标是在网络上创建和发布交互式图表。pyecharts 帮助 Python 开发人员在他们最喜欢的编程语言中创建 echarts 图,这也提高了开发速度。然而,我发现 pyecharts 并不像我希望的那样完美,尤其是与 ggplot2Altair 相比。使用 pyecharts,您需要处理列表而不是熊猫系列。它还要求您对数据集进行切片,以便为每个图表创建多个系列。最重要的是,我发现文档有点过时,这阻碍了我进行更多的测试。你怎么想呢?

如果你想阅读更多关于我的旅程,请考虑关注我,或者如果你不是一个媒体成员,请考虑加入这里。非常感谢。

谢谢你,
格雷果

https://gscheithauer.medium.com/membership

如何只用 Numpy 创建自己的深度学习框架

原文:https://towardsdatascience.com/how-to-create-your-own-deep-learning-framework-using-only-numpy-dfc26b9659ef

本文将向您展示创建基本深度学习框架所需的挑战、组件和步骤

弗拉多·帕诺维奇Unsplash 上拍摄的照片

让我们首先定义我们想要创建什么,并找出我们需要什么组件:我们需要一个支持自动微分的框架来计算几个操作的梯度,一个标准化的方法来构建神经网络层,使用前面提到的操作和模块化方法将它们组合在一个更大的神经网络模型中,以及几个用于训练神经网络的工具,如优化器、激活函数、数据集

我们已经确定了以下组件:

  • 亲笔签名的系统
  • 神经网络层
  • 神经网络模型
  • 优化师
  • 激活功能
  • 数据集

接下来,我们将逐一介绍这些组件,看看它们的目的是什么,以及我们如何实现它们。作为例子和参考,我将使用 gradflow ,这是一个个人开源教育签名系统,具有深度神经网络支持,遵循 PyTorch API

自动签名系统

这是最重要的组件,代表了所有深度学习框架的基础。它将允许我们跟踪将要应用于输入张量的操作,并使用损失函数相对于每个参数的梯度来更新我们的模型的权重。一个条件是这些运算必须是可微的。

我们自动签名系统的基础是变量,通过为我们需要的操作实现 dunder 方法,我们将能够跟踪每个实例的 以及如何计算它们的梯度。为了帮助一些操作,我们将使用一个 numpy 数组来保存实际数据。

变量的另一个重要部分是向后方法,这将计算当前实例相对于计算图中每个祖先的梯度。在具体步骤中,我们将使用来自 origin 操作的父引用和嵌入的渐变函数来更新一个 grad 成员字段。

以下代码片段包含主变量类初始化函数、 add 操作的 dunder 方法以及之前的 backward 方法:

_back_grad_fn,中需要注意两件事,首先我们需要将梯度添加到现有值中,因为我们需要累积它们,以防在计算图中有多条路径到达该变量,其次,我们还需要利用子当前梯度,如果您想要关于自动微分和矩阵演算的更多细节,我强烈推荐这篇文章

神经网络模块

对于实际的神经网络模块,我们希望灵活地实现新的层和模块,并重用现有的层和模块。

遵循 PyTorch API,我们将创建一个基类模块,它需要实现 initforward 方法。除了这两个,我们还需要几个基于实用程序的方法来访问参数和子模块。

基础模块

线性图层

使用上一节的抽象模块我们将实现一个简单的线性层。我们需要执行的数学运算非常简单:

线性层变换

因为我们将使用之前实现的变量自动计算操作的实际结果和梯度,所以实现很简单:

线性的

激活功能

现实世界中的大多数数据在自变量和因变量之间具有非线性关系,我们也希望我们的模型能够学习这种关系。如果我们不在线性层上添加非线性激活函数,无论我们添加多少线性层,最终我们都可以只用一层(一个权重矩阵)来表示它们。

最常用的激活功能是 Relu:

热卢

当我们实现 relu 函数时,我们还需要指定反向传播函数:

优化器

在我们通过我们的模型执行正向传递并通过我们的层反向传播梯度之后,我们需要实际更新参数,以便使损失函数更小,并且这里介入优化器。

最简单的优化器之一是 SGD ( 随机梯度下降),,在我们的实现中,我们将保持一切都非常简单。仅使用梯度和学习率,我们将剪切变化值δ并更新权重:

【计算机】优化程序

数据集

拼图的最后一块是一个组件,它将允许我们组织数据集,并轻松地将其集成到训练过程中。为此,我们创建了一个数据集类,它实现了迭代器的 dunder 方法,并将特性和标签转换为变量类型:

资料组

培养

最后,我们将把所有东西放在一起,并使用人工生成的数据集训练一个简单的线性模型,该数据集使用 sklearn.datasets :

培养

结论

所展示的实现决不是产品级的,而且非常有限,但是我认为它们是一个很好的学习工具,可以更好地理解在其他流行框架下发生的一些操作。

虽然基于标量的运算的基本演算非常简单,但当我们添加多维度并切换到张量时,情况就变得有点复杂,我们必须格外注意。

感谢您的阅读,我希望您会发现这篇文章很有帮助,如果您想了解最新的编程和机器学习新闻以及一些优质的模因:),您可以在 Twitter 上关注我这里或者在 LinkedIn 上联系这里

参考

如何自定义图形中的注释

原文:https://towardsdatascience.com/how-to-customize-annotations-in-graphics-3d2e37a4b466

了解如何像专业人士一样使用 Python 中的 Matplotlib 进行注释。

讲故事:副标题和注释帮助我们快速阅读和理解。图片由作者提供。

介绍

如果你读过 Cole Nussbaumer Knaflic 的《用数据讲故事》,你会知道你在图形中添加的注释可以帮助你向你的观众讲述这个故事。

图 1:代替这个,做这个…图片作者。

看着上面的图片 1,你可能会注意到两种可视化效果之间的巨大差异。第一个滥用了颜色,没有任何轴标签也没有标题,而右边的图形更统一,只有一种颜色,因为我们处理的是单个变量,它有轴标签,标题和注释,帮助我们快速阅读情节。

快速浏览图形图层

可视化可以按照图形 的 语法来构建(参见 Dipanjan (DJ) Sarkar 的链接帖子),这是一组帮助你为图形的每一层做出决定的规则。简而言之,你将决定:

你在策划什么数据

了解你的数据。你想讲什么故事?数据的类型是什么(定量还是分类)?在进入下一步之前,必须回答这些问题。

图 2:定量还是分类。图片由作者提供。

运用什么美学?

x 是什么?y 轴是什么?用什么颜色?这些都是这个话题要回答的问题。通常我们用 X 轴表示解释变量,Y 轴表示响应或目标。因此,如果你用售出的数量来解释销售,Y 轴表示销售,x 轴表示数量更有意义。

哪个秤?

线性刻度是最常见的。你画出它是什么。

当有两个变量保持某种关系时,对数标度或归一化数据会更好,但它们的标度相差太大,无法比较,因为一条曲线会使另一条曲线变平。你应该画出更有意义的东西。

图 3:线性与对数标度。图片由作者提供。

几何图形

如果显示时间序列,使用线。比较两个数值变量之间的关系,考虑一个箱线图。是分类数据之间的比较吗,一个柱状图怎么样?单变量,你有 ecdf,直方图

图形的类型。图片由作者提供。

了解你的数据。据此决定。

统计数据

有时需要加上计数、均值、置信区间。Seaborn 提供了很多很酷的东西,比如每个条形顶部的置信区间。

具有置信区间的 Seaborn 柱状图。图片由作者提供。

坐标系统

笛卡尔坐标使用得更频繁,但有时极坐标也很有用。

极坐标的一个例子。图片由作者提供。

ggplot2这样的库就是建立在这个概念上的,你可以看到正在使用的语法。其他像seaborn这样的人更倾向于统计学。plotly喜欢互动。对我来说,定制就是一切。

释文

但是回到我们在这里的目的,使用这些层,你会更容易思考,勾画和绘制你的视觉效果。你会更加小心地使用颜色、标签、图例,并会创造出更好的图形。

然后,注释将是一个讲得好的故事的最后一笔。

matplotlib 中 annotate 的基本语法如下。

plt.annotate("text", xy=(x_pos, y_pos), color='red', size=12)

让我们看一个例子。

# Plot
data = [12,13, 15, 21, 22, 29, 28, 29, 35, 29, 26, 32]
g = sns.ecdfplot(x=data)
g.set_title('ECDF Plot with basic annotation', size=17)# Basic annotation
plt.annotate("50% of our distribution \nis below 27 = = = = =>", xy=(16, 0.5));

基本注解。图片由作者提供。

你也可以使用plt.text,这是非常基本的。您将在图形中的某个位置添加文本。我们所做的就是提供 x 和 y 位置以及字符串。

plt.text(x, y, s, color, size)
---
# Example
data = [12,13, 15, 21, 22, 29, 28, 29, 35, 29, 26, 32]
g = sns.histplot(x=data)# Text annotation
plt.text(x=15, y=4, s='Random text', color='green')

plt.text()。作者图片

您也可以使用下面的代码在文本周围创建一个框。

plt.text(16, 4, "Random Text", ha="center", va="center", rotation=0, size=15, bbox=dict(boxstyle="round4, pad=0.4", fc="lightgray", ec="r", lw=0));

文本周围的框。图片由作者提供。

箭头和副标题

但是我们可以用注释做更多的事情。我们也可以添加里面有文字的箭头。

# Plot
data = [12,13, 15, 21, 22, 29, 28, 29, 35, 29, 26, 32]
g = sns.histplot(x=data)# Arrow with comments inside
plt.text(19, 4, "Look at this bin!", ha="center", va="center", rotation=0, size=15, **bbox=dict(boxstyle="rarrow, pad=0.4", fc="lightgray", ec="r", lw=0)**);

带注释的箭头。图片由作者提供。

或者最后,我们可以创建一个带有注释和解释的精美图形,帮助我们用数据讲述一个精彩的故事。要添加一个副标题,您实际上将使用plt.title()作为解释文本,使用plt.suptitle()作为您的主标题。请参见下面的代码。

# Setup figure size
plt.figure(figsize=(18,8))**# Data**
months = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
data1 = [12,13, 15, 21, 22, 29, 28, 29, 35, 22, 24, 32]**# Plot**
g = sns.barplot(x=months, y=data1, color='royalblue')**#Title**
plt.suptitle('Sales of Phones in 2021', size=18)
g.set_title(*'''The sales of smartphones continue to grow within our company. Last year we saw a promissing first quarter, followed by a spike in sales for the summer months.
The release of a new model was well accepted by the market, resulting in a sales record for a September month.'''*, color='gray')
g.set(xlabel='Month', ylabel='Sales in $M' )**# Add annotation for the arrow type |--|**
plt.annotate( " ", xy=(4.5, 30), 
            horizontalalignment='center', verticalalignment='center',
            xytext=(7.5,30),
            arrowprops=dict(arrowstyle='|-|', color='gray') )**# Text and Arrow pointing to the top bar in September**
plt.annotate( "Release of the new model", xy=(8.5, 34.8), xytext=(9, 35), arrowprops=dict(arrowstyle="->",color='royalblue'), color='gray', size=12 )**# Text "Spike for Summer Months"**
plt.text(6, 32, "Spike in sales : Summer Months", ha="center", va="center", rotation=0, size=12, bbox=dict(boxstyle="roundtooth, pad=0.5", fc="orange", ec="r", lw=0));plt.show()

讲故事:副标题和注释帮助我们快速阅读和理解。图片由作者提供。

在你走之前

学习新的数据可视化技术总是好的,因为它们将帮助您发展讲故事的技能。

在这篇文章中,我给了你一些新的(或者对某些人来说不算新的)工具,我相信这些工具会增强你的视觉效果,并让你在数据科学家的工作中取得进步。

如果你想加入 Medium,你可以使用这个推荐链接,不要忘记关注我的博客了解更多。

https://gustavorsantos.medium.com/

查看我的 GitHub 中的完整代码

参考

在此处找到文档。

注意:对于一些可视化,我使用了 Python 中 Seaborn 库中的玩具数据集提示

https://matplotlib.org/3.5.1/api/_as_gen/matplotlib.pyplot.text.html https://matplotlib.org/3.5.0/tutorials/text/annotations.html

如何在不训练神经网络的情况下去除图像模糊

原文:https://towardsdatascience.com/how-to-de-blur-images-without-training-neural-networks-72f8597c0014

背景

我发现在点击图片时很难保持手的稳定。很自然,他们中的许多人都有模糊不清的感觉。如果你和这个问题有关,那你就来对地方了。虽然我不能教你摄影,但我可以用几行 python 代码向你展示一种消除图像模糊的技术。鉴于围绕深度学习的热潮,一个解决方案是训练一个自动编码器。但是,训练它们在计算上很昂贵,有时,经典方法工作得很好。因此,我们将使用傅立叶变换。

傅立叶变换在信号和图像处理中有着广泛的应用。它的性能可能不如最先进的深度学习方法令人印象深刻,但它的速度要快得多。如果你在智能手机上点击一张图片后注意到一个处理提示,那么傅立叶变换可能正在后台运行以提高图像质量。它还可以帮助更好地训练现代深度学习架构。任何模型都取决于它所依赖的数据。使用傅立叶变换,您可以应用大量的图像处理技术(降噪、边缘检测等)来提高训练数据的质量。

我不会深究傅立叶变换的数学细节。如果你对此感兴趣,你会在 youtube 上找到很多视频。我特别喜欢的一个是 3Blue1Brown 的主持人格兰特·桑德森。在这篇文章中,我们将重点讨论如何使用傅立叶变换去模糊图像。

汤姆·史密斯Unsplash 上拍照

数学上模糊是什么?

既然我们已经同意进入傅立叶变换的领域,我们首先需要一个图像模糊的数学定义。模糊使图像变得平滑。也就是说,图像丢失了边缘细节。我们可以通过用高斯核卷积图像来实现这一点。下面是一个(3,3)高斯核。

作者图片

请注意,当我们远离中心时,内核权重会减少。因此,当与这样的矩阵卷积时,图像位置将丢失来自周围像素的信息,导致平滑(模糊)。除了高斯,还有其他类型的平滑内核。这里的要点是,模糊图像(B)是对原始图像(I)进行卷积(H)的结果。

模糊图像方程

如果我们能以某种方式逆转这一操作,我们将能够生成原始图像(I)。这个过程称为去卷积,在频域(傅立叶变换)中更容易完成。

图像的傅立叶变换

傅立叶变换( FT )的思想是任何函数都可以近似为无限正弦曲线的加权和。一维正弦波需要 3 个参数来定义。

正弦方程

  1. 振幅(A)决定了波的范围。它从-A,A 开始延伸
  2. 频率(2π/λ)决定两个连续峰值之间的距离
  3. 相位(φ)决定了波的水平移动

因此,傅立叶变换将函数从空间域转移到频率域。

def plot_sine_1D(amp,wavelength,phase):
    x = np.arange(-500, 501, 1)
    y = np.sin((2 * np.pi * x / wavelength)+phase)
    plt.plot(x, y)
    plt.show()
plot_sine_1D(1,300,0)

作者图片

任何图像都是二维离散函数。也就是说,像素是其空间位置的函数。

离散傅立叶变换将图像移动到频率空间,在那里它们由 2D 正弦波表示。

def plot_sine_2D(amp,wavelength,phase,angle):
    x = np.arange(-500, 501, 1)
    X, Y = np.meshgrid(x, x)
    wavelength = 100
    sine_2D = np.sin(
        2*np.pi*(X*np.cos(angle) + Y*np.sin(angle)) / wavelength
    )
    plt.set_cmap("gray")
    plt.imshow(sine_2D)
plot_sine_2D(1,200,0,np.pi)

2D 正弦波

2D 正弦波也可以相对于 x,y 轴旋转。下面是旋转了π/6 弧度的同一个 2D 波。

plot_sine_2D(1,200,0,np.pi/6)

旋转正弦波

让我们设想一些傅立叶变换。我们使用 np.fft.fft2 来实现。该函数的第二行将像素 0,0 移动到图的中心,使可视化更容易。我们的数组大小为 1001,1001,因此中心移动到 500,500。同样,我们取绝对值,因为 FT 返回一个复数。

def compute_fft(f):
    ft = np.fft.fft2(f)
    ft = np.fft.fftshift(ft)
    return ft

sin = plot_sine_2D(1,200,0,np.pi,False)
ft = compute_fft(sin)
plt.xlim([480,520])
plt.ylim([520,480]) 
plt.imshow(abs(ft))

角度为π的正弦波英尺

sin = plot_sine_2D(1,200,0,np.pi/6,False)
ft = compute_fft(sin)
plt.xlim([480,520])
plt.ylim([520,480]) 
plt.imshow(abs(ft))

π/6 旋转的正弦波英尺

在第一个 FT 中,我们得到两个距离中心 10 个单位的点。离中心的距离代表频率。在第二个 FT 图中,我们得到了相同的两个点,但进行了旋转。旋转角度代表波的旋转(30 度)。两点处的像素值描述了振幅。相位信息编码在复数部分,我们不画出来。

f,ax = plt.subplots(1,2,figsize=(15,20))
ax = ax.flatten()
im = cv2.imread('/kaggle/input/randomimages/pic2.jpeg',-1)
im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ax[0].imshow(im,cmap='gray')
ax[1].imshow(20*np.log(abs(compute_fft(im))),cmap='gray')

资料来源:联合国人类住区规划署

英尺的真实图像更难想象。我们在 FT 上进行对数运算,缩小数值,以图像形式绘制出来。

使用傅立叶变换的反卷积

我们已经对 FTs 大惊小怪了,但是它们对我们的情况有什么帮助呢?在频域中,卷积转换为乘法。因此,我们的等式变成了

或者,

对 RHS 进行逆傅立叶变换应该会产生原始图像。但是等等,如何找到正确的平滑核(H)?根据模糊程度,你可以尝试不同的内核。现在让我们坚持使用高斯函数,并用代码实现它。

我们将读入一幅图像,并使用 sigma = 5(内核的标准偏差)的 7,7 高斯内核模糊它

# Plotting image and its blurred version
f,ax = plt.subplots(1,2,figsize=(15,20))
ax = ax.flatten()
im = cv2.imread('../input/randomimages/pic1.jpeg',-1)
im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
im_blur = cv2.GaussianBlur(im,(7,7), 5, 5)
ax[0].imshow(im,cmap='gray')
ax[1].imshow(im_blur,cmap='gray')

资料来源:联合国人类住区规划署

接下来,我们将定义两个函数。一个用于生成给定大小的高斯核,另一个用于获取模糊图像并使其变得清晰。

def gaussian_filter(kernel_size,img,sigma=1, muu=0):
    x, y = np.meshgrid(np.linspace(-1, 1, kernel_size),
                       np.linspace(-1, 1, kernel_size))
    dst = np.sqrt(x**2+y**2)
    normal = 1/(((2*np.pi)**0.5)*sigma)
    gauss = np.exp(-((dst-muu)**2 / (2.0 * sigma**2))) * normal
    gauss = np.pad(gauss, [(0, img.shape[0] - gauss.shape[0]), (0, img.shape[1] - gauss.shape[1])], 'constant')
    return gauss

def fft_deblur(img,kernel_size,kernel_sigma=5,factor='wiener',const=0.002):
    gauss = gaussian_filter(kernel_size,img,kernel_sigma)
    img_fft = np.fft.fft2(img)
    gauss_fft = np.fft.fft2(gauss)
    weiner_factor = 1 / (1+(const/np.abs(gauss_fft)**2))
    if factor!='wiener':
        weiner_factor = factor
    recon = img_fft/gauss_fft
    recon*=weiner_factor
    recon = np.abs(np.fft.ifft2(recon))
    return recon

让我们深入研究一下 fft_deblur 函数。

  1. 我们生成一个给定大小和标准偏差的高斯滤波器。我们也用零填充它,这样它就和图像的形状匹配了。这对于计算频域中的除法是必要的
  2. 计算模糊图像的傅立叶变换
  3. 计算内核的傅立叶变换
  4. 定义维纳因子。我们稍后会谈到这一点。现在,假设它是 1
  5. 将重建定义为(3)和(4)的划分
  6. 将(6)乘以(5)
  7. 逆傅立叶变换(7)并计算其绝对值

让我们分析一下结果。

recon = fft_deblur(im_blur,7,5,factor=1)
plt.subplots(figsize=(10,8))
plt.imshow(recon,cmap='gray')

上述操作的结果

哎呀!这不起作用。之所以如此,是因为我们没有考虑到一个至关重要的因素——噪音。噪声可以从各种来源进入图像。因此,模糊图像等式修改为

现在,在计算模糊图像(B)的傅立叶变换时,我们也隐含地计算噪声分量的傅立叶变换。噪声的傅立叶变换有很多高频值。

noise = np.random.rand(100,100)
noise_fft = np.fft.fft2(noise)
noise_fft = np.fft.fftshift(noise_fft)
f,ax = plt.subplots(1,2,figsize=(15,20))
ax = ax.flatten()
ax[0].imshow(noise,cmap='gray')
ax[0].set_title('Original Image')
ax[1].imshow(20*np.log(abs(compute_fft(noise_fft))),cmap='gray')
ax[1].set_title('Fourier Transform')

另一方面,平滑内核有很多低频值。正如你在下图中看到的,如果我们偏离中心,我们会进入一个主要是黑色的区域(0 像素)。它的原始图像也大部分是黑色的,因为我们用零填充了它。靠近左上方有一小块白色区域。

gauss = gaussian_filter(7,im,5)
gauss_fft = np.fft.fft2(gauss)
gauss_fft = np.fft.fftshift(gauss_fft)
f,ax = plt.subplots(1,2,figsize=(15,20))
ax = ax.flatten()
ax[0].imshow(gauss,cmap='gray')
ax[0].set_title('Original Image')
ax[1].imshow(np.abs(gauss_fft),cmap='gray')
ax[1].set_title('Fourier Transform')

本质上,FT(B)中的高频值对应于噪声。当我们将其除以 FT(H)时,大部分由零组成,我们放大了噪声。因此,我们需要一个常客。香肠因素出现了。你可以在这里找到更多关于维纳滤波器的细节。我们可以用任何其他常数值代替 0.002。

f,ax = plt.subplots(1,2,figsize=(15,20))
recon = fft_deblur(im_blur,7,5,factor='wiener')
ax[0].imshow(im_blur,cmap='gray')
ax[1].imshow(recon)
ax[0].set_title('Blurry Image')
ax[1].set_title('Image reconstruction')
plt.show()

资料来源:联合国人类住区规划署

有了维纳因子,我们得到了更好的结果。我们现在可以用这个常数来得到更清晰的重建。

f,ax = plt.subplots(1,2,figsize=(15,20))
recon = fft_deblur(im_blur,7,5,factor='wiener',const=0.5)
ax[0].imshow(im_blur,cmap='gray')
ax[1].imshow(recon)
ax[0].set_title('Blurry Image')
ax[1].set_title('Image reconstruction')
plt.show()

资料来源:联合国人类住区规划署

资料来源:联合国人类住区规划署

我们不能直接在 RGB 图像上操作 FT。为了消除 RGB 图像的模糊,我们可以在每个颜色维度上分别运行去模糊功能,然后将它们连接起来。

结论

这是一个关于如何使用傅立叶变换去模糊图像的简短指南。虽然去模糊本身是一种应用,但它也可以用作深度学习训练管道中的重要预处理步骤。对傅里叶变换的透彻理解将有助于从事视觉/信号科学的任何人。这是一个宏伟的算法,根据真理的说法,它改变了世界。

参考

https://thepythoncodingbook . com/2021/08/30/2d-python 中的傅里叶变换和图像的傅里叶合成/

作为数据科学家,如何处理令人沮丧的利益相关者情况

原文:https://towardsdatascience.com/how-to-deal-with-frustrating-stakeholder-situations-as-a-data-scientist-92d48e2c32f7

布鲁斯·马斯在 Unsplash 上的照片

作为数据科学家,如何处理令人沮丧的利益相关者情况

并将它们转化为机遇

如果你熟悉我的文章,你就会知道我是利益相关者管理技能的大力倡导者。我坚信,一名优秀的数据科学家不仅应该是利益相关者数据愿景的有效实施者,还应该是帮助利益相关者为其业务问题找到分析解决方案的思想伙伴。但是就像积累任何技能的过程一样,与利益相关者合作不会总是一帆风顺的。

我肯定遇到过令人沮丧的利益相关者的情况;他们中的一些人真的曾经毁了我的一天。不幸的是,根据我与其他数据科学家的交谈,这些情况相当普遍。所以我希望这篇文章能为利益相关者和数据科学家提供一些建议。如果你是一个数据团队的利益相关者,希望这能给你一些启示,告诉你如何更有效地与你的数据伙伴合作,成为一个更好的利益相关者。如果你是一名数据科学家,希望你能得到一些启发,如何不让下面的陈述毁了你的一天,而是利用它们作为发现利益相关者真正需求的机会。

  1. “这个(结果)和我想的不一样……”

这是我从利益相关者那里得到的一个非常普遍的回答。老实说,在我将在本文中提到的所有方法中,它并不是最差的,但它仍然令人沮丧,因为它太抽象了,无法提供任何价值。

然而,涉众的领域知识通常对数据工作非常有价值,因为通常那些嗅探测试是防止任何数据错误或其他错误的第一道防线。因此,当这种说法被提出时,它实际上是数据科学家深入挖掘的一个完美的合作机会。

作为数据科学家如何化挫折为机遇

与利益相关者坐下来,问一些问题。找出分析的数据/结果是如何让他们吃惊的。然后在他们的帮助下,挖掘数据,找出差异的根本原因。当然,仅仅因为数据不符合某人的期望,并不意味着它是错的。但是,有时这种根本原因将提供对数据或业务流程的新见解,并可能帮助您发现一个数据问题,如果没有领域专业知识,您可能不会注意到这个问题。

2.“我们昨天就需要这个(数据,分析,XX)

老实说,无论是谁发明了这个短语,都应该被打上年度最差合作者的烙印,被流放到社会西伯利亚。因为对于这种消极进取的唯一解决方案驱动的反应将是“哦,那让我拿一个时间机器…”。可以理解的是,许多数据需求是迫切的(或者至少目前看起来是如此)。但大多数分析项目不能像高级幻灯片一样在几个小时内完成,因此关于时间表和需求的有效沟通对数据科学家区分工作优先级非常有帮助。

作为数据科学家如何化挫折为机遇

试着找出为什么项目是紧急的,最合理的时间表是什么。要非常清楚为什么不可能立即开发出某样东西并管理期望。

此外,如果某件事非常关键,这很可能不是第一次有人想到要做这件事。因此,很可能已经做了一些工作来帮助回答这个问题的一部分,并将为每个人赢得一点时间来开发更完整的解决方案。作为一名数据科学家,不重新发明轮子可以节省你大量的时间。

最后,为了避免这种情况一次又一次的发生,试着去了解沟通的障碍发生在哪里。如果昨天有人需要这种分析,而今天是数据团队第一次听说,那么很可能有人没有尽早通知你。

3.“为什么我们找不到临时解决方案”

我们可以,但代价是什么?开发强大的数据表/数据源所需的时间与企业回答问题所需的速度之间存在永久性的差异。因此,企业经常要求临时的解决方案。不要误会我的意思,我完全支持必要时的黑客解决方案,只要每个人都知道警告,并仍然致力于开发一个长期的解决方案,最终取代权宜之计。

作为数据科学家如何化挫折为机遇

在我看来,最好的数据科学家可以帮助利益相关者提出相对稳健的临时解决方案,同时帮助设计长期可持续的解决方案。一个例子是数据库中没有记录用于分析或指标监控的数据。权宜之计可能是,如果条目数量合理,请人在 Excel 表中手动记录数据。在这种情况下,数据科学家通常是设计数据输入表的领域专家,以保证数据完整性(例如,构建下拉列表,而不是使用自由文本输入等。).

然而,重要的是不要止步于此;临时解决方案通常无法扩展,并且经常需要大量时间来维护。获得所需的一致性以开发可扩展的长期解决方案是至关重要的(例如,在上面的示例中,让工程承诺在日期 X 之前开始自动记录所需的数据);否则,你将永远被低效、卑微的任务所困。

4.“我们能得到实时数据吗?”

在很多情况下,实时数据被高估了。数据延迟只有在延迟决策时才会成为问题。因此,在这种情况下,我问的第一个问题是“根据实时数据将做出什么决定?”确保答案不是“实时看到它会很酷”。事实证明,许多经理对看到几乎没有延迟的数据感兴趣,但往往不清楚他们实际上会用这些数据做什么。

作为数据科学家如何化挫折为机遇

在某些情况下,实时数据是绝对必要的。一个很好的例子是优步使用的实时激增定价算法。没有实时数据,该模型无法纠正市场的供需失衡。然而,将实时数据呈现给人类(相对于将它吸收到模型中)通常没有多大价值,因为它很难采取行动,并且通常只会导致信息过载。在大多数情况下,特别是如果是为了度量监控的目的,实时数据最多是一个“好东西”。

优秀的数据科学家应该能够倾听利益相关者的痛点以及他们想要实时数据的理由,并能够在确定用例的正确数据延迟和保留期时充当思想伙伴。

5.“为什么 XX(分析、数据可视化等。)如果数据已经存在,需要这么长时间?”

没有数据背景的人,往往会把数据的存在误认为是数据的可用性;仅仅因为一段数据“存在”,并不意味着它是可消化和可用的格式,至少对于没有受过深入数据训练的人来说是这样。每个数据科学家都知道,数据清理和格式化在他们的日常工作中需要花费大量时间。不幸的是,缺乏对数据的理解通常会导致利益相关者和数据科学家之间的不信任。

作为数据科学家如何化挫折为机遇

对于数据科学家来说,学会用通俗易懂的语言解释分析概念并让利益相关者参与数据转换之旅非常重要。如果数据以原始日志的形式“存在”在数据库中,那么向风险承担者展示少量的数据样本可能有助于解释为什么在转换数据之前很难生成任何信息性的见解和/或可视化。业务利益相关者对数据分析工作流的理解越好,他们就越能理解您的时间表要求。

感谢阅读!如果你想了解更多关于数据科学和商业的知识,这里有一些推荐:

</5-mistakes-i-wish-i-had-avoided-in-my-data-science-career-6c22a44304a1>

如何处理数据科学中的缺失值

原文:https://towardsdatascience.com/how-to-deal-with-missing-values-in-data-science-9e5a56fbe928

处理 DS 项目中缺失值的三种实用方法

Pierre Bamin 在 Unsplash 上拍摄的照片

W 在处理现实世界的数据时,您可能经常会发现数据框中缺少一些值。发生这种情况有几个原因,例如:

  • 一些测量值可能会丢失
  • 缺乏信息
  • 抄本错误

那么问题来了:如何处理缺失数据?我们可以接受 0 作为缺失数据的值吗?我们可以删除丢失数据的行吗?

在本文中,我将向您展示处理缺失数据的三种方法,并回答这些问题。

1.提问

当你在数据集中发现缺失值时,你要做的第一件事就是提问,因为,通过提问,你将理解问题;理解问题是数据科学项目最重要的任务:如果我们不理解问题,我们就不能提供价值。

如果有人向你提供数据,问他们这样的问题:

  • 你从哪里得到的数据?
  • 为什么会有缺失值?
  • 这些特征意味着什么?我可以接受 0 作为这些缺失数据的值吗?

如果你自己得到数据,问自己同样的问题。

还有, Google 了很多。搜索您拥有的缺失数据的参考值,并尝试了解您可能会为您的缺失数据赋予哪个值(请记住:即使 0 也是一个值!!).

此外,如果可以的话,尝试联系该领域的专家。例如,如果您正在处理一个医疗数据集,请联系医生(可能是您的医生!)并对你拥有的数据提出问题,尤其是对你缺失的数据。

2.删除行/列

在某些情况下,我们可以删除缺少值或 Nan(Nan =不是一个数字;甚至可以是类似“未测量”或“缺失”的字符串)。

如前所述,我们必须在一定程度上确保我们在删除这些列/行方面做得很好。例如,在我创建的项目中,我发现一些丢失的值,并决定删除这些行。

让我们来分析这个案例:这些数据与世界上所有国家的粮食产量有关。假设我们的数据框架是“df”,这是我发现的:

df.isnull().sum()>>> Area Abbreviation      0
   Area Code              0
   Area                   0
   Item Code              0
   Item                   0
                       ... 
   Y2009                104
   Y2010                104
   Y2011                104
   Y2012                  0
   Y2013                  0
   Length: 63, dtype: int64

对于 2009、2010 和 2011 年,我们有 104 个空值;但是此处列出的列并不都是此数据框的空值;无论如何,如果我们看一下数据,我们可以看到,在一些年,在一些国家,有 0 吨的食物生产值。这意味着一件简单的事情:的数据无法被记录,或者,在那个特定的国家,那个特定的年份,那个特定的食物无法被生产 (或者,在他们的历史上,他们从来没有在那个特定的国家生产过那个特定的食物!).

通过这个简单的分析,我决定使用下面的代码删除具有空值的行:

df **=** df**.**loc[(df**.**loc[:, 'Y1961':'Y2013']**!=**0)**.**any(axis**=**1)]

3.用平均值代替缺失值

有时值 0 是不可接受的,也许因为我们只有少量的数据,删除行/列是不可行的。那么,我们能做什么呢?一种可能性是用同一行/列中的其他值的平均值替换空值。

例如,在这个项目中,我分析了一个数据集,其中我使用机器学习来预测糖尿病。在这种情况下,很容易理解我们不能接受 0 作为身体质量指数(身体质量指数)或血压的值。因为数据很少,所以我不能删除任何一行。所以,我用同一列中其他值的平均值来填充零;我用下面的代码做到了:

#filling zeros with mean value
non_zero = ['Glucose','BloodPressure','SkinThickness','Insulin','BMI']
for coloumn in non_zero:
    diab[coloumn] = diab[coloumn].replace(0,np.NaN)
    mean = int(diab[coloumn].mean(skipna = True))
    diab[coloumn] = diab[coloumn].replace(np.NaN, mean)
    print(diab[coloumn])

这样,我用计算出的其他身体质量指数值的平均值替换了身体质量指数列中的零,等等。

结论

处理丢失的值总是很难,因为我们必须做出决定,并且这些决定必须在编写实际代码之前经过深思熟虑。

所以,先提问,大量 Google,尽量深入理解问题和你要处理的数据。然后,决定如何处理丢失的数据(例如,接受空值、删除列/行、用平均值替换丢失的值或空值)。

我们一起连线吧!

中等

LINKEDIN(向我发送连接请求)

如果你愿意,你可以 订阅我的邮件列表 这样你就可以一直保持更新了!

考虑成为会员:你可以免费支持我和其他像我一样的作家。点击 这里 成为会员。

使用人工智能检测欺诈

原文:https://towardsdatascience.com/how-to-deal-with-unbalanced-data-d1d5bad79e72

机器学习应用

什么是精确和召回,你如何使用它?

马克斯·弗莱施曼在 Unsplash 拍摄的照片

在机器学习中处理不平衡数据是困难的。我使用精确度、召回率、F-beta 分数和阈值,通过应用基本的机器学习理论训练一个分类器来检测欺诈数据。

介绍

我的文章通常是关于机器学习理论,而不是它的应用。在这篇文章中,我想深入一个迷你项目,在这个过程中教给你一些理论,但最重要的是讨论在将机器学习应用于不平衡数据集时的良好实践方法。

不平衡的数据可能很难处理。在本文中,我将训练一个分类器来识别交易数据中的欺诈,并介绍一些可能在其他不平衡数据应用程序中派上用场的方法。

什么是不平衡数据?

不平衡数据由目标变量与其他类相比具有非常不同的观察值数量的数据集组成。在不平衡问题中,目标变量通常是样本最少的变量,这意味着包含目标变量类的观测值不多。在我们的欺诈交易数据示例中,大多数数据都是非欺诈性的,相比之下,欺诈交易的数量非常少。

数据

在这个项目中,我使用了 Kaggle 的信用卡欺诈检测数据集。这个数据集是开源的。该数据集包含 284,807 笔交易,其中只有 492 笔是欺诈性的。即所有交易中只有 0.172% 是欺诈!这个数据集非常不平衡,因此训练模型对欺诈进行分类将是一个挑战。

不平衡数据的度量

在我进入机器学习之前,我想阐述一些重要的理论。我要讲的第一件事是用于分类器的不同度量(我们如何知道它们是否表现良好)。第二是如何使用阈值来偏置分类器。这两个概念在处理不平衡数据分类时超级有用。

精确度与召回率

当在不平衡数据上训练分类器时,准确度根本不是有用的度量。在我们的数据集中,如果我们的分类器将每笔交易都归类为非欺诈性的,它将达到 99.98%的准确率。尽管如此,该模型将是完全无用的,因为它不会发现任何欺诈交易。

因此,我们需要更好的指标来衡量模型的性能:

图 1:猫和狗分类器的精确度和召回率

在上图中,我已经形象化了什么是精确度和召回率。我选择了猫和狗,而不是欺诈和无欺诈,因为它们更容易被形象化,但概念是一样的。图片左边是猫狗的空间,分类器已经对样本进行了分类。圆圈内的样本归类为猫,所有其他样本归类为狗。这些分类有些是对的,有些是错的。

召回率:给定类别的召回率是该类别的正确分类样本量除以该类别的样本总量。

精度:给定类别的精度是正确分类的样本量除以预测为该类别的样本总数。

在上图中,有 4 只正确分类的猫和 7 只猫,这意味着召回率是 4/7。分类器将 6 个数据点分类为猫,意味着精度是 2/3。

在欺诈示例中,回忆是我们设法检测到的欺诈交易的百分比,而精确是我们归类为欺诈的交易实际上是欺诈的交易的百分比。在对欺诈进行分类时,我们主要关心欺诈类别的召回,也就是说,我们希望尽可能多地对欺诈交易进行正确分类。我们仍然关心精确度,只是不如回忆。

F-beta 分数

你们很多人可能听说过 F-1 乐谱。F-1 分数是回忆和精确的结合,它经常被用在文学作品中。

F-1 分数是召回率和精确度的调和平均值。调和平均值是倒数的算术平均值的倒数。精确度和召回率的调和平均值用于 F-1 分数,而不是算术平均值,因为调和平均值对较小的值惩罚更多。因此,如果你的回忆很高,但你的精确度很低,你的 F-1 分数可能很低。

等式 1: F- Beta 分数(作者)

F-1 是 F-beta 分数的一个特例,其中 beta = 1。 F-1 可能不是不平衡数据集的最佳指标,因为它同等地权衡了精确度和召回率。相反,我们可以将 beta 设置为更高的值,以便更加重视回忆。根据您的问题,对您来说,召回率或精确度可能更重要,您必须调整 beta 来满足您的需求。

阈值

现在,我们知道了如何根据上面讨论的指标来衡量模型的性能。正如我提到的,我们对回忆感兴趣。但是我们如何使我们的模型产生最高的召回率呢?

分类器的输出通常是 s 形的(扩展到 Softmax 用于多类分类问题)。模型的输出可以解释为类成员的概率。在欺诈的情况下,模型输出交易是欺诈的概率。

一般来说,如果概率高于 50%,我们称之为欺诈交易,如果低于 50%,我们称之为非欺诈交易。

图 2:示例 sigmoid 的阈值偏置(图片由作者提供)

我们可以更改此阈值,将所有具有较低值(例如 10%)的样本归类为欺诈性样本。这将大大增加我们标记为欺诈的样本数量,但也会降低我们对预测准确性的信心。

让我们回到我们已经看到的精度和召回。通过降低阈值,我们自然会牺牲精确度来提高召回率。我们猜测更多的交易是欺诈性的,特别是我们认为非欺诈性的交易比欺诈性的交易更有可能。通过这样做,我们可以增加我们正确分类为欺诈的数量,但我们也会增加我们错过的非欺诈样本的数量-分类为欺诈。

回顾 F-beta 分数,左边的案例可能比右边的案例有更高的 F1 分数。这是因为 F-1 权衡精确性和回忆平等性。然而,右边的情况可能比左边的情况具有更高的 F-10 分数,因为右边的情况可能具有回忆的增加,这抵消了精确度的降低,足以增加 F-10 分数。

通过改变我们的模型的阈值,我们可以迫使模型预测更多的样本是欺诈性的,这降低了我们的精确度,但提高了召回率。我们可以对每一个可能的阈值都这样做,并映射得到的精度和召回率来选择最佳模型。

应用:欺诈检测

我已经讨论了衡量不平衡数据分类器性能的指标。现在我想讨论如何训练模型,以及如何使用这些指标来产生最佳模型。

探索性数据分析

在开始任何项目之前,我喜欢做好探索性数据分析(EDA)。确保正确理解数据可以在以后编码时节省大量时间。在未来的一篇文章中,我将更一般和详细地谈论 EDA。

我一直探索的一些关键事物:

  • 属性:大小、类型(不一致?),分布参数,如平均值、标准偏差、最小值、最大值
  • 重复:是否有重复的行,我应该删除它们吗?
  • 唯一性(对于分类值)
  • 缺失值(如果您正在编写报告,可以绘制热图或条形图)

对于此数据集,没有重复、唯一或缺失的值。

除了探索这些初始属性,我还希望使用箱线图、直方图和成对散点图来可视化数据的分布。我也检查线性相关性。我不想在这里讨论这个问题,因为它不是很有趣。

机器学习模型

在不平衡的数据上训练机器学习模型可能是一个挑战。开箱即用的机器学习模型很难在不平衡的数据集中表现良好。在欺诈性交易分类的情况下,将所有交易分类为欺诈性交易已经产生了非常小的损失,因此当优化时,比如说使用基于梯度的优化器,梯度将非常小。

因此,我们必须以不同的方式对待不平衡数据分类。在本文中,我将讨论两种方法,但请记住,还有更多方法。这两种方法是欠采样加权分类

欠采样:欠采样简单地说就是我们随机地将样本最多的类下采样到样本最少的类的同样大小。在欺诈交易的情况下,训练集总共有 343 个欺诈交易和近 200,000 个非欺诈交易。我对非欺诈性交易进行了降采样,使其与欺诈性交易的规模相同。由于欠采样,我浪费了大部分数据,因此这通常不是最好的方法。

加权分类:加权分类是在属于样本最少的类别的样本上训练一个权重较大的分类器。为了选择合适的权重,我对每个类别使用了以下等式:

等式 2:每个类别的平衡权重,c 是类别的数量,Ni 是每个类别中的样本数量

通过选择这些权重,我平衡了每类样本数量的差异。对于欺诈交易数据集,非欺诈交易的权重为 0.5,欺诈交易的权重为 289。

结果

我使用欠采样和加权分类训练了一个随机森林模型和一个逻辑回归模型。随机森林模型似乎做得更好。通过改变阈值,我可以绘制下面的图表,权衡每个模型的精度和召回率。

图 3:为分类欺诈交易而训练的机器学习模型的精度和召回率

在上面的图中,每一行都代表了当我改变分类阈值时,模型在精确度和召回率上的折衷。模型越靠近右上角,其 F1 分数越高。我挑选了 3 个模型进行分析(红色、黑色和绿色)。红色模型具有最高的 F1 分数,黑色模型具有更高的召回率和仍然良好的精确度,绿色模型在 3 个模型中具有最高的召回率和最低的精确度。

图 4:图 3 中选择的三个模型的混淆矩阵。左上角是真阳性,右下角是真阴性,右上角是假阳性,左下角是假阴性。

图 4 显示了我选择的 3 个模型的混淆矩阵。红色模型具有最高的 F1 分数,因此假阴性和假阳性的总和最小。错误分类的样本数量很少。然而,该模型将 21/149 欺诈交易分类错误。如果我们牺牲一些精度,我们可以减少这个数字。

如果你看黑色的模型,它错误地分类了 16/149 欺诈交易。绿色的只错分了 10/149。然而,假阴性的减少伴随着假阳性的大量增加。黑色模型预测 88 个非欺诈样本为欺诈样本,绿色模型预测 2492 个!

根据使用情况,红色、黑色或绿色型号可能是最好的。为了提高欺诈性交易的检测率,您可能不介意对欺诈性交易进行错误分类。每个用例都是不同的,由数据科学家来决定每个场景中的最佳模型。

加分内容:本福德定律

图 5:欺诈和非欺诈交易的贝尔福德法则(图片由作者提供)

作为对那些好奇者的额外奖励,我想快速地讲一下贝尔福德定律。

贝尔福德定律就是这条出现在数学中的曲线。它出现在斐波那契数列和柯拉茨猜想中。如果你取非欺诈交易的第一位数,你可以看到第一位数的分布遵循橙色曲线。如果你试图对欺诈性数据做同样的事情,它根本不符合贝尔福德定律。人们可以在他们的模型中实现这一点,例如,通过交易开始时的数字对交易进行加权,但我将把这留给您去探索!

结论

本文向您展示了几种处理不平衡数据(一个类的样本少于其他类的数据)的方法。我先教你什么是回忆和精确。有了精度和召回率,量化机器学习模型在应用于不平衡数据时有多好就变得更容易了。我谈到了阈值,以及如何利用这些阈值使模型偏向更高的回忆。通过这个,我训练了一个模型,它能够在测试集中识别超过 93%的欺诈交易。

支持我👏

希望这对你有所帮助,如果你喜欢,你可以 关注我!

你也可以成为 中级会员 使用我的推荐链接,获得我所有的文章和更多:https://diegounzuetaruedas.medium.com/membership

你可能喜欢的其他文章

信息论应用于 Wordle

强化学习:简介

额外的改进点

披露这不是你能训练的最好的欺诈交易分类器。通过考虑一年中的时间、一周中的某一天,并寻找欺诈交易的周期性,您肯定可以改进这个模型。你也可以使用贝尔福德定律,你可以训练更深层次的模型。您还应该将数据分成一个验证集,选择您的阈值,并对验证集进行评估。

如何确定用于检测网络入侵的数据集

原文:https://towardsdatascience.com/how-to-decide-on-a-dataset-for-detecting-cyber-attacks-c92e4f78e7a7

选择正确入侵检测数据集的简史和标准

Alexander Schimmeck 在 Unsplash 上的照片

你创造了一个惊人的机器学习算法。你采取了一种新颖的方法,应用了被证明是高度准确的技术。您的结果显示了非常高的真阳性率和非常低的假阳性率。你写一篇论文,阐述你的杰出成果,并提交给一个领先的学术会议。你期望这项研究将会受到好评,你将会收到许多对你的工作的引用。

经过漫长的同行评议过程,你终于得到了坏消息。你的论文没有被接受。发生了什么事?你的研究哪里出错了?当你阅读评论者的评论时,你会发现问题不在于你的科学方法。这不是你如何选择功能。这不是你的算法或者你如何计算你的结果。相反,它是你的数据集。

机器学习研究通常基于非常流行的数据集,研究社区已经普遍接受了它们。然而,如果您在过去二十年中参与了入侵检测研究,您可能会发现您的结果被拒绝发表或在发表后受到批评。

是什么让入侵检测数据集与众不同?本文探讨了机器学习对网络安全的挑战。它回顾了入侵检测数据集的短暂历史,探索了当前有用的数据集,概述了选择最佳数据集的标准,并探索了创建相关数据集的未来方向。

1999 年 KDD 杯——原版

第一个入侵检测数据集是为 DARPA 竞赛开发的,被称为 1999 年 KDD 杯[1]。它是使用 cyber range 创建的,cyber range 是一个小型网络,专门为网络安全专业人员创建,用于练习对现实目标的攻击。网络数据包数据是从网络范围捕获的,并使用一种称为 Bro-IDS 的入侵检测系统进行处理。结果是一组从原始网络数据中提取重要特征的 CSV 文件。研究人员处理了数据并添加了标签。

概述 1999 年 KDD 杯是如何产生的。图片作者。

KDD 杯 1999 数据集包括 490 万条连接记录。该数据包括四大类攻击。首先是拒绝服务攻击,这种攻击试图消耗计算机的资源并扰乱正常运行。第二种是用户到根攻击,即拥有用户级访问权限的个人试图提升其权限以获得管理员级访问权限。第三种是远程到本地攻击,这种攻击试图获得远程访问权限。第四,探测攻击,代表攻击者的侦察活动[2]。对正常记录和特定类型的攻击进行标记,使数据集非常适合有监督或无监督的机器学习。

从一开始,1999 年 KDD 杯就为入侵检测数据集设定了标准,因为它是唯一一个允许在不同研究人员之间推广研究的标准。此外,很少有研究人员愿意花时间捕获和标记数百万条记录,结果却让研究界质疑他们数据的质量或真实性。

随着时间的推移,对 1999 年 KDD 杯的批评开始浮出水面。第一个批评是,计算机和网络这些年来发生了变化,这使得 1999 年的数据集在 20 年后变得不那么相关。今天的计算机网络有更新的操作系统、不同的网络技术和改进的网络安全防御。

第二,KDD 杯 1999 年数据集因其许多重复记录而受到批评。复制真的是个问题吗?大多数计算机网络都以正常的节奏运行,因此入侵数据集也包含副本可能是现实的。对于拒绝服务数据来说尤其如此,当有正在进行的攻击时,这些数据看起来非常一致。然而,研究界鄙视重复,因为它会产生过度拟合的问题。

第三个批评是,由于记录的数量如此之多,研究人员通常只使用数据集的一个子集进行测试。随着每个研究人员对不同的子集进行采样,消除重复,并增强数据集,跨研究人员比较结果变得更加困难。

随着时间的推移,衍生产品被创造出来以应对一些批评。古里·KDD 使用了 1999 年 KDD 杯的原始数据,但加入了 DARPA 挑战赛的原始网络数据。包括网络有效载荷和报头数据提高了网络攻击的检测能力[3]。

NSL-KDD 的数据集采用了不同的方法。研究人员清理了 1999 年 KDD 杯的数据,而不是回到原始的网络数据。他们删除了冗余记录和重复记录,以实现更好的数据分布。古雷·KDD 和 NSL-KDD 仍然有一个根本性的问题——它们基于过时的计算机网络,不再适用。

LUT13 是使用与 1999 年 KDD 杯数据集相似的方法创建的。研究人员使用了一个带有现代计算机技术的试验台。他们收集了原始的网络数据包数据,并提取了一个新的特征集。该数据与 1999 年 KDD 杯的数据更相关,并且有所改进,但是没有被研究团体广泛采用。它没有成为入侵检测研究的标准。

尽管有这些改进的数据集,许多研究人员仍然专注于 1999 年 KDD 杯和 NSL-KDD 数据集。这些数据集的使用受到了挑战。会议论文被拒绝,出版物开始建立 1999 年 KDD 杯不再有效的先例。

什么是好的入侵数据集?

用于入侵检测研究的权威数据集可能很难找到。技术变化。威胁不断演变。数据集很快就会失去相关性。

一个好的入侵检测数据集应该基于完善的标准。研究人员已经公布了评估这些数据集的几个标准[5]。在选择数据集或创建新数据集时,请记住这些标准。

数据集应该是完整的,这意味着它们应该包括审计日志和原始网络数据。大多数审计日志包含关于网络攻击的不完整信息。用原始数据补充审计日志可以改进威胁检测。

入侵数据集应包括代表当前威胁形势的各种攻击类型。随着组织投资于网络安全防御,对手会调整他们的战术,这就造成了恶性循环的升级。因此,使用最近创建的数据集或使用可以适应和创建相关攻击的数据集生成器是很重要的。

数据集对于正常活动也需要是真实的。计算机网络可能非常庞大和复杂,因此包含来自小型测试平台的正常流量的数据集可能无法转移到真实的计算机网络。数据集应该包括终端用户工作站、服务器和网络拓扑的多样化选择。

标签尤其重要,但这可能是一项艰巨的任务。无论您使用的是监督学习还是非监督学习,表示基本事实的标注对于计算算法的准确性都是至关重要的。一些研究人员使用网络范围,在允许攻击者利用系统之前先收集正常流量。这允许他们首先创建正常流量的标签,然后标记攻击流量。其他研究人员将攻击数据流注入正常流量。还有一些要经过更费力的取样和人工标记。

隐私也很重要。组织中的计算机网络是最好和最可靠的数据来源。然而,组织不愿意提供详细的网络和审计日志,因为这可能会侵犯隐私。大多数研究人员远离捕捉实际的计算机网络流量。相反,他们专注于模拟数据和网络范围,以避免隐私问题。

数据集也需要被研究界广泛接受。如果没有社区的支持,数据集可能只能在少数研究项目中使用。如果您正在进行入侵检测研究,如果社区支持您的数据,您的结果会更容易被接受。

寻找更好的数据集

UNSW-NB15 已经成为一个较新的数据集,解决了一个好数据集的大部分标准。它创建于 2015 年,带有网络流量生成器,用于产生包括正常流量和模拟攻击流量的合成网络数据[6]。研究人员使用 Bro-IDS 处理原始网络数据,就像 1999 年 KDD 杯数据是如何创建的一样。他们还使用了一个名为 Argus 的附加安全工具来创建更丰富的功能。因为他们生成合成流量,所以他们使用网络流量生成器中的报告功能来导出标签。除了正常的流量之外,它们总共产生了九种不同类型的攻击。

概述 UNSW-NB15 是如何创建的。图片作者。

与优秀入侵检测数据集的标准相比,UNSW-NB15 同时拥有审计日志和原始网络数据。它有更完整的攻击手段。它包含了真实的网络活动,并且被很好地标记。因为它是合成数据,所以不存在隐私问题。完整的数据集甚至包括源和目标 IP 地址,这些地址通常被大多数组织视为过于敏感而不能公开。研究团体已经接受了 UNSW-NB15。因此,它出现在许多同行评议的出版物中。

未来方向

既然你理解了对 1999 年 KDD 杯数据集的批评,你可能想知道 UNSW-NB15 是否仍然相关。毕竟,自 2015 年以来,技术和网络攻击已经发生了变化。这个数据集会遭受与 1999 年 KDD 杯同样的命运吗?

未来的研究人员将继续处理为入侵检测寻找可接受的数据集的挑战。UNSW-NB15 的一个重要贡献是,研究人员开发了一种高效且公认的方法,用于创建真实的(尽管是合成的)入侵检测数据集。

较新的数据集正在出现,如 CICIDS2017,以及专门的数据集,如 Bot-IoT。如果您正在开始学习入侵检测的机器学习,请找到一个数据集:

  • 包括审计日志和原始网络数据
  • 包含各种现代攻击
  • 代表真实多样的正常交通
  • 被标记为
  • 提供隐私保证
  • 被社区所接受

花些时间为你的目标选择最好的数据集。更好的是,使用几个数据集来测试你的算法,看看你是否得到相同的结果。

参考

[1] S. Stolfo,W. Fan,W. Lee,A. Prodromidis 和 P. Chan,《欺诈和入侵检测的基于成本的建模》( 2000 年),美国国防高级研究计划局信息生存性会议和展览会议录

[2] M. Tavallaee,E. Bagheri,W. Lu 和 A. Ghorbani,对 KDD 杯 99 数据集的详细分析(2009 年),2009 年 IEEE 安全和国防应用计算智能研讨会会议录

[3] I .佩罗娜、I .古鲁查加、o .阿伯雷茨、j .马丁、j .穆盖尔扎和 j .佩雷斯,改进网络流量中入侵检测的服务独立有效载荷分析(2008 年),第七届澳大拉西亚数据挖掘会议记录

[4] V. Cao,V. Hoang 和 Q. Nguyen,为入侵检测系统建立数据集的方案(2013 年),第三届世界信息和通信技术大会

[5] W. Haider,J. Hu,J. Slay,B. Turnbull 和 Y. Xie,基于模糊定性建模生成现实入侵检测系统数据集(2017),网络与计算机应用杂志

[6] N. Moustafa 和 J. Slay,UNSW-NB15:网络入侵检测系统的综合数据集(2015),军事通信和信息系统会议

如何在 Python 中修饰类方法

原文:https://towardsdatascience.com/how-to-decorate-class-method-in-python-6627234b33a

劳拉·阿岱在 Unsplash 上拍摄的照片

在 Python 中,函数是一级对象。这意味着它可以作为参数传递给其他函数。使用 decorator,无需重新编写函数代码就可以改变 Python 函数的行为。

Python decorator 的一个流行例子是@property,它允许以安全的方式访问函数的值。您可以使用@property的 setter 属性安全地修改值。更多细节可以在这里找到

Python 的装饰器特性天生就令人困惑(至少对我来说是这样)。此外,我对给定代码中的信息流非常挑剔。我发现使用class作为一种尽可能保持代码简单和抽象的方式很方便。为了演示一种简洁的方式来编写decorate代码,我编写了一个示例代码。

我在这个例子中定义了两个classes

  • GenericClass:带有变量initial_value和方法operation的演示类。operation的主要目标是返回作为参数传入的值的总和。
  • DecoratorClass:包含一个wrapper函数,用于修饰GenericClass对象的operation方法。wrapper函数的主要目的是使用operator函数和value变量来修饰operation方法。该操作符函数可以是 Python 的内置函数,如maxmin,value可以是任意的float数。本质上,wrapper确保当<GenericClass_instance>.operation(*args)被调用时operator(value, <GenericClass_instance>.operation(*args))被返回。

让我们深入一下这个例子。让我们构造一个<GenericClass>的实例。

example = GenericClass(initial_value = -10)

这创建了一个<GenericClass>example实例和 10 的实例变量initial_value

让我们用实例变量operatorvalue构造一个<DecoratorClass>的实例。

always_positive = DecoratorClass(operator=max, value=0.0)

现在让我们来看几个更小的always_positive实例用例的例子。

代码:

获得 5、6 和-7 之间的最小值

min(5, 6, -7)

输出:

-7

但是现在使用always_positive实例,我们可以修改输出,使其返回值大于 0。注意在<DecoratorClass>实例中,操作符是max,值是 0.0。这意味着包装函数的输出是这个修改的函数,使得<modified_function> = max(0.0, <func>)

代码:

modified_function = always_positive(min)print(modified_function)

输出:

<function __main__.DecoratorClass.__call__.<locals>.wrapper at #ID>

输出返回修改函数的typeid()

现在让我们在这个modified_function中传递几个参数并观察输出。

代码:

modified_function(5, 6, 7)

输出:

5

这是显而易见的,因为min(5, 6, 7)是 5,并且即使函数被修改为总是正的,输出仍然保持为 5,因为显而易见 5 大于 0。

代码:

modified_function(5, 6, -7)

输出:

0.0

由于作为modified_function参数传递的所有数字中最小的是-7,并且-7 明显小于 0,所以现在结果被修改为always_positive.value(在本例中为 0.0)。

现在让我们进一步扩展这个概念,使用 python decorator 修改类方法<GenericClass>.operation。装饰器<DecoratorClass>可以通过如下传递参数来实例化。

Class GenericClass:.
.
. @DecoratorClass(operator=max, value=0.0)
   def operation(self, *args) --> float:
       ...

这用装饰器修改了类方法<GenericClass>.operation(),方式与我之前的例子modified_function相似。在这种情况下,代码更加抽象和复杂,可以处理任何帮助函数(如minmax等)。).

这个概念可以进一步扩展到修饰任何类方法来改变它的行为。像这样使用装饰函数的一个用例是“防止”更复杂函数的错误输出。

举例:

这个演示代码可以使用 Google Colab 打开。

如果你喜欢它…

如果你喜欢这篇文章,你可能也会喜欢我其他类似主题的文章。

https://sidbannet.medium.com/membership

关注我 即将发布的关于随机建模、数据科学和 python 技巧的每周文章。

我以前的故事:

A 关于我——我开发高性能计算模型来理解湍流多相流、燃烧火焰。我应用数据科学来加速推进装置的设计创新。我于 2011 年获得了威斯康辛大学麦迪逊分校的博士学位,主修机械和化学工程,辅修数学统计学计算机科学。请随意查看我的 GitHub 资源库,并在Linkedin上关注我。

如何将神经网络定义为数学函数

原文:https://towardsdatascience.com/how-to-define-a-neural-network-as-a-mathematical-function-f7b820cde3f

一个多层神经网络几乎总是被表示为一个带有神经元网络的图表,人们可能会忘记它只是一个数学函数

为了提醒神经网络的基本原理,让我们在没有 神经元、节点、突触、轴突、边缘、隐藏层、感知器的情况下,硬定义它们

作者图片

全局函数

一个 k 层神经网络是一个数学函数 f,它是一个多元函数的组合:f1,f2,…,fk,g,定义为:

f : Rn→ Rp

f=g∘fk∘…∘f2∘f1

在哪里

  • n 是输入 x 的尺寸
  • p 是输出的尺寸 y
  • g 是输出函数(根据输出变量的不同,它可以采取不同的形式)
  • 每个函数 f_i 本身是一个由多元函数组成的

f_i(x)=a(w_i x+b_i)

作者图片

中介函数 f_i

每个函数 f_i 是由函数组成的复合函数

  • wx+b a 输入 x 的线性组合及其系数 w ,加上一个偏置 b
  • ****一个被称为激活函数(对于每个中间函数 f_i 都是一样的)

激活函数可以采取各种形式,例如 sigmoid、tanh、Relu 等。在维基百科页面上,有一个激活列表,如果你想看更多的话。我们可以用它们的数学公式来提醒一些最常见的:

作者图片

让我们通过引入权重 w 和偏差 b 来开发全局函数。

作者图片

结构域和共结构域的维数

每个函数 f_i 将其在 Rn(i-1)(维数 n(i-1))中的输入映射到余域 Rni(维数 ni),Rni 的维数可以由数学家选择(它是神经网络的超参数之一)。

f_i : Rn(i-1)→ Rni

我们有一个特殊的情况:对于 i=1,函数 f1 的输入是全局输入 x。所以维数是 n。

对于每个中间函数 f_i,激活函数是相同的。对于矩阵形式,所有与维度相关的复杂性都发生在线性 w_ix+b_i

  • x 的尺寸为 n(i-1)
  • w 是一个矩阵,它的维数是 ni × n(i-1)
  • b_i 的尺寸为 ni

作者图片

激活函数应用于尺寸为 ni 的矢量 zi

输出函数 g

所有的中间函数 f_i 都在函数的嵌套复合中。输出函数 g 也是一个复合函数

  • wx+b a 输入 x 的线性组合及其系数 w ,加上一个偏置**b**
  • ****答激活函数取决于目标变量的性质。

作者图片

  • 对于一个回归任务,输出激活函数是身份函数。所以我们只有线性组合。函数的共域是 r。
  • 对于一个二元分类任务,输出激活函数为 sigmoid 。输出的值将在 0 和 1 之间。
  • 对于多类分类任务,使用 softmax 函数。值得注意的是,输出是多元的。维数 N 是类的数量。对于每个类,计算 0 和 1 之间的输出。

我们可以通过引入权重和偏差来开发函数 g 的公式:

作者图片

一些特殊情况

为了更好地形象化整个函数,让我们看一些简单的例子。

无中介功能

如果没有中间函数,那么神经网络就相当于输出函数:

  • 无隐含层和连续目标变量的神经网络为线性回归****
  • 无隐含层和二元目标变量的神经网络为逻辑回归****
  • 一个无隐含层的神经网络和一个多项目标变量

作者图片

一个中介功能

如果只有一个中间函数,中间输入的维数是 2(好吧,就说它吧,2 个神经元),那么我们就可以写下完整的函数及其图形。

用于回归

作者图片

对于二元分类

作者图片

性感的词汇和图表

现在,你看到,用这种硬方法,完整的函数变得非常难以阅读。所以神经元网络的表示可以提高可读性。

  • 神经元的输入层节点代表输入 x,神经元的数量是输入 x 的维数
  • ****输出层代表输出 y,神经元的数量取决于目标变量的性质。对于回归二元分类,只有 1。对于多类分类,神经元的数量就是类的数量。
  • ****隐藏层表示中间函数 f_i 的结果
  • **链接或突触代表权重和**的值。所以两层之间的所有链接一起代表一个矩阵。链接数为 ni × n(i-1) ,作为矩阵的维数 wi。

作者图片

结论

在某种程度上,数学家是很好的营销者。人工智能、神经网络无疑吸引了大众更多的关注。但是作为机器学习的初学者,不被这些术语愚弄也是有风险的。

我还想到了其他可以非性感方式定义的算法:支持向量机,Ridge,Lasso,Elastic Net** 等。**

你怎么想呢?

要获得监督机器学习算法的完整概述,您可以阅读以下文章:

** **

为了更好地理解神经网络是如何工作的,有必要了解如何从头开始实现它。如果你懂一门编程语言,比如 Python ,你可以用编程的方式来做。如果没有,也可以在 Excel 中实现。你可以看看我下面的文章:

**

我写关于机器学习算法的文章,请通过下面的链接关注我,并完全访问我的文章:

https://medium.com/@angela.shi/membership **

如何在 TensorFlow 中定义自定义图层、激活函数和损失函数

原文:https://towardsdatascience.com/how-to-define-custom-layer-activation-function-and-loss-function-in-tensorflow-bdd7e78eb67

阿德里安·匡威Unsplash 上的照片

一步一步的解释和完整代码的例子

我有几个关于 Tensorflow 的教程,其中一直使用内置损失函数和层。但是 Tensorflow 比这更有活力。它允许我们编写自己的自定义损失函数,并创建自己的自定义层。所以,在 Tensorflow 中制作高效模型的方法有很多。

最好的学习方法是边做边学。因此,我们将通过使用免费公共数据集的练习来学习,我在上一篇关于多输出模型的教程中使用了该数据集。

我假设你已经知道数据分析、数据清理和 Tensorflow 的基础知识。所以,我们会在开始的时候动作快一点。

数据处理

我将在本教程中使用的开放公共数据集相当干净。但是,一点点的清洁是必要的。

以下是数据集的链接:

https://datahub.io/machine-learning/autos#resource-autos

我已经根据需要清理了数据集。请随时从这里下载干净的数据集,以便跟进:

https://github.com/rashida048/Tensorflow/blob/main/auto_price.csv

我们开始吧。

首先在这里导入所有必需的包:

import numpy as np
import pandas as pdimport tensorflow as tf 
from tensorflow.keras import Sequential 
from tensorflow.keras.layers import Dense 
from tensorflow.keras.optimizers import Adam 
from tensorflow.keras import backend as K
from tensorflow.keras.layers import Layer

这是数据集:

df = pd.read_csv("auto_price.csv")

尽管我说过这是一个干净的数据集,但它仍然有两个不必要的列需要删除:

df = df.drop(columns=['Unnamed: 0', 'symboling'])

我们将把数据集分成三部分。一个用于培训,一个用于测试,一个用于验证。

from sklearn.model_selection import train_test_split
train, test = train_test_split(df, test_size=0.2, random_state=2)
train, val = train_test_split(train, test_size=0.2, random_state=23)

要使用 z 得分方法对训练数据进行规范化,我们需要知道所有训练特征的平均值和标准差。我是这样得到它的:

train_stats = train.describe()
train_stats= train_stats.transpose()
train_stats

还有额外的信息,但平均值和标准差也在那里。

该范数函数获取数据,并使用我们在上一步中获得的平均值和标准差对其进行归一化处理:

def norm(x):
    return (x - train_stats['mean']) / train_stats['std']

让我们标准化训练、测试和验证数据:

train_x = norm(train)
test_x = norm(test)
val_x = norm(val)

在本练习中,汽车的价格将用作目标变量,其余变量用作训练特征。

train_x = train_x.drop(columns='price')
test_x = test_x.drop(columns='price')
val_x=val_x.drop(columns='price')train_y = train['price']
test_y = test['price']
val_y = val['price']

训练和目标变量准备好了。

自定义损失和自定义图层

先说损失函数,大家都知道。这就是均方根误差。我们将它定义为一个函数,并在编译模型时传递该函数。

def rmse(y_true, y_pred):
    return K.sqrt(K.mean(K.square(y_pred - y_true)))

看起来很眼熟吧?让我们把这个函数放在手边,以备后用。你可以尝试许多其他种类的损失函数。

现在,转到自定义层。同样,我们将使用简单的线性公式 Y=WX+B 作为公式。该公式要求权重是 X 和偏差的系数(在公式中表示为“B”)。在您看到代码后,我会更详细地解释这一点:

class SimpleLinear(Layer):def __init__(self, units=64, activation=None):
        super(SimpleLinear, self).__init__()
        self.units = units
        self.activation=tf.keras.activations.get(activation)def weightsAndBias(self, input_shape):
        w_init = tf.random_normal_initializer()
        self.w = tf.Variable(name="kernel",
            initial_value=w_init(shape=(input_shape[-1], self.units),
                                 dtype='float32'),
            trainable=True)b_init = tf.zeros_initializer()
        self.b = tf.Variable(name="bias",
            initial_value=b_init(shape=(self.units,), dtype='float32'),
            trainable=True)def call(self, inputs):
        return self.activation(tf.matmul(inputs, self.w) + self.b)

在上面的代码中,我们从传递单元和激活作为参数开始。这里我使用的单位是 64,这意味着 64 个神经元。我们将最终在模型中指定不同数量的神经元。这里没有激活。我们也将在模型中使用激活。

在上面的“权重和偏差”中,我们初始化权重和偏差,其中权重初始化为随机数,偏差初始化为零。

在调用函数中,我们使用矩阵乘法(matmul 方法执行矩阵乘法)将输入和权重相乘,并添加偏差(记住公式 wx+b)

这是最基本的一条。请随意尝试一些非线性层,可能是二次或三次公式。

模型开发

模型开发是比较简单的部分。我们有 24 个变量作为训练特征。所以输入形状是(24,)。以下是完整的模型:

model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(24,)),
    SimpleLinear(512, activation='relu'),
    tf.keras.layers.Dropout(0.2),
    SimpleLinear(256, activation='relu'),
    SimpleLinear(128, activation='relu'),
    tf.keras.layers.Dense(1, activation='relu')
])

正如你所看到的,我们简单地称我们之前定义的简单线性方法为层。 512、256 和 128 是单位,激活是“relu”

不过也可以使用自定义激活方法,这将在下一部分中介绍。

让我们编译模型并使用我们之前定义的损失函数“rmse ”:

model.compile(optimizer='adam',
              loss = rmse,
              metrics=tf.keras.metrics.RootMeanSquaredError())
h = model.fit(train_x, train_y, epochs=3)
model.evaluate(val_x, val_y)

输出:

Epoch 1/3
4/4 [==============================] - 0s 3ms/step - loss: 13684.0762 - root_mean_squared_error: 13726.8496
Epoch 2/3
4/4 [==============================] - 0s 3ms/step - loss: 13669.2314 - root_mean_squared_error: 13726.8496
Epoch 3/3
4/4 [==============================] - 0s 3ms/step - loss: 13537.3682 - root_mean_squared_error: 13726.8496

在下一部分中,我们将实验一些自定义的激活函数。

自定义激活功能

我将在这里解释使用自定义激活功能的两种方法。第一个是使用λ层。lambda 层定义了该层中的函数。

例如,在下面的模型中,lambda 层获取 SimpleLinear 方法的输出,并获取其绝对值,因此我们不会得到任何负值。

model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(24,)),
    SimpleLinear(512),
    tf.keras.layers.Lambda(lambda x: tf.abs(x)),
    tf.keras.layers.Dropout(0.2),
    SimpleLinear(256),
    tf.keras.layers.Lambda(lambda x: tf.abs(x)),
    tf.keras.layers.Dense(1),
    tf.keras.layers.Lambda(lambda x: tf.abs(x)),
])

请随意尝试 lambda 层中的任何其他类型的操作。

您不必在 lambda 层本身定义操作。它可以在函数中定义,并传递给 lambda 层。

这是一个获取数据并求平方的函数:

def active1(x):
    return x**2

现在,这个函数可以像这样简单地传递给 lambda 层:

model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(24,)),
    SimpleLinear(512),
    tf.keras.layers.Lambda(active1),
    tf.keras.layers.Dropout(0.2),
    SimpleLinear(256),
    tf.keras.layers.Lambda(active1),
    tf.keras.layers.Dense(1),
    tf.keras.layers.Lambda(active1),
])

根据您的项目和需求,可以使用许多其他不同的功能。

结论

Tensorflow 可以如此动态地使用。有很多不同的方法可以操纵它。在这篇文章中,我想分享一些让 Tensorflow 更加灵活的方法。我希望它是有帮助的,并且你在你自己的项目中尝试它。

欢迎在推特上关注我,并喜欢我的脸书页面。

更多阅读

</30-very-useful-pandas-functions-for-everyday-data-analysis-tasks-f1eae16409af>

如何在 Python 类中定义非公共方法

原文:https://towardsdatascience.com/how-to-define-nonpublic-methods-in-a-python-class-f477a1ddf3c0

使用 Python 作为 OOP 的惯用方法

妮娜·梅尔卡多在 Unsplash 拍摄的照片

从本质上讲,Python 是一种面向对象的编程(OOP)语言,它围绕对象构建自己的特性。字符串是对象,自定义类的实例是对象,类、模块甚至包也是对象。OOP 编码中的一个长期原则是封装——在这种设计模式中,您公开用户需要的功能,同时隐藏用户不需要访问的实现细节。

对于任何项目,我们都定义了一系列定制类作为建模各种数据的基础。因此,一个好的项目意味着你定义了结构良好的定制类。当我们处理这些类时,我们应该应用封装技术。虽然我不认为我们应该把封装当作教条,但是您可以考虑两个特殊的封装特性来增加您项目的可维护性— protected private 方法,它们旨在供内部使用。本文将向您展示如何做到这一点。

介绍

你们中的一些人可能知道,在一些 OOP 语言中,我们为封装保留了关键字,例如 protected、private 和 public,它们定义了如何在类外访问属性(或方法)。然而,Python 没有这些关键字,这是因为严格来说,Python 类中定义的一切都是公共的。也就是说,如果你愿意,你可以访问一个类中的任何东西。

尽管如此,Python 中仍然有一些封装约定。为了便于讨论,我们将使用通用 OOP 领域的术语。在访问级别控制方面,属性和方法没有区别。所以,我们只是用方法来演示相关的技术。

定义受保护的方法

我们可以在 Python 中定义受保护的属性。惯例是在方法名前使用下划线。让我们考虑下面的例子:

class User:
    def __init__(self,username) -> None:
        self.username = username def login(self):
        print(f"{self.username} just logged in.") def signup(self):
        self._check_account_existence()
        print(f"{self.username} just signed up an account.") def _check_account_existence(self):
        print(f"Checking if {self.username} has signed up already.")

在这个User类中,signup方法是公共的,而_check_account_existence方法是受保护的。因为这个方法不是公共的,所以当我们使用User类的实例时,它不包含在自动完成提示中:

自动完成提示不包括受保护的方法(作者截图)

如您所见,该列表只包括signup,而不包括_check_account_existence方法。值得注意的是,如果您确实调用了这个受保护的方法,您仍然可以这样做:

>>> user = User("cowboy")
>>> user._check_account_existence()
Checking if cowboy has signed up already.

原因是,正如我前面所说的,Python 对类的方法没有严格的访问控制,它只是一个约定,在方法名前面加上前缀以表明(不是 enforce )它是一个受保护的方法。

定义私有方法

另一种封装技术是关于定义私有方法的。您可以使用两个下划线作为方法名的前缀,而不是使用一个下划线,以表明它是一个私有方法。观察下面的例子:

class User:
    def __init__(self,username) -> None:
        self.username = username

    def signup(self):
        self._check_account_existence()
        print(f"{self.username} just signed up an account.")

    def _check_account_existence(self):
        print(f"Checking if {self.username} has signed up already.")

    def login(self):
        print(f"{self.username} just logged in.")
        self.__pull_data_after_login()

    def __pull_data_after_login(self):
        print(f"Pull additional data for the user: {self.username}")

User类中,__pull_data_after_login是一个私有方法。同样,这个私有方法也不会进入自动完成提示列表。

自动完成提示不包括私有方法(作者截图)

我之前提到过,如果我们愿意,我们可以访问类外的非公共方法,并且我们看到我们可以使用受保护的方法。它也适用于私有方法吗?

>>> user = User("cowboy")
>>> user.__pull_data_after_login()
# AttributeError: 'User' object has no attribute '__pull_data_after_login'

错误是否意味着我们不能访问类外的私有方法?不完全是。访问类外的私有方法需要了解名称篡改的概念,如果从外部访问,私有方法会有一个被篡改的名称。具体来说,它有这个规律:__private_method->-T5。因此,我们可以这样访问__pull_data_after_login:

>>> user = User("cowboy")
>>> user._User__pull_data_after_login()
Pull additional data for the user: cowboy

使用非公开方法的好处

从这些截图中,您可以看到,通过隐藏非公共(受保护的和私有的)方法,您正在帮助代码的用户提高编码效率,因为他们不需要担心选择一个他们无论如何都不应该使用的非公共方法。

值得注意的是,这些方法在类内部仍然可用。下图显示了自动完成提示理解这些非公共方法的可访问性。

对非公共方法的内部访问(作者截图)

封装只适用于类外的代码。当您在类内部工作时,如上图所示,我们仍然可以从自动完成提示列表中选择非公共方法。

受保护方法和私有方法之间的其他区别

当我们在它们各自的部分中介绍受保护的和私有的方法时,我们隐含地展示了受保护的和私有的方法之间的两个区别。

  • 受保护的方法使用一个下划线作为前缀,而私有方法使用两个下划线作为前缀。
  • 我们可以通过使用方法名直接在类外调用受保护的方法。然而,调用私有方法需要名字混淆。

除了 protected 和 private 方法之间的这两个明显区别之外,这两种方法之间的主要区别在于它们在子类中的可访问性。也就是说, protected 方法在子类内是可访问的,而 private 方法在子类内是不可访问的(虽然原因也是因为名字 mangling)。考虑下面的例子。

class Administrator(User):
    def admin_signup(self):
        super()._check_account_existence()

    def admin_login(self):
        super().__pull_data_after_login() >>> admin = Administrator("rodeo")>>> admin.admin_signup()
Checking if rodeo has signed up already.>>> admin.admin_login()
**# AttributeError**: 'super' object has no attribute '_Administrator__pull_data_after_login'

如上所示,在Administrator类中,我们使用超类的 protected 和 private 方法来定义admin_signupadmin_login。当我们使用这两种方法时,只有admin_signup有效,而admin_login无效。原因是私有方法使用当前类的名称自动触发名称篡改。尽管我们的目的是使用超类的私有方法,但它们在子类中并不容易获得。

因此,如果你想定义非公共方法,并且不想让它们在子类中被访问,你应该使用私有方法。否则,您应该使用受保护的方法,使它们可以在子类中访问。

结论

在本文中,我们回顾了在 Python 类中定义受保护方法和私有方法的技术。这些技术属于一个重要的 OOP 概念——封装。虽然 Python 不使用 protected 或 private 作为关键字,但是您应该遵守我们使用下划线作为这些非公共方法前缀的惯例。

如果你想了解更多关于 Python 的知识,可以考虑注册我的时事通讯邮件。如果你想系统地提高你的 Python 技能,请阅读我的新书Python How-ToManning。

如何提供真正的数据驱动的洞察力

原文:https://towardsdatascience.com/how-to-deliver-real-data-driven-insights-e94f2b386c18

什么是真正的洞察力,如何发现它们,以及没有发现它们的代价

合著joo Sousa成长总监 atKausaUmesh Ramakrishnan ,数据经理 atTraveloka。**

Freepik 上 pvproductions 的图片

如今,每个人都在寻找真知灼见。阅读任何职位描述分析团队的使命是“产生洞察力”。但是这个任务很暧昧。首先,他们的角色是发现这些见解(即,进行深入分析并传达见解)还是仅仅让企业能够发现它们(即,构建大多数情况下不提供任何真正见解的仪表板)?

其次,洞察力的定义非常模糊,这个术语经常被误用。大多数人把观察称为洞察力。

因此,数据从业者常常对业务没有根据“生成的见解”采取行动感到沮丧。事实上,他们并没有分享真正的见解。这阻碍了团队交付真正的业务价值,浪费了数据和业务团队的时间,使得追求所谓的洞察力非常昂贵。

什么是洞察力?

洞察力不仅仅是在数据中发现一些“有趣”的东西。在仪表板上显示正在发生的事情不是分享见解。在各种各样的描述中,我最喜欢的是布伦特·戴克斯的描述,它集中在三个标准上:

理解上的转变:不仅仅指出观察到的现象或不正常的现象,而且指出造成这种现象的原因

意想不到的原因:不是有意的,但令人惊讶的事情

3)与您/利益相关者关心的事情一致:与业务目标紧密一致

并将其归结为“我们理解事物的方式发生了意想不到的转变,从而激励我们采取行动。”

可悲的是,即使是可行的见解也会被浪费掉。所以我想补充第四个标准:

4)有效沟通

你的观众只有完全掌握了某样东西,才能付诸行动。否则,这种情况可能会让人想起一个哲学思想实验“如果一棵树倒在森林里,周围没有人听到它,它会发出声音吗?”

现在我们有了一个明确的最终目标,你如何能超越观察并提供真正的见解呢?

如何定期发掘洞察力

可行的见解始于一个为什么的问题,而不是什么。

你不会在仪表板或报告上找到任何见解。他们只是监控度量标准,并涵盖高层次的假设(即,通常的嫌疑人)。因此,你只是在测试重复出现的假设,而这些假设只是触及了表面。你需要利用所有可用的数据,而不是只关注一小部分。(查看这篇文章,学习如何打破其他不良分析习惯。)

不知所措的分析师试图使用仪表盘深入分析,图片由 Freepik 上的 DCStudio 提供

关键在于诊断分析。理解业务指标为什么会变化以及是什么驱动了它们,这是提供真正洞察力的方法。首先询问您的关键业务指标的变化如何满足定义的 3 个标准:

  • 是什么导致了业务指标的变化?
  • 我们计划过会发生这种事吗?
  • 它与我们的业务优先级相关吗?

揭示这些真正的见解需要深入探究原因,即试图利用所有可用数据并结合多个因素/维度和相关指标来找到更精细的见解。

现状

让我们用一个例子来说明这一点。假设你是一家电子商务公司的数据分析师,在过去的 3 周里,活跃用户群(即访问你的应用程序/网站的用户)没有增长。增长/营销部门对此表示担忧,并要求您进一步调查。

您知道指标(活跃用户群)及其趋势(即,过去 3 周持平)。我们听说大多数团队会首先检查数据的准确性…当您可以责怪数据质量时,通过挖掘数据的麻烦有什么乐趣呢?

观察

一旦你确认数据是准确的,是时候放下你的思考帽,想出一套假设了:

  • 按国家和地区细分数字,以比较趋势
  • 检查季节性——像学校假期甚至长周末这样的事件往往会产生前推效应
  • 根据收购月份/渠道等进行群组分析(即新用户与现有用户的对比)

在花了大量时间后,你发现新用户数量(即下载量)下降了,这进一步导致活跃用户在过去几周内持平。
这很有趣,但不是一种洞见。它只是部分地回答了这个问题,业务团队没有任何具体的行动可以据此采取。你需要深入挖掘真正的洞察力。

真正的洞察力

经过头脑风暴,你已经确定了一些额外的假设,关于为什么新用户可能会下降。经过多次分析后,你发现在过去几周内,某个特定搜索词的转化率下降了。这是一个很好的发现,但仍不完整。为了缩小差距,你分析了 app/android 商店上的特定搜索词,发现你的竞争对手正在为这个词开展广告活动。竞争对手正在夺走你的产品。

是的——现在,您已经找到了一种对您的营销团队真正可行的见解。现在,他们可以反击这场运动,带回应用安装数量。

反应式方法的含义

你终于找到了洞察力。然而,这花了很长时间,而且你是在竞争对手发起新的广告活动后 1 个月才发现的。在上个月,您失去了许多活跃用户,这对业务绩效产生了重大影响。

实现数据价值最大化需要主动性。不采取行动,直到你观察到你的仪表板急剧下降,然后花几天时间进行根本原因分析可能会非常昂贵。

理想情况下,数据团队不会等待增长/营销领导来询问为什么会出现这种情况,而是主动分享见解和建议。在这种情况下,可以更早采取行动,将损失降至最低,并迅速采取行动将结果转化为积极的业务影响。

为什么大多数团队没有发现真正的洞察力

最先进的数据团队主动跟踪指标并调查变化,以分享见解和建议。但是许多团队仍然是非常描述性的(例如,发生了什么),只识别高层次的趋势,而忽略了诊断分析。正如我在文章“诊断分析差距”中所探讨的,许多原因导致了这种情况。

诊断分析差距背后的 4 个要素(图片由 Kausa 提供)

如何缩小这一差距

弥合这一差距需要积极主动的“全面诊断分析”(详见文章)。关注哪里取决于每个元素(文化、人员、工具、流程)的起点。简而言之:

  • 文化:提倡一种深入探究原因的数据文化,而不是停留在业务主导的高层次假设上(例如,典型的答案——这是季节性的,这是因为新的营销活动)。确保业务和数据利益相关方保持一致,以推动管理层参与的计划。
  • 人员:将分析师嵌入业务团队,以发展业务和领域专长。促进数据和业务团队之间的紧密协作。创建对最重要用例/指标的共同理解,让分析师主动分享见解。
  • 工具:考虑决策智能平台来增强现有工作流,以运行全面快速的分析,使团队能够主动了解指标变化,并分享数据驱动的见解和建议。
  • 流程:回顾当前的诊断分析流程。确保团队有一致的方法和途径来执行根本原因分析。开发在数据和业务团队之间共享见解和建议的最佳实践。

底线:

发现导致理解转变并与业务成果联系起来的意外原因的团队通过以下方式做到了这一点:

  • 在业务和数据团队之间建立强大的协作
  • 通过利用所有可用数据、综合考虑多个维度并考虑相关指标,深入探究原因
  • 制定清晰的流程,说明如何传播这些见解并迅速采取行动。

想法?把手伸向 若昂索萨成长总监考萨或* 乌米什罗摩克里希南 ,数据经理Traveloka*。我们希望收到您的来信。我们的目标是分享我们的集体经验,让数据团队能够产生更大的业务影响。**

敬请关注更多关于如何增加数据商业价值的文章&分析。

Umesh Ramakrishnan 的说明:所表达的观点是我个人的,并不代表我目前的雇主(Traveloka)

参考资料:

  1. Brent Dykes,洞察力素养:为什么我们需要澄清什么是真正的洞察力 (2022),Forbes.com

如何将面板可视化仪表板部署到 GitHub 页面

原文:https://towardsdatascience.com/how-to-deploy-a-panel-visualization-dashboard-to-github-pages-2f520fd8660

部署 Python 数据应用程序的最快方式

由马克·斯科夫·麦德森和索菲亚·杨拍摄

Python 工具使得构建可视化仪表板变得容易,但是在云中使用 Python 服务器来共享它们可能会很困难且昂贵。如果像将文件推送到 GitHub 页面一样简单,不需要运行服务器,会怎么样?现在是了!感谢 HoloViz 团队,特别是 Philipp Rudiger ,有了新的 Panel 0.14 版本,你可以完全在你的浏览器中运行 Panel data 应用,不需要服务器!

这是目前在 Python 中部署应用程序的最快方式。这些应用程序在加载时性能非常好,因为服务器和客户端之间的通信没有延迟。

在 WebAssembly 中运行仪表板(通过 Pyodide 和 PyScript)是 Python 中 dataviz 的未来。

在本文中,我们将向您展示如何在 Github 页面上轻松部署 Panel 应用程序,并与全世界分享您的应用程序!

什么是面板?

Panel 是开源 HoloViz 生态系统中的仪表板库,包括八个库:Panel、hvPlot、HoloViews、GeoViews、Datashader、Lumen、Param 和 Colorcet,由 Philipp Rudiger、Jim Bednar 和一个贡献者社区开发。查看我们之前关于构建面板仪表盘的三种主要方法的博客文章,了解更多信息。

如何将面板可视化仪表盘部署到 GitHub 页面?

  • 步骤 0:设置环境

您需要安装最新版本的 Panel:

conda install panel hvplot -c pyviz

检查以确保您的面板至少是 0.14.0:

conda list panel
  • 第一步:将面板应用程序转换为 web assembly

如果您有一个面板应用程序文件 app.py,您可以使用一行代码将现有的面板应用程序转换为 WebAssembly:

panel convert app.py --to pyodide-worker --out docs/app

步骤 1 将把你的代码写入一个 HTML 文件和一个 JS 文件。pyodide-worker被指定使用在单独线程中运行的 Pyodide 来生成这两个文件,以提高性能。这两个文件都在 docs/文件夹下。底层技术是web assemblyPyodidePyScript 。查看Panel web assembly 文档pyscript.net、以及我们之前在 PyScript 上发布的博客来了解更多信息。

  • 第二步:向 GitHub 添加文件
git add docs/*git commitgit push
  • 第三步:设置 GitHub 页面

将创建的文件添加到 GitHub 后,可以从 main /docs 在 GitHub 设置-页面-构建部署中配置 GitHub 页面。

一个 hello world 的例子

代码:https://github . com/awesome-panel/examples/blob/main/src/hello-world/app . py

GitHub 页面:https://awesome-panel . GitHub . io/examples/hello-world/app . html

在第一个 hello world 示例中,我们有一个简单的面板应用程序文件 app.py ,它使用面板模板并显示一个句子。

自己试一试:

  • 叉本资源库:https://github.com/awesome-panel/examples
  • Git 克隆您的分叉存储库
  • 设置 Conda 环境,并通过conda install panel hvplot -v pyviz安装最新的面板
  • 你可以panel convert例如通过 WebAssembly 的 hello-world 应用程序
panel convert src/hello-world/app.py --to pyodide-worker --out docs/hello-world
  • 上面的panel convert命令在 docs/hello-world 文件夹中创建了两个文件:app.html 和 app.js。将这两个文件都添加到 GitHub(按照上面的步骤 2),并使用主分支和/docs 文件夹设置 GitHub 页面(参见上面的步骤 3)。几分钟后,你会看到这个应用出现在 Github 页面(你会从自己的分叉回购中获得一个新的 Github 页面链接)。

可选步骤:

  • 要在本地提供 Panel 应用程序,您可以通过panel serve src/hello-world/app.py -autoload在 Panel 服务器上提供 hello-world 应用程序。将于 http://localhost:5006/app 发售。
  • 在 panel convert 步骤中,如果你想避免一遍又一遍地重复大下载,你甚至可以转换成可以安装在笔记本电脑上的渐进式 web 应用程序!它就像添加— pwa 和— title 标志一样简单。
  • 在本地提供 WebAssembly 应用程序:
python3 -m http.server

该应用程序现已在http://localhost:8000/docs/hello-world/app . html上发布

交互式数据框架仪表板示例

代码:https://github.com/sophiamyang/hvplot_interactive

GitHub 页面:

https://sophiamyang . github . io/HV plot _ interactive/HV plot _ interactive . html

之前,我们发布了一篇详细的博文和一个视频教程,讲述了用 Python 创建交互式仪表盘的最简单方法。通过类似的步骤,我们可以将这个应用程序转换为 WebAssembly,并将其部署在 Github 页面上。

请注意,Panel 应用程序文件可以是. py 文件或. ipynb 笔记本文件。在这个例子中,我们的面板应用程序文件是HV plot _ interactive . ipynb

要将此应用程序部署到 Github 页面:

  • 我们使用panel convert将这个应用程序转换为 WebAssembly
panel convert hvplot_interactive.ipynb --to pyodide-worker --out docs
  • 然后,我们按照本文开头的步骤 2 将创建的文件添加到 Github。
  • 最后,我们按照步骤 3 来设置 GitHub 页面。

然后我们可以在 Github 页面上找到我们的应用。

流媒体仪表盘示例

代码:https://github . com/awesome-panel/examples/blob/main/src/streaming-indicators/app . py

Github 页面:https://awesome-panel . github . io/examples/streaming-indicators/app . html

通过同样的步骤,我们甚至可以在 GitHub 页面上部署一个实时流仪表板!

您可以从哪里了解更多信息?

希望这篇文章对你有帮助!如果你有问题或者想联系其他 HoloViz 用户,请查看 https://discourse.holoviz.org/。

鸣谢:

感谢 Jim Bednar 和 Phillipp Rudiger 的指导和反馈!

参考文献:

. . .

马克·斯科夫·麦德森索菲亚·杨于 2022 年 10 月 6 日。

Sophia Yang 是 Anaconda 的高级数据科学家。在 LinkedInTwitterYouTube 上与我联系,并加入 ds/ml❤️读书俱乐部

如何将 Scikit-Learn 模型部署到 Azure 容器实例

原文:https://towardsdatascience.com/how-to-deploy-scikit-learn-models-to-azure-container-instances-a0a59d0d07a1

使用 Azure 容器实例生产您的 Scikit-Learn 模型

1.介绍

现在你已经训练了你的 scikit-learn 模型,下一步是什么?如何将它作为 API 提供给下游应用程序?在本文中,我们将研究如何使用 MLFlow、Azure 机器学习和 Azure 容器实例将 scikit-learn 模型作为 API 进行训练和部署。以下是我们将使用的服务的简要描述。

SpaceXUnsplash 上拍摄的照片

什么是 MLFlow?

ML flow【1】是一个管理 ML 生命周期的开源平台,包括实验、可复制性、部署和中央模型注册。MLFlow 提供 4 种不同的组件:

  1. MLFlow Tracking: 记录和查询实验:代码、数据、配置和结果
  2. MLFlow 项目:将数据科学代码打包成可在任何平台上运行的格式
  3. MLFlow 模型:在不同的服务环境中部署机器学习模型
  4. 模型注册:在中央存储库中存储、注释、发现和管理模型

我们将使用 MLFlow 跟踪功能来记录机器学习实验的参数、结果和工件。

什么是 Azure 机器学习?

Azure 机器学习 [2]是微软 Azure 云计算平台的一部分,帮助数据科学家和工程师管理他们的机器学习工作流程。

什么是 Azure 容器实例?

Azure Container Instances(ACI)[3]是微软 Azure 的托管服务,它允许我们运行负载平衡的容器化服务,并具有带 REST API 的 HTTP 端点。

2.安装 Azure

Azure 帐户

我们将使用 Azure ML 和 ACI,因此 Azure 帐户是强制性的。注册一个免费的 Azure 帐户,如果你是新用户,头 30 天可以获得 200 美元的信用点数。

Azure 机器学习工作区

工作区[4]是 Azure 机器学习的顶级资源,提供了一个集中的地方来处理您在使用 Azure 机器学习时创建的所有工件。工作区保存了所有训练运行的历史,包括日志、指标、输出和脚本的快照。您可以使用这些信息来确定哪一次训练能够产生最佳模型。

资源组是创建 Azure 机器学习工作空间的先决条件。

1。创建资源组

资源组是保存 Azure 解决方案相关资源的容器。

作者图片

  • 创建新的资源组

作者图片

  • 填写详细信息,如订阅、资源组名称和区域

作者图片

2。创建 Azure ML 工作区

  • 在 Azure Services 下或者通过搜索栏找到“机器学习”。

作者图片

  • 点击创建

作者图片

  • 填空。资源组是我们在上一步中创建的。

作者图片

  • MLFlow 跟踪服务器是作为 Azure ML 工作区的一部分自动创建的

3.设置培训环境

IDE

我使用的是 Visual Studio 代码,但是你可以使用任何你选择的 IDE

康达环境

确保您的机器上安装了 miniconda3。从命令行界面创建 python 3.7 conda 环境。环境名是任意的,我将其命名为general

#command line 
conda create -n general python=3.7

激活康达环境。我们将在这种环境下进行所有的开发工作。

#command line
conda activate general

安装必要的软件包

azureml-core==1.39
pandas==1.3.5
scikit-learn==0.23.2
cloudpickle==2.0.0
psutil==5.9.0
mlflow==1.24.0

码头工人

您的本地机器上需要 Docker,因为我们将在本地部署 webservice 作为 docker 容器,以便在将其部署到 Azure 容器实例之前进行调试。

Azure 机器学习工作区配置

下载 Azure 机器学习工作区配置。

作者图片

配置文件采用 JSON 格式,包含以下信息:

# config.json{
    "subscription_id": "your-subscription-id",
    "resource_group": "your-resource-group-name",
    "workspace_name": "your-workspace-name"
}

我们将需要这些信息来连接到 AML workspace 以记录实验。

项目结构

这些是项目文件夹中的笔记本和脚本。我们将在下一节中逐一介绍。

  • train.ipynb:实验的预处理、训练和记录
  • register_model.ipynb:向 Azure ML 注册模型和环境
  • test_inference.ipynb:调用带有样本数据的 web 服务(本地或 ACI)进行测试
  • local_deploy.ipynb:使用 Docker 在本地部署模型
  • aci_deploy.ipynb:模型部署到 ACI
  • score.py:用于推理的模型的输入脚本
  • conda.yaml:包含创建推理环境的依赖关系

4.项目演练

该示例带我们完成了以下步骤:

  • 在本地训练 scikit-learn 模型
  • 在 Azure 机器学习上跟踪 MLFlow 的 scikit-learn 实验
  • 在 Azure 机器学习上注册模型
  • 将模型作为本地 web 服务进行部署和测试
  • 将模型作为 ACI 服务进行部署和测试

我们将使用来自国家糖尿病、消化和肾脏疾病研究所的 Pima 印度糖尿病数据集[5]。数据集的目的是基于数据集中包含的某些诊断测量结果,诊断性地预测患者是否患有糖尿病。数据集由几个医学预测变量和一个二元目标变量Outcome组成。预测变量包括患者的怀孕次数、身体质量指数、胰岛素水平、年龄等。

作者图片

4.1.培训 sci kit-学习模型

本节中的所有代码都在train.ipynb中。

导入包

import mlflow
from azureml.core import Workspace
import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import FunctionTransformer
from sklearn.impute import SimpleImputer

设置工作空间

ws = Workspace.from_config()

运行此单元后,您可能会得到一个 URL 来执行 web 身份验证。这是连接到 Azure 机器学习工作区所必需的。完成后,您可以返回 IDE 并继续下一步。

设置跟踪 URI

MLFlow 跟踪 URI 是我们可以找到 MLFlow 跟踪服务器的地址。我们设置跟踪 URI 来让 MLFlow 知道在哪里记录实验。

mlflow.set_tracking_uri(ws.get_mlflow_tracking_uri())

跟踪 URI 的格式如下

azureml://<region>.api.azureml.ms/mlflow/v1.0/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.MachineLearningServices/workspaces/<aml-workspace>?

设置 MLFlow 实验

下面的代码定义了 MLFlow 实验的名称。MLFlow 实验是组织不同运行的一种方式。一个实验包含多次运行,每次运行都是训练代码的一次执行。我们可以为每次运行定义要存储的参数、结果和工件。如果实验名称不存在,将创建一个新的实验,否则它会将运行记录到同名的现有实验中。

experiment_name = 'diabetes-sklearn'
mlflow.set_experiment(experiment_name)

加载数据集

input_path = 'path\\to\\data.csv'df = pd.read_csv(input_path, sep = ',')y = df.pop('Outcome')
X = dfX_train, X_test, y_train, y_test = train_test_split(X, y)

预处理

def change_type(x): x = x.copy()
    for col in ['Pregnancies', 'Glucose', 'BloodPressure', 'SkinThickness', 'Insulin', 'Age']:
        x[col] = x[col].astype('float') return xdef replace_zeros(x): x = x.copy()
    x[['Glucose','BloodPressure','SkinThickness','Insulin','BMI']] = x[['Glucose','BloodPressure','SkinThickness','Insulin','BMI']].replace(0,np.NaN) return xft_change_type = FunctionTransformer(change_type)
ft_replace_zeros = FunctionTransformer(replace_zeros)
num_imputer = SimpleImputer()

我们创建了两个 scikit-learn FunctionTransformer,用于将所选列的数据类型更改为 float,并用 NaN 替换零值。

创建一个 scikit-learn 管道

rf_clf = RandomForestClassifier()
pipe = Pipeline([('change_type', ft_change_type), ('replace_zeros', ft_replace_zeros), ('fillna', num_imputer), ('clf', rf_clf)])

超参数调谐

mlflow.sklearn.autolog(max_tuning_runs=None)param_grid = {'clf__n_estimators': [10,20,30], 'clf__max_depth':[2,7,10]}clf = GridSearchCV(pipe, param_grid = param_grid, scoring = ['roc_auc', 'precision', 'recall', 'f1', 'accuracy'], refit = 'roc_auc')
clf.fit(X_train, y_train)

记录的结果可以在 Azure ML 实验中找到。

作者图片

最佳模型的模型工件和run_id可以在Outputs + logs选项卡中找到。

作者图片

  • model.pkl是包含 scikit-learn 模型对象的文件。这个模型的文件路径是best_estimator/model.pkl,我们将在下一步中需要模型注册的路径。
  • conda.yamlrequirements.txt包含训练模型所需的 conda 和 pip 包。
  • run_id:ml flow 运行的唯一标识符。我们将在下一步中使用它来检索模型文件。

4.2.注册模型

将模型注册到 Azure Machine Learning 的模型注册中心的目的是让用户能够通过模型版本控制来跟踪模型的变化。以下代码写在register_model.ipynb笔记本上。

检索实验

我们通过定义工作区和实验名称从工作区中检索实验。

from azureml.core import Experiment, Workspaceexperiment_name = 'diabetes-sklearn'ws = Workspace.from_config()
experiment = Experiment(ws, experiment_name)

检索运行

使用上一节中获得的run_id从实验中检索运行。

run_id = 'e665287a-ce53-41f9-a6c1-d0089a35353a'
run = [r for r in experiment.get_runs() if r.id == run_id][0]

注册型号

model = run.register_model(model_name = 'diabetes_model', model_path = 'best_estimator/model.pkl')
  • model_name:赋予注册型号的任意名称
  • model_path:到model.pkl文件的路径

我们可以在 Azure 机器学习的“模型”选项卡中找到注册的模型。将模型文件注册到相同的模型名称会创建不同版本的模型。

作者图片

我们可以通过单击模型名称来查看模型的最新版本的详细信息。详细信息包括生成模型的实验名称和运行 id,这对于维护数据链非常有用。

作者图片

4.3.创建评分脚本

通常称为score.py的评分脚本在推理过程中用作模型的入口点。

score.py由两个强制功能组成:

  1. init():将模型作为全局变量加载
  2. run():通过data参数
    接收待评分的新数据 a .对新数据进行预处理
    b .对新数据进行预测
    c .对预测进行后处理
    d .返回预测结果
# score.pyimport json
import os
import joblib
import pandas as pddef init():
    global model
    model_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'model.pkl')
    model = joblib.load(model_path)def run(data):
    test_data = pd.DataFrame(json.loads(json.loads(data)['input']))
    proba = model.predict_proba(test_data)[:,-1].tolist()
    return json.dumps({'proba':proba})

4.4.本地部署

在本节中,我们将在部署到 ACI 之前在本地调试 webservice。代码写在local_deploy.ipynb中。

定义工作空间

from azureml.core import Workspace
ws = Workspace.from_config()

检索模型

通过定义工作空间、模型名称和模型版本来检索注册的模型。

from azureml.core.model import Model
model = Model(ws, 'diabetes_model', version=5)

创建自定义推理环境

在训练模型时,我们已经将环境依赖性作为一个conda.yaml文件记录到 MLFlow 中。我们将使用这个文件来创建一个定制的推理环境。

作者图片

conda.yaml文件下载到您的项目文件夹中,并在pip依赖项下添加azureml-defaults以及推理过程中需要的任何其他依赖项。下面是conda.yaml现在的样子。

# conda.yamlchannels:
- conda-forge
dependencies:
- python=3.7.11
- pip
- pip:
  - mlflow
  - cloudpickle==2.0.0
  - psutil==5.9.0
  - scikit-learn==0.23.2
  **- pandas==1.3.5
  - azureml-defaults**
name: mlflow-env

接下来,我们用来自conda.yaml文件的依赖项创建一个名为diabetes-env的 Azure ML 环境,并将其注册到 Azure ML Workspace。

from azureml.core import Environment
env = Environment.from_conda_specification(name='diabetes-env', file_path="./conda.yaml")
env.register(ws)

我们可以在“自定义环境”下的 Azure 机器学习“环境”选项卡中查看注册的环境。

作者图片

定义推理配置

这里我们定义了环境和评分脚本。

from azureml.core.model import InferenceConfig
inference_config = InferenceConfig(
    environment=env,
    source_directory=".",
    entry_script="./score.py",
)

定义部署配置

from azureml.core.webservice import LocalWebservice
deployment_config = LocalWebservice.deploy_configuration(port=6789)

部署本地 web 服务

在运行下面的单元之前,确保 Docker 正在您的本地机器上运行。

service = Model.deploy(
    workspace = ws,
    name = 'diabetes-prediction-service',
    models = [model],
    inference_config = inference_config,
    deployment_config = deployment_config,
    overwrite=True)

service.wait_for_deployment(show_output=True)

model.pkl文件将从 Azure Machine Learning 下载到一个临时的本地文件夹中,一个带有依赖关系的 docker 映像将被创建并注册到 Azure Container Registry (ACR)中。该映像将从 ACR 下载到本地机器上,运行 webservice 的 docker 容器将从该映像本地构建。下面显示了成功部署的输出消息。

作者图片

我们可以使用以下公式获得得分 URI:

print (service.scoring_uri)>> '<http://localhost:6789/score>'

这是我们将向其发送评分请求的 URI。

4.5.测试本地 web 服务

在本节中,我们将测试本地 web 服务。代码是用inference_test.ipynb写的。

import requests
import json
import pandas as pdlocal_deployment = True
scoring_uri = '<http://localhost:6789/score>'
api_key = None
input_path = 'path/to/data.csv'# load the data for testing
df = pd.read_csv(input_path, sep = ',')
y = df.pop('Outcome')
X = df
input_data = json.dumps({'input':X.head(1).to_json(orient = 'records')})if local_deployment:
    headers = {'Content-Type':'application/json'}
else:
    headers = {'Content-Type':'application/json', 'Authorization':('Bearer '+ api_key)}
resp = requests.post(scoring_uri, input_data, headers=headers)print("prediction:", resp.text)

我们向scoring_uri发送了 post 请求以及 JSON 格式的数据。下面是input_data的样子:

'{"input": "[{\\\\"Pregnancies\\\\":6,\\\\"Glucose\\\\":148,\\\\"BloodPressure\\\\":72,\\\\"SkinThickness\\\\":35,\\\\"Insulin\\\\":0,\\\\"BMI\\\\":33.6,\\\\"DiabetesPedigreeFunction\\\\":0.627,\\\\"Age\\\\":50}]"}'

下面是对单个记录进行推断的响应示例。返回值包含被诊断为糖尿病的人的概率。

>> "{\\"proba\\": [0.6520730332205742]}"

以下是对 3 条记录的推断的示例响应。

>> "{\\"proba\\": [0.5379796003419955, 0.2888339011346382, 0.5526596295928842]}"

响应格式可以在score.py文件的run功能中自定义。

终止本地 web 服务

通过使用命令提示符终止 Docker 容器来终止 webservice。

# CLI
docker kill <container id>

4.6.部署到 Azure 容器实例

在本地成功测试该模型后,就可以部署到 ACI 了。部署步骤类似于本地部署。在aci_deploy.ipynb笔记本中:

from azureml.core import Workspace
ws = Workspace.from_config()from azureml.core.model import Model
model = Model(ws, 'diabetes_model', version=5)from azureml.core import Environment
env = Environment.get(workspace = ws, name = 'diabetes-env', version = 1)
  • 定义工作空间
  • 从模型注册表中检索模型
  • 检索我们以前从环境注册表中注册的环境

定义推理配置

from azureml.core.model import InferenceConfig
inference_config = InferenceConfig(
    environment=env,
    source_directory=".",
    entry_script="./score.py")

定义部署配置

from azureml.core.webservice import AciWebservice
deployment_config = AciWebservice.deploy_configuration(cpu_cores=0.1, memory_gb=0.5, auth_enabled=True)

我们向 ACI 服务分配资源,如cpu_coresmemory_gb。当auth_enabledTrue时,调用 API 时,web 服务需要一个认证密钥。

部署 ACI Webservice

service = Model.deploy(
    workspace = ws,
    name = 'diabetes-prediction-service',
    models = [model],
    inference_config = inference_config,
    deployment_config = deployment_config,
    overwrite=True)

service.wait_for_deployment(show_output=True)

当部署成功时,将显示以下消息:

>> ACI service creation operation finished, operation "Succeeded"

要得到得分的 URI:

print (service.scoring_uri)>> <http://7aa232e8-4b0b-4533-8a84-13f1ad3e350a.eastus.azurecontainer.io/score>

要获取身份验证密钥:

print (service.get_keys())>> ('MbrPwtQCkQqGBVcg9SjKCwJjsL3FMFFN', 'bgauLDXRyBMqvL7tBnbLAgTLtLMP7mqe')

或者,我们也可以从 Azure 机器学习的“端点”选项卡中获取评分 URI 和认证密钥。

作者图片

4.7.测试 ACI 服务

部署完模型后,让我们再次使用inference_test.ipynb来测试 ACI webservice。更改以下参数,其余代码与本地测试相同。

local_deployment = False
scoring_uri = '<http://7aa232e8-4b0b-4533-8a84-13f1ad3e350a.eastus.azurecontainer.io/score>'
api_key = 'MbrPwtQCkQqGBVcg9SjKCwJjsL3FMFFN'

ACI 的价格表可在这里找到。

5.摘要

在本文中,我们研究了以下内容:

  • 在本地训练 scikit-learn 模型
  • 在 Azure 机器学习上跟踪 MLFlow 的 scikit-learn 实验
  • 在 Azure 机器学习上注册模型
  • 将模型作为本地 web 服务进行部署和测试
  • 将模型作为 ACI 服务进行部署和测试

ACI 建议用于测试或小型生产工作负载。对于大型工作负载,请查看如何部署到您的模型 Azure Kubernetes 服务

6.参考

[1] MLFlow

[2] Azure 机器学习

[3] Azure 容器实例

[4] Azure 机器学习工作区

[5] 皮马印第安人糖尿病数据集,特许 CC0 公共领域

如何以 3 种不同的方式在 C++中部署张量流模型

原文:https://towardsdatascience.com/how-to-deploy-tensorflow-models-in-c-in-3-different-ways-f7e25046be29

这是我过去 4 年来做这件事的总结

由作者制作

介绍

在机器学习项目中,有几种方法可以部署您的最终模型。可以是云部署、移动设备上的部署、嵌入式系统上的部署等。

为此,根据您在日常工作或项目中使用的技术,您可以利用几种编程语言。

在我工作的一些公司中,我们需要在 C++环境中部署我们的深度学习模型。这些模型主要处理图像分类和目标检测。

我记得大约 4 年前在 stackoverflow 上问了一个问题,关于我如何在 C++环境中部署 tensorflow 模型。在这 4 年的时间里,我只收到了 2 个答案!

那是我第一次开始研究在 C++环境中部署 tensorflow 模型的不同选项。

我主要尝试了 3 个选项,因为它们看起来最有希望:

  1. 使用 OpenCV DNN 模块部署模型。
  2. 使用 Tensorflow C++ API 部署模型。
  3. 使用 ONNX 运行时部署模型。

在我告诉你每个选项发生了什么之前,让我问你这个问题。您目前是否想学习如何将 Tensorflow 用于计算机视觉?如果有,那就来看看我的 免费 tensorflow 课程

现在,这里是我上面提到的每一个选项的结果。

使用 OpenCV DNN 模块在 C++中部署张量流模型

opencv 徽标

我记得尝试的第一个选项是 OpenCV DNN 模块。这要追溯到 2018 年。

DNN 代表深度神经网络,这是 OpenCV 开发人员推出的一个模块,用于将深度神经网络集成到已经运行 OpenCV 代码的进程中。

这被证明是对我们目标的快速修复,但这是一种非常有限的方法,因为这个模块当时还是新的,它为部署深度神经网络提供了有限的选择。

例如,我需要部署 InceptionV2 模型,但是我不能,因为 OpenCV DNN 模块只支持 InceptionV1 架构。

DNN 模块在最近几年得到了发展,它似乎为分类和对象检测 部署模型提供了更多的灵活性。

我尝试过的另外两个选项是 Tensorflow C++ API 和 ONNX 运行时。

使用 Tensorflow C++ API 部署模型

tensorflow 徽标

Tensorflow 是使用 C++构建的,它提供了一个 API,使得在 C++中部署模型(甚至训练模型,如果您愿意的话)变得相对容易。这听起来很棒,直到你开始尝试实现一个使用这个 API 的程序。

作为一名开发人员,你知道文档非常重要,但是 Tensorflow 的 C++ API 非常非常有限。仅仅通过阅读文档很难找到您想要的信息。

其次,不支持 Windows 32bits。因此,如果你(或你的客户)有这样一个系统,那么你在这里面临一堵墙,最好尝试寻找其他选择。

但是这个 API 的伟大之处在于,您不必担心您用 Python 训练的模型的兼容性,并且您希望使用 C++ API 来部署它。尤其是在 Python 和 C++中使用相同版本的 Tensorflow 的情况下。

我个人已经使用这个 API 部署了图像分类模型和对象检测模型,除了我上面提到的限制因素之外,这些模型完全按照预期工作。

在 C++中部署 Tensorflow 模型时,我个人尝试的最后一个选项是 ONNX 运行时。

使用 ONNX 运行时部署模型

图片来自维基百科

ONNX 代表开放神经网络交换,它是一个完整的生态系统,旨在标准化机器学习模型的表示。它是由微软开发的。

ONNX 的目标是更容易部署任何类型的机器学习模型,这些模型来自任何类型的 ML 框架,包括 Tensorflow。

要在 C++中使用 ONNX 部署 Tensorflow 模型,您需要做两件事:

  1. 将 Tensorflow 模型转换为 ONNX 格式。有一个开源工具叫做 tf2onnx。
  2. 使用 ONNX 运行时来部署转换后的模型。

我亲自在这么多深度学习模型上测试了这种方法,效果非常好。例如,我将 tensorflow 对象检测 API 中的几乎所有模型都转换为 ONNX 格式,并且能够毫无问题地使用它们进行推理。

在一个朋友向我推荐这个工具并看到它的所有功能后,我爱上了它。

您希望我帮助您构建 Python/C++ ML 管道吗?

如果您目前正在尝试构建一个完整的机器学习管道,其中:

  • 你用 Python 训练和评估深度学习模型。
  • 用 C++部署这些模型。
  • 你的模型仅仅基于计算机视觉(图像识别、物体检测、实例分割、语义分割等等)。

然后随时联系我,在LinkedInTwitter或通过电子邮件(nourislam.mokhtari@gmail.com)。我将帮助您在短时间内设置管道,并提供符合您要求的选择!

关于作者

我是一名机器学习工程师,致力于解决具有挑战性的计算机视觉问题。在 LinkedInTwitter 上关注我的每日内容。此外,通过加入我的 时事通讯 ,让这样的文章直接进入你的收件箱。

如何部署您的机器学习项目

原文:https://towardsdatascience.com/how-to-deploy-your-machine-learning-project-dfc0cf1fba36

将模型投入生产的三种方法的高级视图

需求—机器学习模型部署:

对于任何机器学习预测分析项目,结果(预测、预报等。)将不会到达预期的受众,除非采用一种方法来部署机器学习模型,以便它可以在新记录出现时或成批地对其进行“评分”。我听说,高达 99%的机器学习项目永远无法进入生产阶段。我相信阻止他们的是数据科学家没有学会如何部署他们的通用模型。

通常,生产中的模型会在 web 应用程序中显示其结果。本文旨在向您提供将模型投入生产的三种不同方法的高级视图,而不是提供这些方法的具体细节的“操作指南”。对于这三个示例,我将使用 Microsoft SQL Server,但是在另一个数据库系统中应该可以做类似的事情,除了第三个部署选项在 SQL 存储过程中使用嵌入式 Python 代码。那个只能在 Microsoft SQL Server 上运行。

期望的结果:

假设我们有一个向用户显示信息的 web 应用程序,包括一些表示预测的数值。这可能是为了二进制分类,其中我们想要知道记录被分类为“是”而不是“否”的概率是多少(用从 0 到 1 的百分比表示)。贷款申请是使用分类模型的一个例子。或者,我们可能希望显示日期和时间,或者 X 发生之前的分钟数或小时数,例如当车间中的机器预计将发生故障时,这将提示用户在该事件发生之前进行一些预防性维护。

我将展示三种部署机器学习模型的方法,以便用户可以在 web 应用程序中看到预测的结果。这些方法在创建、设置、部署和维护的复杂程度上会有所不同。对于所有这三种情况,我们都从模型训练代码开始,运行并存储一个模型,供以后在评分中使用。

图一。构建、训练和存储预测模型的 Python 代码

作者图片

ML 部署系统#1: API 和容器

第一个部署选项包括以下步骤:

1。创建一个新记录评分 API。

2。让 web 应用程序在后台调用 API(服务器端),提供一些关于记录的细节,以便…

3。API 中的代码可以构建并运行 SQL 查询,该查询创建并填充 ML 模型评分所需的所有特性。

4。让 API 代码在数据库表中存储每个新记录的预测值,并…

5。让 web 应用程序显示结果,例如“是”的概率(分类模型示例)、“估计到达时间”(回归模型示例)等。,针对每个打开的记录。

在图 2 中,我们看到已经创建了一个 API,并存储在 Docker 容器中。该 API 将位于一个正在运行的 web 服务器上,并将等待向它发出的请求。

图二。嵌入在 Docker 容器中的 Python API 具有可移植性和可靠性

作者图片

在下一张图(图 3)中,执行了一整套步骤。注意步骤 7 可以有两个目的(存储结果和显示结果),同时做以下事情:

a)web 应用程序从 API 获得结果后,会将这些结果存储在危险的数据库表中。

b) 在向用户显示屏幕之前,web 应用程序会填充数据库表中的字段,包括预测结果。

c) 然后,web 应用程序显示每条记录的所有数据,包括预测值。如果我们跳过上面的步骤 a)和 b ),我们可能仍然能够在网页上显示结果,但是我们还没有将它们存储在数据库中,这是我们通常想要做的事情。

图 3。API&容器部署方法的完整示意图

图片作者和icon-library.com

API 和容器方法的优点和挑战

这个系统有许多部分,数据科学家和/或开发人员必须掌握这些技能。但是这个系统也有一些优点。

正面

  • 任何需要进行预测的 web 或控制台应用程序都可以调用 API。
  • 将 API(以及潜在的调用它的 web 应用程序)放入 Docker 容器是封装和保护代码及其依赖项(例如特定的 Python 包版本)的一种极好的方式。
  • Docker 容器可以在本地托管,也可以放入您使用的云平台,无论是 AWS、GCP 还是 Azure。

挑战

  • 创建一个 API 需要时间,因为它不仅仅是一个 Python 脚本。
  • 托管一个 API(或者包含它的容器)需要与保持它运行的资源进行协调。
  • Docker 容器有一个学习曲线。
  • 开发者需要获得 Docker 桌面的批准才能使用 Docker 容器。

ML 部署系统#2: SQL 触发器调用 Python 文件进行评分

虽然 API & Containers 方法(系统#1)可能是健壮和可靠的,但它并不简单。事实上,必须为需要运行的容器和 Streamlit web 应用程序和 API 管理服务器,这使得它变得相当复杂。还有其他更简单的系统也能满足需求。

第一个系统可能是最简单的,但也有其自身的挑战。理想情况下,我们将在 SQL Server 的本地驱动器中创建一个 Python 虚拟环境(因为用于其他目的的 Python 文件可能同样需要由其作者运行),位于包含我们的 Python 评分脚本的文件夹下。这确保了我们计划为其他预测模型运行的其他 Python 文件也可以安全地驻留在该驱动器中,并且不会由于基本 Python 环境中的包的变化而失败。图 4 中的步骤 2 将让 SQL 使用 xp_cmdshell 调用运行 Python 脚本的批处理文件。这里的可以找到一个例子

图四。SQL 和外部 Python 方法

作者图片

SQL 和外部 Python 方法的优点和挑战

这项工作部分发生在数据库内部,部分发生在 SQL“计分”脚本中。

正面

  • 只有三个主要部分— (1)调用批处理文件的 SQL 触发器代码,(2)调用 Python 脚本文件的批处理文件,以及(3)对记录进行评分并将其更新回 SQL 表的 Python 代码。
  • 大多数数据科学家已经用 Python 编码了。
  • 这与 MS SQL Server(可能是其他 RDBMS)配合得很好。

挑战

  • 模型文件(pickle 或一些其他压缩文件)和评分脚本需要驻留在 SQL Server 实例的计算机上,或者可能驻留在该计算机的驱动器盘符下的目录中(C:,L:,K:,等等)。).
  • 服务器需要为评分脚本设置正确的 Python 虚拟环境。
  • 必须在服务器上创建并定位一个批处理文件,SQL 调用该文件并运行 Python 脚本。
  • 要将信息写回 SQL 表,必须在 Python 脚本中使用 SQL 数据库的凭据。

ML 部署系统#3: SQL 触发器代码运行嵌入式 Python

该系统还使用 SQL Server 触发器,以及作为 NVARCHAR 字符串嵌入到存储过程中的 Python 脚本。这就是微软现在所说的“ SQL Server 机器学习服务 (Python 和 R)”。这种方法存在一些挑战。尽管如此,它远没有 API &容器系统复杂,但它要求开发人员知道如何创建 SQL 触发器,并要求 SQL Server 调用嵌入式脚本。它还需要对 SQL 数据库的更新权限,以便 Python 脚本可以在字段中输入值来保存预测。图 5 显示了在用新的预测值更新表格之前的第一部分。

图 5。新记录插入表中,触发 SQL 代码,运行 Python 代码对新记录评分。

作者图片

在 Python 脚本对新记录进行评分后,它将向数据库发送一个 SQL UPDATE 查询调用(图 6 ),并将新的预测值放入保存记录的 SQL 表的一个字段中。该字段可以是一个表示概率的浮点值(用于分类)或 X 发生前的估计分钟数,甚至可以是一个日期/时间值,通过将估计分钟数添加到该记录的开始日期/时间来创建(用于回归)。存储的内容取决于模型的用途。

图 6。危险预测存储在 SQL Server 表中。

作者图片

图 7 显示了部署系统#2 的完整步骤。很明显,它的“活动部件”比系统 1 少。

假设我们的 web 应用程序每 15 秒刷新一次显示的记录。一旦向表中添加了一条记录,就应该足够快地完成并记录预测,以便下次刷新页面时显示预测值以及该记录的其他字段。如果 Python 脚本和模型存储在 SQL Server 表中,那么从触发到更新的整个过程应该只需要几秒钟就可以运行。下次页面刷新时,新记录的预测值将与该记录的其他字段一起出现。

图七。整个 SQL 触发器部署系统,从开始到结束

作者图片

SQL 触发器和嵌入式 Python 方法的优点和挑战

正面

  • 评分发生在存储过程中,任何网页中的触发器或代码都可以调用该存储过程。
  • 不需要创建 API。
  • 不需要设置码头集装箱。
  • Python(或 R)代码运行在与所使用的表相同的 SQL Server 上,运行速度非常快。

挑战

  • 它需要在 SQL Server 实例上启用 Python 的外部脚本执行。
  • 学习将 Python 脚本嵌入存储过程的正确方法需要时间和练习。
  • SQL Server 需要安装代码所需的所有 Python 包。
  • 在 SQL Server 机器上创建 Python 虚拟环境可能更难。
  • 不能使用特定于 python 脚本(用于封装和保护 Python 代码)的虚拟环境,因为脚本完全嵌入在 SQL 存储过程中。它只能使用基本的 Python 环境。
  • 脚本所需的包必须安装在基本 Python 环境中的 SQL Server 上,否则必须修改嵌入式脚本以仅使用标准 Python 包,这些包是安装在 SQL Server 上的机器学习服务的一部分。

摘要

本文的核心是三种部署方法的三个不同图像。我将在下面一起重复它们,以帮助您在开始充实您将如何部署您的机器学习项目的细节之前评估这些差异。

图片作者和icon-library.com

作者图片

作者图片

希望这篇文章对你有所帮助。在接下来的几个月里,我会写更多关于我作为数据科学家所学到的东西。

关注我或订阅(带有信封图标的按钮)很容易获得新文章的通知…只需点击页面侧面或底部的绿色按钮

如何使用 DagsHub+MLflow+AWS Lambda 部署您的 ML 模型

原文:https://towardsdatascience.com/how-to-deploy-your-ml-model-using-dagshub-mlflow-aws-lambda-c85e07b06ef6

一个直观的教程,展示了如何部署训练好的模型并对新数据进行预测

张杰瑞Unsplash 上拍照

机器学习模型的部署是数据科学家最重要的技能之一。清理数据、从数据集中选择最佳要素、设置超参数并训练模型后,最后一步是将模型投入生产,以便根据新数据对其进行评估。

有许多方法可以部署模型。第一种方法是使用像 Flask 和 Django 这样的 web 托管框架。另一种方法是利用众所周知的云平台框架,如 AWS Sagemaker 和 Azure ML framework。第三种也是最后一种方式是利用无服务器计算服务,如AWS Lambda、 Google Cloud 函数和 Azure 函数。

在这篇文章中,我们将在 AWS Lambda 上投入生产一个经过训练的模型,这是一个由亚马逊提供的计算平台,作为亚马逊 Web 服务的一部分,使开发人员能够部署模型和构建应用程序。它还允许避免设置任何环境,并加快我们的工作。我们开始吧!

我们试图解决什么问题?

训练和部署模型以从 ECG 信号中检测异常。来源: flaticon

我们将训练和部署一个模型来从 ECG 信号中检测不规则的心律。由于与正常心律相比,不规则心律通常占少数,我们正在解决异常检测问题。对于机器学习模型来说,这是一项具有挑战性的任务,但如果它工作良好,它将使专业技术人员和医生能够快速检测患者的心律失常,避免任何手动和重复工作。

在本教程中,我们将使用 ECG5000 数据集,其中包含从一名心力衰竭患者身上随机选取的 5000 次心跳。它最初是在 PhysioNet 中发现的,这是一个可供研究人员使用的医疗数据存储库,指示心律是否异常的类值是通过自动注释获得的。

动机

数据科学家不仅需要建立机器模型,还需要跟踪实验、版本数据、代码和模型。其实不同的目的有不同的平台。GitHub 拥有不同版本的代码和数据,并与其他队友协作,MLflow 是最常用的跟踪和部署模型的平台之一。但是从一个平台到另一个平台可能是低效的。

直接用一个平台不是更好吗?此外,GitHub 在处理数据版本和不允许大文件方面并不真正高效。由于这些原因,我在这个项目中使用 DagsHub。这是一个能够更有效地比较不同实验和数据版本的平台。界面很直观,和 GitHub 上的非常相似。换句话说,这就像在一个独特的地方使用 GitHub 和 MLflow。在这里查看文档,开始使用 DagsHub 及其要求。

设置 DVC 并将 DagsHub 配置为 DVC 远程存储

最终 DagsHub 管道概述。作者插图。

一旦您创建了 DagsHub 存储库,并且在您的本地 PC 上有了它的副本,我建议您将 Visual Studio 代码作为 IDE 来使用,因为它通过扩展支持多种语言,并且包含了一个终端,这在本部分和接下来的部分中是需要的。

Dagshub 的美妙之处在于,您可以在存储库中找到所有结果实验,并轻松地更改相关的列来比较这些实验。这是可能的,因为 DagsHub 是建立在 GitHub 和 DVC 之上的,这是一个工具,使您能够在 Git 提交中捕获您的数据和模型的版本。

首先,我们需要在本地环境中安装 DVC:

pip install dvc

关于更详细的说明,还有这个网站展示了与 macOS、Windows 和 Linux 一起工作时的不同解决方案。

安装完成后,我们可以在我们的项目中运行dvc init。这是 DVC 初始化和创建包含配置的新的[.dvc/](https://dvc.org/doc/user-guide/project-structure/internal-files)目录的重要一步。

要在 DagsHub 上上传数据,您可以在您的存储库中找到必要的命令行。

从 DVC 开始。作者插图。

目录:

第 1 部分:使用 MLflow 跟踪的 Keras 模型训练

在我们准备好环境之后,我们可以开始使用 MLflow,这是一个非常高效的开源平台,可以跟踪实验,打包机器学习模型,并将其部署到生产中。

作者插图。

下面几行代码对于创建环境变量至关重要。通过单击 Remote 按钮下的 MLflow 选项,可以将您的凭据复制到 DagsHub 存储库中。用户名和密码包含在 parameters.yaml 文件中。

之后,我们终于可以利用 MLflow 来记录超参数、度量和模型人工制品。

mlflow.tensorflow.autolog()允许从 Tensorflow 到 MLflow 自动记录指标,如优化器和时期数。

在脚本的最后,我们还使用Autoencoder.save(Path("Autoencoder"))将模型保存到本地 PC 上的一个文件中。之后,我们加载模型并保存到 BentoML 本地存储

这里 可以找到 train.py 的完整代码。

我们可以运行 python 脚本 train.py,并每次更改超参数,以了解哪些超参数对提高自动编码器检测 ECG 信号异常的性能贡献更大。

cd src
python train.py

Dagshub 的美妙之处在于,您可以在存储库中找到所有结果实验,并轻松地更改相关的列来比较这些实验。

显示 MLflow 实验的表格。作者 GIF。

它不仅允许将结果收集到一个表格中,而且还可以用一个更加直观和完整的表格来比较不同的运行,该表格包含为每个实验选择的所有超参数。此外,还有一个平行坐标图,用于关注前 5 个超参数对损失和其他图表的贡献,这些图表比较了不同实验的评估指标。

比较不同的实验。作者 GIF。

第 2 部分:用 BentoML 和 AWS Lambda 部署模型

这项任务可以分为不同的步骤:

  • 创建 BentoML 服务
  • 做便当
  • 部署到 AWS Lambda

创建 BentoML 服务

在继续之前,让我们通过在终端上编写以下命令行来检查存储在 BentoML 本地商店中的所有模型:

bentoml models list

它返回以下输出:

作者插图。

正如您可以从存储模型的列表中推断的那样,它们是根据创建时间以降序排列的。因此,我们对带有以下标签的模型感兴趣:keras_model:pdthevrih6w2iaav

现在我们已经确定模型存储在 Bento 中,我们可以创建一个名为service.py的文件,在其中我们创建一个服务来部署我们的深度学习模型。这将导致 API 端点的创建。

首先,我们指定我们想要的模型标签,然后,我们在 Keras 模型上创建一个转轮实例。在我们创建了一个属于类bentoml.Service的实例之后,我们指定服务的名称ecg_model和之前定义的运行器。

现在,我们为 BentoML 服务创建一个端点,称为predict。您还可以注意到有一个由@,service 表示的装饰器,它是前面定义的服务实例。输入和输出的类型也在装饰器中指定,都是 bentoml.io.NumpyNdarray 。点击此处查看更多文档

你可以在这里 找到 service.py 的完整代码。

在函数 predict 中,我们再次期望输入一个 NumPy 数组,因为我们有一个由 140 个要素和一个目标标签组成的数据集。输出的类型也是一个数组,它告诉我们 ECG 信号是否异常。在获得最终输出之前有几个步骤。

第一步是使用预训练的自动编码器重建原始输入。然后,我们计算原始输入和自动编码器产生的输出之间的损耗,并检查损耗是否大于模型训练结束后计算的固定阈值。

最后,我们可以使用以下命令行运行服务:

bentoml serve service.py:service --reload

输出:

之后,我们可以发出服务请求,以检查经过培训的模型是否正常工作。所有的代码都在一个名为servicerequest.py的文件中。我们从测试集中随机选择 10 个数据观察值,并将它们传递给训练好的模型,并通过向 BentoML 服务发出请求来提供基于这些观察值的预测。

你可以在这里 找到 service request . py的完整代码。

当前面的命令行仍在运行时,我们可以在另一个终端中编写这个命令行:

python servicerequest.py

输出:

似乎模型预测对 10 个数据点中的 10 个是正确的!在您的浏览器中打开 http://127.0.0.1:3000 ,您应该会看到这样一个窗口:

作者插图。

做便当

一旦我们定义了 BentoML 服务,我们就可以将所有的源代码、模型文件和依赖项放入一个名为 Bento 的档案中。做便当,有尊重的要求。我们需要在项目文件夹中创建文件bentofile.yaml

然后,我们可以在终端中运行命令行bentoml build,并获得如下输出:

作者插图。

我们可以用命令行bentoml list再次可视化我们的便当列表:

作者插图。

恭喜你!困难的部分已经完成了。模型、服务、Python 需求和 Docker 文件被保存到前面输出指定的文件夹中。

部署到 AWS Lambda

这是我们将要执行的步骤的摘要:

  1. 创建 AWS 帐户并配置凭据
  2. 用 bentoctl 初始化部署。
  3. 构建并推送与 AWS Lambda 兼容的 Docker 映像
  4. 使用 Terraform 应用部署

如果您发现任何问题,这里还有这些步骤的详细文档。

  1. 创建 AWS 帐户并配置凭证

我们将把我们的异常检测模型作为 Lambda 函数部署在 AWS 上。首先,你需要在这里创建一个 AWS 账户 。不要担心,它允许您免费部署模型:免费层允许 AWS Lambda 每月 100 万个请求,这对于像我们这样的小项目来说没有问题。一旦创建了帐户,您需要配置 AWS 凭证。建议你关注这个 youtube 视频。我还建议你在本地电脑上安装 Docker Desktop。

对于 Linux 或 osX:

export AWS_ACCESS_KEY_ID=<YOUR_AWS_ACCESS_KEY_ID>
export AWS_SECRET_ACCESS_KEY=<YOUR_AWS_SECRET_ACCESS_KEY>

对于 Windows:

setx AWS_ACCESS_KEY_ID <YOUR_AWS_ACCESS_KEY_ID>
setx AWS_SECRET_ACCESS_KEY <YOUR_AWS_SECRET_ACCESS_KEY>

还有两个包需要从终端安装,即aws-lambda操作符和它的依赖项boto3包。

pip install bentoctl boto3
bentoctl operator install aws-lambda

2。用 bentoctl 初始化部署

在我们用 bentoctl 初始化部署之后,这是 Bento 的交互式 CLI 命令。

bentoctl init

作者插图。

这个命令行将生成三个文件,这是用 AWS Lambda、deployment_config.yamlbentoctl.tfvarsmain.tf部署模型所必需的。最后需要安装的软件包是terraform。查看此处的安装说明。检查安装是否成功的一个好方法是编写命令行:

terraform --version

3。构建一个 AWS Lambda 兼容的 Docker 映像

现在,我们可以构建 AWS Lambda 兼容的 docker 映像并将其推送到 AWS ECR 存储库。

bentoctl build -b keras_model_ad:latest -f deployment_config.yaml

它返回以下输出:

Created the repository keras_model_ad
The push refers to repository [849711432510.dkr.ecr.us-west-1.amazonaws.com/keras_model_ad]
957db15fed12: Pushed 
1df100fb8cb9: Pushed 
3fef49d17991: Pushed 
11e8b0510c67: Pushed 
9e9bb09e42f7: Pushing 1022.1MiB/1.4GiB...920ee87a2ed2: Pushed 
3ce7d4d72da9: Pushed 
630337cfb78d: Pushed 
6485bed63627: Pushed 
🚀 Image pushed!
✨ generated template files.
  - bentoctl.tfvarsbentoctl has built and pushed the bento and generated the terraform files

4。使用 Terraform 应用部署

最后,我们可以初始化 terraform 项目,它将被应用于创建 Lambda 部署。

terraform init
terraform apply -var-file=bentoctl.tfvars -auto-approve

这是我们预期的输出:

aws_apigatewayv2_api.lambda: Creating...
aws_iam_role.lambda_exec: Creating...
aws_apigatewayv2_api.lambda: Creation complete after 2s [id=libobddgz8]
aws_cloudwatch_log_group.api_gw: Creating...
aws_iam_role.lambda_exec: Creation complete after 3s [id=keras_model_ad-iam]
aws_iam_role_policy_attachment.lambda_policy: Creating...
aws_lambda_function.fn: Creating...
aws_iam_role_policy_attachment.lambda_policy: Creation complete after 1s [id=keras_model_ad-iam-20220910214539285200000001]
aws_cloudwatch_log_group.api_gw: Creation complete after 5s [id=/aws/api_gw/keras_model_ad-gw]
aws_apigatewayv2_stage.lambda: Creating...
aws_apigatewayv2_stage.lambda: Creation complete after 5s [id=$default]
... 

我的 API 服务的链接是https://libobddgz8.execute-api.us-west-1.amazonaws.com/。我们可以使用前面几节中显示的文件 servicerequest.py 快速测试部署的端点。

如果再次运行 servicerequest.py,应该会得到以下输出:

作者插图。

最终想法:

我希望你找到这篇教程,开始用 MLflow 跟踪你的实验,用 BentoML 和 AWS Lambda 部署你的机器学习模型。它是完全免费的,对于初学者来说是一个很好的入门方式。

查看我的 DagsHub 存储库中的代码:

https://dagshub.com/eugenia.anello/anomaly_detection_ecg

你喜欢我的文章吗? 成为会员 每天无限获取数据科学新帖!这是一种间接的支持我的方式,不会给你带来任何额外的费用。如果您已经是会员, 订阅 每当我发布新的数据科学和 python 指南时,您都可以收到电子邮件!

如何使用 Python 部署您自己优化的语音转文本 Web 应用程序

原文:https://towardsdatascience.com/how-to-deploy-your-own-optimized-speech-to-text-web-app-with-python-c956c7838ec8

关于如何构建自己的语音转文本 web 应用程序以最佳方式将音频转换为文本格式的详细指南

伊恩·哈勃在 Unsplash 上拍摄的照片

语音是人类使用的最有效的交流方式之一。有声读物和播客在过去几年越来越受欢迎,尤其是在现代快节奏的生活方式下。然而,阅读一直是我们生活中至关重要的一个方面,也是获取信息的最受欢迎的方法。阅读这篇文章的读者就是最好的例子。

因此,将普通音频数据转换成可读的文本格式以达到广泛的受众的需求是至关重要的。无论是电影中的字幕还是有声读物到书面材料的转换,从可用语音中提取文本数据都是一个重要的应用。通过正确的深度学习技术,可以获得高度优化的语音到文本的转换。

在本文中,我们将了解如何构建一个最佳的方法来将音频数据转换成文本。我们将利用 AssemblyAI 平台,使我们能够以最有效的方式转录和理解音频。现在让我们着手开始这个项目的建设吧!

构建语音转文本 Web 应用程序:

在这一节中,我们将构建语音到文本的 web 应用程序来转录视频。我们将利用 AssemblyAI 的 API token 中的一种易于使用的技术来高效率地转录音频文件。我们还将在 streamlit 中使用一个交互式 web 框架来部署我们的项目。首先,让我们获得成功运行这个项目所需的所有组件。

安装所有必需的依赖项:

用户需要安装的两个主要需求是用于部署项目的 streamlit web 开发框架和 youtube-dl 库,该库将帮助我们从 youtube 和其他类似的视频网站下载视频。这两个库都可以通过简单的 pip 安装命令下载,如下所示。

pip install streamlit
pip install youtube_dl

可以在命令提示符下键入这些命令,如上所示。至于最后一个依赖项,我们需要安装 FFmpeg。这是一个免费的开源软件项目,它将使我们能够以最有效的方式处理音频文件、视频内容、流和其他多媒体文件。因此,从下面的链接下载需求,并通过进入 Windows 平台中的环境变量将它们直接添加到您的路径中。

您可以安装一个 FFmpeg,并提供其 bin 文件的路径,也可以从提供的链接下载 Windows 64 的所有要求。如果你想继续我所做的,那么你可以下载 ffmpeg,ffprobe 和 ffplay 到一个名为 Paths 的文件夹中,并把它添加到你的环境变量中,如下图所示。

作者图片

作者图片

既然我们已经获得了所有必需的库需求,我们可以继续创建一个新的 Python 文件并相应地导入它们。我将把这个 Python 文件命名为 final_app.py。这个 Python 文件将包含我们项目的所有主要代码内容。

import streamlit as st
import youtube_dl
import requests
from config import API_Key

值得注意的是,我们现在已经有了所有必要的导入,包括请求库,它将允许我们轻松地访问任何网站的 URL 链接。然而,有人可能想知道配置导入是什么,我们将在下一节中弄清楚它是什么。

创建配置文件:

在我们继续编码过程之前,我们将访问 AssemblyAI 平台,在那里我们可以免费创建一个帐户,并获得一个 API 密钥,我们可以利用它来轻松理解和转录音频。一旦您登录到您的帐户,您就可以在屏幕右侧复制您的 API 密钥。

在下一步中,我们将创建另一个 Python 文件,该文件将存储从 AssemblyAI 平台生成的 API 密钥。确保将创建的 Python 文件标记为 config.py,在这里我们可以创建一个名为 API_Key 的变量,该变量将存储我们之前从 AssemblyAI 平台复制的 API 地址。代码片段如下所示。

API_Key = "Enter Your Key Here"

添加所有必要的参数:

一旦您完成了配置文件的创建,项目的其余部分将在 final_app.py 部分进行编码。首先,我们将添加下载视频所需的基本参数,并设置 AssemblyAI 网站的适当位置。在理解这些参数的解释之前,让我们先看看下面的代码块。

ydl_opts = {
   'format': 'bestaudio/best',
   'postprocessors': [{
       'key': 'FFmpegExtractAudio',
       'preferredcodec': 'mp3',
       'preferredquality': '192',
   }],
   'ffmpeg-location': './',
   'outtmpl': "./%(id)s.%(ext)s",
}

在上面的代码块中,我们只是定义了 YouTube downloader 所需的一些基本约束。我们将以最佳音频的形式下载视频,并以 mp3 格式保存在我们的本地驱动器中。在下一个代码片段中,我们将为 AssemblyAI 平台定义参数。

transcript_endpoint = "[https://api.assemblyai.com/v2/transcript](https://api.assemblyai.com/v2/transcript)"
upload_endpoint = '[https://api.assemblyai.com/v2/upload'](https://api.assemblyai.com/v2/upload')headers_auth_only = {'authorization': API_Key}
headers = {
   "authorization": API_Key,
   "content-type": "application/json"
}
CHUNK_SIZE = 5242880

我们正在描述我们将上传音频文件的端点,以及该文件的转录将发生的端点。最后,我们还将设置指向我们之前获得的 API 键的头。块大小变量将帮助我们把较大的音频文件分成较小的块。让我们转到下一部分,我们将转录视频。

使用 AssemblyAI 转录 YouTube 视频:

在本节中,我们将创建一个函数来帮助我们转录整个音频数据。首先,我们将从 streamlit 调用一个缓存函数,该函数将存储以前的数据,并且只有在函数的参数发生变化时才会执行新的操作。转录链接是计算所有必要动作的主要功能。确保本节中的所有其他语句和函数都是在 register _ from _ link()函数下定义的。

[@st](http://twitter.com/st).cache
def transcribe_from_link(link, categories: bool):

在 regulate _ from _ link()下的第一个函数中,我们将利用 youtube-dl 导入,并使用视频 ID 将音频内容下载到我们想要的保存位置。我们现在将创建另一个函数来读取下载文件的内容,并将其上传到 AssemblyAI 网站。下面是以下功能的代码片段。

_id = link.strip()def get_vid(_id):
  with youtube_dl.YoutubeDL(ydl_opts) as ydl:
   return ydl.extract_info(_id)# download the audio of the YouTube video locally
 meta = get_vid(_id)
 save_location = meta['id'] + ".mp3"print('Saved mp3 to', save_location)def read_file(filename):
  with open(filename, 'rb') as _file:
   while True:
    data = _file.read(CHUNK_SIZE)
    if not data:
     break
    yield data

在本节的最后一段代码中,我们将使用 requests 库将下载的音频文件上传到 AssemblyAI 平台。一旦上传了音频文件,我们就可以通过发送另一个执行以下操作的请求来开始转录过程。最后,我们可以访问音频文件的转录及其各自的 ID,并将其存储在轮询端点,包含我们的最终结果。

# upload audio file to AssemblyAI
 upload_response = requests.post(
  upload_endpoint,
  headers=headers_auth_only, data=read_file(save_location)
 )audio_url = upload_response.json()['upload_url']
 print('Uploaded to', audio_url)# start the transcription of the audio file
 transcript_request = {
  'audio_url': audio_url,
  'iab_categories': 'True' if categories else 'False',
 }transcript_response = requests.post(transcript_endpoint, json=transcript_request, headers=headers)# this is the id of the file that is being transcribed in the AssemblyAI servers
 # we will use this id to access the completed transcription
 transcript_id = transcript_response.json()['id']
 polling_endpoint = transcript_endpoint + "/" + transcript_idprint("Transcribing at", polling_endpoint)return polling_endpoint

注意:请查看完整的代码部分,以便更好地复制粘贴上述代码。上述代码块中所有剩余的函数和语句都必须在 register _ from _ link()函数下定义。

构建 web 应用程序:

在本节中,我们将使用 streamlit 框架开发 web 应用程序。首先,我们将定义一些我们将在网站布局中使用的功能。web 应用程序可能需要一些时间来完成上传音频文件和接收转换后的文本数据的执行。为了监控所用的时间,我们将使用 get_status 和 refresh_state 函数,这将使我们能够接收响应并检查网站是否在工作。

然后,我们可以继续添加标题和文本框,这将允许用户添加一个链接,通过它可以下载 YouTube 视频的音频并相应地进行转录。我们还将添加一个按钮,允许用户点击并检查转录过程的状态。web 开发的代码如下面的代码片段所示。

if 'status' not in st.session_state:
    st.session_state['status'] = 'submitted'def get_status(polling_endpoint):
 polling_response = requests.get(polling_endpoint, headers=headers)
 st.session_state['status'] = polling_response.json()['status']def refresh_state():
 st.session_state['status'] = 'submitted'st.title('Easily transcribe YouTube videos')link = st.text_input('Enter your YouTube video link', '[https://youtu.be/dccdadl90vs'](https://youtu.be/dccdadl90vs'), on_change=refresh_state)
st.video(link)st.text("The transcription is " + st.session_state['status'])polling_endpoint = transcribe_from_link(link, False)st.button('check_status', on_click=get_status, args=(polling_endpoint,))transcript=''
if st.session_state['status']=='completed':
 polling_response = requests.get(polling_endpoint, headers=headers)
 transcript = polling_response.json()['text']st.markdown(transcript)

完整代码:

作者图片

作者图片

最后,让我们以 GitHub embed 的形式探索一下这个项目的全部代码,看看它是什么样子的。观众可以选择复制粘贴下面的代码来执行他们的项目,并立即尝试对这个项目的各种解释。

完成代码设置后,使用下面的命令运行程序。

streamlit run final_app.py

如果观众正在寻找关于这个主题的视频教程,我强烈建议查看下面的链接,以获得关于如何以两部分系列的形式执行以下项目的简明解释。

结论:

照片由以色列总统府Unsplash 拍摄

随着自然语言处理领域的不断发展,深度学习模型在处理与其相关的任务时变得更加高效。正如本文所讨论的,通过利用现代人工智能技术,我们能够在语音到文本转换的任务上取得非常先进的结果。我们将在以后的文章中涵盖更多这样有趣的项目!

在本文中,我们详细探讨了如何在 streamlit 和 AssemblyAI 平台的帮助下,轻松构建自己的 web 应用程序,成功地将音频数据转换为文本形式。如果你对这篇文章中提到的各点有任何疑问,请在下面的评论中告诉我。我会尽快给你回复。

如果你想在我的文章发表后第一时间得到通知,请点击下面的链接订阅邮件推荐。如果你希望支持其他作者和我,请订阅下面的链接。

https://bharath-k1297.medium.com/membership

看看我的一些与本文主题相关的文章,你可能也会喜欢阅读!

谢谢你们坚持到最后。我希望你们都喜欢这篇文章。祝大家有美好的一天!

如何在 Apache 气流中设计更好的 Dag

原文:https://towardsdatascience.com/how-to-design-better-dags-in-apache-airflow-494f5cb0c9ab

数据工程

设计工作流时需要知道的两个最重要的属性

活动发起人Unsplash 上的照片

上周 ,我们学习了如何快速搭建 Apache Airflow 的开发环境。

这太棒了。

然而,我们还需要学习如何设计一个高效的工作流程。不幸的是,仅仅在我们的指尖有一个伟大的工具并不能单独解决问题。

虽然 Apache Airflow 在为我们做大部分繁重的工作方面做得很好,但是我们仍然需要确保每个 Airflow 任务的某些关键属性,以便获得正确和一致的结果。

幸运的是,存在许多最佳实践。

今天,我们从普遍适用于所有工作流的两个最重要的概念开始。

今天,我们学习原子性幂等性

全有或全无:原子性

通常在数据库系统的上下文中使用,原子性是 ACID 属性之一,被认为是一系列不可分割、不可约的操作,因此要么全部发生,要么什么都不发生。要么完全执行,要么根本不执行。

就 Apache Airflow 而言,这意味着任务应该以这样一种方式定义,即允许成功和适当的结果或者完全失败,而不影响系统的状态。

让我们想象一下,我们必须从 CSV 文件中提取数据,对其进行一些转换,并将结果写入数据库。

很简单,对吧?

一个不好的,非原子方法如下。

我们逐行提取数据,立即应用转换,并将结果立即上传到数据库。都在同一个任务内。

非原子方法[图片由作者提供]

现在,如果一些行被破坏,任务中途失败,我们只剩下期望结果的一部分。一些行已经被处理和插入——一些根本不存在。在避免重复的同时调试和重新运行这项任务将是一场噩梦。

一个改进的,原子工作流可以这样定义。

原子任务的更好方法[图片由作者提供]

所以要记住的一般经验是将操作分成不同的任务。一个操作等于一个单一任务——想想单一责任原则

不幸的是,这个简单的规则不能每次都适用。

一些操作是如此的紧密耦合,以至于最好将它们保持在一个 一致的工作单元。例如,在执行请求之前对 API 进行身份验证。

幸运的是,大多数气流操作器都是以原子方式设计的,可以直接使用。然而,对于更灵活的操作符类型,如 Bash 或 Python 操作符,我们在设计工作流时必须更加小心谨慎。

创建原子气流任务允许从失败中恢复的能力,并且只重新运行失败的和下游的任务。原子性提供了更容易维护和透明的工作流,没有隐藏的依赖性和副作用。

开始、停止、倒带:等幂

幂等性的概念与原子性的概念密切相关,并描述了数学和计算机科学中某些运算的属性。因此操作可以多次应用,而不改变初始应用之外的结果

把按下控制面板上的“on-button”想象成一种操作。多次按下此按钮与只按一次效果相同。

那么这在阿帕奇气流的上下文中意味着什么呢?

使用相同的输入多次调用相同的任务没有额外的效果。换句话说,如果在不改变输入 的情况下重新运行一个任务产生了 相同的输出,则可以认为它是幂等的。

幂等性允许减少故障恢复时间,并且减少数据丢失

现在,假设我们的工作是从数据库中获取特定日期的数据,并将结果写入 CSV 文件。在同一天重新运行该任务应该会覆盖现有文件,并且每次执行时都会产生相同的输出

每次都产生相同输出的幂等任务[图片由作者提供]

假设,我们以不同的方式设计我们的任务,在每次重新运行时,我们简单地将记录附加到一个现有的文件中。

现在,我们违背了 幂等的概念。任务的每次重新运行都会产生不同的结果,其中包含重复的记录。

产生重复结果的非等幂任务[图片由作者提供]

一般来说,写的任务应该检查现有记录覆盖或者使用上插操作,以符合等幂规则。

然而,对于更一般的应用,我们必须仔细考虑所有可能的副作用。

结论:

在本文中,我们讨论了在 Apache Airflow 中设计 Dag 时的两个最重要的原则:原子性幂等性

记住这些概念使我们能够创建更好的工作流,这些工作流是可恢复的、可重新运行的、容错的、一致的、可维护的、透明的,并且更容易理解。

然而,在编码和创建下一个工作流时,有更多的最佳实践需要遵循和考虑。

但这是改天的话题…

喜欢这篇文章吗?成为 中等会员 继续无限学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

https://medium.com/@marvinlanhenke/membership

参考资料/更多资料:

GIN:如何设计最强大的图形神经网络

原文:https://towardsdatascience.com/how-to-design-the-most-powerful-graph-neural-network-3d18b07a6e66

基于图同构网络的图分类

作者图片

图形神经网络不限于对节点进行分类。

最流行的应用之一是图分类。这是处理分子时的一项常见任务:它们被表示为图形,每个原子(节点)的特征可用于预测整个分子的行为。

然而,GNNs 只学习节点嵌入。如何将它们组合起来,以产生一个完整的嵌入的图?在本文中,我们将:

  • 看到一种新型的层,叫做“全局池”,来组合节点嵌入;
  • 介绍一种叫做图同构网络 (GIN)的新架构,由徐等人于 2018 年设计。

我们将详细说明与 GCN 或 GraphSAGE 相比,GIN 在辨别能力方面的优势,以及它与 Weisfeiler-Lehman 测试的联系。除了它强大的聚合器,GIN 还带来了关于 GNNs 的令人兴奋的收获。

可以用下面的 Google Colab 笔记本运行代码。

🌐一.蛋白质数据集

蛋白质的 3D 图(图片由作者提供)

蛋白质是生物信息学中的一个流行数据集。它是代表蛋白质的 1113 个图的集合,其中节点是氨基酸。两个节点足够近的时候用一条边连接(< 0.6 纳米)。目标是将每种蛋白质归类为而非

酶是一种特殊类型的蛋白质,作为催化剂加速细胞中的化学反应。它们对消化(如脂肪酶)、呼吸(如氧化酶)和人体的其他重要功能至关重要。它们也用于商业应用,如抗生素的生产。

该数据集也可在 TUDataset 上获得,并在 PyTorch Geometric 中实现。

**Dataset: PROTEINS(1113)** ----------------------
Number of graphs: 1113
Number of nodes: 23
Number of features: 3
Number of classes: 2

我不是生物化学家,所以我对这些蛋白质很好奇。让我们绘制一个图表,看看它看起来像什么:

使用 matplotlib 绘制蛋白质的 3D 图(图片由作者提供)

先前的 3D 结构是随机生成的:获得正确的 3D 表示是一个非常困难的问题,这是 AlphaFold 的全部要点。

图形不是表示分子的唯一方式。简化的分子输入行输入系统(微笑 ) 是另一种流行的方法,它使用行(串)符号。它是通过打印在稍微修改的分子图的深度优先树遍历中遇到的节点而获得的。

研究人员在研究分子或化合物时经常使用这种表示法。对我们来说幸运的是,蛋白质数据集已经以图表的形式进行了编码。否则,我们可能不得不将微笑字符串转换成networkx图形。

这并不意味着我们将直接向 GNN 提供蛋白质数据集。如果说 GraphSAGE 教会了我们什么的话,那就是迷你批处理非常高效。现在,每当我们实施 GNN 时,它都是不可或缺的工具。

**Training set**   = 890 graphs (14 subgraphs)
**Validation set** = 111 graphs (2 subgraphs)
**Test set**       = 112 graphs (2 subgraphs)

蛋白质并不是一个庞大的数据集,但是小批量将会加快训练的速度。我们可以使用 GCN 或 GAT,但是我想介绍一种新的架构:图同构网络。

🍾二。图形同构网络

杜松子酒是由研究人员设计的,他们试图最大限度地发挥 GNN 的代表性(或辨别力)。但是你如何定义“代表力”?

A.魏斯费勒-雷曼试验

表征 GNN 的“能力”的一种方式是使用魏斯费勒-雷曼(WL)图同构测试。同构的图意味着它们具有相同的结构:相同的连接但是节点有排列。WL 测试能够判断两个图是否同构,但不能保证它们同构。

两个同构的图(图片作者)

这可能看起来不多,但是要区分两个大图是非常困难的。其实这个问题不是已知的在多项式时间内可解,也不是 NP 完全的。它甚至可能介于两者之间,处于计算复杂性类别NP-中级(如果它只存在的话)。

好吧,但这和 GNNs 有什么关系?一些图形学习的研究人员注意到这个测试和 GNNs 学习的方式奇怪地相似。在 WL 测试中,

  1. 每个节点都以相同的标号开始;
  2. 来自相邻节点的标签被聚集并且被散列以产生新的标签;
  3. 重复上述步骤,直到标签停止变化

如果你对 WL 测试感兴趣,我会推荐这篇大卫·比伯的博客文章这篇迈克尔·布朗斯坦的文章

这个测试不仅类似于 GNNs 中如何聚集特征向量,而且它区分图形的能力使它比许多架构更强大,包括 GCNs 和 GraphSAGE。这启发了徐等人设计了一种新的聚合器,他们证明这种聚合器与测试一样好。

B.一个聚合器来管理它们

为了和 WL 测试一样好,这个新的聚合器在处理非同构图形时必须产生不同的节点嵌入。

我们将跳过这篇论文的数学部分,但是他们找到的解决方案是使用两个内射函数。哪些?我们不知道,我们可以用 MLP 学习它们!

  • 对于 GATs,我们使用神经网络来学习给定任务的最佳加权因子
  • 有了 GINs,由于通用逼近定理,我们现在学习两个内射函数的逼近。

下面是如何用 GIN 计算特定节点 i 的隐藏向量:

在这个公式中,ɛ确定了目标节点相对于其邻居的重要性(如果ɛ = 0,它具有相同的重要性)。它可以是可学习的参数,也可以是固定的标量。

请注意,我们谈论 MLP 是为了强调存在不止一层的事实。根据作者的说法,一层对于一般的图形学习来说是不够的。

C.全球统筹

全局池或图形级读出包括使用由 GNN 计算的节点嵌入产生一个图形嵌入

获得图嵌入的一个简单方法是使用嵌入 hᵢ 的每个节点的平均值总和最大值:

作者提出了关于图形级读出的两个要点:

  • 为了考虑所有的结构信息,有必要保持来自先前层的嵌入
  • sum 运算符令人惊讶地比均值和最大值更有表现力。

根据这些观察,他们提出了以下全球统筹方法:

对于每一层,节点嵌入被求和,并且结果被连接。该解决方案将 sum 运算符的表达能力与串联中先前迭代的记忆结合起来。

🧠三世。PyTorch 几何形状的杜松子酒

看到原始设计和它的实现之间的差异总是很有趣的。

PyTorch 几何图形中有一个不同参数的GINConv层:

  • nn:用于逼近我们两个内射函数的MLP
  • eps:ɛ的初始值,默认为0
  • train_eps:判断ɛ是否可训练的真/假语句,默认为

您可以看到,在这个实现中,ɛ被默认地完全删除了:它是一个我们可以调优的超参数,但可能不是一个必需的参数。

PyTorch 几何里有一个二轧棉层,叫GINEConv。它来自于 GIN 的本文的实现,它将一个 ReLU 函数应用于邻居的特征。我们不会在本教程中使用它,因为它的好处还不清楚。

我们仍然需要为GINConv层设计一个 MLP。以下是我们将实施的设计,灵感来自原始文件:

MLP 用于轧棉层(图片由作者提供)

这张纸叠了 5 层,但我们会用 3 层来代替。这是整个架构的样子:

我们的杜松子酒建筑(作者图片)

我找不到任何带有图嵌入连接的 GIN 实现,所以这里是我的版本(它平均提高了 1%的精度)。让我们将其与具有简单平均池(且没有串联)的 GCN 进行比较。

**GCN** test accuracy = **59.38%**
**GIN** test accuracy= **73.70%**

这一次,没有竞争!

GIN 架构的完全胜过 GCN。这种差距(平均 10%的准确度)是由几个原因造成的:

  • GIN 的聚合器是专门设计来鉴别 GCN 的聚合器不能鉴别的图形
  • 来自每一层的图形隐藏向量被连接,而不是仅考虑最后一层的
  • 求和算子优于均值算子(至少在理论上)。

让我们想象一下我们用 GCN 和杜松子酒分类的蛋白质。

作者图片

有趣的是,这两个模型犯了不同的错误。当不同的算法应用于同一问题时,这是机器学习中的一个常见结果。

我们可以通过创建一个合奏来利用这种行为。有许多方法可以组合我们的图形嵌入。最简单的方法是取归一化输出向量的平均值。

**GCN** test accuracy     = **59.38%**
**GIN** test accuracy    = **73.70%**
**GCN+GIN** test accuracy= **75.00%**

这一次,我们很幸运地看到精度提高了

显然,并不总是这样。更复杂的方法包括为分类建立一个完全不同的 ML 算法,比如随机森林。该分类器将图嵌入作为输入,并输出最终的分类。

结论

图同构网络是理解 GNNs 的重要一步。

它们不仅提高了几个基准测试的准确度,还提供了一个理论框架来解释为什么一个架构比另一个更好。在这篇文章中,

  • 我们看到了一个带有图分类的新任务,使用全局池执行;
  • 我们介绍了 WL 测试及其与新 GIN 层的联系;
  • 我们实现了一个杜松子酒和一个 GCN,并用它们的分类做了一个简单的合奏。

尽管 GINs 取得了很好的性能,特别是在社交图方面,但它们的理论优势在现实世界中并不总是很好。其他“可证明强大的”架构也是如此,它们在实践中往往表现不佳,比如 3WLGNN。

如果你喜欢这篇文章,请在推特上关注我,获取更多的图片内容。📣

参考

[1]克里斯多夫·莫利斯和尼尔斯·m·克里格和弗兰卡·鲍斯和克里斯蒂安·克尔斯汀和佩特拉·穆策尔和马里恩·诺依曼。TUDataset:一个用于图形学习的基准数据集集合。在 ICML 2020 年关于图形表示学习和超越的研讨会

[2]徐、柯玉禄、胡、、莱斯科维克、朱雷、杰格尔卡、。图形神经网络有多强大?在 ICLR 2019

相关文章

如何检测时间序列中的异方差

原文:https://towardsdatascience.com/how-to-detect-heteroskedasticity-in-time-series-3413a8aa8da9

时间序列中非恒定方差的检测和处理

Jannes Glas 在 Unsplash 上的照片

如果时间序列的方差随时间变化,那么它就是异方差的。否则,数据集是同质的。

异方差影响时间序列的建模。因此,检测和处理这种情况非常重要。

介绍

让我们从一个直观的例子开始。

下图 1 显示了热门航班乘客的时间序列。你可以看到不同系列的变化是不同的。在数列的后半部分,方差更大。这也是数据水平较高的地方。

图 1:某航空公司的月度乘客。数据集在 pmdarima Python 库中公开。图片作者。

方差的变化对于预测是有问题的。它会影响适当模型的拟合,从而影响预测性能。

但是,仅目视检查是不实际的。你如何以一种更系统的方式发现和处理异方差?

检测异方差

您可以使用统计测试来检查时间序列是否异方差。其中包括以下内容:

这些测试的主要输入是回归模型的残差(如普通最小二乘法)。零假设是残差以等方差分布。如果 p 值小于显著性水平,我们拒绝这个假设。这意味着时间序列是异方差的。显著性水平通常设置为高达 0.05 的值。

statsmodels Python 库实现了上述三个测试。下面是一个片段,它将这些封装在一个类中:

import pandas as pd
import statsmodels.stats.api as sms
from statsmodels.formula.api import ols

TEST_NAMES = ['White', 'Breusch-Pagan', 'Goldfeld-Quandt']
FORMULA = 'value ~ time'

class Heteroskedasticity:

    @staticmethod
    def het_tests(series: pd.Series, test: str) -> float:
        """
        Testing for heteroskedasticity

        :param series: Univariate time series as pd.Series
        :param test: String denoting the test. One of 'white','goldfeldquandt', or 'breuschpagan'

        :return: p-value as a float.

        If the p-value is high, we accept the null hypothesis that the data is homoskedastic
        """
        assert test in TEST_NAMES, 'Unknown test'

        series = series.reset_index(drop=True).reset_index()
        series.columns = ['time', 'value']
        series['time'] += 1

        olsr = ols(FORMULA, series).fit()

        if test == 'White':
            _, p_value, _, _ = sms.het_white(olsr.resid, olsr.model.exog)
        elif test == 'Goldfeld-Quandt':
            _, p_value, _ = sms.het_goldfeldquandt(olsr.resid, olsr.model.exog, alternative='two-sided')
        else:
            _, p_value, _, _ = sms.het_breuschpagan(olsr.resid, olsr.model.exog)

        return p_value

    @classmethod
    def run_all_tests(cls, series: pd.Series):

        test_results = {k: cls.het_tests(series, k) for k in TEST_NAMES}

        return test_results

类别异方差包含两个函数。函数 het_tests 应用了一个特定的测试(White、Breusch-Pagan 或 Goldfeld-Quandt)。函数 run_all_tests 一次性应用所有三个测试。这些函数的输出是相应测试的 p 值。

下面是如何将这些代码应用于图 1 中的时间序列。

from pmdarima.datasets import load_airpassengers

# https://github.com/vcerqueira/blog/blob/main/src/heteroskedasticity.py
from src.heteroskedasticity import Heteroskedasticity

series = load_airpassengers(True)

test_results = Heteroskedasticity.run_all_tests(series)

# {'Breusch-Pagan': 4.55e-07,
# 'Goldfeld-Quandt': 8.81e-13,
# 'White': 4.34e-07}

所有测试的 p 值都接近于零。所以,你可以拒绝零假设。这些测试为异方差的存在提供了令人信服的证据。

以下是时间序列前半部分和后半部分的残差分布:

图 2:时间序列前半部分和后半部分的残差分布。图片作者。

这两部分的残差分布是不同的。Goldfeld-Quandt 检验使用这种类型的分割来检验异方差性。它检查两个数据子样本中残差的方差是否不同。

转换数据

时间序列中异方差的一个常见补救方法是转换数据。对时间序列取对数有助于稳定其可变性。

这是与之前相同的时间序列,但采用对数标度:

图 3:与图 1 相似,但采用对数标度。这里,时间序列显示了一段时间内的稳定变化。

这一次,这个系列的可变性看起来很稳定。让我们使用对数标度的时间序列重新运行测试:

import numpy as np

test_results = Heteroskedasticity.run_all_tests(np.log(series))

# {'Breusch-Pagan': 0.033,
# 'Goldfeld-Quandt': 0.18,
# 'White': 0.10}

这次 p 值更大。只有一个测试(Breusch-Pagan)拒绝了恒定方差的假设。假设显著性水平为 0.05

恢复日志转换

假设您正在使用经过对数转换的数据进行预测。在这种情况下,您需要将预测恢复到原始比例。这是通过变换的逆变换来完成的,在对数的情况下,您应该使用指数。

因此,预测流程的步骤如下:

  1. 转换数据以稳定方差;
  2. 拟合预测模型;
  3. 获取预测,并将其还原到原始比例。

这里有一个例子。

import numpy as np
from pmdarima.datasets import load_airpassengers
from pmdarima.arima import auto_arima
from sklearn.model_selection import train_test_split

series = load_airpassengers(True)

# leaving the last 12 points for testing
train, test = train_test_split(series, test_size=12, shuffle=False)
# stabilizing the variance in the train
log_train = np.log(train)

# building an arima model, m is the seasonal period (monthly)
mod = auto_arima(log_train, seasonal=True, m=12)

# getting the log forecasts
log_forecasts = mod.predict(12)

# reverting the forecasts
forecasts = np.exp(log_forecasts)

图 4:在对转换后的序列建模后,将预测恢复到原始规模。图片作者。

外卖

  • 如果方差不是常数,时间序列就是异方差的;
  • 您可以使用统计测试来测试时间序列是否异方差。这些包括白布鲁希-帕甘试验,或戈德菲尔德-夸特试验;
  • 使用对数变换来稳定方差;
  • 不要忘记将预测恢复到原来的比例。

感谢阅读,下一个故事再见!

进一步阅读

[1]圣母大学理查德·威廉斯的幻灯片讲义。https://www3.nd.edu/~rwilliam/stats2/l25.pdf

[2] Statsmodels 用于白色测试戈德菲尔德-夸恩特测试布鲁赫-帕甘测试的文档。

如何检测数据科学项目中的异常值

原文:https://towardsdatascience.com/how-to-detect-outliers-in-a-data-science-project-17f39653fb17

检测异常值的三种方法,以及 Python 中的示例

威尔·梅尔斯在 Unsplash 上拍照

在一个数据科学项目的开始,一个重要的部分是离群点检测。当我们执行探索性数据分析时,事实上,要做的事情之一是发现异常值并以某种方式对待它们。

在本文中,我们将看到三种检测异常值的方法。但是,在此之前……什么是离群值?让我们引用维基百科:

在统计学中,异常值是与其他观察值显著不同的数据点。异常值可能是由于测量中的可变性造成的,或者它可能表明实验误差;后者有时被排除在数据集之外。异常值会在统计分析中引起严重的问题。

因此,异常值是指相对于我们正在分析的其他数据而言,值过高或过低的数据。当然,在一个数据集中我们不会找到一个唯一的异常值:有几个异常值;这就是为什么我们经常将它们从数据集中排除:否则,异常值会在我们的分析中引起统计问题。

但是排除离群值的标准是什么呢?我们会看到三种方法。

1.图解方法

这是我最喜欢的方法,因为它给了你决定的权力;事实上,正如我之前所说的,我们经常从数据集中删除离群值,由于这种方法是图形化的,您负责决定删除哪些离群值;此外,你决定哪些数据必须被认为是离群值,只是看着图。

让我们看几个我做过的项目的例子。

首先,假设我们有一个名为“cons”的数据框架;让我们用 seaborn 创建一个散点图:

import seaborn as sns*#plotting the scatterplot* 
sns.relplot(data=food, x='mean', y='latitude')

*#defining the size of the figure*
sns.set(rc={'figure.figsize':(30,15)})

*#labeling*
plt.title(f'MEAN PRODUCTION PER LATITUDE', fontsize=16) *#plot TITLE*
plt.xlabel('Mean production [1000 tons]', fontsize=14) *#x-axis label*
plt.ylabel('Latitude', fontsize=14) *#y-axis label*

*#showing grid for better visualization*
sns.set_style("ticks",{'axes.grid' : True})

散点图。图片作者。

不考虑“纬度”和“平均产量”指的是什么,只看数据:哪些点你会认为是异常值?这里我们清楚地看到,异常值只是“较高”的数字;您可以决定离群值是那些值大于 75'000 的值。即使 50 英尺也行。你照我说的做决定;而是决定一个整体的分析(仅仅这个情节是不够的)。

无论如何,这是一种检测异常值的方法。还有一种图形方法是绘制箱线图。让我们看看我的一个项目中的另一个例子。

假设我们有一个数据帧叫做“相位”;我们想画一个箱线图:

import seaborn as sns#boxplot
sns.boxplot(data=phase, x='month', y='time')#labeling
plt.title(f"BOXPLOT", fontsize=16) #plot TITLE
plt.xlabel("MONTH", fontsize=14) #x-axis label
plt.ylabel("CYCLE TIME[m]", fontsize=14) #y-axis label#adding an horizotal line to the mean cycle time
plt.axhline(mean, color="red") 
red_line = mpatches.Patch(color="red",
label=f"mean value: {mean:.1f} [m]")#handling the legend
plt.legend(handles=[red_line],prop={"size":12})

箱线图。图片作者。

即使在这里,让我们只考虑情节,而不是 x 和 y 的意思。即使在这里,异常值也只是那些具有“较高”值的异常值(小点)。使用箱线图,您的控制会少一点,但是异常值是基于统计数据检测出来的:在这种情况下,是那些值大于最大值的异常值;请记住,在箱线图中,最大值的计算方法是“Q3+1.5*IQR”,其中 IQR 是四分位数间距,计算方法是 IQR=Q3-Q1,其中 Q1 是第一个四分位数,Q3 是第三个四分位数。

使用这种图形方法,您对哪些点被认为是异常值的控制会少一些,考虑到值;我会说更好:你有一个统计(图形)方法来定义哪些值可以被认为是离群值;因此,这不是“你决定一切”:在这里,统计数据可以帮助你,我发现这是一个非常好的方法。

这些图形方法只有一个很大的缺点:它们只能用于二维数据。我的意思是,如果只有一列表示输入,一列表示输出,就可以使用这些图。例如,如果你有 20 列代表输入数据,一列代表输出,如果你想使用这些图,你必须绘制 20 个图形;如果有 100 列代表输入呢?你可以理解这些方法非常强大,但是只能在有限的情况下使用。那么,我们需要别的东西。

2.Z 得分法

Z-score,也称为“标准分数”,是一种统计方法,它告诉你给定的观察值与平均值相差多少标准差。

例如,Z 值为 1.2 意味着数据点距离平均值有 1.2 个标准差。

用这种方法,你必须定义一个阈值:当一个数据点的值大于阈值,那么它就是一个异常值。

我们计算 Z 如下:

Z 的公式。图片作者。

其中:

  • x 是数据点的值
  • μ是平均值
  • σ是标准偏差

举个例子吧。假设我们有这些数字:

import numpy as np#my random data
data = [1, 2, 2, 2, 3, 1, 1, 15, 2, 2, 2, 3, 1, 1, 2]#calculating mean
mean = np.mean(data)#calculating standard deviation
std = np.std(data)#printing values
print(f'the mean is: {mean: .2f}')
print(f'the standard deviation ins:{std: .2f}')----------------->>>the mean is:  2.67
the standard deviation ins: 3.36

现在,我们可以设置一个阈值来识别异常值,如下所示:

#treshold
threshold = 3#list of outliers
outlier = []#outlier detection
for i in data:
    z = (i-mean)/std
    if z > threshold:
        outlier.append(i)

print(f'the outliers are: {outlier}')----------------->>>the outliers are: [15]

我们甚至可以使用 Scipy 库中的“stats.zscore ”,它可以应用于 Numpy 数组和数据帧。让我们以数据框为例:

import pandas as pd
import scipy.stats as stats#creating dataframe
data = pd.DataFrame(np.random.randint(0, 10, size=(5, 3)), columns=['A', 'B', 'C'])#z-score
data.apply(stats.zscore)---------------->>>

     A          B           C
0 -0.392232  -0.707107   0.500000
1 -0.392232  -0.353553   -1.166667
2 1.568929    1.767767    1.333333
3 -1.372813  -1.060660   -1.166667
4 0.588348    0.353553    0.500000

在这种情况下,我们必须定义一个阈值,并决定删除哪些值。

Z 分数法有几个缺点:

  • 它只能与一维数据(单列数据帧、数组、列表等)一起使用
  • 它必须与正态分布数据一起使用
  • 我们必须根据数据定义一个阈值

3。隔离林

我们来理解一下什么是隔离森林,引用维基百科:

隔离森林是一种异常检测算法。它使用隔离(一个数据点到其余数据的距离)来检测异常,而不是对正常点进行建模

更深入地说,我们可以说隔离森林是基于决策树构建的,类似于随机森林,它是一个无监督的模型,因为没有预定义的标签。它只不过是一个二元决策树的集合,其中每棵树都被称为一棵“隔离树”。

这意味着在隔离林中,我们根据随机选择的特征,在树形结构中处理随机子采样数据。深入到树中的样本不太可能是异常,因为它们需要更多的切割来隔离它们。

让我们以 scikit-learn 提供的著名“糖尿病数据集”为例:

from sklearn.datasets import load_diabetes #importing data
from sklearn.ensemble import IsolationForest #importing IF#importing dataset
diab = load_diabetes()#defining feature and label
X = diab['data']
y = diab['target']#creating dataframe
df = pd.DataFrame(X, columns=["age","sex","bmi","bp", "tc", "ldl", "hdl","tch", "ltg", "glu"])#checking shape
df.shape------------------>>>(442, 10)

因此,该数据帧有 442 行和 10 列。现在让我们使用隔离林:

#identifying outliers 
iso = IsolationForest()
y_outliers = iso.fit_predict(df)#droping outliers rows
for i in range(len(y_outliers)):
    if y_outliers[i] == -1:
        df.drop(i, inplace = True)#chechink new dataframe shape
df.shape--------------------->>>(388, 10)

正如我们所看到的,行数减少了,因为我们删除了有异常值的行。

我们不得不提醒,我们已经使用了一个集合,无监督的模型;这意味着,如果我们再次运行所有代码,最终的形状(删除有异常值的行后的数据框的形状)可能与 388 不同(作为练习,自己尝试一下)。

隔离森林,即使没有给你留下任何对数据的控制权(是一个无监督的模型),也是我们在本文中看到的三个模型中唯一的一个,它给了我们在多维数据框架中处理(和丢弃对象的可能性;事实上,我们已经处理了整个数据集,没有减少它。

结论

我们已经看到了三种检测异常值的方法。正如我们已经看到的,隔离森林是(三个中)唯一一个让我们处理多维数据的,所以通常是要使用的一个;除非我们正在研究一组非常简单的数据,在这些数据中我们可以使用图形方法(我是图形的忠实粉丝!)或 z 值。

我们一起连线吧!

中等 (跟我来)

LINKEDIN(向我发送连接请求)

如果你愿意,你可以 订阅我的邮件列表 这样你就可以一直保持更新了!

考虑成为会员:你可以免费支持我和其他像我一样的作家。点击 这里的 成为会员。

如何开发气流 CD 管道

原文:https://towardsdatascience.com/how-to-develop-a-cd-pipeline-for-airflow-9a99047907ee

利用 GitHub actions 和天文学家将代码更新快速推送到生产环境中

照片由迈克·本纳Unsplash 拍摄

Apache Airflow 是一个流行的数据编排工具,用于管理工作流和任务。然而,我不断遇到的一个大问题是如何部署生产就绪的气流实例。托管气流的选项包括虚拟机上的自我管理、部署到基于云的平台天文学家、利用 AWS MWAA 等等。

在这些选项中,我发现天文学家在易用性和每月成本方面是最有价值的,尽管在本文中我不会深入到特定平台的比较中。

天文学家是软件/基础设施即服务平台,使数据团队能够更专注于他们的工作流和管道,而不是基础设施和扩展。在本文中,我打算演示如何在不到 10 分钟的时间内,从本地气流环境中自动完成到天文学家的连续部署(CD)管道。

要求

  1. 天文气候 ( 文件)
  2. 天文学家账户
  3. 码头工人
  4. 通过 astro 运行的局部气流
  5. 本地气流实例的 GitHub 帐户和存储库
  6. GitHub 操作

第一步是用 astro CLI 初始化本地气流实例。用astro dev init初始化你的气流项目。然后,用astro dev start测试您的本地环境。

在您的项目目录(git init)中初始化一个新的 Git 存储库,并推送到 GitHub。

天文学家

在您的天文学家帐户中,确保当前部署处于活动状态。在活动部署中创建新的服务帐户。服务帐户将是您的 Github repo 和您部署的 Airflow 实例之间的纽带。确保在创建服务帐户时复制 API 密钥,这是您唯一的机会。

天文学家仪表板和服务帐户作者的照片

使用 astro CLI,通过astro loginastro auth login登录您的天文学家账户。这将提示您输入电子邮件和密码,或者 oauth 凭证。然后运行astro cluster list来获得你的基本域名(后面会提到)。比如gcp0001.us-east4.astronomer.io

要验证服务帐户的创建,请在终端中运行以下命令:

export BASE_DOMAIN=gcp0001.us-east4.astronomer.io
export API_SECRET_KEY=<your_secret_key_for_service_account>
docker login registry.{BASE_DOMAIN} -u _ -p ${API_SECRET_KEY}

如果您能够通过这些命令进行身份验证,那么一切都将步入正轨。

开源代码库

创建一个新的 GitHub secret 来保存天文学家服务帐户 API 密钥。创建一个名为ASTRONOMER_SERVICE_ACCOUNT_KEY的新存储库秘密,并粘贴 API 键值。天文学家的 GitHub actions 工作流在将代码推向生产时会引用这个秘密。

接下来,在存储库中创建新的工作流操作。通过 GitHub 动作选择Docker image。此工作流构建 Docker 映像以部署或推送至存储库。使用这个预配置的main.yml文件(如下)来构建您的 dockerized airflow 实例。

确保添加{ your_release_name }而不是primitive-asteroid-5670。这可以在你的天文学家部署设置中找到。

还要注意,在第 13 行,您需要用 Dockerfile 位置的目录建立workdir。当工作流在 GitHub actions 上运行时,它会将您的存储库编译到一个虚拟环境中,并且需要引用 Dockerfile。在我的 repo 中,Dockerfile 位于 airflow 子目录中。

测试

我们现在准备测试!在 GitHub 上打开一个 PR,将变更合并到devmain中。将代码合并到所需的分支中,工作流就开始了。完成后,您可以查看您的天文学家仪表板,将会看到当前标签的格式:cd-commit hash

作者照片。天文学家中的部署标签示例。

现在,您的气流存储库已启用持续交付/部署管道!如需更多信息/调试帮助,请查看这些文档

概括地说,在本文中,我们通过 GitHub actions 将在天文学家上部署本地天文/气流环境的任务自动化,并开始为 CI/CD 管道奠定基础。

CI/CD 使团队能够采用更“敏捷”的开发框架。我最喜欢的 CI/CD 渠道目标包括:

  1. 效率—减少建立开发环境所花费的时间
  2. 自动发布—避免堵塞和人为错误
  3. 快速部署代码—消除瓶颈,让代码更快投入生产
  4. 拥抱迭代——通过频繁的变更而不是单一的提交和发布来缩短反馈周期

查看这篇帖子,了解更多与敏捷和 CI/CD 相关的目标。

我们实现了一个简单的 CD 管道(只有一个生产环境),但我们也可以利用在天文学家上的多个部署来快速扩展并包括开发和 QA 环境。这将为您的气流环境提供更强大的开发和发布流程。

如何在本地开发和测试您的谷歌云功能

原文:https://towardsdatascience.com/how-to-develop-and-test-your-google-cloud-function-locally-96a970da456f

因此,您已经编写了无服务器云功能,但不想浪费时间部署它并希望它能工作。让我向您展示如何在本地开发和测试您的云功能。

托马斯·索贝克在 Unsplash拍摄的照片

快速介绍:云函数

如果你正在阅读这篇文章,我相信你已经知道什么是谷歌云功能。但以防万一,这是一个无服务器的计算产品,它允许你编写函数,当附加到它的事件被触发时,这些函数就会被触发。

由于这是一项无服务器服务,我们不必担心设置或管理服务器或任何基础设施。这种产品也被称为功能即服务(FaaS)。查看以下文章,了解更多信息,并了解如何在生产中使用它:

绕远路之后,让我们回到我们为什么在这里。

本地开发设置

要在本地开发云功能,我们需要安装功能框架。functions 框架允许我们快速启动本地开发服务器进行测试。您可以在本地调用该函数,它会像在生产环境中一样做出响应。

唯一的区别是在本地完成它允许我们快速调试和迭代,而不是等待很长时间来部署它,然后发现是否有错误!是的,部署需要很长时间!😅

在我们安装之前,请确保创建一个虚拟环境来处理项目。为什么?因为这是一个很好的实践,尤其是当你打算生产它的时候。这适用于任何 python 项目,而不仅仅是这个项目。

如您所知,云功能需要两个文件:

  • main.py: 其中函数的主代码是。
  • requirements.txt: 需要安装的所有库的列表,以使函数工作。

一旦我们的功能为生产做好准备,创建虚拟环境将允许我们轻松地创建需求文件。例如,在 conda 虚拟环境中,我可以运行以下代码来生成需求文件:pip list --format=freeze > requirements.txt

说完这些,让我们从一些代码开始。💻

地方发展步骤

按照以下步骤在本地开发和测试云功能:

步骤 0:目录和虚拟环境

为云功能项目创建一个虚拟环境和一个目录。我在虚拟环境中使用 conda 作为 Anaconda 安装的一部分。

  • 在 Windows 机器上,在命令行中使用mkdir YOUR_DIRECTORY_NAME创建目录。
  • 对于公寓虚拟环境,使用conda create --name YOUR_ENV_NAME python=3.8用 python 版创建一个虚拟环境。
  • 要激活环境,使用conda activate YOUR_ENV_NAME

⚠️ 注: 如果你不关心虚拟环境和项目间的分隔,忽略步骤 0。第一步是导入的开始!

步骤 1:安装功能框架

使用以下内容安装函数框架:

pip install functions-framework

第二步:功能代码主文件

像平常一样,在工作目录中为云函数创建一个 main.py 文件。出于本文的目的,我创建了一个示例文件 main.py

它所做的只是检查是否发送了任何 JSON 有效载荷,并尝试提取作为有效载荷一部分发送的名称。然后它会对名字打招呼。

使用 hello 响应 JSON 有效负载的云函数。(来源:作者)

步骤 3:启动本地开发服务器

在与 main.py 文件相同的目录下,在命令行/终端中运行以下命令来启动一个开发服务器,为您的云功能服务:functions_framework --target=say_hello

上面的代码将 main.py 文件加载到开发服务器中,并指向 say_hello 作为入口点函数。

您现在应该能够调用这个函数了,它在您的本地主机上可用,很可能在端口 8080 上。(http://localhost:8080)

本地机器上运行的云函数。使用虚拟环境(func_local)。(来源:作者)

请注意,这类似于在云中部署该功能。如果有一个库没有安装在本地环境中(类似于在生产环境中 requirements.txt 文件中没有它),服务器将抛出一个错误,就像在生产环境中一样。

例如,我知道在我的虚拟环境中没有安装 XGBoost 库。如果我现在编辑 main.py 来添加import xgboost,保存文件,并通过重新运行上面的代码来重启服务器,它应该会抛出一个错误。为了本地部署成功,我需要在我的虚拟环境中安装这个库。

在编辑 main.py 文件以导入 XGBoost 后,当我尝试再次启动服务器时出错。(来源:作者)

好了,现在我们已经运行了开发服务器,我们需要调用这个函数。

步骤 4:调用本地部署的函数

调用该函数类似于您通常会做的事情。您所要做的就是指向正确的 HTTP 端点。在这种情况下,端点位于本地主机上。您可以使用 cURL 或 python 中的请求库来调用该函数。

出于本文的目的,我编写了一个调用本地部署的云函数的 invoker 函数。它只传递我的名字作为键 hello 的值。

当您运行上面的代码(> python local_func_invoker.py)时,您应该会看到它打印出hello saed,这是来自本地部署的云函数的响应。

调用本地部署的云函数并打印其响应。(来源:作者)

函数框架开发服务器响应传入的请求。(来源:作者)

瞧!现在,您已经了解了在本地开发和测试 Google Cloud 功能所需的一切。

⚠️ 注意: 如果您使用前面提到的方法从虚拟环境中生成 requirments.txt 文件,请确保删除 functions_framework 库,因为我们不需要在生产中安装它。Google Cloud Functions 产品就是建立在这个框架之上的!😄

最后的想法

至少可以说,在等待谷歌云部署很长时间之后,试图在生产中调试它是令人沮丧的。在本文中,我们学习了如何在本地机器上开发和测试 Google Cloud 功能。

有很多方法可以定制函数框架,为了简洁起见,我没有介绍。我强烈推荐查看这个框架的页面和这个框架的 python 版本的 GitHub repo

我们简要介绍了在任何本地开发中使用虚拟环境的最佳实践。这非常有用,尤其是对于生成生产中需要的 requirements.txt 文件。

恭喜你!!您现在知道如何在本地开发和测试您的 Google Cloud 功能,并在转移到生产时节省大量时间和麻烦。🎊

🚀希望这篇文章对你有用。 如果你愿意支持我,可以考虑使用我的 推荐链接 加入 medium。

这样你就可以在这个平台上看到我所有的文章以及更多来自其他优秀作者的文章!😄

您可能喜欢的其他文章:

作为数据科学家,如何开发在线收入流

原文:https://towardsdatascience.com/how-to-develop-online-revenue-streams-as-a-data-scientist-af290fad64ef

探索一些不同的方法,可以用来创造一个网上收入。

Chiara Daneluzzi 在 Unsplash 上拍摄的照片

介绍

在一家公司担任数据科学家可能是一个非常有益的机会,2021 年美国的平均工资约为 117,806 美元[1]。尽管如此,作为一名数据科学家也有可能创造不同的收入流,你可以利用这些收入流来获得额外收入或创建自己的企业。

作为本文的一部分,我们将探索一些最常见的技术,你可以使用这些技术来开始使用你的在线技能来获得某种形式的收入(图 1)。

图 1:附带收入技术(图片由作者提供)。

当自由职业者

作为一名自由职业者,这是一种最常见的兼职方式。在这种情况下,你可以提出解决数据科学/机器学习问题,并设定每小时/项目的预期成本。为了推广您的服务并获得潜在客户的联系,一些最常用的平台是:

如果你决定选择 Upwork,该平台最近还允许你分享你的 Azure 认证,以便从其他自由职业者中脱颖而出。

在线竞赛/黑客马拉松

专业地参加在线竞赛和黑客马拉松也是另一项不错的投资,因为这类活动挑战你学习新技术和在压力下工作,同时给你赢得可观奖金的可能性。

对于数据科学来说, Kaggle 是迄今为止最受欢迎的平台之一,可以参加这类比赛,奖金高达 10 万美元。类似的比赛还可以在 DrivenDataTopcoder 等平台上找到。

或者,您可以使用许多不同的其他在线平台来尝试找到您喜欢的竞争对手,例如:

最后,大型科技公司和大学也倾向于组织这种比赛,如果你有兴趣亲自参加当地的比赛,这可能是一个很好的起点。

举个例子,在过去的几年里,我有机会参加由脸书、谷歌和摩根大通等公司组织的不同的黑客大会。参加这种活动不仅挑战我在短时间内学习新的东西,而且使我有可能与志同道合的人建立新的联系,甚至赢得一些奖项!

创建教育内容

创建在线教育内容是挑战自己的另一个很好的方式,它可以让你在获得额外收入的同时跟上专业领域的最新发展。

你可以采取的一些可能的方法是创造:

  • 博客(例如媒体合作伙伴计划,个人网站)
  • YouTube 视频
  • 在线课程(如 Udemy、Skillshare、Educative.io)
  • 有免费和付费层的时事通讯(杂志,子栈)
  • 在线活动/会议讲座

例如,在介质上写作使我能够不断提醒自己学习新的东西,并且由于这一点,后来我也有机会被邀请在英国、德国和意大利的会议和在线活动上发言!

职业发展顾问

一旦你成为一名有经验的专业人士,你还可以通过向缺乏经验或打算转行的人提供不同形式的服务来获得额外收入。一些例子是:

  • 指导(如跳板、指导俱乐部、敏捷、速滑、指导俱乐部)
  • 模拟面试
  • 数据科学辅导

此外,现在也存在不同的在线平台,如 TechTree ,它可以通过向朋友/同事推荐新的工作机会来获得奖励。

就我而言,我以前作为最终用户使用过辅导网站,我一直觉得它们非常有用,尤其是在考虑去另一个国家找新工作的时候(以便更多地了解那里的文化和该地区可能的薪资范围)。

为开源做贡献

从事开源软件也有可能提供许多不同形式的回报。一些例子是:

  • 为专业人士和企业创建一个具有免费层和付费层的开源库(例如,Plotly 和 Streamlit 等 Python 库遵循这种方法)。
  • 加入付费开源贡献计划,如Google Season of Docs(Season of Docs 是 Google 组织的一项年度计划,旨在将技术作者与开源组织联系起来,以改进图书馆文档)。
  • 为您的免费服务创建一个捐赠页面,使您的用户能够帮助您维护您的项目(例如 Github 捐赠按钮、给我买杯咖啡、Patreon 等)。
  • 使用在线市场,如 GitMarket ,出售你的私有 Git 库和代码片段

销售数码产品

如今,在网上创造一个产品并尝试在各种网络平台上销售是非常容易的。数字产品的一些例子可以是:

  • 书籍、教程、文章、模板
  • 按需提供的应用编程接口(API)

为了销售数码产品,最常用的平台之一是 Gumroad 。API 可以在平台上公开发布,比如 RapidAPI。如果您有兴趣了解更多有关如何创建自己的 API 并使其在线可用以产生利润的信息,请点击此链接获取更多信息。

例如,我在过去创建了一个 API 来自动将中型博客转换成 Markdown 格式(准备用于基于 Jekyll 的网站),并创建了一个数字产品来帮助概念用户创建学习笔记。

联系人

如果你想了解我最新的文章和项目,请在媒体上关注我,并订阅我的邮件列表。以下是我的一些联系人详细信息:

文献学

[1]Indeed.com,建立一份你会热爱的职业。访问地点:https://www.indeed.com/career/data-scientist/salaries

如何用 Python 做微积分

原文:https://towardsdatascience.com/how-to-differentiate-and-integrate-using-python-1dc9444c9278

学习如何使用 SymPy 计算符号方程的导数和积分

约书亚·阿拉贡在 Unsplash 上拍摄的照片

如果你像我一样,准确地记住如何微分和积分方程可能是一个挑战。或者你有一个很长很复杂的方程,你必须积分。根据方程式的不同,手工操作可能需要 10-15 分钟。你不会想这么做的。让我们学习使用 Python 来为我们完成繁重的工作,而不是手工完成所有这些工作。

导入 SymPy 库

与大多数 Python 项目一样,为了成功运行代码,您需要导入适当的库和包。在本文中,我们将使用 SymPy 库。它拥有我们区分和整合所需的一切。该库还包含了其他有用的函数,我们将在后面看到。

# Importing Library
import sympy

定义符号

现在我们已经导入了 SymPy ,我们可以用它来创建我们的符号,这些符号将用于创建方程。我们可以通过调用符号类并使用一个字符串来定义符号来实现。我通常使用与我将要用来操作符号的 Python 变量相同的字符串。

# Defining Symbols
x = sympy.Symbol("x")
y = sympy.Symbol("y")

创建方程式

让我们用刚刚定义的符号创建一个等式。我们可以创建以下等式:

下面是等效的代码:

# Creating Equation
f = x * y + x ** 2 + sympy.sin(2 * y)

区别

为了对等式进行微分,我们可以使用来自 SymPy 库的函数 diff 。你可能已经注意到,我们的方程有两个变量, xy 。这意味着我们可以区分这两个变量。 diff 函数允许我们选择想要用什么符号来微分,所以让我们对 x 求导。

# Differentiate wtr x
df_dx = sympy.diff(f, x)
print("The derivative of f(x,y) wrt x is: " + str(df_dx))

输出:

The derivative of f(x,y) wrt x is: 2*x + y

这个结果符合我们对这个导数的预期。 diff 函数的另一个特点是采用高阶导数。为了做到这一点,我们包括我们的方程,我们的符号和我们的函数中的导数阶。作为一个例子,让我们对 y 取二阶导数并打印结果。

# Second Derivative wrt y
d2f_dy2 = sympy.diff(f, y, 2)
print("The 2nd derivative of f(x,y) wrt y is: " + str(d2f_dy2))

输出:

The 2nd derivative of f(x,y) wrt y is: -4*sin(2*y)

综合

SymPy 也有一个易于使用的符号整合功能。我们可以使用之前创建的相同等式,并针对 x 对其进行积分。代码和输出如下所示。

# Integrate wrt x
F = sympy.integrate(f, x)
print("The integral of f(x,y) wrt x is: " + str(F))

输出:

The integral of f(x,y) wrt x is: x**3/3 + x**2*y/2 + x*sin(2*y)

同样, integrate 函数返回我们期望的结果。我们也可以用积分函数进行定积分。在下面的代码中,我们使用相对于 x 的边界 02 对原始方程进行积分。

# Definite Integral wrt x [0, 2]
F = sympy.integrate(f, (x, 0, 2))
print("The definite integral of f(x,y) wrt x with bounds [0, 2] is: " + str(F))

输出:

The definite integral of f(x,y) wrt x with bounds [0, 2] is: 2*y + 2*sin(2*y) + 8/3

SymPy 的其他有用函数

虽然本文的主要观点是区分和整合,但是 SymPy还有其他很棒的内置函数可能会派上用场。这些可以与积分和微分一起使用,使你的输出更容易理解。我经常使用的两个功能是:

  • 简化是一个很棒的函数,可以用来把一个方程简化成更简单的形式。例如,我们可以简化以下等式:

# Simplifying Equations
g = (x * sympy.tan(x) + x ** 2 * sympy.sin(x))/sympy.sin(x)
g = sympy.simplify(g)
print("The simplified form of g(x) is: " + str(g))

输出:

The simplified form of g(x) is: x*(x + 1/cos(x))
  • Solve 是另一个很棒的函数,可以用来解代数方程组。要使用求解功能,我们需要调整方程组,使其中一边等于零。然后,我们可以使用如下图所示的求解函数,得到 xy 的答案。假设我们有以下一组等式:

# Solving System of Equations
sol = sympy.solve((x + y - 3, 2 * x + 3 * y - 7), (x, y))
print("The solution of the system is (x, y): (" + str(sol[x]) + ", " + str(sol[y]) + ")")

输出:

The solution of the system is (x, y): (2, 1)

现在,您可以使用 Python 进行整合和区分。这些函数可以用来双重检查你的工作或者作为一个快速的解决方案(当然是双重检查数学!).

感谢您阅读文章!如果你有任何问题,请留言告诉我。如果你喜欢阅读,给我一个关注,看看我的其他 Python 和工程文章!

如何对时间序列进行 EDA

原文:https://towardsdatascience.com/how-to-do-an-eda-for-time-series-cbb92b3b1913

熊猫-剖析时间序列探索性分析

Unsplash 上由 Aron 视觉拍摄的照片

数据科学开发周期的早期步骤之一是理解和探索您正在解决的问题的数据。EDA 是更好的数据科学工作流的关键一步,Pandas profiling 是我的首选,它可以用一行代码快速完成,同时为我提供更好地理解数据和发现有意义的见解的输出。

您可能一直在使用 Pandas Profiling 来分析结构化表格数据,这通常是我们学习探索的第一种数据类型,我们都知道 Iris 数据集,对吗?然而,在现实世界的应用中,我们在日常生活中经常会发现另一种类型的数据结构:从交通,到我们的日常轨迹,甚至是我们的电力和水消耗,它们都有一个共同点——时间依赖性。

在一个越来越受数据驱动的世界中,时间序列或序列数据已经成为最有价值的商品之一,这使得执行 EDA 和挖掘时间序列数据成为数据科学从业者迫切需要的技能。

由于时间序列数据的性质,当探索数据集时,它的分析类型不同于当数据集记录被认为是全部独立时。随着在同一数据集中增加一个以上的实体,分析的复杂性也随之增加。

在这篇博文中,我将探索数据集分析中的一些关键步骤,同时利用 pandas 的时间序列特征进行分析。探索的数据集参考了美国的空气质量,可以从环保局网站下载。*

完整的代码和例子可以在 GitHub 库中找到,所以你可以跟随教程。

分析时序数据集中的多个实体

数据描述称,这是美国、波多黎各和美属维尔京群岛的户外监测器收集的空气质量数据。有了这些信息,我们知道这是一个多变量时间序列数据,有几个我们需要考虑的实体。

了解这一点后,我有一些后续问题:有多少位置可用于污染物测量?所有传感器在同一时间段内收集的数据量是否相同?收集的度量在时间和位置上是如何分布的?

这些问题中的一部分可以很容易地通过热图来回答,热图将所有测量和位置与时间进行比较,如下面的代码片段和图像所示:

使用 pandas-profiling 生成时间热图的代码

美国空气质量数据集热图(图片由作者提供)

上图展示了一段时间内每个实体的数据点。我们看到并非所有站点都同时开始收集数据,根据热图的强度,我们可以了解到在给定时间段内,一些站点比其他站点拥有更多的数据点。

这意味着在对时间序列建模时,为训练和测试数据集使用动态时间戳可能比使用预先确定的时间戳更好。我们还必须进一步调查丢失的记录和输入记录的范围。

有了对我们的实体时间分布的基本理解,我们可以开始深入数据分析以获得更多的见解。由于有多个时间序列,让我们来看看每个实体的行为。

对时间序列指标的探究

如果您已经在使用 pandas-profiling,您可能知道如何生成配置文件报告

可以通过传递参数 tsmode = true 来启用对时间序列的支持,并且库将自动识别具有自相关的特征的存在(稍后将详细介绍)。为了让分析正常工作,数据帧需要按照实体列和时间进行排序,否则您总是可以利用 sortby 参数。

这方面的代码非常简单:

下面是使用时序模式时输出报告的样子:

熊猫概况报告的截屏(作者截屏)

季节性和不稳定的警报

具体到时间序列分析,我们可以发现两个新的警告— 非平稳季节性。快速掌握你的时间序列的最简单的方法是查看警告部分。对于这个特定的用例,每个配置文件报告将描述每个美国位置在污染物测量方面的特定行为。

以下是我们报告中的警告:

分析中的警报。(作者截屏)

当一个时间序列的统计特性(如均值和方差)在观察时间内不发生变化时,称该时间序列是平稳的。相反,当时间序列的统计特性依赖于时间时,它是非平稳的。例如,具有趋势和季节性的时间序列(稍后将详细介绍)不是静态的,这些现象会影响时间序列在不同时间的值。

平稳过程相对更容易分析,因为时间和变量之间存在静态关系。事实上,平稳已经成为大多数时间序列分析的普遍假设。

虽然有针对非平稳时间序列的模型,但大多数 ML 算法确实期望输入特征和输出之间存在静态关系。当时间序列不稳定时,根据数据建模的模型的精度在不同点会有所不同。这意味着建模选择受到时间序列的平稳/非平稳性质的影响,当您想要将时间序列转换成平稳序列时,需要应用不同的数据准备步骤。

因此,此警报将帮助您识别此类列,并相应地预处理时间序列。

时间序列中的季节性是一种情况,在这种情况下,数据会经历定期和可预测的变化,这些变化在一个定义的周期内重复出现。这种季节性可能会在时间序列建模时掩盖我们希望建模的信号,甚至更糟的是,它可能会向模型提供一个强烈的信号。此警报可以帮助您识别此类列,并提醒您解决季节性问题。

关于时间相关特性的更多信息

您将注意到的第一个区别是,线形图将取代被标识为依赖于时间的列的直方图。使用线图,我们可以更好地理解所选列的轨迹和性质。对于该 NO2 均值线图,我们看到轨迹呈下降趋势,具有连续的季节变化,最大值记录在系列的初始阶段。

专栏的特征细节(按作者分类的图片)

接下来,当我们切换到该列的更多详细信息时(如上图所示),我们将看到一个带有自相关和偏自相关图的新选项卡。

对于时间序列,自相关显示了时间序列在其当前值与其先前值之间的关系。部分自相关是时间序列在去除先前时间滞后的影响后的自相关。这意味着这些图对于提供关于被分析序列的自相关程度以及移动平均程度的信息是至关重要的。

上面的 ACF 和 PACF 的情节有点像预期的那样模棱两可。纵观我们的警告,我们可以看到 NO2 意味着是一个非平稳的时间变量,这消除了这些图的可解释性。然而,ACF 图有助于证实我们已经怀疑的东西——NO2 意味着是非平稳的——因为 ACF 图值下降非常缓慢,而不是像平稳序列的情况下预期的那样快速下降到零。

从数据分析中收集的信息、时间序列的性质以及非平稳性和季节性等警报让您能够更好地理解手头的时间序列数据。这并不意味着您已经完成了探索性数据分析,我们的目标是将这些见解作为起点,继续进行深入的数据分析和进一步的数据准备步骤。

通过分析空气质量数据集,我们看到几个恒定的列,这些列在建模时可能不会增加太多价值。从缺失值图表中,我们看到 SO2 和 CO2 空气质量指数存在缺失数据,我们应进一步探讨这种情况的影响以及插补或完全删除这些列的范围。发现几个列具有非平稳和季节性警报,下一步将是使它们平稳或确保我们将使用的模型能够处理非平稳数据点。

您已经明白了——作为数据科学家,使用分析工具快速获得数据的整体视图(在我们的案例中是时间序列)并进一步检查数据预处理和建模阶段并做出明智的决策是非常重要的。

结论

熊猫概况的座右铭一直是一样的:“读数据?暂停。生成 Pandas Profiling 报告,并检查数据。现在开始清理,重新迭代探索数据。”

虽然结构化表格数据仍然是数据科学初级阶段最常见的数据,但时间序列数据被广泛使用,并且是许多业务和高级数据驱动解决方案开发的核心。由于时间序列的性质以及记录如何依赖于时间并影响未来事件,数据科学家在探索性数据分析阶段会寻求不同的见解。

因此,在 Pandas Profiling library 整合功能以启用时间序列分析模式来揭示这些见解之前,这只是一个时间问题。从用户获取特定于时间序列的分析报告所需的更改,到提示关注特定于时间序列分析的数据、折线图和关联图的新警报的输出,我们在本文中演示了所有内容。

但是今天探索的度量和分析仅仅是一个开始!更多的问题有待解答。对你来说,你通常用什么方法分析时间序列数据?使用顺序数据集时,您最怀念的是什么?

引文:

“EPA 美国环境保护署”(公共领域)【http://www.ics.uci.edu/~mlearn/MLRepository.html T2

法比亚娜 是 CDO 在y data

用改进的数据加速 AI。

如何在 MongoDB 中进行基本的全文搜索

原文:https://towardsdatascience.com/how-to-do-basic-full-text-searches-in-mongodb-48b17242676

通过 MongoDB 中的文本索引搜索您的文本数据

由于 MongoDB 是一个面向文档的 NoSQL 数据库,所以在一些字段中存储纯文本是很常见的。为了搜索字符串字段,我们可以直接使用正则表达式操作符[$regex](https://docs.mongodb.com/manual/reference/operator/query/regex/)。然而,$regex只能用于简单的搜索查询,不能高效地使用索引。

图片来自 Pixabay 的 DariuszSankowsk

在 MongoDB 中,有更好的方法来搜索字符串字段。一个经典的方法是创建一个text索引,并根据它进行搜索。尽管 MongoDB 现在支持一个“高级”全文解决方案,但是,它只有在您使用 Atlas 托管数据时才有效。由于在我们的工作中经常使用自我管理的 MongoDB 服务器,特别是对于一些小而简单的项目,因此值得学习和使用经典的文本搜索解决方案,它可以通过简单的查询显著提高您的搜索效率。正如后面将要演示的,大多数常见的搜索问题都可以通过使用text索引以及经典的 MongoDB 搜索和聚合查询来解决。

为了进行演示,我们将搜索存储在 MongoDB 数据库中的笔记本电脑列表。请下载这个 JSON 文件(由作者生成)包含一些虚构网店的笔记本电脑数据。请注意,数据是根据一些常见的笔记本电脑品牌随机生成的。它可以免费使用,不会有任何许可问题。然后使用以下命令导入数据:

当上面的代码运行时,我们将在products数据库中拥有一个包含 200 个笔记本电脑数据文档的laptops集合。这些文件的内容如下:

现在数据已经准备好了,我们可以开始创建一个text索引,并进行一些基本的全文搜索。

在本教程中,我们将使用mongosh直接运行查询。如果您需要编写一些复杂的查询,您可能会发现一个 MongoDB IDE 很有帮助,它提供了命令自动完成和错误突出显示。为了简单起见,我们将使用 Docker 容器附带的mongosh,因此我们不需要单独安装任何东西:

$ **docker exec -it mongo-server bash**$ **mongosh "mongodb://admin:pass@localhost:27017"**
test> **use products**
products > **show collections**
laptops

创建一个 **text** 指标

在我们开始之前,有一些重要的事情我们应该记住,即对于一个集合只能有一个 **text** 索引。

让我们在name字段上创建一个text索引,这是通过集合的createIndex()方法完成的:

products> db.laptops.**createIndex( { name: "text" } )** name_text

name是我们想要为其创建索引的字符串字段,而“text”值表示我们想要创建一个支持基本全文搜索的text索引。相比之下,要在 MongoDB 中创建一个常规索引,我们为一个字段指定 1 或-1,以指示该字段在索引中应该按升序还是降序排序。

在我们开始搜索text索引之前,我们应该知道尽管一个集合只能有一个text索引,但是这个索引可以覆盖多个字段。让我们删除上面创建的text索引,并创建一个包含nameattributes字段的新索引。

请注意,text索引可以有不同的名称,但是在一个集合中只能有一个text索引。

使用 **text** 索引的基本全文搜索

现在让我们使用刚刚创建的text索引进行一些基本的全文搜索。我们将使用$text查询操作符来执行文本搜索。例如:

$text操作符使用接受字符串值的$search字段进行文本搜索。在底层,搜索字符串使用空格和标点符号作为分隔符。对于生成的令牌,它们中的每一个都被独立地搜索,并用一个逻辑OR操作符连接。此外,默认情况下,搜索不区分大小写。如果您想进行区分大小写的搜索,您可以为$text操作符指定[$caseSensitive](https://docs.mongodb.com/manual/reference/operator/query/text/#case-and-diacritic-insensitive-search)字段。

因此,使用上面的搜索查询,我们得到的文档包含“HP”或“ProBook ”,但不一定两者都包含。

[
  { _id: 19, name: 'HP ZBook Model 19' },
  { _id: 20, name: 'HP ZBook Model 20' },
  { _id: 3, name: 'HP EliteBook Model 3' },
  { _id: 18, name: 'HP ProBook Model 18' },
  ...
]

按文本分数排序

重要的是,使用$text操作符,会为每个文档分配一个分数,表明文档与搜索字符串的匹配程度。如果“HP”和“ProBook”都匹配某个文档,则该文档的得分高于只匹配“HP”或“ProBook”的文档。我们可以根据分数对文档进行排序,用limit()方法只能得到最上面的。

可能看起来很奇怪,分数是用{$meta: "textScore"}表达式返回的。此外,乍一看可能更奇怪的是:

  • 给定的字段名称(score)并不重要。你可以给一个不同的名字,它仍然会工作。
  • 按分数排序始终是降序。这是有意义的,因为通常我们希望找到最相关的匹配。

通过这个查询,我们可以得到我们想要的最相关的结果:

[
  { _id: 15, name: 'HP ProBook Model 15' },
  { _id: 16, name: 'HP ProBook Model 16' },
  { _id: 18, name: 'HP ProBook Model 18' }
]

按短语搜索

如果我们只想找到完全包含“HP ProBook”的文档,我们可以通过短语进行搜索,只需将搜索字符串放在一对嵌套的引号中。我们可以交替使用单引号和双引号,或者用反斜杠对引号进行转义。以下查询将给出相同的结果:

在搜索查询中使用否定

我们还可以在我们的搜索查询中使用否定,这要求文档不匹配某些标记。让我们搜索“惠普”但不是“ProBook”的笔记本电脑:

在结果列表中,我们再也看不到“ProBook”了:

[
  { _id: 19, name: 'HP ZBook Model 19' },
  { _id: 20, name: 'HP ZBook Model 20' },
  { _id: 3, name: 'HP EliteBook Model 3' },
  ...
]

嵌套文档中的文本搜索

现在让我们用一个属性进行搜索,看看text索引是否同时覆盖了nameattributes字段:

请注意,我们需要按分数排序,否则最高的结果可能不是你所期望的。这是因为“HP 1TB”不是一个短语。实际上,“HP”出现在name字段中,而“1TB”出现在attributes.attribute_value字段中。由于默认情况下使用了OR逻辑运算符,返回的文档将包含“HP”或“1TB ”,但不一定两者都包含。使用sort()limit()方法,我们将返回最相关的结果,这些结果通常是我们想要的。

将$text 运算符与其他运算符结合使用

$text操作符可以和常规的 MongoDB 操作符一起使用。例如,让我们找到价格低于 10000 SEK 的 HP ProBooks:

这是我们得到的结果:

[
  { _id: 13, name: 'HP ProBook Model 13', price: 9994 },
  { _id: 9, name: 'HP ProBook Model 9', price: 9980 }
]

但是需要注意的是,搜索查询中应该只有一个$text操作符,否则只有最后一个有效。这是因为查询文档(Python 中的字典)不能有重复的键。

在聚合中使用$text 运算符

$text操作符也可以用在聚合管道中。但是,有三个主要限制:

  • $text操作器只能在$match阶段使用。
  • 包含$text运算符的$match阶段必须是管道的第一个阶段。
  • $text操作符在$match阶段和整个流水线中只能出现一次。

让我们为“HP ProBook”编写一个聚合管道来计算按 RAM 大小分组的笔记本电脑数量:

[
  { _id: '16GB', count: 2 },
  { _id: '8GB', count: 4 },
  { _id: '4GB', count: 1 }
]

它显示了$text操作符就像聚合管道中的任何其他常规操作符一样工作。

在本文中,我们介绍了 MongoDB 中使用text索引的经典文本搜索。由text索引和相应的$text操作符提供的全文搜索解决方案很简单,但也非常强大。对于大多数只需要通过简单条件进行搜索的小项目来说应该足够了。如果您想进行更高级的搜索,需要有多个字符串字段的索引,并使用复杂的 【应该(不)//【必须(不) 条件,您可能想使用更高级的搜索引擎,如 [Elasticsearch](http://What is Elasticsearch and why is it so fast?) ,或“高级” Atlas Search

如何为 ML 做数据标记、版本控制和管理

原文:https://towardsdatascience.com/how-to-do-data-labeling-versioning-and-management-for-ml-ba0345e7988

丰富食品数据集的案例研究

简介

几个月前,Toloka 和 ClearML 一起创建了这个联合项目。我们的目标是向其他 ML 实践者展示如何首先收集数据,然后在将数据输入 ML 模型之前对数据进行版本化和管理。

我们相信,遵循这些最佳实践将有助于其他人构建更好、更强大的人工智能解决方案。如果你很好奇,可以看看我们一起创建的项目。

项目:食品数据集

我们是否可以丰富现有的数据集,并让算法学会识别新的特征?

我们在 Kaggle 上找到了下面的数据集,并很快决定它非常适合我们的项目。该数据集由使用 MyFoodRepo 收集的数千张不同类型的图像组成,并在 Creative Commons CC-BY-4.0 许可下发布。你可以在官方的食物识别基准论文中查看更多关于这个数据的细节。

食物数据集预览——作者照片

我们注意到食物可以分为两大类:固体和饮料。

食物类型的例子:出售的和流质的——作者照片

此外,我们注意到一些食物比另一些更开胃。

食物类型示例—作者照片

那么,我们能否用这些额外的信息来丰富这个数据集,然后制作一个能够识别新特征的算法呢?

答案是肯定的,我们使用 Toloka 和 ClearML 做到了这一点。

如何标注数据?

对于这一步,我们使用了 Toloka 众包平台。在这个工具中,您可以创建一个注释项目,然后将它分发给世界各地的远程注释者。

项目的第一步是创建界面和详细的说明。在这种情况下,我们想问两个问题:

  • 客观问题:关于食物的种类,固体还是液体
  • 主观问题:关于一个人是否觉得食物开胃

我们使用了您可以在下面看到的界面:

界面——作者照片

此外,在说明书中,我们清楚地说明了什么是固体和液体食物,给出了例子,并提供了边缘案例。

一旦说明和界面准备好了,我们必须为我们的项目邀请表演者。Toloka 注释者遍布世界各地,所以我们必须仔细选择谁能够参与我们的项目。

作者照片

因为我们给出的说明是用英语写的,所以我们决定只邀请说英语的人,并通过考试来测试他们理解这些说明的程度。考试由 10 个任务组成,我们测试了关于食物类型的第一个问题的答案。我们有 5 个固体、4 个液体和 1 个应标记为“其他”的边缘案例。我们要求考试成绩达到 100 分才能进入注释项目。

下图是参加考试的人给出的答案分布。

作者照片

如果你仔细观察最后一个条目,你会注意到它的正确回答率相对较低,只有 49%,相比之下,其余条目的正确回答率都在 90%以上。这是我们用来抓住不注意阅读说明的表演者的边缘案例。最后一张图片由各种类型的食物组成,包括液体和固体,因此应该标记为“其他”。

作者照片

幸运的是,我们过滤掉了回答错误的人。

为了控制注释的质量,我们实施了以下措施:

  • 快速响应规则,
  • 重叠,
  • 和控制任务。

当用户对给定任务的响应太快时,使用快速响应规则。这意味着他甚至没有时间去正确地观察和检查任务,也不可能得到正确的回答。

另一方面,Overlap 让我们对响应更有信心,因为每个任务都被分配给几个注释者,他们的工作可以被聚合。在这种情况下,我们使用了三个重叠。

我们还在正常任务之间分配了控制任务。这意味着每给注释者九个任务,就会有一个控制任务检查他给出的响应是否正确。如果注释者对控制任务给出了不正确的响应,他将被从项目中删除。

作为这个注释的结果,我们使用三个不同的注释器对 980 张图片进行了注释。收集结果大约需要 30 分钟,花费 6.54 美元。我们还有总共 105 人参与了这个项目。

作者照片

现在可以将结果传递给 ClearML 工具,这些工具将用于对收集的数据进行版本化和分析。如果你的项目需要其他类型的注释,你可以在这里浏览不同的注释演示。

数据管理

既然我们实际上已经创建了一个框架来获取和注释数据,我们可以直接使用它,或者更好的是,对它进行版本化,以便我们记住谁在何时做了什么:)

ClearML 是一个开源的 MLOps 平台,它提供了一个名为 ClearML Data 的数据管理工具,可以与平台的其余部分无缝集成。

一旦创建了带注释的数据集,我们只需将其注册到 ClearML 中。

作者照片

一旦在 ClearML 中注册了数据,用户就能够创建和查看数据谱系树,添加数据预览、元数据,甚至图表,如标签分布!这意味着所有信息都封装在一个实体中。

在我们的例子中,我们可以将数据集注释成本保存为元数据。我们还可以存储其他注释参数,如指令、语言参数或其他任何东西!并将其附加到数据集,以便我们以后可以引用它。

作者照片

作者照片

数据现在被追踪到了什么?

好了,现在数据得到了跟踪和管理,但接下来你可能会问。

那么,将它连接到 ClearML 实验管理解决方案的力量来了!

只需一行代码,用户就可以将数据集存储到他们的目标机器上,完全抽象出数据实际存储的位置(或者是在专用的 ClearML 服务器上,或者只是存储在您喜欢的云提供商的存储器上)

作者照片

ClearML Data 从存储数据的任何地方获取数据,并缓存数据,这样连续运行就不需要重新下载数据了!

连接到 ClearML 的实验管理解决方案,用户可以享受它提供的所有功能,如实验比较,我们可以比较两个实验,唯一的区别是注释的成本,并实际查看支付更多注释对我们的模型有什么影响!

作者照片

由于我们将成本保存为元数据,如果我们使用 Toloka 的 SDK 自动化注释任务,我们实际上可以结合 Toloka 和 ClearML 来自动运行注释成本的超参数优化,并计算出我们应该在注释上真正投资多少!

利用超级数据集提升您的数据管理水平

需要从数据集管理工具中获得更多好处?看看超级数据集

超级数据集本质上是将注释和元数据存储在数据库中,以便在训练\测试时可以查询!

用户可以将对数据的查询(称为数据视图)与实验联系起来,并对其进行版本控制!使用 Datviews,您可以在需要时轻松获得数据集的特定子集(甚至多个数据集),这提供了另一个级别的数据管理粒度。

作者照片

如果您需要更好的数据统计数据、更好地控制向网络中输入的数据,以及如果您处理数据的子集并希望避免数据重复(需要大量存储和管理),那么数据视图和超数据集非常有用。

总结

在本文中,您已经学习了如何使用 Toloka 和 ClearML 工具,以食品数据集为例构建 ML 数据工作流。如果你想检查本博客中概述的步骤所需的所有代码,请查看我们准备的 colab 笔记本

此外,我们以网络研讨会的形式展示了我们的实验结果,并为您保存了记录( Toloka partClearML part) )。

你觉得这个指南对管理你自己 ML 项目的数据有用吗?如果您对这个项目有任何反馈或想问问题,请在下面发表评论。

还要特别感谢本文的合著者 @victor.sonckErez Schnaider

PS:我正在 Medium 和aboutdatablog.com上撰写深入浅出地解释基本数据科学概念的文章。你可以订阅我的 邮件列表 以便在我每次写新文章时得到通知。如果你还不是中等会员,你可以在这里加入https://medium.com/@konkiewicz.m/membership

下面还有一些你可能喜欢的帖子

* *

如何在 Python 中进行日志记录

原文:https://towardsdatascience.com/how-to-do-logging-in-python-37fee87b718c

跟踪程序中的事件

维克多·塔拉舒克在 Unsplash 上拍摄的照片

Python 编程语言中最常用的函数之一是print()语句;print()是您在学习 Python 时首先要学习的函数之一。就功能而言,没有任何东西可以与之媲美。但是它不应该用于所有的情况,比如你在调试的时候——尤其是当你在处理一个复杂的程序的时候。

在一个简单的程序中使用print()语句可能不会有什么问题,但我个人不建议这样做。您最好养成使用日志来调试代码的习惯。日志是程序员工具箱中最有用的工具之一。它用于帮助更好地理解程序的流程,并识别在开发程序时可能没有考虑到的场景。

Python 为我们提供了一个名为logging的内置日志模块。在这篇文章中,我们将介绍一些重要的概念,这些概念将允许你开始把logging添加到你的应用程序中。

**Table of contents:** 
--> [A simple introduction to Python's logging module](#e4e6)
--> [Configuring the logger](#826c)
--> [Creating your own logger object](#7300)
--> [Understanding when to use logging](#dd42)

Python 日志模块的简单介绍

日志是与程序相关的事件的自动生成的、带有时间戳的文档。为了产生这样的信息,记录器不断地监视应用程序的流程并存储必要的信息(即谁在什么时间访问了程序)。

在 Python 中,可以使用logging模块来创建日志。它是大多数第三方库使用的一种流行的内置 Python,这意味着您可以将您的日志消息与您正在使用的库的日志消息集成在一起,但这并不是它唯一酷的地方。

logging模块的另一个很酷的特性是它提供了一组函数来简化日志记录过程。每个日志记录函数都以事件的严重级别命名,这使得记录程序中最紧急的事件成为可能。

定义的级别(按严重性递增顺序排列)如下:

  • DEBUG : 用于记录与源代码相关的底层细节,例如,通知开发人员某个函数已被调用或者某个对象的值存储在变量中。
  • INFO : 用于与程序中发生的事情相关的通用信息,例如正在读取的文件或正在发送的电子邮件。
  • 警告 : 用来警告你现在还没有错误,但是将来可能会有错误。
  • 错误 : 用于可预防的错误。
  • 关键 : 用于导致系统失败或无法恢复的错误

换句话说,并非所有日志消息都是平等的。

让我们来看看logging模块附带的默认记录器:

**import** logging **>>>** logging.debug("debug message")
**>>>** logging.info("info message")
**>>>** logging.warning("warning message")
WARNING:root:This is a warning message
**>>>** logging.error("error message")
ERROR:root:error message
**>>>** logging.critical("critical message")
CRITICAL:root:critical message

您可能会注意到两件事:

  1. logging.debug()logging.info()功能未被记录。这是因为默认配置是只记录严重级别为WARNING或以上的消息。
  2. 记录信息的输出格式为severity_level:logger_name:logging_message

我们可以配置我们的日志消息,您将在下一节看到。

配置记录器

在上一节中,我们已经用默认设置介绍了日志模块,但是有时默认设置并不是我们想要的。在这种情况下,我们可以通过配置logging.basicConfig()来设置我们的记录器。

logging.basicConfig()最常用的参数包括:

  • filename —指定使用指定的filename而不是StreamHandler创建一个FileHandler;记录输出被发送到带有给定filename的磁盘文件。
  • filemode —如果指定了filename,那么文件将在给定的filemode中打开。默认模式为“a”:了解更多关于不同模式的信息。
  • format —指定的格式字符串将用于处理程序;默认的格式字符串是levelname:name:message[如上所示]。
  • level—root logger 应设置的指定严重性级别。

让我们进一步探索这些参数。

我们可以使用level参数来设置日志消息的严重性级别。

**import** logging
**from** datetime **import** datelogging.basicConfig(level=logging.INFO)**def** calculate_age(year_of_birth:**int**) -> **int**:
    """Compute the age of a person"""
    current_year = date.today().year
    **return** current_year - year_of_birth

year_of_birth = 1994logging.info(f"User was born in {year_of_birth} and is approximately {calculate_age(year_of_birth)} years old")"""
INFO:root:User was born in 1994 and is approximately 28 years old
"""

如果我们想把我们的日志消息发送到一个文件而不是控制台,我们必须把参数filename传递给我们的logging.basicConfig()并提供一个我们想用来保存文件的名字。

注意 : *basicConfig()* 只有在 root logger 尚未配置的情况下才能调用——只能调用一次。因此,想象接下来的几个代码片段正在更新上面的脚本,而不是扩展它。

logging.basicConfig(level=logging.INFO, filename="example.log") 

对我们的代码执行这个更新,现在会将所有后续的日志消息附加到当前工作目录中名为example.log的文件中——这意味着如果该文件已经存在,那么 logger 会简单地将您的新日志添加到文件的末尾。

您可以通过设置filemode来改变这种行为。默认情况下,filemode参数设置为"a",表示文件为打开写入,如果存在则追加到文件末尾 : 测井文件。让我们将filemode改为"w"::打开进行写入,首先截断文件。

logging.basicConfig(level=logging.INFO, 
                    filename="example.log",
                    filemode="w")

每次程序运行时,日志文件都会被重写,因为我们对filemode做了更改。

目前,正在存储的日志消息来自默认格式— levelname:name:message。我们可以通过在默认配置中设置format参数来改变这一点。

"""
INFO:root:User was born in 1994 and is approximately 28 years old
"""

该消息看起来像这样,但是将被写入一个名为app.log的文件,而不是控制台。

模块logging还提供了几个速记元素,可以很容易地添加到输出格式中。例如,我们可以使用%(asctime)s来输出一个人类可读的LogRecord创建时间。

logging.basicConfig(level=logging.INFO, 
                    filename="example.log",
                    format="%(asctime)s - %(message)s")logging.info(f"User was born in {year_of_birth} and is approximately {calculate_age(year_of_birth)} years old")

我们在example.log文件中的新日志消息将如下所示:

2022-05-17 08:13:16,693 - User was born in 1994 and is approximately 28 years old

创建您自己的记录器对象

到目前为止,我们一直在使用名为root的默认记录器。logging文档建议我们创建自己的Logger类的 logger 对象——当应用程序中有多个模块时,这甚至更重要。

记录器永远不要直接实例化,而要一直通过模块级函数 *logging.getLogger(name)* 。对同名的 *getLogger()* 的多次调用将总是返回对同一个 Logger 对象的引用。
——
来源:Logger 对象文档 】。

以下是我的欺诈检测项目中的一些代码:

python 文件的名称是predict.py:因此,我们在名为predict_logger变量中实例化了一个定制日志记录器(见第 11 行)。

“建议我们使用模块级记录器,通过将名称参数__name__传递给getLogger()来创建一个记录器对象,因为记录器本身的名称会告诉我们从哪里记录事件。__name__是 Python 中一个特殊的内置变量,它计算当前模块的名称。
—【来源:记录器对象文档】。

了解何时使用日志记录

如果你和我一样,你可能还在思考如何知道应该给出什么样的日志消息。

日志文档为我们提供了有用的指导。

何时使用日志记录;【来源: 日志记录 HOWTO 】。

关于日志,我们还可以讨论很多,但是这已经足够让你开始了。将我们在这篇文章中讨论的东西应用到一个个人项目中来巩固知识。需要时,不要害怕参考文档

感谢阅读。

联系我:
LinkedIn
Twitter
insta gram

如果你喜欢阅读这样的故事,并希望支持我的写作,可以考虑成为一名灵媒。每月支付 5 美元,你就可以无限制地阅读媒体上的故事。如果你使用我的注册链接,我会收到一小笔佣金。

已经是会员了?订阅在我发布时得到通知。

https://kurtispykes.medium.com/subscribe

如何在 dbt 中进行单元测试

原文:https://towardsdatascience.com/how-to-do-unit-testing-in-dbt-cb5fb660fbd8

解决测试数据管道的挑战

克劳迪奥·施瓦茨在 Unsplash 上的照片

在最近几年,我们已经看到了构建数据堆栈的技术和工具的巨大发展。现在,在没有大量投资的情况下,构建现代数据管道比以往任何时候都更容易。标准的现代数据堆栈包括但不限于:

  • 云优先数据仓库—一个高度可扩展的分布式云数据仓库,允许使用 SQL 转换万亿字节的数据。BigQuery、雪花、亚马逊红移目前市场领先。
  • 工作流程编排—以编程方式安排和监控数据转换的平台。数据仓库只是来自不同来源的集成数据的中央存储库。我们需要一个像 Airflow 和 dbt 这样的平台,将原始数据转换成对业务有意义的干净数据。与数据仓库不同,许多编排工具是开源的,基础设施由数据团队维护,因此工程师们提出了许多最佳实践,如如何构建 CICD 管道、执行测试、监控、警报等。本文就是其中的一篇,主要讨论 dbt 中的测试。
  • 商业智能—一种工具,允许每个人通过创建仪表板来探索数据和自助服务他们的数据请求。示例工具有 Tableau 和 Looker。员工应该能够利用该工具进行决策。

照片由达尼洛·德罗巴克拍摄

如题,在本文中,我们将回答一个问题:如何在 dbt 中执行单元测试?在看到解决方案之前,让我们先了解一下 dbt 的背景,它的测试策略,以及为什么它对 dbt 是一个挑战?

dbt

dbt 是一个基于 SQL 的数据转换工具,支持数据分析师和工程师转换、测试和记录云数据仓库中的数据。工程师利用领域专业知识创建可重用的数据模型。公司中的任何人都可以使用数据模型来帮助他们决策。

dbt 中的数据测试

为了确保数据模型的正确性,我们需要应用不同类型的测试。dbt 中必备的一个测试是数据测试。这是确保数据质量的一个完整步骤。工程师通常会对管道做出假设:源数据是有效的,模型是合理的,转换后的数据是准确的。但事实通常并非如此。应进行一系列测试以确保数据质量。由于源数据每天都在变化,这些测试应该是生产管道中运行时测试的一部分。根据严重程度,一些测试可能会堵塞管道,以免污染下游。这里我列出了一些常见的数据质量测试:

  • 空值-检查不应有空值的列。
  • 唯一性检查—几列的组合应该是唯一的,以避免重复。
  • 新鲜度检查 —模型是否包含最近的记录?
  • 关系检查-源表中的所有必需数据是否都转换到了目标表中?

dbt-utils 这样的一些 dbt 包提供了一系列现成的通用测试,可以满足大多数需求。为了更好地理解数据测试的作用,让我们把它形象化:

创作人

水平路径是通过数据管道的数据流。每个环境中的数据可能不同,因此数据质量测试应该在生产流程中运行,以确保对源数据的假设总是有效的。

够不够?

dbt 中的单元测试

数据测试可以发现数据质量问题。但是不能保证 SQL 代码的正确性。下面是一个 SQL 示例,它将revenuevat表连接起来,以计算净预订和增值税金额。仅从数据测试很难知道公式或连接逻辑是否正确。

SELECT
  date
  , city
  , SUM(amount_net_booking) as amount_net_booking
  , SUM(amount_net_booking * (1 - 1/(1 + vat_rate))) as amount_vat  
FROM revenue
LEFT JOIN vat USING (city)
GROUP BY 1,2

我们在这里错过的是测试 SQL 逻辑(也称为单元测试)的功能,就像测试常规应用程序一样。如果我构建一个应用程序,我会应用 TDD(测试驱动设计),这是一种常见的软件工程实践,可以帮助我们在正确性方面达到一个良好的信心水平。在推广到生产之前,它确保逻辑是正确的。

虽然 dbt 是一个强大的框架,但我们仍然从头开始编写一堆 SQL 代码来构建模型。只要是人类写的,都有可能出错。这和写一个 Python,Java 程序没什么区别。我们可以将 dbt 模型看作一个函数,其中输入是源表,输出是 SQL 的结果。dbt 中的单元测试是这样一种测试,我们提供模拟输入,然后对照预期的模型检查结果。单元测试的一大优势是我们可以为所有类型的测试用例提供模拟输入,包括边缘用例。这对于涉及复杂业务逻辑的 SQL 代码尤其有用。如果是一个模型链,我们可以向第一个模型提供模拟输入,并断言最终模型和中间模型的结果。这个测试链被称为集成测试。

与数据测试不同,没有必要将单元测试集成到数据管道中,因为在提升到更高的环境后,代码不会被更改。我们不需要对逻辑做任何假设,因为我们已经完全控制了它。只要在下层环境下验证了逻辑,就应该信任它,发布代码。

数据管道中的数据测试与应用程序中的单元测试

由创作

虽然数据管道中的数据测试和常规应用程序中的单元测试是两个不同的概念,但它们有共同的领域。例如,当构建 REST API 接口时,应用程序从外部接收数据,这可能是不可靠的。它必须在处理数据之前验证数据(也称为执行数据质量检查)。尽管大多数软件工程师不认为这是一个标准测试,但这种类型的运行时验证非常类似于数据管道中的数据测试。

在另一种情况下,测试可以被认为是数据测试和单元测试,例如关系检查(例如字段ab的和等于c)。作为一名工程师,理解测试的目标是很重要的,无论是测试动态的数据还是测试静态的逻辑。如果它是关于逻辑的,那么它应该是单元测试,并且只在 CICD 管道中执行一次。如果是关于数据的,那么由于数据的差异,它应该是生产流水线的一部分。数据测试的几个例子:

  • 源数据中有空值吗?
  • 数据包含最近的日期吗?
  • 来自源的每条记录都被转换到目的地了吗?
  • 有没有超出可接受范围的数值?
  • 代码中有重复的地方吗?

单元测试的几个例子:

  • 该模型计算公司的收入,计算是否正确?
  • 该模型包含一些 IF 条件来计算一个字段,我是否遗漏了任何边缘情况?
  • 该模型在几列上进行聚合,我是否遗漏了任何一列?

成熟的数据团队利用自动化数据质量检查和自动化逻辑测试,确保数据对公司具有最高的价值。

dbt 中单元测试的实现

为了演示单元测试如何在 dbt 中工作,我创建了下面的数据管道,它读取两个源表transactionvat,然后将数据转换成最终的模型revenue。作为一名数据工程师,我不一定知道初始阶段的每个逻辑细节,所以我基于某种假设创建了这个模型。

世系图(由制作)

由于这是一个关键而复杂的模型,我想用几个预定义的场景来测试它,并为此创建模拟数据。模拟数据是我的 dbt 项目中的 CSV 文件,其中每个 CSV 文件代表一个源表。我们可以将 CSV 文件存储在data文件夹中,并利用[dbt seed](https://docs.getdbt.com/docs/building-a-dbt-project/seeds)命令将数据加载到数据仓库中。

文件夹结构(由创建)

关于如何/由谁创建模拟数据的一些话。为了确保测试用例的完整性,编写代码的人不应该同时提供测试数据。在许多公司中,分析师或业务涉众是提供测试用例或测试数据的人。

通常,模拟数据不应该与真正的源表混淆。最好将它存储在一个单独的模式中(例如 unit_testing)。我们可以在dbt_project.yml文件中定义这个。unit_testing/revenue文件夹中的每个文件都将被加载到unit_testing模式中。[tags](https://docs.getdbt.com/reference/resource-configs/tags)在选择车型时也发挥着重要作用。当运行dbt build -s +tag:unit_testing时,它将运行标签为unit_testing的所有种子/模型/测试/快照及其上游。

seeds:
  unit_testing:
    revenue:
      schema: unit_testing
      +tags:
        - unit_testing

出于演示的目的,我的 dbt 模型比现实相对简单。

收入模型(由高创建

你发现问题了吗?

问题出在源表。像往常一样,我使用{{ source() }}来引用实际的源表。但是我的模拟数据在一个单独的模式中,它们应该通过使用ref函数来引用,因为它们是种子。我要怎么切换信号源?为了解决这个问题,我创建了一个自定义宏,它能够根据环境或某种触发器来切换源表。

select _ 表宏(由创建)

这个宏有两个输入参数:source_table - >表有真实数据,test_table - >表有模拟数据。宏根据dbt命令中的变量返回表格。如果命令没有提供unit_testing变量或者值为false,则返回source_table,否则返回test_table。你可以根据自己的情况修改这个宏,比如基于[target](https://docs.getdbt.com/reference/dbt-jinja-functions/target)而不是变量来切换表。

dbt使用模拟数据运行模型和测试的命令

dbt build -s +tag:unit_testing --vars 'unit_testing: true'

dbt使用真实数据运行模型的命令。(稍后将在此解释我们为什么需要--exclude标志)

dbt build -s +tag:revenue --exclude tag:unit_testing

更新后的模型现在看起来像这样。我们使用变量{{ import_* }}来表示正确的源表。

更新的收入模式(由高创建

到目前为止,我们已经看到了如何选择正确的源表并在模拟输入上运行模型。接下来,我们将比较实际输出和预期的模拟输出。我们可以利用 dbt-utils 提供的[equality](https://github.com/dbt-labs/dbt-utils/tree/0.7.2/#equality-source)测试来比较两个模型。在compare_model中,我们指的是预期输出模型。

值得注意的是,我们不应该在测试中忘记tags: ['unit_testing']。正如我们之前所说的,单元测试不应该作为生产流水线的一部分运行。在生产中运行这个equality测试实际上意味着我们将生产模型与永远不会工作的模拟输出进行比较。添加标签unit_testing和运行命令dbt build -s +tag:revenue --exclude tag:unit_testing可以确保在生产中跳过测试。

哇,我希望你还在关注我:)让我们来看看不同的比较模型的方法。dbt_utils.equality test 对模型进行精确匹配,但由于精度问题,在比较数字时会变得棘手。解决这个问题的一个方法是创建一个自定义宏,首先对数字列进行舍入,然后进行比较。

自定义宏比较模型(由创建)

只要有助于你发现不同之处,你就可以发挥创造力。

我们完全安全吗?

不幸的是,没有。单元测试给了我们用自定义场景测试逻辑的可能性。但问题是:这些场景是否涵盖了一切?大概不会。有两个问题:

很难提供涵盖所有排列的完美数据集——未知的已知

源数据经常是多种多样的,找出所有可能的组合并为每个组合创建测试数据非常耗时。其中一个策略是预先创建一个单独的层,过滤掉无效的数据并进行一些完整性检查。它在某种程度上限制了排列的数量,所以我们对将要发生的事情更有信心,可以创建相对有限的数据集。

甲骨文问题—(不)已知未知

在我看来,这是一个哲学问题。每次测试都是实际输出和预期输出的比较。

Oracle 问题指难以确定预期产出的情况。基本上,人类从来没有足够的装备来测试他们的程序,因为现实总是比它在测试套件中的表现更复杂。

如前所述,数据源是复杂的。有很多情况我们不知道如何处理。一个简单的策略是使用一种逻辑来处理所有未知的情况,并以此作为答案。想想else在一个 if 条件中的作用。

如果这还不够,那我们就只能忍受了。人类每天都在获取新的知识,程序也是如此。随着我们发现更多的问题,更多的未知将转化为已知,因此我们将能够捕捉越来越多的信息,并每天更好地了解这个世界。

结论

希望这篇文章对你有用。如果您确信并开始在您的数据管道中应用单元测试,那就太好了!如果您没有立即被说服,但是仍然希望从这篇文章中获得一些收获,那么它将是理解单元测试和数据测试在数据管道中的作用,因为您有一天会需要它。如果你对数据管道测试有任何想法,请在评论中告诉我们。干杯!

参考

https://medium.com/slalom-build/the-challenge-of-testing-data-pipelines-4450744a84f1 https://github.com/EqualExperts/dbt-unit-testing

如何对接用 H2O、MLflow、FastAPI 和 Streamlit 构建的机器学习应用

原文:https://towardsdatascience.com/how-to-dockerize-machine-learning-applications-built-with-h2o-mlflow-fastapi-and-streamlit-a56221035eb5

用 Docker 容器化多服务 ML 应用的简单指南

Philippe Oursel 在 Unsplash 上的照片

鉴于 Docker 在可靠地构建、发布和运行机器学习(ML)应用程序方面令人印象深刻的能力,它在数据科学领域的采用呈爆炸式增长并继续激增也就不足为奇了。

本文解释了如何利用 Docker 来封装一个用 H2O AutoML、MLflow、FastAPI 和 Streamlit 构建的多服务 ML 应用程序。

内容

(1)Docker(2)ML 应用概述(3)后端设置— H2O、 ml flow&FastAPI(4)前端设置—Streamlit(5)设置 Docker 撰写

你可以在这里 找到这个项目 的 GitHub 回购。

(1)码头上的底漆

Rubaitul AzadUnsplash 上拍摄的照片

Docker 是一个开源平台服务,它让我们可以使用容器轻松地构建、打包、部署和运行应用程序。

它的工作原理是将应用程序组件(即源代码、依赖项、库)打包成一个单独的可移植包(即容器)。

有了容器,任何使用不同机器的人只需几行代码就可以可靠地启动和运行相同的应用程序。

Docker 容器与底层基础设施的分离|按作者分类的图片

这些容器将应用程序从底层基础设施中分离出来,允许团队在不同的环境中快速一致地交付软件。

以下是该项目的关键 Docker 组件:

Docker 关键组件的概述和流程|按作者分类的图片

  • Dockerfile :一个文本文档,包含关于构建 Docker 图像的说明。它可以被视为具有 Docker 引擎组装映像的特定命令的配方,例如下载要求、复制文件等。
  • Docker Image :一个只读模板,包含可执行源代码以及应用程序运行所需的库和依赖项。当您运行 Docker 映像时,它会生成容器的一个实例。
  • Docker 容器:Docker 图像的一个实时运行实例。
  • Docker Compose :定义和编排多个容器的构建和共享的配置文件。

使用 Docker 最简单的方法是使用 Docker Desktop ,它提供了一个简单的用户界面来构建和共享容器化的应用程序。

Docker 桌面|图片作者登陆页面截图

就像 GitHub Desktop 如何用 Git 简化开发一样,Docker Desktop 让我们使用 Docker 变得很容易。

您可以根据您的操作系统安装合适的 Docker 桌面版本,即 WindowsMacLinux

本项目中使用的其他工具包括:

(2)ML 应用概述

我们将使用的应用程序基于一个早期的项目,在该项目中,我们构建了一个端到端的 ML 管道,以对购买额外车辆保险的可能性较高的健康保险客户进行分类(即交叉销售)。

*

我们将不讨论管道构建,因此请参考上面的文章了解详细信息。

以下是该应用程序中组件的概述:

  • H2O 汽车— 在一系列实验中自动训练 ML 模型
  • MLflow — 跟踪每个 AutoML 实验的结果和工件,并根据性能指标选择最佳模型
  • FastAPI — (通过uvicon服务器)部署和公开最佳模型作为 API 端点
  • Streamlit — 将 API 端点作为一个 web 应用程序,为模型预测请求提供一个简单的用户界面

最终产品是一个用户友好的 web 应用程序,用户可以上传数据并检索每个客户相应的交叉销售预测。

Streamlit web 界面上传客户数据并检索模型预测|作者 Gif*

如下图所示,整个应用程序可以分为两个服务(前端后端)。**

应用程序组件概述|按作者分类的图片(通过公共许可证获得的徽标)

在这一点上,我们有了各种组件的源代码和工件(即,预先训练的模型、API 端点、web 应用程序接口)。让我们学习如何用 Docker 封装整个应用程序。

(3)后端设置— H2O、MLflow 和 FastAPI

应用程序有两个部分(即前端后端),所以我们将它们打包到两个独立的容器中,然后将它们链接到同一个网络中。**

后端和前端服务的分类|按作者分类的图片

我们从探索如何容器化后端设置开始。后端目录结构如下:**

后端目录结构|作者图片

后端设置的源代码可以在 main.py 中找到,它在这里执行以下任务:

  • 初始化 FastAPI、H2O 和 MLflow 客户端的实例
  • 使用 MLflow 客户端从/mlruns中存储的预训练模型集合中跟踪并加载最佳 H2O ML 模型(基于测井损失)
  • 创建一个 FastAPI POST 端点,该端点获取并处理上传的数据,将数据提供给 ML 模型,并以 JSON 格式返回模型预测

dockerizing 的第一步是构建 Dockerfile ,我们将使用它来创建应用程序的 Docker 映像和容器

我们将专门为后端设置创建一个 Dockerfile,并将其保存在/backend目录中。后端设置的文件如下所示:**

让我们了解一下 Dockerfile 文件的内容:

  • 来自 python:3.9 —从 Docker Hub 获取 python 映像(3.9 版),并创建构建 Docker 映像的基础层。
  • 工作目录/应用 —定义 Docker 容器的工作目录
  • 运行 —执行特定命令,例如安装 pip 依赖关系。
  • 复制 —将文件从源文件夹(即 Docker 客户端的当前目录)复制到目标文件夹
  • EXPOSE —表示容器监听连接的端口
  • CMD —指定在 Docker 容器中运行的命令:
***uvicorn main:app --host 0.0.0.0 --port 8000***

上面的命令指示机器启动并托管位于 IP 地址 0.0.0.0 (端口 8000)的 uvicorn 服务器,并在 main.py 文件(即 main : app)中定位 FastAPI ASGI 应用程序。

因为 H2O 服务器需要 Java,我们还需要运行下面的命令在我们的容器中安装一个 Java 运行时环境(JRE)

***RUN apt-get update && apt-get install -y **default-jre*****

如果不执行上述操作,我们将会遇到 H2OStartupError,此时 H2O 服务器找不到 Java。

我们后端设置的 docker 文件现在已经准备好了。构建 Docker 映像和运行容器的经典方法分别是使用docker builddocker run

除非是为了测试目的,否则我会避免在这个阶段单独构建容器。原因是我们将在步骤 5 中学习如何使用 Docker Compose 来构建和并发运行多个容器。

(4)前端设置—简化

让我们把注意力转向构建前端接口。前端目录结构如下:

前端目录结构|作者图片

前端设置的源代码可在 app.py 中找到,它在其中执行以下任务:

  • 定义前端接口与后端 FastAPI 端点通信的端点位置,即endpoint = 'http://**host.docker.internal**:8000/predict'
  • 构建 Streamlit web 界面,包括用于 CSV 文件上传、数据预览和预测下载的组件
  • 将 CSV 数据转换为要解析到 FastAPI 端点的 bytes 对象

前端设置的文件如下所示:**

(5)设置 Docker 组件

虽然我们可以单独构建后端和前端容器,但这并不是创建像我们这样的互连多容器应用程序的最佳方式。

我们可以利用 Docker Compose 的功能来定义和运行多容器应用程序。Docker Desktop 已经安装了撰写插件,所以不需要额外安装。

Docker Compose 是在 YAML 配置文件(docker-compose.yml)中定义的,它指定了构建应用程序的设置和指令。

docker-compose.yml 放在根文件夹| Image by author 中

docker-compose . yml文件如下图所示:

让我们了解一下 docker-compose 文件的内容:

  • 服务 —定义组成应用程序的服务(即后端和前端),以便它们可以在一个隔离的环境中一起运行
  • 构建 —指定构建 Docker 图像的文件夹。由于我们从根文件夹运行 docker-compose ,我们将指定要构建的子目录,即backendfrontend。对于我们直接从根文件夹构建的情况,我们可以指定.
  • image —指定从中启动服务容器的图像。由于我们在构建*部分从头开始构建映像(而不是从注册表中提取),这里的值将是新映像的名称,例如e2e-自动-前端:最新***
  • 端口 —暴露容器端口。该配置将容器端口映射到主机端口,以便我们可以通过 web 浏览器上的 localhost URL 访问应用程序。例如,8501:8501是指主机端口 8501 到容器端口 8501 的映射(即HOST:CONTAINER)。对于后端服务,我们有两个公开的端口,其中 8000 用于 FastAPI 端点,而 54321 用于 H2O 服务器。

端口映射图|作者图片

  • —定义一个,用于保存 Docker 容器生成的数据。它是以VOLUME:CONTAINER_PATH的形式出现的。例如,./backend:/app/backend是指从相对路径 挂载卷内容。/backend (我们的后台目录)放入 /app/backend 容器中。
  • 依赖于 —表示服务之间的启动(和关闭)依赖关系。在我们的例子中,我们希望在前端服务之前创建后端服务。因此,我们在前端服务中包含了一个 depends_on: backend 语句。
  • 网络 —定义容器所连接的网络,引用顶级networks键下的条目。我们通过将两个服务连接在同一个project_network网络下,使它们相互通信。

注意:基于最新的 编写规范 ,不再需要在 YAML 文件中定义顶层版本属性(如 v2、v3)。

(6)本地运行 Docker Compose

是时候执行我们的 docker-compose 文件来构建我们的多服务应用程序了。我们通过从根文件夹运行以下命令来实现这一点:

***docker-compose up -d --build***

运行 docker-compose 命令| Image by author 后的 CLI 输出

然后,我们可以检查 Docker Desktop,看看我们是否已经成功地为两个服务构建了映像,并让应用程序在本地运行。

Docker 桌面上成功创建图像和容器的截图|作者图片

最后,我们可以通过在 web 浏览器上访问localhost:8501来测试我们的应用程序。

after 化后成功加载前端界面|图片由作者提供

从这里,我们还可以通过运行docker-compose down轻松地停止和删除容器、网络、卷和映像

(7)在 AWS 上部署 Docker 容器

已经学会了如何在本地对接和运行我们的 ML 应用程序,直观的下一步是在云上部署这个容器化的应用程序,例如 AWS。****

虽然我想演示这个云部署,但是 Docker 文档已经很好地解释了在 Amazon ECS 上部署 Docker 容器。

***https://docs.docker.com/cloud/ecs-integration/

尽管如此,我打算很快就这个项目在其他云平台上的部署写一个指南,所以请继续关注这个中型页面!***

包装它

通过上面的简单演练,我们已经了解了如何使用 Docker 来封装基于 H2O、MLflow、FastAPI 和 Streamlit 构建的多服务 ML 应用程序。

你可以在这个 GitHub repo 中找到这个项目的源代码和文件。

在你走之前

欢迎您加入我的数据科学学习之旅!点击此媒体页面,查看我的 GitHub ,了解更多令人兴奋的数据科学内容。同时,祝你的 ML 应用程序归档愉快!**

*** https://kennethleungty.medium.com/membership ***

如何下载和浏览电影数据

原文:https://towardsdatascience.com/how-to-download-and-explore-movie-data-1948a887c530

使用 TMDB API 和 python 通过网络分析探索 2022 年奥斯卡提名

又到了莫伊拉·罗斯最喜欢的季节——颁奖!我认为这将是一个很好的机会来对 2022 年奥斯卡提名做一些网络分析,并与 TMDB API 玩玩。本教程将带您了解:

  • 向 TMDB API 查询所有 2022 奥斯卡提名电影的演员和工作人员的完整列表,
  • 从数据中提取网络,
  • 并对提取的图形做一些简单的数据分析和网络分析

请尽情享受,并随时在底部提出您的任何问题或疑问!如果你想作为参考,这里有一个链接指向我的 GitHub 上的代码。

查询 TMDB API

首先,感谢 Monica Powell 撰写了这篇文章,它帮助我理解了 TMDB API。

要开始,你需要去 TMDB 站点获取一个 API 密匙。要获得 API 密钥,只需访问该网站,注册一个新帐户,并使用您的新帐户生成一个新的 API 密钥。它们让事情变得非常简单,我很快就能拿到钥匙。

有了密钥后,创建一个 config.py 文件,将密钥与代码放在一起:

tmdb_api_key = "YOUR API KEY”

这不是绝对必要的,但是养成将 API 键存储在配置文件中而不是直接存储在代码中的习惯是一个好主意,尤其是如果您打算将它发布在 GitHub 上的话。你不想与任何人共享你的 API 密匙,所以把密匙放在一个单独的文件中允许你共享你的代码而不共享你的密匙。

现在我们可以开始从 TMDB 提取数据,并在 Jupyter 笔记本上进行处理。首先,让我们导入我们的包:

import config # to hide TMDB API keys
import requests # to make TMDB API calls
locale.setlocale( locale.LC_ALL, '' )import pandas as pd
import matplotlib.pyplot as plt
import itertools
from pandas import json_normalize 
import networkx as nx
import datetimeapi_key = config.tmdb_api_key # get TMDB API key from config.py file

电影数据库 API 有很棒的文档在这里。我发现Tessa Xie的这篇教程对于理解如何使用这个 API 运行不同的查询非常有帮助。

出于本教程的目的,我们对电影的“演职员表”感兴趣,即演员和工作人员的完整列表。要获得这些信息,我们可以使用如下查询:

#Test API by pulling full credits for "Dune"
query = "[https://api.themoviedb.org/3/movie/](https://api.themoviedb.org/3/movie/)" + "438631" + "/credits?api_key=" + api_key + "&language=en-US"
response =  requests.get(query)
array = response.json()

这将从 TMDB 获得电影' Dune '的所有演职员表,并将其转换为 JSON 格式。JSON 有两个组件:演职人员和工作人员。我们可以使用以下代码将完整的演员表提取到 pandas 数据帧中:

#Get full cast and put into a pandas DF
temp_cast = json_normalize(array, 'cast')

现在我们有了《沙丘》全体演员的数据框架。要将这些数据视为一个网络,我们需要转换这些数据。我们想把演员名单上的每个人和其他人联系起来。我发现最快的方法是使用下面的代码:

#Turn dataframe into a dyadic dataset that we can turn into a graph
dyads_cast = pd.DataFrame(list(itertools.combinations(temp_cast['name'], 2)))
dyads_cast = dyads_cast.drop_duplicates()
dyads_cast.columns = ['source','target']

这就创建了一个“边缘”的数据框架——每个参与者都与其他参与者建立了联系。对于一部电影来说,这并不有趣。我们可以通过使用 NetworkX 包将数据帧转换为图形,并使用 matplotlib 进行可视化,来创建这个网络的简单可视化。

#Turn df into graph using NetworkX
G = nx.from_pandas_edgelist(dyads_cast, 'source', 'target')
pos = nx.spring_layout(G) f, ax = plt.subplots(figsize=(10, 10))
plt.style.use('ggplot')nodes = nx.draw_networkx_nodes(G, pos,
                               alpha=0.8)
nodes.set_edgecolor('k')
nx.draw_networkx_labels(G, pos, font_size=18)nx.draw_networkx_edges(G, pos, width=1.0, alpha=0.2)

作者图片

从 API 中提取所有奥斯卡提名

就像我说的,一部电影看这种网络没什么意思。我们需要奥斯卡提名者的完整名单。据我所知,没有一种简单的方法可以将这些列表转换成可以进行 TMDB 查询的格式,所以我手工制作了自己的列表。如果你想在本教程中使用它,我已经把它附在了我的 GitHub 上。

movies = pd.read_csv("oscars.csv")
#There is no data for the movie Ascension so I exclude to avoid errors later
movies = movies.loc[movies['original_title'] != "Ascension"]

现在是有趣的部分。我们想遍历 2022 年奥斯卡提名的列表,并获得每个提名的全部演员和工作人员,然后将每个提名附加到一个数据帧中。下面的代码遍历我们制作的电影列表,查询 TMDB,提取演员和工作人员的数据帧,然后将它们附加到 full_cast_df 和 full_crew_df。

#Create empty DataFrames to append to
full_cast_df = pd.DataFrame()
full_crew_df = pd.DataFrame()#Loop through movie list
for index, row in movies.iterrows():
    movie_id = row['id']
    #Query TMDB for cast and crew for movie
    query = "[https://api.themoviedb.org/3/movie/](https://api.themoviedb.org/3/movie/)" + str(movie_id) + "/credits?api_key=" + api_key + "&language=en-US"
    response =  requests.get(query)
    if response.status_code==200: 
    #status code ==200 indicates the API query was successful
        array = response.json()
        title = row['original_title']
        #Create DataFrames for this movies cast and crew lists
        temp_cast = json_normalize(array, 'cast')
        temp_crew = json_normalize(array, 'crew')
        #Create a new column called 'movie' where we put the title of the movie
        temp_cast = temp_cast.assign(movie=title)
        temp_crew = temp_crew.assign(movie=title)

        #Append individual movies cast and crew list to the main dataframe so we have one with all of them
        full_cast_df = pd.concat([full_cast_df, temp_cast])
        full_crew_df = pd.concat([full_crew_df, temp_crew])

你可能想分别研究演职人员和工作人员列表,但是在本教程中,我将把他们合并成一个完整的演职人员列表:

fullCastAndCrewDF = pd.concat([full_cast_df,full_crew_df])

将这些组合在一起的一个问题是,剧组有一个名为“角色”的栏目,描述他们在电影中的角色,而演员有一个名为“角色”的栏目,列出他们角色的名字。我们希望有一个专栏可以让我们知道这个人在电影中的角色是什么:

def getRole(x):
    if pd.isnull(x['character']) == True:
        return(x['movie'] + ": " + x['job'])
    else:
        return(x['movie'] + ": " + "Actor " + x['character'])fullCastAndCrewDF['role'] = fullCastAndCrewDF.apply(lambda x: getRole(x), axis = 1)

我们数据的一些数据分析

在我们开始创建所有这些人的大网络并在图上运行网络分析之前,我们可以使用这个 DF 来回答一些问题,例如,“谁在 2022 年奥斯卡提名最多的电影中?”

下面的代码按照名字和角色对 DF 进行分组(跨所有电影),然后按照最多产的人进行排序。

prolifics = fullCastAndCrewDF.groupby(['name']).agg({'movie':lambda x: list(x), 'role':lambda x: list(x)})
prolifics['freq'] = prolifics['movie'].apply(lambda x: len(x))
pd.set_option("display.max_colwidth", -1)
prolifics.sort_values('freq',ascending=False).head(10)

以下是我的结果:

作者图片

我们名单上最多产的人是林·曼努尔·米兰达。他监制,导演,在《滴答,滴答,嘣》里有个小角色!,同时也为恩坎托写歌作曲。他还在纪录片《自我的灵魂之夏》中扮演了一个角色,在 2022 年奥斯卡提名中获得了 6 个学分。

这份名单上有几个人在同一部电影中有多个演职员表。例如,保罗·托马斯·安迪生是《甘草披萨》的制片人、导演、编剧和摄影师。如果我们排除同一部电影中的多个角色呢?

fullCastAndCrewDF_noDupes = fullCastAndCrewDF.drop_duplicates(['name','movie'])
prolifics2 = fullCastAndCrewDF_noDupes.groupby(['name']).agg({'movie':lambda x: list(x), 'role':lambda x: list(x)})
prolifics2['freq'] = prolifics2['movie'].apply(lambda x: len(x))
pd.set_option("display.max_colwidth", -1)
prolifics2.sort_values('freq',ascending=False).head(15)

作者图片

这是三部奥斯卡提名电影的完整名单。只有三个演员演过三部电影:玛娅·鲁道夫、安德鲁·加菲尔德和本尼迪特·王。约翰尼·格林伍德是三部电影的作曲家,这太不可思议了,但其他几个人也为三部不同的奥斯卡提名电影工作。

从数据中提取网络

现在我们已经有了一个包含我们想要的所有内容的数据框架,我们可以提取一个网络并在其上运行一些网络分析。我们有两种方法可以提取这个网络:我们可以把电影看作节点,把人看作它们之间的连接(或边),也可以把人看作节点,把电影看作边。首先,让我们创建一个以电影为节点的网络。

#Create a list of all people
fullCastAndCrew = list(fullCastAndCrewDF['name'].drop_duplicates())#Create an empty DataFrame to append to
movie_network = pd.DataFrame()
for x in fullCastAndCrew:
    #Filter DF for this person
    temp = fullCastAndCrewDF.loc[fullCastAndCrewDF['name'] == x]
    #Create a dyadic dataset for this person between the movies they are in
    dyads = pd.DataFrame(list(itertools.combinations(temp['movie'], 2)))
    #Create a column called 'name' for the person's name
    dyads = dyads.assign(name = x) 
    #Concat this person's data onto our master DF
    movie_network = pd.concat([movie_network,dyads])

#Rename columns
movie_network.columns = ['name','source','target']#Get rid of self references
movie_network = movie_network[movie_network['source'] != movie_network['target']]

上面的代码创建了一个我们所有电影的列表(fullCastAndCrew),遍历列表并创建了一个电影之间链接的二元数据集,其中每个链接都是在两部电影中扮演角色或有工作的人。创建后,DF 应该看起来像这样:

作者图片

这意味着凯特·布兰切特同时出现在《别抬头》和《噩梦小巷》中。有了这个数据集,我们可以创建一个网络的可视化。首先,将网络导出为 csv 文件:

movie_network.to_csv("movie_network.csv")

我使用 Gephi 来可视化网络,因为这比编写所有代码更容易,而且它们看起来非常棒。 Gephi 是一款开源的网络分析和可视化软件。你应该可以很容易地从他们的网站上免费安装。它很容易开始,并允许一些真正美丽的可视化。如果你从未用过 Gephi,这里的是从卢卡·哈默开始入门的好教程。

作者图片

看起来我们列表中的大多数电影之间确实有联系,但是有没有一些电影与这张图完全没有联系呢?为了检查这些“孤儿”电影,我们首先在网络中创建一个电影列表,并删除重复的电影。

#Create a list of all movies in the network to see if any are not connected at all
movie_network_movies = movie_network['source'].tolist() + movie_network['target'].tolist()#Remove duplicates
movie_network_movies = set(movie_network_movies)

然后,我们将这份名单与所有奥斯卡提名电影的原始名单进行比较:

#Compare network list of movies to original list to find orphans
originalList = movies['original_title'].tolist()
non_connected_movies = list(set(originalList) - set(movie_network_movies))
non_connected_movies

有四部孤儿电影:《平行母亲》、《露娜娜:教室里的一头牦牛》、《开我的车》、《用火写作》。还有两部电影《逃离》和《世界上最糟糕的人》(The Worst Person in the World)有关联,但与其他电影没有关联——埃斯基尔·沃格特写过《世界上最糟糕的人》(The Worst Person in the World),也是《逃离》的剧本顾问

如果您想创建一个列来描述这两部影片中每个人的工作,我编写了以下函数:

#Put description of person's role in both movies into a new column
def getDescription(x):
    name = x['name']
    roleInSource = fullCastAndCrewDF.loc[(fullCastAndCrewDF['name'] == name) & (fullCastAndCrewDF['movie'] == x['source'])]['role'].values[0]
    roleInTarget = fullCastAndCrewDF.loc[(fullCastAndCrewDF['name'] == name) & (fullCastAndCrewDF['movie'] == x['target'])]['role'].values[0]
    roles = [roleInSource,roleInTarget]
    return(roles)movie_network['connection_description'] = movie_network.apply(lambda x: getDescription(x), axis = 1)

这给了我们如下所示的输出:

作者图片

在这里,我们可以看到凯特·布兰切特在《不要抬头》中扮演了布里·伊万特里,在《噩梦小巷》中扮演了莉莉斯·里特。我刚刚发现自己对发现一个人如何与多部电影联系在一起很感兴趣,这个专栏让这变得简单了一些。

那么,哪部电影与其他奥斯卡提名电影最有“关联”?有几种方法可以回答这个问题。首先,我们可以找到哪两部电影联系最紧密。

#Which movies are most connected?
movie_network = movie_network.groupby(["source", "target"]).size().reset_index(name="freq")
movie_network.sort_values('freq',ascending=False).head(10)

作者图片

也许毫不奇怪,这两部迪士尼动画电影之间的联系最多。

我们还可以计算每个节点的“度”的总数,即每部电影中同时出现在至少一部其他奥斯卡提名电影中的人数:

#Turn df into graph using NetworkX
G = nx.from_pandas_edgelist(movie_network, 'source', 'target', edge_attr='freq')#Find the degree of everyone in the network
G_sorted = pd.DataFrame(sorted(G.degree, key=lambda x: x[1], reverse=True))
G_sorted.columns = ['movie','degree']
G_sorted.head()

这为我们提供了以下列表:

作者图片

甘草披萨的演员和工作人员名单中有 15 个联系人,他们也出现在我们名单上的其他电影中。如果你想看到甘草比萨和其他电影之间的联系的完整列表,你可以使用这个代码(或转到我的 GitHub 上的笔记本):

#Show all connections between Licorice Pizza and all the other movies on our list 
movie_network.loc[(movie_network['source'] == "Licorice Pizza") | (movie_network['target'] == "Licorice Pizza")]

创建一个网络,人是节点,电影是边

现在让我们创建一个网络,其中人是节点,他们的连接是电影。

#Create an empty DataFrame
people_network = pd.DataFrame()#Loop through movies and create dyads between all people in each movie
for x in movies['original_title']:
    #Filter df for movie
    temp = fullCastAndCrewDF.loc[fullCastAndCrewDF['movie'] == x]
    #Create pairs of all people in the movie
    dyads = pd.DataFrame(list(itertools.combinations(temp['name'], 2)))
    #Create a new column called 'movie'
    dyads = dyads.assign(movie = x)
    #Concat network to master df
    people_network = pd.concat([people_network,dyads])

上面的代码遍历所有电影,并在每部电影中创建所有人的配对——这些配对就是我们在图中的“边”。然后,我们可以重命名这些列,并去掉自我引用,即当一个人与自己相关联时。

#Rename columns
people_network.columns = ['source','target','movie']
#Get rid of self references
people_network = people_network[people_network['source'] != people_network['target']]

类似于上面的问题——如果我们想找到他们之间联系最多的两个人呢?

#Which two people are the most connected?
people_network = people_network.groupby(["source", "target"]).size().reset_index(name="freq")
people_network.sort_values('freq',ascending=False).head(10)

作者图片

我们可以看到唐纳德·莫瓦特和丹尼斯·维伦纽瓦之间有 12 个联系。这是因为丹尼斯·维伦纽瓦在《沙丘》中有三个角色(编剧、导演和制片人),唐纳德·莫瓦特在《沙丘》中有四个角色(化妆部门主管、发型设计师、化妆设计师和假肢设计师)。这可能会引起误解,因为这两个人虽然身兼多职,但实际上只是两个人。如果我们在同一部电影中删除重复的角色,并再次计算连接的频率,会怎么样?

#Drop duplicates
people_network_no_dupes = people_network.drop_duplicates()#Which two people are the most connected?
people_network_freq = people_network_no_dupes.groupby(["source", "target"]).size().reset_index(name="freq")
people_network_freq.sort_values('freq',ascending=False).head(10)

现在我们得到了一个非常不同的列表:

作者图片

在我们的列表中,有很多成对的人合作过两部不同的电影。没有两个人合作过两部以上不同的电影。

现在,我们可以使用 NetworkX 将这个 DF 转换成图形,并运行一些网络分析。下面的代码从我们的边列表中提取一个网络,并按照每个节点的度数进行排序。在这个图表中,这意味着每个人拥有的联系数量。

#Turn df into graph using NetworkX
G = nx.from_pandas_edgelist(people_network_freq, 'source', 'target',edge_attr='freq')#Find the degree of everyone in the network
G_sorted = pd.DataFrame(sorted(G.degree, key=lambda x: x[1], reverse=True))
G_sorted.columns = ['movie','degree']
G_sorted.head()

作者图片

在我们的数据中,人脉最广的人是维多利亚·西奥多。她在《滴答,滴答,嘣!》中扮演了“TTB 乐队 2 号成员——键盘手”的角色她是电影《尾声》剧组的一名音乐家。由于这两部电影拥有我们名单上所有电影中最大的三个演员和工作人员中的两个,维多利亚·西奥多是唯一一个为这两部电影工作的人,她有最多的联系。

现在我们有了一个图表,我们可以从 NetworkX 运行任何内置函数。如果你想四处看看,这里有NetworkX 文档。我们可以用下面的代码找到这个网络中的总人数和总连接数:

#Number of movies in our network
print(str(G.number_of_nodes()) + " people in the network")#Number of connections in the network
print(str(G.number_of_edges()) + " connections (movies) in the network")

这个网络有 3414 人,245939 个连接!这是网络最酷的地方之一——尽管原始数据集可能并不庞大(我们从 37 部电影开始),但网络分析让我们能够提取成千上万的联系和见解,这些在标准数据分析中是无法获得的。

如果我们没有提到中心性测量,这就不是一篇关于网络分析的文章。中心性测量本质上是一种测量网络中节点重要性的方法。衡量重要性的一种方法是计算连接的数量——就像我们上面计算每个节点的度数一样。另一种方法是寻找中间中心性。这是我在以前的一篇文章中对中间中心性的描述。

“中间中心性通过寻找每组两个节点之间的最短路径来计算。对于任意两个节点,它们之间都存在一条最短路径。通过一个节点的最短路径越多,它的介数中心性就越高。在许多节点或节点群之间充当“桥”或“代理”的节点具有较高的“介数中心性”。例如,在一个电力网络中,节点是变电站,链路是电流,位于许多其他变电站之间最短路径上的变电站将有大量电流通过,因此具有更高的介数中心性。”

我们可以使用下面的代码计算中间中心性:

#Calculate bc on our Graph
bc = nx.betweenness_centrality(G,k=1000,weight='freq')#Get nodes from graph and sort by highest betweenness
bc = pd.DataFrame([bc.keys(), bc.values()]).T
bc.columns= ['names', 'values']  # call them whatever you like
bc = bc.sort_values(by='values', ascending=False)

请注意,计算介数可能需要一段时间。

作者图片

这是输出。正如你所看到的,在这个网络中具有最高介数中心性的人是安德鲁·加菲尔德——他出演了其中的三部电影。同样,约翰尼·格林伍德为三部电影配乐,所以他有很高的中间中心性。玛娅·鲁道夫参与了甘草披萨的制作,也参与了卢卡和米切尔夫妇与机器的对决。阿西尔·哈德森是一名舞蹈演员,曾出演过《成为里卡多夫妇》和《未来美国》由于他是《未来 2 美国》和其他电影之间仅有的两个联系之一,他具有非常高的中间中心性。《即将到来的美国 2》的另一个关联是约翰·传奇,,他在动画电影《米切尔一家大战机器》中饰演自己。如果你想看介数最高的人的直观表现,这是我在 Gephi 制作的一个图表。

作者图片

要在 Gephi 中构建这个图,您需要将一个边列表和一个节点列表导出为 csv 文件,然后将它们导入 Gephi。下面是导出这两个文件的代码:

#Get list of nodes from graph
G_nodes = pd.DataFrame(sorted(G.degree, key=lambda x: x[1], reverse=True))
G_nodes.columns = ['names','degree']#Merge betweenness scores into node list
people_nodes = pd.merge(G_nodes,bc, how='left', left_on="names",right_on="names")
#Rename 'names' column -- Gephi is weird about that
people_nodes = people_nodes.rename(columns={'names': 'Id'})#Export to csvs
people_nodes.to_csv("peopleNodes.csv")
people_network_freq.to_csv("peopleEdges.csv")

结论

TMDB 数据库的好处

TMDB API 是一个丰富的电影数据资源。几年前,我写了一篇文章,用 IMDb 数据库对电影数据进行网络分析,但是这些数据有严重的局限性。IMDb 只为每部电影列出 7-10 个“负责人”——通常是导演、几个制片人、作曲家和几个演员。有了 TMDB 的数据库,我们就能得到每部电影的全部演员和工作人员。这让我们可以建立更大、更完整、更有趣的网络。

TMDB 数据库也可以通过 API 获得。所有的 IMDb 数据集都是静态文件,可点击这里下载。这些文件非常庞大,需要进行大量的处理和过滤,才能方便地进行查询。然而,使用那些大的静态文件的好处是,我们从一个地方开始所有的数据。如果我们想要 TMDB 数据库中所有电影的完整列表,我们必须运行额外的电影列表查询——我还没有这样做过。

关于电影网络的思考

名单上所有的美国电影都是相连的,但一些国际电影是断开的。有四部电影与图表完全无关(《平行母亲》、《鲁娜娜:教室里的一头牦牛》、《开我的车》和《用火写作》)——都是国际电影。两部获得提名的国际电影(《世界上最坏的人》和《逃离》)相互关联,但没有其他电影。《上帝之手》(The Hand of God)是一部获得最佳国际电影提名的意大利电影,但它是由网飞制作的,因此与《别抬头》(Don't Look Up)(也是一部网飞电影)共用一个制片人,与《古驰之家》(House of America)的艺术总监也是同一个人

在我几年前用 IMDb 数据写的一篇文章中,我运行了一个社区检测算法,将网络分成紧密分组的节点或社区。这个网络很自然地沿着地理界线瓦解了——有一个中国电影社区,一个西班牙社区等等。充当这些社区和中心“好莱坞”社区之间桥梁的节点具有最高的中间中心性。例如,Penélope Cruz 具有很高的中间中心性,因为她通常是好莱坞和西班牙电影界之间的桥梁。这种地理/语言上的划分在 2022 年奥斯卡的分析中也很明显,即国际电影联系更少。

那么这张图中的密度是多少呢?换句话说,奥斯卡是乱伦、裙带关系、沾沾自喜的骗局吗?我开始这个分析的原因之一是,它看起来像一个密集的图形。我看的每一部奥斯卡提名电影都让我看到另一部奥斯卡提名电影中的人物——《T4》一定是一个非常小的世界,对吗?例如,尽管《法国派遣》没有获得任何奥斯卡提名,但它有蕾雅·赛杜克里斯托弗·沃尔兹杰弗里·赖特——所有这些演员也都出演了死亡时间。我觉得我最近看的电影中有一半都有蒂莫西·柴勒梅德的身影。还是仅仅因为每部电影都有那么多人贡献,所以几乎任何两部电影都会有一个共同的人?

对于一个技术性的回答,我们可以计算我们两个网络的图密度聚类系数。Omar Lizardo 和 Isaac Jilbert 在《社交网络:简介》一书中给图密度下了一个很好的定义。

“图的密度是对参与者之间存在多少联系与参与者之间可能存在多少联系的度量。”

我们电影网的图密度为 0.15,人民网的图密度为 0.042。这意味着电影之间存在大约 15%的潜在联系,而人与人之间只有 4%的联系。那是高还是低?要回答这个问题,我们真的需要一些东西来与之比较。这张图可能比大脑中的神经通路连接更稀疏,但与电影中的其他网络相比呢?下一步,我想将这样一个网络与一个由 37 部随机选择的电影组成的网络进行比较,看看奥斯卡提名者与随机选择的电影之间的联系是多还是少。

从这一分析中可以得出一个结论:参与三部奥斯卡提名电影的工作人员比演员还多。只有三个演员出演了三部电影,但是有八个工作人员出演了三部电影。

对于聚类系数,维基百科提供了这样的定义:

“在图论中,聚类系数是对图中节点倾向于聚集在一起的程度的度量。”

我们的电影图聚类系数为 0.3,人物图聚类系数为 0.98。人际网络的聚类系数要高得多,但根据我们提取该图的方式,这是意料之中的。对于每部电影,每个参与电影制作的人都与其他参与电影制作的人建立了联系。这意味着我们有 37 个完整的图表,根据定义,每部电影一个。同样,如果没有与之比较的东西,很难说 0.3 的聚类系数是高还是低。

我的一些后续问题是:与其他(非提名)电影相比,0.3 的聚类系数高吗?与其他(非提名)电影相比,这些图形密度测量值是高还是低?电影的分类是基于制作公司、导演还是其他变量?我们可以使用网络分析来衡量奥斯卡的代表性吗,也就是说,这 37 部电影是否代表了整个行业?代表性差距在哪里?随着时间的推移,奥斯卡提名者的代表性有所增加吗?随着时间的推移,哪几对人被提名的次数最多?

从电影数据中提取图表让我们能够提出通过传统数据分析无法回答的问题。就连这篇文章中回答的简单问题也是如此,比如“有没有哪部电影没有获得奥斯卡提名?”只能通过把我们的数据连接成图表来回答。一旦我们将数据转换成图表,我们就可以回答更多的问题,其中一些我已经在上面列出来了。也许最重要的是,将数据转化为网络提供了对数据结构更直观的感觉,并允许我们以不同的方式更有创造性地思考我们可能会提出的问题。

如果你觉得这个教程很有帮助和有趣,请跟随:)

请随意评论任何问题,我会尽力回答。

如何使用 Python 和照片库 API 从 Google 相册下载图像

原文:https://towardsdatascience.com/how-to-download-images-from-google-photos-using-python-and-photos-library-api-6f9c1e60a3f3

作者图片

使用 Google 相册 REST API,您可以下载、上传和修改储存在 Google 相册中的图片。

作为快速复习,REST 是应用程序编程接口的一种架构风格,允许与 RESTful web 服务进行交互。[Red20]

GET 请求允许检索数据库条目,POST 请求创建新条目,PUT 请求更新条目,DELETE 请求删除条目。

以下步骤描述了如何设置一个简单的项目,让您可以使用 Python 从 Google 相册下载图像:

1.打开终端窗口并导航到您的工作目录

2.创建子文件夹结构或克隆存储库

git clone [git@github.com](mailto:git@github.com):polzerdo55862/google-photos-api.git

https://github.com/polzerdo55862/google-photos-api.git

文件夹结构—作者截图

repo 包含以下子文件夹:

  • 凭证:文件夹,用于存储向 Google 相册库验证“Python 应用程序”所需的凭证
  • media_items_list: 脚本每次运行时,都会保存一个. csv 文件,其中包含在指定时间段内上传的所有 Google 相册媒体项目和相应的元数据
  • 下载:存储从 Google 相册下载的图片

3.创建虚拟环境并安装所需的软件包

python3 -m venv venv,激活source ./venv/bin/activate,安装需求pip install -r requirements.txt

4.将 venv 添加到 Jupyter 笔记本

安装为 Jupyter: pip install ipykernel提供 IPython 内核的 ipykernel,并将您的虚拟环境添加到 Jupyter: python -m ipykernel install --user --name=venv

您可以通过导航到/Users/Library/Jupyter/kernels来检查安装。应该会有一个名为venv的新目录。在这个文件夹中,您会发现kernel.json文件,它定义了您正在使用的 Python 安装的路径。

卸载不再需要的内核:jupyter kenelspec uninstall venv

5.导航到该文件夹并启动 jupyter 笔记本/实验室

jupyter lab .

创建一个新的 jupyter 笔记本文件(或者在 repo 中打开现有的文件),并选择刚刚创建的环境“venv”作为内核

在 Jupyter 笔记本中选择虚拟环境—作者图片

6.启用 Google 相册 API 服务

创建新项目—作者的图像

  • 要打开 Google API 库,从左侧导航菜单中选择APIs & Services > Library
  • 搜索Google Photos Library API。选择正确的结果,然后单击“启用”。如果已经启用,请单击“管理”
  • 之后,它会将您转到“照片 API/服务详情”页面(https://console.cloud.google.com/apis/credentials)

启用 API 作者提供的图像

7.配置“OAuth 同意屏幕”[Sta21]

  • 在 Google 相册 API 服务页面的左侧,点击“ OAuth 同意屏幕”(在“凭证”下方)并定义同意屏幕
  • 添加测试用户:指定用于测试 API 调用的 google 帐户的电子邮件

将用户添加到同意屏幕—作者截图

8.创建 API/OAuth 凭据

  • 在 Google 相册 API 服务页面的左侧,点击凭证
  • 单击“创建凭据”并创建 OAuth 客户端 ID
  • 作为应用程序类型,我选择“桌面应用程序”,并给你的客户端一个你想用来调用 API 的名称
  • 将 JSON 文件下载到创建的凭证中,将其重命名为client_secret.json,并保存在“凭证”文件夹中

创建凭据—作者提供的图像

9.首次使用谷歌照片图库 API:

下一节展示了如何使用 OAuth 凭证通过 Google Library API 进行身份验证。下面的代码部分包含以下步骤:

  1. 创建 GooglePhotosApi 对象google_photos_api = GooglePhotosApi()

2.函数run_local_server()检查在.pickle文件中是否已经存储了有效令牌,如果没有,它使用client_secret.json文件cred = google_photos_api.run_local_server()运行 OAuth 2.0 授权流

第一次调用 API(OAuth 2.0 授权流程):

Google 将询问您是否要授予应用程序在范围中定义的所需权限:

作者图片

由于目前这只是一个测试应用,谷歌会让你意识到这一点。单击“继续”继续。一旦授予应用程序必要的权限,就会创建一个token_...pickle文件,下载并存储在文件夹/credentials/中。这个令牌文件用于将来的 API 请求。

第一次 API 调用后生成的令牌文件—作者截图

10.使用 Pythons 请求模块和令牌文件从 Google 相册中检索数据

下面的函数向媒体 API 发送 post 请求,以获取所有条目的列表。由于 API 返回限于 100 个项目,所以搜索范围缩小到一天。因此,如果在一天之内创建/上传了超过 100 个图像,这种调用只会丢失图像。

使用 API 的响应将结果和所需的元数据写入数据框并返回:

11.使用定义的功能从 Google 相册下载媒体项目

a.用已经下载到/downloads/文件夹的所有文件创建一个列表

b.定义从开始日期到结束日期(今天)的所有日期的列表

c.对所有日期执行 API 调用,以获得所有媒体项目的列表。API 返回:

d.将下载到/downloads/文件夹中的文件的媒体项目列表与 Google 相册中的媒体项目进行比较,以下载尚未下载的项目。现在可以使用baseUrl和 python 请求模块为每个媒体项发送 get 请求。

e.将包含所有媒体项目的列表另存为。csv 在/media_items_list/

摘要

本文描述了如何通过 Python 使用 Google Photos REST API 下载(和操作)Google Photos 内容。

我主要使用 API 来搜索用我的智能手机拍摄的图像的文本和特征,并将提取的信息推送到概念。

参考

[stat 21]错误 403:来自 Google 身份验证 web API 的 access_denied,2021。URLhttps://stack overflow . com/questions/65184355/error-403-access-denied-from-Google-authentic ation-we b-API-Duncan-Google-ACC

[Red20] RedHat:什么是 REST API?, 2020.网址https://www.redhat.com/en/topics/api/what-is-a-rest-api

如何用 Python 下载优步的六角网格

原文:https://towardsdatascience.com/how-to-download-ubers-hexagonal-grid-with-python-3140fe95e19a

一篇关于使用 python API 访问优步 H3 六边形索引的实践短文

图片作者。

优步开放其 H3 电网已经四年了。该公司最初开发了用于乘坐优化的索引系统,但事实证明它对所有涉及可视化和探索空间数据的任务都很有用。

虽然优步不得不提出这些六边形层次索引来设置动态价格,但地理空间领域的研究人员和从业人员很长时间以来一直在使用网格系统将事件存储到单元中。六边形在模型中最广为人知的用途之一是克里斯塔勒的中心位置理论,这是一种在城市地理学中的理论,试图解释世界各地城市和城镇的分布模式、规模和数量背后的原因。该理论提供了一个六边形网格框架,通过该框架可以研究区域的位置模式。

克里斯塔勒的中心位置理论。改编自克里斯塔勒。来源:韦塞拉,2015 年

六边形形状在这里是理想的,因为它允许由中心位置顶点形成的三角形连接,并允许每个单元以相同的方式与其他六个单元接触(例如,潜在地连接并建立流)。

虽然六边形的变形不太明显,但它们不能完全细分,也不能与街道对齐。所有这些限制都可以通过聚类的偏向性来解决,聚类的细胞反过来模拟对分析更有用的形状。

全球标准化电网的潜力

H3 系统在全世界范围内提供了具有可比较形状和大小的细胞。这为建立一个标准提供了可能性,通过该标准可以将任何空间数据集设置为。这意味着越多的空间研究使用这种网格,数据集就越容易互换和相互比较。

以蒙特利尔的 Anagraph 的加拿大人口数据集为例,该数据集使用了不同的来源——其中包括加拿大 2021 年人口普查——来模拟使用 H3 指数的人口六边形网格数据集

人口网格图。来源: Anagraph 几何查看器。作者截屏。

有影响力的流动性研究员 Rafael Pereira 也是如此,他的关于在巴西获得机会的研究很好地利用了 H3 指数,以更好地捕捉涉及移动路径或连通性的现象的空间动态。

IPEA 获得机会项目。改编自 IPEA。图片作者。

那你是怎么得到它的呢?

如果您使用空间数据,您可能希望能够获得一个链接来下载某处的 shapefile。在这里不会是这样的。

为了得到它,我们需要使用 H3 API 。如果你想知道,一个应用程序编程接口 ( API )设置了可以用来调用(即访问)保存我们需要的数据的服务器的工具。基本上,这意味着我们可以通过向系统发送某些消息,使用一组预定义的规则来与该应用程序及其数据进行交互。

记住这一点,让我们使用 H3 API 文档中描述的方法提取与感兴趣区域相交的所有多边形。第一步是利用 geopandas 吸收上述区域。

图片作者。

既然我们已经获得了一个包含要提取六边形的区域的地理数据框架,让我们开始使用实际的 H3 图书馆。我们将从使用 h3 的 polyfill 方法开始,该函数将从地理数据框架和比例中获取第一个也是唯一一个要素的几何-因为 H3 系统是多比例的,所以我们可以提取多种大小的六边形-这里将是 8,最细的级别。

hexs 变量将返回一个非常简单的列表,其中包含与所提供区域相交的第 8 层所有六边形的 id。

图片作者。

接下来,我们将使用该列表向 H3 API 请求与它们对应的实际几何图形。为此,我们将创建一个 lambda 函数,它将一个输入(十六进制 ID)传递给 h3_to_geo_boundary 方法,并将响应转换为 shapely 的多边形。

然后,我们将使用 python 的 map 方法将 id 列表(hexs 变量)传递给 polygonise 函数。这又被转换成将填充 geoseries 的多边形列表(或 geopanda 的空间类型列表)。

图片作者。

这看起来与我们要找的一模一样,所以剩下的工作就是创建一个包含结果的地理数据框架,并将其导出到地理包(或者 shapefile,如果您是守旧派的话)。

那是一个包裹

就是这个!我们仅用几行代码就成功地提取了我们感兴趣区域的 h3 六边形。

如果你有问题或建议,不要犹豫,随时给我写信。如果你喜欢这篇文章,考虑给我买一杯咖啡,这样我就可以继续写更多的文章了!

如果你还不是一个媒体成员,并且想支持像我这样的作家,请随时通过我的推荐链接注册:

https://guilhermeiablonovski.medium.com/membership

如何方便地从国家统计机构获取和下载公共数据

原文:https://towardsdatascience.com/how-to-easily-access-and-download-public-data-from-national-statistical-institutions-dab9f2e6a18f

R 中 PxWeb API 接口指南,使用 PxWeb 包。

照片由东阮Pixabay 拍摄

PxWeb 是一个网络应用编程接口和网络工具,用于传播来自国家统计机构的数据。在 R 中,有一个名为pxweb的包,它连接到这些 web APIs,使您能够从 NSI 数据库直接将数据下载到 R 会话中,而无需通过 HTTP/HTTPS 使用 web 浏览器。

在本指南中,我将向您展示如何从统计机构下载公共数据。我将举一个例子,寻找显示瑞典父母第一个孩子出生时平均年龄的数据。我们可以在瑞典统计局的人口数据库中找到这些数据,这是他们公开数据的一部分。他们的开放数据可供所有人免费使用。

PxWeb APIs 由元数据和实际数据组成。元数据是一个分层的节点树,其中每一层都包含有关其子节点的信息。您可以将这些节点视为文件夹。您可以在这些表中导航,直到找到包含感兴趣的数据的表。

您需要两件事情来访问和下载数据,API 中指向数据表的 URL 和指定您想要下载什么数据的查询。我将向您展示这两者是如何通过一个非常直观的分步过程获得的。

安装并加载 pxweb 包

如果是第一次使用pxweb包,你需要安装它。然后将它加载到您 R 会话中。

作者图片

导航 API

我们通过输入pxweb_interactive()连接到 API 目录。您可以向该函数传递一个 URL 来跳过一些步骤,直接访问特定的 API 或数据库级别。

作者图片

我们将继续打开 API 目录,以便您可以看到当前包含在软件包中的统计机构。您可以打开任何 PxWeb API,即使它没有包含在软件包中。只需在pxweb_interactive()调用中将 URL 添加到 API 中。

作者图片

我们想从瑞典统计局下载数据,所以我们输入“1”。在选择了一个 API 之后,你还要选择你想要访问的数据库的版本和语言。之后,您将在 API 中看到所有可用的数据库。我们对人口数据库感兴趣,所以我们选择 11 号。

作者图片

您只需继续导航并选择要打开的子文件夹,直到找到包含要下载的数据的表格。

作者图片

作者图片

查询数据

现在我们在包含感兴趣的数据的表中。(表:按地区、活产顺序、父母、观察和年份分列的儿童平均出生年龄。)我们将查询数据并选择每个变量的值,一次一个变量。

作者图片

对于我们的查询,我选择了以下数据:

地区:瑞典和斯德哥尔摩县
BarnOrder(活产顺序):第一个孩子
for older(父母):母亲、父亲
ContentsCode:孩子出生时的平均年龄
Tid(时间):2000 年至 2020 年

下载数据

当您定义了查询后,R 会问您几个问题来帮助您将数据下载到 R 中。

作者图片

通过对所有这些问题选择“是”,pxweb包非常有用,它将你下载数据所需的所有代码打印到控制台的一个整洁的 data.frame 中。

1。将查询代码存储为 json 文件。

根据选择的数据,R 将我们的查询以 json 格式打印到控制台。将它保存在一个单独的 json 文件中。如果想要更改查询,可以直接在这个 json 文件中进行。

作者图片

2。下载数据并转换为 data.frame 格式

使用pxweb_get(url = [url to table], query = [path to json])功能,您可以将数据下载到 R 会话中。r 已经把需要的代码打印到控制台上了。您只需要更改 json 文件的路径。运行as.data.frame()将数据转换成 data.frame

作者图片

现在您在 R 会话中有了一个整洁的 data.frame,您可以继续分析和可视化数据了!我为我们的数据做了一个图表,它显示了斯德哥尔摩第一次做父母的平均年龄远远高于全国平均水平。

作者图片

作者图片

3。获取数据注释

有时数据有注释,您可能也想下载它们。在我们的例子中,没有注释。要下载评论,你只需使用下面的代码。

作者图片

4。获取数据引用

为了可再现性,引用数据是一种好的做法,这样你和其他人就可以看到数据来自哪里,何时下载的。

作者图片

对于我们的例子,引用看起来像这样

瑞典统计局(2022 年)。"按地区、活产顺序、父母、观察和年份分列的儿童平均出生年龄."[使用 pxweb R 包 0.12.0 访问的数据 2022–02–07 12:48:51],<url: class="ae ky" href="http://api.scb.se/OV0104/v1/doris/en/ssd/BE/BE0101/BE0101H/MedelAlder1" rel="noopener ugc nofollow" target="_blank">http://API . SCB . se/ov 0104/v1/Doris/en/SSD/BE/BE 0101/BE 0101h/medel alder 1>。</url:>

如果您是用 LaTex 编写的,该软件包还会将引文打印为 BibTex 条目。

我发现pxweb包是一个非常有用的工具。它很容易使用,并且可以把你想要的数据整理成一个整洁的格式。如果您需要某个项目的数据,您可以通过使用pxweb_interactive()功能浏览目录及其数据库来获得灵感。如果您已经知道使用什么数据,或者如果您随着时间的推移分析某个变量,您可以使用pxweb_get()函数直接获得数据。

**pxweb*套装由曼斯·马格努松、马库斯·凯努、詹尼·霍瓦里和利奥·拉赫蒂(罗彭戈夫)开发。网址:http://github.com/ropengov/pxweb

如何轻松自信地用 Python 实现单元测试

原文:https://towardsdatascience.com/how-to-easily-and-confidently-implement-unit-tests-in-python-cad48d91ab74

知道你的代码不会被破坏,你想晚上睡得更好吗?那么这篇文章就送给你了。

布雷特·乔丹在 Unsplash 上的照片

什么是单元测试,为什么单元测试很重要,单元测试的最佳实践是什么,我如何用 Python 实现单元测试?如果你想知道这些问题的答案,请继续阅读。

什么是测试?

测试是一个简单而直观的概念。您编写与您的主要代码并行的测试,以确保它按照您期望的方式工作。每个人都以这样或那样的方式测试他们的代码——但是这样做有更好和更坏的方法。

大多数人会在终端中运行快速测试,或者混合使用 assert 语句和 print 语句。我不是说不要这样做,但是有更有效的方法来测试你的代码,我很快就会解释。但是首先,让我让你相信测试你的代码是必要的。

为什么要使用测试?

首先,如果你在编写代码的同时编写测试,这会让你在更深的层次上思考你的代码。它会让你更多地考虑你正在编写的代码的输入、输出和目标。这将鼓励你从一开始就编写更高效的代码。

它可以为您节省大量的调试时间。将编写测试视为对时间(和压力水平)的投资。当你写代码的时候,你同时也写了测试。如果事情变得不可收拾,你对这些测试的投入将会给你一个指向问题的大箭头。当涉及到长而复杂的函数时尤其如此。

测试也是可复制的。就像您将一个函数从一个项目复制并粘贴到另一个项目一样,您也可以对测试进行同样的操作。你的功能和测试就像蝙蝠侠和罗宾。

您甚至可以在函数之前编写测试!有一个思想流派叫做测试驱动开发(TDD ),它建议你应该在测试之前编写函数。这是否是一个好主意是一个非常有争议的辩论,我不打算卷入其中。

如何使用测试?

单元五集成测试

首先,我们需要讨论两种主要的测试类型。您将遇到的主要测试类型是单元测试。这是对特定单元或组件的测试——通常是一项功能。集成测试是测试所有这些组件如何组合在一起。下面的例子将集中于单元测试。

所以,让我们从一个独立单元测试的基本例子开始。假设我们有下面的函数:

def add(x,y):
   return x + y

对此进行单元测试的一个例子是:

assert add(2,4) == 6, "Should be 6"

关键字assert让你测试代码中的条件是否返回 True,如果不是,程序将抛出 AssertionError。小心这里的括号,因为断言是一个语句。

如果您在 Python 终端中运行这个,什么也不会发生,因为 2 + 4 实际上等于 6。再试一次,将 6 改为 7,正如所承诺的,您将得到一个 AssertionError。

由作者创建。

如您所见,它显示了 assert 语句后面的错误消息。

不过,我们可以通过测试提高效率和组织性。

测试用例、测试套件和测试运行程序

我给你介绍几个概念。

首先,测试用例。测试用例是对一个案例或一个响应的具体测试。assert 语句是测试用例的一个例子。我们正在检查,在输入 2 + 4 的情况下,我们会收到 6 的答案。

如果我们将许多测试用例组合在一起,我们得到一个测试套件。通常,将许多相似的案例加在一起是有意义的。

当我们运行我们的测试用例以及测试套件时,我们需要一种有组织的、高效的方式来完成它。这就是我们使用测试转轮的地方。测试运行人员协调测试的执行,让我们的生活变得更加轻松。

有许多测试运行程序,但是我最喜欢的和内置到 python 中的是 Unittest 。这就是我们今天要做的。

使用单元测试

Unittest 有一些你必须遵守的规则。一旦你了解了它,它简单、优雅且易于使用。

首先,你必须将所有的测试作为方法放入类中。一旦这样做了,就可以用从 unittest 继承的特殊断言方法替换 assert 关键字。测试用例类。

这是一个例子,用的是我们已经看过的例子。我在那里创建了一个名为“tests.py”的新文件,这是一个标准约定。我将 add 函数存储在一个名为 functions 的文件夹中,与 test.py 在同一层。

由作者创建。

import unittestimport functions class TestAdd(unittest.TestCase): def test_add(self): self.assertEqual(functions.add(2, 4), 6) if __name__ == '__main__':
    unittest.main() 
  1. 首先,我们必须导入unittest作为标准。
  2. 创建一个名为TestAdd的类,它继承自TestCase类。
  3. 将测试函数转换成方法。
  4. 更改断言以使用TestCase类中的self.assertEqual()方法。下面是可用方法的完整列表。
  5. 将命令行入口点改为 call unittest.main()

unittest 断言方法的完整列表—【https://docs.python.org/3/library/unittest.html#unittest. TestCase.assertTrue

现在,如果您在终端中运行 test.py,您应该会看到这个。

由作者创建。

虚线上方的每个点代表一个已经运行的测试。如果这个测试抛出了一个错误,它将被一个 E 或 F 代替。

所以如果我们用 7 代替 6,我们会得到这个:

由作者创建

由作者创建

当然,我们这里只有一个测试,所以我们已经知道它在哪里失败了。如果我们有更多的数据,就很容易看出哪里出了问题,因为它非常具体。

如何写出好的测试?

清楚地命名您的测试——不要忘记称它们为测试。

这个测试不会运行。

class TestAdd(unittest.TestCase): def add_test(self): self.assertEqual(functions.add(4, 2), 7)

测试方法必须以“测试”开始。“测试-添加”将运行,但“添加测试”不会运行。如果你定义了一个不以' test '开头的方法,它会自动通过测试--因为它从来没有运行过。所以还不如根本不存在。实际上,有一个你认为已经通过的测试比一个不存在的测试要糟糕得多。它会影响你的 bug 修复。还有,不要怕名字长,要具体。这使得查找 bug 变得容易多了。

从简单直观的测试开始,逐步建立

从首先想到的测试开始。这些应该确保你的职能的主要目标是正确的。一旦这些测试通过,那么你就可以考虑更复杂的测试了。在确保基本功能正确之前,不要变得复杂。

边缘案例和越界

我喜欢开始思考边缘案例。让我们以处理数字为例。如果我们输入负数会发生什么?还是花车?或者像零这样的边界数。零爱打破代码,所以有一个测试总是好的。让我们再举一些例子。

class TestAdd(unittest.TestCase): def test_add(self): self.assertEqual(functions.add(4, 2), 7) self.assertEqual(functions.add(-1, 1), 0) self.assertEqual(functions.add(-1, -1), -2) self.assertEqual(functions.add(0, -1), -1)

瞧,我们的代码看起来不错:

每个测试都应该是独立的

测试不应该互相依赖。Unittest 有内置的功能来防止你这样做。[setUp()](https://docs.python.org/3/library/unittest.html#unittest.TestCase.setUp)[tearDown()](https://docs.python.org/3/library/unittest.html#unittest.TestCase.tearDown)方法允许您定义将在每个测试方法之前和之后执行的指令。我说这是因为 Unittest 不能保证您的测试会按照您指定的顺序运行。

避免使用 Assert。伊斯特鲁

它只是没有给你足够的信息。它只会告诉你这个值是真还是假。如果你像我们之前一样使用 assertEqual 方法,你会得到更多的信息。

AssertionError: 6 != 7

比以下方式更容易调试:

Expected True, but the actual result was False

有时候你的测试仍然会遗漏一些东西——没关系。

只要回去添加一个新的测试,这样你下次就不会错过了。

让我们来看看这个将一个数四舍五入并加 10 的函数的例子。没什么疯狂的。

def round_plus_ten(x): x = round(x) + 10 return x

这个测试套件。

class TestRound(unittest.TestCase): def test_round(self): self.assertEqual(functions.round_plus_ten(4.3), 14) self.assertEqual(functions.round_plus_ten(4.7), 15) self.assertEqual(functions.round_plus_ten(4.5), 15)

从这个角度来看(如果你还不知道 round 方法的来龙去脉),你会认为所有的测试都通过了。他们没有。

由作者创建

由作者创建

您可以在这里看到(感谢测试运行器的有用性),舍入 4.5 不等于 5。因此,当我们加上 10 时,它不等于 14。round 方法在边距处向下舍入,而不是向上舍入。这些小错误有时会破坏整个程序,正如我在开始时所说的,你甚至不会想到它们。

这个例子强调了两件事。

1 —你永远不会想到你的程序可能失败的所有方式,但是测试增加了你的机会。

2-如果您遗漏了一些东西,回到您的测试文件,为这种情况编写一个新的断言。这意味着您在将来不会再错过它(包括您将函数和测试文件复制到的任何其他项目)。

一个好的测试类在未来和一个好的函数一样有用。

感谢阅读,我希望这能帮助你。

If I’ve inspired you to join medium I would be really grateful if you did it through this [link](https://jamesasher4994.medium.com/membership) — it will help to support me to write better content in the future.If you want to learn more about data science, become a certified data scientist, or land a job in data science, then checkout [365 data science](https://365datascience.pxf.io/c/3458822/791349/11148) through my [affiliate link.](https://365datascience.pxf.io/c/3458822/791349/11148)

这是我写的其他一些东西:

如何使用 Python 轻松实现电子邮件自动化

原文:https://towardsdatascience.com/how-to-easily-automate-emails-with-python-8b476045c151

用 Python 自动化枯燥的电子邮件

Unsplash 上的在线打印机拍摄

你知道大多数办公室工作的共同点吗?在大多数情况下,你必须定期发送电子邮件。

不管你是程序员、数据科学家还是工程师,你都有可能每天都要阅读和回复电子邮件。这项活动并没有给我们的职业增加任何价值,然而它停止了我们的工作流程,占用了我们宝贵的时间。

解决办法?用 Python 实现自动化!

在本指南中,我将向您展示如何使用 Python 自动发送电子邮件。我们将在本教程中使用 Gmail,所以请确保您有一个 Gmail 帐户来测试这种自动化。

**Table of Contents** 1\. [Turn On 2-Step Verification](#62c7)
2\. [Sending Email with Python](#bc59)
 - [Import the libraries and set email sender and receiver](#0c87)
 - [Set the subject and body of the email](#cbd8)
 - [Add SSL](#fe88)
 - [Log in and send the email](#17a9)
3\. [Schedule the Python Script to Run Monthly, Weekly, or Daily](#c3f9)

如果你不想看,你可以看我的视频!

1.打开两步验证

在我们开始编写代码之前,我们需要设置我们的 Gmail 帐户,以便能够在 Python 中使用它。

过去,我们可以通过打开“不太安全的应用程序访问”来轻松地使用 Python 连接到 Gmail,但该选项不再可用。我们现在要做的是打开两步验证,以获得一个 16 个字符的密码,我们可以使用该密码使用 Python 登录 Gmail。

首先,进入你的 Google 账户,选择你想在本教程中使用的账户,并在左侧面板选择“安全”选项。

作者图片

然后向下滚动,直到找到“登录谷歌”部分这里我们需要点击“两步验证”

作者图片

在这之后,我们会看到新的一页。我们必须点击“开始”

谷歌会要求再次登录。然后我们必须输入一个电话号码,并点击“下一步”我们将获得一个代码来验证我们的电话号码。在我们引入代码之后,我们应该会看到下面的页面。

作者图片

我们需要点击“打开”

如果一切设置正确,我们将看到一个新的页面,显示消息“两步验证开始”

最后,我们需要转到“应用程序密码”部分,因此再次转到您的 Google 帐户,点击“安全”,向下滚动直到您找到“登录 Google”部分,然后选择“应用程序密码”。

作者图片

我们需要再次登录。之后,我们应该会看到下面的页面。

作者图片

在“选择应用程序”下拉列表中,选择“其他(自定义名称)”并键入您想要的任何名称。我将我的命名为“Python ”,然后点击“生成”

在此之后,我们应该会看到一个新的页面,在一个黄色框中有 16 个字符的密码,如下所示。

作者图片

都弄好了!我们将使用这个 16 个字符的密码登录我们的 Python Gmail 帐户。

现在,您可以复制这个密码并将其粘贴到 Python 脚本的一个变量中,或者使用环境变量隐藏密码(我强烈推荐您这样做)。你可以按照我的指南在 Windows 和 macOS 上创建环境变量

2.使用 Python 发送电子邮件

一旦我们打开两步验证并有了 16 个字符的密码,我们就可以开始编写代码了。

导入库并设置电子邮件发送者和接收者

要使用 Python 发送电子邮件,我们需要使用以下内置的 Python 库。

**import** smtplib
**import** ssl
**from** email.message **import** EmailMessage

email_sender = 'codelessearnmore@gmail.com'
email_password = 'write-password-here'
email_receiver = 'write-email-receiver-here'

此外,我们设置电子邮件发送者和密码(这是我们用来打开两步验证的电子邮件)以及电子邮件接收者。

请注意,电子邮件收件人不一定是 Gmail 帐户,也可以来自不同的电子邮件服务。

设置电子邮件的主题和正文

现在我们需要定义一个主题和一个主体。我们可以在这里写任何想写的东西。

**subject** = 'Check out my new video!'
**body** = """
I've just published a new video on YouTube: https://youtu.be/2cZzP9DLlkg
"""

注意,我在正文中用三重引号写了多行。

之后,我们实例化EmailMessage类,并使用我们之前为电子邮件、主题和正文创建的变量。

**em** = EmailMessage()
**em['From']** = email_sender
**em['To']** = email_receiver
**em['Subject']** = subject
**em**.set_content(body)

添加 SSL

现在让我们使用 SSL 来增加一层安全性。SSL 是保持互联网连接安全和保护在两个系统之间发送的任何敏感数据的标准技术。

context = ssl.create_default_context()

登录并发送电子邮件

最后,我们指定主机smtp.gmail.com,通过端口465连接,并使用上一步定义的context登录并发送我们的电子邮件。

恭喜你!我们刚刚用 Python 发了一封电子邮件。进入email_receiver收件箱查看我们发送的邮件。

这是我收到的邮件。

作者图片

你可以在我的 Github 上查看我们在本指南中构建的脚本。

注意:如果运行脚本后得到一个ssl.SSLCertVerificationError,搜索一个名为Install Certificates.command的文件并安装它。

为此,进入“应用程序”,点击一个名为“Python 3。x”,并双击文件Install Certificates.command

作者图片

一旦安装完成,在运行脚本时,您应该不会收到任何错误消息。

3.安排 Python 脚本每月、每周或每天运行

您可以使用 macOS 上的 crontab 和 Windows 上的任务调度器来安排每天或每周执行这个 Python 脚本。

要了解如何做到这一点,请查看我下面的指南。

自动化你的生活! 加入我的 10k+人电子邮件列表,获取我的免费自动化备忘单。

如果你喜欢阅读这样的故事,并想支持我成为一名作家,可以考虑报名成为一名媒体成员。每月 5 美元,让您可以无限制地访问数以千计的 Python 指南和数据科学文章。如果你用我的链接注册,我会赚一小笔佣金,不需要你额外付费。

https://frank-andrade.medium.com/membership

如何用 Python 轻松构建第一个机器学习 Web 应用

原文:https://towardsdatascience.com/how-to-easily-build-your-first-machine-learning-web-app-in-python-c3d6c0f0a01c

使用 Python 中的 Flask 创建 ML web 应用程序的分步指南

格式像素上拍照

构建机器学习模型最酷的部分之一是与他人分享我们构建的模型。

不管你建立了多少模型,如果它们离线,只有很少的人能够看到你的成就。这就是为什么我们应该部署我们的模型,这样任何人都可以通过一个漂亮的 UI 来使用它们。

在本文中,我们将从头开始使用 Flask 部署一个线性回归模型。Flask 是一个 Python 框架,让我们可以轻松开发 web 应用程序。遵循本指南后,您将能够在浏览器中使用简单的机器学习模型,如下图 gif 所示。

作者图片

本指南分为两部分。在第 1 节中,我们将快速构建我们的模型,在第 2 节中,我们将从头开始构建 web 应用程序。本指南的主要目的是构建一个 ML web 应用程序,所以你可以去我的 Github 下载在第一部分创建的模型(model.pkl)并跳到第二部分。

**Table of Contents** 1\. [Building a Simple Machine Learning Model](#7113)
 - [First things first — Libraries and Dataset](#a1b9)
 - [The dependent and independent variable](#b886)
 - [Fitting and saving the model](#6bad)
2\. [Building The Web App with Flask](#e14b)
 - [Setting up a new virtual environment](#17b3)
 - [Installing Flask and quick setup](#e0d6)
 - [Loading the model, building the home function and front end](#4a1e)
 - [Building the form and predict function](#0f0a)

不想看书?你可以看我的视频!

1.构建一个简单的机器学习模型

最简单的机器学习算法之一是线性回归。在本节中,我们将构建一个预测房价的多元线性回归。在这一节的最后,我们的模型将保存在 pickle 中,在下一节,我们将使用 Flask 部署我们的机器学习模型。

先做最重要的事—库和数据集

对于这一部分,我们必须安装 scikit-learn 和 pandas:

pip install scikit-learn
pip install pandas

此外,我们将使用包含 3 列的数据集:值(以 1000 美元为单位)、房间数(每个住所的房间数)和距离(到就业中心的加权距离)。你可以在 Github 或者 Google Drive 上找到这个用 Excel 生成的随机数据。

让我们用熊猫来看看这个数据集。

**import pandas as pd**
df = pd.read_csv('prices.csv')

作者图片

我们的线性回归模型的目标是根据房屋的房间数量和到就业中心的距离来预测房屋价值。

因变量和自变量

为了建立我们的线性回归模型,我们必须定义因变量(结果)和自变量(预测)。

这是我们的因变量和自变量。

  • 因变量:“值”
  • 自变量:“房间”和“距离”

下面是设置这两个变量的代码

y = df['Value'] 
X = df[['Rooms', 'Distance']]

拟合和保存模型

通常,您需要争论数据、训练和验证结果,但是为了简单起见,我们将只关注模型的拟合和部署。

为了构建我们的回归模型,我们需要从sklearn导入linear_model

**from** sklearn **import** linear_modellm = linear_model.LinearRegression()
lm.fit(X, y)

一旦我们建立了lm模型,我们就可以预测给定roomsdistancevalue

lm.predict([[15, 61]]

如果运行上面的代码,预测值将被打印出来。

那好吧!但是现在我们想把所有这些部署在一个网站上,这样任何人都可以玩我们的模型。在下一节中,我们将用 Flask 将所有内容从后端发送到前端,但在此之前,让我们用 pickle 保存我们的lm模型。

**import** pickle
pickle.dump(lm, open('model.pkl','wb')) 

注意;如前例所示,lm.predict()接受数据帧格式的输入[[]]。在下一节中,请记住这一点。

2.用 Flask 构建 Web 应用程序

Python 为构建 web 应用程序提供了不同的选项。烧瓶是最简单的选择之一。

对于本节,建议创建一个新环境。使用不同的环境将有助于我们更好地管理构建模型和部署 web 应用程序所需的不同资源。

设置新的虚拟环境

在本节中,我将创建一个名为deploy-mlmodel-env 的虚拟环境,在终端上运行以下命令。

python3 -m venv deploy-mlmodel-env

我将创建一些其他文件夹来更好地组织我的目录。这是它的样子。

图片 bu 作者

您可以随意组织您的目录,但是要确保我们在上一节中保存的model.pkl在 web app(我们将要构建的)所在的同一个文件夹中。

安装烧瓶和快速设置

要安装 Flask,请在终端上运行以下命令。

pip install flask

现在,要检查一切工作正常,请遵循以下步骤。

创建一个新文件——我将命名为 mineapp.py——并粘贴以下代码(这是从 Flask 文档中提取的一个最小的应用程序示例)

**from** flask **import** Flask

app = Flask**(**__name__**)**

@app.route**(**"/"**)**
**def** hello_world**():**
    **return** "<p>Hello, World!</p>"if __name__ == "__main__":
    app.run()

打开一个终端,使用cd进入app.py所在的工作目录,运行以下命令。

python app.py

应该会弹出以下消息。

最后一行有一个格式为127.0.0.1:port的链接。指示我们的应用程序运行的位置。复制链接(我的是http://127.0.0.1:5000)粘贴到你的网页浏览器。如果在按下 enter 键后,您看到消息“你好,世界!”一切都设置正确。

来源:文献

现在让我给你解释一下这个小脚本是做什么的。

  • app = Flask**(**__name__**):** 创建 Flask 类的一个实例。__name__ 是一个代表应用程序模块名称的变量(这有助于 Flask 知道在哪里寻找资源,比如我们稍后将使用的“模板”)
  • @app.route**(**"/"**): @**代表装饰者(他们修改函数或类的行为)。装饰器告诉 Flask 哪个 URL 应该触发我们的函数。在我们的例子中,主页(/)应该触发hello_world()函数。
  • def hello_world**():** 该函数返回将在浏览器中显示的消息。

加载模型,构建主页功能和前端

现在是时候开始在我们之前创建的app.py文件中构建我们的 web 应用程序了。首先,我们导入Flaskrequestrender_template

然后,我们加载之前用 pickle 保存的线性回归模型model.pkl

此外,我们将把hello_world函数重命名为home。每当我们访问主页(‘/’)时,这个函数将呈现一个名为index.html的 HTML 文件。

index.html文件将包含网站的前端(导航栏、按钮、图片等。).构建前端通常需要一些 JavaScript 和 CSS 的知识。也就是说,我们仍然可以只使用 Bootstrap 和基本 HTML 来构建很酷的 web 应用程序。

要构建前端,首先在你的 app 所在的文件夹中创建一个名为“templates”(不能使用任何其他名称)的文件夹。在这个“模板”文件夹中创建一个 HTML 文件。我把这个文件命名为index.html,但是你可以随意命名。

您的目录应该如下所示。

打开 HTML 文件,写下dochtml,然后按 tab 键。如果幸运的话,您的 IDE 将生成一个基本的 HTML 模板。如果没有,复制并粘贴以下模板。

现在添加引导程序,进入这个网站,将 CSS 部分的代码复制/粘贴到index.html<head>部分。这将加载他们的 CSS。

如果您找不到它,下面是要复制/粘贴的代码:

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">

为了好玩,我们还会添加一个导航栏(我们实际上并不需要它,但它会帮助你习惯于引导程序),所以去网站的导航栏部分,复制代码并粘贴到<head>部分(就在 CSS 下面)

我们的index.html文件应该是这样的(我知道看起来很吓人,但这只是我们复制的代码!)

在运行脚本之前,我将把第一行代码中的light元素改为dark,从而把导航条改为深色(如果保持不变,它将是浅色)。

<nav class=”navbar navbar-expand-lg navbar-**dark** bg-**dark**”>

此外,在正文部分,我将添加一个“Hello World!”:

<body>

  <h1>"Hello World!"</h1></body>

现在要看到所有这些变化,首先,按 CTRL + C 退出终端上运行的当前进程。在此之后,再次运行命令python app.py

如果你去 http://127.0.0.1:5000 ,你应该会看到以下内容。

作者图片

太好了!有标题、导航条和信息。现在,让我们构建实际的应用程序来处理预测。

构建表单和预测函数

预测功能将使用我们的机器学习模型进行预测。为此,首先,最终用户需要在表单中引入两个输入(房间和距离)。

我们将在index.html文件的<body>部分构建这个表单。

首先,我们创建一个<form>标签。这将包含最终用户需要引入的输入。

<form action="{{url_for('predict')}}" method=”post”></form>

参数action 中的 URL 表示提交表单时将表单数据发送到哪里。

在这种情况下,我们会将它发送到“/predict”(我们网站的一个新部分)。我们可以编写“/predict”或者使用url_for() 函数来构建一个特定函数的 URL。

然后,在表单部分,我们创建 2 个<input>标签和 1 个<button>。它们背后的代码很简单,所以我不会深入研究。

重要的是要知道输入标签包含房间和距离变量,为了进行预测,用户需要点击“预测值!”按钮

这是我们目前掌握的代码。

请注意,我包含了添加空格的<br>标签和带有说明的<p>标签。此外,我将所有这些都放在一个带有login类的<div>中。

现在让我们构建预测函数!

app.py文件中,我们用 URL“/predict”创建一个装饰器,它触发一个预测函数并呈现index.html文件。

@app.route('/predict',methods=['POST'])
**def** predict(): **return** render_template('index.html')

现在我们需要从flask导入request来访问终端用户在表单中引入的值。

表单中的值以字典形状返回,因此我们必须使用方括号来获取每个值。一旦我们有了值,我们就把它们放在双方括号[[ ]]中进行预测(这是我们的model.pkl接受的格式)

这是我们正在构建的预测函数。

注意,render_template方法有一个名为prediction_text的新参数。该参数包含用户单击预测按钮后将弹出的消息。

这个消息现在在后端。要将其发送到前端,请在index.html文件的<body>中添加prediction_text 变量。

<body>
 <div class="login">
   ...
  <b> {{ prediction_text }} </b>
 </div>
</body>

最后的index.html是这样的:

而最后的app.py看起来是这样的:

就是这样!现在用 CTRL+C 退出当前进程,在终端运行命令python app.py并转到 http://127.0.0.1:5000

您现在应该可以在浏览器中玩您的模型了!

作者图片

加入我的电子邮件列表,与 10k 以上的人一起获取我在所有教程中使用的 Python for Data Science 备忘单(免费 PDF)

如果你喜欢阅读这样的故事,并想支持我成为一名作家,可以考虑报名成为一名媒体成员。每月 5 美元,让您可以无限制地访问数以千计的 Python 指南和数据科学文章。如果你使用我的链接注册,我会赚一小笔佣金,不需要你额外付费。

https://frank-andrade.medium.com/membership

如何用 Python 轻松创建 PDF 文件(3 步)

原文:https://towardsdatascience.com/how-to-easily-create-a-pdf-file-with-python-in-3-steps-a70faaf5bed5

如何使用 Python 和 HTML 模板在几分钟内创建 PDF 文件

图片来自 Shutterstock,授权给 Frank Andrade

PDF 可能是我们在电脑上能找到的最常见的文件类型之一。

我们使用 pdf 格式的简历、报告、发票,应有尽有!

创建 PDF 文件的常用方法是将 Word 文件另存为。但是我们也可以使用 Python 创建一个 pdf 文件。

专业人士?如果您计划使用同一个模板创建多个 pdf,您可以使用 Python!但是首先,我们将了解如何使用 Python 创建 PDF 文件。

在本教程中,我们将首先创建一个简单的 PDF 文件,然后我们将创建一个更高级的文件,如下图所示。

作者图片

如何用 Python 轻松创建 PDF 文件

用 Python 创建 PDF 文件有不同的方法,但我发现使用 HTML 模板是最简单的方法。

使用此选项,我们可以在几分钟内创建基本和高级 pdf!

安装库

要创建 PDF 文件,我们需要安装以下库:

pip install pdfkit
pip install jinja2

在我们使用pdfkit库之前,我们需要安装wkhtmltopdf。安装步骤取决于您的操作系统:

*# macOS (you need to install brew first)*
brew install homebrew/cask/wkhtmltopdf*# Ubuntu*
sudo apt-get install wkhtmltopdf

如果你用的是 Windows,你可以在这里下载安装程序。

现在让我们用 Python 创建一个简单的 PDF。

步骤 1:创建一个带有占位符的 HTML 模板

首先,我们需要创建一个 HTML 文档,稍后我们将使用它作为模板。

为了创建这个 HTML 文档,我们将使用一个名为 HTML 编辑器的网站。在这个网站上,我们可以在左边的可视化编辑器中键入文本,并在右边的源代码编辑器中生成它的 HTML 代码。

这是我在编辑器中引入的文本(这个文件可以在我的 GitHub 上找到)

注意我用{{}}创建的占位符。稍后我们将使用 Python 在这些花括号中引入值。

这是由 HTML 编辑器生成的 HTML 代码。

我们需要复制这段 HTML 代码,在我们的工作目录中创建一个 HTML 文件,然后将代码粘贴到它上面。

步骤 2:为每个占位符创建一个 Python 变量

首先我们导入 jinja2 和 pdfkit。我有一个名为{{today_date}}的占位符,所以我也导入datetime来获得今天的日期。

然后,我们为 HTML 文档中的每个占位符创建一个 Python 变量,并创建一个将占位符与 Python 变量配对的字典。

注意,我将每个 Python 变量命名为占位符,但是它们可以有不同的名称。

步骤 3:为我们的模板创建一个环境并导出 PDF

现在是时候使用 jinja2 为我们的模板创建一个环境了。

template_loader = jinja2.FileSystemLoader(‘./’)
template_env = jinja2.Environment(loader=template_loader)

然后我们指定使用哪个模板。在我的例子中,我将 HTML 文件命名为basic-template.hmtl。在这之后,我们呈现我们在步骤 2 中创建的字典。

template = template_env.get_template(‘basic-template.html’)
output_text = template.render(context)

接下来,我们将wkhtmltopdf添加到pdfkit配置中。为此,我们需要指定安装wkhtmltopdf 的路径。

下面是您需要运行的命令来获得这个路径。

*# macOS/Linux*
>>> which wkhtmltopdf
'/usr/local/bin/wkhtmltopdf'*# Windows*
>>> where wkhtmltopdf
'C:\Program Files\wkhtmltopdf'

最后,我们使用.from_string()方法导出 PDF 文件。

注意,我给.from_string()方法添加了一个 CSS 参数。这是可选的,但我发现有必要将 PDF 中段落的字体变大。

我在工作目录中创建了一个style.css文件,并编写了下面的代码。

p { font-size: 24px; }
li { font-size: 24px; }

就是这样。这是我们用 Python 生成的 PDF。

我们写的代码和本教程使用的文件可以在我的 GitHub 上找到。

现在要生成一个更高级的 PDF,就像下面的发票,我们需要下载一个 HTML 模板并创建一些占位符。在这个视频教程里,我展示了怎么做。

使用 Python 自动化您的生活! 加入我的 10k+人电子邮件列表,获取我的免费自动化备忘单。

如果你喜欢阅读这样的故事,并想支持我成为一名作家,可以考虑报名成为一名媒体成员。每月 5 美元,让您可以无限制地访问数以千计的 Python 指南和数据科学文章。如果你使用我的链接注册,我会赚一小笔佣金,不需要你额外付费。

https://frank-andrade.medium.com/membership

如何在 Python 中轻松定制 SHAP 图

原文:https://towardsdatascience.com/how-to-easily-customize-shap-plots-in-python-fdff9c0483f2

调整颜色和图形大小,并为 SHAP 图添加标题和标签

(图片由作者提供)

HAP(SHapley Additive exPlanations)是一种流行的建模可解释性的方法。Python 包使你能够快速创建各种不同的图。其独特的蓝色和品红色使该图立即识别为 SHAP 图。

不幸的是,Python 包的默认调色板既不是色盲的,也不是影印安全的。因此,您可能需要更改 SHAP 图的颜色。或者也许你只是想调整颜色,以符合你的企业形象。也可能你唯一想要的就是加个标题。

对于一些 SHAP 地块,定制比其他更容易。一些绘图函数已经提供了这样的参数,但是对于一些绘图类型,您必须变得更加灵活。

对于一些 SHAP 地块,定制比其他更容易。

在本文中,我们将讨论如何

  1. 自定义图形和轴对象 的属性,如调整图形大小、添加标题和标签、使用支线剧情等。
  2. 自定义汇总图、瀑布图、条形图和压力图的颜色

在这篇文章中,我们将集中在定制 SHAP 情节。如果你需要关于如何使用 SHAP 软件包的介绍或复习,我推荐 Conor O'Sullivan 的这篇文章:

确保您安装了 SHAP 版本 0.41.0 。否则,您会在本文的代码片段中遇到错误[1,3]。

import shap
print(shap.__version__)

如果没有,请按如下方式升级软件包:

!pip install --upgrade shap

自定义图形和轴对象的属性

在我们开始着色之前,让我们先了解一下基础知识。在本节中,我们将讨论如何自定义图形和轴对象的属性。

为了能够修改 SHAP 图,您需要将show参数设置为False

*show*:返回前是否调用 matplotlib.pyplot.show()。将此项设置为 False 允许在创建图后进一步自定义图。[2]

调整图形大小

不幸的是,当您想要调整 SHAP 图的图形大小时,调整figsize参数没有多大帮助。相反,您需要设置show = False,然后您可以调整图形的大小,如下所示:

fig = plt.figure()shap.plots.bar(shap_values[0], **show = False**)**plt.gcf().set_size_inches(20,6)**
plt.show()

调整标题、标签和限制

当您设置了show = False后,您可以像往常一样自由调整人物的属性。下面你可以看到一个如何改变标题,x 标签和 x 限制的例子。

fig = plt.figure()shap.plots.bar(shap_values[0], **show = False**)**plt.title("Custom Title") 
plt.xlabel("Custom X-Label")
plt.xlim([-12,12])**plt.show()

使用支线剧情

如果你想在一个图形中显示多个支线剧情,可以使用.add_subplot()方法。

fig = plt.figure()**ax0 = fig.add_subplot(131)**
shap.plots.bar(shap_values[0], show = False)**ax1 = fig.add_subplot(132)**
shap.plots.bar(shap_values[1], show = False)**ax2 = fig.add_subplot(133)**
shap.plots.bar(shap_values[2], show = False)plt.gcf().set_size_inches(20,6)
plt.tight_layout() 
plt.show()

自定义颜色

在我们进入如何定制地块的颜色之前,让我们绕一点弯子,了解一下为什么 SHAP 默认调色板不适合

最近,我写了一篇文章强调色盲安全数据可视化的重要性。

不幸的是,SHAP 的默认调色板既不是色盲也不是影印安全的(在 2022 年 8 月写作时),正如你在下图中看到的。

默认 SHAP 调色板模拟色盲(图片由作者提供。用科布利斯模拟色盲

虽然边缘颜色(洋红色(#ff0051)和蓝色(#008bfb)是色盲安全的,但它们不是影印安全的,因为它们具有相似的色调。

此外,渐变调色板不是色盲安全的,因为对于红绿色盲的人来说,中间范围的紫色调与低范围的蓝色调是无法区分的。

汇总图

注意:对于本节,您必须至少安装了 SHAP 版本 0.40.0,并安装了【1】

对于概要剧情来说,换个调色盘简直易如反掌。从版本 0.40.0 开始,您可以简单地使用cmap参数[1]。

shap.summary_plot(shap_values, 
                  X_train,
                  **cmap = "plasma"**)

使用默认和修改的调色板的摘要图(图片由作者提供)

瀑布图

注意:对于本节,您必须至少安装了 SHAP 版本 0.41.0 [3]。

由于我们没有瀑布图可用的参数,我们需要变得狡猾一点。

首先,您需要将show参数设置为False,以便能够修改图[2]。对于瀑布图,我们需要调整 FancyArrow 和文本对象的颜色。

import matplotlib
import matplotlib.pyplot as plt

# Default SHAP colors
default_pos_color = "#ff0051"
default_neg_color = "#008bfb"# Custom colors
positive_color = "#ca0020"
negative_color = "#92c5de"# Plot Waterfall Plot
shap.plots.waterfall(shap_values[0], **show = False**)# Change the colormap of the artists
for fc in plt.gcf().get_children():
    for fcc in fc.get_children():
        if (isinstance(fcc, **matplotlib.patches.FancyArrow**)):
            if (matplotlib.colors.to_hex(fcc.get_facecolor()) == default_pos_color):
                fcc.set_facecolor(positive_color)
            elif (matplotlib.colors.to_hex(fcc.get_facecolor()) == default_neg_color):
                fcc.set_color(negative_color)
        elif (isinstance(fcc, **plt.Text**)):
            if (matplotlib.colors.to_hex(fcc.get_color()) == default_pos_color):
                fcc.set_color(positive_color)
            elif (matplotlib.colors.to_hex(fcc.get_color()) == default_neg_color):
                fcc.set_color(negative_color)plt.show()

使用默认和修改的调色板绘制瀑布图(图片由作者提供)

条形图

对于柱状图,我们需要采用与瀑布图相似的方法。

同样,您需要将show参数设置为False,以便能够修改图[2]。对于条形图,我们需要调整矩形和文本对象的颜色。

# Plot bar plot
shap.plots.bar(shap_values[0], **show = False**)# Change the colormap of the artists
for fc in plt.gcf().get_children():
    # Ignore last Rectangle
    for fcc in fc.get_children()[:-1]:
        if (isinstance(fcc, **matplotlib.patches.Rectangle**)):
            if (matplotlib.colors.to_hex(fcc.get_facecolor()) == default_pos_color):
                fcc.set_facecolor(positive_color)
            elif (matplotlib.colors.to_hex(fcc.get_facecolor()) == default_neg_color):
                fcc.set_color(negative_color)
        elif (isinstance(fcc, **plt.Text**)):
            if (matplotlib.colors.to_hex(fcc.get_color()) == default_pos_color):
                fcc.set_color(positive_color)
            elif (matplotlib.colors.to_hex(fcc.get_color()) == default_neg_color):
                fcc.set_color(negative_color)plt.show()

带有默认和修改的调色板的条形图(图片由作者提供)

力图

幸运的是,对于力图,我们可以简单地使用plot_cmap参数。

您可以手动指定颜色:

# Custom colors
positive_color = "#ca0020"
negative_color = "#92c5de"shap.force_plot(shap_values[0], 
                **plot_cmap = [positive_color, negative_color]**)

通过指定颜色,使用修改的调色板强制绘图(图片由作者提供)

或者使用预定义的调色板:

shap.force_plot(shap_values[0], 
                **plot_cmap = "PkYg"**)

通过使用预定义的调色板,使用修改的调色板强制绘图(图片由作者提供)

结论

本文展示了如何快速定制 SHAP 图。虽然对某些阴谋来说很容易,但对其他阴谋来说,我们必须变得狡猾。

通常,您需要使用show = False参数来调整 SHAP 图。

然后,您可以轻松地定制图形和轴对象的属性,如图形大小、标题和标签,或者您可以添加支线剧情。

自定义颜色

  • 对于一些绘图类型,我们可以直接使用可用的参数。例如,对于汇总图,我们可以使用cmap参数,对于压力图,我们可以使用plot_cmap参数。
  • 对于某些绘图类型,我们没有可用于改变颜色的参数。所以对于瀑布图、条形图之类的图,我们需要逐个改变美工的颜色。

如果您在使用本文的代码片段时遇到问题,请务必检查您是否至少安装了 SHAP 版本 0.41.0。

喜欢这个故事吗?

如果你想把我的新故事直接发到你的收件箱, 订阅

成为一名媒体成员,阅读更多其他作家和我的故事。报名时可以用我的 推荐链接 支持我。我将收取佣金,不需要你额外付费。

https://medium.com/@iamleonie/membership

TwitterLinkedIn,以及Kaggle!**

参考

[1] C. S .“将 shap.summary_plot()的渐变颜色更改为特定的 2 或 3 种 RGB 渐变调色板颜色”。stackoverflow.com。https://stack overflow . com/questions/60153036/changing-the-gradient-color-of-shap-summary-plot-to-specific-2-or-3-RGB-grad(2022 年 8 月 8 日访问)

[2]《SHAP》,《欢迎来到 SHAP 文献》。https://shap.readthedocs.io/en/latest/index.html(2022 年 8 月 8 日访问)

[3] J. Stevenson,“用 show=False 修复瀑布中的 bug”。github.com。https://github.com/slundberg/shap/pull/2342(2022 年 8 月 8 日访问)

如何用 Python 包轻松获取足球数据(无需网络抓取)

原文:https://towardsdatascience.com/how-to-easily-get-football-data-with-a-python-package-without-web-scraping-c922e7ebfb41

在几分钟内获取关于世界杯、冠军联赛、西甲联赛等的数据

图片来自 Shutterstock,授权给 Frank Andrade

足球比赛的每一分钟都会产生数据,这些数据可用于获得高质量的见解,从而推动球员招募、比赛分析并帮助教练做出更好的决策。

不幸的是,大多数在线免费数据集只包含基本数据,如进球、球队名称和比赛日期。

只有基本的统计数据,我们无法获得许多有价值的见解。

要获得高级统计数据,你可以尝试网络抓取,但在花时间在这上面之前,你可以探索一些体育数据提供商免费共享的数据。

在本指南中,我们将探索 Statsbomb 在其 Python 包statsbombpy上共享的所有免费足球数据。

安装库

为了访问所有的足球数据 Statsbomb 共享,我们需要安装statsbombpy

pip install statsbombpy

一旦我们安装了库,我们必须导入它。

from statsbombpy import sb

提供比赛

要查看 Statsbomb 免费分享的所有比赛,我们只需要运行sb.competitions().

我将删除country_namecompetition_name列中的重复项,以显示 Statsbomb 的独特竞争。

# show all competitions
sb.competitions()

# show unique competitions
sb.competitions().drop_duplicates(['country_name', 'competition_name'])

我们可以看到,Statsbomb 的免费版有 FIFA 世界杯、欧冠、西甲、英超等比赛。

也就是说,Statsbomb 有更多的竞争对手,这些竞争对手只能通过 API 访问付费用户。

让我们探索数据集中可用的比赛之一——2018 年国际足联世界杯。

2018 年国际足联世界杯:探索比赛

为了探索 2018 年 FIFA 世界杯的数据,我们需要competition_idseason_id。从上图我们可以看到,数值分别是 43 和 3。

df_2018 = sb.matches(competition_id=43, season_id=3)
df_2018.head(5)

虽然在上图中看不到,但 dataframe df_2018有 22 列。这是一个足球分析项目的良好开端。

为了获得关于特定比赛的更多信息,我们需要match_id。比如 2018 世界杯决赛,法国 vs 克罗地亚,id 8658。

id_final_2018 = 8658
df_2018[df_2018['match_id']==id_final_2018]

既然我们已经验证了 8658 是正确的 id,那么让我们来看看这 90 分钟内的阵容和发生的所有事件。

阵容

让我们看看法国对克罗地亚的比赛阵容。

lineups = sb.lineups(match_id=id_final_2018)

如果我们打印lineups,我们会看到它是一本字典。让我们看看它的钥匙。

>>> lineups.keys()
dict_keys(['France', 'Croatia'])

我们可以通过钥匙进入法国和克罗地亚的阵容。

这是克罗地亚的阵容。

lineups['Croatia']

这是法国队的阵容。

lineups['France']

比赛项目

要获得法国对克罗地亚比赛中的事件,我们需要再次使用比赛的 id。

df_events = sb.events(match_id=id_final_2018)

让我们看看df_events里面的所有列

df_events.columns

我们可以看到这个数据集中有很多信息。让我们只选择几列,并按minutetimestamp列对数据帧进行排序。

df_events = df_events[['timestamp','team', 'type', 'minute', 'location', 'pass_end_location', 'player']]
df_events = df_events.sort_values(['minute', 'timestamp'])

让我们来看看法国对克罗地亚比赛最后一分钟的情况。

df_events.tail(30)

就是这样!现在你可以自己探索这个包来开始你的足球分析项目。

用 Python 学习数据科学? 加入我的 20k 多人电子邮件列表,获取我的免费 Python for Data Science 备忘单。

如果你喜欢阅读这样的故事,并想支持我成为一名作家,可以考虑报名成为一名媒体成员。每月 5 美元,让您可以无限制地访问数以千计的 Python 指南和数据科学文章。如果你使用我的链接注册,我会赚一小笔佣金,不需要你额外付费。

https://frank-andrade.medium.com/membership

如何在 Google Colab 中轻松安装私有 Python 包

原文:https://towardsdatascience.com/how-to-easily-install-private-python-packages-in-google-colab-98a43c8f8976

压缩项目的优雅替代方案

TLDR: 确保了。json 文件包含关键字“用户名”→存储库帐户持有人的姓名,“访问令牌”→您的 GitHub 访问令牌。请注意,该软件包是一个早期版本,将来可能会有所改进。我会尽量保持更新,但如果不是,请访问这里的

!pip install colab-dev-tools
import os
from colabtools.utils import mount_drive, install_private_library
drive_path = mount_drive()
git_access_token_json_path = os.path.join(drive_path, PATH_TO_JSON)
install_private_library(git_access_token_json_path, PROJECT_NAME)

Colab 是一个使用免费 GPU 快速测试深度学习模型的伟大工具。不过它和 Jupyter 笔记本相比最大的缺点之一就是不能安装自定义内核。这意味着你每次都需要安装所有你需要的软件包。在大多数情况下,这不是一个特殊的问题,只是一个小麻烦。你所需要做的就是在笔记本内使用pip install

但是,如果您使用的是私有包,所有这些都将失败。也就是说,您正在一个版本化服务(例如 GitHub)上托管的私有存储库上开发的包。这是因为pip不再工作,因为你需要认证,这是更难实现的,因为 GitHub 决定对 Git 操作取消密码认证

本文详细介绍了一种使用我开发的包 colab-dev-tools 安装私有包的可靠而快速的方法。

使用私有包

以前我有两种方法在 Colab 上使用私有代码:

  1. 将所有代码复制粘贴到 Colab: 这仅适用于小项目(例如 1 或 2 个小文件)。不推荐,因为这样会让笔记本又长又乱;这使得版本控制变得非常困难;几乎任何改变都需要对基础代码进行彻底的重构。
  2. 压缩包并在 Colab 上解压缩:虽然这对于单个用户来说非常有效,但是在团队中维护起来就变得非常困难。zip 文件很容易被放错位置、命名错误,而且版本控制几乎是不可能的。这使得在出现问题时很难重现结果和调试代码。

因为这两种方法都不够,所以必须考虑对 GitHub 进行认证。然而,只有两种方法可以做到这一点:ssh 或使用访问令牌。

当您有固定设备(例如您的计算机)时,ssh 方法非常有用,因为您不需要每次都生成密钥。然而,由于 Colab 是基于会话的,使用 ssh 是一件痛苦的事情,因为每次都需要生成密钥。auth-token 方法更好,但这需要复制粘贴,因为很难记住令牌…

然而,这是有问题的,因为:

  1. 每次复制粘贴时都有暴露密钥的风险
  2. 您可能会将它留在笔记本中,从而在笔记本推送时暴露它
  3. 只是很烦…

因此,我建议的解决方案是将访问令牌存储在您的个人驱动器上,然后每次都从那里读取它,但是要确保读取的内容被一些代码提取出来。这样,您就不会显式地阅读它,从而消除了风险 2)。你也不需要复制粘贴任何东西,因此删除 1)。最后,这个过程非常简单,所以你可以确定你不会因为 3)而感到沮丧。如下图所示。

解决办法

# install the package
!pip install colab-dev-tools# imports
import os
from colabtools.utils import mount_drive, install_private_library# get path to Drive root, e.g. drive/MyDrive/
drive_path = mount_drive()# get path to the access token
git_access_token_json_path = os.path.join(drive_path, PATH_TO_JSON)# install using pip install:
# git+https://{access_token}@github.com/{username}/{repo_name}.gitinstall_private_library(git_access_token_json_path, PROJECT_NAME)

结束语

  • 确保您的驱动器只能由您访问;这降低了您的访问令牌泄露的可能性。
  • 注意,包中的函数只是抽象出代码。他们不会以任何方式加密您的访问令牌密钥。
  • 这种方法的一个缺点是访问令牌的路径在笔记本中是可见的。这意味着,如果攻击者能够访问您的驱动器,他们将能够很容易地找到您的访问令牌 json。因此,每次将笔记本推送到 Github 时,删除路径可能是个好主意。
  • 这个包还有其他工具在使用 Colab 时很有用,比如测量 GPU 利用率,向 GPU 发送对象等…

https://github.com/namiyousef/colab-utils

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

如何使用 PyScript 在 Web 浏览器上轻松运行 Python 可视化

原文:https://towardsdatascience.com/how-to-easily-run-python-visualizations-on-a-web-browser-with-pyscript-4b287ef991cd

使用 PyScript 在 web 浏览器上运行 matplotlib 和 bokeh 可视化的分步指南

FirmbeeUnsplash 上拍摄的照片

在 PyCon US 2022 中,Anaconda 的 CEO 宣布了一项名为 PyScript 的新技术,允许用户在浏览器中编写 Python 代码。

我们只需要用 HTML 编写并运行 Python 代码来构建 web 应用程序。这意味着我们不需要担心部署,但一切都将发生在我们的 web 浏览器中。

你可以在你的网络浏览器上构建的最酷最简单的东西之一就是 Python 可视化,在本指南中,我将向你展示如何使用 PyScript 在你的网络浏览器上显示 matplotlib 和 bokeh 可视化。

此后,您甚至可以构建仪表板并共享 HTML 文件,这样其他人就可以在他们的 web 浏览器中看到它。

不想看书?你可以看我的视频!

先做最重要的事情—将 PyScript 添加到 HTML 模板中

要设置 PyScript,我们首先需要一个基本的 HTML 模板。

大多数文本编辑器和 ide 都有一个你可以使用的 HTML 模板。你只需要创建一个 HTML 文件,然后输入dochtml并按回车键。

在 Pycharm 中,我可以在写完doc后得到模板。万一你没有得到它,这里有一个模板你可以使用。

现在要使用 PyScript,将下面几行添加到 HTML 模板的<head>部分。

<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>

这些台词摘自 PyScript 网站。我会把它们粘贴在<title>标签下面。

你应该有这样的东西。

太好了!到目前为止,我们已经成功地设置了 PyScript。现在让我们在网络浏览器上绘制一些可视化图形。

1.使用 PyScript 在您的 Web 浏览器上绘制 Matplotlib

在我们的 web 浏览器上用 matplotlib 和 bokeh 绘制可视化的步骤有点不同。

让我们首先用 matplotlib 绘制一个线图,并在我们的 web 浏览器中显示它。

正在加载 matplotlib

为了绘制线图,首先,我们必须在 HTML 文件中加载 matplotlib。我们在下面的代码片段中使用了<py-env>标签。

同样,在<body>部分,我使用<py-script>标签为我们的图添加了一个标题。在该标记中,我使用 Python 代码打印了单词“My Lineplot”。

要查看结果,我们必须在 web 浏览器中打开这个 HTML 文件。在 Pycharm 上,我可以通过点击右上角的 Chrome 图标轻松做到这一点。

作者图片

您也可以在浏览器上打开 HTML 文件,方法是右键单击该文件,选择“打开方式”,然后选择 Chrome/Safari/Firefox。

选择浏览器后,将会打开一个新的选项卡。你应该看看这个。

作者图片

太好了!到目前为止,我们已经在浏览器中显示了标题。现在让我们做线图。

在网络浏览器上显示折线图

在我们编写 Python 代码来创建一个线图之前,我们必须在<body>部分创建一个<div>,它将包含这个图的id。id 将是“线图”

<div id="lineplot"></div>

然后我们使用<py-script>标签创建线图。这里我们使用了output属性,并将其设置为我们之前定义的 id。

<py-script output="lineplot">
   # Python Code Goes Here ...
</py-script>

下面是绘制线条的 Python 代码(您应该将它放在py-script标记内)

太好了!如果将所有元素放在一起,您应该会在浏览器中看到下面的线图(加载可能需要几秒钟)。

作者图片

如果你有困难把这些碎片拼在一起,你可以在我的 Github 上找到完整的代码。

2.使用 PyScript 在 Web 浏览器上绘制散景

与 Matplotlib 不同,Bokeh 需要在<head>部分添加几行额外的代码。

让我们看一看。

代码是从 PyScrpt Github 中提取的,除了我们之前从 PyScript 网站复制的两行代码之外,还包括了 Javascript 元素(第 8-17 行)之类的东西。

现在让我们在<body>部分添加一个<div><py-script>标签来显示我们的散景图。

如果您将这两个片段放在一起并刷新您的浏览器,您应该会看到下图。

作者图片

就是这样!现在,您已经知道如何使用 Python 和 HTML 在 web 浏览器上运行可视化。

用 Python 学习数据科学? 通过加入我的 10k+人电子邮件列表,获取我的免费 Python for Data Science 备忘单。

如果你喜欢阅读这样的故事,并想支持我成为一名作家,可以考虑报名成为一名媒体成员。每月 5 美元,让您可以无限制地访问数以千计的 Python 指南和数据科学文章。如果你使用我的链接注册,我会赚一小笔佣金,不需要你额外付费。

https://frank-andrade.medium.com/membership

如何用 Python 轻松汇总音视频文件

原文:https://towardsdatascience.com/how-to-easily-summarize-audio-and-video-files-in-python-13f42be00bf2

使用自动章节来总结 Python 中的音频和视频文件

凯利·西克玛在 Unsplash 上的照片

Auto chapters 是一个强大的功能,它允许我们将音频/视频文件分成“章节”,然后为创建的每个章节自动生成摘要。

这种自动章节功能有不同的应用。像 YouTube 这样的视频平台有帮助用户跳转到他们正在寻找的内容的章节,播客播放器有使播客剧集更容易搜索的章节。

在本文中,我将向您展示如何使用 AssemblyAI API 在 Python 中使用这一特性。该 API 将执行语音到文本转换,然后自动生成包含摘要、标题和要点等数据的章节。

如何用 Python 对音视频文件进行摘要

在本指南中,我们将为史蒂夫·乔布斯 2005 年斯坦福毕业典礼演讲视频创建自动章节,你可以在 YouTube 上找到。视频大约 15 分钟,我将只使用一个语音文件作为输入。

您可以随意使用自己的音频文件,但是,为了充分利用该功能,请确保您使用的音频超过 5 分钟。

除此之外,我们需要创建一个免费的 AssemblyAI 帐户来获得一个 API 密匙。一旦你创建了你的帐号,进入首页标签,寻找一个名为“集成 API”的框来复制你的 API 密匙。

步骤 1:上传你的音频文件并获取网址

为了将语音转换成文本,然后对其进行总结,我们首先需要将音频文件上传到 AssemblyAI API。为此我们需要 2 个输入——音频文件的路径(filename)和 API 键。

之后,我们创建一个函数来读取我们的音频文件。我们将这个函数命名为read_file。为了上传我们的音频文件,我们将在 post 请求中调用这个函数。这个 post 请求将被发送到 AssemblyAI 的上载端点。

最后,我们使用请求中的response来获取上传音频文件的 URL。我们将所有这些存储在一个名为audio_url的变量中,我们将在下一步中使用它。

步骤 2:提交成绩单请求

在这一步中,我们向 AssemblyAI 的转录端点发送一个 post 请求。我们使用audio_url提交上传进行转录。

确保在json 参数中添加密钥/值对‘auto_chapters’: True。这将有助于我们不仅得到转录,而且总结。

最后,我们创建一个名为transcript_id的变量,表示我们提交的 id,我们将在第 3 步中使用它。

第三步:保存文字记录和总结

为了获得我们的脚本和摘要,首先,我们使用transcript_endpointtranscript_id来创建一个名为polling_endpoint的变量。我们将定期向该端点发送 get 请求,以检查我们在步骤 2 中发送的请求的状态。

只有当状态设置为completed时,我们才在文本文件中保存抄本,在 JSON 文件中保存摘要。我们使用变量transcript_id作为这两个文件的名称。

就是这样!现在检查您的工作目录,您会发现一个包含脚本的.txt和一个包含摘要的.json文件。

以下是视频其中一部分的摘要、标题和要点:

{
"**summary**": "You have to trust that the dots will somehow connect in your future. You have to trust in something your gut, destiny, life, karma, whatever. Because believing that the dots will connect down the road will give you the confidence to follow your heart, even when it leads you off the well worn path.",
"**headline**": "Because believing that the dots will connect down the road will give you the confidence to follow your heart, even when it leads you off the well worn path.",
"**start**": 312538,
"**end**": 342070,
"**gist**": "the dots will somehow connect"
    },

现在是你自己尝试的时候了。你可以在我的 Github 上找到本文使用的代码。

加入我的电子邮件列表,与 1 万多人一起获取我在所有教程中使用的 Python for Data Science 备忘单(免费 PDF)

如果你喜欢阅读这样的故事,并想支持我成为一名作家,可以考虑报名成为一名媒体成员。每月 5 美元,让您可以无限制地访问数以千计的 Python 指南和数据科学文章。如果你用我的链接注册,我会赚一小笔佣金,不需要你额外付费。

https://frank-andrade.medium.com/membership

如何在新项目中有效地重用您的旧代码

原文:https://towardsdatascience.com/how-to-effectively-reuse-your-old-code-in-a-new-project-7193d5d5605c

编写你自己的 Python 包

来源:https://unsplash.com/photos/H424WdcQN4Y

当您处理数据一段时间后,您会很快意识到代码的大部分可以从一个项目重用到下一个项目。

在接下来的文章中,我将向您展示一种非常简单有效的方法来创建您的个人 python“包”,只要您在本地(同一台计算机并使用个人文件),只需几行代码就可以重用潜在的大量代码。

创建个人包的步骤

  1. 创建一个名为_init.py_的空文件。该文件用于将磁盘上的目录标记为 Python 包目录。换句话说,它让 Python 将包含它的目录视为模块(可以导入)。
  2. 在同一个目录中,创建一个包含您想要重用的代码的文件。你需要做的是定义一个函数来返回一些东西。例如,在下面的代码中,我定义了一个接受不同参数并返回蒙特卡洛模拟结果的函数。

3.然后,在一个单独的文件夹中,放置你当前的项目,在那里你将需要使用你的“包”。这是代码。

在第 2 行,您只需添加将被重用的代码的位置。

第 4 行是您“导入”包的地方。这里,这一行的意思是我从找到它的文件(Monte_Carlo_Simulation)中导入我创建的函数(Monte_Carlo)。

然后,在第 6 行,我简单地使用这个函数,就像它已经在我当前的项目中一样。它返回结果,我可以在项目的其余部分使用这些结果。

4.如果出现错误,请确保您的文件放置正确。它们应该具有以下结构。

如您所见,在 My_Package 文件夹中,您应该会找到一个名为 pycache 的新文件夹。它是在您使用线from x import y时创建的。这个文件夹包含了字节码,这使得第二次运行你的程序时速度会快一点。

如果你有正确的结构,但你的“包”仍然不能工作,这可能是因为你的主文件中有一个错误(在我的例子中是 Monte_Carlo_Simulation.py)。

就是这样!这个非常简单的技巧将允许你重用你的代码,而不必不断地复制粘贴它。它还允许您“集中”事情,并且如果您想要进行更改,只需更新您的代码一次(而不是必须在您使用它的每个文件中进行更新)。它也使东西更容易阅读。

希望这有所帮助。非常感谢你的阅读!

成为大媒平台会员:https://francoisstamant.medium.com/membership

PS:在接下来的一篇文章中,我将向你展示如何创建一个对任何地方的其他人都可用的包,而不仅仅是你自己。敬请期待!

如何在数据科学简历中有效展示个人项目

原文:https://towardsdatascience.com/how-to-effectively-showcase-personal-projects-on-your-data-science-resume-736cbfa1600

简洁的项目描述是吸引招聘人员眼球的必备要素

罗南古田Unsplash 上的照片

作为一名崭露头角的数据科学家,你最常被告知的一件事是,在简历中列出你的个人项目是展示你的技能和经验的好方法。

然而,当要写一份真正展示一个项目的描述时,我不是唯一一个完全被难住的人,更不用说趋势表明大多数简历应该只有一页长

这意味着必须创建一个公式来保持项目描述简短、切中要点,最重要的是有效。招聘人员投简历的时间只有 7.4 秒,你的项目描述必须吸引他们的眼球,让他们给你打电话面试。

数据科学简历中项目描述的组成部分

目标/目的

招聘人员需要对你的项目目标有一个清晰的认识。

你想通过你的项目完成什么?你的项目试图解决什么问题?你在寻找什么样的答案?在项目中必须做些什么?你为什么尝试这个项目?

现在是时候简要概述您的项目了,包括项目目标、时间表和范围的描述。请记住,你的简历不应该超过一页,这一部分应该简洁,重点是用 1-2 个短句清楚地描述上面列出的项目。

示例:进行了一项分析,以确定 7 月 1 日至 15 日北京的空气污染水平,以及它们如何与同一时间段的住院率相关联。

作用

你在简历上列出的项目不一定是私人项目——事实上,你可以列出你参与的任何项目。

例如,你可以列出你在大学时、以前的工作、竞赛或黑客马拉松中的项目。

主要目的是让招聘人员了解你做了什么,花了多长时间。对于你作为团队成员工作的项目描述,你需要更进一步指出你在项目中的角色和职责。此外,对于一个团队项目描述,现在可以列出您在团队中履行职责所使用的技术或工具。

这一部分不应该超过一句话。

个人项目示例:独立工作 3 周,提取、清理、分析和可视化北京空气污染-住院率数据。

团队项目示例:在一个 4 人团队中担任数据分析师,每周工作 10 小时,使用 Tableau 制作北京空气污染-住院率数据的可视化。

数据

现在是时候给招聘人员一个关于大约数据集大小和偏斜的概念了。这可能包括详细说明所使用的确切数据集,并提供一个链接(如果可以在网上免费获得的话),或者描述数据是如何以及从哪里获得的。

描述的这一部分还可能涉及对用于获取、提取和清理数据的工具和技术的讨论。

这一部分应该有 1-2 个句子长。

示例: OpenRefine 用于清理从开放数据集 A(7 月 1 日至 7 月 15 日之间的北京空气污染水平数据— 350 个值)和开放数据集 B(7 月 1 日至 7 月 15 日之间的北京住院率— 50,000 个值)获得的数据。

使用的模型和工具

可以说,项目描述中最重要的部分是您对整个项目中使用的模型和工具的讨论。

在这里,你可以通过重点列出所使用的模型和技术来表明它与你所申请的工作的相关性。通过列出出现在招聘广告中的技术,你向招聘人员表明你已经成功地利用它们完成了分析。

此部分长度不应超过 1 句话。

示例:这个项目是使用 SQL、Python、Tableau 和逐步回归模型完成的。

密码

现在是时候提供您为项目编写的代码的链接了。

古训总是告诉我们“展示,不要说”。如果招聘人员对你告诉他们的关于你的项目的内容感兴趣,他们会希望你向他们展示你的项目的细节。

因此,现在是时候提供一个到 Github 或其他代码共享库的链接了。

这部分应该只有一句话。

例如:这个项目的代码可以在这里找到:链接

结果

数据科学家的相关性始终取决于他们对公司的影响。

这意味着你需要告诉招聘人员你的项目是如何产生重要结果的。你的分析结果将会证明你可以被给予一个问题去解决,并且带着一个解决方案回来。

专注于你的分析所确定的,你的结果的相关性,如果你愿意,讨论你的结果在未来如何扩展。

这部分应该是 1-2 个句子。

举例:分析结果发现,在空气极度污染期间,北京的住院人数激增,这表明北京的医院应该为这个时候患者的涌入做好准备。这项研究还可以通过考虑极端温度来改进,极端温度也可能加剧城市内的污染和健康问题。

如何将所有这些放在一起产生一个项目描述

下面是我们最终的项目描述,一旦你把所有的单个部分组合在一起:

进行了一项分析,以确定 7 月 1 日至 15 日北京的空气污染水平,以及它们与同期住院率的关系。独立工作 3 周,提取、清理、分析和可视化北京空气污染-住院率数据。OpenRefine 用于清理从开放数据集 A(7 月 1 日至 7 月 15 日之间的北京空气污染水平数据— 350 个值)和开放数据集 B(7 月 1 日至 7 月 15 日之间的北京住院率— 50,000 个值)获得的数据。这个项目是使用 SQL、Python、Tableau 和逐步回归模型完成的。分析结果发现,在极度空气污染期间,北京的住院人数激增,这表明该市的医院应该为此时患者的涌入做好准备。这项研究还可以通过考虑极端温度来改进,极端温度也可能加剧城市内的污染和健康问题。这个项目的代码可以在这里找到:链接

一旦你建立了这个基本的描述,你就可以对它进行提炼,使之更好地与你申请的工作相关,如果有必要的话,可以删减一些内容,使之更简短。

如果你的简历空间不够,另一个选择是在描述中只包括目标、工具和结果,以及代码库的链接。然后,可以使用存储库中的自述文件来包含更多详细信息。这可以节省你简历上的空间,也让你有机会提供额外的细节而不受空间的限制。

关键要点

  • 简历中需要的项目描述的组成部分包括数据分析的目的/目标、您在项目中的角色、您使用的数据的描述、您使用的模型和工具的列表、代码库的链接以及对分析结果的简短讨论。
  • 在你的分析中只包括相关的细节,以确保招聘人员在尽可能短的时间内获得最多的信息。
  • 如果你的简历空间不够,只讨论项目目标、工具和结果——其余的可以在你的代码库的自述文件中讨论。

订阅将我的故事直接发送到您的收件箱:故事订阅

请成为会员,使用我的推荐链接获得无限制的媒体访问权限(我将免费向您收取少量佣金):媒体会员

如何在树叶地图弹出窗口中嵌入交互式绘图可视化

原文:https://towardsdatascience.com/how-to-embed-interactive-plotly-visualizations-in-folium-map-pop-ups-c69c818a8cd9

一个详细的实践教程来提升你的 Python、Plotly 和 Folium 技能

Pixabay 制作的原始图片(由作者修改)

介绍

我最近写了一篇关于如何使用 HTML 将动态文本、图像、网络链接或表格插入到叶子弹出窗口中的文章。在我看来,允许用户将 HTML 网页和可视化作为标记在地图上传递,是 leav 最大的优势之一,并为使地图更具交互性和信息量开辟了无限的可能性。

在前面提到的文章的最后,我们谈到了将交互式 Plotly 图表作为 HTML 传递给 leav map markers 的可能性。在这篇文章中,我将向您展示如何使用 for-loop 和 HTML iframe 在 follow 地图弹出窗口中嵌入交互式 Plotly 图表。这是一个非常实用的编码和数据可视化项目,可以提升您的 Python、Plotly 和 Folium 技能。

具体来说,我们将创建一个 leav 地图,在地图中显示 10 个主要的美国城市作为标记。单击每个标记时,会出现一个弹出窗口,并显示一个交互式 Plotly 图表。该图表显示了该市过去 4 年的住房市场趋势,用户可以使用范围滑块选择不同的时间段。我们将要创建的令人惊叹的树叶地图如下所示:

作者图片

下载数据

转到 redfin 的数据中心,向下滚动到“它如何工作”部分,并下载“城市”级别的区域数据。下载的文件是一个. gz 文件,包含美国大多数城市在过去 10 年左右的住房市场指标。这是一个免费的、开放的数据集,你可以下载并引用 Redfin 用于你自己的目的。

来源: Redfin 房产市场数据

导入库和读取数据

首先,让我们导入所有必要的库并将数据读入 Pandas 数据框。这是一个巨大的数据集,所以读取到 Python 中可能需要比正常情况多一点的时间。

此外,出于演示的目的,我们将我们的数据限制在过去 4 年,10 个美国城市,并且只限于单户房产。我们不需要原始数据集中的所有列,所以我们只保留一些我们在这个项目中需要的列。

作者图片

数据争论

在上面的数据中有一些事情需要注意。字段“period_begin”是一个字符串,以后使用它绘制时间序列图时可能会导致一些问题。因此,让我们将其更改为“日期”类型,并将其重命名为“快照 _ 月份”。

“median_sale_price”和“homes_sold”字段都有一个不必要的小数位,所以让我们将它们都改为整数类型。我们还将创建一个名为“median_sale_price_formatted”的新字段,显示带有千位分隔符的数字。

最后,让我们创建一个名为“文本”的新字段。我们为什么需要它?默认情况下,当用户将鼠标移动到每个数据点上时,Plotly 会显示一个工具提示,显示一些基本信息。然而,默认选项非常有限,视觉上也不太吸引人,所以我们想创建一个定制的工具提示,以控制悬停工具提示中显示的信息内容和方式。

作者图片

创建双 Y 轴绘图图表

我们的数据准备好了,让我们开始绘图。请记住,我们的最终目标是为每个城市创建一个交互式 Plotly 图表,然后将每个图表传递给它在 follow 地图中对应的标记。我们将需要使用 for-loop 和 HTML iframe 来实现这一点。

在我们开始之前,让我们先预热一下,只为一个城市创建一个双 y 轴图表。我们可以选择亚特兰大,在条形图中绘制“homes_sold”指标,在折线图中绘制“median_sale_price”指标,并将这两个图组合成一个具有双 y 轴的组合图。我们还将向组合图添加一个定制的悬停工具提示以及一个范围滑块/选择器。

使用 Plotly Graph_Objects,我们首先使用 make_subplots()创建一个图形,以便该图形可以有两个不同比例的 y 轴。然后,我们向图中添加两条迹线,一条表示条形图,另一条表示线图。最后,我们使用 update_layout()方法更新图表,定制图表标题、图例、x 和 y 轴等。

如果你是 Plotly 的新手,你可以阅读下面这篇文章来学习 Plotly 和 Plotly Graph_Objects 的基础知识。通过这样做,你将有更容易的时间跟踪和理解接下来的代码!

为了便于演示,我将展示整个代码,然后我将对代码的各个部分进行注释,这样您就可以很好地理解它是如何工作的。

第 1–2 行:我们将数据限制在一个城市(亚特兰大,佐治亚州),并使用 make_subplots()方法创建一个具有辅助 y 轴的图形。

第 4–23 行:由于我们绘制的是组合图(折线图和条形图的组合),我们需要在图中添加两条迹线(迹线表示一种可视化形式,如散点图、条形图、饼图等)。).我们首先使用主 y 轴将条形图添加到图中。然后我们添加使用辅助 y 轴的线图。

请注意,折线图是使用 go 绘制的。散射()这是因为 Plotly 折线图是作为连接散点图实现的。这也意味着数据点按照它们在数据集中出现的顺序用线连接起来(因此我们需要在数据争论步骤中按‘snapshot _ month’对数据集进行排序)。在第 19–20 行,我们还将定制的工具提示传递给折线图。

第 25–43 行:我们通过添加图表标题并指定其位置、字体大小、字体颜色等来更新图表。在第 41 行,我们还可以调整图例的位置。默认情况下,图例总是放置在图表区外的右上角,并且垂直放置。

第 45–55 行:我们还可以向图中添加一个范围选择器/滑块,以便用户可以放大到特定的时间段范围,这使得可视化更具信息性和交互性!这可以通过使用 fig.update_xaxes()用几行代码轻松实现。

作者图片

使用 for-loop 为每个城市创建一个 Plotly 图表,并将其导出到 HTML

现在回到我们的最终目标,我们需要使用一个 for 循环来自动执行上面的过程,为每个城市创建一个 Plotly 图表,并将它们导出到 HTML 文件——每个城市一个 HTML 文件!为了帮助您理解这是如何工作的,我将使用相同的策略:我将首先展示整个代码,然后逐部分解释它。

第 1–3 行:我们首先创建一个空的图形容器,在 for-loop 步骤中,我们将一个 Plotly 图形一个接一个地插入其中。我们还将创建两个空的 Python 列表,我们将向其中依次追加城市名和 HTML 文件名。

第 4–8 行:在第 4 行,我们首先获得所有城市名称的唯一列表。然后,我们使用 for 循环遍历数据框,并将每个城市名称及其对应的 HTML 文件名追加到我们之前创建的 Python 列表中(第 6–7 行)。我们还将分别为每个城市创建一个单独的数据框(第 8 行)。

第 10 行:我们为 for 循环中的每个城市创建一个 Plotly 图表/图形。代码与上一节所示的相同,所以我们在这里不再花时间解释。您需要从前面的代码块中复制并粘贴第 2–55 行(第 26 行有一点小的变化),并确保代码放在 for 循环中并正确缩进。

第 12–13 行:对于每个城市,我们创建一个 Plotly 图表,并将其导出到 HTML 文件中。所有十个 HTML 文件将自动保存在与 python 代码文件相同的文件夹中。

作者图片

第 15–17 行:我们创建了一个简单的包含两列的 panda 数据框。第一列包含所有城市名,第二列包含所有相应的 HTML 文件名。

第 18–20 行:我们为每个城市添加纬度和经度信息,并创建最终数据框,将其命名为“df_final”。

作者图片

将 HTML 文件传递给树叶地图标记

我们快到了!现在我们有了所有的 HTML 文件,每个文件都包含一个交互式 Plotly 图表,我们可以使用 iframe 将这些 HTML 文件传递给 follow markers。同样,我们将使用 for-loop 来完成这项工作,但也要借助 HTML iframe!

第 1–2 行:我们使用 follow 启动一个空的美国地图,缩放开始级别为 4。我们还通过取这 10 个城市的纬度和经度的平均值来指定大致位于美国中心的位置。

第 4–7 行:我们使用 for-loop 遍历 df_final 数据帧。对于 df_final 中的每个城市,我们取其对应的 HTML 文件(即 fig0.html、fig1.html 等。)并使用标签将其嵌入 iframe 中。

第 9-10 行:我们使用叶子。Popup()方法和 leav。Marker()将每个 iframe 插入到叶子弹出窗口中,最后使用 add_to()方法将所有标记添加到地图中。

第 13 行:我们可以将叶子地图保存到一个 HTML 文件(index.html)中,该文件将与 python 代码文件放在同一个文件夹中。

现在打开 index.html 文件,检查你的地图!单击地图中的每个标记时,会出现一个弹出窗口,显示一个漂亮的交互式绘图可视化效果!只需点击几下鼠标,您就能了解每个城市的房地产市场和趋势!

作者图片

结束语

Folium 是一个非常棒的地理空间图形库,它使我们能够在地图上传递丰富的 HTML 可视化标记。当我们用 Plotly 漂亮的交互式数据可视化来丰富 Folium 的地理空间制图功能时,结果确实令人印象深刻!我希望你喜欢这篇文章,并学到一些新的东西,这将对你的下一个地理空间数据科学项目有用!

数据来源:

Redfin 数据中心 : Redfin 月度房市数据——城市级。这是由全国房地产经纪公司Redfin提供的一个开放数据集,你可以免费下载,并注明出处。

你可以通过这个推荐链接注册 Medium 会员(每月 5 美元)来获得我的作品和 Medium 的其他内容。通过这个链接注册,我将收到你的一部分会员费,不需要你额外付费。谢谢大家!

深度学习如何对病历进行编码

原文:https://towardsdatascience.com/how-to-encode-medical-records-for-deep-learning-fcd690630e8b

基于 Google Brain 的可扩展、精准的深度学习与电子健康记录及其补充材料的简化图解。**

图片来源:pixabay.com

背景

十多年前,医疗保健行业开始系统地数字化医疗保健数据。希望有一天,我们能够协调来自不同来源的数据,形成患者的“纵向视图”,其中包括关于患者健康的一切,从门诊、住院和用药史到免疫记录、家族史和生活方式观察。人们普遍认为,一旦掌握了患者医疗保健数据的丰富性和完整性,我们就可以大大提高医疗质量、降低运营成本并推进医疗/药物研究。

如果你关注医疗保健技术领域的最新趋势,你会发现这一希望正在变成现实。在一些受控环境中,医疗保健提供商、支付者和研究人员开始从特殊的上游系统中收集越来越多的数据,以构建全面的患者记录。随着这一令人兴奋的发展,现在出现了一个价值百万美元的问题:我们如何真正去利用这些数据记录的力量?

虽然数据分析或机器学习模型开发通常会吸引更多的注意力,但不应忽视数据工程的重要性。这篇博文有一个非常具体的重点。它研究了如何对病历进行编码,并使其适合深度学习,特别是时间序列学习。用简化的例子和可视化的图形说明了 Google Brain 的“ 利用电子健康记录进行可扩展的、精确的深度学习 ”及其补充材料中提出的方法。如果你不想阅读原本 30+页的深奥内容,这篇博文对你来说是个不错的替代。事不宜迟,我们开始吧。

学习任务的设置

学习任务的设置是为重症监护室(ICU)病人做预测。谷歌大脑和许多其他研究人员选择 ICU 设置,因为与其他医疗保健数据相比,ICU 的数据通常是最完整的,可供研究使用。我们可以预测很多事情。我们可以预测临床结果——在这种情况下,死亡事件。我们可以预测资源利用率,在这种情况下,停留时间超过 7 天。我们可以预测护理质量,在这种情况下,出院后 30 天再入院。

传统方法/模型依赖于在预测时评估的精选特征变量。这篇博文最后总结了一些流行的 ICU 分析模型。然而,谷歌大脑团队假设,通过考虑所有可用的患者数据,并执行时间序列分析,可以实现对所有上述结果的更准确预测,这在数据验证中证明是成功的。这里的意义在于

  • 它不需要手动选择特征-模型将学习权衡和组合特征
  • 并且使用患者的所有历史数据,这与仅使用当前快照的其他流行的非深度学习模型相反。

现在,学习任务的设置已经清楚了,让我们深入编码过程,看看病历是如何为学习任务转换的。

编码程序

谷歌大脑团队首先将他们从合作医院获得的 ICU 数据转换为一种开放的医疗保健数据标准,称为 FHIR。要完全解释 FHIR,还需要另外 10 篇博文。但它的核心思想并不难理解。出于这篇博文的目的,我们可以把它想象成 JSON 数据。每个医疗保健概念都有一个 JSON 数据模式— PatientObservationConditionMedicationRequest等等,它们都是医疗保健概念。JSON 数据模式将各个医疗保健概念的字段形式化。比如Patient有一个name,一个birthdayObservationvalue等。从专有医疗保健数据到我们需要的 JSON 数据的转换相对简单,因为大多数专有医疗保健系统也基于公共医疗保健概念对其数据进行建模。

这里要注意的一件重要事情是,虽然结构转换是可以实现的,但医疗保健中的语义翻译极具挑战性。因为医疗保健数据采用各种(有时是专有的)编码系统。"Heart failure"在一个编码系统中可能是"123",在另一个编码系统中可能是"1a2b3c"。不同的编码系统有不同的粒度和层次。将所有东西整合到一个单一的编码系统中是一项艰巨的任务。谷歌大脑团队的方法不需要** 编码系统协调,这是一个至高无上的优势。正如我们将在后面看到的,他们可以做到这一点,因为他们将数据内容视为令牌,并将令牌转换为嵌入。因此,只要医疗数据集使用一套一致的编码系统(具体是什么并不重要),就应该没问题。下面我们来看看具体步骤。**

步骤 1:标记化

第一步是标记所有医疗保健概念中的所有字段。如果它是一个文本字段,我们就用空格来分隔它。比如"high glucose"变成了["high", "glucose"]。对于数值型字段,仅仅把普通的数字当作一个令牌是没有意义的。所以我们需要编码更多的上下文。我们将名称(通常是编码值、数量和单位)连接在一起,形成一个令牌。比如{code:"33747003",quantity:10.2,unit:"mmol/L"}变成了"33747003_10.2_mmol/L"。参见图 1 中的图解。可选地,我们可以量化数量以减少令牌的稀疏性。在步骤 1 之后,我们得到的是医疗保健概念的实例,其中每个实例的所有字段都进行了标记。我们将每个实例的时间戳计算为相对于预定义预测时间(图 1 中的dt1dt2)的以秒为单位的增量时间。预测时间通常是入院后 24 小时或出院时。

图 1:标记化+嵌入。图片作者。

第二步:嵌入

对于每个医疗保健概念中的每个领域,我们都建立了一个预定义大小的词汇表。我们不使用全球词汇,因为不同的领域有不同的医疗保健语义。将来自所有概念的所有标记甚至来自一个概念中所有领域的所有标记混合起来构建词汇表是没有意义的。然后,我们为每个令牌训练一个嵌入。嵌入是与预测任务一起学习的。请注意,我们特意为给定医疗保健概念中的所有字段选择相同的嵌入维度。正如我们将在后面看到的,它使聚合变得更加容易。

在步骤 2 之后,我们得到的类似于图 2。它开始类似于典型的自然语言处理输入,其中你有一系列嵌入,你可以馈送到递归神经网络(RNN)。然而,目前的格式有三个问题:

  1. 每个实例都是一个训练示例。ICU 设置中有数百甚至数千个数据点。我们知道 RNN 不擅长长序列。
  2. 训练示例具有可变的维度,这由所讨论的概念和实例中的标记数量来确定。RNN 不能处理可变长度的嵌入。
  3. 实例/训练示例的时间戳不是均匀分布的。特定事件何时发生具有重要的临床意义。嵌入没有捕捉到。

步骤 3 将解决所有 3 个问题。

图 2:一系列嵌入。图片作者。

第三步:聚合

长序列的第一个问题很容易解决。我们只需要将数据点分成均匀的时间步长。时间步长可以是 1 小时或几小时,可以作为超参数进行调整。我们将在给定的时间步长内聚合所有数据点,以形成单个训练示例。

请记住,给定医疗保健概念中的所有字段共享相同的嵌入维度。因此,我们可以取一个实例中所有字段嵌入的平均值,以形成该实例的聚合嵌入。如果一个概念有多个实例,我们可以进一步平均实例嵌入来形成这个概念的嵌入。由于医疗保健概念是一个预定义的枚举列表,我们可以将概念嵌入连接在一起,形成一个固定大小的示例。如果一个概念没有出现在时间步长中,我们只需将其嵌入设置为全 0。变维的第二个问题现在没有了。注意,我们使用 average throughout 进行聚合,但是您可以想象使用其他聚合方案。

为了解决时间戳含义的最后一个问题,我们取时间戳中所有实例的时间戳的平均值,并将其附加到我们通过字段->实例和实例->概念聚合获得的固定大小嵌入的末尾。这样,时间戳信号也在训练示例中进行了编码。

最终编码结果的图示见图 3。我们现在有了一个不太长的固定大小的嵌入序列,它考虑了事件时间戳。我们现在可以把它喂给 RNN 了。

图 3:RNN 的最终输入。图片作者。

结论

在这篇博客文章中,我们一步一步地演示了如何为 RNN 模型编码医疗记录。它首先将从合作伙伴组织接收的专有数据格式转换成开放的标准 JSON 格式。这使我们能够从结构上理解源数据集。然后,它将每个 JSON 字段中的内容标记化,并为每个标记构建一个嵌入。最后,它在合理的时间范围内聚合令牌嵌入,以创建适合 RNN 模型输入的合理长的固定大小嵌入序列。

上述数据处理的意义是双重的:

  1. 它不需要将病历整合到一个全球编码系统中,从而节省了大量的人工工作。
  2. 它以一种同质的方式对整个患者历史中的所有记录进行编码,以便在模型训练期间可以考虑所有这些记录。

附录:其他常见的非深度学习 ICU 数据分析模型

早期预警评分(EWS)通常在入院后 24 小时计算,以预测死亡的可能性。它使用呼吸频率、氧饱和度、温度、血压、心率和意识等级作为变量。每个变量都有一个由普通医学知识确定的正常范围。基于查找表计算得分,以表征变量离其正常范围有多远。如果所有分数的总和超过一个阈值,这意味着死亡的可能性很高。

再入院的医院评分通常在出院时计算。它考虑了血红蛋白水平、钠水平、入院类型、先前入院次数、住院时间、住院时间是否与癌症相关,以及住院期间是否进行了医疗程序。与上述 EWS 类似,基于已有的医学知识,每个因素的值被转化为风险分值,风险分值的总和描述了再入院的总体风险。

住院时间长的刘评分一般在入院后 24 小时计算。逻辑回归模型(使用适当的正则化技术)将年龄、性别、病情类别、诊断代码、接受的医院服务和生命体征的实验室测试等变量考虑在内,以产生长期住院的概率数字。

如何集成聚类算法

原文:https://towardsdatascience.com/how-to-ensemble-clustering-algorithms-bf78d7602265

意思是你从未见过的

照片由杜凡Unsplash 上拍摄

介绍

在人工智能背景下,集成是一种试图通过聚合多个机器学习模型的预测来提高性能的技术。它可以被认为是一种元学习,其中外部代理通过判断其他代理的单独预测来计算最终预测。

有几种方法可以集成监督算法,如 bagging 和 boosting。特别是,boosting 技术(尤其是 XGBoost)成为任何机器学习应用程序中不可或缺的工具。

另一方面,在无监督的问题中,我们没有听到很多关于集成技术。那么,有可能在聚类算法中使用这种技术吗?这不仅是可能的,而且这些年来已经发展了许多策略[1]。这篇文章探讨了其中的两个。

相似矩阵

与监督方法不同,在监督方法中,集成可以通过将学习者堆叠在其他学习者之上来直接完成,聚类不是那么简单。

在聚类中,数据的最终标签本身没有意义,一个点是在聚类 1 中还是在聚类 2 中并不重要,重要的是谁也在这个聚类中。因此,连接两个不同聚类结果的信息并不像在分类中比较最终标签是否相同那样简单。需要某种方法来计算不同分区上存在多少一致性。

相似性矩阵是将这些信息转换成数据结构的简单方法。它的构造如下:

考虑到我们的数据集上有 n 个点,相似性矩阵将是一个 n x n 矩阵,其中位置( i,j) 包含点 I 和 j 在同一个聚类中落了多少次。下图显示了该矩阵的一个示例。

相似性矩阵示例。图片由作者提供。

表示这些信息的更好方法是使用百分比而不是固体计数。在这种归一化形式中,每个位置( i,j )表示 I 和 j 一起落在同一聚类中的概率。这种标准化是通过将每一行除以其对角线值(总计数)来获得的。

标准化相似性矩阵示例。图片由作者提供。

这种方法更适合机器学习,因为所有值都落在范围[0,1]内。标准化的相似性矩阵将是我们接下来部分的基本构建模块。

具有图连通分量的系综

“图形连接组件”看起来像一个七眼怪物,但却是一个非常简单的技术。这种方法认为出现在一起超过 X%的时间(例如 10%或 50%)的两个点(在同一聚类中)应该在同一最终聚类中。

如果我们将相似性矩阵视为一个图,其中每个点都是一个节点,并且来自(I,j)的边的权重等于矩阵中(I,j)的值,那么这种方法实质上是移除值低于阈值(X%)的边,断开节点。保持连接的节点组是我们的最终集群。这就是这种方法被称为“连接组件”的原因。

从图表中删除边。图片作者。

因为它基于简单的阈值创建新的聚类,所以可以认为它等同于用于监督模型的简单 bagging 集成方法。

让我们看一个 Python 中的例子。

第一步是创建聚类数据集。

聚类数据集。图片由作者提供。

下面的代码使用 K-Means 应用了这种集成聚类技术。

完整代码可在 github 上获得,为了提高可读性,省略了实现细节。

我们来解释一下代码。

NUM_KMEANS=32 是集合中使用的 k 均值模型的总数。

该代码使用 MiniBatchKMeans 来减少训练时间。设置 n_init=1 是必不可少的,因为在默认情况下,sklearn 的 K-means 模型会执行多次,并且只保留最好的结果。因为我们希望存储所有结果,所以值 n_init=1 确保了这一点。减少 max_iter 和 batch_size 也可以提高代码速度。

ClusterSimilarityMatrix 只是一个创建相似性矩阵的简单模块。它接收聚类分区并迭代更新计数。相似矩阵建立后,进行归一化处理。

下面一行代码是模型的核心。

graph = (norm_sim_matrix>MIN_PROBABILITY).astype(int)

在这里,低于 MIN_PROBABILITY=0.6 的概率变成 0(从图中移除边),而高于 MIN _ PROBABILITY = 0.6 的概率变成 1(保持图中的边)。

MIN_PROBABILITY 的值作为一个超参数,应该被细化以达到预期的结果。如果它的值设置得太高(0.9–1.0),数据可能会分布在许多小簇中,如果它设置得太低(0.2–0.4),它可能会找到大簇。

在那之后,只是找到图的连通部分的问题。幸运的是,scipy 包已经给了我们代码。

所以,让我们看看结果。

k 均值图结果。图片作者。

正如我们所看到的,集成技术的结果与数据应该如何划分的预期更加一致。

这个技术挺有意思的。众所周知,K-means 只能找到球状星团,使用预定义的 k 值将空间划分为 Voronoi 单元。但是,通过在这种简单的集合技术中应用 k-means 的大军,他们能够找到更复杂形状的星团,如 HDBSCAN。

世卫组织会赢吗?图片由作者提供。

与其他聚类模型集成

许多聚类算法利用数据的中间表示,例如邻居图或距离矩阵,以便找到最终的聚类。例如,著名的 HDBSCAN 使用最小生成树来表示数据。

因此,许多聚类算法接受相似性/距离矩阵作为输入,而不是常规的点列表。因此,前面介绍的相似性矩阵可以输入其中。

这种方法背后的思想是使用一组“较弱的”聚类算法为后面的算法创建一个“较强的”基础。这种方法类似于监督机器学习中的推进技术。

K-均值和谱的集成。图片作者。

让我们看下面的例子,在这个例子中,我们使用常规的 K-Means 来“提高”谱聚类算法的性能。

重要的是要记住“改进”和“更好”的概念在集群中可能是棘手的,因为没有集群是/应该是什么样子的明确绝对定义[2]。

像以前一样,创建了一组 NUM _ 均值 K 均值模型。aggregator_clt 是负责聚类相似性矩阵的算法,创建最终的聚类标签。

128 个 K 均值模型被用作“较弱”的学习器,谱聚类被用作聚合器。设置 affinity="precomputed "很重要,这样模型才能理解相似性矩阵是为传递的。合体()【法。

:
谱聚类算法接受相似性矩阵,但并非所有超参数(sklearn)中具有 affinity="precomputed "或 metric="precomputed "的聚类模型都是如此。有的需要一个距离矩阵,正好相反。将归一化相似度矩阵转换为距离矩阵的简单方法是应用对数变换,距离= -log(相似度),只需使用一些技术来避免 0≥相似度或相似度> 1

EnsembleClustering 是一个简单的类,用于封装相似性矩阵的创建和模型的训练。

所以,让我们看看结果。

集合 K-均值+光谱与光谱独奏。图片由作者提供。

谱聚类不是像 k-means 那样简单的模型,(奇怪的是,它可以使用 K-Means 作为实现的一个步骤),但是它不能找到我们想要的聚类。集成方法在视觉上比单独的谱聚类执行得更好。

重要的是要记住,这篇文章使用迷你批处理 k-means 只是为了提高执行速度。任何聚类算法都可以用来构建相似性矩阵(只是要小心离群值)。因此,作为家庭作业,我建议尝试使用一组异构聚类算法运行代码,如下图所示。

使用不同来源构建相似性矩阵。图片由作者提供。

结论

集成技术在许多监督机器学习任务中达到了最先进的水平。另一方面,在集群中,它们不太出名,实现起来也不那么简单。希望这篇文章能让我们了解如何在聚类上进行集成。

我们能够使用 K-means 模型(最简单的聚类模型之一)来执行非球状聚类,而不需要传递 K 值。它还能够“改进”另一种聚类算法的结果。

当然,像生活中的一切一样,没有什么灵丹妙药,这篇文章也不是由“集群合奏公司”赞助的。

这篇文章的主要目的是介绍集成聚类的技术。尽管它们非常简单,但我希望这篇文章中涉及的技术能够帮助您理解这个过程是如何工作的。

这篇短文只是触及了聚类集成主题的表面,请在下面的参考资料中搜索更多信息。包含代码的 Github 存储库也在参考资料部分。

感谢您的阅读!😃

参考

GitHub 上的代码:
https://GitHub . com/jaumpedro 214/posts/tree/main/ensamble _ clustering

[1]t .布恩戈恩和 n .伊姆翁(2018 年)。集群集成:最近扩展和应用的方法综述。 计算机科学评论28 ,1–25。
[2]亨宁,C. (2015)。什么是真正的集群?模式识别字母64 ,53–62。
【3】Scikit-Learn,聚类算法官方文档
【4】维基百科文章,组件(图论)

如何确保你能解释为什么你的模型做出预测

原文:https://towardsdatascience.com/how-to-ensure-you-can-explain-why-your-model-makes-predictions-d2c769270e

从模型中提取信息来解释为什么会做出预测的技术

Unsplash 上拍摄的 77 人需求系统

可解释性是你可以在机器学习和数据科学中学习和应用的最重要的主题之一。建立一个表现良好的模型是一回事,帮助你和其他人理解为什么一个模型会产生它所产生的结果是另一回事。

我们举个例子。假设您正在构建一个机器学习模型,该模型将预测客户购买产品的可能性。我们可能有关于他们的不同的人口统计信息,我们可能有关于他们消费的其他产品的信息,我们可能有关于他们的营销信息。仅仅预测客户购买产品的可能性是不够的,我们需要了解他们为什么购买。

通过了解该模型的关键驱动因素,我们或许能够通过关注这些关键驱动因素来提高销售转化率。例如,我们知道人们在一个月或一天中的特定时间更有可能改变信仰;我们可以将我们的销售努力集中在那些更有成效的时间窗口。

现在回想一下你的基础统计学课程和学习简单的线性回归。我们大概都记得一条线的方程:Y = MX + B。我们利用这个等式和系数来预测Y的新值。许多机器学习模型也是如此。如果我们能解释一个模型的每个特征如何影响结果,我们就能帮助其他人理解它是如何工作的。关于简单线性回归的更多内容,请查看我的文章:了解 Excel 强大的线性回归工具。我们将从三个主要方面来解释你的模型。让我们跳进来吧!

  1. 线性和逻辑回归系数
  2. 特征重要性
  3. SHAP 价值观

数据和导入

对于我们今天的演示,我们将使用银行营销 UCI 数据集,您可以在 Kaggle 上找到该数据集。该数据集包含有关营销活动中银行客户的信息,以及可以在分类模型中使用的目标变量。该数据集位于 CC0:公共领域下的公共领域,可用于任何目的。

有关构建分类模型的更多信息,请查看:构建令人惊叹的二进制分类器所需要知道的一切通过多类和多标签模型超越了二进制分类。此外,查看一篇密切相关的文章 4 在机器学习模型中增强特征选择的方法

我们将从导入必要的库和加载数据开始。我们将利用 Scikit-Learn 来学习每一种不同的技术。

import pandas as pd

from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import MinMaxScaler
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OrdinalEncoder
from sklearn.compose import make_column_selector as selector
from sklearn.pipeline import Pipeline

import xgboost
import shap

import matplotlib.pyplot as plt
import seaborn as sns

df = pd.read_csv("bank.csv", delimiter=";")

# This column has too much effect on the model, so we'll drop it
df = df.drop(["duration"], axis=1)

数据准备

我们需要对这个数据集做的第一件事是将我们的目标变量从其余数据中分离出来。因为它位于最后一列,所以我们可以使用iloc函数来分隔它。

# Separate the target variable from the rest of the data
X = df.iloc[:, :-1]
y = df.iloc[:,-1]

像往常一样,我们希望为机器学习准备数据。这意味着对分类值进行编码、对文本进行矢量化(如果合适的话)以及对数值进行缩放。我总是使用管道来确保数据的一致转换。查看我的文章,停止一步一步地构建你的模型。利用管道实现流程自动化!,了解更多关于管道的信息。

我们将利用一个ColumnTransformer并将MinMaxScaler应用于数字数据,将OrdinalEncoder应用于分类数据。有许多编码数据的策略,例如OneHotencoder。然而,出于解释的目的,我们将通过简单地使用序号编码器得到一个更易解释的结果模型集,因为对于每个分类值,列将保持为单个列,而不是多个列。

column_trans = ColumnTransformer(transformers=
        [('num', MinMaxScaler(), selector(dtype_exclude="object")),
        ('cat', OrdinalEncoder(),selector(dtype_include="object"))],
        remainder='drop')

利用我们的y值上的LabelEncoder来确保它被编码为一个数值也是一个最佳实践。

# Encode the target variable
le = LabelEncoder()
y = le.fit_transform(y)

最后,在我们开始之前,我们将把我们的数据分成训练测试组。

# Split the data into 30% test and 70% training
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

线性和逻辑回归系数

正如在引言中提到的,线性和逻辑模型是非常好解释的。我们可以很容易地提取每个特征的系数,并用它们来解释模型。如果你的数据适合线性或逻辑回归,它们往往是解释能力的最佳模型之一。您可以根据每个要素对结果的影响对其应用数学权重。让我们看一个数据集上的例子。

我们将从创建我们的分类器管道的实例开始,使适合我们的训练数据。

# Create a random forest classifier for feature importance
clf = LogisticRegression(random_state=42, 
                             max_iter=1000, 
                             class_weight='balanced')

pipeline = Pipeline([('prep',column_trans),
                        ('clf', clf)])

# Fit the model to the data
pipeline.fit(X_train, y_train)

现在我们有了 fit 管道,我们可以从中提取一些信息。这里,我们通过调用管道中分类器的coef_属性来提取每个特征的系数。

pipeline['clf'].coef_[0]
array([0.75471553, -1.11473323, -0.0714886 , -3.2587945 , 1.78373751,
        2.61506079,  0.02806859,  0.13490259,  0.1151557 ,  0.09080435,
       -0.47980448, -0.82908536, -0.5171127 ,  0.01441912,  0.14207762])

您可以看到数据集中每一列的每个系数,正的或负的。我们一会儿会让它更容易阅读。在此之前,我们先来看看intercept_

pipeline['clf'].intercept_[0]
-0.5418635990682154

让我们以更易读的格式显示系数。我们将首先创建一个包含系数和列名的数据框。

feat_list = []
total_importance = 0
# Make a data frame of Coefficients and Feature Names
for feature in zip(X, pipeline['clf'].coef_[0]):
    feat_list.append(feature)
    total_importance += feature[1]

# create DataFrame using data
df_imp = pd.DataFrame(feat_list, columns =['FEATURE', 'COEFFICIENT']).sort_values(by='IMPORTANCE', ascending=False)
df_imp.sort_values(by='IMPORTANCE', ascending=False)
 FEATURE  COEFFICIENT
5     balance     2.615061
4     default     1.783738
0         age     0.754716
14   poutcome     0.142078
7        loan     0.134903
8     contact     0.115156
9         day     0.090804
6     housing     0.028069
13   previous     0.014419
2     marital    -0.071489
10      month    -0.479804
12      pdays    -0.517113
11   campaign    -0.829085
1         job    -1.114733
3   education    -3.258795

现在我们可以很容易地看到每个特性对模型结果的影响。例如平衡的系数为2.615061。这意味着平衡每增加一个单位,正面结果的几率就会增加2.615061。我们还可以看到教育有一个-3.258795的系数。这意味着教育每增加一个单位,积极成果的概率就会减少-3.258795

在这种情况下,你可以与销售和营销人员沟通的一种方式是“关注平衡水平较高的人,避开教育水平较低的人”。

特征重要性

接下来,对于基于树的分类器和回归器,我们可以输出特征重要性。这是一个极好的功能,既可以选择最有影响力的功能,也可以帮助解释模型。让我们看一个使用数据集的例子。我们将以与之前相同的方式开始,创建分类器和管道的实例,然后使其适合我们的训练数据。

# Create a random forest classifier for feature importance
clf = RandomForestClassifier(random_state=42, 
                             n_jobs=6, 
                             class_weight='balanced')

pipeline = Pipeline([('prep',column_trans),
                        ('clf', clf)])

pipeline.fit(X_train, y_train)

类似于逻辑回归的coef_属性,我们有一个feature_importances_属性为我们提供相对重要性。与系数不同,特征重要性是每个特征重要性的相对度量。所有特征重要性的总和等于 1。您可以将这些视为相对重要性,而不是数学权重。

pipeline['clf'].feature_importances_
array([0.15169613, 0.1668886 , 0.13429024, 0.07288524, 0.05647985,
       0.02818437, 0.07880281, 0.03797838, 0.04328934, 0.00404282,
       0.02838248, 0.02165701, 0.04896554, 0.09215941, 0.03429777])

让我们用一种更易读的格式来显示特性的重要性。我们将首先创建一个数据框,其中包含要素重要性、列名以及所有要素重要性的累积和。

feat_list = []

total_importance = 0
# Print the name and gini importance of each feature
for feature in zip(X, pipeline['clf'].feature_importances_):
    feat_list.append(feature)
    total_importance += feature[1]

# create DataFrame using data
df_imp = pd.DataFrame(feat_list, columns =['FEATURE', 'IMPORTANCE']).sort_values(by='IMPORTANCE', ascending=False)
df_imp['CUMSUM'] = df_imp['IMPORTANCE'].cumsum()
df_imp
 FEATURE  IMPORTANCE    CUMSUM
1         job    0.166889  0.166889
0         age    0.151696  0.318585
2     marital    0.134290  0.452875
13   previous    0.092159  0.545034
6     housing    0.078803  0.623837
3   education    0.072885  0.696722
4     default    0.056480  0.753202
12      pdays    0.048966  0.802168
8     contact    0.043289  0.845457
7        loan    0.037978  0.883436
14   poutcome    0.034298  0.917733
10      month    0.028382  0.946116
5     balance    0.028184  0.974300
11   campaign    0.021657  0.995957
9         day    0.004043  1.000000

我们可以看到工作是最重要的特征,其次是年龄婚姻。再次注意,这和我们看系数的方式有点不同。例如,年龄很容易用系数来解释,因为数字越大,人的年龄就越大,但是对于工作,我们有一个编码特征,它不是真正有序的,这使得它对系数意义不大,但对特征重要性意义更大。这是你的管道和编码策略需要考虑的事情——你将如何解释结果?

SHAP 价值观

SHAP ,代表 SHapley 加法解释,是最先进的机器学习解释能力。该算法于 2017 年由 Lundberg 和 Lee 首次发表,是一种对任何预测算法的输出进行逆向工程的方法。

SHAP 基于博弈论的一个概念,我们有复制模型结果的游戏,而玩家是模型中包含的特征。SHAP 量化了每个玩家对游戏的贡献。

让我们看看 SHAP 是如何处理我们的数据集的。我们将首先创建一个分类器实例,在本例中是非常流行的 XGBoost 和 pipeline,然后使它适合我们的训练数据。

clf = xgboost.XGBRegressor()

pipeline = Pipeline([('prep',column_trans),
                        ('clf', clf)])

pipeline.fit(X_train, y_train);
model = pipeline['clf']

# explain the model's predictions using SHAP
explainer = shap.Explainer(model, 
                           pipeline['prep'].transform(X_train), 
                           feature_names=X_train.columns)
shap_values = explainer(pipeline['prep'].transform(X_train))

# visualize the first prediction's explanation
fig = shap.plots.waterfall(shap_values[1])
plt.tight_layout()
plt.savefig('explainability_01.png', dpi=300);

作者图片

瀑布图显示了对单个预测的解释。每一行都显示了每个要素的正(红色)或负(蓝色)贡献如何移动本次预测的预期模型输出值。

看 x 轴,可以看到期望值E[f(x)] = 0.112。该值是所有观测值的平均预测值。结束值为f(x) = 0.053,是本次观测的预测数。在本例中,我们有一个二进制目标值,因此该预测非常接近于0或在营销活动中无法转化的客户)。SHAP 值是介于两者之间的所有值。例如,婚姻状态的积极变化将增加0.04产生积极结果的概率。

结论

机器学习中的模型可解释性是你可以在实践中学习和实现的最重要的概念之一。理解如何解释为什么您的模型会以这种方式执行,可以转化为更好的业务决策和对您的模型的更多信任。在这篇文章中,我们看了几种解释我们模型的方法。我们查看了逻辑回归的系数,随机森林模型的特征重要性,以及 XGBoost 模型的 SHAP 值。您可以使用这些方法来解释您的模型,并帮助您理解为什么您的模型会做出这样的预测。快乐模型建筑!

这篇文章的所有代码都可以在 GitHub 上找到。

如果你喜欢阅读这样的故事,并想支持我成为一名作家,考虑注册成为一名媒体成员。一个月 5 美元,让你可以无限制地访问成千上万篇文章。如果您使用 我的链接 注册,我将为您赚取一小笔佣金,无需额外费用。

如何估计和减少机器学习模型的碳足迹

原文:https://towardsdatascience.com/how-to-estimate-and-reduce-the-carbon-footprint-of-machine-learning-models-49f24510880

轻松估算机器学习模型碳足迹的两种方法和如何减少碳足迹的 17 个想法

照片由 Unsplash 上的卡拉什尼科夫拍摄

机器学习模型的环境影响越来越受到关注,但主要来自学术界。在这里,对话往往集中在语言模型的碳足迹上,这些语言模型不一定代表一般的机器学习领域,并且对机器学习模型的操作阶段的环境影响关注不够。

此外,关于机器学习的环境影响这一主题的现有材料对如何实际估计和减少环境影响的强调太少。本文试图解决这些问题,是为从事机器学习实践的从业者和研究人员而写的。虽然这篇文章是考虑到机器学习而写的,但其中的一些内容也适用于一般的软件工程。

这篇文章的结构如下:

  1. 首先,我们来看一些来自机器学习的碳排放的具体例子。
  2. 然后,我将介绍两种工具,它们可以用来估计机器学习模型的碳足迹。
  3. 在第三部分,我将提出 17 个想法,告诉你如何减少机器学习相关工作的碳足迹。
  4. 最后,我将介绍一些机器学习可持续性的考虑因素,这些考虑因素在这里没有直接提到,但仍然很重要。

在我们开始之前,我想强调的是,这篇文章不是用来指责或者说教的。这样做的目的只是为了展示你可能会发现或可能不会发现与你的日常活动相关的信息。

1.数据科学和机器学习对环境的影响

所有软件——从运行在我们手机上的应用程序到运行在云中的数据科学管道——都消耗电力,只要我们的电力不是全部由可再生能源产生,电力消耗就会产生碳足迹。这就是为什么机器学习模型可以有碳足迹。

我将使用术语“碳足迹”来指代 CO₂e 的排放量,其中“e”是“当量”的缩写由于甲烷、一氧化二氮甚至水蒸气等其他气体也具有变暖效应,为了简化起见,CO₂-equivalents (CO₂e)通常提供一种标准化的方法来描述一定量的气体会产生多大的变暖效应。

据我所知,在撰写本文时,还没有报告试图估算机器学习领域的总碳足迹。这个结论最近得到了[1]的呼应。

然而,在估计全球数据中心行业的总电力消耗方面已经进行了多种尝试。2015 年和 2016 年报告的数据中心全球能耗估计值在全球电力消耗的 3-5%之间[2][3]。最近,一些人声称数据中心占全球用电量的 1%[4][5]。根据我对这一主题的一些文献的回顾,我的印象是 1 %的估计比 5 %的估计更准确。

如果我们看看组织层面上机器学习的能耗,谷歌说公司总能耗的 15 %用于研究、开发和生产中与机器学习相关的计算[6]。NVIDIA 估计 80–90%的机器学习工作量是推理处理[7]。类似地,Amazon Web Services 已经声明云中 90%的机器学习需求是用于推理的[8]。这远远高于一家未透露姓名的大型云计算提供商在最近的经合组织报告[1]中提出的估计。这家提供商估计,企业客户在计算基础设施上的总支出中有 7-10%用于人工智能应用,其中 3-4.5%用于训练机器学习模型,4-4.5%用于推理。

现在让我们来看看机器学习模型碳足迹的一些具体例子。

表 1 显示了一些大型语言模型的估计能耗和碳足迹的概况。碳足迹从 3.2 吨到 552 吨 CO₂e.不等。现在你可能会注意到,PaLM 的能耗明显大于 GPT-3,尽管 GPT-3 的估计碳足迹是 PaLM 的两倍多。这可能是由于用于训练模型的电力的碳强度的差异。为了客观地看待这些大型语言模型的碳足迹,平均每个美国人一年产生 16.4 吨 CO₂e 排放量[9],平均每个丹麦人产生 11 吨 CO₂e 排放量[10]。因此,GPT 3 号的碳足迹大约相当于 50 个丹麦人一年的碳足迹。

表 1:7 个大型深度学习模型的能耗。改编自[6]和[11]

查看几个使用语言模型进行推理的碳足迹示例,脸书估计他们基于转换器的文本翻译通用语言模型的碳足迹主要由推理阶段控制,使用的推理资源(65%)比训练(35%)多得多[40]。脸书的 ML 训练任务的平均碳足迹是现代对话代理中使用的 Meena 的 1.8 倍,是 GPT-3 的 0.3 倍。

BigScience 的开源语言模型 BLOOM 在 18 天内处理了 230,768 个请求,消耗了 914 千瓦时的电力,排放了 360 千克的二氧化碳,相当于每个请求大约消耗 1.56 gco₂e[41]。

这些大型语言模型在碳足迹方面是极端的情况,很少有数据科学家会从头开始训练这样的大型模型。因此,现在让我们考虑一个可能更接近大多数数据科学家和 ML 工程师日常生活的案例。我最近在法兰克福的 GPU 上训练了一个用于时间序列预测的 Transformer 模型3 个小时。这消耗了 0.57 千瓦时的电力,碳足迹为 340 克 CO₂e,大约相当于一个丹麦人年碳足迹的 0.003 %。

从历史上看,获得最先进结果所需的计算量每 3.4 个月就会翻一番[12],因此这个问题可能会变得更加复杂——这是[13]中的一个担忧——尽管一些人预计由于算法和硬件的改进,能耗会降低[6]。

综上所述,由于缺乏数据,很难描绘出机器学习领域碳足迹的全貌,但特定的模型,特别是语言模型,可能会有很大的碳足迹,一些组织在机器学习相关活动上花费了相对较大的总能耗。

</8-podcast-episodes-on-the-climate-impact-of-machine-learning-54f1c19f52d>

2.如何估计机器学习模型的碳足迹

在我们深入研究可以估计机器学习模型碳足迹的工具的细节之前,熟悉一下计算碳足迹的公式是有帮助的。这非常简单:

碳足迹= E * C

其中 E 是在一些计算过程中消耗的电力单位的数量。这可以量化为千瓦时(kWh)。 C 是指生产一单位电能所排放的 CO₂e 量。这可以量化为每千瓦时电力排放的千克 CO₂e,有时也称为电力的碳强度。碳强度因地理区域而异,因为能源来源因区域而异。一些地区有大量的可再生能源,一些地区则较少。给定这个等式,我们现在可以看到,任何估计一些计算程序的碳足迹的工具必须测量或估计 EC.

有几种工具可以用来估计机器学习模型的碳足迹。根据我的经验,这些工具分为两类:

  1. 估算碳足迹的工具估算E ( 能源消耗)
  2. 测量值E ( 能源消耗)估算碳足迹的工具

在本帖中,我们将仔细看看两个这样的工具:

  1. ML CO2 影响,依赖于 E估计值,因此属于上述第 1 类
  2. CodeCarbon 依赖于 E测量值,因此属于上述类别 2

请注意,其他软件包,例如carbon tracker【14】和experiment-impact-tracker【15】提供了与 CodeCarbon 类似的功能,但我选择关注 CodeCarbon,因为这个软件包似乎在不断更新和扩展,而最近对 carbontrackerexperiment-impact-tracker的提交是很久以前的事了。

必须注意的是,本文中介绍的工具仅估算了一些计算过程中所使用的电力的碳足迹。例如,他们没有考虑与制造运行代码的硬件相关的排放。

2.1.用 ML CO2 影响估计机器学习模型碳足迹

基于网络的免费工具 ML CO2 Impact [16]通过估计训练过程的电力消耗来估计机器学习模型的碳足迹。要使用此工具估算碳足迹,您只需输入以下参数:

  1. 硬件类型(例如 A100 PCIe 40/80 GB)
  2. 硬件使用的小时数
  3. 使用了哪个云提供商
  4. 计算发生在哪个云区域(例如“欧洲-北方 1”)

该工具然后输出你的机器学习模型排放了多少千克 CO₂e。其计算方法如下:

基于当地电网的功耗时间碳排放量,例如:

250 瓦 x 100h 小时= 25 千瓦时 x 0.56 千克当量。二氧化碳/千瓦时= 14 公斤 CO₂e

该工具还显示了碳密度较低的云区的排放量。

像 ML CO2 Impact 这样的工具的好处是,它可以事后用于估计你自己或其他人的模型的碳足迹,而你不必编辑你的脚本来计算估计值。

像 ML CO2 Impact 这样的工具的缺点是,它依赖于对能源消耗的估计,这自然意味着它对碳足迹的估计可能是错误的。事实上,这样的工具可以以 2.42 的比率关闭,如下图 1 所示。

图 1 [17]

2.2.用 CodeCarbon 估计机器学习模型的碳足迹

CodeCarbon [18]是一个适用于 Python 和其他语言的软件包,可以通过在命令提示符下运行pip install codecarbon来安装。CodeCarbon 是这样计算代码的碳足迹的:

CodeCarbon 以固定的时间间隔(例如 15 秒)直接测量执行代码的 GPU、CPU 和 RAM 的耗电量。请注意,CodeCarbon 既可以在本地机器上运行,也可以在云机器上运行。该软件包还监控代码执行的持续时间,并使用这些信息来计算代码的总耗电量。然后,CodeCarbon 会检索您的硬件所在地理位置的电力碳强度信息。如果您在云中训练,CodeCarbon 会自动检索您的云实例的位置信息。然后将电力的碳强度乘以该代码消耗的电量,以提供该代码消耗的电力的总碳排放量的估计值。

可以通过几种方式在您的代码中使用该工具。一种方法是初始化跟踪器对象。当跟踪器对象停止时,CodeCarbon 的默认行为是将结果保存到一个. csv 文件中,该文件将包含有关您的代码消耗了多少电力(以 kWh 为单位)以及该电力释放了多少 CO₂e(以 kg 为单位)的信息。代替写入文件系统,信息可以被发送到记录器[30]。假设您有一个执行模型训练的函数train_model(),那么您可以像这样使用 CodeCarbon:

另一种方法是使用 CodeCarbon 作为上下文管理器,如下所示:

最后,CodeCarbon 可以用作函数装饰器:

注意,如果构造函数的参数log_level被设置为默认值,CodeCarbon 会在每次对你的硬件进行能量消耗测试时打印出几行文本。这将很快淹没您可能有兴趣在模型训练期间在终端中查看的其他信息。如果您改为设置log_level="error" CodeCarbon 将只在遇到错误时打印到终端。

还可以可视化能源消耗和排放,该工具还可以推荐碳强度较低的云区[19]。

2.2.1。关于 CodeCarbon 方法的更多信息

碳强度(C)是进行计算的能源网格中使用的能源(如煤、风)产生的排放的加权平均值。这意味着 CodeCarbon 报告的碳足迹不是实际的碳足迹,而是一个估计值。电力的碳强度每天都在变化,因此计算碳足迹更准确的方法是使用实时的电力碳强度。当地能源网使用的能源被称为能源组合。该方案假设一种能源的碳强度相同,而不管这种能源是在世界上哪个地方生产的,例如,在日本和德国,煤的碳强度被认为是相同的。所有可再生能源的碳强度都是 0。

消耗的功率 (E) 以 kWh 为单位进行测量,并通过以频繁的时间间隔跟踪硬件的电源来获得。默认值是每 15 秒一次,但是可以用measure_power_secs构造函数参数进行配置。

https://kaspergroesludvigsen.medium.com/the-10-most-energy-efficient-programming-languages-6a4165126670

3.如何减少你的机器学习模型的碳足迹

在我们仔细研究如何减少机器学习模型的碳足迹之前,让我们确保我们在术语方面保持一致。

在下文中,我有时会区分训练机器学习模型的碳足迹和使用机器学习模型的碳足迹。前者将被称为“模型训练”或“模型开发”后者将被称为机器学习模型生命周期的“操作”阶段,或者使用该模型进行推理。

我还想指出,我有意不触及碳补偿。这不是因为我反对补偿,而是因为我想通过消除来减少碳排放。查看 Asim Hussain 关于碳足迹术语的精彩演讲,了解抵消和消除之间的更多区别【20】。

3.1.开始估计你工作的足迹

第一个建议很简单,不是关于如何减少单个模型的足迹,而是如何减少你的工作的足迹:开始估计你的模型的碳足迹。如果这样做,您将能够在选择型号时考虑这些信息。我最近遇到了这样一种情况,我的最佳型号比第二好的型号获得了低 13 %的 MAE,但与此同时,最佳型号的碳足迹却大了大约 9000%。你应该用模型误差的减少来换取碳足迹的大幅增加吗?嗯,这显然非常依赖于上下文,最终可能应该由企业根据您(数据科学家或 ML 工程师)提供的数据来决定。

3.2.指定碳足迹预算模型

页面权重预算是 web 开发中的一个术语。页面权重预算指定了一个网站被允许“加权”多少千字节的文件。具体来说,它是网页加载时通过互联网传输的文件的大小[21]。重要的是,在开发开始之前就要指定页面权重预算,并且该预算应该在从设计到实现的整个过程中充当一个导航星。

在数据科学中,我们可以培养一个类似的概念,例如,通过设置一个限制,我们将允许机器学习模型在其生命周期内排放多少。一个更简单的衡量标准是每个推论的碳足迹。

3.3.如果滑板可以带你去你想去的地方,就不要造跑车

下一个建议听起来似乎很简单,但我认为它值得我们不时提醒自己,你并不总是需要非常复杂的解决方案来解决你的问题。

当你开始一个新项目时,从计算一个合理的,但是便宜的基线开始。对于时间序列预测,这样的基线可以使用在 t-n 的值(n 可以是 24,如果您的数据具有每小时的分辨率并显示每日的季节性)作为 t. 的预测值。在自然语言处理中,一个合理的基线可以是作为正则表达式实现的一些启发式方法。在回归中,一个好的基线可能是使用你的目标变量的平均值,潜在地由一些其他变量分组。

一旦你有了一个合理的基线,你就可以与之比较,看看更复杂的解决方案是否值得额外的工作和碳排放。

3.3.测试如果你变小会发生什么

如果您决定神经网络架构适合您的问题,不要盲目选择 2048 的前馈层维度,因为这是研究论文所做的。最近,我用一个非常小的层(每层少于 256 个神经元,有时少得多)的模型在准确性上胜过了一个大型模型。这两个模型有相同的层数和类型——一个只有很小的层数。除了更准确之外,它在推理过程中也更快。

3.4。火车模型哪里能源更清洁

如果你使用的是 Google Cloud、AWS 或 Azure 等云提供商,你可以选择在哪个地区运行你的计算程序。研究表明,仅仅通过在使用更多可再生能源的地区进行实验,排放量就可以减少 30 倍[22]。下面的表 2 显示了在不同地区的谷歌云平台上使用 100 个 GPU 计算 100 小时排放了多少千克二氧化碳当量。很明显,电力的碳强度在不同地区之间差异很大。

表二。来源:毫升二氧化碳影响

3.5。火车模型能源更清洁

如下图 2 和图 2 所示,电力的碳强度每天都在变化,甚至每小时都在变化,图 2 和图 2 显示了 2022 年 1 月 1 日至 2022 年 10 月 7 日期间丹麦东部每天和每天每小时的平均碳足迹(g/kWh)。与普遍的看法相反,该数据显示,中午左右的电力比晚上更干净。

你可以通过将繁重的工作安排在能源更清洁的时段来减少工作的碳足迹。如果你不急着训练一个新的模型,一个简单的想法是当你的云区域的电力碳强度低于某个阈值时开始你的模型训练,当碳强度高于某个阈值时暂停训练。使用 PyTorch,您可以轻松地保存和加载您的模型。您可以硬编码或手动提供您所在地区拥有清洁能源的时间,或者您可以从付费服务中获取数据,如电力地图,该地图提供对各地区电力碳强度的实时数据和预测。

图二。丹麦东部一天中每小时电力的平均碳强度。作者配图。来自https://www.energidataservice.dk/tso-electricity/CO2Emis的数据

图 3。丹麦东部每天的平均电力碳强度。作者配图。来自https://www.energidataservice.dk/tso-electricity/CO2Emis的数据

3.6.优化能耗和模型准确性的超参数

当您运行超参数优化程序时,您可以定义一个双目标优化问题,在该问题中,您可以针对模型精度和能耗进行优化。这将在运营阶段减少模型的能源消耗,从而减少碳足迹。Dercynski 等人[23]使用转换器架构和贝叶斯超参数优化,在掩蔽语言建模任务中规定了困惑(NLP 中的准确性度量)和能量消耗的组合测量。为了在不牺牲复杂度或能耗的情况下确定无法进一步优化的模型,他们确定了帕累托最优模型。他们发现,最重要的参数似乎是隐藏层数、激活函数和位置嵌入类型。

3.7.注意你的激活功能

激活函数的选择会极大地影响模型的训练时间。如下图 4 所示,Dercynski [24]证明了在 MNIST 数据集上将影像分类模型训练到 90 %准确率所需的时间从几秒钟到 500 秒以上不等。除了证明激活函数的选择会影响训练时间,Dercynski 还发现

  1. 在一次对较小的集合进行推理的情况下,激活函数的选择似乎更有效
  2. 如果要避免特别昂贵的激活功能,应该在目标硬件上分析和调整应用程序

图 4。[24]

3.8.提取大型模型

通过提炼大型模型,你可以减少模型在生产中的碳足迹。模型提炼可以被认为是将知识从一个较大的模型转移到一个较小的模型的过程。有时这是通过训练一个较小的模型来模仿一个较大的、已经训练好的模型的行为来实现的。

蒸馏的预训练语言模型的一个例子是 DistilBERT。与未经提炼的版本 BERT 相比,DistilBert 的参数数量减少了 40 %,推理速度提高了 60 %,同时保持了 97 %的语言理解能力[25]。模型提取也已经成功地应用于图像识别[26],我敢说它也可以用于其他领域,例如用神经网络进行时间序列预测。

模型提取是一种有效的方法,可以在不牺牲准确性的情况下产生计算效率更高的模型。但是,如果您应用模型蒸馏的目的是减少模型的碳足迹,请注意蒸馏过程产生的额外碳排放不会超过模型生产期间您将获得的排放节省。

3.9.不要盲目地用更多计算机来解决你的问题

我想我们大多数人会直觉地认为减少某个过程的执行时间会减少它的碳足迹。我的理解是,如果你通过简单地编写执行得更快的更好的代码来加速你的代码,情况就是这样。然而,通过投入更多的计算能力来加速你的程序只会在一定程度上让它更环保——至少根据图 5 来源的研究结果是这样的。

作者测量了在具有不同数量内核的 CPU 上运行粒子物理模拟的处理时间和碳足迹。他们的结果显示在图 5 中。绿线显示运行时间,即运行模拟需要多长时间。橙色线显示了运行模拟产生的碳足迹。值得注意的是,当他们将模拟中使用的 CPU 内核数量从 30 个增加到 60 个时,执行时间几乎没有减少,碳足迹从大约 300 gCO₂e 增加到超过 450 gCO₂e.

由此作者得出结论,一般来说,如果运行时间的减少低于内核数量的相对增加,分配计算将恶化碳足迹。对于任何并行计算,都可能有一个特定的最佳内核数量来实现最小的 GHG 排放。

图 5。[27]

3.10。如果你的模特表现不佳或表现停滞不前,尽早停止模特训练

你可以做的另一件事是减少你的碳足迹,确保你没有浪费资源去训练一个不收敛或者已经收敛并且可能不会进一步改善的模型。实现这一点的工具是 Bjarte Sunde 的pytorchtools【28的提前停止模块。它非常容易使用。创建一个 EarlyStopping 对象,在每个时期之后,将模型的平均损失与模型一起传递给该对象。如果丢失有所改善,EarlyStopping 对象会创建模型的检查点,这意味着它会保存给定时期的模型参数。如果在通过构造函数参数“耐心”定义的多个时期内损失没有改善,则退出训练循环。

3.11。不要使用网格搜索进行超参数调谐

超参数是“烦人的”[29,第 7 页],但却是控制训练算法行为的非常重要的旋钮。它们对你的机器学习模型的性能有很大的影响,因此必须仔细调整。一种方法是通过指定一组超参数来试验和训练该组中可能组合的模型。这被称为网格搜索,并且对于大网格来说计算量非常大,因为模型是为每个可能的组合训练的。幸运的是,存在更有效的方法,如随机搜索和贝叶斯优化。除了计算效率更高之外,它们还被证明可以带来更好的模型性能[30]。Hyperopt [31]、Bayesian Optimization [32]和 Ray Tune [33]是一些 Python 包,可以让您进行高效的超参数调整。

3.12.在专门的数据中心接受培训

云数据中心的能效是典型数据中心的 1.4 到 2 倍,ML 专用硬件的能效是现成系统的 2 到 5 倍。例如,与英伟达的特斯拉 P100 处理器相比,谷歌定制的 TPU v2 处理器在训练一些大型语言模型时使用的能源分别减少了 1.3 倍和 1.2 倍。[17].使用高效的数据中心将减少开发和运营阶段的碳足迹。

3.13.小规模实例调试

减少机器学习模型开发的碳足迹的一个简单方法是减少模型训练程序运行的次数。通过在开始整个训练过程之前对数据的小子集进行试验,您可以更快地发现错误,并减少模型开发过程中的能量消耗。

3.14.尽可能使用预先训练的语言模型

这是显而易见的。除非万不得已,否则不要从头开始训练大型语言模型。相反,对已经可用的进行微调,例如通过 Huggingface [34]。作为一个斯堪的纳维亚人和开源爱好者,我想对我的董事会同事 Dan Saatrup 的 ScandEval 大声疾呼,它对大量开源的斯堪的纳维亚语言模型进行了基准测试[35]。

3.15.让您的服务仅在特定时间可用

最近的一篇文章表明,部署了大型语言模型的云实例的能耗相对较高,即使模型没有主动处理请求[41]。因此,考虑一下您的服务是否必须 24/7/365 可用,或者您是否可以有时关闭它。例如,如果你已经开发了一个基于 ML 的服务供组织内部使用,在某些情况下,你可以合理地预期没有人会在晚上使用这个服务。因此,运行服务的计算资源可以在夜间的几个小时关闭,并在早上再次启动。

3.16。使用稀疏激活的神经网络

神经网络可能需要大量的计算来训练,但稀疏激活的网络可以以更低的能耗产生相同的性能。稀疏网络可以定义为只存在一定百分比的可能连接的网络[36]。

大型但稀疏激活的 dnn 消耗的能量不到大型密集 dnn 的 1/10,尽管使用了同样多甚至更多的参数,但仍不会牺牲精度[17,第 1 页]

在我看来,稀疏神经网络是一个复杂的主题,在机器学习模型脱碳树上还有其他悬得较低的成果,但如果你想进一步探索这一点,这里有一些资源可以开始:

https://ai.googleblog.com/2020/09/improving-sparse-training-with-rigl.html https://ai.googleblog.com/2021/03/accelerating-neural-networks-on-mobile.html

3.17.将数据移动到低能耗存储解决方案

当然,这不是一个专门针对机器学习模型的建议,但它是一个关于如何减少整个应用程序的碳足迹的想法。一些数据存储解决方案比其他解决方案更节能。AWS Glacier 是高效数据归档解决方案的一个例子[37,~02:50]。从像 AWS Glacier 这样的解决方案中检索数据需要一段时间,但它比更快的存储解决方案更节能。

4.机器学习从业者和研究人员的其他可持续性考虑

在这一节中,我将简要指出一些本文没有直接涉及的其他可持续性考虑因素。

如果我们作为机器学习实践者和研究人员——通过提高我们对软件碳足迹的认识——激励数据中心所有者和运营商不断用更高效的硬件替换他们的硬件,那么在这种高效硬件上运行所节省的碳排放可能会被硬件的内含排放所抵消。

此外,碳足迹并不是与机器学习的环境可持续性相关的唯一因素,也不是更广泛的 IT 行业值得关注的因素。

其他考虑因素包括生物多样性评估和机器学习对其他地球边界的影响(如土地系统变化和淡水使用),来自制造、运输和报废影响的直接自然资源影响,以及来自机器学习应用的间接影响[1]。

我们也不能忘记,机器学习模型运行在硬件上,这些硬件是复杂价值链的结果。价值链上的环境影响包括土壤污染、毁林、侵蚀、生物多样性退化、有毒废物处置、地下水污染、水资源利用、放射性废物和空气污染[38]。

以上是机器学习的所有与环境相关的影响,但也存在其他影响,如社会影响[39]。

结论

这篇文章表明,虽然很难确定机器学习作为一个领域的环境影响,但从业者可以很容易地通过 CodeCarbon 或 ML CO2 影响来估计他们的机器学习模型的碳足迹。这篇文章还展示了如何减少机器学习模型碳足迹的 17 个具体想法。其中一些想法是非常容易实现的,而另一些则需要更多的专业知识。

就是这样!我希望你喜欢这篇文章🤞

请留下评论让我知道你的想法🙌

关注更多与可持续数据科学相关的帖子。我也写时间序列预测,比如这里的或者这里的。

此外,请务必查看丹麦数据科学社区可持续数据科学指南,了解更多关于可持续数据科学和机器学习的环境影响的资源。

并随时在 LinkedIn 上与我联系。

参考

[1]https://www . OECD-I library . org/science-and-technology/measuring-the-environmental-impact-of-artificial-intelligence-compute-and-applications _ 7 babf 571-en

[2]https://www . independent . co . uk/climate-change/news/global-warming-data-centers-to-consuming-triple-as-do-power-in-next-decade-experts-warn-a 6830086 . html

[3]https://www . climatechangenews . com/2017/12/11/tsunami-data-consume-fifth-global-electricity-2025/

[3]https://pisrt . org/PSR-press/journals/easl-vol-3-issue-2-2020/new-perspectives-on-internet-electricity-use-in-2030/

[4]https://www . border step . de/WP-content/uploads/2020/04/border step-data center-2018 _ en . pdf

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

[6]https://arxiv.org/ftp/arxiv/papers/2204/2204.05149.pdf

[7]https://www . HPC wire . com/2019/03/19/AWS-upgrades-its-GPU-backed-ai-inference-platform/

[8]https://AWS . Amazon . com/blogs/AWS/Amazon-ec2-update-in f1-instances-with-AWS-inferentia-chips-for-high-performance-cost-effective-inferencing/

[9]https://www . Forbes . com/sites/robto EWS/2020/06/17/deep-learning-climate-change-problem/?sh=1ed2fd916b43

[10]https://kefm . dk/aktuelt/nyheder/2021/apr/foerste-officielle-vurdering-af-danmarks-globale-klimaaftryk

[11]https://arxiv.org/pdf/2204.02311.pdf

https://openai.com/blog/ai-and-compute/

[13]https://towards data science . com/deep-learning-and-carbon-emissions-79723 D5 BC 86 e

https://github.com/Breakend/experiment-impact-tracker

https://github.com/lfwa/carbontracker

[16]https://mlco2.github.io/impact/

https://arxiv.org/ftp/arxiv/papers/2104/2104.10350.pdf

[18]https://github.com/mlco2/codecarbon

[19]https://medium . com/BCG gamma/ai-computing-emisses-co % E2 % 82% 82-we-started-measuring-how-amount-807 dec 8 c 35 e 3

https://www.youtube.com/watch?v=HXEnbi64TdQ&ab _ channel = DevoxxUK

【21】https://www . whole grain digital . com/blog/how-to-page-weight-budget/#:~:text = What % 20 is % 20a % 20 page % 20 weight,when % 20a %网页%20is%20loaded

https://arxiv.org/pdf/2002.05651.pdf

https://aclanthology.org/2021.sustainlp-1.12.pdf

https://arxiv.org/pdf/2006.07237.pdf

https://arxiv.org/abs/1910.01108

[26]https://arxiv.org/abs/1503.02531

https://arxiv.org/ftp/arxiv/papers/2007/2007.07610.pdf

[28]https://github . com/Bjarten/early-stopping-py torch/blob/master/pytorchtools . py

[29]https://arxiv.org/abs/1206.5533

[30]https://www.jmlr.org/papers/v13/bergstra12a.htmlhttps://wandb . ai/site/articles/Bayesian-hyperparameter-optimization-a-primer

[31]http://hyperopt.github.io/hyperopt/

[32]https://github.com/fmfn/BayesianOptimization

https://docs.ray.io/en/latest/tune/index.html

https://huggingface.co/models

[35]https://scandeval.github.io/

[36]https://numenta . com/blog/2020/10/30/case-for-sparsity-in-neural-networks-part-2-dynamic-sparsity #:~:text = We % 20 define % 20a % 20 sparse % 20 neural,some % 20 of % 20 the % 20 connections % 20 missing

[37]https://open.spotify.com/episode/52KcC2NUvFkgzij1cbbQnS?si=ezFjjfwRTt6-I2yTZ5IQEw

[38]https://anatomyof.ai/

[39]https://www.mdpi.com/2071-1050/13/5/2668

https://arxiv.org/pdf/2111.00364.pdf

https://arxiv.org/pdf/2211.02001.pdf

如何估计训练机器学习模型的时间和成本

原文:https://towardsdatascience.com/how-to-estimate-the-time-and-cost-to-train-a-machine-learning-model-eb6c8d433ff7

照片由 RODNAE Productions 从 Pexels 拍摄。

训练机器学习(ML)模型是一个过程,在这个过程中,机器学习算法被输入数据,以从中学习来执行特定的任务(例如分类),并最终具有进行预测的能力。术语“机器学习模型”是指作为训练过程的结果而产生的模型工件。

在本文中,您将学习如何估计训练机器学习模型的时间和成本。

机器学习生命周期的核心是模型训练,机器学习团队努力让算法适合数据。目的是创建一个训练有素的机器学习模型,具有良好的性能,可以对新的或未知的数据进行预测。

作者创建的图像

机器学习模型在许多方面都对企业有益,包括快速分析大量数据,定位异常,以及发现人类难以单独完成的模式。

有几种类型的机器学习模型,包括监督学习和非监督学习。

监督学习是通过使用带标签的数据集来教导算法如何正确地对数据进行分类或预测结果。随着数据被输入到机器学习算法中,其权重被改变,直到模型正确拟合。监督学习模型可以帮助公司大规模解决各种现实世界的问题,例如检测电子商务平台上的欺诈交易。

无监督学习涉及利用算法在不包含标记数据点的数据集中发现模式的过程。这种类型的学习被称为“没有监督的学习”。这些算法揭示了以前未知的模式或数据分组,而不需要数据科学家的任何参与。它非常适合于客户细分以及推荐系统,因为它能够发现信息中的相似性和差异,

为什么估计训练机器学习模型的时间和成本很重要?

对训练机器学习模型所需的时间和成本做出准确的估计是至关重要的。当您在云环境中针对大量数据训练模型时,尤其如此。如果你正在从事一个机器学习项目,了解训练期的长度可以帮助你做出重要的决定。

例如,如果训练周期比您预期的要长,您可以选择调整算法的参数或选择一个替代算法来实现,以缩短训练您的模型所需的时间。当你计划在短时间内运行各种机器学习实验时,这是非常重要的。

有很多机器学习从业者对找出训练一个机器学习模型需要多长时间感兴趣。例如,下面是在堆栈交流论坛中提出的问题。

“我想提前知道我的培训是 8 小时、8 天还是 8 周。(显然,8 是我任意选择的一个数字)。有没有可靠的方法估计一下需要的时间?我能把训练 20 万人所需的时间推断为训练 10 万人所需时间的两倍吗?如果能够估计这将需要几个小时、几天甚至几周的时间,那将会很有帮助,因为这样我就可以提前调整参数。”— by Chowza

您也可以通过以下链接阅读其他问题:

云实例具有不同的特性和成本。根据您的工作负载和特定数据,您可能会选择为高性能实例支付更多费用,或者通过使用低成本实例来节省资金。对于有经验和无经验的数据科学家来说,知道可以选择哪个云实例来训练机器学习模型都是一项挑战。

有时你可以选择使用价格低廉的云实例,但它可能会支持长时间训练你的机器学习模型,最终会增加比你计划花费更多的成本。另一方面,高性能云实例的成本可能会高得多,但它有助于更快地训练你的机器学习模型。

估计训练机器学习模型的成本可以帮助您规划预算,并为您的机器学习项目购买合适的云实例。

如何估算机器学习模型训练时间和成本

Aipaca 团队目前正在开发一个强大的开源工具,称为训练成本计算器(TCC) ,它可以帮助您预测完成神经网络(Tensorflow 和 Pytorch)训练过程所需的时间,方法是使用:

  • 模型的特征
  • 软件环境
  • 计算硬件

它还能够预测不同云实例上各种机器学习任务的云计算成本。TCC 是一个很好的资源,您可以使用它来预算您的计算成本并减少您的支出。

Aipaca 网站上的演示可以向你展示如何找出训练你的机器学习模型所需的时间和成本。

在演示部分,您必须填写以下与您想要在云环境中训练的机器学习模型相关的功能。

注: 演示结果随机生成,仅供概念验证之用。

1。模型中枢 这是一个预先训练好的自包含深度学习模型的集合,适用于广泛的应用。您可以选择以下模型中枢之一:

  • 拥抱脸
  • Pytorch 中心
  • 张量流集线器

2。模型名称 这是您希望用于项目的预训练模型的名称。以下是您可以从演示中选择的预训练模型列表。

  • 伯特
  • 蒸馏 2
  • GPT2
  • 罗伯塔

3。数据大小 你要指定数据集的大小,你要在这个数据集上训练你的机器学习模型。大小必须是千兆字节格式。比如 2 GB 或者 3.45 GB。

4。时期
这是一个超参数,它定义了学习算法在整个训练数据集中训练的次数。例如,您可以将历元数定义为 100。

5。批量大小 批量大小是一个超参数,指定在更新模型参数之前要运行多少个样本。例如,您可以将批次大小指定为 64 个样本。

现在您已经知道了所有必要的特征,您需要指定它们的值,以便估计训练您的机器学习模型的时间和成本。下一步是在演示中填入这些值。

例如:

  • 模特 Hub: 抱紧脸
  • 型号名称:伯特
  • 数据大小: 5 GB
  • 历元数 : 100
  • 批量: 64

点击此处打开演示部分并填写数值。

来自演示的截图

点击计算按钮获得结果。

完成计算过程后,您可以查看结果,其中将包括云实例的名称、预测的训练时间和预测的成本。

来自演示的截图

从上面的结果可以看出,一个名为 c6g.8xlarge.od 的 AWS 云实例将花费 6.19 小时来训练机器学习模型,总成本为 $6.75。与其他云实例相比,成本可能很高,但如果你计划运行多个机器学习实验,你将节省大量时间。

贡献者

训练成本计算器(TCC)对于机器学习项目来说是一个非常好的提高生产力的工具。TCC 将使您能够快速确定适合您的项目的理想训练时间和云实例,而不是根据您的经验来估计训练您的模型需要多长时间以及要利用哪些云实例。

培训成本计算器(TCC)的第一个版本将很快发布,其中包含更多关于如何在您自己的环境中尝试估计云实例的培训时间和成本的功能和细节。

这是一个 100%开源的项目,我们渴望看到更多的贡献者加入我们的社区。

当 TCC 的第一个版本发布时,更多的细节将被添加到 Github 库。请参考资源库以获取未来的更新,或联系我们以了解任何问题。

如果你学到了新的东西或者喜欢阅读这篇文章,请考虑分享给其他人阅读。

如何用用户研究评估一个交互系统

原文:https://towardsdatascience.com/how-to-evaluate-an-interactive-system-with-a-user-study-d8fdb9b69afa

简要总结各种研究者如何设计用户研究,以评估从机器学习到数据提取的不同交互系统的有效性

近年来,交互系统的开发出现了热潮,例如应用程序、网站和端到端工具。交互式系统旨在帮助用户完成某些任务,如清除大型数据集中的错误或从成千上万的文档中快速提取表格。公司在这些项目上花费数千美元,而工程师花费数百小时来构建这些系统。然而,当他们将这些系统展示给用户或客户使用时,用户的反应可能从“这个系统非常难用”到“这个系统太棒了!”。

虽然很难预测你的用户会说什么,但是通过量化你的交互系统的有效性和有用性来减轻用户体验的问题是很重要的。阅读技术文献描述其他人如何进行用户研究来评估他们系统的有效性。

如何使用用户研究来评估交互系统的有效性?具体来说,系统在帮助用户完成目标任务方面有多大用处?

例如,假设你已经建立了一个系统,学习从用户给出的文本例子中自动提取数据。当用户提供电话号码的例子时,你的系统学习从数百个其他文档中提取电话号码。

但是,如何评价该工具是否真的帮助用户快速准确地提取文本呢?图片作者。

如何评价这样的系统是否真正帮助用户快速准确地提取文本?

大多数系统评估要么是基于 T2 算法的,要么是基于 T4 用户的。当您基于算法实现进行评估时,度量标准和方法与对用户进行评估时不同,后者需要招募和观察使用您系统的人。

这篇文章的重点是我所说的比较用户评估。这些评估将您的系统与基准系统进行比较。目标是根据一些选择的标准证明您的系统优于一些基线系统。招募人类,要求他们完成系统上的某些任务,并观察用户执行任务的情况。

我将简要提及十篇论文,它们对调试系统、机器学习系统以及数据转换和数据提取系统进行了比较评估。我将描述这些论文的比较用户评价的一些相似之处和不同之处。希望这篇简短的评论描绘出一个如何进行比较用户评估的总体思路。

选择一个基准系统来比较您的系统

运行比较用户评估包括将用户在您的系统上的表现与基准系统进行比较。

  • 基线系统可以是实际系统的“基本”版本,其核心特性——那些帮助用户完成任务的特性——被剥离了。
  • 或者基线系统可以具有实际系统的一些特征子集。
  • 或者基线系统可能是一个完全不同的系统,可能没有您的系统所具有的有用功能。

这种系统,无论是不同配置的系统还是完全不同的系统,也被称为实验条件

与您系统的基本版本进行比较

例如, WhyFlow 是一个交互式可视化调试系统,其基线是 WhyFlow 的基本版本,其自动生成的错误解释功能被禁用。这个基线旨在模拟手动调试,因为这种自动生成的解释功能并不存在。

对比不同版本的系统

另一种类型的基线可以是系统本身的不同版本,以及启用或禁用的某些功能的组合。这方面的一个例子是在名为 DataPlay 的系统上进行的评估。DataPlay 是一个交互式数据库查询系统,支持试错查询规范。在评估中,用户被要求修复 SQL 查询中的错误。DataPlay 与 Dataplay 本身的两个不同版本进行了比较:

  • DataPlay 的一个版本仅启用了一个称为直接操作的功能。
  • DataPlay 的另一个版本,只启用了一个名为自动查询修正的特性。

与完全不同的系统相比

另一个选择是将你的系统与一个完全不同的系统进行比较,一个完成相同任务的系统。这个系统应该算是最先进的,你的目标是证明你的系统比最先进的系统更好。系统 RxFiddle 就是这样一个实验的例子。

RxFiddle 的用户不得不使用专门为调试反应式程序而设计的可视化工具来调试反应式程序中的错误。由于反应式程序的非线性执行和事件驱动的性质,调试反应式程序比在其他编程范例中调试稍微更具挑战性。当输出异步发生时,这使得用户很难识别错误的来源。由于用户传统上使用 Chrome 的开发工具来调试此类程序,RxFiddle 的对比用户评估是针对 Chrome 的开发工具进行的。

WhyFlow 和 RxFiddle 的相似之处在于它们与传统的调试系统进行了比较,传统的调试系统没有一些关键功能,例如可视化、自动生成的错误解释。

实验类型:受试者内部和受试者之间的用户研究

虽然用户研究设计有很多种,但我将特别关注进行主题内主题间用户研究的论文:

  • 受试者内用户研究:你招募的每个用户都将作为他们自己的基线。换句话说,同一个人测试系统的所有条件。
  • 受试者间用户研究:与受试者内用户研究不同,您招募的每个用户不会测试每个条件。换句话说,不同的用户测试每个条件。

例如,WhyFlow 进行了一项主题内用户研究。所有 10 名被招募的用户都暴露在 WhyFlow 的所有条件下。另一方面,RxFiddle 进行了一项受试者之间的用户研究。他们的一些用户被指示使用 RxFiddle 来完成调试任务。他们招募的其余用户被指示使用传统的调试工具(Chrome Dev Tools)来完成调试任务。

倾向于首选受试者内部用户研究。然而,由于每个被招募的用户都必须暴露于系统的每个条件下,大多数受试者内的用户研究通常会占用大量时间。例如,在 WhyFlow 的例子中,每个用户平均花费 2 个小时,因为每个用户为系统的每个条件花费大约一个小时。受试者内用户研究通常不会招募很多用户(少于 20 个,取决于系统的条件数量)。

受试者之间的用户研究占用每个用户更少的时间,因为他们只暴露于系统的一个条件下。在实验条件下,RxFiddle 用户平均总共花费 40 分钟来完成任务。跨学科用户研究通常会招募很多用户。RxFiddle 的用户研究共招募了 111 名用户。

然而,受试者内部的用户研究具有潜在的学习效应,其中将用户暴露在一种条件下的效应可能会溢出到用户在以下条件下的表现。在审查的受试者内用户研究中,他们通过随机化条件的顺序来降低潜在的学习效果:“工具顺序被随机化以分布可转移知识的影响”。此外,用户的任务在每种情况下都是不同的。

十个比较用户评估摘要

在这一节中,我们提供了十个在系统调试、机器学习和数据提取方面进行的比较用户评估的简要总结。请参见下表,对于每个系统的比较用户评估,我们列出了以下表格:

  • 任务:分配给用户的任务,如调试、标注机器学习模型、完成抽取任务等。
  • 比较:进行比较的系统或特性。
  • 受试者内 : Y 表示该研究为受试者内实验,否则 N 表示受试者间实验。
  • 用户数:招募用户总数。
  • 总时间 : 一个用户学习会话的总持续时间。这些持续时间中的一些包括用户阅读和签署同意书所需的时间、训练用户理解任务和系统所需的时间以及用户回答任何初步和/或研究后问卷所需的时间。
  • 收集的指标:作者在实验过程中记录的一些指标。流行的度量标准包括用户完成分配任务的持续时间以及任务完成的正确性、准确性或百分比。
  • 统计检验:我简单记下了用来比较样本的统计检验,这是一个单独的话题。

10 个比较用户研究表。图片作者。

观察

标记并学习iSeqL尺子是帮助构建机器学习产品的系统。 SEERChartSenseWranglerRousillonTable Repair 是提取数据的系统。我们将在后面详细描述这些系统。

请注意,大多数用户评估都是受试者内部的实验。一个用户会话的持续时间最长为 2 小时。招募的用户数量一般在 10 到 20 左右。

大多数研究收集了用户完成任务所需的持续时间。这个标准通常被用来证明用户使用目标系统比使用基线系统更快地完成分配的任务。大多数研究还收集关于用户表现的准确性指标。这里的准确性指标指的是用户对所分配任务的回答的正确性。

对于输出某种模型的系统,无论是机器学习模型还是数据提取模型(提取文本、表格、图像等的程序。根据文档),他们记录了传统的度量标准,如精确度、召回率和 F1 分数。

机器学习系统的比较用户评价

我们审查的机器学习(ML)系统侧重于帮助用户理解 ML 模型或标记训练 ML 模型所需的数据:

  • Label-and-learn:一个可视化工具,帮助开发人员在标记数据集和训练 ML 分类器时深入了解他们的数据集。在给定训练数据的某个子集及其在测试集上的性能的情况下,它可视化分类器的预测。
  • iSeqL:一个交互式工具,用于快速定制 ML 模型,以提取特定领域的概念,如药物评论数据集中包含药物不良反应的短语。用户迭代地标记数据并训练模型,直到它能够提取特定于领域的概念。
  • 标尺:自动生成标注规则的交互系统。标注规则可以快速标注数千个数据点,为手动标注提供了一种替代方法。传统上,标记规则是由人类手工编写的。Ruler 通过观察用户提供的演示来综合标注规则,从而自动化了这一过程。

对研究设置的评论。虽然在这篇论文样本中,受试者内实验很受欢迎,但 iSeqL 是通过在线进行的受试者间实验进行评估的,就像 RxFiddle 一样。有两种情况:(1)模型预测对用户可见的 iSeqL 版本,以及(2)预测不可见的 iSeqL 版本。这种设置允许 iSeqL 的创建者评估他们关于交互界面的一些设计决策。具体来说,在标注界面中显示模型的预测是否有助于用户识别将提高 ML 模型性能的相关短语?招募的用户的任务是建立一个 ML 模型,并通过提供相关短语来迭代改进它。

另一方面,标签学习和尺子的用户研究是受试者内部的实验。当用户标记训练数据时,标记和学习可视化了 ML 分类器的成功的可能性。Label-and-learn 的用户研究将其用于探索和标注数据的全功能可视化和界面与仅包含文本信息的基本版本的标注界面进行了比较。

我发现标签学习的用户任务与 Ruler 和 iSeqL 的任务不同。每个用户被要求标记 500 个数据点来训练一个二元分类器。在用户标记了 50、100、200 和 400 个实例之后,设置了一个检查点;为了评估用户对二元分类器的心理模型,给用户一个简短的测验。该测验测试了用户对分类器决策的理解。

与帮助人类用户标记数据的 Label-and-learn 和 iSeqL 不同,Ruler 专注于自动生成标记规则。标签规则传统上是在一个叫做 Jupyter 的系统中手工制作的。用户研究的设置很简单:将尺子生成的标注规则与 Jupyter 中手工制作的标注规则进行比较。用户的任务是编写标签规则,以训练垃圾邮件检测和情感分类的 ML 模型。他们记录了标签功能的个人和集体表现。

用户对数据提取系统的比较评价

我们审查的数据提取系统帮助其用户快速准确地执行数据提取或数据转换:

  • SEER:通过从用户突出显示的示例中自动生成提取规则来自动提取文本。
  • ChartSense:一个半自动交互式图表数据提取工具。它集成了可以检测标记的算法,例如条形图中的条、线形图中的标记等。用户可以与系统交互以修复提取中的任何错误。
  • Wrangler:一个用于清理和转换数据的交互系统。系统从用户演示的数据操作中学习数据转换。
  • Rousillon:一个编程系统,它从用户提供的提取内容的演示中学习编写复杂的 web 自动化脚本。
  • 表修复:交互式表修复管道。管道自动提取表格,并附带一个界面友好的手机和平板电脑用户可以轻松修复表格提取中的错误。

对研究设置的评论。大多数数据提取工具的对比用户研究的设置非常简单。用户被指示完成一组提取任务。所有的研究都是受试者内部的实验。这些系统与一个类似的系统进行了比较,后者缺少帮助用户快速准确完成任务的关键功能。

SEER 实验的用户的任务是提取文本实体,如日期和百分比增加/减少。SEER 与用户通过拖放界面手动创建提取规则的系统进行了比较。

ChartSense 实验的用户被要求从条形图和折线图中提取数据。ChartSense 与一个类似但有限的图表提取系统进行了比较,该系统称为 WebPlotDigitizer(用于条形图和折线图的图表提取系统)。

牧马人实验的用户被要求执行数据清理任务,例如值提取、缺失值插补和表格重塑。Wrangler 与 Microsoft Excel 进行了比较,后者允许用户通过一定程度的手动工作来完成这些数据清理任务。

Rousillon 实验的用户被分配了网页抓取任务。网络抓取是指从网站中提取数据。Rousillon 与 Selenium 进行了比较,Selenium 是为编写 web 抓取脚本的用户提供的传统 web 自动化库。

表修复有一个相当不同的用户研究设置。表修复被描述为一个表提取管道,而其用户研究集中在一个伴随的接口的能力,以帮助用户快速和容易地修复在表提取系统中发现的错误。该管道是独一无二的(在撰写本文时)。用户研究的条件由支持的用户交互和设备(手机或平板电脑)的不同组合来定义。

结论

这还远远不够全面,只提供了我在阅读比较用户评估时的一些观察的简要概述。当我们投入大量的时间、金钱和精力来构建这些系统时,我们也应该意识到评估我们的系统是否帮助我们的用户和客户的量化方法。

参考文献

如何评估任何表格合成数据集

原文:https://towardsdatascience.com/how-to-evaluate-any-tabular-synthetic-dataset-8865b7ee0c23

一系列机制和测试,可用于从相似性和实用性角度评估任何表格合成数据集

照片由 DeepMindUnsplash 上拍摄

为什么是合成数据?

合成数据的一些主要优势包括:

  • 可扩展性:真实的训练数据是以线性方式收集的,而合成数据可以产生大量,这缓解了复杂的 ML 任务需要获取大量高质量训练数据的问题。
  • 隐私:由于复杂的隐私要求,数据可用性仍然是一个挑战,尤其是在医疗保健领域。医疗保健研究人员通常很难获得用于次要目的的高质量个体水平数据(例如,测试新的假设,建立统计和 ML 模型)。使用合成数据可以 潜在地 解决这一挑战。

但是,请注意,仅仅让数据“合成”并不能保证隐私。已经表明,合成数据生成并不总是和完全地保护每个人的隐私,尤其是使用非差别隐私数据生成技术。根据经验量化合成数据集的隐私性能也极其困难。单一的隐私度量只能解决某种攻击策略(例如:重新识别攻击、重构攻击或追踪攻击等)。).针对一种攻击表现较好的数据集并不一定意味着它可以抵御不同的攻击。

此外,很难估计攻击者可以获得的知识范围,我们需要假设他们可以获得哪些信息,以及他们试图获得哪些机密信息。更不用说,这些都是已知策略——攻击者可能采用的未知策略数不胜数。这意味着,能够根据经验量化合成数据集的一个(甚至多个)隐私度量的性能,并不足以说明数据集是完全隐私的。

也就是说,本文只关注合成数据集的效用性能。

高斯 Copula 和 CTGAN 数据生成器概述

高斯连接函数

高斯 Copula 是一种用于数据综合的统计建模技术。

Copula 允许我们将联合概率分布分解为变量的边际(根据定义,它们没有相关性)和一个将这些边际“耦合”在一起的函数。换句话说,Copula 是一个“耦合”函数,或者是一个嵌入了相关信息的多元分布。因此,高斯连接函数是一个具有已知相关性的多元正态分布。

该数据生成器的高级流程如下:

  1. 学习每列的概率分布
  2. 对它们应用标准正态的逆 CDF 变换(即,将列的分布转换为正态分布)
  3. 了解这些新生成的随机变量的相关性,以构建 copula 模型
  4. 来自多元标准正态分布的样本,具有学习到的相关性

CTGAN

条件表格生成对抗网络(CTGAN)是一种深度学习数据合成技术。顾名思义,这是一种基于 GAN 的方法。

一个普通的 GAN 由两个神经网络组成:一个作为生成器,接受一些输入并从中生成合成数据。然后,有第二个神经网络作为鉴别器,看看他们是否能区分真实数据和合成数据。来自鉴别器的结果被反馈到发生器,以帮助发生器产生更好的合成输出。

非常高级的 CTGAN 架构概述。图片作者。

CTGAN 与普通 GAN 的区别在于:

  1. Conditional:CTGAN 架构引入了一个条件生成器,它根据某个离散列生成行,并根据该特定离散列的每个类别的对数频率对训练数据进行采样,而不是随机采样训练数据以输入到生成器中,这可能不足以表示高度不平衡的分类列的小类别。这有助于 GAN 模型均匀地(不一定均匀地)探索所有可能的离散值。
  2. 表格:与通常正态分布的图像像素值不同,表格数据中的连续变量可以遵循非高斯和/或复杂的多模态分布。为了解决这个问题,CTGAN 使用特定于模式的规范化来表示连续列。

关于 CTGAN 如何工作的详细描述,请参考他们在发表的论文

合成数据的效用评估

在我们生成一些合成数据后,自然的问题是刚刚生成的数据有多好。具体来说:

  • 合成数据是否保持与真实数据的统计相似性?合成数据保留单变量和多变量分布吗?(即相似性度量)。
  • 在一些计划任务中,用合成数据获得类似的结果并得出与真实数据相同的结论,这可能吗?(即效用度量)。

本文介绍了一系列机制和测试,可以用来评估任何表格合成数据,主要是从保留原始数据的统计属性(相似性)和 ML 功效(效用)的角度。

所有评估都是在来自 UCI 机器学习知识库的败血症存活最小临床记录数据集 (110,204 个实例 x 4 个属性)上进行的。我们使用来自综合数据仓库实施的高斯 Copula 和 CTGAN 模型生成综合数据。

个体分布

鉴于年龄分布在原始数据集中有多种模式,CTGAN 在保持这一属性方面做得更好,而高斯 Copula 仅将分布转化为单一模式。

另一方面,高斯 Copula 比 CTGAN 更好地保持了性别和目标变量类别之间的比例。与高斯 Copula 相比,CTGAN 更好地再现了集数的分布。

所有变量在三个数据集上的分布:真实数据集、高斯 Copula 合成数据集和 CTGAN 合成数据集。图片作者。

缺少值

所有变量最初都没有任何缺失值,来自 CTGAN 和高斯 Copula 的合成数据集能够重现这一点。

K-S 检验

双样本 Kolmogorov–Smirnov(K-S)用于检验两个样本是否来自同一分布。我们在真实和高斯 Copula 数据之间以及真实和 CTGAN 数据之间的所有变量上运行该测试。因为 KS 统计是两个 CDF 之间的最大距离,它越低,对我们的用例越好。

总体而言,与高斯 Copula 相比,CTGAN 的所有变量的平均 KS 统计量略小。

高斯 Copula 与真实数据以及 CTGAN 与真实数据的 2 样本 K-S 测试结果。图片作者。

成对相关

到目前为止,我们已经逐列研究了数据集。现在,让我们来看看两两之间的关系。

高斯 Copula 的成对 Pearsons 相关性的热图似乎与同一性数据的热图更相似。为了验证这一点,我们计算了相关精度。先将相关系数离散化为 6 个等级:[-1,-0.5)(强负),[-0.5,-0.3)(中负),[-0.3,-0.1)(低负),[-0.1,0.1)(无相关性),[0.1,0.3)(低正),[0.3,0.5)(中正),[0.5,1)(强正)。然后,计算合成数据集和原始数据集分配相同相关级别的配对的百分比。

高斯 Copula 的关联精度远大于 CTGAN (83% vs 67%)。

三个数据集之间成对相关的热图。图片作者。

ML 功效

假设一方无法访问原始数据集,他们有可能解决基于合成数据的机器学习问题,并得出尽可能接近真实数据的见解吗?为了回答这个问题,我们使用合成数据集来训练 XGBoost 分类器,并使用它对原始数据进行预测。然后,将这个分数与我们在原始数据上训练 XGBoost 所获得的分数进行比较。

与高斯 Copula 相比,CTGAN 能够实现更接近我们用真实数据实现的预测性能。

XGBoost 分类器的 AUROC 在合成数据上进行训练,并在真实数据上进行评估,与我们在真实数据上训练分类器的结果进行比较。

检测能力

为了评估区分真实实例和合成实例的难度,我们将两个数据集混在一起,并使用标志来指示数据是真实的还是合成的。然后训练一个试图预测这个标志的 ML 模型。预测标记越容易,真实数据和合成数据之间的区别就越明显。

对于这个测试,我们将 XGBoost 和逻辑回归训练为检测器。与高斯 Copula 数据相比,CTGAN 合成数据对 XGBoost 和 Logistic 回归提出了更难区分的挑战,因为它们对应的检测器的 AUROC 更低。

XGBoost 和逻辑回归检测器的 AUROC 性能,尝试区分真实和合成实例。图片作者。

结论

对于这个特定的脓毒症公共数据集,从个体变量评估的角度来看,CTGAN 和高斯 Copula 是不分上下的。然而,高斯 Copula 具有令人惊讶的更好的成对相关准确性,而 CTGAN 实现了更好的 ML 功效,并且更不可能被检测到。

如何在没有基础事实标签的情况下评估聚类性能

原文:https://towardsdatascience.com/how-to-evaluate-clustering-performance-without-ground-truth-labels-9c9792ec1c54

基于群集构造选择适当有效性度量的说明性指南

Unsplash 上由 steve_j 拍摄的照片

介绍

监督学习剧本中有许多方法可用于评估已知基本事实标签情况下的聚类性能。然而,当地面实况不可用时,性能评估就不那么简单了。在这种情况下,我们需要依赖有效性度量,这些度量给我们提供了一个关于如何定义集群的指示。这些有效性指标在很大程度上依赖于数据中聚类的基本构造。

对于由凸球状星团组成的数据,已经提出了多种有效性指标,最流行的是轮廓系数。其他指数包括卡林斯基-哈拉巴斯指数、戴维斯-波尔丁指数和邓恩指数。然而,并不是所有的数据都是由球状星团组成的。有些星系团可以呈现任意形状,由密度来分隔。在这种情况下,我们可以利用基于密度的聚类验证指标,或 DBCV。

注:下图中使用的数据是使用 scikit-learn 的 make_blobsmake_moonsmake_circles 函数生成的。

球状星团

对于主要为球状的星团,最常用轮廓系数 [1]来评估性能。这是一种基于数据点与其自己的聚类相比与其他聚类的相似程度的度量。其值的范围从-1(表示不正确的聚类)到+1(表示高度密集的聚类和良好的分离)。接近 0 的值表示重叠的簇。一个非常适合识别球状星团的算法是 K 均值

下面是一个由 4 个球状星团组成的数据示例(图 1)。这里聚类的标准偏差是 1.2,这导致一些聚类间重叠。然而,K-Means 仍然实现了体面的分离,轮廓系数为 0.44。

图 1:原始数据与 K 均值输出。剪影系数:0.44。

如果我们有非常明确的集群(图 2),我们会期待一个更高的有效性得分。这正是我们在下面的例子中获得的结果,它实现了 0.79 的轮廓系数。本例中聚类的标准偏差为 0.4,产生了更好的可分性。

图 2:原始数据与 K 均值输出。剪影系数:0.79。

然而,如果集群不是由球状形状表征的,轮廓系数可能不是合适的有效性度量。此外,K-Means 可能不是合适的聚类算法,因为它通常更喜欢球形。在下面的例子中,K-Means 明显错误地分类了新月的部分,即使剪影系数仍然产生了令人误解的体面值 0.49。

图 3:非球状数据的 K-均值聚类。

任意形状的簇

对于具有任意形状和大小的聚类,基于密度的聚类验证(DBCV) [2]是优选的评估度量。它根据群集内和群集间的密度来评估群集质量。通过簇内的高密度和簇间的低密度可以获得良好的结果。与剪影系数类似,DBCV 的范围从-1 到+1,分数越高表示聚类质量越好。

有各种常用的聚类算法能够识别任意形状的聚类,如 DBSCAN、HDBSCAN 或 OPTICS。对于下图,我将使用 HDBSCAN (针对有噪声的应用程序的基于层次密度的空间聚类)。

让我们看看 HDBSCAN 在两个新月上的表现:

图 4:月牙形星团上的 HDBSCAN。

由于这两个新月看起来可以通过密度来区分,因此毫不奇怪 HDBSCAN 可以很好地区分它们,相应的 DBCV 为 0.54。相比之下,基于 K 均值标签的 DBCV(图 3)为-0.76,表明如预期的那样,由于错误分类的数据点而导致不正确的聚类。

让我们看另一个任意形状的集群的例子:

图 5:圆形集群上的 HDBSCAN。

同样,这两个圆似乎可以按密度分开,因此,HDBSCAN 实现了 DBCV 为 0.61 的下降结果。相反,K-Means 很难将它们分开,结果,相关的 DBCV 是-0.8(图 6)。

图 6:圆形簇上的 K-均值。

结论

如果无法获得基本事实,就必须依赖基于模型的性能评估指标。虽然剪影系数对于由凸球状星团组成的数据来说是一个可靠的度量,但它通常不适用于任意形状的星团,并且尽管有明显的错误分类,但仍会产生令人迷惑的高分。在这种情况下,DBCV 是首选的度量标准,因为它可以更好地处理任意形状。

参考

[1]彼得·j·鲁瑟夫(1987 年)。"轮廓:聚类分析解释和验证的图形辅助工具."计算与应用数学 20:53–65。

[2] Moulavi,Davoud 等人(2014 年)。"基于密度的聚类验证."2014 SIAM 数据挖掘国际会议论文集。工业和应用数学学会。

如何评价生存分析模型

原文:https://towardsdatascience.com/how-to-evaluate-survival-analysis-models-dd67bc10caae

生存分析中最流行的性能评估指标介绍以及实际的 Python 示例

图片作者。

目录

  1. 简介
  2. 审查
  3. 考克斯比例风险模型
  4. 评估生存模型
    4.1 和谐指数(Harrell ' s C)
    4.2Uno ' s C
    4.3动态 AUC
  5. 结论
  6. 参考文献

1。简介

生存分析包括描述事件时间数据的统计方法的集合。

它源于临床研究,医生最感兴趣的是评估一种新疗法对对照组存活率的影响,或者某些特征如何及时代表不良事件的风险。

这篇文章介绍了与生存分析(审查)相关的挑战,并解释了评估生存模型的流行指标,同时分享了实用的 Python 示例。

2。审查

让我们想象成为临床研究人员。在我们研究的开始,我们招募了所需数量的患者,并将他们分成两组:

  • 干预组接受新的治疗。
  • 对照组进行标准处理。

由于我们希望评估新治疗在预防不良事件(如死亡)方面的显著效果,因此我们对两组患者进行了一段时间的监测。不幸的是,我们可能无法观察到这一事件,原因有几个,例如:

  • 在整个研究期间,患者不会经历该事件。
  • 患者退出研究。
  • 患者失访。

这种情况被称为右删截,是生存分析研究的一个共同特征。我们可以将其与左审查区分开来,后者发生在事件已经发生在登记之前(但时间未知)。

3.Cox 比例风险模型

现在让我们介绍一种流行的生存分析算法,Cox 比例风险模型。

首先,我们将存活率定义为一段时间后没有经历不良事件(死亡)的患者的百分比。Cox 比例风险模型可以评估变量和存活率之间的关联,并被定义为:

图片作者。

该公式表明,风险函数h(t|**xᵢ**)与基线风险函数h₀(t)和相对风险exp(**β'xᵢ**)成比例。

潜在风险函数h₀(t)不依赖于协变量。由于h₀(.)的形式未指定,该模型为半参数模型。而且,不估计h₀(.)也可以估计β

Cox 模型的一个重要优势在于其系数的可解释性。为了解释它,我们可以考虑一个只有一个协变量的简化场景。让我们考虑一个危险因素xᵢ,例如吸烟,作为二元变量(0:不吸烟者对 1:吸烟者)。Cox 模型可表示为h(t|xᵢ)= h₀(t)exp(βxᵢ),其中exp(β)表示吸烟与不吸烟相比,不良事件的相对风险:

  • 吸烟带来的风险:
    (xᵢ=1): h₀(t)exp(β⋅xᵢ) = h₀(t)exp(β⋅1) = h₀(t)exp(β)
  • 不吸烟带来的风险:
    (xᵢ=0): h₀(t)exp(β⋅xᵢ) = h₀(t)exp(β⋅0) = h₀(t)
  • 相对风险=吸烟带来的风险/不吸烟带来的风险:
    h₀(t)exp(β) / h₀(t) = exp(β)

很清楚为什么这个模型在临床场景中受到高度赞赏:它允许医生根据患者的历史和行为来估计不良事件的可解释风险。

让我们用一个利用scikit-survival包的实际 Python 例子来试试,这个包在 GNU GPL 3.0 许可下可用。步骤如下:

  • 导入所需的库:
from sksurv.datasets import load_whas500
from sksurv.linear_model import CoxPHSurvivalAnalysis
from sksurv.preprocessing import OneHotEncoder
from sklearn.pipeline import Pipelineimport numpy as np
import math
from tabulate import tabulate
  • 加载并返回由scikit-survival提供的伍斯特心脏病研究数据集 ⁴:
x, y = load_whas500()
  • 该数据集有 500 个样本和 14 个特征:
x.head()

图片作者。

  • 特征:
    • afb:房颤(0:否,1:是)
    • age:入院年龄(岁)
    • av3:完全性心脏传导阻滞(0:否,1:是)
    • bmi:体重指数(kg/m )
    • chf:充血性心脏并发症(0:否,1:是)
    • cvd:心血管疾病史(0:否 1:是)
    • diasbp:初始舒张压(mmHg)
    • gender:患者性别(0:男,1:女)
    • hr:初始心率(每分钟心跳数)
    • los:住院时间(天)
    • miord : MI 顺序(0:首次,1:复发)
    • mitype : MI 类型(0:非 Q 波,1: Q 波)【1】
  • 终点是死亡,有 215 名患者死亡(43.0%):
status, counts = np.unique(
    ['Censored' if i[0] == False else 'Event' for i in y],
    return_counts = True)dict(zip(status, counts))

图片作者。

  • 创建一个包含所有必需预处理步骤的管道,并符合 Cox 模型:
pipe = Pipeline([('encode', OneHotEncoder()),
                 ('cox_model', CoxPHSurvivalAnalysis())])pipe.fit(x, y)
  • 对于每个协变量xᵢ,我们可以观察它的系数β和相对风险exp(β):
table = np.array([
   x.columns,
   pipe['cox_model'].coef_,
   [math.exp(i) for i in pipe['cox_model'].coef_]
  ]).Tprint(tabulate(table, 
               headers = ['Risk Factor', 
                          'Coefficient [β]', 
                          'Relative Risk [exp(β)]'],
               tablefmt = 'fancy_grid',
               colalign = ('center', 'center', 'center'),
               floatfmt = '.3f'))

图片作者。

相对风险exp(β)可以是:

  • >1(或β>0)为事件(死亡)的风险增加。
  • <1(或β<0)为降低风险的事件。

我们注意到:

  • 考克斯假设比例风险。这意味着预测的风险exp(β)与时间无关。
  • 在现实应用中,医生感兴趣的是相对风险及其相关的 p 值置信区间。在之前的 post⁵中,我们分享了包括这些概念的 Cox 回归模型的更详细的应用。
  • 在这种情况下,Cox 模型被用作例子来达到我们的目的,即讨论评估生存模型的度量和方法。

既然我们将模型与我们的数据进行了拟合,我们想要确定这组相对风险是否可靠。此外,我们希望将该型号与其他型号的性能进行比较。

4。评估生存模型

为了公平地评估与特定估计量相关的误差,一个好的做法是随机地将初始观察值集分成至少个:

  • 训练集:用于拟合模型的观测值子集。
  • 测试集:仅用于评估模型性能的观测值子集。

这种策略背后的想法是,使用用于拟合模型的相同数据来估计模型性能会有偏差。

训练和测试设备。图片作者。

关于评估本身,我们知道像用于定量反应(回归)的 MSE 或用于分类反应(分类)的准确性这样的度量。生存分析问题与传统的回归和分类问题略有不同。此外,由于审查,我们还有一层额外的复杂性。我们可以采用什么标准来评估模型性能?

4.1 和谐指数

让我们考虑一对病人(i, j)。直觉上,风险越高应导致不良事件发生的时间越短。因此,如果模型预测第一个患者(ηᵢ > ηⱼ)的风险评分较高,我们也预期与另一个患者(Tᵢ < Tⱼ)相比存活时间较短。

从这个直觉出发,我们将满足这个期望的每对<i, j>(ηᵢ > ηⱼ : Tᵢ < Tjηᵢ < ηⱼ : Tᵢ > Tⱼ)定义为和谐对,否则为不和谐。大量的一致配对是模型质量的证据,因为与较低风险相比,预测的较高风险对应于有效较短的存活时间。

一致指数 ⁶,也称为 C 指数哈氏 c 指数,定义为一致对数除以可比对数:

这就是审查被考虑的方式:

  • 如果两个病人ij都被审查,我们就没有关于TᵢTⱼ的信息,因此这一对被丢弃
  • 如果只有一名患者被审查,只有当另一名患者在审查时间之前经历了该事件时,我们才保留这对患者。否则,我们没有关于哪个患者可能首先经历了该事件的信息,并且该对被丢弃。

哈氏 C 的计算过程可以直观地表示如下:

图片作者。

我们现在可以表达 c 指数 as⁶:

图片作者。

其中:

  • ij识别一对患者,分别具有生存时间(TᵢTⱼ)和预测风险(ηᵢηⱼ)。
  • I(.)是指标函数,如果其参数为真,则等于 1,否则等于 0。
  • 变量Δⱼ指示Tⱼ是否已被完全观察到(Δⱼ = 1)或未被完全观察到(Δⱼ = 0)。因此,乘以Δⱼ允许丢弃不可比较的对,因为较小的存活时间被删除(Δⱼ = 0)。

让我们使用scikit-survival包在一个实际的 Python 示例中展示所描述的过程:

  • 将数据集拆分为训练集和测试集。
from sklearn.model_selection import train_test_splitx_train, x_test, y_train, y_test = train_test_split(
     x,
     y,
     test_size = 0.2,
     random_state = 42)
  • 在训练集上拟合 Cox 估计量。
pipe = Pipeline([('encode', OneHotEncoder()),
                 ('cox_model', CoxPHSurvivalAnalysis())])pipe.fit(x_train, y_train)
  • 在测试集上评估模型性能(C-index)。
c_index = pipe.score(x_test, y_test)

在我们的例子中,我们在保留数据上获得了等于 0.709 的 C 指数。

C 指数的数值解释:

  • C = 1 :风险与事件时间的完美一致
  • C = 0 :风险与事件时间的完美反协调
  • C = 0.5 : 随机赋值。该模型预测了风险和存活时间之间的关系,以及抛硬币的过程。
  • 理想值的范围在 0.5 和 1 之间。越接近 1,模型越能区分早期事件(高风险)和后期事件(低风险)。

注意事项:

  • c 指数保持着对 time⁷.的隐性依赖
  • censoring⁸.的数量越多,c 指数就变得越偏(向上)

出于这些原因,随着时间的推移,提出了 C 指数和其他指标的变化,如时间相关的 C 指数分析(Longato 等人。⁹,2020)和基于截尾权重逆概率的 c 指数(Uno 等人。⁸, 2011).

4.2 优诺的 C

对具有删截的较小观察时间(Δⱼ = 0)的观察值对的处理导致一致性 probability⁷.估计值的向上偏差因此,Uno 等人。⁸ (2011 年)提出了哈勒尔 c 的一个变体,包括审查权重的逆概率。简而言之,我们引入基于估计的截尾累积分布的权重。

在审查量较高的情况下,Uno 的 C 优于 Harrell 的 C。

scikit-survival包在sksurv.metrics.concordance_index_ipcw ⁰.实现了这个 c 统计这里有一个它的用法的例子。

值得注意的是,Uno 的 C 使用卡普兰-迈耶估计量进行截尾分布。这意味着审查应该独立于变量。然而,正如 paper⁸所说:

对于新的建议,我们假设删失分布是独立的协变量。在执行良好的临床研究中,这种假设并非不合理,尤其是当观察终点(例如,死亡或复合临床终点)时没有竞争风险,并且事件时间可能主要由于管理审查而被审查。[…].另一方面,根据我们模拟研究的结果,即使在删失依赖于协变量时,我们的建议似乎也相当稳健。

4.3 动态 AUC

在二元分类任务中, ROC 曲线(受试者工作特性曲线)绘制了不同分类阈值下的真阳性率(TPR = TP / (TP + FN))与假阳性率(FPR = FP / (FP + TN))的关系:

图片作者。

曲线下面积(AUC) 测量 ROC 曲线下的面积。简而言之,它可以被解释为模型对随机正例的排序比随机负例更高的概率。给定一个模型f,AUC 可以表示为一个威尔科克森-曼-惠特尼统计量:**

来自考尔德斯和西蒙(2007)。

在哪里

  • I(.)是指标函数(如果其参数为真,则为 1,否则为 0)。
  • D₀表示一组阴性(Class 0)观察值。
  • D₁表示一组阳性(Class 1)观察值。

在生存分析中,通过设计,真阳性率和假阳性率依赖于时间。原本健康的患者(真阴性)随着时间的推移会经历不良事件(变成真阳性)。因此,AUC 的表达变得动态。

在文献中,可以找到右删失数据的动态 AUC 估计量的不同建议:

  • 希格蒂和郑(2005)。
  • Uno 等人,⁴ (2007 年)。
  • 洪和蒋(2010)。

我们可以通过scikit-survival包:sksurv.metrics.cumulative_dynamic_auc ⁶.来实现这个度量

给定一个估计患者i的风险评分ηᵢ的模型f(xᵢ),我们可以将时间t的 AUC 定义为:

动态 AUC。来自 sci kit-⁶.生存文档

其中wᵢ代表审查权重的逆概率。

现在让我们根据之前的 Python 示例来估计不同随访时间的 AUC。

首先,我们应该考虑到wᵢ的存在需要从训练数据中估计删失分布。因此,测试集时间范围应在训练集时间范围内:

图片作者。

mins = []
maxs = []
for split in [y_train, y_test]:
  mins.append(min(split, key = lambda t: t[1])[1])
  maxs.append(max(split, key = lambda t: t[1])[1])assert mins[0] <= mins[1] < maxs[1] < maxs[0], \
 'Test set time range must be contained in the train set time range'

此外,在定义计算 AUC 的时间点时,我们还应选择最后一个时间点,以使之后被审查的概率不为零:

import matplotlib.pyplot as plt
from sksurv.metrics import cumulative_dynamic_auc
plt.style.use('ggplot')**# Times <t> at which to calculate the AUC**
va_times = np.arange(1, 1500, 30)
**# where max(<t>) is chosen arbitrarily and < of follow-up time****# Risk scores <f(xi)> on test data**
cph_risk_scores = pipe.predict(x_test)**# AUC at times <t> and its average** cph_auc, cph_mean_auc = cumulative_dynamic_auc(
  y_train, y_test, cph_risk_scores, va_times
)**# Plot the dynamic AUC**
plt.figure(figsize = (12,8))
plt.plot(va_times, cph_auc, marker = 'o')
plt.axhline(cph_mean_auc, linestyle = '--')
plt.title('Test set AUC at different time points', fontsize = 20)
plt.xlabel('Follow-up Time')
plt.ylabel('Dynamic AUC')**# Draw textbox with average AUC**
textbox = 'Average: {:.3f}'.format(cph_mean_auc)
props = dict(boxstyle = 'round', facecolor = 'wheat', alpha = 0.9)
plt.text(1100, 0.55, textbox, fontsize = 18, bbox = props)
plt.grid(True)

图片作者。

5.结论

在本文中,我们讨论了用于评估生存分析模型性能的流行指标,并使用scikit-survival包提供了 Python 中的实际例子。官方文档和参考文献提供了更多关于该主题的示例和高级信息。

6。参考文献

[1] D. R. Cox,回归模型和生命表,皇家统计学会杂志。B 系列(方法学),第 34 卷,第 2 期。,第 187-220 页,1972 年。

[2]s . pl sterl, scikit-survival:一个建立在 scikit-learn 之上的时间-事件分析库,机器学习研究杂志,第 21 卷,第 212 期,第 1–6 页,2020 ( 包网站)。

[3]https://github.com/sebp/scikit-survival/blob/master/COPYING

[4]https://sci kit-survival . readthedocs . io/en/stable/API/generated/sk surv . datasets . load _ whas 500 . html

[5]https://towards data science . com/turning-web-browsing-activity-into-product-ratings-with-survival-analysis-5d 5842 af 2 a6d

[6] F.E. Harrell Jr,R.M. Califf,D.B. Pryor,K.L. Lee,R.A. Rosati,评估医学试验的产出,Jama,247,1982 ( 链接)。

[7] M.J. Pencina,R.B. D'Agostino,总体 C 作为生存分析中的一种判别方法:模型特定人群值和置信区间估计,统计。医学。2004 年 23 日(环节)。

[8] H. Uno,T. Cai,M.J. Pencina,R.B. D'Agostino,L.J. Wei,关于使用删截生存数据评估风险预测程序总体充分性的 C 统计,Stat .医学。,30,2011 ( 链接)。

[9] E. Longato,M. Vettoretti,B. Di Camillo,对预测时间-事件模型的评估和选择的一致性指数的实用观点,生物医学信息学杂志,第 108 卷,2020 年(链接)。

[10]https://sci kit-survival . readthedocs . io/en/stable/API/generated/sk surv . metrics . concordance _ index _ ipcw . html

[11]https://sci kit-survival . readthedocs . io/en/stable/user _ guide/evaluating-survival-models . html

[12] T. Calders,J. Szymon,分类的有效 AUC 优化,载于:J.N. Kok,J. Koronacki,R. Lopez de Mantaras,S. Matwin,D. Mladeni,A. Skowron,(编辑)数据库中的知识发现:PKDD 2007 ,计算机科学讲义,柏林,海德堡,2007 ( 链接)。

[13] Heagerty,P. J .和 Y. Zheng,生存模型预测准确性和 ROC 曲线,生物统计学,61,92–105,2005。

[14] Uno,h .、T. Cai、L. Tian 和 L. J. Wei,用删失回归模型评估 t 年幸存者的预测规则,美国统计协会杂志,102,527–537,2007 年。

[15] H. Hung 和 C. T. Chiang,具有生存数据的时间相关 AUC 模型的估计方法,加拿大统计杂志,第 38 卷,第 1 期,第 8-26 页,2010 年(链接)。

[16]https://sci kit-survival . readthedocs . io/en/stable/API/generated/sk surv . metrics . cumulative _ dynamic _ AUC . html

如何解释决策树的预测

原文:https://towardsdatascience.com/how-to-explain-decision-trees-predictions-7a10834fe54d

入门

如何解释决策树的预测

我们开发了一种方法来解释为什么一个学习过的树模型为一个给定的样本选择一个特定的类,提供了 Python 中的例子

从鸢尾数据集学习的决策树模型,其中花朵被分为三种不同的鸢尾属物种:Setosa、Versicolor 和 Virginica。下面的“可视化学习模型”中解释了这个情节。

随着机器学习模型在不同的用例中变得越来越流行,例如信用风险评估系统、诊断系统甚至节能应用;解释模型决策(或预测)的需要变得更加重要。如果拒绝向客户提供信贷,银行需要向客户解释拒绝信贷的原因;如果患者被诊断患有任何疾病,需要提供该诊断的理由;最后,如果节能应用程序关闭了某个房间的供暖,房主可能想知道为什么会发生这种情况。

一些模型的预测自然比其他模型更容易解释。一方面,神经网络可能在自然语言处理和计算机视觉等几项任务中表现出色,但为了做到这一点,必须训练数百万甚至数十亿个参数,这使得解释模型的输出成为一项非常困难的任务。另一方面,线性回归或决策树等简单模型更容易理解,因此它们的预测也更容易解释。正因为如此,在许多现代系统中,这些模型仍在使用。

在本文中,我们将关注决策树,以及如何解释用于分类的(经过训练的)决策树模型的输出。在接下来的部分中,我们将快速解释决策树是如何工作的,然后我们将看到如何根据导致给定输出的决策路径来解释决策树模型生成的预测。

决策树

决策树的目标是通过学习从数据特征(X)推断的简单决策规则来学习预测目标变量的值(我们的 Y 值或类)的模型。这里的关键是,我们的模型可以被视为一个流程图,其中每个节点代表非叶节点的一个条件或叶节点的一个标签。

我们可以很容易地使用 scikit-learn 训练一个决策树,如下所示。在这个例子中,我们将使用虹膜数据集 —一个众所周知的(无聊的)数据集,通常用作 ML 的玩具示例。我们将把我们的方法应用于这个数据集,但是您可以很容易地修改代码,以应用于您选择的任何其他数据集。下面,我们首先进行必要的导入,然后加载 iris 数据集,并进行 train_test 分割,以创建一个训练集和一个测试集。然后,我们使用训练集训练决策树分类器,将叶节点的最大数量设置为 3,以提高学习模型的可解释性。这降低了我们模型的准确性,如果我们打印分数,我们会看到模型获得 0.964 的分数,而如果我们在没有“max_leaf_nodes”参数的情况下训练决策树,学习后的模型将获得 1.0 的分数(满分)——哦,我们为提高模型的可解释性所做的牺牲!尽管如此,0.964 是一个不错的分数,所以让我们继续下去。

可视化学习到的模型

我们现在可以使用 scikit-learn 中的一种简便方法来绘制我们学习到的模型。我们将首先导入 matplotlib,然后从 scikit-learn 导入名为“plot_tree”的方法。当我们调用该方法时,我们将学习到的模型作为参数发送,然后使用 Iris 数据集数据设置 feature_names 和 class_names 参数。这将把这些数据添加到图中,使它更容易理解。我们可以在下面看到代码和结果。

为我们学习的决策树模型调用 plot_tree()的结果[图片由作者提供]。

我们可以看到,不同的框按级别组织,箭头显示数据点可以遵循的路径。我们从根开始——最上面的盒子。每个框的第一行显示在该树节点中评估的条件;如果对数据点的条件的评估为真,则遵循左边的路径,否则,我们遵循右边的路径。如果一个框不包含条件,这意味着我们已经到达了一个叶子,该叶子将用框的最后一行中所示的类标签来标记数据点。

在每个节点中,我们还可以在“样本”中看到到达该节点的数据点的数量,在“值”中,我们可以看到这些样本与其类别标签相关的分布,其中每个第 I 个元素代表第 I 个类别标签的数据点的数量。此外,每个方框还显示了基尼指数:节点中“杂质”的一种度量。

解释决策树的每个预测

我们现在可以手动回答问题“为什么这个数据点被标记为 X?”通过查看数据点特征,然后沿着该数据点在学习模型中经过的路径。然而,我们可能仍然想要产生一个解释这个路径的自动文本,所以让我们这样做。

我在“了解决策树结构中采用并修改了 Scikit-learn 提供的代码,这样我们就可以打印出决策树中给定样本所遵循的路径。我们可以在下面的例子中看到代码及其输出。

Rules used to predict sample 0:
node 0, feature: petal width (cm), (actual value) 2.4 > 0.800000011920929 (threshold)
node 2, feature: petal length (cm), (actual value) 5.1 > 4.950000047683716 (threshold)
leaf reached, label: virginica

首先,我们声明一些数组,对于给定的样本,我们需要遍历决策树。这些数组中的每一个都有注释,但是如果您仍然不确定其中任何一个的含义,您可以查看 scikit-learn 文章以获得更详细的解释。其次,我们声明样本 id(由它在 X_test 数组中的位置给出)并获得样本的决策路径。

然后,我们迭代路径中包含的所有节点:对于分裂节点(或非叶节点),我们打印节点的编号、条件中使用的特征、给定样本的该特征的值以及阈值,显示样本的值是大于“>”还是小于或等于“=

In the output we see a (somewhat rustic) explanation of why our model has predicted a certain label for the given sample: the petal width is greater than 0.8 and the petal length is greater than 4.95, which our tree model has learned to classify as virginica based on the samples included in the train set. If we check the tree plot, we see that a vast majority of the train samples that meet these conditions are indeed virginica, which explains the label predicted by our model.

Conclusion

We have managed to provide a rustic explanation to a decision trees’ predictions. With this, we aim to improve the trust in our model because any person can now see why a sample was given a certain label or class by our model. We have to keep in mind that we need to use decision trees for this approach to work, which can condemn the performance of our model. In a future article, we will see how we can use other tools such as Shapley values to explain other models different than decision trees.

Where to go from here

  • ”。了解决策树结构— Scikit-learn
    如果你想更深入地了解 scikit-learn 决策树,你可以阅读这篇非常有趣的文章。
  • 如果你对可解释的 ML(或可解释的 AI)感兴趣,你可能会对这本书感兴趣,这本书以实用的方式解释了如何使用 Python 实现可解释的模型。

如何用石灰解释图像分类器

原文:https://towardsdatascience.com/how-to-explain-image-classifiers-using-lime-e364097335b4

学习如何应用流行的可解释人工智能(XAI)方法来解释图像分类器

用石灰解释图像(作者提供的图像)

局部可解释模型不可知解释(LIME) 是最流行的可解释 AI (XAI) 方法之一,用于解释机器学习和深度学习模型的工作。LIME 可以为解决回归和分类问题提供模型不可知的局部解释,它可以应用于结构化数据集,甚至可以应用于文本和图像等非结构化数据集。在本文中,您将更深入地了解如何使用 LIME 来解释基于深度学习的图像分类器以及代码演练。

如果你对 XAI 概念不太熟悉,我强烈推荐你观看过去在 2021 年 APAC 人工智能加速器节上发表的关于 XAI 的演讲:

你也可以浏览我的书 应用机器学习可解释技术 并看看代码库以获得对其他 XAI 方法的实际接触。在本文中,我将参考《应用机器学习可解释技术》https://amzn.to/3cY4c2h一书中提供的 LIME 在图像分类器中的实际应用。

**https://www.amazon.com/Applied-Machine-Learning-Explainability-Techniques/dp/1803246154?_encoding=UTF8&pd_rd_w=Wr6SJ&content-id=amzn1.sym.716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_p=716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_r=6P2PM599T97MRG7NZD9J&pd_rd_wg=m4qUW&pd_rd_r=6e349d93-5ba0-4bfe-9055-905c0153fe58&linkCode=li3&tag=adib0073-20&linkId=35506e1847de5c011fc57aa66c2b1d8e&language=en_US&ref_=as_li_ss_il

如果你想得到关于这本书的详细反馈,这个视频可能对你有用:

现在,让我们开始吧!

将石灰应用于图像分类器

使用传统的要素重要性方法和其他框架,如莱姆和 SHAP,解释表格数据集仍然很容易。然而,主要的挑战总是在解释基于图像等非结构化数据训练的复杂深度学习模型时出现。

通常,深度学习模型在图像数据上比传统的 ML 模型更有效,因为这些模型具有执行自动特征提取的能力。它们可以提取复杂的低级特征,如条纹、边缘、轮廓、拐角和图案,甚至更高级的特征,如较大的形状和物体的某些部分。这些高级特征通常被称为图像中的感兴趣区域(RoI) ,或超像素,因为它们是图像中覆盖图像特定区域的像素集合。

现在,低级特征不是人类可解释的,但是高级特征是人类可解释的,因为任何非技术终端用户都将关于高级特征来联系图像。石灰也以类似的方式工作。该算法试图突出显示图像中对模型决策过程有积极或消极影响的超像素。那么,让我们看看如何使用 LIME 来解释图像分类器。

https://www.amazon.com/Applied-Machine-Learning-Explainability-Techniques/dp/1803246154?_encoding=UTF8&pd_rd_w=Wr6SJ&content-id=amzn1.sym.716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_p=716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_r=6P2PM599T97MRG7NZD9J&pd_rd_wg=m4qUW&pd_rd_r=6e349d93-5ba0-4bfe-9055-905c0153fe58&linkCode=li3&tag=adib0073-20&linkId=35506e1847de5c011fc57aa66c2b1d8e&language=en_US&ref_=as_li_ss_il

设置所需的 Python 模块

在我们开始代码演练之前,请检查代码库中提供的笔记本。笔记本包含实际应用这些概念所需的必要细节。在这一节中,我将向您演示代码,并解释笔记本教程中涵盖的所有步骤。如果尚未安装 Python 库的升级版本,请使用以下命令进行安装:

**!**pip install --upgrade pandas numpy matplotlib seaborn tensorflow lime scikit-image

导入 Python Jupyter 笔记本中已安装的模块

**import** warnings
warnings**.**filterwarnings("ignore")
**import** os
os**.**environ['TF_CPP_MIN_LOG_LEVEL'] **=** '3'

**import** numpy **as** np
**import** matplotlib.pyplot **as** plt
**import** matplotlib.cm **as** c_map
**from** IPython.display **import** Image, display
**import** tensorflow **as** tf
**from** tensorflow **import** keras
**from** tensorflow.keras.applications.xception **import** Xception, preprocess_input, decode_predictions
**from** tensorflow.keras.preprocessing **import** image

**import** lime
**from** lime **import** lime_image
**from** lime **import** submodular_pick

**from** skimage.segmentation **import** mark_boundaries

np**.**random**.**seed(123)

您可以打印安装在您的设置中的 tensorflow 版本。

print(f" Version of tensorflow used: {tf**.**__version__}")Version of tensorflow used: 2.3.1

加载数据

因为我们更感兴趣的是检查如何使用 LIME 解释黑盒图像分类器,所以我们将只关注推理部分。让我们加载任何通用的图像数据。对于这个例子,我们将从这个来源获取数据:https://unsplash.com/photos/GBDkr3k96DE

**def** load_image_data_from_url(url):
    '''
    Function to load image data from online
    '''
    *# The local path to our target image*
    image_path **=** keras**.**utils**.**get_file(
    "shark.jpg", url
    )

    display(Image(image_path))
    **return** image_path

image_path **=** load_image_data_from_url(url **=** "[https://images.unsplash.com/photo-1560275619-4662e36fa65c?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1200&q=80](https://images.unsplash.com/photo-1560275619-4662e36fa65c?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1200&q=80)")

图片来源—Unsplash—https://unsplash.com/photos/GBDkr3k96DE

我们将对图像进行一些初始数据预处理。

IMG_SIZE **=** (299, 299)
**def** transform_image(image_path, size):
    '''
    Function to transform an image to normalized numpy array
    '''
    img **=** image**.**load_img(image_path, target_size**=**size)
    img **=** image**.**img_to_array(img)*# Transforming the image to get the shape as [channel, height, width]*
    img **=** np**.**expand_dims(img, axis**=**0) *# Adding dimension to convert array into a batch of size (1,299,299,3)*
    img **=** img**/**255.0 *# normalizing the image to keep within the range of 0.0 to 1.0*

    **return** img

normalized_img **=** transform_image(image_path, IMG_SIZE)

使用预先训练的张量流模型作为我们的黑盒模型

对于本教程,我们使用预训练的 TensorFlow Keras 异常模型作为我们的黑盒模型。该模型在 ImageNet 数据集(https://www.image-net.org/)上进行预训练,这是最流行的图像分类基准数据集之一。预训练模型可以加载以下代码行:

from tensorflow.keras.applications.xception import Xceptionmodel = Xception(weights="imagenet")

现在让我们使用预训练的 XceptionNet 模型来生成预测。

**def** get_model_predictions(data):
    model_prediction **=** model**.**predict(data)
    print(f"The predicted class is : {decode_predictions(model_prediction, top**=**1)[0][0][1]}")
    **return** decode_predictions(model_prediction, top**=**1)[0][0][1]

plt**.**imshow(normalized_img[0])
pred_orig **=** get_model_predictions(normalized_img)

这将预测以下输出:

The predicted class is : tiger_shark

图像被预测为虎鲨,这是正确的预测,并且黑盒模型能够成功地给出正确的预测。现在,让我们看看前 5 个预测以及模型置信度。

model_prediction **=** model**.**predict(normalized_img)
top5_pred **=** decode_predictions(model_prediction, top**=**5)[0]
**for** pred **in** top5_pred:
    print(pred[1])

该模型生成的前 5 个预测是:

tiger_shark
great_white_shark
hammerhead
scuba_diver
sturgeon

正如我们所看到的,尽管该模型被很好地训练以产生正确的预测,但该模型有可能不只是查看图像中的主要对象,而是查看周围的背景。这一点从水肺 _ 驾驶员出现在前 5 预测列表的预测中可见一斑。因此,理解模型用来进行预测的图像的关键组件或部分对我们来说很重要。

https://www.amazon.com/Applied-Machine-Learning-Explainability-Techniques/dp/1803246154?_encoding=UTF8&pd_rd_w=Wr6SJ&content-id=amzn1.sym.716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_p=716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_r=6P2PM599T97MRG7NZD9J&pd_rd_wg=m4qUW&pd_rd_r=6e349d93-5ba0-4bfe-9055-905c0153fe58&linkCode=li3&tag=adib0073-20&linkId=35506e1847de5c011fc57aa66c2b1d8e&language=en_US&ref_=as_li_ss_il

用石灰解释模型

在本小节中,我们将了解如何使用 LIME 框架从模型使用的图像中识别超像素或区域,以预测具体结果。我们首先需要定义一个图像解释器对象:

explainer **=** lime_image**.**LimeImageExplainer()

接下来,我们需要将推断数据(normalized_img[0])传递给 explainer 对象,并使用 LIME 框架来突出显示对模型预测有最大积极和消极影响的超像素:

exp **=** explainer**.**explain_instance(normalized_img[0], 
                                 model**.**predict, 
                                 top_labels**=**5, 
                                 hide_color**=**0, 
                                 num_samples**=**1000)

我们的 explainer 对象已经准备好了,但是让我们来可视化由 LIME 算法创建的各种解释片段。

plt**.**imshow(exp**.**segments)
plt**.**axis('off')
plt**.**show()

由 LIME 生成的热图图像对我们推断的 sharp 图像(图片由作者提供)

现在,让我们使用顶部片段或超级像素来识别模型用来进行预测的图像的感兴趣区域。

**def** generate_prediction_sample(exp, exp_class, weight **=** 0.1, show_positive **=** **True**, hide_background **=** **True**):
    '''
    Method to display and highlight super-pixels used by the black-box model to make predictions
    '''
    image, mask **=** exp**.**get_image_and_mask(exp_class, 
                                         positive_only**=**show_positive, 
                                         num_features**=**6, 
                                         hide_rest**=**hide_background,
                                         min_weight**=**weight
                                        )
    plt**.**imshow(mark_boundaries(image, mask))
    plt**.**axis('off')
    plt**.**show()generate_prediction_sample(exp, exp**.**top_labels[0], show_positive **=** **True**, hide_background **=** **True**)

LIME 拾取的最重要的超级像素预测输出为虎鲨(图片由作者提供)

从上图中我们可以看到,模型能够识别正确的区域,这表明模型对结果的预测是正确的。

generate_prediction_sample(exp, exp**.**top_labels[0], show_positive **=** **True**, hide_background **=** **False**)

由 LIME 拾取的最重要的超像素,用于预测输出,如带有背景图像的虎鲨(图片由作者提供)

正如我们从前面的图像中看到的,我们也可以只突出超像素的轮廓,并包括背景。但是我们也可以突出正超像素和负超像素。

generate_prediction_sample(exp, exp**.**top_labels[0], show_positive **=** **False**, hide_background **=** **False**)

由 LIME 拾取的最重要的超像素预测输出为虎鲨,背景图像和绿色覆盖突出显示正面区域(作者提供的图像)

上述示例向我们展示了如何隐藏或显示背景以及超像素,甚至勾勒或突出显示超像素,以识别模型用于进行预测的感兴趣区域。我们从这里看到的确实有意义,也确实让我们增加了对黑盒模型的信任。我们还可以形成一个热图来显示每个超像素对于获得更精细的解释能力有多重要。

**def** explanation_heatmap(exp, exp_class):
    '''
    Using heat-map to highlight the importance of each super-pixel for the model prediction
    '''
    dict_heatmap **=** dict(exp**.**local_exp[exp_class])
    heatmap **=** np**.**vectorize(dict_heatmap**.**get)(exp**.**segments) 
    plt**.**imshow(heatmap, cmap **=** 'RdBu', vmin  **=** **-**heatmap**.**max(), vmax **=** heatmap**.**max())
    plt**.**colorbar()
    plt**.**show()

explanation_heatmap(exp, exp**.**top_labels[0])

使用石灰的解释热图(图片由作者提供)

https://www.amazon.com/Applied-Machine-Learning-Explainability-Techniques/dp/1803246154?_encoding=UTF8&pd_rd_w=Wr6SJ&content-id=amzn1.sym.716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_p=716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_r=6P2PM599T97MRG7NZD9J&pd_rd_wg=m4qUW&pd_rd_r=6e349d93-5ba0-4bfe-9055-905c0153fe58&linkCode=li3&tag=adib0073-20&linkId=35506e1847de5c011fc57aa66c2b1d8e&language=en_US&ref_=as_li_ss_il

摘要

正如我们在本笔记中清楚看到的,LIME 可以轻松地用于解释图像分类器。下次,每当你致力于训练深度学习模型来对图像进行分类时,我会强烈建议你尝试用 LIME 来解释你的模型,并了解模型是否正在研究图像的正确区域,以做出最终预测!如果你喜欢这篇文章,并想了解更多关于如何应用 LIME 来解释 ML 模型的信息,我推荐阅读这本书: 【应用机器学习可解释技术】 并探索 GitHub 资源库以获得实际操作的代码示例。

作者关于 TDS 的其他 XAI 相关文章:

  1. 用于在文本数据上训练的模型的可解释机器学习:将 SHAP 与变压器模型相结合
  2. EUCA——一个有效的 XAI 框架,让人工智能更贴近终端用户
  3. 理解可解释人工智能中使用的 SHAP 和沙普利值的工作原理

https://www.amazon.com/Applied-Machine-Learning-Explainability-Techniques/dp/1803246154?_encoding=UTF8&pd_rd_w=Wr6SJ&content-id=amzn1.sym.716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_p=716a1ed9-074f-4780-9325-0019fece3c64&pf_rd_r=6P2PM599T97MRG7NZD9J&pd_rd_wg=m4qUW&pd_rd_r=6e349d93-5ba0-4bfe-9055-905c0153fe58&linkCode=li3&tag=adib0073-20&linkId=35506e1847de5c011fc57aa66c2b1d8e&language=en_US&ref_=as_li_ss_il

参考

  1. GitHub 中的 LIME 开源 Python 框架—https://github.com/marcotcr/lime
  2. 应用机器学习解释技术
  3. GitHub repo 自《应用机器学习可解释技术》——https://GitHub . com/packt publishing/Applied-Machine-Learning-explability-Techniques/**

如何用图论探索图像数据集

原文:https://towardsdatascience.com/how-to-explore-a-dataset-of-images-with-graph-theory-fd339c696d99

组合特征提取、相似性度量和最近邻图

k-最近邻图示例(图片由作者提供)

当你开始处理一个由图片组成的数据集时,你可能会被问到这样的问题:你能检查图片是否好吗?有什么异常吗?一个快速而简单的解决方案是手动逐个查看数据,并尝试对它们进行分类,但这可能是一项繁琐的工作,具体取决于您获得的图片数量。

例如,在制造业中,您可以从由不同类型和大小的电池组成的生产线上获得包含数千张图片的样本。你必须手动浏览所有图片,并按照类型、大小甚至颜色进行排列。

另一方面,另一个更有效的选择是走计算机视觉路线,找到一种可以自动排列和分类图像的算法——这是本文的目标。

但是我们怎样才能自动完成一个人的工作,也就是说,两个两个地互相比较图片,并根据相似性进行分类?这个问题没有统一的答案。尽管如此,我们可以将问题分成更容易的子问题,并逐一解决它们:从每幅图像中提取相关特征,定义特征之间的相似性度量,并根据相似性对它们进行排序。

为了解决每个子问题,我们将在本文中使用以下方法:

  1. 方向梯度直方图(HOG)提取特征
  2. 测量直方图之间相似性的 Wasserstein 距离
  3. K-最近邻图(K-NNG ),以便根据相似性对图像进行排序

方向梯度直方图

任何计算机视觉问题的第一步都是从图片中提取有用的特征。在我们的例子中,我们希望比较图像,并根据相似性对它们进行排序。所以我们希望我们的特征能够区分相似和不太相似的图像。目标检测中经常使用的一个特征是梯度方向直方图(HOG)。

HOG 特征是将图像表示为矢量,其中矢量中的每个元素都是定向梯度的直方图。推荐阅读这篇文章了解 HOG 算法的工作原理。

为了从图像中提取 hog 特征,我们可以使用 Scikit-image 库中的 HOG()函数。以下是在黑白图片上提取的渐变的视觉示例:

方向梯度直方图示例

既然我们已经从图像中提取了特征,我们需要定义这些特征之间的相似性度量。机器学习中常用的相似性度量是欧几里德距离,但是在我们的例子中,我们将使用 Wasserstein 度量来给出两个分布之间的距离度量。

瓦瑟斯坦距离

Wasserstein 度量,也称为推土机距离,是两个概率分布之间的距离度量。它基于测量将一种分布转换成另一种分布所需的“工作量”的思想。

Wasserstein 距离示例(图片由作者提供)

使用 Wasserstein 度量标准有很多原因。一个原因是它是概率度量空间中一个非常自然的度量。这是一个非常通用的指标,可以用来比较不一定相同的分布。

寻找特征向量之间的良好距离度量是许多机器学习算法的基本步骤。在我们的例子中,Wasserstein 度量测量两个直方图之间的距离,因此提供了两个图片之间的相似性度量。

HOG 从图片中提取特征,Wasserstein 度量提供每个特征之间的距离。下一步是绘制数据并探索数据集。对于这个任务,k-最近邻图因其简单性和可解释性而成为自然的选择。

K-最近邻图(K-NNG)

简单地说,K-最近邻图是每个节点都与其 K 个最近邻相连的图。K-NNG 有助于发现数据中的模式。例如,如果您有一个人的身高和体重的数据集,您可以使用 K-最近邻图来找出数据中是否有任何模式。

对于我们的最后一个例子,我创建了自己的玩具数据集,其中有一个杯子的 500 张照片,有几种位置和旋转。

具有不同位置和旋转的杯子数据集(图片由作者提供)

为了发现数据的全局结构,我们可以使用流形学习,例如 t-分布式随机邻居嵌入(t-SNE)来将 HOG 描述符的维度降低到仅二维。

通过这种布局,我们获得了一个分隔节点的图,如下图所示。

30-cup 数据集的最近邻图(图片由作者提供)

我们可以用这种方法轻松地分离不同类型的数据,但我们也可以探索数据集的底层结构。对于杯子的例子,我们能够区分五个水平位置,也能够区分杯子在图片中的旋转。

第一个位置的编码旋转(图片由作者提供)

结论

HOG 特征是一个强大的特征描述符,可用于各种计算机视觉应用。然而,它也是一个高维特征向量,可能很难处理。

然而,我们使用 Wasserstein 度量来计算每个直方图之间的距离,这在计算上是昂贵的,但是在比较两个分布时是自然的选择。

为了改进这种方法,我们可以降低 HOG 特征的维度。例如,我们可以使用更少数量的箱、更粗糙的宁滨方案或更小范围的值,但我们将在另一篇文章中讨论这一点。

最后,通过 K 近邻图,我们了解数据。这包括理解数据代表什么以及数据集的整体结构,这是迭代和细化探索性分析的良好起点。

好奇想了解更多关于 Anthony 的工作和项目吗?在媒体LinkedInTwitter 上关注他。

需要技术写手?将您的请求发送到https://amigo CCI . io

作为高中生如何探索机器学习和自然语言处理

原文:https://towardsdatascience.com/how-to-explore-machine-learning-and-natural-language-processing-as-a-high-school-student-d66b3685c186

从一个女孩到另一个女孩的简单、现实的指南

法比奥Unsplash 上的照片

那里有!你喜欢破译语言的细微差别,思考创造性的写作作品,并为你的校报制作突发新闻故事吗?但是,也许与此同时,在 5 月份的 AP 计算机科学考试后,你是否被所有可以用字符串做的时髦事情迷住了?

伙计,你让我想起了我自己!如果你在这里发现,哇——有一个应用计算机科学和语言的跨学科领域(咳咳,语言的计算分析),但所有在线指南要么是面向成年人的,要么只是为了一些探索目的而过于吓人——那么,这个指南对你来说是完美的!

到最后,你将对机器学习和自然语言处理有一个很好的总体看法,包括关键概念以及为什么它们在只有高中生背景的今天如此重要。至于有形的产品,你会带着一个小的迷你项目离开,然后你可以将这些知识应用到你未来的努力中去!

附:我向你保证,你对本指南了解得越多,它就越有趣。(结尾有拼图!)开头可能是一阵熟悉这个,熟悉那个的猛攻(希望我听起来不要太像 Google-Translate 阅读干巴巴的垃圾邮件哈哈),所以如果你睡着了我不怪你,但是你得到了这个!这是值得的!

目录

介绍

现在,在我开始之前,我想做一个免责声明:如果你在这里希望成为机器学习(ML)和自然语言处理(NLP)的专家,这本指南不适合你。本指南旨在帮助高中生任何其他好奇的灵魂,他们真正对这个迷人的领域感兴趣,并喜欢的起点来探索该领域中一些实际操作的可接近的行动项目,即使你没有研究或大学/行业导师来指导你。(事实上,如果你真的完成了这个指南,我认为这是一个很好的方式来证明你对 ML 和 NLP 的兴趣,当你申请暑期研究项目的时候,这些项目确实需要这个领域的背景知识!)

TL;DR——考虑到高中生在教育水平和时间方面的常见障碍(包括之前没有研究/项目经验),我构建了这个指南,因此我做出了一些适用于我和我认识的许多人的概括;当然,也有很多例外(事实上,我知道这么多令人惊讶的先进、有才华、谦逊的同学),但我希望这个指南对所有人都是可及的,无论起始水平如何。

说完了,我们来探索一下吧!

先决条件

尽管(从任何专业水平的角度来看)掌握微积分、线性代数和其他基础知识是理想的,但任何正在经历或已经经历过美国教育系统的人都可能会注意到:

  • 数学局限性:大多数人直到大三或大四才开始学习微积分(对于那些特别有抱负的人来说是大一或大二),这意味着现实地说,一个好奇的 14 岁孩子可能很难通过购买线性代数教科书并试图理解基础知识来探索某个领域,因为他们甚至没有在学校完成代数 2 荣誉课程(Calc 预科的先决条件)。
  • 时间&优先事项:学生们有很多事情要做,无论是音乐、体育、艺术、舞蹈、俱乐部、本地辅导还是其他兴趣,所以时间是最重要的。

因此,这些先决条件是意识到上面的两个警告,同时如果你真的对这个领域着迷,也让探索变得超级有趣。(如果您已经了解基本的 Python,请随意跳过这一步!)

1。学习基础编程…

…在任何方便的地方,无论是在学校还是在网上(APCS、暑期社区学院、Udemy、Edx 等)。这部分是不可避免的,但不是不可能!

如果你和我一样,在参加了 AP 计算机科学 A 考试或暑期社区大学(T2)Java I 课程(T3)后才知道 ML,那就太好了!对类、函数、数组和基本编程有了很好的了解,你已经为这个先决条件设置好了,可以直接跳到第 2 步了!

即使你没有,也不要担心;考虑到许多学生在大二就完成了 APCS,这并不是一个很大的挑战。如果你需要从某个地方开始,艾萨克·莱曼有趣地写了当你读完这本书,你将学会如何编码是一个很好的切入点。从那里,在网上找一个简单的 Python 课程https://www.edx.org/course/introduction-to-computer-science-and-programming-7或者在你当地的社区大学注册一个学期来打下基础。****

我将继续假设你在高中时已经学过《计算机科学导论》或《APCS》中的 Java,这是学生们非常普遍的基础。

2。为数据科学学习 Python

现在有了编程(可能是 Java)作为基础,Python,一种创建 ML 项目的基本语言,将变得更加容易掌握!

这个 网站 是麻省理工学院为高中生开设的 Beaver Works 暑期学院 ,专门关注“[类似 Python 的]数据分析、机器学习、数值计算等 STEM 应用”,是一个完美的资源。仅仅通读的前两个模块就会以一种易于理解的格式给你一个足够坚实的语言理解,而不会强迫你理解与 ML 无关的概念。****

额外:如果你想更进一步,你还可以通过 BWSI 网站 报名参加他们相应的课程,进行选择题和练习题,还有机会参加他们大三的暑期项目!(课程对我来说是一个很好的学习机会,虽然我最终因为和另一个项目冲突而没有去参加他们的Cog * Works*夏令营;有兴趣的话可以去看看!)*

3。熟悉这些特定的库

有了 ML 和 NLP,事先理解 熊猫 库,让你轻松操作数据,是非常有帮助的。这个 YouTube 系列 很好地总结了这一点(尽管如果你真的没有时间,你可以跳过这一步,稍后花更多的时间去探索。)阅读一些关于图形的内容( matplotlib,seaborn ),你可以通过简单的谷歌搜索很容易地找到这些内容,这也会使体验变得有趣得多。

4.保持好奇!

可以说,从现在开始最重要的先决条件是好奇的心态;没有什么比简单的愿意挖掘和学习更重要的了。假设你已经有了相当于 APCS 的背景知识,以上可以在一周内完成如果你决定雄心勃勃;我故意这样做,因为我完全理解繁忙的高中生活方式的限制!

因此,正如我将在下面详细阐述的那样,作为一名高中生,你最终可能会发现的很多东西不是来自课程,而是来自你自己对 Stack Overflow、YouTube 和 Google 的挖掘。那样你真的会学得更深刻。准备好了?请继续阅读!

快速阅读和软件安装

有很多很棒的课程,比如吴恩达著名的斯坦福 ML 课程,所以如果这是你的学习方法,那就去吧!但是我希望这篇特别的文章成为一个探索指南,你可以相对快速地完成来评估你对这个领域的兴趣也许完成一个迷你项目,而不是正式潜入这个领域我提倡一种更实际的、把你扔进大海的方法。如果你觉得下面的资源很有趣,并且想花更多的时间,那么尽一切办法,参加所有在线的开源课程吧!但是,这里有一个方法可以让你了解一些背景知识就可以做的很酷的事情。

1。今天阅读关于 ML 和 NLP 的影响:

有点乱?我知道,我知道。我们都想直接进入项目时间,但在我看来,开始一件事最重要的因素不仅仅是决定你将做什么,而是决定你为什么要做。因此,探索以下网站会让你对现实世界的影响有更深的理解。(嘿,这是一种激励,为什么不呢?)

  • SpeechTek 杂志 :天哪,我简直无法抑制自己的激动!没有更好的方法来了解自然语言处理在当今世界可以做的所有史诗般的事情,从帮助医生到提高营销策略的效率和为世界各地的残疾人提供访问,然后这是所有最新的,突破性的自然语言处理技术的最新汇编。在我偶然发现这本书的那一刻,我无法停止阅读几个小时,鉴于我的记者心态(我们确实做了很多调查),我真的希望它对你有同样的影响。
  • Google:这是不是不言自明,完全没必要写下来?是的。我还在这里推广吗?是啊!如果 SpeechTek Mag 对你来说不是动力,那就去做一些你自己的研究,看看为什么 NLP 是如此重要!这将是一个疯狂的旅程,但完全值得。

可以说,从现在开始最重要的先决条件是一种好奇的心态;没有什么比简单的愿意挖掘和学习更重要的了。

2.ML 和 NLP 中的概念概述

撇开女学生的兴奋不谈,现在你已经准备好出发了,这里有一些读物可以让你对 ML 和 NLP 有一个简单易懂的概述,包括技术术语、管道和其他必要的工具。(最多 30 分钟,还没编码!)

A)ML 概述:

  • 机器学习,由麻省理工学院斯隆解释的 ,给出了 ML 是什么,ML 的三个子类别(监督、非监督、强化学习),其他 AI 子领域,及其适用性的大图。
  • ML For Dummies ,它确切地解释了 ML 在下面是如何工作的,更详细地解释了三个子类别、关键术语(即培训/验证/测试)和潜在偏差。

B)自然语言处理概述:

  • 什么是自然语言处理? 快速、概念性地了解 NLP 是什么以及如何使用它。
  • 温和开始使用 Python 进行自然语言处理 由 Rahil Shaikh。这篇文章非常简单地介绍了 NLP &如何使用代码来实现上一篇文章中的想法。您现在还不需要编写任何代码。(我们将在下一节中介绍这一点。)只是阅读作为一个开始!
  • 额外:速成计算语言学 如果你是伴随着约翰·格林的速成历史视频长大的,你很幸运!这是我在他们的语言学系列中发现的一个有趣的计算语言学视频,如果你想怀旧和吸收知识的话!

3.软件安装

现在,随着大部分概念性的大图阅读的进行,是时候安装您将使用的实际环境了。

  • 选项 1: 安装 Jupyter Notebook 一个用于创建简单、交互代码的 web 应用(比通常枯燥的 IDE 有趣多了)。你可以随时在本地使用它,这意味着你不必连接到互联网!安装和学习使用 jupyter 笔记本,参考
  • 方案二: 使用 Google Colab Google 的一款基于云的 Jupyter 笔记本,让你和别人分享你的代码变得超级简单,就像分享一个 google doc 一样。要学习如何使用 Google Colab,参考 这个

项目时间!(自然语言处理和毫升)

还和我在一起吗?去你的和你史诗般的注意力跨度!

可以说,本探索指南最令人兴奋的部分是有机会接触一些有趣的开始代码和等待它…迷你项目!等待结束了。我们出发了。

1。通过工作的基线编码指南

Ventsislav Yordanov 已经创建了一个绝对非凡的、易于理解的系列文章,它将带您浏览 NLP 管道各个方面的概念,从探索性分析到预处理,以及实际的代码。我强烈推荐你按照以下顺序,通过自己的努力来学习这些简单、巧妙的指南:

2。全面的 NLP 项目

几乎没有任何一个系列能比这个精彩的开源 系列的五个视频讲座 得到我更多的赞扬,这些讲座来自编写代码的女性以及她们相应的 开源项目代码、幻灯片和资源 ,它们带你经历创建 NLP 项目的整个过程,从 NLP 概念和工作流的基本介绍到探索性分析、预处理、各种方法的详细分步过程****

什么?是的,你没听错。

在 YouTube 上找到这个就像我是一个在圣帕特里克节中了大奖的小妖精,意识到我找到的不仅仅是一罐金币,而是一大罐永不枯竭的麻辣火锅。(Whaaat?如果你被困在一个岛上,火锅会更好。)但是我跑题了…如果你想创建一个有指导的迷你项目,几乎没有比这个坏男孩更好的交易了。

TL;博士?让我再次链接 视频代码 来强调我发现这个资源有多棒!(获胜的被动攻击性>:))

3。更多 ML 导轨

如果你在#2 之后仍然渴望另一种味道,这里的https://machinelearningmastery.com/machine-learning-in-python-step-by-step/这里的这里的 是一些额外的指南和资源,在那里你可以用开放库中可用的数据集来处理一些项目。网上也有很多,所以尽一切办法去寻宝吧!让你想起一个重复出现的主题?********

可以说,从现在开始最重要的先决条件是一种好奇的心态;没有什么比愿意去挖掘和学习更重要的了。

北美计算语言学公开赛(前奥林匹克)

耶,你完成了你的第一个项目!现在,作为一个主要针对高中生的探索性指南,不提到美国官方奥林匹克竞赛之一的北美计算语言学公开赛(【NACLO)(与 AMC 的数学竞赛、USACO 的计算机科学竞赛等一起)是不完整的。)—只不过这次奥林匹克竞赛专门关注语言学难题,重点是计算语言学!****

NACLO 最突出的一点是,它像其他奥林匹克竞赛一样专门针对高中生,所以他们认为你对计算机科学或语言学一无所知(作为 NACLO 半决赛选手,我可以证明这一点;我在没有任何背景知识的情况下完成了他们的拼图。)换句话说,你可以纯粹地使用逻辑来解决他们的难题,同时发现关于 NLP 的迷人之处。以下是我最喜欢的几个关于自然语言处理和机器学习的例子:

另外,如果你感兴趣, NACLO 也有许多关于语言学领域本身的谜题,他们每年 1 月下旬都会举办一场比赛,高中生可以免费报名。美国和加拿大前 10%的选手有资格参加邀请赛,如果你在那里表现出色呢?你可以参加国际语言学奥林匹克竞赛!

布雷特·加伍德在 Unsplash 上拍摄的照片

其他资源

恭喜你坚持到最后!

在我结束这篇探索性指南之前,如果你想更深入,我完全推荐 这篇这篇 指南,作者是其他才华横溢的高中生,他们有一些非常好的建议,告诉你如何在中学阶段就开始学习 AI/ML(我个人不认识这些人,但我过去曾在网上参考过他们的文章,因为我自己也试图学习更多关于这个领域的知识。)

结论

我在自己尝试自己的项目以及与圣克鲁斯大学科学实习项目(UCSC SIP,强烈推荐)相结合的过程中,在网上找到了上述所有资源。)因为我喜欢探索和挖掘,它把我带到了难以想象的令人敬畏的地方。从 YouTube 行业深度挖掘到其他高中生创建的关于如何学习的惊人资源,可能性是无穷无尽的——对于十几岁的青少年来说,这是完全可以实现的!(看到那里的头韵了吗?)

你还在等什么?去探索一下,让我知道进展如何!如果你想更多地了解我是谁,请在这里阅读一些关于我的信息https://goofyseal.medium.com/hey-there-welcome-to-my-blog-ae3eb5de2324或者在这里联系我https://www.carolynwang.co/。最后,如果你有任何反馈或建议,我希望在评论中听到它们!❤********

最后一件事:我在本指南中提供的资源都是开源的,可以在网上找到,对我帮助很大。我与他们中的任何人都没有关系,也没有声称对他们的工作居功。继续探索!

可以说,从现在开始最重要的先决条件是一种好奇的心态;没有什么比愿意去挖掘和学习更重要的了。

呵呵,我真的很喜欢这句格言,嗯?

如何从 PDF 文件提取表格并将其转换为 Pandas 数据框架

原文:https://towardsdatascience.com/how-to-extract-and-convert-tables-from-pdf-files-to-pandas-dataframe-cb2e4c596fa8

因此,您有一些包含表格的 pdf 文件,并希望将它们读入熊猫数据框。让我告诉你怎么做。

约翰内斯·格罗尔在 Unsplash 上的照片

设置

出于本文的目的,我们将从英国住房协会于 12 月 2 日发布的住房统计文件中提取表格。pdf 文件的副本可以在这里找到。

我们将使用 tabula-py 库从 pdf 文件中提取表格。运行pip install tabula-py进行安装

确保您的系统中安装了 Java。如果遇到任何安装错误,请参考库的文档。

好了,我们都准备好撤离了!😎

Tabula:将 Pdf 表格提取到数据框

现在假设感兴趣的 pdf 文件在同一个工作目录中,让我们尝试从中提取表格。要做到这一点,我们需要做的是:

使用 Tabula 从 pdf 文件中读取表格的 Python 代码。(来源:作者)

如您所见,代码非常简单,不言自明。该代码为提取的每个单独的表返回 pandas 数据框的列表。

您可以通过运行len(tables)快速查看提取的表的数量,对于这个例子,T1 应该返回9。如果您看一下本文使用的 pdf 文件,整个文档中有 9 个表格。

现在,我们要做的就是对列表进行索引,将每个表作为一个数据框。例如,tables[0]应该返回第一个表,tables[1]应该返回第二个表。

使用 tables[0]从 pdf 文件中提取的第一个表格。(来源:作者)

从 pdf 文件中提取的第一个表格的实际版本。(来源:作者)

使用表[1]从 pdf 文件中提取的第二个表。(来源:作者)

从 pdf 文件中提取的第二个表格的实际版本。(来源:作者)

记住

从上面两个提取表格的例子可以看出,tabula 库在从 pdf 中提取表格方面做得非常好。但是,它并不总是干净和精确的。有时,我们必须进行一些手动清洁,以:

  • 更正表格的标题
  • 删除不必要的行和列
  • 拆分合并在一起的列。

这些问题通常在嵌套标题表中很突出,并且很容易解决。😄

最后的想法

在本文中,我们看到了使用 Tabula 库从 pdf 文件中提取表格并将其作为 pandas 数据框加载是多么容易。该库在提取表格方面做得很好,但是我们必须总是直观地验证表格的不一致性。大多数时候,任何不一致都很容易解决。

为了完整起见,值得一提的是用于 pdf 表格提取的另一个库: Camelot 。虽然这里没有涉及,但它是白板的一个很好的替代品。两者之间没有偏好,因为两者都做得很好。

现在您已经有了作为数据框的表格,可以随心所欲地操纵它们。😄

🚀希望这篇文章对你有用。 如果你愿意支持我,可以考虑使用我的 推荐链接 加入 medium。这将让你在这个平台上看到我所有的文章以及更多来自其他了不起的作者的文章!🙏

我写的其他文章,你可能会喜欢:

如何使用 Python 从 Twitter API 中提取数据

原文:https://towardsdatascience.com/how-to-extract-data-from-the-twitter-api-using-python-b6fbd7129a33

Tweepy 最新版本概述

卢克·切瑟在 Unsplash 上的照片

在许多情况下,从 Twitter 等社交网络获取外部数据是有价值的。

无论你是大公司还是个人,这都有助于进行和丰富特定主题的分析,监控竞争,评估特定产品的社会声誉,分析客户评论,跟踪对最近事件的反应等。

几年前,从 Twitter 和其他社交网络中提取数据是一场噩梦:没有 API,没有清晰的文档,没有库,并且您必须手动构建复杂的网络爬虫来从底层 HTML 代码中收集数据。

不用说,这是痛苦和笨拙的😰。

希望,事情已经挂起了很多。

在这篇文章中,我将向你展示如何从 Twitter 中提取有用且可操作的数据。为此,我们将使用一个名为 Tweepy 的 Python 包,它将与 Twitter API 交互以获取不同类型的元数据并自动执行任务。

希望你都准备好了。让我们看一看🔍

我们为什么需要 Twitter API?

想象一下:你是一名 web 开发人员,想要提取一个给定帐户的 tweets,以便将它们嵌入到你的应用程序中。您还想每天获取并更新这些推文,以获得最新的推文。

你会怎么做?

为了消费 Twitter 数据,你不需要访问 Twitter 的内部服务器和数据库。你也不需要理解 Twitter 是如何编码的。

您所需要的只是您和 Twitter 后端之间的一个中介,一个您可以请求(通过一些参数)以获得一些数据或与 Twitter 服务交互的中介。

简单地说,API 就是这样:它只是两个相互通信的独立应用程序之间的连接点。

作者图片

作为一种抽象,Twitter API简化了与第三方(开发者、应用、其他 API 等)的集成。).

下面是您可以用 Twitter API 做的事情:

  • 基于标签、关键词、地理位置等以编程方式搜索推文。
  • 构建自动转发预定义账户列表的 Twitter 机器人
  • 基于一系列过滤器实时传输推文
  • 自动关注用户列表
  • 等等。

该 API 允许您以编程方式执行您从界面中手动执行的任何操作。

看起来很有趣:现在让我们看看 Python 如何与 Twitter API 交互。

创建一个 Twitter 应用程序并设置凭证

为了能够重现以下步骤,你需要一个 Twitter 账户。

为了使用 Twitter API,你首先必须在开发者的网站上注册成为 Twitter 开发者。

注册后,您需要创建一个 Twitter 应用程序,该应用程序将设置一系列凭证:这些凭证稍后将由 Tweepy 库使用,以便对您进行身份验证。

首先,进入开发者的仪表盘

作者截图

点击左侧边栏中的概述并点击创建应用按钮。

作者截图

为您的应用程序命名。

作者截图

这将生成以下凭据。这是私人物品,不要和任何人分享。

作者截图

如果您在第一次看到凭据时没有进行复制粘贴,则需要重新生成凭据。为此,从左侧边栏访问您的应用程序,点击键和令牌边栏。

点击每个重新生成按钮,并将以下凭证保存在某处:

  • API_KEY
  • API_KEY_SECRET
  • 访问 _ 令牌
  • 访问 _ 令牌 _ 秘密
  • 不记名 _ 令牌

作者截图

您现在已经准备好使用 API 了。

连接到 Twitter API

为了能够使用 Python 与 Twitter API 进行交互,我们将使用一个名为 Tweepy 的库。

为了能够从源代码中隐藏凭证并将它们作为环境变量加载,我们将使用 python-dotenv

pip install tweepy
pip install python-dotenv

首先,创建一个.env文件来保存您的凭证。

作者截图

在包含.env文件的同一个目录中打开一个 jupyter 笔记本或 python 交互式 shell。

我们可以使用下面的脚本对 Twitter API 进行认证。

让我们检查一下发起这个连接的 Twitter 用户是不是我。

作者截图

为此,我们调用verifiy_credentials方法,该方法返回包含我的个人资料数据的用户对象。

作者截图

这个对象是一个包含大量元数据的 blob。我们可以将其中一些作为对象属性来访问,并将它们打印在屏幕上。

作者截图

这个用户肯定是我。您可以在我的档案中清楚地看到这些数据。

搜索和提取推文

Twitter API 的第一个应用是能够基于多种类型的过滤器以编程方式搜索推文。

例如,让我们搜索一些提到乌克兰🇺🇦.的推文

在设置了认证之后,我们将使用search_tweets方法,遍历提取的 tweets 并打印它们的文本。

下面是运行代码片段后发生的情况。

作者截图

👉在这个例子中,我们没有指定任何过滤器,但是您可以通过设置一些参数来定制搜索,例如您想要的推文数量(count)、语言(lang)、位置(geocode)、停止日期(until)等。
你可以在这里了解全部参数

👉您还可以使用更高级的搜索查询,直接在其中嵌入一些过滤器。
例如,如果您想要提取非转发的关于新冠肺炎的英语推文,您可以编写以下查询:covid-19 lang:en -is:retweet

作者截图

要了解更多关于 Twitter 搜索运营商的信息,请参考这个链接

使用分页搜索大量的推文

在前面的例子中,我们只提取了 15 条左右的 tweets:这是因为 Twitter 有分页机制,我们只得到第一页的结果。

为了循环多个结果页面/tweet,我们需要使用包装了search_tweets方法的光标

Cursor 类的每个实例都支持两种方法,这取决于您想要迭代的内容:

  • items:要迭代的最大项数
  • pages:迭代的最大页数

让我们使用items方法提取 250 条推文。

使用items方法时,我怀疑count参数没有作用。

作者截图

类似地,我们可以使用pages方法获得相同数量的 tweet:我们告诉 Cursor 对象迭代 5 个页面,并为每个页面提取 50 条 tweet。

⚠️如果您积极地使用搜索 API,您可能会遇到 429 错误代码,这表明您已经达到了特定端点的速率限制。

👉例如,/search/tweets/端点上的速率限制是每 15 分钟 180 次。这意味着,在这种限制下,您每 15 分钟最多可以获得 180 * count条推文(count是您在search_tweets方法中指定的参数)

你可以在这里了解更多关于 Twitter 费率限制的信息。

搜索特定账户的推文

假设你想分析埃隆·马斯克的推文:这相当简单。

你所需要做的就是在你的查询前面加上from关键字。
如果你想收集关于特斯拉的推文,你可以这样写:

tesla from:elonmusk lang:en -is:retweet

作者截图

流式实时推文

Twitter API 的一个有趣的功能是能够传输实时推文的样本。这尤其有助于跟踪现场事件并收集相关数据。

为了能够使用 API 的流功能,您首先需要授予对您的 Twitter 应用程序的写访问权限,然后将它移动到一个项目中。

然后,您需要重新生成凭证。

为了能够使用 Tweepy 获取流媒体 tweets,您必须定义一个自定义类,它是StreamingClient类的子类。

这个类需要覆盖一个名为on_tweet的方法,该方法在每次收到 tweet 时执行:为了简单起见,我们告诉这个方法打印 tweet 的 id 和文本。

为了从这个类中实例化一个定制的流,我们需要将无记名令牌传递给构造函数。

然后,我们需要附加一些规则来定义我们想要搜索的内容(注意 tweepy 允许在一个列表中有多个规则,但是在这个例子中我们只设置一个)。

最后,调用filter方法打开流,并对每个传入的 tweet 运行on_tweet方法。

下面的 GIF 说明了流打开后会发生什么。

作者 GIF

要了解更多关于 Tweepy 流的信息,请查看此文档

参考

结论

这篇文章简单介绍了 tweepy 和 Twitter API。它让我们有机会从离线到流媒体模式以各种方式提取推文和元数据。

如果你是一名数据科学家,将 tweepy 添加到你的技能中肯定会给你带来竞争优势,并帮助你用外部数据丰富你的分析。

但是我们只是触及了表面:显然还有更多要学的。如果你想更深入地挖掘,我鼓励你看看 API 文档,一如既往地实验,实验,实验。(3 次不够说)。

今天就这些了。直到下一次更多的编程技巧和教程。👋

新到中?你可以每月订阅 5 美元,并解锁各种主题的无限文章(技术、设计、创业……)你可以通过点击我的推荐链接来支持我

https://ahmedbesbes.medium.com/membership

照片由 charlesdeluvioUnsplash 上拍摄

如何从分类图中提取更多信息

原文:https://towardsdatascience.com/how-to-extract-more-information-from-categorical-plots-8ffac1133eb0

通过使用这两种方法,可以轻松地深入了解分类数据

约翰·施诺布里奇在 Unsplash上的照片

当将分类数据的分布与数字目标变量进行比较时,三种最常用的图通常是箱线图、紫线图和条带图。让我们看看这些使用 Python 的 seaborn 库绘制的图表,并分析我们如何从这些图表中提取更多信息。我们将使用一个关于大型猫科动物及其体重的假想数据集,这是我从维基百科中使用它们的体重统计数据生成的。

import seaborn a sns
import pandas as pddf = pd.read_csv('big_cats.csv')sns.boxplot(df, x='cat', y='weight (kg)')

箱线图(作者提供的图表)

从这些箱线图中,我们可以提取以下信息:

  • 每种大型猫科动物数据点的 50%的重量(彩色方框)。这也被称为四分位距(IQR)。
  • 每种大型猫科动物的平均体重,看 IQR 中间的水平线。
  • 第 25 和第 75 百分位分别称为 Q1 和 Q3。大型猫科动物中最轻的 25%在彩色盒子的前面,最重的 25%在彩色盒子的上面。
  • 任何异常值,即重量分别小于或大于 Q1 和 Q3 的 1.5 倍 IQR 的物种中的个别大型猫科动物。

正如大多数人可能知道的那样,老虎是大型猫科动物中最大的(也是最重的),这一点在剧情中得到了清晰的体现。然而,老虎和狮子的体重差异似乎太大了:在这个数据集中,超过 75%的老虎比任何狮子都重。这里发生了一些奇怪的事情,但是箱线图并没有给我们更多的信息。让我们用sns.violinplot试试小提琴

Violinplot(作者提供的图表)

violinplot 在 boxplot 的顶部添加了一个层,其中 violin 的厚度意味着数据的密度。尽管如此,这并没有回答我们的问题,为什么这个数据集中的狮子是如此之轻。我们可以尝试使用另一个图:stripplot,它绘制单个数据点:

剥离图(作者提供的图表)

最后,我们似乎可以假设为什么狮子的体重出乎意料:只有几个数据点。也许数据集中所有的狮子都是母狮子,它们通常比公狮子轻,或者也许数据集中的几只狮子都是幼狮,还没有发育完全。

现在,当然,我们可以对每个分类变量应用箱线图和剥离图,但这不是一个非常有效的解决方案。

这个问题的一个简单解决方案是使用 e xtra-datascience-tools 包中的add_count_info_to_xticks,并将其应用于我们的第一个箱线图:

(作者要点)

带计数信息的箱线图(按作者分类的图表)

通过添加计数信息,我们可以很容易地发现 lion 数据中出现了一些奇怪的情况。70 个观察中,60 个是,占 85.7%。这意味着 lion 的箱线图仅基于 10 个数据点,考虑这一点很重要,这也是我们需要在前面绘制剥离图的原因。我们还可以提取其他信息,如有多少数据点是 lions (19.3%),所有 nan 值中有多少来自 lions (69.8%),以及总数据集有多少 nan 值:86,即 23.8%(见 y 轴标签)。

使用add_count_info_to_xticks和它的兄弟add_count_info_to_yticks,我们可以从单个图中提取更多的信息,同时仍然选择我们喜欢的图。

因为可视化仍然很好,也许更漂亮一点,我们也可以使用 extra-datascience-tool 的stripboxplot来创建下面的情节:

条形箱线图(作者提供的图表)

使用这个带状盒状图,我们既可以提取盒状图可以给我们的所有信息,也可以提取关于每个类别的单个数据点和数量的信息。使用stripboxplotcount_info参数,我们可以更容易地将计数统计数据添加到图表中:

import pandas as pd
from extra_ds_tools.plots import stripboxplot

df = pd.read_csv('big_cats.csv')
stripboxplot(df, x_col='cat', y_col='weight (kg)', count_info=True)

带计数信息的条形盒图(按作者分类的图表)

结论

箱线图、紫线图和带状图对于比较分类分布非常有用。尽管如此,每个都有自己的优势和劣势。使用轴上的条形盒图和/或额外计数信息有助于从单个图中提取比使用标准图更多的相关信息!

如果你仍然对如何在分类变量上应用新的探索性数据分析方法感兴趣,请务必阅读我的另一篇文章:

https://medium.com/@tomergabay/advancedvaluecounts-for-eda-2f80e2c74ce1

如何用熊猫填补缺失数据

原文:https://towardsdatascience.com/how-to-fill-missing-data-with-pandas-8cb875362a0d

初学者指南

马特·霍夫曼在 Unsplash 上的照片

介绍

处理缺失数据是任何数据科学工作流的重要组成部分。处理缺失数据的常用方法包括(a)忽略缺失数据,(b)删除缺失数据的记录,或(c)填充缺失数据。在本文中,我们将使用一个包含 2021 年 1 月 4 天水果价格的玩具数据集,研究各种填充熊猫库缺失数据的方法。

让我们生成我们的玩具数据集。

df = pd.DataFrame({'date':['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04','2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04'], 'fruit':['apple', 'apple', 'apple', 'apple', 'mango', 'mango', 'mango', 'mango'], 'price': [0.80, None, None, 1.20, None, 2.10, 2.00, 1.80]})
df['date'] = pd.to_datetime(df['date'])

在该数据集中,有 4 条记录的缺失值用“NaN”表示,并且苹果的价格通常低于芒果的价格。

作者图片

方法

用常数值填充

让我们用用户定义的价格 0.85 来填充缺失的价格。“价格”列中所有缺少的值都将用相同的值填充。

df['price'].fillna(value = 0.85, inplace = True)

作者图片

用列的平均值/中值填充

我们可以用整个列的平均价格或中间价格来填充缺失的价格。

# mean
df['price'].fillna(value = df.price.mean(), inplace = True)# median
df['price'].fillna(value = df.price.median(), inplace = True)

df.price.mean()df.price.median()分别返回平均价格(1.975)和中间价格(2.0)。.fillna()方法用给定的平均值或中间值估算缺失的价格。

左图:用平均值估算缺失价格。右图:用中位数估算缺失价格。作者图片

这些价格对于苹果价格来说可能太高,对于芒果价格来说可能太低,因此我们可能不想用所有水果的平均价格来估算苹果的价格。相反,我们可能想用苹果的平均(或中间)价格来估算苹果的缺失价格,并对芒果做同样的事情。这就引出了下一种用特定组内的平均值(或中值)填充缺失值的方法。

用组的平均值/中值填充

我们可以通过以下方式使用组级统计来填充缺失值。

# mean
df['price'].fillna(df.groupby('fruit')['price'].transform('mean'), inplace = True)# median
df['price'].fillna(df.groupby('fruit')['price'].transform('median'), inplace = True)

让我们把上面的代码分成两步。

第一步:计算每种水果的平均价格,并返回一个与原始数据帧行数相同的序列。苹果和芒果的平均价格分别为 1.00 英镑和 2.95 英镑。

df.groupby('fruit')['price'].transform('mean')

第 2 步:根据第 1 步的结果填充缺失的值。

作者图片

向前填充

向前填充,简称为“ffill ”,沿着数据帧的选定轴向前传播最后一个有效观察值(在我们的示例中,沿着列向下)。

df['price'].fillna(method = 'ffill', inplace = True)

作者图片

我们可以通过使用limit参数来限制传播最后一个有效观察的行数。以下示例显示,传播仅限于最后一次有效观察后的 1 步。苹果 2021-01-03 缺少的价格没有填写,因为它是在最后一次有效观察之后 2 步。

df['price'].fillna(method = 'ffill', limit = 1, inplace = True)

作者图片

向前填充用 2021 年 1 月 4 日的苹果价格替换 2020 年 1 月 1 日缺失的芒果价格。这没有意义,因为这不是苹果之间的比较(没有双关语的意思)。因此,我们可能希望对每个水果分别应用向前填充。我们可以通过使用熊猫分组前向填充方法来实现。

组内正向填充

正向填充可以与 groupby 结合使用,在特定组内执行正向填充。

作者图片

df['price'] = df.groupby('fruit')['price'].ffill()

请注意,2021–01–01 上缺失的芒果价格没有被 2021–01–04 上的苹果价格填充,因为苹果和芒果现在被视为不同的组。与前面的例子类似,我们也可以设置limit参数来限制 ffill 传播。

df['price'] = df.groupby('fruit')['price'].ffill(limit = 1)

作者图片

后面充填物

回填也简称为“bfill ”,是正向回填的反义词。在“NaN”值之后的第一个有效观察被识别,并沿着所选的轴向后传播(在我们的例子中是向上的列)。

df['price'].fillna(method = 'bfill', inplace = True)

作者图片

类似地,我们也可以使用limit参数来限制有效观察传播的行数。

df['price'].fillna(method = 'bfill', limit = 1, inplace = True)

组内回填

与前向填充类似,我们也可以仅在特定组内执行后向填充,并限制其传播。

# backfill without propagation limit
df['price'] = df.groupby('fruit')['price'].bfill()# backfill with propagation limited to 1
df['price'] = df.groupby('fruit')['price'].bfill(limit = 1)

FFill 和 BFill 的组合

我们也可以通过方法链接用前向填充填充一个列,然后用后向填充填充。

df['price'] = df.groupby('fruit')['price'].ffill().bfill()

作者图片

注意.ffill().bfill()的顺序很重要。如果我们交换顺序,将首先执行回填,然后执行向前回填,从而产生不同的结果。

df['price'] = df.groupby('fruit')['price'].bfill().ffill()

作者图片

插入

插值是一种估计位于一系列已知离散数据点之间的新数据点的值的方法。我们可以通过以下方式对熊猫应用线性插值

df['price'].interpolate(method = 'linear', inplace = True)

线性插值假设这些值的间距相等。苹果在 2021 年 1 月 2 日和 2021 年 1 月 3 日缺少的值被填充为 0.933 和 1.067,其中价格以 0.133 的间隔增加。

作者图片

以这种方式使用线性插值来填充 2021 年 1 月 1 日缺失的芒果价格是没有意义的,因为我们是基于 2021 年 1 月 4 日的苹果价格和 2021 年 1 月 2 日的芒果价格进行插值的。让我们试着对每个水果分别进行插值。

在组内插值

我们可以按以下方式在特定组内执行插值

df['price'] = df.groupby('fruit')['price'].apply(lambda x: x.interpolate(method='linear'))

芒果在 2021 年 1 月 1 日的价格是“Nan ”,因为没有足够的数据点来执行插值。线性插值需要至少 2 个已知数据点,但是没有芒果在 2021 年 1 月 1 日之前的数据点。

作者图片

假设 2021 年 1 月 1 日和 2021 年 1 月 2 日的芒果价格相同,我们可以使用回填来填充缺失的价格。让我们通过将两种方法链接在一起来依次执行插值和回填。

df['price'] = df.groupby('fruit')['price'].apply(lambda x: x.interpolate(method='linear')).bfill()

作者图片

基于条件的填充值

在某些情况下,我们可能希望根据其他列中的值来定义如何填充缺失值。例如,水果的价格在周末可能比平日更贵。因此,我们希望用以下方式来填补缺失的价格:

作者图片

首先,我们需要通过创建一个布尔列来确定哪些日期是周末和工作日,其中True表示工作日,False表示周末。

df['weekday'] = df['date'].apply(lambda x: False if x.day_name() in ['Saturday', 'Sunday'] else True)

然后我们确定每种水果的平均价格

mean_price = df.groupby('fruit')['price'].transform('mean')

最后我们根据给定的条件用熊猫.where()方法填充缺失值。

df['price'].fillna((mean_price).where(cond = df.weekday, other = mean_price*1.25), inplace = True)

作者图片

结论

在本文中,我们研究了以下使用熊猫填充缺失值的方法。

  • 菲尔娜
  • 向前填充
  • 后面充填物
  • 插入文字

填充方法的选择取决于假设和问题的背景。例如,用苹果和芒果的平均价格来填充芒果的缺失值可能不是一个好主意,因为苹果和芒果在我们的玩具数据集中具有相当不同的价格。

我们还将看到如何将每个方法与 pandas .groupby()方法结合使用,分别为每个组填充缺失值。

  • 加入灵媒阅读更多这样的故事
  • 关注我关于熊猫的教程

如何过滤 SQL 中不存在的记录

原文:https://towardsdatascience.com/how-to-filter-non-existing-records-in-sql-85de6db653d3

了解如何筛选 SQL 表中不存在的记录

图片来自 Unsplash

介绍

除了所有的特别查询之外,开发预定义的报告已经成为我日常工作的一部分。我经常发现我的利益相关者要求我准备报告,他们想知道一些从未发生过的事情。这听起来可能很奇怪,但的确,这就是他们所关心的问题。简而言之,最常出现的问题如下

  1. 哪些是我从未购买过产品的客户?
  2. 哪些产品是从来不卖的?
  3. 哪些活动从不预订?

了解这些答案有助于分析这些问题的症结所在,而且他们可能还会提出一些有利于整体销售的新想法。

我的方法

当我开始准备这样一个问题的答案时,我通常会审核所有我可能感兴趣的表格。例如,在第一个场景中,客户和销售表是最重要的。类似地,在第二个场景中,人们会对产品和销售感兴趣等等。

在任何一种情况下,理解我们需要从一个表中提取另一个表中不存在的信息是很重要的。我将试着解释获得这样一个答案的基本方法,并强调我认为的最佳选择。

解决方法

从技术上来说,当事情发展到编写 SQL 查询时,我感到非常兴奋。SQL 中有多种方法可以实现上述场景,下面提到了其中一些方法:

  1. 使用 NOT IN 语句
  2. 使用外部敷剂
  3. 使用左外部连接
  4. 使用 EXCEPT 语句
  5. 使用不存在

所有这些方法可能产生相同的结果,但是,有可能一种方法比另一种方法执行得更好。在最终确定一种方法之前,我不得不逐一尝试所有的方法。

就本文而言,我想举一个微软提供的全球进口商数据库的例子。这个数据库可以从微软 SQL Server 的官方 Github 页面下载。

使用 NOT IN 语句

虽然这是每个 SQL 开发人员尝试应用的最常见的方法,但这可能不是最好的方法。典型的查询如下所示。

SELECT CustomerName FROM Sales.Customers
WHERE CustomerID NOT IN (SELECT CustomerID FROM Sales.Orders);

这似乎是一个相当不错的查询,只要销售中有 CustomerID,就会返回正确的结果。订单不为空。如果有空值,此方法可能不起作用,因为数据库引擎将其视为左反半连接,但是,它不会反映右侧的空值是否与左侧的空值匹配。

使用外部敷剂

表达相同查询的另一种方式是使用外部 APPLY 子句,查询如下。

SELECT CustomerName FROM Sales.Customers cus
OUTER APPLY (
SELECT CustomerID FROM Sales.Orders ord
WHERE ord.CustomerID = cus.CustomerID
) as sales
WHERE sales.CustomerID IS NULL;

这种方法也使用左反半连接,但是,产生的计划似乎缺少连接操作符。我认为这种方法比前一种方法稍微贵一点,因为它实际上是以不同的方式处理的。外部连接操作符首先引入所有与条件匹配或不匹配的数据,然后应用过滤器,只返回匹配的记录。

使用左外部连接

外部应用的一个常用替代方法是左外部连接。这里,假设因为连接条件是基于 CustomerID 的,所以销售中的所有 CustomerID。对于那些还没有购买的人,订单表将为空。查询计划与前面方法中使用的几乎相似。这里要注意的最重要的事情是确定要对哪一列应用空过滤器。此外,建议在连接条件中使用索引列,因为这有助于获得更好的性能。

SELECT CustomerName FROM Sales.Customers cus
LEFT OUTER JOIN Sales.Orders ord
ON ord.CustomerID = cus.CustomerID
WHERE ord.CustomerID IS NULL;

使用 EXCEPT 语句

另一种方法是使用 EXCEPT 子句,尽管我并不经常使用。在我看来,唯一的问题是,它只能在两列相同的情况下使用,在本例中是 CustomerID。不能在第一个表的 SELECT 语句中使用任何其他列,因为数据库引擎无法识别要对哪一列应用联接条件。

SELECT CustomerID FROM Sales.Customers cus
EXCEPT
SELECT CustomerID FROM Sales.Orders ord;

使用不存在

我处理这种情况的首选是使用 NOT EXISTS 语句。请注意,我在内部查询中使用了“SELECT 1 ”,这有两个原因。首先,SQL Server 并不真正关心 EXISTS 子查询中的内容,其次,从文档的角度来看,它帮助我认识到,仅仅通过查看语句,内部查询并不返回任何记录。就性能而言,我觉得它几乎等同于 NOT IN 和 EXCEPT 语句,但是,一个潜在的优势是它消除了空值或重复的风险。

SELECT CustomerName FROM Sales.Customers cus
WHERE NOT EXISTS (
SELECT 1 FROM Sales.Orders ord
WHERE ord.CustomerID = cus.CustomerID
);

拿走

尽管有多种方法来处理 SQL Server 中不存在的记录的筛选,但我最喜欢的选择是使用 NOT EXISTS 语句。将来,我可能会对所有这些语句使用的所有执行计划进行详细的比较,并对其中每一个语句的性能进行比较。

参考

https://sqlinthewild . co . za/index . PHP/2010/02/18/not-exists-vs-not-in/

如何(最终)在 WSL2 上安装 TensorFlow GPU

原文:https://towardsdatascience.com/how-to-finally-install-tensorflow-gpu-on-wsl2-7be59e278f92

从此再也不用担心 TensorFlow 安装失败

照片由奥努汉·凯斯金拍摄

在我关于在 Windows 上安装 TensorFlow GPU 的文章走红并成为 Google 上的特色片段后,我决定为 Windows 子系统 Linux (WSL2)编写相同的教程。完成本文后,您将能够在 WSL2 安装的 GPU 支持下训练 TensorFlow 模型。

1.确保在 Windows 端安装了 TensorFlow GPU

首先,确保您遵循我的第一篇文章中所写的步骤:

在 WSL2 上安装 TensorFlow 的 GPU 支持是建立在 Windows 端的 NVIDIA CUDA 驱动程序之上的。因此,您必须完成第一篇文章中的步骤。如果您可以从 Windows 命令行运行以下命令并得到相同的输出,那么您就可以开始了:

# Create an env for TensorFlow or use an existing one
$ conda create -n tf python=3.9 -y
$ conda activate tf

$ pip install tensorflow==2.10
$ python
>>> import tensorflow as tf
>>> len(tf.config.list_physical_devices('GPU'))
1

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

https://alphasignal.ai/?referrer=Bex

2.检查您的 WSL2 安装

还没有安装 WSL2 吗?不用担心;在这方面我也帮你搞定了。仔细阅读我上一篇文章中关于安装它的综合文章。

如果你已经安装了 WSL2,但还没有为机器学习工作进行配置,那么继续阅读。

3.在 WSL2 上安装 Anaconda

我首选的包管理器是 Anaconda。让我们把它安装在 WSL2 上。首先,转到https://www.anaconda.com/products/distribution并向下滚动到 Anaconda 安装程序部分:

作者图片

复制突出显示的安装程序的链接。注意,我们选择 Linux,因为 WSL2 不能与 Windows 的.exe可执行文件一起工作。

然后,转到您的 Linux 终端,下载根路径中带有wget(~)的文件:

$ wget [https://repo.anaconda.com/archive/Anaconda3-2022.10-Linux-x86_64.sh](https://repo.anaconda.com/archive/Anaconda3-2022.10-Linux-x86_64.sh)

该命令将下载一个名为Anaconda3-2022.10-Linux-x86_64.sh的 Linux 可执行文件。要运行它,您将使用bash命令:

$ bash Anaconda3-2022.10-Linux-x86_64.sh

按照说明操作(只需按 ENTER 和“yes”)。之后,您可以删除该文件:

$ rm -rf Anaconda3-2022.10-Linux-x86_64.sh

通过运行conda --version确保一切顺利。

$ conda --version
conda 22.9.0

4.为 WSL2 安装 CUDA 和 cuDNN 驱动程序

现在,最关键的步骤——安装兼容的 GPU 驱动程序。继我的第一篇文章之后,你知道 TensorFlow 的最新版本需要 11.2 和 8.1 版本的 CUDA 和 cuDNN。在从 Windows 端安装了这些版本之后,WSL2 需要相同的版本。

要安装它们,请仔细执行以下步骤。

首先,移除旧的 NVIDIA GPG 签名密钥并更新/升级库:

$ sudo sudo apt-key del 7fa2af80
$ sudo apt update && sudo apt upgrade

接下来,下载 CUDA Ubuntu 存储库 pin 并将其移动到相关的目的地,并下载新的签名密钥:

$ wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-wsl-ubuntu.pin
$ sudo mv cuda-wsl-ubuntu.pin /etc/apt/preferences.d/cuda-repository-pin-600

$ sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/3bf863cc.pub
$ sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu2004/x86_64/7fa2af80.pub

然后,下载 WSL2 CUDA 工具包存储库(需要一段时间):

$ sudo add-apt-repository "deb https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/ /"

更新/升级软件包:

$ sudo apt update && sudo apt upgrade

现在,安装 CUDA 存储库(这需要一些时间):

$ sudo apt-get -y install cuda
$ sudo apt update && sudo apt upgrade

最后,我们用以下命令安装 cuDNN 库:

$ sudo apt-get install libcudnn8
$ sudo apt-get install libcudnn8-dev
$ sudo apt-get update && sudo apt-get upgrade

请注意,这些步骤仅适用于 WSL Ubuntu 2004,WSL2 的 x86_64 发行版。对于其他发行版,用你的替换上面三个链接中的$distro$arch。例子:[https://developer.download.nvidia.com/compute/cuda/repos/$distro/$arch/3bf863cc.pub](https://developer.download.nvidia.com/compute/cuda/repos/$distro/$arch/3bf863cc.pub)

5.在 conda 环境中安装 TensorFlow

最后,打造 TensorFlow 专用的 conda 环境。在这里,我将创建一个名为tf的:

$ conda create -n tf python=3.9 -y
$ conda activate tf

现在,用 pip 安装 TensorFlow 并检查安装情况:

$ pip install tensorflow==2.10
$ python
>>> import tensorflow as tf
>>> len(tf.config.list_physical_devices('GPU'))
1

您也可以从终端运行nvidia-smi命令:

作者图片

中间的单元格显示 8GB 中使用了 607MB 的 GPU VRAM。太好了!

现在,让我们训练一个样本模型来看看 GPU 的运行情况。

6.检查运行中的 GPU

在新的 Python 脚本中,粘贴以下代码:

import tensorflow as tf

mnist = tf.keras.datasets.mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

model = tf.keras.models.Sequential(
    [
        tf.keras.layers.Flatten(input_shape=(28, 28)),
        tf.keras.layers.Dense(128, activation="relu"),
        tf.keras.layers.Dropout(0.2),
        tf.keras.layers.Dense(10),
    ]
)

loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
model.compile(optimizer="adam", loss=loss_fn, metrics=["accuracy"])

model.fit(x_train, y_train, epochs=5)

当脚本运行时,再次键入nvidia-smi命令。如果中间的单元格显示正在使用更多的 GPU 资源,如下所示,那么恭喜你!您的 TensorFlow 安装现在在 GPU 支持下完全可用。

请注意,当您从 WSL2 使用 GPU 时,GPU 使用统计数据不会正确显示在任务管理器中。这就是为什么推荐使用nvidia-smi命令的原因。

结论

这就是本教程的内容。请务必关注我订阅我的电子邮件列表,获取我即将发表的关于在 Windows 和 WSL2 上安装支持 GPU 的 PyTorch 的文章。

感谢您的阅读!

https://ibexorigin.medium.com/membership

我的更多故事

[## 使用 Python 和 AWS Lambda 将任何 ML 模型部署为 API 的综合指南

towardsdatascience.com](/comprehensive-guide-to-deploying-any-ml-model-as-apis-with-python-and-aws-lambda-b441d257f1ec)

如何找到任何函数的最优值

原文:https://towardsdatascience.com/how-to-find-any-functions-optimum-a8d713bf1d25

优化指标、模型和功能的聪明方法

图 1:最小-最大值,“增长-增加-体积”,Tumisu, Pixabay

直接使用优化器,无论是最小化器还是最大化器,是一个很少被讨论的主题。这些工具可以很容易地用来寻找,例如,任何函数的局部或全局最小值。我们将深入研究几个示例,第一个示例估计模式,第二个示例找到驱动最高 F1 分数的最佳值。请记住,这种方法可以推广,并且在搜索任何函数曲面上的最小值(或最大值)时非常有效。让我们开始吧。

估计模式

在这个例子中,我们将使用核密度估计 (KDE)来估计真实模式,这是一种以非参数方式估计随机变量的概率密度函数(PDF)的方法。我们将使用具有高斯内核的 KDE(图 2 ),并在其负内核输出上使用最小化器。换句话说,我们正在尝试使用极小值来搜索模式的分布。

图 2:[1,2,3,4,5,6,9]的高斯 KDE 图

下面是用于这个例子的代码,它非常简单,很容易修改,就像我们将看到的其他问题一样。在图 3 中,我们可以看到一个“向量”,然后由高斯 KDE 估计,并使用负输出值在最小化函数中搜索模式。极小值从平均值开始,不超过它的界限。这一数值分布的平均值为 3.556。

图 3:最小化高斯核 KDE 的代码

我们可以看到,值 3.556 介于向量的第三和第四个成员之间,这是高斯 KDE 的最高输出(图 4),也就是说,在使用最小值时,代码中的负值最低。

图 4:每个向量项的核值。

为 F1 分数优化

再举个例子,有点类似。在这个例子中,我们试图找到逻辑回归边界的最佳阈值,使用强力优化器和 F1 分数函数,它试图找到全局最小值。

在这段代码中,我们有一个真实概率向量和预测概率向量的例子。我们有一个包装器函数,它使用阈值计算可能的 y_pred 向量,这是蛮力搜索通过的。这是在 brute()函数内部完成的。我们针对所有可能的预测向量计算真实值的 F1,并且蛮力函数 bookeeps 最好的最小结果恰好是阈值 0.7。我们期望优化器找到阈值 0.7,这将产生与 y_true 相同的 y_pred 向量(基于 y_pred_proba),如图 5 所示。

图 5:理论 LogReg 模型输出的 F1 强力优化器。

摘要

我希望这篇短文能说服您使用这个不常见但非常有用的工具来优化任何函数,无论是度量、模型、算法还是其他。我要感谢 Natanel Davidovits 在很多年前向我介绍了这个想法并提供了上面的代码。

Ori Cohen 博士拥有计算机科学博士学位,主要研究机器学习。他是 ML & DL 纲要StateOfMLOps.com的作者,并且对 AIOps & MLOps 领域很感兴趣。现在,他是 Justt.ai 数据科学的高级数据总监。

如何使用 python 在海上找到陆地

原文:https://towardsdatascience.com/how-to-find-land-when-youre-at-sea-using-python-48111e5d9795

从海洋中的任何一点发现最近的陆地的分析脚本

尼霍阿岛——图片来自维基百科

介绍

令人惊讶的是,我在网上找不到任何解决这个问题的工具。在有人问之前,我不是水手或探险家。至少现在还没有。我对这个问题很好奇,因为我和我的妻子将在几个月后有一个孩子,并且正处于试图决定给她取什么名字的绝望阶段。

我妻子来自中国,我来自美国,所以在一次深夜搜索名字的狂欢中,我们中的一个人想到了从我们出生的医院中找出地理中点。两个医院之间最短距离的中点在哪里?我们用谷歌上的工具很快地搜索了一下,结果是这样的:

谷歌地图

嗯,那没什么帮助,是吗?唯一的婴儿名字选择是“太平洋”,这是一个太大的区域,没有任何特别的感觉。所以我们的下一个想法,也是这篇文章的中心点是“离这个点最近的陆地是什么”。也许它会给我们一些有趣的婴儿名字的想法。

当然,我们可以看看上面的地图,有个大概的概念。它要么是北边的阿拉斯加群岛,要么是南边的夏威夷群岛,甚至可能是东边加利福尼亚海岸的某个地方。但是我太挑剔了,不能接受这样一个大概的猜测。我想知道最近的大陆确切地说是

Python 脚本

我搜索了 google、stack overflow、github 和其他各种资源,都没有找到我们问题的解决方案。那时我决定是时候推迟名称搜索并编写一个 python 脚本了!

从上面可以看到,这个脚本的起点是(38.666067,-158.305948)。这就是之前展示的太平洋中部的点。边注:我了解到有 6 个小数位的 GPS 坐标精度在一厘米以内。就是这么精确!

对于那些对脚本本身感兴趣的人来说,代码中有解释每个步骤的注释。包括导入的模块在内的整个脚本都包含在我的 github 中,你可以在那里找到更多的细节。该脚本运行的基本结构是:

  1. 选择地球上任意一个 GPS 坐标
  2. 测量随机坐标离起点有多远(以英里为单位)
  3. 使用 global_land_mask 模块发现那个点是海洋还是陆地,玩起来非常有趣。
  4. 在一个循环中迭代数百万次。执行的迭代次数越多,结果就越精确。
  5. 最后,我们查询数据帧,仅按陆地点过滤,并按找到的最近距离排序。

看起来离我们在太平洋的起点最近的陆地是(23.06468,-161.93897)位置,如下面的查询结果所示。那原来是尼霍阿岛,一个远离夏威夷主岛的无名小岛。如果没有参与这个项目,我永远不会知道这个小岛的存在。下面所有以“53”开头的点都是我们起点以北的阿拉斯加岛串的一部分。

结论

发现这个岛非常令人兴奋。这个岛只有 0.27 平方英里,所以我很惊讶剧本竟然把它捡起来了,再次表扬了全球陆地面具模块。事实上,它只在我们的查询中出现过一次(尽管有 500 万次迭代),这表明它有多小。阿拉斯加群岛有数百个点几乎与我们的岛一样近,但不完全在那里。

Nihoa 和我们的起点相比

“Nihoa”绝对有给宝宝起名字的潜力,尤其是在做了这么多工作之后。这是一个有点“与众不同”的名字,但它肯定在我们的列表中。显然,这个名字在夏威夷语中的意思是“锯齿状的边缘”,因为山脉的边缘看起来非常尖锐。无论我们是否选择这个名字,在这个项目之后,我永远不会忘记 Nihoa 岛。

更新:我对这个项目做了一些编辑,在另一篇文章中会详细讨论。如果你觉得这个有趣,请检查一下。

考虑通过我的推荐链接加入 Medium:https://andrewhershy.medium.com/membership

如果你觉得这篇文章有帮助/有趣,请看看我的其他文章:

我写了一个 python 脚本帮我玩彩票

基尼指数 vs 信息熵

Alteryx 是否是你数据分析需求的正确选择?

利用数学和 python 优化你的投资组合

Excel vs SQL:概念上的比较

如何找出我的 Python 代码的瓶颈

原文:https://towardsdatascience.com/how-to-find-out-the-bottleneck-of-my-python-code-46383d8ef9f

以战略性的方式调试性能问题

照片由 Unsplash 的 makariostang 拍摄

M 通常情况下,开发人员需要优化代码以使其性能更好。这听起来像是正确的做法,但并不总是如此。代码优化是一个模糊的术语。没有明确的目标,很容易掉进兔子洞,浪费时间。在本文中,我想告诉你一个找到代码瓶颈的战略方法——从理解你是否应该优化你的代码到找出哪个函数导致了性能问题。

应该优化什么,什么时候优化?

我们所说的代码优化是指重写代码,以便程序执行得更快,并使用更少的内存、CPU、磁盘空间或网络带宽。那么,是不是每个程序都需要偶尔优化一下呢?不会。通常,只有少数几类程序需要优化。

实时应用

成熟的实时应用如 Apache Kafka 和 RabbitMQ 以其高吞吐量和低延迟而闻名。许多公司已经在自己的环境中安装了它们。由于设置不同,性能可能会有所不同。

有几个基准可以帮助您评估性能。如果您发现与基准测试相比速度不够快,您可以微调配置或纵向或横向扩展硬件。

具有 SLA 的应用

另一种类型的程序是具有严格服务水平协议(SLA)的程序。换句话说,程序必须在一定的时间限制内交付结果,否则,它可能会影响业务。很明显,SLA 是一个硬门槛,但是不要等到它过线了,那就来不及了。预防措施之一是监控流程,如果发现增长趋势或偏差模式,则发出警报。

其他行为异常的应用

做代码优化的原因不是因为开发者的神感(虽然有帮助),而是数字和事实。在这种情况下,监测起着至关重要的作用。它帮助开发人员理解程序在晴天如何运行,并从那里发现雨天。例如,资源(CPU/内存/磁盘)使用率呈上升趋势、峰值时间、可疑日志等。根本原因可能是多方面的——资源不足、代码中的错误、来自外部的高负载等等。

经验法则是,如果程序与期望的速度相比不够快,就应该优化代码,无论是基准测试、SLA 还是过去的平均性能。通过监控和警报,可以了解系统的健康状况,并帮助开发人员了解使用或行为的趋势,以便采取预先措施。

优化什么?—硬件

当你对数字感到失望时,下一步就是采取行动。开发人员很容易被各种解决方案淹没。大多数性能问题都与运行太慢或使用太多内存有关。

一个潜在的解决方案是拥有更好的硬件。借助云计算,添加更多内核或内存可以在几秒钟内完成。但像任何解决方案一样,它也有利弊。添加更多资源是一种简单快捷的解决方案,可以有效地解决紧急生产问题。但是如果这是您解决性能问题的唯一解决方案,那么您的程序将会非常昂贵。横向扩展会导致成本倍增,而纵向扩展可能会达到云提供商为单台机器所能提供的极限。根据程序的设计,这可能需要从单台机器到分布式系统的代码重构。

不要假设硬件是唯一的解决方案,在对代码进行并行化之前,一定要先在只有一个 CPU 和有限内存的机器上优化代码。在很多情况下,花时间在代码优化上是值得的。比如算法优化——将时间复杂度从 O(n)提高到 O(nlogn)或 O(n),语言切换——使用基于 CPython 的库或使用缓存减少繁重的 I/O 操作量等。

下一个问题是——我如何知道应该优化代码的哪一部分,因为重写整个代码肯定不是一个明智的决定。在下一节中,我将介绍 Python 中的程序概要分析,它可以帮助开发人员快速找到繁重的操作,并从那里进行改进。

优化什么?—软件

为了找出生产应用中的性能瓶颈,开发人员需要可操作的洞察力。一种现代的方法是应用分析,突出最慢的代码,即消耗大部分资源(如 CPU 和内存)的区域。剖析可以是生产(或类似生产的环境)中的一次性操作持续过程。不同的分析器使用不同的方法收集信息,因此具有不同的运行时开销。为您的用例选择正确的分析器非常重要。

在这一节中,我将介绍两种不同的分析方法和几种可视化结果的方式。

举例

在本文中,我们将剖析这个 repo 的代码——一个计算入射波在 2D 物体上散射的简单程序。

来源:https://nesi . github . io/perf-training/python-scatter/introduction

确定性分析器

您可能听说过 cProfile,这是 Python 中的一个内置分析器。cProfile 是一个确定性分析器,它反映了所有函数调用函数返回异常事件都被监控,并且这些事件之间的时间间隔被精确计时。

这种类型的剖析器可以收集高分辨率的剖析信息,但有一个主要缺点:高开销。可以想象,如果应用程序有大量的函数调用,那么分析器将会收集太多的记录。如果函数很小,那么由于分析器本身的开销,结果可能不准确。

然而,下面是如何在这个例子中使用 cProfile。cProfile 的总执行时间是 89.03 秒。

python -m cProfile scatter.py

如果没有 cProfile,这个程序需要 80.50 秒,快了 10%。因此,不建议在生产执行期间使用。

cProfile 的输出如下所示,其中每一行都是执行过程中的一个函数调用。它记录了调用的次数、在该函数中花费的总时间,以及在该函数和所有子函数中花费的累计时间等。

cProfile 的输出由

但是这个表对人类来说很难解释,因为它包含了太多我们并不真正关心的信息,比如 Python 的内部函数。此外,我们不知道每个函数如何与其他函数相关,也不知道较慢的函数的输入是什么。如果一个函数被多个函数调用,就很难找出哪个路径和相应的输入导致了缓慢。

一种解决方案是将结果可视化为图形,以了解函数之间的关系。由于 cProfile 不提供任何可视化,我们需要使用像[snakeviz](https://jiffyclub.github.io/snakeviz/)[gprof2dot](https://github.com/jrfonseca/gprof2dot)这样的库来实现。

snakeviz

我们将在命令行使用 cProfile 来创建一个配置文件,并使用 snakeviz 来解释结果。Snakeviz 有两种可视化风格——冰柱和旭日。在一个函数中花费的时间由矩形的宽度或弧的角度范围来表示。

python -m cProfile -o scatter.prof scatter.py 
# Execution time : 86.27 sec
snakeviz scatter.prof

蛇语(冰柱作者:高 T5)

蛇语(旭日东升)

gprof2dot

gprof2dot 创建了另一种可视化类型——点状图。我更喜欢这种类型的图表,因为它清楚地显示了功能之间的关系,颜色对比更容易发现重要的功能。

gprof2dot --colour-nodes-by-selftime -f pstats output.pstats | \
    dot -Tpng -o output.png

gprof2dot (by @Xiaoxu Gao)的输出

统计分析器

如果我们只想在本地笔记本电脑上开发和调试应用程序的过程中大致了解一下性能,那么 cProfile 是可以的。但是不建议在生产中使用它,因为可能会有明显的性能影响。这就是统计剖析器的用处。

它通过定期对执行状态进行采样来测量应用程序的性能。这种方法不如确定性分析准确,但是它的开销也较小。由于开销较小,它可用于监控生产中正在进行的过程。对于某些应用程序,分析必须是生产中的一个连续过程,在其他环境中很难发现性能问题。

我将列出一些最流行的统计分析器。他们中的大多数都有一个内置的可视化解决方案,所以我们不需要额外的软件包。

pyinstrument

pyinstrument是一个统计 python 分析器,它每 1 ms 记录一次调用堆栈,而不是记录整个跟踪。您可以从命令行直接调用pyinstrument:

pyinstrument scatter.py

您还可以生成交互式网页:

pyinstrument -r html -o output.html scatter.py

与 cProfile 的原始输出不同,pyinstrument给出了一个突出显示的函数调用树,这更容易理解。它花费的时间也比 cProfile 少。

pyinstrument 的输出(由

从树中可以明显看出computerScatteredWaveElement函数是瓶颈。我非常喜欢pyinstrument的简单性,它已经成为我的首选 Python 分析器。

[pyinstrument](https://pyinstrument.readthedocs.io/en/latest/guide.html#profile-a-specific-chunk-of-code) 提供了一个 Python 接口来剖析你的一大块代码。它帮助开发者只关注最有趣的部分。

**from** **pyinstrument** **import** Profiler

profiler = Profiler()
profiler.start()

computerScatteredWaveElement()

profiler.stop()
profiler.print()

根据文件pyinstrument可以配置async功能。例如,我有一个简单的asyc函数:

import asyncio
from pyinstrument import Profilerasync def main():
  p = Profiler()
  with p:
    await asyncio.sleep(5)
  p.print()asyncio.run(main())

输出如下所示。它通过跟踪主线程来工作。任何花费在主线程之外的时间都归于await

pyinstrument 异步仿形的输出(由)

pyinstrument的一个缺点是它只能分析主线程,所以不能在多线程应用程序中使用。例如,我有一个简单的多线程代码:

def thread_function(name):
  time.sleep(2)if __name__ == "__main__":
  with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
    executor.map(thread_function, range(3))

如您所见,输出忽略了其他两个线程。

在多线程代码上使用 pyinstrument 的输出(作者:

yappi

yappi 代表另一种 python 分析器。它支持多线程、asyncio 和 gevent 代码的分析。因为它是用 C 语言设计的,所以与用 Python 设计的分析器相比,它运行得更快。它还支持对代码的特定部分进行分析。

下面是多线程应用程序的分析输出。您可以通过yappi.get_thread_stats()检查每个线程的性能。

threads = yappi.get_thread_stats()
for thread in threads:
  yappi.get_func_stats(ctx_id=thread.id).print_all()

雅皮的产量(作者:高)

py-spy

py-spy是另一个统计剖析器。一个重要的特性是,您可以将探查器附加到现有的进程上。这使得它非常适合长期运行的生产应用程序。

py-spy获取应用程序的 PID 或想要运行的 python 程序的命令行。它从不同的 python 进程中读取内存,出于安全原因,这可能是不允许的。在某些操作系统中,您需要作为根用户运行它。

sudo py-spy record -o profile.svg -- python scatter.py
# Execution time : 78.78 sec
# Or
sudo py-spy record -o profile.svg --pid <pid>

输出是一个冰柱图,类似于 snakeviz。

py-spy 的输出(作者:高 T5)

其他剖析器

在这里,我列出了一些其他选项供您探索和尝试。

扑通:一个低开销的分析器

扑通是一个低开销的分析器,自 2019 年以来一直没有开发。它具有网络风格的可视化,其中圆圈的大小基于函数所花费的时间。箭头粗细表示函数被调用的频率。

python -m plop.collector scatter.py
# Execution time : 73.72 sec
# profile output saved to profiles/scatter.py-20220418-1013-32.plop
# overhead was 1.1695748642208658e-05 per sample
# (0.0011695748642208657%)
python -m plop.viewer --datadir=profiles/

扑通的输出(由)

内存分析器

除了分析 CPU 时间,有时了解内存使用情况也很重要。 memory-profiler 是一个 python 模块,用于监控进程的内存消耗以及逐行分析内存消耗。它提供了一个装饰器接口,所以它不会创建太多的样板代码。

输出显示每一行的内存使用和增量。

内存分析器的输出(作者:

结论

希望这篇文章对你有用!我们已经讨论了何时(不)优化我们的应用程序,以及在必要时如何做。一个快速的解决方案是改进硬件,但这不是一个可持续的解决方案,因为它最终会达到硬件的极限。另一种选择是分析应用程序,并重构导致性能问题的代码部分。

有几种类型的分析器。请务必了解每种分析器的优缺点,并选择适合您的用例的分析器。如果您有任何意见或想法,请告诉我。调试愉快!干杯!

参考

https://granulate.io/introduction-to-continuous-profiling/ https://pythonspeed.com/articles/do-you-need-cluster-or-multiprocessing/

如何用 Python 找到最佳的 Wordle 首组合词

原文:https://towardsdatascience.com/how-to-find-the-best-wordle-first-combination-words-with-python-ded4b0679a5

搜索最佳的第一和第二单词组合

尼尔斯·胡内尔弗斯特在 Unsplash 上的照片

玩 Wordle 时,找到正确的字母通常是由第一个单词决定的。第一个单词越有效,我们就能得到越多的线索来把字母拼对。通常,每个人都有自己的偏好。

对于那些不知道的人来说,wordle 是一个由 Josh Wardle 创建的日常文字游戏,每天都会有一个新的文字难题需要解决。想了解更多,你可以去 https://www.nytimes.com/games/wordle/index.html 的。

在这篇文章中,我将寻找一个解决方案来使用 python 获得最好的第一个单词。这里我只使用基本的统计方法,以便于大家理解。

我将这篇文章分为 4 个部分,即:

  1. 搜索第一个单词
  2. 寻找第二个词
  3. 寻找第一个和第二个单词的组合
  4. 寻找最佳组合

搜索第一个单词

我使用了一个来自 Donald E. Knuth 的《计算机编程艺术》(TAOCP)https://www-cs-faculty.stanford.edu/~knuth/taocp.html的 数据集。数据集包含由 5 个字母(根据 wordle 上的字母限制)组成的英语单词,总共 5757 个单词。

****引用:以上数据集来自唐纳德·e·克努特教授。斯坦福大学计算机编程艺术荣誉退休教授。

我做的第一件事是导入依赖项并加载数据集文件。

**import pandas as pd
import numpy as np
import math**
**words = []
with open('sgb-words.txt') as f:
    words = [line.rstrip() for line in f]**

数据集包含以下数据。

**which
there
their
about
would
...
pupal**

第一个处理是通过删除每个单词中的相同字母来完成的。这是必要的,这样我们可以得到一个有 5 个不同字母的单词。方法如下。

**distinct_words = []
for word in words:
    distinct_words.append(list(set(word)))py**

结果会是这样的。

**[['w', 'h', 'i', 'c'],
['t', 'h', 'e', 'r'],
['t', 'h', 'e', 'i', 'r'],
['a', 'b', 'o', 'u', 't'],
['w', 'o', 'u', 'l', 'd'],
...
['p', 'u', 'a', 'l']]**

之后,我们可以得到每个字母的重量。方法很简单,就是把每个字母加起来,结果以字典的形式呈现出来。权重将决定字母出现的频率,字母出现的越频繁,字母的权重越大。

**letter_counter = {}
for word in distinct_words:
    for letter in word:
        if letter in letter_counter:
            letter_counter[letter] += 1
        else:
            letter_counter[letter] = 0py**

结果会是这样的。

**{'h': 790,
 'w': 500,
 'i': 1538,
 'c': 919,
 'e': 2657,
 't': 1461,
 'r': 1798,
 'u': 1067,
 'a': 2180,
 'o': 1682,
 'b': 668,
 'l': 1433,
 'd': 1099,
 's': 2673,
 'f': 501,
 'g': 650,
 'k': 573,
 'n': 1218,
 'y': 867,
 'p': 894,
 'v': 308,
 'm': 793,
 'q': 52,
 'j': 87,
 'x': 137,
 'z': 120}**

如果排序,结果会是这样的。

**>>> {key: val for key, val in sorted(letter_counter.items(), key = lambda x: x[1], reverse = True)}{'s': 2673,
 'e': 2657,
 'a': 2180,
 'r': 1798,
 'o': 1682,
 'i': 1538,
 't': 1461,
 'l': 1433,
 'n': 1218,
 'd': 1099,
 'u': 1067,
 'c': 919,
 'p': 894,
 'y': 867,
 'm': 793,
 'h': 790,
 'b': 668,
 'g': 650,
 'k': 573,
 'f': 501,
 'w': 500,
 'v': 308,
 'x': 137,
 'z': 120,
 'j': 87,
 'q': 52}**

从这些结果可以看出,出现频率最高的 5 个字母是searo

此外,这是以百分比表示的结果。

**>>> values = letter_counter.values()
>>> total = sum(values)
>>> percent = [value * 100\. / total for value in values]
>>> for i, letter in enumerate(letter_counter.keys()):
...    print("{}: {}".format(letter, percent[i]))h: 2.962685167822989
w: 1.8751171948246765
i: 5.767860491280705
c: 3.4464654040877556
e: 9.964372773298331
t: 5.479092443277705
r: 6.742921432589537
u: 4.00150009375586
a: 8.17551096943559
o: 6.307894243390212
b: 2.505156572285768
l: 5.374085880367523
d: 4.121507594224639
s: 10.024376523532721
f: 1.878867429214326
g: 2.4376523532720795
k: 2.148884305269079
n: 4.567785486592912
y: 3.2514532158259892
p: 3.3527095443465216
v: 1.1550721920120008
m: 2.973935870991937
q: 0.19501218826176636
j: 0.3262703918994937
x: 0.5137821113819614**

接下来,我们只需要找到字母权重最高的单词。方法如下。

**word_values = []
for word in distinct_words:
    temp_value = 0
    for letter in word:
        temp_value += letter_counter[letter]
    word_values.append(temp_value)
words[np.argmax(word_values)]**

而结果是arose。如果从上面的数据来看,可以看到单词arose 的字母具有很高的权重。因此,根据统计结果,我们可以得出结论,单词arose 是用在单词的第一个单词中的最佳单词。

但是仅仅第一个词就够了吗?

有时候我们需要多一个字才能得到足够的线索。因此,我们将搜索另一个词。

寻找第二个词

在我们得到第一个单词后,下一步是得到第一个单词中不包含字母的单词列表。比如我们得到的第一个词是arose。所以数据集中的单词列表不能包含字母arose。如果有一个单词包含这些字母,那么这个单词将从列表中删除。方法如下。

**result_word = []
first_word_list = list(set(best_word))for word in words:
    in_word = False
    i = 0
    while i < len(first_word_list) and not in_word:
        if first_word_list[i] in word:
            in_word = True
        i += 1
    if not in_word:
        result_word.append(word)**

结果如下。

**['which',
'think',
'might',
'until',
...
'biffy']**

字数由之前的 5757 字缩减到 310 字。只剩下 5%左右的单词了。

下一步是我们将重复这个过程,就像我们搜索第一个单词一样。完整的代码如下。

**import pandas as pd
import numpy as np
import mathdef best_words(words):
    distinct_words = []
    for word in words:
        distinct_words.append(list(set(word)))
    letter_counter = {}
    for word in distinct_words:
        for letter in word:
            if letter in letter_counter:
                letter_counter[letter] += 1
            else:
                letter_counter[letter] = 0
    word_values = []
    for word in distinct_words:
        temp_value = 0
        for letter in word:
            temp_value += letter_counter[letter]
        word_values.append(temp_value)
    return word_valuesdef get_best_word(words, word_values):
    return words[np.argmax(word_values)]def remove_word_contain_letters(words, first_word):
    result_word = []
    first_word_list = list(set(first_word))

    for word in words:
        in_word = False
        i = 0
        while i < len(first_word_list) and not in_word:
            if first_word_list[i] in word:
                in_word = True
            i += 1
        if not in_word:
            result_word.append(word)
    return result_wordwords = []
with open('sgb-words.txt') as f:
    words = [line.rstrip() for line in f]word_values = best_words(words)
first_word = get_best_word(words, word_values)
second_words = remove_word_contain_letters(words, first_word)
second_values = best_words(second_words)
second_word = get_best_word(second_words, second_values)print(first_word)  # first word
print(second_word)  # second word**

第一个和第二个单词的结果是aroseunity

从上面的方法可以得出结论,aroseunity是开始 Wordle 游戏的最佳单词。但如果我们看一下上一篇帖子的字母数量统计,可以看出uy这两个字母并不在使用最多的前 10 个字母中。这表明,aroseunity这两个词可能不是最合适的词。

寻找第一个和第二个单词的组合

在这一节中,我们将讨论,以便我们可以得到两个单词,它们的字母都是出现频率最高的字母。

我们只需要重复我们以前做过的过程。如果在之前的过程中我们只使用了具有最佳值的第一个单词,那么现在我们也使用第二好的单词作为第一个单词,这样我们可以得到更多的结果变化。

步骤如下。

第一种方法是计算所有单词的值,然后根据值对单词进行排序。

**values = best_words(words)
values_index = np.argsort(values)[::-1]**

之后,我们将像以前一样搜索第一个和第二个单词。不同的是,这里我们将继续循环查找第一个和第二个单词的组合,以便产生具有最佳值的单词。

**best_val = 0
best_word_list = []
top_words = sorted(values, reverse=True)for i, idx in enumerate(values_index):
    best_word = words[idx]
    second_words = remove_word_contain_letters(words, best_word)
    second_values = best_words(second_words)
    second_best_word = get_best_word(second_words, second_values)
    temp_value = 0
    for letter in second_best_word:
        temp_value += letter_counter[letter]
    if temp_value + top_words[i] >= best_val:
        best_val = temp_value + top_words[i]
        print(best_word, second_best_word, top_words[i] + temp_value)**

结果是这样的。

**arose unity 17141
tears doily 17388
stare doily 17388
tares doily 17388
rates doily 17388
aster doily 17388
tales irony 17507
taels irony 17507
stale irony 17507
least irony 17507
tesla irony 17507
steal irony 17507
slate irony 17507
teals irony 17507
stela irony 17507
store inlay 17507
lores antic 17559
...
laird stone 17739
adorn tiles 17739
radon tiles 17739
tonal rides 17739
talon rides 17739
lined roast 17739
intro leads 17739
nitro leads 17739
nodal tries 17739**

从这些结果来看,第一列是第一个字,第二列是第二个字,第三列是第一个字和第二个字的值之和。

如果看上面的结果,aroseunity这两个词并不是价值最大的词组合。此外,有许多单词组合会获得值 17739,如果您注意单词组合中获得该值的所有字母,则是在数据集中出现最多的十个字母。所以可以得出结论,得到值 17739 的单词组合是我们能得到的最高单词组合。

但是哪个是最佳的单词组合呢?

为了得到这个问题的答案,我们需要根据字母的位置知道它们的重量。

寻找最佳组合

现在,我们将寻找最佳单词组合,作为 Wordle 游戏中的第一个和第二个单词。接下来我们需要做的是计算每个位置的字母权重。方法如下。

**letter_list =['r', 'o', 'a', 's', 't', 'l', 'i', 'n', 'e', 's']
letter_value = {}for letter in letter_list:
    letter_counter = {}
    for i in range(len(letter_list)//2):
        loc_counter = 0
        for j in range(len(words)):
            if words[j][i] == letter:
                loc_counter += 1
        letter_counter[str(i)] = loc_counter
    letter_value[letter] = letter_counter**

变量letter_list由出现次数最多的字母组成。之后,我们将从数据集中的所有单词中统计这些字母在单词的开头出现了多少次,依此类推。

letter_value的内容如下。

**{'r': {'0': 268, '1': 456, '2': 475, '3': 310, '4': 401},
 'o': {'0': 108, '1': 911, '2': 484, '3': 262, '4': 150},
 'a': {'0': 296, '1': 930, '2': 605, '3': 339, '4': 178},
 's': {'0': 724, '1': 40, '2': 248, '3': 257, '4': 1764},
 't': {'0': 376, '1': 122, '2': 280, '3': 447, '4': 360},
 'l': {'0': 271, '1': 360, '2': 388, '3': 365, '4': 202},
 'i': {'0': 74, '1': 673, '2': 516, '3': 284, '4': 45},
 'n': {'0': 118, '1': 168, '2': 410, '3': 386, '4': 203},
 'e': {'0': 129, '1': 660, '2': 397, '3': 1228, '4': 595}}**

这些结果解释了,例如,字母r作为第一个字母出现了 268 次,第二个字母出现了 456 次,等等。所以我们可以得到每个位置的值。

接下来,我们将使用letter_value来计算我们之前得到的单词组合的权重。方法如下。

**result_list = []
for i in range(len(best_word_list)):
    word_value = 0
    for word in best_word_list[i]:
        for j, letter in enumerate(word):
            if letter in letter_value:
                word_value += letter_value[letter][str(j)]
    result_list.append(word_value)**

这是结果。

**for i in range(len(result_list)):
    print(best_word_list[i], result_list[i])=== result ===['arose', 'unity'] 3219
['tears', 'doily'] 5507
['stare', 'doily'] 4148
['tares', 'doily'] 6565
...
['lined', 'roast'] 4983
['intro', 'leads'] 4282
['nitro', 'leads'] 4831
['nodal', 'tries'] 5910**

为了获得最佳的值组合,我们可以输入下面的语法。

**result_index = np.argsort(result_list)[::-1]
best_word_list[result_index[0]]**

而最好的单词组合是tonedrails

最后,这是 Wordle 首次使用 Python 系列进行单词搜索的完整代码。

**import pandas as pd
import numpy as np
import math**
**def best_words(words):
    distinct_words = []
    for word in words:
        distinct_words.append(list(set(word)))
    letter_counter = {}
    for word in distinct_words:
        for letter in word:
            if letter in letter_counter:
                letter_counter[letter] += 1
            else:
                letter_counter[letter] = 0
    word_values = []
    for word in distinct_words:
        temp_value = 0
        for letter in word:
            temp_value += letter_counter[letter]
        word_values.append(temp_value)
    return word_values**
**def get_best_word(words, word_values):
    return words[np.argmax(word_values)]**
**def remove_word_contain_letters(words, first_word):
    result_word = []
    first_word_list = list(set(first_word))

    for word in words:
        in_word = False
        i = 0
        while i < len(first_word_list) and not in_word:
            if first_word_list[i] in word:
                in_word = True
            i += 1
        if not in_word:
            result_word.append(word)
    return result_word**
**words = []
with open('sgb-words.txt') as f:
    words = [line.rstrip() for line in f]

distinct_words = []
for word in words:
    distinct_words.append(list(set(word)))
letter_counter = {}
for word in distinct_words:
    for letter in word:
        if letter in letter_counter:
            letter_counter[letter] += 1
        else:
            letter_counter[letter] = 0**
**word_values = best_words(words)
first_word = get_best_word(words, word_values)
second_words = remove_word_contain_letters(words, first_word)
second_values = best_words(second_words)
second_word = get_best_word(second_words, second_values)**
**values = best_words(words)
values_index = np.argsort(values)[::-1]**
**best_val = 0
best_word_list = []
top_words = sorted(values, reverse=True)**
**for i, idx in enumerate(values_index):
    best_word = words[idx]
    second_words = remove_word_contain_letters(words, best_word)
    second_values = best_words(second_words)
    second_best_word = get_best_word(second_words, second_values)
    temp_value = 0
    for letter in second_best_word:
        temp_value += letter_counter[letter]
    if temp_value + top_words[i] >= best_val:
        best_val = temp_value + top_words[i]
        best_word_list.append([best_word, second_best_word])

letter_list =['r', 'o', 'a', 's', 't', 'l', 'i', 'n', 'e', 's']
letter_value = {}**
**for letter in letter_list:
    letter_counter = {}
    for i in range(len(letter_list)//2):
        loc_counter = 0
        for j in range(len(words)):
            if words[j][i] == letter:
                loc_counter += 1
        letter_counter[str(i)] = loc_counter
    letter_value[letter] = letter_counter

result_list = []
for i in range(len(best_word_list)):
    word_value = 0
    for word in best_word_list[i]:
        for j, letter in enumerate(word):
            if letter in letter_value:
                word_value += letter_value[letter][str(j)]
    result_list.append(word_value)**
**result_index = np.argsort(result_list)[::-1]
print(best_word_list[result_index[0]])**

可以得出结论,单词tonedrails是开始一个 Wordle 游戏的最佳单词组合。除了单词组合中的字母是在数据集中出现最多的字母之外,这些字母还被放置在具有最高值的位置。

答案可能不是完全最优的,因为它只依赖于统计数据,而没有考虑其他因素。如果你有其他方法来获得 Wordle 游戏中的最优单词,请在评论中写下。

如何找到合适的机器学习团队

原文:https://towardsdatascience.com/how-to-find-the-right-machine-learning-team-97a4b56fbbb7

你应该问的问题和你应该避免的危险信号

阿迪·戈尔茨坦在 Unsplash 上的照片

作为机器学习专业人员,在行业内导航多种多样的 ML 角色可能会令人困惑。职称通常没有太大的帮助,因为它们会根据公司和公司内部的组织而变化。职称也往往会随着时间的推移而改变,正如我们在数据分析师到数据科学家的更名中看到的那样。

为了在就业市场上导航,为自己找到潜在的角色,你需要准备一份试探性问题的清单。这里有 3 个:

  • 他们是什么样的 ML 团队?
  • 技能差距有多大?
  • 他们拥有什么,谁是他们的客户?

让我们更深入地探讨这三个试探性的问题,以及为什么在调查 ML 就业市场时它们应该一直在你的脑海中。

他们是什么样的 ML 团队?

在成熟的科技公司(不一定是初创公司),你通常会发现 3 种类型的 ML 团队,基础、应用和研究团队:

Infra ML 团队为模型开发构建服务,他们通过 API 或 ui 为其他团队服务。一个团队可能拥有建模服务,另一个团队拥有特征工程服务,另一个团队拥有推理服务,等等。ML infra 团队致力于解决以下问题:

  • 可伸缩性:我们如何将我们的服务扩展到公司拥有的整个 ML 模型套件?
  • 效率:我们如何减少训练和服务模型的计算成本?
  • 集成:我们如何将模型预测与产品集成?我们如何处理模型推理调用失败的错误情况?
  • 自动化和抽象:我们如何自动化和抽象掉模型开发的大部分繁重工作?我们如何构建用户友好的自助服务工具,以便非技术业务合作伙伴也可以构建和部署他们自己的模型?

应用 ML 团队设计、开发、测试、部署和迭代改进 ML 模型,解决具体的业务问题,在适当的情况下使用 ML infra 团队拥有的工具。这些团队致力于解决以下问题:

  • 框架:我们如何将一个商业问题框架为一个 ML 问题?
  • 数据和特征发现:我们需要什么数据来解决这个问题?我们如何获得正确的标签,并确保它们是可靠的?我们需要什么特性,这些特性的覆盖范围是什么?
  • 实验和 A/B 测试:哪个模型最适合我们的用例?
  • 持续改进:我们应该多久重新训练一次模型?我们如何改进下一个模型版本,使其具有更多特性、更多标记数据、更好的采样或更好的模型架构?

ML 研究团队发明新的算法或模型架构,主要目标是在学术期刊和会议上发表他们的发现。它们是创新的发源地,如 ADAM 优化器、注意力机制或特定的模型架构,如 AlexNet 或 BERT。大多数人工智能研究永远不会进入生产,但当它进入生产时,它可以带来巨大的性能收益。研究团队致力于解决以下问题:

  • 我们如何在公共基准数据集上击败最新的技术水平?
  • 描述大型神经网络行为的经验标度律有哪些?
  • 为什么深度学习首先会起作用,它的局限性是什么?
  • 大型语言模型的微调到底是怎么工作的?

选择一个最符合你想做的 ML 工作的团队。根据我自己的观察,infra ML 团队倾向于吸引具有软件工程背景的人,而应用和研究 ML 团队倾向于吸引具有学术背景的人,通常是博士。这可能是因为应用和研究 ML 的角色更多地由实验驱动,这对于博士科学家来说可能比工程师更自然。

最后,避免引脚工厂,在那里模型开发人员构建模型工件并将它们交给工程师进行部署。这对每个人来说都是令人沮丧的,因为它引入了沟通开销,减慢了迭代周期,并且当生产中出现问题时,会产生不明确的所有权和相互指责。

技能差距有多大?

“我完全知道这很难,但我们会学习如何去做。”—杰夫·贝索斯

永远不会有一个角色让你具备所有必需的技能。相反,在你的个人技能和那些定义角色的技能之间总是会有差距。

这就引入了一个权衡:如果技能差距很大,你会学到更多,但你需要更长的时间来提升。如果技能差距很小,你学到的会更少,但是你会进步得更快,做出贡献也更快。

选择一个技能差距足够小的角色,你有信心能够在合理的时间内做出贡献,但避免那些你真的没有什么新东西可以学习的角色。例如,如果一个新的应用 ML 团队使用与你当前工作相同的建模技术和技术堆栈,只是在一个不同的问题领域,对你来说没有什么新的技术,这可能不是最好的职业发展。

当考虑潜在新角色的技能差距时,与“固定思维模式”相比,采用心理学家所谓的“T0”增长思维模式也是有用的:相信你会在行动中学习到你需要的技能。

他们拥有什么,谁是他们的客户?

每个团队都应该拥有一些东西,他们应该有客户。特别是,

  • infra ML 团队拥有服务,他们的客户要么是其他 infra ML 团队,要么是应用 ML 团队。
  • 应用 ML 团队拥有模型,他们的客户是公司应用和网站的用户,
  • 研究型 ML 团队拥有自己的研究领域,他们的客户大多是其他研究团队,在极少数情况下,如果一项创新足够实用,可以实现产品化,那么就可以使用基础和应用型 ML 团队。

小心那些要么不直接拥有任何东西,要么拥有一些东西但没有客户的团队。例如,如果一个应用 ML 团队不直接拥有模型,而是对其他团队拥有的模型提出建议,那么这个团队的影响将总是受到其他人的善意的限制。或者,如果一个 infra ML 团队拥有一个只有很少内部客户的服务,迟早会有人问这个问题:是否仍然需要这个服务,以及这个团队。

因此,“他们拥有什么,谁是他们的客户”是一个非常有用的危险信号探测器,当你调查新的 ML 团队时,你应该时刻记住这一点。

最后的想法

在寻找你的下一个(或第一个)ML 团队时,永远记住这三个问题:

  • 他们是什么样的 ML 团队?基础、应用还是研究?
  • 技能差距是什么,你对此感到舒服吗?有新的东西让你学习吗?
  • 他们拥有什么,谁是他们的客户?如果他们什么都不拥有,他们如何创造影响力?如果他们没有客户,为什么需要他们?

最后,正如角色和头衔会随着时间的推移而改变一样,你自己的偏好也会随之改变。就我个人而言,我开始了我的 ML 研究之旅,但很快就转向了应用 ML,因为我更喜欢创造现实世界影响的前景,而不是发表可能很快被遗忘的论文。我还知道一些同行从应用 ML 转到基础 ML,因为他们不喜欢进行 ML 实验的不可预测性,或者因为他们想学习新的技能。

永远记住,这是你的职业,如果你不为自己的最大利益着想,别人也不会。做出能让你达到目标的选择。

📫 订阅 把我的下一篇文章直接发到你的收件箱。
💪
成为中等会员 并解锁无限权限。
📖
获取我的电子书 获取更多实用的 ML 见解。

如何在你的机器学习模型中找到弱点

原文:https://towardsdatascience.com/how-to-find-weaknesses-in-your-machine-learning-models-3bcce3c7d71e

IBM 的 FreaAI 的一种可能实现

任何时候使用汇总统计简化数据,都会丢失信息。模型精度也不例外。当将模型简化为汇总统计数据时,您将无法确定哪里的性能最低/最高以及原因。

图 1:使用 IBM FreaAI 的 POC 训练的最低精度决策树。图片作者。

在这篇文章中,我们讨论了 IBM 的 FreaAI 背后的代码,这是一种识别低精度数据切片的有效方法。在以前的帖子中,我们在高层次上讨论了方法,并深入利用 HPD 来找到模型弱点的区域。在这里,我们将通过一个二进制分类器论文的 MVP 实现。

事不宜迟,我们开始吧。

0 —技术概述

FreaAI 是确定表现不佳的数据区域的有效方法。它通过利用最高先验密度(HPD)方法和决策树来搜索我们的特征空间,并找到精确度最低的地方。从那里,可解释的数据切片被返回给工程师。

FreaAI 提出了一个解决方案来模拟可解释性、偏差和概化。

1 —设置

在第 1 部分,我们将快速回顾一下我们在之前的帖子中所涵盖的内容。

1.1 —获取数据

首先,我们需要在这里下载我们的分类数据。这是 CC0 授权的,属于公有领域。数据如下图 2 所示…

图 2:数据集的最后 4 列— src 。图片作者。

import pandas as pd
df = pd.read_csv('DiabetesData/pima-indians-diabetes.data.csv', header=None)

我们还将创建一些虚拟分类列,它们应该会产生非常嘈杂的结果…

# add some more columns for fun (one hot encoded categorical)
np.random.seed(0)
enc_df = pd.DataFrame(dict(
        color=['red' if x > 0.25 else 'green' for x in np.random.rand(len(df.index))],
        gender=['male' if x > 0.55 else 'female' for x in np.random.rand(len(df.index))]
))enc = OneHotEncoder(handle_unknown='ignore')
enc_df = pd.DataFrame(enc.fit_transform(enc_df[['color','gender']]).toarray())df = pd.concat([df, enc_df], ignore_index=True, axis=1)df.columns = ['num_pregnancies','glucose','blood_pressure','skin_thickness','insulin','bmi','diabetes_pedigree','age','outcome', 'color_red','color_green','gender_male','gender_female']

1.2 —训练一个黑盒模型

接下来,我们训练一个 XGBoost 模型…

# split data into X and y
mask = np.array(list(df)) == 'outcome'
X = df.loc[:,~mask]
Y = df.loc[:,mask]# split data into train and test sets
seed = 7
test_size = 0.33
X_train, X_test, y_train, y_test = train_test_split(
                                     X, Y,
                                     test_size=test_size, 
                                     random_state=seed)# fit model no training data
model = XGBClassifier()
model.fit(X_train, y_train)# make predictions for test data
y_pred = model.predict(X_test)
predictions = [round(value) for value in y_pred]# evaluate predictions
accuracy = accuracy_score(y_test, predictions)
print("Accuracy: %.2f%%" % (accuracy * 100.0))# add accuracy and return
out = pd.concat([X_test, y_test], axis=1, ignore_index=True)
out.columns = list(df)accuracy_bool = (np.array(y_test).flatten() ==
                 np.array(predictions))out['accuracy_bool'] = accuracy_bool
out

使用上述配置,该模型实现了约 71%的准确性。为了使这种准确性具有可操作性,我们还创建了一个列accuracy_bool,如果标签预测正确,它就是True的布尔值,否则就是False

太好了,我们都赶上了。

2-训练可解释的决策树

好了,让我们慢一点,真正理解我们代码中的决策树(DT)部分。与最高先验密度方法一样,我们希望找出数据中表现出异常低准确性的区域。因此,我们训练了一个决策树,其中我们的…

  • 特性是 XGBoost 模型中使用的一个或两个特性。
  • 目标变量是上面创建的accuracy_bool列。

我们限制一个或两个特性的原因是为了确保数据切片是可解释的,从而是可用的。让我们看一个例子…

首先,我们创建一个简单的助手来训练我们的决策树。

def fit_DT(df, predictors = ['age']):
    """ Fit binary classifier""" X = df[predictors] 
    y = df['accuracy_bool'] model = DecisionTreeClassifier(max_depth=3, 
                                   criterion='entropy',
                                   random_state=1)
    model.fit(X, y) preds = model.predict(X)
    acc = accuracy_score(y, preds) return model, preds, acc, X

有了这个助手,我们能够将感兴趣的特性传递给predictors参数,并(希望)得到低精度的分割。

2.1 —单变量决策树

作为一个例子,让我们使用数字列age,然后使用 sklearn 中的 export_graphviz 函数将其可视化。

图 3:根据年龄训练的决策树。图片作者。

在图 3 中,每个节点(蓝框)对应一个数据片。叶子最有可能有“小”的sample大小和最极端的entropy,所以我们关注它们。更具体地说,我们在寻找…

  1. 具有低熵(高节点纯度)
  2. 有足够的样本量是有用的
  3. 相对于我们 71%的基线显示出较低的准确性

贯穿以上逻辑,我们可以看到节点 3、4、12 有熵< 0.3. Node 12 we can immediately throw out because it has 2 samples, making it pretty useless. Nodes 3 and 4 have sufficient sample size, however their accuracy is 94.7% and 95.8% respectively, indicating they 突出模型优势而不是弱势。

也许我们选择了一个非常健壮的列,所以让我们继续看另一个例子。

2.2 —二元决策树

这里,我们将利用决策树处理多个特性的能力,这有助于我们理解特性交互。在这个例子中,感兴趣的特征是diabetes_pedigreeblood_pressure

图 4:在血压和葡萄糖上训练的决策树。图片作者。

利用 sklearn 的 graph_viz 库中的filled=True参数,我们可以看到,在图 4 中,橙色节点在第一个索引中的values比第二个索引中的多,这表明我们的错误分类比分类多。

同样,通过上述标准,我们正在寻找具有足够样本量和低精度的纯叶。节点 10、11 和 12 清楚地显示了低准确度的区域,但是它们具有相对较低的样本大小。使用values[1] / sum(values)计算的节点 9 的准确率为 55%,比我们的基线 71%低 16 个百分点。应该进一步探索这些节点。

然而,在深入之前,让我们停下来欣赏一下这个决策树中模型/特性的可解释性。

  • 对于glucose ≤ 104.5 的人,我们展示了 88%的准确率,如我们的根节点所示。如果glucose ≤ 87.5,我们展示 100%的准确性,如节点 2 所示。葡萄糖在其分布的左侧是一个极其有用的特征。
  • 对于glucose > 104.5、blood_pressure > 91.0 的人,我们的准确率下降到 18%。无论是高 **blood_pressure** 还是 **glucose** 都是我们数据的噪音区。

我不是糖尿病专家,但理想情况下,如果你正在做这样的项目,你(或你的队友)可以评估这些结论,看看它们是否有意义。如果没有,可能是数据有问题。

现在,尽管我们缺乏糖尿病知识,但我们可以通过利用来自 dtreeviz 库的可视化来继续分析…

图 5:数据绘图决策树适合血压和葡萄糖。图片作者。

在图 5 中,我们有与图 4 完全相同的决策树,但是这次我们在每个节点/叶绘制数据分布。

很快,我们就能发现一些异常。对于我们最右边的决策路径,我们可以看到我们最右边的叶子对应于葡萄糖非常高的 5 个错误分类,这与先前树的结论一致。此外,我们在最左边的叶子上获得了一张非常好的高精度区域的图片——这只是根分布的一部分,其中glucose ≤ 87.5。

太好了!现在我们已经讨论了关键的可视化,让我们讨论这个二元特征空间的下一步。我们的代码返回我们有问题的数据片的索引。

例如,对于节点 11,这 6 个数据点的行索引是:【58,87,105,108,222,230】。从那里,好的老式 EDA 将有望产生更多的见解。

为了简洁起见,我们不会涉及这些步骤,但希望您能有所了解。

3-识别精确度差的切片

现在,我们已经走过了一个非常具体的例子,让我们把所有的东西放在一个元分析我们的模型。

在本节中,我们将为每个变量以及变量的所有组合创建一个可视化的树。然而,为了减少查看每个可视化的手动负担,我们将精度输出到一个可排序的数据框中。

图 6:我们的元分析的输出。图片作者。

如图 6 所示,我们的输出包括 4 列:

  1. names:HPD 的特征名称或百分位数
  2. indices:该数据切片的行索引
  3. accuracies:数据切片的准确性
  4. method:我们是否使用了决策树(DT)或最高先验密度(HPD)

首先,你会注意到最低精度的分割来自二元决策树。我们创建了一些虚拟列(gendercolor)来测试分类变量拟合,正如所料,它们显示了许多低精度区域。

或者第一个“真正的”有问题的交互来自于blood_pressurenum_pregnancies。如果我们有兴趣深入研究,我们可以研究数据框中返回的索引,看看决策树认为哪些行有问题。

我们还可以看到,HPD 的当前实现对于确定低精度切片不是非常有效——最弱的切片表现出 66%的精度。虽然 HPD 超级有效,但被训练来根据节点纯度进行分割的决策树会发现较弱的切片是有道理的。

最后,这只是一个拙劣地拼凑成 POC 的虚拟示例。这个基线可以得到显著的改进,IBM 的 FreaAI 实现无疑有更多的功能和优化。随意使用这个代码作为起点:)

4 —总结和后续步骤

概括地说,在这篇文章中,我们介绍了 IBM 的 FreaAI 的一个潜在实现。该方法在黑盒模型性能较低的地方找到可解释的数据片段。然后将这些返回给工程师进行纠正。

这个实现对于我们的玩具例子是有效的,但是还有许多可能的改进,这里列出了其中的一些…

  • 支持多类分类
  • 支持回归
  • 数据切片上的统计显著性计算(带 FDR 校正)
  • 模块化成类

感谢阅读!我会再写 19 篇文章,把学术研究带到 DS 行业。查看我的评论,链接到这篇文章的主要来源和一些有用的资源。

如何使用转换器微调 NLP 回归模型

原文:https://towardsdatascience.com/how-to-fine-tune-an-nlp-regression-model-with-transformers-and-huggingface-94b2ed6f798f

从数据预处理到使用的完整指南

照片由 DeepMindUnsplash 上拍摄

HuggingFace 这样的在线图书馆为我们提供了最先进的预训练人工智能模型,可以用于数据科学的许多不同应用。在本帖中,我们将向您展示如何使用预先训练好的模型来解决回归问题。我们将使用的预训练模型是 DistilBERT,它是著名的 BERT 的更轻、更快的版本,其性能为 95%。

假设我们有来自在线广告的文本,并且它的响应率被广告集标准化了。我们的目标是创建一个可以预测广告效果的机器学习模型。

让我们通过导入必要的库并导入我们的数据来开始编码:

import numpy as np
import pandas as pdimport transformers
from datasets import Dataset,load_dataset, load_from_disk
from transformers import AutoTokenizer, AutoModelForSequenceClassificationX=pd.read_csv('ad_data.csv')
X.head(3)

文本代表广告文本,而标签是标准化回复率。

熊猫到数据集

为了使用我们的数据进行训练,我们需要将 Pandas 数据帧转换为“数据集格式。此外,我们希望将数据分为训练和测试,以便我们可以评估模型。这些可以通过运行以下命令轻松完成:

dataset = Dataset.from_pandas(X,preserve_index=False) 
dataset = dataset.train_test_split(test_size=0.3) dataset

如您所见,数据集对象包含训练集和测试集。您仍然可以访问如下所示的数据:

dataset['train']['text'][:5]

令牌化&如何添加新令牌

我们将使用一个预训练的模型,因此我们需要导入它的标记器并标记我们的数据。

tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")

让我们来标记一个句子,看看我们得到了什么:

tokenizer('🚨 JUNE DROP LIVE 🚨')['input_ids']

我们可以解码这些 id 并看到实际的令牌:

[tokenizer.decode(i) for i in tokenizer('🚨 JUNE DROP LIVE 🚨')['input_ids']]

【CLS】【SEP】是特殊的标记,总是出现在句子的开头和结尾。如你所见,代替表情符号的是🚨是【UNK】令牌,表示令牌未知。这是因为预先训练好的模型蒸馏器的单词袋里没有表情符号。但是,我们可以向标记器添加更多的标记,以便在我们根据数据调整模型时可以对它们进行训练。让我们给我们的符号化器添加一些表情符号。

for i in ['🚨', '🙂', '😍', '✌️' , '🤩 ']:
    tokenizer.add_tokens(i)

现在,如果你将句子符号化,你会看到表情符号仍然是表情符号,而不是[UNK]符号。

[tokenizer.decode(i) for i in tokenizer('🚨 JUNE DROP LIVE 🚨')['input_ids']]

下一步是对数据进行标记。

def tokenize_function(examples):
    return tokenizer(examples["text"], padding="max_length", truncation=True)tokenized_datasets = dataset.map(tokenize_function, batched=True)

微调模型

是时候导入预先训练好的模型了。

model = AutoModelForSequenceClassification.from_pretrained("distilbert-base-uncased", num_labels=1)

根据文档,对于回归问题,我们必须通过 num_labels=1

现在,我们需要调整令牌嵌入的大小,因为我们向令牌化器添加了更多的令牌。

model.resize_token_embeddings(len(tokenizer))

度量函数

在回归问题中,您试图预测一个连续值。因此,您需要度量预测值和真实值之间距离的指标。最常见的指标是 MSE(均方误差)和 RMSE(均方根误差)。对于这个应用程序,我们将使用 RMSE,我们需要创建一个函数在训练数据时使用它。

from datasets import load_metric def compute_metrics(eval_pred):
    predictions, labels = eval_pred
    rmse = mean_squared_error(labels, predictions, squared=False)
    return {"rmse": rmse}

训练模型

from transformers import TrainingArguments, Trainertraining_args = TrainingArguments(output_dir="test_trainer",
                                  logging_strategy="epoch",
                                  evaluation_strategy="epoch",
                                  per_device_train_batch_size=16,
                                  per_device_eval_batch_size=16,
                                  num_train_epochs=3,
                                  save_total_limit = 2,
                                  save_strategy = 'no',
                                  load_best_model_at_end=False
                                  ) trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["test"],
    compute_metrics=compute_metrics
)
trainer.train()

保存并加载预训练的模型和标记器

要保存和加载模型,请运行以下命令:

# save the model/tokenizermodel.save_pretrained("model")
tokenizer.save_pretrained("tokenizer")# load the model/tokenizerfrom transformers import AutoModelForTokenClassification
model = AutoModelForSequenceClassification.from_pretrained("model")
tokenizer = AutoTokenizer.from_pretrained("tokenizer")

如何使用模型

一旦我们加载了记号赋予器和模型,我们就可以使用 Transformer 的训练器从文本输入中获得预测。我创建了一个函数,它将文本作为输入并返回预测。我们需要做的步骤如下:

  1. 将数据帧中的文本添加到名为 text 的列中。
  2. 将数据帧转换为数据集。
  3. 将数据集标记化。
  4. 使用培训师进行预测。

当然,你可以不用一个函数来处理多个输入。这样,它会更快,因为它使用批次做预测。

from transformers import Trainer
trainer = Trainer(model=model)def tokenize_function(examples):
    return tokenizer(examples["text"], padding="max_length", truncation=True) def pipeline_prediction(text):
    df=pd.DataFrame({'text':[text]})
    dataset = Dataset.from_pandas(df,preserve_index=False) 
    tokenized_datasets = dataset.map(tokenize_function)
    raw_pred, _, _ = trainer.predict(tokenized_datasets) 
    return(raw_pred[0][0])pipeline_prediction("🚨 Get 50% now!")-0.019468416

总结一下

在这篇文章中,我们向您展示了如何使用预先训练好的模型来解决回归问题。我们使用 Huggingface 的 transformers 库来加载预训练的模型 DistilBERT,并根据我们的数据对其进行微调。我认为 transformer 模型非常强大,如果使用得当,可以比 word2vec 和 TF-IDF 等更经典的单词嵌入方法产生更好的结果。

想从我这里得到更多?: 在媒体 上关注我在
中链接的上添加我通过使用 我的推荐链接 注册媒体来支持我。

如何使用 Dreambooth 微调稳定扩散

原文:https://towardsdatascience.com/how-to-fine-tune-stable-diffusion-using-dreambooth-dfa6694524ae

带有自定义样式或对象的个性化生成图像

作者图片

之前,我已经写过一篇关于使用文本反转对稳定扩散进行微调的文章。本教程重点介绍如何使用另一种叫做 Dreambooth 的方法来微调稳定扩散。与只训练嵌入而不修改基本模型的文本反转方法不同,Dreambooth 微调整个文本到图像模型,以便它学习将唯一标识符与特定概念(对象或样式)绑定。因此,与文本反转相比,生成的图像对于对象或风格来说更加个性化。

本教程基于 HuggingFace 的 Dreambooth 实现的分叉版本。最初的实现需要大约 16GB 到 24GB 来微调模型。维护者 ShivamShrirao 优化了代码,将 VRAM 的使用减少到 16GB 以下。根据您的需求和设置,您可以使用 10GB 至 16GB 的 GPU 对模型进行微调。我亲自测试了在特斯拉 T4 GPU 上的训练是可行的。

请注意,所有现有的实现都不是由 Dreambooth 的原作者实现的。因此,在再现性方面可能会有细微的差别。

让我们继续下一部分来设置所有必要的模块。

设置

建议在继续安装之前创建一个新的虚拟环境。

Python 包

在您的工作目录中,使用以下代码创建一个名为requirements.txt的新文件:

accelerate==0.12.0
torchvision
transformers>=4.21.0
ftfy
tensorboard
modelcards

激活您的虚拟环境,并逐一运行以下命令来安装所有必需的模块:

pip install git+https://github.com/ShivamShrirao/diffusers.git
pip install -r requirements.txt

注意:你需要使用上面的网址安装*diffusers*,而不是直接从*pypi*安装。

bitsandbytes 包

有一个名为bitsandbytes的可选包,可以进一步减少 VRAM 的使用。但是,它仅支持 CUDA 版本 10.2–11.7,并且您的机器必须满足以下要求:

  • LLM.int8():英伟达图灵(RTX 20xx;T4)或安培 GPU(RTX 30xx;a4-A100);(2018 年或更老的一款 GPU)。
  • 8-bit optimizers and quantization:英伟达 Maxwell GPU 或更新(> =GTX 9XX)。

您可以按如下方式安装它:

pip install bitsandbytes

变压器包

对于 GPU 小于 24GB 的用户,您需要安装xformers包来进一步减少 VRAM 的使用。在撰写本文时,安装xformers并不是那么简单,因为缺乏开发者的支持。

您可以按如下方式安装软件包:

pip install xformers

如果您在使用上面的命令时遇到错误,请运行以下命令直接从存储库构建软件包:

pip install git+https://github.com/facebookresearch/xformers.git@main#egg=xformers

如果你有 CUDA 版本的问题,确保你安装了与你的机器兼容的 CUDA 的最新版本。遵循跟随链接的指示。

加速设置

下一步是初始化一个Accelerate环境。运行以下命令:

accelerate config

终端会有多个提示。结合自己的用例来回答。看看下面的例子作为参考:

In which compute environment are you running? ([0] This machine, [1] AWS (Amazon SageMaker)): 0
Which type of machine are you using? ([0] No distributed training, [1] multi-CPU, [2] multi-GPU, [3] TPU [4] MPS): 0
Do you want to run your training on CPU only (even if a GPU is available)? [yes/NO]:no
Do you want to use DeepSpeed? [yes/NO]: no
Do you wish to use FP16 or BF16 (mixed precision)? [NO/fp16/bf16]: fp16

拥抱脸的模型

如果你已经有了稳定扩散的diffusers模型(v1.4/v1.5),可以跳过这一节。对于那些

你必须使用diffusers模型而不是ckpt文件进行微调。您可以使用下面的脚本将您的ckpt文件转换为diffusers模型。

在 HuggingFace 中注册一个新帐户,并在下载或使用重量之前接受模型许可。

一旦完成,请参考文档的这一部分来启用访问令牌。

运行以下命令并传递您的令牌进行身份验证:

huggingface-cli login

它会在初次运行时将权重下载到缓存文件夹中。

数据集

您需要收集高质量的数据集,以获得一致和良好的结果。训练图像应该与预期的输出相匹配,并且分辨率调整为 512 x 512。

请注意,运动模糊或低分辨率等伪像会影响生成的图像。这适用于训练数据集中任何不需要的文本、水印或图标。请务必注意您用于培训的数据集。

根据您的使用情况,您可以使用以下准则:

目标

使用带有普通背景的物体图像。透明背景可能会在对象周围留下边缘或边框。所有训练图像应仅聚焦于物体,并在以下方面有所变化:

  • 照像镜头视角
  • 姿态
  • 道具(服装、发型等。)
  • 背景(在不同地点拍摄)

训练图像的数量应该在 5 到 20 左右。您可能需要裁剪图像,以便只关注对象。

风格

使用你喜欢的风格的图片。可以是你自己的艺术收藏,也可以是风格一致的公共电影/动画/电视剧。所有的训练图像应该集中在风格上,而不是一个特定的对象。

为了更好地概括它,您应该确保同一个对象不会在训练图像中出现超过一次(每个角色一个)。如果你的目标是生成同一风格的不同角色。包括带有字符的训练图像。否则,在训练数据集中包括风景、物体和其他相关图像。

训练图像

在本教程中,我将使用以下训练图像:

作者图片

本教程对训练数据集使用以下术语。

  • Instance images —代表 dreambooth 培训特定概念的自定义图像。您应该根据您的用例收集高质量的图像。
  • Class images —正则化先前保存损失的图像,以防止过拟合。您应该直接从基础预训练模型生成这些图像。您可以选择自己生成它们,或者在运行培训脚本时动态生成它们。

培养

前往下面的 Github 库中的并将[train_dreambooth.py](https://github.com/ShivamShrirao/diffusers/blob/main/examples/dreambooth/train_dreambooth.py)文件下载到您的工作目录中。

训练命令

以下是应根据您的使用情况进行修改的常见参数列表:

  • pretrained_model_name_or_path —从 huggingface.co/models 到预训练模型或模型标识符的路径
  • pretrained_vae_name_or_path —从 huggingface.co/models.到预训练 vae 或 vae 标识符的路径您可以微调带或不带 vae 的模型
  • instance_data_dir —包含实例图像训练数据的文件夹
  • class_data_dir —包含类别图像的训练数据的文件夹
  • instance_prompt —带有指定实例的标识符的提示
  • class_prompt —提示指定与提供的实例图像在同一类中的图像
  • num_class_images —先前保存损失的最小类别图像
  • output_dir-将写入模型预测和检查点的输出目录
  • max_train_steps —要执行的训练步骤总数。建议设置为N * 100,其中N代表实例图像的数量。
  • learning_rate —要使用的初始学习率(在潜在的预热期之后)
  • lr_scheduler —要使用的调度程序类型。在[ linearcosinecosine_with_restartspolynomialconstantconstant_with_warmup之间选择
  • lr_warmup_steps—lr 调度程序中预热的步骤数。使用polynomial时使用max_train_steps / 10或使用constant时使用0
  • save_interval —每 N 步保存一次重量。确保你有足够的存储空间。每个重量在 4GB 左右。

您可以使用以下标志设置自定义值:

--pretrained_vae_name_or_path="stabilityai/sd-vae-ft-mse"

用先前保存损失进行训练有助于防止过度拟合。按如下方式启用它:

--with_prior_preservation --prior_loss_weight=1.0

此外,您可以随unet一起微调text_encoder。然而,这将大大增加 VRAM 的使用。用以下标志设置它:

--train_text_encoder

对于对象训练,可以用下面的例子作为instance_promptclass_prompt的参考。请根据您的用例随意试验不同的字符串。

# Woman
--instance_prompt="photo of zwx woman" \
--class_prompt="photo of a woman" \

# Black man
--instance_prompt="photo of zwx black man" \
--class_prompt="photo of a black man" \

# Dog
--instance_prompt="photo of zwx dog" \
--class_prompt="photo of a dog" \

您可以使用自己的自定义字符串作为唯一标识符。在早期的实现中,大多数例子使用sks作为惟一标识符。然而,sks是一种半自动步枪的已知代币。强烈建议使用不同的唯一标识符,该标识符不是原始稳定扩散数据集中使用的令牌的一部分。

此外,唯一标识符不限于单个字符串。一些用户报告了良好的表现,并提示进行以下风格训练:

# Style 1
--instance_prompt="modern disney style" \
--class_prompt="artwork style" \

# Style 2
--instance_prompt="classic animation style" \
--class_prompt="illustration style" \

关于学习率和调度器,敬请参考 HuggingFace 的以下博客

培训示例

看一下上面训练图像的示例训练命令(在 16GB 内存的特斯拉 T4 上测试):

accelerate launch train_dreambooth.py \
  --pretrained_model_name_or_path="runwayml/stable-diffusion-v1-5" \
  --pretrained_vae_name_or_path="stabilityai/sd-vae-ft-mse" \
  --instance_data_dir="./instance-images/" \
  --class_data_dir="./class-images/" \
  --output_dir="./output-models/" \
  --with_prior_preservation --prior_loss_weight=1.0 \
  --instance_prompt="photo of zwx bear toy" \
  --class_prompt="photo of bear toy" \
  --resolution=512 \
  --train_batch_size=1 \
  --train_text_encoder \
  --mixed_precision="fp16" \
  --use_8bit_adam \
  --gradient_accumulation_steps=1 \
  --gradient_checkpointing \
  --learning_rate=1e-6 \
  --lr_scheduler="constant" \
  --lr_warmup_steps=200 \
  --num_class_images=300 \
  --max_train_steps=2000 \
  --save_interval=500

根据您的工作目录相应地修改数据目录。

如果您的内存不足,请关闭text_encoder训练:

accelerate launch train_dreambooth.py \
  --pretrained_model_name_or_path="runwayml/stable-diffusion-v1-5" \
  --instance_data_dir="./instance-images/" \
  --class_data_dir="./class-images/" \
  --output_dir="./output-models/" \
  --with_prior_preservation --prior_loss_weight=1.0 \
  --instance_prompt="photo of zwx bear toy" \
  --class_prompt="photo of bear toy" \
  --resolution=512 \
  --train_batch_size=1 \
  --mixed_precision="fp16" \
  --use_8bit_adam \
  --gradient_accumulation_steps=1 \
  --gradient_checkpointing \
  --learning_rate=1e-6 \
  --lr_scheduler="constant" \
  --lr_warmup_steps=0 \
  --num_class_images=300 \
  --max_train_steps=2000 \
  --save_interval=500

请确保不要过度训练您的模型,因为 Dreambooth 方法往往会很快过度拟合。如果您的模型不能很好地概括您的提示,或者上面有工件,这很可能意味着您过度训练了您的模型。请减少训练步数或使用较低的学习率进行较高的步数训练。

而且,最新的训练脚本接受了一个名为concept_list的新参数。它表示包含字典列表的 JSON 文件的路径。它将覆盖instance_promptclass_prompt等参数。您可以使用它将多个概念同时训练到一个模型中。例如,给出下面的concept_list.json文件:

[
    {
        "instance_prompt":      "photo of zwx dog",
        "class_prompt":         "photo of a dog",
        "instance_data_dir":    "./instance-images/",
        "class_data_dir":       "./class-images/"
    }
]

您可以在 training 命令中使用以下参数:

--concepts_list ./concepts_list.json

只需在列表中添加一个新词典,同时训练另一个概念。

当您第一次运行它时,它将生成类图像。您可以在后续培训中重复使用相同的课程图像,只要您引用的是相同的概念。只需将class_data_dir设置为与您之前的培训相同的目录。因此,在为特定风格进行训练时,您可以重用大多数生成的类图像。

以下是为本教程生成的一些类图像:

作者图片

培训产出

该脚本将根据 save_interval的值在每个间隔上保存一个新的权重。在每个新生成的权重文件夹中,应该有以下文件和文件夹:

|- feature_extractor
|  |- preprocessor_config.json
|- scheduler
|  |- scheduler_config.json
|- text_encoder
|  |- config.json
|  |- pytorch_model.bin
|- tokenizer
|  |- merges.txt
|  |- special_tokens_map.json
|  |- tokenizer_config.json
|  |- vocab.json
|- unet
|  |- config.json
|  |- diffusion_pytorch_model.bin
|- vae
|  |- config.json
|  |- diffusion_pytorch_model.bin
|- args.json
|- model_index.json

推理

现在,在您的工作目录中创建一个名为inference.py的新 Python 文件。在其中追加以下代码:

from diffusers import StableDiffusionPipeline, DDIMScheduler
import torch

device = "cuda"
# use DDIM scheduler, you can modify it to use other scheduler
scheduler = DDIMScheduler(beta_start=0.00085, beta_end=0.012, beta_schedule="scaled_linear", clip_sample=False, set_alpha_to_one=True)

# modify the model path
pipe = StableDiffusionPipeline.from_pretrained(
    f"./output-models/1500/",
    scheduler=scheduler,
    safety_checker=None,
    torch_dtype=torch.float16,
).to(device)

# enable xformers memory attention
pipe.enable_xformers_memory_efficient_attention()

prompt = "photo of zwx bear toy"
negative_prompt = ""
num_samples = 4
guidance_scale = 7.5
num_inference_steps = 50
height = 512
width = 512

images = pipe(
    prompt,
    height=height,
    width=width,
    negative_prompt=negative_prompt,
    num_images_per_prompt=num_samples,
    num_inference_steps=num_inference_steps,
    guidance_scale=guidance_scale
).images

count = 1
for image in images:
    # save image to local directory
    image.save(f"img-{count}.png")
    count += 1

一些用户报告称,使用xformers生成图像会导致不确定的结果。这意味着您不能使用相同的设置(种子、图像大小等)复制相同的图像。).请自行试验,并根据您的用例相应地修改代码。

完成后,运行下面的命令,使用新调整的模型生成图像。

python inference.py

以下是一些示例输出(没有包括提示,因为我犯了一个错误,最初没有跟踪它们):

作者图片

考虑一下我关于训练有条件/无条件图像生成模型的其他文章:

结论

Dreambooth 是一种用特定概念(对象或样式)微调稳定扩散模型的好技术。

随着人工智能研究和开发的进步,现在普通人可以微调他们自己的定制模型。然而,对于艺术行业来说,这可能是一把机遇和挑战并存的双刃剑。

如果你是艺术家行业的一员,建议你接受并使用这项技术来简化你的工作流程。此外,如果每个人都能明智地使用这项技术来造福人类,那就太好了。

不幸的是,目前我没有足够的内存来使用图像和标题对整个模型进行微调。

感谢你阅读这篇文章。祝你有美好的一天!

参考

  1. 抱紧面部扩散器 Github
  2. shivamshriao 的 Dreambooth Github

如何使用文本反转微调稳定扩散

原文:https://towardsdatascience.com/how-to-fine-tune-stable-diffusion-using-textual-inversion-b995d7ecc095

带有自定义样式或对象的个性化生成图像

人工智能使用提示“一张机器人在野外、自然、丛林中绘画的照片”生成图像

2022 年 8 月 22 日,稳定。艾宣布稳定扩散公开发布,强大的潜文本到图像扩散模型。给定任何文本或图像作为输入,该模型能够生成图像的不同变体。

请注意

…该车型将在 Creative ML OpenRAIL-M 许可下发布。该许可证允许商业和非商业使用。合乎道德地使用模型是开发人员的责任。这包括模型的导数。

本教程侧重于如何微调嵌入,以创建基于自定义样式或对象的个性化图像。我们可以在模型的嵌入空间中将自定义样式或对象表示为新单词,而不是重新训练模型。因此,新单词将以直观的方式指导新图像的创建。

看看下面真实生活对象和使用稳定扩散模型和微调嵌入生成的图像之间的比较:

作者图片

让我们继续下一节的设置和安装。

装置

请注意,本教程是基于稳定扩散的分叉版本,它集成了文本反转以个性化图像生成。官方资源库推荐使用 Anaconda 进行安装。

请参考以下指南来安装所有必需的依赖项:

如果您打算通过pip install安装依赖项,请使用下面的需求文件:

pip install -r requirements.txt

如果安装有问题,请参考以下故障排除指南中的

确保在工作目录或中有所有需要的模型和检查点。缓存文件夹。

或者,你可以在 Google Colab 上使用下面的稳定扩散 AI 笔记本进行测试。按照说明在隔离环境中运行稳定扩散。

数据准备

首先,在根目录下创建一个名为training_data的文件夹(stable-diffusion)。我们将把所有的训练图像放在里面。您可以将它们命名为您喜欢的任何名称,但它必须具有以下属性:

  • 图像尺寸为 512 x 512
  • 图像应该是垂直的
  • 大约 3 到 5 个图像可获得最佳效果(如果使用太多图像,模型可能不会收敛)
  • 图像应该有相似的上下文信息。对于基于风格的微调,配色方案和艺术风格应保持一致。对于基于对象的微调,不同视角的图像应该是同一对象(建议对前后不同的对象保持相同的朝向)。

出于演示目的,我将使用我的个人钥匙串作为基于对象的微调的训练数据。

图片由作者提供

上面的图片是用我的手机相机拍摄的。因此,我必须将它们的大小调整为 512 x 512。我在training_data文件夹中创建了两个新文件夹:

  • raw —用于需要调整大小的原始图像
  • key —所有训练图像的实际子文件夹(512 x 512)

您可以使用以下脚本作为调整训练图像大小的参考:

配置

前往<root>/configs/stable-diffusion/文件夹,你应该会看到以下文件:

  • v1-finetune.yaml
  • v1-finetune_style.yaml
  • v1-推论. yaml

v1-finetune.yaml文件用于基于对象的微调。对于基于样式的微调,您应该使用v1-finetune_style.yaml作为配置文件。

建议创建配置文件的备份,以防您弄乱了配置。

默认配置要求至少 20GB VRAM 用于培训。我们可以通过降低批处理大小和工人数量来减少内存需求。修改以下几行

data:
  target: main.DataModuleFromConfig
  params:
    batch_size: 2
    num_workers: 16...lightning:
  callbacks:
    image_logger:
      target: main.ImageLogger
      params:
        batch_frequency: 500
        max_images: 8

到下面

orkers. Modify the following linesdata:
  target: main.DataModuleFromConfig
  params:
    batch_size: 1
    num_workers: 8...lightning:
  callbacks:
    image_logger:
      target: main.ImageLogger
      params:
        batch_frequency: 500
        max_images: 1
  • batch_size从 2 到 1
  • num_workers从 16 岁到 8 岁
  • max_images从 8 点到 1 点

我已经测试了在 GeForce RTX 2080 上工作的新配置。

您可以在first_state_config下更改训练图像分辨率以减少内存。根据您的 GPU 设备,建议使用 256 或 512。

first_stage_config:
      target: ldm.models.autoencoder.AutoencoderKL
      params:
        embed_dim: 4
        monitor: val/rec_loss
        ddconfig:
          double_z: true
          z_channels: 4
          resolution: 256

此外,您将需要更改initializer_words作为嵌入输入的一部分。它接受字符串列表:

# finetuning on a toy image
initializer_words: ["toy"]# finetuning on a artstyle
initializer_words: ["futuristic", "painting"]

培养

完成后,运行以下命令:

在命令行中指定--no-test,在微调过程中忽略测试。您可以使用--init_word参数来更改initializer_words。请注意,这只适用于单个字符串。如果您打算使用多个字符串,您需要在配置文件中修改它们。

在撰写本文时,您只能进行单个 GPU 培训,并且在指定 GPU 时需要在数字末尾包含一个逗号字符。

如果一切设置正确,训练将开始,并将创建一个logs文件夹。在其中,您可以找到一个文件夹,其中包含您进行的每项培训,以及以下文件夹:

  • checkpoints —包含输出嵌入和训练检查点
  • configs—YAML 格式的配置文件
  • images —示例提示文本、提示图像和生成的图像
  • testtube —与测试相关的文件

训练将无限期运行,或者根据您在配置文件中设置的max_steps的数量运行:

trainer:
  benchmark: True
  max_steps: 4000

检查[v1-finetune.yaml](https://github.com/lstein/stable-diffusion/blob/main/configs/stable-diffusion/v1-finetune.yaml)作为参考,因为该配置不包括在v1-finetune_style.yaml中。省略它可以无限期地运行培训。

您应该检查images文件夹以了解性能。前缀为sample_scaled_的图像代表生成的样本,如果训练顺利,它应该与您的训练数据有一些相似之处。一旦达到 5000 到 7000 步,你就可以停止训练。

在 checkpoints 文件夹中,您应该会看到相当多的文件:

  • embeddings_gs-5699.pt —第 5699 步的嵌入文件
  • epoch=000010.ckpt—10 个时期的训练检查点
  • last.ckpt —上一个纪元的训练关卡
  • embeddings.pt —最后一步的嵌入文件

ckpt文件用于恢复训练。pt文件是应该与稳定扩散模型一起使用的嵌入文件。只需复制所需的嵌入文件,并将其放在方便推断的位置。

推理

交互式终端

对于命令行的使用,只需在运行./scripts/invoke.py时指定embedding_path标志。

python ./scripts/invoke.py --embedding_path /path/to/embeddings.pt

然后,在交互式终端中对 text2image 使用以下提示:

invokeai> "a photo of *"

除此之外,您还可以通过设置init_img标志来执行图像 2 成像:

invokeai> "waterfall in the style of *" --init_img=./path/to/drawing.png --strength=0.7

简化的 API

或者,您可以使用ldm.generate模块以编程方式运行推理。它带有prompt2image功能,作为 text2image 和 image2image 任务的单一端点。

请注意,旧版本包含以下功能,这些功能已被弃用,但仍然有效:

  • txt2img
  • img 2g img

关于输入参数的更多信息,请参考 Python 脚本

您可以在以下要点中找到完整的推理代码以供参考:

结果

请注意,大多数时候结果可能并不好。这个想法是生成大量的图像,并使用适合您的用例的图像。让我们看看我在微调嵌入后得到的结果。

人工智能生成的图像使用提示“水彩画的*与树木”

人工智能生成的图像使用提示“一个袋包风格的*”

人工智能使用提示“带有*标志的衬衫”生成图像

此外,我已经测试了 image2image 任务,并获得了以下输出:

图片由作者提供。右边的图像是使用提示“沙滩上的三个”生成的

考虑一下我关于训练有条件/无条件图像生成模型的其他文章:

结论

稳定扩散的发布为全世界的开发者提供了巨大的潜力和机会。这肯定会对大多数现有行业产生重大影响,影响人工智能的力量可以实现的目标。

在一周的时间内,我看到世界各地的开发人员一起构建他们自己的开源项目,从 web UI 到动画。

我期待着来自开源社区的更多伟大的工具和最先进的模型。

感谢你阅读这篇文章。祝你有美好的一天!

参考

  1. 稳定。AI —稳定扩散公开发布
  2. Github——梦幻机器人风格界面中的稳定扩散
  3. Github —文本倒置

如何在多个 GPU 上微调 YOLOv5

原文:https://towardsdatascience.com/how-to-finetune-yolov5-in-a-multi-gpu-environment-ada1935193d3

插图照片由伊万·巴比多夫派克斯拍摄

众所周知,深度学习模型往往对适当的超参数选择敏感。同时,当您搜索最佳配置时,您希望使用最大的资源…

对象检测是任何 ML/AI 尚未完全掌握的高级计算机视觉(CV)任务之一。简而言之,该任务由图像中给定对象的定位和识别/分类组成。

https://machinelearningmastery.com/object-recognition-with-deep-learning/

目标检测仍然是研究领域的一个热门话题。此外,在许多实际应用的生产中,例如场景中的人物检测或商店货架上物品的识别,使用这种人工智能模型的需求相对较高。这自然会产生一个更大的模型架构集合,甚至更多的实现作为开源项目公开共享。其中之一是 YOLO v5 ,它声称在性能(准确度/精确度)和推理时间之间有最好的比例。

除了训练和推理,该项目还提供了基于进化算法调整的运行超参数搜索。简而言之,该算法分代进行,因此它运行一些短期训练,并根据它们的性能选择最佳的。然后这些最好的混合一些微小的随机变化,再次训练。

简单的屏幕微调

搜索超参数的最简单方法是使用启用的 evolution --evolve <number>参数运行训练。但这最多只使用了一个 GPU,那么我们拥有的其余部分呢?

python train.py \
    --weights yolov5s6.pt \
    --data /home/user/Data/gbr-yolov5-train-0.1/dataset.yaml \
    --hyp data/hyps/hyp.finetune.yaml \
    --epochs 10 \
    --batch-size 4 \
    --imgsz 3000 \
    --device 0 \
    --workers 8 \
    --single-cls \
    --optimizer AdamW \
    --evolve 60

最终,我们可以进行多种培训,但是我们如何推动他们进行合作呢?幸运的是,他们可以共享一个包含转储训练结果的文件,并从中抽取新的群体。由于下一代的随机性,这看起来像是在探索一个更大的群体,正如作者所说

https://github.com/ultralytics/yolov5/issues/918

插图来自 Ultralytics 教程许可格伦·约彻

有哪些选择?

使用不同的 GPU 运行多个训练过程可以通过在--device <gpu-index>参数中指定来设置。但是如何维护众多的进程,并且在你注销或意外断开互联网连接时不丢失它们。

nohup

这是保持流程运行的第一个也是最简单的方法。

nohup python train.py ... > training.log

不幸的是,没有简单的方法将连接回曾经调度过的进程,所以它主要与重定向流到一个文件结合使用。然后,您可以不断刷新文件,但它仍然不总是能很好地播放进度条,因为进度条可能会延伸到许多行。

屏幕

这个 Unix 应用程序在许多情况下都很方便,在这里,它可以在屏幕上旋转每个进程,以后您可以在所有进程之间进行遍历。在每个屏幕中,您都可以完全控制或终止特定的进程。

screen -S training
python train.py ...

码头工人

另一种方法是使用具有共享卷的 docker 容器。其优势在于,您可以在固定的环境中准备客户 docker 映像,最终可以在任何地方运行,甚至在另一个服务器/集群上运行…

docker build -t yolov5 .
docker run --detach --ipc=host --gpus all -v ~:$(pwd) yolov5 \
  python train.py ...
docker ps

上面的命令首先从项目文件夹构建一个 docker 映像。稍后,它旋转一个容器,并立即分离它,对 GPU 完全可见,并将容器中的用户 home 映射到您的本地项目文件夹。最后一个命令是列出所有正在运行的容器。

旋转多个协作码头

您需要单独创建每个屏幕,并在屏幕中启动特定的培训过程。这些额外的工作很容易因为选择了错误的或者已经在使用的设备而被破坏。

docker 的一个优点是,我们可以快速编写一个循环,在旋转任何 docker 容器时启动与 GPU 一样多的容器。唯一的限制可能是足够的 RAM,这也可以在 docker 端用--memory 20g参数来限制。要正确利用实验的共享数据,需要修复project/name,设置exist-okresume参数。

for i in 1 2 3 4 5; do
  sudo docker run -d --ipc=host --gpus all \
    -v ~:/home/jirka \
    -v ~/gbr-yolov5/runs:/usr/src/app/runs \
    yolov5 \
  python /usr/src/app/train.py \
    --weights yolov5s6.pt \
    --data /home/jirka/gbr-yolov5-train-0.1-only_annotations/dataset.yaml \
    --hyp /usr/src/app/data/hyps/hyp.finetune.yaml \
    --epochs 10 \
    --batch-size 4 \
    --imgsz 3000 \
    --workers 8 \
    --device $i \
    --project gbr \
    --name search \
    --exist-ok \
    --resume \
    --evolve 60
done

稍后,为了重新连接到正在运行的容器,例如,为了监视进程,您可以通过将输入容器:

sudo docker ps
sudo docker attach --sig-proxy=false <container-id>

然后使用 CTRL+c 分离回您的用户终端。

最后一种情况是,您不想让培训结束,或者您需要终止您调用的所有正在运行的容器:

sudo docker kill $(sudo docker ps -q)

敬请关注,关注我了解更多!

https://www.kaggle.com/jirkaborovec/starfish-detection-flash-efficientdet

关于作者

Jirka Borovec 拥有 CTU 的计算机视觉博士学位。他已经在几家 IT 创业公司和公司从事机器学习和数据科学工作几年了。他喜欢探索有趣的世界问题,用最先进的技术解决它们,并开发开源项目。

如何修复 Jupyter 笔记本的内核错误

原文:https://towardsdatascience.com/how-to-fix-kernel-error-in-jupyter-notebook-81619e195703

让您的 python 代码运行顺畅

马特·里德利在 Unsplash 上的照片

数据科学涉及技术编程工具的使用。大多数时候,由于分析中的错误、系统兼容性、技术困难或软件开发人员的错误,这些工具变得很复杂。

所有开发人员都必须熟悉 Anaconda Navigator ,对吧?

最通用的编程软件之一,因为它携带了精通所有数据科学项目所需的最流行的工具、库和包。

在这些图书馆中有一本 Jupyter 笔记本。用于创建、开发和共享包含实时代码、可视化和叙述性文本的文件的工具。

但是,使用笔记本电脑会出现一些错误。在启动或处理项目时,很有可能会遇到内核错误。

在我们进入解决方案之前,什么是内核错误?

当您尝试在错误的目录中打开 python 3 文件时,基本上会发生内核错误。事实是 Jupyter 和 Python 是两种完全不同的软件。因此,当 Jupyter 无法连接特定版本的 Python 时,就会出现内核错误。

当系统在定位某些程序运行的路径时遇到困难,这个错误在 Jupyter Notebook 中被称为内核错误。

现在,我们已经熟悉了 Jupyter Notebook 以及错误是怎么回事,让我们深入了解解决方案。

理论够了,来点实际的吧。

1。进入工具的后端。

我们大多数人使用的 Jupyter 笔记本在 Anaconda 上运行。所以要进入后端,打开 Anaconda 命令提示符。因为您的系统中已经安装了 Anaconda,单击搜索栏,键入 Anaconda 提示符并以管理员身份运行。

以管理员身份运行该提示符非常重要,这将使系统准备好对您的软件进行必要的更改。

作者截图。

2。打开基本环境并选择您的目录。

该目录是您希望存储所有当前和未来项目的地方。用不太专业的术语来说,它就像一个巨大的文件夹,可以方便地保存你的笔记、文本文件和图书馆,以供回忆和转移。

黑屏包含一个预设目录c:/windows/system32。但是,建议您在笔记本上运行代码之前切换到首选目录。

我的大部分开发和分析都是在我的e:drive上完成的,在linux文件夹下。这是我将进一步研究库和其他分析项目的地方。输入命令,更改笔记本的目录。

作者截图。

3。为您的笔记本创建另一个环境。

大多数内核错误通常是由于笔记本无法连接其他版本的 Python 而导致的。

默认情况下,除了 Python 3,Jupyter Notebook 中没有其他虚拟环境。

CTRL + C并使用该代码创建一个新的虚拟环境。

conda create -n py

在本教程中,我们将使用py,你可以使用任何你喜欢的环境,不一定非得是py,只要确保在运行命令时用你的环境替换我的环境。

作者截图。

4。激活您刚刚创建的环境。

使用下面的代码激活它

conda activate py

激活后,您可以观察到环境已经从基本状态变为py状态,这证实了新环境的激活工作正常。

接下来呢。

5。安装 ipykernel。

使用下面的代码安装 ipykernel。

conda install ipykernel

我相信你一定在想,ipykernel 是什么?

在其早期阶段,Jupyter 笔记本曾被称为 Ipython 笔记本。因此 ipykernel 基本上是一种连接和管理所有不同内核的方法。

作者截图。

6。将内核添加到新环境中。

现在我们将运行下一行代码,将内核合并到我们的虚拟环境中,并为这个用户安装它。

python -m ipykernel install — user — name myenv — display-name “py”

作者截图。

这就是解决内核错误相关问题的全部内容。如果你想立即测试这些变化,你可以重启 Jupyter Notebook,或者你可以在这个新环境中安装一些你想要的有价值的库。

使用以下代码:

conda install azureconda install pandasconda install backports

资源:

安装 IPython 内核

如何在 Pandas 中展平多索引列和行

原文:https://towardsdatascience.com/how-to-flatten-multiindex-columns-and-rows-in-pandas-f5406c50e569

在 Pandas 数据框架中有效展平多索引列和行的 6 个技巧

安娜斯塔西娅·切平斯卡在 Unsplash 上拍摄的照片

一个 MultiIndex (也称为层次索引)数据帧允许您将多个列作为一个行标识符,将多个行作为一个标题标识符。

熊猫多指数数据框架示例(图片由作者提供)

MultIndex 对于复杂的数据分析非常有用,尤其是在处理高维数据时。Pandas 有多种方法可以输出多索引数据帧,例如,[groupby()](/all-pandas-groupby-you-should-know-for-grouping-data-and-performing-operations-2a8ec1327b5)[melt()](/reshaping-a-dataframe-using-pandas-melt-83a151ce1907)[pivot_table()](/a-practical-introduction-to-pandas-pivot-table-function-3e1002dcd4eb)[stack()](/reshaping-a-dataframe-with-pandas-stack-and-unstack-925dc9ce1289)等。然而,有时在数据帧中使用单级索引会更容易。

在本文中,您将了解如何扁平化多索引列和行。本文组织如下:

  1. 展平列:使用get_level_values()
  2. 展平列:使用to_flat_index()
  3. 展平列:连接列标签
  4. 展平行:展平所有标高
  5. 展平行:展平特定标高
  6. 展平行:连接行标签

请查看笔记本获取源代码。更多教程可从 Github Repo 获得。

1.多索引列:使用get_level_values()

首先,让我们创建一个示例 DataFrame 并调用groupby()来创建一个多索引列:

df = pd.DataFrame({
    'name': ['Tom', 'James', 'Allan', 'Chris'],
    'year': ['2000', '2000', '2001', '2001'],
    'math': [67, 80, 75, 50],
    'star': [1, 2, 3, 4]
})df_grouped = df.**groupby('year')**.agg(
    { 'math': ['mean', 'sum'], 'star': 'sum'}
)

多索引数据框(图片由作者提供)

运行df_grouped.columns,我们可以看到我们有一个多索引列

df_grouped.columnsMultiIndex([('math', 'mean'),
            ('math',  'sum'),
            ('star',  'sum')],
           )

展平多索引列的最简单方法是将columns设置为特定级别,例如,将columns设置为顶级:

df_grouped.columns = df_grouped**.columns.get_level_values(0)**

扁平化多索引数据框架(图片由作者提供)

get_level_values(0)返回顶层,我们将该值赋给df_grouped.columns。这当然有效,但是您可能已经注意到结果有 2 个数学列。

2.展平列:使用to_flat_index()

从 Pandas 版本 0.24.0 开始,to_flat_index()将 MultiIndex 转换为包含级别值的元组索引:

df_grouped.**columns.to_flat_index()**# output
Index(**[('math', 'mean'), ('math', 'sum'), ('star', 'sum')]**, dtype='object')

通过将结果分配给df_grouped.columns,结果将如下所示:

df_grouped.columns = df_grouped**.columns.to_flat_index()**

扁平化多索引数据框架(图片由作者提供)

3.展平列:连接列标签

如果您想要一个更好的人类可读的单级索引,您可以连接 MultiIndex 中的值:

**['_'.join(col) for col in df_grouped.columns.values]**# output
['math_mean', 'math_sum', 'star_sum']

通过将结果赋值给df_grouped.columns,结果将如下所示:

df_grouped.columns 
  = ['_'.join(col) for col in df_grouped.columns.values]

扁平化多索引数据框架(图片由作者提供)

4.展平行:展平所有标高

假设我们有以下包含多索引行的数据帧:

multi_index = pd.MultiIndex.from_tuples([
  ('Oxford', 'A', '01-01-2022'), 
  ('Oxford', 'B', '01-01-2022'), 
  ('Oxford', 'A', '02-01-2022'),
  ('Oxford', 'B', '02-01-2022'),
  ('London', 'C', '01-01-2022'), 
  ('London', 'D', '01-01-2022'),
  ('London', 'C', '02-01-2022'),
  ('London', 'D', '02-01-2022')], 
  names=['Location','Store', 'Date']
)data = {
  'Num_employee': [1,2,3,4,5,6,7,8],
  'Sales': [11,22,33,44,55,66,77,88]
}df = pd.DataFrame(data, index=multi_index)

多索引数据框架(图片由作者提供)

我们可以简单地调用reset_index()来展平 MultiIndex 的每个级别:

df.reset_index()

扁平化多索引数据框架(图片由作者提供)

5.展平行:展平特定标高

reset_index()中的第一个参数控制要展平的级别。默认为None展平所有级别。要展平一个级别或一个级别列表,我们可以传递一个数字/字符串或一个列表:

# Flatten 'Date' level
df.reset_index(**2**)
df.reset_index(**'Date'**)# Flatten 'Store' and 'Date'
df.reset_index(**[1, 2]**)
df.reset_index(**['Store', 'Date']**)

扁平化多索引数据框架(图片由作者提供)

6.展平行:连接行标签

类似地,我们可以连接 MultiIndex 中的值来创建一个更好的人类可读的单一索引:

['_'.join(col) for col in df.index.values]# output
['Oxford_A_01-01-2022',
 'Oxford_B_01-01-2022',
 'Oxford_A_02-01-2022',
 'Oxford_B_02-01-2022',
 'London_C_01-01-2022',
 'London_D_01-01-2022',
 'London_C_02-01-2022',
 'London_D_02-01-2022']

通过将结果分配给df.columns,结果将如下所示:

df.index = ['_'.join(col) for col in df.index.values]

扁平化多索引数据框架(图片由作者提供)

结论

在本文中,我们讨论了关于在 Pandas 中展平多索引列和行的 6 个用例。希望这篇文章能帮你节省分析数据的时间。

感谢阅读。请查看笔记本获取源代码,如果您对机器学习的实用方面感兴趣,请继续关注。更多教程可从 Github Repo 获得。

如何预测具有多重季节性的时间序列

原文:https://towardsdatascience.com/how-to-forecast-time-series-with-multiple-seasonalities-23c77152347e

在 Python 中使用 BATS 和 TBATS 模型的实践示例

阿里·科卡布在 Unsplash 上的照片

在处理时间序列时,我们经常会遇到季节性。季节性在我们的系列中被定义为周期性变化。在我们的系列中,这是一个在固定周期内发生的循环。例如,让我们看看下面显示的流行的航空公司数据集。

一家航空公司从 1949 年 1 月到 1960 年 12 月的每月乘客总数。我们注意到这个系列有一个明显的季节性模式,更多的人在六月、七月和八月旅行(图片由作者提供)

在这里,我们可以清楚地看到一个季节性周期,因为每年的 7 月份左右,航空旅客人数达到高峰,然后再次下降。

为了预测这个系列,我们可以简单地使用一个 SARIMA 模型,因为只有一个长达一年的季节周期。

现在,当我们处理高频数据时,事情变得复杂了。例如,每小时的时间序列可以表现出每日、每周、每月和每年的季节性,这意味着我们现在有多个季节周期。看看下面 94 号州际公路每小时的交通量。

明尼苏达州明尼阿波利斯 94 号州际公路西行每小时交通量。在这里,我们既可以看到每日的季节性(白天行驶的汽车比晚上多),也可以看到每周的季节性(周一至周五行驶的汽车比周末多)。作者图片

看上面的数据,我们可以看到我们有两个季节周期!首先,我们有一个每日季节性,因为我们看到更多的汽车在白天行驶,而不是在晚上。第二,我们有一个周季节性,因为交通流量在工作日高于周末。

在这种情况下,不能使用 SARIMA 模型,因为我们只能指定一个季节周期,而我们的数据中肯定有两个季节周期:每日季节性和每周季节性。

因此,我们将注意力转向球棒球棒型号。使用这些模型,我们可以拟合和预测具有多个季节周期的时间序列。

在本文中,我们首先探索 bat 和 TBATS 背后的理论,然后应用它们来预测未来七天的每小时交通量。我们开始吧!

通过 Python 中的应用时间序列分析,学习最新的时间序列分析技术。课程涵盖统计和深度学习模型,你将使用 Python 和 TensorFlow!

蝙蝠和蝙蝠背后的直觉

在我们深入项目之前,让我们先了解一下蝙蝠和 TBATS 是如何在幕后工作的。

我保证这个理论没那么糟糕(图片由作者提供)

蝙蝠

首字母缩写 BATS 指的是该方法:具有 B ox-Cox 变换、 A RMA 误差、 T rend、 S 季节分量的指数平滑状态空间模型。这里有很多需要剖析的地方,所以我们一步一步来。

  • 指数平滑法是一种预测方法。这些预测方法背后的一般思想是,未来值是过去值的加权平均值,随着我们回到过去,权重呈指数衰减。预测方法包括简单指数平滑法、双指数平滑法或霍尔特法(用于有趋势的时间序列),以及三指数平滑法或霍尔特-温特法(用于有趋势和季节性的时间序列)。
  • 状态空间建模是一个框架,在这个框架中,时间序列被视为一组受一组未观察到的因素影响的观察数据。然后,状态空间模型表示这两个集合之间的关系。同样,这必须被视为一个框架,因为 ARMA 模型可以表示为一个状态空间模型。
  • Box-Cox 变换是一种幂变换,它通过稳定一段时间内的方差和均值来帮助使序列平稳。
  • ARMA 误差是我们对时间序列的残差应用 ARMA 模型以发现任何无法解释的关系的过程。通常,模型的残差应该是完全随机的,除非模型没有捕捉到某些信息。这里,我们使用 ARMA 模型来捕捉残差中的任何剩余信息。
  • 趋势是时间序列的一个组成部分,它解释了序列平均值的长期变化。当我们有一个积极的趋势,那么我们的系列是随着时间的推移而增加。如果趋势为负,则该系列会随着时间的推移而减少。
  • 季节因素解释了序列中的周期性变化。

总之,BATS 是指数平滑方法的扩展,它结合了 Box-Cox 变换来处理非线性数据,并使用 ARMA 模型来捕捉残差中的自相关。

使用 BATS 的优势在于它可以处理非线性数据,解决残差中的自相关问题,因为它使用了 ARMA 模型,并且它可以考虑多个季节周期。

但是,季节周期必须是整数,否则不能应用 bat。例如,假设您有带有年度季节性的周数据,那么您的周期是 365.25/7,大约是 52.2。那样的话,蝙蝠就被排除了。

此外,如果季节周期非常长,BATS 可能需要很长时间来拟合,这意味着如果您有每月的小时数据(周期将是 730),则不适合。

因此,开发了 TBATS 模型来解决这种情况。

TBATS

缩写 TBATS 代表 T rigonometric 季节性, B ox-Cox 变换, A RMA 误差, T 趋势,以及 S 季节性成分。

它使用与 BATS 模型相同的组件,但是它将每个季节周期表示为基于傅立叶级数的三角表示。这使得模型能够适应大的季节周期和非整数的季节周期。

因此,在处理高频数据时,它是一个更好的选择,并且通常比 bat 更适合。

在这里,我故意避开数学,以避免任何混淆。关于蝙蝠和 TBATS 的详细数学解释,我建议你阅读这篇论文

现在我们对这两个模型的工作原理有了一个直觉,让我们应用它们来预测未来七天的每小时交通量。

在 Python 中应用 bat 和 TBATS

让我们看看这两个模型在预测每小时交通量时的作用。你可以参考 GitHub 上的完整源代码。

探测

首先,我们导入这个项目所需的库。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

然后,我们读取包含数据的 CSV 文件。注意,你也可以从 GitHub 下载。

data = pd.read_csv(‘daily_traffic.csv’)
data = data.dropna()

太好了!完成后,我们现在可以可视化我们的数据。

fig, ax = plt.subplots(figsize=(14, 8))ax.plot(data['traffic_volume'])
ax.set_xlabel('Time')
ax.set_ylabel('Traffic volume')fig.autofmt_xdate()
plt.tight_layout()plt.show()

明尼苏达州明尼阿波利斯市 94 号州际公路每小时的交通量(图片由作者提供)

从上图中,我们可以清楚地看到我们有两个季节周期。让我们放大并标记一周中的每一天,以标识这两个时间段。

fig, ax = plt.subplots(figsize=(14, 8))ax.plot(data['traffic_volume'])
ax.set_xlabel('Time')
ax.set_ylabel('Traffic volume')plt.xticks(np.arange(7, 400, 24), ['Friday', 'Saturday', 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'])
plt.xlim(0, 400)fig.autofmt_xdate()
plt.tight_layout()plt.show()

明尼苏达州明尼阿波利斯 94 号州际公路西行每小时交通量。在这里,我们既可以看到每日的季节性(白天行驶的汽车比晚上多),也可以看到每周的季节性(周一至周五行驶的汽车比周末多)。作者图片

当然,我们从本文开始就认识到了这个情节,并注意到周末的交通量确实比平日低。此外,我们看到了每日的季节性,白天的交通比晚上更繁忙。

因此,我们有两个时段:日时段的长度为 24 小时,周时段的长度为 168 小时。让我们在继续建模时记住这一点。

建模

我们现在准备开始建模我们的数据。这里我们用的是 sktime 包。我刚刚发现了这个框架,它为时间序列带来了许多统计和机器学习方法。它还使用了与 scikit-learn 相似的语法约定,使其易于使用。

第一步是定义我们的目标和预测范围。这里,目标是交通量本身。对于预测范围,我们希望预测一周的数据。因为我们有每小时的数据,所以我们必须预测未来的 168 个时间步(7 * 24)。

y = data['traffic_volume']fh = np.arange(1, 168)

然后,我们将数据分成训练集和测试集。我们将保留上周的数据作为测试集,以便评估我们的预测。

这里,我们使用来自 sktimetemporal _ train _ test _ split函数。

from sktime.forecasting.model_selection import temporal_train_test_splity_train, y_test = temporal_train_test_split(y, test_size=168)

可选地,我们可以可视化我们的测试集。

fig, ax = plt.subplots(figsize=(14, 8))ax.plot(y_train, ls='-', label='Train')
ax.plot(y_test, ls='--', label='Test')
ax.set_xlabel('time')
ax.set_ylabel('Daily traffic volu,e')
ax.legend(loc='best')fig.autofmt_xdate()
plt.tight_layout()plt.show()

可视化训练集和测试集。测试只是最后一周的数据,如橙色虚线所示。剩下的用于拟合模型(图片由作者提供)。

基线模型

在我们实现更复杂的 bat 和 TBATS 模型之前,拥有一个基线模型总是一个好主意。这样,我们可以确定我们更复杂的预测方法实际上是否有效。

在这里,我能想到的最简单的基线就是简单地将训练集中上周的数据重复到未来。

y_pred_baseline = y_train[-168:].values

使用球棒

现在我们有了一个基线,让我们继续实现 BATS 模型。

我们首先从 sktime 导入 BATS 模型。然后,我们指定模型的参数进行训练。在这里,我们希望使用 Box-Cox 变换来处理非线性数据。然后,由于我们的数据集没有明显的趋势,我们从模型中删除这些组件。最后,我们指定季节周期,即 24(表示每日季节性)和 168(表示每周季节性)。

一旦指定了模型,我们只需将其放在训练集上,并在预测范围内生成预测。

上面概述的所有步骤都转化为下面的代码。

from sktime.forecasting.bats import BATSforecaster = BATS(use_box_cox=True,
                  use_trend=False,
                  use_damped_trend=False,
                  sp=[24, 168])
forecaster.fit(y_train)y_pred_BATS = forecaster.predict(fh)

应用 TBATS

使用 TBATS 进行预测就像使用蝙蝠一样,只是现在,嗯…我们使用 TBATS!

from sktime.forecasting.tbats import TBATSforecaster = TBATS(use_box_cox=True,
                   use_trend=False,
                   use_damped_trend=False,
                   sp=[24, 168])
forecaster.fit(y_train)y_pred_TBATS = forecaster.predict(fh)

评估绩效

在这一点上,我们有来自基线模型、蝙蝠和 TBATS 的预测。然后我们准备好可视化预测,看看哪个模型表现最好。

可视化的预测给出了下面的图。

fig, ax = plt.subplots(figsize=(14, 8))ax.plot(y_train, ls='-', label='Train')
ax.plot(y_test, ls='-', label='Test')
ax.plot(y_test.index, y_pred_baseline, ls=':', label='Baseline')
ax.plot(y_pred_BATS, ls='--', label='BATS')
ax.plot(y_pred_TBATS, ls='-.', label='TBATS')
ax.set_xlabel('time')
ax.set_ylabel('Daily traffic volume')
ax.legend(loc='best')fig.autofmt_xdate()
plt.tight_layout()plt.show()

预测未来 168 小时的交通量。我们可以看到,所有模型似乎都产生了类似的预测,因为这些线相互重叠。看剧情很难知道哪种模式表现最好。(图片由作者提供)

看上面的图,似乎我们所有的模型都产生了非常相似的预测,因为线是重叠的。仅仅通过查看图很难确定哪个模型表现最好。

我们可以有选择地放大测试集,以便更好地可视化预测。

放大测试集。在这里,蝙蝠似乎在模拟两个季节方面做得很好,而 t BATS 有时会过冲或欠冲。请注意,基线也很好地遵循了实际值。(图片由作者提供)

看上面的图,我们首先注意到两个模型确实模拟了双重季节性,这本身就很好!此外,蝙蝠似乎在预测未来方面做得更好,因为 t BATS 有时似乎过冲或欠冲。还要注意基线模型紧密地跟随实际值的曲线。

我们现在计算一个误差度量来确定最佳模型并比较它们的性能。在这种情况下,为了便于解释,我们使用平均绝对百分比误差(MAPE)。回想一下,MAPE 越接近 0,性能越好。

MAPE 还没有在 scikit-learn 中实现,所以我们自己定义函数。

def mape(y_true, y_pred):
    return round(np.mean(np.abs((y_true - y_pred) / y_true)) * 100,2)

然后,我们简单地计算每个模型的性能,并在条形图中显示出来。

mape_baseline = mape(y_test, y_pred_baseline)
mape_BATS = mape(y_test, y_pred_BATS)
mape_TBATS = mape(y_test, y_pred_TBATS)print(f'MAPE from baseline: {mape_baseline}')
print(f'MAPE from BATS: {mape_BATS}')
print(f'MAPE from TBATS: {mape_TBATS}')fig, ax = plt.subplots()x = ['Baseline', 'BATS', 'TBATS']
y = [mape_baseline, mape_BATS, mape_TBATS]ax.bar(x, y, width=0.4)
ax.set_xlabel('Models')
ax.set_ylabel('MAPE (%)')
ax.set_ylim(0, 35)for index, value in enumerate(y):
    plt.text(x=index, y=value + 1, s=str(round(value,2)), ha='center')plt.tight_layout()

所有模特中的 MAPE。这里,基线模型实现了最佳性能,因为它具有最低的 MAPE。(图片由作者提供)

从上图中,我们可以看到蝙蝠比蝙蝠表现得更好,正如我们从图中观察到的那样,这是意料之中的。但是,我们看到基线模型是性能最好的模型,实现了 11.97%的 MAPE。

这有点虎头蛇尾,但让我们了解一下为什么会发生这种情况。

有可能我们的数据集太小了。可能我们用于测试的样本最终会支持基线模型。验证的一个方法是预测多个 168 小时范围,看看基线模型是否仍然优于其他模型。

还有,可能是我们对模型的参数要求太严格了。在这里,我们强迫两个模型都使用 Box-Cox 变换,并删除趋势成分。然而,我们可以不指定这些参数,并且模型将尝试每个参数的两种可能性,并且选择具有最低 AIC (Akaike 的信息标准)的一个。虽然这使得训练过程更长,但也可能导致蝙蝠和 TBATS 更好的表现。

然而,关键的一点是,建立基线模型对于任何预测项目都是非常重要的。

结论

在本文中,我们学习了 BATS 和 t BATS 模型,以及如何使用它们来预测具有多个季节周期的时间序列,在这种情况下,不能使用 SARIMA 模型。

我们应用这两个模型来预测每小时的交通量,但结果表明我们的基线仍然是表现最好的模型。

然而,我们看到蝙蝠和 t BATS 确实可以模拟具有复杂季节性的时间序列。

潜在的改进

  • 预测多个 168 小时范围,看看基线是否确实是性能最好的模型。你可以使用原始数据集,它包含的数据比我们处理的要多得多。
  • 不指定参数 use_box_coxuse_trenduse_damped_trend ,让模型根据 AIC 做出最佳选择。

关键要点

  • 在预测时,总是建立一个基线模型
  • bat 和 TBATS 可用于建模具有复杂季节性的时间序列
  • BATS 在周期较短且为整数时工作良好
  • TBATS 的训练速度比 bat 快,并且可以处理非整数的季节周期

感谢阅读,我希望学到一些有用的东西!如果你想了解更多关于 Python 中使用统计和深度学习模型进行时间序列预测的知识,可以查看我的时间序列课程

干杯!🍺

如何形成对数据的现实预期

原文:https://towardsdatascience.com/how-to-form-realistic-expectations-about-data-622e85ab62cb

成为“真正的”数据分析师的旅程

业余分析师和专业分析师之间有很大的区别。在我之前的文章【1】【2】中,我们已经详细讨论了前 6 个,现在我们将深入讨论一个大问题: 现实的期望

专业数据与业余数据的差异#7 —对数据的现实预期

如果你是专业分析师,你知道数据不欠你什么。对你的麻烦来说连像样的质量都没有。

宇宙不会因为你掌握了一些数字就欠你可靠的结论。

不幸的是,如果你曾经上过与数据相关的课程,你可能会学到相反的东西。

学生们习惯于期待每一次对数据的探索都能产生真正的见解……因为每一次家庭作业都埋藏着宝藏。这不是偶然的。

很少有教授忍心让你白费力气(为了你好!)而且开放式作业很难评分,所以作为学生你通常接触不到足够多的开放式作业。

优秀的教师希望你对数据职业感到兴奋,所以他们会额外努力为你寻找有趣的数据。在之前的一篇文章中,我给你看了一个数据集,结果是我无聊的木地板的照片(下图)。我内心的表演者在尖叫——我可以向你展示几乎任何其他数据集,它会更有吸引力,但我违背了初衷(是的),提醒你对数据的探索并不总是会带来惊天动地的启示。有时候会,但大多数时候不会。这是工作的一部分。

专业人士对这一点的理解,只能从苦难中诞生。

数据不欠你什么。对你的麻烦来说连像样的质量都没有。

更糟糕的是,分析师的工作性质意味着你更有可能承担探索二手数据的任务——也称为 继承数据——而不是一手数据。

对使用继承数据的指南感兴趣吗?我给你做了一个在这里。图片由作者提供。

如果你(或你所在的团队)直接从现实世界中收集了的观察结果,那么你就在使用的原始数据。换句话说,您可以控制如何记录和存储这些测量结果。

相反的是什么? 继承(次级)数据 是你从别人那里获得的那些数据。(例如,您可以在这里获得超过 2000 万个数据集。)

统计学家和机器学习工程师享受使用定制的原始数据集的快乐的原因是,分析师已经做了探索性的工作,以找出哪些问题值得为之创建数据。

其他数据专业人士在分析师为他们标出这些 x 之前,不会知道去哪里挖掘。照片由 N.Unsplash 上拍摄

统计学家和机器学习工程师是狭窄而深入的工作者,所以让他们指出值得努力的问题真的很重要。如果你的专家正在小心翼翼地解决错误的问题,那么任何对数据科学的投资都将遭受低回报。为了确保你的组织能够很好地利用窄而深的专家,你要么需要确定你已经有了正确的问题,要么你需要一个宽而浅的方法来找到一个。这正是分析的目的。

分析师是怎么做的?在各种杂乱的数据中漫游,而这些数据在设计时并没有考虑到他们的需求。专业分析师经常发现自己在与耗尽的数据、记录不良的公共数据、令人困惑的供应商数据、错误百出的表格、老板收集的名称类似 temp1.xlsx 的电子表格以及混合数据(弗兰肯斯坦对不完全符合你需求的多个来源的合并)作战。

照片由 Unsplash 上的 Haziq JB

当然,分析师也会分析原始数据。他们当然知道。但这不会占用他们太多时间。如果你自己制作了数据,分析它会快得多,因为你大概知道从中可以期待什么…这意味着用不了多久你就可以自由地回到分析二手数据的混乱中去。这就是为什么分析师的大部分时间可能花在继承的数据上。

分析师的大部分时间可能花在继承的数据上。

即使你确切地知道你想解决哪个问题,也不要一头扎进数据收集中。在你的团队探索一些相关数据之前,设计你的数据集合是非常罕见的(通常是不明智的)。这就像在没有观察你的目标受众如何与原型和相关产品互动的情况下尝试 UX 设计。是啊,别那么做。

你经常需要从不好的数据开始,来弄清楚如何做出更好的数据。

虽然所有数据专业人士都知道坏数据不会带来好结果——垃圾进垃圾出——但分析师们痛苦地意识到,你通常需要从坏数据开始,以找出如何制造更好的数据。对分析师来说,糟糕的数据是一个职业现实。这是使他们的工作如此艰难和重要的另一个因素;我希望我们能更多地信任分析师。**

换句话说,所有的路径都指向分析,通常是杂乱的数据。这意味着专业分析师受益于:

  • 领域知识帮助他们理解混乱,并指导他们判断如何花费时间和精力。
  • 数据设计技能根据他们的发现,帮助他们了解数据收集工作。
  • 协作技能帮助他们知道当他们力不从心时可以依靠哪些专家,例如当实验设计问题变得棘手时可以依靠统计学家,当领域技术性很强时可以依靠科学家。
  • 实用主义帮助他们沉默内心的完美主义,尽最大努力从不完美的数据中提取价值。
  • 沟通技巧帮助他们平息利益相关者内心的完美主义,设定合理的预期。
  • 主动的好奇心帮助他们提出棘手的问题,并找到更多的数据来源进行询问。
  • 韧性帮助他们在应对他人糟糕的数据收集选择的挫败感中生存下来。
  • 克制帮助他们避免从不可信的数据中妄下结论。松散地持有你的观点,并小心你的假设是你如何避免与你的原始故事对你不透明的数据打交道的许多陷阱。
  • 谦逊帮助他们避免把自己和他们的分析看得太重。
  • 幽默感。

保持对数据的热情,同时仍然能够冷静地分析数据,这并不容易。当业余爱好者的数据集被证明不足以进行令人尊敬的分析时,他们会变得情绪化。但这就是生活。专业人士接受了这个事实。(如果你正在寻找一些对数据新手的严厉的爱,你会发现这篇文章美味暴躁。)

专业人士知道,仅仅因为你有一个充满数字的电子表格,并不保证你能从中获得任何有用的东西。但是他们会站出来帮助你设计一种方法,让你下次做得更好。

Alexander SinnUnsplash 上拍摄

本文到此为止。在下一篇中,我们将解决业余分析师和专业分析师之间的最后三个差异: 专业数据分析师与业余分析师的差异# 8——知道如何增加价值
专业数据分析师与业余分析师的差异# 9——对时间的不同思考
专业数据分析师与业余分析师的差异# 10——细微的卓越观

让我知道你是否喜欢这个话题,不要忘记与你的社区分享你最喜欢的见解!

专业数据与业余数据的差异#1-#3

软件技能;轻松处理大量数据;不受数据科学偏见的影响。包含在第 1 部分的中。

*

专业数据与业余数据的差异# 4 –# 6

了解职业;拒绝成为数据江湖骗子;对确认偏差的抵抗力。包含在第 2 部分中。

专业数据与业余数据的差异#7

哇,你错过了?向上滚动!

专业数据与业余数据的差异# 8-# 10

https://kozyrkov.medium.com/how-to-add-value-as-a-data-analyst-8a6ae900b82a

感谢阅读!喜欢作者?

让我们做朋友吧!你可以在 TwitterYouTubeSubstackLinkedIn 上找到我。有兴趣让我在你的活动上发言吗?使用表格联系。*

如何将回归问题框架化为分类问题以解释不确定性

原文:https://towardsdatascience.com/how-to-frame-a-regression-problem-as-a-classification-problem-to-account-for-uncertainty-63fb8269486e

foto de Vladislav Vasnetsov:https://www . pexels . com/es-es/foto/cubos-de-basura-de-plastico-de-varios-colores-2682683/

利弊,以及一个工作实例

我敢打赌你去过那里:你有一些数据,你也有一个目标列,你需要使用一些 ML 技术来估计。你能想到的:给定一些财务数据估计价格,一些客户信息估计它的终身价值,一些机械信息估计磨损或使用。这是一个回归问题,目标是在给定一组特征的情况下精确定位连续变量的值。有趣的部分来了。你对这个价值有多大把握?

让我们用第一个例子。您正在向销售经理展示一个价格估算模型,在给定输入的情况下,它估计价格应该是$51.53。你有信心,因为评估 RMSE 是 1.8 美元;对于这个价格范围来说已经足够好了,但是对于$5 到$10 的价格范围来说是一个相当大的问题。这里的问题是,误差在价格范围之间不是均匀分布的。该模型在某些范围内会更准确,而在其他范围内就不那么准确了,RMSE 不会让你知道它对某个估计有多准确。换句话说,你不知道模型的不确定性。

金融领域也有相似之处。你有 100 美元,想在 3 种可能的资产中决定投资方向。如果有人来告诉你把所有的钱都投资到一个单一的资产上,这将是很奇怪的,因为你会期望得到一些建议,比如“把 60%倒过来,30%倒过来,最后 10%倒过来”。

我敢打赌,你可以看到问题的走向。在给定的回归问题中,您可以确定一个预测值,比如 10.5 美元,或者以“该值有 20%的可能性在 0 到 5 之间,有 70%的可能性在 5 到 10 之间,只有 10%的可能性大于 10”的形式提供分布。

下图显示了这一点。

解决回归问题的传统方法是:确定预期的结果。图片由作者提供。

考虑到不确定性的另一种分布式解决方案。图片由作者提供。

这两种方法各有利弊。

精确定位一个值

赞成

  • 告诉某人期望值是 10.5 美元,这意味着什么就不会有疑问了。优点是一个数字很容易理解。

欺骗

  • 如前所述。你对这个价值有多大把握?训练 RMSE 不会告诉你太多关于这个特殊的情况。缺点是你不知道一个特定的预测有多准确。

显示一个分布图

赞成

  • 你知道模型在预测中有多确定。例如,如果模型告诉您某个容器有 90%的可能性,您可以确信它在相应的范围内。另一方面,如果模型给你的值接近 30%,你肯定什么都不知道。甚至知道你什么都不知道也没用。这里的优点是模型考虑了不确定性。

欺骗

  • 这种方法的主要问题可能是可解释性。任何知道概率分布概念的人都会很容易理解如何处理这个结果。如果你足够幸运,能与精明的股东打交道,那你就大功告成了。然而,如果他们不这么做,你将面临更大的挑战。

此时,您可能想知道分类部分在哪里。嗯,看上面的直方图。你明白了吗?如果你没有,就在这里。

不要精确定位值,而是估计它的值属于某个箱的概率,这是:将每个样本分类到一个箱中。

现在让我们用一些代码和一个真实的例子来阐明这个想法。首先,我们将训练一个回归变量来精确定位工资,然后进行修改以将回归问题构建为一个分类问题。

回归任务

我们将使用 Kaggle 上提供的数据科学职位工资 [1]。

数据集看起来像这样。

数据集预览。图片由作者提供。

我不会深入讨论清理和准备数据的细节,但是一般来说,这些步骤包括删除未使用的列、处理分类数据和缩放数据集值。最后,我们将使用XGBoost[2]来训练一个回归变量。

*# Prepare data*X = df.drop(['Unnamed: 0','salary', 'salary_currency','salary_in_usd'], axis=1)
X = pd.get_dummies(X)

y = df['salary_in_usd']*# Split into train test sets*X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=1)
*# Scale data*
t = MinMaxScaler()
t.fit(X_train)
X_train = t.transform(X_train)
X_test = t.transform(X_test)*# Fit model no training data*from xgboost import XGBRegressor
model = XGBRegressor()
model.fit(X_train, y_train)*# Make predictions for test data*y_pred = model.predict(X_test)
predictions = [round(value) for value **in** y_pred]from sklearn.metrics import mean_squared_error

rms = mean_squared_error(y_test, y_pred, squared=False)

*# Not quite good but doing this to compare to the distributive approach*# Output: 41524.12746933382

如果我们看一下前五个预测,它们看起来像这样。

[71284, 44957, 131146, 165507, 100765]

对于每个元素,回归变量旨在精确定位相应薪金的数值。果然不出所料。我不知道是不是我,但当我看着这些数字时,我觉得缺乏一些背景。我有多确定这些数字是正确的?

回归变量实现了 41,524 的 RMSE。我打赌我们可以做得更好,然而,目的不是训练一个超级精确的分类器,而是对比将问题框架化为回归问题或分类问题之间的差异。现在让我们来看分类部分。

分类问题

前面我们说过,将回归问题构建为分类问题的核心思想是,不精确确定数值,而是估计样本属于一组固定箱的概率,即,将每个样本分类到一个箱中。

因此,第一个显而易见的步骤是确定固定箱的集合。为了实现这一点,我们需要查看我们拥有的训练数据的直方图。

描述工资分布的直方图。图片由作者提供。

这就是了。现在我们清楚地知道了大部分工资的位置,最低工资和最高工资。

现在让我们来定义箱子。为了做到这一点,我们将只考虑一个使分类问题更容易的原则:确保数据集不是非常不平衡。我们将通过仔细选择箱的数量来做到这一点,以便属于每个类的元素的计数大致相似。

现在,让我们选择 5 个箱的计数来找到每个箱的极限和元素计数。

*# Let’s calculate the numeric histogram from the actual test target*
hist, bin_edges = np.histogram(y_test, bins=5)
hist, bin_edges

输出

(array([33, 45, 28, 15,  1]),
 array([  4000.,  68000., 132000., 196000., 260000., 324000.]))

第一个箱的数量相当平衡,但是,最后一个箱有一个问题,我们将通过聚合这些箱中的数据来解决。

请注意,此时我们在 y 中的目标只是一堆浮动数字(工资),不适合分类任务,因为这种任务需要一个样本和一个标签,表明样本属于哪个类别。所以接下来的任务是写一些代码来将一个浮点数映射成一个整数标签。

所以看一下下面的代码。

一个简单的函数,将一个数字映射到一个类中。图片由作者提供。

简单吧?我们接收一个浮点数,并根据它的值返回一个标签。代码是不言自明的,只需注意最后的 elif 语句:这是聚合发生的地方。该代码表示“大于 196,000 的所有内容都将被分配一个标签 4”。

我听到你问为什么这些值是硬编码的。答案是因为这只是一个例子。我敢打赌有更明智的方法来选择框的边界,但是,我只是想保持简单,以保持快速移动。

现在让我们再次使用 XGBoost 训练分类。但是首先,我们需要将浮动 y 目标转换成一组分布式 y 目标。这段代码就可以了。

# convert each y in training and test sets to a classy_train_distributive = [map_float_to_class(y) for y in y_train]
y_test_distributive = [map_float_to_class(y) for y in y_test]

现在训练真正的分类任务。

# Import the classifierfrom xgboost import XGBClassifier
from sklearn.metrics import accuracy_scoremodel = XGBClassifier()# Train to get a labelmodel.fit(X_train, y_train_distributive)# Get the labelspredictions = model.predict(X_test)# How good does it workaccuracy_score(y_test_distributive, predictions)# Output: 0.5327868852459017

使用默认参数,我们得到了 0.53 的精度,你打赌它可以得到改善。现在,让我们继续。

如果我们看一下前五个预测,它们看起来像这样。

array([1, 1, 2, 3, 2])

它们只是标签…不太能说明问题。我们感兴趣的不是哪个标签被选中,而是被选中的标签是在哪个底层分布中被挑选出来的。

这段代码将完成这个任务。

# Instead of the labels get the probability distributionspredictions = model.predict_proba(X_test)

前五个预测是这样的。

array([[2.76227575e-03, 8.35917711e-01, 1.60156339e-01, 8.88690702e-04,
        2.75029975e-04],
       [2.02982640e-03, 7.47869253e-01, 2.40976274e-01, 8.92745517e-03,
        1.97156842e-04],
       [9.52042465e-04, 4.67287423e-03, 4.85075146e-01, 2.80507535e-01,
        2.28792369e-01],
       [7.99451722e-04, 8.09144005e-02, 1.74629122e-01, 7.32445538e-01,
        1.12115145e-02],
       [1.12233951e-03, 8.29923898e-02, 8.98771644e-01, 1.67797077e-02,
        3.33951320e-04]], dtype=float32)

嗯…我们有更多的信息!由于一幅图像胜过千言万语(在这种情况下是数组),我们应该更好地制作一个图表。

# Plot some of the predicted salary distributionsfig, ax = plt.subplots(3, 3)
fig.set_size_inches(16, 6)# Random indexes picked
ax[0, 0].bar(labels, predictions[1])
ax[0, 1].bar(labels, predictions[5])
ax[0, 2].bar(labels, predictions[8])ax[1, 0].bar(labels, predictions[10])
ax[1, 1].bar(labels, predictions[15])
ax[1, 2].bar(labels, predictions[20])ax[2, 0].bar(labels, predictions[40])
ax[2, 1].bar(labels, predictions[47])
ax[2, 2].bar(labels, predictions[52])plt.tight_layout()
fig.suptitle("Some calculated distributions samples")
plt.show()

这是输出。我发现这种解决方案比没有上下文的简单浮点数更有表现力。对于一个样本,模型返回一个分布,从这个分布中,你可以获得很多信息。

计算所得预测值的随机子集的预测工资分布。图片由作者提供。

看一下第 1 行和第 0 列。如果你刚刚使用了第一个分类器提供的标签,你可能会犯错误,因为特定样本属于这两个较大类别的概率之间的差异非常小。在这种情况下,也许你应该深入了解候选人的个人资料,然后再做决定。

相比之下,看看第 2 行和第 1 列。该模型非常确定在这个范围内的工资是正确的。

现在,看第 0 行和第 2 列。该模型对工资应该在第二个箱中的某个位置有 3 倍的信心,然而第三个箱是非常相关的。选哪个?你可以获取一些其他数据来做出最终决定:也许招聘部门的人员轮换率很高,更高的薪水可能有助于减少轮换,或者从另一方面来说,这种职位需求很大,因此,你可以在较低的范围内招聘。

我们可以对剩下的分布进行类似的分析,但底线是一样的:与单个值相比,分布提供了更多的数据来进行决策。自己判断。

结论

在这篇文章中,我讨论了通过一个自定义函数将一个回归问题转化为一个分类问题的好处,这个自定义函数将浮点值映射到一个由整数描述的类中。每一类代表一个值域,即一个固定的支持。因此,它提供了固定支持的一组概率,而不是有一个在给定样本的情况下精确定位值的模型。

分布式模型的优点是它提供了更多的决策环境,缺点是它不能提供单一的解决方案。一个人不可能拥有一切。

您是否有此解决方案可能有用的应用?

你可以在这里查看 Kaggle 笔记本。如果你觉得这个帖子有趣,请关注我并分享!

参考

[1]数据科学岗位工资(2022 年更新)。Kaggle 数据集。https://www . ka ggle . com/datasets/ruchi 798/data-science-job-sales/metadata

[2] XGBoost 文档(2022 年更新)。【https://xgboost.readthedocs.io/en/stable/index.html

posted @ 2024-10-18 09:29  绝不原创的飞龙  阅读(199)  评论(0)    收藏  举报