如何使用 Python 下载图像
了解如何使用 Python 模块(如 request、urllib 和 wget)下载图像文件。
来源: Giphy
最近,我在用一个远程系统工作,需要下载一些我的代码最终会处理的图像。
我可以在我的终端上使用 curl 或者 wget 来下载文件。但是,我希望最终用户的整个过程是自动化的。
这让我想到了一个问题:
如何使用 Python 下载图像?
在本教程中,我将介绍几个可用于下载 Python 文件(特别是图像)的模块。涵盖的模块有: 请求 、 wget 、 urllib 。
免责声明:不要下载或使用任何违反其版权条款的图像。
设置
本教程中使用的代码是在安装了 Python 3.6.9 的 Ubuntu 系统上测试的。
我强烈推荐建立一个虚拟环境,其中包含所有测试所需的库。这是你可以做到的。
$ virtualenv image_download
$ source ./image_download/bin/activate
$ pip3 install requests wget
我们将在教程中使用的图像位于这里。是 免费用于商业用途,不需要任何归属 。
我们将用于下载的图像 URL 将是:
[https://cdn.pixabay.com/photo/2020/02/06/09/39/summer-4823612_960_720.jpg](https://cdn.pixabay.com/photo/2020/02/06/09/39/summer-4823612_960_720.jpg)
我们将创建一个简短的脚本来从给定的 URL 下载图像。
脚本将下载与脚本文件相邻的图像,并且可选地,保留原始文件名。
请求模块
请求 是 Python 中一个整洁且用户友好的 HTTP 库。它使得发送 HTTP/1.1 请求变得非常简单。
这似乎是使用 Python 下载任何类型文件的最稳定和推荐的方法。
来源: Giphy
这是完整的代码。
来源:作者
不要担心。让我们一行一行地分解它。
我们将从导入必要的模块开始,还将设置图像 URL。
import requests # to get image from the web
import shutil # to save it locallyimage_url = "[https://cdn.pixabay.com/photo/2020/02/06/09/39/summer-4823612_960_720.jpg](https://cdn.pixabay.com/photo/2020/02/06/09/39/summer-4823612_960_720.jpg)"
我们使用切片符号将文件名从图像链接中分离出来。我们使用正斜杠(/
)分割图像 URL,然后使用[-1]
分割最后一段。
filename = image_url.split("/")[-1]
来自请求模块的get()
方法将用于检索图像。
r = requests.get(image_url, stream = True)
使用
stream = True
来保证没有中断。
现在,我们将以二进制写入模式在本地创建文件,并使用copyfileobj()
方法将我们的映像写入文件。
# Set decode_content value to True, otherwise the downloaded image file's size will be zero.
r.raw.decode_content = True# Open a local file with wb ( write binary ) permission.
with open(filename,'wb') as f:
shutil.copyfileobj(r.raw, f)
我们还可以使用 请求的状态代码 添加某些条件来检查图像是否被成功检索。
我们还可以在下载大文件或者大量文件时通过 增加进度条 来进一步改进。这里的就是一个很好的例子。
Requests 是使用 Python 下载任何类型文件的最稳定和推荐的方法。
Wget 模块
除了 python 请求模块,我们还可以使用 python wget 模块 进行下载。
这是 python 中相当于 GNU wget 的。
使用起来相当简单。
来源:作者
Urllib 模块
通过你的程序访问网站的标准 Python 库是 urllib 。请求模块也使用它。
通过 urllib,我们可以做多种事情:访问网站,下载数据,解析数据,发送 GET 和,POST 请求。
我们可以使用几行代码下载我们的图像:
我们使用了 urlretrieve 方法将所需的 web 资源复制到本地文件中。
需要注意的是,在一些系统和很多网站上,上面的代码会导致一个错误:HTTP Error:HTTP Error 403:Forbidden。
这是因为很多网站不喜欢随机程序访问他们的数据。一些程序可以通过发送大量请求来攻击服务器。这将阻止服务器运行。
这就是为什么这些网站可以:
- 屏蔽你你会收到 HTTP 错误 403 。
- 向您发送不同的数据或空数据。
我们可以通过修改用户代理来克服这个问题,这是一个随我们的请求一起发送的变量。默认情况下,这个变量告诉网站访问者是一个 python 程序。
通过修改这个变量,我们可以像普通用户在标准的 web 浏览器上访问网站一样。
你可以在这里阅读更多关于它的。
结论
请求 已经成为 Python 中事实上的下载东西的方式。
甚至 urllib 文档页面 都推荐请求更高级别的 HTTP 客户端接口。
如果你想在你的程序中有更少的依赖项,你应该选择 urllib。它是标准库的一部分。所以,没必要下载。
希望你觉得这个教程有用。
重要链接
如何使用 Python 下载文件
émile Perron 未喷涂的图像
权威指南
了解如何使用 python 下载 web 抓取项目中的文件
P ython 非常适合在互联网上抓取网页,但在从我想做的网站上抓取一些标题或链接后,我的首要任务之一就是下载文件。我需要一种方法来自动化这个过程!
这里我们将概述如何做到这一点。
到本文结束时,您将
- 注意 python 中 HTTP 处理包的选择
2.详细了解请求包
2.知道如何使用请求包下载文件
3.如何用请求包处理大文件?
4.如何下载使用请求包重定向的文件。
python 中有很多处理互联网的包。你没有必要知道所有这些,但是让你知道为什么人们会选择其中一个。
下面是处理 HTTP 请求的不同包。
- 内置包:urllib 和 urllib2、urllib3
- 请求(基于 urllib3 包)
- grequests(扩展请求以处理异步 HTTP 请求)
- aiohttp(另一个处理异步 http 的包)
你可能会问同步请求和异步请求有什么区别?为什么这很重要?
同步请求阻塞客户端(浏览器),直到操作完成。这意味着有时 CPU 什么也不做,会浪费计算时间。在我看来效率很高!
异步请求不会阻塞浏览器,这允许客户端同时执行其他任务。这允许轻松扩展 1000 个请求。
url-lib 和 url-lib2 包有许多样板文件,有时可能有点难以阅读。我使用 requests 包,因为它是可读的,并且能够管理您无论如何都需要发出的大多数 HTTP 请求。
当您有大量 HTTP 请求时,异步包非常有用。这是一个复杂的话题,但是可以提高 python 脚本的效率。我会在后面的文章中回到这一点!
请求包介绍
要使用请求包,我们必须导入请求模块。然后,我们可以使用一系列方法与互联网互动。使用请求包的最常见方式是使用 requests.get 方法。在幕后,它对选择的 URL 执行 HTTP GET 请求。
首先,我们创建一个发送到服务器的请求对象,然后服务器发回一个响应。这个对象携带关于请求的所有数据。
import requestsurl = 'PLEASE INSERT URL LINK'
html = requests.get(url)
要访问这个对象,我们可以调用 text 方法。这将允许我们看到字符串形式的响应。请求根据从服务器返回的数据进行编码。
我们收到的信息有两部分,头和主体。标题为我们提供了关于响应的信息。可以把邮件头想象成将邮件发送到计算机所需的所有信息。
请看下面一个来自媒体标题的例子!有很多信息告诉我们关于反应。
{'Date': 'Thu, 30 Jan 2020 17:06:12 GMT',
'Content-Type': 'text/html; charset=utf-8',
'Transfer-Encoding': 'chunked',
'Connection': 'keep-alive',
'Set-Cookie': 'uid=lo_NHI3i4bLD514; Expires=Fri, 29-Jan-21 17:06:12 GMT; Domain=.medium.com; Path=/; Secure; HttpOnly,
optimizelyEndUserId=lo_NHI3i4bLD514; path=/; expires=Fri, 29 Jan 2021 17:06:12 GMT; domain=.medium.com; samesite=none; secure,
sid=1:Hu5pQRgkgEyZr7Iq5hNn6Sns/FKPUZaBJBtDCMI+nmsU48zG2lXM+dtrtlefPkfv; path=/; expires=Fri, 29 Jan 2021 17:06:12 GMT; domain=.medium.com; samesite=none; secure; httponly',
'Sepia-Upstream': 'production',
'x-frame-options': 'allow-from medium.com',
'cache-control': 'no-cache,
no-store, max-age=0, must-revalidate',
'medium-fulfilled-by': 'lite/master-20200129-184608-2156addefa, rito/master-20200129-204844-eee64d76ba, tutu/medium-39848', 'etag': 'W/"179e9-KtF+IBtxWFdtJWnZeOZBkcF8rX8"',
'vary': 'Accept-Encoding',
'content-encoding': 'gzip',
'x-envoy-upstream-service-time': '162',
'Strict-Transport-Security': 'max-age=15552000; includeSubDomains; preload',
'CF-Cache-Status': 'DYNAMIC',
'Expect-CT': 'max-age=604800,
report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"', 'Alt-Svc': 'h3-24=":443"; ma=86400, h3-23=":443"; ma=86400', 'X-Content-Type-Options': 'nosniff',
'Server': 'cloudflare',
'CF-RAY': '55d508f64e9234c2-LHR'}
request package get 方法下载响应的正文,而不要求许可。这将与下一节相关!
为了下载文件,我们希望以字节而不是字符串的形式获取请求对象。为此,我们调用 response.content 方法,这样可以确保我们接收的数据是字节格式的。
现在要写一个文件,我们可以使用一个 open 函数,它是 python 内置函数的样板文件。我们指定文件名,而“wb”指的是写入字节。Python 3 需要明确地知道数据是否是二进制的,这就是我们定义它的原因!
然后,我们使用 write 方法写入 get 请求的已定义二进制内容。
with open('filename.txt', 'wb') as r:
r.write(html.content)
with 语句打开了所谓的上下文管理器。这很有用,因为它将关闭 open 函数,而不需要额外的代码。否则,我们将不得不请求关闭 open 函数。我们不必使用 with 语句。
根据请求下载大文件
我们已经讨论了使用请求包下载的基本方法。get 方法参数帮助定义我们如何从服务器请求信息。我们可以用许多方法改变请求。请参阅请求文档以了解更多详细信息。
我们说过请求下载二进制文件的主体,除非另有说明。这可以通过定义流参数来覆盖。这在请求文档中的标题“正文内容工作流”下。见此处了解详情。这是一种控制何时下载二进制文件主体的方法。
request.get(url, stream=True)
在脚本的这一点上,只有二进制文件的头被下载。现在,我们可以通过一个名为 request.iter_content 的方法来控制如何下载文件。这个方法将整个文件停止在内存(缓存)中。
在后台,iter_content 方法迭代响应对象。然后,您可以指定 chunk_size,这是我们定义要放入内存的大小。这意味着在所有数据传输完成之前,连接不会关闭。
详情见此处。
r = requests.get(url, Stream=True)
with open("filename.pdf",'wb') as Pypdf:
for chunk in r.iter_content(chunk_size=1024)
if chunk:
pypdf.write(ch)
因此,这里我们使用一个请求 get 方法来获取内容。我们使用 with 语句作为上下文管理器,并调用 r.iter_content。我们使用 for 循环并定义变量 chunk,这个 chunk 变量将包含由 chunk_size 定义的每 1024 个字节。
我们将 chunk_size 设置为 1024 字节,如果需要,可以是任何值。
我们在将数据块放入内存的同时写入数据块。我们使用 if 语句查找是否有块要写,如果有,我们使用 write 方法来完成。这使得我们不会用尽所有的缓存,并以零碎的方式下载较大的文件。
下载重定向的文件
有时候你想下载一个文件,但网站重定向到检索该文件。请求包可以轻松处理这个问题。
import requests
url = 'insert url'
response = requests.get(url, allow_redirects=True)
with open('filename.pdf') as Pypdf:
pypdf.write(response.content)
这里我们在 get 方法中使用 allow_redirects=True 参数。我们像前面一样使用 with 语句来编写文件。
本文到此为止!敬请期待下一部分。我们将看看验证下载,恢复下载和编码进度条!
在后面的文章中,我们将讨论异步技术。这些可以扩大下载更大的文件集!
关于作者
我是一名医学博士,对教学、python、技术和医疗保健有浓厚的兴趣。我在英国,我教在线临床教育以及运行 www.coding-medics.com网站。
您可以通过 asmith53@ed.ac.uk 或 twitter 这里联系我,欢迎所有意见和建议!如果你想谈论任何项目或合作,这将是伟大的。
更多技术/编码相关内容,请点击这里注册我的简讯。
使用 python 的枚举函数永远改变你的循环方式
medium.com](https://medium.com/analytics-vidhya/everything-you-need-to-know-about-enumerate-a49a7fd0d756)
超越 python 中请求包的基础
émile PerronUnsplash 图像
了解如何在 python 中使用进度条、恢复部分下载的文件和验证文件
当您习惯了 requests python 包后,在命令行应用程序中考虑验证文件、恢复未完成的 get 请求和使用进度条的方法会很有用。这些超出了请求包的基本用途。我们将通过简单的方法使用请求包来实现这一点。
在本文中,您将了解到
- 如何恢复下载不完整的二进制文件
- 如何创建一个简单的下载验证程序来传输文件/备份数据。
- 如何显示简单的命令行进度条?
恢复下载
下载大文件时,可能会因为各种原因而中断。我们有时需要一种能够在最后一个字节恢复的方法来重新建立连接。
作为来自服务器的 HTTP get 请求的一部分,我们将获得数据头和数据体。二进制文件的 HTTP 头返回了我们请求的文件的大量信息!根据请求被发送到的服务器,我们有时会得到的部分之一是accept-ranges
头。这允许客户端下载部分下载的数据。
下面是一个接受下载部分文件的二进制文件头的例子。
{'Server': 'VK',
'Date': 'Wed, 29 Jan 2020 11:47:20 GMT',
'Content-Type': 'application/pdf',
'**Content-Length**': '9713036',
'Connection': 'keep-alive',
'Last-Modified': 'Mon, 20 Jan 2020 13:01:17 GMT',
'ETag': '"5e25a49d-94358c"',
**'Accept-Ranges': 'bytes',**
'Expires': 'Wed, 05 Feb 2020 11:47:20 GMT',
'Cache-Control': 'max-age=604800',
'X-Frontend': 'front632904',
'Access-Control-Expose-Headers': 'X-Frontend',
'Access-Control-Allow-Methods': 'GET, HEAD, OPTIONS',
'Access-Control-Allow-Origin': '*',
'Strict-Transport-Security': 'max-age=15768000'}
有了这种能力,我们还可以向服务器指定我们请求下载的文件的位置。然后,我们可以在该特定位置开始请求二进制数据,并从那里继续下载。
现在,要下载二进制文件的一小部分,我们必须能够用 request get HTTP 方法发送文件头。请求包使我们能够轻松地做到这一点。我们只想获得一定量的字节,我们通过发送一个range
头来指定要接收多少字节。然后,我们可以将它放入一个变量,并通过 get 请求传递它。
resume_headers = {'Range':'bytes=0-2000000'}
r = request.get(url, stream=True, headers=resume_header)
with open('filename.zip','wb') as f:
for chunk in r.iter_content(chunk-size=1024)
f.write(chunk)
笔记
1.我们在请求获取方法中指定了stream = True
。这允许我们控制何时下载二进制响应的主体。
2.我们在requests.get()
方法中使用 headers 参数来定义从 0 到 2000000 的字节位置。范围标题的边界是包含的。这意味着将下载字节位置 0 到 2000000。
4.我们使用一个 with 语句来写文件 filename . zip。r.iter_content
方法允许我们通过以字节为单位定义chunk-size
来指定要下载的数据的大小。在这种情况下,它被设置为 1024 字节。
我们下载了部分文件。这对我们恢复部分下载文件的实际目标有什么帮助?
当我们想要恢复部分下载的文件时,我们在文件头中指定文件大小。这是需要下载的下一个字节。这就是 python 中能够恢复下载的症结所在。
我们需要知道部分下载的文件大小。python 中有一系列的包可以做到这一点,pathlib 是这个用例的一个很好的包。请参见这里的获取使用 pathlib 的指导。
我们首先要导入 pathlib 包
import pathlib
方法path.stat()
返回关于路径的信息(类似于 os.stat,如果你熟悉 os 包的话)。现在我们调用path.stat()
方法的st_size
属性来获取文件的大小(也类似于 OS 包)。
现在我们准备将它投入使用
resume_header = {'Range':f'bytes= {path('filename.zip').stat().st_size}**-**'}
现在,这个需要打开包装。字符串前的 f 是一个 f 字符串,这是一个格式化字符串的好方法。作为一个用例,这里花括号中的{path.stat().st_size}
是一个表达式。我们正在创建的字符串被花括号中表达式的含义所修改。这可能是一个变量,但在这种情况下,我们得到的是我们下载的部分文件的大小。f 字符串解释{}中的任何内容,然后将结果显示为字符串。在这种情况下,它为我们打印文件大小。
字符串中{path.stat().st_size}
后面的粗体连字符表示我们从部分文件大小的字节开始抓取数据,直到文件的末尾。
既然我们理解了这一点,我们就可以将所有这些放在下面的代码中
resume_header = {'Range':f'bytes={path('filename.zip').stat().st_size}-'}
r = requests.get(url,stream=True, headers=resume_header)with open ('filename.zip','ab') as f:
for chunk in r.iter_content(chunk-size=1024):
f.write(chunk)
笔记
- “打开”功能中的“ab”模式将新内容添加到文件中。我们不想覆盖现有的内容,这是代替’ wb ’
验证文件
我们有时需要能够验证下载的文件。如果您恢复了文件下载,或者如果这是您想要与其他人共享的重要研究数据。有一个 python 模块叫做 hashlib 模块,它创建一个散列函数。哈希函数获取数据,并将其转换为唯一的数字和字母字符串。我们称之为哈希对象。这个字符串的计算是通过我们可以指定为模块的一部分的算法来完成的。
让我们开始讨论如何验证下载的文件。我们需要知道哈希值应该是什么才能验证它。我们将读取二进制文件并生成散列,然后可以将它与文件的已知散列值进行比较。由于散列文件是唯一的,我们将能够确认它们是相同的文件。
要创建哈希值,我们需要指定创建它的算法。有很多选择,但在这个例子中,我们使用sha256()
。现在,为了创建一个哈希值,我们使用 hashlib update()
方法,该方法只接受“类似字节”的数据,比如字节。为了访问哈希值,我们调用了hexdigest()
方法。hexdigest()
接受 hash 对象,并为我们提供一串仅十六进制的数字。这个字符串由我们之前指定的算法定义。
一旦创建了哈希值,就不能反向获得原始的二进制数据。它只有一种方式。我们可以通过唯一的哈希值来比较两个文件,并使其在传输给其他人时更加安全。
import hashlibwith open('research.zip', 'rb') **as** f:
content = f.read()
sha = hashlib.sha256()
sha.update(content)
print(sha.hexdigest())
输出:
42e53ea0f2fdc03e035eb2e967998da5cb8e2b1235dd2630ffc59e31af866372
笔记
- hashlib 模块被导入
- 我们使用 with 语句读取文件:这确保了我们不必使用 close 语句。
- 我们调用
read()
方法来读取二进制数据的所有内容 - 创建变量 sha,并使用 SHA 256 算法创建散列对象来创建散列值。
- 使用
update()
方法,我们将二进制数据传递给散列对象。通过这样做,我们得到一个哈希值。 - 使用
hexdigest()
方法,我们可以打印出哈希值,即二进制文件特有的固定字符串。
所以现在无论何时你想验证一个文件,我们都有一个哈希值。如果你不得不再次下载或者把数据传输给同事。你只需要比较你创建的哈希值。如果恢复的下载完成并且具有正确的哈希值,那么我们知道它是相同的数据。
让我们创建一个小脚本来确认您的朋友传输给您的一个文件。例如,您需要输入哈希值。
user_hash = input('Please input hash please: ')sha = hashlib.sha256()with open('file.zip' as 'rb') as f:
chunk = f.read()
if not chunk:
break
sha.update(chunk)
try:
assert sha.hexdigest() == user_hashexcept AssertionError:
print('File is corrupt, delete it and restart program'else:
print('File is validated')
笔记
- 我们要求用户输入一个散列值,该值被赋予变量 user-hash。
- 当我们指定算法时,会创建变量 sha 和散列对象
- 我们使用 with 语句打开想要验证的文件。我们定义变量 chunk,并使用 read 方法为它分配二进制数据。
4.我们使用 hashlib update()
方法为这个块创建一个散列对象。
5.我们使用sha.hexdigest()
为这个块创建一个哈希值。
6.我们使用 assert 关键字,它计算表达式的真值。在这种情况下,根据输入的哈希值评估下载数据的哈希值。
7.我们指定一个异常AssertionError
。当 assert 语句为 false 并指定错误消息时,将调用此函数。
8.在 else 语句中,如果user_hash
变量与文件的哈希值相同,我们打印出该文件已经过验证。
所以这里我们为下载的文件创建了一个非常简单的验证工具。
进度条
有许多软件包可以显示您的编程代码的进度。这里我们就来说一个下载文件时添加进度条的简单方法!如果您正在批量下载,并希望在下载过程中看到进度,这可能会很有用。进度条在很多方面都很有用,不仅仅是下载文件。
Tqdm 是一个第三方 python 包,可以处理进度条。对我来说,这是思考 python 的最好方式,从尽可能少的代码开始,得到你想要的。
首先,您需要使用 pip 安装 tqdm。
pip install tqdm
然后我们会想要导入 tqdm。现在是我们要用 tqdm 方法来显示数据的进度。tqdm 模块可以解释每个块并显示文件的进度。
将进度条合并到下载文件中。首先,我们必须创建一些变量,最重要的是文件的大小。我们可以使用请求包来做到这一点。我们获取二进制头和“内容长度”。向上滚动到另一部分的二进制文件头。它的相关值是我们从服务器请求了多少字节的数据。响应是一个字符串,当在进度条中使用它时,我们必须将它转换成数字格式
另一个重要的部分是文件名。我们可以将 URL 拆分成一个列表,然后非常简单地选择最后一项。
一旦设置好所有变量,我们就可以指定 tqdm 模块。
with 语句意味着一旦操作完成并且 open 函数写入数据,它就关闭。然后,我们使用 tqdm 方法并指定参数来显示正在下载的数据。请注意,论点是非常详细的!让我们一个一个地看。
total
参数是我们定义的文件大小。unit
参数是我们指定的字符串,用于定义数据块的每次迭代的单元。在这种情况下,我们指定 B 为字节。desc
参数显示文件名initial
参数指定了进度条从哪里开始,在本例中为 0。ascii
参数是指定我们用什么来填充进度条。如果设置为 false,它将采用 unicode 来填充进度条。
既然我们已经解释了我们在做什么,现在让我们来看看代码:
from tqdm import tqdmurl = "insert here"
file = url.split('/')[-1]r = requests.get(url, stream=True, allow_redirects=True)
total_size = int(r.headers.get('content-length'))
initial_pos = 0with open(file,'wb') as f:
with tqdm(total=total_size, unit=B,
unit_scale=True, desc=file,initial=initial_pos, ascii=True) as pbar: for ch in r.iter_content(chunk_size=1024),
if ch:
f.write(ch)
pbar.update(len(ch))
输出:
filename.zip 100%|#################################################| 3.71M/3.71M [00:26<00:00, 254kB/s]
笔记
- 我们从 tqdm 模块中导入 tqdm 方法。
- 定义了变量 url。
- 定义了文件变量,我们使用拆分字符串的方法将 url 拆分成一个列表。(‘/’)参数告诉 split 方法在 url 的/'之间拆分字符串。这里,我们想要得到列表的最后一个索引,因为这将是我们想要的文件名。
- 变量 r 用于指定一个 HTTP get 请求,我们允许它有一个开放的数据流并允许重定向。
- 定义了
total_size
变量,并使用请求包获取二进制头。使用 get 方法,我们得到了二进制文件大小的‘content-length’
值。现在,它返回一个字符串,我们用 int()把它变成一个数字。 - 变量
initial_pos
被赋值为 0,这对于 tqdm 方法的指定很重要。 - 我们使用 with 语句访问 tqdm 方法。我们在参数中指定了几项。
r.iter_content
将数据分割成块。我们将 ch 定义为一个 1024 字节的块,如果该块可用,我们将该块写入文件。- 我们调用 tqdm 方法的 update 属性将该块更新到进度条并显示出来。
所以在那之后,你应该对如何处理进度条、验证文件和超越请求包的基础有了更好的了解。
感谢阅读!
关于作者
我是一名医学博士,对教学、python、技术和医疗保健有浓厚的兴趣。我在英国,我教在线临床教育以及运行网站www.coding-medics.com。
您可以通过 asmith53@ed.ac.uk 或 twitter here 联系我,欢迎所有意见和建议!如果你想谈论任何项目或合作,这将是伟大的。
如需更多技术/编码相关内容,请在此注册我的简讯。
如何用 Python 下载上市公司的收益日历
威廉·艾文在 Unsplash 上的照片
用几行代码了解公司的最新收益
在撰写本文时,我们目前正接近 Q1 2020 财报季的尾声。对于许多投资者和量化金融爱好者来说,这是一个特别有趣的时期,有许多短期投资机会。这就是为什么在本文中,我想简要介绍收益季节的概念,并展示如何使用 Python 轻松提取所有重要信息。
什么是收益季节?
术语财报季指的是一年中大多数上市公司向公众发布季度公司财报的时间段。收益季节发生在每个财政季度结束后的几个月,因此这将对应于 1 月、4 月、7 月和 10 月。通常,收益季节持续约 6 周,之后报告的收益补贴数量为淡季频率(仍有一些公司报告淡季,因为它们的财务日历可能与大多数略有不同)。
为什么财报季对潜在投资者来说是一个重要时刻?仅仅是因为在给定公司发布收益的日期前后(主要是在当天),人们可以预期股票会有一些重大的价格变动。这是因为上市公司报告其财务和一般情况:上一季度的利润/亏损、组织的任何重大变化等。金融分析师利用这些信息评估股票的内在价值——以确定其当前市场价格是高估还是低估。这反过来又是投资者买入/卖出/持有股票的潜在信号。
大多数公司都在网站上为潜在/当前投资者开辟了一个专用部分,让他们可以访问收益报告以及即将发布的收益报告的日期。自然,从单个网站获取信息是不可行的(或者至少这不是一次愉快的经历)。这就是为什么我们将参考流行的金融数据来源——雅虎!金融。下面你可以看到一张来自当前收益日历的图片。
在我之前的一篇文章中,我展示了如何利用一些流行的 Python 库来轻松下载与股票价格相关的信息(以及一些关于公司本身的附加信息)。在本文中,我用一个名为yahoo-earnings-calendar
的新库来扩展这个工具包(是的,这个名字是不言自明的)。与前面描述的解决方案相比,它确实有一些优势,您将在下面看到。
使用 Python 下载收入日历
除了标准库,我们需要通过在终端中运行下面一行代码来安装yahoo_earnings_calendar
:
pip install yahoo_earnings_calendar
完成后,我们导入本文中使用的所有库:
下面,我们将介绍下载收入日历的三种可用方法。
下载特定日期的收入
我们探索的第一种方法用于下载特定日期的收入。为了下载数据,我们首先使用datetime
库定义日期。在本例中,我们使用当天(2020 年 5 月 15 日)。然后,我们实例化一个YahooEarningsCalendar
类的对象。使用earnings_on
方法,我们以字典列表的形式下载数据。最后,我们将下载的数据存储在一个pandas.DataFrame
中。
运行代码会生成DataFrame
的预览。
startdatetimetype
列包含有关收益电话会议时间的信息。传统上,收益(以及关于公司状况的任何其他重要信息)是在与感兴趣的投资者召开的收益电话会议上宣布的。综上所述,这是向公众公布收益的时候。
startdatetimetype
栏的图例:
- 蒙特利尔银行——开市前
- AMC——收市后
- TAS/TNS —时间未指定
通过运行df_earnings.shape
,我们看到DataFrame
有 119 行,这与上面的截图一致。以这种方式下载日历的一个潜在缺点是,我们只能获得美国公司的收益数据。
这是雅虎上使用的过滤器的默认设置。财经网站。下载非美国公司信息最简单、最可靠的方法是使用股票代码。我们将在下面讨论这种方法。
下载一系列日期的收入
下载一系列日期的日历与我们已经描述过的非常相似。这一次,我们使用earnings_between
方法并提供感兴趣的时间段的开始和结束日期。对于下面的例子,我们下载未来 7 天的收益日期。
这次earnings_df
包含 312 个位置。
处理收入数据时要考虑的一个重要因素是日历会随着时间的推移而变化。因此,在提前几周/几个月下载收益的情况下,您可能希望不时刷新下载,以确保数据仍然有效。
下载特定产品的收益
最后,我们下载特定产品的收益日期,在本例中是 Twitter。我们通过使用get_earnings_of
方法并提供股票代码来做到这一点。这次不同的是,请求将返回过去和未来收入的列表。这就是为什么我们从时间戳字符串中提取日期(它以 ISO-8601 格式存储)并使用between
方法只过滤掉未来 180 天的收益。
代码返回下表,其中包含 Twitter 在未来 180 天内的两个收益发布日期。
结论
在这篇文章中,我解释了什么是收益季节,以及如何从 Yahoo!金融。
有了可以在 Python 中使用的数据,我可以想到一些潜在的用例:
- 建立一个自动的电子邮件/Slack 机器人通知你相关的收益发布。
- 在用于预测股票价格的 ML 模型中包含收益发布日期。例如,你可以在脸书的预言中指出收益日期作为转折点。
就代码行而言,yahoo-earnings-calendar
库相当紧凑,所以我强烈建议检查代码,以了解数据实际上是如何从 Yahoo!金融。这可能是特别重要的,因为雅虎!倾向于频繁更改网站,这可能导致库变得不可用,至少在修复之前是如此。这就是为什么在将基于它的任何代码投入生产时都应该小心谨慎。此外,熟悉用于抓取数据的方法无疑是有意义的,因此您可以在作者修复任何问题之前修复它们。并且您可以随时使用该更新进行拉取请求:)
你可以在我的 GitHub 上找到本文使用的代码。一如既往,我们欢迎任何建设性的反馈。你可以在推特或评论中联系我。
不久前,我出版了一本关于使用 Python 解决金融领域实际任务的书。如果你感兴趣,我在贴了一篇文章介绍这本书的内容。你可以在亚马逊或者 Packt 的网站上买到这本书。
参考
[1]雅虎!收益日历刮刀— GitHub
如何用 python 为你的科学论文绘制条形图
照片由特雷·赫尔利拍摄
条形图📊(也称为条形图或条形图)是一种可视化工具,读者可以使用它来比较不同类别的条形图所显示的数据。在这个故事中,我试图介绍如何用 python 绘制清晰的条形图。
作为一名学生或研究人员,你必须在科学论文中发表你的努力和成果,研究数据应该易于阅读和获取。共享研究数据是我们越来越鼓励,甚至强制要求的事情。同时,这也是我热衷的事情😘。
首先让我们重新认识一下这位朋友,条形图是谁(什么)?
条形图或条形图是一种图表或图形,用矩形条表示分类数据,矩形条的高度或长度与它们所代表的值成比例。条形图可以垂直或水平绘制。垂直条形图有时被称为柱形图。由维基百科提供。
第一个例子
我做了一个简单的例子,用竖条图直观的展示了一个学生 X 的各科成绩。
所有分数的条形图
这是由一个非常简单的 Matplotlib 代码实现的:
import matplotlib.pyplot as pltfig = plt.figure(figsize=(7,5))ax = fig.add_axes([0,0,1,1])subjects = ['Math', 'Physik', 'English', 'Chemistry', 'History']scores = [90,80,85,72,66]ax.bar(subjects,scores)ax.set_ylabel('scores',fontsize= 12)ax.set_xlabel('subjects',fontsize= 12)ax.set_title('all scores of student X')for i, v in enumerate(scores):ax.text( i ,v + 1, str(v), color='black', fontweight='bold')plt.savefig('barplot_1.png',dpi=200, format='png', bbox_inches='tight')plt.show()
数据分析中的真实案例
对于少量的结果数据,我们可以定义一个列表来保存整个数据,就像前面的例子一样。但有时数据太多,如果我们已经将相同的数据保存在 excel 文件中,那么再次将每个数据输入到一个列表中是低效的。
如果我们通过导入一个 excel 文件或其他文件来开始绘制条形图的过程,这将非常方便。因此,我们需要一个数据框架,它是二维的、大小可变的、潜在异构的表格数据,包括带标签的轴(行和列)。
在我在论文中写的这个真实案例中,我需要准确地比较不同模型的性能。准确度(ACC)是测量值与特定值的接近程度,这是评估分类模型的一个度量标准。从形式上看,准确性有以下定义:
准确度=正确预测的数量/方向总数
此外,通常在多分类模型中使用的前 N 名准确性意味着正确的类出现在前 N 名概率中,从而被认为是“正确的”。在论文中,我采用了前 1 名、前 3 名和前 5 名的准确度来评估预测。我已经在一个名为“model_accs.xlsx”的 excel 文件中输入了所有前 N 名 ACC。
数据,保存在 excel 表格(b)和熊猫数据框©中
有了 pandas,我们可以用 python 从 excel 文件中读取数据。Pandas 是一个开源的、BSD 许可的库,为 Python 编程语言提供了高性能、易于使用的数据结构和数据分析工具。
import pandas as pd
df= pd.read_excel("model_accs.xlsx",header=0) # read excel file
通过函数 pd.read_excel(),我们可以读取我们的结果 excel 文件。如果数据保存在。csv 文件,那么我们可以使用 pd.read_csv(),类似于 pd.read_excel()。
import numpy as nptop_1 = df.iloc[:,3]top_3 = df.iloc[:,2]top_5 = df.iloc[:,1]xlabels = df.iloc[:,0]N =5ind = np.arange(N) # the x locations for the groupswidth = 0.2 # the width of the barsfig, ax = plt.subplots(figsize=(12,8))rects1 = ax.bar(ind, top_1, width, color='b')rects2 = ax.bar(ind + width, top_3, width, color='orange')rects3 = ax.bar(ind + 2*width, top_5, width, color='g')ax.set_xticks(ind + width)ax.set_xticklabels(xlabels,fontsize=10)ax.set_xlabel("models", fontsize=12)ax.set_ylabel("Top-N ACC/%", fontsize=12)ax.set_title('Top-N ACC for 5 different models')ax.legend((rects1[0], rects2[0],rects3[0]),('top-1 acc', 'top-3 acc','top-5 acc'),bbox_to_anchor=(1.13, 1.01))def labelvalue(rects):for rect in rects:height = rect.get_height()ax.text(rect.get_x() + rect.get_width()/2., 1.01*height,'%d' % int(height),ha='center', va='bottom')labelvalue(rects1)labelvalue(rects2)labelvalue(rects3)plt.savefig('barplot_2.png',dpi=200, format='png', bbox_inches='tight')plt.show()
使用上述代码,我们为 5 款车型的 top-N ACC 保存了一个漂亮的条形图,如下所示:
5 款车型的前 N 名 ACC 条形图
进步
但是,我们对这个条形图不太满意,因为条形图太多了。我们能简化显示数据吗🤔?例如,我们将前 1 名、前 3 名和前 5 名 acc 合并到一个条形图中,这意味着我们只需要 5 个条形图来显示 5 个型号的前 N 名 acc。情节中的信息要压缩。在这里,我们可以通过以下预处理输入数据来实现,其中我们减去前 5 名 acc 和前 3 名 acc 以获得差异,对前 3 名 acc 和前 1 名 acc 重复相同的操作。
我们用下面的代码绘制了一个新的条形图:
ax = df[['top-1 acc','top-3 acc','top-5 acc']].plot(kind='bar', title ="Top-N ACC for 5 different models", figsize=(12, 8), legend=True, fontsize=12,stacked=True)top_1 = df.iloc[:,3]top_3 = df.iloc[:,2]top_5 = df.iloc[:,1]xlabels = df.iloc[:,0]ax.set_xticklabels(xlabels,fontsize=10)ax.set_xlabel("models", fontsize=12)ax.set_ylabel("Top-N ACC/%", fontsize=12)for i, v in enumerate(top_1):ax.text( i ,v - 2, str(v), color='black')for i, v in enumerate(top_3):ax.text( i ,v - 3, str(v), color='black')for i, v in enumerate(top_5):ax.text( i ,v + 1, str(v), color='black')plt.savefig('barplot_2.png',dpi=200, format='png', bbox_inches='tight')plt.show()
运行代码后,我们得到一个简单的条形图,它将前 1 名 acc、前 3 名 acc 和前 5 名 acc 集成到一个条形图中。
更直观的 5 款车型前 N 名 ACC 条形图
最后一个条形图看起来非常直观和明显,尽管它包含的信息与倒数第二个有 15 个条形的条形图相同。此外,最后一个条形图的代码比倒数第二个条形图的代码短。因此,我选择在我的论文中使用新的条形图📜。
结论
在这个故事中,我根据自己的经验介绍了用 Python 绘制条形图的方法。对于学生和研究人员来说,掌握如何直观地展示他们的研究数据的技能是很重要的。条形图是科学论文中最好和最常用的插图之一。我希望我的故事对你了解 it⛳️.有所帮助
链接到 GitHub 库:【https://github.com/Kopfgeldjaeger/Bar_graph_with_Matplotlib
参考
这里有两个对 pandas 和 Matplotlib 有用的文档。
[## pandas 文档- pandas 1.1.2 文档
在文档中看到了一个错别字?想要改进现有功能?投稿指南将指导您…
pandas.pydata.org](https://pandas.pydata.org/pandas-docs/stable/index.html) [## Matplotlib . py plot . bar-Matplotlib 3 . 3 . 2 文档
制作条形图。这些条按照给定的对齐方式定位在 x 处。它们的尺寸由高度和宽度给出…
matplotlib.org](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.bar.html)
如何用 Wolfram 语言画一只猫和其他愚蠢的东西
用草图-RNN 神经网络生成手绘草图
你不能教一只老狗新把戏,但也许你可以教一个神经网络画一只猫的画?前几天,当我在仔细阅读总是很有趣的 Wolfram 神经网络库时,我发现了一个小珍品。一个名为 Sketch-RNN 的神经网络自称能够画出猫、狗、长号、风车和许多其他动物和物体。这个,我不得不试试!
为了画一个草图,这个草图-RNN 页面提示我复制并粘贴一大块 Wolfram 语言代码。这工作得非常好,但我想有一个单一的函数来隐藏所有的复杂性。所以我写了一个简单的 ResourceFunction 来做这件事。
这些资源函数非常棒,因为它们基本上是从 web 上自动下载的代码块:
DrawSketch = ResourceFunction[
"user:arnoudb/DeployedResources/Function/DrawSketch"
]
有了这个资源函数,我就可以试着画出我的第一只动物:
(图片由作者和人工“智能”提供)
好吧,所以结果更像是毕加索的作品,而不是伦勃朗的,但很明显,它得到了猫的本质。据推测,随着神经网络的改进和更先进的训练数据,这有可能走得更远。
所有的草图都有随机生成元素,所以你可以画 25 只猫,它们看起来都是独一无二的!
(图片由作者和人工“创造”)
使用这个漂亮的函数,你可以画出总共 114 种动物和物体。我决定尝试一下。许多物品一眼就能认出来,而其他一些则有点神秘:
(图片由作者和我们的人工“助手”提供)
您可以通过修改原始的 DrawSketch 函数并添加随机颜色和线条粗细来获得更多乐趣。这是我用菠萝做的一个例子:
(图片由作者在菠萝的帮助下提供)
这里的可能性是无限的,尝试所有的可能性是非常有趣的。我看不出这有什么实际的应用,除了通过提供给他们很多很多的例子让他们临摹来启发学龄前儿童画某些物体。我希望你喜欢这个愚蠢的小故事,如果你有兴趣了解更多关于 Wolfram 语言的知识,可以看看我最近发表的题为“学习 Wolfram,从零到英雄”的文章。它有一套很棒的指向这种编程语言学习资源的指针!😻🍍
- 基于草图——RNN 根据来自 Wolfram 神经网络库的 QuickDraw 数据进行训练
- 参考:D. Ha,D. Eck,“草图的神经表示”,arXiv:1704.03477 (2017)可从https://github . com/tensor flow/magenta-demos/tree/master/Sketch-rnn-js获得
如何使用 Python 和 Word2vec 绘制地图
从欧洲首都的 Word2vec 向量创建的主要组件的二维可视化表示,也称为地图。
雅各布·布朗在 Unsplash上的照片
到目前为止,Word2vec 绝对是我在自然语言处理研究中遇到的最有趣的概念。想象一下,一种算法可以真正成功地模仿理解单词的含义及其在语言中的功能,可以沿着数百个不同的主题测量单词的接近程度,可以回答更复杂的问题,如“谁对文学来说就像贝多芬对音乐来说”。
我认为直观地表示 word2vec 向量会很有趣:本质上,我们可以获取国家或城市的向量,应用主成分分析来降低维度,并将其放在二维图表上。然后,我们可以观察我们离实际的地理地图有多近。
在这篇文章中,我们将:
- 广义地讨论 word2vec 理论;
- 下载原始预训练向量;
- 看看一些有趣的应用:从列表中找出奇怪的一个,或者对单词进行算术运算,比如著名的
king — man + woman = queen
例子; - 看看我们仅仅基于 word2vec 向量就能多精确地画出欧洲的首都。
最初的 word2vec 研究论文和预训练模型来自 2013 年,考虑到 NLP 文献的扩展速度,它在这一点上是旧技术。更新的方法包括 GloVe (更快的训练,不同的算法,可以在更小的语料库上训练)和 fastText (能够处理字符 n-grams)。我现在坚持原始算法的结果。
快速 Word2Vec 简介
自然语言处理的核心概念之一是我们如何量化单词和表达式,以便能够在模型设置中使用它们。这种语言元素到数字表示的映射被称为单词嵌入。
Word2vec 是一个单词嵌入过程。这个概念相对简单:它一句接一句地在语料库中循环,并符合一个模型,该模型根据来自预定义大小窗口的相邻单词来预测单词。为此,它使用神经网络,但实际上并不使用预测,一旦模型被保存,它只保存第一层的权重。在最初的模型中,我们将要使用的模型,有 300 个权重,所以每个单词都由一个 300 维的向量表示。
请注意,两个单词不一定要彼此接近才能被视为相似。如果两个单词从未出现在同一个句子中,但它们通常被相同的单词所包围,则可以有把握地假设它们具有相似的意思。
word2vec 中有两种建模方法:跳跃式语法和连续式词汇袋,这两种方法都有各自的优点,并且对某些超参数很敏感……但是你知道吗?我们不会去适应我们自己的模型,所以我不打算在这上面花更多的时间,你可以在这篇文章或维基站点中阅读更多关于不同方法和参数的内容。
自然,你得到的单词向量依赖于你训练你的模型的语料库。一般来说,你确实需要一个巨大的语料库,有在维基百科上训练过的版本,或者各种来源的新闻文章。我们将要使用的结果是在谷歌新闻上训练出来的。
如何下载和安装
首先,您需要下载预先训练好的 word2vec 矢量。您可以从针对不同类型文档的各种模型中进行选择。我用的是最初的模型,在谷歌新闻上受过训练,你可以从很多来源下载,只需搜索“谷歌新闻向量负 300 ”。比如这个 GitHub 链接就是一个方便的方法:https://github.com/mmihaltz/word2vec-GoogleNews-vectors。
请注意,该文件有 1.66 GB,但在其辩护中,它包含了 30 亿个单词的 300 维表示。
当谈到在 Python 中使用 word2vec 时,同样,您有许多包可供选择,我们将使用gensim
库。假设您已经将文件保存在word2vec_pretrained
文件夹中,您可以像这样用 Python 加载它:
from gensim.models.keyedvectors import KeyedVectorsword_vectors = KeyedVectors.load_word2vec_format(\
'./word2vec_pretrained/GoogleNews-vectors-negative300.bin.gz', \
binary = True, limit = 1000000)
limit 参数定义了你要输入多少单词,一百万对我来说已经足够了。
玩文字游戏
现在我们已经有了 word2vec 向量,我们可以检查它的一些应用程序。
首先,你实际上可以检查任何单词的矢量表示:
word_vectors['dog']
正如我们所料,结果是一个 300 维的向量,很难解释。但这是整个概念的基础,我们通过将这些向量相加和相减来对它们进行计算,然后我们计算余弦相似度来找到最匹配的单词。
您可以使用most_similar
函数查找同义词,topn
参数定义了您希望列出多少个单词:
word_vectors.most_similar(positive = ['nice'], topn = 5)
结果是
[('good', 0.6836092472076416),
('lovely', 0.6676311492919922),
('neat', 0.6616737246513367),
('fantastic', 0.6569241285324097),
('wonderful', 0.6561347246170044)]
现在,你可能认为用类似的方法,你也可以找到反义词,你只需要输入单词’ nice '作为一个negative
,对吗?不完全是,结果是这样的:
[('J.Gordon_###-###', 0.38660115003585815),
('M.Kenseth_###-###', 0.35581791400909424),
('D.Earnhardt_Jr._###-###', 0.34227001667022705),
('G.Biffle_###-###', 0.3420777916908264),
('HuMax_TAC_TM', 0.3141660690307617)]
这些单词与单词“ nice ”相距甚远,表明它并不总是如你所愿。
您可以使用doesnt_match
功能找出奇数:
word_vectors.doesnt_match(
['Hitler', 'Churchill', 'Stalin', 'Beethoven'])
返回Beethoven
。我想这很方便。
最后,让我们来看几个例子,这些例子通过给算法一种错误的智能感而使它出名。如果我们想要组合字向量father
和woman
的值,但是减去分配给字向量man
的值:
word_vectors.most_similar(
positive = ['father', 'woman'], negative = ['man'], topn = 1)
我们得到:
[('mother', 0.8462507128715515)]
首先,要理解这个手术有点困难,我认为把这个问题表述成“父亲对于男人来说,对于女人来说是什么?“其实没那么有用。想象我们只有两个维度:父母和性别。单词’女人’可以用这个向量来表示:[0, 1]
,'男人是[0, -1]
,'父亲是[1, -1]
,而’母亲是[1, 1]
。现在,如果我们用向量做同样的运算,我们会得到同样的结果。当然,不同之处在于我们有 300 个维度,而不是例子中的 2 个,维度的意义几乎无法解释。
当谈到 word2vec 操作时,有一个著名的性别偏见例子,单词’ doctor’ (我们知道,这是一个中性词)的女性版本曾经被计算为’ nurse’ 。我尝试复制它,但没有得到相同的结果:
word_vectors.most_similar(
positive = ['doctor', 'woman'], negative = ['man'], topn = 1) [('gynecologist', 0.7093892097473145)]
我猜是进步了吧?
好了,现在我们检查了一些基本的可能性,让我们在我们的地图上工作!
映射函数
首先,我们需要一个我们希望我们的映射函数做什么的计划。假设我们有一个想要可视化的字符串列表和一个单词向量对象,我们想要:
- 找到列表中每个单词的单词向量表示;
- 使用主成分分析将维度减少到 2;
- 创建散点图,将单词作为标签添加到每个数据点;
- 作为一个额外的奖励,可以通过任何维度“翻转”结果-主成分分析的向量具有任意方向,当我们绘制地理单词以更好地与现实世界的方向保持一致时,我们可能希望改变这一点。
我们将需要以下库:
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.decomposition import PCAimport adjustText
列表中一个不常用的库是 adjustText ,这是一个非常方便的包,它使得在散点图中编写图例变得简单,而且不会重叠。对我来说,找到这个解决方案出奇的困难,而且据我所知,在 matplotlib 或 seaborn 中没有办法做到这一点。
事不宜迟,这个函数正是我们所需要的:
def plot_2d_representation_of_words(
word_list,
word_vectors,
flip_x_axis = False,
flip_y_axis = False,
label_x_axis = "x",
label_y_axis = "y",
label_label = "city"):
pca = PCA(n_components = 2)
word_plus_coordinates=[]
for word in word_list:
current_row = []
current_row.append(word)
current_row.extend(word_vectors[word]) word_plus_coordinates.append(current_row)
word_plus_coordinates = pd.DataFrame(word_plus_coordinates)
coordinates_2d = pca.fit_transform(
word_plus_coordinates.iloc[:,1:300])
coordinates_2d = pd.DataFrame(
coordinates_2d, columns=[label_x_axis, label_y_axis])
coordinates_2d[label_label] = word_plus_coordinates.iloc[:,0] if flip_x_axis:
coordinates_2d[label_x_axis] = \
coordinates_2d[label_x_axis] * (-1) if flip_y_axis:
coordinates_2d[label_y_axis] = \
coordinates_2d[label_y_axis] * (-1)
plt.figure(figsize = (15,10)) p1=sns.scatterplot(
data=coordinates_2d, x=label_x_axis, y=label_y_axis)
x = coordinates_2d[label_x_axis]
y = coordinates_2d[label_y_axis]
label = coordinates_2d[label_label]
texts = [plt.text(x[i], y[i], label[i]) for i in range(len(x))] adjustText.adjust_text(texts)
现在该测试功能了。我绘制了欧洲国家的首都,但是你可以使用任何列表,总统或其他历史人物的名字,汽车品牌,烹饪原料,摇滚乐队,等等,只要在word_list
参数中传递它。我从中得到一些乐趣,有趣的是看到集群形成并试图在两个轴后面找到一个意义。
如果你想重现结果,这里有一些城市:
capitals = [
'Amsterdam', 'Athens', 'Belgrade', 'Berlin', 'Bern',
'Bratislava', 'Brussels', 'Bucharest', 'Budapest',
'Chisinau', 'Copenhagen','Dublin', 'Helsinki', 'Kiev',
'Lisbon', 'Ljubljana', 'London', 'Luxembourg','Madrid',
'Minsk', 'Monaco', 'Moscow', 'Nicosia', 'Nuuk', 'Oslo',
'Paris','Podgorica', 'Prague', 'Reykjavik', 'Riga',
'Rome', 'San_Marino', 'Sarajevo','Skopje', 'Sofia',
'Stockholm', 'Tallinn', 'Tirana', 'Vaduz', 'Valletta',
'Vatican', 'Vienna', 'Vilnius', 'Warsaw', 'Zagreb']
(安道尔的首都安道尔城不在列表中,无法找到 word2vec 识别的格式。我们会接受的。)
假设您仍然拥有我们在上一节中创建的word_vectors
对象,您可以像这样调用该函数:
plot_2d_representation_of_words(
word_list = capitals,
word_vectors = word_vectors,
flip_y_axis = True)
(y 轴被翻转,以便创建更类似于真实地图的表示。)
结果是:
Word2vec 欧洲地图
我不知道你的感受,当我第一次看到这张地图的时候,我简直不敢相信它的效果是如此之好!是的,当然,你观察的时间越长,你发现的“错误”就越多,一个不祥的结果是莫斯科并不像它应该的那样远离东方……然而,东方和西方几乎完全分开,斯堪的纳维亚和波罗的海国家很好地组合在一起,意大利周围的首都也是如此,这样的例子不胜枚举。
需要强调的是,这绝不意味着纯粹的地理位置,例如,雅典在西边很远,但这是有原因的。让我们回顾一下上面的地图是如何得出的,这样我们就可以充分欣赏它了:
- 谷歌的一组研究人员训练了一个巨大的神经网络,它可以根据上下文预测单词;
- 他们将每个单词的权重保存在一个 300 维的向量表示中;
- 我们取了欧洲各国首都的向量。
- 通过主成分分析将维数降低到 2;
- 将计算出的组件放在图表上。
我觉得这很棒!
参考
霍布森、科尔和汉尼斯(2019 年)。自然语言处理实践:理解、分析和用 Python 生成文本。曼宁出版,2019。
Word2vec 是一种自然语言处理技术。word2vec 算法使用神经网络模型来学习…
en.wikipedia.org](https://en.wikipedia.org/wiki/Word2vec) [## 欢迎阅读 adjustText 的文档!- adjustText 0.7 文档
adjustText 是一个小的库,帮助您调整 matplotlib 图上的文本位置,以删除或最小化与…的重叠
adjusttext.readthedocs.io](https://adjusttext.readthedocs.io/en/latest/)
如何在 Jupyter 上画维恩图
使用 Matplotlib-Venn 的所有基本逻辑文氏图
freepik 创建的业务向量—www.freepik.com
**Table of Contents**[**Introduction**](#8858)1\. [A, B](#53bd)
2\. [TRUE, FALSE](#3ba9)
3\. [A AND B, A NAND B](#3e55)
4\. [A OR B, A NOR B](#ea60)
5\. [A XOR B, A XNOR B](#7811)
6\. [NOT A, NOT B](#296f)
7\. [A NOT B, B NOT A](#f0f1)
8\. [Implication A → B, B → A](#b2c4)
9\. [Mutually exclusive](#76e9)
10\. [Complement](#6b3d)
11\. [Subset](#b30b)[**Conclusion**](#a953)
介绍
在这篇文章中,你会发现如何在 Jupyter 上绘制基本维恩图。为此,我们将使用matplotlib-Venn。matplotlib-venn 用于绘制面积加权的二圆和三圆 venn 图。对于大多数的文氏图,我们将使用双圆文氏图。
(更新:我根据这些代码创建了一个 Python 包。请阅读本。)
让我们开始吧。
** [## 如何在 Docker 上运行 Jupyter 笔记本
不再有 Python 环境和包更新
towardsdatascience.com](/how-to-run-jupyter-notebook-on-docker-7c9748ed209f) [## 介绍基本的维恩图 Python 包:Vennfig
在 Jupyter 或 Terminal 上用一行代码画一个维恩图
towardsdatascience.com](/introducing-basic-venn-diagram-python-package-vennfig-fa3f8e4dcb36)
甲,乙
文氏图
我们将导入venn2
和venn2-circles
并创建一行两列的支线剧情。本文中的大多数图都是我使用的这种设置。
如果你需要所有维恩图都没有支线剧情的代码,可以在 这个链接 找到。
与使用set-edgecolor
相比,venn2-circles
能让你更好地控制边缘线,所以我们同时使用venn2
和venn2-circles
。
我们用相同的子集值为v1
和c1
设置ax=ax1
,这样两者会很好地重叠。
我们使用for
循环遍历每个区域。您可以在下面找到区域 id。
两个圆形区域的 id。图片由作者提供。
在for
循环中,我们设置颜色。我们可以使用其中一个字符{'b', 'g', 'r', 'c', 'm', 'y', 'k', 'w'}
,它是蓝色、绿色、红色、青色、品红色、黄色、黑色和白色的缩写。此外,您可以使用十六进制 RGB 或 RGBA 字符串(例如,'#4287f5'
或'#4287f580'
)。
对于区域 A,我们在区域 ID 10
和11.
中设置颜色
对于区域 B,我们在区域 ID 11
和01
中设置颜色。
我们用get_patch_by_id
到set_color
和set_alpha
。如果不使用set_alpha
,如果区域重叠,区域的颜色将是混合色。
我们需要删除数字,所以我们使用下面的代码来完成这项工作。
txt = v1.get_label_by_id(area)
if txt: txt.set_text('')
我们用set_axis_on
设置一个矩形边界,用set_facecolor
设置矩形的颜色。
我们使用set_title
来设置标题和字体大小。
我们需要在底部留出一些空间,所以我们使用下面的代码来完成这项工作。
ymin, ymax = ax1.get_ylim()
ax1.set_ylim(ymin - 0.1, ymax)
真,假
真假文氏图
对于“真实的”文氏图,我们为for
循环中的所有区域设置颜色skyblue
。
类似地,对于“假”文氏图,我们为for
循环中的所有区域设置颜色white
。
A 和 B,A 和 B
A 和 B,A 和 B 维恩图
对于“A 和 B”文氏图,我们为区域11
设置颜色skyblue
。
对于“A 与 B”维恩图,我们将颜色skyblue
设置为包括facecolor
在内的所有区域,除了区域11
。
A 或 B,A 也不是 B
A 或 B,A 或非 B 文氏图
对于“A 或 B”文氏图,我们为所有区域设置颜色skyblue
、10
、11
、01
,并将颜色white
设置为facecolor
。
对于“A 或非 B”文氏图,我们将颜色white
设置为所有区域,将skyblue
设置为facecolor
。
一个异或 B,一个 XNOR B
一个 XOR B,一个 XNOR B 维恩图
对于“A XOR B”文氏图,我们为区域10
和01
设置颜色skyblue
。
对于“A XNOR B”文氏图,我们将颜色skyblue
设置为区域11
和facecolor
。
不是 A,不是 B
不是 A,不是 B 文氏图
对于“非 A”文氏图,我们为区域01
和facecolor
设置颜色skyblue
,否则,我们为区域10
和11
设置颜色white
。
对于“非 B”文氏图,我们为区域01
和11
设置颜色white
,为区域10
和facecolor
设置颜色skyblue
。
A 不是 B,B 不是 A
A 不是 B,B 不是维恩图
对于“A 不是 B”的文氏图,我们将颜色skyblue
设置为区域10
,否则,我们将颜色white
设置为所有其他区域。
对于“B 非 A”文氏图,我们将颜色skyblue
设置为区域01
,否则,我们将颜色white
设置为所有其他区域。
蕴涵 A → B,B → A
A → B,B → A 文氏图
对于隐含的“A → B”文氏图,我们将颜色white
设置为区域10
,否则,我们将颜色white
设置为所有其他区域。
对于隐含的“B → A”文氏图,我们将颜色white
设置为区域01
,否则,我们将颜色white
设置为所有其他区域。
互斥的
互斥文氏图
对于互斥的文氏图,我们将颜色skyblue
设置为区域10
和01
。
补充
互补文氏图
你可以用一个圆形补丁和一个矩形补丁画一个圆形,但是我们将使用venn3
和venn3_circles
。我们画了三个圆,但我们将通过设置颜色white
来隐藏两个圆,这与facecolor
相同。
通过使用三圈标识,我们可以修改它的属性。
三个圆形区域的 id。图片由作者提供。
我们还通过使用text
添加了U
。
ax1.text(-1, 0.2, r'U', fontsize=15)
v.get_label_by_id()
返回一个对象,该对象是 matplotlib.text.Text 的实例。在这个例子中,我想向您展示如何通过使用set_fontsize
、set_color
、set_rotation
方法来改变它的属性。
子集
子集文氏图
我们可以使用venn2
和venn2_c
来创建一个子集文氏图。我们将区域01
设置为 0。
结论
matplotlib-venn 包用于绘制面积加权的二圆和三圆的维恩图,但是使用您的创造性思维,您也可以创建一个单圆的维恩图。
请继续关注下一篇文章。
通过 成为 会员,可以完全访问媒体上的每一个故事。
https://blog.codewithshin.com/subscribe**
如何用人工智能钻黑洞
黑洞是天空的奥秘。杰西·陈在 Unsplash 上的照片
如果爱因斯坦能做到,你也能。
我 今天是星期天,我们要在你的房间里安装一个新架子。“你能帮我一下吗,”你问。我无法把那颗螺丝拧进墙里。’
“你得先钻个洞,”我回答道,然后拿起螺丝刀。给你。
谢谢你,爱因斯坦!你大声喊道,脸上带着灿烂的笑容。
我傻笑。我敢肯定爱因斯坦在外太空钻的洞比他的墙还多…
“对不起,什么?”你越狱了。
我是说,太空中也有洞。“黑洞!”
在我们银河系的中心有一个黑洞。由马赫凯奥在 Unsplash 上拍摄的照片
你放下螺丝刀,哼了一声笑了。“是啊,爱因斯坦钻了它们,”
“所以他没有钻黑洞,但他告诉我们它们是如何工作的,”你总结道,擦去脸上笑出的泪水。它们是如何工作的?它们像暗物质一样吗?
嗯,不。他们是黑人,不是黑人!“那不一样,”我回答。他们基本上是大胖明星的尸体。
尸体呢。“到底怎么回事……”你说。
是的,尸体!“在它的一生中,恒星是一个巨大的氢球,逐渐燃烧成氦,然后变成更重的元素,”我开始说道。但当氢耗尽时,它就会崩溃。
为什么会崩溃?“它再也没有氢了,这是不是很可悲,”你又笑了。
“我不知道明星是否有感情,”我傻笑着回答。但是只要恒星燃烧氢,它就会发光。光的发射抵消了重力。这颗恒星会因为自身的引力而坍缩,但光的发射使它保持稳定。
“当恒星耗尽氢时,它不会发光,就会坍缩,”你问。
“一点不错,”我确认道。它因自身重力而坍塌。但只要它发光,它就稳定而有活力。
恒星是如何形成和演化的?恒星是最广为人知的天体,代表着最重要的…
science.nasa.gov](https://science.nasa.gov/astrophysics/focus-areas/how-do-stars-form-and-evolve)
“明白了,”你回答。我不确定你指的是星星还是你同时成功钻的洞。你转向我。所以当一颗恒星坍缩时,它基本上就死亡了。然后它就变成了一个黑洞,”
“如果它够重的话,”我澄清道。一颗恒星的终结基本上有三种方式。
埋葬、火葬和僵尸!”你大声喊道,脸上带着灿烂的笑容。
我笑了。不完全是。根据恒星的质量,它最终会成为白矮星、中子星或黑洞。例如,太阳的质量相当低。它最终会变成一颗白矮星。
“太阳会变成僵尸,”你断言,仍然咧着嘴笑。
“好吧,所以轻量级变成僵尸,”我同意。或者,正如天文学家所说的,白矮星
较重的星星呢?你戳。
黑洞是超大质量恒星的尸体
如果恒星的质量是太阳的十倍左右,一旦氢耗尽,就会发生超新星爆炸。“超新星爆发后,坍缩的物质变成了一颗中子星,”我回答道。
什么是中子星?你问。
中子星基本上是一堆中子。当恒星的质量足够大时,引力是如此之强,以至于质子和电子被挤压成中子。“现在你有了一个超高密度的中子球——中子星!”
好了,对我来说就是火葬了。“就像有些人死后被压成钻石,那些恒星被压成中子堆,”你宣布。
“这是个好主意,”我一边回答,一边把一个螺丝拧进了墙上的洞。现在有些恒星质量太大,无法成为中子星。它们被万有引力挤压,我们最终形成了一个黑洞!
当恒星耗尽燃烧所需的氢时,它就会死亡。威尔·斯图尔特在 Unsplash 上拍摄的照片
“好吧,那么黑洞是超大质量的死星?”你问吧。
“一点不错,”我确认道。它们是如此巨大,以至于没有任何东西可以稳定它们,所以所有的东西都会在其中坍塌。如果另一个物体离它太近,它就会像吸尘器一样被吸进去。
它可能发生在任何人身上。也许你正在努力寻找一个新的适合人类居住的星球,或者你正在…
www.bbc.com](http://www.bbc.com/earth/story/20150525-a-black-hole-would-clone-you)
哇哦。“黑洞是埋藏的恒星尸体和巨大的真空吸尘器!”你惊呼。“我们能看看它们吗,”
不完全是。黑洞会吸走一切,甚至光。“反正天空很暗,我们什么也看不见,”我解释道。
但是我看到了一张黑洞的图片你插嘴。
“嗯,是的,”我承认。但是你在图片上真正看到的并不是黑洞本身。它是黑洞边缘的热物质。天文学家称之为事件视界。我们看不到视界后面,但我们可以看到它周围即将被吸入的非常热的物质。
显然拍那张照片真的很难。“为什么这么难,”你问。
“黑洞离我们真的很远,”我解释道。最近的黑洞距离地球如此之远,以至于在月球上看起来就像一个橘子那么大!所以我们需要一个非常大的望远镜来捕捉它。物体越小,我们需要的望远镜就越大。
黑红色抽象,类似黑洞。约翰·保罗·萨默斯在 Unsplash 上的照片
但是我们有非常大的望远镜,对吗?你问吧。
“是的,”我肯定地说。但是为了看到这个黑洞,我们需要一个地球大小的望远镜。
“哦,”你说。
好消息是,我们可以使用世界上不同的望远镜,把它们拼凑成一个大的。然后我们猜测在所有没有望远镜的地方,望远镜会看到什么。
我们猜?那幅著名的画是猜的吗?你哭了。
“嗯,这是一个非常聪明的猜测,”我回答道。“科学家们用人工智能来重建图像,他们是如何做到的非常令人惊讶。”
“哦,好的,”你笑着回答。看来人工智能是钻黑洞的螺丝刀!
我笑了。是的,你可以这么看。想想人工智能也习惯于发现我们从未见过的黑洞。或者它如何被用来探测引力波,引力波通常来自两个合并的黑洞
AI 摇滚!你惊呼。这就是为什么我们用它来研究黑洞,”
“是的,”当我们把你的架子抬到墙上的新位置时,我回答道。不过,我们还是用普通的洞和螺丝起子来钉墙吧,好吗?
“好吧,爱因斯坦,”你傻笑。但是我会在书架旁边挂一张黑洞的海报,不管有没有 AI!’
如何为你的人工智能应用程序轻松下载谷歌的开放图像数据集
由作者通过 Canva 创作,图片列在( CC BY 2.0 许可下)
你是那种想要建立一个自定义图像分类器,但不知道如何从 Google 的 OpenImages 数据集中只下载“图像”而不是标签的书呆子吗?
GIF 承接自 G iphy
你是那种想要建立一个自定义对象检测器,但不知道如何从谷歌的 OpenImages 数据集的 600 个对象类中下载选定的类的人吗?
好吧,我的朋友,你并不孤单,我也曾经有过同样的问题,直到几周前我偶然发现了这个包裹。
但是在学习使用这个包之前,让我们深入了解一下关于 Google 的 OpenImages 数据集的基本事实。
谷歌的开放图像数据集:拨乱反正的举措
开放图像数据集被称为现有计算机视觉数据集中的巨人。它有大约 900 万张图像,标注有图像级标签、对象边界框、对象分段遮罩、视觉关系和本地化叙述。它包含 1.9M 图像上 600 个对象类的总共 16M 的边界框,使其成为具有对象位置注释的最大的现有数据集*。*
据说一张图片胜过千言万语,上面的图片展示了如果你不使用开放的图像数据集,你的应用程序可能会变成另一个物体检测器或另一个图像分类器。但是,如果你利用谷歌开放图像数据集的力量,你可能会把你的人工智能应用程序变成一个通用的可扩展的解决方案,可能服务于许多人或一个社区的需求。[难道这不是我们在不同的屋檐下努力工作的原因吗,通过人工智能来帮助那些无法帮助自己的人,这取决于你]。
开发者模式:是时候做一些安装了
背景故事:
几周前,当我在为我的定制麸质/非麸质食品分类器寻找一个更好的解决方案来下载谷歌的开放图像数据集时,我坚持不懈的搜索将我带到了最近在 2 月份发布的名为“ openimages 的 Python 包。
因此,在博文的这一部分,我将分享我将 python 包安装到我的 Linux 系统中的步骤,以及我如何使用 python 包中的模块来下载数据集中可用的几个类的图像。与此同时,我将分享下载任何类标签的图像和注释所需的命令。
包装说明:
openimages 包附带了一个“ download ”模块,该模块提供了一个具有两个下载功能的 API 和一个相应的 CLI(命令行界面),其中包括可用于从 OpenImages 数据集下载图像和相应注释的脚本入口点。
安装程序:
创建虚拟环境:
作为一个最佳实践,始终使用 Python " 虚拟环境"来为任何特定的应用程序安装 Python 包,因为最好在一个隔离的位置安装包或库,而不是全局安装。
对于 Linux 用户,键入以下命令
virtualenv <DIR>
source <DIR>/bin/activate
如果您是 window 用户,请使用
virtualenv <DIR>
<DIR>\Scripts\activate
当 virtualenv 处于活动状态时,您的 shell 提示符会以 < DIR > 为前缀。
现在,在不影响主机系统设置的情况下,开始在虚拟环境中安装软件包。让我们从升级pip
开始:
<DIR>:~$ pip install --upgrade pip
openimages 包适用于 Python 3.6+版本。所以,一定要确保你有一个支持 openimages 的版本。现在,在活动的虚拟环境中,键入。
<DIR>:~$ pip install openimages
该命令将下载一些库,这些库对于从 Google 的 OpenImages 数据集中下载图像和相应的注释非常重要。
下面列出了将要安装的库:
ImageHash-4.1.0
absl-py-0.9.0
astunparse-1.6.3
boto3–1.13.16
botocore-1.16.16
cachetools-4.1.0
cvdata-0.0.7
docutils-0.15.2
gast-0.3.3
google-auth-1.15.0
google-auth-oauthlib-0.4.1
google-pasta-0.2.0
grpcio-1.29.0
jmespath-0.10.0
keras-preprocessing-1.1.2
markdown-3.2.2
oauthlib-3.1.0
opencv-python-4.2.0.34
openimages-0.0.1
opt-einsum-3.2.1
protobuf-3.12.1
pyasn1–0.4.8
pyasn1-modules-0.2.8
requests-oauthlib-1.3.0
rsa-4.0
s3transfer-0.3.3
tensorboard-2.2.1
tensorboard-plugin-wit-1.6.0.post3
tensorflow-cpu-2.2.0
tensorflow-estimator-2.2.0
termcolor-1.1.0
这是软件包安装完成后输出的样子[open_images_second_trial]只是一个虚拟环境名。
截图由作者拍摄
与这些包一起,两个 python 入口点也被安装在环境中,对应于下面描述的公共 API 函数oi_download_dataset
和oi_download_images
:
openimages.download.download_images
仅用于下载图像openimages.download.download_dataset
用于下载图像和相应的注释。
入口点+ CLI == “您下载数据集的途径”
在这一节中,我将通过使用提供的入口点,向您介绍下载数据集的图像和注释所需的命令行参数。请务必参考下图来加深理解。
在了解了命令行参数[CLI]之后,是时候使用它进行进一步的操作了,任何猜测,是的,你是正确的,下载图像和它们的标签。
I:为类标签下载图像和 PASCAL 格式注释的使用示例
<DIR>:~$ oi_download_dataset --csv_dir ~/<dir_A> --base_dir ~/<dir_A> --labels Zebra Binoculars --format pascal --limit 200
最好将 CSV 目录和基本目录保存在同一个位置,限制完全取决于你想下载多少带有类别标签的图像。
一旦你运行这个命令,去喝热水或啤酒,因为它需要时间将数据下载到您的计算机存储。
II:为类标签下载图像的用法示例
<DIR>:~$ oi_download_images --csv_dir ~/<dir_A> --base_dir ~/<dir_A> --labels Surfboard --limit 200
如果您多次运行这个脚本,那么它将从~/ <dir_a>中读取 CSV 文件,而不是再次下载文件。</dir_a>
截图由作者拍摄
一旦您的课程下载完成,不要忘记退出您的虚拟环境,只需输入:
<DIR>:~$ deactivate
:~$
这标志着整个过程的结束。我希望当你在读这几行的时候,你的数据下载过程一定已经开始了,你一定已经在计划使用哪种模型或者保持什么样的学习速度等等。
资源:
- Openimage 0.0.1:从 Google 的 OpenImages 数据集下载图像和相应注释的工具。
- OpenImages 数据集 Github repo 。
- OIDv4 工具包:下载图像和标签用于物体检测和图像分类任务的实用工具。
- 打开图像的快速图像下载器 V4 。
感谢您的关注
你用你的时间阅读我的作品对我来说意味着一切。我完全是这个意思。
此外,如果你愿意,可以在 Medium、LinkedIn 或 Twitter 上关注我!我很乐意。
阅读纳文·曼瓦尼在媒介上的作品。一个机器学习工程师,一个深度学习爱好者|Mentor @ Coursera…
medium.com](https://medium.com/@naveenmanwani) [## Naveen Manwani -机器学习工程师- AIMonk Labs Private Ltd | LinkedIn
查看纳文·曼瓦尼在全球最大的职业社区 LinkedIn 上的个人资料。Naveen 有一份工作列在他们的…
www.linkedin.com](https://www.linkedin.com/in/naveen-manwani-65491678/) [## 纳文·曼瓦尼
纳文·曼瓦尼的最新推文(@纳文·曼瓦尼 17)。机器学习工程师@ AIMONK Labs Pvt ltd,深…
twitter.com](https://twitter.com/NaveenManwani17)
如何在 Python 中轻松集成来自 Google Sheets、Dropbox 和你的桌面的电子表格
告别电子表格集成难题
免责声明:这篇文章使用了我做的一个产品, API 电子表格 ,我相信这确实是最简单的方法。你可以自己去看看。
当你从事数据科学或分析项目时,通常到处都存储着大量的电子表格。
如果你和我一样,你可能会这样做:
- 下载你的谷歌工作表作为电子表格
- 下载你的 Dropbox 电子表格
- 把它们和你的桌面文件放在同一个文件夹里
- 使用熊猫读取所有文件
这是一个不错的工作流程。但是营销部门的史蒂夫改变了谷歌表单中的一些数据。
“不要担心”,您在重新下载表单并重新运行工作流程时回复。
现在,人力资源部的卡玛拉又给 Dropbox 添加了两个电子表格。
“我明白了”,你一边慢慢冷静一边说。
然后你的老板告诉你把你所有的电子表格用电子邮件发给她,这样她就可以对你的数据进行三次检查。“哦,顺便说一句”,她说,“不要忘了使用我们副总裁力推的样式来更改所有电子表格的名称”
你正式失去理智了。
更简单的方法
我将向您展示如何使用 API 电子表格和 Python 轻松地将所有这些来源的数据整合在一起。并保持更新和同步。这样你就能保持冷静和快乐!
我们将使用 1 个谷歌表,1 个本地文件和 1 个 Dropbox 文件。每个文件将包含来自一个唯一美国州的 Covid 数据:TX、NJ 或 CA。数据将按县在每行上分解,如下所示:
来自 NJ 文件的样本数据。每个文件中的标题都是相同的
我们开始吧!
步骤 0:创建一个空的 Python 文件
创建一个名为spread sheet _ integration . py的空 Python 文件,并将其保存在某个地方。
该文件的最终代码如下。我们将在这篇文章中介绍如何到达那里。
最终文件代码
步骤 1:创建一个 API 电子表格免费帐户
前往www.apispreadsheets.com点击注册创建一个免费账户
第二步:连接到你的谷歌表单
点击谷歌表单上传框
点击 Google Sheets 上传框开始连接
选择您想要连接的 Google 表单
选择要连接的文件
从 Read 选项卡中复制 Python 代码并粘贴到您的 Python 文件中
您的 Python 文件现在将包含以下代码
import requestsr = requests.get("[https://api.apispreadsheets.com/data/581/](https://api.apispreadsheets.com/data/581/)")if r.status_code == 200:
# SUCCESS
data = r.json()
else:
# ERROR
data=None
我们现在要改变代码中的两件事,使数据更容易处理
- 我们将从 r.json()对象的数据键中访问数据
- 我们将导入熊猫并将数据转换成熊猫数据框架
我们的代码现在将如下所示
import requests
import pandas as pdr = requests.get("[https://api.apispreadsheets.com/data/581/](https://api.apispreadsheets.com/data/581/)")if r.status_code == 200:
data = pd.DataFrame(r.json()["data"])
else:
data = None
这篇文章中的所有 API 链接都是公开的,所以请随意使用这些链接进行测试!
步骤 3:连接到你的 Dropbox 文件
点击 Dropbox 上传框。第一次点击会要求您进行身份验证,或者如果您的帐户已经在标签中打开,它会刷新页面。这是 Dropbox 身份验证的预期行为。
点击 Dropbox 上传框开始流程
现在再次点击 Dropbox 上传框,你会看到一个文件选择器。选择您的文件。
按照与上面相同的步骤在文件中复制 Python 代码。
但是,我们现在将更改请求和数据的名称,以便于识别
import requests
import pandas as pdgoogle_sheet_request = requests.get("[https://api.apispreadsheets.com/data/581/](https://api.apispreadsheets.com/data/581/)")dropbox_request = requests.get("[https://api.apispreadsheets.com/data/582/](https://api.apispreadsheets.com/data/582/)")if google_sheet_request.status_code == 200:
google_sheet_data = pd.DataFrame(google_sheet_request.json()["data"])
else:
google_sheet_data = Noneif dropbox_request.status_code == 200:
dropbox_data = pd.DataFrame(dropbox_request.json()["data"])
else:
dropbox_data = None
步骤 4:从桌面上传文件
现在,我们将从您的桌面上传文件。
我们不会再用这个过程来烦你了。只需点击上传或删除文件框,上传您的文件。
按照与上面相同的步骤获取 python 代码,并将其插入到 Python 文件中。然后更改变量名,这样就有意义了。
这将引导我们找到最终的代码
原谅 local_data 上的缩进
就是这样!这就是集成各种来源的电子表格数据有多容易。
最棒的是,如果底层的 Google Sheet 或 Dropbox 文件数据发生变化,那么你的数据会自动更新。
如果你想和别人分享你的数据,你只需要给他们发送 API 链接。
祝你整合之旅好运,如果你遇到任何麻烦或有任何问题,请随时给我在 adhaar@lovespreadsheets.com 留言。
如何使用 TensorFlow 在您的 GPU 上轻松处理音频
使用 TensorFlow 的信号处理模块,充分利用您的 GPU 处理音频数据的能力
对音频数据的深度学习通常需要繁重的预处理步骤。
虽然有些模型运行在原始音频信号上,但其他模型期望将时频表示作为输入。在模型训练之前,预处理通常作为一个单独的步骤来完成,使用像[librosa](https://librosa.github.io/librosa/)
或[Essentia](https://essentia.upf.edu/)
这样的工具。
但是,当您开始处理更大的数据集时,此工作流会带来挑战。
任何时候改变参数,比如采样率或 FFT 大小,都需要再次处理整个数据集,然后才能继续训练。
这意味着等待。😴
即使在可用的 CPU 内核上并行化,预处理也需要很长时间。另外,您需要考虑如何存储和访问不同参数的文件。这无疑会浪费磁盘空间和精神资源,并且很快会变得令人头痛。
这些听起来熟悉吗?
厌倦了这种繁琐的两步走的过程,我开始问自己是不是没有更好的办法。
“没有更好的办法了吗?”
我最近建立了一个高效的音频数据管道,它使我能够按需将音频从文件路径加载到模型中。
[## 如何使用 TensorFlow 2.0 构建高效的音频数据管道
使用 TensorFlow 的数据集 API 消除培训工作流程中的瓶颈
towardsdatascience.com](/how-to-build-efficient-audio-data-pipelines-with-tensorflow-2-0-b3133474c3c1)
我还想对基于声谱图的模型使用相同的数据管道。
在这篇文章中,我想和你分享:
- 如何利用 GPU 的能力来完成信号处理任务。
- 如何构建自定义预处理层以用于任何神经网络。
- 最后还有一点奖金。😲
请继续阅读,了解更多信息。
如何用 5 个简单的步骤预处理您的音频数据
深度学习应用中跨音频域的流行特征表示是 mel-spectrogram 。
mel 谱图是信号频谱随时间变化的直观表示。与标准声谱图的主要区别在于,频率被投射到 mel 音阶 上,其中音高的感知距离等于 mel 频率的距离。这是受我们如何听的启发。
同样,梅尔频谱图的幅度通常是对数标度的,因为这更接近于我们如何感知响度的变化。因此,更精确的术语应该是对数级 mel 标度频谱图。但因为这相当拗口,所以大多数人简称它为对数-梅尔-光谱图或梅尔-光谱图。值得指出的是,尽管 mel 指的是频率等级,但是 log 描述的是震级的等级。
那么,如何将原始音频信号转换成 mel 频谱图呢?
- 计算音频信号的短时傅立叶变换
- 计算大小
- 实例化 mel 滤波器组
- 将线性标度的星等谱图弯曲到 mel 标度
- 将幅度转换为对数标度
让我们详细看看每一步。
这是我们将要学习的声音示例
1.计算短时傅立叶变换
短时傅立叶变换(STFT)将长信号分成较短的片段,通常称为帧,并计算每帧的频谱。帧通常会重叠,以尽量减少边缘的数据丢失。将每一帧的光谱结合起来就产生了光谱图。
要使用 TensorFlow 计算 STFT,请使用[tf.signal.stft(signals)](https://www.tensorflow.org/api_docs/python/tf/signal/stft)
,其中signals
是包含音频信号的张量。
您需要设置的一些参数是:
frame_length
:样本中每一帧的长度。这通常被称为窗口长度或窗口大小。窗口大小以时间分辨率(短窗口)换取频率分辨率(长窗口)。frame_step
:帧间样本数。这通常被称为跳长或跳大小。fft_length
:要应用的 FFT 的大小。这通常称为 FFT 大小,与frame_length
相匹配。它默认为可以包含一个框架的最小 2 次方。因此,如果frame_length
是 2 的幂,并且你没有显式地设置fft_length
,它取相同的值。
spectrograms = tf.signal.stft(signals,
frame_length=1024,
frame_step=512)
2.计算大小
上一步中的 STFT 返回一个复数值张量。使用[tf.abs()](https://www.tensorflow.org/api_docs/python/tf/math/abs)
计算震级。
magnitude_spectrograms = tf.abs(spectrograms)
我们现在可以画出星等谱图。
不过,请注意,在正确缩放数量级之前,您不会看到太多。第二个支线剧情用librosa.amplitude_to_db()
缩放。所以,从技术上讲,这是一个对数级的功率谱。
在第 5 步中会有更多的介绍。
上图:星等谱图。是全黑吗?不。如果你仔细看,你可以在较低的频率上看到一点能量。下图:对数幅度谱图。当量值用对数标度时,你可以在几个频带中看到能量。
3.实例化 Mel-滤波器组
将标准频谱图转换为 mel 频谱图包括将频率扭曲到 mel 标度,并将 FFT 仓组合到 mel 频率仓。
TensorFlow 使这种转变变得容易。
您可以使用[tf.signal.linear_to_mel_weight_matrix()](https://www.tensorflow.org/api_docs/python/tf/signal/linear_to_mel_weight_matrix)
创建一个 mel-filterbank,将线性标度光谱图扭曲到 mel 标度。
您只需要设置几个参数:
num_mel_bins
:生成的 mel 谱图中 mel 频段的数量。num_spectrogram_bins
:源谱图中唯一谱图仓的数量,等于fft_length // 2 + 1
。sample_rate
:输入信号每秒的样本数。lower_edge_hertz
:包含在 mel 标度中的最低频率,单位为赫兹。upper_edge_hertz
:包含在 mel 标度中的最高频率,单位为赫兹。
具有 16 个梅尔槽的梅尔滤波器组
4.将线性标度的星等谱图弯曲到 mel 标度
将平方的星等谱图乘以 mel 滤波器组,就可以得到 mel 标度的功率谱图。
mel_power_specgrams = tf.matmul(tf.square(magnitude_spectrograms),
mel_filterbank)
5.将幅度转换为对数标度
我们以对数方式感知响度的变化。所以,在这最后一步,我们也想用对数来表示 mel 光谱图的幅度。
做到这一点的一个方法是获取梅尔光谱图的log
。但是这可能会给你带来麻烦,因为log(0)
没有定义。相反,您希望以数值稳定的方式将幅度转换为分贝 (dB)单位。
log_magnitude_mel_spectrograms = power_to_db(mel_power_spectrograms)
下面是如何在基于[librosa.power_to_db](https://librosa.github.io/librosa/_modules/librosa/core/spectrum.html#power_to_db)
的 TensorFlow 中做到这一点。
将功率谱转换为张量流中的分贝单位
转换成对数标度后,光谱图的最大值为零,最小值为负top_db
。
“电子琴”的 mel 频谱图,具有 64 个 Mel 频段、16 kHz 采样率、1024 个样本 FFT 大小和 512 个样本跳数大小
现在有趣的部分来了。
准备好立即获得更大的灵活性了吗?
将各个步骤组合到一个自定义的预处理层中,允许您将原始音频馈送到网络,并在 GPU 上动态计算 Mel-spectro gram。
为了创建你的 mel-spectrogram 层(或任何自定义层),你从[tf.keras.layers.Layer](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Layer)
和子类实现三个方法:
__init__()
:将层的配置保存在成员变量中。build()
:定义你的体重。call()
:执行将图层应用到输入张量的逻辑。这是你将音频输入张量转换成梅尔频谱图的地方。
下面是我实现的一个自定义 Keras 层,它将原始音频转换为 log-Mel-spectrogram:
使用此自定义 Keras 层将原始音频转换为 log-Mel-spectrogram
一旦定义好,你就可以在一行代码中添加音频预处理到你的神经网络中。
一个神经网络的例子,它使用了我们上面定义的自定义 LogMelSpectrogram-layer
现在,您可能想知道,将相同的音频信号一次又一次地转换成频谱图,效率会不会低得令人难以置信。
这是一个很好的观点。
在写这篇文章的时候,我遇到了一个“用于音频和音乐信号预处理的 Keras 层”库。作者,Choi 等人,展示了一个基准,它显示,他们的预处理层增加了大约 20%的开销。
所以,这是一个权衡。就像生活中的任何事情一样。
在这种情况下,您用存储空间换取了稍长的计算时间。但不仅如此。您还可以摆脱繁琐的两步过程,并立即获得在音频数据上训练深度学习模型的更大灵活性。
尝试不同的预处理参数现在就像用不同的参数重新开始你的训练程序一样简单。
- 不需要维护单独的预处理脚本。
- 无需记住在多个地方更改参数。
- 在继续训练之前,无需处理整个数据集。
值得开销吗?
你自己决定。
这里有些东西可以帮你做到这一点
所有代码和示例都可以在这个 Colab 笔记本中找到:
[## Google Colab:如何使用 TensorFlow 在 GPU 上处理音频
免费笔记本,互动体验这篇文章。
colab.research.google.com](https://bit.ly/2QEBKEJ)
现在轮到你了。
你简化了(或喜欢简化)的工作流程中有哪一个给了你更多的灵活性和思维空间,尽管它稍微贵了一点?
参考
- 【1】h . Purwins 等,音频信号处理的深度学习(2019),IEEE 信号处理精选期刊 13.2:206–219
- [ 2 ] K. Choi 等人,Kapre:快速实现深度神经网络模型的 GPU 上音频预处理层,Keras (2017) arXiv 预印本
如何在 Keras 模型中轻松使用梯度累积
实现通用梯度累积机制的分步指南
在的另一篇文章中,我们讨论了什么是深度学习中的梯度累积,以及它如何解决运行大批量神经网络时的问题。
在本文中,我们将首先看到如何轻松使用我们在 Run:AI 中实现和使用的通用渐变累积工具。然后,我们将深入研究 Keras 优化器以及我们实现这种通用工具的方式。
在您自己的模型中使用渐变累积
向 Keras 模型添加渐变累积支持非常简单。首先,使用命令安装 Run:AI Python 库:
pip install runai
然后,将渐变累积包导入到 Python 代码中:
import runai.ga
现在,你可以从两个选项中选择一个。您可以用通用的梯度累积包装器包装现有的优化器,或者创建任何内置优化器的梯度累积版本。这两个选项需要指定您想要累积梯度的步数(在下面的示例中作为STEPS
传递)。
使用下一行包装一个现有的优化器(其中optimizer
是您的优化器):
optimizer = runai.ga.keras.optimizers.Optimizer(
optimizer, steps=STEPS)
或者,使用下一行创建任何内置优化器的渐变累积版本(下一个示例中使用了“Adam”):
optimizer = runai.ga.keras.optimizers.Adam(steps=STEPS)
就是这样!您已经成功地向 Keras 模型添加了梯度累积支持。
Keras 优化器概述
在了解了它的易用性之后,现在让我们来看看它到底是怎么回事。首先,我们将研究 Keras 中优化器的概念,并讨论它们的责任和实现。然后,我们将深入探讨我们是如何实现这样一个通用机制的。
哲学
Keras 中的优化器负责实现优化算法——负责最小化损失函数的数学公式。它们接收所有模型参数(权重和偏差)作为输入,计算它们的梯度,并使用它们来生成模型参数的更新。模型参数的更新不是梯度本身,而是使用梯度以及其他参数来计算的。
每个优化算法都有参数。有些优化器有相似的参数(如“epsilon”、“beta_1”、“beta_2”等…),有些可能有独特的(如 Adam 中的“amsgrad”),它们都支持“学习率”(以及学习率衰减)。
在构建模型时,Keras 将调用优化器并传递两个参数。第一个参数将是模型的所有可训练变量——权重和偏差。第二个参数是损失值。注意,可训练变量和损失是张量,而不是张量的实际值。
然后,优化器获取这些输入张量,并将优化算法添加到模型中。它首先计算可训练变量相对于损失的梯度(通过调用tf.gradients()
),然后生成代表数学公式的张量。
然后,Keras 将评估这些张量——由优化器生成——每一步。通过评估这些张量,将计算梯度,然后计算变量更新并将其分配给模型变量,即权重和偏差。
履行
Keras 优化器是 Python 类,它们都继承了一个叫做Optimizer
的基类(这里可以看到)。基类实现了一些方法,并声明了必须在子类中实现的其他(虚拟)方法。让我们简单地检查一下Optimizer
中的方法:
__init__(self, **kwargs)
:初始化常用成员和配置参数。get_updates(self, loss, params)
:没有在基类中实现的虚方法,必须在子类中定义,实现优化器的数学公式。get_gradients(self, loss, params)
:相对于params
(技术上是tf.gradients()
的一个包装器)简化loss
的梯度计算的实用方法。set_weights(self, weights)
:设置优化器的权重值。get_weights(self)
:获取优化器的权重值。get_config(self)
:获取常用配置值。
我们将关注get_updates()
。此方法仅在基类中声明(虚拟的);它不在 it 中实现,必须在所有子类中实现。它的实现是不同优化器之间的主要区别。
正如我们所说,Keras 将调用get_updates()
作为构建模型的一部分。该方法接收两个参数:loss
和params
,它们都是张量。并返回一个张量列表,它们是“赋值”操作——在求值时实际赋值变量更新的张量。
SGD 实现的简化版本
SGD 优化器的算法
让我们检查 SGD 的get_updates()
实现的简化版本。请注意,这是一个简化版本,而不是 Keras 中的实际代码:
SGD 的 get_updates()的简化版本
首先,在第 2 行,优化器通过调用self.get_gradients()
来计算loss
相对于params
的梯度。
然后,在第 4–6 行,优化器遍历模型的所有可训练变量,以及它们各自的计算梯度。对于每个参数,它使用梯度和学习率计算(第 5 行)变量的新值(self.lr
是在__init__()
中初始化的张量)。然后,它创建一个张量,该张量将分配变量的新值(K.update(p, new_p)
),并将其添加到此类张量的列表中(self.updates
)。
最后,在第 8 行,优化器返回“赋值”张量的列表(self.updates
),Keras 将在每一步对其进行评估。
在构建模型时,该方法只被调用一次。这可能需要一些时间来消化,但一定要理解,参数和结果是张量对象,而不是实际的张量值。请注意,第 5 行可能会引起误解,看起来它计算的是实际值,但事实并非如此,它只是张量对象上的语法糖(TensorFlow 的操作符重载)。
现实中更复杂一点
在检查了简化版本之后,是时候弄清楚现实中会发生什么了。
除了它们的简单算法之外,大多数优化器支持学习率衰减,这意味着它们在模型的整个训练过程中修改学习率,而不是为它提供一个常量值。为了支持随时间修改学习率,应该定义时间的概念。正如预期的那样,学习率不是作为自训练阶段开始以来已经过去的实际时间的函数来修改的,而是作为步数的函数来修改的,并且为了支持这一点,优化器计算步数(在它们的实现中称为iterations
)。
此外,Keras 中的 SGD 支持动量和内斯特罗夫动量算法,这使事情变得更加复杂。让我们来看看 SGD 的get_updates()
的实际实现(在 GitHub 上也可以看到):
SGD 的 get_updates()
让我们检查一下我们之前检查过的简化版本的附加内容。
在第 3 行,优化器创建了一个“赋值”张量,在每一步中把self.iterations
增加 1。self.iterations
是步数计数器(张量对象),在__init__()
中创建,初始值为 0。
在第 5–7 行中,我们可以看到学习率衰减公式是步进计数器(self.iterations
)和衰减值(创建时传递给优化器的参数,并设置为self.decay
)的函数。
在第 11 行,它创造了动量的变量。它为每个可训练变量声明另一个具有相同形状的变量,并将其初始化为 0(调用K.zeros(shape)
)。
然后,在可训练变量的迭代中,它计算每个动量的新值(第 14 行),并创建一个“赋值”张量以用新值更新动量(第 15 行)。
然后,在第 17–20 行,它计算参数的新值——取决于是否配置为应用内斯特罗夫动量——并在第 23–24 行对参数应用必要的约束(如果有的话)。
其余的行类似于之前的简化版本。
你可以逛逛optimizer . py并阅读 Keras 不同优化器的实现。
实施梯度累积机制
现在,在深入研究了什么是 Keras 优化器以及它们是如何实现的之后,我们准备讨论梯度累积机制的不同实现方案。
每个优化器特定的实现
可以重写任何优化器来支持梯度累积。梯度应该在几个步骤中累积,然后优化器才应该使用它们来更新模型参数。这不是最佳的,因为梯度累积是一种通用的方法,应该是独立于优化器的,并且这种方法有几个缺陷:
- 每个优化器都有不同的公式来实现不同的优化算法,因此对于相应的梯度累积版本将需要不同的实现。
- 这是特定于版本的,每次原始实现发生变化或添加新的优化器时,都需要修改代码。
- 它会导致代码重复,而且不够优雅。
一种更可取的方法是设计梯度累积模型,使其能够包装任何 Keras 优化器,而不管其优化算法如何。
Keras 优化器的通用包装器
通过具有通用的梯度累积机制,原始优化器中的变化将不需要代码更新。
为了设计和实现通用的梯度累积机制,需要考虑一些事情。
为什么我们需要一个复杂的解决方案?
在每个小批量上运行优化算法不会导致模型参数的相同更新。换句话说,我们不能只在每一步评估优化算法——在每一个小批量上。否则,没有必要进行梯度累积,我们可以使用较小的批量。
如果我们使用全局批次,所有梯度都将使用相同的模型参数值(权重和偏差)进行计算。当将全局批量分成几个小批量时,评估每个步骤的优化算法将导致在每个小批量之后更新模型参数。这意味着不会使用相同的权重和偏差值来计算所有小批量的梯度。
此外,优化器使用各种参数作为其公式的一部分,并且这些参数作为优化算法评估的一部分被更新。在每个小批量之后,每步更新这些参数将导致不同小批量之间优化算法的状态变化。
那我们该怎么办?
我们的包装器是一个继承了 Keras 的基类Optimizer
的 Python 类。我们在创建时接收原始优化器作为参数(在__init__()
中),以及我们想要累积梯度的步骤数。
我们定义优化器公开的所有方法(即get_gradients()
、set_weights()
、get_weights()
等……),并透明地调用原始优化器各自的方法。正如所料,主要逻辑位于get_updates()
中。
让我们开始研究get_updates()
(也可以在 GitHub 上看到),并深入研究算法和实现:
渐变累积包装的 get_updates()
计算梯度
第一行(2)应该看起来很熟悉,我们用和其他优化器一样的方法计算梯度。注意grads
将保存每个小批量的梯度值。
声明辅助张量
在第 5 行中,我们声明了一个步长计数器,名为iterations
,初始值为 0(与其他优化器非常相似)。我们使用步数计数器来判断我们是处于累积的第一步还是最后一步。为此,我们声明两个张量:first
和last
(第 6–7 行)。
first
将被设置为True
每次我们正好经过self.steps
步。从技术上讲,此时iterations % self.steps
将等于 0。例如,如果我们在五个步骤上进行累积,那么在第一个步骤(索引为 0)、第六个步骤(索引为 5)、第十一个步骤(索引为 10)等都是这种情况。在这些情况下,在步骤开始时,我们希望将累积的梯度重置为 0,并再次开始累积。
last
将被设置为True
每一步我们要更新的变量。从技术上讲,此时iterations % self.steps
将等于self.steps — 1
。继续前面的例子,这将是第五步(索引 4)、第十步(索引 9)等的情况
累积的梯度
在第 10 行中,我们声明变量来保存步骤之间的累积梯度值。我们用参数的形状和类型为每个模型参数——为每个可训练的权重或偏差——声明这样一个变量,并用零初始化它们。
使用这些变量,在第 13 行我们声明了张量——agrads
——来保存每一步中累积的梯度值。我们使用first
来告诉我们是否应该从现在开始累积梯度或者使用在前面步骤中累积的梯度。如果first
是True
——意味着我们从现在开始累积——我们单独使用当前小批量的梯度。如果first
是False
——意味着我们应该使用在过去步骤中累积的梯度——我们将当前小批量的梯度加到vagrads
。使用K.switch()
将该控制流(检查first
的值)生成到模型中。
好的,那太好了,但是优化算法本身呢?
作为一个通用包装器,我们不实现任何优化算法。最初的优化器对此负责。正如我们所介绍的,每个优化器都在get_updates()
中实现它的数学公式。在这里,优化器管理并使用公式所需的所有参数(例如,步数计数器、学习率、动量等)。优化器将参数值存储在专用变量中,每次需要更新参数时,它都会将新值赋给专用变量。
方法get_updates()
被调用一次,生成将在每一步中评估的“赋值”张量。其中一些是模型参数的更新,另一些是优化器参数的更新。
只要我们在累积梯度,我们不希望任何这些更新发生。我们不希望更新模型参数,以使所有小批量从完全相同的点开始,在权重和偏差方面具有相同的值。我们不希望优化器参数被更新,以便优化器以好像在全局批处理上运行的速度前进。例如,我们希望步骤计数器仅在所有小批量通过后才增加,因此学习速率将以正确的速率修改。
我们希望所有的更新都在所有的小批量通过之后才发生。从技术上讲,这意味着我们希望更新发生在累加的最后一步——当last
为True
时。
因此,如果我们可以调用最初的优化器的get_updates()
,同时(1)使它使用累积的梯度,并且(2)使所有的变量更新只发生在累积的最后一步,我们将会实现我们想要的。
幸运的是,在 Python 中替换(挂钩)方法真的很容易,通过用不同的实现替换一些方法,我们可以很容易地做到这一点。
优化器从get_updates()
调用它们的get_gradients()
来计算参数相对于损失的梯度。因此,我们将优化器的get_gradients()
替换为一个只返回累积梯度的函数(agrads
—我们在第 13 行生成的张量)。这将导致原始优化器在其算法中引用累积的梯度,并将求解(1)。让我们来看看这种替换方法的简化实现:
get_gradients()替换的简化版本
关于(2),Keras 中的变量可以用三种方法赋值:K.update()
、K.update_add()
和K.update_sub()
。优化器将这些方法用于所有更新——模型参数和优化器参数。我们把他们三个都换掉(可以在 GitHub 上看到)。我们希望使用这些方法创建的所有张量只在最后一个小批量中赋值,否则不做任何事情。因此,在我们的方法中——取代了这三个方法——我们用一个条件开关包装每个被赋值的值,并将这个开关传递给相应的方法。如果这是最后一个小批量(last
是True
),我们将实际值赋给变量,否则,我们赋一个不影响变量的值。对于K.update_add()
和K.update_sub()
,我们赋零,导致变量实际上没有增加或减少。对于K.update()
,我们分配变量的当前值,使变量保持其当前值。让我们来看看这种替换方法的简化实现:
替代赋值方法的简化版本
回到我们的get_updates()
,在第 15–18 行,我们实际上替换了所有这些方法。我们使用助手类——runai.utils.Hook
的子类——来实现这一点。
在第 19 行,我们调用原始优化器的get_updates()
。替换所有这些方法后,我们(1)使其引用累积的梯度,以及(2)使所有更新(“分配”操作)仅在last
为True
时发生。
更新我们的参数
在每一步的最后,我们还有两件事要做。
首先,我们必须更新我们的变量来保存累积梯度的当前值。这是在第 33 行完成的。
其次,我们必须推进我们的步计数器— self.iterations
(第 36 行)。为了确保这发生在步骤的最后,我们在所有其他“赋值”操作的控制依赖下生成张量。这导致步数计数器更新仅在所有其他更新已经发生之后才发生。
结论
这篇文章和之前的文章旨在详细描述一些事情:
- 训练神经网络时可能遇到的批量调整问题以及受 GPU 内存限制的问题。
- 为什么以及如何梯度积累可能有助于解决这些问题。
- 深入探讨 Keras 优化器以及在构建梯度累积机制时需要考虑的事项。
- 如何使用 Run:AI Python 库,轻松为你的 Keras 模型添加渐变累积支持。
我们希望我们能够阐明这些主题,并帮助您更好地理解它们。
后续步骤
在 GitHub 上有一个开源的渐变累积工具,以及使用示例和更多资源。
如果你觉得这很有趣并且对运行你自己的神经网络有帮助,请与我们分享!
如何有效地定义和验证 AI/ML 用例
大多数数据专业人员努力定义转化为数据科学的用例& AI/ML 解决方案带来真正的价值
来源:链接
你可能想知道为什么?
理论上,提出想法、收集反馈和原型以获得演示和验证概念应该很简单。
然而,在现实中,大多数数据科学和机器学习专业人员在该过程的每一步都失败了,结果是交付的解决方案很少达到生产阶段或发布后,并且没有任何价值(没有增加生产力、收入或根本没有娱乐性)。
每 10 个数据科学项目中只有一个能够真正投入生产。 ( 来源 )
有人可能会说,数据科学和机器学习项目只是研究性质的,因此很明显,它们中的大多数将会失败。
当然这是真的,但是如何构建用例定义和验证的过程以减少时间和成本并增加成功率呢?建立一个原型通常是一项重大的投资,需要努力和时间,其中一些需要几个月的时间……船上有一大群 ML 工程师。
此外,由于新冠肺炎限制的存在,一些组织在远程协作和生产力方面举步维艰(尽管一些组织被证明比以前更加有效!).
作者图片
毫无疑问,这里没有金科玉律,不同的公司有不同的流程。然而,本文旨在为数据科学和 ML 专业人员提供指导和技术,帮助他们在障碍之间导航,并使他们能够推出满足用户期望并为公司带来好处(收入、效率、敏捷性)的生产解决方案。
无论用例验证的过程是如何构建的,它都将包含以下两个主要阶段:
● 构思 —用例定义和原型制作准备
● 验证 —建造原型并测量结果
如何定义一个用例?
用例是对如何应用人工智能/人工智能解决特定问题的描述/机会。
一切都始于一个想法,这种想法可能来自不同的来源,有时甚至是不寻常的。也许一位副总裁在 LinkedIn 上看到一篇帖子并受到启发,一位数据科学家可能读过一篇有趣的论文,或者一位 ML 工程师偶然发现了一种新算法并想探索它的潜力。
用例通常来自产品管理、UX 团队或硬件团队,他们刚刚制作了新传感器的原型,或者希望为产品带来令人惊叹的新功能。
上面的每个例子都可能产生有趣的用例,但同时也可能只会导致壮观而昂贵的失败。例如,一个常见的错误是将冷静、复杂的深度学习算法(需要大量不可用的数据)应用于每个问题,即使是那些可以通过启发式或简单的“传统”模型成功解决的问题。
好,怎么开始?
投资创意&研究!
最好的开始方式是组织一次跨团队头脑风暴会议,不仅包括您的数据科学/机器学习团队,还包括来自产品管理、用户体验、硬件等团队的其他利益相关者,以及任何其他可能对用例定义和后续验证做出贡献的人。
这种不同观点+创造力的融合是成功的关键!
数据科学是关于创造力和从数据字节中构建有意义的解决方案,让我们的世界变得更美好!
来源:链接
通过发送有趣的用例示例(论文、视频等),可以激发创造力。)在会前发给所涉缔约方。
通过研究竞争对手及其产品、其他行业的使用案例以及适用的研究论文来促进研究。
当前的疫情和远程协作需求也是一个挑战。务必注重适当的引导,并为所有参与者提供充分的机会来分享他们的想法并提供反馈。
列出会议期间出现的所有想法。选择 10 个左右最有趣的用例,让团队使用以下问题列表检查每个用例,以确定用例的优先级,并选择最有希望进行原型制作的用例:
- 问题 —如何用数据科学和机器学习解决?
- 影响 —用户将如何从建议的解决方案中受益?
- 价值/利益 —有形&无形;成本降低、有效性、敏捷性或其他?
- 创新 —这个想法有多独特/新颖?涉及多少研究?有类似的吗?任何组件都可以重复使用吗?
- 数据 —数据是否可用,或者是否需要为原型制作生成/收集数据?
- 验证 —验证有多容易?
- 复杂性 —构建一个解决方案有多困难,需要多长时间才能为用户发布解决方案?
此时,没有必要关心答案的绝对准确性,因为它们只是支持用例优先级的粗略估计。上面的列表只是重要问题的一个例子,当然可以根据你的具体需求进行调整/扩展。
然而,保持简短。尽可能应用预定义的答案。这样的答案可以进一步用于应用权重和实现评分算法。
上述练习的最终结果应该是为下一阶段列出的三个用例。
来源:链接
从有形的商业利益、对用户的影响和上市时间方面选择最有希望的一个(将首先制作原型)来进行简化的可行性研究。
结果应该是一个简短的总结,概述下一阶段(验证)的工作范围,至少包括以下 6 个方面:1)目标,2)商业机会,3)技术,4)验证方法,5)数据,6)团队,7)进度,8)风险。
如何验证一个用例?
答案是快速成型。
不要在概念验证上花费时间,因为你的主要目标不应该是从技术角度验证构建一个解决方案是否可行。答案永远是肯定的(好吧,几乎总是…)。在大多数合理的情况下,这归结为数据可用性和选择正确算法的问题。
然而,你的验证目标不仅仅是技术可行性,更重要的是构建一个原型来评估产品化解决方案的潜在影响、有用性和好处。此外,评估与开发最终解决方案相关的工作、资源、时间表和风险。
来源:链接
我个人对快速原型的一些建议:
- 明确定义并获得团队对目标、范围、产出和验证标准的理解!
- 在每周冲刺中组织工作(最多 4-5 个,更长可能导致范围蔓延和失败)。
- 逐步构建原型,从基本模型(甚至启发式)开始,然后通过额外的改进来增强,切换到更高级的方法。
- 小型敏捷跨职能团队(1-2 名数据科学家,1-2 名 SME,+领导)。将许多 ML 工程师(一种常见的做法)分配给同一个用例是走向失败的路线图。
- 包括能够验证用例(UX/硬件/产品管理或其他)的中小型企业。
- 寻找最简单的方法,神经网络需要大量你可能没有的数据,并且通常使用经典算法可以获得相同的结果,甚至简单的线性回归或统计模型和试探法的组合。
- 尝试不同的算法 —不要拘泥于一种,针对同一问题尝试其他算法来评估性能。
- 投入时间进行研究 —重用可用的架构、模型和软件包。
- 确保数据质量并应用必要的数据清理。
- 确定您的主要利益相关方并确保持续沟通。
在分布式团队的情况下,特别是考虑到当前的疫情限制,协作可能是困难的,因为快速原型在并置的团队中执行是最有效的。然而,有许多不同的技术和技巧可以应用,从任务管理工具、看板板,到通过视频和即席消息来赶上进度。我不会在这里推广任何特定的工具,因为每个公司都使用他们自己的一套工具,可以有效地应用于预期的目的。
验证,最重要的部分!
来源:链接
显然,我们的目标不是验证模型(这仍然很重要),而是确保构建的原型/演示符合我们定义的用例,有可能对用户产生影响,并且能够产生切实的商业价值。
在这一阶段,您应该在项目开始之前,根据您与团队和利益相关者定义的定量和定性成功标准来验证原型。
量化标准可以是模型必须达到的误差阈值(MSE、召回或任何其他相关的)。它也可以是与模型或原型的性能相关的不同度量的组合。
这部分很容易。
最具挑战性的部分是定性的,在这里你无法衡量一些方面,比如原型可能为用户带来的价值和好处。当然,你可以运行一个焦点小组或者可用性研究,但是,这样的技术需要时间和大量的成本投入。因此,让他们进入下一阶段,暂时依靠您的中小企业——UX 和产品管理的专业知识。也让你公司的其他团队参与进来,分享原型并收集反馈。
然而,请记住——归根结底,这一切都是为了钱……
如果你想让你的商业利益相关者相信你的演示是有价值的,并且可能带来财务利润,你应该进行成本效益分析。首先列出所有直接的、间接的以及无形的成本和收益,包括那些与绩效提高和客户满意度相关的成本和收益。对所有头寸进行货币计量、汇总和比较。如果你很难展示收益,那就和你的团队一起确定并量化它们。
我应该什么时候开始验证?
答案是——一旦你开始快速成型。这应该是一个持续的过程,目的是验证用例的有用性。
在快速原型制作过程中,将结果传达给利益相关者,以获得他们的认同和对后续步骤的同意。这可以是一个简短的周会和/或每日更新的形式。
不管验证的结果如何,总结发现。
摘要可以是文档或演示文稿,不仅应该包括结果,还应该包括与产品化相关的方面,例如在进入下一阶段和开发解决方案时需要考虑的已确定的问题和风险。
当项目由于在特定时间缺乏能力或其他公司优先事项而被搁置时,摘要文档也是有用的。这样的总结可以作为一个很好的起点,甚至对于其他考虑开发的类似用例也是如此。
如果验证后的特定用例没有计划进一步的开发,回顾你的积压工作,挑选下一个并再次启动原型。
来源:链接
最终,你将永远不会达到你所有的用例都通过验证并被安排产品化的地步。
坦率地说,你不应该指望他们。为什么?
因为原型设计和验证是研究的一部分,旨在确保只有最有希望的用例被转化为解决方案,并避免失败。
希望这篇文章能为你提供一些经过验证的技巧和指导,告诉你如何构建你的用例定义、原型和验证过程,从而最大化你的成功率。但一如既往,如何在自己的公司内组织和应用这些建议的指导方针,并将其嵌入到已经到位的流程和工具中,这取决于您。
祝你成功!🙂
感谢阅读。请随时联系 LinkedIn 或发表评论。
如果你管理或想要建立一个数据科学或 AI/ML 团队,你可能会发现我的另一篇文章很有趣:
了解如何有效地开发数据科学单元并避免常见陷阱
towardsdatascience.com](/how-to-build-data-science-unit-f84ee3de63f5)
如何有效地学习和掌握 Python,用于数据科学、人工智能或机器学习。
学习如何重新编码或学习一门新的编程语言可能会非常困难。大多数情况下,我们发现这是因为我们学习的方法不对。
丹尼斯·简斯在 Unsplash 拍摄的照片
如果你正在读这篇文章,那可能是因为你已经迈出了大胆的一步,在数据科学、人工智能或 ML 的众多选择中学习 python。我不会用冗长的演讲来烦你,比如 python 是什么,为什么对于任何想涉足数据科学、人工智能或机器学习领域的人来说,python 是一种很好的语言选择。相反,我将与您分享一些技巧,告诉您如何有效地学习 python 编程语言,踏上精通这门语言的旅程。
Python 是一门真正奇妙的语言。当有人想出一个好主意时,只需要 1 分钟和 5 行代码就可以完成你想要的事情。然后只需要一个小时就可以将脚本扩展到 300 行,之后它仍然几乎做你想做的事情。—杰克·詹森
保持一致
无论你用什么方法或途径学习 python,都要坚持下去。学习,总的来说,没有一个公式。这就是说,许多人可以通过许多不同的方式学习一些东西,并且仍然可以实现他们的目标。然而,找到适合自己的方法取决于每个人。建立一个学习计划。这个计划不能一概而论。你的学习计划应该考虑到你的工作、学校和健康计划。不要对自己太严格。当这一切都完成后,一定要坚持你的学习计划。养成学习的习惯,热爱你所学的东西。通过这样做,你会对你所学的东西产生渴望,并且每天都期待着学习。
写下你学到的东西
写笔记是学习 python 和任何其他编程语言的一个极好的方法。当我们从书本、讲座或辅导视频中学习时,我们不能把所有的东西都记在脑子里。我们必须对重要的观点和话题做笔记,这样我们就可以试着在我们所写的观点上更进一步。通过写笔记,我们可以通过阅读我们写在笔记上的几行来尝试重现我们所学的内容。这对记忆概念和原则以及训练我们的大脑记住我们所学的重要东西非常有帮助。你也可以养成写博客的习惯,在博客上你可以和世界上的其他人分享你的进步,以帮助激励代码新手。写作很有趣,从一个尝试写作并且不想停下来的程序员身上可以看出这一点😄,你可以学习专业写作或只是作为一种爱好,仅仅写你喜欢做的事情就能赚很多钱。
享受乐趣,尝试尝试
让你所学的东西变得有趣和愉快。Python 是一门非常有趣的语言,因此,在学习这门语言的时候,尽你所能享受其中的乐趣。你可以通过写一些关于你所学主题的小脚本来做到这一点。你可以建立迷你项目,这样你就可以实际了解你学到了什么。对代码做大量的实验,找到新的做事方法,如果你找到了使事情变得更简单或修复 bug 的方法,就贡献给你使用的公共库和包。你可以和志同道合的人一起编写你的包或库。
Python 是可执行的伪代码。—布鲁斯·埃凯尔
休息,不要把自己累坏了
编码会变得非常上瘾,个人需要知道什么时候休息。你必须知道什么时候休息,这样你才不会筋疲力尽。倦怠并不是与长时间或过度编码相关的唯一问题,还有严重的健康风险。因此,你需要经常休息。放松,呼吸新鲜空气,偶尔散散步,照顾好自己——看起来整洁健康。不要剥夺自己的休息时间,以至于你看起来像电影中典型的程序员的刻板形象,看起来不修边幅,病怏怏的,脸色苍白。作为程序员要学会把自己,自己的身心健康放在一切之上。
给自己找个搭档
有一个一起学习如何编码的伙伴是非常有趣的,你们可以从对方身上学到很多东西。个人编写代码的方式是独一无二的,通过成对编程,你可以学习编写代码或做其他你不知道的事情的方法。你们可以分享新的资源,举行模拟面试来锻炼自己,甚至一起向专业人士寻求指导。有一个伙伴有助于填补孤独的空虚感,这种空虚感在那些一天花很多时间独自写代码,没有人可以聊天或放松或做其他事情的人身上很常见。
编写 Python 代码的乐趣应该在于看到短小、简洁、易读的类,这些类用少量清晰的代码表达了大量的动作,而不是大量让读者厌烦得要死的琐碎代码。
—吉多·范·罗苏姆
我相信我在这篇文章中分享的一切对寻求进入该领域的初学者和学习进展不顺的中级程序员都有帮助。这些技巧是我从业内专业人士那里学到的,比如德里克·德贝杜伊
我已经策划了几本书来帮助你学习和欣赏 python 编程语言,理解一般编程的核心原理,学习数据科学、人工智能和 ML,享受😀
感谢您抽出时间阅读这个故事。我希望你学到了一些东西,这对你有所帮助。欢迎您在回复部分分享您的想法和观点,您可以直接在 Twitter 或 LinkedIn 上联系我。黑客快乐!
非常感谢 安娜·阿依库 为我校对并纠正我写这篇文章时犯的许多错误。
如何有效预测 Python 中的不平衡类
处理不平衡机器学习分类问题所需的所有细节
图片由 Eneida Nieves 在 Unsplash 拍摄
奇怪的是,我花在分类问题上的时间比花在回归问题上的时间要多得多。幸运的是,我经常处理不平衡的数据集。也许这是因为我的日常工作包括预测和分析信用风险、违约概率和其他欺诈风险!
在通常的情况下,一个人经常遇到付款违约、付款延迟和欺诈事件是不常见的。这就是说,与按时付款或正常的非欺诈活动相比,这类事件的比例通常很低。
这是不平衡数据集的一个非常简单的说明,其中一组(或一类)活动(如违约付款)在样本中的活动(如违约和正常付款)总数中所占的比例非常低。
现在,让我们看看为什么我们在面对不平衡的分类问题时需要小心,以及如何处理这些问题。该员额的其余部分结构如下:
- 介绍
- 模型评估指标
- 成本敏感学习
- 取样方法
介绍
当处理不平衡分类问题时,我们通常更关心正确预测少数类别(也称为肯定类别),例如欺诈事件、支付违约、垃圾邮件等。换句话说,与误报(例如,将正常电子邮件分类为垃圾邮件)相比,减少误报(例如,将欺诈性交易分类为非欺诈性交易)的数量对我们来说更加重要。
直觉上,给定较小的样本大小和偏斜的类分布,ML 模型正确地学习少数类的所有特征要困难得多。一个简单的模型可以通过简单地预测所有情况下的多数类来获得合理的准确性。
模型评估指标
评估指标只是评估特定模型在做出正确预测方面的效率和准确性。对于分类问题,评估度量将模型预测的类别标签(或其概率)与实际的类别标签进行比较,并给出预测的准确性。有几个标准评估指标在平衡的分类问题(例如,准确性)上工作得非常好,但是在倾斜的数据集上却失败得很惨。
因此,我们应该利用某些更适合不平衡分类问题的特定度量。
在继续之前,让我们回顾一下由 Cesar Ferri 等人分类的各种类型的评估指标:
- 阈值度量,基于对误差的阈值或定性理解:准确度、灵敏度/召回率、特异性、精确度、 F 值、灵敏度和特异性的几何平均值 Kappa 统计量。
- 分级标准基于模型对类别(可分离性的概念)的分级程度:在接收器操作特性曲线下的面积( AUROC )和在精度-召回曲线下的面积(PR AUC)。
- 概率度量测量与真实类别概率的偏差: LogLoss 和 Brier Score 。请注意,在使用这些指标之前,需要校准预测的概率。
准确性悖论
尽管它是分类问题中使用最广泛、最容易解释的度量标准,但请不要犯在不平衡数据集的情况下使用准确性度量标准来评估您的分类模型的新手错误。
精度计算如下:
或者,就混淆矩阵而言:
考虑一个具有 1:100 类不平衡的高度偏斜数据集-对于少数类(正)的每个实例,有 100 个多数类(负)的样本。一个简单的分类器(或者,甚至一个人)可以通过对每个测试样本默认预测多数类来实现 99%的预测准确性,而不需要任何实际的机器学习。然而,这并没有描绘真实的画面,因为可能正确预测少数类在上下文中更重要,例如在欺诈检测或垃圾邮件过滤算法中。
不平衡分类问题的评价指标
好的,那么我们应该用什么度量来评估我们的分类器呢?现在让我们来看一些适合不平衡分类的度量标准。
精度
精度是真阳性与分类器预测的总阳性的比率。请记住,在不平衡分类问题的背景下,阳性是指少数类。根据混淆矩阵计算如下:
精度值介于 0 和 1 之间。由于 Precision 本身不涉及假阴性,并且旨在最小化假阳性的数量,因此 Precision 并不真正代表我们也涉及最小化假阴性的全部情况(例如,预测交易为非欺诈性的,而实际上它是欺诈性的)。
Scikit-learn 的[precision_score](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.precision_score.html)
函数计算二元和多类分类问题的精度:
from sklearn.metrics import precision_score# calculate precision for binary classification problem
precision = precision_score(y_true, y_pred, average='binary')# calculate precision for multi-class classification problem
precision = precision_score(y_true, y_pred, labels=[1,2], average='micro')
# labels is a list of all possible class labels
召回
召回率也称为敏感度和真阳性率(TPR),是样本中真阳性与真实阳性的比率。与 Precision 不同,Recall 还考虑了未被归类为阳性(少数)病例的数量。根据混淆矩阵计算如下:
召回值范围在 0 和 1 之间。召回与误报的数量无关,而是旨在最小化误报的数量。
Scikit-learn 的[recall_score](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.recall_score.html)
函数以与precision_score
完全相同的方式计算二元和多类分类问题的召回率。
F 分数
当我们更关心最小化假阳性时,精确度是合适的,而当假阴性的数量更关键时,召回是合适的。
但是,如果我们想同时最大化精确度和召回率,以最小的假阳性和假阴性准确地预测阳性类别呢?例如,在欺诈检测算法中,我们希望准确预测所有欺诈案例,同时不将非欺诈案例预测为欺诈案例。同时最大化精确度和召回率是一个很好的平衡行为,这就是 F 值的作用。
F-Score 提供了一个衡量精确度和召回率的单一分数。因此,最大化 F-Score 将意味着我们将最大化精确度和召回率。F-Score 是精度和召回率的简单调和平均值,并且广泛用于不平衡分类问题。
同样,F 值介于 0 和 1 之间。就像 Precision 和 Recall 一样,scikit-learn 的[f1_score](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.f1_score.html)
函数以完全相同的方式和语法计算二进制和多类问题的 F 分数。
受试者工作特性曲线下面积(AUROC)
ROC 曲线在 x 轴上绘制二元分类器的假阳性率(FPR ),在 y 轴上绘制真阳性率(TPR,召回),所有可能的概率阈值在 0 和 1 之间。TPR 计算如下:
任何分类器的默认概率阈值通常为 0.5,也就是说,如果样本的预测概率大于 0.5,则将该样本分类为属于阳性类别。然而,这个默认的假设不应该用于不平衡的数据集,稍后会有更多的介绍。
完美的分类器应该能够将 TPR 最大化为 1,将 FPR 最小化为 0,因此完美的分类器将在 ROC 曲线的左上象限(坐标 0,1)中一样高。ROC 并不特别偏向多数或少数类,因此,它是平衡和不平衡分类问题的普遍选择。
比较两个分类器的一种简便方法是计算 ROC 曲线下的面积 AUROC,它给出了一个分类器在所有概率阈值上的单一得分。AUROC 的范围在 0 到 1 之间,1 是一个非常熟练的分类器的分数。
使用 scikit-learn 的[roc_curve](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.roc_curve.html)
和[roc_auc_score](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.roc_auc_score.html)
函数绘制 ROC 曲线和计算 AUROC 的完整示例如下:
输出将类似于这样:
针对不平衡分类的 ROC 阈值移动
如上所述,在不平衡分类问题的情况下,使用默认概率阈值 0.5 来预测类别标签将可能导致较差的模型性能。幸运的是,在 ROC 曲线的情况下,确定最佳概率阈值非常简单。直观上,这个最佳阈值最接近 ROC 曲线的左上角,并且可以使用 Youden 的 J 统计很容易地确定。
为由roc_curve
返回的每个阈值计算 J 统计,最大的 J 值是最佳阈值。最简单的 J 统计量计算公式为:
一旦我们调用了roc_curve
函数,使用 J 统计量确定最佳阈值就非常简单了:
#import the required library
from numpy import argmax# calculate inputs for the roc curve
fpr, tpr, thresholds = roc_curve(test_y, yhat_positive)# get the best threshold
J = tpr - fpr
ix = argmax(J)
best_thresh = thresholds[ix]
print('Best Threshold: %f' % (best_thresh))
所有预测概率(yhat
)大于该阈值的样本应被分配到阳性类别。
精确召回曲线下面积(PR AUC)
对于所有可能的概率阈值,PR 曲线在 x 轴上绘制召回,在 y 轴上绘制精度。与 ROC 曲线相反,一个非常熟练的模型向坐标为(1,1)的右上轴弯曲。由于精度和召回率都与真阳性(少数类)有关,这使得它成为不平衡分类问题的有效工具。
比较两个分类器的一种简便方法是计算 PR 曲线下的面积 PR AUC,它给出了一个分类器在所有概率阈值上的单一得分。PR AUC 的范围在 0 和 1 之间,1 是一个完全熟练的分类器的分数。
使用 scikit-learn 的[precision_recall_curve](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.precision_recall_curve.html)
和[auc](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.auc.html)
函数绘制 PR 曲线和计算 PR AUC 的完整示例如下:
输出将类似于这样:
不平衡分类的 PR 曲线阈值移动
类似于 ROC 曲线,在 PR 曲线的情况下,确定最佳概率阈值是足够简单的。直观地说,这个最佳阈值最接近 PR 曲线的右上角,可以使用 F 值轻松确定。
一旦我们调用了precision_recall_curve
函数,使用 F 值的最佳阈值确定如下:
#import the required library
from numpy import argmax# calculate inputs for the roc curve
precision, recall, thresholds = precision_recall_curve(test_y, yhat_positive)# Calculate F-Scores and find the index of ideal score
fscore = (2 * precision * recall) / (precision + recall)
ix = argmax(fscore)
best_thresh = thresholds[ix]
print('Best Threshold: %f' % (best_thresh))
预测概率(yhat
)大于该阈值的所有样本应被分配到阳性类别。
日志损失分数
Log Loss Score 是一种基于概率的评估指标,与预测的分类标签无关。相反,它用于评估预测的校准的概率。一些模型预测校准概率作为训练过程的一部分(例如,逻辑回归),
但是许多模型不预测,并且在使用 LogLoss 或 Brier 分数之前需要校准(例如,支持向量机、决策树和神经网络)。使用 scikit-learn 的[CalibratedClassifierCV](https://scikit-learn.org/stable/modules/generated/sklearn.calibration.CalibratedClassifierCV.html)
类可以很容易地校准概率。
可能的最佳对数损失分数为 0,范围从 0 到无穷大,分数越高越差。它被定义为基于地面真实类别标签(y
)预测概率(yhat
)的分类器的负对数似然性:
Scikit-learn 的[log_loss](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.log_loss.html)
函数使我们在获得如下预测类概率后计算对数损失分数变得容易:
from sklearn.metrics import log_loss# fit a model
model = LogisticRegression()
model.fit(train_X, train_y)# predict probabilities
yhat = model.predict_proba(test_X)# calculate and print Log Loss Score
logloss = log_loss(test_y, yhat)
print('Log Loss Score: %.3f' % (logloss))
欧石南得分
以 Glenn Brier 命名的 Brier Score 计算预测概率和它们各自的正类值之间的均方误差。Brier Score 通常仅适用于二元分类问题,并评估阳性类别的概率。Brier 和 Log Loss 得分之间的关键区别在于 Brier 得分中只考虑了阳性类别的预测概率。
与对数损失分数相反,Brier 分数的范围在 0 到 1 之间,0 是一个非常熟练的分类器的分数。其计算如下,其中yhat
是正类的预测概率,而y
是正类的基本事实标签:
Scikit-learn 的[brier_score_loss](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.brier_score_loss.html)
函数使得一旦我们有了如下预测的正类概率,就可以很容易地计算 Brier 分数:
from sklearn.metrics import brier_score_loss# fit a model
model = LogisticRegression()
model.fit(train_X, train_y)# predict probabilities
yhat = model.predict_proba(test_X)
# retrieve the probabilities for the positive class
yhat_positive = yhat[:, 1]# calculate and print Brier Score
brier = brier_score_loss(test_y, yhat_positive)
print('Brier Score: %.3f' % (brier))
不平衡数据集的交叉验证
k 倍 交叉验证技术在评估平衡甚至轻微偏斜数据集的分类器时非常高效和有效。然而,它在不平衡数据集的情况下失败,因为训练数据通常被分成假设均匀概率分布的折叠。在不平衡数据的情况下,这有可能导致某些折叠完全遗漏在阳性(少数)类别中,或者只有很少的样本。因此,这很可能导致误导性的模型评估。
一种改进的 k-fold 交叉验证,称为分层 k-fold 交叉验证,更适合不平衡分类问题。分层 k-fold 或重复分层 k-fold 保留了每个 fold 中不平衡的类分布。这些 k 倍技术中的任何一种都可以与[cross_val_score](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.cross_val_score.html)
结合使用来预测和评估每个折叠。前面解释的所有评估指标都可以用作cross_val_score
中的scoring
参数。在此参考完整列表。成本敏感学习一节稍后将提供实际演示。
成本敏感学习
在不平衡分类问题的情况下,分类器的误分类错误的感知成本通常是不同的。也就是说,缺失一个正(少数)类的代价通常比负(多数)类的错误分类更关键。换句话说,假阴性比假阳性更关键。
例如,拒绝给一个好客户贷款,并不像给一个可能永远不会还款的坏客户贷款那样糟糕。或者,诊断一个健康的癌症患者并进行更多的医学测试比让一个实际患有癌症的患者出院更好。
成本敏感性学习是 ML 的一个子领域,它考虑了各种错误的成本(包括误分类成本),同时在模型训练期间最小化模型误差。
用于不平衡分类的成本敏感学习集中于首先将不同的成本分配给可能产生的错误分类错误的类型,然后使用专门的方法将这些成本考虑在内。
但是如何将这些成本分配给错误分类,具体来说,是误报和漏报?真阳性和真阴性通常被赋予零成本。由于假阴性通常更重要,假阴性比假阳性的成本更高。在某些情况下,领域知识可以帮助我们。在保险索赔场景中,误报的成本可能是客户跟踪的潜在货币成本,而误报的成本可能是潜在的保险索赔成本。
然而,在所有情况下,分配错误分类成本可能并不简单。在这种情况下,一个有效的起点是将类别分布比率的倒数分配给假阳性和假阴性。例如,如果我们有一个 1:100 类平衡的数据集,假阴性的成本为 100,而假阳性的成本为 1。这是假设在现实生活中进行预测时,相同的类别分布也将成立。
现在,让我们通过某些 ML 模型,看看这种成本敏感的学习可以被纳入其中。
成本敏感的逻辑回归
Scikit-learns 的标准逻辑回归模型可通过class_weight
参数轻松修改,以考虑阶级不平衡。该参数对于来自多数类的示例中出现的错误对模型的惩罚较小,而对于来自少数类的示例中出现的错误对模型的惩罚较大。
class_weight
参数包含所有可能的分类标签及其相关权重/成本的字典,以便在模型拟合过程中加以考虑。同样,这些类权重可以由领域专家通过网格搜索、行业最佳实践或使用前面解释的类分布的逆来确定。
上面最后一个使用逆类分布作为权重的选项是通过将balanced
作为输入传递给class_weight
参数来指定的,而不是手动计算分布。
使用类别加权逻辑回归模型和使用重复分层 k 倍进行评估的完整示例如下:
成本敏感决策树
通过在确定每个节点的分裂点时考虑每个类别的重要性,在决策树中考虑类别不平衡。
就像逻辑回归一样,scikit-learn 的DecisionTreeClassifier
类有一个class_weight
参数,其功能与逻辑回归中的完全一样。
使用类别加权决策树并使用重复分层 k-fold 对其进行评估的完整示例如下:
对成本敏感的 XGBoost
XGBoost 是多个决策树的集合,是随机梯度推进的高效实现。它被广泛用于分类和回归问题,并被发现在几个具有挑战性的机器学习问题中非常有效。
[XGBoostClassifier](https://xgboost.readthedocs.io/en/latest/python/python_api.html#xgboost.XGBClassifier)
的scale_pos_weight
参数用于训练不平衡数据的类加权 XGBoost 分类器。XGBoost 的文档提供了一种估算scale_pos_weight
理想值的便捷方法,如下所示:
使用类加权 XGBoostClassifier 并使用重复分层 k-fold 对其进行评估的完整示例如下:
取样方法
一般来说,我不太喜欢使用各种过采样和欠采样方法来处理训练数据集中的类不平衡。我倾向于在尝试以下任何一种采样方法来纠正类别不平衡之前,对成本敏感的 ML 算法使用适当的评估指标。
首先,让我们确定三种主要类型的抽样方法来补救类别不平衡:
- 过采样包括复制或合成来自少数类的新样本
- 欠采样包括从多数类中删除或只选择一个样本
- 综合方法结合了过采样和欠采样
我通常不喜欢抽样方法而不喜欢成本敏感学习的原因:
- 然而,过采样情况下的潜在过拟合,后面解释的一些高级技术试图解决这个问题
- 采样不足导致有用数据丢失
- 过采样后学习和处理时间增加
如果你决定采用抽样方法,那么在实施时要非常小心。应该仅对训练数据集执行采样。它不会在整个数据集、维持集或验证数据集上执行。原因在于,其目的不是从数据中消除类别偏差,而是继续评估生产中真实和预期的数据的结果模型,以及实际现实问题的代表。
过采样方法
现在,让我们简要了解一些主要的过采样方法。请注意,我不会讨论随机过采样技术([RandomOverSampler](https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.over_sampling.RandomOverSampler.html#imblearn-over-sampling-randomoversampler)
),因为我认为它更容易过拟合。
合成少数过采样技术(SMOTE)
SMOTE 合成来自阳性(少数)类的新数据样本,没有随机复制,并由 Nitesh Chawla 等人在其 2002 年的论文中介绍。来自该论文:“通过获取每个少数类样本并沿着连接任意/所有 k 个少数类最近邻居的线段引入合成样本,对少数类进行过采样。”。
Python 的不平衡学习库包含了 SMOTE 的一个实现,这个实现的类名副其实:[SMOTE](https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.over_sampling.SMOTE.html?#imblearn-over-sampling-smote)
(以及这里描述的许多其他采样方法)。与 scikit-learn 中的任何其他数据转换对象一样,实现了SMOTE
类:它必须被定义和配置,适合数据集,然后被应用来创建数据集的新转换版本。
边界线-SMOTE
韩晖等人在 2005 年提出的边界 SMOTE 是对 SMOTE 的扩展,它使用 k 近邻算法识别并合成少数类的边界实例。imblearn
库的类实现了类似于 SMOTE 的边界 SMOTE。
濒临崩溃的 SVM
边界线-SMOTE SVM 与边界线-SMOTE 相同,但用于识别边界线情况的技术不同,其中使用 SVM 算法而不是 KNN 算法来识别错误分类的边界线情况。这是由 Hien Nguyen 等人在 2011 年的 paper⁴.中提出的imblearn
库的类实现了类似于 SMOTE 的边界 SMOTE SVM。
自适应合成采样(ADASYN)
ADASYN 是由 al.⁵的何海波等人在他们 2008 年的论文中提出的。来自该论文:“ADASYN 基于根据分布自适应地生成少数数据样本的思想:与那些更容易学习的少数样本相比,为更难学习的少数类样本生成更多的合成数据。”。imblearn
库的[ADASYN](https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.over_sampling.ADASYN.html#imblearn-over-sampling-adasyn)
类实现了类似于 SMOTE 的 ADASYN。
实际演示
下面是使用RepeatedStratifiedKFold
的Pipeline
中的DecisionTreeClassifier
使用上述四种过采样技术的完整实践演示(注意,这些类别的某些参数可以调整):
欠采样方法
现在,让我们简要了解一些主要的欠采样方法。注意,我不会讨论随机欠采样([RandomUnderSampler](https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.under_sampling.RandomUnderSampler.html#imblearn-under-sampling-randomundersampler)
)技术,因为我认为它更有可能导致有用数据的丢失。
欠采样未遂
接近失败指的是三种欠采样方法的集合,这些方法基于多数类实例和少数类实例之间的距离来选择样本。这些方法是由张建平和因德吉特·马尼在他们 2003 年的 paper⁶.中提出的这三种方法是:
- NearMiss-1 仅对那些与预定数量的最近少数类实例具有最小平均距离的多数类实例进行欠采样
- NearMiss-2 仅对那些与预定数量的最远少数类实例具有最小平均距离的多数类实例进行欠采样
- NearMiss-3 仅对那些与每个少数类实例具有最小距离的多数类实例进行欠采样
imblearn
库的[NearMiss](https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.under_sampling.NearMiss.html#imblearn-under-sampling-nearmiss)
类实现了与 SMOTE 相似的 NearMiss 的所有三个版本。
其他欠采样方法
下面的imblearn
库中包含了其他几种欠采样方法,它们以类似的方式实现:
- 浓缩近邻 Rule⁷ —
[CondensedNearestNeighbour](https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.under_sampling.CondensedNearestNeighbour.html#imblearn-under-sampling-condensednearestneighbour)
- CNN⁸的两次修改—
[TomekLinks](https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.under_sampling.TomekLinks.html#imblearn-under-sampling-tomeklinks)
- 一面倒的 Selection⁹ —
[OneSidedSelection](https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.under_sampling.OneSidedSelection.html#imblearn-under-sampling-onesidedselection)
- 已编辑最近邻⁰ —
[EditedNearestNeighbors](https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.under_sampling.EditedNearestNeighbours.html#imblearn-under-sampling-editednearestneighbours)
- 邻域清理规则—
[NeighborhoodCleaningRule](https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.under_sampling.NeighbourhoodCleaningRule.html#imblearn-under-sampling-neighbourhoodcleaningrule)
合成方法
有时将过采样和欠采样方法结合起来会更有效。就像上面用一个Pipeline
演示 SMOTE 一样,类似的流水线也可以用来创建一个多采样方法序列,最后用一个分类器。然后,该管道与RepeatedStratifiedKFold
和cross_val_score
一起用于评估预测。
在流水线中结合 SMOTE 和随机过采样的简单示例如下:
# import required libraries
from imblearn.pipeline import Pipeline
from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import RandomUnderSampler
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.tree import DecisionTreeClassifier# define model
model = DecisionTreeClassifier()# define pipeline
oversample = SMOTE(sampling_strategy=0.1)
undersample = RandomUnderSampler(sampling_strategy=0.5)
steps = [('o', oversample), ('u', undersample), ('m', model)]
pipeline = Pipeline(steps=steps)# define cross-validation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)# evaluate model
scores = cross_val_score(pipeline, X, y, scoring='roc_auc', cv=cv, n_jobs=-1)
然而,代替这些手动组合,imblearn
有如下几个标准的合成实现:
- SMOTE 和 Tomek 链接—
[SMOTETomek](https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.combine.SMOTETomek.html#imblearn-combine-smotetomek)
# import required libraries
from imblearn.pipeline import Pipeline
from imblearn.combine import SMOTETomek
from imblearn.under_sampling import TomekLinks
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.tree import DecisionTreeClassifier# define model
model = DecisionTreeClassifier()# define sampling strategy
resample = SMOTETomek(tomek=TomekLinks(sampling_strategy='majority'))# define pipeline
pipeline = Pipeline(steps=[('r', resample), ('m', model)])# define cross-validation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)# evaluate model
scores = cross_val_score(pipeline, X, y, scoring='roc_auc', cv=cv, n_jobs=-1)
- SMOTE 和编辑最近邻—
[SMOTEENN](https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.combine.SMOTEENN.html#imblearn-combine-smoteenn)
# import required libraries
from imblearn.pipeline import Pipeline
from imblearn.combine import SMOTEENN
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.tree import DecisionTreeClassifier# define model
model = DecisionTreeClassifier()# define pipeline
pipeline = Pipeline(steps=[('r', SMOTEENN()), ('m', model)])# define cross-validation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)# evaluate model
scores = cross_val_score(pipeline, X, y, scoring='roc_auc', cv=cv, n_jobs=-1)
结论
我希望上面关于不平衡数据集分类问题的讨论对你有用,就像对我一样。
欢迎联系 me 讨论任何与机器学习或数据和金融分析相关的问题。
继续学习!
参考
来自机器学习大师的杰森·布朗利博士的灵感和功劳,他在我的人工智能之旅中发挥了重要作用
[1] Ferri,c .,Hernández-Orallo,j .,& Modroiu,R. (2009 年)。分类性能测量的实验比较。模式识别。列特。, 30, 27–38.
[2]乔拉、鲍耶、霍尔和凯格尔迈耶(2002 年)。SMOTE:合成少数过采样技术。j .阿提夫。智能。已获授权(JAIR)。16.321–357.10.1613/杰尔 953
[3]韩,黄,王,魏。,&毛,BH。(2005) Borderline-SMOTE:不平衡数据集学习中的一种新的过采样方法。在:黄 DS。,张晓萍。,黄 GB。智能计算的进展。ICIC 2005。
[4] Nguyen,h .,Cooper,e .和 Kamei,K. (2011 年)。不平衡数据分类的边界过采样。国际知识工程和软数据范例杂志。3.4–21.10.1504/IJKESDP
[5]海波,杨,b,加西亚,E. A. &李,S. (2008)。“ADASYN:用于不平衡学习的自适应合成采样方法”,2008 年 IEEE 神经网络国际联合会议(IEEE 计算智能世界大会),香港,2008,第 1322–1328 页,doi:10.1109/ij CNN . 2008 . 20020386306
[6]张,j .和 Mani,I. (2003).不平衡数据分布的 KNN 方法:涉及信息提取的案例研究。ICML 2003 年不平衡数据集学习研讨会会议录。
[7] Hart,p .,“压缩最近邻规则”,载于《信息论》,IEEE 会刊,第 14 卷(3),第 515-516 页,1968 年。
[8] Tomek,I .,“CNN 的两次修改”,载于《系统、人和控制论》,IEEE 汇刊,第 6 卷,第 769-772 页,2010 年。
[9]m . Kubat 和 s . Matwin,“解决不平衡训练集的诅咒:片面选择”,载于《ICML》,第 97 卷,第 179-186 页,1997 年。
[10]Wilson d,“使用编辑数据的最近邻规则的渐近性质”,载于 IEEE 系统、人类和控制论汇刊,第 2 卷(3),第 408-421 页,1972 年。
[11] Laurikkala,j .,“通过平衡班级分布改进困难小班的识别”Springer Berlin Heidelberg,2001 年。