TowardsDataScience 博客中文翻译 2021(三百零三)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

从 Python 到 Go

原文:https://towardsdatascience.com/from-python-to-go-901cea46446f?source=collection_archive---------5-----------------------

通过翻译 Python 代码学习围棋编程

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

图片由亚瑟·拉文伯格·德恩拍摄

我希望这篇文章既可以作为想要学习围棋的 Python 爱好者的字典,也可以作为那些了解 Python 并且只想快速入门 Golang 的人的入门指南。

在我们开始之前,我想简单解释一下为什么在你已经了解 Python 的情况下学习 Go 可能是一个很好的选择。

介绍

首先,我并不是说 Go 是比 Python 更好的语言。Python 是一种很棒的语言,通常是比 Go 更好的选择。这当然取决于你试图解决的问题或者你想要构建的应用程序,但是 Go 确实有很多 Python 没有的东西。

  1. 围棋很快——真的很快!在这个参数上,Go 以几乎类似 C 的速度将 Python 打得落花流水。这部分是因为 Go 是一种静态类型语言,具有优化的、速度极快的编译器,这使得 Go 的开发速度和执行速度都很快。
  2. 开发者友好。尽管围棋的速度很快,但写字的速度却快得惊人。我认为这有几个原因。首先,在围棋中你只有你真正需要的东西,所以你很少会怀疑在哪里用什么。语法清晰易读。甚至在语法上,它也清除了难看的括号和其他不必要的语法。其次,Go 解释器非常聪明,Go 的类型系统在缺少不必要的声明和保护未使用的导入和函数参数中未声明的数据类型的保存系统之间取得了很好的平衡。
  3. 内置的并发和并行。Go 是一门年轻的现代语言,如果你曾经尝试过用 Python 运行一些并行计算的大型项目,你就会知道这是一种痛苦。但在围棋中,却不是。你有被称为 goroutines 的绿色线程,你有通道,这是一种数据结构,它使得并行工作器能够相当安全地相互通信。您还有一种方法来锁定像数组这样的容器以避免竞争情况(如果通道的默认阻塞特性还不够的话),当然还有一种方法来确定运行哪个 goroutine 的优先级,以及一种称为 waitgroup 的同步特性。
  4. 低水平。尽管 Go 是一种开发人员友好的多用途编程语言,但它是非常低级的。也就是说,你对你的机器有很大的控制权。Docker 和 Kubernetes 就是用这种高性能的低级语言构建的一些例子。想一想,仅仅为了创建一个 Docker 容器,您就必须进行系统调用!

走吧。

在本文中,我们将开始从一种语言到另一种语言的句法之旅。也就是说,我还将讨论风格和结构,因为正如你们都知道的,一行一行的直接翻译是不好的,不管是什么语言。

请注意,这是一篇短文,已经跳过了 Go 的某些功能。也就是说,我已经试着包含了最重要的部分,所以这是尽可能独立的,这样你就可以对这门语言有一个全面的了解,并且实际上学习一些围棋。

事不宜迟,让我们直接进入主题,简单讨论一下导入、数据类型和变量声明。

开始

当你来自 Python 时,在 go 中第一件突出的事情是,在每个 Go 文件中,你需要指定什么叫做*包。*我不会详细讨论包和 go 项目的结构,因为这篇文章是关于语法的,但是可以说,如果两个文件在同一个包中,那么它们可以访问彼此的内容。

所以你从声明一个包开始,如果你想在你的文件中有你的执行起点,那么你应该把这个包命名为 main。**主关键字是 Go 中的一个特殊单词,意思是“这是程序开始的地方”。

功能

对于 Python 程序员来说,第二件陌生的事情是,你不需要主动声明运行哪个函数,因为在 Go 中,你总是运行名为 main 的函数。这也意味着如果你想运行任何东西,你必须在 Go 中创建这样一个函数。

在创建函数之前,您可以选择导入内容。这是您应该从 Python 中认识到的最后一点。

让我们看看每种语言中的一些“Hello World”程序,看看可能的开始是什么样子的。

Python 文件实际上不需要注释。与 Go 相比,唯一有趣的是,您需要指定要运行哪个函数,并且不需要导入任何东西。

然而,Go 文件已经有了很大的不同。您指定了一个包(如果不指定,您将会得到一个错误),并且您需要导入一个 format- lib 来执行 IO 操作。您还需要创建一个名为 *main、*的函数,它将在任何情况下运行,Go 中的函数是使用 func 语句创建的,当然在 Python 中我们使用 def

要运行名为" main.go 的 Go 文件,您只需打开一个终端或 shell 环境,确保您位于文件所在的文件夹中,并键入:

go run main.go

需要告诉 Go 函数哪些数据类型可以作为输入和输出。

func calc(number int) float64 {
...
return result
}

这在很多方面都是一件好事,因为它避免了很多错误。它只是更安全。

现在我们已经到了 shell、terminal、cmd、powershell 或您喜欢使用的任何程序,有一些 Go 命令您应该知道。

  • go run 会编译并运行你的文件。
  • 去构建会编译你的文件,构建一个可执行文件,然后你可以和你的朋友分享,并删除他们的硬盘:-)(如果你想留住你的朋友,也许只是做一个游戏)。
  • Go get 是另一个不错的命令,可以让你直接从 Github 这样的在线资源下载 Go 包。

当然还有很多更好的 Go 命令,但我不会破坏所有的乐趣。

数据类型和日常语法

两种语言都有常见的数字类型,如 int、float 等。,所以就不一一赘述了。但是,我们需要了解一些数据类型。

用线串

Go 中的字符串很像 Python,但是字符串所需的许多操作可以在需要导入的库中找到。即字符串库。

切片和阵列

在 Go 中,有两个类似 Python 列表的主要容器。数组和切片。数组有预先指定的元素数量,当您知道需要在变量中存储多少元素时,可以使用数组。此外,数组中只能有一种数据类型。

切片更加灵活,更像 Python 的列表。它们是可变的,可以存储任意数量的元素。但是它们与 Python 列表的不同之处在于,它们也只能存储一种数据类型。然而,有一种方法可以解决单数据类型的问题,我将在后面讨论。

让我们来看看语法。

请注意,我们使用符号:=来简化声明和实例化。这在很多情况下是没问题的,但是只在函数内部。

您可以在外部作用域中声明变量,但语法不同。你需要做一些像

var b uint = 5

当你像这样声明一个变量时,你可以更好地控制你的数据类型。这里我声明了一个无符号的 int(表示一个非负整数)。我不能用上面的简写来这样做,因为 Go 会认为 b 是 int 类型的。

你可以试着运行上面的代码片段。你会看到我们分别打印出数组的类型和切片的值。

一旦你声明了,比如说,一个切片,当然会有很多相关的语法。实际上很像 Python 的语法。

有时我们说 s 是一个“字符串片段”,以明确数据类型。

当然现在 Python 有了更多的容器类型。例如,Python 的 dict 等价于什么?

地图

像许多其他语言一样,Go 选择调用它们的 hashmap map。

它们很像 Python 的字典。

在 Go 中创建地图的方法有几种,但是一旦创建,Pythonistas 就会非常熟悉。

循环和控制流

在 Python 中,我们当然有 for 循环和 while 循环。Go 的目标是更严格一点,所以他们只有一种语法(或多或少)和一种循环类型。为循环。

但是 Go 的 for 循环与 Python 的不同之处在于,它需要被停止,否则它就不会停止,然后你就有了 while 循环。

让我们比较两种语言中的一些代码。

我将在 Go 文件中添加一些内容,解释一些语法。

我认为在这里有几点意见是适当的。请注意,Go 使用花括号代替缩进,并且没有类似 C 语言中的括号。您还可以在这里看到如何在 Go 中编写 if-else 子句,还要注意这里没有括号,并且 else 关键字应该在两个花括号之间。

当我们迭代一个像上面的数字这样的迭代器时,Go 有一个名为范围的关键字使这成为可能,并默认返回一个索引。Go 支持多种输出,你需要学习何时何地输出什么的基本知识。

经验法则是索引输出到值的左边,布尔值和错误输出到右边。当我们继续看例子时,你可以记住这一点。

如果你没有使用元素的索引,那么你只需要在它的位置使用一个下划线。

