TowardsDataScience-博客中文翻译-2021-十-
TowardsDataScience 博客中文翻译 2021(十)
原文:TowardsDataScience Blog
协议:CC BY-NC-SA 4.0
版本控制系统入门
原文:https://towardsdatascience.com/a-laymans-introduction-to-version-control-system-288dea3c3026?source=collection_archive---------15-----------------------
玩 Git

照片由 Unsplash 上的 ammar sabaa 拍摄
“没有真理这种东西。每个人都有自己的版本
你曾经用日期时间戳保存过你的文件吗?我想我们大多数人都这样做是为了保存现有文件的一个版本。当我们要做某些更改,但又想保留原始内容的历史时,这是必需的。在任何时间点,如果你想回到原来的内容,你可以回去。此外,您可能希望记录当前更改完成的原因。
我有一个保存开支的文件夹。我可以通过在文件名中添加日期来维护不同日期的费用,如下所示:

这是**“版本控制”**的粗略形式,其中我们保留了原始文件的备份,并将更改保存到新文件中。如果你正在做一些小的个人工作,比如一些班级项目,这种版本控制或者版本维护是很好的。然而,当您在一个多人工作的软件项目中工作时,您需要一个更好的机制,通过它在多个文件(源代码文件、配置文件或任何类型的文件…..)由多人可以处理。这就是版本控制系统(VCS)的用处。版本控制软件提供了一种在一段时间内跟踪文件变化的机制。
通过使用 VCS,我们可以知道什么、什么时候、由谁进行了更改。
让我们看看您在任何版本控制系统中使用的基本术语和操作:
1.VCS 将提供一个数据库或存储位置,您可以在其中存储您的文件。这被称为储存库或回购。回购协议中包含的文件将被 VCS 追踪。存储库所在的计算机称为“服务器”,而连接到存储库的计算机称为“客户端”。因此,您的计算机将是客户机,而运行版本控制系统的计算机是服务器。
2.在您的机器或本地计算机上,您保存文件和进行更改的位置或文件夹称为“工作副本
3.在存储库中,保存文件的主要地方称为“主干”或**“主分支】**。
4.当你第一次上传你的文件到回购,这被称为“添加”,即你要求 VCS 开始跟踪你的文件。
5.VCS 将为您的文件分配一个版本号。这就是所谓的改版。
6.如果您决定对存储在回购协议上的文件进行更改,您将“检出”该文件。这意味着你现在正在从回购下载一个文件。
7.进行更改后,您可以将文件上传到存储库。这叫做“签到”。除了签入,您还可以提供注释,解释为什么要进行这些更改。
8.VCS 还提供了已完成的更改列表。这叫做“变更日志”。
9.如果一个文件或文件夹被复制为私人使用,它被称为分支。
10.如果一个文件的更改被应用到另一个文件,这被称为合并或修补。
11.如果一个变更与同一个文件的另一个变更相矛盾,这被称为“冲突”。在继续之前,用户必须"解决冲突。
任何好的版本控制系统都应该提供以下特性:
1.备份和恢复
2.跟踪更改
3.分支
4.合并
现在让我们讨论一个 VCS 系统— GIT
GIT 是一个非常流行的版本控制系统,由 Linus Torvalds 于 2005 年创建。它的免费开源软件具有分布式架构。分布式体系结构意味着每个对存储库做出贡献的人在他自己的机器上都有一个存储库的副本。这使得操作非常快。
您可以从下面的链接下载 GIT:
https://git-scm.com/downloads
注意,URL 中的“SCM”代表源代码管理。这只是源代码文件的“版本控制”的另一种说法。
在查看基本的 GIT 功能之前,请记住任何版本控制系统(如 GIT)的目的都是为了跟踪以下关于文件的信息:
有哪些改变?
谁进行了更改?
什么时候做的改动?
基本 GIT 命令和函数:
一旦安装了 GIT,第一个任务就是创建一个新的存储库,这样 GIT 就可以开始跟踪您的文件。首先,您需要向 GIT 提供基本的配置信息,比如您是谁。这可以在 GIT 中实现,如下所示:
添加配置信息— GIT 配置

上面命令中的“— global”意味着我们将对所有将要使用的存储库使用 user.email 和 user.name 的给定值。
创建新的存储库
下一步是创建新的存储库。为此,我们可以创建一个新文件夹,并使用**“GIT init”**命令在其中创建一个 GIT 存储库。

first_repo 是一个文件夹,我们在它下面创建了一个新的存储库。请记住,存储库是我们保存所有希望 GIT 跟踪的文件的地方。
init 命令在文件夹“first_repo”下创建一个空的 git 存储库。如果我们检查 first_repo 文件夹的内容,我们会看到一个目录”。饭桶"

这被称为 Git 目录。它是存储更改和保存更改历史的数据库。里面有一堆文件和目录”。饭桶"

这些目录和文件不应该被直接接触或操作。每当克隆一个存储库时,它都是这样的。git”目录。
git 目录之外的区域称为“工作树”。它是保存当前或新文件的地方。您必须使用“git add”命令开始跟踪一个新文件。
添加新文件到轨道
目前,我们的工作树或工作目录是空的。我们将复制一个希望 GIT 跟踪的文件“expenses.xlsx”。

该 excel 文件的内容如下:

我们现在在工作树中有一个文件。我们将使用**“git add”**命令要求 GIT 开始跟踪它。

“git add”命令将文件添加到一个叫做**“staging area”的地方。Staging Area(也称为 index)是一个由 GIT 维护的文件,它包含关于哪些文件和哪些更改将被“提交”**的信息。这是一个非常重要的概念。GIT 中的文件可以处于以下 3 种状态中的任何一种:
“已修改” —表示文件已被修改,但尚未提交。
【暂存】 —表示文件已经添加到暂存区。它将被提交。
【已提交】 —表示文件已经存储在 GIT 数据库中。
因此,一个基本的 GIT 工作流由 3 个部分组成:

第一步:在工作树中修改文件
步骤 2:您存放那些您希望成为下一次提交的一部分的文件(或更改)
步骤 3:执行一个提交,从 Staging Area 获取文件,并将它们永久存储在 Git 存储库中。
您可以通过**“git status”**命令来检查您的更改的状态
检查文件状态
**“git 状态”**用于检查文件的当前状态

显示我们的文件“expenses.xlsx”是标记为待提交。为了提交它,我们将运行**“git commit”**命令。
提交对回购的变更
“git commit”—运行该命令时,GIT 会打开一个文本编辑器,我们可以在其中输入提交消息。在 GIT 软件的安装过程中,您将选择希望 GIT 使用哪个编辑器作为默认编辑器。我选择了 Notepad++因此它是默认打开的。

我在上面加了一行“增加费用…”
在保存消息时,我们的文件被提交到存储库。

我们刚刚提交了 GIT 中的第一个文件!!
在 GIT 中跟踪文件
您可以将 GIT 视为您的项目的表示。项目不过是一些文件(源代码文件、配置文件、图像文件、数据文件等)的集合。每次我们提交时,GIT 会在那个时间点获取项目(即所有文件)的快照。因此,每当您修改任何文件、暂存它们并提交时,GIT 都会拍摄快照。如果你看这些快照,你会看到你项目的历史。
因此,让我们通过运行 git status 命令来查看我们项目的状态:

这表明没有需要提交的更改,工作树是干净的。让我们修改我们的文件并做一些更改。
我只是添加了一个费用项“西红柿”并保存了文件。

让我们再次运行 git status 命令。

现在,它清楚地告诉我们 expenses.xlsx 已经被修改,并且存在“未提交的更改”
让我们运行“git add”命令来准备更改。

这将我们的文件标记为在下一次提交时提交。
这次,我们将使用一个参数来传递提交消息,如下所示:

我们可以通过发出“git log”命令来检查提交日志。

结果清楚地显示出做了什么更改,由谁做的,以及在什么时间做的。“头->主”表示这是主分支。它是指向项目当前分支的指针。
40 个字符的字母数字字符串-“b 3c 9 b 9 af 054 f 02 f 09968 beb 8 c 6 f 54 DC 9 eba6b 659”是文件内容的哈希值或校验和。GIT 通过这样的哈希值存储每个文件。
撤销更改
可能有这样的情况,我们对一个文件做了一些更改,但是我们想在提交之前撤销它们。我在 expenses.xlsx 文件中增加了一行。

如果我们现在检查 git 状态,它将显示文件已被修改,但更改尚未提交。

假设我们想要“撤销”这些更改。为此,我们可以使用**“git check out”**命令从 git 存储库中“检出”最后提交的快照。

它将恢复我们所做的更改。如果我打开 expenses.xlsx 文件,它将显示以下内容:

如果,你已经上演了的变化。你能恢复它们吗?是的。我们可以使用**“git reset”**命令来恢复已经暂存的变更。
如果您已经提交了更改,那该怎么办。你能恢复它们吗?是的。我们可以使用**“git revert”**命令来恢复已经提交的更改。
分支和合并
在一个多个人一起工作的项目中,一个人想要做一些变更,而同时另一个人想要做一些其他的变更,这是很常见的。在这种情况下,这些人可以制作项目的单独副本。每个人都可以在他们自己的副本(或者分支)上工作,最后应该有一种方法来合并和提交这些个人对主项目所做的变更。
所以当一个新的存储库被创建时,这个默认的分支被称为**“master”。**当我们提交“expenses.xlsx”文件时,我们是在主分支中完成的。
假设我们有另一个人也记下了费用。为了测试 GIT 的分支特性,我们可以为这个额外的人创建一个新的分支。
**【git 分支】**用于显示当前所有分支。

目前,除了主服务器,我们没有任何其他分支。我们可以创建一个名为“new_expenses”的新分支。

现在,这个新人可以通过使用“git checkout”命令切换到“new-expenses”分支。

注意,星号(*)现在出现在 new-expenses 分支的前面。
我创建了一个新文件“expenses2.xlsx”。让我们将它添加到存储库中。


让我们使用“git log”检查日志

请注意,现在标题指向新费用分支。
现在,让我们将这个新分支与 master 合并。为此,您需要切换回主分支并使用**“git merge”**命令


开源代码库
Github 是一个基于网络的存储库托管服务。因此,我们不用创建自己的 GIT 服务器,而是可以使用这个服务来共享和访问 web 上的存储库。我们团队的其他用户可以复制和克隆它们,并根据需要合并更改。 GitLab 和 BitBucket 是其他类似的基于 web 的存储库托管服务。
所以基本上,Github 提供了一个免费的 GIT 服务器。你可以在上面托管你的库,但是你可以托管的免费私有库的贡献者数量是有限制的。您可以随时支付月费,以获得 Github 私人服务器访问的无限制权限。
在 GitHub 上创建一个存储库非常简单。你应该有一个 https://github.com/的账户
一旦创建了一个帐户,就可以从 GITHUB 本身的用户界面创建一个新的存储库开始。

您可以使用**“git clone”**命令将 GitHub 库克隆到您的本地机器上。您必须为这个命令提供您的 GitHub 用户名和密码,它会将一个存储库副本下载到您的本地机器上。
版本控制系统是任何软件开发工作的核心。每个在软件行业工作的人都应该对这些系统如何运行有一些工作知识。本文的目的是给读者一个关于版本控制系统(特别是 GIT)的开端。在下一篇文章中,我将围绕冲突解决和托管服务(如 Github)讨论更多细节。
成为自然语言处理专家的学习之路
原文:https://towardsdatascience.com/a-learning-path-to-becoming-a-natural-language-processing-expert-725dc67328c4?source=collection_archive---------13-----------------------
自然语言处理的 6 个步骤

艾蒂安·吉拉尔代在 Unsplash 上拍摄的照片
像任何其他数据科学分支一样,在线有成千上万的自然语言处理学习材料。此外,像任何其他分支一样,这些材料的大部分针对该领域的具体概念,而不是更大的图片。
这些教程是必不可少的,因为你知道你想学什么,你应该按照什么顺序学习。当你是这个领域的新手,不知道从哪里开始到达你想要的终点时,问题就出现了。
当你想学习新的东西时,你的第一个合乎逻辑的步骤将是查找路线图或有组织的教学大纲,以正确的顺序获得所有你需要的知识。通常,找到一个简单、精确、可操作的路线图并不是一件容易的事情。这本身就是一个需要导航的学习之旅。
</10-nlp-terms-every-data-scientist-should-know-43d3291643c0>
相对于深度教程的数量,一般的视野更广,可以遵循的步骤也不多。这就是为什么我决定写这篇文章,也许是为了帮助你更全面地了解你需要谈论哪些步骤,需要涵盖哪些材料,以及需要获得哪些知识才能被认为是自然语言处理专家。
为了使本文具有包容性,它包括了学习自然语言处理需要解决的 6 个方面;你可能已经熟悉了其中的一些概念;在这种情况下,您可以直接跳到下一步。
第一步:编程
我当时真的很犹豫要不要把编程作为第二个的第一步。最终,我决定把它放在第一位,因为这样你就可以用编程来应用你以后会学到的数学和统计学。
如果你想进入任何技术领域,编程是一项必不可少的技能。编程是这些技能中容易开始学习的一种,但是事情很快就变得复杂了。根据你学习编程的目的,你可以决定在继续学习另一种技能之前你应该走多远。
为了能够使用编程来实现任何自然语言处理应用程序,您需要——至少——掌握任何编程语言的编程基础知识。
幸运的是,有大量的资源可以用来免费学习编程,比如 CodeAcademy 、 edX 和 Coursera 。
第二步:数学、统计和概率
数学和统计学是任何数据科学的重要组成部分,自然语言处理也不例外。数学本身就是一个广阔的领域,那么数学的哪些方面在自然语言处理中发挥作用呢?
为了理解自然语言处理算法,你需要熟悉数学和统计学的四个主要方面。这四个方面是线性代数、概率论、微积分和统计学基础。
从这些方面入手的一个好方法是阅读概念摘要,然后根据需要深入研究每一个方面。下面是我对线性代数、微积分、统计、概率论的一些喜欢的总结。
步骤 3:文本预处理
一旦你掌握了数学和编程基础,你就可以开始学习自然语言处理的基础知识了。任何自然语言处理项目的第一步都是文本预处理。
文本处理是一个总称,用来描述一组可以对文本执行的过程,以便为进一步的分析做准备。更准确地说,文本预处理涵盖了词干、词汇化、标记化、停用词移除和词典等概念。
这些基本的文本预处理技术非常简单,并且经常在 Python 或其他编程语言的大多数自然语言处理包中预先实现。所以,你需要做的是理解这些技术的基础以及它们是如何工作的。
理解这些概念基础的一个很好的资源是麻省理工学院关于文本分析的开放课件。
</6-nlp-techniques-every-data-scientist-should-know-7cdea012e5c3>
步骤 4:机器学习基础
机器学习对于大多数数据科学项目都很重要。如果你在更深入地研究自然语言处理之前理解机器学习的基础知识,这将会有很大的不同。
大多数自然语言处理算法依赖于各种机器学习概念。要完全理解这些算法,您需要熟悉不同类型的机器学习算法,如监督学习、非监督学习和转移学习。
学习机器学习基础知识的一个有用资源是麻省理工机器学习课程或 CodeAcademy 提供的这门课程。
</5-types-of-machine-learning-algorithms-you-need-to-know-5ac7fce8920d>
步骤 5: NLP 核心技术
文本预处理技术用于清理和准备文本,以供核心 NLP 技术进一步分析。这些技术旨在执行特定的任务并从文本中提取信息。
NLP 技术包括应用语言模型、分类文本、构建序列模型、解析文本以提取句法表示以及执行一些机器翻译。有助于简化这一过程的一个步骤是,通过将文本与整数向量进行匹配,对文本进行单词嵌入,从而更容易应用机器学习算法。
学习所有这些技术的一个很好的资源是华盛顿大学提供的关于自然语言处理的课程。
第六步:未来的自然语言处理
我不能告诉你,如果你已经经历了之前的所有步骤,就这样,你已经完成了学习所有你需要知道的自然语言处理。你将有足够的知识来建立项目和申请工作。
但是,自然语言处理是一个正在发展的领域;每天都有新的算法和技术出现。作为一名自然语言处理专家,你需要跟上该领域的最新进展,包括技术方面和学术方面。
订阅一本自然语言处理杂志或者关注科技新闻网站,比如 InfoQ。
外卖食品
开始一个新的领域总是一个挑战,但当你有一个清晰可行的路线图,可以遵循它来实现你的目标时,这个挑战会变得容易一些。
自然语言处理是数据科学的一个分支;它是一个分支,致力于使计算机能够理解和使用人类语言与我们交流,或者只是理解我们正在谈论的东西。在过去的几年里,技术的进步使得各种自然语言处理技术得到了有效的实现和广泛的应用。
</7-tips-for-data-science-newbies-d95d979add54>
在本文中,我向您展示了一个简单、清晰的路线图,帮助您获得学习自然语言处理所需的知识并找到一份工作。本文中的步骤是包容性的,所以我从头开始。如果你已经完成了一些步骤,那么你可以继续下一步。
这些步骤也不一定意味着要连续学习;如果你愿意,你可以平行地学习它们,只是遵循让你舒服的东西,坚持下去,不要放弃。这是成功的唯一可靠的方法。
DAX 优化的一个小挑战
原文:https://towardsdatascience.com/a-little-distinct-challenge-with-dax-optimisation-16c557cc5ed3?source=collection_archive---------22-----------------------
我的一个客户问我如何最好地清点他所有的订单。在 DAX 中,这看起来是一个简单的任务,但要以最佳方式回答这个问题,它还存在一些小障碍。

由克莱顿·罗宾斯在 Unsplash 上拍摄的照片
使用的数据集和场景
在本文中,我使用了微软的 Contoso 数据集。你可以在这里找到:面向零售业的微软 Contoso BI 演示数据集。请注意,此数据集需要一个 SQL Server 实例,因为下载的文件是 SQL Server 数据库备份文件。
因为原始文件“只”包含在线销售表中的 1200 万行,并且我希望有尽可能多的测试数据,所以我在这个表中又生成了 5100 万行,总共 6300 万行。零售表现在包含 1550 万行,而不是 340 万行。
我将这些数据加载到 Power BI 文件中,该文件现在有 1.45 GB,而不是原始数据集中的 210 MB。
我使用 DAX Studio 来衡量不同变体的性能。
当我们查看在线销售表时,我们会注意到
- 该表包含 SaleOrderNumber 列
- 每个 SaleOrderNumber 都存在多次
- 每一行都有一个 SalesOrderLineNumber,每个订单编号从 1 开始。

图 1:每个订单的订单编号和行号
我的客户的问题是,“我如何最有效地计算我的订单?”。
第一次接近
满足要求的最直接的方法是 DISTINCTCOUNT(“在线销售”[销售订单号])。
但是我已经体验了 DISTINCTCOUNT()的一些性能问题,并且想尝试一些不同的东西并比较性能。您可以在 SQLBI 文章分析 DAX 中 DISTINCTCOUNT 的性能中了解 DISTINCTCOUNT()可能存在的问题。
所以我尝试了以下方法:
我使用以下表达式向在线销售表中添加了一个计算列:
[First Order Line Counter] = IF(‘Online Sales’[Sales Order Line Number] = 1, 1, 0)
为了测试结果,我执行了以下查询:
DEFINE
MEASURE ‘All Measures’[Distinct Order Count] =
DISTINCTCOUNT(‘Online Sales’[Sales Order Number])
MEASURE ‘All Measures’[Sum First Line Counter] =
SUM(‘Online Sales’[First Order Line Counter])
EVALUATE
SUMMARIZECOLUMNS(
‘Date’[Year]
,”Distinct Order Count”, ‘All Measures’[Distinct Order Count]
,”First Order Line Count”, ‘All Measures’[Sum First Line Counter]
)
两种测量的结果是相同的。
但是,一旦您开始按其他属性(例如,按品牌名称)对结果进行分割,情况就会发生变化:
DEFINE
MEASURE ‘All Measures’[Distinct Order Count] =
DISTINCTCOUNT(‘Online Sales’[Sales Order Number])
MEASURE ‘All Measures’[Sum First Line Counter] =
SUM(‘Online Sales’[First Order Line Counter])
EVALUATE
SUMMARIZECOLUMNS(
‘Date’[Year]
,**’Product’[BrandName]**
,”Distinct Order Count”, ‘All Measures’[Distinct Order Count]
,”First Order Line Count”, ‘All Measures’[Sum First Line Counter]
)
结果不再一样了:

图 DISTINCTCOUNT()与一阶行总和的结果
大多数行都有一个[销售订单行号],它不同于 1。因此,所有这些行的[第一级行计数器]都为 0。
使用计算列的方法在这种情况下不可用。尽管如此,我通常在每一行中添加一个计数器列 1 来简化计算(SUM()而不是 COUNTROWS())。
第二种方法
第二种方法是使用以下衡量标准:
‘All Measures’[Order Count] =
COUNTROWS(
SUMMARIZE(
‘Online Sales’
,’Online Sales’[Sales Order Number]
)
)
您可以使用 VALUES(' Online Sales '[SalesOrderNumber])或 DISTINCT(' Online Sales '[SalesOrderNumber]),而不是 SUMMARIZE()。但是这三种解决方案在性能上几乎没有区别。不过,如果您注意到 VALUES()和 DISTINCT()之间与可能的空值相关的不同行为,这将会有所帮助(详细信息请参见此处:DAX(SQLBI)中的空行)。
我用我的测试模型测试了这两种变体,我得到了几乎相同的性能:

图 3:不同计数度量
两者都很快,查询几乎完全由存储引擎完成。所有三种变体都返回相同的结果。

图 4:比较基本度量
稍后,我将解释为什么存储引擎而不是公式引擎完成查询很重要。
此时,我本可以去找我的客户,告诉他我的发现:“没关系。你想用什么方法都可以”。
但是我知道他有一些依赖于 DISTINCTCOUNT()模式的复杂计算。所以我也需要测试这些模式。
其中之一是使用 LASTNONBLANK()函数对特定列使用 DISTINCTCOUNT()来计算库存项目。
高级图案
为了使用相同数量的数据,我创建了一个度量来计算特定时间段内最后一天的订单数。
我从 DISTINCTCOUNT()函数开始获取基线:
‘All Measures’[Count Last Day Sales] =
VAR LastSaleDate = LASTNONBLANK(‘Date’[Date]
,DISTINCTCOUNT(‘Online Sales’[SalesOrderNumber])
)
RETURN
CALCULATE(
DISTINCTCOUNT(‘Online Sales’[SalesOrderNumber])
,LastSaleDate
)
我用这个测度查询数据,得到了这个结果:

图 5:统计最后一天的销售额
在这个测试之后,我将上述第二种方法应用于这个度量:
‘All Measures’[Count Last Day Sales 2] =
VAR LastSaleDate = LASTNONBLANK(‘Date’[Date]
,COUNT(‘Online Sales’[SalesOrderNumber])
)
RETURN
CALCULATE(
COUNTROWS(
SUMMARIZE(
‘Online Sales’
,’Online Sales’[SalesOrderNumber]
)
)
,LastSaleDate
)
表现明显不同:

图 6:统计最后一天的销售额 2
可以看到,总时间几乎少了一秒。
更重要的是,与 DISTINCTCOUNT()一样,存储引擎的使用增加了约 5%。
为什么这如此重要:
两个因素使得存储引擎的使用优于公式引擎:
- 存储引擎是多线程的,而公式引擎只是单线程的。
- 存储引擎有缓存,而公式引擎没有任何缓存。
第一个因素使存储引擎更快、更高效。第二个因素使使用更多存储引擎的 measures 更具可伸缩性。这意味着当几个用户都在使用一个带有这个度量的报表时,存储引擎会使用他的缓存,性能会更好。
这个话题在这里详细讲解:DAX(SQLBI)中的公式引擎和存储引擎
真实世界基准
正如 SQLBI 的家伙们总是指出的,理解理论是必不可少的,但更重要的是在具体情况下测试这些知识。
所以我在 DAX Studio 中执行了一个基准测试。结果令人惊讶:

图 7:使用 DISTINCTCOUNT()的基准测试结果
现在,将基准测试结果与使用 SUMMARIZE()的度量进行比较:

图 8:使用 SUMMARIZE()的基准测试结果
当您使用热缓存查看结果时,这个结果令人惊讶。
使用冷缓存时,使用 SUMMARIZE()的测量总是更快。但是一旦我们使用了缓存,DISTINCT()的度量就变得更快了。
当查询执行多次时,使用较少存储引擎的度量执行得更好。这个结果出乎意料,需要更多的分析。
当您并排查看执行计划时,可以找到导致这一结果的原因:

图 9:用缓存计算最后一天的销售额

图 10:用缓存计算最后一天销售额 2
当您比较前两行时,您会看到显著的差异。
使用 DISTINCTCOUNT()的度量生成 4'290 和 6'575 个中间行,而使用 SUMMARIZE()的度量生成 8'536 和 6'575 个中间行。
以下步骤使用较少的行以及 DISTINCTCOUNT()度量值。
这就是使用缓存时 DISTINCTCOUNT()的度量更快的原因。缓存中存储的数据较少,因此要检索的数据也较少。
结论
我给你的主要信息是:不要把任何建议视为理所当然。您的情况总是独一无二的,它会改变应用于您的代码的任何优化的结果。
您需要很好地理解这两个引擎是如何工作的,以及如何使用可用的工具来获得尽可能多的知识。
当您测试代码时,在有缓存和没有缓存的情况下执行查询。为此,您可以使用 DAX Studio 中的“清除缓存然后运行”功能:

图 11:DAX Studio 中的运行选项
将你的专业知识应用到你的具体情况中,不要因为你在网上读过一些东西就认为任何事情都是理所当然的。
考虑现有的用例,以及用户将如何查询数据。使用这些知识来执行有意义的基准测试,并进行有价值的测量。
记录所有的步骤,代码的变更和每次变更后的度量。
对于我的测试,我使用下面的 DAX 查询和所有不同度量的定义来执行测试:
DEFINE
MEASURE ‘All Measures’[Distinct Count] =
DISTINCTCOUNT(‘Online Sales’[SalesOrderNumber])
MEASURE ‘All Measures’[Order Count] =
COUNTROWS(
SUMMARIZE(
‘Online Sales’
,’Online Sales’[SalesOrderNumber]
)
)
MEASURE ‘All Measures’[Order Count D] =
COUNTROWS(
DISTINCT( ‘Online Sales’[SalesOrderNumber] )
)
MEASURE ‘All Measures’[Order Count V] =
COUNTROWS(
VALUES( ‘Online Sales’[SalesOrderNumber] )
)
MEASURE ‘All Measures’[Sum Main Row] =
SUM(‘Online Sales’[First Order Line Count])
MEASURE ‘All Measures’[Sum Sales Line] =
SUM(‘Online Sales’[Sale Line Counter])
MEASURE ‘All Measures’[Sales Last Date] =
VAR LastSaleDate = LASTNONBLANK(‘Date’[Date]
,COUNT(‘Online Sales’[SalesOrderNumber])
)
RETURN
LastSaleDate
MEASURE ‘All Measures’[Count Last Day Sales] =
VAR LastSaleDate = LASTNONBLANK(‘Date’[Date]
,DISTINCTCOUNT(‘Online Sales’[SalesOrderNumber])
)
RETURN
CALCULATE(
DISTINCTCOUNT(‘Online Sales’[SalesOrderNumber])
,LastSaleDate
)
MEASURE ‘All Measures’[Count Last Day Sales 2] =
VAR LastSaleDate = LASTNONBLANK(‘Date’[Date]
,COUNT(‘Online Sales’[SalesOrderNumber])
)
RETURN
CALCULATE(
COUNTROWS(
SUMMARIZE(
‘Online Sales’
,’Online Sales’[SalesOrderNumber]
)
)
*// Alternative to SUMMARIZE is:
// VALUES(‘Online Sales’[SalesOrderNumber]
// )
// )*
,LastSaleDate
)
*//EVALUATE
// SUMMARIZECOLUMNS(
// ‘Date’[Year]
// ,’Customer’[CompanyName]
// ,”Distinct Count”, ‘All Measures’[Distinct Count]
// ,”Sum First order Line”, ‘All Measures’[Sum Main Row]
// ,”Sum Line Counter”, ‘All Measures’[Sum Sales Line]
// ,”Order Count Adv.”, ‘All Measures’[Order Count]
// ,”Distinct Count”, ‘All Measures’[Distinct Count]
// ,”Distinct Count D”, ‘All Measures’[Order Count D]
// ,”Distinct Count V”, ‘All Measures’[Order Count V]
// )*
EVALUATE
SUMMARIZECOLUMNS(
‘Date’[Year]
,’Customer’[CompanyName]
*// ,”Distinct Count”, ‘All Measures’[Distinct Count]
// ,”Sum First order Line”, ‘All Measures’[Sum Main Row]
// ,”Sum Line Counter”, ‘All Measures’[Sum Sales Line]
// ,”Order Count Adv.”, ‘All Measures’[Order Count]
// ,”Sales Last Date”, ‘All Measures’[Sales Last Date]*
,”Count Last Sales”, ‘All Measures’[Count Last Day Sales]
* // ,”Count Last Sales 2", ‘All Measures’[Count Last Day Sales 2]*
)
我取消了想要测试或比较的部分的注释,并直接在脚本中更改了度量。
最后:当你试图找到最佳解决方案时,运用你的常识选择正确的方法。
BTW:您可以将本文中的所有内容应用到 Power BI 和分析服务中。
层次聚类中一个鲜为人知的技巧:权重
原文:https://towardsdatascience.com/a-little-known-trick-in-hierarchical-clustering-weights-762156a2fce0?source=collection_archive---------17-----------------------
重新校准你的数据集来回答一个商业问题
休伊·费恩·泰
和格雷格·佩奇一起

上图:照片由 马克·柯尼希 上图 Unsplash
当数据被分成有意义的组时,营销分析师可以看到消费者行为的模式,并为公司创造有针对性的促销活动奠定基础。但是集群应用不仅仅局限于营销场景。例如,研究基因测序的科学家可以使用聚类分析来分析一个群体中序列之间的进化关系;房地产分析师可以使用这种技术来了解某些类型的房地产相对于该地区类似的房地产应该如何定价。
在本文中,我将演示如何使用一种流行的细分方法——层次聚类来创建客户角色。除此之外,我将说明如何使用权重来重新校准数据集,以反映您当前的业务优先级。
我的数据集?虚构的,可爱的缅因州游乐园:龙虾王国。
想象一下这个场景:随着美国许多地区疫苗接种率的上升,龙虾之乡在因新冠肺炎疫情而暂停业务后,希望赢回客户。公园的管理层如何瞄准他们的顾客?
第一步:丢失分类变量
第一步是删除分类变量*“户主”和“家庭状态”。* 户主只是一个唯一的标识,任意分配给数据集中的每一户。由于*‘homestate’*是绝对的,因此它不适合在此模型中使用,该模型将基于欧几里德距离。
pandas 的 drop()函数将帮助我们实现这一点:
第二步:将数据标准化
我们的数据集包含以不同单位和完全不同的尺度衡量的变量。例如,我们的家庭年收入从 16000 美元到 213000 美元不等,而每个家庭的平均电子邮件打开率从 11%到 34%不等。
如果我们不把这些数据放在一个“公平的竞争环境”中,我们的聚类模型就会因为家庭收入而相形见绌,因为这些数字更大。我们需要以这样一种方式转换数据,使得变量之间可以直接比较。将这些数字改为 z 分数,每个分数的平均值为 0,标准差为 1,就可以达到这个目的。
步骤 3:绘制树状图,决定聚类数,并创建聚类
树状图将记录放在一个轴上,将距离放在另一个轴上,使分析人员能够看到嵌套聚类模型的形成方式。树状图有助于人们确定要构建多少个集群。但是,请记住,图表只是一个决策工具,对于“有多少个集群?”没有“正确”的答案问题,因为这是一个无人监督的学习过程。
经过一些迭代和实验后,我决定在 y=17 标记处切割树突,以生成具有五个不同聚类的模型。

下面的代码单元格包含设置距离阈值为 17 的聚集(自下而上)聚类模型的说明。
请注意,上面的结果是一系列数字,范围从 0 到 4,两端都有方括号。这些数字表明了我们每一次观察的聚类分配。我们需要将这些聚类分配转换到一个数据框中,这样我们就可以将这些数字附加到原始数据集的最后一列。这将使我们以后更容易比较集群。
第四步:给每个变量加上权重
到目前为止,聚类模型中的每个变量都是同等重要的——但是,这并不反映我们的业务优先级。为了对哪些顾客群体更容易被说服重返做出有根据的猜测,我们需要更加重视某些因素,如他们在 2019 年季节参观公园的次数。
带着这个目标,我对数据进行了重新加权:

这种重新加权是一个简单的过程。只需将每个变量的 z 分值乘以一个常数即可。使用这一过程的建模者可以容易地调整这些权重,以便试验不同的结果。
第五步:重新聚类数据
对变量应用不同的权重改变了一些家庭的分组方式。对' visits_2019' 的高度重视将我们大多数的常客家庭集中到了两个特定的群组(群组 3 和群组 4)。但是等等…还有更多。这只是已经发生的变化的一瞥。

步骤 6:检查加权数据引起的差异
当访问次数乘以 50 倍时,最频繁的访问者(和最不频繁的访问者)会更清楚地与群体中的其他人分开。大乘数放大了访问量的差异。
下表展示了这种差异。
在 ward_cluster1 模型(未加权)中,跨集群的平均访问范围略大于 7。我们可以看到两个频繁访问者聚类的平均值在 16 以上,而其他聚类的平均值在 10 左右徘徊。这些平均值的标准偏差为 3.33。
相比之下,使用加权聚类模型,聚类平均值的范围变得明显更大-对于 ward_cluster2 模型,类内平均值的范围跳到 12 以上。每个集群的平均访问量的标准偏差上升了近 44%,因为加权模型为我们带来了更高的高点和更低的低点,这是我们最感兴趣的变量。
步骤 7:可视化未加权和加权数据之间的差异
在我们对基于聚类的图表进行颜色编码之前,我们需要将它们转换成分类数据。
请注意,第二张密度图中的加权数据并未显示组间有太多重叠。在第二张图中,紫色组(聚类 4)中的“超级粉丝”与大部分数据集明显分开。这同样适用于代表“粉丝指数”下端的粉色组(聚类 3)。

上图:未加权数据集中‘visits _ 2019’的分布图。注意一些集群聚集在一起。

上图:加权数据集中“访问量 _2019”的分布图。请注意,集群之间的重叠较少,紫色集群中的超级粉丝更加明显。红色集群中的群体也很突出。
步骤 8:检查加权聚类以创建客户角色

到目前为止,我们的演示集中在权重最大的*‘visits _ 2019’*上,权重为 50%。虽然这些结果本身就能说明问题,但我们需要考虑权重对其余变量的影响,以便更清楚地了解龙虾之乡的客户群。
当我们查看所有变量的平均值时,我们会看到访客档案,这将有助于我们营销部门的员工开展有针对性的活动。以下是这个模型在龙虾王国的游客中识别出的群体的真相:
**死忠粉丝:**这些家庭都是龙虾地的宠儿。尽管平均每个家庭都住在离龙虾产地 85.73 英里(约 137.8 公里)的地方,但他们并不介意“徒步”去公园。2019 年,这些超级家庭平均参观公园 18.03 次。他们是网上商品的最大消费者,也最有可能打开我们的营销邮件。
**套现粉丝:**团里最有钱的。他们也是龙虾之地的坚定支持者,整个 2019 赛季平均有近 13 次访问。
**购物狂忠实者:**这些顾客对龙虾王国的奉献精神应该受到表扬,因为尽管他们住的离公园最远,但他们在这个季节平均会去 15 次以上。这组家庭的平均年收入位居第二。他们是以网上商品消费高而闻名的两个集群之一,他们的电子邮件打开率在所有集群中排名第二。
**中等粉丝:**这个群体的平均访问次数在五个集群中倒数第二。
**远方的仰慕者:**这群家庭大概是最难说服回来的。即使他们很可能会打开营销邮件,但他们在 2019 年只访问了公园 5.69 次。这些家庭在支出方面也相对克制。
这对龙虾之乡意味着什么:
龙虾土地管理公司应该为培养了与家庭的紧密联系而感到自豪。在新冠肺炎疫情之前,普通家庭每个月都会去公园,尽管公园至少有 84.47 英里(约 135.94 公里)远——不完全是在大多数人居住的拐角处。
现在疫苗接种率已经上升,好消息是说服人们重游龙虾之地应该不是很困难,因为人们显然对这个公园有着深厚的感情。
*“铁杆粉丝”*最容易被打动,应该是营销部门的第一批目标家庭。这些家庭最有可能打开营销电子邮件,具有强大的购买力,并且显然喜欢龙虾之乡的体验,因此他们最容易出于任何目的而推动营销漏斗:公园一日游、最新的拉里龙虾毛绒玩具、居家度假、生日派对——只要你能想到的。
*【套现粉丝】*也是狂热粉丝,不需要太多说服就能回来。他们可能会被像居家度假这样的活动所吸引,在龙虾之乡花大钱,因为他们的家庭年收入估计是平均最高的。
如前所述,最难说服的是*‘远方的崇拜者’*。
结论:
缅因州这种地方的主题公园,每年只有三个月的时间赚钱,才会变得太冷。考虑到短暂的机会,这些企业必须进行高度集中的营销,以确保今年的收入最大化。与此同时,主题公园需要通过创造新的游乐设施和体验来确保与观众保持联系。
上面展示的重新平衡的例子仅仅是让人们在新冠肺炎混乱之后回到公园的第一步。为了抓住消费者的脉搏,龙虾土地管理需要定期评估市场状况和消费者情绪。他们可以与他们的“超级粉丝”进行焦点小组讨论,以测试新景点的想法,并分析他们的整体营销组合,以确定他们的钱是否得到了最大的回报。此外,A/B 测试也可以应用到电子邮件简讯中,看看哪种类型的内容更适合作为“诱饵”。
无论哪种方式,跟踪、测试和迭代都是为子孙后代维持龙虾土地未来的必备条件。
数据创建者:
波士顿大学高级讲师 Gregory Page 教授
数据来源:
页,格雷戈里。(2021).龙虾地往届通行证持有者[复出. csv]。检索自https://drive . Google . com/file/d/13 bescseg 95 xluosfbj-h 191 ozzbgf 49h/view?usp =共享
许可证:CC0
采用英特尔神经计算棒和 RaspberryPi 的实时人工智能网络服务器
原文:https://towardsdatascience.com/a-live-ai-web-server-with-intel-ncs-and-a-raspberrypi-9831dce859e6?source=collection_archive---------42-----------------------

迈克尔·泽兹奇在 Unsplash 上的照片
人工智能的应用是无穷无尽的。我收集了一个 RaspberryPi4 和一个英特尔神经计算棒和它们一起玩。树莓是一台具有无限能力的车载计算机,但它还不足以运行复杂的神经网络。NCS 带来了新的可能性。当连接在一起时,它们是一个强大的工具,能够以小尺寸和低能耗加载复杂神经网络 架构。
我将它们组合在一起,构建了一个人工智能支持的网络服务器。任何连接到家庭网络的设备都可以通过网络摄像头观看直播,并根据显示的图像进行智能预测。
设置
给定一个网络摄像头、一个 RaspberryPi 和一个 NCS,它们可以组装在一起,构建一个集成了人工智能的网络服务器。硬件连接很简单,人们只需注意将 NCS 连接到 Raspberry 的 USB3.0 端口,即可获得更好的性能。

这个实验的设置:RaspberryPi4,Intel NCS2 和一个网络摄像头。是的,那是一个 Arduino,但这将是另一个故事。图片作者。
软件
这个项目由三个不同的部分组成,每个部分都有特定的工具。
- 我们需要使用网络摄像头捕捉图像。在这种情况下, OpenCV 会很有用;
- 当使用 OpenVINO 框架捕获图像时,会执行机器学习操作,以获得网络摄像头所看到内容的分类。
- 最后,使用瓶对图像和分类进行流式传输。
拍摄图像
使用 openCV 在 Python 中拍摄图像非常简单。
cap = cv2.VideoCapture(0) # open a connection to webcam
ret, frame = cap.read() # shot
人们必须创建一个与网络摄像头的连接,然后从其中读取数据。
机器学习
给定一张图像,棘手的部分,树莓必须请求神经计算棒来推断一个标签并返回结果。
NCS 可以加载预先训练好的模型,例如 inception-v4 网络。有重量的模型可以从 openVINO 网站获得。
而且 outpu 中每个类的标签都要下载:imagenet _ classe _ index . JSON
def load_model(self):
model_xml = self.model
model_bin = os.path.splitext(model_xml)[0] + ".bin"
# Plugin initialization for specified device
ie = IECore()
# Read IR
self.net = ie.read_network(model=model_xml, weights=model_bin)
assert len(self.net.inputs.keys()) == 1, "Sample supports only single input topologies"
assert len(self.net.outputs) == 1, "Sample supports only single output topologies"
self.input_blob = next(iter(self.net.inputs))
self.out_blob = next(iter(self.net.outputs))
self.net.batch_size = len(self.input)
# Loading model to the plugin
self.exec_net = ie.load_network(network=self.net, device_name=self.device)
#load classes
with open("/home/pi/inception/imagenet_class_index.json",'r') as file:
self.labels_map=json.load(file)
推断图像中的内容
一旦模型和标签被加载到神经计算棒设备中,并且图像被拍摄,就可以简单地推断它在网络摄像头前面是什么。
res = self.exec_net.infer(inputs={self.input_blob: images})
计算机网络服务器
因此,在这一点上,我们有一个图像和一个向量res,其中包含了网络摄像头正在查看的信息。
我们可以通过网络服务器传输这个。使用烧瓶很简单。
def generator():
global model
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
frame = model.process(frame)
encode_return_code, image_buffer = cv2.imencode('.jpg', frame)
io_buf = io.BytesIO(image_buffer)
yield (b'--frame\r\n'+
b'Content-Type: image/jpeg\r\n\r\n' + io_buf.read() + b'\r\n')
@app.route("/video")
def video():
return Response(generator(),mimetype='multipart/x-mixed-replace; boundary=frame')
此功能generator 连续产生个新帧,因此可以传输视频。
请注意frame = model.process_frame(frame),它将帧发送到计算棒,然后连同标签一起发送回来。
连接到新创建的服务器
使用网络中的任何设备,将浏览器指向http://raspberrypi . local我们可以看到整个系统的运行。

系统能正确识别瓶子。图片作者。
现在去月球
在这一点上,极限是天空。这可以用作家庭监视系统、机器人的眼睛、便携式物体识别器等等..
代码
想玩这个吗?代码在 https://github.com/fvalle1/ai_server[的 GitHub 上](https://github.com/fvalle1/ai_server)
模拟非线性动态系统的长短期记忆网络
原文:https://towardsdatascience.com/a-long-short-term-memory-network-to-model-nonlinear-dynamic-systems-72f703885818?source=collection_archive---------15-----------------------
基于 PyTorch based 的非线性动态系统建模
介绍
简而言之,动态系统是随着时间而发展的系统。随着时间的推移会发生什么变化?系统的状态。什么是状态?状态是描述系统的变量。例如,在天体运动的情况下,我们可以把当前的位置和速度看作状态。这些状态可以用来预测天体未来的位置。在这个例子中,天体的运动就是动力系统。
更正式地说,任何未来状态依赖于当前状态以及一组进化规则的系统都被称为动态系统。回到天体的例子,我们知道它的运动受万有引力定律的约束。
为了更好地理解这些系统并做出合理的预测,我们依靠数学方程来表示它们。在动态系统的情况下,我们使用常微分方程。简单地说,常微分方程是关于函数及其导数的方程。特别是,在动态系统中,我们处理关于时间的导数。单变量动态系统的一般形式可以表示为如下所示的 ODE。

有几种数值方法可用于求解常微分方程,如欧拉法、隐式欧拉法、龙格-库塔法等。那么,为什么我们需要另一种方法呢?我们为什么需要深度学习?虽然确实存在几种数值近似法来求解常微分方程,但是在实践中,对于高度非线性的系统,获得这些方程是相当复杂的。这是因为很难考虑影响系统的所有因素。例如,在天气预报的情况下,根本不可能知道影响天气预报的所有变量。因此,我们依靠数据来模拟这些系统。
在第一原理模型中,从质量平衡、能量平衡和动量平衡等物理守恒定律获得的一组数学方程用于表示系统。然而,在基于数据的模型(黑盒模型)中,我们试图从收集的数据中学习过程的行为。如下所示,我们不知道真正的潜在现象。因此,我们使用输入和输出数据来确定最能代表系统的模型。

图 1:基于数据的模型表示【来源】
在这篇文章中,我们将集中讨论长短期记忆(LSTM)网络来模拟非线性动态系统。对递归神经网络(RNN)和 LSTM 的基本理解将会有所帮助。为了更好地理解 RNN 和 LSTM 的工作方式,请参考下面这些精美的插图文章。
考虑中的动态系统
让我们考虑一个黑盒非线性过程。让我们将(x₁(k),x₂(k))定义为时间 k 时的状态,而(u₁(k),u₂(k))作为时间 k 时的输入,(x₁(k+1),x₂(k+1))是下一时间步的状态。

考虑中的非线性动力系统
假设非线性过程处于(x₁(k)、x₂(k 的当前状态,我们用输入信号(u₁(k)、u₂(k)).来激励该过程然后,我们测量输出并将其存储为(x₁(k+1),x₂(k+1),如上所示。我们重复这个实验几次,并记录我们的数据。我们的目标是使用这些数据来模拟底层流程。这种方法对于客户需要基于数据的模型的任何过程都是一样的。
为了公平对待我的化学工程学位,我将考虑一个非线性连续搅拌釜反应器(CSTR)作为我们的动力系统。对于那些了解 CSTR 的人来说,两个状态 x₁和 x₂分别是反应物的浓度(Cₐ)和反应器的温度(t),而两个输入 u₁和 u₂分别是入口浓度(Cₐ₀)和提供给反应器的热量(q)。如果您从未听说过这一点,请不要惊慌,这只是给系统一些背景。
数据生成
不幸的是,我的后院没有一个化学反应堆来进行这个实验(如果我有,那会很奇怪)。幸运的是,这样的系统可以用下面显示的一组 ode 精确地表示。

这些方程足以完整地描述基本过程。然而在实践中,数据会被测量噪声和不可测量的干扰所污染。因此,要为这个项目生成数据,我们可以使用上面显示的一组微分方程,并添加随机噪声来获得非常实用的数据。下面显示了前几个示例。

在实践中,通常数据是成批收集的。为了复制这一点,我收集了 15 批数据。在每一批中,我从不同的初始状态开始,用随机输入信号轰击它。批号 15 的示例图如下所示。

批号 15 的数据
由于所考虑的变量大小的差的数量级,在训练模型之前缩放这些数据是很重要的。
LSTM 网络

本项目使用的 LSTM 网络
**目的:**在 PyTorch 中建立一个 LSTM 网络来模拟上面讨论的非线性动态系统。
我们将使用两个隐藏层,分别有 15 个和 10 个 LSTM 单元。这个网络的输入是我的当前状态和输入信号,而网络的输出是系统的未来状态
我将解释这个过程,并提供一个代码供您在自己的系统中使用。
我已经将全部数据存储在数据帧中。让我们从定义批量大小来批量处理数据开始。我在每一批中收集了 101 个数据点。我用了 14 批数据来训练 LSTM 网络,用剩下的一批来测试模型。
我使用批号 5 作为测试集。我们正在确保数据点属于浮点类型,我正在分割训练集和测试集。
如前所述,缩放对于我们的数据至关重要。我们正在创建两个 MinMax scaler 对象,用于在-1 和 1 之间缩放数据,并将其脱机保存为 pickle 对象。
注意:为了避免任何形式的数据泄漏,测试集不包括在内以适应缩放参数。
然后,归一化的训练和测试集被转换成 torch 张量对象。我们必须以内置 PyTorch 模型能够理解的方式呈现数据。为此,我们定义了一个函数 input_data ,它接收数据和一个窗口大小,以返回输入和输出数据的时间序列。窗口大小是指未来预测的大小。在我们的例子中,我们只需要下一个即时输出。因此窗口大小为 1。

我的数据框的前几个样本
函数 input_data 接收上面显示的数据框以及窗口大小,并返回下面显示的张量对象列表。在列表的每个元素中,有一个大小为(4,2)的元组,分别具有到 LSTM 网络的输入和输出。这形成了我们的训练数据。

我训练数据的前几个样本
我们现在准备用两个隐藏层来定义 LSTM 模型。上面写的类 LSTMmodel 适用于任何输入大小、输出大小和隐藏层中的神经元。这个类中的 forward 函数接收数据序列并返回预测值。
我们现在关注手头的问题,定义一个 LSTMmodel ,其输入大小为 4,两个隐藏层分别具有 15 和 10 个神经元,输出大小为 2。我们还定义了一个均方差损失和 Adam 优化器。
这里使用的所有超参数都是通过交叉验证获得的。
这里,我们训练 100 个时期的模型,并打印每 10 个时期的训练损失。务必分批训练数据,这一点很重要。
我们现在准备对测试集(批号 5)进行预测。我们将模型设置为评估模式,并让 PyTorch 知道我们不再对渐变感兴趣。我们对测试集进行预测,并将其存储在 preds 中。

测试数据的预测值与真实值
瞧啊。上图显示了预测状态与状态真实值的比较。我们可以看到,该模型在测试数据上的性能非常好,RMSE 为 3.27 (1%)。
奖金
对于一些应用程序,有必要对不止一个一次性步骤进行预测。也就是说,我们可能有一个更长的预测范围。在这些情况下,我们可以调整代码以使用预测来进行进一步的预测,如下所示。
预计表现会略差。这是因为第一个时间步之后的预测严重依赖于第一个预测。如果第一次预测偏差很小,误差就会累积并发散,导致性能下降。改进该模型的一个方法是在头脑中训练多个未来预测。

可以看出预测值偏离了真实值
结论
我们总是会遇到非线性动态系统。为了做出预测或未来的预测,必须有一个好的模型来表示这些动态系统。有时很难将高度非线性的系统建模为显式的数学方程。因此,我们依赖于基于数据的模型或黑箱模型。在这篇文章中,我介绍了一种用 LSTM 建模非线性动态系统的方法。我在这里展示的代码非常灵活。请随意使用它们来解决您的问题。你可以在我的 GitHub repo 找到代码。
参考
- Heidarinejad,m .,J. Liu 和 P. D。2012."使用李亚普诺夫技术的非线性过程系统的经济模型预测控制."AIChE journal 58(3):855–870 . doi:10.1002/AIC . 12672 .https://AIChE . online library . Wiley . com/doi/ABS/10.1002/AIC . 12672
- 吴,陈哲,安和林孔,大卫和,帕纳吉奥蒂斯。(2019).基于机器学习的非线性过程预测控制。第一部分:理论。爱车杂志。65.10.1002/aic.16729
- https://www . udemy . com/course/py torch-for-deep-learning-with-python-boot camp/
美国 24 个城市夏季夜间低温一览
原文:https://towardsdatascience.com/a-look-at-summer-nighttime-low-temperatures-across-26-cities-in-the-us-9ea596c5f61f?source=collection_archive---------31-----------------------
在 R 中使用 ggplot 对过去 10 年进行了简明的可视化

美国宇航局在 Unsplash 拍摄的照片
夜间低温
《纽约时报》上周发表了一篇关于夜间低温增加的后果的文章。我也写过一些关于太平洋西北热浪期间夜间低温的想法。
为了进一步展开对话,我认为比较一下美国夏季夜间的低温可能会有所帮助。有许多不同的地区气候,我选择了美国相邻的 24 个城市进行比较,这些城市覆盖了许多气候区域。
如果你有兴趣学习更多关于美国天气数据源的知识,你可能会在我的关于天气数据民主化的教程中找到你想要的。
如果你想快速阅读一下 2021 年 6 月太平洋西北部的历史性热浪,你可能会喜欢这本书。
https://sabolch-horvat.medium.com/the-pacific-northwest-heat-wave-has-lows-that-are-just-as-shocking-as-the-highs-efab4500790f
24 个城市的比较
用于创建这些剧情的 R 脚本和数据,请看我的 GitHub 。如果你感兴趣的城市没有列在下面,希望这个 GitHub 和以前的天气文章足以让你自己重现这些情节。
图表用蓝色阴影显示了十年来的每日低温,以捕捉变化。10 年平均值用粗体橙色表示。尽情享受吧!

作者图片(博伊西,盐湖城)

作者图片(波士顿,纽约)

作者图片(克利夫兰,底特律)

作者图片(达拉斯,休斯顿)

作者图片(华盛顿 DC,夏洛特)

作者图片(丹佛,堪萨斯城)

作者图片(拉斯维加斯,凤凰城)

作者图片(孟菲斯,新奥尔良)

作者图片(迈阿密,亚特兰大)

作者图片(明尼阿波利斯,芝加哥)

作者图片(波特兰,西雅图)

作者图片(旧金山,洛杉矶)
结论
你觉得怎么样?就夏季夜间低温而言,你所在的地区与其他地区是否如你所想的一样相似或不同?请在评论中分享你的想法!
如果你喜欢这篇文章,并想阅读(和写)更多这样的文章,请考虑使用我的推荐链接成为中等会员:https://sabolch-horvat.medium.com/membership
看看贝叶斯键盘的内部
原文:https://towardsdatascience.com/a-look-inside-the-bayesian-keyboard-c10c53e6d5a?source=collection_archive---------16-----------------------
让现代智能手机键盘变得智能的数据驱动功能的视觉之旅

个性化的概率智能手机键盘,具有各种可视化功能:触摸分布、键区、不确定性/熵测量。(作者本人法师)
你输入的就是你得到的?没有现代触摸键盘。这篇文章直观地解释了 smarpthone 键盘的四个核心功能——包括个性化、自动纠错和单词预测。基于我为“智能用户界面”讲座创建的材料,我们检查了这些功能在我们日常打字中的内部工作,并以启发、评估和批判性反思数据驱动和“智能”用户界面的要点作为结论。
特点 1:调整关键领域
现代智能手机键盘对分配给每个按键的屏幕区域进行了个性化设置。这通常不会显示在图形用户界面中,以避免混淆和不良的共同适应——但我们可以在这里揭示它。
触摸数据
当用户打字时,键盘收集背景中的触摸位置(2D 点:x,y)。该图显示了几天来收集的两个人的触摸数据。

触摸两个用户的智能手机键盘。(作者本人法师)
触摸键盘模型
使用这些触摸,我们可以为每个用户创建个性化的按键:这些按键模型可以捕捉每个用户在键盘上的手指放置行为。例如,对 Anna 来说,字母“x”最好放在与 Bob 稍有不同的位置。

适用于两个用户的个性化键盘型号,安装在上图所示的触摸屏上。(我作者法师)
如图所示,我们为个性化键盘建模,每个键 k 具有正态分布 p(t|k) ,安装在该键的触摸位置上。形式上:

每个键 k 被建模为正态分布,以该键的平均触摸位置为中心。该图示出了“c”键的例子。(本人作者法师)
对于每个键 k ,模型因此存储对于该键观察到的触摸的平均位置*(x,y)* ,以及协方差矩阵(可以直观地认为其描述了键的大小和形状)。视觉上,圆圈显示了这些分布的两个和三个标准偏差。
我们在 3D 中也可以这样看:每个键都是一座“小山”,高度对应的是触摸可能性 p(t|k) 。图中显示了“c”键的示例。

“c”键触摸可能性的 3D 图。(我作者法师)
用户按了哪个键?解码触摸
这种键盘模型可以用来解码触摸。“解码”仅仅意味着计算出用户想要按哪个键。
结果显示在这些图中,其中颜色表示每个触摸位置(即像素)最可能的按键。我们已经推出了个性化键盘,根据每个用户的触摸行为进行像素到按键的分配。

两个用户的像素到按键分配,揭示了手指在按键上放置的差异,键盘可以解释这种个性化。(作者本人法师)
形式上,为了得到这些图,我们评估 p(k|t),,即,给定触摸位置 t 的按键 k 的可能性。键盘模型产生了 p(t|k) ,我们用贝叶斯法则将其翻转为 p(k|t) 。这产生了最可能的键k’:

注意事项:
p(k) 是按键 k 上的先验分布,描述了一般按键的可能性,不考虑触摸位置。简单的先验是一致的(即所有的关键字都有相同的可能性)。一个更好的先验使用语言环境,我们将在后面讨论。
p(t|k) 是假设键为 k 时触摸 t 的可能性。这就是上面描述的高斯关键模型。
不确定
既然这是一个概率模型,那么我们可以看看键盘的不确定性。后验 p(k|t) 的熵就是这样一种不确定性的度量。直觉上,如果许多按键 k 对于触摸位置 t 的可能性相等,则该值为高。相反,如果一个特定的键被认为是唯一可能的键,则它是低的。

键盘像素上模型后验的不确定性(熵)。(我作者法师)
上面的图显示了这种熵:不确定性在不同像素-键分配之间的“边界”处最高。这符合我们的直觉,即靠近按键边缘的触摸是“草率的”,或者换句话说,比击中按键死点的触摸更难以理解。
特点二:整合语言语境
这种个性化键盘可以通过整合语言环境来进一步改进。为了说明,我们在这里使用一个简单的二元语言模型。二元组是一对字母(例如“th”)。这很容易建立:简单地计算大量文本中的字母对,并计算它们的相对频率。
在形式上,这个二元模型语言模型是给定前一个键的下一个键的可能性。将此作为解码等式中的先验,我们得到:

我们可以通过比较前一个字母是“q”的例子和前一个字母是“t”的例子来检验语言模型的影响。考虑到英语中这些字母的常见配对,我们期望“u”在“q”之后获得屏幕空间,“h”在“t”之后获得屏幕空间。事实上,该图揭示了这一变化。

(简单)语言模型影响的例子:根据前一个字母是“q”还是“t”来改变按键分配。这些关键区域大小的变化符合我们的直觉,即英语中“q”后面经常跟着“u”,“t”后面经常跟着“h”。(作者本人法师)
为了进一步检验这一结果,我们接下来比较了两种语言环境下模型不确定性的差异。这显示了由于变化的上下文,每个像素的确定性的增益(或损失)。
对于我们从“q”切换到“t”的例子,如前一个字母,我们期望“u”周围的像素失去确定性,而“h”周围的像素获得确定性。这是因为:
- 许多字母很可能跟在“t”后面——这与“q”形成对比,因为“q”后面除了“u”之外很少跟别的字母。
- 反过来,“th”很常见,增加了模型在“t”之后“h”的确定性。
事实上,该图揭示了这种影响。

键盘不确定性(后验熵)的变化取决于前一个字母是“q”还是“t”。(我作者法师)
特点三:解码全词
到目前为止,我们一次解码一个触摸,这相当于关键区域个性化。打字由许多连续的触摸组成。因此,我们也可以研究如何将触摸序列解码成单词,包括语言环境。这可以用来实现“自动校正”。
推广到序列
我们现在寻求找到最可能的字母序列 s ,给定一个观察到的触摸位置序列 o 。那就是:

该等式与单次触摸的等式相同,并且原理保持不变。为了解码单词,我们只需要将其组成部分归纳为按键/触摸序列。为简单起见,假设 n 触摸长度为 n 的字 ( 即无遗漏或虚假触摸),这可以形式化为:

注意事项:
p(s) 是一个先于的字母序列。为了说明,我们重用我们的二元模型**。也就是说, n 个字母(例如一个单词)的序列的联合概率是其键到键转换(即二元模型)的产物。**
p(o|s) 是假设字母序列为 s 时,触摸观察值 o 的可能性。这里我们重用我们的高斯键模型,它为每次触摸产生 p(t|k) 。我们通过乘法在序列上将其聚合为联合概率。
用令牌传递算法寻找最可能的单词
尝试所有可能的字母序列 s 长度 n 以找到最有可能的一个是极其昂贵的(指数)。我们需要做出妥协。具体地说,这里我们使用一个带有波束修剪的令牌传递算法。
简而言之,该算法将一组部分序列作为“标记”来跟踪,这些部分序列可以被分割(即路径中的“分叉”:探索当前序列的多个延续)或被丢弃(即“死胡同”:由标记表示的序列变得太不可能)。
下面显示了一个具体的例子:一个用户想要输入“hello”(左图)。该算法在假设空间中探索了两条路径(右图):“hello”和“helli”。如线条粗细所示,“你好”的可能性较大;解码发现正确的单词是最可能的单词(红色路径)。

通过令牌传递解码预期输入“hello”的触摸序列(左图)。右边的图显示了算法通过假设空间的探索路径;从上到下阅读(垂直:触摸 1-5,水平:红色探索字母,线条粗细表示可能性,红色路径最有可能)。(作者本人法师)
波束搜索宽度
直观地说,波束宽度决定了我们希望允许多少探索。更多的探索可能会增加找到正确单词的机会,但也会增加计算时间。
通过比较不同波束宽度的探索假设,波束宽度的影响变得可见,如下所示:在右侧,算法另外探索了“jello”,然而它认为这比正确的“hello”更不可能(参见与“he”相比以“je”开始的更细的路径)。

增加波束宽度导致探索假设空间中的更多部分(这里将“jello”添加到候选单词列表中)。(作者本人法师)
插入和删除
令牌传递算法的扩展引入了插入(产生一个字母而不处理下一个触摸)和删除(处理下一个触摸而不产生字母)。这些解决了两个常见的用户错误:虚假(误)触摸和意外跳过的按键。
虽然我们在这里不涉及技术细节,但是接下来的两个图用具体的例子说明了插入和删除的解码。
对于插入,我们看例子“hllo”(不小心跳过了“e”)。下图中的插入解码器正确地找到“hello”作为最可能的单词:直观地说,插入“e”比简单地跟随触摸证据产生更高的总体可能性,因为“he”在英语中比“hl”更可能。

用可以插入额外字母的解码器解码“hllo”(用户不小心跳过了“e”)。(作者本人法师)
请注意,本例中的解码器还通过在开头插入“t”来探索“thllo”,因为“th”在英语中的可能性很高。
补充一下,对于删除,我们看“hqello”(偶然的“q”)的例子。解码器正确地发现“hello”是最有可能的假设:虽然“hq”很可能被触摸,但“qe”不太可能通过“ε”(空)跳过“q”而取“he”。

用可以删除触摸(ε)而不是产生字母的解码器解码“hqello”(注意伪“q”)。(作者本人法师)
功能 4:建议下一个单词
到目前为止,所有功能都假设用户已经触摸了按键。相比之下,如果我们没有接触,我们只能依靠语言环境。这产生了“单词建议”的特征。

智能手机键盘上的单词建议,在键入“Hello”后显示。(我作者法师)
例如,我们可以查看最后的 n-1 个字来预测下一个字:

这是一个简单的单词级的ngram 模型,可以通过统计大型文本语料库中的单词序列来训练。最近,深度学习语言模型也被用于这项任务。它们提供了一些优势,比如能够包含更长的上下文。
讨论和要点
在深入你的键盘之后,这一切意味着什么?这里有三个观点可能会影响未来“智能”用户界面的设计,分别是:1)构思,2)评估,3)超越交互的批判性思考。
你的数据驱动键盘的幕后正在进行很多事情
回到一个键盘应用程序,例如五到十年前。我最近这样做是为了好玩,但感觉不太对劲:我觉得奇怪地笨拙和缓慢——可能是因为旧键盘还没有关于我的触摸数据,当然也没有我已经习惯的语言建模和解码的质量。
→ *构思:*为了激发“智能”ui 的新想法,我们可能会问,如何将成功的数据驱动和概率概念从键盘更普遍地转移到 GUI 上(也见最后的建议阅读)。
UX 不止是 UI,尤其是具有“智能”的 UI
如上所述,旧键盘看起来和我最新的键盘应用几乎一样,但是我的用户体验要差很多。今天的键盘是一个交互系统的主要例子,在这个系统中,UX 不能从视觉 UI 中辨别出来,这不能揭示潜在的算法质量。
→ *评估:*经验评估对于自适应 ui 的设计至关重要。可以预期,未来的进展将受益于来自人机交互和人工智能的知识和方法。
数据驱动的 ui 中的数据是如何使用的?
我们已经每天与数据驱动的用户界面交互,这些用户界面收集我们的数据。键盘是极少数交互系统之一,至少在原则上,这些系统只收集输入数据来改进输入法本身。
→ *反思:*我们可以通过调查用户数据在原位(即交互中)与非原位(即超出使用范围)的使用情况,来批判性地检验数据驱动的用户界面。
回顾和思考要点
为了激发进一步的讨论和见解,我们可以将今天的触摸键盘视为:
- *数据驱动的 ui:*键盘使用触摸数据和语言数据来改善你的打字体验和效率。
- *概率 ui:*键盘在解释你的输入时会考虑到不确定性。
- *动态和自适应的用户界面:*集成一个语言模型并不是脱离输入的“魔法”,而是导致像素到键分配的动态变化。
- *生物识别用户界面:*为了适应按键,键盘会学习你个人触摸行为的表现,这因用户而异,就像行为指纹一样。
- *欺骗性用户界面:*键盘内部使用不同的像素到按键的分配,而不是屏幕上显示的按键(出于好意:避免混淆和恶化的协同适应)。
- *搜索者:*键盘搜索一个巨大的假设空间,将你的输入触摸“解码”成单词和句子。
结论
我们已经获得了使今天的智能手机键盘智能的核心功能,并通过基于具体触摸和语言数据的可视化来探索它们的效果和中心参数。
至关重要的是,这里解释的四个核心特征都来自一个概率框架(贝叶斯规则),通过用不同的具体组件填充它的槽。以下是总结:

贝叶斯键盘概述。(我作者法师)
总之,移动触摸键盘已经成为“智能”、数据驱动和概率用户界面的一个普遍的日常例子。
延伸阅读:
- 键盘以外的其他触摸图形用户界面的概率概念
- 关于令牌传递和输入解码的更多信息
- 寻找幻灯片,代码等。?这是基于我在德国拜罗伊特大学的“智能用户界面”讲座上创作的材料。与他人共同教授的开放版本,可在此获得:【https://iui-lecture.org/】T4(包括重现剧情的 Python 笔记本)。
全球、群体和局部模型的可解释性研究
原文:https://towardsdatascience.com/a-look-into-global-cohort-and-local-model-explainability-973bd449969f?source=collection_archive---------8-----------------------
关于不同层次的可解释性以及如何在 ML 生命周期中使用每一层的初级读本
在过去的十年中,机器学习应用的众多进步迅速推动了重大的技术进步。新颖的人工智能技术通过破解计算机视觉、自然语言处理、机器人学和许多其他领域中历史上难以捉摸的问题而彻底改变了工业。今天,说 ML 改变了我们的工作方式、购物方式和娱乐方式并不夸张。
虽然许多模型的性能有所提高,在流行的数据集和挑战上提供了最先进的结果,但模型的复杂性也有所增加。特别是,自省和理解模型为什么做出特定预测的能力变得越来越困难。
既然 ML 模型能够影响我们生活的重要部分,那么我们有能力解释他们是如何做出预测的就变得更加重要了。
在这篇文章中,我们将展示 ML 可解释性的不同层次,以及如何在 ML 生命周期中使用每一个层次。最后,我们将介绍一些常用的方法来获得这些层次的可解释性。
培训中的可解释性

作者图片
首先,让我们来看看可解释性如何在机器学习生命周期的模型训练阶段发挥作用。特别是,让我们开始梳理 ML 可解释性的不同风格。
在训练中特别重要的是全局可解释性。如果在所有预测中ML 工程师能够确定哪些特征对模型的决策贡献最大,那么我们认为 ML 工程师能够获得全局模型的可解释性。这里的关键术语是“所有预测”,不同于群组或局部可解释性——全局是所有预测的平均值。
换句话说,全局可解释性让模型所有者决定每个特征在多大程度上有助于模型如何对所有数据进行预测。
在实践中,使用全局可解释性的一个领域是在特定的基础上向非数据科学团队提供关于模型平均使用什么来做决策的信息。示例:营销团队在查看客户流失模型时,可能想知道预测客户流失最重要的特征是什么。
在此使用案例中,该模型为数据科学之外的利益相关方提供全局洞察,其需求频率和对象可能会有所不同-它更像是一种分析功能,为业务利益相关方提供更多洞察。
还有一个全局可解释性的模型构建器用例,即确保一个模型做你期望的事情,并且没有版本之间的变化。您的模型可能会以不可预见的方式“学习”您打算教给它的函数,如果不能理解它所依赖的特性,就很难说它选择了哪个函数来近似。
让我们用一个模型来预测一个新客户应该为你的银行的新信用卡获得的信用额度。该模型可以通过多种方式完成为新客户分配信用额度的工作,但并非所有方式都是平等的。可解释性工具可以帮助你建立信心,相信你的模型正在学习一个函数,这个函数不会过度索引可能在生产中引起问题的特定特性。

全球特征重要性—年龄最重要|作者图片
例如,假设一个模型非常依赖年龄来预测要分配的信用额度。虽然这可能是偿还大额信贷账单能力的一个强有力的预测因素,但它可能会低估一些有能力支持更高信贷限额的年轻客户的信贷,或高估一些可能不再有收入支持高信贷限额的年长客户的信贷。
可解释性工具可以帮助你在将模型交付生产之前发现潜在的问题。全局可解释性有助于抽查模型中的特性是如何对模型的整体预测做出贡献的。在这种情况下,全局可解释性将能够突出年龄作为模型所依赖的主要特征,并允许模型所有者了解这可能如何影响他们的用户群并采取行动。
在训练过程中,全局可解释性有助于获得对您选择的特征的信心,以便为其预测提供模型。通常,模型构建者会添加大量的特性,并观察到关键模型性能指标的积极变化。了解哪些特性或特性之间的交互推动了这种改进,可以帮助您构建一个更精简、更快速、甚至更通用的模型。
验证中的可解释性
ML 生命周期的下一个阶段:模型验证。让我们看看可解释性是如何帮助模型构建者在将模型交付生产之前验证模型的。
为此,定义我们的下一类模型可解释性很重要:群组可解释性。有时,您需要了解模型如何为数据的特定子集(也称为群组)做出决策。群组可解释性是了解模型特征对数据子集预测的贡献程度的过程。
群组可解释性对于模型所有者来说非常有用,有助于解释为什么模型对于其输入的特定子集表现不佳。它有助于发现模型中的偏差,并帮助您发现可能需要支持数据集的地方。
退一步说,在验证期间,我们的主要目标是看看我们的模型在服务上下文中是如何支持的。更具体地说,验证是关于探测你的模型从它在训练中接触到的数据中概括得有多好。
评估泛化性能的一个关键因素是发现模型性能不佳的数据子集,或者依赖于对其进行训练的数据过于具体的信息,这通常也称为过度拟合。
群组可解释性可以作为模型验证过程中的一个有用工具,帮助解释模型在表现良好的群组和表现不佳的群组之间的预测差异。

群组特征重要性 |作者图片
例如,假设您有一个用于预测特定用户信用评分的模型,并且您想知道该模型是如何对 30 岁以下的用户进行预测的。值得注意的是,该组最重要的特性“费用”不同于全局特性的重要性。群组可解释性有助于调查与其他数据群组(如 50 岁以上的用户)相比,您的模型如何对待这些用户。这可以帮助您发现输入要素和模型结果之间的某种意外或不良关系。
群组可解释性带给你的另一个重要好处是,你能够理解何时将你的模型分割成模型集合,并联合它们的预测。您试图学习的功能很可能最好由模型联盟来处理,群组可解释性可以帮助您发现不同的特性集或模型架构可能更有意义的群组。
生产中的可解释性
最后,让我们看看可解释性如何在生产环境中帮助模型所有者。一旦模型离开研究实验室并投入生产,模型所有者的需求就会有所改变。
在生产中,模型所有者需要能够回答所有上述群组和全局可解释性,除了关于非常具体的例子的问题,以帮助客户支持,实现模型可审计性,或者甚至只是向用户提供关于发生了什么的反馈。
这让我们进入了 ML 可解释性的最后一个类:个体,也被称为局部可解释性。这在某种程度上是不言自明的,但是局部可解释性有助于回答这个问题,“对于这个特定的例子,为什么模型做出这个特定的决定?”

每个预测级别的可解释性—局部 |作者的图像
对于一个 ML 工程师来说,特异性水平是工具箱中一个非常有用的工具,但是需要注意的是,在你的系统中拥有局部可解释性并不意味着你拥有全局和群体可解释性。
局部可解释性对于找到生产中特定问题的根本原因是必不可少的。假设您刚刚看到您的模型拒绝了一个贷款申请人,您需要知道为什么做出这个决定。本地可解释性将帮助您了解哪些特性对拒绝贷款最有影响。
特别是在受监管的行业,比如我们前面例子中的贷款,本地可解释性是最重要的。受监管行业中的公司需要能够证明其模型做出的决策是合理的,并证明该决策不是使用受保护类别信息的特征或衍生产品做出的。
注意:在我们所有的例子中,我们使用 Shap 的绝对值进行可视化;这些隐藏了单个特征的方向信息。

带方向信息的预测级形状 |作者图片
带有方向信息的预测级别形状可以说明特征如何影响结果—在这种情况下,“收费”会降低“年龄”增加时的违约概率。
随着越来越多的法规影响技术,公司将无法躲在 ML 黑匣子后面对他们的产品做出决策。如果他们想获得机器学习的好处,他们将不得不投资于提供本地可解释性的解决方案。
当模型被提供并为你的用户做出预测时,个人推理水平的可解释性可以作为理解你的模型动态的一个极好的切入点。一旦您看到模型预测可能出错,无论是从错误报告还是从您设置的监控阈值,都可以开始调查为什么会发生这种情况。
它可能会让你发现哪些特征对这个决定贡献最大,甚至会让你更深入地研究一个群体,这个群体也可能受到你发现的这种关系的影响。这有助于关闭 ML 生命周期循环,允许你从“我看到了一个单独例子的问题”到“我发现了一种改进我的模型的方法。”
ML 可解释性的常用方法:
既然我们已经定义了 ML 可解释性的一些宽泛的类别,以及它们在 ML 生命周期的不同阶段是如何被使用的,那么让我们把注意力转向今天驱动 ML 可解释性解决方案的一些技术。
SHapley 沙普利加法解释
首先,让我们看看 SHAP,它代表着沙普利加法解释。SHAP 是从合作博弈论的概念发展而来的一种解释技术。SHAP 试图解释为什么一个特定的例子与一个模型的整体预期不同。
对于模型中的每个要素,将计算一个 Shapley 值,该值解释了此要素如何影响此示例中模型预测与“平均”或预期模型预测之间的差异。

利用 SHAP 解释的例子|作者图片
所有输入特征的 SHAP 值将总是加起来作为该示例的观察模型输出和基线(预期)模型输出之间的差,因此是 SH A P 中名称的加法部分
SHAP 还可以使用为每个数据点计算的 Shapley 值来提供全局可解释性,甚至允许您对特定群组进行调整,以获得关于群组之间特征贡献差异的一些见解。
在模型不可知的上下文中使用 SHAP 对于局部解释来说足够简单,尽管如果没有关于你的模型的特定假设,全局和群组计算会很昂贵。
LIME —本地可解释模型不可知
LIME,或局部可解释模型不可知解释,是一种试图提供局部 ML 可解释性的可解释性方法。在高层次上,LIME 试图理解模型输入中的扰动如何影响模型的最终预测。由于它没有对模型如何达到预测做出假设,因此它可以用于任何模型架构,这就是 LI M E 的“模型不可知”部分。

使用感兴趣区域内的线性模型对模型进行局部近似,以获得可解释性。图像由 c3.ai 组成
LIME 试图通过训练一个更易解释的模型来理解特定示例的特征和模型的预测之间的这种关系,该模型例如是一个线性模型,其示例来自原始输入的微小变化。
在训练结束时,可以从线性模型学习到高于特定阈值的系数的特征中找到解释(在考虑一些归一化之后)。这背后的直觉是,线性模型发现这些特征在解释模型的预测中最为重要,因此对于此局部示例,您可以推断每个特征在解释模型所做预测中的作用。
结论
我们正处于一个极其激动人心的机器学习时代,在过去十年左右的时间里,这些技术的历史障碍正在被颠覆。对现代机器学习最常见的批评之一是缺乏可解释的工具来建立信心,提供可审计性,并实现机器学习模型的持续改进。
今天,人们对克服下一个障碍有着浓厚的兴趣。正如所涵盖的一些现代可解释技术所证明的,我们正在前进。
联系我们
如果这个博客引起了你的注意,并且你渴望了解更多关于机器学习可观察性和模型监控,请查看我们其他的博客和 ML 监控上的资源!如果您有兴趣加入一个有趣的 rockstar 工程团队,帮助模型成功生产,请随时联系我们,并在此处找到我们的空缺职位!
一种适用于类不平衡数据的损失函数:“焦点损失”
原文:https://towardsdatascience.com/a-loss-function-suitable-for-class-imbalanced-data-focal-loss-af1702d75d75?source=collection_archive---------6-----------------------
类别不平衡数据下的深度学习

日本长野雾蒙蒙的午后(图片:作者自己的作品)
阶级不平衡:
在机器学习中,有时我们会遇到像 MNIST 时尚数据或 CIFAR-10 数据这样的高手,数据集中每个类别的例子都很平衡。如果在一个分类问题中,样本在已知类别中的分布有偏差,会发生什么?这种在数据集中有严重或轻微偏差的问题是常见的,今天我们将讨论一种处理这种类不平衡数据的方法。让我们考虑一种邮件数据集不平衡的极端情况,我们建立一个分类器来检测垃圾邮件。由于垃圾邮件相对较少,我们假设所有邮件中有 5%是垃圾邮件。如果我们写一行简单的代码——
def detectspam(mail-data): return ‘not spam’
这将给我们 95%的正确答案,尽管这是一个极端的夸张,但你得到了问题。最重要的是,用该数据训练任何模型将导致对普通邮件的高置信度预测,并且由于训练数据中垃圾邮件的数量极低,该模型将很可能无法学会正确预测垃圾邮件。这就是为什么精确度、召回率、F1 分数、ROC/AUC 曲线是真正告诉我们故事的重要指标。正如您已经猜到的,减少这个问题的一个方法是进行采样以平衡数据集,这样类就平衡了。还有其他几种方法来解决机器学习中的类别不平衡问题,杰森·布朗利(Jason Brownlee)整理了一份出色的综合评论,点击这里查看。
计算机视觉中的阶级不平衡;
在计算机视觉问题的情况下,这种类别不平衡问题可能更加严重,这里我们讨论作者如何处理导致焦点丢失的物体检测任务。在快速 R-CNN 类型的算法的情况下,首先我们通过 ConvNet 运行图像以获得特征图,然后在高分辨率特征图上执行区域提议(通常大约 2K 个区域)。这些是两级检测器,当焦损失文件推出时,一个有趣的问题是,像 YOLO 或 SSD 这样的一级检测器是否可以获得与两级检测器相同的精度?单级检测器速度很快,但在此期间的精确度大约是两级检测器的 10–40%。作者认为训练中的等级不平衡是阻止一级探测器获得与二级探测器相同精度的主要障碍。

图 1:对象检测中的类不平衡。[2])
这种等级不平衡的一个例子显示在不言自明的图 1 中,该图取自原作者的演示文稿本身。他们发现,当有更多数量的包围盒覆盖可能物体的空间时,一阶段检测器表现更好。但是这种方法导致了一个主要问题,因为前景和背景数据不是平均分布的。例如,如果我们考虑 20000 个边界框,大多数情况下,其中 7-10 个将实际包含关于对象的任何信息,其余的将包含背景,大多数情况下,它们很容易分类,但没有信息。这里,*作者发现损失函数(如交叉熵)是简单例子会分散训练注意力的主要原因。*以下是图示

图 2:阶级失衡和交叉熵损失(图片由作者提供)。
即使错误分类的样本(图 1 中的红色箭头)比正确分类的样本(绿色箭头)受到更多惩罚,在密集对象检测设置中,由于不平衡的样本大小,损失函数被背景(简单样本)淹没。焦点损耗解决了这一问题,其设计方式使得**减少了简单示例的损耗(“下降重量”),因此网络可以专注于训练困难的示例。**以下是焦点损失的定义—

焦点损失定义
在焦点损失中,有一个调制因子乘以交叉熵损失。当样本被错误分类时, p (代表模型对标签为 y = 1 的类别的估计概率)较低,调制因子接近 1,损失不受影响。当 p →1 时,调制因子接近 0,并且良好分类示例的损耗被向下加权。γ参数的影响如下图所示—

图 3:焦损失与交叉熵损失的比较(图片由作者提供)。代码可在我的笔记本中找到[参考。3]
引用报纸上的话—
调制因子减少了简单示例的损耗贡献,并扩展了示例接收低损耗的范围。
为了理解这一点,我们将使用上述定义比较交叉熵(CE)损失和焦点损失,γ = 2。考虑真值 1.0,我们考虑 3 个预测值 0.90(接近),0.95(非常接近),0.20(离真值很远)。让我们用 TensorFlow 看看下面的损失值—
CE loss when pred is close to true: 0.10536041
CE loss when pred is very close to true: 0.051293183
CE loss when pred is far from true: 1.6094373
focal loss when pred is close to true: 0.0010536041110754007
focal loss when pred is very close to true: 0.00012823295779526255
focal loss when pred is far from true: 1.0300399017333985
这里我们看到,与 CE 损耗相比,焦点损耗中的调制因子起着重要作用。当预测接近事实时,损失受到的惩罚要比预测远离事实时多得多。重要的是,当预测值为 0.90 时,焦损失将为 0.01 × CE 损失,但当预测值为 0.95 时,焦损失将约为 0.002 × CE 损失。现在,我们了解了聚焦损耗如何降低简单示例的损耗贡献,并扩展了示例获得低损耗的范围。这也可以从图 3 中看出。现在,我们将使用一个真实的不平衡数据集,看看焦点损失的实际情况。
信用卡欺诈:阶级不平衡数据集:
*数据集描述:*在这里,我考虑了一个在 Kaggle 中可用的极端类别不平衡数据集,该数据集包含欧洲持卡人在 2013 年 9 月通过信用卡进行的交易。让我们用熊猫——

该数据集显示了两天内发生的交易,我们有 284,807 笔交易。V28 的特征…V28 是通过 PCA 获得的主要组成部分(由于机密问题,未提供原始特征),唯一未通过 PCA 转换的特征是“时间”和“数量”。特征“时间”包含数据集中每笔交易和第一笔交易之间经过的秒数,特征“金额”是交易金额。特征“类别”是响应变量,在欺诈的情况下取值 1,否则取值 0。

图 4:真实交易(0)和欺诈交易(1)在数据集中的分布。图片作者。
*类别不平衡:*让我们画出“类别”特征的分布,它告诉我们有多少交易是真实的和虚假的。如上面的图 4 所示,绝大多数交易都是真实的。让我们用这段简单的代码得到这些数字—
print (‘real cases:‘, len(credit_df[credit_df[‘Class’]==0]))print (‘fraud cases: ‘, len(credit_df[credit_df[‘Class’]==1])) >>> real cases: 284315
fraud cases: 492
因此,类别不平衡比率约为 1:578,因此,对于 578 个真实交易,我们有一个欺诈案例。首先让我们使用一个简单的具有交叉熵损失的神经网络来预测欺诈和真实交易。但在此之前,一个小小的检查告诉我们,“数量”和“时间”功能没有被缩放,而其他功能“V1”,“V2”等被缩放。在这里,我们可以使用standard scaler/RobustScaler来缩放这些特征,由于 robust scaler 对异常值具有鲁棒性,所以我选择了这种标准化技术。

现在,让我们选择如下功能和标签—
X_labels = credit_df.drop([‘Class’], axis=1)
y_labels = credit_df[‘Class’]X_labels = X_labels.to_numpy(dtype=np.float64)y_labels = y_labels.to_numpy(dtype=np.float64) y_lab_cat = tf.keras.utils.to_categorical(y_labels, num_classes=2, dtype=’float32')
对于训练测试分割,我们使用分层来保持标签的比率—
x_train, x_test, y_train, y_test = train_test_split(X_labels, y_lab_cat, test_size=0.3, stratify=y_lab_cat, shuffle=True)
现在我们建立一个简单的神经网络模型,它有三个密集层
def simple_model(): input_data = Input(shape=(x_train.shape[1], )) x = Dense(64)(input_data) x = Activation(activations.relu)(x) x = Dense(32)(x) x = Activation(activations.relu)(x) x = Dense(2)(x) x = Activation(activations.softmax)(x) model = Model(inputs=input_data, outputs=x, name=’Simple_Model’) return model
用类别交叉熵作为损失来编译模型—
simple_model.compile(optimizer=Adam(learning_rate=5e-3), loss='categorical_crossentropy', metrics=['acc'])
训练模型—
simple_model.fit(x_train, y_train, validation_split=0.2, epochs=5, shuffle=True, batch_size=256)
为了真正理解模型的性能,我们需要绘制混淆矩阵以及精确度、召回率和 F1 分数——


图 5:混淆矩阵、精确度、召回率、交叉熵损失下的 F1 分数(图片由作者提供)
我们从混淆矩阵和其他性能指标得分中看到,正如预期的那样,该网络在对真实交易进行分类方面做得非常好,但对于欺诈类,召回值低于 50%。我们的目标是在不改变任何东西的情况下进行测试,除了损失函数。我们能得到更好的性能指标值吗?
使用焦点损失:
首先,让我们用α和γ作为超参数来定义焦点损失,为此,我使用了由 SIG-addons (tfa)维护的 TensorFlow 功能模块。在这个模块下的附加损耗中,有一个聚焦损耗的实现,首先我们导入如下—
import tensorflow_addons as tfafl = tfa.losses.SigmoidFocalCrossEntropy(alpha, gamma)
利用这一点,让我们定义一个自定义损失函数,该函数可以作为“焦点损失”的代理,用于两类特定问题
def focal_loss_custom(alpha, gamma): def binary_focal_loss(y_true, y_pred): fl = tfa.losses.SigmoidFocalCrossEntropy(alpha=alpha, gamma=gamma) y_true_K = K.ones_like(y_true) focal_loss = fl(y_true, y_pred) return focal_loss return binary_focal_loss
我们现在只是重复上述模型定义、编译和拟合的步骤,但这次使用焦点损失,如下所示
simple_model.compile(optimizer=Adam(learning_rate=5e-3), loss=focal_loss_custom(alpha=0.2, gamma=2.0), metrics=[‘acc’])
对于 alpha 和 gamma 参数,我刚刚使用了论文中建议的值(然而问题是不同的),需要测试不同的值。
simple_model.fit(x_train, y_train, validation_split=0.2, epochs=5, shuffle=True, batch_size=256)
使用焦点损失,我们看到如下改进—


图 6:混淆矩阵、精确度、回忆、焦点丢失的 F1 分数(图片由作者提供)
我们看到,使用“焦点损失”后,性能指标显著提高,与之前的案例(69/148)相比,我们可以正确检测到更多的“欺诈”交易(101/148)。
在这篇文章中,我们讨论焦点损失,以及当数据高度不平衡时,它如何改善分类任务。为了演示焦点损失,我们使用了信用卡交易数据集,该数据集高度偏向于真实交易,并显示了焦点损失如何提高分类性能。
我还想提到的是,在我对伽马射线数据的研究中,我们试图将活动星系核(AGN)与脉冲星(PSR)区分开来,伽马射线天空主要由活动星系核构成。下图是这种模拟天空的一个例子。这也是计算机视觉中类不平衡数据集的一个例子。


图 7:作为不平衡数据集示例的活动星系核(上图)和 PSRs(下图)的伽马射线天空图示例。虽然银河系外的活动星系核均匀地分布在整个天空中,但它们大多分布在银道面附近。作者图片。
参考资料:
[1] 焦损原纸
[2] 焦损原图展示
[3]本帖使用的笔记本: GitHub
预测 MLB 游戏结果的机器学习算法
原文:https://towardsdatascience.com/a-machine-learning-algorithm-for-predicting-outcomes-of-mlb-games-fa17710f3c04?source=collection_archive---------7-----------------------
实践教程
机器学习方法能提供超越大众智慧的增量信息优势吗?
我的大部分代码都可以在 GitHub 上的 这里 供读者细读。本文的第一部分介绍了机器学习的几个关键概念元素,而后半部分则侧重于算法方法论。

unsplash.com
原始数据不受认知偏见的影响——没有人类的情感和倾向。在这一理念的指导下,比利·比恩的 2001 Oakland As 为渴望获得冠军的球会设计了一个新的统计蓝图,并催化了一场数据分析革命,这场革命像野火一样蔓延到职业体育的各个方面。正如比恩发现的那样,棒球的丰富数据非常适合预测分析。我选择探索的问题是利用机器学习来预测单个游戏的结果。我的最终逻辑回归和随机森林模型达到了现有科学文献中较高水平的测试精度,并在两年的测试期内超过了拉斯维加斯的博彩赔率。我的结果证实了投注赔率是高效的;然而,我的发现也表明,机器学习方法可能会提供超越大众智慧的增量信息优势,从长远来看,这可能会转化为有意义的见解。我的模型还揭示了团队投球的重要性,即一个团队牛棚的力量比其进攻的质量更能表明其获胜的能力。总的来说,从我的算法中得出的基本方法和见解可能对职业棒球大联盟前台办公室或各种其他体育分析实体的战略决策有用。
为了构建数据集,我采用了网络搜集来汇总 baseball-reference.com 20 年的常规赛数据,总共大约 48,000 场比赛,并搜集了每场比赛的击球和投球统计数据,以计算诸如上垒率(OBP)、每局保送和击球(WHIP)以及平均得分(ERA)等指标。与现有的文献不同,我还包括了每场比赛开始前投手们整个赛季的表现。这是一个计算密集型过程,但在我看来,这是我的模型的一个关键优势,因为它提供了一个有意义的变量,与其他要素具有较低的多重共线性。此外,我推导出了一种方法,通过检查每场比赛失分的分布来衡量一支球队的一致性。我的模型中其他值得注意的特性是比尔·詹姆斯的毕达哥拉斯期望和 Log5 指标,它们分别根据球队以前的得分和胜率来评估球队。我还在我的分析中包含了双重标题,回想起来,这可能不值得增加编程负担。为了避免疑问,我获得了 baseball-reference.com 的许可来收集它的数据。
任何一场 MLB 游戏的结果都充满了变数和纯粹的运气——在某种意义上与抛硬币有相似之处。现存最好的科学文献(埃尔夫林克、瓦莱罗、贾等。)产生了 57–59.5%范围内的准确度水平。从表面上看,这似乎很平常;然而,就我们的问题而言,这已经很不错了。作为参考,拉斯维加斯博彩赔率——通常被认为是职业体育运动最佳预测指标的晴雨表——在过去六年中的准确率仅为 58.2%(使用 covers.com 的数据计算)。达到比共识高百分之一的精度水平可能会被证明是非常有价值的。我的逻辑回归和随机森林模型分别实现了 58.9%和 59.6%的独立分类准确率,后者在 2018 年和 2019 年的赛季中略高于拉斯维加斯的博彩赔率 0.2%。当将投注赔率作为额外的输入变量纳入模型本身时,组合随机森林模型的准确率达到 61.1%,比 2019 年的投注赔率高出 0.8%。逻辑回归算法在同一时期达到了 60.5%。注意:出于我们的目的,我简单地将准确度定义为被算法 h:1/m⋅σ(h(xᵢ)=f(xᵢ)).正确分类的点的百分比
机器学习是对预测算法的研究,这些算法在从数据中学习时会自动改进。第一步是选择一个假设类(一族分类器)。例如,如果我们试图根据鳄梨的颜色和硬度来预测它的味道,一个可能的假设类可能是欧几里得平面上封闭矩形的特征函数族:{ f(x;y) ∈ [x₁,y₁] × [x₂,y₂]},我们的算法将“学习”这个类,以找到具有硬度和颜色的最佳上下边界的矩形。换句话说,这种算法将根据过去对鳄梨质量进行最准确分类的一系列硬度和颜色来预测新鳄梨的质量。直觉上,我们的目标是最小化错误分类鳄梨的概率,即我们的分类器的真实误差。当然,准确的潜在概率分布永远不可能精确知道,因为我们不可能得到世界上的每一个鳄梨。然而,我们的算法在样本数据中误分类的点的百分比,称为经验误差,可以作为所需真实误差的代理。在这个样本数据上实现最小误差的分类器被称为经验风险最小化器(ERM)。
ERM 是一种自然的逻辑方法,但我们必须小心过度拟合——我们的算法在训练数据上表现得非常好,但在预测新的、看不见的数据时表现不佳。例如,可以将 n-1 次多项式拟合到 n 个数据点,这将完美地预测我们的训练数据中的每个点,但泛化能力很差。另一方面,拟合不足是指使用的模型对于数据来说不够复杂,例如对存在二次关系的数据集应用线性回归。众所周知的偏差-方差权衡,这种选择平衡模型的简单性和准确性的假设类以便很好地推广到看不见的数据的概念是机器学习的一个重要原则。
衡量模型预测能力的最佳方式是从一开始就留出一部分数据并隐藏起来,不让分析人员看到。然后,我们根据未隐藏的数据(称为训练数据)训练我们的模型,并随后根据测试数据进行预测,以模拟现实世界的场景。最终,我们希望我们的模型在训练和测试数据上的准确性大致相等。不成比例的高训练与测试精度表明过度拟合。针对手头的问题,我拿出了 2018 和 19 赛季作为测试数据,大概 4800 场,在 2000 到 17 赛季的基础上训练模型。我选择训练和测试数据截止点是为了避免使用从尚未发生的游戏中提取的信息来预测未来,这种现象称为数据泄漏。最后一点:预测棒球比赛的结果是一个二元分类问题,即主队是赢还是输。
特色工程
数据提取过程是计算密集型的,并且通常在编程上是严格的。例如,检索和计算每场比赛前先发投手的个人年龄需要大约 20 个小时。尽管如此,获取大量数据通常非常有帮助,因为我们的训练数据将更好地反映真实的底层分布,而经验误差(假设我们没有过度拟合)应该更好地反映真实误差。我通过特征工程添加的第一个指标是比尔·詹姆斯的毕达哥拉斯预期,这是一个 win%的代理,它代表了一个球队在那个赛季的总得分与失分之比。毕达哥拉斯期望=(得分得分)/[(得分得分得分)+(允许得分)]。杰伊·休曼通过回溯测试发现最佳指数应该是 1.83,而不是 2。我运行了这两种方法,将指数参数设置为 1.83 产生了与目标变量更高的相关性,所以我选择使用 1.83。
我添加的下一个功能是 Log5:p(j beats k)=(Pⱼ-(pⱼ⋅Pₖ))/(pⱼ+pₖ-(2⋅pⱼ⋅pₖ)其中 pⱼ是 j 队赢的游戏的百分比,pₖ是我的 k 队赢的游戏的百分比。log5 公式非常直观。详细解释请看詹姆斯解说此处。实质上,他推导出了 A 队和 B 队胜率之间的巧妙数学关系,以确定 A 队获胜的概率。此外,我在每场比赛前计算了每支球队的 OBP、SLG、ERA、FIP 和 WHIP 指标,还包括每项指标的 3 天、5 天、7 天、… 15 天平均值。为了平衡准确性和与其他功能的低多重共线性,我最终决定采用 10 天跟踪平均值来捕捉团队的短期表现。这些 10 天的跟踪指标被认为是球队整个赛季指标的补充。我还添加了物理学家克里·惠斯南特的公式。Whisnant 开始创建一个衡量标准,也考虑到了球队得分的一致性。他发现击球率较高的球队通常得分分布较窄。尽管 Whisnant 的公式在我的模型中的预测能力低于 PE 或 Log5,但它仍然与目标变量有着有意义的相关性,这让我想到了捕捉团队一致性的各种其他方法。
与比尔·佩蒂的发现一致,我的结果表明,一个团队让步的一致性比得分的一致性更重要(与目标变量的相关性更高)。然而,仅仅找到得分和失分的标准偏差本身并不是有用的度量,因为,当然,一个队得分不能少于零分,所以一个队得分的分布在零处被切断。换句话说,得分低的团队比得分高的团队有更低的标准差,部分原因是因为他们得分低。我想只分离和提取一个团队的一致性,不管它实际得分多少,以便比较苹果。
我的解决方法是这样的:我取了过去 20 年来每支球队失球次数的平均值以及失球次数的标准差,并对过去 20 个赛季的所有 30 支球队都这样做了。然后,我对这 600 个数据点拟合了一个线性回归模型,创建了一个函数,其输入是每场比赛的平均失球次数,其输出是失球次数的标准差。换句话说,这个函数提供了一个团队的标准偏差“应该”基于其平均值的基线。得分跑垒。标准偏差低于基线的团队更加一致,反之亦然。对于每场比赛,我计算了两个队的基线,并从中减去每个队失球的实际标准差。然后,我从 B 队的人数中减去 A 队的人数,以衡量 A 队相对于 B 队的一致性,较高的值表明主队(A 队)比 B 队更一致。

平均值。每场比赛的失分相对于平均值的标准差有所下降。2000-2019 年每场比赛失球数(图片由作者提供)
如上所述,残差之间没有可辨别的模式,因此异方差不是问题。残差也呈现出均值为零的正态分布。这些都是执行线性回归的必要属性。
探索性数据分析
在选择正确的特征输入模型时,我们希望捕获与目标变量最相关的输入变量。然而,我们也希望避免冗余或无关变量会削弱我们的模型效力的情况。让许多相似的特征给我们相同的信息是不可取的。换句话说,我们希望输入要素具有较低的多重共线性。下面是变量的相关热图。除了 log5 和 Whisnant 之外的所有指标都表示为主队和客场队之间的差异(δ**)**。

相关热图(图片由作者提供)
如上所述,毕达哥拉斯期望(δPE)和 Log5 与我们的目标变量具有最高的相关性。团队投球指标似乎是第二有价值的,其中 WHIP 最有价值,这表明不允许保送和安打(OBP 的理论相反)是球队赢得比赛的最重要的考虑因素。先发投手自责分率的差异(SP _ ERA)也有很好的特性:与其他特征的多重共线性低,以及与我们的目标变量的一些有意义的相关性。从逻辑上来说,这是有道理的,因为一个特定的先发投手的质量应该在很大程度上独立于一个球队的进攻或牛棚的其他人的质量,应该对比赛的结果产生实质性的影响。10 天跟踪δPE、δOBP、SLG 和 WHIP 也很有帮助,因为它们可以作为团队短期表现的代理,并且与其他变量的多重共线性较低。鉴于 ERA 与 WHIP 和 WHIP 的高度相关性,我选择从模型的最终输入变量中忽略 ERA。然而,由于我有数万个数据点和不到 15 个特征,我选择保留所有其他特征。

(图片由作者提供)
以上是一些关键变量的分布。正如您所看到的,它们看起来是正态分布的,这在开发模型时会很有帮助。
逻辑回归模型
逻辑回归使用 logit 函数,即众所周知的 sigmoid 函数的逆函数,从输入变量的线性组合中获得离散输出。我们使用简单线性回归的等式,并将其设置为等于我们事件的对数概率:β₁x+β₀ = log[P/(1-P)]。求解 p 得到 1/(1+eᶻ)其中 z = β₁x+β₀.注意:我们取赔率的对数,以便获得围绕原点对称的范围。在潜在的 logit 曲线族(假设类)中,我们的算法选择最大化观察样本的可能性的曲线。
为了更好地理解最大似然,考虑一个简单直观的例子:假设我们有一个包含三个球的盒子,每个球可以是绿色或蓝色。假设我们从盒子里拿两个球,它们都是绿色的。我们对第三个球的颜色的最佳猜测应该是什么?嗯,有两种可能的选择,因为我们已经看到了两个绿色的球,要么是θ₁:盒子里有三个绿色的球,要么是θ₂:盒子里有两个绿色和一个蓝色的球。鉴于盒子里有三个绿色球,观察到我们的两个绿色球样本的几率显然是 100%: P(S|θ₁) = 1。对于第二种情况,假设盒子里实际上有两个绿色球和一个蓝色球,选择两个绿色球的概率是 P(S|θ₂) = ⅔ ⋅ = ⅓.很明显,1 > ⅓,所以我们的“最佳猜测”——最大化观察样本可能性的选择——是三个绿球。我们的逻辑回归模型以这种方式运行,选择 logit 曲线,在给定该曲线参数的情况下,使观察到每个数据点的概率的乘积最大化:arg max[π(P(Xi |θ))]。这就是它“学习”假设类的方式。
一种称为正则化的方法通过在大系数的损失函数中添加惩罚来防止我们的模型过度拟合。通过惩罚模型中增加的复杂性,我们可以防止过度拟合。为了找到最佳的正则化常数,我使用了 k 重交叉验证。K-fold 验证非常聪明和直观。首先,我们将训练数据分成 k 个折叠,并将第一个折叠作为我们的验证数据集。然后,我们在其他 k-1 个折叠上训练该模型,并在第一个折叠上测试它。我们对 k 个折叠中的每一个重复这个过程,最后平均所有的测试折叠精度水平,以达到模型的更精确的整体精度。在我的模型中,我使用 k-fold 验证进行超参数调整,每次修改模型时都执行 k-fold,以便找到最佳参数。在逻辑回归的情况下,我遍历 0 到 1 之间的正则化常数,并在 k 倍中选择平均精度最高的常数。K-folds 验证对于随机森林模型非常有用,因为它有更多的模型参数。
在 2000 年至 2017 年赛季进行训练后,逻辑回归算法在 2018 年至 2019 年赛季进行测试时,准确率达到了 58.9%,而同期拉斯维加斯博彩赔率的准确率为 59.4%(从 covers.com 刮来)。然后,我选择将博彩赔率作为输入特性之一合并到我的模型中。这种组合的逻辑回归模型在 2019 赛季达到了 60.5%的准确率,略高于博彩赔率 60.3%的独立准确率。我只能获得追溯到 2014 年的博彩赔率,所以为了保存足够大部分的数据用于训练集,我只在测试期间使用了一个赛季,而不是两个赛季。
随机森林算法
随机森林算法基于决策树的概念。我们所有人每天都在使用决策树;它们仅仅是一系列逻辑的“如果-否则”问题,以最终得出结论。决策树从根节点开始,接着是分支节点和叶节点。为了确定根节点使用什么值,该算法选择最能分离数据的变量。这通常是用基尼系数来计算的。在我们的鳄梨例子中,如果颜色具有最低的基尼杂质(如果大多数绿色鳄梨味道不好,大多数黑色鳄梨味道好),那么逻辑上根节点的第一个 if-else 语句应该是:鳄梨是绿色的吗?直觉上,这是有意义的,因为如果我们知道颜色是区分好的和坏的鳄梨的最好方法,这应该是我们问的第一个问题。在根节点之后,我们将有两条边指向另外两个节点;这一次我们可能会问鳄梨是高于还是低于一定的硬度,基于这一点,我们可以将其分为味道好还是不好。

unsplash.com
单个决策树通常容易过度拟合,并且不能很好地推广到新数据,因为复杂性在每个新节点都会显著增加。一个巧妙的方法来避免这个问题,但保留了决策树的理想属性是随机森林。由许多决策树(称为集合)组成的随机森林通过称为 bagging 或 bootstrapping 的过程从数据集中随机选择样本(替换),以形成每棵树的新训练集。它还将每棵树限制为 N 个特征的随机子集。实践表明, √ N 通常是为每棵树随机选择的最佳特征数。每个人都在他们自己的引导数据集上接受训练,树的联合体,所有不同的结构,最终投票决定是否将数据点分类为 1 或 0。获得最多投票的输出成为算法的预测。随机森林的美妙之处在于,许多不相关的树将共同产生一个较低方差的一致估计,最终比任何单独的决策树更高的真实准确性。
一旦组合,随机森林算法可以通过改变其参数进行微调,以找到最准确的模型,不会过拟合或欠拟合。这一步被称为超参数调整,是一个优化问题,以确定最大深度、树的数量、每棵树的最大特征等的最佳组合。我使用嵌套 for 循环来生成许多不同的参数组合,并且每次都运行 k 重验证,为我的最终模型选择在 k 重中产生最高平均精度水平的组合。最佳的最大深度和最大特征分别是 5 和 4。在 2018 年至 2019 年赛季,随机森林模型在逻辑回归模型的基础上进行改进,达到了 59.6%的准确率,而博彩赔率的准确率为 59.4%。当将博彩赔率作为模型本身的输入变量时,随机森林算法在 2019 年赛季取得了 61.1%的准确率,而拉斯维加斯的赔率为 60.3%。

(图片由作者提供)
下面是随机森林模型和虚拟决策树分类器的特征重要性图表。比尔·詹姆斯的毕达哥拉斯预期显然是最有价值的特征,它重申了一个不言自明的概念,即要赢得比赛,你必须得分比你承认的多。一个更有启发性的观点是,在得分和胜率之后,投球是胜率最重要的决定因素。贪婪的全垒打和强大的进攻能力经常得到大多数媒体和球迷的关注,但也许前台应该更关心投资他们的牛棚。尽管在探索性数据分析中 OBP 和 SLG 与目标变量的相关性更高,但 SP _ ERA 的重要性如此之高,这一事实进一步强调了这一概念。

(图片由作者提供)
最后,我要感谢 Guillermo Reyes 博士(机器学习的数学教授)和 James Faghmous 博士(Python 中应用机器学习的教授),感谢他们这学期让我着迷于机器学习,并在我整个过程的每一步提供了宝贵的建议。
部署到 IBM Cloud Kubernetes 服务的机器学习应用程序
原文:https://towardsdatascience.com/a-machine-learning-application-that-deploys-to-the-ibm-cloud-kubernetes-service-852c2e26732a?source=collection_archive---------34-----------------------
Python、Docker、Kubernetes

Annamária Borsos 摄影
我们将看到,与之前的文章相比,使用 IBM Cloud 创建 Kubernetes 集群非常容易。Kubernetes 丰富的资源可能会让你很难找到基本的东西。简化 Kubernetes 开发并使其易于部署的一个简单方法是使用 IBM Cloud Kubernetes Services 之类的解决方案。为了创建部署到 IBM Cloud Kubernetes 服务的机器学习应用程序,我们需要一个 IBM Cloud 帐户 ( 注册一个免费帐户 ) ,,) IBM Cloud CLI,Docker CLI,Kubernetes CLI。
在 IBM Cloud 上创建 Kubernetes 服务
IBM Cloud 上的 Kubernetes 服务提供了两种集群类型:
-一个空闲集群(一个工作池,带有一个虚拟共享工作节点,具有两个内核、4GB RAM 和 100GB SAN)
-完全可定制的标准集群(虚拟共享、虚拟专用或裸机),适用于繁重的工作。
如果我们只是想探索,自由集群是很棒的。
在 IBM Cloud 中,只需几次点击,我们就可以自动创建一个 Kubernetes 服务。首先,我们需要连接到我们的 IBM 云仪表板。
我们转到 IBM Kubernetes Service,单击 create clusters,为我们的集群键入一个名称,根据我们的帐户(付费或免费),我们可以选择适当的集群类型(在我们的示例中,我们将只创建一个具有 2 个 vCPUs 和 4 个 RAM 的工作节点),几分钟后,集群就创建好了。

来源:作者
一旦集群准备就绪,我们可以单击我们的集群的名称,我们将被重定向到一个新的页面,其中包含有关我们的集群和工作节点的信息。

来源:作者
要连接到我们的集群,我们可以单击 worker node 选项卡来获取集群的公共 IP。

来源:作者
搞定了。我们可以使用 IBM 云外壳进行快速访问。
如果我们想使用自己的终端,我们需要一些先决条件,如果还没有安装的话。我们需要安装所需的 CLI 工具:IBM Cloud CLI、Kubernetes 服务插件(ibmcloud ks)、Kubernetes CLI (kubectl)。
要安装 IBM Cloud CLI,我们将在终端中键入以下内容来安装独立的 IBM Cloud CLI (ibmcloud):
curl -fsSL [https://clis.cloud.ibm.com/install/linux](https://clis.cloud.ibm.com/install/linux) | sh
这是针对 Linux 的。您可以找到自己的发行版所需的所有命令。
我们通过在出现提示时输入我们的 IBM Cloud 凭据来登录 IBM Cloud CLI:
ibmcloud login
如果我们有一个联邦 ID,我们可以使用 IBM Cloud log in–SSO 来登录 IBM Cloud CLI。
否则,我们也可以使用 IBM Cloud API 键进行连接,如下所示:
ibmcloud login — apikey < IBM CLOUD API KEY >
如果还没有完成,我们可以创建一个 IBM Cloud API 密匙。为此,我们需要转到 IBM 云控制台,转到管理>访问(IAM)并选择 API 密钥:

来源:作者
我们可以单击 create an IBM Cloud API key,添加名称和描述,并将 API key 复制或下载到一个安全的位置。由于上面的命令,我们可以登录。
我们可以为 IBM Cloud Kubernetes 服务安装 IBM Cloud 插件(ibmcloud ks):
ibmcloud plugin install container-service
为 IBM Cloud Container Registry 安装 IBM Cloud 插件(ibmcloud cr):
ibmcloud plugin install container-registry
我们还可以安装 IBM Cloud Kubernetes 服务可观察性插件(ibmcloud ob)
ibmcloud plugin install observe-service
我们的环境中已经安装了 Kubernetes CLI。如果还没有安装,只需按照几个步骤这里。
如果我们想列出客户中的所有集群:
ibmcloud ks cluster ls

来源:作者
我们可以通过运行以下命令来检查我们的群集是否处于健康状态:
ibmcloud ks cluster get -c IBM_Cloud_node
这里, IBM_Cloud_node 是我们的集群名;您还可以使用集群的 ID。

来源:作者
机器学习应用程序的容器化
这个简单的例子将展示如何使用 Python API 和 Flask 创建一个 Docker 容器,通过一个训练有素的机器学习模型来执行在线推理。为此,我们将使用 scikit-learn 和 Iris 数据集训练一个简单的 C-支持向量分类模型,我们将把它分成训练数据和测试数据。
首先,让我们考虑以下文件:
Dockerfile
train.py
api.py
requirements.txt
你可以在 GitHub 上找到所有的文件。
train.py 是一个 python 脚本,用于加载和训练我们的模型。 Dockerfile 将用于构建我们的 Docker 映像,requirements.txt (flask,flask-restful,joblib)用于 Python 依赖关系,而 api.py 是将被调用来使用 api 执行在线推理的脚本。
train.py 文件如下:
我们还需要构建一个 API 来接收数据(X_test)并输出我们想要的东西。在我们的例子中,我们将只请求模型的分类分数:
我们现在已经准备好容器化你的烧瓶应用程序。在我们的项目目录中,我们用 jupyter/scipy-notebook 映像创建了我们的 Dockerfile ,设置了我们的环境变量并安装了 joblib 和 flask ,我们将 train.py 和 api.py 文件复制到映像中。
我们想公开 Flask 应用程序运行的端口(5000 ),所以我们使用 expose。
为了检查我们的应用程序是否运行正常,让我们在本地构建并运行我们的映像:
docker build -t my-kube-api -f Dockerfile .

来源:作者
docker run -it -p 5000:5000 my-kube-api python3 api.py

来源:作者
我们现在可以使用 curl 测试应用程序:
curl [http://172.17.0.2:5000/](http://172.17.0.2:5000/line/232)score

来源:作者
一切正常。
将映像推送到 IBM 云注册中心
有用!既然我们的应用程序工作正常,我们可以进入下一步,在 Kubernetes 集群中部署它。在此之前,我们需要将图像推送到存储库。这里,我们将在 IBM Cloud Registry(一个私有存储库)上推送映像。从我们的帐户仪表板中,我们可以选择集装箱注册:

来源:作者
我们需要使用以下命令在本地安装容器注册插件:
ibmcloud plugin install container-registry -r “IBM Cloud”

来源:作者
然后,我们登录我们的帐户:
ibmcloud login
然后,我们命名并创建我们的名称空间:
ibmcloud cr namespace-add xaviervasques

来源:作者
我们使用以下命令将本地 Docker 守护进程登录到 IBM Cloud Container 注册表中:
docker login -u iamapikey -p <YOUR API KEY> de.icr.io
我们选择一个存储库和标签,通过它我们可以识别图像:
docker tag my-kube-api de.icr.io/xaviervasques/my-kube-api:latest
而我们推送图像(docker 推送 <region_url>/
docker push de.icr.io/xaviervasques/my-kube-api:latest

来源:作者
我们可以通过检查图像是否在我们的私有注册表上来验证图像的状态:
ibmcloud cr image-list
将应用程序部署到 Kubernetes
一旦图像上传到私有注册中心,我们就可以将应用程序部署到 Kubernetes。我们可以使用用户界面或 CLI。对于本章,我们将使用 CLI。我们使用上面的步骤创建我们的 Kubernetes 集群(我们也可以使用命令行创建一个:IBM cloud ks cluster create classic–name my-cluster)。要查看状态,我们键入以下命令:
ibmcloud ks clusters

来源:作者
我们的 my-k8s Kubernetes 集群已经启动并运行。我们可以将 kubectl 连接到集群:
ibmcloud ks cluster config — cluster my_k8s
我们可以检查我们是否连接到集群:
kubectl get nodes

来源:作者
我们将在主节点中创建一个名为“base”的文件夹,并在其中创建以下 YAML 文件:
o namespace.yaml
o 部署. yaml
o service.yaml
o service_port.yaml
o kustomization.yaml
namespace.yaml 文件提供了 Kubernetes 资源的范围:
这个部署. yaml 将让我们管理一组相同的吊舱。如果我们不使用部署,我们将需要手动创建、更新和删除一组 pod。这也是一种轻松自动缩放应用程序的方式。在我们的示例中,我们决定创建两个 pod(副本),加载我们之前推送的 Docker 映像,并运行我们的 api.py 脚本。
service.yaml 文件将我们在一组 Pods 上运行的应用程序作为网络服务公开。
我们还需要创建 service_port.yaml 文件:
我们创建 service_port.yaml 文件的原因是,通过使用 Kubernetes 集群中任何工作节点的公共 IP 地址并公开一个节点端口(node port ),可以通过互联网访问我们的容器化应用程序。我们可以使用这个选项来测试 IBM Cloud Kubernetes 服务和短期的公共访问。
最后,我们创建了 kustomization.yaml 文件:
我们可以配置自己的镜像 pull secret,在 Kubernetes 名称空间而不是默认名称空间中部署容器。通过这种方法,我们可以使用存储在其他 IBM Cloud 帐户中的图像,或者存储在外部私有注册表中的 us 图像。此外,我们可以创建自己的映像 pull secret 来执行 IAM 访问规则,这些规则限制对特定注册表映像名称空间或操作(如 push 或 pull)的权限。我们有几个选项可以做到这一点,其中之一是将图像获取秘密从 Kubernetes 的默认名称空间复制到我们的集群中的其他名称空间。
让我们首先列出集群中的名称空间:
kubectl get namespaces

来源:作者
然后,让我们列出 IBM Cloud Container 注册表的 Kubernetes 默认名称空间中的图像提取秘密:
kubectl get secrets -n default | grep icr-io

来源:作者
为了部署我们的应用程序,我们在主节点中使用这个命令:
kubectl apply — kustomize=${PWD}/base/ — record=true
我们将 all-icr-io 图像提取秘密从默认名称空间复制到我们选择的名称空间。新的图像获取秘密被命名为<名称空间 _ 名称> -icr- <区域> -io:
kubectl get secret all-icr-io -n default -o yaml | sed ‘s/default/mlapi/g’ | kubectl create -n mlapi -f -
我们检查秘密的创建是否成功:
kubectl get secrets -n mlapi | grep icr-io
要查看部署到此名称空间中的所有组件:
kubectl get ns
我们应该获得以下输出:

来源:作者
要查看部署的状态,我们可以使用以下命令:
kubectl get deployment -n mlapi

来源:作者
要查看服务的状态,我们使用以下命令:
kubectl get service -n mlapi

来源:作者
我们可以获得集群中一个工作节点的公共 IP 地址。如果您想要访问专用网络上的工作节点,或者如果您有一个 VPC 集群,请获取专用 IP 地址。
ibmcloud ks worker ls — cluster my_k8s
我们现在可以通过 curl 或您的 web 浏览器来使用我们的部署模型了:
curl [http://172.21.193.80:31261/score](http://172.21.193.80:31261/score)

来源:作者
我们还浏览我们的 Kubernetes 仪表盘并查看我们的服务和许多功能:

来源:作者
后续步骤
当我们致力于将机器学习/深度学习模型投入生产时,在某个时间点会出现一个问题。我在哪里部署我的代码用于训练,在哪里部署我的代码用于批量或在线推理。我们经常需要在多架构环境和混合/多云环境中部署我们的机器学习流程。我们已经了解了如何在 IBM Cloud 上部署应用程序,以及如何部署本地/虚拟机。Kubernetes 可以在各种平台上运行:从简单的集群到复杂的集群,从我们的笔记本电脑到多架构、混合/多云 Kubernetes 集群。问题是什么是最适合我们需求的解决方案。
来源
https://developer . IBM . com/technologies/containers/tutorials/scalable-python-app-with-kubernetes/
https://cloud . Google . com/community/tutorials/kubernetes-ml-ops
https://github.com/IBM/deploy-ibm-cloud-private
https://kubernetes . io/fr/docs/setup/pick-right-solution/# solutions-clés-en-main
https://www . IBM . com/cloud/architecture/tutorials/micro services-app-on-kubernetes?任务=1
https://cloud.ibm.com/docs/containers?topic = containers-registry #其他
https://cloud.ibm.com/docs/containers?topic=containers-nodeport
https://cloud.ibm.com/docs/containers
使用 U-net 进行多类图像分割的迁移学习的机器学习工程师教程
原文:https://towardsdatascience.com/a-machine-learning-engineers-tutorial-to-transfer-learning-for-multi-class-image-segmentation-b34818caec6b?source=collection_archive---------3-----------------------
图像分割模型调试指南

从二元到多类分割任务的 U-net 模型(图片由作者提供)
图像语义分割是计算机视觉领域中最重要的研究和工程领域之一。从自动驾驶的行人和汽车分割[1]到医学图像中病理的分割和定位[2],有几个图像分割的用例。随着深度学习模型广泛用于机器学习(ML)模型的端到端交付,U-net 模型已经成为跨自动驾驶和医疗成像用例的可扩展解决方案【3–4】。然而,大多数现有的论文和方法执行二元分类任务来检测背景上的感兴趣的对象/区域[4]。在本实践教程中,我们将回顾如何从二进制语义分割任务开始,并转移学习以适应多类图像分割任务。
对于一个 ML 工程师来说,在他们的日常工作流程中最大的挫折之一就是花数小时训练一个 ML 模型,结果却毫无意义,比如输出的不是数字 (NaN)或者全是 0 值的图像。在本教程中,我们将通过一个二进制 U-net 模型扩展到多类语义分割的示例,学习从现有作品(论文/代码库)开始 ML 模型构建过程的逐步过程,并对其进行重大修改,以适应您自己的数据需求。
如图 1 所示,U-net 模型表示编码层和解码层以及编码层和各个解码层之间的跳跃连接。跳过连接的主要优点是,它将每个深度层的编码和解码结果相结合,以实现前景(需要输出为白色的像素)与背景(需要输出为黑色的像素)之间的一致分离。

图 1:深度=4 的 U 网模型的例子。左边的层是导致提取密集特征的编码器层,后面是右边的解码器层。灰色箭头表示跳过连接。来源:https://www . dlology . com/blog/automatic-defect-inspection-with-end-to-end-deep-learning/
最终目标是为新的代码库优化调整模型超参数,我们从[5]中现有的 U-net 代码库开始,该代码库使用视网膜图像数据集[6]上的二进制语义分割,以使用 DIARETDB1 数据集[7–8]修改用于视网膜图像病理学多类分类的代码库。病理学分类为亮病变(BL),由“硬渗出物”和“软渗出物”表示,红色病变由“出血”和“红色小点”表示[8]。
数据模型转换的三个主要步骤如下:1)数据准备 2)数据模型和过程 3)结果和度量。
第一步:数据准备:从二进制到多类
构建端到端 ML 模型的第一步是基准测试,这包括尽可能复制现有的代码库/文件。如果这需要修改当前数据集,使其与现有工作的数据相似,那么就应该这样做。
从[5]中的 U-net 代码库开始,对于我们手头的多类病理学分类任务,我们首先复制 U-net 代码库[5]用于单一病理学,出血检测任务。使用下面的代码将带注释的图像遮罩( Y ,表示标签)二进制化。
产生的出血标记显示在下面的图 2 中。


图 2(左):显示灰度出血遮罩(Y)。2(右)显示了通过阈值处理(Y>0.1)获得的二值化出血掩模(图片由作者提供)
医学图像数据集通常会带来“小数据挑战”的问题,即训练样本有限。为了解决这个问题,经常使用使用 Keras 的图像数据增强。这种方法的目标是在运行时生成单个图像及其遮罩的多个放大/缩小、旋转、平移/缩小等价物。下面显示的数据生成器有助于实现这一点。
当在具有很少样本的数据集上训练时,一个重要的考虑是,被训练的模型有被样本像素中的类别不平衡严重偏向的趋势。例如,[8]中的数据集包含 89 幅图像,但是只有大约 30 幅图像包含对应于病理学的大的感兴趣区域。剩下的标记图像大多是 *Y=0。*因此,如果用所有图像训练一个模型,将倾向于预测大多数图像为 Y=0 ,这意味着病理将大部分被遗漏。为了避免这个问题,并将图像数据分为训练集和测试集,我们使用图像 ID 1–27 进行训练,而图像 ID 28–89 仅用于测试。
当从二进制分段迁移到多类分段时,第一个要求是适当地格式化数据。给定原始图像 X 和标签 Y ,则 X 的维数为【m×m×r】,Y 为【m×m×d】,其中输入 U-net 模型的图像维数为 m=256,r=3 (RGB 图像),d 表示多类分类的类数(此处 d=4)。U-net 模型的要求是输入和输出必须属于相同的域/维度,在本例中为[m x m]。唯一的区别是输入 X 可以是彩色或灰度图像,而输出 Y 表示对应于每个病理掩模的二进制图像平面。因此,每个输出图像平面代表像素级的一对一分类。使用下面的代码生成一个图像遮罩示例,用于红色平面中的红色损伤(组合了“出血”和“红色小点”),绿色平面和背景蓝色平面中的明亮损伤(组合了“硬渗出物”和“软渗出物”)。
结果如下图 3 所示。

图 3:为视网膜病理学数据集生成的多类基础事实标签。红色平面代表“出血”和“红点”,绿色平面代表“硬渗出物”和“软渗出物”。(图片由作者提供)
第二步:数据模型和流程
训练最佳 ML 模型的关键任务涉及超参数优化,这涉及选择最佳参数集,以确保深度学习 U-net 模型的权重和偏差非常合适。我们为以下项目执行超参数选择:
- 编译器(Adam)
- 学习率(0.0001)
- 精度指标:要最大化的骰子系数[9]
- 损失度量:负骰子系数(要最小化)
准确性度量和损失度量的其他选项是“准确性”和“分类 _ 交叉熵”,以及“样本 _ 权重=时间”[10]以迎合数据不平衡。
另一个需要调整的模型参数是模型复杂度(即由 U-net 的大小强加的训练复杂度)。因此,需要在深 U 网(深度=4)和浅 U 网(深度=3)上进行训练,图表如下所示。参数较少的模型通常最适合“小数据挑战”。深度为 3 和 4 的模型的变化可以在[11]中看到。

图 4(左)深度=4 的 U 形网。从 Tensorboard 获得的深度=3 的 4(右)U 形网。(图片由作者提供)
在模型训练结束时,损失曲线证明了训练过程的有效性。我们实施的损耗曲线如下图 5 所示。

图 5:二元分割(橙色曲线)与多类分割(蓝色曲线)的张量板损失和准确性度量。多类计算复杂度明显高于二进制分割。(图片由作者提供)
第三步:成果和指标
一旦模型被训练,最后的任务是评估测试数据。定性地,结果如图 6 所示。

图 6:用 40 次运行后训练的模型演示二元和多类语义分割。(图片由作者提供)
对于定量评估,我们考虑以下指标:精确度、召回率、准确度、交集/并集(IoU)和 F1 分数[9] [12],如下所示在二元分割之后。

输出可以在 Github [11]中找到。多类分割中的一个关键部分是使用下面给出的多维 Dice 系数损失。
由于输出 Y 有“d”平面,第一个任务是展平平面,如图[13]和图 7 所示。,随后计算组合骰子系数。因此,多类分割的 Dice 系数在所有输出平面上是相加的,因此它可以超过值 1。

图 7:来自[13]的图像展平的例子。对于 4 维输出 Y,输出被平坦化,随后对平坦化的输出进行 Dice 系数评估。因此,Dice 系数在这种情况下是相加的。(图片由作者提供)
最后,多类分割的定量评估涉及所报告的宏观和微观级别的度量。虽然宏观水平的精度、召回率、准确度、IOU 和 F1 分数对所有类别的权重相等,但微观水平的指标在类别不平衡的情况下更可取,以提供加权结果,如[14]所示。
结论
将学习从现有的 ML 模型转移到新的数据集和用例需要一个战略性的工作流来确保最佳的数据建模。关键在于将工作流程构建为:数据、流程和结果。使用本教程中介绍的分步指南,将有可能将 U-net 模型不仅扩展到其他二元分类任务,而且扩展到多类分类任务。其他处理多类分割的代码库在[15]中。
为了进一步提高本教程中显示的性能,可以针对所有红色和明亮的病变组合更大的图像尺寸和一对一对所有分割方法。此外,为了将教程扩展到更多的类,增加的结果“Y”可以保存为。npy 文件而不是图像,并且可以使用 load 命令来加载增强数据而不是 load_img(仅输入 3D 图像数据)。)使用所提出的方法,读者现在应该具备从现有代码库学习并根据自己的需要修改它们的手段和方法,同时扩展模型和方法的范围。
参考文献
[1] Piccoli,Francesco,等人,“FuSSI-Net:意图预测网络的时空骨架融合”arXiv 预印本 arXiv:2005.07796 (2020)。
[2]罗伊乔杜里,索希尼。"减少医学图像中观察者间可变性的少数镜头学习框架." arXiv 预印本 arXiv:2008.02952 (2020)。
[3]张、、刘庆杰、王."用深度残差 u 网提取道路." IEEE 地球科学与遥感快报15.5(2018):749–753。
4 拉金先生。“查看我们毕业生的最终项目”。[Online]https://blog . fourth brain . ai/check-out-our-graduates-final-projects?UTM _ campaign = Project % 20 presentation % 20 day&UTM _ source = TDS-blog&UTM _ medium = blog&UTM _ term = ml 调试指南&UTM _ content = ml-调试指南
[5]罗伊乔杜里。“使用 TF 2.x 进行医学图像分割的 Unet”【在线】https://github.com/sohiniroych/Unet-using-TF2
[6]胡佛。“凝视计划”。https://cecas.clemson.edu/~ahoover/stare/probing/index.html
[7] Roychowdhury、Sohini、Dara D. Koozekanani 和 Keshab K. Parhi。"梦:使用机器学习的糖尿病视网膜病变分析." IEEE 生物医学和健康信息学杂志18.5(2013):1717–1728。
[8]Singh,Ramandeep 等,“糖尿病性视网膜病变:最新进展”印度眼科学杂志 56.3 (2008): 179。
[9]E Tiu。“评估您的语义细分模型的指标”。【在线】https://towards data science . com/metrics-to-evaluate-your-semantic-segmentation-model。
[10]栈溢出[在线]U-net:如何提高多类分割的准确性?
[11]罗伊乔杜里。“用于多类语义分割的 U-net”。【在线】https://github . com/sohiniroych/U-net-for-Multi-class-semantic-segmentation
12h .库马尔。对象检测和分割的评估度量:mAP[Online]https://kharshit . github . io/blog/2019/09/20/evaluation-metrics-for-object-detection-and-segmentation
[13]https://stack overflow . com/questions/43237124/what-of-the-role-of-flatten-in-keras
[14]数据科学堆栈交换。多类分类设置中的微观平均与宏观平均性能[在线]:https://data science . stack exchange . com/questions/15989/微观平均与宏观平均性能多类分类设置
[15]托尼。Unet:使用 Keras 进行多重分类【在线】https://github . com/hzc Tony/U-net-with multi-class ification
机器学习模型监控清单:要跟踪的 7 件事
原文:https://towardsdatascience.com/a-machine-learning-model-monitoring-checklist-7-things-to-track-2042be98a7b5?source=collection_archive---------28-----------------------
如何监控您的模型以及使用哪些开源工具

图片作者。
**建立一个机器学习模型并不容易。**在生产中部署服务更加困难。但是,即使你设法把所有的管道粘在一起,事情也不会就此停止。
一旦模型投入使用,我们必须立即考虑如何平稳地操作它。毕竟,它现在正在提供商业价值!模型性能的任何中断都会直接转化为实际的业务损失。
**我们需要确保模型交付。**不只是作为一个返回 API 响应的软件,而是作为一个我们可以信任来做出决策的机器学习系统。
这意味着我们需要监控我们的模型。而且还有更多的东西要找!
如果生产中的 ML 让你措手不及,这里有一个需要注意的清单。
1.服务健康
机器学习服务还是服务。您的公司可能已经建立了一些您可以重用的软件监控流程。如果模型实时运行,它需要适当的警报和负责任的人员随叫随到。
即使您只处理批量模型,也不要例外!我们仍然需要跟踪标准的健康指标,比如内存利用率、CPU 负载等等。
我们的目标是确保服务正常运行,并遵守必要的约束条件,例如响应速度。
一个开源工具来检查: Grafana 。
2。数据质量&完整性

图片作者。
机器学习模型有问题吗?在绝大多数情况下,数据是罪魁祸首。
**上游管线和模型断裂。**用户突然改变了模式。数据可能在源头消失,物理传感器失效。这样的例子不胜枚举。
因此,验证输入数据是否符合我们的期望是至关重要的。检查可能包括范围符合性、数据分布、要素统计、相关性或我们认为对数据集“正常”的任何行为。
我们的目标是确认我们正在输入模型可以处理的数据。在它返回不可靠的响应之前。
一个开源工具查: 远大前程 。
3。数据&目标漂移
事情变了。即使我们处理非常稳定的过程。几乎每个机器学习模型都有这个不方便的特质:会随着时间退化。
当模型接收到训练中未见过的数据时,我们可能会经历 数据漂移 **。**假设用户来自不同的年龄组、营销渠道或地理区域。

数据漂移的一个例子。图片作者。
如果现实世界的模式发生变化,漂移的概念就会出现。想象一下像全球疫情这样影响所有顾客行为的偶然事件。或者市场上提供大量免费层的新竞争产品。它改变了用户对你营销活动的反应。

概念漂移的一个例子。图片作者。
这两种漂移的最终衡量标准是模型质量的下降。但是有时候,实际值还不知道,我们无法直接计算出来。在这种情况下,有先行指标可以跟踪。我们可以监视输入数据或目标函数的属性是否发生了变化。
**例如,您可以跟踪关键模型特征和模型预测的分布。**然后,如果它们明显不同于过去的时间范围,则触发警报。

截图来自显然是的报道。
我们的目标是获得世界或数据发生变化的早期信号,是时候更新我们的模型了。
一个开源工具检查: 显然是 。
4.模型性能
要知道你的模型是否运行良好,最直接的方法就是将你的预测与实际值进行对比。您可以使用模型训练阶段的相同指标,无论是分类的精度/召回率,还是回归的 RMSE,等等。如果数据质量或现实世界的模式发生了问题,我们将会看到指标下降。

截图来自显然是的报道。
这里有一些警告。
首先,事实真相或实际标签通常会有延迟。例如,如果你做一个长期的预测,或者数据传递有滞后。有时你需要额外的努力来标记新的数据,以检查你的预测是否正确。在这种情况下,首先跟踪数据和目标漂移作为早期警告是有意义的。
第二,人们不仅需要跟踪模型质量,还需要跟踪相关的业务 KPI。ROC AUC 的下降并不能直接说明它对营销转化有多大影响。将模型质量与业务度量联系起来或者找到一些可解释的代理是至关重要的。
**第三,你的质量度量应该适合用例。**例如,如果您有不平衡的类,准确性度量就很不理想。对于回归问题,您可能会关心错误符号。因此,您不仅应该跟踪绝对值,还应该跟踪误差分布。区分偶然的异常值和真正的衰退也很关键。
所以明智地选择你的衡量标准吧!

我们的目标是跟踪模型服务于其目的的程度,以及当出现问题时如何调试它。
一个开源工具来查: 显然是 。
5。按部门划分的业绩
对于许多型号,上述监控设置就足够了。但是如果您处理更关键的用例,就有更多的项目需要检查。
比如模型哪里出错多,哪里做的最好?
**你可能已经知道一些要跟踪的特定细分市场:**比如你的高端客户相对于总体客户的模型准确性。它需要一个自定义的质量指标,只为您定义的段内的对象进行计算。
**在其他情况下,主动搜索低性能的部分是有意义的。**假设您的房地产定价模型在某个特定的地理区域一贯显示高于实际的报价。这是你想要注意的事情!
根据用例,我们可以通过在模型输出之上添加后处理或业务逻辑来解决这个问题。或者通过重建模型来说明表现不佳的部分。

我们的目标是超越总体性能,了解特定数据切片的模型质量。
6.偏见/公平
当涉及到金融、医疗保健、教育和其他模型决策可能有严重影响的领域时,我们需要更加仔细地检查我们的模型。
例如,基于不同人口统计组在训练数据中的表示,不同人口统计组的模型性能可能不同。模型创建者需要意识到这种影响,并拥有与监管者和利益相关者一起减轻不公平的工具。
为此,我们需要跟踪合适的指标,比如准确率的奇偶校验。它适用于模型验证和持续生产监控。因此,仪表板上还有一些指标!
我们的目标是确保公平对待所有子群体,并跟踪合规情况。
一个开源工具来检查: Fairlearn 。
7.极端值
我们知道模型会出错。在一些用例中,比如广告定位,我们可能并不关心单个输入是奇怪的还是正常的。只要它们不构成模型失败的有意义的部分!
在其他应用程序中,我们可能希望了解每个这样的情况。为了最小化错误,我们可以设计一套规则来处理异常值。例如,让他们进行人工审核,而不是自动做出决定。在这种情况下,我们需要一种方法来检测并相应地标记它们。
我们的目标是标记模型预测不可信的异常数据输入。
一个开源工具检查: 谢顿不在场证明-检测

监控听起来可能很无聊。但是,让机器学习在现实世界中发挥作用是至关重要的。不要等到模型失败才创建你的第一个仪表板!
最初发表于https://www.kdnuggets.com并与Emeli Dral合著。
更多关于生产机器学习的内容,请查看 我们的博客 和关于 ML 监控和验证的动手 教程 。
一个主要的 Seaborn 策划技巧,我希望我能早点学会
原文:https://towardsdatascience.com/a-major-seaborn-plotting-tip-i-wish-i-had-learned-earlier-d8209ad0a20e?source=collection_archive---------11-----------------------
实践教程
了解 Seaborn 中的轴级、图形级和对象级绘图

来自 Unsplash 上的詹姆斯·哈里森(@jstrippa)
Seaborn 是一个非常棒的绘图库,我希望我能在我的 Python 载体中早点开始使用它。我一直是 Matplotlib 的用户,我会花几个小时在一些项目上微调我的绘图美学,以便它们在演示过程中真正吸引同事的注意。我的第一个私家侦探总是说,如果你不出席一个有阴谋的会议,你就没有准备好,所以我总是做好准备。我一点也不知道 Seaborn 在 Python 中绘图是多么简单,尽管它比 Matplotlib 产生了更具视觉吸引力的固定绘图。
数据
我们将使用一个关于企鹅的基本的 Seaborn 数据集,其中有关于几个物种种群的各种记录信息。我们可以查看下面的数据框架:
pen = sns.load_dataset('penguins')pen.head()

企鹅数据集
图形级和轴级功能
Seaborn 的代码基础有一个平面名称空间。Seaborn 中的所有功能都是从顶层访问的,但是代码仍然有层次结构。有几个模块的功能可能通过不同的方式实现相同的目标。
当我第一次开始使用 Seaborn 时,我很困惑为什么有时包装 Matplotlib 样式会改变我的 Seaborn 图,但其他时候 Matplotlib 样式不会像预期的那样工作。这是因为一些函数将数据绘制到一个matplotlib.pyplot.Axes对象上,而其他函数通过一个 Seaborn 对象与 Matplotlib 接口。这些分别被称为轴级和图形级功能。
在层次结构中,轴级功能位于图形级功能之下。例如,sns.displot()是一个图形级功能,包含了histplot、kdeplot、ecdfplot和rugplot轴级功能。Seaborn 中的每个模块都有一个图形级函数,可以创建底层轴级函数的任何类型的绘图。然而,正因为displot() 可以创建所有四种类型的图,使用图形级功能或更具体的轴级功能有其优点和缺点。
看看如何创建一个简单的 KDE 图,显示按物种划分的喙深度的核心密度:
图级
fig_lvl = sns.displot(data=pen, x='bill_depth_mm', hue='species', kind='kde', fill=True)

数字级 KDE 图

数字级别类型
轴水平
fig_ax = sns.kdeplot(data=pen, x='bill_depth_mm', hue='species', shade=True)

轴级 KDE 图

坐标轴图形类型
这两幅图看起来非常相似。我们可以看到图级函数以 plot 的kind作为自变量。他们也生产两种不同的物品。
另外,请注意为了给它们加阴影,我使用了不同的关键字参数。有了sns.displot(),我需要fill=True,而sns.kdeplot()需要shade=True;使用sns.kdeplot()时,关键字fill用纯色填充曲线,而不是更不透明的阴影曲线。寻找sns.displot()的关键字参数可能很困难,因为它适应多种类型的图*。*
考虑
造型
当我们使用轴级绘图时,我们实际上是在使用一个看起来很漂亮的 Matplotlib 对象。这给我们留下了大量的 Matplotlib 功能的进一步定制工作,许多人已经习惯于使用这些功能。
另一方面,Seaborn 样式可能更复杂,因为每种体形类型下都存在多种类型的绘图。由于这种内部层次结构,像sns.displot()这样的函数的文档字符串不会包含所有可用的参数,因为有些参数只适用于某些类型的绘图。然而,一旦你习惯了为 Seaborn figures 寻找关键词的困难,它们就能很好地工作,并提供一些非常有用的工具。
兼容性
当我们创建一个 Seaborn 图形级别的绘图时,它是在自己的轴上绘制的,该轴是在创建时启动的。这意味着我们不能在现有的轴上使用 Seaborn 图形级别的绘图。然而,Seaborn 有一些锦囊妙计来轻松创建网格图,我们将在下面讨论。
轴级绘图是 Matplotlib 对象,可以像任何其他 Matplotlib 图形一样对待。它们可以被捆绑成一个用 Matplotlib 制作的支线剧情网格,当你制作大量不同的剧情时,这真的很有用。除了更容易遵循文档,Matplotlib 兼容性是轴级绘图的最大优势之一。
让我们看看在使用 Matplotlib 子图时,如何使用 Seaborn 轴级函数:
fig, ax = plt.subplots(1,2,figsize=(8,4), gridspec_kw=dict(width_ratios=[4,3]))sns.scatterplot(data=pen, x='bill_depth_mm',y='body_mass_g', hue='species', ax=ax[0])sns.kdeplot(data=pen, x='bill_depth_mm', hue='species', shade=True, ax=ax[1])fig.tight_layout()

Matplotlib 子图中的 Seaborn 轴级图形
更改图形大小和标记轴
我经常对一个新的地块做的头两件事是使它和我的其他地块大小一致,并标记轴。使用 Matplotlib,调整图的大小和标记轴是许多人熟悉的任务,虽然 Seaborn 不同,但它仍然非常简单。
轴级
轴级绘图使用标准的 Matplotlib 图形实例化来确定大小,并使用 Matplotlib 命令来设置每个轴标签。
plt.figure(**figsize**=(12,6))fig_ax = sns.histplot(data=pen, x='bill_depth_mm', hue='species', multiple='stack')plt.**xlabel**('Bill Depth (mm)')

用轴设置标签和大小-标签图
图级
当创建图形和 Seaborn 自己的轴标签函数时,图形级绘图使用height和aspect参数。
fig_lvl = sns.displot(data=pen, x='bill_depth_mm', hue='species', multiple='stack', kind='hist', **height**=5, **aspect**=2)fig_lvl.**set_axis_labels**("Bill Depth (mm)")

使用图形级别的绘图设置标签和大小
带有 Seaborn 数字级情节的支线情节
我们可以使用 Seaborn 创建一些非常有用的绘图网格,通过分类变量自动分隔日期。用 Matplolib 做这件事可能要做更多的工作,包括设置数据子集和为每个轴创建单独的图。
fig_lvl = sns.relplot(data=pen, x='bill_depth_mm', y='body_mass_g', **col**='species', kind='scatter')fig_lvl.set_axis_labels("Bill Depth (mm)", "Body Mass (g)")

图级散点图很容易被分类变量划分
将 Matplotlib 与子情节一起使用
这种绘图也可以用 Matplotlib 完成,但是需要更多的思考。我是这样做的:
species = pen['species'].unique()
fig, ax = plt.subplots(1,3,figsize=(16,6))for a, spec_name in zip(ax,species):
df = pen[pen['species'].str.match(spec_name)]
a.scatter(x=df['bill_depth_mm'], y=df['body_mass_g'],s=15)
a.set_xlim([10,23])
a.set_ylim([2000,6500])
a.set_title(spec_name)

带有 Matplotlib 的支线剧情
我选择使用一个 for 循环来遍历每个轴和每个物种名称。通过这种方式,您可以设置 x 和 y 边界,而不必为每个轴重复相同的代码。这比 Seaborn 需要更多的工作和考虑。我必须手动按物种划分子集,制作正确数量的支线剧情,并对所有数据设置合理的 x/y 限制;Seaborn 自动完成所有这些工作!相当不错。
对象级绘图
当您使用图形级函数sns.displot()来创建直方图时,对象类型是seaborn.axisgrid.FacetGrid,这意味着它是一个与要显示的 Matplotlib API 接口的 Seaborn FacetGrid对象。我们还可以直接使用对象来创建一个图,这将打开进一步的定制。
fig_obj = sns.FacetGrid(pen, col='species', margin_titles=True, height=6)fig_obj.map(plt.scatter, "bill_depth_mm", "body_mass_g", s=30)fig_obj.set(xlim=(10,23),ylim=(2000,6500))fig_obj.set_axis_labels("Bill Depth (mm)", "Body Mass (g)", fontsize=14)

对象级绘图
这个散点图看起来和我们的图形级sns.relplot()图一样,但是通过 Seaborn FacetGrid对象利用了plt.scatter。这是使用 Matplotlib 实现这种绘图的更简单的方法。要使用 Matplotlib 语法进一步调整您的绘图,您可以向map()调用添加更多的关键字参数,或者使用fig_obj.set()函数。您也可以使用类似fig.et_axis_labels()的 Seaborn 图形级绘图函数。
对象提供了灵活性
对于 Seaborn 对象,我们可以做更多的事情。它们更难使用;通常,您可能需要打开两页(或更多页)的文档才能获得您正在寻找的所有参数。但是这些额外的工作得到了一些很好的回报,比如通过数据变量实现简单的分面。
fig = sns.FacetGrid(pen, col="island", hue="species", aspect=.75, height=3.5)fig.map_dataframe(sns.scatterplot, x="bill_depth_mm", y="body_mass_g")fig.set_axis_labels("Bill Depths (mm)", "Body Mass (g)")fig.add_legend()

使用 sns.scatterplot 的 Seaborn FacetGrid 图
包扎
这将节省您理解 Seaborn 中存在的功能层次的时间。大多数情况下,轴级函数是最直接的选择。文档更容易查找和遵循,如果您决定将它们包含在其他 Matplotlib 图中,它们也是兼容的。
正如我们通过使用relplot()按照上面的分类变量分割一个图所看到的,Seaborn figures 使得一些可视化的创建比 Matplotlib 简单得多。因此,虽然大多数基本绘图可以创建为 Matplolib axes 对象,但也有使用 Seaborn Figure 对象的良好用例。Seaborn 可能旨在为用户提供简单性,但它具有高级功能,有助于完善您在 Python 中的绘图目标。
证明文件
- 海博恩
- Matplotlib
声明:本文所有情节均由我为此而作。
数学爱好者的隐马尔可夫模型指南
原文:https://towardsdatascience.com/a-math-lovers-guide-to-hidden-markov-models-ad718df9fde8?source=collection_archive---------3-----------------------
它们是如何工作的,以及它们为什么被“隐藏”起来。
隐马尔可夫模型可以用于研究这样的现象,其中只有一部分现象可以被直接观察到,而其余部分不能被直接观察到,尽管它的影响可以在所观察到的事物上感觉到。未观察到的部分的影响只能估计。
我们使用两个随机过程的混合来表示这种现象。
这两个过程之一是一个“可见过程”。它用于表示现象的可观察部分。使用合适的回归模型,如 ARIMA 、整数泊松模型或曾经流行的线性模型,对可见过程进行建模。无法观察到的部分由一个“隐藏过程表示,其中使用马尔可夫过程模型建模。
如果你是马尔可夫过程的新手,请阅读下面的文章,然后回到这里继续阅读:
一个隐马尔可夫模型的真实例子
让我们来说明如何使用隐马尔可夫模型来表示真实世界的数据集。
下图显示了美国的月失业率:

美国月度失业率(数据来源:美国弗雷德在公共领域许可下)(图片由作者提供)
上图显示了大范围的正增长和负增长区域。我们假设有一些观察者不知道的隐藏过程在起作用,在两种“制度”之间摇摆不定,当前的制度实际上正在影响观察到的通货膨胀率趋势。
在对上述数据集建模时,我们将考虑一个回归模型,它是以下两个随机变量的混合**:**
- 可观察的随机变量 y_t, 用于表示失业率的可观察模式。在每个时间步 t , y_t 就是在 t 的失业率的观察值。
- 一个隐藏的随机变量s _ t它被假定改变它的状态或制度,而每次制度改变,它都会影响观察到的就业模式。换句话说,值 s_t 的变化会影响 y_t 的均值和方差。这是隐马尔可夫模型背后的主要思想。
我们来看看如何精确表达 y_t 和 s_t 之间的这种关系。现在,让我们假设 s_t 在两种状态 1 和 2 之间切换。
重要的问题是:为什么我们称 s_t 为‘隐藏’随机变量?
我们称之为隐藏的,因为我们不知道它何时改变其状态。如果我们知道在每一个时间点上哪个机制是有效的,我们将简单地使 s_t 成为一个回归变量,我们将在 s_t 上回归 y_t !
隐藏随机变量 s_t 的公式
对于失业数据集,我们将假设 s_t 服从具有以下状态转移图的两状态马尔可夫过程:

一个 2 态马尔可夫过程(图片由作者提供)
上面所示的马尔可夫链有两种状态,或者说是编号为 1 和 2 的状态。在这两种状态之间有四种可能的状态转换:
- 状态 1 到状态 1: 这个转换以概率*p11 发生。
从而 p_11= P(s_t=1|s_(t-1)=1)。*这被解读为系统在时间 t 处于状态 1 的概率,假定其在前一时间步 (t-1)处于状态 1 。 - 状态 1 到状态 2 带转移概率:
P _ 12 = P(s _ t = 2 | s _(t-1)= 1)。 - 状态 2 到状态 1 带转移概率:
P _ 21 = P(s _ t = 1 | s _(t-1)= 2)。 - 状态 2 到状态 2 带转移概率:
P _ 22 = P(s _ t = 2 | s _(t-1)= 2)。
由于马尔可夫过程需要在每个时间步都处于某种状态,因此:
p11 + p12 = 1,和,
p21 + p22 = 1
状态转移矩阵 P 让我们以如下紧凑矩阵形式表达所有转移概率:

2 态马尔可夫过程的状态转移矩阵(图片由作者提供)
P 包含根据当前状态转移到下一个状态的概率。
状态概率向量 π_ t 包含在时间 t 处于某一状态的无条件概率。对于我们的 2 步马尔可夫随机变量 s_t, 状态概率分布 π _t ,(又称为δ*_ t****)***由以下二元向量给出:

马尔可夫变量的状态概率分布 s_t(图片由作者提供)
可以看出,如果我们以 s_t 的某个先验(初始)概率分布为0开始,那么*【π_*t可以通过简单地将 P 与自身 t 的次数相乘 的矩阵来计算

给定 t=0 时的概率分布和转移矩阵 P (图片由作者提供),马尔可夫过程在 t 时的状态概率分布公式
**这样我们就完成了马尔可夫分布随机变量 s_t 的公式化。记得我们假设 s_t 是隐藏变量。
让我们暂停一下,提醒自己两件我们不知道的重要事情:
- 我们不知道从一种状态转换到另一种状态的确切时间步骤。
- 我们也不知道跃迁概率 P 或状态概率分布*π_*t。
因此,我们到目前为止所做的是假设存在一个以随机变量 s_t 为特征的两态马尔可夫过程,并且 s_t 正在影响以随机变量 y_t 为特征的观察到的失业率。**
可观测时间序列变量 y_t 的公式
让我们假设没有影响失业率的隐马尔可夫过程。基于这一假设,让我们为失业率构建以下回归模型:

y_t 表示为平均值和误差项之和(图片由作者提供)
我们说的是在任意时刻 t ,观察到的失业率 y_t 是建模均值μ_ cap _ t 和残差** ε_t 之和。建模均值 μ_cap_t 是回归模型对 t 时刻失业率的预测。残差 ε_t 就是从观测速率中减去预测速率。我们将互换使用术语建模含义和预测含义。**
我们将进一步假设我们已经使用了一个非常好的回归模型来计算模型化的均值 μ_cap_t. ,因此,残差 ε_t 可以被假设为,即其方差不随均值变化,此外, ε_t 正态分布在一个零均值和一些方差σ周围。在符号形式上, ε_t 是一个 N(0,σ ) 分布随机变量。****
**现在让我们回到 μ_cap_t 。由于 μ_cap_t 是回归模型的预测值,所以 μ_cap_t 实际上是某个回归函数 η(。)这样说:
μ_cap_t = η(。)
**η的不同选择(。)会产生不同族的回归模型。
例如,如果 η(。)= 0 ,我们得到 白噪声模型 : y_t = ε_t.
如果 η(。)是所有观测值的常数均值y _ barI .e .:
y _ bar =(y _ 1+y2+…+y _ n)/n, 我们得到一个 均值模型:y _ t = y _ bar。
一个更有趣的模型可能依赖于一组“ m+1 ”数量的回归系数β_ cap*=【β_ cap _ 0,β_cap_1,β_cap_2,…,β_ cap _ m】,这些回归系数将因变量y链接到回归变量的矩阵*****

回归变量矩阵 X 和系数向量 β (图片由作者提供)
在上图中, X 中第一列 1 作为回归 β_cap_0 拟合截距的占位符。“cap”符号表示它是训练模型后系数的拟合值。而X***_ t是在时间 t 的一排 X 。***
如果链接函数η()x***_ t,【β_ cap】)是线性的,就得到线性模型。如果链接函数是指数函数,则得到 泊松 , NLS 等。回归模型等等。***
让我们仔细看看线性模型,其特征在于以下一组等式:

由建模平均值组成的线性模型,表示为回归变量的线性组合(图片由作者提供)
冒着使残差 ε_ t 相关的风险,也允许在x***_ t、中引入 y_t 的滞后值,如下所示:***

模型平均值表示为回归变量的线性组合,包括因变量 y_t 的滞后副本。(图片由作者提供)
如果你想知道,不,上述模型是不是一个自回归模型在 ARMA 的意义上。稍后,我们将看看“真实的”AR(1)模型是什么样子的。**
我们的模型说明是不完整的,除非我们在上述模型中还指定了 y_t. 的概率(密度)函数,我们将假设 y_t 是具有平均值 μ_cap_t 的正态分布,并且恒定方差σ:

y 的概率密度函数(图片作者提供)
上述等式应理解为:在回归变量向量_ t和拟合系数向量 β_cap 的条件下,失业率在时间 t 为 y_t 的概率(密度)正态分布,具有恒定方差σ和条件均值μ_ cap _ t******

预测平均值表示为回归向量 x _t 和拟合系数向量 β_cap 的点积(图片由作者提供)
这就完成了 y_t 的可视化流程的制定。
现在让我们将隐马尔可夫过程和可见过程“混合”成一个隐马尔可夫模型。
混合隐马尔可夫变量 ST 和可见随机变量 y t
理解隐马尔可夫模型的关键在于理解可见过程的建模均值和方差是如何受隐马尔可夫过程影响的。
下面我们将介绍马尔可夫变量 s_t 影响 μ_cap_t 和σ的两种方式。
马尔可夫转换动态回归(MSDR)模型
假设我们将回归模型定义如下:

均值模型,其中均值根据基础马尔可夫过程的状态在不同值之间切换(图片由作者提供)
在上面的等式中,我们说模型的预测均值根据潜在马尔可夫过程变量 s_t 在时间 t 处的状态而变化。
和前面一样,预测均值 μ_cap_t_s_t 可以表示为某个链接函数 η(.),即μ_cap_t_s_t = η(。).
**对于这个模型,我们定义 η(。)如下:

预测平均值表示为大小为[n x 1]的 1 向量和大小为[1 x 1]的系数向量的点积(图片由作者提供)
上面的等式是点积x _ tβ_ cap的一个特殊的简单情况,这里不涉及回归变量。因此X*_ t是一个大小为【1 X 1】的矩阵,包含数字 1 ,正如我们前面看到的,它是回归的截距 β_0 的占位符。β_ cap也是一个【1×1】矩阵,只包含回归的截距 β_0_s_t. 两者的点积就是标量值 β_0_s_t,它是截距在时间 t 处于马尔可夫状态 s_t 下的值*****
如果我们假设马尔可夫过程在一组 k 状态【1,2,3,…j,…,k】上运行,则更容易将上述等式表达如下:

可视过程的预测均值根据隐马尔可夫过程所处的状态在不同的值之间切换(图片由作者提供)
回归模型的方程式如下:

均值模型,其中均值根据隐马尔可夫过程所处的状态在不同值之间切换(图片由作者提供)
上式中, y_t 为观测值, μ_cap_t_j 为马尔可夫过程处于状态 j 时的预测均值, ε_t 为回归的残差。
在我们的失业率数据集中,我们假设 s_t 在两种状态 1 和 2 之间切换,这为 μ_cap_t_j 提供了以下规格:

可视过程的预测均值在两个值之间切换,这取决于隐藏的 2 状态马尔可夫过程处于哪个状态(图片由作者提供)
这又产生了用于 y_t 的混合过程,该混合过程在两种方式 μ_s_1 和 μ_s_2 之间切换,如下所示:****

受两状态隐马尔可夫过程影响的均值模型(图片由作者提供)
y_t 对应的两个条件概率密度如下:

y_t 的两个概率密度函数对应于隐马尔可夫过程的两个 2 态(图片由作者提供)
但是每个观察到的 y_t 应该只有一个概率密度与之相关联。
我们将使用 全概率 定律来计算这个单一密度,该定律规定,如果事件 A 可以与事件 A1、事件 A2 或事件 A3 等成对地联合发生,那么 A 的无条件概率可以表示如下:

全概率定律(图片由作者提供)
这是一种图形化的看待方式。有“n”种不同的方式到达节点 A:

事件 A 发生的 n 种不同方式(图片由作者提供)
使用该定律,我们得到在时间 t 观察到特定失业率 y_t 的无条件概率密度如下:

一个 2 态马尔可夫模型影响下的 y 的无条件概率密度(图片作者提供)
敏锐的读者可能已经注意到,在上面的等式中,我们混合了概率和概率密度,但是在这里也可以这样做。以求和形式书写的上述等式如下:

一个 2 态马尔可夫模型影响下的 y 的无条件概率密度(图片由作者提供)
上式中,概率 P(s_t=1) 和 P(s_t=2) 是两态马尔可夫过程的状态概率*****π_ t1和π****_ T2*:****

2 状态马尔可夫过程的状态概率向量(图片由作者提供)
我们已经知道,为了计算状态概率,我们需要假设一些初始条件,然后使用下面的等式:

给定 t=0 时的概率分布和转移矩阵 P (图片由作者提供),马尔可夫过程在 t 时的状态概率分布公式
其中π*_ 0为初始值 t=0 , P 为状态转移矩阵:*****

2 态马尔可夫过程的状态转移矩阵(图片由作者提供)
上面的模型是所谓的马尔可夫转换动态回归(MSDR) 模型家族的一个简单例子。****
评估和培训
训练该模型包括估计以下变量的最佳值:
- 状态转移矩阵 P ,即本质上的转移概率p11和p22、**
- 我们样本数据集中与两个预测失业率水平、和相对应的状态特定回归系数 β_cap_0_1 和β_cap_0_2,
- 恒定方差σ。
可以使用最大似然来进行估计,其找到、β_cap_0_1 、 β_cap_0_2 (使用 β_cap _s 矩阵和σ的值,这些值将最大化观察整个训练数据集 的联合概率密度换句话说,我们希望最大化以下产品:******

观察数据集的可能性(图片由作者提供)
在上面的乘积中,概率密度f(y= y _ t)由我们前面看到的等式(1)给出。
最大化该乘积的自然对数通常更容易,这有利于将乘积转换成总和。因此,我们最大化以下对数-可能性:

观察数据集的对数似然性(图片由作者提供)
对数似然性的最大化是通过对对数似然性 w.r.t .的每个参数 p_11 、 p_22 、 β_cap_0_1 、 β_cap_0_2 和σ取偏导数来完成的,将每个偏导数设置为零,并使用诸如 Newton-Raphson 、 Nelder-Mead 、等一些优化算法来求解五个方程的结果系统
马尔可夫转换动态回归模型(一般情况)
MSDR 的一般方程可以表述如下:

用预测均值 μ_cap_tj 和残差 ε_t 之和表示的观测值 y_t(图片由作者提供)
其中, μ_cap_t_j 是回归变量矩阵x*_ t和特定体制拟合系数向量β_ cap****_ j*的函数。即、********
μ_ cap _ t _ j =η(x_ t,β_ cap_ j)
但是这一次,注意回归系数向量被称为β_ cap*_ j对应于第 j 个马尔可夫状态。*****
如果马尔可夫模型对' k' 状态【1,2,…,j,…,k】, β_cap_s 进行运算,则大小为 [(m+1) X k] 的矩阵如下:

大小为[(m+1) x k]的系数矩阵(图片由作者提供)
中心思想是,根据[1,2,…,k 中的哪个马尔可夫状态或“状态” j *当前有效,回归模型系数将从 β_cap_s 切换到适当的状态特定的向量β_ cap***_ j因此得名‘马尔可夫切换动态回归模型’。********
k-状态马尔可夫过程本身由以下状态转移矩阵 P 控制:

马尔可夫过程的状态转移矩阵 P (图片作者提供)
***并且在时间步长 t 具有以下状态概率分布 π_ t 😗**

k 状态马尔可夫过程的状态概率分布向量(图片由作者提供)
到目前为止,我们假设 y_t 的线性指定条件均值函数如下:

正态分布 y_t 的条件均值,表示为回归变量 x t、y_t 的滞后版本和马尔可夫状态相关拟合系数 ***β_cap j 的线性组合(图片由作者提供)***
上式中, μ_cap_t_j 是马尔可夫状态 j 下 t 时刻的预测均值。x_ t是回归变量【x _ 1t,x_2t,…,x _ mt】在时间 t 的向量,β_ cap_ j是状态特定系数的向量【β_ cap _ 0j,β_cap_1j,β_cap_2j,…,β_cap_mj**
正如我们在 2 态马尔可夫情况下所看到的(参考等式)。1),这为 y_t 产生正态分布的概率密度如下:

以 k 态马尔可夫分布随机变量 s_t 影响下的 y_t 的 β_cap_s 和 P 为条件的概率密度函数(图片由作者提供)
等式(2)只是等式(1)在 k 马尔可夫状态上的扩展。
y_t 不用正态分布。实际上,假设 y_t 代表一个整数随机过程即 y_t 取值 0,1,2,…等。这种过程的例子是纽约市每天的机动车事故数量,或者网站每小时的点击数。这种过程可以使用 泊松 过程模型来建模。在这种情况下,泊松分布 y_t 的概率质量函数采用以下形式:

k 状态马尔可夫过程模型影响下的泊松分布 y_t(图片由作者提供)
其中,特定于制度的均值函数表示如下:

上式中,x_ t和β_ cap****_ j与线性均值函数含义相同。**
训练和评估
马尔可夫转换动态回归模型的训练包括下列变量的最优值的估计:
模型的系数:

大小为[(m+1) x k]的系数矩阵(图片由作者提供)
状态转移概率:

马尔可夫过程的状态转移矩阵 P (图片由作者提供)
和方差σ。
如前所述,估计过程可以是最大似然估计* ( MLE ),其中我们求解一个 (k +(m+1)k +1) 方程系统(实际上,比那个数少得多),对应于 k 马尔可夫转移概率、 (m+1)k 系数 β_cap_s 和方差σ。*
*In an upcoming article, we’ll look at how to build and train both **Linear and Poisson MSDR models** using **Python** and the **statsmodels** library.*
现在让我们看看另一种类型的隐马尔可夫模型,称为马尔可夫切换自回归(MSAR)* 模型。***
马尔可夫转换自回归(MSAR)模型
考虑以下月失业率的模型方程:

在隐马尔可夫过程影响下运行的 AR(1)模型(图片由作者提供)
这里,我们说的是在时间 t 的失业率围绕特定制度的平均值 μ_t_s_t 波动。波动是由两个分量的总和引起的:
- 第一个分量代表在前一时间步的观测值与在前一时间步的拟合状态特定平均值的偏差分数,
- 第二个分量来自残差 ε_t 。
与 MSDR 模型一样,隐马尔可夫过程的状态会影响模型的拟合均值。
注意,该模型不仅依赖于时间 t 的状态值,还依赖于前一时间步 (t-1) 的有效状态。
上述规范可以很容易地扩展到包括过去的 p 时间步长,从而得到遵循 AR(p) 设计模式的 MSAR 模型。
模型说明和评估
MSAR 模型的模型规范的一般框架,包括 y_t 的概率密度函数的规范和估计程序(MLE 或期望最大化)与 MSDR 模型保持一致。
不幸的是,在前面的步骤中,模型对马尔可夫状态的依赖使规范过程和估计变得相当复杂。
我们不会在这里深入讨论这些细节,但是与 MSDR 模型一样,我们将在下一篇文章中研究如何用 Python 和 statsmodels 构建和训练 MSAR 模型。
参考文献和版权
数据集
美国劳工统计局,失业率[UNRATE],从圣路易斯美联储银行检索;https://fred.stlouisfed.org/series/UNRATE, 2021 年 10 月 29 日。在公共许可证下可用。
书
Cameron A. Colin,Trivedi Pravin K ., 对计数数据的回归分析 ,计量经济学学会专论№30,剑桥大学出版社,1998 年。国际标准书号:0521635675
詹姆斯·d·汉密尔顿, 时间序列分析 ,普林斯顿大学出版社,2020 年。ISBN: 0691218633
形象
所有图片的版权均为 Sachin Date 下的 CC-BY-NC-SA 所有,除非图片下方提到了不同的来源和版权。
相关阅读
***
感谢阅读!如果你喜欢这篇文章,请 关注我 获取关于回归和时间序列分析的技巧、操作和编程建议。***
支持向量机的数学解释
原文:https://towardsdatascience.com/a-mathematical-explanation-of-support-vector-machines-e433ffe04362?source=collection_archive---------10-----------------------
加深对最流行的机器学习模型之一的理解

图片由来自 Pixabay 的 Gerd Altmann 提供
支持向量机(SVM)是数据科学领域最流行的机器学习模型之一。直觉上,这是一个相当简单的概念。然而,从数学上来说,支持向量机看起来就像一个黑盒。
在这篇文章中,我有两个目标:
- 我想揭开支持向量机背后的机制,让你更好地理解它的整体逻辑。
- 我想教你如何用 Python 实现一个简单的 SVM,并使用https://www.gradio.app/部署它。最后,您将能够构建这样的东西:
作者创建的 GIF
说到这里,让我们开始吧!
复习:什么是支持向量机?

作者创建的图像
支持向量机(SVM)是一种监督分类技术。支持向量机的本质只是找到一个区分不同类别的界限。
- 在二维空间中,边界称为直线。
- 在三维空间中,边界称为平面。
- 在任何大于 3 的维度中,该边界称为超平面。
让我们假设有两类数据。支持向量机会找到一个边界,使两个类之间的间隔最大化(见上图)。有许多平面可以分隔这两个类别,但只有一个平面可以最大化类别之间的边距或距离。
注释
n =数据点数
m =属性数
x_ij =第 j 个数据点的第 I 个属性
如果数据点是蓝色,y _ j = 1;如果数据点是红色,y _ j = 1
数学

读完这篇文章后,你会明白上面的等式想要达到什么目的。如果看起来很混乱也不用担心!我会尽我所能一步一步地分解它。
请记住,这涵盖了基本支持向量机的数学,不考虑内核或非线性边界之类的东西。
分解一下,我们可以把它分成两个独立的部分:

作者创建的图像
红色部分:红色部分专注于最小化错误,即 SVM 产生的错误分类点的数量。
蓝色部分:蓝色部分着重于最大化利润,这在本文前面已经讨论过了。
先说蓝色部分,或者说方程的第二项。
第二项:利润最大化

正如我前面所说的,您可以在两类数据点之间放置许多边界,但是只有一个边界可以最大化两类之间的边距(如上面的虚线所示)。
我们希望决策边界尽可能远离支持向量,以便当我们有新数据时,它会以更大的确定性落在这个或那个类别中。

让我们假设上面的两个等式分别代表边距的两边。不要太担心 m/-m,只要注意它们如何表示一条线的方程。
两条虚线之间的距离由下面的公式得出,你可以在这里阅读更多关于的内容:

不用那么担心这个方程是怎么推导出来的。相反,请注意,随着 1 和 m (a1,a2,… am)之间的所有 a 变小,分母变小,距离或边距变大!

现在你明白了第二个术语(蓝色部分)的意思,让我们来谈谈第一个术语(红色部分)。
第一项:最小化误差
实际上,你不可能找到一个超平面,完美地将不同的类彼此分开。即使它存在,也不总是你想要使用那个超平面。
考虑下图:

从技术上讲,我们可以设置边界,使红色和蓝色类位于边界的右侧。然而,假设左边的蓝色方块是一个异常值,那么拥有一个具有较大裕度的不完美超平面可能更理想,这被称为软裕度**:**

既然我们已经介绍了“误差”的概念,你应该明白支持向量机的完整等式是试图最小化误差,同时最大化余量**。**
既然我们已经理解了第一个术语背后的目标,让我们重新审视这个等式:

用英语来说,这个等式说的是“取各点误差之和”。

那么^这部分方程是如何表示每个点的误差的呢?让我们深入探讨一下:

我们把 m 和-m 分别设为 1 和-1。实际上,它们可以是任何数字,因为 m 是裕度的比例因子。
因为如果数据点是蓝色的,y_j = 1,如果数据点是红色的,y _ j = 1,所以我们可以组合上边界的方程和下边界的方程来表示所有点:

这可以重写为以下内容:

这个等式假设所有的点都被分类在等式的右边。对于边界错误一侧的任何一点,它都不满足方程。

对你们中的一些人来说,我敢打赌,你脑袋里的灯泡已经亮了。如果没有,不用担心!我们快结束了。

记得我说过这个方程“取每个点的误差之和。”具体来说,就是取零的最大值,第二部分。规则如下:

让这个代表 Z
让上面的等式代表 z。
- 如果给定点在线的右侧,那么 Z 将大于 1。这意味着第一项的第二部分将是一个负数,所以给定点将返回 0(没有错误)
- 如果给定点在线的错误一侧,那么 Z 将小于 1。这意味着第一项的第二部分将是一个正数,因此给定点将返回一个大于 0 的值(错误)。
结论

作者创建的图像
就是这样!总之,支持向量机的目标是通过最小化 a_i 来最小化总误差和最大化裕度。
下一步是什么?建造 SVM。
既然您已经理解了支持向量机背后的数学,下一步就是用 Python 实际构建一个支持向量机模型并部署它!
我将使用经典的 iris 数据集来展示如何用 Python 构建支持向量机(完整代码见 此处 )。
设置
开始之前,您需要安装以下库:
- Numpy
- 熊猫
- 海生的
- Sklearn
- 格拉迪欧
**# Importing libraries**
import numpy as np
import pandas as pd
import seaborn as sns**# Importing data**
iris=sns.load_dataset("iris")
数据准备
from sklearn.model_selection import train_test_split**# Splitting features and target variables**
X=iris.drop("species",axis=1)
y=iris["species"]**# Splitting data into train and test sets**
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25)
数据建模
from sklearn.svm import SVC**# Creating model**
model = SVC(probability=True)
model.fit(X_train,y_train)
使用 Gradio 创建 Web 应用程序
**# Writing a prediction function**
def predict_flower(sepal_length, sepal_width, petal_length, petal_width):
df = pd.DataFrame.from_dict({'Sepal Length':[sepal_length],
'Sepal Width': [sepal_width],
'Petal Length': [petal_length],
'Petal Width': [petal_width]
})predict = model.predict_proba(df)[0]
return {model.classes_[i]: predict[i] for i in range(3)}**# Importing gradio** import gradio as gr**# Creating Web App** sepal_length = gr.inputs.Slider(minimum=0, maximum=10, default=5, label="sepal_length")sepal_width = gr.inputs.Slider(minimum=0, maximum=10, default=5, label="sepal_width")petal_length = gr.inputs.Slider(minimum=0, maximum=10, default=5, label="petal_length")petal_width = gr.inputs.Slider(minimum=0, maximum=10, default=5, label="petal_width")gr.Interface(predict_flower, [sepal_length, sepal_width, petal_length, petal_width], "label", live=True).launch(debug=True)
现在你知道了!你应该有一个全功能的 web 应用程序,在那里你可以摆弄模型的输入,并立即看到输出概率。
作者创建的 GIF
感谢阅读!
如果你坚持到了最后,恭喜你!现在,您应该对基本支持向量机的工作原理有了很好的理解,而且您现在知道如何构建自己的全功能 SVM web 应用程序。
如果你喜欢这个,请给这个一些掌声,并在媒体上跟随我!
我一如既往地祝你学习顺利。:D
不确定接下来要读什么?我为你挑选了另一篇文章:
**
又一个!
</4-machine-learning-concepts-i-wish-i-knew-when-i-built-my-first-model-3b8ca9506451>
特伦斯·申
- 如果你喜欢这个, 跟我上媒 了解更多
- 有兴趣合作吗?让我们连线上LinkedIn
- 报名我的邮箱列表 这里 !**
麦当劳与塔可钟的模拟:寻找更健康的选择
原文:https://towardsdatascience.com/a-mcdonalds-vs-taco-bell-simulation-finding-the-healthier-choice-7de797772df5?source=collection_archive---------7-----------------------

在 Unsplash 上由 Shaafi Ali 拍摄的照片
想象一下。你结束了一整天的工作,决定在回家的路上买些杂货。办完一些事情后,你看看手表:晚上 9 点。为了让自己休息一下,你决定去快餐店吃晚餐。听起来熟悉吗?我敢打赌。
我们都过着极其忙碌的生活。虽然我们都知道快餐不一定是最健康的选择,但许多人仍然利用这些设施,因为它们非常方便。我们倾向于把所有这些连锁餐馆捆绑在一起,认为它们和下一家一样不健康。然而,研究具体的营养事实是区分它们并做出更健康饮食的正确选择的关键。在这个案例研究中,我关注了两家非常受欢迎的快餐店,麦当劳和塔可钟,并回答了这个古老的问题:
从长远来看,在哪个餐馆吃饭会是更健康的选择?
模拟系统
我首先从两家餐馆拿了菜单,给每一项标上主菜、饮料、配菜、甜点、酱汁或调料。对于麦当劳的信息,我从 Kaggle 上的数据集中提取,对于塔可钟,我基于我找到的营养事实网站自己创建了数据集。我保留了每家餐厅特有的饮料,并在分析中丢弃了其余的。也就是说,可乐、雪碧等饮料。从两个数据集中删除,因为我只考虑餐厅的商标食品。该分析的范围仅包括午餐和晚餐菜单项目。
然后,我创建了四个不同的模拟场景,在这些场景中,顾客将从每家餐厅购买餐食,关键的区别在于单词“餐食”的定义。
模拟 1: 顾客单独购买一道主菜
模拟 2: 顾客购买一道主菜和一杯饮料
模拟 3: 顾客购买一份主菜、一份饮料和一份配菜
模拟 4: 顾客购买一道主菜、一杯饮料、一道配菜和一道甜点
为了使分析更加现实,我在两家餐馆的某些菜单项中创建了规定。如果随机选择沙拉作为配菜,脚本会随机选择一种沙拉酱来搭配正餐。如果鸡块或鸡条被选作主菜,那么脚本也会随机选择一种酱与之搭配。对于塔可钟主菜,我确保每个模拟随机选择两种酱来搭配每个主菜。
**对于每个模拟,这些组合的膳食被取样 10,000 次。**由此可以清楚地区分不同的工厂。让我们首先考虑一个最简单的情况,顾客单独点一道主菜。根据模拟 1,我创建了以下图:

模拟 1 结果表明单独主菜的营养分布相似。图片作者。
请注意,两个机构的平均卡路里、脂肪卡路里、胆固醇和钠含量非常相似。我很好奇这种趋势是否适用于所有模拟,这让我比较了所有模拟运行的这些特征的平均值。简而言之,答案是否定的。我创造了这个向我们展示结果的图。

所有模拟的平均值(n=10,000)。图片作者。
我们看到,在不同的试验中,营养特性会有明显的差异。模拟 1 实际上是唯一一个对两家餐馆产生看似相似结果的试验。这意味着餐馆里的饮料、配菜和甜点在营养质量上表现出更大的差异。前面提到的特点,麦当劳比塔可钟高很多。为了评估这些差异在数学上是否显著,我对所有模拟进行了非参数测试(Mann-Whitney U 测试)。可以预见的是,我在所有试验中获得了非常低的 p 值,表明了上述两家餐厅的营养特征之间的显著差异。然而,我并不认为模拟 1 会有显著的不同。
让我们更仔细地看一下模拟 4,它包括一顿全餐。在我看来,这应该是我们最重视的审判。如果我们对前 500 个样品的营养特性进行快照比较,我们会看到以下结果:

总的来说,麦当劳比塔可钟拥有更多的热量和脂肪。图片作者。
正如你所看到的,来自脂肪、胆固醇、反式脂肪和饱和脂肪的热量通常比麦当劳高。为了获得一些关于这些特征中的一些对于麦当劳有多高的定量测量,让我们在模拟 4 中观察 ECDF 对于每一餐的脂肪和胆固醇的卡路里的不同。

更大比例的麦当劳食品含有来自脂肪和胆固醇的更高热量。
正如我们所看到的,大约 37%的麦当劳食物含有超过 600 卡路里的脂肪,这是塔可钟一餐的最大值。此外,大约 60%的塔可钟餐从脂肪中摄取 220 到 410 卡路里的热量,而 60%的麦当劳餐从脂肪中摄取 420 到 650 卡路里的热量。此外,大约 77%的塔可钟餐含有低于 400 卡路里的脂肪,而只有大约 18%的麦当劳餐具有相同的质量。
从右边的图中,我们可以看到所有的塔可钟餐都没有达到大约 90 毫克的胆固醇。另一方面,只有 18%的麦当劳食品低于同样的胆固醇水平。事实上,30%的麦当劳餐含有超过 180 毫克的胆固醇——是塔可钟餐最大胆固醇值的两倍。
那么这一切意味着什么呢?
在我们做出一个轻快的结论之前,让我们考虑一下在这个分析中探索的特征的意义和获得的总体结果。每一个有 10,000 个样本的模拟都产生了两家餐馆之间实质性的和显著的营养差异。具体来说,我们观察到麦当劳在所有进行的模拟中所有特性的值都明显较高。这一定是坏事吗?
根据哈佛大学 T . H Chan 公共卫生学院的研究,由于反式脂肪对我们的血管和心脏有负面影响,所以它是最不适合食用的脂肪。这种脂肪的大量摄入会导致胰岛素抵抗、糖尿病和许多其他并发症。根据 MayoClinic 的一篇文章,从饱和脂肪中获得的最大建议热量是你每日总热量的 10%。一般来说,一个人每天要摄入大约 2000 卡路里的热量,这意味着要保持*【健康】*,脂肪中的热量上限为 200 卡路里。假设你在快餐店吃饭,你很可能会超过这个门槛。然而,在麦当劳吃一顿全餐,你会把它变成原来的三倍或四倍的可能性远远大于在塔可钟。
根据美国美国食品药品监督管理局的一篇文章,高钠饮食会导致心脏病和增加中风的风险。他们指出,推荐的每日钠摄入量少于 2300 毫克。根据模拟 4,麦当劳一餐超过这个数值,而塔可钟平均保持在 1500 毫克左右。最后,较高水平的胆固醇会因脂肪沉积而导致血管堵塞。从模拟快照和 ECDF 图中,我们看到麦当劳的平均胆固醇含量明显高于塔可钟的。
当然,在这项研究中,除了有条件地添加调料/酱料之外,我赋予单词*、【餐】*的定义将在我的模拟中引起算法偏差。在不同的条件下运行更多的模拟来增加分析的真实性是一个好主意。尽管如此,我相信我目前的结果是很有见地的!
总而言之,我的分析结果指向一个清晰的结论:从长远来看,塔可钟是更健康的选择。
如果你喜欢这篇文章,并且对更多类似的内容感兴趣,你可以关注我的 Medium。这个项目的代码可以在我的 Github 这里找到。感谢阅读!
TensorFlow 2.0 中深度 Q 学习的最小工作示例
原文:https://towardsdatascience.com/a-minimal-working-example-for-deep-q-learning-in-tensorflow-2-0-e0ca8a944d5e?source=collection_archive---------10-----------------------
一个多臂土匪的例子来训练一个 Q 网络。使用 TensorFlow,更新过程只需要几行代码

深度,就像深度 Q-learning 一样。克里斯·米凯尔·克里斯特在 Unsplash 上的照片
深度 Q 学习是任何强化学习(RL)实践者的武器库中的一个主要部分。它巧妙地规避了传统 Q-learning 的一些缺点,并利用神经网络的能力进行复杂值函数的逼近。
本文展示了如何在 TensorFlow 2.0 中实现和训练深度 Q 网络,并以多臂土匪问题(一个终止的一次性游戏)为例进行了说明。还提供了对时间差异学习的一些扩展。不过,我认为极小工作示例中的*【极小】*相当字面上的意思,所以重点是有史以来第一次实现深度 Q 学习。
一些背景
在深入学习之前,我假设你已经熟悉了普通 Q 学习和人工神经网络。没有这些基础知识,尝试深度 Q 学习可能会是一次令人沮丧的经历。以下更新机制对您来说应该没有秘密:

Q-learning 的更新函数[1]
传统的 Q-learning 在一个查找表中为每个状态-动作对显式存储一个 Q 值——本质上是对累积折扣奖励的估计。当在特定状态下采取行动时,观察到的奖励会提高价值评估。查找表的大小为 |S|×|A| ,其中 S 为状态空间, A 为动作空间。Q-learning 对于玩具大小的问题往往很有效,但是对于更大的问题就不行了。通常,不可能在任何地方观察到所有的状态-行为对。

在 16 格网格上移动的 Q 学习表示例。在这种情况下,有 16*4=64 个状态-动作对,应该学习它们的值 Q(s,a)。[图片由作者提供]
与普通 Q-学习相比,深度Q-学习将状态作为输入,通过多个神经网络层,并输出每个动作的 Q 值。深度 q 网络可以被视为一个函数 f:s→[Q(s,a)]_∀ a ∈ A 。通过对所有状态采用单一表示,深度 Q 学习能够处理大的状态空间。不过,它预先假定了合理数量的动作,因为每个动作都由输出层中的一个节点表示(大小 |A| )。

深度 Q 网络的例子。在本例中,输入是网格(16 个图块)的一键编码,而输出表示四个动作中每个动作的 Q 值。[图片由作者提供]
在通过网络并获得所有动作的 Q 值之后,我们照常继续。为了平衡勘探和开发,我们利用了一个基本的ϵ-贪婪政策。通过概率 1-ϵ 我们选择最佳动作(输出层上的argmax操作),通过概率 ϵ 我们对随机动作进行采样。
TensorFlow 2.0 实施
在 TensorFlow 中定义 Q 网络并不难。输入维度等于向量状态的长度,输出维度等于动作的数量(如果可行动作的集合是状态相关的,则可以应用掩码)。Q 网络是一种相当简单的神经网络:
在 TensorFlow 2.0 中创建 3 层 Q 网络的示例代码。输入是状态向量,输出是每个动作的 Q 值。
权重更新在很大程度上也是为您处理的,但是您必须向优化器提供一个损失值。损失代表观察值和期望值之间的误差;需要一个可微分的损失函数来正确地执行更新。对于深度 Q 学习,损失函数通常是简单的均方误差。这实际上是 TensorFlow 中的内置损失函数(loss=‘mse’),但我们将在这里使用GradientTape功能,跟踪您的所有操作来计算和应用梯度[2]。它提供了更多的灵活性,并且贴近底层数学,这在转向更复杂的 RL 应用时通常是有益的。
均方损失函数(观察与前面提到的更新机制的相似性)表示如下:

深度 Q 学习的均方误差损失函数
深度 Q 学习方法的一般 TensorFlow 实现如下(GradientTape 在水下施展魔法):
深度 Q 学习训练程序概述。
多臂土匪
多臂土匪问题是 RL[3]中的经典。它定义了若干吃角子老丨虎丨机:每台机器 i 都有一个平均收益 μ_i 和一个标准差 σ_i. 每个决策时刻,你玩一台机器,观察由此产生的奖励。当玩得足够频繁时,你可以估计每台机器的平均回报。不言而喻,最佳策略是玩平均收益最高的老丨虎丨机。
让我们把 Q-learning 网络的例子付诸行动(完整的 Github 代码这里)。我们定义了一个具有三个完全连接的 10 节点隐藏层的简单神经网络。作为输入,我们使用值为 1(表示固定状态)的张量作为输入,四个节点(表示每个机器的 Q 值)作为输出。网络权重被初始化,使得所有 Q 值最初都是 0。对于权重更新,我们使用学习率为 0.001 的 Adam 优化器。
下图显示了一些说明性的结果(10,000 次迭代后)。勘探和开发之间的权衡是显而易见的,尤其是在根本不勘探的时候。注意,结果并不过分准确;普通 Q-learning 实际上对这类问题表现得更好。

多臂土匪问题的 q 值和真值。ϵ=0.0(左上)、ϵ=0.01(右上)、ϵ=0.1(左下)和ϵ=1.0(右下)经过 10,000 次迭代后的结果。探索越少,感知的最佳行为越接近。[图片由作者提供]
时间差异学习
多臂强盗绝对是一个最小的工作例子,但是只处理了我们没有看到直接回报以外的最终情况。让我们看看如何处理非终结的情况。在这种情况下,我们部署时间差异学习—我们使用 Q(s ',a') 来更新 Q(s,a) 。
获得对应于下一个状态*s’的 Q 值本身并不难。你只需将s’*插入到 Q 网络中,并输出一组 Q 值。总是选择最大值,因为这是 Q 学习而不是 SARSA,并使用它来计算损失函数:
next_q_values = tf.stop_gradient(q_network(next_state))
next_q_value = np.max(next_q_values[0])
注意,Q-网络是在一个**stop_gradient** 运算符内调用的【4】。提醒一下,GradientTape跟踪所有的操作,并且同样会使用next_state输入执行(无意义的)更新。使用stop_gradient操作符,我们可以安全地利用对应于下一个状态*s’*的 Q 值,而不用担心错误的更新!
一些实施说明
虽然上面概述的方法原则上可以直接应用于任何 RL 问题,但您会经常发现性能相当令人失望。即使对于基本问题,如果你的普通 Q 学习实现胜过你的花哨的深度 Q 网络,也不要感到惊讶。一般来说,神经网络需要许多观察来学习一些东西,并且通过为所有可能遇到的状态训练单个网络来固有地丢失一些细节水平。
除了良好的神经网络实践(例如,标准化、一键编码、正确的权重初始化),以下调整可能会大大提高算法的质量[5]:
- 小批量:不是在每次观察后更新网络,而是使用批量观察来更新 Q 网络。稳定性通常通过多次观察的训练来提高。每次观察的损失被简单地平均。
tf.one_hot掩码可用于多个动作的更新。 - 经验重放:建立一个先前观察值的缓冲区(存储为 *s,a,r,s’*元组),从缓冲区中抽取一个(或多个,当使用迷你批处理时),并插入 Q 网络。这种方法的主要好处是消除了数据中的相关性。
- 目标网络:创建一个只定期更新(比如每 100 次更新)的神经网络副本。目标网络用于计算Q(s’,a’),而原始网络用于确定 Q(s,a) 。此过程通常会产生更稳定的更新。
外卖
- 一个深度 Q 网络是一个简单的神经网络,以状态向量作为输入,输出对应于每个动作的 Q 值。通过对所有状态使用单一表示,它可以处理比普通 Q-learning(使用查找表)大得多的状态空间。
- TensorFlow 的
GradientTape可以用来更新 Q 网络。对应的损失函数是接近原始 Q 学习更新机制的均方误差。 - 在时间差学习中,基于*Q(s’,a’)更新 Q(s,a) 的估计值。
stop_gradient算子确保对应于Q(s’,a’)*的梯度被忽略。 - 深度 Q 学习伴随着一些实现挑战。如果香草 Q-learning 实际上表现更好,不要惊慌,特别是对于玩具大小的问题。
使用多臂盗匪的最小工作示例的 GitHub 代码可以在 这里 找到。
想要稳定你的深度 Q 学习算法?下面这篇文章可能会让你感兴趣:
转而寻求实施政策梯度方法?请检查我的文章与连续和离散情况下的最小工作示例:
参考
[1]萨顿,理查德和安德鲁巴尔托。强化学习:简介。麻省理工学院出版社,2018。
[2] Rosebrock,A. (2020)使用 TensorFlow 和 GradientTape 来训练 Keras 模型。【https://www.tensorflow.org/api_docs/python/tf/GradientTape
[3] Ryzhov,I. O .,Frazier,P. I .和 Powell,W. B. (2010 年)。多臂土匪问题中一期前瞻策略的鲁棒性。Procedia 计算机科学,1(1):1635{1644。
[4]TensorFlow (2021)。于 2021 年 7 月 26 日从https://www.tensorflow.org/api_docs/python/tf/stop_gradient获得
[5]维基百科贡献者(2021)深度 Q-learning。于 2021 年 7 月 26 日从https://en.wikipedia.org/wiki/Q-learning#Deep_Q-learning获得
自行车共享系统再平衡的混合整数优化方法
原文:https://towardsdatascience.com/a-mixed-integer-optimization-approach-to-rebalancing-a-bike-sharing-system-48d5ad0898bd?source=collection_archive---------16-----------------------
实践教程
旅行商问题在蒙特利尔碧溪的应用

JsTremblay 在维基共享资源上的照片
时间是 2022 年。加拿大的人口已经完全接种了疫苗,在一个炎热的七月下午,蒙特利尔的公园充满了生机,比西骑手挤满了街道,在老港口的咖啡店之间穿梭,沿着拉钦运河转圈。生活又变得美好了。
BIXI 来源于单词“bicycle”和“taXI”,是一个非营利的蒙特利尔公共自行车共享系统,拥有 8000 多辆自行车,分布在岛上的 600 多个车站。BIXI 从每年的 4 月到 11 月开放,它填补了蒙特利尔公共交通系统的一个重要空白,既连接了公共汽车和地铁系统之间的用户,又为短途旅行提供了一种健康、有趣、环保的替代交通工具。客户只需从一个站点取走一辆自行车,以一定的时间和费用租用一段时间,然后返回网络中的另一个站点。然而,由于 BIXI 的成本方案是为短期出行设计的,系统的动态性质可能会造成自行车短缺发生在需求高的位置,而自行车过剩积累在需求低的位置。
战略性地重新分配自行车的能力是 BIXI 客户服务的一个关键决定因素。为了减少自行车共享系统内的潜在失衡,BIXI 的运营商(被称为“司机”)被要求使用卡车将自行车从一个站点重新分配到另一个站点,以便在必要时重新平衡系统。因此,研究 BIXI 如何通过重新平衡自行车来缓解短缺和过剩,从而满足客户不断波动的需求,具有重要的价值。这样做可以确保 BIXI 能够继续吸引更多的骑手,同时最大限度地减少由于系统失衡导致的低效率。
设计自行车再平衡策略
在这个项目中,我们旨在使用混合整数优化来生成自行车再平衡策略,以满足 BIXI 客户不断变化的需求,同时最大限度地降低运营分销系统所产生的估计成本。
简而言之,优化问题包括从一系列可用选项中选择最优选项,称为决策变量,其中最佳选项是最大化或最小化目标函数,同时满足一系列标准,称为约束。优化是运营建模的一个基本分支,具有广泛的实际应用,从安排医院人员到帮助亚马逊设计包裹递送的最佳路线。为了创建最佳的 BIXI 再平衡策略,我们的决策是找到最佳的时间表和自行车数量来进行再平衡,这将最小化目标函数,即 BIXI 的运营成本。为此,我们还需要满足系统*、施加的各种约束*,比如一辆卡车一次可以运载的自行车数量。
为了建立模型,我们使用了 Gurobi 优化求解器,这是一个用于求解线性、二次和混合整数优化问题的编程工具。Gurobi 支持多种编程语言,我们的模型是用 Python 编写的。请随意查看 Github 的代码。
数据和范围
BIXI 为 2014 年至 2019 年拍摄的所有车站和游乐设施提供公开可用的记录。这包括每个站点的地理坐标位置,以及用户所有行程的记录,例如行程日期、持续时间以及自行车在哪个站点上车和下车。我们发现,由于自成立以来碧溪的业务大幅扩张,每年的客流量和车站配置都有很大差异。因此,我们采用了 2019 年的最新可用数据作为我们模型的基础。

带有坐标位置的碧溪站名称示例-每个站都有一个唯一的代码。

2019 年 5 月碧溪乘客历史样本
BIXI 系统包括大蒙特利尔地区的 611 个站点;然而,这些车站中的大多数都位于市中心及其周围。为了节省计算时间以及实现现实可行的路线,选择了凡尔登区内覆盖 13.65 km 的 18 个站点作为感兴趣区域。每个车站都有不同数量的自行车停靠站。由于我们无法获得此信息,我们随机生成了每个码头 10-25 辆自行车的估计范围内的码头容量。为了完成凡尔登区的再平衡活动,我们假设一辆载重量为 40 辆自行车的卡车将被分配到有剩余自行车的站点,并将它们运送到有短缺的站点。

蒙特利尔凡尔登区的 18 个碧溪站用作感兴趣区域。
模型公式:
基本优化模型是通过量化再平衡系统的运营成本并从乘客的估计收入中减去这些成本来构建的,以最小化组织成本,服从路线和再平衡约束。我们基于经典的旅行推销员问题(TSP) 背后的直觉建立了我们的模型,这是一个优化问题,其中“推销员”必须恰好访问一次指定位置的列表,同时选择最短的可能路线并返回到起始位置。
参数
我们首先定义了以下参数以纳入我们的模型:

决策变量
接下来,我们定义了我们的决策变量。这些变量定义了卡车司机必须做出的选择,特别是司机是否会访问一个车站,以及他们将取放多少辆自行车。

目标函数
我们的首要目标是最小化总运营成本,包括每辆自行车的预计自行车消毒成本( h )、每公里的汽油成本( g )以及卡车司机的固定小时工资( w )。这里, B 代表被重新定位的自行车数量,而 D 代表卡车行驶的总距离。

约束条件
最后,我们构建了两组约束——一组关于所选路线,另一组关于自行车重新平衡——来复制必须满足的各种现实需求。从路线的角度来看,我们调整了旅行推销员问题的约束,以确保在不需要重新平衡时,卡车不需要访问每个车站,因为对于 BIXI,卡车只需要在自行车数量低于或高于我们定义的预定阈值时访问车站。
对于重新平衡的限制,我们需要确保卡车将每个站点重新平衡到其理想水平,并且它不会承载超过其容量的自行车。
要深入了解我们如何解决这个问题,请访问我们的 Github。
估计再平衡的成本
为了确保 BIXI 能够保持足够的资金来执行这一重新平衡过程,我们还估算了其运营产生的成本和收入。我们估计重新平衡的成本如下:
- 卡车司机工资:20.52 美元/小时
- 新冠肺炎自行车消毒费用:0.875 美元/辆
- 燃料成本:1.256 美元/升
- 预计燃油效率:4.25 公里/升
- 旅行价格(燃料成本*效率):0.294 美元/公里
估计乘客的收入
通过将每次出行的成本乘以会员与非会员出行的次数,可以估算出感兴趣区域每天和每周的乘客总收入。虽然 BIXI 提供额外的折扣和套餐,但数据并未区分这些旅行,因此所有旅行最终都归入以下费用方案:

会员与非会员旅行的费用方案。请注意,在一定时间后,每增加 15 分钟,将收取 3 美元的费用。
把所有的东西放在一起!
模型公式是使用 Gurobi 9.1 和 Python 3.7 完成的。总之,我们定义了四个主要的决策变量,涉及(1)卡车是否会在站点之间行驶,(2)在到达站点之前它载有多少辆自行车,(3)它卸下的自行车数量,以及(4)它装载的自行车数量。该模型随后选择最佳决策,使得与再平衡相关联的成本最小化,同时确保路线选择和再平衡约束保持满足。
结果
一旦模型建立起来,我们就可以通过将乘客数据(每个站点的自行车接送)输入到模型中来模拟和评估它在任何给定时间的性能。该模型以每小时为基础进行重复评估,由此在每小时开始时更新自行车流,并随后为该小时生成重新平衡路线和决策。

2019 年 7 月 8 日上午 8:00-9:00 凡尔登碧溪站模拟自行车再平衡操作结果。
为了让我们一窥每小时的再平衡系统会是什么样子,我们创建了一个地图,展示了 7 月 8 日 8:00-9:00 卡车的移动。我们看到,在这一小时内,总共有 5 个站点需要重新平衡。当卡车到达车站(1)时,我们假设它装载了 20 辆自行车(总容量的一半)。然后,在站点 2,卡车装载了两辆自行车,这意味着在此点之前站点一定已经超过了理想容量上限。到达站点 3 时,卡车现在装载了 22 辆自行车,随后卸下了一辆自行车,这意味着站点 3 低于其理想容量下限。在第 4 站,卡车现在载有 21 辆自行车,并卸下两辆,在第 5 站,它载有 19 辆自行车,并卸下一辆。然后,卡车返回 1 号站,该小时的再平衡任务完成。从下面的图表中我们可以看到,在这一小时内,总共行驶了 5.56 公里, 6 辆自行车重新平衡,费用为27.40 美元。

2019 年 7 月 8 日卡车再平衡计划的逐小时结果
为了跟踪再平衡进度,我们计算了从 8:00 到 20:00 每小时开始时的净差异,因为这些时间被视为 BIXI 接送最活跃的时间。如果我们全天运行该模型,我们会发现成本最高的时间是从 16:00 到 17:00,在这一时间需要重新分配 10 辆自行车。中午 12:00-13:00 是第二昂贵的时间;然而,这似乎与行驶的距离更大有关,而不是重新分配的自行车数量。从逻辑上讲,这些繁忙时间对于所选的时间段是有意义的,因为从 16:00 到 17:00,客户将使用该服务下班回家,而从 12:00 到 13:00,客户可能在午餐休息时间使用该服务。
新冠肺炎扩展:优先考虑重要员工的自行车出行
随着最近的新冠肺炎疫情,企业不得不彻底发展其业务模式,以适应不断变化的条件和新出现的客户需求。自行车共享系统也不例外。在疫情开始时,BIXI 经历了基本卫生保健工作者的乘车人数的增加,为了满足这些需求,BIXI 开始向基本工作者提供 30 天的免费会员资格。
基于这一信息,我们通过优先考虑医院附近的自行车可用性来探索原始模型的扩展,以确保医护人员能够获得自行车。为了做到这一点,我们修改了原始的优化问题,在系统的一个新的子区域内为医院增加了一个必需的子行程。基本上,卡车将被要求依次访问医院附近的所有站点,以确保首先满足医院工作人员的需求,然后再前往该地区的其他站点。对于扩建,我们选择了蒙特利尔市中心的一个子区域,该区域包括 57 个车站和 6.07 km 的面积,包括西端的蒙特利尔神经医院(Neuro)和东端的蒙特利尔大学医院中心(CHUM)。CHUM 周围的三个站和 Neuro 周围的七个站被选择作为预定义的子旅程,并且起始站也被设置为 CHUM 医院附近的优先站之一。
虽然最近的一项研究在更复杂的环境中提出了类似的想法,但我们通过添加以下两个约束条件实现了具有优先级的路线选择解决方案,其中,ℙ表示一组优先站点,ℝ表示一组常规站点。

约束(3.1)确保卡车在离开起始优先站之后首先访问优先站,约束(3.2)保证从优先站到常规站的访问不超过一次。只有当所有优先站都已被服务并且随后有后续常规站要被服务时,才发生该动作。注意,当需要重新平衡的所有站都是优先站时,约束(3.2)是非绑定的。
以下两张地图显示了添加优先级约束后路线的变化情况:

不添加(左)和添加(右)医院附近车站优先访问限制的路线。
通过添加这组约束,我们观察到卡车仍然能够满足每小时的重新平衡需求,但是正如预期的那样,访问的顺序发生了变化,因此首先访问每个选定的医院站。例如,通过在 2019 年 7 月 8 日 12:00- 13:00 运行一次再平衡迭代,观察到距离从 6.97 km 增加到 7.62 km ,表示相关成本从33.94 美元增加到40.14 美元。有趣的是,计算复杂度也显著增加;基本模型的求解时间不到 1 秒,而具有优先级约束的 1 小时相等时间段的求解时间为 36.84 秒。考虑到蒙特利尔有超过 10 个主要的健康网络,并且许多网络有几个分支,当考虑是否进行这样的操作时,每小时再平衡成本和计算强度的这种潜在增加不是微不足道的。
最后的想法
这个项目的目标是利用 BIXI 的开放访问历史乘客数据集来模拟自行车的持续再平衡对于保持系统平稳运行和满足自行车需求是多么必要,同时满足 BIXI 的底线。
实际上,BIXI 的自行车再平衡系统可能要复杂得多,例如,自行车再平衡要求的阈值可能是通过考虑天气、人口密度、一天中的时间和交通等因素的算法生成的。我们为再平衡选择固定阈值的假设显然没有捕捉到可能影响再平衡决策的全部潜在变量。此外,虽然我们创建了固定的边界区域,卡车只能在这些区域内运行,但 BIXI 通常会部署多辆卡车,在整个岛屿上灵活行驶,从而更容易处理波动的需求。我们还大大简化了成本和费用的估算,因为 BIXI 还会产生营销、管理和数据收集费用。因此,我们的模型不能从企业整体的成功来解释,而只能从模拟的再平衡过程的有效性来解释。
总的来说,我们的分析旨在通过使用混合整数规划技术来优化自行车的再平衡,以满足预期需求,缓解系统中的过剩和短缺,并保持成本效益,从而深入了解蒙特利尔的 BIXI 自行车共享运营。虽然我们只关注了几个选定的地区和时间段,但所创建的模型是可扩展的,可以扩展到其他行政区或时间段。通过提供对维持这样一个动态系统的要求的关键见解,我们最终试图证明蒙特利尔岛上存在进一步提高友好和高效的交通共享运输系统的价值的机会。
如果您想分享任何想法,请随时在 Linkedin 上联系我们。
其他资源:
- 碧溪开源数据
- Github 库
关于我们的更多信息:
https://www.linkedin.com/in/duncan-w/ https://www.linkedin.com/in/hannaswail/ https://www.linkedin.com/in/beiqizhou/ https://www.linkedin.com/in/tzhang96/
一种更容易获得和复制的方法,用于加利福尼亚人工收割作物的卫星制图
原文:https://towardsdatascience.com/a-more-accessible-and-replicable-method-for-satellite-based-mapping-of-hand-harvested-crops-in-6243b8fb82dc?source=collection_archive---------23-----------------------
变更数据
在整体粮食安全、可负担得起的农产品的可用性和美国农业劳动力短缺之间的密切联系的推动下,洛克菲勒基金会的统计和机器学习团队看到了一个为手收作物开发一种可访问和可复制的早期绘图工具的机会。仍在开发中的手工收割作物制图项目旨在创造一种工具,仅使用卫星图像来了解手工收割作物的产量变化。最佳替代方案是美国农业部农田数据层(CDL ),它使用包括私人来源在内的许多数据层输入,主要关注主要作物,直到第二年早春才发布。迄今为止,我们的模型相对于 CDL 有所改进:它完全基于公开可用的数据,它适用于一次一种作物和一个地区,并且它从同年 8 月开始在加利福尼亚州运行,同时提供与 CDL 相比略有下降的准确性。本博客重点关注动机、方法和迄今为止的发现,但深度学习模型和该模型的扩展方面的工作仍在继续。
我们的方法:预见生产挑战
绘制手工收割作物地图的最初动机来自疫情之初,当时有关边境关闭、国内旅行限制、学校关闭等消息表明农业工人短缺进一步加剧。在疫情开始之前,劳动力已经存在基线缺口——2019 年,加州农场局联合会和加州大学戴维斯分校的一项研究发现,在过去的五年里,加州 56%的受访农民无法获得所需的全部劳动力。当新冠肺炎封锁在美国开始时,各地的劳动者都面临着一个艰难的决定,即是否要冒着暴露于病毒的风险去上班和工作,通常是与他人密切接触。根据 2018 年全国农业工人调查,在出生于墨西哥的美国农场工人中,69%的人季节性迁移,这些人受到封闭的陆地边界和关闭的美国领事馆的进一步挑战。对于生活在美国、有孩子但没有强大支持网络的员工来说,要么呆在家里,要么努力为失学的孩子找到一个不太可能负担得起的托儿服务,这两者之间的选择增加了额外的复杂性。这些和其他因素都导致不工作的决定,加剧了现有的劳动力短缺,给依赖工人收获作物的生产者带来了巨大的不确定性。
受这种短缺影响的手工收获的作物是洛克菲勒基金会食品倡议组织称之为“保护性食品”的更广泛食品的一部分——这些食品有助于预防和保护与饮食有关的疾病,根据健康指标和评估研究所的全球疾病负担研究,这是美国最大的死亡原因。虽然许多食物可以起到保护作用,但即使对于最脆弱的家庭来说,水果和蔬菜也是最容易获得和负担得起的。在 2018 年美国最常购买的二十种水果和二十种最常购买的蔬菜中, 14 和 10 分别是手工收获的,包括苹果、核果、柑橘、浆果、西红柿和蔬菜等农产品。手工收割作物产量减少意味着价格上涨和供应减少,限制了最弱势群体获得这些食物。因此,理解手工收获的食品生产系统——并跟踪生产的变化——感觉与我们在洛克菲勒基金会推广保护性饮食的工作密切相关。

蒂姆·莫斯霍尔德在 Unsplash 上拍摄的加州草莓采摘者的照片
作为食品和遥感领域的首席数据科学家,我假设加剧的劳动力短缺以及其他压力因素(不可预测的市场、重大野火等)。)可能会导致生产者在 2020 年或 2021 年不冒险种植。这些大规模决策可能会导致产量大幅下降,从而影响美国最弱势群体获得高营养食品的能力。基于遥感的制图非常适合这种假设检验,因为数据存在于大规模数据中,可追溯到多年前,分辨率允许在整个区域范围内以 10 米乘 10 米的比例进行分类。我把重点放在加州中央谷,因为根据加州农业部的数据,这里生产蔬菜的⅓,水果和坚果的⅔,以及美国 90%以上的葡萄、李子、橄榄、杏仁、开心果和其他作物。该山谷以西部的海岸山脉和东部的内华达山脉为界,总长度为 450 英里(720 公里),宽 50 英里(80 公里),相当于约 18,000 平方英里(47,000 平方公里)和约 4.7 亿个要分类的“地块”或像素。前面的文档描述了我迄今为止的方法和结果。

加州县与中央山谷重叠,在谷歌地球引擎中可视化。
方法:准备随机森林分类器
为了完成这项任务,我首先选择了一种作物分类方法。随机森林长期以来一直是遥感工作的主要内容,因为它相对简单,并且具有高数据维度和多重共线性——光学遥感数据的两个基本特征。虽然深度学习模型因其突破性见解和提高准确性的潜力而受到极大关注,但随机森林始终是测试的基线,因此是一个合理的起点。其次,我决定首先专注于创建一个二元随机森林分类器,原因很简单,只要分类器能够识别感兴趣的作物,其余的土地覆盖是什么就无关紧要了。从整体系统的角度来看,周围区域的土地覆盖总是很重要的,但是由于多类分类器在任何一种作物的确定性较低时通常倾向于像主粮这样的高覆盖作物,因此本项目中感兴趣的目标作物可能会被低估-因此,二元分类是一个合理的起点。
鉴于 Rockefeller Foundation 没有手收作物位置的现有样本集,并且由于疫情期间不可能进行野外工作,我选择从美国农业部的历史农田数据图层分类中进行采样作为替代。如前所述,CDL 每年都会为整个美国创建一张最有可能种植作物的地图,并报告分类以及每个像素的分类概率。虽然这种分类对主要作物表现更好,但它是更可靠数据或定制数据收集的良好替代品。对于每个训练集,我首先从聚焦区域内的 CDL 中采样 10,000 个像素,并过滤掉 80%或更高置信度的像素。我将这些样本分类重新映射为目标作物或非目标作物的二元分类,然后使用这些像素位置对卫星图像进行采样。
对于不熟悉卫星图像的读者来说,术语“卫星图像”可能有点误导——特定时间和位置的每个“图像”都是一组光栅“波段”,用于捕捉特定波长的反射阳光强度和反射率。因此,使用卫星影像需要转换和操作多个栅格堆栈,这将在本文稍后简要介绍。下面是卫星图像波段堆栈和单个像素样本的几何图形的可视化:

仙黛尔·诺顿编写
对于这项工作,我选择 Sentinel-2 作为光学数据,Sentinel-1 作为雷达数据,因为它们重复次数多,分辨率高,有历史数据,可以自由访问。我有意只选择两个来源来创建最精简、最可复制的模型;作为参考,CDL 农田数据层使用来自戴莫斯-1 和英国-DMC-2(两者都是欧洲星座中的有限接入卫星)、哨兵-2、陆地资源卫星 8 和资源卫星 2 的产品,以及美国地质调查局土地覆盖层和美国农业部 CDL 层基于2019 年文档。
许多土地分类可以简单地用来自精选卫星源的单一精选图像来完成——例如,对城市公园进行分类,并挑选植物生长的图像。然而,由于许多植物在一年中的某些时间在光谱带上具有非常相似的值,物种和作物分类问题通常需要与衰老曲线相关的时间序列信息,衰老曲线涉及植物的逐渐变绿,然后随着叶绿素的产生而变褐,然后死亡。在不同的光谱带,尤其是近红外光谱,这条曲线通常会显示为读数变亮,然后变暗,因为叶绿素在高强度下反射某些波长。因为不是所有的植物都在完全相同的时间长出叶子或产生相同面积的叶子和相同体积的叶绿素,衰老曲线的特征可以是非常有用的,甚至是唯一的标识符。对整个季节的值取平均值是一个强大的转换,可以大大减少数据量,同时捕捉曲线的本质。应用这个来准备 Sentinel-2 的图像,我用 QA60 cloudmask 波段遮蔽了云层,然后对 3 月初至 7 月底的所有图像进行平均。这一时间框架抓住了中央山谷的夏季生长季节,许多作物在 3 月种植或转移到外面,7 月收获。在每个像素处取平均值显著地将数据集的大小从大约十个 Sentinel-2 图像(每两周捕获一次)减少到仅仅一个,减少了噪声并有助于捕获独特的衰老曲线特征。尽管 Sentinel-1 图像数据作为合成孔径雷达(SAR)卫星产品有着根本的不同,但出于类似的原因,它也被平均化。下面是一个例子,说明在加利福尼亚的整个生长季节,单个像素上的单个虚构光学波段如何变化,以及在遥感工作中,作物的生物物理变化如何转化为衰老平均值。

仙黛尔·诺顿编写
在上面想象的场景中,这些田地自上一季以来就没有被开垦过,可能有少量的杂草生长;李树还没有叶子。在室外种植甜椒、甜瓜和卷心菜之前,将对土地进行翻耕——这将吸收光线的潮湿土壤带到表面,因此降低了卫星观测到的反射率。在主要作物入土并且树木作物开始开花并长出叶子后,植物将显著增加它们的叶面积和叶绿素含量,增加反射率,直到接近收获时达到峰值。之后,植物会枯死,松散的叶子和卷心菜、甜瓜和甜椒地会被翻耕,反射率会下降。在这个模拟示例中,您可以看到,虽然大多数作物在六月底左右有一个相似的高峰期,但它们各自的曲线是独特的。当我们平均整个季节的反射率值时,每种作物都有一个独特的值,这是曲线本身的一个相当独特的 ID-李子 6.1 最高,卷心菜 2.8 最低。这项工作中使用的所有波段的唯一 id 组合产生了每种作物的唯一 id 向量。
接下来,我从采样波段中准备了一些指数,用于对 Sentinel-1 和 Sentinel-2 准备的影像进行实验,并使用随机森林模型来确定重要变量,这极大地有助于模型开发过程,尤其是减少准备的数据集的大小。为了了解处理的数据量,在中央山谷所有像素使用的所有波段和所有日期的图像派生指数之间,大约有 3000 亿个数据点。最终使用的波段和指数为蓝色、Sentinel-2 观测的角度、作物残留覆盖指数(CRC)、归一化燃烧指数(NBR)、使用红色代替近红外的绿色叶绿素植被指数(GCVI)以及使用 Sentinel-1 的精细 Lee 滤波器的 VH 多极化波长斑点测量。样本按县、流域(代表覆盖流域流域的 3-4 个县)或 2019 年整个中央流域准备。这些样本被送入随机森林,该森林使用了 160 棵树,并将 2018 年图像的内核减少到 5 个像素正方形,即 50 米乘 50 米的瓦片。Kern、Glenn、Butte 和 Tehama 县被排除在外,因为它们在 EE 中返回了错误,而 Shasta 被排除在外,因为它在中央山谷中包含如此少量的农业像素。随机森林的可视化如下所示,其中样本向量输入向量包括单波长观测值和如上所述的整个生长季节的平均指数:

仙黛尔·诺顿编写
然后使用 2019 年相应测试年的 CDL 评估按县分类的结果影像,仅包括置信度为 80%或更高的像素。下图显示的是加利福尼亚州同一区域的田地,仅包含卫星影像、分类器输出和用于参考的杏树 CDL 分类(其中杏树在分类器影像中为浅灰色,在 CDL 影像中为白色)-请注意,分类很接近,但并不完全相同。精度和召回被用来评估分类器的性能对 CDL,它只报告精度和召回在国家一级。并非所有作物都有足够的数据用于分类器——许多不太常见的手工收割的作物,或者在特定区域不太常见的作物,不能用于建模。例如,圣华金县的樱桃代表 1,063,300 个像素中的 62,617 个像素,约占高可信度农业像素景观的 5.9%,但返回的结果较差,这与杏仁的 186,400 个像素相比相形见绌,杏仁约占圣华金高可信度农业景观的 17.5%,建模效果非常好。

由 Madeline Lisaius 使用谷歌地球引擎编写
结果、观察和结论

从上表中可以看出,数据丰富的坚果作物,尤其是杏仁,在所观察的县和日期表现非常好。相比之下,数据越少的作物——葡萄、西红柿和樱桃——表现越差,部分原因是它们用于训练的数据越少,部分原因是用于分类的像素数量(与覆盖率更高的杏树相比)非常少,有时超过 1000 万个像素中只有 10,000 个像素。这些结果是初步的,但是它们给出了与 CDL 相比该模型的功效的感觉。
总的来说,我们所描述的模型在许多情况下在 CDL 的范围内执行,其优点是仅使用公共数据,能够在同年 8 月开始运行,并且公开可用。然而,有许多可能的扩展和改进途径,可以使这种模式高效地扩展到更多的作物。最有效但劳动密集型的方法之一是通过亲自实地考察或从种植者处获得参考坐标来收集感兴趣作物的样本。这将通过在 CDL 采样框架之外增加高置信度数据来增加可以成功建模的作物数量。虽然自举数据是一种选择,但在特定生长条件下的物种生理——转化为跨波长的独特遥感光谱特征集——不容易模拟,因此应谨慎使用这种方法。改进模型的下一步将是增加一层再处理,以去除分类图像中的斑点像素,这将提高召回率和精确度。
该模型本身还没有实现更高层次的目标,即能够以必要的精度在田间水平上精确地测量手工收获作物的种植和生长面积的变化。尽管如此,我们对这一模型的潜力感到非常兴奋,与 CDL 相比,这是一种更轻便、更容易理解作物,尤其是非主粮作物的方法。随着更多的工作,该模型可以更精确地用于目标地区,在这些地区,比例过高或过低的农民正在改变行为以应对冲击,作为一种工具来确定投资目标和确定学习机会。该模型还可以用来预测大规模和特定的粮食生产的变化。由于气候变化和长期劳动力趋势,加州和其他生产手工收割作物的地区面临越来越多的困难,了解景观水平的变化对于了解美国营养食品的供应比以往任何时候都更加重要。该工具的未来版本和其他版本可能有助于提供见解,这些见解可以补充农场工人、农民和其他利益相关者的生活经验,从而就如何保护性地养活美国提供整体和微妙的观点。
具有 Streamlit 和 Plotly 的多页交互式仪表板
原文:https://towardsdatascience.com/a-multi-page-interactive-dashboard-with-streamlit-and-plotly-c3182443871a?source=collection_archive---------4-----------------------
数据可视化
Streamlit 使漂亮的交互式多页仪表板变得简单

Streamlit 应用非常简洁——图片由作者提供
Streamlit 的伟大之处在于,它不仅漂亮,而且简单。
几个月前,我写了一篇关于如何使用 Plotly 和 Flask 编写仪表板的文章——这是使用 Dash 的替代方法,我对此非常满意。这个应用程序由两个文件组成,一个 20 多行的 Python/Flask 应用程序和一个近 30 行的 HTML/Javascript 文件。你可以在这里看到这篇文章:
[## 使用 Plotly 和 Flask 的交互式 Web 仪表板
towardsdatascience.com](/an-interactive-web-dashboard-with-plotly-and-flask-c365cdec5e3f)
然后我决定尝试使用 Streamlit 实现同样的东西:结果是一个大约十几行的 Python 文件。四分之一大小!不仅写起来简单快捷,而且看起来也更好看。
因此,我想分享我的经验,首先,创建一个简单的交互式 Streamlit 应用程序和 Plotly 图表,然后将它开发成一个更复杂(但仍然简单)的多页应用程序。在这个过程中,我研究了如何绘制 Plotly 图表、在 Streamlit 中控制布局以及使用下拉菜单导航。
第一个应用程序将是我的 Flask 应用程序的克隆,看起来像这样:

作者简单的 Streamlit 应用程序图片
用户从左边的下拉菜单中选择一个国家,并在右边绘制相应的图表。
Streamlit 应用程序只是一个 Python 程序,它使用 Streamlit 库,并在终端窗口中使用 Streamlit 命令运行。例如
streamlit run myapp.py
然后它会启动你的浏览器并运行应用程序。
不过,首先要做的是。要使用 Streamlit,您显然必须安装它:
pip3 install streamlit
或者其他任何你用来安装 Python 包的神秘方法。
简单的 Streamlit 应用程序
你用类似这样的东西开始你的 Python 程序:
import streamlit as st
import pandas as pd
import plotly.express as px
我将使用 Pandas 来存储和操作数据,并绘制图表。
出于演示的目的,我使用 Plotly 包中包含的 Gapminder 数据。所以,下一段代码是:
df = pd.DataFrame(px.data.gapminder())
这将创建一个数据帧,其中包含一个关于世界上所有国家的信息表,如下所示:

国家数据-按作者分类的图像
表中列出了每个国家,以及几十年来的预期寿命、人口和人均 GDP 数据。也给出了每个国家的大陆(也有其他数据,但这里不感兴趣)。
我们最初要做的是创建一个选定国家的人口和人均 GDP 的图表。因此,我们需要一个国家名称列表,用户可以从中进行选择。这可以通过从数据框中选择 country 列并创建一个唯一名称列表来轻松实现。
clist = df['country'].unique()
运行之后,我们在变量clist中有一个唯一名称的列表。

国家列表-作者图片
下拉菜单是在clist的侧边栏中创建的,如下所示:
country = st.sidebar.selectbox("Select a country:",clist)
所有的 Streamlit 函数都以st开始。st.sidebar在屏幕左侧创建一个侧边栏,.selectbox使用第一个参数中提供的提示从列表中创建一个下拉列表。
接下来我们画图表。
fig = px.line(df[df['country'] == country],
x = "year", y = "gdpPercap", title = country)
在这里,您可以看到我们在变量fig中创建了一个折线图,只选择数据框中与所选国家对应的行。
整个程序如下所示,正如我前面提到的,它只有十几行代码。
import streamlit as st
import pandas as pd
import plotly.express as pxdf = pd.DataFrame(px.data.gapminder())
clist = df['country'].unique()country = st.sidebar.selectbox("Select a country:",clist)st.header("GDP per Capita over time")fig = px.line(df[df['country'] == country],
x = "year", y = "gdpPercap", title = country)
st.plotly_chart(fig)
有几行我还没讲过。st.header("GDP per Capita over time")创建标题,st.plotly_chart(fig)绘制图表。
当我们运行这个程序时,我们得到了这个:

作者简单的 Streamlit 应用程序图片
我认为,对于这样一个小程序来说,这已经很不错了。
但事情会变得更好。
多页应用程序
我努力说服自己,我可以像使用 Dash 一样轻松地使用 Flask 和 HTML 制作应用程序,作为努力的一部分,我创建了一个简单的多页面应用程序,每个页面使用相同的 HTML 模板,但从 Flask 加载不同的数据。你可以在这里看到这篇文章:
[## 用 Plotly 和 Flask 实现 Web 可视化。
towardsdatascience.com](/web-visualization-with-plotly-and-flask-3660abf9c946)
Streamlit 的情况就不同了。没有对多页面特定支持,我猜这不是一个遗漏。Streamlit 并不意味着创建完整的网站。
但有时一点分页是有用的,所以我写了一个新的应用程序,它在第一个基础上扩展,提供更多信息,并在两个页面上运行。看起来也更好看!
我们的目标是拥有两个页面,一个针对国家,另一个针对大洲。在每一页上,你可以选择一个国家或洲,你会得到两个图表,一个是 GDP,另一个是人口。你可以在下面看到大陆页面的样子。

作者提供的多页 Streamlit 应用程序图片
实际上,也许你看不太清楚,所以这是页面左侧的放大图。

来自多页 Streamlit 应用程序的详细信息-作者图片
左侧是带有下拉菜单的侧栏,您可以在其中选择国家或洲。页面的主要部分包含图表,并有自己的下拉菜单来选择哪个洲(欧洲、亚洲等)。)或者哪个国家。
国家页面看起来像这样。

作者提供的多页 Streamlit 应用程序图片
这个方法很简单。只需在if… else…语句中使用侧边栏下拉菜单返回的值,并在if块或else块中显示适当的数据。代码如下所示:
page = st.sidebar.selectbox('Select page',
['Country data','Continent data'])if page == 'Country data':
# Display the country content here
else:
# Display the continent content here
我使用分栏来并排显示图表,我将布局设置为 wide 以给自己多一点空间。
除此之外,替换这些注释的代码与我们在第一个例子中看到的非常相似。
以下是完整列表:
import streamlit as st
import pandas as pd
import plotly.express as pxst.set_page_config(layout = "wide")df = pd.DataFrame(px.data.gapminder())st.header("National Statistics")page = st.sidebar.selectbox('Select page',
['Country data','Continent data'])if page == 'Country data':
## Countries
clist = df['country'].unique() country = st.selectbox("Select a country:",clist) col1, col2 = st.columns(2) fig = px.line(df[df['country'] == country],
x = "year", y = "gdpPercap",title = "GDP per Capita")
col1.plotly_chart(fig,use_container_width = True) fig = px.line(df[df['country'] == country],
x = "year", y = "pop",title = "Population Growth")
col2.plotly_chart(fig,use_container_width = True)else:
## Continents
contlist = df['continent'].unique()
continent = st.selectbox("Select a continent:",contlist) col1,col2 = st.columns(2) fig = px.line(df[df['continent'] == continent],
x = "year", y = "gdpPercap",
title = "GDP per Capita",color = 'country')
col1.plotly_chart(fig) fig = px.line(df[df['continent'] == continent],
x = "year", y = "pop",
title = "Population",color = 'country')
col2.plotly_chart(fig, use_container_width = True)
现在,如果我聪明的话,我会意识到我在这个应用程序中有大量非常相似的代码,所以会写一些函数来减少这种情况。但是现在我会让它保持原样。
利弊
Streamlit 易于使用并产生非常好的结果,但它只为相当简单的应用程序设计。布局复杂的多页面应用程序并不是它真正想要的,这很公平。
Streamlit 确实有一些很好的布局组件(改天会有更多),多页面应用可以通过 Python 3.10 模式匹配更好地实现(见这里和这里)——改天也会有更多。
一如既往地感谢阅读。你可以在我的 Github 页面下载代码,并在这里看到最终应用的演示,在我的网页上有一大堆关于 Streamlit、数据可视化和 Python 的文章。
更新:我最近设计了一个更复杂的方法,在 Streamlit 的一个网站上创建多个应用程序。在这里阅读: 如何将 Streamlit 应用程序库构建为一个单独的 Web 应用程序
如果你不是一个媒体订阅者,那就注册吧,这样你就可以每月花 5 美元阅读尽可能多的文章。在这里注册我会赚一小笔佣金。
https://alanjones2.github.io
通过社交媒体分析长期直播事件的多视角方法
原文:https://towardsdatascience.com/a-multi-perspective-approach-for-analyzing-long-running-live-events-through-social-media-9162079bfbc8?source=collection_archive---------36-----------------------
思想和理论,纽约,巴黎,米兰,伦敦
四大时装周的案例

Armen Aydinyan 在 Unsplash 上的照片
社交媒体正在主宰人们的日常生活。在我们的生活中,它既是信息的来源,也是分享个人经历和观点的地方。
特别是,它在大型活动(如阿拉伯之春、美国总统选举和许多其他场景)中展示了巨大的沟通、互动和社区建设潜力。
我们提出了一种实用的方法来研究所谓的长期现场活动(LRLEs) 的影响和作用,即活动持续时间长,由某个主办实体组织,在某些地点实际举行,并在很长一段时间内周期性重复。
我们旨在通过探索和分析与 LRLEs 相关的社交媒体平台上产生的用户生成内容(UGC)来研究此类事件。事实上,UGC 主要反映了参与者在实际活动中的亲身体验,因此是关于事件发生的信息。
这吸引了许多社区。对于公共部门来说,这是一扇新的大门,可以探索一些无法解释的主题,如社会的行为模式和改善沟通。对于品牌和企业来说,这是一种了解客户和投放广告的有利可图的方式,因为与其他形式的广告相比,它们可以以更低的成本吸引更多的公众注意力。
我们设计了一种实用的数据科学方法,其目标如下:
- 理解事件期间用户行为的时间动态。
- 了解用户的地理分布及其发布活动。
- 研究活动期间的品牌知名度。
- 检测事件位置和以品牌为目标的参与者的发布动态之间的相关性。
- 确定影响用户生成内容的受欢迎程度的主要因素,并设计模型来预测此类内容的受欢迎程度。
以下是一个概念模型,代表了在此环境中发挥作用的主要实体:

长期运行的实时事件的概念模型(图片由作者提供)
应用多模态方法需要考虑帖子相关的信息、帖子的内容和用户特征。特别是,我们需要提取和分析:
- 与用户相关的特征,也称为社交环境属性,收集发帖用户的相关信息,如其关注者和关注人数、个人资料类型、等。
- 与内容相关的信息,取决于短信的类型(例如,YouTube 上的视频和 Twitter 上的文本),可能包括视觉特征。
- 帖子相关的特征,即通过 API 收集的帖子的元数据,如时间和地理属性、标签、标记、评论数、等。
- 事件相关特征,包括目标事件的统计信息,如平均点赞数,或事件本身的具体信息。
为了展示我们的工作方法,我们选择了四大时装周,分别在纽约、巴黎、米兰和伦敦举办。我们在 Instagram 上收集关于这些事件的 UGC 内容,通过 Instagram API,通过基于标签的数据收集方法来最大化覆盖范围。产生的数据集由 905,726 条 Instagram 帖子、171,078 条与之相关的用户资料和 723,831 张图片组成。

帖子中城市间相关性的重叠。[图片由作者提供]
该研究从理解帖子与事件的相关性开始。结果显示,大多数帖子(92.866%)只与四个城市之一相关。尽管如此,还是存在一些重叠,如此处所示。动机是一些用户发布内容将他们与许多时装周联系起来,只是为了增加他们的知名度。这显然与事件的研究无关,因此可能是至关重要的。
采用的分析维度包括以下报告的维度:
- 标签分析
- 时间分析
- 地理影响
- 网络分析(关注者)
- 流行预测
- 品牌分析

(左)用户的追随者数量( y 轴)与对数形式的追随者数量( x 轴)和(右)。[图片由作者提供]
仔细观察左图,我们可以注意到三个更密集的区域,分别位于位置 0、999 和 7500。第一个峰值是 840 个用户的结果,正好有 0 个追随者,但不同的追随者计数。他们可能是决定不关注任何人或未使用或伪造账户的名人。还有一种可能是 Instagram 禁止了一些用户关注其他人。另一方面,第三个高峰,收集了非常正确部分的所有点,可能是机器人,他们关注许多帐户,以吸引追随者或增加他们的帖子或帐户的可见性。他们的追随者数量平均少于他们的追随者数量。这个峰值对应于 234 个用户,他们准确地关注 7500 个帐户,但是具有不同的关注者计数。这个具体数字可能是 Instagram 的一项政策造成的,该政策禁止用户关注超过 7500 个个人资料。
对于地理分析,我们可以利用地理标记。在收集的 905,726 个帖子中,42.59%带有地理标签。这是每个事件最相关区域的热图。

每个事件的帖子热图。[图片由作者提供]
活动-品牌关系也是一个相关的维度,尤其是对于理解不同品牌的作用和影响。因此,它们中的每一个都被映射到该位置。例如,您可以在这里看到 Spearman 相关性分析的热图矩阵,显示了从四大城市中每个城市对两个品牌(迪奥和香奈儿)的回复中获得的值之间的相关系数。

迪奥和香奈儿影响着不同的时装周。[图片由作者提供]
使用 SVR、XGboost 和 RNN 方法,还开发了一个事件相关帖子受欢迎程度的预测器。
其他分析结果的快速总结显示在本文结尾的图片中,而该方法的完整描述则发表在科学论文(开放获取)中:
Javadian Sabet A .、Brambilla M .、Hosseini M. **一种用于分析社交媒体上长期直播事件的多视角方法。“四大”国际时装周案例研究。**在线社交网络与媒体,第 24 卷,2021,100140,刊号 2468–6964,【https://doi.org/10.1016/j.osnem.2021.100140】。
(https://www . science direct . com/science/article/pii/s 2468696421000239)
数据集也可以在网上获得,在这篇数据集文章中有所描述:
Brambilla M .、Javadian Sabet A .、Hosseini M. 社交媒体在长期直播事件中的作用:四大时装周数据集的案例。 数据简介,35 条【2021】,106840 条10.1016/j . DIB . 2021.106840

多重分析视角。[图片由作者提供]
自然语言处理初级读本
原文:https://towardsdatascience.com/a-natural-language-processing-nlp-primer-6a82667e9aa5?source=collection_archive---------10-----------------------
使用 Python 的常见 NLP 任务概述

照片由 Skylar Kang 从 Pexels 拍摄
自然语言处理 NLP 用于分析文本数据。这可能是来自网站、扫描文档、书籍、期刊、推特、YouTube 评论等来源的数据。
这本初级读本介绍了一些可以使用 Python 执行的常见 NLP 任务。示例大多使用自然语言工具包(NLTK)和 scikit 学习包。假设您具备 Python 和数据科学原理的基本工作知识。
自然语言指的是像英语、法语、阿拉伯语和汉语这样的语言,而不是像 Python、R 和 C++这样的计算机语言。NLP 使文本数据的部分分析自动化,这在以前只有定性方法才有可能。这些定性方法,如框架/主题分析,不能扩展到大量的文本数据。这就是 NLP 的用武之地。它还被用于创建聊天机器人、数字助理(如 Siri 和 Alexa)等其他用途。
本笔记本中使用的数据来自https://www.english-corpora.org/corona/【1】的数据子样本。这些数据是关于冠状病毒疫情的,代表了来自各种媒体来源(例如报纸、网站)的子集,并且是 2020 年 1 月至 5 月期间的数据。该数据包含大约 320 万个英语单词。
使用 Python 加载文本数据
让我们从查看文本数据开始,看看它是什么样子的。我们可以使用操作系统( os )库来列出我们的文本文件夹中的所有文件。在这种情况下,文件位于名为 text 的文件夹中,该文件夹位于名为 NLP 的文件夹中,该文件夹与 Python 源代码文件相关(例如 Jupyter notebook 或。py 文件)并用“.”表示。/".
import os
os.listdir("./NLP/text")
这将生成一个包含 5 个文本文件的列表:
>>> ['20–01.txt', '20–02.txt', '20–03.txt', '20–04.txt', '20–05.txt']
如您所见,有 5 个文本文件(*。txt)。我们可以使用标准的 Python 文件处理函数来打开文件。在这种情况下,我们将把它限制在前 10 行,以了解文件的结构和它包含的信息。在下面的输出中,为了简洁起见,这被缩短了。 next 函数用于遍历文件中的行。
with open("./NLP/text/20–01.txt") as txt_file:
head = [next(txt_file) for i in range(10)]
print(head)>>> ['\n', '@@31553641 <p> The government last July called the energy sector debt situation a " state of emergency . " <p> This was during the mid-year budget review during which the Finance Minister Ken Ofori-Atta castigated the previous NDC government for entering into " obnoxious take-or-pay contracts signed by the NDC , which obligate us to pay for capacity we do not need . " <p> The government pays over GH ? 2.5 billion annually for some 2,300MW in installed capacity which the country does not consume . <p> He sounded alarmed that " from 2020 if nothing is done , we will be facing annual excess gas capacity charges of between $550 and $850 million every year . <p> JoyNews \' Business editor George Wiafe said the latest IMF Staff report expressing fears over a possible classification is " more of a warning " to government . <p> He said the latest assessment raises concerns about the purpose of government borrowings , whether it goes into consumption or into projects capable of generating revenue to pay back the loan . <p> The move could increase the country \'s risk profile and ability to borrow on the international market . <p> @ @ @ @ @ @ @ @ @ @ issue another Eurobond in 2020 . <p> The Finance Minister Ken Ofori-Atta wants to return to the Eurobond market to raise $3bn to pay for expenditure items the country can not fund from domestic sources . <p> The government wants to spend GH ? 86m in 2020 but is projecting to raise only GH ? 67bn . It leaves a deficit of GH ? 19bn , monies that the Eurobond could make available . <p> The planned return to the Eurobond market is the seventh time in the past eight years . <p> Ghana is already among 10 low-income countries ( LICs ) in Africa that were at high risk of debt distress . <p> The country in April 2019 , successfully completion an Extended Credit Facility ( ECF ) programme , or bailout , of the International Monetary fund ( IMF ) . \n']
文本表示
为了以数字方式存储和使用字符,通常用编码系统来表示它们。有 ASCII (美国信息交换标准码)等不同的字符编码标准。例如,字母“a”由 ASCII 码 097 表示,在二进制中也是 01100001。还有其他编码集,如 UTF-8 (Unicode(或通用编码字符集)转换格式,8 位)支持可变宽度的字符。这个系统中的字母“a”是 U+0061。在 Python 中,我们可以像这样直接使用 UTF-8:
u"\u0061">>> 'a'
您可能需要转换导入的文本数据的字符编码,以执行进一步的处理并更好地表示某些符号(例如表情符号🌝).您可以使用 sys 模块中的 getdefaultencoding 函数检查您正在使用的编码类型。要更改编码,您可以使用 setdefaultencoding 函数,例如sys . setdefaultencoding(" utf-8 ")。
import sys
sys.getdefaultencoding()>>> 'utf-8'
数据预处理
应用 NLP 时,数据处理有几个阶段。这些根据确切的上下文而有所不同,但通常遵循类似于下图所示的路径。这通常包括访问文本数据,无论是网页、推文、评论、PDF 文档还是原始文本格式。然后将其分解为算法可以轻松处理的表示形式(例如,表示单个单词或字母的标记),移除常用单词(停用词)(例如,“and”、“or”、“the”)。进一步的标准化之后是诸如特征提取和/或去除噪声的任务。最后,各种模型和方法(例如,主题建模、情感分析、神经网络等。)都适用。

文本数据的通用预处理方法(图片由作者提供)
因为我们已经有了一些要处理的文本,所以我们可以看看预处理数据的后续步骤。我们可以从标记化开始。很多 Python 库都可以完成标记化,包括机器学习库 scikit learn。自然语言处理任务的一个流行库是自然语言工具包(NLTK):
import nltk
**注意:**Python 中另一个强大的 NLP 替代库是 spaCy 。
符号化
即使在库中,也经常有不同的标记器可供选择。例如,NLTK 也有一个 RegexpTokenizer(使用正则表达式)。这里我们将使用 TreebankWordTokenizer 来过滤掉一些标点符号和空格。
from nltk.tokenize import TreebankWordTokenizer
我们将从文本数据中提取一小段文本来说明这是如何工作的。在这里,我们将它作为一个字符串(Python 中用来存储文本数据的一种数据类型)存储在一个名为 txt 的变量中。
txt = "The government last July called the energy sector debt situation a state of emergency. <p> This was during the mid-year budget review during which the Finance Minister Ken Ofori-Atta castigated the previous NDC government for entering into obnoxious take-or-pay contracts signed by the NDC , which obligate us to pay for capacity we do not need . <p> The government pays over GH ? 2.5 billion annually for some 2,300MW in installed capacity which the country does not consume ."
简单的第一步可能是将所有文本转换成小写字母。我们可以通过下功能来实现。
txt = txt.lower()
txt>>> 'the government last july called the energy sector debt situation a state of emergency. <p> this was during the mid-year budget review during which the finance minister ken ofori-atta castigated the previous ndc government for entering into obnoxious take-or-pay contracts signed by the ndc , which obligate us to pay for capacity we do not need . <p> the government pays over gh ? 2.5 billion annually for some 2,300mw in installed capacity which the country does not consume .'
接下来我们可以创建一个treebankwodtokenizer类的实例,并使用 tokenize 函数,传入我们的 txt 变量。输出如下所示(显示前 20 个)。
tk = TreebankWordTokenizer()
tk_words = tk.tokenize(txt)
tk_words[:20]>>> ['the',
'government',
'last',
'july',
'called',
'the',
'energy',
'sector',
'debt',
'situation',
'a',
'state',
'of',
'emergency.',
'<',
'p',
'>',
'this',
'was',
'during']
这个 casual_tokenize 对于社交媒体符号化很有用,因为它可以很好地处理用户名和表情符号之类的事情。 TweetTokenizer 也为 Twitter 分析保持了完整的散列标签。
处理停用词和标点符号
下一件常见的事情是删除停用词。这些是在句子结构中使用的常见高频词,但对分析来说没有太多意义。这些词包括“the”、“and”、“to”、“a”等。我们可以从 NLTK 库中下载这些单词的列表,并将它们存储在一个变量( sw )中,如下所示:
nltk.download("stopwords", quiet=True)
sw = nltk.corpus.stopwords.words("english")
我们可以看看这些单词的前 20 个。
sw[:20]>>> ['i',
'me',
'my',
'myself',
'we',
'our',
'ours',
'ourselves',
'you',
"you're",
"you've",
"you'll",
"you'd",
'your',
'yours',
'yourself',
'yourselves',
'he',
'him',
'his']
在写这篇文章的时候,列表中有超过 100 个停用词。如果你感兴趣,可以使用 len 函数查看列表中有多少单词(例如 len(sw) )。
现在让我们把这些停用词从标记词中去掉。我们可以使用 Python list comprehension 来过滤 tk_words 列表中不在停用字词( sw )列表中的字词。
tk_words_filtered_sw = [word for word in tk_words if word not in sw]
如果您不熟悉列表理解,它们本质上是一种创建列表和遍历列表数据结构的简洁方法。这通常避免了需要多几行单独的“for 循环”代码。假设我想求 0 到 5 的平方。我们可以像这样使用 for 循环:
squared_nums = []
for n in range(5):
squared_nums.append(n**2)
虽然这有预期的效果,但我们可以创建列表,并使用列表理解来遍历它,而不是将它组合成一行代码:
squared_nums = [n**2 for n in range(5)]
如果我们输出变量 tk_words_filtered_sw 的内容,我们可以看到很多停用词现在都被删除了(为简洁起见,缩写为):
tk_words_filtered_sw>>> ['government',
'last',
'july',
'called',
'energy',
'sector',
'debt',
'situation',
'state',
'emergency.',
'<',
'p',
'>',
'mid-year',
'budget',
'review',
'finance',
'minister',
'ken',
'ofori-atta',
'castigated',
'previous',
'ndc',
'government',
'entering',
'obnoxious',
'take-or-pay',
'contracts',
'signed',
'ndc',
','
...
可以看到文本中仍然有句号(句号)、问号、逗号之类的标点符号。同样,我们通常会从列表中删除这些内容。这可以通过多种不同的方式来实现。这里,我们使用字符串库来删除存储结果的标点符号,这个结果存储在一个名为 no_punc 的变量中。
import string
no_punc = ["".join( j for j in i if j not in string.punctuation) for i in tk_words_filtered_sw]
no_punc>>> ['government',
'last',
'july',
'called',
'energy',
'sector',
'debt',
'situation',
'state',
'emergency',
'',
'p',
'',
'midyear',
'budget'
...
然后我们可以从列表中过滤掉这些空字符串(“”)。我们可以将结果存储在一个名为 filtered_punc 的变量中。
filtered_punc = list(filter(None, no_punc))
filtered_punc>>> ['government',
'last',
'july',
'called',
'energy',
'sector',
'debt',
'situation',
'state',
'emergency',
'p',
'midyear',
'budget'
...
最后,我们可能还想从列表中删除数字。为此,我们可以使用 isdigit 函数检查字符串是否包含任何数字。
str_list = [i for i in filtered_punc if not any(j.isdigit() for j in i)]
如您所见,文本数据可能非常混乱,需要在开始运行各种分析之前进行大量清理。另一种去除不必要单词的常用方法是使用词干法或词干法。
词干化和词汇化
词干化指的是将单词缩减到它们的词根(词干)形式。例如,单词“waited”、“waities”、“waiting”可以简化为“wait”。我们可以看一个叫做波特词干分析器的普通词干分析器的例子。首先,我们可以创建一个简短的单词列表来演示这是如何工作的。这一阶段通常跟随单词的标记化。
word_list = ["flying", "flies", "waiting", "waits", "waited", "ball", "balls", "flyer"]
接下来,我们将从 NLTK 导入 Porter 词干分析器。
from nltk.stem.porter import PorterStemmer
制作一个名为 ps 的 PorterStemmer 类的实例。
ps = PorterStemmer()
最后用一个列表理解列表中的每个单词。其结果可以在下面看到。
stem_words = [ps.stem(word) for word in word_list]
stem_words>>> ['fli', 'fli', 'wait', 'wait', 'wait', 'ball', 'ball', 'flyer']
在本应具有不同词干的单词被词干化为同一个词根的情况下,可能会发生词干过度。也有可能得到下面的词干。这在本质上是相反的(应该词根相同的单词却不是)。有各种不同的词干分析器可以使用,如波特,英语斯特梅尔,派斯和洛文斯仅举几例。波特梗是最广泛使用的一种。
有些词干分析器比其他词干分析器更“苛刻”或更“温和”,因此您可能需要尝试不同的词干分析器来获得想要的结果。您也可以根据输出决定在停用词移除之前或之后应用词干。
另一方面,词条释义是通过识别一个单词相对于它出现的句子的意义来工作的。本质上,上下文对于引理满足很重要。这种情况下的词根叫做引理。例如,单词“better”可以用单词“good”来表示,因为这个单词就是它的来源。这个过程在计算上比词干提取更昂贵。
我们需要首先从 NLTK(一个包含英语名词、形容词、副词和动词的大型单词数据库)下载 wordnet 资源。
nltk.download('wordnet', quiet=True)
我们将导入并创建一个 WordNetLemmatizer 的实例,并将其应用于我们之前使用的单词列表。
word_list>>> ['flying', 'flies', 'waiting', 'waits', 'waited', 'ball', 'balls', 'flyer']from nltk.stem import WordNetLemmatizer
lm = WordNetLemmatizer()lem_words = [lm.lemmatize(word) for word in word_list]
lem_words>>> ['flying', 'fly', 'waiting', 'wait', 'waited', 'ball', 'ball', 'flyer']
如果我们将 lem_words 与 stem_words (如下)进行比较,您可以看到,尽管在某些情况下相似/相同,但对于一些单词,如“flying”和“flies ”,使用引理化保留了其含义,否则词干化将会丢失该含义。
stem_words>>> ['fli', 'fli', 'wait', 'wait', 'wait', 'ball', 'ball', 'flyer']
标准化/缩放
移除特征(单词/术语)的另一种方法是使用代表术语频率的 tf-idf 重新调整数据,逆文档频率。

tf-idf 方程(图片由作者提供)
这用于查看一个术语(单词)对文档集合(语料库)中的单个文档有多重要。我们本质上是用这个作为权重。术语频率是该单词/术语在文档中出现的频率。例如,如果我们有两个文件𝑑1 和𝑑2 看起来像这样。
𝑑1 =“那个小男孩在房子里。”𝑑2 =“那个小男孩不在房子里。”
如果在文档 1 ( 𝑑1)中感兴趣的术语是“男孩”,这在七个单词中出现一次 1/7=0.1428。我们可以对每个文档中的每个术语做同样的事情。一旦我们计算出术语频率,我们就可以用语料库中文档总数的对数乘以包含该术语的文档数。这告诉我们一个特定的术语与一个文档是更相关、更不相关还是同等相关。在上面的示例中,文档二中的单词“not”对于区分这两个文档非常重要。高权重是由于文档中的高术语频率和语料库(文档集合)中的低术语频率。TF-IDF 也可以用于文本摘要任务。
为了在实践中使用 TF-IDF,我们将需要使用我们前面看到的文本文件。为了做得更好,我保存了一个没有停用词和 HTML 段落标签的版本。这也被转换成小写。本质上,这是使用一个循环一个接一个地打开文件,一行一行地读取它们,分割成单词。如果这个词不是停用词,它将被写入一个新文件。最后, BeautifulSoup 库用于从文本数据中去除所有的 HTML 标签。
**from** bs4 **import** BeautifulSoup
file_path **=** "./NLP/text/"
file_list **=** ['20-01', '20-02', '20-03', '20-04']
**for** file **in** file_list:
current_file **=** open(file_path **+** file **+** ".txt")
line **=** current_file.read().lower()
soup **=** BeautifulSoup(line)
words **=** soup.get_text().split()
**for** word **in** words:
**if** word **not** **in** sw:
formated_list **=** open((file_path **+** file **+** '-f.txt'),'a')
formated_list.write(" "**+**word)
formated_list.close()
current_file.close()
我们现在可以加载这些文件并将它们的内容存储在变量中。
path = "./NLP/text/processed/"txt_file_1 = open(path + "20–01-f.txt")
file_1 = txt_file_1.read()txt_file_2 = open(path + "20–02-f.txt")
file_2 = txt_file_2.read()txt_file_3 = open(path + "20–03-f.txt")
file_3 = txt_file_3.read()txt_file_4 = open(path + "20–04-f.txt")
file_4 = txt_file_4.read()
我们可以将从文件中提取的文本数据放在一个列表中,以便于使用。
data_files = [file_1, file_2, file_3, file_4]
接下来,我们将导入 pandas 库,它在数据科学中经常使用,并提供以表格结构(数据框)表示数据的功能。接下来,我们将从 sklearn 机器学习库中导入tfidf 矢量器,它将标记文档并应用 IDF 权重。
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
最后,我们可以创建该类的一个实例,并使其适合数据。我们可以在数据框中显示结果,其中每个要素和相关的 TF-IDF 权重按降序排列。最后,为了简洁起见,我们将只输出前 30 个术语。
tv = TfidfVectorizer(use_idf=True)
tfIdf = tv.fit_transform(data_files)
df = pd.DataFrame(tfIdf[0].T.todense(), index=tv.get_feature_names(), columns=["TF-IDF"])
df = df.sort_values('TF-IDF', ascending=False)
df.head(30)

熊猫数据框的输出-为简洁起见而缩短(图片由作者提供)
词频
我们可以对单词数据做的最简单的事情之一是查看一个独特的单词在文档中出现的频率(和/或它在语料库中的累积频率)。我们可以使用 FreqDist 函数来计算一个字典,它的键/值对包含每个术语(单词),后跟它在文本中出现的次数。例如,单词“government”在我们之前使用的原始简短示例文本中出现了 3 次。
dist = nltk.FreqDist(str_list)
dist>>> FreqDist({'government': 3, 'p': 2, 'ndc': 2, 'capacity': 2, 'last': 1, 'july': 1, 'called': 1, 'energy': 1, 'sector': 1, 'debt': 1, ...})
为了使它更容易可视化,我们可以将它输出为一个图。正如您所看到的,单词 government 出现了 3 次,字母 p(来自 HTML 段落标记)出现了两次,其他单词只出现了一次。
dist.plot();

单词的情节和出现频率(图片由作者提供)
另一种显示单词频率的视觉方式是使用单词云,这里单词越大,出现的次数就越多。为此,我们可以使用 WordCloud 库。
from wordcloud import WordCloud
我们还需要来自用于各种可视化的 matplotlib 库中的绘图( plt )。 %matplotlib inline 设置绘图命令,以确保当与 Jupyter 笔记本等字体端一起使用时,绘图出现在代码单元格下方并存储在笔记本中。
import matplotlib.pyplot as plt
%matplotlib inline
接下来,我们需要将数据转换成 word cloud 函数的正确格式。它接受一个字符串,因此我们将把标记化的字符串列表折叠成一个单独的字符串,单词之间留有空格,使用内置的 join 函数进行字符串连接(将字符串连接在一起)。
flattend_text = " ".join(str_list)
接下来,我们可以使用传入文本字符串的 generate 函数创建单词云。
wc = WordCloud().generate(flattend_text)
最后,我们将使用双线性插值选项输出关闭轴文本的单词云,以平滑图像的外观。
plt.imshow(wc, interpolation='bilinear')
plt.axis("off")
plt.show()

词云输出(图片由作者提供)
您还可以使用其他可选参数。一些流行的方法包括设置最大字体大小(max_font_size)和包含的字数(如果你有很多字的话会很有帮助)以及改变背景颜色。例如,我们可以将显示的最大字数设置为 10,并将背景设置为白色。
wc_2 = WordCloud(max_words = 10, background_color = "white").generate(flattend_text)
plt.imshow(wc_2, interpolation='bilinear')
plt.axis("off")
plt.show()

词云输出(图片由作者提供)
n 元语法分析
当我们把单词符号化,并把它们表示成一个单词包时,我们就失去了一些上下文和意义。单个单词本身并不能说明太多,但是它们与其他单词一起出现的频率可能会说明很多。例如,“信息”和“治理”这两个词可能经常一起出现,并具有特定的含义。我们可以用 n 元语法来解释这一点。这是指一起出现的多个令牌。这些标记可以是单词或字母。这里我们将使用单词。两个词(𝑛=2)被称为双字,三个词被称为三字,等等。使用 n 元语法有助于我们保留文本中的一些含义/上下文。
我们将使用前面相同的短文本:
txt>>> 'the government last july called the energy sector debt situation a state of emergency. <p> this was during the mid-year budget review during which the finance minister ken ofori-atta castigated the previous ndc government for entering into obnoxious take-or-pay contracts signed by the ndc , which obligate us to pay for capacity we do not need . <p> the government pays over gh ? 2.5 billion annually for some 2,300mw in installed capacity which the country does not consume .'
接下来,我们可以从 NLTK 实用程序包中导入 ngrams 函数。
from nltk.util import ngrams
我们将使用与之前相同的标记器再次标记文本。
tk = TreebankWordTokenizer()
tk_words = tk.tokenize(txt)
最后,我们将这个标记化的列表传递到 ngrams 函数中,并指定𝑛(在本例中为二进制数的 2)(为简洁起见而缩写)。
bigrams = list(ngrams(tk_words, 2))
bigrams>>> [('the', 'government'),
('government', 'last'),
('last', 'july'),
('july', 'called'),
('called', 'the'),
('the', 'energy'),
('energy', 'sector'),
('sector', 'debt'),
('debt', 'situation'),
('situation', 'a'),
('a', 'state'),
('state', 'of'),
('of', 'emergency.'),
('emergency.', '<'),
('<', 'p'),
('p', '>'),
('>', 'this'),
('this', 'was'),
('was', 'during'),
('during', 'the'),
('the', 'mid-year'),
('mid-year', 'budget')
...
在这里,我们可以看到像“合同”和“签署”或“政府”和“支付”这样的术语,它们提供了比单个单词更多的上下文。作为预处理的一部分,您也可以从文本数据中过滤出 n 元语法。
我们还可以使用 BigramCollocationFinder 类来确定二元模型出现的次数。这里我们按降序对列表进行排序。
from nltk.collocations import BigramCollocationFinder
finder = BigramCollocationFinder.from_words(tk_words, window_size=2)
ngram = list(finder.ngram_fd.items())
ngram.sort(key=lambda item: item[-1], reverse=True)
ngram>>> [(('the', 'government'), 2),
(('<', 'p'), 2),
(('p', '>'), 2),
(('which', 'the'), 2),
(('government', 'last'), 1),
(('last', 'july'), 1),
(('july', 'called'), 1),
(('called', 'the'), 1),
(('the', 'energy'), 1),
(('energy', 'sector'), 1),
(('sector', 'debt'), 1),
(('debt', 'situation'), 1),
(('situation', 'a'), 1),
(('a', 'state'), 1),
(('state', 'of'), 1),
(('of', 'emergency.'), 1),
(('emergency.', '<'), 1),
(('>', 'this'), 1),
(('this', 'was'), 1),
(('was', 'during'), 1),
(('during', 'the'), 1),
(('the', 'mid-year'), 1),
(('mid-year', 'budget'), 1)
...
情感分析
这包括分析文本以确定文本的“正面”或“负面”程度。这可以给我们关于人们的观点/情绪的信息。这可以应用到一些事情上,比如浏览产品评论,以获得产品是否被看好的总体感觉。我们还可以将它用于研究目的——例如,人们在他们的推文中对戴口罩持肯定还是否定态度。为此,我们可以训练一个模型或使用现有的词典。VADER 是用 Python 实现的。这会产生一个介于-1 和+1 之间的正面、负面和中性情绪得分。它还产生一个复合分数,即阳性+中性标准化 (-1 比 1)。首先,我们将下载词典。词典包含与单个单词或文本串相关的信息(例如,语义或语法)。
nltk.download("vader_lexicon", quiet=True)
我们导入了情感分析器类SentimentIntensityAnalyzer,并创建了一个名为 snt 的实例(用于情感)。
from nltk.sentiment.vader import SentimentIntensityAnalyzer
snt = SentimentIntensityAnalyzer()
然后,我们可以向函数 polarity_scores 传递一些文本数据(例如,我们的第二个文件)。您可以在下面的字典数据结构中看到作为键/值对返回的分数。
snt.polarity_scores(data_files[1])>>> {'neg': 0.101, 'neu': 0.782, 'pos': 0.117, 'compound': 1.0}
在这个例子中,查看第二个文本文件,我们可以看到一个占主导地位的中性情绪得分(0.782),后面是一个正得分(0.117)和一个负得分(0.101)。你可以在不同的时间点比较情绪,看看它是如何变化的,或者在不同的小组之间。有时使用的另一个指标是净情绪得分(NSS),它是通过从积极得分中减去消极得分来计算的。首先,我们需要将分数存储在一个变量中来访问它们。
sent_scores = snt.polarity_scores(data_files[1])
然后我们可以从正数中减去负数。
nss = sent_scores['pos'] — sent_scores['neg']
print("NSS =", nss)>>> NSS = 0.016
主题建模
主题建模通常用于文本挖掘,它允许我们创建一个统计模型来发现文本数据中的主题。有各种不同的方法/算法可以做到这一点。我们将在这里看一对夫妇。这是一种无人监管的方法。我们首先来看看潜在语义分析(LSA),它与主成分分析(PCA)的工作原理相同。LSA 是一个线性模型,并假设文档中的术语呈正态分布。它还使用 SVD(奇异值分解),这在计算上是昂贵的。这种方法减少了数据中的噪声。
注意: SVD 的工作原理是将一个文档术语矩阵分成 3 个连续的方阵(其中一个是对角矩阵),然后将它们转置并再次相乘。这个方法可以用来求矩阵的逆矩阵。
第一阶段涉及创建文档术语矩阵。这在行中表示文档,在列中表示术语,在单元格中表示 TF-IDF 分数。然后,我们将 SVD 应用于这个矩阵,以获得最终的主题列表。

文档-术语矩阵,行中有文档,列中有术语。单元格包含 TF-IDF 分数(图片由作者提供)
我们可以使用之前使用的相同的tfidf 矢量器来计算 TF-IDF 分数。我们将限制术语(特征)的数量,以将所需的计算资源减少到 800。
from sklearn.feature_extraction.text import TfidfVectorizer
v = TfidfVectorizer(stop_words='english', max_features=800, max_df=0.5)
X = v.fit_transform(data_files)
如果我们查看文档-术语矩阵的维度,我们可以看到行中有 4 个文档,列中有 800 个术语。
X.shape>>> (4, 800)
我们现在需要实现 SVD,我们可以使用截断的 SVD 类来实现它。这将为我们做繁重的工作。
from sklearn.decomposition import TruncatedSVD
我们可以用参数 n_components 指定主题的数量。在这种情况下,我们将它设置为 4,假设每个文档有一个不同的主主题(**注意:**我们还可以使用像主题一致性这样的方法来确定主题的最佳数量 k )。
svd = TruncatedSVD(n_components=4)
接下来,我们拟合模型并获得特征名称:
svd.fit(X)doc_terms = v.get_feature_names()
现在我们可以输出与每个主题相关的术语。在这种情况下,4 个主题中的每一个都有前 12 个。
for i, component in enumerate(svd.components_):
terms_comp = zip(doc_terms, component)
sorted_terms = sorted(terms_comp, key=lambda x:x[1], reverse=True)[:12]
print("")
print("Topic "+str(i+1)+": ", end="")
for term in sorted_terms:
print(term[0], " ", end="")>>> Topic 1: rsquo href ldquo rdquo ventilators easter keytruda quebec unincorporated ford books inmates
Topic 2: davos wef sibley denly stamler comox nortje caf pd rsquo href ldquo
Topic 3: hopland geely easyjet davos vanderbilt wef asbestos macy jamaat sibley denly stamler
Topic 4: rsquo href ldquo rdquo quebec div eacute src noopener rel mdash rsv
然后,由您根据这些主题所包含的单词来确定它们可能代表什么(主题标签)。
主题建模的另一个流行选项是潜在狄利克雷分配(LDA ),不要与其他 LDA(线性判别分析)混淆。LDA 假设单词的狄利克雷分布,并创建语义向量空间模型。其实现的具体细节超出了本入门书的范围,但本质上,它将文档术语矩阵转换为两个矩阵。一个表示文档和主题,第二个表示主题和术语。然后,该算法尝试根据主题生成所讨论的单词的概率计算来调整每个文档中每个单词的主题。
我们使用与前面 LSA 相同的概念。首先,我们用计数矢量器将数据标记化。然后,我们再次创建 LDA 类的实例,将主题数量设置为 4,并输出前 12 个。
from sklearn.feature_extraction.text import CountVectorizer
cv = CountVectorizer()
fitted = cv.fit_transform(data_files)
from sklearn.decomposition import LatentDirichletAllocation
lda = LatentDirichletAllocation(n_components=4, random_state=42)
lda.fit(fitted)
然后,我们可以像以前一样输出结果:
doc_terms = cv.get_feature_names()for i, component in enumerate(lda.components_):
terms_comp = zip(doc_terms, component)
sorted_terms = sorted(terms_comp, key=lambda x:x[1], reverse=True)[:12]
print("")
print("Topic "+str(i+1)+": ", end="")
for term in sorted_terms:
print(term[0], " ", end="")>>> Topic 1: said 19 covid people coronavirus new health also would one pandemic time
Topic 2: 021 040 25000 421 4q 712 85th 885 accrues accuser acuity afterthought
Topic 3: said coronavirus people health 19 new covid also cases virus one would
Topic 4: 021 040 25000 421 4q 712 85th 885 accrues accuser acuity afterthought
如果我们认为这些数字不相关,我们可能还想回去过滤掉它们。您可以看到,这与我们之前看到的 LSA 产生了非常不同的结果。首先,LSA 是主题建模的良好开端。如果需要,LDA 提供不同的选项。
摘要
这本初级读本概述了现代 NLP 任务中使用的一些常用方法,以及如何用 Python 实现这些方法。每种方法都有细微差别,需要根据手头的任务来考虑。还有像词性标注这样的方法,也称为语法标注,可以为算法提供额外的信息。例如,你可以在某些单词上标注该单词是名词、动词、形容词还是副词等信息。这通常被表示为具有单词、标签的元组列表,例如[('build ',' v '),(' walk ',' v '),(' mountain ',' n')]。还有许多方法可以表示单词和术语,用于后续处理,例如 word2vec 和单词包等。您选择的格式将再次取决于任务和算法要求。与所有机器学习和数据科学一样,数据预处理所花费的时间通常最长,并且对生成的输出有很大影响。读完这本初级读本后,你应该有希望开始从文本数据中获得一些有趣的见解,并对你可能用来分析这类数据的一些方法有所了解。
参考
[1]戴维斯,马克。(2019-)冠状病毒语料库。可在 https://www.english-corpora.org/corona/的[在线购买。](https://www.english-corpora.org/corona/)
艺术风格的神经算法:总结与实现
原文:https://towardsdatascience.com/a-neural-algorithm-of-artistic-style-summary-and-implementation-9dd8452df653?source=collection_archive---------42-----------------------

瓦茨拉夫·pluhař通过 Unsplash
使用 Pytorch 进行风格转换
神经风格,或神经转移,允许用一种新的艺术风格再现一幅给定的图像。在这里,我介绍由 Leon A. Gatys、Alexander S. Ecker 和 Matthias Bethge 提出的神经式算法。该算法接收样式图像、内容图像和输入图像,输入图像可以是空白的白色图像或内容图像的副本。因此,它改变输入图像,使其类似于后一个图像的内容和前一个图像的风格。在开始之前,我想感谢亚历克西斯·雅克的文章。
原则
虽然这个名字可能会让你认为它确实是将样式转移到另一个图像中,但是这个想法是生成一个内容和样式图像之间距离最小的图像。因此,甚至有可能从一个完全白色的图像开始,并实现期望的结果,这是本文中提出的。关于技术细节,总体想法是使用预先训练的网络,并通过反向传播最小化这些距离。
细节

卷积神经网络(CNN)摘自本文。
如上所述,该算法需要三幅图像,目标是生成一幅内容和样式图像之间距离最小的图像。为了实现这一点,作者使用预训练的 VGG-19 网络,并计算输入图像和目标图像(内容和风格图像)的特征图之间的距离。因此,他们计算了 CNN 特定层面的内容和风格损失。
内容损失

内容损失摘自本文。
作者使用平方误差损失来测量内容图像和输入图像的特征表示之间的距离,分别表示为 P 和 F。
风格丧失
为了计算风格损失,作者使用了 Gram 矩阵。因此,我们通过展平以[N,C,W,H]的形式给出的输入来获取所有 C 个特征向量,导致它具有[N x C,W x H]的形状。最后,我们将这个矩阵与它自身的转置相乘,得到一个 Gram 矩阵,它给出了我们的特征相关性。最后,风格损失由风格和输入 gram 矩阵之间的平方误差损失给出。
全损

总损失摘自本文。
总损失是两个损失的加权和。作者提到,默认比率α/β要么是 1×10−3,要么是 1 × 10−4.
模型和标准化
我们将导入 VGG-19 预训练网络,因此我们还需要通过减去平均值并除以标准偏差来归一化我们的图像。
最后,我们将计算 VGG-19 在特定深度层的损失。此外,作者提到用平均层替换最大池层会产生更平滑的图像。因此,我们需要一个新的顺序模块来包含所有这些。
训练详情
与训练网络不同,我们希望优化输入图像。因此,我们使用 L-BFGS 算法来运行我们的梯度下降,并将我们的图像作为张量传递给它进行优化。比率α/β是 1×10^−6.
结果

上图显示了内容和样式图像以及生成的输入图像。此外,您可以看到我们的输入图像在整个梯度下降过程中是如何变化的。

哈萨克斯坦阿斯塔纳。
最后,我想再展示几张我喜欢的图片:)。

哈萨克斯坦阿拉木图。

俄罗斯莫斯科。
一些遗言
我提出了一个简单而有趣的基于 CNN 的算法。然而,已经有更多的方法以不同的方式完成这项任务,特别是在实时情况下。如果你有兴趣,鼓励你进一步研究这个领域。完整的代码可以在我的 GitHub 上找到。
纸
艺术风格的神经算法
相关文章
https://medium.com/tensorflow/neural-style-transfer-creating-art-with-deep-learning-using-tf-keras-and-eager-execution-7d541ac31398 https://medium.com/artists-and-machine-intelligence/neural-artistic-style-transfer-a-comprehensive-look-f54d8649c199
一种新的反人脸识别系统
原文:https://towardsdatascience.com/a-new-anti-facial-recognition-system-401741015ef6?source=collection_archive---------24-----------------------
LowKey 是由马里兰大学的研究人员开发的一种新的反面部识别系统。了解它是如何工作的。

托拜厄斯·图利乌斯在 Unsplash 上的照片
随着深度学习的改进,面部识别软件变得越来越强大。相应的,面部识别软件的隐私担忧也增加了。许多面部识别系统通过抓取互联网上公开的图片来建立数据库,这意味着你的脸可能在你不知道的情况下存在于某个数据库中。避免这个问题的一个方法是不要把你的脸贴到网上。然而,在社交媒体时代,这可能是不可行的。另一种解决方案是改变图像来欺骗面部识别软件,同时保持图像质量,以便您仍然可以使用该图像。这是马里兰大学的一些研究人员发明的“低调”方法。
LowKey 利用了这样一个事实,即大多数面部识别系统都是使用神经网络构建的,众所周知,神经网络对于对抗性攻击很脆弱。对抗性攻击是对神经网络输入的微小改变,导致网络对输入进行错误分类。理想情况下,用例如下。你对一张自拍进行低调的对抗性攻击,然后上传到互联网上。这张低调的照片是由面部识别数据库拍摄的。稍后,您走到外面,监控摄像头拍下您的照片(称为“探头图像”)。但是,它无法将您的探头图像与数据库中的低调图像进行匹配。你安全了。

来源:低调的论文
详情:
LowKey 的目标是在所有面部识别深度学习系统中表现良好。然而,我们不知道我们试图击败的一些深度学习系统的架构。如果我们训练我们的对抗性攻击来击败我们可以访问的一个特定的面部识别神经网络,我们不能保证这将在现场对抗其他网络。这个问题没有完美的解决方案。
低调的研究人员决定在当前最好的开源面部识别神经网络的集合上训练他们的对抗性攻击,希望模型的集合能够让他们的攻击具有更好的推广性。首先,对于集合中的每个模型,研究人员在输入图像上计算该模型的输出。然后,他们对输入图像应用低调对抗性攻击,并使用低调修改的图像作为输入来计算模型的输出。接下来,他们计算两个输出之间的差异。他们对集合中的每个模型都这样做,然后计算差异的总和。他们的目标是使这个总数最大化。这个和越大,面部识别神经网络就越不可能将真实图像和低调修改的图像分类为相同的。
其次,研究人员希望修改后的图像仍然能够被人类识别。为了实现这一目标,他们决定最小化原始图像和低调图像的 LPIPS 指标。 LPIPS (学习感知图像块相似度)是两幅图像之间基于人类的相似性度量。较低的 LPIPS 意味着较高的相似性。
因此,LowKey 有两个目标:基于开源面部识别模型的集合最大化原始图像和 LowKey 图像之间的距离,以及最小化相同两幅图像之间的 LPIPS。在数学符号中,总目标可以写成:

来源:低调的报纸
澄清:
- x 是原始图像
- “x”是低调的形象
- n 是训练集合中模型的数量
- f_i 是第 I 个系综模型
- a 是图像预处理函数
- g 是高斯平滑函数
请注意,第一个目标有两个版本,一个有高斯平滑函数,另一个没有。研究人员包括了高斯平滑函数版本,因为它改善了结果。利用梯度上升训练总目标,并且最终的 x’作为低调图像输出。
低调的研究人员发布了一个在线网络工具,如果你想自己试试的话。这里可以找到这里。例如,这是它对样本图像所做的操作:

资料来源:Unsplash的 Ali Kazal】
结果和限制:
研究人员通过尝试破解两个商业可用的面部识别 API 来测试 LowKey,即亚马逊 Rekognition 和微软 Azure Face。在这两种 API 上,LowKey 都能够保护用户的面部,因此他们被识别的概率低于 3%。在没有低调保护的情况下,两个面部识别系统识别面部的准确率超过 90%。这是一个巨大的差异。
然而,当与其他可能是机密的面部识别系统进行测试时,LowKey 是否也能工作,还有待观察。此外,面部识别系统绕过低调保护的一种方法是用低调图像作为训练数据的一部分来训练系统。这可能会导致一场军备竞赛,其中像 LowKey 这样的反面部识别算法被发布,面部识别公司通过训练考虑到该算法的新模型来做出反应,导致新算法被发布,等等。换句话说,低调有一天可能不再有效。
然而,不管这些疑虑,LowKey 是在互联网和机器学习时代迈向隐私的重要一步。LowKey 证明了一个直观简单的对抗性攻击可以欺骗当前的图像识别系统,同时保持图像质量。更多详情,请参考原文此处。
电影制作的新方法
原文:https://towardsdatascience.com/a-new-approach-to-film-making-80cec94284f0?source=collection_archive---------17-----------------------
对电影统计数据的探索性数据分析显示,一种新的趋势已经掌控了这个行业,并已经为一些关键角色创造了巨额利润。

由丹尼斯·简斯在 Unsplash 上拍摄的照片
自 19 世纪诞生以来,电影业已经取得了长足的发展,不仅成为我们日常生活中的主要娱乐来源,也成为我们现代社会的核心文化支柱。随着新技术的发展,这种增长已经达到了全球水平,电影制作人现在能够接触到世界各地的观众。
强调一些关键数字:2019 年全球票房价值 422 亿美元(其次是 2020 年因新冠肺炎疫情而受到重创)。仅在美国,自 2000 年以来每年制作的电影数量就增长了 4 倍,从 200 部增长到 2019 年的 800 部。
当然,衡量这个行业的标准不再仅仅包括票房数字,自 20 世纪 90 年代以来,电视连续剧在我们的日常娱乐中占据了更加突出的位置,特别是随着网飞或 Prime Video 等流媒体平台的出现。今天,随着大多数人拥有至少一个流媒体服务订阅,我们发现自己处于“流媒体战争”的新时代。目前,流媒体方式的主要传播者网飞(净资产:400 亿美元)以 2.0764 亿用户保持着领先地位,其中大部分用户位于美国和加拿大。紧随其后的是 Prime Video,亚马逊拥有 2 亿 Prime 服务用户。
显然,今天这种媒体的力量及其接触世界各地受众的能力怎么强调都不为过。然而,虽然电影的主要目的是娱乐,但重要的是要注意到它们的额外作用,既作为社会、社会规范和价值观的反映,有时也作为其影响者。
电影已经成为我们文化和历史的重要组成部分。因此,它们也可以被看作是我们过去的记录——它们清楚地反映了当时的社会状况。在他们各自的情节中,他们描绘了当时社会所持有的当代价值观、趋势、问题和信仰。
然而,社会是可塑的。它随着时间的推移而发展和变化。因此,在过去 100 年的每十年里,我们都会看到反映社会意识形态和规范变化的主流电影。关于这种变化的例子,只要看看《007:邦德:T1》系列电影就知道了。我们只需要考虑一下 007 的反派角色的演变,就可以把他们和当时的政治形势联系起来。
今天,电影业出现了一种新趋势,反映了当前的社会变化。这一趋势就是多元化,忽视这一趋势可能会让电影制作人损失数百万未开发的收入。
为了理解这一新趋势,我采用了数据驱动的方法来探索电影制作行业与多元化相关的关键方面。
I .电影业的地理多样性
正如我们所知,作为电影业发展的发源地,好莱坞长期以来一直主导着全球舞台。因此,过去几十年主要见证了美国文化的各种状态主导了屏幕,明显反映了美国在二战后崛起为超级大国,在苏联解体后的 20 世纪 90 年代达到了影响力的顶峰。
然而,自 21 世纪以来,国际舞台上出现了一种新的范式,表明随着世界走向以更大的多边主义为特征的新世界秩序,美国在全球政治层面的影响力正在减弱。因此,本分析探讨的多样性的一个方面是电影制作中地理多样性的演变。电影业是否反映了这一政治趋势?
这就是我们在观察前 20 个国家的票房数字时所看到的情况,这些数字是根据其电影产业的利润规模来衡量的。

撇开 2020 年与大流行相关的崩溃不谈,有两点立即凸显出来:
(1)美国电影业与世界其他地区之间不可思议的差距(不出所料)。
(2)中国电影业利润的指数级增长,正在迅速赶上美国。
放大其余国家,我们看到以下内容:

总体上有积极的增长趋势。因此,在探索日益增加的地理多样性时,更恰当的比较是比较这些国家自 2000 年以来的增长率,如下所示:

有趣的是,美国在过去 20 年的年增长率中排名倒数第三,新电影增长率约为 4%,平均增长率约为 2.5%,相比之下,排名前十的国家虽然拥有明显较小的产业,但年票房利润都至少增长了 10%。
因此,电影业增长最快的市场都是国际性的,其中中国、印度和巴西占主导地位,年平均增长率超过 20%。因此,随着国际观众对更能反映其文化和社会的原创内容的需求迅速增长,这些市场可能为电影制作人提供一个在竞争对手中脱颖而出的有趣机会。
当然,随着疫情对已经占主导地位的流媒体行业的推动,地理多样性应该成为主要参与者中更重要的考虑因素,因为就提供这些服务的服务提供商数量而言,美国以外的市场竞争明显较弱,如下图所示。

网飞已经在利用地理多样性的机遇,开发当地产业,制作越来越多反映当地文化和语言的新内容,包括热门歌曲和一些我最喜欢的:鲁邦(法)、 Dix Pour Cent/Call My Agent!(法兰西) Casa de Papel/Money Heist (西班牙) Fauda (以色列)。
二。电影业中的选角多样性
回顾美国电影,过去几年发表了许多文章,批评好莱坞在选角选择上的最后一个多样性,一些运动开始出现,如 2015 年的#OscarsSoWhite 和 2016 年的# whitewashedOUT,以及非洲裔美国人、拉丁裔、亚裔、LGBTQ 和其他社区的多个多样性代表协会为他们缺乏代表性而大声疾呼。
人们已经在采取措施打造更平衡、更具代表性的演员阵容,像《黑豹》和《疯狂富裕的亚洲人》这样的电影经常被认为是朝着正确方向迈出的指示性步骤。
因此,这项分析探讨了自 2010 年以来在这方面发生的变化,通过检查过去十年中 100 位票房收入最高的演员的“明星得分”,这是一项根据他们出演的票房收入最高的电影数量分配给每个演员的统计数据。

到 2020 年,非洲裔美国演员的平均明星分数上升了 72%,美国土著/阿拉斯加土著演员上升了 36.7%,亚洲演员上升了 21.5%,夏威夷土著/太平洋岛民演员从不存在上升到 377.5。
此外,当比较 2010 年和 2020 年票房前三的演员时,我们看到 2010 年的阵容是:小罗伯特·唐尼、泰勒·洛特纳和希亚·拉博夫,2020 年的是:塞缪尔·L·杰克逊、道恩·强森和丹娜·古瑞拉。
然而,虽然已经取得了重要进展,但仍需要取得更多进展,以建立一个更具包容性和代表性的电影业,不因肤色或其他因素而有所歧视。事实上,仍然有迹象表明,虽然电影业已经开始挑选更多不同肤色的演员,但这些演员仍然倾向于出演次要和不太重要的角色。
在表演艺术中,衡量一部电影中一个角色重要性的标准是计费数。根据维基百科的定义,计费是一个术语,指的是戏剧、电影、电视等演职员表的顺序和其他方面。相应地,角色越重要,计费号越低。然而,这一分析表明,在过去的 10 年里,有色人种演员,特别是非裔美国人、亚裔和美洲土著/阿拉斯加土著演员的平均收入,详见下表。

虽然这清楚地表明,在社会层面上还有更大的改进空间,但发生的巨大变化清楚地表明了新的多元化趋势的本质,这种趋势既抓住了社会,也反映了整个电影业。
电影制作人应该欣然接受这一趋势,尤其是考虑到这样做不仅有利于社会进步,而且从这类电影产生的收入来看,不仅有利可图,还可能使他们的电影获得重要的文化地位。
三。接受和好评
当然,当讨论电影业的新趋势时,必须探讨的一个方面是接受和好评。因此,除了不可避免地提到奥斯卡奖(被广泛认为是业内最重要和最负盛名的奖项)之外,必须给予电影评论家应有的重视,这些独立的声音对电影和整个行业的艺术形式有着深刻的了解。
去年,奉俊昊的《T2 寄生虫》成为奥斯卡 92 年历史上第一部赢得奥斯卡最佳影片奖的外语片,成为头条新闻。除此之外,奉还获得了最佳导演奖,虽然与历史性的爆冷相比没有那么轰动,但仍然意义重大,特别是在奖项变得更具包容性方面,因为他成为继李安之后第二位获得该奖的亚洲人,李安于 2005 年凭借《T4》中的《卧虎藏龙》获得该奖,并于 2012 年凭借《少年派的奇幻漂流》获得该奖。
奥斯卡奖是由美国委员会投票决定的,有一个专门的最佳国际电影类别,现实是,在过去 20 年里,越来越多的非美国电影被提名为最佳影片的主要类别。随着寄生虫终于打破了历史记录,我们肯定会在下一个十年看到更多的选择。
由于它与电影评论家有关,这项分析仅限于比较 IMBd 的数据集有史以来 1000 部最伟大的电影中的美国与非美国电影,结果显示,虽然美国拥有来自单个国家的最多电影(考虑到其在该行业的主导地位,这并不令人惊讶),但总体而言,来自非美国国家的电影数量更多,排名靠前的国家是法国、英国、日本和意大利。
结论
电影制作行业在 2010 年代经历了一个变革的十年,尤其是对更大多样性的呼吁。随着电影成为社会意识状态的代表,人们对努力创造一个更具包容性和多元化的行业所达到的里程碑的印象深刻的接受,突显了更广泛的社会对更大多样性的偏好。通过利用这种趋势和响应这种胃口,电影制作人一定会增加他们的利润和他们作品的文化意义。
正如这一分析所表明的,通过采取更大的行动来实现更多的包容性,并在电影中捕捉这一趋势,电影制作人可以在地理上与竞争对手区分开来,增加他们的电影在全球的文化意义,并通过挖掘未被充分代表的观众对更大代表性和包容性的渴望来创造更多利润。
当然,电影作为一种艺术形式,并不是简单的代表。通过这个行业不可思议的力量和影响,特别是由于新技术的发展,他们也成为有影响力的人,因此,可以用来改变看法和挑战他们的观众对任何问题的看法。因此,通过捕捉这一趋势,并利用清晰和明显的努力将多样性问题融入电影制作,电影可以发挥温和影响社会规范的作用,减少仇恨和歧视,增加接受和包容。
在 Github 上查看完整的分析和数据来源!
AWS 中 ETL 的新竞争者?
原文:https://towardsdatascience.com/a-new-contender-for-etl-in-aws-ec6a3297034d?source=collection_archive---------38-----------------------
运行大规模的 ETL 工作,而没有一大群开发人员在背后支持你

由 Unsplash 上的 Pietro Jeng 拍摄
ETL——或提取、转换、加载——是处理传入数据的常见模式。通过将“转换”集中到一个单独的批量操作中,它允许有效地使用资源,这通常比它的流处理对应物更容易开发和维护。它还非常适合对数据集进行一次性调查,用户可以编写一些自定义代码来对数据集执行一些分析,导出一些结果供以后使用。这种常见的模式是许多数据科学探索的基础,但根据我的经验,我经常发现实现它既笨拙又低效。在本文中,我将概述一项新技术,我认为它可能是数据科学家(和开发人员)武库中的一个有价值的工具。
首先介绍一下我的背景。我是一名软件开发人员,专攻 AWS 数据科学基础设施,拥有软件工程硕士学位。我愿意认为这使我在编写和部署远程运行的代码时不会无精打采,但我发现运行大规模的 ML/数据作业充其量也是具有挑战性的。这一领域的大多数大型技术,例如 Spark,都非常复杂,需要开发团队来维护基础设施,这使得即使是中型公司也完全无法实现。
让我们探索一些不需要开发人员维护的单用户解决方案,重点关注以下评估点:
- 迭代开发的部署速度
- 费用
- 基础设施要求
- 易于与软件开发实践集成(代码林挺、版本控制、构建系统)
其中一项技术是 AWS Glue ETL Jobs ,该技术旨在通过隐藏底层基础设施来简化转换功能的运行,用户只需提供代码库。虽然 Glue 一旦配置好就能很好地工作,但即使是最有经验的开发人员也会感到害怕和沮丧。它不直观的用户界面和糟糕的文档使它很难学习,甚至更难调试,我发现 Spark(Glue ETL 的底层技术)的重要知识是有效使用的必要条件。

图 AWS Glue 的一个错误示例,几乎没有给出任何线索!
这并不全是坏事,一旦你掌握了胶水,它会变得非常强大。DynamicFrame 库(它包装了 spark 数据帧)非常适合读写数据到胶合表,只需一行代码(如果您坚持符合 PEP-8,还需要几行代码……)就可以将几乎无限量的数据写到分区表中——这仍然让我感到困惑!如果您有可以使用 DynamicFrame 导入的大规模数据集,这使得 Glue 成为一个很好的工具,但对于其他任何东西来说效率都很低。
举个简单的例子,作为一种常见的模式,我花了大量的时间来创建 ETL 作业,以便从存储在 S3 的原始数据生成新的数据集——然后将转换后的数据存储回 S3,然后执行分析。听起来很简单,对吗?
假设我在本地机器上有我的代码,我想创建一个粘合作业来运行这个代码,我必须:
- 通过 AWS CLI 将我的脚本上传到 S3(希望第一次能成功……)
- 转到 AWS 控制台
- 转到粘附页面
- 创建新工作
- 为作业配置 IAM 角色,以使用相关权限运行
- 输入你的剧本在 S3 的位置
- 如果需要,设置 ENI 以确保跨 VPC 的数据访问
- 包括任何所需库的 zip 依赖项—(尽管没有 C 扩展,所以祝您使用 pandas 好运!)
- 添加计划
- 运行作业
这甚至不涉及如何开发脚本,我的意思是只需看看将开发端点附加到 Pycharm 的说明!(https://docs . AWS . Amazon . com/glue/latest/DG/dev-endpoint-tutorial-py charm . html)
这并没有将 Glue 设置为日常数据科学/机器学习探索的好工具。简而言之,当根据上面定义的规范进行评估时,Glue ETL 是:
- 由于缺乏良好的本地测试,很难快速迭代新的脚本版本
- 由于火花记录,很难有效地调试
- 由于远程代码编辑和笨拙的部署,与软件工程过程集成具有挑战性
- 易于集成到 S3 和胶水表
那么还有什么其他选择呢?让我们介绍一下我们的竞争者。元流!
Metaflow 是一个相当新的工具,将于 2019 年底推出。它由网飞设计和制造,是一个开源工具,将权力还给数据科学家,降低复杂性,提高迭代速度。它包含一个 Python/R 客户端库,用于编排用户的构建和一组需要用户部署的 AWS 资源(以 Cloudformation 堆栈的形式)。所以,玩笑开够了——让我们探索一下为什么我现在在 Python ETL 工作中使用 Metaflow。
在 Metaflow 上开发新代码轻而易举
Metaflow 添加了一些新的注释来提供其功能,但编排的基础使用了 python、类和方法的既定特性(作为一名“受过经典训练”的软件工程师,这让我感到非常高兴)。流程是一个类,流程中的步骤是函数,每个步骤都链接到下一个要执行的步骤。然后,可以对流程或步骤应用注释,以添加进一步的配置。
# An example of a Metaflow Flow running locally
class TestFlow(FlowSpec): @step
def start(self):
print(“This is the start step!”)
self.next(self.process) # Runs the process step next @step
def process(self, inputs):
print(“This is the process step!”)
self.next(self.end) # Then the end step @step
def end(self):
print(“This is the end step!”)if __name__ == ‘__main__’:
TestFlow() # This initialises the Flow then runs the start step
我想我还没有找到像 Metaflow 这样无缝的工具来切换代码的远程部署。只要对我的步骤做一个注释,我就可以从在笔记本电脑上运行我的流变成在 EC2 上运行 64 核的庞然大物,就这么简单。
# Same Flow as before, but will run on the Cloud!
class TestFlow(FlowSpec): @batch(cpu=64, memory=2000) # Each step get's these resources
@step
def start(self):
print(“This is the start step!”)
self.next(self.process) @batch(cpu=64, memory=2000)
@step
def process(self, inputs):
print(“This is the process step!”)
self.next(self.end) @batch(cpu=64, memory=2000)
@step
def end(self):
print(“This is the end step!”)if __name__ == ‘__main__’:
TestFlow()
元流易于管理
因此,如果你不熟悉 AWS,请耐心听我说,这可能有点难以接受。Metaflow 提供了一个 cloudformation 堆栈来部署其基础设施。这是最精简的基础设施,提供了使用平台所需的所有部件。这种单一的堆栈易于部署和使用,每月维护成本仅为 40 美元左右。然而,这是 Metaflow 最大的缺点,它需要一些关于 AWS 的知识来大规模维护,但是打开和拆除单个堆栈是微不足道的,也是我最希望能够做到的事情。
数据可以直接存入元流
Metaflow 的另一个重要特性是它的元数据存储,允许流中的不同步骤共享数据,并在执行完成后将数据保存到 S3 中。在我之前创建 ETL 管道的例子中,我不需要自己将数据存储到 S3 中,因为 Metaflow 会为我做这件事。因此,当我回来执行我的分析时,我可以获得我的流的最新版本并提取数据集。这使得 Metaflow 对于临时和计划的数据“汇总”都非常强大,而不必管理复杂的数据库。
# A portion of a Flow showing the metadata storage and retrieval
@step
def start(self):
print(“This is the start step!”)
self.message = “Metaflow metadata is cool!” # Saved to S3
self.next(self.process)@step
def process(self, inputs): # Loads message from S3 and into self.
print(f”Let’s print the previous steps message {self.message}”)
self.next(self.end)
除去基础设施成本,在 Metaflow 上运行作业是很便宜的
由于 Metaflow 在幕后使用 Batch,您可以将其配置为使用现货定价。这使得实例成本实际上可以忽略不计,并且由于 Metaflow 可以自动处理重试,因此 SPOT 实例离线的风险很小。在这种情况下,我运行一个 64 核流不到一小时,计算成本为 1.10 美元,这与 Glue 的 16DPU 工作成本形成了鲜明的对比,后者大约为一小时 7 美元。

图 2:运行一个 64 核任务的现货价格快照。
元流流可以轻松调度
虽然 Metaflow 非常适合开发工作流,但是它如何管理生产版本呢?不出所料,太好了。将 @schedule 注释添加到您的流类将允许它的一个表示被推送到 Step 函数,在那里它可以被任何 AWS 事件桥调度/规则触发。这允许许多可能性。想在文件写入 S3 时触发它吗?很简单,只需将步骤函数启动事件附加到规则上,就可以了。
# Will run every hour
@schedule(hourly=True)
class TestFlow(FlowSpec): @step
def start(self):
print(“This is the start step!”)
self.next(self.process) @step
def process(self, inputs):
print(“This is the process step!”)
self.next(self.end) @step
def end(self):
print(“This is the end step!”)if __name__ == ‘__main__’:
TestFlow()
总之,对于我和我的工作流来说,Metaflow 已经被证明是一个强大的工具。它有一些缺点,例如必须管理基础设施,但它丰富的功能(其中许多我还没有谈到)使它成为那些负担不起大规模数据平台的人的优秀工具。在以后的博客文章中,我将探索减轻这些缺点的方法,并更深入地利用 Metaflow 的特性。
物理教育研究的新数据集
原文:https://towardsdatascience.com/a-new-data-set-for-physics-education-research-25631745919?source=collection_archive---------21-----------------------
70,000 份学生对实验物理态度的调查数据集
这篇文章描述了来自 70,000 份科罗拉多实验物理科学学习态度调查(E-CLASS)的免费使用数据集。你可以在这里找到这个数据集:https://github.com/Lewandowski-Labs-PER/eclass-public

照片由 Tra Nguyen 在 Unsplash 上拍摄
整个社会科学领域都存在复制危机。许多研究在重新评估时不能产生相同的结果(例如,在 PER 中,所学课程的证明,而不是之前在中所证明的分数,最能预测学生是否继续攻读物理学位课程)。在某些情况下,如果数据可以免费获得,不同机构的研究可以进行比较,看看结果是否可以重复。数据共享还鼓励数据的长期保存,这保持了数据的完整性,并可以作为未来科学家的培训工具。自由开放的数据也鼓励围绕特定研究问题的对话。可以用不同的方法重新分析结果,以进一步确定结果。在物理教育研究领域,基本上没有可供研究的大型、免费和公开的数据集。
我们使用科罗拉多实验物理科学学习态度调查(E-CLASS)创建了一个大型(70,000 人响应)数据集。这些数据涵盖了 133 所大学,599 门独特的课程和 204 名教师,是在 2016 年至 2019 年期间收集的。该调查评估了一名物理课学生对用实验室技能解决物理问题的态度。在本帖中,我们将介绍数据集和与数据集交互的 python 库。我们鼓励您下载数据集并自己使用它!
E 级数据集
E-CLASS 旨在帮助教师和 PER 研究人员衡量不同实验室课程实施和干预的影响。它是为了解决各种各样的学习目标而开发的,这些学习目标可以粗略地归类为探索学生的认识论和对实验物理的期望。为了能够处理如此大范围的目标,该调查不是为了衡量一个或几个潜在因素而设计的。此外,该调查旨在衡量学生从入门课程到更高级课程的思路进展。为了达到这一点,许多问题是针对入门或高级水平。因此,我们强调,虽然可以考虑“总体”E 级分数,但评估的真正力量来自于检查对个别问题的回答,特别是那些与特定课程的学习目标相一致的问题。
E-CLASS 数据集包含 39505 个调查前响应和 31093 个调查后响应。在某些情况下,学生可以不止一次地回答调查。因此,共有 35380 个对预调查的独特回应和 28282 个对后调查的独特回应。在这种情况下,“独特”被定义为调查前或调查后的第一个回答。该数据集代表了 133 所独特的大学、204 名独特的教师和 599 门独特的课程。该数据集包含入门课程和“一年级以上”课程(BFY)学生的数据。如下图所示,在数据收集期间,每学期收集的数据总量有所增加。

自 2016 年开始自动在线管理以来,学生对 E-CLASS 的累计响应数量。与 BFY 实验室相比,从介绍性课程中收集的学生反馈更多,因为这些课程往往有更多的注册人数。此外,一般来说,更多的学生对前调查作出反应,而不是后调查,这说明了不同的两条线之间的每个实验水平。目前,数据集中总共有 70598 个响应。图片作者。
电子课堂本身由 30 个李克特式问题组成,用来评估学生的知识和对专家的期望。学生被要求从他们的观点和预测实验物理学家的观点对每一个陈述做出回应(从非常同意到非常不同意)。在某些情况下,专家式的回答是不同意。数据已经被预处理以转换 Likert 响应,使得所有数据都在非专家(在数据集中用 1 表示)到专家样(在数据集中用 5 表示)的五点标度上。到目前为止,所有的研究都是通过首先将五分尺度折叠为三分尺度来完成的,但全部范围都包含在公共数据集中。我们警告研究人员,该调查的设计不能可靠地区分量表两端的两个最外层点(即“同意”和“非常同意”或“不同意”和“非常不同意”)。此外,仅在课后调查中,学生被问及哪些项目(30 个项目中的 23 个)对于在课程中获得好成绩是重要的。最后,学生们还被问了一系列关于人口统计、兴趣和职业规划的问题。
DataHelper Python 库
除了数据集本身,我们还编写了一个库来帮助研究人员访问数据。虽然原始数据在几个表中都是 CSV 格式的,但用户通常希望以某种方式缩减数据集,例如只缩减参加入门课程的学生,或者只缩减对前后调查都有反应的学生。下面我们展示一些如何做到这一点的代码示例。
DataHelper 库需要 pandas,并使用 pandas 范式来组织数据。
要导入数据集,我们只需使用以下 cod
**import** DataHelper
e **=** DataHelper**.**eclass_data()
这段代码导入库,然后在e对象中创建完整的数据集。这个e对象可以用来访问底层数据。例如,如果我们想打印回应的总数,我们可以使用函数e.get_buffy_pre()和e.get_intro_pre()。
print('total number of pre responses:',e**.**get_buffy_pre()**.**shape[0]**+** **+** e**.**get_intro_pre()**.**shape[0])>>> total number of pre responses: 39505
这些函数分别返回只包含 BFY 数据和介绍数据的pandas数据帧。因此,返回 dataframe 的shape会给出行数。
如果我们只想获得匹配的数据,我们可以执行类似的操作:
print('Number of matched responses intro:', e**.**get_intro_matched()**.**shape)
print('Number of matched responses bfy:', e**.**get_buffy_matched()**.**shape)>>> Number of matched responses intro: (19445, 175)
>>> Number of matched responses bfy: (3096, 175)
其中函数e.get_intro_matched()为我们执行匹配操作。
github 资源库中有许多示例笔记本。
你可以在这里找到数据集和 DataHelper 库https://github.com/Lewandowski-Labs-PER/eclass-public
本帖汇总论文https://journals . APS . org/prper/abstract/10.1103/physrevphyseducres . 17.020144
分析工作流管理的新观点
原文:https://towardsdatascience.com/a-new-take-on-analytical-workflow-management-e14b8588cdfe?source=collection_archive---------31-----------------------
数据分析/项目管理/教育
由分析专家为分析专家制定的工作流程

来源
作为一名新的分析专家,我所面临的最困难的问题之一是管理和优先化我的项目的能力。我在公司做的大部分工作都是独自完成的,因为我没有一个适合我的分析团队。可以想象,项目堆积起来,你必须找到管理这些项目的方法,同时还要完成实际的开发/分析工作。
我研究了许多不同的项目管理和工作流方法,但是我面对的最大问题是任何大的项目管理/工作流方法(例如敏捷、Scrum 等)。)是因为他们是面向 5 人以上的团队,以提高效率。尽管如此,我花了一些时间修补不同的方法来创建我自己对 PM/工作流方法的看法,并结合来自不同方法的概念,使其适合一个分析师。我觉得这种方法最适合我,但不一定最适合你,所以你必须通过自己的经历找到最适合你的方法。无论您是单独的分析师,还是在团队中工作并需要帮助跟踪您自己的项目和任务,此工作流都是您开始工作的好地方。让我们上车吧!
免责声明:我是一个相对较新的分析专家。这并不是要告诉你你到底需要知道什么,而是从我的经历中给你一些实用的建议。更多信息请查看 走向数据科学 。如果你目前在跟踪你的项目和试图找到更有效率的方法上有困难,请继续阅读!
工作流程概述
我对分析 PM/工作流方法学的理解来自几个不同的方法学,即看板、功能驱动开发(FDD) 和软件开发生命周期(SDLC) :
- 看板: 看板对于展示生产的流程非常有用。如果你曾经走过软件开发团队,看到所有这些带有专栏和便签的大白板,那就是看板。它对于查看生产中可能出现瓶颈的地方也非常有用,这很好,因为您可以看到您需要关注的地方。我为这个工作流程创建了一个概念模板,你可以在这里找到。
- 特征驱动开发(FDD): 特征驱动开发是敏捷中的一门学科。它的重点是围绕系统创建功能。我发现这种方法很有用,因为我通常会有人来找我,因为他们需要在现有流程中添加一些东西(比如测量一个新的指标)或修复一些东西(Tableau 中的图表显示不正确)。这两个任务都涉及过程的一个“特征”,而不是整个过程。
- 软件开发生命周期(SDLC): 这是我自己采用的主要方法,因为我认为它是任何工作流或 PM 方法中最自然的流程。虽然我不是软件开发人员,但我已经调整了方法以更好地适应分析工作。
话虽如此,以下是我对分析工作流方法的概述:
- 要求
- 设计
- 发展
- 测试
- 质量保证/部署
- 维护
我还提到了该工作流中的几个不同的“角色”,如下所述:
- 客户: 请求项目的个人或团队。这并不一定意味着他们将是唯一使用您的解决方案的人,但他们通常是拥有领域知识并能在问答过程中提供帮助的人。我也称他们为“客户”,因为我的工作流程是以我为之服务的人或团队为中心的,类似于顾问-客户关系。
- 利益相关者: 支持本项目开发的任何人(即数据库架构师)或者将利用您的解决方案满足其数据需求的任何人(即客户团队)。
让我们浏览一下每个阶段,以便更好地了解每个阶段的功能!
1)要求
在你开始一个项目之前,你需要知道这个项目的需求是什么。这包括以下内容:
- 最终产品是什么?
- 需要使用哪些数据?
- 不同交付的截止日期是什么?
- 什么利益相关者对这个项目的发展至关重要?
如你所见,这是你计划项目的时候。这也是流程中最重要的阶段,因为没有什么比构建一个流程或模型,却发现最终用户实际上需要的东西与您构建的不同更糟糕的了。
注: 无论“客户”是谁,我都尽量在每个阶段完成后给他们一个更新。这有助于避免出现上述情况,即沟通出现中断,并且构建了不需要构建的东西。
2)设计
在我有了项目的所有需求之后,我开始设计解决方案。这可能是一个 Tableau 仪表板,一个新的 ETL 过程,市场研究分析,等等。在这种方法中,设计是关于绘制和构建解决方案的基本结构或框架。如果这是一个 Tableau 仪表板,我将在一些纸上勾画出每张纸需要放在仪表板上的什么位置,以及它将向最终用户传递什么信息。如果这是一个 ETL 项目,我会绘制一个基本流程图(或者在 Alteryx 中构建基本流程)。这有助于将需求保持在方法的最前沿,这样您就可以被“客户”的要求所约束。这也是您可以在开始开发解决方案之前发现客户可能想知道的问题的时候。
3)发展
开发是任何开发 PM/工作流方法的核心,在这里也是如此。在这个阶段,您将从之前的阶段中取出您的设计,并开始有条不紊地完成每个“功能”(例如,在 Alteryx 公式工具中编写情感分析算法)。在这个过程中,我从 FDD 中提取并按特性构建的原因是因为它有助于将项目分解成可管理的块。如果你是一个单独的分析师或在一个小团队中工作,这很好,因为你可能同时有许多活动的项目在进行,所以这给了你可衡量的可交付成果,如果客户要求更新,你可以与他们交流。“哦,我能够在你的广告仪表板上完成情感计算”比“哦,是的,我正在做你的项目,应该很快就能完成”要好。这种方法是关于仆人领导和客户服务的。在一天结束的时候,你希望你的分析工作能让某人的生活变得更好。根据我的经验,这个过程实现了这一点,同时也使得项目对于单独的分析师或小团队来说更易于管理。
“这种方法完全是关于仆人领导和客户服务的。在一天结束的时候,你希望你的分析工作能让某人的生活变得更好。以我的经验来看,这个过程实现了这一点,同时也使项目对于单独的分析师或小团队来说更易于管理。”
4)测试
那么为什么“测试”和“问/答”是在各自的阶段呢?在这种方法中,测试完全是关于单独的分析师做他们自己的技术问答工作。这是您看到解决方案中缺陷的地方,并且可以在解决方案到达客户端进行 Q/A 之前修复它们。例如,如果我在 Alteryx 中构建 ETL 过程,我可能希望看到该过程如何处理不同的日期数据类型,或者手动计算我的生产数据行,以确保我在管道中创建的所有计算都输出正确的数据。在测试时,我也会尝试单独测试解决方案的所有特性。例如,如果我在一个 Tableau 仪表板上工作,我会测试我可能有的所有不同的过滤器以及任何集合,并选择一些选项以确保一切正常工作。
5)问答和部署
与测试阶段相比,问答更多的是关于数据质量和最终用户输出。我通常会创建一个样本报告或加载少量数据,并将其发送给任何重要的利益相关者以及客户。客户端将能够从最终用户的角度告诉您是否有些事情看起来不对劲,或者数据是否看起来不对。这是一个非常好的实践,可以让您在解决方案投入生产之前对其充满信心。
说到生产,“部署”是让解决方案为生产做好准备的子阶段。这可能意味着自动化一些数据输入功能,这些功能可能是您在开发过程中手动完成的,例如提取 2021 年全年的数据,而不是根据当天提取上周的数据,或者改变仪表板上的颜色,使其更加美观。
6)维护
这个阶段通常发生在其余阶段之后,以及解决方案投入生产一段时间之后。客户端需求是动态的,可能会在解决方案部署一个月后发生变化。这个阶段是为了对你的解决方案进行小的改变和调整,这不会花太多时间。我通常会在项目启动后的两周内将项目留在维护阶段。之后,我会认为该项目已经完成。
注意: 你构建的大多数解决方案在生产过程中可能需要润色,所以尽管你构建的所有东西在技术上可能都需要维护,我通常会将项目留在实际维护阶段 2 周,因为那些是最容易出现错误的解决方案,可能会优先处理。
结论
虽然这是我个人的工作流程,但请记住,每个人都有自己的偏好来提高自己的工作效率。我发现更严格的流程有助于我跟踪我的项目和任务,然而,我知道许多成功的分析专家更喜欢更灵活的工作流程。我希望你会发现这种方法很有用,并从中构建自己的工作流!请继续关注可能的第 2 部分,包括项目示例…
看看我的其他文章吧!
三种分析工具和技巧你现在就可以开始学习
如何演讲:面向有抱负的分析师
数据可视化受众和场景
面向有志分析师的三大技术平台
</10-tips-for-a-successful-internship-e8f0c14cd3d3>成功实习的 10 个秘诀
我作为营销分析实习生学到的东西
营销分析实习生的一天
联系我或接收更多内容,在 Twitter 上关注我@BMNAnalytics!
思考不确定时代建模的新方法
原文:https://towardsdatascience.com/a-new-way-to-think-about-modeling-for-uncertain-times-34d5dafb4a63?source=collection_archive---------40-----------------------
不确定时代的建模:方法、行为和结果

由维克多·福加斯在 Unsplash 上拍摄的照片
疫情或新冠肺炎的传播——首先在中国和南韩,然后在欧洲和美国——非常迅速,让大多数政府、公司和公民措手不及。这场全球健康危机在几周内发展成为经济危机和供应链危机。2020 年 3 月初,全球确诊病例不到 10 万例,截至 1 月 28 日,已激增至 1.01 亿多例,死亡人数超过 210 万。
这个星球上几乎每个人生活的方方面面都受到了新冠肺炎的影响。从直接影响(如死亡、住院、感染)到间接影响(如失业、在家工作、精神健康),病毒几乎影响了这个星球上的每个人。不确定性触及了新冠肺炎统治下生活的方方面面——从健康、行为到经济影响。不确定性往往会助长恐惧、愤怒和沮丧等情绪反应,这种情绪驱动的行为[Firth-Butterfield-etal-2020]往往优先于理性的决定和行动。
除了不确定性之外,个人、公司、决策者和政府都不得不在很少或没有经验、很少历史数据的情况下,在很短的时间内做出决定。高级分析和人工智能模型已被广泛用于帮助解决这些不确定性[Rao-etal-2020]。模型是一种正式的数学表示,可以应用于或校准以适应数据,已被广泛使用。在人类历史上,也许没有任何数据模型比新冠肺炎的感染和死亡曲线更容易辨认。几乎每个人,从印度的农民到美国疾病控制和预防中心(CDC)的主任,都对它们很熟悉。但是这些模型也因其预测的不一致性而招致批评。
那么,模型想要捕捉什么呢?他们能帮助我们做什么决定?我们用什么技术来建立这些模型?
covid 19 影响的系统视图
新冠肺炎的影响是广泛的,全球性的,涉及生活的许多方面,也深刻地影响着我们的生活和生计。对影响的所有不同方面进行建模的最佳方式是采用系统级视图,并隔离关键系统以及这些系统之间的交互。一旦我们有了宏观层面的视图,我们就可以构建那些与我们想要在消费者、公司或国家层面做出的具体决策直接相关的系统的更精细的微观层面的视图。这将使我们变得有弹性——考虑到来自其他相关系统的关键驱动因素,同时也是动态的,我们可以专注于手头的即时决策。图 1 显示了所考虑的所有宏观和微观因素的系统级视图。

图 1:疫情的宏观和微观系统观及其对社会的影响
新冠肺炎疾病进展无疑是影响所有其他宏观层面系统的关键系统。许多疫情水平的不确定性,如疾病的不确定性(例如,感染率、潜伏期、扩散过程、增长率、住院率和死亡率)、测试(例如,诊断测试、抗体测试、准确性)、数据(例如,住院人数、死亡人数)和治愈(例如,治疗药物——其功效和何时可用、疫苗——其功效、试验、批准和规模化可用性)都会影响疾病的进展。这些不确定性具有很强的局部性和时间依赖性,例如,在不同的时间对不同的国家、州甚至是邻近地区产生不同的影响。
疾病的发展无疑会影响政府干预,这是我们的第二个宏观体系。基于国家的社会距离、经济活动的缩减和启动,如学校、酒吧、餐馆等的开放和关闭。实施或解除封锁的时间和持续时间都会对经济活动和人们的行为产生影响。
令人惊讶的是,公民行为已经成为疫情最重要的宏观层面系统组成部分之一——疾病的传播和经济活动反弹或停滞的能力【Firth-Butterfield-etal-2020】。虽然一些国家和美国的一些州在执行行动限制方面非常成功,其公民遵守了政府的干预措施,但其他州要么没有实施限制,要么公民没有遵守。当我们通过消费者需求、劳动力安全以及最终公司的财务可行性来考虑其对公司的微观影响时,这种宏观层面的动态变得极其重要和具有挑战性。
由政府干预推动的经济是另一个主要的宏观体系组成部分,由于疫情、其公民的行为以及政府为减轻公民和公司的经济痛苦而实施的财政刺激,政府干预抑制或促进了经济活动。
所有这四个宏观层次的系统组件都与微观层次的系统组件相互作用。客户、劳动力、公司、需求和供给是四个关键的微观层面的组成部分。客户和员工是公民的微观变体。一个地区或邮政编码内的公民在参与消费产品和服务时被视为客户,在参与为公司工作的经济活动时也被视为劳动力。公司满足消费者的需求,同时也生产商品或中间产品,为其他公司供货。公司也雇佣劳动力来生产商品和服务。所有这些互动都是通过支撑经济的现金来实现的。
在微观层面,需求的不确定性(例如,对航空旅行和旅游等一些产品和服务的需求大幅下降,或对卫生纸等产品的需求大幅增加)、供应链中断、劳动力安全、生产率和时间安排是经济活动的主要影响因素。这些因素加上政府是否提供财政支持,决定了公司的财务可行性(即利润、利润率、流动性和破产),以及个人的购买力、收入水平和就业状况。
制定战略或运营决策不仅需要了解系统层面的观点和组件之间的相互作用,还需要了解关键驱动因素和这些相互作用的性质(例如良性或恶性反馈循环)。考虑到需要做出决策的速度,高管们需要关注疫情的显著影响,以及疫情如何改变正常的反馈回路。
新冠肺炎建模与决策
确定了新冠肺炎系统的关键系统级组件后,我们现在来看看已经构建的特定模型,以及它们帮助我们做出的决策。
疾病进展:流行病学模型
模拟传染病发展的经典方法被称为 SIR 模型。这三个字母记录了一个人在感染过程中的不同状态,例如,变得 S 易受感染,然后 I 被感染,最后 R 从中恢复。这种类型的建模的进一步改进捕获额外的状态,如 SEIRD 模型(易感、暴露、感染、恢复和死亡)捕获暴露和死亡状态。新冠肺炎疫情已经产生了许多这样的模型-为不同的国家构建-捕获更多的国家。例如,一篇论文[Khalil-etal-2012]记录了上述 SEIRD 状态以及接触、隔离、未隔离和免疫状态。其他一些[Kompella-et al-2020;Silva-et-al-2020]记录有症状前和无症状前、有症状和无症状状态、住院和危急状态。一个模型捕获的感染状态越多,就越有利于精细的决策制定。这确实使模型更加复杂,并且需要更多的数据来校准模型。
对疾病进展进行建模的原因是为了能够进行不同的干预,以帮助减少感染、住院、死亡等。以及重返工作岗位和重启经济。这就引出了下一组模型。
政府干预&效果:行为模式
行为模型捕捉可以实施的不同限制和干预,以及它们在减少疾病传播方面的有效性。这些模型模拟干预措施,如居家命令(SHOs)或社会距离限制,并评估它们如何影响流行病学模型所描述的疾病进展。许多这些模型[Chen 等人-2020]具有时空维度,并且可以通过位置和政治关系来估计对这些命令的遵守情况。来自智能手机的移动数据可以帮助跟踪公民的移动,而不一定要识别他们,以评估封锁甚至社交距离干预的有效性。错误信息[Leitner-2020]对个体依从性和疾病进展的作用也可以使用这些方法进行研究。
经济影响:经济模型
当与行为模型结合时,流行病学模型也可以用于分析不同干预的经济影响。这些模型[Silva-etal.2020]允许政策制定者分析社会距离干预的不同情景,这些情景具有不同的流行病学和经济影响。Silva 等人在他们的模型中考虑了七种不同的情景:(1)什么也不做,(2)一级防范,(3)有条件的一级防范,(4)垂直隔离,(5)部分隔离,(6)使用面罩,以及(7)使用面罩以及 50%的社会隔离坚持率。
这些模型不仅有助于通过各种干预机制减少疾病的传播,还可用于以安全的方式重返工作岗位。例如,王等人的论文评估了纽约市的分阶段重新开放策略及其对城市内公共交通、小汽车交通和微观交通方式的影响。
不确定时间的建模方法
三种特定的建模方法或技术已被用于建立这些流行病学、行为和经济模型。历史上,基于方程的方法已被用于传染病传播的建模【段等-2015,亨特等-2018】。微分方程用于定义每个状态(例如,易感、传染性等)中的群体随时间变化的速率。然后随着时间的推移求解这些方程,以了解疾病的动力学。模型中更多的状态意味着需要更多的方程来捕捉相互作用的动力学,因此模型更复杂。基于方程的方法也被称为系统动态(SD)模型。
用于建立流行病学模型的第二种方法是基于主体的模型(ABM)。在基于代理的模型中,每个个体被表示为一个代理,他们与其他代理和环境交互。媒介从一种状态(例如,易感、传染性等)变化到另一种状态,并且运行许多这些媒介提供了疾病传播的总体动态。基于等式的方法将每个状态中的所有个体视为单个“隔间”,并且不允许任何个体差异。然而,在基于代理的模型中,每个代理都是独一无二的,这使得我们可以更自然地对前面讨论过的行为方面进行建模。
最近,机器学习——深度学习和强化学习——被用来建立这些模型。最近的方法是将新冠肺炎病例和死亡与地方层面的社会经济、健康和行为风险因素相结合,并使用深度学习[Fox-etal-2020]来更好地预测疾病进展。同样,强化学习[Kompella-etal-2020]正被用于优化缓解政策。
总之,理解疾病发展的动力学及其对个人行为和经济的影响的必要性导致了基于主体、系统动力学和机器学习模型的复兴。假设、数据、模型、政府干预和人类行为之间丰富的相互作用使得这些模型很难建立,但对于以系统的方式评估不同的策略非常有用。
参考文献
来自新冠肺炎建模的教训:数据、模型和行为的相互作用。“世界经济论坛。全球议程,2020 年 5 月 12 日。
Rao,a .和 Firth-Butterfield,k .“3 种方式——正在转变高级分析和人工智能”世界经济论坛。全球议程,2020 年 7 月 23 日。
埃及疫情流感基于主体的建模智能系统参考图书馆(2012):205–218。
莱特纳斯蒂芬。"关于流行病和信息流行病产生的动力"心灵&社会(2020 年):
陈,m .等.传播居家医嘱的因果估计ArXiv abs/2005.05469 (2020)。
Silva,Petrô nio C.L .等人," COVID-ABS:一种基于主体的新冠肺炎流行病模型,用于模拟社会距离干预的健康和经济影响。“混沌、孤子&分形 139 (2020): 110088。
行为惯性对纽约市公共交通重开策略的影响abs/2006.13368 (2020)。
AICov:一个用于人口协变量新冠肺炎预测的综合深度学习框架。ArXiv abs/2010.03757 (2020)。
Kompella,v .等.“优化新冠肺炎减缓政策的强化学习。ArXivABS/2010.10560(2020)。
传染病流行病学基于主体的模型和基于方程的模型的比较 AICS (2018)。
段文伟,范,周刚,郭炳忠,邱,:传染病模型的数学和计算方法:综述。计算机科学前沿 p. (2015)。https://doi.org/10.1007/s11704-014-3369-2
人工智能和意识的“无废话”指南
原文:https://towardsdatascience.com/a-no-bs-guide-to-ai-and-consciousness-b2976fb7f4c5?source=collection_archive---------9-----------------------
人工智能概论系列的第 5 部分

什么是意识?资料来源:Juan Rumimpunu viaUnsplash
"人工智能对人工大脑的探索已经将意识的神秘转化为有期限的哲学."
麻省理工学院教授马克斯·泰格马克博士
H 又是 ello!距离我上次发帖已经有一段时间了,但是我希望能再次加快速度,至少每两周发布一次这些故事*。因此,记住这一点,欢迎来到探索人工通用智能(AGI)系列的第 5 部分!如果你错过了前四部分,请在这里查看,从第一部分开始。本周我们将关注意识:这个难以捉摸、被误用、令人困惑的术语,它往往会引发存在主义危机…*
具体来说,本周我们要讨论以下问题:
- 什么是意识?
- 意识与思考思考有关吗?
- 什么是感觉,它和意识有什么不同?
- 现在的 AIs 有意识吗?
下周,在第 6 部分,我们将开始寻求阐明一个 AGI(或原型 AGI)可能被创造的实际的、可能的方法,并将主要处理认知建筑的令人难以置信的迷人的世界。
在这个系列中,每周/每隔一周会有一个新的帖子出现(我希望如此),如果有问题、评论或澄清,可以随时给(mferg@mit.edu 发电子邮件。尽情享受吧!
免责声明:毫无疑问,有些人更有资格对我将涉及的问题和主题进行深入的讨论,从情感到神经形态计算。对于这些人来说,这个系列只是对这些主题的介绍,因此,如果为了简洁而省略或浓缩了一些内容,请见谅。我真的只是想要这个系列,以及激发它的课程,作为一个相关 AGI 主题的调查,这些主题通常在学习人工智能或人工智能时不会被教授。还要注意:这个系列与麻省理工学院或其品牌没有任何关系——我只是喜欢在周末写一些我感兴趣的东西,麻省理工学院并不正式认可这里陈述的观点。
第一部分:什么是意识?
剧透警报:没人知道。
“我存在,仅此而已,我觉得这令人作呕。”
――萨特, 存在与虚无
我真的认为我们生活在计算神经科学的黄金时代。新的、强大的视觉、理解、注意力和语言模型正以极快的速度出现,随着它们朝着更像人类的方向发展,不可避免地会出现“它们到底有多像人类?”的问题出现了。请注意,这是一个相当复杂的问题,类似人类可能意味着许多不同的事情;然而,我直觉地感觉到,当大多数人问这个问题时,它倾向于承担意识的内涵。也就是说,随着这些模型变得越来越复杂,它们是在接近某种有意识的东西吗?
这篇文章试图超越对人工智能和意识的大肆宣传,并对现实生活中人工智能和神经科学实验室提出的问题做一个很好的概述,并试图消除人工智能和意识讨论中的一些“手动波动”。在我们的实验室里,我们不谈论意识甚至是一个笑话,因为它是一个如此沉重的术语,一个经常在没有严格纪律的情况下使用的术语,实际上指的是什么。
在研究和试图理解意识思维时,我一直牢记两件事:
- 任何试图声称他们已经理解了意识的本质或者解开了意识的秘密的人都很可能是错误的,或者试图向你推销某些东西。
- 你越研究它,你拼错“意识”这个词的次数就越多。
第一点是 Patricia Churchland 博士的解释[1],它很重要,因为截至 2021 年 9 月,我们完全不知道意识是什么,由什么组成,或者它来自哪里;我们几乎无法定义它,更不用说重现它了。我们有一些理论仍然需要进行实证检验,但没有确定的答案。
我知道这个答案并不十分性感,但我不能真诚地给你一个半生不熟或“胡说八道”的答案——科学现在根本不知道,声称它知道也是错误的。
然而,从现象学的角度来看,我们可以描述有意识和无意识是什么样子。感觉就像你是这个东西,从两只眼睛往外看,控制一个身体,思考。如上所述,意识是一个非常有内涵的词,当人们提到它时,他们可以指很多不同的东西,比如感觉、意识、自我意识、思考和体验。一些神经科学家认为意识是极其复杂系统的涌现属性,这意味着它只是……当大脑变得足够复杂时才出现。许多人被它吸引,包括我自己,因为它是我们对世界知识的一个巨大缺口,有许多进步和事实有待发现。传统上,意识已经被放逐到不可证伪的假设领域,因为众所周知,即使试图提出一个具体的理论也是一个困难的问题。因此,由于意识这个术语本身的复杂性质,我们将尝试解开一些常见的“类型”。
我们要画的意识类型之间的第一个(也可能是最大的)区别是在注意力和现象学(或 a vs. p )之间。简而言之,注意力意识是指意识到某些刺激,许多认知架构都实现了这种确切的机制。我意识到写这个帖子,现在是什么时间,我的手现在正在做什么,等等…另一方面,现象学 c 意识指的是 qualia[2];也就是说,用纳格尔的话来说,成为一只蝙蝠是什么感觉?在模拟中体验自己会是什么感觉?这种类型呼应了感受性、感觉和身心问题,这些都是我们在这个系列讲座中讨论过的。所以,现在许多原型 AGI 系统是有注意力意识的,但真正的乐趣是现象学性质的。

注意力:狗知道什么?现象学:当是一只狗是什么感觉?来源:Michael Dziedzic via Un spash。
意识这个词的另一个“类型”或区别来自安东尼奥·达马西奥,是核心五延伸。 核心 意识就像一个打开/关闭的开关,一个有机体是清醒的,意识到一个时刻,现在,和一个地方,这里[3]。有机体是警觉的,但不关心未来或过去,也没有自我意识。另一方面,当我们通常谈论意识时,我们指的是扩展意识:警觉,关注过去和未来。这通常被认为是人类特有的;你可能会说像猪和牛这样的动物有核心意识,但很难说它们延伸了核心意识。
最后,意识的最后一个区别我们将谈论一个相当众所周知的区别,那就是 无意识 , 潜意识 和前意识之间的区别。这些类型具体地并且通常是指注意力意识的类型:
- 无意识一般表示缺乏意识,不管什么原因【3】。
- 前意识一般是无意识的一个子集,一般表示影响有意识的行为[3]。
- 潜意识,对我们来说,和前意识是一样的【3】。
这里有一个很好的例子:无意识思维由一个人看到和听到的东西组成,但没有有意识地处理。无意识头脑可以储存这些信息,供有意识头脑以后检索,当我们可以科学地证明这一点时,它就被认为是前意识[3]。
所以,我们已经解开了一些关于意识的术语。在阐明它是什么,它从哪里来,或者更有趣的是,如何复制它方面,科学站在哪里?让我们来看看尝试这种解释的三种主要理论:
综合信息论【4】:
- 由托诺尼提出,由克里斯托弗·科赫倡导。
- 简而言之,这是一个功能主义理论,依赖于所谓的综合信息,这是一个网络“影响自己”的可测量程度。这是一个严重的过度简化,但在实验室设置和临床应用中已经显示出非凡的前景。
- phi(综合信息)多的东西更有意识。
- 想多读多学,强烈推荐科赫的书生活本身的感觉。
全局/神经元工作空间理论【5】
- 由 Bernard Baars 提出,并对认知体系结构的发展以及心理和行为建模产生了重大影响。
- 基本上是无意识过程基于注意力意识的显著性来竞争的一种方式,更重要的刺激是你意识到的。
- p 意识有一点棘手,目前的 G/NWT 对如何实现现象意识基本上不置可否。
- 下周当我们谈到认知架构时,我们会再次讨论。
注意图式理论
- 由普林斯顿神经科学家迈克尔·格拉齐亚诺提出。
- 唯物主义理论认为 p-状态是由注意力图式构成的,很像 GWT。在这里了解更多:【nih.gov注意力图式理论:主观意识的机械论解释
我知道这是很多信息;然而,人们用一生的时间来研究意识,而我们只有几千个单词。不要害怕。重要的是要介绍一些基本概念,这样我们才能理解意识在 AGI 身上的明显应用。
同样重要的是要注意,这些是关于不同作者认为意识(p 和 a)可能如何实现的模型/提议——这些模型需要进一步的验证、数据、研究和/或证伪。那确实是关于意识的棘手之处,也是为什么许多现代神经科学家、认知科学家和人工智能研究人员对这个术语犹豫不决——很难确定一个可以在医院、实验室或人工智能模型中得到经验验证的可测试假设。然而,IIT 已经在这一领域取得了长足的进步,如果你感兴趣的话,可以具体参见[6]和[7]了解更多的细节。
第二部分:意识与思考有关思考吗?
或者就我们而言,思考思考思考?
“波洛,”我说。“我一直在想。”
“一个令人钦佩的练习,我的朋友。继续吧。”
――阿加莎·克里斯蒂,末日之屋
我的狗能坐下来反思自己的行为吗?他能把自己投射到未来去考虑我会如何反应吗?比如说,如果他决定咬我的鞋或者在鹿粪里打一个漂亮的滚。大多数人可能会说,不,甚至狗也不具备这种能力,这是人类独有的技能,而且,从我的狗不回避鹿粪来看,我很可能会同意。这种反思的能力,在更高或者更抽象的层面上思考,思考认知本身就是元认知,那就是思考思考。更具体地说,元认知:
- 是一个基本概念,指的是任何知识,或认知过程,指的是,监测或控制认知的任何方面[8]。
- 被许多认知架构实现或在工作中,并被认为是心智的基石能力,至少在高级心智中是如此[9]。
- 很多时候,它被编写成一个“观察者”程序,可以观察情况,监控输入和重要系统,并做出相应的反应。我们将在下周的认知架构课上讨论更多。
- 问题是,我们需要p-意识来进行自我反省和思考吗?
最后一点是真正棘手的,也是许多研究这一问题的人的眼中钉。似乎为了真实地反映你的行为和动机,你必须有某种的内在模型来代表你是一个现象学的存在:也就是说,为了思考我自己,首先必须有一个我自己…深刻的东西!
但是,撇开 hooplah 不谈,元认知与意识有着深刻的联系和交织,不幸的是,我们并没有完全理解这种关系的本质和程度。

所有这些关于思考的思考…来源:Kazi Mizan via Unsplash
第三部分: 什么是觉知,它和意识有什么不同?
避免混乱的快速绕道
“真的有可能把自己的感受告诉别人吗?”
――列夫·托尔斯泰,安娜·卡列尼娜
两个经常被误用和混淆的术语是感觉和意识,甚至在神经科学和人工智能文献中也是如此。我尽力从解开这一困惑的研究人员那里找到最常见的主题,并将其列出如下:
- 感知力就其本身而言,仅仅意味着感觉或感知事物的能力。另一方面,从人类的角度来看,Sapient 用来指聪明的。
- 有些东西可以有知觉但没有意识,比如我的狗(在这种情况下是核心意识但不是扩展意识)。
- 一头牛能感觉到疼痛,体验到被关在笼子里或被带往死亡的感觉吗?我认为是这样的,尽管我将在这里推测,并说这与我们将体验到的感觉不一样,而是更“原始”——也就是说,他们可以感受到,但并不真正思考这些感觉。
- 一般来说,共识是感知是通往意识的道路:任何有意识的东西都必须有感知,但不一定是反过来[10]。对你们这些哲学书呆子来说,感知对于意识来说是必要的,但还不够。
我喜欢用最简单的方式来思考这个问题,还是从狗的角度。我和许多其他人可能会认为,狗显然是有感情的,也就是说,它们能感觉到疼痛和悲伤。然而,他们并不像我们一样有意识,因为他们没有时间上的“我随着时间的推移”,或者像“哇,你知道,我真的可以吃一个很好的鹿粪卷”这样的想法。如果我做得很快,迈克甚至不会注意到!”。他们只是在此时此地经历一些事情,并基于这些经历感受一些事情。
第四部分:现在的人工智能有意识吗?
号码
“有一个帕特里克·贝特曼的想法,某种抽象;但是没有真实的我,只有一个实体,一个虚幻的东西。虽然我可以隐藏我冰冷的目光,你可以握我的手,感觉到肉体紧紧抓住你的手,也许你甚至可以感觉到我们的生活方式可能是相似的,但我就是不在那里。”
——帕特里克·贝特曼,《美国惊魂记》(1991)
我纠结于引用一句美国精神病患者的话,不是因为它无关紧要,而是因为帕特里克·贝特曼是一个令人憎恶的人。这也是这本书的目的:揭示 80 年代美国典型的华尔街雅皮士兄弟亚文化的丑陋面。我认为布莱特·伊斯顿·埃利斯抓住了这一点,我也认为他抓住了这种虚幻而短暂的自我意识,这种自我意识甚至存在于人类中——当你有一个人在各种意义上看起来都很正常,但在元认知或反思意识缺失的地方会发生什么?如果我们人类很难看到另一个人在这方面的缺失,我们怎么可能准确地评估一个动物,甚至一台机器?
好吧,回到我的文学话题:人工智能离全面的 p 意识还很远。一个案例可以,也应该被提出,一些尖端的认知架构是有注意力意识的,但是还没有任何东西实现 p 意识。我没有提出很多坚定的观点,但这是我支持的观点,我很乐意就此进行辩论。
甚至不清楚当大多数人讨论“人工智能和意识”时,他们指的是哪种人工智能:简单的前馈人工神经网络?贝叶斯推理机?线性分类器?一个循环脉冲神经网络?所以,即使这个答案相当枯燥,也要知道人工智能(还)没有意识,很可能一段时间内都不会。然而,我个人确实相信,我们将破解这一密码,并有朝一日创造出一台人工意识机器;但是现在,人类可能只能坚持用老式的方式创造意识思维:)

更多的数据,需要测试来理解意识。资料来源:Olga Guryanova viaUnsplash。
TL;速度三角形定位法(dead reckoning)
现代神经科学不知道意识是什么,但我们有一些关于它可能由什么组成的理论。需要更多的测试、验证、数据和工作才能真正知道,但目前,没有“人工智能”是有意识的,很可能在一段时间内不会。
其他需要考虑的问题:
- 你如何看待“ 复杂系统的突现性 ”关于意识的假说?
- 你认为你能形式化意识吗?
- 重访:你认为我们能在计算机(即图灵机)中实现现象学意识吗?
“我不能假装我没有恐惧。但我最主要的感觉是感激。我爱过也被爱过;我被给予了很多,我也给予了一些回报;我阅读、旅行、思考、写作。
最重要的是,在这个美丽的星球上,我是一个有意识的生物,一个有思想的动物,这本身就是一种巨大的特权和冒险。"
―――奥利弗·萨克斯,感恩
参考资料:
- 帕特里夏·史密斯·丘奇兰。触动神经:作为大脑的自我。诺顿公司,2014 年。
- 《哲学季刊》第 32 卷第 127 号。(1982 年 4 月),第 127-136 页。
- 意识的新科学:探索大脑、心智和自我的复杂性。普罗米修斯图书公司,2016
- https://iep.utm.edu/int-info/
- https://online library . Wiley . com/doi/10.1002/9781119132363 . ch16
- https://www . frontiersin . org/articles/10.3389/fnhum . 2018.00042/full
- https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6703193/
- 罗伯特·威尔逊和弗兰克·凯尔。麻省理工学院认知科学百科全书。麻省理工学院出版社,1999 年。
- 富兰克林,斯坦和乌玛·拉马姆西。"动机、价值观和情感:一枚硬币的三面."第六届表观遗传机器人国际研讨会会议录,法国巴黎,2006 年 9 月,隆德大学认知研究。№128.2006.
- 里斯拜伦。第四时代:智能机器人、有意识的计算机和人类的未来。ATRIA Books,2019。
关于作者
Mike Ferguson 是麻省理工学院 DiCarlo 实验室的计算研究开发人员(ML/AI)。他致力于大脑评分,这是一个测量人工神经网络有多像大脑的工具。他于 2021 年春季毕业于弗吉尼亚大学,获得了计算机科学和应用数学学士学位,以及认知科学和哲学学士学位。他是《一周挑战》一书的参与者,在三年内阅读了超过 155 本关于人工智能、哲学以及对人类意味着什么的书籍。他和他的伯恩山犬“博伊·温斯顿”以及收养的边境牧羊犬“影子”住在马萨诸塞州的梅尔罗斯。
一种构建知识图的无代码方法
原文:https://towardsdatascience.com/a-no-code-approach-to-building-knowledge-graphs-ce5d6b244b2b?source=collection_archive---------19-----------------------
利用像 KgBase 这样的无代码平台从关系数据中获得新的见解

Niklas Ohlrogge 在 Unsplash 上拍摄的照片
我们周围的世界充满了不同实体之间丰富的关系。我们可以在我们的社交网络、企业内部的组织结构图,甚至维基百科上的所有出版物中找到有意义的链接。
这些联系中的数据包含丰富的信息,从中可以得出深刻的见解,这就是知识图擅长捕捉这些关系的地方。
本文深入探讨了我们如何利用无代码平台,如 KgBase 来创建知识图,并给出了一个涉及药物副作用分析的例子。
目录
【1】快速知识简介图表(2)无代码平台的崛起
(3)创建我们第一个无代码知识图表
(1)知识图表快速介绍
知识图组织来自现实世界实体(例如,对象、事件、概念)网络的数据,并捕捉它们之间有意义的(又名语义 ) 关系。

样本知识图|图片来源:斯坦福 CS 520
在其最简单的形式中,知识图是一个有向带标签图,它由三个部分组成:节点、边和标签。
我们来看上面知识图中用红色圈出的例子(**Albert Einstein** → **Germany**)。节点是阿尔伯特·爱因斯坦(人)和德国(国家)边是这一对节点之间的连接,标签代表关系的含义(即阿尔伯特·爱因斯坦出生在德国)。
由于知识图在大规模表示实体和关系方面的可靠性,以及企业在从蓬勃发展的数据存储中提取价值方面日益增长的需求,知识图最近受到了欢迎。
它们目前广泛用于研究和行业的许多应用中,例如聊天机器人、搜索引擎和产品推荐。

奥马尔·弗洛雷斯在 Unsplash 上拍摄的照片
(2)无代码平台的崛起
尽管对编程大肆宣传,但大多数人确实不(也不需要不)知道如何编码。重要的是,组织需要那些知道如何用正确的工具解决问题的人。
无代码解决方案的可用性使数据科学民主化,允许非技术用户执行复杂的分析任务,而无需编写任何代码。
这些解决方案围绕用户友好的用户界面构建,用户只需单击、拖放元素,即可执行一系列自动化功能。
KgBase 是专门为知识图构建的无代码平台的一个例子,它提供了一个即插即用的系统,使用户能够以不同的方式查看各种关系和实体中的数据。
(3)创建我们的第一个无代码知识图
让我们探索一下如何用 KgBase 在仅仅五个步骤中创建图形。我们将对 13 种常用处方药的副作用进行探索性分析。
数据来源于斯坦福网络分析项目( SNAP )。具体来说,我们有三个数据子集(来自原始 ChChSe-Decagon 数据集)要处理:
- drugs . CSV→该组 13 种药品的药品名称和药品代码
- 副作用. CSV→副作用名称及对应代码(MedGen 概念 ID)
- 匹配-药物-副作用. csv →药物及相应副作用的表格数据

match-drug-side-effect.csv |图片作者
步骤 1 —创建项目
登录后,我们将看到仪表板登录页面。点击空白文件夹(带有 + ),使用空白模板开始一个新项目,并给项目命名,例如药物副作用**。**

作者图片
步骤 2 —导入数据
在项目创建之后,已经有一个默认的节点标题为表 1。现在的目标是为三个数据集中的每一个创建一个节点。
我们首先通过点击表 1 名称旁边的省略号()菜单将默认节点重命名为药品 ,并选择编辑以更改节点标签。

作者图片
从这里,我们可以导入数据。在数据选项卡中,点击齿轮图标并从菜单中选择导入数据**。**

作者图片
找到 DRUGS.csv 进行上传,然后在随后的配置 csv 文件部分勾选包含标题行和创建列两个复选框,然后点击继续**。**

作者图片
至此,我们完成了包含 DRUGS.csv 数据的第一个节点。然后我们再添加和两个节点,并对剩下的两个数据集重复上面的指令。
我们通过点击添加按钮来添加节点,我们可以将这两个节点命名为副作用和匹配表。

作者图片
这样做好之后,我们就要有三个节点:药物、副作用、匹配表。
步骤 3 —设置标签
我们将标签设置为药物和副作用的名称,这样我们的图表将显示名称而不是难以理解的代码。****
我们首先从列标题旁边的省略号下拉菜单中选择“用作标签”。确保对所有三个节点的执行此操作,以便药物名称和副作用名称列最终会在旁边有一个灰色的“标签指示器。****

作者图片
步骤 4 —定义节点之间的关系
转到'匹配表'节点,定义所有节点之间的关系。我们点击药品名称栏旁边的省略号菜单,选择“到关系”。

作者图片
我们选择“一对一关系”按钮(因为这是一对一的名称映射),然后单击下一个的。****

作者图片
在下一页,我们将被要求指定一个目标节点标签。我们的目标节点标签( drug_name )已经存在于药品节点中,所以我们在点击 Convert 之前从现有的表格中选择合适的标签。

作者图片
我们对副作用重复这一步骤,其中我们为匹配表节点中的 side_effect_name 与副作用节点中的匹配 side_effect_name 创建了一个对一关系**。**
当该步骤成功完成时,我们将看到标签在匹配表中以浅蓝色突出显示。

作者图片
步骤 5—将表转换为关系
最后一步是根据源列和目标列将整个匹配表转换成关系**。来源是药物名称,,目标是副作用名称,因为我们希望将每种药物与其副作用联系起来。**
我们通过点击匹配表节点的省略号菜单并选择‘To relationship’来执行此转换。

作者图片
在下一页,我们定义相应的源和目标列,然后选择 Convert 。

作者图片
在转换时(需要 5 到 10 分钟),我们将完成我们的知识图,而无需编写任何代码!
(4)可视化知识图
让我们来看看我们构建的知识图的可视化。我们通过点击顶部栏的图表选项卡来完成,页面将显示图表(基于整个网络的随机样本)。

作者的知识图|图像的可视化
红色节点代表药物,而蓝色节点代表副作用。我们可以很容易地看到,根据淋巴结大小,阿司匹林的副作用数量最多。
当我们选择单个副作用时,例如反射减弱**,我们可以看到哪些药物可能会导致特定的副作用。**

作者的知识图|图像的可视化
用户界面中还有大量选项可用于更深入的分析。这些选项包括将图形限制为特定属性的过滤器和基于预定义约束定位路径的复杂查询。
你可以在 这里 浏览这个项目的公共文件夹。
(5)用业务元数据丰富分析
除了创建知识图表, KgBase 还是一个开放协作的知识图表库的所在地,其中包含全球 10 万多家公司的业务数据。这个丰富的数据库使用户能够将分散的数据符号联系在一起,并消除冗余的映射过程。
例如,对医药公司' Amgen' 的简单搜索会返回其通用业务标识符( UBID )和相应的元数据,如品牌映射和财务标识符(例如,CUSIPs、ISINs、DUNS、FIGI 编号等)。)

UBID 知识库中的搜索结果|作者图片
本着开源协作的精神,用户可以通过贡献尚不存在的业务元数据来丰富这个数据库。
例如,“列克制药”的 UBID 是由一名投稿人提供的,该信息随后被批准和添加。

向 UBID 知识图谱库添加元数据|作者图片
(6)结论
关于知识图的能力,我们只看到了冰山一角。例如,企业还可以使用知识图创建通用数据源来连接跨不同领域的多个数据源。
在过去,构建知识图需要大量的工作,但是无代码平台使得非专家创建、集成和维护这样的系统变得更加容易。
因此,看到这些平台继续变得越来越主流并帮助使用知识图表的好处大众化就不足为奇了。
在你走之前
欢迎您来到,与我一起踏上数据科学学习之旅!关注我的媒体页面和 GitHub 以了解更多精彩的数据科学内容。同时,享受构建知识图表的乐趣!
使用 TigerGraph 的地理空间布局功能绘制 UFO 目击图的无代码方法
原文:https://towardsdatascience.com/a-no-code-method-of-mapping-ufo-sightings-with-tigergraphs-geospatial-layout-feature-a7676ea2c074?source=collection_archive---------32-----------------------
将 TigerGraph 的地理空间布局功能用于自定义数据集
介绍
概观
在之前的博客中,我们利用 TigerGraph 的新冠肺炎入门套件,通过地理空间布局功能来绘制旅游事件地图。现在让我们看看如何为自定义数据集使用地理空间布局功能。在这种情况下,我们将使用 Kaggle 的 UFO 目击数据集。让我们投入进去吧!
旅程
- 介绍
- 设置 TigerGraph 3.2 解决方案
- 创建模式
- 准备并加载数据
- 绘制目击地图
- 后续步骤
工具和资源
- TigerGraph 云
- Kaggle (特别是 UFO 数据集)
第一步:建立一个 TigerGraph 3.2 解决方案
首先,我们将推出一个免费的 TigerGraph 3.2 云解决方案。为此,导航至https://tgcloud.io/并登录或注册。
在左侧边栏中,选择“我的解决方案”,然后按蓝色的“创建解决方案”按钮。


点击“我的解决方案”,然后点击“创建解决方案”(图片由作者提供)
在第一页上,确保您的版本是 3.2,并选择空白的初学者工具包。按下一步。

创建一个空白的 3.2 解决方案(图片由作者提供)
不要更改第二页上的任何内容。本质上,这只是为你创造了一个免费的解决方案。

第二页保持原样(图片由作者提供)
在第三页上,更新特定解决方案的信息。

将此更新到您的解决方案中(图片由作者提供)
最后,在第四步,确认一切正常,然后点击“提交”

仔细检查一切并提交!(图片由作者提供)
等到你的状态变成绿色,然后按下四个方块并从下拉菜单中选择“GraphStudio”来启动 GraphStudio。


当你的状态变成绿色时,按下四个方块,然后从下拉列表中点击“GraphStudio”
完美!现在您已经准备好创建您的模式了。
第二步:创建模式
让我们首先基于数据创建模式。为此,点击“全局视图”,然后创建一个新的图表(我称之为不明飞行物)。


点击“全局视图”并从下拉菜单中点击“创建图表”(图片由作者提供)

输入 Graphname(如“UFO”)(图片由作者提供)
要开始设计模式,请按“设计模式”选项卡。

点击进入“设计模式”标签(图片由作者提供)
要添加(局部)顶点,请按顶部的加号按钮并适当编辑属性。

按加号添加一个局部顶点(图片由作者提供)

适当地更新属性。(图片由作者提供)
要添加边,请单击箭头,然后单击要连接的两个顶点。


用箭头添加一条局部边,然后单击要连接的两个顶点(图片由作者提供)

根据需要编辑属性(图片由作者提供)
至于模式设计,虽然我们可以使它更复杂,但我选择将国家、州和城市分成顶点(用它们的值作为主 id 和属性),并将其余数据添加到主 id 为 DateTime 的景点顶点中。

图表的模式(图片由作者提供)

瞄准顶点的属性(图片由作者提供)
一旦创建了模式,按向上键发布模式,您就可以进入下一步了!

按向上箭头发布模式(作者图片)
第三步:准备和加载数据
接下来,我从 Kaggle UFO 目击数据集下载了 complete.csv 文件,并上传到 GraphStudio。为此,导航到“将数据映射到图形”选项卡,然后单击“添加数据文件”选项。


导航到“地图数据”选项卡,然后单击“添加数据文件”选项。(图片由作者提供)
按加号,上传 CSV,然后添加。


选择 CSV,然后按“添加”按钮。(图片由作者提供)
然后,我将 CSV 映射到适当的顶点和边。为此,您可以单击 CSV,按下带有“将数据文件映射到顶点或边”悬停数据的交叉箭头,然后适当地映射数据。

绘制数据图(图片由作者提供)
最后,我通过导航到“Load Data”并按下 play 按钮将数据加载到图表中。


转到“加载数据”选项卡并按下播放按钮。(图片由作者提供)
之后,在图表统计中,您应该会看到图表中所有的顶点和边。

您应该可以看到图中的顶点和边(图片由作者提供)
完美!现在我们可以绘制数据。
第四步:绘制景点地图
最后,使用“Explore Graph”选项卡,我绘制了数据。我首先选择了 100 个景点。

导航到“探索图”并选择 100 个观察点。(图片由作者提供)
接下来,我单击强制并选择地理空间地图选项。这样,顶点就就位了!

测绘结果(图片由作者提供)
从这一点,我可以说大多数的 UFO 目击事件,至少从这个样本来看,是来自美国的。我探索了更多的数据,并放大了美国,以了解更多关于这些目击事件的信息。

只有美国地图(图片由作者提供)
从这里,我可以在 GraphStudio 中微调我的数据探索等等,而无需编写任何代码。
第五步:下一步
完美!既然您已经在这个自定义图表上使用了地理空间映射功能,那么您现在可以轻松地在自己的项目中使用它。如果您有任何问题或遇到任何错误,请随时在社区论坛上发表。
https://community.tigergraph.com/
此外,你可以和更多的 TigerGraph 开发者在社区 Discord 上聊天。
https://discord.gg/gRHWBZNpxW
祝你在你的项目中使用这些地图好运,我迫不及待地想看看你创造了多么棒的项目!
数据源
使用的数据来自 Kaggle 这里是,没有指定许可证。西格蒙德·阿克塞尔在这里从 NUFORC 数据中搜集、地理定位和时间标准化了这个数据集。
一个非流行病学家对美国新冠肺炎疫苗接种公开数据来源的统计检查
原文:https://towardsdatascience.com/a-non-epidemiologists-statistical-examination-of-us-state-level-open-data-sources-on-covid-19-788c37683966?source=collection_archive---------33-----------------------
试图合成一个复杂的数据集网络

图片作者:尼克·费因斯
2021 年 3 月 29 日,我收到了印第安纳州卫生部的电子邮件邀请我接种新冠肺炎疫苗。我没有密切关注疫苗的推出,我正在寻找经验。我的目标是更好地理解疫苗接种运动。在本文发表时,大约 25%的美国人口已经接种了疫苗。我试图获得一些背景资料,并在新冠肺炎的误传世界中梳理出什么是事实,什么是虚假的。从我对 COVID 数据集的早期研究中,我希望看到数据实践的发展。这是跟踪一个非常重要的现实世界现象的一个资金充足的最佳尝试,因此它是数据结构和“最佳实践”的一个很好的例子。作为一个数据猴,很难忽视。所有的代码都是公开的,可以在这里找到:
- 公开回购
数据源
- 《纽约时报》新冠肺炎州级病例跟踪系统(
cvd)维护着州级每日新增病例和死亡人数数据 定义 - 牛津新冠肺炎政府响应跟踪系统(OxCGRT,又名
oxf)描述了与政府政策相关的事件时间表,但不太详细。数据 定义 - OWID (
vax)结合多种来源数据 定义维护每日接种疫苗和完全接种疫苗的人数 - 美国人口普查州级人口(
pop)是基于美国人口普查工作数据 定义对美国人口最全面和最纯粹的估计
连接这些数据源需要清理转换。这些转换的代码在这个博客中进行了总结,在这里我就不赘述了。然而这些代码都可以在公开回购中找到。
数据质量报告
新冠肺炎纽约时报
开始:2020–01–21
结束:2021–03–31
今天:2021–04–01
接种反应变量全状态记录:
- 开始时间:2020 年 3 月 13 日
- 结束时间:2021 年 3 月 31 日
- 未满:【<=2020–03–12]
- subset of states always reporting: [Washington]
Conclusions:
- We remove the data prior to 2020–03–13.
OxCGRT
Starts: 2020–01–01
结束:2021–03–30
今日:2021–04–01
接种反应变量全状态记录:
- 开始时间:2020 年 9 月 14 日
- 结束时间:2021 年 3 月 29 日
- 未满:[2020–12–08,> = 2021–02–12]
结论:
- 我们假设在 2020 年 9 月 14 日之前,没有已知的疫苗接种,因此这些人实际上是 0
OWID 疫苗接种数据(州级数据)
开始:2020–12–20
结束:2021–03–31
今天:2021–04–01
接种反应变量全状态记录:
- 开始时间:2020 年 9 月 14 日
- 结束时间:2021 年 3 月 29 日
- 未满:[2020–12–08,> = 2021–02–12]
结论:
- 除了每个州何时开始提供疫苗之外,这个数据集可能对一些问题有用。
- 不能用于确定疫苗接种活动的早期时间表,即开始日期。
- 反映了疾病预防控制中心如何将疫苗接种归属于各州的政策变化,该政策从 2021 年 2 月 19 日开始实施。这将在这篇博客中一瞥而过,但是解释这个噩梦所需的策略值得在第二篇文章中讨论。代码可在 github 中获得。
清洁任务的非详尽总结
- 我们将连接数据集的关键索引是日期和州名,因此我们在数据集之间符合日期和州名
- 牛津数据集要求将关键变量编码为类别,该数据集描述了与政府政策实施相关的大致时间表,包括美国各州的疫苗接种活动
- 由于疫苗接种数据集在 COVID 病例跟踪数据集之后开始,因此我们在疫苗接种数据集可用之前用 0 填充日期。
- 异常移除。在 OWID 数据集中,起始观测值是异常的。我认为这是因为数据实际上没有涵盖真正的开始日期,所以第一次观察从零开始进行了不合理的跳跃。
- 人口调整。每个源数据集可能已经提供了人口调整后的估计值,也可能没有。我们选择使用疫苗接种、新增病例和死亡的非调整来源观察,所有人口估计都始于独立来源的 2019 年美国人口普查。
调查目标
问题在一开始就被定义,以集中工作并避免迷失在数据的海洋中。可能目前有 1000 多个数据源,它们形成了一个复杂的相互依赖的网络。尝试以某种有意义的方式来度量这种相互依赖性将是一项有趣的后续任务。选择 4 个数据集来回答我们的问题,但它们也包括许多其他变量。所以专注是关键。
调查将围绕 3 个主要问题展开:
- 每个州什么时候开始接种疫苗,谁是第一个,最后一个,平均水平?统计显著?
- 哪些州在给人们接种疫苗和完全接种疫苗方面最快、最慢、一般?统计显著?
- 哪些州看到了疫苗接种对减少新病例的最大、最小和平均影响?统计显著?
该调查将试图解释以下主要混淆因素:
- 在开始接种疫苗时,冠状病毒检测呈阳性的人口比例是多少?(例如,合格人口的规模有多大?)
- 人群中发生了多少个人之间的高风险活动?
- 发生了多少误诊?数据集中有多少噪音?哪些州最擅长报告病例?
- 接种了哪种疫苗?
- 与疫苗相比,行为改变在多大程度上影响了病例/死亡的减少?
每个州从哪一天开始接种疫苗,谁是第一个,最后一个,平均?统计显著?
冠状病毒疫苗的采购在州一级进行,并非所有的州都同时开始。这里,我们考虑每个州的疫苗接种日期变为非零(“0-不可用”)。统计显著性的度量基于日期的分布,我们将描述异常和统计显著性异常。绘制密度图,每天,我们计算开始接种疫苗的州的数量。所以,我们需要计算疫苗首次出现的日期。
如果你知道更多关于这个过程是如何运行的,以及为什么一些州比其他州更慢地实施他们的第一批疫苗,请随时留下评论。作者也没有排除牛津数据集在具体日期上出错的可能性。
疫苗接种的早期、正常和晚期状态
第一个州:俄克拉荷马州(2020–12–11)
最后一个州:亚利桑那州(2021–01–05)
平均日期:(2020–12–15)
中位数日期:(2020–12–15)
标准差:3.74 天
异常和统计显著性
典型的州于 2020 年 12 月 15 日开始为其人口接种疫苗。有 3 个州起步较晚,从最晚的开始:亚利桑那州、内布拉斯加州和密苏里州(按此顺序)。亚利桑那州和内布拉斯加州可被视为统计显著异常,因为它们超过平均值的 3 个标准偏差。
vax_start_dates_oxf = []
for state, data in oxf.df.groupby('state_name'):
a = data[data['vaccination_policy'] != 0.0]
b = a.sort_values('date').iloc[0]
c = b.to_dict()
vax_start_dates_oxf.append(c)
vax_start_dates_oxf = pd.DataFrame(vax_start_dates_oxf)
first_vax = vax_start_dates_oxf.date.min()
vax_start_dates_oxf['days_from_first'] = vax_start_dates_oxf['date'].apply(lambda x: (x-first_vax).days)
vax_start_dates_oxf['days_from_first'].hist(
bins=vax_start_dates_oxf['days_from_first'].max(),
figsize=(16,3), grid=True,
)

州疫苗接种开始日期的 z 分数(图片由作者提供)
接种疫苗的速度:哪些州在给人们接种疫苗和完全接种疫苗方面最快、最慢、一般?统计显著?
加载了两个数据集,其中包含有关全州推广速度的信息。目标是尽快为尽可能多的公民接种疫苗。所以每天我们都会考察一个“步伐排行榜”。我们将为每个日期计算一个函数,该函数根据接种疫苗的受试者和完全接种疫苗的受试者的数量返回各州的有序列表。为此,我们将使用 OWID 数据集,其中包含已接种疫苗的数量。我们将向数据集添加两个新值:
- 各州 2019 年人口普查人口实施的疫苗接种
- 从开始算起的天数
首先,我们观察接种过疫苗的受试者,然后详细讨论等级排序背后的分布,以检验显著性。
我们研究的变量来自 OWID 中的底层数据。
adj_vax['adj_total_vaccinations'] = adj_vax.apply(
lambda x: x['total_vaccinations'] / float(state_to_pop[x['location']]),
axis=1
)
adj_vax['people_vaccinated_%pop'] = adj_vax.apply(
lambda x: x['people_vaccinated'] / float(state_to_pop[x['location']]),
axis=1
)
adj_vax['people_fully_vaccinated_%pop'] = adj_vax.apply(
lambda x: x['people_fully_vaccinated'] / float(state_to_pop[x['location']]),
axis=1
)
adj_vax['days_from_start'] = adj_vax.apply(
lambda x: (x['date'] - state_to_start[x['location']]).days,
axis=1
)
速度领先和统计显著性
为了确定领先是否具有统计显著性,我们将使用“领先步速”的分布作为步速测量的(k-1)-th和k-th观察值之间的%差异。因此每天会有 50 次观察,N=40*50=2000接近于一个显著样本量的观察来检验这个问题。因为我们是根据每日排名的有序列表计算领先速度的,所以我们通过顺序统计进行建模,并将通过比较j-th和k-th“领先速度”的分布来检验“领先就是领先”的假设,其中j != k。
疾病预防控制中心政策变化引起数据质量问题
(彭博,2021–01–21)描述了我们观察到的people_vaccinated和people_fully_vaccinated的累计和在减少的问题。影响 OWID 数据集的 CDC 政策变化的生效日期并不完全相同,因此这使得各州疫苗制度之间的比较变得复杂。我最初是通过寻找变化大到足以导致接种疫苗的人数少于政策变化前一天的例子来发现这一政策变化的影响的。对于该系列变得非单调的州来说,那一天肯定是开始,华盛顿特区将经历巨大变化是有道理的,因为它是联邦雇员相对于人口最集中的地方。然而,这很可能不是影响的程度-其他国家可能有更微妙的影响,但仍然很大。有没有人开发出方法来解释和量化 CDC 政策变化的影响?
应对疾病预防控制中心政策变化的一些挑战包括:
- 各州在不同的日子开始了新的 CDC 计数程序
- 各州经历了不同的影响大小,其中一些很难检测到,而华盛顿特区经历了巨大的影响,因为 CDC 开始以不同的方式计算联邦管理的疫苗,其他州可能影响很小。那么这个怎么衡量呢?
因此,对策以一个规则为中心,该规则可以确定 cdc 政策的开始生效日期,因此我们可以根据各州是在政策之前还是之后对它们进行分组。我们通过计算 CDC 政策宣布生效后的标准差来检查dod_%diff_state_people_vaccinated的异常情况,并发现数量大于平均值的 2 个标准差dod_%diff_state_people_vaccinated。最合适的日期是 2021 年 2 月 17 日
当前排名
自然,疫苗的首次展示在一些地方比其他地方进行得更好。最大的问题是为什么一些州比其他州快得多,以及一些瓶颈是否基于政治地位。
最快的疫苗推广速度
至少接种一次疫苗

最快的是至少接种一次疫苗,占 2019 年美国人口普查人口的百分比。(截至 2020 年 4 月 7 日)(图片由作者提供)
完全接种疫苗

最快全面接种疫苗占 2019 年美国人口普查人口的百分比。(截至 2020 年 4 月 7 日)(图片由作者提供)
疫苗推出最慢
至少接种一次疫苗

在 2019 年美国人口普查中,接种疫苗至少一次的比例最慢。(截至 2020 年 4 月 7 日)(图片由作者提供)
完全接种疫苗

按 2019 年美国人口普查人口的百分比计算,最慢到完全接种疫苗。(截至 2020 年 4 月 7 日)(图片由作者提供)
当我们观察完全接种疫苗的人口百分比与至少接种一次疫苗的人口百分比时,疫苗接种的领导者发生了变化。虽然新罕布什尔州和康涅狄格州在至少给人们接种一次疫苗方面做得很好,但他们在给人们接种疫苗方面做得不够好。特别是在新罕布什尔州,该州在至少接种一次疫苗方面排名第二,但在完成接种方面排名第 22。落后者也会改变。例如,密西西比州在全国至少给人口接种一次疫苗方面是第三慢的,但在完成疫苗接种方面仅是第八慢的。其他值得注意的变化包括华盛顿特区,它不算太差,在至少接种一次疫苗方面排名第 15,但在完成接种疫苗方面排名第 5。当然,最极端的对比是新罕布什尔州,该州在接种一次疫苗方面表现出色,但在完成接种方面还可以。
哪些州见证了全面接种疫苗对减少新发病例的最大、最小和平均影响?统计显著?
据称,Moderna 和辉瑞公司的疫苗在预防该病毒方面有大约 90%的有效性。因此,我们将绘制已完全接种疫苗的人口百分比相对于新增病例数的图表。我们希望看到一个直接和明显的趋势来加强这些说法。我们可以看看在完成疫苗接种方面最有效的州,比如新墨西哥、南达科他和阿拉斯加。然而,在这种情况下,前 3 名的人口密度都很低。康涅狄格和新泽西可能是很好的例子,因为他们在为人口全面接种疫苗方面做得很好,并且人口相对密集和活跃。
解决方案设计:
- 将纽约时报的
cvd数据集与adj_vax数据集连接起来。我们想要一个右连接,所以我们保留来自cvd的索引,并添加来自adj_vax的观察值 - 看专栏:纽约时报的
cases和 OWID 的people_fully_vaccinated_%pop
说明现有的免疫力、畜群和疫苗接种
免疫的两个主要来源导致易感染新冠肺炎病毒的人群显著减少。群体免疫发生在人们感染病毒后,他们在一段时间内是免疫的。根据在伦敦英国公共卫生主办的塞壬研究的 Susan Hopkins在《自然》杂志(2021 年 1 月 14 日)上总结的说法,患有新冠肺炎病毒的人几乎不可能在几个月内患病。疫苗免疫是指人们不太可能因为被戳而感染病毒。
将疾病时间表考虑在内导致实施了 3 个数量,这使得能够对每个州的弱势人群进行估计。数据集的聚合使分析变得复杂,因为我们缺少关键信息。也就是说,我们不知道当时有多少患者被诊断为t死亡或康复。在这种情况下,数据很难解释,因为我们不知道疾病最初被发现后几周的结果。但是,即使在“有人应该知道”检测呈阳性的病人是康复了还是死了的情况下,我们也没有这些信息。也许有,但是在发表的时候,这个数量还不知道。
我们使用 3 个假设来控制免疫人群,如下所示:
vax_imm_lag = 14:接种疫苗的人在完全接种后vax_imm_lag天开始免疫case_incub_pd = 10:人们感染新冠肺炎病毒并开始出现症状的间隔天数case_imty_pd = 4:一个人拥有 covid 几个月后,他们可以再次获得它
我们利用以下这些量实现逻辑:
cvd_and_vax = pd.merge(
left=cvd.df, right=adj_vax,
how='left', left_on=['date', 'state'],
right_on=['date', 'location']
).copy()
cvd_and_vax[['total_vaccinations', 'total_distributed', 'people_vaccinated',
'people_fully_vaccinated_per_hundred', 'total_vaccinations_per_hundred',
'people_fully_vaccinated', 'people_vaccinated_per_hundred',
'distributed_per_hundred', 'daily_vaccinations_raw',
'daily_vaccinations', 'daily_vaccinations_per_million',
'share_doses_used']] = cvd_and_vax[['total_vaccinations', 'total_distributed', 'people_vaccinated',
'people_fully_vaccinated_per_hundred', 'total_vaccinations_per_hundred',
'people_fully_vaccinated', 'people_vaccinated_per_hundred',
'distributed_per_hundred', 'daily_vaccinations_raw',
'daily_vaccinations', 'daily_vaccinations_per_million',
'share_doses_used']].fillna(0.,)cvd_and_vax.dropna(subset=['state'])
del cvd_and_vax['location']cvd_and_vax['cases_%pop'] = cvd_and_vax.apply(
lambda x: compute_fn(
a=x['cases'],
b=apply_dic(state_to_pop, x['state']),
fn=lambda a,b: a/b),
axis=1
)
cvd_and_vax['deaths_%pop'] = cvd_and_vax.apply(
lambda x: compute_fn(
a=x['deaths'],
b=apply_dic(state_to_pop, x['state']),
fn=lambda a,b: a/b),
axis=1
)
cvd_and_vax.index = cvd_and_vax['date']### state-level calcs ###
# an adjusted population measurement accounting for people who have been immunized and
# we have a challenge adjusting the population because if we adjust by deaths and cases, we are double counting
# this is a cost of having aggregated non-subject level data sets. It's impossible to know how to account for
# the cases and deaths in a harmonious way
# - increase people_immd by people_fully_immunized on (t-vax_imm_lag) days ago
# - increase people_immd by cases on (t-case_incub_pd) days ago
# - decrease people_immd by cases that happened more than case_imty_pd*30 days ago
# - don't do anything with deaths because not that many people have died in the grand schemevax_imm_lag = 14 # vaccinated people are immune starting X days after the fully vaccinated
case_incub_pd = 10 # days between people contract covid-19 and start being symptomatic
case_imty_pd = 4 # months after a person has covid, they can get it againstate_level_cvd_and_vax = []
for state, data in cvd_and_vax.groupby('state'):
tmp = data.copy()
tmp['new_daily_cases'] = tmp['cases'] - tmp['cases'].shift(1)
tmp['new_daily_deaths'] = tmp['deaths'] - tmp['deaths'].shift(1)
tmp['people_fully_vaccinated_%pop_immLagAgo'] = tmp['people_fully_vaccinated_%pop'].shift(vax_imm_lag)
tmp['new_daily_people_fully_vaccinated'] = tmp['people_fully_vaccinated'] - tmp['people_fully_vaccinated'].shift(1)tmp['people_immd'] = \
tmp['new_daily_cases'].shift(case_incub_pd) \
+ tmp['people_fully_vaccinated_%pop_immLagAgo'] \
- tmp['new_daily_cases'].shift(case_imty_pd*30)tmp['people_immd_%pop'] = tmp.apply(
lambda x: compute_fn(
a=x['people_immd'],
b=apply_dic(state_to_pop, x['state']),
fn=lambda a,b: a/b),
axis=1
)
state_level_cvd_and_vax.append(tmp)state_level_cvd_and_vax = pd.concat(state_level_cvd_and_vax, axis=0)
state_level_cvd_and_vax['new_daily_cases_%pop'] = state_level_cvd_and_vax.apply(
lambda x: compute_fn(
a=x['new_daily_cases'],
b=apply_dic(state_to_pop, x['state']),
fn=lambda a,b: a/b),
axis=1
)
state_level_cvd_and_vax['new_daily_deaths_%pop'] = state_level_cvd_and_vax.apply(
lambda x: compute_fn(
a=x['new_daily_deaths'],
b=apply_dic(state_to_pop, x['state']),
fn=lambda a,b: a/b),
axis=1
)# compute vulnerable population which is the (census "POP" - people_immd)
state_level_cvd_and_vax['vpop'] = state_level_cvd_and_vax.apply(
lambda x: compute_fn(
a=apply_dic(state_to_pop, x['state']),
b=x['people_immd'],
fn=lambda a,b: a-b),
axis=1
)state_level_cvd_and_vax['new_daily_cases_%vpop'] = state_level_cvd_and_vax.apply(
lambda x: compute_fn(
a=x['new_daily_cases'],
b=x['vpop'],
fn=lambda a,b: a/b),
axis=1
)
state_level_cvd_and_vax['new_daily_deaths_%vpop'] = state_level_cvd_and_vax.apply(
lambda x: compute_fn(
a=x['new_daily_deaths'],
b=apply_dic(state_to_pop, x['state']),
fn=lambda a,b: a/b),
axis=1
)
实际上,我们正在观察 14 天前对新冠肺炎病毒免疫的人口百分比与每日新增病例和每日新增死亡人数的对比。然而,我们没有用总人口来衡量新增病例和新增死亡,而是减去了完全接种疫苗的人群和过去 4 个月内患有 covid 的人群。所有州之间的比较如下图所示:
from scipy.optimize import curve_fit
from scipy.stats import linregress
def do_linregress(df, xcol, ycol):
linfn = lambda x,a,b: a*x+b
expdata = df.dropna(subset=[xcol, ycol], how='any').copy()
return linregress(
x=expdata[xcol],
y=expdata[ycol]
) ax1 = state_level_cvd_and_vax.plot.scatter(
x='people_fully_vaccinated_%pop_immLagAgo', y='new_daily_cases_%vpop', figsize=(16,7), s=2)cases_reg = do_linregress(
df=state_level_cvd_and_vax,
xcol='people_fully_vaccinated_%pop_immLagAgo',
ycol='new_daily_cases_%vpop'
)
plt.plot(
state_level_cvd_and_vax['people_fully_vaccinated_%pop_immLagAgo'],
state_level_cvd_and_vax['people_fully_vaccinated_%pop_immLagAgo']*cases_reg.slope+cases_reg.intercept,
'g--', label='linear fit: slope={}, intercept={}, r^2={}'.format(cases_reg.slope,cases_reg.intercept,math.pow(cases_reg.rvalue,2)))
ax1.legend(loc="upper right")ax1.set_ylim(0.,.00125)print('Assumption: immLag = {}: days after second vaccination for immunity'.format(vax_imm_lag))

截至 14 天前完全接种疫苗的人口百分比与非免疫人口中每日新发病例的流行率。(图片由作者提供)
我们看到有一个明显的下降趋势,表明随着各州接种疫苗越来越多,新冠肺炎的流行程度越来越低。让我们看看一些最好的疫苗接种者和最差的疫苗接种者。这是一个好消息,与我们的希望一致,疫苗正在发挥作用。让我们往下钻。这种方法的一个问题是,虽然总体趋势是负面的,但各国看到的是不同的现实。
人口密度高的州:领先的新泽西州(8)和康涅狄格州(5)对落后的哥伦比亚特区(-5)和佐治亚州(-1)
更密集的人口应该会看到更集中的影响,因为人们彼此接触得更多(乔什昆、耶尔德勒姆和冈杜兹,2021 )。在那项研究中,94%的传播可以用人口密度和风来解释。新泽西州和康涅狄格州由纽约市大都会区主导,而华盛顿特区是华盛顿特区,佐治亚州是亚特兰大。
康涅狄格州排名第五,24.1%的人口接种了全部疫苗。新泽西州排名第八,其 22.6%的人口接种了全部疫苗。我们看到康涅狄格州对新病例的疫苗有轻微的负面影响,我们注意到趋势的解释方差非常低。随着疫苗接种的增加,新泽西州的新病例实际上呈上升趋势。

康涅狄格州:截至 14 天前完全接种疫苗的人口百分比与非免疫人口中每日新发病例的患病率。(图片由作者提供)

新泽西州:截至 14 天前完全接种疫苗的人口百分比与非免疫人群中每日新发病例的患病率。(图片由作者提供)
佐治亚州是全国接种速度最慢的州,只有 14.1%的人口接种了全部疫苗。哥伦比亚特区是第五慢的,有 16.0%的人口完全接种了疫苗

格鲁吉亚:截至 14 天前完全接种疫苗的人口百分比与未免疫人口中每日新发病例的流行率。(图片由作者提供)

哥伦比亚特区:截至 14 天前完全接种疫苗的人口百分比与未免疫人口中每日新发病例的患病率。(图片由作者提供)
效果最明显的是乔治亚州,该州是全国最慢的全面接种者。这表明,除了疫苗之外,其他因素也是原因之一。
结论
在以这种方式检查了所有的州之后,看来疫苗的效果和它减少新病例的能力充其量是微弱的。没有清晰明显的效果可以看出来。对该国最好和最差的疫苗接种者的比较得出了一个令人困惑的结果。新病例的总体趋势似乎是负面的,然而,如果不是因为疫苗,那么这将只是政府出台的无数政策导致的暂时下降。随着这些政策的到期,我们可能会看到病毒的死灰复燃。我们解释了一些大的混淆,但更多的存在。我可以看到这将是人们的全职工作,以检查和跟踪各种数据收集,数据清理和建模问题可能存在于此。
基于强化学习的火车站非平凡电梯控制系统
原文:https://towardsdatascience.com/a-non-trivial-elevator-control-system-in-a-train-station-by-reinforcement-learning-f37e00137172?source=collection_archive---------11-----------------------
思想和理论
为什么火车站的电梯不同,RL 如何优化整体服务质量

中国宁波火车站站台上的电梯
动机
没有电梯,今天的城市生活是无法想象的,电梯控制器算法已经通过不同的技术进行了很好的研究,包括强化学习[1]。浏览参考文献给人的印象是,大多数研究都集中在安装在高层建筑中的电梯上,而对安装在火车站中的电梯几乎没有讨论。然而,火车站的电梯也值得关注,因为它们与建筑物中的系统有着明显的不同。
电梯-列车-车站系统通常具有以下特性:
- 不同列车线路的列车站台位于不同楼层。已经进入车站的人想要去一个特定的楼层乘火车,而已经乘火车到达的人将离开车站或者在另一个楼层换乘火车。
- 在高峰时间,不存在像大楼里那样每个人都去的一个方向。一些人可能想离开火车站,而另一些人可能想在另一层楼换车。
- 乘火车到达车站的人几乎同时在电梯前等候,而从车站外面来的人不一定属于这种情况。
- 电梯通常是为携带沉重行李或婴儿推车的人保留的,因此它们可能没有巨大的载客量。此外,那些有婴儿车的人可能没有第二个选择,只能呆在电梯等候名单上,直到被运送。
一个很好的例子是巴黎的里昂火车站,它有两个地下楼层,在这两个楼层上你可以分别找到两个不同的列车线站台。
从我个人的经验来看,带着我的婴儿车乘电梯从一楼到二楼换乘火车通常需要相当长的时间。
在下文中,我将模拟一个电梯-火车-车站环境,该环境可以很容易地根据您自己的目的进行修改和重用,并实现强化学习以获得电梯控制器的最佳策略。
电梯-火车站系统
考虑具有 3 层的火车站中的电梯,使得 0 层是作为入口/出口的底层,而 1、2、3 层是列车站台。在 0 层等电梯的人是从外面来的,愿意上楼去乘火车,而其他楼层的人是由预定的火车带来的,要么出站,要么去另一个楼层换换口味。我们假设人们可以在任何时候从外面到达 0 层,而人们同时在火车上到达正楼层。
为了简单起见,我们首先考虑一部单独的电梯。这种简化实际上并没有消除太多的一般性,因为在列车站台上总是只有一部电梯可用。
正三层是不同铁路线的列车站台:1 层 A 线,2 层 B 线,3 层 C 线。每 10 分钟,A 线第一分钟到达,B 线第二分钟到达,C 线第三分钟到达。另外,每一趟列车到站,都会有 5 个人一起加入电梯的等候名单。这是有道理的,因为一般来说,只有那些带着行李或婴儿车的人想乘电梯,而其他人会选择这种耗时的选择。对于每个乘火车到达的人,他将有{0.2,0.2,0.6}的概率分别去另外两层和底层。同时,我们假设每 30 秒,在每 10 分钟的前 3 分钟,有 0.9 的概率有一个人将加入 0 楼的等候名单。对于一楼的每一个人,他将有 1/3 的概率去地下三层的每一层。
这部电梯的最大载客量是 5 人。看起来容量很小,但是请记住,他们也有自己的行李!此外,电梯每次停止需要 10 秒钟,从一层到另一层需要 2 秒钟。
首先,我们有:
- 一层,三层。
- 电梯等候名单中的三组 5 名预定人员和一组非自发人员。
- 载客量为 5 人的电梯。
图吹是系统的草图(忘了我画的不好吧,我从幼儿园就没什么进步)。

作者图片:电梯火车站系统插图
构建 RL 环境
在继续下一步之前,我在这一节的开始给出了强化学习的一些必要元素。
简而言之,在 RL 中,主体以离散时间或连续时间与环境交互。在时间步骤中,代理根据环境的当前状态根据特定策略应用动作,导致新的状态并接收测量状态转换质量的奖励。RL 的目标是学习一个策略,或者是确定性的,或者是概率性的,以最大化累积回报。
让我们回到电梯控制器系统。
环境状态是 R⁷向量(楼层 _ 0 _ 上,楼层 _ 1 _ 上,…,楼层 3 下,占用,位置),其中 floor_i^{up/down}是 1 或 0,是 1。如果需要在电梯外的楼层 I 上升/下降,占用是电梯内乘客总数的整数,并且定位电梯所在的当前楼层。请注意,我们只允许在 0 层上行,在 3 层下行。
功能的报酬定义为-(占有率+总和 _i floor_i^{up/down}),即电梯内外的需求总数。换句话说,奖励为 0 的唯一情况是没有乘客在系统中等待,无论是在电梯内部还是外部。
为了构建 RL 环境,我使用了 open AI Gym,这是一个用于开发和比较强化学习算法的工具包。如何构建一个定制的健身房环境不是本文的目的,读者可以在 want [2]中找到关于他们自己的 RL 环境的说明。下面是电梯类的 init 和 reset 函数。
import gym
from gym import spaces
class Elevator(gym.Env):
metadata = {**'render.modes'**: [**'human'**]}
def __init__(self):
*#observation space
# states0: floor_0_up
# states1: floor_1_up
# states2: floor_1_down
# states3: floor_2_up
# states4: floor_2_down
# states5: floor_3_down
# states6: occupancy
# states7: position* super(Elevator, self).__init__()
self.done = 0
self.reward = 0
self.states = np.zeros(8)
self.states[0]=1
self.last_time = 0
self.time = 0
self.max_occupancy = 5
self.action_space = spaces.Discrete(3) *# 0 stop, 1 up, 2 down* self.observation_space = spaces.MultiDiscrete([2,2,2,2,2,2,6,4])
def reset(self):
self.states = np.zeros(8)
*#suppose that there are already 2 people
# waiting on the first floor at the beginning of the session* self.states[0]=1
self.last_time = 0
self.time = 0
self.floor_0_waiting = 2
self.floor_0_waiting_list = [1,2]
self.floor_1_waiting = 0
self.floor_1_waiting_list = []
self.floor_2_waiting = 0
self.floor_2_waiting_list = []
self.floor_3_waiting = 0
self.floor_3_waiting_list = []
self.inside_list = []
self.done = 0
self.reward = 0
return self.states
对更多细节感兴趣的人可以在 Github 上获得本文的完整代码。
培训和结果
为了训练这个系统,我将使用 DQN 深度 Q 网络。注意,对于给定的初始状态和动作,RL 系统的总累积回报也称为 Q 值。理想的策略应该是最大化 Q 值的策略,Q 值通常是未知的,因此产生 Q 学习作为代理的“备忘单”[3]。DQN 旨在通过深度神经网络来逼近 Q 值。在我的实现中,我在稳定基线的帮助下构建了一个大小为 64 的两层 DQN,这是一组基于 OpenAI 基线的强化学习算法的改进实现。这个实现只需要 3 行代码:
elevator= Elevator()
elevator.reset()
model = DQN(**'MlpPolicy'**, elevator, verbose=0)
model.learn(total_timesteps=1e5)
在训练之前,我让电梯做随机动作,从训练开始到清空等候名单需要 800 多秒。而在 1e5 训练时间步骤之后,在我的本地试验中,电梯设法在 246 秒内清空了等候名单,也就是说,4 分钟而不是 10 多分钟(根据我的经验,我有时在火车站排队等候超过 10 分钟!).这突出了电梯控制器系统的显著改进。
结论
当然,我对系统做了许多简化,例如,火车上的人同时加入等待,当没有火车经过时,没有其他人会加入,但训练的结果仍然令人兴奋。此外,我认为系统中只有一部电梯,但在某些车站可能并非如此。作为下一步,值得在系统中增加更多的电梯,并考虑一个多代理 RL 系统来做进一步的优化。
参考
[1]徐苑·卢西恩·布索尼乌和罗伯特·巴布什卡,电梯控制的强化学习,2008 年。https://www . science direct . com/science/article/pii/s 1474667016392783
[2] Adam King,从头开始创建定制的健身房环境——一个股票市场的例子。https://towards data science . com/creating-a-custom-open ai-gym-environment-for-stock-trading-be 532 be 3910 e
[3]使用 Python 中的 OpenAI Gym 进行深度 Q 学习的实践介绍。https://www . analyticsvidhya . com/blog/2019/04/简介-deep-q-learning-python/
Rust 编程语言的简短介绍
原文:https://towardsdatascience.com/a-not-so-short-introduction-to-the-rust-programming-language-2e8542a06b76?source=collection_archive---------2-----------------------
从这里开始,快速学习一门快速、安全、现代的语言

图片来自维基共享资源
你最喜欢的编程语言是什么?
如果你的答案不是生锈,那么请阅读这篇文章。最后,你的答案可能会改变!
在这篇文章中,我将教你 Rust 编程的基础知识。足以让你开始并创建自己的程序。
在文章的最后,我会指导你一些非常好的深造方向。
您可以在 Rust 培训期间以小词典或查找文章的形式回到本文。
学习一门新的编程语言就像学习任何其他语言一样。最快的方法是尝试一下,在这种情况下,你不需要来自不同国家的朋友或飞机。你只需要你的新朋友 Rust 编译器。相信我,它会是一个真正的好朋友。
因此,请随意编写代码,尝试自己的例子,或者像阅读任何其他文章或书籍一样,简单地用一杯浓咖啡阅读这篇文章。
让我们开始吧…
目录
安装和第一个项目
变量
数据类型
∘ 数字
∘ 布尔值
∘ 字符串、 & str 和字符
集合
∘ 数组
∘ 元组
∘ 向量
∘ 哈希映射
函数
控制流和循环
∘ 条件
∘ 循环
Rust 已经存在,如果你想学习一门既安全又经得起未来考验的现代表演语言,Rust 是一个不错的选择。
Rust 是一种系统编程语言,运行速度极快,几乎可以防止所有的崩溃,并消除数据竞争。
尽管 Rust 被归类为系统编程语言,但你真的可以在 Rust 中构建任何东西。你只需要牺牲一些时间。作为回报,你得到的是安全和惊人的速度。
Rust 以难学而闻名,但我认为这实际上取决于最初的方法和心态。
你只需要在编码时有一点不同的想法——就像一个乡下人!
安装和第一个项目
Rust 的安装没有痛苦,这要感谢一个叫做 rustup 的小工具。
你可以按照这里的说明安装 Rust或者只是通过谷歌搜索。
当你安装了 Rust 和它神奇的软件包管理器——Cargo——之后,你就可以开始工作了。
假设您想要创建一个名为“rusty_cli”的项目。
在您的文件系统上找到一个您想要放置项目的位置。然后将自己“cd”到命令/终端中的位置。
当您在想要放置项目的文件夹中时,只需使用cargo new rusty_cli。
Cargo 将施展它的魔法,创建一个它理解的项目结构,包括一个名为src的文件夹,里面是一个名为main.rs的文件。
文件main.rs是程序的入口点。为了运行程序,你有几个不同的选择使用货物。
您可以使用cargo run在调试模式下运行主文件,或者使用cargo build 创建可执行文件。这个可执行文件将存储在target/debug中。
你不必使用 cargo 来编译和运行 Rust 程序,但它是一个非常友好的工具,我强烈推荐使用它。
当您准备好构建最终的可执行文件时,您可以使用命令cargo build --release对其进行编译和优化。该命令将在target/release而不是target/debug中创建一个可执行文件。
这些优化使 Rust 代码运行得更快,但编译时间上的损失很小。
变量
Rust 中的变量是使用let关键字定义的,默认情况下是不可变的。我们来举个例子。下面的代码将还没有编译。
如果你一直跟随,那么你会看到编译器抱怨类似“不能给不可变变量赋值两次”。
为了解决这个问题,我们可以采取以下措施:
注意,如果我们把关键字mut放在变量名的前面,那么变量就变得可变了。
另外,请注意 Rust 中的表达式是如何工作的。表达式是返回值的东西。如果你加上分号,你就抑制了这个表达式的结果,这在大多数情况下是你想要的。
当我们一会儿谈到函数时,这一点会更清楚。
数据类型
数据类型通常与算术运算密切相关,但我不会花太多篇幅来讨论这个问题,因为对数字的常见运算也适用于 Rust。
Rust 中的许多数据类型与其他语言共享。我们有整数类型,如i32或i64,也有浮点数类型,如f64。
我们还有数据类型bool,它可以包含值true或false *,*我们有string , *&str*和char用于存储文本数据,还有tuple,array,vector和hash map作为一些常见的集合。
在此之上,我们有structs 、 *methods* 和associated functions作为 OOP 语言中类和方法的替代,还有一个有趣的类型叫做trait,有点像接口,例如 Go 。
除了用于结构化相关数据的结构和元组结构,我们还有在 Rust 语言中起核心作用的类型enum。
其中一些类型的用法最好通过例子和自己的实验来学习,但是,我认为在这一点上一些最初的解释和例子是合适的。
数字
请注意,当您声明变量时,您可以选择通过在声明中显式声明来指定数据类型。
如果我们想存储一个包含大小为 8 位的无符号整数的变量,我们必须像下面这样做:
如果你刚刚写了let age = 18;,那么 Rust 会推断出年龄的类型是i32。
布尔运算
Rust 中称为“布尔”的布尔与其他语言中的布尔相似。语法是true和false(注意小写),一个例子是let b = true;。
字符串、字符串和字符
字符类型用单引号写成,如*‘c’*,表示数据类型的关键字是char。
Rust 中的字符串比 Python 中的要复杂一些,但这是因为 Python 中隐藏了很多细节。嗯,没有那么多铁锈!
这样做的原因是为了防止将来处理字符串时出现错误。Rust 中的一个常见概念是,该语言通过处理编译时可能出现的错误来确保安全性。无论如何,这是一件好事,但它对程序员提出了一些要求。
字符串被实现为字节的集合,当这些字节被解释为文本时,还有一些方法提供有用的功能。
字符串比许多程序员认为的更复杂。这是因为它们对程序员来说很自然——毕竟,我们现代人习惯于在日常生活中处理文本。
然而,由于我们认为有意义的子串和机器如何解释子串之间存在差异,事情并不像看起来那么简单。我们需要一种叫做编码的东西作为机器和大脑之间的桥梁。
我们不会深入编码世界的细节,但是如果你发现自己有一天晚上无法入睡,那么尽一切办法进行一次研究之旅,深入研究编码,它比你想象的更令人着迷!
Rust 在UTF-8中对字符串进行编码,与 Python 不同,我们可以让字符串在 Rust 中生长。
如上所述,Rust 有不止一种类型的字符串。类型String和类型str,后者通常以&str 、的形式出现,被称为字符串片或字符串文字。
一个String被存储为一个字节Vec<u8>的向量,并带有方便的方法:
我们将很快处理向量。现在,你可以把它们看作一个典型的数组。
这两种类型的字符串之间到底有什么区别,现在就跳过,但是我能说的是,如果你做一个如下的变量:
let s = "Towards Data Science";
那么 s 将是&str类型。如果你想将"Towards Data Science"存储为一个字符串类型,你可以
let s = "Towards Data Science".to_string();
或者相当于:
let s = String::from("Towards Data Science");
这两种类型的主要区别在于&str是不可变的,存储在堆栈上,而字符串类型可以是可变的,因此存储在堆上。
如果你不知道栈和堆,不要担心。了解它们最重要的一点是,访问和写入堆栈要比堆快得多。
在整个运行期间,存储在堆栈上的数据需要具有固定的大小。这意味着如果一个变量被允许增加大小,那么它需要被存储在堆中。
这两种类型也是相关的,正如名称 string slice 所表明的那样,&str是一个字符串类型的子串,不管这意味着什么(试着自己找出答案)。
由于这是一个简短的介绍,我们现在将离开这个主题和这个数据类型,但字符串的数据类型是一个丰富而令人兴奋的主题,我鼓励你在阅读完这篇文章后深入研究这个主题。
收集
在 Rust 中,我们有许多集合,但其中一些比另一些使用得更多。
排列
例如,Rust 中的数组就像 Go 中的数组。它的大小是固定的,因此可以存储在堆栈中,这意味着快速访问。
在数组中,一次只能存储一种数据类型。
语法类似于 Python 的 list:
let rust_array = [1, 2, 3];
您可以像在 Python 中一样访问特定的元素。rust_array[0]给了我们第一个元素,在这个例子中是 1 。
元组
tuple 类型通常在 Rust 中用于在一个集合中存储不同的数据类型。
我们可以用点符号来访问元素:
矢量
Vectors 是 Rust 中最常用的集合之一,因为就像 Python 的列表或 Go 的切片一样,Rust 中的 vector 的大小可以增长。
它只能保存一种数据类型,但是正如您稍后将看到的,有一些方法可以解决这个问题。不过,我们必须知道一种叫做enum的类型,才能开始写这方面的内容。
正如你所想象的,向量可以增长的事实使它成为一个非常重要的类型。
要创建一个新的空向量,我们可以调用Vec::new函数:
let mut v: Vec<i32> = Vec::new();
一旦创建完成,我们现在就可以将元素放入其中。例如,v.push(1)将在v后追加 1,现在大小已经增大。
如果您想实例化包含元素的向量,我们有一个方便的宏:
let v = vec![1, 2, 3];
稍后我们会看到更多的宏。
从向量中获取元素有两种方法。在这种情况下,我们可以像在 Python 中那样用 v[i] 符号获取第 i 个元素。但是我们需要小心,向量实际上有足够的元素。
如果它有更少的元素,而我们试图访问一个不存在的元素,那么我们将在运行时得到一个错误!这很危险,所以 Rust 有另一种方法来访问 vector 中的元素。
我们像let second = v.get(1);一样访问它
现在second将属于Option<T>类型,我还没有介绍过,但是很快你就会知道这意味着什么,以及如何获取值。
我们也可以在 for 循环中迭代向量,但是因为我还没有讨论循环,所以我会向你展示语法。
哈希映射
哈希映射就像 Python 中的字典或 Go 中的映射,类型用HashMap<K, V>表示。它存储了类型为K的键到类型为V.的值的映射
要初始化和填充散列映射,我们可以执行以下操作:
insert方法通过一组键和值作为参数将数据推入散列映射。
如果您想访问哈希表中的数据,我们也有get方法。具体来说,
let a = articles.get(&String::from("Python Graph"));
将返回一个Option类型,我们可以从中获取值。符号&也将很快被涵盖。
当我们想通过一个键来更新哈希表,并且不确定它是否已经存在时,我们有几种选择。其中之一是方便的entry方法:
articles.entry(String::from("Rust")).or_insert("https://www.cantorsparadise.com/the-most-loved-programming-language-in-the-world-5220475fcc22");
如果这个键已经在散列映射中,那么我们将得到一个对它的可变引用,如果没有,那么我们将把参数中指定的数据插入到or_insert中。参考文献将在稍后解释。
功能
功能是 Rust 最重要的特征之一。
我们已经看到了起特殊作用的 main 函数,但是我们当然也能够创建其他函数。
语法很简单。下面是 Rust 中另一个函数的例子:
注意,我们需要告诉 Rust 函数接受哪种数据类型作为输入,以及它将输出哪种类型。这是一件好事,因为它可以防止许多错误。
关于 Rust 的另一个有趣的事情是,你不必通过一个return关键字显式地告诉 Rust 你返回了什么。如果函数中的最后一条语句没有尾随分号,那么这就是函数返回的内容。
这通常也适用于花括号中的代码块。很像 Scala。
在上面的例子中。函数plus_one返回x+1,其中 x 是函数作为参数接受的整数。
在 Rust 中,我们有一个return关键字,但它通常只在你想提前返回某个东西时使用。
控制流程和循环
控制流操作的语法通常最好通过自己做一些小练习来学习。
情况
看看下面的程序,并尝试修改它:
我们看到 Rust 中的注释是用双斜线或者多行注释的/* blah blah */来完成的。还要注意我们如何能够用关键字return提前返回一些东西。
if, else if, else的语法类似于 Go 的。布尔表达式周围不需要括号,这对可读性很好。
环
在 Rust 中,我们有几种不同的循环。
如果你想要一个无限循环,我们有loop,它当然应该在某个时候被打破。因此,Rust 还有一个方便的特性,使您能够打破特定的循环,而不仅仅是内部循环。
下面的例子是从《锈书》中借来的,我们都应该把它放在枕头下(或者在这个时代保存为书签)。
请注意,我们如何通过'label: loop语法标记循环,并通过稍后基于某些条件调用该标记来中断特定的循环。
我们还有一个 while 循环,使用起来非常直观:
接下来当然是 for 循环,其语法如下:
我们能够在迭代器上循环,你是否必须让你的数据类型成为迭代器当然取决于类型本身。注意,这种语法很像 Python 中的语法,只是在 Python 中很少需要改变类型。
所有权和借款
Rust 真正区别于其他语言的一个特征是它处理内存的聪明的所有权系统。
你看,不同的编程语言以不同的方式处理内存。在一些语言中,你必须自己分配和释放内存,这使得你的代码很快,并给你低级别的控制。可以说你“离金属更近了”。这方面的一个例子是 C 。
在其他语言中,你有一个垃圾收集器,它可以确保你的安全并自动清理内存。这既方便又安全,但不是免费的。它会减慢程序的速度。这方面的例子包括 Python 、 Java 和 Go 以及许多其他的。
Rust 采取了一种完全不同的内存管理方法。Rust 在一个被称为所有权的系统中结合了安全性和速度。
正如铁锈书所说:
因为所有权对于许多程序员来说是一个新概念,所以确实需要一些时间来适应。好消息是,你对 Rust 和所有权系统的规则越有经验,你就越能自然地开发出安全高效的代码。坚持下去!
——锈书。
首先,让我们陈述所有权的规则:
- Rust 中的每个值都有一个变量,称为它的所有者。
- 一次只能有一个所有者。
- 当所有者超出范围时,该值将被丢弃。
有意思…是什么意思?
考虑以下代码:
这实际上将而不是编译。为了理解这一点,让我们从所有权的角度来看。
首先,变量s1通过取得值String::from("Hi")的所有权而进入范围。然后变量s2获得该值的所有权,我们从所有权规则中知道,只能有一个所有者。
这意味着变量s1不再有效。在《铁锈》中,我们谈到了“一个被移动的价值”。所以真正发生的是所有权或价值被转移到了s2,因此在那之后我们无法访问s1。
如果s1和s2是例如i32,那么这就不会发生,因为它们的值会被复制。这与 Rust 如何存储不同的值有关。如果一个值存储在堆上,那么这些规则适用,但是如果它存储在栈上,因此实现了Copy特征,那么将会发生一个简单的值拷贝。
让我们看另一个例子,在这里我们将看到函数也可以获得所有权。
下面的例子也是来自铁锈书。
你可以通过查看评论清楚地看到发生了什么。当一个变量作为参数传递给一个函数时,该变量的所有权被转移到该函数,并且该变量在当前范围内变得不可访问。
另外,请注意,如果存储在堆上的变量(例如字符串或向量)超出范围,那么只有在所有权在此之前没有移动的情况下,才会释放内存。
在这一点上,我确信这看起来有点限制和麻烦,你甚至不能在不转移所有权的情况下打印出变量,从而使变量不可访问。
当然,有一个系统可以解决这个问题。
这个系统叫做借力。任何其他语言都有指针。Rust 有引用,这些引用与借用规则配合得很好。
考虑以下代码:
这实际上编译和运行没有任何问题。前缀被称为引用,当一个函数被赋予一个引用或者一个变量被赋予一个引用时,它们并不拥有它的所有权。
在上面的例子中,我们需要在println!宏中使用变量s1,因此我们不能让函数calculate_lenght获得所有权。这个函数只是借用了一个不可变的引用,这个引用的值被分配给了我们想要的s1。
我们也可以有可变的引用,但是有一些规则来管理这个特性,以避免诸如竞争条件等讨厌的问题。
引用的规则如下:
- 在任何给定的时间,你可以拥有或者一个可变引用或者任意数量的不可变引用。
- 参考必须始终有效。
记住这一点的方法是,它就像任何其他文件。一次将读权限分配给几个不同的人是没问题的,因为在这种情况下不会发生任何不好的事情。但是,如果您同时授予几个人对一个文件的写访问权限,可能会出现很多问题。
这就是当你在 Git 中遇到合并冲突时发生的事情,对吗?我们不应该在代码中出现这个问题,因为 Rust 不知道如何处理这个问题。因此,在任何给定时间最多只能有一个可变引用。
结构、枚举和方法
结构和枚举在很多方面都是 Rust 的核心构件。如果你来自面向对象的语言,你会有宾至如归的感觉。
当我们引入哈希映射时,我们创建了一个articles哈希映射来存储文章。然而,如果我们想保存更多关于它们的信息,比如出版商或长度(分钟)呢?
我们可以定制包含这种结构化信息的数据类型吗?嗯,是的。
看一看以下内容:
在文件的底部,我们创建了一个名为Article的结构。我们现在能够在一个容器中存储相关数据。链接、料盒和长度数据称为字段,我们可以用点符号来访问它们,稍后我们会看到。
让我们看看如何使用impl语法在结构上实现方法。
该程序的输出如下:
The article "The Most Loved Programming Language in the World" is about 4 minutes long and is published in Cantors's Paradise.Please go to https://www.cantorsparadise.com/the-most-loved-programming-language-in-the-world-5220475fcc22 to read it.The article "How to Give Your Python Code a Magic Touch" is about 6 minutes long and is published in Towards Data Science.Please go to https://towardsdatascience.com/how-to-give-your-python-code-a-magic-touch-c778eeb9ac57 to read it.
枚举很像结构,但是在枚举中,可以有给定数据类型的子类型,这非常有用。
请考虑对我们的代码进行以下更改:
这个程序的输出是:
The article "How to Give Your Python Code a Magic Touch" is about 6 minutes long and is published in Towards Data Science.Please go to https://towardsdatascience.com/how-to-give-your-python-code-a-magic-touch-c778eeb9ac57 to read it.Programming article coming up!The article "The Most Loved Programming Language in the World" is about 4 minutes long and is published in Cantors's Paradise.Please go to https://www.cantorsparadise.com/the-most-loved-programming-language-in-the-world-5220475fcc22 to read it.
这里介绍了几个新特性,同时也收集了一些旧特性。
首先,注意我们如何创建了一个包含两个变量的Story枚举:Mathematics和DataScience。这很方便,因为回想一下在上面的 vector 小节中,我们说过 vector 只能保存一种类型。嗯,我们已经创建了一个保存类型Story的向量,但是它有一些变体,这些变体不一定包含相同的类型。
DataScience和Mathematics都包含类型Article,但是如果我们愿意,我们也可以选择String和f64。
然后我们还引入了match控制流操作符,它在这种情况下接受一个 enum 并检查它的变量。如果找到匹配,我们就执行一些代码。
非常简单,但是非常强大。
回想一下,vectors 和 hash maps 上的 get-method 都返回了某种叫做Option的类型。
Option是一个有两个变体的枚举:Some和None。
Rust 迫使你以可控和安全的方式处理None值,不像其他语言。
注意,我们可以有嵌套的匹配子句。此代码的输出将与之前相同,但也是一行:
We have less than three elements...
这样,我们可以安全地处理丢失的值。
错误处理
Rust 需要像其他编程语言一样处理错误。没有不出错的软件。
但是在 Rust 中,我们有 enums 供我们使用,这意味着安全的错误处理!
有时候我们真的需要让程序崩溃。这听起来可能很奇怪,但是如果一个错误是不可恢复的和危险的,那么最好关闭它。
这可以通过panic!宏来完成。
panic!宏通过在关闭前清除内存来结束。这需要一点时间,这个行为是可以修改的。
大多数时候,我们实际上能够优雅地处理错误。这是通过Result枚举完成的。
我们还没有谈到泛型,所以这对你来说应该没什么意义。
只需将T替换为任何数据类型,将E替换为任何错误类型。
你现在不需要得到所有这些。但是我认为你已经抓住了要点。File::open返回一个Result枚举,它可能包含错误,也可能不包含错误。
可以用模式匹配来提取和处理。一旦你学会了闭包,你将有更多的选择。
试验
Rust 中的测试内置于语言本身的结构中。看看下面的片段:
您应该为您编写的每个文件添加一个测试模块。我们还没有讨论 Rust 中的模块,但是你已经明白了。
如果你运行cargo test,所有的测试都会自动运行。
在 Rust 中测试的巨大优势是极其有用的编译器。事实上,Rust 开发软件的最佳实践是使用测试驱动开发(TDD)。
这是因为编译器为您的问题提供了很好的解决方案。以至于它几乎可以帮你写代码。
看看这个小教程,明白我的意思:
高级概念:一般类型、特征、生存期、闭包和并发性
关于 Rust 还有很多需要学习的地方,但是如果你一直这么做,你肯定是在正确的轨道上。
这个标题中的特性是你接下来应该关注的,但我会从这里重新引导你,因为这只是一篇介绍性的文章,而不是一本成熟的书。
如果您还不是 Medium 的成员,但想要无限制地访问像这样的故事,您只需点击下面的:
https://kaspermuller.medium.com/membership
进一步阅读的资源:
锈书:
铁锈举例:
文档:
让我们生锈吧:
https://www.youtube.com/channel/UCSp-OaMpsO8K0KkOqyBl7_w
TDS 贡献者注意事项
原文:https://towardsdatascience.com/a-note-to-tds-contributors-d61779707a66?source=collection_archive---------26-----------------------
在假期期间,我们稍微放慢了脚步
对于 TDS 团队来说,2021 年是多事之秋,也是激动人心的一年。随着我们越来越接近终点线,我们将需要一些时间来充电和喘口气。虽然我们将在接下来的几周内继续发布新的帖子,但审查提交内容(来自现有和新作者)的周转时间可能会比通常轻松的速度更长。
无论如何,如果你想与我们分享你的新作品,尽管去做吧——只是要记住,我们可能需要更多的时间来审阅它(并回复你的疑问、问题和评论)。作为一种选择,我们也邀请你在 1 月 3 日之前坚持你的令人兴奋的新项目,那时我们将全力以赴,并渴望阅读你的草稿。
谢谢大家的理解!对于任何庆祝这个月的人,我们祝你节日快乐、安全、轻松。
我们迫不及待地想在 2022 年再次见到你,
TDS 团队

西蒙·因芬格在 Unsplash 上的照片
一种基于词包划分平均的文档嵌入新方法
原文:https://towardsdatascience.com/a-novel-approach-to-document-embedding-using-partition-averaging-on-bag-of-words-b07249d260f9?source=collection_archive---------34-----------------------
实践教程
如何获取向量嵌入的集合并对其进行平均,从而保持其流形结构的多意义主题性。

比阿特丽斯·佩雷斯·莫亚在 Unsplash 上的照片
这是“嵌入、集群和平均”系列的第三篇文章。在深入本教程之前,我建议先阅读前面两篇文章:使用 PyTorch 和 ResNeXt-WSL 从图片中提取丰富的嵌入特征和使用 UMAP 和 GMM 在嵌入空间中进行流形聚类。
在本教程中,我们将使用 ResNext-WSL 模型、UMAP 变换提供的稀疏主题表示、GMM 聚类模型从 COCO 图片中提取嵌入,并为图片集(单词包文档)生成嵌入表示。我们将展示为什么传统的平均技术对于由几个多主题对象组成的文档不太适用,并且我们将扩展分区平滑逆频率(P-SIF) 方法以适用于单词和文本之外的通用领域。
单词袋模型
单词袋模型将文档表示为对象(单词)的加权集合。每个文档都表示为一个词频矩阵,其中行是文档,列是可能值集(词汇表)中的单词,值是该单词在文档中出现的次数。
对于本教程,我们将假设文字就是图片,文档可以是它们的任意集合。为了方便起见,我们将使用 COCO 类别来定义文档,并使用词频来对应图片中该类别的注释数量。

COCO 范畴词袋模型的词频矩阵
如果我们对每行中的术语频率求和,我们会得到以下分布:

每个文档的词频总和

文件尺寸的分布
我们可以观察到,person 和 chair 是数据集中非常受欢迎的注释,但平均来说,每个文档(类别)由一百个单词(图片)组成,我们知道每个单词可能代表多个上下文。
单词加权平均
表示每个文档的简单方法是获取每张图片的嵌入向量,并基于词频进行加权平均。通过这样做,我们将在图片的相同嵌入空间中表示文档,这是一个方便的属性。然而,正如我们将在底部的比较部分看到的,对许多多主题单词进行平均,最终会得到所有文档的几乎相同的向量。很难保留单词中的原始信息,因为它们会相互补偿,从而导致扁平的信息量较少的向量。
术语频率-逆文档频率(tf-idf)平均
tf-idf 是一个统计量,它测量一个单词在它们的集合(语料库)中对一个文档有多重要。一个单词在文档中出现得越频繁,重要性就越低。很可能,罕见的单词将具有更高的权重。
这种技术对于文本数据非常有效,可以过滤掉常见的单词,如 the、a、an、is、at、on,并赋予关键字以重要性。当单词字典(所有可能图片的集合)不遵循语言分布时,这种技术不会给出很大的改进。
我们这种平均的主要问题不在于每个单词的权重,而在于代数运算(和/均值),它去除了向量的所有信息成分。

由 COCO 超级类别着色的 TF-IDF 文档矩阵的 PCA 3D 投影
我们可以看到,属于同一个超级类别的文档倾向于彼此靠近地聚集在一起,但是这种分离不是很明显。
分区 SIF 加权平均
我们介绍的新方法受到了 P-SIF 平均方法的启发。
关键的直觉是:
- 使用稀疏编码对“主题”中的所有“单词”进行聚类(论文作者称之为字典学习,但对我们来说,它们是流形聚类)。
- 针对每个题目,用平滑逆频做图片的加权平均。
- 连接每个主题中的平均向量。
- 去掉第一个主成分。

P-SIF 文档平均算法概述。图片作者。
让我们一步一步来。
主题聚类
原始论文通过字典学习算法使用稀疏编码,例如 K-SVD ,k-means 的一种推广,用于稀疏编码。类似于 PCA,K-SVD 将通过奇异值分解(SVD)学习单词的稀疏表示,并将每个单词表示为原子的线性组合。每个原子就像一个星团的质心。因此,该算法通过交替学习数据的稀疏编码和更新原子以更好地适应数据来工作。这就像在单个算法中优化 SVD 和 k-means。
在上一篇文章中,使用 UMAP 和 GMM 的嵌入空间中的流形聚类,我们已经讨论了那些线性投影和 k-means 在数据以流形结构排列的情况下的局限性。此外,截至今天,除了论文作者在相关 GitHub 库中提供的内容之外,我们找不到任何 K-SVD 算法的成熟实现。因此,我们用 UMAP 和 GMM 的组合代替了 K-SVD。
SIF 平均值
为了执行平滑逆频率(SIF ),我们首先需要计算每个单词出现在文档 p 中的概率。

p(单词)的分布,单词在文档中出现的概率
然后,我们可以计算作为平滑参数α的函数的 SIF 权重(我们已经使用了 0.001 的值)。
为了执行 SIF 文档平均,我们必须将文档中的每个单词乘以 SIF 权重和单词主题概率。现在,我们可以用组合权重对每个主题中的单词进行平均。
连接主题向量
在上一步中,我们为每个文档和主题生成了一个向量。串联只是将所有这些主题向量堆叠在一起。我们可以把连接向量看作是保存单词包中大部分原始信息的一种方式。只有属于特定主题的单词将对嵌入主题子空间中的平均或文档坐标有贡献。
在我们的教程中,我们嵌入了维数为 2048 和 40 的聚类向量。因此,每个文档现在都以 2048*40 = 81920 的尺寸表示。很高,是吧?
我们可以通过在平均之前减少单词的嵌入空间或者通过减少主题的数量来减少这个维度。这两个方面在之前的聚类步骤中已经被次优化了。我们可以,但不是强制性地,用缩减的 UMAP 空间(50 维)替换原始的单词嵌入空间。因此,我们可以获得大小为 50*40 = 2000 维的文档向量。
一般来说,我们可以应用任何降维变换,而不一定是聚类过程中使用的那个。重用用于聚类的相同 UMAP 空间的便利选择不应该限制许多可用的选项。聚类步骤的目的是发现主题并将单词分配给主题概率。
去掉第一个主成分
为了使 SIF 平均技术有效,并与其背后的理论数学相一致,我们需要去除公共话语向量。这个想法是,所有的单词都是根据一个取决于微话题(本地话语)的过程生成的。然而,所有的文档都将共享这个话语的一个组成部分,这个组成部分可以使用 SVD 删除。作为代理,我们因此可以使用 PCA 计算第一主分量,然后从平均和连接之后获得的文档嵌入矩阵中减去它。

重构误差去除文档向量的主分量,点表示第一分量
我们还可以观察到,通过保留剩余的 50 个组件,我们可以在不损失信息的情况下进一步降低文档向量的维数。

左边的图是原始空间中连接的文档向量的重构曲线,而右边的图是 UMAP 空间中的重构曲线。点代表第一个主成分。
我们还可以观察到,通过保留剩余的 50 个组件,我们可能已经进一步降低了文档向量的维数,而没有显著的信息损失。
结果比较
为了测试我们的结果,我们将计算每对文档之间的余弦相似度(在我们的例子中是 COCO 图片类别)。我们应该期望相似的文档,属于相同 COCO 超级类别的文档,与剩余的文档相比具有更高的相似性。
我们比较了 6 种配置:
- 一袋单词
- UMAP 空间中的词汇袋
- TF-IDF
- UMAP 空间中的 TF-IDF
- p-SIF
- UMAP 空间中的 p-SIF
我们可以绘制每个配置的相似性矩阵的热图:

相似性矩阵(单词袋)

相似性矩阵(UMAP 空间中的单词包)

相似性矩阵

相似性矩阵(UMAP 空间中的 TF-IDF)

相似矩阵

相似矩阵(UMAP 空间中的 P-SIF)
我们可以观察到,具有传统单词包和 TF-IDF 平均的 UMAP 变换导致完全误导的结果,其中所有文档以相似的表示(和相似的余弦距离)结束,并且可能在 UMAP 空间的区域中没有任何实际意义。TF-IDF 变换没有产生任何相关的差别。我们已经预料到这种技术对于非语言发行版来说效果不佳。我们最终可以看到,无论是在原始嵌入空间还是在 UMAP 空间,我们修正的 p-SIF 确实提供了更稀疏和更一致的结果。
为了更好地形象化它们的表现,让我们计算属于和不属于同一个超级类别的文档对之间的平均余弦相似度的比率。较高的比率对应于较好的表示。

每个超范畴中所有配对的余弦相似性之内和之外的平均比率。
我们可以观察到,p-SIF 在所有超级类别中都占主导地位,其中一些类别(如动物、电器、电子产品)的性能提升了 7 倍以上。通过对所有超级范畴的结果进行微平均,我们可以总结为一个单一的指标:平均余弦相似性内/外的总比率。

所有超级范畴中所有配对的余弦相似性之内和之外的平均比率。
我们的 p-SIF 被证实是在多上下文情况下用于文档嵌入平均的更好的技术。原始空间中的 p-SIF 和 UMAP 空间中的 p-SIF 之间的差异是极小的,但是允许我们将向量的大小减少大约 40 倍。
结论
在这篇文章中,我们提出了一个重新适应版本的分块平滑逆频率(p-SIF) 算法。我们已经用 UMAP + GMM 的组合代替了 K-SVD 字典学习步骤。我们认为后者是一种更适合嵌入向量的词袋模型的技术,这些向量由深度神经网络生成,并排列在高维空间的流形中。我们已经证明了保留平均到 COCO 超级分类文档中的原始图片的多个主题和上下文的有效性。这种新提出的技术可以用于测量文档之间的相似性,但是也可以用于在新的特征空间中生成平均嵌入向量,该新的特征空间被定制用于表示一般文档可能表示的多义主题。
阅读“嵌入、聚类和平均”系列的前两篇文章:
使用 PyTorch 和 ResNeXt-WSL 从 COCO 图片中提取丰富的嵌入特征。
使用 UMAP 和 GMM 在嵌入空间中进行流形聚类。
你可以在 https://github.com/gm-spacagna/docem 找到代码和笔记本。
原载于 2021 年 1 月 9 日【https://datasciencevademecum.com】。
一种将语音识别集成到认证系统中的新方法
原文:https://towardsdatascience.com/a-novel-approach-to-integrate-speech-recognition-into-authentication-systems-accc02103afe?source=collection_archive---------19-----------------------
人工智能应用
这个系列的最后一部分

马特·博茨福德从 Unsplash 拍摄的照片
在本系列的前两部分中,我们回顾了现有的认证系统和基于 EEG 的认证系统的局限性的部分。这一部分将深入研究基于语音的系统、相关工作及其局限性,并提出一个将自动语音识别用于身份验证系统的想法。
术语语音识别、语音识别和基于语音的身份验证系统将在本文中互换使用。
1.1 优势
与包括虹膜扫描、面部识别和指纹扫描在内的其他类型的身份认证相比,语音识别具有许多重要优势。首先,它通常用于手机认证,因为所有手机都配有麦克风。第二,集成到家用电器和汽车等其他设备中具有成本效益[19];第三,由于物联网设备的快速扩展,它对大多数消费者来说是方便和熟悉的。最后,它已经被证明在某些情况下非常准确[20]。
1.2 组件
语音认证系统中通常使用客户端应用程序和服务器。为了认证用户,客户端应用程序将捕获他们的声音并向服务器发出 API 请求。服务器分析音频并选择是否验证用户[21]。当用户加入一个系统时,除了他们的人口统计信息之外,他们必须提供他们的音频记录。背景噪声总是首先被消除,以确保训练过程不偏斜,因此总是首先进行语音活动检测(VAD)。Zhou 等人[22]利用 LTSD 方法将每个话语划分为重叠的帧,并根据该帧中语音活动的可能性为每个帧分配分数。将收集该概率,以便提取包含声音活动的所有区间。图 2 描绘了由通过记录形成的包络。然后,他们采用离散傅立叶变换提取梅尔频率倒谱系数(MFCC)作为特征,然后在高斯混合模型(GMM)中使用,以计算它们属于该模型的可能性。
通常,在说话人识别中为每个说话人训练一个 GMM。然后,对于每个输入信号,收集特征向量的列表,并且计算属于每个模型的向量的总概率。最后,其模型与输入最匹配的说话者将被选为答案[22]。”

图 2:图中的尖峰对应于用户说了一个单词[ 21 ]的峰值
1.3 限制
基于语音的身份验证系统中最典型的方法有以下两种。第一种是让一个人重复同一句话几次,然后建立一个由声纹范围组成的通用模板。缺点是声纹太广,准确率会不如单个密码或口令。第二种方法是用单个句子制作声纹,并将其用作声纹。甚至,在这种情况下,攻击者可以简单地捕获并窃取身份验证尝试,然后重放它以获得访问权。鉴于这些缺点,Shoup 等人[21]认为,虽然语音认证不能作为独立的认证模式,但作为双因素认证协议的一部分,它将是一种可接受的替代方案。另一个缺点是声纹对一个人来说是唯一的,并且不容易被修改;因此,保护声纹和声音模型至关重要。
因为基于语音的身份验证方法过于笼统,容易被窃取,并且难以更改。设置身份验证以区分用户并允许用户选择他们的密码标准是解决问题的一种方法。
让我们从建议的系统原型开始吧!
2.1 原型
拟议系统将包括两个阶段:
注册方法最初采用说话人识别 API 来捕获用户的声纹并产生相关特征,以便 API 可以在认证阶段识别和验证用户。然后,在系统的后端,用户需要为他们的语音密码(VoicePass)配置规则,并开发一个语音识别 API 来将用户的规则(音频)转换为文本。例如,规则可以包括语言、口令/密码短语中的字符数以及特定短语。所有规则设置输入都将在后端以某种方式被散列。密码将是灵活的,规则将是简单易记的,但 VoicePass 必须遵守只有用户知道的某些限制。为了使其更强大,更能抵御在线攻击,密码不能与上次相同。下图描述了该系统的原型。登录后,用户将被转到网站,表明她已被成功确认,或者她将被要求重新记录她的 VoicePass,因为她的话语不符合要求,或者系统没有将用户识别为设置 VoicePass 的人。用户尝试登录的次数将受到限制。



左图:建议的身份验证系统的注册流程,包括语音注册和设置 VoicePass 规则。右图:登录过程。(图片由作者提供)
2.2 示例
例如,考虑一个英语语音通行证,其中包含单词“Shanghai”和“Singapore ”,长度为 15 到 20 个字符;在这种情况下,即使系统根据第一步提取的特征验证了用户,他们仍然必须通过第二步;因此,在认证过程中,如果用户说“上海是一个拥有数百万人口的充满活力的城市,新加坡也是同样充满活力但人口较少”,她将被验证;相比之下,在核查过程中,任何不符合标准的声明都将被拒绝。例如,“尽管上海正下着倾盆大雨,但加拿大今天天气很好”将不会被验证。攻击者可能会捕获用户的话语并绕过第一阶段。如果不知道系统的密码规则,即使它们包括用户的最后一个密码,也不可能访问。此外,如果用户以普通话或西班牙语配置 VoicePass,不熟悉这些语言的攻击者将会发现更难危害系统。
2.3 优势
该系统的优点包括以下几点:1 .与复杂的密码短语相比,规则易于记忆,用户可以跨多个平台修改规则的一个元素(例如,在前面的示例中,将“新加坡”更改为“加拿大”),同时保持 VoicePass 的可记忆性。2.只要对手没有违反规则,它就能抵抗肩窥、暴力攻击、欺骗和字典攻击。3.它继承了本系列第 3 部分中讨论的基于语音的身份验证系统的优点。
2.4 制约因素
该系统受到以下限制:1 .说话人识别和语音识别 API 的准确性至关重要,因为系统非常依赖它们的性能。2.注册和验证可能需要一些时间,系统可能的延迟应该不会让用户不堪重负。不过,这可以通过改进部署过程来解决。3.尽管改变先前的语音传递选项会增加系统的安全性。然而,(自动语音识别系统)ASR 系统有许多缺点,因为它们容易受到在线和离线攻击[23]。
2.5 结论
万岁!迄今为止,我们已经取得了很大成就:)
我们研究了当前的身份验证方法,并深入比较了基于 EEG 和基于语音的系统,包括架构、采用的方法、安全性、可记忆性和可用性,以及方案的局限性。尽管这两种方法都有好处,但不能忽视其局限性;因此,额外的考虑是为了避免一些障碍,并可作为未来研究课题的建议。
感谢你花时间阅读我的博客。请留意更新,并随时在 Linkedin 上发表评论或联系我。
https://www.linkedin.com/in/fangyiyu/
第 2 部分后的参考资料:
[19] R. G. Zick 和 J. Olsen,“语音识别软件与 ED 中医生制图的传统转录服务”,《美国急诊医学杂志》,第 19 卷,第 4 期,第 295-298 页,2001 年。
[20] D. J. White、A. P. King 和 S. D. Duncan,“作为行为研究工具的语音识别技术,“行为研究方法、仪器、&计算机,第 34 卷,第 1 期,第 1–5 页,2002 年。
[21] A. Shoup,T. Talkar,J. Chen,A. Jain,语音认证方法综述与分析,2016。
[22] X. Zhou,Y. Wu,和 T. Li,“X. Zhou,Y. Wu,和 T. Li”,数字信号处理:说话人识别最终报告(完整版),【2012。
[23] H. Abdullah,K. Warren,V. Bindschaedler,N. Papernot 和 P. Traynor, Sok:我们的语音识别系统中的错误:对自动语音识别和说话人识别系统的攻击概述,2021 年 IEEE 安全和隐私研讨会(SP)。IEEE,2021 年,第 730–747 页。
卡格尔的新手之旅:成功与奋斗的故事
原文:https://towardsdatascience.com/a-novice-journey-in-kaggle-my-ups-and-downs-617bc129b401?source=collection_archive---------23-----------------------
查看一个非技术初学者通常在 Kaggle 中面临的斗争和挑战性经历,以及如何克服它们。

帕特里克·霍金斯在 Unsplash 上的照片
简介
并非所有的故事都是关于卡格尔的成功之旅。在这里,我想分享我自己的经历,成功,但主要是在 Kaggle 中的挣扎,希望像我这样的初学者知道挣扎,以及如何用勇气和毅力面对它。就像我相信的那样,
“如果你想跑得快,你可以自己跑。但如果你想跑得远,你需要和其他能支持你的人一起走。”

照片由 Unsplash 上的克里斯托弗辊拍摄
我加入了 M5 预测准确性与代数,统计和编程的基本知识。一开始,当知道其他竞争者在这些卡格尔比赛中表现得有多好时,我感到很害怕。但是,我鼓起勇气,努力完成这个项目。我的目的是了解端到端数据科学项目,以及有什么比加入 Kaggle 更好的方法。
一、掌握 Kaggle 特性
当你在竞争中工作时,你将被迫导航并掌握 Kaggle 的功能。以下是我学到的一些东西:
- 创建笔记本——ka ggle 提供了一个更加灵活的平台,我可以在这个平台上编写代码和撰写工作内容,而无需任何 HTML 知识。就这么简单。
- 笔记本版本 —每次您做出一些更改时,您所有的工作成果都会被保存,并且您可以查看您所做的所有更改。另外,你有你工作的全部历史,所以如果你想从过去检索一些东西,你可以只点击版本历史。
- 外部数据可以轻松上传和添加。
- 数据集和可视化是可下载的
- RAM 容量大 —比赛中的数据大多文件大小较大;运行和处理它们将需要巨大的 RAM 容量。幸运的是,Kaggle 拥有多达 16 个 RAM,因此可以轻松运行和处理大型数据集。
- 论坛 —我在论坛上获得了一些关于数据、分析和模型的最佳信息。很多人都在分享他们的见解和想法,并愿意向其他团队伸出援手。
从那以后,我开始适应在 Kaggle 和其他平台如 Google Collab 工作。
二。找到正确的方向很有挑战性

乔丹·罗兰在 Unsplash 上的照片
我所说的正确方向是指对案件的轮廓和我的预期产出有一个清晰的了解。我脑子里有我所有的输出,但是做工作来得到输出对我来说是个挑战。我知道这就像是一篇论文,但后来我意识到,我在解决一个不同的问题。独特的问题需要独特的解决方案。一种解决方案并不适合所有情况。
谢天谢地,我读了 Randy Lao 的 Medium 中的数据科学管道。这个管道对我来说是有用的,我也明白这一点,所以我遵循了它。以下是他的 Medium 帖子的摘录(https://Medium . com/breath-publication/life-of-data-data-science-is-ose Mn-f 453 E1 febc 10)
- 获取数据
- 擦除或清理数据
- 探索数据以识别重要的行为、趋势和见解。
- 为预测数据建模。
- 解释数据和结果。
三世。不要依赖别人的作品(发明自己)
我开始独立完成这个项目。刚开始还好,但在 EDA、机器学习之类的一些关键部分还是空白。我觉得我错过了什么。老实说,我研究了其他人的作品,以获得一些见解和灵感。这里有硬币的两面:
**好处:**因为 Kaggle 支持协作,所以检查他人的作品,做出一些反馈,并获得一些灵感是可以接受的。你可以获得一些有趣的见解和反馈,对你的项目有所帮助。
**坏消息:**对你在 Kaggle 看到的一切持保留态度。你可能会把自己封闭在他们所做的事情中,而不是发明自己的工作来解决问题。
我在这里的建议是查看论坛,从其他专业人士那里获得一些建议,并做一些研究。看别人的作品对我没有帮助;它只是阻碍了我的创造力。
四。每个问题都是独特的
仅仅因为这个模型或者 EDA 在其他项目中有效,并不意味着它在这里也有效(或者再次使用相同的模型是合适的)。我在 M5 艰难地学会了预测准确性。最初,我根据我在统计学方面的股票知识进行 EDA:相关性、统计汇总和基本图。
我意识到的一个事实是,每个问题都是独特的。我不应该像对待我过去的作品那样对待这个案子。在某个时候,我想不出还有什么可以给 EDA 的,就瘫痪了。
为了克服这一点,我休息了一会儿,并在日记中写下了围绕这个案例的想法(在我的案例中,是 M5 预测准确性的销售)。然后,我列出了所有我能想到的关于零售的问题,以及所有我想到的与之相关的问题。最终,我能够组织我的 EDA 并发现许多对销售数据的有趣见解——比我以前做的更好。
五、信息过载
当我在做 M5 预测时,我碰到了这些模型:ARIMA、零星需求、梯度推进、LightGBM 等。事实证明,理解这些模型背后的数学太难了——我求助于阅读这些模型在金融领域的应用。它使我能够很好地理解这些模型。

由格伦·卡斯滕斯-彼得斯在 Unsplash 上拍摄的照片
用复杂的模型构建机器学习并不容易。我在这方面的学习经验是不要给自己过多的信息。我必须专注于我能够理解和构建的模型和解决方案,并将其放在我能够进一步理解的环境中(就我而言,是金融)。
六。有一个导师是一个很大的帮助。
我很幸运有一个伟大的导师和一个在我的旅程中给予支持和建议的社区。
我需要对我不知道的事情的指导和建议,我需要对我的工作的评论和反馈,这样我就知道我需要改进的地方。所有这些,我都是从我的导师那里得到的。老实说,挑战是艰难的,我面临的所有这些障碍可能已经迫使我放弃,但我的导师们推动我去完成挑战——在整个比赛中给予指导和支持。
与专业人士或从业者一起工作让我比独自一人走得更快。
我最大的体会是:如果你想走得快,你可以自己走,但如果你想到达更远的地方,你应该和其他人一起工作。

照片由 NeONBRAND 在 Unsplash 上拍摄
最终注释
参加 Kaggle 比赛是一次艰难的旅程,需要耐心、勇气和努力。我了解了自己的优势和劣势,以及我可以进一步改进的地方,并设法从头到尾完成了 Kaggle 项目。即使我在决赛中没有取得好成绩,我也实现了 Kaggle 的目标,如果没有我的导师和社区的支持,我不可能做到这一点。我为此感谢他们,我将利用这次经历去做更多的项目,并在这个领域进一步发展自己。
谢谢你看完我的博文。我希望外面的初学者知道从事数据科学项目是一条艰难的道路。你必须有合适的资源和支持才能生存。从我的旅程中学习,祝你好运!
如果你想看我在 M5 预测准确性方面的工作,这里有链接: M5 预测—准确性(R) | Kaggle 。请随时给出您的意见和反馈!:)
单字符 MLflow 拉请求
原文:https://towardsdatascience.com/a-one-character-mlflow-pull-request-6d135437702d?source=collection_archive---------32-----------------------
上周,我受命为一个数据科学家团队编写一份关于最佳实践的文档,以协调使用 MLflow 的实验,这是一种跟踪数据科学实验参数和结果的工具。那时,我只使用了 MLflow 一天左右,所以任务主要是阅读文档和依靠我多年来在 Domino 数据实验室的经验,这是一个类似的专有数据科学平台。
我想引用的一个 MLflow 段落有一个小错别字:

:-\
不管出于什么原因,这个错别字让我想起了我和同事们的谈话,他们谈到为开源项目做贡献是多么的不容易。我记得我刚出道时的那种感觉。感觉对流行项目唯一“有价值”的贡献是发现革命性的变化,这最好留给“维护项目的专家”。
没有什么比这更偏离事实了。开源项目依靠个人的微小贡献而蓬勃发展,对于一个用心良苦的新人来说,没有什么改变是微不足道的。许多人的小额捐款使项目保持繁荣。欢迎大家参与。我决定使用 MLflow 错别字来演示一个众所周知的项目的量子变化,希望让我的同行更容易理解开源贡献。
变化来得很快,以这样的形式出现:

我打开了一个拉请求,礼貌地介绍自己是一个新的贡献者,并询问这种改变是否可以。有人指出,我需要遵循更多涉及提交的方向,我解决了这个问题。第二天,变更被批准并且被提交给 [master](https://github.com/mlflow/mlflow/blob/master/docs/source/tracking.rst#organizing-runs-in-experiments)。

不要害怕打开一个开源项目的拉请求。和我一起工作过的人,以及我自己,已经对大项目做了局部的改变,并且因为不确定是否会有回报而搁置它们。这个故事的寓意不是搜索阅读材料并开始修复错别字,而是尝试将你在当地的贡献提交回master。您可能必须修正一个测试或者符合注释约定,但是这个迭代过程是一个重要的开发人员体验的一部分,并且会使您成为一个更强的技术贡献者。
MLflow 把我一个字的改动合并成了一个自述。你提交给你最喜欢的项目的任何更实质性的改变都有很大的机会被合并,并有希望成为你未来更多贡献的开始。
瑞安·迪夫 是 Corvus 保险公司的数据科学家。他还是一名物理学家、Linux 黑客和一名糟糕的咖啡师。
制作完美数据科学简历的一站式商店
原文:https://towardsdatascience.com/a-one-stop-shop-for-crafting-your-perfect-data-science-resume-3532a45f54f5?source=collection_archive---------22-----------------------
建立坚如磐石的投资组合所需要知道的

克里斯蒂娜·戈塔迪的图片(来源:Unsplash——感谢克里斯蒂娜!❤)
在过去的几年里,当我申请研究生院和 IT &数据科学工作时,我有好几份简历。看着我的简历从一堆不连贯的、随意散布的要点演变成一份写得很好的文件,让我获得了多个工作机会,这很有趣,也很有启发。
在这篇文章中,我将谈论一份写得合适的数据科学求职简历应该是什么样子,雇主喜欢(和不喜欢)简历上的什么,以及如何增加你获得梦想中的工作机会。我还附上了一份清单,你可以在点击提交申请按钮之前查看一下。
注意:这一建议适用于希望获得第一份全职工作的应届毕业生、希望获得实习机会的学生,或者职业生涯早期的申请者(毕业后有 2-3 年工作经验)。此外,观点可能会有所不同——如果您有任何可能对您有用的其他建议,我很乐意听到您的反馈:)
概述
我能给那些想改善简历的人的最好的一句话建议是:
保持简单,但信息量大!
这正是我的意思——你的简历不应该太长(不超过 1 页),也不应该太模糊,也不应该太详细。写一篇过于详细的文章和一张没有多少内容的空白纸之间有一个甜蜜点。
概括地说,你应该在简历中包括的部分有:
- 专业(工作)经验(必选,第一)
- 教育(必修,第二)
- 奖项/出版物/会议讲座(可选,如有)
- 项目(关于何时包含此项目,请参见下一节)
- 技术技能(必填)
让我们一个一个地深入了解它们!
专业经验
职业经历(或工作经历)部分是简历中最相关的部分,它应该出现在文档的最顶端(在你的名字、LinkedIn 个人资料链接、电话号码、电子邮件地址之后)。
- 注意标题格式。首先是职位,然后是公司名称,然后是括号中的月份/年份,例如数据科学家,Flyber(2016 年 9 月—2018 年 8 月)。如果你为一家被收购的初创公司工作,建议同时提及两家公司,例如 Flyber(被 MegaFlyber 收购)。
- 在这个标题的正下方,加上你工作的城市/州/国家(如果是一个偏远的位置,只需加上你居住的地点)。
- 列出几个要点(最多 5-6 个)来概括你的成就。这些成绩应该是可操作的。例如,比较两者:“使用 scikit-learn 建立了一个预测和防止流失的逻辑回归模型。“vs .”研究、设计并开发了一种逻辑回归算法,该算法预测客户流失的准确率高达 85%,从而避免了每年 900 万美元的收入损失。
- 请注意,第二行更具可操作性,即它清楚地显示了项目影响。此外,技术方法( scikit-learn )甚至没有在第二行中提到,而在第一句的开头就提到了。重点不是展示你知道scikit-learn——每个人都可以复制粘贴最先进的代码,但重要的是对业务、客户或员工的影响。因此,避免以“使用 Python/R/SQL to …”开头的句子,而是提供可操作的语句。面试官更关心业务影响,而不是技术方法。
- 注: 影响可以用不同的方式衡量,不一定与收入挂钩。相反,它可以用客户体验(例如,2021 年正面评价数量增加 50%)、为员工或整个团队节约的(例如,每月 1000 小时)、内部流程改进(例如,与相邻团队更有效的沟通)等来表示。
- 如果你需要帮助衡量影响,请你信任的人帮助你写这一部分。第二双眼睛有助于提升你的成就。
- 使用一致的时态。我的推荐是不用提及人称代词的使用过去式,如进行常规 A/B 测试达到 XYZ;排查报告数据库中的数据异常等。
- 总是按时间倒序列出你的工作经历。
教育
教育部分应该总是在职业经历之后。这一部分应该简短,比第一部分短得多。
- 一般的指导原则是提及大学名称,然后是你获得的学位,然后是年份(不包括月份),例如:维尼拉大学,应用统计学硕士(2014–2016)。
- 我强烈建议用一个要点(不要超过这个)来概述你参加的一些课程、你从事的一个研究项目或你写的一篇论文,例如完成了时间序列分析、数据挖掘和中级 Python 的课程,并进行了一个研究项目:{project_name + impact}。
- 避免提及 MOOCs 和训练营。相信我,雇主并不在乎他们。唯一的例外是,如果你是一个职业转换者,你想强调你投入精力学习编程语言或数学/统计。
- 一个常见的问题是是否要提及你的 GPA 。这取决于你。如果低,肯定不做。如果它相当高,那就去做你喜欢的事情,但是注意雇主越来越不关心它,而他们更关心有形的经验,比如实习和可操作的结果。GPA 低或不太知名的学校的申请人仍然可以同样成功,不应该灰心丧气。只要确保你用有见地的信息来强化你的简历。
技术
一个常见的技术简历错误是列出一系列你非常熟悉的技术技能,有些熟悉,并且用过一两次。避免这个。只列出你擅长使用的技能,并回答关于这些技能的面试问题。
一个不好的例子:
- Python,R,SQL,NoSQL,Java,JavaScript,C++,C#,Visual Basic,Matlab,Octave,git,Hadoop,node.js,Tableau,Linux,Golang。
这种方法不会让你看起来很聪明,所以不要这样做。想一想——很难解释这种混乱,面试官不会真正知道你真正知道/不知道什么。
相反,一个更好的例子应该是:
- Python ( pandas,numpy,scikit-learn,seaborn )
- R ( dplyr,ggplot )
- 一种数据库系统
- (舞台上由人扮的)静态画面
- 熟练使用基本的 git 命令
这告诉面试官你熟悉最相关的 Python 库(这对大多数 DS 工作来说很重要),你也知道一些 R / SQL / Tableau,并且你可以使用 git 。你甚至可以更进一步,针对每个要点,提及一个你应用了这些技能的项目(如果你在网上,添加链接将是一个很好的奖励)。
此外,技术技能应该放在简历的最后。为什么?因为数据科学家应该强调整体影响,而不是工具。工具只是达到目的的手段,目的才是最终的影响。出于这个原因,技术技能当然是相关的,但不应该过分强调(参见上面的职业经历部分,了解我对提及技术技能的想法)。
其他相关章节
如果您碰巧有以下任何一种情况:
- 会议会谈
- 研究论文和出版物
- 奖项(竞赛、俱乐部等)
—在简历中提到它们也无妨。他们会很好地强化你的简历,让你从其他申请者中脱颖而出。如果你没有以上任何一项,那完全没问题,你不必担心。不是所有人都有时间和资源超越我们的教育和工作。但是如果你确实有这些,那就把它们包括进来。也要准备好谈论它们,因为你可能会被问到关于细节的问题。
但是我那些很棒的副业呢?
许多申请人都在考虑是否应该在简历中加入他们的个人项目。这是一个完全合理的问题,我会给出我的 2 美分。
如果你是一名职业转换者或正在寻找第一次或第二次实习的学生,强烈建议提及一两个你真正引以为豪的兼职项目。避开常见的项目,如使用 MNIST 数据集的数字识别、泰坦尼克号生存预测等。这会让你看起来没有创意。努力脱颖而出。想出一些更独特的东西,比如:
- 收集自己的数据集,例如抓取网站或将多个大型数据源合并在一起——没有多少人会这么做,展示良好的数据清理&管理技能看起来棒极了。
- 解决(或试图解决)一个更具挑战性的 Kaggle 问题,需要超越应用最先进的 ML 算法。
- **指标& KPI 设计。**这是一个经常被低估的数据科学领域。人们经常谈论#ML、#AI、#transformers,但设计良好的指标和重要的 KPI 是一个功能良好的厨房的首要任务。例如,您可以包含一个链接,该链接指向您构建的仪表板,在该仪表板中您实现了自己设计的指标。
- 包括一个到你的投资组合网站或 Github 简介的链接。列出项目而不引用源代码不是很有效。雇主喜欢从视觉上消化你的工作,拥有一个作品集也是缺乏相关工作经验的一个很好的代理(就我而言,尽管我缺乏行业工作经验,但在职业生涯早期拥有一个作品集帮助我获得了多个职位——我的面试官告诉我他们真的很喜欢我的博客)。建立一个强大的在线形象会让你从其他候选人中脱颖而出。
如果你有点经验丰富(例如,几个实习或一些全职经验),那么如果你开始列出你的项目,你可能会用尽空间。为了避免这一点,根本就不要提到项目。如果有一些空间,只选择 1 或 2 个你真正感到自豪的(并确保包括相关链接并提及影响)。
清单(点击提交前检查这些!)
- 没有拼写/语法错误。三重检查。
- 没有断开的链接。三重检查。
- 一个专业的电子邮件地址(避免使用化名,如star_wars_fan@gmail.com)。如果你的名字很普通,在别名后面加一两个数字就可以了。
- 没有照片或个人家庭住址。
- 量化的结果和成就。避免含糊地陈述成就,而不注重效果。详见职业经历。
- 工作经历应包括服务的月份/年份。对于教育,提及年份就足够了。
- 技术技能不应该看起来像一个洗衣单。提及你熟悉的库/包/环境,而不仅仅是 Python 或 SQL 。避免列举太多的技术技能。详见技术技能。
- 时态的一致性(例如,总是用过去式写)。
- 最多 1 页。
- 为标题加粗,使简历更具可读性。
- 最重要的是: 保持简洁且信息量大! 设身处地为读者着想,试着看看自己写的东西是否清晰有见地。向某人寻求反馈。
奖励— 如果你想要一份免费的简历模板,请给我发电子邮件(dinajankovic93@gmail.com)来领取你可以编辑和使用的免费模板!
写一份好的简历需要时间、努力和毅力。随着时间的推移,你的简历会不断发展,最终会比以前获得更多的线索,这是完全可以预料的。毕竟享受有趣的学习体验!看着一份你 5 年前用过的、可能再也不会用的简历,会有一些美好的乐趣:)
如果你喜欢这篇文章,并想在新文章出现时得到通知,你可以在这里关注我。如果你想在 LinkedIn 上联系,请随时联系!
数据采样方法管窥
原文:https://towardsdatascience.com/a-peek-at-data-sampling-methods-5d7199c8aab8?source=collection_archive---------20-----------------------
确保你从数据中得出有效的结论

国家癌症研究所在 Unsplash 上拍摄的照片
抽样偏差是现实世界中最常见的偏差类型之一。当用于训练模型的数据不能反映模型在生产时将接收的样本的分布时,就会出现这种情况。
[## 处理数据项目中不同类型的偏差
towardsdatascience.com](/tackling-different-types-of-bias-in-data-projects-29e326660639)
一般来说,每当我们从事机器学习项目时,对将在生产环境中观察到的数据中各种属性的真实比例进行正确的研究是至关重要的。
此外,当我们实际处理一个问题并且数据集非常大时,处理整个数据集通常是不实际的,也没有必要,除非您希望在处理转换和特征工程发生时等待数小时。
一个更有效的策略是,从你的数据中抽取一个足够有用的样本来学习有价值的见解,这个策略仍然允许你从你的结果中得出有效的结论。这种技术被称为数据采样。
什么是数据采样?
我们将来自较大人群的观察结果子集称为样本。然而,取样是指我们的研究将从中收集数据的观察组。因此,数据采样可以定义为从业者用来选择代表较大总体的观察值子集的技术。
通常,与数据打交道的人(即数据科学家、数据分析师等。)使用数据采样技术将大型数据集减少到更小、更易管理的数据量,而不牺牲其洞察力的准确性。
有两种主要的数据采样策略:
- 概率抽样涉及随机选择。数据中的所有观察值都有机会被选择,因此可以对整个群体进行强有力的统计推断。
- 非概率抽样不涉及随机选择。相反,它是基于方便或其他标准。因此,无论构建了多少个样本,一些观察值都没有机会被选中。
非概率抽样方法的一个主要缺陷是它们包括非代表性的样本,并且重要的观察值可能被排除在样本之外。因此,通常建议首先考虑概率抽样方法,这也是我在本文剩余部分只关注这种抽样方法的原因。
概率抽样方法
如前所述,我们通常在因为数据太大以及其他原因(如时间、成本等)而无法研究整个人群的情况下利用数据采样方法。).
在这个演示中,我们将使用我用 Python 创建的合成数据——参见下面的代码。
import numpy as np
import pandas as pd# create synthetic data
id = np.arange(0, 10).tolist()
distance = np.round(np.random.normal(loc=100, scale =5, size=len(id)), 2)# convert to pandas dataframe
data = {"id":id, "distance": distance}
df = pd.DataFrame(data=data)df

作者图片
简单随机抽样
最直接的数据采样方法是简单的随机采样。本质上,子集是由从一个更大的集合中完全随机选择的观察值构成的;每个观察值都有相同的机会从较大的集合中被选中。
# simple sampling example
simple_random_sample = df.sample(n=5, random_state=24)
simple_random_sample

作者图片
简单随机抽样极其简单,易于实现。另一方面,我们仍有可能在样本数据中引入偏差。例如,考虑一个事件,其中我们有一个带有不平衡标签的大型数据集。通过执行简单的随机抽样,我们可能会意外地无法捕捉到足够多的样本来代表少数群体——如果我们能捕捉到任何一个的话。
间隔抽样
间隔抽样是一种技术,它通过定期从较大的集合中选择观测值来创建子集。例如,我们可以决定从更大的集合中选择每 31 个观察值。
# interval sampling example
idx = np.arange(0, len(df), step=2)
interval_sample = df.iloc[idx]
interval_sample

作者图片
如果观察值是随机的,那么间隔抽样通常会比简单的随机抽样返回更好的样本。然而,如果在我们的数据中有周期性或重复的模式,那么间隔抽样是非常不合适的。
分层抽样
分层随机抽样将较大的数据集分成称为分层的组。从这些组中,我们随机选择我们想要创建新子集的观察值。从每个阶层中选择的例子的数量与阶层的大小成比例。
from sklearn.model_selection import StratifiedKFold# dividing the data into groups
df["strata"] = np.repeat([1, 2], len(df)/2).tolist()# instantiating stratified sampling
stratified = StratifiedKFold(n_splits=2)1q
for x, y in stratified.split(df, df["strata"]):
stratified_random_sample = df.iloc[x]stratified_random_sample

作者图片
这种抽样策略倾向于通过减少我们引入的偏倚来提高样本的代表性;在最坏的情况下,我们得到的样本质量不会比简单的随机抽样差。另一方面,定义地层可能是一项困难的任务,因为它需要对数据的属性有很好的了解。这也是目前最慢的方法。
巢式抽样法
当我们不知道如何定义数据的层次时,整群随机抽样是一个很好的选择。在决定了我们希望我们的数据具有的聚类数之后,我们将较大的集合分成这些较小的聚类,然后从它们当中随机选择以形成一个样本。
# cluster sampling example# removing the strata
df.drop("strata", axis=1, inplace=True)# Divide the units into 5 clusters of equal size
df['cluster_id'] = np.repeat([range(1,6)], len(df)/5)# Append the indexes from the clusters that meet the criteria
idx = []# add all observations with an even cluster_id to idx
for i in range(0, len(df)):
if df['cluster_id'].iloc[i] % 2 == 0:
idx.append(i)cluster_random_sample = df.iloc[idx]
cluster_random_sample

作者图片
整群抽样比其他概率抽样方法更节省时间和成本。但是,很难确保您的分类代表更大的集合,因此,与简单随机抽样等其他方法相比,它通常提供的统计确定性更低。
最后一个音符
在处理大型数据集时,数据采样是一种有效的技术。通过利用数据采样技术,我们可以对较大集合中较小的、更容易管理的子集进行采样,以执行我们的分析和建模,同时确保我们仍然可以从该子集得出有效的结论。在本文中,我们讨论了执行数据采样的两种主要方法,为什么从概率采样技术开始可能更好,并在 python 中实现了 4 种概率采样技术。
感谢您的阅读!
如果你喜欢这篇文章,请通过订阅我的**每周简讯与我联系。不要错过我写的关于人工智能、数据科学和自由职业的帖子。**
相关文章
** </7-common-gotchas-of-data-projects-62e8646552f2> [## 数据项目的 7 个常见问题
towardsdatascience.com](/7-common-gotchas-of-data-projects-62e8646552f2) **
粉红税探索性数据分析
原文:https://towardsdatascience.com/a-pink-tax-exploratory-data-analysis-94642f83d4c5?source=collection_archive---------16-----------------------
亚马逊上男女产品的购物比较

罗谢尔·布朗在 Unsplash 上的照片
为了纪念女性历史月,我想做一个与性别平等相关的探索性数据分析(EDA)项目。随着美国同工同酬日的到来,我立刻想到了粉红税。毕竟,没有什么比得到的报酬更少,而你的钱却花不完更让人愤怒的了,仅仅是因为你是一个女人。
什么是粉红税?
粉红税是销售给女性的产品比销售给男性的同等产品更贵的趋势。你有没有注意到粉红色的剃须刀要多花几分钱?还是说女性的除臭剂和男性的价格一样但是容器里的产品少?这是粉红税在起作用!如果你想更深入地了解粉红税,在维基百科上有自己的词条,这是一个很好的起点,在撰写本文时有 27 个参考文献。
根据《Bankrate.com》今年发表的一篇文章,以下是一些关于粉红税的最新事实:
- 粉红税每年花费女性 1351 美元。
- 粉红税从出生时就开始征收,因为除了颜色/营销之外,即使是同等的玩具,对女孩来说平均成本也更高。
- 衣服、个人护理产品和服务都要缴纳粉红税。
- 总的来说,女性为类似商品和服务支付的价格比男性平均高出 7%。
实验
我想亲眼看看在亚马逊上男性和女性商品的购物体验会有什么不同。女性是否面临着平均比男性更贵的产品选择?我开始为自己的小实验创建一些参数。
我决定把它限制在一套服装的范围内:t 恤、牛仔裤、袜子、内衣和运动鞋。这个想法是,一个男人和一个女人在亚马逊上买一整套衣服平均要花多少钱?我想强调的是,这并不是试图找到男女平等的产品,并对它们进行直接比较。相反,它是关于所呈现的整体购物选择。如果女性产品普遍更贵,那么从逻辑上来说,当男性和女性搜索相同的商品时,亚马逊上出现的产品对女性来说平均更贵。我选择亚马逊是因为它是一个非常受欢迎的购物网站,有很多产品。
我用添加了“男士”或“女士”的相同搜索词搜索每一件商品。以下是我做的搜索:
- “男士纯白 t 恤”和“女士纯白 t 恤”
- “男士粗斜纹棉布牛仔裤”和“女士粗斜纹棉布牛仔裤”
- “男士内衣”和“女士内衣”
- “男式水手袜”和“女式水手袜”
- “男士帆布鞋”和“女士帆布鞋”
我注销了我的亚马逊账户,在一个隐姓埋名的 Chrome 窗口中进行了所有这些搜索,希望不会受到我的购买或搜索历史的影响。但我猜在这个数字世界里,没有人能保证我所说的搜索是完全公正的。
我记下了每次搜索的前 25 个项目的价格,包括男性和女性(每个项目 50 英镑)。我想这大概是人们在做出购买决定前合理浏览的商品数量。我跳过了任何特殊的赞助或促销产品,主要是因为这造成了混乱的重复,因为这些产品仍然出现在列表的某个地方(在所有情况下,“赞助”只是将一个项目推到了列表的顶部,但它仍然出现在前 25 名中),我想要 25 个独特的产品。
我还注意保持单位的一致性。例如,袜子、t 恤和内衣往往是成包的。我将所有价格计算为单位成本(一件 t 恤、一条内裤和一双袜子)。我还擅自跳过了我认为不适合搜索的任何产品。例如,当我搜索牛仔布牛仔裤时,会出现一些看起来像牛仔布的打底裤的搜索结果。由于打底裤和粗斜纹棉布牛仔裤是完全不同的产品,我干脆跳过了它们。
结果呢
我使用 Tableau Public 创建了本文中的可视化效果。你可以在我的 Tableau 公众号上找到这些。首先,让我们来看看不分性别的各类商品的平均价格。

作者图片
平均来说,运动鞋是最贵的,一双袜子是最便宜的。我承认,我完全预料到这条牛仔裤会是最贵的。也许这是个人偏见,觉得找到一条真正合身的牛仔裤有多难。
让我们来看看按性别细分的物品平均价格。

作者图片
我们可以看到,就帆布鞋和内衣而言,男性产品的平均价格高于女性。男式帆布鞋的平均价格为 3.61 美元,比女式帆布鞋贵 8.6%。男士内衣比女士内衣贵 1.49 美元或 44%。
其他产品对女性来说比男性更贵。女式牛仔裤平均比男式牛仔裤贵 5.24 美元,涨幅为 15%。女性白色 t 恤的平均价格是男性的两倍多,增长了 112%。虽然袜子的实际成本差异最小,但普通女袜的价格仍然高出近 26%。
有趣的是,在这一点上出现的假设可能解释与粉红税无关的价格差异。如果材料的数量是价格差异的原因,我们预计女性产品在大多数情况下肯定会比男性产品便宜。那肯定不能解释我们在这里看到的牛仔裤、衬衫或袜子。也许有些差异可能与捆绑销售产品有关。比如,如果男士衬衫和袜子有更多的散装货,单位价格会更便宜(这是我在收集数据时特别注意到的而不是)。
好了,现在让我们进入实验的真正问题。对于一个男人和一个女人来说,买一套完整的衣服平均要花多少钱?

作者图片
女性购买所有商品的平均成本为 97.84 美元,比男性的总成本高出 6.23 美元和 6.8%。总平均增幅为 6.8%,这与粉红色税导致女性为产品和服务平均多支付约 7%的估计相符。我认为很有趣的是,我们的最终数字会如此接近真实的平均值,即使这可能完全是由于偶然。
结论
虽然这个 EDA 实验并不意味着是完美的、结论性的,或提出任何真正可行的建议,但采取一种实际操作的方法来比较男女产品价格是很有趣的。像任何好的探索性数据分析一样,这带来的问题比它回答的问题更多:
- 这种差异实际上是显著的还是随机的?如果我们将样本数量从 25 个增加到 100 个或 1000 个,会发生什么?
- 这种差异有多少是由于亚马逊算法造成的?在不同的日子结果会不同吗?
- 如果我们在其他受欢迎的零售网站如沃尔玛或塔吉特百货重复这个实验,我们会发现类似的结果吗?
- 如果我们看不同类型的物品,如个人护理品(肥皂、洗发水等),价格会有差异吗?)或娱乐项目(自行车、运动器材等。)?
- 比较理发、按摩或汽车维修等各种服务的成本的好方法是什么?
- 专注于比较更精确的产品等价物的实验会是什么样的?
如果你们中的任何人进行自己的实验来回答这些问题,我希望你能分享!只有通过解决粉红税,我们才能开始解决它,让每个人都能买得起产品。
在你走之前
美国女性同工同酬日是 2021 年 3 月 24 日,这一天女性最终与男性的收入持平。目前,女性的平均工资是男性的 0.82 美元。
让我们不要忘记美国其他的同酬日:
- 亚裔美国人和太平洋岛民女性——2021 年 3 月 9 日
- 母亲——2021 年 6 月 4 日
- 黑人女性——2021 年 8 月 3 日
- 美国土著妇女——2021 年 9 月 8 日
- 拉丁女性——2021 年 10 月 21 日
请访问aauw.org了解更多信息。AAUW 网站是可以找到同酬信息的地方。
一个强大、简单、有趣的 python 分析器
原文:https://towardsdatascience.com/a-powerful-easy-and-enjoyable-python-profiler-12b792bc91d6?source=collection_archive---------12-----------------------
使用 VizTracer 和 Perfetto 轻松浏览代码执行时间表
在为训练模型处理数据或试图提高推理速度时,我经常面临需要修复的缓慢代码。我尝试了大多数 python 分析器,我真的很喜欢 VizTracer ,因为它非常容易使用,而且非常强大,因为你可以在代码执行时间线上放大和缩小。
要使用它,您只需导入一个“追踪器”并使用启动、停止和保存方法,如下所示:

它将保存一个包含代码执行时间线的 profile.json 文件。然后,您必须运行该命令(安装 viztracer 时会安装 vizviewer)

使用 AWSD 键可以在代码执行时间线中进行缩放/导航,这非常简单快捷。你也可以用鼠标。下面的视频展示了如何浏览我们创建的 profile.json 的示例。它由 Perfetto (由谷歌制造)提供支持,经过优化,甚至可以处理巨大的跟踪文件(多个 GB)。
我用 W 放大,用 S 缩小,用 A/D 向左/右移动,你可以看到主函数(outer_function)在顶部,然后是它正下方的 inner_function,然后是 time.sleep 调用。通过点击这些矩形中的一个,你可以看到关于这个函数调用的更多细节(持续时间,开始/结束时间,等等。).
通过单击并按住,您可以选择代码执行时间线的一部分并获得摘要。你将得到最长的函数,它被调用了多少次,等等。
跟踪变量
您还可以使用 VizCounter 类跟踪变量(假设您正在调试)。例如,我们将投掷一枚硬币,并使用以下代码跟踪正面、反面的数量以及正面的比例:

它通过“vizviewer profile2.json”命令生成:

我只展示了 VizTracer 的一小部分特性。你可以跟踪变量,分析多重处理/多线程程序,函数的入口,等等。更多信息见 VizTracer 。作者也在中等https://gaogaotiantian.medium.com/
自动驾驶汽车数据融合的实用探索
原文:https://towardsdatascience.com/a-practical-dive-into-data-fusion-for-self-driving-cars-7af71949133d?source=collection_archive---------33-----------------------

在 Unsplash 上更聪明地生活的照片
什么是数据融合?
数据融合 ,在抽象的意义上,指的是以 智能 和 高效 的方式组合不同来源的信息,使得系统处理数据的性能优于只给出单一数据源的情况。
在本文中,我们将讨论数据融合如何以及为什么用于各种智能应用,特别是自动驾驶汽车。然后,我们将深入到一个关于自动驾驶汽车的 【稀疏】 数据融合的具体案例研究中,看看数据融合是如何在行动中使用的。
**数据融合的高级思想:**如果我有两个或更多的数据源,并且每个数据源都提供了 新奇 和 预测性 信息来帮助我为我的智能系统做出更好的预测或控制决策,那么我就可以组合这些数据源来提高我的系统的性能。

数据融合背后的主要思想:结合不同的数据源,做出更明智的预测或决策。图片来源:作者。
请注意,我们并不局限于仅组合两种类型的数据源:通常,我们可以跨任何不同的数据源执行数据融合,只要它们是相互引用/校准的。

数据融合可以概括为组合 N 个不同的数据源,只要这些数据源中的每一个都相互参照/校准。
数据融合可以用在哪些学科?
当然这不是一个详尽的列表,但数据融合在以下领域得到了应用:
- 信号处理(匹配滤波、卡尔曼滤波、状态空间控制)。
- 机器人(感知,视觉-惯性里程计(VIO),光束调整[1])。
- 机器学习(语义分割、对象检测和分类、嵌入)。
更一般地说,数据融合可以用于我们使用数据进行预测或决策的任何领域。
使用数据融合的示例领域有哪些?

阿兰·范在 Unsplash 上的照片
同样,这个列表并不详尽,但希望能描绘出数据融合的可能性图景:
- 无人驾驶汽车(下文将详细讨论!)
- 遥感:不同形式的传感器数据,如 RGB 和激光雷达可以融合在一起,用于自动陆地勘测等任务。
- 机器人操纵:基于视觉的数据,如 RGB 或立体,可以与来自操纵器和致动器的里程计数据融合,以提高机器人操纵任务的性能。
我们如何在智能应用中有效利用数据融合?
一些形式的数据融合可能比其他更有效。当使用数据融合作为任何利用数据做出 预测 或 决策 的智能系统的一部分时,需要考虑一些事项:
- 数据融合有哪些步骤可以进行 在线 ? 离线 可以执行哪些步骤?数据融合会导致显著的推理延迟吗?如果会,那么性能上的 X 因子改进值得这种额外的延迟吗?
- 多少在线计算能力(CPU,GPU 等。)我的数据融合管道的预处理和后处理需要吗?
- 多少额外的计算能力(CPU、GPU 等)。)来使用来自我的数据融合管道的数据执行推理?
- 需要多少额外的内存 (RAM)来处理和存储来自我的数据融合管道的数据?
- 如果我使用传感器进行数据融合(例如 RGB 摄像机、立体摄像机、激光雷达传感器、惯性测量单元(IMU)等)。),我的传感器之间是否需要任何额外的校准?
- 我的数据集有多*?给定其他数据集,预测一个数据集有多难,反之亦然?这越困难,你就能从融合这些不同来源的数据中提取越多的信息。***
这些问题可以帮助您权衡不同数据融合方法的利弊,并允许您设计数据融合设置以实现最佳系统性能。
自动驾驶汽车的数据融合

自动驾驶汽车数据融合的例子: RGB 像素和激光雷达点云的融合。图片来源:[2]。
现在我们已经介绍了数据融合,让我们考虑如何将其应用到自动驾驶汽车领域。
数据融合是自主车辆和机器人的感知、目标检测、语义分割和控制中至关重要的子程序。这些和其他需要智能的任务依赖于以有意义的方式组合数据源,使自动驾驶汽车能够尽快做出明智的预测和决策。
自动驾驶汽车的数据融合使用了哪些类型的数据源?
自动驾驶汽车的一些数据源包括:
- ****RGB 像素:这些是来自安装在无人驾驶汽车上的摄像头的红色、绿色和蓝色像素强度。
- ****立体点云:这些点云使用立体深度相机表示物体在空间中的(x,y,z)位置。这些点是通过使用一对立体摄像机估计点的深度来找到的。
- ****激光雷达点云:类似地,这些点云使用激光雷达传感器表示物体在空间中的(x,y,z)位置。通过计算从激光雷达激光扫描返回到激光雷达传感器的返回时间来找到这些点。
- ****里程计:里程计数据通常由惯性测量单元和/或加速度计产生。该数据包含汽车的运动学和动力学信息,如速度、加速度和 GPS 坐标。
这些数据源是如何组合的?
关于如何将上述数据源用于基于数据融合的自动驾驶汽车应用的一些示例包括:
- 里程计数据与点云数据进行定位*。***
- RGB 数据与里程计数据用于解决光束调整问题【1】。
- RGB 和点云数据创建一个 2D 密集图像带有四个通道 (R,G,B,D)——这通常被称为数字表面模型(DSM)。诸如对象检测和分类以及语义分割的任务可以利用这个 DSM。
- RGB 和点云数据创建一个 3D 稀疏点云,,其中每个点都有 (x,y,z,R,G,B) 数据。诸如对象检测和分类以及语义分割的任务可以利用这种具有 RGB 特征的点云。
现在,我们已经介绍了一些自动驾驶汽车数据融合的数据源和应用的示例,让我们更深入地研究自动驾驶汽车数据融合的案例:用于语义分割的激光雷达点云和 RGB 像素之间的稀疏数据融合。
案例研究:稀疏数据融合
GitHub 库
在本案例研究中,我们没有将 RGB 和深度信息融合到具有多个通道的密集 2D 阵列中,而是采用相反的方法,用来自相应的共同参考的 2D 像素的 RGB 值来扩充与深度信息相对应的现有点云*。***
下图说明了这个稀疏数据融合过程。

****稀疏数据融合:通过将点云返回的 (x,y,z) 坐标与对应的 (R,G,B) 空间同一共参照位置的信息串联起来,将 3D 点云数据与 2D RGB 图像数据进行融合。
为什么稀疏融合?
**对于每个智能系统来说,一个至关重要的问题是:为什么这很重要?一些提议的理由:
- 因为我们现在对一个 稀疏的 、3D 点云执行推断,而不是对一个 密集的 、2D 图像执行推断,所以我们不必对密集的、计算密集型的输入进行预测。虽然 GPU 和其他硬件加速技术已经能够显著加速图像上的密集卷积运算,但在大型图像上实时执行语义分割推理仍然是一个需要解决的重要问题。
- ***在 ***【密集融合】中,当我们将我们的点云(3D 点的点集)转换成深度图像(有时称为数字表面模型(DSM))时,我们固有地 丢失了关于这些激光雷达点云的精确 3D 结构的信息 。执行“ 【稀疏融合】 通过保留我们的数据的基于点的表示来保留这种精确的 3D 结构和信息。
请注意,我们承认这种“稀疏融合”方法的一个缺点是,我们没有利用所有的 RGB 像素。
问题陈述
有了要执行的融合任务类型的一些背景信息,我们现在准备正式定义我们的基于数据融合的语义分割任务。数学上:
**********
这里, N 指我们点云中的点数, D 指每个点的维数;在这种情况下, D = 6 (3 代表 x,y,z ,3 代表 R,G,B)。
概略地,这个基于数据融合的语义分割问题可以被可视化为:

这是基于自动驾驶数据融合的语义分段应用程序的数据融合管道的高级概述。
现在我们已经设置了数据融合问题,让我们介绍一下我们将在案例研究中使用的自动驾驶数据集。
奥迪自动驾驶数据集(A2D2)
为了测试这种数据融合方法,我们利用了奥迪自动驾驶数据集(A2D2) [2]。该数据集通过安装在作者汽车上的 校准的 深度和光学传感器,捕捉 RGB 像素和点云返回之间的直接映射。

来自 A2D2 数据集的示例样本。左:激光雷达场景的点云表示。中间:场景的 RGB 图像表示。右:场景的语义标签表示——注意,不同的颜色表示场景中物体的不同地面真实类别,例如车辆、道路、树木或交通信号。图像源[2]。
更重要的是,我们利用这个数据集,因为由于[2]作者的校准工作,像素和点云返回之间存在直接映射 T32。值得注意的是,我们执行数据融合的能力取决于这种校准。
执行数据融合
这种直接映射允许我们将点云返回与 RGB 特征连接起来,使得每个点云点不再仅仅表示为 p = (x,y,z) ,而是表示为 p = (x,y,z,R,G,B) ,其中 R,G,B 值取自与给定激光雷达点共同参考的像素。
为了执行这个数据融合操作,我们在 Python torch中定义了一个自定义的DataLoader 类,当使用__get_item__方法从数据集中检索项目时,该类连接了(x, y, z)和(R, G, B)特征。为了简洁起见,下面只提供了构造函数和采样方法,但是你可以在附录中找到完整的类,也可以在链接的 GitHub 库中找到:
你可以通过他们的校准文件在这里阅读更多关于 A2D2 的创造者是如何制作这张地图的。
学习架构:PointNet++
为了学习这个语义分割问题所需要的映射 f ,我们将使用 PointNet++ ,一个基于点集的深度卷积神经网络。然而,该网络不是在对应于 密集空间图像 的矩阵和张量上执行卷积,而是在点云的 点集空间 中执行高维点集卷积。****
下面,提供了[3]中提出的 PointNet++的架构。由于我们的任务集中于语义分割,我们将利用这种神经网络架构的基于分割的变体。

PointNet++架构。这种架构通过使用一组分层的点集卷积层改进了原始的点网架构[3]。图片来源:[3]。
稀疏数据融合在 PointNet++中的应用
对于这个数据融合任务,我们在每个点组合我们的空间 (x,y,z) 特征和我们的 (R,G,B) 特征,并使用这些连接的特征作为 PointNet++网络的输入。请注意, (R,G,B) 特征不以空间方式处理,即我们不计算像素值之间的“空间”相关性。
我们基于数据融合的语义分割系统如下图所示:

数据融合和语义分割管道,用于我们对自动驾驶汽车的稀疏数据融合案例研究。
为了训练网络,数据转换是离线执行的,以减少在线计算时间。然而,对于实时语义分割设置,该稀疏数据融合预处理步骤将需要实时或接近实时地执行。
实验设置和评估
为了测试该框架的有效性,我们评估了网络对每个激光雷达点云返回的语义标签进行正确分类的能力。具体而言,我们使用语义分割度量来测量该系统的分割性能,例如平均交集超过并集(mIoU) 和准确度度量,下面针对一系列点来定义,我们为这些点预测语义类别*,并且我们为这些点定义了*不同的类别:********
**类 c 😗* 的并集上的交集(IOU)

所有类的并的平均交集(mIOU):

所有类别的精确度:

我们评估了这种稀疏数据融合方法,用于:
- ****两个语义类:分割道路与非道路特征。
- ****六类:这包括按频率排列的“其他”、“道路”、“车辆”、“行人”、“道路/街道标志”、“车道”。请注意,“其他”的真正类别不是“其他”,它是我们在这个实验中聚合到单个“其他”类别中的其他类别之一。
- 55 个类:这将我们的语义分割问题扩展到一组更加多样化的语义类。
作为参考,下面提供了六类语义分割问题中每个主要类的相对比例:

“六类”语义分割问题中六个最常见类的类频率。图片来源:作者。
结果
下表给出了我们应用 PointNet++方法和稀疏数据融合技术的结果。请注意,随着我们减少地面等级的数量,我们的精确度和 mIoU 指标开始显著增加。

精确度和交集(IoU)指标的结果表。请注意以下缩写:wNLL:加权交叉熵,TL:迁移学习(增量迁移学习)。图片来源:作者。
局限性和未来工作
虽然这项工作证明了这个框架的初步可行性,但仍然有大量的额外研究可以扩展这个主题。
这项工作的一个建议延续旨在根据以下指标量化密集和稀疏数据融合之间的性能差异:
- 运行时性能
- 语义分割指标(如准确度、mIoU)
- 在线预处理和后处理时间
如果你有任何继续这项工作的想法,你想分享,请在下面留下回应!
回顾和总结

克里斯托弗·伯恩斯在 Unsplash 上拍摄的照片
在本文中,我们引入了 数据融合 的概念,作为通过 融合不同数据源 来提高智能系统性能的一种手段。我们讨论了一些使用数据融合的示例领域,特别关注数据融合在自动驾驶汽车上的应用。然后,我们深入研究了自动驾驶汽车的数据融合案例。
在案例研究中,我们讲述了为什么和如何进行数据融合,并讨论了我们为什么能够进行数据融合。然后,我们讨论了数据融合在一个示例语义分割系统中的作用,并通过这个案例研究总结了系统性能和未来的工作。
如果你想了解这个案例研究的更多信息,请查看我的 GitHub 知识库中关于 稀疏融合场景分割与 A2D2 的内容。
我希望你喜欢这篇文章,并感谢阅读:)请关注我更多关于强化学习、计算机视觉、编程和优化的文章!
感谢
感谢 A2D2 团队开源了他们的数据集,也感谢[3]的作者开源了 PointNet++神经网络架构。
参考
- 光束法平差——现代综合。视觉算法国际研讨会。施普林格,柏林,海德堡,1999。
- Geyer,Jakob 等人,《A2d2:奥迪自动驾驶数据集》arXiv 预印本 arXiv:2004.06320 (2020)。
- 郝、查尔斯·黎齐·易、苏·列奥尼达斯·吉巴斯。" PointNet++度量空间中点集的深度层次特征学习." arXiv 预印本 arXiv:1706.02413 (2017)。
附录:使用 PointNet++的 A2D2 数据融合数据集的 Python 类
Python 中 A/B 测试的实用指南
原文:https://towardsdatascience.com/a-practical-guide-to-a-b-tests-in-python-66666f5c3b02?source=collection_archive---------5-----------------------
实验和因果推理
数据科学家在实验前、实验中和实验后应遵循的最佳实践

照片由 niko photos 在 Unsplash 上拍摄
介绍
随机对照试验(又名。A/B 测试)是建立因果推断的黄金标准。RCT 严格控制随机化过程,并确保在推广治疗前在协变量间的平均分布。因此,我们可以将治疗组和对照组之间的平均差异归因于干预。
A/B 检验是有效的,只依赖温和的假设,最重要的假设是稳定单位治疗值假设,SUTVA 。它指出,治疗和控制单位不相互作用;否则,干扰会导致有偏差的估计。我最新的博客文章讨论了它的来源和主要技术的应对策略。
作为一名数据科学家,我很高兴看到业界越来越多地采用实验和因果推理。《哈佛商业评论》最近发表了一篇题为“为什么商学院需要教授实验”的文章,强调了融入实验思维的重要性。与之相关的是,他们在另一篇论文中讨论了“在线实验的惊人力量”(Kohavi 和 Thomke,2017)。
A/B 测试大致可以分为三个阶段。
阶段 1 预测试:运行功效分析以确定样本大小。
第二阶段测试:关注关键指标。注意突然下降。
第三阶段后测:分析数据并得出结论。
今天的帖子分享了每个阶段的一些最佳实践,并通过一个假设的案例研究详细介绍了 Python 中的代码实现。
业务场景
抖音开发了一种新的动物过滤器,并希望评估其对使用者的影响。他们对两个关键指标感兴趣:
1.过滤器如何影响用户参与度(例如,花在应用上的时间)?
2.过滤器如何影响用户留存率(如活跃)?
也有一些限制。首先,抖音事先不知道它的性能,更喜欢小规模的研究,尽量少接触。这是理想的方法,因为如果关键指标直线下降(例如,治疗组的对话率为零),他们可以立即结束测试。
第二,这是一个及时的紧急问题,抖音希望在两周内得到答复。幸运的是,抖音已经阅读了我之前关于用户干扰的帖子,并正确地解决了 SUTVA 假设违反的问题。
公司决定聘请一小群非常有才华的数据科学家,你是负责模型选择和研究设计的团队领导。在咨询了多个利益相关者之后,您提出了一个 A/B 测试,并建议了以下最佳实践。
第 1 阶段预测试:目标、指标和样本量
测试的目标是什么?
如何衡量成功?
我们应该运行多长时间?
作为第一步,我们希望阐明测试的目标,并将其反馈给团队。如前所述,该研究旨在测量推出过滤器后的用户参与度和保留度。
接下来,我们转向指标,并决定如何衡量成功。作为一个社交网络应用,我们采用花在应用上的时间来衡量用户参与度和两个布尔变量,指标 1 和指标 2 (如下所述),分别表明用户在 1 天和 7 天后是否活跃。
剩下的问题是:我们应该运行测试多长时间?一个常见的策略是,一旦我们观察到有统计学意义的结果(例如,一个小的 p 值),就停止实验。公认的数据科学家强烈反对 p-hacking,因为它会导致有偏见的结果( Kohavi 等人 2020 )。与此相关的是,当 p-hacking 导致误报时,Airbnb 也遇到了同样的问题(Airbnb 的实验)。
相反,我们应该进行功效分析,并根据三个参数决定最小样本量:
- **显著性水平,**也称为α或α:当假设为真时拒绝零假设的概率。通过拒绝一个真正的零假设,我们错误地声称有一个效果,而实际上没有效果。因此,它也被称为假阳性的概率。
- 统计功效:确实有效果时,正确识别效果的概率。功率= 1 — 第二类误差。
- 最小可检测效应,MDE :为了找到一个广泛认同的 MDE,我们的数据团队与项目经理坐下来,决定最小可接受差异为 0.1。换句话说,用标准差衡量的两组之间的差异需要至少为 0.1。否则,该版本将无法补偿所产生的业务成本(例如,工程师的时间、产品生命周期等)。).例如,如果一个新的设计仅仅带来 0.000001%的提升,那么它就没有任何意义,即使它在统计上是显著的。
以下是这三个参数与所需样本量之间的双向关系:
- 显著性水平降低→更大的样本量
- 统计功效增加→更大的样本量
- 最小可检测效应降低→更大的样本量
通常,我们将显著性水平设置为 5%(或 alpha = 5%),统计功效设置为 80%。因此,样本大小通过以下公式计算:

我自己的截图
其中:
- σ:样本方差。
- 𝛿:治疗组和对照组的差异(以百分比表示)。
为了获得样本方差( σ ),我们通常会运行一个 A/A 测试,该测试遵循与 A/B 测试相同的设计思路,只是对两组进行了相同的处理。
什么是 A/A 测试?
将用户分成两组,然后对两组分配相同的处理。
下面是用 Python 计算样本大小的代码。
from statsmodels.stats.power import TTestIndPower# parameters for power analysis # effect_size has to be positiveeffect = 0.1
alpha = 0.05
power = 0.8# perform power analysis
analysis = TTestIndPower()result = analysis.solve_power(effect, power = power,nobs1= None, ratio = 1.0, alpha = alpha)print('Sample Size: %.3f' % round(result))1571.000
我们需要 1571 个变量。至于我们应该运行多长时间的测试,这取决于应用程序收到多少流量。然后,我们将日流量平均分成这两个变量,等到收集到足够大的样本量(≥1571)。
如上所述,抖音是一个非常受欢迎的应用程序,拥有数百万的 dau。但是,我们专门针对试用新过滤器的用户。此外,最小接触法可能需要几天时间来为实验收集足够的观察数据。
最佳实践
- 了解实验的目标以及如何衡量成功。
- 运行 A/A 测试以估计指标的方差。看看我最近发表的关于如何用 Python 运行和解释 A/A 测试的文章。
- 运行功效分析以获得最小样本量。

埃尔卡里托在 Unsplash 上拍摄的照片
测试期间第 2 阶段:数据收集
我们推出测试并启动数据收集流程。在这里,我们模拟数据生成过程(DGP ),并人工创建遵循特定分布的变量。我们知道真实的参数,这在比较估计的治疗效果和真实的效果时很方便。换句话说,我们可以评估 A/B 测试的有效性,并检查它们在多大程度上导致无偏见的结果。
在我们的案例研究中,有五个变量需要模拟:
1\. userid2\. version3\. minutes of plays4\. user engagement after 1 day (metric_1)5\. user engagement after 7 days (metric_2)
#变量 1 和 2:用户标识和版本
我们有意创建 1600 个对照单位和 1749 个处理单位,以表示潜在的采样比率不匹配,SRM。
**# variable 1: userid** user_id_control = list(range(1,1601))# 1600 control
user_id_treatment = list(range(1601,3350))# 1749 treated**# variable 2: version** import numpy as np
control_status = [‘control’]*1600
treatment_status = [‘treatment’]*1749
#变量 3:播放时间
我们将变量 3(“上场时间”)模拟为正态分布,μ为 30 分钟,σ为 10。具体来说,对照组的平均值是 30 分钟,方差是 10。
概括地说,MDE 的效应参数计算为两组之间的差异除以标准偏差 (μ_1 — μ_2)/σ_squared = 0.1。根据公式,我们得到μ_2 = 31。方差也是 10。
# for control groupμ_1 = 30
σ_squared_1 = 10
np.random.seed(123)
minutes_control = np.random.normal(loc = μ_1, scale = σ_squared_1, size = 1600)# for treatment group, which increases the user engagement by
# according to the formula (μ_1 — μ_2)/σ_squared = 0.1, we obtain μ_2 = 31μ_2 = 31σ_squared_2 = 10np.random.seed(123)minutes_treat = np.random.normal(loc = μ_2, scale = σ_squared_2, size = 1749)
#变量 4:1 天后的用户参与度,metric_1
我们的模拟显示,在 1 天(metric_1)后,对照组有 30%的活跃(真)用户和 70%的不活跃(假)用户,而治疗组分别有 35%的活跃用户和 65%的不活跃用户。
Active_status = [True,False]# control
day_1_control = np.random.choice(Active_status, 1600, p=[0.3,0.7])# treatment
day_1_treatment = np.random.choice(Active_status, 1749, p=[0.35,0.65])
#变量 5:7 天后的用户参与度,metric_2
模拟数据显示,对照组的活跃用户率为 35%,而治疗组在 7 天后的活跃用户率为 25%。
# control
day_7_control = np.random.choice(Active_status, 1600, p=[0.35,0.65])# treatment
day_7_treatment = np.random.choice(Active_status, 1749, p=[0.25,0.75])
真实数据包含一个相反的模式:治疗组在短期内表现更好,但对照组在一周后回来并脱颖而出。
让我们检查一下 A/B 测试是否拾取了反向信号。
final_data.head()

我自己的截图
完整的模拟过程,请参考我的Github。
最佳实践
- 在目睹了一些初步的积极效果后,不要过早地结束你的 A/B 测试。
- 不要提前停车!
- 禁止 p-hacking!
- 相反,当达到最小样本量时就结束它。

拉扎·阿里在 Unsplash 上的照片
阶段 3 后测:数据分析
收集到足够的数据后,我们进入实验的最后一个阶段,即数据分析。作为第一步,检查每个变体中有多少用户是有益的。
# calculate the number of users in each version
final_data.groupby('version')['user_id'].count()

我自己的截图
这似乎是一个可疑的变异分裂:1600 个控制单位,但 1749 个治疗单位。治疗分配过程从表面上看是可疑的,因为分配给治疗的用户比控制组多。
为了正式检查 SRM,我们在治疗组和对照组的实际分割和预期分割之间进行卡方检验(科哈维等人 2020 )。
from scipy.stats import chisquare
chisquare([1600,1749],f_exp = [1675,1675])Power_divergenceResult(statistic=6.627462686567164, pvalue=0.010041820594939122)
我们将 alpha 级别设置为 0.001 来测试 SRM。由于 p 值为 0.01,我们无法拒绝零假设,并得出没有 SRM 证据的结论。与我们的直觉相反,统计测试得出的结论是,治疗任务按预期进行。
画出每组上场时间的分布图
由于变量 minutes_play 是一个浮点数,我们必须在分组前将其四舍五入到最接近的整数。
%matplotlib inlinefinal_data[‘minutes_play_integers’] = round(final_data[‘minutes_play’])plot_df = final_data.groupby(‘minutes_play_integers’)[‘user_id’].count()# Plot the distribution of players that played 0 to 50 minutes
ax = plot_df.head(n=50).plot(x=”minutes_play_integers”, y=”user_id”, kind=”hist”)ax.set_xlabel(“Duration of Video Played in Minutes”)ax.set_ylabel(“User Count”)

我自己的截图
指标 1:a b 组的 1 天保留时间
# 1-day retention
final_data[‘day_1_active’].mean()
0.3248730964467005
一天之后,总体活跃用户率平均徘徊在 32.5%左右。
# 1-day retention by group
final_data.groupby(‘version’)[‘day_1_active’].mean()

我自己的截图
仔细一看,对照组有 29.7%的活跃用户,治疗组有 35%。
自然,我们对以下问题感兴趣:
治疗组较高的保留率是否具有统计学意义?
它的可变性是什么?
如果我们重复这个过程 10,000 次,我们至少观察到极值的频率是多少?
Bootstrap 可以回答这些问题。这是一种重采样策略,用替换数据重复采样原始数据。根据中心极限定理,重采样的分布意味着近似正态分布(查看我在 Bootstrap 上的其他帖子,在 R 或者 Python )。
# solution: bootstrap
boot_means = []# run the simulation for 10k times
for i in range(10000):#set frac=1 → sample all rows
boot_sample = final_data.sample(frac=1,replace=True).groupby (‘version’) [‘day_1_active’].mean() boot_means.append(boot_sample)# a Pandas DataFrame
boot_means = pd.DataFrame(boot_means)# kernel density estimate
boot_means.plot(kind = ‘kde’)

我自己的截图
# create a new column, diff, which is the difference between the two variants, scaled by the control groupboot_means[‘diff’]=(boot_means[‘treatment’] — boot_means[‘control’]) /boot_means[‘control’]*100boot_means['diff']

我自己的截图
# plot the bootstrap sample difference
ax = boot_means[‘diff’].plot(kind = ‘kde’)
ax.set_xlabel(“% diff in means”)

我自己的截图
boot_means[boot_means[‘diff’] > 0]# p value
p = (boot_means[‘diff’] >0).sum()/len(boot_means)
p
0.9996
在引导 10,000 次后,该治疗在 99.96%的时间内具有更高的 1 天保留率。
厉害!
测试结果与我们最初的模拟数据一致。
指标 7:a b 组的 7 天保留期
我们将同样的分析应用于 7 天指标。
boot_7d = []for i in range(10000):
boot_mean = final_data.sample(frac=1,replace=True).groupby(‘version’)[‘day_7_active’].mean() boot_7d.append(boot_mean)
boot_7d = pd.DataFrame(boot_7d)boot_7d[‘diff’] = (boot_7d[‘treatment’] — boot_7d[‘control’]) /boot_7d[‘control’] *100# Ploting the bootstrap % difference
ax = boot_7d['diff'].plot(kind = 'kde')
ax.set_xlabel("% diff in means")

我自己的截图
# Calculating the probability that 7-day retention is greater when the gate is at level 30p = (boot_7d['diff']>0).sum()/len(boot_7d)1-p
0.9983
在 7 天的指标上,控件显然具有更好的用户保持率 99.83%的时间,也与原始数据一致。
1 天和 7 天指标之间的反向模式支持了新奇效应,因为用户被新设计激活和激起了兴趣,而不是因为变化实际上提高了参与度。新奇效应在消费者端 A/B 测试中很受欢迎。
最佳实践
- SRM 是一个真正的问题。我们应用卡方检验对 SRM 进行正式测试。如果 p 值小于阈值(α = 0.001),随机化过程不会按预期进行。
- SRM 会引入使任何测试结果无效的选择偏差。
- 需要掌握三个基本的统计概念:SRM、卡方检验和 bootstrap。
- 比较短期和长期指标以评估新颖性效果。
完整的模拟过程请参考我的 Github 。
结论
A/B 测试需要广泛的统计知识和对细节的仔细关注。有成千上万种方法可以破坏你的测试结果,但只有一种方法可以正确地做到。遵循实验前、中、后描述的最佳实践,为实验的成功做好准备。
Medium 最近进化出了自己的 作家伙伴计划 ,支持像我这样的普通作家。如果你还不是订户,通过下面的链接注册,我会收到一部分会员费。
https://leihua-ye.medium.com/membership
进一步阅读
用曲奇猫测试手机游戏 A/B
喜欢读这本书吗?
请在 LinkedIn 和 Youtube 上找到我。
还有,看看我其他关于人工智能和机器学习的帖子。
对抗性鲁棒性实用指南
原文:https://towardsdatascience.com/a-practical-guide-to-adversarial-robustness-ef2087062bec?source=collection_archive---------34-----------------------
我们正在进入计算机系统威胁建模的新时代
简介 机器学习模型已被证明容易受到敌对攻击,这种攻击包括在测试期间添加到输入中的扰动,旨在欺骗模型,而这些扰动通常是人类察觉不到的。在这份文件中,我强调了几种产生对抗性例子的方法和评估对抗性鲁棒性的方法。
背景
下面是伊恩·古德费勒论文中的典型例子。
(解释和利用对立的例子 (ICLR 2015)伊恩·j·古德菲勒,黄邦贤·施伦斯,克里斯蒂安·塞格迪)
虽然对抗性机器学习仍然是一个非常年轻的领域(不到 10 年),但围绕攻击此类模型并找到其漏洞的论文和工作已经出现了爆炸式增长,变成了防御者和攻击者之间名副其实的军备竞赛。攻击者本质上占了上风,因为破坏东西比修理东西容易。与对抗性 ML 的一个很好的类比是 50 年代的密码学:研究人员不断尝试复杂的方法来保护系统,研究人员不断尝试破解它们,直到他们发明了一种复杂的算法,这种算法可能在计算上过于昂贵而无法破解(DES)。
为此,让我们尝试定义一个模型上的敌对样本是什么样子的。数学上,让我们假设我们有一个带有输入 x 的模型 f ,它可以产生一个预测 y. 然后,模型 f 和输入 x 的对立示例 d 可以定义为:
- f(x+d)!= y ,意味着加到 x 上的扰动 d 不会产生与 x 相同的预测
- L(d) < T ,其中 L 是测量 d 的范数的某个通用函数,其中 T 是该范数的某个上界。
基于上述参数,有一大类算法可用于产生这种扰动。大体上,它们可以用下图来划分。
基于(1)对模型的梯度访问和(2)用于生成样本的规范的不同对立示例的分类。这捕获了几乎所有的攻击,但绝不是一个详尽的列表(图片由作者制作)
我们对对手的威胁建模如下:
- **梯度访问:**梯度访问控制谁可以访问模型 f 和谁不可以。
白盒对手通常可以完全访问模型参数、架构、训练例程和训练超参数,并且通常是文献中使用的最强大的攻击。白盒攻击通常使用梯度信息来寻找对立的例子。
黑盒对手很少甚至没有访问模型参数的权限,模型被抽象为某种 API。黑盒攻击可以使用基于非梯度的优化方法发起,例如(1)遗传算法,(2)随机搜索和(3)进化策略。就计算资源而言,它们通常效率不高,但却是最现实的对手类别。 - **扰动界:**扰动界决定了扰动 d 的大小,通常用一些数学范数如 Lp 范数来度量。
**L0 范数:**L0 范数有界攻击通常涉及修改模型输入信号的一定数量的特征。L0 范数有界攻击通常非常真实,可以在真实世界的系统上发起。一个常见的例子是在停车标志上添加一个贴纸,可以迫使自动驾驶汽车不要减速——所有的背景都被保留下来,只有一小部分环境被修改。
L1 范数:L1 范数有界攻击涉及总扰动值的和的上限。这种攻击相当罕见。
L2 范数:L2 范数有界攻击涉及扰动的上限欧几里德距离/毕达哥拉斯距离d .由于 L2 范数在线性代数和几何中的数学相关性,L2 范数有界攻击被非常普遍地使用。
L_infinity 范数:L _ infinity 范数有界攻击涉及扰动,的最大值的上界,是最先被发现的攻击。在所有攻击中,无限攻击是研究最多的,因为它们在鲁棒性优化中的简单性和数学便利性。
在非常高的层次上,如果我们使用 Lp 范数作为鲁棒性度量,我们可以有 8 种不同类型的攻击(2 x 4)在下面突出显示。还有其他几种特定于域的方法来量化扰动 d 的幅度,但上述方法可以推广到所有输入类型。注意,下面引用的攻击严格针对图像,但是一般原理可以应用于任何模型 f.
按(1)梯度访问和攻击规范类型(作者制作的图像)分类的常见对抗示例的示例
结论:
随着机器学习模型越来越多地嵌入到我们周围的产品和服务中,它们的安全漏洞和威胁变得越来越重要。我们已经强调了对手可能对预先训练的模型发起敌对攻击的不同方法,但是随着我们找到更多的例子,我们将确保再写一篇文章并分享这些发现。
[1] Modas 等人, SparseFool:几个像素造成很大的不同 ,【CVPR】2019
【2】paper not 等人, ***针对机器学习的实用黑盒攻击,***ASIA CCS 2017
【3】Sharma 等人, ***EAD:对深度神经网络的弹性网攻击。***AAAI-2018
【4】卡里尼等, ***走向评估神经网络的鲁棒性,***IEEE Security&Privacy,2017
【5】马德瑞等, ***走向抗对抗性攻击的深度学习模型,***ICLR 2018
【6】古德费勒等, 解释与治理一种基于进化的针对神经网络的对抗性攻击, arxiv 预印本:
【8】Croce 等人, Sparse-RS:查询高效的稀疏黑盒对抗性攻击的通用框架, ECCV 关于真实世界中对抗性鲁棒性的第 20 次研讨会
【9】Alzantot 等人, GenAttack:具有梯度的实用黑盒攻击
使用 PyCaret 的 ARIMA 模型实用指南—第 3 部分
原文:https://towardsdatascience.com/a-practical-guide-to-arima-models-using-pycaret-part-3-823abb5359a7?source=collection_archive---------8-----------------------
理解差异术语

由塞德里克·韦舍在 Unsplash 拍摄的照片
📚介绍
在本系列的前一篇文章中,我们看到了趋势项对 ARIMA 模型输出的影响。本文将着眼于“差异”术语“d ”,并了解它是如何建模的以及它代表了什么。
📖建议的先前阅读
本系列以前的文章可以在下面找到。我建议读者在继续阅读本文之前先浏览一遍。本文建立在前几篇文章中描述的概念的基础上,并重用了其中的一些工作。
使用 PyCaret 的 ARIMA 模型实用指南—第 1 部分
使用 PyCaret 的 ARIMA 模型实用指南—第 2 部分
ARIMA 模型中的 1️⃣“差异-d”概述
在很高的层次上,差异意味着时间序列在任何给定时间点的值取决于前一时间点的值。差值“d = 1”意味着任何时间点的值取决于前一时间点(由等式 1 给出)。ε项表示无法建模的噪声项。

d=1 的 ARIMA 方程(图片由作者使用https://latex2png.com/)
**重要提示:**使用等式 1 生成时间序列的过程也称为“随机漫步”。大多数股票数据都遵循这种模式。如果你仔细观察,你会意识到当这被正确建模时,未来点的最佳预测与最后已知点相同。因此,使用 ARIMA 等传统方法的股票价格模型不会产生“有用”的模型。我们真的需要一个模型来告诉我们明天的股价会和今天的股价一样吗?
2️⃣️用 PyCaret 理解差项
👉步骤 1:设置 PyCaret 时间序列实验
为了更好地理解这个概念,我们将使用来自pycaret游乐场的随机行走数据集。详细内容可以在本文的 Jupyter 笔记本中找到(可在文章末尾找到)。
*#### Get data from data playground ----*
y = get_data("1", **folder="time_series/random_walk"**)exp = TimeSeriesExperiment()
exp.setup(data=y, seasonal_period=1, fh=30, session_id=42)exp.plot_model()

随机漫步数据集[图片由作者提供]
👉步骤 2:执行 EDA
诊断时间序列是否由随机游走过程生成的经典方法是查看 ACF 和 PACF 图。ACF 图将显示扩展的自相关性[1]。PACF 图应显示滞后= 1 时的峰值,且峰值大小应非常接近 1。所有其他的滞后都将是微不足道的。您可以将 PACF 幅度视为等式 1 中滞后值 y(t-1)的系数。我将在另一篇文章中详细介绍这一点。
exp.**plot_model(plot="acf")**
exp.**plot_model(plot="pacf")**

随机游走数据集 ACF 图[图片由作者提供]

随机游走数据集 PACF 图[图片由作者提供]
👉第三步:理论计算
对于随机游走模型,我们可以使用等式 1 来指导我们计算理论值。本质上,下一个时间点被预测为最后一个“已知”时间点。对于样本内预测(即,对训练数据集的预测),这将在每个时间点改变,因为 t = 1 时的最后已知点与 t=10 时的最后“已知”点不同(假设 t = 1 和 t = 10 都在样本内)。
对于样本外预测(即未知交叉验证/测试数据集中的预测),最佳未来预测将是最后一个已知数据点。不管我们对未来的预测有多远,这都是一样的。这是随机游走的样本内和样本外预测之间的一个重要区别。

理论样本内(训练)和样本外(测试)预测[图片由作者提供]
👉第四步:用 PyCaret 建立模型
**#### Random Walk Model (without trend) ----**
model3a = exp.create_model(
"arima",
**order=(0, 1, 0),**
seasonal_order=(0, 0, 0, 0),
trend="n"
)
👉第五步:分析结果
我们将重用我们在以前的文章中创建的相同的助手函数来分析结果。
**summarize_model**(model3a)

随机漫步模型统计摘要[图片由作者提供]
统计总结显示,创建的模型是一个SARIMAX(0,1,0)模型,它与我们希望用d=1构建模型的愿望相匹配。残差σ2(未解释的方差)是 0.9720,代表等式 1 中的epsilon项。
**get_residual_properties**(model3a)

模型残差[图片由作者提供]
查看模型残差,我们可以看到残差确实具有 0.9720 的方差,这与统计汇总相匹配。接下来,让我们绘制预测图,并与我们的理论框架进行比较。
**plot_predictions**(model3a)

样本外预测[图片由作者提供]

缩小样本预测[图片由作者提供]
样本外预测与我们的理论计算相符。即预测与最后已知的数据点(在这种情况下是点 309 处的值)相同。在pycaret中放大交互图的能力使分析结果变得容易,并对模型的工作获得更好的直觉。

样本内预测[图片由作者提供]

放大样本预测[图片由作者提供]
同样,我们也可以观察样本内预测。放大图显示,任何给定时间点的预测都与最后一个已知点相同。并且由于最后已知的数据点从一个时间点变化到下一个时间点,样本内预测也从一个点变化到下一个点。这也符合我们的理论计算。
👉第六步:检查模型是否合适
这也是引入“模型拟合”概念的好时机。检查模型的拟合度实质上意味着检查模型是否从时间序列中获取了所有“信息”。当模型残差不具有任何趋势、季节性或自相关性时,即残差是“白噪声”时,这是正确的。pycaret提供了一个非常方便的功能来检查模型是否合适。我们可以通过将模型传递给check_stats方法/函数来检查模型残差的白噪声特性,如下所示。
exp.**check_stats**(model3a, test="white_noise")

模型剩余白噪声测试[图片由作者提供]
第 4 行和第 5 行证实了残差确实是白噪声,因此模型很好地捕获了来自时间序列的信息。
🚀结论
希望这个简单的模型已经为我们理解 ARIMA 模型中“差项— d”的内部运作打下了良好的基础。在下一篇文章中,我们将看到如何将“差异”术语“d”与本系列上一篇文章中所学的“趋势”组件结合起来。在那之前,如果你愿意在我的社交渠道上与我联系(我经常发布关于时间序列分析的文章),你可以在下面找到我。暂时就这样了。预测快乐!
🔗领英
🐦推特
📘 GitHub
喜欢这篇文章吗?成为 中等会员 继续 无限制学习 。如果您使用下面的链接, ,我会收到您的一部分会员费,而不会对您产生额外的费用 。
https://ngupta13.medium.com/membership
📗资源
- Jupyter 笔记本 内含本文代码
📚参考
[1] 时间序列探索性分析|自相关函数
使用 PyCaret 的 ARIMA 模型实用指南—第 4 部分
原文:https://towardsdatascience.com/a-practical-guide-to-arima-models-using-pycaret-part-4-d595da232540?source=collection_archive---------13-----------------------
结合“趋势”和“差异”术语

马库斯·斯皮斯克在 Unsplash 上的照片
📚介绍
在本系列的前几篇文章中,我们分别看到了趋势项和差异项对 ARIMA 模型输出的影响。本文将着眼于这两个术语的组合效果以及它们是如何建模的。
📖建议的先前阅读
本系列以前的文章可以在下面找到。我建议读者在继续阅读本文之前先阅读这些内容。本文建立在前几篇文章中描述的概念的基础上,并重用了其中开发的框架。
使用 PyCaret 的 ARIMA 模型实用指南—第二部分(趋势术语)
使用 PyCaret 的 ARIMA 模型实用指南—第 3 部分(差异项)
1️⃣将“差异-d”项与趋势分量相结合
当开发具有趋势和差异项的 ARIMA 模型时,模型方程表示如下(对于 d = 1)。

带趋势项的 d=1 的 ARIMA 方程(图片由作者使用https://latex2png.com/)
读者会注意到,这是本系列前几篇文章中的差异和趋势术语的简单线性组合。和以前一样,用户可以选择指定如何对趋势进行建模。有 3 种方法可以对其建模— (1)仅使用截距项“a”,(2)仅使用漂移项“b”,或者(3)同时使用截距项和漂移项。我们将在本文中看到这三个例子。
另一个有趣的观察结果是,如果重新排列等式,如等式 2 所示,趋势项的系数(“a”和“b”)可以通过对数据的一阶差分进行线性回归拟合来获得。我们将使用这个等式来开发模型参数“a”和“b”的理论框架。

趋势项重排后的 d=1 的 ARIMA 方程(图片由作者使用https://latex2png.com/)
2️⃣️使用 PyCaret 理解趋势项和差异项的组合效应
👉步骤 1:设置 PyCaret 时序实验
设置与上一篇文章(描述了差异术语)中的设置相同。详细信息可在本文的 Jupyter 笔记本中找到(可在本文末尾找到)。
*#### Get data from data playground ----*
y = get_data("1", **folder="time_series/random_walk"**)exp = TimeSeriesExperiment()
exp.setup(data=y, seasonal_period=1, fh=30, session_id=42)
👉第 2 步:执行 EDA
我们将跳过本文中的 EDA,因为我们已经在本系列的上一篇文章中执行了它。
👉第 3 步:理论计算
如上所述,我们将使用等式(2)来确定该 ARIMA 模型的模型系数。我们还将模拟三种不同的 ARIMA 模型变体。每个模型将包含第一个差异项和上述趋势选项之一。为了帮助进行理论计算,我们重复使用了前一篇文章中的框架(它只包含第一个差异项),但此外,我们还对残差进行了线性回归。
***# Get Train & Test Data Properties***
y_train **=** exp**.**get_config("y_train")
y_test **=** exp**.**get_config("y_test")***# Compute theoretical prediction for ARIMA(0,1,0)x(0,0,0,0)*** train_data **=** pd**.**DataFrame({"y":y_train})
train_data['preds'] **=** y_train**.**shift(1)
train_data['split'] **=** "Train"
test_data **=** pd**.**DataFrame({'y': y_test})
test_data['preds'] **=** y_train**.**iloc[**-**1]
test_data['split'] **=** "Test"
data **=** pd**.**concat([train_data, test_data])
data['residuals'] **=** data['y'] **-** data['preds']
(1)方法 1:d = 1、trend = "c" 的 ARIMA 模型
y_for_lr **=** data**.**query("split=='Train'")['residuals']**.**dropna()
y_for_lr**.**mean()***>>> 0.020172890811799432***
因此,对于 d=1 且趋势= "c "的模型,我们预计" c "的值= 0.02017。
(2)方法 2:d = 1、trend = "t "的 ARIMA 模型
y_for_lr **=** data**.**query("split=='Train'")['residuals']**.**dropna()
X_train **=** np**.**arange(1, len(y_for_lr)**+**1)**.**reshape(**-**1, 1)
reg **=** LinearRegression(fit_intercept**=False**)**.**fit(X_train, y_for_lr)
print(f"Expected Intercept: {reg**.**intercept_}")
print(f"Expected Slope: {reg**.**coef_}")***>>> Expected Intercept: 0.0
>>> Expected Slope: [0.00018524]***
对于 d=1 且趋势= "t "的模型,我们预计漂移" b "的值= 0.00018524。
(3)方法 3:d = 1、trend = "ct "的 ARIMA 模型
y_for_lr **=** data**.**query("split=='Train'")['residuals']**.**dropna()
X_train **=** np**.**arange(1, len(y_for_lr)**+**1)**.**reshape(**-**1, 1)
reg **=** LinearRegression(fit_intercept**=True**)**.**fit(X_train, y_for_lr)
print(f"Expected Intercept: {reg**.**intercept_}")
print(f"Expected Slope: {reg**.**coef_}")***>>> Expected Intercept: -0.03432448539897173
>>> Expected Slope: [0.0003516]***
对于 d=1 且趋势= "ct "的模型,我们预期常数" a" = -0.0343 和漂移" b "的值= 0.0003516。
👉第 4 步:建模
现在,我们已经讨论了理论计算,让我们使用 PyCaret 构建这些模型,并在实践中观察它们的输出。
**# Model with d = 1 and Trend = "c" ----**
model3b **=** exp**.**create_model(
"arima",
order**=**(0, 1, 0),
trend**=**"c"
)**# Model with d = 1 and Trend = "t" ----** model3c **=** exp**.**create_model(
"arima",
order**=**(0, 1, 0),
with_intercept**=True**, trend**=**'t'
)**# Model with d = 1 and Trend = "ct" ----** model3d **=** exp**.**create_model(
"arima",
order**=**(0, 1, 0),
trend**=**"ct"
)
👉第 5 步:结果分析
我们将重复使用我们在上一篇文章中创建的帮助器函数来分析结果。
(1)方法 1:d = 1、trend = "c "的 ARIMA 模型
**summarize_model**(model3b)
**get_residual_properties**(model3b)

模型 3B 统计摘要[作者图片]
统计概要显示,创建的模型是一个带有“截距”项的SARIMAX(0,1,0)模型。该模型的截距值为 0.0202,与我们的理论计算相符(注意,上面的显示显示了四舍五入的结果)。残差 sigma2(无法解释的方差)为 0.9788,代表等式 1 中的epsilon项。

模型 3B 残差[作者图像]
查看模型残差,我们可以看到残差的方差确实为 0.9788,这与统计汇总相符。接下来,让我们绘制预测图,并将其与我们的理论框架进行比较。
**plot_predictions**(model3b)

基于样本预测的 3B 模型[作者图片]

模型 3B 样本内预测[作者图片]
由于计算预测值的方程(方程 1)比以前的文章更复杂,所以我构建了一个小型 excel 计算器来计算理论预测值(列“Pred(计算)”),并将它们与模型预测值(列“Pred”)进行比较。它们完全匹配(“匹配”列)。此外,请注意,上面的计算器包含样本内点(例如,索引 0、1、2、3、4……),以及样本外预测(索引 310、311、312……)。PyCaret 中的交互式绘图使用户可以非常容易地放大和验证各个时间点的值,以交叉检查答案。
**注意:**我只展示了样本内和样本外预测的一小部分。读者可能希望延伸到更多的点,以加强他们的理解。excel 可以在本文的末尾(在“参考资料”一节中)找到。

模型 3B 理论预测计算[图片由作者提供]
(2)方法二:d=1 且 trend = "t" 的 ARIMA 模型
**summarize_model**(model3c)
**get_residual_properties**(model3c)

模型 3C 统计摘要[图片由作者提供]
统计汇总显示,创建的模型是一个带有“漂移”项的SARIMAX(0,1,0)模型。模型的漂移值 0.0002 与我们的理论计算相匹配(注意,上面显示的是四舍五入后的结果)。残差σ2(未解释方差)为 0.9781,代表等式 1 中的epsilon项。

模型 3C 残差[图片由作者提供]
查看模型残差,我们可以看到残差确实具有 0.9781 的方差,这与统计汇总相匹配。接下来,让我们绘制预测图,并将其与我们的理论框架进行比较。
**plot_predictions**(model3c)

从样本预测中模拟 3C[图片由作者提供]

模型 3C 样本内预测[图片由作者提供]
同样,excel 计算器用于对照模型输出检查理论预测(这次使用斜率项“b”来匹配理论“漂移”值)。同样,由“Pred(计算)”列表示的理论预测(样本内和样本外)与由“Pred”列表示的模型输出相匹配。

模型 3C 理论预测计算[图片由作者提供]
(3)方法三:d=1 且 trend = "ct" 的 ARIMA 模型
**summarize_model**(model3d)
**get_residual_properties**(model3d)

模型 3D 统计摘要[图片由作者提供]
统计概要表明,所创建的模型是一个既有“截距”又有“漂移”项的SARIMAX(0,1,0)模型。模型中的值(截距=-0.0343 和漂移= 0.0004)与我们的理论计算相匹配(注意,上面显示的是四舍五入的结果)。残差σ2(未解释方差)为 0.9778,代表等式 1 中的epsilon项。

3D 残差模型[图片由作者提供]
查看模型残差,我们可以看到残差确实具有 0.9778 的方差,这与统计汇总相匹配。接下来,让我们绘制预测图,并将其与我们的理论框架进行比较。
**plot_predictions**(model3d)

样本预测的 3D 模型[图片由作者提供]

模型 3D 样本内预测[图片由作者提供]
同样,excel 计算器用于对照模型输出检查理论预测(这次使用截距项“a”和斜率项“b”)。同样,由“Pred(计算)”列表示的理论预测(样本内和样本外)与由“Pred”列表示的模型输出相匹配。

模型 3D 理论预测计算[图片由作者提供]
🚀结论
现在我们有了。我们将乐高风格的积木(“趋势”和“差异”术语)组合成一个更复杂的模型。希望这个简单的框架为我们理解这些术语在 ARIMA 模型中如何相互作用打下了良好的基础。在下一篇文章中,我们将看到季节参数“s”和季节差异“D”的影响。在那之前,如果你愿意在我的社交渠道上与我联系(我经常发布关于时间序列分析的文章),你可以在下面找到我。暂时就这样了。预测快乐!
🐦推特
📘 GitHub
喜欢这篇文章吗?成为 中等会员 继续 无限制学习 。如果你使用下面的链接, ,我会收到你的一部分会员费,而不会给你带来额外的费用 。
https://ngupta13.medium.com/membership
📗资源
- Jupyter 笔记本 包含这篇文章的代码
- Excel 计算器 进行理论预测。
用 Python 实现随机森林分类器的实用指南
原文:https://towardsdatascience.com/a-practical-guide-to-implementing-a-random-forest-classifier-in-python-979988d8a263?source=collection_archive---------0-----------------------
用 sklearn 构建咖啡评级分类器
随机森林是一种监督学习方法,这意味着我们的输入和输出之间有标签和映射。它可以用于分类任务,如根据花瓣长度和颜色等测量结果确定花的种类,也可以用于回归任务,如根据历史天气数据预测明天的天气预报。顾名思义,随机森林由多个决策树组成,每个决策树输出一个预测。在执行分类任务时,随机森林中的每个决策树都会为输入所属的一个类投票。例如,如果我们有一个关于花的数据集,并且我们想要确定一种花的种类,那么随机森林中的每棵决策树将投票选出它认为一种花属于哪个种类。一旦所有的树都得出结论,随机森林将计算哪个类(物种)拥有最多的投票,这个类将是随机森林输出的预测。在回归的情况下,随机森林将平均每个决策树的结果,而不是确定最多的投票。因为随机森林利用多个学习者(决策树)的结果,所以随机森林是一种集成机器学习算法。集成学习方法减少了方差并提高了其组成学习模型的性能。
决策树
如上所述,随机森林由多个决策树组成。决策树根据数据的特征将数据分成小组。例如,在花卉数据集中,特征将是花瓣长度和颜色。决策树将继续把数据分成组,直到一个标签(一个分类)下的一小组数据存在。一个具体的例子是选择吃饭的地方。人们可能会细读 Yelp 并根据关键决策找到一个吃饭的地方,比如:这个地方现在开门了吗,这个地方有多受欢迎,这个地方的平均评分是多少,我需要预订吗。如果这个地方是开放的,那么决策树将继续下一个特征,如果不是,决策结束,模型输出“不,不要在这里吃”。现在,在下面的要素中,模型将确定一个地方是否受欢迎,如果该位置受欢迎,模型将移动到下一个要素,如果不受欢迎,模型将输出“不,不要在这里吃”-与之前的过程相同。从本质上讲,人们可以把决策树想象成一个流程图,它根据数据绘制出可以做出的决策,直到得出最终结论。决策树基于测量信息增益的纯度度量来确定在哪里分割特征。在分类的情况下,它根据基尼指数或熵作出决定,在回归的情况下,根据残差平方和作出决定。然而,这其中的数学问题超出了这篇博文的范围。本质上,这些 metics 测量的是信息增益,衡量我们能够从一条数据中收集多少信息。
随机森林逻辑
随机森林算法可以描述如下:
- 假设观测值的数量为 N。这 N 个观测值将被随机抽样并替换。
- 假设有 M 个特征或输入变量。将在每个节点从特征总数 M 中随机选择一个数字 M,其中 m < M。这 M 个变量的最佳分割用于分割节点,并且该值随着森林的增长而保持不变。
- 森林中的每棵决策树都增长到最大程度。
- 该林将基于该林中的树的聚合预测来输出预测。(多数票或平均票)
数据探索
在本帖中,我们将利用随机森林来预测咖啡的杯数。咖啡豆被专业地分为 0-100 分。该数据集包含咖啡豆的总杯突点以及咖啡豆的其他特征,如原产国、品种、风味、香味等。这些特征中的一些将被用于训练随机森林分类器,以基于它接收的总杯突点来预测特定豆的质量。本演示中的数据来自 TidyTuesday 存储库,下面是数据的预览。

为了保证模型的安全性,我们将对该数据集进行子集划分,以包含咖啡的属性列,这些属性包括但不限于:品种、原产国、酸度、酒体和甜度。此外,我们将删除任何包含 nan(非数字/缺失)值的行。
coffee_df = coffee_ratings[['total_cup_points',
'species',
'country_of_origin',
'variety',
'aroma',
'aftertaste',
'acidity',
'body',
'balance',
'sweetness',
'altitude_mean_meters',
'moisture']]
coffee_df = coffee_df.dropna()

从上面我们可以看到,数据不仅包含数值,还包含分类值,如物种、原产国和品种。我们可以通过使用 sklearn 包提供的 OrginalEncoder 函数将这些映射成数值。例如,有两种咖啡:阿拉比卡和罗布斯塔。代码将为这些分配数值,例如 Arabica 映射到 0,而 Robusta 映射到 1。对于其他变量,将遵循类似的逻辑。
from sklearn.preprocessing import OrdinalEncoder
ord_enc = OrdinalEncoder()
coffee_df["species"] = ord_enc.fit_transform(coffee_df[["species"]])
coffee_df["country_of_origin"] = ord_enc.fit_transform(coffee_df[["country_of_origin"]])
coffee_df["variety"] = ord_enc.fit_transform(coffee_df[["variety"]])
既然所有的数据都是数字,我们可以生成图表来观察不同特征之间的关系。一个有用的图表是显示特征的边缘和联合分布的 pairplot。我们放弃了
import seaborn
seaborn.pairplot(coffee_df.drop('total_cup_points', axis = 1))

我们可以看到分布是很难看到的。在某些情况下,分布是完全二元的,如特定的,或非常偏斜的,如平均高度。此外,一些数值变量,如香气和酸度,各包含一个 0 值,这是数据中的异常值,我们将把它们过滤掉并重新绘制 paitplot。
coffee_df = coffee_df[coffee_df['aroma']>0]
coffee_df = coffee_df[coffee_df['acidity']>0]seaborn.pairplot(coffee_df)
下面我们可以更清楚地看到联合分布。图的第一列表示特征如何与目标变量total_cupping_points相关。我们可以看到从aroma到balance的特征似乎与接收到的total_cupping_points有很强的关系。此外,我们在配对图的对角线上看到的边际分布在很大程度上似乎是正态分布的。
我们可以为探索性数据分析(EDA)生成的另一个图是关联矩阵,它将显示特征之间的关联。我们也可以通过 seaborn 软件包来实现这一点。
seaborn.heatmap(coffee_df.corr(),
xticklabels=coffee_df.columns,
yticklabels=coffee_df.columns)

我们可以看到,从aroma到sweetness特征之间呈正相关,与品种之间呈负相关,与altitude_mean_meters和moisture也呈负相关。
数据扩充
如果我们观察总杯数评级的分布,我们可以看到这些值是连续的,而不是离散的,例如对餐馆的星级评级,一星、二星等。在这个项目中,我将把拔罐评级分为三类:低、中、好。这可以通过根据我们下面看到的分布设置阈值来实现。在某个阈值内的任何东西都将被标记为坏的、一般的或好的。更准确地说,我将把低于第 75 百分位的定义为“低”,第 75 和第 90 百分位之间的定义为“一般”,前 10 百分位的定义为“好”。当然,在数据集中,这些标签将是数字的。坏的将被标为 1,一般的标为 2,好的标为 3。

这就是阈值的计算方法。我们将从 numpy 调用 percentile 函数,并输入一个包含代表分界点的百分点的列表。
rating_pctile = np.percentile(coffee_df['total_cup_points'], [75, 90])# The percentile thresholds are
array([83.58, 84.58])
然后,我们使用这些阈值在数据帧中创建一个名为n_rating的新列,代表使用基于以上定义的百分比系统的新标签系统对咖啡的评级。
coffee_df['n_rating'] = 0
coffee_df['n_rating'] = np.where(coffee_df['total_cup_points'] < rating_pctile[0], 1, coffee_df['n_rating'])
coffee_df['n_rating'] = np.where((coffee_df['total_cup_points'] >= rating_pctile[0]) & (coffee_df['total_cup_points'] <= rating_pctile[1]), 2, coffee_df['n_rating'])
coffee_df['n_rating'] = np.where(coffee_df['total_cup_points'] > rating_pctile[1], 3, coffee_df['n_rating'])
下面我们可以观察到由 out 阈值给出的评级的新分布。大多数咖啡评级属于“低”类(准确地说是 75%的数据),只有少数咖啡评级为“好”。

此时,数据几乎可以用于建模了。我们现在需要将数据分成训练集和测试集。训练集将用于训练随机森林分类器,而测试集将用于评估模型的性能-因为这是它以前在训练中没有见过的数据。这里 75%的数据用于训练,25%的数据用于测试。
X = coffee_df.drop(['total_cup_points', 'n_rating', 'sweetness', 'species', 'altitude_mean_meters'], axis = 1)
y = coffee_df['n_rating']
training, testing, training_labels, testing_labels = train_test_split(X, y, test_size = .25, random_state = 42)
接下来,我们将缩放数据,这将是我们所有的功能相同的比例,这有助于确保具有较大值的属性不会过度影响模型。sklearn 中的[StandardScaler](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html)主要计算每个要素的 z 得分,确保数据集中的每个要素的均值为 0,方差为 1。
# Normalize the data
sc = StandardScaler()
normed_train_data = pd.DataFrame(sc.fit_transform(training), columns = X.columns)
normed_test_data = pd.DataFrame(sc.fit_transform(testing), columns = X.columns)
为了子孙后代,我们可以绘制另一个 pairplot,看看归一化是否强调了特征之间的关系。数据归一化后,咖啡属性从aroma到平衡的关系为clearer。由于椭圆联合分布,这些变量之间似乎存在着弦关系。

构建随机森林
现在数据准备好了,我们可以开始编码随机森林了。我们可以用两行代码实例化并训练它。
clf=RandomForestClassifier()
clf.fit(training, training_labels)
然后做预测。
preds = clf.predict(testing)
然后快速评估它的性能。
print (clf.score(training, training_labels))
print(clf.score(testing, testing_labels))1.0
0.8674698795180723
score方法让我们了解随机森林对给定数据的平均准确性。在第一次调用中,我们在训练数据上评估它的性能,然后在测试数据上评估。该模型在训练数据上的准确率为 100%,在测试数据上的准确率较低,为 86.75%。由于训练精度如此之高,而测试又不是那么接近,所以可以肯定地说,该模型过度拟合了——该模型对训练数据的建模太好了,没有概括出它正在学习的东西。把它想象成记忆一个测试的答案,而不是真正学习那个测试的概念。我们将在后面讨论如何减轻这个问题。
我们可以用来评估模型性能的另一个工具是混淆矩阵。混淆矩阵显示了实际类别和预测类别的组合。矩阵的每一行代表预测类中的实例,而每一列代表实际类中的实例。这是一个很好的方法来衡量模型是否能解释类属性的重叠,并理解哪些类最容易混淆。
metrics.confusion_matrix(testing_labels, preds, labels = [1, 2, 3])

第一列代表评级为“低”的咖啡,第二列代表评级为“一般”的咖啡,第三列代表评级为“好”的咖啡。矩阵对角线上的数字 183、19 和 14 代表模型准确分类的咖啡数量。非对角线值代表错误分类的数据。例如,11 种应该被标记为“低”分的咖啡被标记为“一般”。
我们可以从随机森林中获得的另一个有趣的洞察力是探索模型“认为”在确定总杯突点中最重要的特征。
pd.DataFrame(clf.feature_importances_, index=training.columns).sort_values(by=0, ascending=False)

我们可以看到balance、aftertaste和acidity似乎对一杯咖啡获得的总杯数贡献很大。
调整随机森林
当我们在上面的clf=RandomForestClassifier()中实例化一个随机森林时,森林中的树的数量、用于分割特征的度量等参数采用在[sklearn](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html)中设置的默认值。然而,这些默认值通常不是最佳的,必须针对每个用例进行调整。要调整的参数可以在sklearn 文档中找到。调整这些参数的一种方法是执行随机网格搜索。我们定义了一个值的范围,代码可以从中随机挑选,直到找到一组性能最好的值。首先,我们定义搜索算法将搜索的值。
# Number of trees in random forest
n_estimators = np.linspace(100, 3000, int((3000-100)/200) + 1, dtype=int)
# Number of features to consider at every split
max_features = ['auto', 'sqrt']
# Maximum number of levels in tree
max_depth = [1, 5, 10, 20, 50, 75, 100, 150, 200]# Minimum number of samples required to split a node
# min_samples_split = [int(x) for x in np.linspace(start = 2, stop = 10, num = 9)]
min_samples_split = [1, 2, 5, 10, 15, 20, 30]
# Minimum number of samples required at each leaf node
min_samples_leaf = [1, 2, 3, 4]
# Method of selecting samples for training each tree
bootstrap = [True, False]
# Criterion
criterion=['gini', 'entropy']random_grid = {'n_estimators': n_estimators,
# 'max_features': max_features,
'max_depth': max_depth,
'min_samples_split': min_samples_split,
'min_samples_leaf': min_samples_leaf,
'bootstrap': bootstrap,
'criterion': criterion}
这实际上创建了一个可供选择的值字典:
{'n_estimators': array([ 100, 307, 514, 721, 928, 1135, 1342, 1550, 1757, 1964, 2171,
2378, 2585, 2792, 3000]),
'max_depth': [1, 5, 10, 20, 50, 75, 100, 150, 200],
'min_samples_split': [1, 2, 5, 10, 15, 20, 30],
'min_samples_leaf': [1, 2, 3, 4],
'bootstrap': [True, False],
'criterion': ['gini', 'entropy']}
接下来,我们可以开始搜索,然后在随机搜索中找到的参数上安装一个新的随机森林分类器。
rf_base = RandomForestClassifier()
rf_random = RandomizedSearchCV(estimator = rf_base,
param_distributions = random_grid,
n_iter = 30, cv = 5,
verbose=2,
random_state=42, n_jobs = 4)rf_random.fit(training, training_labels)
我们还可以查看随机搜索找到的参数值:
rf_random.best_params_{'n_estimators': 2171,
'min_samples_split': 2,
'min_samples_leaf': 2,
'max_depth': 200,
'criterion': 'entropy',
'bootstrap': True}
从这里我们可以再次评估模型
print (rf_random.score(training, training_labels))
print(rf_random.score(testing, testing_labels))0.9825970548862115
0.8714859437751004
我们现在看到培训分数不到 100%,测试分数是 87.25%。该模型似乎不像以前那样过度拟合。
既然我们已经从随机网格搜索中获得了参数值,我们可以将它们作为网格搜索的起点。原则上,网格搜索的工作方式类似于随机网格搜索,因为它将搜索我们定义的参数空间。然而,它不是搜索随机值,而是搜索参数空间中所有可能的值。这种计算可能是昂贵的,因为随着更多的参数和这些参数的搜索值的增加,搜索增长得非常快。这就是为什么我们首先执行随机网格搜索。我们节省了计算能力,只有当我们有了一个好的起点时,才进行精细的方法搜索。实例化网格搜索也类似于实例化随机网格搜索。
param_grid = {
'n_estimators': np.linspace(2100, 2300, 5, dtype = int),
'max_depth': [170, 180, 190, 200, 210, 220],
'min_samples_split': [2, 3, 4],
'min_samples_leaf': [2, 3, 4, 5]
}
然后我们可以重新训练另一个随机森林。
# Base model
rf_grid = RandomForestClassifier(criterion = 'entropy', bootstrap = True)
# Instantiate the grid search model
grid_rf_search = GridSearchCV(estimator = rf_grid, param_grid = param_grid,
cv = 5, n_jobs = 8, verbose = 2)
grid_rf_search.fit(training, training_labels)
并查看它发现的最佳参数集
best_rf_grid = grid_rf_search.best_estimator_grid_rf_search.best_params_{'max_depth': 170,
'min_samples_leaf': 2,
'min_samples_split': 2,
'n_estimators': 2100}
我们可以看到它找到的结果与随机网格搜索找到的结果相差不远。现在我们可以评估这个模型,以确定它的准确性和性能。
print (grid_rf_search.score(training, training_labels))
print(grid_rf_search.score(testing, testing_labels))0.9839357429718876
0.8714859437751004
我们看到它的表现与随机搜索网格非常相似,因为它的参数没有偏离我们最初开始时的参数太远。
此外,我们还可以查看模型认为最重要的特征。Balance、aftertaste和acidity仍然是排名前三的功能,只是权重略有不同。
最后,我们可以查看最终模型的混淆矩阵。看起来和以前一样。

在本文中,我们对 TidyTuesday 的咖啡数据集进行了一些探索性的数据分析,并构建了一个随机森林分类器,将咖啡分为三组:低、中、好。这些等级决定了咖啡应该得到多少杯点。一旦我们建立了一个初始分类器,我们调整它的超参数,以确定我们是否可以进一步提高模式的性能。
线性回归实用指南
原文:https://towardsdatascience.com/a-practical-guide-to-linear-regression-3b1cb9e501a6?source=collection_archive---------4-----------------------
从 EDA 到特征工程再到模型评估

线性回归备忘单(作者图片来自原始博客
线性回归是负责数值预测的典型回归算法。它不同于分类模型,如决策树、支持向量机或神经网络。简而言之,线性回归找到自变量和因变量之间的最佳线性关系,然后做出相应的预测。
我估计大多数人在数学课上都频繁遇到过函数 y = b0 + b1x 。基本上是简单线性回归的形式,其中 b0 定义截距 b1 定义直线的斜率。我将在“模型实现”一节中解释算法背后的更多理论,本文的目的是走向实用!如果您想访问代码,请访问我的网站。
定义目标
我在这个练习中使用 Kaggle 公共数据集“保险费预测”。数据包括自变量:*年龄、性别、bmi、孩子、吸烟者、*地区、目标变量——费用。首先,让我们加载数据,并使用 df.info() 对数据进行初步检查
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from pandas.api.types import is_string_dtype, is_numeric_dtypedf = pd.read_csv('../input/insurance-premium-prediction/insurance.csv')
df.info()

关键要点:
- 分类变量:性别、吸烟者、地区
- 数字变量:年龄、体重指数、孩子、费用
- 1338 条记录中没有缺失数据
探索性数据分析
EDA 对于调查数据质量和揭示变量之间隐藏的相关性是必不可少的。在本练习中,我将介绍与线性回归相关的三种技术。要全面了解 EDA,请查看:
1.单变量分析
使用直方图显示数值变量,使用条形图显示分类变量的数据分布。


单变量分析(图片由作者提供)
为什么我们需要单变量分析?
- 确定数据集是否包含异常值
- 确定是否需要数据转换或特征工程
在这种情况下,我们发现“费用”遵循幂律分布,这意味着作为特征工程步骤的一个步骤,需要进行对数变换,以将其转换为正态分布。

2.多变量分析
当想到线性回归时,我们能想到的第一个可视化技术是散点图。通过使用单行代码 sns.pairplot(df) 绘制目标变量与自变量的关系,潜在的线性关系变得更加明显。

配对图(图片由作者提供)
现在,添加分类变量作为图例怎么样?


色调=性

色调=区域

色调=吸烟者
从吸烟者与非吸烟者分割的散点图中,我们可以观察到吸烟者(蓝色)的医疗费用明显较高。这表明“吸烟者”这一特征可能是费用的一个强有力的预测因素。

3.相关分析
相关性分析检查变量对之间的线性相关性。这可以通过结合 corr()函数和 sns.heatmap()来实现。


相关性分析(图片由作者提供)
注意,这是在分类变量编码之后(如“特征工程”一节),因此热图中不仅显示数字变量。
为什么我们需要相关性分析?
- 识别独立变量之间的共线性-线性回归假设独立要素之间没有共线性,因此如果存在共线性,则必须删除一些要素。在这个例子中,没有一个独立变量与另一个高度相关,因此不需要删除任何变量。
- 识别与目标密切相关的独立变量——它们是强有力的预测因素。再一次,我们可以看到“吸烟者”与费用相关。
特征工程
EDA 带来了一些关于什么类型的特征工程技术适合数据集的见解。
1.对数变换
我们发现目标变量“费用”是右偏的,服从幂律分布。由于线性回归假设输入和输出变量之间存在线性关系,因此有必要对“费用”变量进行对数变换。如下图,应用 np.log2() 后数据趋于正态分布。除此之外,剧透一下,这个转换确实把线性回归模型得分从 0.76 提高到了 0.78。


转型前的“费用”

转型后的“费用”
2.编码分类变量
机器学习算法的另一个要求是将分类变量编码成数字。两种常见的方法是一热编码和标签编码。如果你想了解更多的区别,请查看:“特征选择和机器学习中的 EDA”。
这里我比较一下这两者的实现和结果。
- 一个热编码
df = pd.get_dummies(df, columns = cat_list)

一个热编码结果
- 标签编码


标签编码
然而,这两种方法都导致模型得分为 0.78,这表明选择任何一种都不会在这个意义上产生显著差异。
模型实现
简单的线性回归, *y = b0 + b1x,*预测一个自变量 x 和一个因变量 y 之间的关系,例如,经典的身高-体重相关性。随着更多特征/独立变量的引入,它演变成多元线性回归 y = b0 + b1x1 + b2x2 + … + bnxn,这不能容易地使用二维空间中的线来绘制。

简单线性回归(图片由作者提供)
我从 scikit-learn 应用了 LinearRegression() 来实现线性回归。我指定了 normalize = True ,这样独立变量将被规范化并转换成相同的标度。scikit-learn 线性回归利用普通最小二乘法找到拟合数据的最佳直线。因此,由系数 b0,b1,b2 … bn 定义的线使观测目标和预测值之间的残差平方和最小(图中的蓝线)

线性回归模型(图片作者提供)
实现非常简单,并返回一些属性:
- model.coef_:系数值— b1,b2,b3 … bn
- model.intercept_:常量值— b0
- model.score:有助于评估模型性能的预测的确定性 R 平方(在模型评估部分有更详细的描述)
我们先用系数值粗略估计一下特征重要性,并可视化。不出所料,吸烟者是医疗费用的主要预测因素。
sns.barplot(x = X_train.columns, y = coef, palette = "GnBu")

回想一下,我们已经对目标变量进行了对数转换,因此不要忘记使用 2**y_pred 来恢复到实际预测费用。


模型评估
线性回归模型可以通过可视化误差分布进行定性评估。也有定量的措施,如平均误差,均方误差,RMSE 和 R 平方。


模型评估(图片由作者提供)
1.误差分布
首先,我使用直方图来可视化误差的分布。理想情况下,它应该多少符合正态分布。非正态误差分布可能表明存在模型未能提取的非线性关系,或者需要更多的数据转换。
2.RMSE 的梅、姆塞
平均绝对误差(MAE):误差绝对值的平均值

均方误差(MSE):均方误差的平均值

均方根误差(RMSE):平方误差平均值的平方根

这三种方法都是通过计算预测值ŷ和实际值 y 之间的差值来测量误差的,因此差值越小越好。主要区别是 MSE/RMSE 惩罚大的误差并且是可微的,而 MAE 是不可微的,这使得它很难应用于梯度下降。与 MSE 相比,RMSE 取平方根,从而保持原始数据比例。
3.r 平方——决定系数
r 的平方或决定系数是一个介于 0 和 1 之间的值,表示模型所解释的实际目标变量的变化量。r 平方定义为 1 — RSS/TSS,1 减去残差平方和(RSS)与总平方和(TSS)之比。更高的 R 平方意味着更好的模型性能。
残差平方和(RSS)


RSS(图片由作者提供)
总平方和(TSS)


TSS(图片由作者提供)
在这种情况下,R 的平方值为 0.78,表明模型解释了目标变量中 78%的变化,这通常被认为是一个好的比率,没有达到过度拟合的水平。
希望你喜欢我的文章:)。如果你想阅读我更多关于媒体的文章,我将非常感谢你的支持,注册媒体会员。
带回家的信息
本文提供了实现线性回归的实用指南,介绍了模型构建的整个生命周期:
- EDA:单变量分析,散点图,相关分析
- 特征工程:对数变换,分类变量编码
- 模型实现:scikit learn LinearRegression()
- 模型评估:平均误差、均方误差、RMSE、R 平方
如果您对视频指南感兴趣:)
https://www.youtube.com/watch?v=tMcbmyK6QiM
更多这样的文章
原载于 2021 年 9 月 18 日 https://www.visual-design.net**的 。
AWS Sagemaker 中的 MLOps 实用指南—第一部分
原文:https://towardsdatascience.com/a-practical-guide-to-mlops-in-aws-sagemaker-part-i-1d28003f565?source=collection_archive---------3-----------------------
如何在 AWS Sagemaker 中实现 CI/CD 模型开发和评估管道?

梵高,文森特。星夜。(来源
这个指南是我自己在 AWS 上寻找一个完整的端到端的模型开发、评估和部署工作的挫折的结果。我在那里看到的所有指南和教程都只覆盖了一部分,而没有完全联系起来。我想写一些东西,帮助人们了解构建模型和部署模型的完整工作,以便前端开发人员可以在他们的网站和应用程序上访问它。
所以,让我们开始吧!
我将本指南分为两部分。
1.使用 AWS Sagemaker Studio 进行模型开发和评估。
2.使用 AWS Lambda 和 REST API 的模型部署
先决条件:
AWS 账户——运行整个教程的费用不到 0.50 美元,所以不要担心。
对 Python 的理解——如今大部分机器学习工作都是用 Python 完成的。
耐心——失败是成功最重要的先决条件,所以继续尝试,直到成功。
第 1 部分:模型开发
我们将在 Sagemaker Studio 中建立一个项目来构建我们的开发管道。
1.登录您的 AWS 账户,从服务列表中选择 Sagemaker 。
2.选择 Sagemaker 工作室并使用快速启动创建工作室。

使用快速启动选项设置 sagemaker studio。(图片由作者提供)
一旦工作室准备就绪,用你刚刚创建的用户打开工作室。创建应用程序可能需要几分钟的时间,但是一旦一切就绪,我们就可以创建项目了。需要理解的是,我们只能创建一个工作室,但是该工作室中有多个用户,并且每个用户都可以在该工作室中创建多个项目。

Sagemaker 控制面板。(图片由作者提供)
3.从左侧导航栏中选择 Sagemaker 组件和注册表,并选择创建项目。

创建项目选项。(图片由作者提供)
默认情况下,Sagemaker 提供了可用于构建、评估主机模型的模板。我们将使用一个这样的模板,并修改它以适应我们的用例。
4.从列表中选择用于模型开发、评估和部署的 MLOps 模板并创建一个项目。

Sagemaker 项目模板。(图片由作者提供)
一旦您的新项目被创建,您将发现 2 个预构建的存储库。第一个定义您的模型开发和评估,另一个将您的模型构建到一个包中,并将其部署到一个端点以供 API 使用。在本指南中,我们将修改第一个模板来运行我们自己的用例。
5.克隆第一个存储库,这样我们就可以修改我们需要的文件。

项目存储库。(图片由作者提供)
我们将要处理的用例是一个客户流失模型,用于预测客户将来是否会退订服务。由于本笔记本背后的想法是学习云中的模型开发和部署,所以我不会深入研究数据,而是直接进入管道开发。
这是我们刚刚克隆的存储库的文件结构,现在让我们看一下将要使用的一些文件。

存储库文件结构。(图片由作者提供)
文件夹 pipelines 包含创建我们的模型开发管道所需的文件,默认情况下,该管道被命名为鲍鱼。
pipeline.py 定义了我们管道的组件,目前,它是用默认值定义的,但是我们将为我们的用例更改代码。
preprocess.py 和 evaluate.py 定义了我们需要在管道中为预处理和评估步骤执行的代码。
codebuild-buildspec-yml 创建并编排管道。
您可以将更多步骤添加到 pipeline.py 和相应的处理文件中,模板还定义了一个 test 文件夹和一个 test_pipelines.py 文件,该文件可用于构建单独的测试管道。
6.将文件夹鲍鱼重命名为客户流失在code build-build spec-yml文件中进行更改以反映这一更改。
**run-pipeline --module-name pipelines.customer_churn.pipeline \**
7.我们需要将数据下载到我们默认的 AWS s3 存储桶中以供使用,我们可以使用笔记本来完成这项工作。从 studio 中的文件选项卡在存储库中创建一个新的笔记本,选择一个带有基本数据科学 python 包的内核,然后将下面的代码粘贴到单元格中并运行。
**!aws s3 cp s3://sagemaker-sample-files/datasets/tabular/synthetic/churn.txt ./
import os
import boto3
import sagemaker
prefix = 'sagemaker/DEMO-xgboost-churn'
region = boto3.Session().region_name
default_bucket = sagemaker.session.Session().default_bucket()
role = sagemaker.get_execution_role()
RawData = boto3.Session().resource('s3')\
.Bucket(default_bucket).Object(os.path.join(prefix, 'data/RawData.csv'))\
.upload_file('./churn.txt')
print(os.path.join("s3://",default_bucket, prefix, 'data/RawData.csv'))**
现在我们需要修改 pipeline.py、evaluate.py 和 preprocess.py 中的代码来满足我们的需求。
8.出于指南的目的,从链接中复制代码以更新 pipeline.py、preprocess.py 和 evaluate.py 中的代码,但确保仔细阅读代码以更好地理解细节。
一切就绪,一旦我们更新了这 3 个文件中的代码,我们就准备好运行我们的第一个管道执行,但是当我们尝试实现 CI/CD 模板时,这将在我们提交和推送代码后自动完成。
9.从侧面导航栏中选择 GIT 选项卡,然后选择您已经修改的文件以添加到暂存区,并将更改提交和推送至远程存储库。

提交更改并将代码推送到远程。(图片由作者提供)
现在转到项目页面上的pipeline选项卡,选择您创建的管道以检查运行的执行情况,您应该会发现一个成功的作业在我们克隆库时自动执行,另一个作业将处于执行状态,您刚刚通过推送代码执行了该作业,现在双击该作业以查看管道图和更多详细信息。

管道的“执行”选项卡。(图片由作者提供)
万岁!!恭喜你刚刚完成了你的第一份培训工作。

管道图。(图片由作者提供)
除非出了差错,你应该看到你的工作**成功了,**但是记住如果它很容易,任何人都会做。失败是走向成功的第一步。

通往成功的道路是崎岖的。(图片由作者提供)
管道完成后,它将创建一个模型并将其添加到您的模型组中,因为我们已经在管道中添加了一个“手动”模型批准条件,所以我们需要选择模型并手动批准它,以创建一个可用于推理的端点。
10.转到项目主页上的模型组选项卡,选择已经创建的模型,您可以查看指标页面来查看评估阶段的结果。

您的模型的度量。(图片由作者提供)
11.如果您对指标满意,您可以选择右上角的批准选项来批准模型。

模型批准页面。(图片由作者提供)
当我们的第二个存储库出现时,一旦您批准了在第二个存储库中定义的模型部署管道,它将执行以部署和托管一个新的端点,我们可以使用它从我们的 API 进行推理。
结论
我试图让本指南保持使用 Sagemaker 的观点,因为它很长,而且还有第 2 部分要写。这里的目标是通过实现一个简单的项目来快速概述 Sagemaker 的不同组件。我给读者的建议是,不要一步一步地遵循指南,用你自己的想法和步骤进行实验,你会经常失败,但你会学到很多东西,这就是议程。希望你喜欢阅读这个指南,就像我喜欢把它放在一起一样。欢迎在评论中提出任何建议或反馈,我们很乐意听到它们。
AWS Sagemaker 中的 MLOps 实用指南—第二部分
使用 AWS Sagemaker 的 MLOps 实用指南—第二部分
原文:https://towardsdatascience.com/a-practical-guide-to-mlops-using-aws-sagemaker-part-ii-c5159b4b51aa?source=collection_archive---------16-----------------------
如何使用 AWS lambda 和 REST API 部署您的模型供全世界使用。

文森特·梵高的《罗讷河上的星夜》(来源)
在我们开始之前,我强烈建议你阅读第一部分,如果你还没有这样做的话。在本指南中,我们将介绍如何部署您的模型,以便前端开发人员可以在他们使用 REST API 的应用程序中使用它,而不必太担心底层细节。

我们需要构建一个管道,将用户的 Web 浏览器(左)连接到我们的模型端点(右)。(图片由作者提供)
由于我们已经在前一部分开发和部署了模型端点,我们将从开发 lambda 函数开始。
AWS 函数
AWS Lambda 是一种无服务器计算服务,允许您运行代码,而无需配置或管理服务器、创建工作负载感知集群扩展逻辑、维护事件集成或管理运行时。
通过使用 AWS Lambda 函数,我们可以避免设置专用服务器来监控传入的请求和执行代码。这样做有很多好处,比如每次 lambda 函数被传入的请求触发时,我们只需支付计算费用,而不是专用的服务器。
按照步骤创建一个 lambda 函数来处理传入的请求。
- 登录 AWS 控制台,从服务列表中选择 lambda。

Lambda function dashboard 显示您使用了多少存储和其他统计数据。(图片由作者提供)
2.创建一个新的 lambda 函数开始编码。

Lambda 函数允许您将简单的代码包部署到无服务器环境中。(图片由作者提供)
3.添加模型端点的名称作为环境变量,方法是单击 configuration 选项卡并添加一个新变量,使用关键字“ENDPOINT_NAME”和值作为开发的端点的名称。

添加端点名称作为环境变量将有助于我们将来在开发更好的模型时自动化这个过程。(图片由作者提供)
4.将下面的代码放入代码编辑器中,确保您将变量“**bucket”**的值替换为您自己的变量,以便它指向您在模型开发期间保存转换的位置。
注意:您可以在第 1 部分开始时创建的笔记本中找到 s3 的位置。
import os
import json
import boto3
import pickle
import sklearn
import warnings
warnings.simplefilter("ignore")# grab environment variables
**ENDPOINT_NAME** = os.environ['ENDPOINT_NAME']
**runtime**= boto3.client('runtime.sagemaker')
**bucket** = "sagemaker-ap-south-1-573002217864"
**key** = "cust-churn-model/transformation/transformation.sav"
s3 = boto3.resource('s3')def lambda_handler(event, context):
payload = process_data(event)
response = runtime.invoke_endpoint(EndpointName=ENDPOINT_NAME,
ContentType='text/csv',
Body=payload)
result = json.loads(response['Body'].read().decode())
predicted_label = 'True' if result > 0.39 else 'False'
return predicted_labeldef process_data(event):
trans = pickle.loads(s3.Object(bucket, key).get()['Body'].read())
event.pop('Phone')
event['Area Code'] = int(event['Area Code'])
obj_data = [[value for key,value in event.items() if key in trans['obj_cols']]]
num_data = [[value for key,value in event.items() if key in trans['num_cols']]]
obj_data = trans['One_Hot'].transform(obj_data).toarray()
num_data = trans['scaler'].transform(num_data)
obj_data = [str(i) for i in obj_data[0]]
num_data = [str(i) for i in num_data[0]]
data = obj_data + num_data
return ",".join(data)
5.在我们执行 lambda 函数之前的最后一步,lambda 函数使用 vanilla python3 来执行,默认情况下没有安装任何库,如 Pandas、NumPy 或 sklearn。因此,我们需要添加一个 sklearn 层,以便可以加载我们的转换。
现在,我将不会进入如何创建和添加一个层的细节,因为这是一个单独的主题,你可以在这里找到更多的细节。
一旦完成,我们就准备好测试我们的 lambda 函数,选择测试下拉菜单来配置一个测试用例,并将下面的输入数据粘贴到其中来运行测试。
{
"State": "SC",
"Account Length": "15",
"Area Code": "836",
"Phone": "158-8416",
"Int'l Plan": "yes",
"VMail Plan": "no",
"VMail Message": "0",
"Day Mins": "10.018992664834252",
"Day Calls": "4",
"Day Charge": "4.226288822198435",
"Eve Mins": "2.3250045529370977",
"Eve Calls": "0",
"Eve Charge": "9.97259241534841",
"Night Mins": "7.141039871521733",
"Night Calls": "200",
"Night Charge": "6.436187619334115",
"Intl Mins": "3.2217476231887012",
"Intl Calls": "6",
"Intl Charge": "2.559749162329034",
"CustServ Calls": "8"
}
6.一旦您运行测试,lambda 函数将通过转换将输入数据运行到我们已经部署的端点,以获得对数据的响应。

如果一切顺利,您将看到模型的响应。(图片由作者提供)
构建 REST API
API 是一组用于构建和集成应用软件的定义和协议。它有时被称为信息提供者和信息用户之间的契约—建立消费者所需的内容(调用)和生产者所需的内容(响应)。
在我们的例子中,lambda 函数是生产者,它使用模型端点来预测消费者提供的输入*(调用)*的分数,消费者可以是前端开发人员开发的任何 web 应用程序。
- 从 AWS 服务列表中选择“【API Gateway】,选择****【创建 API】**选项,创建一个新的 REST API。

使用 REST API,我们可以将模型提供给前端应用程序。(图片由作者提供)
2.从 API 列表中选择 REST API 并点击 build。

构建一个新的 REST API。(图片由作者提供)
3.选择新的 API,给它一个好听的名字,然后创建。确保将端点类型保留为区域。

将端点类型保留为区域。(图片由作者提供)
4.点击动作下拉菜单,选择 “创建资源”。 创建新资源。接下来,再次单击 Actions 并创建一个新的 Post 方法。

5.一旦你创建了一个 Post 方法 你会得到一个选项来将这个方法与你创建的 lambda 函数集成,输入你的 lambda 函数的名字继续。

确保你所有的项目(lambda,API,Sagemaker studio,s3)都在同一个区域。(图片由作者提供)
一旦创建了 API,就需要部署它。正如你所看到的,仪表板显示了你的 API 的架构,以及它是如何集成到你的 lambda 函数中的。

与 lambda 函数一起部署的 API 结构。(图片由作者提供)
6.您可以通过点击动作选项卡并选择部署 API 选项来部署 API。这将为您提供一个链接,您可以使用它向您的模型端点发送 Post 请求。

确保在复制调用 URL 之前选择 post 方法。(图片由作者提供)
将这一切结合在一起
现在是测试我们的模型结果是否可以通过我们的部署公之于众的时候了。我们可以使用 Postman 来测试我们的 API。
在 Postman 中创建一个新的测试,粘贴您从 REST API 中创建的链接,选择 Body 作为输入类型,选择 POST 作为请求类型,并提供输入数据。

Postman 可用于在部署到生产环境之前测试您的 API。(图片由作者提供)
一旦你点击发送,它将发送一个请求给你的 API,API 将把请求传递给 lambda 函数以获得响应。
万岁!!您已经构建了一个完整的端到端的模型部署管道。

响应将由 Postman 连同一些统计数据一起提交。(图片由作者提供)
结论
总之,我们有。
- 在 AWS 上构建了完整的 CI/CD 兼容模型开发管道。
- 使用 AWS lambda 函数执行预处理来访问模型端点。
- 构建了一个 REST API 来向前端应用程序公开我们的模型。
- 使用 Postman 测试我们的管道。
在这个阶段,你应该花点时间回顾一下你做过的所有事情,并试着想出新的很酷的实验来做得更好。
如果你觉得我的工作有帮助,这里是你可以做的。
发表评论让我知道你的想法,或者如果你发现任何问题。
与你的朋友分享这篇文章。
量子振幅放大实用指南
原文:https://towardsdatascience.com/a-practical-guide-to-quantum-amplitude-amplification-dbcbe467044a?source=collection_archive---------23-----------------------
格罗弗的搜索算法是第一个也是最突出的例子之一,展示了量子电路如何比经典算法快几个数量级
本帖是本书的一部分: 用 Python 动手做量子机器学习 。
在之前的文章中,我们对算法的工作原理有了一个概念性的理解。它遵循一个简单的程序。量子预言反转了被搜索状态的振幅。然后,扩散器翻转关于平均振幅的所有状态,因此,放大被搜索的状态。

作者弗兰克·齐克特的图片
我们了解到我们可以使用相位来放大振幅。如果我们应用一个 HZH 序列,它会把一个量子比特从|0⟩态变成|1⟩.态

作者弗兰克·齐克特的图片
但是一个 HIH 序列将一个量子位从|0⟩变成|+⟩,再回到|0⟩.

作者弗兰克·齐克特的图片
虽然电路的起点和终点保持不变,但我们可以通过翻转(HZH)或不翻转(HIH)的相位来控制量子位的最终振幅
在单量子位电路中,这些电路恒等式似乎相当琐碎。所以,现在让我们来看看,我们如何在实际中利用两个量子位和四个状态。
同样,我们从所有状态的相等叠加开始。对于四个状态,每个状态的幅度为 0.5,得到的测量概率为 0.25。

作者弗兰克·齐克特的图片
下一步,我们需要实现 oracle。其目的是翻转有利状态的振幅。假设它在|10⟩.记住,我们从右边(位置 0 的量子位)到左边(位置 1 的量子位)读取量子位。

作者弗兰克·齐克特的图片
如果控制量子位处于|1⟩.状态,受控 z 门(CZ,垂直连接的点)在目标量子位上应用 z 门因此,当两个量子位都处于|1⟩态和|11⟩.态时,这个门就产生了相移通过将受控的 z 门封装在我们应用于第一个量子位的非门中,我们选择了状态|10⟩而不是|11⟩.
下面的状态及其相位图证实了这种影响。我们翻转了|10⟩.的状态 CZ 门纠缠两个量子位。

作者弗兰克·齐克特的图片
现在,我们需要一个扩散器来放大振幅。它从在所有量子位上应用哈达玛门开始。在下图中,散流器从第二个垂直分离器的右侧开始。

作者弗兰克·齐克特的图片
这一系列的哈达玛门有相当有趣的效果。它切换|01⟩和|10⟩.的振幅

作者弗兰克·齐克特的图片
封装在非门中的受控 Z 门的下一序列具有简单的效果。它翻转了|00⟩.的振幅此外,受控制的 Z 闸再次解开两个量子位元的纠缠。

作者弗兰克·齐克特的图片

作者弗兰克·齐克特的图片
现在,|00⟩和|01⟩共享一个阶段,|10⟩和|11⟩共享一个阶段。换句话说,第一个量子位(符号的右边)在|+⟩状态,第二个量子位在|−⟩.状态
当我们在两个量子位上应用哈达玛门时,我们把来自|+⟩的第一个量子位转换成|0⟩,把来自|−⟩的第二个量子位转换成|1⟩.我们总是在|10⟩州测量系统——我们通过神谕标记的州。

作者弗兰克·齐克特的图片
下图描绘了完整的电路

作者弗兰克·齐克特的图片
这个电路包含相当多的相移,直到我们在最后应用哈达玛门,量子位产生了神谕所标记的期望状态。
这个电路中的大多数门都有技术用途。例如,CZ 门允许我们在多量子位系统中标记一个单一的状态。
如果我们把整个电路分成几个部分,从概念上看这些部分,我们可以发现一个熟悉的结构。我们在起点和终点都看到了哈达玛门。中心部分由神谕和扩散器组成,代表我们应用于第一个量子位的 Z 门和应用于第二个量子位的 I 门。
这个电路的整体模式类似于我们应用于第一个量子位的 HIH 序列和我们应用于第二个量子位的 HZH 序列。I-gate 不会改变量子位,而 Hadamard gate 会自行恢复。因此,第一个量子位元会回到它开始时的状态。那是|0⟩.HZH 门等同于非门,将第二个量子位从初始状态|0⟩变成|1⟩.
结论
格罗弗的电路遵循一个简单的想法。第一组哈达玛闸将量子位元带到相位重要的状态。神谕改变了被搜索状态的阶段。扩散器重新排列所有状态的相位,以便后面的哈达玛门将量子位带入标记状态。
这个电路的美妙之处在于,唯一改变的是标记被搜索状态的神谕。扩散器保持不变。
本帖是本书的一部分: 用 Python 动手做量子机器学习 。

在这里免费获得前三章。
使用 Scikit-Learn 分类的七个基本性能指标实用指南
原文:https://towardsdatascience.com/a-practical-guide-to-seven-essential-performance-metrics-for-classification-using-scikit-learn-2de0e0a8a040?source=collection_archive---------11-----------------------
入门
通过 Python 中的实例介绍了准确率、混淆矩阵、准确率、召回率、F1 值、ROC 曲线和 AUROC。

由弗勒在 Unsplash 上拍摄
性能测量是任何机器学习项目中必不可少的过程。我们的机器学习过程可能不总是产生具有预期准确性的最佳模型。因此,这里需要性能测量来评估训练模型在预测中的有效性。
绩效测量中使用的指标种类繁多,但一般来说,它们可以根据模型类型进行分类,1)分类器或 2)回归器。在本文中,我们将通过介绍在分类项目中使用的七个常见的性能度量标准来关注分类器类型的度量。这七项指标如下:
- 准确度得分
- 混淆矩阵
- 精度
- 召回
- F1 得分
- ROC 曲线
- 奥罗克
虽然理解上述一些性能指标的基本概念可能需要一段时间,但好消息是,使用 Python 机器学习库Scikit-Learn,这些指标的实现从未如此简单。Scikit-Learn 可以用几行 Python 代码简化性能测量。

照片由沙哈达特·拉赫曼在 Unsplash 上拍摄
在下面的部分中,将通过基于经典威斯康星州乳腺癌数据集的简单二元分类项目来解释每个性能指标的概念。这种分类的目的是预测乳腺癌肿瘤是恶性还是良性。
为了确保您能够理解这些材料,建议您使用sci kit-learn 0.23 版或更高版本更新您的 Python 包。这里介绍的一些功能在 Scikit-learn 的早期版本中可能不受支持。
注:
完整的源代码可以从我的 Jupyter 笔记本格式的 Github 中获得。(如果您希望在阅读下面的材料时预览源代码,可以提前下载 Jupyter 笔记本)。
1.数据准备
1.1 数据加载
我们将使用威斯康星州乳腺癌数据集进行分类。为了获得数据,我们可以使用 Scikit-Learn 中的一个助手函数。
load_breast_cancer 是一个 Scikit-Learn 辅助函数,它使我们能够获取所需的乳腺癌数据集并将其加载到 Python 环境中。这里我们调用 helper 函数,并将加载的乳腺癌数据赋给一个变量, br_cancer 。
加载的数据集具有 Python 字典结构,其中包括:
- 一个" data" 键,包含一个数组,每个实例一行,每个特征一列
- 包含标签数组的“目标”键
- 包含数据集描述的“描述”键
1.2 数据探索
现在,让我们通过显示前三行记录来快速预览一下加载的数据集。

前三行记录(图片由作者准备)
记录显示乳腺癌数据集由 30 个数字特征组成(每列一个特征)。如果你有兴趣了解更多关于特性的细节,你可以参考这里的资源。
接下来,我们来看看前三个目标值。

前三个目标值(图片由作者准备)
前三个值是 0 ,表示一个“恶性类。还有另一个可能的值是 1,表示“良性类。

两个可能的类别(图片由作者准备)
现在,我们可以将特征值和目标值分别赋给变量 X 和 y,。
1.3 数据标准化
此时,您可能已经注意到 30 个特性的值范围不一致,这可能会影响我们模型预测的准确性。为了避免这个问题,我们可以使用 Scikit-Learn 标准缩放器将特征值重新缩放到其单位方差。

缩放后的特征值(图片由作者准备)
我们创建一个 StandardScaler 对象,并使用其 fit_transform 方法来重新缩放我们的 X 值,并将转换后的值赋给一个变量 X_scaled 。
1.4 将数据分为训练集和测试集
在训练分类器之前,我们需要将数据集分成训练集和测试集。为此,我们可以利用 Scikit-Learn 函数, train_test_split。
train_test_split 可以自动随机化我们的数据集,并根据我们分配的 test_size 将其分成训练集和测试集。在这种情况下,我们将 test_size 设置为 0.3,以便留出 30%的数据集作为测试集,其余的将用作训练集。训练集和测试集分别分配给变量 X_train 、 X_test 、 y_train 和 y_test 。
2.训练分类器
我们将分别基于 k-最近邻算法(KNN)、随机梯度下降(SGD)和逻辑回归来训练三个分类器。我们构建三个分类器的原因是,我们可以使用本文将要介绍的度量标准来比较它们的性能。
Scikit-Learn 为我们提供 KNN、SGD 和逻辑回归分类器。我们需要做的只是将这些分类器( KNeighboursClassifier、SGDClassifier 和 LogisticRegression )导入到我们的 Python 环境中。接下来,我们为每个分类器创建一个对象,然后使用拟合方法开始训练各自的分类器,使用相同的训练集(X _ train&y _ train)作为其输入。
(整个训练过程应该只需要几秒钟,因为我们正在处理一个非常小的数据集。)
现在,让我们通过使用模型内置方法预测来尝试使用我们训练的分类器进行预测。
我们将测试集取到预测方法中,每个分类器的预测结果分别存储在三个变量 y_pred_knn、 y_pred_sgd 和 y_pred_log 中。
3.性能测定
这是本文的主题。在这里,我们将通过深入研究分类器的基本概念及其使用 Scikit-Learn 的实现来涵盖分类器的七个性能指标。
先说最简单的一个,准确率评分。
3.1 准确度得分
3.1.1 概念
准确度分数可能是衡量分类器性能的最直接的指标。这是一个向我们展示正确预测的一部分的指标。公式如下:

准确度分数的公式(图片由作者准备)
假设在我们的测试集中有 100 条记录,并且我们的分类器成功地对其中的 92 条进行了准确的预测,那么准确性得分将是 0.92。
3 . 1 . 2 sci kit-Learn 中的实施
Scikit-Learn 提供了一个函数 accuracy_score ,它接受真实值和预测值作为其输入来计算模型的准确度分数。
首先,我们从 Scikit-Learn 的度量模块中导入 accuracy_score 函数。接下来,我们将 y_test 作为真值,将 y_pred_knn ,y _ pred _ SGD&y _ pred _ log作为预测值输入到 accuracy_score 函数中。将得到的准确度分数分配给三个变量,并打印分数。

三个分类器的结果准确度分数(图片由作者准备)
所得的准确度分数揭示了逻辑回归分类器在三个分类器中表现出最高的性能。然而,所有三个分类器通常都很高(> 95%的准确度),这给了我们一个粗略的想法,即这些分类器在识别恶性或良性肿瘤中是有效的。
3.2 混淆矩阵
3.2.1 概念
总的来说,准确度分数只给了我们正确预测的一小部分。如果我们想从以下几个方面了解我们的分类器,该怎么办:
- 我们的样本中有多少恶性肿瘤被正确和错误地预测了?
- 我们的样本中有多少良性肿瘤被正确和错误地预测了?
这些问题是至关重要的,因为没有一个病人会乐于接受错误报告的医疗结果。理想情况下,对恶性和良性类别的预测应该达到很高的准确度,以最小化错误报告。如果我们的分类器明显偏向恶性或良性类别,我们可能需要通过调整一些超参数或获取额外的数据到训练管道来重新训练我们的分类器。
因此,评估分类器性能的更好方法是使用混淆矩阵。混淆矩阵(也称为误差矩阵)是一个二维表格,允许分类器对正确标记和错误标记的实例进行可视化。
给定测试集中的 100 个实例的样本,其中每个实例属于正类或负类。分类器在该测试集上的性能可以表示为下面的混淆矩阵:

混淆矩阵的样本(图片由作者准备)
上面混淆矩阵中的每一列代表一个实际的类,而每一行代表一个预测的类。左上象限显示在测试集中有 44 个被准确预测的阳性实例,因为实际类(阳性)与预测类(阳性)相匹配。这种结果被称为真阳性(TP) 。另一方面,右上象限显示了被错误预测为阳性类别的 6 个阴性实例,这些实例被称为假阳性(FP) 。
在右下象限,有 48 个被正确预测的负实例,被称为真负(TN) 。最后,左下象限显示 2 个阳性实例,它们被错误地预测为阴性类别,这些实例被称为假阴性(FN) 。
从上面的样本混淆矩阵中,我们可以观察到,分类器在识别负类时表现出比正类稍好的性能。理想情况下,一个好的分类器应该具有尽可能少的假阳性和假阴性。这意味着混淆矩阵的主对角线中的非零数字越高,分类器的性能越好。
3.2.2 在 Scikit-Learn 中实现
虽然对混淆矩阵的解释可能听起来很冗长,但实现只需要几行代码(感谢 Scikit-Learn)。让我们尝试使用 Scikit-Learn 的混淆矩阵函数为我们的 KNN 分类器构建一个混淆矩阵表。
首先,我们将混淆矩阵函数导入到我们的 Python 环境中。通过向函数传递两个必需的参数,真值( y_test )和预测值( y_pred_knn ),将生成一个表示为 2D 数组的混淆矩阵,如下所示:

Scikit-Learn 生成的 2D 阵列(图片由作者准备)
为了减轻我们在乳腺癌预测中解释 2D 阵列的任务,我们可以通过将阳性类别称为恶性,将阴性类别称为良性,来尝试将 2D 阵列映射到我们之前的混淆矩阵表**。**

将 2D 阵列映射到 KNN 分类器的混淆矩阵表(图片由作者准备)
给定测试集中总共 171 个实例,混淆矩阵显示有 59 个恶性肿瘤被正确分类(真阳性),4 个良性肿瘤被错误分类为恶性(假阳性),105 个良性肿瘤被正确分类(真阴性),另外 3 个恶性肿瘤被错误分类为良性(假阴性)。
基本上,KNN 分类器展示了对恶性和良性肿瘤的良好预测工作。通过重复上述类似的步骤,我们还可以为我们的 SGD 分类器和逻辑回归分类器创建混淆矩阵,然后将它们与 KNN 分类器进行比较。

将 2D 阵列映射到 SGD 分类器的混淆矩阵表(图片由作者准备)

将 2D 阵列映射到 log reg 分类器的混淆矩阵表(图片由作者准备)
现在,让我们看看所有三个混淆矩阵,并在它们之间进行比较。

三种分类器混淆矩阵的比较(图片由作者准备)
从上面的结果中,我们可以观察到 SGD 分类器显示出稍高的假阴性数量,尽管它的总体准确度分数优于 KNN。如果我们只有两个分类器的选择,KNN 或 SGD,并且目标是更低的假阴性,KNN 可能是一个更好的选择,即使它的整体准确性分数略低于 SGD。
另一方面,很明显,逻辑回归分类器仍然是赢家,因为它在三个分类器中显示出最低数量的假阳性和假阴性。
3.3 精确度、召回率和 F1 分数
3.3.1 概念
混淆矩阵向我们显示了一个分类结果中真阳性、假阳性、真阴性和假阴性的确切数量。事实上,我们可以进一步从混淆矩阵中导出几个有用的度量。
首先,我们可能会问自己:真正肯定的积极预测的比例是多少?

阳性预测中真正阳性的比例(图片由作者准备)
为了解决这个问题,让我们通过一个简单的数学计算逻辑,如下所示。

精度计算(图片由作者准备)
真正阳性的数量与阳性总数之间的比率就是所谓的**精度。**精度公式如下:

精确公式(图片由作者准备)
精度给了我们一个量词来揭示预测的阳性实例中真正阳性的部分。上面的样本分类器达到了 0.88 的精度分数,这也意味着 88%的预测阳性是真阳性。
现在,让我们考虑另一个微妙的问题:被正确预测为阳性的阳性实例的比例是多少?

预测为阳性的阳性实例的比例(图片由作者准备)
我们将再次使用一个简单的数学逻辑来解决这个问题。

回忆的计算(图片由作者准备)
上面的计算得出真实阳性与阳性实例总数之间的比率,该比率称为召回。回忆也称为敏感度或真阳性率(TPR)。召回的公式如下所示:

回忆公式(图片由作者准备)
上面的样本分类器的召回分数为 0.957,高于其精确度。这意味着在所有 46 个阳性实例中,95.7%被正确预测为阳性。
精确度和召回率也可以合并成一个单一的指标,称为 F1 分数。F1 分数是精确度和召回率的调和平均值。

F1 分数公式(图片由作者准备)
初看起来,F1 分数公式似乎有点令人生畏,但它只是一个特定的平均值,给予低值更多的权重(与平等对待所有值的常规平均值相比)。高 F1 分数表示相似的精确度和召回率。例如,如果我们将 F1 分数公式应用于我们的样本分类器,我们将得到大约 0.917 的分数。这表明样本分类器的准确率和召回率都很高。
重要的是要知道精确度和召回率并不总是相似的,在某些情况下,我们更喜欢精确度高于召回率,反之亦然。例如,我们期望在医学使用案例(如癌症检测)中有更高的召回率。使我们的分类器能够准确地识别尽可能多的真正阳性癌症实例总是比忽略一些阳性实例更好。另一方面,银行分析师可能更喜欢他们的贷款分类器具有更高的精度,这样他们就不会意外拒绝潜在客户并失去业务。
不幸的是,我们不能总是调整我们的分类器来达到几乎同样高的精度和召回率。提高精确度会导致召回率的降低,反之亦然。这就是所谓的精度/召回权衡。
3 . 3 . 2 sci kit-Learn 中的实现
现在是时候再次动手使用 Scikit-Learn 实现我们在本节中涉及的指标了。使用 Sckit-Learn 提供的 classification_report 函数可以轻松获得精确度、召回率和 F1 分数指标。
像往常一样,我们将所需的 classification_report 函数导入到 Python 环境中。接下来,让我们尝试从数据集中提取目标名称(恶性和良性),并将其分配给一个变量 targets 。由 targets 变量保存的名称稍后将显示为最终结果的一部分。最后,我们将三个参数,真值( y_test )、预测值( y_pred_knn、y_pred_sgd & y_pred_log )和目标名称( targets )传递给 classification_report 函数并打印出结果,如下所示。

三个分类器的分类报告(图片由作者准备)
总的来说,三种分类器在准确率、召回率和 F1 值上没有明显的差异。逻辑回归仍然是明显的赢家,恶性和良性类别的 F1 值分别为 0.98 和 0.99。此外,其 0.98 的高召回率已经证明其本身是对恶性肿瘤进行可靠检测的可靠分类器。
3.4 ROC 曲线和 AUROC
3.4.1 概念
接收器工作特性(ROC)曲线为我们提供了一种可视化方法来检查我们训练过的分类器的性能。这是一条绘制分类器的真阳性率(TPR)与其假阳性率(FPR)的曲线。如前所述,TPR 也称为召回。另一方面,FPR 是被错误预测为阳性的阴性实例的比率。
ROC 曲线示例如下:

ROC 曲线(图片由作者准备)
TPR 和 FPR 之间有一个权衡,TPR 越高,分类器产生的 FPR 越多。中间的斜虚线代表随机分类器 ROC 曲线。
一个好的分类器的 ROC 曲线应该尽可能远离对角线,朝向左上角。基于这一基本原理,我们可以通过计算曲线下面积(AUC)来衡量和比较我们的分类器的性能,这将产生一个名为 AUROC ( 受试者操作特性**下的面积)**的分数。一个完美的 AUROC 应该有 1 分,而一个随机分类器应该有 0.5 分。
3 . 4 . 2 sci kit-Learn 中的实施
Scikit-Learn 提供了一个方便的函数, plot_roc_curve ,我们可以用它来创建 roc 曲线并计算 AUROC 分数。
plot_roc_curve 函数只需要三个参数,即分类器( knn_model )、测试集( X_test )和真值( y_test ),它将自动生成 roc 曲线并实时计算我们的 knn 分类器的 AUROC 分数。

KNN 分类器的 ROC 曲线和 AUROC 分数(图片由作者准备)
让我们为 SGD 和逻辑回归分类器重复类似的步骤。

SGD 分类器的 ROC 曲线和 AUROC 分数(图片由作者准备)

Log Reg 分类器的 ROC 曲线和 AUROC 分数(图片由作者准备)
我们的逻辑回归分类器的 AUROC 达到了满分 1。通过查看我们在这里讨论的所有指标的结果,我们可以得出结论,逻辑回归分类器是三者中表现最好的。该分类器被证明是预测乳腺癌肿瘤类型的最可靠的模型。
结论
在本文中,我们已经使用上面介绍的七个度量标准完成了测量三个分类器性能的步骤。使用 Scikit-Learn 可以很容易地实现它们。Scikit-Learn 在一些性能指标中封装了大量底层复杂逻辑,它提供了一个一致的编程接口来接受输入参数并即时生成所需的结果。我希望您能从这里提供的材料中受益,它能让您在学习分类器性能指标的同时接触 Scikit-Learn(如果您还不熟悉 Scikit-Learn)。
资源
完整的源代码可以从我的 Github 库获得。
参考
- Geron,A. (2019)。使用 Scikit-Learn、Keras & TensorFlow 进行机器学习。奥莱利媒体。
- https://en.wikipedia.org/wiki/Confusion_matrix
- 【https://en.wikipedia.org/wiki/Precision_and_recall
TFRecords 实践指南
原文:https://towardsdatascience.com/a-practical-guide-to-tfrecords-584536bc786c?source=collection_archive---------2-----------------------
关于处理图像、音频和文本数据的介绍
TensorFlow 的自定义数据格式 TFRecord 真的很有用。这些文件由速度极快的 tf.data API 提供本机支持,支持分布式数据集,并利用并行 I/O。但它们起初有些令人难以招架。这篇文章是一个实践性的介绍。
概观
在下文中,我们将使用人工数据来回顾 TFRecord 文件背后的概念。记住这一点,我们就可以继续研究图像;我们将使用小型和大型数据集。扩展我们的知识,然后我们处理音频数据。最后一个大的领域是文本领域,我们也会涉及到。为了将所有这些结合起来,我们创建了一个人工的多数据类型数据集,并且,您可能已经猜到了,也将它写入 TFRecords。
TFRecord 的布局
当我开始我的深度学习研究时,我天真地将我分散在磁盘上的数据存储起来。更糟糕的是,我用数千个小文件污染了我的目录,大约只有几 KB。我当时工作的集群并不觉得有趣。加载所有这些文件花了相当长的时间。
这就是 TFRecords(或大型 NumPy 数组,就此而言)派上用场的地方:我们不是存储分散的数据,而是迫使磁盘在块之间跳转,而是简单地将数据存储在一个顺序布局中。我们可以用以下方式来形象化这个概念:

作者创建的可视化
TFRecord 文件可以看作是所有单个数据样本的包装器。每一个数据样本都被称为一个示例,本质上是一个字典,存储着一个键和我们实际数据之间的映射。
现在,看似复杂的部分是这样的:当你想把数据写到 TFRecords 时,你首先必须把你的数据转换成一个特性。这些特征是一个示例的内部组件:

作者创建的可视化
到目前为止,一切顺利。但是现在将数据存储在压缩的 NumPy 数组或 pickle 文件中有什么区别呢?两件事:TFRecord 文件是顺序存储的,由于访问时间短,可以实现快速流式传输。其次,TFRecord 文件原生集成到 TensorFlows tf.data API 中,可以轻松实现批处理、混排、缓存等功能。
另外,如果您有机会和计算资源进行多工人培训,您可以将数据集分布在您的机器上。
在代码级别,特性创建是通过这些方便的方法进行的,我们将在后面讨论这些方法:
要将数据写入 TFRecord 文件,首先要创建一个字典,该字典表示
我想把这个数据点存储在这个键下
当从 TFRecord 文件中读取时,您可以通过创建一个字典来反转这个过程,该字典说
我有这个键,用存储在这个键上的值填充这个占位符
让我们看看这是如何运作的。
图像数据,小

一只小猫。在 Unsplash 上由 Kote Puerto 拍摄的照片
图像是深度学习中的一个常见领域,MNIST [1]和 ImageNet [2]是两个众所周知的数据集。将您的图像从磁盘放入模型的方法有很多:编写一个定制的生成器,使用 Keras 的内置工具,或者从 NumPy 数组加载它。为了高效地加载和解析图像数据,我们可以求助于 TFRecords 作为底层文件格式。
过程如下:我们首先创建一些随机图像——也就是说,使用 NumPy 随机填充给定图像形状的矩阵:宽度、高度和颜色通道:
输出符合预期;我们有 100 个形状为 250x250 的图像,每个图像有三个通道:
(100, 250, 250, 3)
我们也创造一些人为的标签:
因此,我们有一个形状为(100,1)的标签数组,每个图像存储一个标签。打印出前十个标签:
(100, 1)
[[2] [4] [3] [3] [2] [4] [2] [3] [3] [0]]
为了将这些{image,label}对放入 TFRecord 文件,我们编写了一个简短的方法,获取一个图像及其标签。使用上面定义的助手函数,我们创建一个字典,在键 height 、 width 和depth——w中存储我们图像的形状,我们需要这些信息在以后重建我们的图像。接下来,我们还将实际图像存储为 raw_image 。为此,我们首先序列化数组(考虑构建一个长列表),然后将其转换为一个 bytes_feature 。最后,我们存储图像的标签。
所有这些键:值映射构成了一个示例的特性,如上所述:
既然我们已经定义了如何从一对{image,label}创建一个示例,我们需要一个函数将我们的完整数据集写入 TFRecord 文件。
我们首先创建一个 TFRecordWriter ,随后使用它将示例写入磁盘。对于每个图像和相应的标签,我们使用上面的函数来创建这样一个对象。在写入磁盘之前,我们必须对其进行序列化。在我们使用完数据后,我们关闭我们的 writer 并打印我们刚刚解析的文件数:
这就是将图像写入 TFRecord 文件所需的全部内容:
输出与预期的一样,因为我们刚刚解析了 100 个{image,label}对:
Wrote 100 elements to TFRecord
有了这个文件在我们的磁盘上,我们以后可能也会有兴趣阅读它。这也是可能的,并且是相反的:
前面,我们定义了一个用于将内容写入磁盘的字典。我们现在使用类似的结构,但这次是为了读取数据。之前,我们说过键宽度包含 int 类型的数据。因此,当我们创建字典时,我们也分配一个 int 类型的占位符。因为我们正在处理固定长度的特性(我们大部分时间都在处理这些特性;稀疏张量很少使用),我们说:
给我我们存储在键“width”中的数据,并用它填充这个占位符
类似地,我们为其他存储的特性定义了 key:placeholder 映射。然后,我们通过用 parse_single_example 解析元素来填充占位符。假设我们处理的是一个字典,我们通常可以通过访问相应的键来提取所有的值。
在最后一步中,我们必须将图像从序列化形式解析回(高度、宽度、通道)布局。注意,我们希望 out_type 为 int16,这是必需的,因为我们也是用 int16 创建映像的:
为了从解析元素中创建数据集,我们只需利用 tf.data API。我们通过将 TFRecord 文件指向磁盘上的 TF record 文件来创建一个 TFRecordDataset ,然后将我们之前的解析函数应用于每个提取的示例。这会返回一个数据集:
我们可以通过获取单个数据点来探索数据集的内容:
输出是
(250, 250, 3)
()
第一行是一个图像的形状;第二条线是标量元素的形状,它没有维度。
这标志着小型数据集解析的结束。在下一节中,我们将研究如何解析一个更大的数据集,在解析过程中创建多个 TFRecord 文件。
图像数据,大

一只大猫。照片由蒂莫西·梅恩伯格在 Unsplash 上拍摄
在上一节中,我们向单个 TFRecord 文件中写入了一个相当小的数据集。对于更大的数据集,我们可以考虑将数据分割到多个这样的文件中。
首先,让我们创建一个随机图像数据集:
下一步将创建相应的标签:
由于我们现在正在处理一个更大的数据集,我们首先必须确定我们甚至需要多少个碎片。为了计算这一点,我们需要文件总数和希望存储在单个碎片中的元素数量。我们还必须考虑这样的情况,例如,每个分片有 64 个图像和 10 个文件。这将导致 6 个碎片(6x10 ),但会丢失最后 4 个样本。我们只是通过预先添加一个额外的碎片来避免这种情况,如果我们有 60 个文件,就删除它,因为 60//10 不会留下任何余数:
下一步,我们迭代分割/碎片。我们为每个分割创建一个新的文件和 writer,相应地更新文件名。命名遵循{输出目录} {当前碎片数} _ {碎片总数} {文件名}。
对于每一个碎片,我们创建一个临时计数来跟踪我们存储在其中的所有元素。通过计算split _ numberxmax _ files+current _ shard _ count来确定下一个{image,label}对。对于我们的第一个碎片,索引将从 0 到 9;对于第二个碎片,索引将从 10 到 19,依此类推。如果索引等于元素的数量,我们只需打破循环:
准备好索引后,我们可以从相应的数组中获取图像和标签。我们重用了之前编写的 parse_single_image 函数,因为我们只改变了数据集的维度,而没有改变布局。下一步,我们将返回的示例对象写入 TFRecord 文件。最后,我们增加当前和全局计数器;最后,关闭我们的 writer:
和前面一样,我们可以通过一个函数调用来创建 TFRecord 文件:
打印语句的输出是
Using 17 shard(s) for 500 files, with up to 30 samples per shard
100%|██████████| 17/17 [00:03<00:00, 5.07it/s]
Wrote 500 elements to TFRecord
类似于我们的小数据集,我们可以从磁盘中提取较大的文件。因为我们没有改变存储的键,所以我们重用了我们的 parse_tfr_element() 方法。唯一的区别是我们有多个 TFRecord 文件,而不是只有一个。我们可以通过获取符合某个模式的所有文件的列表来处理这个问题;我们简单地搜索所有包含字符串 large_images 的 TFRecord 文件:
我们可以用下面的代码获取一个数据集并查询一个元素:
输出是预期的,一个图像的形状是(400,750,3),标签是一个标量,没有形状:
(400, 750, 3)
()
这标志着将较大的图像数据集解析为多个 TFRecord 文件并获取数据的工作已经结束。在下一节中,我们将讨论存储音频数据。
音频数据

照片由 Alexey Ruban 在 Unsplash 上拍摄
音频是第二种常用的数据类型;有各种各样的大型数据集可用。Christopher Dossman 列出了超过 1 TB 的音频数据——这只是更大的公开数据中的一部分:
对于本节,我们不会从一开始就处理 TBs。相反,我们将关注一个更小的数据集。
让我们从创建它开始,我们需要 librosa 包来完成它。我们使用 librosa 提供的示例文件,并分配一些人工标签。对于每个样本,我们存储原始音频和采样速率:
正如我们之前所做的,我们编写了一个简短的方法来帮助我们将数据放入 TFRecord 文件。因为我们将音频数据和采样率打包到一个公共数组中,所以我们必须简单地查询条目:第一个条目是音频数据,第二个条目保存采样率。
有了这些,我们就可以创建并返回一个示例对象。这里没有什么完全新的东西;方法与之前类似:
前面的函数返回一个样本,准备写入 TFRecord。下一个函数遍历所有样本,并将它们写入磁盘:
然后我们简单地调用
将我们完整的音频数据集写入磁盘。
将它存储在一个文件中,我们可以像以前一样继续:我们编写一个函数,它与向 TFRecord 编写示例的过程相反,而是读取它。这与我们用来解析图像的函数非常相似;只有键有不同的名称:
和前面一样,要创建数据集,我们只需将这个解析函数应用于 TFRecord 文件中的每个元素:
为了查询我们的数据集,我们调用这个函数并检查第一个元素:
输出是
(117601,)
tf.Tensor(0, shape=(), dtype=int64)
第一个条目是音频文件的形状;第二个条目是相应的标签。
这标志着音频数据和 TFRecord 文件工作的结束。在下一节中,我们来看看如何处理文本数据。
文本数据

由米卡·博斯韦尔在 Unsplash 上拍摄的照片
作为最后一个大域,我们有文本数据。考虑到 NLP 研究在过去三、四年中的成功——变形金刚[3]、GPT [4]、…这就不足为奇了。
我们首先创建一个虚拟数据集:
然后,我们创建数据集并查询前五个元素:
这给了我们
['Hey, this is a sample text. We can use many different symbols.',
'A point is exactly what the folks think of it; after Gauss.',
'Hey, this is a sample text. We can use many different symbols.',
'A point is exactly what the folks think of it; after Gauss.',
'Hey, this is a sample text. We can use many different symbols.']
现在我们编写一个函数,从文本数据中创建一个示例对象。过程和前面一样:我们将非标量数据存储为字节特征,将标签存储为标量。
使用下一个函数,我们迭代文本数据集和标签,并将它们写入单个 TFRecord 文件:
将我们的人工文本数据集放到磁盘上只需一个简单的调用:
在下一个函数中,我们反转这个过程,从 TFRecord 文件中获取数据。一个显著的区别是,我们希望我们的特征——文本数据——是字符串类型;因此,我们将 out_type 参数设置为 tf.string :
和以前一样,我们将每个元素都映射到这个函数:
然后我们得到一个数据集,并期待前两个元素:
输出是
b'Hey, this is a sample text. We can use many different symbols.'
tf.Tensor(0, shape=(), dtype=int64)
b'A point is exactly what the folks think of it; after Gauss.'
tf.Tensor(1, shape=(), dtype=int64)
这标志着在 TFRecord 文件的上下文中写入和读取音频数据的结束。在下一节中,我们将合并所有以前的域。
多种数据类型
到目前为止,我们已经检查了单个域。当然,没有什么反对合并多个域!对于以下内容,请考虑以下大纲:
我们有多个图像:
其次,我们对每幅图像都有一个简短的描述,描述图像显示的风景:
最后,我们还有对风景的听觉描述。我们重用上面的虚拟音频数据:
现在,让我们将它们合并到 TFRecord 文件中。我们编写一个函数,接受这些数据类型并返回一个示例对象。这是 TFRecord 格式的另一个好处:即使我们处理多种数据类型,我们也可以将所有内容一起存储在一个对象中:
如前所述,我们迭代所有数据样本并将它们写入磁盘:
创建 TFRecord 文件只是一个函数调用:
既然我们已经将这样一个例子写到磁盘上,我们通过提取特征来读回它。与上一节的主要区别在于,我们有多个特征—文本、图像和音频数据—因此我们必须分别解析它们:
获得组合数据集的代码非常简单:
让我们看看数据集中的第一个元素:
输出是
(<tf.Tensor: shape=(256, 256, 3), dtype=int16, numpy=
array([[[160, 224, 213],
...
[189, 253, 65]]], dtype=int16)>,
<tf.Tensor: shape=(), dtype=string, numpy=b'This image shows a house on a cliff. The house is painted in red and brown tones.'>,<tf.Tensor: shape=(), dtype=int64, numpy=3>,<tf.Tensor: shape=(117601,), dtype=float32, numpy=
array([-1.4068224e-03, -4.4607223e-04, -4.1098078e-04, ...,
7.9623060e-06, -3.0417003e-05, 1.2765067e-05], dtype=float32)>,<tf.Tensor: shape=(), dtype=int64, numpy=0>)
第一个元素是图像,第二个元素是图像的文本描述,第三个元素是文本的标签。最后两个元素是音频数据和音频数据的标签。
这标志着关于将多种数据类型写入 TFRecord 文件的部分到此结束。
摘要
我们讨论了将图像、音频和文本数据写入 TFRecord 文件。我们还讨论了读回这些数据。
不管实际内容如何,程序总是如下:
- 为存储在 TFRecord 文件中的数据定义字典
- 解析数据时,通过复制该字典来重建数据
- 将每个元素映射到解析函数
只有在处理大型数据集时,才需要稍加修改。在这种情况下,您必须将您的数据写入多个 TFRecord 文件,这一点我们在处理大型图像数据一节中已经介绍过。
这里有一个包含所有代码的 Colab 笔记本。
如果您有兴趣了解这种文件格式,您可以阅读我关于自定义音频数据分类的帖子。在那里,我使用 TFRecord 文件来存储我的数据集,并直接在其上训练神经网络:
文学
[1] Y. LeCun 等。,基于梯度的学习应用于文档识别 (1994),IEEE 会议录
[2] J. Deng 等,Imagenet: 大规模分层图像数据库 (2009),IEEE 计算机视觉与模式识别会议
[3] A .瓦斯瓦尼等,注意力是你所需要的全部 (2017),NIPS
[4] A .拉德福德等,通过生成性预训练提高语言理解 (2018),OpenAI
使用 QGIS 处理地理空间数据的实用指南:第 1 部分
原文:https://towardsdatascience.com/a-practical-guide-to-working-with-geospatial-data-using-qgis-part-1-561056a5a3b3?source=collection_archive---------15-----------------------

在 Unsplash 上由 Brett Zeck 拍照
介绍
最近,我开始研究一个涉及分析地理空间数据的项目。要分析这样的数据,可视化是极其重要的一步。你可以很容易地在地图上看到几个图案。如果数据包含 100 个特征,如果我们可以绘制这些特征的地图,并查看数据是否直观地有意义,那就太好了。QGIS 是一个很好的应用程序,允许分析、编辑和可视化地理数据。在本教程的第 1 部分中,我们将学习如何使用 QGIS 来显示地图和分析地理空间数据。我们还将学习对数据进行一些基本的操作。在第 2 部分中,我将讨论一些复杂的操作以及如何使用 geopandas 来操作地理空间数据。
地理数据和 QGIS 简介
地理数据包含一个几何组件,为数据在地图上提供一个位置。几何可以是不同的类型,如点/多点、线/多线和多边形/多边形。
QGIS 是一个免费的地理信息系统应用程序,支持查看、编辑和分析地理空间数据。
你可以从这里下载 QGIS。
shapefiles 有不同的格式,如。shp,。kml,。kmz,。geojson 等。你可以在这里查看所有格式:https://gisgeography.com/gis-formats/
对于本教程,我将使用一个**。来自 SEDAC 网站的 shp** 格式 shapefile。
SEDAC 是社会经济数据和应用中心。它是美国国家航空航天局(NASA)地球观测系统数据和信息系统(EOSDIS)的分布式主动档案中心(DAACs)之一。SEDAC 专注于人类在环境中的互动。
我将使用印度北方邦的村级 shapefile。它包含村庄一级的社会经济特征。你可以从这里下载。
在 QGIS 上加载/显示数据
首先,打开 QGIS 应用程序。点击“新建空项目”。您可以选择:项目->-另存为选项来保存项目。
A.加载 Shapefile 数据
要加载 shapefile,请执行以下步骤:
- 图层->添加矢量图层。
- 选择。shp 文件或选择 shapefile 所在的目录。现在,点击添加。
现在,您可以查看 shapefile。

第一步

第二步

Shapefile 的视图
要查看有关 shapefile 的信息:
- 右键单击左窗格中的 shapefile 名称。
- 点击属性->信息。在这里你可以看到关于 shapefile 的所有细节。

Shapefile 信息
B .修复几何图形(可选)
有时,shapefile 包含无效的几何。当我们试图在 shapefile 上执行一些操作时,它会给出错误“无效几何图形”。要修复几何图形,请执行以下步骤:
- 从菜单栏中,转到处理->工具箱->修复几何。选择您的形状文件。

2.点击运行
3.现在,将创建一个新的 shapefile。如果某些几何图形无效,它将修复这些几何图形。

几何图形固定的 Shapefile
我们将继续我们在这个新的形状文件上的工作。如果旧的 shapefile 没有无效的几何图形,您也可以使用它。但是,我已经知道这个 shapefile 有一些无效的几何图形。而且,它会在以后产生一些问题。
C.查看数据属性
现在,shapefile 已加载。但是我们如何知道 shapefile 中有哪些变量/属性呢?要查看属性:
- 右键单击左窗格中的 shapefile 名称。
- 点击“打开属性表”。
现在,您可以看到数据中存在的所有属性。

第一步

属性表
D.在地图上显示数据属性
让我们在地图上显示 shapefile 中的特定属性。属性可以有两种类型:离散/分类变量或连续值。
以下是实现这一点的步骤:
- 右键单击左侧窗格中的 shapefile 名称。
- 点击属性。
- 现在,点击符号。
- 在顶部,单击下拉菜单。你会看到诸如单一符号、分类、分级等选项。

5.要显示分类属性,请单击分类。
6.在它下面,有一个名为“值”的选项来选择属性。
7.我们将选择“DID ”,这是唯一的地区 ID。
8.现在,在左下角,点击“分类”。按“确定”。
您将看到类似下图的内容。

在地图上显示分类属性
9.要显示连续值,请遵循上述相同的步骤。但是,点击“毕业”,而不是“分类”。
10.现在,在“值”中,选择属性“TOT_P ”,这是总人口。
11.现在,在左下角,有一个叫做“模式”的按钮。它使用特定的模式将连续变量划分为不同的区间,如等计数、等区间、对数标度、自然突变等。
12.我们将使用“自然休息”。Natural Breaks 试图找到数据的自然分组来创建类。
13.在右下角,有一个名为“Classes”的参数。它会将变量划分为用户指定数量的区间。我们将创建 15 个类。

14.现在,点击分类。
你会看到这样的东西。

在地图上显示分级/连续属性
使用 QGIS 操作数据
我们可以使用 QGIS 执行许多操作。例如:将多边形转换为质心,基于特定属性溶解边界等。我们将在这里看到一些操作。
A.按特定属性融合几何
shapefile 中的所有几何图形都使用多边形显示。此 shapefile 还包含村庄边界。但是,如果我们想要合并每个区内的所有边界,并且只保留区边界,该怎么办呢?“溶解”操作正是这样做的。它将融合区域内的所有边界/多边形,并从中创建一个单独的区域/多边形。以下是融合边界的步骤:
- 转到矢量->地理处理工具->融合
- 现在,有一个选项融合领域。我们希望分解一个区内的所有内容,而“DID”变量是唯一的区 ID。所以,我们将通过属性“DID”来溶解。
- 在溶解属性中选择“DID”后,点击“运行”。
你会看到这样的东西-

溶解的几何图形形状文件
B.将多边形转换为质心
也可以将多边形转换为质心。我们将把这个“溶解”的 shapefile 转换成质心。
- 转到矢量->几何工具->质心
- 选择文件“溶解”并点击“运行”。
您将看到类似这样的内容:

生成质心
在 shapefile 上显示街道地图
您也可以在“溶解”的 shapefile 上显示街道地图。
- 首先,在左窗格底部,点击“浏览器”。
- 现在,在众多选项中,双击“OpenStreetMap”。
- 现在,在左窗格底部,再次点击“层”。而且,你会看到一个新的层被称为“OpenStreetMap”

开放街道地图
4.为了将溶解的地图叠加在街道地图上,勾选两个图层。然后,拖动“溶解”层以上的“OpenStreetMap”层。

5.但是,我们看不到 shapefile 后面的地图。这是因为图层的不透明度默认为 100%。我们可以设置图层的不透明度为 50%。
6.现在,右键单击溶解层。
7.转到属性->不透明度。
8.设置不透明度为 50%,点击“确定”。
现在,我们可以看到两层。您也可以放大以获得更好的视图。“放大镜”选项位于底部中间。

查看打开的街道地图以及其他 shapefile
保存形状文件
现在,让我们保存质心文件。要保存 shapefile,请按照下列步骤操作。
- 在左侧窗格中,右键单击一个特定的文件(此处为“质心”)。
- 点击导出->功能另存为。

3.现在,编写所需的输出文件名。您也可以通过选中/取消选中属性旁边的框来选择要保存的属性。

4.最后,单击确定。并且,您的文件被保存。
结论
这是针对初学者的关于如何使用 QGIS 处理地理空间数据的基础教程。现在,您知道了如何将数据加载到 QGIS 中并进行分析。我们还对数据做了一些基本的处理。我希望它对你有帮助。
后续步骤
在本文的第 2 部分,我将尝试使用 QGIS 介绍一些复杂的操作。我将讨论如何使用 geopandas 和 python 来读取和操作 shapefiles。
我希望这篇文章对你有用。
让我知道,如果你有一些关于 QGIS 的其他问题,需要帮助。我将在以后的文章中尝试介绍它们。
**非常感谢您的阅读!🙂
参考
https://earthdata.nasa.gov/eosdis/daacs/sedac https://sedac.ciesin.columbia.edu/data/set/india-india-village-level-geospatial-socio-econ-1991-2001/data-download
9 种回归算法的实用介绍
原文:https://towardsdatascience.com/a-practical-introduction-to-9-regression-algorithms-389057f86eb9?source=collection_archive---------6-----------------------
有效使用不同回归算法的实践教程

由杰森·库德里特在 Unsplash 上拍摄的照片
线性回归通常是人们学习机器学习和数据科学的第一个算法。它简单易懂,但是,由于其功能有限,它不太可能是真实世界数据的最佳选择。最常见的是,线性回归被用作基线模型来评估和比较研究中的新方法。
在处理现实问题时,您应该知道并尝试许多其他回归算法。在本文中,您将通过使用 Scikit-learn 和 XGBoost 的实践来学习 9 种流行的回归算法。这篇文章的结构如下:
- 线性回归
- 多项式回归
- 简单向量回归
- 决策树回归
- 随机森林回归
- 套索回归
- 里脊回归
- 弹性网络回归
- XGBoost 回归
请查看笔记本获取源代码。更多教程可从 Github Repo 获得。
1.线性回归
线性回归通常是人们学习机器学习和数据科学的第一个算法。线性回归是一种线性模型,假设输入变量(X)和单个输出变量(y)之间存在线性关系。一般来说,有两种情况:
- 单变量线性回归:模拟一个 单输入变量(单特征变量)和一个单输出变量之间的关系。
- 多元线性回归(也称多元线性回归):模拟多输入变量(多特征变量)和单输出变量之间的关系。
这种算法非常常见,以至于 Scikit-learn 在LinearRegression()中内置了这种功能。让我们创建一个LinearRegression对象,并使其适合训练数据:
from sklearn.linear_model import LinearRegression# Creating and Training the Model
linear_regressor = **LinearRegression()**
linear_regressor**.fit(X, y)**
一旦训练完成,我们可以检查LinearRegression在coef_属性中找到的系数参数:
linear_regressor.**coef_**array([[-0.15784473]])
现在,用这个模型为训练数据拟合一条线

sci kit-学习线性回归(图片由作者提供)
关于线性回归的几个要点:
- 快速且易于建模
- 当要建模的关系不是非常复杂,并且您没有大量数据时,这尤其有用。
- 非常直观的理解和解读。
- 它对异常值非常敏感。
2.多项式回归
多项式回归是我们想要为非线性可分数据创建模型时最流行的选择之一。这就像线性回归,但使用变量X和y之间的关系来找到绘制符合数据点的曲线的最佳方式。
对于多项式回归,一些自变量的幂大于 1。例如,我们可以提出如下的二次模型:

二次模型(作者图片)
β_0、β_1和β_2是系数x是一个变量/特征ε是偏见
Scikit-learn 在PolynomialFeatures中内置了这个方法。首先,我们需要生成一个由指定次数的所有多项式特征组成的特征矩阵:
from sklearn.preprocessing import PolynomialFeatures# We are simply generating the matrix for a quadratic model
poly_reg = PolynomialFeatures(**degree = 2**)
**X_poly** = **poly_reg.fit_transform(X)**
接下来,让我们创建一个LinearRegression对象,并将其与我们刚刚生成的特征矩阵X_poly相匹配。
# polynomial regression model
poly_reg_model = LinearRegression()
poly_reg_model.fit(**X_poly**, y)
现在采用该模型,并为训练数据X_plot拟合一条线,如下所示:

多项式回归(作者图片)
关于多项式回归的几个要点:
- 能够对非线性可分离数据建模;线性回归做不到这一点。一般来说,它更加灵活,可以模拟一些相当复杂的关系。
- 完全控制特征变量的建模(设置哪个指数)。
- 需要精心设计。需要一些数据知识,以便选择最佳指数。
- 如果指数选择不当,容易过度拟合。
3.支持向量回归
支持向量机在分类问题中是众所周知的。在回归中使用 SVM 被称为支持向量回归 (SVR)。 Scikit-learn 在SVR()中内置了这个方法。
在拟合 SVR 模型之前,通常的最佳实践是执行特征缩放,以便每个特征具有相似的重要性。首先,让我们用StandardScaler()进行特征缩放:
from sklearn.svm import SVR
from sklearn.preprocessing import StandardScaler# Performing feature scaling
scaled_X = StandardScaler()
scaled_y = StandardScaler()scaled_X = scaled_X.fit_transform(X)
scaled_y = scaled_y.fit_transform(y)
接下来,我们创建一个SVR对象,将内核设置为'rbf',将伽玛设置为'auto'。在这之后,我们调用fit()来使其符合缩放的训练数据:
svr_regressor = SVR(**kernel='rbf'**, **gamma='auto'**)
svr_regressor.fit(**scaled_X, scaled_y**.ravel())
现在采用该模型,并为训练数据scaled_X拟合一条线,如下所示:

支持向量回归(图片由作者提供)
关于支持向量回归的几个要点
- 它对异常值是鲁棒的,并且在高维空间中是有效的
- 它具有出色的泛化能力(能够恰当地适应新的、以前看不见的数据)
- 如果特征的数量远大于样本的数量,则容易过度拟合
4.决策树回归
决策树(DTs) 是一种用于分类和回归的非参数监督学习方法[1]。目标是创建一个模型,通过学习从数据特征推断的简单决策规则来预测目标变量的值。一棵树可以被看作是一个分段常数近似。
决策树回归也很常见,以至于 Scikit-learn 内置了DecisionTreeRegressor。无需特征缩放即可创建DecisionTreeRegressor对象,如下所示:
from sklearn.tree import DecisionTreeRegressortree_regressor = DecisionTreeRegressor(random_state = 0)
tree_regressor.**fit(X, y)**
现在采用该模型,并使其符合训练数据:

决策树回归(图片作者提供)
关于决策树的几个要点:
- 易于理解和解释。树木可以被可视化。
- 适用于分类值和连续值
- 使用 DT(即预测数据)的成本是用于训练树的数据点数量的对数
- 决策树的预测既不平滑也不连续(显示为分段常数近似,如上图所示)
5.随机森林回归
基本上,随机森林回归与决策树回归非常相似。它是一种元估计器,可以在数据集的各种子样本上拟合许多决策树,并使用平均来提高预测准确性和控制过度拟合。
随机森林回归器在回归中的表现不一定比决策树好(虽然它通常在分类中表现更好),因为在树构造算法的本质中存在微妙的过拟合-欠拟合权衡。
随机森林回归非常普遍,以至于 Scikit-learn 将它内置于RandomForestRegressor中。首先,我们需要创建一个具有指定数量估算器的RandomForestRegressor对象,如下所示:
from sklearn.ensemble import **RandomForestRegressor**forest_regressor = RandomForestRegressor(
**n_estimators = 300**,
random_state = 0
)
forest_regressor.fit(X, y.ravel())
现在采用该模型,并使其符合训练数据:

随机森林回归(图片作者提供)
关于随机森林回归的几点:
- 减少决策树中的过度拟合并提高准确性
- 它也适用于分类值和连续值
- 需要大量的计算能力和资源,因为它适合多个决策树来组合它们的输出
6.套索回归
套索回归是使用收缩的线性回归的变体。收缩是数据值向中心点收缩为平均值的过程。这种类型的回归非常适合显示高度多重共线性(要素之间的高度相关性)的模型。
Scikit-learn 内置了LassoCV。
from sklearn.linear_model import LassoCVlasso = LassoCV()
lasso.fit(X, y.ravel())
现在采用该模型,并使其符合训练数据:

拉索回归(图片由作者提供)
关于拉索回归的几点:
- 它最常用于消除自动化变量和选择特性。
- 它非常适合显示高度多重共线性(要素之间的高度相关性)的模型。
- 套索回归利用 L1 正则化
- LASSO 回归被认为比 Ridge 更好,因为它只选择一些要素,而将其他要素的系数降低到零。
7.里脊回归
岭回归与套索回归非常相似,因为两种技术都使用收缩。岭回归和套索回归都非常适合显示高度多重共线性(要素之间的高度相关性)的模型。它们之间的主要区别是 Ridge 使用 L2 正则化,这意味着没有一个系数会像 LASSO 回归中那样变为零(而是接近零)。
Scikit-learn 内置了RidgeCV。
from sklearn.linear_model import RidgeCVridge = RidgeCV()
ridge.fit(X, y)
现在采用该模型,并使其符合训练数据:

岭回归(图片作者提供)
关于岭回归的几点:
- 它非常适合显示高度多重共线性(要素之间的高度相关性)的模型。
- 岭回归使用 L2 正则化。贡献较小的特征将具有接近零的系数。
- 由于 L2 正则化的性质,岭回归被认为比拉索差
8.弹性网络回归
ElasticNet 是另一个用 L1 和 L2 正则化训练的线性回归模型。它是套索和岭回归技术的混合,因此也非常适合显示严重多重共线性(要素之间的严重相关性)的模型。
在套索和脊之间进行权衡的一个实际优势是,它允许弹性网在旋转下继承脊的一些稳定性[2]。
Scikit-learn 内置了ElasticNetCV。
from sklearn.linear_model import ElasticNetCV
elasticNet = ElasticNetCV()
elasticNet.fit(X, y.ravel())
现在采用该模型,并使其符合训练数据:

ElasticNet 回归(图片由作者提供)
关于 ElasticNet 回归的几个要点:
- ElasticNet 总是优于 LASSO 和 Ridge,因为它解决了这两种算法的缺点
- ElasticNet 带来了确定最优解的两个 lambda 值的额外开销。
9.XGBoost 回归
极限梯度提升 ( XGBoost )是梯度提升算法的一种高效且有效的实现。梯度提升是指一类集成机器学习算法,可用于分类或回归问题。
XGBoost 是一个开源库,最初由陈天琦在他 2016 年题为“ XGBoost:一个可扩展的树增强系统”的论文中开发。该算法被设计成计算效率高且高效。
如果尚未安装 XGBoost 库,第一步是安装它。
pip install xgboost
XGBoost 模型可以通过创建一个XGBRegressor的实例来定义:
from xgboost import XGBRegressor
# create an xgboost regression model
model = **XGBRegressor(
n_estimators=1000,
max_depth=7,
eta=0.1,
subsample=0.7,
colsample_bytree=0.8,
)**model.fit(X, y)
**n_estimators**:集合中的树的数量,经常增加直到看不到进一步的改进。**max_depth**:每棵树的最大深度,通常取值在 1 到 10 之间。**eta**:用于加权每个模型的学习率,通常设置为 0.3、0.1、0.01 或更小的小值。**subsample**:每棵树使用的样本数,设置为 0-1 之间的值,通常为 1.0 表示使用所有样本。**colsample_bytree**:每个树中使用的特征(列)的数量,设置为 0 到 1 之间的值,通常为 1.0 以使用所有特征。
现在采用该模型,并使其符合训练数据:

XGBoost 回归(图片由作者提供)
关于 XGBoost 的几点:
- XGBoost 在稀疏和非结构化数据上表现不佳。
- 该算法被设计为计算效率高且高效,但是对于大数据集来说,训练时间仍然相当长
- 它对异常值很敏感
结论
在本文中,我们通过使用 Scikit-learn 和 XGBoost 的实践,介绍了 9 种流行的回归算法。在您的工具箱中拥有它们是很好的,这样您就可以尝试不同的算法,并为现实世界的问题找到最佳的回归模型。
我希望你喜欢这篇文章,并学到一些新的有用的东西。
感谢阅读。请查看笔记本获取源代码,如果你对机器学习的实用方面感兴趣,请继续关注。更多教程可从 Github Repo 获得。
参考文献:
- [1]sci kit-学习决策树文档:https://scikit-learn.org/stable/modules/tree.html#tree
- [2] Scikit-Learn ElasticNet 文档:https://sci kit-Learn . org/stable/modules/linear _ model . html # elastic-net
网格搜索、随机搜索和贝叶斯搜索的实用介绍
原文:https://towardsdatascience.com/a-practical-introduction-to-grid-search-random-search-and-bayes-search-d5580b1d941d?source=collection_archive---------10-----------------------
在机器学习中有效使用超参数调整的实践教程

由路易斯·汉瑟在 Unsplash 上拍摄的照片
在机器学习中,超参数是指无法从数据中学习到,需要在训练前提供的参数。机器学习模型的性能在很大程度上依赖于找到最优的超参数集。
超参数调整基本上是指调整模型的超参数,这基本上是一个长度过程。在本文中,您将学习 3 种最流行的超参数调优技术:网格搜索、随机搜索和贝叶斯搜索。这篇文章的结构如下:
- 获取和准备数据
- 网格搜索
- 随机搜索
- 贝叶斯搜索
- 结论
请查看笔记本获取源代码。更多教程可以从 Github Repo 获得。
1.获取和准备数据
为了进行演示,我们将使用来自 Scikit Learn 的内置乳腺癌数据来训练一个支持向量分类器 (SVC)。我们可以用load_breast_cancer函数得到数据:
from sklearn.datasets import **load_breast_cancer****cancer = load_breast_cancer()**
接下来,让我们为特性和目标标签创建df_X和df_y,如下所示:
# Features
df_X = pd.DataFrame(cancer['data'], columns=cancer['feature_names'])# Target label
df_y = pd.DataFrame(cancer['target'], columns=['Cancer'])
另外,如果你想了解更多关于数据集的信息,你可以运行print(cancer['DESCR'])来打印出概要和特性信息。
之后,让我们使用training_test_split()将数据集分成训练集(70%)和测试集(30%):
# Train test split
from sklearn.model_selection import train_test_split
import numpy as npX_train, X_test, y_train, y_test = train_test_split(df_X, np.ravel(df_y), test_size=0.3)
我们将训练一个支持向量分类器 (SVC)模型。正则化参数C和核系数gamma是 SVC 中两个最重要的超参数:
- 正则化参数
C决定正则化的强度。 - 内核系数
gamma控制内核的宽度。SVC 默认使用径向基函数(RBF) 核(也称为高斯核)。
我们将在下面的教程中调整这两个参数。
2.网格搜索
很难找到C和gamma的最佳值。最简单的解决方案是尝试多种组合,看看哪种效果最好。这种创建参数“网格”并尝试所有可能组合的想法被称为网格搜索。

网格搜索——尝试所有可能的组合(图片由作者提供)
这种方法很常见,Scikit-learn 在GridSearchCV中内置了这种功能。CV 代表交叉验证,这是另一种评估和改进我们的机器学习模型的技术。
GridSearchCV采用描述应该尝试的参数的字典和要训练的模型。参数网格被定义为一个字典,其中键是参数,值是要测试的设置。让我们首先定义我们的候选人C和gamma如下:
param_grid = {
'C': [0.1, 1, 10, 100, 1000],
'gamma': [1, 0.1, 0.01, 0.001, 0.0001]
}
接下来,让我们创建一个GridSearchCV对象,并使其适合训练数据。
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVCgrid = **GridSearchCV(SVC(), param_grid, refit=True, verbose=3)**
grid.**fit(X_train,y_train)**

作者图片
一旦训练完成,我们可以检查GridSearchCV在best_params_属性中找到的最佳参数,以及best_estimator_属性中的最佳估计器:
# Find the best paramters
>>> **grid.best_params_**{'C': 1, 'gamma': 0.0001}# Find the best estimator
>>> **grid.best_estimator_**SVC(C=1, gamma=0.0001)
现在,利用这个网格模型,使用测试集创建一些预测,并为它们创建分类报告和混淆矩阵。

3.随机搜索
网格搜索尝试超参数的所有组合,因此增加了计算的时间复杂度,并且可能导致不可行的计算成本。提供了一个更便宜的选择,随机搜索只测试你选择的元组。超参数值的选择是完全随机的。

随机搜索尝试随机组合(作者图片)
这种方法也很常见,Scikit-learn 在RandomizedSearchCV中内置了这种功能。函数 API 和GridSearchCV很像。
首先,让我们指定参数C & gamma和样本分布如下:
import scipy.stats as stats
from sklearn.utils.fixes import loguniform# Specify parameters and distributions to sample from
param_dist = {
'C': **stats.uniform(0.1, 1e4)**,
'gamma': **loguniform(1e-6, 1e+1)**,
}
接下来,让我们用参数n_iter_search创建一个RandomizedSearchCV对象,并使其适合训练数据。
**n_iter_search = 20**
random_search = **RandomizedSearchCV**(
SVC(),
param_distributions=param_dist,
**n_iter=n_iter_search,**
refit=True,
verbose=3
)
**random_search.fit(X_train, y_train)**

RandomizedSearchCV fit()输出示例(图片由作者提供)
类似地,一旦训练完成,我们可以检查由best_params_属性中的RandomizedSearchCV找到的最佳参数,以及在best_estimator_属性中的最佳估计器:
>>> **random_search.best_params_**{'C': 559.3412579902997, 'gamma': 0.00022332416796205752}>>> **random_search.best_estimator_**SVC(C=559.3412579902997, gamma=0.00022332416796205752)
最后,我们采用随机搜索模型,使用测试集创建一些预测,并为它们创建分类报告和混淆矩阵。

预测随机搜索并创建报告(图片由作者提供)
4.贝叶斯搜索
贝叶斯搜索使用贝叶斯优化技术来模拟搜索空间,以尽快达到优化的参数值。它利用搜索空间的结构来优化搜索时间。贝叶斯搜索方法使用过去的评估结果对最有可能给出更好结果的新候选人进行采样(如下图所示)。

贝叶斯搜索(作者图片)
Scikit-Optimize 库附带 BayesSearchCV 实现。
首先,让我们如下指定参数C & gamma和样本分布:
from skopt import BayesSearchCV
# parameter ranges are specified by one of below
from skopt.space import Real, Categorical, Integersearch_spaces = {
'C': **Real(0.1, 1e+4)**,
'gamma': **Real(1e-6, 1e+1, 'log-uniform')**,
}
接下来,让我们用参数n_iter_search创建一个BayesSearchCV对象,并使其适合训练数据。
n_iter_search = 20
bayes_search = BayesSearchCV(
SVC(),
search_spaces,
n_iter=n_iter_search,
cv=5,
verbose=3
)
bayes_search.fit(X_train, y_train)

作者图片
类似地,一旦训练完成,我们可以检查BayesSearchCV在best_params_属性中找到的最佳参数,以及best_estimator_属性中的最佳估计器:
>>> **bayes_search.best_params_**OrderedDict([('C', 0.25624177419852506), ('gamma', 0.00016576008531229226)])>>> **bayes_search.best_estimator_**SVC(C=0.25624177419852506, gamma=0.00016576008531229226)
最后,我们采用贝叶斯搜索模型,使用测试集创建一些预测,并为它们创建分类报告和混淆矩阵。

作者图片
5.结论
在本文中,我们讨论了 3 种最流行的超参数优化技术,这些技术用于获得优化的超参数集,从而训练一个健壮的机器学习模型。
一般来说,如果组合的数量足够有限,我们可以使用网格搜索技术。但是当组合的数量增加时,我们应该尝试随机搜索或贝叶斯搜索,因为它们计算量不大。
希望这篇文章能帮助你节省学习机器学习的时间。我建议你去看看他们的 APIs,2]并了解你可以做的其他事情。
感谢阅读。请查看笔记本获取源代码,如果您对机器学习的实用方面感兴趣,请继续关注。
参考文献:
- [1]sci kit-Learn docs:https://sci kit-Learn . org/stable/auto _ examples/model _ selection/plot _ randomized _ search . html
- [2]sci kit-Optimize docs:https://sci kit-Optimize . github . io/stable/modules/generated/skopt。BayesSearchCV.html
熊猫系列实用介绍
原文:https://towardsdatascience.com/a-practical-introduction-to-pandas-series-9915521cdc69?source=collection_archive---------8-----------------------
你所需要知道的熊猫系列——数据框架的基本构件。

熊猫系列实用介绍(作者使用canva.com图片)
数据帧和系列是 Pandas 中的两个核心数据结构。 DataFrame 是带有行和列的二维标签数据。它就像一个电子表格或 SQL 表。系列是一维标签数组。这有点像 Python 列表的更强大版本。理解序列非常重要,不仅因为它是核心数据结构之一,还因为它是数据帧的构建块。
在本文中,您将学习 Pandas 系列最常用的数据操作,并且应该可以帮助您开始使用 Pandas。这篇文章的结构如下:
- 创建系列
- 检索元素
- 属性(常用)
- 方法(常用)
- 使用 Python 内置函数
源代码请查看笔记本。
1.创建系列
1.1 来自 Python 列表
Python 列表可以传递给 Pandas Series()函数来创建一个系列。
companies = ['Google', 'Microsoft', 'Facebook', 'Apple']pd.Series(companies)0 Google
1 Microsoft
2 Facebook
3 Apple
dtype: **object**
注意事项:
- 所有值的显示顺序与它们在原始 Python 列表中的显示顺序完全相同。
dtype表示对象(是字符串的内部熊猫行话)。- 还有一个额外的列叫做索引。在这种情况下,它类似于 Python 列表中的索引。但是 Pandas 系列的一个主要优点是索引标签不必是数字,它们可以是任何数据类型。
我们可以使用参数index来指定一个自定义索引:
# Pass number
pd.Series(companies,**index=[100,101,102,103]**)**100** Google
**101** Microsoft
**102** Facebook
**103** Apple
dtype: object # Pass string
pd.Series(companies,**index=['GOOGL','MSFT','FB','AAPL']**)
**GOOGL** Google
**MSFT** Microsoft
**FB** Facebook
**AAPL** Apple
dtype: object
1.2 来自字典
一个字典可以传递给熊猫Series()函数。如果没有指定index,字典键将按照排序的顺序构造索引。
companies = {
**'a': 'Google',
'b': 'Microsoft',
'c': 'Facebook',
'd': 'Apple'**
}
pd.Series(companies)**a Google
b Microsoft
c Facebook
d Apple**
dtype: object
如果指定了index,则index中标签对应的数据中的值将被取出。
pd.Series(
companies,
**index=['a', 'b', 'd']**
)**a** Google
**b** Microsoft
**d** Apple
dtype: object
1.3 从标量
如果输入是标量值,那么必须提供参数index。该值将被重复以匹配index的长度:
pd.Series(**10**, index=[100, 101, 102, 103])100 10
101 10
102 10
103 10
dtype: int64
1.4 来自熊猫的read_csv()功能
默认情况下,Pandas read_csv()函数将数据作为数据帧导入。它将整个数据集加载到内存中,当导入一个巨大的 CSV 文件时,这可能是一个内存和性能问题。
pd.read_csv('data.csv')

pd.read_csv(‘data.csv’)结果(图片由作者提供)
如果我们想将数据导入到系列中,而不是数据帧,我们可以提供额外的参数usecols和squeeze。squeeze=True将一列的数据帧转换成一个序列。
pd.read_csv('data.csv', **usecols=['product']**, **squeeze=True**)0 A
1 B
2 C
3 D
Name: product, dtype: object
请看看下面这篇关于熊猫的文章read_csv()
2.检索元素
2.1 带位置
传递索引以检索元素,例如,第一个元素。
s = pd.Series([1,2,3,4,5],index = ['a','b','c','d','e'])s[**0**]
1
检索第一个*n*元素,例如,前 3 个元素
s[**:3**]a 1
b 2
c 3
dtype: int64
检索最后一个n元素。
s[**-3:**]c 3
d 4
e 5
dtype: int64
检索某个范围内的元素
s[**2:4**]c 3
d 4
dtype: int64
逐步检索元素
s[**::2**]a 1
c 3
e 5
dtype: int64
2.2 带索引标签
熊猫系列是一个一维标签数组,我们可以通过索引标签访问元素。
使用索引标签检索单个元素。
s = pd.Series([1,2,3,4,5],index = ['a','b','c','d','e'])s[**'a'**]
1
使用索引标签列表检索多个元素。
s[**['a','c','d']**]a 1
c 3
d 4
dtype: int64
3.属性
Python 中的对象有属性和方法。属性是一种我们可以用来查找信息的方式,而不需要操作或破坏任何东西。方法实际上对对象做了些什么。它可能是操纵它,或者添加值,或者用对象的值做一些计算。
熊猫系列只是 Python 对象的一种类型。在这一节中,我们将介绍熊猫系列中一些常用的属性。
我们先来创作一个熊猫系列。
companies = ['Google', 'Microsoft', 'Facebook', 'Apple']
s = pd.Series(companies)
3.1 值和索引
属性返回序列中所有值的数组。
s.**values**array(['Google', 'Microsoft', 'Facebook', 'Apple'], dtype=object)
属性返回一个RangeIndex对象。我们可以看到它从 0 开始,到 4 结束。最后一部分叫做步长,它告诉我们它的增量是 1
s.**index**RangeIndex(start=0, stop=4, step=1)
**is_unique**属性返回一个布尔值(True或False)。这是检查每个序列值是否唯一的一种非常方便的方法。
s.**is_unique**True
3.2 数据类型和大小
**dtype**属性返回数据类型。它给了我们'O',它是 object 的缩写。
s.**dtype**dtype('O')
**size**属性返回一个系列中的项目数。
s.**size**4
**shape**属性根据元组中的列数返回行数
s.**shape**(4,)
我们还有**ndim**属性,它是维数的缩写,一个序列总是一个一维对象
s.**ndim**1
4.方法
上面提到的方法实际上对对象做了一些事情。它可能是操纵它,或者添加值,或者用对象的值做一些计算。
4.1 显示行
head()和tail()方法分别返回第一行和最后一行*n*。*n*如果不给出任何值,默认为 5。它们对于快速验证数据很有用,例如在排序或追加行之后。
prices = [10, 5, 3, 2.5, 8, 11]
s = pd.Series(prices)s.**head()**0 10.0
1 5.0
2 3.0
3 2.5
4 8.0
dtype: float64s.**head(2)**0 10.0
1 5.0
dtype: float64s.**tail(2)**
4 8.0
5 11.0
dtype: float64
4.2 执行聚合
我们可以对mean()、sum()、product()、max()、min()、median()等系列进行聚合
s.**mean()**s.**sum()**s.**product()**
如果我们需要多个聚合,我们可以在一个列表中将它们传递给agg()方法
s.**agg(['mean','sum','product'])**mean 6.583333
sum 39.500000
product 33000.000000
dtype: float64
4.3 计数值
unique()和nunique()方法分别返回唯一值和唯一值的数量。
s = pd.Series(['a','b','b','a','a'])**s.unique()**
array(['a', 'b'], dtype=object)**s.nunique()**
2
value_counts()方法返回一个序列中每个唯一值出现的次数。了解数值分布的概况是很有用的。
**s.value_counts()**a 3
b 2
dtype: int64
4.4 按值或索引标签排序
sort_values()方法根据某种标准对一个系列进行升序或降序排序。
# ascending by default
s.sort_values()# To sort it in descenting order
s.sort_values(**ascending=False**)# To modify the original series
s.sort_values(**inplace=True**)
sort_index()方法通过索引标签对序列进行排序。它类似于sort_value()。
# ascending by default
s.sort_index()# To sort it in descenting order
s.sort_index(**ascending=False**)# To modify the original series
s.sort_index(**inplace=True**)
4.5 处理缺失值
isna()方法返回一个相同大小的布尔对象,指示值是否丢失。
s = pd.Series([1, 2, 3, np.nan, np.nan])
**s.isna()**0 False
1 False
2 False
3 True
4 True
dtype: bool
我们可以通过用sum()方法链接结果来计算缺失值的数量。
**s.isna().sum()**
2
count()方法返回序列中非缺失值的个数。
s.count()
3
4.6 搜索值
nlargest()和nsmallest()方法返回序列中的最大值和最小值。默认情况下,如果您不给出任何值,它将显示 5 个结果。
s.**nlargest()**s.**nlargest(2)**
有一些逻辑运算符方法:
gt():大于ge():大于等于eq():平等le():小于或等于lt():小于ne():不相等
它们分别相当于>、>=、=、<=、<和!=,但支持用fill_value替换缺失值。
s.le(5, **fill_value=0**) s <= 5
5.使用 Python 内置函数
len()和type()是针对大小和数据类型的 Python 内置函数。
**len(s)**
6**type(s)**
pandas.core.series.Series
dir()目录的简称。如果我们向它传递一个序列,它会给出所有可用属性和方法的输出。
**dir(s)**['T',
'_AXIS_LEN',
'_AXIS_NAMES',
'_AXIS_NUMBERS',
'_AXIS_ORDERS',
'_AXIS_REVERSED',
'_AXIS_TO_AXIS_NUMBER',
'_HANDLED_TYPES',
'__abs__',
....]
要浓缩一个系列,我们可以使用内置的list()函数。我们传递一个列表给Series(),这是一种完全相反的操作。
**list(s)**[10.0, 5.0, 3.0, 2.5, 8.0, 11.0]
类似地,dict()是我们向Series()传递字典时的反向操作
**dict(s)**{0: 10.0, 1: 5.0, 2: 3.0, 3: 2.5, 4: 8.0, 5: 11.0}
Python in关键字返回一个布尔值,将您提供的值与列表中的值进行比较。如果它存在于这些值中,它将返回True,如果不存在,它将返回False。
2.5 **in s**False
2.5 in s返回False,因为默认情况下,Pandas 将在索引标签中查找,而不是在序列中查找实际值。只需确保添加额外的values属性:
2.5 **in s.values**True
结论
Pandas 系列是 Pandas 中的核心数据结构,也是数据框架的基本构件。本文从 5 个方面介绍了 Pandas 系列常用的数据操作。
我希望这篇文章能帮助你节省学习熊猫的时间。当然,熊猫系列有更多的属性和方法可以使用。我建议你查看一下 API 文档并了解你可以做的其他事情。
感谢阅读。请查看笔记本获取源代码,如果您对机器学习的实用方面感兴趣,请继续关注。
你可能会对我的其他一些熊猫文章感兴趣:
- 使用熊猫方法链接提高代码可读性
- 如何对熊猫数据帧进行自定义排序
- 何时使用 Pandas transform()函数
- 你应该知道的熊猫串联()招数
- Pandas 中 apply()和 transform()的区别
- 所有熊猫合并()你应该知道
- 在 Pandas 数据帧中处理日期时间
- 熊猫阅读 _csv()你应该知道的招数
- 用 Pandas read_csv()解析日期列应该知道的 4 个技巧
更多教程可以在我的 Github 上找到
数据科学家模拟建模实用介绍
原文:https://towardsdatascience.com/a-practical-introduction-to-simulation-modelling-for-data-scientists-a5e32cec0304?source=collection_archive---------10-----------------------
几十年来,模拟一直被用于改善物流、供应链管理和制造等领域的运营。然而,今天大多数数据科学家可能并不熟悉它。在本文中,我们将使用模拟改进操作,并使用建模软件 AnyLogic 解释统计输出。

Marcin Jozwiak 在 Unsplash 上拍摄的照片
但是首先,让我们介绍一下模拟建模的世界
仿真建模是一种研究方法,旨在模拟虚拟环境中的物理系统,并从中获取有用的输出统计数据。例如,一个系统可以是一个群体、一个机场或一个货运卡车运输队。
模拟建模也用于改进分析。这通常是通过对模拟系统进行修改来完成的,以在实际投入使用之前,看看是否可以在虚拟模型中进行改进。这使得它成为决策支持和风险缓解的强大工具。总之,模拟非常适用于描述和改进系统。
在模拟建模中,有三个主要框架:
- 离散事件模拟
- 系统动力学
- 基于主体的建模(ABM)
DES 的范围很窄,主要处理流程。典型的应用领域是制造、物流和运营规划。
SD 范围更广,处理更多的聚合系统。典型的应用是人口、流行病和经济。
ABM 的范围可以有所不同,旨在研究系统中的代理如何随时间改变状态。应用范围非常广泛,并且该框架与 DES 和 SD 结合使用效果良好。
如今有许多强大的模拟软件/软件包可供数据科学家使用。其中包括 AnyLogic 、 Arena 和 Simul8 以及 python 和 R 包 SimPy 和smell。当选择一个适合你的时候,要认真考虑你正在解决的问题。较重的商业软件非常适合包含动画和验证输出,但是它通常缺乏基于脚本的包所能实现的复杂性和灵活性。
让我们进入一个简短的案例研究,看看我们如何在 DES 框架内使用模拟来改进流程。
案例研究
考虑下图中装配工厂的两步流程:

从图中我们可以看到,货物每 5 天到达一次。之后,装运被装配,装配时间正态分布为 N(6,1)。最后,组装的装运以 N(5,1)的操作时间包装,并离开系统。
乍一看,我们可以看到装配时间平均比系统的到达率长。因此,我们应该看到在装配站有一些排队等候的人。
使用流程建模库在 AnyLogic 中对此进行建模,为我们提供了以下模型:

该模型的结构由 10 个模块组成。块源和接收器是系统的起点和终点。在源之后,我们有三个模块分配给组件,同样用于包装。这三个块被称为抓住、延迟和释放。这种结构保证了当装配工和打包机的产能闲置*时,新的出货可以进入运行。*它还确保如果一个进程繁忙,在操作之前形成一个队列。
为每个流程分配一个工人,并运行模拟 180 天,我们将得到以下带有固定种子的输出:

从模拟输出中,我们可以看到 36 个装运(源块)进入系统,只有 28 个装运(接收器块)离开系统。我们还可以看到,目前有 6 批货物正在等待组装,1 批正在组装,1 批正在包装。最后,我们还可以看到,装配工人 97%的时间在忙,包装工人 60%的时间在忙。显然,装配操作是限制生产量的瓶颈。
( NB :尽管我们应该理想地运行大约 1000+次模拟来获得这些数字的有效估计,但我们将保持简单,只运行一次模拟)
因此,作为一名数据科学家,你必须弄清楚的是:
- 我们怎样才能缩短排队的时间?
- 我们怎样才能提高系统的效率?
- 我们怎样才能防止装配工人累垮呢?
让我们考虑我们可以做出的三个决定:
- 再雇一个装配工人
- 使装配操作平均快 1 天
- 两样都做 1。第二。
1。雇用另一名装配工人的产量

这个决定似乎并没有给系统增加多少价值。生产量只增加了一个单位(从 28 个增加到 29 个),装配工人似乎仍然超负荷工作,利用率高达 93%。
2。装配作业平均快 1 天的产量

这一决定增加了系统的吞吐量,出货 4 次(从 28 次增加到 32 次),但是,在这种情况下,装配工人似乎也超负荷工作,利用率为 94%。
3。双管齐下的产出 1。第二。

现在的生产量相当稳定,为 34,装配工人不像以前那样超负荷工作,利用率为 50%。有趣的是,23%的瓶颈似乎转向了包装过程。积分利用率更高!
那么这项研究的结论是什么?我们要做决定 3 吗?
——不一定。为了给出更有把握的答案,应该收集额外的数据,例如雇佣额外工人的成本、提高操作速度的成本以及将货物排队等待的成本。时间单位
该模型可以进一步扩展,以提供更强大的决策支持,这就是模拟建模的魅力所在。诸如此类的决定可以在一个无风险环境中进行实验,随着问题的进展,可以对模型进行修改。
有关本文中使用的 AnyLogic PLE 和流程建模库的更多信息,请查看以下链接:
https://www.anylogic.com/
https://www . any logic . com/features/libraries/process-modeling-library/
13 个 Python 片段中的 Matplotlib 实用摘要
原文:https://towardsdatascience.com/a-practical-summary-of-matplotlib-in-13-python-snippets-4d07f0011bdf?source=collection_archive---------7-----------------------

图片由来自 Pixabay 的 Yvette W 提供
Python 中基本数据可视化的基本脚本
Matplotlib 是 Python 中数据可视化的基础。为了最大限度地利用它,人们需要练习它的多种特性和功能,以便能够随意定制情节。
在本文中,我将向您展示总结 Matplotlib 基础知识的 13 个脚本
[[2021 年更新]]
如果你愿意,你可以看看我在 Youtube 上关于这个话题的视频:
用图形和轴绘制基础
import matplotlib.pyplot as plt
import numpy as npfig,axs = plt.subplots(figsize=(15,7))
data1 = np.random.normal(0,1,100)
data2 = np.random.normal(0,1,100)
data3 = np.random.normal(0,1,100)
x_ax = np.arange(0,100,10)
y_ax = np.arange(-3,3,1)
axs.plot(data1,marker="o")
axs.plot(data2,marker="*")
axs.plot(data3,marker="^")
axs.set_xticks(x_ax)
axs.set_xticklabels(labels=x_ax,rotation=45)
axs.set_yticks(y_ax)
axs.set_yticklabels(labels=y_ax,rotation=45)
axs.set_xlabel("X label")
axs.set_ylabel("Y label")
axs.set_title("Title")
axs.grid("on")

面向对象(OO)风格与 Pyplot 风格
如文档中所述,使用 Matplotlib 主要有两种方式:
- OO 风格 :显式创建图形和轴,并对其调用方法
- Pyplot 式 :依靠 Pyplot 模块自动创建和管理图形和轴。
面向对象风格
import matplotlib.pyplot as plt
import numpy as np
x = np.cos(np.linspace(0, 2, 100)) # Create the data
# Note that even in the OO-style, we use `.pyplot.figure` to create the figure.
fig, ax = plt.subplots() # Create a figure and an axes with pyplot.subplots()
ax.plot(x, x, label='linear') # Plot some data on the axes.
ax.plot(x, x**2, label='quadratic') # Plot more data on the axes...
ax.plot(x, x**3, label='cubic') # ... and some more.
ax.set_xlabel('x label') # Add an x-label to the axes.
ax.set_ylabel('y label') # Add a y-label to the axes.
ax.set_title("Simple Plot") # Add a title to the axes.
ax.legend(); # Add a legend.

Pyplot 风格
import matplotlib.pyplot as plt
import numpy as npx = np.cos(np.linspace(0, 2, 100)) # Create the data
plt.plot(x, x, label='linear') # Plot some data on the (implicit) axes.
plt.plot(x, x**2, label='quadratic') # same pipeline but using pyplot.plot directly
plt.plot(x, x**3, label='cubic')
plt.xlabel('x label')
plt.ylabel('y label')
plt.title("Simple Plot")
plt.legend();

何时使用面向对象风格还是 pyplot 风格
Matplotlib 文档中的例子使用了这两种方法,但是强调最好选择其中一种并坚持使用。建议是 将 pyplot 限制为交互式绘图(例如,在 Jupyter 笔记本中),并且对于非交互式绘图 更喜欢 OO 风格。
Matplotlib 图的推荐函数签名
# source: https://matplotlib.org/stable/tutorials/introductory/usage.html#sphx-glr-tutorials-introductory-usage-pyimport matplotlib.pyplot as plt
import numpy as npdef my_plotter(ax, data1, data2, param_dict):
"""
A helper function to make a graph
Parameters
----------
ax : Axes
The axes to draw to
data1 : array
The x data
data2 : array
The y data
param_dict : dict
Dictionary of kwargs to pass to ax.plot
Returns
-------
out : list
list of artists added
"""
out = ax.plot(data1, data2, **param_dict)
return out
data1, data2, data3, data4 = np.random.randn(4, 100)
fig, ax = plt.subplots(1, 1)
my_plotter(ax, data1, data2, {'marker': 'x'})
# 2 sub-plots example
fig, (ax1, ax2) = plt.subplots(1, 2)
my_plotter(ax1, data1, data2, {'marker': 'x'})
my_plotter(ax2, data3, data4, {'marker': 'o'});


格式化您的绘图样式
import matplotlib.pyplot as plt
import numpy as np
t = np.sin(np.linspace(-3,3,50))
# red dashes, blue squares and green triangles
plt.plot(t, t, 'r--', color="red")
plt.plot(t, t**2, 'bs', color="blue")
plt.plot(t, t**3, 'g^', color="green")
plt.plot(t, t**4, "o", color="orange")
plt.plot(t, t**5, "o-", color="black")
plt.show()

查看更多信息
- 在 matplotlib 中自定义样式表
- pyplot.setp 文档
- 控制线属性
使用关键字字符串绘图(来自字典)
# source: https://matplotlib.org/stable/gallery/misc/keyword_plotting.htmlimport matplotlib.pyplot as plt
import numpy as npdata = {'a': np.arange(50),
'c': np.random.randint(0, 50, 50),
'd': np.random.randn(50)}
data['b'] = data['a'] + 10 * np.random.randn(50)
data['d'] = np.abs(data['d']) * 100
plt.scatter('a', 'b', c='c', s='d', data=data)
plt.xlabel('entry a')
plt.ylabel('entry b')
plt.show()

绘制分类变量
import matplotlib.pyplot as plt
import numpy as npnames = ['cats', 'dogs', 'dragons']
values = [5, 25, 125]
plt.figure(figsize=(15, 7))
plt.subplot(131)
plt.bar(names, values, color="red", label="bar chart")
plt.legend()
plt.subplot(132)
plt.scatter(names, values, color="orange", label="scatter plot")
plt.legend()
plt.subplot(133)
plt.plot(names, values, color="green", label="line plot")
plt.legend()
plt.suptitle('Categorical Plots')
plt.show()

使用多个图形
import matplotlib.pyplot as plt
import numpy as npdef f(t):
return np.exp(-t) * np.cos(2*np.pi*t)
t1 = np.arange(0.0, 5.0, 0.1)
t2 = np.arange(0.0, 5.0, 0.2)
plt.figure()
plt.subplot(2,2,1)
plt.plot(t1, f(t1), 'black')
plt.subplot(2,2,2)
plt.plot(t2, np.tan(2*np.pi*t2), 'r--')
plt.subplot(2,2,3)
plt.plot(t2, np.exp(t2), 'g^')
plt.subplot(2,2,4)
plt.plot(t2, np.cos(2*np.pi*t2), 'orange');

您可以使用图形编号来创建多个图形:
import matplotlib.pyplot as plt
import numpy as npplt.figure(1)
plt.subplot(121)
plt.plot([1, 2, 3])
plt.subplot(122)
plt.plot([4, 5, 6])
plt.figure(2)
plt.subplot(121)
plt.plot([1, 2, 3],color="red")
plt.subplot(122)
plt.plot([4, 5, 6],color="red")
plt.title('It is that simple');


查看更多信息:
- 处理多个图形
使用文本
Matplotlib 允许您使用文本对象在绘图中轻松编写任意放置的文本。
#source: https://matplotlib.org/stable/tutorials/introductory/pyplot.html#sphx-glr-tutorials-introductory-pyplot-pymu, sigma = 100, 15
x = mu + sigma * np.random.randn(10000)
# the histogram of the data
n, bins, patches = plt.hist(x, 50, density=1, facecolor='g', alpha=0.75)
plt.xlabel('Smarts')
plt.ylabel('Probability')
plt.title('Histogram of IQ')
plt.text(60, .025, r'$\mu=100,\ \sigma=15$')
plt.axis([40, 160, 0, 0.03])
plt.grid(True)
plt.show()

所有的文本函数都返回一个文本对象实例。请注意,您可以在文本中使用数学表达式,就像上面取自 Matplotlib 文档的例子一样。想法是在文本字符串中插入 latex 语法:
plt.title(r'$\sigma_i=15$')Text(0.5, 1.0, '$\\sigma_i=15$')

更多信息,请访问:
- Matplotlib 中的文本介绍
- py plot 简介
文本注释
# source: https://matplotlib.org/stable/tutorials/text/annotations.html
ax = plt.subplot()
t = np.arange(0.0, 5.0, 0.01)
s = np.cos(2*np.pi*t)
line, = plt.plot(t, s, lw=2)
plt.annotate('local max', xy=(2, 1), xytext=(3, 1.5),
arrowprops=dict(facecolor='black', shrink=0.05),
)
plt.ylim(-2, 2)
plt.show()

更多信息,请访问:
- 使用注释
使用其他轴秤
# adapted from: https://matplotlib.org/stable/tutorials/introductory/pyplot.html#sphx-glr-tutorials-introductory-pyplot-py
# make up some data in the open interval (0, 1)
y = np.random.normal(loc=0.5, scale=0.4, size=1000)
y = y[(y > 0) & (y < 1)]
y.sort()
x = np.arange(len(y))
# plot with various axes scales
plt.figure()
# linear
plt.subplot(221)
plt.plot(x, y, color="red")
plt.yscale('linear')
plt.title('linear',color="red")
plt.grid(True)
# log
plt.subplot(222)
plt.plot(x, y, color="green")
plt.yscale('log')
plt.title('log',color="green")
plt.grid(True)
# symmetric log
plt.subplot(223)
plt.plot(x, y - y.mean(),color="blue")
plt.yscale('symlog', linthresh=0.01)
plt.title('symlog',color="blue")
plt.grid(True)
# logit
plt.subplot(224)
plt.plot(x, y, color="orange")
plt.yscale('logit')
plt.title('logit',color="orange")
plt.grid(True)
# Adjust the subplot layout, because the logit one may take more space
# than usual, due to y-tick labels like "1 - 10^{-3}"
plt.subplots_adjust(top=0.92, bottom=0.08, left=0.10, right=0.95, hspace=0.25,
wspace=0.35)
plt.tight_layout()
plt.show()

更多信息,请访问:
- py plot 简介
数据可视化是一门手艺
这些只是 Matplotlib 背后图形可能性的几个例子。我鼓励您进一步阅读该文档,并研究掌握 Matplotlib 的正确做法。对于那些每天使用它的人来说,我保证这是一个值得追求的目标!
本文的笔记本源代码可以在这里找到。
如果您想了解更多关于 Python 和数据可视化的知识,请查看 Udemy 的这些课程:
这些是附属链接,如果你使用它们,我会得到一小笔佣金,干杯!:)
- Python for Data Science A-Z
- 学习 Python 进行数据可视化
- Python master class 中的数据可视化
如果你喜欢这篇文章,请在 Twitter 、 LinkedIn 、 Instagram 上联系我,并在 Medium 上关注我。谢谢,下次再见!
参考
- Matplotlib 文档
- 在 matplotlib 中自定义样式表
- pyplot.setp 文档
- 控制线属性
- 处理多个图形
- Matplotlib 中的文本介绍
- py plot 简介
- 使用注释
30 个 Python 片段中的熊猫实用摘要
原文:https://towardsdatascience.com/a-practical-summary-of-pandas-in-30-python-snippets-c2d6ce84415e?source=collection_archive---------36-----------------------

由卡洛斯·穆扎在 Unsplash 上拍摄的照片
理解 pandas 库中主要功能的基本脚本
Pandas 是数据科学和机器学习最重要的 Python 库之一。我几乎每天都使用它,但我总是觉得我错过了有用的功能,所以我决定写一个压缩的总结来帮助指导我的熊猫技能的进步。
在本文中,我将用 30 个 Python 片段来分享 pandas 库主要功能的实用摘要。
这些功能
我们将在此介绍的功能包括:
- 使用数据框架
- 读取和写入表格数据
- 过滤数据帧中的行
- 选择特定的行和列
- 创建地块
- 从现有列创建新列
- 计算汇总统计数据
- 对表中的值进行排序
- 组合多个表中的数据
- 处理时间序列数据
- 操作文本数据
我们开始吧!
使用数据框架

让我们从从字典创建一个基本数据帧开始:
import pandas as pd
data = {"Country": ["Portugal", "USA", "France"],
"Population": [10.31*10**6, 329.5*10**6, 67.39*10**6]
}
df = pd.DataFrame(data)
df

当您使用 Python 字典创建 pandas 数据帧时,字典中的键将是数据帧的列标题,相应的值将是列。您可以在同一数据帧中存储多种数据类型。
要从 pandas 数据框架中选择一列,我们需要:
df["Country"]# Output0 Portugal
1 USA
2 France
Name: Country, dtype: object
使用方括号“[]”,这将返回一个Series对象。
如文档中所述:
pandas 系列没有列标签,因为它只是数据帧中的一列。系列确实有行标签。
我们还可以根据 pandas 的解释检查每一列的数据类型:
df.dtypesCountry object
Population float64
dtype: object
在这种情况下,数据类型是浮点(float64)和字符串(object)
读取和写入表格数据
Pandas 提供了read_csv()功能,将存储为 csv 文件的数据读入 pandas 数据帧。Pandas 支持许多不同的文件格式或现成的数据源(csv、excel、sql、json、parquet)。
df = pd.read_csv("Advertising.csv")
df

如果您想查看数据的受控子集,您可以:
df.head(8)

这里我们只显示了数据帧的前 8 行。
如果我们想要可视化数据帧的最后 8 行,我们可以:
df.tail(8)

我们还可以用熊猫轻松读取 excel 文件:
df = pd.read_excel("Advertising.xlsx")
df

您可以从数据帧中获得技术总结:
df.info()# Output<class 'pandas.core.frame.DataFrame'>
RangeIndex: 200 entries, 0 to 199
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 TV 200 non-null float64
1 radio 200 non-null float64
2 newspaper 200 non-null float64
3 sales 200 non-null float64
dtypes: float64(4)
memory usage: 6.4 KB
这将输出关于数据帧的技术信息,如条目数、数据类型、列数、空值数等。
过滤数据帧中的行
假设我对收视率大于 100.0 的电视节目感兴趣,我如何过滤我的数据帧以获得特定的子集?
df[df["TV"]>100]

我们还可以使用条件表达式来帮助过滤。例如,假设我们有 titanic 数据集(与 Pandas 文档中使用的相同):
df = pd.read_csv("titanic.csv")
df

我们希望从 35 岁以下的幸存者那里获得信息,然后我们会使用:
survived_under_35 = df[(df["Survived"]==1) & (df["Age"]<35)]
survived_under_35

在这里,我们使用括号内的条件表达式结合这里的and操作符作为&来组合两个过滤语句。
如果我们只想处理特定列中非空的值,我们可以使用条件函数notna(),它返回True每一行的值都不是空值。
df[df["Age"].notna()]

关于条件表达式和过滤的更多信息,请参见 pandas 文档的这一部分。
选择特定的行和列
假设我想要 40 岁以上乘客的名字。因为我想要行和列的子集,仅仅使用选择括号[]已经不够了,所以我使用了loc/iloc操作符:
df.loc[df["Age"]>40, "Name"]6 McCarthy, Mr. Timothy J
11 Bonnell, Miss. Elizabeth
15 Hewlett, Mrs. (Mary D Kingcome)
33 Wheadon, Mr. Edward H
35 Holverson, Mr. Alexander Oskar
...
862 Swift, Mrs. Frederick Joel (Margaret Welles Ba...
865 Bystrom, Mrs. (Karolina)
871 Beckwith, Mrs. Richard Leonard (Sallie Monypeny)
873 Vander Cruyssen, Mr. Victor
879 Potter, Mrs. Thomas Jr (Lily Alexenia Wilson)
Name: Name, Length: 150, dtype: object
如文档中所述:
使用 loc/iloc 时,逗号前的部分是您想要的行,逗号后的部分是您想要选择的列。
使用列名、行标签或条件表达式时,在选择括号[]前使用 loc 运算符。
对于逗号前后的部分,可以使用单个标签、标签列表、标签片段、条件表达式或冒号。如果您使用冒号,这意味着您想要选择所有行或列。
当您的选择基于表上的位置时,例如使用iloc.,假设您想要 23 到 42 行和 1 到 3 列:
df.iloc[22:42, 0:3]

当使用loc|iloc选择特定的行和/或列时,新值可以分配给所选数据。例如,将名称 anonymous 分配给第三列的前三个元素。有关选择的更多信息,请参见此处。
创建地块
df = pd.read_csv("Advertising.csv")
如果您想快速可视化数据,您可以简单地调用.plot()方法:
df.plot();

在这里,pandas 用数字数据为每一列创建了一个单线图。如果您想得到具体的数据,您可以选择所需的列,例如,假设您只想绘制销售额:
df["sales"].plot();

如果你想评估电视/广播/报纸收视率对销售额的影响,你可以将它们一个一个地对比:
df.plot.scatter(x="TV", y="sales", alpha=0.6);

df.plot.scatter(x="radio", y="sales", alpha=0.6);

df.plot.scatter(x="newspaper", y="sales", alpha=0.6);

pandas 中有许多绘图选项,我们可以使用 Python 中内置的 dir()函数来检查它们:
for method_name in dir(df.plot):
if not method_name.startswith("_"):
print(method_name)area
bar
barh
box
density
hexbin
hist
kde
line
pie
scatter
关于熊猫的更多绘图,查看熊猫文档的这一部分。
从现有列创建新列

在 pandas 中创建新的专栏很简单。只需使用括号[]在左侧分配新的列名,在右侧分配该列的数据:
df["Date"] = pd.date_range("1965-01-01", periods=len(df))
df

注意:这里我还使用了另一个名为 *date_range* 的 cool pandas 方法,它以 *period* 参数指定的周期从一个起点生成一个日期值列表。
但是,如果我们想从一个现有的列创建一个新的列呢?例如,假设我们有熊猫文档使用的空气质量数据集:
df = pd.read_csv("air_quality_no2.csv")
df

假设您想要检查安特卫普与伦敦的值的比率,并将结果保存为新列:
df["ratio_antwerp_london"] = (df["station_antwerp"] / df["station_london"])
df

如果您想对一列应用一个更复杂的函数,并将结果保存为 dataframe 的一个新列,您可以使用.apply()方法。
例如,让我们对来自伦敦站的 NO2 值应用条件,其中,如果它们大于阈值,则输出将为“高”,否则为“低”:
def highLow(temp):
if temp > 24.77:
return "High"
else:
return "Low"
df["station_london_high_low"] = df["station_london"].apply(highLow)
df

使用熊猫.rename()重命名数据列:
data = {"Name": ["John", "Mary", "Paul"],
"Age": [20,25,30],
"Occupation": ["Software Engineer", "Artist", "Product Manager"]
}
df = pd.DataFrame(data)
df_renamed = df.rename(columns={"Name":"First Name",
"Occupation": "Job"})
df_renamed

注意,我不必重命名所有的列,因为Age列保持不变。
计算汇总统计数据
计算熊猫的统计数据非常简单:
df = pd.read_csv("titanic.csv")
print(df["Age"].mean())
print(df["Age"].max())
print(df["Age"].min())
print(df["Age"].median())29.69911764705882
80.0
0.42
28.0df.describe()

您还可以计算给定列的聚合统计信息的特定组合:
df.agg(
{
"Age": ["min", "max", "mean"],
"Parch": ["min", "max", "mean"]
}
)

.describe()方法可以方便地加快速度:
df.describe()

它提供了表格中数字数据的快速概览。您还可以通过一行代码按类别计算值/记录的数量:
df["Pclass"].value_counts()3 491
1 216
2 184
Name: Pclass, dtype: int64
你可以在这个部分看到更多细节。
对表中的值进行排序
假设你有一个姓名和年龄的数据集:
data = {
"Name": ["Lucas", "Beatriz", "Clara", "Sara"],
"Age": [30, 26, 20, 22]
}
df = pd.DataFrame(data)
df

你想按年龄分类:
df.sort_values(by="Age")

您也可以按降序排列:
df.sort_values(by="Age", ascending=False)

组合多个表中的数据
df1 = pd.DataFrame(
{
"Name": ["Lucas", "Beatriz", "Clara", "Sara"],
"Age": [30, 26, 20, 22]
}
)
df2 = pd.DataFrame(
{
"Name": ["John", "Mary"],
"Age": [45, 38]
}
)
df_names_ages = pd.concat([df1, df2], axis=0)
df_names_ages

也可以使用共享列合并两个数据帧。
df1 = pd.DataFrame(
{
"Name": ["Lucas", "Beatriz", "Clara", "Sara"],
"Age": [30, 26, 20, 22],
"City": ["Lisbon", "Barcelona", "London", "Paris"],
}
)
df2 = pd.DataFrame(
{
"City": ["Lisbon", "Barcelona", "London", "Paris"],
"Occupation": ["Machine Learning Enginner", "Scientist", "Writer","Teacher"]
}
)
df_merged = pd.merge(df1,df2,how="left", on="City")
df_merged

在这个部分你可以了解更多关于 pandas 中的连接和合并。
处理时间序列数据
import pandas as pd
import matplotlib.pyplot as plt
假设我们有这样一个数据集:
df = pd.read_csv("typingPerformance.csv")
df

这实际上是我创建的一个数据集,用来跟踪我的触摸打字性能,以显示我在键盘上打字的速度。
这里的一个问题是“日期”列的数据类型是一个string。我希望它是一个datetime对象,这样我就可以对它执行标准的日期操作。Pandas 提供了一种将列转换为 datetime 对象的简单方法:
df["date"] = pd.to_datetime(df["date"])
df

现在,我们可以检查数据类型以确保它是datetime:
df.dtypesdate datetime64[ns]
wpm object
accuracy float64
dtype: object
完美!现在我们可以用简单的表达回答问题了。比如,我什么时候开始跟踪我的打字表现?
df["date"].min()Timestamp('2021-01-14 00:00:00')
我上次练习是什么时候?
df["date"].max()Timestamp('2021-10-01 00:00:00')
我追踪了多久?
df["date"].max() - df['date'].min()Timedelta('260 days 00:00:00')
现在,我可以创建一个新列,指定一些关于日期的信息,如创建该数据点的月份:
df["month"] = df["date"].dt.month
df

现在,我可以画出每个月的平均 wpm(每分钟字数)表现:
df_monthly_performance = df.groupby("month")["wpm"].mean()df_monthly_performance.plot()
plt.ylabel("wpm");

pandas 中有大量与日期相关的功能,我建议查看文档的这一部分,以了解更多信息!
操作文本数据
data = {"Full Name": ["Mark Harrison Junior", "Mary Elisabeth"],
"Age": [40, 50]}
df = pd.DataFrame(data)
df

我们可以使用.str()方法来处理字符串列。例如,我们可以使给定列中的所有字符串都小写:
df["Full Name"].str.lower()0 mark harrison junior
1 mary elisabeth
Name: Full Name, dtype: object
或者基于给定列的文本操作创建另一列:
df["Last Name"] = df["Full Name"].str.split(" ").str.get(-1)
df

我们可以检查字符串列是否包含某个字符串:
df["Full Name"].str.contains("Junior")0 True
1 False
Name: Full Name, dtype: bool
您可以在本部分中了解更多关于文本操作的信息。
学习熊猫
Pandas 是数据科学家和机器学习工程师最常用的 Python 库之一。它具有惊人的功能,如果掌握得当,在处理数据和加快工作流程时会有很大的帮助。
花时间以正确的方式学习 pandas,阅读文档,练习每个项目中经常出现的单个功能,我保证结果会不言自明。
如果你想了解更多关于熊猫的知识,可以看看 Udemy 的这两门课程:
- 终极熊猫训练营
- 熊猫数据分析
(这些是附属链接,如果你使用它们,我会得到一小笔佣金,干杯!:))
如果你喜欢这篇文章,在媒体、上关注我,订阅我的时事通讯,或者加入媒体(如果你还没有的话:)。在 Twitter 、 LinkedIn 和 Instagram 上和我联系!谢谢,下次再见!:)
参考
- 熊猫文档
- 熊猫用户指南
- excalidraw
释放分析和实验力量的实用方法
原文:https://towardsdatascience.com/a-practical-way-to-unleash-the-power-of-analytics-and-experimentation-33372d4cea6f?source=collection_archive---------19-----------------------
我们不能通过雇佣分析师来“打开”分析文化。它需要对整个组织进行积极的监控和指导,以产生真正的影响!

来自 Unsplash 的海蒂·芬(Heidi Fin)拍摄的照片(链接)
如果没有决策要做,就没有分析的需要,导致没有数据的需要,从此没有价值要用数据来创造!
在当前的时代,每个人都是数据驱动的,每个组织策略都围绕着数据,每一次炒作都是关于人工智能/ML 的魔杖。然而,大多数企业都难以从数据中获取价值并建立分析文化。仔细观察实际情况就会发现,对分析的期望往往与组织对做出数据驱动决策的承诺不相符合。
我们经常听到从数据中创造价值的说法。但在现实中,如果没有决策要做,就不需要分析,导致不需要数据,从此没有价值要用数据来创造!如果不产生实际的数据需求,它可能会成为另一种没人关心的僵尸资产。数据驱动型业务的基本重点是如何做出决策。
当业务从一无所知的、基于意见的决策转变为知情的、基于证据的科学决策时,分析成熟度自然会到来。后者自然需要数据和相关的专业知识。

分析领导者在全新环境中的典型旅程(作者插图)
本文将分析的范围定义为“从数据或统计的系统分析中获得的见解”,主要是决策支持。
在过去的十年里,我在从大公司到初创公司和咨询公司的各种业务中建立了多个数据团队。我目睹并参与了许多挖掘数据潜力的尝试。如上图所示的旅程有许多平行的线索,总是从乐观的投资观点开始,到证明投资的影响和回报结束。如果管理层确信,就会投入更多的投资,循环就会重复。
…当数据驱动的决策成为组织中每个成员的习惯时,分析文化就形成了
根据我的经验,这个周期中最关键的部分总是衡量和展示分析的影响。没有它,周期会变慢,分析变得更像一项服务,而不是“变化的引擎”。
分析主要是一个决策支持角色,需要整个组织与之合作。因此,这样一个功能的成功更多的是朝向科学过程而不是结果。正如 Sudaman (安联比荷卢经济联盟的区域首席数据和分析官)在数据框架播客中提到的,当数据驱动的决策成为组织中每个成员的习惯时,分析文化就形成了。
我在跟踪和测量分析文化方面的研究总是会导致许多带有定性指标的分析成熟度阶段的广泛和抽象的定义。这些可能有利于 CXO 在大型组织的层面上做出战略投资决策,但对我来说几乎毫无用处。通常,管理顾问用这一点为大老板指出分析成熟度的未来之路。
但作为一名现场分析领导者,我想关注实际影响的问题:“我应该做些什么来帮助团队朝着基于数据的决策的正确方向前进?”有没有简单的方法来跟踪和监控团队如何利用基于数据的决策?这是否可行,以便领导可以积极使用这些指标来识别瓶颈?
在这里,我提出了一种可量化和可操作的方法来跟踪分析和实验在一个组织中是如何使用的,以及如何释放其潜力。
分析影响漏斗!

分析影响漏斗由作者概念化并呈现
是的,你是对的。上面的漏斗看起来太熟悉了。这是我们在互联网上看到的标准创新漏斗。我只是将这些应用于分析和实验。让我们通过每个阶段和指标来跟踪,以确保漏斗性能。
漏斗顶端
领导者应该引导团队成员发现需要解决的问题,并开始创建实验、测试和学习的积压工作。这里的关键是不断填充漏斗并保持分析能力。随着分析成熟度的提高,我们经常会看到指数级增长,导致分析团队能力耗尽,利益相关者要求更多的见解!没有任何分析项目可以交付,就证明影响而言,这场战斗已经失败了。
分析项目的机会可能来自任何人:无论是从事产品工作的人、查看数据的人、用户研究人员、最终用户反馈等。分析团队应该有一种机制来捕捉这些机会,根据业务目标标记和组织它们。这些可以是标准的请求表格,或者使用吉拉等工具。每一个商业机会都应该以同样的真诚对待,以确保我们不会以一种狭隘的思维结束,也不会不适当地拒绝一个好主意。

科学的优先顺序框架(由作者提交,链接此处
任何提出想法的成员都应该使用第一原则方法详细阐述商业价值和影响。对于一个组织来说,这是最好的标准化。
获得首肯
…一个高度集中的组织是一个联合的团队代表其业务领导思考的地方

这些想法经过了商业领袖的验证,他们会考虑赞助这些想法。尽管创意的产生需要“跳出框框”的思维,但它们应该在很大程度上与业务目标保持一致。当一切顺利时,一个高度集中的组织就建立起来了,在那里,一个联合的团队代表其业务领导进行思考。
很明显,一个更好的联盟将有更高的机会让商业领袖赞助提议的项目。项目赞助的水平代表了战略一致性。为了跟踪这一点,我们可以使用战略一致性分数,这是赞助想法与提交的提案总数的比率。由于此分数是在战略和愿景层面上衡量的,因此应该在更广泛的范围内(跨部门或业务单位)进行衡量,而不是在特定的团队层面。
当得分较低时,高层和中层经理有责任找出缩小差距的方法。造成这种差距的通常原因是业务/战略团队和技术/运营团队之间缺乏联系。这通常是由于缺乏与高层管理人员的沟通和接触造成的。组织需要充满激情的人,他们是不可思议的工作狂。但是如果不对齐,这些马就会朝各个方向拉!
说服团队
…分析和实验的核心目的是增加企业的可选性!

选择性被定义为“可供选择但不是强制性的品质”。说白了,分析和实验的核心目的是增加企业的可选性。但是,只有当企业有能力行使它们时,可选性才是有用的。主要的问题往往是克服惰性,走向探索,而不仅仅是利用已知的问题。
虽然企业领导赞助一个项目,但基层团队可能有不同的优先级。为“可能”受益的项目提取资源可能是一场艰难的对话。分析领导者应该具有情境同理心,以理解团队的每个优先事项,并相应地对实验进行排序。
当一切顺利的时候,这些团队会很乐意接受赞助的实验。这可以通过业务接受率来衡量,业务接受率被定义为实际接受的实验数量与受资助项目总数的比率。较低的接受率可能意味着错过机会或不同团队之间在业务优先级上缺乏一致性。造成这种情况的原因可能是业务发起人没有认识到优先级,也可能是执行团队没有足够的能力。
做出决定
…我们应该绝对区分实验的方式和实验的结果

艰难的部分已经完成了。现在,进行实验,分析结果,并提出选择。但是,它导致了具体的决定吗?
让我非常明确地说:我们应该绝对地区分实验的方式和实验的结果。一个不正确的实验是一个有缺陷的过程,导致不确定的结果,阻止具体的决策。即使一个完美的实验,负面或无影响的结果是可以预期的。
理想情况下,我们希望每个实验或分析概念验证都能产生建议和决策。我们可以通过有效性得分来衡量这一点,有效性得分被定义为进行的实验数量与做出的结论性决策之间的比率。分数少了,我们就需要自省为什么一个实验没有结论。
实验没有做好可能有很多原因。这包括不清楚的问题定义和范围,不充分的样本大小和统计能力,错误的计算,错误的测量,没有考虑次要影响,错误的时间安排等。
接受决定

每一个决定都应该有一个与之相关的行动和结果。当团队完全相信决策时,会立即采取行动,表明对决策的信任。我们可以通过接受分数来衡量信任程度,接受分数被定义为采取的行动与做出的决定的比率。
缺乏后续行动可能意味着对实验或决策缺乏信任。如果决策的背景和团队的关注点之间存在脱节,也会出现这种情况。由于计划和进行实验需要合理的时间,业务优先级的频繁变化会破坏实验的流程和行动的相关性。因此,在将实验转化为行动的过程中,企业和组织的稳定性至关重要。
漏斗底部

在大多数组织中,这是一个经常被忽略或不完整的关键部分。根据我的观察,漏斗通常会在记录下所采取的行动后停止。然而,我们应该继续监测结果并量化预期的影响。
…不承担风险的过于谨慎的团队或不惜一切代价避免失败的团队可能会破坏成功的衡量标准
业务影响可能有多种形式,如运营改善、销售提升、利润提高、客户参与度等。关键是使用通用指标(通常以货币形式)量化这种影响。有了这些信息,我们就可以将成功率定义为积极的净结果与采取的行动总数的比率。虽然高比率是可取的,但成功的度量可能会被不承担风险的过于谨慎的团队或不惜任何代价避免失败的团队所破坏。因此,还应该注意高成功率。
最后一个指标是投资回报率,它是通过各种实验产生的总商业价值与分析领域总投资的总和。实验&的实施是跨团队跨职能的努力。因此,应采用可接受的方式计算归属于分析的回报部分。建议有一个比复杂模型更粗糙的&有意义的归属。我们只需要耐心等待归因模型的进化。
提前计划
从长远来看,任何企业都应该看到这个漏斗发展和稳定。虽然更多的投资会导致漏斗顶端更胖,但也会给净收益和投资回报率带来压力。另一方面,缺乏投资或能力不足会使漏斗变得更细,表明机会成本的积累。
该漏斗是一种很好的方式,可以证明单靠分析团队无法创造奇迹并推动数据成熟。完善一个没有业务承诺的分析团队会导致失望和期望的不匹配。
同时,还应避免挪用其他团队职能的预算来推动对分析的更多关注。没有推向市场的产品,数据就不会产生,分析也不会有意义。
从分析和实验文化起步的组织可能会更好地拥有自上而下的授权,为这些漏斗设定最低 KPI。这些不仅仅是分析 KPI,而是对组织在其核心推动分析和实验方面的成熟度的总体衡量!
关于作者
Shyam 是数据领域的公认领导者,在建立技术和数据领域的全功能团队方面拥有丰富的经验。他目前在 Yara 领导全球数字解决方案的数据科学和分析团队。他热衷于战略和通过数据、分析和人工智能/人工智能创造切实的商业价值。
请在 LinkedIn 这里 随意连接和联系聊天。
参考
https://shyamdsundar.medium.com/prioritising-the-scientific-way-507d4200b6b8 https://www.forbes.com/sites/forbestechcouncil/2020/11/11/optionality-part-i-what-is-it-and-why-is-it-crucial/?sh=7bcae3a864b0 https://www.linkedin.com/posts/shyamdsundar_insights-datascience-analytics-activity-6717605677487017984-z5t1
阿特鲁(扩张的)和深度方向可分卷积的初级读本
原文:https://towardsdatascience.com/a-primer-on-atrous-convolutions-and-depth-wise-separable-convolutions-443b106919f5?source=collection_archive---------7-----------------------
思想和理论
什么是萎缩/扩张和深度方向可分卷积?与标准卷积有何不同?它们的用途是什么?
凭借权重共享和平移不变性等属性,卷积层和 CNN 在使用深度学习方法的计算机视觉和图像处理任务中变得无处不在。考虑到这一点,本文旨在讨论我们在卷积网络中看到的一些发展。我们特别关注的两个发展:阿特鲁(扩张)卷积和深度方向可穿透卷积。我们将看到这两种类型的卷积是如何工作的,它们与普通的卷积有什么不同,以及为什么我们可能要使用它们。
卷积层
在进入正题之前,我们先快速提醒一下自己卷积层是如何工作的。从本质上来说,卷积滤波器只是简单的特征提取器。以前手工制作的特征过滤器现在可以通过反向传播的“魔法”来学习。我们有一个在输入特征图上滑动的核(conv 层的权重),在每个位置,执行逐元素乘法,然后对乘积求和,以获得标量值。在每个位置执行相同的操作。图 1 显示了这一过程。

图 1:一个 3×3 卷积滤波器的作用[1]。
卷积过滤器通过在输入特征图上滑动来检测特定的特征,即,它在每个位置寻找该特征。这直观地解释了卷积的平移不变性。
阿特鲁(扩张)卷积
为了理解 atrous 卷积与标准卷积有什么不同,我们首先需要知道什么是感受野。感受野被定义为产生每个输出元素的输入特征图的区域的大小。在图 1 的情况下,感受野是 3×3,因为输出特征图中的每个元素看到(使用)3×3 输入元素。
深度 CNN 使用卷积和最大池的组合。这样做的缺点是,在每一步,特征图的空间分辨率减半。将所得的特征图植入到原始图像上导致稀疏特征提取。这种效果可以在图 2 中看到。conv。滤镜将输入图像缩减采样为原来的两倍。上采样和在图像上施加特征图表明,响应仅对应于 1/4 的图像位置(稀疏特征提取)。

图 DCNN 中的稀疏特征提取[2]。
阿特鲁(扩张)卷积解决了这个问题,并允许密集特征提取。这是通过一个叫做的新参数(r) 实现的。简而言之,atrous 卷积类似于标准卷积,除了 atrous 卷积核的权重被间隔开或个位置,即,扩展卷积层的核是稀疏的。

图 3:标准与膨胀的内核。

图 4:3×3 阿特鲁(扩张)卷积的作用[1]。
图 3(a)示出了标准内核,图 3(b)示出了具有比率 r = 2 的扩大的 3×3 内核。通过控制速率参数,我们可以任意控制 conv 的感受野。层。这使得 conv。过滤以查看更大的输入区域(感受野),而不降低空间分辨率或增加内核大小。图 4 示出了运行中的扩展卷积滤波器。

图 5。使用扩张卷积进行密集特征提取[2]。
与图 2 中使用的标准卷积相比,在图 5 中可以看出,通过使用比率 r=2 的扩展核来提取密集特征。只需将膨胀参数设置为所需的膨胀速率,即可轻松实现膨胀卷积。
扩展卷积:pytorch 实现
深度方向可分离卷积
深度方向可分离卷积是在例外网[3]中引入的。图 6 示出了标准卷积操作,其中卷积作用于所有通道。对于图 6 所示的配置,我们有 256 个 5x5x3 内核。

图 6:应用于 12x12x3 输入的标准 5x5 卷积。
图 7(a)示出了深度方向卷积,其中滤波器被应用于每个通道。这就是深度方向可分离卷积与标准卷积的区别。深度方向卷积的输出具有与输入相同的通道。对于图 7(a)所示的配置,我们有 3 个 5x5x1 内核,每个通道一个。通道间混合是通过将深度方向卷积的输出与所需数量的输出通道的 1×1 内核进行卷积来实现的(图 7(b))。

图 7:5×5 深度方向的可分离卷积,接着是 1×1 conv。
为什么选择深度可分卷积?
为了回答这个问题,我们来看看执行标准卷积和深度可分卷积所需的乘法次数。
标准卷积 对于图 6 中指定的配置,我们有 256 个大小为 5x5x3 的内核。计算卷积所需的总乘法:
256553(8*8 个位置)= 1228800
深度方向可分离卷积 对于图 7 中指定的配置,我们有 2 个卷积运算:
- 3 个大小为 5×5×1 的核。这里,所需的乘法次数是: 553(88 个位置)= 4800** 2) 256 个大小为 1x1x3 的核用于 1x1 卷积。所需乘法次数: 256113(8*8 个位置)= 49152 深度可分卷积所需乘法总数: 4800 + 49512 = 54312。
我们可以非常清楚地看到深度方向卷积比标准卷积需要更少的计算。
在 pytorch 中,深度方向可分离卷积可以通过将组参数设置为输入通道的数量来实现。
注意:py torch 中的组参数必须是 in_channels 参数的倍数。这是因为在 pytorch 中,通过将输入特征分成组=g 组来应用深度卷积。更多信息点击这里。
结论
这篇文章深入研究了两种流行的卷积类型:atrous(扩张)卷积和深度可分卷积。我们看到了它们是什么,它们与标准卷积运算有何不同,也看到了它们相对于标准卷积运算的优势。最后,我们还看到了如何使用 pyTorch 实现 atrous(扩张)和深度方向可分离卷积。
参考文献
[1]卷积运算(https://github.com/vdumoulin/conv_arithmetic)
[2]陈,梁杰,等,“Deeplab:基于深度卷积网、atrous 卷积和全连通条件随机场的语义图像分割” IEEE 模式分析与机器智能汇刊40.4(2017):834–848。
[3]弗朗索瓦·乔莱。"例外:具有深度可分卷积的深度学习."IEEE 计算机视觉和模式识别会议论文集。2017.
对话式人工智能入门
原文:https://towardsdatascience.com/a-primer-on-conversational-ai-d20c7a4b2a87?source=collection_archive---------33-----------------------
自然语言处理笔记
了解对话式人工智能及其如何帮助人类

亚历山大·奈特在 Unsplash 上拍照
介绍
我敢肯定,我们都曾试图联系我们的银行,但在我们与助理交谈之前,我们必须通过某种自动化系统。当这些系统根本无法理解我们时,这有多烦人?在几分钟的来回和努力理解系统后,我们找到一个真人来处理我们的问题,并带我们经历完全相同的过程。
真令人沮丧!
如果我们要与计算机对话,我们至少希望它尽可能地复制人类的互动,否则有什么意义呢!我们需要计算机像我们一样交流和说话,但我们知道这不是计算机真正的工作方式——除非你教它们…
什么是对话式 AI?
对话式人工智能(AI)由一系列技术组成,这些技术支持聊天机器人等自动消息工具和语音助手等语音应用。用户可以与这些技术对话,因为它们是为了在计算机和人类之间提供类似人类的互动而创建的。
这些技术通常利用大量数据、机器学习(ML)和自然语言处理(NLP)来帮助模仿类似人类的交互,包括识别语音和文本,然后翻译它们的意思。
然而,我们习惯的对话 AI 类型被称为弱 AI (或狭义 AI 在某些圈子中,但这些术语可以互换)。弱,不是因为它缺乏能力,而是因为我们习惯的工具只实现了大脑的有限部分——换句话说,它们专注于执行另一个领域的任务。
另一方面,有强大的人工智能或人工一般智能(AGI)。强人工智能通常是科幻电影中描述的——好吧,没有那么夸张;这种人工智能(AI)仍然是一个理论概念,维基百科将其描述为“智能代理理解或学习人类可以完成的任何智力任务的假设能力。”【来源 : 维基百科】。
用例
如前所述,尽管被称为弱,但弱人工智能正在被各种企业采用——事实上,如果我们看这项技术帮助企业盈利的能力,我们可能不会认为它是弱的。企业中对话式人工智能的一些例子包括:
- 客户支持通常是相当重复的,因此它被在线聊天机器人所取代,可以在客户旅程中帮助客户
- 降低文本到语音转换技术的准入门槛,反之亦然
- 提高医疗保健的运营效率
- 亚马逊的 Alexa、苹果 Siri 和谷歌 Home 等物联网(IoT)设备
- 优化大部分人力资源(HR)流程
对话式人工智能的优势
有许多因素使对话式人工智能对企业有吸引力,因此,如果我们在未来各种行业的企业中看到某种形式的对话式人工智能,我不会感到惊讶。
提高生产力—借助对话式人工智能,自动化支持可全天候处理简单请求。反过来,这一壮举将 up 客户服务代表解放出来,将他们的注意力转移到对话式人工智能无法触及的更复杂的客户问题上。
**降低客户服务成本——**客户服务的运营成本非常高,但有了对话式人工智能,客户的请求可以得到更高的处理量,比电话那头的人还要高。因此,可以更快地向客户提供相关和有用的信息。
**交互式品牌信息——**苹果、微软、谷歌和亚马逊等公司已经通过各自的语音助手很好地做到了这一点。虚拟助理可以让你将你的品牌人格化,让你在客户喜欢的地方与他们见面,这超越了展示广告、社交媒体和其他网络资源。
为员工提供更好的体验— 如前所述,琐碎的任务可以从人类代理那里拿走,并委托给虚拟助理,他们永远不会厌倦重复做同样的事情(事实上,他们会变得更好)。这给人们留下了空间,让他们专注于更复杂的任务,并发展他们的人际技能,以建立新的或巩固现有的客户关系。
包裹
尽管大多数对话式人工智能应用程序目前在解决问题的技能方面受到限制,但它们仍然是非常有效的工具,能够在重复的任务(如客户交互)中减少时间并提高成本效率。进一步补充,对话式人工智能是一个很好的工具,可以用来解放员工,使他们可以更加专注于为企业带来更多价值的任务以及需要更多参与的与客户的互动。
总的来说,对话式人工智能应用程序已经表明,它们能够有效地模仿类似人类的对话体验,从而使客户更加满意。
感谢阅读…
相关文章
</5-ideas-for-your-next-nlp-project-c6bf5b86935c> https://pub.towardsai.net/7-free-online-resources-for-nlp-lovers-26b1e0bba343
梯度下降入门
原文:https://towardsdatascience.com/a-primer-on-gradient-descent-410f2d1a0eaa?source=collection_archive---------32-----------------------
直观地探索梯度下降,将其可视化,并使用 Python 中精彩的 SymPy 库实现一个示例

阿曼德·库利在 Unsplash 上拍摄的照片
为什么我们需要知道什么是梯度下降?
让我们首先定义什么是优化问题。在优化问题中,我们首先列出一个成本,它是可变参数的函数。这些参数的取值范围很大,最终这些值决定了成本。我们在处理这些问题时的目标是找到一组 值,它们将最小化成本函数。梯度下降有助于我们系统地这样做,而不是通过随机选择参数值来随意尝试这样做。
直觉

在 Unsplash 上tefan tefaník拍摄的照片
假设我们在山上徒步旅行,正沿着一个斜坡往下走。现在我们被告知下降时必须闭上眼睛。我们会怎么做?很简单,闭上我们的眼睛,用我们的脚去感觉我们站的地方周围有什么,在我们感觉到一个轻微向下的斜坡的地方走一步。这正是我们在梯度下降中要做的。我们向下迈出的这一步被称为更新步骤。现在,我们当中一些感觉更有冒险精神的人会迈出更大的一步,甚至可能是向下迈出一大步!我们迈出的一步的大小被称为学习率**,它决定了我们到达底部的速度。**
梯度——数字感知的方式
我们谈到了人类是如何轻松定位迈出一步的,但是数字是如何做到这一点的呢?向下的方向是多少?

来源:datahacker.rs
上图中,我们有一个成本 J,它只是一个参数 w 的函数。该函数可以用一个 w 表示的等式来表示。为了更新 w 以减少 J,我们首先从 w 的随机值开始,然后使用该等式来更新该值。

来源:塞缪尔·特伦德勒
这里,α是我们谈到的学习速率。那么到底发生了什么?首先让我们再来看一下图表。在全局最优值(最小成本)右边的任何地方,函数的偏导数都是正的。现在,通过查看图表我们知道,如果我们降低 w 的值,我们就会降低成本。因此,使用上面的等式,我们从当前值 w 中减去一个正数,这反过来使成本最小化。阿尔法决定了我们减去多少。类似地,对于全局最优值左侧的任何 w,该 w 处的梯度为负,因此使用该等式,我们得到比之前更高的值 w,这再次最小化了成本。这总结了一个步骤。
我们按照这个简单的步骤进行固定次数的迭代,或者直到我们看到我们的成本已经收敛并且不会再进一步降低。
为什么要用 SymPy?
SymPy 是一个非常方便的库,它有很多我们可以使用的数学函数。我们将使用它来定义成本函数并计算给定方程的梯度。我们可以很容易地通过 SymPy 计算偏导数。
让我们把手弄脏吧
让我们尝试并优化成本函数 cost = x + y,看看梯度下降是否给出 x 和 y 的最佳值(x=0 且 y=0 时成本=0)。
- 导入必要的库(我在 Google Colab 上运行),如果你想在本地运行,请安装这些库。
2.创造符号,让 SymPy 发挥它的魅力&定义一个成本函数
3.可视化成本函数,我们可以看到在 x=0 和 y=0 时最小值为 0
成本函数(向下滚动)
4.使用带有接头的 sympy.evalf 计算成本
5.计算给定点 x,y 处参数的偏导数
6.肉!这是梯度下降函数,它迭代更新梯度并返回最佳参数值和最小化成本。
7.随着算法的进展,可视化我们的成本函数的变化。

学习率大的问题
好吧,那我们为什么要等这么多次迭代呢?为什么不迈出巨大的一步,降低成本。问题是梯度和学习率的乘积变得非常大,我们的成本直线上升。我们所有的努力都被冲走了,这可能是我们的成本不断飙升,永远不会收敛。
这些图表说明了为什么学习速度如此重要

来源:走向数据科学
让我们看看实际情况,如果我们将学习率提高到 1.1,就会发生这种情况。

我在代码里加了一个条件,如果代价开始射击,不会收敛,会自动降低学习率。
非凸成本函数的问题
由于这是一个入门,我选择了一个非常简单的成本函数,但实际上我们的成本函数可能是非凸的,并且有多个局部最小值。在这种情况下,我们可能会陷入局部最小值,永远不会达到全局最小值。

资料来源:vitalflux.com
如图所示,我们得到了一个错误的印象,即算法已经最小化了成本和收敛,而实际上我们陷入了一个远离全局最小值的局部最小值。
处理这些问题
因为这是给初学者的,我用了简单的梯度下降。我将写一篇关于更复杂的变体的文章,这些变体收敛得更快,并且避开了前面提到的问题。这些包括
- 使用随机梯度下降/批量梯度下降
- 使用 RMSProp 或 Adam。
- 使用指数递减的学习速率。
如果你想让我写这些话题,请在评论中提及。
结尾部分
我们了解了如何使用梯度下降优化成本函数,以及 SymPy 如何轻松地为我们完成所有的计算和繁重的工作。这是对惊人算法的温和介绍,该算法被广泛用于优化机器学习和深度学习模型。
我很想听一些关于这方面的反馈,如果你想要一篇更高级的文章来解释上面提到的调整,也请告诉我。
查看我的 github 的一些其他项目和完整代码。可以联系我 这里 。 感谢您的宝贵时间!
EM 算法的初级读本
原文:https://towardsdatascience.com/a-primer-on-the-em-algorithm-7bd60e9813e?source=collection_archive---------22-----------------------
克里斯蒂安·祖尼加博士

图一。用于混合模型的 EM 模型示例[1]
期望最大化(EM)算法是机器学习中用于估计模型参数的主要算法之一[2][3][4]。例如,它用于估计混合模型中的混合系数、均值和协方差,如图 1 所示。其目标是最大化似然 p(X|θ),其中 X 是观测数据的矩阵,θ是模型参数的向量。这是最大似然估计,实际上对数似然 ln p(X| θ)是最大的。最大化该函数的模型参数被认为是正确的模型参数。EM 是梯度下降的有用替代,并且可能具有几个优点。
1 它更自然地实施约束,例如保持协方差矩阵正定。
2.在许多情况下,例如对于混合模型,它可能收敛得更快。
3.它提供了一种处理缺失数据的方法。
不幸的是,EM 算法对初学者来说可能不容易理解。EM 算法的第一步是假设存在帮助生成数据的隐藏变量 Z。只有数据 X 被直接观察到。隐藏变量有助于将问题分成两个步骤,有时更简单,期望和最大化。通过对联合分布 p(X,Z | θ)进行边缘化,可以将可能性写成隐藏变量 Z 的形式。总和是 z 的所有可能值。

推导 EM 算法需要理解三个主要概念:两个以上变量的 Bayes 定理、凹函数的 Jensen 不等式以及比较概率分布的 Kullback-Leibler 散度。
贝叶斯定理在 em 算法中起着重要的作用。许多人都熟悉两个变量的定理,但是如上所示,三个变量会发生什么呢?虽然形式更复杂,但条件概率的定义仍然适用,它可以用联合分布 p(X,Z,θ)来表示。

无论变量的顺序如何,联合分布都是相同的,这是操纵所有条件概率的基础。在 EM 算法中,将使用 X 和θ来估计 Z,因此条件概率 p(Z | X,θ)很重要。使用上式中的联合分布,Z 的后验分布可表示如下。

方程可以简化为 p(X | θ) = p(X,θ)/p(θ)。

詹森不等式是获得 EM 算法所需的第二个结果。对于凹函数 f(x),f(x)的期望 E[f(x)],小于或等于先应用函数再取期望 f(E[x])。简洁地说,E[f(x)] ≤ f(E[x])。
像对数一样,凹函数是那些向外“凸出”的函数,如图 2 所示。该函数总是大于或等于弦。数学上,对于 x 和 y 之间的任意点 p,f(p) ≥ L(p)其中 L(p)是在 p 处评估的线的值。点 p(或 x 和 y 之间的任意点)可以通过 p = w1 x + w2 y 表示为 x 和 y 的加权组合。权重大于零,总和为 1。利用直线的方程,值 L(p)可以写成 L(p) = w2 f(y) + (1- w2) f(x)。所以对于凹函数f(w1 x+w2 y)≥w2 f(y)+(1-w2)f(x)。

图 2 凹函数位于任意弦之上。
显示詹森不等式的下一步如下,因为期望可以被认为是一个加权和,概率分布给出了权重。一般来说,概率会给出两个以上的权重,但前面的结果可以归纳为许多权重。

要理解的最后一个概念是 Kullback-Leibler 散度,它是两个概率分布 q(z)和 p(z)之间不相似性的度量。当两个分布相等时,KL 散度总是大于或等于零,q(z) = p(z)。它不是对称的,KL(p||q) ≠ KL(q||p),所以它不是距离测度。当真实分布是 p(z)时,它可以被解释为使用分布 q(z)编码数据所需的额外比特数,反之亦然。

掌握了这 3 个概念,EM 算法就更容易理解了。隐藏变量 Z 也具有分布 q(Z)。将 q(z)作为 q(z)/q(z) = 1 引入对数似然中,并利用对数函数是凹的这一事实,詹森不等式给出了关于分布 q(z)的期望。

这个不等式给出了对数似然的一个下界。对数似然和 L(q,θ)之间的差异可以看作是 q(z)和 p(Z|X,θ)之间的 KL 散度。用 p(X,Z| θ) = P(Z|X,θ)P(X| θ)的展开式来证明这一点。

当 KL 散度为零时,或者当 q(z) = p(Z|X,θ)时,完全相等。
最大化对数似然可以通过最大化 L(q,θ)来间接实现。有两种方法可以最大化 L,即改变 q 或改变参数θ。独立地改变每一个更简单。顾名思义,EM 算法有两个步骤,期望和最大化,并迭代进行。首先初始化参数。分布 q(z)在期望步骤中更新,保持参数θ固定为θold。这仅仅涉及到设置 q(z) = p(Z|X,θold)。然后更新参数θ以最大化 L(q,θ),保持在最大化步骤中固定的 q(z)。
期待
设 q(z) = p(Z|X,θold)代入 L。
最大化
保持 q(z)不变,改变θ,最大化 L(p(Z|X,θold),θ。
这两个步骤保证总是增加可能性并且至少收敛到局部最大值。最大化步骤可以根据分布的形式以不同的方式进行。例如,在高斯混合模型中,最大似然估计的修改给出了分析结果。在其他情况下,可能没有解析解,但是求解最大化步骤可能仍然比原始问题简单。
参考文献
[1]https://en.wikipedia.org/wiki/期望% E2 % 80 %最大化 _ 算法
【2】邓普斯特;莱尔德,n . m .;鲁宾,D.B. (1977)。“通过 EM 算法不完整数据的最大可能性”。 《英国皇家统计学会杂志》,B 辑 。39(1):1–38。JSTOR2984875
[3] Bishop 模式识别和机器学习 Springer 2006
[4]墨菲机器学习从概率角度看麻省理工学院出版社 2012 年
机器学习数据挖掘中偏差的来源
原文:https://towardsdatascience.com/a-primer-on-the-sources-of-biases-in-data-mining-for-machine-learning-d82e89604693?source=collection_archive---------26-----------------------
尽管通过大数据实现的自动化水平不断提高,但大部分数据挖掘和机器学习过程仍然依赖于人的干预,从而引入了不同的偏见。

摄影:JESHOOTS.COM在的 Unsplash
在过去几十年中,生成的结构化和非结构化数据的数量呈指数级增长,并且在未来几年还将继续增长。“大数据”分析可能会克服企业和政府几个世纪以来在决策时面临的众多挑战:缺乏足够的数据来制定政策(例如,针对特定社会群体的政策)或检查市场或消费者预期(例如,推荐系统)。由大数据范式驱动的描述性和预测性建模可以帮助决策者获得对个人、商业或集体收益的宝贵见解。
然而,现代数据收集过程和算法仍然容易受到数据挖掘偏见的影响。如果不采取适当的措施,大数据可能会放大现有社会问题(如种族歧视)的负面影响,使研究结果变得毫无价值,甚至适得其反[1],[2]。本博客的目的是探索在数据挖掘过程中以及大数据项目的特征工程阶段可能引入的偏差的潜在来源。
垃圾进垃圾出—大数据也是如此
大数据有可能克服数据可用性的限制,这是一个困扰传统统计分析几十年的问题,但这种分析的价值也容易受到数据质量和数据应用不当的影响。随着数字设备的日益普及,收集各种数据变得比以往任何时候都更加容易。例如,智能手机有能力实时记录你在哪里,你在做什么,你如何花费你的时间和金钱,你和谁见面,多长时间,以及许多这样的个人细节。尽管存在隐私和监控问题,但这些信息已经改变了经济和我们的生活方式。
尽管如此,就像老派的数据分析一样,新数据范式的成功也取决于相同假设的有效性——目标人群包括与被调查问题相关的所有成员;样本反映了统计总体;并且建模变量的选择是适当的。违反任何假设都会导致有偏见的结论,从而降低机器学习解决许多现实世界问题的价值。
图 1 描绘了机器学习练习中的典型步骤序列,并显示了不同的错误如何强化现有的问题。虽然谨慎使用将提供有效的解决方案并减少我们的问题,但任何错误都可能延续或恶化现有的问题(差异、歧视或其他)。

图片由作者根据[2]中的信息提供
第一部分:确定目标人群
数据分析练习的早期步骤之一(如果不是第一步的话)是询问谁或哪些成员最有可能拥有我们需要的信息或熟悉我们试图解决的问题。这组成员是我们期望的群体(姑且称之为问题群体)来考虑样本收集。训练数据样本的代表性必须仅针对与问题有直接联系的问题群体进行测量。
例如,假设一个道路维护部门想要使用众包(通过智能手机)来监控整个城市的道路状况[1]。虽然似乎居住在该地区的所有人都应该是目标人群,但只有在该地区的道路上行驶的人(作为乘客或司机)才是真正的目标人群(我们的问题人群)。来自不旅行或不开车的人的设备的加速度计数据不会增加任何价值。同样,对于招聘目标,所有潜在合格(满足强制性资格要求)的员工都是抽样人群,而不是所有毕业生或求职者。另一个明显的例子是衡量谁会赢得选举的抽样人口。大多数青少年的意见在民意测验中并不重要,因为只有选民(在大多数国家是 18 岁以上的人)才构成选举调查的人口。有多少年轻人被调查并不重要;调查结果或任何基于这种信息的预测模型将是无用的。
虽然在大多数情况下,完成这一步对于适当描述的问题来说可能是微不足道的,但是任何无意的错误都可能对我们工作的准确性和相关性产生巨大的影响。在我们的例子中,在定义了所有驾车者的目标人群后,道路部门现在必须设计一个策略来从一个有代表性的,即使是少量的道路使用者那里收集数据(暂时不包括骑自行车的人和步行的人)。
第二部分:确保有代表性的培训数据
任何小数据或大数据应用的价值取决于训练数据描述问题群体的准确程度。虽然大数据意味着一个巨大的数据集,但它很少代表整个问题群体,并且只捕获其中的一部分,这增加了代表性采样的重要性。创建不反映潜在问题群体的组成的训练数据集将强调某些成员而不代表其他成员。维基百科有一个长长的采样偏差列表,包括选择偏差、排除偏差、报告偏差、检测偏差,这个列表还可以继续下去。事实上,一个小的,但有代表性的样本可以产生比一个大的,有偏见的数据集更可靠的结果[3]。
例如,在上述道路监控项目中,如果该部门依靠智能手机中的加速度计来收集信息,则缺乏此类高科技设备或充足互联网接入的低收入群体可能无法成为样本的一部分[1]。有偏见的数据可能导致纳税人的钱不公平地分配给道路开发和维修,导致一个城市内道路基础设施质量的系统性差异。互联网接入不畅也会限制职位候选人名单,或者简历中的用词会导致招聘中的性别偏见。
第三部分:选择代表性特征
预测因子的选择也会影响模型中如何考虑不同的人群成员。即使我们正确地识别了问题人群,并为训练抽取了一个代表性的样本,输入变量中仍然存在某些差异。可能有许多特征捕捉到群体中某些成员的不完整图像,并且对有偏见的预测者赋予更大的权重将产生不期望的结果。因此,尽管样本很好地描述了所有的人口阶层,但特征工程会间接低估或高估某些群体,并影响模型的公平性。
例如,表面上中性的特征之间的小相关性会产生不公平的结果。如果好斗的司机和老年人都更喜欢红色汽车,对红色汽车收取更高的保险费来惩罚糟糕的司机的决定将间接地对老年人有偏见[2]。
如[2]中所引用的,“被错误代表的群体与已经存在社会偏见(如偏见或歧视)的社会群体相吻合,甚至“无偏见的计算过程也可能导致歧视性的决策程序”。此类风险适用于采样和特征选择步骤。
例如,雇佣好员工取决于“好”的定义,这可以基于过去工作的平均时间或证明的成就记录。使用任期长度作为一个特征会不成比例地排斥在高招聘周转率(或流失率)行业工作的某些人[1]。虽然它是衡量员工忠诚度的理想替代指标,但将其不必要地纳入模型可能会产生主导影响,并延续大数据被认为正在缩小的差异。因此,尽管尽了最大努力来定义人口和收集良好的数据,但选择错误的要素可能会在结果中引入系统性偏差,从而导致问题的出现。
最后的想法
大数据分析有可能克服由个人和人类决策产生的许多偏见,并呈现合理的、有代表性的人口状况。这篇博客的目的是介绍偏见如何成为机器学习建模练习的一部分。在执行数据挖掘和进行机器学习项目时,分析师必须意识到以下三个可能会削弱机器学习项目功效的原因:
未能正确识别与问题相关的统计(问题)人群
使用非代表性训练数据进行预测建模
用于预测目标变量的特征的有偏选择
常言道,“能力越强,责任越大”,在数据挖掘和特征工程方面的任何疏忽都可能使现有问题恶化,而这些努力将会适得其反。只有大数据、其易访问性和明智的数据挖掘的综合效应才有可能彻底改变我们的日常生活,实现环境可持续、社会公平和经济充满活力的世界。
参考
[1] S. Barocas 和 A. D. Selbst,“大数据的不同影响”,《加州法律评论》,第 104 卷,第 3 期,第 671–732 页,2016 年 2 月。
[2] E. Ntoutsi 等,《数据驱动的人工智能系统中的偏差——一项介绍性调查》, WIREs Data Min。知道了。Discov。,第 10 卷第 3 期,第 e1356 页,2020 年 5 月。
[3]j . j . farage 和 N. H. Augustin,“当小数据打败大数据”, Stat。可能吧。列特。,第 136 卷,第 142–145 页,2018 年。
[4] J. Manyika、J. Silberg 和 B. Presten,“我们如何应对人工智能中的偏见?," 2019.【在线】。可用:https://HBR . org/2019/10/what-do-we-do-about-the-bias-in-ai。
带 R 的贝叶斯可加回归树入门
原文:https://towardsdatascience.com/a-primer-to-bayesian-additive-regression-tree-with-r-b9d0dbf704d?source=collection_archive---------8-----------------------
传统集成算法的贝叶斯方法

由 kazuend 在 Unsplash 拍摄的照片
简介
在 XGBoost、Lightgbm 和 catboost 在几次高调的 kaggle 竞赛和机器学习研究中取得巨大成功之后,梯度增强机器(GBM)/集成算法成为许多涉及结构化数据的机器学习问题的主力。GBM 如此成功的原因之一是它可以同样好地处理数值和分类数据。然而,这些传统的基于集成的方法的问题是,它们给我们一个点估计,因此,我们没有办法估计该特定估计有多可信。通过量化经验风险,即 rmse、对数损失等。,我们可以得到一种模型不确定性的感觉(认知不确定性);然而,对于迭代主动学习或更好的风险管理(对于高风险情况),随机不确定性或个体预测不确定性也是非常重要的。为了缓解这个问题,Chipman 等人发表了这篇论文,这是由系综方法的相同精神所激发的;然而,它需要贝叶斯方法来识别模型参数,其中我们可以对我们关于树的形状和总体结构的先验信念进行编码。然后,基于该数据,它将使用 MCMC 反向拟合算法更新先验。在他们的文章中,他们声称在 42 个数据集(包括模拟和药物发现数据)上,它优于其他传统的集成方法。在这篇文章中,我的目的是用波士顿住房数据集上的一个说明性例子来证明这种说法。
树木的集合
系综树的想法来自于这样一种想法,即通过组合比随机猜测稍好的弱学习者的集合,我们可以得到一个强学习者。这些个体学习者中每一个都是低偏差-高方差模型。当组合在一起形成一个集合时,这些树形成一个中等偏差-中等方差模型,该模型在理论和实践上都具有极好的样本外预测性能。
做出推论的一般问题可以写成:

在集成算法中,未知函数被近似为树的和 h(x)。树和模型是一个以多元成分为核心的加性模型,与广义加性模型相反,它可以自然地包括交互作用效应。此外,它还可以包括单棵树无法获得的附加效果。由于这些优异的性质,系综方法吸引了大量的注意力,并导致了 boosting [ Friedman,2001 ]、random forest [ Breiman,2001 ]和 bagging [ Breiman,1996 ]的发展。随机森林使用特征子集来构建每棵树,然后将所有这些单棵树的预测进行组合。相比之下,bagging 使用数据的子集来构建每棵树。Boosting 与其他两种不同之处在于,它按顺序形成模型,其中每棵树都试图适应前一棵树无法解释的数据变化。贝叶斯加性回归树(BART)类似于 Boosting 算法,因为它结合了顺序弱学习者的贡献来进行预测。
贝叶斯加性回归树
在 BART 中,类似于梯度提升的反向拟合算法用于获得树的集合,其中一棵小树与数据拟合,然后该树的残差与另一棵树迭代拟合。然而,BART 在两个方面不同于 GBM,1 .它如何通过使用先验来削弱单个树,以及 2 .它如何在固定数量的树上使用贝叶斯反向拟合来迭代拟合新树。

拟合单棵树(信用:https://www.youtube.com/watch?v=9d5-3_7u5a4&ab _ channel = PutnamDataSciences
在 GBM 中,存在巨大的过度拟合风险,因为我们可以不断迭代,直到我们的经验风险在训练集示例上最小化(此时,所有这些树中存在的比特如此之大,以至于它本质上记住了所有的训练点,而不是概括)。在传统的 GBM 中,限制树深或提前停止等。来规范算法。相比之下,BART 使用智能先验系统地学习树木的收缩量或深度。先验是这样选择的,1。树很小,2。与每个树终端节点相关联的参数值趋向于零(限制灵活性),以及 3。残留噪声的标准差较小。有趣的是,树的数量没有被控制在先验范围内,因为这将导致优化过程中巨大的计算成本。相反,它被设置为默认值 50,这对于大多数应用程序来说已经很不错了。在获得上述三个参数的后验分布后,通过从模型空间(三个参数的后验)连续抽取样本,用反拟合算法进行推断。通过取所有这些图的平均值,我们可以得到任何试验数据的点估计。类似地,相应的分位数给出了测试数据的不确定性区间。
现在是使用 BART 建立预测模型的时候了。对于这部分,我们使用 r 中可用的 bartmachine 包,程序的核心是用 java 编写的。BART 的原作者的本机实现( bayestree )是用 C++编写的,但是它有几个限制(如下所列)。

信用:【https://arxiv.org/pdf/1312.2171.pdf】T4
在本练习中,我们将使用波士顿住房数据,这些数据在 R 中不可用,但我们可以通过 mlbench 软件包轻松获得。在下面的代码中,我们将数据加载到 R:
接下来,我们使用 caret 包将数据分为训练集和测试集:
接下来,我们绘制目标变量的直方图,它是一组特征的房价中值:

中间价直方图
要查看数据中每个要素之间的相关性,我们可以查看相关图:

相关图
看起来在一些特征之间有一些高相关性,这对于其他 ml 算法可能是一个问题,但是对于基于树的集成,我们可以安全地忽略它们。现在,我们可以初始化 bartmachine:
对于大约 400 个数据点和 13 个特征来说,它非常快(只需要大约 2-3 秒)。训练数据的均方根误差为 1.4,考虑到目标值范围在 4-50 之间,这已经相当不错了。夏皮罗-维尔克检验的 p 值表明数据是异方差的。
使用 rmse_by_num_trees 函数,我们可以很容易地找到最佳的树数,而不是使用默认的 50。
基于 rmse 对树数量的图,我们用 65 棵树重新训练该模型,并绘制收敛诊断图。

会聚诊断图
我们可以看到,MCMC 采样在大约 200 次迭代时达到收敛。到 2010 年,它仍在波动。跑更长的时间和更多的磨合是有益的。然而,对于这个练习,这种收敛行为可以被认为是可接受的。
接下来,我们可以使用内置函数查看剩余属性:

残差或多或少在零附近波动,但总体上残差看起来呈正态分布。现在,我们通过绘制预测中值价格与实际中值价格的平价图来说明该算法在训练集和测试集上的性能。

列车数据的奇偶图

测试数据的奇偶图
这令人印象深刻,因为我们现在能够给出每个数据点的(95%预测区间)预测范围,其准确度约为 90%。我们还可以在测试集上计算 rmse 和其他指标。
测试集上的 rmse 为 3.52,r 平方值为 0.89,pearson r 为 0.94。现在,让我们检查一下作者们的说法是真是假。我们用 python 对波士顿住房数据运行了 XGBoost 算法:
这两种实现之间只有微小的差别。通过一些超参数优化,结果可能会改变(我也对训练和测试集使用随机 80–20 分割)。总之,bartmachine 的性能令人印象深刻,因为它也可以给我们一些内在的估计不确定性。
我们还可以使用 bartmachine 中可用的函数来绘制特性重要性:

特征重要性图
摘要
- BART 是一种非常复杂的算法,能够提供与用于构建模型的参数相关的内置不确定性估计。
- 对于各种各样的现实世界机器学习问题,BART 是一个很好的选择。
- 它可以用于设计空间的迭代探索(贝叶斯主动学习),以最小化收集昂贵数据的成本。
大型复杂系统入门
原文:https://towardsdatascience.com/a-primer-to-big-complex-systems-3aba21849fb9?source=collection_archive---------53-----------------------

图片来自 Pixabay 的 WikiImages 。
航天飞机、电信网络,甚至新的高科技创业公司都是大型复杂系统的家园。这些系统雇佣了不同团队的数千名软件开发人员。尽管大系统没有一个确切的科学定义,我们将包含多个服务的系统称为“大系统”通过大量的维基百科链接提供了额外的清晰度,但整体结构的灵感来自于马丁·凯普曼的“设计数据密集型应用
这些系统可以容错,这意味着一个部分偏离预期行为不一定会削弱系统的其余部分。它们还可以自我修复,即在某些意外情况下,系统服务可以自动恢复,无需人工干预。它们也可以是幂等的,这意味着在系统中多次运行输入不会比第一次运行相同的输入改变系统的状态。这些系统可以是无状态的,这意味着服务的任何实例都可以处理任何输入,或者相反是有状态的,这意味着一些实例专用于处理特定的输入。推荐无状态,因为它使我们的组件从令人头疼的协调中解脱出来,这将在后面讨论。
这些系统的输入满足一些先决条件。如果执行成功终止,它们的输出必须满足一组后置条件。这被称为合同设计,是系统所有正确性测试的基础。
这些系统满足功能需求,这意味着系统应该做它应该做的事情。以 Airbnb 为例;列出西雅图所有的海滨别墅,点击应用程序的按钮时预订正确的海滨别墅是两个功能需求。
这些大系统也满足非功能性需求。非功能性需求依赖于应用程序的业务需求;它们包括(但不限于)可用性、可伸缩性、可靠性、一致性和性能(无论是响应时间、吞吐量,还是另一个度量)。例如,预订海滨别墅应该在可接受的时间内(可能不到 5 秒),并且网站应该整天都在运行。
术语
- 节点是网络上的单台计算机(或设备)。
- 系统状态是指系统跟踪的元数据。
- 读请求是在不改变系统状态的情况下从数据库中获取的一条信息。
- 写请求导致系统状态改变。
微服务的炒作
在本文中,我们讨论“无共享”架构,即那些依赖于水平伸缩的架构。这些系统通过一起添加更多节点来扩展,而不是用额外的资源(如 CPU、内存和硬盘)来增强同一个节点。这是业内使用的主要模式,并在云计算中使用。
到目前为止,我们将系统的不同部分称为组件。业内使用的术语是微服务(早期面向服务架构的更名)。很像面向对象编程中的类,微服务应该有一个单一的职责。我们不应该仅仅因为方便就把不相关的功能聚集到一个微服务中。
应用程序架构应将数据节点与控制节点(即数据库中的数据)和“计算”节点中的控制逻辑分开。数据确实比代码更长寿,所以如果我们需要修改系统,混合关注可能是一场噩梦。通常,代码应该准备好处理向后和向前兼容性,这有点棘手。
这些不同的微服务使用网络调用或队列进行交互,以满足功能需求。它们应该是模块化的和可维护的。这些微服务应该是可扩展的,即能够在系统变化最小的情况下提供 10 倍的流量,并且在纵向扩展系统时几乎没有明显的性能差异。
设计一个微服务很像设计一个应用编程接口(API) 。微服务应该在稳定且相对简单的抽象背后隐藏大量的实现细节。他们应该不惜一切代价避免意外的复杂性。
现在,这些微服务使用队列、数据库、缓存和协调服务来完成它们的工作。就像在编写程序时导入库一样,使用数据库或队列使设计服务变得更容易,因为您依赖于数据库或队列提供的保证。
数据库
我们使用术语“数据库”作为一个包罗万象的术语。使用这样的定义,几乎每个数据节点都可以被认为是一个数据库。数据库有不同的类型和风格,从关系数据库到文档数据库,从图形数据库到分布式缓存。一些人认为,即使是队列也是一种特殊的数据库。
通常,数据库的选择是根据应用程序中涉及的实体、它们的关系以及预期的加入流量来进行的。例如,一个图形数据库可以用一个关系模型来表示,该模型在各行之间有大量的连接,这降低了开发人员的工作效率和数据库的性能。
将密钥映射到硬盘的数据库模块称为存储引擎。通常使用日志结构合并树(LSM) 或 B 树来实现。不管索引是如何实现的,数据库都使用预写日志(WAL) 将事务写入磁盘,然后再将它们应用到数据库。它是用来在系统崩溃时恢复系统的。
一些数据库为事务提供 ACID (原子、一致性、隔离和持久性)保证。原子的意思是“要么全部要么什么都没有”一致性高度依赖于应用程序对它的定义。隔离意味着一个事务独立于所有其他事务执行。持久性意味着在向应用程序确认成功之前,更改被持久保存在磁盘上(或复制到不同的节点)。
隔离级别
数据库异常源于应用程序的使用和隔离级别(数据库的保证)。对于某些应用程序,这些异常永远不会发生。异常情况的例子包括:
- 脏读:一个事务读取一个已经被另一个事务修改过但还没有提交的记录。
- 脏写:一个事务写入一个已被另一个事务修改但尚未提交的记录。
- 不可重复读取:一个事务读取同一个记录两次,在整个事务中得到不同的结果。
- 幻影读取:在交易过程中,记录被添加/删除。
- 丢失更新:一种竞争条件,其结果是由于一系列不受控制的事件造成的。例如,几个事务可能同时执行,因此一个写操作会覆盖另一个。
- 写偏斜:基于陈旧数据的更新事务。
为了处理上面提到的一些异常情况,学术界和工业界的工程师提出了隔离级别。尽管这些隔离级别是标准的,但在尝试使用它们之前,最好多读几遍特定数据库的文档:
- 提交读:允许无脏读和无脏写。
- 快照隔离:写不阻塞读,读不阻塞写。每个事务都基于数据库的一致快照。
- 可串行化:即使使用了多线程,也能模拟串行执行。这种隔离模式处理所有数据库异常。实现方式有:串行执行,悲观锁:两阶段锁,或者乐观锁。
缩放比例
扩展包括复制和分区。我们专门为每一个小节。
分身术

图片由来自 Pixabay 的 Herbert Bieser 提供。
分布式系统的第一条规则是节点失效。他们突然地、出乎意料地失败了。为了防止节点故障时数据丢失,我们使用复制,因为它提供了冗余。如果数据只存在于一个节点上,那么我们将需要手动干预来恢复数据并解除阻止试图从故障节点访问其帐户信息的用户。人工干预不利于非常理想的自愈。人工干预需要几个小时,自我修复只需几秒钟。
防止单点故障(SPOF) 的一种方法是将所有数据从一个节点复制到其他节点。复制还有助于提高读取流量性能,因为读取可以定向到更多节点,从而减轻了每个节点的压力。虽然复制是有益的,但它的困难在于保持数据与写请求同步。我们简要讨论三种复制模型。
单头复制
由于相对简单,这是主要的模型。这是在 PostgreSQL 、 MySQL 和 MongoDB 以及其他许多应用中使用的模型。
读取请求可以定向到系统中的任何节点(称为读取副本)。另一方面,写请求必须指向在较早的时间点选出的领导者(或主机)。然后,领导者将更改流(复制日志)传递给其他节点。复制日志可以使用不同的方法实现,如预写日志或基于语句的复制。
一些系统使用主动反熵或读取修复在不同的节点上复制数据。主动反熵通过比较节点间的 Merkle 树、哈希的树来计算出哪些子树需要从一个节点复制到另一个节点。读取修复仅依赖于读取流量来复制不同节点上的数据。如果记录从未被读取,那么数据将无限期地保持陈旧。Riak 为用户提供了两种选择。
与我们之前讨论的 ACID 模型相比,复制滞后产生了 BASE(基本可用、软状态、最终一致性)。基本可用意味着读写流量尽可能可用。软状态意味着读取副本之间的状态可能略有不同。最终一致性意味着最终(在没有额外的写入流量之后),状态将在所有读取副本中保持一致。
非领导者并不重要,它的失败不会影响系统的状态。然而,领导者故障转移并不简单,必须小心实施。在检测到领导者的失败时,读取复制品应该选举新的领导者来接管。选举新领导人的过程被称为达成共识,我们将在本文稍后讨论。
多领导者复制
网络分区确实会发生,而且发生的范围很广。网络分区是指系统中的一些节点与网络中的其他节点断开连接。当单个领导者模型发生这种情况时,写入会被阻止。
这产生了多领导者架构,其中少数领导者可以处理写流量。这些系统更加复杂,需要领导者之间的协调。缺点是写入需要其他节点的一致同意。
无领导复制
对于无领导复制,没有节点是特殊的。我们必须写入许多节点(w;写仲裁)和从许多节点(r;read quorum ),其中 w + r > n(节点数),以获得一致的数据。
分割

Nuno Silva 在 Unsplash 上拍摄的照片。
如果我们有一个包含数百万条记录的大型数据库,不可能将所有数据存储在一个节点上。我们必须按照我们坚持的“水平扩展”方法,在多个节点上以某种方式分割数据。每个节点可以有一个(或多个)分区。
有两种流行的分区方案:
按键分区
- 简单且易于实施
- 产生“热点”,其中大部分流量只被定向到一些节点
- 范围查询很简单
通过关键字的散列进行分区
- 不同版本之间的哈希函数必须一致
- 通过将节点更均匀地分散到多个节点,减少了“热点”
- 范围查询被传递给所有分区,就像在 MongoDB 中,对于其他数据库,像 Couch 和 Riak,它们不支持范围查询
复制和分区一起进行
在一个大系统中,复制和分区是齐头并进的。节点将有不同的分区副本,如下图所示。

该图来自“设计数据密集型应用程序”
大系统中的协调
协调不是系统的功能需求,而是设计选择。一些系统可以将协调问题外包给缓存、数据库、分布式锁管理器或 Zookeeper。
协调问题包括:
- 选举领导服务器(共识)
- 管理组成员资格
- 崩溃检测:跟踪可用的服务器
- 服务发现
- 将工作分配给节点
- 管理元数据,如分区和故障转移
- 分布式锁管理
尽管有处理共识的算法,如 Paxos 和 Raft ,但它们并不简单。实现很容易导致错误。外包给第三方系统(如 Zookeeper)只有在牢记第三方系统不可用时产生的运营开销时才有意义。
网络问题
文章开头提到,我们依靠商品硬件和网络来构建所谓的大系统。这种选择不是没有权衡的。网络不可靠,会导致以下问题:
- 消息延迟和网络分区:没有好的方法来区分网络延迟、网络分区、过载节点或节点崩溃。我们能使用的最好方法是心跳超时,假设一个节点关闭。
- 时钟漂移:即使使用网络时间协议(NTP) ,节点也永远无法确定正确的时间。时钟漂移会导致各种各样的问题,从领导者不更新其领导地位,到拥有过期锁的节点认为它仍然有效。
在单领导者架构中,领导者认为自己是领导者,而它不再是领导者(由于网络分区或时钟漂移),这可能导致裂脑,从而导致数据损坏。在这种情况下,可以使用击剑令牌。
过时的上限定理
尽管已经过时了,CAP 定理指出人们只能从两个事物中选择一个,即一致性或可用性,因为网络分区一直在发生。一致性一般是一个模糊的术语,所以我们用单词“可线性化”来代替,一个非常强的一致性模型。
可线性化意味着如果操作 B 在操作 A 完成后开始,操作 B 必须将相同状态的系统视为完成 A 或更新的状态。它不同于 serializable,因为它不假设并发事务。
系统可以是 CP 或 AP;它们可以是一致的(可线性化的)或可用的,但不能同时是一致的和可用的。社交媒体等一些系统牺牲线性化来获得高可用性,而银行等其他应用牺牲可用性来获得线性化。

注意 CA 不可用,只有 CP 和 AP 模式可用。来源:亚斯敏·穆萨提供。
在本文中,我们讨论了具有“无共享”架构的大型系统。我们描述了我们希望在分布式系统中看到的期望属性,如可用性、可靠性和可伸缩性。我们还描述了不同类型的数据库及其隔离级别。然后,我们讨论了扩展系统的一些注意事项,如分区、复制和一致性。
构建一个大的复杂系统是令人兴奋的努力;现在你正在理解,甚至建立你自己的道路上。
这篇文章最初发表在项目 Nash 上。
你最后一次网飞狂欢的概率
原文:https://towardsdatascience.com/a-probabilistic-take-on-your-last-netflix-binge-86d5296b727f?source=collection_archive---------24-----------------------
随机过程的解析和数值/模拟分析
本文采用分析的方法来分析最近流行的网飞系列中的一款游戏——乌贼游戏。我们将制作陈述来描述游戏中涉及的概率,并将使用模拟分析来确认结果。
剧透警报:
这篇文章揭示了网飞的鱿鱼游戏系列中的一些游戏的细节。我还将从总体上谈论剧情,这可能会揭示一些你只有在几个小时的紧张阅读之后才能了解的信息。如果你打算以后看乌贼游戏,我建议你把这篇文章收藏起来,只有在你看完之后再回来看。

美丽的秋天。由 Marek Piwnicki 在 Unsplash 上拍摄的照片。
《鱿鱼游戏》
到今天为止,乌贼游戏仍然是网飞有史以来最受关注的系列。这部最近上映的韩国电视剧以一场比赛为特色,456 名深陷金融危机的玩家互相对战,争夺赢得约 10 亿₩45 奖金的机会。这场比赛包括 6 个主要的致命游戏,在此期间,不同数量的玩家被淘汰和死亡。我们后来发现,奖金和游戏,据说是通过投注金额放置的贵宾,一个秘密小组的外国人谁一直在游戏和球员打赌。
为了使 VIP 的下注过程尽可能令人兴奋,游戏被设置为玩家需要各种技能和力量来通过每场游戏。例如,体力和策略在第三款拔河游戏中扮演着重要的角色,在这款游戏中,失败的一方将从一个高高竖立的建筑物上跌落并摔死。或者在第一场比赛中,一场敏捷和专注的比赛,玩家需要快速和良好的平衡来逃避死亡。
第五场比赛
但也许唯一一个玩家的命运完全由机会决定,运气是唯一决定因素的游戏是第五个游戏,玻璃垫脚石。在这款游戏中,玩家需要穿过一座连接两个高架在地面上方的平台的桥梁。这座桥由几个部分组成,每个部分由两块并排放置的玻璃面板组成。玩家需要从一个区域跳到下一个区域,每次跳跃时,他们需要跳到两个玻璃面板中的一个上,要么是右边的,要么是左边的。这两块面板看起来完全一样。然而,一种是普通玻璃,会在玩家将它们送向灭亡的重量下破碎,另一种是钢化玻璃,更坚固,可以承受玩家的重量。每一个正确的跳跃到钢化玻璃面板上,并且每一次消除向剩余的玩家展示该部分的钢化玻璃。在游戏开始之前,通过随机过程给每个玩家分配一个等级。等级决定了他们登上舰桥的顺序。除此之外,所有玩家都被集体给予一定的时间过桥,否则将面临灭顶之灾。这个游戏显然对玩家不利,玩家一开始就去。但是他们比后面的玩家差很多吗?这就是我们在本文中要量化和衡量的。这个 YouTube 视频展示了游戏的 VR 版本。

一座由五部分组成的桥。玩家无法分辨面板(图片由作者提供)。
在实际的系列赛中,在游戏的这一点上,只剩下 16 名玩家,每个人随机分配一个从 1 到 16 的数字,这决定了他们踩桥的顺序。这座桥由 18 部分组成(每部分有两块玻璃板)。任何成功通过所有 18 个部分而没有被淘汰的玩家走上平台并被拯救(暂时的!).
分析
我碰到一个 Python 模拟,计算每个玩家的生存概率,我觉得很有趣。我还编写了我的小 Python 模拟,并获得了类似的结果(见下一节)。然而,我决定对概率进行分析建模,为每个生存概率生成封闭形式的表达式,以便可以计算任意数量的玩家和区域的概率。在我们存在之前,让我们把我们的假设列表放在一起。
假设:我假设,
- 一旦一个步骤中的钢化玻璃被识别出来,它将被所有还没有到达那个步骤的玩家记住。
- 除了踩在玻璃板上,没有什么能显示这是普通玻璃还是钢化玻璃。
- 玩家根据他们的等级进行游戏,而不用走到另一个玩家站着的面板上。
符号:这里是我用来模拟概率的符号。

从首先站在桥上的不幸选手开始,1 号选手。让我们找出她生存的概率和她在任何阶段被淘汰的概率。

这意味着,对于参与人 1,被淘汰的概率,以及安全过桥的概率是,

对于参与人 2 来说,在阶段 m 被淘汰的概率是一个条件概率。

通过归纳,我们可以得出参与人 2 的如下一般陈述。

这意味着,对于参与人 2 来说,被淘汰的概率,以及安全过桥的概率是,

使用条件概率,通过归纳,我们可以发现 3 号和 4 号玩家在阶段 k 被淘汰的概率如下。

通过归纳,我们可以发现玩家等级 r 在阶段 m 被淘汰的概率如下。基于此,可以推导出玩家 r 在任一阶段被淘汰的概率,以及玩家 r 安全到达另一平台的概率。

证明:上述说法很容易用归纳法证明,假设 r=K-1 的概率,并在此基础上推导出 r=K 的概率,从而证明该说法。该证明的大致要点是,对于在第 m 段失败的玩家 r (其中 m 至少等于 r ),我们需要让所有的 r-1 玩家在 m-1 阶段的某处失败。发生这种情况有 (m-1)C(r-1) (二项式系数)种情况,每种情况的概率为 2 的 -m 。详细证明联系我!
基于以上结果,玩家 r 在任一阶段失败,并成功过桥的概率为,

2F1(a,b;c;z) 函数是超几何函数,它是广义超几何函数的一种特殊形式,描述如下:

要了解更多关于 Hypergoemetric 函数的信息,请参见此链接。
幸存者人数
我可以想象,当组织者为贵宾们安排比赛时,预期的幸存者人数一定发挥了作用。让我们定义离散随机变量 X 来表示每轮游戏中幸存的玩家数量。为了找到 E(X) ,我们需要计算出它的概率质量函数。对于 N=16 和 *K=18,*的博弈,可以推导出,

对于 *X、*的其他结果的概率,我们先来回顾一下结果 X=1 和 X=2 的概率,然后再进行推广。

总的来说,我们可以说,

**证明:**证明可以用归纳法构造。一般来说, X=0 、 X=N 和 X > N 的概率是不言自明的。对于剩下的选项,记住幸存的事件玩家 k 是幸存的事件玩家 k+1 的子集,以及被淘汰的事件玩家 k+1 是被淘汰的事件玩家 k 的子集是有益的。利用样本空间和事件的概率,你可以得出上面的结论。
幸存玩家的预期数量将会是,

这简化为,

换句话说,幸存玩家的期望数量是所有玩家成功概率的总和。在下一节中,我们将对上述结果进行数值分析。
数值分析
基于上面的闭合表达式,我们可以找到每个参与者的生存概率,其中有 16 个参与者,桥有 K=18 个阶段。Python 脚本如下所示。
当有 K=18 个区域时,每个玩家的结果如下所示。是的,前面的玩家比后面的玩家要差得多。最后 4 名队员生还概率高于 90%。

使用分析结果的 N=16 和 K=18 的生存概率。
这是当 K=18 时,16 个玩家中每一个的生存概率的可视化。

N=16,K=18 的生存概率(图片由作者提供)。
下面你可以看到 16 名玩家( N=16 )生存概率的相同可视化,但是是针对不同数量的部分( K )。请注意,随着桥上增加更多的部分,概率会迅速下降。

N=16 和不同 K 值的生存概率(图片由作者提供)
对于这个具有 N=16 和 K=18 (16 个玩家和 18 个区域)的特定游戏,以下是随机变量 X 的概率质量函数,代表幸存玩家的数量。

我们可以看到,该模式在 X=7 处,代表 7 个玩家以大约 0.185 的概率幸存。也许并不奇怪(注意对称性),这个特定游戏中幸存玩家的预期数量也大约是 7,或者确切地说 E(X)=7.000076294 。如果贵宾们期望幸存玩家的数量在 7 左右,他们一定会惊讶地发现只有 3 名玩家在第 5 场比赛中幸存。
下表显示了不同场景下的 E(X) 的值,以及不同玩家数量和区域的值( N 和 K )。

不同 N 和 K 值下的预期幸存者人数(图片由作者提供)
以下可视化了不同的 N 和k值下幸存玩家的期望值趋势( E(X)

不同 N 和 K 值下的预期幸存者人数(图片由作者提供)
观察该图,我们可以看到,对于任何给定的玩家数量,增加阶段的数量将减少幸存玩家的预期数量。正如所料,对于相同数量的部分,更多的玩家意味着更高的幸存玩家数量。
生存模拟
有了足够多的迭代次数,我们还可以用不同的值 N 和 K 来创建一个模拟,以找到玩家存活的概率以及存活玩家数量的期望值。下面是我写的一个简单的函数,用来计算每个玩家的生存概率。
在对 16 个玩家、18 个区域和 1,000,000 次迭代(游戏回合)运行该函数后,我计算出的 16 个玩家的生存概率与我分析得出的结果几乎相同。

使用模拟的 N=16 和 K=18 的生存概率。
我只模拟了 N=16 和 K=18 情况下的预期幸存者人数。结果非常接近我上面的分析结果。我对 1,000,000 次复制的模拟产生了预期的 6.997991 个幸存者,而分析结果给出了 7.00076294。我没有模拟寻找其他值 N 和 K 的幸存玩家的预期数量,但我认为它们应该也非常接近。
分析结果与模拟
我们得出了不同的 N (玩家数量)和 K (阶段数量)的生存概率和期望生存人数的分析结果。我们还使用数值/模拟分析证实了这些结果。但是哪种方法更有效呢?
一般而言,分析结果往往比模拟结果更受青睐。分析结果特别有用,因为它们提供了分析中的通用性、计算速度和效率。除此之外,分析结果非常有助于产生数值结果和敏感性分析。然而,封闭形式的表达式并不总是可用或容易导出。在这些情况下,模拟可以提供相当准确的结果。在这个特定的模型中,相对容易得出分析结果。然而,如果以随机事件或玩家之间复杂交互的形式给系统增加更多的复杂性,那么导出封闭形式的概率表达式来捕捉生存概率和期望值将变得越来越困难。在这些情况下,模拟可以帮助我们更容易地获得结果。
异常值检测和监控的生产就绪方法
原文:https://towardsdatascience.com/a-production-ready-approach-for-outlier-detection-and-monitoring-5862a75ab4ad?source=collection_archive---------28-----------------------
一种从生产数据集中检测(并移除)异常值的方法。
介绍

威尔·梅尔斯在 https://unsplash.com 拍摄的照片
ML 项目中的生产数据经常受到异常(也称为离群值)的污染。这些异常值可能是由过程中的错误引起的,或者只是数据集的一部分。识别并纠正它们非常重要,因为它们会干扰您对数据的建模/解释。
在本文中,我们将介绍一种生产就绪的方法,以便检测和监控异常值,使您能够节省一些宝贵的时间来构建您的 ML 管道。
第一步,我们将展示一种使用四分位间距(IQR)检测列异常值的简单有效的方法。
第二步,我们将从多维角度(多列)处理离群值,并使用隔离林自动检测它们。
最后,我们将展示一种使用 pandera(一个统计数据验证工具包)监控数据库的有效方法。
本项目中使用的数据集可在 data demo outliers 获得。这是一个虚构的数据集,表示圣保罗的房地产数据。它包含 6 列,分别代表房间(房间数量)车库(车库数量)有用面积(单位面积)价值(单位价格)室内质量(单位室内质量)上市时间(出售单位所需时间)。我在 6 个专栏中介绍了几个异常,以展示下面介绍的方法的有效性。
这篇文章的代码可以在这个 github 库上找到。
包括每个部分的 jupyter 笔记本示例()。/demo/Explore _ outliers _ per _ column . ipynb,
。/demo/Explore _ outliers _ multi _ columns . ipynb,。/demo/Monitor _ outliers _ pandera . ipynb
使用 IQR 轻松检测列方向的异常值

Jhguch 的照片来自 en.wikipedia
四分位数间距(IQR)是统计离差的一种度量,等于第 75 个和第 25 个百分点之间的差值,
或者相当于上下四分位数之间的差值,IQR = Q3 Q1。
它可用于从我们的数据中提取每一列的最异常值。
一种方法是将 Q1-1.5 * IQR,Q3 + 1.5 * IQR 范围之外的每列数据视为潜在的异常值。
对于每一列,我们可以查看包含所有值的分布与排除这些异常值的分布。
当分布具有非常不同的形状时,它会突出显示列中异常值的存在,如下图所示。

IQR
在这里,我们可以在第一行看到市场上价格、面积和时间的完整分布。在第二行,我们在
绘制分布图之前应用了 IQR 滤波:
我们可以看到,在没有过滤的情况下,分布是高度偏斜的,突出了异常值的存在。
过滤后的图更能代表真实的数据分布。根据这些图和我们对数据的了解,我们可以决定每列可以接受的数据范围。
对于本例,我们预计价格不会超出 50 000–10 000 000 雷亚尔的范围,面积不会超出 20–850 平方米的范围,上市时间不会超出 0–400 天的范围
。我们可以为我们的每一列执行这种类型的异常值 EDA。这将有助于使用 pandera 为
部分中的每一列设置我们的业务规则,以便进行异常值监控。
隔离林用于检测多列中的异常值

隔离林不同阈值的 PCA 图
在很多情况下,需要从多维角度检测异常值。例如,您的模型可能依赖于许多特征。在这种情况下,检测每个特征的异常值(对于结构化表格数据是每个列)是不够的。你想要做的是多维度地对待异常值。隔离森林是识别这些异常点的理想工具。
隔离森林属于无监督学习算法的范畴。它将异常观察与样本的其余部分隔离开来,因为它们在特征空间中显得很遥远。这是一种建立在决策树基础上的树集成方法。该算法递归地生成分区,首先随机选择一个特征,然后在所选特征的最小值和最大值之间选择一个随机分割值。该过程继续进行,直到单个点被隔离或者达到指定的最大深度。一旦该算法遍历了整个数据,它就认为异常数据点比其他数据点采取的步骤更少而被隔离(需要更少的分裂来隔离它们)。
对于这个项目,我使用了来自 Scikit-Learn 库中的隔离林实现。训练之后,可以调用预测方法来了解特定样本是否是异常值。正常样本标记为 1,异常值标记为-1。为了可视化我们的高维数据,可以将 PCA 应用于特征以降低数据的维度(根据方差)。然后,我们可以绘制前三个组件,突出显示绿色正常数据和红色异常值。我们可以看到异常有远离主数据的趋势。这是对隔离森林算法的应用进行质量控制的一种有用的方法。识别异常和生成 PCA 图的代码可以在下面找到(更多细节可以在 github 库获得)。
在某些情况下,控制您的异常阈值或您希望被视为异常的数据点的最大数量可能会很有用。为此,调用 score_samples 方法来获得数据集每个点的异常值是很有用的。然后,您可以在箱线图中显示这些分数(下图示例),以便选择不同的阈值。分数越低,数据点就越不正常。选择较低的阈值将允许减少要检测的异常点的数量。

异常分值的箱线图
您甚至可以决定您希望被视为异常的数据集的百分比。所有这些行为的例子都在 jupyter 的笔记本上演示过。/demo/Explore _ outliers _ multi _ columns . ipynb,使用中创建的函数。/demo/outliers_util.py 。
我们为不同的异常阈值生成了 3D PCA 散点图,以创建 gif 插图。我们可以看到,对于异常值检测,我们可以决定更保守或更保守。
这是在您的 ML 管道中使用的一个非常强大的工具,因为数据集中异常的存在会干扰您的模型行为/性能。
通过使用隔离林自动检测和移除最异常的数据点,您可能会提高您的整体模型性能。特别是,如果您的生产数据包含大量样本(高维),移除 0.5%最异常的样本(几乎没有额外成本)将是一个很好的生产实践。
用 pandera 监控你的数据:熊猫的统计数据验证工具包
在生产环境中,数据库会定期更新,并且应监控异常情况。现在我们已经了解了检测和消除生产数据中异常值的技术,我们将了解如何定期监控您的数据库,并使用 Pandera 执行统计验证检查。Pandera 提供了一个灵活且富有表现力的数据验证工具包,帮助用户对 pandas 数据结构进行统计断言。
基于您对数据的了解,您可以轻松地使用 Pandera 来实施规则,以检查要素中的类型和可接受范围。作为下面的例子,我们为演示数据集创建了一些规则。正如我们在异常值 EDA 中看到的,列有用区域应该是一个浮点值,我们不希望值超出 20–850 m2 的范围。
同样,我们为剩余的列 value (价格) rooms 、 garages 、 time_on_market 和 interior_quality 创建了规则。例如,列 interior_quality 应该包含 1、2、3、4 或 5 范围内的整数值。下面是我们演示数据集的代码示例。
基于数据集知识定义规则后,您可以定期运行 pandera 代码来识别数据库中的新异常。如果一些新数据点不遵守您定义的规则,它将输出一些警告消息,突出显示需要纠正的问题。这是确保数据库在不同时间段的数据质量的一种强大而简单的方法。
下面是一个例子,说明在我们没有从数据集中移除异常值的情况下,输出会是什么样子。

输出 Pandera 警告
结论
我们提出了一种从生产数据集中检测(和去除)异常值的方法。
首先,对于每一列,IQR 可用于探索、识别和移除异常数据点,如果您的分布形状受到异常值的影响,则使用分布图进行质量控制。
其次,从多列的角度,我们已经看到了如何使用隔离森林来自动检测特征空间中的异常观察值。在训练您的模型之前移除这些异常将提高您的 ML 管道的稳健性。
然后,我们提出了一种方法来监控您的生产数据,并在不同的时间段检测新的异常。Pandera 使统计数据验证变得容易,确保您的数据库定期无异常。
所有这些技术都有助于确保更好的数据质量,使您能够通过关注 ML 管道的其他领域来提高工作效率。
参考
刘、范晓东、丁肇中、、周志华。“基于隔离的异常检测。”《美国计算机学会数据知识发现汇刊》6.1 (2012): 3。
[https://cs . nju . edu . cn/Zhou zh/Zhou zh . files/publication/tkdd 11 . pdf刘、范晓东、丁肇中、、周志华。“隔离林。”数据挖掘,2008。08 年的 ICDM。第八届 IEEE 国际会议。
[https://cs . nju . edu . cn/Zhou zh/Zhou zh . files/publication/ICD m08 b . pdf?q =隔离森林[https://towards data science . com/outlier-detection-theory-visualizations-and-code-a4fd 39 de 540 c]
[https://www . pyo pensci . org/blog/pandera-python-pandas-data frame-validation]
[https://towards data science . com/how-automated-data-validation-make-me-more-productive-7d6b 396776]
潘德拉文档:
[https://pandera.readthedocs.io/en/stable/]
处理大于内存的数据集的 PySpark 示例
原文:https://towardsdatascience.com/a-pyspark-example-for-dealing-with-larger-than-memory-datasets-70dbc82b0e98?source=collection_archive---------1-----------------------
一个关于如何使用 Spark 对大于内存的数据集执行探索性数据分析的分步教程。
使用 Jupyter 笔记本和 Pandas 数据框分析大于可用 RAM 内存的数据集是一个具有挑战性的问题。这个问题已经解决了(例如这里的这里的或者这里的这里的),但是我在这里的目标有点不同。我将介绍一种对大型数据集进行探索性分析的方法,目的是识别和过滤掉不必要的数据。希望最终熊猫可以处理过滤后的数据集进行剩余的计算。
这篇文章的想法来自于我最近的一个项目,涉及对开放食品事实数据库的分析。它包含在世界各地销售的产品的营养信息,在撰写本文时,他们提供的 csv 出口量为 4.2 GB。这比我在 Ubuntu 虚拟机上的 3 GB 内存还大。然而,通过使用 PySpark,我能够运行一些分析,并且只从我的项目中选择感兴趣的信息。
为了在 Ubuntu 上设置我的环境,我采取了以下步骤:
- 安装 Anaconda
- 安装 Java openJDK 11: sudo apt-get 安装 openjdk-11-jdk。Java 版本很重要,因为 Spark 只能在 Java 8 或 11 上运行
- 安装 Apache Spark(3 . 1 . 2 版本为 Hadoop 2.7 此处)并配置 Spark 环境(将 SPARK_HOME 变量添加到 PATH)。如果一切顺利,你应该可以在你的终端上启动 spark-shell 了
- 安装 pyspark:conda install-c conda-forge pyspark
如果你有兴趣阅读 Spark 的核心概念,这是一个好的开始。如果没有,您可以打开 Jupyter 笔记本,导入 pyspark.sql 模块并创建一个本地 SparkSession:
我使用 sc.read 从我的 SparkSession 中的大型 csv 文件读取数据。尝试在只有 3 GB RAM 的虚拟机上加载 4.2 GB 文件不会出现任何错误,因为 Spark 实际上不会尝试读取数据,除非需要某种类型的计算。
结果是 pyspark.sql.dataframe 变量。重要的是要记住,此时数据并没有真正载入 RAM 存储器。只有在对 pyspark 变量调用一个操作时,才会加载数据,这个操作需要返回一个计算值。例如,如果我要求计算数据集中产品的数量,Spark 很聪明,不会为了计算这个值而尝试加载全部 4.2 GB 的数据(将近 200 万个产品)。
我使用 pyspark 的 printSchema 函数来获取一些关于数据结构的信息:列及其相关类型:

为了开始探索性分析,我计算了每个国家的产品数量,以了解数据库的组成:
BDD_countries 也是 pyspark 数据框架,其结构如下:

我可以过滤这个新的数据框,只保留数据库中记录了至少 5000 种产品的国家,并绘制结果:

例如,从这里我可以过滤掉所有在法国买不到的产品,然后在一个更小、更容易处理的数据集上执行其余的分析。
本文介绍了一种在 Python 中处理大于内存的数据集的方法。通过使用 Spark 会话读取数据,可以执行基本的探索性分析计算,而无需实际尝试将完整的数据集加载到内存中。当我们希望能够获得数据的第一印象并寻找识别和过滤掉不必要信息的方法时,这种类型的方法会很有用。
R markdown 的 python 等价物
原文:https://towardsdatascience.com/a-python-equivalent-for-r-markdown-d6fba36dc577?source=collection_archive---------25-----------------------
R markdown 是分享见解的强大工具。在这篇文章中,我们将展示如何用 python 编写类似的报告。
R markdown 是一个与利益相关者分享见解的强大工具。您可以编写生成图的 R 代码片段。然后可以将其编译成 HTML 或 pdf 文件,与非技术相关人员共享。
这在 python 中没有这么简单。是的,Jupyter 笔记本是与其他开发人员共享分析的一种很好的方式。但是编译成 HTML/pdf,去掉代码片段,对于非技术利益相关者来说已经很不错了,我发现使用 Jupyter 笔记本很笨拙。R markdown 也有很棒的工具来生成好看的表格,而不仅仅是绘图。
不过,我一直在和一个 python 重型团队一起工作,所以一直在试图弄清楚如何生成 R markdown 风格的文档。在这篇文章中,我将概述我用 python 生成的 HTML 报告,这些报告看起来很好,足以与非技术利益相关者分享。这个过程使用一些工具。

卢克·切瑟在 Unsplash 上拍摄的照片
步骤 1:在 HTML 中嵌入绘图
第一步是将图嵌入到一个静态 HTML 中,然后可以与他人共享。一个很好的工具是 plotly 。Plotly 有一个[to_html](https://plotly.com/python-api-reference/generated/plotly.io.to_html.html) 函数(我的一个了不起的同事发现了这个),它将把图形写成 HTML 字符串,然后你可以把它写到一个文件中。
Plotly 图形看起来像零件,它们允许用户将鼠标悬停在点上,以查看值是多少;我发现这很受顾客欢迎。
有时用户需要可以复制粘贴的图形。在这种情况下,我推荐使用 python 更标准的绘图库,如 seaborn 或 matplotlib 。要将图像嵌入到 HTML 中,而不需要 HTML 引用的单独的图像文件,这就有点复杂了。但是您可以通过将图像编码为 base64 并直接写入您的 HTML 来实现。只需按照这个 stackoverflow 帖子中的说明。

照片由 Pankaj Patel 在 Unsplash 上拍摄
步骤 2:设置 HTML 文档的布局
太好了,现在你可以在 html 中嵌入图形了,实际上如果你关闭了 plotly 的to_html函数中的full_html选项,你就可以通过添加字符串来编写任意多的 plotly 图形到 HTML 文件中。
但是布局、评论和数据表呢?这就是我使用 python 的 HTML 模板库的地方——它允许您使用 python 从模板生成静态 HTML 文件。这种技术非常强大,用于 python 后端开发库,如 flask 和 django 。学习起来很快,但是需要一些 HTML 知识。
我使用 Jinja 库来生成我的 HTML 报告(这是 python 中最流行的 HTML 模板库之一)。
第三步:让报告看起来漂亮
对于任何以前使用过 HTML 的人来说,你会知道做任何看起来像样的东西都需要很长时间。
我不想在这上面花太多时间,因为我想尽快生成报告。所以我用了 bootstrap CSS 库。这个工具可以让你在很短的时间内让你的报告看起来很漂亮(我倾向于做的就是用<div class="container">把所有的东西都包起来,可能还会添加一些填充)。
Bootstrap 基本上是一组预建的 HTML 类,可以用来格式化 HTML。例如,让一个 HTML 表格在 bootstrap 中看起来漂亮,就像<table class="table">一样简单(在标准 HTML 中,表格看起来很难看)。您可以通过添加<h1 class="pt-1">在标题元素的顶部添加填充。
思想
正如你所看到的,这是一个比 R markdown 更复杂的过程(如果有人有更好的方法,请联系我们!).但是学习这些工具很有用,尤其是 Jinja 和 bootstrap,它们是 web 开发的标准工具。一旦你学会了这些库,并且准备好了一些预制的模板,这个过程会变得很快。
原载于 2021 年 5 月 4 日【https://jackbakerds.com】。
一个 Python 框架来检索和处理来自 TRIOS 传感器的超光谱场测量(MDSA 格式)
原文:https://towardsdatascience.com/a-python-framework-to-retrieve-and-process-hyperspectral-field-measurements-from-trios-sensors-5e900158648e?source=collection_archive---------33-----------------------
思想和理论

哈利全在 Unsplash 上拍照
介绍
随着技术的快速发展,遥感在不同学科中有着广泛的用途,从森林火灾测绘到水质评估、三维表面建模等等。通过在一定距离上测量一个区域的反射和发射辐射来获得该区域的物理特性有许多优点。然而,实地测量与遥感数据同样重要,这样才能开展研究,将远距离“看到”的东西与地面真实情况联系起来。就多光谱遥感图像而言,重要的是使用高光谱传感器进行实地测量,以便校准最终结果。
语境
2021 年初,我的论文导师告诉我,我们需要恢复一些超光谱场测量数据。这些测量已经在世界各地的各种古代地形战役中完成。目标似乎很简单。我应该从 3 个现场传感器(辐照度和辐射度——上升流和天空传感器)检索测量值,以计算最终的反射率(方程式。1).所有的现场测量都是通过使用众所周知的传感器完成的,并且结果被存储在 Microsoft Access 文件中。mdb)。因为有专门的软件来管理。mdb 文件从制造商的传感器,称为 MDSA XE,我认为这将是一个“小菜一碟”。我大错特错了。

情商。1:遥感反射率公式,其中:Rrs =遥感反射率,Lu =上升辐射亮度,Ld =下降辐射亮度或天空辐射亮度,Ed =辐照度。
德国人以他们的工业和设备质量而闻名。那是毫无疑问的。然而,当谈到系统、用户界面或可用性时,似乎总是缺少一些东西。在 MSDA 的例子中,缺少了很多东西。即使像打开文件这样简单的任务也是一个奇怪的操作,需要重启应用程序。我不能依靠它来完成我的任务。
为此,我开发了一个名为RadiometryTrios的“非官方”框架,可用于 Python,这将使事情变得容易得多,不仅可以访问这种数据,还可以从中创建整个数据库。
框架
如前所述,该框架负责使用 TRIOS 设备处理来自野外活动的超光谱辐射测量数据。
操纵包括:
- 从 MSDA/TRIOS 格式的
.MDB文件中提取辐射测量值。 - 辐射测量分析、数据清理和图表绘制
- 波长插值
- 反射率生成(来自辐射和辐照度测量)
- 不同格式的输入/输出
图 1 显示了RadiometryTrios框架的模式。

图 1:辐射测量 Trios 包模式。图片作者。
包中声明的类有:
- BaseRadiometry :这个类拥有一些其他类通用的功能,比如绘图和插值功能。这个类的方法被声明为“静态的”,可以作为简单的函数使用。
- TriosMDB :这个类负责连接到 access。mdb 文件并从中提取辐射度。可以过滤值,以便提取与感兴趣的测量值相对应。
- 辐射度:该类表示来自特定测量(单个传感器,但多次)的辐射度。它允许数据清理,过滤和绘图。
- 辐射测量组:如上所述,为了获得反射率,需要使用来自 3 个不同传感器的值。在这方面,RadiometryGroup 类存储了许多辐射度,并使同时对所有辐射度应用过滤器变得更加容易。它还支持绘图功能。
- RadiometryDB :最后,最后一个类负责创建和维护一个辐射测量数据库,这个数据库来自于已经处理过的许多测量数据。
安装
这个包可以在下面的 GitHub 库中找到:https://github.com/cordmaur/RadiometryTrios
存储库包含关于安装和依赖项的详细信息,但是,总而言之,只需要克隆项目并安装它。
git clone https://github.com/cordmaur/RadiometryTrios.git
cd RadiometryTrios
pip install -e .
注意:
-e选项将在开发者模式下安装这个包,这样可以更容易地对源代码(在项目文件夹中)进行修改,并且这些修改会自动应用,不需要重新安装。
要检查它是否安装正确,请在 python shell(或 Jupyter 笔记本)上运行以下命令:
import RadiometryTrios
RadiometryTrios.__version__
'0.0.1'
包装使用
一旦我们成功安装了这个包,是时候学习如何使用它的许多功能了。
TriosMDB
将涉及的第一类是TriosMDB类。在nbs/文件夹中的笔记本00_TriosMDB.ipynb 详细描述了如何使用它。
需要注意的是,TriosMDB类负责幕后的 ODBC 连接。这意味着您不必手动处理它,唯一的要求是安装pyodbc包,这是强制性的。让我们看看如何打开连接并显示摘要:
{'FileName': WindowsPath('../mdbs/trios_test.mdb'),
'Records': 937,
'IDDevice': "['IP_c090', 'SAM_83AE', 'SAM_83ba', 'SAMIP_5078', 'SAM_83B0', 'SAM_83BA']",
'IDDataType': "['Inclination', 'Pressure', 'SPECTRUM', 'SAMIP']",
'MethodName': "['SAMIP_5078', 'SAM_83AE', 'SAM_83B0', 'DoubleSpecCalc_2', 'SAM_Calibration_Station', None]",
'IDMethodType': "['SAMIP Control', 'SAM Control', 'DoubleSpecCalc', 'SAM Calibration Station', None]",
'Comment': "['Ed deck', 'Lu deck', 'Ld deck', 'reflectance', None]",
'CommentSub1': "[None, 'factor 0.028']",
'CommentSub2': '[None]'}
一旦一个TriosMDB对象被创建,它就用来自tblData表的所有内容填充一个熊猫DataFrame 。这可以通过.df属性来访问。tblData是三重奏/MSDA 格式的默认表格。要访问内容:
mdb.df.head(3)

分析 MDB 文件最基本的操作可能是执行查询。函数exec_query以列表或 pandas 数据帧的形式返回查询结果。exec_query也可用于检查 MDB 文件中的其他表格。让我们检查一下**tblData** (主表)的内容。结果输出可以是数据帧或列表,其中每一项都是一个表示表行的元组。
mdb.exec_query("select top 1 * from tblData", output_format='pandas')

或者结果可以显示为列表:
results = mdb.exec_query("select top 1 * from tblData", output_format='list')
results[0][:6]('2572_2015-11-14_14-29-21_188_038',
1,
'IP_c090',
'Inclination',
'Calibrated',
None)
从 MDB 中选择辐射度
要检索 MDB 文件的测量值,必须指定所需辐射测量类型应满足的条件。这些条件可以是不同列/值的组合,并且必须在字典中指定。每个条件的组合将与一种辐射测量类型相关,也称为 **r 型。**例如,在这个 MDB 中,我们可以看到已经计算了反射率。检查 ACCESS 中的 MDB,我们可以看到这些反射率与一些 id 设备相关联:

要访问所需的辐射测量,我们首先需要创建一个字典,其中包含每种辐射测量类型的条件,如下所示。一旦select_radiometries被成功调用,如果逻辑= '和',或者如果逻辑= '或',它将检索与所有类型一致的时间,或者在 MDB 上找到的所有时间。每个辐射测量数据帧将被载入.measurements属性。这将在访问测量值部分进行解释。
DatetimeIndex(['2015-11-14 14:39:45', '2015-11-14 14:39:55',
'2015-11-14 14:40:05', '2015-11-14 14:40:15',
'2015-11-14 14:40:25', '2015-11-14 14:40:35',
'2015-11-14 14:40:45', '2015-11-14 14:40:55',
'2015-11-14 14:41:05', '2015-11-14 14:41:15',
'2015-11-14 14:41:25', '2015-11-14 14:41:35',
'2015-11-14 14:41:45', '2015-11-14 14:41:55',
'2015-11-14 14:42:05', '2015-11-14 14:42:15',
'2015-11-14 14:42:25', '2015-11-14 14:42:35',
'2015-11-14 14:42:45', '2015-11-14 14:42:55',
'2015-11-14 14:43:05', '2015-11-14 14:43:15',
'2015-11-14 14:43:25', '2015-11-14 14:43:35',
'2015-11-14 14:43:45', '2015-11-14 14:43:55',
'2015-11-14 14:44:05', '2015-11-14 14:44:15',
'2015-11-14 14:44:25', '2015-11-14 14:44:35',
'2015-11-14 14:44:45', '2015-11-14 14:44:55',
'2015-11-14 14:45:05', '2015-11-14 14:45:15',
'2015-11-14 14:45:25', '2015-11-14 14:45:35',
'2015-11-14 14:45:45', '2015-11-14 14:45:55'],
dtype='datetime64[ns]', freq='10S')
将辐射度可视化
TriosMDB 类的目标基本上是从 Trios/MSDA mdb 中搜索和导出测量值。对于更高级的操作,如插值、反射率计算或数据清理,辐射测量类更合适。尽管如此,TriosMDB 还是提供了一些基本的绘图功能,以确保导出的内容有意义。
mdb.plot_radiometry('reflectance', min_wl=380, max_wl=950)

mdb.plot_radiometries(cols=2, min_wl=380, max_wl=950)

导出辐射测量
最后一步是将辐射度量导出到文本文件。输出是 Trios/MSDA 格式的. txt 文件(类似于。
create_measurement_dir标志表示是否必须创建子目录。子目录名遵循 YYYYMMDD-mmss 格式,并且是RadiometryDatabase类使用的格式。
请记住,这种格式不容易被操纵。它旨在保持与 MSDA 输出文件的兼容性。
为了获得更加用户友好的格式,建议使用由Radiometry类提供的插值输出。
out_dir = mdb.export_txt(create_measurement_dir=True)Saving output file to ..\mdbs\20151114-1439
将返回输出目录。将它存储在一个变量中是一个很好的实践,因为它将用于打开Radiometry类。现在让我们检查一下已经保存的文件:
[file for file in out_dir.iterdir()]
[WindowsPath('../mdbs/20151114-1439/Ed_interpolated.bak'), WindowsPath('../mdbs/20151114-1439/Ed_interpolated.csv'), WindowsPath('../mdbs/20151114-1439/Ed_spectrum_LO.bak'), WindowsPath('../mdbs/20151114-1439/Ed_spectrum_LO.txt'), WindowsPath('../mdbs/20151114-1439/Fig_20151114-1439.png'), WindowsPath('../mdbs/20151114-1439/Ld_interpolated.bak'), WindowsPath('../mdbs/20151114-1439/Ld_interpolated.csv'), WindowsPath('../mdbs/20151114-1439/Ld_spectrum_LO.bak'), WindowsPath('../mdbs/20151114-1439/Ld_spectrum_LO.txt'), WindowsPath('../mdbs/20151114-1439/Lu_interpolated.bak'), WindowsPath('../mdbs/20151114-1439/Lu_interpolated.csv'), WindowsPath('../mdbs/20151114-1439/Lu_spectrum_LO.bak'), WindowsPath('../mdbs/20151114-1439/Lu_spectrum_LO.txt'), WindowsPath('../mdbs/20151114-1439/reflectance_spectrum_LO.txt'), WindowsPath('../mdbs/20151114-1439/Rrs_interpolated.bak'), WindowsPath('../mdbs/20151114-1439/Rrs_interpolated.csv')]
检查反射文件的内容。我们可以在记事本或任何其他文本编辑器中打开它:

如前所述,我们可以看到,这种格式对于在 Excel 或 Pandas DataFrame 中打开是不友好的。辐射测量类提供的interpolated .csv输出更适合这些目的。
笔记本
在/nbs/00_TriosMDB.ipynb笔记本上可以找到包含更多示例的所有代码:
结论
在第一部分中,我们已经看到了如何使用TriosMDB 类从。MSDA/Trios 格式的 mdb 文件。提供了基本的过滤功能来定位内部的精确测量值。mdb 文件并将其导出到文本文件。更高级的操作功能,如数据清理、过滤、插值等。由Radiometry 和RadiometryGroup类提供,但是它们将在下一部分中讨论。
谢谢,到时见。
如果你喜欢这篇文章,并且想继续无限制地阅读/学习,可以考虑成为 中等会员 。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
https://cordmaur.medium.com/subscribe
消除共线性的 Python 库
原文:https://towardsdatascience.com/a-python-library-to-remove-collinearity-5a4eb05d3d73?source=collection_archive---------10-----------------------
一个处理共线变量的简单 Python 库

作者图片
共线性是机器学习项目中非常普遍的问题。它是数据集特征之间的相关性,它会降低我们模型的性能,因为它增加了方差和维数。当你不得不处理无人监督的模型时,情况变得更糟。
为了解决这个问题,我创建了一个移除共线要素的 Python 库。
什么是共线性?
共线性通常称为多重共线性,是一种当数据集的要素显示彼此高度相关时出现的现象。通常用皮尔逊相关系数来衡量。如果相关矩阵显示出绝对值较高的非对角元素,我们就可以讨论共线性。
共线性是一个非常大的问题,因为它增加了模型方差(特别是对于线性模型),它增加了维数而没有增加信息,此外,它扭曲了我们解释模型的能力。如果两个要素共线,则不应将它们放在一起考虑,只应考虑信息最丰富的要素。
我多年来一直在处理共线性问题,最终决定创建一个 Python 库来帮助像我一样的其他数据科学家高效地处理这个问题。
如何消除共线性
首先,我们必须为相关系数的绝对值定义一个阈值。适当的探索性数据分析可以帮助我们在我们的数据集中确定这样一个阈值,但对于一个通用项目,我的建议是使用 0.4。它适用于多种类型的关联,尽管我再次建议执行适当的 EDA 来找到适合您的数据集的值。
一旦设置了阈值,我们需要相关矩阵只包含绝对值小于该阈值的非对角线元素。
对于无监督的问题,想法是计算相关矩阵,并移除所有那些产生绝对值大于该阈值的元素的特征。我们可以从不太相关的对开始,并且只要考虑阈值,就继续添加特征。这给了我们一个不相关的数据集。
对于有监督的问题,我们可以使用例如单变量方法来计算特征重要性。我们可以考虑最重要的特征,然后按照它们的重要性不断添加特征,从最重要的特征到不太重要的特征,只有在考虑阈值约束的情况下才选择它们。
这个想法是,通过添加一个特征,我们在相关矩阵中添加了一个新行和一个新列,所以我们必须小心。这就是为什么我创建了我的图书馆。
“共线性”包
我们可以使用 pip 轻松安装我的“共线性”库。
!pip install collinearity
让我们看看 Python 中的动作。
首先,我们需要导入共线性包的选择非共线性对象。
from collinearity import SelectNonCollinear
这是执行特性选择和实现 sklearn 对象的所有方法的对象。
现在,让我们导入一些有用的库和波士顿数据集。
from sklearn.feature_selection import f_regression
import numpy as np
import pandas as pd
import seaborn as sns
from sklearn.datasets import load_boston sns.set(rc={'figure.figsize':(12,8)})
让我们从无监督方法开始,在这种方法中,我们不知道目标变量,只想减少聚类问题的特征数量,
让我们导入数据集并计算关联热图。
X,y = load_boston(return_X_y=True)
features = load_boston()['feature_names']
df = pd.DataFrame(X,columns=features)
sns.heatmap(df.corr().abs(),annot=True)

作者图片
如我们所见,我们有几个共线的变量(即热图中颜色较浅的变量)
我们现在可以创建一个 SelectNonCollinear 对象的实例,并将阈值设置为 0.4。
selector = SelectNonCollinear(0.4)
与每个 scikit-learn 对象一样,我们有 fit 、 transform 和 fit_transform 方法。我们还有 get_support 方法,它为我们提供了所选特性的数组掩码。
让我们来拟合对象,并获取所选特征的蒙版。
selector.fit(X,y)
mask = selector.get_support()
现在,我们可以只考虑选定的功能,并再次绘制关联热图:
df2 = pd.DataFrame(X[:,mask],columns = np.array(features)[mask])
sns.heatmap(df2.corr().abs(),annot=True)

作者图片
所选要素现在显示出比原始集合更低的共线性,并且没有系数如预期的那样大于 0.4。
对于有监督的方法,我们需要设置得分函数,该函数用于计算一个特性相对于给定目标的重要性。对于像这样的回归问题,我们可以使用 f_regression 。对于分类问题,我们可能要用 f_classif。
我们需要在实例的构造函数中设置这个值。然后我们可以重新安装我们的选择器。
selector = SelectNonCollinear(correlation_threshold=0.4,scoring=f_regression) selector.fit(X,y) mask = selector.get_support()
我们现在可以计算新的热图,在这个例子中,它与无监督的情况相同。
df3 = pd.DataFrame(X[:,mask],columns = np.array(features)[mask])
sns.heatmap(df3.corr().abs(),annot=True)

作者图片
如果我们只想过滤我们的数据集,我们可以很容易地调用转换方法。
selector.transform(X)
# array([[ 0\. , 15.3 , 396.9 , 4.98],
# [ 0\. , 17.8 , 396.9 , 9.14],
# [ 0\. , 17.8 , 392.83, 4.03],
# ...,
# [ 0\. , 21\. , 396.9 , 5.64],
# [ 0\. , 21\. , 393.45, 6.48],
# [ 0\. , 21\. , 396.9 , 7.88]])
这允许我们在 sklearn 的管道中使用 SelectNonCollinear 对象。
pipeline = make_pipeline( SelectNonCollinear(correlation_threshold=0.4,scoring=f_regression), LinearRegression() )
pipeline.fit(X,y)
这样,我们可以毫不费力地在 ML 管道中实现这个对象。
结论
我实现了这个库来消除无监督和有监督机器学习项目的共线性。阈值的值应该根据适当的 EDA 来设置。对于像本例中使用的数据集这样的数据集,可能会出现这样的情况:在无监督和有监督方法之间,所选的要素是相同的。我的建议是根据我们的问题使用正确的方法。
如果您有任何意见、问题或建议,请随时使用我的 GitHub repo:https://github.com/gianlucamalato/collinearity
原载于 2021 年 6 月 28 日 https://www.yourdatateacher.com*。*
迷宫搜索算法的 Python 模块
原文:https://towardsdatascience.com/a-python-module-for-maze-search-algorithms-64e7d1297c96?source=collection_archive---------1-----------------------
Python 迷宫世界 pyamaze
【pyamaze 模块是为方便随机迷宫的生成而创建的,可以有效地应用不同的搜索算法。

这个模块 pyamaze 的主要思想是帮助创建可定制的随机迷宫,并能够在此基础上工作,就像轻松应用搜索算法一样。通过使用这个模块,你不需要编写 GUI 程序,也不需要面向对象的程序,因为这个模块会为你提供支持。这个模块使用 Python 内置的 Tkinter GUI 框架,使用这个模块你不需要安装任何框架。
关于该模块的详细信息如下所示,在本视频中也有解释
安装软件包:
在命令提示符下运行以下命令:
pip install pyamaze
或者你可以访问 GitHub 链接并将模块代码复制为 Python 文件,命名为 pyamaze.py
以下是如何使用模块的详细说明
生成迷宫:
要简单地生成一个迷宫,你需要创建迷宫对象,然后应用 CreateMaze 函数。最后一条语句将应用函数 run 来运行模拟。
from pyamaze import mazem=maze()m.CreateMaze()m.run()
一个随机的 10x10 迷宫将会这样生成:

随机生成一个 10x10 的迷宫
左上角的单元格是迷宫的目标,我们可以通过多种方式将目标更改为任何单元格。此外,默认情况下,会生成一个完美迷宫,这意味着迷宫的所有单元都是可访问的,并且从任何单元到目标单元都有且只有一条路径。因此,任何单元格都可以被视为起始单元格,因此不会突出显示。在内部,最后一个单元,即最后一行和最后一列单元被设置为起始单元。所以,总的任务是找到从右下角的单元格到左上角的单元格的路径。
我们可以在创造迷宫的时候改变它的大小。例如,5x5 迷宫可以生成为:
from pyamaze import mazem=maze(5,5)m.CreateMaze()m.run()

随机的 5x5 迷宫
CreateMaze 函数的第一个参数是行号,第二个参数是列号。要生成大小为 15x20 的迷宫,您应该使用 m.CreateMaze(15,20)函数。
为了在程序中使用迷宫参数,了解这些参数是很重要的。首先,迷宫的单元有两个索引,一个用于行,另一个用于列。之前生成的 5x5 迷宫的指数如下所示:

迷宫细胞的指数
create maze 的可选参数:
为了定制生成的迷宫,我们可以使用不同的可选输入参数。
目标(x 和 y): 要将目标单元格从(1,1)更改为其他单元格,我们可以提供可选参数 x 和 y 作为目标。例如,为了使单元格(2,4)成为目标,我们将使用函数 CreateMaze(2,4)
**图案:**我们可以生成一个水平(或垂直)的图案迷宫。水平模式迷宫意味着与垂直线相比,迷宫将具有更长的水平线,类似地,对于垂直模式,垂直迷宫线将更长。我们可以将可选的参数模式设置为 h 或 H 用于水平模式,将 v 或 V 用于垂直模式。
例如,要生成一个目标为单元格(5,5)的垂直图案 5x5 迷宫,我们将使用如下函数:
m.CreateMaze(5,5,pattern=’v’)
样本生成的迷宫是:

垂直模式迷宫
多路径迷宫:
默认情况下,生成的迷宫是完美迷宫,这意味着从任何单元格到目标单元格只有一条路径。但是,我们可以通过将可选参数 loopPercent 设置为某个正数来生成一个具有多条路径的迷宫。 loopPercent 设为最高值 100 表示迷宫生成算法将最大化多条路径的数量,例如:
m.CreateMaze(loopPercent=100)
生成的迷宫如下所示:

多路径迷宫(环路)
保存生成的迷宫:
也有可能保存任何生成的迷宫供将来使用。为此,我们需要将可选参数 saveMaze 设置为 True 。随机生成的迷宫将作为 CSV 文件保存在工作文件夹中。CSV 文件将包含迷宫内所有单元格的信息以及东西南北方向打开和关闭的墙的信息。1 表示路径在该方向打开,0 表示路径关闭。
通过使用 loadMaze 选项并提供 CSV 文件,我们可以稍后使用 CSV 文件生成相同的旧迷宫。
有了这个特性,我们还可以通过更改 CSV 文件来手动定制迷宫。要从迷宫中添加或删除一面墙,我们应该更改 CSV 文件的两个值。
从 CSV 文件加载迷宫时,创建迷宫时迷宫的大小无关紧要,因为关于大小的信息也是从 CSV 文件加载的。
主题:
迷宫的默认主题是黑暗主题,我们可以通过使用参数 主题 并将其设置为光明主题,将其更改为光明主题。我们在 pyamze 模块中也有一个 COLOR 类来管理不同的颜色。要将主题设置为 light,我们可以将其设置为一个 COLOR class 对象,如下所示:
m.CreateMaze(theme=COLOR.light)
或者我们也可以提供字符串形式的值,如下所示:
m.CreateMaze(theme=”light”)
将代理放入迷宫:
我们可以在迷宫中放置代理(一个或多个)。一个代理可以被认为是一个像机器人一样的物理代理,或者它可以简单地用于在迷宫中突出或指出一个细胞。
为此,我们在 pyamaze 模块中有 代理 类。导入代理类后,我们可以创建代理对象,我们应该提供父迷宫作为第一个输入参数。默认情况下,代理将被放置在迷宫的起始单元格(最后一个单元格)上。
下面是在默认大小的迷宫上创建一个带有灯光主题的代理的完整代码:
from pyamaze import maze,COLOR,agentm=maze(10,10)m.CreateMaze(theme=COLOR.light)a=agent(m)m.run()

灯光主题迷宫中的代理人
现在让我们看看代理类的不同可选参数。
**代理的位置:**代理的默认位置是迷宫的开始单元,即迷宫的右下角。您可以通过设置单元格的值 x 和 y 来更改位置。
代理对象有两个属性 x 和 y ,您可以在创建代理后访问和设置这些属性。此外,代理将属性 位置 设置为元组 (x,y) ,该元组提供完整的 x 和 y 信息作为一个参数。您也可以将其设置为其他值来更改代理的位置。
**代理的目标:**代理的默认目标是迷宫的目标,这意味着代理的目标是到达迷宫的目标。但是,如果要改变代理的目标,可以在创建代理时设置参数 目标 来实现。应该将二值元组指定为代理的目标。
**代理的大小:**默认情况下,代理的大小小于单元格的尺寸。您可以将参数 填充 设置为 真 ,代理将填充整个单元格。
代理的形状:默认情况下,代理为方形,还有第二个形状选项箭头,可以设置为 形状 参数,代理将为箭头形状。这将区分代理的正面和其他面。如果形状设置为箭头,参数 填充 无效。
看脚印:当你要实现一些搜索算法,智能体要在迷宫中移动的时候,可以要求可视化完整的路径轨迹。为此,我们可以将可选参数footprint更改为 True 并且每当代理改变其位置时,脚印的印象将被强加到先前的位置上。脚印只是代理的形状,但颜色不同。查看这段代码的输出:
from pyamaze import maze,COLOR,agentm=maze(5,5)m.CreateMaze()a=agent(m,shape=’arrow’,footprints=True)a.position=(5,4)a.position=(5,3)a.position=(5,2)m.run()
迷宫类的其他属性:
为了实现某种搜索算法,您应该知道迷宫类的一些属性:
行数: m.rows 给出迷宫的行数 m 。
列: m.cols 给出迷宫的列数 m 。
网格: m.grid 是从(1,1)到最后的所有单元格的列表。
**迷宫地图:**随机生成一个迷宫。知道迷宫的不同打开和关闭的墙壁的信息是重要的。该信息在属性 迷宫 _ 地图 中可用。它是一个字典,其中键作为迷宫的单元格,值作为另一个字典,其中包含该单元格在四个方向上的四面墙的信息;东西南北。
您可以看到该属性的值,并使用生成的迷宫确认这些值,如下所示:
print(m.maze_map)
生成的示例迷宫和 迷宫 _ 地图 的值如下所示:

示例迷宫和迷宫 _ 地图如下所示
maze_map = {(1, 1): {‘E’: 1, ‘W’: 0, ’N’: 0, ‘S’: 0}, (2, 1): {‘E’: 0, ‘W’: 0, ’N’: 0, ‘S’: 1}, (3, 1): {‘E’: 0, ‘W’: 0, ’N’: 1, ‘S’: 1}, (4, 1): {‘E’: 0, ‘W’: 0, ’N’: 1, ‘S’: 1}, (5, 1): {‘E’: 1, ‘W’: 0, ’N’: 1, ‘S’: 0}, (1, 2): {‘E’: 0, ‘W’: 1, ’N’: 0, ‘S’: 1}, (2, 2): {‘E’: 0, ‘W’: 0, ’N’: 1, ‘S’: 1}, (3, 2): {‘E’: 1, ‘W’: 0, ’N’: 1, ‘S’: 0}, (4, 2): {‘E’: 1, ‘W’: 0, ’N’: 0, ‘S’: 1}, (5, 2): {‘E’: 0, ‘W’: 1, ’N’: 1, ‘S’: 0}, (1, 3): {‘E’: 1, ‘W’: 0, ’N’: 0, ‘S’: 1}, (2, 3): {‘E’: 0, ‘W’: 0, ’N’: 1, ‘S’: 1}, (3, 3): {‘E’: 0, ‘W’: 1, ’N’: 1, ‘S’: 0}, (4, 3): {‘E’: 1, ‘W’: 1, ’N’: 0, ‘S’: 1}, (5, 3): {‘E’: 1, ‘W’: 0, ’N’: 1, ‘S’: 0}, (1, 4): {‘E’: 1, ‘W’: 1, ’N’: 0, ‘S’: 0}, (2, 4): {‘E’: 0, ‘W’: 0, ’N’: 0, ‘S’: 1}, (3, 4): {‘E’: 0, ‘W’: 0, ’N’: 1, ‘S’: 1}, (4, 4): {‘E’: 0, ‘W’: 1, ’N’: 1, ‘S’: 0}, (5, 4): {‘E’: 1, ‘W’: 1, ’N’: 0, ‘S’: 0}, (1, 5): {‘E’: 0, ‘W’: 1, ’N’: 0, ‘S’: 1}, (2, 5): {‘E’: 0, ‘W’: 0, ’N’: 1, ‘S’: 1}, (3, 5): {‘E’: 0, ‘W’: 0, ’N’: 1, ‘S’: 1}, (4, 5): {‘E’: 0, ‘W’: 0, ’N’: 1, ‘S’: 1}, (5, 5): {‘E’: 0, ‘W’: 1, ’N’: 1, ‘S’: 0}}
从起点到目标的路径:****py amaze模块**(递归回溯器)**中使用的迷宫生成算法,不仅仅是生成一个随机的迷宫,还具有从起点到目标的路径信息。这些信息可以在迷宫的属性路径中作为字典获得。路径的关键是一个单元格,而值也是一个单元格,表示为了达到目标而从关键单元格到值单元格的移动。
**在一条路径上移动代理:在创建一个迷宫和迷宫内的代理(一个或多个)后,我们可以让代理在特定的路径上移动。最好将代理移动到迷宫的路径 * *属性上。为此,我们在迷宫类中有一个名为 tracePath 的方法,它将一个字典作为输入参数。字典的关键字是代理,值是我们希望代理遵循的路径。 tracePath 方法将模拟代理在路径上移动。
运行这段代码并亲自查看模拟。
from pyamaze import maze,agentm=maze(20,20)m.CreateMaze(loopPercent=50)a=agent(m,filled=True,footprints=True)m.tracePath({a:m.path})m.run()
我们有三种方法可以指定代理要遵循的路径。
**作为字典的路径:**如上所示,路径可以是一个字典,其中的键-值对表示从键-单元格到值-单元格的移动。
**路径作为列表:**也有可能提供路径作为单元格列表。然后,代理将遵循从列表中的第一个单元格到最后一个单元格的路径。
tracePath 方法中的可选参数:
对于 tracePath 方法,还有几个可选的参数。
**击杀代理:**在代理完成路径后可以击杀代理。通过设置参数 杀死 到 真 ,代理将在完成路径后 300 毫秒后被杀死。
**移动速度:**我们可以使用参数*控制代理的移动速度,默认值为 300 毫秒。它是代理的移动步骤之间的时间延迟。
**标记一些单元格:**对于不同的演示,可能需要标记一些单元格。为此,有一个 显示标记 的选项可以设置为 真 ,如果代理经过迷宫 标记单元格 列表中出现的任何单元格都会被标记。
**不同路径上的多个代理:*也有可能在各自的路径上移动多个代理。为此,我们可以在输入字典中为 tracePath 方法提供更多的代理路径信息。将会针对字典中提供的所有代理路径对进行移动。
而且,我们可以多次使用 tracePath 方法。在这种情况下,首先第一次提供的所有代理-路径将完成它们的路径,然后第二次在 tracePath 中提供的其他代理-路径对将开始它们的移动,依此类推。
用键盘控制代理
最后,还有用键盘按键控制代理的可能性。为此,您可以使用迷宫类方法enable arrow key并作为输入参数,用箭头键提供要控制的代理。同样,可以使用 enableWASD 方法通过按键 WASD 来控制代理。
观看此视频了解更多细节。
结论:
创建这个模块的主要想法是为了方便生成任何大小和不同图案的迷宫。此外,我们可以在迷宫上放置代理并控制它们。这将有助于实现不同的迷宫搜索算法,你的重点将是搜索算法,而不是努力生成和显示迷宫。您可以实现任何迷宫搜索算法,如深度优先搜索、宽度优先搜索、最佳优先搜索、A-star 搜索、Dijakstra 算法、一些强化学习、遗传算法或任何您能想到的解决迷宫的算法。
这是使用 pyamaze 模块实现不同迷宫搜索算法的播放列表。
季节性库存计划的 Python 或-Tools 模型
原文:https://towardsdatascience.com/a-python-or-tools-model-for-seasonal-inventory-planning-483aaf5aa8b?source=collection_archive---------19-----------------------
如何在 SCIP 求解器中使用 Google 的 ortools python 包进行数学优化

内森·莱蒙在 Unsplash 上拍摄的照片
为什么会有季节性库存?
生产设施可能没有能力在重要季节生产季节性产品。在换季前建立额外的库存通常比购买额外的工具和空间更便宜。例如:
- 如果季节性产品是制造商业务的重要组成部分,那么在淡季安排生产可以在更长的时间内平衡资源。这使得工厂能够配备全职员工,而不是依赖季节性劳动力。
- 即使这些设施能够激增产能以满足需求,也可能导致额外的管理费用,包括加班费。将产品储存在库存中的成本可能低于这一增加的成本。
采用季节前构建方法时,有几个问题需要回答:
- 在季节开始之前,要生产的产品数量是多少?
- 假设随着时间的推移,随着生产计划的顺利进行,库存会逐渐增加,那么制造业需要在什么时候开始生产过剩的库存来为旺季储存呢?
虽然可以用纸和笔设计出一个简单的模型,但这个模型提供了一个可扩展的框架,可以在竞争能力有限的情况下为多种产品提供基础。
模型设置
在创建此多期库存模型之前,请使用 pip 安装或工具。
pip install ortools
接下来,导入包并使用数据设置模型。该模型的数据表示从 2021 年 7 月到 2022 年 6 月的月份。
- 产品需求累计至每月周期
- 对每月能生产的产品数量的[生产能力]限制
- 生产和储存成本
- 初始库存,尽管库存通常会被建模为变量
使用 python 和 ortools 的优化模型
Google 有很好的文档和对 python 和其他一些语言的介绍。该模型遵循该框架,但对多期库存模型进行了更详细的描述。
声明是大多数优化模型的第一步。我们声明要使用的求解器( SCIP )和算法用来确定最优解的决策变量。
一般来说,编写比“p”代表产量,“b”代表期初库存,“e”代表期末库存更多的描述性变量是一种好的做法,但格式化代码使代码不换行也是一种好的做法。因此,没有一种风格适合所有情况。
产量是决策变量,期初和期末库存变量受产量和需求的影响。
输出:
Number of variables = 36
接下来是约束条件。这个模型着眼于 12 个月,从 2021 年 7 月到 2022 年 6 月。库存模型的细微差别是将本期的期末库存与下一期的期初库存联系起来。其他约束条件是标准供应链约束条件,用于:
- 在不超出产能的情况下满足客户需求
- 从一个时期到下一个时期的平稳生产水平(对于该模型,0.8 的 alpha 用于将每月的变化限制在 20%以内)

输出:
Number of constraints = 70
模型的最后一部分是目标函数,以最小化总成本。总成本是生产成本和库存储存成本的总和。

输出:
Total cost = 29812
Solver wall time = 4134680
Problem solved in 40 iterations
分析结果
该模型的最优值是总成本 29812。这有意义吗?
如果将 12 个月的总需求(减去初始库存)乘以 10,预测需求的最低生产成本为 27,400,这是单位生产成本。然而,额外的限制,如最低库存水平、生产平稳性和库存持有成本会导致更高的成本。所以 29812 是合理的。
要查看解决方案,让我们格式化熊猫数据框中的数据。
输出:

这张表可以让你很容易地找到许多问题的答案。除了看到变量(期初库存、产量、期末库存),下面也很容易看到:
- 根据要求,库存没有减少到 50 件以下
- 需求得到了满足。如果由于模型的当前公式而导致需求未得到满足,则该模型将不可行。
- 最大容量在 12 月的高峰期得到了充分利用,但也可以追溯到 11 月、10 月和 9 月。
因此,在 8 月份开始生产过剩库存可能是明智的,这是为了预防一切都不尽如人意的情况。如果生产落后于 8 月份以后,就不可能赶上了。虽然这是一个很好的快速工具,用于调整和战略讨论,但对于战术或运营计划,每周和每天的视图将是必不可少的。
模型限制
这种库存计划模型有许多局限性。这里有几个例子。
- 该模型直到 12 月需求高峰时都有效。模型中使用的数据旨在帮助理解在旺季之前需要建立多少季节性库存。如您所见,在提供的数据结束时,结果将库存减少到零。由于在 12 月份达到高峰之前,该模型不用于对季节性库存准备之外的生产进行建模,因此建议只显示 12 月份的结果。
- 该模型不包括通过加班增加产能的可能性,尽管可变成本结构旨在缓解这种情况下的过渡。
- 该模型没有考虑需求的不确定性。
- 该模型不考虑库存能力、吞吐量能力或装货码头能力。这个模型只考虑了生产能力。
结论
Google 的 ortools 是一种很好的方式来扩展数学优化问题,以便与 SCIP 这样的开源解决方案一起使用。使用 python 进行优化建模还有其他选择,比如 pulp 或 pyomo。这位作者发现,根据不同的模型,哪种方法效果最好存在差异。每一个都有特别吸引人的特性,比如带有 ortools 约束编程的 NextSolution 功能。
优化建模通常用于有大量节约成本机会的复杂问题。但是随着开源选项和易用性的增长,优化也可以用于扩展和自动化更简单的问题。
Python 熊猫对 Excel 用户的介绍
原文:https://towardsdatascience.com/a-python-pandas-introduction-to-excel-users-1696d65604f6?source=collection_archive---------2-----------------------
从 Excel 迁移到 Python 之前您需要知道的核心概念

Bruce Hong 在 Unsplash 上拍照
Pandas 可能是用 Python 进行真实世界数据分析的最佳工具。它允许我们清理数据、争论数据、进行可视化等等。
你可以把熊猫想象成一个超级强大的微软 Excel。你可以在 Excel 中完成的大多数任务也可以在 Pandas 中完成,反之亦然。也就是说,熊猫在许多领域表现出色。
在对 Pandas 的介绍中,我们将比较 Pandas 数据框架和 Excel 电子表格,学习创建数据框架的不同方法,以及如何制作数据透视表。
注意:在学习熊猫之前,你应该知道至少了解 Python 的基础知识。如果你是 Python 的新手,看一下我做的这个指南,马上就能开始使用 Python。
**Table of Contents** 1\. [Why Excel Users Should Learn Python/Pandas](#f35d)
2\. [Pandas DataFrames & Excel Spreadsheets](#7ef2)
3\. [How to Create a Dataframe](#e7d4)
- [Creating a dataframe by reading an Excel/CSV file](#aed5)
- [Creating a dataframe with arrays](#1740)
- [Creating a dataframe with a dictionary](#dfa2)
Excel 用户为什么要学习 Python/Pandas
数据清理、数据标准化、可视化和统计分析等任务可以在 Excel 和 Pandas 上执行。也就是说,Pandas 比 Excel 有一些主要优势。仅举几个例子:
- 大小限制:Excel 可以处理大约 100 万行,而 Python 可以处理数百万行(限制在于 PC 的计算能力)
- 复杂的数据转换:Excel 中的内存密集型计算会导致工作簿崩溃。Python 可以处理复杂的计算,没有任何大问题。
- 自动化:Excel 不是为自动化任务而设计的。你可以创建一个宏或使用 VBA 来简化一些任务,但这是极限。然而,Python 可以超越这一点,提供数百个免费库。
- 跨平台能力:在 Excel 上,你可能会发现 Windows 和 macOS 中的公式不兼容。当与不将英语作为其 Microsoft Excel 版本默认语言的人共享 Excel 文件时,也会发生这种情况。相比之下,不管计算机上的操作系统或语言设置如何,Python 代码都保持不变。
在向您展示如何用 Pandas 替换 Excel(创建数据透视表、可视化等)之前,我将向您解释 Pandas 的核心概念。在整个指南中,我将提到 Excel 来提供一些示例,并将其与熊猫进行比较。Excel 是最流行的电子表格,所以一些类比将帮助你快速掌握熊猫的概念。
我们开始吧!
熊猫数据框架和 Excel 电子表格
Pandas 中的两个主要数据结构是序列和数据帧。第一个是一维数组,第二个是二维数组。

作者图片
在熊猫中,我们主要处理数据帧。熊猫数据框架相当于 Excel 电子表格。熊猫数据框架——就像 Excel 电子表格一样——有两个维度或轴。
数据帧有行和列(也称为系列)。在数据框架的顶部,您将看到列的名称,在左侧是索引。默认情况下,熊猫的索引从 0 开始。
行和列的交集称为数据值或简称为数据。我们可以存储不同类型的数据,如整数、字符串、布尔值等等。
这是一张显示美国各州人口排名的数据图表。稍后我将向您展示创建这样一个数据帧的代码,但现在让我们来分析这个数据帧。

作者图片
列名(州、人口和邮政)也称为特征,而每个行值称为观察值。我们可以说有 3 个特征和 4 个观察值。
请记住,单个列应该具有相同类型的数据。在我们的示例中,states和postal列只包含字符串,而 population 列只包含整数。当试图将不同的数据类型插入到一个列中时,我们可能会得到错误,所以要避免这样做。
总结一下,这就是熊猫和 Excel 之间的术语翻译。
到目前为止,我们还没有谈论太多关于空单元格的内容,但是知道在 Python 中缺失数据用NaN表示是有好处的,它代表“不是一个数字”。只要数据帧中有空值,就会看到一个NaN。
如何创建数据框架
创建数据帧有多种方法。我们可以通过读取 Excel/CSV 文件、使用数组以及字典来创建数据帧。
但是在创建数据框架之前,要确保已经安装了 Python 和 Pandas。如果你是 Python 的新手,你可以通过观看这个视频来安装它。
要安装熊猫,在终端或命令提示符下运行命令pip install pandas 。如果您有 Jupyter 笔记本,您可以通过运行!pip install pandas从代码单元安装它
通过读取 Excel/CSV 文件创建数据帧
毫无疑问,这是在熊猫身上创建数据帧最简单的方法。我们只需要导入 pandas,使用 read_csv()方法,并将 Excel/CSV 文件的名称写在括号内。
让我们来读一个包含世界各国 GDP 数据的 CSV 文件(你可以在这个链接上找到这个文件)
**import pandas as pd**
df_gdp **=** pd**.**read_csv('gdp.csv')
df_gdp
在上面的代码中,我们将 pandas 重命名为“pd”这只是给熊猫命名的惯例。运行上面的代码后,您将看到下面的数据帧。

作者图片
这就是创建数据框架所需的全部内容!现在你可以通过观看我下面的视频教程开始从这个数据框架创建一个数据透视表。
用数组创建数据帧
要创建带有数组的数据帧,我们需要首先导入 Numpy。让我们导入这个库,并用随机数创建一个数组。
**import numpy as np**
data = np.array([[1, 4], [2, 5], [3, 6]])
也就是说,如果您还不习惯使用 Numpy,您可以使用列表符号创建相同的数组。在下一步创建数据帧时,结果将是相同的。
data = [[1, 4], [2, 5], [3, 6]]
为了创建一个数据帧,我们导入 pandas 并使用.Dataframe()方法。在括号内,我们可以添加index和columns参数来指定名称。
**import pandas as pd**
df = pd.DataFrame(data, index=['row1', 'row2', 'row3'],
columns=['col1', 'col2'])
df是数据帧的标准名称。如果我们打印这个df对象,我们得到如下结果:

作者图片
用字典创建数据帧
我们也可以从字典中创建一个数据框架。这是我最喜欢的选择,因为字典可以让我们正确地组织数据。您可能还记得,字典由一个键和值组成。我们可以将列表设置为数据值,将键设置为列名。
让我们在使用字典之前创建一个人口数据框架。首先,我们创建两个列表:州和人口。
# data used for the example (stored in lists)
states = ["California", "Texas", "Florida", "New York"]
population = [39613493, 29730311, 21944577, 19299981]
现在我们创建一个字典,将字符串States和Population设置为键,将之前创建的列表设置为数据值。
# Storing lists within a dictionary
dict_states = {'States': states, 'Population': population}
一旦创建了字典,创建 dataframe 就像使用.Dataframe()方法一样简单,但是这次我们不需要指定列参数,因为它已经在键中指定了。
df_population = pd.DataFrame(dict_states)
如果你打印df_population,你会得到这个数据帧:

作者图片
https://frankandrade.ck.page/bd063ff2d3加入我的电子邮件列表,与 3000 多人一起获取我在所有教程中使用的 Python for Data Science 备忘单
如果你喜欢阅读这样的故事,并想支持我成为一名作家,可以考虑报名成为一名媒体成员。每月 5 美元,让您可以无限制地访问数以千计的 Python 指南和数据科学文章。如果你使用我的链接注册,我会赚一小笔佣金,不需要你额外付费。
**https://frank-andrade.medium.com/membership **
用几行代码实现数据处理、分析和 ML 自动化的 Python 工具
原文:https://towardsdatascience.com/a-python-tool-for-data-processing-analysis-and-ml-automation-in-a-few-lines-of-code-da04b3ba904f?source=collection_archive---------10-----------------------
dabl 图书馆基本指南

图片来自皮克斯拜的拉胡尔·潘迪特
数据科学模型开发管道涉及各种组件,包括数据收集、数据处理、探索性数据分析、建模和部署。在训练机器学习或深度学习模型之前,必须清理或处理数据集,并使其适合训练。处理缺失记录、移除冗余要素和要素分析等过程是数据处理组件的一部分。
通常,这些过程是重复的,并且涉及大部分的模型开发工作时间。各种开源的 Auto-ML 库在几行 Python 代码中实现了整个流水线的自动化,但是它们中的大多数表现得像一个黑盒,并且没有给出关于它们如何处理数据集的直觉。
为了克服这个问题,我们有一个名为 dabl 的开源 Python 库——数据分析基线库,它可以自动化机器学习模型开发管道的大部分部分。本文将介绍 dabl 包的实际实现,包括数据预处理、特性可视化和分析,然后是建模。
dabl:
dabl 是一个 数据分析基线库 ,它使监督机器学习建模对于初学者或没有数据科学知识的人来说更加容易和容易。dabl 的灵感来自 Scikit-learn 库,它试图通过减少样板任务和自动化组件来民主化机器学习建模。
dabl 库包括各种特性,使得用几行 Python 代码处理、分析和建模数据变得更加容易。
开始使用:
dabl 可以从 PyPI 安装,使用
**pip install dabl**
我们将使用从 Kaggle 下载的 Titanic 数据集来实现这个库。
(1.)数据预处理:
dabl 用几行 Python 代码自动化了数据预处理管道。dabl 执行的预处理步骤包括识别缺失值、移除冗余特征以及了解特征的数据类型,以便进一步执行特征工程。
dabl 检测到的特征类型列表包括:
***The list of detected feature types by dabl includes:***
1\. **continuous
2\. categorical
3\. date
4\. Dirty_float
5\. Low_card_int
6\. free_string
7\. Useless**
dabl 使用一行 Python 代码将所有数据集要素自动分类为上述数据类型。
**df_clean = dabl.clean(df, verbose=1)**

(按作者分类的图片),每个功能的自动检测数据类型
原始泰坦尼克号数据集有 12 个特征,它们被 dabl 自动分类为上述数据类型,以进行进一步的特征工程。dabl 还提供了根据需求改变任何特性的数据类型的能力。
**db_clean = dabl.clean(db, type_hints={"Cabin": "categorical"})**
用户可以使用**detect_types()**功能查看每个特征的指定数据类型。

(图片由作者提供),自动检测每个要素映射的数据类型
(2.)探索性数据分析:
EDA 是数据科学模型开发生命周期的重要组成部分。Seaborn、Matplotlib 等是执行各种分析以更好地理解数据集的流行库。dabl 使 EDA 变得非常简单,节省了工作时间。
**dabl.plot(df_clean, target_col="Survived")**
dabl 中的**plot()** 功能可以通过绘制各种图来实现可视化,包括:
- 目标分布条形图
- 散点对图
- 线性判别分析
dabl 自动对数据集执行 PCA,并显示数据集中所有特征的判别 PCA 图。它还显示通过应用 PCA 保留的差异。
(3.)造型:
dabl 通过在训练数据上训练各种基线机器学习算法来加速建模工作流,并返回性能最佳的模型。dabl 做出简单的假设,并为基线模型生成指标。
使用 dabl 中的**SimpleClassifier()**函数,一行代码就可以完成建模。

(图片由作者提供),使用 dabl 进行基线建模的性能指标
dabl 几乎很快就返回了最佳模型(决策树分类器)。dabl 是最近开发的库,提供了模型训练的基本方法。
结论:
Dabl 是一个方便的工具,使监督机器学习更加容易和快速。它用几行 Python 代码简化了数据清理、要素可视化和开发基线模型。dabl 是最近开发的库,需要很多改进,不推荐用于生产。
参考资料:
[1]dabl GitHub:https://github.com/amueller/dabl
感谢您的阅读
解决熄灯问题的量子变量
原文:https://towardsdatascience.com/a-quantum-variant-for-solving-lights-out-problem-a0b5c364f91e?source=collection_archive---------23-----------------------
“量子熄灯求解器”——解决组合问题的独特方法

图 1:https://pixabay.com/images/id-567757/
我们正在见证“量子计算”这个时髦词汇的空前激增。这种炒作驱动的好奇心始于 2019 年谷歌在量子世界创造历史之时。它声称并展示了基于超导架构的 53 量子位量子处理器 Sycamore 的量子优势。这是量子计算机第一次胜过经典计算机。从那天起,这个领域见证了算法优化、硬件增强和基于光子学的体系结构的演变的巨大发展。
那么什么是量子计算呢?
量子计算是对量子设备进行编程,使得不需要的状态相消干涉,而需要的状态相长干涉,给出它们作为输出。为了达到这个目的,三个不可或缺的性质被用来操控量子位元的状态。这些就是叠加,纠缠,干涉。
- 量子叠加:量子叠加是量子力学中的一个基本性质。在经典力学中,波可以表示为多个频率的叠加。同样,在量子力学中,叠加态可以代表所有不同量子态的线性组合。
- 量子纠缠:两个或两个以上的量子比特在不能表示为独立状态时纠缠在一起。当量子比特纠缠在一起时,它们之间存在一个特殊的键。一个状态的结果直接取决于另一个状态的测量。当纠缠对中的一个量子位被测量时,它会导致另一个量子位瞬间坍缩到可以根据第一个量子位的状态 100%确定预测的状态。即使相隔更远的距离,他们也遵循这一原则。这个想法遭到了有史以来最杰出的科学家的强烈批评。爱因斯坦也厌恶这个想法,表达了一句警句“幽灵般的超距作用”。他著名的 EPR 悖论也完全否定了这种现象的存在。在那个时期,这个概念只是理论上的,没有任何实际证明。然而,今天量子纠缠是一个被精确证实的和公认的概念。
- 量子干涉:量子态可以经历类似经典波的干涉。当两个或两个以上的波同相时,它们的振幅增加,而当它们相差 180 度时,它们的振幅相互抵消;因此,量子计算就是设计一种算法,使得所有不太可能的解的振幅相消干涉,而正确的解相长干涉,从而给出正确的答案。
这三个性质构成了任何量子算法不可或缺的一部分。

图 IBM 量子计算系统内部。鸣谢:IBM(来源https://www . Flickr . com/photos/IBM _ research _ Zurich/50252942522/size/k/)
量子算法解决了大量的问题,如蛋白质折叠,药物开发,组合游戏,如数独,国际象棋等等。熄灯就是这种可以用量子计算机解决的组合问题之一。本文描述并阐述了算法,称为“量子熄灯解算器”,它利用量子现象来解决量子设备上的熄灯问题。它成功地将问题转化到量子域中,并提供了问题的有效解决方案。它利用了一个反直觉的概念称为格罗弗算法,使用叠加和振幅放大技巧有效地解决了这个问题。但在进入算法之前,让我们先熟悉一下熄灯问题。
熄灯
熄灯问题是一个经典的组合问题,由 Tiger Electronics 于 1995 年开发。它由一块板组成,灯固定在 n*m 网格的方形瓷砖上。在开始位置,随机的灯被打开,我们的最终目标是关闭网格上的所有灯。这个游戏的规则是:
- 按下任何一个方块将会切换该方块上的灯以及相邻方块上的灯。这里,相邻的瓦片指的是顶部、底部、左侧、右侧的瓦片。对角瓷砖不被视为邻居。此外,切换意味着改变灯光的状态,而不考虑当前状态。例如,如果灯是开着的,它将被关闭,反之亦然。下图显示了按下图块(3,2)时的电路板配置。
- 按两次按钮相当于根本不按。因此,对于任何给定的配置,我们只需要考虑每个按钮按下不超过一次的解决方案。
- 解决方案状态与路径无关。因此,压瓷砖的顺序并不重要。

图 3:按压(3,2)瓷砖后的电路板配置
对上述情况的解决方案概括如下。瓷砖中心的圆点表示解决方案(即待压瓷砖)。

图 4:图 3 中问题的解决方案
习惯了问题之后,我们再推进到实际的算法。我会尽量把数学放在一边,集中精力解决熄灯问题。
量子熄灯解算器
该算法使用 IBMs Qiskit 编程语言。IBMQ 有各种各样的量子设备可以在他们的云上使用。唯一的问题是,量子计算机的最大可能量子位是 15。这些量子设备不能用于执行该算法,因为该算法期望 26 个量子位和 9 个经典位来求解 33 板配置。因此,该算法在一个名为 ibmq_qasm_simulator(版本 0.1.547)的量子模拟器上执行。它最多支持 32 个量子位。因此,使用建议的算法,我们可以使用模拟器解决 33 板配置问题。对于 4*4 板配置,根据该算法需要 40 个量子位和 16 个经典位,这远远超出了 Qasm 模拟器的能力。
最近,IBMQ 又向云添加了一些量子设备模拟器,即稳定器模拟器和扩展稳定器模拟器,最大量子位容量可达 5000 量子位。但是,如果算法由具有许多非 Clifford 门的较小电路组成,那么状态向量方法可能会比扩展稳定器表现得更好。由于所提出的算法包含许多非 Clifford 门,当考虑计算精度时,扩展的模拟器可能不是更好的选择。虽然,在扩展模拟器上解算法还是值得一试的。更大的板配置可以使用更多的量子位来解决。因此,我们将暂时坚持使用 Qasm 模拟器来解决 3*3 板排列的问题。
在深入研究该算法之前,让我们先回顾一下 Grovers 算法如何帮助找到问题的正确解决方案的基本思想。如果你不熟悉 Grovers 算法或者幅度放大和 oracle 函数,强烈建议你去过一次。
在经典算法中,我们一次一个状态地搜索解空间,当我们遇到正确的状态时,我们输出解。有很多不同的技术可以达到这种最终状态。与经典算法相反,Grover 算法使用称为 Hadamard 门的叠加门同时搜索所有可能的输出状态。正确的门标有相位翻转,这意味着将负号加到正确状态的幅度上。由于所有的状态都是同时访问的,所以到这个阶段为止算法的复杂度是 O(1)。现在,你会质疑为什么此时不输出标记的状态?我们还不能输出标记的状态。如果我们测量这一刻的量子态,会得到任意一个态作为输出。这是因为某个状态的输出概率是振幅的平方。例如,考虑 1/2 和-1/2 是两个状态的振幅。1/2 的平方等于-1/2。因此,即使期望状态具有负振幅,两个状态也具有相同的输出概率。由于这个原因,绝对幅度值需要增加,而不仅仅是符号翻转。我们的下一个任务是增加期望状态的幅度,减少不期望状态的幅度。这是通过振幅放大技巧,利用甲骨文和扩散电路实现的。完整的电路在下面的 GitHub 链接上。
用于解决该问题的算法框图如下所述。

图 5:解决熄灯问题的框图
该算法主要分为 3 个阶段:
- 初始化块:
该块接受用户输入,即 33 问题中所有 9 个区块的初始配置。用户以 0 和 1 的字符串的形式提供该输入,其中 0 表示灯关闭,1 表示灯打开。在解释算法的同时,让我们同时解决一个 33 的问题,以便更好地理解。作为算法输入的字符串是 101010101。该字符串表示如下所示的板配置,

图 6:算法的输入
在上图中,黄色表示开启,灰色表示关闭状态。除了为算法提供初始棋盘条件,所有需要的量子位和经典位都被初始化。总共 26 个量子位和 9 个经典位用于计算。在这 26 个量子位中,9 个用于接受用户输入作为板条件,在框图中显示为“初始板条件”。其他 9 个量子位用‘H’表示的叠加态初始化。这意味着阿达玛门应用于这些量子位。这将量子位设置为叠加态。这一点的重要性将在下一阶段解释。被称为‘Oracle-qubit’的单量子位被声明,它从所有可能的状态中标记出正确的状态。剩余的 7 个量子位(在框图中未示出)是用于辅助目的的临时量子位。
2.甲骨文和扩散函数;
在这个模块中有两个关键的部分,它们是,预言电路和扩散电路。Oracle circuit 在给定的输入状态下同时执行所有可能的操作(即执行所有可能的瓷砖翻转)。这是可能的,因为在 9 个量子位上应用了哈达玛门。检查所有这些翻转的输出是很重要的。让所有灯熄灭的那组动作是我们解决问题的方法。检查这种状态,然后使用 Oracle 量子位标记负振幅。如上所述,在这一点上,我们不能测量叠加态。因此需要振幅放大。这是在扩散回路中完成的。
在扩散电路中,被标记状态的幅度被放大,从而减小了其他不期望状态的幅度。在这篇文章中,我不打算探究他的放大是如何工作的。这本身可能就是一个完整的主题。
这两个电路结合起来就形成了这个模块。整个块重复一定的次数(在我们的例子中,17 次)。这是我们想要的 3*3 板配置的最佳可能数量。这个数字取决于用来表示解空间的量子位的数量。在我们的例子中,它是 9 个量子位。因此,要执行的迭代次数计算如下:
π/4 * √2⁹ ∼ 17.27 ∼ 17
每当我们重复这个方块时,振幅就会增加一点。最后,在 17 次迭代之后,与其他状态相比,期望输出的幅度急剧增加。因此,如果我们在这个阶段测量叠加,我们将以非常高的概率(99.95%)得到想要的状态。下图显示了初始化模块、Oracle 和扩散电路的电路。

图 7:左边是初始化电路,中间表示 Oracle 函数,右边方框表示扩散。
3.测量:
该模块测量输出量子位,并将该值复制到 9 个经典位进行可视化。
与确定性的经典计算不同,量子计算本质上是概率性的。因此,强烈建议对大于 100 的镜头执行此算法。Shots 是运行时给量子器件的参数,表示电路执行了多少次。例如,如果 shots=1000,则该电路被执行 1000 次,并且输出被记录该次数。为了执行这个算法,我已经使用了 8188 个镜头。执行该算法后的结果如下图所示。

图 8:8188 个镜头的输出用直方图表示
可以看出,8188 个镜头中,8184 次正确状态是输出(111111111)。但是有 4 次,输出不是要求的状态。因此,该算法在 99.95%的情况下输出正确的状态。
结果和讨论
- 这种搜索算法将搜索解空间的时间复杂度从 O(N)降低到 O(√N)。
- 由于量子世界是概率性的,大多数时候,确定性的答案并不总是可能的。因此,该算法在 99.95 %的情况下输出正确的状态。
量子电路的完整代码可在 GitHub 上获得。
参考文献
- https://qi skit . org/documentation/locale/FR _ FR/tutorials/simulators/6 _ extended _ stabilizer _ tutorial . html
- 卡米洛·萨帕塔,肖扬,“格罗弗的算法”,苏黎世联邦理工学院演讲[在线],数据:2016 年 8 月
- L.K. Grover,“用于数据库搜索的快速量子力学算法”,第 28 届 ACM 计算理论年会论文集,1996 年,arXiv:quant-ph/9605043v3
- IBM Quantum,“使用 Qiskit 学习量子计算:Grover 的算法”[在线]可用:https://qiskit.org/textbook/ch-algorithms/grover.html
- A.B. Mutiara,R.Refianti,“Grover 算法量子搜索在经典计算机中的模拟”,(IJCSIS)《国际计算机科学与信息安全杂志》,第 8 卷第 9 期,日期:2010 年 12 月
- “维基百科:熄灯(游戏)”,2021 年 1 月,[在线]可用:https://en。wikipedia.org/wiki/Lights_Out_(游戏)
一个价值一千个模型的查询
原文:https://towardsdatascience.com/a-query-worth-a-thousand-models-48be1f414bf5?source=collection_archive---------37-----------------------
实践教程
尝试从结构化查询搜索中构建分类器

图片由迪安·莫里亚蒂从皮克斯拜拍摄
数据科学家面临的最大问题是什么?
为了回答这个问题,我们可能会争论一整天。虽然有很多候选,但对我来说最重要的是访问新用例的标记数据。
举个例子,一个经理打电话来说:
“我们需要能够自动识别收到的邮件是应该转到应收帐款部门还是客户服务部,这样我们就可以降低管理成本。”
数据科学家:
"我能拿到他们放在每个桶里的邮件吗?"
经理:
“没有”
数据科学家:
*smh
几乎所有的数据科学家都以某种形式面临这个问题。事实上,这个问题如此之大,以至于整个行业都在致力于帮助数据科学家解决这个问题。最近的一份报告估计该行业的收入在“13.077 亿美元”的范围内。是的,再读一遍那个数字。不是大,是巨。
这个行业如此之大,部分是因为人类很昂贵。因此,人工标记数据也很昂贵。当然,公司已经尝试使用免费劳动力来解决这个“昂贵的人力”问题的某些方面。不,我不是在说奴役人民。我在这里指的是验证码。如果你没有意识到,验证码不仅仅是用于安全,它们也是公司让人们免费标记他们数据的一种方式。
但是,如果有一种方法,我们可以提供一个更自动化的方法来标记数据呢?如果我们可以使用现有的数据和为我们提供这些数据的智能作为代理来创建标签,然后用于训练模型,会怎么样?
在本文中,我尝试了一种自动标记数据的方法,来训练一个可以用来对新数据进行评分的模型。剧透警报,使用 Google I 背后的智能开发结构化查询来获取训练数据和训练标签。一个查询抵得上一千个模型吗?让我们来了解一下!
问题空间
在这次演示中,我们将尝试对文本进行分类。更具体地说,我们希望能够对网站文本进行分类,以识别公司网站是否涵盖感兴趣的特定主题。
假设你有一个客户对更好地识别企业社会责任项目感兴趣。目标是确定公司可能在其网站上描述 CSR 计划的地方。问题是,尽管大多数财富 500 强公司确实使用某种类型的网址来提供有关其 CSR 计划的信息,但细节却很难确定。
以微软为例。他们的企业社会责任网站通常被称为“……企业责任”但进一步审查后,我们看到他们的登录页面链接到几个不同的,更详细的计划。现在想象一下为财富 500 强的所有 500 家公司做这件事。可能需要一分钟。
为了节省一些时间并测试出解决这个问题的数据科学解决方案,我利用谷歌来捕获训练数据,并将它们分配给标签,这些标签可用于训练一个模型来对新文本进行评分,以进一步对该网站文本的内容进行分类。以下是该解决方案的简要概述:
1.从结构化查询中获取前 N 名的 Google 页面结果
2.从每个登录页面抓取文本数据
3.从查询中为每个登录页面创建分类标签
4.训练多类分类模型
5.保存模型并在财富 500 强公司的页面上评分,以确定具体的 CSR 计划
6.可视化结果
从结构化查询构建标记数据
为了测试我们的解决方案,我们首先需要构建训练数据,并将它们与标签相关联。在这种情况下,我们对作为标签的 CSR 类别感兴趣。快速的网络搜索和这篇研究论文给了我一些寻找不同潜在类别的想法。

作者图片
这里,我们重点关注以下 CSR 类型,作为我们数据的标签:
人权
使用条件
环境
腐败
披露信息
公司治理
消费者利益
性别平等
职业融合
赋税
计算环境
Windows 10 操作系统
Python 3.7
图书馆
用 Carbon.now 创建的代码图像
密码
第一组代码使用了 python 中可用的 googlesearch-python 库。我们从 googlesearch-python 库中导入“search ”,并构建一个传递查询字符串并返回前 50 个结果的函数。请注意,这 50 个结果可以根据您的需要进行调整,但该函数的默认设置是返回前 50 个 Google 搜索链接。
import pandas as pd
import numpy as np
from googlesearch import searchdef Gsearch(query, num_res = 50):
results = []
for i in search(query=query,tld=’co.in’,lang=’en’,num=num_res,stop=num_res,pause=5):
results.append(i)
return results
在定义了我们的搜索函数之后,我们开发代码来迭代每个 CSR 类型以构造一个查询,我们将这个查询传递给 googlesearch API,返回一个包含 CSR 标签和前 50 个结果列表的元组。
#develop queriescsr = [‘human rights’,’working conditions’,’the environment’,’corruption’,
‘disclosing information’,’corporate governance’,’consumer interests’,
‘gender equality’,’occupational integration’,’taxes’]results = [(c, Gsearch(‘corporate responsibility and ‘+c)) for c in csr]
内脏检查
这是一般的思考过程,因为 Google 擅长返回与查询相关的信息,通过传递一个特定的和结构良好的查询,我们应该能够返回与我们的查询所代表的标签更具体相关的数据。通过提供一些不同的查询,我们应该能够训练一个模型,该模型能够识别语言数据何时更好地表示一个类而不是另一个类。
返回代码
一旦我们的搜索代码完成了,下一步就是把所有的东西放入熊猫的数据框架中,以便可视化我们到目前为止的结果。有用的“explode”方法允许我们将每个链接结果放到数据帧中它自己的行中。
但是链接本身并不足以训练一个模型。下一步是访问每个链接,从登录页面中抓取文本。为了完成下一步,我们使用 Python 中的“requests”和“bs4”(beautiful soup)库(注意:这一部分可能需要一段时间)。
df = pd.DataFrame(results, columns=[‘label’,’links’]).explode(‘links’)#get website text
import requests
from bs4 import BeautifulSoup
import redef website_text(URL):
#USER_AGENT = “Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:65.0) Gecko/20100101 Firefox/65.0”
#headers = {“user-agent” : USER_AGENT}
headers = {‘User-Agent’: ‘Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36’,’Accept-Encoding’: ‘gzip, deflate, br’,’Accept-Language’: ‘en-US,en;q=0.9,hi;q=0.8’} try:
resp = requests.get(URL, headers=headers)
if resp.status_code == 200:
soup = BeautifulSoup(resp.content, “html.parser”)
for script in soup([“script”, “style”]):
script.extract()
text = soup.get_text()
lines = (line for line in text.splitlines())
chunks = (phrase for line in lines for phrase in line.split(“ “))
text = ‘ \n’.join(chunk for chunk in chunks if chunk)
clean_output = re.sub(r’<.+?>’, ‘ ‘, text)
else:
clean_output = ‘failed to retreive text’
except:
clean_output = ‘failed to retreive text’
return clean_outputdf[‘website_text’] = df[‘links’].apply(website_text)
df = df.loc[df[‘website_text’] != ‘failed to retreive text’]
现在我们有了一个包含标签、链接和这些链接的文本的数据框架。下一步是获得网站文本的“肉”,以提高我们捕捉有意义的语言数据的机会。此外,我们还希望快速清理文本数据,以增加至少一个基本的标准化级别。以下代码使用“nltk”库对句子进行标记化,删除任何少于 7 个单词的句子,并执行一些轻量级清理(例如,小写、删除停用词、删除字符/数字)。
#clean the website text
import nltk
from nltk.corpus import stopwords
stop_words = set(stopwords.words(‘english’))def clean_sentences(text):
sent_text = nltk.sent_tokenize(text)
sentences = [s for s in sent_text if len(s.split()) > 6]
if sentences:
sentences = ‘ ‘.join(sentences)
low = sentences.lower()
no_num = re.sub(r’\d+’, ‘’, low)
no_char = re.sub(r’[\W_]+’, ‘ ‘, no_num)
tokens = nltk.word_tokenize(no_char)
stop_words = set(stopwords.words(‘english’))
no_stop = [i for i in tokens if not i in stop_words]
return no_stopdf[‘clean_text’] = df[‘website_text’].apply(clean_sentences)
df = df.dropna(subset=[‘clean_text’])
快到了。
现在我们需要训练一个模型。在这种情况下,我们将利用流行的“scikit-learn”库来训练一个简单的文本分类模型。由于我们有一个多类输出问题,我们将利用随机森林模型。
这里,我们遵循使用语言数据进行模型训练的标准步骤;使用 term-frequency-inverse-document-frequency(tfi df)过程构建将单词映射到整数的 vocab,将数据分成训练和测试数据集,将模型拟合到训练数据,并检查测试数据的准确性。
#set up data for ML
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifierdef dummy_fun(doc):
return doctfidf = TfidfVectorizer(max_features=600, tokenizer = dummy_fun,
preprocessor=dummy_fun, token_pattern=None,
ngram_range=(1,2))X = tfidf.fit_transform(df[‘clean_text’])
y = df[‘label’]X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.33, random_state=42)clf = RandomForestClassifier(max_depth=3, random_state=0)
clf.fit(X_train, y_train)y_pred_test = clf.predict(x_test)
print('Accuracy: '+str(accuracy_score(y_pred_test, y_test))
>>> 'Accuracy: 0.60'
我们表现如何?
准确性不好,但这只是冰山一角。我们可以采取许多额外的步骤来进一步优化我们的方法并提高模型性能。这里只是将这个解决方案提升到下一个级别的一些附加想法;
使用更精确查询语言,
包括单词嵌入作为特征,
对词类应用更详细的清理过程,
尝试不同的模型类型,
打开一瓶威士忌,站在我们的头上,让 60%的准确率看起来像 90%的准确率。
要获得更详细的信息,我们可以利用 scikit-learn 提供的分类报告,该报告有助于我们更好地评估我们的模型在哪些方面表现良好,在哪些方面表现不佳。下面是在对整个数据集(训练+测试)的模型进行评分后,我们如何将报告放入一个易于阅读或保存的 Pandas 数据框架中:
y_pred = clf.predict(X)
report = classification_report(y, y_pred, output_dict=True)
r = pd.DataFrame(report).transpose()
我们当前解决方案的细节显示,我们在识别人权方面有相当好的表现,但在工作条件方面不太好。

作者图片
考虑到 60%的总体准确率并不可怕,我们采取下一步措施,在新的网站实例上对模型进行评分,以对财富 500 强公司的 CSR 计划进行分类。为了做到这一点,我们拉出财富 500 强的登陆页面,使用与上面类似的代码,我们抓取每个链接,访问这些链接,并拉出相关的文本。这有助于为我们的模型创建数据集,数据集的设置方式与我们的训练数据的设置方式相同。
一旦 dataframe 设置了公司名称列、链接列和网站文本列,我就可以用这个模型给每个网站打分了。为了实现评分,我将数据预处理和模型评分打包到一个简单方便的函数中,该函数输出预测的标签以及与该标签相关联的概率。
def score_csr_model(text, tfidf_model, model):
clean = clean_sentences(text)
tfidf = tfidf_model.transform([clean])
pred = model.predict(tfidf)
pred = pred[0]
pred_proba = np.amax(model.predict_proba(tfidf))
return pred, pred_probadf[‘predicted’] = df[‘website_text’].apply(score_csr_model,
args = [tfidf,clf])
在最后一步,我根据每类公司的平均预测概率,从公司样本中构建一个热图,以估计每家公司包含与每项 CSR 计划相关的信息的程度。为了生成热图,我首先需要根据公司名称和我们模型中该页面上确定的 CSR 计划类型对数据进行分组。作为此代码的一部分,我对模型中每个标签的预测概率进行了平均。
import seaborn
import matplotlib.pyplot as plt#unpack predicted column into two columns
df[[‘predicted’,’proba’]] = pd.DataFrame(df[‘predicted’].tolist(),index=df.index).drop(columns = [‘predicted’])dfsub = df[['label','predicted','proba']].groupby(['label','predicted'])['proba'].mean().reset_index()
dfsub= dfsub.pivot(index='label', columns='predicted', values='proba')figure, ax = plt.subplots(figsize=(10,10))
ax.xaxis.tick_top() # x axis on top
ax.xaxis.set_label_position('top')
ax.set_xticklabels(list(dfsub.columns), size=14)
ax.set_yticklabels(list(dfsub.index.values), size=14)
#sns.set(font_scale=5)
svm = sns.heatmap(dfsub, mask=(df_sub==0), center=0, cmap='Greens', cbar=False,
xticklabels=True, yticklabels=True, linewidths=.1,ax=ax)figure = svm.get_figure()figure.savefig('path/to/save/csr_svm_conf.png', orientation='landscape',
transparent=True,format='png', pad_inches=.1)
调查结果中最明显的一点是,在消费者利益和工作条件方面,覆盖面似乎存在很大差距。在模型中,我们预测工作条件和消费者兴趣的准确性都很低,所以我们可能只是看到了这里表现的模型性能差。然而,有趣的是,我们的模型在识别人权倡议方面表现更好,但似乎更少的公司在其 CSR 沟通中关注人权倡议。

作者图片
尽管只是一个演示,这里收集和分析的数据可能有一些有价值的用途。
对于企业来说,也许你想与这些大公司中的一家合作,来领导与 CSR 类别之一相关的推广工作或产品。了解这些公司如何与这些努力保持一致,可以用来帮助关注最合适的人选。
对于消费者来说,知道哪些公司符合你的价值观有助于我们知道我们想要支持哪些公司并向其购买产品。
对于股东来说,投资于具有强大企业社会责任的盈利性公司的资金需要知道这些优先事项得到了有效的沟通。
对于监管者来说,了解企业社会责任倡议在不同行业的差异可能有助于支持那些需要更多关注企业社会责任倡议的行业的政策变化。
结论
构建包含模型标签的训练数据是一项挑战,自该行业诞生以来一直困扰着数据科学家。在这个演示中,我使用 Google 搜索查询来帮助建立训练数据和相关联的标签,而不需要人工干预。
无论采用哪种方法,这篇文章都代表了一种尝试为分类任务自动标记有价值的训练数据的可能方法。
比如参与学习更多关于数据科学、职业发展或糟糕的商业决策的知识?加入我。
Python 中代码剖析的快速简易指南
原文:https://towardsdatascience.com/a-quick-and-easy-guide-to-code-profiling-in-python-58c0ed7e602b?source=collection_archive---------19-----------------------
编程;编排
使用线路分析器查找函数中的瓶颈

来源:unDraw.co
简介
作为一名数据科学家,你的大部分时间应该花在数据争论和/或训练机器学习模型等任务上。然而,您会发现,当您的代码似乎永远无法执行时,这种情况很快就会消失。出于这个原因,当您需要评估应用程序中的瓶颈并节省您的宝贵时间时,代码剖析就来了。我们今天文章的主角将是 line_profiler 包,我们将使用它来逐行剖析一个函数的运行时,这样我们就可以让您更接近代码效率天堂。开始侧写吧!
注意,对于本文,我将使用 python 笔记本(。ipynb ),因为我发现它们非常适合于实验,这使它们成为一个很好的代码剖析工具,因为您会频繁地对更高效的代码进行修改。
什么是代码剖析?
简而言之,代码分析是一种用于检测每个函数或代码行运行时间以及执行频率的方法。这是找到代码中的瓶颈,从而理解如何优化代码的重要一步。我们的方法本质上是定量的,因为它在代码的各个行上产生汇总统计。因此,它为您的代码的哪些部分需要进一步优化提供了可操作的见解。
如何分析一个函数
探索如何分析我们的代码的最好方法是用一个例子。假设我们有一个简单的函数,将磅转换为千克和克,如下所示:
def pounds_to_metric(pounds):
kilograms = pounds / 2.2
grams = kilograms * 1000
return 'The amount you entered is equal to {} kilograms and {} grams.'.format(int(kilograms), grams)
快速肮脏的方法:%timeit
如果我们想得到这个函数的估计运行时间,我们可以使用 IPython 的 timeit 神奇函数,它将给出总的执行时间。
%timeit pounds_to_metric(115)
跑得最慢的人比跑得最快的人多花了 11.57 倍的时间。这可能意味着正在缓存中间结果。1000000 次循环,最佳 5 次:每次循环 1.27 秒
从输出中,我们可以看到执行了多次运行和循环。% time 它多次运行示例代码,并提供对代码执行时间的估计,使其更准确地表示实际运行时间,而不仅仅依赖于一次迭代。输出中显示的平均值是考虑到多次运行中的每一次运行的运行时间的汇总。
严格的方法:线路剖面仪
因为%timeit 只对一行代码计时,所以当我们想要快速评估一个函数的运行时性能时,它就派上了用场。然而,不难看出为什么这不能很好地扩展到更大的代码块。因此,如果我们想知道函数中的每一行运行了多长时间,这就是 line profiler 包派上用场的地方。
因为这个包不是 Python 标准库的一部分,我们需要单独安装它。这可以通过 pip install 命令轻松完成。接下来,我们将它加载到会话中,如下所示。
%load_ext line_profiler
我们现在可以使用 line profiler 的神奇命令%lprun 来评估 pounds_to_metric 函数中特定代码行的运行时。首先,我们使用-f 标志来指定我们要分析的函数,后跟我们要分析的函数。注意,函数名的传递不带任何括号。最后,我们指定我们想要分析的确切函数调用,以及任何必需的参数。我会像之前一样用 115 作为磅数。
%lprun -f pounds_to_metric pounds_to_metric(115)
分析统计数据
运行前面一行代码会生成一个总结分析统计信息的表,如下所示。

作者图片
现在,让我们浏览一下汇总表的各个列!
首先,显示指定函数行号的列,随后是显示该行被执行次数的命中列。接下来,时间列显示了每一行执行所花费的总时间。该列使用一个特定的计时器单位,可以在输出的第一行中找到。这里,计时器单位使用科学记数法(1e-06)以微秒为单位列出。例如,我们可以看到第五行花了 12 个定时器单位,或者说,大约 13 微秒来运行。
此外, Per Hit 列给出了执行一行所花费的平均时间,通过将 time 列除以 Hits 列来计算。假设我们在这个函数中的所有点击都等于 1,那么 Time 和 Per Hit 列显示了类似的结果。 %这可以帮助我们检测在函数中占用最多时间的代码行。最后,在行内容列中显示每一行的源代码。很整洁,是吧?
Giphy
结论
至此,我们总结了 Python 中代码剖析的快速简单指南。回想一下,我们讨论了如何使用 line-profiler 模块评估函数的性能,以及为什么这种方法比使用%timeit 更好。我希望这篇文章对你有用,欢迎在评论中提问。如果你喜欢这篇文章,一定要看看我在 Medium 上的其他文章。快乐剖析!
快速简单的晨间例行公事,开启富有成效的一周
原文:https://towardsdatascience.com/a-quick-and-easy-morning-routine-to-jumpstart-a-productive-week-6f35dc28f739?source=collection_archive---------42-----------------------
如何在合适的时间开始你的周一早晨

汤姆·罗杰森在 Unsplash 上的照片
在我上一份工作开始的时候,我开始对几乎所有的事情做笔记。如果我脑子里突然冒出一个想法,我会把它写下来。如果我参加一个会议,我会把会议记录和行动项目一起带走。或者,如果我有一个回顾,我会每周记录我的工作,然后在会议前总结。两年后,我有了一个相当大的单词数字笔记本——各种各样的信息,包括完全有意义的完整句子或一些没有上下文的单词。笔记写得越多,就越难快速找到行动项目和成就。
造诣
我首先记录的是我的成就。实话实说吧;作为数据人员,我们一周内有太多事情要做。您可能经常会发现自己在理解业务目标、开发技术解决方案或深入特定主题以解决问题之间切换。随着这一切的进行,我们可能会迷失在细节中,错过我们工作的影响,这就是为什么我喜欢在周一停下来反思。
我上周完成了什么?我的工作对项目、业务或同事产生了什么影响?
后退一步,记录成就,这样在季度或年度评估时,你就有了一份精心策划的清单。这种反思有助于求职的另一个原因是。现在你已经有了一份清单,可以添加到你的 LinkedIn 或简历中,并在面试中讨论。
然而,谈论开发一个成就列表并不意味着一个句子串,比如“开发了一个运行 ETL 过程的脚本”相反,我使用星方法来发展我的清单。正如凯特·布加德在文章中所定义的,明星法是:
“情境:设定场景,给出你例子的必要细节。任务:描述在那种情况下你的职责是什么。
行动:准确解释你采取了哪些措施来解决这个问题。
结果:分享你的行动取得了哪些成果。”
用这个方法,让我们重新定义我们的成就。
- 情况 —您有一个数据集,在对其进行分析之前需要清理。
- 任务 —对于这个项目,你的任务是开发一个脚本来对提供的数据运行 ETL 过程。
- 动作 —为此,您利用 Python 从文本字段中提取数据,规范化信息,并将其上传到 CosmosDB。
- 结果 —最终,您的脚本加载 1TB 的数据,并在 8 小时内存储结果,从而使处理结果的运行速度提高了 4 倍。
既然我们已经考虑了我们成就,我们可以重写我们的陈述:
❌开发了一个脚本来运行 ETL 过程。
✅设计了一个 Python 脚本来运行 1 TB 数据的 ETL 过程,该过程将提取和规范化文本数据并上传到 Cosmos DB。在对数据进行分析之前,该脚本将处理结果的运行速度提高了 4 倍。
在我看来,我更喜欢简历和评论的第二种说法。该语句简要介绍了任务,同时也显示了结果。通过每周写一次这些类型的成就,你的工作已经为你完成了。当到了回顾的时候,你不必试图回忆过去几个月你做了什么。相反,你可以使用你的清单,突出你最自豪的成就。
我喜欢每周做一次的另一个原因是它让我看到我已经取得的进步。我可以回顾我前一周做了什么,看看哪些进展顺利,哪些进展不顺利。如果我需要在这个过程中做一些调整,我可以。
行动项目
除了记录成就,我还通过确定我需要做什么来开始我的一周。在我的上一个角色中,我会通过咨询 scrum board 和 backlog 来做这件事。以此为数字清单,我会决定下一步需要做什么,什么是优先事项。
开始我作为数据科学顾问的新角色时,我决定继续跟踪我的行动项目,但我需要适应这个过程。目前,我们有一个 scrum 板,但是它没有被同样的使用。相反,它关注高层次的目标。对我来说,这还不足以追踪我每周的进度。为了解决这个问题,我现在在物理待办事项清单便笺上列出所有行动项目。这些便笺刚好够大,可以抓住一两天的行动项目。在完成这些行动一周之后,你会发现自己有 2 到 3 张卡片,上面写着那一周你需要做的事情。
回顾过去一周的清单让我能够找出我的分析中哪些已经完成,哪些还没有完成。同样,我可以确定在一周开始时我需要关注什么。
当你开始新的一周时,以下是一些需要考虑的事情:
未完成的行动项目 —上周你有哪些任务没有完成,需要开始或继续?有时候,我无法完成一周清单上的所有事情。所以在下一节课开始时,我会检查这些项目。然后,我从列表中决定什么需要开始或继续。有时,根据我前一周得到的反馈,未完成的行动项目会被安排在以后。
反馈 —一旦这些被计划在以后或被添加到列表中,我接下来要检查的就是与反馈相关的行动项目。你在上周的工作中收到了哪些需要解决的反馈?你得到如何改进你的模型的建议了吗?有人给你一个新的数据集来研究吗?如果它是优先事项,那么我会把它添加到我的列表中。否则,我计划在未来的一周。
计划行动项目——最后,我查看计划项目,看看根据截止日期需要开始什么。需要启动哪些计划任务?有计划的任务有时看起来很容易列入清单,但如果我了解数据科学,情况可能不总是这样。有时,这些任务需要额外的时间来专注于研究、理解业务目标和实施。当你把这些计划好的任务添加到你的清单上时,确保你给自己足够的时间。
在一周的开始,你喜欢看什么,做什么?你有什么你觉得有帮助的惯例吗?
最后的想法
如果你像我一样经常记笔记,你可能会发现很难在其中快速找到行动项目和成就。在我一周的开始,我喜欢做两件事:( 1)在一个列表中记录我一周的成就,( 2)重写我一周的清单。
- 不要跟踪任务列表,而是创建一个你的成就列表以及相关的结果。找到一个适合你的方法。我使用星方法来发展我的清单。这个列表对简历、LinkedIn、面试以及季度或年度评估都很有帮助。
- 用一张需要完成的行动清单开始你的一周。组织你的想法,看看你需要做什么,完成什么。
本文包含附属链接。如果你想了解更多,可以看看我下面的其他文章!
机器学习模型中 AUC-ROC 的快速指南
原文:https://towardsdatascience.com/a-quick-guide-to-auc-roc-in-machine-learning-models-f0aedb78fbad?source=collection_archive---------27-----------------------
比较分类模型有效性的简单且健壮的方法不应该由于太多不同的定义而变得复杂。
机器学习最常见的应用之一是将实体分为两个不同的、不重叠的类别。这些年来,人们已经设计出了几种方法,从非常简单的到更加复杂的到近乎于的黑箱。在处理几乎任何类型的模型时,一个常见的问题是如何比较不同方法的性能,或者不同的参数调整。幸运的是,在二元分类器的情况下,有一个简单的度量抓住了问题的本质:它是接收器操作特性的曲线(即积分)下的面积,因此缩写为 AUC-ROC 或简称为 ROC。
处理你的错误
为了便于讨论,假设一个 tiger vs cat 二元分类器将实体识别为属于真阳性 ( tiger ,接受)或真阴性 ( cat ,拒绝)情况。分类器给每个实体分配一个 0 到 1 之间的数字,如果该数字大于给定的阈值(比如 0.5),则该实体被接受,否则被拒绝。没有一个分类器是完美的,这意味着不到 100%的情况会被正确识别。大多数情况下,它会因为许多原因而误识别事物,特别是小的训练数据集大小和模型的内在限制。很多情况下,我们也在努力拒绝某种形式的“背景噪音”(这里:猫)。
传统上,分类错误分为两类,我在下文中将其称为假阴性 ( 即老虎被分类为猫)和假阳性 ( 即猫被识别为老虎)。不言而喻,将猫识别为老虎远没有将老虎识别为猫危险:这两种类型的错误通常不会被同等对待,并且根据问题的不同,分类器的参数被优化以最小化任何一种类型。
ROC 曲线
说了这么多,我们想找到一种简洁的方法来总结分类器的性能。直观地,人们很容易认识到,给定的模型位于参数空间中的一个折衷点,平衡了真阳性(TP)、假阳性(FP)、假阴性(FN)和真阴性(TN)的数量。一旦模型被训练,我们被允许改变的唯一参数是输出概率的阈值。因此,我们从 0 到 1 扫描这个数字,看看性能如何相应地变化。然而,4D 参数空间几乎是直观的!然而,事实证明这些数字中只有四分之二实际上是独立的,所以更容易将它们组合成其他东西来使用。长话短说,这是一个可能的组合:
真阳性率(TPR) = TP / (TP + FN) =识别信号的效率(εₛ)(也称回忆或灵敏度 )
假阳性率(FPR) = FP / (FP + TN) =低效率(ε_B)拒绝背景
ROC 曲线无非是 TPR 对 FPR,作为产出概率的函数来扫描。通常,它看起来有点像这样:

典型的接收器工作特性 (ROC)曲线示例。图片作者。
另类组合怎么样?当然,如果你看一看维基百科页面,你会发现关于敏感度、召回率、命中率,或真阳性率、特异性、选择性或真阴性率、精确度或阳性预测值、阴性预测值 脱落或假阳性率、假发现率、假遗漏率、流行阈值、威胁分值(TS)或关键成功指数(CSI)、准确度、平衡准确度、马修斯相关系数、福尔克斯-马洛指数、信息量或庄家 所有这些都是为了说明不同的背景可能需要不同的定义,但这些不一定像 TPR vs FPR 那样直观。
解释 ROC 曲线下的面积
假设我们有两个分类器 A 和 B 。他们的 ROC 曲线如下图所示。哪个性能更好?

两种不同模型的比较。图片作者。
在回答这个之前,我们想做一些考虑。两个分类器都具有在 0 和 1 之间的输出,但是通常两个分类器对于相同的 TFP 或 FPR 值将具有不同的阈值。因此,我们可能想要一个不依赖于阈值的度量,除非我们设计分类器来最小化 FP 或 FN 类型的误差。此外,我们想要一个归一化的数字,即可以直接在两者之间进行比较。如果我说分类器 A 的分数是 122,分类器 B 的分数是 72,那就不好说了……但是如果我们知道分数是在 0 和 1 之间归一化的,那么直接比较就很容易了。
具有这种特性的一个简单函数是——猜猜看?——曲线下的面积,,即积分。因为 FPR 和 TPR 都在 0 和 1 之间,所以面积不能小于 0,也不能大于 1。
由于一张图片胜过千言万语,下面这张图片展示了如何通过查看 AUC-ROC 来发现不同分类器的性能:

如何一眼看出哪个是最好的分类器的总结?图片作者。
在实践中,您可能最终会使用某个预定义库中的函数,比如来自 scikit-learn 的函数。该函数需要真实标签,以便将阈值扫描的结果与真实情况进行比较。
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
X, y = load_breast_cancer(return_X_y=True)
clf = LogisticRegression(solver="liblinear", random_state=0).fit(X, y)
roc_auc_score(y, clf.predict_proba(X)[:, 1])
0.99
这也适用于多类吗?的确是这样:只要画出一个类与其他类的对比图。
结论
计算接收器工作特性曲线下的面积是比较不同分类器有效性的最直观的工具。虽然有一些已知的限制,例如,当你想最小化某些类型的错误时,这可能是说服任何人分类器比随机选择答案做得更好的最有效的方法。需要注意的是,比较不同的分类器,特别是属于不同类别的分类器,通常需要更加仔细的思考,例如,训练决策树所需的数据集可能比训练深度神经网络所需的数据集小,但它们在某些特定边缘情况下的效率可能很微妙,仅通过查看单个数字(如 AUC-ROC)很难发现。
交叉熵损失函数快速指南
原文:https://towardsdatascience.com/a-quick-guide-to-cross-entropy-loss-function-8f3410ec6ab1?source=collection_archive---------35-----------------------
实践教程
多类别分类是机器学习中的常见问题。让我们深入研究一下最常用的损失函数的定义。
机器学习历来擅长的最突出的任务之一是将项目(例如图像、文档,声音)分类成不同的类别。特别是近年来,能够执行数学模型的硬件的进步,如卷积神经网络(CNNs)和递归神经网络 (RNNs,LSTMs),使得在性能上实现量子飞跃(有时字面意思)成为可能。然而,定义模型只是故事的一半。为了找到执行这一任务的最佳参数,还需要定义一个成本或损失函数,该函数捕捉我们想要优化的本质,并执行某种形式的梯度下降以达到一组合适的参数。

Jan Antonin Kolar 通过 Unsplash.com 拍摄的照片。
从多项式概率分布到交叉熵
首先,我们需要定义一个描述我们问题的统计框架。通常情况下,属于一个系统的每个项目(例如一只宠物的图片)可以被唯一地分配到 C ≥ 2 个可能的离散类别(例如猫、狗、金鱼)中的一个。对于每个训练示例 i ,我们都有一个基础事实标签( t_i )。此外,我们的模型输出一个由 C 个数字组成的向量,这个向量必须被解释为 j ∈ [1,…, C 是正确的类别的概率。总结一下:
- 每个观察都有离散的可能结果;
- 对于每个观察值,每个类别都有一个给定的发生概率( p 1、…、 p _ C ),使得p 1+…+p_C= 1,并且对于所有j**p _ j≥0;
- 有 N 个观测值,每个观测值都是相互独立的;
如果是这样的话,那么,你很幸运!每个可能的结果都由所谓的二项式概率分布来描述,每个独立试验类别 j 中的即是具有概率 p_j 的正确结果。当我们将试验扩展到C2 类时,相应的概率分布称为多项式。为了简单起见,忽略归一化因子,它看起来是这样的:

多项式概率分布的定义,直到一个归一化因子。图片作者。
正如优化问题中经常出现的情况,当算法在计算机中实现时,处理乘积的最大值可能会引起数值问题。相反,最好使用前面带负号的同一个函数的对数,在参数空间中搜索它的最小值。这通常被称为对数可能性。记住 log 函数的属性,该公式转化为:

多项式概率分布的对数似然,直到一个常数,它可以被重新吸收到优化问题的定义中。图片作者。
一些读者可能已经认识到这个功能:它通常被称为交叉熵,因为它与从信息论中已知的一个量相关,以编码一个人需要多少内存例如来传输一条消息。
简而言之,我们将优化我们的模型的参数,以最小化上面定义的交叉熵函数,其中输出对应于 p_j ,真实标签对应于 n_j 。值得注意的是,真正的标签通常由一个独热编码、即向量来表示,该向量的元素除了在对应于正类的索引处的元素之外都是 0。在我们的例子中,cat=(1,0,0)、dog=(0,1,0)和goldfish=(0,0,1)。这意味着总和logP减少到单个元素n_m log p_m,其中 m 是正类的索引。
将模型输出转换成概率向量
一般来说,ML 模型的输出( logits )不能被解释为不同结果的概率,而是一组浮点数。如何解读这个元组就看我们自己了。如上所述,为了成为概率向量,p_ 1+…+p_C= 1 且 p_j ≥ 0 对于所有 j 。
在**二元分类的情况下,**用于将唯一输出数转换成概率的最常用函数是 sigmoid 函数,也称为逻辑曲线:

s 形函数的定义。图片作者。
s 形管“挤压”接近 0 的负值和+1 的正值:

范围从-10 到 10 的 Sigmoid 函数。图片由作者提供,用 Wolfram:Alpha 制作。
在多类的情况下,需要一个扩展 sigmoid 的函数,以便处理代表跨越 C 可能类的概率的向量。最常用的函数叫做 Softmax:

Softmax 函数的定义。图片作者。
可以看到,每个元素依赖于所有剩余的 N_C-1 元素的值。这很好,因为我们希望概率被标准化。事实上,由于指数函数的属性, softmax 强制所有元素为x _ I0,并且所有元素的总和为 1。这样,应用于逻辑的 softmax 的输出可以被解释为跨可能类别的概率向量。
然而,需要注意的一点是,指数函数可能会使大数字变得更大,以至于它们可能不再适合计算机的内存。幸运的是,有一个常用的技巧来避免这种情况。在我们只有三个类别的情况下,更容易看到它的作用。

Softmax 函数应用于具有三个元素的 logit 向量。
首先,我们确定向量的最大元素。假设是 x_3 。然后,我们将 logits 向量转换如下:

记住 e⁰=1,我们现在应用 softmax :

如果你不相信这个向量与没有减去 x_3 的向量相同,看看第三个元素:

因此,由于指数函数的一个属性,我们可以从 softmax 的计算中“移除”最大的元素,并可能避免内存问题。我觉得这个解决方案至少非常优雅!
这里有一个利用 NumPy 的快速 python 实现:
softmax 的 Python 实现,使用 NumPy 计算指数。
结论
我经常发现交叉熵的大多数解释令人困惑,因为他们把车放在了马的前面。事实上,我们可以从函数定义开始,然后让读者相信这是正确的,但是我更喜欢从头开始。
我希望这篇帖子澄清为什么我们在多类分类任务中需要这样的函数,为什么我们不能只在损失函数中使用模型输出。
决策树快速指南
原文:https://towardsdatascience.com/a-quick-guide-to-decision-trees-bbd2f22f7f18?source=collection_archive---------34-----------------------
很容易迷茫,只见树木不见森林。让我们仔细看看机器学习中的一些最常见的方法,以分析分类和回归任务的异构数据。
决策树是一种非常常见、直观且易于解释的数据分析方法,其目标是将实体分成不同的组(分类)或预测数量(回归)。DT 在处理异质的非标准化输入特征方面也很出色(例如分类的和连续的)。
有什么不喜欢的?

由汤姆·帕森斯在 Unsplash 拍摄的照片
首先,一个简单的决策树 (DT)是一系列的二元决策,接受一组输入特征,并基于这些特征分割输入数据,其方式类似于流行的游戏,如 10 个问题或猜猜我是什么动物。二元问题/答案对的路径可以存储为图形或一组规则。

基本决策树的例子。图片作者。
可以创建具有多个最大可能节点的单个决策树,然后对其进行训练以优化目标函数。有许多常见的算法,如c 4.5(ID3 的继承者)和 CART (分类和回归树)。例如,在 CART 中,基尼指数%20of%20that%20class%20probability.)被用作成本函数来测量分裂样本的“纯度”,而 C4.5 利用信息熵来丰富任一类的叶子。所有算法都实现了一个停止条件,例如每个叶子中元素的最小数量(例如上图中的*【昆虫】)或者是否达到了节点的最大数量(例如上图中的*【鱼】和【蟹】)。在一个树被训练后,一个修剪程序通常被应用来减少节点的数量:更简单的树是优选的,因为它们不太可能过度拟合数据,并且可以说花费更少的时间来执行。**
虽然决策树简单且易于解释,但它们往往会过度拟合数据。然而,优势在于数量:boosting 和 ensemble 方法可以有效地克服这个问题。
****决策树顾名思义,是从一组简单的决策树中构建的,这些决策树被用作“弱”分类器。根据树的组合方式定义了不同的方法。
随机森林【RF’s】,这大概是最直观的,在分类中利用多数票或者在回归中平均。在这种情况下,每棵树输出*,例如类别索引(0 或 1)。最常见的答案作为最终结果。为了避免过度拟合,每个弱分类器在数据的子样本(具有替换)上被训练,并且仅利用输入特征的子集。这种双重欠采样过程简称为 自举聚合 或打包*。在不平衡数据集的情况下,应用类权重是一个常见的过程。有趣的是,随机森林也用于创建输入要素的稀疏矢量嵌入。的基本思想是对节点序列进行矢量化,并将它们保存在二进制元素的向量中。根据停止标准,向量的大小为n_estimators * max_nodes或n_estimators * max_depth。这种向量可以通过非常高效的线性分类器进行分析*,例如*(例如参见 scikit-learn 网站上的本教程)。
另一方面, 梯度提升树【GBDT】**为每个“弱分类器”【h(x)分配不同的非负权重 w ( 即一个相对重要性),最终判决为 w_i * h_i(x) 之和。 boosting 其实就是把很多顺序连接的弱学习者组合起来,达到更好的效果。在这种方法中,通过添加越来越好的树来提高每一步的分类精度,从而最小化目标函数。为此,第 i 第 F_i 在第 (i-1) 第树 F _(I-1)y—F _(I-1)的残差上被训练。权重序列(w1、w2、…、 w_N )结果是递减的,即每棵树都是泰勒级数展开中的一种高阶修正。有关更多详细信息,请参考 xgboost 库的文档,这可能是该算法最常见的实现。有趣的是,增强决策树在实验物理学中扮演着重要的角色,例如在欧洲核子研究中心对基本粒子属性的测量。

两种最流行的集成方法的视觉总结:随机森林(上)和梯度增强树(下)。图片作者。
在我们结束这场讨论之前,值得一提的是,自 2021 年 5 月下旬以来,谷歌的机器学习库 TensorFlow 也提供了一个决策森林和梯度提升的实现,被恰当地称为 TensorFlow 决策森林(TF-DF) 。按照网站上的例子和 Colab 笔记本,人们可以创建一个决策森林,并非常容易地适应熊猫数据框架,例如:
*# Install TensorFlow Decision Forests
!pip install tensorflow_decision_forests
# Load TensorFlow Decision Forests
import tensorflow_decision_forests as tfdf
# Load the training dataset using pandas
import pandas
train_df = pandas.read_csv("dataset.csv")
# Convert the pandas dataframe into a TensorFlow dataset
train_ds = tfdf.keras.pd_dataframe_to_tf_dataset(train_df, label="category")
# Train the model
model = tfdf.keras.RandomForestModel()
model.fit(train_ds)*
有趣的是,该库还提供了一些可视化工具来检查模型,例如 tfdf.model_plotter.plot_model_in_colab(model, tree_idx=0)。
SymPy 符号数学快速指南
原文:https://towardsdatascience.com/a-quick-guide-to-symbolic-mathematics-with-sympy-e88d49406c8b?source=collection_archive---------3-----------------------
了解如何在 Python 中操作数学表达式

米歇尔·玛特隆在 Unsplash 上的照片
您的旅程概述
- 设置舞台
- 安装症状
- 创建 SymPy 符号
- 解方程
- 有用的功能
- 你可以用 SymPy 做的其他事情
- 包装
1 —搭建舞台
无论你是大学的学生,还是从事数据科学的工作,都没有绕过数学的路。有人甚至会说,数据科学(简单地说)是应用数学/统计学的一种形式。在 Python 中,有很多处理数学数值的库,像 NumPy 、 SciPy 、 Scikit-Learn 和 Tensorflow 。然而,要明确地处理数学符号,只有一个竞争者:SymPy。
SymPy 在 Python 中代表符号数学,是一个处理数学的 Python 库。在 NumPy、Pandas 和 Matplotlib 等巨头中,它是 SciPy 生态系统的核心库之一。有了 SymPy,你可以操纵数学表达式。此外,你可以解决大学水平的数学问题,需要微分,积分和线性代数。
在这篇博文中,我将向您展示如何使用 SymPy 中的基础知识,以便您可以开始象征性地解决数学问题。我之前在 SymPy 上制作了一个视频系列,所以如果你是一个视觉学习者,也可以随意看看😃
**前提:**你应该大概知道 Python 的基础知识。除此之外,你不需要任何关于 SymPy 的经验😌
2 —安装 SymPy
SymPy 的开发者推荐通过 Anaconda 安装 SymPy。如果您使用的是 Anaconda,那么您应该已经安装了 SymPy。为了确保您拥有最新的版本,请在 Anaconda 提示符下运行以下命令:
conda update sympy
如果您没有使用 Anaconda,而是使用 PIP,那么您可以运行以下命令:
pip install sympy
对于安装 SymPy 的其他方式,请查看安装选项。
3 —创建交响乐符号
现在让我们从 SymPy 开始吧!SymPy 的基本对象是一个符号。要在 SymPy 中创建一个符号x,您可以写:
# Import the package sympy with the alias sp
import sympy as sp# Create a symbol x
x = sp.symbols("x")
上面的代码创建了符号x。SymPy 中的符号是用来模拟代表未知量的数学符号。因此,下面的计算就不足为奇了:
print(x + 3*x)
**Output:** 4*x
正如你从上面看到的,符号x就像一个未知数。如果你想创建一个以上的符号,那么你可以这样写:
y, z = sp.symbols("y z")
这里你同时做了两个符号,y和z。现在,您可以随意加减乘除这些符号:
print((3*x + 2*y - 3*z)/x)
**Output:** (3*x + 2*y - 3*z)/x
在下一节中,我将向你展示如何用 SymPy 解方程🔥
**Pro 提示:**如果你看 SymPy 的文档,你有时会看到他们使用 import 语句
from sympy import *。除了快速测试之外,这是一个坏主意(即使在这种情况下,我也要说它会养成坏习惯)。问题是这样做会覆盖其他包中的函数和类。所以我一直推荐写import sympy as sp。
4 —解方程

照片由在 Unsplash 上绘制
现在让我们使用 SymPy 符号来解方程:假设你有一个二次多项式x**2 + 5*x + 6。怎么能解方程x**2 + 5*x + 6 = 0?我们大多数人对于如何手工操作都有一些模糊的记忆,但是你是如何让 SymPy 完成这项工作的呢?以下代码首先创建一个符号x,然后创建问题中的等式,最后求解该等式:
import sympy as sp# Creating the symbol x
x = sp.symbols("x")# Creates the equation in question
equation = sp.Eq(x**2 + 5*x + 6, 0)# Solving the equation
solution = sp.solveset(equation, x)
让我们看看上面的代码创建的变量solution:
print(type(solution))
**Output:** <class 'sympy.sets.sets.FiniteSet'>print(solution)
**Output:** FiniteSet(-3, -2)
如您所见,solution变量为我们提供了方程x**2 + 5*x + 6 = 0的两个解。SymPy 的 FiniteSet 类型是一个 iterable 类型,所以如果您愿意,您可以遍历它:
for num in solution:
print(num)**Output:**
-3
-2
如果您想从solution变量中提取数字-3 和-2,您可以首先将solution转换成一个列表,然后像往常一样进行索引:
# Turn solution into a list
solution_list = list(solution)# Access the individual solutions
print(solution_list[0])
**Output:** -3
我们刚刚完成了一个简单的二次多项式,如果你愿意的话,你可以用手算出来。但是,SymPy 解方程远比你我强(抱歉不抱歉)。自己尝试更难的东西,看看 SymPy 能承受多少😁
5 —有用的功能
关于 SymPy 的一个有趣的事情是它包含了有用的数学函数。这些函数可以开箱即用,您应该熟悉一些最常用的函数。
以下脚本使用 SymPy 中的函数创建了三个不同的方程:
import sympy as spx = sp.symbols("x")equation1 = sp.Eq(sp.cos(x) + 17*x, 0)equation2 = sp.Eq(sp.exp(x ** 2) - 5*sp.log(x), 0)equation3 = sp.Eq(sp.sinh(x) ** 2 + sp.cosh(x) ** 2, 0)
如果你仔细阅读上面的代码,你会发现
cos(余弦函数)sin(正弦函数)exp(指数函数)sinh(双曲正弦函数)cosh(双曲余弦函数)
配备了这些函数,您可以例如使激活函数用于深度神经网络。例如,众所周知的 sigmoid 激活函数可以写成如下形式:
sigmoid = 1/(1 + sp.exp(-x))
如果要将值代入 sigmoid 函数,可以使用.subs()方法。让我们试试这个:
print(sigmoid.subs(x, 2))
**Output:** 1/(exp(-2) + 1)
嗯。虽然从技术上来说是正确的,但是将该值作为浮点数会更好。为此,您可以使用函数sp.N()(N 代表数字):
print(sp.N(sigmoid.subs(x, 2)))
**Output:** 0.880797077977882

照片由 Aziz Acharki 在 Unsplash 上拍摄
6 —您可以使用 SymPy 做的其他事情
与其详细地漫谈更多的话题,不如让我给你一个清单,你可以检查一下来提高你的交响乐技巧:
- 导数和积分: SymPy 可以做你在微积分入门课上学到的大部分事情(除了思考😅).您可以从检查 SymPy 中函数的微分开始。
- 矩阵和线性代数: SymPy 可以处理矩阵,从线性代数开始做基本运算。该语法有点类似于 NumPy 使用的语法,但也有区别。首先,请查看 Sympy 中的预科课程
- 简化: SymPy 足够聪明,可以自动对表达式进行一些简化。然而,如果你想对此有更好的控制,那么看看 SymPy 中的简化。
- 深入探究 SymPy: 在本质上,SymPy 使用一种基于树的结构来跟踪被称为表达式树的表达式。如果你想深入了解 SymPy 的内部工作原理,可以查看一下表达式树。
- 与 NumPy 的关系: NumPy 和 SymPy 都是可以处理数学的库。但是,它们根本不同!NumPy 用数字运算,而 SymPy 用符号表达式。这两种方法都有优点和缺点。幸运的是,有一种聪明的方法可以将 SymPy 表达式“导出”到 NumPy 数组。查看 SymPy 中的 lambdify 函数了解其工作原理。
7 —总结
如果你需要了解更多关于 SymPy 的信息,请查看 SymPy 的文档或我在 SymPy 上的视频系列。
**喜欢我写的?**查看我的博客文章类型提示、Python 中的下划线、 5 个很棒的 NumPy 函数和 5 个字典提示以获得更多 Python 内容。如果你对数据科学、编程或任何介于两者之间的东西感兴趣,那么请随意在 LinkedIn 上加我,并向✋问好
Python 流图快速入门
原文:https://towardsdatascience.com/a-quick-introduction-into-stream-graphs-with-python-33ff4493ccc?source=collection_archive---------32-----------------------
使用 altair 可视化库

杰夫·塞奇威克的图片来自 Unsplash
什么是流图?
河流图是堆叠面积图的变体,通过使用流动的有机形状来显示不同类别的数据随时间的变化,从而创造出美观的河流/溪流外观。与堆积面积图不同,堆积面积图在固定的直轴上绘制数据,而流图的值在变化的中心基线周围移动。
流图中的每个单独的流形状与其类别的值成比例。颜色既可以用来区分每个类别,也可以通过改变颜色深浅来显示每个类别的附加定量值。
流图非常适合于显示大量数据集,以便发现各种类别随时间变化的趋势和模式。
流图的缺点是类别可能会被大型数据集弄得杂乱无章,使它们难以阅读和理解。
因此,流图应该留给不打算破译或探索数据细节的读者。流图更适合给出更全面的概述。
更多关于流图的阅读,请查看以下链接:
https://www.data-to-viz.com/graph/streamgraph.html#:~:text=A%20Stream%20graph%20is%20a%20type%20of%20stacked%20area%20chart.&text=Contrary%20to%20a%20stacked%20area,a%20flowing%20and%20organic%20shape https://en.wikipedia.org/wiki/Streamgraph
用 Python 制作流图
对于这个例子,我们将使用 Altair,它是 python 中的一个图形库。Altair 是一个声明式统计可视化库,基于 Vega 和 Vega-Lite。源代码可以在 GitHub 上获得。
https://altair-viz.github.io/
为了开始创建我们的流图,我们需要首先安装 Altair 和 vega_datasets 。
!pip install altair
!pip install vega_datasets
现在,让我们使用牛郎星和织女星数据集创建一个交互式流图来查看多个行业 10 年间的失业数据。
**import** **altair** **as** **alt**
**from** **vega_datasets** **import** data
source = data.unemployment_across_industries.url
alt.Chart(source).mark_area().encode(
alt.X('yearmonth(date):T',
axis=alt.Axis(format='%Y', domain=**False**, tickSize=0)
),
alt.Y('sum(count):Q', stack='center', axis=**None**),
alt.Color('series:N',
scale=alt.Scale(scheme='category20b')
)
).interactive()
使用上面的代码后,您应该能够看到类似这样的内容。

牛郎星流图
这里的流图允许我们快速解释数据中的比例变化。总的来说,我们可以看到 2008 年后所有行业的失业率都在上升。
结论
就是这样!现在前进,创建您自己的流图数据可视化。更多关于流图的资源和教程,请点击下面的链接。
https://www.r-graph-gallery.com/154-basic-interactive-streamgraph-2.html http://bl.ocks.org/mbostock/582915
有关系的
https://medium.com/geekculture/visualizing-human-motion-capture-data-with-d3-js-2acca2a49cff https://medium.com/new-health/visualizing-brain-waves-with-python-24847de94266
感谢您的阅读!!
ggplot2 快速介绍
原文:https://towardsdatascience.com/a-quick-introduction-to-ggplot2-d406f83bb9c9?source=collection_archive---------24-----------------------
理解图形的语法将如何帮助你用 ggplot2 构建任何图形

哈桑·阿尔马西在 Unsplash 上的照片
ggplot2 是 R 中广泛使用的图形库,也是 tidyverse 的一部分。tidyverse 是一个 R 包的集合,它们共享一个公共的设计哲学、语法和数据结构。例如,tidyverse 中的其他包是 dplyr 或 purrr。
图形的语法
ggplot2 建立在图形的语法之上。ggplot2 的开发者之一 Hadely Wickham 将语法描述为
“艺术或科学的基本原则或规则”。
因此,图形的语法是一种描述和创造大范围情节的方法。在 ggplot2 中,所有图都是使用图层创建的,其中每个图层都代表图形的一个组成部分。
在 ggplot2 的快速介绍中,您将了解“gg-plot”是如何构造和构建的。我确信一旦你理解了它的基本结构,你就可以在这些基础上构建未来的任何情节。因此,让我们深入研究,看看我们需要哪些层来使用 ggplot2 创建一个基本的绘图。
基础知识
ggplot2 中的每个图形至少使用以下三个组件构建:
- 数据以及数据点如何相互映射
- 一组几何对象也称为几何图形(表示数据点的视觉标记,如条、点或线)
- 一个坐标系
除了基本图层之外,ggplot2 还提供了许多其他图层,通过着色、缩放、分面或向数据添加统计变换来调整绘图。

ggplot2 的基础层。图片作者。
让我们建立我们的第一个情节,以更好地理解上面的解释。为此,我将利用 Kaggle 上的奥运数据集。开始打印前,请确保安装了库“ggplot2”。此外,我将到处使用 dplyr 库进行数据操作。
作为第一个例子,我们绘制了参加奥运会的运动员的身高(数据)的直方图(几何)。该图包括所有必要的组成部分:数据+几何+坐标系。

直方图显示参加奥运会运动员的身高分布。图片作者。
几何对象(geoms)
可用几何图形根据显示的变量的维度和类型而变化。例如,在我们的第一个图中,我们绘制了一个变量(高度),它是连续的。我强烈推荐打开 RStudio 的 ggplot2 备忘单,因为它提供了可用 geoms 的摘要。让我们绘制不同维度和不同类型的变量来了解一下:

左上:图 1 (1 个变量,连续),右上:图 2 (1 个变量,离散),左下:图 3 (2 个变量,都是连续的),右下:图 4 (2 个变量,一个连续,一个离散)。图片作者。
在不同的几何图形旁边,我们可以观察到另一件事:第二个图(1D,离散)显示一个图仍然显示,即使 coord_cartesian() 没有添加到代码中。第三个图(2D,两个都是连续的)显示,如果您想根据需要调整坐标系,则 coord_cartesian() 是强制的。在下文中,我将把我们的四个基本地块称为地块 1、地块 2、地块 3 和地块 4。
添加一些颜色和形状
在上面的例子中,所有的图形看起来都有点暗淡,可以用一些颜色或形状来改善。让我们通过调整美学属性让剧情变得更有趣。
美学属性可以用不同的方式来调整。 aes() 可以传递给 ggplot() 或特定层,如 geom 层。尤其是在处理一维数据时,这会对您的绘图产生影响。

顶行:对基本图 1 的调整。美学属性需要传递给几何层,以获得想要的结果。中间一排(左):调整到基本情节 3。添加了形状和颜色。底行和中间行(右):调整至图 4。图片作者。
在图 1 的调整二中,我们可以看到“绿色”被视为常量变量。这是因为 aes 的前两个参数(x,y..)被期望的变量。处理二维数据时,情况有所不同(参见图 4 的调整一和调整二)。在这里, aes() 可以无影响地传递给 ggplot() 或 geom 层。
统计变换
除了几何层,数据点还可以使用统计层映射到坐标系。此外,您可能需要对绘图数据进行统计转换,而不是使用原始数据(stat="identity ")。然后你可以将几何层的统计参数设置为“计数”或“汇总”。让我们在图中看到统计如何影响你的图表。

左图:用 stat_layer 计算运动员人数创建的图。右图:平均重量用作可变重量的统计转换。图片作者。
第一张图显示了每个奥运城市的运动员数量,按性别分类。与此相比,stat_plot2 使用转换“summary”按性别显示运动员的平均体重。
位置、标题、图例和网格
现在,您已经了解了 ggplot2 的基础知识。然而,额外的图层可以很容易地添加进去,并极大地影响你的绘图质量:标题、图例、位置或网格。使用 labs() 添加图层以调整绘图标题或轴标题,使用 theme() 或 scale_fill_discrete() 添加图例,或使用 facet_grid() 添加网格。

左图:每个奥运城市的性别比例,添加图层以调整标题、图例和条形图。右图:通过添加层来添加网格和标题,按季节显示运动员的身高和体重之间的相关性。
现在你已经有了在 **ggplot2、**中构建一个基本剧情所需的所有工具,在我看来,也有了构建任何更复杂剧情的要求。通过理解《T21》背后的哲学,并将每一次调整视为另一层,你已经成功了一半。密谋愉快!
资源
- https://rpubs.com/aelhabr/tidyverse-basics
- https://www.tandfonline.com/doi/abs/10.1198/jcgs.2009.07098
- https://cfss.uchicago.edu/notes/grammar-of-graphics/
- https://r studio . com/WP-content/uploads/2015/03/gg plot 2-cheat sheet . pdf
责任 AI 或 rAI 快速介绍
原文:https://towardsdatascience.com/a-quick-introduction-to-responsible-ai-or-rai-ae75fad526dc?source=collection_archive---------36-----------------------

来源:starline 创建的背景向量—www.freepik.com
邀请你开始思考为商业开发一个负责任的人工智能的相关性
人工智能(AI)越来越多地支持我们生活、社会和业务中的关键决策。人工智能和其他决策技术的区别在于它“学习”。
随着人工智能更加深入我们的生活,它将继续变得更加自主,甚至可以在没有人类监督的情况下行动。
人工智能的实施需要精心管理,以避免对品牌和员工、个人以及整个社会的声誉造成无意但重大的损害。
在这种情况下,负责任的 AI 或 rAI 确保这些决策是安全、可靠、经过验证的,并以的方式进行解释。
负责任的人工智能是组织必须达到的基本标准,因为几乎普遍地,人工智能模型可以对某人的生活质量产生巨大影响。
rAI 开发的标准旨在使组织能够理解并执行四个既定的管理原则:、问责、透明,以及最后的责任**。**
探索负责任的人工智能的关键方面
一个很好的切入点是提出这样一个问题,即组织是否能够在智胜竞争的同时发现如何整合他们的文化和社会价值观,企业被推动快速前进,甚至比他们应该的速度更快,这种速度是有代价的?
当一个公司犯了一个错误,机器就会被追究责任。人工智能的一些领域将永远比其他领域更与我们的社会相关。
此外,公司需要展示人工智能是如何做出具体决定的,特别是在涉及金融服务和保险等高度监管的行业时。他们需要积极主动地证明他们的算法,清楚地传达他们的(学习)偏见政策,并对为什么做出决定提供清楚的解释,特别是当有问题时。
这里的建议很简单:对于受监管/高风险的用例,如信贷审批,始终考虑使用透明和可解释的算法,以使一线员工更容易理解和解释客户的决定。
为什么需要有一个负责任的人工智能?
负责任的人工智能是组织必须满足的关键标准,因为几乎普遍地,人工智能模型可以对某人的生活质量产生巨大影响。
人工智能模型的性能不应该是学术数据科学研究的主要焦点;这些模型必须首先是可解释的,其次是可预测的,并内置于负责任的人工智能标准中。
否则,模型会很快变得非常复杂,无法解释。
为了在高度自动化但意识越来越强的世界中取得成功,公司需要了解人工智能带来的挑战和潜在风险,并确保其在组织中的使用符合道德规范,符合监管要求,并得到良好治理的支持。
从治理的角度来看,道德人工智能意味着检查模型并识别其隐藏的偏见。
严格的开发过程,加上潜在资源的可见性,有助于确保分析模型符合伦理。必须持续监控潜在特征,以了解变化环境中的趋势。
这是“首次构建正确”的委婉说法。操作环境模型必须从一开始就设计好。构建高效模型的最佳方法是走上面描述的路线。这极大地降低了模型中的错误风险,从而降低了预期的业务价值,同时在分析过程中影响了客户。
负责任发展的框架。
一些重要的人工智能公司,如微软、IBM,以及许多咨询公司,如 Gartner、McKinsey 和其他公司,都在致力于定义和实现支持 rAI 实现的框架。
在我看来,一种有趣的方法是由普华永道在其“负责任的人工智能实用指南”报告中定义的,该报告由一套人工智能责任工具组成,旨在帮助公司专注于负责任的人工智能项目、开发和部署中需要解决的五个关键维度。
它们包括治理、道德、监管;解释和说明;稳健性和安全性;公正和正义。
该框架为技术决策制定、识别、结合环境和减轻道德风险提供了一个合理的个性化方法。
该工具包支持整个组织的人工智能评估和开发,使公司能够开发高质量、透明、道德、可解释和信任激励的应用程序。
负责任的人工智能路线图面临的挑战
在所有组织中实现负责任的人工智能标准的最大障碍是大多数董事会和首席执行官对分析及其对业务的影响(包括人工智能可能造成的损害)没有足够的理解。
此外,随着人工智能在所有部门的使用越来越多,政府监管即使不是不可避免的,也是非常可能的。董事会、高管和数据科学家不应该将监管视为惩罚或抑制创新,而是必须接受负责任的人工智能是一项有益和必要的要求。
结论
也有大量关于种族主义、性别歧视和侵犯与人工智能相关的隐私的新闻,因此,可以理解的是,领导者们担心确保在他们的业务中引入人工智能系统不会产生负面影响。
几乎可以肯定的是,最好的选择是不要完全停止使用人工智能——它的价值可能太大了,尽早使用人工智能可能对企业有利。
公司应该做的是确保负责任地开发和实施人工智能,注意确认实施结果是相同的,新的定制级别不会导致歧视,数据的获取和使用不会损害用户的隐私,以及他们的组织在人工智能系统的性能和解释模型如何工作的能力之间找到平衡。
公正、开放、同情和稳健必须是所有企业负责任的人工智能政策的四个关键支柱。
虽然组织不能慢下来,但需要团结在一套尊重客户的基本原则和可持续(可能有利可图)的长期成功愿景周围。
这将有助于在我们的社会中建立一个更加公平的人工智能环境。
还有一件事…
如果你想在学习之旅中走得更远,我为你准备了一份令人惊叹的清单,其中包含 60 多门关于人工智能、机器学习、深度学习和数据科学的培训课程,你现在就可以免费参加:
- 什么是预测分析,你今天如何使用它?
- 今天学习 AI、ML、数据科学的最佳免费课程。
- 60 多门课程,有评分,有总结(当然是 AI 做的)。
- 是我们所知的作品的终结吗?世界经济论坛《2020 年的就业前景》报告简析
如果你想继续发现新的资源并了解人工智能,在我的电子书(下方的链接)中,我正在分享关于人工智能、机器学习、深度学习、数据科学、商业智能、分析和其他方面的最佳文章、网站和免费在线培训课程,以帮助你开始学习和发展职业生涯。
学习 AI 在线:200 多种资源在线开始学习 AI
此外,我刚刚在亚马逊上发布了其他有趣的电子书,我相信其中一些可能会让你感兴趣……让我们保持联系,关注我,让我们一起做吧。
- 人工智能、机器人技术和编码(给父母):模拟父母与数字孩子实用指南
- 终结者悖论:神经科学如何帮助我们理解移情和对人工智能的恐惧
- 人工智能从 A 到 Z:揭秘 AI 的本质概念
- 2020 年人工智能:写人工智能的一年
订阅我的每周时事通讯,保持更新
如果你对人工智能、机器学习、数据科学和自动驾驶汽车的话题感兴趣,以及这些创新将如何扰乱世界各地的每一个企业,这份时事通讯肯定会让你保持更新。
点击下面的链接订阅人工智能新闻!
https://medium.com/tech-cult-heartbeat/newsletters/ai-new
在哪里可以了解更多关于媒体上负责任的人工智能的信息
**https://medium.com/@ronbodkin/responsible-ai-f33ab5e6672c https://medium.com/swlh/responsible-ai-how-we-do-we-build-systems-that-dont-discriminate-2592c896fb89 https://medium.com/@ODSC/responsible-ai-2020-expectations-for-the-year-ahead-d15eb8598b6f https://medium.com/ai-ml-at-symantec/responsible-ai-ml-privacy-bias-and-more-in-the-age-of-the-algorithm-36cb5ef68d9a
参考
- 负责任的 Ai-FICO。https://www.fico.com/blogs/what-responsible-ai
- 负责任的人工智能(AI)实用指南——https://www . PwC . com/GX/en/issues/data-and-analytics/Artificial-Intelligence/what-is-Responsible-AI/Responsible-AI-practical-guide . pdf
- 负责任的人工智能在我们快节奏的世界中的重要性…https://TB tech . co/the-importance-of-responsible-ai-in-our-fast-paced-world/
- https://towards data science . com/an-introduction-to-explable-artificial-intelligence-or-xai-f 7 EC 21 db 825 bf
你愿意支持我吗?
为了获得无限的故事,你也可以考虑 注册 成为中等会员,只需 5 美元。此外,如果您使用我的链接注册 ,我会收到一小笔佣金(无需额外费用)。
https://jairribeiro.medium.com/membership **
关于图及其下游任务的公式的快速注释
原文:https://towardsdatascience.com/a-quick-note-on-graphs-and-the-formulation-of-their-downstream-tasks-d8a8c808c93f?source=collection_archive---------14-----------------------
一些重要的任务包括:节点分类、链接预测、社区检测、图分类和三重分类

Robynne Hu 在 Unsplash 上的照片
G raph 数据结构已经被证明可以有效地捕获复杂的非欧几里得数据,如生物和社交网络(欧几里得数据是图像、文本或简单的数字数据)。
我们成功地使用图形作为输入来建立预测模型,并且将各种深度学习技术应用于图形,在某些情况下,增强了图形机器学习模型的性能。
那么,我们可以使用图形预测什么,以及如何从如此复杂的数据结构中构建预测模型呢?
在这篇文章中,我将解释一些与图相关的任务的公式,这些任务也称为图下游任务。这些任务的公式化通常发生在我们学习了图形实体的数字表示之后。
图及其不同类型

照片由 Alina Grubnyak 在 Unsplash 上拍摄
我们使用图形来模拟现实生活中的交互或网络,根据上下文,我们可以使用不同类型的图形结构,例如:
- 无向图:就像一个朋友的社交网络,节点代表个人,边代表他们的友谊。在这里,边没有定向的性质。
- 有向图:这里,我们观察边的有向性质。例如,Instagram 追随者的网络,其中节点是个人账户,边是追随者。比如,我追随埃隆·马斯克,但埃隆并没有追随我。这将向作为关系方向的边添加一个属性。
- 单关系图:这里所有的节点和边都代表一种属性,可以是友谊、互动等,本质上可以是有向的,也可以是无向的。
- 多关系图:这里,节点和边可以有不同的属性,一个简单的例子是代表不同类型朋友的社交网络,比如学校朋友、大学朋友等。知识图(目前非常流行)是多关系图的一个很好的例子。
注意:这不是一个详尽的列表。
通常,在图形机器学习中,第一步是使用一组称为低维嵌入或简单的图形实体的数字表示的数字来捕获网络信息。
现在,让我们来谈谈图下游的任务。
节点分类

纳蕾塔·马丁在 Unsplash 上的照片
图中的节点可以被标记,对于大型图来说,丢失一些标记是常有的事。节点分类被公式化为二元分类任务(在 2 种不同类型标签的情况下)或多类分类任务(> 2 个标签)。
这里,预测机器学习模型的输入特征是节点嵌入或简单的数字表示,例如像节点度、图着色数等图属性。
对于这个分类任务,您可以使用标准的机器学习算法或神经网络方法,如图形神经网络。
链接预测
这是图机器学习的重要任务之一。链接预测的任务是预测图中缺失的边或链接,以及预测预期的边(在动态图的情况下,边基于图的时间点消失和形成)。
在像蛋白质-蛋白质相互作用这样的生物网络背景下,使用标准的实验室实验,很难识别所有可能的蛋白质-蛋白质相互作用。因此,链接预测在这个领域变得至关重要。
根据图形的类型,链路预测可以用不同的方式表示:
- 作为二分类任务:对于二分类,我们需要两个标签,比如正标签和负标签。我们采用图中存在的边来创建正标签的实例,并且我们可以随机采样一些负边来创建负标签的实例。由于边由两个实体(两个节点)组成,我们对节点嵌入(对应于边)进行逐元素乘法,以获得每个实例(正或负)的一个特征向量。现在,这些特征和标签被用来建立预测模型。图形神经网络可用于解决作为二进制分类问题的链路预测问题。
- 计分基础法:思路很简单。我们使用评分函数来学习嵌入,使得我们在具有边缘的情况下得分较高,而在边缘不存在的情况下得分较低。给定分数的阈值,我们可以识别两个给定节点之间的预期边的可能性。在知识图链接预测的情况下,通常采用基于等级的评估方法。此外,知识图中的三元组可以被建模为头部预测(?,r,t)和尾部预测(h,r,)模特。这完全取决于使用链路预测任务构建的用例。
社区检测/图形聚类

照片由内森·杜姆劳在 Unsplash 上拍摄
这是一个无监督的聚类任务,目标是找到一组重要的具有相似属性的实体。有几种算法可以找到聚类,我们也可以使用机器学习技术来达到这个目的。
在生物蛋白质-蛋白质网络中,这种聚类也被称为复杂检测。我们确定了蛋白质复合物,它是一种重要的生物机器。
图形分类
给定一个较大的图,它可以包含属于某一类的一些较小的图簇。图分类是旨在预测较大图中较小集群/社区的标签或类别的任务。
这类任务的一个示例数据集是一组图表,如来自多特蒙德大学的蛋白质数据集。数据集中的每张图都有一个标签,标明它是酶还是非酶。总共有 1113 个图,每个图平均有 39 个节点和 73 条边。由于我们有 2 个标签,这是一个二元分类的任务。
三重分类

由 NASA 在 Unsplash 上拍摄的照片
知识图中的实体被视为三元组。三重分类归结为二元分类任务,其中有两个标签,即阳性和阴性。正三元组是知识图的一部分,负三元组不是知识图的一部分。
一般来说,学习图形实体的高质量嵌入对于图形机器学习是必要的,显然,对于三分类任务也是如此。我们生成的嵌入应该能够获得比负三元组更高的正三元组分数。我们随后定义了一个阈值来区分正三元组和负三元组。
随着知识图不断增长,越来越多的三元组被添加到其中,可能存在质量差的数据被注入到数据库中的问题。不属于知识图的损坏的三元组可能被注入到知识图中,并且识别这种质量差的数据的一种方式是通过使用三元组分类。
图下游任务的使用更多地依赖于领域和为解决相应的领域问题而构建的用例。请记住,图是对复杂的现实生活场景进行建模的优秀工具,这些场景可能与空间、生物、电信、娱乐业(电影、歌曲推荐)等领域相关,每个领域都可能有数百个问题,并且可能使用图机器学习来解决这些问题。
如果你看到了这篇文章的这一部分,感谢你的阅读和关注。我希望你觉得这篇文章内容丰富,并且可以通过 LinkedIn 、 Twitter 或 GitHub 联系到我。
NVIDIA Jarvis 快速概述——对话式人工智能的端到端框架
原文:https://towardsdatascience.com/a-quick-overview-of-nvidia-jarvis-an-end-to-end-framework-for-conversational-ai-fd808d4f6607?source=collection_archive---------27-----------------------
NVIDIA Jarvis 框架简化了训练和部署对话式 AI 系统的过程,使构建具有自动语音识别、文本到语音转换和自然语言理解功能的应用程序变得更加容易

劳拉·穆西康斯基摄于佩克斯
介绍
在过去的几年里,人工智能技术的能力迅速提高。特别是自然语言处理(NLP ),由于 Transformer 体系结构及其衍生产品,已经取得了令人难以置信的进步。当前最先进的系统能够接近人类水平(或者在某些情况下超过人类水平!)在语言生成、文本分类、问答等多项语言任务中的表现。
类似地,当前的语音合成(文本到语音/TTS)模型可以生成与人类语音几乎没有区别的语音。另一方面,自动语音识别(ASR)通常在理解人类语音方面相当成功,即使考虑到嘈杂的背景和不同口音的说话者。可悲的是,我的手机仍然很难识别斯里兰卡的名字,但我真的不能责怪我的手机!然而,当我问路时,我可以相信它能认出我要去的地方的名字(是的,甚至在斯里兰卡!).
总的来说,组成对话式人工智能的不同组件(ASR、语言理解、语言生成和 TTS)已经发展到了这样一个阶段,即该技术不仅是可行的;这几乎是必须的。这可能是千禧一代的我在问,但我真的必须和某人交谈才能预约吗?🙄
特别是由于全球疫情,人类接触受到限制,更多自动化和更少繁琐任务的时机肯定已经成熟!
尽管这些技术取得了进步,但是在将它们用于现实世界时,仍然存在巨大的障碍。例如,训练深度学习模型,这是大多数对话式人工智能技术的基础,需要大量的计算和数据资源。虽然深度学习模型能够做出令人印象深刻的壮举,但构建和训练实现这种潜力的模型通常需要大量的技术专业知识。除此之外,即使您已经训练了您的模型,将它们投入生产并维护它们是另一个挑战,通常需要完全不同的技术专长。
NVIDIA Jarvis Framework 旨在解决所有这些问题,并作为构建对话式人工智能系统的端到端工具包。它为各种任务提供预训练模型,重新训练/微调这些模型的能力(转移学习工具包和/或尼莫),以及(自动)优化模型的轻松部署。
迁移学习,或在新任务/领域上微调预训练模型的能力,是深度学习模型(如 BERT)如此成功的重要原因。迁移学习工具包提供了一种方法,使用这种技术来为您的任务或领域调整预先训练的模型,并生成一个可以使用 Jarvis 直接部署的模型。令人印象深刻的是,您可以通过简单地编辑几个配置文件来完成所有这些,而无需编写任何实际的代码。对于那些想要开始使用对话式人工智能,但之前很少或没有训练和部署深度学习模型的经验的人来说,这应该特别有用。
我目前正在编写一份指南,使用 TLT 来微调一种新语言的 ASR 模型!ASR 对我来说是一个相对较新的领域,到目前为止这个过程如此顺利给我留下了深刻的印象。
接下来,让我们看看 Jarvis 框架支持的不同服务和任务。
贾维斯服务公司
Jarvis 目前支持的服务分为三类:
- 语音识别— Jasper,Quartznet
- 语音合成— TacoTron2,Waveglow
- 自然语言理解—威震天,伯特
NLU 服务包括几个高级和低级 API。
高层
- 命名实体识别
- 意图分类—域分类器和意图/槽标记器(对查询的意图进行分类,并检测意图的相关实体和槽)
- 问题回答
- 标点符号和大写
低级的
- 文本分类
- 令牌分类
所有这些服务都可以通过执行快速入门指南中给出的几个命令来轻松部署。最棒的是,服务是通过 Docker 部署的,所以你真正需要安装的只是 Docker(支持 NVIDIA GPUs)。
您不一定需要部署所有可用的服务。如果您只需要特定的服务并保持较小的资源占用,您可以选择想要部署的服务。
一旦部署完成,您就可以使用提供的 API(gRPC、Python 或命令行)与这些服务进行交互。这使得根据需要构建集成各种 Jarvis 服务的应用程序变得非常容易。
接下来呢?
默认情况下,Jarvis 使用预先训练好的模型,这意味着这些服务将开箱即用地适用于许多不同的用例。例如,您可以通过使用语音识别服务轻松构建一个基于语音的问题回答系统,以获取用户的查询(可能还有在其中寻找答案的文档的名称),使用问题回答服务提取答案,并使用语音合成服务大声读出答案。
虽然预先训练的模型很可能适用于一般情况,但您可以根据感兴趣领域的数据对模型进行微调,以获得最佳性能。例如,如果问答模型预期用于法律案例文件、医疗保健中的患者记录或学术界的研究论文,则可以通过使用相关领域的数据对模型进行微调来获得更好的性能。使用迁移学习工具包框架可以很容易地对模型进行微调,它可以生成一个与 Jarvis 兼容的模型,以便于部署。
总的来说,Jarvis 为您提供了很大的灵活性来更新/微调预训练的模型,以便在定制域上执行得更好,并且仍然能够使用相同的一致管道轻松地部署微调的模型。用于与不同服务交互的 API 也是一致且易于使用的,这使得将 Jarvis 集成到您自己的应用程序中的过程非常简单。
包扎
Jarvis 框架使得为对话式人工智能的各个方面部署最先进的模型成为可能,而不必担心设置不同框架和服务以及让它们相互配合的(通常令人沮丧的)细节。您还可以根据需要自由地微调这些模型,并轻松地将更新的模型部署为 Jarvis 服务。
不同的 Jarvis 服务可以通过 API 单独访问,这使得构建具有高质量 ASR、NLU 和 TTS 功能的定制应用程序变得简单。
总而言之,Jarvis 框架支持对话式 AI 系统的整个生命周期,从训练/微调模型到将它们部署为优化的、生产就绪的服务。这对于那些不太熟悉人工智能和深度学习,但对将对话式人工智能元素融入他们的应用程序感兴趣的应用程序开发人员来说尤其有用。另一方面,熟悉 AI 的研究人员不一定想处理部署他们的模型的后勤工作,他们肯定会欣赏 Jarvis 模型和服务的简单部署过程。
阿帕奇气流快速入门
原文:https://towardsdatascience.com/a-quick-primer-on-apache-airflow-d941fe52d8f?source=collection_archive---------11-----------------------
Airflow 是一个用于创作、调度和监控工作流的平台。它本质上是一个运行在元数据数据库上的排队系统和一个运行任务的调度程序。工作流被写成有向无环图(Dag)。工作流和 DAG 可以互换。
什么是 Dag?
DAG 是您要运行的任务的集合,其组织方式说明了任务之间的依赖关系和关系。
下图显示了 DAG 是一个单向的非循环图,其中图中的每个节点都是一个任务,边定义了任务之间的依赖关系。在任何情况下,您都不应该能够从前向节点返回到已经执行的节点。

显示节点间非循环关系的图表。除非另有说明,所有图片均由作者提供。
DAG 可以被分解成越来越小的作业,并通过生成用代码编写的动态管道来赋予用户完全的控制权。气流 Dag 也是可扩展的和可伸缩的。Dag 功能强大,因为它们允许协作、可管理和可测试的工作流。额外的好处是 Airflow 是用 python 开发的,可以与任何 python API 接口。

并行运行的气流任务
上图显示了气流如何将任务分成分支,这样,如果一个分支失败,另一个分支仍有输出。此外,随着并行计算的出现,处理时间也减少了。由于每项任务都是独立的,因此失败的可能性总体上会降低。
任务是如何执行的?
- 操作符代表工作流中的单个任务,有助于执行您的任务(例如运行 python 函数)。
- 操作员决定当您的 dag 运行时实际要做什么。
- 任务在实例化时是一个操作符。这是工人努力的方向。
气流架构:

上图展示了气流工作流程的一般架构。
- 元数据 —是一个关系数据库,包含任务状态信息,例如消耗内存最多的前十个任务,它包含与当前运行的任务相关的所有数据以及历史数据。
- 调度器 —决定运行哪个任务、何时运行以及以什么顺序运行。
- Web 服务器 —本质上是一个与元数据对话的 flask 应用程序的 UI。
- 执行者 —在地面执行任务。执行器是一个消息队列进程,它计算出哪个工人将执行哪个任务。默认的是顺序执行器——它不能并行运行任务——这意味着它不能用于生产级代码。也可以使用本地执行器,它将运行任务,直到服务器上的所有资源都达到最大容量。这对于中等数量的 Dag 来说很好。这两者都用于单节点群集中,因此不能用于扩展。
- 多节点集群 —具有相同的组件,只有调度程序和 web 服务器放在同一个节点(主节点)中,工作程序放在单独的实例中。这种设置工作得很好,因为它允许通过添加更多的多节点集群来进行扩展(celery 是 python 这里选择的执行器)。
如果您不处理万亿字节的数据,那么最好将调度器、web 服务器和执行器一起放在主节点/集群中。缺点是这种单一集群方法在同一台机器上运行所有内容,因此如果您对 DAG/scheduler 进行了更改,那么您需要重新启动整个工作流,甚至是正在执行的任务。芹菜避免了这一点。

分布式气流架构
如果您确实用 celery 构建了一个分布式工作流,那么就需要一个排队系统组件(比如 Redis)。对于本地工作流,排队由系统处理。
任务的生命周期
- 排定程序会定期检查 DAG 文件夹,查看是否有任何需要运行的 DAGS。
- 如果发现任何 DAGS 等待执行,调度器为其创建图表,这是 DAG 的实时实例化。
- 调度程序将在元数据中将 DAG 状态更新为正在运行,任务将会执行。
- 然后,调度程序读取 DAG,并将任务按执行顺序以消息的形式放入排队系统。每个消息都包含像 DAG ID、任务 ID 和要执行的功能这样的信息。
- 此时,这些任务的状态会更改为“排队”。
- 然后,执行器开始执行任务,并向元数据发送任务的失败/成功消息。
- 当所有任务运行成功或失败时,调度程序最终更新图表的状态。
对创造性人工智能的一些伦理含义的快速思考
原文:https://towardsdatascience.com/a-quick-reflection-on-some-ethical-implications-of-creative-ai-adba63acdd47?source=collection_archive---------33-----------------------

尼克·莫里森在 Unsplash 上拍摄的照片
人工智能正越来越多地应用于更具创造性的领域,引发了人们对知识产权保护的担忧。
免责声明:我不是律师,因此,这篇文章不应被用作法律建议,所以把它作为一个新兴技术和市场变化的经验丰富的观察者的个人意见。
最近,我开始分析一种趋势,这种趋势将人工智能带向一个更具“创造性”的空间,与人类的创造力相结合。
随着人工智能内容生成能力的提高,它开始更经常地应用于更多样化的领域,引发了人们对其内容如何作为知识产权受到保护的担忧。
让我们考虑一下所有依靠知识产权来创造和获取价值的行业和部门。这一系列包括软件、电子产品、消费品、药品、医疗设备、视频游戏、电影和电视、新闻和新闻媒体以及音乐。
这些行业的市场价值和单个参与者的利润与知识产权保护密切相关。
随着人工智能的贡献越来越大,而人类对所产生的价值的贡献越来越小,我们可以预计很快就会看到围绕知识产权是否受到保护的更明显的模糊性。
短期来看,政策环境似乎不会有太大变化。目前的趋势似乎是重申人类作为发明者和作者以及专利和版权办公室在保护人类创造力免受人工智能生成内容影响方面的作用。

照片由 Sam Moqadam 在 Unsplash 拍摄
人工智能辅助的内容与人工智能生成的内容
在人工智能辅助的努力中,人类正在做出创造性的贡献——通常是当前的艺术状态——人工智能将被视为一种工具,不需要被列为共同发明人,而那些团队成员将被列为发明人和作者。
但一个重要的问题不是人工智能能否成为生产者,而是人工智能的产出能否获得版权。
增强特定技能的人工智能通常不会有显著的不同。然而,当我们有更多的人工智能能力成为相关学术或企业角色的https://en.wikipedia.org/wiki/inventor或 作者 时,专利将会增加。希望人工智能辅助的和人工智能生成的输出之间有所区别。
如果我们开始想象特定人工智能生成的工作场景——人工智能在没有任何人类干预的情况下找到数据,训练自己,并“创造”特定的输出——我们可以想象它会如何对现有的知识产权规则施加压力。
在人工智能创造发明的情况下,我们将看到人类作为中间人,对发明创造提出可疑的主张,并在知识产权保护有效性的更大不确定性状态下运作。
我们会遇到一些奇怪的情况,人工智能的产出将大大超过人类能够创造的东西——不仅仅是像“额头的汗水这样的作品,而是真正的莎士比亚级别的小说——但在最严格的法律解释下,不值得知识产权保护。
这里提出了一个伦理困境…谁拥有权利和责任,例如,如果我们有一个仍在运行并自主产生发明的人工智能,但开发该人工智能的所有原始团队成员都死了?
在这种情况下,编辑或团队的公司将仍然拥有人工智能。尽管如此,其雇员在专利申请中对专利权的任何主张都是牵强附会的,不是吗?
还有一个问题是,如果没有杰出的人或公司控制这样的人工智能,谁来为自主人工智能从事有问题的行为承担责任,例如专利侵权。
在回答谁将被视为对人工智能系统编写的信息负责时,圣巴勃罗 CEU 大学传播学院教授、Idoia Ana Salazar garcía 确认经理将负责媒体事务。最终,这台机器会像另一名雇员一样,给记者提供报道角度的建议。
这就是为什么我们必须教育媒体经理和编辑,让他们知道算法的决定如何能够产生重大的社会影响。
当然,版权和专利是不同的情况。目前,美国只为人类创作的作品注册版权(即使考虑 AI 辅助)。与此同时,英国、印度、新西兰、南非和香港等其他国家已经建立了保护计算机生成作品的框架和先例,但作者仍需是人类。然而,著作权被分配给安排创作作品的人。

照片由附身摄影在 Unsplash 上拍摄
但是谁来保护 AI 的权利呢?
人工智能本身如何受到保护与它的输出如何受到保护是一个不同的问题。
人工智能的某些方面可以通过专利和版权得到保护。有些元素——比如数据集和算法——非常适合作为商业秘密。
随着人工智能变得越来越有价值,我们将看到窃取敏感人工智能技术的企图显著增加。反过来,人工智能公司将需要用网络安全解决方案和程序来捍卫它们皇冠上的宝石。
还有一个问题是,人工智能是否可以在音乐等受保护的内容上接受训练,这在法律中还没有完全解决。
虽然版权所有者通常持有衍生作品的权利,但如果经过训练的算法没有降低原创作品的价值,并且经过训练的人工智能的材料很少,那么使用受保护的数据来训练算法可能属于合理使用。
相比之下,如果人工智能出于比较的目的保留受保护材料的数据库(例如,用于监控的面部识别),这可能是不道德的使用,正如美国知识产权所有者协会(IPO)在 2020 年确认的那样。
一些国家正在探索在人工智能培训中使用版权材料的明确豁免——日本已经更新了法律。

杆长在未飞溅上拍照
结论
这个领域的可能性是无穷无尽的,而我们只是处在这场创造性革命的开端。
目前,没有任何即将出台的政策来抑制或影响人工智能著作权或专利局,只要它们符合当前法规设定的准则。
这意味着,在完全由人工智能产生的发明中,我们将在一个更大的不确定性状态下运作,在很长一段时间内,知识产权保护的有效性仍然是一个开放的问题:
谁拥有人工智能产生的发明的权利和责任?
还有一件事…
如果你想阅读更多关于创造性人工智能以及如何开始学习它的内容,你可能也想阅读以下文章:
****https://medium.com/towards-artificial-intelligence/an-overview-of-creative-ai-3fb2e6d2706b https://medium.com/towards-artificial-intelligence/a-simple-approach-to-define-human-and-artificial-intelligence-4d91087d16ff https://medium.com/dataseries/my-favorite-free-or-free-to-audit-courses-to-learn-ai-ml-and-data-science-f15f614a84e5
此外,我刚刚在亚马逊 上出版了一本新的电子书 ,今年我已经在着手出版一些其他的了……让我们保持联系,一起努力吧。
https://www.amazon.com/Jair-Ribeiro/e/B08RW788MS
参考
- 人工智能在数据新闻中的应用:什么是伦理…https://science media hub . eu/2019/10/08/the-use-of-ai-in-data-journalism-what-is-the-ethical-implications/
- 开发人员人工智能伦理指南。https://www . emerald . com/insight/content/doi/10.1108/JICES-12-2019-0138/full/html
- 探索最终用户许可协议。https://alexjohnlucas.com/type/eula
- 创造性人工智能概述—https://medium . com/forward-artificial-intelligence/an-Overview-of-Creative-AI-3 fb2 e6d 2706 b
- 人工智能,伦理和版权。https://hughstephensblog . net/2020/03/16/ai-ethics-and-copyright/
- 人工智能|塑造欧洲的数字未来。https://EC . Europa . eu/digital-single-market/en/artificial-intelligence
- 邪教委员会研究-人工…https://www . europal . Europa . eu/RegData/etudes/BRIE/2020/629220/IPOL _ BRI(2020)629220 _ en . pdf****
关于如何将您的 Streamlit 应用程序部署到 Heroku 的快速教程。
原文:https://towardsdatascience.com/a-quick-tutorial-on-how-to-deploy-your-streamlit-app-to-heroku-874e1250dadd?source=collection_archive---------5-----------------------
关于如何在 Heroku 上托管您的 Streamlit 应用程序的终极指南。

凯文·Ku 在 Unsplash 上的照片
欢迎学习如何将您的 Streamlit 应用程序部署到 Heroku 的分步教程。在过去的两周里,我一直在使用 Streamlit,它的功能给我留下了深刻的印象。它非常适合与全世界分享您的数据科学项目,因为它非常简单。在本教程中,我假设您已经完成了您的应用程序,并且处于部署项目的最后阶段。根据我过去两周的经验,您会认为您可以使用 Streamlit Sharing 立即部署您的项目。但是,您需要申请该功能,他们可能需要几天时间向您发送邀请。更糟糕的是,我甚至听说过这样的故事,人们等了一个星期才收到邀请,以利用 Streamlit 共享。如果你不能等待,你可以将你的应用程序部署到 Heroku 或其他主机上。在本指南中,我将只介绍如何将你的应用程序部署到 Heroku 和上。注意,如果你想将它托管在 AWS 或其他地方,下面的步骤将不起作用。
步骤 1:在本地运行您的 Streamlit 应用程序
第一步是确保您有一个 python 文件。如果您正在使用 Jupyter 笔记本,请确保将您的文件下载为. py 文件。如果你想用 Streamlit 在本地运行你的代码,然后把它推送到 Heroku,这是必要的。我已经创建了一个样本 Streamlit 应用程序,所以我们可以跟着这里。我的 python 脚本的名称是 app.py。要在本地运行代码,请使用命令行界面(CLI)转到保存脚本的目录。进入目录后,运行以下命令。
streamlit run app.py
你的浏览器会自动打开一个窗口,如下图所示。

作者图片
瞧,您已经在本地机器上运行了您的 Streamlit 应用程序。
步骤 2:创建 GitHub 存储库
下一步是为你的应用程序创建一个 GitHub repo。登录您的 GitHub 帐户,按照以下步骤操作:

作者图片
键入您的存储库名称,然后单击“创建存储库”

作者图片
现在,您已经创建了回购,是时候进行第一次提交并推动回购了。在您的终端中,移动到 app.py 所在的目录,并复制粘贴以下代码。
echo "# streamlit-to-heroku-tutorial" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M master
git remote add origin https://github.com/your_username/your_repo_name.git
git push -u origin master
我在上面的代码中初始化我的目录,添加一个 README.md 文件,一个带有你在上面看到的 URL 的远程源,并进行我的第一次推送。
步骤 3:创建 requirements.txt、setup.sh 和 Procfile。
下一步是至关重要的,你要确保你没有任何错别字或任何错误。否则,Heroku 将在您部署应用程序时运行错误。在继续之前,请确保您的目录中有 app.py 和 README.md 文件。
requirements.txt :创建一个 requirements.txt 文件(没有大写字母!)并将所有库添加到您在 python 脚本中使用的文件中。在我的 app.py 示例中,我只是导入了以下库:
import streamlit as st
因此,我在 requirements.txt 文件中添加了“ streamlit ”。Heroku 需要这个文件来知道它需要哪些库来运行您的应用程序。
setup.sh :下一个文件是 setup.sh 文件。这是一个 shell 文件,您需要在文件中添加以下 shell 命令。将下面的代码复制粘贴到文件中:
mkdir -p ~/.streamlit/echo "\
[server]\n\
headless = true\n\
port = $PORT\n\
enableCORS = false\n\
\n\
" > ~/.streamlit/config.toml
如果不添加此文件,当您将应用程序部署到 Heroku 时,将会收到一条错误消息。因此,请确保您创建这个应用程序,并按照我上面写的那样命名。没有大写字母!
Procfile :在您的目录中,创建一个文本文件,并将其命名为“Procfile”在该文件中,复制粘贴以下代码:
web: sh setup.sh && streamlit run app.py
“web”意味着它是一个 web 应用程序。一旦你在 Heroku 上运行这个应用程序,Procfile 就能很好地指定命令。我们指定上面创建的 shell 文件,然后调用 Streamlit 来运行 app.py。
一旦你创建了上面的文件,回顾这些步骤,确保你按照我上面的命名来命名这些文件。不用说,如果你的应用程序有更多的库,你需要在 requirements.txt 文件中列出它们。您要导入的任何库都需要在该文件中。
第三步:连接到 Heroku
一旦你创建了所有需要的文件,现在是时候设置你的应用程序,以便它可以与 Heroku 交互。
你要做的第一件事是确保你已经在你的机器上安装了 Heroku 并创建了一个免费帐户。请参见下面的链接创建一个帐户。
https://www.heroku.com/
根据文档,Heroku CLI 需要 Git。因此,如果你没有 Heroku,点击下面的链接,你可以安装它。
https://devcenter.heroku.com/articles/heroku-cli
当您在机器上安装了 Heroku 并创建了一个帐户后,就该从终端登录您的 Heroku 帐户了。在您的终端中运行以下命令:
heroku login
终端返回以下行:
' ' heroku:按任意键打开浏览器登录或按 q 退出:''
只需点击任意键,你的浏览器就会自动打开。您应该看到以下内容:

作者图片
接下来,单击登录并输入您的凭据。之后,您将看到以下内容:

作者图片
如上图所说,你可以关闭窗口,返回 CLI。下一步是创建 Heroku 应用程序。键入以下命令:
heroku create sample_app22a
在这里,我正在创建一个名为“sample_app22a”的应用程序。如果不指定名称,它将创建一个随机编号的应用程序。因此,我建议为你的应用程序选择一个名字。最后一步是将我们的文件推送到 Heroku。由于 Heroku 使用的是 git,所以命令行会很容易理解。键入以下内容:
git push heroku master
一旦你执行了上面的命令,Heroku 需要几秒钟来安装所有的库并设置你的应用。您将在输出中看到一个 URL,这将是您的应用程序的 URL。请见下文,以供参考。

作者图片
我们没有收到错误消息,现在是时候检查应用程序了。点击下面的链接,你可以在 Heroku 上看到我们的 Streamlit 应用。
好了,伙计们。现在你的应用程序开始工作了,你想把你的改变也推送到你的回购中。
git add -A
git commit -m "Type in a message"
git push
最终意见:
我建议等到收到 Streamlit 共享邀请,这样你就可以利用那个特性,而不是把它部署到 Heroku。我自己创建了一个应用程序,我将在接下来的几天里写一写。当使用 Heroku 的时候,渲染时间对于一些情节来说会稍微长一点。然而,如果你没有时间并且需要尽快部署,Heroku 也会完成这项工作。
希望本文能让您更好地理解如何将您的 Streamlit 应用程序部署到 Heroku。如果你对这个话题有任何问题或有任何反馈,请告诉我。如果你喜欢这篇文章,如果你能在任何社交媒体平台上分享它,我将非常感激。我将在下一篇文章中向您介绍我用 Streamlit 创建的 Covid19-Dashboard web 应用程序及其共享功能。敬请关注!直到下一个 time️ ✌️
https://www.navidma.com/
用 Python 构建应用程序的快速方法
原文:https://towardsdatascience.com/a-quick-way-to-build-applications-in-python-51d5ef477d88?source=collection_archive---------3-----------------------
编程;编排
用几行代码构建 MVP

HalGatewood.com在 Unsplash 上拍照
构建具有图形用户界面并执行复杂任务的 Python 应用程序可能看起来很困难。在最近发表的一篇文章中(见下面的链接),我提到了开始构建应用程序只需要 7 个 Python 库。
本文将用几行代码向您展示如何构建一个简单的翻译应用程序。我只使用两个 Python 库:requests 和 ipywidgets。
基础
我选择编写一个翻译器应用程序作为示例,向您展示用 Python 构建应用程序是多么容易。这个应用程序获得一个英语文本,并显示其西班牙语翻译。非常简单明了。
为此,我们需要应用程序中的两个部分。第一部分是执行翻译的后端,第二部分是与用户交互的前端或图形用户界面(GUI )(获取输入文本并显示输出文本)。
对于后端,我使用 Azure 翻译 API。如果你不熟悉 API(应用编程接口)的概念,我试着用一种毫不费力的方式来解释。API 是一种向服务提供商(通常是服务器)请求服务(例如翻译)的方式(即协议)。例如,您可以使用 Google Maps API 来获取两个位置之间的行驶距离。想象一下,如果 Google Maps API 不存在,那么您应该编写自己的代码来计算基于道路数据库的行驶距离。简单地说,API 阻止你重新发明轮子。有时候第三方 API 是免费的,但是大多数时候,你必须支付一点点费用(特别是如果你经常使用它们的话)。出于本文的目的,我们使用 Microsoft Azure Translator API,它是免费的,可以有限地使用。如果您没有 Azure 帐户,请阅读下一部分;否则可以跳过。
如何创建免费的 Azure 帐户
如果你没有 Azure 帐户,你可以注册一个免费的。按照以下链接中的说明进行操作。它很简单,让你可以免费使用数十种令人敬畏的 API 和服务。
https://docs.microsoft.com/en-us/learn/modules/create-an-azure-account/
创建一个免费的 Azure 账户后,你需要给你的账户添加 Azure Translator API。还是那句话,洒脱。您需要遵循以下链接中的步骤。
https://docs.microsoft.com/en-us/azure/cognitive-services/translator/translator-how-to-signup
如果你做的一切都正确,你必须有一个 API 密匙(即认证密匙)。密钥只是一个字符串,让你可以使用 Azure Translator API。您需要将它放入您的 Python 程序中(下一节)。记住,永远不要和任何人(包括你的用户)分享你的 API 密匙。
A)部分 API
现在你已经有了 Azure Translator 的 API 密匙(恭喜你!),让我们看看如何通过 Python 与 API 对话。
使用 API 的最流行的 Python 库之一是“请求”您可以使用安装它
pip install requests
或者
conda install -c anaconda requests
以下 Python 函数获取文本,并向 Azure Translator API 发送请求。
在继续之前,我必须告诉你一个重要的观点(尤其是对初学者)。事实是:
每个 API 都有一组请求服务的规则。使用谷歌地图 API 不同于 Azure Translator API。要使用 API,您必须阅读文档。
让我们回到我们的代码…
在代码中,您必须输入您的 API 键(参见API_KEY)并指定您的 API 区域(参见API_REGION)。requests.post向 Azure Translator API 发送 POST 请求。要发送请求,需要传递 URL 地址、参数、头和主体。URL 地址是一个 web 地址,Azure 服务器会持续监控该地址是否有任何即将到来的请求。一旦服务器看到您的请求,首先,它检查您在头部的凭证。如果您的凭证有效,它会查看您的参数以了解您的请求。例如,在这种情况下,我请求将 3.0 版的翻译程序从英语(即en)翻译成西班牙语(即es)。如果参数有效,那么 API 服务器获取主体(即本例中的 JSON 对象)并处理我的请求。最后,requests.post返回给我一个 JSON 对象,我将其命名为response。
你可以用一个简单的例子来检验这个函数。在代码末尾添加以下几行,然后运行它。
if __name__ == '__main__':
print(azure_translate('Hello world.'))
您必须看到这样的输出。
[{'translations': [{'text': 'Hola mundo.', 'to': 'es'}]}]
这是响应您的请求的 JSON(或 Python 字典)对象。如果仔细观察,您会看到翻译以及一些附加信息,如翻译的语言(即西班牙语或es)。
同样,这里所说的一切都是基于文档的,在阅读文档之后,您必须能够使用任何 API。如果你不读它,你永远不知道如何与一个 API 通信,以及应该用什么数据结构传递什么参数。
B)部分图形用户界面
现在您已经准备好了后端,是时候构建前端了。正如我之前提到的( link ),ipywidgets 和 Jupyter 笔记本是为浏览器构建简单用户界面的良好组合。
对于我的简单应用程序,我只需要用户界面中的一些元素。这些要素是:
- 显示应用程序名称的标题(装饰性功能)。
- 用于输入英文文本的文本区小工具。
- 点击后请求翻译的按钮。
- 打印西班牙语译文的空白区域。
Ipywidgets 有一组小部件来创建不同种类的用户界面和仪表板。对于这个应用程序,我将使用一个用于标题的HTML小部件、一个用于输入文本的Textarea小部件、一个用于请求翻译的Button小部件和一个用于打印结果的Output小部件。然后我用一个VBox小部件将它们垂直对齐放入一个容器中。
唯一的技巧是当用户点击翻译按钮时如何请求翻译服务。在点击事件时定义这个动作很简单。为此,我定义了一个函数,并将其传递给按钮的on_click方法。当用户点击翻译按钮时,指定的函数将运行并向 Azure Translator API 发送请求。简单吧?
下面的代码显示了应用程序的前端部分。
最终产品
现在,是时候把所有东西放在一个 Jupyter 笔记本文件中了。将这两部分放入 Jupyter 笔记本文件并保存(例如 Translator_API.ipynb)。

图片由作者提供。
由于 Ipywidgets 与 Chrome 配合得非常好,所以请检查您的默认浏览器是否是 Chrome。将默认浏览器设置为 Chrome 后,打开终端,通过 Voila 运行 Jupyter 笔记本代码。
voila Translator_API.ipynb
几秒钟后,您一定会看到您的应用程序在浏览器中自动打开。像我在这里做的那样测试一下。

图片由作者提供。
瞧啊。!!!!只需几个步骤,您就完成了简单的翻译应用程序。您可以通过使用 ipyvuetify 来改善您的 GUI 外观,这是一个充满现代外观小部件的库。你也可以使用 ngrok 和其他人分享你的 MVP(最小可行产品)(详情阅读下面的文章)。
摘要
用 Python 构建应用程序既简单又快速。您可以使用 API 来避免重新发明轮子并构建您的后端。您还可以使用简单的库,如 ipywidgets 或 ipyvuetify,为您的应用程序构建一个简单的 GUI。在本文中,我向您展示了如何用几行代码构建一个简单的翻译应用程序。同样的方法可以应用于更复杂的 MVP 应用程序。
在媒体和推特上关注我的最新消息。
机器学习数据质量监控快速入门
原文:https://towardsdatascience.com/a-quickstart-guideto-high-quality-data-4112ee8c498b?source=collection_archive---------11-----------------------
行业笔记

作者图片
数据正迅速成为我们当前技术的生命线,使公司能够为客户构建、衡量和改善新体验。今天,这不仅仅局限于尖端技术;相反,收集和利用数据在许多商业领域变得非常普遍。
现在,随着机器学习的兴起使新的客户体验成为可能,对数据的重新依赖正在出现。在 ML 驱动的系统的新环境中,构建和维护高质量的数据源变得前所未有的重要。今天的 ML 系统需要大量的数据才能良好运行,处理如此大量的数据给采用这些技术的公司带来了真正的问题。
在今天的实践中,一个模型的好坏往往取决于它所训练的数据。**数据质量在模型被训练后并没有停止变得重要,而是在模型被部署到生产中时仍然重要。**模型预测的质量在很大程度上取决于支持模型功能的数据源的质量。在这篇文章中,我将解释为什么您的团队应该密切关注您的数据质量以及对您的模型最终性能的影响。
我们所说的数据质量是指什么?
数据质量是一个宽泛的术语,可以涵盖数据中的各种问题。首先,让我们定义一下这篇文章中我们不会谈论的内容。在这篇文章中,我们不打算关注“缓慢出血”故障,例如数据随时间的逐渐漂移。如果你有兴趣了解这个极其重要的话题,你可以看看我们早期的一些作品,在这些作品中,我们围绕这个进行了更深入的。
那还剩下什么?嗯,这大体上留下了数据管道中硬故障的概念。为了更深入地挖掘,让我们打破分类数据流和数字数据流的概念。
分类数据
分类数据就像它听起来的那样,是一系列类别,比如某人拥有的宠物类型:狗、猫、鸟、猪?等等。
基数变化
首先,分类数据流可能出错的地方是类别分布的突然变化。更极端地说,假设你的模型预测为你的宠物用品店买哪种宠物食品,开始看到数据说人们现在只养猫。这可能会导致你的模型只购买猫粮,而你所有养狗的潜在客户将不得不去街上的宠物用品店。

作者图片
数据类型不匹配
除了分类数据中基数的突然变化之外,数据流还可能开始返回对该类别无效的值。很简单,这是您的数据流中的一个错误,并且违反了您在数据和模型之间建立的契约。发生这种情况有多种原因:您的数据源不可靠、您的数据处理代码出错、一些下游模式更改等等。在这一点上,无论从您的模型中产生什么都是未定义的行为,您需要确保保护自己免受类型不匹配的影响,就像在分类数据流中一样。
缺失数据
从业者遇到的一个令人难以置信的常见场景是丢失数据的问题。随着用于计算现代 ML 模型的大特征向量的数据流数量的增加,这些值中的一些将为零的可能性比以往任何时候都高。那么你能做些什么呢?
您肯定可以做的一件事是,在培训环境中举手放弃该行,或者在生产环境中在应用程序中抛出一个错误。虽然这将帮助您避免这个问题,但它可能不是最实用的。如果您有数百、数千或数万个数据流用于为您的模型计算一个特征向量,那么丢失其中一个数据流的可能性非常高!
接下来,我们将讨论如何填充这个缺失值,通常称为插补。对于分类数据,您可以选择历史上在您的数据中看到的最常见的类别,或者您可以使用现有的值来预测这个丢失的值可能是什么。
数据
数字数据流也是不言自明的。数字数据是用数字表示的数据,例如银行帐户中的金额,或者室外的温度(华氏或摄氏)。
超出范围违规
首先,数字数据流可能出错的地方是越界。例如,如果年龄是模型的一个输入,而您希望年龄在 0-120 之间,但突然收到一个 300 多的值,这将被视为超出范围。
类型不匹配
类型不匹配也会影响数字数据。对于一个特定的数据流,如果你期望得到一个温度读数,你可能会得到一个分类数据点,你必须适当地处理它。默认行为可能是将这个分类值转换为一个数字,尽管现在有效,但已经完全失去了它的语义,现在是数据中的一个错误,难以跟踪。
缺失数据
对于数字数据,您有更多的插补选项,例如对该特定值采用平均值、中值或其他一些分布度量。这个问题的解决方案的复杂性完全取决于您的应用程序场景,但是要知道这里没有完美的解决方案。

当今监控数据质量面临的挑战
既然我们已经对您可能遇到的数据质量问题有了更好的了解,现在让我们简单地探讨一下从业者在试图跟踪他们的数据质量时遇到的一些常见挑战。
在我们开始之前,重要的是要注意,这不同于数据可观测性的广义产品空间。数据可观测性工具主要关注于监控表和数据仓库的质量,而 ML 可观测性主要关注于监控模型的输入和输出。这些模型是一致发展的,特性被增加和改变,因此模型的数据质量监控必须能够与模型的模式一起发展。
需要监控的数据太多
对于许多当前的 ML 实践者来说,这些天来许多模型依赖大量的特性来执行它们的任务并不奇怪。根据统计学习理论的最新进展,一个经验法则表明,一个模型可以有效地学习训练集中每 100 个样本的大约一个特征。随着训练集的规模激增到数亿甚至数十亿,特征向量长度在数万或数十万的模型并不罕见。
这将我们引向从业者今天面临的一个主要挑战。为了支持这些难以置信的大特征向量,团队已经将越来越大的数据流投入到特征生成中。编写代码来监控每个数据流的质量从根本上来说是站不住脚的,而现实情况是,随着团队实验改进模型,这种数据模式将不可避免地经常发生变化。
最终,没有人愿意坐在那里手动配置阈值、基线,并为输入模型的每个数据流设置自定义数据监控系统。添加一个特性、删除一个特性、改变它的计算方式是很常见的,在 ML 开发循环中增加更多的工作只会减慢你和你的团队的速度。
现在怎么办?
既然我们已经了解了当前在监控和修复数据质量问题方面的一些挑战,我们能做些什么呢?首先,团队需要开始跟踪他们的数据质量如何影响他们模型的最终性能。
利用历史信息
最终,模型的性能才是我们所关心的,很有可能某些数据的质量比其他数据的质量更有价值。为了避免为每个数据流手动创建基线和阈值,团队需要从训练集或历史生产数据中查看数据的历史。

作者图片
一旦确定了这些历史分布,您的监控系统就可以更好地了解应该将数值流中的异常值视为什么,并在分类流严重偏离其历史分布时生成警报。从这些分布中,可以创建智能基线和阈值来平衡这些警报的“嘈杂”程度或可能触发的程度,从而为模型团队提供平衡风险与回报的能力。
除了为所有数据流设置自动警报系统之外,您的数据质量监控系统还应该允许您执行类型检查,以防止模型中的下游错误,并避免潜在的类型转换问题。
使用模型性能爬山
最后,通过跟踪您的模型的最终性能,您的监控系统还应允许您测试不同的数据插补方法,并为您提供这种新插补策略的性能影响。这使您确信您所做的选择会对模型的最终性能产生积极的影响。
随着机器学习的快速发展并进入我们最重要的产品和服务,支持这些体验的工具已经落后了。现代数据质量监控系统的这些核心特征将控制带回给了 ML 工程师,并消除了大量的猜测,不幸的是,这些猜测已经在生产机器学习的艺术中蔓延得非常深了
联系我们
如果这个博客引起了你的注意,并且你渴望了解更多关于机器学习可观察性和模型监控,请查看我们其他的博客和 ML 监控上的资源!如果您有兴趣加入一个有趣的 rockstar 工程团队,帮助模型成功生产,请随时联系我们,并在此处找到我们的空缺职位!
实时计算机图形学中的随机漫步
原文:https://towardsdatascience.com/a-random-walk-in-real-time-computer-graphics-6f4315537464?source=collection_archive---------43-----------------------
GLSL 的照明、纹理和位移映射

图一。一个遥远的场景(2021) | Sean Zhai |用 ShaderToy 创作
数学建模
计算机图形学从数学上定义形状开始。建模球体和立方体可以很容易地解决,但是定义真实世界的对象是具有挑战性的。著名的 3D 茶壶模型是由犹他大学的 Martin Newell 于 1975 年创建的,由于在计算机图形学的早期只有非常有限的模型可用,所以它在许多研究论文中被提及。
建模的另一种方法是用多边形网格来逼近形状;结合 3D 数字化仪和扫描仪,高分辨率多边形模型被广泛使用,但往往需要较长的渲染时间。1995 年第一部 CG 故事片玩具总动员上映,需要 80 万机时。
硬件的进步极大地改善了这种情况,尤其是现代的 GPU 使得实时计算机图形成为现实。但即使在今天,多边形模型仍然需要高度优化,游戏引擎经常使用低多边形模型。用数学定义形状仍然有明显优势。
用光描绘现实
光线被记录为图像中像素的颜色。现代图形处理器的奇迹使得实时制作惊人的图形成为可能,与图形处理器接口的语言是 OpenGL 着色语言(GLSL)。使用 GLSL,我们定义如何渲染像素的颜色;其余的是自动执行的,并且是并行完成的。
我们有完全的自由以任何方式设置场景,但是,遵循现实世界的原则是有帮助的。作为人类,我们的情感经常与和过去经历有相似之处的事物产生共鸣。甚至在构建一个抽象的构图时,我们往往需要一定的熟悉度。

图二。灯光的维度|翟的影像创作
通过观察,我们知道光在表面上的反射是由表面的法线决定的,漫射光对方向不敏感。使用 GLSL,一种简单有效的数字照明方式通常被配置为遵循 3 点工作室照明。根据经验,主光的亮度大约是补光的 10 倍。
在技术术语中,计算机图形照明或多或少取决于双向反射分布函数(BRDF),它描述了光线在撞击表面时如何表现的理论。
纹理、UV 贴图和长方体贴图

图三。特雷西·里斯秀 2008 |图片来源:commons.wikimedia.org
为了创造更真实的外观,最直接的想法是引入一张图片。如果我们想在数字世界中创作岩石时,有一张岩石的照片可以使用,这将使生活变得更容易。一个迫在眉睫的问题是,图像如何包裹物体的表面,当形状复杂时,这可能相当复杂。典型的解决方案在计算机图形学中称为 uv 映射,其中 u 和 v 是定义纹理的坐标。这非常类似于时装业使用织物的方式,这本身就是一门艺术,让不同表面交汇处的图案看起来很漂亮。
下图展示了一种叫做“盒子贴图”的技术。这是米奇·普拉特在皮克斯制作 RenderMan 时发明的。基本思想是从围绕物体的一个假想立方体投射纹理,纹理根据相对于 x、y 或 z 轴的方向混合。

图 4。纹理映射演示| Sean Zhai |使用 ShaderToy 创建
以下是 GLSL 代码中boxmap的功能,由 Inigo Quilez 在 ShaderToy 开发。
// "p" point being textured
// "n" surface normal at "p"
// "k" controls the sharpness of the blending in the transitions areas
// "s" texture sampler
vec4 boxmap( in sampler2D s, in vec3 p, in vec3 n, in float k )
{
// texture along x, y, z axis
vec4 x = texture( s, p.yz );
vec4 y = texture( s, p.zx );
vec4 z = texture( s, p.xy );
// blend factors
vec3 w = pow( abs(n), vec3(k) ); // blend and return
return (x*w.x + y*w.y + z*w.z) / (w.x + w.y + w.z);
}
噪音,逼真的触感
噪声和随机的区别在于,噪声不是随机的。噪声,即使看起来不规则,也需要产生可重复的结果。为了在计算机图形中有用,噪声函数需要创建平滑和渐进的变化。柏林噪音是为电影《创》(1982)开发的,以增加真实感。该算法具有突破性,因为它可以在没有大量数据集或昂贵计算的情况下创建丰富而细致的图像,并激发了其他噪声的发展,如 voronoi、worly 和单纯形噪声。计算机图形学再也不会回到没有噪声功能的日子了。
Perlin Noise 的发展使计算机图形艺术家能够更好地在电影行业的视觉效果中表现自然现象的复杂性。
— 1997 年奥斯卡颁奖典礼

图五。Bloodie 写了一首颂歌| Rebecca Xu,Sean Zhai(使用柏林噪音场创建的生成动画,在处理中编程)
分形噪声和自相似性
几乎所有自然界常见的模式都是粗糙的。它们有着极其不规则和支离破碎的方面——不仅比欧几里得的奇妙的古代几何学更加精细,而且复杂得多。几个世纪以来,测量粗糙度的想法只是一个空想。这是我毕生致力于的梦想之一。—伯努瓦·曼德尔布罗
分数布朗运动有时被描述为“随机行走过程”。Mandelbrot 揭示了 fBm 最重要的特征,即自相似性。为了说明这一点,Mandelbrot 展示了可以在自然界的许多地方观察到的自相似性,例如花椰菜的结构,其中植物的一部分与整体具有相同的结构。
图六。伯努瓦·曼德尔布罗的 TED 演讲
为了实时看到这一点,让我们在 GLSL 实现 fBM。下面是一个例子。复杂性是通过添加用于操纵采样纹理的噪声迭代而逐渐建立的;每次采样频率增加一倍,其幅度减小一半。通过这样做,自相似性得以保持。
// code by ig at shadertoy.comfloat noise1f( sampler2D tex, in vec2 x )
{
return texture(tex,(x+0.5)/64.0).x;
}float fbm1f( sampler2D tex, in vec2 x )
{
float f = 0.0;
f += 0.5000*noise1f(tex,x); x*=2.01;
f += 0.2500*noise1f(tex,x); x*=2.01;
f += 0.1250*noise1f(tex,x); x*=2.01;
f += 0.0625*noise1f(tex,x);
f = 2.0*f-0.9375;
return f;
}
对于偶然发现 ShaderToy 的人来说,随机改变着色器中的参数以获得不同的外观是很有吸引力的,但如果不理解基本原理,可能很难掌握构造着色器的艺术,并且当出现伪像时会令人沮丧。
位移映射
噪波也可以用来改变对象的实际形状,这通常称为置换贴图。将 fBm 噪波作为位移贴图添加到图 4 中,我创建了图 1 的标题图像。源代码可以在下面找到。
形象很简单,希望还是营造出一种偏僻大气的感觉。我想分享一些笔记,而使这一点。
- 构图:一般你的主要对象不要在死点;相机目标位置
ta在 x 轴上轻微移动。 - “建筑结构”的建模是用两个球体连接在一起完成的,减去一个球体来创建凹面形状(可以很容易地在图 4 中看到)。)
- 触摸位移图可以完全改变图像的情绪(比较图 4)。和图 1。).
你可以访问 ShaderToy 查看实时版本。
https://www.shadertoy.com/view/flBGzK
收场白
有可能你做过在画布上画线的图形编程,基本上可以解释为“画家的模型”。GLSL 提供的是更强大的东西。可以实时体验,可以印象更深刻。尝试使用 ShaderToy 或另一个 GLSL 合成工具。干杯!
在 R 中提高数据辩论技巧的一个非常简单的方法
原文:https://towardsdatascience.com/a-really-easy-way-to-improve-your-data-wrangling-skills-in-r-4a418a5315fb?source=collection_archive---------22-----------------------

照片由布雷特·乔丹在 Unsplash 拍摄
当我找工作时,我有很多空闲时间。加上 COVID,嗯,我有很多空闲时间。有一天,我对自己说,鉴于 dplyr 1.0.0+ 相对较新的更新和我个人的理念,你可以总是练习基本技能,我可以用dplyr进行一点练习。我的第一个想法是谷歌“dplyr 练习题”,但如果你现在这么做,你会发现一堆教程网站都有非常基本的dplyr问题。对于 R 的中级和高级用户来说,这可能不是我们想要的。然后,我接下来的想法是“做一个个人项目”。无数的文章和人们都推荐把它作为学习和练习 r 的一种方式。是的,我喜欢个人项目,但有时你也在寻找那种快速的锻炼,你知道吗?有时候,你并不真的想花很长时间去构思一个项目,你只是想快速地做一些演示。
但是后来,我突然想到。哪里有一个地方可以让人们发布对他们来说显然不直观的问题,而其他人可以发布解决方案?
对,那个地方就是栈溢出。
我创建了一个帐户(我一直使用堆栈溢出来查找自己问题的答案,但我从未想过创建一个帐户来回答别人的问题),并设置我的过滤器来选择性地查看dplyr问题:
第一步

第二步

在“以下标记”中键入 r 和 dplyr
游戏计划
现在我已经确定了这个资源,我如何以及你如何开始使用它?
把它当成一次锻炼。
告诉自己每天至少尝试解决 5 个问题。当你点击“应用过滤器”按钮时,你会得到一个问题列表。你可以通过“最新”来查找可能还没有答案的问题。请记住,这些问题会有一系列的困难。通常情况下,你会遇到来自 R 新手的问题,所以这些问题会有相当简单的解决方案。
如果您想要带有“答案”的问题,将“过滤依据”框留空。如果你想解决没有公开答案的问题,按“没有答案”过滤。
注意,不一定要贴你的答案;你可以试着用你自己的 RStudio 编码出答案。
投资
也就是说,你可以试着公开发布你的解决方案。栈溢出有一个游戏的很多方面;您可以获得声望点数和徽章。如果你真的在努力提高你的技能,你可以张贴你的答案,如果它是好的,它可能会被接受为解决方案或被社区投票。你也可以通过过滤有赏金的问题来尝试解决更难的问题(如果你对赏金问题的回答被接受,你可以获得大量信誉点)。
最后,我认为这是一个很好的练习资源,如果你想快速练习,不需要花太多时间。您正在练习解决一个小问题的数据争论技巧。有时候你会想出一个好的解决方案;有时候其他人会想出更好的办法。无论哪种方式,你都可以从全球 R 社区学习。最后但同样重要的是,你要回馈社会。你在帮助那些可能刚刚开始学习 R 的人;记住你曾经是那些人的一员!
让我们用 AI 做饭:如何使用 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 编写食谱推荐机器人
原文:https://towardsdatascience.com/a-recommendation-engine-that-proposes-recipes-after-taking-photos-of-your-ingredients-de2d314f565d?source=collection_archive---------20-----------------------
动手教程,菜谱电报机器人
用 python 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 API 和深度学习模型编码的推荐引擎。给你的冰箱拍张照,等待最佳食谱。

Icons8 团队在 Unsplash 上的照片
为什么你应该读这篇文章:
如果你对计算技术感兴趣,并且想学习更多关于识别引擎、推荐引擎和 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 API 的知识,这篇文章是为你准备的。
我们将一步一步地一起构建一个迷你应用程序,它可以根据您厨房中现有的食材提供定制的食谱。为了更进一步,我们将添加一个识别引擎,它可以根据你发送给机器人的图像识别水果和蔬菜。你可能会问,为什么?仅仅是因为好玩又轻松!
我们还将使用 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 API,因为它提供了一个为小项目创建工作前端的绝佳机会。除此之外,如果您将 Python 用于您的后端活动,您可以使用多个包装器来利用它们的 API 的许多不同选项。我还发现,如果你想开发简单的物联网解决方案,这是一个方便的工具。
我希望这篇文章能启发你去做其他很酷的项目。如果您有任何问题或想分享您的项目,不要犹豫,直接联系我或留下评论。
我们将如何进行?
- 应用程序概述。
- 在本地机器上部署。
- 一点机器学习的代码。
- 结论。
应用程序快速浏览:
有时一张图片(或者,在这种情况下,一段视频)胜过千言万语。这就是为什么这个 GIF 在这里向你展示这个机器人的主要功能和它是如何工作的。
根据你厨房里的食材,机器人可以从各种烹饪风格(意大利、希腊、日本等)中选择一套食谱。).
作者 Gif
自己试试吧!在您的本地机器上部署 bot 以充分享受这种体验。玩得开心!
提示:我用 gfycat 创建了 GIF。他们提出了奇妙的功能和可能性。不要犹豫,点击 这里 试试吧!
在您的本地计算机上尝试(一步一步):
首先,你需要用 丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 应用程序创建一个机器人。然后,您将能够在本地计算机上部署应用程序。
生成电报机器人:
你可以快速浏览一下这个帖子来创建一个带有令牌的电报机器人!然后在创建你的机器人后,你就可以访问它的令牌了!这个你自己留着吧。因为如果有人发现它,他们可以对你的机器人做任何他们想做的事情(安全总比抱歉好)。
在本地部署它:
如果你熟悉 GitHub,你会在下面的 GitHub 页面上看到关于机器人部署的所有信息。
如果您在本地机器上安装了 Docker,只需在终端上运行下面的命令行:
docker run -e token=Your_token tylerdurden1291/丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-bot-recipes:mainimage
机器学习:
我们现在将更深入地研究这个项目,我将它分成了四个部分:
- 我们如何使用 Doc2Vec 模型和预测菜肴的分类器进行推荐?
- 基于深度学习的图像识别。
- 为前端设置电报机器人。
- 得益于 docker 的快速部署。
如何做推荐?
在过去的六年中,最有用的技术之一是自然语言处理(NLP)。在这个领域,研究人员的目标是通过不同的过程来打破语言的深层结构和它们的秘密。让我们用三个要点来总结一下。
- 标记化:这个过程将输入文本转换成机器可以理解的格式。总而言之,文本被转换成一系列由数字组成的向量。
- 特征工程/建模:由于文本现在是机器可以理解的,我们现在可以提取一些知识来执行某项任务。我们称之为特征工程,因为我们从输入中提取特征。它也被称为建模,因为这些特征提取器通常是统计模型。
- **任务:**在 NLP 中,很多任务都可以由一个模型来执行。从简单的任务,如分类,到更复杂的任务,如问答。在我们的小项目中,我们将为菜肴预测执行分类任务,并进行相似性匹配以找到最佳食谱。
建议类型:
当我们讨论建议时,主题是相当模糊的。根据目的不同,存在许多不同类型的建议。例如,网飞或亚马逊会根据你正在观看的内容和其他客户之间的相似性进行推荐。在我们的例子中,我们希望根据您已经拥有的食材和食谱中的项目列表之间的相似性来做出推荐。
一个好的建议是一套食谱,分享你已经拥有的和食谱中的相同成分。基于规则的解决方案是可能的,但是它将产生相当大的编程开销。因此,我选择使用著名的 Doc2Vec 模型。是 Word2Vec 在句子层面的概括。因此,我们可以计算句子相似度,而不是单词相似度。
为了增强用户体验,您可以在对数百万个食谱训练您的 Doc2Vec 之前添加一个模型。 Uber Eats 和 Deliveroo 提议在点菜前选择菜式。使用正确的数据集和简单的模型,我们可以快速实现相同的功能。经过深入研究,我发现了一个包含食物类型的食谱数据集(例如:意大利、墨西哥、法国、中国等。).因此,在第一步中,使用逻辑回归分类器在完整的食谱数据集上预测食物的种类。在第二步中,针对每种类型的烹饪训练 Doc2vec。有了这个管道,我们可以确信我们的模型将只为特定的食物类型提供食谱!
如果您想了解关于该模型的更多信息,我强烈建议您查看以下链接:
- doc2vec
- tf-idf
- 逻辑回归
数据集:
对于项目的这一部分,我们需要两个不同的数据源。
- 第一个数据集使用每个配方的配料集合来训练 Doc2Vec 模型。想到的数据集是 recipes 1M ,但是在写这篇文章的时候他们的网站已经关闭了。但是我发现了另一个非常相似的,叫做食谱盒。
- 第二个数据集用于训练模型,根据一组配料预测菜肴的类型。多亏了 Kaggle 的订阅者,食谱配料数据集正在正确地完成这项工作。
一点编码:
在符号化过程中,我使用了一个简单的管道,将文本符号化并寻找单词的词根。被称为停用词的无用词也被删除以减少噪音。
作者代码
我使用特征工程仅仅是为了预测菜肴类型。TF-IDF 在逻辑回归模型预测菜肴种类之前嵌入输入文本。
作者代码
为了计算食谱中的配料之间的相似性,我们将使用著名的 Doc2Vec 模型。这个模型只需要一个记号化的过程,因为它本身就是在提取特征!注意, Gensim 库允许我们用一个简单的命令预测未知文本的相似性匹配。
作者代码
再进一步:加入基于深度学习的图像识别。
图像识别现在是机器学习中一项众所周知的任务,深度学习模型已经被证明是这项任务的最佳和最可靠的。但是深度学习框架需要巨大的计算能力。因此,迁移学习技术通过使用预先训练的模型而不是从头开始训练新的模型来节省大量时间和开销。
数据集:
存在许多用于图像识别的数据集。我选择了以下数据集,为食物识别量身定制: GroceryStoreDataset 有很多不同环境下多角度拍摄的水果蔬菜照片。这使得它成为目前最好的可用数据集。
一点编码:
由于我正在使用深度学习模型,我需要 GPU 资源,感谢谷歌,我们可以通过 Colab 笔记本轻松访问。因此,我分享了我用来训练 Keras 上的预训练模型的 Resnet 模型的笔记本。
https://drive.google.com/file/d/1A4g5NcBPVu6wpIUgKa4ZuqNoZiO01Q5q/view?usp=sharing
当模型完全训练好时,这里是在应用程序中对单个图像进行预测的代码。
作者代码
如何为前端设置电报机器人:
存在许多 API,知道如何使用它们是一项有用的技能。丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 多年来一直在开发其 API,并且做得非常出色!这个 API 最酷的一点是它的包装器数量,这将简化您的生活。在这个项目中,我使用了 python-丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-bot 包,它被证明是可用的包装器中最容易使用的一个。
编码:
要启动这个包装器,首先,您需要使用 pip 命令安装它。
pip install python-丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-bot
在查看我的代码之前,我强烈建议您专注于理解 ConversationHandler 模式。在他们的示例文件夹中,您将找到可以轻松在本地实现的可用代码和模式。将 python 文件与其对话模式进行比较,而不仅仅是阅读代码行,节省了我几个小时的时间。
如你所见,第一层处理主要按钮和发送给机器人的文本或照片。第二层用于两种不同的交互:
- 当一个图像被发送到机器人,它被处理,它被传递到一个附加函数,一个回调函数能够检索用户触摸的项目。
- 当你点击获取食谱按钮时,情况也是如此。在文章开头的 GIF 中可以看到,点击这个按钮后会要求你选择想要烹饪的美食。需要第二个回调函数来检索用户选择的信息。
注意每个最终层是如何返回主菜单的!
作者代码
如何用 D ocker: 快速部署 App
Docker 是一个你可能已经听说过的开源软件。它使用其操作系统创建容器,以避免在其他机器上部署解决方案时出现软件依赖性问题。我鼓励你学习 Docker,因为如果你从事计算工程,你将会使用它或者其他类似的软件。对于这个项目,我创建了一个镜像,如果你安装了 docker 而不是使用 GitHub,你可以在本地机器上运行这个镜像。如果你是 Docker 新手,我鼓励你去看下面的视频!
命令:
我不会给你一个 docker 课程,并鼓励你去理解什么是容器。但你唯一需要知道的是以下内容。运行容器意味着在你的设备上运行一个新的操作系统。为了构建这个新的操作系统,docker 使用了映像。这篇文章将介绍我是如何为这个项目创建图像以及如何运行它的。
Dockerfile 是您运行以生成图像的文件。因此,它由一个源映像(通常是 Linux OS 容器)和一些命令组成。这些命令将允许我们下载包,设置环境变量,并定义容器启动时将运行的命令。
Dockerfile 文件:
# Base by image from python3.7 source image on amd64
FROM python:3.7# Create a argument variable to call when the image is started
ENV token token_init# copy the requirement within the image before importing the whole code and pip install everything
COPY requirements.txt .
RUN pip3 install --no-cache-dir -r requirements.txt# Import the whole code in the image and change the working directory accordingly
COPY . /app
WORKDIR /app# Run the setup to import models and datasets
RUN bash setup.sh# Create models and the database
RUN python3.7 train_and_populate_recommendation_db.py# Define the command to run when the container will be started
CMD ["sh", "-c", "python3.7 app.py ${token}" ]
当然,您不需要在本地运行它,映像可以在 Docker Hub 上获得,您可以轻松地调用它,只需一个命令就可以运行项目。首先,在您的本地 AMD(例如,每个个人桌面都是 AMD,但 raspberry pi 不是)机器上下载 docker,并使用您的 bot 令牌运行以下命令:
docker run -e token=Your_token_gen_by_Fatherbot tylerdurden1291/丨t丨e丨l丨e丨g丨r丨a丨m丨s丨-bot-recipes:mainimage
结论:
这篇文章的动机是分享的想法。开源项目是避免伟大创意产生过程中瓶颈的最佳方式。因此,我决定分享我的代码,并感谢 Medium,在这篇文章中用我自己的话介绍这个项目。
简单来说,丨t丨e丨l丨e丨g丨r丨a丨m丨s丨 API 可以帮助你快速开发一些有用的 app,docker 会帮助你分享和部署你的解决方案,Python 有令人印象深刻的快速开发功能!
如果你喜欢这篇文章,别忘了鼓掌,如果你认为它很有趣,你可以查看我的 GitHub 页面。
关于数据科学和机器学习学位的红丸观点
原文:https://towardsdatascience.com/a-red-pill-perspective-on-degrees-for-data-science-machine-learning-262b211d5292?source=collection_archive---------17-----------------------
意见
真相会让你自由

蒂姆·约翰逊在 Unsplash 上拍照
做机器学习需要学位吗?我已经很久没有在这场讨论中发表意见了。一个原因是因为我没有学位。见鬼,我就要拿到会计和商业文凭了——我迟到了 5 年,但迟到总比没有好,对吗?LOL。我把 2 便士藏在心里的另一个原因是,我无法有效地解释为什么我没有去。如果你当时问我,我的回答会是——“我没有去,因为我是环境的受害者。去了也没意义”。就这么简单。
现在,我已经设法把我的想法放在一起,用经验武装自己。如果我从未有过这样的经历,我有什么资格对教育是否重要发表意见?嗯,我每天都在做机器学习工作,没有学位,更好的是,没有巨额债务——我保证我没有任何恶意。
红色药丸还是蓝色药丸?
GIF 来源:https://giphy . com/gifs/Keanu-reeves-the-matrix-wachowskis-1 cnsm 9 zkhf 0m 4
因为你一直在滚动,我猜你想要红色药丸。
数据科学或机器学习学位并不是该领域职业生涯的先决条件。
抱歉。
听着,我明白。这件事很敏感也很主观。对于过去 3/4 年熬夜完成论文的读者来说,这当然是难以下咽的苦果。
我喜欢《百万富翁浪子》的作者 MJ DeMarco 对这个问题的描述。他认为,大学学位是由他所谓的剧本创造的超现实——我们可以认为剧本是卖给我们来维持秩序的虚假现实。
“‘大学学位’超现实是双管齐下的。首先,这是一种思想,即智力和财富需要大学学位,而不考虑成本,更重要的是,没有大学学位的生活永远会被就业不足和成绩不佳所强调”。
如果数据科学和机器学习像医学领域一样受到高度监管,那么我会说“绝对如此!学位是必须的。”。我们离高度管制的领域越远,学位就变得越不必要。互联网使这一切成为可能。不相信我?在你的谷歌搜索栏中键入“数据科学课程或“机器学习课程,看看你有多少选项可供选择。
互联网时代给了我们前所未有的获取信息的机会。大多数东西都可以在网上掌握,方法是找到该领域的主题专家,研究他们的作品,然后运用你所学到的东西。
学位通常是其他人的象征。因此,获得一个学位是有一些声望和价值的,但是如果有人能做一份质量非常好的工作,你会在乎他是否有学位吗?你拥有的汽车,你检查过组装它的人是否有学位吗?你脚上的鞋子,你检查过制造商是否有学位吗?
“大学超现实的第二个方面是,花一大笔钱在你热爱的任何领域获得学位,可以保证毕业后有一份工作等着你——而且你的学位让你有资格获得它。”— Mj DeMarco,无脚本
我的观点是,人们得到他们想要的东西。如果一家公司希望你加入他们的数据团队,因为他们已经看到了你的开源贡献,在这一点上你的学位是没有意义的。他们要行动了!
最后的想法
奇怪的是,我并不反对学位。我认为人们应该去做,如果那是他们想做的。我反对的是与学位相联系的错误观念,比如人们一旦完成任期就会有权利感。我不怪他们,他们被卖给了一个梦想——一个超现实,就像 MJ 德马科会说的那样。长话短说,学位并不能保证工作。
感谢阅读!
如果你喜欢这篇文章,请通过订阅我的免费 每周简讯与我联系。不要错过我写的关于人工智能、数据科学和自由职业的帖子。
相关文章
https://medium.com/analytics-vidhya/courses-to-learn-data-science-in-2021-a52e64344e5c
对“张量流悲伤故事”的回复
原文:https://towardsdatascience.com/a-reply-to-tensorflow-sad-story-b4b52ea59bc3?source=collection_archive---------18-----------------------

马库斯·斯皮斯克在 Unsplash 上的照片
T 今天我读了 Zahar Chikishev 的《TensorFlow Sad Story 》,虽然我同意他的大部分观点,但我觉得这对 TensorFlow 本身有点不公平,因为它没有试图掩盖或理解 TensorFlow 为什么是现在这个样子,或者谷歌究竟为什么要做某些事情。自从 2019 年 9 月 TensorFlow 问世以来,我一直是 TensorFlow 的用户,并且感受到了 Zahar 在他的文章中描述的许多相同的痛苦,我开始起草一份回复。然而,正如你从这篇文章中看到的,我的评论失去了控制,所以我决定把它变成一个独立的部分。
需要澄清的是,我并不为 Google 或 TensorFlow 工作,但是,作为一名用户和系统工程师,我也许能够解释为什么 TF 是现在这个样子(我并不同意它的大部分内容,但是我猜它提供了一些视角)。
接下来,我或多或少地按照最初帖子的顺序讨论了每个主题,你可以在这里阅读:
https://medium.com/geekculture/tensorflow-sad-story-cf8e062d84ba
易于安装
事实上,安装 TensorFlow,特别是对于 Python 生态系统的新手来说,可能是一件痛苦的事情。我想谷歌不介意这一点有几个原因:
- 它免费提供实验室,这样你就可以从那里开始
- Anaconda 已经为您预打包了 TensorFlow 及其依赖项,如果您愿意自己安装的话
- 大多数(如果不是全部的话)云提供商将它与他们的 GPU 实例一起预打包
- 坦率地说,到目前为止,这种方法很有效。
此外,很大一部分痛苦来自于 Nvidia 无法发布一个能够跨不同小版本远程兼容的 CUDA SDK。当试图手动安装 TensorFlow 时,大多数人会犯的错误是找到编译 TensorFlow 二进制文件所依据的 CUDA 和 cuDNN 的确切版本。
插件包:
对于那些不知道的人来说,TensorFlow 项目有几个兄弟姐妹,即插件、概率、图形和甘,以及一些不太为人知的,如相似性、代理、和其他。您可以通过浏览 TensorFlow 的 GitHub 页面获得完整列表。
在最初的帖子中,作者抱怨插件包与主包是分开的,这似乎是不必要的,因为他总是两个都安装。虽然我发现了一个微小的麻烦——仅仅是 requirements.txt 文件中让 pip 吞食的另一行,但这是用户不总是理解公司基本原理的一个很好的例子。
TensorFlow 是一个庞然大物软件。它是巨大的,跨越数百万行代码、几种语言、几种设备等。此外,使用 TensorFlow 的所有产品的总和可能接近(或接近)数十亿美元。如果谷歌搞砸了,反弹将是巨大的。因此,将一个项目分割成更易管理的部分是有意义的,比如一个包含所有基本内容的核心包和几个更集中的项目。
在较小的子项目的一般好处中,我强调:(1)您可以按照自己的步调推进每个子项目,(2)它限制了糟糕的发布的影响,以及(3)它简化了对人们正在使用什么的跟踪。
然而,最重要的是能够包含你不确定是否会被主流采用的东西。例如,考虑优化器。我猜 90%的人只知道亚当或者从来懒得去尝试别人。我在 Addons 包上数了超过十个小说优化器。这些应该添加到核心包中吗?这些年来测试和维护的成本是多少?
作为深度学习,一个由上个月的研究推动的领域,我们永远无法知道什么将经得起时间的考验。
渴望是一场骗局:
急切执行是 TensorFlow 2 最令人期待的特性之一。它将为 TensorFlow 带来 PyTorch 式的开发体验,摆脱该死的“会话”基本原理是,eager 可以调试,但速度较慢,而 deferred(图形模式)更快,因为它编译代码,但不能直接调试。谷歌解释说,当训练他们的模型时,人们会使用渴望调试和切换图形模式。
《张量流悲伤的故事》的作者引用了:
TensorFlow 2.0 急切地执行(就像 Python 通常做的那样),在 2.0 中,图形和会话应该感觉像实现细节。
对于计算密集型模型,比如在 GPU 上进行 ResNet50 训练,急切执行性能堪比
[*tf.function*](https://www.tensorflow.org/api_docs/python/tf/function)执行。但是对于计算量较少的模型来说,这种差距会变得更大,对于有大量小操作的模型来说,优化热代码路径还有很多工作要做。
第一个引用中提出的要点是大多数时候,您可以在两个之间无缝切换。第二段引文指出图模式受益于许多低成本操作和优化路径。这里的问题是,“多低的成本才算足够低?”。作者提到使用 ResNet-50 模型,并使用图形模式获得超过五倍的执行速度。如果我是猜测,批量太小,或者 GPU 是相当强大的。在这两种情况下,即使是 ResNet-50 操作也可以被称为低成本。
后来作者提到文档不鼓励使用渴望模式。的确,它本可以措辞得更好。默认情况下,急切模式是关闭的,因为这样更快。然而,如果你正在调试,你可以打开它,随心所欲地调试,然后关闭它。
具有讽刺意味的是,PyTorch 渴望模式默认情况下很快,而 TensorFlow 很慢。事实上,PyTorch 提供了一个混合解决方案,将 Torch 代码 JIT 化为图形模式,以提高性能。我猜如果 PyTorch 团队认为有必要实现一个 JIT 编译器…
数据 API:
我完全同意 tf.data.Dataset 很乱,我不会说我大部分时间都喜欢它。
这个 API 之所以这么烂,是因为它伪装的非常 TF1 化(而且所有 TF1 的东西都很烂)。data API 被设计成跟踪你的代码到 C调用中,所以当你用 Python 写代码时,它被跟踪到一个图形模式表示,并在 CPU C后端运行。
基本原理是性能:虽然 Python 苦于不可并行化(参见全局解释器锁 (GIL)),但 C++代码可以在所有可用的 CPU 线程上自由运行,因此可以更快地处理数据集,从而让 GPU 保持忙碌。缺点是生成的代码无法调试(毕竟是图形模式),运行任何外部 Python 代码都有极其痛苦的语法和性能。
只有图形模式是 TF1 的事情,希望它将成为整个图书馆的过去。与此同时, TensorFlow 2.5 增加了对 tf.data.Dataset 的实验性热切支持,这是一个开始。
API 复制:
TensorFlow 确实具有大量重复的功能。起初这很可怕,但实际上并不是问题。这些大部分都是帮助人们从 TF1 移植代码的遗留操作。如果谷歌放弃所有 1.x 的东西,他们永远不会让人们更新。
一个例子是 TF 1.x 如何拥有自己的操作(比如卷积),然后公开一个更高级的 API (slim)。在此之后,他们开始整合类似 Keras 的语法(tf.layers),这导致采用 Keras 本身作为其主要后端(tf.keras)。所以,现在,他们不得不处理所有这些遗留代码。希望他们会在 TensorFlow 3.0 版本中剥离大部分内容,或者更好的是, JAX 会取代生态系统。
在实践中,您只需关心 tf.nn 模块(类似于 PyTorch)和 tf.keras 包(高级 API ),它隐藏了许多样板文件和形状/尺寸计算。这两个 tf.keras 是主要的 API,而 tf.nn 用于实现定制的东西。
草率开发:
都是真的。句号。
特别是 ImageDataGenerator,它是 Keras 中最流行的数据扩充方法,在我看来,它一直是一个失去控制的样本代码,并开始在生产中使用。
最后一点,虽然我确实认为谷歌可以做得更好,但我知道 TensorFlow 是第一个为大规模模型设计的开源深度学习包之一,因此完全关注速度。在这方面,承认当时的情况是值得注意的。首先,神经网络几十年来一直是个笑话;它们速度慢,难以训练,并且不能提供有意义的好处。人工智能社区对决策树和支持向量机更感兴趣。
随着 CUDA 或在 GPU 上编程非图形的东西,事情开始发生变化。Nvidia 在 2007 年发布了第一个公开版本的 CUDA。当时,它主要是实验性的技术,有一些有趣的用例,但是使用它太痛苦了,而且工具很糟糕(现在仍然是,IMHO)。因此,它的大部分采用来自不同的来源和图形社区本身。直到 2012 年 9 月 30 日,CUDA(和神经网络)才有了改变人生的突破:AlexNet。
使用 CUDA 训练的卷积神经网络赢得 ImageNet 比赛并不是 AlexNet 的唯一壮举;它也成功做到了这一点,准确率提高了 10 个百分点以上。它引起了人们的注意。问题是:所有可用的神经网络工具充其量都是实验性和学术性的。此外,使用 CUDA 虽然并不完全新颖,但绝对不是主流。比赛开始了。
从 AlexNet 到 TensorFlow 首次公开发布,整整用了 3 年 1 个月 11 天。换句话说,对于谷歌大脑团队来说,要将他们在神经网络上的一切重新规划成某种东西,他们可以复制突破性的结果,做进一步的最先进的研究,并向公众开放。
在谷歌大脑团队的论文标题中快速搜索“深度”一词,我们从 2000 年到 2011 年总共有 3 篇论文。在那个时候,人们对“深度学习”或“深度神经网络”没有那么多兴趣。2012 年发布次数变为 3 次,2013 年变为 9 次,2014 年变为 10 次,2015 年 TensorFlow 发布时(准确的说是 2015 年 11 月 11 日)变为 20 次。
从那时起,没有一年没有一些突破性的变化或新奇。试图暴露深度学习的最新水平是一场猫捉老鼠的游戏。PyTorch 是在 TensorFlow 之后一年左右发布的,而变形金刚是在那之后一年提出的。在 2018 年,2019 年和 2020 年,我们分别有 GPT-1,-2 和-3,嘿,我们在 2021 年,GPT-4 的谣言正在流传!
我在这里的观点是,深度学习是一种不断发展的技术,因此,工具总是滞后的。因此,下一个将总是更闪亮,或者至少不会过时。
每个计算机架构师都是赌徒。谷歌工程师打赌性能将主导市场,并为此设计了 TensorFlow,赢得了最大的市场份额。脸书工程师赌上了灵活性,这在学术界获得了回报,但在行业采用方面却落后了。Keras 的创造者 Franç ois Chollet 将赌注押在了易用性上。
谁是对的?可能没有,因为世界正在转向大规模分布式的基于注意力的模型。谁会想到呢?上述工具都不适合这种情况。难怪会看到新的竞争者在函数式编程上下赌注。
尽管如此,我们看到 PyTorch 增加了图形模式,TensorFlow 拥有渴望的功能,并且两者今天都有类似 Keras 的 API。而且,都是互相学习。
长话短说,TensorFlow 有它自己的问题,但是,就像任何其他库一样,其他一些库将会出现并成为它应该成为的样子,其他一些库也会取代它。变化是软件的美妙之处。
有人知道 Java Servlets 吗?
暂时就这些了。如果您对本文有任何问题,请随时发表评论或与我联系。
如果你刚接触媒体,我强烈推荐订阅。对于数据和 IT 专业人士来说,中型文章是 StackOverflow 的完美搭档,对于新手来说更是如此。注册时请考虑使用我的会员链接。
感谢阅读:)
崛起的浪潮——尼日利亚的数据科学和机器学习
原文:https://towardsdatascience.com/a-rising-tide-data-science-and-machine-learning-in-nigeria-144d78aaacbd?source=collection_archive---------26-----------------------
利用 Kaggle 的年度调查,探索人们对 DS 话题越来越浓厚的兴趣

由大卫·罗蒂米在 Unsplash 上拍摄
** * 您可以在这里 ***** 找到该项目的代码https://www.kaggle.com/sootersaalu/a-rising-tide-ds-and-ml-in-nigeria
虽然软件开发仍然是该国的首选编程工作,但数据科学在尼日利亚的受欢迎程度近年来不断增加,因为许多尼日利亚人发现自己被其潜力所吸引,并在该领域获得了收益。
然而,仍有许多工作要做,因为数据科学研究中的现代工具和新改进明显未得到充分利用,这是由于缺乏知识或害怕风险,数据科学对尼日利亚市场的影响没有达到应有的广泛程度,也没有达到持续生成的数据的内在力量得到利用后的广泛程度。
然而,随着对科学感兴趣的个人和企业数量的增加,有很多值得期待的事情——五年谷歌数据科学趋势——迎合尼日利亚培训需求的计划数量也在增加。像尼日利亚数据科学、哈莫耶和 Utiva 这样的公司投入时间和资源来教育年轻和年老的尼日利亚人先进的分析、数据科学和人工智能工具和方法,预测涨潮是一个安全的赌注。
在这份报告中,我们将看看 Kaggle 的年度数据科学和机器学习调查,首先探索尼日利亚人的信息;他们的编程工具“堆栈”,他们在那里学习、消费内容,以及他们的公司在与世界其他地方的信息进行比较时对数据科学的利用。
见解
- 年轻人:我们的参与者大多不到 40 岁,尼日利亚的样本甚至更年轻。
- 学生来了!:我们学生比例高;学士大多数是硕士,尼日利亚的样本大多数是学士。
- **有教养,有教养!:总体而言,尼日利亚拥有超过 50%的学士学位,在传统的大学教育(学士、硕士、博士)方面,该国在世界上遥遥领先。
- 随着经验的增加,比例下降:我们的调查中有更多的编码和机器学习初学者,他们的线性下降是可视化的。
- 你上大学就是为了这个?!与世界其他地区相比,尼日利亚人从大学学习数据科学的比例要低得多。
- **数据科学期刊很无聊,Twitter 线程在哪里?:在我们的尼日利亚样本中,当消费数据科学内容时,期刊、Reddit 和播客最不受欢迎
- 谁是他们当中最伟大的短跑运动员?:对于部署/共享工具,更多的尼日利亚人更喜欢 Streamlit,而不是 Shiny 或 Plotly Dash,这种偏好在世界其他地方正好相反
- 机器学习方法利用不足:很大比例的尼日利亚企业根本不使用机器学习,很少有模型投入生产。
首先,我们看看从 2017 年到现在参与调查的人数

调查对象的趋势
尼日利亚人越来越多地出现在 Kaggle 调查中,就比例排名而言,他们在 2017 年占据第 39 位,而在 2020 年,他们占据第 8 位,其人数(476)本可以使他们在 2017 年获得第 6 位。
与整个世界其他地区相比,尼日利亚受访者的增长没有下降,因为尼日利亚人的数量在最近达到顶峰,是 2017 年尼日利亚参与者数量的 6 倍以上。
参与者的人口统计数据
为了更好地了解参与调查的不同个体,我们需要调查他们的相似性以及如何将他们作为一个整体来描述。
年龄组
在这里,我们绘制了分布图,以探索 Kaggle 调查中尼日利亚和世界其他地区的年龄组,以便于样本之间的比较和分析。

年龄分布比较
如果这项调查具有代表性的话,整个 Kaggle 的人口严重偏向年轻人,80%或更多的受访者年龄在 40 岁以下。
在尼日利亚的样本中尤其如此,因为他们中的大多数人年龄在 35 岁以下,22 岁至 24 岁的人比任何其他年龄组的人都多,这与世界其他地区不同,世界其他地区 25 岁至 29 岁年龄组的人比例最高。
退一步说,尼日利亚以其年轻的人口而闻名,2 亿多人口中超过 90%的人年龄在 55 岁以下
性别
增强受歧视性别的权能和消除性别差距是一项社会需求,所有善意的个人都应努力缓解这一需求。在这里,我们来看看调查中的性别分布。
📍 “非二进制”、“我更喜欢自我透露”和“我宁愿不说”由于比例较低被归入“其他” 📍

性别分布比较
正如可以预料或预测的那样,在 Kaggle 的调查中,男女比例严重失衡,男性在这一领域占据明显优势。这种优势可以说是“STEM”世界和更大的社会性别差距问题的代表。
由于尼日利亚男性的比例(82.4%)高于世界其他地区的男性(78.7%),这个问题再次出现,这在很大程度上证明了在科技计划、科技领域的女性、数据科学领域的女性(如这个数字探索者项目)以及针对尼日利亚女性和其他代表性不足的性别的类似项目中,女性的比例更低。
职业
除了年龄和性别变量之外,职业分析对于了解尼日利亚 Kaggle 人口和钻取平台上参与的细分市场也很重要。

职业比较
作为一个整体,相当大的“Kaggler”人口,确定为学生,这是 Kaggle 最大使用案例的一个秘密高峰,有许多学习计划建议开设 ka ggle 帐户并参与内容,但是,它也可能代表每年进入数据科学的年轻新人的数量,进一步的分析可能是有帮助的。
对于两个样本;在尼日利亚和世界其他地方,排名前六的职位依次是“学生”、“数据科学家”、“数据分析师”、“软件工程师”、“目前未就业”和“其他”(未列出的数据或非数据职位)。
Kaggle 可以被描述为一个数据科学社区,有数据集、竞赛、笔记本和面向数据科学的课程,因此,我们可以说,这里可视化的所有职业都对数据科学感兴趣或从中受益。考虑到这一点,尼日利亚软件工程师的比例为 5.7%,而世界其他地区的比例几乎是 10.3%的两倍,这可能表明尼日利亚软件工程师对数据科学的兴趣较低,或者数据任务之间的分歧较大,这值得以后关注。
尼日利亚数据科学家的比例较高,而其他列出的数据科学角色的比例较低,这代表了数据科学领域尚未解决劳动力和工作角色的最佳分配问题,让个人单独从事端到端数据科学项目。值得注意的是,本次调查中第二大部分尼日利亚人认为目前失业,这是环境或行业的一个令人担忧的迹象。
文化程度
要在数据科学领域取得成功,需要大量的领域知识,以及对需要什么工具、为什么需要它们以及它们的应用的理解。这个领域的大部分工作描述包括教育要求,大多数时候是计算机科学或统计领域的研究生学位。
虽然对于自学者来说,已经经历过该过程的个人的流行例子是一种鼓励,但数据科学领域仍然需要大量的教育基础。

截图【谷歌搜索尼日利亚数据科学职位列表】

截图【数据科学工作确实求职】

教育水平比较
尼日利亚受访者被认为拥有学士学位的比例较高,其次是硕士学位,而世界其他地区的情况正好相反,因为硕士学位毕业生是最大的群体。
总体而言,尼日利亚学士学位比例超过 50%,在传统大学教育(学士、硕士、博士)方面略胜世界其他国家。然而,当只考虑研究生学习时,这一领先优势就丧失了。
此外,高中毕业后没有接受过正规教育的人比例较低,这可能表明此类个人在数据科学领域学习/工作的机会低于平均水平,或者表明更有效的联邦学校计划,甚至是文化压力为什么尼日利亚人是美国受教育程度最高的(移民)群体
回到我们之前关于“学生”是 Kaggle 人群中很大一部分的观点。进一步将工作角色类别与各种教育水平联系起来将是有益的,以便深入学生群体,调查他们是哪个教育水平的学生,以及其他见解。

教育水平与职业(尼日利亚)
从绘制的热图中,我们可以看到,尼日利亚学士学位持有者的比例很高,在所有列出的工作岗位中,有 50%或更多的人拥有学士学位,只有少数例外。看看这些例外情况,DBA/数据库工程师职位只有一名尼日利亚受访者,但他们拥有硕士学位,数据工程师、研究科学家和统计学家职位的硕士学位都多于学士学位以及“其他”类别。
调查这一阴谋表明,尼日利亚学生 Kagglers 大多是在学校获得学士学位,让我们看看这是否是相同的世界其他地方。

教育水平与职业水平(世界其他地区)
如前所述,在世界其他地区,硕士学位的范围更广,他们在所有工作岗位上都占主导地位,除了失业者、软件工程师和学生,他们拥有更多学士学位,以及研究科学家角色,他们大多拥有博士学位(59%)。
比较两个地块和它们的人口,很大比例的研究科学家拥有研究生学位,突出了该角色的高等教育或技术基础。
有了对我们大多数 30 岁以下男性的更好了解,有很大比例的学士学位学生,尼日利亚样本,我们可以继续了解他们对数据科学的兴趣,他们使用了什么工具,他们在哪里学习和消费数据科学内容。
首先,我们探索他们在编码或编程和机器学习方面的经验。

多年的编码比较
由于两个样本都有相对年轻的个体,如前所述,这里的大多数 Kagglers 有 5 年或更少的编码经验就不足为奇了。
尼日利亚样本显示了从一年内开始编程的相对新手到拥有长达 10 年或更长经验的个人的几乎线性的递减过程,比较两个图,我们看到样本中没有尼日利亚个人拥有 20 年以上的经验。

ML 体验对比
机器学习是数据科学的重要组成部分,具有广泛的现实应用。对于我们的调查样本,很大比例的参与者在该主题上只有不到一年的经验。
虽然在百分比比例上存在差异,但在排名上几乎没有差异,因为再次出现了几乎线性的进展,从大部分初学者开始,随着经验的增加而减少。同样,尼日利亚的样本中没有 20 岁以上的人。
数据科学工具
随着对数据驱动的决策和创新需求的增长,数据科学和数据分析领域取得了很大进步。这推动了许多有助于丰富流程的工具的流行和重要性。然而,有很多个人偏好,公司也有使用哪些工具的标准。
在这里,我们来看看其中的一些偏好。

语言偏好比较
Python 的流行仍在继续,SQL 远远落后,这两种编程语言都是大多数数据相关角色使用的主要数据。JavaScript 排名可能指向我们的参与者,尤其是软件工程师的一些网络经验。在我们的世界其他地方的例子中,JavaScript 用户的比例较小,前三名分别是 Python、SQL 和 r。

ML 首选项比较
Scikit-learn 是我们在这两个示例中最受欢迎的框架。自 2007 年首次发布以来,机器学习库一直是数据科学中的一个重要组成部分,它具有初学者友好的方法和针对不同用例的广泛功能。谷歌的张量流在这两个样本中排名第二。比较这两个图,我们的第一个偏差是 Keras 的排名,Keras 经常被用作深度学习的张量流的伴侣。在尼日利亚的样本中,脸书的 PyTorch 并没有排在前五名。

工具首选项比较
尽管有一些软件包吹嘘自己的预测建模能力,但对于数据科学角色来说,用大多数语言编程在建模过程中提供了更大的灵活性。考虑到这一点,看到编程开发应用程序是两个样本中最受欢迎的分析工具就不足为奇了。像 Excel 这样的基本统计软件包通常是个人对“数据”的第一印象,在许多公司中,这些工具仍然是结构化数据的第一接触,随着数据空间的增长,该工具已经有了许多改进,使其能够保持竞争优势。
基于云的软件仍然需要一些改进来迎合大众的口味,尤其是在尼日利亚。尽管大数据的主要吸引力在于更容易管理,但它们满足了尚未普遍实现的需求。
数据科学学习和内容消费
在这里,我们调查参与者如何学习和获取数据科学领域的最新信息。

学习偏好比较
当查看数据科学学习发生的学习平台时,我们看到 Coursera 在两个样本中的比例都高于所有参与者,这可能是对他们在不同主题上的大型课程库以及免费“审核”大多数课程的能力的认可。Udemy 和 Kaggle learn 课程紧随其后,在两个示例中的顺序不同。
比较这两个图,在世界其他地区的样本中,大学课程在前 5 名的存在可能表明了以数据科学为目标的研究生课程的可用性,而尼日利亚的学位只能与统计、数学或计算机科学课程相邻。

内容偏好比较
我们的前 4 名排名在两个样本中相同,百分比相似,突出了这些平台在数据科学相关内容中的突出地位;Kaggle,Youtube,博客和 Twitter。
尼日利亚参与者发现关于数据科学的期刊出版物不如他们的同龄人有用,他们更喜欢时事通讯、Slack 社区和课程论坛。

公共平台首选项
数据科学空间可以是一个畅所欲言的空间,有许多“影响者”,但也有许多人每天分享他们的所作所为或所学。在这里,我们看一下公开分享工作以供他人查看的流行平台。
GitHub 和 Kaggle 在两个样本中都名列前三,GitHub 在编程/开发领域的突出地位对该领域的任何人来说都是显而易见的,因为即使没有允许高效团队合作的出色版本控制功能,它也是建立个人或开源项目组合的绝佳场所。
Kaggle 也是一个展示数据科学人才的好地方,因为公共竞赛或独特的数据集推动了大量人口寻求学习、竞争或建立他们的数据科学肌肉。有相当多的人,特别是在“世界其他地区”的样本中,由于工作限制、个人偏好或其他原因,没有公开分享他们的工作。
值得注意的是,更多的尼日利亚参与者选择了 Streamlit 而不是 Shiny 和 Plotly Dash 作为他们的网络应用程序 dashboarding 需求,这一决定在世界其他地方的样本中是相反的。此外,没有尼日利亚参与者使用过 NBViewer,这是一种将 Jupyter 笔记本(来自 GitHub 或其他地方)呈现为网页的工具,以便于共享或嵌入,这种用例与其他替代品相比有点小众,因为它在世界其他地方的百分比很低。
公司
在这里,我们看看我们的参与者工作过的公司的结构(这一部分是为那些在公司工作的人过滤的),以及他们如何整体上使用机器学习和数据科学。

公司规模比较
我们的大多数参与者,尤其是尼日利亚的参与者,都在员工不足 50 人的公司工作。
比较这些图,我们看到在世界其他地区样本中第二大比例是 10,000 或更多员工的最高选项。这要么是假设这样的公司比预期的更普遍,要么是样本的人口统计数据在很大程度上影响了比例。

DS 团队规模比较
公司数据科学团队规模的前两项让我们看到了公司对数据科学的利用程度。此处显示的大部分公司的数据科学团队少于 3 人,下一个百分比排名是完全没有专门的数据科学团队的公司。
这意味着该公司根本不使用机器学习或数据科学,或者任何数据科学任务都由不完全致力于执行数据科学的公司成员来完成或承担。
在下一个情节中我们会看到更多。

ML 利用率比较
更多的尼日利亚企业在看比例时不使用机器学习方法。对比图表,这两个样本将“探索机器学习方法”或“根本没有使用它们”作为“你的雇主将机器学习方法纳入他们的业务吗?”。
很少有公司已经在尼日利亚生产了模型,这凸显了机器学习方法的利用不足。

在 DS 服务上花费的金额
两个样本中没有为数据科学(机器学习或云服务)付费或从未付费的人的比例相似。尼日利亚的曲线是线性下降的,大多数人都是零美元,我们在尼日利亚样本中至少见过两次这种关系,两次都与参与者的经历有关,所以我们可以暂时假设这个问题是相关的。随着越来越多的人开始学习,还有改进的空间。
为了总结我们的分析,我们来看看一些与数据科学相关的任务,看看有多少人认为数据科学在他们的日常工作中很重要。

DS 工作任务比较
两个样本中的大多数人都执行数据分析来影响业务决策。在排名任务中,尼日利亚人发现建立数据基础设施比任何机器学习任务都重要。比较这两个图,为机器学习的新应用建立原型在尼日利亚人的排名中接近底部,而在世界其他地方的排名中则是第二。
在尼日利亚样本中,也有更高比例的人表示所列任务不是他们工作角色的重要组成部分,为了探究这一论断,有必要将我们的人口统计数据联系起来,尤其是关于参与者职业的数据。

工作任务及其职业的交叉表(尼日利亚)
可以看出,分析任务对于大多数与数据相关的工作角色都很重要。产品/项目经理工作对其他与数据相关的工作任务的需求最高。统计师和其他未列出的数据角色是表示列出的数据相关任务对他们的工作不重要的人中比例最高的一些,软件工程师是另一个值得注意的人。

工作任务及其职业的交叉选项卡(世界其他地区)
本例中的数据工程师和 DBA/数据库工程师花费了大量的时间来构建数据基础设施,这是他们工作的一个重要部分。
比较这两个图,认为所列任务在其工作中不重要的统计学家的比例明显减少,该样本中的大多数参与者通过分析来影响商业决策,我们可以假设,接受调查的尼日利亚统计学家没有多少理由致力于影响商业决策,这可能是由于在教育或研究部门的就业。
结论
尼日利亚人口众多,虽然这通常是一个弱点,但它也可以是一个优势,有了前人的启发,有了帮助年轻人和老年人提高与众多数据科学相关的数据分析师、商业分析师和数学家技能的计划的支持。随着对知识和经验的需求增加,Kaggle 平台上的人数将继续达到峰值。
对于数据科学方法的利用不足,“底线正在上升”,随着数据科学角色的更多空缺,需要了解它们给系统带来的影响,反之亦然,因为这是一个循环,将导致数据科学、其工具和原则的采用。
参考
- 尼日利亚数据科学的谷歌趋势,2015–2020。(2020).检索自https://trends.google.com/trends/explore?date=today%205-y&geo = NG&q = % 2Fm % 2f 0jt 3 _ Q3
- 中情局关于尼日利亚的实况报道。(2020).从 https://www.cia.gov/the-world-factbook/countries/nigeria/[取回](https://www.cia.gov/the-world-factbook/countries/nigeria/)
- 谷歌搜索尼日利亚数据科学家的工作。(2021).检索自网站。作者截图。
- 确实搜索数据科学家的工作。(2021).从https://www.indeed.com/jobs?q=Data%20Scientist&vjk = D2 B1 AFB 5d 21692 a 2中检索。作者截图。
- 关于尼日利亚移民的 Quora 问题。(2020).检索自https://www . quora . com/Why-Nigerians 是美国受教育程度最高的群体。
感谢阅读!
热情的新手掌握数据科学的路线图
原文:https://towardsdatascience.com/a-roadmap-for-the-passionate-novice-to-data-science-mastery-f5f6cdf004e9?source=collection_archive---------8-----------------------
数据科学学习指南
帮助您掌握数据科学的有用提示和资源

由 Lukas Medvedevas 在 Unsplash 拍摄
简介
有这么多的路要走,数据科学新手可能会很快不知所措。你可能会发现自己不知道下一步应该做什么,或者应该从哪里开始。
在这篇文章中,我整理了一个路线图,为你提供一些指导。这是基于我过去几年的精通之旅(顺便说一句,它永远不会结束!).我已经把我的方法系统化了,想和你分享,希望能帮你避开我遇到的坑坑洼洼。
这是给谁的?
这篇文章是写给任何热衷于进入数据科学并掌握这门学科的人的。然而,我想补充一点小小的警告。如果是非技术出身,那就要更加努力了。关于它没有两种方法。许多技术人员认为他们多年来学到的东西都是理所当然的。你没有这种奢侈,但即使如此,你成为大师也是非常可能的。
这条路并不容易,但是从来没有这样一个技术领域如此容易被大众接触到,有如此多的资源可供自学。你需要的只是激情、纪律和计划。
学习哲学
根据我的经验,一条高效的精通之路是采取五管齐下的方法。
阅读、倾听、构建和交流。
📚阅读:在合适的时间读合适的书是避免变得不知所措的关键。不要直接跳进深水区,而是从浅水区慢慢地漂进去。你将开始喜欢阅读数据科学书籍,并积累一个图书馆来帮助你完成任何项目。
👂听着:对于任何难以实现的目标,你都需要一些灵感。对我来说,我听过的许多播客确实启发了我。你不会从播客中获得大量的技术细节,但你会成为一名更全面的数据科学家。在了解该领域当前问题的同时,您自然会掌握数据科学术语。
🔧🔨打造:弄脏自己的手。做项目…很多项目。失败,从错误中学习,获得反馈,适应。如果不弄脏自己的手,你将一事无成,所以不要害怕陷入项目中。通过应用我的知识,我学到了最多。
📢**沟通:**良好的沟通能力通常是普通数据科学家与伟大数据科学家的区别。找到一个听众,交流你学到的东西,无论是通过写作还是演讲。交流新想法是强化新想法的一个好方法。它会迫使你用自己的话重新编码你所学的信息。如果你能正确对待这件事,你将会一举两得:建立你的品牌,同时学习新的概念。
👨👩👧👦网络:最终,你希望掌握这个领域,这样你就能找到工作;网络是关键。加入讨论组,创建 LinkedIn 个人资料,参加活动。把自己放在舒适区之外,掌握数据科学的道路需要你在途中遇到一些人。
路标
你应该把这篇文章作为有用的数据科学资源和材料的链接库。我花时间为你组织这些课程,帮助你从新手成长为大师。没有捷径可走,但只要投入并遵循系统,我保证你会成为大师。
请记住,数据科学在不断发展,因此学习永无止境。路线图系统会向你灌输你需要的学习习惯。
⭐Bonus 提示
1)采取并联方式,避免串联操作。这是我给你的最好的建议。不要等到你已经巩固了所有的理论之后才开始你的第一个项目,阅读和构建同时进行。像这样工作,你会大大减少你的学习时间。
2)计划你的时间——制定一个学习时间表,并坚持下去。每天几个小时应该足够了。

作者图片:您的数据科学路线图
🙈新手
您刚刚开始您的数据科学之旅,因此夯实基础非常重要。你需要数据科学工具的工作知识,对统计学、数学和机器学习的理解。
在线课程
这些课程将为您提供开始有效使用数据科学工具所需的知识。所有课程免费学习。
Python —掌握所有 Python 基础知识,包括函数、循环、数据结构等等。Python 是解决数据科学问题的最佳工具之一,你会很高兴花时间学习它。如果你是计算机编程新手,不用担心,Python 被设计得很容易掌握。耐心和对学习的承诺是所需要的。
课程链接此处
SQL —可以说是处理结构化数据的最重要的工具。有很多分析和机器学习是在结构化数据集上完成的。如果你想有所成就,就要熟悉 SQL。
此处课程链接
Pandas——python 中处理结构化数据的另一个非常有用的工具。你会想要掌握这个。
课程链接此处
机器学习 —在此获得如何识别和解决机器学习问题的基础知识。这门课程会给你足够的见识,让你开始解决自己的问题。
此处课程链接
介绍性文本
我提供了免费在线资源和(非免费)书籍的混合体。不要因为一些书的价格而却步,把它们看作是对自己的投资,从长远来看会有回报的。
**统计:**坚实的统计基础将大有裨益。
如果你想阅读一些浅显但内容丰富的统计资料,可以从大卫·斯皮格尔哈特的《统计的艺术》开始。
这本书充满了应用统计学专家的实用见解。作为一名专业统计学家,大卫很好地吸引了读者的注意力。
数据科学&机器学习:
安德烈·布尔科夫 的百页机器学习书,是初学者的必备读物。安德烈不仅涵盖了 ML 所需的基本数学,他还简明扼要地概述了许多重要的机器学习模型。
福斯特教务长汤姆·福西特的《商业数据科学》是一本很好的初学者指南,可以帮助你从数据科学的角度来看待商业问题。商业问题通常是混乱的,在这本书里你会得到处理这些问题的实用技巧。
凯茜·奥尼尔 的《数学毁灭的武器》是一本围绕人工智能和伦理提出重要考虑的优秀书籍。它将把你的视野从人工智能扩展到它影响的社区。
电脑编程:
😃所有这些资源都是免费的!
Select Star SQL —一本优秀的交互式书籍,适合绝对的初学者,让他们充分了解 SQL 的强大功能。作者假设很少或没有编码或计算机编程经验。
用 Python 自动化枯燥的东西,作者 Al Sweigart——不是数据科学专用的,但仍然有用。我不推荐从头到尾阅读这篇文章,但是,它可以作为你在项目中想要完成的任务的参考。
播客
莱克斯·弗里德曼的人工智能播客——莱克斯深入探讨人工智能更具哲学意义的领域,启发观众进行更深入的思考。他招待过很多不可思议的客人,比如埃隆·马斯克和吴恩达。
凯西·科济尔科夫——凯西是谷歌决策情报主管。她制作了一些技术性的短片,希望向听众灌输良好的数据科学基础知识和最佳实践。
❤️If 你知道任何其他伟大的播客,请留下评论!
🤔中级****
在这个阶段,你应该对自己的能力更有信心。你可能会对 SQL、Python 有所了解,并有坚实的理论基础。你可以开始阅读一些更高级的文本,接触一些项目,寻找数据科学社区。
Kaggle 比赛
Kaggle 是数据科学家最好的免费学习资源之一。他们举办比赛,让你测试你的技能,并建立在你的机器学习知识。
这些比赛的伟大之处在于反馈的能力。你被排在其他参赛者的前面,这给了你一个掌握水平的概念。你也开始建立一个工作组合,向潜在雇主展示你的热情和承诺。
这里有三个我认为你应该尝试的竞赛
《泰坦尼克号》(入门级)——你的任务是预测泰坦尼克号上乘客生还的可能性。这确实是一个入门级的分类任务,非常适合第一个项目。享受其中的乐趣,不要害怕发布你的结果,你总是可以提高你的分数!
高级回归技术(中级) —给你一组房屋数据,你的任务是建立一个机器学习模型来预测它们的销售价格。这不是一项容易的任务,但是在数据清理和高级回归技术方面有一些有价值的经验。
作为对你的进一步指导,我写了一个关于这个问题 的 解决方案,看看你是否能在我的基础上有所改进。
高级(数字识别器) —这是计算机视觉中的一个任务。你将需要建立一个数字识别器使用 MNIST 手写数字数据集。我发现这个任务真的帮助我理解了神经网络和深度学习的力量。
查看我在 计算机视觉 上做的项目,寻求指导。
中间文本
中间文本比介绍性文本更详细一些。他们专注于为您提供一个代码库,帮助您在完成项目时制定自己的解决方案。这些是你的数据科学手册。
用 Scikit-Learn,Keras & TensorFlow 作者 Aurelien Geron——我认为这无疑是你会买到的关于机器学习的最佳书籍之一。这里有许多实用的编码示例,将有助于您的数据科学项目和竞赛。帮你自己一个忙,买一本或者借一本这本书。
深度学习用 Python 作者 Francois Chollet——由深度学习用 Python 中的框架 Keras 的创建者编写。您将获得构建自己的深度学习解决方案所需的理论介绍和实践知识。
社区
在这个阶段,我强烈建议你找一个数据科学社区,并加入其中。加入一个社区是扩展你人际网络的好方法。
⚡️ 专业提示 : Meetup 是一种寻找数据科学社区和网络的绝佳方式。 开户,自己探索。
我定期参加 数据科学的艺术家 见面会 ups。这是一个由全球数据科学爱好者组成的令人惊叹的社区。你会发现来自不同背景的人有很多见解可以分享。
他们有休闲频道、播客、脸书和 LinkedIn 页面,你可以加入并关注。看看他们!
🎓主人****
如果你坚持下去,你至少会了解自己两件事。你比你最初认为的更有能力,而且你真的对数据科学充满热情。
精通不同于其他两个阶段。这是一个持续的过程,需要终生致力于学习。我将尝试给你一个旅程的起点。
✏️Write 博客帖子
学习的最好方法之一是通过教别人。一旦你有了一些项目,为什么不开始写作来帮助别人呢?它将通过要求你在一个主题上构建你的思想,并迫使你弥补知识缺乏的空白,来强化你的知识。
有许多媒体上的出版物你可以申请写作。不要害羞,把自己放出来。如果你真的很好,你甚至可以赚点钱。
⭐ 专业书籍
这里是我们要深入的地方,这些书不适合胆小的人(从这里开始只限爱好者)。
你在寻找精通,这些是你会回来反复参考的书。你将利用这些来寻找最困难问题的答案。
深度学习——伊恩·古德菲勒、约舒阿·本吉奥和亚伦·库维尔 。这是该领域一些顶级研究人员撰写的深度学习书籍中的精华。它有大量的数学证明来指导你理解任何深度学习算法下发生的事情。
这本书的伟大之处在于它可以在网上免费获得!
罗恩·科哈维、黛安·唐&徐亚 可信的在线控制实验——实验是数据科学中不被重视的一部分。在商业环境中设计可信的实验并不是一项容易培养的技能。在线实验的所有错综复杂之处都由作者在本书中提出,他们是该领域的世界领先专家。
💁可选** : 谷歌云平台上的数据科学——作者 Valliappa Lakshmanan 。云计算平台极大地简化了构建端到端机器学习解决方案的过程,将数据科学家和数据工程师的角色结合在一起。见我关于这个的文章**
通过掌握一些云技能,你或许可以为自己开辟一片天地。这是可选的,因为不是所有的组织都使用谷歌的云平台,有些使用微软 azure 或 AWS。无论您选择什么平台,了解云计算,它会一直存在。
💰自主项目
这就是你的创造力发挥的地方。在这个阶段,你应该开始看到别人可能看不到的数据机会。
例如,也许有一个工作过程可以通过机器学习来自动化。开始吧,做一个原型,然后把它推销给你的老板。自我指导项目的美妙之处在于,你从头到尾做每一件事,从构思问题到创造解决方案。支持自己,完成它!
🔥开源代码库
创建一个 GitHub 帐户,并开始在 GitHub 存储库中存储您的所有项目。GitHub 不仅有助于协作和版本控制,它还充当了您希望在后续项目中再次访问的代码的存储库。
⚡️:这是展示你作品组合的好方法。
在这里设置你的 GitHub 账户。
📈研究论文
这个领域是不断发展的,你可能会发现你的问题的解决方案在你读过的书中没有涉及到,因为你正在研究一些前沿的东西。这就是研究论文派上用场的地方。它们的生产速度通常比书籍快,并且涵盖了该领域的最新技术。这是真正为非常先进的。
这是一篇关于深度神经网络最优超参数调整的论文
最后的想法
就个人而言,我对这个领域研究得越多,我就越有激情。会有一些你感到不知所措的黑暗时期,但是记住那些是你成长最多的时期。
成为这个领域的一部分是如此值得的原因之一是它需要很多艰苦的工作。当你看到自己手中掌握着解决问题和设计解决方案的力量时,你会感激自己坚持了下来。
🌈记住这个路线图,回头看看这篇文章,给后面的人留下反馈和建议。我很想听听你从新手到高手的旅程进展如何。
❤️Thank 你!
**https://www.linkedin.com/in/john-adeojo/ **
最短路径算法自学指南,用 Python 实现
原文:https://towardsdatascience.com/a-self-learners-guide-to-shortest-path-algorithms-with-implementations-in-python-a084f60f43dc?source=collection_archive---------4-----------------------
入门
探索最基本的路径查找算法,它们为什么工作,以及它们在 Python 中的代码实现

由凯勒·琼斯在 Unsplash 上拍摄的照片。
在图论中,路径是连接两个节点的个不同的个顶点和边的序列。从一个源节点到目的节点可能有过多的路径。考虑下面的例子:

作者图片
考虑分量(0,1,2,3),我们有两种从 0 到 3 的可能方法。加上(3,4,5,6),我们就有 2×2 种可能的方法。再加上 8 个类似的组件,我们将有 2 个⁰ = 1024 条可能的路径。
就输入而言,路径的数量可以呈指数增长,但只有这些路径的子集使边权重之和最小,这些路径被称为最短路径。
正如我们已经证明的,生成所有路径的集合来寻找最短路径是非常浪费的。在这篇文章中,我将阐述最基本的最短路径算法。目的是确保不仅理解这些算法如何工作,而且理解它们为什么工作,同时避免复杂的数学证明,而是强调直觉,所有这些都将得到 python 代码的支持。
有 BFS 和 DFS 等基本图形算法的先验知识是加分的,但不是必需的。如果你知道什么是边和顶点,你可能知道得够多了。
贯穿本文,图 G(V,E)将被表示为一个邻接表,其中 V 表示图中的顶点集,E 表示图中的边集。

作者图片
例如,上图的邻接表表示如下:
一个如何用 python 表示邻接表的例子。注意这个图是无向的,因为每个边在列表中出现两次,例如:(A,B),(B,A)。
横向优先搜索
广度优先搜索(BFS)是一种基本的图遍历算法。它的工作方式是,对于每个节点,我们扫描它的所有相邻节点,并存储它们,以便我们可以在下一次迭代中依次扫描它们。

样本图上的 BFS 水平。图片作者。
履行
这个用 python 实现的,来自 MIT 6.006 ,虽然不是你在实践中可能会用到的,但它将帮助我们更好地理解 BFS 实际上在做什么,以及我们如何利用它来寻找最短路径。
在 while 循环的每次迭代中,我们通过遍历上一边界中每个节点的邻居来探索新的节点边界。
结果是我们最终将图分成几层,如上图所示,其中第一层由距离源至少一条边的节点组成,第二层由距离源至少两条边的节点组成,以此类推。在上面的代码中,距离数组 dist 为图中的每个节点保存这个值。
然后我们可以推测,在一个图上运行 BFS 后,我们可以找出用最少的边数从源头到达任何节点的方法。嗯,对我来说,这听起来像是图中任何顶点的最短路径!(不完全是…)。
除了距离数组,我们还维护了一个父指针数组(或者哈希表,如果您愿意的话),方便地命名为 parent,其中我们为每个发现的节点 v 指定了发现 v 的节点 u,即它的父节点。
我们使用这个数组来跟踪一个节点以前是否被访问过,但是这本身并不需要指定每个节点的父节点。我们这样做的真正原因是,能够回溯到源,并通过跟随那些父指针来构造最短路径。
BFS 的一个更实际的实现是使用一个队列来存储下一步要探索的节点。但是它抽象了层次的概念,使得理解 BFS 如何给我们提供最短路径变得更加困难。
执行时间
- 需要 v 次迭代来初始化父数组和距离数组
- while 循环只会运行 V 次。因为我们跟踪在父数组中看到的每个节点,所以我们只添加在下一次迭代中要扫描的未探索的节点。
- 在 while 循环的每一次迭代中,我们从队列中弹出一个节点,并扫描与它相邻的所有节点。这等于从 v 发出的边的数量。对图中的每个节点这样做的成本是 O(边的总数= E)。
因此,BFS 的运行时间为 O(V + E) 。
警告
如前所述,需要注意的是,就边的数量而言,这只是最短路径,也就是说,只有在图是未加权的或者所有权重都相同的情况下,这才算“真正的”最短路径。考虑以下示例,其中从 0 到 2 的最短路径不是边数最少的路径:

作者图片
那么我们该如何解决这个问题呢?
一种方法是将初始加权图转化为未加权图,同时保持问题陈述的规格完整,方法是将加权边分解为权重为 1 的边,并用假节点将它们链接在一起。

将先前的图形转换成未加权的图形。图片作者。
这个算法的运行时间是多少?
这仍然是 BFS,所以运行时间在边和顶点方面应该仍然是线性的。但是在我们的新图中有多少呢?
- 对于每条权重为 w 的边,我们用权重为 1 的 w 边来代替:E’= O(W * E)。 W 为最大边重。
- 对于权重为 w 的每条边,我们创建 w -1 个新顶点,而旧顶点还没有去任何地方。 V' = O(W*E + V)。
因此,运行时间是 O(V + W*E) ,在这里我们开始看到这种方法的警告:它取决于权重有多大。这对于权重较小的图也同样适用,但在实践中很少有用。我们更希望有一种算法能够快速找到最短路径,而不管权重值是多少。
为此,我们需要引入一项至关重要的技术,这是在图中寻找最短路径的关键。
边缘松弛

作者图片
放松边(u,v)在于简单地检查我们是否可以从源节点 s,找到通过(u,v) 到 v 的更短路径。
我们通过比较已知的旧路径到 v 的距离,与由到 u 的最短路径和边(u,v)形成的路径的距离来实现。
Relax(u, v, weight):
if d[v] > d[u] + weight(u, v):
d[v] = d[u] + weight(u, v)
parent[v] = u
如果我们确实发现我们可以通过边(u,v)更快地到达 v,那么我们更新以下值:
- d[v]:从源 s 到节点 v 的距离。我们用刚刚与之比较的新值来更新它。
- parent[v],v 的直接父,现在是 u。因为,像在 BFS,我们通过跟随父指针找到路径,这类似于更新到 v 的最短路径
最短路径算法模板
使用我们上面学到的技术,我们可以编写一个简单的骨架算法来计算加权图中的最短路径,它的运行时间不依赖于权重的值。
- 从图形中选择边(u,v)。
- 放松边缘(u,v)。
- 重复 1 和 2,以某种顺序选择边,直到没有边可以放松(对于所有边(u,v),d[v] ≤ d[u] + weight(u,v))
如果图中没有边可以松弛,这意味着没有更好的方法通过任何相邻的边到达任何节点,也就是说,没有比当前路径更短的路径到达任何节点。
这很简单!然而,通常情况下,魔鬼隐藏在细节中,在这种特殊情况下,魔鬼阴险地潜伏在单词**‘某种秩序’**中。不明智的放松令会导致指数时间。一个好的订单甚至可以产生线性时间。该算法的效率取决于放松边缘的顺序,每个后续算法在这方面都有所不同。
贝尔曼·福特
既然我们已经知道了如何按照一定的顺序探索一个叫做 BFS 的图的边和顶点,为什么我们不试试呢?让我们按照广度优先的顺序来研究这个图,沿着这个方向扫描顶点和放松边。
然而这一次,我们不能仅仅满足于扫描每个顶点一次。与边未加权时不同,我们不可能知道是否有更好的路径到达一个节点,一条通过位于前方多个边界的节点的路径,还有待探索,如下例所示。

源节点是一个。不同的颜色代表不同的级别。请注意,没有比节点更多的级别,也没有顶点被添加到一个级别两次。请注意,我们必须多次扫描 B 和 D 才能获得它们的实际最短路径值。图片作者。
相反,如果当扫描节点 u 时,边(u,v)可以被放松,我们放松它,然后我们将它添加到队列中。但是我们不想将一个已经在队列中的节点添加到队列中,并计划在以后扫描,这将是一种浪费。因此,对于每个节点,我们必须跟踪它在任何给定时刻是否在队列中。
实现如下所示:(暂时忽略第 26 到 30 行)
但是为什么这个算法能够找到最短路径呢?
直觉
类似于我们在 BFS 所做的,我们将尝试通过查看队列中的级别来分析该算法。
级别 0 仅由源节点 s 组成。
级别 1 与 BFS 相同,由与源节点相邻的所有节点组成。这些是源的边缘内的节点,即通过长度为 1 的路径。
第二层现在将包括与第一层节点相邻的所有节点,这些节点的边可以放松。这些是图中所有可以通过长度为 2 的路径到达的节点,比长度为 1 的路径快。
在级别 1,长度为 1 的所有最短路径(从源 s)都计算正确。
在第 2 级,所有长度为 2 的最短路径都计算正确。
在级别 V-1,所有长度为 V-1 的最短路径都被正确计算。
一条路径最多只能有 V 个节点,因为一条路径中的所有节点必须互不相同,因此一条路径的最大长度是 V-1 条边。因此,在 V-1 级之后,该算法找到所有最短路径并终止。
负重量循环
到目前为止,我有意忽略了关于加权图的一个重要细节。考虑下图:

负圈图上 BFS 序边松弛的结果。图片作者。
节点 1、2 和 3 形成一个循环。这个圈的特别之处在于它的边的权重之和是负的。在具有负循环的图中寻找最短路径是一个NP-完全问题,没有已知的算法可以计算出有效的解决方案,并且很容易看出为什么。
我们已经看到,寻找最短路径的关键是放松边的顺序,但是无论你放松边 1-2、2-3 和 3-1 的顺序如何,你都不会到达没有边可以放松的点,因为你总是可以通过再次穿过负边、再次关闭循环来减少距离。
因此,我们有必要检测算法中这些循环的存在,以防止算法无限运行。但是怎么做呢?
- 我们已经做了安排,以确保一个节点在一个关卡或阶段中不会出现超过一次。
- 我们还知道,在正常情况下,不应超过 V-1 级。
因此,在整个执行过程中,一个节点最多只能被推入队列 V-1 次。然后我们可以跟踪一个节点被添加到队列中的次数(第 26 行),如果这个数字超过 V-1,我们就检测到了一个负循环(第 28 到 30 行)。
注意:这样做的一个后果是,我们不能在带有负边的无向图上使用这个算法,因为单个负的无向图将被算作一个负循环(因为它等价于 2 个有向边,(u,v)和(v,u))。
执行时间
- 我们知道该算法有 V-1 个阶段,每个阶段对应于我们刚才提到的 V-1 个级别。(例如,在阶段 1 中,我弹出 0 级(这只是源)中的所有节点,扫描它们的所有相邻节点,并扫描下一级节点。)
- 因为我们确保了没有顶点在同一级别的队列中出现超过一次,所以每个级别的顶点不会超过 V 个。
- 在每个阶段,最糟糕的情况是,如果我们将所有的顶点都放在一个级别中,并且必须扫描图中的所有边,这将转化为 O(E)。
因此,算法的总运行时间为 O(V.E) 。
在图形稀疏的情况下,这是二次时间(E = O(V),不是非常浓密),在图形密集的情况下,这是三次时间(E = O(V),非常浓密的图形,每个节点都有很多边)。这可能会很慢,有没有办法加快速度?
事实证明,对于包含负权重边的图,我们无法做得更好。但是谁需要它们呢?它们在实践中并不经常出现。如果我们有一个非负边权重的图,有没有办法利用它来提出一个更快的算法?
迪克斯特拉
考虑下面的例子:

一个图形的开始。
如果我们假设图中没有负边,我们能猜猜哪条边构成了最短路径吗?
权重最小的边将节点 C 链接到源。
为什么会这样呢?好吧,如果存在到节点 C 的较短路径,那么它必须经过从 A 到 E 的一个节点,所有这些节点的边的权重都高于我们选择的权重最小的边。**因为我们没有负权重的边,所以当你添加更多的边时,路径的成本永远不会变小,**所以当我们在图中继续前进时,总的路径权重不可能降低。
因此,我们可以肯定地说(S,C)是到节点 C 的最短路径,因此,我们不必再回到它,这就是 Dijkstra 算法的本质。
算法
Dijkstra 采用贪婪的方法来进行边缘松弛。在每次迭代中,它选择离源最近的节点。它放松它所有的输出边,然后不再检查它,因为它确定这是到那个节点的最短路径的当前值。
它不断重复这一过程,直到它用尽了图上的每个节点,或者,如果你心里有一个目的地节点,直到它到达那个特定的节点。
Pseudo-code Dijkstra (adj, source):visited = {}
Q = priority_queue()
Initialize Q with (node, distance) values, distance being 0 for the source and infinity for every other node.while Q is not empty:
u = extract_min(Q) # deletes u from Q
visited = visited ∪ {u}
for each vertex v, weight in Adj[u]:
if d[v] > d[u] + weight(u, v):
d[v] = d[u] + weight(u, v)
parent[v] = u
Q.decrease_key(v, d[v])
该算法利用了一个优先级队列数据结构,而不是像本文前面那样的常规队列,因为我们需要在每次迭代中弹出最近的节点。

作者图片
你可以在这里找到 Dijkstra 的图像,你可以玩玩,它是由旧金山大学的 David Galles 创作的。
直觉
我们已经探索了为什么这个算法能够计算最短路径的部分直觉。我们可以将这种推理扩展到第一次迭代之后:

作者图片
对于这个特定的状态,优先级队列将返回 N。不存在到节点 N 的更短的路径,因为到 N 的任何其他路径都必须经过当时已经在优先级队列中的节点(我们探索节点并放松其所有相邻边的方式使其如此),所有这些节点都离源远于 A。
至于其他节点,虽然它们的距离值可以在未来的迭代中减少,但它们永远不会变得小于 A 的距离,因为它们减少距离的最佳选择是找到穿过 A 的路径。
执行时间
我们有以下操作:
- O(V)将插入优先级队列(初始化步骤)
- O(V) extract min 操作(队列从 V 个节点开始,一直弹出,直到用完为止)
- 对于每一个提取的顶点,我们做的减少键操作和输出边一样多(最坏的情况)。对所有节点求和等于 O(E)减键操作。
实际的时间复杂度取决于用于实现优先级队列的数据结构。
使用未排序的数组,提取最小值需要完全遍历顶点,导致成本为 O(V)。减少一个键的值可以在常量时间内完成。结果是 O(V + E) = O(V ) 。
使用一个 二进制堆 ,两个操作的开销都是 O(log(V))。总运行时间为O(V . log(V)+e . log(V))= O(e . log(V))。
使用 Fibonacci 堆,您可以获得 O(E)的运行时间,但是这种数据结构对于实际应用来说太花哨了。
至于哪一个是更好的方法,它(显然)取决于 E 的值。E 可以具有的最佳值是 V -1*(当图刚刚连通时)。对于稀疏图 E = O(V),使用二进制堆是更好的选择。
最坏的情况发生在图是密集的,并且我们有从每个节点到几乎每隔一个节点的边的时候。在这种情况下, E = O(V),您最好使用数组实现来节省那些减少的关键操作的成本。
*我忽略了这样一个事实,即当图中有多个断开的组件时,E 可以小于 V-1,因为无论如何都无法从源到达这些组件。您可以从开始节点运行 BFS 来确定哪些节点连接到它,并只将这些节点放入优先级队列中,或者在 for 循环中填充优先级队列,而不是从头开始初始化它(下面的 python 实现就是这种情况)。
履行
这是一个使用堆作为优先级队列的实现,在实践中是最有用的。但是它与伪代码略有不同:
请注意,我们没有减少节点的键,而是将新的(节点,距离)对推入队列,相信队列将返回距离最小的对。至于留在队列中的较大的副本,将在第 12 行通过检查它们是否已经被访问过而被过滤掉。
我选择这样做的原因是,decrease 键为 O(log(V)),我们需要能够从节点 u 快速定位队列中的(u,du)对。Python 的 heapq 实现不提供这样的功能。你可以手工实现,使用一些外部模块,或者发挥创意。
因为队列中的节点数量不再限制在 V 个节点,所以我们最多可以在队列中有 O(E)个节点。渐近运行时间为 O(E . log(E))= O(E . log(V))= O(E . log(V)),所以基本不受影响。
Dijkstra 的运行时间相当好,对于随机图,没有更好的渐近运行时间,尽管在实践中确实存在运行更快的算法。
然而,对于有向无环图(DAGs) 的特殊情况,有最后一种算法比 Dijkstra 的算法更快,甚至可以处理负权重边!
DAG 最短路径
标题中的创造性名称是对这种算法缺乏一个事实的简化,因为没有人真正知道是谁首先发明了它。
现在,一个人在野外遇到一个有向无环图(DAG)时应该发展的基本本能是对它进行拓扑排序。这将给我们一个线性排序,使得如果(u,v)是从 u 到 v 的有向边,那么前一个 u 肯定会出现在后一个 v 之前。
换句话说,在任何路径上,没有一个节点可以先于它的前一个节点。所有的路都是向前的。

拓扑排序前后的 DAG。图片作者。
因此,通过以拓扑顺序迭代每个节点,放松其所有外出边,我们可以放心,一旦节点被扫描其邻居,它将永远不会再次被扫描,因为它的距离值将永远不会被更新,因为实际上没有办法从它的后继节点回到它,这是拓扑排序的属性。
这基本上是用来证明 Dijkstra 贪婪方法的正确性的相同推理,但是没有复杂的解释(Dijkstra 的实际形式证明相当粗糙……)或花哨的数据结构。并且总运行时间与 BFS 相同, O(V + E) 。
实施
我们首先对图进行拓扑排序。为此,下面的代码使用深度优先搜索(DFS)。由于这不是一个最短路径算法,我就不详细介绍了。
现在我们可以实现最短路径算法:
结论
唷,是时候了。这比我预期的时间要长。我们已经探索了最基本的单源最短算法。以下是迄今为止我们看到的算法的总结:

图片作者。
下面是一个决策树,可以帮助您选择最适合您的使用情形的选项:

图片作者。
最后,请注意以下几点:
- 本文中描述的所有算法都是为了找到从一个特定源节点开始的最短路径,因此它们被称为单源最短路径算法。还有其他算法可以找到从图上所有节点的所有最短路径,并且比运行我们已经见过 V 次的算法之一更有效(因为有 V 个源节点)。下次我可能会写一篇关于这些的文章。
- 关于 贝尔曼福特 算法我其实是撒了谎。文章中提出的算法实际上被称为“ 最短路径更快 ”,是贝尔曼福特的改进版本,具有相同的渐近复杂性,但在实践中工作更快。它们也是同样的正确性证明,但是我发现使用最短路径更快的算法更容易看到那个证明。这一点,加上实际的效率,是什么让我选择的变化,而不是原来的。
Flask APIs 系列,第 1 部分:获取和发布
原文:https://towardsdatascience.com/a-series-on-flask-apis-part-1-getting-and-posting-33985dfe8816?source=collection_archive---------7-----------------------

API 允许客户端与服务器通信,对于软件架构至关重要。图片由约翰经许可做。
本文是 Flask APIs 系列文章的一部分。这一部分将介绍如何使用 JSON 文档创建一个基本的 REST API,并在本地运行该 API。后续的每一部分都将引入新技术,帮助您更好地理解云中的 API 和 DevOps。
基础知识:什么是 Flask,什么是 API,什么是 REST API?
Flask 是一个 Python 微框架,通常用于创建 API 或应用编程接口。API 让你与应用程序交互。甚至 Python 中的模块也是一种 API,原因是:它们允许你与应用程序中的外部代码进行交互。API 充当服务器和您之间的一种契约。因此,要清楚地记录呼叫格式和预期的响应类型。
与全栈框架相比,Flask 是一个微框架,它便于接收 HTTP 请求,在控制器中处理这些请求,并返回 HTTP 响应。您可以在 Angular 或 React 的全栈项目中使用 Flask 作为组件,但我们可能不会在本系列中深入讨论。微框架本身通常缺乏身份验证、表单验证和数据库抽象层,但是这些可以使用其他组件内置。
“REST”将架构约束应用于 API。REST 代表代表性状态转移,这意味着当进行调用时,状态的表示也随该调用一起转移。这些包括作为我们的动词的 GET、POST、PUT 和 DELETE,它们的使用导致返回服务器数据的表示。要让你的 API“RESTful ”,有五个关键的组成部分:
- 一个统一接口,它通过我们的动词来标准化请求格式,并且具有逻辑的和模式化的 URI 路由来与 API 交互
- 客户端-服务器分离允许客户端和服务器分别发展,并且仅通过请求 URI 进行通信
- 无状态请求,每个请求都是独立的,不需要创建服务器会话,服务器也不需要维护过去请求的数据
- 可缓存的服务器端响应数据,以提高可伸缩性和客户端性能
- 最后,分层系统架构支持应用中的多层(通常用于身份验证),并且客户端和服务器不知道它们在与哪一层通信
- 按需代码的第六个可选约束允许服务器用代码响应,而不是用 JSON 或 XML 格式表示数据。
如果我们遗漏了任何一个关键组件,我们的 API 就是 REST 式的。关于 RESTful APIs 的更多信息,请查看罗伊·菲尔丁的论文。
构建基本的 Flask API
先决条件:你必须安装 python 和Flask。
- 为你的 flask API 创建一个本地文件夹,并在 VS 代码中打开该文件夹。你可能还想从一开始就把它放到 git repo 中。这将使本系列的后续部分变得更加容易。
- 如下创建两个文件夹和一个 py 文件。将文件夹命名为静态和模板。Flask 专门寻找具有这些名称的文件夹,因此一种功能性的文件夹结构方法将在将来为您省去麻烦。

作者图片
3.打开 demo_api.py 文件,编写以下代码:
代码片段 1: Hello World
重要的是你要在 1 号线接电话。shebang 是一个解释器指令,它告诉程序加载器这个文件应该被解释为 Python 文件,而/usr/bin/env 代表 Python 安装的逻辑路径。排除 shebang 现在可能不会导致问题,但是当您尝试在云中运行它时就会导致问题。
第 9 行的 route decorator 是 Flask 的一个特性,它让我们可以轻松地为 API 创建端点。一般来说,装饰器让我们扩展函数的行为。
第 14 行的 render_template 函数获取第 11 行的文本变量,并将其呈现在index.html文件中。
4*.接下来,用下面的代码在模板文件夹中创建一个名为index.html的文件:
<!DOCTYPE html><html lang="en"><head><title>Flask Demo</title></head><body>{{html_page_text}}</body></html>
在 Python 文件中,双花括号包含了 render_template 函数中引用的变量。
如果你需要更多关于 html 的信息,请查看 W3Schools。
*您不需要创建 html 文件,代码片段会告诉您如何使用或不使用该 API。
5.打开一个终端/命令提示符,然后将您的 demo_api.py 文件放入目录中。接下来,键入:
$ export FLASK_APP=demo_api$ flask run
您应该会在终端/命令提示符下看到以下输出:

作者图片
6.去 https://127.0.0.1:5000 。这是端口 5000 上的本地主机。

作者图片
Localhost 或 127.0.0.1 是对您的家庭计算机的引用。任何网站都不能有以 127 开头的 IP 地址,因为这些 IP 地址是为环回接口保留的,环回接口允许您与计算机模拟的网络服务器进行交互。我们能够在本地主机中测试应用程序,因为当环回被触发时,计算机模拟一个 web 服务器。
获取数据并将数据发布到 API
在这一节中,我们将扩展 API 的功能,展示如何获取数据并将数据发送到文件。让我们想象一个业务场景,其中我们记录和检索每年的事件。假设我们有三个目标:我们想去/all 查看所有时间的所有事件,我们想去/year/
任何时候你有一个带有未指定方法的路由,Flask 就假定这个方法是 GET(客户机正在从服务器请求数据)。
您需要创建一个包含数据的文件。首先,创建一个名为 data 的文件夹,并在其中创建一个名为 data.json 的文件。将以下内容粘贴到 data.json 中:
{"events":[{ "year":"2020","id":1,"event_category":"pandemic","event":"covid"},{ "year":"2020","id":2,"event_category":"environmental","event":"west coast wildfires"},{ "year":"2021","id":1,"event_category":"sports","event":"summer olympics"}]}
让我们从添加一个/all 路由开始。我们需要在我们的 demo_api.py 文件中创建另一个路由和函数,它从 data.json 文件中读取:
代码片段 2:添加/all
第 18 行的 json_url 变量引用了数据所在的路径。然后,我们使用 json.loads 打开该文件,并在index.html页面中呈现它。注意,只要我们注意变量,我们可以将各种不同的数据传递到一个模板中。
在继续之前,请确保此操作符合您的预期。
现在,我们要走/年/
<!DOCTYPE html><html lang="en"><head><title>Flask Demo</title></head><body>{% for item in html_page_text %}<p>{{ item}}</p>{% endfor %}</body></html>
接下来,我们需要创建一个新的路径来按年份获取数据。完整的代码应该如下所示:
代码片段 3:按年份获取
请注意,在第 24 行,我包含了 methods =['GET'],尽管我们过去没有为任何其他路径这样做。如果路由只是获取数据,您不需要指定方法,但是我们将很快扩展这些方法。
第 31 行确保我们访问了 data.json 文件中 events 键内的数据。第 32 行获取传递到路由中的数据,并将其转换为变量。然后,我们遍历列表中的所有数据,使用第 33 行的 list comprehension 获得感兴趣年份的数据。
现在,您可以将任何年份传递到路径中, data.json 中的数据将被过滤,只显示该年的事件。events.html 中的 for 循环对于显示多年来的所有事件至关重要,其中列出了多个事件。如果您在第 36 行使用index.html,您将看到每年只返回一个事件。
如果您在浏览器中进入http://127 . 0 . 0 . 1:5000/year/2020,您应该会看到以下结果:

作者图片
现在我们将处理向 data.json 文件添加新事件。在模板文件夹下创建另一个名为form.html的 html 文件。为了进行 POST,我们需要某种类型的表单来发送数据(或者我们也可以使用 Postman 并在参数中传递数据,稍后会详细介绍)。将以下内容粘贴到form.html中:
<!DOCTYPE html><html lang="en"><head><title>Flask Demo</title></head><body><form action="#" method="post" ><p>Yearly Events:</p><table><tbody><tr><td>Category:</td><td><input type="text" name="category" /></td></tr><tr><td>Event:</td><td><input type="text" name="event" /></td></tr></tbody></table><p><input type="submit" value="submit"/></p></form></body></html>
首先,我们需要在应用程序中呈现这个表单。如下所示添加/add 路由将让我们做到这一点。
代码片段 4:检索表单数据
除了 send_file 函数之外,从第 25 行开始的/add 路径中的所有内容您都应该很熟悉。这让我们可以将表单中的内容发送给客户端。然而,在这一点上,没有任何东西来接收和处理帖子,您将得到一个内部服务器错误。
我们现在需要编写一些逻辑来从表单中获取发布的数据。有几种方法可以做到这一点,但我将向您展示一种方法。欢迎在下面的评论中加入其他方法。
代码片段 5:发布表单数据
我们需要在第 1 行指定它接受 POST 方法。否则,所有代码都将不起作用。
第 15 到 20 行从发布的表单中提取数据。代码通过在form.html属性中指定的名称来引用这些元素。第 21 行到第 25 行将数据放入一个字典中,因此所有数据都是从一个提交的表单中检索出来的。
根据数据文件的格式,第 27 行到第 30 行稍微复杂一些,但是我将根据数据的结构向您展示我的思路。有很多关于像 open 这样的 Python 内置函数的文档,但是我选择 r+作为模式以确保文件可以被读取和更新。
首先,我们需要让 json 的变化按照我们的设想工作。最初,我想,*好吧,我需要加载当前文件中的数据,将新数据追加到事件列表的末尾,然后覆盖原始文件。*如果您试图添加另一个值,您会注意到这并不完全有效…新字典被添加到旧字典的末尾:

作者图片
所以我们需要从文件的开头开始,而不是追加到结尾。这就是寻道功能的用武之地。这将我们指向文件的开头,而不是结尾(数据先前被附加到的地方)
代码片段 6: seek
现在您有了一个基本的 API,可以从一个表单获取数据并将其发送到一个文档中!
**注意/故障排除:**如果您运行上面的代码,您可能会注意到第一行被覆盖了。如果您最初的 data.json 有一些缩进,这可能会有问题。这里是 json.dump 中一个有用的参数派上用场的地方。缩进!
代码片段 7:缩进
您可以使用从 0 开始的任何级别的缩进,但是您需要根据 data.json 文件的缩进方式来试验它。
**其他一些方法:**你可以在内置的打开函数中使用额外的模式来先读取然后覆盖文件。如果你有更多的建议或意见,请在评论区发表。
感谢阅读!
隐式数据增强综述
原文:https://towardsdatascience.com/a-short-survey-on-implicit-data-augmentation-40b3eb1f7430?source=collection_archive---------25-----------------------
隐式数据增强技术综述及未来研究方向

作者图片
数据扩充是一种流行的技术,用于提高可能过度拟合的模型的概化能力。通过生成额外的训练数据并将模型暴露给同一类中的不同版本的数据,训练过程变得更加健壮,因此更有可能将结果模型推广到测试集。最近,与直接转换输入数据的显式数据扩充相比,间接从隐藏空间生成样本的隐式数据扩充显示出良好的性能。本文重点介绍了隐式数据增强的主要研究方向,并提出了该领域的几个研究方向。
简介
衡量训练集和测试集之间性能差异的泛化差距很大程度上来自它们的分布差异。当潜在数据生成过程的所有数据变化在训练集中可用时,即使是简单的模型,如 k-最近邻,也会在测试集中获得近乎完美的泛化性能(Cover & Hart,1967)。然而,在实际应用中,通常会观察到训练集和测试集之间存在一定程度的分布差异。这种分布差异的一个直接影响是,在训练集中表现良好的模型不一定能推广到测试集中,如果没有适当地正则化的话。此外,神经网络通常对输入数据中的噪声敏感(Tang & Eliasmith,2010),因此需要通过数据扩充实现不变性。
文献综述
从数据的角度来看,与模型架构、损失函数或整个模型训练过程的优化算法等其他组件相比,数据扩充是一种常用的正则化技术。它旨在通过对现有训练数据进行随机但真实的转换来生成人工样本,从而增加可用训练数据的多样性。在图像数据的情况下,通过诸如旋转和镜像的技术,显式数据扩充直接转换现有数据以获得新的样本。参见(Shorten & Khoshgoftaar,2019)对常见显式图像数据增强技术的全面综述。
虽然过程很简单,但直接应用随机变换可能无法生成有用的数据,因为生成过程是无人监督的,并且不是针对当前的建模任务。为了缓解这一挑战,(Zhang et al .,2017)提出了一种基于训练特征及其标签的凸组合来生成样本的混合方法。事实上,如果训练集和测试集之间的相似性相当好,显式地对中间样本进行插值,即使是线性插值,也可以生成比随机生成更有用的训练样本。如果测试集与训练集非常不同,则有必要使用原始样本和生成的样本之间的某种形式的距离来生成更具挑战性的对立样本。例如,距离现有样本最远,但仍在同一类目标标签内的人工样本是极端样本,可能有助于支持推广到完全不同的测试集,如(沃尔皮等人,2018 年)的工作所示。
数据扩充也可以在不直接调整输入数据的情况下实现。在变分自动编码器(Kingma & Welling,2013)中,输入数据首先被编码到隐藏空间中,然后通过在隐藏状态变量中引入随机噪声来控制新数据的生成。通过将原始特征空间投影到一个紧凑且深度隐藏的空间,得到的特征往往会被线性化和去纠缠,这使得基于采样或插值的生成过程在实际应用中更有意义(Bengio,Yoshua 等人,2013)。例如,(Wang et al .,2019)在隐藏空间中沿着具有最大类内变化的维度内插新样本,从而在投影回原始输入空间时产生语义上有意义的变换。由这种在自动编码器类型的神经网络中的隐藏空间执行的目标凸插值产生的一个有趣的特性是等价于鲁棒损失函数。这种鲁棒性是通过在解码输出层对网络权重的范数进行加压,经由添加到损失函数的惩罚项来实现的(Bishop,1995a)。这一特性允许通过重构损失函数来进行有效的训练,但仍然引入了隐含的数据正则化效果。
潜在研究方向
显式数据扩充会在生成和训练人工样本时引入相当大的训练开销。相比之下,隐式数据增强可以通过对损失函数的轻微修改来实现类似甚至更好的正则化效果,而不会导致过多的额外训练开销。在下文中,我们为这一激动人心的领域提供了几个潜在的研究方向。
数据。数据扩充本质上旨在生成不同变化的附加样本,以逼近测试集的数据分布。由于特征解缠结效应,在编码操作之后在深层隐藏空间上工作似乎更有希望,而不是显式地调整输入数据,导致更线性化和可分离的特征空间。就在隐藏空间采样候选点而言,我们观察到两个共同的流。一个流侧重于观察点之间的插值,可能沿着具有最大方差的维度,以提高可解释性,如(Wang et al .,2019)所示。另一个流集中于观察样本的受控外推和扰动,以在隐藏空间中生成“硬”对抗样本。我们注意到(沃尔皮等人,2018 年)中使用的第二个流中有一个类似的方法,尽管是在输入数据上。
网络架构。模型架构定义了从输入数据到输出预测的信息流。我们现在将不同版本的网络架构暴露给相同的训练数据,而不是生成不同版本的训练数据。网络架构中引入的随机噪声,如 dropout (Srivastava 等人,2014 年)及其变体,防止了对网络特定部分的过度依赖,使模型更加稳健,对数据中的噪声不太敏感。然而,隐式正则化效果可以以多对多的方式进一步利用,同时引入多个版本的数据和架构,并优先考虑具有高方差的维度。
损失功能。在估计期间,通过模型系数的适当正则化,可以引入几个好的特性。例如,基于范数的惩罚(如 Lasso)已被证明通过在特征空间中隐式引入随机扰动来稳健地估计过程(Xu 等人,2010),而基于协方差的惩罚可用作隐式数据增强技术,如(Wang 等人,2019)所示。因此,研究损失函数中其他形式的正则化的影响是有趣的。此外,对系数的调整大多是即时的和一步到位的,这并不保证它从长远来看是最优的。对系数的多步惩罚似乎是有希望的,它平衡了短期和长期效果之间的权衡,就像在强化学习代理的训练过程中一样。
**优化算法。**随机梯度下降是训练神经网络中最常用的算法,通过对邻近更新进行去相关,该算法被证明是一种隐式正则化算法(Daniel A. Roberts,2018)。这意味着,对于相同的输入数据,与每次迭代的一批样本相比,模型在对每个样本进行单独训练时更有可能泛化。其他技术,例如小权重初始化和大初始学习率,也能够隐式地正则化模型。这些方法本质上关注于输入数据与权重的交互方式,以及呈现给权重的方式,以便持续更新。在这方面,我们期待在输入数据和权重之间的这种相互作用机制上有更多创新的研究进展。例如,权重更新中每个输入数据点的相对贡献可以被插值以生成额外的假更新,这对应于生成更多的训练样本。此外,权重更新时间表也可以遵循基于某些一般化标准的多步前瞻方案。
结论
本文总结了隐式数据增强领域的主要研究进展,并提出了未来的研究方向,包括数据、网络结构、损失函数和优化算法。由于这是一个连接多个领域的重要主题,我们希望我们的工作能够激发研究社区的更多兴趣,并为更广泛的模型概化领域做出贡献。
参考文献
最近邻模式分类。IEEE 信息论汇刊,13(1):21–27,1967。
主教,c . m .(1995 年 a)。模式识别的神经网络。牛津大学出版社。(ˆ1, 5, 7, 9, 23)
唐,伊川&埃利亚史密斯,克里斯。(2010).用于鲁棒视觉识别的深度网络。ICML 2010——第 27 届机器学习国际会议论文集。1055–1062.
用于深度学习的图像数据增强的调查。j 大数据 6,60 (2019)。https://doi.org/10.1186/s40537-019-0197-0
张,&西塞,穆斯塔法&多芬,扬&洛佩斯-帕斯,大卫。(2017).混淆:超越经验风险最小化。
沃尔皮,里卡多&南孔,洪泽克&塞内,奥赞&杜奇,约翰&穆里诺,维托里奥&萨瓦雷塞,西尔维奥。(2018).通过对抗性数据增强推广到未知领域。
金玛,迪德里克&韦林,马克斯。(2013).自动编码变分贝叶斯。ICLR。
透过深度表现更好的混合。ICML (2013 年)。
王、俞林、潘、、宋、史集、张、洪、吴、程、黄、高。(2019).面向深度网络的隐式语义数据增强。
斯利瓦斯塔瓦,尼蒂什&辛顿,杰弗里&克里热夫斯基,亚历克斯&苏茨基弗,伊利亚&萨拉胡季诺夫,鲁斯兰。(2014).辍学:防止神经网络过度拟合的简单方法。机器学习研究杂志。15.1929–1958.
徐,桓&卡拉马尼斯,康斯坦丁&曼诺尔,。(2010).稳健回归和套索。信息论,IEEE 汇刊。56.3561–3574.10.1109/份。2010.2048848656366
丹尼尔·罗伯茨(2018)。SGD 隐式正则化泛化错误。Neurips (2018)。
Python 正则表达式的简单直观指南
原文:https://towardsdatascience.com/a-simple-and-intuitive-guide-to-regular-expressions-404b057b1081?source=collection_archive---------14-----------------------
使用 Python 轻松地从任何文本中提取信息。

Max Kleinen 在 Unsplash 上拍摄的照片
如果您曾经在 Python 中处理过文本数据,您会知道大多数时候您必须处理脏数据。这意味着您正在寻找的特定文本(姓名、日期、电子邮件等)需要提取出来才能使用。
这时正则表达式(regex)就派上用场了。由于它的语法,你将能够找到你想要提取的模式,并节省大量时间。
尽管正则表达式看起来令人生畏,但乍一看,我为本文中将要看到的所有正则表达式创建了一些动画图像,因此您可以很容易地理解它们背后的概念。
**Table of Contents** 1\. [The re module (re.match, re.findall)](#9216)
2\. [^ and $ symbols](#39c1)
3\. [Metacharacters (., \w, \d, \s)](#8860)
4\. [Quantifiers (*, +, ?, {, })](#35eb)
5\. [Group and capture with ( )](#5791)
6\. [Match an expression with [ ]](#bf4d)
7\. [Or](#1426)
8\. [Boundaries (\b)](#a5b1)
9\. [Back-references (e.g. \1](#5fc6))
10\. [Flags](#7c1c)
11\. [Greedy and Lazy match](#d2a9)
12\. [Common Use Cases](#7d2a)
- [Match punctuation](#19ea)
- [Valid date format](#f247)
- [Valid email](#8c18)
- [Valid username](#9e48)
re 模块(重新搜索,重新查找)
在本文中,我们将使用下面的文本来展示正则表达式是如何工作的。
text = '''
Hello World
I love Python!!!!!
My first lucky number is 987-654-321
My second lucky number is 876-543-210
My third lucky number is 765-432-100
'''
我们将使用 Python 来解释一些额外的细节,然而,正则表达式语法对于大多数编程语言来说几乎是相同的。在 Python 中,我们需要导入以下内容来处理正则表达式。
importre
为了找到与正则表达式模式匹配的第一个匹配项和所有匹配项,我们使用下面的。
#return the first match
re.search(pattern, text)# return all the matches
re.findall(pattern, text)
在本文中,为了主要关注学习正则表达式,我们将只检查正则表达式 **pattern**以避免重复输入re.search, re.findall and text``.
^和$符号
这两个符号将分别匹配以指定字符开头或结尾的字符串。让我们看一个上面定义的text变量的例子。
**^Hello** matches any string that starts with Hello **World$** matches a string that ends with World **^Hello World$** matches a string thatstarts and ends with Hello World (exact match)
让我们看看上面列出的正则表达式。

作者图片
中以蓝色突出显示的文本。上面的 gif 将是匹配的图案。
现在很清楚每个符号的作用了。请记住,如果文本是World Hello!,那么前面的模式都不起作用。此外,在这个例子中,默认的 regex 标志被设置为 multiline(我在下面的标志部分解释了 regex 中的标志)
元字符(。,\w,\d,\s)
在正则表达式中,元字符被理解为具有特殊含义的字符,如下所示。
**.** matches any character except a new line
**\d** matches a digit
**\w** matches a word character (a-z, A-Z, 0-9, _)
**\s** matches a whitespace (space, tab, newline)
现在我们来验证一下它们各自的工作原理。

作者图片
记住,上面提到的元字符也有它们的否定形式\D、\W和\S。同样,为了转义这个和其他特殊字符^.[$()|*+?,我们使用反斜杠\。我在Hello World的末尾加了点,看看这是如何工作的。

作者图片
如您所见,当您包含反斜杠\.时,. 并不匹配所有字符
量词(*、+、?, {, })
量词将帮助我们找到一个重复“n”次的字符。我们来看看最基本的量词*+?
假设我们想要匹配单词Python后的感叹号**!** 的数量
Python!***** matches a string that has Python followed by 0 or more **!** Python!**+** matches a string that has Python followed by 1 or more **!** Python!**?** matches a string that has Python followed by 0 or 1 **!**

作者图片
以下量词将让您指定重复的字符数。
Python!**{2}** matches a string that has Pythonfollowedby 2 **!** Python!**{2,}** matches a string that has Pythonfollowed by 2 or more **!** Python!**{2,4}**matches a string that has Pythonfollowed by 2 up to 4**!** Python**(!!){2,4}** matches a string that has Pythonfollowed by 2 up to 4 copies of the sequence **!!**
这可能看起来很可怕,但它比你想象的要简单。让我们来看看。

作者图片
最后一个图案Python**(!!){2,4}** 也捕捉到了感叹号!!,因为有括号。我们将在下一节中对此进行更多的检查。
使用( )进行分组和采集
要捕获模式中的特定字符组,只需添加括号()。例如,正如我们到目前为止所看到的,模式\d+-\d+-\d+将匹配由连字符分隔的数字,但是如果我们只想获得第一个连字符之前的数字组呢?
(\d+)-\d+-\d+ parentheses create a capturing group of the first group of digits before the hyphen -

作者图片
如您所见,当添加括号时,颜色变为绿色,这表示捕获的组。
在 Python 中,您可以使用re.findall()来查找所有的事件并显示捕获的组。
IN [0]: re.findall(r'(\d+)-\d+-\d+', text)
OUT [0]: ['987', '876', '765']
用[ ]匹配表达式
与圆括号不同,方括号[] 不捕捉表达式,只匹配表达式中的任何内容。
**[789]** matches a string that has 7, 8 or 9\. It's like 7|8|9 **[7-9]** same as previous
**[a-zA-Z]** a string that has a letter from a to z or from A to Z **[^a-zA-Z]** a string that has not a letter from a to z or from A to Z. (the **^ is used as negation** of the expression when it's at the beginning inside brackets)
许多人被写在方括号内的模式吓到了,但是当你通过一个例子看到它是如何工作的时候,就不会那么困难了。

作者图片
不管模式有多长,如果它在方括号内,你可以把它们分成“或”条件组。
说到“或”条件,让我们回顾一下目前为止我们已经看到的。
或者
我们已经看到了在正则表达式中获得“或”条件的两种方法。第一种是使用括号,第二种是使用方括号。假设我们想要匹配数字 8 或 9 后面的 2 位数。
(9|8)\d{2} matches a string that has 9 or 8 followed by 2 digits *(captures* 9 or 8*)*[98]\d{2}matches a string that has 9 or 8 followed by 2 digits without capturing 9 or 8

作者图片
你可能还记得,这两者的主要区别是圆括号捕捉组,而方括号不捕捉组。此外,应该在括号中指定“or”|,但是没有必要将它包含在方括号中。
边界(\b)
\b 符号是另一个元字符,它匹配单词字符(\w)和非单词字符(\W)之间的位置。这叫字界。让我们看看这个怎么样。

作者图片
在图中,我们可以看到 3 个不同的位置符合“单词边界”的条件:
- 如果第一个字符是单词字符,则在字符串的第一个字符之前。
- 在字符串的最后一个字符之后,如果最后一个字符是单词字符。
- 字符串中的两个字符之间,其中一个是单词字符,另一个不是单词字符。
现在让我们看看第 2 点只匹配右边的单词边界实际上意味着什么。为此,我们编写了表达式.\b

作者图片
\b 符号还有一个与\b相反的否定\B

作者图片
反向引用(\1)
反向引用帮助我们重用已经识别的捕获组。为了更好地解释这一点,我将把下面的句子添加到我们之前定义的文本中。
“My fourth lucky number is 123–456–123–123–456”
所以我们的目标是找到重复性的123- 放一个又一个。我们可以通过反向引用来解决这个问题。
(123-)\1 the **\1** matches the same text that was matched by the first capturing group (123-)
让我们来看看。

作者图片
我们可以看到,如果只写(123-),得到的不是123-的序列,而是单个元素。相反,如果我们写正则表达式(123-)\1 ,期望的序列是匹配的。该引用相当于编写(123-)(123-)
如果您有一个以上的捕获组,您也可以指定您想要重用的组,方法是写下它的顺序\1为第一个,\2为第二个,依此类推。
旗帜
简而言之,标志是可选参数,用于修改正则表达式的搜索行为。每个标志由一个字母字符表示,并以不同的方式修改搜索行为。
例如,让我们看看标志i,它使表达式不区分大小写。在 Python 中,我们会这样做来添加这个新参数。
# without flag
IN [0]: re.search(r'[a-z]+', 'Hello')
OUT [0]: <re.Match object; span=(1, 5), **match='ello'**># with I flag
IN [1]: re.search(r'[a-z]+', 'Hello', flags=**re.I**)
OUT [1]: <re.Match object; span=(0, 5), **match='Hello'**>
正如我们所看到的,由于正则表达式中增加了参数re.I,我们可以得到整个‘Hello’而不仅仅是‘ello’
使用的其他标志如下
g(全局)让表达式搜索所有匹配项m(多行)使边界字符^和$匹配每一行的开始和结束,而不是整个字符串的开始和结束s(点全)使点符号也匹配换行符。
贪婪和懒惰的搭配
这是一些操作符默认的行为方式。像*+{}这样的一些字符是贪婪的,这意味着它们将匹配最长的可能字符串。例如,假设我们想要获取连字符-中的所有字符
我们可以很容易地得到这个正则表达式-.+- ,但是加号+ 是贪婪的,所以它将尽可能多地使用字符(如果我们的目标是匹配尽可能短的字符串,甚至是其他连字符-) )。,我们应该像?一样加一个懒算子。我们来对比一下。

作者图片
开始时,+ 匹配整个字符串–456–123–123– ,但是? 确保用最少的字符数进行匹配,所以它首先匹配-456-,然后匹配-123-
请记住,您可以通过编写严格的表达式来避免这些贪婪/懒惰的匹配,比如-[^-]+- This 匹配连字符之间的任何内容,同时也不包含任何连字符。
常见使用案例
匹配标点符号
在处理文本时,通常需要在分析前删除标点符号。为此,我们编写以下表达式
[^\w\s]

作者图片
有效的日期格式
这将取决于您希望匹配的格式。让我们假设你想用美国格式匹配一个日期mm-dd-yyyy
\d{2}-\d{2}-\d{4}

作者图片
有效电子邮件
您可以通过以下表达式轻松识别有效的电子邮件
^[^@ ]+@[^@ ]+\.[^@ \.]{2,}$
表达式的键直到需要时才匹配@和空格,所以我们写[^@ ] 来忽略它们。

作者图片
有效用户名
假设用户名只允许小写字母或数字。此外,用户名的最小长度必须是 4 个字符,最大长度必须是 16 个字符。
^[a-z0-9]{4,16}$
你可以在这个网站上测试这个以及我们在本文中使用的其他正则表达式。
就是这样!现在是你创建正则表达式来解决日常任务的时候了!我在我的 Github 上列出了本文中使用的正则表达式字符及其含义。
与 3k 以上的人一起加入我的电子邮件列表,获取我在所有教程中使用的 Python for Data Science 备忘单(免费 PDF)
用深度学习的 Python 构建一个简单的聊天机器人
原文:https://towardsdatascience.com/a-simple-chatbot-in-python-with-deep-learning-3e8669997758?source=collection_archive---------1-----------------------
自然语言处理笔记
如何建立自己的朋友

Lyman Gerona 在 Unsplash 上拍摄的照片
人工智能正在迅速渗透到各行各业的工作流程中。由于自然语言处理(NLP)、自然语言理解(NLU)和机器学习(ML)的进步,人类现在能够开发能够模仿类似人类的交互的技术,包括识别语音和文本。
在本文中,我们将使用 Python 中的 NLP 和神经网络来构建一个聊天机器人。
数据
在我们开始考虑任何编码之前,我们需要建立一个 intents JSON 文件,它定义了在与我们的聊天机器人交互过程中可能出现的某些意图。要做到这一点,我们必须首先创建一组用户查询可能会遇到的标签。例如:
- 一个用户可能希望知道我们聊天机器人的名字,因此我们创建了一个用标签
name标记的意图 - 用户可能希望知道我们聊天机器人的年龄,因此我们创建了一个标签为
age的意图 - 等等等等
对于我们创建的每个标签,我们必须指定模式。本质上,这定义了用户如何向我们的聊天机器人提出查询的不同方式。例如,在name标签下,用户可以用各种方式询问某人的名字——“你叫什么名字?”,“你是谁?”,“你叫什么?”。
然后,聊天机器人将采用这些模式,并将它们用作训练数据,以确定询问我们聊天机器人名称的人看起来会是什么样子,以便它可以适应有人可能询问我们机器人名称的不同方式。因此,用户不必使用我们的聊天机器人已经学会的精确查询。它可以提出这样的问题:“你叫什么?”我们的聊天机器人能够推断出用户想要知道我们聊天机器人的名字,然后它会提供它的名字。
注意:我们的机器人不会超级聪明,所以它不会总是识别我们在说什么,但是有足够的例子,它会在破译方面做得相当不错。
在这个 intents JSON 文件中,每个 intents 标签和模式旁边都有响应。然而,对于我们简单的聊天机器人,不会生成这些响应。这意味着我们的模式不会像用户可以询问的模式那样自由流动(它不会适应),相反,响应将使用聊天机器人在提出查询时将返回的静态响应。
# used a dictionary to represent an intents JSON filedata = {"**intents**": [
{"**tag**": "greeting",
"**patterns**": ["Hello", "How are you?", "Hi there", "Hi", "Whats up"],
"**responses**": ["Howdy Partner!", "Hello", "How are you doing?", "Greetings!", "How do you do?"],
},
{"**tag**": "age",
"**patterns**": ["how old are you?", "when is your birthday?", "when was you born?"],
"**responses**": ["I am 24 years old", "I was born in 1996", "My birthday is July 3rd and I was born in 1996", "03/07/1996"]
},
{"**tag**": "date",
"**patterns**": ["what are you doing this weekend?",
"do you want to hang out some time?", "what are your plans for this week"],
"**responses**": ["I am available all week", "I don't have any plans", "I am not busy"]
},
{"**tag**": "name",
"**patterns**": ["what's your name?", "what are you called?", "who are you?"],
"**responses**": ["My name is Kippi", "I'm Kippi", "Kippi"]
},
{"**tag**": "goodbye",
"**patterns**": [ "bye", "g2g", "see ya", "adios", "cya"],
"**responses**": ["It was nice speaking to you", "See you later", "Speak soon!"]
}
]}
代码
为了编写我们的机器人,我们将需要一些 Python 内置,以及用于 NLP、深度学习的流行库,以及用于处理数组的事实库 NumPy。
**import** json
**import** string
**import** random **import** nltk
**import** numpy **as** np
**from** nltk.stem **import** WordNetLemmatizer **import** tensorflow **as** tf
**from** tensorflow.keras **import** Sequential
**from** tensorflow.keras.layers **import** Dense, Dropoutnltk.download("punkt")
nltk.download("wordnet")
为了创建我们的训练数据,首先我们必须对我们的data做一些事情。以下是清单:
- 创建模式中使用的所有单词的词汇表(回想一下,模式是用户提出的查询)
- 创建一个类的列表——这只是每个意图的标签
- 创建意图文件中所有模式的列表
- 为 intents 文件中的每个模式创建一个所有相关标签的列表
让我们用 Python 来看看这个…
# initializing lemmatizer to get stem of words
lemmatizer = WordNetLemmatizer()# Each list to create
words = []
classes = []
doc_X = []
doc_y = []*# Loop through all the intents
# tokenize each pattern and append tokens to words, the patterns and
# the associated tag to their associated list***for** intent **in** data["intents"]:
**for** pattern **in** intent["patterns"]:
tokens = nltk.word_tokenize(pattern)
words.extend(tokens)
doc_X.append(pattern)
doc_y.append(intent["tag"])
*# add the tag to the classes if it's not there already*
**if** intent["tag"] **not in** classes:
classes.append(intent["tag"])*# lemmatize all the words in the vocab and convert them to lowercase
# if the words don't appear in punctuation* words = [lemmatizer.lemmatize(word.lower()) **for** word **in** words **if** word **not in** string.punctuation]*# sorting the vocab and classes in alphabetical order and taking the # set to ensure no duplicates occur*
words = **sorted**(**set**(words))
classes = **sorted**(**set**(classes))
这是每个列表的外观…
**print**(words)
**>>>> ["'s", 'adios', 'are', 'birthday', 'born', 'bye', 'called', 'cya', 'do', 'doing', 'for', 'g2g', 'hang', 'hello', 'help', 'hi', 'how', 'is', 'later', 'name', 'old', 'out', 'plan', 'see', 'some', 'talk', 'thanks', 'there', 'this', 'time', 'to', 'up', 'wa', 'want', 'week', 'weekend', 'what', 'whats', 'when', 'who', 'ya', 'you', 'your']****print**(classes)
**>>>> ['age', 'date', 'goodbye', 'greeting', 'name']****print**(doc_X)
**>>>> ['Hello', 'How are you?', 'Hi there', 'Hi', 'Whats up', 'how old are you?', 'when is your birthday?', 'when was you born?', 'what are you doing this weekend?', 'do you want to hang out some time?', 'what are your plans for this week', "what's your name?", 'what are you called?', 'who are you?', 'Thanks for your help', 'bye', 'g2g', 'see ya', 'talk later', 'adios', 'cya']****print**(doc_y)
**>>>> ['greeting', 'greeting', 'greeting', 'greeting', 'greeting', 'age', 'age', 'age', 'date', 'date', 'date', 'name', 'name', 'name', 'goodbye', 'goodbye', 'goodbye', 'goodbye', 'goodbye', 'goodbye', 'goodbye']**
既然我们已经分离了我们的数据,我们现在准备训练我们的算法。然而,神经网络希望输入数值,而不是单词,因此,我们首先必须处理我们的数据,以便神经网络可以读取我们正在做的事情。
为了将我们的数据转换成数值,我们将利用一种叫做单词包的技术。有关清理文本和将文本表示为数值的更多信息,请查看我的两篇文章,其中详细介绍了这些技术以及如何在 Python 中执行它们。
*# list for training data*
training = []
out_empty = [0] * len(classes)*# creating the bag of words model*
**for** idx, doc **in** enumerate(doc_X):
bow = []
text = lemmatizer.lemmatize(doc.lower())
**for** word **in** words:
bow.append(1) **if** word **in** text **else** bow.append(0) *# mark the index of class that the current pattern is associated
# to*
output_row = **list**(out_empty)
output_row[classes.index(doc_y[idx])] = 1 *# add the one hot encoded BoW and associated classes to training*
training.append([bow, output_row])*# shuffle the data and convert it to an array*
random.shuffle(training)
training = np.array(training, dtype=**object**)*# split the features and target labels*
train_X = np.array(**list**(training[:, 0]))
train_y = np.array(**list**(training[:, 1]))
随着我们的数据转换成数字格式,我们现在可以建立一个神经网络模型,我们将把我们的训练数据输入其中。其思想是,模型将查看特征并预测与特征相关联的标签,然后从该标签中选择适当的响应。
*# defining some parameters*
input_shape = (**len**(train_X[0]),)
output_shape = **len**(train_y[0])
epochs = 200*# the deep learning model*
model = Sequential()
model.add(Dense(128, **input_shape**=input_shape, **activation**="relu"))
model.add(Dropout(0.5))
model.add(Dense(64, activation="relu"))
model.add(Dropout(0.3))
model.add(Dense(output_shape, **activation** = "softmax"))adam = tf.keras.optimizers.Adam(learning_rate=0.01, decay=1e-6)model.compile(**loss**='categorical_crossentropy',
**optimizer**=adam,
**metrics**=["accuracy"])
**print**(model.summary())
model.fit(x=train_X, y=train_y, epochs=200, verbose=1)

作者图片
在我们的序列模型中,我们使用了一些丢弃层,这些丢弃层在防止深度学习模型过度拟合数据方面非常有效。在另一篇文章中,我对此做了更深入的探讨。
太好了。我们已经训练了我们的深度学习模型,但现在我们必须创建实际的功能,使我们能够在聊天机器人应用程序中使用我们的模型。对于下一个任务,我已经创建了一组实用函数,可以让我们轻松地执行这个任务。
接下来的部分很简单。我们必须创建一个 while 循环,允许用户输入一些查询,然后对这些查询进行清理,这意味着我们获取标记并对每个单词进行词汇化。之后,我们使用单词包模型将文本转换为数值,并预测哪些标签最能代表我们的意图。从那里,我们将从 intents 标记内的响应中随机抽取一个响应,并使用它来响应查询。
# running the chatbot
**while True**:
message = **input**("")
intents = pred_class(message, words, classes)
result = get_response(intents, data)
**print**(result)
让我们看看我们的聊天机器人在运行…

包裹
您现在已经看到了如何使用深度学习和 NLP 技术用 Python 创建一个非常简单的聊天机器人。在我看来,这绝不是一个你想带到招聘经理面前或放在简历上的优雅聊天机器人,但对于任何对对话式人工智能感兴趣的人来说,这是一个很好的开始。如果你碰巧以这篇文章为指导创建了一个聊天机器人,一定要在我的 LinkedIn 或 Twitter 上给我看一些预览,我会在下面链接。
感谢您的阅读!在 LinkedIn 和 T2 Twitter 上与我保持联系,了解我关于数据科学、人工智能和自由职业的最新消息。
相关文章
</5-ideas-for-your-next-nlp-project-c6bf5b86935c> https://pub.towardsai.net/7-free-online-resources-for-nlp-lovers-26b1e0bba343
使用 Airflow 2.0 的简单 DAG
原文:https://towardsdatascience.com/a-simple-dag-using-airflow-2-0-b4c218b2ccd9?source=collection_archive---------28-----------------------
Airflow 2.x 是一个游戏改变者,尤其是它使用新的任务流 API 简化了语法。在本教程中,我们正在构建一个只有两个任务的 DAG。DAG 的任务包括生成随机数(任务 1)和打印该数字(任务 2)。
介绍
背景
这篇博客文章是使用 Airflow 2.0 的最新语法和 Raspberry Pis 构建整个 ETL 管道的系列文章的一部分。这需要一些术语的知识,所以这里是一个刷新记忆的好地方。此外,查看我之前关于如何在树莓派上安装气流 2 的帖子。
完整的代码在 Github 上。
创建 DAG 定义文件
我们将从在airflow/dags文件夹中创建 DAG 定义文件开始:
让我们通过添加 DAG 来填充它。
DAG 分解
@dag装饰工
DAG 有任务。在这个例子中,它有两个任务,其中一个依赖于另一个的结果。为此,我们将使用最新的气流装饰:@dag和@task。
我们首先定义 DAG 及其参数。我们将确定任务集运行的时间间隔(schedule_interval)和开始日期(start_date)。当然,还有其他参数可供选择,但是我们将把范围保持在最小。
注意函数EXAMPLE_simple顶部的@dag装饰器。函数名也将是 DAG id。最后,我们只是运行 DAG 的功能。
@task装潢师
既然@dag包装器已经解决了,我们需要定义里面的两个任务。记住,这个 DAG 有两个任务:task_1生成一个随机数,task_2接收第一个任务的结果并打印出来,如下所示:
从视觉上看,DAG 图形视图如下所示:

前后的代码指的是@dag运算符及其依赖关系。接下来,我们将把所有东西放在一起:
就是这样。让我们运行这个。
运行 DAG
创建 DAG 定义文件后,在airflow/dags文件夹中,它应该会出现在列表中。现在,如果我们想立即运行 DAG,我们需要解除其暂停并触发它。有两个选项来解除暂停和触发 DAG:我们可以使用 Airflow web 服务器的 UI 或终端。让我们两个都处理。
通过用户界面运行
首先,您应该在列表中看到 DAG:

在这个例子中,我以前运行过 DAG(因此一些列已经有了值),但是您应该有一个干净的石板。
现在,我们启用 DAG (1)并触发它(2),因此它可以立即运行:

单击 DAG ID(在本例中称为EXAMPLE_simple),您将看到树形视图。触发新的运行后,您将看到 DAG 正在运行:

转到图表视图,我们可以看到两个任务都成功运行了🎉:

但是显示一个随机生成的数字的task_2的打印输出呢?我们可以查看日志。
通过用户界面检查日志
在图形视图内,点击task_2,点击Log。

可以看到任务的输出:

再次成功🎉!
通过终端运行
对于取消暂停、触发和 DAG,UI 的替代方法非常简单。知道了 DAG 的 ID,我们只需要:
通过终端检查日志
假设您的 airflow 安装在$HOME目录中,可以通过执行以下操作来检查日志:
并选择正确的时间戳:
其中输出应包括:

后面是我们在这次运行中生成的实际数字。
结论
这是一个初学者友好的 DAG,使用了 Airflow 2.0 中新的 Taskflow API。不需要太多代码就可以创建一个简单的 DAG。在本系列的下一篇文章中,我们将使用@task_group装饰器创建并行任务。
原载于pedromadruga.com。
MLOps 的简单解释
原文:https://towardsdatascience.com/a-simple-explanation-of-mlops-e47009e245f7?source=collection_archive---------30-----------------------
以及相关的挑战

国家癌症研究所在 Unsplash 上拍摄的照片
也在 Datatron 博客分享: 什么是 MLOps?
终于!在过去的 8 年里,你一直为之工作的公司注意到了你的呼声,投资于机器学习——这是一项不断发展的壮举,将彻底改变我们所知的商业。你被安排负责发展数据科学团队,但这没什么大不了的,你的远见已经为你做好了准备。
在过去的 18 个月里,你在利润丰厚的数据科学圈子里流连忘返,并在空闲时间熟悉了这种文化,这让你有机会进入一些最有能力的数据科学圈子。由于对大量生产模型来解决人工智能兴起之前无法解决的问题的前景感到兴奋,你制定了一些演示项目来让事情运转起来。
6 周后,结果出来了,演示的性能指标也在不断提高。以前的内部人工智能怀疑论者一夜之间转变为人工智能的传播者。当高管们被告知时,他们的瞳孔开始放大,直到看起来像美元符号。“头奖宝贝!”一位高管尖叫道,“我们需要尽快投入生产。你多久能做到?”另一个问道。考虑到所有已经解决的复杂任务,人们会想象我们可以很快在美元中畅游。剩下要做的只是一些常规的开发工作,对吗?不对。
为了正确看待这一点,在 2019 年底进入 2020 年时,DeepLearning 中分享了一份报告。AI 的时事通讯, *The Batch,*称“研究发现,只有 22%使用机器学习的公司成功部署了一个模型。
"越来越多的公司正在开发供内部使用的机器学习模型。但许多公司仍在努力缩小与实际部署的差距。
(来源 : DeepLearning。艾,批量通迅)
了解我们在开发中使用机器学习时所面临的挑战,为 MLOps 的工作以及公司在工作流程中采用机器学习的重要性奠定了基础。
有哪些挑战?
我们可以从熟悉“DevOps”这个术语开始。DevOps 是软件工程领域的一套最佳实践,使得在几分钟内将软件交付到生产环境中成为可能,同时确保应用程序在生产环境中可靠运行。因此,可以说 DevOps 是统一软件开发和软件操作的软件工程实践。
DevOps =软件开发+软件运营
这就是问题所在。当构建传统的软件应用程序时,DevOps 团队最关心的是代码。另一方面,机器学习应用程序涉及代码和数据——实际上,这是机器学习应用程序和软件工程应用程序之间的根本区别。
部署到生产环境中的最终机器学习模型包含一个应用于大量数据(更好地称为训练数据)的算法,该算法实际上决定了模型在生产环境中的行为-模型的行为也取决于它在推理时接收的输入数据,但我们无法提前知道它会是什么。

作者图片
本质上,传统软件应用和机器学习应用中的代码都是在受控的开发环境中制作的。然而,机器学习应用程序也包括来自称为“真实世界”的永无止境来源的数据。数据不会停止变化,也没有办法完全控制数据应该如何变化。为了增强您对这个概念的理解,您可以考虑代码和数据之间的关系,尽管它们共享一个时间维度,但都生活在各自独立的平面中。

作者图片
平面之间的差距说明了一种脱节,这是几个重要挑战的根源,任何试图将机器学习模型成功部署到生产中的人都应该克服这些挑战。这些挑战包括:
- 部署缓慢
- 训练-发球偏斜(训练期间的表现和发球期间的表现之间的差异)
- 缺乏再现性
试图将机器学习模型部署到生产中的人的目标是弥合这两个层面之间的差距,进而克服如上所列的挑战。
最终想法
总之,MLOps 涵盖了在生产中高效、可靠地部署和维护机器学习系统的最佳实践。当在生产中工作时,机器学习引入了它自己的特定挑战。因此,MLOps 作为一门学科诞生于 DevOps,但却包含了传统 DevOps 工作流中不容易获得的机器学习中涉及的所有复杂内容。
相关文章
https://medium.datadriveninvestor.com/machine-learning-model-deployment-b1eaf7ca96cd
绩效指标的简单框架
原文:https://towardsdatascience.com/a-simple-framework-for-performance-metrics-cca97ddf91e5?source=collection_archive---------22-----------------------
轻松选择适合您问题的最佳指标

Clark Van Der Beken 在 Unsplash 上拍摄的照片
准确性、敏感性、特异性、F1 分数……—性能指标的列表似乎永无止境。尤其是如果你是数据科学的新手,你很容易感到在选择的海洋中束手无策。在这篇文章中,我想向你介绍一个对性能指标进行分组的框架,它们如何相互联系,以及你如何使用它来为你的问题和模型选择最佳指标。
绩效指标框架
你一定听说过一些指标,比如准确度、灵敏度、F1 分数、接收机工作特性(ROC)等等。但是当我开始深入研究它们时,我经常问自己,它们是如何相互联系的。过了一会儿,我偶然发现了由费里和他的同事提出的一个奇妙的框架,这个框架让我的事情变得简单多了。
基本上,我们可以将二进制分类任务的常见性能指标分为三类。它们中的每一个都有不同的用途:
- 阈值度量:检查您的模型是否满足预定义的阈值。
- 分级度量:将模型实例或完整的模型相互比较。
- 概率度量:测量你的分类的不确定性。
让我们按顺序看一下每一个:
阈值度量
这些是你的日常指标,比如准确性、F1、FDR,基本上是维基百科页面上列出的一切。它们的共同点是,您预先指定了哪些性能指标对您给定的问题很重要,并定义了您的模型需要通过的阈值。这就是这个名字的由来。如果你的模型没有通过你的门槛,它甚至不会被进一步考虑。
阈值度量基本上适用于所有的分类器算法,不管它们是直接输出类别标签(像简单的 k 均值或决策树)还是类别成员分数(像模糊 c 均值或逻辑回归)。
我不会详细讨论这些指标是如何计算的,这超出了本文的范围。如果您有兴趣了解各个指标,请查看参考资料,我在其中列出了一些优秀的资料。
我想说的是,如果你有一个平衡或不平衡的数据集,提前检查是非常重要的。对于不平衡的数据集,诸如准确度之类的常见度量已经不再适用,因为总是预测多数类的朴素分类器已经具有高准确度。取而代之的是,使用关注少数类的指标,这是约定俗成的积极类。
排名指标
当处理输出类成员分数的分类器时,排名度量特别有用。要将这个分数转换成一个清晰的类标签,您需要对分数应用一个阈值。但是如何选择这个门槛呢?排名指标让它变得轻而易举。让我们首先假设您有一个平衡的数据集:
训练完模型后,迭代所有可能的阈值,计算真阳性率和假阳性率。然后把这些互相勾连。你最终会得到所谓的接收机工作特性,简称 ROC:

接收器工作特性示意图。一个完美的分类器的 TPR 为 1,FPR 为 0,位于左上角(绿色星号)。无技能分类器发现的真阳性和假阳性一样多,用虚线表示。通过迭代模型的不同阈值,您可以生成一条描述模型行为的曲线(灰线)。比随机分类器差的分类器可以通过简单地选择其输出的反义词而被转换成熟练的分类器。这将反映其行为沿对角线(红星)。图片由作者提供。
一个完美的分类器应该在这个图的左上角。对角线描绘了一个没有技巧的简单分类器。你可以把它想象成一个简单地输出随机数,或者总是一个固定数的分类器。当你移动阈值时,你会偶然得到越来越多的真阳性,但同时你的假阳性也会同样增加。要选择最佳模型,只需选择最靠近左上角的点。你可以通过计算真阳性率——假阳性率(也称为约登 J 统计量)轻松做到这一点。
一个有趣的事实是,对角线以下的模型不一定比随机模型差。通过简单地反转模型输出,你基本上可以通过对角线来反映它的点,并可能获得一个非常熟练的模型。
对于不平衡数据集,对应的图是精度-召回曲线。这一次,最佳分类器位于右上方(与 ROC 相反,ROC 位于左上方),而朴素分类器将在数据集中的阳性部分产生一条穿过 precision(定义为 TP/ (TP + FP))的水平线。这是因为具有随机预测的无技能分类器也有机会将数据集预测为阳性(在精确度中不考虑阴性!).同时,通过移动阈值,无技能分类器将正确地识别越来越多的阳性,从而提高召回率(定义为所有阳性中的真阳性)。

不平衡数据集的精确召回曲线。完美的分类器现在在右上角(绿色的星星),而无技能的分类器总是有恒定的精度。迭代您的模型的阈值将产生类似于灰色线的行为。图片由作者提供。
要选择最佳阈值,计算 Precision + Recall,选择这个点的阈值(等于选择 F1 分最高的模型)。
概率度量
概率度量有点特殊,因为在这里我们不仅要评估我们的模型是否做了正确的分类,而且更感兴趣的是它对分类的确定程度。与排名度量一样,这些当然只能应用于输出类成员概率的模型(在评估它们之前可能需要归一化)。
使用概率度量,我们可以特别惩罚模型以高置信度进行错误分类,而模型输出不是非常确定的错误不会遭受如此高的代价。请注意,一个非决定性的模型通常在概率度量上也不会表现得很好,因为它们也奖励强而正确的预测。
最常见的概率度量是对数损失,也称为交叉熵。因为它对积极因素和消极因素的权重相等,所以您应该只将它应用于平衡的数据集。想象一个二元分类问题,我们用逻辑回归来拟合它:

测井曲线损失的直观解释。想象一个一维问题,其中每个点只是一个数字(x 轴)。对于每一个点,我们都知道属于阳性类别的真实概率,1 表示阳性(绿点),0 表示阴性(红点)。我们对我们的问题进行逻辑回归,以对这些点进行分类(灰线)。预测概率与真实概率之间的差异用于计算对数损失。图片由作者提供。
从我们的测试集中,我们知道给定点在正类中的真实概率,对于负类是 0,对于正类是 1。我们的逻辑回归分配一个在 0 到 1 范围内的概率。对数损失是基于我们的分配概率与真实概率的差异。对于每个点,我们计算对数损失并对所有点进行平均。

对数损失公式。y 这是我们的分类器分配给每个点的概率,即从上面的 s 形曲线上的值。图片由作者提供。
对于不平衡的数据集,您应该再次使用更侧重于积极类的度量,例如 Brier 分数。它被定义为正类的预期和预测概率之间的均方误差:

Brier 分数的定义。请注意,仅适用于正类,不适用于负类。图片由作者提供。
结论
我希望这个框架对你和对我一样有用。首先,决定与您的项目最相关的阈值度量,然后训练您的模型,并用排名度量对它们进行排名。最后,如果你有概率模型,考虑使用概率度量。
当然,困难的部分之一仍然是决定哪一个度量是最有意义的。为此,最好的方法通常是与领域专家深入讨论他们真正想要避免的错误。或者继续关注更多关于这个问题的内容。
参考
Ferri,Hernandez-Orallo & Modroiu (2009):分类性能测量的实验比较。模式识别字母
使用 Python 自动生成 Excel 报表的简单指南
原文:https://towardsdatascience.com/a-simple-guide-to-automate-your-excel-reporting-with-python-9d35f143ef7?source=collection_archive---------0-----------------------
使用 openpyxl 通过 Python 自动生成 Excel 报表

照片由 StockSnap 在 Pixabay 上拍摄
让我们面对它;无论我们的工作是什么,迟早,我们将不得不处理重复的任务,如在 Excel 中更新每日报告。如果你在一家不使用 Python 的公司工作,事情可能会变得更糟,因为你不能只使用 Python 来解决这个问题。
但是不要担心,您仍然可以使用您的 Python 技能来自动化您的 excel 报告,而不必说服您的老板迁移到 Python!你只需要用 Python 模块openpyxl告诉 Excel 你想通过 Python 做什么。与我之前写的鼓励您从 Excel 迁移到 Python 的文章不同,使用 openpyxl,您可以在使用 Python 创建报表时坚持使用 Excel。
**Table of Contents** 1\. [The Dataset](#3bf7)
2\. [Make a Pivot Table with Pandas](#e24a)
- [Importing libraries](#2541)
- [Reading the Excel file](#fdc1)
- [Making a pivot table](#b16b)
- [Exporting pivot table to Excel file](#cd3a)
3\. [Make The Report with Openpyxl](#4913)
- [Creating row and column reference](#67f0)
- [Adding Excel charts through Python](#8c6c)
- [Applying Excel formulas through Python](#e347)
- [Formatting the report sheet](#1600)
4\. [Automating the Report with a Python Function (Full code)](#5cd7)
- [Applying the function to a single Excel file](#30c9)
- [Applying the function to multiple Excel files](#77dc)
5\. [Schedule the Python Script to Run Monthly, Weekly, or Daily](#e271)
数据集
在本指南中,我们将使用一个包含销售数据的 Excel 文件,该文件类似于您用来制作工作报告的输入文件。你可以在 Kaggle 上下载这个文件;不过它有一个. csv 格式,所以你应该把扩展名改成.xlsx或者直接从这个 Google Drive 链接下载(我还把文件名改成了 supermarket_sales.xlsx)
在写任何代码之前,先看看 Google Drive 上的文件,熟悉一下。该文件将成为通过 Python 创建以下报告的输入。

作者图片
现在让我们制作报告,并用 Python 自动完成!
用熊猫做一张枢轴表
导入库
现在您已经下载了 Excel 文件,让我们导入我们将在本指南中使用的库。
import pandas as pd
import openpyxl
from openpyxl import load_workbook
from openpyxl.styles import Font
from openpyxl.chart import BarChart, Reference
import string
我们将使用 Pandas 来读取 Excel 文件,创建一个数据透视表,并将其导出到 Excel。然后我们将使用 Openpyxl 库编写 Excel 公式,制作图表,并通过 Python 格式化电子表格。最后,我们将创建一个 Python 函数来自动化这个过程。
注意:如果你没有在 Python 中安装那些库,你可以通过在你的终端或命令提示符上写 pip install pandas和pip install openpyxl 来轻松安装。
读取 Excel 文件
在我们读取 Excel 文件之前,请确保该文件与您的 Python 脚本位于同一位置。然后,像下面的代码一样读取带有pd.read_excel()的 Excel 文件。
excel_file = pd.read_excel('supermarket_sales.xlsx')
excel_file[['Gender', 'Product line', 'Total']]
该文件有许多列,但我们将只使用性别、产品线和总计列来创建报告。为了向您展示它们的样子,我使用了双括号来选择它们。如果我们把它打印在 Jupyter 笔记本上,你会看到下面这个看起来像 Excel 电子表格的数据框。

作者图片
制作数据透视表
我们可以很容易地从先前创建的excel_file 数据框架中创建一个数据透视表。我们只需要使用.pivot_table() 方法。假设我们想要创建一个数据透视表,显示男性和女性在不同产品线上的总花费。为此,我们编写以下代码。
report_table = excel_file.pivot_table(index='Gender',
columns='Product line',
values='Total',
aggfunc='sum').round(0)
report_table 应该是这样的。

将数据透视表导出到 Excel 文件
为了导出之前创建的数据透视表,我们使用了.to_excel()方法。在括号内,我们必须写出输出 Excel 文件的名称。在这种情况下,我将这个文件命名为report_2021.xlsx
我们还可以指定要创建的工作表的名称以及数据透视表应该位于哪个单元格中。
report_table.to_excel('report_2021.xlsx',
sheet_name='Report',
startrow=4)
现在,Excel 文件被导出到 Python 脚本所在的文件夹中。
用 Openpyxl 制作报表
每次我们想要访问一个工作簿时,我们将使用从openpyxl 导入的load_workbook,然后用.save() 方法保存它。在下面的部分中,我将在每次修改工作簿时加载并保存工作簿;但是,您只需要这样做一次(就像本指南末尾显示的完整代码一样)
创建行和列引用
为了使报告自动化,我们需要获取最小和最大的活动列/行,这样即使我们添加了更多的数据,我们将要编写的代码也会继续工作。
为了获得工作簿中的引用,我们首先用load_workbook()加载工作簿,并使用wb[‘name_of_sheet’]定位我们想要使用的工作表。然后我们用.active访问活动单元格
wb = load_workbook('report_2021.xlsx')
sheet = wb['Report']# cell references (original spreadsheet)
min_column = wb.active.min_column
max_column = wb.active.max_column
min_row = wb.active.min_row
max_row = wb.active.max_row
您可以打印所创建的变量,以了解它们的含义。对于这个例子,我们获得这些数字。
Min Columns: 1
Max Columns: 7
Min Rows: 5
Max Rows: 7
打开我们之前导出的report_2021.xlsx来验证这一点。

作者图片
如上图所示,最小行数为 5,最大行数为 7。同样,最小行是 A (1),最大行是 G (7)。这些参考资料对后面的章节非常有用。
通过 Python 添加 Excel 图表
为了从我们创建的数据透视表创建一个 Excel 图表,我们需要使用我们之前导入的Barchart模块。为了识别数据和类别值的位置,我们使用来自openpyxl 的Reference模块(我们在本文开始时导入了Reference)
wb = load_workbook('report_2021.xlsx')
sheet = wb['Report']# barchart
barchart = BarChart()#locate data and categories
data = Reference(sheet,
min_col=min_column+1,
max_col=max_column,
min_row=min_row,
max_row=max_row) #including headers
categories = Reference(sheet,
min_col=min_column,
max_col=min_column,
min_row=min_row+1,
max_row=max_row) #not including headers# adding data and categories
barchart.add_data(data, titles_from_data=True)
barchart.set_categories(categories)#location chart
sheet.add_chart(barchart, "B12")barchart.title = 'Sales by Product line'
barchart.style = 5 #choose the chart stylewb.save('report_2021.xlsx')
写完这段代码后,report_2021.xlsx文件应该是这样的。

作者图片
分解代码:
barchart = BarChart()从Barchart类初始化一个barchart变量data和categories是代表信息所在位置的变量。我们使用上面定义的列和行引用来实现自动化。另外,请记住,我在data中包括了标题,但在categories中没有- 我们使用
add_data和set_categories将必要的数据添加到barchart中。在add_data内部,我添加了titles_from_data=True,因为我包含了data的标题 - 我们使用
sheet.add_chart来指定我们想要添加到“报告”表中的内容,以及我们想要添加到哪个单元格中 - 我们可以使用
barchart.title和barchart.style修改默认标题和图表样式 - 我们用
wb.save()保存所有的修改
通过 Python 应用 Excel 公式
您可以通过 Python 编写 Excel 公式,就像在 Excel 表格中编写公式一样。例如,假设我们希望对单元格 B5 和 B6 中的数据求和,并在单元格 B7 中以货币样式显示。
sheet['B7'] = '=SUM(B5:B6)'
sheet['B7'].style = 'Currency'
这很简单,对吧?我们可以从 B 列到 G 列重复这个过程,或者使用 for 循环来自动执行。但是首先,我们需要让字母表作为 Excel 中列名的引用(A,B,C,…),为此,我们使用string库并编写以下代码。
import string
alphabet = list(string.ascii_uppercase)
excel_alphabet = alphabet[0:max_column]
print(excel_alphabet)
如果我们打印这个,我们将得到一个从 A 到 g 的列表。
发生这种情况是因为首先,我们创建了一个从 A 到 Z 的alphabet列表,但是然后我们取了一个切片[0:max_column]来匹配这个列表的长度(7)和字母表的前 7 个字母(A-G)。
注意:Python 列表从 0 开始,所以 A=0,B=1,C=2,依此类推。此外,[a:b]切片符号采用 b-a 元素(以“a”开始,以“b-1”结束)
在这之后,我们可以通过列进行循环,并应用求和公式,但是现在使用列引用,所以不用写这个,
sheet['B7'] = '=SUM(B5:B6)'
sheet['B7'].style = 'Currency'
现在我们包括引用,并把它放在 for 循环中。
wb = load_workbook('report_2021.xlsx')
sheet = wb['Report']# sum in columns B-G
for i in excel_alphabet:
if i!='A':
sheet[f'{i}{max_row+1}'] = f'=SUM({i}{min_row+1}:{i}{max_row})'
sheet[f'{i}{max_row+1}'].style = 'Currency'# adding total label
sheet[f'{excel_alphabet[0]}{max_row+1}'] = 'Total'wb.save('report_2021.xlsx')
运行代码后,我们在 B 到 g 之间的列的“总计”行中得到=SUM 公式。

作者图片
分解代码:
for i in excel_alphabet遍历所有活动列,但是我们用if i!='A'排除了 A 列,因为 A 列不包含数字数据sheet[f'{i}{max_row+1}'] = f'=SUM({i}{min_row+1}:{i}{max_row}'与编写sheet['B7'] = '=SUM(B5:B6)'是一样的,但是现在我们对列 A 到 G 也这么做sheet[f'{i}{max_row+1}'].style = 'Currency'为最大行以下的单元格赋予货币样式。- 我们用
sheet[f'{excel_alphabet[0]}{max_row+1}'] = 'Total'将“总计”标签添加到最大行下方的 A 列
格式化报告表
为了完成报告,我们可以添加一个标题,副标题,还可以自定义他们的字体。
wb = load_workbook('report_2021.xlsx')
sheet = wb['Report']sheet['A1'] = 'Sales Report'
sheet['A2'] = '2021'
sheet['A1'].font = Font('Arial', bold=True, size=20)
sheet['A2'].font = Font('Arial', bold=True, size=10)wb.save('report_2021.xlsx')
可以在Font()里面添加其他参数。在这个网站上,你可以找到可供选择的款式列表。
最终的报告应该如下图所示。

作者图片
使用 Python 函数自动生成报告
现在报告已经准备好了,我们可以将目前为止编写的所有代码放入一个自动生成报告的函数中,所以下次我们想要生成这个报告时,我们只需引入文件名并运行它。
注意:为了使这个函数工作,文件名应该具有“sales_month.xlsx”的结构。另外,我添加了几行代码,使用销售文件的月份/年份作为变量,这样我们就可以在输出文件和报告的副标题中重用它。
下面的代码可能看起来很吓人,但这只是我们目前为止所写的加上新的变量file_name, month_name, 和 month_and_extension。
将函数应用于单个 Excel 文件
假设我们下载的原始文件的名称是“sales_2021.xlsx ”,而不是“supermarket_sales.xlsx ”,我们可以通过编写以下内容将公式应用于报表
automate_excel('sales_2021.xlsx')
运行此代码后,您将在 Python 脚本所在的文件夹中看到一个名为“report_2021.xlsx”的 Excel 文件。
将函数应用于多个 Excel 文件
假设现在我们只有每月的 Excel 文件“sales _ January . xlsx”“sales _ January . xlsx”和“sales_march.xlsx”(你可以在我的 Github 上找到这些文件来测试它们)
您可以一个接一个地应用公式来获得 3 个报告
automate_excel('sales_january.xlsx')
automate_excel('sales_february.xlsx')
automate_excel('sales_march.xlsx')
或者您可以先使用pd.concat()将它们连接起来,然后只应用一次函数。
# read excel files
excel_file_1 = pd.read_excel('sales_january.xlsx')
excel_file_2 = pd.read_excel('sales_february.xlsx')
excel_file_3 = pd.read_excel('sales_march.xlsx')# concatenate files
new_file = pd.concat([excel_file_1,
excel_file_2,
excel_file_3], ignore_index=True)# export file
new_file.to_excel('sales_2021.xlsx')# apply function
automate_excel('sales_2021.xlsx')
安排 Python 脚本每月、每周或每天运行
您可以安排我们在本指南中编写的 Python 脚本在您的计算机上随时运行。你只需要分别在 Windows 和 Mac 上使用任务调度器或者 crontab 就可以了。
如果您不知道如何安排工作,请点击下面的指南了解如何安排。
就是这样!在本文中,您了解了如何自动化一个基本的 Excel 报表;然而,一旦你掌握了熊猫图书馆,你可以自己做更多的事情。在下面的链接中,你可以找到我专门为 Excel 用户写的熊猫的完整指南。
我还做了一个指南,帮助你用 Python 建立你的第一个机器学习模型。
你可以在我的 Github 上找到这个分析背后的代码。
与 3k 以上的人一起加入我的电子邮件列表,获取我在所有教程中使用的 Python for Data Science 备忘单(免费 PDF)
Python 中美丽可视化的简单指南
原文:https://towardsdatascience.com/a-simple-guide-to-beautiful-visualizations-in-python-f564e6b9d392?source=collection_archive---------0-----------------------
自定义 Matplotlib & Seaborn,永远忘记那些难看的蓝条。

本杰明·沃罗斯在 Unsplash 上拍摄的照片
你正在进行一个项目,突然你需要画一个图来分析数据或展示发现的见解。你没有太多的时间,但你肯定不想创造一个看起来像这样的情节。

作者图片
然而,你也不想太技术性,不想在一些不是你项目主要目标的事情上浪费更多的时间,那么你应该怎么做呢?
我不知道这种情况在过去发生过多少次,但是通过方便地使用 Matplotlib 和 Seaborn,我想到了一种简单而强大的方法来用 Python 创建好看且可读的可视化。忘记那些带有微小标签的蓝色条形图、直方图、箱线图、散点图和饼图,在这篇文章中,我将向你展示如何给它们一个更好的外观,而不会太专业和浪费很多时间。
**Table of Contents** 1\. [Globally Setting: Graph style and Font size](#aa59)
2\. [Customization of Plots](#8e90)
- [Color Palettes](#73cd)
- [Figure size, figure appearance, title, and axes labels](#e8c8)
3\. [The Dataset](#2362)
4\. [Bar Plot](#ef80)
5\. [Histogram](#efa5)
6\. [Boxplot](#10ec)
7\. [Scatterplot](#055e)
8\. [Piechart + Subplots](#beb4)
- [Single Piechart](#00c8)
- [Piechart side by side (subplots)](#ce2b)
9\. [Line Plot](#911b)
全局设置:图形样式和字体大小
让我更头疼的事情之一是单独设置图中的字体大小。这就是为什么在我们开始制作图之前,最好先全局设置它们。首先,让我们导入我们将在本文中使用的必要库。
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
注意:如果你没有在 Python 中安装这些库,你可以通过在你的终端上写 pip install name_of_library 来安装它们,或者在命令提示符下写下你想要安装的库(例如 pip install matplotlib)
现在,我们可以使用下面的代码轻松地全局设置图形样式和字体大小。
sns.set_style('darkgrid') # darkgrid, white grid, dark, white and ticksplt.rc('axes', titlesize=18) # fontsize of the axes title
plt.rc('axes', labelsize=14) # fontsize of the x and y labels
plt.rc('xtick', labelsize=13) # fontsize of the tick labels
plt.rc('ytick', labelsize=13) # fontsize of the tick labels
plt.rc('legend', fontsize=13) # legend fontsize
plt.rc('font', size=13) # controls default text sizes
首先,我们使用sns.set_style()来设置图形样式。默认情况下,这将使 Matplotlib 和 Seaborn 图形看起来更好。然后,我们使用plt.rc()来定制图形中显示的文本的字体大小。我个人的选择是标题用18,坐标轴上的文字用14 ,其余用13 。你可以随意编辑它们。
就是这样!您只需要这样做一次,就可以获得足够的字体大小和漂亮的图形样式。
地块定制
调色板
默认情况下,Matplotlib 的颜色很难看,但我们可以通过使用 Seaborn 调色板轻松地使它们更漂亮。这些是 Seaborn 的调色板,我们将在本文中使用。
sns.color_palette(‘deep’)

作者图片— Seaborn 调色板
sns.color_palette(‘pastel’)

作者图片— Seaborn 调色板
sns.color_palette(‘Set2’)

作者图片— Seaborn 调色板
这些调色板有一个列表的形式,所以你可以通过做sns.color_palette('deep')[0]从这些调色板中提取颜色,而不是使用传统的‘b’来获得蓝色。如果您执行这段代码,您将获得一个类似于(0.298, 0.447, 0.690)的 RGB 代码,它在 Matplotlib 的 plots 的颜色参数中被接受。我们将在创建图时更好地检查这一点。
在 seaborn 文档中,您可以找到可用调色板的列表。选择一个你喜欢的开始制作好看的图表。
图形大小、图形外观、标题和轴标签
在创建图表时,大多数时候我们需要做一些调整,这样任何人都会很容易理解我们的可视化。以下方法将在本文呈现的情节中反复使用,让我们习惯它们。
**如何调整身材大小?**我们使用plt.figure(figsize)来调整图形尺寸。我们还将使用tight_layout=True来清理一个情节或支线情节之间的填充。
plt.figure(figsize=(8,4), tight_layout=True)
如何编辑图形外观?我们将对情节做的一些基本调整是颜色和线宽。出图时,它们作为额外参数包含在内。
# matplotlib
plt.hist(..., color=sns.color_palette('Set2')[2], linewidth=2)# seaborn
ax = sns.histplot(..., palette='Set2', linewidth=2) # seaborn will have either the color or palette parameters available (it depends on the plot)
如何添加支线剧情(并列剧情)?我们将需要plt.subplots()来制作并排图。
#subplots
fig, ax = plt.subplots(nrows=1,ncols=2, figsize=(12, 5), tight_layout=True)
创建完支线剧情后,我们将使用一维轴ax[0]或二维轴ax[0][0]
如何给剧情添加标签和标题?在 Matplotlib plt.xlabel()和 Seaborn ax.set_xlabel()之间,向轴添加标签和设置标题名称是相似的,但是我更喜欢在 Seaborn 中使用ax.set() 变体,因为它在一行中处理大多数参数。
# matplotlib
plt.xlabel('Nationality')
plt.ylabel('Average Rating')
plt.title('Barplot')#seaborn
ax.set(title='Barplot', xlabel='Nationality', ylabel='Average Rating')
数据集
为了制作有意义的图表,我们需要使用数据集。为了简单起见,我选择了一个在 Kaggle 中可用的干净数据集,你也可以在我的 Github 中找到它。这是一个国际足联球员的数据集,它将帮助我们比较美国和加拿大等非传统足球国家与英格兰、巴西和阿根廷等足球大国。希望在这篇文章的结尾,我们能更好地理解是什么让足球在这些国家变得不同。
在接下来的小节中,我们将使用一个名为df_country 的数据框架,它将只包含有问题的国家。下面的代码会解决这个问题。
df_fifa21 = pd.read_csv('players_20.csv')
country = ['United States', 'Canada', 'England', 'Brazil', 'Argentina']df_country = df_fifa21[df_fifa21[‘nationality’].isin(country)]
现在让我们创建好看的可视化!
条形图
使用 MatplotLib 和 Seaborn 都可以很容易地创建条形图,只是略有不同。条形图将使用矩形条显示分类数据,矩形条的高度或长度与它们所代表的值成比例。看看各国足球运动员的平均得分会很有趣
下面的代码显示了这个绘图所需的额外预处理。
# Preprocessing
barplot = df_country.groupby(['nationality'], as_index=False).mean()[['nationality', 'overall']]
输出如下所示:
nationality overall
Argentina 69.118510
Brazil 71.143894
Canada 62.855072
England 63.253293
United States 64.538682
MatplotLib 中的条形图与 plt.bar()
MatplotLib 的plt.bar() 需要两个参数——分类变量的名称(国籍)和长度(总体评分)。
plt.figure(figsize=(8,4), tight_layout=True)
colors = sns.color_palette('pastel')plt.bar(barplot['nationality'], barplot['overall'], color=colors[:5])plt.xlabel('Nationality')
plt.ylabel('Average Rating')
plt.title('Barplot')
plt.show()
正如我们之前提到的,为了让条形图更有吸引力,我们将使用 Seaborn 调色板。在这种情况下,我们使用了pastel 调色板。

作者图片
显然,来自加拿大、美国和英国的普通球员的评价没有太大的区别。然而,普通球员进不了国家队,只有每个国家的顶级球员才能进,所以如果我们得到前 20 名球员的平均评分,情节就会改变。让我们和 seaborn 核实一下。
使用 sns.barplot()在 Seaborn 中绘制条形图
为了得到每个国家的前 20 名球员,我们需要做一些预处理
# preprocessing
new_df = pd.concat(
[df_country[df_country['nationality']=='Argentina'][:20],
df_country[df_country['nationality']=='Brazil'][:20],
df_country[df_country['nationality']=='England'][:20],
df_country[df_country['nationality']=='Canada'][:20],
df_country[df_country['nationality']=='United States'][:20]]
)barplot = new_df.groupby(['nationality'], as_index=False).mean()[['nationality', 'overall']]
现在可以绘制数据了。我们将使用sns.barplot()来这样做。
plt.figure(figsize=(8,4), tight_layout=True)
ax = sns.barplot(x=barplot['nationality'], y=barplot['overall'], palette='pastel', ci=None)
ax.set(title='Barplot', xlabel='Nationality', ylabel='Average Rating')
plt.show()

作者图片
顶尖选手之间的收视率差距可见一斑。这揭示了为什么美国和加拿大还不是足球大国,但这并不是全部,让我们深入挖掘。
按“n”个变量分组的条形图
现在让我们看看有多少球员在顶级足球联赛中踢球。为此,我们需要按国籍和联赛对数据进行分组(我们将忽略英超联赛,因为大多数英格兰球员都参加这项比赛)
# Preprocessing
barplot = df_country[df_country['league_name'].isin(['Spain Primera Division', 'Italian Serie A', 'German 1\. Bundesliga'])]barplot = barplot.groupby(['nationality', 'league_name'], as_index=False).count()
现在数据已经准备好了,我们可以用 Matplolib 或 Seaborn 绘制它;然而,为了保持简单并避免编写更多的代码行,我们将使用 Seaborn。通过添加hue=‘’ 参数,可轻松绘制由“n”个变量分组的数据。
plt.figure(figsize=(12, 6), tight_layout=True)ax = sns.barplot(x=barplot['nationality'], y=barplot['sofifa_id'], **hue=barplot['league_name']**, palette='pastel')ax.set(title='Nº of Players outside of domestic league' ,xlabel='Country', ylabel='Count')
ax.legend(title='League', title_fontsize='13', loc='upper right')
plt.show()
我们用ax.legend() 单独处理了图例选项,得到了下面的图。

作者图片
正如我们所见,大多数阿根廷和巴西足球运动员都在顶级联赛踢球,而加拿大人和美国人却没有。顶级联赛的球员对国家队在比赛中的成功产生影响,所以这解释了为什么巴西和阿根廷是足球大国。
柱状图
直方图表示数字数据的分布。我们来看看足球运动员的身高分布,分析一下它在这项运动中的相关性。
带 plt.hist()或 sns.histplot()的直方图
MatplotLib 的plt.hist() 和 Seaborn 的sns.histplot()工作原理相同。两者都需要两个参数——数值变量的名称(高度)和容器的数量或列表。在本例中,我们制作了一个名为bins的箱子列表,它将显示在 x 轴上。
plt.figure(figsize=(10,6), tight_layout=True)
bins = [160, 165, 170, 175, 180, 185, 190, 195, 200]# matplotlib
plt.hist(df_country['height_cm'], bins=bins, color=sns.color_palette('Set2')[2], linewidth=2)
plt.title('Histogram')
plt.xlabel('Height (cm)')
plt.ylabel('Count')# seaborn
ax = sns.histplot(data=df_country, x='height_cm', bins=bins, color=sns.color_palette('Set2')[2], linewidth=2)
ax.set(title='Histogram', xlabel='Height (cm)', ylabel='Count')plt.show()

作者图片
直方图显示,大多数球员的身高都在 175-185 厘米之间,因此身高超过 185 厘米似乎在足球中并不那么重要。让我们用箱线图来看看不同国家运动员的身高分布。
箱线图
箱线图显示基于最小值、第一个四分位数(Q1)、中值、第三个四分位数(Q3)和最大值的数据分布。在这种情况下,我们将制作一个箱线图,显示 5 个国家运动员的身高分布。
可以在 Matplotlib 上绘制多个分类变量的箱线图,但是它需要一些额外的预处理,所以为了简单起见,我们将使用 Seaborn 的sns.boxplot()。制作包含多个分类变量的箱线图时,我们需要两个参数——分类变量的名称(国籍)和数值变量的名称(高度 _ 厘米)
plt.figure(figsize=(10,6), tight_layout=True)ax = sns.boxplot(data=df_country, x='nationality', y='height_cm', palette='Set2', linewidth=2.5)
ax.set(title='Boxplot', xlabel='', ylabel='Height (cm)')plt.show()

作者图片
现在,箱线图显示,一个国家队不需要很多高大的足球运动员就能在比赛中取得成功,因为阿根廷和巴西的中位数低于其他国家。阿根廷甚至出现了以长底须为代表的五个国家中最矮的足球运动员。
散点图
散点图显示数据集中两个数值变量之间的关系。在这种情况下,我们将看到球员的身高和体重之间的关系。
plt.figure(figsize=(10,6), tight_layout=True)ax = sns.scatterplot(data=df_country, x='height_cm', y='weight_kg', **hue='nationality'**, palette='Set2', **s=60**)ax.set(xlabel='Height (cm)', ylabel='Weight (kg)')
ax.legend(title='Country', title_fontsize = 12)
plt.show()
在这个图中,我们添加了s来控制点的大小,还添加了hue 来区分国籍

作者图片
从这个散点图中,我们可以看到体重和身高的分布符合简单的线性回归。
饼图+支线剧情
单饼图
我们要做一个显示玩家价值的饼状图。在这个例子中,我们将选出 USMNT (Pullisic)中最有价值的球员,看看他在他的俱乐部中有多有价值。
# Preprocessing
piechart = df_fifa21[df_fifa21['club_name']=='Chelsea']
piechart = piechart.sort_values('value_eur', ascending=False)[['short_name', 'value_eur']]
piechart = piechart[:11]
现在数据已经准备好了,我们可以用 Matplolib 的plt.pie()制作一个饼状图。除了我们通常添加的参数,我们还将考虑autopct 对数字进行舍入,explode突出显示特定的球员,pctdistance调整标签的距离,shadow=True给图表一个坚实的外观。
colors = sns.color_palette('pastel')
plt.figure(figsize=(7, 6), tight_layout=True)
explode_list = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2]plt.pie(piechart['value_eur'], labels=piechart['short_name'], **autopct**='%.0f %%', **explode**=explode_list, **pctdistance**=.7,
colors=colors, **shadow**=True)plt.title('Chelsea', weight='bold')
plt.show()

作者图片
这张饼状图显示,普利奇不是他所在俱乐部最有价值的球员,但至少他排在前 11 名。
并排饼图(支线剧情)
现在让我们并排绘制两张饼状图,看看这名球员对他的俱乐部和国家队的影响。为此,我们将使用plt.subplots(nrows, ncols)。这里行和列决定了我们要创建的图的数量,所以nrow=1和ncols=2 意味着每列 1 个图(总共 2 个)。
#subplots
fig, ax = plt.subplots(1,2, figsize=(12, 5), tight_layout=True)
此外,除了之前创建的piechart ,我们还需要创建第二个饼图框架piechart2。
# Preprocessing
piechart2 = df_fifa21[df_fifa21['nationality']=='United States']
piechart2 = piechart2[:10].sort_values('value_eur')[['short_name', 'value_eur']]
现在我们可以并排绘制两个饼图。

作者图片
现在我们可以验证,普利奇是迄今为止最有价值的美国球员,但在他的俱乐部里,前面还有其他技术娴熟的球员。
线形图
我们将绘制顶级足球运动员的评分图,看看评分在过去 5 年中是如何演变的。为此,我们必须读取 2017 年的国际足联数据集,并争论这些数据。
上面的代码给出了一个可以绘制的数据集。

作者图片
使用 plt.plot()在 Matplolib 中绘制线图
制作线图就像在 Matplotlib 上输入plt.plot() 一样简单,但是我们会做一些简单的定制来使它看起来更好。
plt.figure(figsize=(10,6), tight_layout=True)#plotting
plt.plot(lineplot, 'o-', linewidth=2)#customization
plt.xticks([2017, 2018, 2019, 2020, 2021])
plt.xlabel('Years')
plt.ylabel('Ratings')
plt.title('Rating troughtout the years')
plt.legend(title='Players', title_fontsize = 13, labels=['L. Messi', 'Cristiano Ronaldo', 'K. De Bruyne', 'V. van Dijk', 'K. Mbappé'])
plt.show()
使用上面的代码,我们生成了下图。

作者图片
使用 sns.lineplot()在 Seaborn 中绘制线图
我们也可以很容易地用 seaborn 制作这个情节。
plt.figure(figsize=(10, 5))
ax = sns.lineplot(data=lineplot, linewidth=2.5)
ax.set(xlabel='Year', ylabel='Ratings', title='Rating troughtout the years', xticks=[2017, 2018, 2019, 2020, 2021])
ax.legend(title='Players', title_fontsize = 13)
plt.show()
运行这段代码后,我们应该会得到一个类似上面的图。
就是这样!在本文中,我们学习了如何使用 Matplotlib 和 Seaborn 制作漂亮的情节。所有代码在我的Github上都有。
感谢阅读这篇文章!在下面的文章中,我展示了制作热图、文字云的代码,以及如何在不编码的情况下制作交互式可视化。
</8-free-tools-to-make-interactive-data-visualizations-in-2021-no-coding-required-2b2c6c564b5b>
https://frankandrade.ck.page/bd063ff2d3
