TowardsDataScience-博客中文翻译-2022-十四-

TowardsDataScience 博客中文翻译 2022(十四)

原文:TowardsDataScience

协议:CC BY-NC-SA 4.0

简单方法中的队列分析

原文:https://towardsdatascience.com/cohort-analysis-in-r-the-easy-way-424f19a37d18

作者图片

简单方法中的队列分析

使用群组软件包更快地分析客户保持率

对于零售和订阅业务来说,可视化客户和用户保持率是一种有用的方法,可以跟踪客户和用户倾向于与他们呆在一起的时间,并发现群组规模随时间变化的差异。虽然有各种各样的方法来留住客户,但考虑客户最初注册或第一次购买的时间可能会有所帮助。这基本上就是群组分析所要完成的。在本教程中,我们将探索一些处理队列分析数据的简单快捷方式,并可视化结果。

虽然描述性群组分析在概念上很简单,而且大多数人可能会发现很容易破译最常见的可视化保持时间的方法,但我个人发现编写实际的代码来准备可视化群组分析结果的数据却非常困难。

我已经花了太多时间在网上搜索和浏览 StackOverflow 上这个问题的答案,希望找到简单的解决方案。最后,我确实设法解决了这个问题,但只是通过一些相当复杂的代码,这些代码很难理解,也几乎不可能记住。因此,为了避免不得不一遍又一遍地复制许多行代码,我决定创建一个名为【群组】的小 R 包,提供一些易于使用的功能来简化我自己的工作,并希望能够简化其他正在进行群组分析的人的工作。

数据要求

公司通常存储交易或事件数据,详细说明给定客户或用户何时购买、更新他们的订阅或以其他方式与他们的产品和服务进行交互。作为后者的一个例子,移动游戏提供商可以在每次消费者玩所讨论的游戏时进行记录。本质上,在典型的场景中,我们需要分析数据中的两列:一列包含唯一的用户 id,另一列包含日期。

群组包附带了两个样本数据集,我们将在本教程中使用。名为online_cohorts的第一个数据集是来自 Chen,Sain & Guo (2012)的在线零售数据集的精简版本,仅包含两个关键列:CustomerIDInvoiceDate

另一个数据集,我称之为gamelaunch,,包含了一款手机游戏发布后第一个月的模拟事件数据,过滤后只包含“gameStarted”事件类型。出于我们的目的,关键列将是userideventDate。下面显示了前几行。

head(gamelaunch) %>% 
   mutate(userid=abbreviate(userid))# A tibble: 6 x 3
  userid eventDate           eventName  
  <chr>  <dttm>              <chr>      
1 7479   2016-05-24 00:00:00 gameStarted
2 1852   2016-05-24 00:00:00 gameStarted
3 b719   2016-05-24 00:00:00 gameStarted
4 2919   2016-05-24 00:00:00 gameStarted
5 b495   2016-05-24 00:00:00 gameStarted
6 3615   2016-05-24 00:00:00 gameStarted

入门指南

我们可以安装并加载群组包,并使用下面几行代码查看online_cohorts数据集。因为我们将使用 ggplot2 和其他几个 tidyverse 包中的函数,所以我们也加载 tidyverse(如果需要的话,安装它)。

install.packages("cohorts")library(tidyverse)
library(cohorts)head(online_cohorts)# A tibble: 6 x 2
  CustomerID InvoiceDate
       <dbl> <date>     
1      17850 2010-12-01 
2      13047 2010-12-01 
3      12583 2010-12-01 
4      13748 2010-12-01 
5      15100 2010-12-01 
6      15291 2010-12-01

创建一个广泛的群组表

群组包目前允许用户按月和日进行聚合。继续使用online_cohorts数据集,我们将按月汇总客户订单。

作为第一步,我们将创建一个宽群组表,并用id_vardate参数指定适当的变量名。

online_cohorts %>% 
   cohort_table_month(id_var = CustomerID, date = InvoiceDate)

这将产生如下图所示的输出,其中行代表群组,列代表月份。在本例中,属于群组 1 的客户在 2010 年 12 月进行了第一次购买,属于群组 2 的客户在 2021 年 1 月下了第一笔订单,依此类推。

作者图片

在发动机罩下,cohort_table_month()cohort_table_day() 功能执行以下按键操作:

  1. 通过id_var对数据进行分组
  2. 如果使用cohort_table_month()将日期转换为年和月
  3. 为每个客户创建一个定义为第一个月或第一天的cohort变量
  4. 按群组和月/日重新分组输出
  5. 计算每个群组和月/日对的客户数量
  6. 转换为宽格式,其中列表示月/日,值表示客户数量

获取百分比

如果我们希望将上述值显示为百分比,我们可以将前面的代码输入到cohort_table_month_pct()函数中。

online_cohorts %>% 
   cohort_table_month(id_var = CustomerID, date = InvoiceDate) %>%
   cohort_table_pct()

从下面的输出可以明显看出,根据定义,群组在第一个月完成,这当然需要 100 %的起始值。随着时间的推移,我们应该会看到越来越少的相同客户在最初订单后的几个月内下新订单。

作者图片

群组表左移

对于某些用例,上述结果可能是我们真正想要的。但是,为了生成有意义的图,需要将值向左移动,作为中间步骤。这可以通过简单地将上面显示的代码块放入shift_left()函数来实现。

online_cohorts %>% 
   cohort_table_month(id_var = CustomerID, 
                      date   = InvoiceDate) %>%
   cohort_table_pct() %>%
   shift_left()

甚至可以少调用一个函数来执行相同的处理步骤。下面的代码块涉及与前面的代码示例相同的基础操作,只是顺序不同。但是,这并不影响输出。

online_cohorts %>% 
   cohort_table_month(id_var = CustomerID,
                      date   = InvoiceDate) %>%
   shift_left_pct()

从这些代码块中的任何一个,将创建以下输出:

作者图片

正如我们所看到的,该操作保留了先前输出中的行数和列数,但是现在每一列都代表一个相对的时间点,即t0是每个群组的第一个月,而不是将具体的年份和月份作为列。

这种格式不仅在我们想要制作情节时更容易使用。以这种方式排列群组使得检查结果和比较单个群组之间的趋势更加容易。

转换为长格式和绘图友好的格式

作为绘制结果之前的最后一步,我们需要将数据转换为长格式。我们可以通过“tidyr”包中的pivot_longer()来实现这一点。作为这种转换的结果,前面的列名已经变成了一个名为name的变量。我们还创建了一个名为time的新变量,方法是从name列的每个值中删除“t ”,并将变量类型改为 numeric。

到目前为止,我们一直使用online_cohorts数据集。对于其余的例子,我们将使用gamelaunch数据集,按天而不是按月进行聚合。

gamelaunch_long <- gamelaunch %>%
   cohort_table_day(userid, eventDate) %>%
   shift_left_pct() %>%
   pivot_longer(-cohort) %>%
   mutate(time = as.numeric(str_remove(name,"t")))

检查我们称为gamelaunch_long的新数据帧,我们应该看到下面的输出。

作者图片

最后,我们可以探索绘制结果的方法!

创建线形图

首先,我们做一个线图,展示活跃用户数是如何逐日减少的。为了清楚起见,我们将仅绘制数据的子集,仅包括编号小于或等于 7 的群组。

一个群体当然首先是完整的。因此,当time等于 0(即第一个月或第一天)时,value将始终为 100 (%)。为了消除这种冗余,我们对数据进行过滤,使其只包含time >为 0 的行。

因为我们在前面的阶段将数据左移,所以我们用值 0 填充了数据帧的右下角三角形。将这些值表示为 NA 会更合适,因为只有第一个群组被完全观察到,并且随后的群组随着时间的推移将具有越来越少的观察值。例如,最后一组将只有一个实际观察值。对此,一个简单的解决方案是通过运行以下代码行将所有 0 值设置为 NA:

gamelaunch_long[gamelaunch_long == 0] <- NA

另一个解决方案是包括一个过滤标准,规定value必须大于 0。在下面的代码中,我们在过滤步骤中应用了这个逻辑以及上面讨论的另外两个标准。

请记住,如果数据中存在真 0 值,这些值也将在建议的解决方案中被忽略。在未来版本的队列包中,我计划包含一个可选参数,将 0 值设置为 n a,同时确保仅替换“假”0 值。

让我们保持我们的设置最小化,创建我们的第一个情节!

gamelaunch_long %>%
  filter(cohort <= 7, time > 0, value > 0) %>%
  ggplot(aes(time, value, colour = factor(cohort), group = cohort)) +
  geom_line(size = 1) +
  geom_point(size = 1) +
  theme_minimal()

作者图片

在图中,我们可以看到大约 30 %的用户在 t1 时刻活跃,也就是玩新游戏的第二天,三天的留存率从大约 19 %到 24 %不等。我们还可以观察到,群组 1 的总体保留率要高得多。

创建表格可视化

我们可以用另一种方式来说明我们的结果,那就是再现左移队列表的左上角三角形。我们应用相同的过滤,除了我们将保留所有的群组,并使用geom_raster()来创建由保留率着色的图块,并添加一个geom_text()层来显示实际的百分比。

gamelaunch_long %>%
   filter(time > 0, value > 0) %>%
   ggplot(aes(time, reorder(cohort, desc(cohort)))) +
   geom_raster(aes(fill = log(value))) +
   coord_equal(ratio = 1) +
   geom_text(aes(label = glue::glue("{round(value,0)}%")), 
                 size  = 3, 
                 colour = "snow") +
  scale_fill_gradient(guide = "none") +
  theme_minimal(base_size = 16) +
  theme(panel.grid   = element_blank(),
        panel.border = element_blank()) +
  labs(y = "cohort")

作者图片

摘要

在本教程中,我们探讨了许多易于使用的函数,这些函数使群组分析变得简单明了。借助这些功能,我们可以通过计算不同时间点的保留率来处理事件和事务数据,并根据使用案例和下游任务将其转换为有用的数据格式。最后,我们看到了数据是如何绘制的。

我希望本教程中使用的队列包对其他人有用,并为用户节省一点时间,还可能避免一些麻烦!

参考

  1. 陈大庆、赛梁赛恩和郭昆,“在线零售业的数据挖掘:使用数据挖掘进行基于 RFM 模型的客户细分的案例研究”,《数据库营销和客户战略管理杂志》,第 19 卷第 3 期,第 197-208 页,2012 年(印刷前在线出版:2012 年 8 月 27 日)。doi: 10.1057/dbm.2012.17)。
  2. Dua d .和 Graff c .(2019 年)。UCI 机器学习知识库[http://archive . ics . UCI . edu/ml]。加州欧文:加州大学信息与计算机科学学院。

协整时间序列和差异可能是坏的时候

原文:https://towardsdatascience.com/cointegrated-time-series-and-when-differencing-might-be-bad-f4e2a9132a0c

你听说过整合的时间序列数据,但协整呢?

迈克尔·贾斯蒙德在 Unsplash上的照片

介绍

时序分析工具包中的一个标准方法是差分变换或差分 。尽管非常简单,差异却非常强大。事实上,它允许我们用几乎是一个裸露的白噪音过程超越复杂的时间序列模型

由于它的简单性,每当单位根检验有意义时,差分法就很流行。虽然这在单变量情况下是相当安全的,但对于多变量时间序列来说,情况就不同了。

让我们用一个简单的例子来说明这一点:

一个激励人心的时间序列例子

为了举例说明潜在的问题,我创建了一个人工的二维线性时间序列:

简单的二维时间序列。(图片由作者提供)

这两个时间序列之间似乎有一些联系,但随着时间的推移,这可能显然只是一个虚假的。在这种情况下,你经常看到的下一步是测试两个时间序列的单位根。

来自 statsmodels 的增广 Dickey Fuller 测试显示显著性得分为 0.8171 和 0.8512。这突出了两个时间序列中可见的单位根。因此,差异转换似乎是合乎逻辑的下一步。让我们对训练集这样做,以预测未来的测试集:

时间序列训练集的第一差异。(图片由作者提供)

接下来,我们可以检查两个 VAR(1)模型的预测性能——一个根据原始时间序列训练,另一个根据转换后的时间序列训练:

没有差异的点预测和 95%区间预测。(图片由作者提供)

两个时间序列预测的总 MSE 在0.3463。显然,具有训练数据差异的模型应该执行得更好:

使用差异进行点预测和 95%区间预测。(图片由作者提供)

这一次,总的 MSE 是0.5105 -大约高出 50%。此外,时间序列 1 的预测间隔比没有任何差异时大得多。流行的差异转换似乎出了点问题。

为什么协整很重要

现在,你可能——理所当然地——认为差异模型的表现不佳纯粹是因为偶然。事实上,我们需要更广泛的实验来从经验上验证我们最初的主张。

然而,实际上有可能证明为什么差分对多变量时间序列分析不利。要做到这一点,让我们后退一步,回到单变量时间序列模型,以及为什么差异转换在这里工作。

为了简单起见,我们只看一下 AR(1)VAR(1) 时间序列。所有结果都可以证明对高阶 AR/VAR 也成立。

单位根 AR(1)时间序列—差分可能安全时

在数学上,AR(1)时间序列看起来如下:

(图片由作者提供)

为了使差分有意义,我们需要时间序列有一个单位根。这是特征多项式解的情况

(图片由作者提供)

位于单位圆上,即

(图片由作者提供)

因此,AR 参数的唯一选择是

(图片由作者提供)

因此

(图片由作者提供)

为了使这个方程稳定,我们从两边减去滞后变量:

(图片由作者提供)

显然,现在最好的预测是预测白噪声。请记住,我们同样可以很好地拟合未转换变量的模型。然而,差分时间序列直接揭示了缺乏任何真正的自回归成分。

一方面,差分法在有单位根的单变量时间序列中显然是一个好的选择。然而,对于多元时间序列来说,事情就不那么简单了。

多元时间序列协整

现在考虑一个 VAR(1)时间,其中我们用向量(粗体,小写)和向量(大写)替换 AR(1)模型中的标量:

(图片由作者提供)

与 AR(1)情况类似,VAR(1)时间序列的单位根意味着

(图片由作者提供)

在一般情况下,自回归参数是单位矩阵。这意味着在我们的 VAR(1)时间序列的边际都是独立的和单位根的。如果我们排除这种情况,继续 AR(1),我们得到

(图片由作者提供)

最后一行也被称为 VAR 时间序列的向量误差校正表示。如果你回到我们的模拟,这就是用来产生时间序列的精确公式。

Lütkepohl 所解释的,通过使 Atilde 秩亏,时间序列变得协整。还有另一个更广泛的协整定义,但我们今天不会讨论它。

显然,协整的 VAR(1)时间序列不同于单变量 AR(1)的情况。即使在差分之后,变换后的值也取决于原始时间序列的过去。因此,如果我们不再考虑原始的时间序列,我们就会丢失重要的信息。

如果你正在处理多元数据,你不应该盲目地应用差分。

如何处理协整

上述结果回避了我们应该如何处理协整的问题。典型地,时间序列分析要么与预测有关,要么与推断有关。因此,我想到了两种不同的方法:

交叉验证和回溯测试——实用的“数据科学”方法。如果我们的目标主要是建立最准确的预测,我们不一定需要检测协整。只要生成的模型是高性能的和可靠的,几乎什么都可以。

通常,可以基于交叉验证和样本外性能测试来选择“最佳”模型。协整的主要含义是小心地应用差分。

另一方面,上述结果也表明,添加原始时间序列作为一个特征一般来说可能是一个好主意。

统计测试 —经典的统计方式。显然,协整对于计量经济学家和统计学家来说并不新鲜。如果您有兴趣了解生成过程本身,这种方法可能更方便。

幸运的是,詹姆斯·麦金农的工作为协整检验提供了广泛的见解。其他流行的协整检验是由 Engle 和 Granger 以及 Soren Johansen 开发的。

在 Python 中,可以在 statsmodels 库中找到 MacKinnon 测试。对于上述时间序列,测试得出的 p 值几乎为零。

结论

希望这篇文章能让你大开眼界,不仅仅是直接比较每个时间序列。你现在应该知道协整是多元时间序列的一个特性,需要小心对待。

请记住,标准的协整只与线性时间序列有关。一旦出现非线性动态,事情可能会变得更加混乱,差异可能会更加不合适。

的确,存在一些最*关于非线性协整的研究。你可能想看看它的更多细节。

参考

【1】恩格尔,罗伯特·f;克莱夫·WJ·格兰杰。协整和误差修正:表示、估计和检验。计量经济学:计量经济学学会杂志,1987 年,第 251-276 页。

【2】汉密尔顿,詹姆斯道格拉斯。时间序列分析。普林斯顿大学出版社,2020 年。

【3】吕特克波尔,赫尔穆特。多重时间序列分析的新介绍。斯普林格科学&商业媒体,2005。

原载于 2022 年 8 月 25 日 https://www.sarem-seitz.comhttps://www.sarem-seitz.com/cointegrated-time-series-and-when-difference-transformations-might-be-bad/

协整流行方法[1/2]:恩格尔-格兰杰方法

原文:https://towardsdatascience.com/cointegration-popular-methods-1-2-the-engle-granger-approach-82b6d270ddf2

Python 中的简单协整方法。恩格尔-格兰杰方法,最直观的方法。

图片作者。

大多数协整方法的数学和概念并不总是很简单。通常,复杂的数学工具模糊了方法的意图和步骤。这种复杂性也影响了对这一主题的进一步探索。

恩格尔-格兰杰的协整方法不受此影响。它可能不是最可靠的方法,也不是最稳定的方法,但它简单而直观。对于更稳健的协整方法,参见 BTCD迪基-富勒直接优化

在这个故事中,我们将用简单的数学来介绍 Engle-Granger 方法,并且我们将编写一个迷你库来在未来的项目中使用这个方法。

故事结构

  • 协整,阶 1
  • 从向量和矩阵构建 1D 时间序列
  • 普通最小二乘残差
  • 确定最合适的关系
  • 合成数据示例
  • 代码摘要
  • 最后的话

协整,阶 1

当提到协整时,我们通常是指一阶时间序列的协整。这意味着我们寻求原始时间序列(不是差异)的线性组合,它是稳定的。有时我们找到它;有时候,它不在那里。数学上,我们寻求系数 α 和可能的常数 c ,使得

是静止的。

需要注意的是,如果 u 是静止的,那么无论常数 c 的值是多少,它都是静止的。该常数仅用于重新确定时间序列值的中心。

从向量和矩阵构建 1D 时间序列

在我们深入研究 Engle-Granger 方法之前,我们需要开发一些工具来简化我们未来的工作。

给定一个系数向量和一个进程矩阵(时间序列),每列一个进程,列的索引对应于向量的索引;以下代码的函数“get_u_t”创建了这些条件的线性组合。此外,函数“get_u_mat”从系数矩阵(也按列索引)创建 u 个时间序列的矩阵(每列一个),即 a 向量的向量。**

您可以看到,我们将在 NumPy 数组中使用的约定是,每一列都是一个时间序列,非常类似于 pandas 数据帧的工作方式。

普通最小二乘残差

让我们回到 u 的等式,稍微改写一下。

这里 x_0 变成了 y ,求和不是从零开始,而是从一开始。

现在是恩格尔-格兰杰方法的本质。他们推测使用 OLS 回归规范:

其中 y 是多个时间序列中的一个, x 是所有其他时间序列。那么因为ε是同分布正态的,因此是*稳的,即使来自实际回归的残差 u 不是同分布正态的,它们也会接**稳性

那么我们的系列 u 就是:

其中使用 OLS 估计系数和常数。

请注意,如果我们有 n+1 时间序列,就有 n+1 种方法来选择 yxs。因此,从使用 OLS 的 Engle-Granger 方法中,我们找到了系数矩阵,而不是单个向量。

换句话说,给定一个矩阵,其中每一列都是时间序列 x_j,我们将 OLS 应用于以下每个规格

则每个 u_j 时间序列为:

构建 u_j 矩阵的系数矩阵定义为:

注意负号;这是因为在回归规范中,线性组合在等号的另一边,我们需要考虑这一点。

下面的代码找到了这样一个矩阵,其中每一列对应于一个系数向量。我们已经为线性回归模型定义了一个接口(所有 scikit-learn 回归都实现了这个接口),这样我们就可以测试原始 OLS 之外的其他模型。使用一个接口,我们注入回归模型的依赖性,而不是硬编码它,从而能够在不重写代码的情况下切换模型。

到目前为止,一切都很好;然而,我们需要解决一个问题;我们应该找到的是 a 向量(带有线性组合系数的向量),而不是n+1a向量(系数矩阵)。我们需要决定如何在所有可能的选择中做出选择。

确定最合适的关系

我们使用 Dickey-Fuller *稳性测试来寻找更可能是*稳的关系。我们估计所有关系的检验统计量,并选择具有最小值的一个。简单。

为了快速和简单起见,我们使用直接估计 Dickey-Fuller 检验统计量的方法:

其中时间序列样本量为 T +1, ρ 为滞后序列和差分序列之间的相关性。

如果你想查看这个结果的完整数学证明,我推荐阅读这个故事

实现它的代码:

我们将前一节中编码的函数“get_engle_granger_coint_mat”包装在另一个函数中,该函数对线性模型使用相同的接口,并选择具有最低 Dickey-Fuller 统计值的向量。

当我们想要一个简单的解决方案来寻找一个带有系数的矢量来产生一个潜在的稳定时间序列 u 时,我们就调用这个函数。这里的关键是潜在地静止。有些情况下,恩格尔-格兰杰方法无法找到*稳的时间序列,所以要谨慎使用。再一次,为了更健壮,尽管更复杂的方法,看看 BTCD直接迪基-富勒优化。****

合成数据示例

为了测试我们刚刚编写的代码,我们将使用离散采样相关布朗运动形式的单位根过程。查看前面关于生成这种过程的故事,因为我们将使用那里讨论的代码来生成相关的布朗路径。我们将这样的代码保存为“brownian_motion.py ”,并将其放在运行以下代码的同一个文件夹中。

最后,我们使用 OLS,注入来自 sklearn 的“线性回归”模型,测试 Engle-Granger 方法:

图片作者。

我们用一个接口对回归进行编码,因为我们想要在不重写代码的情况下自由地改变模型。因此,如果我们现在希望使用套索,我们注入一个来自 sklearn 的套索模型。

图片作者。

能这么轻松的换型号真好。尽管在这个特殊的例子中,OLS 似乎产生了一个更好的结果,但不要低估惩罚回归的力量。由于使用 LASSO 的模型复杂度较低,因此它可以产生更稳定的结果。由您决定哪种回归模型更适合您。

代码摘要

最后,为了完整起见,这里是前面几节中的所有代码。这一次,代码没有那么广泛;不过,文档字符串比代码多。

最后的话

这个故事的目的仅仅是教学,直观地探索协整。使用恩格尔-格兰杰方法有助于探索时间序列之间的关系。每种关系产生不同的时间序列;有些比其他的更可能是静止的。调查为什么会发生这种情况是很有趣的。为什么有些时间序列更适合回归模型?这些问题可以创造有价值的数据洞察力。

然而,Engle-Granger 方法在实际中很少用于计算协整向量。为此,我会建议 BTCD 或者 T2 进行迪基-富勒直接优化。

参考

[1] R. F. Engle 和 C. W. J. Granger,协整和误差修正:表示、估计和检验 (1987),《计量经济学》第 55 卷,第 2 期,第 251-276 页

我希望这个故事对你有用。请继续关注协整流行方法迷你系列的第 2 部分。订阅以便在第 2 部分发布后立即收到通知。

**https://medium.com/subscribe/@diego-barba **

喜欢这个故事吗?通过我下面的推荐链接成为一个媒体成员来支持我的写作。无限制地访问我的故事和许多其他内容。

**https://medium.com/@diego-barba/membership **

科林 2022 亮点

原文:https://towardsdatascience.com/coling-2022-highlights-921fd53b712c

更强大的评估指标,不理解任何东西的语言模型,以及对语法错误纠正的更好评估

照片由来自 Pixabay 的 hyungname 拍摄。

COLING 2022 于 10 月中旬在韩国庆州举行。

这次自然语言处理(NLP)会议收到了来自世界各地的 2253 份提交材料,其中只有 632 份(28.1%)被 1935 名评审人员和 44 名项目委员会的高级区域主席接受出版。

对于这些亮点,我选择了 6 篇文章,保留了我的注意力。

层或表示空间:是什么让基于 BERT 的评估度量变得健壮?

作者 Doan Nam Long Vu(达姆施塔特技术大学)、Nafise Sadat Moosavi(谢菲尔德大学)和 Steffen Eger(比勒费尔德大学)

最*自然语言生成的度量依赖于预先训练的语言模型,例如 BERTScore、BLEURT 和 COMET。这些度量标准与标准基准上的人工评估高度相关。然而,对于那些在他们的训练数据中没有被很好地代表的风格和领域,这些度量的表现如何还不清楚。

换句话说,这些指标是否稳健?

作者发现,BERTScore 对字符级扰动并不稳健。例如,从句子中插入/删除一些字符将显著降低与人类评价的相关性。

图 2 来自 Doan Nam Long Vu(达姆施塔特技术大学)、Nafise Sadat Moosavi(谢菲尔德大学)和 Steffen Eger(比勒菲尔德大学)的论文。

作者表明,使用具有字符嵌入的模型,如 ByT5,而不是标准的 BERT 模型,可以使 BERTScore 更健壮,特别是如果我们使用来自第一层的嵌入。

在我看来,这是一项杰出的工作,可能应用于广泛的自然语言生成任务。

我从这篇论文中得出的结论是,基于单词嵌入的度量标准(如原始的 BERTScore)可能不擅长评估涉及用户生成文本的任务,即可能包含大量语法错误的文本,如来自在线讨论*台的文本。在我看来,用 ByT5 对 BERTScore 的这种改编可以提高对用户生成文本的评估。

注:这篇论文获得了大会优秀论文奖。

语法纠错:我们到了吗?

Muhammad Reza qo rib(新加坡国立大学)和 Hwee Tou Ng(新加坡国立大学)

本文首先表明,最*的语法错误纠正方法(GEC)在标准基准上似乎优于人类。

有趣的是,作者发现评估的 GEC 系统实际上未能纠正标准 GEC 基准的大量句子,这在人类中没有观察到。

GEC 系统在纠正不自然的短语、长句和复杂的句子结构方面似乎更容易失败。

Muhammad Reza Qorib(新加坡国立大学)和 Hwee Tou Ng(新加坡国立大学)论文中的表 4 和表 5

作者得出结论,GEC 系统离人类的表现还很远,但目前的基准对 GEC 系统来说有点太容易了。他们建议建立新的基准,关注 GEC 体系仍然难以纠正的语法错误。

我特别喜欢这项工作,因为它指出了 GEC 系统的一些实际限制。虽然最*的工作赞扬了 GEC 系统的超人性能,但这篇论文有助于降低期望值,并激励未来的研究工作进一步改进 GEC 系统,以便它们最终能够实现与人类相当的性能。

所以回答一下论文的标题:N o,GEC 系统还没有出现。

机器阅读,快与慢:模型何时“理解”语言?

作者:Sagnik Ray Choudhury(密歇根大学、哥本哈根大学)、Anna Rogers(哥本哈根大学)和 Isabelle Augenstein(哥本哈根大学)

这是另一项表明大型语言模型什么都不懂的工作。

他们评估了 5 种语言模型的两种语言学技能:比较和共指消解。

他们的结果清楚地表明,所有的模型都依赖于特定的词汇模式,而不是人类用来出色完成这些任务的信息。

他们表明,通过将模型暴露于分布外的反事实扰动。模型不知道如何处理它们,表现明显不佳。因此,有人认为这些模型只是记忆词汇模式,而不是“理解”

我发现这篇论文特别有趣,因为它选择了一种方法来证明计算机和人类处理文本的方式不同。

关于资源丰富的机器翻译预训练和随机初始化的互补性

由常通赞(中国石油大学)、(JD 探索学院)、(JD 探索学院)、(悉尼大学)、(中国石油大学)和陶大成(悉尼大学 JD 探索学院)

资源丰富的机器翻译是尚未明显受益于预训练语言模型(LM)的任务之一。

通过这项工作,作者提出了一项研究,以更好地理解预训练语言模型在资源丰富的情况下何时以及如何对初始化机器翻译系统有用。

他们首先表明,虽然它对翻译准确性几乎没有影响,但使用预训练的 LM 进行初始化会导致更*坦的损失场景和更*滑的词汇概率分布。

根据这些观察,他们假设使用预训练的 LM 进行初始化可以为域外数据集带来更好的翻译准确性,而随机初始化将更好地翻译域内数据集。他们用实验证实了这些假设。

最后,他们提出了预训练 LM 和随机初始化的协调,以在同一训练中获得它们的最佳效果。

我不确定这项工作最终是否会推动预训练 LM 在资源丰富的机器翻译中的集成。尽管如此,我认为值得一提的是,研究人员仍在积极致力于此。

缓解神经机器翻译的注意力不均衡

作者:孙(人工智能实验室)、(南京大学、实验室)、辛(南京大学)、(南京大学)

先前的工作表明,机器翻译中的所有注意力并不同等重要。

根据这一观察,这项工作提出了一种新颖的“头部面具”,以迫使模型更好地*衡注意力头部之间的训练。

描述了两种非常简单的头部屏蔽方法:随机屏蔽和屏蔽重要头部。

他们观察到,使用这两种方法,不同语言对的 BLEU 都有(轻微的)改善。随机遮罩似乎表现更好,尽管它看起来并不显著。然而,重要头部屏蔽在训练期间更好地成功*衡头部之间的重要性。

我特别喜欢方法的简单性。这种头部屏蔽可以在现有的机器翻译框架中轻松实现。

作为无监督机器翻译的释义生成

由孙晓菲(浙江大学,香农。艾)、田(加州大学)、孟玉贤(香农。艾)、彭南云(美国加州大学)、(浙江大学)、李继伟(浙江大学香农。AI),还有春帆(北京大学)

可用于训练的监督释义生成的大多数训练数据集是英语的,限于几个领域,并且很小。

为了减轻这些限制,无监督的释义生成已在最*的工作中提出。这些方法只需要大量感兴趣语言的文本。

在这篇文章中,作者提出了一种新的方法,灵感来自无监督机器翻译(UMT)。

UMT 需要训练源语言和目标语言的两个语料库。两种语言的单词嵌入首先被联合学习并用于初始化机器翻译系统。然后,使用自动编码和反向翻译损耗的组合来改进该翻译系统的模型。

对于释义生成,我们没有源语言和目标语言。他们建议在领域(或主题)层面进行工作。来自 UMT 的源和目标语言成为源和目标域。为了获得这些域,他们在一些单语数据集上执行 LDA 和 k-means 聚类,其中每个聚类(潜在地)是不同的域。然后,他们为多个领域对训练 UMT 模型。最后,在由先前训练的多个 UMT 模型生成的 2500 万个句子对上训练单个 MT 模型。

他们通过大量的实验来评估他们的方法,以证明对以前工作的改进。这个评价很有说服力:

  • 他们使用了 3 种不同的自动度量标准:iBLEU、BLEU 和 ROUGE
  • 他们从以前的工作中复制了几个基线系统
  • 他们在 4 个不同的基准上进行实验
  • 他们进行了人体评估

作为一个在无监督机器翻译技术上做了很多工作的人,我期待它在某个时候被应用于释义,但找不到如何应用。在本文中,单语数据的主题/领域聚类似乎是其工作的主要原因

虽然这些改进令人信服,但我不明白为什么它能如此有效。在这篇论文中,对于集群的需求并没有很好的动机,但是它似乎是这项工作的一个关键部分。此外,他们没有详细讨论为什么他们的方法比以前的工作更好。这项工作解决了以前的无监督释义生成方法的局限性?

结论

我在这里只选择了发表的 632 篇论文中的几篇。我鼓励你们仔细看看的全部会议记录和研讨会。

如果你对机器翻译的最新进展感兴趣,你也可以看看我的 AMTA 2022 亮点:

如果你想支持这项工作,请在 Medium 上跟随我。

合作、同情和意识(3 C)是构建人工智能和拯救人类的关键

原文:https://towardsdatascience.com/collaboration-compassion-and-consciousness-3-cs-are-the-keys-to-building-ai-and-saving-8930023074c7

意见

在这篇文章中,我探索“坏”人工智能;如果我们不做点什么会有什么影响,它在我们的社会中有多普遍,我们如何才能拯救自己?

人工智能(AI)能控制我们吗?

1963 年,斯坦利·米尔格拉姆做了一个实验,以了解是什么让人们服从权威。这个实验以米尔格拉姆实验而闻名。

资料来源:Wikimedia.org

设置如下:

每当学习者(L)给出错误答案时,实验者(E)要求教师(T)向学习者(L)提供电击。电击逐渐上升到 750 伏,这种电击甚至可以杀死学习者。实际上,没有电击,但是老师(T)不知道。教师(T)只能听到每个电击等级的声音,这些声音是录音的。

实验发现,大多数教师(T)最终对学习者(L)施加了最大的电击,如果电击是真实的,可能会杀死学习者(L)。一些实验者抗议在实验过程中给予电击,但还是继续实验。

这个实验表明,我们大多数人会顺从地听从权威的命令,甚至会杀人。我们在历史上一次又一次地经历过这种情况,人们按照命令杀死他人,当后来被问及他们为什么这样做时,他们的回答是“我只是按照命令”。

如果米尔格拉姆实验中的实验者(E)是一个智能机器算法(或 AI)而不是人类实验者(E)发出命令,会怎么样?可能老师(T)连实验者是机器人都不知道。随着语音生成的发展,算法甚至不需要在理解环境或上下文方面变得智能。它可能只是一台“哑机器”,在不知道上下文的情况下发出命令。人们会遵守这些命令吗?我认为很有可能我们大多数人都会。

上面提到的场景是遥远的未来,还是我们已经在经历的事情?

人已经被智能算法以某种方式控制了吗?

当机器人接管世界时,我不是相信世界末日的人之一。然而,我们已经可以看到一种趋势,即人工智能算法正在塑造我们的观点并控制人们的思想。

像 Meta、Tiktok 和 Twitter 这样的社交媒体公司给我们提供信息,我们开始形成观点。斯科特·盖尔威在他的文章中把社交媒体称为大规模杀伤性武器:大规模分散注意力的武器,其目的是转移人们对物质生活的注意力。例如,我们可以看到在乌克兰-俄罗斯战争中。随着普京输掉一场信息战,他继续在一场我们正在失去兴趣的真正的战争中杀死数千人。

我们越来越多地进入虚拟世界,以至于忘记了现实世界,因此可以很容易地被大规模控制,由算法通过虚拟世界向我们提供信息或数据。

情况可能会变得更糟:鉴于我们在米尔格拉姆实验中看到的情况,如果一些坏演员(或权威)决定大规模地使用人工智能来控制人们的思想,那么我们听从命令发动战争和杀害他人的日子就不远了。我们已经可以在社交媒体上看到这一点,人们在不了解对方的情况下互相争斗、表达仇恨和诋毁。看看社交媒体上的仇恨,正在进行的乌克兰-俄罗斯战争真的有可能将我们引向第三次世界大战。

是否为时已晚,或者我们能从“坏”人工智能中拯救世界?

有两种方法可以控制“坏”人工智能的增长:a)通过规章制度,b)我们,人民,意识到并开始做一些事情。

规程

就我个人而言,我从来不喜欢监管,因为它会创建一个自上而下的结构。谁来监管监管者?如果监管者变成了坏演员,那该怎么办?然而,有时它是我们不得不接受的一种必要的邪恶。

最*一段时间,我们可以看到政治家们正在赶上人工智能可以造成什么样的危害,并能够提出良好的法规。例如,最*来自欧盟的数字服务法案 (DSA)提案将让用户更好地理解如何向他们推荐内容,以及如何做出适度的决定。如果*台出错,用户也将享有恢复权利。这可能会解决一些问题,但还不够。一些流氓国家和政客总是有可能滥用法规来控制人民的自由。米尔格拉姆的实验已经表明,我们可以很容易地屈服于权威,所以如果我们仅仅依靠法规,“坏”人工智能的危险会更大。此外,监管者需要大量时间来建立良好的监管。

合作、同情和意识(3 C)

我们对付“坏”人工智能的最好办法是我们这些人。我们必须更加意识到正在发生和可能发生的事情,并建立我们自己想要使用的解决方案。考虑到当今大多数人工智能解决方案对人类和社会的巨大影响,无论如何,脱离人类和社会环境来构建解决方案是有害的。

不同人才之间的合作使我们能够弥合不同心态之间的理解差距,分享知识,并团结人民和价值观。因此,它有助于创造同情心,并利用群体智慧、多样性和包容性为这些社区的长期利益服务。然而,重要的是不仅要有象征性的多样性,还要有真正的观点多样性。

另一个关键要素是意识。由于这个世界上存在如此多的分歧,我们需要明白,在内心深处我们都是一体的,我们所联系的所有群体(民族、宗教、性取向、性别、肤色等)都只是我们头脑中的一个幻觉。我们有同样的恐惧,同样的渴望,和相似的梦想,我们所有的命运都是一样的。因此,我们的意识是集体的。

J.克里希那穆提— Ojai 1982 —与科学家的讨论 2 —心理痛苦

如果我们想要生存并面对未来世界和来自坏演员(和人工智能)的挑战,我们必须带着同情和意识一起合作。否则我们会让智能机器自相残杀,互相争斗,互相压制。我们已经可以看到由大型科技巨头构建的这样的人工智能算法压制不同意见的人。

另一方面,由三个 C(协作、同情和意识)构建的人工智能将帮助我们消除地方性的社会学和历史偏见以及社会中存在的其他不*等。 AI 不会挑战现状,除非这个过程是特意设计来这么做的。

用 3C 的人工智能很难实现吗?

"永远不要怀疑一小群有思想、有奉献精神的公民能够改变世界."—玛格丽特·米德

从文明之初,控制人民就一直是国王和领袖们的目标。在过去,通过权力和力量,现在在人工智能时代将通过数据和知识控制我们的思想。这是非常可怕的,只需点击一个按钮,使用算法,这种控制可以更有效地大规模进行。

但与此同时,在地球的历史上从未有过,由于获取知识的途径被大众化,如此多的人也获得了力量——互联网、连通性和知识。坏演员可以使用的同样的工具,我们这些人也可以出于好的理由获得和使用。有史以来第一次,这么多人有能力做出改变。

机器没有那么聪明,但是如果我们不够警惕和警觉,我们就会被坏人控制。因此,在为时已晚之前,我们有责任用 3C 的(协作、同情和意识)来构建人工智能和未来的解决方案。

小传:出于文章中提到的原因,我创办了 Omdena,一个构建人工智能解决方案的合作*台。随时查看 网站 以及所做的工作。

参考

[1]https://www . creative-resolution . com/post/building-ethical-and-inclusive-ai-through-bottom-up-community-collaboration

PyTorch Lightning 上的协作去噪自动编码器

原文:https://towardsdatascience.com/collaborative-denoising-autoencoders-on-pytorch-lightning-bc79f38f0f7a

自动编码器是一种简单的神经网络推荐方法

推荐系统在我们的数字生活中无处不在。为了提高推荐项目的质量,研究者们对现有的文献提出了数百种算法。许多人已经找到了进入大型生产系统的方法,同时新的算法也一直在开发和测试中。

今晚我应该看什么?维多利亚·希思在 Unsplash 拍摄的照片。

在这篇文章中,我将介绍姚等人的协同去噪自动编码器。CDAE 是自动编码器的变体,非常适合推荐器领域。让我们先处理一些预备工作:

  • 自动编码器是试图从输入中学习压缩映射的神经网络。它首先将输入强制到一个信息瓶颈(编码器),然后尝试从压缩的表示(解码器)重新创建原始输入。
  • 瓶颈有多种形式,例如隐藏层中的节点少得多、输入中添加了噪声、损失函数中有正则项,或者多种技术的组合。
  • 通常,自动编码器用于预先训练大型网络,因为它不需要来自数据的额外标签。它使用数据本身进行训练,这就是所谓的自我监督学习。

自动编码器非常值得推荐,因为它们可以从输入中学习有效的低维表示。这与矩阵分解非常相关,它从评级矩阵中学习用户和项目的潜在表示。矩阵分解是许多推荐系统的主力,对研究人员和工程师来说,改进、概括、重构甚至重新发明这个轮子的努力非常有吸引力。在推荐中,输入非常稀疏(长尾问题),CDAE 可能是解决稀疏性的一种方法。

CDAE 有以下建筑。输入层有一个用户节点(红色),它使用户个性化的信息能够在网络中流动。隐藏层的节点比输入和输出少得多。这类似于矩阵分解和主成分分析中的潜在维数的思想。训练网络包括在一定程度上破坏输入,并通过网络将其转发。即使存在信息瓶颈和损坏的数据,输出层也必须接*输入。这使得网络创建了评级的有效低维映射。为了推断,用户评级向量没有被破坏,并且在网络中正向传递。n 个最高输出构成了前 n 个推荐项目。

吴耀等人 2016 年。前 N 名推荐系统的协同去噪自动编码器。【https://doi.org/10.1145/2835776.2835837】()

履行

对于我的实现,我非常感谢 James Le 的代码和他的文章的工作。我也推荐 RecBole 供读者研究。我将使用 2003 年发布的拥有 6000 个用户和 4000 个项目的 MovieLens 1M 数据集 [1]。

我使用 Pytorch Lightning 来构建我的代码。光线调节用于超参数优化。 CometML 用于记录我的结果。你可以在这里上我的 Kaggle 笔记本,在这里上 CometML 实验

数据及其数据加载器

该数据集包含 100 万电影评级,因此得名。在本练习中,我们仅保留评分≥4 的评分。评分低于 5 的所有项目和用户将被反复删除。它产生了以下评级矩阵。它很小,但对于演示来说已经足够好了。

Starting interactions info
Number of rows: 6038
Number of cols: 3533
Density: 2.697%
Ending interactions info
Number of rows: 6034
Number of columns: 3125
Number of ratings: 574376
Density: 3.046%

对于数据分割,我做了以下工作:至少有 5 个评级的用户有 20%的评级成为验证集的一部分。我对测试集重复这个过程。

数据准备完毕后,我开始为 PyTorch 安装数据加载器。我们有三个版本——训练、测试和推理。训练加载器包含用于训练的稀疏矩阵。测试加载器包含训练矩阵和目标矩阵。推理加载器包含用于推理的用户 id。如果我们不这样做,那么我们的用户 id 索引将从提供的行为稀疏矩阵中计算,而不是从原始输入空间中计算。

模型

PyTorch Lightning 需要一些简单的面向对象编程规则来构建训练循环。好处是巨大的:一个完整的框架可以依靠各种回调、记录器、调度策略、多 GPU 支持等等。我有以下要点供你检查,但请在这里检查整个课程的

为了训练,我们使用 CometML & Ray Tune duo。前者通过CometLoggerCallback收集指标。后者只需添加几行代码即可完成超参数调整。在本练习中,将通过网格搜索彻底使用这些参数。如果你需要更智能的东西,那么还有其他搜索算法可以尝试,如果需要的话,还有时间预算来限制成本。

模型结果

CometML 产生了一些我在机器学习中见过的最漂亮的面板。您可以将您的参数绘制成图表,通过 notes 与其他人协作,并且为您的团队拥有一个模型注册表。值得一试。下面这个仪表盘是不是很神奇?这是我们在上面做的超参数调整。

图片由作者使用 CometML 制作。每个图表都是训练过程中每一步的指标。

右下角的*行坐标图显示了超参数搜索如何获得最佳模型。我以下面的超参数结束。在本练习中,隐藏节点的数量和损坏率是最终指标的最关键影响因素。

{'hidden_dim': 100, 'corruption_ratio': 0.3, 'learning_rate': 0.3, 'wd': 0, 'activation_fun': 'tanh'}

对于这些指标,有些应该是熟悉的。这些指标被参数化为@ k,这是前 k 个推荐的项目。精度和召回率类似于分类设置中的精度和召回率。NDCG 是衡量排名质量的一个标准。以下是一些“超出”准确性的指标。虽然需要一个好的 NDCG,但该数据集相当密集,因此推荐可能会非常重复和枯燥。

  • 基尼系数——衡量用户间推荐项目差异的指标。越低,推荐越独特。
  • 覆盖率——在训练集中的所有项目中,推荐了多少个项目
  • 新鲜感——衡量前 k 个推荐有多受欢迎的指标。越低,推荐就越“不足为奇”。

我们将何去何从?

此时,您可能对自动编码器如何在推荐设置中工作有了很好的理解。这可以说是这个领域中最简单的算法之一,但是你也应该尝试变分自动编码器和序列自动编码器。

您还可以将您的工作从笔记本升级到 MLOps 管道。MLOps 是关于在机器学习中创造可持续性的。考虑到你有十几个项目,模型,训练循环,服务管道…很明显,需要一个框架来组织事情。Kedro 是管理所有这些的一种方式。

最后,我还写了一个项目,在那里我实现了一个从数据工程到培训、测试和部署的推荐管道。这是一个漫长的过程,但让你的 ML 可持续发展是值得的。

感谢阅读!

[1] F .麦克斯韦·哈珀和约瑟夫·康斯坦。2015.电影镜头数据集:历史和背景。美国计算机学会交互式智能系统汇刊 5,4:19:1–19:19。

请到 http://itstherealdyl.comhttps://itstherealdyl.com/2022/04/28/collaborative-denoising-autoencoders-on-steam-games/查看我的博客,了解更多我的作品。

如何使用 Python 在终端中打印彩色文本

原文:https://towardsdatascience.com/coloured-text-terminal-python-dc5692ee6319

用 Python 打印彩色文本到标准输出和错误

照片由 Levi GuzmanUnsplash 上拍摄

打印标准输出或标准错误是开发人员在记录有用信息甚至调试部分源代码时需要执行的最常见的操作之一。

在许多情况下,从冗长的角度来看,被报告的信息量可能是相当大的。因此,重要的是要确保打印的任何信息都是一致的,并且对用户来说是可读的。为了达到这个目标,你可以使用的一个技巧是在标准输出/错误上给打印出来的文本着色。

在今天的文章中,我们将探讨两种不同的方法,在使用 Python 编写应用程序时,您可以利用这两种方法在终端上打印彩色文本。

使用 ANSI 转义序列打印彩色文本

ANSI 转义序列是一种标准,用于定义和控制终端选项,如颜色、字体样式和光标位置。

这些序列由字节序列组成,以一个 ASCII 转义字符(即八进制的\033)和一个括号字符(因此,类似于\033[)开始,这些字符被嵌入到文本和序列需要有效的特定位置。

请注意,使用 ANSI 转义序列,您甚至可以对文本应用进一步的格式,包括下划线、粗体等。

现在让我们创建一个由一些 ANSI 转义序列组成的简单类,这些转义序列可用于指定不同类型的文本格式和样式。

class TextFormatter:
    """
    Contains numerous ANSI escape sequences used to apply
    formatting and styling to text.
    """
    # Blue colouring
    BLUE_COL = '\033[94m' # Red Colouring
    RED_COL = '\033[91m' # Green colouring
    GREEN_COL = '\033[92m'

    # Reset formatting and styling
    RESET = '\033[0m' # Underlined text
    UNDERLINE = '\033[4m' # Yellow colouring
    YELLOW_COL = '\033[93m'

现在你所需要做的就是简单地将这些序列添加到你想要格式化或样式化的文本的开头。

print(
  f'{TextFormatter.BLUE_COL}This is a text in blue'
  f'{TextFormatter.RESET}'
 )
 print(
  f'{TextFormatter.RED_COL}This is a text in red'
  f'{TextFormatter.RESET}'
 )
 print(
  f'{TextFormatter.GREEN_COL}This is a text in green'
  f'{TextFormatter.RESET}'
 )
 print(
  f'{TextFormatter.UNDERLINE}This is an underlined text'
  f'{TextFormatter.RESET}'
 )
 print(
  f'{TextFormatter.YELLOW_COL}This is a text in yellow'
  f'{TextFormatter.RESET}'
 )

标准输出(终端)上的输出应该与下面的屏幕截图中所示的相同:

Python 标准输出中的彩色文本—来源:作者

值得一提的是,无论何时使用 ANSI 转义序列,都必须重新设置格式。否则,应用的样式和格式将继续使用。这就是为什么我们在我们的TextFormatter类下定义了RESET序列的原因,只要你想终止先前样式/格式的效果,就应该使用这个序列。

例如,假设我们想打印绿色文本,但是我们忽略了RESET序列:

print(TextFormatter.GREEN_COL + 'Hi!')

这将对输出文本进行着色,但是即使我们的应用程序结束,着色仍然有效,如

来源:作者

在启用和禁用 ANSI 转义序列时,您甚至可以创建一个函数来简化您的工作。例如,下面的函数将完成这个任务,您将不再需要关心重置应用的样式:

def print_formatted_text(ansi_seq: str, text: str) -> None:
    print(f'{ansi_seq}{text}{TextFormatter.RESET}')

你可以像下面这样调用它:

print_formatted_text(TextFormatter.GREEN_COL, 'Hello, World!')

还有一点很重要,那就是 ANSI 转义序列并不能在所有*台上开箱即用。如果您在 Windows 计算机上运行 Python 应用程序,您可能需要运行额外的命令才能使格式和样式有效。这通常可以通过一个简单的命令来实现:

import os os.system('color')

使用 Colorama 进行跨*台着色

如果您想避免使用 ANSI 转义序列定义格式和样式的手动过程,您可以利用 PyPI 上提供的第三方 Python 包[Colorama](https://pypi.org/project/colorama/)

该软件包提供了跨*台的文本着色,这意味着 ANSI 转义字符序列可以在 MS Windows 上开箱即用。

你可以通过pip在 PyPI 上安装包:

$ pip install Colorama

您可以用与我们在本文前一节中讨论的自定义方法非常相似的方式来使用它:

from colorama import Fore
from colorama import Styleprint(f'Text in {Fore.GREEN}green{Style.RESET_ALL} color!')

终端上的输出将是:

Python 和 Colorama 标准输出上的彩色文本—来源:作者

其他选择

[termcolor](https://pypi.org/project/termcolor/)软件包实现了让用户在终端上打印彩色文本的功能。但是请注意,在后台,termcolor会发出 ANSI 代码,因此它可能无法在开箱即用的 Windows 上工作。例如,为了让 ANSI 转义序列工作,您可能必须运行os.system('color')

最后的想法

在今天的教程中,我们讨论了以一致和可读的方式打印标准输出和错误信息的重要性。有一种技术可以帮助你朝着这个方向前进,那就是在向终端报告这个信息的时候加入颜色。

有几种不同的方法可以帮助你实现这个目标。从简单的 ANSI 转义序列到第三方 Python 包,如Coloramatermcolor。但是请注意,正如我们在本文中讨论和展示的那样,除非您在源代码中运行一些额外的命令,否则这些方法中的一些并不能在所有*台上开箱即用。

成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。

https://gmyrianthous.medium.com/membership

相关文章你可能也喜欢

对抗维度的诅咒

原文:https://towardsdatascience.com/combating-the-curse-of-dimensionality-62b0c2bf3472

方法来减少数据集的维数,以减少过度拟合并加速该过程

照片由莫仁·许Unsplash 上拍摄

当您处理高维数据时,您很可能会遇到过拟合、较长的计算时间和/或模糊的见解等问题。在本文中,我们将探讨一些高维数据的降维方法。但在此之前,我们先说几件在深入降维之前需要了解的重要事情。

降维有两种方式,即特征选择和特征提取。 特征选择 是指从数据集中选取最重要的原始形式的特征进行建模。而 特征提取 是指在不丢失任何重要信息的情况下,从现有特征中创建新特征。

数据集中要素的数量必须小于记录的总数,如果要增加要素,观测值的数量应呈指数增长。具有更多特征和更少记录的数据集将导致模型过度拟合,这是我们一直想要避免的。因此,我们丢弃对决策没有太大帮助的不重要的特征,只保留重要的特征。但是,我们如何知道哪些特性对我们来说是重要的呢?幸运的是,Python 库使降维过程变得更加容易。那么,让我们来了解一下降低数据维数的不同方法,以及如何在 Python 中实现它们。

具有方差阈值的特征选择

顾名思义,方差代表数据集中的可变性,表明分布有多分散。如果一个特征的方差很低,那么这个特征就不那么重要。假设我们有一个狗的健康数据集,它具有不同的特征,指示狗的体重、身高、身体质量指数等。如果权重特性始终只有一个或两个值,则权重的方差为零,因此对我们来说不重要。由于所有记录中的权重都是相同的,因此很明显,该特征对于我们产生未知见解或对预测模型的训练没有太多帮助。

作者创建的样本数据集

Python 的 scikit-learn 库提供了一种使用variance threshold估算器删除低方差特性的简单方法。我们可以将阈值参数设置为等于我们想要设置的任何方差阈值。方差低于阈值的要素会被自动丢弃。

方差阈值的 Python 实现

在第 1 行和第 2 行中,我们导入并定义了阈值等于 1 的估计量。在第 5 行中,我们将估计量与数据集相匹配。在第 8 行中,我们创建了一个具有方差等于 1 或更大的特征的变量掩码,在第 9 行中,我们通过将掩码应用于原始数据集来获得缩减的数据集。

具有成对相关性的特征选择

相关性定义了两个特征之间的关系。正相关意味着如果一个特性增加,另一个也会增加,负相关意味着如果一个特性增加,另一个会减少。为了清楚地理解,假设相同的狗物种数据集,但这次我们将着眼于两个特征,即体重和身高。如果这两个变量之间的相关性为 0.99,则它们具有很强的正相关意义,如果狗的体重增加,其高度也增加,反之亦然。因此,使用这两个特征进行建模只会导致过度拟合和资源/时间开销,因为一个特征足以映射特征和目标之间的关系。

成对关联的 Python 实现

在第 1 行中,我们计算数据集中所有要素的相关性。在第 4 行和第 5 行,我们创建了一个相关矩阵的布尔掩码,以消除重复的相关值,并将该掩码应用于原始的相关矩阵。在第 8、9 和 10 行中,我们对简化的矩阵列运行一个循环,以获得相关性大于 0.9 的列,并打印出我们需要删除的列名。

递归特征消除

递归特征消除或 RFE 是一种使用监督机器学习算法的特征选择技术。该算法帮助它获得每个特征的系数,并在每次迭代中消除具有最低有效系数的特征,直到它达到期望的特征数量。

RFE 的 Python 实现

在第 1 行和第 2 行,我们导入了决策树分类器和 RFE。在第 5–7 行,我们将决策树定义为 dt,将 RFE 定义为 rfe,其中 estimator 设置为等于 dt,n_features_to_select 设置为 5,这意味着我们希望从数据集中获得 5 个最重要的特征。在第 10 行,我们将重要的特性定义为 selected_features,在第 11 行,我们打印 selected_features 来查看我们最重要的特性。

用主成分分析或 PCA 进行特征提取

PCA 使用线性代数在协方差矩阵、特征值和特征向量的帮助下将原始变量转换成新变量。它从寻找协方差矩阵的特征值和特征向量开始,并使用特征值和特征向量来计算主分量。较高的特征值是重要的,其形成主分量,并且通过在其中存储具有重要信息的变量来获得特征矩阵。通过将原始数据集的转置与所获得的特征向量的转置相乘,获得最终的数据矩阵。

PCA 的 Python 实现

在第 1 行,我们导入 PCA。在第 4 行中,我们将 pca 定义为 PCA,并传递了等于 5 的 n_components,表示我们需要 5 个提取的特征。在第 7 行和第 8 行,我们创建了一个新的数据集,包含我们新提取的特征。

结论

在本文中,我们讨论了维数灾难,并理解了特征选择和特征提取之间的区别。然后,我们学习了四种降维技术以及如何在 Python 中实现它们。

我真的希望,这有助于你学习新的技能或消除对降维的疑虑。如果你有任何问题,请在评论中联系我。点击拍手,分享文章,如果你喜欢它。感谢您的阅读!

在熊猫中将地层数据与测井测量相结合

原文:https://towardsdatascience.com/combining-formation-data-with-well-log-measurements-in-pandas-8c29589ec132

PYTHON 和岩石物理学

用 Python 集成地下测量

马丁斯·克拉斯廷斯摄影:https://www.pexels.com/photo/cracked-stone-wall-838981/

当处理地下数据时,我们经常处理以不同方式采样的数据集。例如,以规则的增量在地下的间隔上连续记录测井测量值(例如,每 0.1 米的测量值),而地层顶部是单个深度点。

测井和地质构造数据的不同采样率。图片由作者提供。

在本文中,我们将介绍一种将地质地层顶部数据与测井测量相结合的方法。这将允许我们将这些数据用于未来的机器学习过程和数据可视化。

视频教程

这个教程的视频版本可以在我的 YouTube 频道上找到,链接如下。

本教程中使用的数据

本教程中使用的数据是 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 来加载和存储我们的地层数据,以及 lasio 来从 las 文件加载我们的测井数据。

import lasio
import pandas as pd

接下来,我们将开始导入我们的测井数据。为此,我们需要调用lasio.read()并传入。las 文件。

由于我们将在 pandas 中工作,我们需要将 lasio 对象转换为 dataframe,然后重置索引。这将获取设置为深度的当前索引,并将其作为新列放入 dataframe 中。

df_19SR = lasio.read('Data/15-9-19_SR_COMP.las').df()
df_19SR.reset_index(inplace=True)

从 las 文件中加载后,Volve 井 15/9–19-SR 的 Pandas 数据帧。图片由作者提供。

装载地层数据

地层数据通常存储在 csv 文件的简单表格中,带有地层名称和相关深度。因此,我们可以通过使用pd.read_csv()并传入文件名来使用 pandas 加载 csv。

在这个例子中,文件没有标题行,所以需要添加一个标题行,我们可以通过使用names参数来指定名称。

df_19SR_formations = pd.read_csv('Data/Volve/15_9_19_SR_TOPS_NPD.csv', header=None, names=['Formation', 'DEPT'])df_19SR_formations['DEPT'] = df_19SR_formations['DEPT'].astype(float)df_19SR_formations

一旦地层数据被加载到数据帧中,我们就可以通过调用其名称:df_19SR_formations来查看该数据帧,这将返回以下内容:

Volve 油田 15/9–19-SR 井内地质构造的名称和深度。图片由作者提供。

合并数据

现在有了两个包含我们想要处理的数据的数据帧,我们需要将它们组合起来。我们可以通过创建一个函数来实现这一点,然后使用.apply()方法来检查每个深度值,并查看在该深度级别应该出现什么样的地层。

在下面的函数中,我们首先创建地层深度和名称的列表。

然后,我们逐一循环,检查三个条件:

  1. 如果我们在列表中的最后一个编队(项目)
  2. 如果我们位于列表中第一个地层(项目)之前的深度
  3. 如果我们在两个地层深度之间
def add_formations_to_df(depth_value:float) -> str:
    formation_depths = df_19SR_formations['DEPT'].to_list()
    formation_names = df_19SR_formations['Formation'].to_list()

    for i, depth in enumerate(formation_depths):
        # Check if we are at last formation
        if i == len(formation_depths)-1:
            return formation_names[i]

        # Check if we are before first formation
        elif depth_value <= formation_depths[i]:
            return ''

        # Check if current depth between current and next formation
        elif depth_value >= formation_depths[i] and depth_value <= formation_depths[i+1]:
            return formation_names[i]

一旦编写了函数,我们就可以在数据帧中创建一个名为 FORMATION 的新列,并将这个新函数应用到DEPT列。

df_19SR['FORMATION'] = df_19SR['DEPT'].apply(add_formations_to_df)df_19SR

当我们调用 dataframe 时,我们可以看到我们的新列中有地层数据。

结合地层数据和测井数据后的数据帧。图片由作者提供。

我们可以仔细看看一个具体的深度范围:4339 到 4341 米,看看地层名称的变化。

df_19SR.loc[(df_19SR['DEPT'] >= 4339) & (df_19SR['DEPT'] <= 4341)]

使用将测井数据和地层顶部合并在一起后的数据帧。在熊猫中应用()方法。图片由作者提供。

正如我们在上面看到的,斯卡格拉克调频在 4340 米后开始,在此之前,我们有胡金调频。

摘要

将地质地层信息集成到测井数据集中是一个相对简单的过程。一旦我们在主数据框架中有了这些信息,我们就可以使用它来可视化我们关于地质的数据,并且在我们进行机器学习过程时也可以利用这些信息。

如果您想了解如何将地层顶部与测井测量结果结合起来进行可视化,请查看这篇文章:

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

其次,通过注册会员,你可以获得完整的媒介体验,并支持我和其他成千上万的作家。每月只需花费你 5 美元,你就可以接触到所有精彩的媒体文章,也有机会通过写作赚钱。

如果你用 我的链接报名,你直接用你的一部分费用支持我,不会多花你多少钱。如果你这样做了,非常感谢你的支持!**

命令行数据分析变得简单

原文:https://towardsdatascience.com/command-line-data-analytics-b2ac88f912d1

使用 Python 支持的 SQL

加布里埃尔·海因策Unsplash 拍摄的照片

当涉及到数据处理时,命令行非常强大。尽管如此,我们中的许多人并没有利用数据。我能想到一些原因:

  • 可读性差:重点是尽量减少您需要键入的内容,而不是一系列命令的可读性;
  • 陡峭的学习曲线:许多命令,有许多选项;
  • 看起来过时了:这些工具中的一些是从 70 年代开始的,目标是分隔文本文件(而不是像 JSON 和 YAML 这样的现代格式)。

这些促使我编写一个命令行工具,它注重可读性、易学性和现代数据格式,同时利用命令行生态系统。最重要的是,它还利用了 Python 生态系统!遇见 SPyQL —中间有 Python 的 SQL:

**SELECT** date.fromtimestamp(purchase_ts) **AS** purchase_date,
  sum_agg(price * quantity) **AS** total
**FROM** csv('*my_purchases.csv*')
**WHERE** department.upper() == 'IT' and purchase_ts is not Null
**GROUP** BY 1
**ORDER** BY 1
**TO** json

SPyQL 在行动

我认为了解 SPyQL 并熟悉命令行的最佳方式是打开终端并解决问题。在这种情况下,我们将尝试了解手机信号塔的地理分布。开始吧!

设置

让我们从安装 SPyQL 开始:

$ pip3 install -U spyql

并检查其版本:

$ spyql --version
spyql, version 0.8.0

让我们也安装 MatplotCLI ,这是一个利用 Matplotlib 从命令行创建绘图的实用程序:

$ pip3 install -U matplotcli

最后,我们将下载一些示例数据(您也可以将 URL 复制粘贴到您的浏览器,并从那里下载文件):

$ wget [https://raw.githubusercontent.com/dcmoura/blogposts/master/spyql_cell_towers/sample.csv](https://raw.githubusercontent.com/dcmoura/blogposts/master/spyql_cell_towers/sample.csv)

该 CSV 文件包含 2022 年 9 月 10 日添加到 OpenCellid 数据库的手机信号塔数据。( OpenCellid 项目的OCID-diff-cell-export-2022–09–10-T000000.csv文件,根据知识共享署名-类似共享 4.0 国际许可未经修改进行再分发)。

检查数据

让我们通过获取文件的前 3 行来查看数据:

$ head -3 *sample.csv*radio,mcc,net,area,cell,unit,lon,lat,range,samples,changeable,created,updated,averageSignal
GSM,262,2,852,2521,0,10.948628,50.170324,15762,200,1,1294561074,1662692508,0
GSM,262,2,852,2501,0,10.940241,50.174076,10591,200,1,1294561074,1662692508,0

您可以用 SPyQL 做同样的操作:

$ spyql "**SELECT** * **FROM** csv **LIMIT** 2" < *sample.csv*

或者

$ spyql "**SELECT** * **FROM** csv('*sample.csv*') **LIMIT** 2"

请注意,我们告诉获取 2 行数据,而不是 3 行文件(其中第一行是标题)。SPyQL 的一个优点是我们可以很容易地改变输出格式。让我们将输出更改为 JSON,并查看第一条记录:

$ spyql "**SELECT** * **FROM** csv('*sample.csv*') **LIMIT** 1 **TO** json(indent=2)"{
  "radio": "GSM",
  "mcc": 262,
  "net": 2,
  "area": 852,
  "cell": 2521,
  "unit": 0,
  "lon": 10.948628,
  "lat": 50.170324,
  "range": 15762,
  "samples": 200,
  "changeable": 1,
  "created": 1294561074,
  "updated": 1662692508,
  "averageSignal": 0
}

查询数据

让我们先数一数我们有多少记录:

$ spyql "**SELECT** count_agg(*) **AS** n **FROM** csv('*sample.csv*')"n
45745

注意,聚合函数有后缀_agg,以避免与 Python 的函数冲突,如minmaxsum

现在,让我们按类型数一数我们有多少个手机信号塔:

$ spyql "**SELECT** radio, count_agg(*) **AS** n **FROM** csv('*sample.csv*') **GROUP BY** 1 **ORDER BY** 2 DESC **TO** pretty"radio        n
-------  -----
GSM      31549
LTE      12996
UMTS      1182
CDMA        16
NR           2

注意漂亮的打印输出。我们可以通过将输出格式设置为 JSON 并将结果传送到 MatplotCLI 来绘制上述结果:

$ spyql "**SELECT** radio, count_agg(*) **AS** n **FROM** csv('*sample.csv*') **GROUP BY** 1 **ORDER BY** 2 DESC **TO** json" | plt "**bar**(radio, n)"

由 MatplotCLI 使用 SPyQL 查询的输出创建的 Matplolib 图

有多简单?😃

查询数据:一个更复杂的例子

现在,让我们来看看当天新增手机基站最多的前 5 个国家:

$ spyql "**SELECT** mcc, count_agg(*) **AS** n **FROM** csv('*sample.csv*') **GROUP** **BY** 1 **ORDER** **BY** 2 DESC **LIMIT** 5 **TO** pretty" mcc      n
-----  -----
  262  24979
  440   5085
  208   4573
  310   2084
  311    799

MCC 代表移动国家代码(262 是德国的代码)。MCC 的第一个数字标识区域。这里有一段来自维基百科的摘录:

0: Test networks
2: Europe
3: North America and the Caribbean
4: Asia and the Middle East
5: Australia and Oceania
6: Africa
7: South and Central America
9: Worldwide

让我们复制粘贴上述地区列表,并创建一个新的文件名mcc_geo.txt。在 mac 上,这和$ pbpaste > mcc_geo.txt一样简单,但是你也可以将它粘贴到文本编辑器中并保存。现在,让我们要求 SPyQL 以 CSV 格式打开该文件并打印其内容:

$ spyql "**SELECT** * **FROM** csv('*mcc_geo.txt*') **TO** pretty" col1  col2
------  -------------------------------
     0  Test networks
     2  Europe
     3  North America and the Caribbean
     4  Asia and the Middle East
     5  Australia and Oceania
     6  Africa
     7  South and Central America
     9  Worldwide

SPyQL 检测到分隔符是冒号,并且文件没有标题。我们可以使用 colN 语法来寻址第n列。现在,让我们创建一个 JSON 对象,它具有与输入行一样多的键值对。让输入的第一列为,第二列为,并将结果保存到一个新文件中:

$ spyql "**SELECT** dict_agg(col1,col2) **AS** json **FROM** csv('*mcc_geo.txt*') **TO** json('*mcc_geo.json*', indent=2)"

我们可以使用cat来检查输出文件:

$ cat *mcc_geo.json* {
  "0": "Test networks",
  "2": "Europe",
  "3": "North America and the Caribbean",
  "4": "Asia and the Middle East",
  "5": "Australia and Oceania",
  "6": "Africa",
  "7": "South and Central America",
  "9": "Worldwide "
}

基本上,我们已经将所有输入行聚合到一个 Python 字典中,然后将其保存为一个 JSON 文件。尝试从SELECT中移除AS json别名,以理解我们为什么需要它:-)

现在,让我们按地区而不是按 MCC 来获取统计数据。为此,我们将加载刚刚创建的 JSON 文件(使用-J选项)并进行字典查找:

$ spyql -Jgeo=*mcc_geo.json* "**SELECT** geo[mcc//100] **AS** region, count_agg(*) **AS** n **FROM** csv('*sample.csv*') **GROUP** **BY** 1 **ORDER** **BY** 2 DESC **TO** pretty"region                               n
-------------------------------  -----
Europe                           35601
Asia and the Middle East          5621
North America and the Caribbean   3247
Australia and Oceania              894
Africa                             381
South and Central America            1

我们将整数除以 100,得到 MCC 的第一个数字,然后在我们刚刚创建的 JSON(作为 Python 字典加载)上查找这个数字。这就是我们在 SPyQL 中通过字典查找进行连接的方式:-)

在查询中利用 Python 库

SPyQL 的另一个优势是我们可以利用 Python 生态系统。让我们试着做更多的地理统计。让我们来数一数欧洲 H3 单元(分辨率为 5)的塔。首先,我们需要安装 H3 库:

$ pip3 install -U h3

然后,我们可以将经纬度对转换为 H3 单元,通过 H3 单元计算我们有多少座塔,并将结果保存到 CSV 中:

$ spyql "**IMPORT** h3 **SELECT** h3.geo_to_h3(lat, lon, 5) **AS** cell, count_agg(*) **AS** n **FROM** csv('*sample.csv*') **WHERE** mcc//100==2 **GROUP** **BY** 1 **TO** csv('*towers_by_h3_res5.csv*')"

借助开普勒,可视化这些结果相当简单。只要去 kepler.gl/demo 的打开上面的文件。您应该会看到类似这样的内容:

通过 SPyQL 的 H3 池(分辨率 5)对聚集进行开普勒可视化

最后的话

我希望您喜欢 SPyQL,并且我可以向您展示从命令行查询数据是多么简单。在这篇关于 SPyQL 的第一篇文章中,我们只是触及了皮毛。我们能做的还有很多。在本文中,我们几乎没有利用 Shell 和 Python 生态系统。我们使用了一个小文件(SPyQL 可以处理 GB 大小的文件,而不会影响系统资源)。所以,敬请期待!

试用 SPyQL,然后将您的想法反馈给我。谢谢大家!

资源

SPyQL 回购:【github.com/dcmoura/spyql

SPyQL 文档: spyql.readthedocs.io

MatplotCLI 回购:github.com/dcmoura/matplotcli

你可以在 TweeterLinkedInVimeo 上找到我!

文章最初发表于 danielcmoura.com。

决定数据科学项目成败的常见问题

原文:https://towardsdatascience.com/common-issues-that-will-make-or-break-your-data-science-project-64e976c21a14

关于发现数据问题、为什么它们是有害的以及如何正确解决它们的有用指南

Unsplash 上由张志勇拍摄的照片

我相信大多数人都熟悉调查,该调查表明数据科学家花费大约 80%的时间准备和管理数据。那是一周 5 天中的 4 天!

虽然这听起来很疯狂(或者很无聊),但是您很快就会意识到为什么会有这种趋势,我认为这表明了数据清理和数据验证的重要性。

垃圾进,垃圾出。

在任何分析项目中,获得正确的数据都是成功的一半以上。事实上,任何花哨或复杂的模型都不足以补偿低质量的数据。

对于刚开始涉足这个领域的新手来说(对我来说肯定是这样),我理解在处理一个新的数据集时,很难知道到底要注意什么。

考虑到这一点,我想提出一个指南,介绍您在旅途中的某个时间点可能会遇到的常见数据问题,以及如何正确处理这些问题以及它们各自的利弊的框架。

这篇博文并不是一个详尽的列表,而是在预处理和解释数据时你会发现的最关键和最常见的列表。

1.处理重复

重复数据是同一表中相同数据的简单重复实例,在大多数情况下,应该完全删除重复数据。

如今,大多数编程语言中都有内置函数可以帮助检测重复数据,例如,r 中的重复函数。

关于处理重复项,理解主键的概念也很重要。

主键是表中每一行的唯一标识符。每一行都有自己的主键值,根本不应该重复。例如,在客户表中,这可能是客户 ID 字段,或者在事务数据集中,这可能是事务 ID。

识别表中的主键是检查重复项的好方法。具体来说,主键中不同值的数量需要等于表中的行数。

如果它们相等,那么很好。如果不是,你需要进一步调查。

主键不一定只有一列。多个列可以构成一个表的主键。

2.缺少值

通常,有两种类型的缺失值:NA(不可用的缩写)和 NAN(非数字的缩写)。

NA 表示由于未知原因丢失数据,而 NAN 表示有一个结果,但不能用计算机表示,例如,一个虚数或如果您不小心将任何数除以零。

缺失的值会导致我们的模型失败或导致错误的解释,因此,我们需要找到解决它们的方法。处理缺失值主要有两种方法:忽略缺失值的观测值或插补。

在大规模数据集的情况下,我们可以简单地丢弃所有丢失的数据,但是,我们有丢失信息的风险,这不适合小数据集。

另一方面,价值插补可分为单变量插补和多变量插补。我以前写过一篇关于插补的博文,如果你有兴趣深入探讨这个话题,请随意查看。

实际上,单变量插补是指使用*均值、中值或众数替代基于单个列的值。另一方面,多变量插补考虑多个列,并涉及算法的使用。例如,估算连续变量的最简单模型是分类变量的线性回归或 k 均值聚类。多变量插补通常优于单变量插补,因为它能更准确地预测缺失数据。

需要判断处理缺失值的最佳方式。也可能有这样的情况,在数据集中,零支付的索赔被表示为 NA 而不是 0。在这个特定的场景中,简单地用 0 替换 NA 是有意义的。在其他情况下,需要更多的考虑。

3.极端值

离群值是与其他数据点有很大不同的数据点。它们会扭曲分析或模型。

确定异常值的一种方法是将四分位间距(IQR)标准应用于变量,如果观察值高于上四分位 1.5IQR,低于四分位 1.5IQR,则视为异常值。

箱线图通常将这些点绘制为经过须点的点,这被认为是检测异常值的单变量方法。直方图在可视化分布和发现潜在异常值方面同样出色。对于两个变量,考虑使用散点图。

如何处理离群值?你可以保留、删除、封顶,或者用*均值、中间值或随机数来估算。

4.相关性考虑

这与其说是一个数据问题,不如说是一个如何解释相互关联的变量的提醒。

机器学习模型非常擅长学习输入数据和输出预测之间的关系。但是,他们缺乏因果推理。因此,得出结论时必须小心,不要过度解读变量之间的关联。

统计学中有一句名言,“相关性并不意味着因果关系”。

一个变量与另一个变量相关,但不一定有直接影响,这有几个原因。这些原因可能包括伪相关性、异常值和混杂因素。

我们将在这里更详细地讨论它们。

相关性并不意味着因果关系。

4.1 虚假关联

伪相关是指两个变量以某种方式相关,但实际上它们之间没有真正的关系。

泰勒·维根拍摄的图片——虚假关联

从上面的图表可以看出,一个滑稽的例子是奶酪消费和纠缠在床单上导致死亡之间的关系。显然,这两个变量之间没有任何逻辑因果关系,这种相关性只不过是巧合。

这是你可以在这里找到的许多其他例子之一

4.2 异常值引起的相关性

相关性有时也可能由异常值驱动。

我们可以通过移除异常值来测试这一点,结果相关性会显著降低。正如上一节所提到的,这强调了在探索数据集时识别异常值的重要性。

或者,我们也可以计算 Spearman 相关性,而不是 Pearson 相关性,因为 Spearman 计算相关性是基于值的等级顺序,因此不受异常值的影响。

4.3 混杂变量引起的相关性

混杂因素可能是相关性被误解的最常见原因。如果变量 X 和 Y 是相关的,如果 Z 的变化引起 X 和 Y 的变化,我们称 Z 为混杂变量。

例如,假设您想要调查两组之间的死亡率,一组由酗酒者组成,另一组由从不饮酒者组成。死亡率是反应变量,饮酒量是你的独立变量。

如果你发现酗酒者更容易死亡,那么似乎可以凭直觉得出结论,饮酒会增加死亡风险。然而,饮酒可能不是两组间唯一不同的死亡率影响因素。例如,那些从不饮酒的人可能有更健康的饮食或更少吸烟,这两者也对死亡率有影响。这些其他影响因素(饮食和吸烟习惯)被称为混杂变量。

那么,我们如何解决这个问题呢?对于少量的混杂因素,我们可以使用一种称为分层的方法,即抽样数据,其中混杂变量变化不大,然后检查每组中自变量和因变量之间的关系。

回到我们之前的例子,我们可以将样本分为吸烟者和非吸烟者两组,然后检查每组中酒精消费量和死亡率之间的关系。

理论上,这表明我们应该包括所有与响应变量有关系的解释变量。不幸的是,有时并非所有的混杂因素都有可能被收集或准确测量。此外,添加过多的解释变量可能会引入多重共线性,并增加回归估计值的方差。

这是精确度和偏差之间的权衡。随着我们开始包含更多的变量,我们减少了预测中的偏差,但多重共线性增加了,因此方差也增加了。

5.特征工程

特征工程是选择原始数据并将其转换为用于训练模型的特征的过程。

在准备数据集时,我们需要知道每一列中的变量是什么类型,以便可以适当地使用它们来解决回归或分类问题。

一些重要的考虑事项包括:

  • 我的特征和它们的属性是什么?
  • 我的特征如何相互作用以适应模型?
  • 如何调整原始要素以表示原始预测值?

通过检查汇总统计数据,我们通常能够确定我们的特征的属性。然而,选择或构建正确的特性并不是一件容易的事情,这通常取决于领域中的经验和专业知识。

然而,下面是你可以考虑为你的项目做的 3 个特征工程的例子。

5.1 算法无法处理的分类变量

对于无法处理分类变量的算法,如逻辑回归和支持向量机,它们期望所有变量都是数字,流行的方法是将它们转换为 n 数字变量,每个变量取值 1 或 0。这被称为一键编码。

回归问题使用了一种稍微不同的一次性编码,称为哑编码。不同的是,一键编码产生了 n-1 个数值变量。

作者图片

正如你所看到的,对于哑编码,如果我们知道两个变量的值,我们可以很容易地推导出第三个变量的值。具体来说,如果两个变量的值为 0,这意味着第三个变量的值为 1。这样做,我们避免给我们的回归模型冗余信息,可能导致不可识别性。

像 Python 和 R 这样的通用编程语言中有一些包支持一键编码和虚拟编码。

5.2 具有高基数的分类变量

高基数意味着有太多的唯一值。

决策树和广义线性模型(GLMs)等算法无法处理高基数的分类数据。

决策树分割特征,使得每个子树变得尽可能同质。因此,随着基数的增长,拆分的数量也在增长,从而增加了模型的复杂性。

另一方面,GLMs 为分类数据的每个级别创建虚拟变量。因此,对于每个具有 n 类别的分类变量,模型将生成 n-1 个附加参数。这并不理想,因为它会导致过度拟合和较差的样本外预测。

处理高基数分类变量的一种流行方法是宁滨,它是组合相似分类变量类的过程。这种分组通常需要商业环境的领域知识或从数据探索中获得的知识,例如,通过检查级别的频率和分析感兴趣的变量和响应变量之间的关系。对类别进行宁滨后,可以使用一键编码将类别变量转换为值为 1 和 0 的虚拟数值变量。

宁滨的一些例子包括将国家分组为大洲,或者将预期寿命分组为 0-50 岁和 50 岁以上。

5.3 数据集中的大量特征或变量

与高基数相似,当数据集中有太多要素时,我们会面临长训练时间和过度拟合的挑战。拥有太多的功能也会使数据可视化变得困难。

作为一名数据科学的初学者,我记得有一个误解,即在构建模型时,变量越多越好。这显然不是事实。

减少变量的数量对于简化数据集至关重要,因此我们只需关注那些实际上有意义且可能携带最多信号而非噪声的要素。

有几种方法可以减少功能的数量,但在这里我将分享 4 种你可能想考虑的方法:

  1. 领域知识:如果经验或专业知识告诉您某些变量在预测响应变量方面表现良好,则手动使用领域知识。例如,债务收入比是用来评估一个人的信誉和预测违约概率的常用指标。
  2. 降维:通过将点投影到一个更低维度的空间来减少变量的数量。目标是获得一组新的特征,这些特征比原来的少,但仍然保留尽可能多的信息。一种流行的降维技术被称为主成分分析(PCA)。PCA 下的新特征应该解释原始特征,换句话说,高度相关但不与任何新特征相关。我以前写过关于 PCA 算法的文章这里如果你有兴趣了解更多细节的话。
  • 子集选择:通过一个叫做逐步回归的过程,找到表现良好的变量子集,去掉多余的变量。这可以通过向前选择或向后排除过程来实现。正向选择包括从没有变量开始,在每一步增加一个变量,对模型拟合产生最大的改进。另一方面,反向选择包括从所有变量开始,在每一步中去除一个对模型拟合度影响最小的变量。
  • 收缩:LASSO 和 Ridge regression 等技术通过在残差*方和(RSS)中增加一个惩罚项,将过拟合和欠拟合的可能性降到最低。我不会讲太多细节,但是可以在这里随意阅读这些技术。

6.不*衡数据集

当我们有明显稀疏的少数类和丰富的少数类时,就会出现不*衡的数据集。

这是分类问题中的一个问题,因为我们的模型没有获得足够的关于少数类的信息来进行准确的预测。具体来说,由于不*衡,模型更有可能显示出对多数阶级的偏见,这可能导致误导性的结论。

不*衡数据集的常见例子可以在欺诈检测、客户流失和贷款违约中找到。

让我们以欺诈检测为例。欺诈交易通常只占大型数据集中的很小一部分(你会希望如此,否则每个人都会避免使用银行)。假设每 1000 笔交易中可能只有 1 起欺诈案件,占整个数据集的 0.1%。如果机器学习算法简单地预测 100%的交易不是欺诈性的,在这个特定的例子中,它将具有 99.9%的准确率,这在表面水*上看起来可能非常高。

但是,如果银行要实施这种模式,它很可能无法标记未来的欺诈交易,这对银行来说成本很高。

用抽样方法处理不*衡数据有几种方法:

  • 欠采样:这是我们减少多数类样本数量的地方。欠采样的缺点是我们会丢失很多有价值的数据。
  • 过采样:这是我们增加少数类样本数量的地方。过采样的缺点是我们创建了过多的重复数据点,这可能会导致我们的模型过拟合。
  • 合成少数过采样技术(SMOTE): SMOTE 旨在欠采样和过采样之间取得*衡。SMOTE 的优势在于,我们不会创建副本,而是创建与原始数据点略有不同的数据点。

就像我在这篇博文的开头所说的,这绝不是你需要注意的事情的详尽清单,但是我希望这篇指南不仅能帮助你在未来更加意识到这些问题,还能帮助你学会如何处理它们。

如果你在这篇文章中发现了任何价值,并且还不是一个媒体会员,如果你使用下面的链接注册会员,这对我和这个*台上的其他作者来说意义重大。它鼓励我们继续推出像这样的高质量和信息丰富的内容——提前感谢您!

https://chongjason.medium.com/membership

不知道接下来要读什么?这里有一些建议。

用于临床文本分类的常见机器学习和深度学习方法

原文:https://towardsdatascience.com/common-machine-learning-and-deep-learning-methods-for-clinical-text-classification-188473477a32

面向医疗保健的自然语言处理(NLP ),使用 NLTK、spaCy、TF-IDF、单词嵌入以及非序列和序列建模,如 LSTM 和 Transformer

作者照片

随着机器学习和深度学习算法的进步,自然语言处理( NLP )成为人工智能研究和应用的热门话题,因为文本(例如,英语句子)是自然语言数据的主要类型。例如,文本经常出现在医疗保健数据集中,如电子健康记录( EHR )。医疗领域的文本数据有很多人工智能方法,如临床命名实体识别()、临床文本分类等。

在本文中,我使用开源临床文本数据集[1][7][8]来介绍一些常见的机器学习和深度学习方法,用于临床文本分类。

CRISP-DM 类似,NLP 的机器学习过程包括以下常见步骤:

  • 商业理解
  • 数据理解
  • 数据准备
  • 建模
  • 模型评估
  • 模型部署

1.商业理解

对于任何一个数据科学项目来说,了解要解决的问题是什么是非常重要的。

本文要解决的问题是如何从医学文本中预测医学专业。

2.数据理解

为了解决确定的问题,我们需要收集和理解数据。

如前所述,我使用来自 Kaggle 的开源临床文本数据集[1]。下载数据集 mtsamples.csv 文件后,以下代码将数据集作为 Pandas DataFrame 加载到内存中:

data = pd.read_csv('./medical-nlp/data/mtsamples.csv', index_col=0)
data.head()

如上表所示,特征列转录为英文句子,而目标/标签列医疗 _ 专业为分类。该信息表明要解决的问题是临床文本分类问题。

有 40 个独特的医学专业类别。数据集严重失衡。不同类别的数据样本数量从 6 到 1,103 不等。

3.数据准备

如前所述,数据集非常不*衡。

3.1 不*衡数据的处理

为了缓解数据不*衡问题,下面的代码删除了数据样本少于 100 或者不是医学专业的类别。

filtered_data = data[['transcription', 'medical_specialty']]
filtered_data.loc[:, 'medical_specialty'] = filtered_data['medical_specialty'].apply(lambda x:str.strip(x))
mask = (filtered_data['medical_specialty'] == 'SOAP / Chart / Progress Notes') | \
       (filtered_data['medical_specialty'] == 'Office Notes') | \
       (filtered_data['medical_specialty'] == 'Consult - History and Phy.') | \
       (filtered_data['medical_specialty'] == 'Emergency Room Reports') | \
       (filtered_data['medical_specialty'] == 'Discharge Summary') | \
       (filtered_data['medical_specialty'] == 'Letters')filtered_data = filtered_data[~mask]data_categories  = filtered_data.groupby(filtered_data['medical_specialty'])
filtered_data_categories = data_categories.filter(lambda x:x.shape[0] > 100)
filtered_data_categories['medical_specialty'].value_counts()

生成的数据集包含以下 9 类医学专业:

数据集按照如下方式进行混洗,以避免任何人为的数据模式。

data = filtered_data_categories.sample(frac=1.0)

此外,与[1]类似, SMOTE 算法也用于自动上采样少数数据样本,以改善文本编码后的数据*衡。

3.2 数据预处理

正常数据集和 NLP 数据集之间的主要区别在于,NLP 数据集包含文本特征,例如医疗转录。文本特征由一系列句子组成(在 NLP 术语中称为文本或文档语料库)。就功能类型而言,区别如下:

普通数据集中有两种类型的要素:

  • 数字特征(如温度)
  • 分类特征(例如,诸如“IL”、“WA”等状态。)

但是,NLP 数据集中有三种类型的要素:

  • 数字特征(如温度)
  • 分类特征(如特征医疗 _ 专业,如上表所示)
  • 文本特征(例如上表中的特征转录

为了处理缺失数据,并减少词汇和训练数据的大小,除了提取医疗实体之外,以下数据预处理步骤通常应用于文本特征(例如,转录特征)以进行文本分类:

  • 处理丢失的数据
  • 提取医疗实体(仅用于临床文本分类)
  • 标准化文本
  • 标记文本
  • 删除停用词
  • 堵塞物
  • 把…按屈折变化形式进行归类

处理缺失数据

机器学习不允许缺失数据。如果丢失条目的数量相对较少,可以简单地丢弃丢失的数据。NLP 中处理缺失数据的另一种常用方法是从数据集中的其他相关要素复制信息。例如,NLP 特征“转录”中缺少的条目可以通过从特征“描述”中复制相应的条目来填充,因为描述是转录的概要。

在本文中,feature transcription 列中的缺失条目被简单地删除,而不会显著损害模型预测的准确性,因为只有 33 个缺失条目。

df = data.dropna(subset=['transcription'])

3.2.2 提取医疗实体

特征栏转录中最重要的内容是医学笔记。如[1]所述,提取医疗实体用于临床文本分类被证明是非常有用的。这是通过使用 spaCy [3]库实现的,如下所示:

import spacy
import en_ner_bionlp13cg_mdnlp = en_ner_bionlp13cg_md.load()def medical_entities( text):
    entities = []
    doc = nlp(text)
    for ent in doc.ents:
        entities.append(ent.text)
    return ' '.join(entities)df['transcription'] = df['transcription'].apply(medical_entities)

标准化文本

标准化文本有两个常见步骤:

  • 将文本改为小写:这有助于避免机器学习模型学习字符的大小写。
  • 去掉标点符号:这有助于减少词汇量

例如,给定上面的文本字符串,标准化文本的两个步骤可以在一条语句中完成,如下所示:

text = text.lower().translate(str.maketrans('', '', string.punctuation))

以下是生成的文本:

3.2.4 标记文本

这有助于把一篇文章分成词汇的各个部分。如果文本被视为单词序列,则通常使用单词级(1-gram)标记化。单词级标记化还支持删除停用词、词干和词汇化的活动。

N 元语法(通常 N = 2 或 3)标记化通常用于将文本视为一个单词包(单词的原始有序序列丢失)的情况。

例如,下面的代码使用 scikit-learn 库将文本字符串标记为单个单词/标记。

from nltk.tokenize import word_tokenize
tokens = word_tokenize(text)

移除停用字词

这有助于在不损害模型预测准确性的情况下减少词汇表的大小。以下代码使用 NLTK 库从标记化单词中移除英语停用词。

from nltk.corpus import stopwords
english_stopwords = set(stopwords.words('english'))clean_tokens = []
for tok in tokens:
    tok = tok.strip() # remove space
    if tok not in english_stopwords:
        clean_tokens.append(tok)

堵塞

这有助于减少词汇量。以下代码使用 NLTK [4]库对单词/标记进行词干分析。

from nltk.stem import PorterStemmer
stemmer = PorterStemmer()
stemming_word = stemmer.stem(‘being’) 

词汇化

这有助于减少词汇量。下面的代码使用 NLTK 库对单词/令牌进行词汇化。

from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
root_word = lemmatizer.lemmatize('words')

上述数据预处理步骤可以合并成一个函数来清理文本字符串:

def clean_text(text):
    # get English stopwords
    english_stopwords = set(stopwords.words('english'))

    # change to lower case and remove punctuation
    text = text.lower().translate(str.maketrans('', '', string.punctuation))

    # divide string into individual words
    tokens = word_tokenize(text)

    stemmer = PorterStemmer()
    lemmatizer = WordNetLemmatizer() clean_tokens = []
    for tok in tokens:
        tok = tok.strip() # remove space
        if tok not in english_stopwords:
            clean_tok = lemmatizer.lemmatize(tok) # lemmatizition
            clean_tok = stemmer.stem(clean_tok) # Stemming
            clean_tokens.append(clean_tok) return " ".join(clean_tokens)

以下是通过调用 clean_text()函数生成的干净文本示例。

请注意,步骤 3.2.3 和 3.2.5 通常是有用的,但对于本文中的临床文本分类不是必需的,因为这两个步骤已经在步骤 3.2.2 中完成了。

3.3.特征工程

一旦对文本特征进行预处理,就需要将每个文本(文档)编码为数字向量(称为矢量化),因为机器学习和深度学习模型只理解数字。编码方法的选择取决于如何解释文本。在文本分类中,文本串(文档)通常被视为一个单词包或一个单词序列。以下是一些常见的文本编码/矢量化方法。

如果一个文本被视为一个单词包,那么我们通常使用下面的方法将一个文本/文档转换为一个数字向量:

  • TF-IDF 矢量化
  • 多重热编码

TF-IDF 矢量化

Multi-Hot [2]编码方法将一个文本/文档编码为具有 0 和 1 的值的词汇长度的稀疏向量,其中 1 指示词汇中相应单词/标记的存在。

与 Multi-Hot 类似,TF-IDF 矢量化也将一个文本/文档编码为词汇长度的稀疏向量。主要区别在于,TF-IDF 编码向量不仅包含词汇表中相应单词/标记的存在信息,还包含由反向文档频率(IDF)加权的标记频率(TF)。因此,TF-IDF 编码的矢量比 multi-Hot 编码的矢量具有更大的预测能力。

像 Multi-Hot 一样,TF-IDF 编码向量的长度可以与整个词汇表的长度相同。典型的截断长度是 20,000。类似于[1],应用 PCA 算法来降低维数。

以下函数将分类标签转换为整数,并使用 3-gram TF-IDF 和 PCA 将转录特征编码为稀疏向量:

from sklearn.preprocessing import LabelEncoder
from sklearn.decomposition import PCA
from imblearn.over_sampling import SMOTEdef tfidf_pca(X_feature, y_label):
    '''
    X_feature = df['transcription'].values
    y_label = df['medical_specialty'].values
    '''

    le = LabelEncoder()
    y_int = le.fit_transform(y_label) tfidf = TfidfVectorizer(tokenizer=clean_text, ngram_range=(1,3))
    pca = PCA(n_components=0.95)
    X_tfidf = tfidf.fit_transform(X_feature)
    X_pca = pca.fit_transform(X_tfidf.toarray()) smote_over_sample = SMOTE(sampling_strategy='minority') X, y = smote_over_sample.fit_resample(X_pca, y_int.tolist()) X = np.array(X)
    y = np.array(y)

    return X, y

单词嵌入

如果一个文本被视为一个单词序列,那么我们可以使用以下常用方法将文本/文档中的每个单词转换为一个向量,并将整个文本/文档转换为一个向量数组:

除了更短的长度之外,单词嵌入相对于一键编码的另一大优势是单词嵌入以这样一种方式编码单词的含义,使得在向量空间中更接*的单词在含义上是相似的。

给定一个文本/文档,有两个步骤将其映射到给定大小的密集向量:

  • 步骤 1:将文本转换成词汇表中单词/标记索引的向量
  • 步骤 2:使用定制的训练或预训练的单词嵌入算法(例如,Word2Vec 和 GloVe)将每个单词索引转换成浮点数的密集向量

下面的函数将分类标签转换成整数,将转录特性转换成词汇表中单词/标记索引的向量。

from tensorflow.keras import layersdef indecies_vectorize(X_feature, y_label, max_length = 1500, max_tokens = MAX_TOKENS):
    '''
    X_feature: df['transcription'].values
    max_length: maximum number of words in one text/document
    max_tokens: the length of vocabulary
    '''

    le = LabelEncoder()
    y_int = le.fit_transform(y_label)

    text_vectorization = layers.TextVectorization(
        max_tokens=max_tokens,
        output_mode="int",
        output_sequence_length=max_length,
    ) # training the text vectorization object
    text_vectorization.adapt(X_feature)    # convert preprocessed training text into anrray of integers/indecies
    indecies_array = text_vectorization(X_feature) 

    smote_over_sample = SMOTE(sampling_strategy='minority')
    X, y = smote_over_sample.fit_resample(indecies_array, y_int)

    X = np.array(X)
    y = np.array(y) return X, y

下面的代码显示了如何使用 Keras 的自定义训练单词嵌入层将单词索引矢量编码为长度为 256 的密集矢量序列。

import keras
inputs = keras.Input(shape=(None,), dtype="int64")
embedded = layers.Embedding(input_dim=max_tokens, output_dim=256, mask_zero=True)(inputs)

位置嵌入

如[2]所述,词序信息在文本分类中起着重要作用。[2]中的以下代码是将词序信息添加到单词嵌入中,以提高使用Transformer【2】进行文本分类的性能。

class PositionalEmbedding(layers.Layer):
    def __init__(self, sequence_length, input_dim, output_dim, **kwargs):
        super().__init__(**kwargs)
        self.token_embeddings = layers.Embedding(
            input_dim=input_dim, output_dim=output_dim)

        self.position_embeddings = layers.Embedding(
            input_dim=sequence_length, output_dim=output_dim)

        self.sequence_length = sequence_length
        self.input_dim = input_dim
        self.output_dim = output_dim def call(self, inputs):
        length = tf.shape(inputs)[-1]
        positions = tf.range(start=0, limit=length, delta=1)
        embedded_tokens = self.token_embeddings(inputs)
        embedded_positions = self.position_embeddings(positions)
        return embedded_tokens + embedded_positions def compute_mask(self, inputs, mask=None):
        return tf.math.not_equal(inputs, 0) def get_config(self):
        config = super().get_config()
        config.update({
            "output_dim": self.output_dim,
            "sequence_length": self.sequence_length,
            "input_dim": self.input_dim,
        })
        return config

下表总结了不同文本编码方法的选择。

4.建模

一旦数据集为建模做好准备,我们需要选择一个机器学习/深度学习模型,并用准备好的数据对其进行训练。

4.1 型号选择

与选择文本编码方法类似,选择用于文本分类的机器学习或深度学习模型取决于如何对文本进行编码。具体来说,我们可以选择下表所示的型号:

下面来自[2]的 TransformerEncoder 类实现了一个多头基于注意力的转换器,用于本文中的临床文本分类。

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layersclass TransformerEncoder(layers.Layer):
    def __init__(self, embed_dim, dense_dim, num_heads, **kwargs):
        super().__init__(**kwargs)
        self.embed_dim = embed_dim
        self.dense_dim = dense_dim
        self.num_heads = num_heads
        self.attention = layers.MultiHeadAttention(
            num_heads=num_heads, key_dim=embed_dim)
        self.dense_proj = keras.Sequential(
            [layers.Dense(dense_dim, activation="relu"),
             layers.Dense(embed_dim),]
        )
        self.layernorm_1 = layers.LayerNormalization()
        self.layernorm_2 = layers.LayerNormalization() def call(self, inputs, mask=None):
        if mask is not None:
            mask = mask[:, tf.newaxis, :]
        attention_output = self.attention(
            inputs, inputs, attention_mask=mask)
        proj_input = self.layernorm_1(inputs + attention_output)
        proj_output = self.dense_proj(proj_input)
        return self.layernorm_2(proj_input + proj_output) def get_config(self):
        config = super().get_config()
        config.update({
            "embed_dim": self.embed_dim,
            "num_heads": self.num_heads,
            "dense_dim": self.dense_dim,
        })
        return config

本文选择了以下模型:

TF-IDF 编码的非序列模型:

单词嵌入的序列模型:

  • LSTM

位置嵌入的序列模型:

  • Transformer(即 TransformerEncoder 类)

4.2.模特培训

通常,在模型训练开始之前,我们需要将数据集分成训练、验证和测试子集。为了简单起见,在本文中数据集只分成两个子集:一个用于模型训练,另一个用于模型测试/评估。

from sklearn.model_selection import train_test_splitX_feature = df['transcription'].values
y_label = df['medical_specialty'].valuesif SEQUENCE_MODEL:
    X, y = indecies_vectorize(X_feature, y_label)
else:   
    X, y = tfidf_pca(X_feature, y_label)X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)
X_train.shape, X_test.shape, y_train.shape, y_test.shape

4.2.1 使用 TF-IDF 的非序列建模

如前所述,本文中使用了以下 TF-IDF 编码的非序列模型:

例如,下面的代码创建并训练一个多输出分类器。

from sklearn.multioutput import MultiOutputClassifier
from sklearn.neighbors import KNeighborsClassifierif not SEQUENCE_MODEL:
    multi_class_clf = MultiOutputClassifier(KNeighborsClassifier())
    y_train = y_train.reshape(-1, 1)
    multi_class_clf.fit(X_train, y_train)

4.2.2 使用具有单词嵌入的 LSTM 的序列建模

在本文中,我使用带有自定义单词嵌入的双向 LSTM 来演示如何为文本分类执行序列建模(参见下面的代码)。

import kerasdef create_lstm_model(embedding_layer = None):
    # create input layer
    inputs = keras.Input(shape=(None,), dtype="int64") # add word embedding layer
    if embedding_layer is not None:
        embedded = embedding_layer(inputs)
    else:
        embedded = layers.Embedding(input_dim=MAX_TOKENS, output_dim=256, mask_zero=True)(inputs) # add LSTM layer
    x = layers.Bidirectional(layers.LSTM(32))(embedded) # add dropout layer
    x = layers.Dropout(0.5)(x) # add output layer
    outputs = layers.Dense(9, activation="softmax")(x) # combine all layers into one model
    lstm_model = keras.Model(inputs, outputs) # specifiy optimizer, loss, and metrics for the model
    lstm_model.compile(optimizer="rmsprop",
                  loss="sparse_categorical_crossentropy",
                  metrics=["accuracy"]) # print the summay of the model architecture
    lstm_model.summary()

    return lstm_modelif SEQUENCE_MODEL:
    if USE_GROVE:
        lstm_model = create_lstm_model(embedding_layer)
    else:
        lstm_model = create_lstm_model()

    # define callback function
    callbacks = [
        keras.callbacks.ModelCheckpoint("embeddings_bidir_gru_with_masking.keras",
                                        save_best_only=False)
    ] # train model
    lstm_model.fit(X_train, y_train, epochs=10, callbacks=callbacks)

4.2.3 使用变压器的序列建模

最*,基于注意力的变换算法成为序列建模中优于 LSTM 的算法。下面的代码使用具有位置嵌入的多头注意力转移算法进行临床文本分类。

def create_transformer(): vocab_size = 20000
    sequence_length = 1500
    embed_dim = 256
    num_heads = 2
    dense_dim = 32 inputs = keras.Input(shape=(None,), dtype="int64")
    x = PositionalEmbedding(sequence_length, vocab_size, embed_dim)(inputs)
    x = TransformerEncoder(embed_dim, dense_dim, num_heads)(x)
    x = layers.GlobalMaxPooling1D()(x)
    x = layers.Dropout(0.5)(x)
    outputs = layers.Dense(9, activation="softmax")(x)
    transformer_model = keras.Model(inputs, outputs)
    transformer_model.compile(optimizer="rmsprop",
                  loss="sparse_categorical_crossentropy",
                  metrics=["accuracy"])
    transformer_model.summary()

    return transformer_modelif SEQUENCE_MODEL:
    transformer_model = create_transformer() callbacks = [
        keras.callbacks.ModelCheckpoint("full_transformer_encoder.keras",
                                        save_best_only=False)
    ] transformer_model.fit(X_train, y_train, epochs=10, callbacks=callbacks)

5.模型评估

评估分类模型的常用指标有:

作为一个例子,下面的代码计算准确度和 F1 分数,并为本文中的多类临床文本分类创建一个混淆矩阵图。

from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplaydef plot_confusion_matrix(y_test, y_pred, labels):
    cm = confusion_matrix(y_test, y_pred, labels=rf_clf.classes_)
    disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=rf_clf.classes_) 
    fig, ax = plt.subplots(figsize=(15,15))
    disp.plot(ax=ax)if not SEQUENCE_MODEL:
    y_pred = logistic_clf.predict(X_test) acc_score = accuracy_score(y_test, y_pred)
    print('logistic_clf Accuracy score: ', acc_score) f1 = f1_score(y_test, y_pred, average='weighted')
    print('logistic_clf F1 score: ', f1)

    plot_confusion_matrix(y_test, y_pred,   labels=logistic_clf.classes_)

下表总结了模型评估结果。

6.模型部署

一旦在部署的模型评估中确定了文本分类的最佳模型,下一步就是将确定的模型部署到生产系统中。一种常见的方法是将模型作为 Web 服务部署在服务器上,目标生产系统中的其他组件可以调用它来获得文本分类结果。

为此,选定的训练模型(如逻辑回归)和相关的编码对象都应保存到文件中(如 Python pickle 文件)。然后,可以将这些保存的编码对象和模型加载回内存,以便在部署环境中进行预测。

7.结论

在本文中,我使用了一个开源的临床文本数据集[1][7][8]来演示一些常见的文本/文档编码方法以及相关的机器学习和深度学习算法,用于临床文本分类。

有许多不同类型的文本编码方法和机器学习/深度学习算法可用于文本分类。本文提供了不同文本编码方法和相应的适用机器学习/深度学习模型之间的映射的总结。

除了使用自定义数据集训练单词嵌入,我还使用预训练的单词嵌入手套[5]进行了实验,并注意到使用自定义数据训练单词嵌入在准确性方面具有更好的模型性能。

模型评估结果表明,在临床文本分类中,使用 spaCy 提取医学实体并使用 SMOTE 算法*衡数据对于提高模型的准确性非常重要。

参考

[1]临床文本分类:https://www . ka ggle . com/ritheshreenivasan/Clinical-Text-class ification

[2] F. Chollet,用 Python 进行深度学习,第二版,Manning,2021

[3]空间:https://allenai.github.io/scispacy/

[4]NLTK:【https://www.nltk.org/】T4

[5]手套:https://nlp.stanford.edu/projects/glove/

[6] Y. Huang,Github 中的 Jupyter 笔记本

[7]MTS 示例:https://www.mtsamples.com

[8] T .波义耳,https://www.kaggle.com/tboyle10/medicaltranscriptions

鸣谢:我要感谢 MTSamples 和 Kaggle 提供的数据集。

A/B 测试中的常见错误

原文:https://towardsdatascience.com/common-mistakes-during-a-b-testing-bdb9eefdc7f0

我们通往卓越的道路布满了错误。让我们来做吧!

在过去的几年里,我目睹了人们在 A/B 测试设计和后期分析中犯的许多错误。我想在这里讨论三个这样的错误以及如何克服它们。

使用曼-惠特尼方法比较中位数

第一个错误是曼-惠特尼检验的使用不当。这种方法被大量误解和误用,因为大多数人使用这种检验,假设它是中位数的*似非参数“t 检验”。实际上,我们只能使用曼-惠特尼检验来检查我们的分布是否有变化。

在这个图中,我们可以看到分布 X 和 Y 有相同的分布,只是有一个位移。作者图片

当我们应用曼-惠特尼检验时,我们设定我们的假设如下:

无效假设。作者图片

另一个假设。作者图片

我们应该总是考虑假设,对于这个测试只有两个:

  1. 我们的观察是独立的
  2. 我们的分布有相同的形状

如何计算曼-惠特尼统计:

  1. 按数量级排列所有的观察结果
  2. 为所有观察分配数字等级
  3. 计算两组的 U 统计值

R —样本 1 的所有等级的总和,n—1 个样本的观察次数。作者图片

R —样本 2 的所有等级的总和,n —样本 2 的观察次数。作者图片

4.从这两个值中选择最小值

5.使用曼-惠特尼 U 检验的统计表,找出观察到 U 值或更低值的概率。

所以我们发现不能用它来比较中位数,我们应该用什么来代替呢?

幸运的是,统计学家弗兰克·威尔科克森在 1945 年发明了有符号秩检验。现在它的正式名称是“威尔科克森符号秩检验”。

我们对测试的假设与开始时的预期一样:

零假设,m-中位数。作者图片

另一个假设,m-中位数。作者图片

如何计算 Wilcoxon 符号秩检验统计量:

  1. 对于每一对观测值,计算差值,并保留其绝对值和符号
  2. 将绝对值从最小到最大排序,并按顺序排列。
  3. 最后,计算测试统计数据:

作者图片

4.w 具有已知的分布。如果 n 大于 20,那么它就是*似正态分布的。因此,我们可以测量在零假设下观察到它的概率,从而获得显著性水*。

公式背后的一点直觉:

如果中值差是 0,那么一半符号应该是正的,一半应该是负的,并且符号不应该与等级相关。如果中值差不为零,那么 W 会很大。

对所有案例和每个数据集使用引导。

第二个错误是一直使用自举。我见过很多次,为了确保我们可以在这种情况下使用自举,人们甚至不需要一些初步的操作就可以将自举应用于每个数据集。

应用引导的主要假设是:

样本应代表从中抽取样本的人群

如果我们的数据样本有偏差,不能很好地代表我们的总体,我们的自举统计也会受到影响,也会有偏差。这就是为什么我们应该衡量不同人群和细分市场的比例。

如果在我们的数据样本中只有女性,但是在我们的整个客户数据库中,性别是*均分布的,我们不能在这里应用 bootstrapping。

好的做法是比较我们整个人群和数据集之间的所有主要细分市场。

对于 I 类和 II 类错误,请始终使用默认值。

最后,但并非最不重要的是为实验选择正确的参数。在 95%的情况下,95%的数据分析师/科学家,95%的公司使用默认值=> 5 %的 I 型错误率和 20%的 II 型错误率(或 80%的检验功效)。

为什么我们不能选择 0%的 I 类错误率和 0%的 II 类错误率呢?

这不可避免地导致我们必须收集无限量的样本,我们的实验将永远持续下去。

这肯定不是我们要找的。这就是为什么我们必须在我们需要获得的样本数量和我们的错误率之间进行妥协。

我鼓励人们考虑你的产品的所有可能的规格。最方便的方法是创建下表,并与产品经理和产品负责人讨论。

典型的决策表。MDE——最小可检测效应。作者图片

对于网飞来说,即使 1%的 MDE 也能带来可观的利润,但对于小型创业公司来说,情况并非如此。对于谷歌来说,涉及数千万人的实验活动绝对是轻而易举的事情,因此最好将你的打字错误率设置为 0.1 %,并对你的结果更有信心。

感谢你的阅读,不要害怕犯错和学习。这是进步的必由之路!

超参数调整中的常见错误

原文:https://towardsdatascience.com/common-mistakes-in-hyper-parameters-tuning-ff5951e6c2d

机器学习模型的超参数调整是一个反复试验的游戏。要想成功,最好避免以下错误。

照片由丹尼斯·莱昂Unsplash 上拍摄

从给定的数据集开始,训练机器学习模型意味着计算最小化/最大化给定度量或优化函数的一组模型参数。通常使用基于梯度下降的方法找到最佳点。

然而,大多数模型都定义了一个额外的参数层,称为超参数。它们的值影响模型训练期间计算的参数,并且它们不能从数据中直接估计。例如,岭回归模型的正则化参数、随机森林模型的树的数量、神经网络的层数等等。

推荐的超参数调整方法取决于您正在训练的模型类型和您考虑的超参数数量。我将在这里重点介绍网格搜索,这是一种简单的超参数调优方法,也是数据科学学生首先想到的方法之一。它需要为每个参数定义一个潜在值列表,为每个组合训练模型,并根据给定的标准选择产生最佳结果的值。

虽然原理很简单,但这种方法仍然容易出错。以下是我遇到的最常见的错误。

1.不检查所选网格的灵敏度

这个错误我已经见过好几次了。学生在一个参数上定义一个网格,运行 GridSearchCV,提取对应于最佳分数的超参数值,然后…就是这样!

没有进一步的分析,没有调查围绕这个最佳值发生了什么的图表。根据网格定义的好坏,仅查看最佳分数及其相应的超参数值可能不足以得出正确的结论。这就引出了下一点。

2.选择不合适的值范围

当定义组成网格的值时,最好首先选择一个包含大范围值的粗粒度网格,以便能够确定要微调的感兴趣的区域。

根据网格的定义方式,您可能会认为模型对参数变化非常敏感:

所选择的超参数值显示了相对于该超参数的评估分数的高灵敏度(图片由作者提供)

或者该模型对于所选择的参数根本不敏感:

所选择的超参数值显示出评估分数对该超参数缺乏敏感性(图片由作者提供)

事实可能在中间的某个地方,所以为第一次测试选择足够大的范围是很重要的。

(图片由作者提供)

在确定了总灵敏度范围之后,可以进行微调步骤,以便找到最佳值。

作者图片

3.没有注意度量标准

下一点更有哲理性,但我认为记住这一点很重要。超参数的最佳值取决于所使用的评估分数。

在第一个例子中,我使用 R2 分数进行岭回归。sklearn 软件包提供了广泛的预定义模型性能测量值,用于评分参数。使用上例中的“最大误差”分数会导致超参数的不同最佳值:

超参数的最佳值取决于所选的评估指标(图片由作者提供)

需要根据模型的目的来选择用于超参数调整的分数。它应该根据业务逻辑或我们试图使用模型解决的整体问题来定义。GridSearchCV 非常灵活,允许我们定义任何类型的自定义函数来评估模型得分。

让我们考虑一个分类问题,我们想训练一个逻辑回归模型。我们希望根据使用专业领域知识定义的自定义分数来调整正则化参数。

让我们假设在我们的自定义分数中,假阳性的惩罚是假阴性的 10 倍。我们可以定义一个函数,将已知的训练输出值和模型预测的值作为参数,并计算所需的度量。我们可以通过调用 skearn metrics 模块中的 make_scorer 函数,将其转换为 GridSearchCV 可以使用的分数。

减去

在为网格选择正确的值范围和分析返回的结果时,超参数调优需要非常注意。所获得结果的质量还取决于所使用的评估度量,在许多情况下,改变评估度量将导致最佳超参数值的改变。

机器学习项目失败的常见原因

原文:https://towardsdatascience.com/common-reasons-why-machine-learning-projects-fail-62fe811024d6

了解机器学习项目失败的各种方式可以确保人们在面对这种情况之前采取正确的步骤和措施来避免它们

Unsplash 上的 CHUTTERSNAP 拍摄

好吧,你在确保你的机器学习模型在训练数据上表现良好方面做得很好。下一步将是实时部署它,并从用户和企业那里获得反馈,了解使用它是否导致了各种数据产品收入的增加。但对于一个成功的机器学习项目来说,有很多东西和错综复杂的东西必须先处理好,才能交给用户消费。查看机器学习项目失败的可能性列表,可以提高我们对它们的认识,并设计正确的步骤来进一步减少这种情况。在本文中,我们将探索机器学习项目失败的各种方式,从而更好地理解它们。

可供公司使用的数据量已经飞速增长,预计未来还会增长。尽管他们拥有大量的数据,但未能利用这些数据就相当于根本没有数据。因此,他们正在寻找该领域拥有数据科学和机器学习学位的专业人士来使用最先进的技术,并赋予他们预测能力。

因此,公司在构建和使用人工智能应用方面投入了巨大的精力。也许这是互联网上谈论最多的术语之一,公司在吸引这个领域做得很好。然而,他们还必须意识到的一件事是,这些项目有可能由于大量原因而失败。诊断他们失败的地方有助于减少失败,并在公司的 ML 从业者和研究人员之间建立信任。

现在让我们探索各种 ML 项目失败背后的原因,并试图找到解决它们的方法。

ML 项目失败的原因

在我们的机器学习设置中,可能会遇到许多失败的方式,其中一些原因是数据没有准备好用于 ML,或者有时可能存在过度拟合或可伸缩性问题。我们将探索其中的每一个领域,并获得对它们的透彻理解。

无法将机器学习与商业联系起来 —令人印象深刻的是,机器学习模型能够搅动大量数据,并从中获得大量见解,并以类似于人类水*的表现或更好的表现对他们没有见过的数据进行预测。然而,无法将机器学习如何用于业务以及它是否能够在收入、客户保留或其他因素方面满足业务的目标联系起来,通常会导致项目的失败。为了避免这个问题,建议在项目开始之前进行一次头脑风暴会议,讨论机器学习和人工智能如何能够解决早期使用的传统方法无法解决的挑战。如果企业的目标和机器学习的使用之间没有太多重叠,那么这很可能不会给团队增加价值,从而导致团队失败。

未能理解所需资源 —公司有时会低估运行一个人工智能项目所需的资源总量。有时人们会认为,拥有一个强大的图形处理单元(GPU)和一个功能齐全的 CPU 对于 AI 应用程序来说已经足够了。然而,可能需要更多的资源,如负载*衡器和存储设备,这些设备可以在用于人工智能目的之前存储大量数据。我们谈论的是万亿字节的数据,而不仅仅是千兆字节。应该建立不容易出错的数据处理管道。因此,避免这一问题的最佳步骤是在最终决定应该为项目分配多少资源之前,进行市场调查,并了解用户的案例研究。

ML 模型过拟合和欠拟合 —过拟合和欠拟合是机器学习中最普遍的问题。用训练数据训练一个过于复杂的模型,你可能会面临过度拟合的问题。另一方面,在复杂的数据上训练不太复杂的 ML 模型会导致拟合不足。因此,成功通常包括找到两者之间的正确*衡,以便模型能够很好地概括他们以前没有见过的数据(测试集)。如果你想对这些话题有更透彻的理解,请随意点击下面的链接,我在这里详细强调了这两个术语之间的区别。

机器学习中偏差和方差的差异| Suhas Maddali | 2022 年 9 月|走向数据科学(medium.com)

没有合适的人才 —虽然这一点显而易见,但值得一提的是,有大量的人没有合适的技能,而这些技能正是公司特别寻找的,以填补数据科学家或机器学习工程师的角色。在线课程在强化大量概念方面做得很好,并确保学生为解决现实世界的问题做好准备。然而,它们并没有涵盖数据科学家的日常任务的全貌,例如在训练 ML 模型之前提取数据、加载数据、组织和转换数据。因此,我们确实有大量的申请,公司正面临着寻找合适候选人的压力,因为对它的需求很大,而该领域训练有素的专业人员短缺。

选择错误的误差指标 —为了建立一个机器学习管道,已经付出了很多努力,并且还采取了一些步骤来确保 ML 模型针对所选择的指标进行了优化。这些模型的性能对于实践者所考虑和选择的度量来说是很好的。然而,同样的误差度量可能并不是解决当前问题的最佳选择。例如,考虑到像癌症诊断预测这样的案例,我们看到诸如准确性这样的指标并不能很好地向我们展示模型在数据上的实际表现,选择这种指标有时会对业务影响产生毁灭性的后果。由于数据集的本质是高度不*衡的(患者数量越多,患癌症的机会越低),准确性可能会给出一个夸大的画面,而无法解释机器学习模型的强度。因此,应该为这些问题选择替代指标,如精度召回。因此,为手头的问题选择正确的度量很重要,这样才能解决业务挑战。

不定期监控 ML 模型 —在生产中部署模型后,定期检查模型在实时数据上的实际表现也很重要。由于许多原因,可能会有数据漂移概念漂移,这在很大程度上阻碍了 ML 模型的性能。定期了解模型的性能并对其进行基准测试,可以确保公司不会在机器学习项目开发周期的某些阶段因模型的错误预测而损失收入。

没有选择正确的模型 —有一大组机器学习模型可以实时训练和部署。有时,ML 从业者可以限制只使用某一套模型,如 XGBoost、随机森林或梯度推进决策树(GBDT)。然而,根据应用程序的不同,这些模型也可能不适合使用,尤其是对于训练资源有限或要求低延迟预测且预算有限的任务。在这些情况下,可以部署更简单的模型,如线性回归或逻辑回归(分类),从而能够轻松地部署它们,而无需过多强调部署。

无法移除异常值 —在我们的数据中,训练集和测试集中可能都有异常值。因此,在部署模型之前未能处理它们也使得事情变得复杂,并且在模型被实时生产之后,管理人员会提出许多问题。为了避免这种成本,移除训练和测试集中的异常值有助于 ML 实践者区分优先级,并使模型对异常值更鲁棒,并对新数据进行良好的概括。因此,在部署时,应该花时间去除那些影响实时性能的异常值。

结论

看完这篇文章,你应该能理解机器学习项目失败的原因了。值得注意的是,可能有大量其他原因导致他们失败,但这些是大多数组织中常见的原因。采取正确的步骤避免它们对于企业来说是有用的,因为在部署之后,it 部门要花费大量的收入来诊断它们。感谢您花时间阅读这篇文章。

如果你想获得更多关于我的最新文章的更新,并且每月只需 5 美元就可以无限制地访问中型文章,请随时使用下面的链接来添加你对我工作的支持。谢了。

https://suhas-maddali007.medium.com/membership

以下是您联系我或查看我作品的方式。

GitHub: 苏哈斯马达利(Suhas Maddali)

YouTube:https://www.youtube.com/channel/UCymdyoyJBC_i7QVfbrIs-4Q

LinkedIn: (1)苏哈斯·马达利,东北大学,数据科学| LinkedIn

中等: 苏哈斯·马达利—中等

常见的面试问题:vs 在哪里有资格

原文:https://towardsdatascience.com/commonly-asked-interview-question-where-vs-having-vs-qualify-1445a1d15902

基础知识回归| SQL 初学者基础知识

作者图片,创建于 canva

你是否曾经被分配了一个分析新数据集的任务,但你不知道从哪里开始?当我第一次作为商业智能顾问开始处理数据时,我也遇到过同样的情况。开始处理包含数百万条您不熟悉的记录的数据有时会让人不知所措。

因此,从较小的数据块开始并向前推进始终是一种最佳实践(是的!数据分析 101)。首先选择一个子集,如部门、产品或位置,然后转移到更大的数据子集。

相信我,知道如何有效地检索企业数据是一项需要磨练的关键技能,因为它会进一步放大数据的价值;不仅仅是日常的商业任务,从面试的角度来看也是如此,因为这是我到目前为止遇到的最常见的面试问题。

下面是大多数 SQL 风格中最常用的数据过滤子句的快速指南。其中均用于基于条件表达式过滤查询结果集,但用例不同。

我在用classic modelsMySQL 样本数据库进行演示;它保存汽车零售商的业务数据。下面是 ER 图,以便快速理解,

作者图片

其中

  • 其中是根据条件表达式过滤出结果集的最常用子句。
  • 通过子句可以使用/不使用组。一起使用时, GROUP BY 子句总是跟在 WHERE 子句后面。

这是来自产品表的样本数据,

SELECT * FROM CLASSICMODELS.PRODUCTS LIMIT 10;

作者图片

比方说,我们想要按每条产品线分组的产品线 老爷车、老爷车摩托车、的当前总库存数量信息。

#where clause exampleSELECT
    PRODUCTLINE,
    SUM(QUANTITYINSTOCK) AS TOTAL_QUANTITY
FROM 
    CLASSICMODELS.PRODUCTS
WHERE PRODUCTLINE IN ('Classic Cars', 'Vintage Cars', 'Motorcycles')
GROUP BY PRODUCTLINE;

上面的查询将返回以下输出:

作者图片

拥有

  • HAVING 类似于 WHERE 子句,不同之处在于它用于使用任何集合函数的过滤条件,并涉及作为过滤条件/表达式的 GROUP BY 子句。
  • GROUP BY 先于 HAVING 子句。(具有子句的总是用在由子句分组的之后)
  • 当在查询中使用 HAVING 子句时,只有满足条件表达式的组才会出现在输出中。

继续上一个示例,我们进一步希望将结果集过滤到总量超过 100000 的产品系列,

#having clause exampleSELECT
    PRODUCTLINE,
    SUM(QUANTITYINSTOCK) AS TOTAL_QUANTITY
FROM 
    CLASSICMODELS.PRODUCTS
WHERE PRODUCTLINE IN ('Classic Cars', 'Vintage Cars', 'Motorcycles')
GROUP BY PRODUCTLINE
HAVING TOTAL_QUANTITY > 100000;

该查询将返回以下输出,

作者图片

WHERE子句的一些关键区别,

  • 语法方面的,其中子句在 GROUP BY 子句之前,这意味着它将在执行聚合计算之前基于条件表达式过滤行。
    而在语法上,具有子句的位于 GROUP BY 子句之后,因此它将在执行聚合计算后过滤行。从性能优化的角度来看,具有子句的慢,在中,应尽可能避免。**
  • 当两者一起使用时, WHERE 子句将首先过滤单个行,然后将这些行分组,执行聚合计算,最后将使用 HAVING 子句过滤组。
  • 其中子句可用于所有 DML 命令,而具有的只能用于 SELECT 语句。

晋级

  • 限定用于过滤表达式根据用户指定的条件使用任何分析/窗口函数的情况。

继续产品线的例子,之前我们查询了产品线老爷车、老爷车摩托车的当前库存产品总量。现在,我们来看看产品线中库存数量最高的前 3 种产品。由于 MySQL 不支持 QUALIFY 子句,请尝试在其他支持的 SQL 环境中运行下面的查询。

#qualify clause example
SELECT 
    PRODUCTLINE,
    PRODUCTNAME,
    QUANTITYINSTOCK,
    ROW_NUMBER() OVER (PARTITION BY PRODUCTLINE ORDER BY   QUANTITYINSTOCK DESC) AS ROW_NUM
FROM 
    CLASSICMODELS.PRODUCTS
WHERE PRODUCTLINE IN ('Classic Cars', 'Vintage Cars', 'Motorcycles') 
QUALIFY ROW_NUM <= 3;

上面的查询将返回,

作者图片

通过使用嵌套查询可以得到相同的结果,

#qualify clause work-around using nested query
SELECT 
    PRODUCTLINE,
    PRODUCTNAME,
    QUANTITYINSTOCK,
    ROW_NUM
FROM 
   (
    SELECT
        PRODUCTLINE,
        PRODUCTNAME,
        QUANTITYINSTOCK,
        ROW_NUMBER() OVER (PARTITION BY PRODUCTLINE ORDER BY QUANTITYINSTOCK DESC) AS ROW_NUM
    FROM 
       CLASSICMODELS.PRODUCTS
    WHERE PRODUCTLINE IN ('Classic Cars','Vintage Cars','Motorcycles')
   )SUBQ
WHERE SUBQ.ROW_NUM <= 3;

还是我个人的最爱;使用【CTE(常用表表达式)

*#qualify clause work-around using cte
WITH STOCK_RANKING
AS
 (
  SELECT
      PRODUCTLINE,
      PRODUCTNAME,
      QUANTITYINSTOCK,
      ROW_NUMBER() OVER (PARTITION BY PRODUCTLINE ORDER BY QUANTITYINSTOCK DESC) AS ROW_NUM
 FROM 
      CLASSICMODELS.PRODUCTS
 WHERE PRODUCTLINE IN ('Classic Cars','Vintage Cars','Motorcycles')
 )

SELECT 
   PRODUCTLINE,
   PRODUCTNAME,
   QUANTITYINSTOCK,
   ROW_NUM
FROM 
   STOCK_RANKING
WHERE ROW_NUM <= 3;*

结论

出于上述原因,我个人尽量避免使用带有子句的。我通常会创建一个临时的或中间的表,在那里获取数据的子集,然后在另一个查询中使用;为了的可读性的复用性。总而言之,如果它是针对您的业务案例的性能优化解决方案,了解这些条款并使用它总是值得的。**

这里有一些有用的资源,

快乐学习!

作为数据科学家进行交流

原文:https://towardsdatascience.com/communicating-as-a-data-scientist-why-it-matters-and-how-to-do-it-well-f1c34d28c7c4

为什么它很重要以及如何做好它

托马斯·勒在 Unsplash 上的照片

作为一名数据科学家,你需要向非技术同事传达你的发现和建议。这可能包括高级管理层、贵公司的其他部门,甚至客户。因此,你必须发展强大的沟通技巧。

我们经常谈论作为一名数据科学家,沟通是多么重要。然而,我们对阐明和发展它说得还不够。

在这篇博文中,我们将讨论沟通在数据科学中的重要性,并概述一些有效沟通的技巧。

通信在数据科学中的重要性

沟通是任何数据科学角色的关键。作为一名数据科学家,我们将依赖您向非技术同事传达您的发现和建议。这可能包括高级管理层、公司内的其他部门,甚至客户。因此,培养良好的沟通技巧是至关重要的。

随着数据科学的发展,数据科学家将他们的发现有效地传达给没有技术背景的人变得越来越重要。此外,沟通是理解复杂概念并将其转化为利益相关者可以理解并采取行动的明确建议的关键。这篇博文将讨论沟通在数据科学中的重要性,并为成为一名有效的沟通者提供一些建议。

但是为什么它在数据科学中如此重要呢?

首先,数据科学就是要清晰简洁地理解和交流复杂的概念。你需要向没有技术背景的人解释你的发现,这样他们才能理解其中的含义并做出明智的决定。

第二,数据科学家经常与不同部门的利益相关者合作。为了提高效率,数据科学家需要了解业务环境,以及他们的发现如何影响公司的其他部门。

第三,数据科学在不断发展,新的技巧和技术也在不断涌现。作为一名数据科学家,跟上这些变化并将其有效地传达给你的团队或组织是非常重要的。

第四,数据科学可用于各种目的,如改善客户体验、推动创新或优化运营。如果您希望您的团队或组织在这一领域进行投资,阐明数据科学项目价值的能力是必不可少的。

关于沟通的一些规则

现在,我们已经了解了沟通在数据科学中如此重要的一些原因,让我们来看看如何成为更有效的沟通者的一些规则,之后我将分享一些建议。

首先,数据科学家在解释他们的发现时需要清晰简洁。这意味着避免复杂的行话,使用每个人都能理解的简单语言。

其次,数据科学家应该花时间了解业务环境,以及他们的发现如何影响公司的其他部门。这将有助于他们与不同部门的利益相关者有效沟通。

第三,数据科学家应该跟上该领域的变化,并准备好向非技术同事解释新的技巧或技术。

如何做这件事的一些建议

交流是关于与某人的联系

数据科学家将数据与故事联系起来,让外行人更容易理解。要做到这一点,数据科学家必须首先了解对他们的受众来说什么是重要的。他们希望得到回答的问题是什么?然后,数据分析师可以将发现转化为有意义的故事,并提供背景。这不是把数据转储到某人身上。

作为一名数据科学家,交流需要清晰的思路

这是关于有清晰的想法。如果多人阅读你的发现,他们会得出相同的结论吗?他们是否以同样的方式理解你的数据、方法和结果?交流也是关于验证的。

解释的效率至关重要;你能快点说重点吗?

能够简化数据以便任何人都能理解是一项有价值的技能。数据科学中的术语过于复杂或过度使用会导致误解和不信任。

让你的听众感到与你有联系。

数据科学是关于人类的。数据科学家必须记住这一点,而且不仅仅是在向非技术背景的人演示时。重要的是找到与你一起工作的每个人的共同点,以建立信任并有效地前进。

请务必阅读这本书

赤裸裸的统计—查尔斯·惠兰

书中的图片

《裸统计》这本书讲的是数据通信。它教导如何以一种让没有技术背景的人容易理解的方式来解释数据。这本书涵盖了数据可视化,统计学和通信技术等主题。对于想要提高沟通技巧的数据科学家来说,这是一个极好的资源。

结论

作为一名数据科学家,有多种有效沟通的方式。这些只是作为一名数据科学家成为有效沟通者的一些技巧。记住,沟通是关键。

准备好回答关于你的数据和分析的问题。耐心点,花点时间详细解释你的发现。记住,不是每个人都有技术背景,所以你需要能够解释事情。

培养强大的沟通技能对于数据科学家来说至关重要。通过遵循这篇博文中概述的技巧,您可以成为一名更有效的沟通者,并对您的数据科学项目产生更大的影响。

免责声明:本帖中有附属链接支持我的写作。如果你通过他们购买,我可以赚取佣金,而且你不用为此付出任何代价。

干杯

能源优化水*的比较分析

原文:https://towardsdatascience.com/comparative-analysis-of-energy-optimization-levels-90eb1463427b

复杂的能源优化需要市场、资产和家庭之间的沟通。

不同级别的能量优化可以获得多少!?

能源使用优化使消费者能够最大限度地降低电费。如今,智能能源管理应用能够以较低的电价将单个设备的消耗转移到小时。

然而,优化潜力要大得多,因为一些能源设备(电动汽车、家用电池)可以同时充当电力的消费者和生产者。这些资产的同步和多方向优化使家庭能够实现非常大的成本节约。

经过两年的研究和开发,我最*推出了一种能源优化器,它可以为一个或多个能源市场的无限数量的同时运行的多方向资产找到数学上的最佳能源使用模式,同时考虑资产的特定限制(所需的电池充电水*、电动汽车与充电器的连接、总容量、功率、充电效率等)。).

本文以一个样本家庭为基础,展示了在不同的能源优化水*下可以节省多少能源。为了比较这些水*,在一年期间(2021 年 10 月 24 日至 2022 年 10 月 23 日)模拟了家庭的最佳行为,并估算了总电费。为了说明能源行为,我将突出显示 2022 年 8 月 17 日 08:00–2022 年 8 月 18 日 07:00 这一天的能源使用模式。

免责声明:本分析中使用的数据发布在 ENTSOE-E transparency Platform 上,获得知识共享署名 4.0 国际许可(CC-BY 4.0)

样本家庭

分析中使用的样本家庭概况如下:

  • 地点:爱沙尼亚。
  • 用电量:家庭年用电量 9654 千瓦时,家庭主保险丝的大小为 20 安培。
  • 太阳能解决方案:太阳能电池板最大产能 7.5 kW,屋顶角度 40 度,屋顶朝南,太阳能电池板年总产量 6981 kWh。
  • 电包:可变(基于股票市场价格)(链接电包)。
  • 网络包:网络 4 ( 链接到 Elektrilevi 包)。

此外,我们的样本家庭拥有一辆电动汽车:

  • 用电量: 20 千瓦时/百公里。
  • 年行驶里程:1.5 万公里。
  • 电动车充电器:功率 7.4 kW。
  • 汽车在工作日 18:00-08:00 和周末 15:00-10:00 连接充电器。
  • 往返充电效率 90%。

我还实施了一个附加要求,即每天早上电动车离开家时,电池必须充满电。

基本场景—无优化

为了评估优化带来的收益,我们首先从一个没有能源优化的场景开始。考虑到家庭的基本负荷、太阳能电池板的生产和电动汽车的消耗,家庭的年电费为 1830€(使用爱沙尼亚市场 2021 年 10 月 24 日至 2022 年 10 月 23 日的电价)。

如果没有优化,太阳能电池板的消耗和多余的生产会自动送到电网。

仔细观察一下 2022 年 8 月一天的用电量(见下表),我们的家庭在 08:00 到 16:00 之间会向电网出售电力,因为太阳能电池板产生的电力超过了家庭的需求。

18:00 车辆插电,自动开始充电,尽管电价极高。作为一般模式,可以强调的是,如果没有优化能源使用,我们的家庭将在最便宜的时段向电网出售电力,并在电力昂贵时从电网消费电力。

2022 年 8 月 17 日至 18 日家庭和电动汽车的消耗,无智能能源管理。电动汽车一插上电源就开始充电,不管电价如何。

级别 1 —通过电价优化单个资产的消耗

我在本文中考虑的最简单的优化是根据电力市场价格控制单个设备(例如电动汽车)的消耗。这可以通过集成软件(如现代热泵)或与设备通信的外部软件(如 Gridio,它选择最便宜的充电时间)来完成。

优化单个设备的消耗,就是选择价格最便宜的小时(作者准备)。

如果我们的家庭根据市场价格优化了电动汽车的充电,就可以节省大约。每年 400€。仔细看看 8 月 17-18 日的模拟,我们可以看到优化系统将电动汽车的充电时间从 18:00(汽车连接时)转移到了早上 04:00,此时电价最便宜。

2022 年 8 月 17 日至 18 日根据市场价格优化充电时家庭和电动汽车的消耗(图片由作者提供)。

级别 2 —优化单个资产的充电和放电

今天,一些型号的电动汽车允许双向充电,这意味着电动汽车既可以作为消费者,也可以作为生产者。

优化单个设备的消耗和生产,就是找到使一个家庭的电力成本最小化的时间表(作者准备)。

双向优化既可以“天真地”执行,也可以“非天真地”执行。前者意味着纯粹根据市场价格进行优化,而不考虑家庭的基本负荷或太阳能电池板的生产。在此分析中,市场价格和家庭条件都作为输入提供给优化器,目标是找到一个解决方案,使家庭的总电力成本最小化。结果显示,与基本方案相比,双向充电将能够使家庭的能源成本降低*€1380。

对一天的分析(下图)显示了比以前更复杂的行为模式:当电价昂贵时,电动汽车向电网发送电力,当电价便宜时充电,并决定在特定时间(22:00-23:00)最小化家庭的总消耗。同时,优化系统还考虑了电动汽车必须在早上 08:00 之前充满电的约束。

在双向充电优化的情况下,2022 年 8 月 17-18 日家庭和电动汽车的消耗。优化系统找到一个解决方案,使一个家庭的电力成本最小化(图片由作者提供)。

级别 3 —多项资产的双向优化

假设我们家住户也买了一块华为 luna 2000–10-S0 家用电池,容量 10 kWh,充电速度 5 kW。这意味着我们有机会同时对几个设备(电动汽车和家用电池)进行双向优化。

在这种情况下,我们的示例家庭的年总成本将达到-€191,这意味着售电收入将大于消费成本。

优化多个设备的双向充电意味着控制设备的同时行为,目标是最小化家庭的总成本。在我们的例子中,有可能使电费成本为负(售电净收入超过消费成本)(图片由作者提供)。

单日分析(下图)揭示了相对复杂的能源行为模式。我想强调“消费”一栏与“电价”之间的关系:在许多小时内,家庭的能源消耗几乎减少到零(10:00-18:00)。造成这种情况的原因是家庭在用电时必须支付的网络费和税款,但这些费用无法通过生产电力收回。这反过来意味着,在很多时间里,家庭“脱离电网”是最佳选择。

一个完全优化的家庭实际上与电网断开许多小时,只有当套利机会很高时才与电网互动!

在电价较高的时段(08:00-09:00 和 18:00-21:00),家庭向电网发送电力(消耗为负),电动汽车在 8 月 18 日凌晨再次充满电。

在多项资产双向优化的情况下,2022 年 8 月 17 日至 18 日的家庭和电动汽车消费。这两种资产同时优化,以尽量减少一个家庭的电力成本(图片由作者提供)。

任何想要查看全年优化电池和 EV 模式的人都可以通过此链接 访问相应的谷歌电子表格。

第 4 级—多资产和多市场优化

除了电价市场,还有电力频率市场,其目的是确保电网中的恒定频率(50 或 60 赫兹)。参与价格和频率市场意味着针对多个市场同时优化多个设备。能量优化器可以处理这种复杂性,但由于波罗的海的频率市场仍处于测试阶段,我将这一分析留给未来。多资产和多市场的情况可以图示如下:

多资产和多市场优化设置的图解(图片由作者提供)。

摘要

让我们再来看看 2022 年 8 月 17-18 日所有优化级别的家庭用电模式。我们可以强调这样的规则,即我们允许执行的优化越复杂,家庭在与电价相反的方向上消耗越多,并且在价格套利的可能性很小的小时中,优化系统决定将家庭的总消耗归零(就像家庭与电网断开连接一样)。

2022 年 8 月 17 日至 18 日样本家庭在不同优化水*下的消费(图片由作者提供)。

不同优化级别的家庭年电费比较显示,最大的优势来自双向优化功能的增加。在几个设备同时优化的情况下,有可能使电力成本为负(售电净收入超过消费成本)。

不同优化水*下样本家庭的年电费(图片由作者提供)

总之,智能能源控制可以非常简单(按最便宜的小时充电),也可以非常复杂和优化(多项资产的多方向同时充电)。有时候,太复杂的解决方案不值得,但不是在这种情况下。当我们充分发挥能源优化的潜力时,我们有可能实现净负能源成本。

用卡方检验比较分类变量的相关性(Stat-12)

原文:https://towardsdatascience.com/compare-dependency-of-categorical-variables-with-chi-square-test-982baff64e81

使用卡方检验寻找分类变量间依赖关系的完整指南

UnsplashKier In Sight 的照片

动机

许多统计测试是可用的,像 p-测试,z-测试,学生的 t-测试,方差分析测试等。为什么我们需要卡方检验?上述测试都没有显示分类变量的依赖性。卡方检验是做这项工作的最好的统计武器。测试背后的主要思想是下面的条款[2]—

“契合度”

让我们用一个例子让它变得简单一点。假设你掷一枚硬币 18 次。一般头尾胜负的概率是 o.5 .所以,概率上说如果你掷一个硬币 18 次,你应该得到 9 次头和 9 次尾。但是你观察到头部的出现次数是 12 次而不是 9 次。这意味着预期值和观察值之间存在差异。 卡方检验显示我们的观察值和期望值有多接*!

卡方检验

卡方检验是一种检验,用于确定某一事件的观察发生次数与预期发生次数之间是否存在显著差异。根据维基百科—

皮尔逊卡方检验用于确定在列联表的一个或多个类别中,预期频率和观察频率之间是否存在统计学上的显著差异[1]。

1900 年,卡尔·皮尔逊写了一篇关于卡方检验的论文

在相关变量系统的情况下,一个给定的偏离概率的系统是这样的,它可以被合理地认为是来自随机抽样

标题有点长,难以实现。所以,他也表达了测试的目的,他说—

“本文的目的是研究任何理论上的观测误差系统的概率标准,并将其应用于确定频率曲线的拟合优度。”

卡尔·皮尔逊从未在测试中使用卡方这个名字,他只是用符号 X 来代表测试。之后,根据希腊字母的名称【X】, 人们称这种检验为卡方检验。

卡方( X )的计算公式很简单。

其中, O 为观测值, E 为期望值。

卡方分布

卡方分布有一个标准值。有了标准值,我们决定是接受还是拒绝我们的假设。教程[3]帮助我轻松地实现了发行版。让我们尝试用几行 Python 代码来绘制分布图。

输出

作者图片

这些线条显示了不同自由度的卡方值分布。水*线与曲线相交,交点表示各个自由度的临界值。

让我们做一些计算,并用 python 实现卡方检验。关于卡方的文章提供了一个实现指南[4]。

假设你有一些关于受教育程度和性别的数据,如下图。

作者图片

基于以上数据,我们想确定男女之间是否存在基于教育水*的显著差异。

X 值计算的逐步计算

假设

零假设→ 性别和受教育程度无显著差异。

替代假设→ 性别和受教育程度存在显著差异。

首先,我们将计算行总计和列总计。

作者图片

现在,我们需要计算每个条目的期望值。它可以通过以下公式计算。

在我们的例子中,总计= 205。 所以,期望值为 **Gender → Man and Education → Secondary School is (105 x 70)/205 = 35.85** 。如果我们计算所有的值,我们将得到表中所示的值。

期望值表(图片由作者提供)

最后,我们将通过应用公式来计算卡方值。

对于给定的数据,我们计算出的【X】值为 3.12。自由度可以与教育级别(中学、高中和大学)和性别(男性和女性)相关联。所以,自由度为=(3–1)x(2–1)= 2。

卡方表(图片由作者提供)

  • 置信度为 95%的 2 自由度 X 的临界值为 5.991。

这里,X<X-临界。

结果表明,我们不能拒绝零假设。因此,我们可以得出结论,性别和教育水*之间没有显著差异。

用 python 实现

让我们创建数据集。

import pandas as pd
data=pd.DataFrame([['Man',30,40,35],['Woman',40,30,30]],columns=['Gender','Secondary School','Higher Secondary School','College'])

输出

作者图片

我们将通过importingchi2_contingency模块来使用 Python 的Scipy library 。该模块仅处理数值。因此,我们只需要提取数值。

data.iloc[:,1:].values

上面的代码将完成这项工作。是时候装上chi2_contingency 型号了。

from scipy.stats import chi2_contingency
stat, p, dof, expected = chi2_contingency(data.iloc[:,1:].values)

print('The Chi-Square value is {:.3f}.\nDegree of freedom is {}.\nExpected table value is \n {}'.format(stat,dof,expected)

输出

The Chi-Square value is 3.122.
Degree of freedom is 2.
Expected table value is 
 [[35.85365854 35.85365854 33.29268293]
 [34.14634146 34.14634146 31.70731707]]

它显示了与我们手工计算相同的结果。让我们尝试将输出可视化。

输出

作者图片

黑色竖线的右边是拒绝区域,线的左边是零假设的接受区域。由于我们计算的卡方值落在可接受区域,我们不能拒绝零假设。

结论

统计学是一种从样本数据推断总体的有趣技术。没有统计数据,我们就无法建立预测模型,因为预测模型可以帮助我们借助过去的数据洞察未来的结果。然而,不同的统计技术和测试被用来分析不同的事物。卡方检验帮助我们显示两个分类变量之间的关系。

【注意:对 的说明】何塞·波尔蒂利亚 ,关于卡方检验帮助我把概念弄清楚。】

参考

  1. https://en.wikipedia.org/wiki/Chi-squared_test
  2. 卡尔·皮尔逊 F.R.S. (1900) X. 关于在相关变量系统的情况下,给定系统与概率的偏差是这样的标准,即可以合理地认为它是从随机抽样中产生的,《伦敦、爱丁堡和都柏林哲学杂志和科学杂志》,50:302,157–175,DOI:10.1080/147888463897
  3. Python-卡方检验(tutorialspoint.com)
  4. Python —皮尔逊卡方检验— GeeksforGeeks

关于数据科学统计学的完整系列文章

  1. 少即是多;采样的‘艺术’(Stat-01)
  2. 熟悉数据科学最重要的武器~变量(Stat-02)
  3. 要提高数据分析能力,您必须了解频率分布(Stat-03)
  4. 通过可视化频率分布找到数据集的模式(Stat-04)
  5. 比较多个频率分布,从数据集中提取有价值的信息(Stat-05)
  6. 用简短的讨论消除你对意思的误解(Stat-06)
  7. 通过规范化提高您的数据科学模型效率(Stat-07)
  8. 数据科学的基本概率概念(Stat-08)
  9. 从朴素贝叶斯定理到朴素贝叶斯分类器的路线图(Stat-09)
  10. https://medium.datadriveninvestor.com/all-you-need-to-know-about-hypothesis-testing-for-data-science-enthusiasts-30cfe1dce028?source=your_stories_page-------------------------------------数据科学爱好者关于假设检验的所有知识(Stat-10)
  11. 多组间统计比较用 ANOVA (Stat-11)
  12. 用卡方检验比较分类变量的相关性(Stat-12)

您可以通过以下链接订阅媒体上的每一篇文章。

*https://mzh706.medium.com/membership

订阅以下链接,获取我的文章通知。

https://mzh706.medium.com/subscribe *

使用相似性度量比较文档

原文:https://towardsdatascience.com/comparing-documents-with-similarity-metrics-e486bc678a7d

自然语言处理中如何利用数学比较文本的初步研究

帕特里克·托马索在 Unsplash 上的照片

评估文档之间的相似性是自然语言处理中的一个常见步骤。它在许多具有信息检索和翻译等功能的微服务中扮演着不可或缺的角色。

花点时间问问自己:机器首先是如何比较文本的?

如果您想为自己利用这些技术,您需要了解一点执行文本比较背后的数学知识。

虽然许多确定文档相似性的微服务非常复杂,并且采用了先进的技术和概念,但是您可以通过首先了解可以量化文本片段之间的相似性的更简单的度量标准,朝着正确的方向迈出一步。

相似性度量虽然很幼稚,但却是向自己介绍比较文档概念的好方法。在这里,我们探讨两个比较著名的相似性度量:欧几里德距离和余弦相似性。

欧几里得距离

请记住,在 NLP 中,文本的主体被表示为向量。

那么,从数学的角度来看,比较向量最合适的方法是什么?

直觉上,比较两个向量之间的距离似乎是最合理的方法。

测量两个向量之间距离的度量是欧几里德距离。

其公式如下所示:

注意:在 Python 中,可以使用 Sklearn 模块的 euclidean_distances 函数轻松计算这个度量。

虽然用这种度量来比较向量可能有意义,但在 NLP 中使用时,它会引入一个明显的问题。

请看下图:

矢量图(由作者创建)

向量 x 和 y 之间的距离取决于这些向量的大小。在这种情况下,向量 x 或 y 的大小增加会导致更大的欧几里德距离。

就 NLP 而言,这意味着在多样性和频率方面具有更多单词的较大正文文本将比较小正文文本具有更大的量级,即使它们共享相同的主题。

这可能是一个问题,因为比较文档的人对文档的主题比对文本的数量更感兴趣。

想想我们已经变得如此依赖的搜索引擎。如果我们在谷歌中搜索“气球”,我们会希望看到与气球最相关的文章。我们不想局限于与查询本身一样长的结果。

因此,欧几里德距离可能不是文档相似性的最佳度量。

那么,我们如何在数学上比较文档,同时忽略大小,专注于主题呢?

余弦相似性

一个学派建议考虑向量之间的角度而不是距离。

表示为向量的文档可以通过评估两个向量之间的角度来进行比较。

考虑两个向量的角度的度量是余弦相似性度量

余弦相似度的公式如下所示:

余弦相似度(由作者创建)

余弦相似性值的范围可以从 0 到 1,0 表示最低相似性,1 表示最高相似性。

要理解余弦相似性如何胜过欧几里德距离,请看下图。

矢量图(由作者创建)

不管矢量 x 和 y 的大小变化多少,矢量 x 和 y 之间的角度将保持不变。

这意味着余弦相似性考虑两个向量之间的角度,而不检查向量的大小。这消除了欧几里德距离度量带来的问题。

作为余弦相似性度量的演示的一部分,考虑以下 3 个句子:

我喜欢在炎热的夏天吃冰淇淋。

只有无聊的人才不喜欢吃冰淇淋。

我不喜欢在夏天出去,因为天气太热了。

我们可以通过推导这些句子的向量表示之间的角度余弦来评估这些句子之间的相似性。

由于 Sklearn 模块的余弦相似度函数,这在 Python 中很容易实现。

首先,让我们创建一个函数来计算两个给定文本的余弦相似度。这个函数将用 TF-IDF 算法将给定的句子转换成向量,并计算生成的向量的余弦相似度。

我们可以使用这个函数来确定这三个句子之间的相似度。

代码输出(由作者创建)

基于结果,句子 1 和 2 以及句子 1 和 3 具有最高的相似度,而句子 2 和 3 具有最低的相似度。

这是有道理的,因为句子 1 和 2 都提到了“吃冰淇淋”,而句子 1 和 3 都提到了“炎热的夏天”。另一方面,句子 2 和 3 实际上没有共享任何主题,因此导致低余弦相似性分数。

结论

照片由普拉蒂克·卡蒂亚尔Unsplash 拍摄

自然,我们经常依赖的微服务是复杂的,依赖的不仅仅是简单的矢量化和相似性度量。

但是,如果您掌握了比较文本的简单方法,您将朝着理解 NLP 中用于文档相似性的更高级技术迈进了一步。

我祝你在数据科学的努力中好运!

用 easycheck 比较浮点数

原文:https://towardsdatascience.com/comparing-floating-point-numbers-with-easycheck-dcbae480f75f

easycheck 可以帮助您在类似断言的情况下比较浮点数

比较浮点数。图片作者。

在 Python 中比较浮点数比您想象的要简单。这要感谢math模块,但不仅仅是。大卫·阿莫斯最*在他的 关于数据科学的文章中非常好地描述了这个主题,所以如果你对基础知识感兴趣,请先阅读它。

在本文中,我将向您展示如何在类似断言的情况下比较浮点数。人们不应该在生产代码中使用assert语句,因为在调用 Python 脚本时,所有断言都可能被屏蔽,这是通过-O优化标志完成的。所以,在你的产品代码中使用assert是有风险的,尤其是当它们负责重要的检查时。这样的应用程序可能会出现意外行为。

上面我强调了“生产”。这是因为在开发过程中,当您检查代码中的各种条件时,您可以使用assert。但是,您需要记住,不要运行带有优化标志的代码。记住,一旦你完成了开发,以后就要依赖它们了。

如果您想在生产代码中使用断言,该怎么办?如果不是assert,那是什么?

幸运的是,还有其他选择,在这里我们将讨论其中的一个:[easycheck](https://github.com/nyggus/easycheck)包。它提供了我们称之为类似于assert的功能。这些函数允许检查一个条件(或几个条件)并在违反条件时抛出异常(或发出警告);当一个条件满足时,什么都不会发生。

你看到与assert陈述的相似之处了吗?事实上,easycheck的行为与此类似,但是提供了更丰富的功能。

在本文中,我们将在一个上下文中讨论easycheck:比较浮点数。在此之前,我们需要讨论比较浮点数的基础知识。主要的 Python 工具是标准库中的math.isclose()函数。了解其工作原理将为我们分析easycheck的报价提供背景。

比较浮动有什么大惊小怪的?

一方面,

一切都好。另一方面,

一点都不好!

这些都是常见的问题,当浮点数以这种意想不到的方式运行时,我可以提供更多类似的例子。但这不是本文的目的。你可以在 David Amos 的文章中看到更多的例子和相当详细的解释。

最常见的——也是大多数情况下最好的——解决方案是使用标准库math.isclose()函数。它允许使用差异的相对容差(rel_tol,默认为rel_tol=1e-09)或差异的绝对容差(abs_tol,默认为abs_tol=0.0)来比较两个浮点数。这是最简单的用例:

上面,我使用了该函数的默认设置,这意味着用相对容差1e-09和无绝对容差(默认设置为 0)来比较这两个数字。换句话说,这两个数字被认为相对不接*

abs(x — y)/min(x, y) > rel_tol

否则,它们被认为是相对接*。当然,我们必须在提供的容差范围内考虑这个接*度。两个数字在一个容差的上下文中可以接*,在另一个容差的上下文中可以不接*。

注意关闭并不意味着没有不同没有关闭并不意味着不同。这只是文字,我们如何解读数字取决于我们自己。然而,本质上,这个函数并不能让你判断两个数字是否相同。顾名思义,它使您能够分析两个数字有多接*。

要了解更多信息,请阅读 Python 的 [math](https://docs.python.org/3/library/math.html) 模块的文档,以及上面提到的 David Amos 的文章。

easycheck比较浮动

math.isclose()函数返回一个布尔值,告知两个数字在给定容差下是否接*,是相对还是绝对,或者两者都有。这样,当你想回答这样一个问题:这两个数字是否接*时,它将满足你的需要。

然而,当您想在类似断言的上下文中这样做时,math.isclose()不能直接应用。您可以使用一个if-else块来实现,在这个块中,当条件不满足时,您会引发一个异常。但是你可以使用一个专用的工具来完成,因为这正是easycheck包设计的目的。

通过类似断言的上下文,我理解了检查条件的情况,当条件不满足时,就会引发异常;如果是的话,什么也不会发生。这就是assert的工作原理。有了easycheck,你可以发出警告,但是你还可以做更多的事情。因此,在提供assert所提供的同时,easycheck实际上提供了更多:

  • assert语句不应该在生产代码中使用,因为在运行程序时,它在代码中的所有实例都可以被优化标志(-O)屏蔽。在某些情况下,这是一件好事,因此easycheck将很快获得类似的功能。
  • assert语句使您能够仅引发AssertionError,并带有可选消息。使用easycheck,您可以引发任何您想要的异常并发出任何您想要的警告。
  • assert作为裸机工具,速度更快。

可以使用一个if块或一系列if块来代替easycheck。然而,easycheck更加优雅,提供了更加丰富的功能。此外,if-与easycheck不同,块用于各种目的。因此,当你看到一个if-块时,你必须阅读它,看看它的目的是什么。当你看到一个assert语句或者一个easycheck函数调用时,你马上就知道它是验证码。

为了比较浮点数,我们可以使用easycheck.check_if_isclose()函数。它的名字,你也看到了,和math.isclose()差不多,很好记。它的 API 也和math.isclose()差不多。我写“几乎相同”只是因为它有几个额外的(我们在下面讨论它们)。关键是在比较数字方面,这两个函数的工作方式完全相同,因为easycheck.check_if_isclose()math.isclose()的直接包装器。

因此,从数学的角度来看,这两个函数的工作方式完全相同。区别在于它们的行为方式:

  • math.isclose()返回一个布尔值:如果数字足够接*,则返回True,否则返回False
  • 当两个数字足够接*时,不执行任何操作。当它们不是时,它要么引发一个错误,要么发出一个警告,这取决于您的请求。您可以使用可选消息。

下一节将详细分析这个函数。

easycheck.check_if_isclose()在行动

这是该函数的签名:

这里,

  • xy都是仅位置参数,是传递给math.isclose()的两个参数(作为ab)。
  • handle_with是一个典型的easycheck参数,用在它的所有检查函数中。它设置不满足条件时使用的异常类。在这个函数中,默认为NotCloseEnoughError,一个在easycheck中定义的异常类。如果您需要捕捉和处理这个异常,您必须从包中导入它。
  • message当然是与异常一起使用的消息。你可以随意定制。默认值是None,对于这个函数来说,这实际上意味着消息将是"The two float numbers are not close enough"。如果不想使用任何信息,使用message=""
  • rel_tolabs_tolmath.isclose()中使用的参数完全相同。它们具有相同的名称、默认值和行为,并且它们被直接传递给math.isclose()

所以,如果你已经知道如何使用math.isclose()——如果你想使用easycheck.check_if_isclose(),你就应该知道后者如何比较数字。注意一个微小的区别:调用math.isclose()时,您可以使用关键字参数ab,而easycheck函数只使用位置参数。因此,如果您在isclose()函数中使用了ab参数名称,请记住删除它们。

因此,您可以做的唯一额外定制是特定于easycheck的参数,即handle_withmessage,尽管实际上您可以简单地将它们保留。默认错误可能工作得很好,它的名字传达了您需要的一切:NotCloseEnoughError。当然,你也可以使用任何其他的例外,一个自定义一个

是时候看看这个函数的实际作用了。我确信,如果你知道如何使用math.isclose()并且使用过几次,你在理解下面例子中发生的事情时不会有任何问题。

注意 :一定要记住,如果满足条件,什么都不会发生,几次检查都会看到这个。

上述对easycheck.check_if_isclose()的调用既不改变handle_with也不改变message。让我们看看我们能做些什么:

花几分钟分析上面的片段,自己决定easycheck.check_if_isclose()是否容易使用。

easycheck比较单元测试中的浮点

由于单元测试是基于断言的环境,你可以在单元测试中使用easycheck.check_if_isclose(),例如在[pytest](https://docs.pytest.org/en/7.1.x/)[doctest](https://docs.python.org/3/library/doctest.html)中。然而,easycheck带有一个别名easycheck.check_if_isclose(),专用于测试:easycheck.assert_if_isclose()。作为别名,它的用法和easycheck.check_if_isclose()完全一样。下面的脚本展示了一个典型的pytest文件的例子:

当然,这个代码没有什么特别的。这与之前的检查类似,但是之前是在代码上下文中进行的,而现在是在单元测试上下文中进行的。

如果您运行测试文件,您将会看到测试将会失败:

pytest 中easycheck.assert_if_isclose()的使用:失败测试的输出。图片作者。

结论

浮动相对容易比较,但是只有当你知道如何比较的时候。在大多数情况下,math.isclose()将是首选方法。这是一个简单的函数,我认为使用起来相当简单,我希望你同意我的观点。

然而,在某些情况下,easycheck.check_if_isclose()或者它的单元测试别名easycheck.assert_if_isclose()会更适合您的需要。例如,您可能更喜欢在生产代码中使用前者。

easycheck是一个外部包,需要安装。它可以从 PyPi 获得,所以您可以使用pip安装它:

如果您决定使用easycheck,您将得到一个模块,您不仅可以使用它来比较两个浮点数,还可以执行各种检查。但是这个故事我以后会讲的…

感谢阅读!留下你对比较浮动、math.isclose()easycheck.check_if_isclose()的看法的评论。也许你知道另一个工具,在这些或不同的场景中,它对比较浮点数特别有帮助?

资源

  • 大卫·阿莫斯(2022)。Python 中比较浮点数的正确方法,走向数据科学
  • 仓库中的 [easycheck](https://github.com/nyggus/easycheck)
  • [math](http://Documentation of the math module)[模块](http://Documentation of the math module)的文档
  • 科萨克米(2022)。我们应该在 Python 中使用自定义异常吗?走向数据科学
  • [pytest](https://docs.pytest.org/en/7.1.x/) 的网页
  • [doctest](https://docs.python.org/3/library/doctest.html)模块的文档

感谢

感谢 David Amos 关于比较浮点数的好文章。如果没有它,我将不得不把这篇文章写得更长,这样就不那么关注它的内容:使用easycheck来比较浮动。

比较线性回归和逻辑回归

原文:https://towardsdatascience.com/comparing-linear-and-logistic-regression-11a3e1812212

一个入门级数据科学面试问题的探讨

数据科学面试的深度各不相同。有些面试非常深入,测试候选人对高级模型或复杂微调的了解。但许多面试都是在入门级别的情况下进行的,试图测试候选人的基础知识。在这篇文章中,我们将看到一个可以在这样的采访中讨论的问题。尽管这个问题非常简单,但讨论带来了机器学习基础的许多有趣方面。

问题:线性回归和 Logistic 回归有什么区别?

这两者之间实际上有许多相似之处,首先是他们的名字听起来非常相似。它们都使用直线作为模型函数。他们的图表看起来也非常相似。

作者图片

但是尽管有这些相似之处,它们在方法和应用上是非常不同的。我们现在将强调这些差异。为了进行比较,我们将使用在讨论任何机器学习模型时通常考虑的以下几点:

  • 假设或模型族
  • 输入和输出
  • 损失函数
  • 最优化技术
  • 应用

我们现在将比较线性回归(LinReg)和逻辑回归(LogReg)在这些点上的差异。让我们从应用程序开始,让讨论步入正轨。

应用

图片由 Rajashree Rajadhyax 提供

线性回归用于根据其他量来估计一个量。举个例子,想象一下,作为一名学生,你在暑假经营一个柠檬水摊。你想算出明天会卖出多少杯柠檬水,这样你就可以买足够的柠檬和糖。从你长期销售柠檬水的经验中,你已经弄清楚了销售与一天中的最高温度有很大的关系。因此,您希望使用预测的最高温度来预测柠檬水销售。这是一个经典的 LinReg 应用,在 ML 文献中一般称为预测。

LinReg 还用于找出特定输入如何影响输出。在柠檬水摊位示例中,假设您有两个输入——最高温度和当天是否是假日。你想知道最高温度和假日哪个对销售影响更大。LinReg 将有助于识别这一点。

LogReg 主要用于分类。分类是将输入分类到许多可能的篮子中的一个的行为。分类对人类的智力如此重要,以至于说“大部分智力都是分类的”一点都不会错。分类的一个很好的例子是临床诊断。考虑老年人,可靠的家庭医生。一位女士走进来,抱怨不停地咳嗽。医生进行各种检查,在许多可能的情况中做出选择。一些可能的情况相对无害,比如喉咙感染。但是有些很严重,比如肺结核甚至肺癌。基于各种因素,医生决定她患了什么病,并开始适当的治疗。这是分类在起作用。

我们必须记住,估算和分类都是猜测任务,而不是计算。在这类任务中没有确切或正确的答案。猜测任务是机器学习系统擅长的。

模范家庭

ML 系统通过检测模式来解决猜测问题。他们从给定的数据中检测模式,然后使用它来执行任务,如估计或分类。在自然现象中发现的一个重要模式是关系模式。在这个模式中,一个量与另一个量相关。在大多数情况下,这种关系可以用数学函数来*似。

从给定的数据中识别一个数学函数被称为“学习”或“训练”。学习有两个步骤:

  1. 函数的“类型”(例如线性、指数、多项式)由人来选择
  2. 学习算法从给定的数据中学习参数(如直线的斜率和截距)。

因此,当我们说 ML 系统从数据中学习时,它只是部分正确。选择函数类型的第一步是手动的,并且是模型设计的一部分。函数的类型也称为“假设”或“模型族”。

在 LinReg 和 LogReg 中,模型族都是线性函数。众所周知,直线有两个参数——斜率和截距。但是这只有在函数只接受一个输入时才成立。对于大多数现实世界的问题,有不止一个输入。这些情况下的模型函数称为线性函数,而不是直线。一个线性函数有更多的参数需要学习。如果模型有 n 个输入,则线性函数有 n+1 个参数。如上所述,这些参数是从给定的数据中学习的。出于本文的目的,我们将继续假设该函数是带有两个参数的简单直线。LogReg 的模型函数稍微复杂一些。这一行是有的,但它与另一个功能相结合。我们一会儿就会看到这一点。

输入和输出

正如我们上面所说,LinReg 和 LogReg 都是从给定的数据(称为训练数据)中学习线性函数的参数。训练数据包含什么?

通过记录一些真实世界的现象来准备训练数据(RWP)。例如,最高气温和柠檬水销售之间的关系是一个 RWP。我们看不到潜在的关系。我们所能看到的是每天的温度和销售额。在记录观测值时,我们指定一些量作为 RWP 的输入,另一些量作为输出。在柠檬水的例子中,我们将最高温度称为输入,将柠檬水的销售额称为输出。

作者图片

我们的训练数据包含成对的输入和输出。在本例中,数据将包含每天最高温度和柠檬水销售量的行。这就是 LinReg 的输入和输出。

LogReg 执行的任务是分类,所以它的输出应该是一个类。我们假设有两个类,分别叫 0 和 1。模型的输出也应该是 0 或 1。

然而,这种指定输出的方法并不十分恰当。请参见下图:

作者图片

黄色的点属于 1 级,浅蓝色的点属于 0 级。这条线是我们的模型函数,它将两个类分开。根据该分隔符,黄色点(a 和 b)都属于 1 类。但是,b 点的隶属度比 a 点的隶属度确定得多,如果模型只是简单地输出 0 和 1,那么这个事实就失去了。

为了纠正这种情况,LogReg 模型产生每个点属于某个类的概率。在上面的例子中,点‘a’属于类 1 的概率低,而点‘b’的概率高。由于概率是介于 0 和 1 之间的数字,因此 LogReg 的输出也是如此。

现在请看下图:

作者图片

这张图和前面的一样,只是增加了 c 点。该点也属于第 1 类,并且实际上比 b 点更确定。但是,按照点与直线的距离成比例地增加点的概率是错误的。直观地说,一旦你离开这条线一段距离,我们或多或少就能确定这些点的隶属关系。我们不需要进一步增加概率。这符合概率的本质,概率的最大值可以是 1。

为了使 LogReg 模型能够产生这样的输出,line 函数必须连接到另一个函数。第二个函数称为 sigmoid,其等式为:

因此,LogReg 模型看起来像:

作者图片

sigmoid 函数也称为“逻辑函数”,这就是“逻辑回归”这个名称的由来。

如果有两个以上的类,LogReg 的输出是一个向量。输出向量的元素是输入属于该特定类别的概率。例如,如果临床诊断模型的第一元素具有值 0.8,则意味着该模型认为患者有 80%的概率患感冒。

损失函数:

我们看到 LinReg 和 LogReg 都从训练数据中学习线性函数的参数。他们是如何学习这些参数的?

他们使用一种叫做“最优化”的方法。优化的工作原理是为给定的问题生成许多可能的解决方案。在我们的例子中,可能的解决方案是(斜率,截距)值的集合。我们使用性能指标来评估这些解决方案。最终选择在这一措施上被证明是最佳的解决方案。

在 ML 模型的学习中,性能度量有时被称为“损失”,帮助我们计算它的函数被称为“损失函数”。我们可以将此表示为:

Loss = Loss_Function (Parameters_being_evaluated)

术语“损失”和“损失函数”具有负面含义,这意味着更低的损失值表示更好的解决方案。换句话说,学习是一种优化,旨在找到产生最小损失的参数。

我们现在将看到用于优化 LinReg 和 LogReg 的常见损失函数。请注意,在实际应用中使用了许多不同的损失函数,因此我们可以讨论最常见的损失函数。

对于 LinReg 参数的优化,最常见的损失函数称为误差*方和(SSE)。该函数接受以下输入:

1)所有的训练数据点。对于每个点,我们指定:

a)输入,如最高数据温度、

b)输出,如售出的柠檬水玻璃杯的数量

2)带参数的线性方程

然后,该函数使用以下公式计算损耗:

SSE Loss = Sum_for_all_points(
Square_of(
output_of_linear_equation_for_the_inputs — actual_output_from_the_data point
))

LogReg 的优化度量是以非常不同的方式定义的。在 SSE 函数中,我们提出以下问题:

If we use this line for fitting the training data, how much error will it make?

在设计 LogReg 优化的度量时,我们会问:

If this line is the separator, how likely is it that we will get the distribution of classes that is seen in the training data?

因此,这一措施的输出是一种可能性。测量函数的数学形式使用对数,因此命名为对数似然(LL)。在讨论输出时,我们看到 LogReg 函数包含指数项(e '提升到' z '的项)。对数有助于有效处理这些指数。

你应该很直观地明白,优化应该使 LL 最大化。这样想:我们要找到使训练数据最有可能的那条线。然而在实践中,我们更喜欢可以最小化的度量,所以我们只取 LL 的负值。因此,我们得到负对数似然(NLL)损失函数,尽管根据我的说法,称它为损失函数是不太正确的。

所以我们有两个损失函数:LinReg 的 SSE 和 LogReg 的 NLL。请注意,这些损失函数有许多名称,您应该熟悉这些术语。

摘要

尽管线性回归和逻辑回归看起来和听起来非常相似,但实际上它们是完全不同的。LinReg 用于估计/预测,LogReg 用于分类。诚然,它们都使用线性函数作为基础,但 LogReg 进一步增加了逻辑函数。它们使用训练数据和生成模型输出的方式不同。这两者还使用了非常不同的损失函数。

进一步的细节可以探究。为什么选择 SSE?可能性是如何计算的?为了避免更多的数学运算,我们在这里没有深入研究优化方法。但是,您必须记住,LogReg 的优化通常需要迭代梯度下降法,而 LinReg 通常可以使用快速封闭形式的解决方案。我们可以在另一篇文章中讨论这些和更多的问题。

浓缩咖啡提取率测量方法的比较

原文:https://towardsdatascience.com/comparing-methods-for-measuring-extraction-yield-4fd4da584be1

咖啡数据科学

浓缩咖啡提取率测量方法的比较

干测量与湿测量

冲泡咖啡时,主要的定量质量指标是提取率(EY)。EY 有两种测定方法:烘干废咖啡和测量总溶解固体(TDS)来计算 EY。我想知道这两种方法的一致性如何,所以我收集了一些数据。

咖啡含有大约 30%的可溶性固形物,通常情况下,浓缩咖啡的良好提取率在 18%到 22%之间。特殊的技术可以将提取率提高到接* 30%,而不会对风味产生负面影响。

测量方法

干燥一个用过的圆盘会去除所有的水分,如果你将干燥的重量与输入的重量进行比较,你就会知道现在有百分之多少的粉末被去除或提取。需要注意的是,假设拍摄前的咖啡不含水。

用折射仪测量总溶解固体量(TDS),这个数字结合弹丸的输出重量和咖啡的输入重量用来确定提取到杯中的咖啡的百分比,称为提取率(EY)** 。**

使用 Atago 仪表测量 TDS。所有图片由作者提供

用 200 华氏度或 93 摄氏度的烤箱或烤面包机烤 30 分钟左右相对容易。

设备/技术

浓缩咖啡机:金特快

咖啡研磨机:小生零

咖啡:家庭烘焙咖啡,中杯(第一口+ 1 分钟)

预灌注:长

输液:压力脉动

过滤篮 : 20g VST

其他设备: Atago TDS 计Acaia Pyxis 秤

表演

一个简单的比较显示读数很接*,但有很多噪音。

散点图显示更好的观点。干燥的 EY 几乎总是高于 TDS 测量的 EY。似乎有一个大致的线性趋势,但似乎有很多变化。甚至当通过烘烤分割时,图案被展开。

****

如果有的话,这些结果表明,TDS 测量的 EY 可能低于实际 EY。问题是要确切知道能提取多少。用用过的咖啡和 T2 浓缩咖啡粉可以做到这一点,所以也许我会在一次性实验中尝试一下。

如果你愿意,可以在推特YouTubeInstagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以在关注我,在订阅

我的进一步阅读:

我未来的书

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事启动页面

摄影飞溅页面

改善浓缩咖啡

断奏生活方式概述

测量咖啡研磨分布

浓缩咖啡中的粉末迁移

咖啡萃取

咖啡烘焙

咖啡豆

浓缩咖啡用纸质过滤器

浓缩咖啡篮及相关主题

意式咖啡观点

透明 Portafilter 实验

杠杆机维修

咖啡评论和想法

咖啡实验

SQL 与 NoSQL |比较关系和非关系数据库管理

原文:https://towardsdatascience.com/comparing-relational-and-non-relational-database-management-systems-sql-vs-nosql-f4c8f5988365

关系数据库(SQL)与非关系数据库(NoSQL)

泰勒·维克在 Unsplash 上的照片

关系数据库管理系统(RDBMS)是一种数据库管理系统,通常与 SQL 查询语言相关联。另一方面,NoSQL(代表而不仅仅是 SQL )与非关系型数据库管理相关联。关系数据库先于非关系数据库出现。它们需要一个预定义的模式,指明数据库中的结构和关系必须遵循的规则。RDBMS 的每个状态都必须满足模式中规定的完整性约束,因此,关系数据库在格式上是非常结构化和不灵活的。
因此,它们适用于简单和静态的数据结构,换句话说,数据在记录后不会改变。
就其结构而言,关系数据库以分组为关系的元组来表示数据。这些关系被称为表,每个表都有一定数量的行/记录(其中每个记录对应一个元组)和列/属性。每个列/属性都有一个数据类型(比如 integer 或 string),列中的每个元素都必须符合指定的数据类型。

在关系数据库中,不同表中的记录以及记录之间的关系通过来定义。主键是唯一标识表中行的属性。然后,这些主键可以作为属性包含在其他表的行中,以指示跨表记录之间的关系。当一个表中的主键表示另一个表中的关系时,它被称为外键

例如,我们可以考虑一个包含销售公司所有雇员的表,每个雇员都有一个惟一的雇员 ID,作为雇员表中的主键。我们还有一个不同的表,包含该公司的所有销售额,每个销售额都有一个惟一的销售 ID,这是销售表中的主键。但是,公司可能希望跟踪每笔销售是由哪个雇员完成的,因此我们也将雇员 ID 作为一个属性包含在 sales 表中。在 sales 表中,雇员 ID 被称为外键,因为它指示表之间的关系,但不是 sales 表中的唯一标识符(因为每个雇员可以进行多次销售)。

克劳迪奥·施瓦兹在 Unsplash 上的照片

由于预定义的模式和关系结构,关系数据库具有几个有利的特性。首先,参照完整性加强了两个关系之间的一致性。一个结果是每个外键都必须指向一个现有的主键。例如,如果我们试图删除上面的 employee 表中的一个条目,我们还必须删除 sales 表中与该雇员相关的每一条记录,否则我们将有一个断开的/不一致的链接。其次,每个数据库事务必须坚持四个属性,*(原子性、一致性、隔离性、持久性),否则,事务将被拒绝。这些属性确保数据库在出现错误、服务器崩溃和其他潜在问题时仍保持有效状态。

然而,*年来,大数据技术的应用已经扩展到各种各样的领域,在这些领域中,数据可能是动态的和缺乏结构的。由于传统关系系统的不灵活性,非关系数据库管理系统已经成为处理实践中对数据库管理系统提出的不断变化的需求的必需品。与 RDBMS 相反,非关系(NoSQL)系统不需要预定义的模式。因此,该模式是动态的和可适应的,允许用户处理那些不能清楚地分割成具有预定义关系的实体表的数据。除了允许非结构化数据,非关系系统还提供了更好、更便宜和更容易的可伸缩性。关系系统特有的严格模式确保了它的准确性和一致性,但也带来了阻碍水*可伸缩性的缺点。很难有一个遵循 ACID 的分布式系统,因此,关系系统有助于纵向扩展(向现有服务器添加更多资源,而不是添加更多服务器)。另一方面,NoSQL 系统的约束不太严格,允许跨多个服务器分布事务和负载(水*伸缩)。*

照片由 Massimo BotturiUnsplash 上拍摄

然而,正如 CAP 模型告诉我们的,任何数据库系统只能提供以下三种保证中的两种:一致性、可用性和分区容差。非关系系统提供的额外灵活性是有代价的,我们用 ACID 替换了 BASE(基本可用性、软状态、最终一致性)。在 CAP 模型的三个保证中,BASE 优先考虑数据可用性,而 ACID 优先考虑一致性。基本系统虽然最终是一致的,但并不强制立即一致,这是与符合 ACID 的关系数据库的主要区别。

考虑到每种数据库管理系统的优点和缺点,不可能对其中一种做出明确的判断。在选择关系型和非关系型(NoSQL)系统时,必须考虑用户独特的用例。例如,社交网络订阅源是动态的、非结构化的,并且包含大量的流数据;这将是一个用例,我们需要 NoSQL 的灵活性。

如果你从这些文章中获得了价值,并且还不是 medium 会员,考虑使用下面的链接注册 Medium!👇

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

MAE、MSE 和 RMSE 的稳健性比较

原文:https://towardsdatascience.com/comparing-robustness-of-mae-mse-and-rmse-6d69da870828

存在异常值时主要回归指标的表现

由克里斯·利维拉尼在 Unsplash 上原创

如果您处理数据,您可能已经知道 MSE 比 MAE 对异常值更敏感。但是你测试过吗?我做到了,这篇文章就是关于它的。

许多回归模型依赖于距离度量来确定向最佳结果的收敛。甚至“最佳”结果的定义也需要用某种度量标准来定量解释。

通常使用的度量是*均误差(MAE)、均方误差(MSE)或均方根误差(RMSE)。

作者图片

简而言之, MAE 评估观测值(数据集的条目)到回归预测值的绝对距离,取所有观测值的*均值。我们使用距离的绝对值,因此负误差被适当地考虑。这正是上图描述的情况。

另一种方法是*方距离,这样结果就是正的。这是由 MSE 完成的,由于幂函数的性质,较高的误差(或距离)在度量中比较低的误差权重更大。

MSE 中的一个反弹是,度量单位也是*方的,因此如果模型试图以美元预测价格,MSE 将产生一个没有意义的单位(美元)数。 RMSE 然后被用于通过对 MSE 误差求*方根来将 MSE 误差返回到原始单位,同时保持惩罚较高误差的属性。

稳健性

稳健性可以定义为系统或模型在暴露于噪声或夸大的输入时保持稳定并且只有很小变化(或根本没有变化)的能力。

因此,一个健壮的系统或指标必须较少受到异常值的影响。在这种情况下,很容易得出 MSE 可能不如 MAE 稳健的结论,因为误差的*方将对异常值施加更高的重要性。

让我们证明这一点。

代码准备

这项研究的代码可以在我的 github 上找到,所以可以随意跳到下一节。

首先,我们定义计算所有三个指标的代码。在这种情况下,我们不会将观察值与回归线进行比较,而是测量每个观察值到集合*均值的距离:

然后,我们创建包含许多随机观察值的集合。这些点将从均值= 100、方差= 20 的正态分布中取样。

现在进行主功能evaluate_metrics()。这里的目标是评估每组观测值的*均误差、均方误差和 RMSE。当然,由于创建集合的随机过程,指标会略有不同。我们可以在没有异常值的情况下绘制这种分布,称之为“原始”分布。

然后我们可以对每个集合中的随机点进行采样,并乘以一个很高的数,这样它们肯定会成为异常值。通过对那些现在有噪声的观测重复上述过程,我们可以绘制另一条分布曲线,并与原始曲线进行比较。

该函数的代码如下。

实验

通过改变离群值的数量(num_outliers)和原始观测点(amplitude_outliers)所乘以的标量的幅度,可以在许多不同的场景中比较指标的稳健性。

因此,作为一个对照组,我们可以将函数设置为零异常值

evaluate_metrics(data, num_outliers = 0, amplitude_outliers = 1)

结果是原始分布和噪声分布完全相同,正如所料:

作者图片

不过,有几件事值得注意。MAE 分布的*均值约为 16,MSE 分布的*均值约为 400。预计 MSE 误差的值比 MAE 误差高大约 2 的幂,所以这并不是什么新鲜事。

但是,当取均方差的*方根并得到 RMSE 时,我们得到的*均值约为 20,高于均方差。这是因为 MSE 和 RMSE 对较高误差的放大作用大于较低误差。

此外,RMSE 和 MSE 曲线是相同的,这也是意料之中的,因为*方根不应该改变分布,只有规模。(注意:要比较它们,请关注曲线,忽略直方图)

现在我们可以开始用噪声数据进行比较。在第一个测试中,我们只能添加两个振幅= 2 的异常值:

evaluate_metrics(data, num_outliers = 2, amplitude_outliers = 2)

正如预期的那样,异常值将增加*均误差,并导致噪声分布右移:

作者图片

当将任何噪声分布与其原始对应物进行比较时,可以注意到噪声分布现在是变形的。预计它们不会具有与原始分布相同的形式,因为异常值可以随机改变这些不再完全正态(高斯)的分布。

此外,很明显,噪声 MSE 和 RMSE 分布比 MAE 分布移动得更多。这进一步证明了它们对异常值的鲁棒性较差。

通过添加更多的异常值,我们可以得到更远的分布:

evaluate_metrics(data, num_outliers = 10, amplitude_outliers = 2)

作者图片

振幅也起着重要的作用,所以我们可以回到有两个异常值,但振幅较高的情况

evaluate_metrics(data, num_outliers = 2, amplitude_outliers = 10)

在这种情况下,由于 MSE 和 RMSE 受高强度异常值的影响更大,因此对它们的分离甚至更差:

作者图片

总之,现在已经清楚了异常值对 MSE 或 RMSE 等*方误差的影响,重要的是要说明,在没有噪声的应用中,这些指标利大于弊,因为它们可以最小化更大的误差,即使这意味着接受更频繁、更小的误差。

查看本文的 github 资源库:

https://github.com/vinyluis/Articles/tree/main/Comparing robustness of MAE MSE and RMSE

如果你喜欢这个帖子…

支持我一杯咖啡!

给我买杯咖啡!

看看这个很棒的帖子

</5-tips-to-start-a-career-in-data-211ad15a7ca8>

用 Kolmogorov-Smirnov (KS)检验比较样本分布

原文:https://towardsdatascience.com/comparing-sample-distributions-with-the-kolmogorov-smirnov-ks-test-a2292ad6fee5

如何使用 python 比较样本并了解它们是否来自同一个发行版

杨致远原创于 Unsplash

假设您有两组来自传感器的读数,您想知道它们是否来自同一种机器。你如何比较这些分布?

简单的回答是:您可以使用两样本 Kolmogorov-Smirnov (KS)检验,本文将带您完成这个过程。

比较分布

在统计学中,我们经常需要了解给定的样本是否来自特定的分布,最常见的是正态(或高斯)分布。为此,我们有所谓的正态性检验,如夏皮罗-维尔克、安德森-达林或柯尔莫哥洛夫-斯米尔诺夫检验。

它们都衡量样本来自正态分布的可能性,并有相关的 p 值来支持这种衡量。

然而,Kolmogorov-Smirnov 检验更进一步,允许我们比较两个样本,并告诉我们它们来自同一分布的可能性。这个测试对于评估回归和分类模型非常有用,这将在后面解释。

科尔莫戈罗夫-斯米尔诺夫试验(KS)

简单地说,我们可以将双样本检验的 KS 统计量定义为每个样本的 CDF(累积分布函数)之间的最大距离。

KS 测试。图片作者。

在上图中,蓝线代表样本 1 的 CDF(【F1(x)),绿线代表样本 2 的 CDF(【F2(x))。Kolmogorov-Smirnov 统计量 D 由下式给出

n 作为样本 1 的观察次数, m 作为样本 2 的观察次数。然后,我们将 KS 统计量与各自的 KS 分布进行比较,以获得测试的 p 值。

KS 分布。图片作者。

双样本检验的 KS 分布取决于参数 en ,可以很容易地用表达式计算出来

累积分布函数

好吧,这个测试和其他统计测试很相似。但是为了计算 KS 统计量,我们首先需要计算每个样本的 CDF。

函数 cdf(sample,x) 简单来说就是样本上低于 x 的观测值的百分比。对于给定的值 x ,我们可以用一个简单的算法来计算任何样本的 CDF:

  • 对样品进行分类
  • 统计样本中有多少观察值小于或等于 x
  • 除以样本的观察总数

或者使用等效的 python 代码:

评估正态性(单样本检验)

正如我之前所说,KS 检验主要用于检查样本是否正态分布。我们可以使用 KS“单样本”测试来做这件事。

scipy.stats库有一个 ks_1samp 函数可以为我们完成这项工作,但是出于学习的目的,我将从头开始构建一个测试。这方面的代码可以在 my github 上找到,所以可以跳过这一部分。

https://github.com/vinyluis/Articles/tree/main/Kolmogorov-Smirnov

为了构建评估 KS 1 样本正态性检验的ks_norm(sample)函数,我们首先需要计算 KS 统计量,将样本的 CDF 与正态分布的 CDF 进行比较(均值= 0,方差= 1)。然后我们可以通过使用 KS 分布的生存函数scipy.stats.kstwo.sf【3】来计算n = len(sample)的 KS 分布的 p 值:

像这样简单。

现在我们需要一些样本来测试它:

# Create random samples
norm_a = np.random.normal(loc = 0, scale = 1, size = 500)
norm_b = np.random.normal(loc = 0.1, scale = 1, size = 500)
norm_c = np.random.normal(loc = 3, scale = 1, size = 500)
f_a = np.random.f(dfnum = 5, dfden  = 10, size = 500)

示例的样本。图片作者。

样本norm_anorm_b来自正态分布,非常相似。样本norm_c也来自正态分布,但是均值更高。f_a样本来自 f 分布。

重要的是在测试前标准化样本,否则具有不同*均值和/或变化的正态分布(如norm_c)将无法通过测试。我们现在可以对它们的正态性进行 KS 检验:

# Performs the KS normality test in the samples
ks_norm_a = ks_norm(standardize(norm_a))
ks_norm_b = ks_norm(standardize(norm_b))
ks_norm_c = ks_norm(standardize(norm_c))
ks_f_a = ks_norm(standardize(f_a))# Prints the result
print(f"norm_a: ks = {ks_norm_a['ks_stat']:.4f} (p-value = {ks_norm_a['p_value']:.3e}, is normal = {ks_norm_a['p_value'] > 0.05})")
print(f"norm_b: ks = {ks_norm_b['ks_stat']:.4f} (p-value = {ks_norm_b['p_value']:.3e}, is normal = {ks_norm_b['p_value'] > 0.05})")
print(f"norm_c: ks = {ks_norm_c['ks_stat']:.4f} (p-value = {ks_norm_c['p_value']:.3e}, is normal = {ks_norm_c['p_value'] > 0.05})")
print(f"f_a: ks = {ks_f_a['ks_stat']:.4f} (p-value = {ks_f_a['p_value']:.3e}, is normal = {ks_f_a['p_value'] > 0.05})")

结果是:

norm_a: ks = 0.0252 (p-value = 9.003e-01, is normal = True)
norm_b: ks = 0.0324 (p-value = 6.574e-01, is normal = True)
norm_c: ks = 0.0333 (p-value = 6.225e-01, is normal = True)
f_a: ks = 0.1538 (p-value = 8.548e-11, is normal = False)

我们比较 p 值和显著性。如果 p < 0.05 我们拒绝零假设,假设样本不来自正态分布,就像f_a发生的那样。所有其他三个样本被认为是正常的,正如预期的那样。

如前所述,使用scipy.stats.ks_1samp()函数可以获得相同的结果:

# Evaluates the KS test
ks_norm_a = stats.ks_1samp(x = standardize(norm_a), cdf = stats.norm.cdf)
ks_norm_b = stats.ks_1samp(x = standardize(norm_b), cdf = stats.norm.cdf)
ks_norm_c = stats.ks_1samp(x = standardize(norm_c), cdf = stats.norm.cdf)
ks_f_a = stats.ks_1samp(x = standardize(f_a), cdf = stats.norm.cdf)

比较两个样本(双样本测试)

双样本 KS 检验允许我们比较任意两个给定的样本,并检查它们是否来自相同的分布。

它在三个主要方面不同于单样本测试:

  • 我们需要计算两种分布的 CDF
  • KS 分布使用参数 en ,该参数涉及两个样本中的观察次数。
  • 如果我们想知道样本的分布是否相同,就不应该对样本进行标准化。

很容易将前面的代码用于双样本 KS 测试:

我们可以评估所有可能的样本对:

输出是:

norm_a vs norm_b: ks = 0.0680 (p-value = 1.891e-01, are equal = True)
norm_a vs norm_c: ks = 0.8640 (p-value = 1.169e-216, are equal = False)
norm_a vs f_a: ks = 0.5720 (p-value = 6.293e-78, are equal = False)
norm_b vs norm_c: ks = 0.8680 (p-value = 5.772e-220, are equal = False)
norm_b vs f_a: ks = 0.5160 (p-value = 2.293e-62, are equal = False)
norm_c vs f_a: ks = 0.6580 (p-value = 1.128e-106, are equal = False)

正如预期的那样,只有样本norm_anorm_b可以从相同的分布中取样,以达到 5%的显著性。我们不能认为所有其他对的分布都是相等的。

Scipy

出于教学目的,我已经详细介绍了 KS 测试,但是这两个测试都可以通过使用 python 上的 scipy 模块轻松执行。

使用 scipy.stats.ks_1samp 函数可以进行单样本(正态)测试,使用 scipy.stats.ks_2samp 函数可以进行双样本测试。看看吧!

结论

现在您有了一个比较分布的新工具。KS 真的很有用,而且由于嵌入在 scipy 上,也很好用。

KS 测试对于评估分类模型也是相当有用的,我将在以后的文章中展示我们如何做到这一点。

如果你喜欢这个帖子…

支持我一杯咖啡!

给我买杯咖啡!

看看这个很棒的帖子

参考

[1] Scipy Api 参考。 scipy.stats.ks_2samp。

[2] Scipy Api 参考。 scipy.stats.ks_1samp。

[3] Scipy Api 参考。 scipy.stats.kstwo

比较无与伦比的| 3D 数据可视化

原文:https://towardsdatascience.com/comparing-the-incomparable-3d-data-visualization-69980d64e2d2

一个网络工具,可以显示非常不同的数字

你很少看到数据可视化比较数字从遥远的数量级。当然,这有一个很好的理由:如果一个数字在另一个数字旁边缩小,它可能不会占据足够的空间来具有任何视觉意义。也就是说,我们可以从巩固相距甚远的数字之间的关系中获得很多洞察力。出于这个原因,我已经开始尝试三维数据可视化,以显示相距太远而无法在二维空间中读取的相对数字。

我写这篇文章有两个目标。我想提供一个快速的工具来直观地比较相差几个数量级的数字。我还想鼓励非传统的数据可视化方法,而不仅仅是一个噱头。从不同的角度看数字,我们可以用新的方式理解它们。

这种方法有一些限制。三维的量比 2D 的量更神秘。如果你把一个罐子里的糖果倒出来,铺在桌子上,估计里面的糖果数量就容易多了。通过将信息放入三维空间,我在折叠它,但我也允许更多的信息同时出现在同一个地方。(把你的糖果放在罐子里会更有效率。)此外,尽管在屏幕上花了很多时间,我们还是以三维的方式感知世界。我们对三维空间的日常理解赋予了图像具体的意义。

净值

这个项目的灵感来自两年前流行的两个引人注目的数据可视化。他们以两种不同的、意想不到的方式展示了同样的信息。一幅是汉弗莱·杨的《抖音》,画中显示,如果一粒大米代表 10 万美元,那么杰夫·贝索斯的财富就相当于 58 磅。另一个是马特·科罗斯托夫(Matt Korostoff)的互动可视化,只有长时间滚动,你才能看到贝佐斯的巨大净资产(这是 3D 的一种替代方式,允许你显示非常不同的数量)。这两种想象都向我展示了财富不*等——一个我已经意识到的问题——比我想象的还要严重。这些图片让我将极度财富的规模概念化。

埃隆·马斯克的净资产,2670 亿美元,2022 年 8 月 16 日;2019 年美国家庭净资产中值为 121,760 美元。来源:彭博新闻,美联储

因为埃隆·马斯克已经取代杰夫·贝索斯成为世界首富,所以我把他的净资产想象成了现实。

p 值

我已经可视化了两个 p 值阈值的统计显著性。创建这个图像帮助我更好地理解这些阈值意味着什么。p 值表示在测试数据集中的变量时,零假设(变量没有统计显著相关性的假设)的概率。足够低的 p 值使您能够宣布关系具有统计显著性,这里我们可以看到深蓝色和浅蓝色两个阈值具有统计显著性。0.05 是典型的标准(深蓝色),0.005 是更严格的阈值(浅蓝色)。

在这些图像中,较小的数量嵌套在较大的数量中。对于 p 值示例,这种技术并不罕见,因为 p 值是概率的一个分数表达式。以嵌套形式显示相加为整体的部分是很常见的,比如在饼图中。更不寻常的是,p<=0.005 is imaged as a chunk taken out of p<=0.05. I have chosen to work this way for a couple of reasons. In these visualizations, the smaller numbers are small enough relatively that the “bites” taken from their larger neighbors aren’t all that substantial. In addition, this technique allows the small figures to appear closer and for all information to stack neatly into a single prism.

Population

As a way of considering where Americans stand in our larger global context, I’ve made this visualization of U.S. population as nested in to the total world population.

2019 Populations: United States Population, 332 million; World Population, 7.84 billion. Source: World Bank

Because my approach is unusual, and I’m comfortable with the library, I’ve used Babylon . js写出这些可视化效果。这是一个为 3D 艺术制作的 JavaScript 库。虽然它没有像 D3.js 这样的数据专用库那样多的现成数据 viz 功能,但它很灵活,并且是空间数字驱动的。通过一些努力和创造性,巴比伦可以用来显示数据。

数量级|视觉参考

在我的最后一个例子中,我使用了同样的技术来显示连续的数量级(10 的幂)。这个示例包含一些交互性,欢迎您点击查看代码。当您比较相差几个数量级的值时,此示例可用作快速参考。如果您没有时间为一组特定的数字创建可视化效果,您仍然可以通过对照该可视化效果检查每个数字的 10 次方来获得一个大概的参考。

自己做

我在这个链接上创建了一个资源,这样您就可以创建自己的三维数据可视化来比较两个值。如果您正在进行一个数据科学项目,希望比较两个相距甚远的数字,这个资源可能会对您有用。下面,我详细介绍了一个如何使用这个工具的例子。请注意,它在台式机或笔记本电脑的网络浏览器中效果最佳。

利用美国人口普查局最*的数据,我估计在北卡罗莱纳州有 9868 名自我认同的跨性别者。根据人口普查局最*的家庭脉动调查,它是美国邻*地区跨性别人口比例最小的州。如果我使用 Matplotlib 创建一个跨性别人口与该州 1039 万总人口的条形图,跨性别人口会变得非常小。你实际上看不到它。

了解不同的人口统计群体在人口中所占的百分比是很重要的,同时,在图表上隐藏一个小群体可能是有害的。例如,当涉及到政策制定时,即使是小团体也得到了发展壮大所需要的代表和资源,这一点很重要。当一个群体处于系统性劣势时,这一问题尤为紧迫。

正如你在下面看到的,如果我使用 3D 方法,北卡罗来纳州的跨性别人口就变得可见了。要使用这个在线工具,我只需将导航到链接,点击每个数字字段来修改它。然后,我通过点击和输入标签字段来添加标签。作为一个半隐藏的临时演员,我还可以更改标题。可视化完成后,您可以截图。您可以使用自己选择的设计软件进行进一步的编辑。

资料来源:家庭脉搏调查,第 3.5 阶段(2022 年),美国社区调查,5 年数据(2020 年)

当我第一次开始编写驱动本文的代码时,我尝试了几种不同的设计策略来查看不同的数字。除了 3D 之外,我还尝试创建二维甚至一维的参考,它们会随着时间的推移而动画化。我最终专注于 3D,因为它方便紧凑。(上面唯一需要动画的可视化是数量级参考,这是因为这些数字跨越了十个数量级。)整个过程让我意识到,即使是同样的数量,看起来也会有所不同,这取决于你如何对待它。这种探索让我们对数据有了新的了解。

除特别注明外,所有图片均为作者所有。

比较事物:贝叶斯方法

原文:https://towardsdatascience.com/comparing-things-the-bayesian-approach-b9a26ddb5ef1

如何进行包含不确定性的概率比较

比较东西很难。当比较所依据的信息只是部分的或不确定的时候,情况更是如此。当心那些提供单一数字的人,他们声称,这些数字利用并抓住了所有的不确定性。幸运的是,贝氏帮你搞定了。让我们在回答一个重要问题时,看看如何进行适当的概率比较:哪个国家有最好的国家足球队?

评级团队

一种流行的对运动队或个人运动员进行评级的方法是所谓的 ELO 评级系统,由 Arpad Elo 博士开发。它最初是用来给国际象棋选手排名的,但现在已经成功应用于其他领域,包括足球。

ELO 系统给每个队分配一定的分数。积分越多,球队越好。每次两队比赛时,他们根据一个简单的公式交换分数。您可以在 eloratings 网站上找到更多详细信息。简而言之,赢的队得到奖励分,而输的队失去分。被交易的点数取决于对立球队之间的初始分差、比赛结果中的净胜球、比赛的赌注以及哪支球队在主场比赛。

ELO 系统的一个方便的数学属性是,基于两个队的评级,我们可以计算出如果他们现在比赛,他们中的每一个赢另一个的概率。我已经用这个属性在模拟了 2020 年欧洲杯小组赛,对哪支球队进一步晋级的预测证明是相当准确的。

在撰写本文时,根据 ELO 排名,前两个国家队是巴西队和法国队,分别获得 2155 分和 2116 分。巴西排名更高,他们战胜法国的概率由下式给出

返回 0.56 或 56%。这是假设他们在中立场地比赛,即任何一方都没有主队优势。

太好了。但是这 56%真的意味着目前巴西是更好的球队吗?我们能有多确定?

评级系统的不足之处

像 ELO 这样的评级系统有两个主要问题。首先,他们仅仅基于比赛结果,而忽略了所有其他可用的信息。第二,他们毫无保留地依赖于对团队质量的点估计。让我们看看我说的这些是什么意思。在这最后的足球部分,请耐心听我说——我们现在要讨论的也适用于所有其他类型的比较!

忽略数据中没有的内容

虽然过去的比赛是球队未来表现的可靠预测,但它们并不能解释球场外发生的事情。

根据 transfermarkt.com 的说法,两名法国球员(保罗·博格巴和恩戈洛·坎特)在撰写本文时受伤。这两名球员对球队至关重要,他们每人至少 5000 万€的市值反映了这一点。他们可能为球队过去的良好表现做出了贡献,但无法在即将到来的比赛中有所帮助。在巴西方面,预计没有主要球员会错过下一场比赛。

这一观察有两个结果:首先,我们不太确定法国的 ELO 评分,因为它是在受伤发生之前就已经确定的。第二,由于这两名球员的缺席,我们可以预计法国队的获胜机会将会减少。

依靠点估计

我们之前说过,ELO 系统依赖于对团队质量的点估计。这意味着一个团队的技术和形式的所有复杂性被简化为一个单一的数字,ELO 分数。如果一个队由于运气赢得了最后一场比赛,他们的得分将与他们输了的情况不同,即使他们的实际技能在两种情况下是相同的。

比较事物需要什么

因此,我们得出了在进行比较时需要考虑的三个关键因素,无论是在足球还是其他领域。

  • 首先,我们需要能够表达我们用于比较的测量的不确定性(在这些伤害之后,ELO 评分仍然准确吗?).
  • 其次,我们需要能够根据我们的外部知识随意改变衡量标准(看起来法国队在两名重要球员缺阵的情况下获胜的机会更小)。
  • 第三,我们需要一种比单个数字更好的方法来获取我们用来进行比较的指标(单个数字的指标会受到随机性的影响)。

为了进行适当的比较,我们需要一个能够捕捉不确定性的指标,我们可以根据外部知识进行转换,并且这不是一个单一的数字。

我们如何进行满足这三个要求的比较?进入贝叶斯!

走向贝叶斯

贝叶斯统计中,我们分析的所有变量都是用概率分布来描述的,而不是单一的数字。在我们的案例中,2116 这个数字无论如何也无法描述法国国家队的所有技术、状态和动力。但是我们可以指定一个围绕这个数字的分布,它会做得更好。

不过,让我们从巴西开始吧。对于这支队伍,我们对他们的评级没有太大的异议,也许除了这样一个事实,那就是围绕它肯定有一些不确定性。让我们假设他们的评级可以用正态分布来描述,均值等于 2155,巴西的 ELO 评级,标准偏差为 20,以反映他们的真实技能实际上可能更低或更高。

现在回到法国。我们需要他们的 ELO 得分分布在两个方面与巴西不同:

  • 首先,它应该更宽泛,以反映法国评级的不确定性。
  • 第二,它应该稍微倾斜,以反映在缺乏关键参与者的情况下,他们实际上更有可能比 2116 更低而不是更高的评级。

为了实现这两个效果,让我们用一个偏态正态分布来描述法国分数,其均值为 2116,标准差为 40,偏态参数设置为 3。

我们可以从两个团队的评级分布中抽取许多值,并绘制它们的密度图,以查看它们之间的比较情况。

各队之前的排名分布。图片由作者提供。

看起来我们达到了我们想要的。我们刚刚定义的两个分布在贝叶斯术语中被称为先验分布,因为我们是在观察两个队相互比赛之前提出它们的。

让我们来画出两队排名的联合分布。这显示了每对可能得分的概率。我们可以看到,非零概率的斑点向下倾斜到法国的较低评级,并且纵向拉伸程度大于横向拉伸程度(请注意轴的比例略有不同)。

各队的联合排名分布。图片由作者提供。

我们现在可以使用我们的先验分布来推导巴西赢得比赛的概率。这归结为简单地检查巴西的排名高于法国的频率:(b_sample > f_sample).mean()返回 0.63,即 63%。这高于我们之前的 56%,反映了我们对法国分数的主观不确定性。

贝叶斯方法允许我们将关于世界的外部知识注入到统计分析中,以使其更加准确。

请注意我们是如何将我们关于世界的外部知识注入到统计分析中,以使其更加准确。但是贝叶斯方法最好的事情还在后面:我们如何基于数据进化我们先前的信念!

让你的信念进化

我们现在站在这样的立场上,巴西现在更有可能成为一支更好的球队,如果他们现在互相比赛,有 63%的机会赢下 Frace。想象一下,他们做到了,法国赢了。这是否意味着我们错了?法国队真的是一支更好的球队吗?还是这一个游戏没有足够强的证据来这么宣称?贝叶斯框架给出了所有的答案!

然而,为了得到它们,我们需要对概率分布进行一些计算。我们之前所做的先验抽样对于估计获胜几率已经足够好了,但是现在我们需要一个更严格的方法。让我们从重新计算我们的前科开始。

我们将使用 empiricaldist 包来做这件事。这是一个建立在熊猫基础上的很好的小工具,可以很容易地定义和计算概率分布。首先,我们需要提供分布的分位数,也就是可能的评级值。*均正负 100 应该够好了。然后,对于每个评级值,我们根据我们选择的先验分布计算确切的概率:巴西为正态分布,法国为偏态分布。最后,我们对结果进行归一化,以确保概率总和为 1,就像它们在分布中一样。

基于这些,我们可以重新绘制之前的联合概率图。这一次,我们将把它建立在概率网格的基础上。这是一个数据框,其中列表示巴西可能的评级值,行索引表示法国的评级,单元格保存相应评级对的概率。

各队的联合排名分布。图片由作者提供。

你可以自己验证一下,结果的剧情和之前的是一样的。但是这种呈现数据的方式让我们可以进行有趣的计算。

再一次,想象法国赢了巴西。对于每一对可能的分数,出现这种结果的可能性有多大?这个答案叫做可能性。这是观察结果的概率,在这种情况下,法国队获胜,这是两队排名分数的所有可能组合。让我们计算并绘制它!

请注意我们在将 XY 传递给 get_p_win 函数时是如何交换它们的。这是因为法国队是赢家,其得分存储在 Y 变量中,上述函数计算得分作为第一个参数传递的球队赢第二个参数的概率。这是结果图。

法国赢巴西的可能性。图片由作者提供。

不出所料,当法国的评级高而巴西的评级低时(左上角),法国获胜的可能性最大。但是这种结合的可能性相当小——见上文。那么,我们如何将我们之前对每支球队评级的信念与法国的意外胜利结合起来呢?

我们简单地将先验与可能性相乘,并再次归一化,以得到后验分布,它反映了我们在观看比赛后对收视率的看法。

各队的联合后验排名分布。图片由作者提供。

这种分配应该更有利于法国。由于通过查看两个独立的图并不能清楚地看到这一点,所以让我们想象一下先验和后验之间的区别。

后关节和前关节的区别。图片由作者提供。

白色区域是先验概率高于后验概率的地方,深蓝色区域是后验概率较高的地方。现在很明显,我们对巴西评级的信心下降了,而对法国的信心上升了。但这是否意味着我们不再认为巴西是一支更好的球队?让我们再次通过计算巴西队获胜的概率来找出答案,他们是否应该再次比赛。

这将返回 0.53,即 53%。法国队赢得我们想象中的比赛是一个不太可能的结果,但这并不足以让我们相信他们是更好的球队。总的来说,我们仍然认为袖手旁观巴西是目前的顶级足球国家队,尽管他们的优势并不大!

感谢阅读!如果你对如何更严格地将贝叶斯思维应用于统计数据分析感兴趣,请查看我关于主题的介绍性文章。要了解贝叶斯思维如何帮助我们更好地理解日常生活问题,请查看这篇文章

另外,可以随意看看我在 DataCamp 上教的 Python 课程中的 贝叶斯数据分析。它从最基本的概率开始,通过贝叶斯 A/B 测试和决策分析逐步发展到更高级的主题,如用马尔可夫链蒙特卡罗模拟方法拟合和评估贝叶斯回归模型。

如果你喜欢这篇文章,为什么不订阅电子邮件更新我的新文章呢?并且通过 成为媒介会员 ,可以支持我的写作,获得其他作者和我自己的所有故事的无限访问权限。

需要咨询?你可以问我任何事情,也可以在这里为我预约 1:1http://hiretheauthor.com/michal

你也可以试试我的另一篇文章。不能选择?从这些中选择一个:

** [## 贝叶斯数据分析最温和的介绍

towardsdatascience.com](/the-gentlest-of-introductions-to-bayesian-data-analysis-74df448da25) **

比较美国总统的第一年

原文:https://towardsdatascience.com/comparing-u-s-presidents-first-years-eefecb30a3d5

可视化新闻情绪,最常见的词,布什,奥巴马,特朗普和拜登的支持率

作者创建的 Tableau 仪表板

在这个项目的第一部分 中,我用 tensorflow 创建了一个情感分析的模型。我用这个模型对过去四位美国总统执政第一年的新闻文章摘要进行了情感分析。文章摘要通过《纽约时报》的 API 获得。在第二部分,我用 Tableau 形象化了这个分析的结果。我还列出了每位总统每个月最常用的十个单词。最后,我将盖洛普****https://news.gallup.com/home.aspx的总统支持率包括在内,看看新闻情绪如何与公众支持率相关(或背离)。***

最终的结果就是这个Tableau Dashboard

你可以看看这个 jupyter 笔记本 来看看我到底是如何使用 python 库 nltk 来提取每个总统/月份组合的十个最常见的单词,忽略像‘the’、‘and’、‘he’等停用词的。注意,首先需要加载president _ df _ final . JSON,这是本项目part 1**的输出文件之一。**

总体情绪/认可

总统对新闻的正面评价(总体提及和直接提及)和支持率(作者图片)

在上图中,有几件事很突出。首先,所有的消息都是坏消息。对所有总统来说,*均整体新闻情绪只有 25-35%是正面的。说到半空的杯子!第二个观察,包含奥巴马名字(直接提及)的新闻摘要非常正面——大约 65%!最后的观察——布什的*均支持率非常高。稍后将变得清楚的是,这主要是由于 911 袭击后他的支持率大幅上升。

最常见的单词

所有总统

历届总统第一年最常使用的词汇(图片由作者提供)

在所有总统的第一年,有些词很突出。阿富汗,塔利班,军事,战争,中国,冠状病毒,本拉登等。都出现在大量的摘要中。布什是第四个被提及最多的词,这意味着他的名字在第一年被直接提及了很多次。当我们按总统筛选时,这个图表变得更加有趣。比如,我们来比较一下特朗普和拜登的第一年。

法宝

特朗普第一年最常用的词(图片由作者提供)

当过滤特朗普时,我们看到特朗普第一年的最大新闻显然是特朗普。然而,当我们过滤拜登的时候,他的名字几乎没有出现在我们的视野中(右下方)。他的第一年完全被新冠肺炎占据了。

拜登(姓氏)

拜登第一年最常用的词(图片由作者提供)

每月趋势

按总裁划分的月度趋势(图片由作者提供)

在上图中,我们可以看到每位总统的以下月度趋势:总体新闻情绪、直接提及新闻情绪和支持率。我们再次看到,所有总统的总体新闻情绪都是负面的。全年直接提及对奥巴马非常有利。考虑到 NYT 的左倾,特朗普的支持率也高得惊人。最后,我们可以看到布什的支持率从 9 月份开始飙升,这解释了我们之前看到的非常高的*均支持率。

从 9 月到 12 月对布什的直接新闻情绪与支持率之间的差异来看,直接提到总统可能是非常负面的,因为世界上发生的事件,而不一定是因为新闻机构的政治倾向。《纽约时报》在 9/11 之后的日子里可能不会说布什总统的坏话,但新闻内容是极其负面的,而且他的名字碰巧被涉及到。相反也可能是真的,这可以解释为什么直接提到特朗普是非常积极的。这并不是说 NYT 在为他唱赞歌,但也许 2017 年的世界只是处于相当不错的状态。鉴于 2001 年发生了 9/11,2009 年发生了大衰退,2021 年发生了全球性的疫情,也许 2017 年还不算太糟糕。

支持率与直接新闻情绪

每位总统的支持率(+)与直接新闻情绪(直线)(图片由作者提供)

以上,我们对每位总统的月度支持率和直接新闻情绪进行了直接对比。这里有几件事很突出。首先,有时坏消息有利于总统批准。9/11 袭击后的布什显然就是这种情况,当时整个国家团结起来,爱国主义高涨。尽管新闻非常明显是负面的(包含布什名字的新闻摘要从 9 月到 12 月只有大约 20%是正面的),他的支持率还是直线上升。如果我们过滤布什和 9 月,我们会看到下面的前 10 个词,都与袭击有关。

布什,九月

布什上任第一年 9 月最常使用的词汇(图片由作者提供)

有点讽刺的是,我们可以看到完全相反的情况发生在拜登第一年的 8 月。虽然最常见的词非常相似,但它们对他的支持率产生了相反的影响。9/11 事件 20 年后,美国狼狈地从阿富汗撤军,导致了负面的直接新闻情绪(8 月和 9 月约有 20%的正面消息),但拜登受到了指责。他的支持率从 8 月份的 49 下降到 9 月份的 43,并在今年剩下的时间里保持稳定。在这种情况下,坏消息情绪对总统批准来说是坏消息。

拜登,奥古斯特

拜登上任第一年八月最常用的词(图片由作者提供)

结论

对于从事项目工作的人来说,项目中最令人满意的部分通常是让代码正确运行,构建一个按预期工作的模型,等等。然而,如果没有结果可以显示,代码正常运行或模型按预期工作就没有意义。这就是为什么我推动自己构建项目的第一部分,并在 Tableau 中可视化结果(使用一些额外的、易于获取的数据)。

探索仪表板格式的数据真的很有趣。它允许我进一步深入数据中的低谷和高峰。最常见的词汇让我更好地理解了在特定时间哪些话题在推动国家叙事。将数据可视化可以让某些趋势变得清晰,这是熊猫的数据框架所做不到的。

总之,如果我没有将结果可视化,我的项目就不会完成。我很高兴我强迫自己写下并发表了这篇文章!我希望你很高兴你读了它:)

*参考文献

盖洛普公司《总统支持率——乔·拜登》Gallup.com,2021 年 2 月 5 日,news . Gallup . com/poll/329384/president-approval-ratings-Joe-Biden . aspx**

盖洛普公司《总统支持率——唐纳德·特朗普》【Gallup.com】2016 年 11 月 16 日,news . Gallup . com/poll/203198/president-approval-ratings-Donald-trump . aspx

盖洛普公司《总统支持率——巴拉克·奥巴马》Gallup.com,2016 年 4 月 21 日news . Gallup . com/poll/116479/Barack-Obama-presidential-job-approval . aspx**

盖洛普公司《总统支持率——乔治·w·布什》Gallup.com,2013 年 6 月 11 日,news . Gallup . com/poll/116500/president-approval-ratings-George-bush . aspx**

ArcGIS Dashboard、Tableau Dashboard 和 R Flexdashboard 的比较

原文:https://towardsdatascience.com/comparison-between-arcgis-dashboard-tableau-dashboard-and-r-flexdashboard-86604cd125d1

为数据分析项目选择正确的工具

卢卡斯·布拉塞克在 Unsplash 上的照片

仪表板提供增强的数据可见性,并帮助企业获得更深入的见解。然而,市场上充斥着许多可以用来创建仪表板的工具和软件。作为一名数据科学家,选择正确的数据可视化工具可能是一项艰巨的任务,因为大多数*台都提供类似的核心功能,但每个*台都专注于特定的业务用例。为您的组织选择正确的工具对于其长期成功至关重要,尤其是因为在项目中期很难更改数据分析的核心组件。在本文中,我将讨论三种工具,即 ArcGIS Dashboards、Tableau Dashboards 和 R Flexdashboards,并讨论它们的优缺点,以帮助您的组织更轻松地实现可视化目标。

ArcGIS 仪表盘

最*,在新冠肺炎疫情启动期间,ArcGIS 因其公共报告用途而广受欢迎。这些新冠肺炎仪表板中最著名的是约翰·霍普斯金大学冠状病毒资源中心仪表板。该仪表盘是使用 ArcGIS 仪表盘创建的,并由 ESRI 的 Living Atlas 团队提供支持。《时代》杂志甚至将约翰霍普金斯大学冠状病毒资源中心列入其 2020 年最佳发明名单,成为疫情全球和区域传播的首选数据源。许多其他州和政府机构也创建了类似的仪表板,以努力传播对该病毒的认识和透明度。ArcGIS 不仅可用于新冠肺炎报告。它在许多商业和专业环境中有着广泛的用途。

ArcGIS Dashboard 是环境系统研究所(ESRI)的产品。据 ARC 咨询集团称,ESRI 是地理信息系统(GIS)的领导者,控制着该领域约 43%的全球市场份额。图 1 显示了我使用 ArcGIS Online 应用程序创建的 ArcGIS 仪表盘示例。此示例代表了 ArcGIS Dashboard 的一般布局和美学属性。

图 ArcGIS 仪表盘示例。图片作者。

如果空间信息(纬度和经度)是数据集的重要组成部分,并且您需要定期计算地理统计数据,那么 ArcGIS dashboard 将是一个值得考虑的便捷工具。ArcGIS 通过工具箱提供统计分析工具,如 Moran's I 索引工具和空间聚类分析工具,无需编写大量代码即可访问这些工具。还可以对空间数据进行高级业务和网络分析。该仪表盘产品可与其他 ESRI 产品(如 ArcMap、ArcGIS Story Maps 和 ArcGIS Online)轻松集成,从而使数据驱动的故事讲述变得更加个性化和有效。同样,如果您需要在空间数据表示中具有高度的准确性和精确性,ESRI 产品是这一领域的冠军。ArcGIS 可以有效地处理矢量和栅格数据,您可以在 ArcGIS 环境中轻松地将一种数据类型转换为另一种数据类型。ESRI 还提供 ArcGIS online,您可以在其中为利益相关方发布仪表盘。

但是,ArcGIS 许可可能非常昂贵,可能不适合小型企业。ArcGIS 中的大多数功能都可以通过点击式界面来访问,但对于初学者来说,学习曲线可能会很陡。新用户将不得不学习许多关于如何在地球表面上表示空间栅格和矢量数据的新概念,而更高级的概念,如三角不规则网络或空间统计,可能需要大量的时间来学习。使用地理坐标系和投影坐标系投影数据对于来自非空间背景的新用户来说也是一个挑战。

在撰写本文时,ESRI 提供的仪表板布局选项非常少,而且很难改变仪表板的美观。为此,ESRI 引入了 ArcGIS Arcade,一种轻量级表达式语言。然而,这种语言摒弃了简单的点击式用户界面,这种界面使得大多数初学者能够直观地创建仪表板。类似地,仪表板中只有少数几种图表类型可用,制作雷达图等复杂的图表可能具有挑战性。因此,ESRI 的 dashboard 产品可能不太适合希望创建专门可视化的组织,尤其是在涉及有限空间数据的情况下。ArcGIS dashboard 最适合于空间数据科学家、土地使用规划者以及需要在日常工作中不断进行位置分析的企业和政府机构。

Tableau 仪表盘

Tableau 是数据可视化和商业智能领域的领导者之一。Tableau 最初是在斯坦福大学开发的,后来作为一家私人公司进入市场。该公司于 2019 年被 Salesforce 收购。根据 Slintel 的数据,Tableau 在商业智能领域拥有大约 17.09%的市场份额,其客户遍布全球 166 个国家。图 2 显示了 Tableau 仪表板的一个例子。

图 2:在 Tableau 中创建的仪表板示例。图片作者。

Tableau 帮助用户快速创建交互式可视化。该软件在幕后处理大部分腿部工作,并提供简单的布局,可以配置为制作图表和图形。与其他工具相比,Tableau 易于学习,因为大多数可视化工作可以通过使用简单的拖放界面来完成。Tableau 仪表板可用于使数据讲述个性化和有效,因为可以用最少的代码创建自定义可视化。即使需要编码,这种语言也类似于 SQL,已经被多个行业的许多数据专业人员使用。Tableau 还可以用来可视化空间数据。它可以识别 ESRI 的 shapefile 格式,以及 KML 和 GeoJason 格式来显示地理单位,如县、州或国家。用户还可以将 Mapbox 地图添加到他们的仪表板中,这使得进行位置分析工作更加容易和快速。可以轻松过滤或调整地形或海岸线等地图图层属性。同样,该软件可以连接到许多数据库,如 MySQL 和 Teradata,并可以有效地处理大量数据。作为一名从业者,你也可以在 Tableau Server 或 Tableau Public 中为你的利益相关者分享和发布你的结果,使他们更容易访问你的发现。

要在 Tableau 中进行可视化,您的组织需要购买许可。幸运的是,这个许可比 ArcGIS 便宜。如果成本仍然是一个问题,可以在 Tableau Public 中创建和发布您的仪表板,这是免费的。尽管 Tableau 在可视化空间数据的能力方面有所发展,但它仍然落后于竞争对手,尤其是与 ESRI 相比。如果您有纬度和经度格式的数据,您可以快速可视化和绘制见解,但是,在进行任何空间分析时必须小心谨慎。空间分析过程(如空间裁剪)在 Tableau 中也不可用。Tableau 也不擅长导入光栅数据,尽管可以执行一些操作,例如导入光栅图像作为背景并识别其像素行号和列号。

对于非空间数据的可视化,Tableau 比 ArcGIS 更具优势。首先,它有各种各样的可视化效果,无需任何编码就可以创建和定制。它还具有许多独特的功能,使得数据准备和混合工作比 ArcGIS 更加简单和直观。在各行各业,Tableau 也是一种更常用的产品,由于它的广泛使用,组织可能会更容易雇用和留住人才。因此,对于需要干净快速开发可视化产品的简单直观的业务用例,Tableau 是最佳选择。

Flexdashboard

Flexdashbaord 是 R 的一个包,可以从起重机上自由安装。r 是数据科学领域中一种流行的编程语言,已经成为数据科学家在操作、可视化和分析数据时的首选工具。Flexdashboard 特别基于 R Markdown,支持 html 小部件和网格图形。

图 3:flex dashboard 的例子。图片作者。

Flexdashboard 的主要优势之一是它是开源和免费的。r 还可以有效地处理空间和非空间数据类型。RStudio 对 Flexdashboard 的支持最好,这是一个流行的 r GUI,也是免费的。r 为各种统计分析提供了大量的软件包。对于空间数据,R 有栅格sf 包,可以分别处理栅格数据和矢量数据。这些分析的结果可以导入到 Flexdashboard 中,用于仪表板目的。Flexdashboard 的美妙之处在于,它基于基于行和列的样式,使得更改仪表板的网格布局变得很容易。如果你想让你的 dashboarding 之旅变得有趣和容易,你可以使用 Tidyverse,一个在 R 中流行的包,它使用了图形原理的语法。您可以使您的统计数据,甚至您的仪表板可重复,您可以更改参数或修复错误,没有太大的麻烦。最后,您可以用 HTML 呈现仪表板,并将其附加到您的电子邮件中或嵌入到您的网站中。您还可以在 Rpubs 中发布您的仪表板,Rpubs 是一个免费的 web 发布站点。

r 是一种编程语言,它也有一个有点陡峭的学习曲线。像 ggplotgui 这样的软件包已经试图通过为初学者提供一些 gui 界面来减少这种学习曲线。同样,像 dplyr、ggplot2 这样的库也让学习 R 的旅程不那么痛苦。然而,从 Flexdashboard 创建的仪表板只是静态的。如果你需要让你的仪表盘具有交互性,你可以安装 R Shiny 包。然而,托管/发布闪亮的仪表板可能具有挑战性。你可以将你的 R Shiny 应用和仪表盘免费部署到 Shinnyapps.io 的云上,但在本文撰写之时仅限于 5 个应用。如果您想部署更多的应用程序,它们有不同的定价等级。

R 和 Flexdashboard 的天才之处在于它是免费的,任何人都可以使用,不管有没有许可证。能够整合来自 ggplot2 的独特可视化意味着它提供了比 ArcGIS 和 Tableau 更大的灵活性,但这种仪表板创建方法也因其需要用户来自编码背景而受到阻碍。

结论

本文中讨论的所有三种工具(ArcGIS、Tableau Dashboard 和 Flexdashboard)都可以帮助您的组织实现其数据可视化目标。但是,因为他们每个人都专注于自己的利基领域,所以他们可能比其他人更适合某些项目。有一些功能可用于将一个*台连接到另一个*台,例如,您可以将 Tableau 连接到 ESRI ArcGIS Server,甚至可以在 Tableau 工作流中使用 R 脚本。但是,这些跨*台连接器提供的功能有限,不建议在生产环境中使用它们。

对于一个新的组织,或者对于一个刚刚涉足商业领域的数据科学家来说,我建议从一个单一的仪表板产品开始。对于涉及空间数据的业务用例,ArcGIS 是至高无上的。为了便于创建和非空间可视化,Tableau 可能是最好的选择。另一方面,Flexdashboard 为那些有编码背景的人提供了空间和非空间能力的良好*衡。无论您为自己或您的组织选择哪种仪表板创建*台,最重要的是您要创新并找到创造性的方法来将数据传达给您的业务利益相关者。作为一名新兴的科学家,我发现学习这些工具是一个非常有益的过程,我希望你也一样。

Python 在越南卒中医疗机构地理编码服务中的应用比较

原文:https://towardsdatascience.com/comparison-of-geocoding-services-applied-to-stroke-care-facilities-in-vietnam-with-python-ff0ba753a590

Python 实践教程

仔细观察匹配率和空间精度

这部作品与 凯凯泽 迈赫迪法耶兹巴赫什 合著。所有错误和遗漏都是作者的。

塔玛斯·图兹-卡泰Unsplash 上拍摄的照片

地理编码是将文本格式的地址转换为经纬度等地理坐标的过程,文本格式是定位建筑物、地块或结构所需的信息,通常以特定格式使用,包含政治边界、街道名称、建筑编号、组织名称和邮政编码等内容。只有地址可用时进行地理编码是位置验证(例如,通过卫星叠加)和分析(例如,访问分析、气候暴露、以及任何基于空间的研究)的第一步,前提是解决方案需要了解兴趣点(例如,卫生设施、人口、学校、道路)的位置。

在健康环境中,这项任务通常是在基于空间的健康研究中进行所有操作之前执行的基本的第一步。因此,这些机构内使用的地理编码系统的质量是机构(生产者)和希望使用这些数据的研究人员或决策者(消费者)最关心的问题。然而,随着新产品不断上市,地理编码系统也在不断发展。当面临关于构建、购买或维护任何特定地理编码系统的决策时,机构必须开发和使用跨数轴的标准。

尤其是在发展中国家应用现有工具进行地理编码时,分析人员需要密切关注进行这种转换的过程和陷阱。特别是在弱寻址的设置中,这可能会导致转换中的间隙。

我们通过使用一组经过验证的越南卒中机构地址数据集来证明这一点,该数据集由世界银行驻越南团队进行人工地理编码和验证。

在这篇博客中,我们将通过 OpenStreetMap、Mapbox 和谷歌Python 中对越南中风护理机构的地址进行地理编码,并演示一种计算地理编码质量的方法文献中报告了各种衡量地理编码质量的指标。

地理编码系统质量指标(来源— 一个用于比较地理编码系统的评估框架)

在本博客中,我们将报告 匹配率 (所有能够被地理编码的记录的百分比),以及 空间精度 (可匹配地理编码和地面真实位置之间的距离的频率分布)。

我们的目标不是推荐使用其中一个,而是展示如何在不同国家的 Python 中的 Jupyter Notebook environment(JPNE)中轻松完成这样的评估。

我们在这个练习中使用的数据集是越南 106 个中风护理机构的列表,这些机构的完整地址是已知的。我们的团队还人工编制了这些位置的地面真实数据,并验证了纬度和经度。

包含越南 106 个中风护理机构的地址和地理坐标的数据框架(图片由作者提供)

1.通过 Geopy 使用 OpenStreetMaps (OSM)数据进行地理编码

Geopy 是一个 Python 客户端,使得 Python 开发者能够使用第三方地理编码器和其他数据源来定位全球各地的地址、城市、国家和地标的坐标。nomim是一个通过名称和地址搜索 OpenStreetMap 数据(地理编码)并生成 OSM 点的合成地址(反向地理编码)的工具。通过 Python 中的 geopy 客户端,可以使用 nomist 查询 OSM 数据以对地址进行地理编码,如以下代码所示-

代码执行时间为 55.4 秒,匹配率仅为 16%,这意味着在 106 个设施中,Nominatim 只能返回 17 个地址的地理编码。

使用 Geopy 进行地理编码的时间和匹配率(图片由作者提供)

为了计算空间精度,计算 Geopy 返回的地理编码与地面真值坐标之间的哈弗辛距离(球面上两点间的大圆距离)。然后,我们绘制哈弗线距离的频率分布,以可视化的空间精度。

使用 Geopy 进行地理编码的空间精度(图片由作者提供)

使用 Geopy 进行地理编码的位置地图(图片由作者提供)

Python 中的“Geocoder”库

许多在线地理编码服务提供商(尤其是 Google、HERE 和 Mapbox 等专有*台)不包含 Python 库。为了用 Python 从这些*台获取数据,我们需要使用请求和不同的 JSON 响应,而没有标准化的查询和响应模式。为了帮助克服这一挑战,并为这些*台提供一个单一的访问库,已经开发了 Geocoder 库。对于使用 Mapbox 和 Google 进行地理编码,我们将演示如何通过几行代码,使用地理编码器库查询这些服务。

2.通过地理编码器使用 Mapbox 进行地理编码

代码执行耗时 23 秒,匹配率为 73%(106 个 stroke 设施中有 77 个地址进行了地理编码)。

地图框地理编码位置和实际位置之间的哈弗线距离统计(图片由作者提供)

由于存在一些具有极值的异常值,我们将所有异常值(大于 30 公里)归入直方图的一个柱中。

地图框地理编码位置与实际位置之间距离的频率分布(图片由作者提供)

使用 Mapbox 进行地理编码的位置地图(图片由作者提供)

Mapbox 给出了不同国家的搜索结果,比如台湾和利比亚。如果我们去除这些异常值,我们可以清楚地看到越南内部的哈弗线距离分布。

使用 Mapbox 进行地理编码的位置地图(无异常值)(图片由作者提供)

3.通过地理编码器使用谷歌地理编码

代码执行时间为 1 分 12 秒,匹配率为 100%(对所有 106 个 stroke 设施进行地理编码)。

地图框地理编码位置与实际位置之间的哈弗线距离分布(图片由作者提供)

空间精度-使用 Google 进行地理编码(图片由作者提供)

用谷歌地理编码的地图(图片由作者提供)

谷歌对越南境内的所有地点进行地理编码,匹配率为 100%。只有一个位置与实际位置的误差大于 4 km。

结论

在这篇博客中,我们探索了通过 Python 使用 Geopy、Google 和 Mapbox 地理编码服务,并使用越南中风护理机构位置的手动地理编码数据集验证了结果。对于这三种服务,将计算并报告匹配率和空间精度指标。由于与这些服务相关的成本也与中低收入国家的应用密切相关,我们在下表中总结了这些指标以及与*台相关的成本-

Geopy、Mapbox 和 Google 地理编码的比较结果摘要(图片由作者提供)

我们想要重申的是,我们的目标并不是推荐使用一个而不是另一个,而是展示如何针对不同的国家环境,在 Python 中的 Jupyter Notebook environment(JPNE)中轻松完成这样的评估。

我们在部署基于云的 JPNE 流程方面积累了越来越多的经验,包括世界银行的新冠肺炎及其他地区大数据观察站(BDO)和越南公共资产治理颠覆性技术(DT4PAG)项目。通过正在进行的一系列中型博客投稿(例如, 【用 Python 可视化全球人口数据集】*【当地气候分析:越南卫生机构的雨水暴露】 ),我们将继续分享我们的经验,特别是他们如何帮助推进数据驱动的见解,以实现可持续发展目标,并推动应用技术的实践学习和技能建设,重点关注公共部门。*

**本教程的完整代码可以在GitHub repo中找到。即使你不是 Python 程序员,我们也希望这篇文章能让你直观地感受到利用这类数据进行新一代决策支持的可能性和过程。

竞争性编程和字母代码

原文:https://towardsdatascience.com/competitive-programming-alphacode-e9ebc3f88000

解决竞争性编程挑战的培训模型

他们论文中展示的 DeepMind 的 AlphaCode 概述

DeepMind 的字母代码

DeepMind 最*发表了一篇论文,介绍了他们如何训练一个名为 AlphaCode 的模型,该模型可以将一个竞争性编程问题作为输入,然后生成一个解决方案,在参与这些竞争性编程挑战的人中排名 54%。那相当令人印象深刻!这里是博客和 T2 论文的链接。

他们使用来自许多举办这些比赛的不同网站的大量示例挑战和解决方案来训练他们的模型。他们还建立了一个 GitHub 网站,将这些数据提供给那些想尝试训练自己模型的人。读完报纸后,我认为这将是一件伟大的事情。当时我一点也不知道,要做到这一点需要做多少工作。这就是这篇博文的主要目的。我想向您展示我做了什么,以及我如何能够接受他们提供的输入,这是一种专有的格式,并将其转换为简单的 JSON。这是一种非常简单的格式,可以用作您自己模型的输入。

克隆存储库并下载数据

AlphaCode 团队为代码竞赛创建了一个 GitHub 知识库。将存储库克隆到您本地机器上。我们将在后面的步骤中用到它。该库中的自述文件告诉您如何下载数据。按照他们给你的步骤去做。我觉得这有点可怕,因为你必须使用谷歌云,如果你不小心,它会开始从你的信用卡上收取你没有清理和删除的服务费用。在你把文件下载到你的机器上之后,确保你删除了你必须创建的应用程序。我下载了数据,放在 D:\ Data \ contest problem \ DM-code-contests。

Riegeli 格式和 protobuf

下载完数据后,你会注意到它们都是 Riegeli 格式的文件。这是 protobuf 的一种特殊格式,可以很好地压缩字符串。不幸的是,你无法在谷歌环境之外处理这些文件。TensorFlow 的最新版本提到了它们,但我无法从 TensorFlow 中读取它们。

安装 Ubuntu 18.04

为了构建和运行程序来访问 riegeli 文件,我们需要安装 Ubuntu 18.04。我在我的 Windows 10 PC 上使用 WSL,所以我简单地用这个命令在上面安装了 Ubuntu 18.04 发行版:

wsl --install -d Ubuntu-18.04

如果你有一台 Windows 10 PC,但没有安装 WSL,我发现最简单的安装方法是安装 Docker Desktop,并告诉它使用 WSL 作为后端。

安装 Bazel

为了在克隆的存储库中构建东西,我们需要 Bazel。你可以在 https://bazel.build/install 找到如何安装的说明。首先,您需要添加密钥:

sudo apt install apt-transport-https curl gnupg
curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor >bazel-archive-keyring.gpg
sudo mv bazel-archive-keyring.gpg /usr/share/keyrings
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/bazel-archive-keyring.gpg] https://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list

然后,您可以安装和升级它:

sudo apt update && sudo apt install bazel
sudo apt update && sudo apt full-upgrade

安装 clang 和 python 3 开发

最终的构建需求是 clang 和 python 3 开发:

sudo apt install clang
sudo apt install python3-dev

构建示例

现在我们可以开始建造东西了。在 linux 提示符下,转到您克隆存储库的目录。从那里发出以下命令:

bazel run -c opt :print_names_and_sources /mnt/d/Data/ContestProblem/dm-code_contests/code_contests_valid.riegeli

这将需要相当长的时间来运行,因为 Bazel 将下载并构建所有必要的依赖项。如果一切顺利,您应该会看到验证样本及其来源的列表。做这件事的实际 python 代码在存储库中的print _ name _ and _ sources . py中。

创建脚本将 riegeli 文件转换为 JSON

现在我们知道构建环境可以工作了,我们将创建一个新的 python 脚本,它将通读所有的训练、验证和测试 riegeli 文件,并将它们转换成 JSON。创建一个名为的文件 convert_riegeli_to_json.py :

为了能够构建和运行它,我们需要在构建文件的末尾添加一些行:

将 riegeli 文件转换为 JSON

现在一切就绪,我们只需构建并运行脚本,指定输入文件夹和输出文件夹,如下所示:

bazel run -c opt :convert_riegeli_to_json /mnt/d/Data/ContestProblem/dm-code_contests /mnt/d/Data/ContestProblem/dm-code_contests_json

然后应该构建并运行脚本,当它转换每个文件时,您应该会看到类似这样的内容:

Bazel 构建并运行 convert_riegeli_to_json.py

完成更改

我为 DeepMind 项目创建了一个 PR 草案,以便您可以详细了解我所做的更改。这里可以看到

结论

我发现让 Bazel 工作,然后构建项目很有趣。在这个过程中,我发现了很多关于 protobuf 和 riegeli 格式的东西。现在我已经有了 JSON 文件,下一步是尝试创建和训练一个模型,以实现类似于 AlphaCode 的东西。

资源

  1. AlphaCode 博客文章:https://www . deep mind . com/Blog/competitive-programming-with-alpha code
  2. AlphaCode 论文:https://arxiv . org/ABS/2203.07814
  3. 代码竞赛 GitHub:https://github.com/deepmind/code_contests
  4. 巴泽尔:https://bazel.build/install
  5. https://github.com/google/riegeli
  6. 原蟾蜍:【https://developers.google.com/protocol-buffers】T4
  7. 我的公关:https://github.com/deepmind/code_contests/pull/21

用 PostgreSQL 中的例子完整解释 SQL 连接和联合

原文:https://towardsdatascience.com/complete-explanation-on-sql-joins-and-unions-with-examples-in-postgresql-cbd868fe9e95

罗马卡夫在 Unsplash 上拍摄的照片

所有常用的连接类型和一些有趣的类型

本文将是 SQL 联合和连接的综合指南。许多时间数据库的设计方式是连接和联合必不可少的。为了方便起见,数据可以存储在几个独立的表中,而不是有一个大表。因此,学习联合和连接以正确使用它们是很重要的。

在这个演示中,我们将使用 PostgreSQL。这是现在非常流行的 SQL 引擎。但是同样的查询也可以在许多其他主流 SQL 引擎中工作。

如果您阅读本文是为了学习,请键入并尝试自己运行查询。这是唯一的学习方法。

让我们开始吧。

准备数据表

我将为这次演示准备一些虚拟数据表。这些是创建三个表的命令:游戏、制造和黄金。

CREATE TABLE public.games(country character varying(50) NOT NULL,games character varying(50) NOT NULL,year integer NOT NULL);CREATE TABLE makes (country varchar (50) NOT NULL,clubs varchar (50) NOT NULL,games varchar (50) NOT NULL);create table gold (player_name varchar (100) not null,years varchar (10) not null,games varchar (50) null);

游戏表有三列:国家、游戏和年份。makes 表有三列:国家、俱乐部和游戏。最后,黄金表有三列:玩家姓名、年份和游戏。

我们需要在表格中插入一些数据来继续:

insert into gamesvalues("USA", "Baseball", 2012),("China", "Wrestling", 2011),("England", "Cricket", 2015),("India", "Cricket", 2011),("USA", "Football", 2018),("Spain", "Football", 2014),("China", "Basketball", 2019),("Italy", "Football", 2017);insert into makesvalues('USA', 'gk', 'Basketball'),('China', 'kl', 'Wrestling'),('Finland', 'ds', 'Football'),('England', 'nj', 'Cricket'),('Spain', 'lp', 'Football'),('Norway', 'ko', 'Basketball'),('India', 'kg', 'Wresling'),('South Africa', 'ep', 'Cricket'),('Nigeria', 'wm', 'Swimming'); insert into goldvalues('Jimmy', '2018', 'Football'),('Danny', '2012', 'Baseball'),('Indra', '2011', 'Cricket'),('Yun', '2019', 'Basketball'),('Mojo', '2017', 'Football'),('David', '2015', 'Cricket');

数据插入完成。让我们看一下表格。这是游戏桌:

这是制造商表:

这是金桌:

桌子准备好了。它们可能看起来不完整。但是我们将能够学习使用它们,并在我们现实世界的项目中使用这个概念。

联合

游戏和制作表都有国家列。我们希望在一个地方看到所有的国家:

select country from games union allselect country from makes;

下面是部分结果。结果,一个国家来了好几次,这可能是不必要的。这怎么解决?

还有另一种类型的联合称为 union distinct。它只会返回不同的值:

select country from games union distinct 
select country from makes;

我们也可以使用多列。在下一个示例中,我们将看到国家和游戏列。因此,它将显示两个表中的列。

select country, games from games union allselect country, games from makes;

union distinct 在这里也可以用来获得国家和游戏的不同组合。

select country, games from games union distinct
select country, games from makes;

我们在结果中有 14 行数据。你可能会多次找到一个国家或一个游戏。但是在这两个表格中有 14 种独特的国家和游戏组合。

请注意,在游戏列中,我们将“year”作为整数值,在黄金列中,我们将“years”列作为 varchar 值。我们能在他们身上使用联合吗?

我们可以,但是我们需要首先使它们具有相同的数据类型。这里我将把 gold 表中的“years”列转换为一个整数,然后执行 union。我们还使用了一个别名,并将“years”列设置为“year”来匹配

select year from gamesunion distinctselect cast(years as int) as year from gold;

可以在两个以上的表上使用 union 吗?

是的。这里有一个例子:

select games from games 
union all
select games from makes
union all
select games from gold;

这是输出的一部分。

我们也可以使用不同的联合。或者,一个“所有”一个“不同”:

select games from games 
union all
select games from makes
union distinct
select games from gold;

它只返回所有三个牌桌中不同的游戏。摔跤来了两次。但是如果你仔细注意,拼写是不同的。这是数据库中的一个错误。所以,你需要注意表格中的拼写。

连接

连接的工作方式不同。它连接着柱子。我们将研究不同类型的连接。首先,看一些简单的默认连接。

游戏和制作表都有国家列。

这是使用国家/地区列的默认联接:

select * from games joinmakes on games.country = makes.country;

两个表是基于它们之间的共同国家和所有其他列连接的,因为我们没有指定结果中需要哪些列。同一个国家栏出现了两次,这是不必要的。

在下一个例子中,我将指定我想在结果中返回的列。这里我对最后一个查询做了一些修改。

我们对表使用别名或简称。例如,我们将用 g 表示“游戏”表,用 m 表示“制造”表。

我们希望从游戏表中得到的列将被指定为 g.column_name。列 country 将来自游戏表。所以,它会被称为 g.country。

在上一个例子中,我们在表中还有两个“游戏”列。但它们并不完全相同。所以,我们两个都想要。为了清楚起见,我们将使用列别名,将 games 表中的列命名为 g_games,将 makes 表中的 games 列命名为 m_games。

select g.country, g.year, g.games as g_games, m.clubs, m.games as m_games 
from games g
join makes m on g.country = m.country;

连接类型

有不同类型的连接。让我们一个接一个地处理所有的连接。

内部连接

我要提到的第一种类型是内部连接。这实际上是默认类型。如果你没有提到任何类型,它会给你内部连接。在我们最后的两个例子中,我们没有提到任何类型。因此,它自动执行内部连接。

我们正在对 country 列执行内部联接。因此,它将只返回两个表之间的公共国家。

我们可以将最后一个示例重写如下,只使用 inner join 而不是' join '。

select g.country, g.year, g.games as g_games, m.clubs, m.games as m_games from games ginner join makes m on g.country = m.country;

左外连接

我们再次使用同一个例子。这一次将使用左外部联接代替内部联接。当我们在 country 列上进行连接时,在左外部连接中,左侧的所有国家都将被接受。在这里,游戏表位于左侧,因为它是这个查询中首先提到的。从右侧或 makes 表中,它将只使用左侧国家/地区的可用信息。如果 makes 表中没有关于 games 表中任何国家的任何信息,这些位置将显示为空。以下结果中有一些空值:

select g.country, g.year, g.games as g_games, m.clubs, m.games as m_games from games gleft outer join makes m on g.country = m.country;

如果我们想在游戏桌面上看到游戏桌面所在国家所有游戏的俱乐部名称,该怎么办?

在这种情况下,我们将需要根据游戏和国家列加入。就这么办吧。

多列上的左外部连接

在这个查询中,左外部连接是使用 country 和 games 列完成的。这一次,它将返回右表(制造商表)中的值,其中国家和游戏值将与游戏表匹配。

select g.country, g.year, g.games, m.clubs 
from games g
left outer join makes m on g.country = m.country and 
g.games = m.games;

我们也可以连接两个以上的表。

连接两个以上的桌子

现在,我们希望在最后一个查询中包含在游戏中提到的年份中赢得金牌的玩家姓名。因此,我们还必须在游戏和年份上将黄金表与游戏表连接起来,并在输出中包含玩家姓名。

提醒一下,gold 表中的“year”列存储为 varchar。需要将其转换为整数才能进行连接。

select g.country, g.year, g.games, m.clubs, gd.player_name
from games g
left outer join makes m on g.country = m.country and 
g.games = m.games
left outer join gold gd on g.games = gd.games and
g.year = cast(gd.years as int);

现在我们有了游戏表中提到的国家中与游戏相关的俱乐部,以及那些年赢得金牌的运动员的名字。

您可以在内部联接、右外部联接和完全外部联接中对多个列和两个以上的表执行联接。

我们将快速浏览右外连接和全外连接。

右外连接

这一次,我们将加入游戏,并再次制作国家表,以执行正确的外部连接。所以,后面要提到的表将获得优先权。我们将像以前一样,先放“游戏”表,再放“制造”表。

但是在输出表中,我们将从 makes 表中获取所有国家,只有当左表中的信息与右表中的国家相匹配时,才从左表中获取信息。

select m.country, g.year, g.games as g_games, m.clubs, m.games as m_games from games gright outer join makes m on g.country = m.country;

因为我们只在“国家”加入,所以相应的 m _ 游戏和俱乐部都来自那个国家。由于美国和中国在“游戏”表中出现了两次,“制造”表中的信息与这两行连接了两次。所以,总共有 11 行。

在这种情况下,同时使用“国家”和“游戏”更合适:

select m.country, g.year, g.games as g_games, m.clubs, m.games as m_games 
from games g
right outer join makes m on g.country = m.country
and g.games = m.games;

全外连接

我们将只对“country”执行完全联接,我们将同时返回 m.country 和 g.country,因为完全联接将返回这两列中所有国家的信息:

select g.country, g.year, g.games as g_games, m.country, m.clubs, m.games as m_games 
from games g
full outer join makes m on g.country = m.country
and g.games = m.games;

当我们对国家和游戏列进行完全连接时,将从两个表中获取国家和游戏的所有组合:

select g.country, g.year, g.games as g_games, m.country, m.clubs, m.games as m_games 
from games g
full outer join makes m on g.country = m.country
and g.games = m.games;

这些都是非常常见的连接类型。

PostgreSQL 和许多其他 SQL 引擎也支持在“join”语句中使用关键字“using”而不是“on”:

select g.country, g.year, g.games as g_games, m.clubs, m.games as m_games from games gfull outer join makes m using (country);

请随意试用。

自然连接

PostgreSQL 和其他一些 SQL 引擎,如 MySQL,支持自然连接,如果你不提及连接条件,它会使用公共列自然地“连接”。让我们使用“游戏”和“制作”表进行自然连接:

select g.country, g.year, m.clubs 
from games g natural join makes m;

如您所见,我没有提到任何连接条件。尽管如此,它还是在乡村和游戏栏目上做了一个内部连接。因为国家和游戏列在“游戏”和“制造”表之间是通用的。

使用自然内部连接将得到完全相同的结果,如下所示:

select g.country, g.year, m.clubs 
from games g natural inner join makes m;

还可以执行自然左外连接、自然右外连接和自然全外连接。

自然左外连接示例

select g.country, g.year, m.clubs 
from games g natural left outer join makes m;

输出:

自然右外连接的例子

select g.country, g.year, m.clubs 
from games g natural right outer join makes m;

输出:

自然全外连接的例子

select g.country, g.year, m.clubs 
from games g natural full outer join makes m;

一些其他类型的连接

这里还可以提到一些其他类型的连接。一个是交叉连接。

交叉连接

交叉连接就像两个表的点积。左表的每一行都与右表的每一行连接。这里举个例子。

select * from games cross join makes;

这里我展示了输出的一部分。因为产量这么大。

我从两个表中取出所有的列,但是您可以像我们之前做的那样指定某些列。

你可能会想为什么会有人做交叉连接。在这种类型的数据表中帮助不大。但有时它会很有用。

以上提到的连接都是 92 式连接。但是还有一些其他类型的语法,我想在这里提一下。

还有一种 89 式的联接,只执行内联接。它使用“where”子句而不是“join”。

select g.country, g.year, g.games as g_games, m.country, m.clubs, m.games as m_games 
from games g, makes m
where g.country = m.country;

注意,它做的和内部连接完全一样。

结论

这些都是我想在这里谈论的工会和加入。我希望它有帮助。这些连接中的大多数也可以在其他 SQL 引擎中执行。有时你可能需要一个小的语法变化。你只需要检查文档。请随意尝试您正在使用的任何 SQL 引擎。

请随时关注我的 Twitter脸书页面,并查看我的 YouTube 频道

更多阅读

https://pub.towardsai.net/an-overview-of-the-major-sql-query-clauses-and-most-commonly-used-functions-60720e2a20d7 </30-very-useful-pandas-functions-for-everyday-data-analysis-tasks-f1eae16409af>

使用 MLflow 和 DagsHub 进行实验跟踪的完整指南

原文:https://towardsdatascience.com/complete-guide-to-experiment-tracking-with-mlflow-and-dagshub-a0439479e0b9

创建可重复且灵活的 ML 项目

作者图片

介绍

当人们不停地说数据专家花 80%的时间清理数据时,你会感到厌烦吗?虽然这是事实,但机器学习工作流程的另一部分也值得关注,那就是机器学习实验。

跟踪许多机器学习模型及其超参数就像试图在浴缸中养五只狗一样。没有帮助,不可能不让其中一个从你手中溜走。你需要一些灵活而强大的东西来组织每一个实验,所有的细节、代码和数据。

拥有一个所有试验的真实数据库,可以让您将全部注意力放在编写代码上,而不是担心基础设施问题。

在本文中,您将了解机器学习中强大的实验跟踪技术。具体来说:

  1. 什么是 MLflow 及其跟踪 API 的基础知识。
  2. 如何将 MLflow 连接到 DagsHub 以获得更好的 UI 和免费存储
  3. 深入 MLflow 工作流,了解如何为流行的 ML 框架启用自动日志记录
  4. 使用 DagsHub 客户端日志记录器通过 git 进行轻量级实验跟踪
  5. 使用 DagsHub 的实验选项卡来管理您的所有实验及其结果

什么是机器学习中的实验跟踪?

任何成功的生产模式背后,都有许多失败的实验和想法。如果不努力组织你的工作流程以及你如何对待每一个新想法,你不可能神奇地得到一个完美的模型。

机器学习中的实验跟踪是关于保存和版本化与每个实验相关的相关细节(元数据)。根据您的期望和业务需求,这些细节可能会发生变化,但以下是几乎每个项目都需要的最重要的细节:

  • 培训和测试指标
  • 模型超参数和结构
  • 运行时间
  • 模型的依赖性
  • 重现实验的代码
  • 训练模型所需的数据等。

如果没有合适的工具,你会发现手动跟踪这么多东西是非常麻烦的。

为什么要为实验跟踪而烦恼呢?

实验跟踪不是为了保存一大堆模型和超参数。它是关于跟踪什么有效,什么无效。

在任何严肃的项目中,你都会尝试很多模型类型和架构,很容易失去对这些细节的感觉。通过拥有一个你所有想法及其结果的数据库,你可以专注于改进工作原型,而不是担心所有令人讨厌的失败细节。

此外,单个项目中可以有许多“最佳模型”。为您的所有实验建立一个共享的存储库可以很容易地根据不同的需求对它们进行分类。根据您的约束,如果可解释性是您的主要关注点,您可以选择具有最佳验证分数的模型,或者具有最短运行时间的模型,或者具有最少参数的模型。

开始实验跟踪的最佳方式是使用经过实战检验的工具,这些工具集成了您需要的所有功能,而不是发明轮子。

设置

在我们开始使用用于实验跟踪的库之前,让我们进行一些设置。

尽管你可以自己阅读这篇文章,但它是我用 Kaggle 的宠物流行度竞赛数据做的项目的第二部分。该项目旨在根据图像和元数据预测宠物的可爱程度。

第一部分,我解释了我解决这个问题的方法,我使用的工具,并且第一次看到了图像和它们的元数据。建议你看 EDA 部分熟悉一下。

您还可以运行以下命令,将 repo 下载到您的环境中并设置依赖关系。

请注意,数据文件超过 1GB,所以最后一个dvc pull命令需要一段时间才能完成。此外,有许多严重的依赖安装。

如果您不想执行上述步骤,我建议您只安装这些库并下载图像的元数据 CSV:

他们将足以跟随。

https://ibexorigin.medium.com/membership

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

https://alphasignal.ai/?referrer=Bex

MLflow 测井实验基础

机器学习实验最好的开源包之一是 MLflow。虽然它的主要吸引力是它的实验跟踪 API,但它有打包 ML 项目并将它们部署到产品中的功能。我们今天只关注它的跟踪 API。

跟踪 API 是以尽可能简单的方式设计的。导入库后,您可以立即开始记录模型参数和实验结果。这里有一个例子:

这两个基本命令在根目录中生成一个名为mlruns的特殊缓存。它看起来是这样的:

现在,关于这些目录,你需要知道的是,你总是使用版本控制工具,如 Git 或 DVC,来跟踪它们。一旦有了足够多的实验进行比较,就可以在终端上运行mlflow ui命令:

作者

但是这个本地服务器 UI 只对您可见。一个更好的选择是使用免费的跟踪服务器,这样所有的 MLflow 文件都可以远程存储,其他人都可以看到。这就是达格·哈马舍尔德的用武之地。

上一篇文章提到过,DagsHub 是数据科学家的 GitHub。除了托管代码,它还有专门的存储系统用于数据版本控制(DVC)和使用 MLflow 进行实验跟踪。DagsHub 上的任何存储库都公开了 MLflow 的远程跟踪 URI。这是我的宠物木瓜项目的回购:

作者

要开始向该跟踪服务器发送实验详细信息,您需要采取以下步骤:

导入 MLflow 后,将跟踪 URI 设置为您的回购页面上的链接。然后,为您的 DagsHub 用户名和密码设置两个环境变量,这可以在您的 DagsHub 帐户设置下找到。

如果您不想将敏感信息添加到您的脚本中,并意外地将它们提交给 git,您可以系统创建环境变量。以下是在 Windows 上的操作方法:

或者在 MacOS 上:

现在,所有实验都将被记录到 DagsHub 中,这将在 experiments 选项卡下可见。以下是 Pet Pawpularity 项目的外观(这是一个链接):

作者

所有这些实验都是使用我在开始时列出的步骤手工记录的。我用过 XGBoost,LGBM,CatBoost,Sklearn,Keras 这些型号。

该实验选项卡具有 MLFlow 原生 UI 的所有功能,并提供了更多的灵活性和设计。我们将在后面讨论实验选项卡的特性。

深入了解 MLflow 工作流程

到目前为止,我们还没有看到 MLflow 承诺的自动化工作流及其跟踪 API。我们一直在使用log_paramslog_metrics手工记录参数和指标。

过一段时间后,这种方法将变得乏味,因为我们仍然在自己提取参数和指标。此外,记录额外的参数,如运行时间、神经网络的模型架构等,需要更多的工作和代码。

MLflow 为许多流行的 ML 框架公开了单独的自动日志记录类来解决这个问题。以下是其中的一些:

这些自动日志记录类记录模型的参数、训练指标,以及任何可用的拟合参数,如早期停止、时期等。在 Sklearn 的情况下,sklearn.autolog类还记录用 GridSearch 进行超参数调优试验的结果或管道对象的结果。

让我们先来看看这个类的一个例子:

您不必理解代码中发生的所有事情,因为有一些自定义函数。但是如果你好奇,这里有一个高层次的概述:

  • 第 10 行:get_metadata函数加载宠物 Pawpularity 元数据训练 CSV,返回两组。
  • 第 12 行初始化一个 RandomForestRegressor 示例。

关键部分从第 20 行开始,我们调用了start_run上下文管理器。MLflow 工作流程基于运行的概念。运行可以是在这个start_run上下文管理器下编写的一段代码。由于我们在脚本开始时调用了sklearn.autolog()函数,在start_run之后发生的实验细节将被记录下来,包括:

  • 模型超参数
  • 回归的训练指标,如均方误差、R2、*均误差等。
  • 来自sklearn.metrics的自定义指标,如 RMSE

end_run()功能是可选的。您应该注意到,为了让自动记录器检测来自sklearn.metrics的定制指标,您应该在导入它们之前启用自动记录器。以下是 DagsHub 上记录的实验:

作者

让我们看看 Keras 的另一个自动记录器示例:

下面是代码正在做的事情:

  • 第 1 行启用 Keras 自动记录器
  • 第 13 行开始运行
  • 第 15 行用顺序 API 构建了一个 Keras 模型
  • 第 18–29 行通过提前停止回调来编译模型

让我们看看实验结果如何:

作者

你可以阅读这些文档来了解更多关于自动记录器的信息。

使用 Git 和 DagsHub 进行日志记录实验

如果这些信息太多,您可以选择一个更轻量级的选项,比如 DagsHub 客户机包来记录您的实验。有了dagshub,几乎没有学习曲线。下面是一个简单的函数,它将用户定义的超参数和指标记录到 git:

一旦您使用期望的参数运行这个函数,它将在项目根目录下创建两个文件(除非您在函数中指定另一个位置)——metrics.csvparams.yml。将这两个文件添加到 git 并提交更改后,DagsHub 会识别它们,并将参数和指标放在 Experiments 选项卡下。您将会看到这些实验都标有 Git 标签:

作者

尽管 DagsHub 客户端没有漂亮的自动记录器,但它是完全可复制的。假设您正在使用 DVC 来跟踪数据,那么您可以通过一个git checkout切换到任何实验以及完成实验时的项目状态。

MLflow 确实记录了提交散列,但是所有 MLflow 运行都将自己附加到最*一次提交,即实验发生之前的。所以,你需要做的不仅仅是“点击一个按钮”来回到实验的代码。

与 DagsHub 客户端相比,这是一个明显的劣势。

用 DagsHub 分析实验结果

当然,实验选项卡不仅仅显示一个列表。最重要的特点是对比实验。只需选择您想要的,DagsHub 就会生成几个有用的比较指标:

作者

您还可以为具有不同目标或数据的实验分配标签。例如,我使用了metaconv标签来表示实验使用了元数据图像或图像卷积。

由于dagshub使用 git 进行跟踪,MLflow 可以推断出当前的提交哈希,所以可以直接进入运行实验时的项目状态。

最后,您可以直接从 DagsHub 运行git diffs。您可以采取以下步骤来查看两个实验之间的代码和文件差异:

作者

在复制了您想要的实验的提交散列之后,转到 files 选项卡并将它们粘贴到两个字段中。已更改的文件和目录将突出显示。

如果您按下“文件比较”按钮,您会看到每个更改过的文件、脚本和笔记本的深入概述:

作者

结论

现在,您知道了如何使用 Git、MLflow 和 DagsHub 跟踪您的实验。您可以自动记录您的所有实验,并在 DagsHub 上生成漂亮的图表进行比较。任何人都可以从你的实验中看到和学到东西,不管是成功的还是失败的。最重要的是,你获得了一个强大的工具来组织你的试验和想法,这对机器学习项目的成功至关重要。

在本教程中,您已经学习了:

  1. 什么是实验跟踪,为什么你要为它费心
  2. 简单的跟踪工作流是什么样子的
  3. 如何将 MLflow 连接到 DagsHub 这样的远程跟踪服务器
  4. 如何使用 MLflow 及其自动记录器类
  5. 如何使用 DagsHub 和 git 跟踪进行轻量级实验
  6. 如何使用 DagsHub 的实验选项卡分析您的实验结果

感谢您的阅读!

您可以使用下面的链接成为高级媒体会员,并访问我的所有故事和数以千计的其他故事:

https://ibexorigin.medium.com/membership

或者订阅我的邮件列表:

https://ibexorigin.medium.com/subscribe

从零开始完成逐步遗传算法的全局优化

原文:https://towardsdatascience.com/complete-step-by-step-genetic-algorithm-from-scratch-for-global-optimization-6fee5c55dd3b

深潜

再也不用担心陷入局部最小值了

BraňoUnsplash 上拍照

**Table of Contents**[**🌎 What is Global Optimization?**](#388a)[**🧾 Problem Statement**](#c315)[**🔢 Encoding and Decoding Functions**](#b6fa)[**🧬 Selection, Crossover, and Mutation**](#13df)
   ∘ [Selection](#d8ec)
   ∘ [Crossover](#92f8)
   ∘ [Mutation](#03db)
[**👨‍💻 Genetic Algorithm**](#daea)[**🧪 Experiment**](#0239)
   ∘ [Experiment 1: m = 15](#066e)
   ∘ [Experiment 2: m = 30](#bd6a)
[**📌 Conclusion**](#64df)

🌎什么是全局优化?

数学和相关领域的知识之“树”不会只靠长出新枝来生长。事实上,经常发生的情况是,被认为完全不同的分支突然被认为是相关的。

米歇尔·哈兹温克尔

优化过程的一个问题是目标函数经常有许多局部最小值。在某些情况下,如果目标函数足够复杂或者整体模型太大,这是可以容忍的。例如,在典型的神经网络模型中,损失函数的优化器并不是为解决局部极小值问题而设计的。为了克服这一点,一些从业者使用具有不同初始权重或不同优化器参数的相同模型,希望一个模型会给出比其他模型稍好的结果。

在特殊情况下,局部极小值是不可容忍的,因此全局优化器是非常需要的。它们被设计来寻找不可微的或者甚至未知的潜在目标函数的全局最小值。有三种最常见的算法:

  1. 遗传算法
  2. 粒子群优化
  3. 模拟退火

最让我感兴趣的是,这些算法都是受现实生活现象的启发。遗传算法是基于进化原理的模拟。粒子群优化最初是为了模拟社会行为,作为鸟群或鱼群中生物运动的程式化表示。模拟退火模拟在缓慢降低的温度下晶体的凝固。

在这个故事中,我们将把注意力集中在遗传算法上。我们先导入一些库。

🧾问题陈述

DNA,生物遗传的分子基础,由公有领域

我们今天看到的世界,有各种不同的生物,有高度适应环境的个体,有生态*衡(乐观的假设仍然存在),是三十亿年实验的产物,我们称之为进化,一个基于有性和无性繁殖、自然选择、突变等等的过程。如果我们向内看,今天的生物的复杂性和适应性是通过长期提炼和组合遗传物质而实现的。

在生物学中,我们知道遗传信息被总结在染色体中,染色体是由蛋白质和单分子 DNA 组成的细胞成分。对于遗传算法,我们用一串 0 和 1 对染色体进行建模,这也将被称为个体(为简单起见,我们假设每个个体由一条染色体表示)。一些个体将会参与竞争,而那些 T4 健康状况良好的个体将会繁衍后代。我们所说的具有良好的适应性是指优化目标函数。

具体地说,我们将引入一个简单的问题并同时构建遗传算法。问题是找到…的根源

其中x∈【1,3】。当然, f 是已知的,可微的,并且在区间[1,3]中有一个根,因此如果我们使用普通的局部优化技术,我们应该是好的。然而,出于学习的目的,我们将采用遗传算法来代替。

首先,让我们创建一个等价的最大化问题

也就是说,我们使 f 为非正,然后寻找最大值。如果找到的最大值接*于零(具有一定的容差 ε ),那么导致最大值的 x 就是有问题的根。如果不是,那么算法还没有找到 f 的根。

🔢编码和解码功能

与传统的优化算法不同,遗传算法是一种概率优化方法。而且遗传算法对一个函数f:x的搜索空间并不是直接在 X 上,而是在 X 的编码结果上。假设我们用 S 表示这个编码结果。在使用遗传算法之前,我们首先要做的是找到一个将 X 映射到 S 的编码函数。然后,我们在优化后做的最后一件事是执行这个编码函数(解码函数)的逆函数,它将 S 映射到 X 。编码和解码函数不必是双射的。然而,在大多数情况下,如果解码函数是内射的,就容易多了。

我们使用的编码函数是

在哪里

对于每一个 xX 。这里,{0,1} 是由 0 和 1 组成的长度为 n 的字符串的完整集合,bin 是将集合{0,1,…,2 ⁻ }映射到其长度为 n 的二进制表示的函数,round 是将实数舍入到最接*的整数的函数。既然x∈【1,3】,那么 a = 1、 b = 3。注意,由于循环运算,我们的编码函数不是双射的。

老实说,编码功能看起来很吓人,至少对我来说是这样。幸运的是,我们真的不需要在算法中定义编码函数,因为我们已经为 x 设置了随机值。策略不是为 xX 初始化随机值,而是为二进制表示 sS 初始化随机值。下面是代码。

从这里,我们可以将解码函数定义如下

在哪里

每隔。注意这个解码函数是内射的。

在这个故事中,我们将固定 n = 20,尽管我们鼓励您尝试其他的 n 值,看看会发生什么。当 n = 20 时,遗传算法在区间[1,3]中执行的精度达到

因此,我们不能使用小于 9.54 × 10⁻⁷.的误差容差 ε 在这个故事中,默认情况下,我们选择 ε = 1 × 10⁻⁵,但是您可能想在程序中更改这个参数。

🧬选择、交叉和变异

基本上,遗传算法执行以下步骤:

  1. 随机初始化字符串种群 B₀ = ( b₁₀,b₂₀,…,bₘ₀ ),其中每个 bᵢ₀ 为{0,1} 中的个体字符串, m 为种群中的个体数,索引 0 表示种群 B₀ 为第 0 代。
  2. 执行选择、交叉和变异循环,直到满足停止标准。在这个故事中,选择的停止标准是当一个种群的最佳适应度满足|f(x)|≤ε或达到最大迭代次数(最大世代数)时。默认情况下,最大迭代次数是 1000,但是您可以在程序中更改该参数。

选择

选择是通过从第 t 代的种群中抽取一个样本,使 t = 1,2,…,然后从这个样本中选出一个最适合的个体,继续进入第( t +1)代的种群。第 t 代中没有被选中的个体会相继死去。在这个故事中,使用的样本大小是

从人口中的个体数量来看。这个过程要执行 m 次,这样每一代种群中的个体数量是相同的。

这种选拔过程被称为锦标赛选拔。我们使用这种选择方案而不是轮盘赌选择来避免过早收敛到局部最大值的可能性(尽管这可以通过突变来避免),因为具有良好适应性的个体在下一代中填充种群的速度太快。

交叉

t 代种群中的每个个体都是成双成对的(如果 m 是奇数,那么就有一个个体没有伴侣)。然后,对于每个单独的对和某个概率,从{1,2,…,n1 }中随机选择一个指数。在这个故事中,概率是

这意味着必须发生交叉。此后,交换两个个体中所选索引之后的每个比特分量。

这个交叉过程叫做单点交叉

变化

突变是对第 t 代群体中每个个体的每一位进行反转(从 0 到 1 或从 1 到 0)。以某个小概率执行反演。在这个故事中,概率

已使用。将 pₘ 的值设置得很小,以避免遗传算法期间出现混乱。执行变异过程以避免收敛到局部最大值。

当然,你可以改变

如果你想的话。

👨‍💻遗传算法

在进入算法之前,让我们创建一个 python 函数print_result来显示第一代和最后一代的种群、适应度和*均适应度。它还显示最佳适应性以及达到最佳适应性的点 x

现在我们准备好了。遗传算法建立在我们到目前为止已经创建的函数之上。大致的算法是这样的:

Initialize a random population
While the stopping criterion is not met, do:
    Selection
    Crossover
    Mutation
    Decode population

请在下面找到完整的算法。注意,我们使用参数random_state来确保再现性。

接下来,为了漂亮地显示结果,我们创建了另一个名为plot_result的 python 函数,它将显示:

  1. —**|f|的图,以及图上最后一个人口的位置(解码后)
  2. 每一代人的最佳健身

🧪实验

除了取决于随机性,迭代收敛还取决于串的长度 n 和群体中个体的数量 m 。如前所述,我们固定 n = 20。现在我们就来玩玩 m 的值。我们尝试 m 的两种选择如下。

实验一: m = 15

====================================================================
Generation 1 max fitness -0.0174 at x = 1.9165
# 1	[0 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 1 0 0 1]   fitness: -0.0174
# 2	[1 1 0 1 0 0 1 1 0 0 1 1 0 1 0 1 1 1 0 0]   fitness: -0.8531
# 3	[1 1 0 1 0 0 0 1 0 1 1 1 0 1 0 1 0 1 0 1]   fitness: -0.8342
# 4	[1 0 1 0 1 0 1 0 1 0 0 1 0 1 0 1 0 0 1 1]   fitness: -0.4428
# 5	[1 1 1 0 0 1 0 0 1 0 1 1 0 1 1 1 0 1 1 1]   fitness: -1.0461
# 6	[1 1 1 0 1 1 1 0 1 1 0 1 1 1 1 1 1 0 1 0]   fitness: -1.1612
# 7	[0 1 0 1 0 1 0 0 0 1 0 1 1 0 0 1 1 1 1 0]   fitness: -0.1666
# 8	[0 1 0 0 1 0 0 1 1 0 1 0 1 0 0 1 1 0 1 1]   fitness: -0.2122
# 9	[0 1 0 1 1 0 0 1 1 1 1 0 0 1 0 1 1 1 1 1]   fitness: -0.1402
# 10	[0 0 0 0 0 0 0 0 1 1 1 1 0 1 0 1 1 0 1 0]   fitness: -0.3417
# 11	[0 1 0 1 1 0 1 0 0 1 0 0 0 0 1 1 1 0 1 0]   fitness: -0.1384
# 12	[0 0 1 0 1 1 1 1 1 1 1 1 0 1 1 1 0 1 1 0]   fitness: -0.2935
# 13	[0 1 0 1 1 1 1 0 0 1 0 1 1 0 0 0 1 1 0 0]   fitness: -0.1177
# 14	[1 1 0 1 1 0 1 1 1 1 1 0 1 1 0 0 1 1 0 0]   fitness: -0.9482
# 15	[0 1 1 0 1 1 1 1 1 0 0 0 0 1 1 0 0 0 1 1]   fitness: -0.0196
Average fitness: -0.4489
==================================================================== 

====================================================================
Generation 27 max fitness -0.0000 at x = 1.8955
# 1	[0 1 1 1 0 0 1 0 1 0 0 1 1 0 1 0 0 0 0 1]   fitness: -0.0001
# 2	[0 1 1 0 0 0 1 0 0 0 0 1 1 0 0 1 0 0 1 1]   fitness: -0.0977
# 3	[0 1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 0 1 1 1]   fitness: -0.0319
# 4	[0 1 1 1 0 0 1 0 0 1 0 1 1 0 1 1 0 1 1 0]   fitness: -0.0017
# 5	[0 0 1 1 0 0 1 0 0 0 1 1 1 0 1 1 0 0 0 1]   fitness: -0.2879
# 6	[0 1 1 1 0 0 0 0 0 1 1 1 1 0 1 1 0 0 1 0]   fitness: -0.0136
# 7	[0 1 1 1 0 0 0 0 1 0 1 1 1 1 1 1 0 1 0 1]   fitness: -0.0119
# 8	[0 1 1 1 0 0 1 0 0 1 1 1 1 1 1 1 1 1 0 1]   fitness: -0.0008
# 9	[1 1 1 1 0 0 1 0 0 0 1 1 1 0 1 1 1 0 0 0]   fitness: -1.1996
# 10	[0 1 1 0 0 0 1 1 1 1 1 1 1 0 1 1 1 1 1 0]   fitness: -0.0874
# 11	[1 1 1 1 0 1 1 0 0 1 1 1 1 0 1 1 0 1 1 0]   fitness: -1.2485
# 12	[0 1 1 1 0 0 1 0 0 1 1 1 0 0 0 1 1 1 0 0]   fitness: -0.0011
# 13	[0 1 1 1 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 0]   fitness: -0.0000
# 14	[0 0 1 1 0 0 0 0 0 1 1 1 1 0 0 0 1 1 1 1]   fitness: -0.2923
# 15	[0 1 1 1 0 0 1 0 0 1 1 1 0 0 1 1 1 1 0 1]   fitness: -0.0011
Average fitness: -0.2184
==================================================================== 

Solution found at iteration 27

图片作者作者

实验二:m = 30

====================================================================
Generation 1 max fitness -0.0174 at x = 1.9165
# 1	[0 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 1 0 0 1]   fitness: -0.0174
# 2	[1 1 0 1 0 0 1 1 0 0 1 1 0 1 0 1 1 1 0 0]   fitness: -0.8531
# 3	[1 1 0 1 0 0 0 1 0 1 1 1 0 1 0 1 0 1 0 1]   fitness: -0.8342
# 4	[1 0 1 0 1 0 1 0 1 0 0 1 0 1 0 1 0 0 1 1]   fitness: -0.4428
# 5	[1 1 1 0 0 1 0 0 1 0 1 1 0 1 1 1 0 1 1 1]   fitness: -1.0461
# 6	[1 1 1 0 1 1 1 0 1 1 0 1 1 1 1 1 1 0 1 0]   fitness: -1.1612
# 7	[0 1 0 1 0 1 0 0 0 1 0 1 1 0 0 1 1 1 1 0]   fitness: -0.1666
# 8	[0 1 0 0 1 0 0 1 1 0 1 0 1 0 0 1 1 0 1 1]   fitness: -0.2122
# 9	[0 1 0 1 1 0 0 1 1 1 1 0 0 1 0 1 1 1 1 1]   fitness: -0.1402
# 10	[0 0 0 0 0 0 0 0 1 1 1 1 0 1 0 1 1 0 1 0]   fitness: -0.3417
# 11	[0 1 0 1 1 0 1 0 0 1 0 0 0 0 1 1 1 0 1 0]   fitness: -0.1384
# 12	[0 0 1 0 1 1 1 1 1 1 1 1 0 1 1 1 0 1 1 0]   fitness: -0.2935
# 13	[0 1 0 1 1 1 1 0 0 1 0 1 1 0 0 0 1 1 0 0]   fitness: -0.1177
# 14	[1 1 0 1 1 0 1 1 1 1 1 0 1 1 0 0 1 1 0 0]   fitness: -0.9482
# 15	[0 1 1 0 1 1 1 1 1 0 0 0 0 1 1 0 0 0 1 1]   fitness: -0.0196
# 16	[1 0 1 0 1 0 1 1 0 0 1 1 1 1 0 0 0 1 0 1]   fitness: -0.4489
# 17	[1 0 0 1 1 1 0 0 0 0 0 1 1 0 0 1 0 0 0 1]   fitness: -0.3129
# 18	[0 0 1 1 0 0 0 0 0 1 0 1 0 0 1 1 1 1 1 0]   fitness: -0.2926
# 19	[1 1 0 1 1 0 0 0 0 0 1 1 1 0 1 1 0 1 1 0]   fitness: -0.9076
# 20	[0 0 1 1 0 1 0 1 0 0 1 1 0 1 1 0 1 0 1 0]   fitness: -0.2801
# 21	[1 1 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 1 1 0]   fitness: -0.8456
# 22	[1 1 0 0 0 1 1 0 1 1 0 1 0 0 0 0 0 0 1 1]   fitness: -0.7216
# 23	[0 1 1 0 1 0 1 0 1 0 0 0 0 1 0 1 1 1 1 0]   fitness: -0.0499
# 24	[0 1 0 0 1 0 0 1 1 1 1 1 1 0 1 1 1 0 1 0]   fitness: -0.2110
# 25	[0 0 0 1 1 1 0 1 1 0 1 1 0 1 0 1 1 1 1 1]   fitness: -0.3271
# 26	[0 0 1 1 0 0 1 1 0 1 1 1 1 1 1 1 1 0 1 0]   fitness: -0.2847
# 27	[1 1 0 0 1 1 1 0 1 1 0 0 0 1 0 0 1 1 0 1]   fitness: -0.8054
# 28	[1 1 0 0 0 1 1 0 1 0 0 0 0 1 0 1 1 0 1 0]   fitness: -0.7186
# 29	[1 0 0 1 0 1 0 1 0 0 0 0 0 1 0 1 0 1 0 1]   fitness: -0.2531
# 30	[0 1 1 1 1 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0]   fitness: -0.0454
Average fitness: -0.4413
==================================================================== 

====================================================================
Generation 11 max fitness -0.0000 at x = 1.8955
# 1	[0 1 1 1 0 0 1 0 1 0 0 1 0 1 1 1 1 0 0 1]   fitness: -0.0002
# 2	[0 1 1 1 0 0 1 0 1 0 0 1 1 1 1 1 1 0 1 0]   fitness: -0.0000
# 3	[0 1 1 1 1 0 1 0 1 0 1 1 0 1 0 1 1 1 1 1]   fitness: -0.0536
# 4	[1 1 1 1 0 0 0 0 1 0 0 1 0 0 1 1 1 1 0 1]   fitness: -1.1807
# 5	[0 1 1 0 1 0 1 0 0 0 0 0 0 1 1 1 1 1 0 1]   fitness: -0.0528
# 6	[0 1 1 1 1 0 1 0 1 0 0 1 0 1 1 0 1 1 1 1]   fitness: -0.0528
# 7	[0 0 1 1 0 0 1 0 1 0 0 1 0 1 1 1 1 1 0 0]   fitness: -0.2870
# 8	[0 0 0 1 0 0 0 0 1 0 0 1 0 1 1 1 1 1 1 0]   fitness: -0.3394
# 9	[1 1 1 1 0 0 0 0 0 1 0 1 0 1 1 1 1 1 0 1]   fitness: -1.1780
# 10	[0 1 1 1 0 0 1 0 1 0 0 1 0 1 1 1 1 1 0 0]   fitness: -0.0002
# 11	[0 1 1 1 0 0 1 0 1 1 0 1 1 1 0 1 1 1 0 0]   fitness: -0.0016
# 12	[0 1 1 1 0 1 1 0 0 1 0 1 0 1 1 0 1 1 1 0]   fitness: -0.0242
# 13	[0 1 1 0 1 0 1 0 1 0 0 1 0 1 1 1 0 1 0 0]   fitness: -0.0495
# 14	[0 1 1 1 0 0 1 0 0 0 0 1 1 1 0 1 1 1 1 0]   fitness: -0.0032
# 15	[0 0 1 1 0 1 1 0 1 0 0 1 1 1 0 0 1 1 0 0]   fitness: -0.2763
# 16	[0 0 1 1 1 0 1 0 0 0 0 0 0 1 0 1 1 1 1 1]   fitness: -0.2665
# 17	[0 0 1 1 1 1 1 0 1 0 0 1 1 0 0 0 1 0 1 0]   fitness: -0.2521
# 18	[0 1 0 1 0 0 0 1 1 0 0 1 0 1 1 0 1 0 0 0]   fitness: -0.1791
# 19	[0 1 1 1 0 0 1 0 1 0 0 1 0 0 1 1 1 0 0 0]   fitness: -0.0003
# 20	[0 1 1 1 0 0 1 0 1 0 1 1 0 1 1 1 1 1 1 0]   fitness: -0.0006
# 21	[0 1 1 1 0 0 1 0 1 0 0 1 1 1 0 1 1 1 0 1]   fitness: -0.0000
# 22	[0 1 0 1 0 0 1 0 0 1 0 1 0 0 1 1 1 0 1 0]   fitness: -0.1758
# 23	[0 1 1 1 0 0 1 0 1 1 0 1 0 1 1 1 1 1 1 0]   fitness: -0.0014
# 24	[0 1 1 1 0 0 1 0 1 0 0 1 0 1 1 1 1 1 0 1]   fitness: -0.0002
# 25	[0 1 1 1 0 0 1 0 0 1 0 1 1 1 1 0 1 1 1 1]   fitness: -0.0016
# 26	[1 1 0 1 0 0 1 1 0 0 0 1 1 0 0 1 1 1 0 0]   fitness: -0.8519
# 27	[0 1 1 1 1 0 1 0 1 0 0 1 1 1 1 0 1 1 0 1]   fitness: -0.0530
# 28	[0 1 1 1 1 0 1 0 1 0 1 1 0 1 0 1 1 0 1 0]   fitness: -0.0536
# 29	[0 1 1 1 0 0 1 0 1 0 0 1 0 1 1 0 0 1 1 0]   fitness: -0.0002
# 30	[0 1 1 1 0 0 1 0 1 0 0 1 0 1 1 1 0 1 1 0]   fitness: -0.0002
Average fitness: -0.1779
==================================================================== 

Solution found at iteration 11

图片作者作者

从上面的结果可以看出,对于这两种情况,程序都能找到

在[1,3]中,即 x ≈ 1.8955。从上面 f 的洋红色图上的预测种群图可以看出,对于两种情况,种群都聚集在-|f(x)|≈0 附*。

然而,这个解决方案是在不同数量的迭代中发现的:

  1. m = 15 的情况下,经过 27 次迭代后找到解,这意味着程序已经执行了 27 × 15 = 405 次求值。由于搜索空间的数量是 2 ⁵,程序只需要 405 / 2 ⁵ =总搜索空间的 1.24%。
  2. m = 30 的情况下,经过 11 次迭代后找到解,这意味着程序已经执行了 11 × 30 = 330 次求值。由于搜索空间数为 2 ⁰,程序只需要 330 / 2 ⁰ = 3.07 × 10⁻⁷部分总搜索空间。

m = 30 的情况下所需的世代数小于在 m = 15 的情况下所需的世代数,这是有意义的,因为在前一种情况下人口更多。总而言之,遗传算法比在一个搜索空间中随机寻找一个解 x 要有效得多,尤其是在 m = 30 的情况下。

最后,从上面的最佳适应度对迭代的曲线图(用青色表示)可以看出,一般来说,每一代都会有适应度比上一代更好的个体。然而,可能有某些代人的健康状况比上一代人差。由于突变过程,这是很自然的事情。

📌结论

遗传算法是一种强大的全局优化技术,如果应用正确的设置,可以根除局部陷阱。这完全是概率性的,结果取决于过程的随机性,个体中染色体的长度,以及群体中个体的数量。我们已经看到了搜索函数根的遗传算法。据观察,遗传算法比在搜索空间中随机寻找根有效得多。

🔥你好!如果你喜欢这个故事,想支持我这个作家,可以考虑 成为会员 。每月只需 5 美元,你就可以无限制地阅读媒体上的所有报道。如果你注册使用我的链接,我会赚一小笔佣金。

🔖想了解更多关于经典机器学习模型的工作原理,以及它们如何优化参数?或者 MLOps 大型项目的例子?有史以来最优秀的文章呢?继续阅读:

**Albers Uzila

艾伯斯·乌兹拉**

从零开始的机器学习

**View list8 stories****Albers Uzila

艾伯斯乌兹拉**

高级优化方法

**View list7 stories****Albers Uzila

艾伯斯乌兹拉**

MLOps 大型项目

**View list6 stories****Albers Uzila

艾伯斯乌兹拉**

我最好的故事

**View list24 stories****Albers Uzila

艾伯斯·乌兹拉**

R 中的数据科学

View list7 stories****

从头开始完成分步粒子群优化算法

原文:https://towardsdatascience.com/complete-step-by-step-particle-swarm-optimization-algorithm-from-scratch-74471d064f91

深潜

以及它在解决一个非线性控制理论问题中的实现

Unsplash 上由 James Wainscoat 拍摄

**Table of Contents**[🐦 An Inspiration from Nature](#bf74)
[✍️ Problem Statement](#f3fb)
[💻 Building the PSO Algorithm](#caa0)
[🧪 Testing the Algorithm by Running Once](#5e1c)
[📉 Analyzing Performance](#2954)
   ∘ [Case 1: N = 3 and scaling = 0.10](#b940)
   ∘ [Case 2: N = 6 and scaling = 0.03](#a1e3)
   ∘ [Case 3: N = 12 and scaling = 0.01](#f990)
[📌 Conclusion](#053b)

🐦来自大自然的灵感

粒子群优化(PSO)算法是一种基于群体的搜索算法,基于对鸟群中鸟类社会行为的模拟。粒子群概念的最初意图是用图形模拟鸟群优雅而不可预测的编排,发现控制鸟类同步飞行能力的模式,并通过以最佳队形重组来突然改变方向。从这个最初的目标,这个概念演变成一个简单而有效的优化算法。

所以,就像遗传算法一样,粒子群算法是受自然启发的。

[## 从零开始完成逐步遗传算法的全局优化

towardsdatascience.com](/complete-step-by-step-genetic-algorithm-from-scratch-for-global-optimization-6fee5c55dd3b)

在粒子群优化算法中,个体,也称为粒子,在超多维搜索空间中“飞行”。搜索空间内粒子位置的改变是基于个体模仿其他个体成功的社会心理倾向。因此,群体中一个粒子的变化受到其邻居的经验或知识的影响。因此,一个粒子的搜索行为受到群体中其他粒子的影响(因此,PSO 是一种共生的合作算法)。对这种社会行为进行建模的结果是,搜索过程的进行使得粒子随机地返回到搜索空间中先前成功的区域。

像往常一样,我们先导入一些库。

✍️问题陈述

我们将涉及一点数学。您可能希望阅读本节,以掌握并完全理解问题陈述。但是,如果您想向前跳,可以随意向下滚动到本节的编码部分。

我们介绍了一个非线性控制理论问题,并使用粒子群算法来解决它。给定以下系统

我们将设计控件 u ,使 y = x₁ ( t )跟随 yₚ ( t )。这里,对于 i = 1,2,3,所有的 xᵢu 都是时间 t 的函数, ẋᵢxᵢ 相对于 t 的一阶导数。我们今后将把所有函数的集合称为{ x₁x₂x₃ } by x

随着输出y=x₁(t),系统的相对度为 2,即 y ( t )对时间的二阶导数显式包含 u 。接下来,我们建立系统的范式。假设

然后,通过定义 żᵢzᵢ 相对于 t 的一阶导数,我们得到了下面的范式

这是一个不稳定的系统,因为ż₃=z₁+z₃。在非线性控制系统理论中,它处于非最小阶段。所以设计 u 来跟踪 yₚ ( t )被 y ( t )是没用的。根据非线性控制理论,采用输出重定义的方法,仍然可以设计出 u ,从而可以通过 y ( t )跟踪 yₚ ( t )。

此外,如果选择了另一个输出(输出重新定义),例如y=x₃(t),我们将得到如下新系统

这个系统的相对度是 3。系统的标准形式是通过声明

因此,我们得到

该系统处于正常状态,可以通过选择控制u(t)=v(t)a(x)来稳定,其中**

这里, x₃⸴ₚ 是我们为 x₃x₃⸴ₚ ⁾是Ix₃⸴ₚ相对于 t 的第阶导数。注意,x₃⸴ₚ⁽⁰⁾=x₃⸴ₚ。同样, bᵢ 是一个常数。所以,我们有

假设w=z₁x₃⸴ₚw ⁾是 w 相对于 t 的第 i 阶导数,我们得到 ODE

选择 b₀ = 6, b₁ = 11, b₂ = 6,则上述 ODE 的特征方程为λ+6λ+11λ+6 = 0,因此有负根 λ ∈ {-1,-2,-3}。颂歌的解决方案是

用实常数 C₁C₂C₃ 。作为设计控件 u 的一部分,我们可以用 C₂ = C₃ = 0 来设置初始条件 x₁ (0) = 0。那么请注意

以便

因此,

换句话说,如果已知 x₃⸴ₚ ( t ),就可以确定 x₁ ( t ),看 x₁ ( t )是否逼* sin t 。函数 x₃⸴ₚ ( t )通常可以写成以下傅立叶级数

注意,我们还需要 x₃⸴ₚ ( t )的一阶导数,简单来说就是

参数 αβₙγₙ 可以*似使得 x₁ ( t )接* sin t 。在这个故事中,我们将通过解决下面的优化问题来寻找它们

通过假设 x₁ ( t )对 sin t 的逼*只会在区间[0,4π]上看到。

但是积分很难编码。相反,我们将区间[0,4π]划分为 100 个大小相等的子区间。然后,使用梯形法数值求解 f 的最小化过程,如下所示

其中𝒫( d₀d₁ ,…, d₁₀₀ )是区间[0,4π]的划分。

💻构建粒子群算法

照片由 Danist SohUnsplash 上拍摄

上述最小化问题使用粒子群算法解决。PSO 算法是概率性的,因为它包含随机过程。所有 2 个 N 个 + 1 个参数存储在一个数组中,该数组在 PSO 上下文中通常被称为“粒子”。在这个故事中,形成了 800 个粒子 pₖ ,它们用遵循正态分布的随机值进行初始化,从而获得了大小为 800 × (2 N +1)的矩阵。

然后,对这些初始参数进行缩放,以校正过大的尖峰(请记住,我们想要*似的函数是 sin t ,它仅在-1 ≤ sin t ≤ 1 时定义,因此远离[-1,1]的尖峰数量需要尽可能少)。比例常数遵循 N 的大小,并将在下面的 实验 部分中进行公式化。所有这些初始参数都是每个粒子的*个人最佳pₖ⸴ᵦₑₛₜpₖ。也就是说,对于每个粒子,这些初始参数的值是最佳的,使得 f 最小。另外,我们可以选择这 800 个粒子中的一个作为全局最优* gᵦₑₛₜ ,即所有粒子中 f 最小的粒子。每个粒子的速度vₖpₖ也以类似的方式初始化。

然后迭代,直到满足停止标准。在一次迭代中,执行以下操作:

  1. 在区间[0,1]上均匀选取大小为 2 N + 1 的随机数 r₁r₂
  2. 对于每个粒子 pₖ 在任何时候 t ,使用以下公式更新速度

其中 c₁c₂ 分别是认知社会常数。在这个故事中,设定 c₁ = c₂ = 1。变量 w惯性权重,其在本例中被初始化为 1,然后在每次迭代中被减少一个因子 r = 0.99。您可以在程序中更改 c₁c₂wr 的值。

3.通过设置w:=w×r减少 w

4.对于每个粒子 pₖ 在任何时候 t ,使用公式更新 pₖ

5.如果 f 值小于先前的全局最佳值,则通过选择 800 个粒子中具有最小 f 的 1 个来更新全局最佳值

6.更新个人最好。对于每个粒子 pₖ ,比较 pₖfpₖ⸴ᵦₑₛₜf 。如果 pₖf 小于 pₖ⸴ᵦₑₛₜf ,更新pₖ⸴ᵦₑₛₜ=pₖ

如果不满足以下 3 个语句中的一个,迭代将停止:

  • gᵦₑₛₜf 值大于公差 ε 。在这个故事中,我们选择了 ε = 10⁻⁵.
  • 当前迭代次数仍然小于最大迭代次数。在这个故事中,最大迭代次数设置为 1000。
  • gᵦₑₛₜf 没有减少的情况下进行的连续迭代次数仍然小于提前停止迭代限制。在这个故事中,提前停止设置为 100。也就是说,如果在 100 次迭代后 gᵦₑₛₜf 没有减少,迭代停止。实现提前停止的目的是为了在多次执行 PSO 时节省时间(参见 实验 部分)。

您可以在程序中更改参数 ε 、最大迭代次数、提前停止

🧪通过运行一次来测试算法

现在,我们将尝试运行一次 PSO 算法,看看它是否正常工作。我们用 N = 3,比例= 0.1。

Initial condition:   params = [0.1 -0.1 -0.3 0.1 -0.1 -0.0 -0.1]
		     error = 5.1687Iteration: 1	best params = [0.1 -0.2 -0.3 0.0 -0.1 -0.1 -0.1]
		error = 4.0092
Iteration: 2	best params = [0.1 -0.6 -0.4 0.0 -0.1 -0.1 0.0]
		error = 3.6121
Iteration: 3	best params = [0.0 -0.4 -0.5 0.0 -0.0 0.0 0.0]
		error = 1.2643
Iteration: 4	best params = [0.0 -0.4 -0.6 -0.0 -0.0 0.0 -0.0]
		error = 1.2772
Iteration: 5	best params = [-0.0 -0.5 -0.8 -0.1 -0.0 0.0 -0.0]
		error = 2.7673
Iteration: 6	best params = [-0.0 -0.6 -0.6 0.0 0.0 0.0 -0.0]
		error = 1.9027
Iteration: 7	best params = [-0.0 -0.5 -0.6 -0.0 0.0 0.0 -0.0]
		error = 1.3108
Iteration: 8	best params = [0.1 -0.4 -0.5 0.0 0.0 -0.0 0.0]
		error = 1.4853
Iteration: 9	best params = [-0.1 -0.5 -0.5 -0.0 0.0 0.0 -0.0]
		error = 1.4060
Iteration: 10	best params = [0.0 -0.5 -0.5 0.0 0.0 0.0 -0.0]
		error = 0.8704
Iteration: 11	best params = [0.0 -0.5 -0.5 0.0 0.0 -0.0 0.0]
		error = 1.4382
Iteration: 12	best params = [0.0 -0.5 -0.5 -0.0 -0.0 0.0 0.0]
		error = 0.8478
Iteration: 13	best params = [0.0 -0.5 -0.5 -0.0 -0.0 0.0 0.0]
		error = 0.7722
Iteration: 14	best params = [0.0 -0.5 -0.5 0.0 -0.0 -0.0 0.0]
		error = 0.8501
Iteration: 15	best params = [-0.0 -0.5 -0.5 0.0 0.0 -0.0 -0.0]
		error = 1.1804
Iteration: 16	best params = [0.1 -0.5 -0.5 0.0 0.0 0.0 -0.0]
		error = 0.9567
Iteration: 17	best params = [-0.0 -0.5 -0.5 -0.0 -0.0 0.0 0.0]
		error = 0.7197
Iteration: 18	best params = [0.0 -0.5 -0.5 0.0 -0.0 0.0 -0.0]
		error = 0.4595
Iteration: 19	best params = [0.0 -0.5 -0.5 0.0 -0.0 0.0 0.0]
		error = 0.2959
Iteration: 20	best params = [-0.0 -0.5 -0.5 0.0 -0.0 0.0 -0.0]
		error = 0.4951
Iteration: 21	best params = [0.0 -0.5 -0.5 0.0 -0.0 0.0 -0.0]
		error = 0.4831
Iteration: 22	best params = [-0.0 -0.5 -0.5 0.0 -0.0 0.0 0.0]
		error = 0.6799
Iteration: 23	best params = [-0.0 -0.5 -0.5 -0.0 0.0 0.0 0.0]
		error = 0.4144
Iteration: 24	best params = [-0.0 -0.5 -0.5 -0.0 0.0 0.0 -0.0]
		error = 0.5413
Iteration: 25	best params = [0.0 -0.5 -0.5 -0.0 -0.0 0.0 0.0]
		error = 0.4145
Iteration: 26	best params = [0.0 -0.5 -0.5 -0.0 -0.0 0.0 0.0]
		error = 0.3616
Iteration: 27	best params = [-0.0 -0.5 -0.5 -0.0 0.0 0.0 -0.0]
		error = 0.3272
Iteration: 28	best params = [-0.0 -0.5 -0.5 0.0 -0.0 -0.0 0.0]
		error = 0.2329
Iteration: 29	best params = [-0.0 -0.5 -0.5 0.0 -0.0 -0.0 -0.0]
		error = 0.2442
Iteration: 30	best params = [0.0 -0.5 -0.5 0.0 -0.0 0.0 0.0]
		error = 0.2628
Iteration: 31	best params = [-0.0 -0.5 -0.5 0.0 -0.0 0.0 -0.0]
		error = 0.1614
Iteration: 32	best params = [-0.0 -0.5 -0.5 0.0 -0.0 -0.0 -0.0]
		error = 0.2218
Iteration: 33	best params = [0.0 -0.5 -0.5 0.0 -0.0 0.0 0.0]
		error = 0.1540
Iteration: 34	best params = [-0.0 -0.5 -0.5 -0.0 -0.0 -0.0 -0.0]
		error = 0.1594
Iteration: 35	best params = [-0.0 -0.5 -0.5 0.0 0.0 -0.0 -0.0]
		error = 0.1561
Iteration: 36	best params = [-0.0 -0.5 -0.5 0.0 -0.0 -0.0 0.0]
		error = 0.0816
Iteration: 37	best params = [-0.0 -0.5 -0.5 0.0 -0.0 -0.0 -0.0]
		error = 0.0612
Iteration: 38	best params = [-0.0 -0.5 -0.5 -0.0 -0.0 -0.0 0.0]
		error = 0.0926
Iteration: 39	best params = [0.0 -0.5 -0.5 -0.0 -0.0 -0.0 0.0]
		error = 0.0501
Iteration: 40	best params = [0.0 -0.5 -0.5 -0.0 -0.0 -0.0 -0.0]
		error = 0.0544
Iteration: 41	best params = [0.0 -0.5 -0.5 -0.0 -0.0 -0.0 -0.0]
		error = 0.0417
Iteration: 42	best params = [-0.0 -0.5 -0.5 -0.0 -0.0 -0.0 -0.0]
		error = 0.0285
Iteration: 43	best params = [-0.0 -0.5 -0.5 -0.0 0.0 -0.0 -0.0]
		error = 0.0228
Iteration: 44	best params = [-0.0 -0.5 -0.5 -0.0 0.0 -0.0 -0.0]
		error = 0.0284
Iteration: 45	best params = [-0.0 -0.5 -0.5 -0.0 0.0 -0.0 -0.0]
		error = 0.0340
Iteration: 46	best params = [0.0 -0.5 -0.5 -0.0 -0.0 -0.0 -0.0]
		error = 0.0240
Iteration: 47	best params = [0.0 -0.5 -0.5 -0.0 0.0 0.0 -0.0]
		error = 0.0159
Iteration: 48	best params = [0.0 -0.5 -0.5 -0.0 0.0 -0.0 -0.0]
		error = 0.0153
Iteration: 49	best params = [-0.0 -0.5 -0.5 -0.0 0.0 0.0 -0.0]
		error = 0.0156
Iteration: 50	best params = [-0.0 -0.5 -0.5 -0.0 0.0 0.0 -0.0]
		error = 0.0149
Iteration: 51	best params = [-0.0 -0.5 -0.5 -0.0 -0.0 0.0 -0.0]
		error = 0.0152
Iteration: 52	best params = [-0.0 -0.5 -0.5 -0.0 -0.0 -0.0 -0.0]
		error = 0.0110
Iteration: 53	best params = [0.0 -0.5 -0.5 -0.0 -0.0 -0.0 -0.0]
		error = 0.0069
Iteration: 54	best params = [0.0 -0.5 -0.5 -0.0 0.0 -0.0 -0.0]
		error = 0.0076
Iteration: 55	best params = [0.0 -0.5 -0.5 -0.0 0.0 -0.0 0.0]
		error = 0.0056
Iteration: 56	best params = [0.0 -0.5 -0.5 -0.0 0.0 -0.0 -0.0]
		error = 0.0035
Iteration: 57	best params = [-0.0 -0.5 -0.5 -0.0 -0.0 0.0 -0.0]
		error = 0.0038
Iteration: 58	best params = [0.0 -0.5 -0.5 -0.0 0.0 -0.0 0.0]
		error = 0.0025
Iteration: 59	best params = [0.0 -0.5 -0.5 0.0 -0.0 0.0 0.0]
		error = 0.0011
Iteration: 60	best params = [0.0 -0.5 -0.5 0.0 0.0 0.0 0.0]
		error = 0.0014
Iteration: 61	best params = [-0.0 -0.5 -0.5 0.0 0.0 0.0 0.0]
		error = 0.0009
Iteration: 62	best params = [0.0 -0.5 -0.5 0.0 0.0 0.0 0.0]
		error = 0.0005
Iteration: 63	best params = [0.0 -0.5 -0.5 -0.0 0.0 0.0 0.0]
		error = 0.0007
Iteration: 64	best params = [0.0 -0.5 -0.5 -0.0 0.0 0.0 0.0]
		error = 0.0007
Iteration: 65	best params = [0.0 -0.5 -0.5 -0.0 0.0 0.0 0.0]
		error = 0.0005
Iteration: 66	best params = [0.0 -0.5 -0.5 -0.0 0.0 -0.0 0.0]
		error = 0.0003
Iteration: 67	best params = [0.0 -0.5 -0.5 -0.0 0.0 0.0 0.0]
		error = 0.0003
Iteration: 68	best params = [0.0 -0.5 -0.5 0.0 0.0 0.0 0.0]
		error = 0.0002
Iteration: 69	best params = [0.0 -0.5 -0.5 -0.0 -0.0 0.0 0.0]
		error = 0.0002
Iteration: 70	best params = [-0.0 -0.5 -0.5 0.0 0.0 0.0 0.0]
		error = 0.0001
Iteration: 71	best params = [0.0 -0.5 -0.5 -0.0 0.0 0.0 0.0]
		error = 0.0001
Iteration: 72	best params = [-0.0 -0.5 -0.5 0.0 -0.0 0.0 0.0]
		error = 0.0001
Iteration: 73	best params = [-0.0 -0.5 -0.5 0.0 0.0 -0.0 0.0]
		error = 0.0001
Iteration: 74	best params = [-0.0 -0.5 -0.5 0.0 0.0 -0.0 0.0]
		error = 0.0001
Iteration: 75	best params = [0.0 -0.5 -0.5 -0.0 -0.0 -0.0 0.0]
		error = 0.0000
Iteration: 76	best params = [0.0 -0.5 -0.5 -0.0 0.0 0.0 0.0]
		error = 0.0000
Iteration: 77	best params = [0.0 -0.5 -0.5 0.0 -0.0 -0.0 -0.0]
		error = 0.0000
Iteration: 78	best params = [0.0 -0.5 -0.5 -0.0 0.0 -0.0 0.0]
		error = 0.0000
Iteration: 79	best params = [-0.0 -0.5 -0.5 -0.0 -0.0 0.0 -0.0]
		error = 0.0000
Iteration: 80	best params = [0.0 -0.5 -0.5 0.0 -0.0 -0.0 -0.0]
		error = 0.0000

图片作者作者

太好了,非常管用!在迭代过程中,我们看到最佳误差波动,但总体趋势下降。这并不奇怪,因为粒子会四处移动,有时会通过局部最小值。

由于 N = 3,所以有 2 × 3 + 1 = 7 个参数可以玩。该算法找到的最终参数是

因此,

这可以很容易地用来验证

经过对 x₂x₃ 的计算,我们得到 u 的设计为

很容易检查所有这些函数是否满足问题陈述中给出的系统。

从上面可以看出,PSO 算法需要 80 次迭代来解决优化问题。为了查看逼*进度,我们将使用plot_result python 函数在一些迭代中在区间[0,4π]中绘制 x₁ ( t )和 sin t ,如下所示。注意,我们使用了basic_units.py,一个来自 matplotlib 文档的 python 文件,因此需要定义我们自己的sin函数。这种费力的工作只是为了将 x 轴网格线显示为弧度的倍数。

图片作者作者

📉分析性能

我们已经得到了我们想要的。因此,尝试 N 的其他值是没有用的。所以,把这个部分当作一个沙箱,我们在这里尝试改变 N ,多次运行 PSO 算法,看看它什么时候崩溃。

迭代收敛高度依赖于初始参数的选择和所执行的缩放。另外, x₃⸴ₚ 的参数个数(由 N 决定)也影响迭代收敛。一个容易看到的观察结果是,如果 N 足够大,那么所选择的比例常数必须足够小。这是因为大的 N 导致三角函数 sin( nt )和 cos( nt )很有可能达到极值 1 或-1,从而导致 x₁ 上的尖峰。为此,我们尝试了三种选择 N 和缩放:

  • N = 3,缩放比例= 0.10
  • N = 6,缩放= 0.03
  • N = 12,缩放= 0.01

对于每种情况,我们将运行粒子群算法 100 次。然后,绘制结果的*均值,以查看整体性能。为此,我们构建了一个名为plot_average_result的 python 函数,如下所示。

情况 1: N = 3,缩放比例= 0.10

Average number of iterations: 78.23
Average parameters found    : [-0.0 -0.5 -0.5 0.0 0.0 -0.0 -0.0]
Average errors              : 4.663474180805023e-07

图片由作者

该程序运行大约 78 次迭代,并找到返回 10⁻⁷阶的 gᵦₑₛₜf ,小于 ε = 10⁻⁵.的参数找到的参数是[0,-0.5,-0.5,0,0,0,0]。我们已经检查过这些参数确实产生了y=x₁(t)非常接* y = sin t ,从上图中也可以看出,两者的图形在[0,4π]内的所有点都重合。

情况 2: N = 6,缩放比例= 0.03

Average number of iterations: 155.96
Average parameters found    : [0.0 -0.5 -0.5 -0.0 0.0 -0.0 0.0 0.0 0.0 -0.0 0.0 -0.0 -0.0]
Average errors              : 0.0033187883813983877

图片作者作者

该程序运行大约 156 次迭代,并设法找到生成具有 10⁻顺序的 gᵦₑₛₜf 的参数。100 次跑步中的一些因为提前停止而停止。所得到的参数实际上与情况 1 中的参数相似,从上图中也可以看出,曲线图 yyₚ 几乎在所有点上重合。

情况 3: N = 12,缩放比例= 0.01

Average number of iterations: 146.63
Average parameters found    : [0.0 -0.5 -0.5 -0.0 0.0 -0.0 -0.0 0.0 0.0 0.0 0.0 -0.0 0.0 -0.0 0.0 0.0
 0.0 -0.0 0.0 -0.0 0.0 0.0 0.0 -0.0 -0.0]
Average errors              : 0.6630980162922079

图片作者作者

该程序运行了大约 147 次迭代,并设法找到生成具有 10⁻顺序的 gᵦₑₛₜf 的参数。查看比情况 2 中更低的*均迭代次数,我们得出结论,许多运行(从 100 次运行)停止是因为它们达到了早期停止。从上图可以看出, yyₚ 的曲线图在波峰和波谷处略有偏离。

📌结论

粒子群优化算法(PSO)是一种全局优化算法,本质上是概率性的,因为它包含随机过程。群体的概念最初是为了用图形模拟鸟群优雅而不可预测的舞蹈动作而研究的。然而,我们已经实现了粒子群算法来解决一个非线性控制理论问题。该算法能够以高精度找到控制 u

🔥你好!如果你喜欢这个故事,想支持我这个作家,可以考虑 成为会员 。每月只需 5 美元,你就可以无限制地阅读媒体上的所有报道。如果你注册使用我的链接,我会赚一小笔佣金。

🔖想了解更多经典机器学习模型的工作原理,以及它们是如何优化参数的?或者 MLOps 大型项目的例子?有史以来最优秀的文章呢?继续阅读:

**Albers Uzila

艾伯斯·乌兹拉**

从零开始的机器学习

**View list8 stories****Albers Uzila

艾伯斯·乌兹拉**

高级优化方法

**View list7 stories****Albers Uzila

艾伯斯·乌兹拉**

MLOps 大型项目

**View list6 stories****Albers Uzila

艾伯斯·乌兹拉**

我最好的故事

**View list24 stories****Albers Uzila

艾伯斯·乌兹拉**

R 中的数据科学

View list7 stories****

用于医学图像去噪的复值 CNN

原文:https://towardsdatascience.com/complex-valued-cnns-for-medical-image-denoising-12a4262c6ef6

一种新的医学图像去噪方法

来源

深度学习,特别是卷积神经网络(CNN),正在塑造数据驱动的问题解决的未来。从文本相关的问题,如语音生成、内容编写等,到视觉任务,如图像分类、对象检测,CNN 被广泛使用。在过去的几年中,已经提出了许多先进的 CNN 架构,如图形 CNN、基于注意力的 CNN、复值 CNN 等。在这篇文章中,我将总结我在这里发表的研究论文,其中提出了一种新的基于复值 CNN 的深度学习模型用于医学图像去噪。

介绍

医学成像通过以多种方式帮助医疗专业人员,包括疾病诊断、治疗和风险预测,彻底改变了卫生部门。然而,X 射线、计算机断层扫描(CT)、超声波和磁共振成像(MRI)等医学图像容易受到各种噪声的影响。例如,胸部 X 射线(CXR)图像经常被高斯噪声破坏,高斯噪声出现在采集、存储、传输和处理过程中。医学图像中的噪声会降低图像质量,甚至使其在诊断上无法使用。这可能会阻碍进一步的决策,导致疾病的诊断、治疗或分析不佳。因此,总是迫切需要在不损害潜在信息的情况下降低医学图像的噪声,因为由此产生的诊断直接影响人类健康和生命。

一些传统的医学图像去噪(MID)技术包括基本的数字图像滤波器、自适应滤波器、非局部均值算法和多尺度技术。然而,医学图像中复杂的噪声导致这些技术的性能不尽人意。“然后是卷积神经网络(CNN)”。毫无疑问,CNN 已经成为众多数据驱动任务,尤其是图像处理的主流解决方案。对于 MID,已经报道了各种基于 CNN 的架构,如卷积自动编码器和生成式对抗网络(GANs)。这些 CNN 技术涉及两种 CNN 架构,例如,在 GANs 中,我们有一个生成器和鉴别器,在自动编码器中,我们有一个编码器和解码器。然而,有许多方法只涉及一种 CNN 架构,如 DnCNN。

给定用于 MID 的基于 CNN 的方法,可以得出结论,所有这些方法都涉及实值 CNN,即处理实数的 CNN 架构。这促使我为 MID 开发 CVC nn,正如你可能已经猜到的,这是为 MID 实现 CVC nn 的第篇研究论文(同时,这也是我的第一篇研究论文)。

最*,复值 CNN(cv CNN)越来越受欢迎,因为它们提供了比实值 CNN 更好的结果,并且由于硬件行业的进步,这些模型的实现已经成为可能。现在出现了以下问题:

  1. CVCNNs 如何优于它们的实值对应物
  2. CVCNNs 如何用于 MID

我不会主要关注第一个问题,因为它超出了本文的范围。不过,我可能会写另一篇文章,说明 CVCNNs 相对于其实值对等物的优势,所以请继续关注:)

提议的方法

提出的用于 MID 的 CVCNN 模型被称为 CVMIDNet。模型框架如图 1 所示,其中 Conv、BN 和 ReLU 代表卷积层、批量归一化和校正线性单元函数。

图一。CVMIDNet 的架构。来源

以下是该模型的主要组成部分:

复值卷积层(CVCL)

在 CVCL 中,实值卷积运算被推广到复数域。在实值卷积层中,在输入矩阵 I 和实值核 K,即 I*K 之间执行卷积运算。在复值卷积层中,I 和 K 都是复矩阵,使得:

I = Ir + iIc
K = Kr + iKc

其中,Ir、Ic、Kr 和 Kc 是实矩阵。现在,复值卷积运算变为:

I * K =(Ir * Kr Ic * Kc)+I(Ic * Kr+Ir * Kc)

复值批量规范化(CVBN)

类似于 CVCL,在 CVBN 中,实值 BN 运算以如下方式推广到复数域:

CNB(Z) = BN(A) + i(BN(B))

其中 BN()和 CNB()分别表示实值和复值 BN 运算。Z 是被认为是 Z = A + iB 的复值参数

复值 ReLU (CVReLU)

当涉及到一般化实值激活函数(在这个例子中是 ReLU)时,我们有许多方法可以做到这一点,因此我们有不同版本的 CVReLU。最常见的包括 ModReLU、zReLU 和 CReLU。在文献中,有足够的证据表明 CReLU 的性能优于其他潜在的同类产品,尤其是在与图像相关的任务中,因此它被考虑用于 CVMIDNet。CReLU 按如下方式获得:

CReLU(z) = ReLU(R(z)) + i(ReLU(I(z)))

其中,z、R(z)和 I(z)表示复值参数、z 的实部和 z 的虚部。

数据集和实验细节

本研究考虑了一个公开可用的 CXR 图像数据集(链接),其中图像受到高斯噪声的影响。CXR 图像被考虑用于去噪,因为由于其成本效益和非侵入性方法,它们是最重要的医学成像技术类型之一。为训练选择了 400 幅图像,为测试集选择了 100 幅(与训练集不重叠)图像。

整个工作的代码是使用 Tensorflow 在 Python 中开发的。必要时还开发了定制层和数据生成器。

结果

峰值信噪比(PSNR)和结构相似性指数(SSIM)被用来评估 CVMIDNet。此外,该模型还与 BM3D、DnCNN、FDCNN 等其他先进的 MID 技术进行了比较。CVMIDNet 的实值对应物(通过用其实值对应物替换 CVMIDNet 中的复值运算而开发的),称为 RVMIDNet,也被考虑用于性能评估。

考虑了许多高斯噪声水*,即 sigma = 15、25、40、50 和 60 (sigma 代表高斯噪声中的噪声水*,更多的是这里的)。结果显示在下表和下图中。

表 1 去噪图像的 PSNR 结果。来源

表 2 去噪图像的 SSIM 结果。来源

图二。去噪图像的*均 PSNR 图。来源

图 3。去噪图像的*均 SSIM 图。来源

通过与其他最新技术进行比较,发现 CVMIDNet 在各种噪声水*下对受高斯噪声影响的 CXR 图像进行去噪方面优于所有其他方法。

图 sigma = 15 的去噪图像。来源

结论

首次提出并实现了一种新的基于复值 CNN 的深度学习模型 CVMIDNet,该模型具有用于医学图像去噪的残差学习。CVMIDNet 使用复值卷积层、复值批量归一化和 CReLU 激活来实现,以从胸部 X 射线图像中去除高斯噪声。CVMIDNet 的去噪性能与四种潜在的最先进的去噪方法进行了比较,即块匹配和 3D 滤波、DnCNN、特征引导去噪卷积神经网络以及除 RVMIDNet 之外的具有残差学习的深度 CNN 模型,其中 RVMIDNet 具有与 CVMIDNet 相同的架构,但所有操作都是实值的。据观察,CVMIDNet 在所有调查的五个噪音水*上以显著的优势优于所有其他模型。此外,视觉评估还清楚地表明,CVMIDNet 比其他比较模型更有效地降低了噪声并恢复了图像。

结尾注释

所以这是一个关于我的一个新方法的研究的简介,这个方法被杂志接受:生物医学信号处理和控制

如果这篇文章对你有用,那么你可能会发现我的其他文章同样有趣。此外,如果你想或正在寻找开发这样的模式,那么你可以联系我在五月:【https://www.fiverr.com/shubhankarrawat

快乐学习!!

仅使用 Python 的生产 ML 系统的组件

原文:https://towardsdatascience.com/components-of-a-production-ml-system-using-only-python-d6cf27405c82

学习和构建 MLOps 组件基础的基础

我最*为纽约数据科学学院做了一个关于生产中的机器学习的演讲,我根据这个演讲改编了这篇文章。这篇文章的目的是使用唯一的 Python 代码演示一个生产 ML 系统的一些组件的基本功能。对于感兴趣的人,我还将在 2022-23的生产课上教授机器学习!

Devilz 拍摄。 on Unsplash

免责声明:本文不代表实际生产系统的设置,而是作为一个教育工具,代表这些工具的一些轻量级功能,以帮助那些没有机会使用这些系统的人熟悉这些系统。

也就是说,下面的每个代码片段都是为了演示您可能在实现 MLOps 的生产 ML 系统中看到的一些东西——仅使用Python!酷吧?要开始使用,请确保安装了以下库:

pandas
sklearn
pytest

下面是一些我们将在本教程中使用的合成用户数据。它包含两个输入要素和一个目标。这并不代表真实的场景,但有利于演示:

**import** pandas **as** pdurl = "[https://raw.githubusercontent.com/kylegallatin/components-of-an-ml-system/main/data/user_data.csv](https://raw.githubusercontent.com/kylegallatin/components-of-an-ml-system/main/data/user_data.csv)"user_data **=** pd**.**read_csv(url, index_col**=**0)
user_data**.**head()

现在让我们开始吧…

功能存储

特征库(和特征系统)旨在使机器学习系统的特征易于管理、产品化和定义。它们通常可用于模型训练和低延迟服务。一些技术来看看:泰克顿,盛宴。

下面的解决方案允许我们将用户数据转换成一个以user_id为关键字的字典——这样我们就可以快速检索我们想要预测的用户的特征。它也不妨碍我们在培训过程中读取所有数据。

我们可以用我们的数据初始化这个类,然后将新的特性定义为函数!该函数将自动应用于我们的数据并创建新功能:

feature_store **=** SuperSimpleFeatureStore(user_data)

**def** new_feature(feature_dict: Dict) **->** Dict:
    **return** feature_dict["feature_1"] ****** 2

feature_store**.**register_feature("feature_3", new_feature)
feature_store**.**get_user_feature("a27b09ee-0cf8-11ed-899e-b29c4abd48f4")

ML 元数据存储(实验跟踪)和模型注册

ML 元数据(实验跟踪)本质上是你的数据科学项目的实验室笔记本。这个想法是你捕捉所有的元数据和实验运行的信息,使事情具有可重复性。在此之上是一个模型注册中心,这将是一个更集中的管理和版本化模型的地方。一些可以参考的工具:MLFlow,Weights and Biases,Comet,Sagemaker。

在这种情况下,我们的设计更简单。我们将在一个 CSV 文件中捕获关于我们实验的所有信息,用于跟踪结果。

现在我们有了助手函数,我们可以进行不同的训练运行并记录结果:

每当我们运行上面的代码时,我们将向我们的“ML 元数据存储”追加另一行。

自动化培训渠道

一旦模型代码、数据和参数被优化,代码可以被抽象到源代码控制的 repo (git)中,训练代码可以被调度和自动化。在像电子商务这样的情况下,已经有新的数据进入,模型经常需要重新训练。您想要自动化训练和部署模型的过程,这些模型的参数已经被合理地设置。一些可以参考的工具:气流,库伯流。

在可能是迄今为止最大的过度简化中,我这样编译了代码,并将其放入自己的 Python 脚本中——然后添加了一个无限循环,以在每次运行之间休息 1 分钟来持续训练模型。这样,我们可以在后台运行脚本来不断训练新的模型(在运行之间有 60 秒的睡眠时间)。

要在后台运行该脚本,请使用:

python3 main.py &

连续累计

持续集成是主动向中央存储库提交变更的行为,也包括自动化测试和构建。大多数这些动作都是由 git 提交和推送到 Github 这样的远程存储库来触发的。在本例中,我添加了一个可以使用pytest运行的简单测试。虽然还没有自动化,但这是在 ML repo 中设置测试的一个很好的起点。值得关注的工具:Jenkins、云构建、Buildkite。

pytest

动作:通过添加pytest 命令作为 git 预提交挂钩,自己练习 CI(ie 将在您尝试提交代码时运行)。

持续交付/部署和模型服务器

连续交付是可靠地发布软件的小的迭代变更的实践,以确保它可以被可靠地发布。持续部署就是持续部署。在 ML 的情况下,这将是自动化过程的一部分——其中模型训练管道自动将新训练的模型发送到模型服务器。要看的工具:Jenkins,Cloud Build,Buildkite,Argo CD。

模型服务器通常是接受预测输入(要素)并返回预测的 HTTP 服务器。要看的工具:Tensorflow 发球,谢顿核心。

在这种情况下,不是做“CD ”,我们只是在每次预测时更新加载最新的训练模型(记住它在后台更新)。然后,我们使用一个predict函数代替模型服务器来获取给定用户 ID 的特性并进行预测。

array([0.])

在真实的场景中,我们永远不会为每个预测再次加载模型,但是这段代码确保我们无论如何都使用最新的模型。为了改进这个解决方案,请尝试添加代码,以便在我们的模型存储发生变化时只读取新的模型!

性能监控

生产系统的监控和可观察性绝对是一个系统中最重要的组成部分之一。真正的系统也有警报,通知工程师生产问题。在这种情况下,我们将创建一个简单的监视器,记录预测的延迟并报告*均值。一些研究工具:普罗米修斯,格拉夫纳。

这段代码添加了一个非常简单的监视类,它跟踪并记录做出预测所需的时间。

如果我们想在继续预测时看到*均预测时间,我们可以使用监视器来实现!

monitor**.**mean()

结论

生产系统是困难的,如果没有在工业部门工作过相当长的时间,就更难获得实际经验。虽然上面的代码或示例都不是“生产就绪”的,但是它们应该为您提供一个学习这些组件的基础知识的基础,然后在它们的基础上进行构建。

在野外,您可能会看到这里所表示的组件的许多不同的组合和实现——包括我没有包括的其他组件!如果您想在本文中看到更多的概念,请告诉我!在这里看这个项目的 git 回购。

今年秋天,我将教授一门生产机器学习课程,如果感兴趣,请联系 LinkedIn 或 Twitter!

理解辍学:通过做玩具例子进行深度学习

原文:https://towardsdatascience.com/comprehend-dropout-deep-learning-by-doing-toy-examples-d07f985c8e2f

丢弃是深度神经网络中主要的正则化技术之一。这个故事有助于你深刻理解什么是辍学,它是如何运作的。

完全连接的网络(由作者创建)

在深度学习中,尤其是在物体检测中,很容易发生过拟合。过度拟合意味着模型非常复杂,以至于它非常适合训练集,但在测试集上失败。失败意味着它有时甚至检测到测试图像中的噪声。

在对象检测中,通常使用预训练的骨干进行训练,或者继续使用预训练的模型进行训练。这就是为什么在几个时代之后,验证的损失高于训练的损失。在这种情况下,添加一个下降层是有帮助的。

在 Pytorch 中,我们可以简单地通过以下方式添加一个 Dropout 层:

from torch import nn
dropout = nn.Dropout(p=0.2)

但是引擎盖下会发生什么呢?

辍学正规化方案

Dropout 技术通过选择隐藏层中的一些神经元,从原始神经网络创建子神经网络。选择是重新采样神经网络中的节点(仅隐藏层中的节点)并定义一些遮罩。

辍学不是为了偏向节点!剔除是一种正则化技术,其思想是减少由权重引起的过拟合。因此,正则化不适用于偏差节点,因为它们不接收任何输入。因此,放弃它们无助于改进预测。

玩具示例

考虑下面的全连接网络,其中激活函数是 ReLU。(要看网络和矩阵的关系,看上面的 GIF。)

辍学玩具示例

在本例中,目标是使用以下漏失掩码预测 x = (1,1)。

漏屏

为了计算预测,我们应该计算隐藏层中的值。

第一个隐藏层:

其中 g⁽ ⁾是激活函数,则

注意:第一个丢弃层μ⁰是所有节点的丢弃层。因此,对结果没有任何影响。

第二个隐藏层:

其中 g⁽ ⁾是 ReLU 激活函数,则

第三个隐藏层:

其中 g⁽ ⁾是 ReLU 激活函数,则

输出层:

练习:

如果缺失掩码为:

最后的答案是:

摘要

这个故事有助于你理解辍学技巧。我计划在机器学习和深度学习中增加更多这样的玩具例子。因此,如果你喜欢阅读更多,请继续关注😊。

https://sciencenotes.medium.com/membership

使用 Python 和 AWS Lambda 将任何 ML 模型部署为 API 的综合指南

原文:https://towardsdatascience.com/comprehensive-guide-to-deploying-any-ml-model-as-apis-with-python-and-aws-lambda-b441d257f1ec

把那个模型放到网上

照片由 苏西 拍摄

介绍

人们说 Python 最好的一点是它丰富的开源库。恕我不能苟同。

在完成一项任务时有多种选择可能会给你带来很大的灵活性,但它们最终可能会造成巨大的混乱,让程序员感到困惑和愤怒。

现在,这是关于机器学习操作(MLOps)的情况。*年来,它已经成为一个如此重要的领域,以至于 Python 社区已经出色地应对了这种情况——通过创建尽可能多的工具和库来执行 MLOps 规程。

现在,对于一个普通用户来说,筛选所有的信息,比较并提出一套最终的工具来解决他们的业务问题是一个挑战。

即使他们做到了,把他们放在一起,让他们交流,并达成一个现成的,像样的机器学习解决方案也是一个完全独立的问题。

以将模型部署为 API 为例(本文的主题)。你会选择哪一套工具来完成这项工作?

暂时,让我们忘记所有开始时的忙乱,比如数据版本化、模型选择和特征工程,并且说你已经有了一个现成的模型。

如何将模型转换成 HTTPS 地址,以便用户可以发送请求?有这么多的选择,像 Flask,Django,FastAPI 等等。

即使选择了框架,让它上线也不容易。你使用 AWS,Heroku,GCP,或其他几十个几乎声称他们提供了“唯一最好的方法”来做到这一点吗?

为了省去您回答所有这些问题的麻烦,在本文中,我将介绍一个解决方案,与其他替代方案相比,它应该非常简单明了,没有任何麻烦。你只需要知道scikit-learnxgboost;其余的我会教。

最后,我们将构建这个 API :

作者图片

用户可以向它的classify端点发送请求以获得预测,并通过一个链接在任何地方嵌入这个 API。

https://ibexorigin.medium.com/membership

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

https://alphasignal.ai/?referrer=Bex

我们将使用的堆栈

在我们开始之前,让我概述一下我们将使用的技术列表,并解释我选择它们的原因。

  • 熊猫,熊猫——无需解释。
  • SklearnXGBoost —模型训练。它们只是为了说明的目的而被选择的,并且这些指令将在来自任何其他框架的模型上工作
  • BentoML——将训练好的模型打包到本地 API 中(后面会详细解释)
  • bentoctl —一个 CLI 工具,允许您构建 Docker 映像,并使用一个命令将它们保存为云兼容格式
  • Terraform —另一款用于管理云基础设施的 CLI 工具。它负责创建资源和函数,并将容器推送给它们,而不需要访问 50 万个页面。
  • AWS —最受欢迎、最可靠、最灵活的云*台(你可以通过 Google Trends 确认)。
  • AWS Lambda —在无服务器云上运行代码——高度可扩展且舒适。

所以,事不宜迟,让我们开始吧。

BentoML 是什么,它的目的是什么?

为了最大化机器学习的商业影响,数据科学家和工程师之间从模型训练到部署的交接应该是快速和迭代的。

然而,数据科学家通常不具备打包训练好的模型并将其推给工程师的技能,而工程师发现很难处理来自几十个不同 ML 框架的模型。

BentoML 的创建就是为了解决这些问题,并尽可能容易/快速地交付到生产部署。在接下来的几节中,您将看到 BentoML 如何使执行繁琐的 MLOps 操作变得容易。这些例子是:

  • 将任何框架的任何模型保存为统一格式,以简化协作。
  • 使用单个 Python 函数创建 HTTP API 端点,以加快迭代速度。
  • 使用 Docker 和一个 CLI 命令将模型需要的所有东西打包。

阅读文档这里了解更多信息,或者继续阅读。

数据集准备和模型训练

这篇文章的核心是关于模型部署的,所以我想把您的全部注意力集中在这个领域。

为此,我假设您在阅读本文时已经有了训练有素的模型,并且希望尽快部署它。

为了在这里进行模拟,我们将创建一个合成数据集,训练一个 XGBoost 模型,并继续前进,就好像您已经完成了 MLOps 生命周期的所有先前步骤,如数据清理、探索、特征工程、模型实验、超参数调整,并找到了在您的数据集上表现最佳的模型。

我们创建了一个简单的数据集,包含七个特征和 10k 个样本,目标是二进制分类。

我们将它加载回来,训练一个普通的 XGBoost 分类器,并假设它是我们调优的模型。

将训练好的模型保存为 BentoML 格式

通过调用特定于框架的save命令,可以将训练好的模型保存为 BentoML 兼容的格式:

返回的对象是 BentoML Model类的一个实例,带有一个名为标签的标签。

标签由两部分组成——用户给出的名称和版本字符串,以区分不同时间保存的模型。即使保存了相同的模型,BentoML 也会创建一个新的目录和一个版本字符串。

BentoML 支持几乎所有基本的 ML 框架:

  • 经典:Sklearn、XGBoost、CatBoost、LightGBM
  • 深度学习:TensorFlow,PyTorch,PyTorch Lightning,Keras,Transformers
  • 其他:ONNX,MLFlow,fast.ai,statsmodels,spaCy,h2o,Gluon 等。

每个框架都有一个相应的bentoml.framework.save_model命令。

当一个模型被保存时,它进入一个名为 BentoML model store 的本地目录。从最后一个输出(path参数)中,我们看到我的模型商店位于/home/bexgboost/bentoml/models。您可以通过在终端中调用bentoml models list命令来查看您所有型号的列表:

你也可以看到我其他项目的模型。

注意:在 BentoML 文档和本文中,名称“model”和“tag”可以互换使用,以指代模型存储中保存的模型。

save_model具有其他参数,用于传递关于模型的额外信息,从元数据到其他用户定义的对象(例如,作为单独对象的模型的特征重要性):

上面,我们保存了我们的 XGBoost 模型和其他数据,比如作者(我),特性重要性分数,您可以用booster.get_score和一个虚拟指标来检索。

共享模型

使用bentoml models export命令,BentoML 模型存储中的模型可以作为独立的档案共享:

当您不知道标签的确切版本字符串时,可以使用“:latest”后缀来选择最新的版本。使用上面的命令,我们将分类器导出到models目录下的.bentomodel档案中。当队友发送给你一个.bentomodel存档时,你可以使用import命令将其发送到你当地的 BentoML 模型商店:

检索保存的模型

有几种方法可以将保存的模型从模型库中加载到您的环境中。最简单的就是load_model功能。和save_model一样,load_model也是特定于框架的:

该函数将以保存前的相同格式加载模型,这意味着您可以使用其本机方法,如predict:

要将模型作为 BentoML Model对象加载,您可以使用models.get命令,它不是特定于框架的:

tag = bentoml.models.get("xgb_custom:latest")

您可能希望以这种格式加载模型的原因是,现在您可以访问它的附加组件,如元数据和标签:

检索模型的最后也是最重要的方法是将它们作为跑步者加载:

Runners 是 BentoML 的特殊对象,根据它们的框架进行优化,以最有效的方式使用系统资源。运行器是我们将在下一节构建的 API 的核心组件。

现在,我们已经准备好开始构建 API 了!

https://ibexorigin.medium.com/membership

组织成脚本

到目前为止,我们一直使用笔记本。我们需要切换到 Python 脚本来构建 API 服务。我们来整理一下前面几节的代码。在generate_data.py文件中,创建一个保存来自“数据集准备”部分的合成数据的函数:

完整的generate_data.py脚本可以在这里找到。

在一个train.py文件中,创建一个函数来训练我们的 XGBoost 分类器,并将其保存到 BentoML 模型存储中:

完整的train.py脚本可以在这里找到。

为了完整起见,请以正确的顺序运行这两个脚本,以生成数据集并将一个新模型保存到模型存储中。

创建 API 服务脚本

现在,是时候创建本地 API 了。为此,我们只需要一个简单的脚本,如下所示:

在加载了以models.get作为跑步者的模型后,我们创建了一个名为svc的对象。这将是一个 BentoML Service对象的实例。Service是抽象表示我们的 API 的高级类。

我们通过创建一个同名的函数向服务对象添加一个名为classify的端点:

让我们一行一行地理解上面的片段。

首先,我们从bentoml.io导入一个新的类NumpyNdarray——输入/输出模块。为了标准化输入和输出,BentoML 提供了几个类似于NumpyNdarray的类,如TextFileImagePandasDataFrame等。

将这些类添加到svc.api装饰器的inputoutput参数中可以确保正确的数据类型被传递到我们的 API 端点。在我们的例子中,我们确保传递给我们的classify函数的数据总是一个 NumPy 数组。

如果我们正在处理图像模型,我们的输入类可能是一个FileImage类,而输出将再次是NumpyNdarray

在函数内部,我们使用 runner 的predict.run方法来获得对输入的预测。该方法调用了 XGBoost booster 对象的predict方法。

下面是脚本最终的样子:

就是这样!通过使用bentoml serve,我们可以创建一个本地调试服务器:

$ bentoml serve service.py:svc --reload

重要提示:上述命令中的service.pysvc变量根据您的脚本名和服务对象名而变化。如果在一个名为api.py的脚本中有一个名为api的服务对象,那么命令应该是bentoml serve api.py:api --reload。标签确保 BentoML 无需重启服务器就能检测到对脚本的修改。

以下是该命令的输出示例:

作者图片

GIF 显示该 API 在本地运行于 http://127.0.0.1:3000:

作者 GIF

通过使用 Swagger UI,BentoML 向您展示了我们 API 的交互式文档。我们已经可以向它发送请求来获得预测:

耶!我们的 API 起作用了——它将给定的样本分类为第一类。

做便当

现在,我们将 API 打包成一个便当。

Bento 是由 BentoML 引入的一个术语,指的是一个包含使我们的 API 工作所需的所有东西的档案——以一种统一的格式。在便当中,将会有关于构建 Docker 映像和我们的 API 模型的依赖关系的说明。

我们通过在与脚本相同的目录级别中创建一个bentofile.yaml文件(名称应该相同)来开始构建便当。它将如下所示:

include字段用于列出运行我们的便当所需的所有脚本。在我们的例子中,我们只是添加了所有的 Python 脚本。接下来是packages字段,它应该列出依赖项及其版本。

在大型项目中,很难跟踪所有的依赖项及其版本,所以您可以使用pipreqs库为您的项目创建一个requirements.txt文件:

$ pip install pipreqs
$ pipreqs --force .  # --force overrides existing req file

然后,您可以将依赖项复制到bentofile.yaml

在您准备好bentofile.yaml之后,我们调用build命令并指定到bentofile.yaml的路径,在我们的例子中是项目根(.):

$ bentoml build .

如果成功,您将看到如下输出:

作者图片

您也可以在 CLI 中运行bentoml list来检查便当:

如您所见,我的系统上有三个便当,其中两个属于当前项目。有现成的便当意味着我们可以在线部署它。

设置 AWS 凭据

因为我们将 API 部署为 AWS Lambda 函数,所以我们必须设置我们的 AWS 凭证。最好的方法是通过 CLI。

首先,转到您的 AWS IAM 控制台并找到您的凭证。通常可通过按钮“管理访问密钥按钮”获得:

作者图片

点击它,你将到达这里:

作者图片

创建一组新密钥或下载现有密钥。然后,转到您的终端并运行以下命令:

对于 Linux 或 osX:

对于 Windows:

这将仅为当前虚拟环境设置您的 AWS 凭据。

将便当部署到 AWS Lambda

为了部署我们的 Bento,我们将使用 BentoML 的名为bentoctl的本地 CLI 包。用boto3包安装它(对于 AWS 依赖项)并安装aws-lambda操作符。然后,调用bentoctl init:

$ pip install bentoctl boto3
$ bentoctl operator install aws-lambda
$ bentoctl init

该命令将询问您几个问题。您只需要为部署提供一个名称— xgb_classifier。您可以将其余部分保留为默认值。

部署说明取自bentoctl文件上的这里的

作者 GIF

将创建三个文件— deployment_config.yamlbentoctl.tfvarsmain.tf。他们会喜欢下面的:

作者图片

作者 GIF

现在,我们将安装另一个名为terraform的工具。Terraform 简化了直接从 CLI 创建和管理云资源。它将使用上述三个文件,主要是main.tf文件,该文件列出了我们即将推出的 AWS Lambda 函数的所有细节。

你可以在找到 Terraform 的安装说明,这里是 Linux 的。对于其他系统,遵循此处的说明。要检查安装是否成功,请使用:

$ terraform -h

如果它打印出命令列表,则安装成功。

之后,我们用bentoctl build命令构建一个 AWS Lambda 兼容的 Docker 映像:

$ bentoctl build -b xgb_classifier:latest -f deployment_config.yaml

我们添加我们的便当的名称和版本,并通过deployment_config.yaml文件指定构建规范。该过程应该如下所示:

作者 GIF

如果您收到botocore.exceptions.ClientError,那么 AWS 凭证没有正确设置。再回到那一步。

如果映像构建成功,您应该会看到如下所示的输出:

作者图片

最后,我们使用 Terraform 将图像推送到 AWS Lambda 函数。使用以下命令:

$ terraform init
$ terraform apply -var-file=bentoctl.tfvars -auto-approve

作者 GIF

最后,您将看到下面的消息,它显示了我们部署的 Lambda API 的 URL:

作者图片

显示 UI 需要一段时间,但完成后,当您单击链接时,将会看到 API 文档:

第一次启动时,链接会显示一条内部服务器错误消息。忽略它。

作者图片

但是它将立即可用于发送请求和获得预测:

结论

唷!考虑到我在开始时说过文章会很简单,这需要很多步骤。但是,由于我们手头有现成的 ML 解决方案,这一切都是值得的。

将模型部署为 API 是让用户与模型交互的最佳方式之一。以 Dalle-E 或 GPT-3 等著名服务为例。两者都是暴露在一个简单的 API 下的大规模模型,并放在一个网站内。使用本文中的技术,您可以创建相同的产品,尽管一开始它们可能不是十亿参数模型。

感谢您的阅读!

https://ibexorigin.medium.com/membership https://ibexorigin.medium.com/subscribe

更多来自我的故事…

</25-advanced-pandas-functions-people-are-using-without-telling-you-b65fa442f0f4> </25-numpy-treasures-buried-in-the-docs-waiting-to-be-found-60d8e17931cd> https://ibexorigin.medium.com/28-weekly-machine-learning-tricks-and-resources-that-are-pure-gems-1-8e5259a93c94

面向数据科学家的 GitHub 综合指南

原文:https://towardsdatascience.com/comprehensive-guide-to-github-for-data-scientist-d3f71bd320da

通过 UI 和命令行为数据科学家提供的 GitHub 教程


罗曼·辛克维奇·🇺🇦Unsplash 拍摄的图像

本文的目的是向数据科学家/分析师(或任何非工程专业人士)简要介绍如何使用 GitHub 以及应遵循的最佳实践。本教程将包含使用 UI 和命令行(终端)的组合指南。Git 命令的命名约定在 GitHub 提供的*台上是一致的,因此如果您更喜欢使用 Github desktop 或 GitLab 而不是 web UI 或命令行,这些技能应该是可交换的。以下是文章的提纲。

目录

  • 为什么要用 GitHub?
    -什么是版本控制?
  • 创建帐户和 Git 安装
  • 创建存储库
    • Git 忽略&环境文件
      -授权访问
  • 基础 Git 命令
    -克隆存储库
    -状态
    -添加文件
    -提交文件&提交消息
    -推送变更
    -拉取变更
  • 合并冲突
  • 检查文件版本历史
  • ReadME.md 的重要性
  • GitHub 背后的直觉
  • 结束语
  • 资源

为什么要用 GitHub?

GitHub 或任何版本控制软件对于任何软件开发项目都很重要,包括那些数据驱动的项目。GitHub 是一个软件,它允许通过一个叫做 Git 的工具对你的项目进行版本控制。它允许用户分发代码、在项目上协作、通过 CI/CD(持续集成/持续部署)帮助项目的部署、恢复到项目的先前版本等等。如果有多个人在同一个项目上合作,那么使用 GitHub 尤其重要。对于行业专业人士和为开源项目做贡献的个人来说,这是一种很常见的情况。

使用 GitHub 不仅从行业角度来看很重要,而且它也是展示你在科技行业求职技能的有力工具。它让潜在的雇主看到你目前拥有的技能水*,你参与过的项目,你编写代码、文档和解决问题的能力。它是许多有抱负的软件工程师、数据科学家、分析师、研究人员等使用的不可或缺的工具。来帮助他们找工作。

什么是版本控制?

版本控制本质上就像它的名字一样,你控制着你正在工作的项目的版本。如果您引用许多流行的开源项目,如 Airflow 或 Pandas,当您安装它时,它们有各种相关的版本,每个版本都有不同的实现&在特定的时间点对项目的更改。

创建帐户和 Git 安装

创建一个 GitHub 帐户并在命令行上安装 Git 相当简单明了。

你可以进入与 GitHub 相关的注册页面,用你的邮箱创建一个账户。请注意,如果你是一名学生/有一个学生电子邮件,注册它可以免费访问 GitHub 上的升级计划。

要在命令行上下载 Git,您可以参考下面的网站并下载与您的计算机相关的适当文件。根据提示提供的建议配置下载,应该不会有任何问题。要检查您是否已经在命令行中成功安装了 Git,您可以打开您的命令行/终端并键入git --version。这将返回如下内容:

git version 2.30.1 (Apple Git-130)

这表明 Git 已经成功安装在您的计算机上,现在您可以使用 Git 命令了。

将 Git 链接到您的帐户

运行以下命令将允许您通过 Git 连接到您的 GitHub 帐户。

git config --global user.email "[you@example.com](mailto:you@example.com)"
git config --global user.name "your name"

创建存储库

创建 GitHub 资源库有两种方法。您可以在本地计算机上创建一个文件夹并初始化它(通过在命令行中导航到该文件夹并键入git init)或者您可以使用 UI 来创建 repo。我将向你展示如何使用 UI,因为它允许你用一个简单的项目模板进行初始化,该模板包括gitignoreREADME.md文件。

要创建一个新的资源库,请导航到您的 GitHub 帐户上的资源库部分,然后按下按钮New。如果您找不到存储库部分,可以根据您的帐户更新以下 url:

[https://github.com/<USER_NAME>?tab=repositories](https://github.com/vatsal220?tab=repositories)
- Replace `<USER_NAME>` with your GitHub username or visit [https://github.com/new](https://github.com/new)

在 GitHub 上创建新存储库的位置。图片由作者提供。

点击New,您将被要求提供存储库的名称、描述、隐私设置、自述文件、gitignore 和许可证。您需要填写的唯一必填字段是Repository Name。根据您的工作地点,您可能需要为您的项目遵循特定的命名约定。根据经验,您应该将您的存储库命名为您将要工作的项目的缩写描述符。应该简短明了。然而,请注意,有许多流行的开源存储库并不遵循这种命名约定。

明智的做法是提供一个描述,并用 README.md 文件和 gitignore 文件初始化您的存储库。README.md 文件将由您提供的描述组成。我已经为 Python 使用了提供的 gitignore 模板。如果愿意,您也可以添加许可模板。如果你正在做一个开源项目,添加一个许可文件是非常重要的。

为了让你的库真正开源,你需要许可它,这样其他人就可以自由地使用、修改和分发软件。
-https://docs . github . com/en/repositories/managing-your-repository ys-settings-and-features/customizing-your-repository/licensing-a-repository[1]

我为本文创建的存储库。图片由作者提供。

准备好后,点击Create repository。在创建时,下面应该是你所看到的。

git——使用作者提供的 README.md 和. gitignore. Image 创建的教程存储库。

请注意,每个 GitHub 存储库都有一个空间限制,表明目录的大小不得超过 free & pro 帐户的最大阈值 2GB(根据他们的文档)。因此,如果您正在处理像机器学习模型或大型 CSV 这样的大文件,不建议将这些结果上传到 GitHub。如果您没有使用 AWS,最好将这些结果上传到您的 S3 桶或等效物中。

Git 忽略环境文件

gitignore文件所做的是忽略特定的文件,不将其推送到 GitHub 存储库。当您在处理包含高度敏感信息的项目时,这一点至关重要,例如包含用户信息、API 凭证、数据库凭证等的 CSV。无论回购是公开的还是私有的,这都是您不希望推送到存储库的信息。

当您在 Python 中使用 API 凭证时,最好使用环境文件。环境文件本质上是一个文本文件,它包含运行项目所需的环境变量的键值对。例如,如果您通过 Python 中的boto3连接到 AWS,您将需要 AWS 秘密密钥和 AWS 秘密访问密钥。然后,您将创建一个保存该信息的.env文件,如下所示:

secret_key='my secret key'
secret_access_key='my access key'

你可以通过像os[python-dotenv](https://pypi.org/project/python-dotenv/)这样的库在你的代码中访问这个文件。请注意,当您用gitignore文件初始化存储库时,它不会自动将.env和其他敏感文件包含在其中。这是您必须手动更新的内容。

授予访问权限

如果你正在与他人合作,教程的这个部分是非常重要的。在机构工作的时候比较常见。要将一个合作者或一个合作者团队添加到项目中,您首先需要进入该存储库的设置。然后,您可以单击左侧边栏上的协作者选项。最后,您可以通过搜索来添加人员/团队,并邀请他们参与项目协作。

关于如何将协作者添加到存储库中的指南。图片由作者提供。

基本 Git 命令

有 6 个基本的 git 命令,每个人都应该知道这是软件的基础。这些命令如下所示:

git clone
git status
git add
git commit
git push
git pull

请注意,通过使用 UI 或 GitHub 桌面,您可以在不了解这些命令的情况下使用 GitHub 的全部功能。出于本教程的目的,我将向您展示如何通过终端/命令行使用这些命令。

此外,请注意,这些并不是 Git 提供的所有命令,还有更多命令与 UI / GitHub 桌面上产品的各种功能相关联。这些是您在大多数数据驱动项目中需要用到的最基本的方法。

克隆存储库

克隆存储库将允许您将存储库的内容下载到本地计算机。要克隆存储库,您需要存储库 URL 或 SSH 密钥。你可以通过点击“代码”按钮找到网址,并把网址复制到 HTTPS 部分(如下所示)。

在哪里可以找到存储库 URL。图片由作者提供。

然后导航到您的命令行,您可以在您想要的位置克隆(下载)这个存储库。键入以下命令:

git clone <url>
- Where `<url>` is the URL associated with your repository. I'll be running the following command to clone this tutorial.git clone [https://github.com/vatsal220/git-tutorial.git](https://github.com/vatsal220/git-tutorial.git)

将 GitHub 库克隆到您的本地计算机上。图片由作者提供。

现在您已经成功地克隆了存储库。您应该能够在自己选择的 IDE 中打开它。

状态

运行git status命令将允许您检查本地目录中所做的更改。它将指示文件已被创建/修改/删除。

我创建了一个名为test.py的新文件,其中有一行代码打印 hello world。我还更新了gitignore文件,添加了以下内容:

# Environment files
.env

导航到链接到这个存储库的适当目录后,我可以运行git status。以下是您应该看到的结果:

检查目录状态是否有任何文件更改。图片由作者提供。

显示.gitignore文件已被修改,test.py文件未被跟踪。未跟踪的文件本质上表明它是一个以前在项目中没有见过的新文件。

添加文件

随着项目的进展,您可能希望更新您的存储库。这就是git add命令允许你做的事情。该命令表示存储库中已经进行了更改。它表示您希望在下一次提交时更新文件。

您可以通过运行以下命令来单独添加文件:

git add <file name>
- Where `<file name>` is the name of the file you want to add.git add .gitignore
git add test.py

或者,您可以运行以下命令来表明您想要添加对存储库所做的所有更改:

git add .

添加文件后,您可以再次检查状态。它应该表明这些文件已经被添加并准备好提交。

将文件添加到项目后文件的状态。图片由作者提供。

提交文件和提交消息

编写好的提交消息对于任何项目都是至关重要的。当你浏览项目的历史,查看进展的不同阶段,看看你以前做了什么,有一个好的提交消息将节省你大量的时间。提交信息应该简短,并且与你对项目所做的改变直接相关。例如,一个错误的提交消息应该是这样的:updated project。虽然这是准确的,但它显然不会产生任何有用的信息。一个好的提交消息应该是这样的:added .env to gitignore and created test file

以下是在终端/命令行中编写提交消息的约定:

git commit -m "<your message>"
- Replace `<your message>` with the commit message. This message should be in quotes.git commit -m "added .env to gitignore and created test file"

与我添加到项目中的文件相关联的提交消息。图片由作者提供。

推动变革

现在,为了让这些更改被记录下来并在 UI 中可见,您需要推送它们。这可以使用git push命令轻松完成。

将变更推回存储库。图片由作者提供。

现在检查 UI 中的存储库,您应该看到文件已经被添加/修改。您将看到与更改相关联的最新提交消息以及与最*更改相关联的时间。

在推送更改后,在 web UI 中显示存储库中的更改。图片由作者提供。

有一个推送内容的最佳实践列表,尤其是当您处理与生产环境相连接的存储库时。对于大多数数据科学家/分析师来说,情况并非如此,因此它不应该太适用于本文的目标受众,但是如果您感兴趣,这篇文章清楚地概述了最佳实践。我想强调的一个最佳实践是,在开发过程中,您应该定期提交和推动变更。不仅仅是在你完成了文件/项目之后。提交和推送应该是频繁的,并且应该突出项目中的持续变化和进展。

拉动变化

类似于我们刚刚将变更推送到我们的存储库,我们也可以拉取其他贡献者所做的变更。最佳实践是在进行新的开发之前检查存储库,查看项目是否有任何变更,如果有变更,那么将变更提取到您的本地存储库。

例如,如果我让这个项目的另一个贡献者创建一个名为setup.py的新文件,那么我可以运行git pull命令来指示执行一个拉请求。运行以下命令将允许您获取其他贡献者对存储库所做的更改。

git pull origin main
- The word `main` reflects the name of the branch I am pulling from. Unless you've created a new branch, the name of the current branch you're working on will either be `main` or `Master`.

提取其他贡献者对存储库所做的更改。图片由作者提供。

合并冲突

当有多个合作者时,GitHub 中的冲突是很常见的。当多个合作者更改与同一文件相关联的代码时,会发生合并冲突。Git 无法识别哪个版本的代码是正确的,因此解决这个问题的唯一方法是通过手工检查每个合作者所做的更改。合并分支时,这些冲突很常见。

检查文件版本历史

您可以通过查看提交历史来检查与文件相关联的版本历史。这将允许您查看与该文件相关的代码中的差异。它将显示添加的内容(以绿色突出显示)和删除的内容(以红色突出显示)。要导航到提交历史,请单击下面以蓝色突出显示的提交按钮。

导航到与项目关联的提交历史记录的指南。单击提交按钮。图片由作者提供。

这会将您带到一个页面,该页面包含提交、时间戳和提交消息的列表。您可以导航到任何提交,并查看与该推送相关的项目中的差异。

与项目关联的提交历史记录。图片由作者提供。

正如您在下面看到的,与我们刚刚推送的提交消息相关联。它包括对.gitignoretest.py文件所做的更改。用绿色突出显示(在右手边),这表明我们向 gitignore 添加了.env,向测试脚本添加了print("hello world")。在左侧,我们可以看到这些文件在包含这些更改之前的样子。

与提交相关的版本差异。图片由作者提供。

正如本文开头所指出的,这是 GitHub 最重要的方面之一,也是它如此有用的原因。

ReadME.md 的重要性

通常,当用户导航到一个新项目时,自述文件是开发人员浏览的第一个文件。这个文件应该提供关于项目的上下文信息,以及如何运行适当的脚本/复制结果。如果复制结果需要环境文件和环境变量,自述文件应该明确指出这一点。如果没有自述文件,对于不熟悉该项目的人来说,找出如何重现从中生成的结果就变得很麻烦。

下面这个由 othneildrew 创建的存储库包含一个模板用于一个优秀的自述文件。请随意查看并将其用于您的项目。

GitHub 背后的直觉

让我们围绕 GitHub 背后的直觉来结束这篇文章,因为现在您应该熟悉它的基本命令和大多数最佳实践。您可以将每个 GitHub 存储库想象成一个图,其中初始节点是与其相关联的第一个提交。那么每一个进行中的提交都会用一个新的节点来扩展该图,本质上是将以前版本的存储库连接到当前版本。查看与项目相关的版本历史与识别一个节点相对于另一个节点所做的更改是一样的。

在存储库中创建一个新的分支与向图中的最新节点添加一个新的叶子是一样的。该新叶可以通过分支中的附加提交和推送来扩展。合并回初始流程,您将会把新开发的分支中的变更合并到初始分支中。下面可以直观地看到整个过程:

与 GitHub 存储库相关的示例树结构。图片由作者提供。

结束语

本教程中没有提到各种命令。git loggit diff仅举几个例子。在我看来,学习新事物的最好方法是投入进去,亲自尝试。使用 UI、GitHub Desktop、Git 和其他资源来完成你正在做的项目。这将极大地提高你的技能和未来合作的能力。Git 是一个文档非常丰富的资源,如果你感到困惑或者只是好奇,我强烈推荐你访问他们的网站

在我的 GitHub 页面这里,你可以随意查看与本教程相关的资源库。

如果你想转型进入数据行业,并希望得到经验丰富的导师的指导和指引,那么你可能想看看最敏锐的头脑。Sharpest Minds 是一个导师*台,导师(他们是经验丰富的实践数据科学家、机器学习工程师、研究科学家、首席技术官等。)将有助于你的发展和学习在数据领域找到一份工作。点击查看它们

资源

如果你喜欢读这篇文章,我写的其他文章你可能也会喜欢。

[## 贝叶斯 A/B 测试解释

towardsdatascience.com](/bayesian-a-b-testing-explained-344a6df88c1a)

MlFlow 综合指南

原文:https://towardsdatascience.com/comprehensive-guide-to-mlflow-b84086b002ae

使用 ML Flow 跟踪数据科学项目的 ML 工作流

图片由麦特·哈迪Unsplash 拍摄

从事数据科学项目时的一个常见问题是,随着您运行越来越多的实验,跟踪您的机器学习模型的性能。 MLFlow 是一个开源的 Python 库,帮助开发者跟踪与各种应用相关的各种实验,包括但不限于经典机器学习、自然语言处理、推荐系统、时间序列分析等。本文将提供一个深入的教程,介绍如何使用 MLFlow 来优化项目的实验组件。以下是文章的结构:

目录

  • 机器学习工作流
  • 什么是 MLFlow?
    -跟踪
    -项目
    -模型
    -注册
  • 装置
  • 教程
    -需求
    -预测脚本
    -使用 MLFlow 更新预测脚本
  • MLFlow GUI
  • 结束语
  • 资源

机器学习工作流

机器学习工作流程通常由 4 个步骤组成。首先是原始数据,然后是数据预处理和特征工程,接着是模型开发,最后是部署。可以想象,这个生命周期是一个由许多要运行的实验组成的迭代过程。MLFlow 的重点主要放在模型开发上,您希望将性能最好的模型推向生产。即使选择并部署了最佳模型,最好的做法是引入一个监控系统来跟踪模型的性能,以确定何时需要重新培训。每个数据科学项目都会出现这种迭代过程,当个人同时从事多个项目时,或者当您稍后重新访问一个项目时,很难跟踪/调整这一过程。这就是机器学习工作流棘手和困难的原因,MLFlow 有助于解决上面提到的许多痛点。

机器学习生命周期。图片由作者提供。

什么是 MLFlow?

MLFlow 是一个开源库,帮助数据和研究科学家优化他们的机器学习工作流程。它由 4 个部分组成,跟踪,项目,模型和模型注册。该工具旨在与任何流行的开源机器学习库结合使用,包括 Sci-Kit Learn、PyTorch、Keras、TensorFlow 等。该库的使用有助于数据驱动的研究人员和科学家使他们的项目可被他人复制和重用。

跟踪

MLFlow 的跟踪组件指的是在构建机器学习管道时记录参数、性能/其他指标、版本和其他工件[1]。当进行大量实验时,以有效的方式跟踪与每个实验相关的参数和性能指标对于识别最佳性能参数至关重要。该组件易于设置,并与笔记本和脚本兼容。MLFlow 的跟踪功能是连接 MLFLow 其他组件的基础。

项目

MLFlow 的这一组成部分旨在帮助其用户实现与他们正在进行的项目相关的再现性。将该组件与 GitHub 等版本控制软件结合使用,可以最大限度地发挥其功能。将此组件与 MLFlow 跟踪结合使用,将允许 MLFLow 记住项目版本和所有跟踪的参数[1]。该组件将其结果保存在一个通常称为mlruns的文件夹中,该文件夹由 MLFlow 创建。这个文件夹可以被推送到你的 GitHub 库,因为它不应该包含任何敏感信息。

模型

MLFlow 的建模组件指的是已开发模型的打包以及与它们相关的辅助部署。它兼容各种基于云的工具,包括 Azure、AWS (SageMaker),以及 Docker 和 Airflow 等服务。它允许将模型保存并加载为.sav.pkl文件,以供日后参考使用。

登记处

MLFlow 的注册组件旨在帮助管理 MLFlow 生命周期。

它提供了模型沿袭(MLflow 实验和运行产生了模型)、模型版本化、阶段转换(例如从阶段转换到生产或归档)和注释。
【1】https://www.mlflow.org/docs/latest/concepts.html

装置

MLFlow 的安装过程非常简单,您可以依靠 pip 并在您的终端/命令行中运行pip install mlflow,或者转到他们的 GitHub 存储库并将其克隆到您的本地计算机上。安装后,您可以在终端/命令行中运行命令mlflow --version来确认它已经安装在本地。

用于本教程的 MLFlow 版本。图片由作者提供。

辅导的

我将概述如何使用 MLFlow 更新现有的模型训练过程。

要求

我正在使用的 Python 的当前版本是 3.8.8,在本教程中需要以下软件包:

mlflow=1.25.1
numpy=1.20.1
sklearn=0.24.1

预测脚本

上面的代码显示了如何构建一个梯度推进分类器来预测用户的年龄范围。该脚本将自动生成随机数据集,训练模型并评估模型的性能。

使用 MLFlow 更新预测脚本

上面的脚本显示了包含 MLFlow 功能的预测脚本的更新。使用了几个不同的函数:

  1. mlflow.start_run
    该功能指示新运行的开始,它将跟踪指标和参数。如果您想要引用一个现有的运行,那么您可以传递与该运行相关联的run_id
  2. mlflow.log_metric
    该功能将记录当前活动运行下的一个指标。在上面的脚本中,我们记录了训练模型后生成的准确性指标。
  3. mlflow.log_param 该功能将记录当前正在运行的参数。在上面的脚本中,我们记录了用于训练模型的参数。
  4. mlflow.sklearn.log_model
    记录当前运行下的 scikit-learn 模型。在上面的脚本中,我们将 GradientBoostingClassifier 模型保存为 sklearn 模型。
    注:ml flow 支持的其他流行的机器学习库还有很多。这些库包括 TensorFlow、PyTorch 等。

MLFlow 内置了上面没有提到的各种其他函数。这些是用于任何通常的分类/回归相关管道的主要指标。MLFlow 确实为各种人工智能领域提供了相当广泛的支持,包括推荐系统、计算机视觉、自然语言处理等。

运行更新的脚本将在目录中创建一个名为mlruns的新文件夹,该文件夹将保存记录的值、模型等。对于每次运行。这允许您在给定一些特定参数的情况下比较哪些运行具有更好的结果。

本地目录中 mlruns 文件夹的位置。图片由作者提供。

您可以手动检查文件夹,也可以通过 GUI 查看结果,GUI 有一个很棒的 UI。

MLFlow GUI

要初始化贵由,只需在终端/命令行中运行命令mlflow ui。应该出现的是一个到本地主机服务器的链接,该服务器保存着与每次运行相关联的日志模型、参数和指标。

MLFlow GUI 的初始化。图片由作者提供。

转到链接http://127.0.0.1:5000将引导您进入以下页面:

MLFlow GUI。图片由作者提供。

点击任何一次运行,您将进入以下页面:

MLFlow GUI 显示参数、度量、模型等。图片由作者提供。

您可以比较所有运行的参数和指标,因为我们已经记录了模型,所以我们也获得了关于如何为未来的管道加载和使用模型的相当多的信息。模型是一个下拉菜单,包括模型信息、与 conda 环境相关的 yaml 文件、模型和需求的可下载 pickle 文件。

GUI 中的模型分解。图片由作者提供。

这可能是这个模块最有用的特性之一。在比较结果以查看哪个模型具有最佳准确性之后,我们可以轻松地下载与最佳性能相关联的模型。然后,这个模型可以很容易地输入到与项目相关的生产管道中。

结束语

本教程展示了如何使用 MLFlow 更新现有的模型训练和预测管道,以跟踪各种参数、指标和日志模型。它有助于与用户相关的机器学习生命周期,因为记录实验结果更加有效和容易。

请在我的 GitHub 页面这里查看与本教程相关的资源库。

如果你想转型进入数据行业,并希望得到经验丰富的导师的指导和指引,那么你可能想看看最敏锐的头脑。Sharpest Minds 是一个导师*台,导师(他们是经验丰富的实践数据科学家、机器学习工程师、研究科学家、首席技术官等。)将有助于你的发展和学习在数据领域找到一份工作。在这里查看。

资源

如果你觉得读这篇文章有用,这里是我写的其他文章,你可能也会觉得有用。

https://pub.towardsai.net/community-detection-with-node2vec-6cd5a40c7155

主成分分析综合指南

原文:https://towardsdatascience.com/comprehensive-guide-to-principal-component-analysis-bb4458fff9e2

主成分分析的理论解释

当您想要减少大型数据集中的变量数量时,可以使用主成分分析(简称:PCA)。PCA 试图只留下那些在数据集中仍然解释大部分方差的变量。因此,与其他特征强烈相关的所有特征都被移除。

我们什么时候用主成分分析?

数据集具有相互相关的变量,即相互依赖时,各种算法,如线性回归,会出现问题。对于这样的模型,重要的是我们在不减少数据的信息内容的情况下减少维度。

PCA 的另一个应用是在聚类分析中,比如 k-means 聚类,我们需要预先定义聚类的个数。减少数据集的维度有助于我们获得信息的第一印象,并能够估计,例如,哪些是最重要的变量,以及数据集可能有多少个聚类。

PCA 是如何工作的?

主成分分析的核心思想是,一个数据集中可能有几个变量测量同一事物,即相关的。因此,不同的维度可以组合成更少的所谓主成分,而不会损害数据集的有效性。例如,体型与鞋码有很高的相关性,因为在许多情况下,高个子也有较大的鞋码,反之亦然。因此,如果我们把鞋码作为一个变量从数据集中去掉,信息量并没有真正减少。

统计中,一个数据集的信息量是由方差决定的。这表示数据点离中心有多远。方差越小,数据点越接**均值,反之亦然。因此,较小的方差表明*均值已经是数据集的良好估计值。

在第一步中,PCA 试图找到最大化数据集的解释方差的变量。然后,逐步添加更多的变量来解释方差的剩余部分,因为方差,即与均值的偏差,包含了最多的信息。如果我们想基于它训练一个模型,就应该保留它。

第一步,主成分分析试图找到一条尽可能使它和数据点之间的距离最小的直线。该程序与线性回归中的程序相同。因此,该线是数据集所有单个特征的总和,并形成第一主成分。

第一主成分|图片:作者

然后尝试创建与第一主分量正交(即垂直)的第二条线,并再次最小化到数据点的距离。这些线必须彼此正交,因为主成分不应该彼此相关,并且因为垂直线也很可能解释不包含在第一成分中的方差。

目标是多少个主成分?

基本上,在主成分的数量和剩余的信息内容之间有一个相关性。这意味着,随着更多的组成部分,你也解释了更多的差异,从而有更多的信息包含在数据集中。而极少的成分,则意味着维度大大降低了,这就是主成分分析的目的。

然而,根据 Kaiser (1960 ),有一个很好的参考点,根据这个参考点可以选择组件。应该只选择方差大于 1 的主成分。因为只有这些成分比数据集中的单个变量能解释更多的变化,这可能并确实导致维数减少。

如何解释主成分?

主成分本身很难解释,因为它们是各维度的线性组合。因此,它们代表了几个变量的加权混合。但是,在实际应用中,这些变量的组合也可以具体解释。

例如,考虑一个包含各种个人信息的数据集,比如年龄、体重、身高、信用度、收入、储蓄和债务。例如,在这个数据集中,可能出现两个主要成分。第一个主成分大概由信用度、收入、储蓄和债务等维度组成,这些变量的系数很高。例如,这个主成分可以被解释为这个人的财务稳定性。

主成分分析我们需要什么要求?

与类似的统计分析相比,为了获得有意义的结果,主成分分析只有几个必须满足的要求。数据集应具备的基本属性有:

  • 特征之间的相关性应该是线性的。
  • 数据集应该没有异常值,即严重偏离质量的单个数据点。
  • 如果可能,变量应该是连续的。
  • 样本越大,PCA 的结果越好。

并非所有的数据集都可以直接用于主成分分析。必须确保数据*似为正态分布和区间比例,即两个数值之间的区间始终具有相同的间距。例如,日期是按时间间隔计算的,因为从 1980 年 1 月 1 日到 1981 年 1 月 1 日的时间间隔与从 2020 年 1 月 1 日到 2021 年 1 月 1 日的时间间隔相同(闰年除外)。最重要的是,区间缩放必须由用户自己判断,并且不能通过标准化的统计测试来检测。

Python 中的主成分分析

有许多程序可以自动计算主成分分析,并且可以将结果与不同数量的成分进行比较。在 Python 中,这在模块“Scikit-Learn”的帮助下工作,在这里我们还将仔细查看其示例

在该应用中,使用了所谓的虹膜数据集。这是机器学习领域中一个流行的训练数据集。这是来自生物学的数据,更精确的信息来自所谓的鸢尾属植物。对于每一朵花,花瓣的长度和宽度以及所谓的萼片都是可用的。我们将有关植物的信息存储在变量 X 中,将相应花朵的名称存储在变量 y 中。

在我们的例子中,我们试图将这四个维度减少到三个主要部分,以便能够在三维图中可视化它们。数据的实际转换发生在三行代码中。首先,我们需要设置一个 PCA 对象,其中包含所需数量的组件。然后,我们可以将其应用于我们的数据集,并最终将四维值转换为三维值:

在 Matplotlib 的帮助下,我们的结果可以在三维图中可视化,并且可以看到,即使在三维空间中,同一花卉物种的植物仍然彼此接*。因此,数据集的真实信息内容没有丢失。

主成分分析和虹膜数据集|图片:作者

这是你应该带走的东西

  • 主成分分析用于大型数据集中的降维。
  • 它有助于基于它的机器学习模型的数据预处理,如聚类分析或线性回归。
  • 数据集中必须满足某些先决条件,PCA 才有可能实现。例如,特征之间的相关性应该是线性的。

关于主成分分析主题的其他文章

  • 你可以在我们的同事 Studyflix 找到关于主成分分析的详细解释,包括一个说明性的视频。
  • 对驱动因素分析的已知、当前和新的要求。载于:凯勒等人(编辑。):Marktforschung der Zukunft——门还是机器?,威斯巴登,2016 年,第 231–243 页。
  • 电子计算机在因素分析中的应用。载于:教育和心理测量,1960 年第 1 期,第 141-151 页。

如果你喜欢我的作品,请在这里订阅https://medium.com/subscribe/@niklas_lang或者查看我的网站* 数据大本营 !还有,medium 允许你每月免费阅读 3 篇 。如果你希望有无限制的 访问我的文章和数以千计的精彩文章,不要犹豫,点击我的推荐链接:【https://medium.com/@niklas_lang/membership】每月花$5***获得会员资格**

* *

真实世界中 Python 日志的综合指南第 1 部分

原文:https://towardsdatascience.com/comprehensive-guide-to-python-logging-in-the-real-world-part-1-8762d5aa76da

基础知识、生命周期、层次结构、陷阱和最佳实践

照片由 Unsplash 上的 Dariusz Sankowski 拍摄

Python 日志模块是现实生活中日志记录的首选机制。它使用起来非常简单,但是当日志失败时,很难理解为什么,除非你完全理解生命周期和细微差别。在本系列的第一部分中,您将从逻辑上理解日志模块的内部工作方式——层次结构、生命周期和工作方式,以及支持理解的小代码片段。那些有可能让你的生活变得痛苦的陷阱都在前面列出来了。在第二部分中,您将了解 python 日志记录的首选使用模式、各种日志记录配置方法,以及最重要的是,如何有效地使用日志记录进行异常处理,最后一部分将介绍典型应用程序堆栈中 python 异常处理的最佳实践。事不宜迟,我们从一个哲学问题的简短答案开始:既然有方便的 print ()为什么要进行日志记录,然后直接跳到所有日志记录操作的中间。

为什么要伐木

想象一下,一个被数百或数千并发用户访问的多用户应用程序使用 print ()方法向 stdout 发送定制的消息。以下是关于 print ()的潜在问题以及 python 日志记录如何解决这些问题。

  1. 对日志消息持久性的控制:传统系统没有人看 print ()发送到 stdout/stderr 的输出。这些消息可能会凭空消失,或者没有机制在以后的某个时间点检索它们以进行分析和故障排除。Python 日志让我们透明地将消息发送到不同的持久目的地(比如一个文件),而不影响用户在应用软件中调用的底层 API。软件开发者仍将继续调用 logger.info ()、 logger.warn ()等。但是消息会到达不同的目的地。[这种对使用 print ()的反对现在已经不太相关了,因为现代应用程序堆栈使用 docker、AWS redirect stdout 等容器。到选择的目的地—分别是 json 或纯文本日志文件和 cloudwatch 日志]
  2. 细粒度控制 : 打印()输出没有严重性概念的普通文本。Python 日志记录具有内置的六级日志消息严重性概念和定制选项。该控件有助于从日志文件中过滤具有特定或更高严重性的日志消息,并忽略较低严重性的消息。
  3. 功能性和非功能性方面的分离:如果我们想将一个非常冗长的模块的输出限制为只有警告和错误消息,而没有代码中根深蒂固的 if-else 块,那么就没有办法使用 print ()。使用 python 日志模块,可以在应用程序之外对其进行声明式控制。一般来说,非功能方面与功能关注点是正交的,应该在功能软件之外一起处理。优雅架构的这一方面是日志模块的核心设计目标。
  4. 分离内容和方式 : Python 日志记录是分离内容(记录)和方式(记录)的理想解决方案。如果仅仅是为了打印(),第三方库将无法登录到通常由应用软件在连接应用程序时使用库决定的不可预见的目的地。
  5. 特定于环境的日志:一个软件开发团队可能想要在不同的环境中记录不同的级别。例如,您可能希望在开发环境中看到调试和信息消息,而在生产环境中关闭它们可能是更好的选择。Python 日志中的声明性日志配置工具允许在不修改代码的情况下实现这一目标。
  6. 在日志中捕获用户上下文:我们通常想知道日志消息出现的时间。有时,知道哪个模块发出了某个日志消息对调试很有帮助。在多用户场景中,拥有线程 id、会话 id 等可以节省大量时间。在日志消息中,从数百万个日志行中隔离出实际错误的执行路径。这类似于众所周知的从干草堆里挑针的能力。
  7. 日志文件的旋转和归档:海量的日志文件很难读写。日志模块允许轻松地控制文件的大小,在特定大小或特定时间滚动文件,并存档旧日志。这些铃声和口哨声对故障排除非常有帮助,并且经常用于举几个例子。
  8. 商业智能:具有上述所有特性的经过深思熟虑的日志记录策略有助于生成关于软件使用情况的统计数据,检测异常情况,并消除安全事故。

好吧。为什么说得够多了。让我们继续讨论什么和如何做。

用伐木机把你的脚弄湿

开始记录很容易。只需使用日志中的内置方法之一——无论是调试()、信息()、警告()、错误()、关键()。下面的代码将消息This is a warning打印到控制台。

import logging

logging.warning("This is a warning") # prints message - This is a warning

然而,这不是你如何使用它。我们永远不会想直接从日志模块调用日志功能。我们总是先获得一个 Logger 对象,然后使用它进行日志记录,如下面的代码片段所示。

logger = logging.getLogger() # gets the root logger
logger.error("This is an error") # prints message - This is an error

# gets the logger with name mylogger
named_logger = logging.getLogger("mylogger")
named_logger.critical("Very critical") # prints message - Very critical

在上面的代码片段中可以看到两种风格的 getLogger ()。

  1. 不带任何参数的函数返回根日志记录器——原始日志记录器,即使没有显式配置也存在,并且在加载日志记录模块时可用。
  2. 随后的变化按需创建一个名为mylogger的记录器。如果名为mylogger的记录器已经存在,那么返回对那个预先存在的记录器的引用。

虽然记录器是一个类,可以直接实例化,但是强烈建议不要这样做,原因有二:

  1. 我们希望日志模块能够控制日志程序的生命周期(比如使用最后的日志处理程序等等)。—关于这一点的更多信息可以在本文后面找到)
  2. 我们希望 python 运行时通过在全局字典中保留日志的引用来重用日志

最佳实践:应用程序和模块不应该使用根日志记录器直接记录。应为应用程序和模块配置特定的记录器。

日志记录级别

根据日志消息的严重性定义了五个日志记录级别。它们分别对应于五个记录器方法调试()、信息()、警告()、错误()、关键(),数值分别从 10 到 50,以调试<信息<警告等等。日志级别表示消息的重要性(或严重性)。

使用 Logger.setLevel()方法将日志级别分配给记录器,如下所示:

# gets the logger with name mylogger
named_logger = logging.getLogger("mylogger")
named_logger.setLevel(logging.WARN)

named_logger.warn("I am warning you") # prints message - I am warning you

named_logger.info("FYI") # this is not printed

分配给记录器的级别充当严重性标记阈值。任何记录低严重性消息的尝试都会被忽略。在上面的代码片段中,记录器级别被设置为 WARN。因此,记录器将打印严重性至少为 WARN(或更高)的消息。严重性较低的消息,即调试和信息被忽略——就好像它们从未被调用过一样。

如果记录器上没有设置级别,那就太意外了!它的默认日志记录级别是 NOT_SET,数值为 0,不会记录任何消息。

突击测验:在这篇文章的前两个代码片段中,我们从未设置任何明确的日志级别,但是警告日志消息被打印出来。您可能认为这可能是因为默认的日志级别是 WARN。然而,这与我之前的默认日志级别= NOT_SET 的说法相矛盾。这是交易。的确,WARN 是 root logger 的默认日志级别,但不是其他日志级别。这个第 22 条军规的完整答案需要等到你读到这篇文章中关于日志层次结构的部分,以及有效日志级别的概念。坚持住!

自定义级别

Python 日志作为一个可扩展的模块,允许您定义自己的级别。但是它们在大多数情况下是不必要的,因为现有的级别是根据以前的使用情况选择的。但是,如果您觉得需要自定义级别,以下是添加自定义级别的快速方法。优选地,在任何日志记录开始之前,将该代码放置在应用引导逻辑中

import logging
FATAL_LEVEL_NUM = 60
logging.addLevelName(FATAL_LEVEL_NUM, "FATAL")
def fatal(self, message, *args, **kwargs):
    if self.isEnabledFor(FATAL_LEVEL_NUM):
        self._log(FATAL_LEVEL_NUM, message, args, **kwargs) 

logging.Logger.fatal = fatal

# Now you can use the fatal
named_logger = logging.getLogger("mylogger")
named_logger.setLevel(logging.WARN)
named_logger.fatal("A fatal error indeed")

最佳实践:如果您正在开发 python 库,尤其是供其他应用程序使用的第三方库,而您事先并不知道,那么尽可能避免在库中定义和使用自定义日志级别。自定义级别的语义有待解释,并影响分配的数字级别。这会导致库之间的混乱以及库和使用自定义级别的应用程序之间的摩擦。

python 日志的四大支柱

日志模块有四个主要的逻辑组件:记录器、处理器、过滤器和格式化程序。

  1. Logger 为应用程序代码提供了启动日志记录的函数。对于提供的每条日志消息,Logger 都会创建一条日志记录,并将其发送给相关的处理程序。记录器与一个日志记录级别相关联。记录器是日志记录的必要组成部分。
  2. 每个处理程序对应一个日志目的地。对应于多个目的地(文件、控制台等),可以将多个处理程序附加到一个记录器。).处理程序还与日志记录级别相关联(除了日志记录器中的级别之外,用于更好地控制每个目的地是否接收/忽略日志消息)。记录器必须至少有一个处理程序
  3. 过滤器是一个可选的工具,用于应用细粒度的逻辑来确定是处理还是丢弃日志记录。我们可以将日志记录级别看作是粗过滤器,决定日志记录器/处理程序是否接受日志消息。就像级别一样,过滤器可以与记录器及其处理程序相关联。
  4. 格式化程序指定输出中的日志消息的布局,并输出到目的地。自然,它是一个只与 Handler 相关联的构造。

图一。UML 图显示了日志模块的重要组件(图片由作者提供)

上面的图 1 捕获了 UML 图中所有四个重要的组件。如果你不懂 UML,没关系。你还是可以直观的跟着箭头走,感受一下关系。

  1. 记录器和处理程序都扩展了一个公共的父类。由于这种继承,记录器和处理程序都持有一个过滤器集合(零个或更多)。
  2. 记录器持有一个处理程序集合(零个或多个)
  3. 可以在记录器和处理程序上设置日志记录级别
  4. 处理程序只有一个格式化程序来格式化日志消息

突击测验:为什么在记录器和处理器上都有设置记录级别的选项?在 Logger 上设置日志级别的选项还不够吗?下面标题为“层级感知日志记录生命周期”一节中的最佳实践回答了这个问题。

简化的日志生命周期

既然我们已经理解了日志模块的重要结构组件,我们可以在层次结构中的固定级别上跟踪它们的交互。下一节将全面讨论层次感知交互。把这一部分当成是之后正餐的开胃菜。图 2 显示了当应用程序试图记录警告级别的消息时的流程。记录器、处理程序、过滤器和格式化程序在流中的角色是不言自明的。

图二。不考虑层级的简化日志记录过程(图片由作者提供)

最佳实践:尽管可以在记录器及其相应的处理程序上设置日志记录级别,但最好在记录器上设置级别,而不要在处理程序上设置日志记录级别。当一个记录器有多个附加的处理程序,并且我们希望每个处理程序(目的地)只记录来自记录器的消息的一个子集时,在处理程序上设置日志记录级别的选项是最有益的。例如,如果记录器级别设置为 INFO,并且有两个附加的处理程序(记录到 consile . sys . stderr 的流处理程序)和一个 FileHandler,并且我们只想在文件中记录错误消息,那么我们保留 Stream Handler 的级别不变,但是将 FileHandler 的级别设置为 error。

日志记录层次结构

Python 记录器形成了一个层次结构。根日志记录器位于层次结构的顶端。任何用名称 say myapp创建的记录器都是根记录器的子记录器。名为myapp.mymodule的记录器是myapp记录器的子代。

Logger 有一个重要的属性叫做 propagate 。默认情况下,其值为True

  1. 为 True 时,所有子记录器将日志消息传递给其祖先记录器的处理程序,通常向上传播到根记录器,在根记录器中配置了大多数处理程序。
  2. 当 propagate 设置为 False 时,子记录器仅将日志消息传递到其值设置为 False 的祖先记录器(或根记录器,以较早者为准)。

最佳实践:最好为大多数记录器保留默认值 propagate = True,并且只为某些顶级记录器、propagate = False 的记录器和根记录器配置处理程序。在没有显式处理程序的情况下,根据需要为每个模块创建子记录器。

app_logger = logging.getLogger("myapp")
module_logger = logging.getLogger("myapp.mymodule")
class_logger = logging.getLogger("myapp.mymodule.myclass")
print(app_logger.parent) # prints root
print(module_logger.parent) # prints myapp
print(class_logger.parent) # prints myapp.mymodule

注意点标记层次结构中那些缺失的父代

如前所述,名为myapp.mymodule的 logger 是myapp logger 的子代。然而,有一个问题。这假设了myapp记录器的存在。如果从未创建过myapp记录器,那么记录器myapp.mymodule将被创建为根记录器的子记录器!

class_logger = logging.getLogger("myapp.mymodule.myclass")
print(class_logger.parent) # prints root !!!

支持层次结构的日志生命周期

有了简化的日志生命周期和日志层次结构的知识,使用 Python 日志高级教程中的图表就不难理解完整的生命周期。

图二。层级感知完整日志生命周期(图片来自 Python 日志高级教程)

  1. 和以前一样,日志生命周期始于记录器接收到在适当级别记录消息的请求。
  2. 记录器确定是否可以继续执行指定的记录级别阈值,然后检查配置是否过滤了绿色信号。到目前为止一切顺利。然而,在这一点上,由于 propagate 被设置为 True,所以向前的流程略有不同
  3. 如果在当前层次结构中有显式配置的处理程序分配给记录器,则调用它们。
  4. 除了步骤 3 中的处理之外,日志记录器还将日志消息处理委托给其父日志记录器(如果存在),直到 propagate 设置为 False 或到达根日志记录器
  5. 递归地执行上述步骤 2、3 和 4,直到满足退出条件之一。
  6. 在第 3 步和第 4 步中,当日志消息处理传递给处理程序时,它会执行类似于第 2 步的检查。然而,在处理程序方面没有层次化的处理(就像与记录器相关的第 3 步和第 4 步)。无论哪个处理程序被要求做日志记录工作,都会毫不犹豫地去做。

最佳实践:从上面的层次化流程流可以清楚地看出,一个处理程序应该明确地绑定到一个日志记录器上。多个记录器不应该共享同一个处理程序引用(尽管这在技术上是可能的)。在多个记录器中使用同一个处理程序违背了实现逻辑分离的目的,而这正是最初设计多个记录器的目的。最好只为 propagate=False 或 root logger 的记录器显式配置单独的处理程序。除了是一个好的设计之外,这还有助于防止由于讨厌的重复记录到目的地而引起的混乱。

日志层次结构的重要含义

缺少处理程序、最后一个处理程序是两种行为边界情况,它们来自层级感知日志记录流程。但是最好将这种边界情况行为明确化,以避免混淆。

当使用 getLogger ()函数创建记录器时,记录级别设置为NOTSET。我们通常显式调用 setLevel ()来为层次结构中的某个日志记录者分配日志记录级别,但不是为所有的日志记录者。出现了两种情况

未找到记录器 XYZ 的处理程序

如果没有为整个记录器链显式设置日志记录级别,并且某个祖先记录器的 propagate = False,则日志消息会传播到父记录器,直到到达 propagate = False 的祖先记录器。如果 propagate = False 的祖先记录器 XYZ 具有适当的日志记录级别设置,但没有错误配置的处理程序,则提供错误消息“找不到记录器 XYZ 的处理程序”。

最后的处理者

如果未显式设置日志记录级别,并且 propagate = True,则日志消息会传播到父日志记录器。遍历父记录器链,直到找到一个级别不是NOTSET的祖先,或者到达根记录器。根日志记录器有一个默认的WARNING级别设置。默认情况下,root logger 还配置了一个最后处理程序。因为在根处没有其他处理程序,所以使用 lastResort 处理程序。这个 lastResort 处理程序是一个方便的处理程序,用于防止消息被完全忽略,并将警告级别的消息写入 sys.stderr。这就是为什么在几乎没有配置的情况下调用日志记录时,我们只能在控制台(Jupyter 笔记本或终端)中看到警告级别的消息。出于某种原因,如果您想要标记这种行为(如 Python 3.2 之前的版本),那么您可以将 lastResort 处理程序设置为 None,如下面的代码片段所示

import logging
rootLogger = logging.getLogger()
rootLogger.lastResort = None

# this shows a message - no handlers could be found for root
rootLogger.warning("Sample warning) 

有效测井水*

层次结构的另一个重要成果是有效的日志级别。正如您已经知道的,当使用 getLogger ()函数创建一个日志记录器时,日志记录级别被设置为NOTSET。如果子日志记录器没有设置级别,则日志记录模块沿着其父日志记录器的链向上移动,直到找到具有设置级别的日志记录器。这是子记录器的有效日志级别。因此,有效日志级别是日志记录器显然计划自己记录消息的级别。这个有效的日志级别或者等于显式设置的级别,或者等于其级别显式设置的最*的祖先,如下面的代码所示。

import logging

rootLogger = logging.getLogger() #logs at WARN level

# logging level not set explicitly in app_logger. Falls back to root level
app_logger = logging.getLogger("myapp")

# module_logger has the logging level set explicitly to INFO
module_logger = logging.getLogger("myapp.mymodule")
module_logger.setLevel(logging.INFO)

# logging level not set explicitly in class_logger
# falls back to paernt's level = INFO
class_logger = logging.getLogger("myapp.mymodule.myclass")

print(rootLogger.getEffectiveLevel()) # WARN
print(app_logger.getEffectiveLevel()) # WARN

print(module_logger.getEffectiveLevel()) # INFO
print(class_logger.getEffectiveLevel())  # INFO

总结和前进

这就是本期节目的全部内容。希望你喜欢阅读这篇逻辑和直觉优先的日志介绍,而不是事实优先的方法。在这一部分中,我们已经讨论了很多内容——从 hello world 开始,全面了解日志生命周期,发现其中的隐患,并总结相关的最佳实践。最精彩的部分还在后面。他们很快就会来。下一部分将涵盖使用模式、python 日志配置、有效的异常处理日志。在本系列的最后,我们将深入探讨 python 异常处理的最佳实践,并结合在实际应用程序堆栈中有效使用 python 日志记录。请留意他们。

数据科学家使用 Conda 的 Python 虚拟环境综合指南

原文:https://towardsdatascience.com/comprehensive-guide-to-python-virtual-environments-using-conda-for-data-scientists-6ebea645c5b

Conda via 终端虚拟环境指南

图片由罗伯特·祖尼科夫Unsplash 拍摄

本文将全面指导数据科学家如何使用 Conda 为您的项目创建、导出和使用虚拟环境。本教程将专门针对 Python 虚拟环境。下面概述了文章的结构。

目录

  • 什么是康达虚拟环境?
  • 为什么要使用虚拟环境?
  • 康达装置
  • 创建一个虚拟环境
    -通过命令行
    -通过环境文件
    -激活环境
    -停用环境
  • 环境列表
    -环境中已安装软件包的列表
  • 导出虚拟环境
  • 克隆虚拟环境
  • 删除虚拟环境
  • 结束语
  • 资源

什么是康达虚拟环境?

简而言之,虚拟环境就是位于您计算机上的一个目录,用于在一个隔离的位置运行您的脚本。您可以创建许多不同的虚拟环境,每个环境都是相互隔离的。这允许您用不同版本的不同包运行您的项目和代码。

有各种各样的服务提供给你创建虚拟环境,这些服务因编码语言不同而不同。特别是对于 Python,创建和使用虚拟环境的两种最常见的方式是通过包管理器pipconda。尽管它们的功能可能重叠,但每个管理器的总体设计是不同的。我使用 conda 来管理我的虚拟环境的主要原因是因为它非常强大,可以通过 conda 和 pip 打包安装,它允许安装不同版本的 Python 和其他编程语言,并且该软件是为数据科学家设计的。

为什么要使用虚拟环境?

虚拟环境的使用在数据科学中是至关重要的,尤其是在项目协作、将项目交付生产化、管理包依赖冲突以及使结果更容易重现时。Python 并不是管理包的最佳工具,你安装在电脑上的每个包都带有当前包所依赖的其他几个包。所有这些软件包都会以不同的版本安装,以确保最新安装的软件包能够正常工作。如果不指定检查与您正在安装的软件包相关联的版本,这将成为一个问题。

假设你在项目 Y 上工作,你使用的是版本 2.0.1 的pandas,然而当你在项目 X 上工作时,你使用的是版本 2.0.0 的pandas。想象一下,这些版本之间的差异是随着 X 项目使用的 pandas 上的各种功能被弃用而产生的。这实际上意味着,随着库版本的更新,您为项目 X 编写的调用不推荐使用的函数的脚本将不再工作。当您刚刚开始数据科学之旅,并且没有很多项目时,这个问题可能不会出现,但是在某个时候,您会遇到这个或非常类似的问题。

最佳实践是为您正在进行的每个项目创建一个独立的虚拟环境。这是由于两个主要原因;首先,项目的依赖关系和版本可能会不同,您会继续处理越来越多的项目。其次,生产环境将需要这些依赖项及其相关版本。较旧/较新的版本可能已弃用或向库中添加了新函数。当将您的模型交付给数据/机器学习工程师以投入生产时,您将向他们提供模型、与使用模型生成预测相关联的脚本以及保存加载和运行模型所需的包和那些包的版本的需求/环境文件。

康达装置

Conda 有大量关于其安装的文件。遵循下面的指南将指出在 Windows / Mac / Linux 操作系统中安装 anaconda / miniconda 的必要步骤和说明。

创建虚拟环境

通过命令行

在安装了conda之后,您可以在终端/命令行的任何路径运行以下命令:

conda create -n <env_name>

-n代表名称,您可以将<env_name>替换为您想要创建的环境的名称。出于本教程的目的,我将通过下面的命令创建一个名为conda_tutorial的环境。一个好的技巧是保持环境名称与您将要使用该环境的项目非常相似或相关。

conda create -n conda_tutorial

您还可以通过以下命令指定您希望使用环境创建的 Python 版本:

conda create -n conda_tutorial python=3.9

根据 Conda 文档,如果在创建环境时没有指定 Python 版本,它将默认使用 Python 3.9[3]。

通过 Yaml 文件

以下是与 conda 环境文件相关的结构,通常命名为environment.yml

您将在本文后面看到如何创建这个环境文件。现在,要使用提供给您的环境文件在您的计算机上创建环境,您可以运行以下命令。

conda env create -f environment.yml

请注意,这将要求您在命令行/终端上使用与environment.yml文件相同的路径。

创建这些环境时,它会提示您继续(参考下图)。键入y并按回车键,如果你想继续,否则按n

继续创建 conda 环境。图片由作者提供。

激活环境

创建环境后,您需要激活环境。这样做的命令是:

conda activate <env_name>

一旦环境被激活,您将在命令行的括号中看到它。

conda_tutorial 已激活。图片由作者提供

停用环境

同样,要停用环境,您只需运行:

conda deactivate

一旦环境被停用,您将返回到默认的base环境。

停用 conda_tutorial,现在回到默认基础环境。图片由作者提供。

环境列表

通过运行以下命令,您可以获得在您的计算机上创建的所有环境的列表:

conda env list

运行此命令后,您将看到在您的计算机上创建的所有环境的列表,以及可以找到这些环境的相关路径。*指当前活动环境,base环境为默认环境。

康达环境列表。图片由作者提供。

环境中已安装软件包的列表

运行命令conda list将在一个活动的 conda 环境中展示所有已安装的包。正如你在下面的图片中看到的,它展示了包的名字,版本和内部版本。

活动 conda 环境中已安装软件包的列表。图片由作者提供。

导出虚拟环境

导出虚拟环境对于项目移交/协作至关重要。以下命令将允许您将当前活动环境导出到一个environment.yml文件中。以下命令将允许您导出环境:

conda env export > environment.yml

它应该产生以下文件:

克隆虚拟环境

当您知道一个项目所必需的库与您以前工作过的另一个项目相同(如果不是非常相似的话)时,克隆一个环境可以节省时间。以下命令允许您克隆环境:

conda create --name <clone_name> --clone <existing_env>

在这里,您可以用新环境的名称替换<clone_name>,用您试图克隆的现有环境的名称替换<existing_env>

删除虚拟环境

无论出于何种原因,您可能在某个时候想要删除现有的虚拟环境。以下命令向您展示了如何做到这一点。对想要删除的多个环境重复该过程。

conda remove --name <env_name> --all

您用想要删除的环境的名称替换<env_name>

结束语

本质上,本教程概述了什么是虚拟环境,以及为什么您应该在您的下一个项目中使用它们。在团队环境中工作时,使用虚拟环境至关重要,原因如下:

  1. 使结果的协作和再现性更易于管理
  2. 降低依赖性冲突的可能性
  3. 使项目移交更容易

如果你想转型进入数据行业,并希望得到经验丰富的导师的指导和指引,那么你可能想看看最敏锐的头脑。Sharpest Minds 是一个导师*台,导师(他们是经验丰富的实践数据科学家、机器学习工程师、研究科学家、首席技术官等。)将有助于你的发展和学习在数据领域找到一份工作。点击这里查看它们。

资源

如果你喜欢读这篇文章,下面是我写的其他文章,你可能也会觉得很有见地:

https://pub.towardsai.net/community-detection-with-node2vec-6cd5a40c7155

编写其他人可以使用的 Python 函数的综合指南

原文:https://towardsdatascience.com/comprehensive-guide-to-writing-python-functions-others-can-use-2fa186c6be71

函数编写是一项技能——迈出掌握它的第一步

照片由Dziana HasanbekovaUnsplash

介绍

让我们搞清楚:每一行代码都是写给其他人阅读的。句号。

想知道为什么大多数人用英语编码吗?为什么不用汉语、俄语、克林贡语或古波斯语?其实编码语言重要吗?嗯,没有。

每一个源代码,不管是什么语言,都被转换成只有计算机才能使用的机器语言。

因此,大多数编程语言使用英语关键字的根本原因是,英语是全球通用的语言,被数十亿人所理解。

用英语编写源代码使人类更容易创建计算机程序,并与世界各地的其他程序员合作。这一切都归结于编写可理解的代码。

你写的代码是你的脸面,是其他程序员评判你的第一件事。这就是为什么你越早把这个真理灌输给自己越好。

这篇文章将讲述如何编写干净的、文档记录良好的函数,这些函数遵循最佳实践,并且是 ide 所乐于见到的。

**https://ibexorigin.medium.com/membership

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

https://alphasignal.ai/?referrer=Bex

文档字符串

在您编写了一个函数之后,让它变得可理解的第一步是添加一个 docstring。下面是对一个好的 docstring 的剖析:

所有记录良好且受欢迎的库都以不同的格式遵循这种剖析。有 4 种主要的文档字符串格式:

  • 谷歌风格
  • Numpydoc
  • 重组后的文本
  • EpyTex

我们只关注前两个,因为它们是最受欢迎的。

Google 风格的文档字符串

先说 Google Style 的功能描述部分:

第一句话应该包含函数的目的,就像文章中的主题句一样。它应该在打开三重引号后立即开始。可选的解释应作为单独的、不缩进的段落给出:

接下来是论据部分:

Args:开始新段落表示您正在定义参数。参数在新的一行给出,缩进两个空格。在参数名之后,参数的数据类型应该用括号括起来。对于可选参数,应该添加一个额外的‘可选’键。

最后,定义返回值:

如果您的函数引发了任何有意的错误,您也可以通过 errors 部分:

有时,您可能需要在结尾处包含示例或额外注释:

Numpydoc 格式文档字符串

这种格式是数据科学社区中最流行的。以下是完整格式:

error s 和notes部分遵循相同的模式。尽管它需要更多的台词,但我更喜欢这部。

以下是两种风格的示例函数:

如果功能使用*yield*关键字,可以用*Yields*改变*Returns*段。

如果用户使用像 PyCharm 这样的现代 ide,添加类型提示会非常有帮助。

不用谷歌就能访问函数的文档字符串

您也可以通过调用函数名上的.__doc__来访问任何函数的 docstring:

使用__doc__可以很好地处理小函数,但是对于像numpy.ndarray这样具有大文档字符串的大函数,您可以使用inspect模块的.getdoc函数:

它以一种易于阅读的方式显示函数的文档。

一次做一件事

许多初学者常犯的一个错误是编写太长太复杂的函数。

总是建议将函数设计为只执行一个特定的任务。小而精确的函数更容易用现代 ide 测试和调试

现在,你可能会想:‘如果我的代码产生了一个错误,我从来不需要花超过 2-3 分钟来解决它。“我总是可以用简单的print语句来解决它们,然后玩一玩……”这是典型的初学者误解。

当我刚开始学习 Python 时,我也认为我所学的书籍和课程在代码中制造了大量的 bug。因为那时,我写的代码还不够复杂,不足以产生“令人头疼的”错误。

如果你仍然这样想,试着写一个实际上有几百行的脚本/程序。你会明白我的意思。

同时,考虑这个函数:

数据集链接:https://www.kaggle.com/datasets/juanmah/world-cities

首先,docstring 没有很好地描述函数。如果我们花一些时间阅读代码,我们会意识到它的主要目的是从path参数中读取一个csv文件,并使用country参数对其进行子集化,返回该国人口最多的前 25 个城市。

如果你注意的话,这个函数的主要目的是在一行中完成的(就在第二个注释之后)。其他生产线正在执行不太清楚的清洁任务。

最理想的情况是将这一功能拆分开来,这样所有的清洁工作都在一个区块中完成,而 25 个城市的子集则在另一个区块中完成。让我们从清洁开始:

在上面的函数中,我使用了.rename方法将lng列重命名为lon。在最初的脏函数中,创建了一个新列,删除了不必要的旧列。

下一步是创建另一个函数,它是给定国家顶级城市的子集:

这个函数比原来的要好,因为我还插入了异常处理逻辑,用于当数据中没有匹配的国家时。

这两个新功能包含更好的文档并遵循最佳实践。

结论

在本文中,您了解了编写清晰易读的函数的最佳实践。现在,您可以用两种流行的惯例编写函数文档字符串,并将冗长而混乱的函数分解成更容易调试的模块化函数。

编写好的函数本身就是一种技能,就像任何技能一样,需要时间和练习来掌握它。感谢您的阅读!

您可以使用下面的链接成为高级媒体会员,并访问我的所有故事和数以千计的其他故事:

https://ibexorigin.medium.com/membership

或者订阅我的邮件列表:

https://ibexorigin.medium.com/subscribe

阅读更多我的故事:

https://ibexorigin.medium.com/6-sklearn-mistakes-that-silently-tell-you-are-rookie-f1fe44779a4d 💔-best-often-better-alternatives-to-histograms-61ddaec05305> **

关于在分类中使用混淆矩阵的综合教程

原文:https://towardsdatascience.com/comprehensive-tutorial-on-using-confusion-matrix-in-classification-92be4d70ea18

学习使用混淆矩阵,根据问题的重要性来控制模型输出

使用 Sklearn 掌握混淆矩阵的基础知识,并为二进制分类中最常用的三个指标建立实用的直觉:精确度、召回率和 F1 分数。

照片由 汤玛士蕾pix abay

介绍

分类是机器学习的一个重要部分。它的好处和应用是无穷无尽的——从探测新的小行星和行星到识别癌细胞,所有这些都是通过分类算法完成的。

分类解决的问题类型分为两种:无监督的和有监督的。无监督分类器通常是神经网络,可以对视频、音频和图像等非结构化数据进行训练。相比之下,监督模型处理带标签的表格数据,是经典机器学习的一部分。本文的重点是后者;特别是,我们将探索所有监督分类问题的共同点:混淆矩阵

**https://ibexorigin.medium.com/membership

获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:

https://alphasignal.ai/?referrer=Bex

开发分类预处理流水线

好的模型需要好的数据。因此,即使在基于混淆矩阵对模型进行调整之前,也必须尽可能多地处理可用信息,以实现最佳的模型性能。

典型的预处理工作流包括处理缺失值、缩放/归一化数字特征、编码分类变量以及执行所需的所有其他特征工程步骤。我们将在本节中看到一个这样的例子。

我们将使用来自 UCI 机器学习库的信用卡审批数据集来预测信用卡审批。银行在向新客户发放信用卡之前,需要考虑很多因素:收入水*、贷款余额、个人信用报告等。这通常是一个困难而*凡的任务,所以现在,银行使用 ML 算法。让我们来看一下数据:

作者图片

因为它是私有数据,所以特征名称保留为空。让我们先解决这个问题:

数据集包含数值和分类特征。此数据集中缺失的值用问号(?).我们将用NaN s 替换它们:

要素 0、1、3、4、5、6 和 13 包含缺失值。检查数据,我们可能会猜测特性 13 包含邮政编码,这意味着我们可以删除它。对于其他行,由于它们只占数据集的不到 5%,我们也可以删除这些行:

我们没有使用插补技术,因为空值的数量很少。如果您想了解其他稳健插补技术,本文将有所帮助:

现在让我们把重点放在数值上。具体来说,我们将查看它们的分布:

>>> df.describe().T.round(3)

所有要素的最小值都为 0,但它们都在不同的比例上。这意味着我们必须使用一些标准化,我们将通过直观地探索这些特性来了解是哪种标准化:

import seaborn as sns>>> df.hist();

作者图片

特征具有偏斜分布,这意味着我们将执行非线性变换,如PowerTransformer(使用对数):

如果您想了解更多关于其他数字特征转换技术的信息,我也已经介绍过了:

为了编码分类特征,我们将使用一个OneHotEncoder。在隔离要在编码中使用的列之前,让我们将数据分成特性和目标数组:

现在,隔离要进行 OH 编码的分类列:

最后,我们将构建预处理管道:

混淆矩阵介绍

最后一步,我在管道中添加了一个RandomForestClassifier作为基础模型。我们希望该模型能够更准确地预测批准的申请,因为这意味着银行会有更多的客户。这也将使批准的申请成为我们预测中的阳性类别。让我们最后评估一下管道:

所有分类器的默认得分是准确性得分,其中我们的基础管道令人印象深刻地达到了约 87%。

但是,这里有一个准确性的问题——什么是模型准确?它能更好地预测合适的应用程序,还是能更准确地检测不合适的候选程序?从商业角度来看,你的结果应该回答这两个问题,而准确性不能做到这一点。

作为解决方案,让我们最终引入一个混淆矩阵:

由于这是一个二元分类问题,矩阵的形状为 2x2(目标中的两个类)。矩阵的对角线显示正确分类样本的数量,非对角线单元显示模型出错的位置。为了理解矩阵,Sklearn 提供了一个可视化的,这要好得多:

作者图片

这个混淆矩阵提供了更多的信息。以下是一些需要注意的事项:

  • 这些行对应于实际值
  • 这些列对应于预测值
  • 每个单元格都是每个真实/预测值组合的计数

请注意轴标签,第一行代表实际的负面类别(拒绝的申请),而第二行代表实际的正面类别(批准的申请)。类似地,第一列是正面预测,第二列是负面预测。

在我们继续解释这个输出之前,让我们先确定这个矩阵的格式。在其他文献中,您可能会看到实际的正类出现在第一行,而预测的正类出现在第一列。我也习惯了这种格式,并发现它更容易解释。

我们将翻转矩阵,使第一行和第一列是正类。我们还将使用 Sklearn 的ConfusionMatrixDisplay函数来绘制定制矩阵。下面是一个包装函数:

作者图片

我们使用np.flip翻转矩阵,并通过ConfusionDisplayFunction绘制它,它只接受一个矩阵,并通过display_labels参数接受自定义类别标签。

让我们最终解读这个矩阵:

  • (左上) — 78 个申请实际上被批准,和模型正确地将它们归类为批准**
  • (右下) —实际上有 95 份申请被拒绝,和模型正确地将它们归类为被拒绝的
  • (左下) — 13 份申请实际上被拒绝,但是模型错误地将它们归类为批准**
  • (右上) —实际上有 12 份申请被批准,但是模型错误地将它们归类为拒绝

由于混淆矩阵的流行,每个真实/预测单元组合在社区中都有自己的名称:

  • 真阳性(TP) —实际阳性,预测阳性(左上角,78)
  • 真阴性(TN) —实际阴性,预测阴性(右下角,95)
  • 假阳性(FP) —实际阴性,预测阳性(左下角,13)
  • 假阴性(FN) —实际阳性,预测阴性(右上,12)

尽管您可能会看到不同格式的矩阵,但上述四项将始终存在。这就是为什么在创建模型之前,在心里记下上述四个术语在您的特殊情况下指的是什么是有帮助的。

拟合模型后,您可以在混淆矩阵上使用.ravel()方法提取上述 4 个元素中的每一个:

精确度、召回率和 F 分数

在这一节中,我们将了解让我们进一步比较一个混淆矩阵与另一个混淆矩阵的指标。假设我们有另一个使用LogisticRegression作为分类器的管道:

左逻辑回归,右随机森林分类器。作者图片。

看着上面的图,我们可以说随机森林和逻辑回归的结果是相似的。然而,我们可以从混淆矩阵中得出三个常见的度量标准,以便对它们进行比较。这些被称为精度召回、F1 得分。让我们详细了解每一个:

  1. 精度是正确分类的阳性类别数与预测阳性类别总数之比。在我们的例子中,它是正确分类的总数,批准的应用程序 (TP = 77)除以预测的批准分类总数(所有预测的阳性,不管它们是否正确,TP + FP = 94)。使用矩阵术语,它是:

作者图片

你可以很容易地用三 P 法则记住这一点——precision 包括所有的正数,并使用矩阵左侧的术语。

Sklearn 对精度的官方定义是:“分类器不将一个阴性样本标记为阳性的能力。”在我们的例子中,我们的模型能够不将拒绝的申请标记为批准。因此,如果我们希望模型在过滤不合适的应用程序时更加准确,我们应该针对精度进行优化。换句话说,尽可能增加真阳性,减少假阳性。0 假阳性给出 1 的精度。

  1. 回忆 : 灵敏度,命中率,真阳性率(TPR) 。它是正确分类的阳性数除以目标中实际阳性总数的比率。在我们的例子中,它是正确分类的批准的申请数 (TP = 77)除以实际批准的申请总数(不管它们是否被正确预测,TP + FN = 90)。使用混淆矩阵的术语:

作者图片

回忆使用混淆矩阵第一行中的术语。

Sklearn 对召回的官方定义是:“分类器找到所有正样本的能力。”如果我们优化召回,我们将减少假阴性(错误分类,批准的申请)的数量,增加真阳性的数量。但是这可能是以假阳性的增加为代价的——即错误地将被拒绝的申请归类为被批准的。

由于它们的性质,精确度和召回率是一种权衡关系。根据您的业务问题,您可能需要以牺牲另一个为代价来优化其中一个。然而,如果你想要一个*衡的模型,也就是说,一个同样善于发现积极和消极因素的模型呢?

在我们的案例中,这是有意义的——如果一家银行能够找到尽可能多的客户,同时避免不良候选人,从而消除潜在的损失,那么它将受益最大。

  1. 第三个指标,称为 F1 得分,试图精确测量:它量化了模型正确预测两个类别的能力。它通过取精度和召回率的调和*均值来计算:

作者图片

你会问,为什么调和意味着什么?因为它是如何计算的,调和*均数真正给出了一个*衡的分数。如果精度或召回率的值较低,F1 分数会受到很大影响。与简单*均值相比,这是一个有用的数学特性。

所有这些指标都可以使用 Sklearn 进行计算,并且可以在metrics子模块下获得:

RandomForest 具有更高的精确度,这表明它在发现可批准的应用程序方面更好,同时降低了假阳性,即不正确地分类不需要的候选对象。

RandomForests 也赢得了回忆。类似地,它在过滤假阴性方面更好,即减少被分类为阴性的阳性样本的数量。由于 RandomForests 在这两个分数上都赢了,我们可以期待它也有一个更高的 F1:

正如预期的那样,RF 具有更高的 F1,对于我们的情况来说,它是一个更健壮的模型。

您可以使用classification_report功能一次打印出所有这些分数:

在我们关注这些指标的优化之前,让我们看一下其他场景来加深我们的理解。

在解释精确度、召回率和 F1 方面进行更多练习

由于这些指标之间的差异是微妙的,您需要一些实践来培养对它们的强烈直觉。在本节中,我们将做到这一点!

假设我们正在检测跳伞商店出售的降落伞是否有缺陷。助手检查所有可用的降落伞,记录它们的属性,并对它们进行分类。我们希望将这一过程自动化,并建立一个能够非常好地检测故障降落伞的模型。

出于示例目的,我们将综合创建数据集:

由于工作降落伞多得多,这是一个不*衡的分类问题。让我们建立术语:

  • 正面类:有缺陷的降落伞
  • 反面课堂:工作降落伞
  • 真正的正面:故障降落伞预测正确
  • 真正的否定:工作降落伞预测正确
  • 误报:故障降落伞预测错误
  • 假阴性:工作降落伞预测错误

让我们根据这些数据评估一个随机森林模型:

作者图片

在这个问题中,我们应该尽可能地降低右上方(假阴性),因为即使是一个有故障的降落伞也意味着跳伞者的死亡。看看分数,我们应该优化召回分数:

作者图片

如果假阳性增加是完全可以的,因为我们将拯救人们的生命,即使我们可能会损失一些钱。

在第二个场景中,我们将尝试预测客户流失(停止或继续使用我们公司的服务)。同样,让我们为这个问题建立术语:

  • 积极类:继续使用
  • 负面类:流失
  • 真阳性:想要继续,预测正确
  • 真正的负面因素:流失,预测正确
  • 误报:流失,预测错误
  • 假阴性:想要继续,预测错误

我们将再次构建一个合成数据集,并在其上评估 RF:

作者图片

在这种情况下,我们希望留住尽可能多的客户。这意味着我们必须降低误报率,这表明我们应该优化精度:

作者图片

在本文中,我们只关注三个指标。但是,您可以从混淆矩阵中获得许多其他得分,如特异性、NPV、FNR 等。看完这篇文章,你应该能读到关于该话题的维基百科页面。如果你对指标感到困惑,也可以看看这篇的精彩文章

最后,让我们看看如何针对我们今天讨论的每个指标进行优化。

使用 HalvingGridSearchCV 优化特定指标的模型

在本节中,我们将了解如何针对我们选择的指标提升模型的性能。在上面的章节中,我们使用了带有默认参数的模型。为了提高它们的性能,我们必须进行超参数调整。具体来说,我们应该找到为我们期望的度量给出最高分数的超参数。

寻找这个神奇的布景既乏味又费时。因此,我们将引出HalvingRandomSearchCV类,它在模型的可能参数网格上进行探索,并为传递给它的scoring参数的评分函数找到给出最高分数的集合。

你可能会惊讶于我没有使用 GridSearch。在我的一篇文章中,我展示了减半网格搜索比常规网格搜索快 11 倍。并且减半网格搜索甚至更快,允许我们在很大程度上拓宽我们的超参数空间。你可以在这里阅读对比:

</11-times-faster-hyperparameter-tuning-with-halvinggridsearch-232ed0160155>

作为第一步,我们将构建超参数空间:

现在,我们将在这个网格上搜索三次,针对我们今天讨论的每个指标进行优化:

我们在精确度方面得分较高,但在召回和 F1 方面得分较低。这是一个迭代的过程,所以你可以继续搜索,直到分数提高。或者,如果你有时间,可以换成 HalvingGridSearch,它比 HalvingRandomSearch 慢很多,但是给出的结果要好得多。

摘要

任何分类问题中最困难的部分是理解您试图解决的业务问题,并相应地优化度量标准。一旦你从理论上构造了合适的混淆矩阵及其项,就只剩下编码部分了。

就编码而言,拥有一个优秀的预处理管道可以确保您为自己选择的基础模型获得最好的分数。确保根据底层分布对数据进行缩放/规范化。预处理之后,为多个分类器创建管道的副本。逻辑回归、随机森林和 KNN 分类器都是不错的选择。

为了优化,选择对半网格或对半随机搜索。事实证明,它们比以前的同类产品要好得多。感谢阅读!**

CompTIA Security+ (Plus) SY0-601 考试指南:你需要知道的一切

原文:https://towardsdatascience.com/comptia-security-plus-sy0-601-exam-guide-everything-you-need-to-know-f813606ebe52

正确通过 CompTIA Security+ (Plus) SY0-601 考试

文章最后更新时间:2022 年 7 月

丹·尼尔森在 Unsplash 上拍摄的照片

介绍

在当今的技术环境中,数据专业人员比以往任何时候都更需要考虑数据和系统的安全性。随着网络攻击的数量以前所未有的速度增长,从 IBM 到上市后初创公司 Darktrace 的许多公司都在将数据科学支持的网络安全作为未来五到十年的业务重点。如果你是一名想要进入人工智能网络安全行业的数据科学家,参加 CompTIA Security+ (Plus) 考试是一个很好的起点。这篇文章包含了你需要了解的关于 SY0-601 的一切,SY0-601 是 CompTIA 的全球认证考试,旨在验证你在 IT 安全方面的技能。

列出考试规格后,我们将开始浏览 SY0–601 考试的内容,以及您将会遇到的问题类型。然后,我们将回顾一些准备工作的注意事项,我将介绍哪些资源可以用来学习,哪些应该避免。一旦你准备好参加考试,我会告诉你如何安排考试,考试当天会发生什么,以及如何在你通过考试后保持你的认证。

考试规格

CompTIA Security+测试是一项相当复杂的考试。以下是详细情况:

  • 长度:最多 90 个问题(但你可以少问一些)
  • 时长: 90 分钟时限
  • 考试价格:参考考试价格网页在此找到您所在地区的价格信息。
  • 问题格式:选择题(一个或多个正确答案)和表现型问题(PBQs)。回答不正确是没有惩罚的,所以一定要回答好每一个问题。
  • 及格分数: 750 / 900 分(83.3%)
  • 考试最后更新日期:2020 年 11 月 12 日
  • 夺回策略: 第一次失败后没有等待期。超过这个时间后,任何失败都有 14 天的等待期——没有考试次数的上限。
  • 认证到期政策 : 认证在认证考试后 3 年到期。他们可以通过培训、重新认证考试和资格认定活动进行更新。稍后将详细介绍。
  • 测试环境:通过培生 VUE 在线或现场。

考试内容

考试内容分为 5 个领域:

  1. 攻击、威胁和漏洞(24%)
  2. 建筑和设计(21%)
  3. 实施(25%)
  4. 运营和事故响应(16%)
  5. 治理、风险和法规遵从性(14%)

在你做任何事情之前,我强烈建议你阅读一下官方考试目标大纲,了解更多关于考试内容的细节。要访问考试目标,您需要加入 CompTIA 电子邮件列表(很容易取消订阅),并且获得大纲是非常值得的。该文件将 5 个领域中的每一个细分为子列表,这些子列表给出了考试中可能涉及的每个主题的综合列表。它还包含 Security+(SY0–601)缩略词列表,这是一个 4 页的概要,列出了考试中可能出现的每个缩略词。

题型

考试有几个不同类型的问题,你应该做好准备。从官方的测试指南中还不清楚你是否可以因为你的任何一个答案得到部分分数,但是不正确的答案是没有惩罚的。这意味着回答每个问题对你最有利。通过皮尔森 VUE 在线考试时,所有的问题都可以标记为待复习,所以你也可以标记棘手的问题,如果你不能马上确定答案,稍后再回来。

考虑到这些细节,让我们来看看问题类型。

基于绩效的问题(pbq)。

您将从 2-6 道 pbq 开始考试。这些交互式问题旨在测试您解决现实问题的能力。可能会要求您根据控制台日志识别攻击类型,根据一组网络要求配置一组访问控制列表,或者将一组协议与其正确的端口号进行匹配。pbq 可能包含多项选择、填空或拖放考试组件,有些甚至要求您与模拟虚拟环境进行交互。

有 1 个或更多正确答案的多项选择

选择题部分占了考试的大部分。大多数问题只有一个正确答案。但是,有些会要求您选择多个正确答案。通过问题提示后的(选择两个)(选择三个)括号说明,您将能够识别有多个正确答案的问题,因此请务必仔细阅读。

准备注意事项

这里有一些帮助我第一次通过 CompTIA Security+ SY0-601 的学习技巧。

  • 务必使用合法的免费 CompTIA Security+ SY0-601 学习资源。互联网上有很多精彩的免费资源可以帮助你准备考试。刀子乐队教授精彩的 SY0-601 培训视频、[参加十次小测验](http://CompTIA Security+ Take Ten Challenges)、每月学习小组提供超过 21 小时的高质量内容,与 SY0-601 考试目标保持一致。这些视频是开始准备的好地方。另外,考虑使用别人制作的免费的 QuizletAnki 抽认卡来学习。如果你担心免费的抽认卡可能包含错误,考虑制作你自己的抽认卡,并在脸书Discord 上与安全+社区分享,供同行评审,尽管这更费时间。
  • 请考虑购买一本好的 CompTIA Security+ SY0-601 书籍。如果从课本上学的好,我推荐买一本 SY0-601 考试的优质书。你会在网上找到很多选择,但我个人在亚马逊上买了 Chapple 和 Seidl(很遗憾,不是赞助商),毫无保留地推荐。内容组织得很好,每一章都链接到考试目标中的一个特定子点,使其易于阅读。它还带有两个免费的实践测试,抽认卡和章节测验,可通过在线门户网站获得。
    注:如果钱不是问题,可以尽情挥霍 官方 CompTIA Security+学习指南 ,但我个人认为在有其他更低价格点的优质选择时,不值得花那么多钱。
  • 务必仔细阅读每个问题,并注意粗体和大写单词。除了选择多项提示,CompTIA 多项选择题通常包含大写的最高级。他们会询问最有可能的解决方案或最佳方法或第一优先事项。即使多个其他答案可能有些正确,也要选择最佳答案。
  • 一定要适应安全+pbq。要想知道会发生什么,请务必查看 CompTIA 提供的安全性+示例模拟。更多 PBQ 风格的例子,请查看电子学习课程中的 CompTIA pbq。并非所有这些电子学习 pbq 都基于安全+考试内容,但它们肯定会帮助您获得一般的舒适 pbq。CompTIA 也有一些填写 PBQ 的提示以及 PBQ FAQ 页面来帮助你。

以下是我建议你在准备过程中避开的一些事情。

  • 不要使用考试垃圾网站或以其他方式违反 CompTIA 考生协议 。如果你在谷歌上搜索安全+认证考试,你一定会找到考试垃圾网站。考试转储网站包含过去安全+考试的真题,由已经参加过考试的人编辑。不幸的是,考试垃圾不是好的学习材料,原因有很多。首先,CompTIA 测试人员也有 Google。考试经常轮换和更新,考试组织者保持警惕,以确保这些网站上出现的问题不会出现在您的实际考试中。更重要的是,访问考试转储被认为是作弊,违反了 CompTIA 考生协议。任何违反协议的行为都会让你被长期禁止参加 CompTIA 认证,同时你当前的考试成绩也会立即不及格。练习规避风险,避开这些网站。
    注:如果你在找练习题,我推荐 CompTIA 免费安全+练习题 [刀子乐队教授的十个小测验](http://CompTIA Security+ Take Ten Challenges) , 杰森·戴恩的 Udemy 课程和考试 迈克·梅尔斯的练习测试 这些是我用来熟悉 CompTIA Security+问题风格的资源,我发现它们都相当准确地代表了实际测试。
  • 不要购买或使用 SY0-501 考试的学习材料来代替 SY0-601 考试。 SY0-501 于 2021 年 7 月 31 日被 SY0-601 取代为 CompTIA Security+认证考试。它们是类似的测试,但新的 SY0-601 有一些旧 SY0-501 版本中没有的额外考试目标。在你购买或使用任何学习材料之前,确保你得到的是测试的正确版本。
  • 不要等太久才安排考试。实际上,请阅读下一部分,并马上安排考试。安排考试给你一个准备工作的日期,并迫使你保持动力,因为你已经在游戏中得到一些钱。如果你不能及时到达你需要的地方,你可以在考试前 24 小时重新安排考试。另外,关于准备的一个快速提示:你可能永远不会为安全+考试做好 100%的准备。我的意思是,你看过考试目标表和它的四(4)页缩略词吗?好消息是,你不需要为通过这次考试做 100%的准备——你只需要取得 750/900 分(83.3%)。现在就安排考试,争取在考试日期前完成 83.3%的模拟考试。

安排考试和考试日提示

准备好安排考试了吗?太好了!您可以直接从 CompTIA 网站购买考试,价格为当地的全价。然而,在你这样做之前,一定要四处看看有没有折扣。在安排 CompTIA Security+考试时,许多合作公司和供应商都会提供折扣券,为您节省一些费用。我工作的公司允许我拿到一张 15%折扣的优惠券参加考试,所以在支付全价之前一定要和你的雇主核实一下。刀子乐队教授还提供了一张 10%折扣的考试代金券,美国和加拿大的所有人都可以使用,同时在培生 VUE 网站上还有关于如何兑换代金券的精彩说明

无论您决定为考试支付多少费用,都要准备好创建 CompTIA 认证档案并验证您的一些个人信息。何时参加考试由你决定——如果你感到冲动,你可以(通常)将考试安排在你想参加的日子,但我建议你如果可以的话,提前几周安排考试。

您还可以选择亲自参加考试还是通过皮尔逊 VUE 在线考试。我决定参加在线考试,所以我不能对现场监督发表评论,但我要说的是,我在皮尔逊 VUE 的经历非常积极,这次考试也不例外。这里有一些建议,可以让你在皮尔森 VUE 的经历尽可能顺利:

  • 确保你的考试空间是安静的,并且在考试期间你不会被打扰。为了防止作弊,如果你考试时有其他人和你在一起,你的考试成绩可能会作废。皮尔逊 VUE 软件还将使用你的计算机的麦克风记录你考试时发出的任何声音,以防止通过音频信号作弊。这也意味着你需要在整个考试中保持沉默——不要大声朗读问题,因为这可能会导致失格。
  • 确保你的考试空间尽可能的空着。你需要在考试前拍四张你的考试区域的前、后、左、右的照片。在拍摄这些照片之前,请确保移除任何纸张、铅笔、外部键盘或鼠标等。符合测试规则。你不允许在测试过程中书写(尽管你可以使用虚拟记事本)或使用外部设备,所以最好完全清空你的测试区域。
  • 考试时要注意你的眼睛。您的前置摄像头将记录您的整个测试过程,并且您将在整个过程中受到皮尔森 VUE 监考人的监控。如果你在考试时不看电脑屏幕,会让人怀疑你可能作弊。如果你是那种喜欢在思考的时候盯着远处看的人,那么在考试的 90 分钟里,尽你所能抵制这种冲动。

虽然这些规则看起来很多,但在测试过程中并不明显。如果你没有作弊,你真的没有什么好担心的。想象一下,你回到了高中,遵循你在真实课堂上遵循的规则——保持沉默,眼睛盯着考试,不要从任何人或任何事物获得帮助。

维护您的 CompTIA Security+认证

如果这一部分与你相关,那么恭喜你!您已经通过了安全+考试,并且在接下来的三年内获得了正式认证。庆祝活动结束后,请前往本页了解如何维护和更新您的认证。当你玩得开心的时候,时间过得很快!

您正在顺利通过 CompTIA Security+ SY0-601 认证考试。最后一点:永远记住认证只是你学习之旅的开始,而不是结束。一旦你获得认证,你就要好好利用这个认证——无论是工作还是个人项目。

祝你考试顺利,认证愉快!

*Acknowledgments: A big thank you to the wonderful Claire Hoffman for proofreading and editing this article and putting up with my neglect of the Oxford comma. If you liked this story and want to read more, follow me on Medium and subscribe via my referred members link here:* [https://sethbilliau.medium.com/membership](https://sethbilliau.medium.com/membership). 

计算创造力

原文:https://towardsdatascience.com/computational-creativity-6a5d77b3ed12

在建筑计算工具中集成横向思维的人工智能实验管道

生成的计划|来源:作者

建筑工具从传统到现代计算的转变已经集中在效率和生产力上。这是因为建筑师使用的许多计算工具都是工业学科的遗产,如汽车和制造业。例如,CATIA 是 Frank Gehry 和他的团队用来实现复杂设计的软件,最初是为航空业开发的。

作为从这些领域继承的结果,这些其他学科的价值和标准已经离散地渗透到建筑中。因此,优化、标准化和效率的概念,垂直思维的所有品质,或工业时代的推理,在这些工具中不可避免地优先于横向思维品质,如不准确、不确定性和事故,这些品质通常与艺术实践相关。

然而,正如布莱恩·劳森、奈杰尔·克罗斯和凯斯·多斯特等学者的工作所指出的,创造力和优秀设计之间有着明显的关系。他们的工作指出,成功的建筑设计必须有创造性的设计过程,这种创造性的过程表现为设计师*衡发散和收敛思维的能力——发散思维与爱德华·德·波诺创造的术语“横向思维”密切相关。这种创造性的设计过程往往会带来意想不到的设计机会。

因此,随着我们的工具变得越来越数字化,这些工具强加的功能和方法极大地关注了垂直思维,已经自动地和无意地限制了可能的设计空间。

本文的目标是将横向思维策略重新整合到建筑设计工具中。我们认为,缺乏这些特定品质的今天的计算工具可以受益于在建筑设计过程的早期阶段嵌入人工智能,作为一种在我们的过程中解决横向思维方法的方法。具体而言,我们提出了一个基于生成式对抗网络(GANs)的 4 步人工智能驱动的管道,该管道利用访问机器潜在空间的能力,并将该空间用作设计 3D 建筑结构的实验性数字环境。

相关工作

过去十年左右的架构工具主要集中在参数化方法上。这些方法的特点是为元素之间的关系赋值,并操纵这些值来控制和组织这些关系。另一方面,机器学习算法通过探索数据并识别其中的模式来工作,而不依赖于预定的方程作为模型。几位建筑师和研究人员最*探索了机器学习算法的潜力,特别是生成性对抗网络(GANs),以提高创造性的可能性。这些 GAN 算法可以统计地学习和模仿呈现给它们的任何数据分布,并且通常用于生成目的。

可预测的产出

黄等将 GANs 应用于建筑图纸的识别与生成。作者使用 pix2pixHD,这是一种经过修改的 GAN,它成对学习图像数据,并根据输入生成新图像。他们使用不同颜色标记的房间图作为输入来制作公寓*面图。Chang 等人提出了一个图约束的生成对抗网络,用于从建筑气泡图中自动生成多个房屋布局选项。

这些作品清楚地展示了 GANs 生成建筑计划并可能优化建筑流程和工作流的潜力和能力。结果的可接受性取决于它们与当前架构状态的熟悉程度或相似程度。因此,就横向思维方法而言,这些方法表现不佳,因为它们的输出往往总是相当可预测、可预期的,并且受限于已知的内容。

然而,正如菲利普·莫雷尔所说,“任何建筑师的任务都不是用计算机来复制或自动化已经想到和产生的东西,而是让计算机揭示一种全新形式的建筑智能。”他详细阐述了“机器,[……]将在逻辑上产生一种也超出我们通常能力的建筑”,并指出这种建筑仍有待产生。我们的工作旨在扩展这一点,并让机器揭示一种新的“不可思议的架构”

“任何建筑师的任务都不是用计算机来复制或自动化已经想到和产生的东西,而是让计算机展现一种全新的建筑智能。”

不可预测的产出

Chaillou 提出了一种使用嵌套 GAN 模型生成整个公寓建筑的方法。使用这种方法,作者演示了嵌套不同的模型如何产生独特的输出和介于当前已知风格之间的新的架构风格。尽管这种方法显示了很好的结果,但该过程仍然涉及大量的图像对的管理以进行训练。

我们的工作建立在这些研究的基础上,并提出了一系列的步骤和方法,通过这些步骤和方法,我们讨论了人工智能驱动的横向思维在建筑工具中的潜力。

方法学

我们提出了一个使用 StyleGAN 生成 3D 结构的管道,并探索其潜在空间作为 512 维虚拟环境进行设计。潜在空间是 n 维空间,其中,在训练 GAN 模型之后,该模型的生成器学习将该空间中的点映射到特定生成的图像,该图像类似于其最初被训练的数据集的图像。每次模型定型时,这些映射都会发生变化。

潜在空间具有可以被查询和导航的结构,其中该空间中的每个点是表示图像的 512D 向量。我们的 4 步过程利用这个空间的能力和属性来设计一个 3D 结构。(1)它首先包括通过 StyleGAN 模型的训练来初始化点的虚拟潜在空间。(2)接下来的步骤是通过选择或生成表示图像的 512D 向量来进入该空间并访问其维度。(3)此外,在获得一个点(图像)之后,我们通过使用向量算术运算和插值来在空间中导航,以生成被转换成图像的新点。(4)最后,我们通过使用这些图像的像素值来生成体素 3D 结构。我们展示了这条管道,并建议它如何将建筑数字工具推向实验领域。

管道流程图|来源:作者

虚拟环境代表建筑师当前设计、分析、编辑和生成 3D 结构的数字设计空间。目前使用的工具,如 Rhino3D,侧重于正交方法,并依赖于曲线,直线,曲面,NURBS 等。,并操纵这些元素在 3D 虚拟空间中创建设计。在本文中,我们通过训练机器来初始化一个 512D 虚拟设计环境,并提出在该空间中进行设计的不同方法。

I .初始化虚拟环境

为了初始化虚拟环境,StyleGAN 模型在从几个不同的在线来源(如 ArchDaily 和 Artstor)收集的 5000 个建筑*面图上进行训练。收集的数据集主要由不同风格和时期的房屋*面图组成。这允许对机器可能学习的可能图像特征进行更好的控制。在训练之后,生成 512D 的潜在空间,其中具有相似特征的数据点(表示图像)在该空间中被放置得更靠*。我们使用这个生成的“虚拟环境”作为搜索和设计可能性的设计基础。

潜在空间|来源:作者

二。进入空间

接下来的一步就是进入这个空间。我们使用两种主要方法来访问这个潜在空间的维度:通过点生成,通过随机使用 512 维向量(图像)的一组值,或者通过用户选择或设计的绘图的图像嵌入。

在第一种方法中,机器遍历潜在空间并生成对应于指定向量值的图像。在第二种方法中,可以使用 StyleGAN 嵌入算法,其中机器将嵌入的图像映射到空间中最接*具有相似特征的图像的特定点。

三。遨游太空

在这个空间中生成或选择点之后,我们在矢量算术运算中使用这些点来创建新的点,然后将这些点转换为图像。举例来说,通过添加向量,我们组合空间中具有不同特征的不同点,并生成一个新点。具体来说,就建筑*面图而言,通过在空间中添加不同的点(图像向量),我们正在添加对应于建筑设计中不同属性和可能风格的*面图的向量,这取决于初始数据集是什么。这允许有目标但不可预测的图像生成。下图显示了我们流程中的一个输出。

混合不同因素的计划|来源:作者

此外,除了组合向量,我们在两个或更多点之间进行线性插值。通过从一个点到另一个点的插值,我们创建了一系列具有不同数量的步骤或相似度的变换或过渡图像,如下图所示。

不同系数的􀀗interpolating |来源:作者

插值|来源:作者

四。生成 3D 体素化结构

最后,为了创建 3D 形状,我们堆叠在 Z 空间中生成的一系列图像,并生成体素结构。为此,在该步骤中,内插图像的像素值被读取并被转换成定义实体体素体积的布尔值的 3D 阵列。

这种生成的虚拟环境(潜在空间)作为我们当前计算工具(如 Rhino 和 AutoCAD)环境的替代空间。在一台机器的空间内工作会带来新的偏见。然而,我们认为当前的“机械”操作通常在当前的 3D 建模软件中执行,如切片、放样、修剪等。,通过遵循一系列步骤和规则来产生相对可预测的输出。

然而,通过我们集成的非顺序和非逻辑管道和潜在空间方向导航技术,我们的目标是摆脱操纵工具的曲线、直线和表面的既定方法,并转向使用矢量算术运算和像素和体素作为横向思维方法的构建块。这种方法可以为设计和激发新的空间和形式概念提供新的机会。此外,在这个过程中,机器在设计输出中扮演着积极的角色,而不仅仅是达到目的的手段。在接下来的部分中,我们将通过一系列独特的 3D 形式来展示这一点,这些形式是在潜在空间中使用 4 个初始起点生成的。

结果

为了测试我们的管道,我们在生成的潜在空间中选择 4 个随机点(*面图的图像:A、B、C、D ),并获得它们的矢量表示。然后,我们测试了 4 种不同的插值方法和在这些点之间导航的方法,并生成了总共 200 幅图像,我们稍后将使用这些图像来生成 3D 体素结构。

随机点|来源:作者

一.导航方法 1:等比例

在第一种方法中,我们测试了在插值期间两个*面之间的比率变化对生成形式的影响。作为第一个测试,我们给两个计划一个*等的机会(50:50)。

等比|来源:作者

二。导航方法 2:不等比率

在第二种方法中,我们改变每个插值点的比率。通过改变比率,我们给其中一个图像更高的百分比,以生成与其自身比与另一个图像更相似的图像。

不*等比率|来源:作者

三。导航方法 3:混合

对于第三种方法,我们找到两个点的*均向量,我们在这两个点之间进行插值,并在这些新向量之间进行插值。在这个步骤中,在图像之间进行 50:50 的插值。在下图中,我们显示了每个*面图像的不同百分比的混合结果。

混合|来源:作者

四。导航方法 4:组合混合和不等比率

最后,在最后一种方法中,我们结合了最后两种方法:混合和不等比插值。

混合和不*等比率|来源:作者

上图展示了四种方法的性能。所有这些方法的插值顺序都是从 A 点到 B 点,然后到 C 点,最后到 D 点,每次插值之间有 50 步。

动词 (verb 的缩写)改变顺序

然而,以这种顺序进行插值仅仅是一种可能的方法。在下图中,我们看到了点与点之间不同顺序的插值结果,并展示了这种简单的变化如何显著影响生成的输出。

使用相同的点但不同的插值序列生成的表格|来源:作者

不及物动词改变点

此外,所有这些 3D 结构都是在四个选定点之间进行插值的结果。然而,在如此广阔的潜在空间中,我们有无限的选择空间。下图显示了由不同组的 4 个初始点生成的输出图库。

使用 4 个初始点的不同集合生成的表格|来源:作者

讨论

本文中对 gan 及其内部属性的使用向我们展示了一组新的交互方法,这些方法通常位于传统的架构学科边界之外。通过将这些离散的步骤结合到我们的过程中,我们展示了一个替代的实验空间,其中的形式是通过一系列不同的连续 2D 图像间接生成的。我们认为,使用像素和体素作为建筑的组成部分可以将建筑图纸从精确的工具中解放出来,还可以检索图纸的潜在生成性和横向思维。虽然产生于建筑*面图,但由此产生的高度复杂的形式画廊落在概念模型和建筑结构的交叉点上,描绘了独特的美学特征,并超越了我们今天熟悉的建筑输出。

尽管这些形式源自 2D 计划,但这种方法并不意味着是建筑项目的唯一驱动力。此外,在生成 3D 结构后,需要建筑师的专业知识来将这些形式转化为有意义的架构方案。因此,为了将其转化为一个实用的工具,需要进行进一步的探索,以更好地理解所用方法产生的结果的差异和变化。

3D 结构部分|来源:作者

然而,引入的管道,如果整合到我们的数字流程中,允许产生几个不同的输出,这些输出可能不一定彼此直接相关,这些质量与横向思维方法非常一致。这种方法,以其众多不同的输出和实验性质,可能允许设计者从一个新的角度看待一个问题,或激发新的思考方式。因此,这项新的研究不仅有可能为设计过程中的潜在思维创造新的机制,还可以让设计师摆脱既定的思维方式,并质疑我们通常认为理所当然的工具中嵌入的当前设计技术。

生成的结构|来源:作者

结论

这篇文章展示了未来探索设计工具的管道,这些工具鼓励并强调建筑计算工具中的实验和横向思维方法,这些品质在我们今天的工具中并没有得到优先考虑。具体来说,在本文中,我们介绍了一个 4 步人工智能驱动的管道,它使用机器的潜在空间作为数字环境进行设计,我们演示了在这个空间中导航以生成 3D 体素结构的示例。该过程的结果旨在作为可能的架构过程场景的示例,并作为当前方法到推测性设计方法之间的过渡。

我们假设,这样的管道,如果完全整合到数字建筑工具中,可能使我们能够将横向思维融入到我们当前的数字过程中,并将我们的建筑工具从工业时代的思维中拉出。因此,通过强化不确定性和不可预测性,这门学科的课程可以根据我们的数字未来进行调整。

这篇文章还提出了计算机不仅作为工具,而且作为设计过程中的合作者的使用,以及人机交互的下一步。与我们今天拥有的数字工具不同,所呈现的管道不是遵循直接的输入输出关系,而是允许机器自由地处理像素,并贡献自己对输入的理解来生成绘图。这种基于机器感知和习得特征的不精确和不准确的特殊空间是想象力和横向思维的潜力所在。这为我们提供了以新的和新颖的方式处理建筑图纸的机会,并可能允许发现新的空间和以前“不可想象”的概念。这也引入了一个由人类逻辑和偏见做出的设计决策,并允许我们重新想象我们的设计方式,以及我们如何以新的和令人兴奋的方式表达我们的建筑环境。

参考

奥斯汀,m .,&马修斯,L. (2018 年 1 月)。绘图不精确:以位和像素表示的数字绘图。《不精确和不忠的重新校准——建筑计算机辅助设计协会第 38 届年会论文集》,ACADIA 2018。

博诺,经济学博士(1985 年)。六顶思考帽。利特尔·布朗公司。

Chaillou,S. (2019 年 7 月 17 日)。ArchiGAN:公寓建筑设计的生成堆栈。检索自https://dev blogs . NVIDIA . com/archigan-generative-stack-apartment-building-design/

马萨诸塞州克莱普尔(2019)。大会 2019。大会 2019。从 https://www.youtube.com/watch?v=PxAQL7y9wCw取回

马萨诸塞州克莱普尔(2020 年 1 月 9 日)。建筑中的数字:过去、现在和未来。从https://space10.com/project/digital-in-architecture/取回

纽约克罗斯(2006 年)。设计者的认知方式。斯普林格伦敦。doi:10.1007/1–84628–301–9。

k .多斯特和 n .克罗斯(2001 年)。设计过程中的创造力:问题解决方案的共同进化。设计研究,22(5),425–437 页。

黄,魏,郑,H. (2018 年 10 月)。基于机器学习的建筑图纸识别和生成。《建筑计算机辅助设计协会(ACADIA)第 38 届年会论文集》,墨西哥墨西哥城(第 18-20 页)。

t .卡拉斯、s .莱恩和 t .艾拉(2019 年)。一种基于风格的生成对抗网络生成器体系结构。IEEE 计算机视觉和模式识别会议论文集(第 4401–4410 页)。

Klemmt,c .,Pantic,I .,Gheorghe A .,Sebestyen,a .(2019)。离散与离散生长:用细胞生长模拟生成的几何形状的离散制造。《阿卡迪亚学报》,2019 年。

劳森,B. (2006 年)。设计师如何思考:设计过程去神秘化?劳特利奇。

刘,h,廖,l,斯里瓦斯塔瓦,A. (2019)。匿名作文。《阿卡迪亚学报》,2019 年。

j .梅(2018)。信号。形象。建筑。哥伦比亚大学出版社。

米勒,人工智能(2019)。机器中的艺术家:人工智能驱动的创造力世界。麻省理工出版社。

1999 年,张克宏,郑春燕,森和古川。House-GAN:用于图约束房屋布局生成的关系生成对抗网络。arXiv 预印本:2003.06988。

牛顿博士(2019)。建筑设计中的生成性深度学习。技术|建筑+设计,3(2),176–189。

伊索拉,p .,朱,J. Y .,周,t .,& Efros,A. A. (2017)。基于条件对抗网络的图像到图像翻译。IEEE 计算机视觉和模式识别会议论文集(第 1125-1134 页)。

Retsin,G. (2019)。离散:重新评价建筑中的数字化。约翰·威利父子公司。

m . w . Steen son(2017 年)。建筑智能:设计师和建筑师如何创造数字景观。麻省理工出版社。

计算机视觉和黑色素,DEI 案例研究

原文:https://towardsdatascience.com/computer-vision-and-melanin-a-dei-case-study-df4a6f304a01

为了纪念黑人历史月,我想写关于机器学习的进步和错误,特别是计算机视觉,以及拥有一个大而多样的数据集的必要性

照片由 奥拉迪梅吉

我这个月开始以兼职教授的身份教书,这让我非常兴奋。由于我教授数据科学 101,我希望我的学生在他们早期的数据科学之旅中带走的一点是建立道德模型的责任,以及即使是大公司也没有做好这一点,以及成为努力做好这一点的工人阶级的一部分是多么重要。

让我们谈谈解决谷歌等科技巨头多年来缺乏训练数据多样性的许多机器学习算法之一的最新进展。最*,我通过广告听说谷歌推出了智能手机上最具包容性的摄像头。据说谷歌的 Pixel 6 拍摄了数千张照片,使他们的训练数据因其 Real Tone 技术而变得更加多样化 25 倍。《华尔街日报》的这篇文章展示了这些对比,确实表明谷歌的 Pixel 6 看起来最清晰,而且未经编辑;它不会像这些照片中的三星 Galaxy S21 那样提亮较暗的皮肤。

在培训数据方面,他们的产品营销经理在 Pixel 6 发布会上指出,他们的培训数据现在多样化了 25 倍。我不知道他们是否在将其与他们的原始训练数据进行比较。让我们假设这是因为他们提到他们拍了几千张照片,而不是几万张。所以假设他们加了 9000 张图片。这可能意味着最初他们的有色人种训练数据集可能有数百个。他们是否认为深色皮肤是一种二项式分类,他们只需要数百张黑人的照片,而不考虑肤色的多样性?蕾哈娜的化妆品牌 Fenty Beauty 推出时,推出了 40 种不同色调的化妆品,最*又增加了 10 种,这在化妆行业引起了轰动和破坏(以一种好的方式)。自从人们认识到人的肤色可以表现为大范围的色调分布后,他们觉得更多的人看到了她的化妆品品牌。现在很难想象人们的化妆需求最终得到了满足,他们会回到不那么包容的东西上去。

在我们考虑需要多少数据样本来支持这种色调分布之前,让我们先从高层次上了解一下计算机视觉是如何工作的。与我们相似,计算机视觉算法也可以检测模式,只是我们接*模式的方式与计算机发现模式的方式非常不同。计算机对像素进行数学运算。像素是代表图像的最小单位。像素以值的形式保存信息,值的范围从 0 到 255,分别表示黑到白。

瓦迪姆·博古洛夫Unsplash 上的照片

计算机视觉的一些领域包括:

  • 边缘检测检测图像的边缘。这篇文章展示了索贝尔公式背后的数学原理来证明边缘,下面的视频也是如此。

  • 对象检测将边界框应用于感兴趣的对象

  • 对象分割对属于每一类的所有像素进行分类

  • 图像分类将分类标签应用于整个图像。比如这个图像里有猫吗?

下面的视频展示了对象检测与对象分割和图像分类之间的区别。

当你开始学习数据科学时,他们展示的最受欢迎的图像分类数据集之一是 MNIST 数据集,这是一个手写数字的大型数据集。参考链接还展示了自 1998 年以来的不同算法及其测试错误率。正如您在该链接的表格中看到的,直到我们进入多层神经网络、卷积等不同方法和更大的模型,测试错误率才会下降。这些类是数字 0 到 9 的手写数字。训练数据集是 60,000 个样本,测试数据集是 10,000 个样本。这是每个数字*均 6000 个训练样本。

尽管有人可能会争辩说,技术和计算每年都有更大的进步,更多的训练数据解决所有问题还不够。然而,与推进实际技术相比,这是一个良好的开端,而不是沉重的负担。

回到这个问题,我们需要多少数据样本才能开始使用人脸作为算法的输入?深度神经网络(DNNs)已经证明它们具有低错误率*(当正确使用时)。挑战在于它需要非常大的数据集。萨利赫·沙欣法尔、保罗·米克、格雷格·法尔松写道:“我需要多少张照片?”虽然不是关于人,但这是一项“了解每类样本量如何影响自主野生动物监测中*衡设计的深度学习模型性能指标”的研究。在他们的研究中,你会看到他们的错误率随着数据集规模的增加而下降。

感觉就像一个能够接触到最聪明的人和资源的大型科技巨头花了一分多钟来解决他们的机器学习产品中的偏见。2015 年当谷歌的技术将黑人的图像分类为大猩猩时,2018 年的“修复”是完全删除大猩猩的标签作为一种预测。技术和数据规模并不是唯一的挑战,还有伦理方面的挑战。我们需要问自己这样一个问题,“这是弊大于利吗?”。就像帕累托原理一样,80%的结果来自 20%的努力。目前,领先的科技巨头对这项技术的应用有着最大的影响力。2018 年 5 月,亚马逊的 Rekognition 算法错误地将大约 30 名国会议员与面部照片关联起来,这一臭名昭著的事件引发了人们的关注。在接下来的几年里,从旧金山开始,该市禁止使用面部识别软件,这将限制执法机构利用它进行监控。其他城市在以下领域效仿;圣地亚哥、波特兰、波士顿、马萨诸塞州,以及 2021 年 7 月的弗吉尼亚州。

我想到的最好的研究例子之一是 Joy Buloamwini 博士在麻省理工学院的论文陈述性别差异,它放大了这些科技巨头的面部识别软件的差距,尤其是在有色人种女性中。她指出的问题还是缺乏训练数据。她发现,当将 IBM、微软和亚马逊的分类器应用于一个更加*衡和多样化的人物图像数据集时,她基于来自世界各地 3 个非洲国家和 3 个欧洲国家的 1270 名政治家构建了这个数据集。在她的论文中,她举例展示了来自试点议会基准(PPB)数据集的图像样本,其中 44%为女性,47%为深色皮肤。相比之下,在她的论文中,她发现用于训练这家科技巨头的性别分类器的数据集不成比例地大多是浅色皮肤,最小的一组深色皮肤女性约占数据集的 4%。

当她将性别分类器应用于 PPB 数据集时,她发现最佳分类器的错误率在肤色较深的女性中比肤色较浅的女性高 32 倍。

就像我们数据科学家如何通过查看各种分类分数来执行模型选择一样,我们也必须在多维空间中查看它们,尤其是在处理人口统计数据时。在她的论文中,你会发现 Buloamwini 博士提出的记分卡的一个例子,以促进未来面部识别数据集中的多样性。

面部识别在执法部门以外也有使用案例,如生物信息学,如苹果的 Face ID。还有拉纳·埃尔·卡利欧比博士的作品,我喜欢读她的新书《T2 女孩解码》。她在麻省理工学院时是人工智能情感领域的先驱。最初,她的想法是用情商来增强技术,以帮助被诊断患有自闭症的人进行社交互动。患有自闭症的人在社交场合很难区分情绪,2006 年,Rana 和麻省理工学院媒体实验室一起创造了智能眼镜,帮助自闭症患者识别他们正在交往的人的情绪。在她的书中,她谈到了作为妻子、母亲、计算机科学家、她的公司、研究和文化的生活。在一次事件中,她一直在全力处理这件事,她遭遇了一场车祸,她写道,如果她的车能在开车前判断她的情绪状态,这可能会有助于防止车祸的发生,

因此,我留给读者的问题是:除了增加训练数据,我们如何确保我们生活中使用的算法是合乎道德和负责任的?即使这项技术是可行的,我们还应该利用它吗?使用或不使用它的含义是什么?

计算机视觉:卷积基础

原文:https://towardsdatascience.com/computer-vision-convolution-basics-2d0ae3b79346

深入探究许多神经网络的基本单元。

图 0:火焰的火花,类似于使用卷积提取的特征(图片由作者提供)

在这个深度学习的时代,我们有先进的计算机视觉模型,如 YOLO、Mask RCNN 或 U-Net 等,所有这些模型背后的基础细胞是卷积神经网络(CNN),或者更精确地说是卷积运算。这些网络试图解决对象检测、分割和实时推理的问题,这导致了许多现实生活中的用例。

因此,让我们来看看基础知识,在这一系列教程中,我将深入探讨以下基本主题,以创建能够带来许多此类创新的整体学习:

  1. 卷积的 A-Z。
  2. 深入分析 1D,2D 和三维有线电视新闻网层。
  3. CNN 在 2D 的前向传播。

说够了…我们开始吧:)

图 1: 2D 卷积示例(维基媒体)

介绍

在本教程中,我们将发现卷积运算符及其各种参数的本质。完成本教程后,您将了解:

  1. 回旋
  2. 过滤器和内核
  3. 步幅和衬垫
  4. 真实世界的用例

什么是卷积?这有什么关系?为什么要用卷积?

这些是每个数据科学家在其深度学习之旅中至少会遇到一次的一些问题。我时不时会有这些疑问。

因此,从数学上讲,卷积是两个函数(矩阵)上的一个运算符,它产生第三个函数(矩阵),第三个函数是具有不同特征(矩阵中的值)的另一个函数的修改输入。

在计算机视觉中,卷积通常用于从输入图像中提取或创建特征图(在内核的帮助下)。

基本术语

图 2: 2D 卷积(GIF 由文森特提供)

在上图中,蓝色矩阵是输入,绿色矩阵是输出。而我们有一个内核通过输入矩阵来获取/提取特征。所以我们先来了解一下输入矩阵。

输入矩阵:一幅图像由像素组成,其中每个像素都在[0,255]的包含范围内。所以我们可以用矩阵来表示一幅图像,每个位置代表一个像素。像素值代表其亮度,即 pixel - > 0 为黑色,pixel - > 255 为白色(最高亮度)。灰度图像只有一个像素矩阵,即它没有任何颜色,而彩色图像(RGB)有 3 个通道,每个通道代表其颜色密度。

图 3:数字 8 的灰度图像;形状(24x 16);每个像素(0-255)代表颜色的亮度/密度(图片由作者提供)

上图的形状是:(24,16)其中高度= 24,宽度= 16。类似地,我们有一个有 3 个通道的彩色图像(RGB ),它可以用一个形状矩阵来表示:(高度、宽度、通道)

现在,我们知道了卷积算子的第一个输入是什么,但是如何对这个输入进行变换,得到输出的特征矩阵。这里出现了术语“内核,它作用于输入图像以获得所需的输出。

内核:在一幅图像中,我们可以说一个像素包围另一个像素具有相似的值。为了利用图像的这一特性,我们有了核。核是一个小矩阵,它使用定位能力从给定的图像(输入)中提取所需的特征。通常,内核比输入图像小得多。我们有不同的内核用于不同的任务,如模糊,锐化或边缘检测。

卷积发生在输入图像和给定的核之间。它是输入图像的内核和本地化部分之间的滑动点积。

图 4:输入(5,5);内核(3,3);卷积 2D(作者图片)

在上面的图像中,对于第一次卷积,我们将在图像中选择一个 3x3 的区域(顺序),并与内核进行点积。哒哒!这是我们做的第一个卷积,我们将逐个像素地移动感兴趣的区域。

图 5:图像中内核和选定区域之间的卷积(图片由作者提供)

感兴趣区域(ROI)的维度总是等于核的维度。我们在每个点积之后移动这个 ROI,并继续这样做,直到我们得到完整的输出矩阵。

图 6:水*核的 2D 卷积(图片由作者提供)

现在,我们知道了如何执行卷积,输入到底是什么,以及内核是什么样子。但是在每个点积之后,我们将 ROI 滑动一些像素(可以跳过 1、2、3 …个像素)。该功能由一个名为步幅的参数控制。

步幅:该参数控制/修改图像中 ROI 的移动量。大于 1 的跨距用于减小输出尺寸。直观地说,它跳过了每个点积中的几个像素的重叠,这导致了输出的最终形状的减少。

图 7:2D 卷积的例子

在上面的图像中,我们总是将 ROI 移动 1 个像素,并使用内核执行点积。但是如果我们增加步距,假设步距= 2,那么输出矩阵的维数将是-> 2 x 2(图 8)。

图 8:2D 卷积中的步幅= 2

多通道图像卷积

现在,我们知道了输入是什么样子,还有一些通用参数,比如 kernel 和 stride。但是,如果我们在图像中有多个通道,即图像是彩色的,或者更准确地说,如果输入矩阵的形状是:(高度、宽度、通道),其中通道大于 1,那么卷积如何工作呢?

图 9:彩色图像;RGB (BGR)通道(图片由作者提供)

现在你可能有一个问题,我们只有一个内核,如何在一堆 2D 矩阵上使用它(在我们的例子中,三个 2D 矩阵堆叠在一起)。所以这里我们将引入术语'滤波器

通常人们会互换过滤器和内核,但实际上它们是不同的。

滤波器:是一组用于图像卷积的核。例如:在一个彩色图像中,我们有 3 个通道,对于每个通道,我们有一个内核(用于提取特征),一组这样的内核被称为过滤器。对于灰度图像(或 2D 矩阵),术语滤波器等于内核。在一个过滤器中,所有的内核可以相同,也可以不同。特定的核可以用于提取特定的特征。

那么卷积是如何发生的呢?

图 10:彩色图像上的 2D 卷积

每个通道由它的内核来执行(完全类似于灰度图像上的卷积)以提取特征。所有的内核应该有相同的尺寸。因此,我们将多个输出矩阵(每个通道一个)组合(借助矩阵加法)成一个输出。

图 11:将多个通道的输出聚合成一个通道(图片由作者提供)

因此输出是给定图像的特征图(提取的特征)。我们可以进一步将该输出与经典的机器学习算法一起用于分类/回归任务,或者该输出也可以被用作给定图像中的变化之一。

填充和输出尺寸

此时,我们对图像和内核之间的卷积是如何发生的有了相当不错的理解。但这还不够。有时,需要得到与给定输入尺寸相同的精确输出尺寸,我们需要将输入转换成不同的形式,但大小相同。下面是填充的用法。

填充:它有助于保持恒定的输出大小,否则在使用内核的情况下,输出是一个较小的维度,在某些情况下可能会产生瓶颈。此外,填充有助于保留图像边界的信息。在填充中,我们用假像素填充图像的边界(边缘)。更常见的是,我们使用零填充,即在矩阵的边缘添加暗像素,这样原始边缘像素的信息不会丢失。

图 12:填充示例(Vincent的 GIF)

我们还可以添加多个填充,即,我们可以在边界使用 n 个像素,而不是在每个边缘使用单像素填充。这通常由卷积中使用的核维数决定。

图 13:2D 卷积中两个像素的填充

恭喜你!我们已经讲述了卷积运算的基本概念。但是,我们如何知道矩阵的输出形状呢?为了回答这个问题,我们有一个简单的公式来帮助计算输出矩阵的形状。

图 14:计算输出矩阵的宽度和高度(图片由作者提供)

其中:
wᵢ - >输入图像宽度,hᵢ - >输入图像高度
wₖ - >内核宽度,hₖ - >内核高度
sᵥᵥ - >步幅为宽度,sₕ - >步幅为高度
pᵥᵥ - >沿图像宽度填充,pₕ - >沿图像高度填充

通常,卷积中的填充、步幅和内核是对称的(高度和宽度相等),这将上述公式转换为:

图 15:对称输入图像的宽度/高度和其他参数的计算(图片由作者提供)

其中:
i - >输入形状(高度=宽度)
k - >内核形状
p - >沿图像边缘填充
s - >用于卷积的步幅(用于滑动点积)

那么,现在怎么办?在接下来的部分中,我们将学习不同类型的内核,它们被设计来对图像执行特定的操作。

图像内核

卷积有两种不同的用法:或者在梯度下降的帮助下利用卷积神经网络中的可学习内核,或者利用预定义内核来转换给定图像。今天,我们将关注后一种,并学习在内核的帮助下,所有不同类型的转换都是可能的。

让我们把这看作一个输入图像。

图 16:输入图像(代表图像的矩阵)(图像由维克多拍摄)

现在,在内核的帮助下,并对输入图像和给定内核使用卷积,我们将给定图像转换成所需的形式。下面是一些变换,可以在图像卷积中的自定义内核的帮助下完成。

  1. 检测水*线和垂直线
  2. 边缘检测
  3. Photoshop 中的模糊、锐化、轮廓、浮雕和其他各种变形
  4. 侵蚀和膨胀

那么我们先来看一个最基础的内核,它就是模糊内核。模糊内核有很多种,但最著名的是高斯模糊和方块模糊。

图 17:模糊内核(作者图片)

图 18:给定图像上的高斯模糊(图像由维克多拍摄)

类似地,其他内核有助于将图像转换成所需的形式。在上面的图片中,我们有一个很好的插图来尝试不同的内核:【https://setosa.io/ev/image-kernels/

但一般来说,有一些核心,我们作为数据科学家应该掌握,它是线检测核心,主要包括水*,垂直和对角线。

图 19:线条检测内核(图片由作者提供)

从上图来看,这些线检测内核的直观性非常清晰。假设任务是检测图像中的水*线。让我们构建一个相同的内核。所以一般来说,3 x 3 内核是一个不错的选择。现在来检测水*线(根据上面的直觉),如果我们减去所有附*的像素,认为它是一条水*线。在这种情况下,水*线将很容易看到,因为我们已经减少了其附*的像素值,这将是一条直线或与我们希望检测的线类型精确*行。

但是对于要检测的线,我们应该以什么样的比例减少附*的像素或者增加像素呢?实际上,这完全取决于用例以及内核的几次迭代,以获得良好的匹配。

我们来玩一下给定的水*核及其卷积结果。

图 20:水*线检测(图片由作者提供)

惊讶!因此,从图 20 中,我们可以很容易地说明,如果我们增加基本水*内核中的值,那么只会检测到几行。这就是内核对图像的影响。此外,我们还可以通过给定值的对称修改来增加/减少给定核的密度。

这就是了…希望你了解并喜欢:D 的博客

结论

在给定的博客帖子中,讨论了以下主题:

  1. 卷积的基本术语:输入、内核、步长、填充、滤波器
  2. 灰度图像和彩色图像的区别
  3. 灰度和彩色图像的 2D 卷积
  4. 卷积运算符输出的形状
  5. 探索不同的图像内核

在接下来的教程中,您将了解 CNN 图层的深入工作、CNN 图层的前向和后向传播、不同类型的 CNN 图层以及一些用于提取特征地图的最新深度学习模型。

参考

[1] CS231n 用于视觉识别的卷积神经网络https://cs231n.github.io/convolutional-networks/

[2] Vincent Dumoulin,Francesco Visin,深度学习卷积算法指南,https://arxiv.org/abs/1603.07285

[3]线路检测,【https://en.wikipedia.org/wiki/Line_detection】T2

[4] Irhum Shafkat,直观理解用于深度学习的卷积,https://towards data science . com/intuitive-Understanding-Convolutions-for-Deep-Learning-1 f6f 42 faee 1

[5]维克托·鲍威尔,图像内核,https://setosa.io/ev/image-kernels/

浏览器中的计算机视觉、自然语言处理和游戏

原文:https://towardsdatascience.com/computer-vision-nlp-and-gaming-in-the-browser-8e5fcf895a14

释放 Python Panel、Pyodide 和 PyScript 的威力

索菲亚·杨马克·斯科夫·麦德森

照片由 Karly SantiagoUnsplash 上拍摄

我们现在生活在一个可以在浏览器中运行 Python 的时代,拥有 WebAssembly、Pyodide 和 PyScript 的强大功能!这对数据从业者和开发者意味着什么?这意味着我们可以运行计算机视觉任务,NLP 任务,甚至完全用 Python 开发游戏,并直接在浏览器中运行您的 Python 代码。一切都发生在你的浏览器里!

本文将向您展示三个简单的示例,展示在浏览器中运行 Python 计算机视觉应用程序、文本分析应用程序和简单的琐事游戏的潜力。

怎么会?

本文中的三个例子都是从 Python 面板仪表板开始的。 Panel 是来自开源 HoloViz 生态系统的 dashboarding 库。要了解如何用 Python 制作面板仪表盘,请查看我们之前的博客文章构建面板仪表盘的三种主要方式如何将面板可视化仪表盘部署到 Github 页面

一旦你有了一个 Panel 应用app.py,用一行代码使用panel convert,你就可以将你的 Panel 应用转换成 WebAssembly(这个特性非常感谢 Philipp Rudiger ):

panel convert app.py — to pyodide-worker — out docs

Panel convert 可以使用 pyodide 或 pyscript 作为后端,但 pyodide worker 目前是更快的选择。查看面板文档以了解您可以选择的不同参数。

计算机视觉

自己试试 app:https://awesome-panel . github . io/examples/videostream-interface/app . html

Code:https://github . com/awesome-panel/examples/blob/main/src/videostream-interface/app . py

我们的第一个示例显示了一个计算机视觉应用程序,用于显示来自网络摄像头本地流的视频,并执行实时视频转换和人脸检测。该应用程序有两个主要组件:

  • pn.widgets.VideoStream是一个面板小工具,允许我们与网络摄像头流进行交互。
  • Scikit-image 是 Python 中的一个图像处理库,它处理所有的变换和人脸检测。

只需几百行 Python 代码,您就可以在 Python 广泛的开源库生态系统的基础上,轻松构建一个像这样进行复杂图像处理的应用程序。

自然语言处理

自己试试 app:https://sophiamyang . github . io/panel _ simple _ text _ analysis/text _ analysis . html

代码:https://github . com/sophiamyang/panel _ simple _ text _ analysis/blob/main/text _ analysis . ipynb

我们的第二个例子展示了一个简单的文本分析。您可以在输入文本框中键入文本或上传文件,然后您将看到该文本的情感分析、N 元语法分析和主题建模结果:

  • 情感分析使用 TextBlob 并返回极性和主观性。极性范围从-1 到 1,其中-1 为负,1 为正。TextBlob 还可以使用主观性函数来计算主观性,主观性的范围是从 0 到 1,0 是客观的,1 是主观的。
  • n 元语法分析通常用于查看哪些单词经常一起出现。我们通常喜欢研究两个或三个单词的组合,即二元/三元模型。
  • 有许多方法可以进行主题建模。在这个例子中,我们使用了非负矩阵分解(NMF)方法

要了解更多关于 Python 中基本文本分析的知识,请查看我们的之前关于这个主题的博文

赌博

https://sophiamyang.github.io/panel_trivia_game/trivia.html】亲自试用 app:

代码:https://github . com/sophiamyang/panel _ trivia _ game/blob/main/trivia . ipynb

你能做一个游戏并在浏览器中运行吗?是的,绝对的!您的 Panel 应用程序完全不需要与数据相关。

在这个例子中,我们构建了一个非常简单的琐事游戏应用程序。我们定义了问题的数量、难度和游戏的类别,然后我们会看到一个问题列表,让我们决定每个问题是对还是错。这款应用有两点值得一提:

  • 我们使用requestsOpen Triva 数据库 API 中获取琐事游戏问题。
  • 类似于 Java 中的 SetOnClickListener 等方法和其他语言中的类似方法,使用 Panel,我们可以传递一个 Python 函数on_click来确定当有点击时执行什么。

这三个应用只是展示我们可以用 Panel 和浏览器做什么的潜力的开始,不需要服务器!再努力一点,你就可以制作更多复杂的面板应用程序,并在浏览器中运行它们。请随时在https://discourse.holoviz.org/分享您的申请,我们期待看到您的创造。

鸣谢:

感谢 Jim Bednar 和 Phillipp Rudiger 的指导和反馈!

参考文献:

. . .

索菲亚杨马克斯科夫麦德森于 2022 年 10 月 26 日。

Sophia Yang 是 Anaconda 的高级数据科学家。在 LinkedInTwitterYouTube 上与我联系,并加入 ds/ml❤️读书俱乐部

在社交网络数据集上计算分类系数

原文:https://towardsdatascience.com/computing-assortativity-coefficients-on-a-social-network-dataset-7f65796feb70

分类性有助于分析网络中的连接模式。让我们用它来确认人们是否倾向于与相似的人联系。

照片由法比奥Unsplash 上拍摄

在本文中,我们将使用一些脸书数据来探索网络分类性(也称为同向性)的概念,我们将其定义为节点连接到其相似节点的趋势。

网络或图形是由节点(顶点)和边(链接)组成的数据表示:在本文中,我们将只考虑无向和未加权的边。我们将首先呈现我们打算使用的数据集,经历数据加载和争论步骤,并呈现网络。

接下来,我们将介绍网络匹配度的概念。将使用的主要理论框架是 Newman 等人 2003 年[1]的文章,该文章定义并解释了网络分类度的概念。

然后,我们将把这一指标应用到数据集上,以确认是否——如文章所述——人们倾向于与和他们相似的人联系。

1.数据

文中用到的数据[2]可以从本页下载。我们需要两套文件:

  1. 文件“Facebook _ combined . txt . gz”包含来自 10 个网络的 4039 个节点的边。边以邻接表格式表示(即[0,1]表示节点 0 和节点 1 之间有一条边)。
  2. 文件“Facebook . tar . gz”包含其他几个文件。我们将只使用”。“和”的壮举。featnames”文件,它对应于所有节点的网络属性(及其名称)。

1.1 加载网络

我们将使用 Python 中的 NetworkX 库。

导入主网络文件非常简单:

让我们快速浏览一下网络。以下表示允许显示两个重要特征:

  1. 节点颜色将随节点度数(即每个节点拥有的连接数)而变化。
  2. 节点大小将根据节点介数中心性而变化,介数中心性是一种量化节点有多少位于其他节点之间的路径上的度量,或者换句话说,该度量量化移除具有高介数中心性的节点会破坏网络的程度。这一指标的公式如下:

作者图片

n^i_st:表示从“s”到“t”经过节点“I”的最短路径数;
g_st:是从“s”到“t”的不一定经过节点“I”的最短路径总数;
n:是节点的总 nr,可以省略 1/n 项。

作者图片

1.2 添加节点属性

为了给节点分配属性,我们需要解析以下文件:

  • ".feat”文件包含 0/1 条目的矩阵。每行代表一个节点,每列代表一个属性。如果节点“I”具有属性“j ”,则条目
  • 每一行都在”。featnames "文件包含来自"的相应列的名称。“档案壮举。这样,我们就能够理解每个属性的名称。

使用 nx 库,我们可以通过以下方式为节点分配属性:

最后,我们可以获得每个节点的所有属性信息,例如节点 id“200”:

作者图片

2.属性匹配系数

在社会网络的研究中,分析节点之间的连接模式起着重要的作用。分类性有助于理解人们是否倾向于连接到相似或不相似的节点,并且这种网络属性可能影响网络结构:例如,在离散属性上的强分类性可能将网络分成子网。假设出生年份是一个非常强的分类属性:因此我们可以期望不同年龄的人的子网连接在一起。

纽曼等人。all (2003)在他们的文章中定义了一种度量网络中的配合度的方法,即配合度系数(也可在 NetworkX 库 Link1Link2 ):

  • 让我们考虑一个节点的属性。该属性可以取值:【A1,A2,…】
  • 我们可以构建一个混合矩阵 M,其中条目 e[i][j] 表示网络(E)中 tot 条边的分数,该网络将具有属性 A = A[i] 的节点连接到具有属性 A = A[j] 的节点

作者图片

  • 然后,我们构建以下数量:

作者图片

  • 配合系数可以用下面的公式计算(第二个公式使用 tr()迹的矩阵符号。我们将在下面看到一个例子):

作者图片

2.1 计算匹配系数

让我们计算可用数据集的一个属性的系数:“性别”。在我们的数据集中,该属性可以采用 3 个值:“匿名特征 77”、“匿名特征 78”和“无”。

首先,以这种方式获得混合矩阵:

作者图片

(注意:通过设置 normalized = False,我们将在矩阵中获得有效的边数)。

我们现在将使用矩阵符号公式计算系数:

  • 矩阵轨迹(主要对角线元素的总和)表示连接节点之间性别相同的连接部分。这种情况下的痕迹是:53.65%
  • 然后我们需要混合矩阵的*方和

最终结果是:0.0841

这个系数可以从-1(完全不同配的情况)到+1(完全匹配),在这种情况下,我们在这个属性上有一个低的但是正的匹配。

3.结论

通过对每个属性重复上述过程,我们可以找到网络中最合适的属性:

作者图片

正如所料,网络似乎是分类的,特别是在与地理位置、出生年份、姓氏、学校相关的属性上,这些属性可以决定人们相遇的环境或原因。唯一有点不相称的属性是政治倾向。

参考

有效地连接多个(混乱的)数据帧

原文:https://towardsdatascience.com/concatenate-multiple-and-messy-dataframes-efficiently-80847b4da12b

如何批处理和连接带有杂乱数据的数据帧

图片由 Pixabay 提供(作者修改)

在数据世界中,连接数据集是一项非常常见的数据管理任务。根据您的需要,您可能需要通过垂直堆叠来连接多个数据帧(与 SQL 中的“union”操作相同)。或者,您可能需要通过基于一些公共键水*连接或合并它们来连接它们。

当垂直连接数据集时,假设数据帧具有相同的列名,并且列的顺序相同,我们可以简单地使用pandas.concat()方法来执行连接。我们只需要指定axis=0,它告诉pandas将第二个数据帧堆叠在第一个之下,将第三个堆叠在第二个之下,依此类推。

pd.concat([df1, df2, df3], axis=0)

如果您有相当多的数据集(比如 8 个或 10 个)要连接,并且这些数据集可能有不同的列名或者列的顺序不同,该怎么办?当然,您可以逐个导入和处理每个数据集,然后将它们连接起来。但是,有没有更优雅、更高效的方法呢?

在这篇文章中,我将带你看一个真实世界的例子,在这个例子中,我们可以使用for loop和一些Pandas技巧有效地批处理和连接多个混乱的数据帧。用于演示的数据文件可以从 Kaggle 下载。总共有 8 个 csv 文件。从 2015 年到 2022 年的每一年,每个文件都包含了 153 个国家的幸福得分以及用于解释得分的因素。

作者图片

我们的目标是将这些文件连接成一个包含三列的数据框架——一个“年份”列、“国家”列和“幸福指数”列。稍后,我们可以创建一些有趣的数据可视化来显示幸福分数在不同国家之间的差异以及随时间的变化。让我们看看它是如何工作的。

第一步:

让我们首先使用 Python 的glob函数返回所有文件路径的列表。这将有助于我们使用for loop一次将所有文件读入 pandas 数据帧。

第二步:

接下来,让我们使用for loop将所有文件读入 pandas 数据帧。如果这些数据集都有相同的列名,并且列的顺序相同,我们可以使用pd.concat()轻松地将它们连接起来。让我们使用下面的代码来检查一下是否是这种情况(注意,在第 4 行中,为了方便检查,我将所有的列名都改成了小写)。

作者图片

这 8 个数据集有不同的列,它们有不同的列数、不同的列名和不同的列顺序。例如,如上面的屏幕截图所示,在一个数据帧中,幸福分数的列名为“幸福分数”,而在其他数据帧中,该列名为“幸福分数”、“分数”或“阶梯分数”。

鉴于数据的混乱,直接连接这 8 个数据帧是不可行的。在拼接之前我们需要做一些预处理,我们可以使用for loop来批量处理它们。

第 1 行:我们创建一个空列表dfs。稍后,我们将用for loop迭代将每个数据帧添加到这个列表中。

第 6–7 行:我们根据从列名中观察到的特定模式,从每个数据帧中迭代并提取“国家”列和“幸福指数”列。

第 9–11 行:我们创建了一个新的 dataframe df1,它只有我们需要的三列——country _ col、score_col 和 year_col。

第 13 行:我们使用for loop迭代将 8 个预处理数据帧中的每一个添加到列表dfs中。

第 14 行:我们将相同的列名分配给列表中的所有数据帧,以便在下一步中连接它们,这需要相同的列名。

通过参考 dfs[0]、dfs[1]、dfs[2]等,您可以快速查看我们刚刚创建的每个数据帧的外观。

图像

第三步:

最后,由于所有数据帧都有相同的列名和顺序,我们可以使用pd.concat()方法轻松地将它们连接起来。在第 1 行中,我们连接了列表dfs,中的所有数据帧,在第 2–3 行中,我们清理了“幸福分数”和“国家”列,以确保我们的数据为下一部分的可视化做好准备。

作者图片

额外收获:一张显示全球幸福水*的动画地图

在充分准备和清理了我们的数据后,让我们使用plotly.express创建一个动画 choropleth 地图,显示全球的幸福水*。

关于Plotly的一个好处是,它有自然地球数据集中定义的国家的内置几何图形,并且不需要外部 GeoJSON 文件来绘制 choropleth 地图。要使用内置的国家几何图形,我们只需提供locations作为三个字母的 ISO 国家代码

第 3–6 行:我们通过将 df_all 与 df_ISO 连接来添加三个字母的 ISO 国家代码,df _ ISO 具有 ISO 代码,可以在 Kaggle 上下载。

第 9–14 行:我们使用px.choropleth()创建了一个动画的 choropleth 地图。locations参数接受数据集中表示 3 个字母的 ISO 代码的任何列。此外,我们可以通过在animation_frame参数中指定“年份”来轻松地将动画添加到 choropleth 地图中。

第 16–22 行:我们添加了一个地图标题,并调整了它的字体、大小、颜色和位置。

作者 GIF

这就对了。我们批量处理了多个原始的杂乱数据文件,并将它们连接起来,以创建一个数据帧,为分析和可视化做好准备。感谢阅读,我希望你喜欢这篇文章!

数据来源:

  1. 《2022 年世界幸福报告》于 Kaggle 发布。许可证: CC0:公共领域。引文:Helliwell,John F .,Richard Layard,Jeffrey Sachs 和 Jan-Emmanuel 德·内维编辑。2020.2020 年世界幸福报告。纽约:可持续发展解决方案网络

  2. Kaggle 上的“国家 ISO 代码|洲|标志 URL”。许可证: GPL 2

你可以通过这个推荐链接注册 Medium 会员(每月 5 美元)来获得我的作品和 Medium 的其他内容。通过这个链接注册,我将收到你的一部分会员费,不需要你额外付费。谢谢大家!

概念嵌入模型:超越精确性-可解释性的权衡

原文:https://towardsdatascience.com/concept-embedding-models-beyond-the-accuracy-explainability-trade-off-f7ba02f28fad

由马特奥·埃斯皮诺萨·扎伦加和皮埃特罗·巴比洛主演。摘自 NeurIPS 论文“概念嵌入模型”(GitHub)。

TL;博士

  • 问题— 人类对深度神经网络的信任目前是一个公开的问题,因为它们的决策过程是不透明的。目前的方法,如概念瓶颈模型,以降低准确性为代价使模型更易解释(反之亦然)。
  • 关键创新— 一个受监督的概念嵌入层,它学习语义上有意义的概念表示,并允许简单的人工测试时干预。
  • 解决方案——概念嵌入模型增加人类对深度学习的信任,超越准确性-可解释性的权衡——既高度准确又可解释。

概念嵌入模型超越了概念瓶颈模型中的准确性-可解释性权衡,具有*乎最优的任务准确性和概念一致性。最佳权衡用红星表示(右上角)。任务是学习两个向量之间点积的符号(+/-)。图片由作者提供。

学习概念:可解释人工智能的新前沿

概念瓶颈模型(或 CBMs,[1])自 2020 年问世以来,已经成为可解释人工智能的一项重大成就。这些模型试图通过鼓励深度神经网络通过设计 变得更加可解释 来解决人类对人工智能缺乏信任的问题。为此,建立信任措施首先学习它们的输入(例如,猫和狗的图像)和一组" 概念 "之间的映射,这些概念对应于人类通常用来描述他们所看到的事物的高级信息单元(例如,"胡须"、"长尾"、"黑毛"等……)。这个映射函数,我们将称之为“概念编码器”,是通过——你猜对了:)——一个可微分和高度表达的模型(如深度神经网络)学习的!正是通过这个概念编码器,CBMs 然后通过将概念映射到输出标签来解决感兴趣的下游任务(例如,将图像分类为狗或猫):

概念瓶颈模型将任务( Y )作为概念( C )的函数来学习。图片由作者提供。

用于将概念映射到任务标签的标签预测器可能是您最喜欢的可区分模型,尽管在实践中它往往是简单的,如单个完全连接的层。由于 CBM 能够在预测过程中学习中间概念,它们可以:

  • 为他们的预测提供简单的 基于概念的解释 。这些是人类可以直观理解的解释,而不是需要用户高度脑力负荷的基于特征的解释(例如,显著性图)。例如,在图像分类中,基于概念的解释可能看起来像:“如果红色和圆形,那么它是苹果”,这比基于特征的解释更直观,例如:“如果 pixel-#7238 和 pixel-#129,那么它是苹果”。
  • 允许 人类专家与模型 互动,在测试时改变预测错误的概念,通过专家互动显著提高任务准确性。

基于概念的解释和人类干预都极大地有助于增加人类对建立信任措施的信任。这是由于(I)它们的设计可解释架构,(ii)CBM 解释中使用的术语与专家使用的已知人类类别之间的明确一致性,以及(iii)它们对人类交互的本地支持,允许专家通过概念干预测试任务对所学概念的因果依赖性的强度。

概念瓶颈模型增加了人们的信任,提供了直观的基于概念的解释,并支持人们对概念的干预。

童话的结尾:CBMs 中准确性与可解释性的权衡

如同生活中的一切,建立信任措施也有不幸的阴暗面。在最初,概念瓶颈模型试图通过将分类任务限制在类似人类概念的中间水*上来“通过设计”提高可信度。然而,我们的爱情故事到这里就结束了,我们意识到,天下没有免费的午餐。虽然 CBM 在结构上比传统的深度神经网络更具可解释性,但这种新的可解释性可能会以任务准确性为代价!在训练模型所需的概念监督很少的现实情况下,这种情况尤其严重,从而质疑建立信任措施的实际效用。这可以从下图中看出,随着我们监督的概念数量的减少,我们观察到 CBM 的任务准确性急剧下降:

在缺乏概念监督的现实世界条件下,概念瓶颈模型的准确性迅速下降。CUB 数据集。图片由作者提供。

当概念监督不足或分类问题变得棘手时,普通概念瓶颈模型可能会在现实世界条件下崩溃。

为了解决这一限制,Manhipei 等人[2]探索了 CBMs 的混合版本,其中概念层增加了一组无监督的神经元,允许模型使用这一额外的学习能力来解决分类任务:

混合概念瓶颈模型在概念层的无监督神经元中编码额外的信息。图片由作者提供。

这个技巧使得混合 CBM 在任务准确性方面优于普通 CBM。然而,这种性能的提高是以模型的可解释性和可信度为代价的,因为:

  • 额外的神经元通常不符合任何已知的人类概念

  • 概念干预对输出标签的影响急剧下降,这表明模型正在使用额外的神经元而不是学习的概念来解决任务。

从经验上来说,我们可以在任务准确性和基本事实标签与通过下图中不同概念瓶颈模型(我们还包括一个没有概念层作为参考的端到端模型)学习的概念的一致性之间观察到这种折衷:

概念瓶颈模型中的准确性-可解释性权衡(点数据集[3])。最佳权衡用红星表示(右上角)。任务是学习两个向量之间点积的符号(+/-)。图片由作者提供。

普通和混合概念瓶颈模型在准确性和可解释性之间提供了不同的折衷,但是它们远非最佳!

这是所谓的“准确性-可解释性权衡”的一个简单例子:在许多重要的问题中,你可以得到:

  • 一个更简单不太精确的模型(例如 Koh 等人的 CBM)

运筹学

  • 一个更精确更难解释的模型(例如 Manhipei 等人的 CBM)。

可解释性较差的模型的问题在于,人类往往不信任自己的预测,因为他们不理解决策过程,也无法检查这个过程是否有意义——因此质疑部署此类模型的道德和法律影响。

出于这些原因,这种准确性-可解释性权衡是“诅咒”现代机器学习(尤其是基于概念的模型)的最具挑战性的公开问题之一。这就是为什么解决这个问题是这个领域中的“金块”之一!

准确性-可解释性的权衡“诅咒”现代机器学习,包括概念瓶颈模型!在解决重要问题时,很难同时最大限度地提高准确性和可解释性。

除了准确性和可解释性之间的权衡

为了解决基于概念的模型中的这种准确性-可解释性权衡,我们最*提出了 概念嵌入模型 (CEMs,[3]),这是一类基于概念的模型,其中:

  • 该架构将每个 概念 表示为一个 监督向量 。直观上,使用高维嵌入来表示每个概念允许额外的监督学习能力,这与混合 CBM 相反,在混合 CBM 中,流经其非监督瓶颈激活的信息是概念不可知的。
  • 培训程序包括一个规范化策略( RandInt ),在培训 期间将 CEMs 暴露于 概念干预,以提高此类行动在测试时的有效性。

概念嵌入模型将每个概念表示为一个监督向量。图片由作者提供。

我们在简单的玩具数据集和具有挑战性的真实数据集上的实验表明,CEMs:

  • 克服准确性与可解释性的权衡在解决分类问题时与等效的黑盒模型一样准确(甚至可能更准确!)并且在以下方面与传统的 CBM 一样可解释:( a)学习的概念表示与概念基本事实一致的程度:

概念嵌入模型超越了概念瓶颈模型中准确性和可解释性的权衡。最佳权衡在每个图的右上角。图片由作者提供。

  • 支持有效的人类干预允许人类专家与模型互动,通过在测试时修正预测错误的概念来提高预测准确性,这与混合 CBM 相反:

RandInt 的概念嵌入模型支持有效的人工干预(与混合概念瓶颈模型相反)。图片由作者提供。

  • 扩展到缺乏概念监督的真实环境:

概念嵌入模型适用于缺乏概念监督的现实世界。图片由作者提供。

  • 使用每个概念的预测激活状态,提供基于概念的解释作为普通的 CBMs(例如,“如果红色和圆形,而不是翅膀,那么它是一个苹果”)。

概念嵌入模型超越了概念瓶颈模型中准确性和可解释性的权衡——它们既准确又可解释!

最后,通过监督整个嵌入,CEMs 学习概念表示,与混合 CBMs 学习的无监督嵌入相比,概念的激活状态/真值之间的区别更明显,如下例所示:

CUB 数据集中概念的低维表示“有白色翅膀”,显示每个样本的概念激活状态。CEMs 嵌入显示在左侧(a),混合 CBMs 嵌入显示在右侧(b)。图片由作者提供。

这表明 CEM 能够在每个概念向量中编码显式符号信息(即,概念是活动的还是非活动的)子符号概念语义(即,每个概念嵌入中的子集群),这与混合 CBM 相反。

带回家的信息

CEMs 超越了当前的准确性和可解释性的权衡,显著增加了人类的信任度!

特别是 CEM:

  • 作为 准确的 作为标准的端到端模型没有概念(而且往往更准确!);
  • 作为 可解释的 作为标准概念瓶颈模型(而且往往更可解释!);
  • 作为 响应 人为干预的标准概念瓶颈模型。

参考

[1]彭伟高,阮涛,邓耀祥,斯蒂芬·穆斯曼,,曾金,和佩西·梁。概念瓶颈模型。在机器学习国际会议上,第 5338–5348 页。PMLR(2020)。

[2]安妮塔·马欣佩、贾斯汀·克拉克、艾萨克·拉赫、终曲·多希-维勒兹和潘薇薇。黑盒概念学习模型的承诺和陷阱。arXiv 预印本 arXiv:2106.13314 (2021)。

[3] Mateo Espinosa Zarlenga、Pietro Barbiero、Gabriele Ciravegna、Giuseppe Marra、Francesco Giannini、Michelangelo Diligenti、Zohreh Shams、Frederic Precioso、Stefano Melacci、Adrian Weller、Pietro 莉雅和 Mateja Jamnik“概念嵌入模型”arXiv 预印本:2209.09056 (2022)。

概念学习:让你的网络具有可解释性

原文:https://towardsdatascience.com/concept-learning-making-your-network-interpretable-735a0698fc03

eberhard grossgasteiger 在 Unsplash 上的照片

O 在过去的十年里,神经网络在各种各样的数据集和问题上表现出了卓越的性能。虽然准确性和 F1 分数等指标通常适用于衡量模型学习数据底层结构的能力,但模型的表现仍然像一个黑盒。这一事实通常使得神经网络不能用于安全关键应用,在这些应用中,人们需要知道预测是基于哪些假设做出的。

想象一下,一个放射科医生使用一个带有神经网络主干的程序来帮助他在 x 光图像上找到疾病。使用传统方法,它只会输出疾病的名称,而没有任何置信度的测量(有关如何输出真实置信度得分的描述,请参见我的上一篇关于神经网络校准的文章)。这对医生几乎没有帮助,因为他不知道决定是如何做出的,也不知道图像的哪一部分影响了决定。他实际上想要接收的是图像中强烈指示预测疾病的异常列表(例如,指示肿瘤的肺部可见肿块)。

这就是概念学习派上用场的地方。它不是简单地预测给定输入的一组疾病,而是返回许多导致这一决定的概念。在这篇文章中,你了解了什么是概念学习,以及如何在你自己的项目中实现它。

概念学习

在介绍中,我已经使用了概念这个词。但是在这个上下文中它实际上是什么意思呢?为了理解这一点,想象一下你是如何区分不同的动物的。你可以使用他们的皮毛颜色,重量,速度,腿的数量和更多的属性来实现这一点。你有它!这些都是可以用来描述网络预测的概念。在文献中,属性一词经常与概念互换使用。显然,这些概念高度依赖于手头的任务。

可解释的概念可以用两种不同的方式加以利用。训练方法旨在建立一个内在可解释的模型,直接输出发现的概念。另一方面,事后方法不需要特殊的培训过程,而是解释一个已经存在的模型。我会带你穿过他们两个!

培训方法

这类方法集中于创建既可以由人类直接分析,也可以输出一组提取的图像概念的架构。因此,这些方法只能在你想从零开始训练一个新模型的时候使用。如果这听起来有点难以理解,请不要担心。我将带你浏览一篇最*发表的论文。

众所周知,标准卷积神经网络的行为类似于特征提取器。CNN 中早期的过滤器倾向于提取低级特征,如角和边,而后来的过滤器提取高级特征,如对象部分。理论上,这些过滤器能够解释全局的内部推理(即,不针对单个样本)。然而,所学习的过滤器可能不被人类理解,并且不能解释单个例子的内部推理。由神经网络的完全连接的层编码的潜在空间进一步根本不可解释。

概念瓶颈模型

图 1:概念瓶颈模型的架构[1]

这就是概念瓶颈模型【1】派上用场的地方。他们使用标准的 CNN 模型(如 ResNet 或 VGG ),但对其中一个全连接层进行了整形,以匹配需要为给定数据集定义的多个预定义概念。这一层被称为模型的瓶颈。每个输入图像都需要用它的类标签和一组描述它的概念来标注。对于本文中使用的鸟类分类数据集,概念是二元的,并描述类似于 wing_color:blackhead_color:yellow 的属性。为了训练模型,在类别标签上使用标准反向传播。此外,概念损失用于确保对应于概念的节点仅在概念实际存在于输入图像中时才被激活。如果概念节点的 Sigmoid 置信度超过 50%,则认为该概念节点被激活。

更精确地定义,该模型被分成两部分:概念提取器 c = g(x) ,它将输入 x 映射到由瓶颈层编码的一组预定义概念 c 。后面是小分类网络 y = f(g(x)) 预测类标签。

ProtoPNet

图 ProtoPNet 架构[5]

杜克大学研究人员提出的 ProtoPNet 是另一个有趣的架构。它通过剖析输入图像并将其与预测类的原型部分进行比较来推理其预测。

临时方法

如果您想要分析一个已经训练好的模型,或者受限于一个非常具体的架构,那么您可能需要使用事后方法,这种方法对要检查的底层模型几乎不做任何假设。

有关事后方法的深入介绍,请参阅概念学习系列的第二部分!

干杯!

相关文献

培训方法

[1]高秉文、阮廷文、唐永生、马士曼、皮尔逊、金炳良、梁(2020)。概念瓶颈模型。

[2]李,c .,齐亚,M. Z .,Tran,Q.-H .,于,x .,哈格,G. D .,& Chandraker,M. (2018)。具有中间概念的深度监管。

[3]威克拉马纳亚克,s .,徐,w .,,李,M. L. (2021)。通过引导概念学习的可理解卷积神经网络。

[5]陈,陈,李,陶,丁,巴内特,鲁丁,苏,郑继光(2019)。这看起来像这样:可解释图像识别的深度学习。

[6]m . Nauta,r . van Bree 和 c . Seifert(2021 年)。用于可解释的细粒度图像识别的神经原型树。

事后方法

[7] Kim,b .,Wattenberg,m .,Gilmer,j .,Cai,c .,Wexler,j .,Viegas,f .,和 Sayres,R. (2018 年)。特征归因之外的可解释性:概念激活向量的定量测试(TCAV)。

[8]周,b .,孙,y .,鲍尔,d .,&托拉尔巴,A. (2018)。可视化解释的可解释基分解。

[9] Bau,d .,周,b .,科斯拉,a .,Oliva,a .,& Torralba,A. (2017)。网络剖析:量化深层视觉表征的可解释性。

[10] Fong,r .,& Vedaldi,A. (2018 年)。Net2Vec:量化和解释概念如何被深度神经网络中的过滤器编码。

[11] Ghorbani,a .,Wexler,j .,Zou,j .,和 Kim,B. (2019 年)。走向基于概念的自动解释。

[12]方,张,林,杨,吴,姚等(2020).基于概念的精细图像解释及其在感染性角膜炎分类中的应用。

确保数据质量的概念和实践

原文:https://towardsdatascience.com/concepts-and-practices-to-ensure-data-quality-f3f0a95acbbf

有许多潜在的数据质量问题,也有许多改进的方法。这篇文章描述了保持数据信任的两条准则、三个概念和四个最佳实践。

解决数据质量似乎就像推一块巨石上山。但是我们可以建造高度计、氧气罐和耐力来帮助我们前进。图片由作者提供。

TL;博士:

  1. 存储和使用数据是不够的。数据驱动型企业需要相信他们的数据是健康可靠的。
  2. 将数据质量问题分组到维度中,通过指标衡量最高优先级的维度,并围绕最重要的指标建立 SLA,使您专注于影响最大的数据质量问题。
  3. 指标只是数字,除非它们是可操作的。涉众需要知道度量标准与他们有什么关系。
  4. 良好的数据实践可以降低数据质量问题的发生频率,并防止已经发生的问题演变成更大的问题。
  5. 主动保护和提高数据质量可以保护您团队的时间,扩大您的影响力,并增加信任度。

糟糕的数据质量会分散团队的时间,增加数据基础设施的复杂性,并削弱对数据的信任。但这并不止于此。在组织层面上,数据质量问题导致企业损失数百万收入,降低运营效率,并导致糟糕的业务决策。

不幸的是,修复数据质量不是一蹴而就的事情。这也不仅仅是承认数据质量问题的存在。打个比方,数据质量并不完全不同于个人的生物健康。

虽然着手“变得健康”(拥有高质量的数据)是一个令人钦佩的目标,但如果不清楚你希望改变哪些品质(维度),就很难设定和达到任何有意义的基准(指标)。

一旦你达到了对你来说更健康的样子,你需要继续监测这些品质,无论是你人体的血压还是你最重要的餐桌的新鲜度延迟次数,然后将你的数字与正在进行的目标进行比较,以保持这条道路。没有度量标准,就很难让自己负责任。

因此,保持数据健康的第一步是确定最重要的方面,比如最大限度地提高数据的可用性。第二步是跟踪这些维度的指标,例如数据利益相关者标记的问题数量。第三步是根据这些指标建立 SLA,比如 24 小时响应时间。

数据质量问题类别(维度)与如何衡量这些类别(指标)的示例。图片由作者提供。

关于数据质量推理的三个概念

在我们开始之前,我们应该澄清数据质量维度、数据质量指标和服务水*协议之间的区别,特别是因为这些术语在数据生态系统的其他地方也有使用。

  • 数据质量维度是数据质量问题的主题类别。问题根据其重要性进行分组,如及时性、完整性或准确性。
  • 数据质量度量描述了具体的、量化的维度度量。例如,及时性维度可以通过捕获表刷新延迟的小时数的度量来实现。
  • 服务水*协议 是与业务目标相关的战略指标,数据团队对此负责。因此,如果度量是表刷新延迟的小时数,那么 SLA 可以测量过去一个季度中超过 12 小时的延迟数。

根据数据质量维度是独立于用例还是依赖于数据的使用方式,您可以进一步将其分为两类:

  • 固有尺寸,与用例无关。例子:准确性、完整性、一致性、安全性和及时性。
  • 外在维度,依赖于每个涉众及其用例的知识。示例:相关性、可靠性、有用性、有效性和可用性。

如果你想深入研究数据质量维度和指标,请查看这篇之前的博文。有了这些概念,我们可以进入两个指导方针。

数据质量维度和度量可以独立于用例(内在的)或者依赖于用例(外在的)。两者的作用取决于手头的目标。图片由作者提供。

有意义的数据度量的两个准则

雇用数据从业者并保护他们的时间专注于增值工作已经够难了。从一个问题跳到另一个问题,在特定的基础上实施不同的度量标准,占用了本已宝贵的时间。

数据团队和领导者应注意确保他们专注于与业务利益相关者关心的业务成果相关联的清晰指标,并为数据制作者阐明清晰的行动路线。

衡量什么是重要的

在您实现数据度量之前,您应该停下来确定您在度量什么以及为什么度量。最有可能的是,这将涉及到与使用你的团队准备的数据的商业利益相关者交谈。或者,您可以使用元数据,如血统和查询日志来量化哪些数据使用最频繁。

虽然您可以努力为公司中的每一个数据用例建立指标,但在不久的将来,您可能会想回家、吃饭,并与朋友和家人一起出去玩。

一个更可行的开始是关注当今贵公司最重要和最有影响力的数据用例,而不是试图煮沸海洋。

确定数据如何推动业务目标,服务于这些目标的数据资产,以及影响这些资产的质量问题。这意味着为您的用例确定最常见的数据质量问题类型(维度)(例如,相关性、及时性等)。).这些常见的棘手问题指出了您应该优先考虑并围绕其构建数据指标的维度。

这一过程使您能够更容易地识别和处理与业务成果最一致的指标。您可以首先解决最重要的问题,并且通过这些指标量化数据团队正在进行的工作以取得高水*的成果会更容易。

度量标准可以简单也可以复杂,但最重要的是度量标准衡量对您的业务至关重要的数据质量的各个方面。图片由作者提供。

一旦您确定了要衡量的数据质量维度,您就可以将这些维度与特定的指标联系起来,从而帮助您解决数据难题。以下是一些例子:

  1. 假设你在一家销售可堆肥水瓶的电子商务公司工作。但是您的数据仓库正遭受着不可靠数据(外在维度)的问题,因为瓶盖供应商的输入数据不一致。没有记录最新产品系列的库存和销售的表格,而您的旗舰产品系列的表格中有季节性定价应该出现的空白字段。为了度量这个维度,您可以建立度量来跟踪针对完整映射的验证程度、空数据值的数量、满足的约束的数量或者针对输入机制的验证程度。
  2. 或者,你可能在一家 B2B SaaS 公司工作,该公司将水族馆出租给办公室。重要的数据用例可能包括面向顶级公司的销售预测,面向高管和办公室经理的营销活动的受众定位。确保 lead 表中 ID 主键的一致性(内在维度)是一个很好的监控指标。
  3. 最后,如果你在一家出售成本价特效药的网上药店。您可能担心隐私和安全性(内在维度),因为您处理敏感的 PII/PHI,在这种情况下,包含潜在敏感信息的行数可能是一个相关的度量。

注意:您的指标会随着时间而变化。随着潜在质量问题的解决,一些高优先级的度量标准可能会变得优先级较低。随着企业成功定义的改变,您需要监控的数据也会随之改变。

使指标具有可操作性

请记住数据团队既不是公司数据的创造者,也不是消费者。我们是乘务员。虽然我们可能认为我们知道要优先考虑的正确维度和要跟踪的正确指标,但我们需要来自我们团队成员的输入,以确保我们不会在不及时的外在维度或与用例无关的内在维度上浪费时间。

例如,假设我们已经实现了跟踪销售数据一致性的指标,而销售团队的许多问题都与数据一致性无关。作为响应,我们可以开发一个包含唯一值和引用完整性的仪表板。但是,如果仪表板数据与数据团队面临的完整性问题没有联系,团队就不会理解这些数字,也不会理解为什么它们对每个团队的计划很重要。

我们提供的数据质量指标应该易于人们消化、理解并应用到他们的工作中。毕竟,如果度量是不可操作的,那么跟踪它们又有什么意义呢?

度量标准的存在是为了衡量和改进现实世界的概念。在最好的情况下,度量标准衡量什么是重要的,并且是可操作的。‍图片由作者提供。

为了使指标易于理解,您可以在一个目标和关键结果(OKRs) 报告中提供它们,作为数据健康的快照。也许您可以将它们放在仪表板中,这样团队就可以跟踪度量的进展。也许你用它们来演示一个团队层面的变化是如何影响下游用户的。

或者,您可以建立 SLA应该是与数据的创建者和消费者协同进行的一项工作。每个维度和指标都有不同的相关 SLA,但重要的是有一个直接负责的团队对每个维度和指标负责。

量化和交流数据质量度量的方法有很多,但重要的是不要让涉众怀疑信息的含义以及他们应该如何处理它。

改变数据质量的四种做法

一旦您开始建立数据质量度量来跟踪数据质量,您将开始看到指示需要改进的区域的模式。请记住,度量标准只是建立度量标准来跟踪数据质量。目标是预防和解决数据质量问题,以便利益相关者可以确信他们正在根据可靠的高质量信息制定战略和运营措施。

正如如何衡量数据质量取决于您遇到的具体问题一样,提高数据质量的实践也因具体情况而异,具体取决于确切的指标和数据堆栈。

但是,有一些通用的最佳实践可以帮助您从一开始就防止数据质量问题的发生,并帮助您解决那些不可避免地会突然出现的问题,以免它们演变成大问题。

预防可以预防的问题

随着数据团队的成熟和数据在整个企业中的使用,数据资产的数量自然会增长。因此,数据质量问题越来越容易出现,低质量的数据也越来越容易被发现。集思广益,你可以制定业务流程,以加强您的数据防御。

定期数据质量评估和围绕质量的 okr 可以帮助您在数据问题还处于早期阶段时就将其标记出来,并在它们造成下游损害之前消除它们。

寻求其他团队的帮助,以减少由数据输入错误引起的准确性和有效性错误。除了鼓励数据输入培训之外,尽可能提供选项集,以防止混淆州缩写(密歇根州是缩写为“Mich .”还是“MI?”?)以后不会引起头痛。

如果你从第三方来源获取数据,确保你的公司执行跟踪计划,以提高数据的质量。您可以创建专门为捕获入站数据问题而设计的指标,例如满足多少(和多长时间一次)约束、针对完整映射的验证程度等等。

投资于鼓励数据质量的数据基础设施工具

现代数据堆栈使监控数据质量和改进指标变得前所未有的简单。从产品分析工具,如 Segment Protocols、Avo 和 Iteratively,到 ELT 解决方案,如 Fivetran 和 Airbyte,再到反向 ETL 解决方案,如 Census 和 Hightouch,有一套资源可以帮助您确保您的数据是可靠的、最新的和正确联合的。

尽管有各种各样的数据基础设施工具,但是一定要投资于那些提高数据质量的工具。图片由作者提供。

经常深入检查指标

在意健康的人,一次不去医生那检查,一去不回。他们定期进行测试和筛查,让他们知道现在需要做哪些健康改善,以及以后需要关注哪些方面。

我们知道我们是在向唱诗班说教,但数据健康需要同样的警惕。当您定期检查传入和传出的数据时,您可以发现任何需要采取的纠正措施或任何需要注意的危险信号,以免引发危机。此外,您还可以深入了解企业如何推动改进或变得更具竞争力。

根据利益相关者的影响调整数据质量

对于数据团队之外的人来说,“数据质量度量”听起来像一门外语。如果数据质量将成为企业文化的一个重要组成部分,你需要让它具有相关性,并证明数据是可信的。

衡量数据质量改进的影响,并定期用其他团队能够理解的语言进行交流。例如,假设客户数据质量提高 10%,客户成功团队可以更快地解决投诉,从而使客户保持率提高 5%。

广泛分享这 5%的改进,并将其与数据质量的改进联系起来。即使不了解数据质量指标的人也能理解留住客户的价值。

报告数据团队之外的同事关心的指标,并展示他们如何与数据质量联系起来,有助于更好地了解数据的来源,并建立对数据正确性的信任。

现代数据质量工具收集关于数据的元数据,以检测、减轻和防止数据质量问题。图片由作者提供。

摘要

在数据驱动的世界中,可信的数据对企业成功至关重要。作为公司数据的管理者,数据团队在帮助业务团队实现公司目标方面发挥着至关重要的作用。

但是没有粘土我们就做不了砖。数据质量是降低基于数据的决策风险的一个重要因素。度量是防止将决策建立在低质量数据基础上的安全措施。更重要的是,它们为业务团队提供了一个了解数据团队工作的窗口,以及对数据所隐含的洞察力的信心。

这篇作品最初发表在 元位面博客 上。

感谢阅读 TDS 社区!想了解 Capsule Pharmacy、improved Foods 和 Drift 的高杠杆数据团队如何确保对其数据的信任吗?联系 元位面团队 或者在 LinkedIn 上联系 凯文

为数据分析师工作面试做准备的概念和问题

原文:https://towardsdatascience.com/concepts-and-questions-to-prep-for-your-data-analyst-job-interview-a075d571dae8

对数据分析师的需求正在上升——市场分析显示,高达 85%的公司已经采用了数据分析技术

作者在 Canva 上创建的图片

先说一个简单的问题:什么是数据分析师?数据分析师收集并使用数据来回答问题,并提供问题的解决方案。数据分析师的日常任务包括:

  • 数据的收集和存储
  • 维护整洁有序的数据结构
  • 为业务问题收集数据和/或创建报告的查询准备
  • 利用收集和组织的数据为日常问题提供真正的解决方案

数据分析师应该熟悉的一些常用工具包括:

  • 结构化查询语言
  • 计算机编程语言
  • r、SAS 和或 SPSS
  • 擅长

但是作为一名数据分析师,你能期望在什么样的公司工作呢?2022 年 1 月,经济时报引用了(数据分析是 2022 年最需要的技能)。在您的研究中,您可能会遇到 FAANG 这个术语。FAANG 是最著名的五大数据分析公司的首字母缩写:脸书、亚马逊、苹果、网飞和谷歌。然而,选择不仅限于这些业务。随着对数据分析技能的需求迅速增加,市场上充满了各种选择,如电话公司、互联网提供商、杂货店、学校等。这里有一篇很棒的文章( 11 家最适合作为数据科学家工作的公司),关于数据分析师应该关注的其他知名公司。

无论你去哪里,如上所述,SQL 技能是一个数据分析师的必备技能。我们已经确定了每个数据分析师都应该知道的 5 个基本技能:连接、子查询和 cte、等级、聚合函数和 case 表达式。下面是对每个功能的简要介绍,一个利用该概念的示例面试问题,以及一个数据分析师如何处理所提出问题的简短概述。

作者在 Canva 上创建的图像

1.连接

什么是联接?

通常,您需要从多个表中收集数据来执行一项任务。为此,必须使用联接。联接将两个表结合在一起,根据查询中指定的约束生成一个新的合并表。连接的一般语法*是:

SELECT values
FROM table a
    JOIN table b
    ON a.commonvalue = b.commonvalue

指定的联接方法(INNER、LEFT OUTER、RIGHT OUTER、FULL)将不同地利用列和查询。例如,内部联接将只显示右侧表中的数据满足左侧联接条件的行。但是,左外联接首先执行内联接,然后对于参数左侧没有找到匹配项的所有行,将为该行添加一个针对右侧列的 null 值。

在查询中使用联接

组织良好的连接可以让您访问优化查询所需的所有数据。这里有一个关于 StrataScratch 的问题,它使用了 JOIN: Product Transaction Count

截图来自 StrataScratch

问题链接:https://platform . stratascratch . com/coding/10163-product-transaction-count

Select *
FROM excel_sql_transaction_data t
    JOIN excel_sql_inventory_data i
    ON t.product_id = i.product_id

假设

因为这个问题的数据集存放在两个独立的表中,所以我们使用 JOIN 来收集查询所需的所有数据。这个问题注意到一些产品可能没有交易并忽略它们。因此,应该使用内部联接,因为它只会生成表 a 在表 b 中找到匹配约束的行。您还将看到 COUNT()的使用对这个解决方案的重要性,这将在下面进一步讨论。

方法

该解决方案的其余方法需要确定所需的输出(product_name 和事务数量)。SELECT 语句将选择 product_name 和 COUNT()的事务数。这就是此解决方案需要 JOIN 的原因。COUNT()函数必须从 excel_sql_transaction_data 表中提取,但是该项目要求我们也从 excel_sql_inventory_data 表中提取产品名称。内部连接在公共元素 product_id 上完成。最后,结果将按产品分组。

用这个问题练习 JOIN

使用下面的代码查看 JOIN 如何处理这个问题中的数据(这不是发布的问题的解决方案)。

SELECT *
FROM excel_sql_transaction_data t
JOIN excel_sql_inventory_data i ON t.product_id = i.product_id

查看我们的帖子“ SQL JOIN 面试问题 ”来练习更多这样的问题。

接下来,我们将讨论的下一个主题是子查询和 cte。我们将包括一个练习题,它结合了连接的使用和下一个技能。

2.子查询和 cte

什么是子查询?什么是 CTE?

子查询是嵌套在另一个查询中的查询。例如,如果您的任务是数羊,但您不知道羊是什么,那么问题“羊是什么”就变成了“有多少只羊?”。子查询用在当前查询的 WHERE 子句中,并嵌套在括号()内,有时称为带括号的子查询。带括号的子查询用在子查询表达式中,用于查看数据是否存在于查询中,是否可以在表中找到特定的数据,等等。

当使用 WITH 子句调用时,子查询成为 CTE。首字母缩写词 CTE 代表公共表表达式。CTE 的作用类似于临时表,但仅设计用于查询中-一旦查询完成,CTE 将自动销毁。cte 通常用于提高查询的可读性,尤其是在涉及递归的时候。以下是 CTE 如何出现以及如何在查询中使用的一般示例:

WITH cte_name_here AS (
   SELECT values
   FROM table
   WHERE...
)SELECT value
FROM cte_name_here
WHERE...

在查询中使用子查询& CTE

在查询中使用 CTE 可以解决 StrataScratch *台上的以下问题:

截图来自 StrataScratch

问题链接:https://platform . stratascratch . com/coding/10173-days-at-number-one

假设

为这个数据分析师访谈问题提供了两个表,因此第一个假设是我们将执行一个连接来收集解决方案所需的所有数据。问题是问一首歌在同一天在美国和世界范围内排名第一的天数,而不是这首歌在美国和世界范围内分别排名第一的总天数。由于输出请求曲目名称和曲目在第一个位置的天数,因此在此查询中需要使用 COUNT()。

方法

在这种方法中,将创建一个 CTE 来保存歌曲在全球市场上排名第一的曲目名称和日期。初始化 CTE 后,将在“轨迹名称”列的两个表之间执行左连接。我们将把结果减少到全球表中排名第一的位置,然后按曲目名称、日期对这些结果进行分组。我们现在有了一个新的数据集,它只包括这首歌在全球排名第一的曲目名称和日期。

接下来可以准备一个新的查询,将 CTE 的结果与包含美国排名的表连接起来。由于 trackname 是在 CTE 中返回的,因此这将是执行连接的值。SELECT 语句将从 US 表中请求曲目名称,并从 US 表中请求日期计数()。将在 WHERE 子句中对结果进行筛选,以仅返回美国表中的日期与从 CTE 返回的日期相匹配的结果(该表包含全球表中的日期)。由于使用了 COUNT(),结果将按曲目名称分组,根据说明,ORDER BY 也将按曲目名称按 A-Z 或升序排序。

带着这个问题练习 CTE

使用下面的代码来练习创建一个 CTE(这不是张贴的问题的解决方案)。运行此代码以查看在创建 CTE 后查询时所有数据的显示方式。

WITH temp_CTE AS
  (SELECT us.trackname,
          ww.date
   FROM spotify_daily_rankings_2017_us us
   LEFT JOIN spotify_worldwide_daily_song_ranking ww ON ww.trackname = us.trackname
   WHERE ww.position = 1
   GROUP BY us.trackname,
            ww.date)
SELECT *
FROM temp_CTE

让我们换个话题,转到下一个概念,RANK()和它的类似函数 DENSE_RANK(),来讨论 PostgreSQL 中如何对值进行排序。

3.军阶

作者在 Canva 上创建的图像

什么是等级?

SQL RANK 函数是一个为结果集的每一行分配排名的函数。RANK()函数是 SQL 窗口函数家族的一员。窗口函数使用一组表格行中的数据来执行计算。在这种情况下,计算将根据查询中指定的参数从低到高对这些值进行编号。如果需要,可以指定一个分区,该分区将允许对结果集中的多个类别(分区)进行排序。在分区排名中,每个类别从排名 1 开始,因此一组数据可能会产生多组排名。

与 RANK()类似的是 DENSE_RANK()窗口函数。DENSE_RANK()还为结果集的每一行分配一个排名,但是当结果集中有重复值时,RANK()将显示并列排名,但是它将跳过下一个排名编号,直到它达到唯一值(即 1、2、2、4、4、4、7 等)。),而 DENSE_RANK()将在达到并列值(即 1、1、2、2、3、4、5 等)后继续按顺序排序。),如下图。

下面是如何调用 RANK()和 DENSE_RANK()的示例:

RANK() OVER(
[PARTITION BY name_of_column_for_partition]
ORDER BY name_of_column_to_rank
)

Dense_Rank 是:

DENSE_RANK() OVER(
[PARTITION BY name_of_column_for_partition]
ORDER BY name_of_column_to_rank
)

请注意,分区表达式在方括号[]中,因为它在使用 RANK 和 DENSE_RANK 时是可选的。当值相等时,RANK 和 DENSE_RANK 的结果相互比较如下:

排名:

密集 _ 排名:

类似于 RANK()和 DENSE_RANK()的最后一个窗口函数是 ROW_NUMBER()。函数的作用是:返回当前行的编号。这与 RANK()和 DENSE_RANK()的初始化相同。以下示例显示了使用 ROW_NUMBER()时结果如何变化:

行号:

为什么要用 Rank?

当结果应该排序和编号时,最好使用 Rank。例如,如果您希望根据一组参数来查找公司中表现最好的员工,可以在查询中使用 RANK()或 DENSE_RANK()来轻松识别结果。这两个函数之间的选择通常取决于呼叫者是否希望在结果中包含“ties”。因为表中的数据还可以划分为更小的组来进行排序(每个组从值 1 开始),所以如果要评估杂货店库存中易腐食品的受欢迎程度,并对水果、蔬菜、熟食等进行单独排序,rank()将会很有帮助。

在查询中使用排名

下面的问题是在查询中使用 DENSE_RANK()的一个很好的例子。

截图来自 StrataScratch

问题链接:https://platform . stratascratch . com/coding/10161-ranking-hosts-by-beds

假设

因为这个问题清楚地表明输出在寻找一个排名,我们知道将使用 RANK()或 DENSE_RANK()。由于指令没有说明允许相同级别的*局或排名,这里的选择是 DENSE_RANK()。因为一个主机可以有多个属性,所以我们需要合计床位数。最后,由于一个主人可以拥有多处房产,但是所提出的面试问题并没有说明按照房产来划分床位数量,这是你需要向面试官澄清的事情。

方法

第一步是准备一条 select 语句来查找每台主机的床位数。使用 SUM()计算床位总数。为了可读性和易用性,我们在查询期间将这些结果保存在一个 CTE 中。找到床位数后,将从 CTE 中选择所需的列,并使用 DENSE_RANK()按床位数最高的行进行排序。务必注意不要过早使用 rank 函数,否则结果会不准确。

带着这个问题练习排位

使用下面的代码来看看一个表格中的数据是如何排列的(这不是对发布的问题的解决方案)。运行这段代码来查看结果集。将 RANK()更改为 DENSE_RANK(),然后更改 ROW_NUMBER(),看看结果如何变化。

SELECT RANK() OVER(
                   ORDER BY n_beds DESC) AS rank,
       apartment_id,
       apartment_type,
       n_beds
FROM airbnb_apartments

接下来,我们将介绍聚合函数,包括上面提到的 SUM()和其他聚合函数。

4.聚合函数— COUNT()、SUM()、MAX()、MIN()

SQL 聚合函数是一种可怕的方式,它总结了许多内置的 SQL 窗口函数,这些函数从一组多个输入值中返回一个结果。聚合函数中有许多可用的功能,例如查找值的总和、查找一组值的范围、计算一列中的行数等。由于这些函数的健壮性,这里不提供如何初始化一个或多个聚合函数的例子,请参考 PostgreSQL 文档以获得深入的解释。

SQL 中为什么使用聚合函数?

坦率地说,如果没有聚合函数,查询会很无聊。它们为解决日常任务提供了强大的功能。常见的聚合函数有 SUM(),它对指定列中的行进行求和;COUNT(),它计算符合规范的列中存在的行数;MAX(),它从一列的行中产生最大值;MIN()从一列的行中产生最小值。由于聚合函数提供了广泛的功能,可以说它们是数据分析师可以开发的最强大的技能之一。

在查询中使用聚合函数

为了解决一个在解决方案中使用聚合函数的问题,让我们看看下面这个来自 StrataScratch 的问题。

截图来自 StrataScratch

问题链接:https://platform . stratascratch . com/coding/9908-客户订单和详细信息

假设

此问题要求从数据集中输出每个城市的订单,该数据集中包含城市名称、订单数量、客户数量以及该城市的订单总成本等列。这意味着我们需要使用 COUNT()获得订单和客户的总数,使用 SUM()获得订单的总成本。这些结果将按城市列分组,但结果将需要仅限于(限制)有 5 个或更多订单的城市。最后,因为本例中有多个表,所以将使用左连接,因为我们希望在计算中包括每个城市的所有客户,甚至包括没有下订单的客户。

方法

查看提供的两个表,两个表中的公共值是 custid 列,它将用于连接。通过首先准备 JOIN 语句,我们能够收集从两个表中提取所需的所有数据点。左连接将用于包括所有客户,甚至包括那些没有下订单的客户。准备好 join 子句后,接下来是 SELECT 语句。SELECT 应该返回城市、订单总数、客户总数和总成本。对于订单总数和客户总数,分别使用 COUNT()。因为同一个客户可能下了多个订单,所以使用 DISTINCT 关键字来避免重复。要计算每个城市所有订单的总成本,请使用 SUM()。GROUP BY 子句通常与聚合函数一起使用,在许多情况下,如果省略该子句,将会出现语法错误。结果应该按城市分组。最后,我们希望将结果限制在拥有 5 个或更多订单的城市。将 HAVING 子句与 GROUP BY 结合使用,将订单数限制为 5 个或更多(> 5)。

带着这个问题练习集合函数

使用下面的代码练习使用聚合函数(这不是张贴问题的解决方案)。运行此代码,查看如何使用 COUNT 和 SUM 来收集客户的订单总数,并使用 orders 表中的数据对总成本求和:

SELECT cust_id,
       COUNT(cust_id) AS num_orders,
       SUM(total_order_cost) AS total_cost
FROM orders
GROUP BY cust_id
ORDER BY cust_id DESC

接下来,我们将讨论 sql 中 case 表达式的使用,包括一个例子,您可以在介绍下一个概念的同时继续练习聚合函数。

5.格表达式

什么是格表达式?

由查询中的 case 表示的 CASE 表达式是一个条件表达式,类似于其他语言中的 If/Else 语句。如果满足某个条件,则在查询中指定该条件以及结果。在许多情况下,术语 case 语句与 case 表达式可以互换使用。有关 CASE 如何出现在查询中的一般示例,请参见下面的内容:

SELECT CASE WHEN condition THEN result
    ELSE other_result
    END

为什么要用 Case 表达式?

当值或动作依赖于特定行或列的状态时,CASE 表达式非常有用。通过 CASE 表达式优化和缩短查询,通常可以节省几十行代码。case 不仅限于一个条件——在一个 CASE 表达式中可以计算多达 255 个单独的条件/参数!如果不使用 case 表达式,查询将是乏味而耗时的。

在查询中使用大小写

以下问题是学习和练习如何在查询中使用 case 表达式的好方法。这个数据分析师面试问题还使用了聚合函数,允许您进一步提高该技能。

截图来自 StrataScratch

问题链接:https://platform . stratascratch . com/coding/9729-inspections-per-risk-category

假设

该问题的解决方案应包括两栏:风险类别和每个类别的检查次数。虽然输出很简单,但在表面之下还有更多。并非所有的健康检查都会导致违规或风险。这意味着对于一行或多行运行状况检查,risk_category 字段可能为空。我们需要识别这些行,并将它们分配给无风险,这就是查询中将使用 CASE 的地方。

方法

在 select 语句中,我们将使用 CASE 表达式**首先查找 risk_category 列中值为 NULL 的所有行。这将被分配给无风险。否则,它将保持当前值。接下来,使用 COUNT()查找 inspection _ ids 的总数。在 risk_category 列上将 GROUP BY 与 COUNT 结合使用。结果应该按照检查次数从高到低排序,因此我们将使用“按[值]排序”DESC 来完成查询。

用这个问题练习案例

使用下面的代码查看使用此问题中的数据的 case 表达式的示例(这不是已发布问题的解决方案)。运行此代码,查看案例表达式如何根据记录的分数将运行状况检查指定为“通过”或“失败”:

SELECT business_name,
       inspection_date,
       CASE
           WHEN inspection_score > 50 THEN 'passed'
           ELSE 'failed'
       END
FROM sf_restaurant_health_violations
ORDER BY inspection_date DESC
  • *关于使用 CASE 表达式的注意事项:对于这个特殊的问题,COALESCE()是比 CASE 更有效的解决方案。COALESCE()是 CASE 的语法快捷方式。Coalesce 返回其第一个不为 null 的参数。它可以用来用默认值代替空值。在这种情况下,如果 risk_category 列中的值不为空,COALESCE (risk_category,' No Risk ')将返回该值。否则,该行的值将返回“无风险”。

结论

在上面几节中,我们已经学习了如何使用连接、子查询和 cte、秩、聚合函数和 case 表达式。我们已经对数据进行了计数,对列表中的项目进行了排序,连接了表,并遍历了案例条件。这些都是数据分析师的日常技能,我们鼓励尽可能提高这些技能。在面试或准备数据科学领域的新职位时,精通这些科目是一个优势。虽然本文涵盖的主题对于所有人来说都是很好的学习基础,但在成为或成长为数据分析师的过程中,还有很多东西需要学习。查看我们的帖子“ 数据分析师面试问题 ”和“ 数据分析师 SQL 面试问题 ”,了解数据分析多样化领域的更多实践。

数据科学面试中你必须知道的概念——第一部分:分布

原文:https://towardsdatascience.com/concepts-you-have-to-know-for-data-science-interviews-part-i-distribution-f4c28da3fc50

Unsplash 上的 Edge2Edge 媒体拍摄

办公时间

数据科学家访谈中最常见的问题

这是一年的开始,许多人都在寻找新的机遇和新的挑战。我记得在我过去的多轮招聘中,我经常努力找到一个好的综合资源来准备我的数据科学面试,所以我决定自己整理一个。

如果您正在开始新一轮招聘,或者希望在新的一年提升您的数据科学知识技能,希望您会发现这份备忘单/速成课程作为起点很有帮助。这是数据科学访谈系列的第一篇文章,我想提到一些基本的分布和与分布相关的基本概念,它们在数据科学访谈中经常被问到。

我将在本系列中涉及的概念绝不是详尽的,它是数据科学访谈中最常被问到的问题的汇总列表,或者是优秀的数据科学家根据我的经验应该熟悉的概念。

与分布相关的基本统计概念

对于你们中的一些人来说,这似乎太基础了,但重要的是要确保你真正理解简单统计概念的定义、差异和用例,如均值、中值和众数。我在采访中反复看到的几个关键概念是:

  1. *均值不同于中值,因为*均值更容易受到异常值和分布偏斜度的影响。*均值将与对称分布的中值相同。对于左偏分布,*均值将小于中值,而对于右偏分布,*均值将大于中值。
  2. 众数代表分布的“峰值”,它与对称分布的*均值和中值重叠。对于左偏分布,众数大于中位数和*均数;并且对于右偏分布,模式比两者都小。

图来自 Stack Exchange (注意:Stack Exchange 图像都是 CC 许可的,允许商业使用)

分配

分布是统计学中一个非常重要的概念,在面试中经常会被用到。有很多发行版,但有几个重要且常见的发行版会在访谈中被反复提及和使用:

  1. 正态分布

这是要知道的最重要的分布,因为生活中的许多事情都遵循正态分布——成年人的身高、成年人的智商等等。重要的是要知道,正态分布的均值、中值和众数是相同的,因为它是对称的非偏斜的

正态分布在*均值附*有对称变化,定义为标准差。这意味着这些值同样有可能高于或低于*均值。但是,值与*均值相差较大幅度的可能性要小于较小幅度的可能性(无论方向如何)。事实上,对于正态分布,68.3%的值位于距*均值 1 个标准偏差以内;95.5%位于*均值的 2 个标准偏差内,99.7%位于*均值的 3 个标准偏差内。

正态分布仅由两个参数决定,即*均值和标准差。*均值决定了分布的中心,即峰值(*均值、中值和众数)所在的位置,而标准差决定了分布的形状/分布范围,标准差越小,分布越紧密。

stats.stackexchange.com

2。伯努利分布

伯努利分布描述了一个只有两种结果的实验。为了简单起见,我们通常将这两种结果描述为成功-1 和失败-0。这种分布最常见的例子是像掷硬币一样,正面代表“成功”,反面代表“失败”;或者天气结果,比如是否会下雨,下雨就是“成功”,不下雨就是“失败”(或者反过来,如果你真的讨厌下雨)。

这个分布只有一个参数——成功概率 p 。在公*硬币的情况下, p= 50%。

3。二项式分布

二项式分布与伯努利分布密切相关,因为它模拟了重复伯努利实验中的成功次数。

二项式分布带两个参数——成功概率 p 和重复次数 n.p 大于 0.5 时,分布是左偏的;当它小于 0.5 时,分布是右偏的,当 p = 0.5 时,你猜对了,分布是对称的。

左偏二项分布(栈交换)

对称二项分布

如果你认为上面的对称二项分布很像正态分布,那你就对了。事实上,当实验次数足够大时,二项分布可以*似为正态分布(其中 n 为实验重复次数, p 为成功概率,经验法则是当 np 和 n(1-p)都大于 10 时,二项分布可以*似为正态分布)。

你可能会被问到的其他不太常见的分布是泊松分布(它描述了特定时间范围内的事件数量;最常见的例子是在固定时间范围内到达餐馆的顾客数量),指数分布(它与泊松分布相关,因为它描述了事件之间的时间间隔;在客户示例中,它描述了在固定时间窗口内每个客户到达之间经过的时间)和伽马分布(它类似于指数分布,因为它描述了到达固定数量的事件的总时间;继续这个例子,它描述了在一定数量的顾客到达餐馆之前你需要等待的时间。

如何进行测试

这些概念通常不会以学校测试的形式单独测试,因为面试官希望看到你可以实际使用这些概念来解决现实世界的问题,而不是记住关于它们的维基百科页面。因此,常见的问题大致如下:

  • “XX 的分布情况如何(例如 Facebook Marketplace 页面访问时长等。)有吗?”
  • 后续问题:“这个分布的*均值和中位数是什么关系?”或者“你认为这个分布的*均值会比中值大还是小?”

希望这个总结对你的招聘过程有所帮助。记住,仅仅通过阅读几篇关于统计的文章,你不会成为统计专家;掌握统计知识需要练习。因此,让自己熟悉这一点的最好方法是尽可能利用这些知识;例如,当你研究你感兴趣的公司时,问问自己对这家公司来说最重要的指标是什么,你认为他们的分布是什么样的。

不知道接下来要读什么?以下是一些建议:

数据科学面试中你必须知道的概念——第二部分。可能性

原文:https://towardsdatascience.com/concepts-you-have-to-know-for-data-science-interviews-part-ii-probability-5c8830f13fb5

Unsplash 上拍摄的 ThisisEngineering RAEng

数据科学家访谈中最常见的问题

系列的最后一篇文章(数据科学面试你必须知道的概念——第一部分:分布)中,我提到了分布的基础知识——最重要的分布及其可能在数据科学面试中出现的特征。在这篇文章中,我想用公司喜欢问 DS 候选人的常见概率问题来继续教程。

概率是一门复杂的学科,如果你真的想深入了解它,可能很难在短时间内掌握。其实是大学数学专业横跨一整个学期的必修课。因此,这篇文章肯定不会让你成为概率专家,而是会让你了解这个主题中最常见的测试领域。

条件概率/贝叶斯定理

条件概率是 DS 面试中测试最多的概率问题类型。这是一项有用的技能,因为在我们的日常工作中,我们遇到的许多分析问题都涉及到条件概率——例如,假设疾病测试结果为阳性,那么患病的概率是多少。条件概率通常用贝叶斯定理计算,公式如下:

维基百科

A、B → 事件

P(A|B) →给定 B 为真的概率

P(B|A) → 概率 B 给定 A 为真

P(A),P(B)→A 和 B 的独立概率

独立性在学习条件概率时是一个重要的概念。值得注意的是,如果 P(A|B) = P(A),意思是“给定 B 的概率”与“A 的概率”相同,那么 A 和 B 两个事件是独立的。

独立事件的一个很好的例子是每次抛硬币的结果;为了公*起见:

A:在第二次翻转中翻转一个头→ P(A) = 1/2

B:第一次翻转时翻转尾巴→ P(B) = 1/2

A|B:在第二次翻转中翻转一个尾巴,在第一次翻转中翻转一个头→ P(A|B) = 1/2

知道你在第一次翻转中翻转了一个头,并不会改变下一次翻转尾巴的概率,所以这两个事件是独立的。

在面试中,你应该考虑使用贝叶斯定理的一个强有力的暗示是像“给定”或“条件”这样的关键短语。

总概率

全概率定律表述如下:

维基百科

【Bx】是不相交的事件,它们组合起来代表整个选择宇宙。假设一个小组由来自旧金山或西雅图人组成。我们知道这个团 40%来自 SF ( P( Bx ) ),60%来自西雅图(P(By));西雅图今天下雨的概率是 70% ( P(A|By ) ),SF 今天下雨的概率是 20% ( P(A|Bx) )。我们在组内随机叫一个人,他们所在的城市今天下雨的概率是多少( P(A) )?

利用上面的公式,我们很容易得到 P(A) = 0.40.2+0.60.7 = 0.5

全概率通常用于条件概率的计算,因为对于下面所示的条件概率,P(B)通常不是直接给出的,而是必须使用全概率法则来计算。

维基百科

二项式概率

我们已经在我之前关于分布的文章中讨论过二项分布。二项式概率是使用二项式分布来计算一个只有两种结果的实验的 Y 次试验中恰好有 n 次成功的概率(一个很好的例子是抛硬币)。

维基百科

成功的试验次数

n: 总试验次数

单次试验成功的概率

n! : n 阶乘,其计算结果为 n(n-1)(n-2)… 321*

k! : k 阶乘,计算方法同上

(n-k)!你说到点子上了

认识到问题涉及只有两种结果的事件是决定何时使用二项式公式计算概率的关键。

一个很好的例子是:在 10 次抛硬币中获得 4 个正面的概率(假设这是一个不公*的硬币,对于每次抛硬币,有 1/4 的概率获得正面,3/4 的概率获得反面)

在本例中:

n = 10,k=4,p=1/4

这个的计算结果应该是 10!/(4!6!)(1/4)⁴(3/4)⁶ = 2101/4⁴(3/4)⁶= 0.15*

这些考试是如何进行的,如何准备

这些测试有很多不同的方式。但是总的主题是,它们通常被组合起来测试,而不是孤立地测试。如上所述,当在面试中被问到时,全概率定律可以很容易地融入贝叶斯定理。

需要注意的是,仅仅记住这些公式对于面试来说是不够的。因为在面试中,没有人会告诉你什么时候用哪个公式。确定使用哪一个是正确的可能是最困难的部分。掌握它的最好方法是看大量的样题,试着不去看答案,而是试着自己解决。熟悉需要使用这些公式的问题类型是关键。对于样题,简单的谷歌搜索会给你很多结果。如果你想有一个更集中的概率问题“数据库”,我强烈推荐尼克·辛格和凯文·霍的 Ace《数据科学面试 书。

寻找更多面试指南?这里有一些文章可能会有帮助!

* *

数据科学面试中你必须知道的概念——第三部分。基本监督学习模型

原文:https://towardsdatascience.com/concepts-you-have-to-know-for-data-science-interviews-part-iii-basic-supervised-learning-models-5115673f57

杰森·莱姆在 Unsplash 上的照片

数据科学家建模访谈中最常见的问题

这是我采访系列的第三篇文章。我希望这个系列可以作为有抱负的数据科学家准备面试的集中起点。如果你感兴趣,前两篇文章在这里:

  1. 数据科学面试中你必须知道的概念——第一部分:分布
  2. 数据科学面试中你必须知道的概念——第二部分。概率

在这篇文章中,我想谈一谈可能是许多有抱负的数据科学家最感兴趣的部分——ML。ML 是一个超级复杂的话题,所以我甚至不会试图在一篇文章中涵盖它的所有内容。事实上,我会将 ML 部分分成几个帖子,并在每个帖子中谈论 ML 的不同方面和不同类别的模型。在这篇文章中,我将只关注基本监督学习模型

当谈到 ML 时,有无数类型的模型,从简单的模型如线性和逻辑回归一直到复杂的模型如深度学习和强化学习。我会一篇接一篇地介绍面试中会出现的重要问题。

首先,重要的是要知道,除非你的目标是超级建模密集型角色,如机器学习工程师(MLE)或研究科学家, ML 通常不是面试的最大焦点。面试官通常只想看到你对不同的模型和建模技术有基本的了解;你不会被要求在白板上证明或者为你建立的神经网络的层数辩护。

一般来说,ML 模型/技术可以分为两类——监督学习和非监督学习。

有监督学习和无监督学习之间的区别是数据科学家应该熟悉的最基本的概念之一。监督学习是所有 ML 技术的总分类,利用标记数据集,非监督学习技术使用未标记数据集。一个具体的例子:如果你想建立一个模型来区分狗和猫,你会使用监督学习,因为无论是狗还是猫(你想预测的类别),每个数据点都应该有一个明确的正确答案。然而,如果你只是想把家养宠物聚集在一起,你可以使用无监督学习。每个数据点的标签都没有明确的“正确”答案——一只小狗可能会和其他小猫而不是大狗归为一组。本文将关注最常测试的监督学习技术;我将在下面的文章中深入探讨更多的高级监督学习模型非监督学习

线性回归

这可以说是 ML 中使用的最基本的模型(如果你认为它“算作”ML 的话)。线性回归是监督学习中最常用的方法,最适合预测连续变量(相对于分类变量)。

线性回归本质上是试图拟合所有训练数据点的最佳直线。“最佳线”的定义根据损失函数的选择而变化。最常用的是“普通最小二乘法(OLS)”,它通过最小化误差*方和来寻找最佳直线。误差定义为 rᵢ = yᵢ -y^ ,其中 y^ 为模型预测值, yᵢ 为观测(真实)值。您希望最小化的值是上述误差项的总和

误差*方和项

来自维基百科的线性回归图解

逻辑回归

逻辑回归和线性回归之间的最大区别在于,线性回归模拟连续变量,而逻辑回归模拟事件(具有二元结果的事件)的概率,因此输出是介于 0 和 1 之间的

值得注意的是,即使通常用于分类,逻辑回归本身并不是一个分类器。但是当在顶部设置一个阈值(通常为 0.5)时,它可以变成一个分类器。确定了截止值后,概率可以转换为二进制输出。例如,如果您试图预测一封电子邮件是否是垃圾邮件,阈值为 0.5 的逻辑回归会将任何预测“成为垃圾邮件的概率”大于等于 50%的电子邮件归类为垃圾邮件。

了解分类器由两部分组成—阈值和逻辑回归—可以帮助您理解为什么选择适当的截止值是模型调整的一个重要但通常被忽略的部分,当涉及到由逻辑回归支持的分类器时。

手推车

CART 是分类树和回归树的缩写;顾名思义,这是一种监督学习技术,可用于预测分类或连续变量。CART 通常和随机森林一起讲,因为 CART 是更简单的版本;它是一棵树,而不是一片森林(我将在下一篇文章中介绍随机森林)。

与回归或随机森林相比,CART 的最大优势是其可解释性,因为它可以绘制用于构建树的特征分割。下图展示了一个超级简单的购物车模型。像这样的插图可以很容易地被你用来拟合模型的大多数购物车包绘制出来,它可以帮助你可视化模型是如何在后台构建的。另一个有趣的事情是,它向你展示了什么样的特征首先被用来分割模型;所以这也说明了特性的重要性。

作者插图

这些是如何测试的,需要注意什么

一般来说,有两种方法来测试这些基本的 ML 建模概念——简历驱动或理论驱动。

  • 简历驱动:面试问题会根据你的简历。所以确保你花几个小时去回忆一下,刷新你对简历中提到的模特经历的理解。根据面试官和他/她的机器学习背景,他们可能会就你提到的某些算法提出深入的问题。
  • 理论驱动:如果你缺乏建模经验,或者建模出现在面试的案例研究部分,问题将是理论性和假设性的。面试官会问你在某种情况下你会怎么做。他们可能会通过在数据集上植入一些问题来扔给你一个曲线球,看看你是否知道如何处理建模中的困难数据问题(我们将在我即将发表的关于模型训练的文章中详细介绍)。
  • 要记住的事情:在谈论你的建模经历时,确保你展示出你明白可解释性是建立模型时最重要的事情。对于几乎每一个常用的模型,都有无数种方法来可视化模型性能和特性重要性。请继续关注这方面的文章。另一件要记住的事情是数据清理特征工程同样重要,如果不比建模本身更重要的话。否则,您的模型将遭受臭名昭著的“垃圾进垃圾出”症状。

有兴趣阅读更多关于数据科学的职业建议吗?我可能有东西给你:

</5-lessons-mckinsey-taught-me-that-will-make-you-a-better-data-scientist-66cd9cc16aba> [## 麦肯锡教给我的 5 条经验将使你成为更好的数据科学家

towardsdatascience.com](/5-lessons-mckinsey-taught-me-that-will-make-you-a-better-data-scientist-66cd9cc16aba)

数据科学面试中你必须知道的概念——第四部分。随机森林

原文:https://towardsdatascience.com/concepts-you-have-to-know-for-data-science-interviews-part-iv-random-forest-5c125e4b5777

伊琳娜·伊里斯在 Unsplash 上的照片

数据科学家访谈中最常见的问题

这是采访系列的第四篇文章。我希望这个系列能够成为有抱负的数据科学家在面试准备方面的集中起点。到目前为止,我们已经讨论了以下概念:

  1. 第一部分:发行
  2. 第二部分。概率
  3. 第三部分。基本监督学习模型

在这篇文章中,我想继续在 ML 领域的旅程,并谈论高级监督学习模型。更具体地说,我将把重点放在随机森林上,因为在更复杂/高级的 ML 模型中,它可能是 DS 访谈中最常用和最常被问到的。事实上,我作为一名数据科学家在麦肯锡的采访中被问及随机森林;如果你的面试中有建模部分,知道如何在高层次上直观地解释算法肯定会帮助你从其他面试者中脱颖而出。

什么是随机森林

我们在上一篇文章中谈到了购物车模型。提醒一下,CART 代表分类和回归树;随机森林是一片森林。描述性命名约定揭示了两者之间的明确关系——随机森林由多个决策树组成。

随机森林是一种集成方法(集成方法是一种结合多种学习算法以获得更好结果的 ML 方法,实现 1+1>2 的效果),利用多棵树来避免过拟合(决策树容易过拟合)。想象森林中的每棵树都投下一票,对整个模型的最终决策有发言权;最终的决策/预测是通过森林获得多数票来实现的。

作者图片

为了避免过度拟合,树不应该相关。模型如何避免树被关联?你可能会问。Random Forest 通过做两件事来确保这一点——在构建每棵树时,随机选择一个训练样本子集,以及随机选择一个特征子集。这种“随机子集化”经常用于集合模型,通常被称为【装袋】,并且经常被用于减少训练模型中的方差

既然说到“装袋”,这里就有点跑题了。“助推”是 ML 模型中常用的另一种方法;事实上,梯度推进决策树是决策树家族中一个高性能的表亲。我提这个是因为“装袋”和“助推”经常被拿来比较;我在不同的采访中被问及他们之间的差异。“提高”的特别之处在于它可以提高学习能力差的学生。与“bagging”并行和单独地构建树不同,“boosting”过程顺序地构建树;所以每棵树都可以从前一棵树的错误中“学习”并改进。

有很多关于在介质上“增强”的详细解释,所以我不会在这里进入任何技术细节。但值得注意的是,由于这种“顺序”的性质,“助推”算法训练更慢,与“装袋”算法相比,更容易过度拟合。

回到随机森林。如果你还记得我们在上一篇文章中谈到的,CART 最大的优势可以说是它的可解释性。尽管随机森林在性能方面通常是 CART 的一个改进(特别是在测试集上,因为它不容易过度拟合),但在这个过程中,它在一定程度上牺牲了可解释性。随着树木数量的增长,将越来越难绘制每棵树并查看它们在分割数据时使用的特征;因此,要准确理解每棵树是如何建造的变得更加困难。但是仍然可以生成要素重要性图(跨越森林中的树木)。大多数随机森林包都带有这样一个易于访问的地块。

这些是如何测试的,需要注意什么

我已经在之前的帖子中讲述了如何测试 ML 概念,以及在回答 ML 建模问题时需要记住的最重要的事情。如果你想了解更多,请点击下面的链接。

关于随机森林或者任何复杂的最大似然算法,唯一要补充的是,能够用通俗的语言解释算法是很重要的。我的意思是,面试官通常感兴趣的是测试你对算法的理解,而不是 T2 寻找的维基百科页面的记忆版本。

最后的小提示,练习你对 ML 算法的直观解释的最好的观众是不在分析领域的朋友;你可以很快判断出你对算法的描述是否有意义。

有兴趣阅读更多关于数据科学的职业建议吗?我可能有东西给你:

</5-lessons-mckinsey-taught-me-that-will-make-you-a-better-data-scientist-66cd9cc16aba> [## 麦肯锡教给我的 5 条经验将使你成为更好的数据科学家

towardsdatascience.com](/5-lessons-mckinsey-taught-me-that-will-make-you-a-better-data-scientist-66cd9cc16aba)

并发和并行:区别是什么?

原文:https://towardsdatascience.com/concurrency-and-parallelism-what-is-the-difference-bdf01069b081

理解这些复杂话题的一种全新的简单方法

我自己用diagrams.net制作的图像

在我目前的职位和许多文章中,我经常听到这些说法,然而,当我第一次开始时,我并没有真正理解它们的意思,自然我觉得这是不可接受的。

有了这种感觉后,我立即决定我不能忍受这种情况,并开始深入研究它们,以理解它们为什么对计算机科学如此重要,并发现如何使用简单的例子来学习它们。

在这篇文章中,我将从基本层面回顾这些概念,以及用 Python 实现的一些简单实现,这些实现帮助我更好地理解它们。

如果你想在读完这篇文章后努力理解它们,我建议你用一个简单的 for 循环同步地重新实现上面的例子,自己看看有什么不同。

什么是并发和并行?

当您开发具有大量任务的复杂系统时,您最终会发现同步执行所有这些操作对于您的需求来说不够高效。

并发性和并行性是实现来允许我们通过在多个任务之间交织或者通过并行执行它们来处理这种情况的机制。

从表面上看,这些机制似乎是相同的,然而,它们都有完全不同的目的。

并发

并发的目标是当一个任务被迫等待外部资源时,通过在它们之间切换来防止任务相互阻塞。一个常见的例子是处理多个网络请求。

一种方法是启动一个请求,等待响应,然后启动下面的请求,重复这个过程,直到处理完每个请求。这种方法的问题是速度很慢,效率很低。

更好的方法是同时启动每个请求,然后在收到响应时在它们之间切换。通过这样做,我们消除了等待响应所花费的时间。

*行

如果你有十个工人,你不会希望其中一个做所有的工作,而其他九个却无所事事。

相反,你可以把工作分给所有的工人,这样不仅工作会做得更快,而且工人会做得更少。

并行性采用相同的概念,并将其应用于手边的硬件资源。这是通过启动利用计算机拥有的所有 CPU 核心的进程或线程来最大限度地利用所述资源。

这两个概念对于同时处理多个任务都非常有用,尽管您需要为自己的特定需求选择正确的方法。

对于非常依赖外部资源的任务,并发性是惊人的,而对于许多 CPU 密集型任务,并行性是惊人的。

我们如何在 Python 中使用这些概念?

Python 为我们提供了实现并发和并行的机制,对于并发,我们有线程异步,而对于并行,我们可以利用多处理

这些经常被视为可怕的话题,在某些方面确实如此,但是我发现,在深入理论之前,从每个实现中选取一个相对简单的例子,并以多种方式进行处理是最好的方法。

我强烈建议你在读完这篇文章后,带着我在下面留下的概念和例子去玩,直到你觉得足够舒服,可以自己尝试用不同的方式实现它们。

穿线

已经说过在实践之前不要太担心理论,我们确实需要对什么是线程有一个基本的概念来开始线程化。

线程类似于顺序程序,因为它有一个开始、一个执行序列和一个结束。在线程运行期间的任何时候,都有一个单独的执行点。但是,线程不是程序,它不能独立运行。

本质上,一个线程是一个独立的执行流,在这里你可以独立于程序的其他部分来执行一个或多个函数。然后,您可以处理结果,通常是等待所有线程运行完成。

Python 中有两种处理线程的主要方式,要么使用线程库,要么使用作为上下文管理器创建的 ThreadPoolExecutor ,这是管理池的创建&销毁的最简单方式。

如果你看一下上面的例子,我们只是创建了一个在单独的线程中启动的函数,它只是启动线程,然后休眠,模拟一些外部等待时间。

在 main 函数中,您可以看到我是如何实现上述两个方法的,第一个在第 9-19 行,第二个在第 23 & 24 行。

虽然这两种方法都相当简单,但很明显哪种实现需要我们付出更少的努力。

这是一个相当简单的例子,但是,它有助于理解理论。下面的脚本可能是一个更现实的简单例子。

在这个代码片段中,我们通过执行 thread_function() 的多个实例,使用线程同时从多个 URL 读取数据,并将结果存储在一个列表中。

正如您所看到的,使用 ThreadPoolExecutor 可以轻松处理所需的线程。虽然这是一个小例子,但我们可以使用它提交更多的 URL,而不必等待每个响应。

从上面的例子中,我们可以看到线程是处理等待其他资源的任务的一种方便且容易理解的方式,我们还看到 Python 的标准库附带了高级实现,使它变得更加容易。

然而,我们还必须记住, Python 运行时将其注意力分散在线程之间,以便能够正确地管理它们,因此这不适合 CPU 密集型工作。

协程和异步

协程是通过特殊构造而不是系统线程来并发执行功能的一种不同方式。

请原谅我再次让你接触一些关于这个主题的基础理论知识,但是了解什么是协程对于理解我们在 Python 中实现它时发生的事情是很重要的。

协程是一种通用的控制结构,通过它,流控制在两个不同的例程之间协作传递而不返回,它不是线程化的,也不是多重处理的。它也不是建立在这两者之上的,它是一个使用协作多任务的单线程、单进程设计。

本质上,虽然线程化需要多个函数并在不同的线程上运行它们,但 asyncio 在单个线程上运行,并允许程序的事件循环与多个任务通信,以允许每个任务在最佳时间轮流运行。

我们通过使用 asyncio 在 Python 中实现了这一点,asyncio是一个 Python 包,它为运行和管理协同程序以及 asyncwait关键字提供了基础和 API。

与前面类似,您可以看到我们如何实现一个非常基本的示例:

我相信这是在 Python 中实现并发性的一种更加干净和简单的方式。然而,它对语言来说要新得多,因此比线程使用得少。

我可以再举一个与从多个 URL 读取数据完全相同的例子,并使用 asyncio 实现它。

起初,它可能看起来有点复杂,但我认为它比线程化更清晰、更明确、更容易理解。

这是因为协程在程序的语法中明确了哪些函数是并行运行的,而对于线程,任何函数都可以在一个线程中运行。

它们也不像线程那样受体系结构限制的约束,并且由于它在单个线程上运行,所以需要的内存更少。

唯一的缺点是,它们确实需要用自己的语法编写代码,并且它不能与同步代码很好地混合,以及它们不允许 CPU 密集型任务并行高效运行的事实。

多重处理

多重处理是一种机制,通过启动多个独立的 Python 解释器实例,允许你并行运行许多 CPU 密集型任务。

每个实例接收运行相关任务所需的代码和数据,并在自己的线程上独立运行。

虽然上面的例子对于您希望使用多重处理运行的任务类型来说并不令人惊奇,但是我们可以以类似的方式再次实现它们,这样我们就可以看到它们之间的不同之处。

上面是我们可以用多重处理复制的最基本的过程,下面重新实现了从多个 URL 同时读取数据的完全相同的功能。

在上面的代码片段中, Pool() 对象表示一组可重用的流程,我们映射了 iterable 以在函数的每个实例之间进行分配。

这提供的一个巨大优势是,每个操作都在一个单独的 Python 运行时和一个完整的 CPU 内核上运行,允许我们同时运行 CPU 密集型进程。

缺点之一是,每个子流程都需要一份主流程发送给它的数据副本,通常它们会将数据返回给主流程。

正如我前面说过的,我一直在处理一个极其简单的例子。

然而,我发现学习和适应一门语言中新的复杂概念的最好方法是,一开始让它变得非常简单,然后慢慢地但肯定地剥去简单性,暴露下面的复杂细节。

我希望这有助于你找到一种方法,以相对简单的方式处理这些庞大的主题。

深度网络的置信度校准:为什么和如何?

原文:https://towardsdatascience.com/confidence-calibration-for-deep-networks-why-and-how-e2cd4fe4a086

神经网络的不确定性估计(由作者创建)

置信度校准被定义为某个模型为其任何预测提供准确的正确概率的能力。换句话说,如果一个神经网络预测某个图像是一只置信度为 0.2 的猫,如果神经网络校准正确,这个预测应该有 20%的机会是正确的。这种校准的置信度得分在各种“高风险”应用中非常重要,在这些应用中,不正确的预测非常成问题(例如,自动驾驶汽车、医疗诊断等)。),因为与每个预测相关联的校准概率分数允许识别和丢弃低质量的预测。因此,即使还不能完全解释神经网络输出,置信度校准通过将每个预测与精确的不确定性/置信度分数相关联,提供了避免实践中的重大错误的实用途径。

在这篇博文中,我将探讨深度学习中的信心校准主题,从信心校准背后的动机、为什么它很重要以及如何使用它开始。然后,我将概述测量置信度校准的常用方法,包括 brier 评分、预期校准误差、最大校准误差等。最后,我将概述深度学习中现有的置信度校准方法,重点关注在大规模应用中最有效和高效的方法。

为什么校准很重要?

校准可以扩大深度学习的范围(作者创建)

从业者经常错误地将从神经网络获得的预测概率(即 softmax 分数)解释为模型置信度。然而,众所周知,现代神经网络经常以接* 100%的 softmax 分数做出差的(即不正确的)预测,使得预测概率成为对真实置信度的差的和误导性的估计[2]。虽然早期的神经网络在这方面并不“过于自信”,但从神经网络预测中获得准确的不确定性分数的问题并非微不足道— 我们如何才能使 softmax 分数实际上反映给定预测的正确概率?

目前,深度学习已经在许多领域(例如,图像/语言处理)中普及,并且通常用于错误是可接受的应用中。例如,考虑一个电子商务推荐应用程序,其中神经网络可能在 90%以上的情况下提供高质量的推荐,但偶尔会发现最相关的产品。虽然这样的应用很多,但将深度学习部署到医疗诊断或核能等高风险领域需要尽可能减少不正确的模型预测。因此,准确预测模型不确定性是一个有影响的问题,有可能扩大深度学习的范围。

潜在应用

鉴于置信度校准是一个非常重要的问题,有可能对深度学习社区产生巨大影响,人们可能会想知道哪些类型的应用程序最依赖于正确校准的不确定性。虽然有很多,但我在本节中概述了几个,以提供相关背景并激发实践中置信度校准的益处。

过滤不良预测。给定适当校准的模型,可以丢弃具有高不确定性(或低置信度)的预测,以避免不必要的模型误差。这种基于与每个预测相关联的置信度得分来丢弃不正确预测的能力在上述高风险应用中尤其有效。虽然在短期内真正解释或理解神经网络输出可能仍然很困难,但正确校准的不确定性分数为检测和避免神经网络的错误提供了一种实用的途径。

模型感知主动学习。适当的不确定性估计可以轻松识别模型难以理解的数据。因此,可以将与低置信度预测相关的数据放在一边,传递给人工注释者进行标记,并包含在模型的训练集中。通过这种方式,模型的不确定性可以用来迭代地识别模型不理解的数据,实现一种模型感知的主动学习

检测食品数据。具有良好校准特性的模型通常可用于检测不符合分布(ood)的数据,或者与模型的训练集显著不同的数据。虽然校准和 OOD 检测是正交的问题,例如,尽管校准不佳,softmax 分数仍可直接用于检测 OOD 数据[16],但它们经常被串联研究,其中最佳校准方法是根据校准和检测 OOD 数据的能力进行评估的(即,通过将高不确定性/低置信度分配给此类示例)[6]。

测量校准

尽管现在已经很清楚置信度校准是一个有用的属性,但与精度或损失等具体性能指标相比,它并不容易测量。因此,随着时间的推移,已经提出了各种不同的置信度校准度量,每种度量都有自己的优缺点。在本节中,我将按照相关性的顺序概述最广泛使用的度量标准。对于这些指标中的每一个,我将确定它是否是一个合适的评分规则——意味着最佳分数对应于一个完美的预测,并且不存在“琐碎的”最佳解决方案——解释分数的直观意义,并描述它是如何计算的。

布赖尔分数[1]

Brier 评分(BS)是一种适当的评分规则,它测量预测概率向量和独热编码真实标签之间的*方误差。较低的分数对应于更精确的校准;见下图的描述。

计算 Brier 分数(由作者创建)

直觉上,BS 测量预测概率的准确性。它可以分解为三个组成部分——不确定性(标签上的边际不确定性)、分辨率(个体预测与边际的偏差)和可靠性(真实标签频率的*均违反)——如下所示。

Brier 乐谱的分解(由作者创建)

尽管 BS 是测量网络预测校准的良好指标,但它对与不频繁事件相关的概率不敏感。因此,除了 BS 之外,利用多个指标进行测量校准通常会提供有用的见解。

预期和最大校准误差[2]

预期校准误差(ECE)计算置信度和准确度之间的预期差异。期望值的这种差异可以如下所示进行计算。

预期可信度和准确性之间的确切差异(由作者创建)

虽然上述表达式不能以封闭形式计算,但我们可以通过基于相关置信度得分将模型预测划分到单独的箱中来*似计算。然后,可以计算每个条柱内*均置信度和准确度之间的差异,如下图所示。

预期校准误差的置信宁滨(由作者创建)

从这里开始,ECE 计算每个箱内*均置信度和准确度之间的差异,然后根据每个箱的相对大小对这些值进行加权*均。最大校准误差(MCE)遵循相同的过程,但等于各区间的*均置信度和精度之间的最大差值。有关 ECE 和 MCE 的更严格的公式,请参见下图。

预期和最大校准误差的表达式(由作者创建)

对于 ECE 和 MCE,较低的分数对应于较好的校准预测。ECE 和 MCE 都不是正确的评分规则,这意味着*凡的解决方案(例如,预测统一的随机概率)存在最佳校准误差。此外,由于宁滨过程,这两个指标都不会随着预测的改善而单调下降。尽管如此,由于这些指标能够提供模型校准的简单和可解释的估计,所以它们通常被使用。MCE 通常用于可靠的置信度测量绝对必要的应用中(即校准中的大误差是有害的),而 ECE 则提供更全面的跨频段*均指标。

可靠性图表。如果希望获得表征校准误差的图,而不是像 ECE 或 MCE 那样的标量度量,则每箱精度和置信度测量可以很容易地转换成可靠性图。这些图表在 y 轴上描绘了准确度,在 x 轴上描绘了*均置信度。然后,将每个条柱内的*均置信度和准确度测量值绘制在图上,形成一个线形图。在这里,完美的校准将在可靠性图上产生一条对角线,其中置信度等于每个独立仓内的精度;请看下面的插图。

可靠性图的描述(由作者创建)

可靠性图表通常有助于可视化所有箱的校准误差。虽然 ECE 和 MCE 将条柱统计数据汇总到一个简单的标量指标中,但可靠性图表可以立即查看每个条柱的属性,从而在一个易于解释的图中捕获更多校准信息。

负对数似然

负对数似然 (NLL)是一个适当的评分规则,可用于评估保留数据的模型不确定性,其中较低的分数对应于较好的校准。尽管通常用作训练的目标函数,NLL 表征了真实标签的预测和实际置信度之间的差异,当所有数据都以 100%的置信度被正确预测时,达到完美的零分。参见下面的 NLL 公式,其中y是一些神经网络的原始矢量输出。

负对数似然度量(由作者创建)

然而,NLL 过分强调尾部概率,这意味着与正确、完全自信的预测的轻微偏差会导致 NLL 的大幅增加。这种特性对神经网络的影响可以很容易地观察到,其中 NLL(即目标函数)相对于训练集可能很低,但由于网络倾向于做出高置信度预测以最小化 NLL(即本文开头提到的“过度自信”问题),因此对测试集的错误预测具有 100%的置信度[2]。

通常,我们可能希望对来自不同于训练集的分布的数据评估模型的行为,因此没有模型理解的真实标签(即 ood 数据)。在这种情况下,由于缺乏真正的标签,前面的指标都不能用于评估。相反,模型的行为通常通过测量由这种 OOD 数据产生的输出分布的来分析。

高熵和低熵输出分布(由作者创建)

直观上,OOD 数据应该导致具有高熵的网络预测,对应于所有可能的输出都被分配均匀概率的不确定状态。另一方面,对于被很好理解的数据的网络预测应该具有低熵,因为如果模型是准确的并且被适当校准,则该模型以高置信度预测正确的类。因此,当在一组包含 OOD 数据的测试实例上评估模型时,正常和 OOD 数据的预测熵应该清楚地分开,表明模型在 OOD 实例上表现出可测量的不确定性。

校准方法

在这一节中,我将探讨已经提出的用于改进神经网络置信度校准的许多方法。其中一些方法是可以添加到培训过程中的简单技巧,而其他方法则需要利用保留验证集的后处理阶段,甚至需要对网络架构进行重大更改。在描述每种方法时,我将概述它们的优缺点,重点关注每种方法是否适合在大规模深度学习应用中使用。

温度标度[2]

当现代深度神经网络的不良校准首次被发现和探索时(即,本文开头概述的“过度自信”问题),作者将此类网络做出过度自信、错误预测的趋势归因于最*的发展,如增加神经网络大小/容量、批量标准化、权重衰减较少的训练,甚至使用 NLL 损失(即,由于强调尾部概率,这种损失将网络预测推向高置信度)。令人惊讶的是,这种用于神经网络训练的现代最佳实践——尽管产生了具有令人印象深刻的性能的网络——被发现产生了与前几代架构(例如 LeNet [7])相比具有显著退化的校准属性的网络。

为了解决这种较差的校准,[2]的作者探索了几种不同的事后校准技术,这些技术在训练完成后通过使用一些保留验证集来执行校准。他们发现,调整输出层的 softmax 温度(即,在二进制设置中称为 Platt 缩放[8])以最小化验证集上的 NLL,在校准网络预测时最为有效。因此,softmax 变换被修改为如下所示的正值温度T

带和不带温度缩放的 Softmax 变换(由作者创建)

在该表达式中,T的较大值将“软化”输出分布(即,使其趋向均匀分布),而T的较小值将更加强调分布中最大值的输出。因此,T参数实质上控制了输出分布的熵。

通过在抑制验证集上调整T参数来优化 NLL,[2]的作者能够显著改善网络校准。然而,这一校准过程需要一个验证数据集,并在训练后作为一个单独的阶段执行。此外,后来的工作发现,这种方法不能很好地处理 OOD 数据,并且当暴露于网络的数据是非 I . I . d .【6】时完全失效。因此,在给定足够陌生或敌对的数据的情况下,网络仍然可以以很高的可信度做出错误的预测。

基于系综的校准[9]

众所周知,与单个网络相比,集成(或几组独立训练的网络,共同用于预测)可以提供更好的性能[10]。然而,[9]的作者证明了对系综内的网络预测进行*均也可用于获得有用的不确定性估计。特别地,通过使用适当的评分规则(例如,NLL)作为目标函数的 i)ii) 用对立的例子[11]扩充训练集,以及 iii) 训练网络的集合,来修改训练过程;见下文的描述。

基于集合的校准概述(由作者创建)

集合中的每个网络都是独立地并且在整个数据集上训练的(即,具有不同的随机初始化和洗牌),这意味着集合中每个成员的训练可以并行执行。然后,通过对所得集合的预测进行*均,即使在大规模数据集上也可以获得高质量的不确定性估计。此外,这种方法被证明对数据集中的变化是鲁棒的,允许食品样本被准确地检测。因此,尽管处理多个网络会导致额外的计算成本,但是基于集合的校准技术是简单的、高度鲁棒的和高性能的。

混乱[12]

Mixup 是一种简单的数据扩充技术,通过采用随机采样(来自 beta 分布)加权的训练样本的凸组合,并使用这种组合样本来训练网络;请参见下面的示意图。

混合数据扩充程序(由作者创建)

值得注意的是,mixup 结合了输入图像和它们相关的标签。此外,最*的工作[13]已经发现,在训练期间使用混合,除了提供显著的调节和性能益处之外,还可以产生具有改进的校准属性的分类模型。这一发现甚至在大规模上也成立,mix up——包括已经提出的各种变体——甚至被证明在检测 OOD 数据方面是有效的[14]。有趣的是,[13]的作者发现简单地混合输入图像不足以实现校准益处,揭示了输出标签的混合对于校准网络输出是必不可少的。研究标签*滑(即增加标签分布的熵)对网络性能和校准的影响的相关工作进一步支持了这一发现[15]。

贝叶斯神经网络[3]

贝叶斯神经网络——其动机是无限宽的神经网络在其权重上的分布收敛到高斯过程(因此具有封闭形式的不确定性估计)[4]——可以简单地定义为在其权重上放置分布的有限神经网络。这种公式提供了对过拟合的鲁棒性,并且能够表示网络内的不确定性。然而,贝叶斯神经网络,即使使用了新开发的变分推理技术,也遭受了令人望而却步的计算和存储成本。事实上,基本模型的大小通常必须加倍,以便能够用贝叶斯公式进行适当的不确定性估计[5]。因此,贝叶斯神经网络还不适合大规模应用,但我推荐任何对这种方法感兴趣的人阅读这篇精彩而实用的概述

作为贝叶斯*似的辍学[5]

如上所述,贝叶斯网络能够对模型的不确定性进行推理,但是在计算成本方面经常受到限制。然而,最*的工作表明,神经网络训练辍学[17]是高斯过程的贝叶斯*似。此外,通过简单地 i) 运行多个随机前向传递(具有不同的丢失实例)和 ii) *均每个前向传递的预测,可以利用该属性来生成深度网络预测的不确定性分数;见下文对这种方法的描述,这通常被称为蒙特卡洛辍学。

剔除后的不确定性估计(由作者创建)

有趣的是,这种作为高斯过程*似的漏失视角支持鲁棒的不确定性估计,而无需改变底层网络或要求任何后处理。事实上,所需要的只是训练一个带有丢失的正常网络,并在测试时执行多个带有丢失的随机前向传递,其中每个不同的前向传递可以并行化,以避免增加延迟。这种方法在大规模应用中工作得非常好,并且被证明既实现了最先进的置信度校准,又以高精度检测 OOD 数据。然而,基于丢失的校准的性能比上面讨论的基于集合的技术稍差。

那么…你应该用什么呢?

虽然我们在这篇文章中概述了几种置信度校准的方法,但有人可能会问,哪种方法在实践中最有用。这种确定的相关考虑是简单性、有效性和效率。我们已经看到,温度缩放和利用贝叶斯神经网络的不确定性*似值等方法可能在较大规模下效果不佳,例如,温度缩放在非 i.d .数据上中断,而贝叶斯神经网络的计算成本很高,因此在某些情况下效率较低。其他方法工作得相当好,并提供令人印象深刻的大规模校准结果。因此,假设这些方法通常是有效的,人们可以开始考虑它们的简单性和效率。

Mixup 是一种易于实现的(即,只需参见论文中的参考实现)数据增强技术,可以将其添加到训练中以改善最终网络的校准,使其成为校准神经网络的低成本和简单的选择。类似地,利用网络集合提供了令人印象深刻的校准结果,并且易于实现(即,只需训练更多的网络!).但是,它引入了训练多个网络并将其全部用于预测的额外计算费用,因此与像 Mixup 这样的数据增强技术相比,降低了训练和预测的效率。更进一步,蒙特卡洛退出不会降低训练的效率,并提供令人印象深刻的大规模不确定性校准,但在预测期间需要多次向前传递,并且通常优于基于集合的不确定性估计。因此,方法的选择通常是基于应用的,并且取决于操作的约束条件(例如,训练需要快速,所以使用 Mixup 或 Monte Carlo dropout,效率不是问题,所以使用系综等)。).

结论

非常感谢你阅读这篇文章!希望对你有帮助。如果您有任何反馈或担忧,请随时评论该帖子或通过 twitter 联系我。如果你想了解我未来的工作,你可以通过媒体了解我。我的博客专注于深度学习的实用技术,我试图发布两篇文章,内容涉及从视频上的深度学习到使用深度网络的在线学习技术的主题。如果您对我的出版物和其他作品感兴趣,也可以随时查看我的个人网站上的内容。这一系列的文章是我作为一名研究科学家在 Alegion 完成的背景研究的一部分。如果你喜欢这篇文章,请随时查看该公司和任何相关的空缺职位——我们总是希望与对深度学习相关主题感兴趣的积极个人进行讨论或雇用他们!

参考书目

[1]Glenn w . Brier,“用概率表示的预测的验证”每月天气回顾78.1(1950):1–3。

[2]郭,传,等.“论现代神经网络的校准”机器学习国际会议。PMLR,2017。

[3]尼尔,拉德福德 M. 神经网络的贝叶斯学习。第 118 卷。斯普林格科学&商业媒体,2012 年。

[4]克里斯托弗·威廉斯《用无限网络计算》神经信息处理系统的进展 9 (1996)。

[5]加尔、亚林和邹斌·格拉马尼。"作为贝叶斯*似的辍学:表示深度学习中的模型不确定性."机器学习国际会议。PMLR,2016。

[6]奥瓦迪亚、亚尼夫等,“你能相信你的模型的不确定性吗?评估数据集变化下的预测不确定性。”神经信息处理系统进展 32 (2019)。

[7] LeCun,Yann 等,“基于梯度的学习应用于文档识别”IEEE 86.11(1998):2278–2324 会议录。

[8] Platt,John 等人,《支持向量机的概率输出以及与正则化似然方法的比较》。大间距分类器的进展,10(3):61–74,1999。

[9] Lakshminarayanan、Balaji、Alexander Pritzel 和 Charles Blundell。"使用深度集成的简单和可扩展的预测不确定性估计."神经信息处理系统进展 30 (2017)。

10 迪特里希。机器学习中的集成方法。在多分类器系统中。2000.

[11]古德费勒、施伦斯和塞格迪。解释和利用对立的例子。2015 年在 ICLR。

[12]张,,等.“混合:超越经验风险最小化” arXiv 预印本 arXiv:1710.09412 (2017)。

[13] Thulasidasan,Sunil 等人,“关于混合训练:深度神经网络的改进校准和预测不确定性”神经信息处理系统进展 32 (2019)。

[14] Wolfe,Cameron R .,和 Keld T. Lundgaard。" E-Stitchup:预训练嵌入的数据扩充." arXiv 预印本 arXiv:1912.00772 (2019)。

[15]米勒、拉斐尔、西蒙·科恩布利思和杰弗里·e·辛顿。“标签*滑在什么情况下有帮助?."神经信息处理系统进展 32 (2019)。

[16]亨德里克斯、丹和凯文·金佩尔。"检测神经网络中错误分类和非分布样本的基线." arXiv 预印本 arXiv:1610.02136 (2016)。

[17] Srivastava,Nitish 等人,“辍学:防止神经网络过度拟合的简单方法”机器学习研究杂志15.1(2014):1929–1958。

置信区间 vs 预测区间:有什么区别?

原文:https://towardsdatascience.com/confidence-interval-vs-prediction-interval-what-is-the-difference-64c45146d47d

为你的预测选择正确的区间估计

Unsplash 上由J . Scott Rakozy拍摄的照片

置信区间预测区间是两种区间估计,在统计分析中用于量化与给定估计相关的不确定性。两种类型的区间都提供了一个值的范围,参数的真实值可能位于该范围内,并具有指定的置信度。但是,置信区间和预测区间之间存在一些关键差异,了解这些差异对于为给定情况选择合适的区间非常重要。

让我们创建一个简单的线性回归模型的例子,通过这个模型,我们试图根据一所房子的*方英尺(即 X)来预测洛杉矶的房价(即 Y)。我们可以用下面的格式写这个线性回归。

等式 1

但对于这个话题,让我们通过解释变量置于其*均值的中心来重写这个等式(即,用其*均值减去每个解释变量)。

等式 2

其效果是斜率(β)根本不会改变,因为居中只会通过减去一个常数(β*x_bar)来改变等式中的比例,但截距(α)的值会改变。

在线性回归模型中,我们为什么要将解释变量集中在其均值上?

当解释变量不居中时,模型中的截距项代表解释变量等于零时响应变量的预测值。这个值没有意义。

相反,如果解释变量以其均值为中心,截距项就变成了响应变量的均值,解释起来更直观。

*均响应的置信区间是多少?

置信区间是对给定的一组解释变量值预测*均响应值的区间估计。

一个置信区间与来自 OLS 估计量、 α和β.的抽样不确定性有关

αβ 是线性回归模型中的系数(或参数)。我们通常不了解它们,因为在很多情况下,不可能收集所有的人口数据来计算它们的价值。相反,我们只能依靠样本数据来计算 OLS 估计量,α^β^ 来估计α和β。如果我们收集一组不同的数据并再次拟合模型,我们可能会得到α和β.的不同值α的这种不确定性(又名采样不确定性)是预测响应值的不确定性来源之一。*

在预测的背景下,对于给定的一组解释变量值,置信区间为我们提供了一系列的*均响应值。

例如,如果我们想估计洛杉矶 2000 *方英尺的*均房价,那么我们就在谈论置信区间。

如何计算*均响应值的置信区间?

我们需要知道*均响应值 (y^)的期望值方差来计算置信区间。

我们知道方程 2 中线性回归模型的 OLS 估计值是(见证明此处)

作者图片

给定值解释变量(x)的*均响应值的期望值(又名点估计值)为

作者图片

为了计算*均响应值的方差,我们需要得到α和β抽样分布,特别是它们的方差。它们是(参见此处的证明)

作者图片

然后,我们可以计算*均响应值的方差:

作者图片

这里σ是误差项的方差,通常未知。我们可以用样本数据的均方差( MSE 或 S ) 来估计它的值。

作者图片

最后,我们可以计算*均响应的置信区间:

作者图片

新响应的预测间隔是多少?

预测区间是对给定的一组解释变量值预测新响应值或未来观察值的区间估计。

预测区间比置信区间宽。因为它不仅包括来自 OLS 估计量α和β抽样不确定性,而且还考虑了来自线性回归模型无法解释的不可约误差、 ε、的不确定性。

在预测的上下文中,对于给定的一组解释变量值,预测区间为我们提供了任何可能响应值的值范围。

例如,如果我们想估计洛杉矶一座 2000 *方英尺的随机房屋的价值,那么我们就在谈论预测区间。

如何计算新响应的预测间隔?

我们需要知道新响应变量(y)的期望值方差

我们知道这一点

作者图片

作者图片

因此,新响应变量的期望值是

作者图片

这与*均响应的预期值相同。新响应变量的方差为

作者图片

最后,我们可以计算新响应的预测区间:

作者图片

为什么预测区间比置信区间宽?

数学上,从公式中,我们可以看到预测区间包括额外项σ,以说明误差项的方差

直观地说,在我们的例子中,房价可能会因回归模型中未包括的其他因素而变化,如位置、房屋状况、抵押贷款利率和其他未观察到的因素。这些被排除的变量将被包含在误差项ε中。预测区间需要考虑这些排除变量的不确定性。因此,对于相同的解释变量值,预测区间比置信区间具有更宽的范围。

决定置信区间和预测区间宽度的因素是什么?

从公式中,我们可以看到

  • 随着 MSE 的减小,区间的范围也减小。为了使线性回归模型中的 MSE 更小,我们需要确保模型的适当性,并包含相关的和有意义的预测因子。
  • 随着 t 乘数的降低,置信水*降低,则区间范围缩小。
  • 随着样本量的增加,则区间的范围减小。
  • 预测值的方差越高,区间越窄。直观上,预测者能为模型提供的信息越多,区间估计就越精确。
  • 预测值的输入越接*它们的*均值,区间就越窄。直观地说,当预测值在均值附*时,线性回归模型在预测方面更精确。因此,我们期望区间估计有一个“沙漏形状。

如何计算多元线性回归(MLR)模型中的置信区间和预测区间

通常,我们会处理一个有多个预测因子的线性回归模型。MLR 的置信区间和预测区间与简单线性回归非常相似。

MLR 置信区间的一般公式为

作者图片

MLR 中预测区间的一般公式为

作者图片

摘要

置信区间和预测区间都是区间估计,它们提供了一个值范围,在该范围内,真实值可能位于指定的置信水*。然而,置信区间用于估计总体参数,而预测区间用于预测未来观测值。置信区间通常比预测区间窄,因为它们仅包括与估计总体参数相关的不确定性,而预测区间包括与预测单个值相关的额外不确定性。根据具体的统计问题和被分析数据的类型选择合适的区间估计是很重要的。

来源:

PennState Stat 415:数理统计简介

PennState STAT 501:回归方法

如果你想探索更多与统计相关的帖子,请查看我的文章:

感谢您的阅读!!!

如果你喜欢这篇文章,并且想请我喝杯咖啡,点击这里

您可以注册一个 会员 来解锁我的文章的全部访问权限,并且可以无限制访问介质上的所有内容。如果你想在我发表新文章时收到电子邮件通知,请订阅。

简单解释了置信区间

原文:https://towardsdatascience.com/confidence-intervals-simply-explained-58b0b11e985f

置信区间的简明解释。

Unsplash 上的 Edge2Edge 媒体拍摄

介绍

置信区间是统计学和数据科学中需要理解的一个基本概念。在本文中,我将简单明了地解释什么是置信区间以及如何计算它们。

直觉

简而言之,置信区间可以被认为是来自给定总体数据集的采样参数的相关不确定性。

区间是给定参数(通常是*均值)的一系列值,并附有‘置信度’来衡量您对真实总体参数位于随机样本区间范围内的确信程度。

置信水*是指当你抽取大量随机样本时,置信区间将包含真实总体参数的确定性。最常见的概率极限有*和 99% 。这意味着用 95% 置信区间抽取的随机样本中的将包含真实参数**。这并不意味着给定的随机样本有95%的机会在其区间范围内包含真参数。这是一个微小但重要的细微差别。*****

注:置信区间是用正态置信区间公式计算的。非正态数据怎么办?大多数总体服从 中心极限定理 ,因此我们可以计算大多数非正态数据的正态置信区间。

数学

(正常)置信区间的公式为:

LaTeX 中生成的方程。

其中为样本均值s 为样本标准差n 为样本量,*为均值的数。*******

如果 z = 1.96 ,这是指一个95%的置信度,而 z = 2.576 是指一个99%的置信度。这来自于有多少数据落在正态分布的不同标准偏差内。****

可以看到,随着 n 趋向于无穷大区间范围越来越小,最终将达到零。这意味着我们几乎 100%确定我们掌握了真实的意思。****

例子

假设我们有学生的考试成绩:70,80,85,75,71,65,90,96,95,60。该群体的均值78.7

假设我们对第一个 5 个结果进行采样:70、80、85、75、71,并且想要 95%的置信度:

  • x̄ = 76.2
  • s ~ 6.3
  • n = 5
  • z = 1.96

因此,我们发现我们的置信区间为:

LaTeX 中生成的方程。

事实上,在这种情况下,总体*均值位于我们的抽样*均值的置信区间内。

结论

希望你喜欢这篇关于置信区间的简短而甜蜜的文章!如果你喜欢,记得留下掌声!

和我联系!

(所有表情符号都是由 OpenMoji 设计的——开源的表情符号和图标项目。许可证: CC BY-SA 4.0

标签错误是必须的吗?自信学习有用吗?

原文:https://towardsdatascience.com/confident-learning-err-did-you-say-your-data-is-clean-ef2597903328

以数据为中心的人工智能,深度学习中的数据

不管你可能听说过什么,让深度学习如此伟大的是数据!

有一句老话总结得很好:

型号只有一样好一样好 数据

这就给我们带来了真正的问题:你的数据到底有多好?收集地面实况/训练数据集是极其昂贵、费力和耗时的。标记的过程包括搜索感兴趣的对象,并应用先验知识和试探法来做出最终决定。表示(感兴趣的)对象是否存在的决定,如果存在,对其进行注释以提供额外的信息,如边界框和分段掩码。

在这个过程中,有几个因素会导致数据集中出现错误。问题是,我们能做些什么?在本帖中,我将涉及标注错误发生的一些原因、标注中的错误为何必不可少,以及可以使用哪些工具和技术来管理标注数据集中的错误。然后,我再深入到自信学习的细节。我还将演示如何使用 cleanlab ,一个自信学习实现【1】,轻松找到数据中的噪声。

免责声明:在深入细节之前,我想确认,在我写这篇文章的时候,我没有以任何身份隶属于 cleanlab 或受其赞助。

这篇文章分为以下几个部分:

1。标签错误的原因

2。增加贴标错误风险的贴标效率技巧

3。标签中的错误是必要的

4。确切地说,什么是自信学习?

4.1。基础知识

4.2。CL 的局限性

5。使用 cleanlab 进行多标签分类的实际标签噪声分析

5.1。型号信息

5.2。使用 cleanlab 探索噪声

6。参考文献

7。结论

标签错误的原因

让我们先来看看标签中可能出现错误的一些原因。这种错误的一大类是工具/软件错误。这些可以使用良好的软件最佳实践来控制和管理,比如涵盖软件和数据的测试。另一类错误是来自贴标机本身的错误。这些问题难以追踪。因为贴标机毕竟是这个深度学习过程中的神谕!如果我们不相信他们,那我们相信谁?

丽贝卡·克劳利(Rebecca Crowley)有一项非常有趣的工作,她提供了一个详细的图表,列出了为什么在场景中搜索时可能会错过某个(感兴趣的)物体,或者为什么他们可能会做出错误的最终决定。在我看来,一些直接影响标签的因素包括:

  1. 搜索满足:一旦找到某样东西就停止搜索的倾向,导致过早停止,从而增加了遗漏注释的机会【4】。这更适用于需要多个注释的场景。例如,多标签或分段标注(狗和笔在图像中,但标注者只为狗标注,而没有花足够的时间来发现笔并在标签中捕捉)。
  2. 过度自信&信心不足:这种类型的标签错误与一个人过度或低估的认知感有关。
  3. 可用性(avail ability):如果某件事经常发生或很少发生,对它进行错误的注释会有一种隐含的偏见[4]。对于具有挑战性的贴标任务来说尤其如此。例如,如果一个位置的癌症患病率为 0.01%,那么当标记一个不那么直接的病例时,标记者更可能标记非癌症而不是癌症。
  4. 锚定/确认偏差:当贴标机对贴标任务的结果做出先发制人的决定,然后寻找支持该决定的信息。例如,相信他们正在看一个癌症病例,他们开始在图像中搜索异常以支持该病例是癌症的发现。在这个不公*的搜索/决策过程中,他们更容易犯错误。
  5. 赌徒谬误:当他们遇到类似案件的重复模式时,他们很可能会偏离并倾向于打破这种模式的结果【4】。
  6. 在所有这些原因中,认知超载也是标签错误的一个有效且公*的原因。

增加标签错误风险的标签效率技巧

鉴于获取标注数据集的过程非常昂贵,有时会应用一些巧妙的技巧和技术来优化标注漏斗。虽然有些技术侧重于通过标签体验进行优化,如快速交互式对象注释 [5],但其他技术侧重于使用自动标签技术来减轻标签负担,以帮助贴标机。特斯拉有一个非常强大的机制来实现大规模的自动标签,正如 Karpathy 在2021 CVPR中所谈到的。他们肯定有反馈的优势(不仅仅是事件值得标记,还有司机做了什么或者是否导致了灾难)。这是不是所有深度学习实践机构都有的优势!令人印象深刻!然后,我们还有一个训练制度的弱监督类,我不会详细介绍(也许是另一天的主题)!

事实是,你用来优化这个过程的技巧越聪明,你的数据集中出错的几率就越高。例如,在标签循环中使用模型越来越多地被用于优化标签过程(如本演示文稿中详述的),作为自动标签/预标签技巧,其中预测的标签被显示给贴标签机,而贴标签机仅微调注释,而不是从一开始就进行注释。这个过程有两个主要挑战:

a)它可能会在标签中引入整个范围的偏差,如上文(标签误差的原因)中所述。

b)如果模型不能与人类标记器相提并论,校正垃圾在先标记的劳动和厌倦增加了数据集中的错误风险。这是认知超载的典型案例。

如果这个例子还不够,让我们来看一个使用本体/知识图自动标注的例子。这里,如果编码在本体/知识图中的知识有偏差,错误传播的风险就太高了。例如,如果它是一个海洋水体,它可能是一个游泳池。因为,与常识相反,海洋池确实存在(例子可以在这篇博文中找到)。或者,如果它是一栋房子,那它就不是水体——因为你知道湖边的房子确实存在!

标签中的错误是必然的

鉴于目前所讨论的挑战,可以说错误是不可避免的。在这个过程中的先知是贴标签的,他们只是普通人!

我是 不完美;我只是 人类

显然,在 10 个流行的数据集上,估计*均至少有 3.3%的错误,例如,标签错误至少占 ImageNet 验证集 2 的 6%。

假设人类贴标机将产生一个完美干净的数据集,嗯,至少可以说有些过火。如果你关心的话,你可以使用多个标签来减少错误,通过一致意见来移除噪音。这是产生高质量数据集的一种很好的技术,但是它也贵很多倍,速度慢,因此作为标准的操作方式是不切实际的。除了昂贵之外,这也不能保证一个干净的数据集。这一点从 Northcutt 的 NeurIPS 2021 [2]的工作中可以明显看出,该工作分析了流行数据集测试集中的错误,这些数据集报告了流行数据集中数百个样本的顺序,尽管查看了贴标机的整理结果,但仍无法就真实情况达成一致(参见论文中的表 2 以供参考)。

在过去的几年里,我一直在使用模型在循环中寻找数据集中与模型不一致的样本。我发现的其他一些有用的技术是利用损失函数,正如 Andrej Karpathy 所说!最*,我已经看到了部署基于本体的违例来查找样本的巨大好处,这些样本要么是 a)标签错误,要么是 b)我们没有意识到的极端边缘情况(也称为分布外[OOD]样本)。

然而,当我遇到诺斯卡特团队的清洁实验室项目(T21)并开始挖掘这个领域的大量文献时,我意识到我一直生活在遗忘中!我很兴奋地发现了所有的文献,这些文献提出了我迄今为止一直在使用的技巧和窍门,而我并没有意识到它们。不会再有了!!在接下来的章节中,我将讲述我通过阅读这些文献所学到的东西。

到底什么是自信学习?

所有型号都是错的,但有些是 有用的

自信学习【1】(CL)就是利用我们手头所有有用的信息来发现数据集中的噪音,提高数据集的质量。它是关于使用一个 oracle(贴标机)并在构建中使用另一个 oracle(即模型)测试它!在很高的层面上,这正是我们通常所说的模型在回路中!

学习存在于数据环境中,然而置信度的概念通常关注模型预测,而不是标签质量!https://arxiv.org/abs/1911.00068

自信学习 (CL)是一类学习,其重点是尽管数据集中存在一些噪声,但仍能学好。这是通过准确和直接表征数据中标签噪声的不确定性来实现的。CL 依赖的基础就是那个Label noise is class-conditional, depending only on the latent true class, not the data 1 。例如,一个leopard很可能被错误地标记为jaguar。这是一个非常强有力的论点,实际上是不真实的。我可以认为场景(即数据)对贴标者的决定有影响。例如,一只在水中航行的脏东西如果在水中就不太可能被贴上汽车的标签。换句话说,用卡车运输的脏兮兮的东西会不会比在水上行驶的时候更容易被贴上汽车的标签?所以数据和背景很重要!
这个假设是in statistics any assumption is fair if you can solve for x!的经典案例。既然我们已经对此进行了挖掘,公*地说,这一假设在某种程度上是正确的,即使不完全正确。

CL 做出的另一个假设是,数据集中的错误率是< 1/2. This is a fair assumption and is coming from Angluin & Laird 的[3]提出的用于类别条件噪声过程的方法,该方法在 CL 中用于计算噪声和真实标签的联合分布。

自信学习中,一个相当好的性能模型被用来估计数据集中的误差。首先得到模型的预测值,然后利用特定类别的阈值设置得到置信度的联合分布矩阵;然后将其归一化以获得误差矩阵的估计。然后,这个估计的误差矩阵为数据集修剪、计数和排列数据集中的样本建立基础。

估计联合分布具有挑战性,因为它需要将认知的不确定性(模型预测的概率)与随机的不确定性(有噪声的标签)区分开来,但这是有用的,因为它的边缘产生了文献中使用的重要统计数据,包括未被破坏的标签之前的潜在噪声跃迁率和反向噪声率。 1

自信学习 图片(图片来自1)**

特定于类的阈值的作用对于处理每个类的模型性能的变化是有用的。这种技术也有助于处理预测标签中的冲突。

自信学习cleanlab (它的 python 实现)的伟大之处在于,虽然它没有提出任何开创性的算法,但它做了一些很少有人做的事情。将 antecedent 作品整合到一个非常好的技术框架中,这个框架如此强大,以至于它理所当然地质疑塑造深度学习进化的主要数据集。他们对包括 MNIST 在内的 10 个流行数据集的分析的工作受到了高度赞赏。这也提醒我们,我们正在大规模地让整个深度学习景观过度适应像 MNIST 和 ImageNet 这样的数据集,因为它们几乎必须使用数据集来基准测试和验证更大更好的算法,并且它们至少有 3.3%的误差,如果不是 20%(根据诺斯卡特的团队的估计)!

这种方法用于并排比较,其中样本被随机修剪(下图中的橙色部分所示),或者更有策略地通过 CL 仅去除有噪声的样本(下图中的蓝色部分所示)。准确度结果如下所示。CL 比随机修剪做得更好!

借鉴 自信学习 (图片来自1*)*

以下是 CL 标记为有噪声/错误的一些样本的示例,还包括边缘情况,其中 a)两者都不正确,b)这是 CL 建议或提供的标签,但不清楚两者中哪一个是正确的(不一致):

使用自信学习 2 纠正的样本示例。(图片来自* 2 )*

CL 显然不是 100%准确。在最好的情况下,这是一种使用认知不确定性预测器(模型)来估计噪声的努力。尽管如此,这些失败的例子也很有挑战性。

示例示例自信学习奋力拼搏!2(图片来自 2 )

基本原则

让我们来看看 CL 构建的基础,深入了解一下构建自信学习 ( cleanlab )的基础的前因和相关著作!

  1. 如上所述,由 Angluin & Laird 提出的 is 类条件噪声是 CL 使用的主要概念。
  2. 使用加权损失函数来估计错误分类的概率,如在 7 中使用的,与化学发光领域非常相关,尽管它没有直接用于由自信学习框架文件提出的化学发光技术。
  3. 使用迭代噪声交叉验证技术,如 Chen 等人提出的。 al[8],利用模型在环方法寻找噪声样本。该算法如下所示:

的 INCV 算法(图片来自【8】)

4.CL 不直接使用mentor net【6】。然而,这是非常相关的工作,建立在数据驱动的培训方法。简单地说,有一个教师网络,它建立了一个由易到难的样本(使用损失测量得出)的课程,学生在这个课程之外接受培训..

MentorNet 架构(图片来自 [https://arxiv.org/abs/1712.05055 6])

5.数据驱动教学还有其他变化,一个值得注意的例子是合作教学【9】,它看起来像是成对地互相教学,并在学习过程中互相传递无噪声样本(根据损失测量计算)。合作教学试图解决的主要问题是存在于导师网的记忆效应。(又名 M-Net)但由于数据共享,不在合作教学【9】中。

合作教学 [https://arxiv.org/abs/1804.06872 9]方法与 MentorNet [6[又名 M-Net(图片来自 [https://arxiv.org/abs/1804.06872 9])

6.理解小损耗是有用样本和很可能正确样本的良好指标,而跳动的、高损耗产生的样本是有趣的!它们可能是极端的边缘情况或不符合分布的样本,也可能表明是错误的。这只适用于性能合理的模型,其能力至少比随机机会要好,如果不是更好的话!

CL 的局限性

关于标签错误,CL 完全忽略的一件事是当一个或多个真正的标签完全丢失时。与多类分类相比,这更可能发生在多标签设置中,甚至更复杂的标签设置中,如分割或检测。例如,如果图像中有一台电视和一个水瓶,并且仅有的注释是针对电视的,而水瓶完全丢失了!这目前没有在 CL 中建模,因为依赖于在给定标签和真实标签之间建立成对的类条件分布。例如,如果给定的标签是猫,而实际的标签是狗。当真正的标签存在时,框架本身不允许它为丢失的标签建模。

CL 中提出的成对类别条件分布也限制了其在多标签设置中的使用。当多个标签可以在同一数据上共存时,显式。例如,屋顶和游泳池都可以出现在图像中,它们不一定是唯一的。这种限制来自成对(单类给出与单类预测)建模。这与斯坦福汽车数据集不同,在斯坦福汽车数据集中,品牌和型号被预测为多个标签,但它们是唯一的,即一辆车可以是 ute 或掀背车,但只有丰田或沃尔沃才能生产。在这种情况下,排他性允许对成对的类条件分布进行建模。这些是使用多头网络建模的更多的多标签多类。真正的多标签数据集无法像这些成对联合分布一样建模。它们也许可以用更复杂的联合分布公式来建模,但这种方法不能很好地扩展。自信学习【1】目前是一种计算量很大的算法,复杂度为 O(m2 + nm)。

说了这些,可能是文献中没有解释的东西,因为似乎 cleanlab 本身支持多标签分类。从概念上讲,我不清楚多重标签是如何工作的。随着此工具 12 上问题的解决,对多标签的支持也在发展。

使用 cleanlab 进行多标签分类的实际标签噪声分析

既然我们已经介绍了背景和理论基础,让我们使用置信学习的实现 cleanlab 来测试标签噪声。具体来说,考虑到围绕它的不确定性,我将使用多标签分类(如上所述)!。对于这次实践,我将使用 MLRSNet 数据集。这个尖峰是使用 ResNet 作为多标签图像分类器构建的,预测可以同时共存的 6 个类别。这些类是['airplane', 'airport', 'buildings', 'cars', 'runway', 'trees'] 并衍生自 MLRSNet 子集——即仅使用airplaneairport

这个项目的源代码和这个笔记本label-noise Github 库。笔记本检查 cleanlab 在检测标签噪音方面的表现,并识别出未分配的样品、奇怪的样品以及错误!

模型信息

使用标签噪声训练 19 个时期的模型的训练和验证损失。注意,对于这个峰值,我选择退出 n 重交叉验证(CV)。使用 CV 可以得到更好的结果,但是速度不快。

本练习中使用的模型的训练日志(图片由作者提供)

cleanlab 在噪声方面的探索

如本笔记本中的所示,过滤方法提供了一个被认为有噪声的样本列表。这将 38%的样本外数据标记为噪声/错误。

等级提供了标签质量在 0-1 范围内的样本顺序,数字越高,样本质量越好。我用get_self_confidence_for_each_label方法寻找分布外(OOD)样本和基于熵的排序。每一项的分布如下:

基于熵排序的置信度排序(图片由作者提供)

自信排序的自信顺序(图片由作者提供)

被选为最低质量或置信度的样本确实是正确选择的。图像中遗漏了一架飞机(显示在突出显示的覆盖图中),另一个样本是 OOD!

样本被清除标记为噪声(图片由作者提供)

更有趣的是,所有三种过滤方法,按置信度和熵排序,都标记了这两个样本!因此,我们提高了阈值,虽然有假阳性(噪声),但也有一些错误的好例子。

假阳性样本被清除标记为噪声(图片由作者提供)

另一个。真阳性样本被清除标记为噪声(图片由作者提供)

我不确定我是否遵循了如何解释多标签的成对计数,所以这是另一天的练习!

结论

正如本帖所讨论的,标签错误不可避免有几个原因。虽然需要不小的努力来最小化数据集中的误差,但是数据集中的误差管理也是有保证的。发现噪音数据、不一致数据或代表系统缺陷的数据(软件/工具问题或对定义目标类的概念的理解问题)的管理。像模型在环这样的方法,或者像本体这样的附加信息来发现数据集中这样的噪声或错误是有效的技术。自信学习为分析含噪声或 OOD 样本的数据集提供了坚实的基础,这是一种对多类方法非常有效的技术,并不断发展对多标签分类的支持。现在,开始清理数据集!大扫除快乐!

参考

  1. C.g .诺斯卡特、l .江和 I .庄。自信学习:估计数据集标签的不确定性。人工智能研究杂志,70:1373–1411,2021。 1911.00068
  2. c . g . north cutt、a . Athalye 和 j . Mueller(2021 年)。测试集中普遍存在的标签错误会破坏机器学习基准的稳定性。国际学习代表研讨会(ICLR)。 2103.14749
  3. D.安格鲁因和 p .莱尔德。从嘈杂的例子中学习。机器学习,2(4):343–370,1988 年。链接
  4. Crowley RS,Legowski E,Medvedeva O,Reitmeyer K,Tseytlin E,Castine M,Jukic D,Mello-Thoms C .在基于计算机的系统中自动检测病理学家之间的启发和偏见。健康科学教育理论与实践。2013 年 8 月;18(3):343–63.doi:10.1007/s 10459–012–9374-z。PMID:22618855;PMCID: PMC3728442。链接
  5. 黄玲和和 Amlan Kar 和陈和 Sanja Fidler,用曲线快速交互对象注释-GCN。CVPR 2019链接
  6. 姜,周,梁,李,李,,李(2018)。Mentornet:在损坏的标签上学习非常深度的神经网络的数据驱动课程。机器学习国际会议(ICML)。 1712.05055
  7. 名词(noun 的缩写)Natarajan、I. S. Dhillon、P. K. Ravikumar 和 A. Tewari。带着嘈杂的标签学习。神经信息处理系统会议(NeurIPS),第 1196–1204 页,2013 年。 NurIPS 2013
  8. 页(page 的缩写)陈,廖本斌,陈国荣,张绍良。理解和利用用噪声标签训练的深度神经网络。国际机器学习大会(ICML),2019 年。 1905.05040
  9. 韩,b,姚,q,余,x,牛,g,徐,m,胡,w,曾,I,杉山,m(2018)。合作教学:具有极度噪声标签的深度神经网络的鲁棒训练。神经信息处理系统会议。 1804.06872

自信地理解置信区间

原文:https://towardsdatascience.com/confidently-understanding-the-confidence-intervals-54142c56b081

在 10 分钟内了解一个重要但被广泛误解的概念

克里斯·利维拉尼Unsplash 上拍摄

置信区间——我们都听说过!我们中的许多人认为我们理解他们,而我们中的一些人实际上理解他们。下面这篇文章致力于首先理解置信区间背后的直觉,然后继续讨论我们如何使用样本均值/标准误差/误差幅度等来创建置信区间。,捕捉他们周围的误解,触及影响他们的主要因素。让我们开始吧!!

置信区间背后的直觉

我们经常想知道人口参数比如每户一周的*均花费是多少,10 岁学生的*均身高是多少或者从伦敦开车到爱丁堡的*均时间是多少。虽然我们想了解人口数量,但实际情况是我们永远无法获得所有的人口数据。要知道一个国家内所有家庭的花费几乎是不可能的,我们不可能有所有 10 岁儿童的身高统计数据,要知道每个人从伦敦开车到爱丁堡所花的时间也是不切实际的。

在这种情况下,统计学就可以派上用场了,因为我们想知道关于人口的一些事情,我们会(几乎!)从来没有接触过人口的数据。我们能得到的是来自一个群体中的一个样本的数据。通过统计学,我们可以根据样本数据中的观察值推断出总体参数

推断是指我们根据观察到的样本得出关于总体参数的结论或估计。

现在,我们使用样本数据的估计值来推断总体参数,总体参数可以有一个固定值,但我们永远不会知道它(记住,总体参数是未知的!),所以存在一个范围,这个范围可以从观察到的样本数据中推断出来。因为这是一个范围,范围越宽,我们就越有信心,而范围越窄,我们就越不有信心总体参数将位于其中。
例如,如果范围非常宽,比如从 0 到无穷大(或者从最小可能值到最大可能值),我们可以 100%确定人口参数在它之内(因为它还能在哪里!!)→ 但是,这样极宽的范围一点帮助都没有! (知道人口参数在 0 到无穷大之间你能做什么——什么都不做!)

本质上,为了推断一个总体参数,我们需要以观察样本为基础,并围绕它构建一个有一定置信度的范围(或区间)。观察样本均值附*的这个区间(或范围)称为置信区间

通过示例了解

我们来举个例子,假设你想确定从伦敦到爱丁堡的开车时间。让我们假设一年中有 10 万次从伦敦经由 【即人口=10 万次行程】 到爱丁堡的旅行。实际上不可能询问每个人的旅程并记下旅行时间。这意味着不可能知道 10 万人口的*均出行时间
→人口*均出行时间是一个未知数,比如说‘t’。

显然,从整个人口中获取数据是不可行的;然而,你能做的是问一些经历过这一旅程的人(可能在你的邻居或工作场所附*)来得到一个估计。比方说,你从人口的样本中获得 100 次旅行的数据,*均旅行时间为 9.5 小时。这 100 次旅行是一个子集,是 100K 次旅行的样本,样本的*均旅行时间称为样本均值。让 t '表示这些样本*均值,对于样本#1,t ' = 9.5 小时

请注意,选择该样本有几种可能性。如果您选择不同的 100 次旅行(即不同的样本),那么您将获得的*均旅行时间(即样本均值)可能会(并且很可能会)不同。正如你在下面的图片-1 中看到的,样本#2 的样本均值为 10 小时。类似地,样本#N 可以具有 8.8 小时样本*均值。由于样本是总体的子集,样本均值永远不会是总体均值的完美代表。此外,我们知道来自同一人群的不同样本可以有不同的样本均值。这叫做采样误差

让 t '表示这些样本均值。由于所有这些样本都来自 100K 旅程的原始人群,因此可以说所有样本均值 (来自所有这 N 个样本) 将遵循以“未知”人群均值为中心的正态分布 (假设 N 很大)

  • 也就是说,如果我们取 N 个样本,我们将有 N 个样本均值,分别用 t'(1),t'(2),…,t'(N)表示,并且 t '(即样本均值)的分布是以 t(总体均值)为中心的正态分布。 请参考图片-1(下图)进行参考。

图片-1 |总体、样本、样本均值和样本均值分布(图片由作者提供)

让我们集中于样本#1,样本均值 t ' = 9.5 小时,这个值可以位于样本均值分布的任何位置。它可以位于 t 的左侧或右侧,可以靠*或远离总体均值 t。这种不确定性的原因是我们不知道真正的总体均值是什么。

现在,考虑这个问题,

样本均值 t '在 t 的 2 个标准差以内的概率是多少?
请注意,这里的标准差是取多个样本均值后 t '值的偏差,即 t'(1),t'(2),…,t'(N)。

从正态分布性质我们知道 95%的值 位于总体均值的±2 个标准差之间

图片-2 |以未知总体均值为中心的样本均值分布(图片由作者提供)

这意味着,95%的时间 t’将位于 t 的 2 个标准偏差内。 这相当于说..( b 的 c 内 a a b c 内相同)。)总体均值(t)在样本均值(t’)的 2 个标准差以内的概率为 95%。

为了推断 t,我们希望在 t '的任一侧构造一个区间,使得 t 有 95%的可能性位于该区间内。
——我们必须在 t '附*建立一个 95%的置信区间(CI)。

构建区间

为了定义 t '附*的这个区间,理想的是知道 t '的标准偏差。t '中的标准偏差来自于取多个样本并找出各种样本*均值的偏差。但是,我们不会那样做,对吧!
(持续从总体中抽取无限样本是不可行的)

我们有什么东西可以帮助我们估计样本均值的偏差,从而给出 CI 的概念吗? 嗯是的!!我们有来自总体的 100 个观察值中的样本#1,我们可以用它来估计偏差和区间。这叫做样本的标准误差。**

样本的标准误差 标准误差(或样本均值的标准误差)是一种推断统计,简单地说就是告诉我们样本数据代表总体的准确程度。它描述了总体中多个样本的可变性,并且使用样本中收集的数据来计算**

让我们看看也会影响置信区间(CI)的标准误差的一些属性:

标准误差(以及 CI)应取决于两个因素:

  1. 感兴趣人群的变异:

如果我们的总体值彼此非常接*,即所有 100K 行程的旅行时间变化非常小,那么我们从同一总体中选择的任何样本将彼此非常相似。这意味着,样本均值不会有很大的不同,观察到的样本均值可能接*总体均值。
感兴趣的群体的低变化意味着我们的估计将非常接*真实的群体值
→我们将有一个非常窄的置信区间

类似地,如果我们的总体值有很大的可变性,那么很可能来自同一总体的每个样本都互不相同,因此,样本均值也会有很大变化。我们不太确定我们观察到的样本均值是否接*总体均值。
高人口变异将意味着我们的估计不会接*人口*均值。
我们将有一个宽的置信区间

2。样本大小

小样本量意味着没有大量的观察值来进行推断,异常值会影响样本均值。这意味着小样本很可能彼此不同,因此样本均值也可能有很大变化。
采样误差的影响很大,我们对观察到的样本不太确定。
我们会有一个
宽的置信区间*。*

另一方面,高样本量意味着在一个样本中有很多观察值,因此异常值的影响被抵消了。这意味着来自同一总体的不同样本(高样本量)彼此差异不大,因此,样本均值也将彼此接*。
→减少采样误差的影响。我们可以更加确定观察到的样本均值。
→我们将有一个非常窄的置信区间

根据上述内容,样本的标准误差可定义为:

标准误差=标准偏差(样本)/样本量

低人口方差,Std。戴夫。(样本)低→ 标准。错误—低
高总体方差
,标准差。戴夫。(样本)高→ 标准。错误—高电*

对于较小的样本,样本量较低→ 标准。错误-高 对于较大的样品,样品尺寸高→ 标准。错误—低电*

将此应用于我们的虚拟数据,我们得到 0.25 小时的标准误差。

请记住,对于 95%的置信度,我们可以在样本均值的任意一侧取 2SE 来构建我们的置信区间。这意味着,对于 95%的置信度,样本均值的两边都有一个误差范围(等于 2SE)。

置信水*下的误差幅度是在样本均值的任一侧,我们在推断总体均值时可以预期的最大偏差

*误差范围= 2 标准误差(置信度为 95%)

请注意,误差幅度是:
1 的函数。自信程度。
2。样本的标准误差

我们可以在 9.5 小时样本均值的两侧构建一个 2 * SE(= 2 * 0.25 = 0.5 小时)的区间,并得到人口*均出行时间的置信区间在 9 小时之间。(= 9.5 小时–0.5 小时)和 10 小时。(= 9.5 小时+0.5 小时)

在 95%的置信度下,*均行程时间在 9-10 小时之间。

由于 CI 是一个区间,因此有一个下限和一个上限,如下:

置信下限= 样本均值—误差幅度 置信上限= 样本均值+误差幅度

置信区间=样本均值+/-误差幅度=【LCL,UCL】

在我们的例子中,CI = [9.0,10.0],LCL = 9.0 小时,UCL = 10.0 小时

词的解释:

如果我们取另一个样本,我们将有一个不同样本均值(t’),一个不同的样本标准误差,一个不同的误差幅度,因此,一个完全不同的置信区间。从这些随机样本中计算出的一些区间将包含真实总体均值,而一些则不包含。请参见下面的图片-3。95%的置信水*意味着从这些随机样本中计算出的 95%的置信区间将包含真实的总体均值。换句话说,如果你进行 100 次研究,你会得到 100 个不同的置信区间。我们预计这 100 个置信区间中的 95 个将包含真实的总体均值。

图-3 |不同样本不同 CI;有些包含真实人口*均数,有些不包含。
95%的置信度意味着每 100 个样本中有 95 个这样的 CI 具有真实*均值(图片由作者提供)

置信度不在区间内,因为它会从一个样本到另一个样本不断变化,置信度在方法*内。*

如果我们一遍又一遍地使用相同的方法,它将产生区间 (可能相同也可能不相同,取决于样本),该区间将包含当时真实总体参数的 95%

在上面的例子中,我们 95%确信从伦敦到爱丁堡的旅行时间在(9.0,10.0)小时的区间内。

常见误解总体参数的值有 95%的机会或可能性或概率位于置信区间内。在本例中,我们 95%确定该值在 9-10 小时之间。这是* 错了!*

相反,这意味着如果通过相同的方法获得更多的样本,那么很可能其中 95%的计算置信区间将包含真实的总体参数——这就是具有 95%置信度的含义。**

影响置信区间的因素

以下是可能影响置信区间宽度的因素:

  1. 置信水*:
    增加置信水*→增加误差幅度→增加 CI 宽度(更宽)
  2. 样本量:
    增加样本量→减少 SE /误差范围→减少 CI 宽度(更窄)
  3. 样本可变性: (可能是我们无法控制的) 样本可变性增加→SE/误差范围增加→CI 宽度增加(更宽)

摘要

  • 人口参数始终保持未知*原样(几乎!)不可能有全部人口的数据。*
  • 我们可以从原始群体的样本中获得数据,并且我们可以利用统计来推断群体参数
  • 来自同一总体的不同样本可能(将)具有不同的样本均值,即样本均值存在一定程度的可变性。

标准误差给出了总体中多个样本间样本的可变性的概念。**

  • 由于样本均值的可变性,我们永远无法估计总体参数(未知)的设定值,更确切地说它很可能存在于可从样本中描述的值的范围内。这个范围取决于我们想要的预先选择的置信度。

低置信度→宽范围→我们不太精确
高置信度→窄范围→我们更精确

  • 标准误差和置信水*产生误差幅度,用于说明样本均值的可变性。它用于构建样本均值两侧的置信区间。

置信区间是值的范围,其可能包含具有一定置信度的总体参数。
—围绕样本*均值构建,并考虑样本的可变性。

置信区间=样本均值+/-误差幅度= [LCL,UCL]

  • *置信区间的宽度随着置信水*的不同而不同:
    • 直接
    • 间接,考虑样本量
    • 直接随着样本的变化而变化(因此也是总体)*

错误解读: 95%置信区间并不意味着*总体参数有 95%的可能会在这个区间内。*

正确解读: 95%的信心指的是对方法的信心。如果使用相同的方法获取 100 个样本,我们将有 100 个不同的 CI,其中 95 个将包括总体参数*。*

对自己对置信区间的理解要有信心!

保持联系..

如果你喜欢这篇文章并且对类似的文章感兴趣的话 在 Medium 上关注我加入我的邮件列表(..如果你已经不是了..)跳上成为 中的一员获取成千上万篇有用的文章。(如果你使用以上链接,我将获得你 50%的会员费)**

..不断学习,不断成长!

使用 Pydantic 和 Hydra 的模型训练实验的配置管理

原文:https://towardsdatascience.com/configuration-management-for-model-training-experiments-using-pydantic-and-hydra-d14a6ae84c13

软件评审、演示

你如何管理你的模型训练实验的配置?您觉得配置管理具有挑战性吗?你考虑过九头蛇吗?Pydantic 怎么样?这篇文章详细介绍了 Hydra 和 Pydantic,以及如何使用它们来简化配置管理。

H 您如何管理模型训练实验的配置?拥有良好的配置管理可以改善用户体验并简化实验管理。拥有一个好的配置解决方案的一些间接优势是干净、可靠和简单的应用程序代码。这对于任何软件应用程序都是如此,但是有些应用程序比其他应用程序需要更高的配置投资。这里的一个关键区别可能是一个有多少配置字段,以及这些字段之间的相互关系。对于深度学习实验来说,这可能会变得非常混乱,在深度学习实验中,配置和超参数的列表可能会在一个人脱离即席实验后迅速增长。

根据定义,模型训练配置是分层的。例如,实验配置可以分解为数据和模型规格。虽然这些是松散耦合的规范,但它们可能会对彼此施加某种程度的限制,例如,模型的输出规范需要与数据规范一致。如果数据源是 MNIST,分类器网络需要输出 10 长度的向量,如果是 PASCAL VOC,需要输出 20 长度的向量。

总的来说,训练实验的配置方案有以下要求:

  1. 能够轻松地将训练实验的各种组件的配置模板化。
  2. 能够以分级方式组织培训配置,承认参与组件的依赖性和层次结构。
  3. 无需重复,通过插值、表达式等方式,在任何需要的地方跨模块重用配置。
  4. 能够使用模板编写配置,并通过覆盖、环境等应用定制。
  5. 能够存储和重用最终组装/编译的配置,并可靠地再现实验。
  6. 支持结构化配置,由潜在的复杂、规范的 python 类型组成,除了类型提示之外还具有强大的验证支持。如果对动态特定领域验证不感兴趣,这可能是可选的——这在 yaml/json 等序列化形式中是无法实现的。
  7. 能够对配置进行版本控制,并根据配置规范实施模式,以实现可靠性和健壮性。
  8. 能够轻松集成到复杂的分布式启动器框架中,用于本地和远程启动。
  9. 一种配置管理,它很好地集成到您的工具的回声系统中,并且不是非常命令式的。

考虑到这一点,我评估了一堆工具,其中一个组合 HydraPydantic 脱颖而出,成为一个不错的选择。在这篇文章中,我将回顾我对这两个工具的学习,并谈谈我仍然看到的差距。最后,针对这一差距提出了一个尝试性的解决方案。该员额的结构如下:

  1. 九头蛇——它的优势,也是我认为它的弱点。
  2. 如何用它来填补九头蛇的空缺
  3. Pydra 配置管理的缺失位,即Hydra&Pydantic
  4. 缩小差距的解决方案
  5. 结论

注:本帖分享的样本和代码可在这里获得。

水螅

Hydra 是一个动态分层配置管理工具,能够覆盖部分配置,也可以通过各种来源(如命令行参数、环境变量)来组合配置。它为模板化配置提供了一个很好的解决方案,可以根据您的目标动态地重新调整。除了重写规则、组合和插值以重新配置模板之外,它还提供了一种以普通的旧 python 对象风格表示配置的机制,并且可以自己处理序列化和反序列化。在一些值得注意的特性方面——使用 hydra,您可以在来自同一个模板源的多个配置实例上触发多进程工作负载。这对于包括并排比较或参数扫描在内的许多用例来说是一个非常方便的特性。

它也是可扩展的,人们可以编写插件来启动本地或远程工作负载。其他一些值得注意的特性是运行器配置和回调。总而言之,由 OmegaConf 提供支持,这是一个非常棒的配置管理工具。

一个简单的非结构化配置示例

让我们看一个简单的使用 hydra 进行基于 yaml 的配置,而不涉及 python 对象模型进行配置。这个例子是从一个九头蛇样本借用并扩展而来的。本例展示了 3 个配置模块,即通过高层 config.yaml 组装在一起的 db、schema 和 ui。

分层 hydra 配置示例。图片由作者提供。

import logging
from dataclasses import dataclass
from typing import List, Optionalimport hydra
from hydra.core.config_store import ConfigStore
from hydra.core.hydra_config import HydraConfig
from omegaconf import MISSING, DictConfig, OmegaConflog = logging.getLogger(__name__) @hydra.main(config_path="conf", config_name="config")
def my_app(cfg: DictConfig) -> None:
    log.info("Type of cfg is: %s", type(cfg))
    cfg_dict = OmegaConf.to_container(cfg, throw_on_missing=False, resolve=True) log.info("Merged Yaml:\n%s", OmegaConf.to_yaml(cfg)) log.info(cfg.db)
    log.info(cfg.db.driver) log.info(HydraConfig.get().job.name) if __name__ == "__main__":
    my_app()

示例代码可以在这里找到

这个脚本中发生的一些事情是:

  • 配置是如何加载的:上面的脚本告诉 hydra 在conf下寻找分层配置作为配置目录的基本位置,在config.yaml下寻找顶级配置规范。这个设置是由 python decorator @hydra.main(config_path="conf", config_name="config")默认的。用户可以覆盖这些设置并将配置位置指向另一个地方,方法是使用--config-dir作为基本目录,使用--config-name作为顶层 config.yaml,如下所示:
python my_app_non_structured.py --config-dir coni_custom_hydra python my_app_non_structured.py --config-name config_hydra
  • 我可以访问什么格式的配置:一旦 hydra 加载了配置,它将作为 dict/dictionary 加载,并作为 OmegaConfDictConfig出现。DictConfig的好处是你可以像变量访问器一样访问字段,比如上面代码中的cfg.db.driver代替了 dict str 键访问模式。
  • 合成来自哪里:在conf目录中定义的是模板配置。有些值可能会丢失——这在 yaml 中可以表示为???。也可以在运行时覆盖模板配置中的一些值。例如:python my_app_non_structured.py db.user=suneeta这里,应用程序将看到的最终使用的配置是:
db:
  driver: mysql
  user: suneeta
  pwd: secret
ui:
  create_db: true
  view: true
schema:
  database: school
  tables:
  - name: students
  - name: exams
  • 我的运行中使用的最终配置是什么:Hydra 将运行中使用的配置细节保存在其输出位置。默认情况下,输出位置为outputs/YYYY-MM-DD/HH-MM-SS/.hydra/config.yaml,可用于重新运行相同的运行以获得再现性。
python my_app_non_structured.py --config-dir=outputs/2022-03-16/13-45-29/.hydra

Hydra 还允许您配置作业和运行设置,这种配置的示例位于这里。或者,也可以在主 config.yaml 文件中覆盖这些设置:

defaults:
  - _self_  # Note: to source default of hydra config 
  - db: mysql
  - ui: full
  - schema: schoolhydra:
  job:
    env_set: 
      HDF5_USE_FILE_LOCKING: "false"
      ## Useful for distributed train setup
      # RANK: ${hydra.job.num}
    env_copy: ## Local environment copy
      - API_KEY    job_logging:
    version: 1
    formatters:
      simple:
        format: "[%(levelname)s] - %(message)s"
    handlers:
      console:
        class: logging.StreamHandler
        formatter: simple
        stream: ext://sys.stdout
    root:
      handlers: [console] disable_existing_loggers: false run:
    dir: outputs/${hydra.job.name}/${now:%Y-%m-%d_%H-%M-%S}
  • Multi-run 和模板:Multi-run 允许用户在相同的配置模板上运行多进程工作负载,但是动态地改变它的一些值。实际上,用户将在不同的配置下运行相同代码的多个进程。参数扫描是一个很好的用例,它会派上用场。在接下来的运行中,multirun正在为学校、支持和仓库的模式触发 3 个不同的流程。
python my_app_non_structured.py db.user=suneeta schema=school,support,warehouse  --config-dir conf_custom_hydra --multirun

每个进程都有一个应用程序可以识别的 int id。索引从 0 开始,如下图所示。

多次运行的示例。图片由作者提供。

这在分布式培训运行中特别有用,在这种情况下,需要知道像过程的等级这样的事情。这可以使用 hydra 作为之后的来轻松配置:

hydra:
  job:
    env_set: 
      RANK: ${hydra.job.num}

使用结构化配置的扩展

如果你的应用程序配置稍微复杂一些,你可能想要配置的对象表示,那么 Hydra 提供了带有ConfigStore的结构化配置选项。这里的就是一个例子。

在这种情况下,您将配置对象模型定义如下:

@dataclass
class DBConfig:
    user: str = MISSING
    pwd: str = MISSING
    driver: str = MISSING
    timeout: int = 100 @dataclass
class MySQLConfig(DBConfig):
    driver: str = "mysql" @dataclass
class PostGreSQLConfig(DBConfig):
    driver: str = "postgresql" @dataclass
class View:
    create_db: bool = False
    view: bool = MISSING @dataclass
class Table:
    name: str = MISSING @dataclass
class Schema:
    database: str = "school"
    tables: List[Table] = MISSING @dataclass
class Config:
    # We can now annotate db as DBConfig which
    # improves both static and dynamic type safety.
    db: DBConfig
    ui: View
    schema: Schema

这里有一些值得注意的事情:

  1. MISSING是表示为???的 yaml 等价缺失的替换。
  2. Hydra 只能处理普通的旧 python 对象,最多只能处理数据类dataclasses的替代物。
  3. 结构化配置不能处理 python 原语,也不能序列化(序列化和反序列化)规范或复杂的 python 对象。甚至没有像 python pathlib Path这样的东西。

一旦配置对象模型完成,应该定义ConfigStore并注册配置对象:

cs = ConfigStore.instance()
cs.store(name="config", node=Config)
cs.store(group="db", name="mysql", node=MySQLConfig)
cs.store(group="db", name="postgresql", node=PostGreSQLConfig)
cs.store(name="ui", node=View)
cs.store(name="schema", node=Schema)

这里,配置注册表中的group键表示互斥的组。关于这些的更多信息可以在这里找到。

hydra injection 如何改变以支持配置存储?不会太多,如这个示例所示,在这种情况下,将DictConfig更改为您的高级配置对象Config就行了。然后,OmegaConf.to_object(cfg)在 python 对象模型中解包 dict config。

@hydra.main(config_path="conf", config_name="config")
def my_app(cfg: Config) -> None:    
    log.info("Type of cfg is: %s", type(cfg))
    cfg_dict = OmegaConf.to_container(cfg, throw_on_missing=False, resolve=True) cfg_obj = OmegaConf.to_object(cfg)

这是应用程序迁移到结构化配置所需做的全部工作,使用以下命令可以探索前面讨论的功能:

python my_app.py
python my_app.py db.user=suneeta    
python my_app.py db.user=suneeta --config-dir conf_custom_hydra
# python my_app.py db.user=suneeta --config-name config_hydra
# Multi-run
python my_app.py db.user=suneeta schema=school,support,warehouse  --config-dir conf_custom_hydra --multirun

代码位于这里

还有另一种方法 Hydra 提供给通过配置实例化对象。这种方法要求用户事先知道哪个配置是可对象的,因为将它们解包成对象需要显式调用instantiate API。这种用法的一个例子如下,请注意配置中的__target__字段中的全限定类名为my_app.Optimizer,这将导致实例化为my_app.Optimizer(algo="SGD", lr=0.01):

实例化对象的示例。图片取自九头蛇文档

在我看来,这个特性应该谨慎使用,因为它将配置与特定于应用程序的对象紧密耦合在一起。这种混合配置处理方法很难维护和理解。

九头蛇的其他一些有趣的特征

插入文字

插值提供了一种引用现有配置而不是复制它的方法。它还允许用户使用通过配置中的字符串插值获得的派生值。插值示例如下所示:

插值的例子。图片取自九头蛇文档。

九头蛇指令

Hydra 允许使用指令覆盖包配置;这些的文档在这里。简而言之,它们提供了动态重写和重定位配置的方法。我认为这是邪恶的,为 yaml 工程提供了便利。如果您打算在标准接口之外使用 config,这也可能是一个调试噩梦。

重写配置规范的指令示例..图片取自九头蛇文档

谈到指令,__global__在管理配置覆盖方面非常方便。这里显示的一个例子是九头蛇样本本身

九头蛇的不足之处。

总的来说, OmegaConfHydra 是两个强大的配置管理工具,但是,我个人发现这些工具有以下缺点:

  1. 不支持 serde(序列化和反序列化)规范或复杂的 python 对象真的很烦人,会给应用程序带来更多开销。退一步说,只有原始支持才是一个好的开始。
  2. OmegaConfHydra 也不支持配置中的Union类型。
  3. 对结构化配置类型的支持仅限于普通的旧 Python 对象或数据类(及其替代物)。
  4. 验证框架是任何配置管理框架中的必备组件。用户提供的任何东西都必须在应用程序中进行验证,比如类型检查、特定于应用程序的验证、约束限制等。这一任务目前主要由应用程序来完成。留给应用程序的选择是使用结构化配置作为简单对象,并显式执行所有验证,包括类型检查等明显的事情。在我看来,这是有局限性的。
  5. 插值是伟大的特性。扩展到这是能够运行基于表达式的插值,如项目列表中的总项目列表。然而,随着问题的提出,九头蛇缺乏这种支持。

Pydantic

Pydantic 提供了一个运行时类型执行和验证,它本身是一个数据验证和设置管理工具。它使用纯规范的 python 数据模型,并为此提供了两种方法:

  1. 数据类替换下降
  2. 基本模型抽象

通过其验证框架和类型检查,pydantic 提供了模式实施,并可以序列化和反序列化各种格式的对象,包括但不限于 yaml/json、xml、ORM 等。它的字段类型支持特别是约束类型非常丰富,极大地简化了应用程序配置验证。例如图像大小可以小于 0 吗?验证这一点的最佳方法是什么?限制是在配置级别定义的,还是分散在使用配置的应用程序中?

总的来说,pydantic 是一个文档完备的库,其 dataclass 用法的一个示例如下图所示:

import logging
import sys
from pathlib import Path
from typing import Optional, Unionfrom pydantic import BaseModel, conint, validator
from pydantic.dataclasses import dataclass log = logging.getLogger(__name__) @dataclass
class Dataset:
    name: str
    path: str @validator("path")
    def validate_path(cls, path: str) -> Path:
        if Path(path).exists():
            print("exist")
        return Path(path) @dataclass
class Model:
    type: str
    num_layers: conint(ge=3)
    width: Optional[conint(ge=0)] @validator("type")
    def validate_supported_type(cls, type: str) -> str:
        if type not in ["alex", "le"]:
            raise ValueError(f"'type' canonly be [alex, le] got: {type}")
        return type @dataclass
class Config:
    dataset: Dataset
    model: Model

注意这里使用的验证器装饰器@validator("type")。这是一种验证特定应用逻辑的方法。

BaseModel 提供了更多的功能,因为它提供了Config内部类的语法糖,可以用来配置 base model 的具体实现的行为。细节可以在这里找到。像anystr_loweruse_enum_values这样的一些设置非常方便。谁不想使用不区分大小写的配置,但又不想让应用程序发生大小写转换呢?比如 bce 和 BCE 的意思和二元交叉熵有什么不同吗?BaseModel 实现如下所示:

class Dataset(BaseModel):
    name: str
    path: str @validator("path")
    def validate_path(cls, path: str) -> Path:
        if Path(path).exists():
            print("exist")
        return Path(path) class Config:
        title = "Dataset"
        max_anystr_length = 10
        allow_mutation = False
        validate_assignment = True
        anystr_lower = True
        validate_all = True
        use_enum_values = True

完整的示例代码位于这里

BaseSettings 也是另一个很棒的特性,它试图抽象出来自环境变量、init 文件等其他来源的设置/配置。

class Secrets(BaseSettings):
    api_key: str = Field("", env="api_key")
    token: str class Config:
        # case_sensitive = True
        env_nested_delimiter = "_" @classmethod
        def customise_sources(
            cls,
            init_settings: SettingsSourceCallable,
            env_settings: SettingsSourceCallable,
            file_secret_settings: SettingsSourceCallable,
        ) -> Tuple[SettingsSourceCallable, ...]:
            return env_settings, init_settings, file_secret_settings

一些有趣的笔记

  1. 有趣的是,pydantic 的验证器可以重新用于实现派生字段。这里的一个例子是:用例是,在另一个模块比如 data 中的 config 中已经提供了一个类列表。您想要在模型配置中由此“推断”类的总数。在这种情况下,您可以从数据模块中插入并复制一系列类到模型中,但是您实际上只关心总类的要求没有实现,因为您还不能进行基于表达式的插入。在这种情况下,total_classes可以被定义为 int 的列表,然后在验证时推导出总数,让您的 in config 对象始终表示总 int 值,并在验证时进行基于逻辑的推导。这方面的例子如下:
from typing import List, Union
from pydantic import BaseModel, conint, validatorclass Model(BaseModel):
    total_classes: Union[conint(ge=0), List[conint(ge=0)]] @validator("total_classes")
    def validate_classes(cls, total_classes: Union[conint(ge=0), List[conint(ge=0)]]) -> conint(ge=0):
        if isinstance(total_classes, List):
            return len(total_classes)
        return total_classes

我还没有看到像这样使用验证器的任何问题,但是不确定这是否是验证器支持的预期用途。此外,不确定为什么验证器在上述接口中返回。

  1. 九头蛇的基准相当有利(见下图)。然而,他们没有对 OmegaConf 和其他一些相关工具进行基准测试,详情见这里的。

九头蛇的基准。图片取自 Pydantic 文档页面

Pydantic 能填补九头蛇的缺口吗

Pydantic 提供了一个强大的验证框架,这是 hydra 所缺少的。虽然直接替换 pydantic 数据类可以与 hydra 一起工作,但人们仍然会错过模型配置的语法糖,仍然会局限于基本类型和非联合类型以及更有趣的 pydantic 约束类型。

公*地说,九头蛇和 pydantic 的直接整合是不存在的。接下来的问题应该是,我们能让它发挥作用吗?当然可以:)。

这里的显示了一个示例,演示了 HydraPydantic 如何结合使用。集成的秘诀在于以下几点:

  1. 放弃使用九头蛇的ConfigStore
  2. 将配置读取为DictConfig并通过 dict 解包到 Pydantic BaseModel 对象

简而言之,这是两行代码:

OmegaConf.resolve(cfg)
r_model = Config(**cfg)

其中ConfigPydantic 的 BaseModel 的具体实现。我们在这里做出的决定是,配置是以 yaml 格式指定的,我们让 Hydra 来管理模板、组合以及非结构化配置管理的所有优点。在解析和合并配置时,我们用 Pydantic 进行反序列化,并获得 Pydantic 验证、检查等所有好处。

这与其他生态系统工具集成得如何

鉴于 hydra 可以提供 dict 格式的最终配置,配置端可以很容易地与关心配置的 echo 系统工具集成。鉴于大多数实验管理和跟踪工具都支持将配置作为 dict 来管理,这不是一个挑战。来自Weights and bias的帖子详细介绍了整合。

有趣的是,Hydra 的其他特性,如 multirun 和 sweeps,由于采用了多进程,可能会干扰其他采用 MP 技术的工具。

版本配置

如果一个人使用大型的、积极发展的代码库,版本控制是非常重要的实践。出于同样的原因,REST APIs 应该被版本化,docker 映像应该被版本化,库版本应该被版本化,等等,应用程序配置规范也应该被版本化。如果不是为了增量更新,那么至少是为了突破性的改变。Kubernetes 实际上做得很好,用户可以带来他们支持的版本的资源规范,它可以与那个版本一起为你创建资源。配置管理比 Kubernetes immplements 复杂得多,但在我看来,这里可以转移的是:

  1. 创建运行时,始终使用最新版本的配置。
  2. 准备好一个支持,您可以将旧配置迁移到最新版本的配置,这样您就可以在需要时使用更新的功能重现[而不是重复]您的实验。

这个原型是一个玩具示例,探索如何处理配置中的版本控制,并在提供旧版本配置时提供一个迁移路径。这里所做的假设是,您的训练代码只能与最新版本的 config 一起工作,因此应用程序代码很简单,并且总是渐进的。每当引入重大变更时,就会创建一个新的浮点版本的 config,而先前版本的 config 会实现到下一版本的迁移路径。

下面显示的代码代表模型配置,它有 3 个版本v,即 1.0、2.0、3.0。每个版本都对前一个版本做出了突破性的改变,但是每个具体的实现都实现了一个“def to _ next(self)->Optional[base model]”方法,该方法在将配置迁移到新规范时会出现问题。

class VersionModel(BaseModel, abc.ABC):
    v: Literal["inf"] = Field(float("inf"), const=True) class Config:
        title = "Model"
        allow_mutation = False
        max_anystr_length = 10
        validate_assignment = True
        anystr_lower = True
        validate_all = True
        use_enum_values = True def version(self) -> float:
        return self.v def _next_version_model(self) -> float:
        versions = list(fake_registry.keys())
        versions.sort()
        idx = versions.index(self.v) + 1
        if idx == len(versions):
            return None
        return versions[idx] def next_version(self) -> BaseModel:
        next_class = fake_registry.get(self._next_version_model())
        return next_class @abc.abstractmethod
    def to_next(self) -> BaseModel:
        pass class Model1(VersionModel):
    # https://pydantic-docs.helpmanual.io/usage/types/#arguments-to-constr
    type: str  # constr(to_lower=True)
    num_layers: conint(ge=3)
    width: Optional[conint(ge=0)]
    # v: float = Field(1.0, const=True)
    zoom: conint(gt=18) = 19
    v: Literal[1.0] = Field(1.0, const=True) # @classmethod
    # def to_next(cls, instance: Type[VBT]) -> BaseModel:
    def to_next(self) -> Optional[BaseModel]:
        next_class = self.next_version()
        if next_class != Model2:
            raise Exception("WTH") d = self.dict()
        d.pop("v")
        return Model2(**d) class Model2(Model1):
    width: conint(ge=5)
    context: conint(ge=256) = 256
    # v: float = Field(2.0, const=True)
    v: Literal[2.0] = Field(2.0, const=True) def to_next(self) -> Optional[BaseModel]:
        next_class = self.next_version()
        if next_class != Model3:
            raise Exception("WTH") return Model3(
            new_context=self.context,
            num_layers=self.num_layers,
            type=self.type,
            width=self.width,
            zoom=self.zoom,
        )class Model3(Model1):
    new_context: conint(ge=512, le=1300) = 512
    v: Literal[3.0] = Field(3.0, const=True) def to_next(self) -> Optional[BaseModel]: return None

配置模板,如这里的所示也被版本化。

让我们来看一下各种场景:

  1. 用户想要运行培训并使用最新配置,他们运行python example.py model=resnet_v3
  2. 一个用户想运行一个培训,并使用最新的配置,但覆盖了一些值,他们运行python example.py model=resnet_v3 +model.zoom=25
  3. 用户想要从旧配置重新运行培训,他们运行python example.py。他们使用 v2 版本的配置,迁移失败,因为 v3 中的字段context要求值大于或等于 512,但 v2 模板中使用的配置是 256。用户收到了关于需要更改配置以使其工作的反馈。
  4. 3 中的同一个用户想要从旧配置中重新运行一个培训,他们运行python example.py model.context=512。它们可以运行,应用程序执行迁移,而应用程序实际上只有模型 3 版本的对象配置。

  5. 我想公开模型配置的模式,我该怎么做:
_Models = Annotated[Union[Model1, Model2, Model3], Field(discriminator="v")]      
_schema = schema_json_of(_Models, title="Model Schema", indent=2)

这将为模型配置生成以下模式:

{
  "title": "Model Schema",
  "discriminator": {
 "propertyName": "v",
 "mapping": {
   "1.0": "#/definitions/Model1",
   "2.0": "#/definitions/Model2",
   "3.0": "#/definitions/Model3"
 }
  },
  "anyOf": [
 {
   "$ref": "#/definitions/Model1"
 },
 {
   "$ref": "#/definitions/Model2"
 },
 {
   "$ref": "#/definitions/Model3"
 }
  ],
  "definitions": {
 "Model1": {
   "title": "Model",
   "type": "object",
   "properties": {
     "v": {
       "title": "V",
       "const": 1.0,
       "enum": [
         1.0
       ],
       "type": "number"
     },
     "type": {
       "title": "Type",
       "type": "string"
     },
     "num_layers": {
       "title": "Num Layers",
       "minimum": 3,
       "type": "integer"
     },
     "width": {
       "title": "Width",
       "minimum": 0,
       "type": "integer"
     },
     "zoom": {
       "title": "Zoom",
       "default": 19,
       "exclusiveMinimum": 18,
       "type": "integer"
     }
   },
   "required": [
     "type",
     "num_layers"
   ]
 },
 "Model2": {
   "title": "Model",
   "type": "object",
   "properties": {
     "v": {
       "title": "V",
       "const": 2.0,
       "enum": [
         2.0
       ],
       "type": "number"
     },
     "type": {
       "title": "Type",
       "type": "string"
     },
     "num_layers": {
       "title": "Num Layers",
       "minimum": 3,
       "type": "integer"
     },
     "width": {
       "title": "Width",
       "minimum": 5,
       "type": "integer"
     },
     "zoom": {
       "title": "Zoom",
       "default": 19,
       "exclusiveMinimum": 18,
       "type": "integer"
     },
     "context": {
       "title": "Context",
       "default": 256,
       "minimum": 256,
       "type": "integer"
     }
   },
   "required": [
     "type",
     "num_layers",
     "width"
   ]
 },
 "Model3": {
   "title": "Model",
   "type": "object",
   "properties": {
     "v": {
       "title": "V",
       "const": 3.0,
       "enum": [
         3.0
       ],
       "type": "number"
     },
     "type": {
       "title": "Type",
       "type": "string"
     },
     "num_layers": {
       "title": "Num Layers",
       "minimum": 3,
       "type": "integer"
     },
     "width": {
       "title": "Width",
       "minimum": 0,
       "type": "integer"
     },
     "zoom": {
       "title": "Zoom",
       "default": 19,
       "exclusiveMinimum": 18,
       "type": "integer"
     },
     "new_context": {
       "title": "New Context",
       "default": 512,
       "minimum": 512,
       "maximum": 1300,
       "type": "integer"
     }
   },
   "required": [
     "type",
     "num_layers"
   ]
 }
  }
}

结论

拥有像 HydraPydantic 这样的工具来简化配置管理和有效处理验证是很棒的。如果 Hydra 也能与 Pydantic 很好地集成就更好了,但至少有一种方法可以一起使用这两种工具。我对版本化配置的想法,以及如何用 Pydra ie Pydantic 和 Hydra 实现它的想法仍在发展中。如果你考虑过替代方案,我会洗耳恭听。

配置一个在 PyCharm 中运行的诗歌环境

原文:https://towardsdatascience.com/configure-a-poetry-environment-that-runs-in-pycharm-eba47420f0b6

Tru“Tru”kat sandeUnsplash 上拍摄的照片

诗歌结构

Python 中依赖性管理和打包的快速简单指南

poems是一个很棒的开源工具,可以减轻设置环境和配置依赖项的痛苦。

在这篇博客中,我将向你略略展示诗歌的能力和其中蕴含的力量。我还将指导您完成在 PyCharm 中配置诗歌环境的技术过程。

与一些现有的依赖管理和打包工具相比,poem 有几个优点(更多细节请参考poem 的介绍一个诗意的道歉)。也许诗歌越来越受欢迎的关键原因可以在下面的引言中找到:

poetry是一个处理依赖项安装以及构建和打包 Python 包的工具。它只需要一个文件来完成所有这些:新的,标准化的 pyproject.toml

换句话说,诗歌用pyproject.toml来代替setup.pyrequirements.txtsetup.cfgMANIFEST.inPipfile

使用诗歌管理 Python 打包和依赖项有许多不同的配置选项。我将在这篇博客中展示的是我认为最方便的配置,它满足了我的所有需求。

装置诗歌

按照 poems 的文档按照你的系统环境安装 poems。

为 PyCharm 安装诗歌插件

对于 PyCharm 版本> =2021.3,无需手动安装插件即可集成诗歌。

对于版本低于 2021.3 的 PyCharm,我们将安装 PyCharm 所需的插件。你可以在下面找到不同 JetBrains IDEs 的诗歌版本列表。

https://plugins.jetbrains.com/plugin/14307-poetry/versions

单击上面的链接后,IDE 中将出现一个弹出窗口,显示如何安装插件的说明。

创建新的诗歌项目

我们现在准备创建我们的新的诗歌环境!在本例中,我将创建一个名为 reviews 的包,用于训练和服务我们的文本分类模型,该模型从租户评论中提取与住宅区生活质量相关的信息( Haber 和 Waks,2021 )。

poetry new reviews

这一步的输出是pyproject.toml文件:

[tool.poetry]
name = "reviews"
version = "0.1.0"
description = ""
authors = ["hai.rozencwajg <EMAIL>"]

[tool.poetry.dependencies]
python = "^3.7"

[tool.poetry.dev-dependencies]
pytest = "^5.2"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

我安装的 Python 版本是*3.7.9*,[tool.poetry.dependencies]下的 Python 版本是^3.7,即等于或大于3.7小于4的 Python 版本。

要阅读更多关于诗歌的符号,如脱字符号(^)和其他版本约束,请参阅诗歌的依赖规范指南。

创建一个诗歌虚拟环境

接下来,我们将通过运行以下命令为这个项目创建一个诗歌环境:

poetry install

这将创建一个本地虚拟环境,用于根据pyproject.toml文件中列出的配置运行项目。

本地环境是在诗歌本地环境~/Library/Caches/pypoetry/virtualenvs的默认路径中创建的。

添加虚拟环境作为解释器

在 PyCharm 中添加 Python 解释器。PyCharm 截图。

在 PyCharm 中点击添加解释器按钮后,自动找到已有的解释器,自动为该项目激活诗歌虚拟环境。

安装 Python 包

类似于著名的pip install命令,诗歌也支持使用诗歌添加命令轻松安装 Python 包。

poetry add google-cloud-storage

运行上面的代码后,一个新的行被添加到记录google-cloud-storage包版本的pyproject.toml文件中。

[tool.poetry]
name = "reviews"
version = "0.1.0"
description = ""
authors = ["hai.rozencwajg <EMAIL>"][tool.poetry.dependencies]
python = "^3.7"
**google-cloud-storage = "^2.4.0"** 
[tool.poetry.dev-dependencies]
pytest = "^5.2"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

此外,还创建了一个poetry.lock文件。该文件跟踪软件包的已安装版本及其依赖项,如下面的日志中所列:

Using version ^2.4.0 for google-cloud-storageUpdating dependencies
Resolving dependencies... (9.7s)Writing lock filePackage operations: 18 installs, 0 updates, 0 removals • Installing pyasn1 (0.4.8)
  • Installing cachetools (5.2.0)
  • Installing certifi (2022.6.15)
  • Installing charset-normalizer (2.1.0)
  • Installing idna (3.3)
  • Installing protobuf (4.21.2)
  • Installing pyasn1-modules (0.2.8)
  • Installing rsa (4.8)
  • Installing six (1.16.0)
  • Installing urllib3 (1.26.10)
  • Installing google-auth (2.9.0)
  • Installing googleapis-common-protos (1.56.3)
  • Installing requests (2.28.1)
  • Installing google-api-core (2.8.2)
  • Installing google-crc32c (1.3.0)
  • Installing google-cloud-core (2.3.1)
  • Installing google-resumable-media (2.3.3)
  • Installing google-cloud-storage (2.4.0)

利用诗歌的力量解决兼容性问题

接下来,我想将google-cloud-bigquery包添加到诗歌中,所以我运行了诗歌添加命令:

poetry add google-cloud-bigquery

但是这一次,我犯了一个错误,这个错误展示了诗歌的力量:

Using version ^3.2.0 for google-cloud-bigqueryUpdating dependencies
Resolving dependencies... (0.2s)SolverProblemErrorThe current project's Python requirement (>=3.7,<4.0) is not compatible with some of the required packages Python requirement:
    - google-cloud-bigquery requires Python >=3.6, <3.11, so it will not be satisfied for Python >=3.11,<4.0

  Because google-cloud-bigquery (3.2.0) requires Python >=3.6, <3.11
   and no versions of google-cloud-bigquery match >3.2.0,<4.0.0, google-cloud-bigquery is forbidden.
  So, because reviews depends on google-cloud-bigquery (^3.2.0), version solving failed.at ~/.poetry/lib/poetry/puzzle/solver.py:241 in _solve
      237│             packages = result.packages
      238│         except OverrideNeeded as e:
      239│             return self.solve_in_compatibility_mode(e.overrides, use_latest=use_latest)
      240│         except SolveFailure as e:
    → 241│             raise SolverProblemError(e)
      242│ 
      243│         results = dict(
      244│             depth_first_search(
      245│                 PackageNode(self._package, packages), aggregate_package_nodes• Check your dependencies Python requirement: The Python requirement can be specified via the `python` or `markers` properties

    For google-cloud-bigquery, a possible solution would be to set the `python` property to ">=3.7,<3.11"[https://python-poetry.org/docs/dependency-specification/#python-restricted-dependencies](https://python-poetry.org/docs/dependency-specification/#python-restricted-dependencies),
    [https://python-poetry.org/docs/dependency-specification/#using-environment-markers](https://python-poetry.org/docs/dependency-specification/#using-environment-markers)

原来在最新版本的google-cloud-bigquery==3.2.0和在pyproject.toml文件中列出的可能的 Python 版本之间有一个兼容性问题。

幸运的是,诗歌也为我们提供了一个可能的解决方案:

对于 google-cloud-bigquery,一个可能的解决方案是将“python”属性设置为“> =3.7,❤️.11"

As we can see above, Poetry instructs us to be stricter about the Python version by limiting to 【 instead of the current setup 【 , so I changed the Python version in 【 file as suggested.

[tool.poetry]
name = "reviews"
version = "0.1.0"
description = ""
authors = ["hai.rozencwajg <EMAIL>"]

[tool.poetry.dependencies]
**python = ">=3.7,<3.11"** google-cloud-storage = "^2.4.0"

[tool.poetry.dev-dependencies]
pytest = "^5.2"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

Now, after re-running the Poetry add 命令用于google-cloud-bigquery包,安装成功结束。

Using version ^3.2.0 for google-cloud-bigqueryUpdating dependencies
Resolving dependencies... (91.8s)Writing lock filePackage operations: 8 installs, 1 update, 0 removals • Updating protobuf (4.21.2 -> 3.20.1)
  • Installing grpcio (1.47.0)
  • Installing grpcio-status (1.47.0)
  • Installing numpy (1.21.6)
  • Installing proto-plus (1.20.6)
  • Installing google-cloud-bigquery-storage (2.14.0)
  • Installing pyarrow (8.0.0)
  • Installing python-dateutil (2.8.2)
  • Installing google-cloud-bigquery (3.2.0)

我们还可以看到protobuf版本被降级(自动)以支持我们所有的版本兼容性约束。

新的pyproject.toml文件现在看起来像这样:

[tool.poetry]
name = "reviews"
version = "0.1.0"
description = ""
authors = ["hai.rozencwajg <EMAIL>"]

[tool.poetry.dependencies]
python = ">=3.7,<3.11"
google-cloud-storage = "^2.4.0"
**google-cloud-bigquery = "^3.2.0"** 
[tool.poetry.dev-dependencies]
pytest = "^5.2"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

其他好吃的

特定软件包版本的安装

pip类似,poems 支持特定包版本的安装:

poetry add pandas~=1.3

仅为开发环境安装包

告别多个requirements.txt文件很好玩。poem 支持在一个文件下管理生产和开发环境。下面我安装了pandas-profiling,仅用于开发环境中的数据探索。

poetry add pandas-profiling --dev

pandas-profiling包将列在[tool.poetry.dev-dependencies]部分下,而不是[tool.poetry.dependencies]下。

卸载软件包

卸载就像添加软件包一样简单:

poetry remove google-cloud-bigquery

打开一个新的外壳,用一个诗歌环境激活它

poetry shell

结论

诗歌是一个伟大的工具,它有许多功能,使你作为一个开发人员能够以一种清晰、简单和透明的方式管理你的依赖关系。使用诗歌有助于环境设置,并有助于解决兼容性问题。

我肯定会在我未来的项目中继续使用诗歌,我希望你也这么想。

【】是一名首席数据科学家在 天际线 ,一家https://www.jll.co.il/*公司和部分*【JLL】科技 任职。我们使用大量多样的信息和尖端技术,为房地产专业人士提供产生独特商业价值的视角。

参考

** * https://www.jetbrains.com/help/pycharm/poetry.html *

Julia 中的共形预测

原文:https://towardsdatascience.com/conformal-prediction-in-julia-351b81309e30

第 1 部分—简介

图 1:两个不同样本的预测集和变化的覆盖率。随着覆盖率的增长,预测集的规模也在增长。图片作者。

构建可信的人工智能系统的第一个关键步骤是对预测不确定性保持透明。模型参数是随机变量,它们的值是从噪声数据中估计出来的。这种固有的随机性贯穿到模型预测中,至少为了避免对模型的过度自信,应该解决这个问题。

除了这种明显的担忧,事实证明,量化模型的不确定性实际上开启了无数的可能性,以改善上游和下游的建模任务,如主动学习和鲁棒性。例如,在贝叶斯主动学习中,不确定性估计用于指导新输入样本的搜索,这可以使地面实况调查任务更有效(Houlsby et al. 2011)。关于下游任务中的模型性能,不确定性量化可用于提高模型校准和稳健性(Lakshminarayanan、Pritzel 和 Blundell,2016 年)。

在以前的帖子中,我们已经看到了如何在贝叶斯环境中量化不确定性(参见这里这里)。因为在贝叶斯建模中,我们通常关心的是估计后验分布,我们得到的不确定性估计几乎是副产品。这对所有的意图和目的来说都是很好的,但是它依赖于对先前分布的假设。就我个人而言,我不反对做出先验分布假设的想法。相反,我认为贝叶斯框架将在模型中整合先验信息的想法正式化,因此为指导科学提供了一个强大的工具包。尽管如此,在某些情况下,这一要求可能被视为过于严格,或者我们可能只是缺乏事先信息。

进入:保形预测(CP)——一种可扩展的频率主义方法用于不确定性量化和覆盖控制。在这篇文章中,我们将介绍 CP 的基本概念。Julia 中的许多实际使用示例应该有助于传达一些直觉,并理想地吸引那些有兴趣为新的令人兴奋的开源开发做出贡献的人。

📖背景

保形预测有望成为一种易于理解、无分布和模型不可知的方法,以生成统计上严格的不确定性估计。这是相当拗口的,所以让我们来分解一下:首先,正如我希望在这篇文章中说明的那样,基本概念确实是相当容易理解的;第二,CP 确实只依赖于最小的分布假设;第三,生成共形预测的通用程序实际上几乎普遍适用于所有监督模型,因此使得该框架非常吸引 ML 社区;最后,CP 实际上具有频率覆盖保证,确保保形预测集包含具有用户选择的概率的真值。对于这个边际覆盖性质的正式证明和对这个主题的详细介绍,我推荐 Angelopoulos 和 Bates (2021)的教程。

在下文中,我们将大致把 Angelopoulos 和 Bates (2021)的教程及其设定的一般框架作为参考。不指望你读过这篇论文,但我也不会在这里重复任何细节。

CP 可用于生成回归模型的预测区间和分类模型的预测集(稍后将详细介绍)。最*也有一些关于共形预测分布和概率预测的工作。有趣的是,它甚至可以用来补充贝叶斯方法。例如,Angelopoulos 和 Bates (2021 年)指出,先验信息应纳入预测集,并证明贝叶斯预测分布如何整合,以符合覆盖的频率主义概念。与之相关的是,Hoff (2021)提出了一种贝叶斯最优预测方法。最后,Stanton、Maddox 和 Wilson (2022)最*提出了一种在贝叶斯优化中引入保形预测的方法。我发现这种结合不同思想流派的工作非常有前途,但是我有点偏离主题了…所以,事不宜迟,让我们看一些代码。

📦Julia 中的共形预测

在关于 CP 的第一篇短文的这一部分,我们将看看如何在 Julia 中实现共形预测。特别是,我们将研究一种方法,它与在 MLJ 可用的许多受监督的机器学习模型中的任何一种兼容:一个由艾伦图灵研究所新西兰战略科学投资基金资助的漂亮、全面的机器学习框架。我们将通过一些基本的使用示例,使用我正在开发的一个新的 Julia 包:[ConformalPrediction.jl](https://github.com/pat-alt/ConformalPrediction.jl)

ConformalPrediction.jl是一个通过保形预测对在 MLJ 训练的机器学习模型进行不确定性量化的软件包。在撰写本文时,它仍处于开发的早期阶段,但已经实现了一系列不同的 CP 方法。非常欢迎投稿:

文档

投稿人指南

分裂共形分类

我们考虑一个简单的二元分类问题。让(Xᵢ,Yᵢ),i=1,…,n 表示我们的特征-标签对,让μ: 𝒳 ↦ 𝒴表示从特征到标签的映射。为了便于说明,我们将使用 moons 数据集🌙。使用[MLJ.jl](https://alan-turing-institute.github.io/MLJ.jl/v0.18/),我们首先生成数据,并分成训练集和测试集:

**using** MLJ 
**using** Random Random.seed!(123) *# Data:* 
X, y = make_moons(500; noise=0.15) 
train, test = partition(eachindex(y), 0.8, shuffle=true)

在这里,我们将使用一个称为分裂共形预测的 CP 的具体情况,然后可以总结如下:

  1. 将训练分成适当的训练集和单独的校准集:𝒟ₙ=𝒟[train] ∪ 𝒟[cali].
  2. 在适当的训练集上训练机器学习模型:μ(Xᵢ,Yᵢ)用于 i ∈ 𝒟[train].
  3. 使用校准数据𝒟[cali]和拟合模型μ(Xᵢ,Yᵢ)为 i ∈ 𝒟[train].计算𝒮的不合格分数
  4. 对于用户指定的期望覆盖率(1-α),计算不一致分数经验分布𝒮.的相应分位数 q̂
  5. 对于给定的分位数和测试样本 X[test],形成相应的保形预测集:C(X[test])=

这是在[ConformalPrediction.jl](https://github.com/pat-alt/ConformalPrediction.jl)中用于分类和回归的默认程序。

你可能想在这里看一下分类案例的源代码(或者下面的 Github 要点)。作为第一个重要的步骤,我们首先定义一个具体的类型SimpleInductiveClassifier,它包装了来自[MLJ.jl](https://alan-turing-institute.github.io/MLJ.jl/v0.18/)的监督模型,并为一些超参数保留了额外的字段。作为第二个步骤,我们定义了训练程序,其中包括数据分割和校准步骤。最后,作为第三个步骤,我们执行上述等式中的过程(步骤 5)来计算保形预测集。

上面的永久链接会带你到本文写作时最新的软件包版本。由于该软件包还处于开发的早期阶段,因此代码库和 API 可能会发生变化。

朱莉娅的简单归纳共形分类。来自[ConformalPrediction.jl](https://github.com/pat-alt/ConformalPrediction.jl).的代码片段

现在让我们把这个带到我们的🌙数据。为了说明包的功能,我们将演示设想的工作流程。我们首先按照标准的[MLJ.jl](https://alan-turing-institute.github.io/MLJ.jl/v0.18/)约定定义我们的原子机器学习模型。使用[ConformalPrediction.jl](https://github.com/pat-alt/ConformalPrediction.jl),我们然后使用标准 API 调用conformal_model(model::Supervised; kwargs...)将原子模型包装在共形模型中。为了根据我们的共形模型进行训练和预测,我们可以再次依靠传统的[MLJ.jl](https://alan-turing-institute.github.io/MLJ.jl/v0.18/)程序。特别是,我们将保形模型包装在数据中(将它变成一台机器),然后在训练集上拟合它。最后,我们使用我们的机器来预测新测试样本Xtest的标签:

*# Model:* 
KNNClassifier = @load KNNClassifier pkg=NearestNeighborModels 
model = KNNClassifier(;K=50) *# Training:* 
**using** ConformalPrediction 
conf_model = conformal_model(model; coverage=.9) 
mach = machine(conf_model, X, y) 
fit!(mach, rows=train) *# Conformal Prediction:* 
Xtest = selectrows(X, first(test)) 
ytest = y[first(test)] 
predict(mach, Xtest)[1]**> UnivariateFinite{Multiclass{2}}**      
     ┌                                        ┐ 
   0 ┤■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 0.94   
     └                                        ┘

最终预测是集值的。虽然SimpleInductiveClassifier的 softmax 输出保持不变,但预测集的大小取决于所选的覆盖率(1-α)。

当指定覆盖率非常接* 1 时,预测集通常会包括许多(在某些情况下是所有)可能的标签。例如,在下面,当将覆盖率设置为等于(1-α)=1.0 时,两个类别都包括在预测集中。这是直观的,因为高覆盖率实际上要求预测集以高概率覆盖真实标签。

conf_model = conformal_model(model; coverage=coverage) 
mach = machine(conf_model, X, y) 
fit!(mach, rows=train) *# Conformal Prediction:* 
Xtest = (x1=[1],x2=[0]) 
predict(mach, Xtest)[1]**> UnivariateFinite{Multiclass{2}}**      
     ┌                                        ┐ 
   0 ┤■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 0.5   
   1 ┤■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 0.5   
     └                                        ┘

相反,对于低覆盖率,预测集也可以是空的。例如,对于(1-α)=0.1 的选择,我们测试样本的预测集是空的。这有点难以直观地思考,我还没有找到一个令人满意的、直观的解释(如果你有,请分享!).当预测集为空时,predict调用当前返回missing:

conf_model = conformal_model(model; coverage=coverage) 
mach = machine(conf_model, X, y) 
fit!(mach, rows=train) *# Conformal Prediction:* 
predict(mach, Xtest)[1]**>** missing

图 1 应该更直观地说明这里到底发生了什么。它说明了所选覆盖率对预测的 softmax 输出和二维特征空间中的集合大小的影响。等高线被月球数据点(包括测试数据)覆盖。以红色突出显示的 X₁和 X₂这两个样本是为了便于说明而手动添加的。我们一个一个来看这些。

首先,请注意 X₁(红十字)属于预测不确定性较高的领域。它正好位于我们零级卫星的右下角🌜(橙色),这个区域几乎完全被我们的一级卫星所包围🌛(绿色)。对于低覆盖率,X₁的预测集是空的:在左侧,这由 softmax 概率的缺失轮廓指示;在右边,我们可以看到相应的集合大小确实为零。对于高覆盖率,预测集包括 y=0 和 y=1,表明共形分类器不确定真实标签的事实。

关于 X₂,我们观察到,虽然也位于我们的零类卫星的边缘,但该样本填充的区域没有被来自相反类的数据点完全包围。在该区域中,可以预期基础原子分类器对其预测更加确定,但是仍然不是非常有信心。这是如何通过我们相应的共形预测集反映出来的?

对于低覆盖率(大约< 0.9),保形预测集不包括 y=0:集大小为零(右图)。只有对于更高的覆盖率,我们才有 C(X₂)={0}:。覆盖率高到足以包括 y=0,但是相应的 softmax 概率仍然相当低。例如,对于(1-α)=0.9,我们有 p̂(y=0|X₂)=0.72.

这两个例子说明了一个有趣的观点:对于以高预测不确定性为特征的区域,保形预测集通常是空的(对于低覆盖率)或大的(对于高覆盖率)。虽然集值预测可能需要习惯,但这个概念总体上是直观的。

图 2:覆盖率对保形预测集的影响。最大软概率显示在左侧。预测集的大小显示在右侧。图片作者。

🏁结论

这真的是保形预测的短暂停留:一个活跃的研究领域,可能值得更多的关注。不过,希望这篇文章有助于提供一些色彩,如果有的话,让你对这个话题更加好奇。让我们回顾一下上面最重要的几点:

  1. 保形预测是一种有趣的不确定性量化的频率主义方法,它甚至可以与贝叶斯相结合。
  2. 它是可扩展的和模型不可知的,因此非常适用于机器学习。
  3. [ConformalPrediction.jl](https://github.com/pat-alt/ConformalPrediction.jl)在 pure Julia 中实现 CP,可用于从[MLJ.jl](https://alan-turing-institute.github.io/MLJ.jl/v0.18/)开始可用的任何监督模型。
  4. 在现有的强大的机器学习工具包上直接实现 CP 向 ML 社区展示了这个框架的潜在用途。
  5. 标准共形分类器产生集值预测:对于不明确的样本,这些集通常很大(对于高覆盖率)或为空(对于低覆盖率)。

下面我将留给你一些进一步的资源。

📚更多资源

你可能已经遇到了令人敬畏的保形预测 repo : Manokhin (n.d .)提供了与保形预测相关的资源的全面、最新的概述。在列出的文章中,你还可以找到 Angelopoulos 和 Bates (2021),他们启发了这篇文章的大部分内容。报告还指出了其他流行编程语言的开源实现,包括 Python 和 r。

参考

安吉洛普洛斯,阿纳斯塔西奥斯 n,斯蒂芬贝茨。2021."保形预测和无分布不确定性量化的简明介绍."https://arxiv.org/abs/2107.07511

霍夫彼得。2021."频率覆盖控制下的贝叶斯最优预测."【https://arxiv.org/abs/2105.14045】T4。

霍尔斯比、尼尔、费伦茨·胡斯扎尔、邹斌·加赫拉马尼和马蒂·朗格耶尔。2011."用于分类和偏好学习的贝叶斯主动学习."https://arxiv.org/abs/1112.5745

拉克什米纳拉亚南、巴拉吉、亚历山大·普里策尔和查尔斯·布伦德尔。2016."使用深度集成的简单和可扩展的预测不确定性估计."https://arxiv.org/abs/1612.01474

马诺欣,瓦列里。"可怕的共形预测"

斯坦顿,塞缪尔,韦斯利·马多克斯和安德鲁·戈登·威尔逊。2022."保形覆盖保证的贝叶斯优化."https://arxiv.org/abs/2210.12496

关于归属,请引用此作品为:

帕特里克·奥特梅尔和帕特里克·奥特梅尔。2022.朱丽亚·🟣的共形预测🔴🟢."2022 年 10 月 25 日。

原载于 2022 年 10 月 25 日 https://www.paltmeyer.comhttps://www.paltmeyer.com/blog/posts/conformal-prediction/

围绕混淆矩阵的混淆指标

原文:https://towardsdatascience.com/confusing-metrics-around-the-confusion-matrix-6ee54e4ed603

理解从混淆矩阵导出的一些混淆分类度量的直观方法

威廉·沃比在 Unsplash 上的照片

动机

“如果你不能衡量它,你就不可能改进它”。

在机器学习和数据科学领域,特别是在统计分类中,“混淆矩阵”通常用于导出一组指标,可以对这些指标进行检查,以提高分类器模型的性能或比较多个模型的性能。

虽然混淆矩阵本身是不言自明的,但通常从它导出的指标很难理解,因为:

  • 指标在多个学科领域有不同的名称
  • 并非所有的指标都与问题的背景相关
  • 没有最佳指标指标,它们每个都提供了不同但有价值的见解。

我们将尝试基于基本概念直观地推导公式,而不是从度量的数学公式开始。

关键假设

为了使我们的解释简单易行,我们假设:

  • 一个二元分类器(有两个输出类)。
  • 分类是硬预测 —分类器的输出是预测它所属的类别,而不是概率和分数。

混淆矩阵是不言自明的

它可能被称为“混淆”,因为它描述了分类器在进行预测时有多混乱——一些类被正确分类,而一些没有。

混乱矩阵——作者图片

定义一个“积极的”类

在从混淆矩阵中探索任何度量之前,要理解的最重要的概念是在给分类器的问题的上下文中“肯定”和“否定”类的真正含义。通常,词语阳性阴性可能会让我们对它们的自然含义感到困惑,但这里重要的是要理解:

阳性类是存在 我们试图检测或预测的

这里有一些例子。这里可以注意到,这些只是对问题的积极类的通常选择;它们可以根据问题的上下文根据需要进行交换。

问题背景下的积极和消极类—作者图片

在问题的上下文中定义 TP/TN/FP/FN

给定对正类的理解,我们可以在问题的上下文中定义 TP,FP,TN 和 FN。这有助于我们清楚地理解从中得出的指标。以下是一些例子:

问题上下文中的预测类-作者图片

定义可以衡量绩效的指标

直观地说,我们希望找出并推导出一个度量标准的逻辑,该度量标准可以测量分类器预测正确类别的频率,或者换句话说,分类器在选择相关项目和消除不相关项目时的准确度有多高。我们问自己:

在所有预测中,正确预测的比例是多少?

数学上,我们可以将其定义为:

准确性公式—作者提供的图像

我们称之为准确性。

某些模型的“准确性”

让我们来看一些例子的准确性度量是如何工作的。我们将使用通过测试一些我们将要比较的模型而产生的混淆矩阵。

混淆矩阵中一些分类器的准确性—图片由作者提供

根据公式,所有这些模型都显示精度= 0.85。然而,这些模型似乎非常不同。模型 2 甚至没有预测任何积极的东西。模型 4 似乎是一个很好的模型,但具有与模型 2 相同的准确性。

很明显,出问题了。

让我们回顾一下准确性度量公式:

准确性公式—作者提供的图像

  • 只要(TP + TN)在具有相同数量的数据点的模型中是相同的(因此分母的值是相同的),精度将是相同的。FP 和 FN 的影响被隐藏,我们失去了宝贵的洞察力
  • 对于数据集中的类别不*衡,计算会偏向较重类别的性能。如果你看到模型 1 和模型 2 的阳性率只有 10%或 15%,那么准确率仍然很高,并且偏向于阴性类的表现。TP(在分子中)和(TP + FN)都很低,这是因为正例的数量很少,因此它们对度量的贡献不如 TN 和(TN + FP)大。

“准确性”的替代方案

如上所述,准确性不能作为评估和比较模型的唯一标准。我们需要制定一些额外的指标,这些指标也可以考虑各个预测类型的贡献——预测积极因素的效果如何,或者预测消极因素的效果如何。因此,让我们在准确度指标之后再添加一些指标。从左至右阅读下表,并说服自己其中的逻辑。

导出额外的度量标准,重点关注各个正面和负面类别

精准还是召回?哪个更好?

这里是我们讨论中最关键的部分——如果只有准确性是不够的,那么我们应该检查哪些指标

答案在分类问题的上下文中—

  • 什么是正课?
  • 我们的重点领域或指标目标是什么?
  • FP 和 FN 哪个错误的预测代价更高(应该避免)?

为了说明,现在让我们专注于精度召回

精确度/召回率及其使用——作者图片

基于上下文的首选指标的几个示例

等等!精确度和召回率也会有异常

就像准确性一样,如果作为感兴趣的单一指标,即使是精确度和召回率也有一些限制—

  • 该模型能够以非常高的召回率预测所有积极的事情。
  • 该模型可以具有非常高的精度,即使它只正确地预测了一个正值,而将所有事物都错误地分类为负值。

下图显示了三个模型,一个是*衡的,一个是召回率高但精度和准确度低的,一个是精度高但召回率和准确度低的。

高精度和高召回率并不总是代表一个好的模型——作者的图像

两全其美——F1 得分

知道精度和召回率都不足以作为评估模型性能的独立指标(每一个都有其自身的局限性),如果精度和召回率的效果都在单个指标中被捕获,那会怎么样呢?一些*均精度和召回。

这样的指标确实存在,并被称为 F1 得分,它被计算为精确度和召回率的调和*均值

F1 分数—按作者分类的图片

但是为什么调和意味着什么呢?

Precision 和 recall 的分子中都有 TP,但分母不同。为了*均它们,*均它们的倒数是有意义的,也就是调和*均值。

由于 F1 分数是精确度和召回率的*均值,这意味着F1 分数给予精确度和召回率同等的权重:

  • 如果精确度和召回率都高,模型将获得高 F1 分数
  • 如果精确度和召回率都低,模型将获得低 F1 分数
  • 如果精度和召回率中的一个较低而另一个较高,模型将获得中等 F1 分数

上面显示的精确度和召回率图表现在扩展到显示 F1 分数。观察与*衡模型相比,高召回率和高精度模型的 F1 值是如何降低的。

与 F1 分数的度量比较—按作者分类的图片

快速回顾一下

  • 需要从上下文中识别正面和负面类别,以解释和评估来自混淆矩阵的度量。
  • TP/TN/FP/FN 需要根据上下文重新措辞。
  • 精度是衡量性能的一个明显但不充分的指标,因为它没有考虑 FP 和 FN 的影响。
  • 精确度和召回率集中于真阳性率;但是精度是基于预测的肯定,而召回是基于实际的肯定。
  • 模型的精度和召回率可能个别较高,但作为独立的指标,它们也不足以用于模型评估。
  • 根据问题的目标,精确和回忆与某些特定类型的问题有各自的相关性。
  • 精确度和召回率是有权衡的——要使用的度量标准取决于错误分类的成本。
  • F1 分数考虑了精确度和召回率的影响。
  • 准确度和 F1 分数可以是最终评估分类器性能的良好指标,尽管还有许多其他指标可以提供有价值的见解。
  • 召回率(TPR)和 FPR 用于评估另一个非常重要的指标——AUC ROC 得分,这对于评估软分类非常重要。但是我们在这里没有涉及软分类;感兴趣的读者可以阅读它了解什么是 TPR 和 FPR。

结束想法

统计世界有更多更微妙的指标。即使不常用于分类器评估,也绝对值得一看。

我希望这篇文章能最大程度地帮助初学者理解分类标准的真正含义,并帮助他们根据真正的直觉而不是填鸭式来决定最好的标准。

请随时建议编辑这个页面,我会很乐意遵守。

快乐学习。

参考资料:

在准备这篇文章的时候,我参考了下面提到的一些很棒的文章和博客。我感谢所有丰富了我知识的作者和投稿人。

https://kiwi Damien . github . io/interview-practice-with-precision-and-recall . html

******【https://en.wikipedia.org/wiki/Precision_and_recall ******

https://data science . stack exchange . com/questions/30881/when-is-precision-more-important-over-recall

https://tryo labs . com/blog/2013/03/25/why-accuracy-alone-bad-measure-class ification-tasks-and-what-we-can-do-about-it

******https://stats.stackexchange.com/questions/424737/is-there-a-name-for-this-metric-tn-tn-fn

https://towardsdatascience.com/the-f1-score-bec2bbc38aa6******

锥形与扁*毛刺咖啡研磨机

原文:https://towardsdatascience.com/conical-vs-flat-burr-coffee-grinders-779539ab6328

咖啡数据科学

零生态位 vs ODE+SSP

a 向朋友借了一首带 SSP 多用毛刺的颂歌,我拍了一系列对拍,对比小众。我对比较*面毛刺和锥形毛刺特别感兴趣。

我没有注意到味道上的巨大差异,而且很难说任何差异是由于研磨分布而不是扁*和圆锥形的一些其他性质的差异。

所有图片由作者提供

我开始比较两者的粒子分布,一旦我拨入颂歌,它或多或少地类似于小生境。它不像我想象的那样是单峰的,部分原因是因为毛刺没有对齐,这是这个实验的主要警告。

设备/技术

浓缩咖啡机 : 像样的浓缩咖啡机

咖啡研磨机 : 小生零同道码SPP 毛刺

咖啡:家庭烘焙咖啡,中杯(第一口+ 1 分钟)

镜头准备:断奏夯实断奏

预输注:长,约 25 秒

输液:压力脉动

过滤篮 : 20g VST

其他设备: Atago TDS 计Acaia Pyxis 秤

绩效指标

我使用两个指标来评估技术之间的差异:最终得分和咖啡萃取。

最终得分 是记分卡 7 个指标(尖锐、浓郁、糖浆、甜味、酸味、苦味和回味)的*均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水*。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。

用折射仪测量总溶解固体量(TDS),这个数字结合咖啡的输出重量和输入重量用于确定提取到杯中的咖啡的百分比,称为提取率(EY)** 。**

【IR】强度半径定义为 TDS vs EY 控制图上原点的半径,所以 IR = sqrt( TDS + EY)。这一指标有助于标准化产量或酿造比的击球性能。****

成对拍摄

我比较了 15 次烘烤中的 29 对照片,这些照片是在烘烤休息的几天里拍摄的。我没有注意到很大的味道差异,但就 EY 而言,*毛边似乎提取得稍微多一些。

********

我通过常规(在这种情况下,断奏捣实,但不是筛过的咖啡)和断奏(三层筛过的)进一步细分。我有 20 个常规镜头对和 9 个断奏镜头对。

还是那句话,我没看出味道有很大区别。EY 似乎略高,但我在杯子里尝不出它的味道。

********

我也看了个人的口味分数,看看颂歌是否有所不同。

我将这些结果按常规和断奏分开,结果似乎是混杂的。

Rich 和糖浆得分的差异在 20 对中没有统计学意义,在双尾对 t 检验中 p 值分别为 0.231 和 0.302,这远远超过了 0.050 的统计学意义。最初的味觉得分差异都不具有统计学意义。

我查看了总体统计数据,EY 刚好超过统计显著阈值。

我敢肯定有更好的*毛刺磨床和圆锥毛刺磨床来比较;这两者的表现非常相似。Ode 在提取率上略有优势,但就味道而言,它们似乎差不多。

如果你愿意,可以在推特、 YouTubeInstagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以关注我在订阅

我的进一步阅读:

我未来的书

我的链接

浓缩咖啡系列文章

工作和学校故事集

如何在 Cloud Composer 上连接到气流工作者

原文:https://towardsdatascience.com/connect-airflow-worker-gcp-e79690f3ecea

在谷歌云*台上连接气流工作者

照片由克里斯蒂安·休姆Unsplash 上拍摄

介绍

Cloud Composer 是 Google 云*台上 Apache Airflow 的托管服务。换句话说,您可以在几秒钟内拥有一个高度可用的气流环境,然后您可以从 GCP 的用户界面进行管理。

显然,它需要连接到集群的气流工作者,以便执行某些任务,例如执行命令或检查工作者的各个方面。例如,如果您想要连接到 Airflow 数据库,那么一旦您连接到集群中的一个 workers,那么就很容易做到。

在今天的简短教程中,我们将详细介绍一个循序渐进的指南,你可以按照这个指南与谷歌云*台上的任何气流工作者建立联系。这非常简单,基本上可以通过四个简单的步骤来完成。

步骤 1:获取您的环境的项目路径和区域

  • 从控制台上的 Cloud Composer 环境中,单击您想要连接的环境。
  • 然后选择ENVIRONMENT CONFIGURATION选项卡
  • 从屏幕上出现的部分,我们将需要项目路径和环境的区域。
  • 前者可以在GKE cluster下找到(会是projects/../../gke的形式)

  • 以及配置中zone条目下的区域

  • 请记下它们,因为我们将在后续步骤中使用它们

步骤 2:获取 Kubernetes 集群的凭证

现在我们需要运行[get-credentials](https://cloud.google.com/sdk/gcloud/reference/container/clusters/get-credentials)来检索运行 Cloud Composer 的 Kubernetes 集群的凭证。

gcloud container clusters get-credentials \
    <project-path> \
    --zone <zone>

一旦您执行了上面的命令,一个带有适当凭证和端点信息的kubeconfig文件将会更新,该文件指向 Google Kubernetes 引擎中特定集群的kubectl

步骤 3:获取正在运行的 Composer 和 Worker 的名称空间

现在,我们需要检索正在运行的 Cloud Composer 实例的名称空间以及我们希望连接到的 Airflow worker 的名称。为此,我们需要运行以下命令。

kubectl get pods --all-namespaces

该命令的输出将——很可能——包含大量用于气流调度器、气流工作器等的名称空间。

  • 从输出中的NAMESPACE列,记下前缀为composer-的云组件实例的名称空间。
  • 此外,请注意其中一个气流工作者的NAME(请注意,输出包含各种气流组件的大量条目,因此请确保选择其中一个气流工作者。名称应该有一个airflow-worker-前缀)。

第四步:连接到气流工作者

最后,现在我们已经有了 Cloud Composer 名称空间和 Airflow worker 的名称,我们只需运行以下命令就可以连接到它:

kubectl exec -itn <composer-namespace> <worker-name> -- /bin/bash

举个例子,

kubectl exec -itn \
    composer-1-10-0-airflow-1-10-15-5983e0fe \
    airflow-worker-8d8c49c87-9v7c4 \
    -- /bin/bash

瞧啊。现在,您已连接到气流工作者。您现在可以运行气流命令(如airflow --version),甚至可以通过运行airflow shell连接到气流数据库。

最后的想法

Cloud Composer 是谷歌云*台上 Apache Airflow 的托管服务,是让数据工程师编写、执行和编排数据管道的最强大的服务之一。

在今天的短文中,我们探讨了连接到 Cloud Composer 集群上的 Airflow Workers 并执行某些命令甚至连接到 Airflow 数据库所需的步骤。

编码快乐!

成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。

https://gmyrianthous.medium.com/membership

相关文章您可能也喜欢

https://levelup.gitconnected.com/ebs-vs-efs-aws-7b3e41c093f7

将数据战略中的点连接起来

原文:https://towardsdatascience.com/connect-the-dots-in-data-strategy-56f65a1e63a5

几年前,我在一家上市公司的新业务部门工作。第一年年末,我和联合创始人一起做年度回顾。一切看起来都很好,直到财务预测显示新业务不会产生管理层从一开始就预期的结果。事实证明,在年度评估之前,没有人把所有的业务数据放在一个地方,并解释它的含义。在接下来的一年,该公司根据年度审查的见解对新业务进行了重组。

后来,我在其他几家不同行业的公司工作过,也发生过类似上述的糟糕决策。大多数时候,它们是片面数据的结果。

数据驱动的战略正在出现,但大图却不见了

许多公司已经意识到数据分析可以成为决策的超级力量。他们雇佣人才并安装数据收集软件来实施数据驱动战略。然而,很少有公司有能力用数据来理解大局。

需要考虑所有维度的数据,以了解业务绩效和潜在的改进。然而,当团队独立地设置目标和度量标准时,没有人组织起来连接度量标准,不清楚每个团队的工作如何相互影响。

例如,营销追求为公司带来流量,产品努力在他们的*台上吸引用户,销售工作则尽可能多地吸引和拓展客户。每个公司都梦想了解哪个客户群转化最多,他们来自哪里,以及如何判断改变不太理想的客户群的行为是否可能以及如何改变。没有一个团队可以单独回答这些问题。

此外,许多公司在测试其与利润的相关性之前使用指标。他们假设哪些指标可能会影响业务,但在 OKR 使用这些指标之前,他们从未采取措施来验证这些假设。

更糟糕的是,许多公司都有数据科学家从一个请求跑到另一个请求。这些安排消耗了数据科学家的脑力,夺走了他们进行战略思考的时间,并阻止他们为公司带来真正的商业价值。

最后,分析软件正在把公司从连接这些点上拖走。如果没有大量的投资,公司很难让第三方软件互相交流,并提供一个商业的大画面。

如何连接数据分析中的点并避免陷阱

第一步是召集数据团队和领域专家一起制定业务流程。数据系统应该是业务流程的“数字孪生兄弟”。为了实现这个目标,团队需要理解在每个节点上跟踪什么。一个简化的 B2C 产品用户旅程如下图所示。

图表 1(图片由作者提供)

在描绘了用户旅程之后,下一步是提出正确的问题。上面的图表中列出了示例业务问题。根据问题,第三步是头脑风暴相关指标,形成假设。例如,为了了解客户来自哪里,团队可能依赖于点击广告、印象和页面访问指标。

接下来,团队需要收集数据,并用可视化或统计方法验证假设。在 OKR 使用这些指标之前,测试它们是至关重要的。否则,指标可能会导致有偏见的投资,比如市场焦点、定价策略等等。

当不同的利益相关者同意度量标准时,团队现在可以构建一个仪表板来监控业务决策如何影响度量标准和利润。桑基图是展示顾客如何沿着管道移动的好方法。

图表 2(图片由作者提供)

当公司创建他们的数据战略时,他们通常在绘制客户旅程和形成假设之前,首先考虑他们需要什么工具。如图 1 所示,全面的数据策略需要复杂的数据堆栈来提供不同的功能。由于数据分析生态系统仍然支离破碎,公司可能需要与十多家供应商打交道来构建数据堆栈。如果公司从评估供应商的每项能力开始,他们可能会很快淹没在信息中,失去大局。因此,建议公司采用自上而下的方法规划其数据战略

最后,公司应该定期检查指标。在一个场景中相关的指标在另一个场景中可能不相关。当业务发展时,指标也应该发展。

要从实践的角度了解更多关于这个话题的信息,你可以参考增强你的货币化——一种引导得分的实用方法。如果你想更深入地讨论数据策略,请联系 Ivy 。要掌握商业策略和分析,请关注我的 Medium。下一篇文章再见。

用 Python 高效地将数据点连接到道路图

原文:https://towardsdatascience.com/connecting-datapoints-to-a-road-graph-with-python-efficiently-cb8c6795ad5f

如何从头开始构建一个函数,然后用 numba 将它加速 80 倍

美国宇航局在 Unsplash 拍摄的照片

一般来说,找到一个给定点的最*的道路是很容易的,但是当我们谈论数百万个点和数千条道路时,事情可能会变得有点复杂。我想告诉你如何从头构建一个这样的函数,然后用 Numba 把它加速 80 倍。

因此,在本文中,我将解决以下任务:

考虑到

-700 万个点,每个点由其经纬度决定
-图中 1 万条道路。道路以 OSMnx 图形的形式存储

去做

对于图中的每条道路,找出这条特定道路距离最*的点的数量。

本质上需要的是将第一张地图转换成第二张地图,但是要有更多的点和街道。

颜色表示与给定街道相关的点数。(图片由作者提供)

不幸的是,给定的任务对于标准的 Shapely 函数来说太重了,所以我们需要定制解决方案。

1.几何学

作者图片

让我们从最简单的方法开始。从坐标原点到两点定义的直线的距离可以用以下公式计算:

作者图片

我们可以用这个公式来计算从任何给定点的距离。要做到这一点,所需要做的就是转换坐标,使给定点在原点结束。

让我们编写一个简单的函数,遍历所有的街道并找到最*的一条。

唯一的问题是,在现实生活中,街道不是无限的,通常由它们的端点来定义。

作者图片

考虑图中的情况。虽然点 A 更靠*第一个线段,但上面的公式告诉我们,点 A 更靠*第二个线段,因为它的延伸线就在点附*。

作者图片

为了消除这些街道,让我们引入一个规则,即从数据点到街道的垂直线必须在其端点之间相交。否则,街道被认为是不相关的。我想指出的是,这条规则相当于要求从数据点到街道端点的线与街道成锐角。第二个要求更容易检查。我们需要做的就是计算代表三角形边的向量的标量积。如果两个向量之间的角度是钝角,则标量积为负,反之亦然。

下面是检查三角形是否是锐角的代码。

我不会从头开始重写整个函数,只显示发生变化的部分。整个功能会在文末呈现。

我猜你已经知道我们将面临的下一个问题。现实生活中不是所有的街道都是直的。考虑下图中的情况

作者图片

我们刚刚开发的算法将第一条线作为最*的一条线返回,而答案显然是第二条线。这是因为当前的方法只考虑了端点,而没有考虑曲率。幸运的是,OSMnx 图还包含街道的几何形状,可以用街道子段的端点坐标序列的形式来表示。

作者图片

现在,要解决这个问题,我们需要做的就是对每条街道的所有子分段进行迭代。

然而,这又产生了一个意想不到的问题。如果某条远处街道的某一段的延续正好位于数据点附*,会发生什么情况?

作者图片

该点将与街道№2 相关联,而它显然属于第一条街道。然而,这个问题可以通过检查每个子线段的三角形是否尖锐来解决,就像我们已经对街道的端点所做的那样。

这涵盖了所有可能导致问题的情况,因此我们可以进入下一部分,效率优化。

2.效率优化

至此,整体算法完成。我们可以添加到函数逻辑中来加速它的唯一方法是检查街道是否太远,如果太远就删除街道。添加一条线后,检查所有端点是否都在一定距离之内,函数如下所示:

不幸的是,经过所有的调整后,计算 700 万个点中每个点的最*街道需要大约一周的时间。我们需要更深入。

我将使用 Numba 库来进一步加速这个函数。它所做的是在运行时使用 LLVM 编译器库将某些 Python 函数翻译成优化的机器代码。唯一的缺点是它不支持动态类型以及一些特定于 Python 的数据类型,如 Pandas 数据框。我故意没有使用不支持的数据类型,所以不会有问题。所以我们所要做的就是指定在加速函数中使用的变量的数据类型。

对于要用 Numba 强制的函数,必须在它之前放置@jit decorator。仅此而已。

现在,为了测试效率增益,让我们加载伦敦市中心的街道图,并生成一千个点。我试着用 Numba 加速和不用 Numba 加速找到所有点最*的街道。结果如下:

  • 不含数字——4 分 27 秒
  • 数字为 0 分 3.4 秒

代码运行速度提高了 80 倍,令人印象深刻。将 700 万个点与街道相关联的初始任务仅用了几个小时就完成了,而不是一周。

我把所有的代码和更多的图片做了一个笔记本。你可以在这个库中找到它。

感谢您阅读文章,希望您觉得有用!

https://vityazevdanil.medium.com/

将 DBeaver 连接到 Google BigQuery

原文:https://towardsdatascience.com/connecting-dbeaver-to-google-bigquery-23c8a12e55b5

利用 JDBC,一步一步

图片来源于unsplash.com

BigQuery Web 界面。作者截图。

从我第一次使用 Google BigQuery 开始,我就觉得有必要连接到本地 IDE,而不是使用 Web 界面。尽管如此,我还是给了使用的时间,心想也许是因为多年使用专业工具像 DataGrip、Toad、SQLDeveloper、SQL Server Management Studio、Workbench J 等,我已经过时了。

也许我没有足够的耐心,或者我是对的,但是无论如何,如果以下任何一个问题正发生在你身上,也许这篇文章会帮助你:

  • 你有没有感觉到 Google BigQuery 的网络界面让你的速度变慢了?
  • 当你知道你的 SQL 是正确的时候,你有一些奇怪的错误信息吗?
  • 您想重用您的代码并拥有一个包含 SQL 的本地文件吗?
  • 你用标签输了吗?
  • 创建新的数据库对象时,是否需要刷新整个页面?

摘要

在本帖中,我们将学习如何使用 JDBC 连接到 BigQuery:

  1. 安装 DBeaver
  2. 了解先决条件
  3. 配置 BigQuery 连接
  4. 测试连接

最后,我将添加感谢结论、有用的资源。

我建议您查看我之前在https://towardsdatascience . com/Run-big query-SQL-using-Python-API-Client-b 5287 AC 05 b 99上发表的关于使用 Python API 客户端运行 big query SQL的帖子,因为它详细介绍了创建和配置服务帐户以及添加公共数据集的步骤。

安装 DBeaver

DBeaver 是面向开发人员和数据库管理员的免费、流行、开源的通用数据库工具。

我选择在以下链接下载并安装 DBeaver 社区版:

[https://dbeaver.io/download/](https://dbeaver.io/download/)

DBeaver 社区安装程序。作者截图。

了解先决条件

要使用 JDBC 连接 BigQuery,您需要:

  • 项目:项目 ID
  • 用户:服务账号邮箱
  • 密钥路径:服务账户密钥文件

项目

项目名称不起作用。您听说您正在寻找项目 ID ,您可以在创建一个项目并选择页面顶部的项目名称后获得它,如下图所示:

项目名称不起作用。您需要一个项目 ID。图片由作者编辑。

用户

您可以通过选择基于用户的认证来使用您的 Google 帐户,但是当您关闭并打开 IDE 时,它会要求您再次登录。作为最佳实践,建议使用服务帐户。

如果不知道如何创建服务账号,可以查看我之前在的帖子 https://towardsdatascience . com/run-big query-SQL-using-python-API-client-b 5287 AC 05 b 99

OAuth 类型,DBeaver 连接。作者截图。

在 DBeaver 中,较新版本不请求用户,但是如果您使用的是旧版本,请注意用户字段正在等待服务帐户电子邮件。你可以进入IAM&Admin→Service Account:

服务帐户电子邮件。图片由作者编辑。

关键路径

密钥路径是指创建密钥时生成的 JSON 文件。如需了解更多信息,您可以查看我之前在https://towardsdatascience . com/run-big query-SQL-using-python-API-client-b 5287 AC 05 b 99上的帖子

添加关键服务帐户。图片由作者编辑。

配置 BigQuery 连接

我们将通过转到文件→新建并选择数据库连接来连接到 BigQuery:

新连接,DBeaver 向导。作者截图。

然后在搜索栏写 bigquery ,选择左边的 All ,选择 Google BigQuery 图标,和下一步按钮:

连接到数据库。DBeaver。作者截图。

对于连接设置,输入项目 ID ,选择服务库,选择 KEY JSON 文件的路径,如果是询问用户字段,则使用服务账户邮箱

连接到数据库。DBeaver。图片由作者编辑。

然后选择左边的测试连接按钮,下载辛巴 JDBC 驱动程序:

下载辛巴 JDBC 驱动程序。DBeaver。作者截图。

测试连接

我们将使用美国名称来测试连接。要添加公共数据集,请遵循我在https://towardsdatascience . com/run-big query-SQL-using-python-API-client-b 5287 AC 05b 99上一篇文章中的步骤

使用以下 SQL 查询并按左侧的播放橙色三角形:

SELECT name, SUM(number) as total_people
FROM `bigquery-public-data.usa_names.usa_1910_2013`
WHERE state = 'TX'
GROUP BY name, state
ORDER BY total_people DESC
LIMIT 20

您将获得以下结果:

使用 DBeaver 的 BigQuery SQL 查询结果。作者截图。

结论

使用本地 IDE 连接 Google BigQuery 有两种方式,一种是使用 ODBC,另一种是使用 JDBC。

我发现与 JDBC 连接可能会令人困惑,如果你不知道该做什么,它会花费太多的时间,这就是为什么我解释了如何配置它,我很确定同样的过程可以与其他支持它的数据库工具一起工作。

请注意,您将失去的一个重要东西是要扫描的卷的可见性:

谷歌大查询图形用户界面。作者截图。

谢谢

给我的妻子戴安娜,她陪伴着我,忍受着我,并推动我继续分享。

有用的资源

https://cloud.google.com/bigquery/docs/reference/odbc-jdbc-drivers https://dbeaver.io/

一致的半监督、可解释的医学成像多任务处理

原文:https://towardsdatascience.com/consistent-semi-supervised-explainable-multi-tasking-for-medical-imaging-aa96abbb3b07

MultiMix:从医学图像中进行少监督、极端多任务学习

我们提出的模型的示意图:MultiMix(图片由作者提供)

在这篇文章中,我将讨论一种新的半监督、多任务医学成像方法,名为 MultiMix ,作者是 Ayaan Haque (me)、Abdullah-Al-Zubaer Imran、王一行和 Demetri Terzopoulos。我们的论文以全论文形式被 ISBI 2021 接受,并在 4 月的大会上发表。我们论文的扩展和改进结果也发表在了 MELBA 期刊上。本文将包括对方法、结果的回顾,以及一个简短的代码回顾。代码可在这里获得。

概述:

MultiMix 通过采用基于置信度的增强策略和为联合任务提供可解释性的新型显著性桥模块来执行联合半监督分类和分割。当完全监督时,基于深度学习的模型可以有效地执行复杂的图像分析任务,但这种性能严重依赖于大型标记数据集的可用性。特别是在医学成像领域,标记昂贵、耗时,并且易于被观察者改变。因此,允许从有限数量的标记数据进行学习的半监督学习已经被研究作为监督学习的替代方法。

此外,在同一个模型中学习多个任务进一步提高了模型的泛化能力。此外,多任务处理允许任务之间的共享表示学习,同时需要更少的参数和更少的计算,使模型更有效,更不容易过度拟合。

我们对不同数量的标记数据和多源数据进行了大量实验,证明了我们方法的有效性。此外,我们还提出了跨任务的域内和跨域评估,以展示我们的模型适应具有挑战性的泛化场景的潜力,这对于医学成像方法来说是一项具有挑战性但重要的任务。

背景:

问题

基于学习的医学成像*年来有所增长,主要是因为深度学习的增长。然而,深度学习的基本问题总是挥之不去,那就是它们需要大量的标记数据才能有效。不幸的是,这在医学成像领域是一个更大的问题,因为收集大型数据集和注释可能很困难,因为它们需要领域专业知识,昂贵,耗时,并且难以在集中式数据集中组织。此外,泛化是医学成像领域中的一个关键问题,因为来自不同来源的图像在质量和数量上可能有很大不同,如果我们想要在多个领域中实现强大的性能,这使得模型建立的过程很困难。我们希望用一些关键的方法来解决这些基本问题,这些方法都是围绕着半监督和多任务学习展开的。

什么是半监督学习?

为了解决有限标记数据问题,半监督学习(SSL)作为一种有前途的方法受到了广泛关注。在半监督学习中,未标记的示例与标记的示例结合使用,以最大化信息增益。在半监督学习方面已经有了很多研究,包括一般的和医学领域的。这些方法我就不详细讨论了,这里列出一些比较突出的方法,有兴趣的可以参考一下[ 1234 ]。

解决有限样本学习的另一个解决方案是使用来自多个来源的数据,因为这增加了数据中样本的数量以及数据的多样性。然而,这样做是有挑战性的,需要特定的训练方法,但如果做得正确,它会非常有影响力。

什么是多任务学习?

多任务学习(MTL)已被研究用于提高许多模型的推广能力。多任务学习被定义为优化单个模型中的多个损失,从而通过共享表征学习来执行多个相关任务。在一个模型中联合训练多个任务可以提高模型的概化能力,因为每个任务都可以相互调整。此外,假设训练数据来自具有有限注释的不同任务的不同分布,多任务在这种情况下对于以几乎没有监督的方式进行学习可能是有用的。将多任务与半监督学习相结合可以提高性能,并在这两项任务中取得成功。同时完成这两项任务可能非常有益,因为不需要经过医学培训的专业人员,一个单一的深度学习模型就可以非常准确地完成这两项任务。

关于医疗领域的相关工作,方法我就不赘述了,这里列举一下:[ 12345678910 。然而,这些工作的主要限制是它们没有使用来自多个来源的数据,这限制了它们的可推广性,以及大多数方法只是单任务方法。

因此,我们提出了一种新的、更通用的多任务模型,称为 MultiMix ,结合了基于置信度的增强和显著性桥模块,以从多源数据中联合学习诊断分类和解剖结构分割。显著图使得能够通过有意义的视觉特征的可视化来分析模型预测。显著图可以以几种方式产生,最显著的是通过从输入图像计算类别分数的梯度。虽然任何深度学习模型都可以通过显著图进行更好的解释,但据我们所知,尚未探索单个模型中两个共享任务之间的显著桥。

算法:

我们提出的方法的示意图(图片由作者提供)

让我们从定义我们的问题开始。我们使用两个数据集进行训练,一个用于分段,一个用于分类。对于分割数据,我们可以使用符号 Xs 和 Y,它们分别是图像和分割遮罩。对于分类数据,我们可以使用符号 Xc 和 C,它们是图像和类标签。

关于我们的模型架构,我们使用基线 U-Net 架构,这是一种使用编码器-解码器框架的常用分段架构。编码器的功能类似于标准的 CNN。为了使用 U-Net 执行多任务处理,我们从具有池化和全连接层的编码器中分支出来,以获得最终的分类输出。

一个标准 U 型网络的示意图(图片来自 Ronneberger

分类:

对于我们提出的分类方法,我们利用数据增强和伪标记。受[1]的启发,我们采用一个未标记的图像,并执行两个独立的增强。首先,未标记的图像被弱增强,并且从该图像的弱增强版本,基于来自模型的当前状态的预测假定伪标记。这就是为什么该方法是半监督的,但我们稍后将更多地讨论伪标记过程。

其次,对相同的精确的未标记图像进行强增强,并且利用来自弱增强图像和强增强图像本身的伪标记来计算损失。本质上,我们教导模型将弱增强图像映射到强增强图像,并且这迫使模型学习诊断分类所需的基本底层特征。两次扩充图像也最大化了从单一图像获得的潜在知识。这也有助于提高泛化能力,就好像模型被迫学习图像中最重要的部分一样,它将能够克服图像中由于不同域而出现的差异。

关于增强,我们对弱增强图像使用传统的增强,例如水*翻转和轻微旋转。强增强策略要有趣得多。我们创建了一个非常规的强大增强池,并对任何给定的图像应用随机数量的增强。这些增强是相当失真的,例如包括裁剪、自动对比、亮度、对比度、均衡、同一性、旋转、锐度、剪切等等。通过应用任何数量的这些,我们创建了非常多种多样的图像,这在处理低样本数据集时尤其重要。我们最终发现,这种增强策略对于强大的性能非常重要。

现在我们回过头来讨论一下伪贴标签的过程。因此,一旦弱增强被转换成伪标签,我们仅在模型生成伪标签的置信度高于调谐阈值时才使用它们。注意,如果模型生成伪标签的置信度高于调谐阈值,这防止了模型从不正确和差的标签中学习。这导致了自由效果的课程,因为当预测在开始时不太自信时,模型主要从标记的数据中学习。随着对未标记图像的标记的生成,模型变得更有信心,结果,模型变得更有效。就提高性能而言,这也是一个非常重要的特性。

现在我们来看看损失函数。分类损失可由以下等式建模:

分类损失方程(图片由作者提供)

其中 L-sub-l 是监督损失,c-hat-l 是分类预测,c-l 是标签,λ是无监督分类权重,L-sub-u 是无监督损失,c-hat-s 是对强增强图像的预测,argmax(c-hat-w)是来自弱增强图像的伪标签,t 是伪标签阈值。

这基本上概括了分类方法,所以现在让我们继续细分方法。

分段:

提议的显著桥的示意图(图片由作者提供)

对于分割,预测是通过具有跳跃连接的编码器-解码器架构进行的,这是非常简单的。我们对分割的主要贡献是整合了一个显著性桥接模块来桥接两个任务,如上图所示。我们使用从编码器扩展到分类分支的梯度,基于模型预测的类别生成显著图。整个过程如上所示,但本质上是一个显著图突出显示了模型使用图像的哪些部分来对图像进行肺炎分类。当可视化时,它们最终看起来类似于分段图,使其成为分段桥的完美补充。

虽然我们不知道分割图像是否代表肺炎,但生成的图突出显示了肺部,以最终分割分辨率创建图像。因此,当用显著图产生和可视化图像的类别预测时,它有点类似于肺掩模。我们假设这些显著图可以用于在解码器阶段指导分割,在从有限的标记数据中学习的同时产生改进的分割。

在 MultiMix 中,所生成的显著图与输入图像连接,被下采样,并被添加到输入到第一解码器级的特征图中。与输入图像的连接允许两个任务之间更强的连接,并且由于它提供的上下文,提高了桥模块的效率。添加输入图像和显著图为解码器提供了更多的上下文和信息,这在处理低样本数据时非常重要。

现在我们来讨论训练和损耗。对于标记样本,我们通常使用参考肺掩模和预测分割之间的 dice 损失来计算分割损失。

由于我们没有未标记分割样本的分割模板,我们不能直接计算它们的分割损失。因此,为此,我们计算标记和未标记示例的分割预测之间的 KL 散度。这不利于模型做出与标记数据越来越不同的预测,而这有助于模型更适合未标记的数据。虽然这是一种计算损失的间接方法,但它仍然允许模型从未标记的分割数据中学习很多。

关于损失,我们的分割损失可以写成:

分割损失方程(图片由作者提供)

其中,α是与分类相比的分割损失权重,y-hat-l 是标记的分割预测,y-l 是相应的掩码,β是无监督的分割权重,y-hat-u 是未标记的分割预测。

我们的模型是在分类和分割损失的组合目标上训练的。既然我们已经讨论了损失,那么就结束了细分方法以及整个方法部分。

数据集:

这些模型被训练和测试用于分类和分割任务,每个任务的数据来自两个不同的来源:一个我们将称为 CheX [ 11 ]的肺炎检测数据集,以及日本放射技术学会或 JSRT [ 12 ]分别用于分类和分割。当我们提到域内数据集时,这是两个数据集。

重要的是,我们在两个外部数据集上验证了模型,每个任务一个数据集。我们使用了 Montgomery County 胸部 X 射线,或 MCU [ 13 ],以及 NIH 胸部 X 射线数据集的一个子集,我们将称之为 NIHX [ 14 。来源的多样性对我们的模型提出了重大挑战,因为图像质量、大小、正常和异常图像的比例以及四个数据集的强度分布的差异都非常不同。下图显示了强度分布的差异,以及每个数据集的图像示例。所有 4 个数据集都有 CC BY 4.0 许可证。

所有数据集的强度分布(左)和分类数据集的示例(右)(图片由作者提供)

成绩:

我们在多个数据集上使用不同数量的标记数据进行了大量实验,包括域内和跨域。

为了说明结果,我们在测试中使用了多个基线,因为我们对模型的每个添加都有一个基线。我们从一个准系统 U-Net 和一个标准分类器(enc)开始,enc 是具有密集层的编码器特征提取器。然后,我们将这两者结合起来,形成我们的基线多任务模型(UMTL)。我们还使用了具有半监督方法的编码器(EncSSL)、具有显著性桥的多任务模型(UMTLS)以及具有显著性桥和所提出的半监督方法的多任务模型(UMTLS-SSL),其基本上是多混合的,没有 KL 发散,用于半监督分割。当然,我们还有 MultiMix。

在训练方面,我们在多个级别的标记数据集上进行训练。对于分类,我们使用 100、1000 和所有标签,对于分段,我们使用 10、50 和所有标签。对于我们的结果,我们将使用符号:model-seglabels-classlabels(例如 MultiMix-10–100)。对于评估,我们使用准确性(Acc)和 F1 得分(F1-N 和 F1-P)进行分类,对于分割,我们使用骰子相似性(DS)、Jaccard 相似性得分(JS)、结构相似性指数度量(SSIM)、*均 Hausdorff 距离(HD)、精确度(P)和召回率(R)。

下图是 MultiMix 在多个基线下的性能表。最好的完全监督分数用下划线标出,最好的半监督分数用粗体标出。

多重混合和基线的定量评估表(图片由作者提供)

该表显示了模型性能如何随着每个新组件的加入而提高。对于分类任务,与基线模型相比,我们基于置信度的半监督学习增强方法显著提高了性能。即使每个任务的标记数据最少,我们的 MultiMix-10–100 在准确性方面也优于完全监督的基线编码器。对于分割,显著桥模块的包含产生了比基线 U-Net 和 UMTL 模型大的改进。即使使用最少的分段标签,我们也可以看到比其对应部分提高了 30%的性能,证明了我们提出的多混合模型的有效性。

我们非常重视泛化的重要性,我们的结果表明我们的模型能够很好地泛化。MultiMix 在两个任务中的泛化能力都有所提高,在领域中始终表现良好。如表中所示,MultiMix 的性能与域内的一样有前途。MultiMix 在分类任务中取得了优于所有基准模型的分数。由于前面讨论的 NIHX 和 CheX 数据集中的显著差异,分数不如域内结果好。然而,它确实比其他型号表现得更好。

显示分割性能分割的骰子分数的方框图(图片由作者提供)

下图是一个箱线图,显示了我们在域内和跨域评估中的分割结果的一致性。我们显示数据集中每个图像的模型的骰子得分。从图中,我们可以看到,与基线相比,MultiMix 是最强的模型。

对照基线的多混合边界可视化(图片由作者提供)

我们将讨论的最后一个数字是我们模型的细分预测的可视化。我们显示了一个预测的边界,为每一个提出的分割任务增加对地面真相在不同的标记数据,在域内和跨域。该图显示 MultiMix 的边界预测与地面真实边界非常一致,尤其是与基线相比时。特别是对于跨领域,MultiMix 是最好的,远远超过其他产品,显示了我们强大的概括能力。

代码审查:

现在我们已经介绍了方法和结果,让我们进入代码。我将主要检查模型架构和训练循环,因为这些是主要的贡献领域。注意,代码是用 PyTorch 和 Python 写的。

让我们先来看看卷积模块。

每个块是一个双卷积块。我们从一个核大小为 3 的 2d 卷积层开始,然后我们使用一个实例归一化层和一个负斜率为 0.2 的 LeakyReLU 的激活函数。然后,我们再次重复这个序列,以完成卷积模块。

现在让我们来看看显著桥。

该代码仅用于生成显著图。我们首先传入输入、编码器和优化器。然后,我们创建图像的副本,以确保图像的梯度不被修改。然后,我们将输入 require_grad 设置为 true,并将编码器设置为 eval 模式。然后我们得到编码器的特征图和输出,这样我们就可以生成显著图。我们首先获得分类输出的最大索引,然后使用。backward()函数来收集渐变。然后,我们通过使用。abs()函数。重要的是,我们必须将优化器的梯度置零,因为使用逆向计算梯度,这在更新模型参数时会有问题。

既然我们已经介绍了体系结构的组件,让我们把它们放在一起,检查整个体系结构。

我们将模型分成独立的编码器和解码器模块,并将它们组合在 MultiMix 类中。对于编码器,我们使用双 conv 模块,每次放大 2 倍。查看正向函数,我们在每个卷积块后保存特征图,用于跳过编码器和解码器之间的连接,我们使用 max-pooling 层来解构图像。然后,我们使用*均池层和密集层为多任务添加分类分支,以获得最终的分类输出(outC)。我们返回所有的特征图以及分类预测供解码器使用。

然后在解码器中,我们使用卷积层来减少特征图,并使用上采样层来重建图像。forward 函数是所有奇迹发生的地方。我们首先将显著图与原始图像连接并堆叠在一起。然后,我们对输入进行下采样,以便它可以与跳过连接一起连接在第一个卷积块中。对于接下来的卷积模块,我们只需执行标准的反卷积,跳过连接即可获得最终输出(out)。

一旦我们建立了模型,我们就可以建立我们的训练循环。这是一段相当冗长且令人生畏的代码,所以不要担心,我们会分解它。

在我们讨论循环之前,注意我们已经省略了许多方法和训练循环来简化它。

如果我们从第 52 行开始,我们从组合所有训练数据集开始,包括监督分割训练集、未标记分割训练集、监督分类训练集、弱增强分类集和强增强分类集。后两者具有相同的精确图像,但只是在不同的级别上被增强。下一组行只是简单地对数据进行基本的拼接和组合,以便所有数据都统一地通过模型发送。

一旦我们将所有输入传递到模型中,我们就将它们全部传递给 calc_loss 函数。在 calc_loss 函数中,我们首先获得基本的监督分类和分割损失(dice 和 lossClassifier)。我们使用骰子损失进行分割,使用交叉熵进行分类。

对于半监督分类,我们首先通过 softmax 函数传递弱增强图像预测以获得概率,然后使用 torch.max 函数获得标签。然后我们使用。ge 函数只保留高于置信阈值的预测,这是方法中讨论的一个重要因素。然后我们计算无监督分类损失(lossUnlabeled)。

最后,我们使用标记的和未标记的分割预测(kl_seg)来计算 KL 散度。所有计算完成后,我们将所有损失乘以各自的权重(λ、α、β)后求和,从而将它们合并成一个损失计算。一旦这被传递回主训练循环,我们简单地用 loss.backward()计算梯度,并用 optimizer.step()更新模型的参数。

代码审查部分到此结束。我们没有过增强和数据处理部分,因为它是相当乏味的。如果你感兴趣,可以在下面的回购处查看完整代码:https://github.com/ayaanzhaque/MultiMix

结论与思考:

在这篇博文中,我们解释了 MultiMix,这是一种新颖的少监督多任务学习模型,用于联合学习分类和分割任务。通过整合一致性增强和新的显著性桥模块以实现更好的可解释性,MultiMix 即使在有限标记数据和多源数据上训练时,也能执行改进和一致的肺炎检测和肺部分割。我们使用四个不同的胸部 X 射线数据集进行的大量实验真实地证明了 MultiMix 在域内和跨域评估中的有效性。我们未来的工作将致力于进一步提高 MultiMix 的跨域性能,尤其是分类性能。我们目前正在准备一个完整的期刊提交,包括更多的结果和工作的扩展。

做这项工作对我来说真的很令人兴奋。作为一名高中生,我很感激有机会与合格和经验丰富的研究人员一起做前沿研究。整个过程对我来说相当具有挑战性,因为我在如何撰写正式的研究论文和进行适当而令人信服的实验方面几乎没有经验。甚至编码和构建实际的附加组件也花费了相当多的时间。我仍然在熟悉 PyTorch,但从事这个项目非常有趣和令人兴奋,我学到了很多关于深度学习和医学成像的知识。我对这次会议感到非常兴奋,有机会见到其他研究人员并了解该领域的新研究,我相信我们未来的工作也会像这个项目一样成功。感谢您的阅读。

如果您觉得本博客或论文的任何部分有趣,请考虑引用:

[@article](http://twitter.com/article){melba:2021:011:haque,
    title = "Generalized Multi-Task Learning from Substantially Unlabeled Multi-Source Medical Image Data",
    authors = "Haque, Ayaan and Imran, Abdullah-Al-Zubaer and Wang, Adam and Terzopoulos, Demetri",
    journal = "Machine Learning for Biomedical Imaging",
    volume = "1",
    issue = "October 2021 issue",
    year = "2021"
}

Python 中的约束编程

原文:https://towardsdatascience.com/constraint-programming-67ac16fa0c81

在 8,080,104 个候选项中找出一个解决方案的编程范例

图片由作者提供,表情符号由open moji(CC BY-SA 4.0)

约束编程是一种技术,找到每一个解决方案,尊重一组预定义的约束。

对于数据科学家来说,它是一个非常有价值的工具,可以用来解决各种各样的问题,比如调度、时间表、排序等等。在本文中,我们将看到如何以两种不同的方式使用 CP:

  1. 可满足性:目标是通过缩小潜在解决方案的大集合来找到一个或多个可行的解决方案(,考虑我们的约束的解决方案);
  2. 优化:目标是根据一个目标函数找到最佳可行解,就像线性规划(LP)一样。

我们将使用来自 Google 的 CP-SAT 或-Tools ,一个优秀的免费开源 CP 求解器。请注意,它与 MPSolver 的不同,MP solver 专用于线性和混合整数编程。CP 和 LP 之间的区别相当令人困惑,我们将在文章的最后触及这个话题。

可以用下面的 Google Colab 笔记本运行代码。

🪖 I. 三个童子军问题的可满足性

图片作者,表情符号由open moji(CC BY-SA 4.0)

上一篇中,我们创造了一支军队来击败对手。但是有一个小问题:我们必须猜测他的军队有多强大。

这次我们就派斥候去了解一下的确切数字。我们的 3 名侦察兵观察了敌营,这是他们告诉我们的:

  • 侦察兵 1:士兵数量是 13 的倍数
  • 侦察兵 2:士兵数量是 19 的倍数
  • 侦察兵 3:士兵数量是 37 的倍数
  • 他们都同意士兵人数不超过一万

我们的侦察兵有一种个人的清点士兵的方法,但是我们可以结合这三种观察做一个模型。

让我们把士兵的数量称为。我们可以将我们的问题转化为以下同余系统:

如果你不熟悉这个符号,这是它在编程术语中的意思:

我们用 OR-Tools 来实现吧。我们需要做的第一件事是导入并创建 CP-SAT 模型和求解器

建模过程与我们在线性编程中所做的非常相似。

创建我们的 CP 模型的第一步是声明变量。在这个例子中,我们只有一个:军队,士兵的数量。

我们必须给出下限和上限。下限是 1,因为我们知道有军队,而上限根据侦察兵的说法是 10,000:

在 OR-Tools 中,我们使用NewIntVar方法来创建这个变量。

第二步是声明约束

在这个例子中,我们确定了三个约束。模是一个特殊的运算符,所以我们需要一个特定的函数用 CP-SAT 来处理:AddModuloEquality。如果你需要其他方法,你可以在这个地址找到参考指南。

不像线性规划,我们这里不用定义一个目标函数

原因很简单:没什么好优化的!我们只想找到一个满足我们约束的可行解,但是没有“好”或“坏”的答案。这是约束编程的一个关键特征。

我们的模型是完成,我们现在可以要求或-工具来解决它。

================= Solution =================
Solved in 0.00 milliseconds🪖 **Army = 9139**Check solution:
  - Constraint 1: 9139 % 13 = 0
  - Constraint 2: 9139 % 19 = 0
  - Constraint 3: 9139 % 37 = 0

我们在不到一毫秒的时间内得到了答案:敌军中有 9139 名士兵。万岁,我们现在可以发射侦察兵了!

我们将搜索空间限制在上限 10000,这给了我们一个唯一解。但是如果我们推这个极限,情况还是这样吗?

CP 的另一个好处是能够找到问题的每一个可能的解决方案。当搜索空间很大时,这可能需要很长时间,因为求解器必须强力搜索整个空间(而不是用试探法减少空间)。让我们通过打印每个可能的解来探索这个特性,每个解都有一个新的上限 100,000

使用 OR-Tools,我们要求求解器根据enumerate_all_solutions参数寻找每一个可能的解。然后我们给它分配一个回调类,打印求解器找到的每个解。

我们找到了 10 种解决方案!这是意料之中的,因为我们将上限提高了十倍:这些解都是 9,139 的倍数。

如你所见,这个例子与优化无关:这是一个纯粹的可满足性问题。另一方面,这个同余系统可以用中国剩余定理手动求解。但是 CP 不仅限于此…

🍻二。优化和啤酒

图片由作者提供,表情符号由open moji(CC BY-SA 4.0)

再来看另一个问题:我军还有几天就要面对敌人了。与此同时,军需官必须准备好战役中要用到的口粮。

补给车的空间有限,一些口粮比其他的更受 T21 人欢迎。有三种可能的配给:

  • 🥖面包:只占 1 个空间但是人气 3 士兵没那么喜欢;
  • 🥩:占 3 格,人气 10;
  • 🍺啤酒:占了 7 个空位但是士兵爱吃,人气 26。

图片由作者提供,表情符号由open moji(CC BY-SA 4.0)

补给车的容量为 19 个车位。如何挑选最好的口粮来使的知名度最大化

这是一个我们已经见过的优化问题:实际上,它是著名的背包问题的变体。我们可以重用前一篇文章中的代码,只需更改输入参数。

这一次,我们将使用约束编程来解决它。这种范式并不局限于寻找可行的解决方案。它还可以使用不同的算法来处理这种开销,从而执行优化。

让我们创建一个问题模型。首先,我们必须声明三个变量:🥖面包,🥩,和🍺啤酒。可以有 0 个,但数量不能超过最大容量。

这一次,我们只有一个约束:面包、肉和啤酒所占据的空间不能超过货车的容量 (19)。

我们希望最大化所选口粮的总受欢迎度:

模型完成,CP-SAT 可以解决问题

================= Solution =================
Solved in 0.00 millisecondsOptimal value = **68 popularity**
Food:
  - 🥖Bread = 2
  - 🥩Meat  = 1
  - 🍺Beer  = 2

我们获得了最高人气 (68)可能容量 19。

约束是否得到尊重?我们赶紧查一下:1×2🥖 + 3×1 🥩 + 7×2 🍺= 19,确实≤ 19。

好的,我想问另一个问题:这个问题有多少种解决方案?再次,我们可以用一个具体的回调来回答它,来统计它们。

121

我们找到了容量为 19 的 121 个解决方案。但是这个数字很快就增加了:容量为 1000,就有8080104个可能的解决方案!然而,CP-SAT 在不到一秒的时间内就找到了最优解。怎么可能呢?

CP 求解器不会用穷举搜索来强力解决问题,而是结合试探法和组合搜索。更具体地说,约束满足问题最流行的三种技术是https://en.wikipedia.org/wiki/Backtracking约束传播局部搜索 。****

CP-SAT 很特别,因为它结合了 CP 和 SAT:它是合并 CP、LP、SAT 和元启发式的更广泛趋势的一部分。

我们说过前面的问题可以用线性编程来解决,所以让我们比较一下两种解决方案的代码:

****

左:LP 码,右:CP 码(图片由作者提供)

如您所见,语法非常相似,但并不相同:模型/解算器与解算器,NewIntVar而不是IntVar,等等。有一点翻译要做,但它很容易管理。

这两种技术非常接*:它们都处理带约束的变量,并使用数学和启发式方法进行优化。然而,CP 仅限于离散参数,而 LP 处理连续参数。另一方面,您可以在 CP 中实现类似于【所有不同】的专门化约束,但在 LP 中却不能。下面总结了这两种技术之间的主要区别:

图片由作者提供,表情符号由open moji(CC BY-SA 4.0)

如果你想了解更多关于这个话题的内容,我推荐 Irvin J. Lustig 的这篇文章和 Jean-Fran ois Puget 的文章。在建模和优化方面,CPLEX 的文档还详细描述了这个地址的不同之处

结论

作者图片

约束编程是数学优化工具箱中另一项令人难以置信的技术。与传统的声明式编程相比,这是一种完全不同的方法。在这篇文章中,

  • 我们看到CP 的两个应用具有可满足性和优化性;
  • 我们在 OR-Tools 中实现了 CP 模型,玩了回调函数;
  • 我们强调了 CP 和 LP 之间的差异

在本介绍中,我们将自己限制在简单的问题上,但是 CP 在复杂的调度和路由问题上有着惊人的应用。这是我想在以后的文章中讨论的话题。

如果你有兴趣了解更多,请随时在 Twitter 上关注我,地址是@ maxime labanne。感谢您的关注!

相关文章

** **

构建关于 Neo4j 云的知识图

原文:https://towardsdatascience.com/construct-a-knowledge-graph-on-the-neo4j-cloud-f8094e7bdbec

如何在 AuraDB 中存储你的 CAZy 知识

我们的世界充满了数据和信息。但是要将它们转化为知识并最终转化为智慧需要付出努力和时间。其中一个关键过程是数据的格式化。合适的格式有助于我们的理解和发现。知识图就是这样一种格式。

知识图是表示特定领域知识的网络。它也被称为语义网络,因为它通过语义关系将不同类型的节点(例如,对象、人或位置)连接成一个网络。即使知识图可以包含不同的东西,但它是直观的,因为它的组织方式类似于我们的思维方式。因此用户可以快速掌握它所代表的内容。此外,它是可视化和可搜索的。因此,用户可以通过交互式浏览网络或通过数据库查询了解具体情况来获得快速概览。

我们正在见证各行各业知识图表的爆炸式增长。它将内容放入谷歌结果页面的信息框中。亚马逊在 Amazon.com、亚马逊音乐、Prime Video 和 Alexa 上使用知识图表。沃尔玛也是如此。这些公司使用知识图表来发现新的见解,提出建议,并开发语义搜索。

在我之前的文章中,我已经写过如何将三张公共医学知识图谱转换成一个名为 Doctor.ai 的聊天机器人。后来,我做了一个 NLP 管道,使用 GPT-3 从原始文本中提取关系(这里的和这里的和)。在本文中,我将使用该管道在 Neo4j 云上制作一个 CAZy 知识图— AuraDB

CAZy 代表Carbohydrate-Aactive enZYmes(CAZy)。它是一个门户网站,提供合成、修饰或降解碳水化合物的酶(CAZymes)的信息(从酶的角度来看,这里的碳水化合物是底物)。一年前,我在 Neo4j 写过一篇关于分析其内容的文章。在这里,我将扩展该项目。我将从公共研究文章中提取底物和酶相互作用,并将其添加到 CAZy 数据中,以形成新的知识图(图 1)。最后,我将创建一个语音聊天机器人前端,以便用户可以用简单的英语查询知识图。聊天机器人是基于我以前的项目 Doctor.ai

图一。CAZy 知识图的构建流程。图片作者。

这个项目的 Python 代码存放在我的 GitHub 库中。

https://github.com/dgg32/cazy_download_for_kg/tree/master

文本提取的 NLP 管道是基于我以前的项目。在这个项目中,我用 CAZy 关系的培训文件更新了存储库。

https://github.com/dgg32/huggingface_gpt3

而聊天机器人前端作为一个名为“cazy_kg”的分支托管在我的 doctorai_eli5 资源库下。

https://github.com/dgg32/doctorai_eli5/tree/cazy_kg

最后,Aura 的数据导入器的数据模型托管在这里。

https://1drv.ms/u/s!Apl037WLngZ8hhB5Ay287gTrOzvh?e=JyYuPJ

1.数据

图二。此项目中的 Neo4j 架构。图片作者。

即使知识图很小,它也由许多小部分组成(图 2)。有四种节点和九种关系。我已经通过网站上的DOWNLOAD CAZY功能下载了最新的 CAZy 数据。请注意,*面文件有质量问题,其内容与 CAZy 网站不完全一致。在这些数据中,我们得到了基因组和 CAZy 节点,以及Genome -[:HAS_CAZY]->Cazy关系。此外,我们可以推断出几个关系:一些 CAZy 模块的共线性和同源性(Cazy -[:COEXISTS]-> CazyCazy -[:RELATES]-> Cazy),亚家族和家族对(Cazy -[:IS_A]-> Cazy,以及 CAZy-底物结合对(Cazy -[:BINDS]-> Substrate)。最后,我收集了四篇示例研究文章,并提取了Cazy-[:DEGRADES]-> Substrate我的 NLP 管道的关系(第 2 节中的描述)。我包括了每个关系的每个信息源的数字对象标识符(DOI)。我还指出了信息来源是主要的(原始发现和想法的报告)还是次要的(基于主要来源的一般作品)。

下载包含 205,462 个基因组和更多的关系。因为自由层光环只允许 50,000 个节点和 175,000 个关系,所以我们需要稍微缩减我们的数据集。在这个项目中,我只保留了拟杆菌门的 650 个基因组。拟杆菌门是一组细菌。它们是生物圈中重要的多糖降解者。他们的大量基因组致力于多糖的分解。像普雷沃氏菌这样的成员是牛、羊瘤胃以及人类口腔和大肠中的常驻生物。其他成员如福尔摩沙Zobellia 在海洋中被发现,它们在那里降解藻类多糖。

除了 CAZy,我们还需要其他数据源来扩充知识图。例如,我从 NCBI 网下载了多糖的本体用于Substrate -[:IS_A]-> Substrate关系。数据包含不同多糖的分组。值得注意的是,有不同的分组方法,每种多糖可以属于多个组。例如,海藻酸是一种藻酸盐。但它也是己糖醛酸、葡萄糖醛酸、等的一员。这里我只考虑 MeSH 中“多糖”的分组。

2.NLP 管道

我已经为这个项目调整了我的 NLP 管道。首先,我为 GPT 3 号提供了新的训练提示。至于引擎,我把text-davinci-002引擎换成了更便宜的text-curie-001,因为令我惊讶的是,后者产生的噪音更少,因此效果更好。我在这个项目中用了两次。首先,它被用来提取三个与 CBM 相关的关系:BINDSCOEXISTSRELATES。然后我用它从示例研究文章中提取出DEGRADES关系。结果不错,但并不完美。所以最后需要少量的手工处理。

受 Tomaz Bratanic 的文章的启发,我还在我的 NLP 管道中添加了实体链接功能。它的任务是消除名词的歧义。例如,维生素 C 和抗坏血酸都会转化为抗坏血酸。在引擎盖下,它使用 NCBI 网格在互联网上进行转换,并缓存结果。该函数在转到 NCBI 之前将首先查询缓存。这带来了两个好处。一方面节省带宽。另一方面,用户可以检查实体链接并进行必要的更改。例如,根据 MeSH,与xyloglucan最相关的命中是xyloglucan endotransglycosylase而不是xyloglucan本身。但是我可以简单地在cache.tsv文件中纠正这个错误,管道将从现在开始返回正确的实体。

3.在 Aura 中创建一个 Neo4j 项目并导入数据

一旦所有文件都准备好了,我们就可以将它们导入到 Aura 中。首先,创建一个空的 Aura 实例(图 3)。在密码管理器中保护您的密码以备后用。

图 3。创建一个空的 Aura 实例。图片作者。

然后,选择Data Importer并将所有 CSV 和 TSV 文件拖到Files面板中。然后创建四类节点:TaxonGenomeCazySubstrate和九类关系(图 4)。你可以在我的链接中找到带有数据的数据模型。

图 4。CAZy 知识图中的模式或数据模型。图片作者。

当一切设置好后,点击Run Import按钮,Aura 将在一分钟内导入所有数据。

4.探索 CAZy 知识图表

导入后,我们可以通过点击Explore按钮打开 Bloom。在 Bloom 中,我们可以自由地探索 CAZy 知识图。例如,我可以用下面的查询可视化所有的BINDS关系。

图 5。CAZy 知识图中的所有绑定关系。图片作者。

在所有六个 CAZy 类别中,只有 CBM 模块具有BINDS关系。这个问题立即清楚地表明,植物中的结构多糖和贮藏多糖形成两个独立的簇。较大的一种由结构多糖组成,如纤维素、木聚糖和葡甘露聚糖。它们在植物细胞壁内非常接*。纤维素、木聚糖和甘露聚糖都通过坚韧的β键连接在一起。因此,我们可以找到如此多的 CBM 来结合一种以上的多糖,这是有道理的。有趣的是,CBM1,2,3,37 和 54 甚至将几丁质连接到簇上。几丁质存在于节肢动物的外骨骼和真菌的细胞壁中。在这个群之外,starch 用 9 个 CBM 建立了自己的群。淀粉是植物中的储存化合物。与上面提到的结构多糖不同,淀粉是通过α键连接的。

我们还可以获得可能降解纤维素的拟杆菌门的列表,因为它们拥有纤维素降解 CAZy 家族,而这些家族又是从四篇研究论文中提取的。因为有 340 个,所以我只展示前 10 个。

第二栏显示是否已知该微生物是纤维素降解菌。“0”代表否定,“2”代表未知。因此,根据菌株描述,列表中的最后两个菌株【algicola 纤维素菌 DSM 14237 和Chitinophaga pinensisDSM 2588 不能降解纤维素。基于这一结果,CAZy 是预测多糖代谢的良好输入数据源吗?在我看来,因为 CAZy 是一个基于序列相似性的系统,它不是代谢功能的直接代理。因此,单一 CAZy 家族的出现是纤维素降解的微弱迹象。但是,如果一个基因组拥有多个家族可以做同样的事情,那么我们就可以更加确定这个预测。但是由于序列相似性很容易计算,这是创建纤维素降解候选列表的良好开端。之后,你可以做实验室测试或搜索文献来确认这些发现。

最后,我们可以计算有多少拟杆菌编码 GH16。这个家族中的许多酶降解海洋多糖,如海带多糖和琼脂。

答案是 71。这是一个令人惊讶的小数字,因为根据之前的研究,北海藻华期间的大部分 GH16 CAZymes 可以追溯到拟杆菌门

5.添加聊天机器人前端

用 Cypher 导航知识图很有趣,但这只是少数会编程的人的特权。然而,我们可以建立一个基于 GPT 3 的聊天机器人(图 6 ),这样每个人都可以访问英语的知识图表。实质上,聊天机器人将自然语言翻译成密码,并从数据库中获得答案。

图 6。CAZy 知识图聊天机器人的体系结构。图片作者。

建立聊天机器人很容易。我们可以借用 Doctor.ai 的代码,只需修改 GPT-3 的提示。令人惊讶的是,通过下面的提示,GPT-3 可以生成正确的密码查询,即使不知道我们的数据模型。

前端托管在 AWS Amplify 上。可以看我之前文章这里这里的说明。您需要填写六个环境变量。REACT_APP_NEO4JURI可能有点棘手。单击您的Instances页面上的实例,您可以在Connection URI旁边找到值。它应该是这样的:

neo4j+s://[random_string].databases.neo4j.io

一旦前端启动并运行,您就可以与聊天机器人进行对话,并通过它从知识图中获得一些答案。

图 7。借用 Doctor.ai 的前端。图片作者。

如图 7 所示,我查询了黄杆菌属的成员基因组。我还询问了能降解淀粉的 CAZy 家族和医生。ai 聊天机器人给了我从研究文章中提取的答案。

结论

绘制自己的知识图表是一种非常令人满意的体验。你基本上是在总结和数字化你特定领域的知识。它是你的个人知识库。当你把它托管在云上,你就可以随时在线查看它的信息。有了基于 GPT 3 的聊天机器人,你可以有效地语音导航知识图表。正如安妮·墨菲·保罗在她的书《扩展的思维中指出的那样,通过卸载我们在外部媒体上的记忆和知识,我们可以释放更多的思维能力来进行创造性思维。因此,知识图表可以帮助我们发现旧数据的新见解。另外,它可以浏览、搜索和共享。您甚至可以设置 GraphQL 或 REST APIs 来向您的同事甚至全世界公开您的数据。

这个项目只是一个引子。我只将可用基因组的一小部分导入 Aura,因为它的自由层对图的大小有限制。你可以用它的专业版来托管一个更大的图。例如,您也可以将其他基因注释(如 MEROPS、KEGG 和 COG)合并到图表中。您还可以创建自己的其他领域的知识图表,如地理、政治和物流。

您还可以使用图形数据科学库(GDS)向现有图形添加更多值。为什么不用图机器学习来预测一些节点属性,比如纤维素降解?然后,您可以将预测结果添加到图表中。

最重要的是,从你的知识图表中获得乐趣。

*https://dgg32.medium.com/membership *

如何使用 Python 对音频文件进行内容审核

原文:https://towardsdatascience.com/content-moderation-python-assemblyai-4a09ca61d346

用 Python 和 AssemblyAI API 检测音频文件中的敏感内容

格伦·卡丽在 Unsplash 拍摄的照片

介绍

在我以前的一篇文章中,我讨论了语音识别和如何用 Python 执行语音到文本转换。当处理音频或视频文件时,有时能够检测到任何敏感内容以便采取某些操作是非常重要的。

例如,您可能想要在播客上执行语音到文本转换,同时您想要检测是否有任何参与者或发言者讨论毒品、色情或酒精(或任何其他可能被视为敏感的内容)。

在今天的教程中,我们将讨论内容审核,以及如何使用 Python 和 AssemblyAI API 检测音频甚至视频文件中的敏感内容。

使用 Python 对音频和视频文件进行内容审核

AssemblyAI API 提供了一个[内容审核功能](https://docs.assemblyai.com/audio-intelligence#content-moderation),允许你执行内容安全检测。在接下来的几节中,将在我们的分步指南中使用它来检测输入文件中是否提到了敏感话题,如果是,则是在何时以及说了什么。API 可以捕捉的一些主题包括事故、灾难、公司财务、赌博和仇恨言论(还有更多的主题,因此如果您正在寻找其他主题,请确保查看包含所涵盖主题详细列表的文档

现在,让我们从一个音频文件开始,我们将对其执行语音到文本转换,同时我们还将启用内容审核功能,以便检测音频文件是否涉及 API 支持的任何敏感话题。请注意,如果您想要遵循这个逐步指南,您将需要来自 AssemblyAI 的一个绝对免费的 API 访问令牌

现在我们有了 API 的访问令牌,让我们做一些必需的导入,并为将发送到 AssemblyAI 端点的请求准备头部。

导入请求库并准备 POST 请求的标题—来源:作者

然后,我们需要读入我们想要执行语音识别和内容审核的音频文件,以便将其上传到 AssemblyAI 的相应托管服务,该服务将返回我们将在后续请求中使用的 URL。

将输入文件上传到 AssemblyAI 的托管服务—来源:作者

既然我们已经将音频文件上传到托管服务,并从端点接收回了upload_url,我们可以继续执行实际的语音到文本任务,将它与敏感内容检测结合起来。注意,为了启用内容审核特性,我们还需要将参数content_safety传递给True

执行语音转文本和敏感内容检测—来源:作者

响应(显示在上面的注释中)将包括已经进行的转录的转录 ID。最后一步涉及使用idGET请求。注意,我们一直发送GET请求,直到响应的状态被标记为completed(或error):

最后,我们将来自转录端点的响应写入一个文件:

将来自转录端点的响应写入文件—来源:作者

解释内容审核输出

我们在上一节中发送给转录端点的POST请求的响应将类似于下面共享的响应。

转录端点返回的响应包括语音转文本和内容安全标签—来源:作者

音频文件的文本转录(即语音转文本的结果)包含在外部text字段中。现在内容安全检测结果将包含在content_safety_labels键中,如下所述:

  • **results**:是包含内容安全检测模型标记的音频转录的所有部分的列表
  • **results.text**:包含触发检测模型的文本转录的字段。
  • **results.labels**:是包含内容安全检测模型为特定转录文本段预测的所有标签(例如disasterdrugsalcohol)的列表。这个列表中的每个 JSONObject 还带有confidenceseverity指标(关于这两个术语的更多内容将在下一节讨论)。
  • **results.timestamp**:表示包含被标记内容的音频文件的开始和结束时间(以毫秒为单位)的字段。
  • **summary**:该键包含results中预测的每个标签相对于整个音频文件的置信度。例如,如果我们以某个特定标签的单一结果结束,比如说0.99置信度,但同时音频文件长达 5 小时,那么 summary 将显示该标签的置信度低得多,因为它在整个音频中没有被广泛使用。
  • **severity_score_summary**:提供results中包含的每个预测标签相对于整个音频文件的整体严重性。

了解严重性和置信度得分

在解释内容安全检测模型给出的结果时,我们遇到了两个评分术语。

事实上,每一个预测的标签都会有其严重性分数和置信度分数严重性分数表示被标记的内容有多严重,分数越低表示内容的严重性越低。另一方面,置信度分数表明模型在预测输出标签时的置信度。注意,它也是以0-1的刻度来测量的。****

例如,考虑我们在 API 响应中观察到的预测的disasters标签的严重性和置信度得分。

"labels": [
    {
        "confidence": 0.9986903071403503,
        "severity": 0.11403293907642365,
        "label": "disasters"
    }
],

0.9986903071403503的置信度指示 AssemblyAI 内容安全检测模型 99.87%确信在指定的timestamp的音频文件的口述内容是关于低严重性的自然灾害(0.1140)。

完整代码

今天教程中使用的完整代码可以在下面分享的 GitHub Gist 中找到。

用于音频转录和敏感内容检测的完整代码—来源:作者

最后的想法

在今天的文章中,我们展示了如何使用 Python 和 AssemblyAI API 对音频或视频文件执行敏感内容审核。相关的 API 端点提供了能够检测敏感内容的功能。

此外,我们讨论了如何解释返回的响应,并检查内容安全检测模型是否标记了输入音频的任何部分。最后,我们解释了如何解释信心和严重性分数以及它们的实际含义。

成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。

https://gmyrianthous.medium.com/membership

你可能也会喜欢

内容安全策略:如何用 Webpack 和 Nginx 创建基于 nonce 的安全策略

原文:https://towardsdatascience.com/content-security-policy-how-to-create-an-iron-clad-nonce-based-csp3-policy-with-webpack-and-nginx-ce5a4605db90

图片来源:Quest Henkart

内容安全政策通过限制不同来源和地点提供内容的方式,帮助防止 XSS (跨站点脚本)攻击。

在本文中,我将提供一个循序渐进的过程,介绍如何实现符合 CSP3 的严格动态 CSP 策略,并使用 Webpack 和 Nginx 正确地应用它来提供静态内容。无论您使用什么样的文件服务器,都可以遵循本指南。

本指南结束时,CSP 评估员会给你一个绿色的 CSP 勾号。

外面的情况有多糟?非常非常糟糕

内容安全政策已经存在很多年了,但是互联网上关于如何实际实施它的文档和指南少得惊人。事实上,要了解在线社区对 CSP 的理解有多差,只需在谷歌 Chrome 上下载“CSP 评估器”扩展并四处浏览。

你会注意到什么?首先,在这个网站上,你会看到媒体有一个脚本 src 策略‘unsafe-eval’‘unsafe-inline’关于:https:‘self’。基本上这个政策和没有政策是一样的。它允许任何资源(只要是 https)通过 eval 将字符串作为代码注入该网站,从而将 medium.com 暴露给 XSS 攻击和其他攻击媒介。

白名单、白名单和更多白名单

CSP1 和 CSP2 规范提供了白名单的概念。这意味着在一个页面上提供或显示的每一个域都必须在 CSP 策略中列入白名单。最终结果是难以置信的长白名单,很难或者不可能管理和更新。

它们也不安全。还有大量的 CSP 绕过和 JSONP 的使用,JSONP 在 youtube 和 angular 库中很流行,可以用来注入来自看似可信来源的脚本。事实证明,正如这篇著名的研究论文中所表达的那样,这并不罕见,这篇论文激发了 CSP3 中严格动态的产生

严格动态:一种更简单更安全的方式

严格动态由 W3C 提出,此后被除 Safari 之外的所有浏览器采用, Safari 可能会将它包含在下一个主要版本中,不幸的是,这个版本每年发布一次。它去掉了 script-src 白名单的要求,代之以一个加密随机数。事实上,使用严格动态,所有白名单项目都会被忽略,只要浏览器接受严格动态,否则就会使用白名单项目。相反,严格动态将允许任何脚本,只要它匹配包含的加密随机数或散列。

Nonce 和现有 Webpack 模块的故障

为每个页面加载唯一生成 nonce 是至关重要的。这是不可猜测的。只要随机数是随机的,严格动态就会阻止 XSS 攻击。如果随机数是确定性的或静态的,那么它是无用的,并且违背了 CSP 策略的目的。这就是为什么你应该 100%避免使用 Slack 的 Webpack 模块用于 CSP,它不起作用,也不会保护你的网站。避免它。他们可能会在某个时候更新它以创建随机随机数,但目前构建它的方式排除了这种可能性,因为它只能在构建时而不是运行时创建随机数。

在这个问题上你也可能碰到谷歌的尝试。相反,它们在构建时自动散列源文件,并在 html 元策略中提供该散列。虽然这实际上是一种安全的方法,但当您仍然需要在应用程序中使用 webpack 不支持的其他脚本时,它将会失败。一旦你在你的网络服务器上添加了一个基于随机数的策略,它将与谷歌的策略相冲突,因为他们用来注入散列的脚本将被拒绝。

虽然 HTML 元页面中允许 CSP 策略,但是不可能在那里设置 report-uri。这意味着当用户遇到故障时,将没有日志记录系统,它将无声地失败。因此,通常建议使用来自 web 服务器的内容安全策略头。

游戏攻略

定义策略

default-src 'self';
script-src 'nonce-{random}' 'strict-dynamic' 'unsafe-inline' https:;
object-src 'none';
base-uri 'self';
report-uri https://example.com/csp

这应该是起点。严格动态只适用于 script-src 条目。这意味着你仍然需要将其他条目列入白名单。所有不存在的条目都将退回到 default-src,如果它们是从不同的域提供的,您将会看到一个错误。点击这里查看所有可用条目。您还可以考虑在 script-src 上添加回退白名单条目,以覆盖 Safari 用户,直到下一个版本(在这种情况下,任何域都将被允许提供内嵌内容,只要它们来自 Safari 上的 https 源,不是很安全,白名单会更好)。对于其他浏览器,只有 nonce-{random}和 strict-dynamic 是必需的,其余的将被忽略。

将随机数占位符添加到 html 模板中

现在我们需要在每次页面加载时设置一个新的 window.nonce,这样它就可以应用于所有 webpack 生成的脚本和包。为此,我们创建了一个任意格式的占位符,在本例中,我选择了CSP_NONCE。注意,围绕 window.nonce 的脚本也需要占位符,否则它将被严格动态策略拒绝

<!DOCTYPE html>
<html>
  <head>
    <title><%= htmlWebpackPlugin.options.title %></title>
    <script nonce="**CSP_NONCE**">
       window.nonce = "**CSP_NONCE**";
     </script>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

应用 CSP 策略并填充随机数占位符

接下来我们跳到 Nginx,在这里我们创建一个变量并将其应用到头部。我使用了一个变量,因为它允许我按部分组织 CSP 头,它还允许我轻松地将开发 CSP 和生产 CSP 分开,由于 http/s 和 devtools 的原因,它们的需求略有不同。在我的真实项目中,它看起来像这样:

"'nonce-r@ndom' ${defaultsrc} ${imgsrc} ${connectsrc} ${stylesrc} ..."

然后,我们需要实际上把' nonce-random '变成一个密码随机字符串。幸运的是,nginx 提供了开箱即用的‘$ request _ id ’,这在 CSP 策略中是这样的

'nonce-$request_id'

server{
  set csp "script-src 'nonce-$request_id' 'strict-dynamic' 'unsafe-inline' https:; object-src 'none'; base-uri 'self'; default-src 'self'; report-uri https://example.com/csp"
..
..
location / {
  ..
  add_header Content-Security-Policy "${csp}"
  try_files /path/to/index.html =404;
}

服务内容呢?Nginx 不是一个支持模板的文件服务器,大多数信息都建议使用第三方节点服务器来处理模板。但其实 nginx 支持这个就好。它不是默认模块,所以您需要确保已经使用。" —带-http_sub_module" 配置。如果使用官方的 nginx docker 容器(或 openresty),默认情况下会包含它。

既然我们已经启用了 sub_module,我们就可以添加 sub_filter 附加物了

add_header Content-Security-Policy "${csp}"
sub_filter_once off;
sub_filter ‘**CSP_NONCE**’ $request_id;
try_files /path/to/index.html =404;

sub _ filter _ once off 导致 nginx 替换占位符的多个实例。这是至关重要的,因为我们既需要将它应用于脚本标记,也需要将其设置为变量。另一个命令用 CSP 策略中列出的相同 request_id 替换CSP_NONCE的所有实例

webpack_nonce 隐藏功能

webpack_nonce 是 webpack 的一个神奇的、可怕的文档化功能,它实际上做得很好。只不过实际应用起来需要大量的黑客攻击。

它必须放在 Webpack 设置中指定的条目文件(通常是 index.js)的顶部。第一行应该是这样的:

__webpack_nonce__ = window.nonce

这个特定的方法神奇地打开了 Webpack 中的一个特性集,该特性集将随机数应用于运行时加载的所有脚本。它实际上工作得很好。将这个变量放在任何其他地方都会导致它不起作用。index.js 的第 1 行!

成功!开玩笑的。现在让我们修改 webpack

为什么不管用?如果您应用一个基于随机数的 CSP 策略,那么自动生成的、实际加载条目文件的脚本将永远无法运行,因为…您猜对了..它不是 nonced。Webpack 仅在加载条目文件后应用随机数,无法将其应用于加载条目文件的脚本。但是不要担心,我们有一个解决方案。

在这一点上,你应该使用 Nginx 提供一个可靠的 CSP3 策略,在应用到你的 index.html 文件的每个页面负载上创建一个新的随机随机数。如果您在浏览器的 devtools 中查看网页或源代码,您会注意到 index.html 页面已经用 CSP 报头中提供的相同 NONCE 替换了CSP_NONCE。太棒了。你也可以通过 window.nonce 在你的应用中的任何地方访问随机数。这不是一个安全问题,因为攻击向量需要黑客在提供随机数之前知道随机数

所以在这一点上,你可能会问为什么你看着一个白色的屏幕?

正如我之前提到的,webpack_nonce 只是部分完整的实现,这可能是 Slack 和 Google 试图创建他们自己的解决方案的原因。由于 webpack_nonce 只能在入口文件中设置,而不能在 index.html 文件中设置,除非 nonce 应用于外部脚本,否则如何加载入口文件呢?如果使用包分割和/或块,情况会更复杂。不幸的是,html-webpack-plugin 没有这个功能,所以我们被困住了。

自定义插件

在您的 webpack.config.js 文件中,我们需要创建一个新的自定义插件,它从 html-webpack-plugin 获取一个钩子,并将CSP_NONCE占位符注入到每个脚本标记中。魔力来了

var HtmlWebpackPlugin = require("html-webpack-plugin")class NoncePlaceholder {
  apply(compiler) {
    compiler.hooks.thisCompilation.tap("NoncePlaceholder", (compilation) => {HtmlWebpackPlugin.getHooks(compilation).afterTemplateExecution.tapAsync(
        "NoncePlaceholder", 
        (data, cb) => {
          const { headTags } = data
          headTags.forEach((x) => {
            x.attributes.nonce = "**CSP_NONCE**"
          })
          cb(null, data)
        }
      )
    })
  }
}var html = new HtmlWebpackPlugin({
  title: "title",
  template: "index.ejs",
  filename: "index.html",
})const config = {
   ...
   ...
   plugins: [html, new NoncePlaceholder()]
}

这个非占位符自定义插件现在将向 index.html 文件中的每个脚本注入一个 nonce="CSP_nonce ",允许它被 nginx 子过滤器覆盖并转换为允许的 NONCE

第三方脚本呢?

由于 nonce 存在于 window.nonce 中,因此您可以将该 nonce 应用于应用程序中的任何脚本。例如,对于谷歌标签管理器,你可能有

googleTagManager.setAttribute(“src”,“[https://www.googletagmanager.com/gtag/js?id=](https://www.googletagmanager.com/gtag/js?id=)" + id)googleTagManager.setAttribute(“nonce”, window.nonce)

您需要将 window.nonce 作为 nonce 属性应用于任何导入的脚本或跟踪器。

其他指令

当您应用 nonces 来允许第三方脚本运行时,您会注意到大量的 CSP 错误。例如,Google Analytics 需要 img-src 和 connect-src 中的白名单条目。CSP3 中的严格动态没有涵盖这些内容。在 W3C 的下一个草案出台之前,我们仍然需要将所有其他指令列入白名单。对于谷歌,你可以遵循他们的指南,了解哪些东西需要列入白名单。对大多数人来说,他们完全没有文档,你只需要测试功能,看看什么需要被列入白名单。这也是 report-uri 如此重要的原因之一。

但是不要把你看到的所有错误都列入白名单!并不是所有的功能都是必要的,尤其是谷歌的服务,否则 Meta 会不断试图用追踪器入侵你的网站。您的 CSP 头将保护您的用户免受这种影响,只有白名单的最少领域,你可以实现你想要的功能。

最后的想法

为什么会这么复杂?为什么 webpack_nonce 不能被更好地记录?为什么不能在 index.html 文件中应用它,这样入口文件就可以加载,而不是自己失败?为什么大多数网站的 CSP 政策不完善?为什么行业领导者创建的 webpack 插件会导致人们创建不安全的策略?为什么 html-webpack-plugin 不允许我们设置 nonce 属性?这里有很多开源的机会。但是在花了一个多星期在本应该花几个小时的事情上之后,我希望这篇博客文章能帮助人们走上正确的道路,并实施一个坚实的 CSP3 政策

Python 中基于模糊逻辑的内容标注

原文:https://towardsdatascience.com/content-tagging-with-fuzzy-logic-in-python-d9041c572cac

学习如何使用一个简单的脚本用模糊逻辑标记文本内容

图片作者。

术语模糊逻辑指的是所有那些应用基于真理*似值的启发式规则和功能。

在计算机科学中,模糊逻辑是为了帮助提供一个真实度,而不是真实的真实度。这种方法允许我们不准确地回答同样不精确问题。

模糊逻辑的一个例子

假设我们被问及年龄,但是在形式上

你年纪大吗?

让我们从逻辑的角度来看这个问题:

  • 如果我们是 5 岁,我们可能不算老
  • 如果我们 70 岁了,我们可能会被认为是老了
  • ……但如果我们 50 岁了,我们该怎么回答?

模糊逻辑这样回答:

是也不是。

虽然传统逻辑只以两种状态来表达自己,即真和假模糊逻辑想要填充之间的内容,提供真度而不是布尔表达式。

回到上面的例子,按逻辑类型分解问题,我们会得到问题的答案:你是老年人吗?

假设我们实际上可以活到 75 岁,

传统逻辑:年龄> 75 岁为真;否则为假
模糊逻辑:年龄/ 75%资深。因此,如果我们 70 岁,那么根据模糊逻辑,我们将有 93%的年龄。

对于我们的分析师来说,模糊逻辑成为一种工具,用于关联、区分或分组由测量定义的元素。

使用模糊逻辑进行标记/分类

在本文中,我将介绍使用 Python 中的模糊逻辑对文本内容进行标记或分类。我将使用来自我的意大利语个人博客(diariodiunanalista.it)的内容。

使用 Levenshtein 距离 作为评估系统,我们将使用模糊逻辑将一篇文章与一个或多个预定义的标签相关联。

Levenshtein 距离是一种常用于评估两个字符串之间差异的度量。它计算字符串 A 变成字符串 b 需要多少个字符。

一个例子:
-字符串 A: foo |字符串 B:fii
Levenshtein 距离:2

事实上,需要对 A 进行两次编辑才能将其转换为 B (oo -> ii)。

如果读者对字符串操作及其主要应用感兴趣,即自动校正,我建议阅读这篇文章,它解释了自动校正模型如何工作

我们的模糊逻辑系统将基于一个名为Fuzz的库,它涵盖了我们的用例。

我们要做什么?

经常阅读我的内容的读者会知道我使用一段时间前创建的脚本从在线博客创建语料库。我将使用它来从 Diario 安迪 Analista.it 检索文章,并尝试用我们的模糊逻辑系统来标记它们。

通过这个小项目,我想让读者能够根据预定义的标签标记任何文本内容。

由于这种方法不是基于预测模型,我们需要为软件提供我们希望应用于文档的标签。

这种方法比基于预测模型的方法更有优势。一个模型可能会推断出不准确的标签,这可能不符合我们心目中的标准。

通过预先定义标签,我们可以确保标签与我们的意图一致。当然,我们可以也一定会看到错误,但它们会更容易管理。

要求

只有两个要求:熊猫和绒毛。

pip install pandas thefuzz

标签创建

我们将要应用的函数需要一个参考才能工作。为此,我们将创建一个名为tags的列表,其中包含我们希望应用于文档的标签。

导入数据集

使用上面链接的 blog scraper,让我们创建一个包含两列的数据集:url 和文章。

文章数据框架示例。图片作者。

这是我们的语料库。在写这篇文章的时候,大约有 30 篇文章——因此它是一个非常小的语料库。对于我们的例子来说,它仍然是好的。

标签功能

我们现在将编写代码来使用模糊逻辑应用标记。算法是这样工作的:

  • 在标签间循环
  • 对于每个标签,使用 Fuzz 的 process.extract 提取一组代表该标签的文章,按分数排序
  • 对于前面输出的每个元素,在 Python 字典中构建数据,并创建一个 Pandas 数据帧
  • 收集完所有的数据帧后,用连接将它们连接起来

让我们写函数

应用标记功能

让我们通过运行编写的代码来查看标记结果

标记数据集。图片作者。

正如我们所见,标记并不完美,但大多数结果实际上是一致的。

当一个页面属于多个类别时,如 Python 中的第 3 行时序聚类用于股市预测即属于聚类progetti 标签。

也有男的。这很正常。一篇文章可能不与大于为某个标签建立的阈值(在我们的例子中是 55)的阈值相关联。在这种情况下,没有标签与内容相关联,因此分配 NaN。改变置信度阈值将有助于产生或多或少的结果。

结论

我们已经看到了如何使用模糊逻辑和 Pandas 数据框架在 Python 中标记内容。

这是一个小项目,但它可以在工作场所产生重要的影响。在数据集上手动应用标签可能需要几个小时。这是自动化这些任务的一种简单而有效的方法。

下一步

在这个例子中,我使用了文章的正文。这是一个任意的选择,但是举例来说,你可以对文章的标题或者元描述做同样的事情。如果这些文本是主题的代表,我们的系统可以工作得更好!自己试试:)

如果你想支持我的内容创作活动,欢迎点击我下面的推荐链接,加入 Medium 的会员计划。我将收到你投资的一部分,你将能够以无缝的方式访问 Medium 的大量数据科学文章。

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

下次见!👋

连续 21 点(一):介绍和初步结果

原文:https://towardsdatascience.com/continuous-blackjack-i-introduction-and-first-results-be70c5da426f

连续二十一点问题的解析和数值观点

埃里克·麦克林在 Unsplash 上的照片

介绍

这是我们将分析连续玩 21 点问题的几篇文章中的第一篇。特别是,我们希望将亨利·查尔斯沃斯穆昭的工作扩展到其他发行版。在这第一篇文章中,我们将复制现有的结果,并提出一种将它们扩展到其他发行版的方法。然后,我们将分析均匀分布的情况,并展示一些有趣的情节。

问题陈述

考虑 21 点游戏的连续版本,它有以下规则:

  1. 每个玩家 i 从一个空筹码 S_i=[] 开始。这个堆栈的值定义为 V_i=∑|S_i|S_ji。
  2. 庄家从分布 P(x) 中抽取随机值。
  3. 玩家轮流玩游戏。每个玩家的回合开始于从庄家处收到一个数字,并将其加入其筹码 S_i 。然后,玩家有两个选择:
  4. 决定停止游戏,用当前筹码结束游戏。然后该玩家的回合结束,轮到下一个玩家。
  5. 获取另一个数字,将其添加到堆栈中,然后返回步骤 3。玩家可以在 V < 1 的时候随时这样做。如果 V > 1 玩家自动输了,下一个玩家的回合开始。
  6. V 值最高的玩家赢得游戏。

问题是,赢得这场游戏的最佳策略是什么?

预赛

首先让我们定义一下 F(t;a,b) 是在区间 R=(a,b) 中着陆的概率,假设我们实际上在 t,如果 t < a,我们将继续玩下去。这个概率可以分为两部分,(1)我们在下一个回合中在 R 着陆的概率,以及(2)我们在下一个回合中不是在 R 上着陆而是在下面的一个回合中着陆的概率。

用数学术语来说,这是

均匀分布

P=U[0,1] 的特殊情况下

对两边的 t 求导,我们得到

常数 K 可以使用F(a;a,b)= b a,所以 K=(b−a)e^a.

请注意,这个等式并不依赖于 a、b 和 t 的特定值,而是依赖于它们之间的距离。因此,可以将值W = ba定义为范围的宽度,将D = ta定义为从当前位置到下限的距离。那么,这个等式可以写成

战略

在本节中,我们将分析如何使用上一节中得出的结果来寻找不同场景中的最佳策略。

1 对 1

让我们从最简单的情况开始:你只和另外一个人比赛。如果第二个玩家破产,第一个玩家就得一分。如果第一个玩家的得分是 s,那么第二个玩家的概率是1f(0;s,1) 破产,这意味着如果我们留在 s,我们获胜的概率是1 F(0;s,1)。当然,如果我们可以选择我们的 s,我们会选择 s=1 ,但是由于这是一个随机过程,我们不能选择 s,我们唯一可以选择的是在哪个 α 停止抽取数字。这个 α 是由以下几点定义的:假设我们坚持在 α 的情况下获胜的概率与假设我们多抽一个号码的情况下获胜的概率相同。

具体情况:均匀分布

对于这一部分,让我们假设 P=U[0,1] 并且所有玩家都从 x=0 开始。在这种情况下,上述推理所描述的条件被写成

注意左边在增加,而右边在减少。

模拟结果

在得出理论结果之前,让我们通过模拟来寻找最佳阈值。为此,我们将尝试每个可能的阈值,并模拟 50000 个游戏。然后,我们将检查作为所选阈值的函数的第一个玩家获胜的概率。结果绘制在下图中:

第一个玩家获胜的概率与停止阈值

可以看到,最大获胜概率是在t∫= 0.6左右实现的,更具体的是t∫=(0.565±0.035)。为了计算最佳阈值及其偏差,我们进行了蒙特卡罗模拟。也就是说,我们已经使用预期的获胜概率及其 99%的置信区间生成了 1000 个阈值-概率曲线样本。然后,我们计算了每个样本的最佳阈值,从这组最佳阈值中,我们计算了*均值和标准偏差。

知道了最佳值所在的范围,让我们重复上面的模拟,但是阈值在 0.5 和 0.65 之间。使用这个较小的范围,我们得到最佳阈值t∫=(0.568±0.021)。最后,最优阈值下的期望获胜概率为p _ win(t∫)=(0.4278 0.0011)。现在让我们看看分析结果是否与模拟相符。

分析结果

使用截面均匀分布和 P=U[0,1] 的结果,最佳 α 的等式为

曲线的绘制 1−(1−α)eα和(1−α)−eα(α−2)−e.

这是一个没有封闭形式的非线性方程,但可以用数值方法*似求解,解为α≈0.5706。这意味着当我们筹码的累计值大于 0.5706 时,我们应该结束这一轮。这个结果与我们在模拟中发现的范围是一致的。

结论

在这第一篇文章中,我们已经推导出了落在区间 (a,b) 内的概率的一般方程,假设我们目前处于 t 。我们还导出了最佳阈值必须满足的条件。最后,我们研究了均匀分布的特殊情况——在数值上和分析上——并研究了它的性质。

在下面的帖子中,我们将研究当分布 P 变化时,所有这些结果是如何变化的。我们还将研究与 N 个玩家而不是一个玩家对战的情况。

这个故事最初发表在这里

将 ML 模型持续部署到边缘

原文:https://towardsdatascience.com/continuous-deployment-of-ml-models-to-the-edge-909a01d6352

真实的例子:工地安全监控

作者图片

与在云中远程运行推理相比,在靠*数据生成位置的边缘设备中运行机器学习(ML)推理具有几个重要优势。这些优势包括实时处理、更低的成本、无需连接即可工作的能力以及更高的隐私性。然而,今天,在分布式边缘设备中实现用于边缘推断和模型连续部署的端到端 ML 系统可能很麻烦,并且比集中式环境困难得多。

与任何现实生活中的生产 ML 系统一样,最终目标是一个重复迭代和部署模型的连续循环。

这篇博客文章描述并展示了一个真实的例子,说明我们如何使用 Valohai MLOps *台JFrog Artifactory 仓库管理器和 JFrog Connect 物联网边缘设备管理*台创建一个完整的 ML 系统,并不断改进自己。

真实用例:建筑工地安全应用

对于我们的用例示例,我们选择了一个突出边缘推理优势的实际应用:工地安全监控。

大多数法规要求建筑工地上的每个人都使用必要的安全设备,如安全帽。这对工地管理者来说很重要,因为不遵守安全规定可能会导致更多的伤害、更高的保险费率,甚至是处罚和罚款。

作者图片

为了监控这些网站,我们基于运行对象检测 ML 模型的 Raspberry Pi 4 设备设置了智能摄像机,该模型可以识别被捕获的人是否戴着安全帽。

在这样的用例中,边缘推理的好处是显而易见的。建筑工地经常有不可靠的连接,检测必须接*实时。在现场的智能摄像机上运行该模型,而不是在云中运行,确保正常运行时间,最大限度地减少连接问题或要求,同时解决可能的隐私和合规性问题。

下面描述了我们如何实现该解决方案的细节。

解决方案概述:持续 ML 培训渠道

我们针对边缘设备的持续培训管道设置包括两个主要部分:

  1. 负责培训和再培训模型的 Valohai MLOps *台,以及
  2. JFrog Artifactory 和 JFrog Connect 负责将模型部署到建筑工地的智能摄像机上。

培训和部署渠道(图片由作者提供)

解决方案组件(图片由作者提供)

培训和部署模型

在 Valohai MLOps *台中,我们定义了一个典型的深度培训管道,分为三个步骤:

预处理和训练步骤是你从深度学习机器视觉管道中所期望的。我们主要是在预处理中调整图像大小,训练步骤使用强大的 GPU 云实例重新训练一个 YOLOv5s 模型。

代码片段:valohai.yaml

更有趣的步骤是部署步骤,我们将 Valohai *台与 JFrog DevOps *台集成在一起。 valohai.yaml 是一个配置文件,它定义了各个步骤以及连接这些步骤的管道。下面是我们在 YAML 定义的示例deployment-jfrog步骤。

- step:
    name: deployment-jfrog
    image: python:3.9
    command:
    - cp /valohai/inputs/model/weights.pt /valohai/repository/w.pt  
    - zip -r /tmp/model.zip /valohai/repository/model
    - curl >
       -H "X-JFrog-Art-Api:$JFROG_API_KEY" >
       -T /tmp/model.zip "$JFROG_REPOSITORY/model.zip"
    - python jfrog-connect.py >
       --flow_id=f-c4e4-0733 >
       --app_name=default_app >
       --project=valohaitest >
       --group=Production
    inputs:
    - name: model
      default: datum://017f799a-dc58-ea83-bd7f-c977798f3b26
      optional: **false**
    environment-variables:
    - name: JFROG_REPOSITORY
      optional: **true**
    - name: JFROG_API_KEY
      optional: **true**

让我们看看部署步骤是如何工作的。

首先,部署步骤构建一个包含模型+权重的 zip 存档,然后将其上传到 JFrog Artifactory。Valohai 将前一训练步骤的权重作为输入文件提供给该步骤,并将所需的JFROG_API_KEYJFROG_REPOSITORY秘密作为环境变量提供给该步骤。

下一步是启动一个更新流程,通过调用 JFrog Connect API 在智能摄像机群中发布新模型。

瓦罗海的训练管道(图片由作者提供)

我们已经建立了一个 Valohai 管道,该管道将模型上传到 JFrog Artifactory,并在 JFrog Connect 服务中触发模型的部署,该服务在整个智能相机车队中交付新模型。

模型部署过程被表示为一个 JFrog Connect 更新流。更新流是需要在边缘设备中发生的一系列动作。使用 JFrog Connect 的拖放接口,我们创建了一个更新流程,其中包括更新智能摄像机中的模型所需的步骤。这些步骤是:

用 Jfrog 创建更新流(图片由作者提供)

  1. 从 JFrog Artifactory 下载模型,
  2. 运行脚本来安装模型,以及
  3. 重启设备。

如果其中一个步骤失败, JFrog Connect 会将设备回滚到之前的状态,因此设备总是以已知状态结束。进一步了解 JFrog 连接更新流程

Ddata 收集管道(图片由作者提供)

持续培训

一旦模型部署到整个边缘设备群,我们的工作就没有完成。摄像机全天候收集潜在的训练数据,并遇到有趣的边缘情况。

在这个阶段,我们需要创建一个管道,每周从智能相机群中收集标记的图像,并将它们上传到 S3 桶中进行手动重新标记,并最终用于重新训练模型。

计划管道的工作方式:

  1. 使用对 S3 存储桶具有只写访问权限的 AWS STS 创建临时凭据
  2. 使用内置的临时密钥升级 JFrog Artifactory 中的上传脚本
  3. 触发 JFrog 连接更新流以在设备群中运行上传脚本
  4. 每个设备上传一批新的图像到 S3 桶

设备群上传的新训练数据由人类使用 Sama 或 Labelbox 等*台手动标记,一旦数据被标记,这些*台使用我们的上传 S3 桶作为其源,另一个 S3 桶作为目标。

注意:庞大的车队会产生太多数据,无法进行手动标记,设备本身可能会很快耗尽空间。幸运的是,像 YOLOv5 这样的机器视觉模型通常有一个置信度和预测标签。我们使用置信度阈值过滤设备上存储的训练数据,该阈值优先考虑边缘情况。

结论

总之,我们展示了如何创建一个连续的循环,在生产中跨一系列边缘设备重复迭代和部署 ML 模型。Valohai MLOps *台与 JFrog DevOps *台的 Artifactory 和 Connect 相结合,使我们能够实现这一目标,并创建一个不断自我改进的 ML 系统。

原载于 2022 年 7 月 13 日【https://jfrog.com】

连续机器学习

原文:https://towardsdatascience.com/continuous-machine-learning-e1ffb847b8da

持续学习(图片由作者提供)

CML (Iterative.ai)简介

这篇文章是为寻找理解连续机器学习的简要指南的数据科学家和工程师写的,它是什么?它是如何工作的?以及如何将它集成到您的日常模型开发过程中?

让我们开始吧!

您可能听说过 CI/CD(持续集成/持续部署),其中软件工程团队开发一个应用程序,无缝集成新的变更、错误修复和增强,并部署最新的应用程序。这在软件场景中是可行的,因为有工具和技术可以做到这一点。

让我们以构建一个简单的 web 应用程序为例。构建 web 应用程序的最小团队由前端工程师、后端工程师、数据库管理员和部署工程师组成。

网络应用开发团队(图片由作者提供)

团队将在 GitHub 或一些存储库托管服务中拥有他们的代码存储库。随着新代码的更改和错误修复的修补,开发人员将开始把代码推送到存储库的特性和修复分支。一旦代码通过验证,就会产生一个 pull 请求,将变更与主分支合并;在合并最新代码之后,触发管道来扫描和测试代码,一旦通过,就可以打包和部署代码。

软件开发中的 CI/CD 流程(图片由作者提供)

现在想象一个机器学习(ML)和数据科学家团队试图实现同样的目标,但使用 ML 模型。这涉及到一些复杂的问题-

  • 开发 ML 模型不同于开发软件。大部分代码本质上是一个黑盒,很难找出 ML 代码中的问题。
  • 验证 ML 代码本身就是一门艺术,在软件代码中使用静态代码检查和代码质量检查是不够的,我们需要数据检查、健全性检查和偏差验证。
  • ML 模型的性能取决于用于训练和测试的数据。
  • 软件开发有标准化的架构和设计模式,ML 没有广泛采用的设计模式,每个团队可能遵循他们自己的风格。
  • 多个分类器和算法可以用来解决同一个问题。

所有这些复杂性提出了一个重要的问题——ML 能以持续集成的方式进行吗?

这就是 CML 的用武之地。 CML 是由 Iterative.ai 开发的一款优秀开源工具,它允许数据科学家和机器学习团队使用现有的网站如 GitHub、GitLab、和工具如 DockerDVC 来执行模型的持续训练和集成。不需要额外的技术堆栈。

现在你可能会说——“但是我很高兴在我的笔记本上开发并运行我的 ML 模型,我可以随时改变参数,随心所欲地调整代码。我为什么需要 CML?”

我们为什么需要慢粒?

考虑将 ML 模型投入生产的过程——一群数据科学家致力于解决问题,获取数据,建立模型,根据数据训练模型,测试和评估模型。如果足够好,他们会部署它。在这个过程中,我们需要确保某些制衡措施到位-

  • 一个数据科学家创建的模型可以被其他人在不同的系统和环境中复制吗?
  • 用于培训的数据版本是否正确?
  • 模型的性能指标是可验证的吗?
  • 我们如何跟踪并确保模型得到改进?
  • 大多数团队会使用云 GPU 实例来训练模型——这可能是一个按需实例,以降低成本(仅在训练期间需要)。我们如何确保为培训建立适当的环境?
  • 一旦培训完成,是否有一份报告给我们提供培训课程的详细信息,以便以后进行比较?
  • 在模型的再训练过程中会发生同样的检查吗?

这些步骤对于确保模型随着时间的推移而改进是必要的。随着团队越来越大,或者随着模型变得越来越复杂,保持跟踪变得非常乏味。

CML提高了&简化了这个过程;引入一个连续的工作流,用于供应云实例、在其上训练模型、收集指标、评估模型性能和发布摘要报告。它允许开发人员引入一系列检查点,这些检查点在不同的场景中更容易跟踪和重现。

CML 工作流使这一切成为可能,不需要额外的技术堆栈,几行代码就可以无缝集成到大多数开发人员熟悉的现有开发流程中。

这增加了开发流程的可见性,数据科学家现在可以访问多个培训报告和指标来比较和评估模型。这有助于团队更快地开发模型并将其投入生产,减少了大量的手工工作以及在性能下降时修复模型所涉及的返工。

让我们部署(图片由作者提供)

让我们看看它是如何工作的。

CML 是如何工作的?

CML 将 CI/CD 风格的自动化注入到工作流中。大多数配置是在存储库中保存的一个cml.yaml配置文件中定义的。在下面的示例中,该文件指定了当特征分支准备与主分支合并时应该执行的操作。当发出一个 pull 请求时,GitHub 动作利用这个工作流并执行配置文件中指定的活动——比如运行train.py文件或生成一个准确性报告。

CML 使用一组叫做的函数。这些是帮助我们工作流的预定义代码,比如允许这些报告作为评论发布,甚至启动云运行器来执行工作流的其余部分。你可以在下面的工作流程中看到所有这些步骤是如何被压缩成一个步骤的

CML 工作流程(图片由作者提供)

让我们用一个例子来理解这一点

例子

假设 3 名数据科学家— Anya、Jack 和 Nora 正在构建一个分类器来识别和分类不同的水果。 Anya 从一个基本的二进制分类器开始,它识别一个水果,并将其分类为苹果或非苹果。然后,杰克继续添加识别桔子和香蕉的能力。

杰克要做的就是

  1. 创建他的特征分支
  2. 编写他的代码,在以前的模型上运行他的训练和测试
  3. 将他的代码推送到特性分支
  4. 提交一个 pull 请求,将他的代码合并到主分支

当发出“拉”请求时,CML 跳进去,并运行在cml.yaml配置文件中给出的动作。生成一个报告,然后团队可以决定是否合并 Jack 的代码。没有重复的文件,没有同一笔记本的多个副本,只是一个简化的工作流程。

那么在这个配置文件中到底发生了什么样的奇迹呢?让我们来看看

这个cml.yaml文件是一个 GitHub 动作脚本。如果你一开始感到困惑,不要担心,我会为你简化它。

这个文件告诉 GitHub 以下几点

  • 行动流程 —模型培训的名称是什么
  • 该工作流应在何时执行——根据对 main 的拉取请求
  • 它应该做什么工作 —火车模型
  • 它应该在哪里执行——在装有最新 Ubuntu 操作系统的 GitHub runner 上(我们在这里没有使用云 GPU runner)
  • 需要执行哪些步骤 —列车模型
  • 执行这一步需要什么 — checkout,setup-python,setup-cml。这些是 GitHub 及其市场中可用的操作。动作是某人已经编写的执行任务的代码片段,您可以在脚本中轻松重用。所以你的最新代码会在临时的 Ubuntu 虚拟机上签出,python 和 cml 会安装在那台机器上。
  • 应该使用什么环境变量—REPO _ TOKEN 由 GitHub 给出,所以虚拟机知道只有授权的 GitHub repo 才被允许执行这个任务。
  • 在此步骤中应该执行哪些命令 —安装 python 包,运行 train.py 文件,将评估报告发布到名为report.md的文件中。这将显示报告数据,如准确性、评估指标和误差指标,无论您希望将哪一项指定为模型评估过程的一部分。
  • CML-Functions —您会注意到脚本最后两行中的*cml publish**cml send-comment*命令,它们是 CML Functions 。这些函数简化了您在 pull 请求中创建模型训练的详细报告的任务。您可以创建一个很酷的可视化报告来概述模型的性能。这有助于数据科学家确定最终合并可以批准哪个拉请求。

简而言之,Jack 所做的就是编写他的代码,测试他的模型,将他的更改推送到他的分支,然后提出一个 pull 请求。模型评估、比较和结果列表的其余步骤由 CML 负责。CML 操作完成后,一个很酷的培训会议报告可供其他数据科学家验证和评估——在同一个报告中,如下所示。

CML 报告(图片由作者提供)

假设 Nora 想要使用最新的代码,用她的数据进行训练,想要增加按百分比分类的能力。因此,她的模型将水果图像分类为 96%的苹果或 60%的香蕉,她有大量的图像数据集要训练,GPU 将为她节省大量精力。 但是 Nora 不知道设置基于 CUDA GPU 的实例所需的所有系统设置和配置。

在这里,CML 也来帮忙了。她可以使用定制的云运行器,连接到 AWS GPU 实例并训练她的模型,而不必学习额外的技术或系统设置知识。她所要做的就是配置cml.yaml文件来使用 AWS 和 GPU 设置。然后,工作流将使用自定义的基于 GPU 的容器来训练模型并发布她的结果。

CML Magic(图片由作者提供)

现在,每当有人创建一个特性、模型增强、性能改进或错误修复时,评估报告将在合并过程中随时可用。多个数据科学家可以同时研究一个模型的并行版本,比如不同的分类器算法,使用 CML 他们可以查看模型是否经过适当的训练、可部署和比较指标;都在同一个存储库工作流中。

太棒了。接下来呢?

如果你是数据科学家或机器学习团队,首先在 GitHub、GitLab 或 Bitbucket 上创建你的知识库。前往https://github.com/iterative/cml按照那里给出的步骤开始你的 CML 之旅。

您可以尝试以下用例

  • 查看您的模型培训的模型准确性和性能指标报告
  • 使用 CML 使用 DVC 在不同版本的数据上运行您的培训,提取新数据,培训您的模型,发布您的报告并将您的最新模型推送到您的存储中。
  • 如果您有一个 TensorFlow 模型,您可以连接到 tensorboard.dev 并使用 CML 工作流定期发布您的报告
  • 为你的项目使用定制的 CML runner,并在你的 AWS EC2、Azure、GCP 云实例或你的本地机器上训练你的模型
  • 使用基于 AWS GPU 的实例,无需额外设置,一旦完成培训,就可以删除该实例。有助于降低培训和实例成本。
  • 由于工作流在基础级别使用 GitHub 操作,所以您也可以将脚本扩展到其他工作流操作——例如创建一个模型 pickle 文件,并在每次推送特定分支时将其存储在远程存储中。
  • 在 GitHub Actions 工作流之上添加 CML,很容易将其与现有工作流集成—假设您希望跟踪数据的主要版本和模型更改,您可以使用 CML 来训练模型,在主要版本的 pull 请求期间生成报告,并添加一个简单的 GitHub 操作来邮寄该报告。——CML+github 操作的可能性是♾️。

目前就这些。快乐的慢粒冒险🙂

链接和参考

MLOps:使用云将您的模型投入生产

原文:https://towardsdatascience.com/continuous-model-deployment-using-aws-68d89c5448f1

使用 AWS、S3 和 CloudFormation 将您的深度学习模型持续部署到云

照片由 Fotis FotopoulosUnsplash 上拍摄

介绍

MLOps 变得越来越重要。根据像这样的文章,“87%的数据科学项目从未进入生产”。这令人担忧。这意味着,*均来说,100 个模型中只有 13 个能投入生产。剩下的 87 个只是丢失了。它们被卡在 Jupyter 笔记本的 Git 库的某个地方。那是一场灾难!然而另一方面,这也是一个机会。对于拥有将模型投入生产的必要技能的开发人员来说,这是一个机会,因为公司需要将模型投入生产的人来使用它们。因此,如果你对如何将模型投入生产感兴趣,请继续阅读!此外,您可以派生出我的 Github 库并按照本文中的指南在您自己的 AWS 帐户中复制所有内容。这有助于更好地理解主题。

在我的上一篇文章中,我使用 Github Actions 和 Docker 开发了一个持续部署管道,将一个经过训练的模型部署到 AWS Elastic Beanstalk。在那篇文章中,我还使用 Git LFS(大文件存储)对我的模型和源代码进行了版本化。阅读本文,了解 Docker 容器是如何创建的,以及如何在 AWS 中创建一个弹性 Beanstalk 应用程序并将 Docker 容器部署到其中。

在本文中,我想向您展示一个更优化的设置,它只利用 AWS 服务。该模型现在被版本化并存储在 AWS S3 桶中,而不再存储在代码中。我为部署模型而创建的管道是使用 AWS CodePipeline 创建的。该模型最终仍然部署在 Elastic Beanstalk 上,但是这一次它首先部署在一个临时环境中,以便您或团队成员能够首先测试它。如果您或您的团队成员对新模型感到满意,可以给予批准,新模型将被部署到生产环境中。

在上一篇文章中,我还在 AWS 中手动创建了完整的基础设施,但这次我使用了 CloudFormation。CloudFormation 是 AWS 提供的一种以代码形式创建基础设施的服务。这样做的好处是,您的基础设施和您的代码都是版本化的,并且您总是可以通过一次点击来创建或删除所有服务,而不是手动创建或删除所有资源。你可以在这里阅读更多关于云形成的信息。

图 1:使用的 AWS 服务的概述(图片由作者提供)。

管道概述

让我们首先更深入地了解我创建的管道。图 2 显示了完整管道和所有单个步骤的概述。现在,我想更详细地解释这个流程中的每一步。

图 2:管道步骤概述(图片由作者提供)。

Gif 1:部署到暂存环境和手动批准步骤的演示(Gif 由作者提供)。

代码 AWS CodePipeline 的 YAML 代码(作者代码)。

克隆源存储库

克隆源存储库是管道中的第一步。这里的源代码库被克隆并打包成一个 zip 文件。然后,这个 zip 文件作为输入提供给管道的下一步。我还将这个阶段配置为在链接的源代码库中检测到更改时总是运行。通过这种方式,只要代码中发生了变化,管道就会立即运行,并且新的应用程序会始终部署到登台环境中。

克隆源代码库步骤利用了 AWS CodeStar 连接。这是 AWS 中配置从 AWS 到 Github 库的连接的一种新方法。我已经使用 AWS 控制台手动创建了这样一个连接。你可以按照这个指南来创建这样一个到你的 Github 库的连接。

借鉴 S3 模式,打造码头工人形象

既然我们已经将代码放在一个 zip 包中,那么是时候为应用程序的部署做准备了。第一步是从相应的 s3 存储桶中提取模型的当前最新版本。我创建了一个版本化的 s3 bucket,并将我的模型上传到其中。您可以在我的存储库这里(代码 2)找到该步骤的 bash 脚本。您可以在已经设置好与 AWS 一起使用的 Linux 控制台中执行这个 bash 脚本。你可以按照这个指南来配置你的控制台,以便能够连接到你的 AWS 账户。

代码 2: Bash 脚本,用于创建一个版本化的 S3 存储桶,然后将我训练好的模型上传到该存储桶(由作者编写代码)。

在我从 s3 中取出模型后,我想构建 Docker 映像,稍后也将在 AWS Elastic Beanstalk 上构建。这有助于确保仍然可以创建容器,并且最新的源代码版本可以正常工作,至少从基础设施的角度来看是这样。

这两个步骤(从 s3 提取和构建 Docker 映像)都在 AWS 代码构建步骤中执行。CodeBuild 是“一个全面管理的持续集成服务,它编译源代码,运行测试,并生成准备部署的软件包”(来源)。CodeBuild 步骤也在存储在源代码存储库中的 yaml 文件中定义。您可以在我的存储库中找到它,也可以在下面的代码片段中看到它(代码 3)。

代码 3:定义代码构建步骤的 YAML 代码(由作者编写代码)。

在 CodeBuild 步骤中,我首先从 s3 下载最新的模型( pre_build 步骤),构建 Docker 映像以查看应用程序是否仍然可以创建( build 步骤),最后,将所有内容打包到一个 zip 包中,以便这个 zip 包可以直接部署到 Elastic Beanstalk(artifacts 部分)。

然后,CodeBuild 步骤会引用创建的 buildspec。您可以在下面的 CloudFormation 模板中看到相应的 yaml 代码(代码 4)。

代码 4:代码构建步骤的 YAML 片段。这个 YAML 片段是 CloudFormation 模板的一部分(由作者编写代码)。

部署到弹性豆茎

既然我们现在仍然可以构建应用程序,并且我们已经有了所需的 zip 包,那么是时候将该应用程序部署到试运行环境中了。首先部署到一个临时环境是很重要的,这样在将一个损坏的应用程序部署到客户与您的应用程序交互的生产环境之前,可以首先测试新的应用程序。此外,不总是创建新的产品版本也是有意义的。也许您希望每月向生产环境发布一次新版本,但是您仍然希望总是在您的试运行环境中测试新创建的特性。

因此,我在部署到试运行环境之后和部署到生产环境之前添加了一个手动批准步骤。您或团队成员现在可以首先检查在试运行环境中启动并运行的应用程序,如果一切正常,他或她可以批准它开始部署到生产环境。当然,如果你有具体的发布时间表,也可以只在你的发布日期批准。我个人总是倾向于在将应用程序部署到生产环境之前进行手动操作,这样只有在需要部署的时候才会进行部署。这增加了一层额外的安全性,因为批准者确实知道在批准后现在部署到生产中(至少他或她应该知道)。

代码 5:Elastic Beanstalk staging and production environment 的 YAML 片段。它还包含每个环境的配置,如 EC2 实例类型。这个 YAML 片段是 CloudFormation 模板的一部分(由作者编写代码)。

在 AWS 中安装管道

好吧。现在您已经看到了管道的作用。现在让我们在 AWS 中安装这个管道。正如我之前提到的,我使用 CloudFormation 创建了管道,使所有东西都可以作为代码使用。这有助于将管道和我的源代码一起版本化,并方便地安装或卸载所有需要的服务。否则,用户必须自己安装所有的服务,这可能会占用大量时间,并且也是一个容易出错的过程。你可以在我的源代码库这里找到 CloudFormation yaml 文件。

我真的建议您按照下面的步骤来更好地了解管道。只需将 my source 存储库分支并克隆到您的本地机器上。然后,您可以运行接下来的步骤,首先创建一个 s3 bucket 并将模型上传到该 s3 bucket,然后使用相应的 yaml 文件安装 CloudFormation 堆栈。

让我们现在开始吧!

步骤 1:将存储库克隆到您的本地机器上

首先将存储库克隆到您的本地机器上。您还必须运行 git lfs pull 来获取训练好的模型,因为这是使用 git lfs 上传的。

步骤 2:创建 s3 存储桶并上传模型

打开命令行运行 create-and-upload-s3.sh bash 文件。如果你在 Windows 机器上运行它,你可以安装 Git Bash 来在你的 Windows 机器上运行 Bash 文件。

在打开的命令行中,导航到 aws_infra_setup 文件夹并运行 bash create-and-upload-s3.sh 来创建 s3 bucket 并将模型从 Git 存储库上传到创建的 bucket。

图 3:运行 bash 脚本来创建 s3 bucket 并将训练好的模型上传到其中(图片由作者提供)。

步骤 3:创建到 Github 的连接,并修改 CloudFormation 模板来使用这个连接

为了在管道中克隆源存储库,需要有一个被授权克隆源存储库的连接。为此,你可以遵循这个指南来创建这样的连接。

然后,您可以导航到这个连接并复制该连接的 UID(图 4 ),并用您的 UID 替换我的 UID (CloudFormation 模板 yaml 第 53 行)。

图 4:查找 Github 连接的 UID,然后可以将其添加到 CloudFormation 模板 yaml 文件中(图片由作者提供)。

图 5:需要添加 Github 连接 UID 的 CloudFormation 的代码片段(图片由作者提供)。

步骤 4:创建云形成堆栈

转到您的 AWS web 控制台。在搜索栏中,搜索“ CloudFormation ”。然后点击“创建堆栈”。应该会打开一个新 UI,让您配置您的 CloudFormation 堆栈。在“模板准备好了处保留第一个选项,并在“指定模板部分下选择“上传模板文件”。然后,您可以点击“选择文件,并选择位于“ aws_cloud_formation ”文件夹中的 CloudFormation 模板文件(cloud-formation-stack-pipeline . YAML)。

图 6:在 AWS web 控制台中创建 CloudFormation 堆栈的配置截图(图片由作者提供)。

然后你可以点击下一个。为您的堆栈输入一个名称(即 birds-classifier-cicd-stack),然后再次点击“Next”。您可以将下一页中的所有设置保留为默认值。再次点击下一个。在最后一页,您必须向下滚动到底部并勾选复选框,以确认 AWS CloudFormation 可能会创建 IAM 资源。这是必需的,因为 Pipeline、CodeBuild 和 Elastic Beanstalk 都有自己的 IAM 角色。

最后你可以点击创建堆栈。CloudFormation 现在应该为您创建所有的资源和服务。一切创建完成后,您可以在搜索栏中搜索“ CodePipeline ,点击名为“ birds-classifier-cicd 的管道。该管道应该已经运行。第一次运行时会失败,因为弹性 Beanstalk 环境在启动并运行之前需要更多的时间。但是一旦弹性 Beanstalk 环境准备就绪,就应该重试部署阶段。然后,您可以转到试运行环境,检查应用程序并批准部署到生产环境(参见上面的 c.f. Gif 1)。

结论

我们现在已经为您训练的 ML 模型创建了一个专业的自动化部署。现在发布新的型号真的很容易,你的型号现在是 13%的产品中的一部分,而不是 87%的产品中的一部分。恭喜你!

谢谢你把我的文章看完!我希望你喜欢这篇文章和我参与的项目。如果你想在未来阅读更多类似的文章,请关注我,保持更新。

接触

LinkedIn|Github

Python 中的等高线图和单词嵌入可视化

原文:https://towardsdatascience.com/contour-plots-and-word-embedding-visualisation-in-python-9dd2dacff6ac

等高线图对于单词嵌入可视化来说是简单且非常有用的图形。这个端到端教程使用 IMDb 数据来说明 Python 中的编码。

图一。等高线图示例。来源:commons.wikimedia.org。

介绍

文本数据矢量化是现代自然语言处理中必不可少的一步。Mikolov 等人(2013a)和 Mikolov 等人(2013b)开发的两个 Word2Vec 模型普及了单词嵌入的基本概念。在高维空间中对文本数据进行矢量化,我们可以针对机器翻译和情感分类等任务调整 ML 模型。

单词嵌入通常被绘制成三维图形,这给在论文和演示中容易地呈现它们带来了一些困难。在这里,等高线图是如何处理三维数据可视化的简化,不仅在 NLP 中,而且最初在许多其他学科中。等高线图可用于在二维图形中呈现单词嵌入(即,单词的矢量表示)本文提供了在二维空间中可视化单词嵌入的分步指南,并开发了可以使用等高线图的用例。

什么是等高线图?

等高线图可以在二维图中显示三维数据。它是一个二维图表,使用圆形(通常是彩色的)来表示第三个轴。圆上的任何一点在第三轴上都有相同的值。以下是等值线图中同一三维数据集的图形表示:

图二。显示 3D 数据的等高线图,来源:代码可从此处获得。

这种类型的图形广泛用于制图,其中拓扑地图上的等高线指示相同的高程。许多师兄弟使用等高线图,包括占星术、气象学和物理学。等高线通常显示海拔高度(如地理特征的高度),但它们也可用于显示密度、亮度或电势(Glen,2022)。

分步指南

回到 Python 中的 NLP,我们将在经典的 IMDb 电影评论数据集上展示等高线图,该数据集与属性 4.0 国际许可共享。除了最后一个可视化步骤,实证应用程序遵循我在文章 中开发的策略,用 word 2 vec(kolab,2021)对文本数据进行聚类。有完整 python 代码的 Jupyter 笔记本这里

语料准备和 Word2Vec 模型训练

首先,我们将进行精确的数据预处理操作,如( Korab,2021) 。接下来,来自Gensim库中的 Word2Vec 模型对文本语料库进行矢量化,并提供单词嵌入。这段代码训练了一个 Word2Vec 模型,其中 Gensim == 4.2.0 用于 200 个维度,只考虑出现次数大于 10 的单词:

主成分分析降维

下一步,我们需要将数据的维度从 200 维减少到可以在笛卡尔三维空间中可视化的 3 维。这里,主成分分析 (PCA)是一个标准解:

以下是矢量化数据的外观:

图 3。IMDb 数据用 Word2Vec 矢量化,用 PCA 降维

等高线图可视化

最后,我们将在等高线图中显示数据。

使用 Word2vec 获得的向量捕获了单词的语义和语法质量,模型将语义相似的单词分组为彼此接*的单词。等值线图有助于在简单易懂的图中清晰地显示复杂的数据集。

可视化部分包括(1)使用米勒(2020) 提供的代码将坐标旋转成矩阵结构,( 2)生成等高线图,(3) 在图中标注文字。所有这些步骤的 python 代码:

这是前 60 次嵌入的等高线图:

图 4。词嵌入的二维等高线图。

我们可以看到,Word2Vec 模型将单词“film”、“films”、“T9”“movie”、“T11”和“movies”在所有 3 个维度中彼此靠*地分组。同样,“人物”【导演】“演员”也是彼此接*。对于出版质量数字,检查 Matplotlib 文档以格式化一些重叠单词的注释。

为了比较,让我们看一下显示相同数据的三维等值线图:

图 5。单词嵌入的三维等高线图。

结论

等高线图是很少使用,但非常有用的文字嵌入可视化图形。好的例子包括各种演示中的数据故事和研究论文中的格式图表。在某个阈值内,论文和演示文稿中的 3d 嵌入可视化可能会变得不清楚和混乱。另一方面,等高线图提高了图形的解释能力,同时保持了它们的信息价值。它们的好处随着三维数据的复杂性而增加,有助于更多地了解数据集的结构。

完整的代码,包括所有的例子,都在我的 GitHub 上。

PS:你可以订阅我的 邮箱列表 在我每次写新文章的时候得到通知。如果你还不是中等会员,你可以在这里加入https://medium.com/@petrkorab/membership

参考

[1]格伦,S. 2022。等高线图:定义、示例。Statistics show to . com:我们其他人的基本统计数据!

[2] Korab,2021 年。用 Word2Vec 对文本数据进行聚类。 Python 直白的英语。

[3]t . miko lov,Sutskever,I .,Chen,k .,Corrado,G. S .,Dean,J. 2013a。词和短语的分布式表征及其组合性。 神经信息处理系统进展 26 (NIPS 2013)。

[4]t .米科洛夫,陈,k .,科拉多,G. S .,迪安,J. 2013b。向量空间中单词表示的有效估计计算与语言。**

[5]米勒著,第 2020 页。使用 matplotlib 在 Python 中绘制等高线:像 X-Y-Z 一样简单 Alex P. Miller 博客 ,2020 年 2 月 24 日。

基于形态学算子的灰度图像对比度增强

原文:https://towardsdatascience.com/contrast-enhancement-of-grayscale-images-using-morphological-operators-de6d483545a1

利用 OpenCV 中的形态学算子增强灰度图像对比度的简单方法

米拉德·穆阿菲在 Unsplash 上的照片

介绍

对比度增强是一种非常常见的图像处理技术,用于增强低对比度图像中的特征。几种方法如对比度拉伸直方图均衡自适应直方图均衡对比度受限自适应直方图均衡CLAHE 等。已经被用于增强图像的对比度。在本文中,我们将研究另一种对比度增强的方法,这种方法是使用形态学变换的组合来实现的。

什么是形态变换或运算符?

形态变换或形态运算符是简单的图像变换,通常应用于二值图像,但也可以应用于灰度图像。形态变换有各种类型,如侵蚀扩张张开闭合渐变礼帽黑帽。这些变换的两个主要部分是输入图像和被称为结构化元素(SE) 的内核。在我们详细讨论不同类型的形态变换之前,让我们先了解一下结构元素。

什么是结构元素?

结构元素(SE) 是在执行形态学操作时检查的每个像素周围的邻域。结构化元素可以有不同的形状和大小,改变它会显著影响转换的性能。

OpenCV 提供的结构化元素有三种形状——长方形椭圆形十字形。下图显示了这三种形状。

大小为 5 x 5 的结构元素的不同形状(图片由作者提供)

形态运算符的类型

不同类型的形态运算符有:

  1. 侵蚀— 根据 OpenCV 文档,侵蚀算子的工作原理类似于土壤侵蚀。它“侵蚀”,或者更简单地说,去除图像中前景对象的边界。前景对象边界处的像素被移除。它会缩小图像中对象的大小。
  2. 膨胀— 膨胀的作用与侵蚀完全相反。它“扩大”或扩展前景对象的边界,从而增加图像中对象的大小。如果我们想要连接前景物体的破碎部分,这是很有用的。
  3. 开启— 开启操作用于去噪。首先应用腐蚀操作,然后是膨胀操作。腐蚀操作首先从图像中移除所有小的噪声区域,然后应用膨胀来恢复对象的原始大小。
  4. 关闭— 关闭是打开的反义词,意思是先膨胀后腐蚀。这对于连接或填充前景对象中出现的小点很有用,同时保持对象的大小。
  5. 梯度— 形态学从膨胀结果中减去腐蚀结果,得到图像的梯度。渐变操作的结果是图像中前景对象的轮廓。
  6. 高帽/白帽— 高帽变换,也称为白帽变换,是通过从原始图像中去除或减去图像的开口得到的。这个操作符给出了图像中比结构元素小的明亮特征。
  7. 黑帽/底帽— 黑帽变换,也称为底帽变换,是通过从原始图像中去除或减去图像的闭合而得到的。这个操作符给出了图像中比结构元素小的暗特征。

注意:礼帽和黑帽变换更适合灰度图像。

形态变换如何帮助对比度增强?

简而言之,对比度增强需要做到以下几点:

  1. 使得图像中的亮区域更亮。
  2. 使得图像中的暗区域更暗。

如前所述,顶帽变换的结果是由输入图像中所有亮特征组成的图像,黑帽变换的结果是由输入图像中所有暗特征组成的图像。因此,为了增强对比度,我们需要输入图像的 Top 和 Black Hat 变换。

在获得输入图像的顶帽和黑帽变换之后,我们将向输入图像添加顶帽变换,以使其亮区域更亮,并且从输入图像中减去黑帽变换,以使其暗区域更暗。

上述步骤可以表示为如下所示的等式:

对比度增强方程

其中 R 为结果图像, I 为输入图像, TB 分别为顶帽和黑帽变换。

下面的流程图描述了增强对比度的步骤。

使用形态学变换增强对比度的步骤(图片由作者提供)

密码

我们将使用 Python 和 OpenCV 实现这种对比度增强技术。我们需要首先使用 pip 安装opencv-python

pip install opencv-python

安装 OpenCV 后,我们将在代码中导入库。

import cv2 as cv

我们将使用下面的图片作为我们的代码,它来自 GitHub 上的新冠肺炎图片库。

本库中的图像数据收集自德国汉诺威汉诺威医学院诊断和介入放射学研究所,并根据知识共享署名 3.0 未经许可获得许可。

输入图像

我将图像缩小了 50%,以减小图像的尺寸。

为了读取这个图像,我们将使用 OpenCV 的imread函数。

filename = # path to the image file
img = cv.imread(filename,0)

现在我们有了我们的图像,我们将获得这个图像的顶部和黑帽变换。在此之前,我们需要构建我们的结构化元素或内核。为此,我们可以使用 OpenCV 提供的getStructuringElement函数。

kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE,(5,5))

在上面的代码片段中,我们构建了一个大小为(5,5)的椭圆结构元素。您可以通过更改这些参数进行实验,并观察对输出的影响。

下一步是使用我们在上一步中构建的内核来获得输入图像的变换。

# Top Hat Transform
topHat = cv.morphologyEx(img, cv.MORPH_TOPHAT, kernel)# Black Hat Transform
blackHat = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel)

一旦我们有了变换,我们将应用之前看到的方程。

res = img + topHat - blackHat

大小为(5,5)的椭圆形内核的输出图像

我们可以看到输入图像的对比度有所提高。一些在输入图像中不突出的微小特征现在是可见的。然而,如果没有仔细选择结构化元素,这种技术也会给图像增加一些噪声。

例如,下图显示了选择大小为(15,15)的椭圆形结构元素时的输出。肺部和骨骼边缘的微小特征现在比早期输出更加突出和清晰,但我们可以在输出图像中看到一些靠*身体边界的噪声区域,即背景中的白色斑块。

输出图像,用于大小为(15,15)的椭圆形内核

随着你继续增加结构元素的尺寸,前景特征将变得更加突出,但是背景将开始变得越来越嘈杂。具有大小为(35,35)的结构化元素的输出在背景中有更多的噪声区域。

输出图像,用于大小为(35,35)的椭圆形内核

结论

因此,我们看到了如何使用礼帽和黑帽形态学操作的组合来增强灰度图像的对比度。如上所示,一些微小的特征得到了极大的增强,在我们的输出图像中变得更加突出。

要记住的要点

  1. 这种方法可能不如原始的对比度拉伸方法有效,因为它在图像中引入了噪声,因为我们继续增加结构元素的大小。
  2. 因为结构化元素基本上是应用变换时要考虑的邻域的大小,所以输出也将取决于输入图像的大小。例如,与 250×250 图像的(35,35)核相比,1000×1000 大小的图像的(35,35)核将形成更小的区域。因此,调整图像大小也会影响此方法的输出。
  3. 由于 Top 和 Black Hat 变换分别为我们提供了比结构化元素小的更亮和更暗的特征,如果要增强的特征的大小小于我们选择的结构化元素的大小,这种对比度增强方法将会很好地工作。因此,精确地增强较大特征的对比度变得困难,因为我们的内核的较大尺寸将在我们的图像背景中引入较大的噪声区域。

感谢您的阅读!:)如果你有任何问题,可以在 LinkedIn 上联系我。

参考

  1. OpenCV:形态学变换https://docs . OpenCV . org/3.4/d9/d61/tutorial _ py _ morphology _ ops . html
  2. Kushol R,Nishat R. M .,Rahman A. B. M. A .,Salekin M. M .,“使用具有最佳结构元素形态学算子的医学 X 射线图像的对比度增强”,arXiv:1905.08545v1 [cs .2019 年 5 月 27 日
  3. 辛瑞希·b·温瑟,汉斯·拉塞尔,斯维特拉娜·格贝尔,萨宾·k·马斯克,简·b·辛瑞希斯,延斯·沃格尔-克劳森,弗兰克·k·瓦克,马里乌斯·m·霍普,伯恩哈德·c·迈耶,“新冠肺炎图像储存库”,DOI:10.6084/M9 . fig share . 12676786

3 分钟对比学习

原文:https://towardsdatascience.com/contrastive-learning-in-3-minutes-89d9a7db5a28

自我监督任务中对比学习的指数级进展

深度学习研究已经转向图像识别任务的监督领域,许多人现在已经转向一个更未探索的领域:通过自我监督学习的方式执行相同的任务。导致这项看似不可能的任务取得巨大进步的基石之一是对比学习损失的引入。这篇文章深入探讨了最*提出的一些对比损失,这些损失将无监督学习的结果推到了与监督学习类似的高度。

信息损失

Oord 等人提出的最早的对比学习损失之一是信息损失。他们在论文中提出了以下损失:

其中分子实质上是正对的输出,分母是正对和负对的所有值之和。最终,这种简单的损失迫使正对具有更大的值(将对数项推至 1,从而小于 0 ),负对相距更远。

SimCLR

图一。SimCLR 概述。从https://arxiv.org/abs/2002.05709检索的图像。

SimCLR 是第一篇建议通过图像增强将对比损失用于自监督图像识别学习的论文。

通过对同一幅图像进行数据扩充来生成正对,反之亦然,我们可以允许模型学习特征来区分图像,而无需明确提供任何基本事实。

动量对比(MoCo)

图二。MoCo 概述。从 https://arxiv.org/abs/1911.05722取回的图片

先前的信息损失是基于一个正的和一些负的小批量提出的。何等人扩展了这一概念,将对比学习描述为类似于将最佳键与给定队列匹配的学习。直觉导致了动量对比(MoCo)的基础,它本质上是一个键和值的字典/内存网络,键存储在多个批次中,并以类似队列的方式慢慢地消除最老的批次。这允许训练更加稳定,因为它类似于音调变化不太剧烈的动量。

去耦对比学习

图 3。用 DCL 交换信息对的改进。图片来自 https://arxiv.org/abs/2110.06848。

以前的对比学习论文要么需要大批量,要么需要动量机制。最*的论文去耦对比学习(DCL)希望通过对原始信息损失进行简单的改变来改变这一点:简单地从分母中去除正对。

虽然看起来简单,但 DCL 实际上允许更好的收敛,并最终形成了比以前的论文 SimCLR 和 MoCo 更好的基线。

测试每个概念

上述论文的代码已由作者提供。为了测试这些概念,人们可以简单地下载不同的数据集,看看无监督学习方法的效果如何。

需要注意的是,这些任务通常需要您自己的数据加载器,而不是使用 PyTorch 提供的数据加载器。一个可以检索 ImageNet、CIFAR100 和其他著名图像数据集的地方是这里的。

结束注释

现在你知道了!一篇关于对比学习论文在图像识别的无监督学习中的最新进展的短文。本文仅涵盖了这一范围内的部分工作。许多伟大的论文如 NNCLRMoCo v2 也值得一读。希望你在理解这些优雅而有效的概念时感到有趣!

感谢你坚持到现在🙏 我会在计算机视觉/深度学习的不同领域发布更多内容,所以 加入并订阅 如果你有兴趣了解更多!

Java 中的控制流和条件

原文:https://towardsdatascience.com/control-flow-and-conditionals-in-java-c3da77f59581

用于数据科学的 Java 第 2 部分

克劳迪奥·施瓦茨在 Unsplash 上拍摄的照片

这是介绍用于数据科学的 Java 基础知识的系列文章的第二篇。在之前的帖子中,Java 被介绍为大数据和物联网应用中常用的语言,以及如何在 Java 中创建变量和使用不同的数据类型。在这篇文章中,我们将在这个基础上讨论 Java 中的控制流和条件,这是构建更复杂代码的基础。

If 条件

当考虑控制您的代码流时,您首先要做的是能够在条件为真时运行代码。例如,如果你知道外面很冷,那么你会希望你的电脑潜在地告诉你外套放在哪里。这可以在 Java 中使用if语句来实现。

Java 的工作方式是声明if (condition) {perform some code}。这意味着您首先需要声明if,然后在if之后,您需要将条件放在括号中。如果条件满足,那么在{}括号中指定的任何代码都将运行。简单!

如前所述,这方面的一个例子是,如果天气冷,你的电脑会告诉你穿上外套。这可以通过以下方式实现:

boolean isCold = true;

if (isCold) {
    // executes only if isCold is true
    System.out.println("It's cold, wear a coat!");
}

这里,isCold是必须解析为truefalse的测试条件,它将决定是否运行包含在{}中的代码。

为此,花括号决定了变量的范围。这意味着如果我们在花括号中定义一个变量,那么它只能在花括号中使用,不能在其他地方使用。相反,在花括号外定义的任何变量(不是在不同的花括号中)都可以在花括号内使用!

其他声明

当满足if条件时,您很少想要运行代码。在某些情况下你想运行一些代码if条件被满足,否则你想运行一些其他代码。这可以使用与if语句一起使用的else语句来实现。

这方面的一个例子是在交通灯系统中。如果你开车时看到绿灯,那么你想继续,但如果你看到红灯,那么你需要停下来。这可以编码为:

boolean isLightGreen = true;

if (isLightGreen) {
    System.out.println("Drive!");
} else {
    system.out.println("Stop!");
}

Else if 语句

如果第一个条件失败,然后您希望在运行任何其他代码之前检查另一个条件,那么这个过程会变得更加复杂。这可以使用else if语句来实现。这基本上是当if的第一个条件失败时,运行这段代码if的另一个条件被满足。

建立在交通灯系统上,第二个条件可以是是否有黄灯。这是因为如果有黄灯,那么这通常意味着你应该减速。在这种情况下,你不会想马上停下来,而是先慢下来。

boolean isLightGreen = false;
boolean isLightYello = true;

if (isLightGreen) {
    System.out.println("Drive!");
} else if (isLightYellow) {
    System.out.println("Slow Down!");
} else {
    System.out.println("Stop!");
}

在这种情况下,将首先检查isLightGreen条件。如果是false,则isLightYellow条件将被检查。然后,也只有在那时,如果isLightYellowfalse,那么else语句中的代码将运行。

布尔评估

当运行这些ifelseelse if语句时,我们只想在一条语句评估为truefalse时进入代码块。在这种情况下,我们可以使用比较运算符来检查一个语句是真还是假。为此,我们可以使用:

  • <:小于
  • >:大于
  • <=:小于或等于
  • > =:大于或等于
  • ==:相等

例如,如果我们想检查我们的银行账户中是否有足够的钱来购买一件商品:

double money = 12.3;
double price = 4.10;

if (money >= price){
  System.out.println("Item bought!");
} else {
  System.out.println("Not enough money!");
}

我们可以使用>=来比较运算符将我们拥有的钱是否大于价格的陈述简化为truefalse

逻辑运算符

当然,在某些情况下,我们希望将条件组合在一起,组成更复杂的truefalse条件。这可以使用逻辑运算符来完成:

  • &&:还有
  • ||:或者
  • 没有

例如,如果想要确保我们在银行中有足够的资金,并且价格低于我们的最高价格:

double money = 12.3;
double price = 4.10;
double maxPrice = 4;

if (money >= price && price < maxPrice){
  System.out.println("Item bought!");
} else {
  System.out.println("Not enough money!");
}

在这种情况下,商品没有被购买!

了解这些逻辑运算符的求值顺序很重要,这样可以确保得到预期的结果。为此,评估的顺序是:

  1. ()
  2. !
  3. &&
  4. ||

交换语句

最后,Java 中还有 switch 语句。这使您可以检查变量的值,并根据它可能取值的列表测试它是否相等。这些值(或条件)中的每一个都被称为一个案例,我们可以为其创建不同的行为。

这方面的一个例子是检查自动售货机中的某个号码分配了什么项目和值。除了创建 if 和 else 语句,还可以使用 switch 语句,如下所示:

String item;
double cost;
int passcode;

switch(passcode){
    case 123: 
        item = "Snickers";
        cost = 1.80;
        break;
    case 123: 
        item = "Walkers";
        cost = 2.10;
        break;
    case 123: 
        item = "Lucozade";
        cost = 2.50;
        break;
    default: 
        item = "Unknown";
        cost = 0;
        break;
}

在每一种情况下,都会分配一个项目和成本。每个案例末尾的break意味着代码将转到花括号的末尾,而不是检查其他条件。这确保了一次只执行一个案例。

结尾的最后一个 case 是默认 case,它与 else 语句一样,在没有其他 case 匹配时触发。

结论

Java 是一种广泛使用的编程语言,经常应用在大数据或物联网应用中。这对于任何数据科学家来说都非常有用。通过这种实践,您现在应该能够使用控制流和条件,包括 if、else、else if、布尔求值和 switch 语句,在 Java 中构建更复杂的代码!

如果你喜欢你所读的,并且还不是 medium 会员,请使用下面我的推荐链接注册 Medium,来支持我和这个*台上其他了不起的作家!提前感谢。

https://philip-wilkinson.medium.com/membership

或者随意查看我在 Medium 上的其他文章:

TensorFlow 中的早期停止-防止神经网络的过度拟合

原文:https://towardsdatascience.com/control-the-training-of-your-neural-network-in-tensorflow-with-callbacks-ba2cc0c2fbe8

如何使用回拨在适当的表现下停止训练

尔万·赫斯里Unsplash 上拍照

在本文中,我将解释如何通过使用回调来控制 Tensorflow 中神经网络的训练。回调是在过程中反复调用的功能(例如神经网络的训练),通常用于验证或纠正某些行为。

在机器学习中,我们可以使用回调来定义在训练时期之前、期间或结束时发生的事情。这对于记录性能或在我们的性能指标达到某个阈值时停止训练特别有用。这种机制称为提前停止

例如,如果您设置了 1000 个历元,并且在 200 个历元时已经达到了期望的精度,那么训练将自动停止,避免您可能过度拟合您的模型。让我们看看这是如何在 Tensorflow 和 Python 中实现的。

让我们通过从 Tensorflow 导入 fashion_mnist 数据集来打好基础。我们将使用这个数据集来解释回调是如何工作的。

这是我们的数据集的样子

来源:https://www . research gate . net/figure/Sample-images-from-Fashion-MNIST-dataset _ fig 8 _ 356111457

早期停课班

第二步是创建专门用于提前停止的类。我们将创建一个继承自tf.keras.callbacks.Callback的类,并允许我们在达到 95%的准确率时停止训练。如果通过查看 Tensorflow 模型提供的日志来满足条件,回调将使用 on_epoch_end 函数来停止训练。

这里,我们访问继承自tf.keras.callbacks.Callbackon_epoch_end 方法,并通过对导致训练停止的条件进行编码来覆盖其行为。

让我们继续实现我们的张量流模型。

深度神经网络分类任务

我们将使用一个多层神经网络来对数据集中的衣物进行分类。最好的方法是使用卷积神经网络,但是对于这个例子,深度神经网络也可以。

我们现在准备训练模型。要使用回调,只需将对象放入要提供给模型的fit() 方法中的回调参数的列表中。

训练停止,因为我们已经达到 95%的准确率。图片作者。

下面是如何设置回调来控制一个神经网络的训练!希望你今天学到了新东西👍

保持坚强,度过艰难时刻。这是值得的。干杯!

代码模板

通过自然语言控制网络应用程序,使用 GPT 3 将语音转换为命令

原文:https://towardsdatascience.com/control-web-apps-via-natural-language-by-casting-speech-to-commands-with-gpt-3-113177f4eab1

最后一篇文章展示了 GPT3 的实际应用,对工作流程和源代码细节进行了完整的解释。

自从 OpenAI 发布了 GPT3 并给出了一些 免费积分 进行试用以来,我一直在发表文章:( I)探索它的潜力和局限性,强调它实际上“知道”多少,以及(ii)展示如何实际制作使用它的应用程序,尤其是侧重于客户端 web 应用程序。我评价了 GPT3 关于自然 科学 与一些 积极 消极的发现 ,我展示了如何做出一个 非常聪明的聊天机器人出来 我展示了 如何将它与语音识别和合成 结合起来,以制作一个非常智能的机器人,你可以 自然地与之对话 。 这些和其他例子证明了 GPT3 所提供的巨大能力,也强调了将它集成到 web 应用程序中是多么容易。我认为这将是该系列的最后一篇文章,至少就目前而言,演示最后一个应用:使用 GPT-3 将自然语言中的命令转换为特定于应用程序的命令,然后您可以使用这些命令来控制这些应用程序。

从自然语言到定义的命令

你可能听说过 GitHub Copilot 和类似的人工智能工具,它们根据人类的提示创建代码。这些工具基于神经网络,如 GPT-3 本身,即训练输出与输入一致的文本。例如,GitHub Copilot 本身由 OpenAI Codex 驱动,这是 GPT-3 本身的修改版本。

在自动代码编写工具中,用户以注释的形式编写提示,然后由 AI 模块处理,输出一段有希望执行所需任务的代码(示例)。该工具可以做到这一点,因为它是在数十亿行包含注释的代码上训练出来的。

如果我们想要控制一个有命令行的应用程序,我们在这里需要的基本上是一样的:我们必须阅读(或听到和语音识别)自然语言中的命令,然后生成可以发送到应用程序命令行的代码:

总体布局:自然语言的文本通过键盘输入或从语音中识别,然后通过 GPT-3 进行处理,预先提示一系列自然语言命令对,调整到一个人想要控制的目标应用程序。输出很可能由可以直接应用于目标应用程序的命令组成。作者根据自己的图画和照片组成的图形。

在这里,我将向您展示如何实际实现这个方案,作为控制一个非常特殊的应用程序的方法:JSmol,一个用于网页内分子可视化的 JavaScript 库。您可以在此视频和 twit 中看到运行的示例,其中以自然语言输入或说出的请求被转换为 JSmol 命令并应用于可视化:

如果您现在想亲自尝试一下这个例子,请点击这里:

【T4http://lucianoabriata . alter vista . org/tests/GPT-3/jsmol-gp T3-speech rec-speech synth . html

(你需要一把 GPT-3 的开启钥匙,见这里。)

除了酷之外还有什么用?

我认为这种技术至少有三个明显的好处:

  • 最重要的是,它允许用户像 JSmol 的脚本语言允许的那样精细地控制应用程序,但不需要了解它。事实上,在我实验室一位同事的要求下,我写了这个例子。他曾经指出(我也同意),有太多的程序在做类似的事情,都有自己的命令和脚本语言,很难记住它们。
  • 即使你知道这些命令,但没有正确输入,或者如果语音识别引擎失败,GPT-3 会纠正错误,因为它试图产生 JSmol 一致的命令。
  • 正如我在视频中举例说明的那样,你甚至不需要输入英语的自然语言命令,因为 GPT-3 会“内部翻译”你的输入,将它从任何语言直接转换成 JSmol 的语言。

另外,特别是这个例子是基于网络的,正如我一直强调的,通过完全在网页内工作,你可以在你的笔记本电脑、*板电脑或电脑上运行这个相同的工具,只需将你的网络浏览器指向网页的 URL。(顺便说一句,我再次向你推荐这个免费的托管服务,它包括 JS 和 PHP 支持,因为你需要在 web 应用中使用 GPT-3)。

从开发人员的角度看三个关键点,并深入研究代码

在我们了解这个应用程序如何工作之前,关于 JSmol 作为我们要控制的示例目标应用程序,有三个要点,对于其他应用程序,您必须考虑:

  • JSmol 支持通过脚本语言传递命令,这是简化由 GPT3 产生的命令的执行的关键。
  • 互联网上充斥着关于 JSmol 脚本语言的教程和例子,所以 GPT-3 很可能在培训中见过很多。
  • 即使考虑到上述情况,我们也必须为 GPT-3 提供一个清晰的提示,包括少量学习,以便它“理解”我们希望它的输出中包含类似 JSmol 的命令。

通用工作流程+将自然语言转换为命令

如第一个图中所总结的,工作流的核心是将键入的或从语音中识别的自然语言文本输入到 GPT-3 提示符中,该提示符包含一系列针对用户想要控制的目标应用而调整的自然语言命令对。更详细地说,开始提示包括反映完成自然语言请求(问题)中指示的任务需要什么命令(答案)的成对“问题-答案”句子,并且用户要求的实际请求以问题的形式被附加到提示上。

我上面所说的“问题”和“答案”也可以被认为是自动化代码编写者精神中的“注释”和“代码”。GPT-3 并不在乎我们叫它们什么,甚至不在乎我们如何编码它们,只要我们尊重它们的格式。对于 JSmol 示例,正如您在视频中看到的那样,我使用“Q:”作为自然语言输入,使用“A:”作为 app 命令输出。

因此,给定这段简短的提示(实际的提示更长):

请给我看所有的疏水残基。
A:选择 ala、ile、leu、val、ile、phe、met 线框 50。
问:显示丙氨酸 34 为球体。
答:选择 ala 34 空格填充。
问:用洋红色显示链 b。
A:选择:b;洋红色。
问:将链 A 和 B 显示为绿色表面。
A:选择:A,:b;等值面分子;颜色绿色。隐藏所有的表面。
答:全选;等值面关闭。
问:隐藏残基 33 至 99。
答:选择 33–99;线框关闭;空格填充关闭;卡通关闭。
问:显示 p 链的 5-107 位残基
A:选择 5–107:p;卡通开启;线框 50。
问:请把所有的阴性残基当棒子给我看。
答:选择 asp、glu 线框 50。
问:给我看看谷氨酰胺 154。
A:选择 gln 和 154;线框 50。

当用户发出请求时,如“请将所有阳性残基显示为蓝色棒”,这将添加到提示的末尾,如下所示:

问:请用蓝棒显示所有阳性残留物
A:

然后,GPT-3 将得到一个 JSmol-consistent 命令,它必须从最后一个“A:”开始扩展文本。通过删除“A:”之前的输入,剩下的命令必须发送给 JSmol。

一个看似显而易见但鉴于我得到的一些评论值得澄清的注意事项。当然,GPT 3 号什么都不懂;这只是一个基于数十亿训练令牌连接的统计模型,由我们的提示调整,这(希望)导致它产生正确的命令。上面段落中的“希望”是指不能完全保证输出就是您需要 JSmol 执行的命令。甚至可能不是命令,会让 JSmol 失败。也就是说,产生的命令的质量和准确性取决于 GPT-3 的训练,我们可以通过微调程序来提高,特别是在提示符中提供的少量学习。你可以在http://Lucia noabriata . alter vista . org/tests/GPT-3/jsmol-gp T3-speech rec-speech synth . html查看这个完全相同的示例网页的源代码来查看完整的提示

完整的源代码,从语音识别到 GPT-3 处理和命令执行

我的示例页面的源代码(上面的链接,您可以在大多数浏览器中使用 CTRL+U 看到它)是不模糊的,并在关键行进行了注释,准备好供您全面检查。但是让我在这里补充一些解释:

此处讨论的应用程序的源代码,可从http://lucianabriata . alter vista . org/tests/GPT-3/jsmol-gp T3-speech rec-speech synth . html获得

库、基本 HTML 和控件布局

第一组代码加载了三个库:Jquery,用于简化对 GPT-3 API 的异步调用,正如我在前面的例子中所展示的 Annyang,用于简化语音识别,也如前面所展示的 JSmol,它是用于分子可视化的 JavaScript 库。

从第 14 行开始的脚本标记只配置 JSmol 可视化,然后在第 35 行插入 HTML。

第 37 到 45 行设置了一个 div ,其中包含一系列按钮、复选框和段落,用户可以在其中与机器人进行交互(我说“机器人”是因为我喜欢把这个应用程序想象成“操作 JSmol 的机器人”)。在这些控件中,文本框允许用户键入文本,复选框控制语音识别是否激活(当激活时,识别的文本被发送到文本框),第 44 行的段落将显示由 GPT-3 转换并发送到 JSmol 应用程序的命令。

GPT-3 的 JavaScript 代码

从第 51 行开始,我们定义了用 GPT-3 处理自然语言输入文本的函数。在获得用户提供的 API 键之后,应用程序将其输入附加到核心提示中(第 53 行,注意我们添加了“Q:”和“A:”两个词)。通过对 GPT-3 的异步调用(第 56 行),我们最终获得了一大块数据(第 58 行),其中包括我们的完整提示(即核心提示加上新问题),这些提示是用 GPT-3 提出的 JSmol 命令扩展的。

第 59 行到第 63 行清理了 GPT-3 在数据中返回的文本,删除了 URL、Qs 和 as,以及开始提示符,以便在我称为 textupdate 的变量中,以干净的形式为 JSmol 准备好生成的命令。

第 64 行将命令发送给 JSmol,第 66 行将它们显示在屏幕上。

在这个函数的最后,第 68 行启动了 Annyang 的语音识别,正如我们接下来将看到的,当 GPT-3 处理命令时,它是关闭的。

用于语音识别的 JavaScript 代码

第 73 行打开了一个在页面加载时只调用一次的函数。这个函数在 Annyang ( resul t)中设置了一个回调函数,告诉它在听到并识别出一个短语时该做什么。在记录它听到的内容(第 75 行和第 76 行)之后,如果应用语音命令的复选框打开(第 77 行),该函数显示识别的文本(第 78 行)并调用(第 80 行)在输入上应用 GPT-3 的函数,所有这些都在上面解释过(并在代码的第 51 行中定义)。请注意,在调用 GPT 函数之前,我们也关闭了 Annyang(第 79 行),这样它将停止识别语音,直到它再次被激活(第 68 行)。

一些你可能会喜欢的关于 GPT-3 的文章

www.lucianoabriata.com我写作并拍摄我广泛兴趣范围内的一切事物:自然、科学、技术、编程等等。 成为媒介会员 访问其所有故事(我免费获得小额收入的*台的附属链接)和 订阅获取我的新故事 通过电子邮件 。到 咨询关于小职位 查看我的 服务页面这里 。你可以 这里联系我

从外部数据库控制您的气流 Dag

原文:https://towardsdatascience.com/control-your-airflow-dag-from-an-external-database-f56d88f7df29

荷兰 Zaandam 的 Zaanse Schans(作者)

Apache Airflow 是一个非常流行的框架,用于调度、运行和监控任务,这些任务被分组到 DAG(有向无环图)中。每个 DAG 都有几个描述 DAG 将如何以及何时执行的参数。DAG 本身由安排在流中的任务组成。DAG 参数被定义为 DAG 类的属性,并存储在代码中。这种解决方案在许多情况下是足够的。

然而,dag 的配置可以被委托并存储在别处——在与外部用户的 GUI 链接的一些数据库中。

由此,dag 的一些参数可以在不接触代码源的情况下被定义,例如由非开发者定义。例如,想象一个化学实验室,其中自动化过程由气流控制,化学家可以使用 web 界面改变一些参数。

在这个简短的故事中,我将展示如何使用外部配置源来动态创建和配置 Dag。这里的一个假设是,所有 Dag 在任务和关系方面都是相似的。因此,只有几个参数可以通过数据库进行配置:

  • 调度时间
  • 执行参数

动态配置的 Dag 流(按作者)

该解决方案由两个 Dag 组成:

  • read_config 负责从数据库获取配置
  • dynamic_dags 负责根据配置创建 Dag

读取配置

有人可能会问,为什么我们需要两个 DAG,为什么不将所有内容都放在一个 DAG 中。这是因为 Airflow 处理 Python 文件的方式。调度程序每隔 n 秒扫描一次dags/文件夹中的文件,并使用 Python 解释器对其进行评估。扫描频率由dag_dir_list_interval参数控制。
因此,在评估部分,我们不应该做任何昂贵的动作——显然连接到数据库和读取表是其中之一。

相反,数据库读取部分应该转移到由操作符运行的代码中(比如 PythonOperator )。这正是发生在read_config达格的事情。

在 DAG 中,有一个由 PythonOperator 运行的任务

  • 从数据库中读取配置(即config.dags
  • 将配置放入气流变量中

就是这样。气流变量存储用于保存配置(使用 JSON 格式)。下面是 DAG 的定义:

import logging
from datetime import timedelta

import airflow
import mysql.connector
from airflow import DAG
from airflow.models.connection import Connection
from airflow.models.variable import Variable
from airflow.operators.python import PythonOperator

logger = logging.getLogger("airflow.task")

default_args = {
    "owner": "airflow",
    "depends_on_past": False,
    "retries": 0,
    "retry_delay": timedelta(minutes=5),
}

mysql_connection = Connection.get_connection_from_secrets("mysql")

def read_dags_config():
    db_conn = mysql.connector.connect(host=mysql_connection.host, user=mysql_connection.login,
                                      password=mysql_connection.password, database='config')
    cursor = db_conn.cursor()
    cursor.execute("select id, enabled, schedule, description from config.dags")

    rows = cursor.fetchall()

    if rows is None:
        rows = []

    logger.info(f"Config rows: {rows}")
    if len(rows) > 0:
        Variable.set("dags_config", rows, serialize_json=True)

with DAG(
        "read_config",
        default_args=default_args,
        schedule_interval="@hourly",
        start_date=airflow.utils.dates.days_ago(0),
        catchup=False) as dag:
    PythonOperator(task_id="read-config", python_callable=read_dags_config, dag=dag)

来自数据库的配置每小时准备就绪。这些行被序列化为 JSON 并保存在 Airflow 变量中:

气流中的变量列表(按作者)

动态 DAG

第二个 dag(动态 DAG)负责创建 DAG。该解决方案使用了 Airflow 处理 Python 文件的方式。基本上,在扫描dags/中的文件时,Airflow 会寻找类型为 DAG 的对象。在内部,py 文件由 Python 解释器评估,然后扫描globals()字典。

程序很简单。首先,我们从包含要创建的 Dag 列表的变量中获取配置。接下来,我们遍历列表并运行返回DAG对象的函数。以及作为变量放入 global()字典中的DAG对象。

from datetime import timedelta

import airflow
from airflow import DAG
from airflow.models.variable import Variable
from airflow.operators.python import PythonOperator

default_args = {
    "owner": "airflow",
    "depends_on_past": False,
    "start_date": airflow.utils.dates.days_ago(0),
    "retries": 2,
    "retry_delay": timedelta(minutes=5),
}

def create_dag(dag_id: str, schedule: str = None, description: str = None):
    dag = DAG(
        dag_id,
        default_args=default_args,
        schedule_interval=schedule,
        dagrun_timeout=timedelta(hours=1),
        catchup=False,
        description=description)

    task_1 = PythonOperator(task_id="task_1", python_callable=lambda: x+1, dag=dag)
    task_2 = PythonOperator(task_id="task_2", python_callable=lambda: 1, dag=dag)

    task_1 >> task_2

    return dag

dags_config = Variable.get("dags_config", deserialize_json=True)

for dag_id, schedule, description in dags_config:
    globals()[f"dag-{dag_id}"] = create_dag(f"dag-{dag_id}", schedule, description)

这里,应该强调两个重要部分。一个功能create_dag负责定义任务和它们之间关系的整个过程。最后一部分,迭代 DB 中的配置。注意内置方法globals()的用法,它返回一个字典。

创建的动态 Dag 列表(按作者)

综上所述,气流还是无非是一个常规的 Python 代码。因此,使用语言和生态系统的所有特性没有任何障碍。

我希望你喜欢这个故事,它会对你的日常工作有所帮助。如果您有任何问题或建议,请随时通过 Twitter 联系我。

控制 X 吗?

原文:https://towardsdatascience.com/controlling-for-x-9cb51652f7ad

通过弗里希-沃-洛弗尔定理理解线性回归力学

简介

应用计量经济学通常对建立因果关系感兴趣。即 T 对某个结果 y 的“治疗”效果是什么。在一个简单的双变量案例中,我们可以想象随机将治疗 T =1 分配给一些个体,将 T=0 分配给其他个体。这可以用下面的线性回归模型来表示:

(1)

如果我们假设处理是真正随机分配的,那么 T 与误差项正交,或者用经济学家的行话来说,外生。因此,我们可以估算 eq。(1)使用普通最小二乘法(OLS)并用因果解释解释 T 上的系数估计值——*均治疗效果(ate):

(2)

然而,当我们处理非实验性数据时,几乎总是这样,对感兴趣项的处理与误差项正交,或者,用经济学家的行话来说,内生。例如,假设我们感兴趣的是确定小时候读书时间对个人未来教育成就的治疗效果。没有任何随机分配的时间花在阅读作为一个孩子,估计一个简单的线性回归,如方程。(1)将无法捕捉可能驱动个人花费在阅读书籍上的时间教育程度(即,社会经济地位、父母教育、潜在能力、其他爱好等)的大量附加因素。).因此,在处理非实验性数据时,我们必须依赖于对额外协变量的控制,然后论证治疗现在“与随机分配一样好”,以建立因果关系。这就是所谓的条件独立性假设(CIA)。在上面的教育例子中,我们可以重新定义情商。(1)作为:

(3)

我们现在控制一组观察到的协变量 X 。当且仅当中央情报局成立时,对读数的关键兴趣估计采用因果解释。也就是说,花费在读取上的时间与误差项正交,条件X 上。相当于,

(4)

没有中央情报局,我们的系数估计是有偏差的,我们在因果关系方面的话是有限的。现实地说,为中央情报局辩护通常是相当困难的,而且不幸的是,这种假设是不可直接检验的。事实上,我上面所讨论的是整个计量经济学领域的基本动力,该领域致力于建立、发展和实施准实验研究设计,以建立因果关系,包括但绝对不限于差异中的差异、综合控制和工具变量设计。这些准实验设计旨在利用感兴趣的治疗中的外源性(“几乎是随机的”)变异源 T 来研究 T 对某些结果 y 的因果影响。有一些优秀的计量经济学文本可供那些几乎没有或根本没有计量经济学背景的人阅读,包括尼克·亨廷顿-克莱因的《效应》、斯科特·坎宁安的《因果推理:混音带》或《勇敢而真实的因果推理[1][2][3]约书亚·安格里斯特(Joshua Angrist)和约恩·斯特芬·皮施克(jrn-Steffen Pischke)为感兴趣的人提供了“基本无害的计量经济学”的更深入探讨。[4]

尽管通过单独控制协变量来建立 CIA 特别困难,但计量经济学中有一个重要的定理,它为“控制”额外协变量的真正含义提供了一些非常强大的直觉。最终,这不仅提供了对线性回归潜在机制的更深入理解,还提供了如何概念化关键利益关系(即 TY 的影响)。

弗里希-沃-洛弗尔定理

在 19 世纪,计量经济学家拉格纳·弗里希和弗雷德里克·v·沃发展了一个超级酷的定理(FWL 定理),该定理允许估计线性回归中的任何关键参数,其中首先“部分消除”附加协变量的影响,该定理后来被迈克尔·c·洛弗尔推广。[5][6]首先,快速复习一下线性回归会有所帮助。

给定一组独立变量X,线性回归求解结果 y 的最佳线性预测值,其中 y 的拟合值被投影到由X 跨越的空间上。在矩阵符号中,我们感兴趣的线性回归模型的特征在于:

(5)

线性回归的目标是最小化残差*方和(RSS),因此可以通过以下优化问题来解决:

(8)

取导数并设等于零, (6) 的最优解为:

(9)

这是普通的最小二乘(OLS)估计器,当我们运行线性回归以获得参数估计时,它是幕后的主力。现在,让我们回顾一下是什么让 FWL 如此伟大。

让我们回到我们估算儿童时期阅读的教育回报的例子。假设我们只想获得方程中感兴趣的关键参数。(3);也就是说,儿童时期每月阅读天数对受教育程度的影响。回想一下,为了对我们的估计做出一个因果陈述,我们必须让 CIA 满意。因此,我们可以控制一组额外的协变量 X,然后使用在 (7) 中导出的 OLS 估计器直接估计 (3) 。然而,FWL 定理允许我们在以下 3 步程序中,在读取时获得完全相同的关键参数估计值:

  1. 回归读为仅协变量集 X ,同样,将教育*读为仅协变量集 X*

(8)+(9)

2.存储估计(8)+(9)后的残差,表示为读作** 和教育**

(10)+(11)

3.将教育** 倒退到改为**

(12)

就是这样!

直观地说,FWL 定理分离出由附加协变量解释的阅读(治疗/利益变量)和教育(利益结果 ) 中的变异,然后使用剩余的变异来解释利益的关键关系。这一过程可以推广到任何数量的感兴趣的关键变量。关于这个定理的更正式的证明,参考文献[7]。FWL 定理最*作为去偏置/正交机器学习的理论基础而备受关注,其中步骤 1 和 2 使用机器学习算法而不是 OLS 来进行。有一些非常酷的发展正在弥合计量经济学和机器学习之间的差距,我希望将来有一些关于这些新方法的酷应用的帖子。然而,Matheus Facure Alves 的第 2 部分“勇敢和真实的因果推理”是一个很好的起点。

现在你可能想知道为什么你要经历这个过程来获得完全相同的关键估计值。首先,它为线性回归的机制提供了大量的直觉。第二,它允许你想象你治疗中的剩余变化(读作),这被用来解释你结果中的剩余变化(教育)。让我们来看看实际情况!

FWL 定理应用

在本节中,我们将模拟一个高度程式化的数据集,以提供一个应用 FWL 定理的简化数值示例,来回答我们关于儿童阅读教育回报的经验问题。

假设我们假设了一组人口统计学变量,我们确定这些变量是满足等式 1 中 CIA 所必需的相关混杂因素。(3),从而让我们获得对童年阅读教育回报的因果解释。也就是说,假设我们将关键混杂因素确定为父母双方的*均教育水*(年)( pareduc )、以数万美元计的家庭收入( HHinc )和智商得分( IQ )。我们将为混杂因素人工生成数据集和以下数据生成过程(DGP ),如下所示:

(13)

此外,估计方程。(3)我们必须有关键治疗的措施,他们小时候一个月的*均阅读天数(读作),以及主要结果,他们多年的总教育程度( educ )。我们用高斯误差项和教育误差项中的异方差人工生成这些关键变量,如下所示:

(14)

因为我们知道真实的 DGP,所以感兴趣的参数的真实值是 0.2。让我们把这个 DGP 拿到 Python 上模拟数据:

请注意,通常情况下,DGP 中的所有值都是任意选择的,因此数据很适合用于演示目的。然而,在这个模拟的范围内,我们可以将“阅读”的系数解释如下:*均而言,一个人小时候每月多读一天书,其受教育程度就增加 0.2 年。

 *## Import Relevant Packages
import pandas as pd
import numpy as np
from scipy.stats import skewnorm
import seaborn as sns
import matplotlib.pyplot as plt

## Data Generating Process
df = pd.DataFrame()
n = 10000

# Covariates
df['pareduc'] = np.random.normal(loc=14,scale=3,size=n).round()
df['HHinc'] = skewnorm.rvs(5,loc=3,scale=4,size=n).round()
df['IQ'] = np.random.normal(loc=100,scale=10,size=n).round()

# Childhood Monthly Reading
df['read'] = (-25+
              0.3*df['pareduc']+
              2*df['HHinc']+
              0.2*df['IQ']+
              np.random.normal(0,2,size=n)).round()

df = df[(df['read']>0) & (df['read']<31)] # Drop unrealistic outliers

# Education Attainment
df['educ'] = (-15+
              0.2*df['read']+
              0.1*df['pareduc']+
              1*df['HHinc']+
              0.2*df['IQ']+
              df['read']/15*np.random.normal(0,2,size=len(df)).round())

## Plot Simulated Data
fig, ax = plt.subplots(3,2,figsize=(12,12))
sns.histplot(df.HHinc,color='b',ax=ax[0,0],bins=15,stat='proportion',kde=True)
sns.histplot(df.IQ,color='m',ax=ax[0,1],bins=20,stat='proportion',kde=True)
sns.histplot(df.pareduc,color='black',ax=ax[1,0],bins=20,stat='proportion',kde=True)
sns.histplot(df.read,color='r',ax=ax[1,1],bins=30,stat='proportion',kde=True)
sns.histplot(df.educ,color='g',ax=ax[2,0],bins=30,stat='proportion',kde=True)
sns.regplot(data=df,x='read',y='educ',color='y',truncate=False,ax=ax[2,1])
plt.show()*

数据看起来有点像:

图 1

右下角的图表提供了 educread 的散点图和原始回归线。从表面上看,这种关系表明,小时候每月阅读的天数和教育程度之间存在非常强的正相关关系。然而,我们知道,通过构造,这并不是 educread 之间的真实关系,因为存在共同的混杂协变量。我们可以通过回归分析更正式地量化这个结果和偏差。现在,让我们继续估计简单的回归(例如,等式)。(3)减去 X ),所有相关协变量的多元回归(即等式。(3))和 FWL 三步过程(即,方程。(8)-(12)):

*import statsmodels.formula.api as sm

## Regression Analysis

# Naive Regression
naive = sm.ols('educ~read',data=df).fit(cov_type="HC3")

# Multiple Regression
multiple = sm.ols('educ~read+pareduc+HHinc+IQ',data=df).fit(cov_type='HC3')

# FWL Theorem
read = sm.ols('read~pareduc+HHinc+IQ',data=df).fit(cov_type='HC3')
df['read_star']=read.resid

educ = sm.ols('educ~pareduc+HHinc+IQ',data=df).fit(cov_type='HC3')
df['educ_star']=educ.resid

FWL = sm.ols("educ_star ~ read_star",data=df).fit(cov_type='HC3')

## Save Nice Looking Table
from stargazer.stargazer import Stargazer

file = open('table.html','w')

order = ['read','read_star','HHinc','pareduc','IQ','Intercept']
columns = ['Naive OLS','Multiple OLS','FWL']
rename = {'read':'Read (Days/Month)','read_star':'Read*','hhincome':'HH Income',
          'pareduc':"Avg. Parents Education (Yrs)"}

regtable = Stargazer([naive, multiple, FWL])
regtable.covariate_order(order)
regtable.custom_columns(columns,[1,1,1])
regtable.rename_covariates(rename)
regtable.show_degrees_of_freedom(False)
regtable.title('The Simulated Effect of Childhood Reading on Educational Attainment')

file.write(regtable.render_html())
file.close()*

回归结果是:

表 1

上面的表 1 给出了回归输出结果。我们可以立即观察到,由于与教育程度和童年阅读呈正相关的混杂变量,对阅读的简单回归估计值是向上偏的。当我们包括列(2)中的额外协变量时,我们得到的估计值接* DGP 中构建的真实值 0.2。正如所料,FWL 三步法得出了完全相同的估计值!

回归中符号偏差的一般经验法则是 cov(结果,X)的符号乘以 cov(治疗,X)的符号。通过构造,我们得到 cov(educ,X)>0 和 cov(read,X)>0,因此是正偏置。

因此,我们现在已经展示了 FWL 被用于获得相同的估计,但是 FWL 的真正力量在于绘制真实关系的能力。下图 2 显示了未考虑协变量的原始回归的初始关系,以及 FWL 过程的残差关系,其中噪声来自 DGP 的随机误差项。在这种情况下,FWL 坡才是真正的关系!我们可以看到斜率的估计是多么的不同。这就是 FWL 定理的真正力量所在!它允许我们在剔除已经被额外协变量解释的变异后,可视化治疗和结果之间的关系。

图 2

讨论

我们已经深入讨论了弗里希-沃-洛弗尔定理,并提供了一种直观的方法来理解当人们对治疗参数感兴趣时,对回归模型中的协变量进行“控制”意味着什么。这是一个强有力的定理,并为多年来发展的许多计量经济学结果提供了强有力的基础。

FWL 提供了一个强有力的机制,通过这个机制,在剔除了额外协变量的影响后,可以可视化结果和治疗之间的关系。事实上,FWL 可以用来研究任何两个变量之间的关系,以及协变量在解释它们之间的潜在关系时所起的作用。我建议在您对两个变量之间的关系以及附加协变量在混淆这种关系中的作用感兴趣的数据集上进行尝试!

希望你从这篇帖子中获得了一些新的知识!

参考

[1] N .亨廷顿-克莱因,效果:研究设计和因果关系介绍 (2022)。

[2] S .坎宁安,《因果推断:大杂烩》 (2021)。

[3] M. F .阿尔维斯,(2021)勇敢而真实的因果推论。

[4] J. Angrist & J.S. Pischke,大部分无害的计量经济学:一个经验主义者的伴侣 (2009)。普林斯顿大学出版社。

[5]弗里希,拉格纳和沃。与个体趋势相比的部分时间回归(1933)。计量经济学:计量经济学学会杂志,387–401 页。

[6]洛弗尔。经济时间序列的季节调整和多元回归分析(1963)。美国统计协会杂志58(304):993–1010。

[7]洛弗尔。FWL 定理的一个简单证明(2008)。经济教育杂志。39 (1): 88–91.

感谢您阅读我的帖子!我在 Medium 上的帖子试图利用 计量经济学 统计/机器学习 技术来探索现实世界和理论应用。此外,我试图通过理论和模拟提供某些方法论的理论基础。最重要的是,我写作是为了学习!我希望把复杂的话题变得更容易理解。如果你喜欢这个帖子,请考虑 跟随我上中

Dag 和控制变量

原文:https://towardsdatascience.com/controls-b63dc69e3d8c

因果数据科学

如何使用有向无环图选择因果推理的控制变量

所有图片由作者提供,由美人鱼-js 生成

在分析因果关系时,很难理解哪些变量是进行分析的条件,即如何“分割”数据,以便我们在比较苹果和苹果。例如,如果你想了解拥有一台*板电脑对学生成绩的影响,比较学生社会经济背景相似的学校是有意义的。否则,风险在于只有更富裕的学生才能买得起*板电脑,如果不加以控制,我们可能会将这种影响归因于*板电脑,而不是社会经济背景。

当感兴趣的治疗来自适当的随机实验时,我们不需要担心其他变量的条件作用。如果*板电脑在学校之间随机分配,并且我们在实验中有足够多的学校,我们就不必担心学生的社会经济背景。以一些所谓的“控制变量”为条件进行分析的唯一好处可能是功率的增加。然而,这是一个不同的故事。

在这篇文章中,我们将简要介绍有向无环图,以及它们如何有助于选择变量来进行因果分析。Dag 不仅为我们在分析中需要包括哪些变量提供了直观的视觉感受,还提供了我们不应该包括哪些变量以及为什么。

有向无环图

定义

有向无环图 ( DAG s)提供了数据生成过程的可视化表示。随机变量用字母表示(如 X ),因果关系用箭头表示(如→)。例如,我们解读

作为 X (可能)原因 Y 。我们称一条路径为两个变量和**之间的任意连接,独立于箭头的方向。如果所有的箭头都指向前方,我们称之为因果路径,否则我们称之为寄生路径。**

作者图片

在上面的例子中,我们在 XY 之间有一条路径,通过变量【z₁】【z₂】【z₃】。既然不是所有的箭头都指向前方,那么路径就是乱真XY 没有因果关系。实际上,变量【z₂】是由【z₃】共同造成的,因此阻断了路径。**

Z₂ 被称为对撞机

我们分析的目的是评估两个变量 XY 之间的因果关系。有向无环图是有用的,因为它们为我们提供了关于哪些其他变量 Z 的指示,我们需要在这些变量上条件我们的分析。以一个变量为分析条件意味着我们保持它不变,并得出我们的结论其他条件不变。例如,在线性回归框架中,插入另一个回归变量 Z 意味着我们在给定X条件Z的观测值上,计算 Y 的条件期望函数的最佳线性逼*。**

因果关系

为了评估因果关系,我们要关闭 XY 之间的所有伪路径。现在的问题是:

  • 一个路径什么时候打开?如果不包含对撞机。否则为关闭
  • 如何关闭一个打开的路径?您在上设定至少一个中间变量。
  • 你如何打开一个封闭的路径?你的条件是沿途所有的碰撞器。

假设我们再次对 XY 的因果关系感兴趣。让我们考虑下图:

作者图片

在这种情况下,除了直接路径之外,通过变量【z₁】【z₂】Z₃ ,在 XY 之间还有三条非直接路径

让我们考虑这样的情况,我们分析 XY 之间的关系,忽略所有其他变量。

  1. 通过 Z₁ 的路径是开放的但是它是虚假的****
  2. 通过t39】z₂t41】的路径是因果****
  3. 通过 Z₃ 的路径是闭合的既然 Z₃碰撞器而且是乱真的****

让我们画同样的图,用灰色的变量表示我们正在调节的变量,用虚线表示闭合路径,用红线表示虚假开路,用绿线表示因果开路。

作者图片

在这种情况下,要评估之间的因果关系,我们需要通过关闭**【z₁】的路径。我们可以通过对 Z₁的进行条件分析来做到这一点。******

作者图片

现在我们能够通过对【z₁】的条件作用来恢复x 与y 之间的因果关系。******

如果我们也在调节 Z₂会发生什么?在这种情况下,我们将关闭通过的路径,只留下 XY 之间的直接*路径打开。然后我们将只恢复 XY直接效果,而不是间接效果。*****

作者图片

如果我们也在条件作用于 Z₃ 会发生什么?在这种情况下,我们将打开通过 Z₃ 的路径,这是一条虚假路径。然后我们将而不是能够恢复 XY 的因果关系。

作者图片

例如:班级人数和数学成绩

假设你对班级规模对数学成绩的影响感兴趣。大班对学生的表现是好是坏?

假设数据生成过程可以用下面的 DAG 来表示。

作者图片

感兴趣的变量被突出显示。而且,ability周围的虚线表示这是一个我们在数据中没有观察到的变量。

我们现在可以加载数据并检查它看起来像什么。数据是模拟的,你可以在这里找到原始数据生成过程

**from src.dgp import dgp_schooldf = dgp_school().generate_data()
df.head()**

为了估计class sizemath scores的因果影响,我们应该以哪些变量作为回归的条件?

首先,让我们看看,如果我们不以任何变量为条件进行分析,而只是对class size进行math score回归,会发生什么。我们使用 statsmodels 软件包进行统计分析。

**import statsmodels.formula.api as smfsmf.ols('math_score ~ class_size', df).fit().summary().tables[1]**

在表格的第二行,我们可以看到估计的感兴趣系数(class size)coef及其估计的标准误差(std err)。class_size的影响是负的,在统计上不同于零(具有非常低的 p 值,P>|t|=0.003)。

但是我们应该相信这个估计的效果吗?没有任何控制,这是我们正在捕捉的效果的 DAG 表示。

作者图片

有一个通过good school寄生路径,该路径使偏向我们估计的系数。直觉上,被更好的学校录取会提高学生的数学成绩,更好的学校可能会有更小的班级规模。我们需要控制学校的质量。

**smf.ols('math_score ~ class_size + good_school', df).fit().summary().tables[1]**

现在估计class sizemath score的影响是无偏!的确,数据生成过程中的真实系数是 0.2

作者图片

如果我们用控制所有变量会发生什么?

**smf.ols('math_score ~ class_size + good_school + math_hours + class_year + hist_score', df).fit().summary().tables[1]**

系数再次被偏置。为什么?

我们通过控制hist score打开了一条新的伪路径。事实上,hist score是一个对撞机,对它的控制打开了一条通过hist scoreability的路径,否则这条路径是关闭的。

作者图片

这个例子的灵感来自下面的推文。

结论

在这篇文章中,我们看到了如何使用有向无环图来选择因果分析中的控制变量。Dag 是非常有用的工具,因为它们提供了随机变量之间因果关系的直观图形表示。与“信息越多越好”的普遍直觉相反,有时包括额外的变量可能会使分析产生偏差,妨碍对结果的因果解释。特别是,我们必须注意不要包括打开原本会关闭的虚假路径的碰撞器。

参考

[1] C .西内利,A .福尼,j .珀尔,好与坏控制的速成班 (2018),工作论文**

[2] J. Pearl,因果关系 (2009),剑桥大学出版社**

[3] S .坎宁安,《因果推论》第三章(2021),耶鲁大学出版社**

密码

你可以在这里找到 Jupyter 的原始笔记本:

*****https://github.com/matteocourthoud/Blog-Posts/blob/main/notebooks/controls.ipynb *****

感谢您的阅读!

真的很感谢!🤗如果你喜欢这个帖子并且想看更多,可以考虑 关注我 。我每周发布一次与因果推断和数据分析相关的主题。我尽量让我的帖子简单而精确,总是提供代码、例子和模拟。

还有,一个小小的 免责声明 :我写作是为了学习所以错误是家常便饭,尽管我尽力了。当你发现他们的时候,请告诉我。也很欣赏新话题的建议!

Python 中方便的调度程序

原文:https://towardsdatascience.com/convenient-scheduler-in-python-2adbb57be94f

用 python 调度 ETL 任务的小规模便捷方法。

一个永远悬而未决的任务的例子,波兰 2021 。(作者供图)。

介绍

Python 已经成为一种通用语言。它尤其常用于数据科学中的分析和解决算法问题,但在 web 开发中也很流行。这种组合使它成为各种提取-转换-加载(ETL)任务的合理选择。

然而,这些任务中的许多都相当小,不需要大型框架,如气流Luigi 。当轮询一个或多个 web 页面的数据时,一个简单的 python 脚本加上 crontab 就足够了。尽管如此,当一个项目变得稍微大一点时,使用 cron 管理多个作业可能会变得很麻烦。同时,“小作业”的 Airflow 裸装至少需要 4GB RAM 和 2 个 CPU(此处)。考虑到 AWS 的成本,它至少是一个一直运行的 t2.small 实例。

有中间的吗?小到可以使用,比如说 t2.nano (非常便宜)并且相当“可维护”和“可扩展”?

在这篇文章中,我想和你分享一个简单的方法,它使用 python 的 schedule 包,并做了一些修改。

Python 调度程序

Python schedule 库提供了简单的任务调度。它可以使用pip来安装,并且非常容易使用。不幸的是,文档没有提供在更大的项目中使用它的例子:

import schedule
import time

def job():
    print("I'm working...")

    # Run job every 3 second/minute/hour/day/week,
    # Starting 3 second/minute/hour/day/week from now
    schedule.every(3).seconds.do(job)
    schedule.every(3).minutes.do(job)
    schedule.every(3).hours.do(job)
    schedule.every(3).days.do(job)
    schedule.every(3).weeks.do(job)

    # Run job every minute at the 23rd second
    schedule.every().minute.at(":23").do(job)

    # Run job every hour at the 42rd minute
    schedule.every().hour.at(":42").do(job)

    # Run jobs every 5th hour, 20 minutes and 30 seconds in.
    # If current time is 02:00, first execution is at 06:20:30
    schedule.every(5).hours.at("20:30").do(job)

    # Run job every day at specific HH:MM and next HH:MM:SS
    schedule.every().day.at("10:30").do(job)
    schedule.every().day.at("10:30:42").do(job)

    # Run job on a specific day of the week
    schedule.every().monday.do(job)
    schedule.every().wednesday.at("13:15").do(job)
    schedule.every().minute.at(":17").do(job)

    while True:
        schedule.run_pending()
            time.sleep(1)

正如您所看到的,所有的函数都在模块级别被调用,这对于将它放在脚本中是可以的。但是,如果您有几个不同的作业,代码很快就会变得混乱,特别是如果不同的调用需要不同的参数。

换句话说,利用面向对象的方法并围绕它定义一些“架构”可能更好。

在项目中使用它

为了便于讨论,假设我们有一组专用的 ETL 任务,使用下面的抽象类建模:

from abc import ABC, abstractmethod
from typing import Any, Dict, TypeVar

E = TypeVar("ETL")

class BaseETL(ABC):
    def __init__(self, **kwargs: Dict) -> None:
        self.raw_data = None
        self.transformed_data = None

    @abstractmethod
    def extract(self, **kwargs: Dict) -> E:
        ...

    @abstractmethod
    def transform(self, **kwargs: Dict) -> E:
        ...

    @abstractmethod
    def load(self, **kwargs: Dict) -> Any:
        ...

    def run(self, **kwargs: Dict) -> None:
        self.extract(**kwargs).transform(**kwargs).load(**kwargs)

任何实现 ETL 过程的类都会继承这个基类。例如,extract方法可以获取一个网站。然后transform将原始 HTML 转换成数据库可接受的格式。最后,load会将数据保存到数据库中。按照这个顺序执行的所有方法都可以使用run方法包装。

现在,在定义了 ETL 类之后,我们希望通过schedule模块以一种很好的方式来调度它们。

两个示例 ETL 任务

为了简洁,在下面的例子中,让我们跳过继承,只关注run方法。假设他们的extracttransformload方法在别处实现。

etl.py

class DummyETL:  # normally DummyETL(BaseETL)
    def __init__(self, init_param: int) -> None:
        # super().__init__()  # - not needed here
        self.init_param = init_param

    def run(self, p1: int, p2: int) -> None:
        name = self.__class__.__name__
        print(f"{name}({self.init_param}, p1={p1}, p2={p1})")

class EvenDummierETL:  # same...
    def __init__(self, init_param: int) -> None:
        # super().__init__()  # - same
        self.init_param = init_param

    def run(self, p1: int) -> None:
        name = self.__class__.__name__
        print(f"{name}({self.init_param}, p1={p1})")

例如,构造函数的参数可以指定用于抓取的页面的 URL。方法的参数可以用来传递秘密。

现在,我们已经定义了 ETL 类,让我们创建一个单独的注册中心来将流程与某种时间表关联起来。

注册表. py

import schedule

from etl import DummyETL, EvenDummierETL

def get_registry():
    dummy_etl = DummyETL(init_param=13)
    dummier_etl = EvenDummierETL(init_param=15)

    return [
        (dummy_etl, schedule.every(1).seconds),
        (dummier_etl, schedule.every(1).minutes.at(":05")),
    ]

get_registry功能是定义时间表的地方。尽管参数的值是硬编码的,但是您可以考虑函数从配置文件中加载它们的情况。无论哪种方式,它都会返回一个元组列表,这些元组匹配带有Job的 ETL 对象(来自schedule)。注意,这是我们的约定。作业尚未与任何特定的Scheduler相关联(同样来自schedule)。然而,公约允许我们在项目的任何其他部分这样做。我们不必将它们与模块级对象绑定,如文档示例所示。

我们基于调度程序的调度程序

最后,让我们创建一个新的类来激活整个机制。

scheduler.py

import time
from typing import Dict, List, Tuple, TypeVar

from schedule import Job, Scheduler

from etl import DummyETL, EvenDummierETL
from etl import E  # we could do so from e.g. etl.base

S = TypeVar("Scheduler")

class TaskScheduler:
    def __init__(self, registry: List[Tuple[E, Job]]) -> None:
        self.scheduler = Scheduler()
        self.registry = []

        for task, job in registry:
            self.registry.append(task)
            self.scheduler.jobs.append(job)

    def register(self, run_params: Dict) -> S:
        jobs = self.scheduler.get_jobs()
        for task, job in zip(self.registry, jobs):
            params = run_params.get(task.__class__.__name__)
            job.do(task.run, **params)

        return self

    def run(self, polling_seconds: int) -> None:
        while True:
            time.sleep(polling_seconds)
            self.scheduler.run_pending()

我们的TaskScheduler使用组合来创建一个单独的Scheduler实例,并向其中添加先前注册的作业。尽管不是强制的,我们使用typing来给出一个强有力的提示,告诉构造函数应该提供什么来正确地注册作业。然后,register方法是一个提供绑定的独立方法。最后,同样重要的是,run激活机器。

使用此实现的脚本如下所示:

run.py

from registry import get_registry
from scheduler import TaskScheduler

if __name__ == "__main__":
    run_params = {
        "DummyETL": dict(p1=1, p2=2),  # e.g. from env vars
        "EvenDummierETL": dict(p1=3),
    }

    registry = get_registry()  # e.g. from script's args or config
    task_scheduler = TaskScheduler(registry).register(run_params)
    task_scheduler.run()

这个解决方案最弱的一点可能是在run_params字典中使用__class__.__name__作为键的约定。然而,考虑到这种方法的简单性,它可能是可以的,特别是如果这些参数是在运行时定义的。有很多选择,其中之一是创建一个额外的抽象层,比如像DummyTask这样的对象,作为 ETL 对象和注册中心之间的桥梁。

任务调度的另一种方法

回到TaskScheduler,我们也可以通过继承来定义它,而不是像以前一样通过组合来定义。这将意味着扩展schedule的原生Scheduler类的功能。在这种情况下,TaskScheduler如下所示:

class TaskScheduler(Scheduler):  # <- here
    def __init__(self, registry: List[Tuple[E, Job]]) -> None:
        super().__init__()  # <- here
        self.registry = []

        for task, job in registry:
            self.registry.append(task)
            self.jobs.append(job)  # <- here

    def register(self, run_params: Dict) -> S:
        jobs = self.get_jobs()  # <- here
        for task, job in zip(self.registry, jobs):
            params = run_params.get(task.__class__.__name__)
            job.do(task.run, **params)

        return self

    def run(self, polling_seconds: int) -> None:
        while True:
            time.sleep(polling_seconds)
            self.run_pending()  # <- and here

你决定哪种方式更好,如果有的话;).

结论

在这篇简短的文章中,我们展示了如何扩展简单的schedule模块来创建一个小型 ETL 工作机器。最重要的是,这种方法允许在一个小项目中更好地组织代码,而不必去找大炮。

最初发表于https://zerowithdot.com

对话式 BI:文本到 SQL

原文:https://towardsdatascience.com/conversational-bi-text-to-sql-c9f52a89acc5

用自然语言查询 SQL 数据库的艺术

Pic 鸣谢:探索未知,作者 Soma Biswas (Flickr: 链接,经允许转载)

介绍

“商务智能的未来是对话式的”——这是 Gartner 和其他分析师在过去几年中一直告诉我们的。

让我们关注结构化数据,更准确地说是关系数据。这形成了大多数商业智能(BI)世界的底层存储格式,无论您是交互查询数据库还是在 Tableau、Power BI、Qlik Sense 等中构建报告。与这种存储*台交互的主要语言是 SQL。我们已经看到了这一领域的一些产品,例如 Power BI Q & A ,Salesforce Photon

在本文中,我们讨论的是将自然语言查询(NLQ)翻译成 SQL,也称为数据库自然语言接口(NLIDB)。

例如,让我们考虑一个包含语言和人口详细信息的国家表——说明如下:

国家表:国家 ID |名称|语言|人口数
NLQ1: 哪个国家的人口数最多? SQL1: Select Name,max([人口数])from Country;

大多数自然语言问答系统的核心[1]是一个自然语言理解单元(NLU)模块,它试图通过提取和分类“话语”来理解 NLQ 的意图。简而言之,人们可以将话语视为句子中的关键短语,例如国家、最大值、人口、计数

图:文本到 SQL 参考架构(图片由作者提供)

下一步是根据这些信息生成相应的 SQL 查询。因此,我们需要一个转换/映射逻辑来将‘Country’映射到‘Country’表(要查询的表),将‘maximum’映射到 MAX SQL 函数,将‘Population Count’映射到‘Population Count’列。这就是事情开始变得具有挑战性的地方。

将 NLQ 语句映射到正确的 SQL 操作符。首先,在确定一个话语是否对应于表、列、主/外键、SQL 操作符时,这是非常重要的。

例如,在没有数据库模式的任何固有知识的情况下,映射逻辑很难确定这种情况下的“计数”是指列“人口计数”,而不是 SQL 函数计数。对于复杂的查询,这个问题变得更加严重,例如,

哪种语言被最多的国家使用?

其 SQL 翻译将涉及两个 SQL 函数:MAX & COUNT。复杂查询的其他例子包括我们需要连接多个表的场景。

NLQ — SQL 翻译深度探讨

在这一节中,我们确实深入问题领域,反思现有的文献/方法,以理解所涉及的技术挑战。

该领域主要引用了两个基准数据集:

  • WikiSQL :是一个用于开发自然语言接口的大型带注释语料库,随论文一起介绍[2]。
  • Spider 是一个大规模带注释的语义解析和文本转 SQL 数据集。 SParC 是 Spider 的上下文相关/多回合版本, CoSQL 是 Spider 和 SParC 数据集的对话版本。有关详细讨论,请参考随附的论文[3]。

正如 Spider 在其介绍性文本中所强调的,任何 NLIDB 解决方案不仅需要理解底层数据库模式,而且还应该推广到新的模式。泛化的挑战在于:( a)为语义解析器编码数据库模式,( b)在给定的 NLQ 中对数据库列、键及其提及之间的对齐进行建模[4]。

在这种背景下,让我们看看一些试图将(缺失的)数据库模式知识编码到神经网络中的工作。有向图是一种编码数据库模式关系的流行形式。 [4]提出了一个统一的框架来解决文本到 SQL 编码器中的模式编码、链接和特征表示。[5]用图形神经网络对数据库模式进行编码,这种表示在编码器-解码器语义解析器中的编码和解码时都使用。[6]提出了一种数据库模式交互图编码器,以利用数据库模式项的历史信息。在解码阶段,使用 gate 机制来衡量不同词汇的重要性,然后预测 SQL 标记。

作为文本到 SQL 生成器的预先训练的大型语言模型[7]在一定程度上有所帮助,特别是。,通过利用注意机制对表名和列名进行编码[8]。但是,对于复杂的 SQL 操作,他们仍然需要处理模式关系。

论文显示了在嵌入数据库模式方面的重大进展,然而,它们仍然是特定于所考虑的数据集的;并且不能很好地推广到新的领域/模式。

解决方案指针

在这一节中,我们将考虑如何最好地将这种缺失的领域知识/数据库模式关系添加到文本到 SQL 生成器中。

手操纵进场着陆

今天,大多数问答系统都由一个自然语言理解(NLU)单元组成,该单元被训练成以受监督的方式识别用户的查询。这包括目前市场上可用的 Q & A 系统,例如谷歌 DialogFlow ,亚马逊 [Lex](http://The core of such chatbots is an intent recognition NLU, which is trained with hard-coded examples of question variations.) ,微软 LUISRASA

因此,首先需要通过提供一组 nlq、问题变体及其相应的答案来训练他们——在本例中是相应的 SQL 查询。

除了“意图”和“话语”,定制问答系统的一个重要部分是提供“实体”[9]。实体是指领域特定的词汇,例如,在 HR 应用程序的上下文中,它们可以指组织的办公室位置。

图 3:(说明性的)IBM Watson Assistant 中的手动配置

这里的要点是,类似于配置/训练聊天机器人,我们也可以手动地以数据库模式的形式输入领域知识,以改进 NLIDB 系统中文本到 SQL 的生成。

为了澄清,SQL 解析器可以提取表、列名、键关系等。,来自基础数据定义语言(DDL)规范文件。

因此,在这种情况下,需要手动输入的知识是表、列及其关系的自然语言描述——这是大多数数据库文档所缺少的。

虽然手动浓缩有效,并且通常是最可靠的方法;重要的是要记住,NLIDB 系统主要面向业务用户,即报告/仪表板的消费者;他们可能不太熟悉技术数据输入。此外,这不是一次性的数据输入,每次底层数据库模式发生变化时,都需要对编码的领域知识进行调整。

基于主动/强化学习的自动化方法

引导文本到 SQL 生成器的一个好方法是从现有的 SQL 查询日志和 BI 报告中学习。公*地说,大多数 NLIDB 系统将补充现有的 BI *台。因此,利用历史 SQL 日志和现有报告/仪表板来了解最常见的 SQL 查询,从而了解可用于初始培训的 nlq 是有意义的。

可以通过引入辅助任务来提高该初始模型的泛化能力,该辅助任务可以明确地学习 NLQ 中的实体与模式中的表、列、键名之间的映射[10]。最*的工作已经将其扩展到少数镜头学习任务,例如[11]提出了一种有效的元学习策略,该策略利用两步梯度更新来迫使模型学习对零镜头表的泛化能力。

强化学习(RL)方法在这种情况下也很有趣,其中可以训练一个深度 Q-网络(DQN)代理来“评分”新的(看不见的)查询,以便可以有效地添加它们来扩充(离线)训练数据集。例如,[12]提出了一种基于 RL 的自我改进的企业聊天机器人,它显示出在 20-30 个训练周期内,性能从最初的 50%成功率增加到 75%。

图:基于强化学习的问答训练数据集的扩充(图片由作者提供)

未来的工作

最后,我们对未来进行了一些思考。对于 text-to-SQL,主要目标是重新创建 SQL 查询到数据库的范例,使用自然语言查询(NLQs)。

我们相信,对话式 BI 将更具颠覆性,能够以新的方式与数据库(或一般的数据存储)进行交互。

例如:

  • 元数据机器人:鉴于企业数据库的复杂性,以及随之而来的对它们进行编码的困难;也许我们开始着手解决这个问题的方式是错误的。如果我们能为用户提供一个能够回答查询的 Q & A 系统(姑且称之为元机器人——元数据查询中的元,与元/脸书无关)。数据库架构,例如,“哪个表包含瑞士的销售数据?”以及针对 SQL 操作符的某种自动完成功能,例如,“我们在一个表中有德国和西班牙的销售数据吗?”,由相应表上的连接/过滤器回答;用户将能够高效地编写他们的 SQL 查询,而不需要任何高级的 SQL 知识。
  • 增量查询:前一点已经暗示过了。今天的查询大多是一次性的。另一方面,我们的谈话有一个流程——我们继续以前说过的话——基于历史背景[13]。是的,存储过程按顺序执行 SQL 查询,但是,它是预定义的逻辑。对话式 BI 将能够实时地逐步细化查询结果,直到用户找到他/她正在实时寻找的数据。

图:增量查询(作者图片)

参考

  1. D.比斯瓦斯。聊天机器人&自然语言搜索。走向数据科学,https://towardsdatascience . com/chatbots-natural-language-search-cc 097 f 671 B2B
  2. 钟,熊和理查德索契。2017. Seq2SQL:使用强化学习从自然语言生成结构化查询https://arxiv.org/abs/1709.00103
  3. 陶宇等 2018。 Spider:用于复杂和跨领域语义解析以及文本到 Sql 任务的大规模人工标注数据集https://arxiv.org/abs/1809.08887
  4. 王柏林等人。艾尔。2020. RAT-SQL:文本到 SQL 解析器的关系感知模式编码和链接。进行中。计算语言学协会第 58 届年会。https://doi.org/10.18653/v1/2020 . ACL-main . 677
  5. 本·博金,马特·加德纳,乔纳森·贝兰特(2019)。用图形神经网络表示模式结构,用于文本到 SQL 解析。ACL,https://arxiv.org/pdf/1905.06241.pdf
  6. 蔡和万晓军。2020. IGSQL:基于数据库模式交互图的神经模型,用于依赖上下文的文本到 SQL 生成。进行中。2020 年自然语言处理经验方法会议(EMNLP),https://aclanthology.org/2020.emnlp-main.560.pdf
  7. 林,谢文伟,索彻,r .,,熊,C. (2020)。为跨域文本到 SQL 语义解析桥接文本和表格数据调查结果https://arxiv.org/abs/2012.12627
  8. Bahdanau、Dzmitry、Kyunghyun Cho 和 Yoshua Bengio。通过联合学习对齐和翻译的神经机器翻译https://arxiv.org/pdf/1409.0473.pdf
  9. W.沙拉比、a .阿兰特斯、T. G .迪亚兹和 c .古普塔。从大规模特定领域知识库构建聊天机器人:挑战与机遇, 2020,https://arxiv.org/pdf/2001.00100.pdf
  10. 常,刘,汤,黄,何,周,等(2020)。带辅助任务的零触发文本到 SQL 学习https://arxiv.org/pdf/1908.11052.pdfAAAI
  11. 陈,杨,郭,徐,王,邱,齐,王,李,洪(2021)。利用表格内容,通过元学习实现文本到 SQL 的零转换https://arxiv.org/pdf/2109.05395.pdfAAAIhttps://arxiv.org/pdf/2109.05395.pdf
  12. E.里恰尔代利·比斯瓦斯。基于强化学习的自我改进聊天机器人。RLDM 2019,https://towards data science . com/self-improving-chatbots-based-on-reinforcement-learning-75 CCA 62 debce
  13. 南雷迪,陈,曼宁。 CoQA:会话式问答挑战。计算语言学协会汇刊 2019,https://doi.org/10.1162/tacl_a_00266

音频数据的会话情感分析

原文:https://towardsdatascience.com/conversational-sentiment-analysis-on-audio-data-cd5b9a8e990b

分析言语中的情感

图为 Unsplash 上的

情感分析,也称为观点挖掘,由于其不同的工业应用,是自然语言处理(NLP)中的一个热门任务。在将 NLP 技术专门应用于文本数据的情况下,主要目标是训练一个模型,该模型可以在不同的情感类别之间对给定的文本片段进行分类。下图显示了情感分类器的高级概述。

情感分析模型概述(图片由作者提供)

例如,三类分类问题的类可以是PositiveNegativeNeutral。三类情感分析问题的一个例子是流行的 Twitter 情感分析数据集,这是一个实体级的情感分析任务,针对 Twitter 上各种用户发布的多语言推文。

虽然 NLP 中的大多数先前的研究和开发主要集中在对文本应用情感分析,但是最*,我们已经看到基于语音的交互工具在用户中的大规模采用和流行,使得研究人员和组织在语音空间中构建情感分类器。

因此,这篇文章将展示如何使用 AssemblyAI APIPython 构建一个基于对话数据的情感分析系统。端到端系统在涉及严格的客户支持和反馈评估的领域具有广泛的适用性——这使得它成为一个需要解决的重要且有价值的问题,尤其是在语音领域。最后,我还将展示一个广泛的分析,以增强所获得结果的可解释性,并从数据中得出适当的见解。

你可以在这里找到这篇文章的代码。此外,文章的亮点如下:

对对话音频数据的情感分析情感分析结果情感分析见解

会话音频数据的情感分析

在这一节中,我将演示如何使用 AssemblyAI API 将给定的一段预先录制的语音对话中的各个句子分为三个情感类别:PositiveNegativeNeutral

通过 API 概述情感分析模型(图片由作者提供)

步骤 1:安装需求

构建情感分类器的要求很少。就 python 库而言,我们只需要 Python 中的[requests](https://pypi.org/project/requests/)包。这可以通过以下方式完成:

pip install requests

步骤 2:生成 API 令牌

下一步是在 AssemblyAI 网站上创建一个账户,这是免费的。一旦完成,您将获得您的私有 API 访问密钥,我们将使用它来访问语音到文本模型。

步骤 3:上传音频文件

出于本教程的目的,我将使用两个人之间预先录制的音频对话来对进行情感分析。一旦您获得了 API 密钥,您就可以继续对预先录制的音频文件执行情感分类任务。

但是,在此之前,您需要上传音频文件,以便可以通过 URL 访问它。选项包括上传到 AWS S3 桶,音频托管服务,如 SoundCloud 或 AssemblyAI 的自托管服务等。我已经将音频文件上传到 SoundCloud,可以在下面访问。

如果你想把音频文件直接上传到 AssemblyAI 的主机服务,你也可以这样做。我已经在下面的代码块中演示了这个循序渐进的过程。

步骤 3.1:进口要求

我们从导入项目的需求开始。

步骤 3.2:指定文件位置和 API_Key

接下来,我们需要指定音频文件在本地机器上的位置以及注册后获得的 API 密钥。

步骤 3.3:指定上传端点

  • endpoint:这指定了要调用的服务,在本例中是“上传”服务。
  • headers:保存 API 密钥和内容类型。

步骤 3.4:定义上传功能

音频文件一次最多只能上传 5 MBs (5,242,880 字节)。因此,我们需要分块上传数据。这些然后在服务端点上被合并回来。因此,您不需要担心处理大量的 URL。

第 3.5 步:上传

最后一步是调用 POST 请求。post 请求的响应是一个保存音频文件的upload_url的 JSON。我将使用这个 URL 来执行音频情感分类的后续步骤。

第四步:情感分析

在这一步,我们已经满足了对音频文件执行情感分析任务的所有必要的先决条件。现在,我们可以继续调用 API 来获取期望的结果。这是一个两步过程,将在下面的小节中演示。

步骤 4.1:提交文件进行转录

第一步是调用 HTTP Post 请求。这实质上是将你的音频文件发送给在后台运行的人工智能模型进行转录,并指示它们对转录的文本进行情感分析。

传递给 POST 请求的参数有:

  1. endpoint:指定要调用的转录服务。
  2. json:这个包含了你的音频文件的 URL 作为audio_url键。由于我们希望对会话数据进行情感分析,所以sentiment_analysis标志和speaker_labels被设置为True
  3. headers:此处装有authorization键和content-type

JSON 响应中收到的 post 请求的当前状态是queued。这表明音频当前正在被转录。

而且,JSON 响应中的sentiment_analysis标志也是True。然而,由于当前状态为queued,对应于sentiment_analysis_results键的值为

步骤 4.2:获取转录结果

为了检查 POST 请求的状态,我们需要使用上面收到的 JSON 响应中的id键发出 GET 请求。

接下来,我们可以继续处理 GET 请求,如下面的代码块所示。

传递给 GET 请求的参数是:

  1. endpoint:指定调用的服务和使用id键确定的 API 调用标识符。
  2. headers:这个保存了你唯一的 API 密匙。

这里你要知道转录结果要等到status键变成completed才准备好。转录所需的时间取决于输入音频文件的长度。因此,您必须定期发出重复的 GET 请求来检查转录状态。下面实现了一种简单的方法:

情感分析结果

一旦status变为completed,您将会收到类似下面提到的响应。

  1. JSON 响应中的status标记为completed。这表明在转录音频时没有错误。
  2. text键包含输入音频对话的完整转录,共 22 个句子。
  3. 由于音频文件由多个扬声器组成,我们将words键中的所有speaker键视为不为空speaker键是“A”或“b”
  4. 我们可以看到所有单个单词和整个转录文本的置信度得分。分数范围从 0 到 1,0 为最低,1 为最高。
  5. 使用 JSON 响应的sentiment_analysis_results键可以访问音频中 22 个单独句子的情感分析结果。
  6. 对应每个句子,我们得到一个类似于上面第 4 点的confidence分数。
  7. 使用句子词典的sentiment键可以检索每个句子的情感。第二句的情感分析结果如下所示:

情感分析洞察

JSONs 通常很难阅读和解释。因此,为了使数据在视觉上更具吸引力,并进行进一步的分析,让我们将上面的情感分析结果转换成一个数据框架。我们将存储句子的text、句子的duration、句子的speaker和句子的sentiment。这在下面实现:

用上面的代码片段生成的 DataFrame 如下图所示。这里,我们有在对话期间说出的 22 个句子,以及相应的说话者标签(“A”和“B”),它们的持续时间(以秒计),以及由模型预测的句子的情绪。

音频文件中的句子(图片由作者提供)

排名第一的扬声器分布

可以使用如下所示的value_counts()方法计算每个说话者说出的句子数量:

要查看发言者的百分比分布,我们可以将normalize = True传递给value_counts()方法,如下所示:

就句子数量而言,说话者“A”和“B”对对话的贡献是相等的。

#2 发言者持续时间分布

接下来,让我们计算对话中每个发言者的个人贡献。如下所示:

我们使用groupby()方法计算他们演讲的总时长。就持续时间而言,说话者 A 是占优势的说话者。

#3 情感分布

在对话中说出的 22 个句子中,只有 3 个被标记为negative情绪。此外,没有一个句子被预测为positive情绪。

归一化分布可以计算如下:

#4 演讲者层面的情感分布

最后,让我们计算一下各个说话者的情绪分布。这里,为了更好的可视化,我们将使用crosstab(),而不是使用groupby()方法。下面演示了这一点:

说话者“A”所说的否定句比说话者“B”所说的多。

情感层面的*均句子时长排名第五

最后,我们将计算属于各个情感类别的句子的*均持续时间。这通过使用groupby()方法实现如下:

negative句的*均持续时间小于neutral句。

最后,在这篇文章中,我们讨论了 AssemblyAI API 的一个特定的 NLP 用例。具体来说,我们看到了如何在包含多个说话者的预先录制的音频文件上构建情感分类模块。最后,我们对情感分析结果进行了广泛的分析。从 API 获得的结果突出了输入音频文件中 22 个单独句子的情感。

你可以在这里找到这篇文章的代码。

在接下来的文章中,我将从技术和实践的角度讨论 AssemblyAI API 的更多用例,比如实体检测、内容审核等等。

下次见。感谢阅读。

转换为音频可能会改善结果:使用暹罗网络的昵称分类

原文:https://towardsdatascience.com/conversion-to-audio-may-improve-results-using-siamese-networks-for-nickname-classification-647cb0f88680

使用暹罗网络学习姓名和昵称之间的相似性。将文本转换为语音可以改善结果。

Unsplash 上由 Waldemar Brandt 拍照

我在本文中使用暹罗网络来学习姓名和昵称之间的相似性度量。训练好的模型告诉我们一个昵称对于一个给定的名字有多可信(假设名字在前面)。我探索了不同的架构,实验表明,对于一个小得多的网络,使用 TTSed 名称和昵称对的频谱图可以改善结果。

目前的项目提出了一个有趣的研究案例,因为查看姓名,这是“上下文无关”的文本,允许我们测试将文本转换为音频对性能的影响,而不考虑可能影响结果的其他因素。例如,在情感分析中,不同的语调可以改变给定文本的整体感觉。因此,将句子转换成语音可能会导致伪像。

这篇文章并不意味着作为一个介绍暹罗网络或对比损失。然而,我为这样的介绍添加了链接,好奇的读者可以参考下面的任何链接。

有关下面实验的更多细节,请参见该项目的 GitHub 页面这里

介绍

了解两个元素之间的相似性对于许多应用程序都很重要。每当人们在手机上使用人脸识别时,他们的图像就会与现有图像进行比较。同一个人的图像可能会因光线、角度、面部毛发等因素而有所不同。所有这些都使得这个比较问题成为一项重要的任务。

相似性可以通过距离度量来衡量,就像 KNN 所做的那样,但是当面对复杂的数据时,它只会带我们走一段路。这里来帮助我们的暹罗网络架构。在暹罗网络中,我们通常使用两个或三个输入,然后通过相同的权重传递;不是计算输入之间的距离,而是测量它们嵌入之间的距离,并输入适当的损失。这允许我们将两个不同输入的嵌入推得更远,同时将来自同一类的两个输入的嵌入拉向彼此。

暹罗网络有一些有趣的用例。它们已被用于检测场景变化(Baraldi、Grana 和 Cucchiara (2015) [1])。在这篇出色的博文中,雷使用了暹罗网络对数字进行聚类。通过学习不同种类的输入之间的相似性(以及因此的不相似性),暹罗网络被用于零/少数镜头学习,其中我们试图说明一个输入是否熟悉网络熟悉的输入。关于这个主题的更多预览,请访问这篇博客文章。

虽然大多数在线示例将连体网络用于计算机视觉,但连体网络在 NLP 领域也有一些很酷的应用。加西亚,Á·阿尔瓦罗等人(2021) [2]使用暹罗网络进行事实检查,建立一个语义感知模型,可以评估两个文本之间的相似程度,其中一个是事实。Gleize,Martin 等人(2019) [3]使用暹罗网络找到更有说服力的论点。他们的数据既包含相同立场的句子对,也包含交叉立场的句子对(即一个支持主题,另一个反对主题)。他们的网络任务是选择辩论的哪一方更有说服力。Neculoiu、Versteegh 和 Rotaru (2016) [4]提出了一种在可变长度字符序列上学习相似性度量的深度架构。他们的模型应用于学习职称之间的相似性(“java 程序员”应该更接*“java 开发人员”,但离“HR 专员”更远)。他们的体系结构包括四层 BLSTM,后面是一个线性层,并且他们使用嵌入之间余弦相似性的对比损失。这是我最初的架构,但它的表现并不好,可能是因为数据量少。

上绰号

昵称是对熟悉的人、地方或事物的专有名称的替代。通常用来表达喜爱,一种喜爱的形式,有时是娱乐,它也可以用来表达对人格的诽谤。(来源:维基百科,此处)

昵称可以包含在名字中,也可以被包含在名字中。有时候,名字和昵称之间的联系并不明显。中世纪的英国人喜欢押韵。因此,“罗伯特”变成了“罗布”,然后,因为它和“鲍勃”押韵,这个昵称就被保留了下来。请看奥斯卡·泰对 Quora 问题的精彩回答。

【比尔】莎士比亚,维基百科,此处

在很多情况下,人们可以在昵称中看到名字的子串,反之亦然,在保持昵称发音相似的同时改变元音也很常见(例如,“I”到“ea”)。另一个标准变化是用“ie”代替名字的结尾(例如,“萨曼莎”改为“余思敏”)。

创建姓名和昵称之间的相似性度量的任务首先是在学习的同时获得乐趣。这种模型的一些用例可以包括信任评估——例如,一个人在他们的在线帐户中使用的昵称/用户名与他们的姓名(与交易相关)匹配的可能性有多大。密码强度评估——使用自己的名字可能会导致弱密码,使用自己的昵称也可能会导致弱密码。

数据

这个项目的数据是通过几个来源创建的:

  1. 这里的男/女小称
  2. 安全企业主患者索引(SOEMPI),此处
  3. common_nickname_csv,此处

样本不够大,这极大地限制了我们的网络规模以及学习和归纳的能力。下表对其进行了描述。

样本大小

对于给定的名字,检查昵称是否合理的最简单的方法是使用子串匹配。在某些情况下,名字的子串完全包含在昵称中,反之亦然。令人惊讶的是,第二种更常见(2.2%对 26.5%!).

实验

实验 1 :首先我实现了【4】中的模型。该模型由四个具有 64 长度隐藏状态的双向 LSTM 层组成。最后一个 BLSM 层的隐藏状态(一个向前和一个向后)被*均(“时间*均”),然后 64 长度的向量通过密集层。在最初的论文中,两个输入,职位,被输入到模型中,在我们的例子中,名字和昵称被传递。

BLSM 模式的启发[4]

实验 2 :让一个 LSTM 网络工作起来很有挑战性,对于我们所拥有的数据量来说,这可能是不可能的。然后,我在文本上使用 1d-CNN 暹罗网络。在时间序列数据上使用 CNN 的一个限制(例如,匹配两个字母序列的任务)是,它不保留序列中元素之间递归关系的任何信息。为了说明这一点,我同时使用了字母嵌入和位置嵌入(Gehring et al. (2017) [5])。

第二个实验的模型。在前三个块中,relu 用作激活函数,在第四个也是最后一个块中,使用 sigmoid。

实验三:由于昵称通常是通过社会交流创造出来的,所以有些名字听起来更像,而不是写出来的。例如,“Relief”和“Leafa”,在训练数据中是一对。虽然名字中的“lief”部分与昵称中的“Leaf”部分的写法不同,但它们听起来非常相似。为此,我通过谷歌的 gtts 库将所有的名字和昵称转换成语音。然后我使用 librosa 包将生成的 .mp3 文件转换成光谱图。

第三个实验的模型。D(A,B)是两个元素之间的欧几里德距离。

在实验 2 和实验 3 中,隐藏的 1d/2d-CNN 层都以这样的方式构造,即它们将返回与输入相同维数的张量。然后输入和结果以一种 ResNet 的方式相加在一起(he 等人,(2016 a))【6】。

实验 4 :最后,作为一个基准,我将上述模型与非学习方法进行比较,如 Jaro,Jaro-WinklerLevinstein Distance (参见 William,Ravikumar 和 Fienberg (2003) [7]了解更多信息)。

结果比较

不幸的结果表明,非学习算法的表现比任何网络都好(但这有什么意思呢!).BLSTM 无法学习任何东西,即使在尝试缩小它之后(删除一些 BLSTM 层,输出一个短得多的隐藏状态长度)。1d-CNN 得到了一些不错的结果,但是 2d CNN 得到了更好的结果,因为参数数量少得多。

最终,Jaro Winkler 得到了最好的结果。

对上述结果的一个可能的解释是,我们拥有的数据太少,无法从一开始就训练这样的模型。

然而,两个网络都能够学习,而且不仅仅是在名字中包含昵称的简单情况,反之亦然。

结果分析

这部分的结果是 1d-CNN 模型的结果。查看哪些案例被正确分类是很有趣的,但是对不正确分类的仔细分析可以告诉我们一些关于被估计的相似性的信息。

正确案例:下表给出了正确分类的配对结果。不出所料,大多数真正的阳性案例都很简单,比如名字包含在昵称中,反之亦然。类似地,真阴性最低分配对案例在字母和发音方面都非常不同,只有“Kimberly”和“Becki”例外(我可能认为“Becki”是“Kimberly”的昵称,但也许这只是我的错)。

错误案例:更有趣的群体。看起来大多数 FP 案例都是合理的配对。人们可能会认为“玛蒂”(而不是听起来可能不同的“玛蒂”)实际上是“玛莎”的昵称。“玛丽”和“玛姬”也是如此。艾丽和玛格丽特是特别有趣的例子。我手头的资料包括“Margaret”和“Meggie”这一对。“Allie”作为名字只有“Ali”作为昵称。“艾丽”作为昵称,是“艾伦”、“爱丽丝”等的昵称。这些例子可能意味着网络能够学习名字和昵称之间的一些潜在逻辑。另一方面,看看 10 个最低的假阴性病例是令人难过的,因为这个组的许多名字都包括他们的昵称,反之亦然。

有关决策和边界的更多示例,请参见附录。

附录:损失函数、训练和提炼

损失函数:在我的实验中,我使用了几个损失函数。首先,我使用了[4]中描述的损失函数。然后我去探索不同的功能。我使用对比损失,灵感来自这个实现。然后,我还使用了 BCE 损失,受[8]的启发,他使用对比损失和 BCE 损失的加权*均值进行癫痫发作预测。总体而言,对比损失在 ROC AUC 方面取得的结果比 BCE 损失稍差,但其目标略有不同。对比损失的目的是辨别输入向量的特征,随着下面等式中的α减小,将负得分推向零。

对比损失,符号取自此处的。

在所描述的项目中,我没有探究三重态损失,后续项目也可以扩展使用这一点。参见这篇帖子,了解 BCE 损失、对比损失和三重损失之间更详细的比较。

下图显示了对比损失在类别之间的区分程度。

按损失类型的分数分布

训练:在暹罗网络中,两个输入通过同一个网络(或者,换句话说,我们对它们使用共享权重)。当我们不知道哪个输入将首先被输入时,它是有帮助的。在我们的例子中,从构造开始,这些对以相同的顺序构建—(姓名,昵称),因此,使用不同的权重对它们中的每一个进行稍微不同的编码,但是在某种程度上使得这些编码的结果仍然具有较低的欧几里德距离,可能会改善结果。确实如此。对名字和昵称使用不同的权重改善了结果,但也使网络的参数数量翻倍。未来的工作可以通过将这种无限制网络的结果与具有共享权重的更深网络的结果进行比较来评估使用非共享权重的益处,使得两者具有相似数量的参数。

提炼:根据来自的 Laura Leal-Taixé教授的建议,这个关于暹罗网络的精彩讲座,暹罗网络的训练可以通过以下步骤进行提炼:

  1. 训练网络几个时期
  2. d(A,P)表示同一类的两个输入之间的距离,d(A,N)表示不同类的两个元素之间的距离。在第二步,我们只采取困难的情况下,如

A,锚(名),正例 P(真实昵称)和反例 N(不正确昵称)之间的相似距离。Laura Leal-Taixé教授的批注讲座在此

3.只对疑难病例进行训练。

细化网络能够取得稍微改善的结果,但并没有把网络改得面目全非。

决策界限:下图显示了每个类别的分数分布。这些分布被分别归一化,所以我们可以把数据看成是*衡的。我选择使用 0.4 的决策边界。

下面是低于阈值的 10 个样本,接下来是最接*阈值的 10 个样本,然后是来自阈值以上区域的另外 10 个样本。

我们看到最接* 0.3 的例子大多是无效对。最接*判定阈值的 10 对中的 4 对是有效的,最接* 0.5 的 10 对中的 7 对是有效的。此外,我们看到在大多数正面例子中,名字不包括昵称,反之亦然。

文献学

[1]巴拉尔迪、洛伦佐、科斯坦蒂诺·格拉纳和丽塔·库恰拉。"用于广播视频中场景检测的深度连体网络."第 23 届 ACM 国际多媒体会议会议录。2015.

[2]韦尔塔斯-加西亚、Á·阿尔瓦罗等人,“通过语义感知多语言模型反击错误信息”智能数据工程和自动化学习国际会议。施普林格,查姆,2021。

[3]格莱泽、马丁等《你信服了吗?用连体式网络选择更有说服力的证据。” arXiv 预印本 arXiv:1907.08971 (2019)。

[4]neculiou,Paul,Maarten Versteegh 和 Mihai Rotaru。"用暹罗循环网络学习文本相似性."第一届 NLP 表征学习研讨会论文集。2016.

[5] Gehring,Jonas 等,“卷积序列到序列学习”机器学习国际会议。PMLR,2017。

[6]何,,等.“用于图像识别的深度残差学习”IEEE 计算机视觉和模式识别会议论文集。2016.

[7]科恩、威廉·w .、帕拉德普·拉维库马尔和斯蒂芬·芬伯格。"名称匹配任务的字符串距离度量的比较." IIWeb 。第三卷。2003.

[8] Dissanayake,Theekshana 等,“使用深度学习模型进行独立于患者的癫痫发作预测。” arXiv 预印本 arXiv:2011.09581 (2020)。

使用 Python 将 CSV 文件转换为 LAS 文件

原文:https://towardsdatascience.com/convert-csv-files-to-las-files-with-python-7de4a47fc996

快速简单的转换过程,使用 LASIO 和 CSV 数据从头开始创建 LAS 文件

使用 LASIO 从 CSV 到 LAS。作者创建的图像。

测井数据可以多种格式交付(、 LAS 、CSV、ASC 等)。).如果你有一个包含测井数据的 CSV 文件,并且你想把它转换成 LAS 格式,你可以使用 LASIO

LAS 文件是一种简单的格式。它们是简单的文本文件,包含油井元数据、参数信息和测井数据测量值。这些文件很容易在任何文本编辑器中打开,您可以快速轻松地阅读内容。

但是,有时您可能会得到一个包含测井测量值的 CSV 文件,并希望将其转换为 LAS 文件。在这篇文章中,我们将涵盖这一点。

我们将看到如何使用优秀的 LASIO 库将一个简单的 CSV 文件转换成这样的 LAS 文件。

如果你愿意,你可以在我的 YouTube 频道下面观看这个版本。

笔记本和数据

你可以从我的 Github 仓库下载笔记本和数据,这里:https://github.com/andymcdgeo/Petrophysics-Python-Series

加载所需的库

首先,我们将加载所需的 python 库。在本教程中,我们将使用拉西奥熊猫

import lasio
import pandas as pd

有关使用 lasio 的更多信息,请点击此处查看本文:

https://andymcdonaldgeo.medium.com/loading-and-displaying-well-log-data-b9568efd1d8

使用熊猫载入 CSV 文件

接下来,我们需要加载我们的 CSV 文件。

这是使用 pandas 的read_csv()函数并传入文件位置和文件名来完成的。

data = pd.read_csv('Data/Notebook 22/Notebook 22 - VOLVE - 15_9-19.csv')

一旦文件被读取,我们就可以通过调用 pandas data.head()函数来检查文件的内容。

data.head()

它返回一个包含数据统计信息的表格。

测井数据的数据帧头。图片由作者提供。

我们现在可以看到,在我们的数据框架中有 18 列,以及测井记录测量的混合。

为了确保数据都是数字,并了解数据中有多少个空值,我们可以调用 pandas 函数[.info()](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.info.html?highlight=info#pandas-dataframe-info)。这不是一个必要的步骤,但是它允许我们检查列是否是数字的(float64 或 int64)。

data.info()

dataframe.info()方法应用于测井数据,指示数据类型和空计数。图片由作者提供。

用 LASIO 创建一个空的 LAS 对象

在将数据从 CSV 传输到 LAS 之前,我们首先需要创建一个空白的 LAS 文件。这是通过调用lasio.LASFile()并将其赋给一个变量来实现的。在这个例子中,这个变量叫做las_file

las_file = lasio.LASFile()

当我们尝试查看新创建的 LAS 文件的内容时,我们可以看到标题信息为空。

las_file.header

我们还可以通过调用las_file.curves来确认文件中没有数据,这将返回一个空列表。

设置 LAS 文件元数据

现在我们有了一个空白的 las 对象,我们需要向 LAS 头添加信息。

第一步是创建一些我们想要填充的变量。这样做,而不是直接将它们传递到 HeaderItem 函数中,使得将来更改它们更容易,也使得可读性更好。

例如,如果我们创建了一个函数,我们希望根据不同的文件更新头文件中的特定参数,我们可以很容易地将这些变量传递到函数中,而不必更新函数中的代码。

well_name = 'Random Well'
field_name = 'Random Field'
uwi = '123456789'
country = 'Random Country'

要开始给标题赋值,我们需要调用las_file.well并选择我们想要添加的标题属性。在右边,我们将更新 HeaderItem 并为其提供一个值。

las_file.well['WELL'] = lasio.HeaderItem('WELL', value=well_name)
las_file.well['FLD'] = lasio.HeaderItem('FLD', value=field_name)
las_file.well['UWI'] = lasio.HeaderItem('UWI', value=uwi)
las_file.well['CTRY'] = lasio.HeaderItem('CTRY', value=country)

完成后,我们可以再次调用我们的头,我们现在可以看到井名、UWI、国家和字段名称的值都已更新。

las_file.header

添加深度曲线

要将曲线添加到文件中,我们可以使用add_curve功能并传入数据和单位。

此处的示例显示了如何将一条曲线添加到名为 DEPT 的文件中。注意,如果添加主深度数据,它需要作为 DEPT 而不是 depth 放入。

las_file.add_curve('DEPT', data['DEPTH'], unit='m')

书写剩余的曲线

为了使事情变得简单,我创建了一个包含每条测井曲线的测量单位的列表。请注意,这不包括深度测量的单位。

units = ['m',
 'inches',
 'unitless',
 'us/ft',
 'us/ft',
 'us/ft',
 'us/ft',
 'API',
 'v/v_decimal',
 'v/v_decimal',
 'v/v_decimal',
 'v/v_decimal',
 'v/v_decimal',
 'g/cm3',
 'g/cm3',
 'ohm.m',
 'ohm.m',
 'degC']

然后,我们可以开始遍历数据帧中的每个测井测量值/列以及单位列表。这是使用 Python zip函数实现的。

因为我们在 las 文件中已经有了深度,所以我们可以通过检查列名来跳过这一列。还有其他处理方法,例如将深度和曲线一次性写入 las 文件。

for col, unit in zip(data.columns, units):
    if col != 'DEPTH':
        las_file.add_curve(col, data[col], unit=unit)

当我们检查curves函数时,我们可以看到我们所有的曲线都有适当的单位。我们还可以从列表的 data.shape 部分看到,每条曲线有 4101 个值,这证实了我们有数据。

las_file.curves

我们可以通过调用曲线来确认我们有值。在下面的例子中,我调用了 GR,我们得到了一个返回的包含伽马射线值的数组,它与前面给出的 dataframe 中的值相匹配。

las_file['GR']

它返回:

array([  36.621,   36.374,   30.748, ..., -999\.   , -999\.   , -999\.   ])

导出 LAS 文件

一旦我们对 las 文件感到满意,我们现在可以将其导出到一个文件中,并在任何其他软件包中使用它。

las_file.write('Output/Notebook 22/OutputLAS_FINAL.las')

摘要

在本文中,我们介绍了如何将包含测井/岩石物理测量值的简单 CSV 文件转换为行业标准 LAS (Log ASCII 标准)文件。一旦在 lasio 中创建了一个空白的 LASFile 对象,就可以用正确的元数据手动更新标题项,也可以用正确的值更新曲线。

感谢阅读。在你走之前,你一定要订阅我的内容,把我的文章放到你的收件箱里。 你可以在这里做!

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

*https://andymcdonaldgeo.medium.com/membership *

使用 Python 将 HTML 转换为 PDF

原文:https://towardsdatascience.com/convert-html-to-pdf-using-python-4df78b40de1b

在本教程中,我们将探索如何使用 Python 将 HTML 文件转换为 PDF

弗洛里安·奥利佛在 Unsplash 上拍摄的照片

目录

  • 介绍
  • 示例 HTML 文件
  • 使用 Python 将 HTML 文件转换为 PDF
  • 使用 Python 将网页转换为 PDF
  • 结论

介绍

有几个在线工具可以让你把 HTML 文件和网页转换成 PDF 格式,而且大多数都是免费的。

虽然这是一个简单的过程,但能够自动化它对于一些 HTML 代码测试以及将所需网页保存为 PDF 文件非常有用。

要继续学习本教程,我们需要:

wkhtmltopdf 是一个开源命令行工具,使用 Qt WebKit 渲染引擎将 HTML 文件渲染成 pdf。

为了在 Python 中使用它,我们还需要 pdfkit 库,它是 wkhtmltopdf 实用程序的包装器。

首先,为您的操作系统搜索 wkhtmltopdf 安装程序。对于 Windows,你可以在这里找到最新版本的 wkhtmltopdf 安装程序。只需下载。exe 文件并安装在您的计算机上。

记住安装目录的路径。
在我这里是:C:\ Program Files \ wkhtmltopdf

如果您没有安装 Python 库,请打开“命令提示符”(在 Windows 上)并使用以下代码进行安装:

pip install pdfkit

示例 HTML 文件

为了继续学习本教程,我们需要一些 HTML 文件。

下面是我们将在本教程中使用的一个示例 HTML 文件:

https://pyshark.com/wp-content/uploads/2022/06/sample.html】

如果您下载它并在浏览器中打开,您应该会看到:

在代码编辑器中打开它,应该会显示:

使用 Python 将 HTML 文件转换为 PDF

让我们从使用 Python 将 HTML 文件转换成 PDF 开始。

sample.html文件与 main.py 文件位于同一目录下,代码为:

首先,我们需要找到 wkhtmltopdf 可执行文件wkhtmltopdf.exe的路径

回想一下,我们在C:\ Program Files \ wkhtmltopdf中安装了。exe 文件在该文件夹中。导航到它,您应该看到可执行文件的路径是:C:\ Program Files \ wkhtmltopdf \ bin \ wkhtmltopdf . exe

现在,我们已经拥有了所需的一切,可以使用 Python 轻松地将 HTML 文件转换为 PDF:

您应该会看到 sample.pdf 的创建在同一个目录中:

作者图片

哪个应该看起来像这个

使用 Python 将网页转换为 PDF

使用 pdfkit 库,您还可以使用 Python 将网页转换为 PDF。

让我们把 wkhtmltopdf 项目页面转换成 pdf!

在这一节中,我们将重用前一节中的大部分代码,除了现在我们将使用网页的 URL 和而不是 HTML 文件。pdfkit 类的 from_url() 方法:

您应该会看到webpage.pdf创建在同一个目录中:

作者图片

哪个应该看起来像这个

结论

在本文中,我们探索了如何使用 Python 和 wkhtmltopdf 将 HTML 转换成 PDF。

如果你有任何问题或对编辑有任何建议,请随时在下面留下评论,并查看我的更多 Python 编程教程。

原载于 2022 年 6 月 23 日 https://pyshark.com**的

在 Pytorch 和 Tensorflow 中将图像转换为张量

原文:https://towardsdatascience.com/convert-images-to-tensors-in-pytorch-and-tensorflow-f0ab01383a03

学习以本机方式转换数据

Unsplash 上的 Clarisse Croset 拍摄的照片

如你所知,张量代表了你的机器学习项目的构建模块。它们是不可变的,只能被创建,不能被更新。处理张量是复杂的,因为它在很大程度上依赖于你使用的框架,并且没有关于如何编码它的标准化。

因此,您将经常陷入这样一种情况,即您必须执行自定义操作,例如从 Pytorch 转换到 Tensorflow 或改变张量的维度。

在本教程中,您将学习:

  • 在 Pytorch 和 Tensorflow 框架中将图像转换为张量
  • 使用torch.permute改变 Pytorch 张量的维度顺序
  • 使用tf.transpose改变张量流张量的维度顺序
  • 将张量从 Pytorch 转换为 Tensorflow,反之亦然

让我们继续下一节,开始安装所有必要的 Python 包。

设置

强烈建议您在继续安装之前创建一个新的虚拟环境。

Pytorch

运行以下命令来安装torchtorchvision软件包。

pip install torch torchvision

torchvision是一个基本的软件包,它提供了相当多的图像变换功能,如调整大小和裁剪。

Python 图像库

此外,您需要安装 Python 图像库(PIL ),它在加载您的图像时补充了torchvision。您可以按如下方式安装它:

pip install Pillow

张量流

从版本 2 开始,Tensorflow 的安装变得简单多了。使用以下命令安装它:

pip install tensorflow

完成安装后,继续下一节的实施。

将图像转换为张量流张量

在本节中,您将学习为 Pytorch 和 Tensorflow 框架实现图像到张量的转换代码。

供您参考,张量流中图像张量的典型轴顺序如下:

shape=(N, H, W, C)
  • N —批量大小(每批图像的数量)
  • H —图像的高度
  • W —图像的宽度
  • C —通道数(RGB 通常使用 3 个通道)

您可以轻松地加载图像文件(PNG、JPEG 等。)和下面的代码:

更改张量流张量维度

此外,Tensorflow 确实提供了一个名为tf.transpose的有用函数,可以根据perm的值改变张量的维数。默认情况下,perm设置为[n-1…0],其中 n 代表维度的数量。

假设你想改变张量的形状

(224, 224, 3) -> (3, 224, 224)

简单地调用tf.transpose函数如下:

tensor = tf.transpose(tensor, perm=[2, 0, 1])

这在对源自 Pytorch 的模型(例如,从 Pytorch 到 ONNX 到 Tensorflow 的转换)执行推理时很方便,因为两种框架之间图像张量的标准结构不同。

将图像转换为 Pytorch 张量

另一方面,Pytorch 中图像张量的形状与张量流张量略有不同。而是基于以下torch.Size:

torch.Size([N, C, H, W])
  • N —批量大小(每批图像的数量)
  • C —通道数(RGB 通常使用 3 个通道)
  • H —图像的高度
  • W —图像的宽度

加载图像数据有多种方式,其中一种如下:

  • 通过枕形包装装载
  • 设置转换功能
  • 对图像应用调整大小变换
  • 设置张量转换函数
  • 对图像应用张量转换函数

看看下面的转换脚本:

与 Tensorflow 使用术语扩展维度来添加新维度不同,Pytorch 基于挤压和取消挤压。挤压意味着你将通过截断来减少维度,而 unsqueeze 将为相应的张量增加一个新的维度。

更改 Pytorch 张量维度

此外,您可以通过torch.permute功能轻松地重新排列张量的维度。假设您想要按如下方式更改形状:

(3, 224, 224) -> (224, 224, 3)

调用torch.permute函数时,应传入以下输入:

torch.permute(tensor, (1, 2, 0))

在 Pytorch 和 Tensorflow 之间转换张量

张量转换的一个最简单的基本工作流程如下:

  • 将张量(A)转换为 numpy 数组
  • 将 numpy 数组转换为张量(B)

Pytorch 到 Tensorflow

Pytorch 中的 Tensors 自带了一个名为numpy()的内置函数,该函数会将其转换为 numpy 数组。

py_tensor.numpy()

然后,简单地调用 tf.convert_to_tensor() 函数如下:

import tensorflow as tf...tf_tensors = tf.convert_to_tensor(py_tensor.numpy())

张量流向 Pytorch

另一方面,tensors 从 Tensorflow 到 Pytorch 的转换遵循相同的模式,因为它有自己的numpy()函数:

tf_tensors.numpy()

随后,您可以调用 torch.from_numpy() 进行张量转换:

import torch...py_tensors = torch.from_numpy(tf_tensors.numpy())

结论

让我们回顾一下你今天所学的内容。

本文首先简要解释了张量和操作张量的困难。

接下来,它通过pip install进入安装过程。

它继续逐步指导将图像数据转换为 Tensorflow 张量,以及如何根据自己的需要更改张量的维度。

此外,还介绍了 Pytorch 框架的张量转换和相应的维数置换。

最后,它突出显示了一些代码片段,用于将 tensors 从 Tensorflow 转换为 Pytorch,反之亦然。

感谢你阅读这篇文章。祝你有美好的一天!

参考

  1. tensor flow——张量介绍
  2. Tensorflow — tf.io
  3. py torch—torch vision . transform

将 Jupyter 笔记本转换为功能

原文:https://towardsdatascience.com/convert-jupyter-notebooks-into-functions-6fbda7b18419

参数化笔记本,以便您可以通过编程方式运行它们

你已经在 Jupyter 笔记本上训练了你的机器学习模型。现在,您希望对每天获得的数据运行该模型。

日复一日,你创建了同一个笔记本的新副本并运行它。您存储笔记本的副本,并将结果传递给利益相关者。

在另一个场景中,您每天都有一组新的数据需要在 Jupyter notebook 上用相同的代码可视化。

因此,您创建了同一个笔记本的新副本,并修改了输入。同样,您存储笔记本的副本,并将结果传递给您的利益相关者。

听起来不痛苦吗?

这是你的桌面吗?只是一堆笔记本叠在一起而已!稳定扩散成像

如果我们有一个函数run_notebook(input_data),这个问题就可以解决。通过提供参数input_data,笔记本将使用新的 input_data 运行。输出将是使用新数据运行的笔记本的副本。

这正是造纸厂所做的。

这里有一个它的快速演示。

Papermill:参数化并自动执行 Jupyter 笔记本

它是一个用于参数化、执行和分析 Jupyter 笔记本的开源工具。只需将参数传入笔记本,Jupyter 笔记本就会自动运行。

造纸厂的使用案例

如果手动对多个数据集进行相同的分析,既耗时又容易出错。例如,每日报告控制面板可能需要每天根据新数据进行刷新。Papermill 实现了自动化。

Jupyter 笔记本中的机器学习算法可能用于每天生成结果。Papermill 可用于在生产中生成结果,而不是每天用新数据手动运行笔记本。

在这篇文章中,我回顾了:

  • 安装造纸厂
  • Papermill 入门
  • 使用 Papermill 定期生成可视化报告
  • 在造纸厂生产中运行机器学习算法
  • 你可以用 Papermill 做的其他事情
  • 进一步的阅读和资源

1.安装造纸厂

只需在您的终端中运行以下命令。

pip install papermill[all]

2.Papermill 入门

在朱庇特笔记本上

  1. 在你的桌面上创建一个 Jupyter 笔记本,命名为hello_papermill
  2. 比方说,我们要参数化 ab 来计算a+b。我们将创建这个代码块。

3.转到工具栏->视图->单元格工具栏->标签。

4.在第一个单元格的右上角键入parameters。点击“添加标签”。笔记本参数化!

5.启动终端并导航到您的桌面。

对于 Mac 用户,该命令是:

cd ~/Desktop/ 

对于 Windows 用户,该命令为

cd C:\Users\YOUR_USER_NAME_HERE\Desktop

6.用这个命令运行你的参数化笔记本。该命令告诉 Papermill“使用参数a=10b=20运行hello_papermill.ipynb,并将结果存储在output.ipynb中”

papermill hello_papermill.ipynb output.ipynb -p a 10 -p b 20

7.从 Jupyter 界面,打开output.ipynb。您应该会看到以下自动生成的内容。

单元格[1]中的所有输入都被单元格[2]中的参数覆盖。请注意,单元格[2]是由 Papermill 自动生成的,并且具有注入参数标签。

3.使用 Papermill 定期生成可视化报告

现在我们已经浏览了 Papermill 的“hello world ”,让我们深入第一个可能的用例。

在运行这段代码之前,请安装以下软件包。

pip install yfinance
pip install matplotlib

在我的Desktop上,我创建了一个叫做plot_stock_price的 Jupyter 笔记本。

本笔记本:

  • 接受参数stock,它是公司的股票代码(微软用MSFT,特斯拉用TSLA,Meta 用Meta),
  • 提取一家公司的股票价格,
  • 绘制图表,
  • 将图形导出为名为output_{stock}.png的文件

这是代码。

import pandas
import yfinance
import matplotlib.pyplot as plt

# selecting a stock ticker
stock = 'MSFT' # This line is parameterized.
stock_list = [stock]

# downloading the stock
stock_data = yfinance.download(stock,start="2021-10-01", end="2022-02-14")
stock_data.head(5)

# plot only the Opening price of ticket
data = stock_data.loc[:,"Open"].copy()

# Plot the data with matplotlib
plt.style.use("seaborn")
fig, ax = plt.subplots(1, figsize=(16,5))
ax.plot(data)

# Save the image as a PNG file
fig.savefig(f'output_{stock}.png')
print(f"Image saved to output_{stock}.png")

接下来,再次打开您的终端并导航到您的桌面。(上面我提供了一些说明)。运行此命令。这告诉 papermill“使用参数stock='TSLA'运行plot_stock_price.ipynb,并将输出笔记本存储到output.ipynb”。

papermill plot_stock_price.ipynb output_TSLA.ipynb -p stock 'TSLA' 

您应该在终端中看到类似这样的内容。

Input Notebook:  plot_stock_price.ipynb
Output Notebook: output_TSLA.ipynb
Executing:   0%|                                                                                                                                          | 0/8 [00:00<?, ?cell/s]
Executing notebook with kernel: python3
Executing: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 8/8 [00:04<00:00,  1.81cell/s]

最后,再次检查你的桌面。你应该会看到两个文件:output_TSLA.ipynboutput_TSLA.png。太好了,我们已经成功运行了参数化笔记本。

4.在经过训练的机器上对不同数据集进行预测

下一个用例是我们熟悉的。

你已经在笔记本上训练了你的机器学习算法。现在,您需要定期对新数据运行算法。

在运行这段代码之前,请安装以下软件包。

pip install scikit-learn
pip install pandas
pip install numpy

在我的Desktop上,我创建了一个叫做predict_linear_regression的 Jupyter 笔记本。

这个笔记本

  • 基于模拟数据训练线性回归模型,
  • 以输入文件(CSV)格式作为参数读入,
  • 创建模拟输入,
  • 基于 CSV 文件中的输入进行预测,并且
  • 将预测导出为名为output_{stock}.png的文件
import numpy as np
from sklearn.linear_model import LinearRegression
import pandas as pd

X = np.array([[1, 1], [1, 2], [2, 2], [2, 3]])

# Convert the array X into a pandas dataframe
train_df = pd.DataFrame(X, columns=['a', 'b'])

# Create a new column 'y' with the formula y = 3 + a + 2*b 
np.random.seed(5)
train_df['y'] = 3 + train_df['a'] + 2*train_df['b'] 

reg = LinearRegression().fit(train_df.drop(columns=['y']), 
                             train_df['y'])

# Create a mock input dataset 
X1 = np.array([[5, 3], [10, -4]])
input_set1 = pd.DataFrame(X1, columns=['a', 'b'])
input_set1.to_csv('input_set1.csv', index=False)

# Create another mock input dataset
X2 = np.array([[10, -1], [2, -6]])
input_set2 = pd.DataFrame(X2, columns=['a', 'b'])
input_set2.to_csv('input_set2.csv', index=False)

# Make predictions on the mock input datasets
input_name = 'input_set1.csv' # Parameterized
output_name = 'output_set1.csv' # Parameterized

# Read test input
pred_df = pd.read_csv(input_name)

# Make predictions 
pred_df['y_pred'] = reg.predict(pred_df)

pred_df.to_csv(output_name, index=False)

接下来,再次打开您的终端并导航到您的桌面。(上面我提供了一些说明)。运行此命令。这告诉 papermill“使用参数输入名='input_set2.csv'和输出名='output_set2.csv'运行predict_linear_regression.ipynb。最后,将输出笔记本存储到predict_output.ipynb

papermill ./predict_linear_regression.ipynb ./predict_output2.ipynb -p input_name './input_set2.csv' -p output_name './output_set2.csv' 

您应该在终端中看到类似这样的内容。

Input Notebook:  ./predict_linear_regression.ipynb
Output Notebook: ./predict_output2.ipynb
Executing:   0%|                                                                                                                                         | 0/11 [00:00<?, ?cell/s]Executing notebook with kernel: python3
Executing: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 11/11 [00:05<00:00,  2.12cell/s]

最后,再次检查你的桌面。你应该看到两个文件:predict_output2.ipynboutput_set2.csv。很好,我们已经成功地为机器学习用例运行了一个参数化的笔记本。

5.用 Papermill 做更多

Papermill 还有更多有用的功能。这里我强调几个有趣的用法。

将笔记本电脑作为功能运行

你可以把笔记本作为一个函数来执行,而不是在终端中执行笔记本。这里有两个实现相同目标的备选方案。

备选方案 1:在终端中,导航到包含predict_linear_regression.ipynb的目录。然后,运行命令

papermill ./predict_linear_regression.ipynb ./predict_output2.ipynb -p input_name './input_set2.csv' -p output_name './output_set2.csv'

备选方案 2:在 Jupyter 中,导航到包含predict_linear_regression.ipynb的目录。在那里创建一个新的笔记本并运行命令。

import papermill as pm

pm.execute_notebook(
   'predict_linear_regression.ipynb',
   'predict_output2.ipynb',
   parameters = {'input_name': './input_set2.csv', 
                 'output_name': './output_set2.csv')

将您的结果上传到亚马逊 S3 或云

$ papermill predict_linear_regression.ipynb s3://bkt/output.ipynb -p alpha 0.6 -p l1_ratio 0.1

提供一个. yml 文件,而不是参数

$ papermill predict_linear_regression.ipynb s3://bkt/output.ipynb -f parameters.yaml

6.造纸厂的更多资源

  • 网飞公布了他们如何使用 Papermill 自动执行笔记本日常数据分析和工程工作。
  • 阅读文档以更清楚地了解它是如何工作的。

在这篇博文中,我们学习了如何用 Papermill 参数化一个笔记本。这是优化数据科学工作流程的绝佳工具。试试看!

使用 Papermill,这样你的笔记本就可以放在适当的位置。

我是 Travis Tang,在 tech 工作的数据科学家。我在开源图书馆的 TowardsDataScience 上发表博文。每天,我都会在 LinkedIn 上发布数据科学技巧。关注我,获取更多定期更新。

将 PASCAL VOC XML 转换为 YOLO 用于对象检测

原文:https://towardsdatascience.com/convert-pascal-voc-xml-to-yolo-for-object-detection-f969811ccba5

预处理影像数据集的技巧和诀窍

作者图片

本教程涵盖以下分步指南:

  • 将 XML 注释转换为 YOLO 注释
  • 使用新创建的 YOLO 注释可视化图像中的边界框
  • 将数据集分为训练集、验证集和测试集

概观

PASCAL VOC XML

PASCAL 视觉对象类(VOC)项目是最早的计算机视觉项目之一,旨在标准化数据集和注释格式。注释可以用于图像分类和对象检测任务。

以下代码片段是 PASCAL VOC XML 注释的示例:

根据其规范,注释将以人类可读的 XML 格式定义,并与图像具有相同的名称(除了扩展名之外)。它应该具有以下项目:

  • folder —图像的父目录。
  • filename —图像的名称(包括扩展名)。
  • path —图像的绝对路径
  • source:database —文件在数据库中的原始位置。仅在使用数据库时适用。否则,它将默认为Unknown
  • size:width —图像的宽度,以像素为单位。
  • size:height —图像的高度,以像素为单位。
  • size:depth —图像的深度。对于对象检测任务,它表示通道的数量。
  • segmented-确定注释是线性的(0)还是非线性的(1)。非线性是指多边形形状。
  • object:name —对象的标签。
  • object:pose —确定对象的方向是否不同。正常图像默认为Unspecified
  • object:truncated —确定对象是完全可见(0)还是部分可见(1)。部分可见是指隐藏在另一个对象后面的对象。
  • object:difficult —确定物体是易于识别(0)还是难以识别(1)。
  • object:bndbox:xmin —左上位置的 x 坐标。
  • object:bndbox:ymin —左上位置的 y 坐标。
  • object:bndbox:xmax —右下角位置的 x 坐标。
  • object:bndbox:ymax —右下角位置的 y 坐标。

PASCAL VOC XML 注释的一个主要问题是,我们不能直接使用它进行训练,尤其是在对象检测任务上。大多数最新的模型依赖于不同的注释格式。最受欢迎的是:

  • COCO——一个 JSON 文件包含整个数据集的五个信息部分。
  • YOLO —每个图像的单独文本文件,与预期图像具有相同的名称。

YOLO

YOLO 的规格如下:

  • 每个对象在文本文件中都应该有自己的一行
  • 每一行应具有以下模式:class x_center y_center width height
  • 类别号必须是从 0 开始的整数
  • x_centery_centerwidthheight必须为规范化形式(范围从 0 到 1)

例如,上述注释可以用 YOLO 格式表示如下:

0 0.65814696485623 0.6966426858513189 0.07987220447284345 0.14148681055155876
0 0.7124600638977636 0.6882494004796164 0.09584664536741214 0.11990407673860912

继续下一节,学习如何将 XML 注释转换成 YOLO 文本文件。

将 PASCAL VOC XML 转换为 YOLO

在工作目录中创建一个名为xml2yolo.py的新脚本。确保数据集和 Python 脚本的结构如下:

root
├──annotations (folder)
├  ├── 1.xml
├  ├── 2.xml
├  └── n.xml
├──images (folder)
├  ├── 1.jpg
├  ├── 2.jpg
├  └── n.jpg
└──xml2yolo.py

导入

首先,在文件顶部追加以下导入语句:

import xml.etree.ElementTree as ET
import glob
import os
import json

效用函数

然后,定义以下效用函数:

  • xml_to_yolo_bbox —将 XML 边界框(xminyminxmaxymax)转换为 YOLO 边界框(x_centery_centerwidthheight)
  • yolo_to_xml_bbox —将 YOLO 边界框转换为 XML 边界框
def xml_to_yolo_bbox(bbox, w, h):
    # xmin, ymin, xmax, ymax
    x_center = ((bbox[2] + bbox[0]) / 2) / w
    y_center = ((bbox[3] + bbox[1]) / 2) / h
    width = (bbox[2] - bbox[0]) / w
    height = (bbox[3] - bbox[1]) / h
    return [x_center, y_center, width, height]def yolo_to_xml_bbox(bbox, w, h):
    # x_center, y_center width heigth
    w_half_len = (bbox[2] * w) / 2
    h_half_len = (bbox[3] * h) / 2
    xmin = int((bbox[0] * w) - w_half_len)
    ymin = int((bbox[1] * h) - h_half_len)
    xmax = int((bbox[0] * w) + w_half_len)
    ymax = int((bbox[1] * h) + h_half_len)
    return [xmin, ymin, xmax, ymax]

初始化

继续将以下变量添加到脚本中:

classes = []
input_dir = "annotations/"
output_dir = "labels/"
image_dir = "images/"os.mkdir(output_dir)

注意,如果在当前工作目录中存在一个名为 labels 的文件夹,那么os.mkdir将会产生一个错误。没有添加异常处理,因为它允许我们识别剩余文件并在干净的状态下工作。我们可以添加以下条件语句,在创建新目录之前检查该目录是否存在:

if not os.path.isdir(output_dir):
    os.mkdir(output_dir)

获取 XML 文件

之后,使用glob.glob函数获取annotation文件夹中所有xml文件的列表。循环检查标签文件是否有对应的图像:

files = glob.glob(os.path.join(input_dir, '*.xml'))
for fil in files:
    basename = os.path.basename(fil)
    filename = os.path.splitext(basename)[0]
    if not os.path.exists(os.path.join(image_dir, f"{filename}.jpg")):
        print(f"{filename} image does not exist!")
        continue

从逻辑上讲,标签文件应该有相应的图像文件。然而,图像文件不一定需要标签文件。一个图像文件可能不包含任何对象,我们称之为背景图像。

上面的代码将打印出没有图像对的注释的名称。要么删除注释,要么填充丢失的图像。

解析 XML 文件的内容

随后,使用ET模块解析 xml 文件的内容。调用findfindall函数从文件中提取特定的元素。每个元素对象都包含内置的text函数来获取底层值。追加结果,并将其保存为具有相同基本名称的文件。

files = glob.glob(os.path.join(input_dir, '*.xml'))
for fil in files:

    ... result = [] tree = ET.parse(fil)
    root = tree.getroot()
    width = int(root.find("size").find("width").text)
    height = int(root.find("size").find("height").text) for obj in root.findall('object'):
        label = obj.find("name").text
        if label not in classes:
            classes.append(label)
        index = classes.index(label)
        pil_bbox = [int(x.text) for x in obj.find("bndbox")]
        yolo_bbox = xml_to_yolo_bbox(pil_bbox, width, height)
        bbox_string = " ".join([str(x) for x in yolo_bbox])
        result.append(f"{index} {bbox_string}") if result:
        with open(os.path.join(output_dir, f"{filename}.txt"), "w", encoding="utf-8") as f:
            f.write("\n".join(result))

注意,新标签会自动添加到classes变量中。索引基于相应标签的第一次出现。因此,我们应该将 classes 变量保存为文本文件以供参考:

with open('classes.txt', 'w', encoding='utf8') as f:
    f.write(json.dumps(classes))

它将生成一个名为classes.txt的文本文件。文本文件将包含表示数据集中所有唯一类的字符串列表。例如:

["tablets"]

运行脚本

转换的完整脚本如下:

运行以下命令,将 XML 注释转换为 YOLO 格式的文本文件:

python xml2yolo.py

可视化边界框

在训练之前检查数据集的质量是一个很好的做法。有时,注释或图像配对可能是错误的。因此,需要验证数据集的质量。一个好方法是在相应图像的顶部绘制边界框。

我们可以使用PillowOpenCV包。本教程使用Pillow包来绘制边界框。

让我们创建另一个名为draw.py的脚本来可视化注释和图像。

导入

将以下导入语句添加到文件中:

from PIL import Image, ImageDraw

效用函数

我们将需要两个效用函数:

  • yolo_to_xml_bbox —将 YOLO 边界框转换回 XML 格式(基于像素)。这主要是因为Pillow的所有ImageDraw.Draw功能都使用像素。
  • draw_image —在输入图像的顶部绘制边界框。然后,通过用户界面显示出来。
def yolo_to_xml_bbox(bbox, w, h):
    # x_center, y_center width heigth
    w_half_len = (bbox[2] * w) / 2
    h_half_len = (bbox[3] * h) / 2
    xmin = int((bbox[0] * w) - w_half_len)
    ymin = int((bbox[1] * h) - h_half_len)
    xmax = int((bbox[0] * w) + w_half_len)
    ymax = int((bbox[1] * h) + h_half_len)
    return [xmin, ymin, xmax, ymax]def draw_image(img, bboxes):
    draw = ImageDraw.Draw(img)
    for bbox in bboxes:
        draw.rectangle(bbox, outline="red", width=2)
    img.show()

outline变量修改为边界框的不同颜色。

初始化

继续初始化以下变量:

image_filename = "images/medical_pills.jpg"
label_filename = "labels/medical_pills.txt"
bboxes = []

相应地替换文件名。

图像处理

加载图像并将预处理数据存储到bboxes变量中:

img = Image.open(image_filename)with open(label_filename, 'r', encoding='utf8') as f:
    for line in f:
        data = line.strip().split(' ')
        bbox = [float(x) for x in data[1:]]
        bboxes.append(yolo_to_xml_bbox(bbox, img.width, img.height))

绘制边界框

最后,调用draw_image实用函数在图像上绘制边界框:

draw_image(img, bboxes)

运行脚本

以下 Github 要点中的完整脚本:

保存文件并在终端上运行以下命令:

python draw.py

该脚本将显示一个图像,并在其上绘制相应的边界框。例如:

作者图片

如果边界框与预期结果不一致,则图像或注释是错误的。

分成不同的组

下一步是将数据集分成不同的部分。为简单起见,本教程分为三组,即训练、验证和测试。创建一个名为split_datasets.py的新 Python 脚本。

导入

像往常一样,在脚本顶部添加以下导入语句:

import random
import glob
import os
import shutil

效用函数

之后,定义一个实用函数,将现有的图像和注释复制到新的文件夹中。

def copyfiles(fil, root_dir):
    basename = os.path.basename(fil)
    filename = os.path.splitext(basename)[0] # image
    src = fil
    dest = os.path.join(root_dir, image_dir, f"{filename}.jpg")
    shutil.copyfile(src, dest) # label
    src = os.path.join(label_dir, f"{filename}.txt")
    dest = os.path.join(root_dir, label_dir, f"{filename}.txt")
    if os.path.exists(src):
        shutil.copyfile(src, dest)

当脚本中有错误或缺陷时,使用复制而不是移动来防止数据的意外丢失。

初始化

继续初始化以下变量:

label_dir = "labels/"
image_dir = "images/"
lower_limit = 0
files = glob.glob(os.path.join(image_dir, '*.jpg'))

glob用于图像文件,而不是注释,因为可能会出现图像不包含标签的情况。如果图像总数与标签文件总数不匹配,请不要惊讶。

我们将调用random.shuffle函数来随机重组数据集的顺序:

random.shuffle(files)

请注意,所有三个部分的最终分割在每次运行中都是不同的。如果数据集不*衡,这可能是一个问题。相应地修改脚本。

下一步是定义分割比例。本教程使用以下比率:

  • train — 80%的数据集
  • val —数据集的 10%
  • test — 10%的数据集
folders = {"train": 0.8, "val": 0.1, "test": 0.1}
check_sum = sum([folders[x] for x in folders])assert check_sum == 1.0, "Split proportion is not equal to 1.0"

添加一个断言来验证比率的最终总和等于 1 是一个很好的做法。这确保了每个部分之间没有数据集重叠。

只需更改字典的底层值。例如,下面的代码片段:

folders = {"train": 0.6, "val": 0.2, "test": 0.2}

将设定比率定义如下:

  • train — 60%的数据集
  • val — 20%的数据集
  • test — 20%的数据集

如果比例不等于 1,终端将输出以下错误消息。

AssertionError: Split proportion is not equal to 1.0

复制文件

最后但同样重要的是,将相应的图像和注释复制到所需的部分:

for folder in folders:
    os.mkdir(folder)
    temp_label_dir = os.path.join(folder, label_dir)
    os.mkdir(temp_label_dir)
    temp_image_dir = os.path.join(folder, image_dir)
    os.mkdir(temp_image_dir) limit = round(len(files) * folders[folder])
    for fil in files[lower_limit:lower_limit + limit]:
        copyfiles(fil, folder)
    lower_limit = lower_limit + limit

上面的代码片段将为 train、val 和 test 创建相应的文件夹。如果文件夹在创建过程中存在(在脚本的后续运行中),将会引发一个错误。每次运行前删除生成的文件夹,以确保没有数据集重叠。

运行脚本

分割数据集的完整代码如下:

在终端中运行以下命令:

python split_datasets.py

完成后,我们应该在工作目录中获得以下结构:

root
├──annotations (folder)
├  ├── 1.xml
├  ├── 2.xml
├  └── n.xml
├──images (folder)
├  ├── 1.jpg
├  ├── 2.jpg
├  └── n.jpg
├──test(folder)
├  ├── images (folder)
├  └── labels (folder)
├──train(folder)
├  ├── images (folder)
├  └── labels (folder)
├──val (folder)
├  ├── images (folder)
├  └── labels (folder)
├──draw.py
├──split_datasets.py
└──xml2yolo.py

现在,我们可以使用它来训练对象检测模型,使用支持 YOLO 注释的机器学习框架。

结论

让我们回顾一下今天的话题。

本文首先简要介绍了 PASCAL VOC XML 和 YOLO 格式。

然后,它提供了将 PASCAL VOC XML 文件转换为 YOLO 注释的深入指导。

随后,它强调了验证新创建的注释的重要性。可以通过创建一个在图像顶部绘制边界框的脚本来进行验证。

最后,它介绍了如何将数据集分成三个不同的部分,即训练、验证和测试。

感谢你阅读这篇文章。祝你有美好的一天!

参考

  1. YOLOv5 —列车定制数据
  2. ka ggle——药丸检测数据集

卷积神经网络(CNN)架构用简单的图表用简单的英语解释

原文:https://towardsdatascience.com/convolutional-neural-network-cnn-architecture-explained-in-plain-english-using-simple-diagrams-e5de17eacc8f

神经网络和深度学习课程:第 23 部分

原始图片由 Gerd AltmannPixabay 获得,由作者编辑

我们已经讨论了一种神经网络架构——多层感知器(MLP)。MLP 不适用于图像数据,因为即使对于小图像,网络中也涉及大量参数。

卷积神经网络(CNN)是专门为处理图像而设计的。它们广泛应用于计算机视觉领域。

CNN 的动机

以下是在处理图像数据时使用 CNN 而不是 MLPs 的两个主要原因。这些原因会激励你更多地了解 CNN。

  • 要对图像使用 MLPs,我们需要使图像变*。如果我们这样做,空间信息(相邻像素之间的关系)将会丢失。所以,准确度会大大降低。CNN 可以保留空间信息,因为它们以原始格式拍摄图像。
  • CNN 可以显著减少网络中的参数数量。因此,CNN 是参数有效的。

灰度与 RGB 图像(先决条件)

CNN 处理灰度和 RGB 图像。在我们继续之前,你需要了解灰度和 RGB 图像之间的区别

图像由像素组成。在深度学习中,图像被表示为像素值的数组。

灰度图像中只有一个颜色通道。因此,灰度图像被表示为(height, width, 1)或简称为(height, width)。我们可以忽略第三维度,因为它是一维的。因此,灰度图像通常表示为 2D 阵列(张量)。

RGB 图像中有三个颜色通道( R ed、 G reen 和 B lue)。因此,一个 RGB 图像被表示为(height, width, 3)。第三维表示图像中颜色通道的数量。RGB 图像被表示为 3D 阵列(张量)。

灰度与 RGB 图像表示(图片由作者提供,使用 draw.io 制作)

注意:这里有更多的资源来了解更多关于灰度和 RGB 图像的信息。

CNN 架构

与 MLP 架构相比,CNN 架构比较复杂。在 CNN 架构中有不同类型的附加层和操作。

CNN 以原始格式拍摄图像。我们不需要像在 MLPs 中那样将图像展*以用于 CNN。

CNN 中的层

CNN 中主要有三种类型的层:卷积层汇聚层全连接(密集)层。除此之外,在每个卷积层和全连接层之后添加激活层。

CNN 中的操作

CNN 中有四种主要类型的运算:卷积运算汇集运算展*运算分类(或其他相关)运算

别糊涂了!我将逐一讨论这些内容,并最终将它们结合起来,形成一个 CNN 架构的全貌。

卷积层和卷积运算

CNN 的第一层是卷积层。CNN 中可以有多个卷积层。第一个卷积层将图像作为输入并开始处理。

目标:

  • 从图像中提取一组特征,同时保持邻*像素之间的关系。

卷积层有三个元素:输入图像滤波器特征图卷积运算 发生在每个卷积层中。

卷积运算只不过是图像部分和滤波器之间的 元素乘和 运算。现在,参考下图。

卷积运算(图片由作者提供,用 draw.io 制作)

卷积操作发生在图像的一部分和过滤器之间。它输出特征图(缩小图像)。

滤镜:这也叫 内核 或者 特征检测器 。这是一个小矩阵。在单个卷积层中可以有多个滤波器。在卷积层中使用相同大小的滤波器。每个过滤器都有特定的功能。使用多个过滤器来识别图像中不同的一组特征。滤波器的大小和滤波器的数量应该由用户指定为超参数。该尺寸应小于输入图像的尺寸。过滤器内的元素定义了 过滤器配置 。这些元素是 CNN 中的一种参数,在训练期间学习。

图像部分:图像部分的大小应该等于我们选择的滤镜的大小。我们可以在输入图像上垂直和水*移动过滤器,以创建不同的图像部分。图像部分的数量取决于我们使用的 步幅 (稍后将详细介绍)。

特征图:特征图存储不同图像部分和滤波器之间的不同卷积运算的输出。这将是下一个池层的输入。特征图中元素的数量等于我们通过移动图像上的过滤器获得的不同图像部分的数量。

卷积计算

上图显示了图像部分和单个滤镜之间的卷积运算。您可以得到按行或按列的元素乘法,然后求和。

# Row-wise
**(0*0 + 3*1 + 0*1) + (2*0 + 0*1 + 1*0) + (0*1 + 1*0 + 3*0) = 3**

该计算的结果被放置在特征图中的相应区域中。

然后,我们通过将图像上的过滤器向右水*移动一步来进行另一个计算。我们在输入图像上移动滤波器的步数(像素)称为步距。移动可以水*和垂直进行。这里,我们用Stride=1。步幅也是一个应该由用户指定的超参数。

另一个步长=1 的卷积运算(图片由作者提供,用 draw.io 制作)

在这里,我们也可以得到按行或按列的元素乘法,然后求和。

# Row-wise
**(3*0 + 0*1 + 1*1) + (0*0 + 1*1 + 0*0) + (1*1 + 3*0 + 2*0) = 3**

该计算的结果被放置在特征图中的相应区域中。

同样,我们可以通过在图像上水*和垂直移动一步(用Stride=1)来进行类似的计算。

特征图的尺寸小于输入图像的尺寸。特征图的大小也取决于步幅。如果我们用Stride=2,尺寸会进一步缩小。如果 CNN 中有几个卷积层,那么最后特征图的大小会进一步减小,这样我们就不能在特征图上做其他操作了。为了避免这一点,我们使用应用填充到输入图像。填充是一个超参数,我们需要在卷积层进行配置。它会在图像的每一侧添加额外的零值像素。这有助于获得与输入相同大小的特征地图。

应用于输入图像的填充(图片由作者制作,用 draw.io 制作)

应用填充后,输入图像的新大小为(8,8)。如果我们现在用Stride=1做卷积运算,我们得到一个大小为(6x6)的特征图,它等于应用填充之前原始图像的大小。

上图显示了灰度图像和单个滤镜的卷积运算。当图像是 RGB 并且在处理过程中涉及多个滤镜时,您还应该对卷积运算有所了解。

多滤波器卷积运算

在这里,我只改变了过滤器的数量。输入图像类型仍然是灰度。

多重滤镜的卷积运算****(图片由作者提供,用 draw.io 制作)

唯一的区别是在特征图上增加了另一个维度。第三维度表示过滤器的数量。

RGB 图像上的卷积运算

这里,我对 RGB 图像应用卷积运算。这里使用单个过滤器。

****用单个滤镜对 RGB 图像进行卷积运算(图片由作者提供,用 draw.io 制作)

当图像是 RGB 时,滤镜应该有 3 个通道。这是因为 RGB 图像有 3 个颜色通道,需要 3 通道过滤器来进行计算。

这里,如前所述,计算发生在图像部分和滤波器之间的每个对应通道上。通过将每个通道的所有计算输出相加,获得最终结果。这就是为什么特征地图没有第三维。

用多个滤波器对 RGB 图像进行卷积运算

这是最复杂的版本,也是真实世界的场景。

****用多重滤镜对 RGB 图像进行卷积运算(图片由作者提供,用 draw.io 制作)

这里,另一个维度也被添加到特征映射中。第三维度表示过滤器的数量。

汇集层和汇集操作

池层是 CNN 中使用的第二种类型的层。在一个 CNN 中可以有多个池层。每个卷积层之后是一个汇集层。因此,卷积层和池层成对使用。

目标:

  • 通过获取最大数量或*均数量来提取最重要(相关)的特征。
  • 减少从先前卷积层返回的输出的维数(像素数)。
  • 减少网络中的参数数量。
  • 去除由先前卷积层提取的特征中存在的任何噪声。
  • 增加 CNN 的准确性。

池层有三个元素:特征图滤镜池特征图汇集操作 发生在每个汇集层中。

汇集操作发生在特征地图的一部分和过滤器之间。它输出汇集的要素地图。

有两种类型的池操作。

  • ****最大池化:获取应用过滤器的区域的最大值。
  • *****均池:获取应用过滤器的区域中值的*均值。

下图显示了应用于从之前的卷积运算中获得的要素图上的最大池化运算。

****最大池(图片由作者提供,用 draw.io 制作)

****过滤器:这一次,过滤器只是一个窗口,因为里面没有元素。因此,在池层中没有需要学习的参数。过滤器仅用于指定特征图中的一个部分。滤波器的大小应由用户指定为超参数。该大小应小于功能图的大小。如果特征图有多个通道,我们应该使用具有相同数量通道的过滤器。池操作将在每个通道上独立完成。

****特征映射部分:特征映射部分的大小应该等于我们选择的滤镜的大小。我们可以在特征图上垂直和水*移动过滤器来创建不同的部分。区段的数量取决于我们使用的步幅。

****汇集特征图:汇集特征图存储不同特征图部分和过滤器之间不同汇集操作的输出。这将是下一个卷积层(如果有)或展*操作的输入。

合并操作中的步长和填充

  • ****步幅:这里的步幅通常等于滤镜的大小。如果过滤器尺寸是(2x2),我们使用Stride=2
  • ****填充:将填充应用于特征图,以调整汇集的特征图的大小。

步幅和填充都是我们需要在池层中指定的超参数。

****注意:对特征图应用池化后,通道数不变。这意味着我们在特征图和汇集的特征图中具有相同数量的通道。如果特征图有多个通道,我们应该使用具有相同数量通道的过滤器。池操作将在每个通道上独立完成。

展*操作

在 CNN 中,从最终汇集层返回的输出(即最终汇集的特征图)被馈送到多层感知器(MLP ),该感知器可以将最终汇集的特征图分类到类别标签中。

MLP 只接受一维数据。因此,我们需要将最终的池化要素地图展*到保存 MLP 输入数据的单个列中。

与拼合原始图像不同,拼合合并贴图时会保留重要的像素相关性。

下图显示了如何展*仅包含一个通道的池化要素地图。

****展*单通道汇集特征图(图片由作者提供,用 draw.io 制作)

下图显示了如何展*包含多个通道的池化要素地图。

****展*多通道汇集特征图(图片由作者提供,用 draw.io 制作)

完全连接的(密集)层

这些是 CNN 的最后几层。输入是前一个展*的层。可以有多个完全连接的层。最后一层执行分类(或其他相关)任务。在每个完全连接的层中使用激活函数。

目标:

  • 将图像中检测到的特征分类到类别标签中。

CNN 中的层排列

在这里,我将讨论如何添加每一层来构建整个 CNN 架构。在典型的 CNN 中,各层按以下顺序排列。

****CNN 整体架构(图片由作者提供,用 draw.io 制作)

CNN 输入照原样获取图像。输入图像经过一系列的层和操作。

需要卷积层和汇集层来从图像中提取特征,同时保持重要的像素相关性。它们还减少了原始图像的维数(像素数量)。这些层成对一起使用。

ReLU 激活用于每个卷积层。

滤波器的数量在每个卷积层中增加。例如,如果我们在第一个卷积层使用 16 个滤波器,我们通常在下一个卷积层使用 32 个滤波器,以此类推。

前几层关注图像数据中不太重要的图案(如边缘)。末端层发现更复杂的图案(例如,脸部图像中的鼻子、眼睛)。最后一层完成分类任务。

ReLU 激活用于每个完全连接的层,除了最后一层,其中我们使用 Softmax 激活用于多类分类。

通过上图,我们可以把 CNN 想象成 MLP 的一个改良版。绿色框中的图层对图像进行了一些修改。橙色的盒子里装着 MLP。在绿色方框和橙色方框之间有一个展*层。

****注:CNN 中图层排列的编码部分将用 Keras 在单独的文章中完成。

今天的帖子到此结束。

如果您有任何问题或反馈,请告诉我。

我希望你喜欢阅读这篇文章。如果你愿意支持我成为一名作家,请考虑 注册会员 以获得无限制的媒体访问权限。它只需要每月 5 美元,我会收到你的会员费的一部分。

**https://rukshanpramoditha.medium.com/membership

非常感谢你一直以来的支持!下一篇文章再见。祝大家学习愉快!**

加入我的神经网络和深度学习课程

**

点击此图片进入我的神经网络和深度学习课程(作者截图)**

鲁克山·普拉莫迪塔
2022–06–20

解释了卷积神经网络——如何用 Python 成功地对图像进行分类

原文:https://towardsdatascience.com/convolutional-neural-networks-explained-how-to-successfully-classify-images-in-python-df829d4ba761

神经网络

用完整的 Python 示例直观地解释了 Deep 回旋网,该示例教您如何构建自己的 DCNs

使用深度卷积神经网络的图像识别(DCN)。形象由作者

介绍

一类特殊的神经网络叫做卷积神经网络(CNN) 是为图像识别而设计的。虽然这听起来可能超级幻想,但我向你保证,任何人都可以掌握它背后的主要思想。

在本文中,我将介绍 CNNs 的基本组成部分,并为您提供每个部分如何工作的示例。我还将介绍 Python 代码,您可以使用这些代码借助于 Keras/Tensorflow 库来构建深度卷积神经网络

内容

  • 机器学习算法领域中的卷积神经网络
  • 卷积神经网络的结构是什么?它们是如何工作的?
  • 一个完整的 Python 示例,向您展示如何构建和训练自己的 Deep CNN 模型

机器学习领域中的深度卷积神经网络(DCN)

下图是我尝试对最常见的机器学习算法进行分类的结果。

虽然我们经常以监督的方式将神经网络用于标注的训练数据,但我觉得它们在机器学习方面的独特方法值得单独归类。

因此,我的图显示了从机器学习领域的核心延伸出来的神经网络(NNs)。卷积神经网络占据了 NNs 的一个分支,并且包含诸如 DCN、DN 和 DCIGN 之类的算法。

下图为互动图,请点击不同类别放大显示更多👇。

机器学习算法分类。交互图由作者制作。

如果您喜欢【数据科学与机器学习】 ,请 订阅 获取带有我的新文章的电子邮件。

卷积神经网络的结构是什么?它们是如何工作的?

让我们从比较典型的前馈神经网络和卷积神经网络的结构开始。

在传统的前馈神经网络中,我们有输入、隐藏和输出层,其中每一层可能包含多个节点。我们通常将具有一个以上隐藏层的网络称为【深】网络。

深度前馈神经网络。图片由作者提供。

与此同时,卷积神经网络(CNN)往往是多维的,包含一些特殊的层,毫不奇怪地被称为卷积层。此外,卷积层通常伴随着池层(最大或*均),这有助于减少卷积特征的大小。

卷积神经网络。图片由作者提供。

卷积层

值得强调的是,我们可以有不同维度的卷积层:

  • 一维( Conv1D ) —适用于文本嵌入、时间序列或其他序列。
  • 二维( Conv2D ) —图像的典型选择。
  • 三维( Conv3D ) —可用于视频,本质上只是图像序列,或用于 3D 图像,如 MRI 扫描。

因为我在本文中主要关注图像识别,所以让我们更仔细地看看 2D 卷积是如何工作的。1D 和 3D 卷积的工作方式相同,只是它们少了一个或多了一个维度。

输入图像通过卷积层。图片由作者提供。

注意,对于灰度图片,我们只有一个通道。同时,我们将有三个独立的通道用于彩色图片,每个通道包含各自颜色(红、绿、蓝)的值。

我们还可以指定卷积层需要多少个滤波器。拥有多个过滤器可以让我们从图像中提取更广泛的特征。

卷积是如何工作的?

卷积有三个部分:输入(如 2D 图像)、滤波器(又称内核)和输出(又称卷积特征)。

卷积。对输入数据应用过滤器的迭代过程中的第一次计算。图片由作者提供。

卷积过程是迭代的。首先,对输入图像的一部分应用滤镜,并记录输出值。然后,当步距=1 时,滤波器移动一个位置,或者当步距设置为较大数值时,滤波器移动多个位置,重复相同的过程,直到卷积特征完成。

下面的 gif 图像说明了对 5x5 输入应用 3x3 过滤器的过程。

卷积在起作用。Gif 图片由作者提供。

让我详细说明以上内容,让您更好地理解过滤器的用途。首先,您会注意到我的自定义过滤器在中间一列全是 1。这种类型的滤波器设计用于识别输入图像中的垂直线,因为只要出现垂直线,它就会给出强信号(高值)。

为了比较,如果我们应用一个为寻找水*线而设计的过滤器,下面是卷积特征(输出)的样子:

用于查找水*线的过滤器。图片作者作者

如您所见,整个输出填充了相同的值,这意味着在输入图像中没有明确的水*线指示。

值得注意的是,我们不需要手动指定不同滤波器的值。滤波器的创建是在卷积神经网络的训练期间自动处理的。虽然,我们可以告诉算法我们想要多少个滤波器

附加选项

设置卷积层时,我们还有几个选项可以调整:

  • 填充 —在某些情况下,我们可能希望输出与输入的大小相同。我们可以通过添加一些填充来实现这一点。同时,它可以使模型更容易捕捉驻留在图像边缘的基本特征。

输入周围填充的卷积。图片由作者提供。

  • 步幅 —如果我们有大的图像,那么我们可能希望使用更大的步幅,即一次移动一个滤镜多个像素。虽然它确实有助于减小输出的大小,但较大的步幅可能会导致某些功能丢失,如下例所示:

使用 stride=(2,2)的卷积运算。Gif 图片由作者提供。

多重卷积层

设置多个卷积层来改善网络通常是有益的。这些好处来自后续卷积层识别图像内的额外复杂性。

深度卷积网络(DCN) 中的第一层倾向于找到低级特征(例如,垂直、水*、对角线……)。同时,更深的层次可以识别更高层次的特征,如更复杂的形状,代表真实世界的元素,如眼睛、鼻子、耳朵等。

汇集层

通常在卷积层之后添加一个池层。其目的是减少卷积特征的大小,提高计算效率。此外,它可以通过保持最强的激活来帮助消除数据噪声。

执行池化是为了减少卷积特征的大小。图片由作者提供。

有两种常用的池类型:

  • Max pooling —取内核覆盖区域的最高值(适合去噪)。
  • *均池 —计算内核覆盖区域的*均值。

最大池化和*均池化图解。Gif 图片由作者提供。

展*和密集图层

一旦我们完成了卷积特征的推导,我们需要将它们展*。这使我们能够拥有一个一维输入向量,并利用传统的前馈网络架构。最后,我们训练网络以找到最佳的权重和偏差,这使我们能够正确地对图像进行分类。

卷积神经网络的前馈部分。图片由作者提供。

根据数据的大小和复杂性,您可能希望有多对卷积层和池层,然后是多个密集层,使您的网络“更深”

一个完整的 Python 例子,向你展示了如何构建和训练你自己的深度 CNN 模型

设置

我们需要获得以下数据和库:

  • 加州理工学院 101 图像数据集(来源)

数据许可: 归属 4.0 国际(CC BY 4.0)

参考资料:飞飞、r .弗格斯和 p .佩罗娜。从少量训练实例中学习生成视觉模型
:在
101 个对象类别上测试的增量贝叶斯方法。IEEE。CVPR 2004,基于生成模型的视觉研讨会。2004

让我们导入库:

上面的代码打印了我在这个例子中使用的包版本:

Tensorflow/Keras: 2.7.0
pandas: 1.3.4
numpy: 1.21.4
sklearn: 1.0.1
OpenCV: 4.5.5
matplotlib: 3.5.1

接下来,我们下载并摄取加州理工学院 101 图像数据集。请注意,在这个例子中,我们将只使用四个类别(“达尔马提亚”、“刺猬”、“骆马”、“熊猫”),而不是全部 101 个。

与此同时,我们通过调整数据大小和标准化数据、对标签进行编码并将其分成训练样本和测试样本来准备数据。

上面的代码打印出我们的数据的形状,对于输入数据是[samples,rows,columns,channels],对于目标数据是[samples,labels]:

Shape of whole data:  (237, 128, 128, 3)
Shape of X_train:  (189, 128, 128, 3)
Shape of y_train:  (189, 1)
Shape of X_test:  (48, 128, 128, 3)
Shape of y_test:  (48, 1)

为了更好地理解我们正在处理的数据,让我们显示一些输入图像。

显示来自训练数据的 10 幅图像。图片由作者提供。

训练和评估深度卷积神经网络(DCN)

您可以按照代码中的注释来理解每个部分的作用。除此之外,这里有一些高层次的描述。

我将模型构建为具有多个卷积汇集丢弃层,以创建一个“深度”架构。正如本文前面提到的,初始卷积层帮助提取低级特征,而后面的卷积层识别更多的高级特征

所以我的 DCN 模型的结构是:

  • 输入层
  • 第一组卷积、最大汇集和丢弃层
  • 第二组卷积、最大汇集和丢弃层
  • 第三组卷积、最大汇集和丢弃层
  • 展*图层
  • 密集隐藏层
  • 输出层

请注意, Dropout 层根据我们提供的速率(在本例中为 0.2)随机将输入单位设置为 0。这意味着随机 20%的输入(要素/结点)将被设置为零,并且不会为模型贡献有意义的权重。脱落层的目的是帮助防止过度贴合

最后,请注意,我在第一组卷积和最大池层中列出了所有可能的参数,因为我想给你一个可以更改的简单参考。但是,我们将它们中的大多数保留为默认值,因此我们不需要每次都显式列出它们(请参见第二组和第三组卷积层和最大池层)。

有了指定的模型结构,让我们编译它,训练它并打印结果。

上面的代码打印了一个模型结构的概要:

深度卷积神经网络(DCN)模型概述。图片由作者提供。

它还以分类报告的形式打印性能摘要:

深度卷积神经网络(DCN)模型结果。图片由作者提供。

我们可以看到,该模型已经正确地识别了几乎所有的训练图像(f1-得分为 0.99)。然而,在测试数据上的表现却不尽如人意,f1 得分为 0.81。

可能会出现一些过度拟合的情况,因此值得尝试各种参数和网络结构,以找到最佳设置。与此同时,我们拥有的图像数量相对较少,这使得模型的训练和评估变得更加困难。

附加评估

最后,我想看看模型会把我的狗放在哪个类别。虽然我的狗不是达尔马提亚狗,但它是黑白相间的。我想知道这个模特是否会认出他是一只狗而不是一只熊猫😂

Jupyer 笔记本中我的狗的图像。图片由作者提供。

准备图像并使用先前训练的 DCN 模型来预测标签。

结果如下:

Shape of the input:  (1, 128, 128, 3)

DCN model prediction:  [['dalmatian']]

Probabilities for each category:
dalmatian  :  0.92895913
hedgehog  :  0.004558794
llama  :  0.010929748
panda  :  0.055552367

因此,模型已经确定我的狗是一只斑点狗,尽管有 5.5%的概率是一只熊猫😆

结束语

我真诚地希望你喜欢阅读这篇文章,并获得一些新的知识。

你可以在我的 GitHub 资源库 找到完整的 Jupyter 笔记本代码。可以随意用它来构建自己的深度卷积神经网络,如果有任何问题或建议,请随时联系。

还有,你可以在这里找到我的其他神经网络文章:前馈深度前馈RNNLSTMGRU

干杯!
索尔·多比拉斯

如果你已经花光了这个月的学习预算,下次请记得我。 我的个性化链接加入媒介:

https://solclover.com/membership

用于脑电图脑-机接口的卷积神经网络

原文:https://towardsdatascience.com/convolutional-neural-networks-for-eeg-brain-computer-interfaces-9ee9f3dd2b81

PyTorch 和 TensorFlow 中的代码示例

深度学习(DL)在各个领域的受欢迎程度都有了巨大的增长。DL 也已经被用于脑-机接口(BCI)和脑电图(EEG)。然而,DL 模型需要适应脑电图数据。这是如何做到的?在 BCIs 领域,DL 方法有多成功?

图一。乔希·里默尔在 Unsplash 上的照片

在这篇文章中,我们首先解释了为什么对于脑机接口来说,与传统的机器学习(ML)方法相比,DL 更有优势。我们解释卷积神经网络(CNN)如何工作,以及它们如何被改变和用于脑电图数据。我们将深入研究一个特定的网络 EEGNET,并在 PyTorch 和 TensorFlow 中提供 EEGNET 的代码示例。最后,我们讨论了如何对脑电图数据进行深度迁移学习。

该职位的组织结构如下:

  1. 为什么要用深度学习?
  2. 脑电图数据的专用 CNN
  3. 解释最流行的 CNN 脑电图数据:EEGNET
  4. TensorFlow 和 PyTorch 中的代码示例 EEGNET
  5. 深度迁移学习可能吗?

尽情享受吧!

为什么要深度学习?

在 BCI 领域,两种常见的分类方法是公共空间模式(CSP)和黎曼几何(RG)。这两种方法之前都有大量的预处理,其中最重要的一步是频率滤波,这是一种提取特征的方法。CSP 和 RG 在这里有更详细的解释,频率滤波在这篇文章有更详细的解释。

用于特征提取步骤的滤波器范围必须由研究者手动选择,这引入了主观偏见。其次,受试者之间最显著的大脑信号的频率范围也不同。由于手动寻找每个对象的最佳范围可能非常彻底,研究人员通常选择一个大致的范围(例如 8-40 赫兹),希望这个范围对所有对象都足够了。

这就是 DL 发挥作用的地方。

DL 的优势在于它是一种端到端的方法,其中在模型中结合了特征提取和分类。DL 模型可以从原始脑电图数据中提取特征,这意味着数据可以在没有研究人员手动选择过滤器的情况下进行预处理。一些研究使用原始脑电图数据[1],而其他研究仅在 1–100Hz 的宽范围内应用带通滤波器,以最大限度地减少极低频和高频噪声伪像[2]。

这种端到端方法消除了研究人员对频率滤波的主观偏见,DL 模型能够了解每个个体对象的最佳范围。

现在我们知道了 DL 的优点,让我们看看 DL 是如何在 BCI 领域使用的!

脑电卷积神经网络

DL 在 BCI 领域最突出的例子是卷积神经网络(CNN)的应用,它最初用于图像等计算机视觉任务,但也用于音频信号。

图像和音频信号通常具有分层结构,其中附*的特征对于当前特征是重要的,而远处的特征不那么重要。当 EEG 数据被视为 2D 阵列,以时间步长数为宽度,以电极数为高度时(如图 2 所示),EEG 数据具有与图像或音频信号相似的特征。附*时间点的数据对于当前数据点以及同一时间点其他通道的数据都很重要。使用卷积和非线性,CNN 可以在这些类型的数据中学习局部非线性特征和局部模式。

图 2:脑电图数据示例。脑电图数据可以被视为一个 2D 阵列,行是电极通道,列是时间点。图片作者。

CNN 通过使用内核来工作。内核是数据上的滑动窗口,从左到右、从上到下扫描。对于每次扫描,计算该窗口中的数据与内核值的点积,本质上总结了该窗口中数据的信息。下面的图 3 给出了一个直观的例子。

图 3:CNN 的滑动窗口。图片来自作者,灵感来自来源

关于 EEG 数据的 CNN,最流行的模型是用所谓的时间和空间卷积开发的。

时间卷积的核大小为 1 x 时间点,,其中滑动窗口将在特定时间帧内遍历每个通道,因此汇总了每个通道在该时间帧内的 EEG 数据。

对于每个时间点,对所有通道应用空间卷积,从而汇总所有通道的信息。卷积可以用不同的内核值应用多次,创建不同类型的原始数据摘要(称为特征映射)。

图 4:应用于脑电图数据的时间卷积和空间卷积。图片作者。

这种卷积的目的是通过用时间卷积表示频率滤波,用空间卷积表示空间滤波来表示 CSP 流水线。

EEGNET 是用于 EEG 分类的最流行的 DL 模型之一[1]。EEGNET 以其相对较大的网络和有限的参数数量而闻名,在最*的研究中被大量使用。

让我们详细解释 EEGNET,并附上代码示例!

EEGNET

图 5:为我们的研究调整的 EEGNET 网络。图片作者。

EEGNET 由一个时间和空间卷积组成,但也有另一种形式的卷积,称为可分离卷积。在以下章节中,将对 EEGNET 进行解释。

请注意,原始的 EEGNET 与我们在这里解释的实现略有不同。例如,原始论文的作者将模型应用于 64 个电极通道 x 128 个时间点的 EEG 数据,而我们使用的是 8 个电极通道 x 500 个时间点的 EEG 数据。一般来说,建议在将网络应用于您自己的数据时,试验一下内核大小和参数值。

网络的第一层是时间卷积。卷积的内核大小与原始的 EEGNET 保持一致,大小为 1 x 64 。该层中的特征地图的数量,命名为过滤器大小( fz ),是基于超参数搜索选择的。每个卷积层在卷积后应用批量归一化,以归一化前一层的输出,从而确保下一层的归一化输入。

第二层是大小为 8 x 1 的空间卷积。第一尺寸等于电极通道的数量。来自前一层的特征图的数量乘以深度参数( D ),该深度参数也是基于超参数搜索选择的。应用批量标准化后,用指数线性单位(ELU)实现非线性。当 x > 0,时,ELU 保持输出 x 不变,并且对于 x ≤ 0 ,函数exp(x)—1被应用。

然后,应用步长为 5 的核大小为5×1的时间*均池,对每 5 个时间点的数据进行*均以降低维数。由于我们研究中的输入大小(500)不能被原始网络中的步幅值 8 整除,所以我们选择了步幅值 5。

*均汇集后,辍学层紧随其后。在训练期间,dropout 以一定的概率随机地将输入的一些元素置零 pdrop 。这通过减少特定节点对早期层中的节点的依赖性来防止对训练数据的过度拟合,因为节点对之间的高度依赖性可能导致对训练数据中的特定特征的过度拟合,这不会出现在验证和测试数据中。通过超参数搜索找到了 pdrop 的值。

接下来,应用一个可分离的卷积层,该卷积层由一个核大小为 1 x 16 的时间卷积组成,如在原始 EEGNET 中所使用的,紧接着是一个 1 x 1 卷积,该卷积对来自前一层的所有特征映射上分组的核进行,本质上概括了特征映射上的时间卷积的输出。在这一层,另一批标准化和 ELU 被应用。

之后,应用了另一个 5 x 1 *均池,然后是一个 dropout 层。最后,数据被展*,并且应用了线性层。

与最初的 EEGNET 一样,上面解释的所有卷积层都是以步长 1 应用的,没有添加偏移。对于时间卷积,使用“相同”填充,其中零被添加到输入的左侧和右侧,以在卷积后具有相同的输出大小。

作为优化方法,使用了 Adam 优化器。Adam 的学习率 lr 也是通过超参数搜索找到的。

PyTorch 和 TensorFlow 中的 EEGNET

现在所有的解释都结束了,让我们看看如何编写这个模型!

最初的作者在他们的 Github 资源库中提供了他们在 TensorFlow 中的模型实现。它们在 TensorFlow 中实现,归结为以下代码:

我们的实现是在 PyTorch 中开发的,可归结为:

转移学习?

EEGNET 在应用单个个体的数据时,很可能会表现得非常糟糕。为什么?仅仅是因为数据量不足以让 EEGNET 正确校准。由于这个原因,迁移学习(TL)已经被用于 BCI 领域,在将模型应用于新的主题之前,模型将从多个主题的数据中学习。然而,最初的实验表明,用于 EEG 数据的 TL 伴随着许多困难和问题。让我们检查一下。

噪音可变性:脑电图捕捉源自你大脑的电活动。然而,脑电图电极不是智能设备。他们不能区分来自大脑的电信号和其他电信号。这可能是很多信号。想想你的手机,显示器,空调,你能想到的。这里的难点在于,这些噪声源每天都不一样,在其他环境中也不一样。这种噪音的可变性会导致您自己的实验中的受试者和会话之间的差异。但是想象一下在完全不同的环境中捕获的数据集之间的差异。尽管这种噪声只会少量影响 EEG 数据,但当在多个数据集或多个受试者的数据上训练通用模型时,它仍然会带来困难[3]。

脑电图仪:另一个可变性的来源是脑电图仪本身。这里的主要组成部分是将帽子放置在对象的头上。虽然我们有一个标准化的电极放置方法(10–20 国际系统),但是测量受试者头部的距离以及随后放置电极帽是一个稍微主观的过程。这导致受试者或会话之间的帽放置的微小差异,从而导致 EEG 信号的差异,因为电极可能离源自大脑的原始信号更远或更*。同样,当比较多个数据集的 EEG 数据时,这个问题变得更大。其他实验可能使用了不同的 EEG 设备,这些设备具有不同的材料和略微不同的帽放置..

神经可变性:大脑是一个复杂的器官。自然,用脑电图捕捉一个人的想法似乎很容易,但潜在的机制在受试者之间的差异中起着很大的作用,而且在同一受试者的日常差异中也是如此。

人们发现,对于相同的受试者,在相同的环境下执行相同的任务,大脑信号每天都不同[2]。这可能会在 DTL 过程中造成问题,而且还会使多天使用同一个模型变得困难。因此,模型应该每天微调或重新训练。

让 DTL 变得更加困难的是,一些受试者没有表现出足够强的大脑信号来被 DL 模型识别为模式[4]。在您的数据集中有这样的主题会在训练期间混淆 DL 模型。

最后,我们的思维方式也因人而异。如果我们以运动想象为例,我们可以用两种方式来实现它:

  • 动觉:想象以第一人称视角执行运动任务。
  • 视觉:想象某人或你自己从第三人称视角执行运动任务。

已经发现,与后者相比,第一种方法导致更清晰的大脑活动模式[5]。如果数据集包含两种方法的混合,这也会给 DTL 的学习过程带来问题。

一种用于 EEG 迁移学习的方法:为了总结迁移学习的主题,给出了将迁移学习应用于 EEG 数据的指南列表:

  • 为了确保受试者之间的数据相似,最好的办法是自己收集数据。在收集数据的过程中,你可以控制对受试者的指示(例如,指示他们只进行动觉运动想象)。还有,用的是同一个脑电图仪,环境尽可能的相似,帽子放置你有控制权。
  • 要执行 DTL,请在多个主题的数据上训练您的模型。对于特定的主题或会话,总是收集少量的数据来执行微调。将通用模型直接应用于新的主题或会话很可能会产生不好的结果。
  • 在训练过程中,在训练集中有多个主题,但在验证集中也有一个主题。在每个历元之后,通过对来自该主题的少量数据微调当前模型来模拟微调过程,然后通过对该主题的剩余数据应用模型来获得您的验证准确性。

结论

在这篇文章中,我们讨论了:

  • 深度学习如何凭借端到端学习的优势进入 BCI 领域
  • 为什么卷积神经网络是 BCI 领域最受欢迎的深度学习模型,以及它们是如何工作的
  • 关于 EEGNET 的深入解释,EEG net 是最受欢迎的 EEG 数据模型
  • 然后,我们在 TensorFlow 和 PyTorch 中提供了 EEGNET 的代码
  • 最后,我们讨论了在应用深度迁移学习时可能遇到的问题,以及如何通过专门的培训过程来克服这些问题。

感谢您的阅读。如果感兴趣的话,可以在我的另一篇文章这里中找到关于建立 BCI 系统所需的所有步骤的更多细节。

参考

  1. 弗农·劳赫恩、阿米莉亚·J·梭伦、尼古拉斯·R·韦托维奇、斯蒂芬·M·戈登、周*雄和布伦特·J·兰斯。 Eegnet:基于 eeg 的脑-计算机接口的紧凑卷积神经网络。神经工程学报,15(5):056013,2018。
  2. 张策,金永根,阿齐姆·埃斯坎达里安。 EEG-Inception:用于基于 EEG 的运动想象分类的精确且健壮的端对端神经网络。神经工程学报 18.4 (2021): 046014。
  3. 雅尔达·沙里亚里、特里萨·M·沃恩、LM·麦卡恩、布伦丹·Z·艾利森、乔纳森·R·沃尔帕和迪安·J·克鲁森斯基。使用纵向脑电图数据对肌萎缩侧索硬化患者脑机接口性能变化的探索。神经工程杂志,16(5):056031,2019。
  4. Benjamin Blankertz、Claudia Sanelli、Sebastian Halder、E . Hammer、Andrea Kübler、Klaus-Robert Müller、Gabriel Curio 和 Thorsten Dickhaus。预测 bci 性能研究 bci 文盲。英国医学委员会神经科学,10(增刊 1):2009 年第 84 页
  5. 克里斯塔·纽珀、莱因霍尔德·舍雷尔、米丽娅姆·赖纳和格特·普福尔茨赫勒。运动动作的想象:单次脑电图中动觉和视觉-运动想象模式的差异效应。认知大脑研究,25(3):668–677,2005。

卷积神经网络:从日常理解到更具技术性的深度探讨

原文:https://towardsdatascience.com/convolutional-neural-networks-from-an-everyday-understanding-to-a-more-technical-deep-dive-83af329e5d89

等等,电脑知道怎么看?!?

最*,我不得不使用卷积神经网络(CNN)进行研究,并不断试图自己理解它们是什么。虽然研究不同的功能并不难,但最难的部分是试图用一种有意义且不太专业的方式向我的朋友和家人解释 CNN。今天,我想提供 CNN 的技术定义和非技术定义,以帮助你更好地理解什么是 CNN,并帮助你向你认识的人解释它们!

图片来自作者

哇哦。我的电脑有眼睛?!

电脑是怎么看的?卷积神经网络(CNN)!这些机器学习算法目前处于计算机视觉和解释图像和视频的最高梯队。这篇文章将提供一个技术定义,加上一个“我对机器学习一无所知”的定义,让你更深入地理解 CNN,并在日常对话中向你的朋友和同事解释它们。对于这个例子,我将使用我的狗 Biscotti 的图片作为参考!

意大利脆饼!(图片来自作者)

卷积层

现在,请注意,由于我们看到的是红色、绿色和蓝色(RGB)光谱,从技术上讲,每种颜色都有自己的层。为了今天的讨论,我把这个因素放在一边,以减少解释的复杂化。

“我对机器学习一无所知”的解释

神经网络的卷积层充当计算机的眼睛,并像人眼一样扫描图像!随着时间的推移,图层帮助网络将不同的要素与某一类样本相关联,以进行分类。例如,如果我向 CNN 展示狗和人类的各种图片,它可能会学会将任何有 4 条腿的东西与狗联系起来,而将两条腿与人类联系起来!实质上,CNN 将从图像的每个部分获取信息。它将为图像的每个部分创建一个小部分。例如,一个内核可能通过网络的第一层获得我的狗的某些部分。

找到一只耳朵!(图片来自作者)

随着内核继续沿着图像移动,它将获得图像的其他属性。例如,它可以在一个节点中找到我们的狗的鼻子。

找到一个鼻子!(图片来自作者)

使用不同的模式,CNN 的各层将学习如何提取特征和这些特征的某些方面(鼻子的轮廓和组成鼻子的不同颜色)。你可能想知道,计算机能看到颜色吗?嗯,算是吧。一幅图像必须被转换成一个数值数组,每个数值代表一种特定的颜色。解释这一点的一种方式是想象计算机将一幅图像变成一个数字网格,其中距离较*的数字代表相似的颜色。

图像变成像素值(图片来自作者)

技术解释

在 CNN 的卷积层中,这些层以密集相关的点为目标,这些点最终是图像中的重要特征(1)。一层中放置的神经元数量取决于数据集的复杂性、计算能力和内存可用性。卷积层是根据它们对图像中给定张量执行的卷积矩阵运算而命名的。卷积运算需要一个张量

并在图像片段和之间进行逐元素乘法

其中 kI 是由第层索引的第k卷积核。提取数据的图像区域
由坐标 xy 给出。c 是通道的索引(1 代表灰度,3 代表 RGB)。

卷积方程(图片来自作者)

P 是特征矩阵中的总行数,而 Q 是特征矩阵中的总列数。

卷积核(滤波器)

“我对机器学习一无所知”的解释

本质上,内核是 CNN 的一部分,它从图像的每个部分获取信息。每个内核;会有不同的图案,这样计算机就可以找到样本的不同特征。例如,一些过滤器会在图像中找到波状图案,而其他过滤器可能会找到直的、水*的图案。看情况吧!一个过滤器可能会找到狗的边缘,而另一个过滤器能够拾取构成狗的皮毛的图案。

技术解释

卷积层中的滤波器(也称为“内核”)通过为每个神经元设置不同的权重来分解采样到该层的输入,
产生各种特征图。神经元将忽略除了在其感受野收集的数据以外的所有信息。例如,具有代表穿过其 nxn 感受野中间的水*线的核的神经元将把所有输入乘以零,除了穿过中心水*线的那部分输入。卷积核在图像上的移动由层的步幅决定。

进展

“我对机器学习一无所知”的解释

步幅告诉我们,我们的计算机应该移动多少来拾取图像的下一个特征框。例如,选择一个太大的步幅,你可能会错过图像的特征。如果我们选择一个巨大的步幅,我们可能会迫使 CNN 跳过狗的脸,让计算机认为狗没有脸和两只耳朵。那就太可怕了!

这一大步迈得真大!(图片来自作者)

技术解释

步幅是每个感受野之间的距离(一个核从一个分区移动到另一个分区的距离)。通常,使用跨距 2,因为它也具有对图像进行下采样的效果。

汇集层

“我对机器学习一无所知”的解释

想象一下,在这一点上,美国有线电视新闻网已经扫描了我的狗的一堆较小的图像。也许它会有一些重要的特征,比如我的狗的鼻子

找到一个鼻子!(图片来自作者)

也许会有一些不太重要的特征,比如图像的背景噪声

通过汇集图像的特征,计算机可以开始丢弃不太重要的特征,并专注于感兴趣的特征,将从这些重要特征收集的信息结合在一起。随着时间的推移,计算机希望摆脱图像的背景信息,只关注描述实体的重要特征的组合(在这种情况下,鼻子对狗很重要,但地毯不重要!),导致模型以某种概率对图像内的对象类型进行分类。

技术解释

在卷积层之后,实施汇集层,目的是对图像执行维数减少,减少参数的数量和模型的复杂性(2)。在汇集层,“几个附*的特征检测器的输出被组合成一个局部或全局的‘特征包’,以某种方式保留与任务相关的信息,同时移除不相关的细节”(3)。池层的目标是在每一步获得图像的子样本,并揭示不变特征。(4)图像分类中流行的两种方法是*均池和最大池。*均池取每个步长内核中所有元素的*均值。

*均池(图片来自作者)

最大池在每一步中获取过滤器中的最大数量。对于对象识别,已经发现最大池化减少了误差,并且在用于特征提取的图像下采样中提供了改进。

最大池(图片来自作者)

填料

“我对机器学习一无所知”的解释

进入的图像大小必须与出去的图像大小相同!说够了!

技术解释

由于样本的输入大小随着其穿过
CNN 的层而减小,填充确保网络的输出样本大小与输入样本大小和形状相同。零填充将零添加到输入图像的任何边界,当向下传递到神经网络的层时,该边界被丢弃。

全连接层

“我对机器学习一无所知”的解释

想象一下,现在计算机已经找到了所有重要的特征,需要弄清楚它在看什么。全连接层是 CNN 的“大脑”,将从提供给它的特征中提取信息,并预测所有这些特征的相似之处。

技术解释

一旦图像通过 CNN 架构的卷积层,它必须被展*为一维数组,以通过一系列完全连接的层。CNN 架构的全连接层反映了典型的人工神经网络(ANN)。信息通过各层传递,最终进入激活功能。然后,在网络优化器
的支持下,使用反向传播来更新全连接层的权重,以输出更准确的结果。随着时间的推移,不断向完全连接的层提供批量样本将有助于它学习对 CNN 解析的图像进行正确的分类预测。

结论

现在你知道了!现在你对计算机如何看有了高层次的理解!围绕 CNN 做了很多研究,我强烈建议你找到更多,并尝试自己实现它们!

如果你喜欢今天的阅读,请关注我,并告诉我你是否希望我探讨另一个主题(这对我的帮助超乎你的想象)!另外,在LinkedIn上加我,或者随时联系!感谢阅读!

来源

  1. Asifullah Khan、Anabia Sohail、Umme Zahoora 和 A. Qureshi。深度卷积神经网络的最新结构综述。人工智能评论,第 1-62 页,2020 年。
  2. 凯龙·奥谢和瑞安·纳什。卷积神经网络导论。更正,abs/1511.08458,2015 年
  3. 伊兰·布鲁,让·庞塞和扬·勒昆。视觉识别中特征池的理论分析。《第 27 届国际机器学习会议论文集》, ICML,10 年,第 111-118 页,麦迪逊,WI,美国,2010 年。全媒体。
  4. 奥雷连恩·杰龙。用 Scikit Learn & TensorFlow 实践机器学习。O Reilly 媒体公司,塞瓦斯托波尔,2017。

使用 Python 实现一维卷积

原文:https://towardsdatascience.com/convolutions-in-one-dimension-using-python-54d743f18063

Unsplash 上由 Ocramnaig_o1 拍摄的照片

了解 CNN 的构建模块,停止获取大小不匹配的错误

我经常看到有人想学习如何快速开发深度学习应用程序,他们学习了 PyTorch 或 Tensorflow 等一些库的基础知识,但他们并没有真正理解那些他们如此肤浅地使用的神奇功能背后的含义。经常会发生这样的情况,当一些东西不工作或者你需要定制一些功能时,没有人知道从哪里开始。

当一个人对计算机视觉感兴趣时,他通常会开始研究卷积神经网络,从高层次来看,它们是非常容易理解的。但有时,当我的朋友或同事不是在处理二维图像,而是必须使用一维卷积时(例如,因为他们必须处理信号),他们会感到非常困惑,因为他们无法想象正在发生什么。这是因为他们还没有完全理解 CNN 的构建模块。因此有了这篇文章的名字。

介绍📚

1959 年,大卫·H·哈贝尔和托尔斯滕·威塞尔发现了人类视觉皮层的一种特殊功能。根据一个人正在看的图像,神经元被不同地激活。具体来说,视觉皮层有不同的层次。第一层是在看有边缘的图像时激活的,第二层是在给图像添加细节时激活的,依此类推…

卷积神经网络正是受到这种功能的启发。如您所知,它们被分为不同的层,每一层都试图从正在处理的原始图像中提取特征。
第一个 CNN 是由 Yann LeCun 在 20 世纪 90 年代开发的,并且在著名的论文 中描述了使用反向传播网络 的手写数字识别。

一点背景知识👨🏼‍🎓

在开发机器学习算法时,最重要的事情之一(如果不是最重要的话)是提取最相关的特征,这是在项目的特征工程部分中完成的。在 CNN 中,这个过程是由网络自动完成的。特别是在早期层中,网络试图提取图像的最重要的特征,例如边缘和形状。另一方面,在最后一层,它将能够结合各种特征来提取更复杂的特征,如眼睛或嘴巴,这可能是有用的,例如,如果我们想创建一个人类图像的分类器。

让我们想象一只狗的形象。我们希望在这个图像中找到一只耳朵,以确保有一只狗。我们可以创建一个过滤器内核,一次运行整个图像的一部分,看看它是否能在图像的不同点找到一只耳朵。

特征图(图片由作者提供)

在图像中,我们有一组紫色的权重(内核),当乘以输入图像的像素值时,它会告诉我们是出现了耳朵还是下巴。我们是如何创建这些重量参数的?嗯……随意!这将是网络的训练,它将慢慢地学习正确的权重参数。

最终的输出(橙色)被称为特征图
通常在卷积之后,所以在获得特征地图之后,我们有汇集图层来汇总更多信息,然后我们将有另一个卷积,等等——但是在本文中我们不讨论其他图层。

一维卷积💻

我们已经直观地理解了卷积是如何从图像中提取特征的。但是卷积也经常用于其他类型的数据,如文本,这是因为卷积只不过是一个公式,我们需要了解它是如何工作的。
一维卷积是在两个向量之间定义的,而不是像图像中常见的那样在矩阵之间定义的

所以我们将有一个向量 x 作为我们的输入,还有一个内核 w 作为第二个向量。

卷积公式(图片作者提供)

符号 ***** 表示卷积(不是乘法)。 Y[i] 是合成向量 y 的条目 i

首先,如果你注意到求和的极值从 -inf+inf ,但是这在机器学习中没有多大意义。我们通常在前面加上一定的尺寸。假设输入向量的大小必须是 12。但是如果向量小于前缀的大小会发生什么呢?嗯,我们可以在向量的开头和结尾添加零,使其大小合适,这种技术被称为填充

填充(图片由作者提供)

然后我们假设原始输入 x 和滤波器 w 分别具有尺寸 nm ,其中 n ≤ m 。那么具有填充的输入将具有大小 n + 2p 。而原来的公式会变成如下。

卷积公式(图片作者提供)

从上面的公式中,我们可以注意到一点。我们所做的是滚动矢量 x_p 和矢量 w 的单元格。不过,向量 x_p 是从右向左滚动,w 是从左向右滚动。但是然后我们可以简单地反转向量 w 并且执行 x_pw_rotated 之间的向量积。
让我们直观地看看会发生什么。首先,我们旋转过滤器。

滤镜旋转(图片由作者提供)

初始公式告诉我们要做的是,在两个向量之间做矢量积,只考虑初始向量的一部分。这部分被称为局部感受野。然后,我们每次将向量 w_r 滑动两个位置,在这种情况下,我们会说我们使用的是 stride = 2 。后者也是我们需要优化的网络的超参数。

步幅=2 的 1D 卷积(图片由作者提供)

衬垫️⃣

您应该注意到,根据我们使用的填充模式,我们会或多或少地强调一些输入单元格。在前面的例子中,当我们计算输出 y[0] 时,单元格 x[0] 只被考虑了一次。相反, x[2] 单元格在 y[1]y[2] 的计算中都被考虑,因此它更重要。我们还可以通过使用填充来处理向量边界处的单元格的重要性。
有 3 种不同类型的衬垫:

  1. 全模式:填充参数 p 设置为 p = m-1 ,其中 m 为内核大小。这种填充导致输出大于输入,因此很少使用。
  2. 相同模式:用于确保输出与输入大小相同。例如,在计算机视觉中,输出图像将与输入图像大小相同,因此通常是最常用的。
  3. 有效模式:当 p =0 时,所以我们不使用填充。

如何确定卷积输出的大小?

许多人经常对 CNN 各层的输入和输出大小感到困惑,并与不匹配错误作斗争!实际上,计算卷积层的输出大小非常简单。

假设我们有一个输入 x, a 内核 w 并且想要计算卷积 y = xw* 。

要考虑的参数将是 x 的尺寸 nw 的尺寸 m填充 p步距 s 。输出的尺寸 o 将由以下公式给出:

卷积输出尺寸(图片由作者提供)

⌊⌋符号表示楼层操作。例如⌊2.4⌋ = 2。
让我们通过例子来看看如何应用这个公式:

示例 1(图片由作者提供)

在第一个示例中,我们看到输出大小与输入大小相同,因此我们推断我们使用了相同的模式填充。
我们看到另一个例子,我们改变了内核大小和步幅。

示例 2(图片由作者提供)

我们来编码吧!⌨️

如果到目前为止你还是有点迷茫,没问题。让我们开始接触代码,事情会变得更加清晰。

让我们试着在一些真实数据上运行这个函数,看看结果。让我们将结果与 NumPy 内置的自动计算卷积结果的函数进行比较。

最后的想法🤔

如您所见,我们开发的函数和 NumPy 的卷积方法的结果是相同的。卷积是卷积神经网络以及现代计算机视觉的基本元素。我们经常在不了解组成复杂算法的构件的情况下,立即开始实现复杂的算法。在我看来,一开始,花一点时间去更详细地了解那些看起来更没用、更无聊的东西,可以在未来节省我们很多时间,因为我们将知道如何立即解决我们在途中发现的各种错误。在下一篇文章中,我的目标是在二维情况下进行归纳!👋🏽

结束了

马赛洛·波利蒂

LinkedinTwitterCV

凉爽散点图

原文:https://towardsdatascience.com/cool-scatter-plots-dfb23bebb3dc

如何改变 seaborn 的大小和颜色

在本文中,作者 Corey Wade,Berkeley Coding Academy承担了 Python、pandas 和 matplotlib 的基础知识。所有代码都可以在 Colab 笔记本这里

你可能在网上看到过非常酷的散点图。这些点不是显示统一大小和颜色的点,而是以某种方式改变大小和颜色,增加了新的数据维度。图表不仅看起来更好,而且信息量也更大。

在本文中,我将向您展示如何通过几个简单的步骤使用 seaborn 创建非常酷的散点图。Seaborn 与 matplotlib 配合得很好,所以如果您以前使用过 matplotlib,就可以使用了。

来自维基共享,免费的媒体仓库。知识共享 归属 2.0 通用许可

鲍鱼壳数据

首先,让我们找一些数据来处理。我从 UCI 机器学习库中选择了鲍鱼壳数据。下面是将鲍鱼壳数据加载到 Jupyter 或 Colab 笔记本的 Python 代码。

import pandas as pddf = pd.read_csv(‘https://archive.ics.uci.edu/ml/machine-learning-databases/abalone/abalone.data', header=None)df.columns = [‘Sex’, ‘Length’, ‘Diameter’, ‘Height’,‘Whole weight’, ‘Shucked weight’, ‘Viscera weight’,‘Shell weight’, ‘Rings’]df.head()

图片由作者科里·韦德提供

如您所见,鲍鱼壳数据包含除“性别”列之外的所有数字列。鲍鱼壳数据集的通常目标是在给定长度、高度和性别测量值的情况下预测年轮的数量。

Matplotlib 图

在创建 seaborn 图之前,让我们创建一个标准的 matplotlib 图进行比较。

y 值将是我们试图预测的“环”列,而 x 值可以是任何值。让我们从“直径”一栏开始。

# Create baseline scatterplot
import matplotlib.pyplot as plt
plt.scatter(df['Diameter'], df['Rings'])
plt.show()

图片由作者科里·韦德提供

正如所料,图表呈上升趋势。当鲍鱼壳的直径增加时,环的数量通常增加,比预期的变化更多。(设置 alpha=0.4plt.scatter 显示异常值。)

第一 Seaborn 图

让我们使用 seaborn 添加一些大小和颜色的变化。首先,seaborn 需要进口。我更喜欢实现 seaborn 的灰色背景和白色网格。两者都可以如下进行。

# Import seaborn and set grid
import seaborn as sns
sns.set()

现在让我们创建一个 seaborn 散点图。和 plt.scatter 有点不同,但是风格足够接*。除了设置 x=df['直径']y=df['环'] 之外,我们还可以自由选择列的大小和色调,如下面的代码片段所示。

# Create scatter plot with size and hue variation
sns.scatterplot(x=df['Diameter'], y=df['Rings'],
                size=df['Height'], hue=df['Shucked weight'])
plt.show()

图片由作者科里·韦德提供

从上图可以看出,seaborn 自动包含了一个 x 和 y 标签,以及一个关于色调和尺寸的漂亮图例。但是大小变化不清楚,图例截断了太多数据。

改进的 Seaborn 图

美化图形没有限制。我更喜欢在视觉吸引力和高效代码之间取得*衡。以下改进用最少的代码优化了 seaborn 散点图。

  1. 使用PLT . fig . fig(figsize)放大绘图,以获得更多屏幕空间,同时限制图例。
  2. 通过 sns .散点图中的尺寸参数包含更多尺寸变化。
  3. 使用 plt.savefig 获得带标题的高分辨率输出。(“dpi”参数代表“每英寸点数”。)

下面是上述实现的 Python 代码,以及从 Colab Notebook 文件夹下载到我的本地机器的 png 图像。

# Change figure size
plt.figure(figsize=(13,6))# Create cool scatter plot
sns.scatterplot(x=df['Diameter'], y=df['Rings'],
               size=df['Height'], hue=df['Shucked weight'],
               sizes=(20,600))# Give title
title = 'Abalone Shells Scatterplot'
plt.title(title)# Save graph
plt.savefig(title, dpi=200)
plt.show()

图片由作者科里·韦德提供

上图是一个明确的改进。散点图清楚地显示,壳重和壳高以及直径的增加结合起来预测鲍鱼壳有更多的环,图例放置得很好。

Seaborn 调色板

虽然 seaborn 的默认颜色令人印象深刻,但改变调色板以适应您的数据故事绝对值得付出努力。

调色板参数包含在 sns .散点图选项中。查看调色板选项的一个很酷的技巧是向调色板参数中输入天书(无论你想要什么),如下面的代码片段所示。

# Create cool scatter plot
sns.scatterplot(x=df['Diameter'], y=df['Rings'],
               size=df['Height'], hue=df['Shucked weight'],
               sizes=(20,600),
               palette='ooooo')

图片由作者科里·韦德提供

当调色板值强制出错时,seaborn 显示调色板选项是多么好啊!在 seaborn 语言中,' _r '是反转的意思,表示调色板是可逆的,原色是缩写的,所以' Bu '是' Blue '的缩写,以此类推。

既然鲍鱼壳来自海洋,那就试试‘蓝色’的调色板吧。

# Change figure size
plt.figure(figsize=(13,6))# Create cool scatter plot
sns.scatterplot(x=df['Diameter'], y=df['Rings'],
               size=df['Height'], hue=df['Shucked weight'],
               sizes=(20,600),
               palette='Blues')# Give title
title = 'Abalone Shells Scatterplot'
plt.title(title)# Save graph
plt.savefig(title, dpi=200)
plt.show()

图片由作者科里·韦德提供

现在,代表海浪的颜色选择为数据故事添加了一个新的图层。

散点图子集

防止大型散点图拥挤的一个重要调整是查看数据的子集。通常,几百行就足以获得模式的指示,而不会丢失临界值。

以下 Python 代码将散点图限制为前 400 行。

# Take subset of data for scatterplots
df_sub = df[:400]# Change figure size
plt.figure(figsize=(13,6))# Create cool scatter plot
sns.scatterplot(x=df['Diameter'], y=df['Rings'],
               size=df['Height'], hue=df['Shucked weight'],
               sizes=(20,600),
               palette='Blues')# Give title
title = 'Abalone Shells Scatterplot'
plt.title(title)# Save graph
plt.savefig(title, dpi=200)
plt.show()

图片由作者科里·韦德提供

这是一个漂亮的图表。一些高度较大的异常值已被移除,以允许更大的视觉变化。

分类列有效

回想一下,鲍鱼壳数据集包括带有选项“M”、“F”和“I”的“性别”列,这些选项根据数据源代表“男性”、“女性”和“婴儿”

令人惊叹的是,seaborn 散点图允许对色调和大小进行分类选择,如下面的代码片段所示。

首先,我们设置 hue=df['Sex'] ,其他都不变。

# Change figure size
plt.figure(figsize=(13,6))# Create cool scatter plot
sns.scatterplot(x=df['Diameter'], y=df['Rings'],
               size=df['Height'], hue=df['Sex'],
               sizes=(20,600),
               palette='Blues')# Give title
title = 'Abalone Shells Scatterplot'
plt.title(title)# Save graph
plt.savefig(title, dpi=200)
plt.show()

图片由作者科里·韦德提供

正如预期的那样,深蓝色的幼鲍壳较小,尽管雌雄壳之间没有明显的图案。

接下来,我们设置 size=df['性别']hue=df['高度'] 。换句话说,我们呈现相同的数据,但是切换了尺寸颜色参数。我也选择了通过设置调色板='Blues_r' 来反转蓝色。

# Change figure size
plt.figure(figsize=(13,6))# Create cool scatter plot
sns.scatterplot(x=df['Diameter'], y=df['Rings'],
               size=df['Sex'], hue=df['Height'],
               sizes=(20,600),
               palette='Blues_r')# Give title
title = 'Abalone Shells Scatterplot'
plt.title(title)# Save graph
plt.savefig(title, dpi=200)
plt.show()

图片由作者科里·韦德提供

我喜欢上图中婴儿鲍鱼壳很小!

把所有的放在一起

在本文中,您了解了如何使用 seaborn 改变散点图的大小和颜色,以及修剪数据集、使用分类列和优化图像输出的额外好处。

下面是所有的代码,加上一个调整后的参数 size=df['Shell weight'] 得出一个原始的图形。

# Load Abalone Shell Data
import pandas as pd
df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/abalone/abalone.data', header=None)
names = ['Sex', 'Length', 'Diameter', 'Height', 'Whole weight', 'Shucked weight', 'Viscera weight', 'Shell weight', 'Rings']
df.columns=names# Take subset of data for scatterplots
df_sub = df[:400]# Change figure size
plt.figure(figsize=(13,6))# Create cool scatter plot
sns.scatterplot(x=df_sub['Diameter'], y=df_sub['Rings'],
               size=df_sub['Sex'], hue=df_sub['Shell weight'],
               sizes=(20,600),
               palette='Blues_r')# Give title
title = 'Abalone Rings Scatterplot'
plt.title(title)# Save graph
plt.savefig(title, dpi=200)
plt.show()

图片由作者科里·韦德提供

编码快乐!这里是完整的 Colab 笔记本供你参考。

“酷散点图”是在 柏克莱编码学院 教授给湾区及更远地区青少年的众多主题之一。暑假期间, 伯克利编码学院 提供了机器学习& AI 暑期项目,此外还有全年 1-1 节课。作者科里·韦德是伯克利编码学院https://www.berkeleycodingacademy.com/的导演和创始人。

数据科学家的酷软件工程概念

原文:https://towardsdatascience.com/cool-software-engineering-concepts-for-data-scientists-d6bd54243f4e

这些是我作为数据科学家和团队成员学到的一些软件工程概念

照片由 @maxcodes @Unsplash.com 拍摄

与许多数据科学家一样,我的背景是统计学。当我偶然发现这个领域时,我真的被预测模型所吸引,鉴于我的背景,他们背后的推理是第二天性。我 10 年前开始从事这个行业,当时它还在从数据挖掘向数据科学进行语义转换。在数据挖掘领域,大多数工具都是拖放式的(如 IBM SPSS Modeler 或 SAS Enterprise Miner ),大多数预测模型都没有在代码中部署——R 虽然存在,但主要用于学术环境。

从我与业内人士的几次交谈中,我的经历似乎与大多数统计学家相似——一开始,我们可能开发了一些代码,但我们并不特别担心它的质量。

刚开始的时候我的软件工程技术有点差。我没有接受过编写正确代码或遵循软件工程最佳实践的培训。幸运的是,我和很多工程师一起工作过,他们指导我改进代码,教给我一些概念,这些概念对于提高我作为数据科学家的技能非常重要。意识到他/她的代码质量的数据科学家是一个更有同情心的专业人士——他关心那些将不得不在事后调试、部署或改进他们的模型的人,并可能在未来避免许多技术债务

在这篇文章中,我将分享一些最酷的概念,它们帮助我提高了代码编写技能,并成为一名更全面的数据科学家。

棉短绒

linter 是一个软件,它检查你的代码是否有错误或不一致,指导你写更干净的代码。

使用棉绒在两个方面帮助了我:

  • 在语法方面,构建更加一致的代码;
  • 早点抓虫子;

例如,如果你使用 Python,你可以在你喜欢的 IDE 上使用 flake8pylint,它会自动嗅出你的脚本中的代码错误或风格不一致。第一次使用棉绒也会让你惊讶于你以前不知道的习惯。举个例子,当我写代码时,在使用 linter 之前,我总是在缩进代码之前在许多指令上使用不必要的尾随空白——当然我的代码是工作的,但是那些尾随空白是我在没有必要的情况下进行的额外击键。**

当您 lint 您的代码时,其他用户会更好地阅读它,因为大多数开发人员遵循相同的风格指南——对于 Python,官方的风格指南是 PEP 8 ,前面提到的 flake8pylint 使用的风格指南。风格指南是一组规范化的规则来格式化你的代码,比如编写函数、注释代码等的通用格式。

棉绒的另一个优点?它们还指出了我们编写代码时会出现的常见错误,例如调用尚未声明的对象。总而言之,linters 对于开发者来说是一个伟大的生产力工具。

面向对象编程

当你开始编码时,特别是当你开始在一个数据项目中编码时,你可能不会立即陷入面向对象编程(OOP)中。

在大多数工程学位中,OOP 是初学者的概念——让你的程序灵活是必不可少的。OOP 使您能够启动您的脚本并使用具有特定行为、方法和属性的对象。

一件很酷的事情是,如果你已经用 Python 写了代码,你就已经在处理对象了!Python 是一种面向对象的语言,你定义的变量如‘ABC’123 本身就是对象。它们根据自己的特征表现出一定的行为,您可以根据它们的类型访问不同的方法— 例如,某些方法/函数只能由 Python 中的字符串类型对象访问,如 capitalize()或 format()。

您也可以使用这种范式来组织您的代码,并使您的代码以一种更有趣、更灵活的方式流动。将对象与函数式编程相结合将避免产生难以维护和调试的“意大利面条式代码”软件。通过学习面向对象编程,我也能够熟悉继承或多态的概念。

当然,OOP 不是一个万能/终极的解决方案——它应该在你的代码中有标准和小心地应用,因为在代码中到处扔对象也会导致一些混乱和过度工程化。

单元和集成测试

当我职业生涯开始时在商业智能领域工作时,我已经接触过“概念性”ETL(提取-转换-加载)测试——单元/集成测试有些类似。

当我开始使用代码交付模型时,我偶然发现的最重要的概念之一是编写好的测试,这些测试可以在部署模型时捕捉错误并控制环境。在数据世界中,这对于理解更改代码如何影响模型结果尤其重要。

给你的模型增加了一个新的变量?用该特性的预期行为和一些原型例子编写一个测试。测试对于捕捉早期错误和测试您可能为模型构建的数据管道周围的东西非常重要——默认情况下,特征工程是一个容易出错的过程。

构建好的测试将避免部署有问题的新版本,或者从根本上改变模型的基本原理。结合 CI/CD 管道(接下来将详细介绍),测试是非常强大的工具,有助于创建更具可伸缩性和更健壮的模型。

单元测试孤立地检查特定的功能或特性——通常他们一次只测试一个功能。集成测试将您的软件作为一个整体进行评估,测试整个代码的逻辑和流程。

使用 Python 的一个常见测试框架是 pytest ,而在 R 中通常使用 testthat

版本控制系统

这个概念可能已经是大多数数据科学家日常工作的一部分,并被业内每个人广泛采用。今天,大多数(如果不是全部)数据科学家已经使用了 VCS 系统,如 Git 或 Azure DevOps。如果没有一个 VCS 来编写健壮的模型,我们绝对无法生存。这些工具不仅对于部署和版本跟踪极其重要,对于团队协作也是必不可少的。如果没有 VCS,数据科学家可能会在开发代码时相互碰撞,改写和破坏彼此的工作。

对于数据科学项目,VCS 非常棒,因为人们可以并行执行实验,构建不同的功能或测试不同的模型。一次只有一个人在一个脚本中工作的日子已经一去不复返了——这会降低整个团队的效率和生产力。

Git 是世界上最著名的版本控制系统。这是一个简单而有效的框架,用于比较代码和跟踪变更,支持并行工作、特性回滚和代码审查。大多数(如果不是全部的话)今天的开源项目都是使用某种类型的 VCS 系统开发的,这显示了 VCS 在过去十年中是如何征服世界的。

CI/CD

CI/CD for Continuous Improvement/Continuous Development 是一种开发框架/理念,它使您能够快速安全地交付软件。

CI/CD 在管道中有它最著名的工具,一段可运行的代码,检查并确保您的部署的有效性。例如,在 CI/CD 管道中,您可以通过在每次有人将代码推入 VCS 时运行自动化测试来检查开发人员是否没有将错误引入到代码中。

正如您在最后一句中可能已经注意到的,CI/CD 管道是我们上面讨论的概念的完美结合。在 CI/CD 管道中,您可以控制代码错误、代码林挺,甚至构建生产部署——所有这些都由代码控制,无需开发人员付出任何努力。

构建良好的 CI/CD 管道是一门艺术。通过掌握它,你一定会避免开发过程中的失误,并避免将错误版本交付给生产。

感谢你花时间阅读这篇文章!在过去的几年里,我学到了很多关于开发最佳实践的知识,并想分享我成为一名更好的数据科学家的经历和旅程。将这些概念添加到您的工具箱中可能会向您的团队展示您是一个关心技术债务的人,并且希望在将来避免充满痛苦和悲伤的调试会议。

我在 Udemy 上开设了一门关于学习 数据科学的课程——这门课程是为初学者设计的,包含 50 多个练习,我希望您能在身边!****

**https://ivopbernardo.medium.com/membership **

在每小时报告中应对夏令时

原文:https://towardsdatascience.com/coping-with-daylight-saving-time-in-hourly-reporting-b753578927a6

当你需要每小时报告一次时,夏令时开关可能是一个真正的问题。我是这样解决的。

照片由乔恩·泰森Unsplash 上拍摄

介绍

通常,我们以天或更低的粒度创建报告。

一段时间以前,我为一个客户工作,该客户为他们的生产线创建能耗报告,这些生产线全天候运行。

他们的数据汇总到 15 分钟。

在这种情况下,切换到夏令时再切换回太阳时会导致报告中出现问题。

对于本文,我创建了一个基于日期和时间的表,时间序列为每分钟一行,每行的值为 1。

这样,我可以直接展示开关的效果。

问题

当我将该表加载到 Power BI 中时,当我查看每月级别的数据时,我得到以下报告:

图 1 —问题(作者提供的图)

当我查看其中一个月的每日级别时,在没有开关的情况下,在小时级别的数据上添加工具提示后,我得到以下报告:

图 2——每日*均每月的问题(作者提供的数字)

现在,我们来看一个月的每日数据,其中包含一个开关:

图 3 —带开关的一天的数据(由作者提供)

如你所见,我们的数据在秋季有一个峰值。在春天,当我们从太阳时切换到夏令时时,我们会在数据中得到一个间隙。

问题是,在现实中,数据没有间隙和尖峰,但我们看到它们是因为开关。

这可能会使报告的消费者感到困惑。

Dex Ezekiel 在 Unsplash 上拍摄的照片

解决办法

一个可能的解决方案的第一步是用开关识别日子。

为此,当我在 Azure SQL 数据库中加载我的日期表时,我使用了以下 T-SQL 代码:

SET @TimeZone_Offset =
  DATEDIFF(hh,
    DATEADD(hh, 4, @DT),
    CONVERT(datetime2,
      SWITCHOFFSET(DATEADD(hh, 4, @DT),
             DATEPART(TZOFFSET,
                DATEADD(hh, 4, @DT
                AT TIME ZONE ‘Central European Standard Time’)
                )
            )
       );

变量@DT 包含一个日期。

然后,我向 DATEDIFF()的第一个参数的日期添加四个小时。

下一步是使用 SWITCHOFFSET()作为 DATEDIFF()的第二个参数切换到 UTC 时区,并获得本地时区和 UTC 之间的差异。在调用 DATEPART(TZOFFSET,…)函数时,需要设置您的时区。

将数据写入数据表后,我使用下面的代码用时间开关在每一行上设置一个特殊值:

WITH [Result]
AS
(SELECT [DateKey]
    ,CASE [TimeZone_Offset] — LAG([TimeZone_Offset], 1, 1)
                                   OVER(ORDER BY [DateKey])
       WHEN 1 THEN 2.5
       WHEN -1 THEN 1.5
       ELSE [TimeZone_Offset]
     END AS [TimeZone_Offset_Chg]
   FROM [dbo].[Date])
UPDATE [dbo].[Date]
    SET [TimeZone_Offset] = [R].[TimeZone_Offset_Chg]
  FROM [dbo].[Date] AS [D]
     INNER JOIN [Result] AS [R]
        ON [R].[DateKey] = [D].[DateKey];

我使用 LAG()函数将实际行与前一行进行比较,以查看值是否发生了变化。

然后,当事情发生变化时,我设置特定的值(秋天为 1.5,春天为 2.5)。

这样,我就可以找到在太阳时和夏令时之间转换的日子。

接下来是我想如何处理这些信息。

例如,我想在我的报告中显示那天是否发生了切换。

为了实现这个目标,我创造了一种新的方法来编辑动态评论:

Comment =
IF(HASONEVALUE(DayLight_SavingTime_Demo[TimeZone_Offset])
     ,”Normal OP”
     ,”Switch of Daylight saving time happened”
   )

当某一天发生切换时,HASONEVALUE()为列[TimeZone_Offset]返回 false。

为了实现这一点,我设置了我的演示数据集来在正确的时间切换 TimeZone_Offset:

图 4 —带开关的数据(作者提供的图)

因此,当我用开关检查一天的列[TimeZone_Offset]时,我得到了不止一个值。所以,HASONEVALUE()返回 FALSE。

在 Power BI 中,结果如下所示:

图 5 —带开关和动态标题的一天(作者提供的图片)

在典型的一天,我显示文本“正常 OP”:

图 6 —没有开关的日子和动态标题(作者提供的图片)

这个小小的添加让消费者知道发生了什么,并正确理解数据。

结论

虽然这是一个相当奇特的问题,但在处理这个问题时,我学到了很多关于使用时区的知识。

在这种情况下,你可能会找到另一种方式来展示你的结果。

例如,我的客户正在考虑在秋天转换时*滑一天中的值。我还不知道他将如何处理春季数据的缺口。

无论如何,我的方法让你敞开心扉,说出你想如何应对这种情况。它只为您提供了完成这项工作的工具集。

Yianni Mathioudakis 在 Unsplash 上拍摄的照片

这取决于你和你的用户来制定细节以应对时间的转换。

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

企业需求和人工智能的未来,第二部分

原文:https://towardsdatascience.com/corporate-imperatives-and-the-future-of-ai-part-ii-fc086d25060a

美国公司法以及科技公司和强化学习代理的危险工具推理

Unsplash 上由 Cedrik Wesche 拍摄的照片

过去几年,大型数字*台以及人工智能和数据科学道德领域的发展和扩张取得了快速增长。数字*台由世界上一些最大的科技公司拥有,这些公司统称为大科技 : 字母表 ( 谷歌)亚马逊苹果Meta(脸书)和微软。

通过数字*台,大技术越来越多地调节和影响我们购买的产品、使用的服务和消费的娱乐。这些上市公司将他们的数字*台和数据共享基础设施联网,以创建规模、社会影响力和经济价值前所未有的全球*台生态系统。对于那些对数字*台如何利用基于行为主义心理学强化学习的个性化原则来修改人类用户的“环境”感到好奇的读者,请参见公司规则系列的第一部分。

因为上市公司依靠公共金融市场为未来项目获取资本,他们最终必须对全球股东和债券持有人——他们所谓的 剩余索取者的财富寻求需求做出回应。由此产生的法律考虑约束了企业的推理和行为,并对我们从道德上评估其行为的方式产生了影响,特别是那些运营数字*台的企业,如谷歌、亚马逊和脸书。我特别担心工具理性的公司部署工具理性的 RL 代理,而几乎没有监督。

请注意,许多关于法律约束和工具理性的问题也适用于私募股权风险投资,它们越来越多地被用于推动新技术公司的早期增长。

企业社会责任与人工智能

大型科技公司在推进人工智能研究、发布政治新闻、教育公民和传播公共卫生信息方面发挥着越来越大的作用。后一类职能传统上由具有正式道德和政治问责制度的公共机构和政府履行。

虽然记者们经常谴责大型科技公司的垄断行为,但我想关注一个略有不同的问题。随着公司拥有的*台日益成为各行各业的数字插孔,人们不禁要问:个人和社会真的从这种安排中受益了吗?鉴于它们在现代生活中的新影响力,企业在我们全球化的社会中应该扮演什么样的角色?

在一份关于企业社会责任的有影响力的系列论文中,商业伦理学家吉多·帕拉佐安德烈亚斯·舍雷尔认为,全球化需要为企业的巨大社会作用找到新的道德理由。这些道德理由必须超越增加便利或生产效率的实用理由。此外,鉴于公司在全球范围内运作,它们必须吸引不同民族国家和文化的人。也就是说,他们还必须考虑到 价值多元化 : 事实上,来自不同文化的通情达理的人可能对善与对有着相互冲突的观念。

帕拉佐和舍雷尔建议在公共领域进行参与性的民主讨论,以此来阐明证明全球公司新发现的社会角色和责任的道德理由。一旦这样的民主机制到位,像谷歌和脸书这样的公司就可以真正谈论做“有益于社会的数据科学”

企业人工智能嵌入在更大的技术、经济、法律和道德体系中。理性的辩护可以在每一个层面上给出,但最终会在一个基于社会群体的“生活形式”的特定道德愿景中出现来源:作者。

企业自有数字*台的社会嵌入性

企业开发和拥有的数字*台和人工智能技术位于一套复杂且相互强化的嵌套社会结构中。

股东与公司的关系在公司法和合同法中有明文规定,并在法院判决中得到执行,而法院判决本身是从普通法的先例演变而来的。当然,法官是由政治领导人任命的,或者在某些情况下,由投票公众直接选举产生。最后,伦理考虑证明谁投票、如何投票以及在什么年龄投票是合理的。伦理考量为政治进程的结果提供了规范的合法性。我们一致认为腊肠狗不应该投票,它们的政治观点,无论多么可爱,在道德上都是无关紧要的。至少目前是这样。

上图说明了企业所有的数字*台的嵌套性质,在不同层面上提出了新的合法性问题。尽管我们经常认为公司结构是理所当然的,但在现实中,正如新自由主义理论所强调的,它需要一个复杂而强大的法律和政治体系才能繁荣。例如,在经济制度层面,资本主义指的是私人拥有的生产资料。在资本主义体系中,公司需要特定的制度和理念才能存在。私有财产的概念是必要的。合同必须由法院签订和执行。公司章程必须由立法机关起草,等等。

资本主义作为一种经济体系,本身依赖于更大的政治背景和基础理论。政治理论在政治规则和程序中得以实现,这些规则和程序赋予行使政治权力的规范性合法性,即民主选举总统。反过来,这些民主程序又被*等、公正和透明的道德价值观所证明,即“一人一票”等原则法治 所证明,这使得公民只对那些公开颁布的法律负责。

每个层次都有其自身的正当性,在不同层次上可能会有冲突,尤其是在不稳定的社会系统中。这些辩解的底线在哪里?我追随维特根斯坦,相信伦理体系——实际上是正式体系本身——最终是基于任意的“生活形式”,而不是终极真理或宏大叙事。

公司的性质是什么?一些商业伦理学家将公司视为经济主体,其形式结构与机器人同构。埃里克·克鲁尔在 Unsplash 上的照片

数字*台:盈利组织和自动化决策

数字*台将利润驱动型组织的概念与基于人工智能/人工智能的自动化相结合。对于自主人工智能系统,我指的是数字*台上的系统,旨在使用强化学习 (RL)的形式和算法来生成个性化推荐。

尽管自动化决策似乎是实现更有效的社会资源分配的自然方式,但数字*台的概念在伦理上令人担忧。为什么?因为它结合了两件具有粗略道德记录的事情:自主人工智能系统和一个被称为公司的虚拟法律实体。虽然企业确实擅长高效生产产品和服务,但它们也有这样的历史:

奇怪的是,RL-agents 和公司都遭受道德缺陷,因为他们狭隘的工具理性支配着他们的行为。因此,我们可以预期由公司代理部署的 RL 代理也会出现类似的伦理问题。更糟糕的是,通过数字*台将这两个工具理性代理结合起来可能比单独使用任何一个都更糟糕。

公司的法律基础和宗旨

为了更好地理解为什么大型科技公司的行为如此有争议(导致了像欧盟的 GDPR 这样的法律),在头脑中有一个公司到底是什么的图片是有帮助的。这是默认的 MBA 观点。

公司法人是一种法律结构,旨在解决裁定各种股东的独立利益的问题。当自然人团体同意“合并”并集中资源以实现共同目标时,它们就形成了。因此,经常听到正统经济学家把现代公司说成是分布在空间和时间上的理性利己主义者之间的契约关系。

美国公司法从经济角度出发,认为公司决策是为理性自利的股东对更高市场价值的偏好服务的。股东权利旨在确保公司管理者尊重股东的“首要利益”——实现投资回报最大化。据说,公司经理对股东负有“信托责任”,要以最有利于他们财务利益的方式行事。至少在理论上,经理是受合同约束的代理人来执行委托人即股东的命令。即使是企业的慈善捐赠也必须受到限制,并支持长期财富最大化的目标。

公司作为依法组建的集体决策机构,从其合法和正式的结构中享有一定的财务利益。首先,公司的创建将个人原本不同的利益结合在一起,创造了一种纽带,培养了公司内部的信任,使得内部交易比涉及外部市场的交易成本更低。此外,公司的成立使得几乎无限数量的不同股东的资本被集中起来,用于一个单一的目标。例如,法人股东的有限责任意味着个人只能失去他们在合资企业中的个人投资。然而,有限责任也可能创造一种道德风险的场景,投资者承担了比他们应该承担的更多的风险,因为他们只对一些负面影响负责。

作为正式组织结构的社会本体论和企业形而上学

这是对公司的另一种看法。在一篇很有影响力的文章中,哲学家约翰·拉德认为公司是正式的组织,它们是本质上是追求目标的机器,其功能部件由个体人类演员组成。组织理论家和人工智能先驱希尔伯特·西蒙同意这一观点,认为正式组织本质上是“决策结构”

形而上学地说,公司不同于其他集体,如家庭。虽然个体数据科学家或股东可能在集体中行动,但行动归于组织,而不是组成组织的个人。公司的雇员可以被解雇或重新雇用,而不改变公司的身份。拿这个和一个家庭比。个体成员的身份是不可替代的——当你把你的祖母和住在你楼上的疯老太太换了位置时,你的家庭就不再是你的家庭了。

公司是看不见的,但在因果关系有效的意义上是真实的。这听起来可能很奇怪,但这是人类独特的能力的结果,人类能够对规范性法律做出反应,就好像它们是物理法律一样。举个例子,你可能会为了捍卫你的荣誉而与人打架。如果荣誉不是你头脑中的一个无形概念,却能因果解释你的行为,那它是什么?

考虑一下这个。你可以踢一栋大楼或公司总部的一张桌子,但无论你如何努力,你都踢不到一家公司。这是因为当某些具有法律和政治合法性的机构宣布它们存在于我们的社会现实中时,它们就存在于我们的集体意识中。就像在 Python 脚本中定义一个函数一样,我们通过声明它是这样来实现它,并通过它在解决我们的问题时的因果功效来判断我们函数的“正确性”。

哲学家约翰·塞尔称这些规范性行为为“声明性言语行为”,其合法性基于“地位功能”,我们作为一个社会同意将其归因于特定的制度。例如,当牧师在适当的场合说“我现在宣布你们成为夫妻”,你们就这样结婚了。他的言语行为立刻创造了它所代表的现实。

公司是经济主体,其任务是优化法律预先规定的目标函数。他们不能思考目的,只能思考实现目的的手段。这种缺乏决定目的的自由意味着他们没有能力承担道德责任。布鲁诺·格雷罗在 Unsplash 上拍摄的照片

弗兰肯斯坦、工具理性和道德责任

公司的存在是为了实现特定的、法律上可强制执行的财富最大化目标,通常会在公司章程中详细说明。然而,作为纯粹虚构的法律实体,公司受到其组织结构和美国公司法的限制,以工具理性的方式行事。拉德认为,这种正式的组织结构展示了一种语言游戏https://en.wikipedia.org/wiki/Language_game,它定义了一个正式组织意味着什么。根据定义,不符合手段-目的的工具理性不能进入决策过程。**

什么是工具理性或理性?工具理性是选择最有利于合法强加的利润最大化目标的技术手段。正如希尔伯特·西蒙解释的那样,

【工具理性】不能告诉我们向何处去;充其量它能告诉我们如何到达那里。它是一把出租的枪,可以用来为我们的任何目标服务,无论是好的还是坏的。

作为一个纯粹工具理性的代理人有什么道德含义?受其正式组织结构的限制,公司不能被认为是道德代理人。根据康德的观点,拉德声称公司不能行使道德自由,因为他们只能推理手段,而不能推理最终目的。因此,他们缺乏承担道德责任的能力。虽然我们可能会在正常的对话中指责或赞扬企业的行为,好像它们本可以采取不同的行动,但我们犯了一个范畴错误。

因此,公司就像一个不道德的弗兰肯斯坦,存在于人类道德共同体的界限之外,如果我们希望保持安全,就必须对其行为进行正式或法律约束。

这听起来像 RL 中的 值对齐 问题吗?

公司和 RL-agent 以相似的方式组织。两者都依赖于工具推理来最大化由法律或*台数据科学家定义的奖励。产生的行为策略分别是业务环境和*台环境的“解决方案”。来源:维基百科

工具理性 RL 和经济主体的病态行为

从抽象的意义上来说,公司是正式的代理,它们通过传感器感知环境的状态(收集输入数据)并且通过致动器对其做出动作(做出决定,执行操作)并且在这样做的过程中修改(计算)环境——我们的社会。数字*台为企业提供了在数字环境中实际执行感知和行动的技术基础设施。

令人担忧的是,RL-agent 和企业都受到工具推理的限制,因为它们的基础是预先选择的目标函数的数值优化。按照美国公司法的要求,公司的预定目标是利润最大化或股东财富最大化。数字*台上的 RL-agent 同样以最大化折扣累积奖励为目标。

正如 Nick Bostrom 等作者所指出的,工具理性会导致 RL-agent 中自相矛盾的非理性行为。批判理论家 马克斯·霍克海默把工具理性描述为一种

过于频繁地削尖剃刀刀片会变得太薄,最终甚至不足以完成它所局限的纯粹形式主义的任务。

工具理性也可以解释企业的贪婪。最*泄露的潘多拉文件揭示了巨富们如何利用空壳公司和信托基金在世界各地的避税天堂隐藏巨额资金,以隐藏他们的身份。利润最大化的工具性目标诱使许多大公司采取了在道德上与我们人类公民相抵触的行为政策。但是法律迫使他们隐喻的手。如果股东认为他们在履行财富最大化的职责时玩忽职守,他们有起诉董事会的合法权利。这是工具理性和胡萝卜加大棒的行为主义心理学。

正如一些美国公民对主要科技公司不缴纳公*份额的税收感到愤怒一样,数据和人工智能伦理学家担心基于行为参与度的工具化优化奖励功能的数字“环境”影响——包括其对政治系统和心理健康的潜在离线“泄漏”。经济学家将这些效应称为 外部性,但它们是被称为企业的经济主体的代谢废物。**

但也许我们只是把期望定得太高了。也许问题不在于公司结构本身,而在于我们把公司想象成有道德情感的人的方式。

不要被品牌个性所迷惑。与部署在数字*台上的 RL 代理类似,企业行为是在追求最大化预定义目标函数的过程中进行狭义战略工具推理的结果。照片由 Alexey MakUnsplash 上拍摄

企业品牌、个性、责备和道歉

现代企业在品牌和营销活动上投入了巨大的资源。为什么?这样做为这些经济主体创造了人格代理,并培养了与消费者、雇主和监管者的情感纽带。想想脸书的口号“让世界更紧密地联系在一起”,或者麦当劳的“我爱它”。“更讽刺的是,人们可能会称之为经济主体为了更好地实现其目标而进行的一种战略操纵。

不同的公司开发不同的“文化”、“政策”和“业务流程”以适应他们的环境。更成功的人通过反复试验来学习如何根据商业环境采取更有效的行动。他们行为策略的有效性是相对于一个目标函数来定义的。就公司而言,法律定义了目标函数。旁注:特拉华州的公司法对定义公司的宗旨很有影响。小小的特拉华州拥有超过 100 万个商业实体和 66%的财富 500 强企业。相比之下,对于数字*台,数据科学家指定奖励函数,使其与企业目标函数相关联。成功的 RL-agent 和企业学习独特的“个性”或行为策略,以帮助他们“控制”他们的特定环境,并积累最大的回报/利润。

奇怪的是,美国法律倾向于将宪法的某些方面解读为适用于公司和自然人。 Thom Hartmann 解释说,美国最高法院支持第 14 修正案适用于公司和自然人。公司现在可以在美国宪法中主张自然人的许多权利,比如言论自由。因此,尽管公司既不是道德代理人/病人,也不是有意识的实体(尽管是由个体有意识的人聚集而成),我们还是给予了它们许多公民权利。

公司品牌进一步鼓励将法人与自然人错误类比。如果公司像自然人一样,那么责备或表扬他们似乎是很自然的——采取一种有意的立场,并赋予他们各种有意的状态,如信念、需求和欲望,以理解他们的行为。但在这样做的时候,如果我们不仔细思考,我们很容易被操纵。

脸书为其人工智能如何将黑人照片标记为“灵长类动物”而“道歉”为例脸书已经学会散发道歉的行为外壳,以实现恢复信任和社会和谐的战略目标,这是一种与大量未来利润相关的商业环境状态。这些外部运动只是人类为了追求更大的投资回报而进行的目标导向的试错的可理解的副作用。

因此,脸书公司的道歉是表里不一的。脸书本身从未经历过恐惧和痛苦的有意状态,这种状态定义了道歉的经历,并赋予其道德价值(我们倾向于惩罚那些较少宣布自己有罪的人)。没有什么https://en.wikipedia.org/wiki/What_Is_It_Like_to_Be_a_Bat%3F让脸书体验遗憾、内疚或羞耻,只有真诚道歉的数据科学家、经理和董事会成员的经历。

并非每个公司(总是)都是科学怪人

不要误解我。企业偶尔会以道德上值得称赞的方式行事,即使我们在称赞它们时犯了一个类别错误。例如,鸿海TSMC 两家世界上最大的电子/芯片制造商捐赠了 1000 万剂新冠肺炎疫苗来帮助台湾的疫苗接种工作。**

但是,即使是理性利己的经济代理人也会表现出看起来的利他动机行为,如果这是他们长期生存所必需的。仔细观察,这种利他行为是因为它的长期效用而被选择的,而不是出于任何内在的内疚、悔恨或仁慈。

公司无疑提高了全球数百万人的物质生活水*,但这些利益的分配并不均衡。在英国非殖民化的余波中,避税天堂和离岸金融中心的爆炸式增长也于事无补。尽管取得了一些进展,但政治理论家认为,提高一些人的生活水*并不足以自动证明公司进入以前由国家行为者关注的生活领域是合理的。与现代全球公司不同,国家可以指出其社会权力背后的实质性道德和政治理由。

对于大型科技公司数字*台的社会影响力,有什么同等的道德理由吗?

浓缩咖啡中味道与提取率的关系

原文:https://towardsdatascience.com/correlating-taste-to-extraction-yield-in-espresso-75f4ecddd809

咖啡数据科学

检查多年的拍摄数据

当我发布与浓缩咖啡相关的结果时,我经常会得到类似的批评:你的口味是主观的(因此只是一种观点),提取率(咖啡最可量化的指标)与口味无关;因此你什么也没做。

我想用数据来解决这个问题,这些年来我已经收集了不少数据。经过 4 年的数据收集,我有 3000 杯浓缩咖啡的数据,如果萃取率和味道之间存在相关性,我应该可以看到。

我将从数据清理开始,然后讨论我是如何基于 based 对数据进行规范化的。我有跨多种机器、烘烤和技术的数据。

绩效指标

我使用两组指标来评估技术之间的差异:最终得分和咖啡萃取。

最终得分 是记分卡 7 个指标(尖锐、浓郁、糖浆、甜味、酸味、苦味和回味)的*均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水*。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。

用折射仪测量总溶解固体量(TDS),这个数字结合咖啡的输出重量和输入重量用于确定提取到杯中的咖啡的百分比,称为提取率(EY)** 。**

【IR】强度半径定义为 TDS vs EY 控制图上原点的半径,所以 IR = sqrt( TDS + EY)。这一指标有助于标准化产量或酿造比的击球性能。****

数据清理

所有图片由作者提供

我把所有的数据都整理成一张简化的表格。目的是为了简单,所以我没有保留所有的行。我从 3000 多张照片开始。

首先,我删除了所有没有提取产量信息或没有味道评分的镜头。然后,我去除了少于 10 次的烘烤以及一些其他指标(见下表),剩下 51 次烘烤中的 934 次。

数据分析

我们可以绘制原始数据,非标准化,有一个总的趋势是随着 EY 增加味觉评分。

对于每一次烘焙,我都使用 Z 归一化法对 EY 和味道进行归一化处理:

然后,我使用所有分数的*均值和标准差将这些数字转换回它们的常规域。

在高层次上,我做了一个关联。对于大多数指标来说,它们似乎与味道的相关性在 50%左右。100%表示它们是相同的,0%表示它们不相关,而-100%表示反向相关。

我们可以将所有的标准化值绘制成每次烘烤的散点图和柱状图。

********

TDS 似乎与最佳拟合的较小 R 值更相关。

********

我特别喜欢强度半径(IR ),因为它结合了 TDS 和 EY,可以标准化输出产量。

********

大多数烘焙的相关性高于 50%。我们还可以绘制出 TDS 相关性和 EY 相关性与味觉的关系。一些烘焙真的很低,甚至是负的。

故障分析

其中六种烘焙食物与味道呈负相关,当我单独观察每一种时,它们似乎与趋势相反。除了一些看起来很好的解释,我在这些数据中看不到任何东西。

这六次烘焙中有五次发生在疫情之前,所以有可能与当时的咖啡烘焙或某种浓缩咖啡工艺有关。我没有删除它们,因为我认为它们是故事中有趣的一部分。不是所有的烘焙在萃取率和味道之间都有很好的相关性,但是大部分都有。

对于 2019 年的烘烤,我一直在做大量的滤纸实验,所以变量有点混淆。

总的来说,我发现了我的口味和提取率之间的相关性。一些烘焙的相关性比其他的更高。每个人的经历都是不一样的,但公开的关于这个话题的数据大多是跨越几个镜头的小样本,而不是更大的探索。这就是为什么更大规模的数据是重要的。

与此同时,EY 在味道方面波动很大,因为味道可能会很嘈杂,尤其是在多次烘焙、年份和技术上。噪音中肯定有可分离的信号,我希望其他人能收集类似的数据,以帮助更广泛地将提取率作为咖啡领域的有用工具。

如果你愿意,可以在推特、 YouTubeInstagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以关注我在订阅

我的进一步阅读:

我未来的书

我的链接

浓缩咖啡系列文章

工作和学校故事集

相关性不是因果关系…或者是吗?

原文:https://towardsdatascience.com/correlation-is-not-causation-or-is-it-487d842dff23

当谈到相关性时,你如何超越挥臂

任思谚Unsplash 上拍照

相关性:分析的瓶颈

“相关性不是因果关系”是你在分析学中经常听到的一句话(从现在起,我将把它简称为 CINC,我选择听它为“扭结”)。在我的职业生涯中,我多次看到业务分析师或数据科学家展示数据散点图,显示两个变量 A 和 B 之间的相关性,并发出例行警告。不幸的是,在 90%的情况下,他们会继续做下面两件事情中的一件:

  • 他们继续说,就好像他们确实已经证明了变量 A 导致变量 b。例如,“我们可以看到,收到的营销电子邮件的数量与客户的终身价值相关。当然,相关性不是因果关系。话虽如此,现在让我们来谈谈如何加大营销力度,提高客户的 LTV。在这种情况下,CINC 只不过是一个几乎不加掩饰的免责声明,保护分析师的屁股,以防你愚蠢地相信他们的结论。
  • 或者,他们说除非你进行随机实验,否则你不能得出任何进一步的结论。这种方法在受过统计学训练的分析师中更常见,它的优势是在智力上更诚实。然而,在实践中,商业伙伴往往只是点头附和,一旦发言者离开房间,他们就根据变量 A 制定计划,导致变量 b。

然而,这种令人遗憾的状况并不一定是常态。每当我们观察数据中的相关性时,实际上变量 A 之外的有限数量的可能情况导致了变量 B:

  1. 观察到的相关性并不反映感兴趣人群中的真实相关性,
  2. 变量 B 导致变量 A,
  3. 变量 A 和变量 B 有共同的原因,
  4. 有一个更复杂的因果结构在起作用。

1.没有真正的相关性

最简单的情况是,在感兴趣的总体中实际上没有任何相关性。这有两种可能发生的方式:噪音(又名。采样变化)和偏差。

噪音。首先,如果你的样本“太小”,或者你连续抽取了太多样本(又名。钓鱼探险),观察到的相关性可能只是一个随机的侥幸。这是一个真正的问题,尤其是如果你依赖 p 值作为重要性的衡量标准,而不是通过置信区间来确定经济重要性,但我不会纠缠于此:我觉得大多数人都对那个陷阱有很好的把握,在大多数商业情况下,样本不会那么小。如果您有一百万行,那么在您的潜在问题列表中,抽样变化应该非常低。如果你的样本较小,就使用更稳健的指标,比如中值而不是*均值。人们经常低估中位数的稳健性,即使样本非常小(数学在附录中)。

偏见。当您的样本不能很好地代表您感兴趣的人群时,就会出现偏差。例如,“去年拥有活动帐户的所有客户”通常是“明年拥有活动帐户的所有客户”的合理替代。另一方面,“去年所有拥有活跃账户的客户都提供了电子邮件地址”则不是。偏倚是一个比噪声更隐蔽的问题,因为即使是大样本也可能成为它的受害者,正如最*一项关于 COVID 的研究所示[1]。

避免偏见,或者至少认识到它,并不复杂。简单地尽可能精确地写下你的样本的定义和你感兴趣的人群的定义。如果你的样本真的是从你的人口中随机抽取的,你就可以开始了。在任何其他情况下,可能会有偏见,例如,如果你在你的人群中随机接触一些人,但你的样本只包括那些回答或提供完整答案的人。试着找出你感兴趣的人群中的子类别,这些子类别可能在你的样本中被遗漏或代表不足。推而广之,如果你的人群中有残疾、没有互联网连接的贫穷老年妇女,你能充分接触到她们吗?

如果你在想“但那只是我人口中的极小一部分!”,我请你再想一想。子类别可能会在你的人口中占很大份额,即使每个子类别都很小。仅从你个人的角度来看,它们也可能显得很小。我目前住在西非,最*很难更新一部 iPhone:它需要 1)下载数千兆字节的数据,2)通过 WiFi(另一部手机 hotspotting 无法工作),3)在充电时。但发展中国家智能手机的典型拥有者可能在家里没有 WiFi(他们的智能手机是他们唯一的互联网接入),商店里的 WiFi 带宽通常有限,假设他们甚至允许你使用电插头。如果你住在美国西海岸,这可能是一个“边缘案例”,但它可能包含数亿甚至数十亿智能手机用户!

2.反向因果关系(B 导致 A)

下一种可能性是变量 A 和 B 之间的相关性可能源于变量 B 导致变量 A,而不是相反。例如,收到的营销电子邮件数量和客户终身价值之间的相关性可能是由于营销通过电子邮件将目标锁定在高 LTV 客户。一旦你考虑到这种可能性,它在你的数据中是如何发生的就很明显了。

3.混杂因素(A 和 B 有共同的原因)

最后一种“简单”的情况是当 A 和 B 有共同的原因时。例如,营销预算可能在美国的州一级分配,或者在国际上在国家一级分配。然后加州的客户(分别是美国的)可能比田纳西州的客户拥有更高的 LTV 和收到更多的营销电子邮件。,在尼日利亚)。同样,一旦您考虑到这种可能性,它在您的数据中是如何发生的就很明显了。

4.还有什么(更复杂的因果结构)

前三种情况可能代表了你在实践中会遇到的 90%的情况,但是从技术上讲,它们并没有涵盖所有的可能性。为了完整起见,我将简要地谈一谈还有什么。

一类更复杂的因果结构是当你显式或隐式地控制一个你不应该控制的变量。例如,一名军医发现,战场上止血带的使用与存活率呈负相关;问题是他的分析是基于到达野战医院的士兵。但是止血带的主要好处是,它可以让受重伤的士兵存活到他们到达医院,而不是流血过多。这意味着总体上有更多的士兵存活下来,但只有很少一部分被送到医院,因为我们增加了更多的严重病例。顺便提一下,这个例子也可以解释为数据收集中的偏差(即,观察到的负相关不代表感兴趣的人群),这表明数据收集和数据分析并不像人们通常认为的那样分离。

最后,我们有一些情况似乎是大自然设计的,让科学家们困惑不解。例如,人们已经知道自闭症与简单的肠道微生物群(即肠道中细菌种群多样性较低)有关。这是否意味着微生物组导致自闭症?最*的一项研究表明“不,恰恰相反”:自闭症儿童经常限制饮食,因为感官体验会淹没他们,有限的食物种类导致有限的微生物种类。但是接下来,如何解释粪便移植改善了自闭症儿童的行为?一个新兴的假设是,“粪便移植通过缓解不*衡的微生物群直接带来的不适症状,改善了自闭症儿童的行为,但不影响该疾病的神经基础”[3]。相应的因果图是:

作者图片

最终,科学通过开发越来越精确和完整的模型来解释手头的所有事实而进步。这同样适用于商业:实现对客户(或员工)行为的深入理解需要建立准确的因果图,正如我在我的书 用 R 和 Python【4】进行行为数据分析中解释的那样。

总结和结论

每当您在数据中观察变量 A 和 B 之间的相关性时,除了 A 导致 B 之外,正好有 4 种可能性:

  1. 由于采样噪声或偏差,观察到的相关性不能反映感兴趣人群中的真实相关性;
  2. 变量 B 引起变量 A;
  3. 变量 A 和变量 B 有一个共同的原因;
  4. 有一个更复杂的因果结构在起作用。

这意味着,你不必把自己局限于“相关不是因果”。通过仔细思考其他可能性并排除不合理的可能性,你可以得出结论,“这种相关性可能反映了因果关系,一旦我们确定了我们想要采取的行动,就可以通过运行 A/B 测试来确认这一点”。如果事情变得太复杂,您可以构建因果图来确定发生了什么。

参考

[1]https://news . Harvard . edu/gazette/story/2021/12/vaccine-surveys-fell-victim-to-big-data-paradox-Harvard-researchers-say/

[2]这个例子出自朱迪亚·珀尔(Judea Pearl)和达纳·麦肯齐(Dana MacKenzie), 《为什么:因果的新科学 》一书。

[3]《经济学家》,“肠道菌群失调如何与自闭症联系在一起”

[4] Florent Buisson, 用 R 和 Python 进行行为数据分析:真实业务结果的客户驱动数据

你也可以看看我以前在 Medium 上的帖子:

附录:中位数估计量的稳健性

请记住,根据定义,人口的中位数是这样的,一半人口的值低于它,一半人口的值高于它。无论数据分布的形状、峰值数量等如何,这一点都成立。

这意味着,如果从总体中随机抽取两个值 x 和 y,有 4 种可能性:

  • 都低于人口中位数,概率 0.5 * 0.5 = 0.25;
  • 他们都高于人口中位数,概率也是 0.25;
  • 一个低于人口中位数,一个高于,概率 0.5。

更一般地说,如果你有 N 个值:

  • 它们都低于 0.5^N 概率的中间值。
  • 它们都高于 0.5^N 概率的中位数。
  • 中位数位于概率为 1–2(0.5^n).的 n 个值的最小值和最大值之间*

这意味着,即使只有 5 个值的样本,也有 94%的机会将总体中值归入您的样本。有 10 个值时,概率达到 99.8%。现在,我不能保证你会对这个置信区间的大小感到满意,但至少你会非常清楚地意识到,在当前的情况下,抽样变异有多重要。

相关矩阵,非神秘化

原文:https://towardsdatascience.com/correlation-matrix-demystified-3ae3405c86c1

关联矩阵:什么是关联矩阵,它是如何构建的,它有什么用途

这看起来像散点图,不是吗?稍后将详细介绍。照片由rovenimages.com:

在这个关于统计指数的迷你系列(最初是根据我在 Datamasters.it 当老师的经验设计的)的上一篇文章中,我们已经研究了方差、标准差、协方差 e 相关性。在本文中,我们将重点关注上一篇文章中概述的一种数据结构,当我开始学习机器学习时,我简直惊呆了,不是因为这是一个难以理解的概念,而是因为它让我清楚地了解了数据科学和机器学习的力量。

我们在哪里停下来的?相互关系

我说的数据结构就是强大的相关矩阵。像许多其他数据科学概念一样,它是一个易于理解甚至更易于使用的代数概念。让我们快速回顾一下相关性:它是一个指数,显示两个随机变量 X 和 y 之间的线性关系。它总是一个介于-1 和 1 之间的数字,其中:

  • -1 意味着这两个变量具有逆线性关系:当 X 增加时,Y 减少
  • 0 表示 X 和 Y 之间没有线性相关性
  • 1 表示这两个变量具有线性关系:当 X 增加时,Y 也增加。

当心!相关性并不意味着因果关系。当 X 和 Y 之间的相关性接* 1 时,我们不能说 X 的变化意味着 Y 的后续变化。例如,考虑两个变量:“一年内每天售出的冰淇淋数量”和“一年内晒伤的数量”。这两个变量可能有很高的相关性,但是两个变量中一个的变化不会反映另一个。高相关性,低因果性。现在:回到相关矩阵。

相关矩阵

相关矩阵是一个*方(行数等于列数)对称(矩阵等于其转置),所有主对角元素等于 1 且半正定(其所有特征值均非负)的矩阵。虽然前 3 个属性很容易理解和可视化,但在最后一个条件上花一些时间是值得的,因为不是所有主对角线等于 1 的正方形对称矩阵都是半正定的,因此不是所有满足前 3 个必要条件的矩阵都是相关矩阵。例如,下面的矩阵:

m = [
    [1, 0.6, 0.9],
    [0.6, 1, 0.9],
    [0.9, 0.9, 1]
]

有一个负特征值。你可以用纸和笔找到它,但是当我们可以让其他人做算术的时候,为什么还要麻烦呢?我们可以用 Python 和 numpy 得到 m 的所有特征值:

m = [
    [1, 0.6, 0.9],
    [0.6, 1, 0.9],
    [0.9, 0.9, 1]
]eigenvalues = np.linalg.eig(m)
print(eigenvalues[0])Out: [ 2.60766968  0.4        -0.00766968]

np.linalg.eig 函数将一个矩阵作为输入(在所有编程语言中,它可以表示为一个列表列表、一个数组数组或一个矢量向量),并返回一个包含两个元素的元组:

  • 第一个是矩阵的特征值列表
  • 第二个是包含矩阵的归一化特征向量的列表

特征值是返回的元组中索引为[0]的元素。有一些技术可以使一个非半正定矩阵成为半正定矩阵,但是我们不会在这里讨论这个话题。如果你想进一步研究这个话题,你可以查看这个网址。

构建相关矩阵

现在让我们试着去理解一个相关矩阵是如何产生的,假设它已经有了之前写的所有属性。

让我们从一个数据集开始,也称为“随机变量集”,或者如果你喜欢一组代表单个观察值的行和列,其中每行有一定数量的列或特征

当我开始阅读这本书来研究 ML 时,第一个完整的预测模型例子(一个简单的线性回归,第二章)在一个由加州地区房屋数据组成的数据集上训练自己。你可以从这里下载。当我第一次读到什么是线性回归,当我学习探索性分析部分(相关性和相关性矩阵出现的地方)时,我的感知之门很快就打开了,正如有人所说。是的,没有麦斯卡林。我们,计算机科学家,很少需要去旅行。顺便说一下:数据集的每一行代表不同的加州区;另外,每一行都有以下特性(特性是一个很酷的名字,可以称之为“随机变量”,或者更好:变量你可以在上计算一些统计指数):

  • 经度
  • 纬度
  • 房屋年龄中位数
  • 房间总数
  • 卧室总数
  • 人口数量
  • 家庭
  • 中等收入
  • 房价中位数
  • 海洋接*度

这本书对于任何想学习机器学习的人来说都是真正的必读,尽管它不适合完全初学者,如果你有基本的数据科学背景就更好了。所有的代码都可以在这里找到,把它收藏起来。

我们可以说我们的数据集有一个n x 10维度,其中n是行数,即加利福尼亚地区的数量。

让我们为这个数据集构建相关矩阵。我们要计算相关性的变量是数据集的 10 个特征。哦,好吧,在这个数据集中,有一个特征的相关性是没有意义的:我们正在谈论的是ocean_proximity特征,一个分类变量。“分类”意味着变量的定义域是一组离散的值,而不是一组连续的数字。特别是,对于这些特性,唯一允许的值是:

{“1H OCEAN”, “INLAND”, “NEAR OCEAN”, “NEAR BAY”, “ISLAND” }

所以用这个变量计算相关性(计算两个连续随机变量之间线性关系的指标)是没有意义的。我们可以把它从相关矩阵中排除。让我们从头开始:我们的数据集由 10 个特征组成,但我们忽略了其中的一个,因此我们的相关矩阵最初将是一个空的 9x9 矩阵:

一个空的 9x9 矩阵。图片由作者提供。

现在让我们用实际的相关性填充矩阵。让我提醒您,矩阵的每个元素都有一个行索引和一个列索引,用于描述它在矩阵中的位置。我们从 0 开始对行和列进行计数:这意味着(例如)最左边的最低值的位置是8, 0(第 8 行,第 0 列)。第四行最右边的元素的位置是3, 8(第 3 行,第 8 列)。矩阵的对称性告诉我们一件更有趣的事情:位置为i, j的元素等于位置为j, i的元素(位置为3, 8的元素等于位置为8, 3的元素):为了满足这一性质,我们必须构建矩阵,使得位于某一位置的变量也位于同一列。例如,让我们从longitude特性开始,假设我们想在第 0 行使用它。对称条件要求我们必须对第 0 列使用longitude特性。然后我们对latitude做同样的操作:第 1 行,第 1 列。housing_median_age?第 3 行,第 3 列,依此类推,直到我们使用了所有的数据集特征并得到这个空矩阵:

相关矩阵的标签。图片由作者提供。

我们试着读一下这个矩阵:位置为0, 5(第 0 行,第 5 列)的元素表示经度与人口的相关性;对于对称属性,它等于位置为5, 0的元素,表示人口和经度之间的相关性。两个变量 X 和 Y 之间的相关性等于 Y 和 X 之间的相关性。对于位置为6, 7的元素,包含“家庭”和“中位数 _ 收入”之间的相关性的元素以及等于索引为7, 6的元素,median_incomehouseholds之间的相关性也是如此。

现在考虑矩阵主对角线上的一个元素,例如,位置为4, 4的元素:它将表示“总卧室数”与其自身的相关性。根据定义,变量与其自身的相关性是总是 1 。当然,所有的主对角线元素都有这个性质:一个相关矩阵的所有主对角线元素都等于 1。

Python、pandas 和 seaborn 中的相关矩阵

现在:要用实际值填充相关矩阵,我们应该计算每对变量的相关性。无聊这个证明留给读者做练习。我们可以用“熊猫”来代替:

import pandas as pdhousing = pd.read_csv('datasets/housing.csv')rounded_corr_matrix = housing.corr().round(2)print(rounded_corr_matrix[‘median_income’])

在命名的(它是as pd部分)导入指令之后,让我们使用 pandas 方法read_csv读取我们之前下载的 CSV 文件,该方法将文件的路径作为输入,让我们将读取结果存储在一个名为housing的变量中。read_csv返回的数据类型是一个DataFrame,pandas 中定义的最重要的数据类型,代表一组数据(有人说“数据集”了吗?).我们可以在一个数据帧上使用许多方法和函数,其中有corr()方法;顾名思义,我们可以用它从一个数据集中得到一个相关矩阵!我们使用方法round(2)将相关值四舍五入到第二个小数位,只是因为我们想使用可读性更好的矩阵。在下一条指令中,我们以熊猫Series的形式打印median_income和所有其他特征之间的相关值。它是一种类似于常规数组的数据结构(例如,我们可以使用数字索引来访问它的值),但是具有超能力。另外,我们可以访问一个指定第二个索引的特定值。例如:

rounded_corr_matrix['median_income']['housing_median_age']

将保持median_incomehousing_median_age之间的相关性。得心应手,对吧?我们还可以使用以下指令打印按降序排列的median_income特征的所有相关值

rounded_corr_matrix["median_income"].sort_values(ascending=False)

输出将是:

median_income         1.00
median_house_value    0.69
total_rooms           0.20
households            0.01
population            0.00
total_bedrooms       -0.01
longitude            -0.02
latitude             -0.08
housing_median_age   -0.12
Name: median_income, dtype: float64

因此,要获得整个数据集的相关矩阵,需要使用corr()方法。如果我们想改进可视化相关矩阵的方式,我们可以使用 seaborn 的heatmap函数。

import seaborn as snsheatmap = sns.heatmap(rounded_corr_matrix, annot=True)
heatmap.set_title('Correlation Heatmap', fontdict={'fontsize':12}, pad=12)

热图是一种数据可视化工具,可以将特定现象映射到色标上。在我们的例子中,较深的颜色用于映射较低的值(黑色映射相关值-1),而较高的值映射到较浅的颜色(白色映射相关值+1)。Seaborn 有一个heatmap方法,它将我们将要创建热图的二维数据结构作为第一个参数:在我们的例子中是相关矩阵。我们向名为annotheatmap函数传递另一个参数:在热图单元格中写入实际的相关值很有用,可以更精确地了解正在发生的事情。

​​

加州住房数据集的 Seaborn 热图。图片由作者提供。

正如我们所见,热图的有用性依赖于对可视化数据解释的即时性。例如,快速浏览后,很明显“总卧室数”和total_rooms (0.93,非常接*于 1),total_roomnspopulationtotal_bedroomshouseholds之间有很高的相关性。很有道理,不是吗?相比之下,我们将为latitudelongitude设置一个较低的相关值(稍等片刻,试着想象一下加利福尼亚州的形状)。对于 0 附*的值(例如median_incomepopulation),我们不能说什么。

多亏了 pandas,我们可以获取数据集特征的子集并打印相关的相关矩阵。为了获取我们的相关矩阵特征的子集,我们所要做的就是创建一个带有特征 名称的列表,并在原始矩阵上使用括号符号:

features = ["median_house_value", "median_income", "total_rooms",
                  "housing_median_age"]subset = rounded_corr_matrix[features].loc[features]
heatmap = sns.heatmap(subset, annot=True)

我们注意到,如果我们试图简单地访问rounded_corr_matrix[features],我们将得到一个 9x4 的矩阵,其中包含 4 个所选特征与所有其他数据集特征的关联。我们使用loc pandas 属性,这允许我们使用它们的名称而不是数字索引来访问 9x4 数据结构的特性子集。这些名字当然是features的名字。我们得到一个 4x4 的结构,可以在上面使用我们的热图。结果如下:

数据集子集的热图。图片由作者提供。

散点图—基础

最后,我们使用 pandas 函数scatter_matrix,它为我们提供了更加直观的相关矩阵可视化。顾名思义,该矩阵不是由数字构成的,而是由散点图(2D 图,其中每个轴都是一个数据集要素)构成的。

将特征对之间的线性关系可视化是很有用的(与经典相关矩阵的目的相同,但从视觉的角度来看)。

from pandas.plotting import scatter_matrixfeatures = ["total_rooms", "population", "households", "median_house_value"]
scatter_matrix(housing[features], figsize=(12, 8))

输出是:

加州住房数据集子集的散布矩阵。图片由作者提供。

注意一件奇怪的事情:我们在主对角线上有直方图。理论上,我们应该在这些位置找到变量和本身之间的相关性,但是如果我们画出它们,我们只会得到方程 y=x 的直线(我们在 x 轴和 y 轴上有相同的值,一条直线)。“scatter_matrix”向我们展示了这些变量的直方图,而不是可视化的 45 度线,只是为了快速了解特征的分布。查看其他图,对于某些变量对(es。人口/总房间数,或家庭/人口)有明显的正相关,在某些情况下非常接*1。相比之下,所有变量都呈现出一个与' median_house_value '(最有趣的特征,我们应该设计一个机器学习预测模型)接* 0 的相关值,而且这些图非常“稀疏”。

相关矩阵的使用

既然我们知道了如何构建关联矩阵,并且在探索了 Python 中其他形式的数据可视化技术之后,我们可以问自己这种数据结构的实际用途是什么。通常,在机器学习中使用相关矩阵来进行一些探索性和初步的分析,以推测哪种预测模型可以有效地解决给定的任务。例如,如果我们的模型是一个能够预测房价的回归模型(即我们的模型应该预测一个连续值),我们可以对最感兴趣的特征使用相关矩阵。在这种情况下,最相关的特征(毫无疑问)将是median_house_value,因此传统的方法是绘制该特征和具有更高相关性的特征之间的相关性的热图或散点图:

features = ["median_house_value", "total_rooms", "median_income"]scatter_matrix(housing[features], figsize=(12, 8))

我们会发现median_incomemedian_house_value之间有非常明显的相关性(收入中值越高,房屋价值中值越高……一如既往,这是有道理的)。然后我们可以尝试建立、训练和优化一个简单的线性回归模型。我们不会得到一个非常精确的模型,但这仍然是一个起点,不是吗?

奖励赛道—加州,我们来了!

在文章的前面,我们问了latitudelongitude之间非常低的相关值意味着什么。为了科学起见,让我们画一个这两个变量的散点图:

加州,我们来了!作者图片

嘿,它看起来不像真正的加州的吗?是的,当然!纬度和经度之间的低相关值是由于地理加州形状类似于具有负角度系数的直线。这不是很有趣吗?

下面是生成熊猫散点图的代码:

housing[['longitude', 'latitude']].plot.scatter(x="longitude", y="latitude")

快乐学习和编码!

相关性 vs 协方差:这比看起来简单得多

原文:https://towardsdatascience.com/correlation-vs-covariance-its-much-simpler-than-it-seems-2e9a5d33945b

什么是相关性?我们如何计算连续变量之间的相关性?和协方差有什么区别?

显然,两个人都明白什么是相关性。吉尔·威灵顿摄:https://www . pexels . com/it-it/foto/due-persone-in-piedi-nella-fotografia-di-sa Goma-40815/

机器学习是一个奇妙的研究领域。研究机器学习意味着从最不同的领域(数学、金融、生物学、计算机科学等)获取最有趣的概念,目的是产生准确可靠的预测模型。在我在 Datamasters 担任机器学习和数据科学教师的经历中,学生们不止一次对与数据科学世界相关的基本概念和索引感到困惑。在我的第一篇文章中(这里有意大利语的),我写了一些指数:方差、标准差和协方差。

在这篇文章中,我们将研究另一个听起来令人困惑的指数,但是让我告诉你:它绝对不是火箭科学。我们说的是相关系数。相关性看起来很像协方差,它的使用非常精确:为我们提供关于两个随机变量之间存在关系的信息(如果是的话,还有存在的种类)。不同寻常的是,在“相关性”这个术语下,可以找到许多彼此非常不同的公式和系数。一个系数对另一个系数的使用是基于我们想要计算相关性的变量的类型。

似乎是件大事,嗯?嗯,也许吧。事实是,在某些情况下,事实证明这根本不是限制性的,比你所能想象的要简单得多。让我们从两个随机变量开始,旧好的 6 个人的“体重”和“身高”:

让我们想象一下这些要点:

用 pyplot 制作的数据集的可视化。图片由作者提供。

在开始之前,我们先做个声明。这些变量是数字,即可以在一个数字集合或该集合的区间中采用任何值的变量。它们是而不是 分类变量(其可能值在预定义的集合中的变量,例如“头发颜色”,该集合中可能只有值[“棕色”、“金发”、“黑色”等])。对于我们之前介绍的数值变量,计算相关系数的最常见方法是使用皮尔逊系数。公式是:

皮尔逊相关系数。图片由作者提供。

正如我们所看到的,皮尔逊相关只不过是一个分数,分子是协方差,分母是变量标准差的乘积。

皮尔逊系数用于检测两个随机连续变量之间的线性关系。如果您想测量两个随机变量之间的非线性关系,您只需使用其他系数(如 Spearman 系数)。计算两个随机变量样本之间相关性的公式稍微复杂一些,但基本上我们总是使用相对于变量标准偏差“标准化”的协方差测量。毕竟,为了计算两个随机变量(X,Y)之间的相关性,我们必须:

  • 计算变量*均值
  • 计算变量 std。偏差
    -计算每个样本与变量*均值之差的*方
    -对所有这些*方求和
    -除以样本数
    -求这个分数的*方根
  • 计算 X 和 Y 之间的协方差
    -对于我们数据集中的每个条目,计算 X 分量和 X 均值之间的差,并将其乘以 Y 分量和 Y 均值之间的差
    -对这些乘积求和
    -除以样本数

说起来容易做起来难。让我们继续:

计算“体重”和“身高”的*均值:

μ_w = 76KG
μ_h = 180.33cm

计算标准。重量偏差:

我们得到这样的结果:

σ_w = 13.5523

身高标准也是一样。偏差:

σ_h = 10.8115

为了计算协方差,我们必须考虑每个点(即初始表的单行/单对:[100,194],[80,182],[75,184],…),计算每个分量与其均值之间的差,然后将它们相乘,并对所有这些乘积求和。最后,我们除以 6:

我们得到的是体重和身高之间的协方差:

cov(体重、身高)= 163 公斤-厘米

现在我们可以计算体重和身高之间的皮尔逊相关:

体重和身高之间的皮尔逊相关

被这些数字吓到了?

好吧,如果你喜欢 Python,你可以用 NumPy 用这几行代码得到同样的结果:

import numpy weight = [100, 80, 75, 56, 66, 79]
height = [194, 182, 184, 162, 171, 189]
pearson_corr = numpy.corrcoef(weight, height)[0, 1]
print(pearson_corr) # we'd get exactly 0.92932799

现在,休息一下,注意两件事。首先,相关性是一个无单位数。分子处的 kg-cm 对简化为分母处的标准偏差测量单位。仅这个特性就使得相关性非常有趣,使用起来非常灵活。但是真正改变游戏规则的是相关性有一个明确的区间:它总是一个介于-1 和 1 之间的数字。其含义类似于协方差:

  • 当 X 和 Y 之间的相关性在-1 和 0 之间时,X 和 Y 是反向相关:这意味着当 X 增加时,Y 减少
  • 当 X 和 Y 之间的相关性为 0 时,X 和 Y 没有线性关系
  • 当 X 和 Y 之间的相关性在 0 和 1 之间时,X 和 Y 直接相关:当 X 增加时,Y 也增加。

此外,相关性越接*-1,反向相关性就越“明显”。当然,相关性越接* 1,直接相关性就越明显。在我们的例子中,0.929非常接* 1,这表明体重和身高之间有非常高的直接相关性:我们基本上是说一个人越高,他/她就越重。毕竟这是有道理的。只要看一眼图表,我们就能注意到体重和身高之间的相同关系:

相当的正相关,是吧?图片由作者提供。

让我们画出变量之间相关的另外两种情况。这里有一个非常接*-1 的相关性:

相关性接*-1。图片由作者提供。

这是一个非常接*于 0 的相关性:

相关性接*于 0。图片由作者提供。

在每个图表之前,我们用 Python 打印了相关矩阵,它类似于协方差矩阵。这是一个描述变量之间相关性的正方形表格。在主对角线上我们找到一个变量和本身之间的相关性,当然我们有最大相关值:1。在其他单元格中,我们有行值和列值之间的相关性。但是在另一篇文章中有更多关于这个主题的内容。

在文章结束之前,让我们快速回顾一下协方差和相关性的类比和区别。

图片由作者提供。

我希望这篇文章对你的读者有用。不客气!

生产中经济高效且可扩展的 YOLOv5 模型推理

原文:https://towardsdatascience.com/cost-efficient-scalabel-yolov5-model-inference-in-production-ebe814d44f75

不仅仅是 AWS Lambda

克拉克·蒂布斯在 Unsplash 上拍摄的照片

推理成本可能占计算成本的很大一部分,为了解决这一问题并降低高昂的推理成本,AWS 已经为各种场景提供了几种模型推理解决方案:

但是,如果您正在寻找一个更加灵活、可定制、成本更低的无服务器解决方案,该怎么办呢?最重要的是,如果您的组织正在处理多云基础架构,它可能会被“提升并转移”到其他云*台。或者担心解决方案被某个特定提供商锁定?

欢迎来到 BGL 关于如何实现 AWS Lambda 作为模型推理服务来处理生产中大量推理请求的故事。

上下文

我们的工程团队正在构建一个人工智能产品,以自动化几个业务流程。拥抱人脸转换器(用于 NLP 任务)和约洛夫 5 (用于对象检测任务)框架都被集成,并且已经基于商业案例和数据集训练了几个模型。推理 API 与现有的业务工作流相集成,以实现流程的自动化,因此组织可以将资源从繁琐和低价值的工作中抽离出来,并降低运营成本。

目前的系统每天处理 1000 多个推理请求,在不久的将来,数量将增长 50 倍。一旦候选模型被部署到生产环境并稳定下来,主要的成本就在模型推理上了。

方案设计

作者图片

该解决方案利用几个 AWS 服务来实现以下目的(在该解决方案的上下文中):

  • Sagemaker:培训定制模型
  • EFS:存储已训练模型的工件,作为主要的模型加载源
  • S3:存储已训练模型的工件,作为第二个模型加载源
  • ECR:托管 Lambda docker 映像
  • EventBridge:调用 Lambda 的“调度程序”
  • 系统管理器:在参数存储中存储模型路径

训练

  1. Sagemaker 通常会将模型工件压缩并输出到 S3。此外,在这种情况下,通过添加额外的 Sagemaker 通道名称,还将一个副本保存到 EFS(在 3.2 中解释)。

λ部署

2.1 无服务器框架用于管理 Lambda 配置,通过 Jenkins 和 docker 将所有必需的包和 Lambda 脚本构建到 Docker 映像中,并进一步推送到 ECR。

注意:模型人工制品并没有嵌入到这幅图像中,它们留在了 S3 和 EFS。

下面是一个用于构建 Lambda 映像的 docker 文件示例:

  • 来自 AWS(public.ecr.aws/lambda/python:3.8.2021.11.04.16)的公共 lambda 基本图像
  • 复制用 awslambda.py 编写的 Lambda 逻辑
  • 复制 YOLOv5 项目(最初克隆自 YOLOv5 )作为在 Lambda 中本地加载 YOLOv5 训练模型将需要它
  • 所有需要的包都在一个单独的文件中定义,这个文件叫做 lambda-requirements.txt,在同一个目录下

作者图片

2.2 每个 Lambda 都配置了一个关联的 EventBridge 规则(在无服务器 YAML 文件中)。EventBridge 每 5 分钟调用一次 Lambda,有两个重要目的:

  • 保持 Lambda 温暖以避免冷启动而不触发实际的推理请求
  • 在第一个预热请求中预加载期望的模型,然后缓存它(通过全局变量),这将显著减少由后续实际推理请求的模型加载所导致的推理提前期

作者图片

上面的代码片段显示了无服务器 YAML 文件中使用的 Lambda 配置的结构。详情请参考无服务器框架文档,要点如下:

  • ephemeralStorageSize 5120 会将 Lambda 的“/tmp”文件夹的大小配置为 5120MB(在 3.2 中解释)
  • 模型桶和路径作为 EventBridge 调用的输入参数(在 3.1 中解释)

推论

下图解释了 Lambda 处理逻辑,背后的原理是检查调用是否被触发:

  • 通过 lambda warming 请求(通过 EventBridge) ->加载模式(第一次)& cache-->不处理推理返回,
  • 由实际推理请求->过程推理->返回推理结果

作者图片

3.1 S3 桶和相应的模型路径保存在系统管理器参数存储中,因此这与 Lambda 部署是分离的。工程师可以通过更改参数将 Lambda 指向任何所需的模型,而无需重新部署该 Lambda。

3.2 EFS 是一个文件系统,所以直接从 EFS 挂载和加载模型要快得多(请密切关注 EFS 的带宽成本)。如果 EFS 加载失败(路径无效、带宽受限等),Lambda 会将模型工件从 S3 下载到本地的'/tmp '目录,并从那里加载模型。确保 Lambda 有足够的存储空间用于“/tmp”(在我们的例子中,ephemeralStorageSize 参数被设置为 5120MB)是很重要的!

在 Lambda 中本地加载 YOLOv5 模型非常简单:

作者图片

  • 确保您复制了 yolov5 项目目录(在 2.1 中提到)并将目录的路径设置为 repo_or_dir
  • 使用模型=“自定义”和来源=“本地”
  • 该路径指向有效的*。pt YOLOv5 训练模型。

限制

所有的模型都是错的,但有些是有用的——乔治·博克斯

所有的解决方案都是错的,但有些是有用的——本文作者:)

没有完美的解决方案,所有解决方案都有权衡和限制,建议的解决方案的一些限制包括:

  • Lambda 推理不是为要求实时处理和极低延迟的实时推理而设置的
  • Lambda 有 15 分钟的运行时间限制,如果推理时间太长,就会失败
  • EFS 带宽费用是额外的费用,但是你可以切换到 S3 下载和加载作为主要方法,EFS 安装和加载作为次要方法。它速度较慢,但成本较低,并且批量推断通常对延迟不敏感

潜在提升和转移

该解决方案的一些功能/设计模式可能会被提升并转移到其他云*台(例如 Azure、GCP ),因为它们提供与 AWS 类似的服务,其中两个有价值的服务是:

  • 使用低成本的无服务器计算机服务(Azure 函数、GCP 函数)来服务模型批量推理,并与“调度程序”集成以保持服务“温暖”
  • 设计预加载和缓存模型的逻辑,以减少推理处理时间

总结

感谢您的阅读,希望您喜欢这篇文章,以下是一些要点:

  • AWS Lambda、EFS 和 S3 可以组合成一个经济高效、可扩展且健壮的服务,用于模型批量推理(最多 15 分钟)
  • 正确实现 AWS EventBridge Lambda 触发器有助于最小化 Lambda 冷启动
  • 在 Lambda 中实现模型预加载和缓存逻辑将有助于减少模型推理的交付时间
  • 将模型路径作为系统参数传递,而不是将模型嵌入到 Lambda 图像中,这样可以获得更大的灵活性(解耦)
  • 在其他云*台上应用类似的概念有潜在的提升和转变机会

AWS 中的成本优化策略

原文:https://towardsdatascience.com/cost-optimisations-within-aws-72a9149c92e5

考虑减少 EC2、Lambda 和 S3 的经常性费用

在过去的四年里,我与亚马逊网络服务公司(Amazon Web Services)进行了广泛的合作,在我的圈子里经常出现的一个话题是在云中运行应用程序和数据库的成本。无论是在简单存储服务 (S3)中存储数据的价格,保留弹性块存储 (EBS)卷的快照的价格,还是运行弹性云计算 (EC2)实例的价格,费用很容易累积,并在我们审查即将到来的账单时引起我们的注意。

思考最*我在 EC2、 Lambda 和 S3 工作中应用的成本优化,让我们探索如何分析我们的费用并利用 AWS 的功能来减少我们的账单。这绝不是一篇独特的博文 AWS 和其他贡献者提供了大量的材料——但我希望它能成为未来参考的有用补充。

来源:作者成本浏览器截图

成本浏览器

在 AWS 控制台中,我们可以导航到成本浏览器以了解我们现有的费用和预测的未来账单。

来源:作者的 AWS 搜索截图

这将引导我们进入成本管理主页,在这里我们可以查看到目前为止 AWS 成本的高级图表。谢天谢地,我的个人账单看起来很健康,但商业账户可能会有明显更高的数字。

来源:作者的成本管理截图

选择条形图上方的“在成本浏览器中查看”,我们将自己重定向到一个更复杂的图表,该图表具有分解费用的过滤器。按服务对成本进行分组,我们看到在我的案例中,税收对我的成本的贡献最大,其次是关键管理服务 (KMS)。

来源:作者成本浏览器截图

另一个可能证明特别有价值的分组是标签。通过应用于不同 AWS 资源的定义良好的标签键和值框架,按标签进行的计费细分对于更深入地了解 AWS 费用的来源非常有用——特别是如果资源是按部门、团队或不同的组织粒度层进行标记的话。

对我们的成本来源有了更好的理解,让我们从 EC2 开始,探索 AWS 在其几个最受欢迎的服务中提供了哪些功能来帮助我们减少账单。

弹性云计算(EC2)

EC2 覆盖了各种不同的资源,是一种伞式服务,用于服务器实例、流量负载*衡器弹性网络接口以及其他基础设施。实例可能需要持久存储,采用 EBS 卷的形式。此外,我们可能希望使用机器映像轻松启动与现有配置匹配的副本实例,或者我们可能希望使用快照保留 EBS 卷的备份。

这些不同的资源和策略的成本很容易攀升。首先从 EC2 实例开始,我们可以采用 EC2 实例节省计划来降低特定实例类型和 AWS 区域的计算费用,或者探索计算节省计划来降低计算成本,而不考虑类型和区域。前者在编写时节省高达 72%,而后者节省高达 66%,并扩展到 ECS Fargate 和 Lambda 函数。

EC2 还提供不同的购买选项以供举例。这包括保留实例,在这种情况下,我们可能会以较低的成本承诺一年或三年的特定配置,以及现场实例,在这种情况下,如果我们乐意应用程序被中断,我们可能会支付明显较低的成本。

考虑了实例购买和计算计划之后,我们可以将注意力转向 EBS 支持的机器映像和卷快照。数据生命周期管理器对于自动化这些资源的创建、保留和删除非常有用。但是,这不会管理通过其他方式创建的映像和快照,也不包括实例存储支持的映像。

来源:作者的数据生命周期管理器截图

虽然对降低成本没有帮助,但另一个值得强调的功能是 EC2 回收站。如果我们手动删除图像和快照,或者依靠数据生命周期管理器,回收站可以作为一个安全网来避免意外删除资源—在可配置的时间内保留图像和快照,我们可以在它们被永久删除之前恢复它们。

来源:作者 EC2 回收站截图

λ函数

在讨论了 EC2 实例之后,让我们考虑一下前面提到的 Lambda 服务。与 EC2 不同,Lambda 函数是无服务器的,因此主要考虑资源使用和配置,而不是供应成本。

首先,让我们探索一下指令集架构的功能。2021 年 9 月,AWS 推出了 Arm/Graviton2 处理器,用于全面上市,作为当前运行 x86 处理器的功能的更便宜、更高性能的替代品。AWS 文档建议了从 x86 切换到 Graviton2 的迁移步骤,这对于节省初始成本是明智的。

一个更微妙的成本将我们的注意力转移到了 CloudWatch 中 Lambda 的日志配置。默认情况下,Lambda 会自动为其函数创建日志组,除非已经存在一个与名称/aws/lambda/{functionName}匹配的组。这些默认组不配置日志保留期,让日志无限累积,增加了 CloudWatch 的成本。考虑使用匹配的名称和保留策略显式配置组,以维护可管理的日志量。

最后,同样重要的是,考虑 Lambda 函数的内存容量。Lambda 根据以 GB 秒为单位的计算时间收费,其中以秒为单位的持续时间是从函数代码执行时开始计算,直到它返回或终止,四舍五入到最接*的毫秒。为了减少这些时间,我们需要最佳的内存配置。 AWS Lambda 功率调谐可以帮助识别这些优化,尽管考虑到底层使用 AWS 阶跃函数会有显著的初始成本。

简单存储服务(S3)

离开处理服务,让我们现在考虑 S3 境内的数据存储。持久化高达 5TB 的对象,S3 使用“桶”来存储理论上无限数量的对象。没有默认的对象保留策略,因此存储桶大小可能会快速增长,从而增加我们的 AWS 账单。我们不仅要为我们存储的数据量付费,还要为我们使用的S3 存储类别付费。

有几种价格不同的课程可供选择。标准(默认)类是最昂贵的,允许对具有高可用性和短访问时间的对象进行常规访问。非频繁访问(IA)类降低了需要有限访问(通常每月一次)的数据的成本,而通过 Glacier 的归档选项进一步降低了成本。

为了管理存储类别和数据保留时间,我们可以关注一下 S3 生命周期配置规则。应用这些规则,我们可以自动将数据转移到不同的存储类别,然后分别在数据创建后的 X 天和 Y 天将其永久删除。

来源:作者提供的 S3 生命周期配置规则的屏幕截图

结论

这篇博客文章只涵盖了 AWS 众多不同服务中的一小部分,希望能为 EC2、Lambda 和 S3 的成本优化考虑提供有用的参考。账单和费用是一个经常性的话题——毫无疑问,我们中的很多人都会遵循这里提到的策略,但我相信还有很多其他的选择和想法值得分享。请告诉我们你是否采取了不同的方法来减少你的账单,以及这些方法被证明有多有效。

大规模统计不同的指标

原文:https://towardsdatascience.com/count-distinct-metrics-at-scale-95a394c03f1

如何加速不同查询的计数并设计高效的聚集表

DreamStudio 生成的图像

一种复杂的算法,超对数对数(HLL) 可以用来估计多重集中的不同元素。本文讨论了使用 HLL 大规模处理 count distinct 指标的实用方法。然而,这篇文章并没有探究 HLL 的内部运作。

数据分析中最常见的度量之一是某些实体的计数差异。例如,您可能对有多少不同的用户感兴趣,或者对有多少不同的用户执行某个操作感兴趣,或者对有多少不同的设备访问了您的网站感兴趣。从概念上讲,count distinct 是一个简单的操作。例如,您可以编写以下 SQL 查询来从用户表中获取不同的用户-

SELECT
  count(distinct user_id) as unique_users
FROM
  user

但是,在处理大规模数据时,您可能会遇到两个计数不同的问题

  1. 高基数
  2. 添加

高基数

高基数指的是大量不同的值,想想具有数千万或数亿个唯一值的列。如果您正在大规模处理数据,您可能会经常遇到这些情况。例如,考虑下面的场景。

你有一个非常受欢迎的消息应用程序,该应用程序记录用户活动的事件。记录的事件示例有 app_start、start_message、read_message、sent_message 等。在任何一天,你都有大约一千万的独立用户和几亿的总事件。事件表是具有以下模式的日期分区表

要获得该应用在任何给定日期的 DAU(每日活跃用户),您可以编写以下查询

SELECT
  count(distinct user_id)
FROM
  event
WHERE
  dt_partition = '2022-12-17'

但是由于表的大小(一个 dt 分区有 100 万个事件)和 user_id 的基数(1000 万个唯一的 user _ id),这个查询会非常慢,而且需要大量资源。为了计算非重复计数,SQL 引擎必须检查所有的值,同时在内存中维护所有的唯一值。SQL 引擎将增加一些优化来加快速度,但在它的核心,这是一个非常资源密集型的计算。为了加快计算速度,可以使用*似相异操作。大多数 SQL 引擎都包含 count distinct 的*似版本,下面是一些来自 PrestoSpark-SQL红移BigQuery 的例子。使用*似不同的函数,您可以设置标准误差的上限。下面是使用*似函数和标准误差上限 0.005 时查询的样子。

SELECT
  approx_distinct(user_id, 0.005)
FROM
  event
WHERE
  dt_partition = '2022-12-17'

*似相异函数功能强大且有弹性,但仅在数据规模允许且用例对答案中的小错误稳健时使用。例如,*似不同函数对于财务会计用例来说不是一个好主意。超对数算法支持*似计数不同函数。超对数算法是一种概率数据结构,可用于估算数据集中不同元素的数量。它基于将输入数据映射到一组桶,然后使用空桶的数量来估计输入数据的基数(即不同元素的数量)的思想。

相加性

计算不同指标的另一个问题是它们不能在不同的维度上相加。让我们更深入地探讨一下这个问题。

让我们使用以下模式为日期-事件类型-事件子类型粒度上的事件构建一个聚合表

可以使用以下查询来构建该表

SELECT
  dt_partition as event_date,
  event_type,
  event_subtype,
  count(*) as event_count,
  approx_distinct(user_id, 0.005) as distinct_user_count
FROM
  event
GROUP BY
  1, 2, 3

在实践中,数据分析师、数据科学家和 ML 工程师广泛使用这种聚合表来执行探索性分析、进行实验、为 ML 创建数据集以及为仪表板提供动力。聚合表具有预计算的指标,可以进一步聚合到任何所需的粒度。例如,从 agg_event_type_daily 表中,我们可以简单地通过按 event_date 分组并对 event_count 求和来获得所有 event_type 的每日事件计数。

SELECT
  event_date,
  sum(event_count) as daily_event_count
FROM
  agg_event_type_daily
GROUP BY
  1

聚集表中的计数不同指标无法进一步聚集,我们无法从 agg_event_type_daily 表中获取所有 event_type 的每日不同用户。为了解决这个问题,我们可以利用*似相异计数函数使用的数据结构,即 HLL 草图(超对数草图)。HLL 草图是一种概率数据结构,用于估计数据集中唯一元素的数量。不同底层集合的 HLL 草图可以被合并,得到的 HLL 草图可以用来得到底层集合的并集的唯一元素。让我们看看如何将 HLL 草图合并到一个汇总表中。 agg_event_type_daily 表的更新模式如下所示

对该表的查询如下

SELECT
  dt_partition as event_date,
  event_type,
  event_subtype,
  count(*) as event_count,
  approx_distinct(user_id, 0.005) as distinct_user_count,
  approx_set(user_id, 0.005) as distinct_user_sketch
FROM
  event
GROUP BY
  1, 2, 3

新的 agg_event_type_daily 表让我们可以在不同的粒度上聚合不同的用户计数。例如,我们现在可以获得如下的每日不同用户计数

SELECT
  event_date,
  cardinality(merge(distinct_user_sketch)) as daily_distinct_user_count
FROM
  agg_event_type_daily
GROUP BY
  1

本例中使用的 HLL 函数是 Presto 特有的,但类似的函数也存在于其他查询引擎中,如 SparkRedshiftBigQuery

结论

当您在大规模计算不同的度量时,并且您在准确性方面有一些余地,您应该

  • 使用 approx_distinct 函数来加速查询
  • HLL 地图合并到聚合表中,以实现进一步聚合

如何计算熊猫数据帧列的 NaN 值

原文:https://towardsdatascience.com/count-nan-values-pandas-27a50acfc929

计算 pandas DataFrames 列中的空值

Kelly SikkemaUnsplash 上拍摄的照片

介绍

在今天的短文中,我们将讨论 Python 和 Pandas 中一个简单但常见的任务。具体来说,我们将展示在特定的 DataFrame 列中计算空值的多种方法。更具体地说,我们将讨论如何计数

  • NaN特定列中的值
  • NaN整个数据帧中的值
  • NaN每个单独列中的值
  • NaN列子集中的值
  • 所有列中包含NaN值的行
  • 特定列中包含NaN值的行

首先,让我们创建一个示例 DataFrame,我们将在本教程中引用它,以便理解如何计算空值。

import pandas as pd 
df = pd.DataFrame(
    [
        (1, 100, None, 'A'),
        (2, None, True, 'B'),
        (3, 150, None, None), 
        (4, 100, None, 'B'),
        (5, None, False, 'B'),
        (6, 120, False, 'A'),
        (7, 45, True, 'C'),
    ], 
    columns=['colA', 'colB', 'colC', 'colD']
)print(df) ***colA   colB   colC  colD
0     1  100.0   None     A
1     2    NaN   True     B
2     3  150.0   None  None
3     4  100.0   None     B
4     5    NaN  False     B
5     6  120.0  False     A
6     7   45.0   True     C***

计算特定列中的 NaN 值

现在,为了计算特定列中包含NaN值的行数,您可以使用[pandas.Series.isna()](https://pandas.pydata.org/docs/reference/api/pandas.Series.isna.html#pandas.Series.isna)方法后跟sum(),如下所示:

>>> **df['colB'].isna().sum()**
2>>> **df['colA'].isna().sum()**
0

或者,您也可以使用[isnull()](https://pandas.pydata.org/docs/reference/api/pandas.isnull.html)方法:

>>> **df['colB'].isnull().sum()**
2

计算每一列的 NaN 值

现在,如果您想要获得每个单独列的缺失值的计数,那么您可以使用后面跟有sum()[pandas.DataFrame.isna()](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.isna.html#pandas.DataFrame.isna)方法。输出将是一个 Series 对象,包含原始数据帧中每一列的计数:

>>> **df.isna().sum()**
colA    0
colB    2
colC    3
colD    1
dtype: int64

对列子集中的 NaN 值进行计数

如果只需要原始数据帧中的一部分列的计数,可以执行与上一节相同的操作,但是这次对数据帧进行切片:

>>> **df[['colA', 'colD']].isna().sum()** colA    0
colD    1
dtype: int64

对指定列中只有 NaN 值的行进行计数

现在,如果您想计算所有指定列中缺少值的行数,可以使用下面的符号。例如,让我们假设我们想要计算在colCcolD中有多少行丢失了值:

>>> **df[['colC', 'colD']].isna().all(axis=1).sum()**
1

对每列中只包含 NaN 值的行进行计数

同样,如果您想计算整个数据帧中每一列只包含缺失值的行数,可以使用下面的表达式。注意,在我们的示例数据帧中,不存在这样的行,因此输出将是 0。

>>> **df.isnull().all(axis=1).sum()**
0

计算整个数据帧内的 NaN 值

最后,如果要计算整个数据帧中每一列包含的缺失值的数量,可以使用以下表达式:

>>> **df.isna().sum().sum()**
6

最后的想法

在今天的短文中,我们讨论了使用 Pandas 数据帧时的一个非常简单但常见的任务,并展示了如何计算特定列或整个数据帧中的空值。

成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。

https://gmyrianthous.medium.com/membership

你可能也会喜欢

如何计算熊猫数据帧列中某个值的出现次数

原文:https://towardsdatascience.com/count-occurrences-of-a-value-pandas-e5dad02303e9

计算熊猫数据帧列中特定值的出现频率

照片由纳丁·沙巴纳Unsplash 上拍摄

介绍

当处理 pandas 数据框架时,我们通常需要检查数据并提取一些指标,这些指标最终将帮助我们更好地理解数据,甚至识别一些异常情况。我们在日常工作中需要执行的一个非常简单但常见的任务是计算某个值在数据帧中出现的次数。

在今天的简短教程中,我们将展示如何计算熊猫数据帧列中特定值的频率。我们将探讨如何计算该列中出现的所有唯一值的频率,或者只计算某个特定值的频率。

首先,让我们创建一个示例数据框架,我们将在本教程中引用它来演示几个概念。

import pandas a pddf = pd.DataFrame(
    [
        (1, 5, 'A', True),
        (2, 15, 'A', False),
        (3, 5, 'B', True),
        (4, 6, 'A', False),
        (5, 15, 'C', True),
        (6, None, 'B', True),
        (7, 15, 'A', False),
    ],
    columns=['colA', 'colB', 'colC', 'colD']
)print(df)
 ***colA  colB colC   colD
0     1   5.0    A   True
1     2  15.0    A  False
2     3   5.0    B   True
3     4   6.0    A  False
4     5  15.0    C   True
5     6   NaN    B   True
6     7  15.0    A  False***

使用 groupby

在计算某个特定值在特定列中出现的次数时,我们的第一个选择是用groupbycount来计算该特定值。让我们假设我们想要计算列colB中的每个值出现了多少次。下面的表达式可以帮我们解决这个问题:

**>>> df.groupby('colB')['colB'].count()**5.0     2
6.0     1
15.0    3
Name: colB, dtype: int64

请注意,上面的表达式将给出指定列中出现的每个非空值的频率。

使用值计数

或者,我们可以使用[pandas.Series.value_counts()](https://pandas.pydata.org/docs/reference/api/pandas.Series.value_counts.html)方法,该方法将返回包含唯一值计数的熊猫Series

**>>> df['colB'].value_counts()**15.0    3
5.0     2
6.0     1
Name: colB, dtype: int64

默认情况下,value_counts()将返回非空值的频率。如果您还想包括None值的频率,您可以简单地将dropna参数设置为False:

**>>> df['colB'].value_counts(dropna=False)**15.0    3
5.0     2
NaN     1
6.0     1
Name: colB, dtype: int64

将计数添加为新列

如果您想将结果添加回原始数据帧,您需要使用transform()方法,如下图所示:

**>>>** **df['colB_cnt'] =** **df.groupby('colB')['colB'].transform('count')
>>> df
**   colA  colB colC   colD  colB_cnt
0     1   5.0    A   True       2.0
1     2  15.0    A  False       3.0
2     3   5.0    B   True       2.0
3     4   6.0    A  False       1.0
4     5  15.0    C   True       3.0
5     6   NaN    B   True       NaN
6     7  15.0    A  False       3.0

现在,每一行都将具有在新创建的列colB_cnt下的列colB中出现的值的相关频率。

获取特定值的频率

在前面的部分中,我们展示了如何计算出现在特定列中的所有唯一值的频率。如果您只对单个值的频率感兴趣,那么您可以使用以下任何一种方法(假设我们希望值15出现在列colB中的次数):

**>>> (df.colB.values == 15).sum()**
3>>> **(df.colB == 15).sum()**
3>>> **len(df[df['colB'] == 15])** 3

最后的想法

在今天的短文中,我们探讨了在计算特定 pandas DataFrame 列中值的频率时的一些不同选项。此外,我们展示了如何在现有数据框架中添加计算的计数/频率作为新列。

最后,我们探索了如何使用一些不同的选项计算 DataFrame 列中特定值的频率。

成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。

https://gmyrianthous.medium.com/membership

你可能也会喜欢

https://betterprogramming.pub/11-python-one-liners-for-everyday-programming-f346a0a73f39

强化学习的反事实 II:改善奖励学习

原文:https://towardsdatascience.com/counterfactuals-for-reinforcement-learning-ii-improving-reward-learning-4c59d9c0429d

使用反事实进行更安全的奖励函数学习

在本系列的前一部分中,我介绍了反事实,并展示了如何在 POMDP 框架中对它们进行编码。在这一部分,我将集中讨论如何将反事实应用于奖励学习这一新兴领域。文章将首先简要总结奖励学习的基本要素。接下来,我将通过一个运行中的例子来展示奖励学习如何无法产生预期的结果。最后,我将介绍反事实奖励学习,并展示它如何在我们的例子中帮助解决常规奖励学习的问题。如果您已经阅读了第一部分,理解本文的唯一要求是您熟悉强化学习的基础知识。

奖励学习:弄清楚你想要什么

简而言之,奖励学习专注于寻找强化学习问题的奖励函数的算法。这个想法是,一个习得的奖励函数应该比一个预定义的函数更准确地描述程序员的意图。我已经在之前的文章中写了更多关于奖励学习背后的动机及其问题。

作为一个连续的例子,我们将考虑我所说的字母问题。假设我们的代理是一个清洁机器人,我们可以告诉它在我们工作时清洁我们的一个房间:厨房或客厅。也因为我们是大忙人,我们必须一大早就离开,而我们的代理人还在给电池充电,所以我们不能告诉它要打扫哪个房间。相反,我们将这些信息写在一封信中,让代理在收费后阅读。

一个正在考虑打扫哪个房间的清洁机器人。来源:作者根据各种来源的材料生成,见下面的图片来源

字母问题几乎是一个典型的强化学习问题,只不过有两种可能的奖励函数。如果这封信告诉代理人打扫厨房,它将因打扫厨房而获得 1 英镑的奖励,客厅也是如此。我们称之为奖励学习问题,因为代理首先需要弄清楚其奖励函数的真实性质,然后才能解决任务。

为了使这个想法更加正式,我将使用在第一部分中建立的 POMDPs 的符号。我们想用所谓的奖励函数学习过程来扩展被建模为 POMDP 的传统强化学习问题。在 POMDP 中,奖励函数 R 是常数。我们可以认为这意味着代理人总是绝对肯定地知道他们的真实回报。然而,为了让代理能够学习奖励函数,它必须能够对奖励函数的真实性质有较弱的信念。这样的信念可以被表达为奖励函数上的概率分布。那么,代理人得到的报酬就是基于这种分布的期望。例如,如果代理人认为打扫厨房或客厅的可能性是相等的,那么它会认为打扫的回报是 0,5。当然,如果代理不能更新他们的信念,就不会有任何学习。因此,代理收到的观察结果可以改变它对奖励函数的信念。编码这种变化的数学对象是:

  • ρ:奖励函数学习过程。从历史到奖励函数分布的函数。

类似于我们如何从策略和以前的历史中获得当前行为的概率,以及从奖励函数和以前的历史中获得当前奖励,我们从奖励函数学习过程和以前的历史中获得当前奖励函数的概率。

利用奖励学习解决字母问题

现在我们已经讨论了数学预备知识,让我们在 POMDP 框架内对字母问题建模。我们把公寓模拟成一个 3x3 的网格世界,网格对应于房间。机器人从左上角的房间开始,信封在中上,厨房在中左,客厅在右下。按照 gridworlds 的惯例,代理可以在四个基本方向上移动以改变网格(相应的动作将表示为 N、E、S 和 W)。此外,如果它与信封在同一个房间中,它可以读取它(动作 R),如果它在厨房或客厅中,它可以清洁(动作 C),这将结束该集并导致奖励。如前所述,奖励是从奖励函数的分布中推断出来的,奖励函数是从代理的历史和学习过程ρ中得到的。有两个潜在的奖励函数:K 和 L,分别对打扫厨房和客厅给予 1 的奖励。此外,由于我们不希望我们的清洁机器人走掉,它每次进入一个房间都会得到-0.1 的奖励。

字母问题的网格世界。来源:作者根据各种来源的材料生成,见下面的图片来源

最初,直到它读了信,代理人不确定要打扫哪个房间。因此,对于代理没有阅读信件的任何历史,ρ将 50%给予 K,50%给予 l。另一方面,如果代理阅读信件,那么ρ将 100%给予对应于来自信件的指令的奖励函数。信中所写的奖励功能的本质被认为是环境的一部分。像我们这样的模型可以允许许多可能的环境,例如,一个字母表示 L,一个字母表示 k。但是,环境不会在同一训练运行的不同阶段之间改变,因为这将使一致的奖励学习成为不可能。

我们认为这个环境对于每个网格有一个状态和一个观察值。这是因为我们使用奖励学习过程ρ和代理的历史给出的分布来模拟关于奖励的不确定性。如果你把它作为一个程序来实现,那么ρ可能隐含在不同的状态中,这对应于代理可能拥有的不同信念。在[1]中是这样做的。

那么ρ如何融入强化学习的数学中呢?在 RL 中,我们试图找到一个策略,在一集的所有未来时间内优化预期回报。这种期望由价值函数给出,价值函数通常基于代理的策略和当前状态。相反,在我们的设置中,我们采用一种更通用的方法,并考虑到该时间步长的历史:

强化学习的价值函数,用历史表示。来源:作者生成

这里,该值是长度为 n 和策略π的可见历史的函数。对于每一个具有 m 个步骤的潜在完整历史,给定所看到的历史和策略,该历史的概率乘以它将给予我们的总回报。为了对奖励学习过程进行调整,我们必须考虑存在多个可能的奖励函数,其概率基于ρ。因此,我们将对回报函数的期望并入我们的价值函数:

用于奖励学习的价值函数。来源:作者根据[3]生成

就我们的目的而言,我们感兴趣的是这个价值函数所激励的行为。由于清洁行动结束了这一集,如果它在没有阅读信封的情况下随机选择了一个房间,那么代理最多可以获得以下奖励:清洁厨房将获得 0.4 英镑的奖励(清洁正确房间奖励的 50%,进入一个房间-0.1 英镑)。打扫客厅的最高奖励是 0,1,因为要进入 4 个房间才能到达那里。另一方面,如果它阅读信封,然后清理正确的房间,它将收到厨房 0.9 和客厅 0.6 的奖励。这是一个非常安全的奖励学习过程,非常适合训练我们的清洁机器人。然而,只要稍微调整一下,这个过程就可能被滥用。

字母问题的不安全版本

假设我们的代理不仅仅是一个清洁机器人,而是一个多用途的助手,可以帮助我们完成许多任务,比如说写信。因此,我们给了我们的代理另外两个动作,它可以用来操纵我们的信件。当它在包含字母的网格上时,它可以写一条信息告诉它打扫厨房或客厅。如果它在阅读信件之前这样做,这将相应地影响奖励学习过程的结果。有了上面定义的价值函数,最优策略将永远是去信封,修改它说 K,阅读它,然后打扫厨房,总奖励为 0,9。然而,尽管代理收到的数字分数尽可能高,但其行为不一定与我们的意图一致。代理将了解使其清洁厨房的政策,即使我们写的说明是清洁客厅!

使用反事实改进奖励学习

如果我们的代理足够聪明,能够理解自然语言中的命令,那么我们可以告诉它类似这样的话:“打扫房间,如果你不写信,就会在信封上写下。”。然而,在机器能够将这样的命令转化为奖励学习过程之前,可能还需要 GTP 的几次迭代。因此,我们将不得不用老办法来做,并把这一新过程编码到构成我们算法基础的数学中。在本系列的第一部分中,我们从 POMDP 和“反事实”策略开始。他们被用来获得一个新的“反事实”POMDP,如果一个人遵循反事实政策,它将从旧 POMDP 上发生的事情中获得知识。在我们的设置中,我们将类似地使用奖励学习过程和反事实策略来获得新的反事实奖励学习过程。因此,奖励学习过程“在写信之前或之后阅读信的内容,以确定打扫哪个房间”和反事实策略“阅读信,但不写信”将结合起来产生反事实奖励学习过程“阅读信的内容,而不写信,以确定打扫哪个房间”。

那么给定一个奖励学习过程ρ和一个策略π,给定一个看得见的历史 h(n),我们如何得到反事实的奖励学习过程ρ(π)?为了便于解释,我将从一个简化假设得出的等式开始,然后将其扩展到完整的等式。还记得在第一部分中,我们是如何将我们的反事实陈述框定为“如果反事实历史 h’已经发生,那么我们可以推断历史 h 具有这种可能性”。在反事实奖励学习的情况下,陈述变成“如果 R 有这些概率,给定π产生的历史,那么我们可以推断 R 的概率,给定另一个历史 h”。然而,与第 1 部分类似,为了实现这一点,我们需要假设所有的历史在某个时间步之前都共享其底层的真实状态。因此,我们的简化假设是,我们确实知道所看到的历史的第一个状态是 s。然后,我们可以计算当第一个状态是 s 并且代理遵循π时,获得完整历史 h 的概率 P(h|s(1) = s,π)。因此,为了得到给定 s(1) = s 的反事实奖励学习过程的概率,我们取给定从 s 开始的历史的原始奖励学习过程的期望:

如果第一个状态已知,从反事实奖励学习过程中获得奖励函数 R 的概率。来源:作者生成

我们如何处理不知道第一状态的更一般的情况?主要区别在于,在可能历史的总和中,给出历史 h 的概率的项 P(h|s(1)=s,π)不再是固定的。取而代之的是,这一项也变成了一个期望,这一次是在可能的状态 s 上:

来源:作者根据[2]生成

这就是我们想要的方程,它展示了在已知历史的情况下,如何得到 R 的反事实概率。这就把我们引向了反事实价值函数,用给定政策的反事实奖励学习过程来代替原始定义中的奖励学习过程:

反事实价值函数。这里,带有下标 c 的策略表示反事实策略。来源:作者生成

找到正确的反事实政策

为了解决信件问题,我们需要找到一个反事实策略,它将产生一个价值函数,激励代理在不操纵信件的情况下清理正确的房间。还记得我们如何将反事实指令表述为“阅读信件,但不要写信给它”。因此,我们需要一个恒定的策略,告诉代理首先向西,然后执行读取操作。为了计算出结果,它仍然需要结束这一集,所以让我们选择一个策略,让它在之后清理厨房。把所有的东西放在一起,我们得到一个不变的策略,它将导致下面的动作序列:{W,R,E,S,C}。用词:往西,读信,往东,往南,打扫厨房。

我们不变的政策导致反事实的学习过程,给对应于信中指示的奖励函数一个概率 1。因此,对于以清洁正确的房间结束的历史,值函数将仅具有非零值。我们做到了!我们保证了清洁机器人的安全!

讨论

注意我们的反事实政策总是以打扫厨房结束。尽管如此,代理人使用反事实价值函数学习他们的政策,可能最终会根据信中所写的内容来打扫房间。如果信中说打扫客厅,那么代理将学习打扫客厅,并获得该环境的最高可能奖励,即使遵循反事实政策将导致打扫厨房并获得负奖励。这是因为反事实策略唯一重要的方面是它学习的奖励函数,而不是它产生的行动的确切序列。这意味着,当我们有了将导致学习正确奖励函数的策略的想法(“读信而不写信”)时,反事实奖励学习是有用的,但不是最终政策应该看起来像什么。尽管如此,对于现实生活中的代理人来说,他们的行为可能会以更复杂的方式与奖励学习过程相互作用,因此可能不像我们的玩具例子那样容易想出一个好的反事实政策。

在计算上,所有这些都可以像典型的强化学习问题一样实现。不是每个房间都有一个状态,而是有多个状态,对应于代理在该状态下的奖励函数的信念。但是有一个限制。为了从反事实学习过程中获得奖励函数的概率,你需要计算 P(h|s(1) = s,π)项。因此,您要么需要能够基于策略模拟历史,要么需要有足够的资源来运行足够多的剧集来估计这种概率。这给你应用反事实奖励学习的环境设置了一些限制。

总之,反事实奖励学习仍然有一些实际的(需要提出一个反事实的政策)和技术的(可能需要一个环境的模型)限制。然而,在正确的情况下,它是一个有用的工具,可以使奖励学习过程的结果更符合人类的意图。因此,随着奖励学习变得更加普遍,反事实很可能仍然是人工智能安全研究人员工具箱的一部分,并可能为进一步的研究提供坚实的基础。

文献学

[1] Armstrong 等人,在线学习奖励函数的陷阱,Arxiv,2020 年 4 月 28 日,【https://arxiv.org/abs/2004.13654

[2] Armstrong Stuart,反事实不可影响代理人,LessWrong,2017 年 6 月 2 日,https://www . less wrong . com/posts/5bd 75 cc 58225 BF 067037536 b/反事实不可影响代理人

[3] Armstrong Stuart,奖励函数学习:价值函数,LessWrong,2018 年 4 月 24 日,https://www . less wrong . com/posts/55 hjdq 5y 7 dv 3s 4h 49/Reward-function-Learning-The-value-function

[4]埃弗里特·汤姆,走向安全的人工通用智能,汤姆·埃弗里特网站,2019 年 6 月,https://www.tomeveritt.se/papers/2018-thesis.pdf

[5] Everitt Tom 和 Hutter Marcus,强化学习中的奖励篡改问题和解决方案:因果影响图视角,Arxiv,2021 年 3 月 26 日,https://arxiv.org/abs/1908.04734

照片来源

Sidekix MediaUnsplash 上拍摄的客厅照片。

内奥米·赫伯特在 Unsplash 上拍摄的厨房照片。

来自维基共享资源的卡通机器人。

posted @ 2024-10-18 09:32  绝不原创的飞龙  阅读(392)  评论(0)    收藏  举报