for _, number := range numbers {...

在上面的循环片段中,我们使用了一个空的 for 循环作为 Python 中的“while True”。在 Go 中,还可以使用布尔类型(在 Go 中称为 bool ),这样就变成了真正的 while 循环。

for someBool {...

Go 还有一个 else-if 语句,相当于 Python 的 elif 当然,语法是

} else if ... {

转换

当一个值有多种可能性,并且需要在程序中进行有效的控制流时,Go 中的 switch 语句非常有用。在 Python 中,你必须做很多 if-elif-else 语句,但是在 Go 中你可以做以下事情。

这个语法几乎是不言自明的。如果没有其他选择,默认块将运行,类似于“else”。这不是强制性的,您可以跳过它,如您在顶部开关块中看到的那样。注意,Go 在这里借用了 Python 中的冒号和缩进,以使其可读性更好。

错误处理

在 Go 中,错误处理与许多其他语言有很大不同。我个人喜欢,但不是所有人都喜欢。

Go 中的错误通常是从函数中返回的。所以下面是一个常见的模式

你当然可以打印错误信息或者让 go 在所谓的死机中关闭。这条线

panic(message)

将打印出消息并关闭程序。

两颗北极指极星

Go 是一种低级编程语言。这意味着你可以很好地控制你的电脑。特别是,你可以用指针访问内存地址。这有很多好处。当您需要对某个数据类型(比如某个函数或方法)进行永久更新时,这尤其有用(后面会详细介绍)。

指针的语法很简单,非常像 c 语言。

在下面的例子中,我们创建一个 int a 并获取它的内存地址,并将其存储在变量 b 中。

这段代码将打印出如下内容

0xc0000140b8
5

注意,我们使用解引用操作符(星号)*来取回内存地址保存的值。

结构和方法

当然,Python 是一种面向对象的编程语言,也就是说,它支持这些被调用对象的类和实例。事实上,在 Python 中,几乎所有东西都是对象。从函数到字符串和生成器,它们都是对象。如果你不相信我,你可以试着在一些数据上调用内置函数 dir ,打印输出,你会看到你可以在给定对象上调用的属性和方法。

在围棋中,事情就大不一样了。

Go 不是面向对象的语言,因此它没有类、类方法或对象。然而,正如你现在将看到的,它确实有对等物。

Go 有*结构。*像 C 语言中一样,这些类似于 JavaScript 中的对象,在某种意义上类似于 Python 中只有字段的类。

基本语法如下:

你可以在 Go 中使用 type 关键字创建一个 struct,这个想法就像 Python 中的类一样,你可以创建自己的数据类型。

像类一样,Go 也提供方法,它们非常像 Python 的方法,除了它们不是在结构内部定义的,而是在结构外部定义的。

让我们看看他们的行动。在上面增加以下内容。

你可以看到我们在 Go 中定义方法的方式很像函数,除了我们在参数前的括号中定义它属于哪个结构。

还要注意,它接受指针类型,而不是结构本身的实例。如果我去掉星号,简单地创建一个如下形式的方法

func (p person) setSkill(skill string) {
p.skills = skill
}

那这个就不行了。原因很简单。我想永久地改变该结构的实例!我不想只得到改变后的值,而让它保持不变。我当然可以这样做,但这不会永远改变结构。相反,如果我在内存地址(指针指向的地方)改变值,那么结构体的实例就会改变值,直到我们再次改变它。

那么你可能会问,为什么(在第 12 行)我们不需要传递一个指向方法的指针?我们有 p 而没有T10 p

好吧,实际上你可以这样做

(&p).setSkill("Coding Go")

但是 Go 编译器足够聪明,能够理解你想要的实际上是一个指针,而不是结构本身的实例,所以这只是上面括号中的语法糖——丑陋。

方法中指针的概念会让很多初学者感到困惑,但是你应该记住,如果你想永久地改变一些东西,那么就使用指针方法。如果你只是想使用一些值,那么使用结构本身。

接口

Go 的一个非常好且有用的特性是接口的概念。你应该把一个接口看作是一个共同的标准,它把具有相同方法的结构粘合在一起。

更准确地说,接口是方法的集合,所以如果一个结构正好有那些方法,那么它满足接口,我们可以互换使用接口和结构及其方法。

假设我有一个圆形结构和一个方形结构。它们都有周长方法和面积方法,具有相同的参数和输出。

然后我们可以声明一个包含这些类型方法的 shape 接口。

让我们看一个这种情况的经典例子,注意我们导入的包周围的括号——这是多个导入的语法。

重点是,即使函数 measure 采用一种类型的形状,也可以接受类型的矩形圆形。这个概念被称为多态性,Go 通过接口支持它。

你有没有想过 Println 函数如何能够打印不同的字体,或者 len 函数如何能够计算不同字体的长度?

这是因为接口。

当然,在 Python 中,这也是可能的,因为它是面向对象的语言。您可以简单地访问 dunder-method len()并返回它。

一个非常有用的界面的例子是空界面。

interface{}

每个结构都满足空接口,因此这个接口表示任何类型。

还记得我告诉过你,在数组和切片中有一个单一类型的解决方案吗?答案是接口。

我们可以对某个接受多种类型的接口做一个切片。下面的方法可行。

d := []interface{}{1, "Kasper", 3.2, 'A'}
fmt.Println(d)

注意,切片的最后一个条目是一个用单引号括起来的字符

空接口是一个不错的技巧,但不完全是最佳实践。为了避免错误,人们应该总是尽可能地严格。也就是说,可能没有其他解决办法。

并发和 Goroutines

在很多情况下,用 Python 并行化代码是一个挑战。

现在,Go 是一种现代语言,内置了对并发性和并行性的支持。他们甚至有一个关键词。

当然,重要的是要意识到并发和并行计算是不同的。这本身可能是一整篇文章。高层的理解就目前而言已经足够了。

也就是说,并行计算是指 CPU 在同一时间进行多项计算(使用多个内核或线程)。并发性意味着程序在并行工作器(或线程)之间切换上下文,以便当一个工作器无法继续工作时(由于某种原因被阻塞,或者只是必须等待,例如服务器响应),上下文切换到准备好的工作器,然后从它停止的地方继续工作。这并不意味着工人们同时做任何事情。

在 Go 中可以很容易地做这两件事,而且在很多情况下,你可以同时做这两件事,而 Go 编译器甚至不会让你知道。

在我们开始这条迷人的道路之前,让我们先从你已经遇到过的东西开始,即主要的 goroutine。

无论如何都要运行的主函数实际上是所谓的 goroutine(在其他语言中也称为绿色线程)。它总是在跑。

你应该把一个围棋程序想象成一条河,在这条河中,主线索就是主河流,如果你愿意,这条河的小分支可以产生或分支。

这些分支河流被称为 goroutines,用关键字 go 来命名

请注意背景字符串是如何以没有明显顺序的方式并行打印出来的。这就是在 Go 中并行化代码有多容易。

当然,由于 rase 条件、不安全的数据传输和同步问题,这带来了潜在的危险,但 Go 是智能构建的,因此当然有解决所有这些问题的解决方案。

频道

Go 中的 Channels 是一种数据类型,可以以相对安全的方式将数据从一个 goroutine 传输到另一个 Go routine。

一个例子:

在上面的代码片段中,发生了以下情况:

首先,我们创建一个名为*消息、*的通道,然后我们从主例程中分支出一个匿名函数(比如 Pythons lambdas ),将消息“ping”发送到通道中。此时,通道被阻塞。如果另一个 goroutine 试图发送消息,该消息将在队列中结束,等待通道被清空/读取,以便它可以接收另一个消息。你可以使用所谓的缓冲区来创建通道,缓冲区可以在阻塞之前接受 x 个消息,但我们不会对此进行详细说明。

然后,我们读取第 11 行的消息,并将其存储在一个名为 msg 的变量中。然后,当然,我们把它打印到控制台上。

关于 Go 程序的生命周期,有一点需要注意。当 main 函数完成时,所有其他 goroutines 也退出,即使这些函数没有完成并且没有返回任何东西。为了展示这一点,让我们来看看下面的内容。

如果你试着运行这个,你会发现我们没有得到一个 ping!这是因为 main 函数(goroutine)在匿名 goroutine 开始打印任何东西之前就结束了。然而,如果你等待它,它会得到打印的东西。下面将打印出所有的 pings。

这是可行的,但不是最佳实践。

在围棋中,我们有所谓的等待组。它的目的是同步所有的 go routine,这样当 main 函数返回时,所有的 go routine 也返回了。

这段代码要好得多,但需要一些解释。

  • 我们已经将函数从匿名函数改为普通函数,只有被调用时才会运行。我们称这个函数为计数
  • 回到主函数中,我们声明一个 WaitGroup 类型的名为 wg 的变量。这基本上是一个计数器。当工作组。Add(x)被调用我们把 x 加到计数器上,当 wg。Done()被称为我们减去 1。
  • 函数 counting 有一个指向 waitgroup 的*类型的参数。*指针类型是必需的,因为记住我们想要从等待组中永久地 subract 1。
  • counting 函数内部的 defer 语句的意思是“在返回之前,将以下操作作为最后一个操作”。这非常有用,因为有时很难知道事情会以什么顺序发生。在我们的例子中,我们告诉 waitgroup 我们完成了,waitgroup 计数器减 1。
  • 在后台运行函数计数作为 goroutine 之后,我们调用 wg。Wait()将等待 waitgroup 计数器变为 0,然后移动到下一行。

waitgroup 的规则是,每次运行 goroutine 时,都需要向 wait group 添加 1。每当一个 goroutine 返回,你应该减去 1。然后等待所有人完成 wg。等待()。

然而,还有另一种不用等待组的方法。

事实证明,您可以在一个通道上循环,并且只有当通道关闭时,这才会停止。所以这种阻塞特性经常被用来同步你的 goroutines。查看下面的代码,它将给出与上面相同的输出。

非常整洁!我们给函数 counting 一个通道作为参数,并使用该通道与主 goroutine 通信,我们将在该通道上循环并打印出所有发送的消息。回到计数,我们在退出函数之前关闭通道,在主函数中我们现在知道通道已经关闭,我们可以继续了。

select 语句

有时你有多个通道可以读取,很难事先知道哪个通道准备好被读取。你当然不想浪费任何时间,那么我们如何解决这个问题?

答案是另一项名为的杰出发明 select 语句。看看下面的例子。

select 语句与 switch 语句非常相似,只是它在通道之间进行选择。上面是一个很好的例子,说明了什么时候这是有用的。当 c1 准备好被读取时,没有理由等待 c2 通道。这样做的结果是,运行这个只需要 2 秒钟,而不是 3 秒钟。

select 语句还有一个默认的 case,这也非常有用。

命名约定和公共变量

你可能已经注意到,我倾向于保持变量名很短,而不是像 Python 中那样。这其实是故意的。

你看,Go 语言的一部分就是简单性、有效性和简短的名字。这不是开玩笑!当然,和往常一样,名字应该是描述性的,但是你不需要太多。例如,循环中的伪变量应该是一个字母的名称,函数名应该是一个单词,等等。当对审阅者、读者或同事有意义时,使用速记。

此外,变量应该是骆驼大小写,而不是下划线。

但是有一件重要的事情你需要知道。变量首字母的大小写很重要!

在 Go 中,如果你想导出函数和变量以便在其他文件中访问它们,它们应该以大写字母开头。就是这样。然后你就可以从外面接近它们了。如果它们以小写字母开头,那么它们是私有变量,只能在你的文件或作用域中访问。

从这里去哪里

我会推荐一个 Go 连同其他几个链接的游览。

我希望你学会了一些围棋,并享受这一旅程。我相信这种语言将成为世界上最受欢迎和最受欢迎的语言之一,当然,它已经相当受欢迎了。

理解这种语言有时会有点困难,因为很多标准库在幕后使用接口来做各种各样的事情,比如在后台向数组写入字节,但是如果你坚持下去,你很快就会学会。

编码快乐!

借助 ATOM 和 Streamlit 从原始数据到 web 应用部署

原文:https://towardsdatascience.com/from-raw-data-to-web-app-deployment-with-atom-and-streamlit-d8df381aa19f?source=collection_archive---------39-----------------------

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

卡洛斯·穆扎Unsplash 上拍摄的照片

介绍

在本文中,我们将向您展示如何创建一个简单的 web 应用程序,该应用程序能够帮助数据科学家在提供的数据集上快速执行预测模型性能的基本分析。用户将能够上传自己的数据集(作为. csv 文件),并以两种方式调整机器学习管道:选择对原始数据集应用哪些数据清理步骤,以及选择要训练和评估的模型。我们将用 50 行代码完成所有这些工作!怎么会?使用正确的库。

  • 我们将使用 ATOM 进行数据处理和模型训练。ATOM 是一个为快速探索机器学习管道而设计的库。如果你想对这个包有一个温和的介绍,请阅读这个故事。
  • 我们将使用 Streamlit 来创建 web 应用程序。Streamlit 是一个流行的库,可以在几分钟内制作出漂亮的数据应用程序。

构建 web 应用程序

建立

开始进行必要的导入并设置 streamlit 的配置。我们选择一个宽布局,以便有空间显示两个相邻的地块。

import pandas as pd
import streamlit as st
from atom import ATOMClassifier# Expand the web app across the whole screen
st.set_page_config(layout="wide")

管道菜单

这个想法是能够从位于侧边栏的菜单中修改机器学习管道。该菜单将由复选框组成,这些复选框将决定将哪些元素(数据清理步骤或模型)添加到管道中,就像一个菜谱,您可以在其中选择自己的配料。

使用st.sidebar可以将对象添加到 streamlit 的侧边栏中。我们将要实施的数据清理步骤是:特征缩放、分类特征编码和缺失值插补。

st.sidebar.title("Pipeline")

# Data cleaning options
st.sidebar.subheader("Data cleaning")
scale = st.sidebar.checkbox("Scale", False, "scale")
encode = st.sidebar.checkbox("Encode", False, "encode")
impute = st.sidebar.checkbox("Impute", False, "impute")

之后,我们添加可用于拟合数据的模型。这一次,我们将复选框包装在一个字典中,以便以后能够对它们进行循环(注意,我们使用 ATOM 的模型缩写作为键)。

# Model options
st.sidebar.subheader("Models")
models = {
    "gnb": st.sidebar.checkbox("Gaussian Naive Bayes", True, "gnb"),
    "rf": st.sidebar.checkbox("Random Forest", True, "rf"),
    "et": st.sidebar.checkbox("Extra-Trees", False, "et"),
    "xgb": st.sidebar.checkbox("XGBoost", False, "xgb"),
    "lgb": st.sidebar.checkbox("LightGBM", False, "lgb"),
}

**注意:**确保安装了 XGBoostLightGBM 软件包,以便能够使用这些型号。

数据摄取

侧边栏菜单已经完成,是时候制作应用程序的主体了。第一部分是数据摄取,我们可以上传想要使用的数据集。为此使用 streamlit 的 file_uploader 函数。

st.header("Data")
data = st.file_uploader("Upload data:", type="csv")# If a dataset is uploaded, show a preview
if data is not None:
    data = pd.read_csv(data)
    st.text("Data preview:")
    st.dataframe(data.head())

模型训练和评估

最后,编写将处理数据、训练模型和评估结果的实际管道。注意,这个例子只适用于二进制分类任务。

st.header("Results")

if st.sidebar.button("Run"):
    placeholder = st.empty()  # Empty to overwrite write statements
    placeholder.write("Initializing atom...")

    # Initialize atom
    atom = ATOMClassifier(data, verbose=2, random_state=1)

    if scale:
        placeholder.write("Scaling the data...")
        atom.scale()
    if encode:
        placeholder.write("Encoding the categorical features...")
        atom.encode(strategy="LeaveOneOut", max_onehot=10)
    if impute:
        placeholder.write("Imputing the missing values...")
        atom.impute(strat_num="median", strat_cat="most_frequent")

    placeholder.write("Fitting the models...")
    to_run = [key for key, value in models.items() if value]
    atom.run(models=to_run, metric="f1")

    # Display metric results
    placeholder.write(atom.evaluate())

    # Draw plots
    col1, col2 = st.beta_columns(2)
    col1.write(atom.plot_roc(title="ROC curve", display=None))
    col2.write(atom.plot_prc(title="PR curve", display=None))

else:
    st.write("No results yet. Click the run button!")

这是相当大的一段代码,所以让我解释一下这里发生了什么。开始的 if 语句在侧边栏中创建了一个按钮,如果点击它,就会执行 if 语句中的代码块。只要没有单击该按钮,管道就不会运行。这确保了管道不会在每次单击菜单中的一个复选框后开始运行。 if 语句内的代码块执行以下操作:

  • 创建一个占位符文本块,以便在管道运行时写入一些进度信息。
  • 初始化一个将处理管道的 ATOMClassifier 实例。使用此命令,数据会自动拆分为 80%-20%比率的训练集和测试集。
  • 运行侧栏中每个选中复选框对应的数据清理步骤。
  • 使用 atom 的 run 方法在训练集上训练所有选择的模型。
  • 使用评分方法输出模型在测试集上的表现。
  • 显示所有训练模型的接收机工作特性曲线精度-召回曲线。display=None 参数对于返回创建的 matplotlib 图形是必需的。

尝试一下

就这样,web 应用程序完成了!让我们试一试。要运行该应用程序,请打开终端并转到文件所在的目录。运行命令streamlit run <name_web_app>.py。web 应用程序将自动在您的默认浏览器中打开。按照此处描述的步骤进行部署。

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

所示示例中使用的数据是来自 Kaggle 的澳大利亚天气数据集的变体。可以从这里下载。这个数据集的目标是预测明天是否会下雨,在目标列RainTomorrow上训练一个二元分类器。这个例子的完整代码可以在这里找到。

结论

我们已经看到了如何使用 ATOM 和 Streamlit 快速创建一个能够探索基本机器学习管道的 web 应用程序。由于这两个库的灵活性和易用性,添加新模型、允许回归管道、显示一些额外的图表或增加管道的复杂性,都不会花费太多精力来改进 web 应用程序。

相关故事:

有关 ATOM 的更多信息,请查看该项目的 GitHub文档页面。对于 bug 或特性请求,请不要犹豫,在 GitHub 上打开问题或给我发电子邮件。

使用 Python 从 Redshift 到 Google 电子表格

原文:https://towardsdatascience.com/from-redshift-to-google-spread-sheet-using-python-fd4b50131940?source=collection_archive---------14-----------------------

读取、写入和格式化电子表格的简化工作流程

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

作者图片

最近,我试图从亚马逊红移数据库中提取数据,并使用 Python 脚本将其推送到谷歌电子表格中。该脚本的目的是从 Amazon redshift 数据库中读取数据,应用一些业务规则,并将其写入 google 电子表格。

我已经在我的 python 脚本中使用了 gspread 库,它只不过是用于 google sheets 的 python API。使用它,我们可以非常容易地读取、写入和格式化电子表格。

要与 Google API 交互,第一步是在 Google 开发控制台中创建一个项目并启用 API。

  1. 创建一个项目(点击这里):

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

作者图片

2.给项目命名:

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

作者图片

3.转到项目仪表板,点击+启用 API 和服务:

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

作者图片

4.搜索 Google Drive API,点击它并启用它。执行相同的过程来启用 Google 电子表格 API:

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

作者图片

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

5.点击创建凭证:

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

作者图片

6.选择参数并点击我需要什么凭证?

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

作者图片

7.输入服务帐户名并选择角色:

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

作者图片

8.现在单击 KEYS 并创建一个 json 格式的新密钥:

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

作者图片

将下载一个 JSON 文件。我们的脚本中需要这个 JSON 文件。因此将该文件重命名为client _ secret key . JSON

现在转到你的 Google Drive,创建一个 Google Sheet,命名为redshift-to-Google-Sheet。从上面下载的 JSON 文件中复制 client_email 值,并将该 Google Sheet 共享给此 client_email 并具有编辑权限。

至此,我们已经设置好了一切,现在让我们编写 Python 脚本。要使用 python 脚本与电子表格交互,我们必须安装 gspread Python 库。因此,打开终端并运行以下命令。oauth2client 是一个 python 库,用于访问受 OAuth 2.0 保护的资源。

pip install gspread
pip install oauth2client

现在创建一个 Python 文件,并将其命名为 redshift_to_spradsheet py。复制并粘贴下面的代码。

import gspread
from oauth2client.service_account import ServiceAccountCredentialsscope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/spreadsheets",
         "https://www.googleapis.com/auth/drive.file", "https://www.googleapis.com/auth/drive"]credentials = ServiceAccountCredentials.from_json_keyfile_name('client_secretkey.json', scope)
client = gspread.authorize(credentials)

现在让我们添加连接到红移数据库的代码。我使用了 sqlalchemy 库,它方便了 Python 程序和数据库之间的通信。

要安装 sqlalchemy,请键入以下内容:

pip install sqlalchemy

现在将 sqlalchemy 导入到 python 脚本中,并使用 create_engine 建立数据库连接。在连接字符串之后,编写 select 查询(或任何其他 DML)来获取数据并将其存储到 pandas 数据帧中。

from sqlalchemy **import**  create_engine
import pandas as pd*# Connecting to postgresql*
engine = create_engine('postgresql://user:password@host:5439/database')
data_frame = pd.read_sql('SELECT * FROM article_sales;', engine)

要将此数据框写入 google 电子表格,我们必须安装 df2gspread python 库。要安装 df2gspread,请键入以下内容:

pip install df2gspread

现在将 df2gspread 导入到 python 脚本中,并创建一个名为 write_googlesheet 的函数,如下所示:

from df2gspread import df2gspread as d2gdef write_googlesheet(df, spreadsheet_key, sheet_title, starting_cell, overwrite):
    d2g.upload(df, spreadsheet_key, sheet_title, credentials=credentials, col_names=overwrite, row_names=True, start_cell = starting_cell, clean=overwrite)

这个 d2g.upload 函数将给定的熊猫数据帧上传到 Google Drive,并返回 gspread 工作表对象。这里我已经从电子表格的 url 传递了电子表格键,工作表标题作为电子表格名称(即工作表 1、工作表 2)。要了解更多关于函数参数的信息,请点击此处

github 链接: redshift_spreadsheet.py

现在运行 Python 脚本,在浏览器中打开红移到 Google-Sheet Google Sheet。您将看到您的 Google 表单已更新了内容。

结论

这篇文章的目的是让人们了解这种类型的实现。可以有许多不同的策略,但我发现它不太复杂,对于天真的开发人员来说容易理解。

从零开始:置换特征对 ML 可解释性的重要性

原文:https://towardsdatascience.com/from-scratch-permutation-feature-importance-for-ml-interpretability-b60f7d5d1fe9?source=collection_archive---------4-----------------------

实践教程

使用排列要素重要性来发现数据集中哪些要素对预测有用-在 python 中从头实现。

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

阿诺·塞纳Unsplash 上拍摄的照片

介绍

机器学习中的高级主题由黑盒模型主导。顾名思义,黑盒模型是复杂的模型,很难理解模型输入是如何组合起来进行预测的。像人工神经网络这样的深度学习模型和像随机森林、梯度推进学习器和模型堆叠这样的集成模型是黑盒模型的例子,它们在从城市规划计算机视觉的各种领域中产生非常准确的预测。

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

黑盒模型图

然而,使用这些黑盒模型的一个缺点是,通常很难解释预测者是如何影响预测的——尤其是使用传统的统计方法。本文将解释另一种解释黑盒模型的方法,称为排列特征重要性。置换要素重要性是一个强大的工具,无论我们使用什么模型,它都允许我们检测数据集中哪些要素具有预测能力。

我们将从讨论传统统计推断和特征重要性之间的差异开始,以激发对排列特征重要性的需求。然后,我们将解释排列特征的重要性,并从头开始实现它,以发现哪些预测因子对于预测 Blotchville 的房价是重要的。最后,我们将讨论这种方法的一些缺点,并介绍一些将来可以帮助我们了解置换特性重要性的包。

统计推断与特征重要性

当使用传统的参数统计模型时,我们可以依靠统计推断来精确地描述我们的输入与输出之间的关系。例如,当我们使用线性回归时,我们知道预测值的一个单位变化对应于输出值的一个线性变化。这种变化的幅度是在模型拟合期间估计的,我们可以使用概率论为这些估计提供不确定性度量。

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

照片由贾维尔·阿莱格·巴罗斯乌普斯普什上拍摄

不幸的是,当使用黑盒模型时,我们通常不可能做出这种声明。深度神经网络可能有数百、数千甚至百万个可训练权重,将输入预测器连接到输出预测(ResNet-50 有超过 2300 万个可训练参数)以及几个非线性激活函数。当处理一个如此复杂的模型时,通过分析找出预测器和预测之间的关系变得极具挑战性。

开发特性重要性技术是为了帮助缓解这种可解释性危机。特征重要性技术根据每个预测器改进预测的能力为其分配一个分数。这使我们能够根据预测因子的相对预测能力对模型中的预测因子进行排序。

生成这些特征重要性分数的一种方法是利用随机排列的力量。下一节将解释如何使用 python 执行置换要素重要性。

置换特征重要性

特性重要性背后的思想很简单。对预测有用的输入包含有价值的信息。如果您通过随机打乱特征值来破坏这些信息,那么您的预测质量将会下降。如果质量下降很小,那么原始预测器中的信息在确定您的预测时并不十分有效-没有它,您的模型仍然很好。此外,如果下降幅度很大,那么原始预测值中的信息会对您的预测产生很大影响。

这个想法通过三个简单的步骤实现。假设您已经训练了一个 ML 模型并记录了一些预测的质量度量(例如 MSE、对数损失等)。对于数据集中的每个预测值:

  1. 随机打乱预测值中的数据,同时保持其他预测值不变
  2. 基于置换值生成新的预测,并评估新预测的质量
  3. 通过计算新预测相对于原始预测的质量下降来计算要素重要性分数

计算完所有要素的要素重要性分数后,可以根据预测有用性对其进行排序。为了帮助更具体地解释排列特征的重要性,考虑下面的综合案例研究。

案例研究:预测房价

注意:代码在最有指导意义的时候被包括在内。请点击此处 了解本指南的完整代码

假设 Blotchville 的 10000 套房屋的价格由四个因素决定:房屋颜色、邻里密度得分、邻里犯罪率得分、邻里教育得分。Blotchville 的房子不是红色就是蓝色,所以颜色被编码成二进制指示器。三个量化分数标准化,近似正态分布。根据下面的数据生成公式,可以从这些因素中确定房价:

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

数据生成方程

该数据集还包含其他五个与房价无关且没有预测能力的预测因素。这里是数据集前五行的快照,df

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

数据集的快照

假设我们要训练一个模型,从其他九个预测值中预测价格。我们可以使用任何黑盒模型,但是为了这个例子,让我们训练一个随机森林回归器。为此,我们将数据分为训练和测试数据集。然后,我们使用 sklearn 拟合一个简单的随机森林模型。

from sklearn.model_selection import train_test_split 
from sklearn.ensemble import RandomForestRegressorX = df.drop(columns = 'price')
# One-hot encode color for sklearn
X['color'] = (X['color'] == 'red')
y = df.price# Train Test Split
X_train, X_test, y_train, y_test = train_test_split(X, y,
                                                    test_size=0.33, 
                                                    random_state=42)# Instantiate a Random Forest Regressor
regr = RandomForestRegressor(max_depth=100, random_state=0)# Fit a random forest regressor
regr.fit(X_train, y_train)

此时,请随意花些时间来调整随机森林回归器的超参数。但是,由于这不是关于超参数调整的指南,我将继续使用这个简单的随机森林模型——它可以很好地说明置换特征重要性的有用性。

评估回归预测质量的一个常用指标是在测试集上评估的均方根误差(RMSE) 。让我们计算模型预测的 RMSE,并将其存储为rmse_full_mod

from sklearn.metrics import mean_squared_errorrmse_full_mod = mean_squared_error(regr.predict(X_test), y_test, squared = False)

现在,我们可以通过改组每个预测器并记录 RMSE 的增加来实现置换特征重要性。这将允许我们评估哪些预测因子对预测有用。下面是从头开始做这件事的代码。看看你是否能把这段代码的注释和我们之前的算法匹配起来。

# Initialize a list of results
results = []# Iterate through each predictor
for predictor in X_test:

    # Create a copy of X_test
    X_test_copy = X_test.copy()

    # Scramble the values of the given predictor
    X_test_copy[predictor] = X_test[predictor].sample(frac=1).values

    # Calculate the new RMSE
    new_rmse = mean_squared_error(regr.predict(X_test_copy), y_test,
                                  squared = False)

    # Append the increase in MSE to the list of results 
    results.append({'pred': predictor,
                    'score': new_rmse - rmse_full_mod })# Convert to a pandas dataframe and rank the predictors by score
resultsdf = pd.DataFrame(results).sort_values(by = 'score',
                                              ascending = False)

得到的数据帧包含置换特征重要性分数。大的分数对应于 RMSE 的大幅度增加——当预测因子被打乱时,模型表现更差的证据。在检查该表时,我们看到四个数据生成预测因子(教育、肤色、密度和犯罪)具有相对较大的值,这意味着它们在我们的模型中具有预测能力。另一方面,五个虚拟预测值具有相对较小的值,这意味着它们对于进行预测并不那么有用。

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

排列数据帧的结果

我们还可以使用 matplotlib 绘制置换特征重要性分数的图表,以便于比较。

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

置换特征重要性图

从这个分析中,我们获得了关于我们的模型如何做出预测的有价值的见解。我们看到,在我们的模型中,教育分数是预测房价时提供最有价值信息的预测因子。房屋颜色、密度分数和犯罪分数似乎也是重要的预测因素。最后,五个虚拟预测值似乎没有太多的预测能力。事实上,由于去除虚拟预测因子 3 实际上导致了 RMSE 的降低,我们可以考虑进行特征选择,并在未来的分析中去除这些不重要的预测因子。

排列特征重要性的缺点

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

马丁·埃斯特夫在 Upsplash 拍摄的照片

虽然我们已经看到了排列特性重要性的许多好处,但是承认它的缺点也同样重要(没有双关的意思)。以下是使用排列特征重要性的一些缺点:

  1. **计算时间:**这个过程可能计算量很大,因为它需要你迭代每个预测器并做出预测。如果做预测并不便宜,或者如果你有很多很多的预测者,这可能是昂贵的。
  2. **存在多重共线性时性能不佳:**如果数据集具有相关要素,排列要素重要性的性能会很差。如果一个预测器中的信息也存储在相关的预测器中,那么当这些预测器中的一个被打乱时,该模型仍然可以很好地执行。
  3. **分数是相对的,不是绝对的:**排列重要性分数显示了模型中特性的相对预测能力。然而,这些分数实际上没有任何脱离上下文的有意义的价值——任何分数都可能根据其他分数而变得很好或很差。
  4. **特征重要性仍然不是统计推断:**特征重要性技术只能告诉你一个预测器有多有用——它们不能提供对关系本质的任何洞察(例如线性、二次等。)或预测器效果的大小。排列特征重要性不是统计推断的替代品,而是在无法执行传统推断时的替代解决方案。

结论

置换特征重要性是工具箱中的一个有价值的工具,用于分析黑盒模型和提供 ML 可解释性。有了这些工具,我们可以更好地理解我们的预测者和我们的预测之间的关系,甚至执行更有原则的特征选择。

尽管我们从头开始实现了排列特征重要性,但是有几个包提供了排列特征重要性的复杂实现以及其他模型无关的方法。Python 用户应该查看eli5alibiscikit-learnLIMErfpimp包,而 R 用户则转向imlDALEXvip

烫发快乐!如果你有任何问题,欢迎留言,我会尽我所能提供答案。

致谢:非常感谢出色的克莱尔·霍夫曼校对和编辑了这篇文章,并忍受了我对牛津逗号的忽视。我也很感谢 Leo Saenger 阅读了这篇文章并提供了他的建议。

建立 conda 环境的完整指南

原文:https://towardsdatascience.com/from-soup-to-nuts-guide-for-setting-up-a-conda-environment-58afc7c4801?source=collection_archive---------12-----------------------

conda 的全面指南,从选择安装程序到设置环境、通道和安装包

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

Unsplashveeterzy 拍摄的照片

动机:

你好!Conda 是数据科学社区中最受欢迎的工具之一,然而,理解实施该步骤的步骤和成本可能会令人困惑,因为几乎没有一个地方解释过,所以我决定写一篇。

我将关注三个主题,第一个是关于 conda 安装程序选项,Anaconda,miniconda 和 miniforge,如果不使用它们,你会错过什么。第二个主题将是关于建立一个环境,你可以可靠地用于多个项目,以及当你需要更多的配置时如何修改。最后一部分是关于渠道与环境和包装的关系,这也是一个被忽视的话题,但如果你想以最小的麻烦生产你的作品,这对于展示良好的工程技能是非常重要的。

PS:我用的是 macOS Catalina 10.15.7,用的是 Conda 4 . 9 . 0 版本。如果您对具体版本有疑问,请留下评论。

TL;博士?

所以,我向您承诺,到本文结束时,您可能会了解如何通过机会成本在以下两者之间进行选择来设置您的 conda 环境:

  • 迷你康达和迷你锻造 安装工
  • 环境 命名为唯一和标准
  • 针对您的环境全局添加 通道
  • 从不同渠道安装

希望你喜欢,我会在最后见到你!

康达

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

超能力者康达

conda 是一个开源的、跨平台、 依赖环境 管理工具——理论上——适用于任何语言(但大部分支持在 数据科学和机器学习特定语言 上,如 Python、R、Ruby、C/C++、FORTRAN、…)。Anaconda 是首先开发它的公司,然后在 BSD 许可下开源。它拥有比 pip 和 virtual env 加起来还多的功能。Pip 是 Python 之上的一个包管理器,用于有限数量的库,也就是说,它不能安装 Python。Virtualenv 是一个简单的环境管理器,根本不能安装包…我猜你在这一点上确信使用 conda,所以我们可以继续!

安装康达的前三名安装工分别是 Anacondaminicondaminiforge 。前两个由 Anaconda 开发,并在其网站上提供,而 miniforge 是由社区最近创建的,因为 miniconda 不支持aarch64架构的

如果您需要特定的需求,比如在 aarch64(arm64)或 ppc64le (POWER8/9)架构上运行您的模型,您应该使用 miniforge 安装。它还支持 PyPy,这是 Python 的一个轻量级版本。在安装过程中,它将conda-forge设置为默认的——也是唯一的——通道,并且没有defaults通道。我们将在下一部分更详细地讨论通道。

使用 miniforge 的另一个原因是 Anaconda/miniconda 上的商业使用限制(*)是由于最近在[Term Of Service of Anaconda](https://www.anaconda.com/terms-of-service),上的一个变化,在那里将存储库用于商业活动被宣布为违规,这包括使用从defaults通道安装的包。

此外,有几个开源项目已经从 mini-conda 转移到 miniforge,这个这个,这表明支持这个回购的社区将会增加。

如果你喜欢 ToS 并且不需要架构需求,我们有两个选择,Anaconda 或者 miniconda。如果您想要提供一次性安装的完整版本,并且您有 5GB 的磁盘空间,Anaconda 将为您安装 Python + 250 包。对于新手来说,它可能是一个不错的选择,因为它有现成的常用包,以及 Anaconda Navigator 等应用程序,您可以在这些应用程序中为您的环境启动 JupyterLab、pySpider IDE。Anaconda 也有多个版本,即个人版是免费版本,企业版是为您的团队,如果你想扩展和管理定制的软件包和渠道。

我们的最后一个选择是最小安装程序miniconda将是一个很好的选择,因为它将建立defaults通道。*它比 Anaconda 安装要好,因为您了解了更多关于下载哪些包的信息,并且您不必释放 5 GB 的空间。

PS:如果你觉得你错过了 Anaconda Navigator,Spyder 你可以用 conda 安装,第一个在默认通道有,Spyder 两个都有。

$ conda install anaconda-navigator
$ conda install spyder

🛑也有不同的方法来运行我们的安装程序:

  • **仅 miniconda, miniforge 尚不支持。
  • Cloud VM :如果你想隔离你的环境,在云上运行,只有miniconda有 AWS 的 AMI images 的报价。
  • 容器 : Docker 安装程序可用于: minicondaminiforge

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

帕克森·沃尔伯Unsplash 上拍摄的照片

环境创造

Conda environment是一种组织多个包及其依赖关系的抽象方式。我们创建的任何新环境都有一个目录,所有的包都将下载到这个目录中,并且与这个环境相关的任何配置和历史都将存储在这个目录中。如果您已经安装了 Anaconda 的安装程序,它会在anaconda的安装目录下创建一个名为base的环境。您可以通过运行conda env list命令来检查这一点:(*)指的是默认环境(当我们没有主动使用任何环境时)。

$ conda env list
# conda environments:
#
base        *  /Users/ebrucucen/opt/anaconda3

这很好,但是我们想要我们自己的环境。关于如何命名环境,有两个约定。

首先,你可以给你的环境起一个独特的名字。这个实现为 Python 的每个版本创建了一个环境(因为它是我们都感兴趣的主要语言,对吗?),比如分别针对 Python 3.7 和 Python 3.8 版本的conda-py37env-py3.8。这很好,如果你是环境新手,可能你不会有很多版本的 Pythons,有多个复杂依赖树的包。您可以从任何项目文件夹访问您的环境,并在执行涉及环境的命令时遵循 conda 文档,不会出现任何问题,因为环境将设置在标准位置(/user/…/envs/)**

为了创建一个环境,我们使用conda create命令,后跟环境名,以及一个 package=version 对列表,其中版本是可选的,代价是安装最新的版本。

*$ conda create --name env-py3.8 python=3.8 numpy=1.19.5*

第二个选项是使用 通用名称 到您的所有环境,并为每个项目文件夹创建一个新的,例如conda-env.这意味着,对于您正在处理的任何项目文件夹,您可以以相同的方式引用环境名称,并以一致的方式在您的任何自动化脚本中使用。请注意,子命令--prefix只与--name相互作用,小心选择你的毒药!

*$ conda create  --prefix /<possibly a long path>/conda-env python=3.7# or if you are already on the same directory:$ conda create  --prefix ./conda-env python=3.7*

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

马克斯·库库鲁兹亚克在 Unsplash 上拍摄的照片

环境激活

无论您选择了哪种命名约定,现在您都有了一个环境,(env-py3.8 或 conda-env 或两者都有(!)),接下来我们需要做的是激活,这样我们就可以开始将软件包安装到这些环境中:

*$ conda activate env-py3.8*

它(默认情况下)在命令行上显示环境名,准备接受下一组指令…

*(env-py3.8) $*

或者

*$ conda activate ./conda-env*

结果不是很漂亮的展示,而且肯定没有很好的利用你的空间

*(/<possibly a long path>/conda-env) $*

要改变这种行为,只显示环境名,您可以修改.condarc文件(默认情况下在您的主目录下,~/)。condarc,如果你不确定能在conda config — show-sources前找到答案:

*conda config --set env_prompt '({name})'*

现在,如果你已经设法跟随我到这一点,我们应该有一个环境,激活等待我们安装软件包。

如果你想放松一下,深入一下,看看 env 文件夹的子目录,其中conda-meta文件夹包含history文件来跟踪这个环境中的每个动作,每个包的 JSON 文件列出了它的编译号、依赖项和文件位置…如果你发现/知道任何有趣的事情,请留下评论,这将有助于我们更好地理解环境之谜。我们需要软件包,而channels帮助我们获得正确的版本和依赖关系,让我们开始下一步吧!**

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

科迪·韦弗在 Unsplash 上拍摄的照片

频道

通道是我们的包的仓库。单独维护的每个通道可能有不同版本的包,每个版本有不同的内部版本,并且相同版本的包在每个通道中可能有不同的依赖关系。查看 Stackoverflow 问题以获得更多相关讨论。

一个很好的例子是最常见的两个包,NumPy 和 Tensorflow,其中 Anaconda 的 defaults channel 和 conda-forge 有不同的版本。

**numpy                         1.19.5  py39he588a01_1  conda-forge
numpy                         1.19.2  py39he57783f_0  pkgs/maintensorflow                    2.0.0 mkl_py37hda344b4_0  pkgs/main
tensorflow                    1.14.0      hcba10bf_0  conda-forge**

为避免混淆,这并不意味着我们要安装 tensorflow 2.0.0 版本时引用 conda-forge 通道,而是意味着 conda 将尝试使用 tensorflow 2.0 模块的默认通道,并为每个依赖项确定 conda-forge 的优先级,作为回报,您将获得:

**_tflow_select      pkgs/main/osx-64::_tflow_select-2.3.0-mkl
  absl-py            conda-forge/osx-64::absl-py-0.11.0-py37hf985489_0
 ...
  tensorboard        pkgs/main/noarch::tensorboard-2.0.0-pyhb38c66f_1
  tensorflow         **pkgs/main/osx-64::tensorflow-2.0.0**-mkl_py37hda344b4_0
  tensorflow-base    pkgs/main/osx-64::tensorflow-base-2.0.0-mkl_py37h66b1bf0_0
  tensorflow-estima~ pkgs/main/noarch::tensorflow-estimator-2.0.0-pyh2649769_0
  termcolor          conda-forge/noarch::termcolor-1.1.0-py_2
  werkzeug           conda-forge/noarch::werkzeug-1.0.1-pyh9f0ad1d_0**

添加频道

如上所述,miniconda 和 Anaconda 安装的默认通道是defaults通道,而对于 miniforge,默认通道是conda-forge通道。我们可以通过查看配置文件来显示我们的通道(不管您是否处于激活的环境中):

**$ conda config --show-sources**

其结果与此类似(您的会略有不同):

**==> /Users/ebrucucen/.condarc <==
auto_update_conda: False
ssl_verify: True
channels:
  - conda-forge
  - defaults**

当您在激活的环境中时,您可以全局地或本地地向您的环境添加通道。对于全球安装,您可以调用conda config add conda-canary 来测试要在 24 小时内发布的包

**$ conda config --add channels conda-canary**

我们还可以创建特定于环境的通道。假设我们想在 env-py3.8 环境中安装基因组相关的包,然后我们可以激活一个环境,向它传递--env参数,并向它添加 bioconda 通道:

**$ conda activate env-py3.8
(env-py3.8) $conda config --env --add channels bioconda**

结果将与此类似(您可能有/可能没有默认通道)

**(env-py3.8) $conda config --show-sources==> /Users/ebrucucen/.condarc <==
auto_update_conda: False
ssl_verify: True
channels:
  - conda-canary
  - conda-forge
  - defaults==> /Users/ebrucucen/opt/anaconda3/envs/env-py3.8/.condarc <==
channels:
  - bioconda
  - defaults**

附加频道

您可能已经注意到,add命令修改了配置文件,将最新的附加通道放在列表的顶部。conda 对频道的顺序很固执,因为它本质上是一个优先列表。如果我们的新通道应该到底部,而不是顶部,我们可以使用append参数(或者修改配置文件,我听到了)

**(env-py3.8) $conda config --env --append channels test-channel**

如果我们检查配置文件,我们将看到我们的通道是最后一项(是的,你是对的,在执行 add/append channel 命令期间没有通道验证发生,但是当你想要搜索/安装包时它将出错)

**(env-py3.8) $conda config --show-sources==> /Users/ebrucucen/.condarc <==
auto_update_conda: False
ssl_verify: True
channels:
  - conda-canary
  - conda-forge
  - defaults==> /Users/ebrucucen/opt/anaconda3/envs/env-py3.8/.condarc <==
channels:
  - bioconda
  - defaults
  - test-channel**

移除频道

如果你想删除一个频道(要么是你犯了一个错误,要么是你不再需要它),就像运行--remove参数一样简单,同样的原理,你需要指定--env标签来从激活的环境中删除频道,否则,conda 会给出一个错误,告诉你它找不到这个频道。

**(env-py3.8) $conda config --env --remove channels test-channel**

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

照片由沃洛季米尔·托卡Unsplash 上拍摄

包装

最后,我们现在可以安装我们的软件包了。为了找到你需要的,我推荐 Anaconda search ,它给出了每个包的版本和下载,你可以更好地了解你的选择,另外你可以为你的包找到好的jupyternotebooks**。****

由于每个环境都有一个按优先顺序排列的通道列表,任何安装都将逐个检查版本(如果指定)是否可用。

**$ conda search spyder**

我安装软件包的 6 大方法是:在特定的环境下,特定的版本,特定的版本(可能是天书),从特定的渠道,有依赖或者没有依赖。对于前 3 种,我们可以使用这种格式:

**$ conda install -n <env-name> -c <channel> <package_name>=<version>=<build_string>$ conda install -n env-py3.9 -c conda-forge numpy=1.19.5=py39he588a01_1**

默认情况下,conda install 会安装相关的软件包。我们应该明确地告诉他们我们不想要依赖(danger Williams,我假设我们知道我们在这一点上在做什么)。

**$ conda install -c conda-forge numpy --no-deps**

战斗号令

感谢您的耐心,并通过我的帖子阅读。现在,你已经有了一个 conda 设置的环境和通道,可以安装你需要的任何包(以及 Pip 和其他工具),正如我在每个选择背后所承诺的那样。希望你喜欢。这是一个简单的过程,你可以定制你想要的,比如创建你自己的频道,软件包,将所有可用的支持。祝您愉快!

从 SQLite 到 Pandas——你需要知道的 7 个基本操作

原文:https://towardsdatascience.com/from-sqlite-to-pandas-7-essential-operations-you-need-to-know-c7a5dd71f232?source=collection_archive---------11-----------------------

相信我——这很简单。

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

兰迪·塔兰皮在 Unsplash 上的照片

大约十年前,当我在做 iOS 开发时,还没有成熟的移动应用程序数据库解决方案,因此,我必须在应用程序中实现自己的数据库。我选择使用 SQLite,这是一种成熟的轻量级关系数据库解决方案。

当我将部分职业重心转向数据科学时,我很高兴地得知 Python 也有管理 SQLite 的 API。重要的是,pandas 是数据处理的首选库,它提供了与各种数据库(包括 SQLite)通信的相关功能。将它们结合使用,我们可以对本地存储和数据操作做很多事情。在本文中,让我们探索一些基本的操作。

1.连接到数据库

为了使用 SQLite 数据库,我们利用了内置的sqlite3模块,它提供了完整的通用 SQLite 数据库操作。下面向您展示了我们如何连接到数据库。

import sqlite3

con = sqlite3.connect("test.db")

通过调用connect函数,将会发生两件事。

  1. 该模块将连接到test.db数据库。如果它不存在,它将在当前目录中创建这样命名的数据库。
  2. 这个函数调用将创建一个代表数据库的[Connect](https://docs.python.org/3/library/sqlite3.html#sqlite3.Connection)对象。从现在开始,我们用这个Connection对象执行任何与数据库相关的操作。

如果你不想处理一个物理测试数据库,模块可以通过运行下面的代码在内存中创建一个数据库。

con_memory = sqlite3.connect(":memory:")

为了当前的教程,我们将坚持使用链接到test.dbcon对象。

2.创建新表并插入记录

首先,我们把一些数据放入数据库。为简单起见,假设我们想要两个数据字段(姓名和年级),将有四条记录,如下所示。

names = ['John', 'Mike', 'Jane', 'Bella']
grades = [90, 95, 92, 98]

下面的代码向您展示了我们如何创建一个表并相应地插入这些记录。

新表和记录

  • 就像其他数据库一样,我们首先需要创建一个游标来执行 SQLite 语句。有一点需要注意的是,你可以使用非标准的 *execute* *executemany* 方法直接与 *Connect* 对象在一起,让你的代码看起来更整洁一点,尽管在这个遮光罩下,光标仍然是由 Python 为你创建的。关于是否显式创建光标,这是您的个人选择。
  • 为了在 SQLite 数据库中创建一个表,我们使用了CREATE TABLE table_name (field0 field0_type, field1 field1_type, …)。你可以在 SQLite 网站这里找到支持的数据类型。简而言之,它支持文本、整数、blob(可以用 blob 保存二进制数据)和实数。值得注意的是,SQLite 没有 boolean 类型,您可以考虑使用整数 0 和 1 来表示布尔值。
  • 要插入一条记录,只需调用cur.execute(“INSERT into transcript values (‘John’, 90)”)。但是,要用一个函数调用插入多条记录,您应该使用executemany方法,在该方法中,您将 SQL 语句模板和一个iterator一起传递,后者的项将被顺序添加到模板中。
  • 为了提交所有这些事务来更新数据库,我们在con对象上调用commit方法。

3.查询记录

要查询记录,您可以应用类似的方法——使用execute方法提交所需的 SQL 语句。下面的代码向您展示了我们如何查询按成绩排序的记录。

>>> cur.execute("select * from transcript order by grade desc")
<sqlite3.Cursor object at 0x1103b5ea0>

您可能会注意到,调用execute并没有直接返回我们预期的结果——所有记录。相反,这个调用返回同一个cursor对象。运行 SELECT 语句后,可以将游标视为迭代器。因此,我们可以将它包含在一个列表构造函数中,以显示所有记录。

>>> list(cur)
[('Bella', 98), ('Mike', 95), ('Jane', 92), ('John', 90)]

或者,cursor 对象有内置的方法fetchall来显示记录,或者feathone来检索一个匹配的记录。顺便提一下,为了避免返回值调用execute,我们使用了下划线。

>>> _ = cur.execute("select * from transcript order by grade desc")
>>> cur.fetchall()
[('Bella', 98), ('Mike', 95), ('Jane', 92), ('John', 90)]
>>> _ = cur.execute("select * from transcript order by grade desc")
>>> cur.fetchone()
('Bella', 98)

4.更新记录

为了更新记录,我们使用下面的 SQL 语句语法:update table_name set field_name=new_value, another_field=new_value where condition。应用这个语法,让我们考虑下面的更新。

>>> cur.execute("update transcript set grade = 100 where name = 'John'")
<sqlite3.Cursor object at 0x1103b5ea0>
>>> list(cur.execute("select * from transcript order by grade desc"))
[('John', 100), ('Bella', 98), ('Mike', 95), ('Jane', 92)]

如上所示,我们成功地更新了 John 的分数,这样我们就有了不同的分数顺序。

5.删除记录

要删除记录,我们使用下面的 SQL 语句语法:delete from table_name where condition。不要忽略条件,这一点非常重要,否则会删除表中的所有行,在大多数情况下,这不是我们想要的操作。下面是一个例子。

>>> _ = cur.execute("delete from transcript where name='John'")
>>> list(cur.execute("select * from transcript order by grade desc"))
[('Bella', 98), ('Mike', 95), ('Jane', 92)]

如上所示,我们已经删除了 John 的记录。

6.用熊猫读取 SQLite 数据

用熊猫操纵 SQLite 数据库很好玩。Pandas 提供了一个函数read_sql,它允许我们直接执行 SQL 语句,而不用担心底层的基础设施。

>>> import pandas as pd
>>> df = pd.read_sql("select * from transcript", con)
>>> df
    name  grade
0   Mike     95
1   Jane     92
2  Bella     98

本质上,这个函数调用创建了一个DataFrame,从这里您可以利用 pandas 库提供的所有通用方法。

有些人可能见过熊猫功能read_sql_tableread_sql_query。实际上,read_sql函数只是这两个函数的包装器。它将评估输入并调用适当的函数。因此,在我们的日常使用中,我们可以简单地使用read_sql功能,让熊猫为我们做繁重的工作。

7.将数据帧写入 SQLite

在使用 pandas 处理数据之后,是时候将 DataFrame 写回 SQLite 数据库进行长期存储了。Pandas 为此操作提供了to_sql方法。下面显示了一种可能的用法。

>>> df['gpa'] = [4.0, 3.8, 3.9]
>>> df.to_sql("transcript", con, if_exists="replace", index=False)
>>> list(cur.execute("select * from transcript order by grade desc"))
[('Bella', 98, 3.9), ('Mike', 95, 4.0), ('Jane', 92, 3.8)]
  • 不像read_sql,它是熊猫库中的一个函数,to_sqlDataFrame类的一个方法,因此它将被DataFrame对象直接调用。
  • to_sql方法中,您指定要保存DataFrame的表。
  • if_exists参数很重要,因为默认情况下,该参数被设置为“fail”,这意味着当表已经存在时,您不能将当前的DataFrame写入该表——将引发一个ValueError。因为在我们的例子中,由于更新的 GPA 信息,我们想要替换现有的表,我们将if_exisits参数指定为“replace”
  • index设置为False会在保存到表格时忽略DataFrame对象的索引。它与您可能更熟悉的to_csv方法具有相同的效果。

结论

在本文中,我们回顾了使用 Python 内置的 sqlite3 模块来使用 SQLite 数据库的基本操作。正如您所看到的,使用提供的方法,我们可以非常方便地操作常见的 SQL 操作,如插入、更新和删除。本质上,如果您已经了解 SQL,就没有太多的学习曲线。

我们还探索了 pandas 如何与 SQLite 数据库接口。记住接口的诀窍很简单——read _ SQL 是从 SQLite 数据库中提取任何内容,而 to_sql 是将数据转储回 SQLite 数据库。也就是说,假设您的主要数据处理工具是 pandas,相对于 SQLite 数据库,read_sql用于 out,to_sql用于 in。

从教学到数据科学

原文:https://towardsdatascience.com/from-teaching-to-data-science-5d6d712f6a3f?source=collection_archive---------7-----------------------

我是如何以及为什么从教小学转向数据科学的

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

作者照片

成为你想成为的人

当我第一次开始浏览职业选择时,我几乎立即放弃了数据科学,因为招聘信息中列出了要求:

  • Python、SQL 和/或 R 的编码经验
  • 计算机科学、工程、数学或统计学硕士或博士学位
  • 超过 5 年的数据科学家经验

当时,我的编码技能非常有限,我的硕士学位与数据科学无关,我的职业经历是作为一名小学教师为黑人和棕色人种的儿童争取不平等。已经埋在学生贷款债务中,获得另一个硕士学位似乎不是最好的方法。我认为从事数据科学是一个遥不可及的梦想。

但是,一天下午,当我们像凯瑟琳·强森、米丝蒂·科普兰和索尼娅·索托马约尔一样,结束社会研究单元的“障碍打破者”课程时,我为学生们计划的课程目标在我脑海中回响,大胆地唱道:

“你可以成为任何你想成为的人。”

我热爱教学,热爱教学背后的目的。但我也想探索在课堂之外做出改变的方法。我已经看到了数据对缩小学生阅读和数学技能差距的影响,我渴望使用数据科学作为一种强大的工具来做出改变。

虽然我还没有资格获得数据科学的工作,但我不得不相信自己并投入工作,就像在我之前的破障者一样。以下是我如何利用自己的教师经验,获得了过渡到数据科学领域所需的额外技能。

可转移的技能

一个伟大的老师在某一天会身兼数职——我们是演员、顾问、记者、职业鞋匠,仅举几例。因为我们什么都做,所以我想我的教学经验可以提高我在数据科学家中的候选资格。下面列出了一些传授给数据科学专业的教学技能。

  • 向非技术观众演示— 教师和数据科学家都必须以清晰简洁的方式向精通数据科学以外主题的观众传达信息,无论是 Roblox 还是 ROI。我一天的大部分时间都在给 6 岁的孩子分解概念,比如分数。如果我的一年级学生在自助餐厅的空闲时间兴奋地分享他们如何"将煎饼分成两半、三分之二和四分之三",我相信我可以与商业利益相关者讨论 z 分数的相关性。
  • 数学知识 —虽然只是初级,但我一天中的大部分时间都围绕着数学,包括数据收集和分析。我最喜欢的数学单元,毫无疑问,是三年级课程的第一个单元,“数据和我的班级群体”在开学的前六周,我的学生学会了如何收集、绘制图表和解释数据。每个小组提出一个问题,他们想了解他们同学的一些情况。他们四处收集数据,根据收集到的数据制作条形图或象形图,然后分析结果。在这一单元结束时,我的学生不仅了解了班上最喜欢的魔法生物是什么,还了解了数学与他们的关系。

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

三年级“数据和我的班级社区”项目—作者照片

  • 数据驱动分析—我想进入数据科学领域的主要原因:利用数据做出更好的决策。在每个单元之前,我们评估了学生在阅读、写作和数学方面已经掌握的知识。基于这些评估,我们找出了哪些主题需要更深入的探讨,或者哪些是我们可以快速回顾的。对于远远落后的学生,我们举行小组干预,并针对他们尚未获得的技能。因为我们使用数据,我们能够监控他们的进展并加快他们的成长。我很自豪地说,每一个在阅读和数学方面落后的学生在年底都达到了年级水平,而已经达到年级水平的学生甚至比以前更强。

获取新知识

尽管一名教师身兼数职,但编程不是其中之一。为了让我成功地过渡到数据科学领域,我需要发展我的技术技能。我从小处着手,首先测试数据科学职业是否适合我。然后我学的越多,我就越投入。我在下面列出了我的步骤,考虑到每个步骤所花费的时间和金钱,我肯定会建议你也按照这个顺序来做。

  • Codecademy,$ 40/月——Codecademy 的数据科学职业道路为我奠定了数据科学的基础,这是我在参加数据科学信息会议后立即去的地方。我没有任何编码经验,但是 Codecademy 指导我如何用 python 和 SQL 编码,然后给我机会自己写出代码。起初它看起来很初级,但我真的很欣赏它课程的简单性。一旦我掌握了足够的编码技能,这个网站就会推出测试我编码技能的项目。我也承认,即使是现在,当我接触新事物时,我仍然会参考 Codecademy。
  • 社区大学可能是免费的,但肯定比大学便宜——我个人支付了 800 美元,因为我就住在旧金山的边界线之外。在旧金山城市学院上课填补了很多知识空白,并让我在数据科学的重要主题上有了很好的复习。有一个学期,我上了多元微积分,线性代数,还有统计和概率。这是一个充满挑战和数学负担的学期,但仍然很有趣。如果你计划参加训练营,我特别建议你提前学习数学课程,如果你还没有的话。训练营的课程在一天内涵盖了一个学期的内容。它没有给学习者足够的时间来消化材料。如果你当地的社区大学也提供其他与数据科学相关的课程,我肯定会建议你也参加这些课程。你学得越多,准备越充分。
  • 训练营,15000 美元——如果你正在考虑从事数据科学方面的职业,并且没有技术背景,我肯定会推荐你加入训练营。没错,这是一笔大的金融投资,但训练营可以帮助你发展数据科学职业所需的技能,并为你提供所需的支持。我目前参加了熨斗的在线兼职课程。起初,我很担心,因为我亲自学习更好,但在线课程仍然提供社区感觉,这很有帮助。在熨斗,您将有 5 个项目可以添加到您的个人资料中。这些项目非常棒,因为你从中获得了如此多的经验——你正在编码、分析结果、向业务涉众展示分析和建议,以及向技术观众展示你的代码。作为一名数据科学家,你正在获得实践经验,到时候你可以和潜在的雇主谈论这些。
  • ****实习,免费——在写这篇文章的时候,我刚刚开始在苹果公司实习,是一名 MVT 数据科学分析师。我要说的是,我上面提到的一切,包括可转移的技能和新知识,都帮助我为面试做好了准备。我很高兴能够利用我在训练营和 Codecademy 中学到的知识来构建和创造可以应用于现实世界问题的模型。实习也是一个很好的社交机会。随着旅程的继续,我会写更多关于这个的内容。

结论

从教学过渡到数据科学是一个漫长的旅程,但至少可以说是一个激动人心的旅程。通过 Codecademy、社区大学和我的训练营,我已经获得了很多技能,我知道我的技能只会随着经验的增加而增加。虽然我时常怀念教书的日子,但我很高兴能利用我的数据科学技能来从事一些有所作为的项目。

所以对于那些没有技术背景的人,不要担心。有志者事竟成。记住,你可以成为任何你想成为的人。

如果你正在向数据科学领域过渡,我很想知道,你是如何利用自己的经验来帮助自己的?

从文本到知识:信息提取管道

原文:https://towardsdatascience.com/from-text-to-knowledge-the-information-extraction-pipeline-b65e7e30273e?source=collection_archive---------0-----------------------

实现信息提取管道,包括共指解析、实体链接和关系提取技术。

我很高兴向大家展示我最近在做的项目。如果你一直关注我的帖子,你会知道我热衷于将自然语言处理和知识图结合起来。在这篇博文中,我将展示我的信息提取数据管道的实现。稍后,我还将解释为什么我认为 NLP 和图的结合是通向可解释人工智能的途径之一。

信息提取管道

到底什么是信息提取管道?简单来说,信息抽取就是从文本等非结构化数据中抽取结构化信息的任务。

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

我实现 IE 管道的步骤。作者图片

我的信息提取管道的实现包括四个部分。在第一步中,我们通过一个共指消解模型运行输入文本。共指消解的任务是找到引用特定实体的所有表达式。简单来说,它将所有代词与所指实体联系起来。一旦这一步完成,它会将文本分割成句子,并删除标点符号。我注意到,当我们第一次去掉标点符号时,用于命名实体链接的特定 ML 模型工作得更好。在管道的命名实体链接部分,我们试图提取所有提到的实体,并将它们连接到目标知识库。在这种情况下,目标知识库是维基百科。命名实体链接是有益的,因为它还处理实体歧义消除,这可能是一个大问题。

一旦我们提取了提到的实体,IE 管道就试图根据文本的上下文推断出实体之间的关系。IE 管道结果是实体及其关系,因此使用图形数据库来存储输出是有意义的。我将展示如何将 IE 信息保存到 Neo4j

我将使用下面摘自维基百科的一段话来带你浏览 IE 管道。

Elon Musk is a business magnate, industrial designer, and engineer. He is the founder, CEO, CTO, and chief designer of SpaceX. He is also early investor, CEO, and product architect of Tesla, Inc. He is also the founder of The Boring Company and the co-founder of Neuralink. A centibillionaire, Musk became the richest person in the world in January 2021, with an estimated net worth of $185 billion at the time, surpassing Jeff Bezos. Musk was born to a Canadian mother and South African father and raised in Pretoria, South Africa. He briefly attended the University of Pretoria before moving to Canada aged 17 to attend Queen's University. He transferred to the University of Pennsylvania two years later, where he received dual bachelor's degrees in economics and physics. He moved to California in 1995 to attend Stanford University, but decided instead to pursue a business career. He went on co-founding a web software company Zip2 with his brother Kimbal Musk.

文字复制自https://en.wikipedia.org/wiki/Elon_Musk*,在*CC BY-SA 3.0 license下可用。

第一步:共指消解

如前所述,共指解析试图找到文本中引用特定实体的所有表达式。在我的实现中,我使用了运行在空间框架之上的来自 Huggingface 的neural corf 模型。我使用了 Neuralcoref 模型的默认参数。一路上我注意到的一件事是 Neuralcoref 模型不能很好地处理位置代词。我还从一个 GitHub 问题中借用了一个小的改进代码。共指解决部分的代码如下:

如果我们通过 coref_resolution 函数运行示例文本,我们将得到以下输出:

*Elon Musk is a business magnate, industrial designer, and engineer. 
Elon Musk is the founder, CEO, CTO, and chief designer of SpaceX. 
Elon Musk is also early investor, CEO, and product architect of Tesla, Inc. Elon Musk is also the founder of The Boring Company and the co-founder of Neuralink. A centibillionaire, Musk became the richest person in the world in January 2021, with an estimated net worth of $185 billion at the time, surpassing Jeff Bezos. Musk was born to a Canadian mother and South African father and raised in Pretoria, South Africa. Elon Musk briefly attended the University of Pretoria before moving to Canada aged 17 to attend Queen's University. Elon Musk transferred to the University of Pennsylvania two years later, where Elon Musk received dual bachelor's degrees in economics and physics. Elon Musk moved to California in 1995 to attend Stanford University, but decided instead to pursue a business career. Elon Musk went on co-founding a web software company Zip2 with Elon Musk brother Kimbal Musk.*

在这个例子中,不需要高级的共指消解技术。Neuralcoref 模型将几个代词“他”改成了“埃隆·马斯克”。虽然看起来很简单,但这是提高我们 IE 管道整体效率的重要一步。

第二步:命名实体链接

就在最近,我发表了一篇使用命名实体链接构建知识图的博文。这里,我想使用不同的命名实体链接模型。我第一次尝试使用脸书 BLINK 型号,但我很快意识到它在我的笔记本电脑上无法工作。它需要至少 50GB 的空闲空间,这本身不是一个大问题,但它也需要 32GB 的 RAM。我的笔记本电脑只有 16GB 的内存,我们仍然需要管道的其他部分来工作。所以我恢复使用老式的 wiki ifier API,它已经被证明是有用的。而且完全免费。如果你想找到更多关于 API 的信息,看看我以前的博客文章或者官方文档。

在我们通过 Wikifier API 运行我们的输入文本之前,我们将把文本分成句子并去掉标点符号。总的来说,这一步的代码如下:

我忘记提到 Wikifier API 返回一个实体所属的所有类。它查看的实例和类的子类,并遍历整个类层次结构。我决定过滤掉属于个人、组织或地点的实体。如果我们通过管道的命名实体链接部分运行我们的示例文本,我们将得到下面的输出。

维基化过程的一个好处是,我们还可以为实体及其标题获取相应的维基数据 id。拥有 WikiData ids 可以解决实体歧义消除的问题。你可能想知道如果一个实体在维基百科上不存在会发生什么。不幸的是,在这种情况下,Wikifier 不会识别它。不过,我对此并不太担心,因为如果我没记错的话,维基百科有超过 1 亿个实体。

如果你仔细观察结果,你会注意到比勒陀利亚被错误地归类为一个组织。我试图解决这个问题,但维基百科的类层次结构很复杂,通常跨越五六跳。如果有一些维基类专家,我会很乐意听取你的建议。

第三步:关系提取

到目前为止,我已经介绍了所有的概念。我以前从来没有钻研过关系抽取。到目前为止,我们只研究了共现网络。因此,我很高兴向大家介绍工作关系提取流程。我花了很多时间搜索任何可能做得不错的开源模型。我很高兴偶然发现了 OpenNRE 项目。它具有五个开源关系提取模型,这些模型在 Wiki80 或 Tacred 数据集上进行训练。因为我是维基百科的忠实粉丝,所以我决定使用 Wiki80 数据集。在 Wiki80 数据集上训练的模型可以推断 80 种关系类型。我没有尝试过在 Tacred 数据集上训练的模型。你可以自己试试。在 IE 管道实现中,我使用了wiki80_bert_softmax模型。顾名思义,它在引擎盖下使用了 BERT 编码器。有一点是肯定的。如果你没有一个图形处理器,你不会有一个好时光。

如果我们在 OpenNRE 库中查看一个示例关系提取调用,我们会注意到它只推断关系,并不试图提取命名实体。我们必须提供一对带有ht参数的实体,然后模型试图推断出一个关系。

*model.infer({'text': 'He was the son of Máel Dúin mac Máele Fithrich, and grandson of the high king Áed Uaridnach (died 612).', 'h': {'pos': (18, 46)}, 't': {'pos': (78, 91)}})
('father', 0.5108704566955566)*

结果输出关系类型以及预测的置信度。我的用于关系提取的并不完美的代码看起来像这样:

我们必须使用命名实体链接的结果作为关系提取过程的输入。我们迭代一对实体的每个排列,并试图推断出一种关系。正如您在代码中看到的,我们还有一个 relation_threshold 参数来忽略置信度较低的关系。稍后你会明白为什么我们使用排列而不是实体的组合。

因此,如果我们通过关系提取管道运行我们的示例文本,结果如下:

关系抽取是一个很难解决的问题,所以不要期望完美的结果。我必须说,这个 IE 管道工程以及,如果不是比一些商业解决方案更好。显然,其他商业解决方案要好得多。

第四步:知识图谱

当我们处理实体及其关系时,将结果存储在图形数据库中才有意义。我在我的例子中使用了 Neo4j

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

作者图片

记住,我说过我们将试图推断所有实体对的排列之间的关系,而不是组合。看看排行榜的结果,就很难找出原因了。在图形可视化中,很容易观察到,虽然大多数关系都是双向推断的,但并不是在所有情况下都是如此。例如,Elon Musk 和宾夕法尼亚大学之间的工作地点关系被假设为仅在一个方向上。这给我们带来了 OpenNRE 模型的另一个缺点。关系的方向并不像我们希望的那样精确。

工业工程流水线的一个实例

为了不让您空手而归,我将向您展示如何在您的项目中使用我的 IE 实现。我们将通过 Kaggle 上的 BBC 新闻数据集运行 IE 管道。IE 管道实现最困难的部分是建立所有的依赖关系。我希望你保持头脑清醒,所以我建立了一个你可以使用的 docker 图像。运行以下命令使其启动并运行:

*docker run -p 5000:5000 tomasonjo/trinityie*

第一次运行时,必须下载 OpenNRE 模型,所以绝对不要使用-rm选项。如果你想对项目做一些修改并构建自己的版本,我还准备了一个 GitHub 库

由于我们将把结果存储到 Neo4j 中,您还需要下载并设置它。在上面的例子中,我使用了一个简单的图形模式,其中节点代表实体,关系代表关系。现在我们将稍微重构一下我们的图表模式。我们希望在图中存储实体和关系,同时保存原始文本。拥有审计线索在现实场景中非常有用,因为我们已经知道 IE 管道并不完美。

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

作者图片

将关系重构到中间节点可能有点违背直觉。我们面临的问题是,我们不能让一个关系指向另一个关系。鉴于这个问题,我决定将一个关系重构为一个中间节点。我本可以发挥我的想象力来产生更好的关系类型和节点标签,但事实就是如此。我只想让关系方向保留它的功能。

将 BBC 新闻数据集中的 500 篇文章导入 Neo4j 的代码如下。你必须让 trinityIE docker 运行,IE 管道才能工作。

该代码还可以在 GitHub 上以 Jupyter 笔记本的形式获得。根据你的 GPU 能力,IE 管道可能需要一些时间。现在让我们检查输出。显然,我选择了有意义的结果。运行以下查询:

*MATCH p=(e:Entity{name:'Enrico Bondi'})-[:RELATION]->(r)-[:RELATION]->(), 
        (r)<-[:MENTIONS_REL]-(s)
RETURN **

结果

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

BBC 新闻数据集上的 IE 抽取结果。作者图片

我们可以看到恩里科·邦迪是意大利公民。他在意大利众议院任职。另一种关系是推断他也拥有 Parmalat。经过短暂的谷歌搜索,似乎这个数据或多或少至少在可能的范围内。

通往可解释人工智能的道路

你可能会想,这和可解释的人工智能有什么关系。我给你一个真实的例子。这篇研究论文的标题是通过知识图谱完成为新冠肺炎进行药物再利用。我不是医生,所以不要期待详细的介绍,但我可以给出一个高层次的概述。网上有很多医学研究论文。还有在线医疗实体数据库,如 MeSHEnsembl 。假设您在生物医学研究论文上运行命名实体链接模型,并使用一个在线医学数据库作为目标知识库。在这种情况下,您可以提取文章中提到的实体。更具挑战性的部分是关系提取。因为这是一个如此重要的领域,伟大的头脑聚集在一起,提取这些关系。

可能有更多的项目,但是我知道在提到的文章中也使用了 SemMedDB 项目。现在你有了你的知识图表,你可以试着预测现有药物的新用途。在网络科学中,这被称为链路预测。当你试图预测链接以及它们的关系类型时,科学界称之为知识图完成。想象一下,我们已经预测了现有药物的一些新用例,并向医生或药理学家展示了我们的结果。他的回答可能是,那很好,但是你为什么认为这个新用例会工作呢?机器学习模型是一个黑盒,所以这并没有真正的帮助。但是你能给医生的是现有药物和它能治疗的新疾病之间的所有联系。而且不仅是直接关系,还有两三跳之外的关系。我会举一个例子,所以对生物医学研究者来说可能没有意义。假设现有的药物抑制了与疾病相关的基因。药物和疾病之间可能有许多直接或间接的联系。因此,我们已经向可解释的人工智能迈出了一步。

结论

我对这个项目的进展非常满意。在过去的一年左右的时间里,我一直在尝试将 NLP 和知识图结合起来,现在我已经将我所有的知识都集中到了一篇文章中。我希望你喜欢它!

附:如果你想对 IE 管道做一些改动,代码可以作为 Github 库 获得。转载这篇博文的代码也可以作为 Jupyter 笔记本

从文本到表格,老方法

原文:https://towardsdatascience.com/from-text-to-table-the-old-school-way-d7f8ba41dac?source=collection_archive---------50-----------------------

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

Unsplash 上对@fredmarriage 的积分。简单的方法还是困难的方法?小工厂还是大工厂?

利用 Excel 的强大功能从文本文件中获取表格

语境

例如, Y 你有写在 Windows 记事本的文本文件中的数据。两行之间有一些额外的间隔。你通常可以从一个在线网站上复制/粘贴一些随机的行。

目标

您希望获得一个表格,其中每一行对应于文本文件中的一行。

怎么会?

  1. 在 excel 中复制/粘贴整个文本文件
  2. 格式化为表格
  3. 过滤掉空白

就是这样!!

例子

假设您想将哈利波特的引用存储在一个表中,并希望以某种方式进行处理。

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

我们都爱的五句哈利波特语录!

我通常会将这些引用写在一个简单的文本文件中,如下所示。

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

我在一个文本文件里写了五段哈利波特的引言。

现在,在以后的某个时候,我决定把它们放在一张桌子上玩,并做一些数据科学。自然地,我可以将这种方法扩展到一千个报价,以便更加精确。但是让我们拿这五个一来证明我们的观点。

首先,如上图所示,我把我的哈利波特引语复制/粘贴到一个 Excel 表格上。

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

从 txt 文件复制/粘贴哈利波特语录到 Excel。

然后,我需要使用下面突出显示的“ Format as Table ”将我的工作表格式化为表格。

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

使用突出显示的图标格式化为表格。

最后,我需要过滤掉空白,去掉空行。

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

取消选择空白!

就这样,我们得到了我们想要的输出。

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

上述三个步骤的输出。

我可以将我的独特专栏的标题修改如下。

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

将我独特的专栏重新命名为我最喜欢的标题。

供选择的

对于已经向我指出这种“noob”Excel 方法的数据科学家来说,另一种 Python 方法可以定义如下:

  1. 处理文本文件
  2. 然后将其存储在熊猫数据帧
  3. 最后,将熊猫表保存为 csv/tsv 文件

但是嘿!尽管这种 Python 方法在概念上微不足道,但人们可以注意到它比“老派”Excel 方法要耗时得多。

另外,只要你能完成工作,谁在乎你是不是菜鸟!😉

从围棋到卡格:台湾卡格大师的故事

原文:https://towardsdatascience.com/from-the-game-of-go-to-kaggle-the-story-of-a-kaggle-grandmaster-from-taiwan-5adcd4fff38d?source=collection_archive---------17-----------------------

与郝坤·叶的对话:数据科学家和 Kaggle 大师

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

作者图片

在这一系列采访中,我在 H2O.ai 展示了一些知名数据科学家和 Kaggle 大师的故事,他们分享了自己的旅程、灵感和成就。这些采访旨在激励和鼓励那些想了解成为一名 Kaggle 特级大师的人。

最近有机会采访了叶坤浩— 一位 Kaggle 竞赛的特级大师和一位数据科学家atH2O . ai。坤浩拥有台湾国立交通大学的计算机科学硕士学位。他的重点是多臂土匪问题和应用于计算机游戏的强化学习,包括但不限于 2048 AI 和计算机围棋。他作为一名软件工程师开始了他的职业生涯,致力于为即将到来的 5G 市场竞争的最新 5G 芯片组产品。

在这次采访中,我们将更多地了解他的学术背景、他对 Kaggle 的热情以及他作为数据科学家的工作。以下是我与郝坤对话的摘录:

您能告诉我们您的背景以及从电子工程到计算机科学,最终到数据科学的转变吗?

***😗**在攻读学士学位期间,我主修电子工程(EE)和计算机科学(EECS)。尽管我在电子工程方面成绩很好,也不擅长编程,但计算机科学(CS)似乎更有趣。从那以后,我在计算机科学上花了更多的时间,甚至攻读了计算机科学硕士学位。

在研究生院,我得到了一位教授吴亦琛(I-Chen Wu)的建议,他主要从事 RL(强化学习)算法在计算机游戏中的应用,如ChessGogame 2048。由于对GoAI的浓厚兴趣,我找到了我的导师。事实上,我甚至梦想成为一名职业围棋手,但我的父母不让我走上他们的职业道路😃。人工智能在当时对我来说似乎很花哨,所以我想做用 AI 下围棋、打败职业选手的研究。我们的实验室叫做 CGI ( 电脑游戏智能)实验室,甚至在电脑奥林匹克中拿了很多奖牌。我还参与了一个 2048 AI 项目,在不同的比赛中获得了几枚奖牌。

毕业后,我在联发科的第一份工作是 4G 和 5G 调制解调器芯片的软件工程师。尽管我在半导体行业工作,但我对机器学习的兴趣从未消退。意识到强化学习需要一段时间才能完全应用于行业,我开始强调监督学习。我报名参加了 Coursera 上的课程,包括吴恩达的— 深度学习专业 ,甚至还有马里奥斯的(H2O.ai 的 Kaggle GransMaster 研究员)— 向顶级 ka ggler 学习, 以使我的基础正确。渐渐地,我开始参加很多 Kaggle 比赛。我的想法是向他人学习,同时运用我的知识解决现实世界的问题。

Kaggle 最初吸引你的是什么,你是什么时候赢得第一次胜利的?

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

郝坤的 Kaggle 简介 |图片来自 Kaggle

坤浩 : 我加入 Kaggle 并不是因为它有吸引力,而是因为我想通过在知名的数据科学平台上解决问题来证明自己。我的第一枚金牌是在家庭信用违约风险竞赛中获得的,这是一项预测客户还款能力的竞赛。我的团队是一个庞大的团队,他们在非常不同的方面共同努力来提高我们的分数。

你在高尔夫比赛中一直表现出色。是什么让你有动力一次又一次地去竞争。

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

郝坤在 Kaggle 上的一些令人印象深刻的成绩

坤昊 : 在 Kaggle 上赢了几次之后,我沉迷于做自己喜欢的事情的感觉。我很感激有这样一个平台,在这里我可以与世界各地的人和聪明的头脑联系,证明自己,并在比赛中学习新的东西,帮助更好地解决实际问题!

你在圣诞老人 2020 比赛中获得第十名,成为大师。在 RL 的背景让你在这场比赛中有优势吗?

Kun-Hao : 正如我之前提到的,在读研期间有一些 RL 的经验绝对让我在这样的竞争中有一些优势。

你和 Marios Michailidis 搭档,又名KazAnova他那时已经是 KGM 了。你对与更有经验的卡格勒人合作有什么建议?

这是一个好主意,首先在一些竞争中证明自己,并尝试所有可能的解决方案。只有这样,与更有经验的卡格勒人合作才是明智的。此外,在你对比赛有了很好的了解后组队是有意义的,因为那时你可以向有经验的卡格勒人询问他们过去在类似比赛中的经验,建议,以及他们将如何处理这些问题。

您被邀请作为 2019 年 Kaggle Days China 的演讲嘉宾。你能分享一些你在那里的经历吗?

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

郝坤在 Kaggle Days China 发表演讲|图片由坤昊提供(来自个人收藏)

***坤豪😗2019 年我作为嘉宾演讲嘉宾受邀参加 Kaggle Days China 。这件事发生在加入 H2O.ai 之前,当时我是 Kaggle 高手,在联发科做软件工程师。在活动中,我遇到了 Marios Michailidis 和 Mikhail Trofimov,他们碰巧是我上过的 Coursera 课程的导师。坐在观众席上听他们的演讲是多么激动人心的时刻。我还见到了加博尔·法多尔、德米特里·拉尔科和后来成为我在 H2O 同事的雅亨·巴巴金,并与他们共进晚餐。

作为 H2O.ai 的数据科学家,你的角色是什么,你在哪些具体领域工作?

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

郝坤在 H2O.ai | H2O.ai 网站

Kun-Hao : 我在 H2O.ai 做一名竞技数据科学家,我还在学习如何扮演好这个角色。具有竞争力意味着:

  1. 我需要不断提高自己的 ML 知识和解决问题的能力,我通过参加 Kaggle 或其他数据科学竞赛平台并取得好成绩来做到这一点。
  2. 运用竞赛经验提高 H2O.ai 的产品竞争力。
  3. 快速学习新事物,并在任何需要的地方提供帮助,这意味着我可以在需要时作为软件工程师或客户数据科学家工作。

目前,我的主要工作是 Kaggle 竞赛,开发 H2O Wave 应用,并帮助 APAC 和中国地区的售前工作。

你通过 Kaggle 学到的最好的东西有哪些是你在 H2O.ai 的专业工作中应用到的?

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

郝坤·叶在 CTDS 讨论他的 SIIM ISIC 黑色素瘤 14 位解决方案。秀场 |图片由 CTDS 秀场提供*

Kun-Hao : 我认为很重要并且主要从 Kaggle 那里学到的一些技能是:

  1. 最先进的机器学习知识,
  2. 如何应用它们解决实际问题,以及
  3. 如何验证模型,以便对看不见的测试用例进行归纳。

这些技能帮助我从软件工程师转变为数据科学家,并在我的工作中发挥了重要作用。然而,我从 Kaggle 身上学到的最好的东西是快速理解问题*,寻找现有的解决方案,并自己实施更好的解决方案**,这是我几乎在我参加的每个比赛中都重复的方法。*

例如,在参加由 Jigsaw 举办的 有毒评论分类比赛之前,我对 BERT 一无所知,也不知道如何使用它,也不知道它背后的想法。我试图从公共内核中学习,改进我的模型,并扩展我的知识,以在排行榜上获得一个好的最终位置(第 9 名)。

在参加 Jigsaw 举办的有毒评论分类大赛之前,我对 BERT 一无所知,也不知道如何使用它,更不知道它背后的想法。我试图从公共内核中学习,改进我的模型,并扩展我的知识,以在排行榜上获得一个好的最终位置(第 9 名)。

在工作中,我和我的同事 Shivam 一起开发了一个优化 Wave 应用程序。在做这个 app 之前,我对纯数值优化了解不多。然而,我们的客户要求这个功能。我们致力于优化应用程序,以扩展我们的云产品的完整性。我研究了不同的现有框架,它们的局限性,它们解决问题的效果如何,并在 Wave 应用程序中创建了一个优化功能的集成版本。我之前对它没有深入的了解,但是当有这样的需求时,我把从 Kaggle 中学到的东西应用到问题中,包括但不限于机器学习相关的问题。

任何喜欢的 ML 资源(MOOCS、博客等)…)您愿意与社区分享吗?

Kun-Hao : 对于基本面,我建议上 Coursera 的在线课程。在准备好所有的基础知识后,我建议投入到比赛中,搜索相关的论文和博客文章。每一篇论文/博客/想法,只要在实际场景(比如竞赛)中起作用/有帮助,都是很好的资源!

对刚刚开始或希望开始数据科学之旅的数据科学有志者有什么建议吗?

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

图片由坤昊提供|来自个人收藏

Kun-Hao : 我想分享一下我在 Kaggle Days China 上分享的建议。

  1. 从小处着手:定义你的小成功
  2. 胸怀大志:定义你自己的伟大目标
  3. 不断奋斗:努力工作,享受任何微小的成功,不自觉地沉迷于过程。

我从 Kaggle 学到的最好的东西是快速理解问题,寻找现有的解决方案,并自己实施更好的解决方案,这是我几乎在我参加的每个比赛中重复的方法。

外卖食品

坤昊的卡格尔之旅是非凡的,这次采访是了解他背后的努力工作的一个很好的方式。他的口号是从每场比赛中学习一些东西,这是鼓舞人心的,他最近的成功清楚地表明了他对自己技术的掌握。

阅读本系列的其他采访:

从健身房到 Jupyter 笔记本——在一天内构建一个蹲起计数器应用程序

原文:https://towardsdatascience.com/from-the-gym-to-a-jupyter-notebook-building-a-squats-counter-app-in-a-day-955ecfbf8d12?source=collection_archive---------35-----------------------

用数据捕捉现实世界中的物理现象,这是一件特别令人满意的事情。作为一名机器学习顾问,我已经习惯了与医疗数据、图像等打交道。但是,当你在屏幕上看到的数据捕捉到移动、位置等信息时,这一切都变得令人耳目一新。因此,当月亮感知的创始人 Andrei 向我挑战,要我在一天内开发一个应用程序,它可以获取我手机的加速度计数据,并利用它做一些很酷的事情时,我非常兴奋。

因此,我开始在一个开发日内构建一个蹲下计数应用程序。

获取数据

在我们过度思考如何量化深蹲的数量和质量之前,先看看一些实时数据是个好主意。Moonsense 可以轻松地将数据从我的 iphone 上传到他们的云存储解决方案,再下载到我的笔记本电脑。这个过程相当轻松:你只需下载一个记录器应用,点击记录按钮,将手机的加速度、陀螺仪和地理信息同步到云端,之后你可以下载到笔记本电脑上。

所以我继续前进,把我的手机拿在手里,开始泵一些铁。这是我把手机放在口袋里做的。

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

好吧,我跟你说实话。这不是我。图片来源:Adobe Stock Photo 授权。

每次我做一系列深蹲重复动作时,我会点击记录按钮,输入一个自由文本标签,比如“4 次深蹲”。

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

如果没有必须的低电量电池,这不会是一个好的屏幕截图

就是这样。现在让我们看看如何使用我们的 Moonsense API 键来检索数据。

这个脚本迭代我记录的所有会话,并打印出每个会话的熊猫数据帧和加速度

因此,打印加速度数据帧会得到这样的输出

timestamp         x         y          z
0    1620847740629 -0.471039  5.075854   9.129929
1    1620847804060  3.401349  4.373932  10.150064
..             ...       ...       ...        ...

有道理。我们看到手机在三个方向上感受到的加速度,x,y 和 z 方向肯定与手机的方向有关。

分析我们的第一批录音

让我们把数据画出来,看看它是否更容易理解。

让我们看看它生成的图表。让我们先来看一个会话,在这个会话中,我将设备静止放在我的桌子上:

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

哼!如果你以前没有处理过加速度计数据,你可能会认为数据几乎为零,但我们看到 z 轴上有一个很大的值。这个数值接近 9.81 米/秒——地球引力。所以我们现在明白了,设备只有在自由落体的时候才会吐出全 0。如果有什么东西顶住了重力,它会报告它是一个向上的力(我们将继续把所有作用在设备上的力称为“加速度”,尽管这肯定是一个误称)。

如果以任意角度拿着手机(例如,系在我的手臂上),这种重力不会整齐地沿着 z 轴排列,而是分散在不同的 x、y、z 轴上。更糟糕的是,如果手机在运动过程中旋转,这种重力测量将以不同的方式在 x,y,z 方向之间泄漏——使我们的数据视图变得复杂。

好了,现在让我们来看一个真正的深蹲训练,让事情变得简单一些。让我们双手握住手机与地面平行,抽出 4 个深蹲。

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

当我们深蹲着看录像时,我们看到:

  1. 每个深蹲似乎由两座小山组成。一个离 9.81 m/sec 的重力值不远的小的,一个很高的,在那里手机感觉到非常强的向上的推力。
  2. 在两座山之间,我们看到 z 轴上的加速度下降,下降到大约 5-6 米/秒的最小值

下面这个故事解释了我们所看到的现象:

  1. 在我们开始蹲下之前,什么也没有发生,手机准确地感受到了我们阻止它下落的力——9.81 米/秒。
  2. 因为手机并不完全平行于地面,这个力会沿着不止一个轴分解——一部分 9.81 指向 z 轴,一部分指向 y 轴,等等。如果我的手是真正水平的,我们会在 Z 方向看到精确的 9.81,而在其他方向什么也看不到。
  3. 当我们蹲下时,该设备几乎是自由落体——因此它感受到的力从 9.81 减小。观测值与 9.81 的差值,大致就是我们的向下加速度。
  4. 最后,当我们深蹲到底时,我们施加了很大的向上的力——足以克服重力并突然改变手机的运动方向。太多了!因此,我们确实看到手机报道的测量值直线上升。

好的,那么我们从这个分析中得到什么呢?

  1. 尽管手机的整体运动基本上是在一个上下运动的维度上,但它不固定的方向让我们的生活有点困难,因为我们需要弄清楚“下”的整体方向是什么。
  2. 虽然我们看到的整体运动相当复杂,但简单地计算大峰的数量似乎就等于我们记录的蹲下次数。

计数峰值

在上图中,我手动覆盖了一个大的 1,2,3,4 数字来计算深蹲的重复次数。我们现在的目标是在代码中复制让我做这个计算的逻辑。所以我们来试着分解一下。我们在找什么?

  1. 明显高于重力的加速度峰值(因此 12+米/秒可能是一个很好的阈值)。
  2. 当然,一旦我们达到峰值加速度,我们将得到许多超过 12 的重复测量,所以我们希望将它们聚集成连续的段。超过 12 的连续测量值显然属于同一个深蹲重复,不应该重复计算。
  3. 为了简单起见,我们只看 Z 轴,假设这是整个运动方向。听说过主成分分析的人可能已经知道,如果手机的方向是其他固定的方向,我们有一种方法来计算出运动的实际方向。但不管怎样,这是以后的事了。

所以这是一种天真的方法,但是让我们看看它会带给我们什么,一旦我们看到它是如何失败的,我们就改进它。

让我们来看看它生成的图表:

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

好吧!我们真的快到了。首先出现的是,我们已经确定了我们希望在这里看到的 4 个真正的峰值。但是我们也有一些错误的峰值——比如在 0.5 秒标记处的瞬时峰值(你可以在那里看到一个单独的橙色标记)。或者类似地,在我们第一个真正的红色峰值之前有一个绿色标记。显然,我们需要以某种方式拒绝非常小的异常值观察。也许我们可以抛弃所有只损失了很短持续时间的片段。但是这就足够了吗?

for start_loc,end_loc in zip(segment_starts, segment_ends):
    print(t[end_loc] - t[start_loc])0.03999999999999998
0.03999999999999915
**0.43900000000000006**
0.08000000000000007
**0.359
0.7590000000000003**
**0.19900000000000162 * note: this corresponds to the gray segment**
**0.3990000000000009**

很接近,但没有雪茄。如果我们拒绝非常短的峰,我们将消除 3 个假阳性,但从我们的图中可以看到,我们的最后一个峰意外地分裂成 2 个灰色和芥末色的亚段。如果我们仅仅依赖于段时间长度,我们的代码将会非常脆弱。基本上,在我们的高加速度阈值以下的单个瞬间下降总是可以将我们的部分分成 2 部分。

所以让我们做最后一次尝试来改进它。让我们对信号进行预处理,使其对像这样的瞬间失误具有鲁棒性。

平滑曲线

我的本科专业是物理和电子工程,所以我认为我不得不承认,这一部分最终只是一个低通滤波器的应用,旨在抑制我们信号的高频成分。

但你不需要了解数字信号处理的第一件事,就能明白我们在做什么。我们不喜欢我们的信号有这些小的噪声起伏,容易产生低于阈值的假峰值和假谷值。如果我们平滑我们的信号,只让持续的高测量值通过我们的阈值,我们会在一个更好的地方。这可以简单到每 N 次连续测量取平均值。我们可以尝试加入其他低通滤波器,看看结果是否会有所改善,一般认为低通滤波器会尝试不同的加权来平均相邻的测量值。我们要保持这个超级简单:用周围 N 个测量值的平均值代替每个测量值。

平均信号

看着我上面展示的照片,看起来一个真实的片段通常持续大约 0.4 秒,这是我个人蹲着的经验。每隔 0.04 秒就有一个样本出现,这意味着查看大约 10 个相邻的样本,就可以大致知道我们想要一起计算多少个测量值的平均值。如果您想知道我是如何知道每 0.04 秒就有一个样本出现的,这很简单:

import numpy as np
print(np.diff(t))
[0.04  0.041 0.039 0.04  0.04  0.04  0.04  0.039 0.041 0.039 0.04  0.04....]
# cool: our data is coming in at almost exactly even time spacing, every 0.04 seconds. If it was less consistent, we'd be interpolating to a fixed time window. But we can get away with just pretending the time spacing is even

那么我们如何平均每 10 个样本呢?我们可以写一个 for 循环来完成这个任务。但它的计算效率更高,完全等同于用 10 个采样值为 1/10 的滤波器对信号进行卷积。代码如下:

如果你不熟悉卷积的概念,这看起来有点像胡言乱语,没关系。在谷歌上搜索“我如何用 python 计算滚动平均值”会让你看到我写的代码。我还是要说,如果你要处理一维信号,了解卷积如何工作以及什么是滤波器是进一步阅读的好主意。那么输出是什么样的呢?让我们在过滤加速度数据帧后重新运行代码

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

嘿,很快,成功了!

很棒的东西!我们捕捉到了这个会话的所有 4 个蹲坐,这次没有假阳性。

0.1 版完成。下一步是什么?

好吧,我们一起黑了一个超级简单的第一版。本帖不再做更多开发。但在我们结束之前,我想强调下一步该怎么做才能让它成为一款强大的应用:

如果你不衡量自己,你就无法提高

到目前为止,我们一直在疯狂地研究,以使结果适用于指导我们的一组特定的小例子。到目前为止,我已经有了一堆关于如何进一步改善结果、使代码对任意的手机方向保持健壮等等的想法。

但是我在开发周期中要做的第一件事不会是修改我们的蹲式计数器的代码。现在我们有了第一个工作版本,要做的事情是计算我们做得有多好,并确保我们所做的后续代码更改使这个数字朝着正确的方向移动。

幸运的是,我们的问题被很好地定义了,所以我们可以衡量自己!对于我做的每一次录音,我都认真地记下了深蹲的次数。当我们从 Moonsense 获取会话数据时,这个标签是可用的。因此,在下一章中,我们将添加一段代码来捕获我们的平均误差,然后开始进行更改,以降低我们的误差指标。

我们也将尝试看看我们是否能解决量化蹲姿质量水平的想法——也许用“一致性”来定义质量。或者可以提取一些描述性的统计数据,比如峰值加速度,然后看看这些数字如何与基于同一时段视频的专家对下蹲质量的评估相匹配。我们甚至可以为每一次会议贴上下蹲质量专家评估的标签,并训练一个机器学习模型,根据我们提取的数字特征预测专家评估。这将使我们的应用成为一个潜在的有趣和有用的产品。

关闭循环,使之成为一个活生生的应用程序

Moonsense 有一个简洁的小特性,叫做“数据消费者”,在这里你可以定义一个函数来处理新数据,只要它变得可用。这允许近乎实时的行为,比如当用户做了蹲起动作时,就向用户发送推送通知。一旦我们有了一个像样的下蹲质量评估器,我们就可以立即给用户反馈他们的下蹲做得如何。

你可以在这个回购中找到完整的代码示例

从笔记本电脑到企业

原文:https://towardsdatascience.com/from-the-laptop-to-the-enterprise-4a4234e961f5?source=collection_archive---------37-----------------------

当你从周末数据科学战士变成企业数据科学家时,要考虑三件事

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

图片由 www_slon_pics 来自 Pixabay

在线学习数据科学的免费内容多得简直荒谬。关于数据科学的媒体教程、Youtube 视频、MOOC 内容(例如 Coursera)和个人博客都创建了一个巨大而廉价的生态系统,只需你的笔记本电脑就可以学习数据科学。

没有什么比关注一篇半生不熟的博客文章,调试提供的代码以满足您自己的数据需求,并看着新技能诞生更令人兴奋的了。就在我们眼前出生。在我们的笔记本电脑上。太神奇了!

事实上,正是能够成功地浏览无数的在线资源,并将我所学的内容翻译到我的笔记本电脑上(当然是按工作顺序),让我一开始就有信心进入数据科学领域。

但在笔记本电脑上学习数据科学是一回事,了解如何将所学知识应用于大型企业通常会带来新的挑战,而大多数免费在线材料对此没有帮助。

你说我需要访问那个数据库是什么意思?我是数据科学家?访问数据不是我职位的要求吗?

当我离开学术岗位,在一家大型企业开始我的第一份数据科学工作时,我就面临着这样的问题。我在笔记本电脑上取得的所有成功并不是毫无意义的,但我仍然有很多东西要学习,以确保我可以继续将我最近获得的数据科学技能应用于大型企业问题。

这些问题是如此有力,以至于这不是我第一次在这里写关于的话题。

在本文中,我基于我之前对企业数据科学家面临的问题的见解,研究了所有年轻数据科学家在大型企业向数据科学角色过渡时需要考虑的 5 件事。我们开始吧!

第一件事:服务器架构

数据科学教育通常只关注让代码工作,这通常意味着创建固定的数据集(例如预先设计的数据集),利用笔记本电脑安装的 IDE 环境(例如 Anaconda、VS-Code)或预先配置的云管理笔记本环境(例如 Google CoLab、AWS Sagemaker、Azure DataBricks),并确保一切都已正确连接。

为了对这一过程进行抽象,数据科学家需要数据、处理该数据的计算环境以及连接到数据存储位置的方法。在企业环境中,这些服务被组织在一个服务器网络中,这些服务器之间的连接程度各不相同。因此,了解如何连接到这些服务器对于数据科学家在他们的岗位上最有效地工作是至关重要的。

当然,先进企业可能有工程团队,他们可以帮助新的数据科学家访问常用的数据资产,但是数据科学家因识别不常用的数据源来帮助他们的开发而臭名昭著。因此,通常需要对服务器架构有足够的了解,以帮助工程师、IT 专业人员和安全团队了解如何将数据科学工作台与这些资产联系起来。即使有基本的了解,也有助于确保在数据科学和 IT 支持团队之间建立信任,这是确保数据科学家尽可能对企业产生影响的关键因素。

等等,什么是数据科学工作台?

在现代企业中,数据科学工作台通常是运行软件的单个服务器或服务器集群,允许数据科学家连接到数据以执行不同的数据科学任务。这些服务器可以是内部软件解决方案(如 Dataiku 或 Alteryx)或托管云服务(DataBricks、AWS Sagemaker、GCP 数据实验室)。在这两种情况下,开发人员都是通过 web 浏览器来访问服务的。

这些环境中的大多数允许数据科学家访问数据科学中常用的 Python 和 Python 库(例如 pandas、scikit)。在某些情况下,企业还可能允许这些服务器连接到 Python 包索引,以便能够访问新的和不断发展的库。

这似乎很简单,数据科学家还需要什么?

在许多情况下,访问常见的企业数据资产不足以满足特定业务问题的需求。因此,数据科学家通常需要能够访问非传统数据源,例如来自应用程序数据库的应用程序级数据、存储在共享文件系统上的数字文档,或者通过 API 调用来自第三方的数据源。

要记住的核心概念:服务器之间的通信有几种不同的方式,其中一些协议或 API 取决于服务器或服务器上的软件要执行的功能(例如,数据库服务器与 web 服务器)。大多数连接机制利用了 TCP/IP 协议,该协议要求知道至少两件关于服务器的事情;他们的 IP 地址和端口号。

IP 地址是赋予服务器的名称,这样在网络上传输的信息就知道去哪里找这些信息。这些 IP 地址可以是人类可读的,这需要域名系统(DNS)将人类可读的服务器名称映射到其数字 IP 地址,但这不是必须的。服务器上的端口只是唯一标识网络上事务的数字。端口有助于区分不同类型的网络服务,例如 web 服务(HTTP)、文件服务(FTP)或邮件服务(SMTP)等等。

连接到通用服务器

通用服务器本质上是一台远程计算机。在企业中,可以构建和供应这些服务器,以允许开发人员访问计算资源,满足本地笔记本电脑或数据科学工作台不容易满足的要求。例如,数据科学开发人员可能需要访问开源光学字符识别(OCR)工具,如 Tesseract,以便从图像中提取文本。在这种开发环境中,在独立服务器上安装像 Tesseract 这样的工具可能是最容易的。

为了连接到这些服务器,我们通常使用安全 shell 或 SSH 协议。像 PuTTY 或 WinSCP 这样的客户端应用程序允许我们使用笔记本电脑与远程服务器建立 SSH 连接。为了建立这些连接,我们需要知道服务器的名称或 IP 地址,并且可能需要一个公钥-私钥对。在大多数企业中,这些密钥对是不必要的,因为您的用户名(如员工 ID 等)可能与一个目录相关联,该目录会告诉网络中的任何服务器谁可以访问该服务器。

当需要密钥对时,公钥存储在服务器上,私钥存储在客户端(例如您的笔记本电脑)。为了使用 PuTTY 连接到服务器,我们输入服务器的名称或 IP 地址、端口(对于 SSH 通常是 22),然后在我们的客户机环境中提供私钥的位置。

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

作者图片

连接后,您可以使用命令行脚本来使用服务器的资源,这些脚本允许您执行不同的任务。具体的命令行语法将取决于服务器使用的操作系统(例如 Windows 与 Linux)。

连接数据库

数据库服务器只是运行各种数据库软件的服务器,为存储某些类型的信息而优化。为了访问这些数据库中的数据,大多数数据库(如 SQLServer、PostgreSQL 或 MySQL)都有允许访问的特殊 API。这些 API 是 Java 数据库连接(JDBC)或开放式数据库连接(ODBC)规范。

Python、R、SAS 和 Java 都有帮助建立到这些数据库的连接的库。至少,我们需要了解以下内容才能进行连接:

服务器名称

数据库名称

用户名

密码

一旦连接到数据库,您就可以使用适当的数据库语法(如 SQL for SQL databases)从数据库中提取数据。

连接到共享文件系统(如 Windows 目录、AWS 弹性文件系统)

如前所述,数据科学家经常面临数据在企业数据库中不可用的情况。相反,所需的数据可能存储在共享文件系统中。这些文件系统只是用来存储各种文件类型(包括文档、图像或声音文件)的目录。因为这些文件类型不容易存储在数据库解决方案中,所以我们将它们存储在文件系统中。

有几种不同的方法可以访问这些文件系统,以便数据科学工作台可以使用这些数据。一种方法是将文件系统目录装载到 data science workbench 服务器上,以便这些目录中的文件变得可用,就像它们是根文件结构的一部分一样。如何挂载文件系统取决于操作系统,对服务器有一定的管理权限,并知道远程服务器的 IP 地址。因此,这项任务通常由服务器架构师来执行。

访问共享文件系统中的文件的另一种方法是将文件移动到 data science workbench 可访问的位置。根据我的经验,将文件复制到可访问的位置是最安全的,尤其是在开发期间,这进一步强调了作为数据科学生态系统的一部分,访问小型开发服务器的价值。

使用 API

最后,在数据科学中,可能需要从应用程序编程接口或 API 获取数据。为客户提供服务的第三方供应商可能会通过 API 向客户公开他们的服务收集的一些数据。例如,我的一个团队被要求从使用 Qualtrics 调查平台构建和托管的调查中获取数据。为了完成这项任务,我们利用 Qualtrics API 为我们的公司调查请求数据。

今天,大多数 API 利用 URL 和 HTTP 协议来提供对信息的访问。对于数据科学家来说,连接到这些 API 需要向 API 发出请求,并传递指向正确 URL 的参数。如果处理得当,URL 会以 JSON 格式响应所需的信息。

要使用 API,您可能需要一个 API 密钥(也称为令牌),在许多情况下,这些密钥在过期之前只持续一定的时间。在代码中,目标是构建传递适当参数和身份验证令牌的 URL,以获取所需的数据。这里的是使用 Python 入门 API 的绝佳资源。

第二件事:关于安全、身份和访问管理(IAM)的更多信息

构成现代企业 IT 生态系统的所有这些服务器都需要严格的安全协议,这可能会影响数据科学家的工作方式。基本思想是确保只有那些有授权的人被允许访问信息。如今,这主要是通过基于角色的访问控制(RBAC)来处理的,在这种情况下,角色被创建并被授予执行各种操作(如访问数据库或服务器)的权限。

然后,用户被分配到被分配了角色的组,从而给予用户访问该角色所允许的操作的权限。因此,对于数据科学家来说,了解如何请求访问不同的角色以执行不同的工作职能至关重要。

例如,一名数据科学家想要访问一个企业应用程序正在使用的 MongoDB 数据库,因为它包含由用户(企业的客户)编写的自由格式文本数据。为了获得访问权限,数据科学家需要识别组“MongoDB Production”,然后选择分配给该组的适当角色“Application Schema User Read”,以便能够为她的用户获得成功连接和读取数据库的权限。

第三件事:了解计算发生在哪里

在所有这些服务器中,每台服务器都有自己的身份和访问权限,当数据科学家在工作时,很容易忘记哪些系统的负担最重。在大多数数据科学教育中,我们只知道我们用来执行工作(如争论数据和训练模型)的系统的计算限制。那些讨厌的记忆错误一定要提醒我们。

但是,了解计算发生在哪里可以帮助年轻的数据科学家开发更好的代码,利用跨服务器资源的本地计算,从而减少令人讨厌的内存错误的可能性。

事实上,训练模型需要我们的数据科学工作台能够访问强大的计算(例如 GPU 和/或集群)。然而,鉴于我们 60%以上的工作都花在争论数据上,并且大多数数据库服务器都配备了非常强大的计算环境,了解如何利用这些环境可以带来一些显著的好处。让我们看一个简单的例子。

通常需要数据科学家访问数据库,连接几个表,并将数据转换成机器学习格式。完成这些任务的一种方法是利用 data science workbench,使用 Python 的 pyodbc 库访问数据库,查询每个表,将结果作为两个数据帧输入 data science workbench 的 pandas 库,连接这些表,并处理它们。

在这个场景中,我们使用支持数据科学工作台的服务器上可用的计算来执行所有数据科学任务。作为这一过程的替代,我们可以选择利用数据库服务器来执行其中的一些任务。以下是我们的流程可能会发生的变化。

我们可以编写 SQL 来连接数据库中的表,而不是使用 pyodbc 分别从每个表中返回数据并使用 pandas 来连接它们。此外,我们可以将该表作为临时表返回给数据库,或者在对连接的数据执行争论功能的单个语句中包含额外的 SQL。然后,这些 SQL 查询的结果可以放入我们的数据科学工作台上的单个数据框架中。

第二个过程的一些好处包括降低对数据科学工作台上计算的要求。提高了性能,因为许多数据库软件解决方案针对 SQL 操作进行了优化。以及处理大型数据集的能力,因为数据库服务器通常包含高度的计算资源。

最后,我分享了一些在我刚开始学习企业数据科学时给我留下深刻印象的概念。我希望这些能帮助你有一个良好的开端,至少能让你在企业环境中更自信地驾驭数据科学。

比如参与学习数据科学、职业发展或糟糕的商业决策?加入我

用熊猫魔法从跟踪数据到时间序列

原文:https://towardsdatascience.com/from-trace-data-to-time-series-with-panda-magic-8efe0fa4ea82?source=collection_archive---------23-----------------------

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

伊洛娜·弗罗利希在 Unsplash 上的照片

本文将指导您使用强大的 Pandas 将数百万行跟踪数据快速转换成宽格式的时间序列表。

数据

在这次演示中,我将使用来自开放大学的 OULAD 数据集。完整的数据集,以及一个可爱的数据描述,可在上面的链接。这是一个关于在线课程中虚拟学习环境下学生活动的数据集。它涵盖了 7 个模块中每一个模块的 2 年和 4 个队列。

我以前写过这个数据集,因为它是我的最爱之一。你可以在我的文章中阅读我以前的一些工作,使用这些数据建立预测模型,通过学生如何与他们的学习环境互动来预测学生的成绩

今天,我们将探索压缩集合中的 student_vle.csv 文件。该文件包含学生与学习环境中可访问的在线活动交互的跟踪数据。每行代表学生完成的一项活动,包括他们在该活动中的点击次数。

目标

在我之前对这个数据集的研究中,我使用这些跟踪数据的集合来预测学生是否能通过这门课。我使用学生点击的总次数。

但是现在我每天都用学生的行为来做我的预测。这意味着使用时间序列数据来描述学生的参与度如何随着时间的推移而变化。对于本文,我将只记录学生每天点击的次数,尽管对于我的实际模型,我使用了更多的变量,并将课程每天的多个列作为输入变量。

因为我想要每个学生的时间序列数据,所以我将从个人活动交互观察中创建一个宽格式的时间序列表。每一行将是给定课程的给定群组中的单个学生。每一列都描述了当天学生在学习环境中点击活动的次数。

这些日期与该群组的开始日期相关。一些学生在课程开始前 25 天就开始工作,课程长达 270 天。因此,我们的最终表将有 295 列。

这是我们想要的样子:

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

作者图片

流程概述

第一次尝试将数据从跟踪日志转换到宽形式的时间序列表时,我尝试使用嵌套的 for 循环来读取跟踪日志中的每个条目,并将其放在新表上的正确位置。**不要这样。**我用一个计数器观察了一下这个过程,并做了一些快速计算。对于略多于 1000 万行的跟踪数据,这将花费我超过 5 天的运行时间来完成。有一种说法是,“如果你对熊猫使用嵌套的 for 循环,可能有更好的方法。”

相反,我使用布尔掩码来创建 Pandas 文档中所谓的“视图”,或者在不破坏原始数据的情况下过滤数据。为此,我分别过滤了每天的数据,并将该视图的结果按照时间顺序合并到一个新的 dataframe 中。

流程细节

跟踪数据启动了一个活动交互列表,其中包含描述活动、模块、群组、学生和点击次数的变量。我将模块、群组和学生合并到一个“注册”栏中,以便于索引。

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

作者图片

如您所见,每个学生每天都有多个条目,甚至每个活动都有多个条目,因为每个条目都是与单个活动的单个交互。学生似乎经常在同一天多次参与同一个活动。我们需要做的第一件事,为了获得每天点击的数据,是对数据进行分组。要了解更多关于如何使用 Pandas Groupby 函数的信息,你可以阅读我的关于主题的文章

我们可以使用以下代码按学生和日期对该表进行分组:

按学生和日期分组

def group_by_day(student_vle): #group by registration and day
   vle_group = student_vle.groupby(by = [‘registration’, ‘date’]) #sum up the clicks for each day for each student
   sum_clicks = vle_group.sum().reset_index()
   sum_clicks = sum_clicks.drop(columns=['id_site']) #sort by student and day
   sum_clicks = sum_clicks.sort_values(by=[‘registration’,’date’]) return sum_clicks

函数group_by_day()使用df.groupby() Pandas 方法按学生和日期对数据进行分组,并使用df.sum()聚合方法生成一个新的数据框架,其中汇总了每个学生每天的点击量。

我还做了一个完全不必要的排序,因为看到按学生和日期排序的数据很好,可以对它有一个简要的了解,但这对于接下来的步骤是完全不需要的。如果您正在处理一个更大的数据集,或者将代码投入生产,一定要跳过这一步。

此代码返回下表:

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

作者图片

我们现在每个学生每天只有一个条目。他们每项活动的点击数总和被加在一起,以表示他们全天的点击数总和,而不是每项活动交互实例的点击数总和。

由于我需要秩序,条目是按学生和日期组织的。我认为在模块的日子里看到每个学生的工作流程是很好的。

现在,我们可以开始一天一天地分割这张表,然后用下面的代码将这些部分并排放在一起:

过滤并合并

def create_time_series(sum_clicks): #Create a new dataframe to hold our timeseries data.
   time_series = pd.DataFrame() #Create one row for each student registration
   time_series['registration'] = sum_clicks['registration'].unique() start_date = sum_clicks['date'].min()
   end_date = sum_clicks['date'].max()
   date_range = range(start_date, end_date) counter = len(date_range) #Iterate through the days of the course: for date in date_range: #create a views of the data, one day at a time. single_date_df = sum_clicks[sum_clicks['date'] == date]
      single_date_df = single_date_df.drop(columns=['date']) #rename columns to describe date and data.
      new_cols = ['registration'] +   [f'clicks_on_day_{date}'] single_date_df.columns = new_cols #merge into the time series dataframe. time_series = time_series.merge(single_date_df,
                                      how='left',
                                      on='registration',
                                      validate = '1:m') print('Days remaining to be processed: ', counter)
      clear_output(wait=True)
      counter -= 1 #Missing data represents no clicks that day, so fill with 0. time_series = time_series.fillna(0) time_series = time_series.set_index('registration', drop=True) return time_series

过滤器

上面的函数遍历模块中的每一天,并使用一个布尔数组(Trues 和 Falses 数组)来过滤当天的数据。它检查每一行的“date”变量,并只返回其日期与该迭代的当前日期相匹配的行。

例如:

sum_clicks['date'] == 0将返回一个与 sum_clicks 长度相同的序列,但是为数据变量为‘0’的每一行填充 True,为其余的行填充 False。

sum_clicks[sum_clicks['date'] == 0]将只返回布尔数组包含 True 的行的视图。

当我们将上述过滤器应用于 sum_clicks 表时,我们得到:

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

作者图片

请注意,我们只有每个学生在课程第 0 天或第一天的点击量总和。你可能还会意识到,大多数学生可能不会每天都在虚拟学习环境中学习。因此每个每日视图不会包含每个学生。下一步中的左连接将有助于解决这个问题。

上述函数的下一部分将每天的视图合并到一个我们已经准备好的 dataframe 上,该 data frame 为每个学生注册记录一行,但没有数据。

合并

time_series = time_series.merge(single_date_df,
                                how=’left’,
                                on=’registration’,
                                validate = ‘1:m’)

df.merge()是将一个数据帧合并到另一个数据帧的一种方法。这相当于在 SQL 中加入表的另一种数据管理工具。这种方法的神奇之处在于合并。我准备了名为“time_series”的空数据帧,专门用来按时间顺序连接这些视图。该数据帧有一个名为“注册”的列,表示数据中存在的唯一注册。每个学生注册一排,不多不少。这很重要。

当我在 for 循环中合并每个每日视图时,我使用“registration”作为键。这确保了正确的数据进入正确的行,即使这些行在“时间序列”和我们正在合并的每日视图中的顺序不同。当我们像这样转换数据时,我们还需要考虑我们的数据完整性。用键合并是确保行之间的值不会混淆的最好方法。

how='left'告诉 Pandas 保留左侧数据帧的记录,在本例中为“时间序列”。不要丢弃任何一个,不要添加任何一个,不要重新排列它们。只需获取正确数据帧中的行,在本例中为“single_date_df”,并附加匹配的行。放弃任何不喜欢的。我们希望确保每天每个注册都有一条记录。

告诉 Pandas 使用该列作为键来匹配每个数据帧的行。否则它不知道 single_date_df 数据帧中的哪些行在合并时去了哪里!最后,validate='m:1'的意思是‘多对一’。这告诉 Pandas 检查每天的正确数据帧中是否只有一个值。还有一种方法可以确保我们的数据不会被弄乱。如果右边的数据帧“single_day_df”中没有与左边“time_series”中的注册相匹配的记录,Pandas 将用 np.nan 或“无数据”填充该值。

一旦这个循环结束,dataframe 将有每个学生每天的所有点击计数,按时间顺序从左到右排列。在某一天没有发现学生点击的任何地方都将有一个名词性名词。我们将使用time_series = time_series.fillna(0)将这些名词性名词替换为零。毕竟那个 np.nan 真正的意思就是:那个学生那天什么都没点。

我还将“注册”设置为索引,因为 Pandas 让我可以快速完成,这就是那个列的内容,学生注册的索引。我之前没有这样做,因为它稍微简化了合并语法,将它作为自己的列。

这是我们的决赛桌。很稀疏。

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

作者图片

奖励:稀疏化!

就因为我爱你们大家,我想再给你们看一个魔术。我们上面创建的时间序列数据帧大部分都是零。这在商业中被称为“稀疏数据框架”。这一个只是有点稀疏,但是我们可能使用的其他数据帧都充满了零。如果我们像这样保存它们,单独记录每个零会浪费很多空间。再一次,熊猫来救援了!

我们可以压缩数据帧,方法是从本质上删除零,同时跟踪它们的位置:

sparse_time_series = time_series.astype(pd.SparseDtype('int', 0))

上述代码通过删除零,将时间序列数据帧压缩了大约 1/3。在代码的(pd.SparseDtype('int', 0)部分,我们告诉 Pandas,产生的稀疏数据帧将具有‘int’或 integer 类型的值,并且零是我们想要压缩的。

在其他应用程序中,尤其是自然语言处理,使用这种方法可以将数据压缩到原来的许多倍。

摘要

您了解了如何将跟踪数据记录(可能是用户交互、物联网 pings 或任何定期返回值的东西)转换为按选定时间段(在本例中是按天)聚合的广泛形式的时间序列数据帧。您了解了如何使用df.groupby聚合数据,将布尔掩码传递给数据帧,比如用df[df['date'] == 0]]在一列中创建您想要的数据的视图,以及用df.merge()迭代地将每个时间段的数据附加到前一个时间段,以创建宽格式的时间序列数据帧。

另外,您还学习了一种压缩方法,可以更有效地描述稀疏数据帧。当您想要使用非常大、非常稀疏的数据集进行建模时,这变得非常重要。许多标准的机器学习工具可以有效地处理稀疏数据帧。

在上面的例子中,这些策略将处理时间从 5 天减少到 1 到 2 分钟,这取决于你的机器。

完整代码:

下面是 Github 的完整代码要点,它将下载、解压缩和转换这个特定的数据集。请随意复制它,并将其用作您自己项目的模板。

参考资料:

Kuzilek J .、Hlosta M .、Zdrahal Z. 开放大学学习分析数据集 Sci。数据 4:170171 doi:10.1038/sdata . 2017.171(2017)。

从单词到向量

原文:https://towardsdatascience.com/from-words-to-vectors-e24f0977193e?source=collection_archive---------7-----------------------

自然语言处理中文本表示的直观介绍

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

格伦·卡丽在 Unsplash 拍摄的照片

你可能会使用数据来建立机器学习模型,以解决特定的任务,如预测客户是否会流失或估计股票价格。在所有这些例子中,数据通常包含数字特征,如果任何特征以文本格式表示(例如分类特征,则应用各种编码技术将其转换为数字,因为机器学习算法被设计为仅与数字一起工作。在这里,我们实际上遇到了将单词转换成数字的基本尝试,但是在这种情况下,我们的目的仅仅是捕获关于文本 特征的信息,而不是文本本身。这对于上面提到的任务来说当然是完全没问题的,在这些任务中,目标不是理解单词,而是捕捉这些单词所包含的知识。

另一方面,像确定客户评论的情绪或预测不完整句子中的下一个单词这样的任务需要某种形式的理解给定文本中的单词。毕竟,当我们试图手动解决这些任务时,这就是我们所做的,但是我们如何教会计算机为我们做这些呢?这就是自然语言处理(NLP),人工智能(AI)的一个分支,在其他涉及分析和理解人类语言的任务中所关注的。然而,在自然语言处理的核心,存在着一个基本的挑战:文本表示。换句话说,我们如何将给定的文本转换成 NLP 算法可以处理并用来解决现实世界任务的数字形式?在本文中,我将概述一些基本的和高级的方法来应对这个基本的挑战。

基本方法

基本编号

现在,解决这个问题的最基本和最简单的方法是什么?当你思考的时候,让我建议一个。只需给字典中的每个单词分配一个唯一的数字,然后就可以收工了!

word    | number
_________________
a       |  1
able    |  2
       ...
book    |  325
       ...
paper   |  1024
       ...
zoology |  5067
       ...

这是一个很好且简单的表示,但是它有一个主要的缺点。除了这些数字没有捕捉到单词的任何含义之外,另一方面,它们给单词强加了一种隐含的和不必要的语义排序。事实上,没有任何理由让论文的编号大于图书的编号,而小于动物学的编号。 ML 算法对数据分布非常敏感,这种表示可能会误导算法认为论文在某种程度上是比更好(或更差)的候选。看来我们的第一次尝试悲惨地失败了。下一步是什么?

字符编码

在我们的第一次尝试中,我们给单词分配了任意的数字,也许这就是问题所在。也许我们应该在如何选择这些数字上变得聪明一点,并开始考虑与单词有某种联系的数字。事实上,这里可能想到的一个直接想法是字符编码。单词是由字符组成的,并且在单词和它在计算机中的字符编码表示之间已经存在一对一的映射。那么,如果我们将每个单词映射到代表其 ASCII 或 Unicode 编码的数字,而不是任意数字,会怎么样呢?啊哈!起初听起来非常简单有趣,但是如果你仔细观察,你会发现这只是告诉你单词*是什么,不是单词的意思。*换句话说(没有双关的意思),97 112 112 108 101 可能是字符序列的编码 a p p l e ( 的确如此),然而,它远不是单词 apple 的有意义的表示,因为仅仅是字母的组合并不携带它们所组成的单词的任何固有含义。这种表示也有类似于基本编号的语义排序问题。

一键编码

因此,看起来我们是在正确的轨道上,但是我们应该考虑其他方法来克服与编号相关的内在语义排序问题,而不是搜索信息性的编号分配。这就是向量出现的地方。让我们回到我们的基本编号方法,并扩展它以避免排序问题。因此,我们仍将为每个单词分配一个唯一的整数,但不是将数字保持为十进制形式,而是将数字编码为大小为|V|的二进制向量(0 和 1 的向量),其中 V 是给定文本中单词的词汇。这个向量在任何地方都是 0,除了在对应于我们分配给单词的数字的索引处,我们将在那里放置 1。让我们看一个简单的文本示例来说明这一点:

I think therefore I am.

给定这篇课文,我们的词汇由 4 个单词组成:V ={ I,think,因此,am }。我们从 1:

I   think   therefore   am
1     2        3        4

因此,我们的新单词向量将如下所示:

 **1  2  3  4** I          [**1**, 0, 0, 0]
think      [0, **1**, 0, 0]
therefore  [0, 0, **1**, 0]
am         [0, 0, 0, **1**]

正如你所看到的,在这些向量中没有隐含排序的概念,所以我们实现了一个更有效而简单的单词表示。唷!

然而,由于其自身的以下主要限制,该方案在实践中很少使用:

  • 虽然我们的玩具示例很短,但是在现实世界中,您需要处理大量的文本和大量的词汇。因为我们的独热编码单词向量的维数与词汇表的大小成正比,所以我们最终会得到大的稀疏向量,其中大多数条目都是零,这在计算上是低效的。稀疏也容易造成过拟合
  • 每个单词被视为一个独立的单元,并且在这种表示中没有单词之间关系的概念,例如相似性。例如,如果我们取任意两个向量的欧几里得距离余弦相似度,不管单词之间的潜在关系如何,我们都会得到相同的结果。换句话说,这种表示不能捕捉单词相对于其他单词的语义。
  • 如果不重新训练和扩大词汇量,就没有办法表示我们的词汇中以前没有见过的新单词(又称 out of vocabulary words )。

袋字

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

安妮·斯普拉特在 Unsplash 上的照片

让我们试着遵循我们的传统,逐步克服一种方法的缺点,希望产生一种更好的表示方法。一键编码的主要缺点之一是明显缺乏对建立单词间语义关系的支持。让我们看看是否可以通过利用我们关于语义的知识来解决这个限制。两个单词什么时候语义相似?这实际上是一个很难的问题,我们将在本文的后面回到这个问题。让我们考虑一个不同的、相对简单的问题。两段文本什么时候语义相似?一个直观而直接的答案是,当这些文本共享大量相同的单词时。因此,让我们尝试提出一种表示方法,通过将文本片段(也称为文档)而不是单个单词转换为基于其组成单词的向量来编码这一事实。与我们之前的方法类似,我们为每个单词分配一个唯一的编号,但是我们不是用这些编号来表示单词,而是使用它们和相应的词频来构造给定文档的有用表示。

更具体地说,我们将每个文档转换成一个维为|V|的向量,其中 V 是我们的词汇表,索引 i 处的元素只是对应于数字 i 的单词在文档中出现的次数。让我们看几个例子来更好地理解这个概念:

Document 1: I think therefore I am
Document 2: I love dogs
Document 3: I love cats

我们的词汇是 V = {我,想,因此,我,爱,狗,猫}让我们像以前一样分配唯一的数字:

I   think   therefore   am   love   dogs   cats
1     2         3       4      5     6       7

那么我们的文档向量将是:

 I  think  therefore  am  love  dogs  cats
Document 1: [ **2**,   **1**,      **1**,      **1**,    0,   0,    0 ]
Document 2: [ **1**,   0,      0,      0,    **1**,   **1**,    0 ]
Document 3: [ **1**,   0,      0,      0,    **1**,   0,    **1** ]

这些向量本质上把相应的文档表示为单词的包(集合),而不考虑上下文和单词的顺序。如果你注意到了,文档 1 和文档 3 的向量在向量空间中彼此非常接近,这反映出它们有许多共同的单词。实际上,这些文档之间的欧几里德距离远小于例如文档 1 和文档 2 之间的距离。因此,这种表示允许我们测量文档的语义相似性,而不是一次性编码,但是如果你更深入地观察,你会意识到这种表示离一次性编码不远,事实上可以通过简单地将文档中单词的一次性编码向量相加来实现。这里真正的区别是,我们是根据文件而不是文字来操作的。

虽然这种方法似乎提供了更丰富、更简单的表示,并且事实上在实践中被普遍使用,特别是对于文本分类,但是它有几个主要缺点:

  • 我们的新文档向量的大小仍然由词汇大小决定,这意味着高维度和稀疏性问题仍然存在。
  • 新的语义相似性特性非常严格,严重依赖于共享单词之间的字面词典匹配。例如,文档“我游泳”、“我游泳”和“我走路”的向量在向量空间中彼此距离相等,即使前两个句子在意义上非常接近。
  • 句子中的顺序可以极大地改变意思,因此将句子视为没有顺序和上下文的单词集合会导致像“狗吃了食物”和“食物吃了狗”这样的文档用相同的向量表示。
  • OOV 问题仍然没有解决。

一袋 n 元硬币

像往常一样,让我们再次尝试补救前一种方法的一些问题,看看我们在哪里着陆。单词袋方法的一个主要问题似乎是缺乏顺序和上下文。你能想出一个简单的方法来抓住这些概念吗?让我们后退一步,找出问题的根源。单词袋方法缺乏上下文的原因是因为它将单词视为独立的原子单位。另一方面,上下文通常不能从一个单词中确定,而是在单词序列出现时出现。因此,与其将文档表示为一个由单个单词组成的包,不如将其视为一个由一些固定大小的连续单词序列(也称为*n-grams)*组成的包,从而捕获一些上下文。然后,我们的词汇表将由 n 元语法组成,像以前一样,我们将为每个词汇表条目分配一个唯一的数字,并用向量来表示文档,这些向量对这些条目在文档中出现的频率进行编码。让我们将这个概念应用到上面提到的文档中。如果我们将每个文档分成由两个相邻单词组成的块(即 2-gram 或 bigram),我们会得到以下词汇表:

V = {我思故我思,故我在,我爱爱狗爱猫}

然后我们给每个词汇成员分配一个唯一的数字:

I think:         1
think therefore: 2
therefore I:     3
I am:            4
I love:          5
love dogs:       6
love cats:       7

现在我们可以为每个文档构造二元模型向量:

 **1  2  3  4  5  6  7**
Document 1: [ **1**, **1**, **1**, **1**, 0, 0, 0 ]
Document 2: [ 0, 0, 0, 0, **1**, **1**, 0 ]
Document 3: [ 0, 0, 0, 0, **1**, 0, **1** ]

如果你注意到,我们之前的单词包方法只是 n 元单词包的的一个特例,其中 n=1。我们还看了这种方法最常用的一种情况,叫做 二元模型 表示法。另一个流行的案例被称为毫不奇怪的 三元模型 其中 n=3。正如您所看到的,扩展我们对文档中语义含义的更好代表的概念有助于我们捕捉更多的上下文。事实上, n 的值越大,包含的上下文就越多,但是会产生更稀疏的向量。一般来说,n=2,3 的 n-grams 的方法由于其上下文优势而优于单词包方法,但其他问题,如高向量维数、稀疏性和缺乏对 OOV(词汇外)单词的支持,仍然使其在实际应用中不太有效。

TF-IDF

在进入更高级的方法之前,我们先来看看最后一种基本的矢量化方法。这一次,让我们考虑一个文档中单词的不同方面,以通知我们的向量表示。我们仍然在寻找文档的有意义的表示,问题是文档还有什么特征?好吧,想象一下,给你一篇像这篇文章这样的文章,让你用几个关键词来总结它。你会怎么做?你会简单地报告前 5 个最常用的词吗?可能不会,因为你很可能会以类似于 am,are,is,like,the,this,that (又名停用词)的词语结束。所以,你会去寻找对文档来说总体上更加重要的单词,对吗?例如,文本表示单词矢量化将是表示这篇文章的良好候选。这是我们下一个表示方法背后的核心思想。我们希望将文档中的每个单词与某种重要性或相关性分数相关联,并用这些分数的向量来表示文档,而不是分配任意的数字。现在问题变成了如何计算这些分数?在进入公式之前,让我们理解它们背后的直觉。我们的目的是设计一个公式,让文档中重要的单词(也称为术语)比不太重要的单词获得更高的分数。我们知道,对于某些文档来说重要的单词可能会在该文档中频繁出现(虽然大多数情况下很少出现),但是几乎总是比停用词少得多。这意味着项频率(TF) 不足以简单地表示重要性,事实上,大多数时候是错误的。然而,这是我们用来计算最终分数的必要信息。因此,让我们根据我们的目的来调整这个值。我们实际上需要将这个 TF 分数乘以另一个分数,这个分数对于停用词要低得多,对于重要术语要高得多。并且这个新的乘数被称为逆文档频率(IDF) 分数,其本质上依赖于停用词不仅在一个文档中频繁出现而且在所有文档中频繁出现的简单实现。因此,如果我们简单地取一个单词出现在文档中的频率的倒数,那么对于重要的单词,这个值应该更高,因为它们最有可能只出现在它们的相关文档中(因此文档更少)。因此,我们得到下面的公式来计算给定文档 d: 中每个术语 t 的得分

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

来源:作者

其中每个功能定义如下:

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

来源:作者

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

来源:作者

如果你注意到了,这里我们取倒频的对数,这样做的原因是为了惩罚非常大的值,这些值是我们从极其罕见的术语(如拼写错误的单词)中得到的。

现在我们已经为我们的表示提出了评分方法,让我们将它应用到我们的一个文档(文档 2 )中,看看它在实践中的表现。请注意,我们有 3 个文档,文档 2 总共有 3 个术语。

**word   TF score     IDF score          TF-IDF score**
I      1/3 = 0.33   log(3/3) = 0       0.33 * 0 = 0
love   1/3 = 0.33   log(3/2) = 0.18    0.33 * 0.18 = 0.059     
dogs   1/3 = 0.33   log(3/1) = 0.48    0.33 * 0.48 = 0.158 I   think   therefore   am   love   dogs   cats
Document 2 vector: [0     0        0        0    0.059  0.158    0]

正如您所看到的,我们最终得到了单词 I 的最低值,它对所考虑的文档并不重要,而更高的值被授予更相关的单词。这意味着 TF-IDF 表示还允许我们测量文档之间的语义相似性,虽然它通常用于 NLP 应用,如文本分类和信息检索,但它仍然存在一些基本缺点,如高维度、稀疏性和无法处理 OOV 词。

高级方法

单词嵌入

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

来源:developers.google.com

我们在寻找单词的有意义的表示方面已经走了很长的路,并且我们已经看到了一些有趣的基础方法,但是我们仍然无法逃脱高维度和稀疏性的诅咒。以前的表述似乎也不能概括单词的真正语义。我们能做得更好吗?让我们重温一下我们提出的、但在本文前面被方便地回避的难题:什么时候两个词在语义上相似?让我们稍微分离一下语义相似性的概念。我们如何确定两个单词是否相似?比如这两个词相似吗?当然是的,因为两者都指人类。啊哈!所以,在人类的语境中,这些词是 语义相近的 以此类推,类似于国王、王后、男孩、女孩的其他词语在同一语境中也是同等相关的。但是如果我们转换上下文,比方说,从性的角度来说,那么突然之间,这些术语似乎没有了相同程度的相似性。显然,在这种情况下,男人女人更类似于男孩,女人本身比男人更类似于女孩*。那么,从这个观察中我们能得出什么结论呢?那就是语境在确定语义相似度中起着举足轻重的作用。因此,按照这种推理,如果我们能够以某种方式将这些上下文编码成一个数字向量,那么产生的向量将比我们迄今所看到的更能代表它们相应的单词。让我举个例子来说明一下。我将基于以下上下文为上面提到的每个单词(加上一些额外的单词)构建一些虚拟向量:*

  1. 是人吗?
  2. 是男的吗?
  3. 是女的吗?
  4. 是国家统治者吗?
  5. 是无生命的吗?
**word/context   1\.    2\.    3\.     4\.    5.**
king         [ 0.9   1     0      1     0 ]
queen        [ 0.9   0     1      1     0 ]
man          [ 1     1     0      0.5   0 ]
woman        [ 1     0     1      0.5   0 ]
boy          [ 1     1     0      0.5   0 ]
girl         [ 1     0     1      0.5   0 ]
book         [ 0     0     0      0     1 ]
paper        [ 0     0     0      0     1 ]

这里,每个维度中的值代表了我们对单词与所考虑的上下文的相关性的信任程度。正如您所看到的,在某些上下文中语义相似的单词在与相同上下文相关联的维度上的向量空间中也是彼此接近的。现在注意这个向量的根本不同之处。它的维度不再与我们的词汇大小相关,而是与通常小得多的上下文(特征)的数量相关,这意味着我们可以用低维、密集的向量来表示单词,同时提供了检测语义相似性的关键好处。但是利益实际上并没有到此为止。这种表示也允许我们回答其他关于语言模式的有趣问题。例如,我们可以问男人之于国王就像女人之于什么?语言学上的答案是*女王,*实际上,你可以通过对向量进行如下操作来得出这个答案:

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

这也从直觉上讲是有道理的,如果你从*国王、身上去掉男子气概,你应该只剩下纯粹的皇室概念,给这个结果加上女人味应该会给你一个王后。*宾果!

所以,现在我们有了一个巧妙的方法,用紧凑的向量以一种更加语义直观的方式来表示单词(又名单词嵌入),问题变成了我们实际上如何得到这些向量?我们查看了一个带有几个上下文的小样本语料库,但是在庞大词汇的现实世界中,手动生成这些向量几乎是不可能的。同样,对于向量维数,我们应该考虑多少上下文也不清楚。在 2013 年,Mikolov 等人[1]的一项革命性工作表明,基于神经网络的表示模型“word2vec”可以实现上述示例中所示的结果。该模型基于大量文本学习给定维度(超参数)的单词嵌入,然而,所学习的向量不像示例中使用的向量那样可解释,因为从向量来看,每个维度代表什么类型的上下文并不十分清楚。我不会深入模型如何工作的细节(也许在未来的文章中),但是 paper 提出的模型架构背后的核心思想也依赖于上下文的重要性。他们的“连续单词包”方法本质上是试图预测句子中的单词,给定它周围的单词作为上下文,而“SkipGram”方法则相反,并推断给定单词的上下文。

虽然单词嵌入表示解决了基本方法的大多数关键问题,但是一个问题即处理 OOV 单词的能力仍然没有被覆盖。为了解决这个问题,一种称为“fastText”的流行技术[6]通过使用关于单词部分的信息,例如形态属性(例如前缀、后缀等),对单词嵌入训练进行了有趣的修改。).这种方法背后的关键思想是通过单词的组成字符 n 元文法来表示单词,并一起学习单词和字符 n 元文法的嵌入。为了生成一个我们从未见过的单词的嵌入,比方说,parocial,我们将它分解成它的字符 n-grams,如 par,aro,roc,och,…,ial ,并组合这些 n-grams 的嵌入来生成单词parocial 的嵌入。

单词嵌入方法已被证明是 NLP 的基础构件,并从那时起启发了更复杂的文本表示方案。其中一个称为“doc 2 vec”[2]扩展了“word2vec”方法,直接学习任意长度文本的表示。在过去几年中,已经引入了更多的全局(GloVe [3])和上下文单词表示(ELMo [4],BERT [5])来解决与简单单词嵌入相关联的单词歧义问题(即,表示在不同上下文中表示不同事物的单词,例如同音异义词)。这些表示非常复杂,需要有自己独立的博客帖子。

结论

在本文中,我试图阐明 NLP 中文本表示的一些基本和高级矢量化方法背后的动机和直觉。我讨论了各种技术的优缺点以及它们之间的联系。神经文本表示仍然是 NLP 的一个不断发展的领域,其艺术状态变化很快,然而,所有这些进步的核心是本文讨论的基本思想。

参考文献

[1] 托马斯·米科洛夫程凯格雷戈·科拉多杰弗里·迪恩向量空间中单词表征的高效估计 (2013)

[2] 郭诉勒托马斯·米科洛夫分发陈述的句子和文件 (2014)

[3]杰弗里·潘宁顿、理查德·索切尔和克里斯托弗·曼宁。2014.手套:单词表示的全局向量

[4] 马修·e·彼得斯马克·诺伊曼莫希特·伊耶马特·加德纳克里斯多佛·克拉克肯顿·李卢克·泽特勒莫耶深层语境化的话语表征

[5] 雅各布·德夫林张明蔚肯顿·李克里斯蒂娜·图塔诺娃伯特:语言理解深度双向变形金刚前期训练

[6] 皮奥特·博亚诺夫斯基爱德华·格雷夫阿曼德·茹林托马斯·米科洛夫用子词信息丰富词向量

使用 FRONNI 计算具有置信区间的机器学习模型性能度量

原文:https://towardsdatascience.com/fronni-a-python-library-for-quickly-calculating-machine-learning-model-performance-metrics-with-3baf28eaa5c0?source=collection_archive---------31-----------------------

一个 Python 库,用于快速计算和显示带有置信区间的机器学习模型性能指标

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

FRONNI 这个名字来源于统计学家 Bradley Efron 的姓氏,Bradley Efron 是 bootstrap 重采样技术的发明者,John Ioannidis 是广受好评的文章《 为什么大多数发表的研究结果都是假的 **》的作者。**照片由 Minh TranUnsplash 拍摄

数据科学家花费大量时间评估他们的机器学习模型的性能。这样做的一种常见方法是针对分类问题的分类报告,例如内置在 scikit-learn 库中的报告(在 Github 上被引用超过 440,000 次)。类似地,对于回归问题,人们使用 r2 得分MSEMAE

依赖这些的问题是,当我们的测试样本中有不平衡的和/或小的数据集时,构成每个点估计的数据量可能非常小。因此,无论对评估指标有什么样的估计,都不可能真正代表现实世界中发生的事情。相反,向读者呈现一系列置信区间的值会好得多。

例如,我们可以通过使用 bootstrap 技术从原始数据集(替换)创建数百个样本,然后丢弃最极端的 5%的值以获得 95%的置信区间,从而轻松创建任何感兴趣的指标的置信区间。

然而,当数据集很大时,如上所述运行引导程序会变成计算量很大的计算。即使是相对较小的 100 万行样本,当重采样 1000 次时,也会变成 10 亿行数据集,并导致计算花费接近一分钟的时间。当离线进行这些计算时,这不是问题,但是工程师经常在 Jupyter 笔记本上交互工作,并且希望快速得到答案。出于这个原因, Meta (又名脸书)决定为常见的机器学习指标创建一些这些计算的快速实现,例如使用 numba 库的 precision & recall,它提供了比常规 Python 并行处理代码大约 23 倍的加速。

让我们用分类问题的例子来证明这一点。考虑标准的手写数字数据集,我们正在构建一个 ML 模型来识别数字。

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

到目前为止,这是标准的东西。现在,我们可以使用 FRONNI 来获得精确度、召回率、f1 分数和相关的置信区间。PyPi 中有这个库,要安装 FRONNI 只需运行 pip install。

pip 安装 fronni

现在运行 FRONNI 分类报告,以获得每个类别的精确度、召回率和 f1 分数及其置信区间。您可以使用参数 n 控制自举样本的数量。

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

瞧啊。,它给出了每个类的精确度、召回率和 f1 分数的上限和下限。

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

数字分类器的 FRONNI 分类报告输出示例。

类似地,FRONNI 回归模块给出了 RMSE、r2 评分和 MAE 的置信区间。完整的文档请参考 GitHub 库。

完整的深度学习组合项目第 1 部分

原文:https://towardsdatascience.com/full-deep-learning-portfolio-project-part-1-78df161214aa?source=collection_archive---------14-----------------------

系统地寻找鸟类图像分类任务的最佳训练策略

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

托马斯·列斐伏尔在 Unsplash 上的照片

介绍

想从事机器学习工程师的工作,但从未实际从事过机器学习项目?然后找工作真的不容易。大多数公司都在寻找有经验的机器学习工程师。我所说的经验并不是指你参加过机器学习在线课程。不要误解我的意思:参加机器学习在线课程以获得更多关于该主题的知识总是很棒的!然而,对于一个雇主来说,正确地评估一门在线课程是非常困难的。有些很容易,有些很有挑战性。然而,雇主能评估好的是自己的项目。在那里,他可以直接看到你如何处理某些话题,以及你已经从项目中获得了什么经验。

然而,在这些项目中,你不应该只关注机器学习部分,这主要是在 Jupyter 笔记本上完成的,但你也应该考虑部署。因为现在训练深度学习模型不再具有挑战性。像 Keras 这样的库允许你在几行代码内创建和训练一个深度学习模型。然而,如果你能够开发一个成熟的应用程序,那么你肯定会更有趣。此外,如果你已经开发了一个网页,并可以在那里展示你训练有素的模型,而不是让他浏览你的 Jupyter 笔记本,在那里只能看到代码和打印输出,那么你可以更好地说服一个没有技术背景的招聘人员。

为此,我创作了两篇文章,其中系统地发现并应用了深度学习训练策略,并通过网站部署了训练好的模型。

在这个系列的第一部分,我想向你展示一个如何为图像分类任务找到一个好模型的系统方法。作为数据集,我决定使用来自 Kaggle 的开源鸟类物种数据集,你可以在这里找到。代码和所有文档都可以在我的 Github 页面这里找到。代码是用 Python 写的。

在本系列的第二部分,我将向您展示如何使用 html 和 Flask 开发一个完整的 web 应用程序,包括前端和后端。你可以在这里找到文章。

如果你对我如何使用 Docker 和 Github Actions 将完整的 web 应用程序部署到 AWS Elastic Beanstalk 感兴趣,那么我可以推荐你阅读我的这篇文章。

内容

在第一部分中,我介绍了数据集,并已经对输入数据进行了一些预处理。在第二部分,我将向您展示我如何使用 Tensorflow 创建输入管道,以及它的代码是什么样子。方法部分描述了我为找到最佳训练策略而进行的各种评估。每当要训练 CNN 时,可以使用这些评估。结果部分显示了最终培训策略的培训结果。结论部分总结了这个项目的结果,而展望部分提供了本系列第二篇文章的参考。

探索性数据分析和预处理

作为第一步,我将提供的“Bird_Species.csv”文件加载到 pandas 数据框中(图 1)。

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

图 1:初始加载的数据帧头。

数据集的创建者还提供了第二个 csv 文件,包含图像的类和一些元数据。我还将这个 csv 文件加载到 pandas 数据框中(图 2)。

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

图 2:包含类和图像形状的数据帧的头部。

然后,我使用第二个数据框快速检查了该数据集中不同类的数量,并将其与“Bird_Species.csv”文件(代码 1)中唯一标签的数量进行了比较。

代码 1:读入数据文件并检查所有的类是否都存在于完整的数据集中。

有趣的是,根据“class_dict.csv”文件,鸟类有 300 个不同的类别,但在整个数据集中,只有 285 个不同的类别。因此,我检查了哪些类没有出现在数据集中,并查看了文件夹,以确定它们是真的没有出现,还是只是在“Bird_Species.csv”文件中丢失了。确实有缺失班级的图片。这意味着现有的 csv 文件不正确。所以我首先创建了一个干净的 csv 文件,保存它并在这个项目的其余部分使用它。这一步的代码可以在“Make_Clean_Dataset.ipynb”笔记本这里找到。

既然数据集是干净的,我开始进一步研究它。我从绘制数据集的一些随机示例图像开始,以便对图像的外观有所了解。图 3 显示了两个示例鸟图像。

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

图 3:鸟类数据集的两个示例图像。左图是一只非洲冠鹤,右图是一只冈比亚鹌鹑。

作为下一步,我绘制了已经由作者创建的训练和测试集的分布图(图 4 和图 5)。这对于检查数据集是否不平衡以及确保测试分布和训练分布大致相同非常重要。

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

图 4:从数据集作者创建的训练集的分布。

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

图 5:从数据集作者创建的测试集的分布。

可以看出,训练集是不平衡的,而测试集是完全平衡的。这清楚地表明测试集来自不同于训练集的分布。这可能会导致模型在测试集上表现良好,但在真实世界数据上表现不佳,因为测试分布没有反映“真实”分布。因此,我决定使用 Scikit-Learn 的分层混洗技术创建自己的训练、验证和测试集。但是在分割数据之前,我还对标签进行了一次性编码,以匹配 CNN 所需的输入格式。代码 2 显示了这些步骤的代码,包括清理后的数据集 csv 文件的初始加载。

代码 2:用于通过执行分层混洗分割来创建训练、验证和测试集的代码。

图 6 和图 7 显示了分层洗牌拆分后训练集和测试集的分布。这两个发行版现在来自同一个发行版。

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

图 6:使用分层洗牌拆分后的训练集分布。

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

图 7:使用分层洗牌拆分后测试集的分布。

训练数据集有点不平衡,这应该不是问题。但是让我们稍后检查过采样是否可以提高这个数据集的性能。

这里没有添加验证集的数字,但是它与测试集和训练集具有相同的分布。

创建输入管道

对于训练深度学习模型来说,拥有一个好的输入管道总是很重要的。Tensorflow 通过其 ImageDataGenerator 类为您提供了很好的支持。这个类允许您指定一些预处理,让您从一些数据扩充中选择,并允许您在训练期间批量加载图像。这一点尤其重要,因为对于大型数据集,如果在训练之前必须先加载一次所有图像,将会占用大量 RAM。

对于鸟类分类,我创建了以下输入管道步骤:

  1. 应用一些随机选择的数据扩充,这样大约 10%的数据没有被扩充。
  2. 归一化图像像素值,使它们在(0,1)的范围内。

我使用了一些来自 imgaug Python 库的基本数据扩充,以增加数据集中的变化。这个库非常有用,因为它实现了几乎所有你能想到的扩充。本项目使用的数据扩充是通过对示例图像应用扩充并评估图像是否仍然有意义来手动选择的。在上面提到的 Github 存储库中,可以在 Jupyter 笔记本中看到不同应用增强的评估结果,称为“Check Augmentations.ipynb”。一般来说,可以使用这些增强,并且可以一次用一个额外的增强来训练模型,并且将其性能与没有任何增强的基线模型进行比较。但是为了这个项目,我决定不做这个评估,因为我假设每一个增强都会导致与基线模型相比的改进。

我使用了以下扩展(图 8):

  1. 左右翻转图像。
  2. 将像素值乘以偏移量。
  3. 盐和胡椒。
  4. 伽玛对比度变化。
  5. 向像素值添加偏移量。
  6. 添加附加高斯噪声。
  7. 应用运动模糊。
  8. 应用仿射变换。
  9. 旋转图像。
  10. 应用弹性变换。

增强“添加”和“伽玛对比度”从不同时使用,因为这可能导致不真实的图像。

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

图 8:应用增强的概述(图片由作者提供)。

代码 3 展示了创建输入管道的完整 Python 代码,同时使用了 Tensorflow 的“flow_from_dataframe”选项。这允许在训练期间分批加载图像。您只需要一个 csv 文件,其中第一列包含图像的名称,其他列包含该图像的标签。为了首先找到最佳的 CNN 架构,我决定使用 8 的批量大小,并将图像的大小固定为(224,224)。

代码 3:使用 Tensorflow 和 ImageDataGenerator 类创建输入管道的代码。

方法学

输入管道已创建。现在是时候找到最适合的训练策略了。首先,比较了一些最先进的 CNN 架构,并选择性能最佳的架构作为本项目剩余部分的架构。其次,比较不同的图像尺寸,以便找到最佳的图像尺寸。第三步,尝试过采样来处理稍微不平衡的数据集。最后一步,使用贝叶斯超参数搜索来搜索最优超参数。

方法部分的代码没有包含在本文中,因为它太长了。请随意检查我的 Github Jupyter 笔记本,查看并复制我创建的代码。我只包含了对数据帧进行过采样的代码,因为这可能是更有趣的代码部分。

CNN 架构比较

有许多不同的 CNN 架构可用于鸟类分类器。在本项目中,选择了六种不同的 CNN 架构(表 2)并进行相互比较。每种架构都用于训练具有表 1 中给出的超参数的鸟分类器。最后,最佳验证 f1 分数被存储并用于找到最佳 CNN 架构。这里,仅使用最佳验证 f1 分数,并且忽略了这一点,即每个体系结构具有不同的训练复杂性,并且可能一个体系结构仅导致稍差的验证 f1 分数,但是具有比达到更高验证 f1 分数的模型少得多的参数。但是对于未来的优化,也可以考虑训练复杂度,并且可以将其包括在决定中,将哪个编码器架构用于最终的鸟分类器。表 2 还显示了最终结果。可以看出,DenseNet121 实现了最佳的 f1 验证分数,因此被用作鸟类分类器的最终编码器架构,也用于该项目的其他评估。图 5 显示了不同编码器在训练过程中的 f1 分数,图 4 显示了训练过程中的损失值。

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

表 1:用于 CNN 架构比较的超参数。

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

图 4:不同编码器架构的训练过程中的损耗值。使用分类交叉熵作为损失函数。

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

图 5:F1-不同编码器架构训练过程中的得分。

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

表 2:在训练过程中使用的 CNN 架构和它们的最好成绩。

图像大小比较

在通往最佳训练策略的道路上,接下来应该找到最佳图像尺寸。将评估和比较四个不同的选项。使用表 1 中的超参数为四种图像尺寸中的每一种训练 DenseNet。结果可以在表 3 中找到,其中再次将最佳验证 f1 分数作为决策的衡量标准。图 6 和 7 显示了在不同图像尺寸的训练过程中 f1 分数和损失值的结果。

正如人们所猜测的:图像越大,模型的性能越好。然而,从图像大小 192x192 到 224x224,最佳验证 f1 分数仅增加 0.4%。因此,我决定使用 192x192 作为图像大小,以便减少可训练参数的数量,并稍微加快训练过程。

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

图 6:F1-在用不同图像尺寸训练 DenseNet 的训练过程中的分数。

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

图 7:用不同图像尺寸训练 DenseNet 的训练过程中的损失值。使用分类交叉熵作为损失函数。

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

表 3:最佳验证 f1-用不同图像尺寸训练 DenseNet 的得分和准确度。

过采样

如前所述,数据集略有不平衡。因此,可以使用过采样来更好地平衡数据集,并避免模型更偏向多数类而预测少数类不太准确的风险(图 8,代码 4)。

代码 4:获取数据帧并对其进行过采样以获得完全平衡的数据帧的代码。过采样是通过对少数类更频繁地重用图像来实现的。

然后使用过采样数据集和来自表 1 的超参数来训练 DenseNet121,除了时期的数量减少到 20 个时期。这是由于过采样,因此是模型应该学习得更快的原因,因为相同的图像在一个训练时期内不止一次可用。过采样模型的最佳验证 f1 分数为 95.4%,这与没有应用过采样的情况几乎相同。因此,过采样不用于训练最终的鸟类分类器,因为它也需要更多的训练时间,并且通常更容易过拟合。

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

图 8:应用过采样后的训练数据集。训练集现在完全平衡,这是通过复制少数类的相同图像来实现的,只要每个类具有相同数量的样本。

贝叶斯超参数搜索

作为找到最佳训练策略的最后一步,使用贝叶斯超参数搜索来优化超参数。贝叶斯搜索的优点在于,它在寻找最优超参数方面比随机搜索更有效,并且比网格搜索需要更少的迭代。κ为 3 的高斯过程被用作优化策略。手动提供四个初始点,这将有助于将优化过程引向最佳方向。贝叶斯优化被执行 12 次迭代。使用称为“置信下限”的获取函数,并且它获得最佳验证 f1 分数作为要优化的度量。置信下限试图最小化其优化度量。因此,使用负的最佳验证 f1 分数。表 4 显示了超参数使用的搜索空间,而表 5 显示了最佳参数。衰减率指定学习率在每个衰减步骤时期应该减少多少。

图 9 显示了贝叶斯超参数搜索的收敛图。可以看出,最佳参数是在最后一次迭代中找到的。这是由于贝叶斯优化的性质。在开始阶段,存在大量的不确定性,Bayes 模型在非最优区域采样较多。但是最后,模型在最佳区域中采样更多,因此找到越来越好的参数。

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

表 4:贝叶斯超参数优化的优化超参数及其搜索空间。

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

表 5:通过贝叶斯超参数搜索找到的最佳超参数。

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

图 9:贝叶斯优化的收敛图。该图显示了迭代次数和获得的最佳 f1 分数。

结果

使用在方法部分中找到的所有发现来训练鸟类分类器。鸟类分类器现在已经训练了 30 个时期,根据验证 f1 分数的最佳模型被存储为 Tensorflow 模型(图 10)。之后,加载验证 f1 分数为 96.2%的最佳模型,并在保留测试集上进行评估,以检查最终 birds 分类器在真实世界数据上的性能。最佳模型在保留测试集上获得了几乎 96%的 f1 分数,这与在训练过程中获得的最佳验证 f1 分数几乎相同。这表明,该模型在真实世界数据上表现得非常好,并且该模型在训练和验证数据上没有过度拟合。

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

图 10:用于训练最终鸟类分类器的训练指标。

结论

最终的鸟类分类器在保留测试集上实现了几乎 96%的 f1 分数。由于其良好的性能,DenseNet121 被用作 CNN 的底层架构。作为目标图像尺寸,使用 192x192 像素的尺寸。训练集不是过采样的,因为在过采样的训练集上训练的模型与在非过采样的训练集上训练的模型获得了近似相同的验证 f1 分数。利用贝叶斯超参数搜索优化了一些超参数。

观点

在本系列的第二部分中,我开发了一个 API,前端用 HTML 编写,后端应用程序使用 Python 库 Flask。如果你对它的工作原理感兴趣,请阅读第二篇文章。你可以在这里找到第二篇。总的来说,我总是建议您将最终的机器学习应用程序嵌入到可部署的应用程序中,因为这是机器学习工程师在一天结束时需要考虑的问题。

谢谢你把我的文章看完!我希望你喜欢这篇文章和我参与的项目。如果你想在未来阅读更多类似的文章,请关注我,保持更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值